From 83c7de21cba00269b226fa5a01f613db64619b67 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 25 Apr 2012 13:02:19 +0000 Subject: [PATCH 0001/2357] isdn/gigaset: ratelimit CAPI message dumps commit 8e618aad5348b6e6c5a90e8d97ea643197963b20 upstream. Introduce a global ratelimit for CAPI message dumps to protect against possible log flood. Drop the ratelimit for ignored messages which is now covered by the global one. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/gigaset/capi.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 343b5c80cb7..292ca2fc852 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -14,6 +14,7 @@ #include "gigaset.h" #include #include +#include #include #include #include @@ -223,10 +224,14 @@ get_appl(struct gigaset_capi_ctr *iif, u16 appl) static inline void dump_cmsg(enum debuglevel level, const char *tag, _cmsg *p) { #ifdef CONFIG_GIGASET_DEBUG + /* dump at most 20 messages in 20 secs */ + static DEFINE_RATELIMIT_STATE(msg_dump_ratelimit, 20 * HZ, 20); _cdebbuf *cdb; if (!(gigaset_debuglevel & level)) return; + if (!___ratelimit(&msg_dump_ratelimit, tag)) + return; cdb = capi_cmsg2str(p); if (cdb) { @@ -2058,12 +2063,6 @@ static void do_reset_b3_req(struct gigaset_capi_ctr *iif, CapiResetProcedureNotSupportedByCurrentProtocol); } -/* - * dump unsupported/ignored messages at most twice per minute, - * some apps send those very frequently - */ -static unsigned long ignored_msg_dump_time; - /* * unsupported CAPI message handler */ @@ -2073,8 +2072,7 @@ static void do_unsupported(struct gigaset_capi_ctr *iif, { /* decode message */ capi_message2cmsg(&iif->acmsg, skb->data); - if (printk_timed_ratelimit(&ignored_msg_dump_time, 30 * 1000)) - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); + dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); } @@ -2085,11 +2083,9 @@ static void do_nothing(struct gigaset_capi_ctr *iif, struct gigaset_capi_appl *ap, struct sk_buff *skb) { - if (printk_timed_ratelimit(&ignored_msg_dump_time, 30 * 1000)) { - /* decode message */ - capi_message2cmsg(&iif->acmsg, skb->data); - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); - } + /* decode message */ + capi_message2cmsg(&iif->acmsg, skb->data); + dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); dev_kfree_skb_any(skb); } From cdbf0ff56f0690ac4b6335427d565a858512ab1f Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 25 Apr 2012 13:02:20 +0000 Subject: [PATCH 0002/2357] isdn/gigaset: fix CAPI disconnect B3 handling commit 62a1cfe052346b96a552b6a9178d412c709711bb upstream. If DISCONNECT_B3_IND was synthesized because of a DISCONNECT_REQ with existing logical connections, the connection state wasn't updated accordingly. Also the emitted DISCONNECT_B3_IND message wasn't included in the debug log as requested. This patch fixes both of these issues. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/gigaset/capi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 292ca2fc852..579aa021a65 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -1887,6 +1887,9 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, /* check for active logical connection */ if (bcs->apconnstate >= APCONN_ACTIVE) { + /* clear it */ + bcs->apconnstate = APCONN_SETUP; + /* * emit DISCONNECT_B3_IND with cause 0x3301 * use separate cmsg structure, as the content of iif->acmsg @@ -1911,6 +1914,7 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, } capi_cmsg2message(b3cmsg, __skb_put(b3skb, CAPI_DISCONNECT_B3_IND_BASELEN)); + dump_cmsg(DEBUG_CMD, __func__, b3cmsg); kfree(b3cmsg); capi_ctr_handle_message(&iif->ctr, ap->id, b3skb); } From 4e1468e1f16dcd141bb256fd7320687b5b8bc975 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 25 Apr 2012 13:02:20 +0000 Subject: [PATCH 0003/2357] isdn/gigaset: improve error handling querying firmware version commit e055d03dc088a990fe5ea24a2d64033a168da23c upstream. An out-of-place "OK" response to the "AT+GMR" (get firmware version) command turns out to be, more often than not, a delayed response to a previous command rather than an actual error, so continue waiting for the version number in that case. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/gigaset/ev-layer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 624a8256a77..685638ac116 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -190,6 +190,7 @@ struct reply_t gigaset_tab_nocid[] = ACT_INIT} }, {RSP_OK, 121, 121, -1, 0, 0, {ACT_GOTVER, ACT_INIT} }, + {RSP_NONE, 121, 121, -1, 120, 0, {ACT_GETSTRING} }, /* leave dle mode */ {RSP_INIT, 0, 0, SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"}, @@ -1314,8 +1315,9 @@ static void do_action(int action, struct cardstate *cs, s = ev->ptr; if (!strcmp(s, "OK")) { + /* OK without version string: assume old response */ *p_genresp = 1; - *p_resp_code = RSP_ERROR; + *p_resp_code = RSP_NONE; break; } From 64126fa12b904d5dae0b7e33fac540c46faf67c5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 21 May 2012 16:06:20 -0700 Subject: [PATCH 0004/2357] vfs: make AIO use the proper rw_verify_area() area helpers commit a70b52ec1aaeaf60f4739edb1b422827cb6f3893 upstream. We had for some reason overlooked the AIO interface, and it didn't use the proper rw_verify_area() helper function that checks (for example) mandatory locking on the file, and that the size of the access doesn't cause us to overflow the provided offset limits etc. Instead, AIO did just the security_file_permission() thing (that rw_verify_area() also does) directly. This fixes it to do all the proper helper functions, which not only means that now mandatory file locking works with AIO too, we can actually remove lines of code. Reported-by: Manish Honap Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/aio.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index 67a6db3e1b6..e7f2fad7b4c 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1456,6 +1456,10 @@ static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat) if (ret < 0) goto out; + ret = rw_verify_area(type, kiocb->ki_filp, &kiocb->ki_pos, ret); + if (ret < 0) + goto out; + kiocb->ki_nr_segs = kiocb->ki_nbytes; kiocb->ki_cur_seg = 0; /* ki_nbytes/left now reflect bytes instead of segs */ @@ -1467,11 +1471,17 @@ static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat) return ret; } -static ssize_t aio_setup_single_vector(struct kiocb *kiocb) +static ssize_t aio_setup_single_vector(int type, struct file * file, struct kiocb *kiocb) { + int bytes; + + bytes = rw_verify_area(type, file, &kiocb->ki_pos, kiocb->ki_left); + if (bytes < 0) + return bytes; + kiocb->ki_iovec = &kiocb->ki_inline_vec; kiocb->ki_iovec->iov_base = kiocb->ki_buf; - kiocb->ki_iovec->iov_len = kiocb->ki_left; + kiocb->ki_iovec->iov_len = bytes; kiocb->ki_nr_segs = 1; kiocb->ki_cur_seg = 0; return 0; @@ -1496,10 +1506,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat) if (unlikely(!access_ok(VERIFY_WRITE, kiocb->ki_buf, kiocb->ki_left))) break; - ret = security_file_permission(file, MAY_READ); - if (unlikely(ret)) - break; - ret = aio_setup_single_vector(kiocb); + ret = aio_setup_single_vector(READ, file, kiocb); if (ret) break; ret = -EINVAL; @@ -1514,10 +1521,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat) if (unlikely(!access_ok(VERIFY_READ, kiocb->ki_buf, kiocb->ki_left))) break; - ret = security_file_permission(file, MAY_WRITE); - if (unlikely(ret)) - break; - ret = aio_setup_single_vector(kiocb); + ret = aio_setup_single_vector(WRITE, file, kiocb); if (ret) break; ret = -EINVAL; @@ -1528,9 +1532,6 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat) ret = -EBADF; if (unlikely(!(file->f_mode & FMODE_READ))) break; - ret = security_file_permission(file, MAY_READ); - if (unlikely(ret)) - break; ret = aio_setup_vectored_rw(READ, kiocb, compat); if (ret) break; @@ -1542,9 +1543,6 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat) ret = -EBADF; if (unlikely(!(file->f_mode & FMODE_WRITE))) break; - ret = security_file_permission(file, MAY_WRITE); - if (unlikely(ret)) - break; ret = aio_setup_vectored_rw(WRITE, kiocb, compat); if (ret) break; From 4c68b0f805f759fa0c61b9bbfb2ca0324b00cbd3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 23 Mar 2012 07:23:31 -0700 Subject: [PATCH 0005/2357] cfg80211: warn if db.txt is empty with CONFIG_CFG80211_INTERNAL_REGDB commit 80007efeff0568375b08faf93c7aad65602cb97e upstream. It has happened twice now where elaborate troubleshooting has undergone on systems where CONFIG_CFG80211_INTERNAL_REGDB [0] has been set but yet net/wireless/db.txt was not updated. Despite the documentation on this it seems system integrators could use some more help with this, so throw out a kernel warning at boot time when their database is empty. This does mean that the error-prone system integrator won't likely realize the issue until they boot the machine but -- it does not seem to make sense to enable a build bug breaking random build testing. [0] http://wireless.kernel.org/en/developers/Regulatory/CRDA#CONFIG_CFG80211_INTERNAL_REGDB Cc: Stephen Rothwell Cc: Youngsin Lee Cc: Raja Mani Cc: Senthil Kumar Balasubramanian Cc: Vipin Mehta Cc: yahuan@qca.qualcomm.com Cc: jjan@qca.qualcomm.com Cc: vthiagar@qca.qualcomm.com Cc: henrykim@qualcomm.com Cc: jouni@qca.qualcomm.com Cc: athiruve@qca.qualcomm.com Cc: cjkim@qualcomm.com Cc: philipk@qca.qualcomm.com Cc: sunnykim@qualcomm.com Cc: sskwak@qualcomm.com Cc: kkim@qualcomm.com Cc: mattbyun@qualcomm.com Cc: ryanlee@qualcomm.com Cc: simbap@qualcomm.com Cc: krislee@qualcomm.com Cc: conner@qualcomm.com Cc: hojinkim@qualcomm.com Cc: honglee@qualcomm.com Cc: johnwkim@qualcomm.com Cc: jinyong@qca.qualcomm.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index e9a0ac83b84..15f347477a9 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -388,7 +388,15 @@ static void reg_regdb_query(const char *alpha2) schedule_work(®_regdb_work); } + +/* Feel free to add any other sanity checks here */ +static void reg_regdb_size_check(void) +{ + /* We should ideally BUILD_BUG_ON() but then random builds would fail */ + WARN_ONCE(!reg_regdb_size, "db.txt is empty, you should update it..."); +} #else +static inline void reg_regdb_size_check(void) {} static inline void reg_regdb_query(const char *alpha2) {} #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ @@ -2322,6 +2330,8 @@ int __init regulatory_init(void) spin_lock_init(®_requests_lock); spin_lock_init(®_pending_beacons_lock); + reg_regdb_size_check(); + cfg80211_regdomain = cfg80211_world_regdom; user_alpha2[0] = '9'; From 538926ed486b8012193586e0c2dceda20e9c032a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 13 May 2012 18:35:56 +0100 Subject: [PATCH 0006/2357] regulator: core: Release regulator-regulator supplies on error commit e81dba85c6388dfabcb76cbc2b8bd02836a53ae5 upstream. If we fail while registering a regulator make sure we release the supply for the regulator if there is one. Signed-off-by: Mark Brown Acked-by: Liam Girdwood Signed-off-by: Greg Kroah-Hartman --- drivers/regulator/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 046fb1bd861..c18f0fd1577 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2971,6 +2971,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, unset_regulator_supplies(rdev); scrub: + if (rdev->supply) + regulator_put(rdev->supply); kfree(rdev->constraints); device_unregister(&rdev->dev); /* device core frees rdev */ From ae77ce9aa720eefa34f3644d0d9e3ce3976e8f07 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 21 May 2012 12:52:42 -0700 Subject: [PATCH 0007/2357] Fix blocking allocations called very early during bootup commit 31a67102f4762df5544bc2dfb34a931233d2a5b2 upstream. During early boot, when the scheduler hasn't really been fully set up, we really can't do blocking allocations because with certain (dubious) configurations the "might_resched()" calls can actually result in scheduling events. We could just make such users always use GFP_ATOMIC, but quite often the code that does the allocation isn't really aware of the fact that the scheduler isn't up yet, and forcing that kind of random knowledge on the initialization code is just annoying and not good for anybody. And we actually have a the 'gfp_allowed_mask' exactly for this reason: it's just that the kernel init sequence happens to set it to allow blocking allocations much too early. So move the 'gfp_allowed_mask' initialization from 'start_kernel()' (which is some of the earliest init code, and runs with preemption disabled for good reasons) into 'kernel_init()'. kernel_init() is run in the newly created thread that will become the 'init' process, as opposed to the early startup code that runs within the context of what will be the first idle thread. So by the time we reach 'kernel_init()', we know that the scheduler must be at least limping along, because we've already scheduled from the idle thread into the init thread. Reported-by: Steven Rostedt Cc: David Rientjes Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- init/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/init/main.c b/init/main.c index 44b2433334c..cb54cd3dbf0 100644 --- a/init/main.c +++ b/init/main.c @@ -560,9 +560,6 @@ asmlinkage void __init start_kernel(void) early_boot_irqs_disabled = false; local_irq_enable(); - /* Interrupts are enabled now so all GFP allocations are safe. */ - gfp_allowed_mask = __GFP_BITS_MASK; - kmem_cache_init_late(); /* @@ -842,6 +839,10 @@ static int __init kernel_init(void * unused) * Wait until kthreadd is all set-up. */ wait_for_completion(&kthreadd_done); + + /* Now the scheduler is fully set up and can do blocking allocations */ + gfp_allowed_mask = __GFP_BITS_MASK; + /* * init can allocate pages on any node */ From afde0dae8ee521686465141a44aa8060f4805cab Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 May 2012 09:37:30 +0200 Subject: [PATCH 0008/2357] s390/pfault: fix task state race commit d5e50a51ccbda36b379aba9d1131a852eb908dda upstream. When setting the current task state to TASK_UNINTERRUPTIBLE this can race with a different cpu. The other cpu could set the task state after it inspected it (while it was still TASK_RUNNING) to TASK_RUNNING which would change the state from TASK_UNINTERRUPTIBLE to TASK_RUNNING again. This race was always present in the pfault interrupt code but didn't cause anything harmful before commit f2db2e6c "[S390] pfault: cpu hotplug vs missing completion interrupts" which relied on the fact that after setting the task state to TASK_UNINTERRUPTIBLE the task would really sleep. Since this is not necessarily the case the result may be a list corruption of the pfault_list or, as observed, a use-after-free bug while trying to access the task_struct of a task which terminated itself already. To fix this, we need to get a reference of the affected task when receiving the initial pfault interrupt and add special handling if we receive yet another initial pfault interrupt when the task is already enqueued in the pfault list. Signed-off-by: Heiko Carstens Reviewed-by: Martin Schwidefsky Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/mm/fault.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 46ef3fd0663..4e66860029f 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -574,6 +574,7 @@ static void pfault_interrupt(struct ext_code ext_code, tsk->thread.pfault_wait = 0; list_del(&tsk->thread.list); wake_up_process(tsk); + put_task_struct(tsk); } else { /* Completion interrupt was faster than initial * interrupt. Set pfault_wait to -1 so the initial @@ -588,14 +589,22 @@ static void pfault_interrupt(struct ext_code ext_code, put_task_struct(tsk); } else { /* signal bit not set -> a real page is missing. */ - if (tsk->thread.pfault_wait == -1) { + if (tsk->thread.pfault_wait == 1) { + /* Already on the list with a reference: put to sleep */ + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + set_tsk_need_resched(tsk); + } else if (tsk->thread.pfault_wait == -1) { /* Completion interrupt was faster than the initial * interrupt (pfault_wait == -1). Set pfault_wait * back to zero and exit. */ tsk->thread.pfault_wait = 0; } else { /* Initial interrupt arrived before completion - * interrupt. Let the task sleep. */ + * interrupt. Let the task sleep. + * An extra task reference is needed since a different + * cpu may set the task state to TASK_RUNNING again + * before the scheduler is reached. */ + get_task_struct(tsk); tsk->thread.pfault_wait = 1; list_add(&tsk->thread.list, &pfault_list); set_task_state(tsk, TASK_UNINTERRUPTIBLE); @@ -620,6 +629,7 @@ static int __cpuinit pfault_cpu_notify(struct notifier_block *self, list_del(&thread->list); tsk = container_of(thread, struct task_struct, thread); wake_up_process(tsk); + put_task_struct(tsk); } spin_unlock_irq(&pfault_lock); break; From 3102e700882480237273c4e45a65f23fce0dd345 Mon Sep 17 00:00:00 2001 From: "nagalakshmi.nandigama@lsi.com" Date: Tue, 20 Mar 2012 12:10:01 +0530 Subject: [PATCH 0009/2357] SCSI: mpt2sas: Fix for panic happening because of improper memory allocation commit e42fafc25fa86c61824e8d4c5e7582316415d24f upstream. The ioc->pfacts member in the IOC structure is getting set to zero following a call to _base_get_ioc_facts due to the memset in that routine. So if the ioc->pfacts was read after a host reset, there would be a NULL pointer dereference. The routine _base_get_ioc_facts is called from context of host reset. The problem in _base_get_ioc_facts is the size of Mpi2IOCFactsReply is 64, whereas the sizeof "struct mpt2sas_facts" is 60, so there is a four byte overflow resulting from the memset. Also, there is memset in _base_get_port_facts using the incorrect structure, it should be "struct mpt2sas_port_facts" instead of Mpi2PortFactsReply. Signed-off-by: Nagalakshmi Nandigama Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt2sas/mpt2sas_base.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 8a59a772fdf..18084788ee3 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3343,7 +3343,7 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag) } pfacts = &ioc->pfacts[port]; - memset(pfacts, 0, sizeof(Mpi2PortFactsReply_t)); + memset(pfacts, 0, sizeof(struct mpt2sas_port_facts)); pfacts->PortNumber = mpi_reply.PortNumber; pfacts->VP_ID = mpi_reply.VP_ID; pfacts->VF_ID = mpi_reply.VF_ID; @@ -3385,7 +3385,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) } facts = &ioc->facts; - memset(facts, 0, sizeof(Mpi2IOCFactsReply_t)); + memset(facts, 0, sizeof(struct mpt2sas_facts)); facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion); facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion); facts->VP_ID = mpi_reply.VP_ID; @@ -4262,7 +4262,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) goto out_free_resources; ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, - sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); + sizeof(struct mpt2sas_port_facts), GFP_KERNEL); if (!ioc->pfacts) { r = -ENOMEM; goto out_free_resources; From 694450c8fa0dd37c49910c8d278cd68fab219006 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 30 Apr 2012 11:57:44 -0700 Subject: [PATCH 0010/2357] isci: fix oem parameter validation on single controller skus commit fc25f79af321c01a739150ba2c09435cf977a63d upstream. OEM parameters [1] are parsed from the platform option-rom / efi driver. By default the driver was validating the parameters for the dual-controller case, but in single-controller case only the first set of parameters may be valid. Limit the validation to the number of actual controllers detected otherwise the driver may fail to parse the valid parameters leading to driver-load or runtime failures. [1] the platform specific set of phy address, configuration,and analog tuning values Reported-by: Dave Jiang Tested-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/isci/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 5137db5a5d8..bc6cf888631 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -476,7 +476,7 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic if (!orom) orom = isci_request_oprom(pdev); - for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) { + for (i = 0; orom && i < num_controllers(pdev); i++) { if (sci_oem_parameters_validate(&orom->ctrl[i], orom->hdr.version)) { dev_warn(&pdev->dev, From b7a1a2016dba604884bfffb2e5ccf0ebc41b6e52 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Fri, 27 Apr 2012 09:59:16 -0500 Subject: [PATCH 0011/2357] RDMA/cxgb4: Always wake up waiters in c4iw_peer_abort_intr() commit 0f1dcfae6bc5563424346ad3a03282b8235a4c33 upstream. This fixes a race where an ingress abort fails to wake up the thread blocked in rdma_init() causing the app to hang. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/cxgb4/cm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 92b4c2b0308..8f431439144 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -2667,11 +2667,8 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb) /* * Wake up any threads in rdma_init() or rdma_fini(). - * However, this is not needed if com state is just - * MPA_REQ_SENT */ - if (ep->com.state != MPA_REQ_SENT) - c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); sched(dev, skb); return 0; } From 466dab407e47968777912aa23e5c66d1bd715405 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Fri, 27 Apr 2012 10:24:33 -0500 Subject: [PATCH 0012/2357] RDMA/cxgb4: Use dst parameter in import_ep() commit bd61baaf59669accae2720799394a51fecabe5d9 upstream. Function import_ep() is incorrectly using ep->dst instead of the dst ptr passed in. This causes a crash when accepting new rdma connections becase ep->dst is not initialized yet. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/cxgb4/cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 8f431439144..b770a044fb8 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1593,7 +1593,7 @@ static int import_ep(struct c4iw_ep *ep, __be32 peer_ip, struct dst_entry *dst, n, n->dev, 0); if (!ep->l2t) goto out; - ep->mtu = dst_mtu(ep->dst); + ep->mtu = dst_mtu(dst); ep->tx_chan = cxgb4_port_chan(n->dev); ep->smac_idx = (cxgb4_port_viid(n->dev) & 0x7F) << 1; step = cdev->rdev.lldi.ntxq / From ece17ce979baa62e074ba2d617e3a3ffc77ada84 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 30 Apr 2012 15:31:29 -0500 Subject: [PATCH 0013/2357] RDMA/cxgb4: Drop peer_abort when no endpoint found commit 14b9222808bb8bfefc71f72bc0dbdcf3b2f0140f upstream. Log a warning and drop the abort message. Otherwise we will do a bogus wake_up() and crash. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/cxgb4/cm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index b770a044fb8..4c7c62fe49d 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -2656,6 +2656,12 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb) unsigned int tid = GET_TID(req); ep = lookup_tid(t, tid); + if (!ep) { + printk(KERN_WARNING MOD + "Abort on non-existent endpoint, tid %d\n", tid); + kfree_skb(skb); + return 0; + } if (is_neg_adv_abort(req->status)) { PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep, ep->hwtid); From ae5b51f1aa5ccba9c36b16c56d3c000125ae7e41 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 7 May 2012 17:59:47 +0000 Subject: [PATCH 0014/2357] powerpc: Fix broken cpu_idle_wait() implementation commit 9cd75e13de2dcf32ecc21c7f277cff3c0ced059e upstream. commit 771dae818 (powerpc/cpuidle: Add cpu_idle_wait() to allow switching of idle routines) implemented cpu_idle_wait() for powerpc. The changelog says: "The equivalent routine for x86 is in arch/x86/kernel/process.c but the powerpc implementation is different.": Unfortunately the changelog is completely useless as it does not tell _WHY_ it is different. Aside of being different the implementation is patently wrong. The rescheduling IPI is async. That means that there is no guarantee, that the other cores have executed the IPI when cpu_idle_wait() returns. But that's the whole purpose of this function: to guarantee that no CPU uses the old idle handler anymore. Use the smp_functional_call() based implementation, which fulfils the requirements. [ This code is going to replaced by a core version to remove all the pointless copies in arch/*, but this one should go to stable ] Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra Cc: Deepthi Dharwar Cc: Trinabh Gupta Cc: Arun R Bharadwaj Acked-by: Benjamin Herrenschmidt Link: http://lkml.kernel.org/r/20120507175651.980164748@linutronix.de Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/idle.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 6d2209ac0c4..04d79093d7a 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -113,6 +113,9 @@ void cpu_idle(void) } } +static void do_nothing(void *unused) +{ +} /* * cpu_idle_wait - Used to ensure that all the CPUs come out of the old @@ -123,16 +126,9 @@ void cpu_idle(void) */ void cpu_idle_wait(void) { - int cpu; smp_mb(); - - /* kick all the CPUs so that they exit out of old idle routine */ - get_online_cpus(); - for_each_online_cpu(cpu) { - if (cpu != smp_processor_id()) - smp_send_reschedule(cpu); - } - put_online_cpus(); + /* kick all the CPUs so that they exit out of pm_idle */ + smp_call_function(do_nothing, NULL, 1); } EXPORT_SYMBOL_GPL(cpu_idle_wait); From 305d212b5e9d473230de491b2b722424af1dfc9b Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 11 May 2012 10:56:56 +0100 Subject: [PATCH 0015/2357] KEYS: Use the compat keyctl() syscall wrapper on Sparc64 for Sparc32 compat commit 45de6767dc51358a188f75dc4ad9dfddb7fb9480 upstream. Use the 32-bit compat keyctl() syscall wrapper on Sparc64 for Sparc32 binary compatibility. Without this, keyctl(KEYCTL_INSTANTIATE_IOV) is liable to malfunction as it uses an iovec array read from userspace - though the kernel should survive this as it checks pointers and sizes anyway. I think all the other keyctl() function should just work, provided (a) the top 32-bits of each 64-bit argument register are cleared prior to invoking the syscall routine, and the 32-bit address space is right at the 0-end of the 64-bit address space. Most of the arguments are 32-bit anyway, and so for those clearing is not required. Signed-off-by: David Howells cc: sparclinux@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/sparc/Kconfig | 3 +++ arch/sparc/kernel/systbls_64.S | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 6c0683d3fcb..76c7ccfb1eb 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -584,6 +584,9 @@ config SYSVIPC_COMPAT depends on COMPAT && SYSVIPC default y +config KEYS_COMPAT + def_bool y if COMPAT && KEYS + endmenu source "net/Kconfig" diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index db86b1a0e9a..3a58e0d66f5 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -74,7 +74,7 @@ sys_call_table32: .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid -/*280*/ .word sys32_tee, sys_add_key, sys_request_key, sys_keyctl, compat_sys_openat +/*280*/ .word sys32_tee, sys_add_key, sys_request_key, compat_sys_keyctl, compat_sys_openat .word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64 /*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare From c3083d9d9e5860c365e93b1e96aa65613fa829fb Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 4 Apr 2012 13:47:11 -0400 Subject: [PATCH 0016/2357] SELinux: if sel_make_bools errors don't leave inconsistent state commit 154c50ca4eb9ae472f50b6a481213e21ead4457d upstream. We reset the bool names and values array to NULL, but do not reset the number of entries in these arrays to 0. If we error out and then get back into this function we will walk these NULL pointers based on the belief that they are non-zero length. Signed-off-by: Eric Paris Signed-off-by: Greg Kroah-Hartman --- security/selinux/selinuxfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d7018bfa1f0..3068d16cf12 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1232,6 +1232,7 @@ static int sel_make_bools(void) kfree(bool_pending_names[i]); kfree(bool_pending_names); kfree(bool_pending_values); + bool_num = 0; bool_pending_names = NULL; bool_pending_values = NULL; From 7716183bcc917203fb8353a226a0228167b9e832 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 18 May 2012 10:58:26 +0200 Subject: [PATCH 0017/2357] fbdev: sh_mobile_lcdc: Don't confuse line size with pitch commit 72c04af9a2d57b7945cf3de8e71461bd80695d50 upstream. When using the MERAM the LCDC line size needs to be programmed with a MERAM-specific value different than the real frame buffer pitch. Fix it. Reported-by: Guennadi Liakhovetski Signed-off-by: Laurent Pinchart Acked-by: Florian Tobias Schandinat Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/video/sh_mobile_lcdcfb.c | 5 +++-- drivers/video/sh_mobile_lcdcfb.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 7a0b301587f..e672698bd82 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -758,7 +758,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) } lcdc_write_chan(ch, LDDFR, tmp); - lcdc_write_chan(ch, LDMLSR, ch->pitch); + lcdc_write_chan(ch, LDMLSR, ch->line_size); lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); if (ch->format->yuv) lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); @@ -847,6 +847,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) ch->base_addr_y = ch->dma_handle; ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual; + ch->line_size = ch->pitch; /* Enable MERAM if possible. */ if (mdev == NULL || mdev->ops == NULL || @@ -882,7 +883,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg, ch->pitch, ch->yres, pixelformat, - &ch->pitch); + &ch->line_size); if (!IS_ERR(meram)) { mdev->ops->meram_update(mdev, meram, ch->base_addr_y, ch->base_addr_c, diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index da1c26e78a5..5c3bddd2cb7 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h @@ -84,6 +84,7 @@ struct sh_mobile_lcdc_chan { unsigned long base_addr_y; unsigned long base_addr_c; + unsigned int line_size; int (*notify)(struct sh_mobile_lcdc_chan *ch, enum sh_mobile_lcdc_entity_event event, From b10dfc7a2b20aaf6fad56f7b0725c4aaa9438ad1 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 10 May 2012 23:28:05 +0300 Subject: [PATCH 0018/2357] IB/core: Fix mismatch between locked and pinned pages commit c4870eb874ac16dccef40e1bc7a002c7e9156adc upstream. Commit bc3e53f682d9 ("mm: distinguish between mlocked and pinned pages") introduced a separate counter for pinned pages and used it in the IB stack. However, in ib_umem_get() the pinned counter is incremented, but ib_umem_release() wrongly decrements the locked counter. Fix this. Signed-off-by: Yishai Hadas Reviewed-by: Christoph Lameter Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/umem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 71f0c0f7df9..a8411232207 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -269,7 +269,7 @@ void ib_umem_release(struct ib_umem *umem) } else down_write(&mm->mmap_sem); - current->mm->locked_vm -= diff; + current->mm->pinned_vm -= diff; up_write(&mm->mmap_sem); mmput(mm); kfree(umem); From d026b7150e38a1764d83fc57b6e4448d5e278eaf Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 22 Apr 2012 13:37:09 +0200 Subject: [PATCH 0019/2357] drivers/staging/comedi/comedi_fops.c: add missing vfree commit abae41e6438b798e046d721b6ccdd55b4a398170 upstream. aux_free is freed on all other exits from the function. By removing the return, we can benefit from the vfree already at the end of the function. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 9bcf87ae4c0..a796964bfff 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -280,7 +280,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev, if (ret == 0) { if (!try_module_get(dev->driver->module)) { comedi_device_detach(dev); - return -ENOSYS; + ret = -ENOSYS; } } From 8f830c404b611cc9c47a0f91c1c91103e3ff8e30 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 18 May 2012 12:40:42 +0200 Subject: [PATCH 0020/2357] perf/x86: Update event scheduling constraints for AMD family 15h models commit 5bcdf5e4fee3c45e1281c25e4941f2163cb28c65 upstream. This update is for newer family 15h cpu models from 0x02 to 0x1f. Signed-off-by: Robert Richter Acked-by: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1337337642-1621-1-git-send-email-robert.richter@amd.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/perf_event_amd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index 95e7fe1c5f0..9edc786aef8 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -493,6 +493,7 @@ static __initconst const struct x86_pmu amd_pmu = { * 0x023 DE PERF_CTL[2:0] * 0x02D LS PERF_CTL[3] * 0x02E LS PERF_CTL[3,0] + * 0x031 LS PERF_CTL[2:0] (**) * 0x043 CU PERF_CTL[2:0] * 0x045 CU PERF_CTL[2:0] * 0x046 CU PERF_CTL[2:0] @@ -506,10 +507,12 @@ static __initconst const struct x86_pmu amd_pmu = { * 0x0DD LS PERF_CTL[5:0] * 0x0DE LS PERF_CTL[5:0] * 0x0DF LS PERF_CTL[5:0] + * 0x1C0 EX PERF_CTL[5:3] * 0x1D6 EX PERF_CTL[5:0] * 0x1D8 EX PERF_CTL[5:0] * - * (*) depending on the umask all FPU counters may be used + * (*) depending on the umask all FPU counters may be used + * (**) only one unitmask enabled at a time */ static struct event_constraint amd_f15_PMC0 = EVENT_CONSTRAINT(0, 0x01, 0); @@ -559,6 +562,12 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev return &amd_f15_PMC3; case 0x02E: return &amd_f15_PMC30; + case 0x031: + if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1) + return &amd_f15_PMC20; + return &emptyconstraint; + case 0x1C0: + return &amd_f15_PMC53; default: return &amd_f15_PMC50; } From 59784034b157f70d1e8cf56b114527faeadecfaf Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 8 May 2012 16:52:31 +0200 Subject: [PATCH 0021/2357] HID: wiimote: Fix IR data parser commit 74b89e8a3625c17c7452532dfb997ac4f1a38751 upstream. We incorrectly parse incoming IR data. The extra byte contains the upper bits and not the lower bits of the x/y coordinates. User-space expects absolute position data from us so this patch does not break existing applications. On the contrary, it extends the virtual view and fixes garbage reports for margin areas of the virtual screen. Reported-by: Peter Bukovsky Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-wiimote-core.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index cac3589b1ed..84e2fbec5fb 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -769,7 +769,7 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir, /* * Basic IR data is encoded into 3 bytes. The first two bytes are the - * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits + * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits * of both. * If data is packed, then the 3rd byte is put first and slightly * reordered. This allows to interleave packed and non-packed data to @@ -778,17 +778,11 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir, */ if (packed) { - x = ir[1] << 2; - y = ir[2] << 2; - - x |= ir[0] & 0x3; - y |= (ir[0] >> 2) & 0x3; + x = ir[1] | ((ir[0] & 0x03) << 8); + y = ir[2] | ((ir[0] & 0x0c) << 6); } else { - x = ir[0] << 2; - y = ir[1] << 2; - - x |= (ir[2] >> 4) & 0x3; - y |= (ir[2] >> 6) & 0x3; + x = ir[0] | ((ir[2] & 0x30) << 4); + y = ir[1] | ((ir[2] & 0xc0) << 2); } input_report_abs(wdata->ir, xid, x); From 774a93aa647f8939867c8ff956847bc63dd51cb3 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 30 Apr 2012 09:13:46 +0200 Subject: [PATCH 0022/2357] usbhid: prevent deadlock during timeout commit 8815bb09af21316aeb5f8948b24ac62181670db2 upstream. On some HCDs usb_unlink_urb() can directly call the completion handler. That limits the spinlocks that can be taken in the handler to locks not held while calling usb_unlink_urb() To prevent a race with resubmission, this patch exposes usbcore's infrastructure for blocking submission, uses it and so drops the lock without causing a race in usbhid. Signed-off-by: Oliver Neukum Acked-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/usbhid/hid-core.c | 61 +++++++++++++++++++++++++++++++---- drivers/usb/core/urb.c | 21 ++++++++++++ include/linux/usb.h | 3 ++ 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 5bf91dbad59..4bbb883a3dd 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -399,6 +399,16 @@ static int hid_submit_ctrl(struct hid_device *hid) * Output interrupt completion handler. */ +static int irq_out_pump_restart(struct hid_device *hid) +{ + struct usbhid_device *usbhid = hid->driver_data; + + if (usbhid->outhead != usbhid->outtail) + return hid_submit_out(hid); + else + return -1; +} + static void hid_irq_out(struct urb *urb) { struct hid_device *hid = urb->context; @@ -428,7 +438,7 @@ static void hid_irq_out(struct urb *urb) else usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); - if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) { + if (!irq_out_pump_restart(hid)) { /* Successfully submitted next urb in queue */ spin_unlock_irqrestore(&usbhid->lock, flags); return; @@ -443,6 +453,15 @@ static void hid_irq_out(struct urb *urb) /* * Control pipe completion handler. */ +static int ctrl_pump_restart(struct hid_device *hid) +{ + struct usbhid_device *usbhid = hid->driver_data; + + if (usbhid->ctrlhead != usbhid->ctrltail) + return hid_submit_ctrl(hid); + else + return -1; +} static void hid_ctrl(struct urb *urb) { @@ -476,7 +495,7 @@ static void hid_ctrl(struct urb *urb) else usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) { + if (!ctrl_pump_restart(hid)) { /* Successfully submitted next urb in queue */ spin_unlock(&usbhid->lock); return; @@ -535,11 +554,27 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re * the queue is known to run * but an earlier request may be stuck * we may need to time out - * no race because this is called under + * no race because the URB is blocked under * spinlock */ - if (time_after(jiffies, usbhid->last_out + HZ * 5)) + if (time_after(jiffies, usbhid->last_out + HZ * 5)) { + usb_block_urb(usbhid->urbout); + /* drop lock to not deadlock if the callback is called */ + spin_unlock(&usbhid->lock); usb_unlink_urb(usbhid->urbout); + spin_lock(&usbhid->lock); + usb_unblock_urb(usbhid->urbout); + /* + * if the unlinking has already completed + * the pump will have been stopped + * it must be restarted now + */ + if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) + if (!irq_out_pump_restart(hid)) + set_bit(HID_OUT_RUNNING, &usbhid->iofl); + + + } } return; } @@ -583,11 +618,25 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re * the queue is known to run * but an earlier request may be stuck * we may need to time out - * no race because this is called under + * no race because the URB is blocked under * spinlock */ - if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) + if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) { + usb_block_urb(usbhid->urbctrl); + /* drop lock to not deadlock if the callback is called */ + spin_unlock(&usbhid->lock); usb_unlink_urb(usbhid->urbctrl); + spin_lock(&usbhid->lock); + usb_unblock_urb(usbhid->urbctrl); + /* + * if the unlinking has already completed + * the pump will have been stopped + * it must be restarted now + */ + if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + if (!ctrl_pump_restart(hid)) + set_bit(HID_CTRL_RUNNING, &usbhid->iofl); + } } } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index cd9b3a2cd8a..9d912bfdcff 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -680,6 +680,27 @@ void usb_unpoison_urb(struct urb *urb) } EXPORT_SYMBOL_GPL(usb_unpoison_urb); +/** + * usb_block_urb - reliably prevent further use of an URB + * @urb: pointer to URB to be blocked, may be NULL + * + * After the routine has run, attempts to resubmit the URB will fail + * with error -EPERM. Thus even if the URB's completion handler always + * tries to resubmit, it will not succeed and the URB will become idle. + * + * The URB must not be deallocated while this routine is running. In + * particular, when a driver calls this routine, it must insure that the + * completion handler cannot deallocate the URB. + */ +void usb_block_urb(struct urb *urb) +{ + if (!urb) + return; + + atomic_inc(&urb->reject); +} +EXPORT_SYMBOL_GPL(usb_block_urb); + /** * usb_kill_anchored_urbs - cancel transfer requests en masse * @anchor: anchor the requests are bound to diff --git a/include/linux/usb.h b/include/linux/usb.h index 73b68d1f2cb..26229fd8d61 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1379,6 +1379,7 @@ extern int usb_unlink_urb(struct urb *urb); extern void usb_kill_urb(struct urb *urb); extern void usb_poison_urb(struct urb *urb); extern void usb_unpoison_urb(struct urb *urb); +extern void usb_block_urb(struct urb *urb); extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); extern void usb_poison_anchored_urbs(struct usb_anchor *anchor); extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor); @@ -1391,6 +1392,8 @@ extern struct urb *usb_get_from_anchor(struct usb_anchor *anchor); extern void usb_scuttle_anchored_urbs(struct usb_anchor *anchor); extern int usb_anchor_empty(struct usb_anchor *anchor); +#define usb_unblock_urb usb_unpoison_urb + /** * usb_urb_dir_in - check if an URB describes an IN transfer * @urb: URB to be checked From 5f7bac87c60030bc2a0bb58789696f9624d5e8d9 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Fri, 11 May 2012 16:17:16 +0200 Subject: [PATCH 0023/2357] HID: logitech: read all 32 bits of report type bitfield commit 44d27f7dfedd9aadc082cda31462f6600f56e4ec upstream. On big-endian systems (e.g., Apple PowerBook), trying to use a logitech wireless mouse with the Logitech Unifying Receiver does not work with v3.2 and later kernels. The device doesn't show up in /dev/input. Older kernels work fine. That is because the new hid-logitech-dj driver claims the device. The device arrival notification appears: 20 00 41 02 00 00 00 00 00 00 00 00 00 00 00 and we read the report_types bitfield (02 00 00 00) to find out what kind of device it is. Unfortunately the driver only reads the first 8 bits and treats that value as a 32-bit little-endian number, so on a powerpc the report type seems to be 0x02000000 and is not recognized. Even on little-endian machines, connecting a media center remote control (report type 00 01 00 00) with this driver loaded would presumably fail for the same reason. Fix both problems by using get_unaligned_le32() to read all four bytes, which is a little clearer anyway. After this change, the wireless mouse works on Hugo's PowerBook again. Based on a patch by Nestor Lopez Casado. Addresses http://bugs.debian.org/671292 Reported-by: Hugo Osvaldo Barrera Inspired-by: Nestor Lopez Casado Signed-off-by: Jonathan Nieder Signed-off-by: Nestor Lopez Casado Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-logitech-dj.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 2b56efcbdf6..d44ea58c597 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "usbhid/usbhid.h" #include "hid-ids.h" #include "hid-logitech-dj.h" @@ -265,8 +266,8 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, goto dj_device_allocate_fail; } - dj_dev->reports_supported = le32_to_cpu( - dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]); + dj_dev->reports_supported = get_unaligned_le32( + dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE); dj_dev->hdev = dj_hiddev; dj_dev->dj_receiver_dev = djrcv_dev; dj_dev->device_index = dj_report->device_index; From 3d7a75d7dc0c8c8e60f8c40622b7e3519e702714 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sat, 14 Apr 2012 17:46:01 +0200 Subject: [PATCH 0024/2357] um: Fix __swp_type() commit 2b76ebaa728f8a3967c52aa189261c72fe56a6f1 upstream. The current __swp_type() function uses a too small bitshift. Using more than one swap files causes bad pages because the type bits clash with other page flags. Analyzed-by: Hugh Dickins Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- arch/um/include/asm/pgtable.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h index 6a3f9845743..9a61ee184ee 100644 --- a/arch/um/include/asm/pgtable.h +++ b/arch/um/include/asm/pgtable.h @@ -348,11 +348,11 @@ extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr); #define update_mmu_cache(vma,address,ptep) do ; while (0) /* Encode and de-code a swap entry */ -#define __swp_type(x) (((x).val >> 4) & 0x3f) +#define __swp_type(x) (((x).val >> 5) & 0x1f) #define __swp_offset(x) ((x).val >> 11) #define __swp_entry(type, offset) \ - ((swp_entry_t) { ((type) << 4) | ((offset) << 11) }) + ((swp_entry_t) { ((type) << 5) | ((offset) << 11) }) #define __pte_to_swp_entry(pte) \ ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) From f09f8dad903d3c469bf11b49c2d4c5259906a153 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sat, 14 Apr 2012 17:29:30 +0200 Subject: [PATCH 0025/2357] um: Implement a custom pte_same() function commit f15b9000eb1d09bbaa4b0a6b2089d7e1f64e84b3 upstream. UML uses the _PAGE_NEWPAGE flag to mark pages which are not jet installed on the host side using mmap(). pte_same() has to ignore this flag, otherwise unuse_pte_range() is unable to unuse the page because two identical page tables entries with different _PAGE_NEWPAGE flags would not match and swapoff() would never return. Analyzed-by: Hugh Dickins Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- arch/um/include/asm/pgtable.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h index 9a61ee184ee..5888f1b8347 100644 --- a/arch/um/include/asm/pgtable.h +++ b/arch/um/include/asm/pgtable.h @@ -273,6 +273,12 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval) } #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) +#define __HAVE_ARCH_PTE_SAME +static inline int pte_same(pte_t pte_a, pte_t pte_b) +{ + return !((pte_val(pte_a) ^ pte_val(pte_b)) & ~_PAGE_NEWPAGE); +} + /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. From bbe784b683f6e49bc345577fc5398344bc7c289e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 11 May 2012 17:17:17 -0700 Subject: [PATCH 0026/2357] persistent_ram: Fix buffer size clamping during writes commit 484dd30e016eb425b0de871357fff2c9bb93be45 upstream. This is a longstanding bug, almost unnoticeable when calling persistent_ram_write() for small buffers. But when called for large data buffers, the write routine behaves incorrectly, as the size may never update: instead of clamping the size to the maximum buffer size, buffer_size_add_clamp() returns an error (which is never checked by the write routine, btw). To fix this, we now use buffer_size_add() that actually clamps the size to the max value. Also remove buffer_size_add_clamp(), it is no longer needed. Signed-off-by: Anton Vorontsov Acked-by: Colin Cross Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/persistent_ram.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/staging/android/persistent_ram.c b/drivers/staging/android/persistent_ram.c index 8d8c1e33e0f..3d986ce50b9 100644 --- a/drivers/staging/android/persistent_ram.c +++ b/drivers/staging/android/persistent_ram.c @@ -79,23 +79,6 @@ static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a) } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old); } -/* increase the size counter, retuning an error if it hits the max size */ -static inline ssize_t buffer_size_add_clamp(struct persistent_ram_zone *prz, - size_t a) -{ - size_t old; - size_t new; - - do { - old = atomic_read(&prz->buffer->size); - new = old + a; - if (new > prz->buffer_size) - return -ENOMEM; - } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old); - - return 0; -} - static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz, uint8_t *data, size_t len, uint8_t *ecc) { @@ -300,7 +283,7 @@ int notrace persistent_ram_write(struct persistent_ram_zone *prz, c = prz->buffer_size; } - buffer_size_add_clamp(prz, c); + buffer_size_add(prz, c); start = buffer_start_add(prz, c); From a1542bf241dcf836035ecc67c1df4a96c097bd0b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 18 Apr 2012 23:16:45 -0700 Subject: [PATCH 0027/2357] docs: update HOWTO for 2.6.x -> 3.x versioning commit 591bfc6bf9e5e25e464fd4c87d64afd5135667c4 upstream. The HOWTO document needed updating for the new kernel versioning. The git URI for -next was updated as well. Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- Documentation/HOWTO | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Documentation/HOWTO b/Documentation/HOWTO index f7ade3b3b40..59c080f084e 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO @@ -218,16 +218,16 @@ The development process Linux kernel development process currently consists of a few different main kernel "branches" and lots of different subsystem-specific kernel branches. These different branches are: - - main 2.6.x kernel tree - - 2.6.x.y -stable kernel tree - - 2.6.x -git kernel patches + - main 3.x kernel tree + - 3.x.y -stable kernel tree + - 3.x -git kernel patches - subsystem specific kernel trees and patches - - the 2.6.x -next kernel tree for integration tests + - the 3.x -next kernel tree for integration tests -2.6.x kernel tree +3.x kernel tree ----------------- -2.6.x kernels are maintained by Linus Torvalds, and can be found on -kernel.org in the pub/linux/kernel/v2.6/ directory. Its development +3.x kernels are maintained by Linus Torvalds, and can be found on +kernel.org in the pub/linux/kernel/v3.x/ directory. Its development process is as follows: - As soon as a new kernel is released a two weeks window is open, during this period of time maintainers can submit big diffs to @@ -262,20 +262,20 @@ mailing list about kernel releases: released according to perceived bug status, not according to a preconceived timeline." -2.6.x.y -stable kernel tree +3.x.y -stable kernel tree --------------------------- -Kernels with 4-part versions are -stable kernels. They contain +Kernels with 3-part versions are -stable kernels. They contain relatively small and critical fixes for security problems or significant -regressions discovered in a given 2.6.x kernel. +regressions discovered in a given 3.x kernel. This is the recommended branch for users who want the most recent stable kernel and are not interested in helping test development/experimental versions. -If no 2.6.x.y kernel is available, then the highest numbered 2.6.x +If no 3.x.y kernel is available, then the highest numbered 3.x kernel is the current stable kernel. -2.6.x.y are maintained by the "stable" team , and +3.x.y are maintained by the "stable" team , and are released as needs dictate. The normal release period is approximately two weeks, but it can be longer if there are no pressing problems. A security-related problem, instead, can cause a release to happen almost @@ -285,7 +285,7 @@ The file Documentation/stable_kernel_rules.txt in the kernel tree documents what kinds of changes are acceptable for the -stable tree, and how the release process works. -2.6.x -git patches +3.x -git patches ------------------ These are daily snapshots of Linus' kernel tree which are managed in a git repository (hence the name.) These patches are usually released @@ -317,13 +317,13 @@ revisions to it, and maintainers can mark patches as under review, accepted, or rejected. Most of these patchwork sites are listed at http://patchwork.kernel.org/. -2.6.x -next kernel tree for integration tests +3.x -next kernel tree for integration tests --------------------------------------------- -Before updates from subsystem trees are merged into the mainline 2.6.x +Before updates from subsystem trees are merged into the mainline 3.x tree, they need to be integration-tested. For this purpose, a special testing repository exists into which virtually all subsystem trees are pulled on an almost daily basis: - http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git + http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git http://linux.f-seidel.de/linux-next/pmwiki/ This way, the -next kernel gives a summary outlook onto what will be From eae68611b2683cc1a9a7ca669c60a65020071004 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 27 Apr 2012 14:23:54 +0200 Subject: [PATCH 0028/2357] USB: cdc-wdm: sanitize error returns commit 24a85bae5da2b43fed423859c09c5a81ab359473 upstream. wdm_flush() returns unsanitized USB error codes. They must be cleaned up to before being anded to user space Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 0bb2b3248da..0209b467aa7 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -534,7 +534,7 @@ static int wdm_flush(struct file *file, fl_owner_t id) dev_err(&desc->intf->dev, "Error in flush path: %d\n", desc->werr); - return desc->werr; + return usb_translate_errors(desc->werr); } static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) From fccfda602805358246118c8ed991a0cb32160d0f Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 27 Apr 2012 14:36:37 +0200 Subject: [PATCH 0029/2357] USB: cdc-wdm: fix memory leak commit 2f338c8a1904e2e7aa5a8bd12fb0cf2422d17da4 upstream. cleanup() is not called if the last close() comes after disconnect(). That leads to a memory leak. Rectified by checking for an earlier disconnect() in release() Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 0209b467aa7..6bf1a404223 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -625,6 +625,8 @@ static int wdm_release(struct inode *inode, struct file *file) kill_urbs(desc); if (!test_bit(WDM_DISCONNECTING, &desc->flags)) desc->manage_power(desc->intf, 0); + else + cleanup(desc); } mutex_unlock(&wdm_mutex); return 0; From d0765ea47c9ab8466b8765ff768251b572670148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 9 May 2012 13:53:21 +0200 Subject: [PATCH 0030/2357] USB: cdc-wdm: poll must return POLLHUP if device is gone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 616b6937e348ef2b4c6ea5fef2cd3c441145efb0 upstream. Else the poll will be restarted indefinitely in a tight loop, preventing final device cleanup. Cc: Oliver Neukum Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 6bf1a404223..1fb3d3107ca 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -545,7 +545,7 @@ static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) spin_lock_irqsave(&desc->iuspin, flags); if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - mask = POLLERR; + mask = POLLHUP | POLLERR; spin_unlock_irqrestore(&desc->iuspin, flags); goto desc_out; } From 577bd3ef6eed18ea3c866b2f25b14aa5e139b41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 9 May 2012 13:53:22 +0200 Subject: [PATCH 0031/2357] USB: cdc-wdm: cannot use dev_printk when device is gone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6b0b79d38806481c1c8fffa7c5842f3c83679a42 upstream. We cannot dereference a removed USB interface for dev_printk. Use pr_debug instead where necessary. Flush errors are expected if device is unplugged and are therefore best ingored at this point. Move the kill_urbs() call in wdm_release with dev_dbg() for the non disconnect, as we know it has already been called if WDM_DISCONNECTING is set. This does not actually fix anything, but keeps the code more consistent. Cc: Oliver Neukum Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 1fb3d3107ca..c184b37ae98 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -530,7 +530,9 @@ static int wdm_flush(struct file *file, fl_owner_t id) struct wdm_device *desc = file->private_data; wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); - if (desc->werr < 0) + + /* cannot dereference desc->intf if WDM_DISCONNECTING */ + if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags)) dev_err(&desc->intf->dev, "Error in flush path: %d\n", desc->werr); @@ -621,12 +623,15 @@ static int wdm_release(struct inode *inode, struct file *file) mutex_unlock(&desc->wlock); if (!desc->count) { - dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); - kill_urbs(desc); - if (!test_bit(WDM_DISCONNECTING, &desc->flags)) + if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { + dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); + kill_urbs(desc); desc->manage_power(desc->intf, 0); - else + } else { + /* must avoid dev_printk here as desc->intf is invalid */ + pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__); cleanup(desc); + } } mutex_unlock(&wdm_mutex); return 0; From 9ed2cb7819e7df0e0fe0cce574c64e57b4806fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 9 May 2012 13:53:23 +0200 Subject: [PATCH 0032/2357] USB: cdc-wdm: remove from device list on disconnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6286d85e8efdb59252d1ceb99a56fa6b0b11526c upstream. Prevents dereferencing an invalid struct usb_interface pointer. Always delete entry from device list whether or not the rest of the device state cleanup is postponed. The device list uses desc->intf as key, and wdm_open will dereference this key while searching for a matching device. A device should not appear in the list unless probe() has succeeded and disconnect() has not finished. Cc: Oliver Neukum Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index c184b37ae98..4c8321ea4c5 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -309,9 +309,6 @@ static void free_urbs(struct wdm_device *desc) static void cleanup(struct wdm_device *desc) { - spin_lock(&wdm_device_list_lock); - list_del(&desc->device_list); - spin_unlock(&wdm_device_list_lock); kfree(desc->sbuf); kfree(desc->inbuf); kfree(desc->orq); @@ -778,6 +775,9 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor out: return rv; err: + spin_lock(&wdm_device_list_lock); + list_del(&desc->device_list); + spin_unlock(&wdm_device_list_lock); cleanup(desc); return rv; } @@ -903,6 +903,12 @@ static void wdm_disconnect(struct usb_interface *intf) cancel_work_sync(&desc->rxwork); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); + + /* the desc->intf pointer used as list key is now invalid */ + spin_lock(&wdm_device_list_lock); + list_del(&desc->device_list); + spin_unlock(&wdm_device_list_lock); + if (!desc->count) cleanup(desc); mutex_unlock(&wdm_mutex); From 24312d34c95702e51240f58c073db30630170fbf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 14 May 2012 15:04:50 -0700 Subject: [PATCH 0033/2357] workqueue: skip nr_running sanity check in worker_enter_idle() if trustee is active commit 544ecf310f0e7f51fa057ac2a295fc1b3b35a9d3 upstream. worker_enter_idle() has WARN_ON_ONCE() which triggers if nr_running isn't zero when every worker is idle. This can trigger spuriously while a cpu is going down due to the way trustee sets %WORKER_ROGUE and zaps nr_running. It first sets %WORKER_ROGUE on all workers without updating nr_running, releases gcwq->lock, schedules, regrabs gcwq->lock and then zaps nr_running. If the last running worker enters idle inbetween, it would see stale nr_running which hasn't been zapped yet and trigger the WARN_ON_ONCE(). Fix it by performing the sanity check iff the trustee is idle. Signed-off-by: Tejun Heo Reported-by: "Paul E. McKenney" Signed-off-by: Greg Kroah-Hartman --- kernel/workqueue.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 5abf42f63c0..7da267c8d0d 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1210,8 +1210,13 @@ static void worker_enter_idle(struct worker *worker) } else wake_up_all(&gcwq->trustee_wait); - /* sanity check nr_running */ - WARN_ON_ONCE(gcwq->nr_workers == gcwq->nr_idle && + /* + * Sanity check nr_running. Because trustee releases gcwq->lock + * between setting %WORKER_ROGUE and zapping nr_running, the + * warning may trigger spuriously. Check iff trustee is idle. + */ + WARN_ON_ONCE(gcwq->trustee_state == TRUSTEE_DONE && + gcwq->nr_workers == gcwq->nr_idle && atomic_read(get_gcwq_nr_running(gcwq->cpu))); } From ab9094fa038106675b40dbb5ee78b60255d6c436 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 23 May 2012 12:48:13 +0100 Subject: [PATCH 0034/2357] mm: mempolicy: Let vma_merge and vma_split handle vma->vm_policy linkages commit 05f144a0d5c2207a0349348127f996e104ad7404 upstream. Dave Jones' system call fuzz testing tool "trinity" triggered the following bug error with slab debugging enabled ============================================================================= BUG numa_policy (Not tainted): Poison overwritten ----------------------------------------------------------------------------- INFO: 0xffff880146498250-0xffff880146498250. First byte 0x6a instead of 0x6b INFO: Allocated in mpol_new+0xa3/0x140 age=46310 cpu=6 pid=32154 __slab_alloc+0x3d3/0x445 kmem_cache_alloc+0x29d/0x2b0 mpol_new+0xa3/0x140 sys_mbind+0x142/0x620 system_call_fastpath+0x16/0x1b INFO: Freed in __mpol_put+0x27/0x30 age=46268 cpu=6 pid=32154 __slab_free+0x2e/0x1de kmem_cache_free+0x25a/0x260 __mpol_put+0x27/0x30 remove_vma+0x68/0x90 exit_mmap+0x118/0x140 mmput+0x73/0x110 exit_mm+0x108/0x130 do_exit+0x162/0xb90 do_group_exit+0x4f/0xc0 sys_exit_group+0x17/0x20 system_call_fastpath+0x16/0x1b INFO: Slab 0xffffea0005192600 objects=27 used=27 fp=0x (null) flags=0x20000000004080 INFO: Object 0xffff880146498250 @offset=592 fp=0xffff88014649b9d0 This implied a reference counting bug and the problem happened during mbind(). mbind() applies a new memory policy to a range and uses mbind_range() to merge existing VMAs or split them as necessary. In the event of splits, mpol_dup() will allocate a new struct mempolicy and maintain existing reference counts whose rules are documented in Documentation/vm/numa_memory_policy.txt . The problem occurs with shared memory policies. The vm_op->set_policy increments the reference count if necessary and split_vma() and vma_merge() have already handled the existing reference counts. However, policy_vma() screws it up by replacing an existing vma->vm_policy with one that potentially has the wrong reference count leading to a premature free. This patch removes the damage caused by policy_vma(). With this patch applied Dave's trinity tool runs an mbind test for 5 minutes without error. /proc/slabinfo reported that there are no numa_policy or shared_policy_node objects allocated after the test completed and the shared memory region was deleted. Signed-off-by: Mel Gorman Cc: Dave Jones Cc: KOSAKI Motohiro Cc: Stephen Wilson Cc: Christoph Lameter Cc: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index b1956913752..bf5b485ecd3 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -607,27 +607,6 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, return first; } -/* Apply policy to a single VMA */ -static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new) -{ - int err = 0; - struct mempolicy *old = vma->vm_policy; - - pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff, - vma->vm_ops, vma->vm_file, - vma->vm_ops ? vma->vm_ops->set_policy : NULL); - - if (vma->vm_ops && vma->vm_ops->set_policy) - err = vma->vm_ops->set_policy(vma, new); - if (!err) { - mpol_get(new); - vma->vm_policy = new; - mpol_put(old); - } - return err; -} - /* Step 2: apply policy to a range and do splits. */ static int mbind_range(struct mm_struct *mm, unsigned long start, unsigned long end, struct mempolicy *new_pol) @@ -676,9 +655,23 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, if (err) goto out; } - err = policy_vma(vma, new_pol); - if (err) - goto out; + + /* + * Apply policy to a single VMA. The reference counting of + * policy for vma_policy linkages has already been handled by + * vma_merge and split_vma as necessary. If this is a shared + * policy then ->set_policy will increment the reference count + * for an sp node. + */ + pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n", + vma->vm_start, vma->vm_end, vma->vm_pgoff, + vma->vm_ops, vma->vm_file, + vma->vm_ops ? vma->vm_ops->set_policy : NULL); + if (vma->vm_ops && vma->vm_ops->set_policy) { + err = vma->vm_ops->set_policy(vma, new_pol); + if (err) + goto out; + } } out: From 51c75d344b36152159b19466964dab4ae1a19fcd Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 21 May 2012 09:26:59 +1000 Subject: [PATCH 0035/2357] md: using GFP_NOIO to allocate bio for flush request commit b5e1b8cee7ad58a15d2fa79bcd7946acb592602d upstream. A flush request is usually issued in transaction commit code path, so using GFP_KERNEL to allocate memory for flush request bio falls into the classic deadlock issue. This is suitable for any -stable kernel to which it applies as it avoids a possible deadlock. Signed-off-by: Shaohua Li Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 01233d855eb..2b30ffdb81b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -452,7 +452,7 @@ static void submit_flushes(struct work_struct *ws) atomic_inc(&rdev->nr_pending); atomic_inc(&rdev->nr_pending); rcu_read_unlock(); - bi = bio_alloc_mddev(GFP_KERNEL, 0, mddev); + bi = bio_alloc_mddev(GFP_NOIO, 0, mddev); bi->bi_end_io = md_end_flush; bi->bi_private = rdev; bi->bi_bdev = rdev->bdev; From 2fa8ba3d8d0f49c4b087a026889a1154c3d94901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Thu, 3 May 2012 11:37:12 +0200 Subject: [PATCH 0036/2357] Add missing call to uart_update_timeout() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8b979f7c6bf13a57e7b6002f1175312a44773960 upstream. This patch fixes a problem reported here: http://article.gmane.org/gmane.linux.ports.arm.kernel/155242/match=auart Signed-off-by: Lothar Waßmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mxs-auart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 55fd362b987..039c054349e 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -369,6 +369,8 @@ static void mxs_auart_settermios(struct uart_port *u, writel(ctrl, u->membase + AUART_LINECTRL); writel(ctrl2, u->membase + AUART_CTRL2); + + uart_update_timeout(u, termios->c_cflag, baud); } static irqreturn_t mxs_auart_irq_handle(int irq, void *context) From b4bc0181430409b4ffbac0da0a286b1ea0a91dfe Mon Sep 17 00:00:00 2001 From: Christian Melki Date: Mon, 30 Apr 2012 11:21:26 +0200 Subject: [PATCH 0037/2357] 8250.c: less than 2400 baud fix. commit f9a9111b540fd67db5dab332f4b83d86c90e27b1 upstream. We noticed that we were loosing data at speed less than 2400 baud. It turned out our (TI16750 compatible) uart with 64 byte outgoing fifo was truncated to 16 byte (bit 5 sets fifo len) when modifying the fcr reg. The input code still fills the buffer with 64 bytes if I remember correctly and thus data is lost. Our fix was to remove whiping of the fcr content and just add the TRIGGER_1 which we want for latency. I can't see why this would not work on less than 2400 always, for all uarts ... Otherwise one would have to make sure the filling of the fifo re-checks the current state of available fifo size (urrk). Signed-off-by: Christian Melki Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 5c27f7e6c9f..d537431d7e2 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -2280,10 +2280,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, quot++; if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { - if (baud < 2400) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; - else - fcr = uart_config[port->type].fcr; + fcr = uart_config[port->type].fcr; + if (baud < 2400) { + fcr &= ~UART_FCR_TRIGGER_MASK; + fcr |= UART_FCR_TRIGGER_1; + } } /* From 0b3539aad80702d68bcc3211fb4f5779f84d9d75 Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Wed, 25 Apr 2012 12:17:24 +0200 Subject: [PATCH 0038/2357] 8250_pci: fix pch uart matching commit aaa10eb1d0034eccc096f583fe308f0921617598 upstream. The rules used to make 8250_pci "ignore" the PCH uarts are lacking pci subids entries, preventing it to match and thus is breaking serial port support for theses systems. This has been tested on a nanoETXexpress-TT, which has a specifici uart clock. Tested-by: Erwan Velu [stable@: please apply to 3.0-stable, 3.2-stable and 3.3-stable] Signed-off-by: Arnaud Patard Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 858dca865d6..3614973c999 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1609,54 +1609,72 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8811, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8812, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8813, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8814, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x8027, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x8028, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x8029, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x800C, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x800D, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, From d0afed68fb1d586034be7a7e038488e83c37a89f Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 14 May 2012 14:51:22 +0100 Subject: [PATCH 0039/2357] tty: Allow uart_register/unregister/register commit 1e66cded334e6cea596c72f6f650eec351b1e959 upstream. This is legitimate but because we don't clear the drv->state pointer in the unregister code causes a bogus BUG(). Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=42880 Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 9c4c05b2825..246b823c1b2 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv) tty_unregister_driver(p); put_tty_driver(p); kfree(drv->state); + drv->state = NULL; drv->tty_driver = NULL; } From 27234cee48f54e3f3125e44bc8b05c42b977a113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Piel?= Date: Mon, 7 May 2012 12:37:54 +0200 Subject: [PATCH 0040/2357] USB: ftdi-sio: add support for Physik Instrumente E-861 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b69cc672052540e8efb1368420f10d7d4d8b8a3d upstream. This adds VID/PID for the PI E-861. Without it, I had to do: modprobe -q ftdi-sio product=0x1008 vendor=0x1a72 http://www.physikinstrumente.com/en/products/prdetail.php?sortnr=900610 Signed-off-by: Éric Piel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 02e7f2d32d5..95bba992416 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -809,6 +809,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, + { USB_DEVICE(PI_VID, PI_E861_PID) }, { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 0838baf892f..f3c7c78ede3 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -785,6 +785,14 @@ #define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ #define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ + +/* + * Physik Instrumente + * http://www.physikinstrumente.com/en/products/ + */ +#define PI_VID 0x1a72 /* Vendor ID */ +#define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */ + /* * Bayer Ascensia Contour blood glucose meter USB-converter cable. * http://winglucofacts.com/cables/ From 2aa5c3521c154db6e3bbbda1a2f0b07da4938626 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 7 May 2012 11:20:06 -0400 Subject: [PATCH 0041/2357] usb-serial: ftdi_sio: fix oops during autosuspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5cbe61c5aff0a8ada691eb8b07dbfb55c303f640 upstream. This patch (as1550) fixes a bug in the usb-serial core that affects the ftdi_sio driver and most likely others as well. The core implements suspend and resume routines, but it doesn't store pointers to those routines in the usb_driver structures that it registers, even though it does set those drivers' supports_autosuspend flag. The end result is that when one of these devices is autosuspended, we try to call through a NULL pointer. The patch fixes the problem by setting the suspend and resume method pointers to the appropriate routines in the USB serial core, along with the supports_autosuspend field, in each driver as it is registered. This should be back-ported to all the stable kernels that have the new usb_serial_register_drivers() interface. Signed-off-by: Alan Stern Reported-and-tested-by: Frank Schäfer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 97355a15bbe..6933355c964 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1338,7 +1338,6 @@ static int usb_serial_register(struct usb_serial_driver *driver) driver->description); return -EINVAL; } - driver->usb_driver->supports_autosuspend = 1; /* Add this device to our list of devices */ mutex_lock(&table_lock); @@ -1373,7 +1372,7 @@ static void usb_serial_deregister(struct usb_serial_driver *device) * @serial_drivers: NULL-terminated array of pointers to drivers to be registered * * Registers @udriver and all the drivers in the @serial_drivers array. - * Automatically fills in the .no_dynamic_id field in @udriver and + * Automatically fills in the .no_dynamic_id and PM fields in @udriver and * the .usb_driver field in each serial driver. */ int usb_serial_register_drivers(struct usb_driver *udriver, @@ -1392,11 +1391,17 @@ int usb_serial_register_drivers(struct usb_driver *udriver, * the serial drivers are registered, because the probe would * simply fail for lack of a matching serial driver. * Therefore save off udriver's id_table until we are all set. + * + * Suspend/resume support is implemented in the usb-serial core, + * so fill in the PM-related fields in udriver. */ saved_id_table = udriver->id_table; udriver->id_table = NULL; udriver->no_dynamic_id = 1; + udriver->supports_autosuspend = 1; + udriver->suspend = usb_serial_suspend; + udriver->resume = usb_serial_resume; rc = usb_register(udriver); if (rc) return rc; From f5872d789e93efed59705b849de8b665c48d6b75 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 8 May 2012 15:15:25 -0400 Subject: [PATCH 0042/2357] usb-storage: unusual_devs entry for Yarvik PMP400 MP4 player commit df767b71e5816692134d59c0c17e0f77cd73333d upstream. This patch (as1553) adds an unusual_dev entrie for the Yarvik PMP400 MP4 music player. Signed-off-by: Alan Stern Reported-by: Jesse Feddema Tested-by: Jesse Feddema Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 856ad92c40d..8f3cbb8dc81 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1885,6 +1885,13 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Jesse Feddema */ +UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000, + "Yarvik", + "PMP400", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ), + /* Reported by Hans de Goede * These Appotech controllers are found in Picture Frames, they provide a * (buggy) emulation of a cdrom drive which contains the windows software From faf7fee9add05c8cebc2e7c8e6ff3feea364b868 Mon Sep 17 00:00:00 2001 From: Matthias Fend Date: Mon, 7 May 2012 14:37:30 +0200 Subject: [PATCH 0043/2357] USB: ffs-test: fix length argument of out function call commit eb9c5836384cd2a276254df6254ed71117983626 upstream. The out functions should only handle actual available data instead of the complete buffer. Otherwise for example the ep0_consume function will report ghost events since it tries to decode the complete buffer - which may contain partly invalid data. Signed-off-by: Matthias Fend Acked-by: Michal Nazarewicz Signed-off-by: Greg Kroah-Hartman --- tools/usb/ffs-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c index 4b107b5e623..8674b9ec14f 100644 --- a/tools/usb/ffs-test.c +++ b/tools/usb/ffs-test.c @@ -297,7 +297,7 @@ static void *start_thread_helper(void *arg) ret = t->in(t, t->buf, t->buf_size); if (ret > 0) { - ret = t->out(t, t->buf, t->buf_size); + ret = t->out(t, t->buf, ret); name = out_name; op = "write"; } else { From 0053c7e96ee9a516e7e8499f6fc28c0d9c43d40c Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Mon, 16 Apr 2012 14:19:07 -0700 Subject: [PATCH 0044/2357] usb: usbtest: two super speed fixes for usbtest commit 6a23ccd216b6a8ba2c67a9f9d8969b4431ad2920 upstream. bMaxPacketSize0 field for super speed is a power of 2, not a count. The size itself is always 512. Max packet size for a super speed bulk endpoint is 1024, so allocate the urb size in halt_simple() accordingly. Signed-off-by: Paul Zimmerman Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbtest.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 9dcb68f04f0..055b84adeda 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -1028,7 +1028,10 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param) case 13: /* short read, resembling case 10 */ req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0); /* last data packet "should" be DATA1, not DATA0 */ - len = 1024 - udev->descriptor.bMaxPacketSize0; + if (udev->speed == USB_SPEED_SUPER) + len = 1024 - 512; + else + len = 1024 - udev->descriptor.bMaxPacketSize0; expected = -EREMOTEIO; break; case 14: /* short read; try to fill the last packet */ @@ -1387,11 +1390,15 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb) static int halt_simple(struct usbtest_dev *dev) { - int ep; - int retval = 0; - struct urb *urb; + int ep; + int retval = 0; + struct urb *urb; + struct usb_device *udev = testdev_to_usbdev(dev); - urb = simple_alloc_urb(testdev_to_usbdev(dev), 0, 512); + if (udev->speed == USB_SPEED_SUPER) + urb = simple_alloc_urb(udev, 0, 1024); + else + urb = simple_alloc_urb(udev, 0, 512); if (urb == NULL) return -ENOMEM; From 54c6b536f2c7ebc77f74937c3f4789ef191aa479 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Fri, 18 May 2012 20:29:56 +0200 Subject: [PATCH 0045/2357] USB: ehci-platform: remove update_device commit 8377c94f627f7943da9a7eefdb21fd2e9e7ec629 upstream. The update_device callback is not needed and the function used here is from the pci ehci driver. Without this patch we get a compile error if ehci-platform is compiled without ehci-pci. Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-platform.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index d238b4e24bb..82c1eb8b18d 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -75,8 +75,6 @@ static const struct hc_driver ehci_platform_hc_driver = { .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, - .update_device = ehci_update_device, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; From ada3a3d0cb75f4cb015a2521badcffcf6d16ba45 Mon Sep 17 00:00:00 2001 From: Russ Dill Date: Fri, 4 May 2012 04:24:47 -0700 Subject: [PATCH 0046/2357] USB: EHCI: OMAP: Finish ehci omap phy reset cycle before adding hcd. commit 3aa2ae74ba630ec9b98736d64aea8e4cb490861d upstream. 'ARM: OMAP3: USB: Fix the EHCI ULPI PHY reset issue' (1fcb57d0f) created a regression with Beagleboard xM if booting the kernel after running 'usb start' under u-boot. Finishing the reset before calling 'usb_add_hcd' fixes the regression. This is most likely due to usb_add_hcd calling the driver's reset and init functions which expect the hardware to be up and running. Signed-off-by: Russ Dill Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-omap.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 5c78f9e7146..e669c6a7e91 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -242,15 +242,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) ehci_reset(omap_ehci); - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) { - dev_err(dev, "failed to add hcd with err %d\n", ret); - goto err_add_hcd; - } - - /* root ports should always stay powered */ - ehci_port_power(omap_ehci, 1); - if (pdata->phy_reset) { /* Hold the PHY in RESET for enough time till * PHY is settled and ready @@ -264,6 +255,15 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) gpio_set_value(pdata->reset_gpio_port[1], 1); } + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(dev, "failed to add hcd with err %d\n", ret); + goto err_add_hcd; + } + + /* root ports should always stay powered */ + ehci_port_power(omap_ehci, 1); + return 0; err_add_hcd: From 658b069b7c6b5d91cd89a24dde34ec91918f6e25 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Thu, 10 May 2012 10:31:21 +0900 Subject: [PATCH 0047/2357] USB: gpio_vbus: provide an appropriate debounce interval commit 934ccec4da14dc0586dfe08b36166364bdd2181b upstream. In commit c2344f13b59e007d782a3e591ebc551bc583a8b7 (USB: gpio_vbus: add delayed vbus_session calls, 2009-01-24), usb_gadget_vbus_connect() and ...disconnect() were extracted from the interrupt handler, so to allow vbus_session handlers to deal with msleep() calls. This patch takes the approach one step further. USB2.0 specification (7.1.7.3 Connect and Disconnect Signaling) says that the USB system software (shall) provide a debounce interval with a minimum duration of 100 ms, which ensures that the electrical and mechanical connection is stable before software attempts to reset the attached device. Signed-off-by: Shinya Kuribayashi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/otg/gpio_vbus.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c index a0a2178974f..fe208643a74 100644 --- a/drivers/usb/otg/gpio_vbus.c +++ b/drivers/usb/otg/gpio_vbus.c @@ -37,7 +37,7 @@ struct gpio_vbus_data { struct regulator *vbus_draw; int vbus_draw_enabled; unsigned mA; - struct work_struct work; + struct delayed_work work; }; @@ -94,7 +94,7 @@ static int is_vbus_powered(struct gpio_vbus_mach_info *pdata) static void gpio_vbus_work(struct work_struct *work) { struct gpio_vbus_data *gpio_vbus = - container_of(work, struct gpio_vbus_data, work); + container_of(work, struct gpio_vbus_data, work.work); struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data; int gpio, status; @@ -152,7 +152,7 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data) otg->gadget ? otg->gadget->name : "none"); if (otg->gadget) - schedule_work(&gpio_vbus->work); + schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100)); return IRQ_HANDLED; } @@ -300,7 +300,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier); - INIT_WORK(&gpio_vbus->work, gpio_vbus_work); + INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work); gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw"); if (IS_ERR(gpio_vbus->vbus_draw)) { From 33c3504a085337d80750d2ab68e8ea2127b63ba5 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 9 May 2012 10:48:54 +0200 Subject: [PATCH 0048/2357] USB: ohci-at91: add a reset function to fix race condition commit 07e4e556eff4938eb2edf2591de3aa7d7fb82b52 upstream. A possible race condition appears because we are not initializing the ohci->regs before calling usb_hcd_request_irqs(). We move the call to ohci_init() in hcd->driver->reset() instead of hcd->driver->start() to fix this. This was experienced when we share the same IRQ line between OHCI and EHCI controllers. Signed-off-by: Nicolas Ferre Tested-by: Christian Eggers Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 13ebeca8e73..55d3d641447 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -223,7 +223,7 @@ static void __devexit usb_hcd_at91_remove(struct usb_hcd *hcd, /*-------------------------------------------------------------------------*/ static int __devinit -ohci_at91_start (struct usb_hcd *hcd) +ohci_at91_reset (struct usb_hcd *hcd) { struct at91_usbh_data *board = hcd->self.controller->platform_data; struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -233,6 +233,14 @@ ohci_at91_start (struct usb_hcd *hcd) return ret; ohci->num_ports = board->ports; + return 0; +} + +static int __devinit +ohci_at91_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; if ((ret = ohci_run(ohci)) < 0) { err("can't start %s", hcd->self.bus_name); @@ -418,6 +426,7 @@ static const struct hc_driver ohci_at91_hc_driver = { /* * basic lifecycle operations */ + .reset = ohci_at91_reset, .start = ohci_at91_start, .stop = ohci_stop, .shutdown = ohci_shutdown, From c84ac3a2f033f13f55e737b4b9e3395b66c523d4 Mon Sep 17 00:00:00 2001 From: Huajun Li Date: Fri, 18 May 2012 20:12:51 +0800 Subject: [PATCH 0049/2357] USB: Remove races in devio.c commit 4e09dcf20f7b5358615514c2ec8584b248ab8874 upstream. There exist races in devio.c, below is one case, and there are similar races in destroy_async() and proc_unlinkurb(). Remove these races. cancel_bulk_urbs() async_completed() ------------------- ----------------------- spin_unlock(&ps->lock); list_move_tail(&as->asynclist, &ps->async_completed); wake_up(&ps->wait); Lead to free_async() be triggered, then urb and 'as' will be freed. usb_unlink_urb(as->urb); ===> refer to the freed 'as' Signed-off-by: Huajun Li Cc: Alan Stern Cc: Oncaphillis Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 8df4b76465a..4e577728ead 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -333,17 +333,14 @@ static struct async *async_getcompleted(struct dev_state *ps) static struct async *async_getpending(struct dev_state *ps, void __user *userurb) { - unsigned long flags; struct async *as; - spin_lock_irqsave(&ps->lock, flags); list_for_each_entry(as, &ps->async_pending, asynclist) if (as->userurb == userurb) { list_del_init(&as->asynclist); - spin_unlock_irqrestore(&ps->lock, flags); return as; } - spin_unlock_irqrestore(&ps->lock, flags); + return NULL; } @@ -398,6 +395,7 @@ static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr) __releases(ps->lock) __acquires(ps->lock) { + struct urb *urb; struct async *as; /* Mark all the pending URBs that match bulk_addr, up to but not @@ -420,8 +418,11 @@ __acquires(ps->lock) list_for_each_entry(as, &ps->async_pending, asynclist) { if (as->bulk_status == AS_UNLINK) { as->bulk_status = 0; /* Only once */ + urb = as->urb; + usb_get_urb(urb); spin_unlock(&ps->lock); /* Allow completions */ - usb_unlink_urb(as->urb); + usb_unlink_urb(urb); + usb_put_urb(urb); spin_lock(&ps->lock); goto rescan; } @@ -472,6 +473,7 @@ static void async_completed(struct urb *urb) static void destroy_async(struct dev_state *ps, struct list_head *list) { + struct urb *urb; struct async *as; unsigned long flags; @@ -479,10 +481,13 @@ static void destroy_async(struct dev_state *ps, struct list_head *list) while (!list_empty(list)) { as = list_entry(list->next, struct async, asynclist); list_del_init(&as->asynclist); + urb = as->urb; + usb_get_urb(urb); /* drop the spinlock so the completion handler can run */ spin_unlock_irqrestore(&ps->lock, flags); - usb_kill_urb(as->urb); + usb_kill_urb(urb); + usb_put_urb(urb); spin_lock_irqsave(&ps->lock, flags); } spin_unlock_irqrestore(&ps->lock, flags); @@ -1410,12 +1415,24 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) static int proc_unlinkurb(struct dev_state *ps, void __user *arg) { + struct urb *urb; struct async *as; + unsigned long flags; + spin_lock_irqsave(&ps->lock, flags); as = async_getpending(ps, arg); - if (!as) + if (!as) { + spin_unlock_irqrestore(&ps->lock, flags); return -EINVAL; - usb_kill_urb(as->urb); + } + + urb = as->urb; + usb_get_urb(urb); + spin_unlock_irqrestore(&ps->lock, flags); + + usb_kill_urb(urb); + usb_put_urb(urb); + return 0; } From 3c8e06de9d7d35461601d987605d091d3c817fba Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 11 May 2012 13:56:57 -0700 Subject: [PATCH 0050/2357] USB: serial: ti_usb_3410_5052: Add support for the FRI2 serial console commit 975dc33b82cb887d75a29b1e3835c8eb063a8e99 upstream. The Kontron M2M development board, also known as the Fish River Island II, has an optional daughter card providing access to the PCH_UART (EG20T) via a ti_usb_3410_5052 uart to usb chip. http://us.kontron.com/products/systems+and+platforms/m2m/m2m+smart+services+developer+kit.html Signed-off-by: Darren Hart CC: Al Borchers CC: Peter Berger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ti_usb_3410_5052.c | 6 ++++-- drivers/usb/serial/ti_usb_3410_5052.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index ab74123d658..3377437550d 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -165,7 +165,7 @@ static unsigned int product_5052_count; /* the array dimension is the number of default entries plus */ /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ /* null entry */ -static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -180,6 +180,7 @@ static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, }; static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { @@ -189,7 +190,7 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, }; -static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -208,6 +209,7 @@ static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, { } }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index f140f1b9d5c..b353e7e3d48 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -37,6 +37,7 @@ #define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */ #define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */ #define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */ +#define FRI2_PRODUCT_ID 0x5053 /* Fish River Island II */ /* Multi-Tech vendor and product ids */ #define MTS_VENDOR_ID 0x06E0 From 66595c7dabba38c4ad40bad992c3f612b75a9f71 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Sun, 1 Apr 2012 15:17:16 +0800 Subject: [PATCH 0051/2357] usb: gadget: fsl_udc_core: dTD's next dtd pointer need to be updated once written commit 4d0947dec4db1224354e2f6f00ae22ce38e62a43 upstream. dTD's next dtd pointer need to be updated once CPU writes it, or this request may not be handled by controller, then host will get NAK from device forever. This problem occurs when there is a request is handling, we need to add a new request to dTD list, if this new request is added before the current one is finished, the new request is intended to added as next dtd pointer at current dTD, but without wmb(), the dTD's next dtd pointer may not be updated when the controller reads it. In that case, the controller will still get Terminate Bit is 1 at dTD's next dtd pointer, that means there is no next request, then this new request is missed by controller. Signed-off-by: Peter Chen Acked-by: Li Yang Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/fsl_udc_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 55abfb6bd61..188a89f9514 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -736,6 +736,8 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) lastreq = list_entry(ep->queue.prev, struct fsl_req, queue); lastreq->tail->next_td_ptr = cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK); + /* Ensure dTD's next dtd pointer to be updated */ + wmb(); /* Read prime bit, if 1 goto done */ if (fsl_readl(&dr_regs->endpointprime) & bitmask) return; From be89311ce0799bba12f6b9f73228c2b264074a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffen=20M=C3=BCller?= Date: Mon, 30 Apr 2012 13:05:34 +0200 Subject: [PATCH 0052/2357] usb: add USB_QUIRK_RESET_RESUME for M-Audio 88es MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 166cb70e97bd83d7ae9bbec6ae59a178fd9bb823 upstream. Tested-by: Steffen Müller Signed-off-by: Steffen Müller Signed-off-by: Stefan Seyfried Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 4c65eb6a867..32d3adc315f 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -123,6 +123,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Guillemot Webcam Hercules Dualpix Exchange*/ { USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Midiman M-Audio Keystation 88es */ + { USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME }, + /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, From ce5833387ab9481e2d83939a4a36203e3461ef73 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 9 Feb 2012 15:55:13 -0800 Subject: [PATCH 0053/2357] xhci: Add Lynx Point to list of Intel switchable hosts. commit 1c12443ab8eba71a658fae4572147e56d1f84f66 upstream. The upcoming Intel Lynx Point chipset includes an xHCI host controller that can have ports switched from the EHCI host controller, just like the Intel Panther Point xHCI host. This time, ports from both EHCI hosts can be switched to the xHCI host controller. The PCI config registers to do the port switching are in the exact same place in the xHCI PCI configuration registers, with the same semantics. Hooray for shipping patches for next-gen hardware before the current gen hardware is even available for purchase! This patch should be backported to stable kernels as old as 3.0, that contain commit 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support EHCI/xHCI port switching." Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 4 +++- drivers/usb/host/pci-quirks.c | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index fe8dc069164..bc94d7bf072 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -368,7 +368,9 @@ static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) { return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == 0x1E26; + (pdev->device == 0x1E26 || + pdev->device == 0x8C2D || + pdev->device == 0x8C26); } static void ehci_enable_xhci_companion(void) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 32dada8c8b4..4e68720709a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -712,12 +712,28 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, return -ETIMEDOUT; } -bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) +#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31 + +bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev) { return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI; } + +/* The Intel Lynx Point chipset also has switchable ports. */ +bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev) +{ + return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && + pdev->vendor == PCI_VENDOR_ID_INTEL && + pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI; +} + +bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) +{ + return usb_is_intel_ppt_switchable_xhci(pdev) || + usb_is_intel_lpt_switchable_xhci(pdev); +} EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); /* From 296b8ce71ac3c48cd43d9373b444d9856cfeebff Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Sat, 14 Apr 2012 02:54:30 +0800 Subject: [PATCH 0054/2357] xHCI: keep track of ports being resumed and indicate in hub_status_data commit f370b9968a220a3d79d870dd7dee674cc0ff3d10 upstream. This commit adds a bit-array to xhci bus_state for keeping track of which ports are undergoing a resume transition. If any of the bits are set when xhci_hub_status_data() is called, the routine will return a non-zero value even if no ports have any status changes pending. This will allow usbcore to handle races between root-hub suspend and port wakeup. This patch should be backported to kernels as old as 3.4, that contain the commit 879d38e6bc36d73b0ac40ec9b0d839fda9fa8b1a "USB: fix race between root-hub suspend and remote wakeup". Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 22 ++++++++++++---------- drivers/usb/host/xhci-ring.c | 1 + drivers/usb/host/xhci.c | 12 ++++++++++-- drivers/usb/host/xhci.h | 2 ++ 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 673ad120c43..89850a82d51 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -558,6 +558,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_dbg(xhci, "Resume USB2 port %d\n", wIndex + 1); bus_state->resume_done[wIndex] = 0; + clear_bit(wIndex, &bus_state->resuming_ports); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); xhci_dbg(xhci, "set port %d resume\n", @@ -845,7 +846,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) /* Initial status is no changes */ retval = (max_ports + 8) / 8; memset(buf, 0, retval); - status = 0; + + /* + * Inform the usbcore about resume-in-progress by returning + * a non-zero value even if there are no status changes. + */ + status = bus_state->resuming_ports; mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC; @@ -885,15 +891,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd) spin_lock_irqsave(&xhci->lock, flags); if (hcd->self.root_hub->do_remote_wakeup) { - port_index = max_ports; - while (port_index--) { - if (bus_state->resume_done[port_index] != 0) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "suspend failed because " - "port %d is resuming\n", - port_index + 1); - return -EBUSY; - } + if (bus_state->resuming_ports) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "suspend failed because " + "a port is resuming\n"); + return -EBUSY; } } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3d9422f16a2..cb1de111dae 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1377,6 +1377,7 @@ static void handle_port_status(struct xhci_hcd *xhci, xhci_dbg(xhci, "resume HS port %d\n", port_id); bus_state->resume_done[faked_port_index] = jiffies + msecs_to_jiffies(20); + set_bit(faked_port_index, &bus_state->resuming_ports); mod_timer(&hcd->rh_timer, bus_state->resume_done[faked_port_index]); /* Do the rest in GetPortStatus */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 36641a7f237..5910048b0a2 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -152,7 +152,7 @@ int xhci_reset(struct xhci_hcd *xhci) { u32 command; u32 state; - int ret; + int ret, i; state = xhci_readl(xhci, &xhci->op_regs->status); if ((state & STS_HALT) == 0) { @@ -175,7 +175,15 @@ int xhci_reset(struct xhci_hcd *xhci) * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. */ - return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); + ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); + + for (i = 0; i < 2; ++i) { + xhci->bus_state[i].port_c_suspend = 0; + xhci->bus_state[i].suspended_ports = 0; + xhci->bus_state[i].resuming_ports = 0; + } + + return ret; } #ifdef CONFIG_PCI diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3d69c4b2b54..ce1edd7246a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1362,6 +1362,8 @@ struct xhci_bus_state { u32 suspended_ports; u32 port_remote_wakeup; unsigned long resume_done[USB_MAXCHILDREN]; + /* which ports have started to resume */ + unsigned long resuming_ports; }; static inline unsigned int hcd_index(struct usb_hcd *hcd) From e6842282219e127d1ef3d6346082ab80214bbcbf Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 16 Apr 2012 10:56:47 -0700 Subject: [PATCH 0055/2357] xhci: Avoid dead ports when CONFIG_USB_XHCI_HCD=n commit 51c9e6c7732b67769c0a514d31f505e49fa82dd4 upstream. If the user chooses to say "no" to CONFIG_USB_XHCI_HCD on a system with an Intel Panther Point chipset, the PCI quirks code or the EHCI driver will switch the ports over to the xHCI host, but the xHCI driver will never load. The ports will be powered off and seem "dead" to the user. Fix this by only switching the ports over if CONFIG_USB_XHCI_HCD is either compiled in, or compiled as a module. This patch should be backported to stable kernels as old as 3.0, that contain commit 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support EHCI/xHCI port switching." Signed-off-by: Sarah Sharp Reported-by: Eric Anholt Reported-by: David Bein Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 4e68720709a..df0828cb2aa 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -758,6 +759,19 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) { u32 ports_available; + /* Don't switchover the ports if the user hasn't compiled the xHCI + * driver. Otherwise they will see "dead" USB ports that don't power + * the devices. + */ + if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) { + dev_warn(&xhci_pdev->dev, + "CONFIG_USB_XHCI_HCD is turned off, " + "defaulting to EHCI.\n"); + dev_warn(&xhci_pdev->dev, + "USB 3.0 devices will work at USB 2.0 speeds.\n"); + return; + } + ports_available = 0xffffffff; /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable * Register, to turn on SuperSpeed terminations for all From a3cb26c10b08940959884d8f35097ecbb4bbac9d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Apr 2012 15:06:09 +0200 Subject: [PATCH 0056/2357] usb-xhci: Handle COMP_TX_ERR for isoc tds commit 9c745995ae5c4ff787f34a359de908facc11ee00 upstream. While testing unplugging an UVC HD webcam with usb-redirection (so through usbdevfs), my userspace usb-redir code was getting a value of -1 in iso_frame_desc[n].status, which according to Documentation/usb/error-codes.txt is not a valid value. The source of this -1 is the default case in xhci-ring.c:process_isoc_td() adding a kprintf there showed the value of trb_comp_code to be COMP_TX_ERR in this case, so this patch adds handling for that completion code to process_isoc_td(). This was observed and tested with the following xhci controller: 1033:0194 NEC Corporation uPD720200 USB 3.0 Host Controller (rev 04) Note: I also wonder if setting frame->status to -1 (-EPERM) is the best we can do, but since I cannot come up with anything better I've left that as is. This patch should be backported to kernels as old as 2.6.36, which contain the commit 04e51901dd44f40a5a385ced897f6bca87d5f40a "USB: xHCI: Isochronous transfer implementation". Signed-off-by: Hans de Goede Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index cb1de111dae..d40194c8ca6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1804,6 +1804,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, break; case COMP_DEV_ERR: case COMP_STALL: + case COMP_TX_ERR: frame->status = -EPROTO; skip_td = true; break; From c9022f1306507d81a527c86ec756c938c3b8bc70 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 8 May 2012 07:09:26 -0700 Subject: [PATCH 0057/2357] xhci: Reset reserved command ring TRBs on cleanup. commit 33b2831ac870d50cc8e01c317b07fb1e69c13fe1 upstream. When the xHCI driver needs to clean up memory (perhaps due to a failed register restore on resume from S3 or resume from S4), it needs to reset the number of reserved TRBs on the command ring to zero. Otherwise, several resume cycles (about 30) with a UAS device attached will continually increment the number of reserved TRBs, until all command submissions fail because there isn't enough room on the command ring. This patch should be backported to kernels as old as 2.6.32, that contain the commit 913a8a344ffcaf0b4a586d6662a2c66a7106557d "USB: xhci: Change how xHCI commands are handled." Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 68eaa908ac8..3c9bb3db8ec 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1807,6 +1807,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->event_ring = NULL; xhci_dbg(xhci, "Freed event ring\n"); + xhci->cmd_ring_reserved_trbs = 0; if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; From 587c53c66ccee465f78d4d23c75aa9e4899597af Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 8 May 2012 09:22:49 -0700 Subject: [PATCH 0058/2357] xhci: Add new short TX quirk for Fresco Logic host. commit 1530bbc6272d9da1e39ef8e06190d42c13a02733 upstream. Sergio reported that when he recorded audio from a USB headset mic plugged into the USB 3.0 port on his ASUS N53SV-DH72, the audio sounded "robotic". When plugged into the USB 2.0 port under EHCI on the same laptop, the audio sounded fine. The device is: Bus 002 Device 004: ID 046d:0a0c Logitech, Inc. Clear Chat Comfort USB Headset The problem was tracked down to the Fresco Logic xHCI host controller not correctly reporting short transfers on isochronous IN endpoints. The driver would submit a 96 byte transfer, the device would only send 88 or 90 bytes, and the xHCI host would report the transfer had a "successful" completion code, with an untransferred buffer length of 8 or 6 bytes. The successful completion code and non-zero untransferred length is a contradiction. The xHCI host is supposed to only mark a transfer as successful if all the bytes are transferred. Otherwise, the transfer should be marked with a short packet completion code. Without the EHCI bus trace, we wouldn't know whether the xHCI driver should trust the completion code or the untransferred length. With it, we know to trust the untransferred length. Add a new xHCI quirk for the Fresco Logic host controller. If a transfer is reported as successful, but the untransferred length is non-zero, print a warning. For the Fresco Logic host, change the completion code to COMP_SHORT_TX and process the transfer like a short transfer. This should be backported to stable kernels that contain the commit f5182b4155b9d686c5540a6822486400e34ddd98 "xhci: Disable MSI for some Fresco Logic hosts." That commit was marked for stable kernels as old as 2.6.36. Signed-off-by: Sarah Sharp Reported-by: Sergio Correia Tested-by: Sergio Correia Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 1 + drivers/usb/host/xhci-ring.c | 20 +++++++++++++++++--- drivers/usb/host/xhci.h | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 7a856a767e7..19e89216436 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -72,6 +72,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " "has broken MSI implementation\n", pdev->revision); + xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_NEC) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d40194c8ca6..525a1ee8127 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1787,8 +1787,12 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* handle completion code */ switch (trb_comp_code) { case COMP_SUCCESS: - frame->status = 0; - break; + if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { + frame->status = 0; + break; + } + if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) + trb_comp_code = COMP_SHORT_TX; case COMP_SHORT_TX: frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ? -EREMOTEIO : 0; @@ -1885,13 +1889,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, switch (trb_comp_code) { case COMP_SUCCESS: /* Double check that the HW transferred everything. */ - if (event_trb != td->last_trb) { + if (event_trb != td->last_trb || + TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { xhci_warn(xhci, "WARN Successful completion " "on short TX\n"); if (td->urb->transfer_flags & URB_SHORT_NOT_OK) *status = -EREMOTEIO; else *status = 0; + if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) + trb_comp_code = COMP_SHORT_TX; } else { *status = 0; } @@ -2050,6 +2057,13 @@ static int handle_tx_event(struct xhci_hcd *xhci, * transfer type */ case COMP_SUCCESS: + if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) + break; + if (xhci->quirks & XHCI_TRUST_TX_LENGTH) + trb_comp_code = COMP_SHORT_TX; + else + xhci_warn(xhci, "WARN Successful completion on short TX: " + "needs XHCI_TRUST_TX_LENGTH quirk?\n"); case COMP_SHORT_TX: break; case COMP_STOP: diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ce1edd7246a..ac142760fd3 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1481,6 +1481,7 @@ struct xhci_hcd { #define XHCI_RESET_ON_RESUME (1 << 7) #define XHCI_SW_BW_CHECKING (1 << 8) #define XHCI_AMD_0x96_HOST (1 << 9) +#define XHCI_TRUST_TX_LENGTH (1 << 10) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ From 61fb50b8328e61b6038d99c6333a60b5b02328d8 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 10 May 2012 10:19:21 +0200 Subject: [PATCH 0059/2357] USB: fix resource leak in xhci power loss path commit f8a9e72d125f4e00ec529ba67b674321a1f3bf31 upstream. Some more data structures must be freed and counters reset if an XHCI controller has lost power. The failure to do so renders some chips inoperative after a certain number of S4 cycles. This patch should be backported to kernels as old as 3.2, that contain the commits c29eea621900f18287d50519f72cb9113746d75a "xhci: Implement HS/FS/LS bandwidth checking." and commit 839c817ce67178ca3c7c7ad534c571bba1e69ebe "xhci: Implement HS/FS/LS bandwidth checking." Signed-off-by: Oliver Neukum Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 3c9bb3db8ec..497ed7723e4 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1791,6 +1791,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); struct dev_info *dev_info, *next; + struct list_head *tt_list_head; + struct list_head *tt; + struct list_head *endpoints; + struct list_head *ep, *q; + struct xhci_tt_bw_info *tt_info; + struct xhci_interval_bw_table *bwt; + struct xhci_virt_ep *virt_ep; + unsigned long flags; int size; int i; @@ -1850,8 +1858,26 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } spin_unlock_irqrestore(&xhci->lock, flags); + bwt = &xhci->rh_bw->bw_table; + for (i = 0; i < XHCI_MAX_INTERVAL; i++) { + endpoints = &bwt->interval_bw[i].endpoints; + list_for_each_safe(ep, q, endpoints) { + virt_ep = list_entry(ep, struct xhci_virt_ep, bw_endpoint_list); + list_del(&virt_ep->bw_endpoint_list); + kfree(virt_ep); + } + } + + tt_list_head = &xhci->rh_bw->tts; + list_for_each_safe(tt, q, tt_list_head) { + tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list); + list_del(tt); + kfree(tt_info); + } + xhci->num_usb2_ports = 0; xhci->num_usb3_ports = 0; + xhci->num_active_eps = 0; kfree(xhci->usb2_ports); kfree(xhci->usb3_ports); kfree(xhci->port_array); From edad2199132a88f160c4939d1ad3eecc4c33b211 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Sat, 5 May 2012 00:50:10 +0800 Subject: [PATCH 0060/2357] usbcore: enable USB2 LPM if port suspend fails commit c3e751e4f4754793bb52bd5ae30e9cc027edbb12 upstream. USB2 LPM is disabled when device begin to suspend and enabled after device is resumed. That's because USB spec does not define the transition from U1/U2 state to U3 state. If usb_port_suspend() fails, usb_port_resume() is never called, and USB2 LPM is disabled in this situation. Enable USB2 LPM if port suspend fails. This patch should be backported to kernels as old as 3.2, that contain the commit 65580b4321eb36f16ae8b5987bfa1bb948fc5112 "xHCI: set USB2 hardware LPM". Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ec6c97dadbe..c8e0704c6e5 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2499,6 +2499,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) NULL, 0, USB_CTRL_SET_TIMEOUT); + /* Try to enable USB2 hardware LPM again */ + if (udev->usb2_hw_lpm_capable == 1) + usb_set_usb2_hardware_lpm(udev, 1); + /* System sleep transitions should never fail */ if (!PMSG_IS_AUTO(msg)) status = 0; From 10c4a0daae42270ef15c208e95556587a1cd5fd5 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 21 May 2012 15:27:44 +0100 Subject: [PATCH 0061/2357] gma500: Fix Poulsbo suspend/resume crash on devices with SDVO ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7beff62ee39d3ccf088bb77f61a63037f714d235 upstream. Reported-by: Guillaume Clément Signed-off-by: Alan Cox Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/gma500/psb_device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index 95d163e4f1f..328a19309f0 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c @@ -197,7 +197,8 @@ static int psb_save_display_registers(struct drm_device *dev) } list_for_each_entry(connector, &dev->mode_config.connector_list, head) - connector->funcs->save(connector); + if (connector->funcs->save) + connector->funcs->save(connector); mutex_unlock(&dev->mode_config.mutex); return 0; @@ -235,7 +236,8 @@ static int psb_restore_display_registers(struct drm_device *dev) crtc->funcs->restore(crtc); list_for_each_entry(connector, &dev->mode_config.connector_list, head) - connector->funcs->restore(connector); + if (connector->funcs->restore) + connector->funcs->restore(connector); mutex_unlock(&dev->mode_config.mutex); return 0; From 46f736c6f722e9a71ab552178a6bf4edf85ba371 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 6 May 2012 16:01:05 -0500 Subject: [PATCH 0062/2357] b43legacy: Fix error due to MMIO access with SSB unpowered commit 8f4b20388fa77226a3605627a33a23f90d559e50 upstream. There is a dummy read of a PCI MMIO register that occurs before the SSB bus has been powered, which is an error. This bug has not been seen earlier, but was apparently exposed when udev was updated to version 182. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/b43legacy/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index df7e16dfb36..a98db30b7ac 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1571,8 +1571,6 @@ static void b43legacy_request_firmware(struct work_struct *work) const char *filename; int err; - /* do dummy read */ - ssb_read32(dev->dev, SSB_TMSHIGH); if (!fw->ucode) { if (rev == 2) filename = "ucode2"; From b019d4bf936fa7212341053f337c6714f29fc95e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 May 2012 21:45:43 +0100 Subject: [PATCH 0063/2357] drm/i915: Avoid a double-read of PCH_IIR during interrupt handling commit 9adab8b5a7fde248504f484e197589f3e3c922e2 upstream. Currently the code re-reads PCH_IIR during the hotplug interrupt processing. Not only is this a wasted read, but introduces a potential for handling a spurious interrupt as we then may not clear all the interrupts processed (since the re-read IIR may contains more interrupts asserted than we clear using the result of the original read). Signed-off-by: Chris Wilson Cc: Jesse Barnes Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_irq.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index afd4e03e337..f57e5cfb162 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -424,14 +424,11 @@ static void gen6_pm_rps_work(struct work_struct *work) mutex_unlock(&dev_priv->dev->struct_mutex); } -static void pch_irq_handler(struct drm_device *dev) +static void pch_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 pch_iir; int pipe; - pch_iir = I915_READ(SDEIIR); - if (pch_iir & SDE_AUDIO_POWER_MASK) DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", (pch_iir & SDE_AUDIO_POWER_MASK) >> @@ -529,7 +526,7 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) if (de_iir & DE_PCH_EVENT_IVB) { if (pch_iir & SDE_HOTPLUG_MASK_CPT) queue_work(dev_priv->wq, &dev_priv->hotplug_work); - pch_irq_handler(dev); + pch_irq_handler(dev, pch_iir); } if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { @@ -629,7 +626,7 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) if (de_iir & DE_PCH_EVENT) { if (pch_iir & hotplug_mask) queue_work(dev_priv->wq, &dev_priv->hotplug_work); - pch_irq_handler(dev); + pch_irq_handler(dev, pch_iir); } if (de_iir & DE_PCU_EVENT) { From 629bdbbcd239bae8ef798c1f9c2c4cd006ecf389 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 14 Apr 2012 18:41:32 -0700 Subject: [PATCH 0064/2357] drm/i915: [GEN7] Use HW scheduler for fixed function shaders commit a1e969e0332de7a430e62822cee8f2ec8d83cd7c upstream. This originally started as a patch from Bernard as a way of simply setting the VS scheduler. After submitting the RFC patch, we decided to also modify the DS scheduler. To be most explicit, I've made the patch explicitly set all scheduler modes, and included the defines for other modes (in case someone feels frisky later). The rest of the story gets a bit weird. The first version of the patch showed an almost unbelievable performance improvement. Since rebasing my branch it appears the performance improvement has gone, unfortunately. But setting these bits seem to be the right thing to do given that the docs describe corruption that can occur with the default settings. In summary, I am seeing no more perf improvements (or regressions) in my limited testing, but we believe this should be set to prevent rendering corruption, therefore cc stable. v1: Clear bit 4 also (Ken + Eugeni) Do a full clear + set of the bits we want (Me). Cc: Bernard Kilarski Reviewed-by (RFC): Kenneth Graunke Signed-off-by: Ben Widawsky Reviewed-by: Eugeni Dodonov Reviewed-by: Kenneth Graunke Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 15 +++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9d24d65f0c3..29bfd899573 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -615,6 +615,21 @@ #define GEN6_BSD_RNCID 0x12198 +#define GEN7_FF_THREAD_MODE 0x20a0 +#define GEN7_FF_SCHED_MASK 0x0077070 +#define GEN7_FF_TS_SCHED_HS1 (0x5<<16) +#define GEN7_FF_TS_SCHED_HS0 (0x3<<16) +#define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) +#define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */ +#define GEN7_FF_VS_SCHED_HS1 (0x5<<12) +#define GEN7_FF_VS_SCHED_HS0 (0x3<<12) +#define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */ +#define GEN7_FF_VS_SCHED_HW (0x0<<12) +#define GEN7_FF_DS_SCHED_HS1 (0x5<<4) +#define GEN7_FF_DS_SCHED_HS0 (0x3<<4) +#define GEN7_FF_DS_SCHED_LOAD_BALANCE (0x1<<4) /* Default */ +#define GEN7_FF_DS_SCHED_HW (0x0<<4) + /* * Framebuffer compression (915+ only) */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1b1cf3b3ff5..af4ac9260dc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8612,6 +8612,18 @@ static void gen6_init_clock_gating(struct drm_device *dev) } } +static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) +{ + uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE); + + reg &= ~GEN7_FF_SCHED_MASK; + reg |= GEN7_FF_TS_SCHED_HW; + reg |= GEN7_FF_VS_SCHED_HW; + reg |= GEN7_FF_DS_SCHED_HW; + + I915_WRITE(GEN7_FF_THREAD_MODE, reg); +} + static void ivybridge_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -8656,6 +8668,8 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) DISPPLANE_TRICKLE_FEED_DISABLE); intel_flush_display_plane(dev_priv, pipe); } + + gen7_setup_fixed_func_scheduler(dev_priv); } static void g4x_init_clock_gating(struct drm_device *dev) From d8a0b3e41b7cac5dcd6408073f70818bb9675f25 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 13 May 2012 22:29:25 +0200 Subject: [PATCH 0065/2357] drm/i915: don't clobber the pipe param in sanitize_modesetting commit a9dcf84b14ef4e9a609910367576995e6f32f3dc upstream. ... we need it later on in the function to clean up pipe <-> plane associations. This regression has been introduced in commit f47166d2b0001fcb752b40c5a2d4db986dfbea68 Author: Chris Wilson Date: Thu Mar 22 15:00:50 2012 +0000 drm/i915: Sanitize BIOS debugging bits from PIPECONF Spotted by staring at debug output of an (as it turns out) totally unrelated bug. v2: I've totally failed to do the s/pipe/i/ correctly, spotted by Chris Wilson. Reviewed-by: Chris Wilson Reviewed-by: Eugeni Dodonov Signed-Off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index af4ac9260dc..79a7de1f31b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7617,10 +7617,11 @@ static void intel_sanitize_modesetting(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; u32 reg, val; + int i; /* Clear any frame start delays used for debugging left by the BIOS */ - for_each_pipe(pipe) { - reg = PIPECONF(pipe); + for_each_pipe(i) { + reg = PIPECONF(i); I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); } From dc9f6719d012a955d3e87f720c8ed9d03f2b9020 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 3 May 2012 12:22:06 +0200 Subject: [PATCH 0066/2357] gpio: mpc8xxx: Prevent NULL pointer deref in demux handler commit d6de85e85edcc38c9edcde45a0a568818fcddc13 upstream. commit cfadd838(powerpc/8xxx: Fix interrupt handling in MPC8xxx GPIO driver) added an unconditional call of chip->irq_eoi() to the demux handler. This leads to a NULL pointer derefernce on MPC512x platforms which use this driver as well. Make it conditional. Reported-by: Thomas Wucher Signed-off-by: Thomas Gleixner Cc: Felix Radensky Cc: Kumar Gala Cc: Grant Likely Signed-off-by: Grant Likely Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-mpc8xxx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index e6568c19c93..5a1817eedd1 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -163,7 +163,8 @@ static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) if (mask) generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, 32 - ffs(mask))); - chip->irq_eoi(&desc->irq_data); + if (chip->irq_eoi) + chip->irq_eoi(&desc->irq_data); } static void mpc8xxx_irq_unmask(struct irq_data *d) From 4e799d5e79f04b8099c1bd2ff9dc047d3fefd2c1 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Fri, 11 May 2012 15:29:50 -0700 Subject: [PATCH 0067/2357] spi/spi-fsl-spi: reference correct pdata in fsl_spi_cs_control commit 067aa4815a9bc12a569d8a06afef50ba5773afbf upstream. Commit 178db7d3, "spi: Fix device unregistration when unregistering the bus master", changed spi device initialization of dev.parent pointer to be the master's device pointer instead of his parent. This introduced a bug in spi-fsl-spi, since its usage of spi device pointer was not updated accordingly. This was later fixed by commit 5039a86, "spi/mpc83xx: fix NULL pdata dereference bug", but it missed another spot on fsl_spi_cs_control function where we also need to update usage of spi device pointer. This change address that. Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Joakim Tjernlund Signed-off-by: Grant Likely Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-fsl-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 5f748c0d96b..6a62934ca74 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -933,7 +933,7 @@ static struct spi_master * __devinit fsl_spi_probe(struct device *dev, static void fsl_spi_cs_control(struct spi_device *spi, bool on) { - struct device *dev = spi->dev.parent; + struct device *dev = spi->dev.parent->parent; struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data); u16 cs = spi->chip_select; int gpio = pinfo->gpios[cs]; From 284e7be895509cdaf9f58e2f789c00b5e9da2244 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 15 May 2012 11:47:47 +0300 Subject: [PATCH 0068/2357] hvc_xen: NULL dereference on allocation failure commit 201a52bea928687b7557728b176ac4f8a37d5cbd upstream. If kzalloc() returns a NULL here, we pass a NULL to xencons_disconnect_backend() which will cause an Oops. Also I removed the __GFP_ZERO while I was at it since kzalloc() implies __GFP_ZERO. Acked-by: Stefano Stabellini Signed-off-by: Dan Carpenter Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_xen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 83d5c88e716..d3d91dae065 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev, if (devid == 0) return -ENODEV; - info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); + info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); if (!info) - goto error_nomem; + return -ENOMEM; dev_set_drvdata(&dev->dev, info); info->xbdev = dev; info->vtermno = xenbus_devid_to_vtermno(devid); From 474d1f4678a679a98eaf53801e7f95c61ae9daa7 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 21 May 2012 16:54:10 +0100 Subject: [PATCH 0069/2357] xen: do not map the same GSI twice in PVHVM guests. commit 68c2c39a76b094e9b2773e5846424ea674bf2c46 upstream. PV on HVM guests map GSIs into event channels. At restore time the event channels are resumed by restore_pirqs. Device drivers might try to register the same GSI again through ACPI at restore time, but the GSI has already been mapped and bound by restore_pirqs. This patch detects these situations and avoids mapping the same GSI multiple times. Without this patch we get: (XEN) irq.c:2235: dom4: pirq 23 or emuirq 28 already mapped and waste a pirq. Signed-off-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/xen.c | 4 ++++ drivers/xen/events.c | 5 +++-- include/xen/events.h | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 7415aa92791..56ab74989cf 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -64,6 +64,10 @@ static int xen_register_pirq(u32 gsi, int gsi_override, int triggering, int shareable = 0; char *name; + irq = xen_irq_from_gsi(gsi); + if (irq > 0) + return irq; + if (set_pirq) pirq = gsi; diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0a8a17cd80b..6908e4ce2a0 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -611,7 +611,7 @@ static void disable_pirq(struct irq_data *data) disable_dynirq(data); } -static int find_irq_by_gsi(unsigned gsi) +int xen_irq_from_gsi(unsigned gsi) { struct irq_info *info; @@ -625,6 +625,7 @@ static int find_irq_by_gsi(unsigned gsi) return -1; } +EXPORT_SYMBOL_GPL(xen_irq_from_gsi); /* * Do not make any assumptions regarding the relationship between the @@ -644,7 +645,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, mutex_lock(&irq_mapping_update_lock); - irq = find_irq_by_gsi(gsi); + irq = xen_irq_from_gsi(gsi); if (irq != -1) { printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n", irq, gsi); diff --git a/include/xen/events.h b/include/xen/events.h index 0f773708e02..04399b28e82 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -103,6 +103,9 @@ int xen_irq_from_pirq(unsigned pirq); /* Return the pirq allocated to the irq. */ int xen_pirq_from_irq(unsigned irq); +/* Return the irq allocated to the gsi */ +int xen_irq_from_gsi(unsigned gsi); + /* Determine whether to ignore this IRQ if it is passed to a guest. */ int xen_test_irq_shared(int irq); From ed14f88b0953dd749bcae068dd9bc1a5e556a789 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 18 May 2012 15:31:12 +0100 Subject: [PATCH 0070/2357] nouveau: nouveau_set_bo_placement takes TTM flags commit c284815debba2f14ee2fd07b1b4cc972ab116110 upstream. This seems to be wrong to me, spotted while thinking about dma-buf. Reviewed-by: Ben Skeggs Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 7d15a774f9c..12ce044f12f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1030,7 +1030,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) nvbo->placement.fpfn = 0; nvbo->placement.lpfn = dev_priv->fb_mappable_pages; - nouveau_bo_placement_set(nvbo, TTM_PL_VRAM, 0); + nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0); return nouveau_bo_validate(nvbo, false, true, false); } From 1c2cc4a3922738f434fe4872a850f40095cc79d3 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 22 Mar 2012 13:55:05 -0300 Subject: [PATCH 0071/2357] smsusb: add autodetection support for USB ID 2040:c0a0 commit 4d1b58b84472d1d300a66e1c5fd765b21e74ba15 upstream. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb/siano/smsusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index b1fe5137df0..63c004a25e0 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -542,6 +542,8 @@ static const struct usb_device_id smsusb_id_table[] __devinitconst = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0xc090), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc0a0), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { } /* Terminating entry */ }; From 70a4571f9abef85e20c60a4654883d5250a36246 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Mar 2012 09:50:36 -0300 Subject: [PATCH 0072/2357] media: uvcvideo: Fix ENUMINPUT handling commit 31c5f0c5e25ed71eeced170f113bb590f2f1f6f3 upstream. Properly validate the user-supplied index against the number of inputs. The code used the pin local variable instead of the index by mistake. Reported-by: Jozef Vesely Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/uvc/uvc_v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index ff2cdddf9bc..53ab9729c29 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -687,7 +687,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) break; } pin = iterm->id; - } else if (pin < selector->bNrInPins) { + } else if (index < selector->bNrInPins) { pin = selector->baSourceID[index]; list_for_each_entry(iterm, &chain->entities, chain) { if (!UVC_ENTITY_IS_ITERM(iterm)) From 46592a6929ec62012bb1b089026b9df6c4827ff9 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 21 May 2012 20:51:24 +0300 Subject: [PATCH 0073/2357] x86, relocs: Build clean fix commit b2d668da9307c4c163dd603d2bb3cadb10f9fd37 upstream. relocs was not cleaned up when "make clean" is issued. This patch fixes the issue. Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1337622684-6834-1-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 94e91e401da..b1c611e6da6 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -206,6 +206,7 @@ archclean: $(Q)rm -rf $(objtree)/arch/i386 $(Q)rm -rf $(objtree)/arch/x86_64 $(Q)$(MAKE) $(clean)=$(boot) + $(Q)$(MAKE) $(clean)=arch/x86/tools define archhelp echo '* bzImage - Compressed kernel image (arch/x86/boot/bzImage)' From 3c47c685100285be39ff7e347f762480b448b956 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 23 May 2012 14:02:34 -0700 Subject: [PATCH 0074/2357] x86-32, relocs: Whitelist more symbols for ld bug workaround commit fd952815307f0f272bf49fd364a7fd2f9992bc42 upstream. As noted in checkin: a3e854d95 x86, relocs: Workaround for binutils 2.22.52.0.1 section bug ld version 2.22.52.0.[12] can incorrectly promote relative symbols to absolute, if the output section they appear in is otherwise empty. Since checkin: 6520fe55 x86, realmode: 16-bit real-mode code support for relocs tool we actually check for this and error out rather than silently creating a kernel which will malfunction if relocated. Ingo found a configuration in which __start_builtin_fw triggered the warning. Go through the linker script sources and look for more symbols that could plausibly get bogusly promoted to absolute, and add them to the whitelist. In general, if the following error triggers: Invalid absolute R_386_32 relocation: ... then we should verify that is really meant to be relocated, and add it and any related symbols manually to the S_REL regexp. Please note that 6520fe55 does not introduce the error, only the check for the error -- without 6520fe55 this version of ld will simply produce a corrupt kernel if CONFIG_RELOCATABLE is set on x86-32. Reported-by: Ingo Molnar Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/tools/relocs.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index b43cfcd9bf4..b8f7c65fc40 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -60,6 +60,17 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { "__x86_cpu_dev_(start|end)|" "(__parainstructions|__alt_instructions)(|_end)|" "(__iommu_table|__apicdrivers|__smp_locks)(|_end)|" + "__(start|end)_pci_.*|" + "__(start|end)_builtin_fw|" + "__(start|stop)___ksymtab(|_gpl|_unused|_unused_gpl|_gpl_future)|" + "__(start|stop)___kcrctab(|_gpl|_unused|_unused_gpl|_gpl_future)|" + "__(start|stop)___param|" + "__(start|stop)___modver|" + "__(start|stop)___bug_table|" + "__tracedata_(start|end)|" + "__(start|stop)_notes|" + "__end_rodata|" + "__initramfs_start|" "_end)$" }; From c51ac8ac9a82d4883c9b62247cca98195da8cd63 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 24 May 2012 07:01:38 -0700 Subject: [PATCH 0075/2357] x86, relocs: Add jiffies and jiffies_64 to the relative whitelist commit ea17e7414bc62e8d3bde8d08e3df1d921c518c17 upstream. The symbol jiffies is created in the linker script as an alias to jiffies_64. Unfortunately this is done outside any section, and apparently GNU ld 2.21 doesn't carry the section with it, so we end up with an absolute symbol and therefore a broken kernel. Add jiffies and jiffies_64 to the whitelist. The most disturbing bit with this discovery is that it shows that we have had multiple linker bugs in this area crossing multiple generations, and have been silently building bad kernels for some time. Link: http://lkml.kernel.org/r/20120524171604.0d98284f3affc643e9714470@canb.auug.org.au Reported-by: Stephen Rothwell Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/tools/relocs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index b8f7c65fc40..b685296d446 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -71,6 +71,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { "__(start|stop)_notes|" "__end_rodata|" "__initramfs_start|" + "(jiffies|jiffies_64)|" "_end)$" }; From e6b2a258ab83555e062cd2bc2a0ade31b8c118d1 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 23 May 2012 14:14:22 -0700 Subject: [PATCH 0076/2357] x86/mce: Fix check for processor context when machine check was taken. commit 875e26648cf9b6db9d8dc07b7959d7c61fb3f49c upstream. Linus pointed out that there was no value is checking whether m->ip was zero - because zero is a legimate value. If we have a reliable (or faked in the VM86 case) "m->cs" we can use it to tell whether we were in user mode or kernelwhen the machine check hit. Reported-by: Linus Torvalds Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce-severity.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index 0c82091b165..1ccd453903d 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -165,15 +165,19 @@ static struct severity { }; /* - * If the EIPV bit is set, it means the saved IP is the - * instruction which caused the MCE. + * If mcgstatus indicated that ip/cs on the stack were + * no good, then "m->cs" will be zero and we will have + * to assume the worst case (IN_KERNEL) as we actually + * have no idea what we were executing when the machine + * check hit. + * If we do have a good "m->cs" (or a faked one in the + * case we were executing in VM86 mode) we can use it to + * distinguish an exception taken in user from from one + * taken in the kernel. */ static int error_context(struct mce *m) { - if (m->mcgstatus & MCG_STATUS_EIPV) - return (m->ip && (m->cs & 3) == 3) ? IN_USER : IN_KERNEL; - /* Unknown, assume kernel */ - return IN_KERNEL; + return ((m->cs & 3) == 3) ? IN_USER : IN_KERNEL; } int mce_severity(struct mce *m, int tolerant, char **msg) From 11c8c735ebf68c754bdd94cebd307a96fcd95068 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 16 Apr 2012 19:16:54 -0400 Subject: [PATCH 0077/2357] mmc: sdio: avoid spurious calls to interrupt handlers commit bbbc4c4d8c5face097d695f9bf3a39647ba6b7e7 upstream. Commit 06e8935feb ("optimized SDIO IRQ handling for single irq") introduced some spurious calls to SDIO function interrupt handlers, such as when the SDIO IRQ thread is started, or the safety check performed upon a system resume. Let's add a flag to perform the optimization only when a real interrupt is signaled by the host driver and we know there is no point confirming it. Reported-by: Sujit Reddy Thumma Signed-off-by: Nicolas Pitre Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/sdio.c | 2 +- drivers/mmc/core/sdio_irq.c | 11 +++++++---- include/linux/mmc/host.h | 2 ++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2c7c83f832d..13d0e95380a 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -947,7 +947,7 @@ static int mmc_sdio_resume(struct mmc_host *host) } if (!err && host->sdio_irqs) - mmc_signal_sdio_irq(host); + wake_up_process(host->sdio_irq_thread); mmc_release_host(host); /* diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index f573e7f9f74..3d8ceb4084d 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -28,18 +28,20 @@ #include "sdio_ops.h" -static int process_sdio_pending_irqs(struct mmc_card *card) +static int process_sdio_pending_irqs(struct mmc_host *host) { + struct mmc_card *card = host->card; int i, ret, count; unsigned char pending; struct sdio_func *func; /* * Optimization, if there is only 1 function interrupt registered - * call irq handler directly + * and we know an IRQ was signaled then call irq handler directly. + * Otherwise do the full probe. */ func = card->sdio_single_irq; - if (func) { + if (func && host->sdio_irq_pending) { func->irq_handler(func); return 1; } @@ -116,7 +118,8 @@ static int sdio_irq_thread(void *_host) ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort); if (ret) break; - ret = process_sdio_pending_irqs(host->card); + ret = process_sdio_pending_irqs(host); + host->sdio_irq_pending = false; mmc_release_host(host); /* diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index cbde4b7e675..0707d228d7f 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -297,6 +297,7 @@ struct mmc_host { unsigned int sdio_irqs; struct task_struct *sdio_irq_thread; + bool sdio_irq_pending; atomic_t sdio_irq_thread_abort; mmc_pm_flag_t pm_flags; /* requested pm features */ @@ -352,6 +353,7 @@ extern int mmc_cache_ctrl(struct mmc_host *, u8); static inline void mmc_signal_sdio_irq(struct mmc_host *host) { host->ops->enable_sdio_irq(host, 0); + host->sdio_irq_pending = true; wake_up_process(host->sdio_irq_thread); } From 6cd4efb3a17356075c8e3f1bd191b4d120714851 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 24 Apr 2012 17:56:29 +0200 Subject: [PATCH 0078/2357] mmc: cd-gpio: protect against NULL context in mmc_cd_gpio_free() commit 0e9f480bb553d39ee06ccd45639ba7a5446a7b81 upstream. Do not oops, even if mmc_cd_gpio_free() is mistakenly called on a driver cleanup path, even though a previous call to mmc_cd_gpio_request() failed. Signed-off-by: Guennadi Liakhovetski [stable@: please apply to 3.3-stable] Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/cd-gpio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c index 2c14be73254..f13e38decea 100644 --- a/drivers/mmc/core/cd-gpio.c +++ b/drivers/mmc/core/cd-gpio.c @@ -73,6 +73,9 @@ void mmc_cd_gpio_free(struct mmc_host *host) { struct mmc_cd_gpio *cd = host->hotplug.handler_priv; + if (!cd) + return; + free_irq(host->hotplug.irq, host); gpio_free(cd->gpio); kfree(cd); From e5bdf9b518d0ff03455dce3da9bce8ad95c25e6d Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 17 May 2012 10:27:12 +0800 Subject: [PATCH 0079/2357] mmc: omap_hsmmc: pass IRQF_ONESHOT to request_threaded_irq commit db35f83ef47b5f180f2670d11f5f93992314ea09 upstream. The flag of IRQF_ONESHOT should be passed to request_threaded_irq, otherwise the following failure message should be dumped because hardware handler is defined as NULL: [ 3.383483] genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq 368 [ 3.392730] omap_hsmmc: probe of omap_hsmmc.0 failed with error -22 The patch fixes one kernel hang bug which is caused by mmc card probe failure and root device can't be brought up. Signed-off-by: Ming Lei Acked-by: Venkatraman S Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/omap_hsmmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 56d4499d438..71a0c4ea1bc 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1969,7 +1969,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) ret = request_threaded_irq(mmc_slot(host).card_detect_irq, NULL, omap_hsmmc_detect, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), From c90791c7638d3c9a0de762d8b416d0e809b1dc31 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Fri, 25 May 2012 12:32:09 -0400 Subject: [PATCH 0080/2357] tile: fix bug where fls(0) was not returning 0 commit 9f1d62bed7f015d11b9164078b7fea433b474114 upstream. This is because __builtin_clz(0) returns 64 for the "undefined" case of 0, since the builtin just does a right-shift 32 and "clz" instruction. So, use the alpha approach of casting to u32 and using __builtin_clzll(). Signed-off-by: Chris Metcalf Signed-off-by: Greg Kroah-Hartman --- arch/tile/include/asm/bitops.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/tile/include/asm/bitops.h b/arch/tile/include/asm/bitops.h index 16f1fa51fea..bd186c4eaa5 100644 --- a/arch/tile/include/asm/bitops.h +++ b/arch/tile/include/asm/bitops.h @@ -77,6 +77,11 @@ static inline int ffs(int x) return __builtin_ffs(x); } +static inline int fls64(__u64 w) +{ + return (sizeof(__u64) * 8) - __builtin_clzll(w); +} + /** * fls - find last set bit in word * @x: the word to search @@ -90,12 +95,7 @@ static inline int ffs(int x) */ static inline int fls(int x) { - return (sizeof(int) * 8) - __builtin_clz(x); -} - -static inline int fls64(__u64 w) -{ - return (sizeof(__u64) * 8) - __builtin_clzll(w); + return fls64((unsigned int) x); } static inline unsigned int __arch_hweight32(unsigned int w) From e568e5e8d83af106def2d9353761b5ac01f9df22 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 25 May 2012 17:42:54 +0100 Subject: [PATCH 0081/2357] intel-iommu: Add device info into list before doing context mapping commit e2ad23d04c1304431ab5176c89b7b476ded2d995 upstream. Add device info into list before doing context mapping, because device info will be used by iommu_enable_dev_iotlb(). Without it, ATS won't get enabled as it should be. ATS, while a dubious decision from a security point of view, can be very important for performance. Signed-off-by: Xudong Hao Signed-off-by: Xiantao Zhang Acked-by: Chris Wright Signed-off-by: David Woodhouse Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-iommu.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index f93d5ac8f81..5fda348702c 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2286,12 +2286,6 @@ static int domain_add_dev_info(struct dmar_domain *domain, if (!info) return -ENOMEM; - ret = domain_context_mapping(domain, pdev, translation); - if (ret) { - free_devinfo_mem(info); - return ret; - } - info->segment = pci_domain_nr(pdev->bus); info->bus = pdev->bus->number; info->devfn = pdev->devfn; @@ -2304,6 +2298,17 @@ static int domain_add_dev_info(struct dmar_domain *domain, pdev->dev.archdata.iommu = info; spin_unlock_irqrestore(&device_domain_lock, flags); + ret = domain_context_mapping(domain, pdev, translation); + if (ret) { + spin_lock_irqsave(&device_domain_lock, flags); + list_del(&info->link); + list_del(&info->global); + pdev->dev.archdata.iommu = NULL; + spin_unlock_irqrestore(&device_domain_lock, flags); + free_devinfo_mem(info); + return ret; + } + return 0; } From dcff6a45745b9df7f2c9255fc4998be8d52ea67c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 13 May 2012 20:09:38 +0300 Subject: [PATCH 0082/2357] iommu: Fix off by one in dmar_get_fault_reason() commit fefe1ed1398b81e3fadc92d11d91162d343c8836 upstream. fault_reason - 0x20 == ARRAY_SIZE(irq_remap_fault_reasons) is one past the end of the array. Signed-off-by: Dan Carpenter Cc: Joerg Roedel Cc: Youquan Song Cc: walter harms Cc: Suresh Siddha Link: http://lkml.kernel.org/r/20120513170938.GA4280@elgon.mountain Signed-off-by: Ingo Molnar [bwh: Backported to 3.2: s/irq_remap_fault_reasons/intr_remap_fault_reasons/] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/dmar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 35c1e17fce1..97b2e21ac46 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1056,8 +1056,8 @@ static const char *intr_remap_fault_reasons[] = const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) { - if (fault_reason >= 0x20 && (fault_reason <= 0x20 + - ARRAY_SIZE(intr_remap_fault_reasons))) { + if (fault_reason >= 0x20 && (fault_reason - 0x20 < + ARRAY_SIZE(intr_remap_fault_reasons))) { *fault_type = INTR_REMAP; return intr_remap_fault_reasons[fault_reason - 0x20]; } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) { From 6019ae78aa65afe273da8c0dfeed8e89fb5edf8f Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Thu, 29 Mar 2012 20:44:06 +0100 Subject: [PATCH 0083/2357] ARM: 7365/1: drop unused parameter from flush_cache_user_range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4542b6a0fa6b48d9ae6b41c1efeb618b7a221b2a upstream. vma isn't used and flush_cache_user_range isn't a standard macro that is used on several archs with the same prototype. In fact only unicore32 has a macro with the same name (with an identical implementation and no in-tree users). This is a part of a patch proposed by Dima Zavin (with Message-id: 1272439931-12795-1-git-send-email-dima@android.com) that didn't get accepted. Cc: Dima Zavin Acked-by: Catalin Marinas Signed-off-by: Uwe Kleine-König Signed-off-by: Russell King Cc: Will Deacon Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/cacheflush.h | 2 +- arch/arm/kernel/traps.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index d5d8d5c7268..1252a2675ca 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -249,7 +249,7 @@ extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr * Harvard caches are synchronised for the user space address range. * This is used for the ARM private sys_cacheflush system call. */ -#define flush_cache_user_range(vma,start,end) \ +#define flush_cache_user_range(start,end) \ __cpuc_coherent_user_range((start) & PAGE_MASK, PAGE_ALIGN(end)) /* diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 778454750a6..55b2f3dc6bb 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -496,7 +496,7 @@ do_cache_op(unsigned long start, unsigned long end, int flags) if (end > vma->vm_end) end = vma->vm_end; - flush_cache_user_range(vma, start, end); + flush_cache_user_range(start, end); } up_read(&mm->mmap_sem); } From 8209f1cb6873c4e43fba6e768d244b77f1c9d4b3 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Mon, 30 Apr 2012 10:26:14 +0100 Subject: [PATCH 0084/2357] ARM: 7409/1: Do not call flush_cache_user_range with mmap_sem held commit 435a7ef52db7d86e67a009b36cac1457f8972391 upstream. We can't be holding the mmap_sem while calling flush_cache_user_range because the flush can fault. If we fault on a user address, the page fault handler will try to take mmap_sem again. Since both places acquire the read lock, most of the time it succeeds. However, if another thread tries to acquire the write lock on the mmap_sem (e.g. mmap) in between the call to flush_cache_user_range and the fault, the down_read in do_page_fault will deadlock. [will: removed drop of vma parameter as already queued by rmk (7365/1)] Acked-by: Catalin Marinas Signed-off-by: Dima Zavin Signed-off-by: John Stultz Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/traps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 55b2f3dc6bb..63d402f75e2 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -496,7 +496,9 @@ do_cache_op(unsigned long start, unsigned long end, int flags) if (end > vma->vm_end) end = vma->vm_end; + up_read(&mm->mmap_sem); flush_cache_user_range(start, end); + return; } up_read(&mm->mmap_sem); } From 91aecc8b34db49950ba118bce93b7e300946a751 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 11 May 2012 18:01:38 -0600 Subject: [PATCH 0085/2357] ARM: dt: tegra cardhu: fix typo in SDHCI node name commit 1dfebb426cfd16e2080f8c95e00ca2462f2325d4 upstream. Cardhu's eMMC controller is on sdhci@78000600, not sdhci@78000400. Fix the typo. This roughly doubles the IO performance, since the support-8bit property actually takes effect. Signed-off-by: Stephen Warren Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/tegra-cardhu.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/tegra-cardhu.dts b/arch/arm/boot/dts/tegra-cardhu.dts index ac3fb755845..631a86cb11a 100644 --- a/arch/arm/boot/dts/tegra-cardhu.dts +++ b/arch/arm/boot/dts/tegra-cardhu.dts @@ -64,7 +64,7 @@ status = "disable"; }; - sdhci@78000400 { + sdhci@78000600 { support-8bit; }; }; From 07e2c719a35160023c327fac6389e106357d734a Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 19 Nov 2010 13:16:22 +0100 Subject: [PATCH 0086/2357] MCE: Fix vm86 handling for 32bit mce handler commit a129a7c84582629741e5fa6f40026efcd7a65bd4 upstream. When running on 32bit the mce handler could misinterpret vm86 mode as ring 0. This can affect whether it does recovery or not; it was possible to panic when recovery was actually possible. Fix this by always forcing vm86 to look like ring 3. Signed-off-by: Andi Kleen Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 11c9166c333..61604aefc40 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -437,6 +437,14 @@ static inline void mce_gather_info(struct mce *m, struct pt_regs *regs) if (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) { m->ip = regs->ip; m->cs = regs->cs; + + /* + * When in VM86 mode make the cs look like ring 3 + * always. This is a lie, but it's better than passing + * the additional vm86 bit around everywhere. + */ + if (v8086_mode(regs)) + m->cs |= 3; } /* Use accurate RIP reporting if available. */ if (rip_msr) From 16d815fd230b81d49d395e91b084f0731ea6e4a2 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Thu, 3 May 2012 15:56:36 +0200 Subject: [PATCH 0087/2357] i2c: davinci: Free requested IRQ in remove commit 9868a060ccf769c08ec378a9829137e272e9a92c upstream. The freed IRQ is not necessary the one requested in probe. Even if it was, with two or more i2c-controllers it will fails anyway. Signed-off-by: Marcus Folkesson Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index a76d85fa3ad..79b4bcb3b85 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -755,7 +755,7 @@ static int davinci_i2c_remove(struct platform_device *pdev) dev->clk = NULL; davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); - free_irq(IRQ_I2C, dev); + free_irq(dev->irq, dev); iounmap(dev->base); kfree(dev); From 3e5f29bd22e597d66d9c1013a0ab190e6b48a8ba Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 7 May 2012 12:16:19 +0530 Subject: [PATCH 0088/2357] i2c: tegra: notify transfer-complete after clearing status. commit c889e91d2cc22123f20f40dde0c0a91856a20eea upstream. The notification of the transfer complete by calling complete() should be done after clearing all interrupt status. This avoids the race condition of misconfigure the i2c controller in multi-core environment. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-tegra.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 55e5ea62cce..df19f3d588c 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -401,8 +401,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) disable_irq_nosync(i2c_dev->irq); i2c_dev->irq_disabled = 1; } - - complete(&i2c_dev->msg_complete); goto err; } @@ -411,7 +409,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) i2c_dev->msg_err |= I2C_ERR_NO_ACK; if (status & I2C_INT_ARBITRATION_LOST) i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST; - complete(&i2c_dev->msg_complete); goto err; } @@ -429,14 +426,14 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ); } + i2c_writel(i2c_dev, status, I2C_INT_STATUS); + if (i2c_dev->is_dvc) + dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); + if (status & I2C_INT_PACKET_XFER_COMPLETE) { BUG_ON(i2c_dev->msg_buf_remaining); complete(&i2c_dev->msg_complete); } - - i2c_writel(i2c_dev, status, I2C_INT_STATUS); - if (i2c_dev->is_dvc) - dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); return IRQ_HANDLED; err: /* An error occurred, mask all interrupts */ @@ -446,6 +443,8 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) i2c_writel(i2c_dev, status, I2C_INT_STATUS); if (i2c_dev->is_dvc) dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); + + complete(&i2c_dev->msg_complete); return IRQ_HANDLED; } From f18a511703b6667edee4703fdd8b73ca18e232a4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 1 Jun 2012 15:18:44 +0800 Subject: [PATCH 0089/2357] Linux 3.4.1 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a6879630a3e..0bd155435a3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 0 +SUBLEVEL = 1 EXTRAVERSION = NAME = Saber-toothed Squirrel From edb302ba464c6151ddb24ba4fb18c8e0a0ef9f7c Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Wed, 16 May 2012 14:22:21 +0300 Subject: [PATCH 0090/2357] exofs: Fix CRASH on very early IO errors. commit 6abe4a87f7bc7978705c386dbba0ca0c7790b3ec upstream. If at exofs_fill_super() we had an early termination do to any error, like an IO error while reading the super-block. We would crash inside exofs_free_sbi(). This is because sbi->oc.numdevs was set to 1, before we actually have a device table at all. Fix it by moving the sbi->oc.numdevs = 1 to after the allocation of the device table. Reported-by: Johannes Schild Signed-off-by: Boaz Harrosh Signed-off-by: Greg Kroah-Hartman --- fs/exofs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 735ca06430a..59e0849772b 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -745,7 +745,6 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) sbi->one_comp.obj.partition = opts->pid; sbi->one_comp.obj.id = 0; exofs_make_credential(sbi->one_comp.cred, &sbi->one_comp.obj); - sbi->oc.numdevs = 1; sbi->oc.single_comp = EC_SINGLE_COMP; sbi->oc.comps = &sbi->one_comp; @@ -804,6 +803,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) goto free_sbi; ore_comp_set_dev(&sbi->oc, 0, od); + sbi->oc.numdevs = 1; } __sbi_read_stats(sbi); From c18577564bf53876695646432e34e2e86c69a4b8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 9 Apr 2012 15:05:44 +0200 Subject: [PATCH 0091/2357] microblaze: Do not select GENERIC_GPIO by default commit 59516b07b4ffa7e607a5787674ea3c405f1b390c upstream. The microblaze architecture does not provide a native GPIO API implementation nor requires GPIOLIB, but still selects GENERIC_GPIO by default. As a result the following build error occurs, if GPIOLIB is not selected: include/asm-generic/gpio.h: In function 'gpio_get_value_cansleep': include/asm-generic/gpio.h:218: error: implicit declaration of function '__gpio_get_value' include/asm-generic/gpio.h: In function 'gpio_set_value_cansleep': include/asm-generic/gpio.h:224: error: implicit declaration of function '__gpio_set_value' This patch addresses the issue by not selecting GENERIC_GPIO by default. This causes the GPIO API to be stubbed out if no implementation is provided. Signed-off-by: Lars-Peter Clausen Tested-by: Michal Simek Signed-off-by: Greg Kroah-Hartman --- arch/microblaze/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index ac22dc7f4ca..333b85e80c0 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -57,7 +57,7 @@ config GENERIC_CLOCKEVENTS def_bool y config GENERIC_GPIO - def_bool y + bool config GENERIC_CSUM def_bool y From e6157b97c60f1a9243a57563895a8eb81dbf3117 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 30 May 2012 09:45:39 +0000 Subject: [PATCH 0092/2357] SCSI: fix scsi_wait_scan commit 1ff2f40305772b159a91c19590ee159d3a504afc upstream. Commit c751085943362143f84346d274e0011419c84202 Author: Rafael J. Wysocki Date: Sun Apr 12 20:06:56 2009 +0200 PM/Hibernate: Wait for SCSI devices scan to complete during resume Broke the scsi_wait_scan module in 2.6.30. Apparently debian still uses it so fix it and backport to stable before removing it in 3.6. The breakage is caused because the function template in include/scsi/scsi_scan.h is defined to be a nop unless SCSI is built in. That means that in the modular case (which is every distro), the scsi_wait_scan module does a simple async_synchronize_full() instead of waiting for scans. Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_wait_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_wait_scan.c b/drivers/scsi/scsi_wait_scan.c index 74708fcaf82..ae781487461 100644 --- a/drivers/scsi/scsi_wait_scan.c +++ b/drivers/scsi/scsi_wait_scan.c @@ -12,7 +12,7 @@ #include #include -#include +#include "scsi_priv.h" static int __init wait_scan_init(void) { From 798a1aaef46a15208ff6974679ed63cc542feebd Mon Sep 17 00:00:00 2001 From: Jun'ichi Nomura Date: Tue, 22 May 2012 18:57:17 +0900 Subject: [PATCH 0093/2357] SCSI: Fix dm-multipath starvation when scsi host is busy commit b7e94a1686c5daef4f649f7f4f839cc294f07710 upstream. block congestion control doesn't have any concept of fairness across multiple queues. This means that if SCSI reports the host as busy in the queue congestion control it can result in an unfair starvation situation in dm-mp if there are multiple multipath devices on the same host. For example: http://www.redhat.com/archives/dm-devel/2012-May/msg00123.html The fix for this is to report only the sdev busy state (and ignore the host busy state) in the block congestion control call back. The host is still congested, but the SCSI subsystem will sort out the congestion in a fair way because it knows the relation between the queues and the host. [jejb: fixed up trailing whitespace] Reported-by: Bernd Schubert Tested-by: Bernd Schubert Signed-off-by: Jun'ichi Nomura Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_lib.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 5dfd7495d1a..4037fd5b1e0 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1378,16 +1378,19 @@ static int scsi_lld_busy(struct request_queue *q) { struct scsi_device *sdev = q->queuedata; struct Scsi_Host *shost; - struct scsi_target *starget; if (!sdev) return 0; shost = sdev->host; - starget = scsi_target(sdev); - if (scsi_host_in_recovery(shost) || scsi_host_is_busy(shost) || - scsi_target_is_busy(starget) || scsi_device_is_busy(sdev)) + /* + * Ignore host/starget busy state. + * Since block layer does not have a concept of fairness across + * multiple queues, congestion of host/starget needs to be handled + * in SCSI layer. + */ + if (scsi_host_in_recovery(shost) || scsi_device_is_busy(sdev)) return 1; return 0; From 3876c722319d9b8463b9e82394d81f6d0c45021e Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Tue, 29 May 2012 15:06:22 -0700 Subject: [PATCH 0094/2357] mm/fork: fix overflow in vma length when copying mmap on clone commit 7edc8b0ac16cbaed7cb4ea4c6b95ce98d2997e84 upstream. The vma length in dup_mmap is calculated and stored in a unsigned int, which is insufficient and hence overflows for very large maps (beyond 16TB). The following program demonstrates this: #include #include #include #define GIG 1024 * 1024 * 1024L #define EXTENT 16393 int main(void) { int i, r; void *m; char buf[1024]; for (i = 0; i < EXTENT; i++) { m = mmap(NULL, (size_t) 1 * 1024 * 1024 * 1024L, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (m == (void *)-1) printf("MMAP Failed: %d\n", m); else printf("%d : MMAP returned %p\n", i, m); r = fork(); if (r == 0) { printf("%d: successed\n", i); return 0; } else if (r < 0) printf("FORK Failed: %d\n", r); else if (r > 0) wait(NULL); } return 0; } Increase the storage size of the result to unsigned long, which is sufficient for storing the difference between addresses. Signed-off-by: Siddhesh Poyarekar Cc: Tejun Heo Cc: Oleg Nesterov Cc: Jens Axboe Cc: Peter Zijlstra Acked-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/fork.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/fork.c b/kernel/fork.c index 687a15d5624..81633337aee 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -356,7 +356,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) } charge = 0; if (mpnt->vm_flags & VM_ACCOUNT) { - unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + unsigned long len; + len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; if (security_vm_enough_memory_mm(oldmm, len)) /* sic */ goto fail_nomem; charge = len; From 3634d6fec1f80012110962d58dbd396aaa99d960 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Tue, 29 May 2012 15:06:15 -0700 Subject: [PATCH 0095/2357] mm: fix NULL ptr deref when walking hugepages commit 08fa29d916c6e271ad13978cd993e7238c68db97 upstream. A missing validation of the value returned by find_vma() could cause a NULL ptr dereference when walking the pagetable. This is triggerable from usermode by a simple user by trying to read a page info out of /proc/pid/pagemap which doesn't exist. Introduced by commit 025c5b2451e4 ("thp: optimize away unnecessary page table locking"). Signed-off-by: Sasha Levin Reviewed-by: Naoya Horiguchi Cc: David Rientjes Cc: Andi Kleen Cc: Andrea Arcangeli Cc: KOSAKI Motohiro Cc: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/task_mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 1030a716d15..7faaf2acc57 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -784,7 +784,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, /* find the first VMA at or above 'addr' */ vma = find_vma(walk->mm, addr); - if (pmd_trans_huge_lock(pmd, vma) == 1) { + if (vma && pmd_trans_huge_lock(pmd, vma) == 1) { for (; addr != end; addr += PAGE_SIZE) { unsigned long offset; From 319b5641660fb09660c6faaaa99af9ddff973737 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 29 May 2012 15:06:45 -0700 Subject: [PATCH 0096/2357] mm: consider all swapped back pages in used-once logic commit e48982734ea0500d1eba4f9d96195acc5406cad6 upstream. Commit 645747462435 ("vmscan: detect mapped file pages used only once") made mapped pages have another round in inactive list because they might be just short lived and so we could consider them again next time. This heuristic helps to reduce pressure on the active list with a streaming IO worklods. This patch fixes a regression introduced by this commit for heavy shmem based workloads because unlike Anon pages, which are excluded from this heuristic because they are usually long lived, shmem pages are handled as a regular page cache. This doesn't work quite well, unfortunately, if the workload is mostly backed by shmem (in memory database sitting on 80% of memory) with a streaming IO in the background (backup - up to 20% of memory). Anon inactive list is full of (dirty) shmem pages when watermarks are hit. Shmem pages are kept in the inactive list (they are referenced) in the first round and it is hard to reclaim anything else so we reach lower scanning priorities very quickly which leads to an excessive swap out. Let's fix this by excluding all swap backed pages (they tend to be long lived wrt. the regular page cache anyway) from used-once heuristic and rather activate them if they are referenced. The customer's workload is shmem backed database (80% of RAM) and they are measuring transactions/s with an IO in the background (20%). Transactions touch more or less random rows in the table. The transaction rate fell by a factor of 3 (in the worst case) because of commit 64574746. This patch restores the previous numbers. Signed-off-by: Michal Hocko Acked-by: Johannes Weiner Cc: Mel Gorman Cc: Minchan Kim Cc: KAMEZAWA Hiroyuki Reviewed-by: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/vmscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 33dc256033b..0932dc27e19 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -722,7 +722,7 @@ static enum page_references page_check_references(struct page *page, return PAGEREF_RECLAIM; if (referenced_ptes) { - if (PageAnon(page)) + if (PageSwapBacked(page)) return PAGEREF_ACTIVATE; /* * All mapped pages start out with page table From e42adb30f43ce5aa3f362c45328209f95bf9d519 Mon Sep 17 00:00:00 2001 From: KyongHo Date: Tue, 29 May 2012 15:06:49 -0700 Subject: [PATCH 0097/2357] mm: fix faulty initialization in vmalloc_init() commit dbda591d920b4c7692725b13e3f68ecb251e9080 upstream. The transfer of ->flags causes some of the static mapping virtual addresses to be prematurely freed (before the mapping is removed) because VM_LAZY_FREE gets "set" if tmp->flags has VM_IOREMAP set. This might cause subsequent vmalloc/ioremap calls to fail because it might allocate one of the freed virtual address ranges that aren't unmapped. va->flags has different types of flags from tmp->flags. If a region with VM_IOREMAP set is registered with vm_area_add_early(), it will be removed by __purge_vmap_area_lazy(). Fix vmalloc_init() to correctly initialize vmap_area for the given vm_struct. Also initialise va->vm. If it is not set, find_vm_area() for the early vm regions will always fail. Signed-off-by: KyongHo Cho Cc: "Olav Haugan" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/vmalloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 94dff883b44..1196c7728ed 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1185,9 +1185,10 @@ void __init vmalloc_init(void) /* Import existing vmlist entries. */ for (tmp = vmlist; tmp; tmp = tmp->next) { va = kzalloc(sizeof(struct vmap_area), GFP_NOWAIT); - va->flags = tmp->flags | VM_VM_AREA; + va->flags = VM_VM_AREA; va->va_start = (unsigned long)tmp->addr; va->va_end = va->va_start + tmp->size; + va->vm = tmp; __insert_vmap_area(va); } From 75713d3f1b75e0054d47b258895225e152e638cb Mon Sep 17 00:00:00 2001 From: Meenakshi Venkataraman Date: Wed, 16 May 2012 22:35:57 +0200 Subject: [PATCH 0098/2357] iwlwifi: update BT traffic load states correctly commit 882dde8eb0d49ce0f853f8f4084dde56a21fe55f upstream. When BT traffic load changes from its previous state, a new LQ command needs to be sent down to the firmware. This needs to be done only once per change. The state variable that keeps track of this change is last_bt_traffic_load. However, it was not being updated when the change had been handled. Not updating this variable was causing a flood of advanced BT config commands to be sent to the firmware. Fix this. Signed-off-by: Meenakshi Venkataraman Signed-off-by: Wey-Yi Guy Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 7e590b349dd..da2be3e09ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -884,6 +884,7 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, if ((priv->bt_traffic_load != priv->last_bt_traffic_load) || (priv->bt_full_concurrent != full_concurrent)) { priv->bt_full_concurrent = full_concurrent; + priv->last_bt_traffic_load = priv->bt_traffic_load; /* Update uCode's rate table. */ tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); From 784c9700444d2ebbace0a1d3a3ac48c3d5852164 Mon Sep 17 00:00:00 2001 From: Meenakshi Venkataraman Date: Wed, 16 May 2012 22:35:59 +0200 Subject: [PATCH 0099/2357] iwlwifi: do not use shadow registers by default commit 66a770729a5cdd24efed8afa5258f81232d8bba2 upstream. Shadow registers in the device are meant to allow the driver to update certain device registers without needing to wake up all components of the device. However, using this feature in the device causes communication between the driver and the device to become unreliable, resulting in host command timeouts. Disable this feature by default till a fix is available for the bug. Signed-off-by: Meenakshi Venkataraman Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-2000.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index ea108622e0b..4da050ffa62 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -183,7 +183,7 @@ static const struct iwl_base_params iwl2000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, - .shadow_reg_enable = true, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ .hd_v2 = true, }; @@ -202,7 +202,7 @@ static const struct iwl_base_params iwl2030_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .shadow_reg_enable = true, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ .hd_v2 = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f0c91505a7f..9f71b85f591 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -282,7 +282,7 @@ static const struct iwl_base_params iwl6000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, - .shadow_reg_enable = true, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ }; static const struct iwl_base_params iwl6050_base_params = { @@ -299,7 +299,7 @@ static const struct iwl_base_params iwl6050_base_params = { .chain_noise_scale = 1500, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 1024, - .shadow_reg_enable = true, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ }; static const struct iwl_base_params iwl6000_g2_base_params = { @@ -316,7 +316,7 @@ static const struct iwl_base_params iwl6000_g2_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .shadow_reg_enable = true, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ }; static const struct iwl_ht_params iwl6000_ht_params = { From 444b7bce3152cc6ef1fb599331d053c9c40eb374 Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Tue, 15 May 2012 10:19:16 -0500 Subject: [PATCH 0100/2357] cifs: Include backup intent search flags during searches {try #2) commit 2608bee744a92d60d15ff4e6e0b913d8b406aedd upstream. As observed and suggested by Tushar Gosavi... --------- readdir calls these function to send TRANS2_FIND_FIRST and TRANS2_FIND_NEXT command to the server. The current cifs module is not specifying CIFS_SEARCH_BACKUP_SEARCH flag while sending these command when backupuid/backupgid is specified. This can be resolved by specifying CIFS_SEARCH_BACKUP_SEARCH flag. --------- Reported-and-Tested-by: Tushar Gosavi Signed-off-by: Shirish Pargaonkar Acked-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsproto.h | 6 ++++-- fs/cifs/cifssmb.c | 12 +++++------- fs/cifs/readdir.c | 15 +++++++++++++-- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 96192c1e380..97f5d0371cb 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -192,11 +192,13 @@ extern int CIFSTCon(unsigned int xid, struct cifs_ses *ses, extern int CIFSFindFirst(const int xid, struct cifs_tcon *tcon, const char *searchName, const struct nls_table *nls_codepage, - __u16 *searchHandle, struct cifs_search_info *psrch_inf, + __u16 *searchHandle, __u16 search_flags, + struct cifs_search_info *psrch_inf, int map, const char dirsep); extern int CIFSFindNext(const int xid, struct cifs_tcon *tcon, - __u16 searchHandle, struct cifs_search_info *psrch_inf); + __u16 searchHandle, __u16 search_flags, + struct cifs_search_info *psrch_inf); extern int CIFSFindClose(const int, struct cifs_tcon *tcon, const __u16 search_handle); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index da2f5446fa7..6b79efd7d75 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -4344,7 +4344,7 @@ int CIFSFindFirst(const int xid, struct cifs_tcon *tcon, const char *searchName, const struct nls_table *nls_codepage, - __u16 *pnetfid, + __u16 *pnetfid, __u16 search_flags, struct cifs_search_info *psrch_inf, int remap, const char dirsep) { /* level 257 SMB_ */ @@ -4416,8 +4416,7 @@ CIFSFindFirst(const int xid, struct cifs_tcon *tcon, cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); - pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | - CIFS_SEARCH_RETURN_RESUME); + pSMB->SearchFlags = cpu_to_le16(search_flags); pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); /* BB what should we set StorageType to? Does it matter? BB */ @@ -4487,8 +4486,8 @@ CIFSFindFirst(const int xid, struct cifs_tcon *tcon, return rc; } -int CIFSFindNext(const int xid, struct cifs_tcon *tcon, - __u16 searchHandle, struct cifs_search_info *psrch_inf) +int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle, + __u16 search_flags, struct cifs_search_info *psrch_inf) { TRANSACTION2_FNEXT_REQ *pSMB = NULL; TRANSACTION2_FNEXT_RSP *pSMBr = NULL; @@ -4531,8 +4530,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon, cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO)); pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); pSMB->ResumeKey = psrch_inf->resume_key; - pSMB->SearchFlags = - cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); + pSMB->SearchFlags = cpu_to_le16(search_flags); name_len = psrch_inf->resume_name_len; params += name_len; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index e2bbc683e01..0a8224d1c4c 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -219,6 +219,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, static int initiate_cifs_search(const int xid, struct file *file) { + __u16 search_flags; int rc = 0; char *full_path = NULL; struct cifsFileInfo *cifsFile; @@ -270,8 +271,12 @@ static int initiate_cifs_search(const int xid, struct file *file) cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; } + search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; + if (backup_cred(cifs_sb)) + search_flags |= CIFS_SEARCH_BACKUP_SEARCH; + rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls, - &cifsFile->netfid, &cifsFile->srch_inf, + &cifsFile->netfid, search_flags, &cifsFile->srch_inf, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); if (rc == 0) @@ -502,11 +507,13 @@ static int cifs_save_resume_key(const char *current_entry, static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon, struct file *file, char **ppCurrentEntry, int *num_to_ret) { + __u16 search_flags; int rc = 0; int pos_in_buf = 0; loff_t first_entry_in_buffer; loff_t index_to_find = file->f_pos; struct cifsFileInfo *cifsFile = file->private_data; + struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); /* check if index in the buffer */ if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || @@ -560,10 +567,14 @@ static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon, cifsFile); } + search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; + if (backup_cred(cifs_sb)) + search_flags |= CIFS_SEARCH_BACKUP_SEARCH; + while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && (rc == 0) && !cifsFile->srch_inf.endOfSearch) { cFYI(1, "calling findnext2"); - rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, + rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, search_flags, &cifsFile->srch_inf); /* FindFirst/Next set last_entry to NULL on malformed reply */ if (cifsFile->srch_inf.last_entry) From 27ab30eb965b9d26c5811f5505d95c8ede08c580 Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Mon, 21 May 2012 09:20:12 -0500 Subject: [PATCH 0101/2357] cifs: fix oops while traversing open file list (try #4) commit 2c0c2a08bed7a3b791f88d09d16ace56acb3dd98 upstream. While traversing the linked list of open file handles, if the identfied file handle is invalid, a reopen is attempted and if it fails, we resume traversing where we stopped and cifs can oops while accessing invalid next element, for list might have changed. So mark the invalid file handle and attempt reopen if no valid file handle is found in rest of the list. If reopen fails, move the invalid file handle to the end of the list and start traversing the list again from the begining. Repeat this four times before giving up and returning an error if file reopen keeps failing. Signed-off-by: Shirish Pargaonkar Reviewed-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsglob.h | 1 + fs/cifs/file.c | 57 +++++++++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 4ff6313f0a9..73fea285b84 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -43,6 +43,7 @@ #define CIFS_MIN_RCV_POOL 4 +#define MAX_REOPEN_ATT 5 /* these many maximum attempts to reopen a file */ /* * default attribute cache timeout (jiffies) */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 81725e9286e..e7ebb5a2ed1 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1539,10 +1539,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only) { - struct cifsFileInfo *open_file; + struct cifsFileInfo *open_file, *inv_file = NULL; struct cifs_sb_info *cifs_sb; bool any_available = false; int rc; + unsigned int refind = 0; /* Having a null inode here (because mapping->host was set to zero by the VFS or MM) should not happen but we had reports of on oops (due to @@ -1562,40 +1563,25 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, spin_lock(&cifs_file_list_lock); refind_writable: + if (refind > MAX_REOPEN_ATT) { + spin_unlock(&cifs_file_list_lock); + return NULL; + } list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (!any_available && open_file->pid != current->tgid) continue; if (fsuid_only && open_file->uid != current_fsuid()) continue; if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { - cifsFileInfo_get(open_file); - if (!open_file->invalidHandle) { /* found a good writable file */ + cifsFileInfo_get(open_file); spin_unlock(&cifs_file_list_lock); return open_file; + } else { + if (!inv_file) + inv_file = open_file; } - - spin_unlock(&cifs_file_list_lock); - - /* Had to unlock since following call can block */ - rc = cifs_reopen_file(open_file, false); - if (!rc) - return open_file; - - /* if it fails, try another handle if possible */ - cFYI(1, "wp failed on reopen file"); - cifsFileInfo_put(open_file); - - spin_lock(&cifs_file_list_lock); - - /* else we simply continue to the next entry. Thus - we do not loop on reopen errors. If we - can not reopen the file, for example if we - reconnected to a server with another client - racing to delete or lock the file we would not - make progress if we restarted before the beginning - of the loop here. */ } } /* couldn't find useable FH with same pid, try any available */ @@ -1603,7 +1589,30 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, any_available = true; goto refind_writable; } + + if (inv_file) { + any_available = false; + cifsFileInfo_get(inv_file); + } + spin_unlock(&cifs_file_list_lock); + + if (inv_file) { + rc = cifs_reopen_file(inv_file, false); + if (!rc) + return inv_file; + else { + spin_lock(&cifs_file_list_lock); + list_move_tail(&inv_file->flist, + &cifs_inode->openFileList); + spin_unlock(&cifs_file_list_lock); + cifsFileInfo_put(inv_file); + spin_lock(&cifs_file_list_lock); + ++refind; + goto refind_writable; + } + } + return NULL; } From e01b7f872913f583b5c043b99c8f5af2eb44d051 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Thu, 17 May 2012 10:34:34 -0400 Subject: [PATCH 0102/2357] PARISC: fix boot failure on 32-bit systems caused by branch stubs placed before .text commit ed5fb2471b7060767957fb964eb1aaec71533ab1 upstream. In certain configurations, the resulting kernel becomes too large to boot because the linker places the long branch stubs for the merged .text section at the very start of the image. As a result, the initial transfer of control jumps to an unexpected location. Fix this by placing the head text in a separate section so the stubs for .text are not at the start of the image. Signed-off-by: John David Anglin Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/vmlinux.lds.S | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index fa6f2b8163e..64a999882e4 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -50,8 +50,10 @@ SECTIONS . = KERNEL_BINARY_TEXT_START; _text = .; /* Text and read-only data */ - .text ALIGN(16) : { + .head ALIGN(16) : { HEAD_TEXT + } = 0 + .text ALIGN(16) : { TEXT_TEXT SCHED_TEXT LOCK_TEXT @@ -65,7 +67,7 @@ SECTIONS *(.fixup) *(.lock.text) /* out-of-line lock text */ *(.gnu.warning) - } = 0 + } /* End of text section */ _etext = .; From dab0a045b4ff1689617a0fdbd4e8060770effa58 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 21 May 2012 07:49:01 +0100 Subject: [PATCH 0103/2357] PARISC: fix TLB fault path on PA2.0 narrow systems commit 2f649c1f6f0fef445ce79a19b79e5ce8fe9d7f19 upstream. commit 5e185581d7c46ddd33cd9c01106d1fc86efb9376 Author: James Bottomley [PARISC] fix PA1.1 oops on boot Didn't quite fix the crash on boot. It moved it from PA1.1 processors to PA2.0 narrow kernels. The final fix is to make sure the [id]tlb_miss_20 paths also work. Even on narrow systems, these paths require using the wide instructions becuase the tlb insertion format is wide. Fix this by conditioning the dep[wd],z on whether we're being called from _11 or _20[w] paths. Tested-by: Helge Deller Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/entry.S | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 53503421702..07ef351edd5 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -552,7 +552,7 @@ * entry (identifying the physical page) and %r23 up with * the from tlb entry (or nothing if only a to entry---for * clear_user_page_asm) */ - .macro do_alias spc,tmp,tmp1,va,pte,prot,fault + .macro do_alias spc,tmp,tmp1,va,pte,prot,fault,patype cmpib,COND(<>),n 0,\spc,\fault ldil L%(TMPALIAS_MAP_START),\tmp #if defined(CONFIG_64BIT) && (TMPALIAS_MAP_START >= 0x80000000) @@ -581,11 +581,15 @@ */ cmpiclr,= 0x01,\tmp,%r0 ldi (_PAGE_DIRTY|_PAGE_READ|_PAGE_WRITE),\prot -#ifdef CONFIG_64BIT +.ifc \patype,20 depd,z \prot,8,7,\prot -#else +.else +.ifc \patype,11 depw,z \prot,8,7,\prot -#endif +.else + .error "undefined PA type to do_alias" +.endif +.endif /* * OK, it is in the temp alias region, check whether "from" or "to". * Check "subtle" note in pacache.S re: r23/r26. @@ -1189,7 +1193,7 @@ dtlb_miss_20w: nop dtlb_check_alias_20w: - do_alias spc,t0,t1,va,pte,prot,dtlb_fault + do_alias spc,t0,t1,va,pte,prot,dtlb_fault,20 idtlbt pte,prot @@ -1213,7 +1217,7 @@ nadtlb_miss_20w: nop nadtlb_check_alias_20w: - do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate + do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate,20 idtlbt pte,prot @@ -1245,7 +1249,7 @@ dtlb_miss_11: nop dtlb_check_alias_11: - do_alias spc,t0,t1,va,pte,prot,dtlb_fault + do_alias spc,t0,t1,va,pte,prot,dtlb_fault,11 idtlba pte,(va) idtlbp prot,(va) @@ -1277,7 +1281,7 @@ nadtlb_miss_11: nop nadtlb_check_alias_11: - do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate + do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate,11 idtlba pte,(va) idtlbp prot,(va) @@ -1304,7 +1308,7 @@ dtlb_miss_20: nop dtlb_check_alias_20: - do_alias spc,t0,t1,va,pte,prot,dtlb_fault + do_alias spc,t0,t1,va,pte,prot,dtlb_fault,20 idtlbt pte,prot @@ -1330,7 +1334,7 @@ nadtlb_miss_20: nop nadtlb_check_alias_20: - do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate + do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate,20 idtlbt pte,prot @@ -1457,7 +1461,7 @@ naitlb_miss_20w: nop naitlb_check_alias_20w: - do_alias spc,t0,t1,va,pte,prot,naitlb_fault + do_alias spc,t0,t1,va,pte,prot,naitlb_fault,20 iitlbt pte,prot @@ -1511,7 +1515,7 @@ naitlb_miss_11: nop naitlb_check_alias_11: - do_alias spc,t0,t1,va,pte,prot,itlb_fault + do_alias spc,t0,t1,va,pte,prot,itlb_fault,11 iitlba pte,(%sr0, va) iitlbp prot,(%sr0, va) @@ -1557,7 +1561,7 @@ naitlb_miss_20: nop naitlb_check_alias_20: - do_alias spc,t0,t1,va,pte,prot,naitlb_fault + do_alias spc,t0,t1,va,pte,prot,naitlb_fault,20 iitlbt pte,prot From c6fb8b4e362693c4d4864de46607c558852a570a Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 24 May 2012 04:58:27 +0000 Subject: [PATCH 0104/2357] solos-pci: Fix DMA support commit b4bd8ad9bb311e8536f726f7a633620ccd358cde upstream. DMA support has finally made its way to the top of the TODO list, having realised that a Geode using MMIO can't keep up with two ADSL2+ lines each running at 21Mb/s. This patch fixes a couple of bugs in the DMA support in the driver, so once the corresponding FPGA update is complete and tested everything should work properly. We weren't storing the currently-transmitting skb, so we were never unmapping it and never freeing/popping it when the TX was done. And the addition of pci_set_master() is fairly self-explanatory. Signed-off-by: David Woodhouse Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/atm/solos-pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index e8cd652d201..98510931c81 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -984,6 +984,7 @@ static uint32_t fpga_tx(struct solos_card *card) } else if (skb && card->using_dma) { SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data, skb->len, PCI_DMA_TODEVICE); + card->tx_skb[port] = skb; iowrite32(SKB_CB(skb)->dma_addr, card->config_regs + TX_DMA_ADDR(port)); } @@ -1152,7 +1153,8 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) db_fpga_upgrade = db_firmware_upgrade = 0; } - if (card->fpga_version >= DMA_SUPPORTED){ + if (card->fpga_version >= DMA_SUPPORTED) { + pci_set_master(dev); card->using_dma = 1; } else { card->using_dma = 0; From 6ea90b39f492460884b218ffe066210f129771fb Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 15 May 2012 17:47:52 +0200 Subject: [PATCH 0105/2357] MIPS: BCM63XX: Add missing include for bcm63xx_gpio.h commit 442209f31dafef9fde852858e1ce566b675b720d upstream. bcm63xx_gpio.h uses macros defined in bcm63xx_cpu.h without including it, leading to the following build failure: CC [M] drivers/mmc/core/cd-gpio.o In file included from arch/mips/include/asm/mach-bcm63xx/gpio.h:4:0, from arch/mips/include/asm/gpio.h:4, from include/linux/gpio.h:30, from drivers/mmc/core/cd-gpio.c:12: arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h: In function 'bcm63xx_gpio_count': arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h:10:2: error: implicit declaration of function 'bcm63xx_get_cpu_id' arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h:11:7: error: 'BCM6358_CPU_ID' undeclared (first use in this function) arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h:11:7: note: each undeclared identifier is reported only once for each function it appears in arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h:13:7: error: 'BCM6338_CPU_ID' undeclared (first use in this function) arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h:15:7: error: 'BCM6345_CPU_ID' undeclared (first use in this function) arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h:17:7: error: 'BCM6368_CPU_ID' undeclared (first use in this function) arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h:19:7: error: 'BCM6348_CPU_ID' undeclared (first use in this function) make[7]: *** [drivers/mmc/core/cd-gpio.o] Error 1 Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Maxime Bizon Cc: Florian Fainelli Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h index 3d5de96d403..1d7dd96aa46 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h @@ -2,6 +2,7 @@ #define BCM63XX_GPIO_H #include +#include int __init bcm63xx_gpio_init(void); From 74b31d2a64a49ce8dbf8620eba0a116a892d4d0b Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Tue, 29 May 2012 02:00:22 -0700 Subject: [PATCH 0106/2357] mac80211: fix ADDBA declined after suspend with wowlan commit 7b21aea04d084916ac4e0e8852dcc9cd60ec0d1d upstream. WLAN_STA_BLOCK_BA is set while suspending but doesn't get cleared when resuming in case of wowlan. This causes further ADDBA requests received to be rejected. Fix it by clearing it in the wowlan path as well. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/util.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 32f7a3b3d43..3862c966dec 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1321,6 +1321,12 @@ int ieee80211_reconfig(struct ieee80211_local *local) } } + /* add back keys */ + list_for_each_entry(sdata, &local->interfaces, list) + if (ieee80211_sdata_running(sdata)) + ieee80211_enable_keys(sdata); + + wake_up: /* * Clear the WLAN_STA_BLOCK_BA flag so new aggregation * sessions can be established after a resume. @@ -1342,12 +1348,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) mutex_unlock(&local->sta_mtx); } - /* add back keys */ - list_for_each_entry(sdata, &local->interfaces, list) - if (ieee80211_sdata_running(sdata)) - ieee80211_enable_keys(sdata); - - wake_up: ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); From 27e73d90ba0c26397eaeed7119553e77ae5bb486 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Wed, 23 May 2012 18:19:51 +0200 Subject: [PATCH 0107/2357] ixp4xx: fix compilation by adding gpiolib support commit 9dde0ae3769875ec1370cb316e50c54b57d52c1a upstream. Once again, ixp4xx no longer even compiles. This patch fixes the issue by converting over to gpiolib. This patch was first made by Imre and posted by Marc, and I added in Russell's suggestion to empty the gpio header file. This fix should also go for 3.1, 3.2, 3.3, and 3.4. Signed-off-by: Richard Cochran Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/Kconfig | 2 +- arch/arm/mach-ixp4xx/common.c | 48 +++++++++++++- arch/arm/mach-ixp4xx/include/mach/gpio.h | 79 +----------------------- 3 files changed, 48 insertions(+), 81 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 36586dba6fa..7a8660a2f26 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -556,7 +556,7 @@ config ARCH_IXP4XX select ARCH_HAS_DMA_SET_COHERENT_MASK select CLKSRC_MMIO select CPU_XSCALE - select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB select GENERIC_CLOCKEVENTS select MIGHT_HAVE_PCI select NEED_MACH_IO_H diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index ebbd7fc90eb..a9f80943d01 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -107,7 +108,7 @@ static signed char irq2gpio[32] = { 7, 8, 9, 10, 11, 12, -1, -1, }; -int gpio_to_irq(int gpio) +static int ixp4xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) { int irq; @@ -117,7 +118,6 @@ int gpio_to_irq(int gpio) } return -EINVAL; } -EXPORT_SYMBOL(gpio_to_irq); int irq_to_gpio(unsigned int irq) { @@ -383,12 +383,56 @@ static struct platform_device *ixp46x_devices[] __initdata = { unsigned long ixp4xx_exp_bus_size; EXPORT_SYMBOL(ixp4xx_exp_bus_size); +static int ixp4xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + gpio_line_config(gpio, IXP4XX_GPIO_IN); + + return 0; +} + +static int ixp4xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, + int level) +{ + gpio_line_set(gpio, level); + gpio_line_config(gpio, IXP4XX_GPIO_OUT); + + return 0; +} + +static int ixp4xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + int value; + + gpio_line_get(gpio, &value); + + return value; +} + +static void ixp4xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, + int value) +{ + gpio_line_set(gpio, value); +} + +static struct gpio_chip ixp4xx_gpio_chip = { + .label = "IXP4XX_GPIO_CHIP", + .direction_input = ixp4xx_gpio_direction_input, + .direction_output = ixp4xx_gpio_direction_output, + .get = ixp4xx_gpio_get_value, + .set = ixp4xx_gpio_set_value, + .to_irq = ixp4xx_gpio_to_irq, + .base = 0, + .ngpio = 16, +}; + void __init ixp4xx_sys_init(void) { ixp4xx_exp_bus_size = SZ_16M; platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices)); + gpiochip_add(&ixp4xx_gpio_chip); + if (cpu_is_ixp46x()) { int region; diff --git a/arch/arm/mach-ixp4xx/include/mach/gpio.h b/arch/arm/mach-ixp4xx/include/mach/gpio.h index 83d6b4ed60b..ef37f2635b0 100644 --- a/arch/arm/mach-ixp4xx/include/mach/gpio.h +++ b/arch/arm/mach-ixp4xx/include/mach/gpio.h @@ -1,79 +1,2 @@ -/* - * arch/arm/mach-ixp4xx/include/mach/gpio.h - * - * IXP4XX GPIO wrappers for arch-neutral GPIO calls - * - * Written by Milan Svoboda - * Based on PXA implementation by Philipp Zabel - * - * 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 __ASM_ARCH_IXP4XX_GPIO_H -#define __ASM_ARCH_IXP4XX_GPIO_H - -#include -#include - -#define __ARM_GPIOLIB_COMPLEX - -static inline int gpio_request(unsigned gpio, const char *label) -{ - return 0; -} - -static inline void gpio_free(unsigned gpio) -{ - might_sleep(); - - return; -} - -static inline int gpio_direction_input(unsigned gpio) -{ - gpio_line_config(gpio, IXP4XX_GPIO_IN); - return 0; -} - -static inline int gpio_direction_output(unsigned gpio, int level) -{ - gpio_line_set(gpio, level); - gpio_line_config(gpio, IXP4XX_GPIO_OUT); - return 0; -} - -static inline int gpio_get_value(unsigned gpio) -{ - int value; - - gpio_line_get(gpio, &value); - - return value; -} - -static inline void gpio_set_value(unsigned gpio, int value) -{ - gpio_line_set(gpio, value); -} - -#include /* cansleep wrappers */ - -extern int gpio_to_irq(int gpio); -#define gpio_to_irq gpio_to_irq -extern int irq_to_gpio(unsigned int irq); - -#endif +/* empty */ From c163f56463e26f771e3dc7e67921f268053ad8e6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 24 May 2012 14:32:20 +0200 Subject: [PATCH 0108/2357] ath9k: fix a use-after-free-bug when ath_tx_setup_buffer() fails commit 81357a281dcc454841532c46b30e6f2ba12b73ea upstream. ath_tx_setup_buffer() can fail if there is no ath_buf left, or if mapping DMA failed. In this case it frees the skb passed to it. If ath_tx_setup_buffer is called from ath_tx_form_aggr, the skb is still linked into the tid buffer list and must be dequeued before being released. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/xmit.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 23eaa1b26eb..d59dd01d6cd 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -64,7 +64,8 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct sk_buff *skb); + struct sk_buff *skb, + bool dequeue); enum { MCS_HT20, @@ -811,7 +812,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, fi = get_frame_info(skb); bf = fi->bf; if (!fi->bf) - bf = ath_tx_setup_buffer(sc, txq, tid, skb); + bf = ath_tx_setup_buffer(sc, txq, tid, skb, true); if (!bf) continue; @@ -1726,7 +1727,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, return; } - bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false); if (!bf) return; @@ -1753,7 +1754,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, bf = fi->bf; if (!bf) - bf = ath_tx_setup_buffer(sc, txq, tid, skb); + bf = ath_tx_setup_buffer(sc, txq, tid, skb, false); if (!bf) return; @@ -1814,7 +1815,8 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct sk_buff *skb) + struct sk_buff *skb, + bool dequeue) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_frame_info *fi = get_frame_info(skb); @@ -1863,6 +1865,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, return bf; error: + if (dequeue) + __skb_unlink(skb, &tid->buf_q); dev_kfree_skb_any(skb); return NULL; } @@ -1893,7 +1897,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, */ ath_tx_send_ampdu(sc, tid, skb, txctl); } else { - bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false); if (!bf) return; From 2b06dfb55b78e57734a696324ce7d593b1c084be Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 30 May 2012 18:23:56 -0400 Subject: [PATCH 0109/2357] x86, amd, xen: Avoid NULL pointer paravirt references commit 1ab46fd319bcf1fcd9fb6311727d532b580e4eba upstream. Stub out MSR methods that aren't actually needed. This fixes a crash as Xen Dom0 on AMD Trinity systems. A bigger patch should be added to remove the paravirt machinery completely for the methods which apparently have no users! Reported-by: Andre Przywara Link: http://lkml.kernel.org/r/20120530222356.GA28417@andromeda.dapyr.net Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/enlighten.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 95dccce8e97..6c7f1e8a312 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1106,7 +1106,10 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .wbinvd = native_wbinvd, .read_msr = native_read_msr_safe, + .rdmsr_regs = native_rdmsr_safe_regs, .write_msr = xen_write_msr_safe, + .wrmsr_regs = native_wrmsr_safe_regs, + .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, From c780682d113ef97164359897f4463585b4c27524 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 14 May 2012 22:45:28 +0300 Subject: [PATCH 0110/2357] NFS: kmalloc() doesn't return an ERR_PTR() commit 5abc03cd919535c61b813f2319cb38326a41e810 upstream. Obviously we should check for NULL here instead of IS_ERR(). Signed-off-by: Dan Carpenter Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/idmap.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index ba3019f5934..3e8edbe71ec 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -640,20 +640,16 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, struct idmap_msg *im; struct idmap *idmap = (struct idmap *)aux; struct key *key = cons->key; - int ret; + int ret = -ENOMEM; /* msg and im are freed in idmap_pipe_destroy_msg */ msg = kmalloc(sizeof(*msg), GFP_KERNEL); - if (IS_ERR(msg)) { - ret = PTR_ERR(msg); + if (!msg) goto out0; - } im = kmalloc(sizeof(*im), GFP_KERNEL); - if (IS_ERR(im)) { - ret = PTR_ERR(im); + if (!im) goto out1; - } ret = nfs_idmap_prepare_message(key->description, im, msg); if (ret < 0) From 27b0a5338ea769a35f1c8346cd07a3c938c919e7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 28 May 2012 11:36:28 -0400 Subject: [PATCH 0111/2357] NFSv4: Map NFS4ERR_SHARE_DENIED into an EACCES error instead of EIO commit fb13bfa7e1bcfdcfdece47c24b62f1a1cad957e9 upstream. If a file OPEN is denied due to a share lock, the resulting NFS4ERR_SHARE_DENIED is currently mapped to the default EIO. This patch adds a more appropriate mapping, and brings Linux into line with what Solaris 10 does. See https://bugzilla.kernel.org/show_bug.cgi?id=43286 Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 99650aaf893..e9b1eb701a0 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -101,6 +101,8 @@ static int nfs4_map_errors(int err) case -NFS4ERR_BADOWNER: case -NFS4ERR_BADNAME: return -EINVAL; + case -NFS4ERR_SHARE_DENIED: + return -EACCES; default: dprintk("%s could not handle NFSv4 error %d\n", __func__, -err); From 7a0786dcc32e5d16721449d43cfb90d7869d08ea Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Tue, 29 May 2012 15:06:46 -0700 Subject: [PATCH 0112/2357] hugetlb: fix resv_map leak in error path commit c50ac050811d6485616a193eb0f37bfbd191cc89 upstream. When called for anonymous (non-shared) mappings, hugetlb_reserve_pages() does a resv_map_alloc(). It depends on code in hugetlbfs's vm_ops->close() to release that allocation. However, in the mmap() failure path, we do a plain unmap_region() without the remove_vma() which actually calls vm_ops->close(). This is a decent fix. This leak could get reintroduced if new code (say, after hugetlb_reserve_pages() in hugetlbfs_file_mmap()) decides to return an error. But, I think it would have to unroll the reservation anyway. Christoph's test case: http://marc.info/?l=linux-mm&m=133728900729735 This patch applies to 3.4 and later. A version for earlier kernels is at https://lkml.org/lkml/2012/5/22/418. Signed-off-by: Dave Hansen Acked-by: Mel Gorman Acked-by: KOSAKI Motohiro Reported-by: Christoph Lameter Tested-by: Christoph Lameter Cc: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/hugetlb.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index ae8f708e3d7..d7c6cc51d58 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2157,6 +2157,15 @@ static void hugetlb_vm_op_open(struct vm_area_struct *vma) kref_get(&reservations->refs); } +static void resv_map_put(struct vm_area_struct *vma) +{ + struct resv_map *reservations = vma_resv_map(vma); + + if (!reservations) + return; + kref_put(&reservations->refs, resv_map_release); +} + static void hugetlb_vm_op_close(struct vm_area_struct *vma) { struct hstate *h = hstate_vma(vma); @@ -2173,7 +2182,7 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma) reserve = (end - start) - region_count(&reservations->regions, start, end); - kref_put(&reservations->refs, resv_map_release); + resv_map_put(vma); if (reserve) { hugetlb_acct_memory(h, -reserve); @@ -2990,12 +2999,16 @@ int hugetlb_reserve_pages(struct inode *inode, set_vma_resv_flags(vma, HPAGE_RESV_OWNER); } - if (chg < 0) - return chg; + if (chg < 0) { + ret = chg; + goto out_err; + } /* There must be enough pages in the subpool for the mapping */ - if (hugepage_subpool_get_pages(spool, chg)) - return -ENOSPC; + if (hugepage_subpool_get_pages(spool, chg)) { + ret = -ENOSPC; + goto out_err; + } /* * Check enough hugepages are available for the reservation. @@ -3004,7 +3017,7 @@ int hugetlb_reserve_pages(struct inode *inode, ret = hugetlb_acct_memory(h, chg); if (ret < 0) { hugepage_subpool_put_pages(spool, chg); - return ret; + goto out_err; } /* @@ -3021,6 +3034,9 @@ int hugetlb_reserve_pages(struct inode *inode, if (!vma || vma->vm_flags & VM_MAYSHARE) region_add(&inode->i_mapping->private_list, from, to); return 0; +out_err: + resv_map_put(vma); + return ret; } void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) From c7faf5bbaeba30053627de3b333d3c17e051ba80 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 19 May 2012 12:12:53 -0400 Subject: [PATCH 0113/2357] sunrpc: fix loss of task->tk_status after rpc_delay call in xprt_alloc_slot commit 1afeaf5c29aa07db25760d2fbed5c08a3aec3498 upstream. xprt_alloc_slot will call rpc_delay() to make the task wait a bit before retrying when it gets back an -ENOMEM error from xprt_dynamic_alloc_slot. The problem is that rpc_delay will clear the task->tk_status, causing call_reserveresult to abort the task. The solution is simply to let call_reserveresult handle the ENOMEM error directly. Reported-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/clnt.c | 2 ++ net/sunrpc/xprt.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index adf2990aceb..25302c80246 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1288,6 +1288,8 @@ call_reserveresult(struct rpc_task *task) } switch (status) { + case -ENOMEM: + rpc_delay(task, HZ >> 2); case -EAGAIN: /* woken up; retry */ task->tk_action = call_reserve; return; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 0cbcd1ab49a..da72492360b 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -984,15 +984,16 @@ static void xprt_alloc_slot(struct rpc_task *task) goto out_init_req; switch (PTR_ERR(req)) { case -ENOMEM: - rpc_delay(task, HZ >> 2); dprintk("RPC: dynamic allocation of request slot " "failed! Retrying\n"); + task->tk_status = -ENOMEM; break; case -EAGAIN: rpc_sleep_on(&xprt->backlog, task, NULL); dprintk("RPC: waiting for request slot\n"); + default: + task->tk_status = -EAGAIN; } - task->tk_status = -EAGAIN; return; out_init_req: task->tk_status = 0; From f9a07f3089169d943ba0e61e7670e61199020870 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 12 Apr 2012 12:49:26 +0200 Subject: [PATCH 0114/2357] iommu/amd: Check for the right TLP prefix bit commit a3b93121430c7b46c2895a7744261be107ccdf7f upstream. Unfortunatly the PRI spec changed and moved the TLP-prefix-required bit to a different location. This patch makes the necessary change in the AMD IOMMU driver. Regressions are not expected because all hardware implementing the PRI capability sets this bit to zero anyway. Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index a5bee8e2dfc..08f3eecb87a 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2035,20 +2035,20 @@ static int pdev_iommuv2_enable(struct pci_dev *pdev) } /* FIXME: Move this to PCI code */ -#define PCI_PRI_TLP_OFF (1 << 2) +#define PCI_PRI_TLP_OFF (1 << 15) bool pci_pri_tlp_required(struct pci_dev *pdev) { - u16 control; + u16 status; int pos; pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); if (!pos) return false; - pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); + pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status); - return (control & PCI_PRI_TLP_OFF) ? true : false; + return (status & PCI_PRI_TLP_OFF) ? true : false; } /* From c2fcf3a04bc4c9a9b97962b3b71c86ba393672e3 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 12 Apr 2012 14:12:00 +0200 Subject: [PATCH 0115/2357] iommu/amd: Add workaround for event log erratum commit 3d06fca8d2aa3543030e40b95f1d62f9f5a03540 upstream. Due to a recent erratum it can happen that the head pointer of the event-log is updated before the actual event-log entry is written. This patch implements the recommended workaround. Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 08f3eecb87a..d90a421e9ca 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -450,12 +450,27 @@ static void dump_command(unsigned long phys_addr) static void iommu_print_event(struct amd_iommu *iommu, void *__evt) { - u32 *event = __evt; - int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; - int devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK; - int domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK; - int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK; - u64 address = (u64)(((u64)event[3]) << 32) | event[2]; + int type, devid, domid, flags; + volatile u32 *event = __evt; + int count = 0; + u64 address; + +retry: + type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; + devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK; + domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK; + flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK; + address = (u64)(((u64)event[3]) << 32) | event[2]; + + if (type == 0) { + /* Did we hit the erratum? */ + if (++count == LOOP_TIMEOUT) { + pr_err("AMD-Vi: No event written to event log\n"); + return; + } + udelay(1); + goto retry; + } printk(KERN_ERR "AMD-Vi: Event logged ["); @@ -508,6 +523,8 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt) default: printk(KERN_ERR "UNKNOWN type=0x%02x]\n", type); } + + memset(__evt, 0, 4 * sizeof(u32)); } static void iommu_poll_events(struct amd_iommu *iommu) From 70838c4536517458c38249763311ff56727cd293 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 23 May 2012 11:48:59 -0400 Subject: [PATCH 0116/2357] drm/radeon: fix XFX quirk commit 1ebf169ad4dc68f18cc0dab35163b0f324fc6c41 upstream. Only override the ddc bus if the connector doesn't have a valid one. The existing code overrode the ddc bus for all connectors even if it had ddc bus. Fixes ddc on another XFX card with the same pci ids that was broken by the quirk overwriting the correct ddc bus. Reported-by: Mehdi Aqadjani Memar Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_atombios.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f6e69b8c06c..b1e3820df36 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -444,7 +444,9 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, */ if ((dev->pdev->device == 0x9498) && (dev->pdev->subsystem_vendor == 0x1682) && - (dev->pdev->subsystem_device == 0x2452)) { + (dev->pdev->subsystem_device == 0x2452) && + (i2c_bus->valid == false) && + !(supported_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))) { struct radeon_device *rdev = dev->dev_private; *i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93); } From 772605e73b1f07be3736cc3fc0bc0ce0c56db773 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 24 May 2012 22:55:15 -0400 Subject: [PATCH 0117/2357] drm/radeon: fix typo in trinity tiling setup commit 1f73cca799d29df80de3e8f1f1c488485467577a upstream. Using the wrong union. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/ni.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index a48ca53fcd6..2432f9a3485 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -865,7 +865,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ if (rdev->flags & RADEON_IS_IGP) - rdev->config.evergreen.tile_config |= 1 << 4; + rdev->config.cayman.tile_config |= 1 << 4; else rdev->config.cayman.tile_config |= ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; From ae6bfcca08d692defdbde53e36963752211b6c03 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 12 May 2012 22:22:58 +0200 Subject: [PATCH 0118/2357] drm/i915: properly handle interlaced bit for sdvo dtd conversion commit 59d92bfa5f0cdf57f82f5181b0ad6af75c3fdf41 upstream. We've simply ignored this, which isn't too great. With this, interlaced 1080i works on my HDMI screen connected through sdvo. For no apparent reason anything else still doesn't work as it should. While at it, give these magic numbers in the dtd proper names and add a comment that they match with EDID detailed timings. v2: Actually use the right bit for interlaced. Tested-by: Peter Ross Reviewed-by: Paulo Zanoni Signed-Off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_sdvo.c | 12 ++++++++---- drivers/gpu/drm/i915/intel_sdvo_regs.h | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index ae5e748f39b..eea58c6cb05 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -769,10 +769,12 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, ((v_sync_len & 0x30) >> 4); dtd->part2.dtd_flags = 0x18; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + dtd->part2.dtd_flags |= DTD_FLAG_INTERLACE; if (mode->flags & DRM_MODE_FLAG_PHSYNC) - dtd->part2.dtd_flags |= 0x2; + dtd->part2.dtd_flags |= DTD_FLAG_HSYNC_POSITIVE; if (mode->flags & DRM_MODE_FLAG_PVSYNC) - dtd->part2.dtd_flags |= 0x4; + dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE; dtd->part2.sdvo_flags = 0; dtd->part2.v_sync_off_high = v_sync_offset & 0xc0; @@ -806,9 +808,11 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, mode->clock = dtd->part1.clock * 10; mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); - if (dtd->part2.dtd_flags & 0x2) + if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE) + mode->flags |= DRM_MODE_FLAG_INTERLACE; + if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) mode->flags |= DRM_MODE_FLAG_PHSYNC; - if (dtd->part2.dtd_flags & 0x4) + if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) mode->flags |= DRM_MODE_FLAG_PVSYNC; } diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 6b7b22f4d63..9d030142ee4 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -61,6 +61,11 @@ struct intel_sdvo_caps { u16 output_flags; } __attribute__((packed)); +/* Note: SDVO detailed timing flags match EDID misc flags. */ +#define DTD_FLAG_HSYNC_POSITIVE (1 << 1) +#define DTD_FLAG_VSYNC_POSITIVE (1 << 2) +#define DTD_FLAG_INTERLACE (1 << 7) + /** This matches the EDID DTD structure, more or less */ struct intel_sdvo_dtd { struct { From 3baa3206a209b224d1265665d6f969fdbd99c08d Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 22 May 2012 15:23:24 -0300 Subject: [PATCH 0119/2357] drm/i915: Adding TV Out Missing modes. commit 9589919fb3d269d4202a112b197468c7db1f97a3 upstream. These 2 modes were removed by mistake during a clean up. So, now it is time to add them back. For further info about supported mode and standard timing table please check: VOL_3_display_registers_updated.pdf at intellinuxgraphics.org. Note that this regression has been introduce in commit 55a6713b3f30a5024056027e9dbf03ac8f13bfc9 Author: Rodrigo Vivi Date: Thu Dec 15 14:47:33 2011 -0200 drm/i915: Removing TV Out modes. and this commit partially reverts it by re-adding the wrongly removed modes. Reported-by: Robert Lowery Signed-off-by: Rodrigo Vivi [danvet: Pimped commit message to cite the commit that introduced this regression.] Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_tv.c | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 05f765ef546..586d26cd8a8 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -673,6 +673,54 @@ static const struct tv_mode tv_modes[] = { .filter_table = filter_table, }, + { + .name = "480p", + .clock = 107520, + .refresh = 59940, + .oversample = TV_OVERSAMPLE_4X, + .component_only = 1, + + .hsync_end = 64, .hblank_end = 122, + .hblank_start = 842, .htotal = 857, + + .progressive = true, .trilevel_sync = false, + + .vsync_start_f1 = 12, .vsync_start_f2 = 12, + .vsync_len = 12, + + .veq_ena = false, + + .vi_end_f1 = 44, .vi_end_f2 = 44, + .nbr_end = 479, + + .burst_ena = false, + + .filter_table = filter_table, + }, + { + .name = "576p", + .clock = 107520, + .refresh = 50000, + .oversample = TV_OVERSAMPLE_4X, + .component_only = 1, + + .hsync_end = 64, .hblank_end = 139, + .hblank_start = 859, .htotal = 863, + + .progressive = true, .trilevel_sync = false, + + .vsync_start_f1 = 10, .vsync_start_f2 = 10, + .vsync_len = 10, + + .veq_ena = false, + + .vi_end_f1 = 48, .vi_end_f2 = 48, + .nbr_end = 575, + + .burst_ena = false, + + .filter_table = filter_table, + }, { .name = "720p@60Hz", .clock = 148800, From 46790988c91cc239152996c9ed4b4c3dcd2703d8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 22 May 2012 21:41:25 +0200 Subject: [PATCH 0120/2357] drm/i915: wait for a vblank to pass after tv detect commit bf2125e2f7e931b50a6c76ba0435ba001409ccbf upstream. Otherwise the hw will get confused and result in a black screen. This regression has been most likely introduce in commit 974b93315b2213b74a42a87e8a9d4fc8c0dbe90c Author: Chris Wilson Date: Sun Sep 5 00:44:20 2010 +0100 drm/i915/tv: Poll for DAC state change That commit replace the first msleep(20) with a busy-loop, but failed to keep the 2nd msleep around. Later on we've replaced all these msleep(20) by proper vblanks. For reference also see the commit in xf86-video-intel: commit 1142be53eb8d2ee8a9b60ace5d49f0ba27332275 Author: Jesse Barnes Date: Mon Jun 9 08:52:59 2008 -0700 Fix TV programming: add vblank wait after TV_CTL writes Fxies FDO bug #14000; we need to wait for vblank after writing TV_CTL or following "DPMS on" calls may not actually enable the output. v2: As suggested by Chris Wilson, add a small comment to ensure that no one accidentally removes this vblank wait again - there really seems to be no sane explanation for why we need it, but it is required. Launchpad: https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel/+bug/763688 Reported-and-Tested-by: Robert Lowery Cc: Rodrigo Vivi Acked-by: Chris Wilson Signed-Off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_tv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 586d26cd8a8..c82b1d4fd24 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1233,6 +1233,11 @@ intel_tv_detect_type(struct intel_tv *intel_tv, I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); I915_WRITE(TV_CTL, save_tv_ctl); + POSTING_READ(TV_CTL); + + /* For unknown reasons the hw barfs if we don't do this vblank wait. */ + intel_wait_for_vblank(intel_tv->base.base.dev, + to_intel_crtc(intel_tv->base.base.crtc)->pipe); /* Restore interrupt config */ if (connector->polled & DRM_CONNECTOR_POLL_HPD) { From e552a3bfe0c60c65d35cc3ee6a5f20d9702ebc9a Mon Sep 17 00:00:00 2001 From: Jan-Benedict Glaw Date: Tue, 22 May 2012 15:21:53 +0200 Subject: [PATCH 0121/2357] drm/i915: no lvds quirk for HP t5740e Thin Client commit 3347111999870c37eab1b969e90af9fdaf0334ba upstream. This box has DisplayPort and VGA, but no LVDS. Product specs are at http://h10010.www1.hp.com/wwpc/us/en/sm/WF25a/12454-12454-321959-338927-3640406-4282707.html?dnr=1 and dmidecode output can be found at http://www.getslash.de/bug_attachments/dmidecode-t5740e.txt Signed-off-by: Jan-Benedict Glaw Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 9c71183629c..9fadd643181 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -745,6 +745,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "AT5NM10T-I"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Hewlett-Packard HP t5740e Thin Client", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP t5740e Thin Client"), + }, + }, { .callback = intel_no_lvds_dmi_callback, .ident = "Hewlett-Packard t5745", From 08c372db1aa0a65e0b2135e8556be35e1175f9b9 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Tue, 29 May 2012 15:06:30 -0700 Subject: [PATCH 0122/2357] kbuild: install kernel-page-flags.h commit 9295b7a07c859a42346221b5839be0ae612333b0 upstream. Programs using /proc/kpageflags need to know about the various flags. The provides them and the comments in the file indicate that it is supposed to be used by user-level code. But the file is not installed. Install the headers and mark the unstable flags as out-of-bounds. The page-type tool is also adjusted to not duplicate the definitions Signed-off-by: Ulrich Drepper Acked-by: KOSAKI Motohiro Acked-by: Fengguang Wu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/Kbuild | 1 + include/linux/kernel-page-flags.h | 4 ++++ tools/vm/page-types.c | 28 +--------------------------- 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 3c9b616c834..50f55c77f8b 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -227,6 +227,7 @@ header-y += kd.h header-y += kdev_t.h header-y += kernel.h header-y += kernelcapi.h +header-y += kernel-page-flags.h header-y += keyboard.h header-y += keyctl.h header-y += l2tp.h diff --git a/include/linux/kernel-page-flags.h b/include/linux/kernel-page-flags.h index 26a65711676..a1bdf696635 100644 --- a/include/linux/kernel-page-flags.h +++ b/include/linux/kernel-page-flags.h @@ -32,6 +32,8 @@ #define KPF_KSM 21 #define KPF_THP 22 +#ifdef __KERNEL__ + /* kernel hacking assistances * WARNING: subject to change, never rely on them! */ @@ -44,4 +46,6 @@ #define KPF_ARCH 38 #define KPF_UNCACHED 39 +#endif /* __KERNEL__ */ + #endif /* LINUX_KERNEL_PAGE_FLAGS_H */ diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index 7dab7b25b5c..f77c96bec7e 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -35,6 +35,7 @@ #include #include #include "../../include/linux/magic.h" +#include "../../include/linux/kernel-page-flags.h" #ifndef MAX_PATH @@ -73,33 +74,6 @@ #define KPF_BYTES 8 #define PROC_KPAGEFLAGS "/proc/kpageflags" -/* copied from kpageflags_read() */ -#define KPF_LOCKED 0 -#define KPF_ERROR 1 -#define KPF_REFERENCED 2 -#define KPF_UPTODATE 3 -#define KPF_DIRTY 4 -#define KPF_LRU 5 -#define KPF_ACTIVE 6 -#define KPF_SLAB 7 -#define KPF_WRITEBACK 8 -#define KPF_RECLAIM 9 -#define KPF_BUDDY 10 - -/* [11-20] new additions in 2.6.31 */ -#define KPF_MMAP 11 -#define KPF_ANON 12 -#define KPF_SWAPCACHE 13 -#define KPF_SWAPBACKED 14 -#define KPF_COMPOUND_HEAD 15 -#define KPF_COMPOUND_TAIL 16 -#define KPF_HUGE 17 -#define KPF_UNEVICTABLE 18 -#define KPF_HWPOISON 19 -#define KPF_NOPAGE 20 -#define KPF_KSM 21 -#define KPF_THP 22 - /* [32-] kernel hacking assistances */ #define KPF_RESERVED 32 #define KPF_MLOCKED 33 From 58f9c9764228f69ef523dcf5f87d5b587464fb52 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 30 May 2012 07:51:07 -0700 Subject: [PATCH 0123/2357] mm: fix vma_resv_map() NULL pointer commit 4523e1458566a0e8ecfaff90f380dd23acc44d27 upstream. hugetlb_reserve_pages() can be used for either normal file-backed hugetlbfs mappings, or MAP_HUGETLB. In the MAP_HUGETLB, semi-anonymous mode, there is not a VMA around. The new call to resv_map_put() assumed that there was, and resulted in a NULL pointer dereference: BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 IP: vma_resv_map+0x9/0x30 PGD 141453067 PUD 1421e1067 PMD 0 Oops: 0000 [#1] PREEMPT SMP ... Pid: 14006, comm: trinity-child6 Not tainted 3.4.0+ #36 RIP: vma_resv_map+0x9/0x30 ... Process trinity-child6 (pid: 14006, threadinfo ffff8801414e0000, task ffff8801414f26b0) Call Trace: resv_map_put+0xe/0x40 hugetlb_reserve_pages+0xa6/0x1d0 hugetlb_file_setup+0x102/0x2c0 newseg+0x115/0x360 ipcget+0x1ce/0x310 sys_shmget+0x5a/0x60 system_call_fastpath+0x16/0x1b This was reported by Dave Jones, but was reproducible with the libhugetlbfs test cases, so shame on me for not running them in the first place. With this, the oops is gone, and the output of libhugetlbfs's run_tests.py is identical to plain 3.4 again. [ Marked for stable, since this was introduced by commit c50ac050811d ("hugetlb: fix resv_map leak in error path") which was also marked for stable ] Reported-by: Dave Jones Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Christoph Lameter Cc: Andrea Arcangeli Cc: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/hugetlb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index d7c6cc51d58..263e17703b3 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3035,7 +3035,8 @@ int hugetlb_reserve_pages(struct inode *inode, region_add(&inode->i_mapping->private_list, from, to); return 0; out_err: - resv_map_put(vma); + if (vma) + resv_map_put(vma); return ret; } From 22aca500eb55daf5c84bffb001d3cce14da08b08 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 May 2012 18:00:43 +0200 Subject: [PATCH 0124/2357] ALSA: usb-audio: fix rate_list memory leak commit 5cd5d7c44990658df6ab49f6253c39617c53b03d upstream. The array of sample rates is reallocated every time when opening the PCM device, but was freed only once when unplugging the device. Reported-by: "Alexander E. Patrakov" Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/pcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0eed6115c2d..67a4d6dbb32 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -699,6 +699,9 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, int count = 0, needs_knot = 0; int err; + kfree(subs->rate_list.list); + subs->rate_list.list = NULL; + list_for_each_entry(fp, &subs->fmt_list, list) { if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) return 0; From 75df3ae2060eb00b909ac65fc4d2798c4e53969a Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Thu, 17 May 2012 00:13:02 +0900 Subject: [PATCH 0125/2357] slub: fix a memory leak in get_partial_node() commit 02d7633fa567be7bf55a993b79d2a31b95ce2227 upstream. In the case which is below, 1. acquire slab for cpu partial list 2. free object to it by remote cpu 3. page->freelist = t then memory leak is occurred. Change acquire_slab() not to zap freelist when it works for cpu partial list. I think it is a sufficient solution for fixing a memory leak. Below is output of 'slabinfo -r kmalloc-256' when './perf stat -r 30 hackbench 50 process 4000 > /dev/null' is done. ***Vanilla*** Sizes (bytes) Slabs Debug Memory ------------------------------------------------------------------------ Object : 256 Total : 468 Sanity Checks : Off Total: 3833856 SlabObj: 256 Full : 111 Redzoning : Off Used : 2004992 SlabSiz: 8192 Partial: 302 Poisoning : Off Loss : 1828864 Loss : 0 CpuSlab: 55 Tracking : Off Lalig: 0 Align : 8 Objects: 32 Tracing : Off Lpadd: 0 ***Patched*** Sizes (bytes) Slabs Debug Memory ------------------------------------------------------------------------ Object : 256 Total : 300 Sanity Checks : Off Total: 2457600 SlabObj: 256 Full : 204 Redzoning : Off Used : 2348800 SlabSiz: 8192 Partial: 33 Poisoning : Off Loss : 108800 Loss : 0 CpuSlab: 63 Tracking : Off Lalig: 0 Align : 8 Objects: 32 Tracing : Off Lpadd: 0 Total and loss number is the impact of this patch. Acked-by: Christoph Lameter Signed-off-by: Joonsoo Kim Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- mm/slub.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 80848cd3901..71de9b5685f 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1514,15 +1514,19 @@ static inline void *acquire_slab(struct kmem_cache *s, freelist = page->freelist; counters = page->counters; new.counters = counters; - if (mode) + if (mode) { new.inuse = page->objects; + new.freelist = NULL; + } else { + new.freelist = freelist; + } VM_BUG_ON(new.frozen); new.frozen = 1; } while (!__cmpxchg_double_slab(s, page, freelist, counters, - NULL, new.counters, + new.freelist, new.counters, "lock and freeze")); remove_partial(n, page); @@ -1564,7 +1568,6 @@ static void *get_partial_node(struct kmem_cache *s, object = t; available = page->objects - page->inuse; } else { - page->freelist = t; available = put_cpu_partial(s, page, 0); stat(s, CPU_PARTIAL_NODE); } From 15de0eade174f9aade57a4080f1bac1a36e45e83 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 29 May 2012 22:03:48 -0400 Subject: [PATCH 0126/2357] vfs: umount_tree() might be called on subtree that had never made it commit 63d37a84ab6004c235314ffd7a76c5eb28c2fae0 upstream. __mnt_make_shortterm() in there undoes the effect of __mnt_make_longterm() we'd done back when we set ->mnt_ns non-NULL; it should not be done to vfsmounts that had never gone through commit_tree() and friends. Kudos to lczerner for catching that one... Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/namespace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/namespace.c b/fs/namespace.c index e6081996c9a..4e465397e45 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1073,8 +1073,9 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill) list_del_init(&p->mnt_expire); list_del_init(&p->mnt_list); __touch_mnt_namespace(p->mnt_ns); + if (p->mnt_ns) + __mnt_make_shortterm(p); p->mnt_ns = NULL; - __mnt_make_shortterm(p); list_del_init(&p->mnt_child); if (mnt_has_parent(p)) { p->mnt_parent->mnt_ghosts++; From c8c0b91569f01d7713c843245c538b51f733646a Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Tue, 29 May 2012 11:02:21 -0700 Subject: [PATCH 0127/2357] vfs: increment iversion when a file is truncated commit 799243a389bde0de10fa21ca1ca453d2fe538b85 upstream. When a file is truncated with truncate()/ftruncate() and then closed, iversion is not updated. This patch uses ATTR_SIZE flag as an indication to increment iversion. Mimi said: On fput(), i_version is used to detect and flag files that have changed and need to be re-measured in the IMA measurement policy. When a file is truncated with truncate()/ftruncate() and then closed, i_version is not updated. As a result, although the file has changed, it will not be re-measured and added to the IMA measurement list on subsequent access. Signed-off-by: Dmitry Kasatkin Acked-by: Mimi Zohar Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/attr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/attr.c b/fs/attr.c index 73f69a6ce9e..d94d1b63c63 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -176,6 +176,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr) return -EPERM; } + if ((ia_valid & ATTR_SIZE) && IS_I_VERSION(inode)) { + if (attr->ia_size != inode->i_size) + inode_inc_iversion(inode); + } + if ((ia_valid & ATTR_MODE)) { umode_t amode = attr->ia_mode; /* Flag setting protected by i_mutex */ From fd62fa971584007e612be6e531101842de97715a Mon Sep 17 00:00:00 2001 From: Stephan Gatzka Date: Sat, 2 Jun 2012 03:04:06 +0000 Subject: [PATCH 0128/2357] fec_mpc52xx: fix timestamp filtering commit 9ca3cc6f3026946ba655e863ca2096339e667639 upstream. skb_defer_rx_timestamp was called with a freshly allocated skb but must be called with rskb instead. Signed-off-by: Stephan Gatzka Acked-by: Richard Cochran Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/freescale/fec_mpc52xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c index 7b34d8c698d..fc87e8933ce 100644 --- a/drivers/net/ethernet/freescale/fec_mpc52xx.c +++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c @@ -437,7 +437,7 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) length = status & BCOM_FEC_RX_BD_LEN_MASK; skb_put(rskb, length - 4); /* length without CRC32 */ rskb->protocol = eth_type_trans(rskb, dev); - if (!skb_defer_rx_timestamp(skb)) + if (!skb_defer_rx_timestamp(rskb)) netif_rx(rskb); spin_lock(&priv->lock); From cdd5479bf6cfbaf84308beda5b76037dbea471b1 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Mon, 21 May 2012 20:29:45 -0700 Subject: [PATCH 0129/2357] x86, x32, ptrace: Remove PTRACE_ARCH_PRCTL for x32 commit bad1a753d4d4deb09d4bc0bac1dd4fc3298502e9 upstream. When I added x32 ptrace to 3.4 kernel, I also include PTRACE_ARCH_PRCTL support for x32 GDB For ARCH_GET_FS/GS, it takes a pointer to int64. But at user level, ARCH_GET_FS/GS takes a pointer to int32. So I have to add x32 ptrace to glibc to handle it with a temporary int64 passed to kernel and copy it back to GDB as int32. Roland suggested that PTRACE_ARCH_PRCTL is obsolete and x32 GDB should use fs_base and gs_base fields of user_regs_struct instead. Accordingly, remove PTRACE_ARCH_PRCTL completely from the x32 code to avoid possible memory overrun when pointer to int32 is passed to kernel. Link: http://lkml.kernel.org/r/CAMe9rOpDzHfS7NH7m1vmD9QRw8SSj4Sc%2BaNOgcWm_WJME2eRsQ@mail.gmail.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/ptrace.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 685845cf16e..cf1178332bc 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1211,12 +1211,6 @@ static long x32_arch_ptrace(struct task_struct *child, 0, sizeof(struct user_i387_struct), datap); - /* normal 64bit interface to access TLS data. - Works just like arch_prctl, except that the arguments - are reversed. */ - case PTRACE_ARCH_PRCTL: - return do_arch_prctl(child, data, addr); - default: return compat_ptrace_request(child, request, addr, data); } From d961b4e3f741d32fb5fe96fe1123c96a3025a1db Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 30 May 2012 11:43:19 -0400 Subject: [PATCH 0130/2357] x86: Reset the debug_stack update counter commit c0525a6972d3f1fb83058ef503e183475d6e4e26 upstream. When an NMI goes off and it sees that it preempted the debug stack, to keep the debug stack safe, it changes the IDT to point to one that does not modify the stack on breakpoint (to allow breakpoints in NMIs). But the variable that gets set to know to undo it on exit never gets cleared on exit. Thus every NMI will reset it on exit the first time it is done even if it does not need to be reset. [ Added H. Peter Anvin's suggestion to use this_cpu_read/write ] Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/nmi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index 47acaf31916..32856fa4384 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c @@ -491,14 +491,16 @@ static inline void nmi_nesting_preprocess(struct pt_regs *regs) */ if (unlikely(is_debug_stack(regs->sp))) { debug_stack_set_zero(); - __get_cpu_var(update_debug_stack) = 1; + this_cpu_write(update_debug_stack, 1); } } static inline void nmi_nesting_postprocess(void) { - if (unlikely(__get_cpu_var(update_debug_stack))) + if (unlikely(this_cpu_read(update_debug_stack))) { debug_stack_reset(); + this_cpu_write(update_debug_stack, 0); + } } #endif From a5b57cd820528f863d519ac5a0f6a94e5e8b3a0e Mon Sep 17 00:00:00 2001 From: Dmitry Maluka Date: Fri, 11 May 2012 20:51:51 +0300 Subject: [PATCH 0131/2357] mtd: nand: fix scan_read_raw_oob commit 34a5704d91d6f8376a4c0a0143a1dd3eb3ccb37e upstream. It seems there is a bug in scan_read_raw_oob() in nand_bbt.c which should cause wrong functioning of NAND_BBT_SCANALLPAGES option. Artem: the patch did not apply and I had to amend it a bit. Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/nand_bbt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 20a112f591f..30d1319ff06 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -324,6 +324,7 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, buf += mtd->oobsize + mtd->writesize; len -= mtd->writesize; + offs += mtd->writesize; } return 0; } From bdcefb1987edb1c62828d6c79f93e4b7af8734e2 Mon Sep 17 00:00:00 2001 From: Frank Svendsboe Date: Thu, 17 May 2012 22:43:09 +0200 Subject: [PATCH 0132/2357] mtd: of_parts: fix breakage in Kconfig commit 2e929d001e85126d9267de373d4b76014789661d upstream. MTD_OF_PARTS and the default setting is not working due to using 'Y' instead of 'y', introduced in commit d6137badeff1ef64b4e0092ec249ebdeaeb3ff37. This made our board, and possibly other boards using DTS defined partitions and not having CONFIG_MTD_OF_PARTS=y defined in the defconfig, fail to mount root. Signed-off-by: Frank Svendsboe Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5760c1a4b3f..27143e042af 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -128,7 +128,7 @@ config MTD_AFS_PARTS config MTD_OF_PARTS tristate "OpenFirmware partitioning information support" - default Y + default y depends on OF help This provides a partition parsing function which derives From 29924c0318327d0444e0317587faf4a0693527a8 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 24 May 2012 00:17:23 +0200 Subject: [PATCH 0133/2357] mtd: block2mtd: fix recursive call of mtd_writev commit 2e24e32e2759348c9290404abad4f729f791bfad upstream. The 'mtd_writev' interface calls the function assigned to the '_write' field of a given mtd device if that is not NULL. The block2mtd driver sets the '_writev' field to the 'mtd_writev' function itself and thus causes a endless loop. This is caused by 1dbebd32562b3c2caeca35960e5cb00bfcc12900 (mtd: harmonize mtd_writev usage). Remove the assignment from the block2mtd driver to fix the issue. Signed-off-by: Gabor Juhos Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/devices/block2mtd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index a4a80b742e6..7d7000d2fff 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -271,7 +271,6 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) dev->mtd.flags = MTD_CAP_RAM; dev->mtd._erase = block2mtd_erase; dev->mtd._write = block2mtd_write; - dev->mtd._writev = mtd_writev; dev->mtd._sync = block2mtd_sync; dev->mtd._read = block2mtd_read; dev->mtd.priv = dev; From 1e98ce80a4493f32b44f227d6050318462ca9d5d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 25 May 2012 16:22:42 +0200 Subject: [PATCH 0134/2357] mtd: mxc_nand: move ecc strengh setup before nand_scan_tail commit 4a43faf54e9173b6acce37cf7f053fc9515a2cdf upstream. Since commit 6a918bade9dab40aaef80559bd1169c69e8d69cb, the mxc_nand driver fails with: Driver must set ecc.strength when using hardware ECC This is because nand_scan_tail checks for correct ecc strength settings, so we must set them up before nand_scan_tail. Signed-off-by: Sascha Hauer Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/mxc_nand.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index cc0678a967c..6f87c7464ec 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1219,12 +1219,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) if (nfc_is_v21() && mtd->writesize == 4096) this->ecc.layout = &nandv2_hw_eccoob_4k; - /* second phase scan */ - if (nand_scan_tail(mtd)) { - err = -ENXIO; - goto escan; - } - if (this->ecc.mode == NAND_ECC_HW) { if (nfc_is_v1()) this->ecc.strength = 1; @@ -1232,6 +1226,12 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->ecc.strength = (host->eccsize == 4) ? 4 : 8; } + /* second phase scan */ + if (nand_scan_tail(mtd)) { + err = -ENXIO; + goto escan; + } + /* Register the partitions */ mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts, pdata->nr_parts); From 44920b1991d9182bc3ff8f90df71b0e5311448dc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 30 May 2012 10:09:30 -0400 Subject: [PATCH 0135/2357] drm/radeon: fix regression in UMS CS ioctl commit 9b00147d9f2ba137ce74b66b768a8312be0b6781 upstream. radeon_cs_parser_init is called by both the legacy UMS CS ioctl and the KMS CS ioctl. Protect KMS specific pieces of the code by checking that rdev is not NULL. Reported-by: Michael Burian Signed-off-by: Alex Deucher Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_cs.c | 31 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 5cac8327833..2418cf6da1c 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -158,6 +158,7 @@ static int radeon_cs_sync_rings(struct radeon_cs_parser *p) return 0; } +/* XXX: note that this is called from the legacy UMS CS ioctl as well */ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) { struct drm_radeon_cs *cs = data; @@ -252,22 +253,24 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) } } - if ((p->cs_flags & RADEON_CS_USE_VM) && - !p->rdev->vm_manager.enabled) { - DRM_ERROR("VM not active on asic!\n"); - return -EINVAL; - } - - /* we only support VM on SI+ */ - if ((p->rdev->family >= CHIP_TAHITI) && - ((p->cs_flags & RADEON_CS_USE_VM) == 0)) { - DRM_ERROR("VM required on SI+!\n"); - return -EINVAL; - } + /* these are KMS only */ + if (p->rdev) { + if ((p->cs_flags & RADEON_CS_USE_VM) && + !p->rdev->vm_manager.enabled) { + DRM_ERROR("VM not active on asic!\n"); + return -EINVAL; + } - if (radeon_cs_get_ring(p, ring, priority)) - return -EINVAL; + /* we only support VM on SI+ */ + if ((p->rdev->family >= CHIP_TAHITI) && + ((p->cs_flags & RADEON_CS_USE_VM) == 0)) { + DRM_ERROR("VM required on SI+!\n"); + return -EINVAL; + } + if (radeon_cs_get_ring(p, ring, priority)) + return -EINVAL; + } /* deal with non-vm */ if ((p->chunk_ib_idx != -1) && From d8d09befb4156f23d50a607c75e99dd06e8bccf8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 31 May 2012 18:53:36 -0400 Subject: [PATCH 0136/2357] drm/radeon: fix bank information in tiling config commit 29d654067a98c1cb8874c774e5fd799a038af8a6 upstream. While there are cards with more than 8 mem banks, the max number of banks from a tiling perspective is 8, so cap the tiling config at 8 banks. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=43448 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 9 ++++++--- drivers/gpu/drm/radeon/ni.c | 9 ++++++--- drivers/gpu/drm/radeon/rv770.c | 8 ++++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index cfa372cb1cb..03f4217eb6a 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2136,9 +2136,12 @@ static void evergreen_gpu_init(struct radeon_device *rdev) /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ if (rdev->flags & RADEON_IS_IGP) rdev->config.evergreen.tile_config |= 1 << 4; - else - rdev->config.evergreen.tile_config |= - ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; + else { + if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + rdev->config.evergreen.tile_config |= 1 << 4; + else + rdev->config.evergreen.tile_config |= 0 << 4; + } rdev->config.evergreen.tile_config |= ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8; rdev->config.evergreen.tile_config |= diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 2432f9a3485..93eb6f94229 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -866,9 +866,12 @@ static void cayman_gpu_init(struct radeon_device *rdev) /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ if (rdev->flags & RADEON_IS_IGP) rdev->config.cayman.tile_config |= 1 << 4; - else - rdev->config.cayman.tile_config |= - ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; + else { + if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + rdev->config.cayman.tile_config |= 1 << 4; + else + rdev->config.cayman.tile_config |= 0 << 4; + } rdev->config.cayman.tile_config |= ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8; rdev->config.cayman.tile_config |= diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index cdab1aeaed6..bf50e4bfcb1 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -689,8 +689,12 @@ static void rv770_gpu_init(struct radeon_device *rdev) if (rdev->family == CHIP_RV770) gb_tiling_config |= BANK_TILING(1); - else - gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); + else { + if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + gb_tiling_config |= BANK_TILING(1); + else + gb_tiling_config |= BANK_TILING(0); + } rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3); gb_tiling_config |= GROUP_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); if ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) From fe3777aab674403f6da7f168b28b5ef5d369e426 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 31 May 2012 18:54:43 -0400 Subject: [PATCH 0137/2357] drm/radeon: properly program gart on rv740, juniper, cypress, barts, hemlock commit 0b8c30bc4943137a4a36b9cb059b1cc684f5d702 upstream. Need to program an additional VM register. This doesn't not currently cause any problems, but allows us to program the proper backend map in a subsequent patch which should improve performance on these asics. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 5 +++++ drivers/gpu/drm/radeon/evergreend.h | 1 + drivers/gpu/drm/radeon/rv770.c | 2 ++ drivers/gpu/drm/radeon/rv770d.h | 1 + 4 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 03f4217eb6a..e3c6b79a91b 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1029,6 +1029,11 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + if ((rdev->family == CHIP_JUNIPER) || + (rdev->family == CHIP_CYPRESS) || + (rdev->family == CHIP_HEMLOCK) || + (rdev->family == CHIP_BARTS)) + WREG32(MC_VM_MD_L1_TLB3_CNTL, tmp); } WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index b4eefc355f1..a5b88aad834 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -232,6 +232,7 @@ #define MC_VM_MD_L1_TLB0_CNTL 0x2654 #define MC_VM_MD_L1_TLB1_CNTL 0x2658 #define MC_VM_MD_L1_TLB2_CNTL 0x265C +#define MC_VM_MD_L1_TLB3_CNTL 0x2698 #define FUS_MC_VM_MD_L1_TLB0_CNTL 0x265C #define FUS_MC_VM_MD_L1_TLB1_CNTL 0x2660 diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index bf50e4bfcb1..80a292bc457 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -151,6 +151,8 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + if (rdev->family == CHIP_RV740) + WREG32(MC_VM_MD_L1_TLB3_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 79fa588e9ed..75380927e9c 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -174,6 +174,7 @@ #define MC_VM_MD_L1_TLB0_CNTL 0x2654 #define MC_VM_MD_L1_TLB1_CNTL 0x2658 #define MC_VM_MD_L1_TLB2_CNTL 0x265C +#define MC_VM_MD_L1_TLB3_CNTL 0x2698 #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 #define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 From 888e4b9df23905c6e29e6f26727349c3a81da844 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 31 May 2012 19:00:24 -0400 Subject: [PATCH 0138/2357] drm/radeon: fix HD6790, HD6570 backend programming commit 95c4b23ec4e2fa5604df229ddf134e31d7b3b378 upstream. Without this bit sets we get broken rendering and lockups. fglrx sets this bit. Bugs that should be fixed by this patch : https://bugs.freedesktop.org/show_bug.cgi?id=49792 https://bugzilla.kernel.org/show_bug.cgi?id=43207 https://bugs.freedesktop.org/show_bug.cgi?id=39282 Signed-off-by: Jerome Glisse Acked-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e3c6b79a91b..51e8d086767 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2178,9 +2178,9 @@ static void evergreen_gpu_init(struct radeon_device *rdev) WREG32(CC_SYS_RB_BACKEND_DISABLE, rb); WREG32(GC_USER_RB_BACKEND_DISABLE, rb); WREG32(CC_GC_SHADER_PIPE_CONFIG, sp); - } + } - grbm_gfx_index |= SE_BROADCAST_WRITES; + grbm_gfx_index = INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES; WREG32(GRBM_GFX_INDEX, grbm_gfx_index); WREG32(RLC_GFX_INDEX, grbm_gfx_index); From 71a47b9b18398fb55ab48865c0886a5b0ded6253 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Jun 2012 15:39:11 +0200 Subject: [PATCH 0139/2357] drm/ttm: Fix spinlock imbalance commit a8ff3ee211fccf708e1911bbc096625453ebf759 upstream. This imbalance may cause hangs when TTM is trying to swap out a buffer that is already on the delayed delete list. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/ttm/ttm_bo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 1f5c67c579c..18434186ed1 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1821,6 +1821,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) spin_unlock(&glob->lru_lock); (void) ttm_bo_cleanup_refs(bo, false, false, false); kref_put(&bo->list_kref, ttm_bo_release_list); + spin_lock(&glob->lru_lock); continue; } From 7e9f6a5a90c6c261247fbd9dbd38bf6f78779af6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Jun 2012 15:48:04 +0200 Subject: [PATCH 0140/2357] drm/vmwgfx: Fix nasty write past alloced memory area commit 0824db38e515644f8d1bfd64adbd7cb2c6ea7c62 upstream. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index 51c9ba5cd2f..21ee7822656 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c @@ -66,7 +66,7 @@ static int vmw_gmr2_bind(struct vmw_private *dev_priv, cmd += sizeof(remap_cmd) / sizeof(uint32); for (i = 0; i < num_pages; ++i) { - if (VMW_PPN_SIZE > 4) + if (VMW_PPN_SIZE <= 4) *cmd = page_to_pfn(*pages++); else *((uint64_t *)cmd) = page_to_pfn(*pages++); From 630ec1481b8aa0f6f66d521f04feacd74bfc19f5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 28 May 2012 22:31:41 +0000 Subject: [PATCH 0141/2357] asix: allow full size 8021Q frames to be received [ Upstream commit 9dae31009b1a00d926c6fe032d5a88099620adc3 ] asix driver drops 8021Q full size frames because it doesn't take into account VLAN header size. Tested on AX88772 adapter. Signed-off-by: Eric Dumazet CC: Greg Kroah-Hartman CC: Allan Chou CC: Trond Wuellner CC: Grant Grundler CC: Paul Stewart Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/asix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 42b5151aa78..609fcc33159 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -35,6 +35,7 @@ #include #include #include +#include #define DRIVER_VERSION "22-Dec-2011" #define DRIVER_NAME "asix" @@ -321,7 +322,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 0; } - if ((size > dev->net->mtu + ETH_HLEN) || + if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || (size + offset > skb->len)) { netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", size); From 86a2569c810dff80fc7ba16dd77bc2697c28317a Mon Sep 17 00:00:00 2001 From: Yanmin Zhang Date: Wed, 23 May 2012 15:39:45 +0000 Subject: [PATCH 0142/2357] ipv4: fix the rcu race between free_fib_info and ip_route_output_slow [ Upstream commit e49cc0da7283088c5e03d475ffe2fdcb24a6d5b1 ] We hit a kernel OOPS. <3>[23898.789643] BUG: sleeping function called from invalid context at /data/buildbot/workdir/ics/hardware/intel/linux-2.6/arch/x86/mm/fault.c:1103 <3>[23898.862215] in_atomic(): 0, irqs_disabled(): 0, pid: 10526, name: Thread-6683 <4>[23898.967805] HSU serial 0000:00:05.1: 0000:00:05.2:HSU serial prevented me to suspend... <4>[23899.258526] Pid: 10526, comm: Thread-6683 Tainted: G W 3.0.8-137685-ge7742f9 #1 <4>[23899.357404] HSU serial 0000:00:05.1: 0000:00:05.2:HSU serial prevented me to suspend... <4>[23899.904225] Call Trace: <4>[23899.989209] [] ? pgtable_bad+0x130/0x130 <4>[23900.000416] [] __might_sleep+0x10a/0x110 <4>[23900.007357] [] do_page_fault+0xd1/0x3c0 <4>[23900.013764] [] ? restore_all+0xf/0xf <4>[23900.024024] [] ? napi_complete+0x8b/0x690 <4>[23900.029297] [] ? pgtable_bad+0x130/0x130 <4>[23900.123739] [] ? pgtable_bad+0x130/0x130 <4>[23900.128955] [] error_code+0x5f/0x64 <4>[23900.133466] [] ? pgtable_bad+0x130/0x130 <4>[23900.138450] [] ? __ip_route_output_key+0x698/0x7c0 <4>[23900.144312] [] ? __ip_route_output_key+0x38d/0x7c0 <4>[23900.150730] [] ip_route_output_flow+0x1f/0x60 <4>[23900.156261] [] ip4_datagram_connect+0x188/0x2b0 <4>[23900.161960] [] ? _raw_spin_unlock_bh+0x1f/0x30 <4>[23900.167834] [] inet_dgram_connect+0x36/0x80 <4>[23900.173224] [] ? _copy_from_user+0x48/0x140 <4>[23900.178817] [] sys_connect+0x9a/0xd0 <4>[23900.183538] [] ? alloc_file+0xdc/0x240 <4>[23900.189111] [] ? sub_preempt_count+0x3d/0x50 Function free_fib_info resets nexthop_nh->nh_dev to NULL before releasing fi. Other cpu might be accessing fi. Fixing it by delaying the releasing. With the patch, we ran MTBF testing on Android mobile for 12 hours and didn't trigger the issue. Thank Eric for very detailed review/checking the issue. Signed-off-by: Yanmin Zhang Signed-off-by: Kun Jiang Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_semantics.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 5063fa38ac7..8861f91a07c 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -145,6 +145,12 @@ static void free_fib_info_rcu(struct rcu_head *head) { struct fib_info *fi = container_of(head, struct fib_info, rcu); + change_nexthops(fi) { + if (nexthop_nh->nh_dev) + dev_put(nexthop_nh->nh_dev); + } endfor_nexthops(fi); + + release_net(fi->fib_net); if (fi->fib_metrics != (u32 *) dst_default_metrics) kfree(fi->fib_metrics); kfree(fi); @@ -156,13 +162,7 @@ void free_fib_info(struct fib_info *fi) pr_warn("Freeing alive fib_info %p\n", fi); return; } - change_nexthops(fi) { - if (nexthop_nh->nh_dev) - dev_put(nexthop_nh->nh_dev); - nexthop_nh->nh_dev = NULL; - } endfor_nexthops(fi); fib_info_cnt--; - release_net(fi->fib_net); call_rcu(&fi->rcu, free_fib_info_rcu); } From be078c8003469b75aa9119254c163b2961321744 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Sat, 26 May 2012 01:30:53 +0000 Subject: [PATCH 0143/2357] ipv6: fix incorrect ipsec fragment [ Upstream commit 0c1833797a5a6ec23ea9261d979aa18078720b74 ] Since commit ad0081e43a "ipv6: Fragment locally generated tunnel-mode IPSec6 packets as needed" the fragment of packets is incorrect. because tunnel mode needs IPsec headers and trailer for all fragments, while on transport mode it is sufficient to add the headers to the first fragment and the trailer to the last. so modify mtu and maxfraglen base on ipsec mode and if fragment is first or last. with my test,it work well(every fragment's size is the mtu) and does not trigger slow fragment path. Changes from v1: though optimization, mtu_prev and maxfraglen_prev can be delete. replace xfrm mode codes with dst_entry's new frag DST_XFRM_TUNNEL. add fuction ip6_append_data_mtu to make codes clearer. Signed-off-by: Gao feng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/dst.h | 1 + net/ipv6/ip6_output.c | 68 +++++++++++++++++++++++++++++++----------- net/xfrm/xfrm_policy.c | 3 ++ 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index bed833d9796..8197eadca81 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -60,6 +60,7 @@ struct dst_entry { #define DST_NOCOUNT 0x0020 #define DST_NOPEER 0x0040 #define DST_FAKE_RTABLE 0x0080 +#define DST_XFRM_TUNNEL 0x0100 short error; short obsolete; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index b7ca46161cb..13e5399b1cd 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1181,6 +1181,29 @@ static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src, return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL; } +static void ip6_append_data_mtu(int *mtu, + int *maxfraglen, + unsigned int fragheaderlen, + struct sk_buff *skb, + struct rt6_info *rt) +{ + if (!(rt->dst.flags & DST_XFRM_TUNNEL)) { + if (skb == NULL) { + /* first fragment, reserve header_len */ + *mtu = *mtu - rt->dst.header_len; + + } else { + /* + * this fragment is not first, the headers + * space is regarded as data space. + */ + *mtu = dst_mtu(rt->dst.path); + } + *maxfraglen = ((*mtu - fragheaderlen) & ~7) + + fragheaderlen - sizeof(struct frag_hdr); + } +} + int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, @@ -1190,7 +1213,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct inet_cork *cork; - struct sk_buff *skb; + struct sk_buff *skb, *skb_prev = NULL; unsigned int maxfraglen, fragheaderlen; int exthdrlen; int dst_exthdrlen; @@ -1248,8 +1271,12 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, inet->cork.fl.u.ip6 = *fl6; np->cork.hop_limit = hlimit; np->cork.tclass = tclass; - mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? - rt->dst.dev->mtu : dst_mtu(&rt->dst); + if (rt->dst.flags & DST_XFRM_TUNNEL) + mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? + rt->dst.dev->mtu : dst_mtu(&rt->dst); + else + mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? + rt->dst.dev->mtu : dst_mtu(rt->dst.path); if (np->frag_size < mtu) { if (np->frag_size) mtu = np->frag_size; @@ -1345,25 +1372,27 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, unsigned int fraglen; unsigned int fraggap; unsigned int alloclen; - struct sk_buff *skb_prev; alloc_new_skb: - skb_prev = skb; - /* There's no room in the current skb */ - if (skb_prev) - fraggap = skb_prev->len - maxfraglen; + if (skb) + fraggap = skb->len - maxfraglen; else fraggap = 0; + /* update mtu and maxfraglen if necessary */ + if (skb == NULL || skb_prev == NULL) + ip6_append_data_mtu(&mtu, &maxfraglen, + fragheaderlen, skb, rt); + + skb_prev = skb; /* * If remaining data exceeds the mtu, * we know we need more fragment(s). */ datalen = length + fraggap; - if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) - datalen = maxfraglen - fragheaderlen; - fraglen = datalen + fragheaderlen; + if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) + datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len; if ((flags & MSG_MORE) && !(rt->dst.dev->features&NETIF_F_SG)) alloclen = mtu; @@ -1372,13 +1401,16 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, alloclen += dst_exthdrlen; - /* - * The last fragment gets additional space at tail. - * Note: we overallocate on fragments with MSG_MODE - * because we have no idea if we're the last one. - */ - if (datalen == length + fraggap) - alloclen += rt->dst.trailer_len; + if (datalen != length + fraggap) { + /* + * this is not the last fragment, the trailer + * space is regarded as data space. + */ + datalen += rt->dst.trailer_len; + } + + alloclen += rt->dst.trailer_len; + fraglen = datalen + fragheaderlen; /* * We just reserve space for fragment header. diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 7661576b6f4..a15d2a03172 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1919,6 +1919,9 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, } ok: xfrm_pols_put(pols, drop_pols); + if (dst && dst->xfrm && + dst->xfrm->props.mode == XFRM_MODE_TUNNEL) + dst->flags |= DST_XFRM_TUNNEL; return dst; nopol: From ea1ae37f4a2c41ea684f2e725332147eb6496026 Mon Sep 17 00:00:00 2001 From: James Chapman Date: Tue, 29 May 2012 23:13:23 +0000 Subject: [PATCH 0144/2357] l2tp: fix oops in L2TP IP sockets for connect() AF_UNSPEC case [ Upstream commit c51ce49735c183ef2592db70f918ee698716276b ] An application may call connect() to disconnect a socket using an address with family AF_UNSPEC. The L2TP IP sockets were not handling this case when the socket is not bound and an attempt to connect() using AF_UNSPEC in such cases would result in an oops. This patch addresses the problem by protecting the sk_prot->disconnect() call against trying to unhash the socket before it is bound. The patch also adds more checks that the sockaddr supplied to bind() and connect() calls is valid. RIP: 0010:[] [] inet_unhash+0x50/0xd0 RSP: 0018:ffff88001989be28 EFLAGS: 00010293 Stack: ffff8800407a8000 0000000000000000 ffff88001989be78 ffffffff82e3a249 ffffffff82e3a050 ffff88001989bec8 ffff88001989be88 ffff8800407a8000 0000000000000010 ffff88001989bec8 ffff88001989bea8 ffffffff82e42639 Call Trace: [] udp_disconnect+0x1f9/0x290 [] inet_dgram_connect+0x29/0x80 [] sys_connect+0x9c/0x100 Reported-by: Sasha Levin Signed-off-by: James Chapman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_ip.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 6274f0be82b..cc8ad7bf51d 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -251,9 +251,16 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct inet_sock *inet = inet_sk(sk); struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr; - int ret = -EINVAL; + int ret; int chk_addr_ret; + if (!sock_flag(sk, SOCK_ZAPPED)) + return -EINVAL; + if (addr_len < sizeof(struct sockaddr_l2tpip)) + return -EINVAL; + if (addr->l2tp_family != AF_INET) + return -EINVAL; + ret = -EADDRINUSE; read_lock_bh(&l2tp_ip_lock); if (__l2tp_ip_bind_lookup(&init_net, addr->l2tp_addr.s_addr, sk->sk_bound_dev_if, addr->l2tp_conn_id)) @@ -284,6 +291,8 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) sk_del_node_init(sk); write_unlock_bh(&l2tp_ip_lock); ret = 0; + sock_reset_flag(sk, SOCK_ZAPPED); + out: release_sock(sk); @@ -304,13 +313,14 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len __be32 saddr; int oif, rc; - rc = -EINVAL; + if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */ + return -EINVAL; + if (addr_len < sizeof(*lsa)) - goto out; + return -EINVAL; - rc = -EAFNOSUPPORT; if (lsa->l2tp_family != AF_INET) - goto out; + return -EAFNOSUPPORT; lock_sock(sk); @@ -364,6 +374,14 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len return rc; } +static int l2tp_ip_disconnect(struct sock *sk, int flags) +{ + if (sock_flag(sk, SOCK_ZAPPED)) + return 0; + + return udp_disconnect(sk, flags); +} + static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { @@ -599,7 +617,7 @@ static struct proto l2tp_ip_prot = { .close = l2tp_ip_close, .bind = l2tp_ip_bind, .connect = l2tp_ip_connect, - .disconnect = udp_disconnect, + .disconnect = l2tp_ip_disconnect, .ioctl = udp_ioctl, .destroy = l2tp_ip_destroy_sock, .setsockopt = ip_setsockopt, From 010589e2bce841733dc989fd56c5c3aba41a759c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 29 May 2012 03:35:08 +0000 Subject: [PATCH 0145/2357] skb: avoid unnecessary reallocations in __skb_cow [ Upstream commit 617c8c11236716dcbda877e764b7bf37c6fd8063 ] At the beginning of __skb_cow, headroom gets set to a minimum of NET_SKB_PAD. This causes unnecessary reallocations if the buffer was not cloned and the headroom is just below NET_SKB_PAD, but still more than the amount requested by the caller. This was showing up frequently in my tests on VLAN tx, where vlan_insert_tag calls skb_cow_head(skb, VLAN_HLEN). Locally generated packets should have enough headroom, and for forward paths, we already have NET_SKB_PAD bytes of headroom, so we don't need to add any extra space here. Signed-off-by: Felix Fietkau Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/skbuff.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 111f26b6e28..c1689071fa2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1881,8 +1881,6 @@ static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom, { int delta = 0; - if (headroom < NET_SKB_PAD) - headroom = NET_SKB_PAD; if (headroom > skb_headroom(skb)) delta = headroom - skb_headroom(skb); From 978041f2a946a4616f7cdb60f6d453ffa83298c1 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Thu, 24 May 2012 11:32:38 +0000 Subject: [PATCH 0146/2357] xfrm: take net hdr len into account for esp payload size calculation [ Upstream commit 91657eafb64b4cb53ec3a2fbc4afc3497f735788 ] Corrects the function that determines the esp payload size. The calculations done in esp{4,6}_get_mtu() lead to overlength frames in transport mode for certain mtu values and suboptimal frames for others. According to what is done, mainly in esp{,6}_output() and tcp_mtu_to_mss(), net_header_len must be taken into account before doing the alignment calculation. Signed-off-by: Benjamin Poirier Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/esp4.c | 24 +++++++++--------------- net/ipv6/esp6.c | 18 +++++++----------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 89a47b35905..cb982a61536 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -459,28 +459,22 @@ static u32 esp4_get_mtu(struct xfrm_state *x, int mtu) struct esp_data *esp = x->data; u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4); u32 align = max_t(u32, blksize, esp->padlen); - u32 rem; - - mtu -= x->props.header_len + crypto_aead_authsize(esp->aead); - rem = mtu & (align - 1); - mtu &= ~(align - 1); + unsigned int net_adj; switch (x->props.mode) { - case XFRM_MODE_TUNNEL: - break; - default: case XFRM_MODE_TRANSPORT: - /* The worst case */ - mtu -= blksize - 4; - mtu += min_t(u32, blksize - 4, rem); - break; case XFRM_MODE_BEET: - /* The worst case. */ - mtu += min_t(u32, IPV4_BEET_PHMAXLEN, rem); + net_adj = sizeof(struct iphdr); break; + case XFRM_MODE_TUNNEL: + net_adj = 0; + break; + default: + BUG(); } - return mtu - 2; + return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) - + net_adj) & ~(align - 1)) + (net_adj - 2); } static void esp4_err(struct sk_buff *skb, u32 info) diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 1ac7938dd9e..65dd5433f08 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -411,19 +411,15 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu) struct esp_data *esp = x->data; u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4); u32 align = max_t(u32, blksize, esp->padlen); - u32 rem; + unsigned int net_adj; - mtu -= x->props.header_len + crypto_aead_authsize(esp->aead); - rem = mtu & (align - 1); - mtu &= ~(align - 1); - - if (x->props.mode != XFRM_MODE_TUNNEL) { - u32 padsize = ((blksize - 1) & 7) + 1; - mtu -= blksize - padsize; - mtu += min_t(u32, blksize - padsize, rem); - } + if (x->props.mode != XFRM_MODE_TUNNEL) + net_adj = sizeof(struct ipv6hdr); + else + net_adj = 0; - return mtu - 2; + return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) - + net_adj) & ~(align - 1)) + (net_adj - 2); } static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, From 2c693b1d2fd1789a8b52f3644d41547b1ba9a26e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 28 May 2012 14:16:57 -0400 Subject: [PATCH 0147/2357] ext4: fix potential NULL dereference in ext4_free_inodes_counts() commit bb3d132a24cd8bf5e7773b2d9f9baa58b07a7dae upstream. The ext4_get_group_desc() function returns NULL on error, and ext4_free_inodes_count() function dereferences it without checking. There is a check on the next line, but it's too late. Reviewed-by: Jan Kara Signed-off-by: Dan Carpenter Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ialloc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 409c2ee7750..8900f8b2ad4 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -488,10 +488,12 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent, for (i = 0; i < ngroups; i++) { grp = (parent_group + i) % ngroups; desc = ext4_get_group_desc(sb, grp, NULL); - grp_free = ext4_free_inodes_count(sb, desc); - if (desc && grp_free && grp_free >= avefreei) { - *group = grp; - return 0; + if (desc) { + grp_free = ext4_free_inodes_count(sb, desc); + if (grp_free && grp_free >= avefreei) { + *group = grp; + return 0; + } } } From 3c7f096206323ae4c9ad3db62fece0b19df21532 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 28 May 2012 14:17:25 -0400 Subject: [PATCH 0148/2357] ext4: force ro mount if ext4_setup_super() fails commit 7e84b6216467b84cd332c8e567bf5aa113fd2f38 upstream. If ext4_setup_super() fails i.e. due to a too-high revision, the error is logged in dmesg but the fs is not mounted RO as indicated. Tested by: # mkfs.ext4 -r 4 /dev/sdb6 # mount /dev/sdb6 /mnt/test # dmesg | grep "too high" [164919.759248] EXT4-fs (sdb6): revision level too high, forcing read-only mode # grep sdb6 /proc/mounts /dev/sdb6 /mnt/test2 ext4 rw,seclabel,relatime,data=ordered 0 0 Reviewed-by: Andreas Dilger Signed-off-by: Eric Sandeen Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e1fb1d5de58..be67c0b91a3 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3592,7 +3592,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount4; } - ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY); + if (ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY)) + sb->s_flags |= MS_RDONLY; /* determine the minimum size of new large inodes, if present */ if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { From a9ea4481033197d29c606a935b24336a96cb3082 Mon Sep 17 00:00:00 2001 From: Haogang Chen Date: Mon, 28 May 2012 14:21:55 -0400 Subject: [PATCH 0149/2357] ext4: fix potential integer overflow in alloc_flex_gd() commit 967ac8af4475ce45474800709b12137aa7634c77 upstream. In alloc_flex_gd(), when flexbg_size is large, kmalloc size would overflow and flex_gd->groups would point to a buffer smaller than expected, causing OOB accesses when it is used. Note that in ext4_resize_fs(), flexbg_size is calculated using sbi->s_log_groups_per_flex, which is read from the disk and only bounded to [1, 31]. The patch returns NULL for too large flexbg_size. Reviewed-by: Eric Sandeen Signed-off-by: Haogang Chen Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/resize.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 59fa0be2725..53589ff8824 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -161,6 +161,8 @@ static struct ext4_new_flex_group_data *alloc_flex_gd(unsigned long flexbg_size) if (flex_gd == NULL) goto out3; + if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_flex_group_data)) + goto out2; flex_gd->count = flexbg_size; flex_gd->groups = kmalloc(sizeof(struct ext4_new_group_data) * From c40a4bd1e80db2b3af7b064b6eece0e689be60a9 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Mon, 28 May 2012 17:02:25 -0400 Subject: [PATCH 0150/2357] ext4: disallow hard-linked directory in ext4_lookup commit 7e936b737211e6b54e34b71a827e56b872e958d8 upstream. A hard-linked directory to its parent can cause the VFS to deadlock, and is a sign of a corrupted file system. So detect this case in ext4_lookup(), before the rmdir() lockup scenario can take place. Signed-off-by: Andreas Dilger Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/namei.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 349d7b3671c..0a94cbbe882 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1037,6 +1037,12 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru EXT4_ERROR_INODE(dir, "bad inode number: %u", ino); return ERR_PTR(-EIO); } + if (unlikely(ino == dir->i_ino)) { + EXT4_ERROR_INODE(dir, "'%.*s' linked to parent dir", + dentry->d_name.len, + dentry->d_name.name); + return ERR_PTR(-EIO); + } inode = ext4_iget(dir->i_sb, ino); if (inode == ERR_PTR(-ESTALE)) { EXT4_ERROR_INODE(dir, From d7286a55eb1088df8f8d8c1bde34e0342c63804c Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 30 May 2012 23:00:16 -0400 Subject: [PATCH 0151/2357] ext4: add missing save_error_info() to ext4_error() commit f3fc0210c0fc91900766c995f089c39170e68305 upstream. The ext4_error() function is missing a call to save_error_info(). Since this is the function which marks the file system as containing an error, this oversight (which was introduced in 2.6.36) is quite significant, and should be backported to older stable kernels with high urgency. Reported-by: Ken Sumrall Signed-off-by: "Theodore Ts'o" Cc: ksumrall@google.com Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index be67c0b91a3..a68703a5610 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -497,6 +497,7 @@ void __ext4_error(struct super_block *sb, const char *function, printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n", sb->s_id, function, line, current->comm, &vaf); va_end(args); + save_error_info(sb, function, line); ext4_handle_error(sb); } From 5720f8de251bbf23fc9f4191d6ed5734110b7d67 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 31 May 2012 23:46:01 -0400 Subject: [PATCH 0152/2357] ext4: don't trash state flags in EXT4_IOC_SETFLAGS commit 79906964a187c405db72a3abc60eb9b50d804fbc upstream. In commit 353eb83c we removed i_state_flags with 64-bit longs, But when handling the EXT4_IOC_SETFLAGS ioctl, we replace i_flags directly, which trashes the state flags which are stored in the high 32-bits of i_flags on 64-bit platforms. So use the the ext4_{set,clear}_inode_flags() functions which use atomic bit manipulation functions instead. Reported-by: Tao Ma Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ioctl.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 6eee25591b8..e7eade8b6d6 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -38,7 +38,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) handle_t *handle = NULL; int err, migrate = 0; struct ext4_iloc iloc; - unsigned int oldflags; + unsigned int oldflags, mask, i; unsigned int jflag; if (!inode_owner_or_capable(inode)) @@ -115,8 +115,14 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (err) goto flags_err; - flags = flags & EXT4_FL_USER_MODIFIABLE; - flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE; + for (i = 0, mask = 1; i < 32; i++, mask <<= 1) { + if (!(mask & EXT4_FL_USER_MODIFIABLE)) + continue; + if (mask & flags) + ext4_set_inode_flag(inode, i); + else + ext4_clear_inode_flag(inode, i); + } ei->i_flags = flags; ext4_set_inode_flags(inode); From d2e926777a97fc29ebfa409584ed4e790f2e68bf Mon Sep 17 00:00:00 2001 From: Salman Qazi Date: Thu, 31 May 2012 23:51:27 -0400 Subject: [PATCH 0153/2357] ext4: add ext4_mb_unload_buddy in the error path commit 02b7831019ea4e7994968c84b5826fa8b248ffc8 upstream. ext4_free_blocks fails to pair an ext4_mb_load_buddy with a matching ext4_mb_unload_buddy when it fails a memory allocation. Signed-off-by: Salman Qazi Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/mballoc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 99ab428bcfa..5c315abc87b 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -4636,6 +4636,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, */ new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); if (!new_entry) { + ext4_mb_unload_buddy(&e4b); err = -ENOMEM; goto error_return; } From f940c5366eaaea9630ba643a036c2df321f66db3 Mon Sep 17 00:00:00 2001 From: Salman Qazi Date: Thu, 31 May 2012 23:52:14 -0400 Subject: [PATCH 0154/2357] ext4: remove mb_groups before tearing down the buddy_cache commit 95599968d19db175829fb580baa6b68939b320fb upstream. We can't have references held on pages in the s_buddy_cache while we are trying to truncate its pages and put the inode. All the pages must be gone before we reach clear_inode. This can only be gauranteed if we can prevent new users from grabbing references to s_buddy_cache's pages. The original bug can be reproduced and the bug fix can be verified by: while true; do mount -t ext4 /dev/ram0 /export/hda3/ram0; \ umount /export/hda3/ram0; done & while true; do cat /proc/fs/ext4/ram0/mb_groups; done Signed-off-by: Salman Qazi Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/mballoc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 5c315abc87b..6b0a57eafb5 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2517,6 +2517,9 @@ int ext4_mb_release(struct super_block *sb) struct ext4_sb_info *sbi = EXT4_SB(sb); struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits); + if (sbi->s_proc) + remove_proc_entry("mb_groups", sbi->s_proc); + if (sbi->s_group_info) { for (i = 0; i < ngroups; i++) { grinfo = ext4_get_group_info(sb, i); @@ -2564,8 +2567,6 @@ int ext4_mb_release(struct super_block *sb) } free_percpu(sbi->s_locality_groups); - if (sbi->s_proc) - remove_proc_entry("mb_groups", sbi->s_proc); return 0; } From b642cb6a143da812f188307c2661c0357776a9d0 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 5 Jun 2012 21:36:33 +0400 Subject: [PATCH 0155/2357] radix-tree: fix contiguous iterator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit fffaee365fded09f9ebf2db19066065fa54323c3 upstream. This patch fixes bug in macro radix_tree_for_each_contig(). If radix_tree_next_slot() sees NULL in next slot it returns NULL, but following radix_tree_next_chunk() switches iterating into next chunk. As result iterating becomes non-contiguous and breaks vfs "splice" and all its users. Signed-off-by: Konstantin Khlebnikov Reported-and-bisected-by: Hans de Bruin Reported-and-bisected-by: Ondrej Zary Reported-bisected-and-tested-by: Toralf Förster Link: https://lkml.org/lkml/2012/6/5/64 Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/radix-tree.h | 5 ++++- lib/radix-tree.c | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index 0d04cd69ab9..ffc444c38b0 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -368,8 +368,11 @@ radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags) iter->index++; if (likely(*slot)) return slot; - if (flags & RADIX_TREE_ITER_CONTIG) + if (flags & RADIX_TREE_ITER_CONTIG) { + /* forbid switching to the next chunk */ + iter->next_index = 0; break; + } } } return NULL; diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 86516f5588e..3ac50dc5563 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -673,6 +673,9 @@ void **radix_tree_next_chunk(struct radix_tree_root *root, * during iterating; it can be zero only at the beginning. * And we cannot overflow iter->next_index in a single step, * because RADIX_TREE_MAP_SHIFT < BITS_PER_LONG. + * + * This condition also used by radix_tree_next_slot() to stop + * contiguous iterating, and forbid swithing to the next chunk. */ index = iter->next_index; if (!index && iter->index) From 346327670c51ea6741eee95874fbcca4ff69c383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 4 Jun 2012 18:36:58 +0200 Subject: [PATCH 0156/2357] drm/radeon/audio: don't hardcode CRTC id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0aecb5a4ba1ea4167f31d1790eec027f1e658f2d upstream. This is based on info released by AMD, should allow using audio in much more cases. Signed-off-by: Rafał Miłecki Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/r600_audio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index ba66f3093d4..24e39399367 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -239,6 +239,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); int base_rate = 48000; switch (radeon_encoder->encoder_id) { @@ -264,8 +265,8 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) WREG32(EVERGREEN_AUDIO_PLL1_DIV, clock * 10); WREG32(EVERGREEN_AUDIO_PLL1_UNK, 0x00000071); - /* Some magic trigger or src sel? */ - WREG32_P(0x5ac, 0x01, ~0x77); + /* Select DTO source */ + WREG32(0x5ac, radeon_crtc->crtc_id); } else { switch (dig->dig_encoder) { case 0: From ce58755a4fe65790a2e80559e0c585ba610b5f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 3 Jun 2012 16:09:43 +0200 Subject: [PATCH 0157/2357] drm/radeon: fix vm deadlocks on cayman MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit bb4091558228ff4a3e02328c931e683fc7f08722 upstream. Locking mutex in different orders just screams for deadlocks, and some testing showed that it is actually quite easy to trigger them. Signed-off-by: Christian König Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_gart.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index c58a036233f..62050f52194 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -478,12 +478,18 @@ int radeon_vm_bo_add(struct radeon_device *rdev, mutex_lock(&vm->mutex); if (last_pfn > vm->last_pfn) { - /* grow va space 32M by 32M */ - unsigned align = ((32 << 20) >> 12) - 1; + /* release mutex and lock in right order */ + mutex_unlock(&vm->mutex); radeon_mutex_lock(&rdev->cs_mutex); - radeon_vm_unbind_locked(rdev, vm); + mutex_lock(&vm->mutex); + /* and check again */ + if (last_pfn > vm->last_pfn) { + /* grow va space 32M by 32M */ + unsigned align = ((32 << 20) >> 12) - 1; + radeon_vm_unbind_locked(rdev, vm); + vm->last_pfn = (last_pfn + align) & ~align; + } radeon_mutex_unlock(&rdev->cs_mutex); - vm->last_pfn = (last_pfn + align) & ~align; } head = &vm->va; last_offset = 0; @@ -597,8 +603,8 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev, if (bo_va == NULL) return 0; - mutex_lock(&vm->mutex); radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&vm->mutex); radeon_vm_bo_update_pte(rdev, vm, bo, NULL); radeon_mutex_unlock(&rdev->cs_mutex); list_del(&bo_va->vm_list); @@ -643,9 +649,8 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) struct radeon_bo_va *bo_va, *tmp; int r; - mutex_lock(&vm->mutex); - radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&vm->mutex); radeon_vm_unbind_locked(rdev, vm); radeon_mutex_unlock(&rdev->cs_mutex); From d16ba207028eac4f38b908507d731ca894a91744 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 5 Jun 2012 09:50:28 -0400 Subject: [PATCH 0158/2357] drm/radeon/kms: add new Trinity PCI ids commit d430f7dbf7bd6aaaa40c0660b3204df8cf07b22b upstream. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/ni.c | 21 +++++++++++++++++---- include/drm/drm_pciids.h | 8 ++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 93eb6f94229..ad0a38007de 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -657,15 +657,28 @@ static void cayman_gpu_init(struct radeon_device *rdev) rdev->config.cayman.max_pipes_per_simd = 4; rdev->config.cayman.max_tile_pipes = 2; if ((rdev->pdev->device == 0x9900) || - (rdev->pdev->device == 0x9901)) { + (rdev->pdev->device == 0x9901) || + (rdev->pdev->device == 0x9905) || + (rdev->pdev->device == 0x9906) || + (rdev->pdev->device == 0x9907) || + (rdev->pdev->device == 0x9908) || + (rdev->pdev->device == 0x9909) || + (rdev->pdev->device == 0x9910) || + (rdev->pdev->device == 0x9917)) { rdev->config.cayman.max_simds_per_se = 6; rdev->config.cayman.max_backends_per_se = 2; } else if ((rdev->pdev->device == 0x9903) || - (rdev->pdev->device == 0x9904)) { + (rdev->pdev->device == 0x9904) || + (rdev->pdev->device == 0x990A) || + (rdev->pdev->device == 0x9913) || + (rdev->pdev->device == 0x9918)) { rdev->config.cayman.max_simds_per_se = 4; rdev->config.cayman.max_backends_per_se = 2; - } else if ((rdev->pdev->device == 0x9990) || - (rdev->pdev->device == 0x9991)) { + } else if ((rdev->pdev->device == 0x9919) || + (rdev->pdev->device == 0x9990) || + (rdev->pdev->device == 0x9991) || + (rdev->pdev->device == 0x9994) || + (rdev->pdev->device == 0x99A0)) { rdev->config.cayman.max_simds_per_se = 3; rdev->config.cayman.max_backends_per_se = 1; } else { diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 58d0bdab68d..961dae0d26e 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -561,11 +561,19 @@ {0x1002, 0x9909, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x990A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x990F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9910, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9913, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9917, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9990, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9991, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9993, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9994, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0, 0, 0} #define r128_PCI_IDS \ From 36fbcdf64a3c15a8a98adb5ea018ce1913215e25 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 5 Jun 2012 09:50:29 -0400 Subject: [PATCH 0159/2357] drm/radeon/kms: add new Palm, Sumo PCI ids commit 4a6991cc1fad514745b79181df3ace72d561e7aa upstream. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_pciids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 961dae0d26e..c5b0d8cd056 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -531,6 +531,7 @@ {0x1002, 0x9645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ {0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ + {0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ {0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ @@ -550,6 +551,7 @@ {0x1002, 0x9807, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x980A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ From b1840525b3af198ada9f60fc25c980e97e189933 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 5 Jun 2012 09:50:30 -0400 Subject: [PATCH 0160/2357] drm/radeon/kms: add new BTC PCI ids commit a2bef8ce826dd1e787fd8ad9b6e0566ba59dab43 upstream. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_pciids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index c5b0d8cd056..86c4cf91639 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -181,6 +181,7 @@ {0x1002, 0x6747, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6748, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x674A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ @@ -198,6 +199,7 @@ {0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6771, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ From fab83a044aa7d4b968f466f4eb3946388528497a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 5 Jun 2012 09:50:31 -0400 Subject: [PATCH 0161/2357] drm/radeon/kms: add new SI PCI ids commit 7aaa61b3476462b69f1ac7669fcca8d608ce3cb5 upstream. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_pciids.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 86c4cf91639..81368ab6c61 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -231,10 +231,11 @@ {0x1002, 0x6827, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ - {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ - {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ From 98e69566e80c4de231456dbf4e6735ddfeb599db Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 31 May 2012 17:38:11 +0200 Subject: [PATCH 0162/2357] iommu/amd: Cache pdev pointer to root-bridge commit c1bf94ec1e12d76838ad485158aecf208ebd8fb9 upstream. At some point pci_get_bus_and_slot started to enable interrupts. Since this function is used in the amd_iommu_resume path it will enable interrupts on resume which causes a warning. The fix will use a cached pointer to the root-bridge to re-enable the IOMMU in case the BIOS is broken. Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu_init.c | 13 +++++-------- drivers/iommu/amd_iommu_types.h | 3 +++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index c56790375e0..542024ba6db 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1029,6 +1029,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) if (!iommu->dev) return 1; + iommu->root_pdev = pci_get_bus_and_slot(iommu->dev->bus->number, + PCI_DEVFN(0, 0)); + iommu->cap_ptr = h->cap_ptr; iommu->pci_seg = h->pci_seg; iommu->mmio_phys = h->mmio_phys; @@ -1323,20 +1326,16 @@ static void iommu_apply_resume_quirks(struct amd_iommu *iommu) { int i, j; u32 ioc_feature_control; - struct pci_dev *pdev = NULL; + struct pci_dev *pdev = iommu->root_pdev; /* RD890 BIOSes may not have completely reconfigured the iommu */ - if (!is_rd890_iommu(iommu->dev)) + if (!is_rd890_iommu(iommu->dev) || !pdev) return; /* * First, we need to ensure that the iommu is enabled. This is * controlled by a register in the northbridge */ - pdev = pci_get_bus_and_slot(iommu->dev->bus->number, PCI_DEVFN(0, 0)); - - if (!pdev) - return; /* Select Northbridge indirect register 0x75 and enable writing */ pci_write_config_dword(pdev, 0x60, 0x75 | (1 << 7)); @@ -1346,8 +1345,6 @@ static void iommu_apply_resume_quirks(struct amd_iommu *iommu) if (!(ioc_feature_control & 0x1)) pci_write_config_dword(pdev, 0x64, ioc_feature_control | 1); - pci_dev_put(pdev); - /* Restore the iommu BAR */ pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4, iommu->stored_addr_lo); diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 2452f3b7173..24355559a2a 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -481,6 +481,9 @@ struct amd_iommu { /* Pointer to PCI device of this IOMMU */ struct pci_dev *dev; + /* Cache pdev to root device for resume quirks */ + struct pci_dev *root_pdev; + /* physical address of MMIO space */ u64 mmio_phys; /* virtual address of MMIO space */ From 3e743873ed23bed0ab24ed33a92d960887ccfafa Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 1 Jun 2012 15:20:23 +0200 Subject: [PATCH 0163/2357] iommu/amd: Fix deadlock in ppr-handling error path commit eee53537c476c947bf7faa1c916d2f5a0ae8ec93 upstream. In the error path of the ppr_notifer it can happen that the iommu->lock is taken recursivly. This patch fixes the problem by releasing the iommu->lock before any notifier is invoked. This also requires to move the erratum workaround for the ppr-log (interrupt may be faster than data in the log) one function up. Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu.c | 71 ++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index d90a421e9ca..a2e418cba0f 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -547,26 +547,12 @@ static void iommu_poll_events(struct amd_iommu *iommu) spin_unlock_irqrestore(&iommu->lock, flags); } -static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u32 head) +static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u64 *raw) { struct amd_iommu_fault fault; - volatile u64 *raw; - int i; INC_STATS_COUNTER(pri_requests); - raw = (u64 *)(iommu->ppr_log + head); - - /* - * Hardware bug: Interrupt may arrive before the entry is written to - * memory. If this happens we need to wait for the entry to arrive. - */ - for (i = 0; i < LOOP_TIMEOUT; ++i) { - if (PPR_REQ_TYPE(raw[0]) != 0) - break; - udelay(1); - } - if (PPR_REQ_TYPE(raw[0]) != PPR_REQ_FAULT) { pr_err_ratelimited("AMD-Vi: Unknown PPR request received\n"); return; @@ -578,12 +564,6 @@ static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u32 head) fault.tag = PPR_TAG(raw[0]); fault.flags = PPR_FLAGS(raw[0]); - /* - * To detect the hardware bug we need to clear the entry - * to back to zero. - */ - raw[0] = raw[1] = 0; - atomic_notifier_call_chain(&ppr_notifier, 0, &fault); } @@ -595,25 +575,62 @@ static void iommu_poll_ppr_log(struct amd_iommu *iommu) if (iommu->ppr_log == NULL) return; + /* enable ppr interrupts again */ + writel(MMIO_STATUS_PPR_INT_MASK, iommu->mmio_base + MMIO_STATUS_OFFSET); + spin_lock_irqsave(&iommu->lock, flags); head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET); while (head != tail) { + volatile u64 *raw; + u64 entry[2]; + int i; - /* Handle PPR entry */ - iommu_handle_ppr_entry(iommu, head); + raw = (u64 *)(iommu->ppr_log + head); + + /* + * Hardware bug: Interrupt may arrive before the entry is + * written to memory. If this happens we need to wait for the + * entry to arrive. + */ + for (i = 0; i < LOOP_TIMEOUT; ++i) { + if (PPR_REQ_TYPE(raw[0]) != 0) + break; + udelay(1); + } + + /* Avoid memcpy function-call overhead */ + entry[0] = raw[0]; + entry[1] = raw[1]; - /* Update and refresh ring-buffer state*/ + /* + * To detect the hardware bug we need to clear the entry + * back to zero. + */ + raw[0] = raw[1] = 0UL; + + /* Update head pointer of hardware ring-buffer */ head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE; writel(head, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); + + /* + * Release iommu->lock because ppr-handling might need to + * re-aquire it + */ + spin_unlock_irqrestore(&iommu->lock, flags); + + /* Handle PPR entry */ + iommu_handle_ppr_entry(iommu, entry); + + spin_lock_irqsave(&iommu->lock, flags); + + /* Refresh ring-buffer information */ + head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET); } - /* enable ppr interrupts again */ - writel(MMIO_STATUS_PPR_INT_MASK, iommu->mmio_base + MMIO_STATUS_OFFSET); - spin_unlock_irqrestore(&iommu->lock, flags); } From cd08f77d07306f1294a78f13de5f55348c21df5b Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Thu, 3 May 2012 14:48:26 +0100 Subject: [PATCH 0164/2357] ACPI battery: only refresh the sysfs files when pertinent information changes commit c5971456964290da7e98222892797b71ef793e62 upstream. We only need to regenerate the sysfs files when the capacity units change, avoid the update otherwise. The origin of this issue is dates way back to 2.6.38: da8aeb92d4853f37e281f11fddf61f9c7d84c3cd (ACPI / Battery: Update information on info notification and resume) Signed-off-by: Andy Whitcroft Tested-by: Ralf Jung Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/battery.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 86933ca8b47..7dd3f9fb9f3 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -643,11 +643,19 @@ static int acpi_battery_update(struct acpi_battery *battery) static void acpi_battery_refresh(struct acpi_battery *battery) { + int power_unit; + if (!battery->bat.dev) return; + power_unit = battery->power_unit; + acpi_battery_get_info(battery); - /* The battery may have changed its reporting units. */ + + if (power_unit == battery->power_unit) + return; + + /* The battery has changed its reporting units. */ sysfs_remove_battery(battery); sysfs_add_battery(battery); } From cf9ab4c62be7837c2f007cd51ab3604ca0620070 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 4 Jun 2012 11:00:45 -0700 Subject: [PATCH 0165/2357] vfs: Fix /proc//fdinfo/ file handling commit 0640113be25d283e0ff77a9f041e1242182387f0 upstream. Cyrill Gorcunov reports that I broke the fdinfo files with commit 30a08bf2d31d ("proc: move fd symlink i_mode calculations into tid_fd_revalidate()"), and he's quite right. The tid_fd_revalidate() function is not just used for the /fd symlinks, it's also used for the /fdinfo/ files, and the permission model for those are different. So do the dynamic symlink permission handling just for symlinks, making the fdinfo files once more appear as the proper regular files they are. Of course, Al Viro argued (probably correctly) that we shouldn't do the symlink permission games at all, and make the symlinks always just be the normal 'lrwxrwxrwx'. That would have avoided this issue too, but since somebody noticed that the permissions had changed (which was the reason for that original commit 30a08bf2d31d in the first place), people do apparently use this feature. [ Basically, you can use the symlink permission data as a cheap "fdinfo" replacement, since you see whether the file is open for reading and/or writing by just looking at st_mode of the symlink. So the feature does make sense, even if the pain it has caused means we probably shouldn't have done it to begin with. ] Reported-and-tested-by: Cyrill Gorcunov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/base.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 57b8159f26f..9fc77b412ac 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1803,7 +1803,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) rcu_read_lock(); file = fcheck_files(files, fd); if (file) { - unsigned i_mode, f_mode = file->f_mode; + unsigned f_mode = file->f_mode; rcu_read_unlock(); put_files_struct(files); @@ -1819,12 +1819,14 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) inode->i_gid = 0; } - i_mode = S_IFLNK; - if (f_mode & FMODE_READ) - i_mode |= S_IRUSR | S_IXUSR; - if (f_mode & FMODE_WRITE) - i_mode |= S_IWUSR | S_IXUSR; - inode->i_mode = i_mode; + if (S_ISLNK(inode->i_mode)) { + unsigned i_mode = S_IFLNK; + if (f_mode & FMODE_READ) + i_mode |= S_IRUSR | S_IXUSR; + if (f_mode & FMODE_WRITE) + i_mode |= S_IWUSR | S_IXUSR; + inode->i_mode = i_mode; + } security_task_to_inode(task, inode); put_task_struct(task); @@ -1859,6 +1861,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir, ei = PROC_I(inode); ei->fd = fd; + inode->i_mode = S_IFLNK; inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; ei->op.proc_get_link = proc_fd_link; From 584b886aee3aff5fe7eb21e30f779eb5cd1daa36 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 31 May 2012 15:39:11 +1000 Subject: [PATCH 0166/2357] md: raid1/raid10: fix problem with merge_bvec_fn commit aba336bd1d46d6b0404b06f6915ed76150739057 upstream. The new merge_bvec_fn which calls the corresponding function in subsidiary devices requires that mddev->merge_check_needed be set if any child has a merge_bvec_fn. However were were only setting that when a device was hot-added, not when a device was present from the start. This bug was introduced in 3.4 so patch is suitable for 3.4.y kernels. However that are conflicts in raid10.c so a separate patch will be needed for 3.4.y. Reported-by: Sebastian Riemer Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid1.c | 4 ++++ drivers/md/raid10.c | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 15dd59b84e9..d7e95772145 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2548,6 +2548,7 @@ static struct r1conf *setup_conf(struct mddev *mddev) err = -EINVAL; spin_lock_init(&conf->device_lock); rdev_for_each(rdev, mddev) { + struct request_queue *q; int disk_idx = rdev->raid_disk; if (disk_idx >= mddev->raid_disks || disk_idx < 0) @@ -2560,6 +2561,9 @@ static struct r1conf *setup_conf(struct mddev *mddev) if (disk->rdev) goto abort; disk->rdev = rdev; + q = bdev_get_queue(rdev->bdev); + if (q->merge_bvec_fn) + mddev->merge_check_needed = 1; disk->head_position = 0; } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 3f91c2e1dfe..d037adb295a 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3311,7 +3311,7 @@ static int run(struct mddev *mddev) (conf->raid_disks / conf->near_copies)); rdev_for_each(rdev, mddev) { - + struct request_queue *q; disk_idx = rdev->raid_disk; if (disk_idx >= conf->raid_disks || disk_idx < 0) @@ -3327,6 +3327,9 @@ static int run(struct mddev *mddev) goto out_free_conf; disk->rdev = rdev; } + q = bdev_get_queue(rdev->bdev); + if (q->merge_bvec_fn) + mddev->merge_check_needed = 1; disk_stack_limits(mddev->gendisk, rdev->bdev, rdev->data_offset << 9); From ee9c8a04666ba15762f736f9030e6e8df02ca1a5 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Fri, 18 May 2012 03:04:08 +0300 Subject: [PATCH 0167/2357] wl1251: fix oops on early interrupt commit f380f2c4a12e913356bd49f8790ec1063c4fe9f8 upstream. This driver disables interrupt just after requesting it and enables it later, after interface is up. However currently there is a time window between request_irq() and disable_irq() where if interrupt arrives, the driver oopses because it's not yet ready to process it. This can be reproduced by inserting the module, associating and removing the module multiple times. Eliminate this race by setting IRQF_NOAUTOEN flag before request_irq(). Signed-off-by: Grazvydas Ignotas Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/wl1251/sdio.c | 2 +- drivers/net/wireless/wl1251/spi.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index 1b851f650e0..e2750a12c6f 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c @@ -260,6 +260,7 @@ static int wl1251_sdio_probe(struct sdio_func *func, } if (wl->irq) { + irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); if (ret < 0) { wl1251_error("request_irq() failed: %d", ret); @@ -267,7 +268,6 @@ static int wl1251_sdio_probe(struct sdio_func *func, } irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - disable_irq(wl->irq); wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq; diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c index 6248c354fc5..87f6305bda2 100644 --- a/drivers/net/wireless/wl1251/spi.c +++ b/drivers/net/wireless/wl1251/spi.c @@ -281,6 +281,7 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) wl->use_eeprom = pdata->use_eeprom; + irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); if (ret < 0) { wl1251_error("request_irq() failed: %d", ret); @@ -289,8 +290,6 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - disable_irq(wl->irq); - ret = wl1251_init_ieee80211(wl); if (ret) goto out_irq; From b522dbf26fe08158348773c36dbf88e8147dcc66 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 22 May 2012 09:30:33 -0700 Subject: [PATCH 0168/2357] drm/i915: always use RPNSWREQ for turbo change requests commit 89ba829e38bd500f438bc08af4229204c8ed7f35 upstream. Media turbo requests can either use RPVSWREQ or RPNSWREQ to indicate what the interrupt handler should do. Since we only deal with the latter in our turbo code, make the media engine use that for turbo requests. Tested-by: Joe Bloggsian Signed-off-by: Jesse Barnes Reviewed-by: Eugeni Dodonov Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 79a7de1f31b..d4d162f6bab 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8368,7 +8368,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); I915_WRITE(GEN6_RP_CONTROL, GEN6_RP_MEDIA_TURBO | - GEN6_RP_MEDIA_HW_MODE | + GEN6_RP_MEDIA_HW_NORMAL_MODE | GEN6_RP_MEDIA_IS_GFX | GEN6_RP_ENABLE | GEN6_RP_UP_BUSY_AVG | From 546230dfa483f6d1f188d1a1a20122ecabf82816 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Apr 2012 22:43:42 +0100 Subject: [PATCH 0169/2357] drm/i915/dp: Flush any outstanding work to turn the VDD off commit 17038de5f16569a25343cf68668f3b657eafb00e upstream. As we may kick off a delayed workqueue task to switch of the VDD lines, we need to complete that task prior to turning off the panel (which itself depends upon VDD being off). v2: Don't cancel the outstanding work as this may trigger a deadlock Signed-off-by: Chris Wilson Cc: Keith Packard Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_dp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4b637919f74..3a866f0410b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1149,6 +1149,7 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n"); + ironlake_panel_vdd_off_sync(intel_dp); /* finish any pending work */ pp = ironlake_get_pp_control(dev_priv); pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); From 9b660f3019d6fe55be99d85bacf28fe74fb14c1c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 20 May 2012 17:14:50 +0200 Subject: [PATCH 0170/2357] drm/i915: enable vdd when switching off the eDP panel commit 6cb49835da0426f69a2931bc2a0a8156344b0e41 upstream. We have one bug report from a validation team that we get the eDP panel sequencing still somewhat wrong: We need to enable VDD while switching off the panel and backlight. Unfortunately that reporter seems to have fallen off the earth :( For another reporter this actually fixes a black panel issue because without this the backlight/panel gets confused and doesn't light up again. v2: I've forgotten to remove the vdd_off call in panel_off which is now bogus. This essentially reverts commit 17038de5f16569a25343cf68668f3b657eafb00e Author: Chris Wilson Date: Mon Apr 16 22:43:42 2012 +0100 drm/i915/dp: Flush any outstanding work to turn the VDD off v3: the current panel_off code forces off the vdd power, too. Which is bogus and resulted in some funny warnings later on when we've tried to do aux channel communications with just the vdd forced on. Fix this, too. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=46312 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=43163 Tested-by: Vincent Frentzel Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_dp.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3a866f0410b..1d19408192b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1148,11 +1148,10 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); - WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n"); - ironlake_panel_vdd_off_sync(intel_dp); /* finish any pending work */ + WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); pp = ironlake_get_pp_control(dev_priv); - pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); + pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); @@ -1260,18 +1259,16 @@ static void intel_dp_prepare(struct drm_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + /* Make sure the panel is off before trying to change the mode. But also + * ensure that we have vdd while we switch off the panel. */ + ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_backlight_off(intel_dp); ironlake_edp_panel_off(intel_dp); - /* Wake up the sink first */ - ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_link_down(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, false); - - /* Make sure the panel is off before trying to - * change the mode - */ } static void intel_dp_commit(struct drm_encoder *encoder) @@ -1303,10 +1300,11 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (mode != DRM_MODE_DPMS_ON) { + /* Switching the panel off requires vdd. */ + ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_backlight_off(intel_dp); ironlake_edp_panel_off(intel_dp); - ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, mode); intel_dp_link_down(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, false); From dadce2efa18e448bb42678efdc72a819bceaa9b7 Mon Sep 17 00:00:00 2001 From: maximilian attems Date: Wed, 16 May 2012 09:46:30 +0200 Subject: [PATCH 0171/2357] IA64: Add cmpxchg.h to exported userspace headers commit 98e4cff73a18af27f0d40d0b0d37f105dfc1994a upstream. Fixes klibc build on ia64 after 85f8f7759e418c814ee2ceacf73eddb9bed39492. Cc: Paul Gortmaker Signed-off-by: maximilian attems Signed-off-by: Tony Luck Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/ia64/include/asm/Kbuild | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild index 241d1c53ba6..d4eb9383f5f 100644 --- a/arch/ia64/include/asm/Kbuild +++ b/arch/ia64/include/asm/Kbuild @@ -1,6 +1,7 @@ include include/asm-generic/Kbuild.asm header-y += break.h +header-y += cmpxchg.h header-y += fpu.h header-y += gcc_intrin.h header-y += ia64regs.h From 6ab997e0b5440eee1bc76bb9d83aa86e3966adb2 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Thu, 7 Jun 2012 19:04:19 -0400 Subject: [PATCH 0172/2357] ext4: don't set i_flags in EXT4_IOC_SETFLAGS commit b22b1f178f6799278d3178d894f37facb2085765 upstream. Commit 7990696 uses the ext4_{set,clear}_inode_flags() functions to change the i_flags automatically but fails to remove the error setting of i_flags. So we still have the problem of trashing state flags. Fix this by removing the assignment. Signed-off-by: Tao Ma Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ioctl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index e7eade8b6d6..1365903a514 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -123,7 +123,6 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) else ext4_clear_inode_flag(inode, i); } - ei->i_flags = flags; ext4_set_inode_flags(inode); inode->i_ctime = ext4_current_time(inode); From 1f5547c7f183363eabe07e5d202a49f2e94e995a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 10 Jun 2012 00:36:33 +0900 Subject: [PATCH 0173/2357] Linux 3.4.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0bd155435a3..901a95571ea 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 1 +SUBLEVEL = 2 EXTRAVERSION = NAME = Saber-toothed Squirrel From 666b7a8a0355bb510cd9804f6d2973be89045fc4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 5 May 2012 00:39:21 +1000 Subject: [PATCH 0174/2357] drm/nouveau/disp: fix dithering not being enabled on some eDP macbooks commit a6a17859f1bdf607650ee055101f54c5f207762b upstream. Signed-off-by: Ben Skeggs Cc: Maarten Lankhorst Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_connector.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index fa860358add..7b11edb077d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -654,7 +654,13 @@ nouveau_connector_detect_depth(struct drm_connector *connector) if (nv_connector->edid && connector->display_info.bpc) return; - /* if not, we're out of options unless we're LVDS, default to 8bpc */ + /* EDID 1.4 is *supposed* to be supported on eDP, but, Apple... */ + if (nv_connector->type == DCB_CONNECTOR_eDP) { + connector->display_info.bpc = 6; + return; + } + + /* we're out of options unless we're LVDS, default to 8bpc */ if (nv_encoder->dcb->type != OUTPUT_LVDS) { connector->display_info.bpc = 8; return; From cd977c84fc641cecc3b2b62a8f626815a794ad58 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 28 May 2012 22:33:02 +0100 Subject: [PATCH 0175/2357] drm/i915: Reset last_retired_head when resetting ring commit c3b20037926e607b6cdaecbf9d3103e2ca63bc31 upstream. When we reset the ring control registers, including the HEAD and TAIL of the ring, we also need to reset associated state. In this instance, we were failing to reset the cached value of ring->last_retired_head and so upon the first request for more space following a resume would potentially (depending on a narrow race window) believe that the HEAD had advanced much further than reality. This is a regression from: commit a71d8d94525e8fd855c0466fb586ae1cb008f3a2 Author: Chris Wilson Date: Wed Feb 15 11:25:36 2012 +0000 drm/i915: Record the tail at each request and use it to estimate the head Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_ringbuffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 62892a826ed..e0ecef68c39 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -309,6 +309,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) ring->head = I915_READ_HEAD(ring); ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; ring->space = ring_space(ring); + ring->last_retired_head = -1; } return 0; From 6d6a10124daeccc44f5d291cad4bea64639a2c66 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Wed, 6 Jun 2012 11:59:06 -0300 Subject: [PATCH 0176/2357] char/agp: add another Ironlake host bridge commit 67384fe3fd450536342330f684ea1f7dcaef8130 upstream. This seems to come on Gigabyte H55M-S2V and was discovered through the https://bugs.freedesktop.org/show_bug.cgi?id=50381 debugging. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=50381 Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/char/agp/intel-agp.c | 1 + drivers/char/agp/intel-agp.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 962e75dc478..4293c484056 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -898,6 +898,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_B43_HB), ID(PCI_DEVICE_ID_INTEL_B43_1_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB), + ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D2_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB), diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 7ea18a5fe71..439d7e7553b 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -211,6 +211,7 @@ #define PCI_DEVICE_ID_INTEL_G41_HB 0x2E30 #define PCI_DEVICE_ID_INTEL_G41_IG 0x2E32 #define PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB 0x0040 +#define PCI_DEVICE_ID_INTEL_IRONLAKE_D2_HB 0x0069 #define PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG 0x0042 #define PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB 0x0044 #define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB 0x0062 From 5a32293d5c1045e99b70582783b453d08e71cfdb Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jun 2012 14:21:13 -0700 Subject: [PATCH 0177/2357] btree: fix tree corruption in btree_get_prev() commit cbf8ae32f66a9ceb8907ad9e16663c2a29e48990 upstream. The memory the parameter __key points to is used as an iterator in btree_get_prev(), so if we save off a bkey() pointer in retry_key and then assign that to __key, we'll end up corrupting the btree internals when we do eg longcpy(__key, bkey(geo, node, i), geo->keylen); to return the key value. What we should do instead is use longcpy() to copy the key value that retry_key points to __key. This can cause a btree to get corrupted by seemingly read-only operations such as btree_for_each_safe. [akpm@linux-foundation.org: avoid the double longcpy()] Signed-off-by: Roland Dreier Acked-by: Joern Engel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- lib/btree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/btree.c b/lib/btree.c index e5ec1e9c1aa..5cf9e74ec3f 100644 --- a/lib/btree.c +++ b/lib/btree.c @@ -319,8 +319,8 @@ void *btree_get_prev(struct btree_head *head, struct btree_geo *geo, if (head->height == 0) return NULL; -retry: longcpy(key, __key, geo->keylen); +retry: dec_key(geo, key); node = head->node; @@ -351,7 +351,7 @@ void *btree_get_prev(struct btree_head *head, struct btree_geo *geo, } miss: if (retry_key) { - __key = retry_key; + longcpy(key, retry_key, geo->keylen); retry_key = NULL; goto retry; } From e6a6c7d2e51c9af9ce9fab247b1bc2af3967cfbb Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 1 Jun 2012 18:13:43 +1000 Subject: [PATCH 0178/2357] powerpc/time: Sanity check of decrementer expiration is necessary commit 860aed25a1f0936d4852ab936252b47cd1e630f1 upstream. This reverts 68568add2c ("powerpc/time: Remove unnecessary sanity check of decrementer expiration"). We do need to check whether we have reached the expiration time of the next event, because we sometimes get an early decrementer interrupt, most notably when we set the decrementer to 1 in arch_irq_work_raise(). The effect of not having the sanity check is that if timer_interrupt() gets called early, we leave the decrementer set to its maximum value, which means we then don't get any more decrementer interrupts for about 4 seconds (or longer, depending on timebase frequency). I saw these pauses as a consequence of getting a stray hypervisor decrementer interrupt left over from exiting a KVM guest. This isn't quite a straight revert because of changes to the surrounding code, but it restores the same algorithm as was previously used. Acked-by: Anton Blanchard Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/time.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 2c42cd72d0f..730e69cb7e9 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -474,6 +474,7 @@ void timer_interrupt(struct pt_regs * regs) struct pt_regs *old_regs; u64 *next_tb = &__get_cpu_var(decrementers_next_tb); struct clock_event_device *evt = &__get_cpu_var(decrementers); + u64 now; /* Ensure a positive value is written to the decrementer, or else * some CPUs will continue to take decrementer exceptions. @@ -508,9 +509,16 @@ void timer_interrupt(struct pt_regs * regs) irq_work_run(); } - *next_tb = ~(u64)0; - if (evt->event_handler) - evt->event_handler(evt); + now = get_tb_or_rtc(); + if (now >= *next_tb) { + *next_tb = ~(u64)0; + if (evt->event_handler) + evt->event_handler(evt); + } else { + now = *next_tb - now; + if (now <= DECREMENTER_MAX) + set_dec((int)now); + } #ifdef CONFIG_PPC64 /* collect purr register values often, for accurate calculations */ From e6e70e4c7ef345d3af2d2ba98c2d2f175aa64c2a Mon Sep 17 00:00:00 2001 From: Steffen Rumler Date: Wed, 6 Jun 2012 16:37:17 +0200 Subject: [PATCH 0179/2357] powerpc: Fix kernel panic during kernel module load commit 3c75296562f43e6fbc6cddd3de948a7b3e4e9bcf upstream. This fixes a problem which can causes kernel oopses while loading a kernel module. According to the PowerPC EABI specification, GPR r11 is assigned the dedicated function to point to the previous stack frame. In the powerpc-specific kernel module loader, do_plt_call() (in arch/powerpc/kernel/module_32.c), GPR r11 is also used to generate trampoline code. This combination crashes the kernel, in the case where the compiler chooses to use a helper function for saving GPRs on entry, and the module loader has placed the .init.text section far away from the .text section, meaning that it has to generate a trampoline for functions in the .init.text section to call the GPR save helper. Because the trampoline trashes r11, references to the stack frame using r11 can cause an oops. The fix just uses GPR r12 instead of GPR r11 for generating the trampoline code. According to the statements from Freescale, this is safe from an EABI perspective. I've tested the fix for kernel 2.6.33 on MPC8541. Signed-off-by: Steffen Rumler [paulus@samba.org: reworded the description] Signed-off-by: Paul Mackerras Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/module_32.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index 0b6d79617d7..2e3200ca485 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c @@ -176,8 +176,8 @@ int module_frob_arch_sections(Elf32_Ehdr *hdr, static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val) { - if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16) - && entry->jump[1] == 0x396b0000 + (val & 0xffff)) + if (entry->jump[0] == 0x3d800000 + ((val + 0x8000) >> 16) + && entry->jump[1] == 0x398c0000 + (val & 0xffff)) return 1; return 0; } @@ -204,10 +204,9 @@ static uint32_t do_plt_call(void *location, entry++; } - /* Stolen from Paul Mackerras as well... */ - entry->jump[0] = 0x3d600000+((val+0x8000)>>16); /* lis r11,sym@ha */ - entry->jump[1] = 0x396b0000 + (val&0xffff); /* addi r11,r11,sym@l*/ - entry->jump[2] = 0x7d6903a6; /* mtctr r11 */ + entry->jump[0] = 0x3d800000+((val+0x8000)>>16); /* lis r12,sym@ha */ + entry->jump[1] = 0x398c0000 + (val&0xffff); /* addi r12,r12,sym@l*/ + entry->jump[2] = 0x7d8903a6; /* mtctr r12 */ entry->jump[3] = 0x4e800420; /* bctr */ DEBUGP("Initialized plt for 0x%x at %p\n", val, entry); From 3410afedcda2f504e8fbe02a7f4c49912ce688c8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 8 Jun 2012 14:58:13 +0930 Subject: [PATCH 0180/2357] module_param: stop double-calling parameters. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ae82fdb1406ad41d68f07027fe31f2d35ba22a90 upstream. Commit 026cee0086fe1df4cf74691cf273062cc769617d "params: _initcall-like kernel parameters" set old-style module parameters to level 0. And we call those level 0 calls where we used to, early in start_kernel(). We also loop through the initcall levels and call the levelled module_params before the corresponding initcall. Unfortunately level 0 is early_init(), so we call the standard module_param calls twice. (Turns out most things don't care, but at least ubi.mtd does). Change the level to -1 for standard module_param calls. Reported-by: Benoît Thébaudeau Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman --- include/linux/moduleparam.h | 10 +++++----- init/main.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index ea36486378d..944bc186ea3 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -128,7 +128,7 @@ struct kparam_array * The ops can have NULL set or get functions. */ #define module_param_cb(name, ops, arg, perm) \ - __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, 0) + __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1) /** * _param_cb - general callback for a module/cmdline parameter @@ -192,7 +192,7 @@ struct kparam_array { (void *)set, (void *)get }; \ __module_param_call(MODULE_PARAM_PREFIX, \ name, &__param_ops_##name, arg, \ - (perm) + sizeof(__check_old_set_param(set))*0, 0) + (perm) + sizeof(__check_old_set_param(set))*0, -1) /* We don't get oldget: it's often a new-style param_get_uint, etc. */ static inline int @@ -272,7 +272,7 @@ static inline void __kernel_param_unlock(void) */ #define core_param(name, var, type, perm) \ param_check_##type(name, &(var)); \ - __module_param_call("", name, ¶m_ops_##type, &var, perm, 0) + __module_param_call("", name, ¶m_ops_##type, &var, perm, -1) #endif /* !MODULE */ /** @@ -290,7 +290,7 @@ static inline void __kernel_param_unlock(void) = { len, string }; \ __module_param_call(MODULE_PARAM_PREFIX, name, \ ¶m_ops_string, \ - .str = &__param_string_##name, perm, 0); \ + .str = &__param_string_##name, perm, -1); \ __MODULE_PARM_TYPE(name, "string") /** @@ -431,7 +431,7 @@ extern int param_set_bint(const char *val, const struct kernel_param *kp); __module_param_call(MODULE_PARAM_PREFIX, name, \ ¶m_array_ops, \ .arr = &__param_arr_##name, \ - perm, 0); \ + perm, -1); \ __MODULE_PARM_TYPE(name, "array of " #type) extern struct kernel_param_ops param_array_ops; diff --git a/init/main.c b/init/main.c index cb54cd3dbf0..b08c5f75974 100644 --- a/init/main.c +++ b/init/main.c @@ -508,7 +508,7 @@ asmlinkage void __init start_kernel(void) parse_early_param(); parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param, - 0, 0, &unknown_bootoption); + -1, -1, &unknown_bootoption); jump_label_init(); From d913c02b0a172d5dca6280da5b17a407d69bbce4 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Wed, 30 May 2012 10:54:57 -0700 Subject: [PATCH 0181/2357] timekeeping: Fix CLOCK_MONOTONIC inconsistency during leapsecond commit fad0c66c4bb836d57a5f125ecd38bed653ca863a upstream. Commit 6b43ae8a61 (ntp: Fix leap-second hrtimer livelock) broke the leapsecond update of CLOCK_MONOTONIC. The missing leapsecond update to wall_to_monotonic causes discontinuities in CLOCK_MONOTONIC. Adjust wall_to_monotonic when NTP inserted a leapsecond. Reported-by: Richard Cochran Signed-off-by: John Stultz Tested-by: Richard Cochran Link: http://lkml.kernel.org/r/1338400497-12420-1-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/time/timekeeping.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index d66b21308f7..d42574df7c5 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -964,6 +964,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) timekeeper.xtime.tv_sec++; leap = second_overflow(timekeeper.xtime.tv_sec); timekeeper.xtime.tv_sec += leap; + timekeeper.wall_to_monotonic.tv_sec -= leap; } /* Accumulate raw time */ @@ -1079,6 +1080,7 @@ static void update_wall_time(void) timekeeper.xtime.tv_sec++; leap = second_overflow(timekeeper.xtime.tv_sec); timekeeper.xtime.tv_sec += leap; + timekeeper.wall_to_monotonic.tv_sec -= leap; } timekeeping_update(false); From c573b3798f5fd9e24f9ec23a39c4915c6e024faf Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 7 Jun 2012 18:56:06 -0400 Subject: [PATCH 0182/2357] ext4: fix the free blocks calculation for ext3 file systems w/ uninit_bg commit b0dd6b70f0fda17ae9762fbb72d98e40a4f66556 upstream. Ext3 filesystems that are converted to use as many ext4 file system features as possible will enable uninit_bg to speed up e2fsck times. These file systems will have a native ext3 layout of inode tables and block allocation bitmaps (as opposed to ext4's flex_bg layout). Unfortunately, in these cases, when first allocating a block in an uninitialized block group, ext4 would incorrectly calculate the number of free blocks in that block group, and then errorneously report that the file system was corrupt: EXT4-fs error (device vdd): ext4_mb_generate_buddy:741: group 30, 32254 clusters in bitmap, 32258 in gd This problem can be reproduced via: mke2fs -q -t ext4 -O ^flex_bg /dev/vdd 5g mount -t ext4 /dev/vdd /mnt fallocate -l 4600m /mnt/test The problem was caused by a bone headed mistake in the check to see if a particular metadata block was part of the block group. Many thanks to Kees Cook for finding and bisecting the buggy commit which introduced this bug (commit fd034a84e1, present since v3.2). Reported-by: Sander Eikelenboom Reported-by: Kees Cook Signed-off-by: "Theodore Ts'o" Tested-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 4bbd07a6fa1..8da837be0c8 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -90,8 +90,8 @@ unsigned ext4_num_overhead_clusters(struct super_block *sb, * unusual file system layouts. */ if (ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), block_group)) { - block_cluster = EXT4_B2C(sbi, (start - - ext4_block_bitmap(sb, gdp))); + block_cluster = EXT4_B2C(sbi, + ext4_block_bitmap(sb, gdp) - start); if (block_cluster < num_clusters) block_cluster = -1; else if (block_cluster == num_clusters) { @@ -102,7 +102,7 @@ unsigned ext4_num_overhead_clusters(struct super_block *sb, if (ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), block_group)) { inode_cluster = EXT4_B2C(sbi, - start - ext4_inode_bitmap(sb, gdp)); + ext4_inode_bitmap(sb, gdp) - start); if (inode_cluster < num_clusters) inode_cluster = -1; else if (inode_cluster == num_clusters) { @@ -114,7 +114,7 @@ unsigned ext4_num_overhead_clusters(struct super_block *sb, itbl_blk = ext4_inode_table(sb, gdp); for (i = 0; i < sbi->s_itb_per_group; i++) { if (ext4_block_in_group(sb, itbl_blk + i, block_group)) { - c = EXT4_B2C(sbi, start - itbl_blk + i); + c = EXT4_B2C(sbi, itbl_blk + i - start); if ((c < num_clusters) || (c == inode_cluster) || (c == block_cluster) || (c == itbl_cluster)) continue; From 8d9fe5b77cbabd1805b30418ba32b3c1389303d0 Mon Sep 17 00:00:00 2001 From: Cliff Wickman Date: Thu, 7 Jun 2012 08:31:40 -0500 Subject: [PATCH 0183/2357] x86/uv: Fix UV2 BAU legacy mode commit d5d2d2eea84b0d8450b082edbc3dbde41fb8bfd8 upstream. The SGI Altix UV2 BAU (Broadcast Assist Unit) as used for tlb-shootdown (selective broadcast mode) always uses UV2 broadcast descriptor format. There is no need to clear the 'legacy' (UV1) mode, because the hardware always uses UV2 mode for selective broadcast. But the BIOS uses general broadcast and legacy mode, and the hardware pays attention to the legacy mode bit for general broadcast. So the kernel must not clear that mode bit. Signed-off-by: Cliff Wickman Link: http://lkml.kernel.org/r/E1SccoO-0002Lh-Cb@eag09.americas.sgi.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/uv/uv_bau.h | 1 - arch/x86/platform/uv/tlb_uv.c | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h index becf47b8173..6149b476d9d 100644 --- a/arch/x86/include/asm/uv/uv_bau.h +++ b/arch/x86/include/asm/uv/uv_bau.h @@ -149,7 +149,6 @@ /* 4 bits of software ack period */ #define UV2_ACK_MASK 0x7UL #define UV2_ACK_UNITS_SHFT 3 -#define UV2_LEG_SHFT UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT #define UV2_EXT_SHFT UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT /* diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 3ae0e61abd2..59880afa851 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -1295,7 +1295,6 @@ static void __init enable_timeouts(void) */ mmr_image |= (1L << SOFTACK_MSHIFT); if (is_uv2_hub()) { - mmr_image &= ~(1L << UV2_LEG_SHFT); mmr_image |= (1L << UV2_EXT_SHFT); } write_mmr_misc_control(pnode, mmr_image); From cc3aeacdba55676938fc11e00e13699141b9aeb8 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 16 Apr 2012 18:01:53 +0200 Subject: [PATCH 0184/2357] x86, MCE, AMD: Make APIC LVT thresholding interrupt optional commit f227d4306cf30e1d5b6f231e8ef9006c34f3d186 upstream. Currently, the APIC LVT interrupt for error thresholding is implicitly enabled. However, there are models in the F15h range which do not enable it. Make the code machinery which sets up the APIC interrupt support an optional setting and add an ->interrupt_capable member to the bank representation mirroring that capability and enable the interrupt offset programming only if it is true. Simplify code and fixup comment style while at it. Signed-off-by: Borislav Petkov Cc: Robert Richter Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce_amd.c | 56 ++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 99b57179f91..2c1d178be46 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -51,6 +51,7 @@ struct threshold_block { unsigned int cpu; u32 address; u16 interrupt_enable; + bool interrupt_capable; u16 threshold_limit; struct kobject kobj; struct list_head miscj; @@ -83,6 +84,21 @@ struct thresh_restart { u16 old_limit; }; +static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits) +{ + /* + * bank 4 supports APIC LVT interrupts implicitly since forever. + */ + if (bank == 4) + return true; + + /* + * IntP: interrupt present; if this bit is set, the thresholding + * bank can generate APIC LVT interrupts + */ + return msr_high_bits & BIT(28); +} + static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) { int msr = (hi & MASK_LVTOFF_HI) >> 20; @@ -104,8 +120,10 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) return 1; }; -/* must be called with correct cpu affinity */ -/* Called via smp_call_function_single() */ +/* + * Called via smp_call_function_single(), must be called with correct + * cpu affinity. + */ static void threshold_restart_bank(void *_tr) { struct thresh_restart *tr = _tr; @@ -128,6 +146,12 @@ static void threshold_restart_bank(void *_tr) (new_count & THRESHOLD_MAX); } + /* clear IntType */ + hi &= ~MASK_INT_TYPE_HI; + + if (!tr->b->interrupt_capable) + goto done; + if (tr->set_lvt_off) { if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) { /* set new lvt offset */ @@ -136,9 +160,10 @@ static void threshold_restart_bank(void *_tr) } } - tr->b->interrupt_enable ? - (hi = (hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) : - (hi &= ~MASK_INT_TYPE_HI); + if (tr->b->interrupt_enable) + hi |= INT_TYPE_APIC; + + done: hi |= MASK_COUNT_EN_HI; wrmsr(tr->b->address, lo, hi); @@ -202,14 +227,17 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) if (shared_bank[bank] && c->cpu_core_id) break; - offset = setup_APIC_mce(offset, - (high & MASK_LVTOFF_HI) >> 20); - memset(&b, 0, sizeof(b)); - b.cpu = cpu; - b.bank = bank; - b.block = block; - b.address = address; + b.cpu = cpu; + b.bank = bank; + b.block = block; + b.address = address; + b.interrupt_capable = lvt_interrupt_supported(bank, high); + + if (b.interrupt_capable) { + int new = (high & MASK_LVTOFF_HI) >> 20; + offset = setup_APIC_mce(offset, new); + } mce_threshold_block_init(&b, offset); mce_threshold_vector = amd_threshold_interrupt; @@ -309,6 +337,9 @@ store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size) struct thresh_restart tr; unsigned long new; + if (!b->interrupt_capable) + return -EINVAL; + if (strict_strtoul(buf, 0, &new) < 0) return -EINVAL; @@ -467,6 +498,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, b->cpu = cpu; b->address = address; b->interrupt_enable = 0; + b->interrupt_capable = lvt_interrupt_supported(bank, high); b->threshold_limit = THRESHOLD_MAX; INIT_LIST_HEAD(&b->miscj); From 25ffc87a852380b75e5ce9618164f506b1254112 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 31 May 2012 20:53:08 +1000 Subject: [PATCH 0185/2357] hwrng: atmel-rng - fix race condition leading to repeated bits commit 121daad8fd1dce63076fa55aaedd5dc3f981b334 upstream. Data valid gets cleared by reading the ISR (status register) and NOT from reading ODATA (data register). A new data word can become available between checking ISR and reading ODATA, causing us to reuse the same data word next time atmel_trng_read() gets called, if that happens before the following data word is ready. With this fixed, rngtest no longer complains of 'Continous run' errors. Before: rngtest -c 1000 < /dev/hwrng rngtest 3 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warr. rngtest: starting FIPS tests... rngtest: bits received from input: 20000032 rngtest: FIPS 140-2 successes: 923 rngtest: FIPS 140-2 failures: 77 rngtest: FIPS 140-2(2001-10-10) Monobit: 0 rngtest: FIPS 140-2(2001-10-10) Poker: 0 rngtest: FIPS 140-2(2001-10-10) Runs: 1 rngtest: FIPS 140-2(2001-10-10) Long run: 0 rngtest: FIPS 140-2(2001-10-10) Continuous run: 76 rngtest: input channel speed: (min=721.402; avg=46003.510; max=49321.338)Kibitss rngtest: FIPS tests speed: (min=11.442; avg=12.714; max=12.801)Mibits/s rngtest: Program run time: 1931860 microseconds After: rngtest -c 1000 < /dev/hwrng rngtest 3 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warr. rngtest: starting FIPS tests... rngtest: bits received from input: 20000032 rngtest: FIPS 140-2 successes: 1000 rngtest: FIPS 140-2 failures: 0 rngtest: FIPS 140-2(2001-10-10) Monobit: 0 rngtest: FIPS 140-2(2001-10-10) Poker: 0 rngtest: FIPS 140-2(2001-10-10) Runs: 0 rngtest: FIPS 140-2(2001-10-10) Long run: 0 rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=777.518; avg=36988.482; max=43115.342)Kibitss rngtest: FIPS tests speed: (min=11.951; avg=12.715; max=12.887)Mibits/s rngtest: Program run time: 2035543 microseconds Signed-off-by: Peter Korsgaard Reported-by: George Pontis Acked-by: Nicolas Ferre Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/char/hw_random/atmel-rng.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index f518b99f53f..6289f0eee24 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -36,6 +36,13 @@ static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max, /* data ready? */ if (readl(trng->base + TRNG_ODATA) & 1) { *data = readl(trng->base + TRNG_ODATA); + /* + ensure data ready is only set again AFTER the next data + word is ready in case it got set between checking ISR + and reading ODATA, so we don't risk re-reading the + same word + */ + readl(trng->base + TRNG_ISR); return 4; } else return 0; From cc62e8bf1f779a54369e71e665211140a254df5c Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 30 May 2012 01:43:08 +0200 Subject: [PATCH 0186/2357] crypto: aesni-intel - fix unaligned cbc decrypt for x86-32 commit 7c8d51848a88aafdb68f42b6b650c83485ea2f84 upstream. The 32 bit variant of cbc(aes) decrypt is using instructions requiring 128 bit aligned memory locations but fails to ensure this constraint in the code. Fix this by loading the data into intermediate registers with load unaligned instructions. This fixes reported general protection faults related to aesni. References: https://bugzilla.kernel.org/show_bug.cgi?id=43223 Reported-by: Daniel Signed-off-by: Mathias Krause Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- arch/x86/crypto/aesni-intel_asm.S | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S index be6d9e365a8..3470624d783 100644 --- a/arch/x86/crypto/aesni-intel_asm.S +++ b/arch/x86/crypto/aesni-intel_asm.S @@ -2460,10 +2460,12 @@ ENTRY(aesni_cbc_dec) pxor IN3, STATE4 movaps IN4, IV #else - pxor (INP), STATE2 - pxor 0x10(INP), STATE3 pxor IN1, STATE4 movaps IN2, IV + movups (INP), IN1 + pxor IN1, STATE2 + movups 0x10(INP), IN2 + pxor IN2, STATE3 #endif movups STATE1, (OUTP) movups STATE2, 0x10(OUTP) From e82c95f9f0cb025da8e1af6df1c29080a78d0f84 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Jun 2012 13:28:42 +0200 Subject: [PATCH 0187/2357] drm/ttm: Fix buffer object metadata accounting regression v2 commit a393c730ab69617c3291a3b0b2a228c9be2fc28c upstream. A regression was introduced in the 3.3 rc series, commit "drm/ttm: simplify memory accounting for ttm user v2", causing the metadata of buffer objects created using the ttm_bo_create() function to be accounted twice. That causes massive leaks with the vmwgfx driver running for example SpecViewperf Catia-03 test 2, eventually killing the app. Furthermore, the same commit introduces a regression where metadata accounting is leaked if a buffer object is initialized with an illegal size. This is also fixed with this commit. v2: Fixed an error path and removed an unused variable. Signed-off-by: Thomas Hellstrom Reviewed-by: Konrad Rzeszutek Wilk Cc: Jerome Glisse Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/ttm/ttm_bo.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 18434186ed1..8b73ae84efe 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1193,6 +1193,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, (*destroy)(bo); else kfree(bo); + ttm_mem_global_free(mem_glob, acc_size); return -EINVAL; } bo->destroy = destroy; @@ -1294,22 +1295,14 @@ int ttm_bo_create(struct ttm_bo_device *bdev, struct ttm_buffer_object **p_bo) { struct ttm_buffer_object *bo; - struct ttm_mem_global *mem_glob = bdev->glob->mem_glob; size_t acc_size; int ret; - acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct ttm_buffer_object)); - ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false); - if (unlikely(ret != 0)) - return ret; - bo = kzalloc(sizeof(*bo), GFP_KERNEL); - - if (unlikely(bo == NULL)) { - ttm_mem_global_free(mem_glob, acc_size); + if (unlikely(bo == NULL)) return -ENOMEM; - } + acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct ttm_buffer_object)); ret = ttm_bo_init(bdev, bo, size, type, placement, page_alignment, buffer_start, interruptible, persistent_swap_storage, acc_size, NULL); From 4e050dfccceeb07641b8cf50618eb71e5208a6dc Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 23 May 2012 16:10:14 -0400 Subject: [PATCH 0188/2357] Btrfs: fall back to non-inline if we don't have enough space commit 2adcac1a7331d93a17285804819caa96070b231f upstream. If cow_file_range_inline fails with ENOSPC we abort the transaction which isn't very nice. This really shouldn't be happening anyways but there's no sense in making it a horrible error when we can easily just go allocate normal data space for this stuff. Thanks, Signed-off-by: Josef Bacik Acked-by: Chris Mason Cc: Alexandre Oliva Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 61b16c641ce..0df0d1fd4fe 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -257,10 +257,13 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans, ret = insert_inline_extent(trans, root, inode, start, inline_len, compressed_size, compress_type, compressed_pages); - if (ret) { + if (ret && ret != -ENOSPC) { btrfs_abort_transaction(trans, root, ret); return ret; + } else if (ret == -ENOSPC) { + return 1; } + btrfs_delalloc_release_metadata(inode, end + 1 - start); btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0); return 0; From 20528f7e3c40fa95faf5ebc028c16c40216d0b76 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Jun 2012 13:43:11 +0200 Subject: [PATCH 0189/2357] iwlwifi: disable WoWLAN if !CONFIG_PM_SLEEP commit fcb6ff5e2cb83e1de10631f6621f45ca3401bf61 upstream. If CONFIG_PM_SLEEP is disabled, then iwlwifi doesn't support suspend/resume handlers and thus mac80211 (correctly) refuses advertising WoWLAN. Disable WoWLAN in the driver in this case. Reported-by: Sebastian Kemper Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-mac80211.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index c24a7134a6f..dcb13c89677 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -196,6 +196,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_IBSS_RSN; +#ifdef CONFIG_PM_SLEEP if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len && trans(priv)->ops->wowlan_suspend && device_can_wakeup(trans(priv)->dev)) { @@ -214,6 +215,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, hw->wiphy->wowlan.pattern_max_len = IWLAGN_WOWLAN_MAX_PATTERN_LEN; } +#endif if (iwlagn_mod_params.power_save) hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; From 5a4c9cbfe943986db40b699c5320fdacfa2885b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Jun 2012 09:38:35 +0200 Subject: [PATCH 0190/2357] iwlwifi: unregister LEDs if mac80211 registration fails commit 0e1fa7ef25004b9c1a14147bce61c15c2f1c6744 upstream. Otherwise the LEDs stick around and cause issues the next time around since they're still there but not really hooked up. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-mac80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index dcb13c89677..1018f9b8b41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -245,6 +245,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, ret = ieee80211_register_hw(priv->hw); if (ret) { IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); + iwl_leds_exit(priv); return ret; } priv->mac80211_registered = 1; From 5ca732f5673f2a1fa9e4d6451259ae5891fa6b60 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 6 Jun 2012 09:13:36 +0200 Subject: [PATCH 0191/2357] iwlwifi: don't mess up the SCD when removing a key commit d6ee27eb13beab94056e0de52d81220058ca2297 upstream. When we remove a key, we put a key index which was supposed to tell the fw that we are actually removing the key. But instead the fw took that index as a valid index and messed up the SRAM of the device. This memory corruption on the device mangled the data of the SCD. The impact on the user is that SCD queue 2 got stuck after having removed keys. The message is the log that was printed is: Queue 2 stuck for 10000ms This doesn't seem to fix the higher queues that get stuck from time to time. Reviewed-by: Meenakshi Venkataraman Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-agn-sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index c4175603864..bef3f242434 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -1222,7 +1222,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, key_flags |= STA_KEY_MULTICAST_MSK; sta_cmd.key.key_flags = key_flags; - sta_cmd.key.key_offset = WEP_INVALID_OFFSET; + sta_cmd.key.key_offset = keyconf->hw_key_idx; sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK; sta_cmd.mode = STA_CONTROL_MODIFY_MSK; From f4c3d440c898725132291e5171b3244c2027c30e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 6 Jun 2012 13:55:02 +0200 Subject: [PATCH 0192/2357] iwlwifi: disable the buggy chain extension feature in HW commit d012d04e4d6312ea157b6cf19e9689af934f5aa7 upstream. This feature has been reported to be buggy and enabled by default. We therefore need to disable it manually. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-prph.h | 1 + drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 3b1069290fa..dfd54662e3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -224,6 +224,7 @@ #define SCD_TXFACT (SCD_BASE + 0x10) #define SCD_ACTIVE (SCD_BASE + 0x14) #define SCD_QUEUECHAIN_SEL (SCD_BASE + 0xe8) +#define SCD_CHAINEXT_EN (SCD_BASE + 0x244) #define SCD_AGGR_SEL (SCD_BASE + 0x248) #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 4d7b30d3e64..66df0166cfd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -1128,6 +1128,11 @@ static void iwl_tx_start(struct iwl_trans *trans) iwl_write_prph(trans, SCD_DRAM_BASE_ADDR, trans_pcie->scd_bc_tbls.dma >> 10); + /* The chain extension of the SCD doesn't work well. This feature is + * enabled by default by the HW, so we need to disable it manually. + */ + iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); + /* Enable DMA channel */ for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++) iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan), From 721632c39add11e5d5fa5dd8b956dcae63d02b17 Mon Sep 17 00:00:00 2001 From: Meenakshi Venkataraman Date: Wed, 30 May 2012 11:39:33 +0200 Subject: [PATCH 0193/2357] mac80211: fix error in station state transitions during reconfig commit bd34ab62a3297bd7685da11b0cbe05ae4cd8b02c upstream. As part of hardware reconfig mac80211 tries to restore the station state to its values before the hardware reconfig, but it only goes to the last-state - 1. Fix this off-by-one error. Signed-off-by: Meenakshi Venkataraman Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3862c966dec..eb9d7c0529b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1224,7 +1224,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) enum ieee80211_sta_state state; for (state = IEEE80211_STA_NOTEXIST; - state < sta->sta_state - 1; state++) + state < sta->sta_state; state++) WARN_ON(drv_sta_state(local, sta->sdata, sta, state, state + 1)); } From d4bb7f49f4d5ea7a287899178df55b4725bb32d2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 31 May 2012 15:09:27 +0200 Subject: [PATCH 0194/2357] mac80211: clean up remain-on-channel on interface stop commit 71ecfa1893034eeb1c93e02e22ee2ad26d080858 upstream. When any interface goes down, it could be the one that we were doing a remain-on-channel with. We therefore need to cancel the remain-on-channel and flush the related work structs so they don't run after the interface has been removed or even destroyed. It's also possible in this case that an off-channel SKB was never transmitted, so free it if this is the case. Note that this can also happen if the driver finishes the off-channel period without ever starting it. Reported-by: Nirav Shah Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/iface.c | 12 ++++++++++++ net/mac80211/offchannel.c | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index c20051b7ffc..48f937e1ecf 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -514,6 +514,18 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ieee80211_configure_filter(local); break; default: + mutex_lock(&local->mtx); + if (local->hw_roc_dev == sdata->dev && + local->hw_roc_channel) { + /* ignore return value since this is racy */ + drv_cancel_remain_on_channel(local); + ieee80211_queue_work(&local->hw, &local->hw_roc_done); + } + mutex_unlock(&local->mtx); + + flush_work(&local->hw_roc_start); + flush_work(&local->hw_roc_done); + flush_work(&sdata->work); /* * When we get here, the interface is marked down. diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index f054e94901a..935aa4b6dee 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -234,6 +234,22 @@ static void ieee80211_hw_roc_done(struct work_struct *work) return; } + /* was never transmitted */ + if (local->hw_roc_skb) { + u64 cookie; + + cookie = local->hw_roc_cookie ^ 2; + + cfg80211_mgmt_tx_status(local->hw_roc_dev, cookie, + local->hw_roc_skb->data, + local->hw_roc_skb->len, false, + GFP_KERNEL); + + kfree_skb(local->hw_roc_skb); + local->hw_roc_skb = NULL; + local->hw_roc_skb_for_status = NULL; + } + if (!local->hw_roc_for_tx) cfg80211_remain_on_channel_expired(local->hw_roc_dev, local->hw_roc_cookie, From 073e100877a39f36163398cde868e98fa6d3f0a1 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 3 Jun 2012 23:32:32 +0300 Subject: [PATCH 0195/2357] mac80211: fix non RCU-safe sta_list manipulation commit 794454ce72a298de6f4536ade597bdcc7dcde7c7 upstream. sta_info_cleanup locks the sta_list using rcu_read_lock however the delete operation isn't rcu safe. A race between sta_info_cleanup timer being called and a STA being removed can occur which leads to a panic while traversing sta_list. Fix this by switching to the RCU-safe versions. Reported-by: Eyal Shapira Signed-off-by: Arik Nemtsov Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/sta_info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 38137cb5f6f..d93d39b8434 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -378,7 +378,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) /* make the station visible */ sta_info_hash_add(local, sta); - list_add(&sta->list, &local->sta_list); + list_add_rcu(&sta->list, &local->sta_list); set_sta_flag(sta, WLAN_STA_INSERTED); @@ -688,7 +688,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) if (ret) return ret; - list_del(&sta->list); + list_del_rcu(&sta->list); mutex_lock(&local->key_mtx); for (i = 0; i < NUM_DEFAULT_KEYS; i++) From 2d539f9e66ea9aaf4998e98fbfe719f99d5f6590 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Jun 2012 12:25:19 +0100 Subject: [PATCH 0196/2357] ASoC: wm8994: Ensure all AIFnCLK events are run from the _late variants commit c8fdc1b56611faa7b38eab6b99da5e20113661ff upstream. Ensure that all the actions get taken at appropriate times by calling the _PRE and _POST events for the aifNclk_ev functions explicitly. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8994.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 2de12ebe43b..a8de3bc6501 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1207,17 +1207,19 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: if (wm8994->aif1clk_enable) { - aif1clk_ev(w, kcontrol, event); + aif1clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMU); snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1, WM8994_AIF1CLK_ENA_MASK, WM8994_AIF1CLK_ENA); + aif1clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMU); wm8994->aif1clk_enable = 0; } if (wm8994->aif2clk_enable) { - aif2clk_ev(w, kcontrol, event); + aif2clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMU); snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1, WM8994_AIF2CLK_ENA_MASK, WM8994_AIF2CLK_ENA); + aif2clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMU); wm8994->aif2clk_enable = 0; } break; @@ -1238,15 +1240,17 @@ static int late_disable_ev(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMD: if (wm8994->aif1clk_disable) { + aif1clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMD); snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1, WM8994_AIF1CLK_ENA_MASK, 0); - aif1clk_ev(w, kcontrol, event); + aif1clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMD); wm8994->aif1clk_disable = 0; } if (wm8994->aif2clk_disable) { + aif2clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMD); snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1, WM8994_AIF2CLK_ENA_MASK, 0); - aif2clk_ev(w, kcontrol, event); + aif2clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMD); wm8994->aif2clk_disable = 0; } break; From 38a3c37777b7a0864b70480067b8606100139c11 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Jun 2012 12:31:32 +0100 Subject: [PATCH 0197/2357] ASoC: wm8994: Apply volume updates with clocks enabled commit bfd37bb5f681961e255fd2f346c20fdae2ef3f27 upstream. Volume updates may not be acted upon if there is no clock applied when the volume update is written. Ensure this doesn't happen by writing out registers with volume updates after we enable each of the clocks. There are more registers updated than before as previously we were relying on wm_hubs to set those for controls it manages. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8994.c | 93 ++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index a8de3bc6501..f351b933f5c 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -46,6 +46,39 @@ #define WM8994_NUM_DRC 3 #define WM8994_NUM_EQ 3 +static struct { + unsigned int reg; + unsigned int mask; +} wm8994_vu_bits[] = { + { WM8994_LEFT_LINE_INPUT_1_2_VOLUME, WM8994_IN1_VU }, + { WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, WM8994_IN1_VU }, + { WM8994_LEFT_LINE_INPUT_3_4_VOLUME, WM8994_IN2_VU }, + { WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, WM8994_IN2_VU }, + { WM8994_SPEAKER_VOLUME_LEFT, WM8994_SPKOUT_VU }, + { WM8994_SPEAKER_VOLUME_RIGHT, WM8994_SPKOUT_VU }, + { WM8994_LEFT_OUTPUT_VOLUME, WM8994_HPOUT1_VU }, + { WM8994_RIGHT_OUTPUT_VOLUME, WM8994_HPOUT1_VU }, + { WM8994_LEFT_OPGA_VOLUME, WM8994_MIXOUT_VU }, + { WM8994_RIGHT_OPGA_VOLUME, WM8994_MIXOUT_VU }, + + { WM8994_AIF1_DAC1_LEFT_VOLUME, WM8994_AIF1DAC1_VU }, + { WM8994_AIF1_DAC1_RIGHT_VOLUME, WM8994_AIF1DAC1_VU }, + { WM8994_AIF1_DAC2_LEFT_VOLUME, WM8994_AIF1DAC2_VU }, + { WM8994_AIF1_DAC2_RIGHT_VOLUME, WM8994_AIF1DAC2_VU }, + { WM8994_AIF2_DAC_LEFT_VOLUME, WM8994_AIF2DAC_VU }, + { WM8994_AIF2_DAC_RIGHT_VOLUME, WM8994_AIF2DAC_VU }, + { WM8994_AIF1_ADC1_LEFT_VOLUME, WM8994_AIF1ADC1_VU }, + { WM8994_AIF1_ADC1_RIGHT_VOLUME, WM8994_AIF1ADC1_VU }, + { WM8994_AIF1_ADC2_LEFT_VOLUME, WM8994_AIF1ADC2_VU }, + { WM8994_AIF1_ADC2_RIGHT_VOLUME, WM8994_AIF1ADC2_VU }, + { WM8994_AIF2_ADC_LEFT_VOLUME, WM8994_AIF2ADC_VU }, + { WM8994_AIF2_ADC_RIGHT_VOLUME, WM8994_AIF1ADC2_VU }, + { WM8994_DAC1_LEFT_VOLUME, WM8994_DAC1_VU }, + { WM8994_DAC1_RIGHT_VOLUME, WM8994_DAC1_VU }, + { WM8994_DAC2_LEFT_VOLUME, WM8994_DAC2_VU }, + { WM8994_DAC2_RIGHT_VOLUME, WM8994_DAC2_VU }, +}; + static int wm8994_drc_base[] = { WM8994_AIF1_DRC1_1, WM8994_AIF1_DRC2_1, @@ -1006,6 +1039,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = w->codec; struct wm8994 *control = codec->control_data; int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA; + int i; int dac; int adc; int val; @@ -1064,6 +1098,13 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w, WM8994_AIF1DAC2L_ENA); break; + case SND_SOC_DAPM_POST_PMU: + for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++) + snd_soc_write(codec, wm8994_vu_bits[i].reg, + snd_soc_read(codec, + wm8994_vu_bits[i].reg)); + break; + case SND_SOC_DAPM_PRE_PMD: case SND_SOC_DAPM_POST_PMD: snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, @@ -1089,6 +1130,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; + int i; int dac; int adc; int val; @@ -1139,6 +1181,13 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, WM8994_AIF2DACR_ENA); break; + case SND_SOC_DAPM_POST_PMU: + for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++) + snd_soc_write(codec, wm8994_vu_bits[i].reg, + snd_soc_read(codec, + wm8994_vu_bits[i].reg)); + break; + case SND_SOC_DAPM_PRE_PMD: case SND_SOC_DAPM_POST_PMD: snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, @@ -1587,9 +1636,11 @@ SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, aif1clk_ev, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, aif2clk_ev, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), @@ -3943,39 +3994,11 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) pm_runtime_put(codec->dev); - /* Latch volume updates (right only; we always do left then right). */ - snd_soc_update_bits(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, - WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); - snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, - WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); - snd_soc_update_bits(codec, WM8994_AIF1_DAC2_LEFT_VOLUME, - WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU); - snd_soc_update_bits(codec, WM8994_AIF1_DAC2_RIGHT_VOLUME, - WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU); - snd_soc_update_bits(codec, WM8994_AIF2_DAC_LEFT_VOLUME, - WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU); - snd_soc_update_bits(codec, WM8994_AIF2_DAC_RIGHT_VOLUME, - WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU); - snd_soc_update_bits(codec, WM8994_AIF1_ADC1_LEFT_VOLUME, - WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU); - snd_soc_update_bits(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME, - WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU); - snd_soc_update_bits(codec, WM8994_AIF1_ADC2_LEFT_VOLUME, - WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU); - snd_soc_update_bits(codec, WM8994_AIF1_ADC2_RIGHT_VOLUME, - WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU); - snd_soc_update_bits(codec, WM8994_AIF2_ADC_LEFT_VOLUME, - WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU); - snd_soc_update_bits(codec, WM8994_AIF2_ADC_RIGHT_VOLUME, - WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU); - snd_soc_update_bits(codec, WM8994_DAC1_LEFT_VOLUME, - WM8994_DAC1_VU, WM8994_DAC1_VU); - snd_soc_update_bits(codec, WM8994_DAC1_RIGHT_VOLUME, - WM8994_DAC1_VU, WM8994_DAC1_VU); - snd_soc_update_bits(codec, WM8994_DAC2_LEFT_VOLUME, - WM8994_DAC2_VU, WM8994_DAC2_VU); - snd_soc_update_bits(codec, WM8994_DAC2_RIGHT_VOLUME, - WM8994_DAC2_VU, WM8994_DAC2_VU); + /* Latch volume update bits */ + for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++) + snd_soc_update_bits(codec, wm8994_vu_bits[i].reg, + wm8994_vu_bits[i].mask, + wm8994_vu_bits[i].mask); /* Set the low bit of the 3D stereo depth so TLV matches */ snd_soc_update_bits(codec, WM8994_AIF1_DAC1_FILTERS_2, From 508cb55ffc236b401a84ec7e5caec470e0f85a89 Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Fri, 1 Jun 2012 09:13:17 -0500 Subject: [PATCH 0198/2357] bcma: add ext PA workaround for BCM4331 and BCM43431 commit 69aaedd3cfd23b2c732e3cf1227370a35f5c89d4 upstream. MacBook Pro models with BCM4331 wireless have been found to have the ext PA lines disabled after resuming from S3 without external power attach. This causes them to be unable to transmit. Add a workaround to ensure that the ext PA lines are enabled on BCM4331. Also extend all handling of ext PA line muxing to BCM43431 as is done in the Broadcom SDK. BugLink: http://bugs.launchpad.net/bugs/925577 Cc: Arend van Spriel Cc: Hauke Mehrtens Signed-off-by: Seth Forshee Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/bcma/driver_chipcommon_pmu.c | 4 +++- drivers/bcma/sprom.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index a058842f14f..61ce4054b3c 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -139,7 +139,9 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc) bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); break; case 0x4331: - /* BCM4331 workaround is SPROM-related, we put it in sprom.c */ + case 43431: + /* Ext PA lines must be enabled for tx on BCM4331 */ + bcma_chipco_bcm4331_ext_pa_lines_ctl(cc, true); break; case 43224: if (bus->chipinfo.rev == 0) { diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 3e2a6002aae..4588da2729b 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -432,13 +432,13 @@ int bcma_sprom_get(struct bcma_bus *bus) if (!sprom) return -ENOMEM; - if (bus->chipinfo.id == 0x4331) + if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431) bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); pr_debug("SPROM offset 0x%x\n", offset); bcma_sprom_read(bus, offset, sprom); - if (bus->chipinfo.id == 0x4331) + if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431) bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); err = bcma_sprom_valid(sprom); From a6382a8c4d9287ddca721edf622100e33c4546b9 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 12 Jun 2012 13:15:12 +0200 Subject: [PATCH 0199/2357] ALSA: HDA: Pin fixup for Zotac Z68 motherboard commit edfe3bfc1b779ddda9bcff523eb022dda37b93c8 upstream. Pin 0x1b was connected to the front panel connector, which according to the HDA standard should contain a mic and a headphone. In this case, the headphone was listed as "line out" by BIOS. BugLink: https://bugs.launchpad.net/bugs/993162 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7810913d07a..e56c2c817e0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6606,6 +6606,7 @@ enum { ALC662_FIXUP_ASUS_MODE7, ALC662_FIXUP_ASUS_MODE8, ALC662_FIXUP_NO_JACK_DETECT, + ALC662_FIXUP_ZOTAC_Z68, }; static const struct alc_fixup alc662_fixups[] = { @@ -6755,6 +6756,13 @@ static const struct alc_fixup alc662_fixups[] = { .type = ALC_FIXUP_FUNC, .v.func = alc_fixup_no_jack_detect, }, + [ALC662_FIXUP_ZOTAC_Z68] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x1b, 0x02214020 }, /* Front HP */ + { } + } + }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -6768,6 +6776,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), + SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68), SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), #if 0 From 6fa9c3400dd4cbf30c597dbde5d6abbc12b9764d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Jun 2012 12:16:50 +0200 Subject: [PATCH 0200/2357] cfg80211: fix interface combinations check commit 463454b5dbd8dbab6e2fc6c557329e5b811b9c32 upstream. If a given interface combination doesn't contain a required interface type then we missed checking that and erroneously allowed it even though iface type wasn't there at all. Add a check that makes sure that all interface types are accounted for. Reported-by: Mohammed Shafi Shajakhan Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/util.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/net/wireless/util.c b/net/wireless/util.c index 957f2562161..b5b689070ba 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -936,6 +936,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, enum nl80211_iftype iftype) { struct wireless_dev *wdev_iter; + u32 used_iftypes = BIT(iftype); int num[NUM_NL80211_IFTYPES]; int total = 1; int i, j; @@ -969,12 +970,14 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, num[wdev_iter->iftype]++; total++; + used_iftypes |= BIT(wdev_iter->iftype); } mutex_unlock(&rdev->devlist_mtx); for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { const struct ieee80211_iface_combination *c; struct ieee80211_iface_limit *limits; + u32 all_iftypes = 0; c = &rdev->wiphy.iface_combinations[i]; @@ -989,6 +992,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, if (rdev->wiphy.software_iftypes & BIT(iftype)) continue; for (j = 0; j < c->n_limits; j++) { + all_iftypes |= limits[j].types; if (!(limits[j].types & BIT(iftype))) continue; if (limits[j].max < num[iftype]) @@ -996,7 +1000,20 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, limits[j].max -= num[iftype]; } } - /* yay, it fits */ + + /* + * Finally check that all iftypes that we're currently + * using are actually part of this combination. If they + * aren't then we can't use this combination and have + * to continue to the next. + */ + if ((all_iftypes & used_iftypes) != used_iftypes) + goto cont; + + /* + * This combination covered all interface types and + * supported the requested numbers, so we're good. + */ kfree(limits); return 0; cont: From 5ab37d70078783aa8dd6dbec0e614c83ab694cb8 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 1 Jun 2012 11:29:40 +0200 Subject: [PATCH 0201/2357] rt2x00: use atomic variable for seqno commit e5851dac2c95af7159716832300b9f50c62c648e upstream. Remove spinlock as atomic_t can be used instead. Note we use only 16 lower bits, upper bits are changed but we impilcilty cast to u16. This fix possible deadlock on IBSS mode reproted by lockdep: ================================= [ INFO: inconsistent lock state ] 3.4.0-wl+ #4 Not tainted --------------------------------- inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. kworker/u:2/30374 [HC0[0]:SC0[0]:HE1:SE1] takes: (&(&intf->seqlock)->rlock){+.?...}, at: [] rt2x00queue_create_tx_descriptor+0x380/0x490 [rt2x00lib] {IN-SOFTIRQ-W} state was registered at: [] __lock_acquire+0x47b/0x1050 [] lock_acquire+0x84/0xf0 [] _raw_spin_lock+0x33/0x40 [] rt2x00queue_create_tx_descriptor+0x380/0x490 [rt2x00lib] [] rt2x00queue_write_tx_frame+0x1a/0x300 [rt2x00lib] [] rt2x00mac_tx+0x7f/0x380 [rt2x00lib] [] __ieee80211_tx+0x1b3/0x300 [mac80211] [] ieee80211_tx+0x105/0x130 [mac80211] [] ieee80211_xmit+0xad/0x100 [mac80211] [] ieee80211_subif_start_xmit+0x2d9/0x930 [mac80211] [] dev_hard_start_xmit+0x307/0x660 [] sch_direct_xmit+0xa1/0x1e0 [] dev_queue_xmit+0x183/0x730 [] neigh_resolve_output+0xfa/0x1e0 [] ip_finish_output+0x24a/0x460 [] ip_output+0xb7/0x100 [] ip_local_out+0x20/0x60 [] igmpv3_sendpack+0x4f/0x60 [] igmp_ifc_timer_expire+0x29f/0x330 [] run_timer_softirq+0x15c/0x2f0 [] __do_softirq+0xae/0x1e0 irq event stamp: 18380437 hardirqs last enabled at (18380437): [] __slab_alloc.clone.3+0x67/0x5f0 hardirqs last disabled at (18380436): [] __slab_alloc.clone.3+0x33/0x5f0 softirqs last enabled at (18377616): [] __do_softirq+0x123/0x1e0 softirqs last disabled at (18377611): [] do_softirq+0x9d/0xe0 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&(&intf->seqlock)->rlock); lock(&(&intf->seqlock)->rlock); *** DEADLOCK *** 4 locks held by kworker/u:2/30374: #0: (wiphy_name(local->hw.wiphy)){++++.+}, at: [] process_one_work+0x109/0x3f0 #1: ((&sdata->work)){+.+.+.}, at: [] process_one_work+0x109/0x3f0 #2: (&ifibss->mtx){+.+.+.}, at: [] ieee80211_ibss_work+0x1b/0x470 [mac80211] #3: (&intf->beacon_skb_mutex){+.+...}, at: [] rt2x00queue_update_beacon+0x24/0x50 [rt2x00lib] stack backtrace: Pid: 30374, comm: kworker/u:2 Not tainted 3.4.0-wl+ #4 Call Trace: [] print_usage_bug+0x1f6/0x220 [] mark_lock+0x2c2/0x300 [] ? check_usage_forwards+0xc0/0xc0 [] __lock_acquire+0x4bc/0x1050 [] ? __kmalloc_track_caller+0x1c0/0x1d0 [] ? copy_skb_header+0x26/0x90 [] lock_acquire+0x84/0xf0 [] ? rt2x00queue_create_tx_descriptor+0x380/0x490 [rt2x00lib] [] _raw_spin_lock+0x33/0x40 [] ? rt2x00queue_create_tx_descriptor+0x380/0x490 [rt2x00lib] [] rt2x00queue_create_tx_descriptor+0x380/0x490 [rt2x00lib] [] rt2x00queue_update_beacon_locked+0x5f/0xb0 [rt2x00lib] [] rt2x00queue_update_beacon+0x2d/0x50 [rt2x00lib] [] rt2x00mac_bss_info_changed+0x1ca/0x200 [rt2x00lib] [] ? rt2x00mac_remove_interface+0x70/0x70 [rt2x00lib] [] ieee80211_bss_info_change_notify+0xe0/0x1d0 [mac80211] [] __ieee80211_sta_join_ibss+0x3b8/0x610 [mac80211] [] ? mark_held_locks+0x64/0xc0 [] ? virt_efi_query_capsule_caps+0x12/0x50 [] ieee80211_sta_join_ibss+0xf9/0x140 [mac80211] [] ieee80211_ibss_work+0x416/0x470 [mac80211] [] ? trace_hardirqs_on+0xb/0x10 [] ? skb_dequeue+0x4b/0x70 [] ieee80211_iface_work+0x13f/0x230 [mac80211] [] ? process_one_work+0x109/0x3f0 [] process_one_work+0x185/0x3f0 [] ? process_one_work+0x109/0x3f0 [] ? ieee80211_teardown_sdata+0xa0/0xa0 [mac80211] [] worker_thread+0x116/0x270 [] ? manage_workers+0x1e0/0x1e0 [] kthread+0x84/0x90 [] ? __init_kthread_worker+0x60/0x60 [] kernel_thread_helper+0x6/0x10 Signed-off-by: Stanislaw Gruszka Acked-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2x00.h | 3 +-- drivers/net/wireless/rt2x00/rt2x00mac.c | 1 - drivers/net/wireless/rt2x00/rt2x00queue.c | 13 ++++++------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 471f87cab4a..c264dfa6e61 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -396,8 +396,7 @@ struct rt2x00_intf { * for hardware which doesn't support hardware * sequence counting. */ - spinlock_t seqlock; - u16 seqno; + atomic_t seqno; }; static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 2df2eb6d3e0..a8885f06006 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -277,7 +277,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, else rt2x00dev->intf_sta_count++; - spin_lock_init(&intf->seqlock); mutex_init(&intf->beacon_skb_mutex); intf->beacon = entry; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 9b1b2b7a780..50f92d5a2bd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -207,6 +207,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); + u16 seqno; if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) return; @@ -227,15 +228,13 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev, * sequence counting per-frame, since those will override the * sequence counter given by mac80211. */ - spin_lock(&intf->seqlock); - if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) - intf->seqno += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(intf->seqno); - - spin_unlock(&intf->seqlock); + seqno = atomic_add_return(0x10, &intf->seqno); + else + seqno = atomic_read(&intf->seqno); + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(seqno); } static void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev, From fb8e114490823c581899112e82ee710ccd14fa11 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Tue, 17 Apr 2012 01:50:32 +0200 Subject: [PATCH 0202/2357] wireless: rt2x00: rt2800usb add more devices ids commit 63b376411173c343bbcb450f95539da91f079e0c upstream. They were taken from ralink drivers: 2011_0719_RT3070_RT3370_RT5370_RT5372_Linux_STA_V2.5.0.3_DPO 2012_03_22_RT5572_Linux_STA_v2.6.0.0_DPO 0x1eda,0x2210 RT3070 Airties 0x083a,0xb511 RT3370 Panasonic 0x0471,0x20dd RT3370 Philips 0x1690,0x0764 RT35xx Askey 0x0df6,0x0065 RT35xx Sitecom 0x0df6,0x0066 RT35xx Sitecom 0x0df6,0x0068 RT35xx Sitecom 0x2001,0x3c1c RT5370 DLink 0x2001,0x3c1d RT5370 DLink 2001 is D-Link not Alpha Signed-off-by: Xose Vazquez Perez Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800usb.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 001735f7a66..5851be71f3a 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -922,6 +922,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x1482, 0x3c09) }, /* AirTies */ { USB_DEVICE(0x1eda, 0x2012) }, + { USB_DEVICE(0x1eda, 0x2210) }, { USB_DEVICE(0x1eda, 0x2310) }, /* Allwin */ { USB_DEVICE(0x8516, 0x2070) }, @@ -1134,6 +1135,10 @@ static struct usb_device_id rt2800usb_device_table[] = { #ifdef CONFIG_RT2800USB_RT33XX /* Belkin */ { USB_DEVICE(0x050d, 0x945b) }, + /* Panasonic */ + { USB_DEVICE(0x083a, 0xb511) }, + /* Philips */ + { USB_DEVICE(0x0471, 0x20dd) }, /* Ralink */ { USB_DEVICE(0x148f, 0x3370) }, { USB_DEVICE(0x148f, 0x8070) }, @@ -1145,6 +1150,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x8516, 0x3572) }, /* Askey */ { USB_DEVICE(0x1690, 0x0744) }, + { USB_DEVICE(0x1690, 0x0764) }, /* Cisco */ { USB_DEVICE(0x167b, 0x4001) }, /* EnGenius */ @@ -1159,20 +1165,25 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Sitecom */ { USB_DEVICE(0x0df6, 0x0041) }, { USB_DEVICE(0x0df6, 0x0062) }, + { USB_DEVICE(0x0df6, 0x0065) }, + { USB_DEVICE(0x0df6, 0x0066) }, + { USB_DEVICE(0x0df6, 0x0068) }, /* Toshiba */ { USB_DEVICE(0x0930, 0x0a07) }, /* Zinwell */ { USB_DEVICE(0x5a57, 0x0284) }, #endif #ifdef CONFIG_RT2800USB_RT53XX - /* Alpha */ - { USB_DEVICE(0x2001, 0x3c15) }, - { USB_DEVICE(0x2001, 0x3c19) }, /* Arcadyan */ { USB_DEVICE(0x043e, 0x7a12) }, /* Azurewave */ { USB_DEVICE(0x13d3, 0x3329) }, { USB_DEVICE(0x13d3, 0x3365) }, + /* D-Link */ + { USB_DEVICE(0x2001, 0x3c15) }, + { USB_DEVICE(0x2001, 0x3c19) }, + { USB_DEVICE(0x2001, 0x3c1c) }, + { USB_DEVICE(0x2001, 0x3c1d) }, /* LG innotek */ { USB_DEVICE(0x043e, 0x7a22) }, /* Panasonic */ From 1a4ea49398c1e32475a65a34cd4ff5de64449bca Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Tue, 17 Apr 2012 16:28:05 +0200 Subject: [PATCH 0203/2357] wireless: rt2x00: rt2800usb more devices were identified commit e828b9fb4f6c3513950759d5fb902db5bd054048 upstream. found in 2012_03_22_RT5572_Linux_STA_v2.6.0.0_DPO RT3070: (0x2019,0x5201) Planex Communications, Inc. RT8070 (0x7392,0x4085) 2L Central Europe BV 8070 7392 is Edimax RT35xx: (0x1690,0x0761) Askey was Fujitsu Stylistic 550, but 1690 is Askey Signed-off-by: Xose Vazquez Perez Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800usb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 5851be71f3a..5601302d09a 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -992,6 +992,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* DVICO */ { USB_DEVICE(0x0fe9, 0xb307) }, /* Edimax */ + { USB_DEVICE(0x7392, 0x4085) }, { USB_DEVICE(0x7392, 0x7711) }, { USB_DEVICE(0x7392, 0x7717) }, { USB_DEVICE(0x7392, 0x7718) }, @@ -1067,6 +1068,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Philips */ { USB_DEVICE(0x0471, 0x200f) }, /* Planex */ + { USB_DEVICE(0x2019, 0x5201) }, { USB_DEVICE(0x2019, 0xab25) }, { USB_DEVICE(0x2019, 0xed06) }, /* Quanta */ @@ -1150,6 +1152,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x8516, 0x3572) }, /* Askey */ { USB_DEVICE(0x1690, 0x0744) }, + { USB_DEVICE(0x1690, 0x0761) }, { USB_DEVICE(0x1690, 0x0764) }, /* Cisco */ { USB_DEVICE(0x167b, 0x4001) }, @@ -1235,12 +1238,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c0b) }, { USB_DEVICE(0x07d1, 0x3c17) }, { USB_DEVICE(0x2001, 0x3c17) }, - /* Edimax */ - { USB_DEVICE(0x7392, 0x4085) }, /* Encore */ { USB_DEVICE(0x203d, 0x14a1) }, - /* Fujitsu Stylistic 550 */ - { USB_DEVICE(0x1690, 0x0761) }, /* Gemtek */ { USB_DEVICE(0x15a9, 0x0010) }, /* Gigabyte */ @@ -1261,7 +1260,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x05a6, 0x0101) }, { USB_DEVICE(0x1d4d, 0x0010) }, /* Planex */ - { USB_DEVICE(0x2019, 0x5201) }, { USB_DEVICE(0x2019, 0xab24) }, /* Qcom */ { USB_DEVICE(0x18e8, 0x6259) }, From a06d0d26d87cc397e11e75f6c1fc54d191bf60ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Tue, 5 Jun 2012 21:18:10 +0000 Subject: [PATCH 0204/2357] net: sierra_net: device IDs for Aircard 320U++ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit dd03cff23d694cfb0fdae80cb618e7ced05ea696 upstream. Adding device IDs for Aircard 320U and two other devices found in the out-of-tree version of this driver. Cc: linux@sierrawireless.com Cc: Autif Khan Cc: Tom Cassidy Signed-off-by: Bjørn Mork Acked-by: Greg Kroah-Hartman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/sierra_net.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index b59cf20c781..cc9776c2a39 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -946,7 +946,7 @@ struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb, } static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 }; -static const struct sierra_net_info_data sierra_net_info_data_68A3 = { +static const struct sierra_net_info_data sierra_net_info_data_direct_ip = { .rx_urb_size = 8 * 1024, .whitelist = { .infolen = ARRAY_SIZE(sierra_net_ifnum_list), @@ -954,7 +954,7 @@ static const struct sierra_net_info_data sierra_net_info_data_68A3 = { } }; -static const struct driver_info sierra_net_info_68A3 = { +static const struct driver_info sierra_net_info_direct_ip = { .description = "Sierra Wireless USB-to-WWAN Modem", .flags = FLAG_WWAN | FLAG_SEND_ZLP, .bind = sierra_net_bind, @@ -962,12 +962,18 @@ static const struct driver_info sierra_net_info_68A3 = { .status = sierra_net_status, .rx_fixup = sierra_net_rx_fixup, .tx_fixup = sierra_net_tx_fixup, - .data = (unsigned long)&sierra_net_info_data_68A3, + .data = (unsigned long)&sierra_net_info_data_direct_ip, }; static const struct usb_device_id products[] = { {USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */ - .driver_info = (unsigned long) &sierra_net_info_68A3}, + .driver_info = (unsigned long) &sierra_net_info_direct_ip}, + {USB_DEVICE(0x0F3D, 0x68A3), /* AT&T Direct IP modem */ + .driver_info = (unsigned long) &sierra_net_info_direct_ip}, + {USB_DEVICE(0x1199, 0x68AA), /* Sierra Wireless Direct IP LTE modem */ + .driver_info = (unsigned long) &sierra_net_info_direct_ip}, + {USB_DEVICE(0x0F3D, 0x68AA), /* AT&T Direct IP LTE modem */ + .driver_info = (unsigned long) &sierra_net_info_direct_ip}, {}, /* last item */ }; From f939c6c260e4fe2b2b5e9b2d0f9a5103e28d23d5 Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Wed, 23 May 2012 17:45:09 +0530 Subject: [PATCH 0205/2357] can: c_can: fix "BUG! echo_skb is occupied!" during transmit commit 617caccebe451716df21c069b079d5936ed7b0f3 upstream. This patch fixes an issue with transmit routine, which causes "can_put_echo_skb: BUG! echo_skb is occupied!" message when using "cansequence -p" on D_CAN controller. In c_can driver, while transmitting packets tx_echo flag holds the no of can frames put for transmission into the hardware. As the comment above c_can_do_tx() indicates, if we find any packet which is not transmitted then we should stop looking for more. In the current implementation this is not taken care of causing the said message. Also, fix the condition used to find if the packet is transmitted or not. Current code skips the first tx message object and ends up checking one extra invalid object. While at it, fix the comment on top of c_can_do_tx() to use the terminology "packet" instead of "package" since it is more standard. Signed-off-by: AnilKumar Ch Acked-by: Wolfgang Grandegger Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/c_can/c_can.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 536bda072a1..9ac28df3c89 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -686,7 +686,7 @@ static int c_can_get_berr_counter(const struct net_device *dev, * * We iterate from priv->tx_echo to priv->tx_next and check if the * packet has been transmitted, echo it back to the CAN framework. - * If we discover a not yet transmitted package, stop looking for more. + * If we discover a not yet transmitted packet, stop looking for more. */ static void c_can_do_tx(struct net_device *dev) { @@ -698,7 +698,7 @@ static void c_can_do_tx(struct net_device *dev) for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { msg_obj_no = get_tx_echo_msg_obj(priv); val = c_can_read_reg32(priv, &priv->regs->txrqst1); - if (!(val & (1 << msg_obj_no))) { + if (!(val & (1 << (msg_obj_no - 1)))) { can_get_echo_skb(dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST); stats->tx_bytes += priv->read_reg(priv, @@ -706,6 +706,8 @@ static void c_can_do_tx(struct net_device *dev) & IF_MCONT_DLC_MASK; stats->tx_packets++; c_can_inval_msg_object(dev, 0, msg_obj_no); + } else { + break; } } From 8414ac8c1e0ba119febfd2e46c24afda7768cee3 Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Wed, 23 May 2012 17:45:10 +0530 Subject: [PATCH 0206/2357] can: c_can: fix an interrupt thrash issue with c_can driver commit 148c87c89e1a8863d3d965179f3ab1a06490569e upstream. This patch fixes an interrupt thrash issue with c_can driver. In c_can_isr() function interrupts are disabled and enabled only in c_can_poll() function. c_can_isr() & c_can_poll() both read the irqstatus flag. However, irqstatus is always read as 0 in c_can_poll() because all C_CAN interrupts are disabled in c_can_isr(). This causes all interrupts to be re-enabled in c_can_poll() which in turn causes another interrupt since the event is not really handled. This keeps happening causing a flood of interrupts. To fix this, read the irqstatus register in isr and use the same cached value in the poll function. Signed-off-by: AnilKumar Ch Acked-by: Wolfgang Grandegger Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/c_can/c_can.c | 7 +++---- drivers/net/can/c_can/c_can.h | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 9ac28df3c89..fa016214c52 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -952,7 +952,7 @@ static int c_can_poll(struct napi_struct *napi, int quota) struct net_device *dev = napi->dev; struct c_can_priv *priv = netdev_priv(dev); - irqstatus = priv->read_reg(priv, &priv->regs->interrupt); + irqstatus = priv->irqstatus; if (!irqstatus) goto end; @@ -1030,12 +1030,11 @@ static int c_can_poll(struct napi_struct *napi, int quota) static irqreturn_t c_can_isr(int irq, void *dev_id) { - u16 irqstatus; struct net_device *dev = (struct net_device *)dev_id; struct c_can_priv *priv = netdev_priv(dev); - irqstatus = priv->read_reg(priv, &priv->regs->interrupt); - if (!irqstatus) + priv->irqstatus = priv->read_reg(priv, &priv->regs->interrupt); + if (!priv->irqstatus) return IRQ_NONE; /* disable all interrupts and schedule the NAPI */ diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h index 9b7fbef3d09..5f32d34af50 100644 --- a/drivers/net/can/c_can/c_can.h +++ b/drivers/net/can/c_can/c_can.h @@ -76,6 +76,7 @@ struct c_can_priv { unsigned int tx_next; unsigned int tx_echo; void *priv; /* for board-specific data */ + u16 irqstatus; }; struct net_device *alloc_c_can_dev(void); From d8bf1e7c7623585d4742d283c027b83f212477af Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Wed, 23 May 2012 17:45:11 +0530 Subject: [PATCH 0207/2357] can: c_can: fix race condition in c_can_open() commit f461f27a4436dbe691908fe08b867ef888848cc3 upstream. Fix the issue of C_CAN interrupts getting disabled forever when canconfig utility is used multiple times. According to NAPI usage we disable all the hardware interrupts in ISR and re-enable them in poll(). Current implementation calls napi_enable() after hardware interrupts are enabled. If we get any interrupts between these two steps then we do not process those interrupts because napi is not enabled. Mostly these interrupts come because of STATUS is not 0x7 or ERROR interrupts. If napi_enable() happens before HW interrupts enabled then c_can_poll() function will be called eventual re-enabling. This patch moves the napi_enable() call before interrupts enabled. Signed-off-by: AnilKumar Ch Acked-by: Wolfgang Grandegger Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/c_can/c_can.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index fa016214c52..8dc84d66eea 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -1064,10 +1064,11 @@ static int c_can_open(struct net_device *dev) goto exit_irq_fail; } + napi_enable(&priv->napi); + /* start the c_can controller */ c_can_start(dev); - napi_enable(&priv->napi); netif_start_queue(dev); return 0; From 5f68127d9cf4b358060ce5f9906246262a56f179 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 25 Apr 2012 14:34:04 +0100 Subject: [PATCH 0208/2357] gma500: don't register the ACPI video bus commit 155689defc782b486a7e6776a57ecc4ebb37ed52 upstream. We are not yet ready for this and it makes a mess on some devices. Signed-off-by: Alan Cox Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/gma500/psb_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index c34adf9d910..09af2ffbb30 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -349,7 +349,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) PSB_WSGX32(0x30000000, PSB_CR_BIF_3D_REQ_BASE); /* igd_opregion_init(&dev_priv->opregion_dev); */ - acpi_video_register(); +/* acpi_video_register(); */ if (dev_priv->lid_state) psb_lid_timer_init(dev_priv); From 3e2b0c74fa03b8788f8f7e9bcc778463e53c49a9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 25 Apr 2012 14:33:33 +0100 Subject: [PATCH 0209/2357] acpi_video: fix leaking PCI references commit cfb46f433a4da97c31780e08a259fac2cb6bd61f upstream. Signed-off-by: Alan Cox Acked-by: Matthew Garrett Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/video.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 9577b6fa265..66e8f7333e9 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1745,6 +1745,7 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) static int __init intel_opregion_present(void) { + int i915 = 0; #if defined(CONFIG_DRM_I915) || defined(CONFIG_DRM_I915_MODULE) struct pci_dev *dev = NULL; u32 address; @@ -1757,10 +1758,10 @@ static int __init intel_opregion_present(void) pci_read_config_dword(dev, 0xfc, &address); if (!address) continue; - return 1; + i915 = 1; } #endif - return 0; + return i915; } int acpi_video_register(void) From 8997b2223b9d81f6085764d08f9de3a2da760333 Mon Sep 17 00:00:00 2001 From: Dimitri Sivanich Date: Tue, 5 Jun 2012 13:44:36 -0500 Subject: [PATCH 0210/2357] sched: Fix the relax_domain_level boot parameter commit a841f8cef4bb124f0f5563314d0beaf2e1249d72 upstream. It does not get processed because sched_domain_level_max is 0 at the time that setup_relax_domain_level() is run. Simply accept the value as it is, as we don't know the value of sched_domain_level_max until sched domain construction is completed. Fix sched_relax_domain_level in cpuset. The build_sched_domain() routine calls the set_domain_attribute() routine prior to setting the sd->level, however, the set_domain_attribute() routine relies on the sd->level to decide whether idle load balancing will be off/on. Signed-off-by: Dimitri Sivanich Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20120605184436.GA15668@sgi.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/sched/core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index e5212ae294f..2000e069fc9 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -6230,11 +6230,8 @@ int sched_domain_level_max; static int __init setup_relax_domain_level(char *str) { - unsigned long val; - - val = simple_strtoul(str, NULL, 0); - if (val < sched_domain_level_max) - default_relax_domain_level = val; + if (kstrtoint(str, 0, &default_relax_domain_level)) + pr_warn("Unable to set relax_domain_level\n"); return 1; } @@ -6439,7 +6436,6 @@ struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, if (!sd) return child; - set_domain_attribute(sd, attr); cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu)); if (child) { sd->level = child->level + 1; @@ -6447,6 +6443,7 @@ struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, child->parent = sd; } sd->child = child; + set_domain_attribute(sd, attr); return sd; } From c1e23cbad36dfccd873b19944ebb2d1712a673a7 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sat, 9 Jun 2012 10:57:41 -0400 Subject: [PATCH 0211/2357] drm/radeon: fix tiling and command stream checking on evergreen v3 commit d26098759cf6d32148649c165f87a7590bc25b89 upstream. Fix regresson since the introduction of command stream checking on evergreen (thread referenced below). Issue is cause by ddx allocating bo with formula width*height*bpp while programming the GPU command stream with ALIGN(height, 8). In some case (where page alignment does not hide the extra size bo should be according to height alignment) the kernel will reject the command stream. This patch reprogram the command stream to slice - 1 (slice is a derivative value from height) which avoid rejecting the command stream while keeping the value of command stream checking from a security point of view. This patch also fix wrong computation of layer size for 2D tiled surface. Which should fix issue when 2D color tiling is enabled. This dump the radeon KMS_DRIVER_MINOR so userspace can know if they are on a fixed kernel or not. https://lkml.org/lkml/2012/6/3/80 https://bugs.freedesktop.org/show_bug.cgi?id=50892 https://bugs.freedesktop.org/show_bug.cgi?id=50857 !!! STABLE need a custom version of this patch for 3.4 !!! v2: actually bump the minor version and add comment about stable v3: do compute the height the ddx was trying to use [airlied: drop left over debug] Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen_cs.c | 49 ++++++++++++++++++++++++--- drivers/gpu/drm/radeon/radeon_drv.c | 3 +- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 70089d32b80..ea69daeffac 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -52,6 +52,7 @@ struct evergreen_cs_track { u32 cb_color_view[12]; u32 cb_color_pitch[12]; u32 cb_color_slice[12]; + u32 cb_color_slice_idx[12]; u32 cb_color_attrib[12]; u32 cb_color_cmask_slice[8];/* unused */ u32 cb_color_fmask_slice[8];/* unused */ @@ -127,12 +128,14 @@ static void evergreen_cs_track_init(struct evergreen_cs_track *track) track->cb_color_info[i] = 0; track->cb_color_view[i] = 0xFFFFFFFF; track->cb_color_pitch[i] = 0; - track->cb_color_slice[i] = 0; + track->cb_color_slice[i] = 0xfffffff; + track->cb_color_slice_idx[i] = 0; } track->cb_target_mask = 0xFFFFFFFF; track->cb_shader_mask = 0xFFFFFFFF; track->cb_dirty = true; + track->db_depth_slice = 0xffffffff; track->db_depth_view = 0xFFFFC000; track->db_depth_size = 0xFFFFFFFF; track->db_depth_control = 0xFFFFFFFF; @@ -250,10 +253,9 @@ static int evergreen_surface_check_2d(struct radeon_cs_parser *p, { struct evergreen_cs_track *track = p->track; unsigned palign, halign, tileb, slice_pt; + unsigned mtile_pr, mtile_ps, mtileb; tileb = 64 * surf->bpe * surf->nsamples; - palign = track->group_size / (8 * surf->bpe * surf->nsamples); - palign = MAX(8, palign); slice_pt = 1; if (tileb > surf->tsplit) { slice_pt = tileb / surf->tsplit; @@ -262,7 +264,10 @@ static int evergreen_surface_check_2d(struct radeon_cs_parser *p, /* macro tile width & height */ palign = (8 * surf->bankw * track->npipes) * surf->mtilea; halign = (8 * surf->bankh * surf->nbanks) / surf->mtilea; - surf->layer_size = surf->nbx * surf->nby * surf->bpe * slice_pt; + mtileb = (palign / 8) * (halign / 8) * tileb;; + mtile_pr = surf->nbx / palign; + mtile_ps = (mtile_pr * surf->nby) / halign; + surf->layer_size = mtile_ps * mtileb * slice_pt; surf->base_align = (palign / 8) * (halign / 8) * tileb; surf->palign = palign; surf->halign = halign; @@ -434,6 +439,39 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i offset += surf.layer_size * mslice; if (offset > radeon_bo_size(track->cb_color_bo[id])) { + /* old ddx are broken they allocate bo with w*h*bpp but + * program slice with ALIGN(h, 8), catch this and patch + * command stream. + */ + if (!surf.mode) { + volatile u32 *ib = p->ib->ptr; + unsigned long tmp, nby, bsize, size, min = 0; + + /* find the height the ddx wants */ + if (surf.nby > 8) { + min = surf.nby - 8; + } + bsize = radeon_bo_size(track->cb_color_bo[id]); + tmp = track->cb_color_bo_offset[id] << 8; + for (nby = surf.nby; nby > min; nby--) { + size = nby * surf.nbx * surf.bpe * surf.nsamples; + if ((tmp + size * mslice) <= bsize) { + break; + } + } + if (nby > min) { + surf.nby = nby; + slice = ((nby * surf.nbx) / 64) - 1; + if (!evergreen_surface_check(p, &surf, "cb")) { + /* check if this one works */ + tmp += surf.layer_size * mslice; + if (tmp <= bsize) { + ib[track->cb_color_slice_idx[id]] = slice; + goto old_ddx_ok; + } + } + } + } dev_warn(p->dev, "%s:%d cb[%d] bo too small (layer size %d, " "offset %d, max layer %d, bo size %ld, slice %d)\n", __func__, __LINE__, id, surf.layer_size, @@ -446,6 +484,7 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i surf.tsplit, surf.mtilea); return -EINVAL; } +old_ddx_ok: return 0; } @@ -1532,6 +1571,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) case CB_COLOR7_SLICE: tmp = (reg - CB_COLOR0_SLICE) / 0x3c; track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_slice_idx[tmp] = idx; track->cb_dirty = true; break; case CB_COLOR8_SLICE: @@ -1540,6 +1580,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) case CB_COLOR11_SLICE: tmp = ((reg - CB_COLOR8_SLICE) / 0x1c) + 8; track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_slice_idx[tmp] = idx; track->cb_dirty = true; break; case CB_COLOR0_ATTRIB: diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index ef7bb3f6eca..15250fbee7d 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -57,9 +57,10 @@ * 2.13.0 - virtual memory support, streamout * 2.14.0 - add evergreen tiling informations * 2.15.0 - add max_pipes query + * 2.16.0 - fix evergreen 2D tiled surface calculation */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 15 +#define KMS_DRIVER_MINOR 16 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); From d5b9a38383178758ddf671b7a5551afab4e504b2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Jun 2012 17:05:40 +0100 Subject: [PATCH 0212/2357] drm/i915: Mark the ringbuffers as being in the GTT domain commit 3eef8918ff440837f6af791942d8dd07e1a268ee upstream. By correctly describing the rinbuffers as being in the GTT domain, it appears that we are more careful with the management of the CPU cache upon resume and so prevent some coherency issue when submitting commands to the GPU later. A secondary effect is that the debug logs are then consistent with the actual usage (i.e. they no longer describe the ringbuffers as being in the CPU write domain when we are accessing them through an wc iomapping.) Reported-and-tested-by: Daniel Gnoutcheff Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41092 Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e0ecef68c39..302d3d54fb4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1027,6 +1027,10 @@ int intel_init_ring_buffer(struct drm_device *dev, if (ret) goto err_unref; + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) + goto err_unpin; + ring->map.size = ring->size; ring->map.offset = dev->agp->base + obj->gtt_offset; ring->map.type = 0; From 9abcb7517f13aa54152bee6370538b8f56893349 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 10 May 2012 19:49:38 +0400 Subject: [PATCH 0213/2357] fuse: fix stat call on 32 bit platforms commit 45c72cd73c788dd18c8113d4a404d6b4a01decf1 upstream. Now we store attr->ino at inode->i_ino, return attr->ino at the first time and then return inode->i_ino if the attribute timeout isn't expired. That's wrong on 32 bit platforms because attr->ino is 64 bit and inode->i_ino is 32 bit in this case. Fix this by saving 64 bit ino in fuse_inode structure and returning it every time we call getattr. Also squash attr->ino into inode->i_ino explicitly. Signed-off-by: Pavel Shilovsky Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/dir.c | 1 + fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index df5ac048dc7..bc438320cac 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -863,6 +863,7 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat, if (stat) { generic_fillattr(inode, stat); stat->mode = fi->orig_i_mode; + stat->ino = fi->orig_ino; } } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 572cefc7801..d1819269aab 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -82,6 +82,9 @@ struct fuse_inode { preserve the original mode */ umode_t orig_i_mode; + /** 64 bit inode number */ + u64 orig_ino; + /** Version of last attribute change */ u64 attr_version; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 26783eb2b1f..a59cf5e673d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -91,6 +91,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) fi->nlookup = 0; fi->attr_version = 0; fi->writectr = 0; + fi->orig_ino = 0; INIT_LIST_HEAD(&fi->write_files); INIT_LIST_HEAD(&fi->queued_writes); INIT_LIST_HEAD(&fi->writepages); @@ -139,6 +140,18 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) return 0; } +/* + * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down + * so that it will fit. + */ +static ino_t fuse_squash_ino(u64 ino64) +{ + ino_t ino = (ino_t) ino64; + if (sizeof(ino_t) < sizeof(u64)) + ino ^= ino64 >> (sizeof(u64) - sizeof(ino_t)) * 8; + return ino; +} + void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, u64 attr_valid) { @@ -148,7 +161,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, fi->attr_version = ++fc->attr_version; fi->i_time = attr_valid; - inode->i_ino = attr->ino; + inode->i_ino = fuse_squash_ino(attr->ino); inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); set_nlink(inode, attr->nlink); inode->i_uid = attr->uid; @@ -174,6 +187,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, fi->orig_i_mode = inode->i_mode; if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) inode->i_mode &= ~S_ISVTX; + + fi->orig_ino = attr->ino; } void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, From 54a40b2cf40d655dbbdcc017288be75b1ae1b701 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Fri, 4 May 2012 22:15:10 +0100 Subject: [PATCH 0214/2357] libata: add a host flag to ignore detected ATA devices commit db63a4c8115a0bb904496e1cdd3e7488e68b0d06 upstream. Where devices are visible via more than one host we sometimes wish to indicate that cirtain devices should be ignored on a specific host. Add a host flag indicating that this host wishes to ignore ATA specific devices. Signed-off-by: Andy Whitcroft Signed-off-by: Jeff Garzik Cc: Victor Miasnikov Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 6 ++++++ include/linux/libata.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 23763a1ec57..d31ee557b39 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1973,6 +1973,12 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, if (class == ATA_DEV_ATA) { if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) goto err_out; + if (ap->host->flags & ATA_HOST_IGNORE_ATA && + ata_id_is_ata(id)) { + ata_dev_dbg(dev, + "host indicates ignore ATA devices, ignored\n"); + return -ENOENT; + } } else { if (ata_id_is_ata(id)) goto err_out; diff --git a/include/linux/libata.h b/include/linux/libata.h index e926df7b54c..6e887c742a2 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -247,6 +247,7 @@ enum { ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */ ATA_HOST_STARTED = (1 << 1), /* Host started */ ATA_HOST_PARALLEL_SCAN = (1 << 2), /* Ports on this host can be scanned in parallel */ + ATA_HOST_IGNORE_ATA = (1 << 3), /* Ignore ATA devices on this host. */ /* bits 24:31 of host->flags are reserved for LLD specific flags */ From 0d48d35de9b7dbe7e68d2a741c2f8d6a9e2eed3f Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Fri, 4 May 2012 22:15:11 +0100 Subject: [PATCH 0215/2357] ata_piix: defer disks to the Hyper-V drivers by default commit cd006086fa5d91414d8ff9ff2b78fbb593878e3c upstream. When we are hosted on a Microsoft Hyper-V hypervisor the guest disks are exposed both via the Hyper-V paravirtualised drivers and via an emulated SATA disk drive. In this case we want to use the paravirtualised drivers if we can as they are much more efficient. Note that the Hyper-V paravirtualised drivers only expose the virtual hard disk devices, the CDROM/DVD devices must still be enumerated. Mark the host controller ATA_HOST_IGNORE_ATA to prevent enumeration of disk devices. BugLink: http://bugs.launchpad.net/bugs/929545 BugLink: http://bugs.launchpad.net/bugs/942316 Signed-off-by: Andy Whitcroft Signed-off-by: Jeff Garzik Cc: Victor Miasnikov Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ata_piix.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 7857e8fd0a3..3c809bfbccf 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -1554,6 +1554,39 @@ static bool piix_broken_system_poweroff(struct pci_dev *pdev) return false; } +static int prefer_ms_hyperv = 1; +module_param(prefer_ms_hyperv, int, 0); + +static void piix_ignore_devices_quirk(struct ata_host *host) +{ +#if IS_ENABLED(CONFIG_HYPERV_STORAGE) + static const struct dmi_system_id ignore_hyperv[] = { + { + /* On Hyper-V hypervisors the disks are exposed on + * both the emulated SATA controller and on the + * paravirtualised drivers. The CD/DVD devices + * are only exposed on the emulated controller. + * Request we ignore ATA devices on this host. + */ + .ident = "Hyper-V Virtual Machine", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), + }, + }, + { } /* terminate list */ + }; + const struct dmi_system_id *dmi = dmi_first_match(ignore_hyperv); + + if (dmi && prefer_ms_hyperv) { + host->flags |= ATA_HOST_IGNORE_ATA; + dev_info(host->dev, "%s detected, ATA device ignore set\n", + dmi->ident); + } +#endif +} + /** * piix_init_one - Register PIIX ATA PCI device with kernel services * @pdev: PCI device to register @@ -1669,6 +1702,9 @@ static int __devinit piix_init_one(struct pci_dev *pdev, } host->flags |= ATA_HOST_PARALLEL_SCAN; + /* Allow hosts to specify device types to ignore when scanning. */ + piix_ignore_devices_quirk(host); + pci_set_master(pdev); return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht); } From a694d36e943f3fff08e19d942d4db819c94401c1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 17 Jun 2012 11:21:44 -0700 Subject: [PATCH 0216/2357] Linux 3.4.3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 901a95571ea..a0804c6de69 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 2 +SUBLEVEL = 3 EXTRAVERSION = NAME = Saber-toothed Squirrel From 8bca81891d1b2a8849bbfb54dcd0ac74ce5de85f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 4 Jun 2012 14:58:07 +0200 Subject: [PATCH 0217/2357] ARM i.MX53: Fix PLL4 base address commit cdd781ab1906d039c2a93078385645d2d5af8491 upstream. MX53_DPLL4_BASE accidently returned the base address of PLL3. Fix this. Signed-off-by: Sascha Hauer Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-imx/crm-regs-imx5.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/crm-regs-imx5.h b/arch/arm/mach-imx/crm-regs-imx5.h index 5e11ba7daee..5e3f1f0f4ca 100644 --- a/arch/arm/mach-imx/crm-regs-imx5.h +++ b/arch/arm/mach-imx/crm-regs-imx5.h @@ -23,7 +23,7 @@ #define MX53_DPLL1_BASE MX53_IO_ADDRESS(MX53_PLL1_BASE_ADDR) #define MX53_DPLL2_BASE MX53_IO_ADDRESS(MX53_PLL2_BASE_ADDR) #define MX53_DPLL3_BASE MX53_IO_ADDRESS(MX53_PLL3_BASE_ADDR) -#define MX53_DPLL4_BASE MX53_IO_ADDRESS(MX53_PLL3_BASE_ADDR) +#define MX53_DPLL4_BASE MX53_IO_ADDRESS(MX53_PLL4_BASE_ADDR) /* PLL Register Offsets */ #define MXC_PLL_DP_CTL 0x00 From 9ffa519e1b6c7db54ce371a809dd45584aff42bf Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 22 May 2012 22:13:46 +0800 Subject: [PATCH 0218/2357] ARM: imx6: exit coherency when shutting down a cpu commit 602bf40971d7f9a1ec0b7ba2b7e6427849828651 upstream. There is a system hang issue on imx6q which can easily be seen with running a cpu hotplug stress testing (hotplug secondary cores from user space via sysfs interface for thousands iterations). It turns out that the issue is caused by coherency of the cpu that is being shut down. When shutting down a cpu, we need to have the cpu exit coherency to prevent it from receiving cache, TLB, or BTB maintenance operations broadcast by other CPUs in the cluster. Copy cpu_enter_lowpower() and cpu_leave_lowpower() from mach-vexpress to have coherency properly handled in platform_cpu_die(), thus fix the issue. Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-imx/hotplug.c | 42 ++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index 89493abd497..20ed2d56c1a 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -12,6 +12,7 @@ #include #include +#include #include int platform_cpu_kill(unsigned int cpu) @@ -19,6 +20,44 @@ int platform_cpu_kill(unsigned int cpu) return 1; } +static inline void cpu_enter_lowpower(void) +{ + unsigned int v; + + flush_cache_all(); + asm volatile( + "mcr p15, 0, %1, c7, c5, 0\n" + " mcr p15, 0, %1, c7, c10, 4\n" + /* + * Turn off coherency + */ + " mrc p15, 0, %0, c1, c0, 1\n" + " bic %0, %0, %3\n" + " mcr p15, 0, %0, c1, c0, 1\n" + " mrc p15, 0, %0, c1, c0, 0\n" + " bic %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 0\n" + : "=&r" (v) + : "r" (0), "Ir" (CR_C), "Ir" (0x40) + : "cc"); +} + +static inline void cpu_leave_lowpower(void) +{ + unsigned int v; + + asm volatile( + "mrc p15, 0, %0, c1, c0, 0\n" + " orr %0, %0, %1\n" + " mcr p15, 0, %0, c1, c0, 0\n" + " mrc p15, 0, %0, c1, c0, 1\n" + " orr %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 1\n" + : "=&r" (v) + : "Ir" (CR_C), "Ir" (0x40) + : "cc"); +} + /* * platform-specific code to shutdown a CPU * @@ -26,9 +65,10 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { - flush_cache_all(); + cpu_enter_lowpower(); imx_enable_cpu(cpu, false); cpu_do_idle(); + cpu_leave_lowpower(); /* We should never return from idle */ panic("cpu %d unexpectedly exit from shutdown\n", cpu); From 688b04fe535dafad0849c1980361d9f2a1596a7e Mon Sep 17 00:00:00 2001 From: Jaccon Bastiaansen Date: Mon, 30 Apr 2012 11:53:43 +0200 Subject: [PATCH 0219/2357] ARM i.MX imx21ads: Fix overlapping static i/o mappings commit 350ab15bb2ffe7103bc6bf6c634f3c5b286eaf2a upstream. The statically defined I/O memory regions for the i.MX21 on chip peripherals and the on board I/O peripherals of the i.MX21ADS board overlap. This results in a kernel crash during startup. This is fixed by reducing the memory range for the on board I/O peripherals to the actually required range. Signed-off-by: Jaccon Bastiaansen Signed-off-by: Sascha Hauer Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-imx/mach-mx21ads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c index e432d4acee1..4460d25faae 100644 --- a/arch/arm/mach-imx/mach-mx21ads.c +++ b/arch/arm/mach-imx/mach-mx21ads.c @@ -32,7 +32,7 @@ * Memory-mapped I/O on MX21ADS base board */ #define MX21ADS_MMIO_BASE_ADDR 0xf5000000 -#define MX21ADS_MMIO_SIZE SZ_16M +#define MX21ADS_MMIO_SIZE 0xc00000 #define MX21ADS_REG_ADDR(offset) (void __force __iomem *) \ (MX21ADS_MMIO_BASE_ADDR + (offset)) From 2a82d9e11ab5f467e0faa2253204c75de675b037 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 14 Jun 2012 22:15:00 +0200 Subject: [PATCH 0220/2357] Revert "drm/i915/dp: Use auxch precharge value of 5 everywhere" commit 6b4e0a93ff6e45714c72bdce193f719ed94810e3 upstream. This reverts commit 092945e11c5b84f66dd08f0b87fb729715d377bc. This commit prevents a DP screen from properly training the link. Oddly enough it works, once the machine has been warm-booted with an older kernel. According to DP docs this _should_ have been the right precharge time. Also, the commit that originally introduces this was just general snb DP enabling and didn't mention any specific reason for this special value. Whatever, trust the reporter that this makes things worse and let's just revert it. v2: Less spelling fail. Reviewed-by: Adam Jackson Cc: Jesse Barnes Reported-by: "Wouter M. Koolen" Buglink: https://lkml.org/lkml/2012/6/14/301 Signed-Off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_dp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1d19408192b..68624218d05 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -368,7 +368,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, int recv_bytes; uint32_t status; uint32_t aux_clock_divider; - int try, precharge = 5; + int try, precharge; intel_dp_check_edp(intel_dp); /* The clock divider is based off the hrawclk, @@ -388,6 +388,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, else aux_clock_divider = intel_hrawclk(dev) / 2; + if (IS_GEN6(dev)) + precharge = 3; + else + precharge = 5; + /* Try to wait for any previous AUX channel activity */ for (try = 0; try < 3; try++) { status = I915_READ(ch_ctl); From 789ed2afd385af95798c6ec419ad41f8801975a4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 14 Jun 2012 22:06:36 +0200 Subject: [PATCH 0221/2357] drm/radeon: add some additional 6xx/7xx/EG register init commit b866d1334ba2d544bc575d75357dea6bdcdc7f46 upstream. - SMX_SAR_CTL0 needs to be programmed correctly to prevent problems with memory exports in certain cases. - VC_ENHANCE needs to be initialized on 6xx/7xx. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 3 +++ drivers/gpu/drm/radeon/evergreend.h | 1 + drivers/gpu/drm/radeon/r600.c | 1 + drivers/gpu/drm/radeon/r600d.h | 1 + drivers/gpu/drm/radeon/rv770.c | 5 ++++- drivers/gpu/drm/radeon/rv770d.h | 3 +++ 6 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 51e8d086767..e72c03ff595 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2210,6 +2210,9 @@ static void evergreen_gpu_init(struct radeon_device *rdev) smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.evergreen.sx_num_of_sets); WREG32(SMX_DC_CTL0, smx_dc_ctl0); + if (rdev->family <= CHIP_SUMO2) + WREG32(SMX_SAR_CTL0, 0x00010000); + WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_size / 4) - 1) | POSITION_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_pos_size / 4) - 1) | SMX_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_smx_size / 4) - 1))); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index a5b88aad834..f62ccd3555d 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -273,6 +273,7 @@ #define SCRATCH_UMSK 0x8540 #define SCRATCH_ADDR 0x8544 +#define SMX_SAR_CTL0 0xA008 #define SMX_DC_CTL0 0xA020 #define USE_HASH_FUNCTION (1 << 0) #define NUMBER_OF_SETS(x) ((x) << 1) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c8187c4b6ae..b1ff9ccd2d6 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1906,6 +1906,7 @@ void r600_gpu_init(struct radeon_device *rdev) WREG32(PA_CL_ENHANCE, (CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3))); WREG32(PA_SC_ENHANCE, FORCE_EOV_MAX_CLK_CNT(4095)); + WREG32(VC_ENHANCE, 0); } diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 59f9c993cc3..12ceb829a03 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -483,6 +483,7 @@ #define TC_L2_SIZE(x) ((x)<<5) #define L2_DISABLE_LATE_HIT (1<<9) +#define VC_ENHANCE 0x9714 #define VGT_CACHE_INVALIDATION 0x88C4 #define CACHE_INVALIDATION(x) ((x)<<0) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 80a292bc457..591040b9466 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -782,6 +782,9 @@ static void rv770_gpu_init(struct radeon_device *rdev) ACK_FLUSH_CTL(3) | SYNC_FLUSH_CTL)); + if (rdev->family != CHIP_RV770) + WREG32(SMX_SAR_CTL0, 0x00003f3f); + db_debug3 = RREG32(DB_DEBUG3); db_debug3 &= ~DB_CLK_OFF_DELAY(0x1f); switch (rdev->family) { @@ -960,7 +963,7 @@ static void rv770_gpu_init(struct radeon_device *rdev) WREG32(PA_CL_ENHANCE, (CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3))); - + WREG32(VC_ENHANCE, 0); } void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 75380927e9c..7095a713ad8 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -208,6 +208,7 @@ #define SCRATCH_UMSK 0x8540 #define SCRATCH_ADDR 0x8544 +#define SMX_SAR_CTL0 0xA008 #define SMX_DC_CTL0 0xA020 #define USE_HASH_FUNCTION (1 << 0) #define CACHE_DEPTH(x) ((x) << 1) @@ -307,6 +308,8 @@ #define TCP_CNTL 0x9610 #define TCP_CHAN_STEER 0x9614 +#define VC_ENHANCE 0x9714 + #define VGT_CACHE_INVALIDATION 0x88C4 #define CACHE_INVALIDATION(x) ((x)<<0) #define VC_ONLY 0 From eda8cc4ce07d538bb4170330e53ae52c5f637be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 10 Jun 2012 23:39:55 +0200 Subject: [PATCH 0222/2357] drm via: initialize object_idr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ce020ea53264f1460ae619cfc12f968dbd0b8974 upstream. The field obejct_idr of struct drm_via_private was introduced with the commit http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=77ee8f3825054f23b17e9c8f728f061defd86cdc . In that patch idr_init(&dev->object_name_idr) was called instead of idr_init(&dev_priv->object_idr) by mistake, leaving the dev_priv->object_idr uninitialized. To be more exact, the object_idr buffer is filled with zeros because of kzalloc(), but the dev_priv->object_idr.lock spinlock can cause system freeze at lib/idr.c:move_to_free_list() when spin_lock_irqsave() is called on this spinlock. The patch was tested on Clevo D4J, model D410J laptop, on the following hardware, without AGP kernel module loaded: # lspci -s 01:00.0 -n 01:00.0 0300: 1106:3108 (rev 01) # lspci -s 01:00.0 -v 01:00.0 VGA compatible controller: VIA Technologies, Inc. K8M800/K8N800/K8N800A [S3 UniChrome Pro] (rev 01) (prog-if 00 [VGA controller]) Subsystem: CLEVO/KAPOK Computer Device 4702 Flags: bus master, 66MHz, medium devsel, latency 64, IRQ 16 Memory at f0000000 (32-bit, prefetchable) [size=64M] Memory at d1000000 (32-bit, non-prefetchable) [size=16M] Expansion ROM at [disabled] Capabilities: [60] Power Management version 2 Capabilities: [70] AGP version 3.0 Signed-off-by: Márton Németh Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/via/via_map.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/via/via_map.c b/drivers/gpu/drm/via/via_map.c index 1f182254e81..c126182ac07 100644 --- a/drivers/gpu/drm/via/via_map.c +++ b/drivers/gpu/drm/via/via_map.c @@ -100,12 +100,11 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset) if (dev_priv == NULL) return -ENOMEM; + idr_init(&dev_priv->object_idr); dev->dev_private = (void *)dev_priv; dev_priv->chipset = chipset; - idr_init(&dev->object_name_idr); - pci_set_master(dev->pdev); ret = drm_vblank_init(dev, 1); From 8d96bccced28ba3c12ffb923aa264aa6b0d604a1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 16 Jun 2012 07:41:28 +0100 Subject: [PATCH 0223/2357] drm/udl: only bind to the video devices on the hub. commit e5a867a51d9b009f90d5dca6a320608e4e8a37ec upstream. This is ported from udlfb. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=832188 Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_drv.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index 53673907a6a..08eff0dbb80 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -13,8 +13,21 @@ static struct drm_driver driver; +/* + * There are many DisplayLink-based graphics products, all with unique PIDs. + * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff) + * We also require a match on SubClass (0x00) and Protocol (0x00), + * which is compatible with all known USB 2.0 era graphics chips and firmware, + * but allows DisplayLink to increment those for any future incompatible chips + */ static struct usb_device_id id_table[] = { - {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,}, + {.idVendor = 0x17e9, .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0x00, + .bInterfaceProtocol = 0x00, + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS | + USB_DEVICE_ID_MATCH_INT_PROTOCOL,}, {}, }; MODULE_DEVICE_TABLE(usb, id_table); From ebbd13c9d27ab013fdf7005829a80d504b0cb32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Mon, 11 Jun 2012 19:09:25 +0200 Subject: [PATCH 0224/2357] drm sis: initialize object_idr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 648ccc7d35e3416fdc739d2e520e85de3125361b upstream. The filed object_idr of struct drm_sis_private was introduced with commit http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=6de8a748881f1cd9d795454da2b6db616d5ca3d7 . The idr_init(&dev->object_name_idr) is called instead of idr_init(&dev_priv->object_idr) by mistake, leaving object_idr uninitialized. Correct this. This patch was not tested because of lack of hardware. Signed-off-by: Márton Németh Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/sis/sis_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index 30d98d14b5c..dd14cd1a003 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -47,9 +47,9 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset) if (dev_priv == NULL) return -ENOMEM; + idr_init(&dev_priv->object_idr); dev->dev_private = (void *)dev_priv; dev_priv->chipset = chipset; - idr_init(&dev->object_name_idr); return 0; } From 6a07cbc4ef9cea9f9eabc676fd6b8c03c11f51cc Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 23 May 2012 12:53:11 -0400 Subject: [PATCH 0225/2357] xen/hvc: Collapse error logic. commit 2e5ad6b9c45d43cc4e7b8ac5ded1c55a7c4a3893 upstream. All of the error paths are doing the same logic. In which case we might as well collapse them in one path. Acked-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_xen.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index d3d91dae065..afc7fc27aa5 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -216,22 +216,16 @@ static int xen_hvm_console_init(void) return 0; r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); - if (r < 0) { - kfree(info); - return -ENODEV; - } + if (r < 0) + goto err; info->evtchn = v; hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); - if (r < 0) { - kfree(info); - return -ENODEV; - } + if (r < 0) + goto err; mfn = v; info->intf = ioremap(mfn << PAGE_SHIFT, PAGE_SIZE); - if (info->intf == NULL) { - kfree(info); - return -ENODEV; - } + if (info->intf == NULL) + goto err; info->vtermno = HVC_COOKIE; spin_lock(&xencons_lock); @@ -239,6 +233,9 @@ static int xen_hvm_console_init(void) spin_unlock(&xencons_lock); return 0; +err: + kfree(info); + return -ENODEV; } static int xen_pv_console_init(void) From 85fc3e3eba89272acb005f320ccafa0588a48f49 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 23 May 2012 12:55:38 -0400 Subject: [PATCH 0226/2357] xen/hvc: Fix error cases around HVM_PARAM_CONSOLE_PFN commit a32c88b9386ce3df87f28dd46bdc3776cd6edf75 upstream. We weren't resetting the parameter to be passed in to a known default. Nor were we checking the return value of hvm_get_parameter. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_xen.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index afc7fc27aa5..3277f0eec4a 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -219,7 +219,8 @@ static int xen_hvm_console_init(void) if (r < 0) goto err; info->evtchn = v; - hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); + v = 0; + r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); if (r < 0) goto err; mfn = v; From 2da19ffd395d0fdba4ccbc4a3c751554059d4aa3 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 23 May 2012 12:56:59 -0400 Subject: [PATCH 0227/2357] xen/hvc: Check HVM_PARAM_CONSOLE_[EVTCHN|PFN] for correctness. commit 5842f5768599094758931b74190cdf93641a8e35 upstream. We need to make sure that those parameters are setup to be correct. As such the value of 0 is deemed invalid and we find that we bail out. The hypervisor sets by default all of them to be zero and when the hypercall is done does a simple: a.value = d->arch.hvm_domain.params[a.index]; Which means that if the Xen toolstack forgot to setup the proper HVM_PARAM_CONSOLE_EVTCHN (or the PFN one), we would get the default value of 0 and use that. Fixes-Oracle-Bug: 14091238 Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_xen.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 3277f0eec4a..944eaeb8e0c 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -214,14 +214,19 @@ static int xen_hvm_console_init(void) /* already configured */ if (info->intf != NULL) return 0; - + /* + * If the toolstack (or the hypervisor) hasn't set these values, the + * default value is 0. Even though mfn = 0 and evtchn = 0 are + * theoretically correct values, in practice they never are and they + * mean that a legacy toolstack hasn't initialized the pv console correctly. + */ r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); - if (r < 0) + if (r < 0 || v == 0) goto err; info->evtchn = v; v = 0; r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); - if (r < 0) + if (r < 0 || v == 0) goto err; mfn = v; info->intf = ioremap(mfn << PAGE_SHIFT, PAGE_SIZE); From c7aa88da6b435fb45b01fe6076caf73ee6e529ae Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 29 May 2012 13:07:31 +0200 Subject: [PATCH 0228/2357] xen/setup: filter APERFMPERF cpuid feature out commit 5e626254206a709c6e937f3dda69bf26c7344f6f upstream. Xen PV kernels allow access to the APERF/MPERF registers to read the effective frequency. Access to the MSRs is however redirected to the currently scheduled physical CPU, making consecutive read and compares unreliable. In addition each rdmsr traps into the hypervisor. So to avoid bogus readouts and expensive traps, disable the kernel internal feature flag for APERF/MPERF if running under Xen. This will a) remove the aperfmperf flag from /proc/cpuinfo b) not mislead the power scheduler (arch/x86/kernel/cpu/sched.c) to use the feature to improve scheduling (by default disabled) c) not mislead the cpufreq driver to use the MSRs This does not cover userland programs which access the MSRs via the device file interface, but this will be addressed separately. Signed-off-by: Andre Przywara Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/enlighten.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 6c7f1e8a312..40edfc37a6f 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -207,6 +207,9 @@ static void __init xen_banner(void) xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : ""); } +#define CPUID_THERM_POWER_LEAF 6 +#define APERFMPERF_PRESENT 0 + static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0; static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0; @@ -240,6 +243,11 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx, *dx = cpuid_leaf5_edx_val; return; + case CPUID_THERM_POWER_LEAF: + /* Disabling APERFMPERF for kernel usage */ + maskecx = ~(1 << APERFMPERF_PRESENT); + break; + case 0xb: /* Suppress extended topology stuff */ maskebx = 0; From 5f1d81e9fb6c05e8ab89a610bb63cdc8f0f66d81 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 31 May 2012 15:26:38 -0400 Subject: [PATCH 0229/2357] NFSv4.1: Fix a request leak on the back channel commit b3b02ae5865c2dcd506322e0fc6def59a042e72f upstream. If the call to svc_process_common() fails, then the request needs to be freed before we can exit bc_svc_process. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/svc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 4153846984a..234ee39000a 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1379,7 +1379,8 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, sizeof(req->rq_snd_buf)); return bc_send(req); } else { - /* Nothing to do to drop request */ + /* drop request */ + xprt_free_bc_request(req); return 0; } } From 5e74cfe1feb56745cecce815adf6fd2c7dfb6a58 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 8 Jun 2012 10:58:09 -0400 Subject: [PATCH 0230/2357] NFSv4: Fix unnecessary delegation returns in nfs4_do_open commit 2d0dbc6ae8a5194aaecb9cfffb9053f38fce8b86 upstream. While nfs4_do_open() expects the fmode argument to be restricted to combinations of FMODE_READ and FMODE_WRITE, both nfs4_atomic_open() and nfs4_proc_create will pass the nfs_open_context->mode, which contains the full fmode_t. This patch ensures that nfs4_do_open strips the other fmode_t bits, fixing a problem in which the nfs4_do_open call would result in an unnecessary delegation return. Reported-by: Fred Isaman Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e9b1eb701a0..d60c2d870ab 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1861,6 +1861,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, struct nfs4_state *res; int status; + fmode &= FMODE_READ|FMODE_WRITE; do { status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, &res); if (status == 0) From d946d96cd89b13fc354b6f7ed2c4de3e72c87d8e Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 12 Jun 2012 08:28:48 -0400 Subject: [PATCH 0231/2357] nfsd4: BUG_ON(!is_spin_locked()) no good on UP kernels commit bc2df47a408f2d64cf81bcfd0f6e3e14c84cb0ab upstream. Most frequent symptom was a BUG triggering in expire_client, with the server locking up shortly thereafter. Introduced by 508dc6e110c6dbdc0bbe84298ccfe22de7538486 "nfsd41: free_session/free_client must be called under the client_lock". Cc: Benny Halevy Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7f71c69cdcd..e79c24e232f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -862,7 +862,7 @@ static void free_session(struct kref *kref) struct nfsd4_session *ses; int mem; - BUG_ON(!spin_is_locked(&client_lock)); + lockdep_assert_held(&client_lock); ses = container_of(kref, struct nfsd4_session, se_ref); nfsd4_del_conns(ses); spin_lock(&nfsd_drc_lock); @@ -1041,7 +1041,7 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) static inline void free_client(struct nfs4_client *clp) { - BUG_ON(!spin_is_locked(&client_lock)); + lockdep_assert_held(&client_lock); while (!list_empty(&clp->cl_sessions)) { struct nfsd4_session *ses; ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, From 3993b24649773080897fde524ea2d9f311eba2aa Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 6 Jun 2012 19:50:40 -0400 Subject: [PATCH 0232/2357] tracing: Have tracing_off() actually turn tracing off commit f2bf1f6f5f89d031245067512449fc889b2f4bb2 upstream. A recent update to have tracing_on/off() only affect the ftrace ring buffers instead of all ring buffers had a cut and paste error. The tracing_off() did the exact same thing as tracing_on() and would not actually turn off tracing. Unfortunately, tracing_off() is more important to be working than tracing_on() as this is a key development tool, as it lets the developer turn off tracing as soon as a problem is discovered. It is also used by panic and oops code. This bug also breaks the 'echo func:traceoff > set_ftrace_filter' Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 2a22255c101..464a96f3d4c 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -383,7 +383,7 @@ EXPORT_SYMBOL_GPL(tracing_on); void tracing_off(void) { if (global_trace.buffer) - ring_buffer_record_on(global_trace.buffer); + ring_buffer_record_off(global_trace.buffer); /* * This flag is only looked at when buffers haven't been * allocated yet. We don't really care about the race From b7013d0a16b881481dc25ba4d42c5203bebe5ff1 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 11 Jun 2012 10:03:42 -0400 Subject: [PATCH 0233/2357] rpc_pipefs: allow rpc_purge_list to take a NULL waitq pointer commit 92123e068efa310b09e9943ac1cfd10ff6b6d2e4 upstream. In the event that we don't have a dentry for a rpc_pipefs pipe, we still need to allow the queue_timeout job to clean out the queue. There's just no waitq to wake up in that event. Reported-by: Hans de Bruin Reported-by: Joerg Platte Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/rpc_pipe.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 3b62cf28803..faa078f74b2 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -71,7 +71,9 @@ static void rpc_purge_list(wait_queue_head_t *waitq, struct list_head *head, msg->errno = err; destroy_msg(msg); } while (!list_empty(head)); - wake_up(waitq); + + if (waitq) + wake_up(waitq); } static void @@ -91,11 +93,9 @@ rpc_timeout_upcall_queue(struct work_struct *work) } dentry = dget(pipe->dentry); spin_unlock(&pipe->lock); - if (dentry) { - rpc_purge_list(&RPC_I(dentry->d_inode)->waitq, - &free_list, destroy_msg, -ETIMEDOUT); - dput(dentry); - } + rpc_purge_list(dentry ? &RPC_I(dentry->d_inode)->waitq : NULL, + &free_list, destroy_msg, -ETIMEDOUT); + dput(dentry); } ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg, From 696615b7f9872cf81a840cde982775c521f56ea3 Mon Sep 17 00:00:00 2001 From: "nagalakshmi.nandigama@lsi.com" Date: Tue, 17 Apr 2012 11:25:04 +0530 Subject: [PATCH 0234/2357] SCSI: mpt2sas: Fix unsafe using smp_processor_id() in preemptible commit a2c658505bf5c75516ee0a79287223e86a2474af upstream. When CONFIG_DEBUG_PREEMPT is enabled, bug is observed in the smp_processor_id(). This is because smp_processor_id() is not called in preempt safe condition. To fix this issue, use raw_smp_processor_id instead of smp_processor_id. Signed-off-by: Nagalakshmi Nandigama Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt2sas/mpt2sas_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 18084788ee3..3f03342b303 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1785,7 +1785,7 @@ static inline void _base_writeq(__u64 b, volatile void __iomem *addr, static inline u8 _base_get_msix_index(struct MPT2SAS_ADAPTER *ioc) { - return ioc->cpu_msix_table[smp_processor_id()]; + return ioc->cpu_msix_table[raw_smp_processor_id()]; } /** From 78ac34ad3199ad0cd9c23d6084c8627daa748a2b Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Fri, 15 Jun 2012 17:55:50 -0700 Subject: [PATCH 0235/2357] swap: fix shmem swapping when more than 8 areas commit 9b15b817f3d62409290fd56fe3cbb076a931bb0a upstream. Minchan Kim reports that when a system has many swap areas, and tmpfs swaps out to the ninth or more, shmem_getpage_gfp()'s attempts to read back the page cannot locate it, and the read fails with -ENOMEM. Whoops. Yes, I blindly followed read_swap_header()'s pte_to_swp_entry( swp_entry_to_pte()) technique for determining maximum usable swap offset, without stopping to realize that that actually depends upon the pte swap encoding shifting swap offset to the higher bits and truncating it there. Whereas our radix_tree swap encoding leaves offset in the lower bits: it's swap "type" (that is, index of swap area) that was truncated. Fix it by reducing the SWP_TYPE_SHIFT() in swapops.h, and removing the broken radix_to_swp_entry(swp_to_radix_entry()) from read_swap_header(). This does not reduce the usable size of a swap area any further, it leaves it as claimed when making the original commit: no change from 3.0 on x86_64, nor on i386 without PAE; but 3.0's 512GB is reduced to 128GB per swapfile on i386 with PAE. It's not a change I would have risked five years ago, but with x86_64 supported for ten years, I believe it's appropriate now. Hmm, and what if some architecture implements its swap pte with offset encoded below type? That would equally break the maximum usable swap offset check. Happily, they all follow the same tradition of encoding offset above type, but I'll prepare a check on that for next. Reported-and-Reviewed-and-Tested-by: Minchan Kim Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/swapops.h | 8 +++++--- mm/swapfile.c | 12 ++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/include/linux/swapops.h b/include/linux/swapops.h index 792d16d9cbc..47ead515c81 100644 --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -9,13 +9,15 @@ * get good packing density in that tree, so the index should be dense in * the low-order bits. * - * We arrange the `type' and `offset' fields so that `type' is at the five + * We arrange the `type' and `offset' fields so that `type' is at the seven * high-order bits of the swp_entry_t and `offset' is right-aligned in the - * remaining bits. + * remaining bits. Although `type' itself needs only five bits, we allow for + * shmem/tmpfs to shift it all up a further two bits: see swp_to_radix_entry(). * * swp_entry_t's are *never* stored anywhere in their arch-dependent format. */ -#define SWP_TYPE_SHIFT(e) (sizeof(e.val) * 8 - MAX_SWAPFILES_SHIFT) +#define SWP_TYPE_SHIFT(e) ((sizeof(e.val) * 8) - \ + (MAX_SWAPFILES_SHIFT + RADIX_TREE_EXCEPTIONAL_SHIFT)) #define SWP_OFFSET_MASK(e) ((1UL << SWP_TYPE_SHIFT(e)) - 1) /* diff --git a/mm/swapfile.c b/mm/swapfile.c index fafc26d1b1d..38186d96a72 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1924,24 +1924,20 @@ static unsigned long read_swap_header(struct swap_info_struct *p, /* * Find out how many pages are allowed for a single swap - * device. There are three limiting factors: 1) the number + * device. There are two limiting factors: 1) the number * of bits for the swap offset in the swp_entry_t type, and * 2) the number of bits in the swap pte as defined by the - * the different architectures, and 3) the number of free bits - * in an exceptional radix_tree entry. In order to find the + * different architectures. In order to find the * largest possible bit mask, a swap entry with swap type 0 * and swap offset ~0UL is created, encoded to a swap pte, * decoded to a swp_entry_t again, and finally the swap * offset is extracted. This will mask all the bits from * the initial ~0UL mask that can't be encoded in either * the swp_entry_t or the architecture definition of a - * swap pte. Then the same is done for a radix_tree entry. + * swap pte. */ maxpages = swp_offset(pte_to_swp_entry( - swp_entry_to_pte(swp_entry(0, ~0UL)))); - maxpages = swp_offset(radix_to_swp_entry( - swp_to_radix_entry(swp_entry(0, maxpages)))) + 1; - + swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1; if (maxpages > swap_header->info.last_page) { maxpages = swap_header->info.last_page + 1; /* p->max is an unsigned int: don't overflow it */ From 781259df8b5637b7ea0810b633c6da3570c7b4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sat, 19 May 2012 19:20:50 +0200 Subject: [PATCH 0236/2357] USB: option: Add Vodafone/Huawei K5005 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4cbbb039a9719fb3bba73d255c6a95bc6dc6428b upstream. Tested-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index f4465ccddc3..5d166e86e46 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -150,6 +150,7 @@ static void option_instat_callback(struct urb *urb); #define HUAWEI_PRODUCT_E14AC 0x14AC #define HUAWEI_PRODUCT_K3806 0x14AE #define HUAWEI_PRODUCT_K4605 0x14C6 +#define HUAWEI_PRODUCT_K5005 0x14C8 #define HUAWEI_PRODUCT_K3770 0x14C9 #define HUAWEI_PRODUCT_K3771 0x14CA #define HUAWEI_PRODUCT_K4510 0x14CB @@ -666,6 +667,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x31) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x32) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x33) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) }, From 18246bfb1f51368b2d1386d2775124b207e158cb Mon Sep 17 00:00:00 2001 From: Andrew Bird Date: Mon, 28 May 2012 12:43:06 +0100 Subject: [PATCH 0237/2357] USB: option: Updated Huawei K4605 has better id commit 42ca7da1c2363dbef4ba1b6917c4c02274b6a5e2 upstream. Later firmwares for this device now have proper subclass and protocol info so we can identify it nicely without needing to use the blacklist. I'm not removing the old 0xff matching as there may be devices in the field that still need that. Signed-off-by: Andrew Bird Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5d166e86e46..154a08373a3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -667,6 +667,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x31) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x32) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x31) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x32) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x33) }, From c4962879787761e53777b1811787acb1753df7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B4=E4=B8=8D=E5=BE=97?= Date: Mon, 28 May 2012 21:31:29 +0800 Subject: [PATCH 0238/2357] USB: option: add more YUGA device ids commit 0ef0be15fd2564767f114c249fc4af704d8e16f4 upstream. Signed-off-by: gavin zhu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 44 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 154a08373a3..9f805f0e32d 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -426,7 +426,7 @@ static void option_instat_callback(struct urb *urb); #define SAMSUNG_VENDOR_ID 0x04e8 #define SAMSUNG_PRODUCT_GT_B3730 0x6889 -/* YUGA products www.yuga-info.com*/ +/* YUGA products www.yuga-info.com gavin.kx@qq.com */ #define YUGA_VENDOR_ID 0x257A #define YUGA_PRODUCT_CEM600 0x1601 #define YUGA_PRODUCT_CEM610 0x1602 @@ -443,6 +443,8 @@ static void option_instat_callback(struct urb *urb); #define YUGA_PRODUCT_CEU516 0x160C #define YUGA_PRODUCT_CEU528 0x160D #define YUGA_PRODUCT_CEU526 0x160F +#define YUGA_PRODUCT_CEU881 0x161F +#define YUGA_PRODUCT_CEU882 0x162F #define YUGA_PRODUCT_CWM600 0x2601 #define YUGA_PRODUCT_CWM610 0x2602 @@ -458,23 +460,26 @@ static void option_instat_callback(struct urb *urb); #define YUGA_PRODUCT_CWU518 0x260B #define YUGA_PRODUCT_CWU516 0x260C #define YUGA_PRODUCT_CWU528 0x260D +#define YUGA_PRODUCT_CWU581 0x260E #define YUGA_PRODUCT_CWU526 0x260F - -#define YUGA_PRODUCT_CLM600 0x2601 -#define YUGA_PRODUCT_CLM610 0x2602 -#define YUGA_PRODUCT_CLM500 0x2603 -#define YUGA_PRODUCT_CLM510 0x2604 -#define YUGA_PRODUCT_CLM800 0x2605 -#define YUGA_PRODUCT_CLM900 0x2606 - -#define YUGA_PRODUCT_CLU718 0x2607 -#define YUGA_PRODUCT_CLU716 0x2608 -#define YUGA_PRODUCT_CLU728 0x2609 -#define YUGA_PRODUCT_CLU726 0x260A -#define YUGA_PRODUCT_CLU518 0x260B -#define YUGA_PRODUCT_CLU516 0x260C -#define YUGA_PRODUCT_CLU528 0x260D -#define YUGA_PRODUCT_CLU526 0x260F +#define YUGA_PRODUCT_CWU582 0x261F +#define YUGA_PRODUCT_CWU583 0x262F + +#define YUGA_PRODUCT_CLM600 0x3601 +#define YUGA_PRODUCT_CLM610 0x3602 +#define YUGA_PRODUCT_CLM500 0x3603 +#define YUGA_PRODUCT_CLM510 0x3604 +#define YUGA_PRODUCT_CLM800 0x3605 +#define YUGA_PRODUCT_CLM900 0x3606 + +#define YUGA_PRODUCT_CLU718 0x3607 +#define YUGA_PRODUCT_CLU716 0x3608 +#define YUGA_PRODUCT_CLU728 0x3609 +#define YUGA_PRODUCT_CLU726 0x360A +#define YUGA_PRODUCT_CLU518 0x360B +#define YUGA_PRODUCT_CLU516 0x360C +#define YUGA_PRODUCT_CLU528 0x360D +#define YUGA_PRODUCT_CLU526 0x360F /* Viettel products */ #define VIETTEL_VENDOR_ID 0x2262 @@ -1215,6 +1220,11 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU516) }, { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) }, { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU881) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU882) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU581) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU582) }, + { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU583) }, { USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) }, { USB_DEVICE(LG_VENDOR_ID, LG_PRODUCT_L02C) }, /* docomo L-02C modem */ From d2002eb8a3a9c6d9182e1652b3ec22f6dd20741b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 29 May 2012 18:22:48 +0200 Subject: [PATCH 0239/2357] USB: option: fix memory leak commit b9c3aab315b51f81649a0d737c4c73783fbd8de0 upstream. Fix memory leak introduced by commit 383cedc3bb435de7a2 ("USB: serial: full autosuspend support for the option driver") which allocates usb-serial data but never frees it. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 9f805f0e32d..66c6bae2359 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -47,6 +47,7 @@ /* Function prototypes */ static int option_probe(struct usb_serial *serial, const struct usb_device_id *id); +static void option_release(struct usb_serial *serial); static int option_send_setup(struct usb_serial_port *port); static void option_instat_callback(struct urb *urb); @@ -1273,7 +1274,7 @@ static struct usb_serial_driver option_1port_device = { .ioctl = usb_wwan_ioctl, .attach = usb_wwan_startup, .disconnect = usb_wwan_disconnect, - .release = usb_wwan_release, + .release = option_release, .read_int_callback = option_instat_callback, #ifdef CONFIG_PM .suspend = usb_wwan_suspend, @@ -1384,6 +1385,15 @@ static int option_probe(struct usb_serial *serial, return 0; } +static void option_release(struct usb_serial *serial) +{ + struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); + + usb_wwan_release(serial); + + kfree(priv); +} + static void option_instat_callback(struct urb *urb) { int err; From a0ae72b68662f833a56c060fbd483609941e8284 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 29 May 2012 17:57:52 +0200 Subject: [PATCH 0240/2357] USB: option: fix port-data abuse commit 4273f9878b0a8271df055e3c8f2e7f08c6a4a2f4 upstream. Commit 8b4c6a3ab596961b78465 ("USB: option: Use generic USB wwan code") moved option port-data allocation to usb_wwan_startup but still cast the port data to the old struct... Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 66c6bae2359..2706d8acb94 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1288,35 +1288,6 @@ static struct usb_serial_driver * const serial_drivers[] = { static bool debug; -/* per port private data */ - -#define N_IN_URB 4 -#define N_OUT_URB 4 -#define IN_BUFLEN 4096 -#define OUT_BUFLEN 4096 - -struct option_port_private { - /* Input endpoints and buffer for this port */ - struct urb *in_urbs[N_IN_URB]; - u8 *in_buffer[N_IN_URB]; - /* Output endpoints and buffer for this port */ - struct urb *out_urbs[N_OUT_URB]; - u8 *out_buffer[N_OUT_URB]; - unsigned long out_busy; /* Bit vector of URBs in use */ - int opened; - struct usb_anchor delayed; - - /* Settings for the port */ - int rts_state; /* Handshaking pins (outputs) */ - int dtr_state; - int cts_state; /* Handshaking pins (inputs) */ - int dsr_state; - int dcd_state; - int ri_state; - - unsigned long tx_start_time[N_OUT_URB]; -}; - module_usb_serial_driver(option_driver, serial_drivers); static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, @@ -1399,7 +1370,8 @@ static void option_instat_callback(struct urb *urb) int err; int status = urb->status; struct usb_serial_port *port = urb->context; - struct option_port_private *portdata = usb_get_serial_port_data(port); + struct usb_wwan_port_private *portdata = + usb_get_serial_port_data(port); dbg("%s", __func__); dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); @@ -1460,7 +1432,7 @@ static int option_send_setup(struct usb_serial_port *port) struct usb_serial *serial = port->serial; struct usb_wwan_intf_private *intfdata = (struct usb_wwan_intf_private *) serial->private; - struct option_port_private *portdata; + struct usb_wwan_port_private *portdata; int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; int val = 0; dbg("%s", __func__); From d64cbbc9603861015cd616327f63b10394c0418a Mon Sep 17 00:00:00 2001 From: Seiji Aguchi Date: Tue, 15 May 2012 17:35:09 -0400 Subject: [PATCH 0241/2357] kdump: Execute kmsg_dump(KMSG_DUMP_PANIC) after smp_send_stop() commit 62be73eafaa045d3233337303fb140f7f8a61135 upstream. This patch moves kmsg_dump(KMSG_DUMP_PANIC) below smp_send_stop(), to serialize the crash-logging process via smp_send_stop() and to thus retrieve a more stable crash image of all CPUs stopped. Signed-off-by: Seiji Aguchi Acked-by: Don Zickus Cc: dle-develop@lists.sourceforge.net Cc: Satoru Moriya Cc: Tony Luck Cc: a.p.zijlstra@chello.nl Link: http://lkml.kernel.org/r/5C4C569E8A4B9B42A84A977CF070A35B2E4D7A5CE2@USINDEVS01.corp.hds.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/panic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/panic.c b/kernel/panic.c index 8ed89a175d7..9ed023b8333 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -108,8 +108,6 @@ void panic(const char *fmt, ...) */ crash_kexec(NULL); - kmsg_dump(KMSG_DUMP_PANIC); - /* * Note smp_send_stop is the usual smp shutdown function, which * unfortunately means it may not be hardened to work in a panic @@ -117,6 +115,8 @@ void panic(const char *fmt, ...) */ smp_send_stop(); + kmsg_dump(KMSG_DUMP_PANIC); + atomic_notifier_call_chain(&panic_notifier_list, 0, buf); bust_spinlocks(0); From 152a4f421da62406d8836aa2c9e53b7b3e405e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Janne=20Kalliom=C3=A4ki?= Date: Sun, 17 Jun 2012 17:05:24 -0400 Subject: [PATCH 0242/2357] hfsplus: fix overflow in sector calculations in hfsplus_submit_bio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a6dc8c04218eb752ff79cdc24a995cf51866caed upstream. The variable io_size was unsigned int, which caused the wrong sector number to be calculated after aligning it. This then caused mount to fail with big volumes, as backup volume header information was searched from a wrong sector. Signed-off-by: Janne Kalliomäki Signed-off-by: Christoph Hellwig Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/hfsplus/wrapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index 7daf4b852d1..90effcccca9 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c @@ -56,7 +56,7 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector, DECLARE_COMPLETION_ONSTACK(wait); struct bio *bio; int ret = 0; - unsigned int io_size; + u64 io_size; loff_t start; int offset; From 231afb7c7ded9bf798b71efdf576615e91c367af Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Sun, 17 Jun 2012 17:05:25 -0400 Subject: [PATCH 0243/2357] hfsplus: fix bless ioctl when used with hardlinks commit 7dea9665fee828fb56db3bae5b9685d9fa006d33 upstream. HFS+ doesn't really implement hard links - instead, hardlinks are indicated by a magic file type which refers to an indirect node in a hidden directory. The spec indicates that stat() should return the inode number of the indirect node, but it turns out that this doesn't satisfy the firmware when it's looking for a bootloader - it wants the catalog ID of the hardlink file instead. Fix up this case. Signed-off-by: Matthew Garrett Signed-off-by: Christoph Hellwig Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/hfsplus/ioctl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index c640ba57074..09addc8615f 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -31,6 +31,7 @@ static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags) struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); struct hfsplus_vh *vh = sbi->s_vhdr; struct hfsplus_vh *bvh = sbi->s_backup_vhdr; + u32 cnid = (unsigned long)dentry->d_fsdata; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -41,8 +42,12 @@ static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags) vh->finder_info[0] = bvh->finder_info[0] = cpu_to_be32(parent_ino(dentry)); - /* Bootloader */ - vh->finder_info[1] = bvh->finder_info[1] = cpu_to_be32(inode->i_ino); + /* + * Bootloader. Just using the inode here breaks in the case of + * hard links - the firmware wants the ID of the hard link file, + * but the inode points at the indirect inode + */ + vh->finder_info[1] = bvh->finder_info[1] = cpu_to_be32(cnid); /* Per spec, the OS X system folder - same as finder_info[0] here */ vh->finder_info[5] = bvh->finder_info[5] = From d6bc383209efd8a57b3c73ef2524a98df32c7bcc Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 15 Jun 2012 14:51:39 +1000 Subject: [PATCH 0244/2357] Make hard_irq_disable() actually hard-disable interrupts commit f948501b36c6b3d9352ce212a197098a7e958971 upstream. At present, hard_irq_disable() does nothing on powerpc because of this code in include/linux/interrupt.h: #ifndef hard_irq_disable #define hard_irq_disable() do { } while(0) #endif So we need to make our hard_irq_disable be a macro. It was previously a macro until commit 7230c56441 ("powerpc: Rework lazy-interrupt handling") changed it to a static inline function. Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras Signed-off-by: Greg Kroah-Hartman -- arch/powerpc/include/asm/hw_irq.h | 3 +++ 1 file changed, 3 insertions(+) --- arch/powerpc/include/asm/hw_irq.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 51010bfc792..102abd6dbc0 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -99,6 +99,9 @@ static inline void hard_irq_disable(void) get_paca()->irq_happened |= PACA_IRQ_HARD_DIS; } +/* include/linux/interrupt.h needs hard_irq_disable to be a macro */ +#define hard_irq_disable hard_irq_disable + /* * This is called by asynchronous interrupts to conditionally * re-enable hard interrupts when soft-disabled after having From b063a624f08cfa64c2d9162d1525da95519e6156 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 1 Jun 2012 10:06:23 +0200 Subject: [PATCH 0245/2357] xhci: Fix invalid loop check in xhci_free_tt_info() commit 46ed8f00d8982e49f8fe2c1a9cea192f640cb3ba upstream. xhci_free_tt_info() may access the invalid memory when it removes the last entry but the list is not empty. Then tt_next reaches to the list head but it still tries to check the tt_info of that entry. This patch fixes the bug and cleans up the messy code by rewriting with a simple list_for_each_entry_safe(). This patch should be backported to kernels as old as 3.2, that contain the commit 839c817ce67178ca3c7c7ad534c571bba1e69ebe "xhci: Store information about roothubs and TTs." Signed-off-by: Takashi Iwai Signed-off-by: Sarah Sharp Reviewed-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 39 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 497ed7723e4..dab2f175296 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -793,10 +793,9 @@ static void xhci_free_tt_info(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, int slot_id) { - struct list_head *tt; struct list_head *tt_list_head; - struct list_head *tt_next; - struct xhci_tt_bw_info *tt_info; + struct xhci_tt_bw_info *tt_info, *next; + bool slot_found = false; /* If the device never made it past the Set Address stage, * it may not have the real_port set correctly. @@ -808,34 +807,16 @@ static void xhci_free_tt_info(struct xhci_hcd *xhci, } tt_list_head = &(xhci->rh_bw[virt_dev->real_port - 1].tts); - if (list_empty(tt_list_head)) - return; - - list_for_each(tt, tt_list_head) { - tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list); - if (tt_info->slot_id == slot_id) + list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) { + /* Multi-TT hubs will have more than one entry */ + if (tt_info->slot_id == slot_id) { + slot_found = true; + list_del(&tt_info->tt_list); + kfree(tt_info); + } else if (slot_found) { break; + } } - /* Cautionary measure in case the hub was disconnected before we - * stored the TT information. - */ - if (tt_info->slot_id != slot_id) - return; - - tt_next = tt->next; - tt_info = list_entry(tt, struct xhci_tt_bw_info, - tt_list); - /* Multi-TT hubs will have more than one entry */ - do { - list_del(tt); - kfree(tt_info); - tt = tt_next; - if (list_empty(tt_list_head)) - break; - tt_next = tt->next; - tt_info = list_entry(tt, struct xhci_tt_bw_info, - tt_list); - } while (tt_info->slot_id == slot_id); } int xhci_alloc_tt_info(struct xhci_hcd *xhci, From 708053a5a4e304915aae1ecab2e5fea9921c9f82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 1 Jun 2012 10:06:24 +0200 Subject: [PATCH 0246/2357] xhci: Don't free endpoints in xhci_mem_cleanup() commit 32f1d2c536d0c26c5814cb0e6a0606c42d02fac1 upstream. This patch fixes a few issues introduced in the recent fix [f8a9e72d: USB: fix resource leak in xhci power loss path] - The endpoints listed in bw table are just links and each entry is an array member of dev->eps[]. But the commit above adds a kfree() call to these instances, and thus it results in memory corruption. - It clears only the first entry of rh_bw[], but there can be multiple ports. - It'd be safer to clear the list_head of ep as well, not only removing from the list, as it's checked in xhci_discover_or_reset_device(). This patch should be backported to kernels as old as 3.2, that contain the commit 839c817ce67178ca3c7c7ad534c571bba1e69ebe "xhci: Store information about roothubs and TTs." Signed-off-by: Takashi Iwai Signed-off-by: Sarah Sharp Reviewed-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index dab2f175296..6b908249b01 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1772,17 +1772,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); struct dev_info *dev_info, *next; - struct list_head *tt_list_head; - struct list_head *tt; - struct list_head *endpoints; - struct list_head *ep, *q; - struct xhci_tt_bw_info *tt_info; - struct xhci_interval_bw_table *bwt; - struct xhci_virt_ep *virt_ep; - unsigned long flags; int size; - int i; + int i, j, num_ports; /* Free the Event Ring Segment Table and the actual Event Ring */ size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); @@ -1839,21 +1831,22 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } spin_unlock_irqrestore(&xhci->lock, flags); - bwt = &xhci->rh_bw->bw_table; - for (i = 0; i < XHCI_MAX_INTERVAL; i++) { - endpoints = &bwt->interval_bw[i].endpoints; - list_for_each_safe(ep, q, endpoints) { - virt_ep = list_entry(ep, struct xhci_virt_ep, bw_endpoint_list); - list_del(&virt_ep->bw_endpoint_list); - kfree(virt_ep); + num_ports = HCS_MAX_PORTS(xhci->hcs_params1); + for (i = 0; i < num_ports; i++) { + struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table; + for (j = 0; j < XHCI_MAX_INTERVAL; j++) { + struct list_head *ep = &bwt->interval_bw[j].endpoints; + while (!list_empty(ep)) + list_del_init(ep->next); } } - tt_list_head = &xhci->rh_bw->tts; - list_for_each_safe(tt, q, tt_list_head) { - tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list); - list_del(tt); - kfree(tt_info); + for (i = 0; i < num_ports; i++) { + struct xhci_tt_bw_info *tt, *n; + list_for_each_entry_safe(tt, n, &xhci->rh_bw[i].tts, tt_list) { + list_del(&tt->tt_list); + kfree(tt); + } } xhci->num_usb2_ports = 0; From 5dc6fed88a3ed8ce57c2e3bc0db97527b59a3977 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Wed, 13 Jun 2012 10:51:57 +0800 Subject: [PATCH 0247/2357] xHCI: Increase the timeout for controller save/restore state operation commit 622eb783fe6ff4c1baa47db16c3a5db97f9e6e50 upstream. When system software decides to power down the xHC with the intent of resuming operation at a later time, it will ask xHC to save the internal state and restore it when resume to correctly recover from a power event. Two bits are used to enable this operation: Save State and Restore State. xHCI spec 4.23.2 says software should "Set the Controller Save/Restore State flag in the USBCMD register and wait for the Save/Restore State Status flag in the USBSTS register to transition to '0'". However, it does not define how long software should wait for the SSS/RSS bit to transition to 0. Currently the timeout is set to 1ms. There is bug report (https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1002697) indicates that the timeout is too short for ASMedia ASM1042 host controller to save/restore the state successfully. Increase the timeout to 10ms helps to resolve the issue. This patch should be backported to stable kernels as old as 2.6.37, that contain the commit 5535b1d5f8885695c6ded783c692e3c0d0eda8ca "USB: xHCI: PCI power management implementation" Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Cc: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5910048b0a2..9248d496cb8 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -795,8 +795,8 @@ int xhci_suspend(struct xhci_hcd *xhci) command = xhci_readl(xhci, &xhci->op_regs->command); command |= CMD_CSS; xhci_writel(xhci, command, &xhci->op_regs->command); - if (handshake(xhci, &xhci->op_regs->status, STS_SAVE, 0, 10*100)) { - xhci_warn(xhci, "WARN: xHC CMD_CSS timeout\n"); + if (handshake(xhci, &xhci->op_regs->status, STS_SAVE, 0, 10 * 1000)) { + xhci_warn(xhci, "WARN: xHC save state timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } @@ -848,8 +848,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) command |= CMD_CRS; xhci_writel(xhci, command, &xhci->op_regs->command); if (handshake(xhci, &xhci->op_regs->status, - STS_RESTORE, 0, 10*100)) { - xhci_dbg(xhci, "WARN: xHC CMD_CSS timeout\n"); + STS_RESTORE, 0, 10 * 1000)) { + xhci_warn(xhci, "WARN: xHC restore state timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } From bd1031c0027fab25f9d1e8229bc380298ae6d0a0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 13 Jun 2012 11:44:58 +0200 Subject: [PATCH 0248/2357] usb-storage: Add 090c:1000 to unusal-devs commit afff07e61a5243e14ee3f0a272a0380cd744a8a3 upstream. This device gives a bogus answer to get_capacity(16): [ 8628.278614] scsi 8:0:0:0: Direct-Access USB 2.0 USB Flash Drive 1100 PQ: 0 ANSI: 4 [ 8628.279452] sd 8:0:0:0: Attached scsi generic sg4 type 0 [ 8628.280338] sd 8:0:0:0: [sdd] 35747322042253313 512-byte logical blocks: (18.3 EB/15.8 EiB) So set the quirk flag to avoid using get_capacity(16) with it: [11731.386014] usb-storage 2-1.6:1.0: Quirks match for vid 090c pid 1000: 80000 [11731.386075] scsi9 : usb-storage 2-1.6:1.0 [11731.386172] usbcore: registered new interface driver usb-storage [11731.386175] USB Mass Storage support registered. [11732.387394] scsi 9:0:0:0: Direct-Access USB 2.0 USB Flash Drive 1100 PQ: 0 ANSI: 4 [11732.388462] sd 9:0:0:0: Attached scsi generic sg3 type 0 [11732.389432] sd 9:0:0:0: [sdc] 7975296 512-byte logical blocks: (4.08 GB/3.80 GiB) Which makes the capacity look a lot more sane :) Signed-off-by: Hans de Goede Tested-by: Simon Raffeiner Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 8f3cbb8dc81..f4d3e1a8e7d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1107,6 +1107,13 @@ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, USB_SC_RBC, USB_PR_BULK, NULL, 0 ), +/* Feiya QDI U2 DISK, reported by Hans de Goede */ +UNUSUAL_DEV( 0x090c, 0x1000, 0x0000, 0xffff, + "Feiya", + "QDI U2 DISK", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_READ_CAPACITY_16 ), + /* aeb */ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff, "Feiya", From 0fd47a3802d9fd08a65625572c5c4089aa6f3e78 Mon Sep 17 00:00:00 2001 From: Tony Zelenoff Date: Tue, 5 Jun 2012 17:58:04 +0400 Subject: [PATCH 0249/2357] USB: mos7840: Fix compilation of usb serial driver commit b9c87663eead64c767e72a373ae6f8a94bead459 upstream. The __devinitconst section can't be referenced from usb_serial_device structure. Thus removed it as it done in other mos* device drivers. Error itself: WARNING: drivers/usb/serial/mos7840.o(.data+0x8): Section mismatch in reference from the variable moschip7840_4port_device to the variable .devinit.rodata:id_table The variable moschip7840_4port_device references the variable __devinitconst id_table [v2] no attach now Signed-off-by: Tony Zelenoff Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c526550694a..62739ff58c7 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -206,7 +206,7 @@ static const struct usb_device_id moschip_port_id_table[] = { {} /* terminating entry */ }; -static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { +static const struct usb_device_id moschip_id_table_combined[] = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, From c1cbfb94dab7c2f5092d0eef4ce87fdb4119a7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 24 May 2012 11:19:04 +0200 Subject: [PATCH 0250/2357] USB: qcserial: Add Sierra Wireless device IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c41444ccfa33a1c20efa319e554cb531576e64a2 upstream. Some additional IDs found in the BSD/GPL licensed out-of-tree GobiSerial driver from Sierra Wireless. Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 0206b10c9e6..50b5371719f 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -105,7 +105,13 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x1410, 0xa021)}, /* Novatel Gobi 3000 Composite */ {USB_DEVICE(0x413c, 0x8193)}, /* Dell Gobi 3000 QDL */ {USB_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */ + {USB_DEVICE(0x1199, 0x9010)}, /* Sierra Wireless Gobi 3000 QDL */ + {USB_DEVICE(0x1199, 0x9012)}, /* Sierra Wireless Gobi 3000 QDL */ {USB_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ + {USB_DEVICE(0x1199, 0x9014)}, /* Sierra Wireless Gobi 3000 QDL */ + {USB_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ + {USB_DEVICE(0x1199, 0x9018)}, /* Sierra Wireless Gobi 3000 QDL */ + {USB_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ {USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */ {USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */ { } /* Terminating entry */ From 8951420c6c7a04504659319692435ac627f3f795 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 22 May 2012 20:45:13 +0100 Subject: [PATCH 0251/2357] USB: mct_u232: Fix incorrect TIOCMSET return commit 1aa3c63cf0a79153ee13c8f82e4eb6c40b66a161 upstream. The low level helper returns 1 on success. The ioctl should however return 0. As this is the only user of the helper return, make the helper return 0 or an error code. Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=43009 Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mct_u232.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 6edd26130e2..ef4d7adfbd9 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -317,13 +317,16 @@ static int mct_u232_set_modem_ctrl(struct usb_serial *serial, MCT_U232_SET_REQUEST_TYPE, 0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE, WDR_TIMEOUT); - if (rc < 0) - dev_err(&serial->dev->dev, - "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc); + kfree(buf); + dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr); - kfree(buf); - return rc; + if (rc < 0) { + dev_err(&serial->dev->dev, + "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc); + return rc; + } + return 0; } /* mct_u232_set_modem_ctrl */ static int mct_u232_get_modem_stat(struct usb_serial *serial, From b85ecf1acde49dcc2be67fa4777db259af8ed136 Mon Sep 17 00:00:00 2001 From: Jon Povey Date: Fri, 25 May 2012 10:50:18 +0900 Subject: [PATCH 0252/2357] usb: musb: davinci: Fix build breakage commit 6594b2d7b1ef8260e6e36ddc96bd37a40e39ba80 upstream. This appears to have been broken by commit 5cfb19ac604a68c030b245561f575c2d1bac1d49 (ARM: davinci: streamline sysmod access) For now, fix by hardcoding USB_PHY_CTRL and DM355_DEEPSLEEP Tested on DM365 with defconfig changes. Signed-off-by: Jon Povey Acked-by: Sekhar Nori CC: Felipe Balbi Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/davinci.c | 1 + drivers/usb/musb/davinci.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 768b4b55c81..9d63ba4d10d 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -34,6 +34,7 @@ #include #include +#include #include diff --git a/drivers/usb/musb/davinci.h b/drivers/usb/musb/davinci.h index 046c84433ca..371baa0ee50 100644 --- a/drivers/usb/musb/davinci.h +++ b/drivers/usb/musb/davinci.h @@ -15,7 +15,7 @@ */ /* Integrated highspeed/otg PHY */ -#define USBPHY_CTL_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x34) +#define USBPHY_CTL_PADDR 0x01c40034 #define USBPHY_DATAPOL BIT(11) /* (dm355) switch D+/D- */ #define USBPHY_PHYCLKGD BIT(8) #define USBPHY_SESNDEN BIT(7) /* v(sess_end) comparator */ @@ -27,7 +27,7 @@ #define USBPHY_OTGPDWN BIT(1) #define USBPHY_PHYPDWN BIT(0) -#define DM355_DEEPSLEEP_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x48) +#define DM355_DEEPSLEEP_PADDR 0x01c40048 #define DRVVBUS_FORCE BIT(2) #define DRVVBUS_OVERRIDE BIT(1) From d6fe7df7f2d8c9523deed36bd24036f100b8844b Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Sat, 26 May 2012 00:21:33 +0300 Subject: [PATCH 0253/2357] usb: musb_gadget: fix crash caused by dangling pointer commit 08f75bf14fadaa81fe362d5acda9b77b113dd0a2 upstream. usb_ep_ops.disable must clear external copy of the endpoint descriptor, otherwise musb crashes after loading/unloading several gadget modules in a row: Unable to handle kernel paging request at virtual address bf013730 pgd = c0004000 [bf013730] *pgd=8f26d811, *pte=00000000, *ppte=00000000 Internal error: Oops: 7 [#1] Modules linked in: g_cdc [last unloaded: g_file_storage] CPU: 0 Not tainted (3.2.17 #647) PC is at musb_gadget_enable+0x4c/0x24c LR is at _raw_spin_lock_irqsave+0x4c/0x58 [] (musb_gadget_enable+0x4c/0x24c) from [] (gether_connect+0x3c/0x19c [g_cdc]) [] (gether_connect+0x3c/0x19c [g_cdc]) from [] (ecm_set_alt+0x15c/0x180 [g_cdc]) [] (ecm_set_alt+0x15c/0x180 [g_cdc]) from [] (composite_setup+0x85c/0xac4 [g_cdc]) [] (composite_setup+0x85c/0xac4 [g_cdc]) from [] (musb_g_ep0_irq+0x844/0x924) [] (musb_g_ep0_irq+0x844/0x924) from [] (musb_interrupt+0x79c/0x864) [] (musb_interrupt+0x79c/0x864) from [] (generic_interrupt+0x64/0x7c) [] (generic_interrupt+0x64/0x7c) from [] (handle_irq_event_percpu+0x28/0x178) ... Signed-off-by: Grazvydas Ignotas Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index f42c29b11f7..95918dacc99 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1232,6 +1232,7 @@ static int musb_gadget_disable(struct usb_ep *ep) } musb_ep->desc = NULL; + musb_ep->end_point.desc = NULL; /* abort all pending DMA and requests */ nuke(musb_ep, -ESHUTDOWN); From 5c551ead8ae210031fc241729f4391dff7e682ce Mon Sep 17 00:00:00 2001 From: Ricardo Martins Date: Tue, 22 May 2012 18:02:03 +0100 Subject: [PATCH 0254/2357] USB: fix PS3 EHCI systems commit 4f7a67e2dd49fbfba002c453bc24bf00e701cc71 upstream. After commit aaa0ef289afe9186f81e2340114ea413eef0492a "PS3 EHCI QH read work-around", Terratec Grabby (em28xx) stopped working with AMD Geode LX 800 (USB controller AMD CS5536). Since this is a PS3 only fix, the following patch adds a conditional block around it. Signed-off-by: Ricardo Martins Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 4a3bc5b7a06..bb73df6597b 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -671,7 +671,9 @@ static int ehci_init(struct usb_hcd *hcd) hw = ehci->async->hw; hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma); hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD); +#if defined(CONFIG_PPC_PS3) hw->hw_info1 |= cpu_to_hc32(ehci, (1 << 7)); /* I = 1 */ +#endif hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT); hw->hw_qtd_next = EHCI_LIST_END(ehci); ehci->async->qh_state = QH_STATE_LINKED; From 74351aa4f061229e40e44ae8e150f8de8c45fc13 Mon Sep 17 00:00:00 2001 From: Mikko Tuumanen Date: Fri, 1 Jun 2012 11:28:55 +0300 Subject: [PATCH 0255/2357] USB: serial: cp210x: add Optris MS Pro usb id commit 5bbfa6f427c1d7244a5ee154ab8fa37265a5e049 upstream. Signed-off-by: Mikko Tuumanen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index ec30f95ef39..95de9c08da1 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -82,6 +82,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */ { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ + { USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */ { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */ { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ From 9a12826c11fc0b7cebe6ee0b0711f5ccaf8f6323 Mon Sep 17 00:00:00 2001 From: Evan McNabb Date: Fri, 25 May 2012 22:46:14 -0400 Subject: [PATCH 0256/2357] USB: ftdi-sio: Add support for RT Systems USB-RTS01 serial adapter commit e00a54d772210d450e5c1a801534c3c8a448549f upstream. Add support for RT Systems USB-RTS01 USB to Serial adapter: http://www.rtsystemsinc.com/Photos/USBRTS01.html Tested by controlling Icom IC-718 amateur radio transceiver via hamlib. Signed-off-by: Evan McNabb Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 95bba992416..53e3e2c5b33 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -737,6 +737,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index f3c7c78ede3..5661c7e2d41 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -784,6 +784,7 @@ #define RTSYSTEMS_VID 0x2100 /* Vendor ID */ #define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ #define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ +#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */ /* From 12ad741b1c60c341bf85a90c828b6fa1df47dba5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 13 Jun 2012 11:20:19 -0400 Subject: [PATCH 0257/2357] USB: add NO_D3_DURING_SLEEP flag and revert 151b61284776be2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c2fb8a3fa25513de8fedb38509b1f15a5bbee47b upstream. This patch (as1558) fixes a problem affecting several ASUS computers: The machine crashes or corrupts memory when going into suspend if the ehci-hcd driver is bound to any controllers. Users have been forced to unbind or unload ehci-hcd before putting their systems to sleep. After extensive testing, it was determined that the machines don't like going into suspend when any EHCI controllers are in the PCI D3 power state. Presumably this is a firmware bug, but there's nothing we can do about it except to avoid putting the controllers in D3 during system sleep. The patch adds a new flag to indicate whether the problem is present, and avoids changing the controller's power state if the flag is set. Runtime suspend is unaffected; this matters only for system suspend. However as a side effect, the controller will not respond to remote wakeup requests while the system is asleep. Hence USB wakeup is not functional -- but of course, this is already true in the current state of affairs. A similar patch has already been applied as commit 151b61284776be2d6f02d48c23c3625678960b97 (USB: EHCI: fix crash during suspend on ASUS computers). The patch supersedes that one and reverts it. There are two differences: The old patch added the flag at the USB level; this patch adds it at the PCI level. The old patch applied to all chipsets with the same vendor, subsystem vendor, and product IDs; this patch makes an exception for a known-good system (based on DMI information). Signed-off-by: Alan Stern Tested-by: Dâniel Fraga Tested-by: Andrey Rahmatullin Tested-by: Steven Rostedt Reviewed-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci.c | 5 +++++ drivers/pci/quirks.c | 26 ++++++++++++++++++++++++++ drivers/usb/core/hcd-pci.c | 9 --------- drivers/usb/host/ehci-pci.c | 8 -------- include/linux/pci.h | 2 ++ include/linux/usb/hcd.h | 2 -- 6 files changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 111569ccab4..f597a1aa5e6 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1743,6 +1743,11 @@ int pci_prepare_to_sleep(struct pci_dev *dev) if (target_state == PCI_POWER_ERROR) return -EIO; + /* Some devices mustn't be in D3 during system sleep */ + if (target_state == PCI_D3hot && + (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP)) + return 0; + pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev)); error = pci_set_power_state(dev, target_state); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4bf71028556..bf33f0b7f95 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2917,6 +2917,32 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); +/* + * The Intel 6 Series/C200 Series chipset's EHCI controllers on many + * ASUS motherboards will cause memory corruption or a system crash + * if they are in D3 while the system is put into S3 sleep. + */ +static void __devinit asus_ehci_no_d3(struct pci_dev *dev) +{ + const char *sys_info; + static const char good_Asus_board[] = "P8Z68-V"; + + if (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP) + return; + if (dev->subsystem_vendor != PCI_VENDOR_ID_ASUSTEK) + return; + sys_info = dmi_get_system_info(DMI_BOARD_NAME); + if (sys_info && memcmp(sys_info, good_Asus_board, + sizeof(good_Asus_board) - 1) == 0) + return; + + dev_info(&dev->dev, "broken D3 during system sleep on ASUS\n"); + dev->dev_flags |= PCI_DEV_FLAGS_NO_D3_DURING_SLEEP; + device_set_wakeup_capable(&dev->dev, false); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3); + static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) { diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 57ed9e400c0..622b4a48e73 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -493,15 +493,6 @@ static int hcd_pci_suspend_noirq(struct device *dev) pci_save_state(pci_dev); - /* - * Some systems crash if an EHCI controller is in D3 during - * a sleep transition. We have to leave such controllers in D0. - */ - if (hcd->broken_pci_sleep) { - dev_dbg(dev, "Staying in PCI D0\n"); - return retval; - } - /* If the root hub is dead rather than suspended, disallow remote * wakeup. usb_hc_died() should ensure that both hosts are marked as * dying, so we only need to check the primary roothub. diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index bc94d7bf072..123481793a4 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -144,14 +144,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) hcd->has_tt = 1; tdi_reset(ehci); } - if (pdev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK) { - /* EHCI #1 or #2 on 6 Series/C200 Series chipset */ - if (pdev->device == 0x1c26 || pdev->device == 0x1c2d) { - ehci_info(ehci, "broken D3 during system sleep on ASUS\n"); - hcd->broken_pci_sleep = 1; - device_set_wakeup_capable(&pdev->dev, false); - } - } break; case PCI_VENDOR_ID_TDI: if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { diff --git a/include/linux/pci.h b/include/linux/pci.h index e444f5b4911..8b2921ad51a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -176,6 +176,8 @@ enum pci_dev_flags { PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2, /* Provide indication device is assigned by a Virtual Machine Manager */ PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4, + /* Device causes system crash if in D3 during S3 sleep */ + PCI_DEV_FLAGS_NO_D3_DURING_SLEEP = (__force pci_dev_flags_t) 8, }; enum pci_irq_reroute_variant { diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index d28cc78a38e..5de415707c2 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -126,8 +126,6 @@ struct usb_hcd { unsigned wireless:1; /* Wireless USB HCD */ unsigned authorized_default:1; unsigned has_tt:1; /* Integrated TT in root hub */ - unsigned broken_pci_sleep:1; /* Don't put the - controller in PCI-D3 for system sleep */ unsigned int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ From 9b81405d1683801862cce030aafb062dcbe5c88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sat, 19 May 2012 19:19:48 +0200 Subject: [PATCH 0258/2357] USB: cdc-wdm: Add Vodafone/Huawei K5005 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit de102ef41f24a4c251c4a3838796bb27557d4d93 upstream. Tested-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 4c8321ea4c5..83d14bfc2b2 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -55,6 +55,15 @@ static const struct usb_device_id wdm_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */ }, + { + /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | + USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = HUAWEI_VENDOR_ID, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 57, /* NOTE: CDC ECM control interface! */ + }, { } }; From 9cc2d461d9ae92fdabd9097fb5ff2977fe59d995 Mon Sep 17 00:00:00 2001 From: Otto Meta Date: Wed, 6 Jun 2012 18:46:21 +0200 Subject: [PATCH 0259/2357] usb: cdc-acm: fix devices not unthrottled on open commit 6c4707f3f8c44ec18282e1c014c80e1c257042f9 upstream. Currently CDC-ACM devices stay throttled when their TTY is closed while throttled, stalling further communication attempts after the next open. Unthrottling during open/activate got lost starting with kernel 3.0.0 and this patch reintroduces it. Signed-off-by: Otto Meta Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index b32ccb46101..640cf7983b0 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -567,6 +567,14 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) usb_autopm_put_interface(acm->control); + /* + * Unthrottle device in case the TTY was closed while throttled. + */ + spin_lock_irq(&acm->read_lock); + acm->throttled = 0; + acm->throttle_req = 0; + spin_unlock_irq(&acm->read_lock); + if (acm_submit_read_urbs(acm, GFP_KERNEL)) goto error_submit_read_urbs; From 7eec718ac79fd0533a9a6aedc5ac9e1ee82b6028 Mon Sep 17 00:00:00 2001 From: Tom Cassidy Date: Wed, 6 Jun 2012 17:08:48 +1000 Subject: [PATCH 0260/2357] USB: serial: sierra: Add support for Sierra Wireless AirCard 320U modem commit 19a3dd1575e954e8c004413bee3e12d3962f2525 upstream. Add support for Sierra Wireless AirCard 320U modem Signed-off-by: Tomas Cassidy Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 8c8bf806f6f..449bf6d31e2 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -304,6 +304,10 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */ .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, + /* AT&T Direct IP LTE modems */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF), + .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + }, { USB_DEVICE(0x0f3d, 0x68A3), /* Airprime/Sierra Wireless Direct IP modems */ .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, From 3561c241b6ef53454ac0e26e5c92f39b324a7799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 30 May 2012 10:00:14 +0200 Subject: [PATCH 0261/2357] USB: serial: Enforce USB driver and USB serial driver match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 954c3f8a5f1b7716be9eee978b3bc85bae92d7c8 upstream. We need to make sure that the USB serial driver we find matches the USB driver whose probe we are currently executing. Otherwise we will end up with USB serial devices bound to the correct serial driver but wrong USB driver. An example of such cross-probing, where the usbserial_generic USB driver has found the sierra serial driver: May 29 18:26:15 nemi kernel: [ 4442.559246] usbserial_generic 4-4:1.0: Sierra USB modem converter detected May 29 18:26:20 nemi kernel: [ 4447.556747] usbserial_generic 4-4:1.2: Sierra USB modem converter detected May 29 18:26:25 nemi kernel: [ 4452.557288] usbserial_generic 4-4:1.3: Sierra USB modem converter detected sysfs view of the same problem: bjorn@nemi:~$ ls -l /sys/bus/usb/drivers/sierra/ total 0 --w------- 1 root root 4096 May 29 18:23 bind lrwxrwxrwx 1 root root 0 May 29 18:23 module -> ../../../../module/usbserial --w------- 1 root root 4096 May 29 18:23 uevent --w------- 1 root root 4096 May 29 18:23 unbind bjorn@nemi:~$ ls -l /sys/bus/usb-serial/drivers/sierra/ total 0 --w------- 1 root root 4096 May 29 18:23 bind lrwxrwxrwx 1 root root 0 May 29 18:23 module -> ../../../../module/sierra -rw-r--r-- 1 root root 4096 May 29 18:23 new_id lrwxrwxrwx 1 root root 0 May 29 18:32 ttyUSB0 -> ../../../../devices/pci0000:00/0000:00:1d.7/usb4/4-4/4-4:1.0/ttyUSB0 lrwxrwxrwx 1 root root 0 May 29 18:32 ttyUSB1 -> ../../../../devices/pci0000:00/0000:00:1d.7/usb4/4-4/4-4:1.2/ttyUSB1 lrwxrwxrwx 1 root root 0 May 29 18:32 ttyUSB2 -> ../../../../devices/pci0000:00/0000:00:1d.7/usb4/4-4/4-4:1.3/ttyUSB2 --w------- 1 root root 4096 May 29 18:23 uevent --w------- 1 root root 4096 May 29 18:23 unbind bjorn@nemi:~$ ls -l /sys/bus/usb/drivers/usbserial_generic/ total 0 lrwxrwxrwx 1 root root 0 May 29 18:33 4-4:1.0 -> ../../../../devices/pci0000:00/0000:00:1d.7/usb4/4-4/4-4:1.0 lrwxrwxrwx 1 root root 0 May 29 18:33 4-4:1.2 -> ../../../../devices/pci0000:00/0000:00:1d.7/usb4/4-4/4-4:1.2 lrwxrwxrwx 1 root root 0 May 29 18:33 4-4:1.3 -> ../../../../devices/pci0000:00/0000:00:1d.7/usb4/4-4/4-4:1.3 --w------- 1 root root 4096 May 29 18:33 bind lrwxrwxrwx 1 root root 0 May 29 18:33 module -> ../../../../module/usbserial --w------- 1 root root 4096 May 29 18:22 uevent --w------- 1 root root 4096 May 29 18:33 unbind bjorn@nemi:~$ ls -l /sys/bus/usb-serial/drivers/generic/ total 0 --w------- 1 root root 4096 May 29 18:33 bind lrwxrwxrwx 1 root root 0 May 29 18:33 module -> ../../../../module/usbserial -rw-r--r-- 1 root root 4096 May 29 18:33 new_id --w------- 1 root root 4096 May 29 18:22 uevent --w------- 1 root root 4096 May 29 18:33 unbind So we end up with a mismatch between the USB driver and the USB serial driver. The reason for the above is simple: The USB driver probe will succeed if *any* registered serial driver matches, and will use that serial driver for all serial driver functions. This makes ref counting go wrong. We count the USB driver as used, but not the USB serial driver. This may result in Oops'es as demonstrated by Johan Hovold : [11811.646396] drivers/usb/serial/usb-serial.c: get_free_serial 1 [11811.646443] drivers/usb/serial/usb-serial.c: get_free_serial - minor base = 0 [11811.646460] drivers/usb/serial/usb-serial.c: usb_serial_probe - registering ttyUSB0 [11811.646766] usb 6-1: pl2303 converter now attached to ttyUSB0 [11812.264197] USB Serial deregistering driver FTDI USB Serial Device [11812.264865] usbcore: deregistering interface driver ftdi_sio [11812.282180] USB Serial deregistering driver pl2303 [11812.283141] pl2303 ttyUSB0: pl2303 converter now disconnected from ttyUSB0 [11812.283272] usbcore: deregistering interface driver pl2303 [11812.301056] USB Serial deregistering driver generic [11812.301186] usbcore: deregistering interface driver usbserial_generic [11812.301259] drivers/usb/serial/usb-serial.c: usb_serial_disconnect [11812.301823] BUG: unable to handle kernel paging request at f8e7438c [11812.301845] IP: [] usb_serial_disconnect+0xb5/0x100 [usbserial] [11812.301871] *pde = 357ef067 *pte = 00000000 [11812.301957] Oops: 0000 [#1] PREEMPT SMP [11812.301983] Modules linked in: usbserial(-) [last unloaded: pl2303] [11812.302008] [11812.302019] Pid: 1323, comm: modprobe Tainted: G W 3.4.0-rc7+ #101 Dell Inc. Vostro 1520/0T816J [11812.302115] EIP: 0060:[] EFLAGS: 00010246 CPU: 1 [11812.302130] EIP is at usb_serial_disconnect+0xb5/0x100 [usbserial] [11812.302141] EAX: f508a180 EBX: f508a180 ECX: 00000000 EDX: f8e74300 [11812.302151] ESI: f5050800 EDI: 00000001 EBP: f5141e78 ESP: f5141e58 [11812.302160] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [11812.302170] CR0: 8005003b CR2: f8e7438c CR3: 34848000 CR4: 000007d0 [11812.302180] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [11812.302189] DR6: ffff0ff0 DR7: 00000400 [11812.302199] Process modprobe (pid: 1323, ti=f5140000 task=f61e2bc0 task.ti=f5140000) [11812.302209] Stack: [11812.302216] f8e3be0f f8e3b29c f8e3ae00 00000000 f513641c f5136400 f513641c f507a540 [11812.302325] f5141e98 c133d2c1 00000000 00000000 f509c400 f513641c f507a590 f5136450 [11812.302372] f5141ea8 c12f0344 f513641c f507a590 f5141ebc c12f0c67 00000000 f507a590 [11812.302419] Call Trace: [11812.302439] [] usb_unbind_interface+0x51/0x190 [11812.302456] [] __device_release_driver+0x64/0xb0 [11812.302469] [] driver_detach+0x97/0xa0 [11812.302483] [] bus_remove_driver+0x6c/0xe0 [11812.302500] [] ? __mutex_unlock_slowpath+0xcd/0x140 [11812.302514] [] driver_unregister+0x49/0x80 [11812.302528] [] ? printk+0x1d/0x1f [11812.302540] [] usb_deregister+0x5d/0xb0 [11812.302557] [] ? usb_serial_deregister+0x45/0x50 [usbserial] [11812.302575] [] usb_serial_deregister_drivers+0x2d/0x40 [usbserial] [11812.302593] [] usb_serial_generic_deregister+0x12/0x20 [usbserial] [11812.302611] [] usb_serial_exit+0x8/0x32 [usbserial] [11812.302716] [] sys_delete_module+0x158/0x260 [11812.302730] [] ? mntput+0x1e/0x30 [11812.302746] [] ? sysenter_exit+0xf/0x18 [11812.302746] [] ? trace_hardirqs_on_caller+0xec/0x170 [11812.302746] [] sysenter_do_call+0x12/0x36 [11812.302746] Code: 24 02 00 00 e8 dd f3 20 c8 f6 86 74 02 00 00 02 74 b4 8d 86 4c 02 00 00 47 e8 78 55 4b c8 0f b6 43 0e 39 f8 7f a9 8b 53 04 89 d8 92 8c 00 00 00 89 d8 e8 0e ff ff ff 8b 45 f0 c7 44 24 04 2f [11812.302746] EIP: [] usb_serial_disconnect+0xb5/0x100 [usbserial] SS:ESP 0068:f5141e58 [11812.302746] CR2: 00000000f8e7438c Fix by only evaluating serial drivers pointing back to the USB driver we are currently probing. This still allows two or more drivers to match the same device, running their serial driver probes to sort out which one to use. Signed-off-by: Bjørn Mork Reviewed-by: Felipe Balbi Tested-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 6933355c964..bcf261778d0 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -670,12 +670,14 @@ static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, static struct usb_serial_driver *search_serial_device( struct usb_interface *iface) { - const struct usb_device_id *id; + const struct usb_device_id *id = NULL; struct usb_serial_driver *drv; + struct usb_driver *driver = to_usb_driver(iface->dev.driver); /* Check if the usb id matches a known device */ list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { - id = get_iface_id(drv, iface); + if (drv->usb_driver == driver) + id = get_iface_id(drv, iface); if (id) return drv; } From bc9b784a0be41c0966817b6f53e589f73c82392b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 12 Jun 2012 20:23:52 +0200 Subject: [PATCH 0262/2357] USB: fix gathering of interface associations commit b3a3dd074f7053ef824ad077e5331b52220ceba1 upstream. TEAC's UD-H01 (and probably other devices) have a gap in the interface number allocation of their descriptors: Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 220 bNumInterfaces 3 [...] Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 [...] Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 2 bInterfaceCount 2 bFunctionClass 1 Audio bFunctionSubClass 0 bFunctionProtocol 32 iFunction 4 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 [...] Once a configuration is selected, usb_set_configuration() walks the known interfaces of a given configuration and calls find_iad() on each of them to set the interface association pointer the interface is included in. The problem here is that the loop variable is taken for the interface number in the comparison logic that gathers the association. Which is fine as long as the descriptors are sane. In the case above, however, the logic gets out of sync and the interface association fields of all interfaces beyond the interface number gap are wrong. Fix this by passing the interface's bInterfaceNumber to find_iad() instead. Signed-off-by: Daniel Mack Reported-by: bEN Reported-by: Ivan Perrone Tested-by: ivan perrone Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index ca717da3be9..ef116a55afa 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1803,7 +1803,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) intfc = cp->intf_cache[i]; intf->altsetting = intfc->altsetting; intf->num_altsetting = intfc->num_altsetting; - intf->intf_assoc = find_iad(dev, cp, i); kref_get(&intfc->ref); alt = usb_altnum_to_altsetting(intf, 0); @@ -1816,6 +1815,8 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (!alt) alt = &intf->altsetting[0]; + intf->intf_assoc = + find_iad(dev, cp, alt->desc.bInterfaceNumber); intf->cur_altsetting = alt; usb_enable_interface(dev, intf, true); intf->dev.parent = &dev->dev; From 064cd01904b2796438079f50f91b3b7fc90bf559 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 9 Jun 2012 11:38:12 +0800 Subject: [PATCH 0263/2357] ASoC: wm8904: Fix GPIO and MICBIAS initialisation for regmap conversion commit 433897f7408b556f7dfbb98c94deea02e634d2a7 upstream. We no longer have a flat ASoC cache so can't peer directly into the array any more but should instead use the register I/O functions to update the cache. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8904.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 65d525d74c5..4e190b5950b 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2084,7 +2084,6 @@ static int wm8904_probe(struct snd_soc_codec *codec) { struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_pdata *pdata = wm8904->pdata; - u16 *reg_cache = codec->reg_cache; int ret, i; codec->cache_sync = 1; @@ -2180,14 +2179,18 @@ static int wm8904_probe(struct snd_soc_codec *codec) if (!pdata->gpio_cfg[i]) continue; - reg_cache[WM8904_GPIO_CONTROL_1 + i] - = pdata->gpio_cfg[i] & 0xffff; + regmap_update_bits(wm8904->regmap, + WM8904_GPIO_CONTROL_1 + i, + 0xffff, + pdata->gpio_cfg[i]); } /* Zero is the default value for these anyway */ for (i = 0; i < WM8904_MIC_REGS; i++) - reg_cache[WM8904_MIC_BIAS_CONTROL_0 + i] - = pdata->mic_cfg[i]; + regmap_update_bits(wm8904->regmap, + WM8904_MIC_BIAS_CONTROL_0 + i, + 0xffff, + pdata->mic_cfg[i]); } /* Set Class W by default - this will be managed by the Class From bb1b9f8f93c29dc7855703bd65435e0c442782c3 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Tue, 12 Jun 2012 08:27:04 +0800 Subject: [PATCH 0264/2357] hwrng: atmel-rng - fix data valid check commit c475c06f4bb689d6ad87d7512e036d6dface3160 upstream. Brown paper bag: Data valid is LSB of the ISR (status register), and NOT of ODATA (current random data word)! With this, rngtest is a lot happier. Before: rngtest 3 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warr. rngtest: starting FIPS tests... rngtest: bits received from input: 20000032 rngtest: FIPS 140-2 successes: 3 rngtest: FIPS 140-2 failures: 997 rngtest: FIPS 140-2(2001-10-10) Monobit: 604 rngtest: FIPS 140-2(2001-10-10) Poker: 996 rngtest: FIPS 140-2(2001-10-10) Runs: 36 rngtest: FIPS 140-2(2001-10-10) Long run: 0 rngtest: FIPS 140-2(2001-10-10) Continuous run: 117 rngtest: input channel speed: (min=622.371; avg=23682.481; max=28224.350)Kibitss rngtest: FIPS tests speed: (min=12.361; avg=12.718; max=12.861)Mibits/s rngtest: Program run time: 2331696 microsecondsx After: rngtest 3 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warr. rngtest: starting FIPS tests... rngtest: bits received from input: 20000032 rngtest: FIPS 140-2 successes: 999 rngtest: FIPS 140-2 failures: 1 rngtest: FIPS 140-2(2001-10-10) Monobit: 0 rngtest: FIPS 140-2(2001-10-10) Poker: 0 rngtest: FIPS 140-2(2001-10-10) Runs: 1 rngtest: FIPS 140-2(2001-10-10) Long run: 0 rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=777.363; avg=43588.270; max=47870.711)Kibitss rngtest: FIPS tests speed: (min=11.943; avg=12.716; max=12.844)Mibits/s rngtest: Program run time: 1955282 microseconds Signed-off-by: Peter Korsgaard Reported-by: George Pontis Acked-by: Nicolas Ferre Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/char/hw_random/atmel-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index 6289f0eee24..731c9046cf7 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -34,7 +34,7 @@ static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max, u32 *data = buf; /* data ready? */ - if (readl(trng->base + TRNG_ODATA) & 1) { + if (readl(trng->base + TRNG_ISR) & 1) { *data = readl(trng->base + TRNG_ODATA); /* ensure data ready is only set again AFTER the next data From 40ca92aafc8135368625ba3c8825bcd54f3569a8 Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Tue, 8 May 2012 20:40:12 -0300 Subject: [PATCH 0265/2357] edac: avoid mce decoding crash after edac driver unloaded commit e35fca4791fcdd43dc1fd769797df40c562ab491 upstream. Some edac drivers register themselves as mce decoders via notifier_chain. But in current notifier_chain implementation logic, it doesn't accept same notifier registered twice. If so, it will be wrong when adding/removing the element from the list. For example, on one SandyBridge platform, remove module sb_edac and then trigger one error, it will hit oops because it has no mce decoder registered but related notifier_chain still points to an invalid callback function. Here is an example: Call Trace: [] atomic_notifier_call_chain+0x1a/0x20 [] mce_log+0x46/0x180 [] apei_mce_report_mem_error+0x4a/0x60 [] ghes_do_proc+0x192/0x210 [] ghes_proc+0x46/0x70 [] ghes_notify_sci+0x48/0x80 [] notifier_call_chain+0x55/0x80 [] __blocking_notifier_call_chain+0x5a/0x80 [] ? acpi_os_wait_events_complete+0x23/0x23 [] blocking_notifier_call_chain+0x16/0x20 [] acpi_hed_notify+0x19/0x1b [] acpi_device_notify+0x19/0x1b [] acpi_ev_notify_dispatch+0x67/0x7f [] acpi_os_execute_deferred+0x29/0x36 [] process_one_work+0x132/0x450 [] worker_thread+0x17b/0x3c0 [] ? manage_workers+0x120/0x120 [] kthread+0x9e/0xb0 [] kernel_thread_helper+0x4/0x10 [] ? kthread_freezable_should_stop+0x70/0x70 [] ? gs_change+0x13/0x13 Code: f3 49 89 d4 45 85 ed 4d 89 c6 48 8b 0f 74 48 48 85 c9 75 17 eb 41 0f 1f 80 00 00 00 00 41 83 ed 01 4c 89 f9 74 22 4d 85 ff 74 1d <4c> 8b 79 08 4c 89 e2 48 89 de 48 89 cf ff 11 4d 85 f6 74 04 41 RIP [] notifier_call_chain+0x46/0x80 RSP CR2: ffffffffa01af838 ---[ end trace 0100930068e73e6f ]--- BUG: unable to handle kernel paging request at fffffffffffffff8 IP: [] kthread_data+0x10/0x20 PGD 1a0d067 PUD 1a0e067 PMD 0 Oops: 0000 [#2] SMP Only i7core_edac and sb_edac have such issues because they have more than one memory controller which means they have to register mce decoder many times. Signed-off-by: Chen Gong Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/edac/i7core_edac.c | 15 ++++----------- drivers/edac/sb_edac.c | 8 ++++---- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 85226ccf529..0fe2277d867 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1932,12 +1932,6 @@ static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val, if (mce->bank != 8) return NOTIFY_DONE; -#ifdef CONFIG_SMP - /* Only handle if it is the right mc controller */ - if (mce->socketid != pvt->i7core_dev->socket) - return NOTIFY_DONE; -#endif - smp_rmb(); if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) { smp_wmb(); @@ -2234,8 +2228,6 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev) if (pvt->enable_scrub) disable_sdram_scrub_setting(mci); - mce_unregister_decode_chain(&i7_mce_dec); - /* Disable EDAC polling */ i7core_pci_ctl_release(pvt); @@ -2336,8 +2328,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev) /* DCLK for scrub rate setting */ pvt->dclk_freq = get_dclk_freq(); - mce_register_decode_chain(&i7_mce_dec); - return 0; fail0: @@ -2481,8 +2471,10 @@ static int __init i7core_init(void) pci_rc = pci_register_driver(&i7core_driver); - if (pci_rc >= 0) + if (pci_rc >= 0) { + mce_register_decode_chain(&i7_mce_dec); return 0; + } i7core_printk(KERN_ERR, "Failed to register device with error %d.\n", pci_rc); @@ -2498,6 +2490,7 @@ static void __exit i7core_exit(void) { debugf2("MC: " __FILE__ ": %s()\n", __func__); pci_unregister_driver(&i7core_driver); + mce_unregister_decode_chain(&i7_mce_dec); } module_init(i7core_init); diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index a203536d90d..e9858ba26ff 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1669,8 +1669,6 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev) debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", __func__, mci, &sbridge_dev->pdev[0]->dev); - mce_unregister_decode_chain(&sbridge_mce_dec); - /* Remove MC sysfs nodes */ edac_mc_del_mc(mci->dev); @@ -1738,7 +1736,6 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) goto fail0; } - mce_register_decode_chain(&sbridge_mce_dec); return 0; fail0: @@ -1867,8 +1864,10 @@ static int __init sbridge_init(void) pci_rc = pci_register_driver(&sbridge_driver); - if (pci_rc >= 0) + if (pci_rc >= 0) { + mce_register_decode_chain(&sbridge_mce_dec); return 0; + } sbridge_printk(KERN_ERR, "Failed to register device with error %d.\n", pci_rc); @@ -1884,6 +1883,7 @@ static void __exit sbridge_exit(void) { debugf2("MC: " __FILE__ ": %s()\n", __func__); pci_unregister_driver(&sbridge_driver); + mce_unregister_decode_chain(&sbridge_mce_dec); } module_init(sbridge_init); From 9f138fc8bc57beedc154729260f909ff60490296 Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Mon, 14 May 2012 05:51:26 -0300 Subject: [PATCH 0266/2357] edac: fix the error about memory type detection on SandyBridge commit 2cbb587d3bc41a305168e91b4f3c5b6944a12566 upstream. On SandyBridge, DDRIOA(Dev: 17 Func: 0 Offset: 328) is used to detect whether DIMM is RDIMM/LRDIMM, not TA(Dev: 15 Func: 0). Signed-off-by: Chen Gong Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/edac/sb_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index e9858ba26ff..0f9552d6b56 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -599,7 +599,7 @@ static int get_dimm_config(const struct mem_ctl_info *mci) pvt->is_close_pg = false; } - pci_read_config_dword(pvt->pci_ta, RANK_CFG_A, ®); + pci_read_config_dword(pvt->pci_ddrio, RANK_CFG_A, ®); if (IS_RDIMM_ENABLED(reg)) { /* FIXME: Can also be LRDIMM */ debugf0("Memory is registered\n"); From eef458cb6f020f165de00a5e284048be49e9ee27 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Mon, 11 Jun 2012 10:18:13 -0500 Subject: [PATCH 0267/2357] 9p: BUG before corrupting memory commit 5fcb08befaf57faa1b00e514915c1660252b8c26 upstream. The BUG_ON() in pack_sg_list() would get triggered only one time after we've corrupted some memory by sg_set_buf() into an invalid sg buffer. I'm still working on figuring out why I manage to trigger that bug... Signed-off-by: Sasha Levin Signed-off-by: Eric Van Hensbergen Signed-off-by: Greg Kroah-Hartman --- net/9p/trans_virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 3d432068f62..052d343d43f 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -192,10 +192,10 @@ static int pack_sg_list(struct scatterlist *sg, int start, s = rest_of_page(data); if (s > count) s = count; + BUG_ON(index > limit); sg_set_buf(&sg[index++], data, s); count -= s; data += s; - BUG_ON(index > limit); } return index-start; From efe79381e421af64d34b926917bfb81ef11717dc Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Mon, 21 May 2012 16:31:12 +0300 Subject: [PATCH 0268/2357] remoteproc/omap: fix dev_err typo commit 6b03976288538a94e072bbfcd12d69a20daea8aa upstream. For some reason one of the dev_err invocations is using a wrong device so fix that. Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/remoteproc/omap_remoteproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index 69425c4e86f..de138e30d3e 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -182,7 +182,7 @@ static int __devinit omap_rproc_probe(struct platform_device *pdev) ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { - dev_err(pdev->dev.parent, "dma_set_coherent_mask: %d\n", ret); + dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret); return ret; } From d186a40464141d201f93ee87e0be6f0d2ef029d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Date: Sun, 10 Jun 2012 14:37:07 +0300 Subject: [PATCH 0269/2357] remoteproc: fix print format warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e981f6d41acda2ae8c05e60feb2cb97772b4a6e6 upstream. Fix compile warnings from GCC 4.6.1 when printing values of type size_t. drivers/remoteproc/remoteproc_core.c:251:6: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘size_t’ [-Wformat] drivers/remoteproc/remoteproc_core.c:938:9: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 4 has type ‘size_t’ [-Wformat] drivers/remoteproc/remoteproc_core.c:1023:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat] Signed-off-by: Sjur Brændeland Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/remoteproc/remoteproc_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index e756a0df366..6957c963dc9 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -247,7 +247,7 @@ rproc_load_segments(struct rproc *rproc, const u8 *elf_data, size_t len) } if (offset + filesz > len) { - dev_err(dev, "truncated fw: need 0x%x avail 0x%x\n", + dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", offset + filesz, len); ret = -EINVAL; break; @@ -934,7 +934,7 @@ static void rproc_resource_cleanup(struct rproc *rproc) unmapped = iommu_unmap(rproc->domain, entry->da, entry->len); if (unmapped != entry->len) { /* nothing much to do besides complaining */ - dev_err(dev, "failed to unmap %u/%u\n", entry->len, + dev_err(dev, "failed to unmap %u/%zu\n", entry->len, unmapped); } @@ -1020,7 +1020,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) ehdr = (struct elf32_hdr *)fw->data; - dev_info(dev, "Booting fw image %s, size %d\n", name, fw->size); + dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size); /* * if enabling an IOMMU isn't relevant for this rproc, this is From 6582db31eb1e89ef6b08242a16a781849dada810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Date: Sun, 10 Jun 2012 14:37:51 +0300 Subject: [PATCH 0270/2357] remoteproc: fix missing fault indication in error-path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 30338cf09f82523d8747670f7363cc8af347c79f upstream. If rproc_find_rsc_table() fails, rproc_fw_boot() must set return-value before jumping to clean_up label. Otherwise no error value is returned. Signed-off-by: Sjur Brændeland Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/remoteproc/remoteproc_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 6957c963dc9..7591b9774d0 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1041,8 +1041,10 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) /* look for the resource table */ table = rproc_find_rsc_table(rproc, fw->data, fw->size, &tablesz); - if (!table) + if (!table) { + ret = -EINVAL; goto clean_up; + } /* handle fw resources which are required to boot rproc */ ret = rproc_handle_boot_rsc(rproc, table, tablesz); From 8d87325fd98f66eceec445bd0d724feb63335c40 Mon Sep 17 00:00:00 2001 From: Chris Boot Date: Tue, 24 Apr 2012 07:24:52 +0000 Subject: [PATCH 0271/2357] e1000e: Disable ASPM L1 on 82574 commit d4a4206ebbaf48b55803a7eb34e330530d83a889 upstream. ASPM on the 82574 causes trouble. Currently the driver disables L0s for this NIC but only disables L1 if the MTU is >1500. This patch simply causes L1 to be disabled regardless of the MTU setting. Signed-off-by: Chris Boot Cc: "Wyborny, Carolyn" Cc: Nix Link: https://lkml.org/lkml/2012/3/19/362 Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/82571.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c index b3fdc6977f2..c6d95f2031e 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.c +++ b/drivers/net/ethernet/intel/e1000e/82571.c @@ -2061,8 +2061,9 @@ const struct e1000_info e1000_82574_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, - .flags2 = FLAG2_CHECK_PHY_HANG + .flags2 = FLAG2_CHECK_PHY_HANG | FLAG2_DISABLE_ASPM_L0S + | FLAG2_DISABLE_ASPM_L1 | FLAG2_NO_DISABLE_RX, .pba = 32, .max_hw_frame_size = DEFAULT_JUMBO, From e60a87bab7ce339c034b7d7dd365d687bbffd091 Mon Sep 17 00:00:00 2001 From: Chris Boot Date: Tue, 24 Apr 2012 07:24:58 +0000 Subject: [PATCH 0272/2357] e1000e: Remove special case for 82573/82574 ASPM L1 disablement commit 59aed95263bdd0e2b48eb9be5a94346d2d4abf90 upstream. For the 82573, ASPM L1 gets disabled wholesale so this special-case code is not required. For the 82574 the previous patch does the same as for the 82573, disabling L1 on the adapter. Thus, this code is no longer required and can be removed. Signed-off-by: Chris Boot Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/netdev.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 9520a6ac1f3..00e961e42c6 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5293,14 +5293,6 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } - /* 82573 Errata 17 */ - if (((adapter->hw.mac.type == e1000_82573) || - (adapter->hw.mac.type == e1000_82574)) && - (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN)) { - adapter->flags2 |= FLAG2_DISABLE_ASPM_L1; - e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L1); - } - while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); /* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */ From c17f648b6e8adb8379b2d2972e24953285332f44 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Thu, 26 Apr 2012 14:11:32 +0200 Subject: [PATCH 0273/2357] ntp: Correct TAI offset during leap second commit dd48d708ff3e917f6d6b6c2b696c3f18c019feed upstream. When repeating a UTC time value during a leap second (when the UTC time should be 23:59:60), the TAI timescale should not stop. The kernel NTP code increments the TAI offset one second too late. This patch fixes the issue by incrementing the offset during the leap second itself. Signed-off-by: Richard Cochran Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/time/ntp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index f03fd83b170..e8c867173ae 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -412,6 +412,7 @@ int second_overflow(unsigned long secs) if (secs % 86400 == 0) { leap = -1; time_state = TIME_OOP; + time_tai++; printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n"); } @@ -426,7 +427,6 @@ int second_overflow(unsigned long secs) } break; case TIME_OOP: - time_tai++; time_state = TIME_WAIT; break; From 77bcff9d8249e55b43349ddc3f5ef3b8a63600b8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 16 May 2012 22:35:58 +0200 Subject: [PATCH 0274/2357] iwlwifi: fix the Transmit Frame Descriptor rings commit ebed633c61c023e5d1aa4ed159cd67406e9e37c2 upstream. The logic that allows to have a short TFD queue was completely wrong. We do maintain 256 Transmit Frame Descriptors, but they point to recycled buffers. We used to attach and de-attach different TFDs for the same buffer and it worked since they pointed to the same buffer. Also zero the number of BDs after unmapping a TFD. This seems not necessary since we don't reclaim the same TFD twice, but I like housekeeping. This patch solves this warning: [ 6427.079855] WARNING: at lib/dma-debug.c:866 check_unmap+0x727/0x7a0() [ 6427.079859] Hardware name: Latitude E6410 [ 6427.079865] iwlwifi 0000:02:00.0: DMA-API: device driver tries to free DMA memory it has not allocated [device address=0x00000000296d393c] [size=8 bytes] [ 6427.079870] Modules linked in: ... [ 6427.079950] Pid: 6613, comm: ifconfig Tainted: G O 3.3.3 #5 [ 6427.079954] Call Trace: [ 6427.079963] [] warn_slowpath_common+0x72/0xa0 [ 6427.079982] [] warn_slowpath_fmt+0x33/0x40 [ 6427.079988] [] check_unmap+0x727/0x7a0 [ 6427.079995] [] debug_dma_unmap_page+0x5a/0x80 [ 6427.080024] [] iwlagn_unmap_tfd+0x12c/0x180 [iwlwifi] [ 6427.080048] [] iwlagn_txq_free_tfd+0x49/0xb0 [iwlwifi] [ 6427.080071] [] iwl_tx_queue_unmap+0x67/0x90 [iwlwifi] [ 6427.080095] [] iwl_trans_pcie_stop_device+0x341/0x7b0 [iwlwifi] [ 6427.080113] [] iwl_down+0x17e/0x260 [iwlwifi] [ 6427.080132] [] iwlagn_mac_stop+0x6c/0xf0 [iwlwifi] [ 6427.080168] [] ieee80211_stop_device+0x5e/0x190 [mac80211] [ 6427.080198] [] ieee80211_do_stop+0x288/0x620 [mac80211] [ 6427.080243] [] ieee80211_stop+0x17/0x20 [mac80211] [ 6427.080250] [] __dev_close_many+0x81/0xd0 [ 6427.080270] [] __dev_close+0x2d/0x50 [ 6427.080276] [] __dev_change_flags+0x82/0x150 [ 6427.080282] [] dev_change_flags+0x23/0x60 [ 6427.080289] [] devinet_ioctl+0x6a0/0x770 [ 6427.080296] [] inet_ioctl+0x95/0xb0 [ 6427.080304] [] sock_ioctl+0x70/0x270 Reported-by: Antonio Quartulli Tested-by: Antonio Quartulli Signed-off-by: Emmanuel Grumbach Reviewed-by: Wey-Yi W Guy Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- .../net/wireless/iwlwifi/iwl-trans-pcie-int.h | 2 +- .../net/wireless/iwlwifi/iwl-trans-pcie-tx.c | 20 ++++++++++++------- drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 4 +--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index 1c2fe87bd7e..3b844b79b14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h @@ -342,7 +342,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, enum iwl_rxon_context_id ctx, int sta_id, int tid, int frame_limit, u16 ssn); void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, - int index, enum dma_data_direction dma_dir); + enum dma_data_direction dma_dir); int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, struct sk_buff_head *skbs); int iwl_queue_space(const struct iwl_queue *q); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index e92972fd6ec..d7964b12ef1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -237,32 +237,38 @@ static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta, for (i = 1; i < num_tbs; i++) dma_unmap_single(trans->dev, iwl_tfd_tb_get_addr(tfd, i), iwl_tfd_tb_get_len(tfd, i), dma_dir); + + tfd->num_tbs = 0; } /** * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] * @trans - transport private data * @txq - tx queue - * @index - the index of the TFD to be freed - *@dma_dir - the direction of the DMA mapping + * @dma_dir - the direction of the DMA mapping * * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, - int index, enum dma_data_direction dma_dir) + enum dma_data_direction dma_dir) { struct iwl_tfd *tfd_tmp = txq->tfds; + /* rd_ptr is bounded by n_bd and idx is bounded by n_window */ + int rd_ptr = txq->q.read_ptr; + int idx = get_cmd_index(&txq->q, rd_ptr); + lockdep_assert_held(&txq->lock); - iwlagn_unmap_tfd(trans, &txq->meta[index], &tfd_tmp[index], dma_dir); + /* We have only q->n_window txq->entries, but we use q->n_bd tfds */ + iwlagn_unmap_tfd(trans, &txq->meta[idx], &tfd_tmp[rd_ptr], dma_dir); /* free SKB */ if (txq->skbs) { struct sk_buff *skb; - skb = txq->skbs[index]; + skb = txq->skbs[idx]; /* Can be called from irqs-disabled context * If skb is not NULL, it means that the whole queue is being @@ -270,7 +276,7 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, */ if (skb) { iwl_op_mode_free_skb(trans->op_mode, skb); - txq->skbs[index] = NULL; + txq->skbs[idx] = NULL; } } } @@ -1100,7 +1106,7 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, iwlagn_txq_inval_byte_cnt_tbl(trans, txq); - iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr, DMA_TO_DEVICE); + iwlagn_txq_free_tfd(trans, txq, DMA_TO_DEVICE); freed++; } return freed; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 66df0166cfd..6eac984b2d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -430,9 +430,7 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id) spin_lock_bh(&txq->lock); while (q->write_ptr != q->read_ptr) { - /* The read_ptr needs to bound by q->n_window */ - iwlagn_txq_free_tfd(trans, txq, get_cmd_index(q, q->read_ptr), - dma_dir); + iwlagn_txq_free_tfd(trans, txq, dma_dir); q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); } spin_unlock_bh(&txq->lock); From adf264357dfa43d9c3b79f3885a7dd4b962b36e1 Mon Sep 17 00:00:00 2001 From: Meenakshi Venkataraman Date: Tue, 5 Jun 2012 20:24:37 +0200 Subject: [PATCH 0275/2357] iwlwifi: use correct supported firmware for 6035 and 6000g2 commit d2c8b15d0cb486f4938ba7f2af349d9d1220cb10 upstream. My patch iwlwifi: use correct released ucode version did not correctly report supported firmware for the 6035 device. This patch fixes it. The minimum supported firmware version for 6035 is v6. Also correct the minimum supported firmware version for the 6000g2 series of devices. Signed-off-by: Meenakshi Venkataraman Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-6000.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 9f71b85f591..c0cfa4e652c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -49,17 +49,20 @@ #define IWL6000_UCODE_API_MAX 6 #define IWL6050_UCODE_API_MAX 5 #define IWL6000G2_UCODE_API_MAX 6 +#define IWL6035_UCODE_API_MAX 6 /* Oldest version we won't warn about */ #define IWL6000_UCODE_API_OK 4 #define IWL6000G2_UCODE_API_OK 5 #define IWL6050_UCODE_API_OK 5 #define IWL6000G2B_UCODE_API_OK 6 +#define IWL6035_UCODE_API_OK 6 /* Lowest firmware API version supported */ #define IWL6000_UCODE_API_MIN 4 #define IWL6050_UCODE_API_MIN 4 -#define IWL6000G2_UCODE_API_MIN 4 +#define IWL6000G2_UCODE_API_MIN 5 +#define IWL6035_UCODE_API_MIN 6 #define IWL6000_FW_PRE "iwlwifi-6000-" #define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode" @@ -425,9 +428,25 @@ const struct iwl_cfg iwl6030_2bg_cfg = { IWL_DEVICE_6030, }; +#define IWL_DEVICE_6035 \ + .fw_name_pre = IWL6030_FW_PRE, \ + .ucode_api_max = IWL6035_UCODE_API_MAX, \ + .ucode_api_ok = IWL6035_UCODE_API_OK, \ + .ucode_api_min = IWL6035_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ + .lib = &iwl6030_lib, \ + .base_params = &iwl6000_g2_base_params, \ + .bt_params = &iwl6000_bt_params, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .adv_pm = true + const struct iwl_cfg iwl6035_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", - IWL_DEVICE_6030, + IWL_DEVICE_6035, .ht_params = &iwl6000_ht_params, }; From 75862961e9b445a9bfce25b9da70ef930a857762 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 30 May 2012 10:36:12 +0200 Subject: [PATCH 0276/2357] iwlwifi: fix TX power antenna access commit a5fdde28b4f5fb756032e7ad2c6fcdcffde20958 upstream. Since my commit iwlwifi: use valid TX/RX antenna from hw_params the config values are pure overrides, not the real values for all hardware. Therefore, the EEPROM TX power reading code checks the wrong values, it should check the hw_params values. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 23cea42b949..79dddc481da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -513,28 +513,28 @@ static int iwl_find_otp_image(struct iwl_trans *trans, * iwl_get_max_txpower_avg - get the highest tx power from all chains. * find the highest tx power from all chains for the channel */ -static s8 iwl_get_max_txpower_avg(const struct iwl_cfg *cfg, +static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element, s8 *max_txpower_in_half_dbm) { s8 max_txpower_avg = 0; /* (dBm) */ /* Take the highest tx power from any valid chains */ - if ((cfg->valid_tx_ant & ANT_A) && + if ((hw_params(priv).valid_tx_ant & ANT_A) && (enhanced_txpower[element].chain_a_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].chain_a_max; - if ((cfg->valid_tx_ant & ANT_B) && + if ((hw_params(priv).valid_tx_ant & ANT_B) && (enhanced_txpower[element].chain_b_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].chain_b_max; - if ((cfg->valid_tx_ant & ANT_C) && + if ((hw_params(priv).valid_tx_ant & ANT_C) && (enhanced_txpower[element].chain_c_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].chain_c_max; - if (((cfg->valid_tx_ant == ANT_AB) | - (cfg->valid_tx_ant == ANT_BC) | - (cfg->valid_tx_ant == ANT_AC)) && + if (((hw_params(priv).valid_tx_ant == ANT_AB) | + (hw_params(priv).valid_tx_ant == ANT_BC) | + (hw_params(priv).valid_tx_ant == ANT_AC)) && (enhanced_txpower[element].mimo2_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].mimo2_max; - if ((cfg->valid_tx_ant == ANT_ABC) && + if ((hw_params(priv).valid_tx_ant == ANT_ABC) && (enhanced_txpower[element].mimo3_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].mimo3_max; @@ -637,7 +637,7 @@ static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) ((txp->delta_20_in_40 & 0xf0) >> 4), (txp->delta_20_in_40 & 0x0f)); - max_txp_avg = iwl_get_max_txpower_avg(cfg(priv), txp_array, idx, + max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx, &max_txp_avg_halfdbm); /* From f5f062e1be5fdafaa68c4dd97a2d64ef78458b37 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 4 Jun 2012 23:24:51 -0700 Subject: [PATCH 0277/2357] target: Return error to initiator if SET TARGET PORT GROUPS emulation fails commit 59e4f541baf728dbb426949bfa9f6862387ffd0e upstream. The error paths in target_emulate_set_target_port_groups() are all essentially "rc = -EINVAL; goto out;" but the code at "out:" ignores rc and always returns success. This means that even if eg explicit ALUA is turned off, the initiator will always see a good SCSI status for SET TARGET PORT GROUPS. Fix this by returning rc as is intended. It appears this bug was added by the following patch: commit 05d1c7c0d0db4cc25548d9aadebb416888a82327 Author: Andy Grover Date: Wed Jul 20 19:13:28 2011 +0000 target: Make all control CDBs scatter-gather Signed-off-by: Roland Dreier Cc: Andy Grover Signed-off-by: Nicholas Bellinger [bwh: Backported to 3.2: we have transport_complete_task() and not target_complete_cmd()] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_alua.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index c7746a3339d..f30e124874b 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -351,9 +351,11 @@ int target_emulate_set_target_port_groups(struct se_task *task) out: transport_kunmap_data_sg(cmd); - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - return 0; + if (!rc) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return rc; } static inline int core_alua_state_nonoptimized( From ff74ae50f01ee67764564815c023c362c87ce18b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 22 Jun 2012 11:37:50 -0700 Subject: [PATCH 0278/2357] Linux 3.4.4 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a0804c6de69..058320d6bc5 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 3 +SUBLEVEL = 4 EXTRAVERSION = NAME = Saber-toothed Squirrel From c84299b8ddb3de60ac857aee396d709346eed27f Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 31 May 2012 16:40:06 +0200 Subject: [PATCH 0279/2357] Tools: hv: verify origin of netlink connector message commit bcc2c9c3fff859e0eb019fe6fec26f9b8eba795c upstream. The SuSE security team suggested to use recvfrom instead of recv to be certain that the connector message is originated from kernel. CVE-2012-2669 Signed-off-by: Olaf Hering Signed-off-by: Marcus Meissner Signed-off-by: Sebastian Krahmer Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 146fd6147e8..d9834b36294 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -701,14 +701,18 @@ int main(void) pfd.fd = fd; while (1) { + struct sockaddr *addr_p = (struct sockaddr *) &addr; + socklen_t addr_l = sizeof(addr); pfd.events = POLLIN; pfd.revents = 0; poll(&pfd, 1, -1); - len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0); + len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0, + addr_p, &addr_l); - if (len < 0) { - syslog(LOG_ERR, "recv failed; error:%d", len); + if (len < 0 || addr.nl_pid) { + syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", + addr.nl_pid, errno, strerror(errno)); close(fd); return -1; } From c1389ce1e02c1e1f617d7cf70852ad5d9f9ef355 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 18 Jun 2012 15:01:50 -0600 Subject: [PATCH 0280/2357] ARM: tegra: make tegra_cpu_reset_handler_enable() __init commit 6355f25ed965421725d92cf719fc63008690ca1c upstream. This solves a section mismatch warning. I hadn't noticed this before, because my compiler was inlining tegra_cpu_reset_handler_enable() inside tegra_cpu_reset_handler_init(), which is already __init, but I switched compilers and it stopped doing that. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-tegra/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c index 4d6a2ee99c3..5beb7ebe294 100644 --- a/arch/arm/mach-tegra/reset.c +++ b/arch/arm/mach-tegra/reset.c @@ -33,7 +33,7 @@ static bool is_enabled; -static void tegra_cpu_reset_handler_enable(void) +static void __init tegra_cpu_reset_handler_enable(void) { void __iomem *iram_base = IO_ADDRESS(TEGRA_IRAM_RESET_BASE); void __iomem *evp_cpu_reset = From e4508b4cb7402c66e6f5a16df954bdff20b673b9 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Mon, 25 Jun 2012 19:49:28 +0200 Subject: [PATCH 0281/2357] ALSA: hda - Add Realtek ALC280 codec support commit befae82e2906cb7155020876a531b0b8c6c8d8c8 upstream. This chip looks very similar to ALC269 and ALC27* variants. The bug reporter has verified that sound was working after this patch had been applied. BugLink: https://bugs.launchpad.net/bugs/1017017 Tested-by: Richard Crossley Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e56c2c817e0..c43264f5981 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6976,6 +6976,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 }, { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 }, { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 }, + { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, From 354e550aab1074eaa87f0db4404f0edeab3ec591 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 26 Jun 2012 15:00:20 +0200 Subject: [PATCH 0282/2357] ALSA: hda - Fix memory leaks at module unload commit 59cad16bc6deb85bd2a464da92bbaae289f0286f upstream. Some caches aren't released properly at module unloading time. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_codec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 841475cc13b..926b455392c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1192,6 +1192,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) { if (!codec) return; + snd_hda_jack_tbl_clear(codec); restore_init_pincfgs(codec); #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); @@ -1200,6 +1201,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) list_del(&codec->list); snd_array_free(&codec->mixers); snd_array_free(&codec->nids); + snd_array_free(&codec->cvt_setups); snd_array_free(&codec->conn_lists); snd_array_free(&codec->spdif_out); codec->bus->caddr_tbl[codec->addr] = NULL; From 9fe9217b874769f0b42bc4f8de4fc3df785e9ef3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Jun 2012 07:30:39 +0200 Subject: [PATCH 0283/2357] ALSA: hda - Fix power-map regression for HP dv6 & co commit 6e1c39c6b00d9141a82c231ba7c5e5b1716974b2 upstream. The recent fix for power-map controls (commit b0791dda813) caused regressions on some other HP laptops. They have fixed pins but these pins are exposed as jack-detectable. Thus the driver tries to control the power-map dynamically per jack detection where it never gets on. This patch corrects the condition check for fixed pins so that the power-map is set always for these pins. NOTE: this is no simple backport from 3.5 kernel. Since 3.5 kernel had significant code change in the relevant part, I fixed this differently. BugLink: http://bugs.launchpad.net/bugs/1013183 Reported-by: Luis Henriques Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2cb1e08f962..7494fbc1f26 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4388,7 +4388,7 @@ static int stac92xx_init(struct hda_codec *codec) AC_PINCTL_IN_EN); for (i = 0; i < spec->num_pwrs; i++) { hda_nid_t nid = spec->pwr_nids[i]; - int pinctl, def_conf; + unsigned int pinctl, def_conf; /* power on when no jack detection is available */ /* or when the VREF is used for controlling LED */ @@ -4415,7 +4415,7 @@ static int stac92xx_init(struct hda_codec *codec) def_conf = get_defcfg_connect(def_conf); /* skip any ports that don't have jacks since presence * detection is useless */ - if (def_conf != AC_JACK_PORT_NONE && + if (def_conf != AC_JACK_PORT_COMPLEX || !is_jack_detectable(codec, nid)) { stac_toggle_power_map(codec, nid, 1); continue; From 3f8d5752c3926dab96e00bfb5d0c8e2f015a975e Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 4 Jun 2012 16:27:54 +0000 Subject: [PATCH 0284/2357] powerpc/ftrace: Do not trace restore_interrupts() commit 2d773aa4810d4a612d1c879faacc38594cc3f841 upstream. As I was adding code that affects all archs, I started testing function tracer against PPC64 and found that it currently locks up with 3.4 kernel. I figured it was due to tracing a function that shouldn't be, so I went through the following process to bisect to find the culprit: cat /debug/tracing/available_filter_functions > t num=`wc -l t` sed -ne "1,${num}p" t > t1 let num=num+1 sed -ne "${num},$p" t > t2 cat t1 > /debug/tracing/set_ftrace_filter echo function /debug/tracing/current_tracer It finally came down to this function: restore_interrupts() I'm not sure why this locks up the system. It just seems to prevent scheduling from occurring. Interrupts seem to still work, as I can ping the box. But all user processes freeze. When restore_interrupts() is not traced, function tracing works fine. Signed-off-by: Steven Rostedt Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 641da9e868c..64eec59193f 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -277,7 +277,7 @@ EXPORT_SYMBOL(arch_local_irq_restore); * NOTE: This is called with interrupts hard disabled but not marked * as such in paca->irq_happened, so we need to resync this. */ -void restore_interrupts(void) +void notrace restore_interrupts(void) { if (irqs_disabled()) { local_paca->irq_happened |= PACA_IRQ_HARD_DIS; From 3fb55c2a681f7618c828b5853abc27f86d7e9fe1 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 19 Jun 2012 20:01:45 +0000 Subject: [PATCH 0285/2357] powerpc: Fix uninitialised error in numa.c commit 82b2521d257b5c0efd51821cf5fa306e53bbb6ba upstream. chroma_defconfig currently gives me this with gcc 4.6: arch/powerpc/mm/numa.c:638:13: error: 'dm' may be used uninitialized in this function [-Werror=uninitialized] It's a bogus warning/error since of_get_drconf_memory() only writes it anyway. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/numa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index b6edbb3b4a5..6e8f677f564 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -635,7 +635,7 @@ static inline int __init read_usm_ranges(const u32 **usm) */ static void __init parse_drconf_memory(struct device_node *memory) { - const u32 *dm, *usm; + const u32 *uninitialized_var(dm), *usm; unsigned int n, rc, ranges, is_kexec_kdump = 0; unsigned long lmb_size, base, size, sz; int nid; From 8057f6c444173496806618f2fe173c2f02fb3995 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 26 Jun 2012 21:26:37 +0000 Subject: [PATCH 0286/2357] powerpc/pseries: Fix software invalidate TCE commit bc6dc752f35488160ffac07ae91bed1bddaea32a upstream. The following added support for powernv but broke pseries/BML: 1f1616e powerpc/powernv: Add TCE SW invalidation support TCE_PCI_SW_INVAL was split into FREE and CREATE flags but the tests in the pseries code were not updated to reflect this. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 0915b1ad66c..2d311c0caf8 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -106,7 +106,7 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index, tcep++; } - if (tbl->it_type == TCE_PCI_SWINV_CREATE) + if (tbl->it_type & TCE_PCI_SWINV_CREATE) tce_invalidate_pSeries_sw(tbl, tces, tcep - 1); return 0; } @@ -121,7 +121,7 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) while (npages--) *(tcep++) = 0; - if (tbl->it_type == TCE_PCI_SWINV_FREE) + if (tbl->it_type & TCE_PCI_SWINV_FREE) tce_invalidate_pSeries_sw(tbl, tces, tcep - 1); } From ee1602ff18545ddf7f19638fb350e4eec2030c0d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 27 Jun 2012 13:13:52 +0000 Subject: [PATCH 0287/2357] powerpc: check_and_cede_processor() never cedes commit 0b17ba7258db83cd02da560884e053b85de371f2 upstream. Commit f948501b36c6 ("Make hard_irq_disable() actually hard-disable interrupts") caused check_and_cede_processor to stop working. ->irq_happened will never be zero right after a hard_irq_disable so the compiler removes the call to cede_processor completely. The bug was introduced back in the lazy interrupt handling rework of 3.4 but was hidden until recently because hard_irq_disable did nothing. This issue will eventually appear in 3.4 stable since the hard_irq_disable fix is marked stable, so mark this one for stable too. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/hw_irq.h | 5 +++++ arch/powerpc/platforms/pseries/processor_idle.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 102abd6dbc0..6627a3e1b13 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -102,6 +102,11 @@ static inline void hard_irq_disable(void) /* include/linux/interrupt.h needs hard_irq_disable to be a macro */ #define hard_irq_disable hard_irq_disable +static inline bool lazy_irq_pending(void) +{ + return !!(get_paca()->irq_happened & ~PACA_IRQ_HARD_DIS); +} + /* * This is called by asynchronous interrupts to conditionally * re-enable hard interrupts when soft-disabled after having diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 41a34bc4a9a..e61483e8e96 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -106,7 +106,7 @@ static void check_and_cede_processor(void) * we first hard disable then check. */ hard_irq_disable(); - if (get_paca()->irq_happened == 0) + if (!lazy_irq_pending()) cede_processor(); } From 7abbc8e46545b3c98734484b4fbfaf849ed29c27 Mon Sep 17 00:00:00 2001 From: Jose Miguel Goncalves Date: Sat, 12 May 2012 06:11:49 +0900 Subject: [PATCH 0288/2357] ARM: SAMSUNG: Fix for S3C2412 EBI memory mapping commit 3dca938656c7b0ff6b0717a5dde0f5f45e592be5 upstream. While upgrading the kernel on a S3C2412 based board I've noted that it was impossible to boot the board with a 2.6.32 or upper kernel. I've tracked down the problem to the EBI virtual memory mapping that is in conflict with the IO mapping definition in arch/arm/mach-s3c24xx/s3c2412.c. Signed-off-by: Jose Miguel Goncalves Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-samsung/include/plat/map-s3c.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-samsung/include/plat/map-s3c.h b/arch/arm/plat-samsung/include/plat/map-s3c.h index 7d048759b77..c0c70a895ca 100644 --- a/arch/arm/plat-samsung/include/plat/map-s3c.h +++ b/arch/arm/plat-samsung/include/plat/map-s3c.h @@ -22,7 +22,7 @@ #define S3C24XX_VA_WATCHDOG S3C_VA_WATCHDOG #define S3C2412_VA_SSMC S3C_ADDR_CPU(0x00000000) -#define S3C2412_VA_EBI S3C_ADDR_CPU(0x00010000) +#define S3C2412_VA_EBI S3C_ADDR_CPU(0x00100000) #define S3C2410_PA_UART (0x50000000) #define S3C24XX_PA_UART S3C2410_PA_UART From 45500e587ad1c2ea809c52961675c4eb9befcab5 Mon Sep 17 00:00:00 2001 From: Jonghwan Choi Date: Wed, 20 Jun 2012 17:05:37 +0900 Subject: [PATCH 0289/2357] ARM: SAMSUNG: Should check for IS_ERR(clk) instead of NULL commit a5d8f4765f0e92ef027492a8cb979c5b8d45f2c3 upstream. On the error condition clk_get() returns ERR_PTR(). Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-samsung/include/plat/watchdog-reset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-samsung/include/plat/watchdog-reset.h b/arch/arm/plat-samsung/include/plat/watchdog-reset.h index f19aff19205..bc4db9b04e3 100644 --- a/arch/arm/plat-samsung/include/plat/watchdog-reset.h +++ b/arch/arm/plat-samsung/include/plat/watchdog-reset.h @@ -25,7 +25,7 @@ static inline void arch_wdt_reset(void) __raw_writel(0, S3C2410_WTCON); /* disable watchdog, to be safe */ - if (s3c2410_wdtclk) + if (!IS_ERR(s3c2410_wdtclk)) clk_enable(s3c2410_wdtclk); /* put initial values into count and data */ From 937bff779cd840aca9f74dd7f2d43dafad3979bb Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 27 Jun 2012 17:28:57 +0100 Subject: [PATCH 0290/2357] ARM: 7438/1: fill possible PMD empty section gaps commit 19b52abe3c5d759661500a1dc810924369b2ad46 upstream. On ARM with the 2-level page table format, a PMD entry is represented by two consecutive section entries covering 2MB of virtual space. However, static mappings always were allowed to use separate 1MB section entries. This means in practice that a static mapping may create half populated PMDs via create_mapping(). Since commit 0536bdf33f (ARM: move iotable mappings within the vmalloc region) those static mappings are located in the vmalloc area. We must ensure no such half populated PMDs are accessible once vmalloc() or ioremap() start looking at the vmalloc area for nearby free virtual address ranges, or various things leading to a kernel crash will happen. Signed-off-by: Nicolas Pitre Reported-by: Santosh Shilimkar Tested-by: "R, Sricharan" Reviewed-by: Catalin Marinas Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/mm/mmu.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index aa78de8bfdd..75f9f9d6709 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -783,6 +783,79 @@ void __init iotable_init(struct map_desc *io_desc, int nr) } } +#ifndef CONFIG_ARM_LPAE + +/* + * The Linux PMD is made of two consecutive section entries covering 2MB + * (see definition in include/asm/pgtable-2level.h). However a call to + * create_mapping() may optimize static mappings by using individual + * 1MB section mappings. This leaves the actual PMD potentially half + * initialized if the top or bottom section entry isn't used, leaving it + * open to problems if a subsequent ioremap() or vmalloc() tries to use + * the virtual space left free by that unused section entry. + * + * Let's avoid the issue by inserting dummy vm entries covering the unused + * PMD halves once the static mappings are in place. + */ + +static void __init pmd_empty_section_gap(unsigned long addr) +{ + struct vm_struct *vm; + + vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm)); + vm->addr = (void *)addr; + vm->size = SECTION_SIZE; + vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; + vm->caller = pmd_empty_section_gap; + vm_area_add_early(vm); +} + +static void __init fill_pmd_gaps(void) +{ + struct vm_struct *vm; + unsigned long addr, next = 0; + pmd_t *pmd; + + /* we're still single threaded hence no lock needed here */ + for (vm = vmlist; vm; vm = vm->next) { + if (!(vm->flags & VM_ARM_STATIC_MAPPING)) + continue; + addr = (unsigned long)vm->addr; + if (addr < next) + continue; + + /* + * Check if this vm starts on an odd section boundary. + * If so and the first section entry for this PMD is free + * then we block the corresponding virtual address. + */ + if ((addr & ~PMD_MASK) == SECTION_SIZE) { + pmd = pmd_off_k(addr); + if (pmd_none(*pmd)) + pmd_empty_section_gap(addr & PMD_MASK); + } + + /* + * Then check if this vm ends on an odd section boundary. + * If so and the second section entry for this PMD is empty + * then we block the corresponding virtual address. + */ + addr += vm->size; + if ((addr & ~PMD_MASK) == SECTION_SIZE) { + pmd = pmd_off_k(addr) + 1; + if (pmd_none(*pmd)) + pmd_empty_section_gap(addr); + } + + /* no need to look at any vm entry until we hit the next PMD */ + next = (addr + PMD_SIZE - 1) & PMD_MASK; + } +} + +#else +#define fill_pmd_gaps() do { } while (0) +#endif + static void * __initdata vmalloc_min = (void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET); @@ -1064,6 +1137,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc) */ if (mdesc->map_io) mdesc->map_io(); + fill_pmd_gaps(); /* * Finally flush the caches and tlb to ensure that we're in a From 9b385370031c7880d19ce46849d3768aa30b3e09 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 25 Jun 2012 13:33:11 +0000 Subject: [PATCH 0291/2357] powerpc/kvm: sldi should be sld commit 2f584a146a2965b82fce89b8d2f95dc5cfe468d0 upstream. Since we are taking a registers, this should never have been an sldi. Talking to paulus offline, this is the correct fix. Was introduced by: commit 19ccb76a1938ab364a412253daec64613acbf3df Author: Paul Mackerras Date: Sat Jul 23 17:42:46 2011 +1000 Talking to paulus, this shouldn't be a literal. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index b70bf22a3ff..24b23a4307b 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -776,7 +776,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) lwz r3,VCORE_NAPPING_THREADS(r5) lwz r4,VCPU_PTID(r9) li r0,1 - sldi r0,r0,r4 + sld r0,r0,r4 andc. r3,r3,r0 /* no sense IPI'ing ourselves */ beq 43f mulli r4,r4,PACA_SIZE /* get paca for thread 0 */ From 7e9356ed7ba29f1f76d7b5fae6b3c9f128663741 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 28 Jun 2012 19:28:57 +0000 Subject: [PATCH 0292/2357] powerpc/xmon: Use cpumask iterator to avoid warning commit bc1d7702910c7c7e88eb60b58429dbfe293683ce upstream. We have a bug report where the kernel hits a warning in the cpumask code: WARNING: at include/linux/cpumask.h:107 Which is: WARN_ON_ONCE(cpu >= nr_cpumask_bits); The backtrace is: cpu_cmd cmds xmon_core xmon die xmon is iterating through 0 to NR_CPUS. I'm not sure why we are still open coding this but iterating above nr_cpu_ids is definitely a bug. This patch iterates through all possible cpus, in case we issue a system reset and CPUs in an offline state call in. Perhaps the old code was trying to handle CPUs that were in the partition but were never started (eg kexec into a kernel with an nr_cpus= boot option). They are going to die way before we get into xmon since we haven't set any kernel state up for them. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/xmon/xmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 0f3ab06d222..eab3492a45c 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -971,7 +971,7 @@ static int cpu_cmd(void) /* print cpus waiting or in xmon */ printf("cpus stopped:"); count = 0; - for (cpu = 0; cpu < NR_CPUS; ++cpu) { + for_each_possible_cpu(cpu) { if (cpumask_test_cpu(cpu, &cpus_in_xmon)) { if (count == 0) printf(" %x", cpu); From 8f5b330048b06ca0e2ffa88300922808ebc2b93f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 25 May 2012 09:29:12 -0300 Subject: [PATCH 0293/2357] media: smsusb: add autodetection support for USB ID 2040:f5a0 commit 3e1141e2ce5667301a74ca2ef396d9bd5e995f7f upstream. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb/siano/smsusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index 63c004a25e0..664e460f247 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -544,6 +544,8 @@ static const struct usb_device_id smsusb_id_table[] __devinitconst = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0xc0a0), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xf5a0), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { } /* Terminating entry */ }; From 19d07e884b7fd22f92eb8939556dcbf55df1982c Mon Sep 17 00:00:00 2001 From: Hiroaki SHIMODA Date: Wed, 30 May 2012 12:24:39 +0000 Subject: [PATCH 0294/2357] bql: Fix POSDIFF() to integer overflow aware. [ Upstream commit 0cfd32b736ae0c36b42697584811042726c07cba ] POSDIFF() fails to take into account integer overflow case. Signed-off-by: Hiroaki SHIMODA Cc: Tom Herbert Cc: Eric Dumazet Cc: Denys Fedoryshchenko Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- lib/dynamic_queue_limits.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c index 6ab4587d052..c87eb76f2fd 100644 --- a/lib/dynamic_queue_limits.c +++ b/lib/dynamic_queue_limits.c @@ -10,7 +10,7 @@ #include #include -#define POSDIFF(A, B) ((A) > (B) ? (A) - (B) : 0) +#define POSDIFF(A, B) ((int)((A) - (B)) > 0 ? (A) - (B) : 0) /* Records completed count and recalculates the queue limit */ void dql_completed(struct dql *dql, unsigned int count) From 1414a53d956340ca8b1b27e05ab94ba63e82ed97 Mon Sep 17 00:00:00 2001 From: Hiroaki SHIMODA Date: Wed, 30 May 2012 12:25:19 +0000 Subject: [PATCH 0295/2357] bql: Avoid unneeded limit decrement. [ Upstream commit 25426b794efdc70dde7fd3134dc56fac3e7d562d ] When below pattern is observed, TIME dql_queued() dql_completed() | a) initial state | | b) X bytes queued V c) Y bytes queued d) X bytes completed e) Z bytes queued f) Y bytes completed a) dql->limit has already some value and there is no in-flight packet. b) X bytes queued. c) Y bytes queued and excess limit. d) X bytes completed and dql->prev_ovlimit is set and also dql->prev_num_queued is set Y. e) Z bytes queued. f) Y bytes completed. inprogress and prev_inprogress are true. At f), according to the comment, all_prev_completed becomes true and limit should be increased. But POSDIFF() ignores (completed == dql->prev_num_queued) case, so limit is decreased. Signed-off-by: Hiroaki SHIMODA Cc: Tom Herbert Cc: Eric Dumazet Cc: Denys Fedoryshchenko Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- lib/dynamic_queue_limits.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c index c87eb76f2fd..0fafa77f403 100644 --- a/lib/dynamic_queue_limits.c +++ b/lib/dynamic_queue_limits.c @@ -11,12 +11,14 @@ #include #define POSDIFF(A, B) ((int)((A) - (B)) > 0 ? (A) - (B) : 0) +#define AFTER_EQ(A, B) ((int)((A) - (B)) >= 0) /* Records completed count and recalculates the queue limit */ void dql_completed(struct dql *dql, unsigned int count) { unsigned int inprogress, prev_inprogress, limit; - unsigned int ovlimit, all_prev_completed, completed; + unsigned int ovlimit, completed; + bool all_prev_completed; /* Can't complete more than what's in queue */ BUG_ON(count > dql->num_queued - dql->num_completed); @@ -26,7 +28,7 @@ void dql_completed(struct dql *dql, unsigned int count) ovlimit = POSDIFF(dql->num_queued - dql->num_completed, limit); inprogress = dql->num_queued - completed; prev_inprogress = dql->prev_num_queued - dql->num_completed; - all_prev_completed = POSDIFF(completed, dql->prev_num_queued); + all_prev_completed = AFTER_EQ(completed, dql->prev_num_queued); if ((ovlimit && !inprogress) || (dql->prev_ovlimit && all_prev_completed)) { From 4f4bdaeb40df95499c1ee7ea3fbca9d76174a59e Mon Sep 17 00:00:00 2001 From: Hiroaki SHIMODA Date: Wed, 30 May 2012 12:25:37 +0000 Subject: [PATCH 0296/2357] bql: Avoid possible inconsistent calculation. [ Upstream commit 914bec1011a25f65cdc94988a6f974bfb9a3c10d ] dql->num_queued could change while processing dql_completed(). To provide consistent calculation, added an on stack variable. Signed-off-by: Hiroaki SHIMODA Cc: Tom Herbert Cc: Eric Dumazet Cc: Denys Fedoryshchenko Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- lib/dynamic_queue_limits.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c index 0fafa77f403..0777c5a45fa 100644 --- a/lib/dynamic_queue_limits.c +++ b/lib/dynamic_queue_limits.c @@ -17,16 +17,18 @@ void dql_completed(struct dql *dql, unsigned int count) { unsigned int inprogress, prev_inprogress, limit; - unsigned int ovlimit, completed; + unsigned int ovlimit, completed, num_queued; bool all_prev_completed; + num_queued = ACCESS_ONCE(dql->num_queued); + /* Can't complete more than what's in queue */ - BUG_ON(count > dql->num_queued - dql->num_completed); + BUG_ON(count > num_queued - dql->num_completed); completed = dql->num_completed + count; limit = dql->limit; - ovlimit = POSDIFF(dql->num_queued - dql->num_completed, limit); - inprogress = dql->num_queued - completed; + ovlimit = POSDIFF(num_queued - dql->num_completed, limit); + inprogress = num_queued - completed; prev_inprogress = dql->prev_num_queued - dql->num_completed; all_prev_completed = AFTER_EQ(completed, dql->prev_num_queued); @@ -106,7 +108,7 @@ void dql_completed(struct dql *dql, unsigned int count) dql->prev_ovlimit = ovlimit; dql->prev_last_obj_cnt = dql->last_obj_cnt; dql->num_completed = completed; - dql->prev_num_queued = dql->num_queued; + dql->prev_num_queued = num_queued; } EXPORT_SYMBOL(dql_completed); From 31fab24bd9cdb9733383cbf9732cda1649f2a760 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 May 2012 21:18:10 +0000 Subject: [PATCH 0297/2357] net: sock: validate data_len before allocating skb in sock_alloc_send_pskb() [ Upstream commit cc9b17ad29ecaa20bfe426a8d4dbfb94b13ff1cc ] We need to validate the number of pages consumed by data_len, otherwise frags array could be overflowed by userspace. So this patch validate data_len and return -EMSGSIZE when data_len may occupies more frags than MAX_SKB_FRAGS. Signed-off-by: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/sock.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index b2e14c07d92..0f8402ea434 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1600,6 +1600,11 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len, gfp_t gfp_mask; long timeo; int err; + int npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + + err = -EMSGSIZE; + if (npages > MAX_SKB_FRAGS) + goto failure; gfp_mask = sk->sk_allocation; if (gfp_mask & __GFP_WAIT) @@ -1618,14 +1623,12 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len, if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { skb = alloc_skb(header_len, gfp_mask); if (skb) { - int npages; int i; /* No pages, we're done... */ if (!data_len) break; - npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT; skb->truesize += data_len; skb_shinfo(skb)->nr_frags = npages; for (i = 0; i < npages; i++) { From 6fc5186c0628a5dfcfdbc9355bad225613fa7618 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 1 Jun 2012 05:54:56 +0000 Subject: [PATCH 0298/2357] cipso: handle CIPSO options correctly when NetLabel is disabled [ Upstream commit 20e2a86485967c385d7c7befc1646e4d1d39362e ] When NetLabel is not enabled, e.g. CONFIG_NETLABEL=n, and the system receives a CIPSO tagged packet it is dropped (cipso_v4_validate() returns non-zero). In most cases this is the correct and desired behavior, however, in the case where we are simply forwarding the traffic, e.g. acting as a network bridge, this becomes a problem. This patch fixes the forwarding problem by providing the basic CIPSO validation code directly in ip_options_compile() without the need for the NetLabel or CIPSO code. The new validation code can not perform any of the CIPSO option label/value verification that cipso_v4_validate() does, but it can verify the basic CIPSO option format. The behavior when NetLabel is enabled is unchanged. Signed-off-by: Paul Moore Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/cipso_ipv4.h | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index 9808877c2ab..a7a683e30b6 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h @@ -42,6 +42,7 @@ #include #include #include +#include /* known doi values */ #define CIPSO_V4_DOI_UNKNOWN 0x00000000 @@ -285,7 +286,33 @@ static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb, static inline int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) { - return -ENOSYS; + unsigned char *opt = *option; + unsigned char err_offset = 0; + u8 opt_len = opt[1]; + u8 opt_iter; + + if (opt_len < 8) { + err_offset = 1; + goto out; + } + + if (get_unaligned_be32(&opt[2]) == 0) { + err_offset = 2; + goto out; + } + + for (opt_iter = 6; opt_iter < opt_len;) { + if (opt[opt_iter + 1] > (opt_len - opt_iter)) { + err_offset = opt_iter + 1; + goto out; + } + opt_iter += opt[opt_iter + 1]; + } + +out: + *option = opt + err_offset; + return err_offset; + } #endif /* CONFIG_NETLABEL */ From 0440cf6d8187e69ef2eb52db5f7690f1da2a2c1c Mon Sep 17 00:00:00 2001 From: Devendra Naga Date: Thu, 31 May 2012 01:51:20 +0000 Subject: [PATCH 0299/2357] r8169: call netif_napi_del at errpaths and at driver unload [ Upstream commit ad1be8d345416a794dea39761a374032aa471a76 ] when register_netdev fails, the init'ed NAPIs by netif_napi_add must be deleted with netif_napi_del, and also when driver unloads, it should delete the NAPI before unregistering netdevice using unregister_netdev. Signed-off-by: Devendra Naga Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index ce6b44d1f25..161e0451747 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5966,6 +5966,8 @@ static void __devexit rtl_remove_one(struct pci_dev *pdev) cancel_work_sync(&tp->wk.work); + netif_napi_del(&tp->napi); + unregister_netdev(dev); rtl_release_firmware(tp); @@ -6288,6 +6290,7 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; err_out_msi_4: + netif_napi_del(&tp->napi); rtl_disable_msi(pdev, tp); iounmap(ioaddr); err_out_free_res_3: From f375a27c17c033dc9503b12b8379055fd59110ba Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 4 Jun 2012 00:18:19 +0000 Subject: [PATCH 0300/2357] drop_monitor: dont sleep in atomic context [ Upstream commit bec4596b4e6770c7037f21f6bd27567b152dc0d6 ] drop_monitor calls several sleeping functions while in atomic context. BUG: sleeping function called from invalid context at mm/slub.c:943 in_atomic(): 1, irqs_disabled(): 0, pid: 2103, name: kworker/0:2 Pid: 2103, comm: kworker/0:2 Not tainted 3.5.0-rc1+ #55 Call Trace: [] __might_sleep+0xca/0xf0 [] kmem_cache_alloc_node+0x1b3/0x1c0 [] ? queue_delayed_work_on+0x11c/0x130 [] __alloc_skb+0x4b/0x230 [] ? reset_per_cpu_data+0x160/0x160 [drop_monitor] [] reset_per_cpu_data+0x2f/0x160 [drop_monitor] [] send_dm_alert+0x4b/0xb0 [drop_monitor] [] process_one_work+0x130/0x4c0 [] worker_thread+0x159/0x360 [] ? manage_workers.isra.27+0x240/0x240 [] kthread+0x93/0xa0 [] kernel_thread_helper+0x4/0x10 [] ? kthread_freezable_should_stop+0x80/0x80 [] ? gs_change+0xb/0xb Rework the logic to call the sleeping functions in right context. Use standard timer/workqueue api to let system chose any cpu to perform the allocation and netlink send. Also avoid a loop if reset_per_cpu_data() cannot allocate memory : use mod_timer() to wait 1/10 second before next try. Signed-off-by: Eric Dumazet Cc: Neil Horman Reviewed-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/drop_monitor.c | 102 +++++++++++++--------------------------- 1 file changed, 33 insertions(+), 69 deletions(-) diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index a7cad741df0..b856f87e63d 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -33,9 +33,6 @@ #define TRACE_ON 1 #define TRACE_OFF 0 -static void send_dm_alert(struct work_struct *unused); - - /* * Globals, our netlink socket pointer * and the work handle that will send up @@ -45,11 +42,10 @@ static int trace_state = TRACE_OFF; static DEFINE_MUTEX(trace_state_mutex); struct per_cpu_dm_data { - struct work_struct dm_alert_work; - struct sk_buff __rcu *skb; - atomic_t dm_hit_count; - struct timer_list send_timer; - int cpu; + spinlock_t lock; + struct sk_buff *skb; + struct work_struct dm_alert_work; + struct timer_list send_timer; }; struct dm_hw_stat_delta { @@ -75,13 +71,13 @@ static int dm_delay = 1; static unsigned long dm_hw_check_delta = 2*HZ; static LIST_HEAD(hw_stats_list); -static void reset_per_cpu_data(struct per_cpu_dm_data *data) +static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data) { size_t al; struct net_dm_alert_msg *msg; struct nlattr *nla; struct sk_buff *skb; - struct sk_buff *oskb = rcu_dereference_protected(data->skb, 1); + unsigned long flags; al = sizeof(struct net_dm_alert_msg); al += dm_hit_limit * sizeof(struct net_dm_drop_point); @@ -96,65 +92,40 @@ static void reset_per_cpu_data(struct per_cpu_dm_data *data) sizeof(struct net_dm_alert_msg)); msg = nla_data(nla); memset(msg, 0, al); - } else - schedule_work_on(data->cpu, &data->dm_alert_work); - - /* - * Don't need to lock this, since we are guaranteed to only - * run this on a single cpu at a time. - * Note also that we only update data->skb if the old and new skb - * pointers don't match. This ensures that we don't continually call - * synchornize_rcu if we repeatedly fail to alloc a new netlink message. - */ - if (skb != oskb) { - rcu_assign_pointer(data->skb, skb); - - synchronize_rcu(); - - atomic_set(&data->dm_hit_count, dm_hit_limit); + } else { + mod_timer(&data->send_timer, jiffies + HZ / 10); } + spin_lock_irqsave(&data->lock, flags); + swap(data->skb, skb); + spin_unlock_irqrestore(&data->lock, flags); + + return skb; } -static void send_dm_alert(struct work_struct *unused) +static void send_dm_alert(struct work_struct *work) { struct sk_buff *skb; - struct per_cpu_dm_data *data = &get_cpu_var(dm_cpu_data); + struct per_cpu_dm_data *data; - WARN_ON_ONCE(data->cpu != smp_processor_id()); + data = container_of(work, struct per_cpu_dm_data, dm_alert_work); - /* - * Grab the skb we're about to send - */ - skb = rcu_dereference_protected(data->skb, 1); + skb = reset_per_cpu_data(data); - /* - * Replace it with a new one - */ - reset_per_cpu_data(data); - - /* - * Ship it! - */ if (skb) genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL); - - put_cpu_var(dm_cpu_data); } /* * This is the timer function to delay the sending of an alert * in the event that more drops will arrive during the - * hysteresis period. Note that it operates under the timer interrupt - * so we don't need to disable preemption here + * hysteresis period. */ -static void sched_send_work(unsigned long unused) +static void sched_send_work(unsigned long _data) { - struct per_cpu_dm_data *data = &get_cpu_var(dm_cpu_data); + struct per_cpu_dm_data *data = (struct per_cpu_dm_data *)_data; - schedule_work_on(smp_processor_id(), &data->dm_alert_work); - - put_cpu_var(dm_cpu_data); + schedule_work(&data->dm_alert_work); } static void trace_drop_common(struct sk_buff *skb, void *location) @@ -164,33 +135,28 @@ static void trace_drop_common(struct sk_buff *skb, void *location) struct nlattr *nla; int i; struct sk_buff *dskb; - struct per_cpu_dm_data *data = &get_cpu_var(dm_cpu_data); - + struct per_cpu_dm_data *data; + unsigned long flags; - rcu_read_lock(); - dskb = rcu_dereference(data->skb); + local_irq_save(flags); + data = &__get_cpu_var(dm_cpu_data); + spin_lock(&data->lock); + dskb = data->skb; if (!dskb) goto out; - if (!atomic_add_unless(&data->dm_hit_count, -1, 0)) { - /* - * we're already at zero, discard this hit - */ - goto out; - } - nlh = (struct nlmsghdr *)dskb->data; nla = genlmsg_data(nlmsg_data(nlh)); msg = nla_data(nla); for (i = 0; i < msg->entries; i++) { if (!memcmp(&location, msg->points[i].pc, sizeof(void *))) { msg->points[i].count++; - atomic_inc(&data->dm_hit_count); goto out; } } - + if (msg->entries == dm_hit_limit) + goto out; /* * We need to create a new entry */ @@ -202,13 +168,11 @@ static void trace_drop_common(struct sk_buff *skb, void *location) if (!timer_pending(&data->send_timer)) { data->send_timer.expires = jiffies + dm_delay * HZ; - add_timer_on(&data->send_timer, smp_processor_id()); + add_timer(&data->send_timer); } out: - rcu_read_unlock(); - put_cpu_var(dm_cpu_data); - return; + spin_unlock_irqrestore(&data->lock, flags); } static void trace_kfree_skb_hit(void *ignore, struct sk_buff *skb, void *location) @@ -406,11 +370,11 @@ static int __init init_net_drop_monitor(void) for_each_present_cpu(cpu) { data = &per_cpu(dm_cpu_data, cpu); - data->cpu = cpu; INIT_WORK(&data->dm_alert_work, send_dm_alert); init_timer(&data->send_timer); - data->send_timer.data = cpu; + data->send_timer.data = (unsigned long)data; data->send_timer.function = sched_send_work; + spin_lock_init(&data->lock); reset_per_cpu_data(data); } From 89a5feb2d59123824c344665c09328bb9fdb4fe9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 5 Jun 2012 03:00:18 +0000 Subject: [PATCH 0301/2357] inetpeer: fix a race in inetpeer_gc_worker() [ Upstream commit 55432d2b543a4b6dfae54f5c432a566877a85d90 ] commit 5faa5df1fa2024 (inetpeer: Invalidate the inetpeer tree along with the routing cache) added a race : Before freeing an inetpeer, we must respect a RCU grace period, and make sure no user will attempt to increase refcnt. inetpeer_invalidate_tree() waits for a RCU grace period before inserting inetpeer tree into gc_list and waking the worker. At that time, no concurrent lookup can find a inetpeer in this tree. Signed-off-by: Eric Dumazet Cc: Steffen Klassert Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/inetpeer.h | 5 ++++- net/ipv4/inetpeer.c | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index b94765e38e8..2040bff945d 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -40,7 +40,10 @@ struct inet_peer { u32 pmtu_orig; u32 pmtu_learned; struct inetpeer_addr_base redirect_learned; - struct list_head gc_list; + union { + struct list_head gc_list; + struct rcu_head gc_rcu; + }; /* * Once inet_peer is queued for deletion (refcnt == -1), following fields * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index d4d61b694fa..dfba343b250 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -560,6 +560,17 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout) } EXPORT_SYMBOL(inet_peer_xrlim_allow); +static void inetpeer_inval_rcu(struct rcu_head *head) +{ + struct inet_peer *p = container_of(head, struct inet_peer, gc_rcu); + + spin_lock_bh(&gc_lock); + list_add_tail(&p->gc_list, &gc_list); + spin_unlock_bh(&gc_lock); + + schedule_delayed_work(&gc_work, gc_delay); +} + void inetpeer_invalidate_tree(int family) { struct inet_peer *old, *new, *prev; @@ -576,10 +587,7 @@ void inetpeer_invalidate_tree(int family) prev = cmpxchg(&base->root, old, new); if (prev == old) { base->total = 0; - spin_lock(&gc_lock); - list_add_tail(&prev->gc_list, &gc_list); - spin_unlock(&gc_lock); - schedule_delayed_work(&gc_work, gc_delay); + call_rcu(&prev->gc_rcu, inetpeer_inval_rcu); } out: From b133be60ddab3b700ec1e516cc6ec5aac20770e0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Jun 2012 00:07:20 +0000 Subject: [PATCH 0302/2357] net: l2tp_eth: fix kernel panic on rmmod l2tp_eth [ Upstream commit a06998b88b1651c5f71c0e35f528bf2057188ead ] We must prevent module unloading if some devices are still attached to l2tp_eth driver. Signed-off-by: Eric Dumazet Reported-by: Denys Fedoryshchenko Tested-by: Denys Fedoryshchenko Cc: James Chapman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_eth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 63fe5f353f0..7446038e6b4 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -167,6 +167,7 @@ static void l2tp_eth_delete(struct l2tp_session *session) if (dev) { unregister_netdev(dev); spriv->dev = NULL; + module_put(THIS_MODULE); } } } @@ -254,6 +255,7 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p if (rc < 0) goto out_del_dev; + __module_get(THIS_MODULE); /* Must be done after register_netdev() */ strlcpy(session->ifname, dev->name, IFNAMSIZ); From 4ffa79bd261281152345b55d77da1709d1afdf3c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 8 Jun 2012 06:25:00 +0000 Subject: [PATCH 0303/2357] l2tp: fix a race in l2tp_ip_sendmsg() [ Upstream commit 4399a4df98a63e30fd16e9d0cecc46ea92269e8f ] Commit 081b1b1bb27f (l2tp: fix l2tp_ip_sendmsg() route handling) added a race, in case IP route cache is disabled. In this case, we should not do the dst_release(&rt->dst), since it'll free the dst immediately, instead of waiting a RCU grace period. Signed-off-by: Eric Dumazet Cc: James Chapman Cc: Denys Fedoryshchenko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_ip.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index cc8ad7bf51d..b1d4370c896 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -516,10 +516,12 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m sk->sk_bound_dev_if); if (IS_ERR(rt)) goto no_route; - if (connected) + if (connected) { sk_setup_caps(sk, &rt->dst); - else - dst_release(&rt->dst); /* safe since we hold rcu_read_lock */ + } else { + skb_dst_set(skb, &rt->dst); + goto xmit; + } } /* We dont need to clone dst here, it is guaranteed to not disappear. @@ -527,6 +529,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m */ skb_dst_set_noref(skb, &rt->dst); +xmit: /* Queue the packet to IP for output */ rc = ip_queue_xmit(skb, &inet->cork.fl); rcu_read_unlock(); From 1a36f94f6a9906d389787c259f86f13fc48c82a6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 10 Jun 2012 23:24:00 +0000 Subject: [PATCH 0304/2357] lpc_eth: add missing ndo_change_mtu() [ Upstream commit e30478598a8476d02e3b00caa89ce1a3b1dad54b ] lpc_eth does a copy of transmitted skbs to DMA area, without checking skb lengths, so can trigger buffer overflows : memcpy(pldat->tx_buff_v + txidx * ENET_MAXF_SIZE, skb->data, len); One way to get bigger skbs is to allow MTU changes above the 1500 limit. Calling eth_change_mtu() in ndo_change_mtu() makes sure this cannot happen. Signed-off-by: Eric Dumazet Cc: Roland Stigge Cc: Kevin Wells Acked-by: Roland Stigge Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/nxp/lpc_eth.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 6dfc26d85e4..27934fdb288 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1310,6 +1310,7 @@ static const struct net_device_ops lpc_netdev_ops = { .ndo_set_rx_mode = lpc_eth_set_multicast_list, .ndo_do_ioctl = lpc_eth_ioctl, .ndo_set_mac_address = lpc_set_mac_address, + .ndo_change_mtu = eth_change_mtu, }; static int lpc_eth_drv_probe(struct platform_device *pdev) From 3d5f5b08fa79068f567534166fb88ccebcb7c6d4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 11 Jun 2012 07:21:36 +0000 Subject: [PATCH 0305/2357] lpc_eth: fix tx completion [ Upstream commit 3f16da51b0e533871d22a29682f3c3969d4f7e22 ] __lpc_handle_xmit() has two bugs : 1) It can leak skbs in case TXSTATUS_ERROR is set 2) It can wake up txqueue while no slot was freed. Signed-off-by: Eric Dumazet Reported-by: Roland Stigge Tested-by: Roland Stigge Cc: Kevin Wells Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/nxp/lpc_eth.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 27934fdb288..0c5edc17a1e 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -936,16 +936,16 @@ static void __lpc_handle_xmit(struct net_device *ndev) /* Update stats */ ndev->stats.tx_packets++; ndev->stats.tx_bytes += skb->len; - - /* Free buffer */ - dev_kfree_skb_irq(skb); } + dev_kfree_skb_irq(skb); txcidx = readl(LPC_ENET_TXCONSUMEINDEX(pldat->net_base)); } - if (netif_queue_stopped(ndev)) - netif_wake_queue(ndev); + if (pldat->num_used_tx_buffs <= ENET_TX_DESC/2) { + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + } } static int __lpc_handle_recv(struct net_device *ndev, int budget) From 217fc833225f3a2ba55eabd3916bfbef38185cd1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Jun 2012 04:58:35 +0000 Subject: [PATCH 0306/2357] net: neighbour: fix neigh_dump_info() [ Upstream commit 4bd6683bd400c8b1d2ad544bb155d86a5d10f91c ] Denys found out "ip neigh" output was truncated to about 54 neighbours. Signed-off-by: Eric Dumazet Reported-by: Denys Fedoryshchenko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/neighbour.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0a68045782d..73b90351df5 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2214,9 +2214,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, rcu_read_lock_bh(); nht = rcu_dereference_bh(tbl->nht); - for (h = 0; h < (1 << nht->hash_shift); h++) { - if (h < s_h) - continue; + for (h = s_h; h < (1 << nht->hash_shift); h++) { if (h > s_h) s_idx = 0; for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0; @@ -2255,9 +2253,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, read_lock_bh(&tbl->lock); - for (h = 0; h <= PNEIGH_HASHMASK; h++) { - if (h < s_h) - continue; + for (h = s_h; h <= PNEIGH_HASHMASK; h++) { if (h > s_h) s_idx = 0; for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { @@ -2292,7 +2288,7 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) struct neigh_table *tbl; int t, family, s_t; int proxy = 0; - int err = 0; + int err; read_lock(&neigh_tbl_lock); family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; @@ -2306,7 +2302,7 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) s_t = cb->args[0]; - for (tbl = neigh_tables, t = 0; tbl && (err >= 0); + for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) { if (t < s_t || (family && tbl->family != family)) continue; @@ -2317,6 +2313,8 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) err = pneigh_dump_table(tbl, skb, cb); else err = neigh_dump_table(tbl, skb, cb); + if (err < 0) + break; } read_unlock(&neigh_tbl_lock); From 8ec2c824f3773dcc31316535acd8c725c22a7341 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 7 Jun 2012 06:51:04 +0000 Subject: [PATCH 0307/2357] ipv6: fib: Restore NTF_ROUTER exception in fib6_age() [ Upstream commit 8bd74516b1bd9308c17f67583134d93f777203ca ] Commit 5339ab8b1dd82 (ipv6: fib: Convert fib6_age() to dst_neigh_lookup().) seems to have mistakenly inverted the exception for cached NTF_ROUTER routes. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_fib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 93717435013..92bb9cba5c3 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1560,7 +1560,7 @@ static int fib6_age(struct rt6_info *rt, void *arg) neigh_flags = neigh->flags; neigh_release(neigh); } - if (neigh_flags & NTF_ROUTER) { + if (!(neigh_flags & NTF_ROUTER)) { RT6_TRACE("purging route %p via non-router but gateway\n", rt); return -1; From f9909f77764c6e7d9f6067ac58bf3f68a02ed266 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 18 Jun 2012 12:08:33 +0000 Subject: [PATCH 0308/2357] ipv6: Move ipv6 proc file registration to end of init order [ Upstream commit d189634ecab947c10f6f832258b103d0bbfe73cc ] /proc/net/ipv6_route reflects the contents of fib_table_hash. The proc handler is installed in ip6_route_net_init() whereas fib_table_hash is allocated in fib6_net_init() _after_ the proc handler has been installed. This opens up a short time frame to access fib_table_hash with its pants down. Move the registration of the proc files to a later point in the init order to avoid the race. Tested :-) Signed-off-by: Thomas Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index bc4888d902b..c4920ca83f5 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2953,10 +2953,6 @@ static int __net_init ip6_route_net_init(struct net *net) net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ; net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; -#ifdef CONFIG_PROC_FS - proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); - proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); -#endif net->ipv6.ip6_rt_gc_expire = 30*HZ; ret = 0; @@ -2977,10 +2973,6 @@ static int __net_init ip6_route_net_init(struct net *net) static void __net_exit ip6_route_net_exit(struct net *net) { -#ifdef CONFIG_PROC_FS - proc_net_remove(net, "ipv6_route"); - proc_net_remove(net, "rt6_stats"); -#endif kfree(net->ipv6.ip6_null_entry); #ifdef CONFIG_IPV6_MULTIPLE_TABLES kfree(net->ipv6.ip6_prohibit_entry); @@ -2989,11 +2981,33 @@ static void __net_exit ip6_route_net_exit(struct net *net) dst_entries_destroy(&net->ipv6.ip6_dst_ops); } +static int __net_init ip6_route_net_init_late(struct net *net) +{ +#ifdef CONFIG_PROC_FS + proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); + proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); +#endif + return 0; +} + +static void __net_exit ip6_route_net_exit_late(struct net *net) +{ +#ifdef CONFIG_PROC_FS + proc_net_remove(net, "ipv6_route"); + proc_net_remove(net, "rt6_stats"); +#endif +} + static struct pernet_operations ip6_route_net_ops = { .init = ip6_route_net_init, .exit = ip6_route_net_exit, }; +static struct pernet_operations ip6_route_net_late_ops = { + .init = ip6_route_net_init_late, + .exit = ip6_route_net_exit_late, +}; + static struct notifier_block ip6_route_dev_notifier = { .notifier_call = ip6_route_dev_notify, .priority = 0, @@ -3043,19 +3057,25 @@ int __init ip6_route_init(void) if (ret) goto xfrm6_init; + ret = register_pernet_subsys(&ip6_route_net_late_ops); + if (ret) + goto fib6_rules_init; + ret = -ENOBUFS; if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) || __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) || __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL)) - goto fib6_rules_init; + goto out_register_late_subsys; ret = register_netdevice_notifier(&ip6_route_dev_notifier); if (ret) - goto fib6_rules_init; + goto out_register_late_subsys; out: return ret; +out_register_late_subsys: + unregister_pernet_subsys(&ip6_route_net_late_ops); fib6_rules_init: fib6_rules_cleanup(); xfrm6_init: @@ -3074,6 +3094,7 @@ int __init ip6_route_init(void) void ip6_route_cleanup(void) { unregister_netdevice_notifier(&ip6_route_dev_notifier); + unregister_pernet_subsys(&ip6_route_net_late_ops); fib6_rules_cleanup(); xfrm6_fini(); fib6_gc_cleanup(); From 019984b4454af824ff1c23aa6f53010b54b5c683 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 6 Jun 2012 10:01:30 +0000 Subject: [PATCH 0309/2357] sky2: fix checksum bit management on some chips [ Upstream commit 5ff0feac88ced864f44adb145142269196fa79d9 ] The newer flavors of Yukon II use a different method for receive checksum offload. This is indicated in the driver by the SKY2_HW_NEW_LE flag. On these newer chips, the BMU_ENA_RX_CHKSUM should not be set. The driver would get incorrectly toggle the bit, enabling the old checksum logic on these chips and cause a BUG_ON() assertion. If receive checksum was toggled via ethtool. Reported-by: Kirill Smelkov Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/marvell/sky2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 487a6c8bd4e..589753fb673 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -4381,10 +4381,12 @@ static int sky2_set_features(struct net_device *dev, netdev_features_t features) struct sky2_port *sky2 = netdev_priv(dev); netdev_features_t changed = dev->features ^ features; - if (changed & NETIF_F_RXCSUM) { - bool on = features & NETIF_F_RXCSUM; - sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), - on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); + if ((changed & NETIF_F_RXCSUM) && + !(sky2->hw->flags & SKY2_HW_NEW_LE)) { + sky2_write32(sky2->hw, + Q_ADDR(rxqaddr[sky2->port], Q_CSR), + (features & NETIF_F_RXCSUM) + ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } if (changed & NETIF_F_RXHASH) From 43d950abdab622bf97d0a0c233809f88a3eb6240 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 8 Jun 2012 00:28:16 -0700 Subject: [PATCH 0310/2357] Revert "niu: Add support for byte queue limits." [ Upstream commit 6a2b28ef036ab5c66fdc606fe97d9e5cb34ea409 ] This reverts commit efa230f2c68abab817f13473077f8d0cc74f43f3. BQL doesn't work with how this driver currently only takes TX interrupts every 1/4 of the TX ring. That behavior needs to be fixed, but that's a larger non-trivial task and for now we have to revert BQL support as this makes the device currently completely unusable. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/sun/niu.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index c99b3b0e2ea..8489d09494a 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -3598,7 +3598,6 @@ static int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx) static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) { struct netdev_queue *txq; - unsigned int tx_bytes; u16 pkt_cnt, tmp; int cons, index; u64 cs; @@ -3621,18 +3620,12 @@ static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) netif_printk(np, tx_done, KERN_DEBUG, np->dev, "%s() pkt_cnt[%u] cons[%d]\n", __func__, pkt_cnt, cons); - tx_bytes = 0; - tmp = pkt_cnt; - while (tmp--) { - tx_bytes += rp->tx_buffs[cons].skb->len; + while (pkt_cnt--) cons = release_tx_packet(np, rp, cons); - } rp->cons = cons; smp_mb(); - netdev_tx_completed_queue(txq, pkt_cnt, tx_bytes); - out: if (unlikely(netif_tx_queue_stopped(txq) && (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) { @@ -4333,7 +4326,6 @@ static void niu_free_channels(struct niu *np) struct tx_ring_info *rp = &np->tx_rings[i]; niu_free_tx_ring_info(np, rp); - netdev_tx_reset_queue(netdev_get_tx_queue(np->dev, i)); } kfree(np->tx_rings); np->tx_rings = NULL; @@ -6739,8 +6731,6 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb, prod = NEXT_TX(rp, prod); } - netdev_tx_sent_queue(txq, skb->len); - if (prod < rp->prod) rp->wrap_bit ^= TX_RING_KICK_WRAP; rp->prod = prod; From a459fdd31c96993f6fcee4879eb20bc1e7bac2ed Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Jun 2012 22:59:59 +0000 Subject: [PATCH 0311/2357] be2net: fix a race in be_xmit() [ Upstream commit cd8f76c0a0c6fce0b2cf23c9bd0123f91453f46d ] As soon as hardware is notified of a transmit, we no longer can assume skb can be dereferenced, as TX completion might have freed the packet. Signed-off-by: Eric Dumazet Cc: Sathya Perla Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/emulex/benet/be_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 528a886bc2c..1bbf6b3eca9 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -731,6 +731,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); if (copied) { + int gso_segs = skb_shinfo(skb)->gso_segs; + /* record the sent skb in the sent_skb table */ BUG_ON(txo->sent_skb_list[start]); txo->sent_skb_list[start] = skb; @@ -748,8 +750,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, be_txq_notify(adapter, txq->id, wrb_cnt); - be_tx_stats_update(txo, wrb_cnt, copied, - skb_shinfo(skb)->gso_segs, stopped); + be_tx_stats_update(txo, wrb_cnt, copied, gso_segs, stopped); } else { txq->head = start; dev_kfree_skb_any(skb); From 09838df9d2ff31252a69a8393ea96a9734eba7e8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 10 Jun 2012 21:11:57 +0000 Subject: [PATCH 0312/2357] dummy: fix rcu_sched self-detected stalls [ Upstream commit 16b0dc29c1af9df341428f4c49ada4f626258082 ] Trying to "modprobe dummy numdummies=30000" triggers : INFO: rcu_sched self-detected stall on CPU { 8} (t=60000 jiffies) After this splat, RTNL is locked and reboot is needed. We must call cond_resched() to avoid this, even holding RTNL. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/dummy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 442d91a2747..bab0158f1cc 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -187,8 +187,10 @@ static int __init dummy_init_module(void) rtnl_lock(); err = __rtnl_link_register(&dummy_link_ops); - for (i = 0; i < numdummies && !err; i++) + for (i = 0; i < numdummies && !err; i++) { err = dummy_init_one(); + cond_resched(); + } if (err < 0) __rtnl_link_unregister(&dummy_link_ops); rtnl_unlock(); From c51c618955c052c1d34de9b325bb49a375e874a0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 Jun 2012 06:03:51 +0000 Subject: [PATCH 0313/2357] bonding: Fix corrupted queue_mapping [ Upstream commit 5ee31c6898ea5537fcea160999d60dc63bc0c305 ] In the transmit path of the bonding driver, skb->cb is used to stash the skb->queue_mapping so that the bonding device can set its own queue mapping. This value becomes corrupted since the skb->cb is also used in __dev_xmit_skb. When transmitting through bonding driver, bond_select_queue is called from dev_queue_xmit. In bond_select_queue the original skb->queue_mapping is copied into skb->cb (via bond_queue_mapping) and skb->queue_mapping is overwritten with the bond driver queue. Subsequently in dev_queue_xmit, __dev_xmit_skb is called which writes the packet length into skb->cb, thereby overwriting the stashed queue mappping. In bond_dev_queue_xmit (called from hard_start_xmit), the queue mapping for the skb is set to the stashed value which is now the skb length and hence is an invalid queue for the slave device. If we want to save skb->queue_mapping into skb->cb[], best place is to add a field in struct qdisc_skb_cb, to make sure it wont conflict with other layers (eg : Qdiscc, Infiniband...) This patchs also makes sure (struct qdisc_skb_cb)->data is aligned on 8 bytes : netem qdisc for example assumes it can store an u64 in it, without misalignment penalty. Note : we only have 20 bytes left in (struct qdisc_skb_cb)->data[]. The largest user is CHOKe and it fills it. Based on a previous patch from Tom Herbert. Signed-off-by: Eric Dumazet Reported-by: Tom Herbert Cc: John Fastabend Cc: Roland Dreier Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 9 +++++---- include/net/sch_generic.h | 7 +++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bc13b3d7743..a579a2f57c5 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -76,6 +76,7 @@ #include #include #include +#include #include "bonding.h" #include "bond_3ad.h" #include "bond_alb.h" @@ -381,8 +382,6 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) return next; } -#define bond_queue_mapping(skb) (*(u16 *)((skb)->cb)) - /** * bond_dev_queue_xmit - Prepare skb for xmit. * @@ -395,7 +394,9 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, { skb->dev = slave_dev; - skb->queue_mapping = bond_queue_mapping(skb); + BUILD_BUG_ON(sizeof(skb->queue_mapping) != + sizeof(qdisc_skb_cb(skb)->bond_queue_mapping)); + skb->queue_mapping = qdisc_skb_cb(skb)->bond_queue_mapping; if (unlikely(netpoll_tx_running(slave_dev))) bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb); @@ -4162,7 +4163,7 @@ static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) /* * Save the original txq to restore before passing to the driver */ - bond_queue_mapping(skb) = skb->queue_mapping; + qdisc_skb_cb(skb)->bond_queue_mapping = skb->queue_mapping; if (unlikely(txq >= dev->real_num_tx_queues)) { do { diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 55ce96b53b0..9d7d54a00e6 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -220,13 +220,16 @@ struct tcf_proto { struct qdisc_skb_cb { unsigned int pkt_len; - unsigned char data[24]; + u16 bond_queue_mapping; + u16 _pad; + unsigned char data[20]; }; static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) { struct qdisc_skb_cb *qcb; - BUILD_BUG_ON(sizeof(skb->cb) < sizeof(unsigned int) + sz); + + BUILD_BUG_ON(sizeof(skb->cb) < offsetof(struct qdisc_skb_cb, data) + sz); BUILD_BUG_ON(sizeof(qcb->data) < sz); } From da7de70e5098b7b01c17ea8ac46086ac9154576e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 Jun 2012 19:30:21 +0000 Subject: [PATCH 0314/2357] netpoll: fix netpoll_send_udp() bugs [ Upstream commit 954fba0274058d27c7c07b5ea07c41b3b7477894 ] Bogdan Hamciuc diagnosed and fixed following bug in netpoll_send_udp() : "skb->len += len;" instead of "skb_put(skb, len);" Meaning that _if_ a network driver needs to call skb_realloc_headroom(), only packet headers would be copied, leaving garbage in the payload. However the skb_realloc_headroom() must be avoided as much as possible since it requires memory and netpoll tries hard to work even if memory is exhausted (using a pool of preallocated skbs) It appears netpoll_send_udp() reserved 16 bytes for the ethernet header, which happens to work for typicall drivers but not all. Right thing is to use LL_RESERVED_SPACE(dev) (And also add dev->needed_tailroom of tailroom) This patch combines both fixes. Many thanks to Bogdan for raising this issue. Reported-by: Bogdan Hamciuc Signed-off-by: Eric Dumazet Tested-by: Bogdan Hamciuc Cc: Herbert Xu Cc: Neil Horman Reviewed-by: Neil Horman Reviewed-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/netpoll.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 3d84fb9d887..f9f40b932e4 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -362,22 +362,23 @@ EXPORT_SYMBOL(netpoll_send_skb_on_dev); void netpoll_send_udp(struct netpoll *np, const char *msg, int len) { - int total_len, eth_len, ip_len, udp_len; + int total_len, ip_len, udp_len; struct sk_buff *skb; struct udphdr *udph; struct iphdr *iph; struct ethhdr *eth; udp_len = len + sizeof(*udph); - ip_len = eth_len = udp_len + sizeof(*iph); - total_len = eth_len + ETH_HLEN + NET_IP_ALIGN; + ip_len = udp_len + sizeof(*iph); + total_len = ip_len + LL_RESERVED_SPACE(np->dev); - skb = find_skb(np, total_len, total_len - len); + skb = find_skb(np, total_len + np->dev->needed_tailroom, + total_len - len); if (!skb) return; skb_copy_to_linear_data(skb, msg, len); - skb->len += len; + skb_put(skb, len); skb_push(skb, sizeof(*udph)); skb_reset_transport_header(skb); From 9bfb2101d5f2dffbfcc9d15c57c56459ca61c967 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 Jun 2012 23:50:04 +0000 Subject: [PATCH 0315/2357] bnx2x: fix checksum validation [ Upstream commit d6cb3e41386f20fb0777d0b59a2def82c65d37f7 ] bnx2x driver incorrectly sets ip_summed to CHECKSUM_UNNECESSARY on encapsulated segments. TCP stack happily accepts frames with bad checksums, if they are inside a GRE or IPIP encapsulation. Our understanding is that if no IP or L4 csum validation was done by the hardware, we should leave ip_summed as is (CHECKSUM_NONE), since hardware doesn't provide CHECKSUM_COMPLETE support in its cqe. Then, if IP/L4 checksumming was done by the hardware, set CHECKSUM_UNNECESSARY if no error was flagged. Patch based on findings and analysis from Robert Evans Signed-off-by: Eric Dumazet Cc: Eilon Greenstein Cc: Yaniv Rosner Cc: Merav Sicron Cc: Tom Herbert Cc: Robert Evans Cc: Willem de Bruijn Acked-by: Eilon Greenstein Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 15 ----------- .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 27 ++++++++++++++----- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 2c9ee552dff..75d35ec9b71 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -744,21 +744,6 @@ struct bnx2x_fastpath { #define ETH_RX_ERROR_FALGS ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG -#define BNX2X_IP_CSUM_ERR(cqe) \ - (!((cqe)->fast_path_cqe.status_flags & \ - ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG) && \ - ((cqe)->fast_path_cqe.type_error_flags & \ - ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG)) - -#define BNX2X_L4_CSUM_ERR(cqe) \ - (!((cqe)->fast_path_cqe.status_flags & \ - ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG) && \ - ((cqe)->fast_path_cqe.type_error_flags & \ - ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG)) - -#define BNX2X_RX_CSUM_OK(cqe) \ - (!(BNX2X_L4_CSUM_ERR(cqe) || BNX2X_IP_CSUM_ERR(cqe))) - #define BNX2X_PRS_FLAG_OVERETH_IPV4(flags) \ (((le16_to_cpu(flags) & \ PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) >> \ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 4b054812713..03489fde7fe 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -568,6 +568,25 @@ static inline void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, fp->eth_q_stats.rx_skb_alloc_failed++; } +static void bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe, + struct bnx2x_fastpath *fp) +{ + /* Do nothing if no IP/L4 csum validation was done */ + + if (cqe->fast_path_cqe.status_flags & + (ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG | + ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG)) + return; + + /* If both IP/L4 validation were done, check if an error was found. */ + + if (cqe->fast_path_cqe.type_error_flags & + (ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG | + ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG)) + fp->eth_q_stats.hw_csum_err++; + else + skb->ip_summed = CHECKSUM_UNNECESSARY; +} int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) { @@ -757,13 +776,9 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) skb_checksum_none_assert(skb); - if (bp->dev->features & NETIF_F_RXCSUM) { + if (bp->dev->features & NETIF_F_RXCSUM) + bnx2x_csum_validate(skb, cqe, fp); - if (likely(BNX2X_RX_CSUM_OK(cqe))) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - fp->eth_q_stats.hw_csum_err++; - } skb_record_rx_queue(skb, fp->rx_queue); From 8f530e3bc3af125ac013732b5c54a3af2ad791a2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 13 Jun 2012 09:45:16 +0000 Subject: [PATCH 0316/2357] bnx2x: fix panic when TX ring is full [ Upstream commit bc14786a100cc6a81cd060e8031ec481241b418c ] There is a off by one error in the minimal number of BD in bnx2x_start_xmit() and bnx2x_tx_int() before stopping/resuming tx queue. A full size GSO packet, with data included in skb->head really needs (MAX_SKB_FRAGS + 4) BDs, because of bnx2x_tx_split() This error triggers if BQL is disabled and heavy TCP transmit traffic occurs. bnx2x_tx_split() definitely can be called, remove a wrong comment. Reported-by: Tomas Hruby Signed-off-by: Eric Dumazet Cc: Eilon Greenstein Cc: Yaniv Rosner Cc: Merav Sicron Cc: Tom Herbert Cc: Robert Evans Cc: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 03489fde7fe..41bb34fcf68 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -191,7 +191,7 @@ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata) if ((netif_tx_queue_stopped(txq)) && (bp->state == BNX2X_STATE_OPEN) && - (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 3)) + (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 4)) netif_tx_wake_queue(txq); __netif_tx_unlock(txq); @@ -2349,8 +2349,6 @@ int bnx2x_poll(struct napi_struct *napi, int budget) /* we split the first BD into headers and data BDs * to ease the pain of our fellow microcode engineers * we use one mapping for both BDs - * So far this has only been observed to happen - * in Other Operating Systems(TM) */ static noinline u16 bnx2x_tx_split(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, @@ -3002,7 +3000,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) txdata->tx_bd_prod += nbd; - if (unlikely(bnx2x_tx_avail(bp, txdata) < MAX_SKB_FRAGS + 3)) { + if (unlikely(bnx2x_tx_avail(bp, txdata) < MAX_SKB_FRAGS + 4)) { netif_tx_stop_queue(txq); /* paired memory barrier is in bnx2x_tx_int(), we have to keep @@ -3011,7 +3009,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) smp_mb(); fp->eth_q_stats.driver_xoff++; - if (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 3) + if (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 4) netif_tx_wake_queue(txq); } txdata->tx_pkt++; From 993772c70fda9d05299fc3a8ed9d1cba268870f1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 14 Jun 2012 06:42:44 +0000 Subject: [PATCH 0317/2357] net: remove skb_orphan_try() [ Upstream commit 62b1a8ab9b3660bb820d8dfe23148ed6cda38574 ] Orphaning skb in dev_hard_start_xmit() makes bonding behavior unfriendly for applications sending big UDP bursts : Once packets pass the bonding device and come to real device, they might hit a full qdisc and be dropped. Without orphaning, the sender is automatically throttled because sk->sk_wmemalloc reaches sk->sk_sndbuf (assuming sk_sndbuf is not too big) We could try to defer the orphaning adding another test in dev_hard_start_xmit(), but all this seems of little gain, now that BQL tends to make packets more likely to be parked in Qdisc queues instead of NIC TX ring, in cases where performance matters. Reverts commits : fc6055a5ba31 net: Introduce skb_orphan_try() 87fd308cfc6b net: skb_tx_hash() fix relative to skb_orphan_try() and removes SKBTX_DRV_NEEDS_SK_REF flag Reported-and-bisected-by: Jean-Michel Hautbois Signed-off-by: Eric Dumazet Tested-by: Oliver Hartkopp Acked-by: Oliver Hartkopp Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/skbuff.h | 7 ++----- net/can/raw.c | 3 --- net/core/dev.c | 23 +---------------------- net/iucv/af_iucv.c | 1 - 4 files changed, 3 insertions(+), 31 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c1689071fa2..c1bae8dff77 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -225,14 +225,11 @@ enum { /* device driver is going to provide hardware time stamp */ SKBTX_IN_PROGRESS = 1 << 2, - /* ensure the originating sk reference is available on driver level */ - SKBTX_DRV_NEEDS_SK_REF = 1 << 3, - /* device driver supports TX zero-copy buffers */ - SKBTX_DEV_ZEROCOPY = 1 << 4, + SKBTX_DEV_ZEROCOPY = 1 << 3, /* generate wifi status information (where possible) */ - SKBTX_WIFI_STATUS = 1 << 5, + SKBTX_WIFI_STATUS = 1 << 4, }; /* diff --git a/net/can/raw.c b/net/can/raw.c index cde1b4a20f7..46cca3a91d1 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -681,9 +681,6 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, if (err < 0) goto free_skb; - /* to be able to check the received tx sock reference in raw_rcv() */ - skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF; - skb->dev = dev; skb->sk = sk; diff --git a/net/core/dev.c b/net/core/dev.c index 99e1d759f41..533c586c64d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2091,25 +2091,6 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features) return 0; } -/* - * Try to orphan skb early, right before transmission by the device. - * We cannot orphan skb if tx timestamp is requested or the sk-reference - * is needed on driver level for other reasons, e.g. see net/can/raw.c - */ -static inline void skb_orphan_try(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - - if (sk && !skb_shinfo(skb)->tx_flags) { - /* skb_tx_hash() wont be able to get sk. - * We copy sk_hash into skb->rxhash - */ - if (!skb->rxhash) - skb->rxhash = sk->sk_hash; - skb_orphan(skb); - } -} - static bool can_checksum_protocol(netdev_features_t features, __be16 protocol) { return ((features & NETIF_F_GEN_CSUM) || @@ -2195,8 +2176,6 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, if (!list_empty(&ptype_all)) dev_queue_xmit_nit(skb, dev); - skb_orphan_try(skb); - features = netif_skb_features(skb); if (vlan_tx_tag_present(skb) && @@ -2306,7 +2285,7 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, if (skb->sk && skb->sk->sk_hash) hash = skb->sk->sk_hash; else - hash = (__force u16) skb->protocol ^ skb->rxhash; + hash = (__force u16) skb->protocol; hash = jhash_1word(hash, hashrnd); return (u16) (((u64) hash * qcount) >> 32) + qoffset; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 07d7d55a1b9..cd6f7a991d8 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -372,7 +372,6 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, skb_trim(skb, skb->dev->mtu); } skb->protocol = ETH_P_AF_IUCV; - skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF; nskb = skb_clone(skb, GFP_ATOMIC); if (!nskb) return -ENOMEM; From f7153a449ce35459169a790ba6cce8830c116894 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 26 Jun 2012 05:48:45 +0000 Subject: [PATCH 0318/2357] bridge: Assign rtnl_link_ops to bridge devices created via ioctl (v2) [ Upstream commit 149ddd83a92b02c658d6c61f3276eb6500d585e8 ] This ensures that bridges created with brctl(8) or ioctl(2) directly also carry IFLA_LINKINFO when dumped over netlink. This also allows to create a bridge with ioctl(2) and delete it with RTM_DELLINK. Signed-off-by: Thomas Graf Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bridge/br_if.c | 1 + net/bridge/br_netlink.c | 2 +- net/bridge/br_private.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 0a942fbccc9..e1144e1617b 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -240,6 +240,7 @@ int br_add_bridge(struct net *net, const char *name) return -ENOMEM; dev_net_set(dev, net); + dev->rtnl_link_ops = &br_link_ops; res = register_netdev(dev); if (res) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index a1daf8227ed..cbf9ccd4578 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -211,7 +211,7 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } -static struct rtnl_link_ops br_link_ops __read_mostly = { +struct rtnl_link_ops br_link_ops __read_mostly = { .kind = "bridge", .priv_size = sizeof(struct net_bridge), .setup = br_dev_setup, diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index e1d88225787..51e8826e78c 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -538,6 +538,7 @@ extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr) #endif /* br_netlink.c */ +extern struct rtnl_link_ops br_link_ops; extern int br_netlink_init(void); extern void br_netlink_fini(void); extern void br_ifinfo_notify(int event, struct net_bridge_port *port); From 3cc270f7fcd34b08d37ed51fb4c25b0f513f2e65 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 25 Jun 2012 22:48:41 +0000 Subject: [PATCH 0319/2357] xen/netfront: teardown the device before unregistering it. [ Upstream commit 6bc96d047fe32d76ef79f3195c52a542edf7c705 ] Fixes: [ 15.470311] WARNING: at /local/scratch/ianc/devel/kernels/linux/fs/sysfs/file.c:498 sysfs_attr_ns+0x95/0xa0() [ 15.470326] sysfs: kobject eth0 without dirent [ 15.470333] Modules linked in: [ 15.470342] Pid: 12, comm: xenwatch Not tainted 3.4.0-x86_32p-xenU #93 and [ 9.150554] BUG: unable to handle kernel paging request at 2b359000 [ 9.150577] IP: [] linkwatch_do_dev+0x81/0xc0 [ 9.150592] *pdpt = 000000002c3c9027 *pde = 0000000000000000 [ 9.150604] Oops: 0002 [#1] SMP [ 9.150613] Modules linked in: This is http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=675190 Reported-by: George Shuklin Signed-off-by: Ian Campbell Tested-by: William Dauchy Cc: stable@kernel.org Cc: 675190@bugs.debian.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 0ebbb1906c3..796afbf13eb 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1935,14 +1935,14 @@ static int __devexit xennet_remove(struct xenbus_device *dev) dev_dbg(&dev->dev, "%s\n", dev->nodename); - unregister_netdev(info->netdev); - xennet_disconnect_backend(info); - del_timer_sync(&info->rx_refill_timer); - xennet_sysfs_delif(info->netdev); + unregister_netdev(info->netdev); + + del_timer_sync(&info->rx_refill_timer); + free_percpu(info->stats); free_netdev(info->netdev); From d3ae4a87530c1e10c0705995c87fe8a7b4267f4b Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 20 Jun 2012 12:52:56 -0700 Subject: [PATCH 0320/2357] mm: fix slab->page _count corruption when using slub commit abca7c4965845924f65d40e0aa1092bdd895e314 upstream. On arches that do not support this_cpu_cmpxchg_double() slab_lock is used to do atomic cmpxchg() on double word which contains page->_count. The page count can be changed from get_page() or put_page() without taking slab_lock. That corrupts page counter. Fix it by moving page->_count out of cmpxchg_double data. So that slub does no change it while updating slub meta-data in struct page. [akpm@linux-foundation.org: use standard comment layout, tweak comment text] Reported-by: Amey Bhide Signed-off-by: Pravin B Shelar Acked-by: Christoph Lameter Cc: Pekka Enberg Cc: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/mm_types.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 3cc3062b376..b35752fb2ad 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -56,8 +56,18 @@ struct page { }; union { +#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \ + defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE) /* Used for cmpxchg_double in slub */ unsigned long counters; +#else + /* + * Keep _count separate from slub cmpxchg_double data. + * As the rest of the double word is protected by + * slab_lock but _count is not. + */ + unsigned counters; +#endif struct { From 6ef0d09aaa123dfba91f3261c78827c4d85e786a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 10 Jul 2012 18:36:40 +1000 Subject: [PATCH 0321/2357] powerpc: More fixes for lazy IRQ vs. idle commit be2cf20a5ad31ebb13562c1c866ecc626fbd721e upstream. Looks like we still have issues with pSeries and Cell idle code vs. the lazy irq state. In fact, the reset fixes that went upstream are exposing the problem more by causing BUG_ON() to trigger (which this patch turns into a WARN_ON instead). We need to be careful when using a variant of low power state that has the side effect of turning interrupts back on, to properly set all the SW & lazy state to look as if everything is enabled before we enter the low power state with MSR:EE off as we will return with MSR:EE on. If not, we have a discrepancy of state which can cause things to go very wrong later on. This patch moves the logic into a helper and uses it from the pseries and cell idle code. The power4/970 idle code already got things right (in assembly even !) so I'm not touching it. The power7 "bare metal" idle code is subtly different and correct. Remains PA6T and some hypervisor based Cell platforms which have questionable code in there, but they are mostly dead platforms so I'll fix them when I manage to get final answers from the respective maintainers about how the low power state actually works on them. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/hw_irq.h | 2 + arch/powerpc/kernel/irq.c | 46 +++++++++++++++++++ arch/powerpc/platforms/cell/pervasive.c | 11 +++-- .../platforms/pseries/processor_idle.c | 17 ++++--- 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 6627a3e1b13..09e6d5951bb 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -124,6 +124,8 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs) return !regs->softe; } +extern bool prep_irq_for_idle(void); + #else /* CONFIG_PPC64 */ #define SET_MSR_EE(x) mtmsr(x) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 64eec59193f..d6946e10a25 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -286,6 +286,52 @@ void notrace restore_interrupts(void) __hard_irq_enable(); } +/* + * This is a helper to use when about to go into idle low-power + * when the latter has the side effect of re-enabling interrupts + * (such as calling H_CEDE under pHyp). + * + * You call this function with interrupts soft-disabled (this is + * already the case when ppc_md.power_save is called). The function + * will return whether to enter power save or just return. + * + * In the former case, it will have notified lockdep of interrupts + * being re-enabled and generally sanitized the lazy irq state, + * and in the latter case it will leave with interrupts hard + * disabled and marked as such, so the local_irq_enable() call + * in cpu_idle() will properly re-enable everything. + */ +bool prep_irq_for_idle(void) +{ + /* + * First we need to hard disable to ensure no interrupt + * occurs before we effectively enter the low power state + */ + hard_irq_disable(); + + /* + * If anything happened while we were soft-disabled, + * we return now and do not enter the low power state. + */ + if (lazy_irq_pending()) + return false; + + /* Tell lockdep we are about to re-enable */ + trace_hardirqs_on(); + + /* + * Mark interrupts as soft-enabled and clear the + * PACA_IRQ_HARD_DIS from the pending mask since we + * are about to hard enable as well as a side effect + * of entering the low power state. + */ + local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS; + local_paca->soft_enabled = 1; + + /* Tell the caller to enter the low power state */ + return true; +} + #endif /* CONFIG_PPC64 */ int arch_show_interrupts(struct seq_file *p, int prec) diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index efdacc82957..d17e98bc0c1 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c @@ -42,11 +42,9 @@ static void cbe_power_save(void) { unsigned long ctrl, thread_switch_control; - /* - * We need to hard disable interrupts, the local_irq_enable() done by - * our caller upon return will hard re-enable. - */ - hard_irq_disable(); + /* Ensure our interrupt state is properly tracked */ + if (!prep_irq_for_idle()) + return; ctrl = mfspr(SPRN_CTRLF); @@ -81,6 +79,9 @@ static void cbe_power_save(void) */ ctrl &= ~(CTRL_RUNLATCH | CTRL_TE); mtspr(SPRN_CTRLT, ctrl); + + /* Re-enable interrupts in MSR */ + __hard_irq_enable(); } static int cbe_system_reset_exception(struct pt_regs *regs) diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index e61483e8e96..c71be66bd5d 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -99,15 +99,18 @@ static int snooze_loop(struct cpuidle_device *dev, static void check_and_cede_processor(void) { /* - * Interrupts are soft-disabled at this point, - * but not hard disabled. So an interrupt might have - * occurred before entering NAP, and would be potentially - * lost (edge events, decrementer events, etc...) unless - * we first hard disable then check. + * Ensure our interrupt state is properly tracked, + * also checks if no interrupt has occurred while we + * were soft-disabled */ - hard_irq_disable(); - if (!lazy_irq_pending()) + if (prep_irq_for_idle()) { cede_processor(); +#ifdef CONFIG_TRACE_IRQFLAGS + /* Ensure that H_CEDE returns with IRQs on */ + if (WARN_ON(!(mfmsr() & MSR_EE))) + __hard_irq_enable(); +#endif + } } static int dedicated_cede_loop(struct cpuidle_device *dev, From dd3ce2fa647d42d524392d5e6a0647061fc64c67 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 10 Jul 2012 18:37:56 +1000 Subject: [PATCH 0322/2357] powerpc: Fix build of some debug irq code commit 21b2de341270bd7bb7a811027ffe63276d9b3b75 upstream. There was a typo, checking for CONFIG_TRACE_IRQFLAG instead of CONFIG_TRACE_IRQFLAGS causing some useful debug code to not be built This in turns causes a build error on BookE 64-bit due to incorrect semicolons at the end of a couple of macros, so let's fix that too Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/hw_irq.h | 4 ++-- arch/powerpc/kernel/irq.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 09e6d5951bb..907e9fddfcb 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -85,8 +85,8 @@ static inline bool arch_irqs_disabled(void) } #ifdef CONFIG_PPC_BOOK3E -#define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory"); -#define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory"); +#define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory") +#define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory") #else #define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1) #define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index d6946e10a25..d7ebc58c907 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -229,7 +229,7 @@ notrace void arch_local_irq_restore(unsigned long en) */ if (unlikely(irq_happened != PACA_IRQ_HARD_DIS)) __hard_irq_disable(); -#ifdef CONFIG_TRACE_IRQFLAG +#ifdef CONFIG_TRACE_IRQFLAGS else { /* * We should already be hard disabled here. We had bugs From ee0b2dd6344911d7769f9fd638d30f45e66b8410 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 Jun 2012 00:47:58 +0200 Subject: [PATCH 0323/2357] NFC: Return from rawsock_release when sk is NULL commit 03e934f620101ca2cfc9383bd76172dd3e1f8567 upstream. Sasha Levin reported following panic : [ 2136.383310] BUG: unable to handle kernel NULL pointer dereference at 00000000000003b0 [ 2136.384022] IP: [] __lock_acquire+0xc0/0x4b0 [ 2136.384022] PGD 131c4067 PUD 11c0c067 PMD 0 [ 2136.388106] Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC [ 2136.388106] CPU 1 [ 2136.388106] Pid: 24855, comm: trinity-child1 Tainted: G W 3.5.0-rc2-sasha-00015-g7b268f7 #374 [ 2136.388106] RIP: 0010:[] [] __lock_acquire+0xc0/0x4b0 [ 2136.388106] RSP: 0018:ffff8800130b3ca8 EFLAGS: 00010046 [ 2136.388106] RAX: 0000000000000086 RBX: ffff88001186b000 RCX: 0000000000000000 [ 2136.388106] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 2136.388106] RBP: ffff8800130b3d08 R08: 0000000000000001 R09: 0000000000000000 [ 2136.388106] R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000002 [ 2136.388106] R13: 00000000000003b0 R14: 0000000000000000 R15: 0000000000000000 [ 2136.388106] FS: 00007fa5b1bd4700(0000) GS:ffff88001b800000(0000) knlGS:0000000000000000 [ 2136.388106] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2136.388106] CR2: 00000000000003b0 CR3: 0000000011d1f000 CR4: 00000000000406e0 [ 2136.388106] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 2136.388106] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 2136.388106] Process trinity-child1 (pid: 24855, threadinfo ffff8800130b2000, task ffff88001186b000) [ 2136.388106] Stack: [ 2136.388106] ffff8800130b3cd8 ffffffff81121785 ffffffff81236774 000080d000000001 [ 2136.388106] ffff88001b9d6c00 00000000001d6c00 ffffffff130b3d08 ffff88001186b000 [ 2136.388106] 0000000000000000 0000000000000002 0000000000000000 0000000000000000 [ 2136.388106] Call Trace: [ 2136.388106] [] ? sched_clock_local+0x25/0x90 [ 2136.388106] [] ? get_empty_filp+0x74/0x220 [ 2136.388106] [] lock_acquire+0x18a/0x1e0 [ 2136.388106] [] ? rawsock_release+0x4f/0xa0 [ 2136.388106] [] _raw_write_lock_bh+0x40/0x80 [ 2136.388106] [] ? rawsock_release+0x4f/0xa0 [ 2136.388106] [] rawsock_release+0x4f/0xa0 [ 2136.388106] [] sock_release+0x18/0x70 [ 2136.388106] [] sock_close+0x29/0x30 [ 2136.388106] [] __fput+0x11a/0x2c0 [ 2136.388106] [] fput+0x15/0x20 [ 2136.388106] [] sys_accept4+0x1b4/0x200 [ 2136.388106] [] ? _raw_spin_unlock_irq+0x4c/0x80 [ 2136.388106] [] ? _raw_spin_unlock_irq+0x59/0x80 [ 2136.388106] [] ? sysret_check+0x22/0x5d [ 2136.388106] [] sys_accept+0xb/0x10 [ 2136.388106] [] system_call_fastpath+0x16/0x1b [ 2136.388106] Code: ec 04 00 0f 85 ea 03 00 00 be d5 0b 00 00 48 c7 c7 8a c1 40 84 e8 b1 a5 f8 ff 31 c0 e9 d4 03 00 00 66 2e 0f 1f 84 00 00 00 00 00 <49> 81 7d 00 60 73 5e 85 b8 01 00 00 00 44 0f 44 e0 83 fe 01 77 [ 2136.388106] RIP [] __lock_acquire+0xc0/0x4b0 [ 2136.388106] RSP [ 2136.388106] CR2: 00000000000003b0 [ 2136.388106] ---[ end trace 6d450e935ee18982 ]--- [ 2136.388106] Kernel panic - not syncing: Fatal exception in interrupt rawsock_release() should test if sock->sk is NULL before calling sock_orphan()/sock_put() Reported-by: Sasha Levin Tested-by: Sasha Levin Signed-off-by: Eric Dumazet Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- net/nfc/rawsock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 5a839ceb2e8..e879dce5281 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -54,7 +54,10 @@ static int rawsock_release(struct socket *sock) { struct sock *sk = sock->sk; - pr_debug("sock=%p\n", sock); + pr_debug("sock=%p sk=%p\n", sock, sk); + + if (!sk) + return 0; sock_orphan(sk); sock_put(sk); From 6ee6b4d65c65a006b54b2f8f0aee405b1e01e2b2 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Mon, 25 Jun 2012 16:05:27 +0200 Subject: [PATCH 0324/2357] NFC: Prevent multiple buffer overflows in NCI commit 67de956ff5dc1d4f321e16cfbd63f5be3b691b43 upstream. Fix multiple remotely-exploitable stack-based buffer overflows due to the NCI code pulling length fields directly from incoming frames and copying too much data into statically-sized arrays. Signed-off-by: Dan Rosenberg Cc: security@kernel.org Cc: Lauro Ramos Venancio Cc: Aloisio Almeida Jr Cc: Samuel Ortiz Cc: David S. Miller Acked-by: Ilan Elias Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- net/nfc/nci/ntf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 2e3dee42196..e460cf13c56 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -106,7 +106,7 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data)); data += 2; - nfca_poll->nfcid1_len = *data++; + nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE); pr_debug("sens_res 0x%x, nfcid1_len %d\n", nfca_poll->sens_res, nfca_poll->nfcid1_len); @@ -130,7 +130,7 @@ static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, struct rf_tech_specific_params_nfcb_poll *nfcb_poll, __u8 *data) { - nfcb_poll->sensb_res_len = *data++; + nfcb_poll->sensb_res_len = min_t(__u8, *data++, NFC_SENSB_RES_MAXSIZE); pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len); @@ -145,7 +145,7 @@ static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, __u8 *data) { nfcf_poll->bit_rate = *data++; - nfcf_poll->sensf_res_len = *data++; + nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE); pr_debug("bit_rate %d, sensf_res_len %d\n", nfcf_poll->bit_rate, nfcf_poll->sensf_res_len); @@ -331,7 +331,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, switch (ntf->activation_rf_tech_and_mode) { case NCI_NFC_A_PASSIVE_POLL_MODE: nfca_poll = &ntf->activation_params.nfca_poll_iso_dep; - nfca_poll->rats_res_len = *data++; + nfca_poll->rats_res_len = min_t(__u8, *data++, 20); pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len); if (nfca_poll->rats_res_len > 0) { memcpy(nfca_poll->rats_res, @@ -341,7 +341,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, case NCI_NFC_B_PASSIVE_POLL_MODE: nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep; - nfcb_poll->attrib_res_len = *data++; + nfcb_poll->attrib_res_len = min_t(__u8, *data++, 50); pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len); if (nfcb_poll->attrib_res_len > 0) { memcpy(nfcb_poll->attrib_res, From 684f49c63edb17b18b8ffc84495e0b0aacc8f4ad Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Thu, 7 Jun 2012 04:54:29 -0400 Subject: [PATCH 0325/2357] hwmon: (applesmc) Limit key length in warning messages commit ac852edb47b15900886ba2564eeeb13b3b526e3e upstream. Key lookups may call read_smc() with a fixed-length key string, and if the lookup fails, trailing stack content may appear in the kernel log. Fixed with this patch. Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/applesmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index f082e48ab11..70d62f5bc90 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -215,7 +215,7 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len) int i; if (send_command(cmd) || send_argument(key)) { - pr_warn("%s: read arg fail\n", key); + pr_warn("%.4s: read arg fail\n", key); return -EIO; } @@ -223,7 +223,7 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len) for (i = 0; i < len; i++) { if (__wait_status(0x05)) { - pr_warn("%s: read data fail\n", key); + pr_warn("%.4s: read data fail\n", key); return -EIO; } buffer[i] = inb(APPLESMC_DATA_PORT); From a4ab3b05fe0320bad00a1ba320d6fd4b9cd29643 Mon Sep 17 00:00:00 2001 From: Lubomir Schmidt Date: Fri, 15 Jun 2012 15:12:17 -0500 Subject: [PATCH 0326/2357] staging: r8712u: Add new USB IDs commit 3026b0e942c65c65c8fc80d391d004228b52b916 upstream. There are two new devices for this driver. Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/usb_intf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index e419b4fd82b..2c80745a446 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -102,6 +102,8 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = { /* - */ {USB_DEVICE(0x20F4, 0x646B)}, {USB_DEVICE(0x083A, 0xC512)}, + {USB_DEVICE(0x25D4, 0x4CA1)}, + {USB_DEVICE(0x25D4, 0x4CAB)}, /* RTL8191SU */ /* Realtek */ From 615fb8b018599cfe16b466b1a1c98cf1c3ecaf0e Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Wed, 20 Jun 2012 12:52:57 -0700 Subject: [PATCH 0327/2357] nilfs2: ensure proper cache clearing for gc-inodes commit fbb24a3a915f105016f1c828476be11aceac8504 upstream. A gc-inode is a pseudo inode used to buffer the blocks to be moved by garbage collection. Block caches of gc-inodes must be cleared every time a garbage collection function (nilfs_clean_segments) completes. Otherwise, stale blocks buffered in the caches may be wrongly reused in successive calls of the GC function. For user files, this is not a problem because their gc-inodes are distinguished by a checkpoint number as well as an inode number. They never buffer different blocks if either an inode number, a checkpoint number, or a block offset differs. However, gc-inodes of sufile, cpfile and DAT file can store different data for the same block offset. Thus, the nilfs_clean_segments function can move incorrect block for these meta-data files if an old block is cached. I found this is really causing meta-data corruption in nilfs. This fixes the issue by ensuring cache clear of gc-inodes and resolves reported GC problems including checkpoint file corruption, b-tree corruption, and the following warning during GC. nilfs_palloc_freev: entry number 307234 already freed. ... Signed-off-by: Ryusuke Konishi Tested-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/nilfs2/gcinode.c | 2 ++ fs/nilfs2/segment.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index 08a07a218d2..57ceaf33d17 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c @@ -191,6 +191,8 @@ void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs) while (!list_empty(head)) { ii = list_first_entry(head, struct nilfs_inode_info, i_dirty); list_del_init(&ii->i_dirty); + truncate_inode_pages(&ii->vfs_inode.i_data, 0); + nilfs_btnode_cache_clear(&ii->i_btnode_cache); iput(&ii->vfs_inode); } } diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 0e72ad6f22a..88e11fb346b 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -2309,6 +2309,8 @@ nilfs_remove_written_gcinodes(struct the_nilfs *nilfs, struct list_head *head) if (!test_bit(NILFS_I_UPDATED, &ii->i_state)) continue; list_del_init(&ii->i_dirty); + truncate_inode_pages(&ii->vfs_inode.i_data, 0); + nilfs_btnode_cache_clear(&ii->i_btnode_cache); iput(&ii->vfs_inode); } } From 132a45d8bdc699d831dcc51cfd4db7238d183b42 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 27 Jun 2012 20:08:44 +0200 Subject: [PATCH 0328/2357] udf: Use 'ret' instead of abusing 'i' in udf_load_logicalvol() commit cb14d340ef1737c24125dd663eff77734a482d47 upstream. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/super.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index ac8a348dcb6..9da6f4ee112 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1233,11 +1233,9 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, BUG_ON(ident != TAG_IDENT_LVD); lvd = (struct logicalVolDesc *)bh->b_data; - i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); - if (i != 0) { - ret = i; + ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); + if (ret) goto out_bh; - } for (i = 0, offset = 0; i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength); From b3b9f9cd546c4b3d72b0a95ba4ca29c840fce28e Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 27 Jun 2012 20:20:22 +0200 Subject: [PATCH 0329/2357] udf: Avoid run away loop when partition table length is corrupted commit adee11b2085bee90bd8f4f52123ffb07882d6256 upstream. Check provided length of partition table so that (possibly maliciously) corrupted partition table cannot cause accessing data beyond current buffer. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/super.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 9da6f4ee112..ce911f50b39 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1225,6 +1225,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, struct genericPartitionMap *gpm; uint16_t ident; struct buffer_head *bh; + unsigned int table_len; int ret = 0; bh = udf_read_tagged(sb, block, block, &ident); @@ -1232,13 +1233,20 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, return 1; BUG_ON(ident != TAG_IDENT_LVD); lvd = (struct logicalVolDesc *)bh->b_data; + table_len = le32_to_cpu(lvd->mapTableLength); + if (sizeof(*lvd) + table_len > sb->s_blocksize) { + udf_err(sb, "error loading logical volume descriptor: " + "Partition table too long (%u > %lu)\n", table_len, + sb->s_blocksize - sizeof(*lvd)); + goto out_bh; + } ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); if (ret) goto out_bh; for (i = 0, offset = 0; - i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength); + i < sbi->s_partitions && offset < table_len; i++, offset += gpm->partitionMapLength) { struct udf_part_map *map = &sbi->s_partmaps[i]; gpm = (struct genericPartitionMap *) From 4836ee563d65bb492f907cbe267a5761b9693e4d Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 27 Jun 2012 21:23:07 +0200 Subject: [PATCH 0330/2357] udf: Fortify loading of sparing table commit 1df2ae31c724e57be9d7ac00d78db8a5dabdd050 upstream. Add sanity checks when loading sparing table from disk to avoid accessing unallocated memory or writing to it. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/super.c | 86 +++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index ce911f50b39..8d86a8706c0 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include "udf_sb.h" @@ -1215,11 +1216,59 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) return ret; } +static int udf_load_sparable_map(struct super_block *sb, + struct udf_part_map *map, + struct sparablePartitionMap *spm) +{ + uint32_t loc; + uint16_t ident; + struct sparingTable *st; + struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing; + int i; + struct buffer_head *bh; + + map->s_partition_type = UDF_SPARABLE_MAP15; + sdata->s_packet_len = le16_to_cpu(spm->packetLength); + if (!is_power_of_2(sdata->s_packet_len)) { + udf_err(sb, "error loading logical volume descriptor: " + "Invalid packet length %u\n", + (unsigned)sdata->s_packet_len); + return -EIO; + } + if (spm->numSparingTables > 4) { + udf_err(sb, "error loading logical volume descriptor: " + "Too many sparing tables (%d)\n", + (int)spm->numSparingTables); + return -EIO; + } + + for (i = 0; i < spm->numSparingTables; i++) { + loc = le32_to_cpu(spm->locSparingTable[i]); + bh = udf_read_tagged(sb, loc, loc, &ident); + if (!bh) + continue; + + st = (struct sparingTable *)bh->b_data; + if (ident != 0 || + strncmp(st->sparingIdent.ident, UDF_ID_SPARING, + strlen(UDF_ID_SPARING)) || + sizeof(*st) + le16_to_cpu(st->reallocationTableLen) > + sb->s_blocksize) { + brelse(bh); + continue; + } + + sdata->s_spar_map[i] = bh; + } + map->s_partition_func = udf_get_pblock_spar15; + return 0; +} + static int udf_load_logicalvol(struct super_block *sb, sector_t block, struct kernel_lb_addr *fileset) { struct logicalVolDesc *lvd; - int i, j, offset; + int i, offset; uint8_t type; struct udf_sb_info *sbi = UDF_SB(sb); struct genericPartitionMap *gpm; @@ -1281,38 +1330,9 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, } else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) { - uint32_t loc; - struct sparingTable *st; - struct sparablePartitionMap *spm = - (struct sparablePartitionMap *)gpm; - - map->s_partition_type = UDF_SPARABLE_MAP15; - map->s_type_specific.s_sparing.s_packet_len = - le16_to_cpu(spm->packetLength); - for (j = 0; j < spm->numSparingTables; j++) { - struct buffer_head *bh2; - - loc = le32_to_cpu( - spm->locSparingTable[j]); - bh2 = udf_read_tagged(sb, loc, loc, - &ident); - map->s_type_specific.s_sparing. - s_spar_map[j] = bh2; - - if (bh2 == NULL) - continue; - - st = (struct sparingTable *)bh2->b_data; - if (ident != 0 || strncmp( - st->sparingIdent.ident, - UDF_ID_SPARING, - strlen(UDF_ID_SPARING))) { - brelse(bh2); - map->s_type_specific.s_sparing. - s_spar_map[j] = NULL; - } - } - map->s_partition_func = udf_get_pblock_spar15; + if (udf_load_sparable_map(sb, map, + (struct sparablePartitionMap *)gpm) < 0) + goto out_bh; } else if (!strncmp(upm2->partIdent.ident, UDF_ID_METADATA, strlen(UDF_ID_METADATA))) { From 7b9f477f5188e237f52c8a1243fd55615c63064f Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 6 Jun 2012 10:50:06 -0600 Subject: [PATCH 0331/2357] iommu/amd: Fix missing iommu_shutdown initialization in passthrough mode commit f2f12b6fc032c7b1419fd6db84e2868b5f05a878 upstream. The iommu_shutdown callback is not initialized when the AMD IOMMU driver runs in passthrough mode. Fix that by moving the callback initialization before the check for passthrough mode. Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 542024ba6db..c04ddca7f12 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1641,6 +1641,8 @@ static int __init amd_iommu_init(void) amd_iommu_init_api(); + x86_platform.iommu_shutdown = disable_iommus; + if (iommu_pass_through) goto out; @@ -1649,8 +1651,6 @@ static int __init amd_iommu_init(void) else printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n"); - x86_platform.iommu_shutdown = disable_iommus; - out: return ret; From b9e619e35c808f11f2da804c2fac1f2031e1cafd Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 21 Jun 2012 14:52:40 +0200 Subject: [PATCH 0332/2357] iommu/amd: Initialize dma_ops for hotplug and sriov devices commit ac1534a55d1e87d59a21c09c570605933b551480 upstream. When a device is added to the system at runtime the AMD IOMMU driver initializes the necessary data structures to handle translation for it. But it forgets to change the per-device dma_ops to point to the AMD IOMMU driver. So mapping actually never happens and all DMA accesses end in an IO_PAGE_FAULT. Fix this. Reported-by: Stefan Assmann Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index a2e418cba0f..dfe7d37c82c 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -83,6 +83,8 @@ static struct iommu_ops amd_iommu_ops; static ATOMIC_NOTIFIER_HEAD(ppr_notifier); int amd_iommu_max_glx_val = -1; +static struct dma_map_ops amd_iommu_dma_ops; + /* * general struct to manage commands send to an IOMMU */ @@ -2267,6 +2269,13 @@ static int device_change_notifier(struct notifier_block *nb, list_add_tail(&dma_domain->list, &iommu_pd_list); spin_unlock_irqrestore(&iommu_pd_list_lock, flags); + dev_data = get_dev_data(dev); + + if (!dev_data->passthrough) + dev->archdata.dma_ops = &amd_iommu_dma_ops; + else + dev->archdata.dma_ops = &nommu_dma_ops; + break; case BUS_NOTIFY_DEL_DEVICE: From 4ce16269215ffaad3d480425bc74bf632956151e Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Wed, 27 Jun 2012 12:54:01 +0300 Subject: [PATCH 0333/2357] iommu/tegra: smmu: Fix unsleepable memory allocation commit 8f53dc724a83a0082184fa27df80c25c7df47340 upstream. allo_pdir() is called in smmu_iommu_domain_init() with spin_lock held. memory allocations in it have to be atomic/unsleepable. Signed-off-by: Hiroshi DOYU Reported-by: Chris Wright Acked-by: Chris Wright Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/tegra-smmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index eb93c821f59..17ef6c49366 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -550,13 +550,13 @@ static int alloc_pdir(struct smmu_as *as) return 0; as->pte_count = devm_kzalloc(smmu->dev, - sizeof(as->pte_count[0]) * SMMU_PDIR_COUNT, GFP_KERNEL); + sizeof(as->pte_count[0]) * SMMU_PDIR_COUNT, GFP_ATOMIC); if (!as->pte_count) { dev_err(smmu->dev, "failed to allocate smmu_device PTE cunters\n"); return -ENOMEM; } - as->pdir_page = alloc_page(GFP_KERNEL | __GFP_DMA); + as->pdir_page = alloc_page(GFP_ATOMIC | __GFP_DMA); if (!as->pdir_page) { dev_err(smmu->dev, "failed to allocate smmu_device page directory\n"); From 735129c4609e98fd149cddda50b823e43bab0677 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Wed, 6 Jun 2012 10:09:25 +0300 Subject: [PATCH 0334/2357] rpmsg: avoid premature deallocation of endpoints commit 5a081caa0414b9bbb82c17ffab9d6fe66edbb72f upstream. When an inbound message arrives, the rpmsg core looks up its associated endpoint and invokes the registered callback. If a message arrives while its endpoint is being removed (because the rpmsg driver was removed, or a recovery of a remote processor has kicked in) we must ensure atomicity, i.e.: - Either the ept is removed before it is found or - The ept is found but will not be freed until the callback returns This is achieved by maintaining a per-ept reference count, which, when drops to zero, will trigger deallocation of the ept. With this in hand, it is now forbidden to directly deallocate epts once they have been added to the endpoints idr. Reported-by: Fernando Guzman Lugo Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/rpmsg/virtio_rpmsg_bus.c | 36 ++++++++++++++++++++++++++++++-- include/linux/rpmsg.h | 3 +++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 75506ec2840..9623327ba50 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -188,6 +188,26 @@ static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env) rpdev->id.name); } +/** + * __ept_release() - deallocate an rpmsg endpoint + * @kref: the ept's reference count + * + * This function deallocates an ept, and is invoked when its @kref refcount + * drops to zero. + * + * Never invoke this function directly! + */ +static void __ept_release(struct kref *kref) +{ + struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint, + refcount); + /* + * At this point no one holds a reference to ept anymore, + * so we can directly free it + */ + kfree(ept); +} + /* for more info, see below documentation of rpmsg_create_ept() */ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp, struct rpmsg_channel *rpdev, rpmsg_rx_cb_t cb, @@ -206,6 +226,8 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp, return NULL; } + kref_init(&ept->refcount); + ept->rpdev = rpdev; ept->cb = cb; ept->priv = priv; @@ -238,7 +260,7 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp, idr_remove(&vrp->endpoints, request); free_ept: mutex_unlock(&vrp->endpoints_lock); - kfree(ept); + kref_put(&ept->refcount, __ept_release); return NULL; } @@ -306,7 +328,7 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept) idr_remove(&vrp->endpoints, ept->addr); mutex_unlock(&vrp->endpoints_lock); - kfree(ept); + kref_put(&ept->refcount, __ept_release); } /** @@ -790,7 +812,13 @@ static void rpmsg_recv_done(struct virtqueue *rvq) /* use the dst addr to fetch the callback of the appropriate user */ mutex_lock(&vrp->endpoints_lock); + ept = idr_find(&vrp->endpoints, msg->dst); + + /* let's make sure no one deallocates ept while we use it */ + if (ept) + kref_get(&ept->refcount); + mutex_unlock(&vrp->endpoints_lock); if (ept && ept->cb) @@ -798,6 +826,10 @@ static void rpmsg_recv_done(struct virtqueue *rvq) else dev_warn(dev, "msg received with no recepient\n"); + /* farewell, ept, we don't need you anymore */ + if (ept) + kref_put(&ept->refcount, __ept_release); + /* publish the real size of the buffer */ sg_init_one(&sg, msg, RPMSG_BUF_SIZE); diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index a8e50e44203..195f373590b 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -38,6 +38,7 @@ #include #include #include +#include /* The feature bitmap for virtio rpmsg */ #define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ @@ -120,6 +121,7 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user * @rpdev: rpmsg channel device + * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler * @addr: local rpmsg address * @priv: private data for the driver's use @@ -140,6 +142,7 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32); */ struct rpmsg_endpoint { struct rpmsg_channel *rpdev; + struct kref refcount; rpmsg_rx_cb_t cb; u32 addr; void *priv; From 0f9c37b38800c35e83f43949d93bffefff5b43af Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Thu, 7 Jun 2012 15:39:35 +0300 Subject: [PATCH 0335/2357] rpmsg: make sure inflight messages don't invoke just-removed callbacks commit 15fd943af50dbc5f7f4de33835795c72595f7bf4 upstream. When inbound messages arrive, rpmsg core looks up their associated endpoint (by destination address) and then invokes their callback. We've made sure that endpoints will never be de-allocated after they were found by rpmsg core, but we also need to protect against the (rare) scenario where the rpmsg driver was just removed, and its callback function isn't available anymore. This is achieved by introducing a callback mutex, which must be taken before the callback is invoked, and, obviously, before it is removed. Reported-by: Fernando Guzman Lugo Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/rpmsg/virtio_rpmsg_bus.c | 25 +++++++++++++++++++------ include/linux/rpmsg.h | 3 +++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 9623327ba50..39d3aa41add 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -227,6 +227,7 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp, } kref_init(&ept->refcount); + mutex_init(&ept->cb_lock); ept->rpdev = rpdev; ept->cb = cb; @@ -324,10 +325,16 @@ EXPORT_SYMBOL(rpmsg_create_ept); static void __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept) { + /* make sure new inbound messages can't find this ept anymore */ mutex_lock(&vrp->endpoints_lock); idr_remove(&vrp->endpoints, ept->addr); mutex_unlock(&vrp->endpoints_lock); + /* make sure in-flight inbound messages won't invoke cb anymore */ + mutex_lock(&ept->cb_lock); + ept->cb = NULL; + mutex_unlock(&ept->cb_lock); + kref_put(&ept->refcount, __ept_release); } @@ -821,14 +828,20 @@ static void rpmsg_recv_done(struct virtqueue *rvq) mutex_unlock(&vrp->endpoints_lock); - if (ept && ept->cb) - ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, msg->src); - else - dev_warn(dev, "msg received with no recepient\n"); + if (ept) { + /* make sure ept->cb doesn't go away while we use it */ + mutex_lock(&ept->cb_lock); - /* farewell, ept, we don't need you anymore */ - if (ept) + if (ept->cb) + ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, + msg->src); + + mutex_unlock(&ept->cb_lock); + + /* farewell, ept, we don't need you anymore */ kref_put(&ept->refcount, __ept_release); + } else + dev_warn(dev, "msg received with no recepient\n"); /* publish the real size of the buffer */ sg_init_one(&sg, msg, RPMSG_BUF_SIZE); diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 195f373590b..82a673905ed 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -39,6 +39,7 @@ #include #include #include +#include /* The feature bitmap for virtio rpmsg */ #define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ @@ -123,6 +124,7 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32); * @rpdev: rpmsg channel device * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler + * @cb_lock: must be taken before accessing/changing @cb * @addr: local rpmsg address * @priv: private data for the driver's use * @@ -144,6 +146,7 @@ struct rpmsg_endpoint { struct rpmsg_channel *rpdev; struct kref refcount; rpmsg_rx_cb_t cb; + struct mutex cb_lock; u32 addr; void *priv; }; From 9471356d7e58fbc3e1d307d911432261398abb56 Mon Sep 17 00:00:00 2001 From: Suresh Jayaraman Date: Tue, 12 Jun 2012 07:15:50 +0530 Subject: [PATCH 0336/2357] cifs: fix parsing of password mount option commit e73f843a3235a19de38359c91586e9eadef12238 upstream. The double delimiter check that allows a comma in the password parsing code is unconditional. We set "tmp_end" to the end of the string and we continue to check for double delimiter. In the case where the password doesn't contain a comma we end up setting tmp_end to NULL and eventually setting "options" to "end". This results in the premature termination of the options string and hence the values of UNCip and UNC are being set to NULL. This results in mount failure with "Connecting to DFS root not implemented yet" error. This error is usually not noticable as we have password as the last option in the superblock mountdata. But when we call expand_dfs_referral() from cifs_mount() and try to compose mount options for the submount, the resulting mountdata will be of the form ",ver=1,user=foo,pass=bar,ip=x.x.x.x,unc=\\server\share" and hence results in the above error. This bug has been seen with older NAS servers running Samba 3.0.24. Fix this by moving the double delimiter check inside the conditional loop. Changes since -v1 - removed the wrong strlen() micro optimization. Signed-off-by: Suresh Jayaraman Acked-by: Sachin Prabhu Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/connect.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e0b56d7a19c..981cc62a34d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1585,24 +1585,26 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, * If yes, we have encountered a double deliminator * reset the NULL character to the deliminator */ - if (tmp_end < end && tmp_end[1] == delim) + if (tmp_end < end && tmp_end[1] == delim) { tmp_end[0] = delim; - /* Keep iterating until we get to a single deliminator - * OR the end - */ - while ((tmp_end = strchr(tmp_end, delim)) != NULL && - (tmp_end[1] == delim)) { - tmp_end = (char *) &tmp_end[2]; - } + /* Keep iterating until we get to a single + * deliminator OR the end + */ + while ((tmp_end = strchr(tmp_end, delim)) + != NULL && (tmp_end[1] == delim)) { + tmp_end = (char *) &tmp_end[2]; + } - /* Reset var options to point to next element */ - if (tmp_end) { - tmp_end[0] = '\0'; - options = (char *) &tmp_end[1]; - } else - /* Reached the end of the mount option string */ - options = end; + /* Reset var options to point to next element */ + if (tmp_end) { + tmp_end[0] = '\0'; + options = (char *) &tmp_end[1]; + } else + /* Reached the end of the mount option + * string */ + options = end; + } /* Now build new password string */ temp_len = strlen(value); From f4367f246e048e7fac50769d1d1447306a984f4e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 2 Jul 2012 07:24:25 -0400 Subject: [PATCH 0337/2357] cifs: when server doesn't set CAP_LARGE_READ_X, cap default rsize at MaxBufferSize commit ec01d738a1691dfc85b96b9f796020267a7be577 upstream. When the server doesn't advertise CAP_LARGE_READ_X, then MS-CIFS states that you must cap the size of the read at the client's MaxBufferSize. Unfortunately, testing with many older servers shows that they often can't service a read larger than their own MaxBufferSize. Since we can't assume what the server will do in this situation, we must be conservative here for the default. When the server can't do large reads, then assume that it can't satisfy any read larger than its MaxBufferSize either. Luckily almost all modern servers can do large reads, so this won't affect them. This is really just for older win9x and OS/2 era servers. Also, note that this patch just governs the default rsize. The admin can always override this if he so chooses. Reported-by: David H. Durgee Signed-off-by: Jeff Layton Signed-off-by: Steven French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/connect.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 981cc62a34d..402fa0f9bc0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3398,18 +3398,15 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) * MS-CIFS indicates that servers are only limited by the client's * bufsize for reads, testing against win98se shows that it throws * INVALID_PARAMETER errors if you try to request too large a read. + * OS/2 just sends back short reads. * - * If the server advertises a MaxBufferSize of less than one page, - * assume that it also can't satisfy reads larger than that either. - * - * FIXME: Is there a better heuristic for this? + * If the server doesn't advertise CAP_LARGE_READ_X, then assume that + * it can't handle a read request larger than its MaxBufferSize either. */ if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP)) defsize = CIFS_DEFAULT_IOSIZE; else if (server->capabilities & CAP_LARGE_READ_X) defsize = CIFS_DEFAULT_NON_POSIX_RSIZE; - else if (server->maxBuf >= PAGE_CACHE_SIZE) - defsize = CIFSMaxBufSize; else defsize = server->maxBuf - sizeof(READ_RSP); From ad95174b4857549e7b1659f66a29b5151176ade0 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 6 Jun 2012 10:33:10 +0530 Subject: [PATCH 0338/2357] ath9k: Fix a WARNING on suspend/resume with IBSS commit 2031b4c2b4904f7448ab9e4bc6b9bf16e32709f5 upstream. this patch is dependent on the patch "cfg80211: fix interface combinations" In ath9k currently we have ADHOC interface as a single incompatible interface. when drv_add_interface is called during resume we got to consider number of vifs already present in addition to checking the drivers 'opmode' information about ADHOC. we incorrectly assume an ADHOC interface is already present. Then we may miss some driver specific data for the ADHOC interface after resume. The above mentioned checks can be removed from the driver, as the patch 'cfg80211: fix interface combinations' ensures that if an interface type is not advertised by the driver in any of the interface combinations(via ieee80211_iface_combination) then it shall be treated as a single incompatible interface. Fixes the following warning on suspend/resume with ibss interface. ath: phy0: Cannot create ADHOC interface when other interfaces already exist. WARNING: at net/mac80211/driver-ops.h:12 ieee80211_reconfig+0x1882/0x1ca0 [mac80211]() Hardware name: 2842RK1 wlan2: Failed check-sdata-in-driver check, flags: 0x0 Call Trace: [] warn_slowpath_common+0x72/0xa0 [] ? ieee80211_reconfig+0x1882/0x1ca0 [mac80211] [] ? ieee80211_reconfig+0x1882/0x1ca0 [mac80211] [] warn_slowpath_fmt+0x33/0x40 [] ieee80211_reconfig+0x1882/0x1ca0 [mac80211] [] ? mutex_lock_nested+0x23a/0x2f0 [] ieee80211_resume+0x27/0x70 [mac80211] [] wiphy_resume+0x8f/0xa0 [cfg80211] Cc: Rajkumar Manoharan Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/main.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 798ea57252b..42e3f427c74 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1419,15 +1419,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, } } - if ((ah->opmode == NL80211_IFTYPE_ADHOC) || - ((vif->type == NL80211_IFTYPE_ADHOC) && - sc->nvifs > 0)) { - ath_err(common, "Cannot create ADHOC interface when other" - " interfaces already exist.\n"); - ret = -EINVAL; - goto out; - } - ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); sc->nvifs++; From e0d1c1de5638a4fffbc9d5d9f141c434531dc3b9 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 13 Jun 2012 21:28:09 +0530 Subject: [PATCH 0339/2357] ath9k: Fix softlockup in AR9485 commit bcb7ad7bcbef030e6ba71ede1f9866368aca7c99 upstream. steps to recreate: load latest ath9k driver with AR9485 stop the network-manager and wpa_supplicant bring the interface up Call Trace: [] ? ath_hw_check+0xe0/0xe0 [ath9k] [] __const_udelay+0x28/0x30 [] ar9003_get_pll_sqsum_dvc+0x4a/0x80 [ath9k_hw] [] ath_hw_pll_work+0x5b/0xe0 [ath9k] [] process_one_work+0x11e/0x470 [] worker_thread+0x15f/0x360 [] ? manage_workers+0x230/0x230 [] kthread+0x93/0xa0 [] kernel_thread_helper+0x4/0x10 [] ? kthread_freezable_should_stop+0x70/0x70 [] ? gs_change+0x13/0x13 ensure that the PLL-WAR for AR9485/AR9340 is executed only if the STA is associated (or) IBSS/AP mode had started beaconing. Ideally this WAR is needed to recover from some rare beacon stuck during stress testing. Before the STA is associated/IBSS had started beaconing, PLL4(0x1618c) always seem to have zero even though we had configured PLL3(0x16188) to query about PLL's locking status. When we keep on polling infinitely PLL4's 8th bit(ie check for PLL locking measurements is done), machine hangs due to softlockup. fixes https://bugzilla.redhat.com/show_bug.cgi?id=811142 Reported-by: Rolf Offermanns Tested-by: Mohammed Shafi Shajakhan Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 42e3f427c74..d5dabcb61a0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -960,6 +960,15 @@ void ath_hw_pll_work(struct work_struct *work) hw_pll_work.work); u32 pll_sqsum; + /* + * ensure that the PLL WAR is executed only + * after the STA is associated (or) if the + * beaconing had started in interfaces that + * uses beacons. + */ + if (!(sc->sc_flags & SC_OP_BEACONS)) + return; + if (AR_SREV_9485(sc->sc_ah)) { ath9k_ps_wakeup(sc); From 7664af6e949f3facf0e8071053627a8fa4aaff5a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Jun 2012 03:04:52 +0200 Subject: [PATCH 0340/2357] ath9k: fix a tx rate duration calculation bug commit 76591bea9714a58d8924154068c78d702eb2cb17 upstream. The rate pointer variable for a rate series is used in a loop before it is initialized. This went unnoticed because it was used earlier for the RTS/CTS rate. This bug can lead to the wrong PHY type being passed to the duration calculation function. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index d59dd01d6cd..efb7f00f356 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1001,13 +1001,13 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, } /* legacy rates */ + rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; if ((tx_info->band == IEEE80211_BAND_2GHZ) && !(rate->flags & IEEE80211_RATE_ERP_G)) phy = WLAN_RC_PHY_CCK; else phy = WLAN_RC_PHY_OFDM; - rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; info->rates[i].Rate = rate->hw_value; if (rate->hw_value_short) { if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) From d8a7bedebed60ec6366550edccff31f3e8c509a4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Jun 2012 03:04:53 +0200 Subject: [PATCH 0341/2357] ath9k: fix invalid pointer access in the tx path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 80b08a8d8829a58b5db14b1417151094cc28face upstream. After setup_frame_info has been called, only info->control.rates is still valid, other control fields have been overwritten by the ath_frame_info data. Move the access to info->control.vif for checking short preamble to setup_frame_info before it gets overwritten. This regression was introduced in commit d47a61aa "ath9k: Fix multi-VIF BSS handling" Signed-off-by: Felix Fietkau Reported-by: Thomas Hühn Acked-by: Sujith Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/xmit.c | 29 +++++++++++++++----------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8c84049682a..4bfb44a094d 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -213,6 +213,7 @@ struct ath_frame_info { enum ath9k_key_type keytype; u8 keyix; u8 retries; + u8 rtscts_rate; }; struct ath_buf_state { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index efb7f00f356..4d571394c7a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -938,6 +938,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_rate *rates; const struct ieee80211_rate *rate; struct ieee80211_hdr *hdr; + struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); int i; u8 rix = 0; @@ -948,18 +949,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, /* set dur_update_en for l-sig computation except for PS-Poll frames */ info->dur_update = !ieee80211_is_pspoll(hdr->frame_control); - - /* - * We check if Short Preamble is needed for the CTS rate by - * checking the BSS's global flag. - * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. - */ - rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info); - info->rtscts_rate = rate->hw_value; - - if (tx_info->control.vif && - tx_info->control.vif->bss_conf.use_short_preamble) - info->rtscts_rate |= rate->hw_value_short; + info->rtscts_rate = fi->rtscts_rate; for (i = 0; i < 4; i++) { bool is_40, is_sgi, is_sp; @@ -1776,10 +1766,22 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + const struct ieee80211_rate *rate; struct ath_frame_info *fi = get_frame_info(skb); struct ath_node *an = NULL; enum ath9k_key_type keytype; + bool short_preamble = false; + + /* + * We check if Short Preamble is needed for the CTS rate by + * checking the BSS's global flag. + * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. + */ + if (tx_info->control.vif && + tx_info->control.vif->bss_conf.use_short_preamble) + short_preamble = true; + rate = ieee80211_get_rts_cts_rate(hw, tx_info); keytype = ath9k_cmn_get_hw_crypto_keytype(skb); if (sta) @@ -1794,6 +1796,9 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; fi->framelen = framelen; + fi->rtscts_rate = rate->hw_value; + if (short_preamble) + fi->rtscts_rate |= rate->hw_value_short; } u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) From 084f5074c2d08a343590f386de79fd9ae2406c03 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 18 Jun 2012 13:13:30 +0530 Subject: [PATCH 0342/2357] ath9k_hw: avoid possible infinite loop in ar9003_get_pll_sqsum_dvc commit f18e3c6b67f448ec47b3a5b242789bd3d5644879 upstream. "ath9k: Fix softlockup in AR9485" with commit id 64bc1239c790e051ff677e023435d770d2ffa174 fixed the reported issue, yet its better to avoid the possible infinite loop in ar9003_get_pll_sqsum_dvc by having a timeout as suggested by ath9k maintainers. http://www.spinics.net/lists/linux-wireless/msg92126.html. Based on my testing PLL's locking measurement is done in ~200us (2 iterations). Cc: Rolf Offermanns Cc: Sujith Manoharan Cc: Senthil Balasubramanian Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hw.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index fa84e37bf09..0c59778d47b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -720,13 +720,25 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); + int i = 0; + REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); udelay(100); REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); - while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) + while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) { + udelay(100); + if (WARN_ON_ONCE(i >= 100)) { + ath_err(common, "PLL4 meaurement not done\n"); + break; + } + + i++; + } + return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; } EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); From 301fef5503d98deb0b0d27b643b711b73e04c578 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 20 Jun 2012 16:29:20 +0530 Subject: [PATCH 0343/2357] ath9k_htc: configure bssid on ASSOC/IBSS change commit 931cb03afed7b541392295f3afc4638da32f08a0 upstream. After the change "mac80211: remove spurious BSSID change flag", BSS_CHANGED_BSSID will not be passed on association or IBSS status changes. So it could be better to program bssid on ASSOC or IBSS change notification. Not doing so, is affecting the packet transmission. Reported-by: Michael Leun Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 2b8f61c210e..abbd6effd60 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1496,6 +1496,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--; if (priv->ah->opmode == NL80211_IFTYPE_STATION) { + ath9k_htc_choose_set_bssid(priv); if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1)) ath9k_htc_start_ani(priv); else if (priv->num_sta_assoc_vif == 0) @@ -1503,13 +1504,11 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_BSSID) { + if (changed & BSS_CHANGED_IBSS) { if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { common->curaid = bss_conf->aid; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); ath9k_htc_set_bssid(priv); - } else if (priv->ah->opmode == NL80211_IFTYPE_STATION) { - ath9k_htc_choose_set_bssid(priv); } } From aeb0da0b585868aed04e53afd1234791efcfac08 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 23 Jun 2012 19:23:31 +0200 Subject: [PATCH 0344/2357] ath9k: fix dynamic WEP related regression commit bed3d9c0b71f9afbfec905cb6db3b9f16be29d4d upstream. commit 7a532fe7131216a02c81a6c1b1f8632da1195a58 ath9k_hw: fix interpretation of the rx KeyMiss flag This commit used the rx key miss indication to detect packets that were passed from the hardware without being decrypted, however it seems that this bit is not only undefined in the static WEP case, but also for dynamically allocated WEP keys. This caused a regression when using WEP-LEAP. This patch fixes the regression by keeping track of which key indexes refer to CCMP keys and only using the key miss indication for those. Reported-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/recv.c | 3 ++- drivers/net/wireless/ath/key.c | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index c54b7d37bff..420d69b2674 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -143,6 +143,7 @@ struct ath_common { u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX); + DECLARE_BITMAP(ccmp_keymap, ATH_KEYMAX); enum ath_crypt_caps crypt_caps; unsigned int clockrate; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 1c4583c7ff7..1efd6c9beb3 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -821,7 +821,8 @@ static bool ath9k_rx_accept(struct ath_common *common, * descriptor does contain a valid key index. This has been observed * mostly with CCMP encryption. */ - if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID) + if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || + !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; if (!rx_stats->rs_datalen) diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 0e81904956c..5c54aa43ca2 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -556,6 +556,9 @@ int ath_key_config(struct ath_common *common, return -EIO; set_bit(idx, common->keymap); + if (key->cipher == WLAN_CIPHER_SUITE_CCMP) + set_bit(idx, common->ccmp_keymap); + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { set_bit(idx + 64, common->keymap); set_bit(idx, common->tkip_keymap); @@ -582,6 +585,7 @@ void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key) return; clear_bit(key->hw_key_idx, common->keymap); + clear_bit(key->hw_key_idx, common->ccmp_keymap); if (key->cipher != WLAN_CIPHER_SUITE_TKIP) return; From 72c06c7a0aa9158d75216a86307f6a80f284b11f Mon Sep 17 00:00:00 2001 From: Panayiotis Karabassis Date: Tue, 26 Jun 2012 23:37:17 +0300 Subject: [PATCH 0345/2357] ath9k: enable serialize_regmode for non-PCIE AR9287 commit 7508b657967cf664b5aa0f6367d05016e7e3bc2a upstream. https://bugzilla.kernel.org/show_bug.cgi?id=42903 Based on the work of Signed-off-by: Panayiotis Karabassis Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0c59778d47b..6dfd9644884 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -558,7 +558,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || - ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) && + ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && !ah->is_pciexpress)) { ah->config.serialize_regmode = SER_REG_MODE_ON; From 78713ddf9b1d43729c9d497072b63f6dcee17d15 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 20 Jun 2012 14:16:57 +0100 Subject: [PATCH 0346/2357] ASoC: wm2200: Add missing BCLK rate commit b0dfa4541e48ac4cc5f017285432c89923ad0f58 upstream. Without this very high BCLKs will be configured incorrectly. Reported-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm2200.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index acbdc5fde92..32682c1b7cd 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1491,6 +1491,7 @@ static int wm2200_bclk_rates_dat[WM2200_NUM_BCLK_RATES] = { static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = { 5644800, + 3763200, 2882400, 1881600, 1411200, From becbf4ebbb41acee5c0dcf2851af6bd84964fc00 Mon Sep 17 00:00:00 2001 From: "Hebbar, Gururaja" Date: Tue, 26 Jun 2012 19:25:11 +0530 Subject: [PATCH 0347/2357] ASoC: tlv320aic3x: Fix codec pll configure bug commit c9fe573a6584034670c1a55ee8162d623519cbbf upstream. In sound/soc/codecs/tlv320aic3x.c data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); In the above code, pll-p value is OR'ed with previous value without clearing it. Bug is not seen if pll-p value doesn't change across Sampling frequency. However on some platforms (like AM335x EVM-SK), pll-p may have different values across different sampling frequencies. In such case, above code configures the pll with a wrong value. Because of this bug, when a audio stream is played with pll value different from previous stream, audio is heard as differently(like its stretched). Signed-off-by: Hebbar, Gururaja Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/tlv320aic3x.c | 4 +--- sound/soc/codecs/tlv320aic3x.h | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 8d20f6ec20f..b8f0262ac3e 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -936,9 +936,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, } found: - data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); - snd_soc_write(codec, AIC3X_PLL_PROGA_REG, - data | (pll_p << PLLP_SHIFT)); + snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, PLLP_MASK, pll_p); snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 6f097fb6068..08c7f6685ff 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -166,6 +166,7 @@ /* PLL registers bitfields */ #define PLLP_SHIFT 0 +#define PLLP_MASK 7 #define PLLQ_SHIFT 3 #define PLLR_SHIFT 0 #define PLLJ_SHIFT 2 From dbc904343caccba0ce47a51379c4a743da504a8a Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Mon, 2 Jul 2012 15:29:53 -0400 Subject: [PATCH 0348/2357] Btrfs: run delayed directory updates during log replay commit b6305567e7d31b0bec1b8cb9ec0cadd7f7086f5f upstream. While we are resolving directory modifications in the tree log, we are triggering delayed metadata updates to the filesystem btrees. This commit forces the delayed updates to run so the replay code can find any modifications done. It stops us from crashing because the directory deleltion replay expects items to be removed immediately from the tree. Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/tree-log.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index eb1ae908582..dce89da9c86 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -690,6 +690,8 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, kfree(name); iput(inode); + + btrfs_run_delayed_items(trans, root); return ret; } @@ -895,6 +897,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ret = btrfs_unlink_inode(trans, root, dir, inode, victim_name, victim_name_len); + btrfs_run_delayed_items(trans, root); } kfree(victim_name); ptr = (unsigned long)(victim_ref + 1) + victim_name_len; @@ -1475,6 +1478,9 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, ret = btrfs_unlink_inode(trans, root, dir, inode, name, name_len); BUG_ON(ret); + + btrfs_run_delayed_items(trans, root); + kfree(name); iput(inode); From dec7e3ab49dcdb1b7997008230eb18d520899119 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 19 Jun 2012 11:33:06 +0200 Subject: [PATCH 0349/2357] drm/edid: don't return stack garbage from supports_rb commit b196a4980ff7bb54db478e2a408dc8b12be15304 upstream. We need to initialize this to false, because the is_rb callback only ever sets it to true. Noticed while reading through the code. Signed-Off-by: Daniel Vetter Reviewed-by: Adam Jackson Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_edid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5a18b0df828..6e38325d04a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -574,7 +574,7 @@ static bool drm_monitor_supports_rb(struct edid *edid) { if (edid->revision >= 4) { - bool ret; + bool ret = false; drm_for_each_detailed_block((u8 *)edid, is_rb, &ret); return ret; } From eb858e23a8aa132d068aa639f617ba38e008d077 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 26 Jun 2012 12:12:30 +1000 Subject: [PATCH 0350/2357] drm/nouveau/fbcon: using nv_two_heads is not a good idea commit 9bd0c15fcfb42f6245447c53347d65ad9e72080b upstream. nv_two_heads() was never meant to be used outside of pre-nv50 code. The code checks for >= NV_10 for 2 CRTCs, then downgrades a few specific chipsets to 1 CRTC based on (pci_device & 0x0ff0). The breakage example seen is on GTX 560Ti, with a pciid of 0x1200, which gets detected as an NV20 (0x020x) with 1 CRTC by nv_two_heads(), causing memory corruption because there's actually 2 CRTCs.. This switches fbcon to use the CRTC count directly from the mode_config structure, which will also fix the same issue on Kepler boards which have 4 CRTCs. Signed-off-by: Ben Skeggs Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 8113e9201ed..6fd2211121f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -497,7 +497,7 @@ int nouveau_fbcon_init(struct drm_device *dev) nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; ret = drm_fb_helper_init(dev, &nfbdev->helper, - nv_two_heads(dev) ? 2 : 1, 4); + dev->mode_config.num_crtc, 4); if (ret) { kfree(nfbdev); return ret; From 6ad566e162cbf778300fd6bfe37c98b5ce46d58b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Jun 2012 15:30:41 +0200 Subject: [PATCH 0351/2357] drm/i915: Fix eDP blank screen after S3 resume on HP desktops commit 6db65cbb941f9d433659bdad02b307f6d94465df upstream. This patch fixes the problem on some HP desktop machines with eDP which give blank screens after S3 resume. It turned out that BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2. Otherwise it doesn't take effect on these SNB machines. Tested with 3.5-rc3 kernel. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=49233 Signed-off-by: Takashi Iwai Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_suspend.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 2b5eb229ff2..0d13778a5aa 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -740,8 +740,11 @@ static void i915_restore_display(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) { I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->saveBLC_PWM_CTL); I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->saveBLC_PWM_CTL2); - I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->saveBLC_CPU_PWM_CTL); + /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2; + * otherwise we get blank eDP screen after S3 on some machines + */ I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->saveBLC_CPU_PWM_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->saveBLC_CPU_PWM_CTL); I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS); I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS); I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR); From a00d69ed0676b53e7e5c8d086d47a92f15b91e38 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 28 Jun 2012 17:53:07 -0400 Subject: [PATCH 0352/2357] drm/radeon: fix VM page table setup on SI commit c21b328ea8c7c71cd2daf50557db440bbaa7ef55 upstream. Cayman and trinity allow for variable sized VM page tables, but SI requires that all page tables be the same size. The current code assumes variablely sized VM page tables so SI may end up with part of each page table overlapping with other memory which could end up being interpreted by the VM hw as garbage. Change the code to better accomodate SI. Allocate enough space for at least 2 full page tables and always set last_pfn to max_pfn on SI so each VM is backed by a full page table. This limits us to only 2 VMs active at any given time on SI. This will be rectified and the code can be reunified once we move to two level page tables. Signed-off-by: Alex Deucher Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_gart.c | 13 +++++++++++-- drivers/gpu/drm/radeon/si.c | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 62050f52194..2a4c592a75a 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -289,8 +289,9 @@ int radeon_vm_manager_init(struct radeon_device *rdev) rdev->vm_manager.enabled = false; /* mark first vm as always in use, it's the system one */ + /* allocate enough for 2 full VM pts */ r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager, - rdev->vm_manager.max_pfn * 8, + rdev->vm_manager.max_pfn * 8 * 2, RADEON_GEM_DOMAIN_VRAM); if (r) { dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n", @@ -635,7 +636,15 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) mutex_init(&vm->mutex); INIT_LIST_HEAD(&vm->list); INIT_LIST_HEAD(&vm->va); - vm->last_pfn = 0; + /* SI requires equal sized PTs for all VMs, so always set + * last_pfn to max_pfn. cayman allows variable sized + * pts so we can grow then as needed. Once we switch + * to two level pts we can unify this again. + */ + if (rdev->family >= CHIP_TAHITI) + vm->last_pfn = rdev->vm_manager.max_pfn; + else + vm->last_pfn = 0; /* map the ib pool buffer at 0 in virtual address space, set * read only */ diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 27bda986fc2..2af1ce69e6e 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2527,12 +2527,12 @@ int si_pcie_gart_enable(struct radeon_device *rdev) WREG32(0x15DC, 0); /* empty context1-15 */ - /* FIXME start with 1G, once using 2 level pt switch to full + /* FIXME start with 4G, once using 2 level pt switch to full * vm size space */ /* set vm size, must be a multiple of 4 */ WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0); - WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, (1 << 30) / RADEON_GPU_PAGE_SIZE); + WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn); for (i = 1; i < 16; i++) { if (i < 8) WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), From 4849c078f07f5eb93eff651d3a32cdd434f0787a Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 20 Jun 2012 09:48:43 +0800 Subject: [PATCH 0353/2357] ACPI video: Still use ACPI backlight control if _DOS doesn't exist commit b03738430c7537d5f87948e0b35d8aaf2688c6b4 upstream. This fixes a regression in 3.4-rc1 caused by commit ea9f8856bd6d4ed45885b06a338f7362cd6c60e5 (ACPI video: Harden video bus adding.) Some platforms don't have _DOS control method, but the ACPI backlight still works. We should not invoke _DOS for these platforms. https://bugzilla.kernel.org/show_bug.cgi?id=43168 Cc: Igor Murzov Signed-off-by: Zhang Rui Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/video.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 66e8f7333e9..48b5a3cda37 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -558,6 +558,8 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; + if (!video->cap._DOS) + return 0; if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) return -EINVAL; From d54520f7cef2f18b7578d08c6a5a40eac026c3df Mon Sep 17 00:00:00 2001 From: Stuart Hayes Date: Wed, 13 Jun 2012 16:10:45 -0500 Subject: [PATCH 0354/2357] acpi_pad: fix power_saving thread deadlock commit 5f1601261050251a5ca293378b492a69d590dacb upstream. The acpi_pad driver can get stuck in destroy_power_saving_task() waiting for kthread_stop() to stop a power_saving thread. The problem is that the isolated_cpus_lock mutex is owned when destroy_power_saving_task() calls kthread_stop(), which waits for a power_saving thread to end, and the power_saving thread tries to acquire the isolated_cpus_lock when it calls round_robin_cpu(). This patch fixes the issue by making round_robin_cpu() use its own mutex. https://bugzilla.kernel.org/show_bug.cgi?id=42981 Signed-off-by: Stuart Hayes Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpi_pad.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index a43fa1a57d5..1502c50273b 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -36,6 +36,7 @@ #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator" #define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80 static DEFINE_MUTEX(isolated_cpus_lock); +static DEFINE_MUTEX(round_robin_lock); static unsigned long power_saving_mwait_eax; @@ -107,7 +108,7 @@ static void round_robin_cpu(unsigned int tsk_index) if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) return; - mutex_lock(&isolated_cpus_lock); + mutex_lock(&round_robin_lock); cpumask_clear(tmp); for_each_cpu(cpu, pad_busy_cpus) cpumask_or(tmp, tmp, topology_thread_cpumask(cpu)); @@ -116,7 +117,7 @@ static void round_robin_cpu(unsigned int tsk_index) if (cpumask_empty(tmp)) cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus); if (cpumask_empty(tmp)) { - mutex_unlock(&isolated_cpus_lock); + mutex_unlock(&round_robin_lock); return; } for_each_cpu(cpu, tmp) { @@ -131,7 +132,7 @@ static void round_robin_cpu(unsigned int tsk_index) tsk_in_cpu[tsk_index] = preferred_cpu; cpumask_set_cpu(preferred_cpu, pad_busy_cpus); cpu_weight[preferred_cpu]++; - mutex_unlock(&isolated_cpus_lock); + mutex_unlock(&round_robin_lock); set_cpus_allowed_ptr(current, cpumask_of(preferred_cpu)); } From 890b3d0ea620c942718dd29d601a7aaa4362280b Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Tue, 12 Jun 2012 11:20:19 +0800 Subject: [PATCH 0355/2357] ACPI, APEI, Avoid too much error reporting in runtime commit 34ddeb035d704eafdcdb3cbc781894300136c3c4 upstream. This patch fixed the following bug. https://bugzilla.kernel.org/show_bug.cgi?id=43282 This is caused by a firmware bug checking (checking generic address register provided by firmware) in runtime. The checking should be done in address mapping time instead of runtime to avoid too much error reporting in runtime. Reported-by: Pawel Sikora Signed-off-by: Huang Ying Tested-by: Jean Delvare Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/apei/apei-base.c | 17 +++++++++++++++-- drivers/acpi/apei/apei-internal.h | 9 +++++++++ drivers/acpi/apei/ghes.c | 6 +++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 5577762daee..6686b1eaf13 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) - return acpi_os_map_generic_address(&entry->register_region); + return apei_map_generic_address(&entry->register_region); return 0; } @@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) - acpi_os_unmap_generic_address(&entry->register_region); + apei_unmap_generic_address(&entry->register_region); return 0; } @@ -606,6 +606,19 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr, return 0; } +int apei_map_generic_address(struct acpi_generic_address *reg) +{ + int rc; + u32 access_bit_width; + u64 address; + + rc = apei_check_gar(reg, &address, &access_bit_width); + if (rc) + return rc; + return acpi_os_map_generic_address(reg); +} +EXPORT_SYMBOL_GPL(apei_map_generic_address); + /* read GAR in interrupt (including NMI) or process context */ int apei_read(u64 *val, struct acpi_generic_address *reg) { diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index cca240a3303..f220d642136 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -7,6 +7,8 @@ #define APEI_INTERNAL_H #include +#include +#include struct apei_exec_context; @@ -68,6 +70,13 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio /* IP has been set in instruction function */ #define APEI_EXEC_SET_IP 1 +int apei_map_generic_address(struct acpi_generic_address *reg); + +static inline void apei_unmap_generic_address(struct acpi_generic_address *reg) +{ + acpi_os_unmap_generic_address(reg); +} + int apei_read(u64 *val, struct acpi_generic_address *reg); int apei_write(u64 val, struct acpi_generic_address *reg); diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 9b3cac0abec..1599566ed1f 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -301,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) if (!ghes) return ERR_PTR(-ENOMEM); ghes->generic = generic; - rc = acpi_os_map_generic_address(&generic->error_status_address); + rc = apei_map_generic_address(&generic->error_status_address); if (rc) goto err_free; error_block_length = generic->error_block_length; @@ -321,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) return ghes; err_unmap: - acpi_os_unmap_generic_address(&generic->error_status_address); + apei_unmap_generic_address(&generic->error_status_address); err_free: kfree(ghes); return ERR_PTR(rc); @@ -330,7 +330,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) static void ghes_fini(struct ghes *ghes) { kfree(ghes->estatus); - acpi_os_unmap_generic_address(&ghes->generic->error_status_address); + apei_unmap_generic_address(&ghes->generic->error_status_address); } enum { From 371122fc6eef7cafc8acaf0891fd15cf623388a3 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Mon, 4 Jun 2012 15:00:04 +0800 Subject: [PATCH 0356/2357] ACPI: Make acpi_skip_timer_override cover all source_irq==0 cases commit ae10ccdc3093486f8c2369d227583f9d79f628e5 upstream. Currently when acpi_skip_timer_override is set, it only cover the (source_irq == 0 && global_irq == 2) cases. While there is also platform which need use this option and its global_irq is not 2. This patch will extend acpi_skip_timer_override to cover all timer overriding cases as long as the source irq is 0. This is the first part of a fix to kernel bug bugzilla 40002: "IRQ 0 assigned to VGA" https://bugzilla.kernel.org/show_bug.cgi?id=40002 Reported-and-tested-by: Szymon Kowalczyk Signed-off-by: Feng Tang Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/acpi/boot.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 7c439fe4941..9b3d328ade5 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -422,12 +422,14 @@ acpi_parse_int_src_ovr(struct acpi_subtable_header * header, return 0; } - if (intsrc->source_irq == 0 && intsrc->global_irq == 2) { + if (intsrc->source_irq == 0) { if (acpi_skip_timer_override) { - printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n"); + printk(PREFIX "BIOS IRQ0 override ignored.\n"); return 0; } - if (acpi_fix_pin2_polarity && (intsrc->inti_flags & ACPI_MADT_POLARITY_MASK)) { + + if ((intsrc->global_irq == 2) && acpi_fix_pin2_polarity + && (intsrc->inti_flags & ACPI_MADT_POLARITY_MASK)) { intsrc->inti_flags &= ~ACPI_MADT_POLARITY_MASK; printk(PREFIX "BIOS IRQ0 pin2 override: forcing polarity to high active.\n"); } @@ -1334,7 +1336,7 @@ static int __init dmi_disable_acpi(const struct dmi_system_id *d) } /* - * Force ignoring BIOS IRQ0 pin2 override + * Force ignoring BIOS IRQ0 override */ static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d) { @@ -1344,7 +1346,7 @@ static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d) */ if (!acpi_skip_timer_override) { WARN(1, KERN_ERR "ati_ixp4x0 quirk not complete.\n"); - pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n", + pr_notice("%s detected: Ignoring BIOS IRQ0 override\n", d->ident); acpi_skip_timer_override = 1; } @@ -1438,7 +1440,7 @@ static struct dmi_system_id __initdata acpi_dmi_table_late[] = { * is enabled. This input is incorrectly designated the * ISA IRQ 0 via an interrupt source override even though * it is wired to the output of the master 8259A and INTIN0 - * is not connected at all. Force ignoring BIOS IRQ0 pin2 + * is not connected at all. Force ignoring BIOS IRQ0 * override in that cases. */ { From 5752cdb805ff89942d99d12118e2844e7db34df8 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Mon, 4 Jun 2012 15:00:05 +0800 Subject: [PATCH 0357/2357] ACPI: Remove one board specific WARN when ignoring timer overriding commit 7f68b4c2e158019c2ec494b5cfbd9c83b4e5b253 upstream. Current WARN msg is only for the ati_ixp4x0 board, while this function is used by mulitple platforms. So this one board specific warning is not appropriate any more. Signed-off-by: Feng Tang Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/acpi/boot.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 9b3d328ade5..2b84bc38857 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1340,12 +1340,7 @@ static int __init dmi_disable_acpi(const struct dmi_system_id *d) */ static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d) { - /* - * The ati_ixp4x0_rev() early PCI quirk should have set - * the acpi_skip_timer_override flag already: - */ if (!acpi_skip_timer_override) { - WARN(1, KERN_ERR "ati_ixp4x0 quirk not complete.\n"); pr_notice("%s detected: Ignoring BIOS IRQ0 override\n", d->ident); acpi_skip_timer_override = 1; From b939c2acf1dc42b08407ef5174f2e8d6f43dd5ea Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Mon, 4 Jun 2012 15:00:06 +0800 Subject: [PATCH 0358/2357] ACPI: Add a quirk for "AMILO PRO V2030" to ignore the timer overriding commit f6b54f083cc66cf9b11d2120d8df3c2ad4e0836d upstream. This is the 2nd part of fix for kernel bugzilla 40002: "IRQ 0 assigned to VGA" https://bugzilla.kernel.org/show_bug.cgi?id=40002 The root cause is the buggy FW, whose ACPI tables assign the GSI 16 to 2 irqs 0 and 16(VGA), and the VGA is the right owner of GSI 16. So add a quirk to ignore the irq0 overriding GSI 16 for the FUJITSU SIEMENS AMILO PRO V2030 platform will solve this issue. Reported-and-tested-by: Szymon Kowalczyk Signed-off-by: Feng Tang Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/acpi/boot.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 2b84bc38857..bbdffc2da36 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1470,6 +1470,14 @@ static struct dmi_system_id __initdata acpi_dmi_table_late[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6715b"), }, }, + { + .callback = dmi_ignore_irq0_timer_override, + .ident = "FUJITSU SIEMENS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), + }, + }, {} }; From b429b0cf0a702501aaa7bdf59c235643c529a83c Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 20 Feb 2012 14:20:06 +0800 Subject: [PATCH 0359/2357] ACPI, x86: fix Dell M6600 ACPI reboot regression via DMI commit 76eb9a30db4bc8fd172f9155247264b5f2686d7b upstream. Dell Precision M6600 is known to require PCI reboot, so add it to the reboot blacklist in pci_reboot_dmi_table[]. https://bugzilla.kernel.org/show_bug.cgi?id=42749 cc: x86@kernel.org Signed-off-by: Zhang Rui Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/reboot.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index d840e69a853..3034ee5afb0 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -471,6 +471,14 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), }, }, + { /* Handle problems with rebooting on the Precision M6600. */ + .callback = set_pci_reboot, + .ident = "Dell OptiPlex 990", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"), + }, + }, { } }; From 0bd3d94b39087298b88f7ee2570d1062e09e8dfd Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Tue, 5 Jun 2012 00:02:05 -0400 Subject: [PATCH 0360/2357] ACPI sysfs.c strlen fix commit 9f132652d94c96476b0b0a8caf0c10e96ab10fa8 upstream. Current code is ignoring the last character of "enable" and "disable" in comparisons. https://bugzilla.kernel.org/show_bug.cgi?id=33732 Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 9f66181c814..240a2440097 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -173,7 +173,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp) { int result = 0; - if (!strncmp(val, "enable", strlen("enable") - 1)) { + if (!strncmp(val, "enable", strlen("enable"))) { result = acpi_debug_trace(trace_method_name, trace_debug_level, trace_debug_layer, 0); if (result) @@ -181,7 +181,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp) goto exit; } - if (!strncmp(val, "disable", strlen("disable") - 1)) { + if (!strncmp(val, "disable", strlen("disable"))) { int name = 0; result = acpi_debug_trace((char *)&name, trace_debug_level, trace_debug_layer, 0); From cb739ad1bba5a996533cf381b9079a1e876d15bb Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 22 Jun 2012 08:54:02 +0200 Subject: [PATCH 0361/2357] ARM: Orion: Fix Virtual/Physical mixup with watchdog commit 0fa1f0609a0c1fe8b2be3c0089a2cb48f7fda521 upstream. The orion watchdog is expecting to be passed the physcial address of the hardware, and will ioremap() it to give a virtual address it will use as the base address for the hardware. However, when creating the platform resource record, a virtual address was being used. Add the necassary #define's so we can pass the physical address as expected. Tested on Kirkwood and Orion5x. Signed-off-by: Andrew Lunn Signed-off-by: Olof Johansson Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-kirkwood/include/mach/bridge-regs.h | 1 + arch/arm/mach-kirkwood/include/mach/kirkwood.h | 1 + arch/arm/mach-orion5x/include/mach/bridge-regs.h | 2 +- arch/arm/mach-orion5x/include/mach/orion5x.h | 1 + arch/arm/plat-orion/common.c | 2 +- 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h index 957bd7997d7..086f25e761d 100644 --- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h +++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h @@ -38,6 +38,7 @@ #define IRQ_MASK_HIGH_OFF 0x0014 #define TIMER_VIRT_BASE (BRIDGE_VIRT_BASE | 0x0300) +#define TIMER_PHYS_BASE (BRIDGE_PHYS_BASE | 0x0300) #define L2_CONFIG_REG (BRIDGE_VIRT_BASE | 0x0128) #define L2_WRITETHROUGH 0x00000010 diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h index fede3d503ef..c5b68510776 100644 --- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h +++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h @@ -80,6 +80,7 @@ #define UART1_VIRT_BASE (DEV_BUS_VIRT_BASE | 0x2100) #define BRIDGE_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0x20000) +#define BRIDGE_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x20000) #define CRYPTO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x30000) diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/include/mach/bridge-regs.h index 96484bcd34c..11a3c1e9801 100644 --- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h +++ b/arch/arm/mach-orion5x/include/mach/bridge-regs.h @@ -35,5 +35,5 @@ #define MAIN_IRQ_MASK (ORION5X_BRIDGE_VIRT_BASE | 0x204) #define TIMER_VIRT_BASE (ORION5X_BRIDGE_VIRT_BASE | 0x300) - +#define TIMER_PHYS_BASE (ORION5X_BRIDGE_PHYS_BASE | 0x300) #endif diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h index 2745f5d95b3..683e085ce16 100644 --- a/arch/arm/mach-orion5x/include/mach/orion5x.h +++ b/arch/arm/mach-orion5x/include/mach/orion5x.h @@ -82,6 +82,7 @@ #define UART1_VIRT_BASE (ORION5X_DEV_BUS_VIRT_BASE | 0x2100) #define ORION5X_BRIDGE_VIRT_BASE (ORION5X_REGS_VIRT_BASE | 0x20000) +#define ORION5X_BRIDGE_PHYS_BASE (ORION5X_REGS_PHYS_BASE | 0x20000) #define ORION5X_PCI_VIRT_BASE (ORION5X_REGS_VIRT_BASE | 0x30000) diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index 74daf5ed143..331f8bbded9 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -570,7 +570,7 @@ void __init orion_spi_1_init(unsigned long mapbase, static struct orion_wdt_platform_data orion_wdt_data; static struct resource orion_wdt_resource = - DEFINE_RES_MEM(TIMER_VIRT_BASE, 0x28); + DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28); static struct platform_device orion_wdt_device = { .name = "orion_wdt", From 0341705f37081a337d6c073d326e4e9ad2ddcc83 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 29 Jun 2012 09:25:58 +0200 Subject: [PATCH 0362/2357] ARM: Orion: Fix WDT compile for Dove and MV78xx0 commit 1e0c1ce00d83834d03f4d8d039734ca4703298df upstream. Commit 0fa1f0609a0c1fe8b2be3c0089a2cb48f7fda521 (ARM: Orion: Fix Virtual/Physical mixup with watchdog) broke the Dove & MV78xx0 build. Although these two SoC don't use the watchdog, the shared platform code still needs to build. Add the necessary defines. Reported-by: Nicolas Pitre Signed-off-by: Andrew Lunn Tested-by: Nicolas Pitre Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-dove/include/mach/bridge-regs.h | 1 + arch/arm/mach-dove/include/mach/dove.h | 1 + arch/arm/mach-mv78xx0/include/mach/bridge-regs.h | 1 + arch/arm/mach-mv78xx0/include/mach/mv78xx0.h | 2 ++ 4 files changed, 5 insertions(+) diff --git a/arch/arm/mach-dove/include/mach/bridge-regs.h b/arch/arm/mach-dove/include/mach/bridge-regs.h index 226949dc4ac..f953bb54aa9 100644 --- a/arch/arm/mach-dove/include/mach/bridge-regs.h +++ b/arch/arm/mach-dove/include/mach/bridge-regs.h @@ -50,5 +50,6 @@ #define POWER_MANAGEMENT (BRIDGE_VIRT_BASE | 0x011c) #define TIMER_VIRT_BASE (BRIDGE_VIRT_BASE | 0x0300) +#define TIMER_PHYS_BASE (BRIDGE_PHYS_BASE | 0x0300) #endif diff --git a/arch/arm/mach-dove/include/mach/dove.h b/arch/arm/mach-dove/include/mach/dove.h index ad1165d488c..d52b0ef313b 100644 --- a/arch/arm/mach-dove/include/mach/dove.h +++ b/arch/arm/mach-dove/include/mach/dove.h @@ -78,6 +78,7 @@ /* North-South Bridge */ #define BRIDGE_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0x20000) +#define BRIDGE_PHYS_BASE (DOVE_SB_REGS_PHYS_BASE | 0x20000) /* Cryptographic Engine */ #define DOVE_CRYPT_PHYS_BASE (DOVE_SB_REGS_PHYS_BASE | 0x30000) diff --git a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h index c64dbb96dba..eb187e0e059 100644 --- a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h +++ b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h @@ -31,5 +31,6 @@ #define IRQ_MASK_HIGH_OFF 0x0014 #define TIMER_VIRT_BASE (BRIDGE_VIRT_BASE | 0x0300) +#define TIMER_PHYS_BASE (BRIDGE_PHYS_BASE | 0x0300) #endif diff --git a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h index 3674497162e..e807c4c52a0 100644 --- a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h +++ b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h @@ -42,6 +42,7 @@ #define MV78XX0_CORE0_REGS_PHYS_BASE 0xf1020000 #define MV78XX0_CORE1_REGS_PHYS_BASE 0xf1024000 #define MV78XX0_CORE_REGS_VIRT_BASE 0xfe400000 +#define MV78XX0_CORE_REGS_PHYS_BASE 0xfe400000 #define MV78XX0_CORE_REGS_SIZE SZ_16K #define MV78XX0_PCIE_IO_PHYS_BASE(i) (0xf0800000 + ((i) << 20)) @@ -59,6 +60,7 @@ * Core-specific peripheral registers. */ #define BRIDGE_VIRT_BASE (MV78XX0_CORE_REGS_VIRT_BASE) +#define BRIDGE_PHYS_BASE (MV78XX0_CORE_REGS_PHYS_BASE) /* * Register Map From 8c890e34f58fc8d3c0eafecf0bdc92c4161b1679 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 25 May 2012 16:11:09 -0400 Subject: [PATCH 0363/2357] xen/blkback: Copy id field when doing BLKIF_DISCARD. commit 8c9ce606a60e4a0cb447bdc082ce383b96b227b4 upstream. We weren't copying the id field so when we sent the response back to the frontend (especially with a 64-bit host and 32-bit guest), we ended up using a random value. This lead to the frontend crashing as it would try to pass to __blk_end_request_all a NULL 'struct request' (b/c it would use the 'id' to find the proper 'struct request' in its shadow array) and end up crashing: BUG: unable to handle kernel NULL pointer dereference at 000000e4 IP: [] __blk_end_request_all+0xc/0x40 .. snip.. EIP is at __blk_end_request_all+0xc/0x40 .. snip.. [] blkif_interrupt+0x172/0x330 [xen_blkfront] This fixes the bug by passing in the proper id for the response. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=824641 Tested-by: William Dauchy Acked-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/block/xen-blkback/common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 773cf27dc23..9ad3b5ec1dc 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -257,6 +257,7 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst, break; case BLKIF_OP_DISCARD: dst->u.discard.flag = src->u.discard.flag; + dst->u.discard.id = src->u.discard.id; dst->u.discard.sector_number = src->u.discard.sector_number; dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; @@ -287,6 +288,7 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst, break; case BLKIF_OP_DISCARD: dst->u.discard.flag = src->u.discard.flag; + dst->u.discard.id = src->u.discard.id; dst->u.discard.sector_number = src->u.discard.sector_number; dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; From 31b1da2a2ae8a053c33e1fd5b87ec3ea39e81b99 Mon Sep 17 00:00:00 2001 From: Tao Guo Date: Wed, 13 Jun 2012 21:17:21 +0200 Subject: [PATCH 0364/2357] umem: fix up unplugging commit 32587371ad3db2f9d335de10dbd8cffd4fff5669 upstream. Fix a regression introduced by 7eaceaccab5f40 ("block: remove per-queue plugging"). In that patch, Jens removed the whole mm_unplug_device() function, which used to be the trigger to make umem start to work. We need to implement unplugging to make umem start to work, or I/O will never be triggered. Signed-off-by: Tao Guo Cc: Neil Brown Cc: Jens Axboe Cc: Shaohua Li Acked-by: NeilBrown Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/umem.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index aa2712060bf..9a72277a31d 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -513,6 +513,44 @@ static void process_page(unsigned long data) } } +struct mm_plug_cb { + struct blk_plug_cb cb; + struct cardinfo *card; +}; + +static void mm_unplug(struct blk_plug_cb *cb) +{ + struct mm_plug_cb *mmcb = container_of(cb, struct mm_plug_cb, cb); + + spin_lock_irq(&mmcb->card->lock); + activate(mmcb->card); + spin_unlock_irq(&mmcb->card->lock); + kfree(mmcb); +} + +static int mm_check_plugged(struct cardinfo *card) +{ + struct blk_plug *plug = current->plug; + struct mm_plug_cb *mmcb; + + if (!plug) + return 0; + + list_for_each_entry(mmcb, &plug->cb_list, cb.list) { + if (mmcb->cb.callback == mm_unplug && mmcb->card == card) + return 1; + } + /* Not currently on the callback list */ + mmcb = kmalloc(sizeof(*mmcb), GFP_ATOMIC); + if (!mmcb) + return 0; + + mmcb->card = card; + mmcb->cb.callback = mm_unplug; + list_add(&mmcb->cb.list, &plug->cb_list); + return 1; +} + static void mm_make_request(struct request_queue *q, struct bio *bio) { struct cardinfo *card = q->queuedata; @@ -523,6 +561,8 @@ static void mm_make_request(struct request_queue *q, struct bio *bio) *card->biotail = bio; bio->bi_next = NULL; card->biotail = &bio->bi_next; + if (bio->bi_rw & REQ_SYNC || !mm_check_plugged(card)) + activate(card); spin_unlock_irq(&card->lock); return; From a7c60136e5bf96bc58a27ab9822a2e48ed768429 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 21 Jun 2012 11:36:50 +0100 Subject: [PATCH 0365/2357] stable: Allow merging of backports for serious user-visible performance issues commit eb3979f64d25120d60b9e761a4c58f70b1a02f86 upstream. Distribution kernel maintainers routinely backport fixes for users that were deemed important but not "something critical" as defined by the rules. To users of these kernels they are very serious and failing to fix them reduces the value of -stable. The problem is that the patches fixing these issues are often subtle and prone to regressions in other ways and need greater care and attention. To combat this, these "serious" backports should have a higher barrier to entry. This patch relaxes the rules to allow a distribution maintainer to merge to -stable a backported patch or small series that fixes a "serious" user-visible performance issue. They should include additional information on the user-visible bug affected and a link to the bugzilla entry if available. The same rules about the patch being already in mainline still apply. Signed-off-by: Mel Gorman Signed-off-by: Greg Kroah-Hartman --- Documentation/stable_kernel_rules.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt index f0ab5cf28fc..4a7b54bd37e 100644 --- a/Documentation/stable_kernel_rules.txt +++ b/Documentation/stable_kernel_rules.txt @@ -12,6 +12,12 @@ Rules on what kind of patches are accepted, and which ones are not, into the marked CONFIG_BROKEN), an oops, a hang, data corruption, a real security issue, or some "oh, that's not good" issue. In short, something critical. + - Serious issues as reported by a user of a distribution kernel may also + be considered if they fix a notable performance or interactivity issue. + As these fixes are not as obvious and have a higher risk of a subtle + regression they should only be submitted by a distribution kernel + maintainer and include an addendum linking to a bugzilla entry if it + exists and additional information on the user-visible impact. - New device IDs and quirks are also accepted. - No "theoretical race condition" issues, unless an explanation of how the race can be exploited is also provided. From 21017faf87a93117ca7a14aa8f0dd2f315fdeb08 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Wed, 20 Jun 2012 12:53:01 -0700 Subject: [PATCH 0366/2357] mm: correctly synchronize rss-counters at exit/exec commit 4fe7efdbdfb1c7e7a7f31decfd831c0f31d37091 upstream. do_exit() and exec_mmap() call sync_mm_rss() before mm_release() does put_user(clear_child_tid) which can update task->rss_stat and thus make mm->rss_stat inconsistent. This triggers the "BUG:" printk in check_mm(). Let's fix this bug in the safest way, and optimize/cleanup this later. Reported-by: Markus Trippelsdorf Signed-off-by: Konstantin Khlebnikov Cc: Oleg Nesterov Cc: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/exec.c | 2 +- kernel/exit.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/exec.c b/fs/exec.c index b1fd2025e59..29e5f840544 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -823,10 +823,10 @@ static int exec_mmap(struct mm_struct *mm) /* Notify parent that we're no longer interested in the old VM */ tsk = current; old_mm = current->mm; - sync_mm_rss(old_mm); mm_release(tsk, old_mm); if (old_mm) { + sync_mm_rss(old_mm); /* * Make sure that if there is a core dump in progress * for the old mm, we get out and die instead of going diff --git a/kernel/exit.c b/kernel/exit.c index d8bd3b425fa..9d81012290e 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -643,6 +643,7 @@ static void exit_mm(struct task_struct * tsk) mm_release(tsk, mm); if (!mm) return; + sync_mm_rss(mm); /* * Serialize with any possible pending coredump. * We must hold mmap_sem around checking core_state From 3d90eeae377192032aa58c1934582cc155a2498f Mon Sep 17 00:00:00 2001 From: Mandeep Singh Baines Date: Sun, 24 Jun 2012 23:31:09 +0200 Subject: [PATCH 0367/2357] PM / Sleep: Prevent waiting forever on asynchronous suspend after abort commit 1f758b23177d588a71b96ad02990e715949bb82f upstream. __device_suspend() must always send a completion. Otherwise, parent devices will wait forever. Commit 1e2ef05b, "PM: Limit race conditions between runtime PM and system sleep (v2)", introduced a regression by short-circuiting the complete_all() for certain error cases. This patch fixes the bug by always signalling a completion. Addresses http://crosbug.com/31972 Tested by injecting an abort. Signed-off-by: Mandeep Singh Baines Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index b462c0e341c..3085f9bcdd8 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1021,7 +1021,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) dpm_wait_for_children(dev, async); if (async_error) - return 0; + goto Complete; pm_runtime_get_noresume(dev); if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) @@ -1030,7 +1030,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) if (pm_wakeup_pending()) { pm_runtime_put_sync(dev); async_error = -EBUSY; - return 0; + goto Complete; } device_lock(dev); @@ -1087,6 +1087,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) } device_unlock(dev); + + Complete: complete_all(&dev->power.completion); if (error) { From 2f0d20928b7360267ec80bb393971752f2351463 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Wed, 23 May 2012 16:47:31 +0530 Subject: [PATCH 0368/2357] dmaengine: pl330: dont complete descriptor for cyclic dma commit 30c1dc0ff30b5552e8af555265dbeac5637cbb48 upstream. Commit eab215855803 ("dmaengine: pl330: dont complete descriptor for cyclic dma") wrongly completes descriptor for cyclic dma, hence following BUG_ON is still hit with cyclic DMA operations. kernel BUG at drivers/dma/dmaengine.h:53! Signed-off-by: Tushar Behera Acked-by: Jassi Brar Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/pl330.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index fa3fb21e60b..8c44f17a99e 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2322,7 +2322,7 @@ static void pl330_tasklet(unsigned long data) /* Pick up ripe tomatoes */ list_for_each_entry_safe(desc, _dt, &pch->work_list, node) if (desc->status == DONE) { - if (pch->cyclic) + if (!pch->cyclic) dma_cookie_complete(&desc->txd); list_move_tail(&desc->node, &list); } From d5b8efa118c7bf1b88e0f6f0185fbdd3c0ee67ed Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Wed, 20 Jun 2012 14:35:28 -0400 Subject: [PATCH 0369/2357] NFS: Force the legacy idmapper to be single threaded commit b1027439dff844675f6c0df97a1b1d190791a699 upstream. It was initially coded under the assumption that there would only be one request at a time, so use a lock to enforce this requirement.. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/idmap.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 3e8edbe71ec..93aa3a4c4b0 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -57,6 +57,11 @@ unsigned int nfs_idmap_cache_timeout = 600; static const struct cred *id_resolver_cache; static struct key_type key_type_id_resolver_legacy; +struct idmap { + struct rpc_pipe *idmap_pipe; + struct key_construction *idmap_key_cons; + struct mutex idmap_mutex; +}; /** * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields @@ -310,9 +315,11 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, name, namelen, type, data, data_size, NULL); if (ret < 0) { + mutex_lock(&idmap->idmap_mutex); ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, name, namelen, type, data, data_size, idmap); + mutex_unlock(&idmap->idmap_mutex); } return ret; } @@ -354,11 +361,6 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *typ /* idmap classic begins here */ module_param(nfs_idmap_cache_timeout, int, 0644); -struct idmap { - struct rpc_pipe *idmap_pipe; - struct key_construction *idmap_key_cons; -}; - enum { Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err }; @@ -469,6 +471,7 @@ nfs_idmap_new(struct nfs_client *clp) return error; } idmap->idmap_pipe = pipe; + mutex_init(&idmap->idmap_mutex); clp->cl_idmap = idmap; return 0; From c10f88285e2daf11ef8ec9726a25804abb9a84be Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Wed, 6 Jun 2012 14:41:31 +0530 Subject: [PATCH 0370/2357] clk: Allow late cache allocation for clk->parents commit 7975059db572eb47f0fb272a62afeae272a4b209 upstream. Parent clocks for muxes are cached in clk->parents to avoid frequent lookups, however the cache allocation happens only during clock registeration and later clk_set_parent() assumes a cache space available and allocated. This is not entirely true for platforms which do early clock registerations wherein the cache allocation using kzalloc could fail during clock registeration. Allow cache allocation to happen later as part of clk_set_parent() to help such cases and avoid crashes assuming a cache being available. While here also replace existing kmalloc() with kzalloc() in the file. Signed-off-by: Rajendra Nayak Signed-off-by: Mike Turquette Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9cf6f59e3e1..3ff9377a49e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -997,7 +997,7 @@ static struct clk *__clk_init_parent(struct clk *clk) if (!clk->parents) clk->parents = - kmalloc((sizeof(struct clk*) * clk->num_parents), + kzalloc((sizeof(struct clk*) * clk->num_parents), GFP_KERNEL); if (!clk->parents) @@ -1063,9 +1063,13 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent) old_parent = clk->parent; /* find index of new parent clock using cached parent ptrs */ - for (i = 0; i < clk->num_parents; i++) - if (clk->parents[i] == parent) - break; + if (clk->parents) + for (i = 0; i < clk->num_parents; i++) + if (clk->parents[i] == parent) + break; + else + clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents), + GFP_KERNEL); /* * find index of new parent clock using string name comparison @@ -1074,7 +1078,8 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent) if (i == clk->num_parents) for (i = 0; i < clk->num_parents; i++) if (!strcmp(clk->parent_names[i], parent->name)) { - clk->parents[i] = __clk_lookup(parent->name); + if (clk->parents) + clk->parents[i] = __clk_lookup(parent->name); break; } From 8bd6035bfc6a0c401e1ed01d2658e502a6f6683b Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 3 Jul 2012 12:11:41 +0530 Subject: [PATCH 0371/2357] clk: fix parent validation in __clk_set_parent() commit 863b13271f1608ab3af6f7a371047d9a66693e38 upstream. The below commit introduced a bug in __clk_set_parent() which could cause it to *skip* the parent validation which makes sure the parent passed to the api is a valid one. commit 7975059db572eb47f0fb272a62afeae272a4b209 Author: Rajendra Nayak Date: Wed Jun 6 14:41:31 2012 +0530 clk: Allow late cache allocation for clk->parents This was identified by the following compiler warning.. drivers/clk/clk.c: In function '__clk_set_parent': drivers/clk/clk.c:1083:5: warning: 'i' may be used uninitialized in this function [-Wuninitialized] .. as reported by Marc Kleine-Budde. There were various options discussed on how to fix this, one being initing 'i' to clk->num_parents, but the below approach was found to be more appropriate as it also makes the 'parent validation' code simpler to read. Reported-by: Marc Kleine-Budde Signed-off-by: Rajendra Nayak Signed-off-by: Mike Turquette Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 3ff9377a49e..2da025ee226 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1062,26 +1062,24 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent) old_parent = clk->parent; - /* find index of new parent clock using cached parent ptrs */ - if (clk->parents) - for (i = 0; i < clk->num_parents; i++) - if (clk->parents[i] == parent) - break; - else + if (!clk->parents) clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents), GFP_KERNEL); /* - * find index of new parent clock using string name comparison - * also try to cache the parent to avoid future calls to __clk_lookup + * find index of new parent clock using cached parent ptrs, + * or if not yet cached, use string name comparison and cache + * them now to avoid future calls to __clk_lookup. */ - if (i == clk->num_parents) - for (i = 0; i < clk->num_parents; i++) - if (!strcmp(clk->parent_names[i], parent->name)) { - if (clk->parents) - clk->parents[i] = __clk_lookup(parent->name); - break; - } + for (i = 0; i < clk->num_parents; i++) { + if (clk->parents && clk->parents[i] == parent) + break; + else if (!strcmp(clk->parent_names[i], parent->name)) { + if (clk->parents) + clk->parents[i] = __clk_lookup(parent->name); + break; + } + } if (i == clk->num_parents) { pr_debug("%s: clock %s is not a possible parent of clock %s\n", From 96e1ecef17e300d49ecc5b7378a82e7389227191 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 9 Jun 2012 11:07:56 +0800 Subject: [PATCH 0372/2357] gpiolib: wm8994: Pay attention to the value set when enabling as output commit 8cd578b6e28693f357867a77598a88ef3deb6b39 upstream. Not paying attention to the value being set is a bad thing because it means that we'll not set the hardware up to reflect what was requested. Not setting the hardware up to reflect what was requested means that the caller won't get the results they wanted. Signed-off-by: Mark Brown Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-wm8994.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index 92ea5350dfe..aa61ad2fcaa 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -89,8 +89,11 @@ static int wm8994_gpio_direction_out(struct gpio_chip *chip, struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); struct wm8994 *wm8994 = wm8994_gpio->wm8994; + if (value) + value = WM8994_GPN_LVL; + return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, - WM8994_GPN_DIR, 0); + WM8994_GPN_DIR | WM8994_GPN_LVL, value); } static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value) From 96445edb34f5ade124081edda2c915714aec4b9a Mon Sep 17 00:00:00 2001 From: Dmitry Shmygov Date: Wed, 20 Jun 2012 15:51:40 +0400 Subject: [PATCH 0373/2357] USB: option: add id for Cellient MEN-200 commit 1e2c4e59d2b8797973471b4a287a43eac12a0f40 upstream. Add vendor and product ID to option.c driver for Cellient MEN-200 EVDO Rev.B 450MHz data module. http://cellient.com Signed-off-by: Dmitry Shmygov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 2706d8acb94..6b4fc40718c 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -497,6 +497,10 @@ static void option_instat_callback(struct urb *urb); /* MediaTek products */ #define MEDIATEK_VENDOR_ID 0x0e8d +/* Cellient products */ +#define CELLIENT_VENDOR_ID 0x2692 +#define CELLIENT_PRODUCT_MEN200 0x9005 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -1233,6 +1237,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */ + { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); From 2ce4171eeb3bbe0192a5888dbb9bc499e70a9c9b Mon Sep 17 00:00:00 2001 From: Forest Bond Date: Fri, 22 Jun 2012 10:30:38 -0400 Subject: [PATCH 0374/2357] USB: option: Add USB ID for Novatel Ovation MC551 commit 065b07e7a14676f4138ce4619d229c0be5a74230 upstream. This device is also known as the Verizon USB551L. Signed-off-by: Forest Bond Acked-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 6b4fc40718c..956319d4e19 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -236,6 +236,7 @@ static void option_instat_callback(struct urb *urb); #define NOVATELWIRELESS_PRODUCT_G1 0xA001 #define NOVATELWIRELESS_PRODUCT_G1_M 0xA002 #define NOVATELWIRELESS_PRODUCT_G2 0xA010 +#define NOVATELWIRELESS_PRODUCT_MC551 0xB001 /* AMOI PRODUCTS */ #define AMOI_VENDOR_ID 0x1614 @@ -738,6 +739,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) }, + /* Novatel Ovation MC551 a.k.a. Verizon USB551L */ + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, From 35733efe3599b30ace9b035eb425be85aaa3ae12 Mon Sep 17 00:00:00 2001 From: Craig Shelley Date: Tue, 26 Jun 2012 23:20:04 +0100 Subject: [PATCH 0375/2357] USB: CP210x Add 10 Device IDs commit 3fcc8f96829776cf181918461923d1e3bbb831a2 upstream. This patch adds 10 device IDs for CP210x based devices from the following manufacturers: Timewave Clipsal Festo Link Instruments Signed-off-by: Craig Shelley Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 95de9c08da1..53e7e692d61 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -93,6 +93,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ + { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */ { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ @@ -134,7 +135,13 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ + { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ + { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ + { USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */ + { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */ + { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */ + { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ @@ -146,7 +153,11 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ + { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */ + { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */ { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ + { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ }; From b18504e4a631e31edd939fe569342274927d4b41 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 20 Jun 2012 16:04:19 -0400 Subject: [PATCH 0376/2357] SCSI & usb-storage: add try_rc_10_first flag commit 6a0bdffa0073857870a4ed1b4489762146359eb4 upstream. Several bug reports have been received recently for USB mass-storage devices that don't handle READ CAPACITY(16) commands properly. They report bogus sizes, in some cases becoming unusable as a result. The bugs were triggered by commit 09b6b51b0b6c1b9bb61815baf205e4d74c89ff04 (SCSI & usb-storage: add flags for VPD pages and REPORT LUNS), which caused usb-storage to stop overriding the SCSI level reported by devices. By default, the sd driver will try READ CAPACITY(16) first for any device whose level is above SCSI_SPC_2. It seems likely that any device large enough to require the use of READ CAPACITY(16) (i.e., 2 TB or more) would be able to handle READ CAPACITY(10) commands properly. Indeed, I don't know of any devices that don't handle READ CAPACITY(10) properly. Therefore this patch (as1559) adds a new flag telling the sd driver to try READ CAPACITY(10) before READ CAPACITY(16), and sets this flag for every USB mass-storage device. If a device really is larger than 2 TB, sd will fall back to READ CAPACITY(16) just as it used to. This fixes Bugzilla #43391. Signed-off-by: Alan Stern Acked-by: Hans de Goede CC: "James E.J. Bottomley" CC: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sd.c | 2 ++ drivers/usb/storage/scsiglue.c | 6 ++++++ include/scsi/scsi_device.h | 1 + 3 files changed, 9 insertions(+) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 5ba5c2a9e8e..a239382b2bd 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1898,6 +1898,8 @@ static int sd_try_rc16_first(struct scsi_device *sdp) { if (sdp->host->max_cmd_len < 16) return 0; + if (sdp->try_rc_10_first) + return 0; if (sdp->scsi_level > SCSI_SPC_2) return 1; if (scsi_device_protection(sdp)) diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index a324a5d21e9..11418da9bc0 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -202,6 +202,12 @@ static int slave_configure(struct scsi_device *sdev) if (us->fflags & US_FL_NO_READ_CAPACITY_16) sdev->no_read_capacity_16 = 1; + /* + * Many devices do not respond properly to READ_CAPACITY_16. + * Tell the SCSI layer to try READ_CAPACITY_10 first. + */ + sdev->try_rc_10_first = 1; + /* assume SPC3 or latter devices support sense size > 18 */ if (sdev->scsi_level > SCSI_SPC_2) us->fflags |= US_FL_SANE_SENSE; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 6efb2e1416e..ba969885232 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -151,6 +151,7 @@ struct scsi_device { SD_LAST_BUGGY_SECTORS */ unsigned no_read_disc_info:1; /* Avoid READ_DISC_INFO cmds */ unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */ + unsigned try_rc_10_first:1; /* Try READ_CAPACACITY_10 first */ unsigned is_visible:1; /* is the device visible in sysfs */ DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ From 5a851e1314972efe28723b15b57ff645cb818003 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 20 Jun 2012 16:04:30 -0400 Subject: [PATCH 0377/2357] usb-storage: revert commit afff07e61a52 (Add 090c:1000 to unusal-devs) commit 0070513b5e005161a7a7fd9a3f48f982b41eb094 upstream. This patch (as1560) reverts commit afff07e61a5243e14ee3f0a272a0380cd744a8a3 (usb-storage: Add 090c:1000 to unusal-devs). It is no longer needed, because usb-storage now tells the sd driver to try READ CAPACITY(10) before READ CAPACITY(16) for every USB mass-storage device. Signed-off-by: Alan Stern Acked-by: Hans de Goede CC: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index f4d3e1a8e7d..8f3cbb8dc81 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1107,13 +1107,6 @@ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, USB_SC_RBC, USB_PR_BULK, NULL, 0 ), -/* Feiya QDI U2 DISK, reported by Hans de Goede */ -UNUSUAL_DEV( 0x090c, 0x1000, 0x0000, 0xffff, - "Feiya", - "QDI U2 DISK", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_READ_CAPACITY_16 ), - /* aeb */ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff, "Feiya", From 0d84f6e5ba73f0b2ef3af8e5c1f96b8ab8ecff6f Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 12 Jun 2012 12:53:13 +0300 Subject: [PATCH 0378/2357] cfg80211: fix potential deadlock in regulatory commit fe20b39ec32e975f1054c0b7866c873a954adf05 upstream. reg_timeout_work() calls restore_regulatory_settings() which takes cfg80211_mutex. reg_set_request_processed() already holds cfg80211_mutex before calling cancel_delayed_work_sync(reg_timeout), so it might deadlock. Call the async cancel_delayed_work instead, in order to avoid the potential deadlock. This is the relevant lockdep warning: cfg80211: Calling CRDA for country: XX ====================================================== [ INFO: possible circular locking dependency detected ] 3.4.0-rc5-wl+ #26 Not tainted ------------------------------------------------------- kworker/0:2/1391 is trying to acquire lock: (cfg80211_mutex){+.+.+.}, at: [] restore_regulatory_settings+0x34/0x418 [cfg80211] but task is already holding lock: ((reg_timeout).work){+.+...}, at: [] process_one_work+0x1f0/0x480 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 ((reg_timeout).work){+.+...}: [] validate_chain+0xb94/0x10f0 [] __lock_acquire+0x8c8/0x9b0 [] lock_acquire+0xf0/0x114 [] wait_on_work+0x4c/0x154 [] __cancel_work_timer+0xd4/0x11c [] cancel_delayed_work_sync+0x1c/0x20 [] reg_set_request_processed+0x50/0x78 [cfg80211] [] set_regdom+0x550/0x600 [cfg80211] [] nl80211_set_reg+0x218/0x258 [cfg80211] [] genl_rcv_msg+0x1a8/0x1e8 [] netlink_rcv_skb+0x5c/0xc0 [] genl_rcv+0x28/0x34 [] netlink_unicast+0x15c/0x228 [] netlink_sendmsg+0x218/0x298 [] sock_sendmsg+0xa4/0xc0 [] __sys_sendmsg+0x1e4/0x268 [] sys_sendmsg+0x4c/0x70 [] ret_fast_syscall+0x0/0x3c -> #1 (reg_mutex){+.+.+.}: [] validate_chain+0xb94/0x10f0 [] __lock_acquire+0x8c8/0x9b0 [] lock_acquire+0xf0/0x114 [] mutex_lock_nested+0x48/0x320 [] reg_todo+0x30/0x538 [cfg80211] [] process_one_work+0x2a0/0x480 [] worker_thread+0x1bc/0x2bc [] kthread+0x98/0xa4 [] kernel_thread_exit+0x0/0x8 -> #0 (cfg80211_mutex){+.+.+.}: [] print_circular_bug+0x68/0x2cc [] validate_chain+0x978/0x10f0 [] __lock_acquire+0x8c8/0x9b0 [] lock_acquire+0xf0/0x114 [] mutex_lock_nested+0x48/0x320 [] restore_regulatory_settings+0x34/0x418 [cfg80211] [] reg_timeout_work+0x1c/0x20 [cfg80211] [] process_one_work+0x2a0/0x480 [] worker_thread+0x1bc/0x2bc [] kthread+0x98/0xa4 [] kernel_thread_exit+0x0/0x8 other info that might help us debug this: Chain exists of: cfg80211_mutex --> reg_mutex --> (reg_timeout).work Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock((reg_timeout).work); lock(reg_mutex); lock((reg_timeout).work); lock(cfg80211_mutex); *** DEADLOCK *** 2 locks held by kworker/0:2/1391: #0: (events){.+.+.+}, at: [] process_one_work+0x1f0/0x480 #1: ((reg_timeout).work){+.+...}, at: [] process_one_work+0x1f0/0x480 stack backtrace: [] (unwind_backtrace+0x0/0x12c) from [] (dump_stack+0x20/0x24) [] (dump_stack+0x20/0x24) from [] (print_circular_bug+0x280/0x2cc) [] (print_circular_bug+0x280/0x2cc) from [] (validate_chain+0x978/0x10f0) [] (validate_chain+0x978/0x10f0) from [] (__lock_acquire+0x8c8/0x9b0) [] (__lock_acquire+0x8c8/0x9b0) from [] (lock_acquire+0xf0/0x114) [] (lock_acquire+0xf0/0x114) from [] (mutex_lock_nested+0x48/0x320) [] (mutex_lock_nested+0x48/0x320) from [] (restore_regulatory_settings+0x34/0x418 [cfg80211]) [] (restore_regulatory_settings+0x34/0x418 [cfg80211]) from [] (reg_timeout_work+0x1c/0x20 [cfg80211]) [] (reg_timeout_work+0x1c/0x20 [cfg80211]) from [] (process_one_work+0x2a0/0x480) [] (process_one_work+0x2a0/0x480) from [] (worker_thread+0x1bc/0x2bc) [] (worker_thread+0x1bc/0x2bc) from [] (kthread+0x98/0xa4) [] (kthread+0x98/0xa4) from [] (kernel_thread_exit+0x0/0x8) cfg80211: Calling CRDA to update world regulatory domain cfg80211: World regulatory domain updated: cfg80211: (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp) cfg80211: (2402000 KHz - 2472000 KHz @ 40000 KHz), (300 mBi, 2000 mBm) cfg80211: (2457000 KHz - 2482000 KHz @ 20000 KHz), (300 mBi, 2000 mBm) cfg80211: (2474000 KHz - 2494000 KHz @ 20000 KHz), (300 mBi, 2000 mBm) cfg80211: (5170000 KHz - 5250000 KHz @ 40000 KHz), (300 mBi, 2000 mBm) cfg80211: (5735000 KHz - 5835000 KHz @ 40000 KHz), (300 mBi, 2000 mBm) Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 15f347477a9..baf5704740e 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1389,7 +1389,7 @@ static void reg_set_request_processed(void) spin_unlock(®_requests_lock); if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) - cancel_delayed_work_sync(®_timeout); + cancel_delayed_work(®_timeout); if (need_more_processing) schedule_work(®_work); From a7faba5c5263f9d8a31b3f542a0504552fa80932 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 19 Jun 2012 09:26:39 +0000 Subject: [PATCH 0379/2357] batman-adv: fix skb->data assignment commit 2c995ff892313009e336ecc8ec3411022f5b1c39 upstream. skb_linearize(skb) possibly rearranges the skb internal data and then changes the skb->data pointer value. For this reason any other pointer in the code that was assigned skb->data before invoking skb_linearise(skb) must be re-assigned. In the current tt_query message handling code this is not done and therefore, in case of skb linearization, the pointer used to handle the packet header ends up in pointing to free'd memory. This bug was introduced by a73105b8d4c765d9ebfb664d0a66802127d8e4c7 (batman-adv: improved client announcement mechanism) Signed-off-by: Antonio Quartulli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/batman-adv/routing.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 7f8e1589941..8df3a1ff516 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -618,6 +618,8 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if) * changes */ if (skb_linearize(skb) < 0) goto out; + /* skb_linearize() possibly changed skb->data */ + tt_query = (struct tt_query_packet *)skb->data; tt_len = tt_query->tt_data * sizeof(struct tt_change); From 0c290a35a401ba4f608cb9cc669645a3b07498e2 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Wed, 20 Jun 2012 17:16:05 +0200 Subject: [PATCH 0380/2357] batman-adv: only drop packets of known wifi clients commit 5870adc68fc39d81089f1e80efdf64b97e5c37a1 upstream. bug introduced with 59b699cdee039d75915c354da06937102d1f9a84 If the source or destination mac address of an ethernet packet could not be found in the translation table the packet was dropped if AP isolation was turned on. This behavior would make it impossible to send broadcast packets over the mesh as the broadcast address will never enter the translation table. Signed-off-by: Marek Lindner Acked-by: Antonio Quartulli Signed-off-by: Greg Kroah-Hartman --- net/batman-adv/translation-table.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 1f869212784..f014bf83aed 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1803,10 +1803,10 @@ bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst) { struct tt_local_entry *tt_local_entry = NULL; struct tt_global_entry *tt_global_entry = NULL; - bool ret = true; + bool ret = false; if (!atomic_read(&bat_priv->ap_isolation)) - return false; + goto out; tt_local_entry = tt_local_hash_find(bat_priv, dst); if (!tt_local_entry) @@ -1816,10 +1816,10 @@ bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst) if (!tt_global_entry) goto out; - if (_is_ap_isolated(tt_local_entry, tt_global_entry)) + if (!_is_ap_isolated(tt_local_entry, tt_global_entry)) goto out; - ret = false; + ret = true; out: if (tt_global_entry) From 7cc0ab128f8866767113eece040dc838175901b2 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 25 Jun 2012 21:54:46 +0000 Subject: [PATCH 0381/2357] ixgbe: Do not pad FCoE frames as this can cause issues with FCoE DDP commit 57efd44c8cad440fb00ef8078cb018ab2f221373 upstream. FCoE target mode was experiencing issues due to the fact that we were sending up data frames that were padded to 60 bytes after the DDP logic had already stripped the frame down to 52 or 56 depending on the use of VLANs. This was resulting in the FCoE DDP logic having issues since it thought the frame still had data in it due to the padding. To resolve this, adding code so that we do not pad FCoE frames prior to handling them to the stack. Signed-off-by: Alexander Duyck Tested-by: Phil Schmitt Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 4 ++-- drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 14 ++++++++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 81b15558953..f8f85eca4ae 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -189,7 +189,7 @@ enum ixgbe_ring_state_t { __IXGBE_HANG_CHECK_ARMED, __IXGBE_RX_RSC_ENABLED, __IXGBE_RX_CSUM_UDP_ZERO_ERR, - __IXGBE_RX_FCOE_BUFSZ, + __IXGBE_RX_FCOE, }; #define check_for_tx_hang(ring) \ @@ -283,7 +283,7 @@ struct ixgbe_ring_feature { #if defined(IXGBE_FCOE) && (PAGE_SIZE < 8192) static inline unsigned int ixgbe_rx_pg_order(struct ixgbe_ring *ring) { - return test_bit(__IXGBE_RX_FCOE_BUFSZ, &ring->state) ? 1 : 0; + return test_bit(__IXGBE_RX_FCOE, &ring->state) ? 1 : 0; } #else #define ixgbe_rx_pg_order(_ring) 0 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index ed1b47dc083..a269d11259c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -628,7 +628,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, int v_idx, f = &adapter->ring_feature[RING_F_FCOE]; if ((rxr_idx >= f->mask) && (rxr_idx < f->mask + f->indices)) - set_bit(__IXGBE_RX_FCOE_BUFSZ, &ring->state); + set_bit(__IXGBE_RX_FCOE, &ring->state); } #endif /* IXGBE_FCOE */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 467948e9ecd..a66c2159b1f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1036,17 +1036,17 @@ static inline void ixgbe_rx_hash(struct ixgbe_ring *ring, #ifdef IXGBE_FCOE /** * ixgbe_rx_is_fcoe - check the rx desc for incoming pkt type - * @adapter: address of board private structure + * @ring: structure containing ring specific data * @rx_desc: advanced rx descriptor * * Returns : true if it is FCoE pkt */ -static inline bool ixgbe_rx_is_fcoe(struct ixgbe_adapter *adapter, +static inline bool ixgbe_rx_is_fcoe(struct ixgbe_ring *ring, union ixgbe_adv_rx_desc *rx_desc) { __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; - return (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && + return test_bit(__IXGBE_RX_FCOE, &ring->state) && ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_ETQF_MASK)) == (cpu_to_le16(IXGBE_ETQF_FILTER_FCOE << IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT))); @@ -1519,6 +1519,12 @@ static bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring, skb->truesize -= ixgbe_rx_bufsz(rx_ring); } +#ifdef IXGBE_FCOE + /* do not attempt to pad FCoE Frames as this will disrupt DDP */ + if (ixgbe_rx_is_fcoe(rx_ring, rx_desc)) + return false; + +#endif /* if skb_pad returns an error the skb was freed */ if (unlikely(skb->len < 60)) { int pad_len = 60 - skb->len; @@ -1745,7 +1751,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, #ifdef IXGBE_FCOE /* if ddp, not passing to ULD unless for FCP_RSP or error */ - if (ixgbe_rx_is_fcoe(adapter, rx_desc)) { + if (ixgbe_rx_is_fcoe(rx_ring, rx_desc)) { ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb); if (!ddp_bytes) { dev_kfree_skb_any(skb); From 8010204c43b1b1543b35972060a0dcaea2cce6fe Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 15 Jun 2012 00:20:44 +0000 Subject: [PATCH 0382/2357] can: c_can: precedence error in c_can_chip_config() commit d9cb9bd63eb27ac19f26a8547128c053f43a5da8 upstream. (CAN_CTRLMODE_LISTENONLY & CAN_CTRLMODE_LOOPBACK) is (0x02 & 0x01) which is zero so the condition is never true. The intent here was to test that both flags were set. Signed-off-by: Dan Carpenter Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/c_can/c_can.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 8dc84d66eea..86cd532c78f 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -590,8 +590,8 @@ static void c_can_chip_config(struct net_device *dev) priv->write_reg(priv, &priv->regs->control, CONTROL_ENABLE_AR); - if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY & - CAN_CTRLMODE_LOOPBACK)) { + if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) && + (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) { /* loopback + silent mode : useful for hot self-test */ priv->write_reg(priv, &priv->regs->control, CONTROL_EIE | CONTROL_SIE | CONTROL_IE | CONTROL_TEST); From 70f6c28e4621b4c7047e3d4b848fc0393a9789e3 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 27 Jun 2012 16:19:18 +0800 Subject: [PATCH 0383/2357] can: flexcan: use be32_to_cpup to handle the value of dt entry commit 85f2f834e85517307f13e30e630a5fc86f757cb5 upstream. The freescale arm i.MX series platform can support this driver, and usually the arm cpu works in the little endian mode by default, while device tree entry value is stored in big endian format, we should use be32_to_cpup() to handle them, after modification, it can work well both on the le cpu and be cpu. Cc: Shawn Guo Signed-off-by: Hui Wang Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/flexcan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 1efb08386c6..00baa7e094f 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -933,12 +933,12 @@ static int __devinit flexcan_probe(struct platform_device *pdev) u32 clock_freq = 0; if (pdev->dev.of_node) { - const u32 *clock_freq_p; + const __be32 *clock_freq_p; clock_freq_p = of_get_property(pdev->dev.of_node, "clock-frequency", NULL); if (clock_freq_p) - clock_freq = *clock_freq_p; + clock_freq = be32_to_cpup(clock_freq_p); } if (!clock_freq) { From eb2e99be9b4f0354c28f8528cf3e87ef7b2d0ce8 Mon Sep 17 00:00:00 2001 From: "Andrew Bird (Sphere Systems)" Date: Sat, 19 May 2012 22:28:36 +0000 Subject: [PATCH 0384/2357] USB: qmi_wwan: Make forced int 4 whitelist generic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 00001880cd8faaa349fe2ebb158f7e0cd8026048 upstream. Change the forced interface 4 whitelist to use the generic shared binder instead of the Gobi specific one. Certain ZTE devices (K3520-Z & K3765-Z) don't work with the Gobi version, but function quite happily with the generic. This has been tested with the following devices: K3520-Z K3565-Z K3765-Z K4505-Z It hasn't been tested with the ZTE MF820D, which is the only other device that uses this whitelist at present. Although Bjorn doesn't expect any problems, any testing with that device would be appreciated. Signed-off-by: Andrew Bird Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index d316503b35d..62a1a4350f1 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -357,9 +357,9 @@ static const struct driver_info qmi_wwan_gobi = { /* ZTE suck at making USB descriptors */ static const struct driver_info qmi_wwan_force_int4 = { - .description = "Qualcomm Gobi wwan/QMI device", + .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_gobi, + .bind = qmi_wwan_bind_shared, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, .data = BIT(4), /* interface whitelist bitmap */ From 6052c2a9783d95a58c797931cebd5a8f1cfdbefd Mon Sep 17 00:00:00 2001 From: "Andrew Bird (Sphere Systems)" Date: Sat, 19 May 2012 22:28:38 +0000 Subject: [PATCH 0385/2357] USB: qmi_wwan: Add ZTE (Vodafone) K3520-Z MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f7142e6c226076fd40c2ebaad9fb0c9a631b790e upstream. Signed-off-by: Andrew Bird Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 62a1a4350f1..fd692a2aee2 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -356,6 +356,15 @@ static const struct driver_info qmi_wwan_gobi = { }; /* ZTE suck at making USB descriptors */ +static const struct driver_info qmi_wwan_force_int1 = { + .description = "Qualcomm WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_shared, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(1), /* interface whitelist bitmap */ +}; + static const struct driver_info qmi_wwan_force_int4 = { .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, @@ -430,6 +439,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K3520-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x0055, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int1, + }, { /* ZTE (Vodafone) K3565-Z */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, From 4dd207877fcaf5453be515a529f593061bbd2d8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 21 Jun 2012 02:45:58 +0000 Subject: [PATCH 0386/2357] net: qmi_wwan: fix Gobi device probing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b9f90eb2740203ff2592efe640409ad48335d1c2 upstream. Ignoring interfaces with additional descriptors is not a reliable method for locating the correct interface on Gobi devices. There is at least one device where this method fails: https://bbs.archlinux.org/viewtopic.php?id=143506 The result is that the AT command port (interface #2) is hidden from qcserial, preventing traditional serial modem usage: [ 15.562552] qmi_wwan 4-1.6:1.0: cdc-wdm0: USB WDM device [ 15.562691] qmi_wwan 4-1.6:1.0: wwan0: register 'qmi_wwan' at usb-0000:00:1d.0-1.6, Qualcomm Gobi wwan/QMI device, 1e:df:3c:3a:4e:3b [ 15.563383] qmi_wwan: probe of 4-1.6:1.1 failed with error -22 [ 15.564189] qmi_wwan 4-1.6:1.2: cdc-wdm1: USB WDM device [ 15.564302] qmi_wwan 4-1.6:1.2: wwan1: register 'qmi_wwan' at usb-0000:00:1d.0-1.6, Qualcomm Gobi wwan/QMI device, 1e:df:3c:3a:4e:3b [ 15.564328] qmi_wwan: probe of 4-1.6:1.3 failed with error -22 [ 15.569376] qcserial 4-1.6:1.1: Qualcomm USB modem converter detected [ 15.569440] usb 4-1.6: Qualcomm USB modem converter now attached to ttyUSB0 [ 15.570372] qcserial 4-1.6:1.3: Qualcomm USB modem converter detected [ 15.570430] usb 4-1.6: Qualcomm USB modem converter now attached to ttyUSB1 Use static interface numbers taken from the interface map in qcserial for all Gobi devices instead: Gobi 1K USB layout: 0: serial port (doesn't respond) 1: serial port (doesn't respond) 2: AT-capable modem port 3: QMI/net Gobi 2K+ USB layout: 0: QMI/net 1: DM/DIAG (use libqcdm from ModemManager for communication) 2: AT-capable modem port 3: NMEA This should be more reliable over all, and will also prevent the noisy "probe failed" messages. The whitelisting logic is expected to be replaced by direct interface number matching in 3.6. Reported-by: Heinrich Siebmanns (Harvey) Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 83 ++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index fd692a2aee2..6dbe422f8cc 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -257,29 +257,6 @@ static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) return rv; } -/* Gobi devices uses identical class/protocol codes for all interfaces regardless - * of function. Some of these are CDC ACM like and have the exact same endpoints - * we are looking for. This leaves two possible strategies for identifying the - * correct interface: - * a) hardcoding interface number, or - * b) use the fact that the wwan interface is the only one lacking additional - * (CDC functional) descriptors - * - * Let's see if we can get away with the generic b) solution. - */ -static int qmi_wwan_bind_gobi(struct usbnet *dev, struct usb_interface *intf) -{ - int rv = -EINVAL; - - /* ignore any interface with additional descriptors */ - if (intf->cur_altsetting->extralen) - goto err; - - rv = qmi_wwan_bind_shared(dev, intf); -err: - return rv; -} - static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf) { struct usb_driver *subdriver = (void *)dev->data[0]; @@ -347,15 +324,15 @@ static const struct driver_info qmi_wwan_shared = { .manage_power = qmi_wwan_manage_power, }; -static const struct driver_info qmi_wwan_gobi = { - .description = "Qualcomm Gobi wwan/QMI device", +static const struct driver_info qmi_wwan_force_int0 = { + .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_gobi, + .bind = qmi_wwan_bind_shared, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, + .data = BIT(0), /* interface whitelist bitmap */ }; -/* ZTE suck at making USB descriptors */ static const struct driver_info qmi_wwan_force_int1 = { .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, @@ -365,6 +342,15 @@ static const struct driver_info qmi_wwan_force_int1 = { .data = BIT(1), /* interface whitelist bitmap */ }; +static const struct driver_info qmi_wwan_force_int3 = { + .description = "Qualcomm WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_shared, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(3), /* interface whitelist bitmap */ +}; + static const struct driver_info qmi_wwan_force_int4 = { .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, @@ -390,16 +376,23 @@ static const struct driver_info qmi_wwan_force_int4 = { static const struct driver_info qmi_wwan_sierra = { .description = "Sierra Wireless wwan/QMI device", .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_gobi, + .bind = qmi_wwan_bind_shared, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, .data = BIT(8) | BIT(19), /* interface whitelist bitmap */ }; #define HUAWEI_VENDOR_ID 0x12D1 + +/* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ +#define QMI_GOBI1K_DEVICE(vend, prod) \ + USB_DEVICE(vend, prod), \ + .driver_info = (unsigned long)&qmi_wwan_force_int3 + +/* Gobi 2000 and Gobi 3000 QMI/wwan interface number is 0 according to qcserial */ #define QMI_GOBI_DEVICE(vend, prod) \ USB_DEVICE(vend, prod), \ - .driver_info = (unsigned long)&qmi_wwan_gobi + .driver_info = (unsigned long)&qmi_wwan_force_int0 static const struct usb_device_id products[] = { { /* Huawei E392, E398 and possibly others sharing both device id and more... */ @@ -493,20 +486,24 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_sierra, }, - {QMI_GOBI_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ - {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ - {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ - {QMI_GOBI_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ - {QMI_GOBI_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ - {QMI_GOBI_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ - {QMI_GOBI_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ + + /* Gobi 1000 devices */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ + {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ + {QMI_GOBI1K_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ + {QMI_GOBI1K_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ + + /* Gobi 2000 and 3000 devices */ {QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ {QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */ {QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */ From a71e15c90f58beb7a7f8df6ab7d46fb7c4ca618b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 21 Jun 2012 23:11:18 +0000 Subject: [PATCH 0387/2357] net: qmi_wwan: fix Oops while disconnecting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d9b8706843a501034d09bea63ca6723a2ed02b11 upstream. usbnet_disconnect() will set intfdata to NULL before calling the minidriver unbind function. The cdc_wdm subdriver cannot know that it is disconnecting until the qmi_wwan unbind function has called its disconnect function. This means that we must be able to support the cdc_wdm subdriver operating normally while usbnet_disconnect() is running, and in particular that intfdata may be NULL. The only place this matters is in qmi_wwan_cdc_wdm_manage_power which is called from cdc_wdm. Simply testing for NULL intfdata there is sufficient to allow it to continue working at all times. Fixes this Oops where a cdc-wdm device was closed while the USB device was disconnecting, causing wdm_release to call qmi_wwan_cdc_wdm_manage_power after intfdata was set to NULL by usbnet_disconnect: [41819.087460] BUG: unable to handle kernel NULL pointer dereference at 00000080 [41819.087815] IP: [] qmi_wwan_manage_power+0x68/0x90 [qmi_wwan] [41819.088028] *pdpt = 000000000314f001 *pde = 0000000000000000 [41819.088028] Oops: 0002 [#1] SMP [41819.088028] Modules linked in: qmi_wwan option usb_wwan usbserial usbnet cdc_wdm nls_iso8859_1 nls_cp437 vfat fat usb_storage bnep rfcomm bluetooth parport_pc ppdev binfmt_misc iptable_nat nf_nat nf_conntrack_ipv4 nf_conntrack nf_defrag_ipv4 iptable_mangle iptable_filter ip_tables x_tables dm_crypt uvcvideo snd_hda_codec_realtek snd_hda_intel videobuf2_core snd_hda_codec joydev videodev videobuf2_vmalloc hid_multitouch snd_hwdep arc4 videobuf2_memops snd_pcm snd_seq_midi snd_rawmidi snd_seq_midi_event ath9k mac80211 snd_seq ath9k_common ath9k_hw ath snd_timer snd_seq_device sparse_keymap dm_multipath scsi_dh coretemp mac_hid snd soundcore cfg80211 snd_page_alloc psmouse serio_raw microcode lp parport dm_mirror dm_region_hash dm_log usbhid hid i915 drm_kms_helper drm r8169 i2c_algo_bit wmi video [last unloaded: qmi_wwan] [41819.088028] [41819.088028] Pid: 23292, comm: qmicli Not tainted 3.4.0-5-generic #11-Ubuntu GIGABYTE T1005/T1005 [41819.088028] EIP: 0060:[] EFLAGS: 00010246 CPU: 1 [41819.088028] EIP is at qmi_wwan_manage_power+0x68/0x90 [qmi_wwan] [41819.088028] EAX: 00000000 EBX: 00000000 ECX: 000000c3 EDX: 00000000 [41819.088028] ESI: c3b27658 EDI: 00000000 EBP: c298bea4 ESP: c298be98 [41819.088028] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [41819.088028] CR0: 8005003b CR2: 00000080 CR3: 3605e000 CR4: 000007f0 [41819.088028] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [41819.088028] DR6: ffff0ff0 DR7: 00000400 [41819.088028] Process qmicli (pid: 23292, ti=c298a000 task=f343b280 task.ti=c298a000) [41819.088028] Stack: [41819.088028] 00000000 c3b27658 e2a80d00 c298beb0 f864051a c3b27600 c298bec0 f9027099 [41819.088028] c2fd6000 00000008 c298bef0 c1147f96 00000001 00000000 00000000 f4e54790 [41819.088028] ecf43a00 ecf43a00 c2fd6008 c2fd6000 ebbd7600 ffffffb9 c298bf08 c1144474 [41819.088028] Call Trace: [41819.088028] [] qmi_wwan_cdc_wdm_manage_power+0x1a/0x20 [qmi_wwan] [41819.088028] [] wdm_release+0x69/0x70 [cdc_wdm] [41819.088028] [] fput+0xe6/0x210 [41819.088028] [] filp_close+0x54/0x80 [41819.088028] [] put_files_struct+0x75/0xc0 [41819.088028] [] exit_files+0x46/0x60 [41819.088028] [] do_exit+0x141/0x780 [41819.088028] [] ? wake_up_state+0xf/0x20 [41819.088028] [] ? signal_wake_up+0x28/0x40 [41819.088028] [] ? zap_other_threads+0x6b/0x80 [41819.088028] [] do_group_exit+0x34/0xa0 [41819.088028] [] sys_exit_group+0x18/0x20 [41819.088028] [] sysenter_do_call+0x12/0x28 [41819.088028] Code: 04 83 e7 01 c1 e7 03 0f b6 42 18 83 e0 f7 09 f8 88 42 18 8b 43 04 e8 48 9a dd c8 89 f0 8b 5d f4 8b 75 f8 8b 7d fc 89 ec 5d c3 90 ff 88 80 00 00 00 0f 94 c0 84 c0 75 b7 31 f6 8b 5d f4 89 f0 [41819.088028] EIP: [] qmi_wwan_manage_power+0x68/0x90 [qmi_wwan] SS:ESP 0068:c298be98 [41819.088028] CR2: 0000000000000080 [41819.149492] ---[ end trace 0944479ff8257f55 ]--- Reported-by: Marius Bjørnstad Kotsbak Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 6dbe422f8cc..c2ae4266617 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -197,6 +197,10 @@ static int qmi_wwan_manage_power(struct usbnet *dev, int on) static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) { struct usbnet *dev = usb_get_intfdata(intf); + + /* can be called while disconnecting */ + if (!dev) + return 0; return qmi_wwan_manage_power(dev, on); } From a92fdd54f75eae8e7d591070c83e146ab8eec2e3 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 8 Jun 2012 16:16:04 +0100 Subject: [PATCH 0388/2357] oprofile: perf: use NR_CPUS instead or nr_cpumask_bits for static array commit e734568b675c985db2026848fefaac01c22977a5 upstream. The OProfile perf backend uses a static array to keep track of the perf events on the system. When compiling with CONFIG_CPUMASK_OFFSTACK=y && SMP, nr_cpumask_bits is not a compile-time constant and the build will fail with: oprofile_perf.c:28: error: variably modified 'perf_events' at file scope This patch uses NR_CPUs instead of nr_cpumask_bits for the array initialisation. If this causes space problems in the future, we can always move to dynamic allocation for the events array. Cc: Matt Fleming Reported-by: Russell King - ARM Linux Signed-off-by: Will Deacon Signed-off-by: Robert Richter Signed-off-by: Greg Kroah-Hartman --- drivers/oprofile/oprofile_perf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/oprofile/oprofile_perf.c b/drivers/oprofile/oprofile_perf.c index da14432806c..efc4b7f308c 100644 --- a/drivers/oprofile/oprofile_perf.c +++ b/drivers/oprofile/oprofile_perf.c @@ -25,7 +25,7 @@ static int oprofile_perf_enabled; static DEFINE_MUTEX(oprofile_perf_mutex); static struct op_counter_config *counter_config; -static struct perf_event **perf_events[nr_cpumask_bits]; +static struct perf_event **perf_events[NR_CPUS]; static int num_counters; /* From 174d58573117bc688e9481c8f7392bd1ddf24fcf Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Thu, 14 Jun 2012 18:07:15 -0700 Subject: [PATCH 0389/2357] x86, compat: Use test_thread_flag(TIF_IA32) in compat signal delivery commit 0b91f45b23cb73ce11acdc3cf4c6efd4441e3b3e upstream. Signal delivery compat path may not have the 'TS_COMPAT' flag (that flag indicates how we entered the kernel). So use test_thread_flag(TIF_IA32) instead of is_ia32_task(): one of the functions of TIF_IA32 is just what kind of signal frame we want. Signed-off-by: Suresh Siddha Link: http://lkml.kernel.org/r/1339722435.3475.57.camel@sbsiddha-desk.sc.intel.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/ia32/ia32_signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index a69245ba27e..4f5bfacf464 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -38,7 +38,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) { int err = 0; - bool ia32 = is_ia32_task(); + bool ia32 = test_thread_flag(TIF_IA32); if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; From 3f616017b684a5faf29b7a6b7b100209357136e4 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 22 Jun 2012 10:58:06 -0700 Subject: [PATCH 0390/2357] x86, cpufeature: Rename X86_FEATURE_DTS to X86_FEATURE_DTHERM commit 4ad33411308596f2f918603509729922a1ec4411 upstream. It makes sense to label "Digital Thermal Sensor" as "DTS", but unfortunately the string "dts" was already used for "Debug Store", and /proc/cpuinfo is a user space ABI. Therefore, rename this to "dtherm". This conflict went into mainline via the hwmon tree without any x86 maintainer ack, and without any kind of hint in the subject. a4659053 x86/hwmon: fix initialization of coretemp Reported-by: Jean Delvare Link: http://lkml.kernel.org/r/4FE34BCB.5050305@linux.intel.com Cc: Jan Beulich Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeature.h | 2 +- arch/x86/kernel/cpu/scattered.c | 2 +- drivers/hwmon/coretemp.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 340ee49961a..f91e80f4f18 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -176,7 +176,7 @@ #define X86_FEATURE_XSAVEOPT (7*32+ 4) /* Optimized Xsave */ #define X86_FEATURE_PLN (7*32+ 5) /* Intel Power Limit Notification */ #define X86_FEATURE_PTS (7*32+ 6) /* Intel Package Thermal Status */ -#define X86_FEATURE_DTS (7*32+ 7) /* Digital Thermal Sensor */ +#define X86_FEATURE_DTHERM (7*32+ 7) /* Digital Thermal Sensor */ #define X86_FEATURE_HW_PSTATE (7*32+ 8) /* AMD HW-PState */ /* Virtualization flags: Linux defined, word 8 */ diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index addf9e82a7f..ee8e9abc859 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -31,7 +31,7 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c) const struct cpuid_bit *cb; static const struct cpuid_bit __cpuinitconst cpuid_bits[] = { - { X86_FEATURE_DTS, CR_EAX, 0, 0x00000006, 0 }, + { X86_FEATURE_DTHERM, CR_EAX, 0, 0x00000006, 0 }, { X86_FEATURE_IDA, CR_EAX, 1, 0x00000006, 0 }, { X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006, 0 }, { X86_FEATURE_PLN, CR_EAX, 4, 0x00000006, 0 }, diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index b9d512331ed..0f52799973d 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -664,7 +664,7 @@ static void __cpuinit get_core_online(unsigned int cpu) * sensors. We check this bit only, all the early CPUs * without thermal sensors will be filtered out. */ - if (!cpu_has(c, X86_FEATURE_DTS)) + if (!cpu_has(c, X86_FEATURE_DTHERM)) return; if (!pdev) { @@ -765,7 +765,7 @@ static struct notifier_block coretemp_cpu_notifier __refdata = { }; static const struct x86_cpu_id coretemp_ids[] = { - { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTS }, + { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM }, {} }; MODULE_DEVICE_TABLE(x86cpu, coretemp_ids); From 002aea347be398407f6e4eb7f08d754ce4f8dd71 Mon Sep 17 00:00:00 2001 From: Mitch A Williams Date: Sat, 30 Jun 2012 00:23:19 +0000 Subject: [PATCH 0391/2357] igbvf: fix divide by zero commit 0e90b49ca4b891f085b57559a3071a4feefb496c upstream. Using ethtool -C ethX rx-usecs 0 crashes with a divide by zero. Refactor this function to fix this issue and make it more clear what the intent of each conditional is. Add comment regarding using a setting of zero. CC: David Ahern Signed-off-by: Mitch Williams Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/igbvf/ethtool.c | 29 ++++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/igbvf/ethtool.c b/drivers/net/ethernet/intel/igbvf/ethtool.c index 8ce67064b9c..90eef07943f 100644 --- a/drivers/net/ethernet/intel/igbvf/ethtool.c +++ b/drivers/net/ethernet/intel/igbvf/ethtool.c @@ -357,21 +357,28 @@ static int igbvf_set_coalesce(struct net_device *netdev, struct igbvf_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - if ((ec->rx_coalesce_usecs > IGBVF_MAX_ITR_USECS) || - ((ec->rx_coalesce_usecs > 3) && - (ec->rx_coalesce_usecs < IGBVF_MIN_ITR_USECS)) || - (ec->rx_coalesce_usecs == 2)) - return -EINVAL; - - /* convert to rate of irq's per second */ - if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3) { + if ((ec->rx_coalesce_usecs >= IGBVF_MIN_ITR_USECS) && + (ec->rx_coalesce_usecs <= IGBVF_MAX_ITR_USECS)) { + adapter->current_itr = ec->rx_coalesce_usecs << 2; + adapter->requested_itr = 1000000000 / + (adapter->current_itr * 256); + } else if ((ec->rx_coalesce_usecs == 3) || + (ec->rx_coalesce_usecs == 2)) { adapter->current_itr = IGBVF_START_ITR; adapter->requested_itr = ec->rx_coalesce_usecs; - } else { - adapter->current_itr = ec->rx_coalesce_usecs << 2; + } else if (ec->rx_coalesce_usecs == 0) { + /* + * The user's desire is to turn off interrupt throttling + * altogether, but due to HW limitations, we can't do that. + * Instead we set a very small value in EITR, which would + * allow ~967k interrupts per second, but allow the adapter's + * internal clocking to still function properly. + */ + adapter->current_itr = 4; adapter->requested_itr = 1000000000 / (adapter->current_itr * 256); - } + } else + return -EINVAL; writel(adapter->current_itr, hw->hw_addr + adapter->rx_ring->itr_register); From 8359e058c9677f0459760f3610161bc2cfcd930f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 25 Jun 2012 18:01:12 -0500 Subject: [PATCH 0392/2357] rtlwifi: rtl8192cu: New USB IDs commit f63d7dabd5da9ef41f28f6d69b29bc084db0ca5a upstream. The latest Realtek driver for the RTL8188CU and RTL8192CU chips adds three new USB IDs. Reported-by: Xose Vazquez Perez Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 82c85286ab2..5bd40856635 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -301,9 +301,11 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ + {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/ {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/ + {RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/ /* HP - Lite-On ,8188CUS Slim Combo */ {RTL_USB_DEVICE(0x103c, 0x1629, rtl92cu_hal_cfg)}, {RTL_USB_DEVICE(0x13d3, 0x3357, rtl92cu_hal_cfg)}, /* AzureWave */ @@ -345,6 +347,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/ {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/ + {RTL_USB_DEVICE(0x0bda, 0x8186, rtl92cu_hal_cfg)}, /*Realtek 92CE-VAU*/ {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/ {RTL_USB_DEVICE(0x0e66, 0x0019, rtl92cu_hal_cfg)}, /*Hawking-Edimax*/ {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/ From 576f080b901d7258874a4632850ad94fc296911f Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 1 Jun 2012 11:14:03 +0300 Subject: [PATCH 0393/2357] mac80211: clear ifmgd->bssid only after building DELBA commit 88a9e31c506c00c8b7a2f1611406d0e38dcb33b3 upstream. ieee80211_set_disassoc() clears ifmgd->bssid before building DELBA frames, resulting in frames with invalid bssid ("00:00:00:00:00:00"). Fix it by clearing ifmgd->bssid only after building all the needed frames. After this change, we no longer need to save the bssid (before clearing it), so remove the local array. Reported-by: Ido Yariv Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 20c680bfc3a..425653f464c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1375,7 +1375,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sta_info *sta; u32 changed = 0; - u8 bssid[ETH_ALEN]; ASSERT_MGD_MTX(ifmgd); @@ -1385,10 +1384,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!ifmgd->associated)) return; - memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); - ifmgd->associated = NULL; - memset(ifmgd->bssid, 0, ETH_ALEN); /* * we need to commit the associated = NULL change because the @@ -1408,7 +1404,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, netif_carrier_off(sdata->dev); mutex_lock(&local->sta_mtx); - sta = sta_info_get(sdata, bssid); + sta = sta_info_get(sdata, ifmgd->bssid); if (sta) { set_sta_flag(sta, WLAN_STA_BLOCK_BA); ieee80211_sta_tear_down_BA_sessions(sta, tx); @@ -1417,13 +1413,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, /* deauthenticate/disassociate now */ if (tx || frame_buf) - ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason, - tx, frame_buf); + ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, + reason, tx, frame_buf); /* flush out frame */ if (tx) drv_flush(local, false); + /* clear bssid only after building the needed mgmt frames */ + memset(ifmgd->bssid, 0, ETH_ALEN); + /* remove AP and TDLS peers */ sta_info_flush(local, sdata); From cec8fdaf9656e82c599729595baae99c2c2a78b7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 27 Jun 2012 15:38:56 +0200 Subject: [PATCH 0394/2357] mac80211: correct behaviour on unrecognised action frames commit 4b5ebccc40843104d980f0714bc86bfcd5568941 upstream. When receiving an "individually addressed" action frame, the receiver is required to return it to the sender. mac80211 gets this wrong as it also returns group addressed (mcast) frames to the sender. Fix this and update the reference to the new 802.11 standards version since things were shuffled around significantly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d64e285400a..c9b508ea9d6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2459,7 +2459,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) * frames that we didn't handle, including returning unknown * ones. For all other modes we will return them to the sender, * setting the 0x80 bit in the action category, as required by - * 802.11-2007 7.3.1.11. + * 802.11-2012 9.24.4. * Newer versions of hostapd shall also use the management frame * registration mechanisms, but older ones still use cooked * monitor interfaces so push all frames there. @@ -2469,6 +2469,9 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) return RX_DROP_MONITOR; + if (is_multicast_ether_addr(mgmt->da)) + return RX_DROP_MONITOR; + /* do not return rejected action frames */ if (mgmt->u.action.category & 0x80) return RX_DROP_UNUSABLE; From c482c429398b707c9a228e89535b242252cc4c33 Mon Sep 17 00:00:00 2001 From: Stone Piao Date: Wed, 20 Jun 2012 20:21:10 -0700 Subject: [PATCH 0395/2357] mwifiex: fix 11n rx packet drop issue commit 925839243dc9aa4ef25305f5afd10ed18258a4ac upstream. Currently we check the sequence number of last packet received against start_win. If a sequence hole is detected, start_win is updated to next sequence number. Since the rx sequence number is initialized to 0, a corner case exists when BA setup happens immediately after association. As 0 is a valid sequence number, start_win gets increased to 1 incorrectly. This causes the first packet with sequence number 0 being dropped. Initialize rx sequence number as 0xffff and skip adjusting start_win if the sequence number remains 0xffff. The sequence number will be updated once the first packet is received. Signed-off-by: Stone Piao Signed-off-by: Avinash Patil Signed-off-by: Kiran Divekar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mwifiex/11n_rxreorder.c | 5 +++-- drivers/net/wireless/mwifiex/11n_rxreorder.h | 7 +++++++ drivers/net/wireless/mwifiex/wmm.c | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 9c44088054d..900ee129e82 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -256,7 +256,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, else last_seq = priv->rx_seq[tid]; - if (last_seq >= new_node->start_win) + if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM && + last_seq >= new_node->start_win) new_node->start_win = last_seq + 1; new_node->win_size = win_size; @@ -596,5 +597,5 @@ void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); - memset(priv->rx_seq, 0, sizeof(priv->rx_seq)); + mwifiex_reset_11n_rx_seq_num(priv); } diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h index f1bffebabc6..6c9815a0f5d 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.h +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -37,6 +37,13 @@ #define ADDBA_RSP_STATUS_ACCEPT 0 +#define MWIFIEX_DEF_11N_RX_SEQ_NUM 0xffff + +static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv) +{ + memset(priv->rx_seq, 0xff, sizeof(priv->rx_seq)); +} + int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *, u16 seqNum, u16 tid, u8 *ta, diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 5a7316c6f12..0797c2eac5b 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -404,6 +404,8 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE; priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE; + mwifiex_reset_11n_rx_seq_num(priv); + atomic_set(&priv->wmm.tx_pkts_queued, 0); atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); } From 30716eeec35ce79a2140b4814bd417e02da08450 Mon Sep 17 00:00:00 2001 From: Stone Piao Date: Wed, 20 Jun 2012 20:21:11 -0700 Subject: [PATCH 0396/2357] mwifiex: fix WPS eapol handshake failure commit f03ba7e9a24e5e9efaad56bd1713b994ea556b16 upstream. After association, STA will go through eapol handshake with WPS enabled AP. It's observed that WPS handshake fails with some 11n AP. The reason for the failure is that the eapol packet is sent via 11n frame aggregation. The eapol packet should be sent directly without 11n aggregation. This patch fixes the problem by adding WPS session control while dequeuing Tx packets for transmission. Signed-off-by: Stone Piao Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mwifiex/wmm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 0797c2eac5b..3e6abf018b5 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1211,6 +1211,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid) || + priv->wps.session_enable || ((priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set)) { From 881aa809b005753a64fe9409c1d229912cc925ce Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 7 Jul 2012 10:17:00 -0700 Subject: [PATCH 0397/2357] vfs: make O_PATH file descriptors usable for 'fchdir()' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 332a2e1244bd08b9e3ecd378028513396a004a24 upstream. We already use them for openat() and friends, but fchdir() also wants to be able to use O_PATH file descriptors. This should make it comparable to the O_SEARCH of Solaris. In particular, O_PATH allows you to access (not-quite-open) a directory you don't have read persmission to, only execute permission. Noticed during development of multithread support for ksh93. Reported-by: ольга крыжановская Cc: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/open.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/open.c b/fs/open.c index 5720854156d..3f1108b1914 100644 --- a/fs/open.c +++ b/fs/open.c @@ -396,10 +396,10 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) { struct file *file; struct inode *inode; - int error; + int error, fput_needed; error = -EBADF; - file = fget(fd); + file = fget_raw_light(fd, &fput_needed); if (!file) goto out; @@ -413,7 +413,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) if (!error) set_fs_pwd(current->fs, &file->f_path); out_putf: - fput(file); + fput_light(file, fput_needed); out: return error; } From f838956ac64e227e682d7d4da9883888b9aab381 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 9 Jun 2012 19:08:25 +0300 Subject: [PATCH 0398/2357] mtd: cafe_nand: fix an & vs | mistake commit 48f8b641297df49021093763a3271119a84990a2 upstream. The intent here was clearly to set result to true if the 0x40000000 flag was set. But instead there was a | vs & typo and we always set result to true. Artem: check the spec at wiki.laptop.org/images/5/5c/88ALP01_Datasheet_July_2007.pdf and this fix looks correct. Signed-off-by: Dan Carpenter Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/cafe_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 2a96e1a1206..6d22755969d 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -102,7 +102,7 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int cafe_device_ready(struct mtd_info *mtd) { struct cafe_priv *cafe = mtd->priv; - int result = !!(cafe_readl(cafe, NAND_STATUS) | 0x40000000); + int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000); uint32_t irqs = cafe_readl(cafe, NAND_IRQ); cafe_writel(cafe, irqs, NAND_IRQ); From f632881de16f8c3133cd1b0866937f50fa2e9156 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Wed, 27 Jun 2012 17:09:54 +0800 Subject: [PATCH 0399/2357] aio: make kiocb->private NUll in init_sync_kiocb() commit 2dfd06036ba7ae8e7be2daf5a2fff1dac42390bf upstream. Ocfs2 uses kiocb.*private as a flag of unsigned long size. In commit a11f7e6 ocfs2: serialize unaligned aio, the unaligned io flag is involved in it to serialize the unaligned aio. As *private is not initialized in init_sync_kiocb() of do_sync_write(), this unaligned io flag may be unexpectly set in an aligned dio. And this will cause OCFS2_I(inode)->ip_unaligned_aio decreased to -1 in ocfs2_dio_end_io(), thus the following unaligned dio will hang forever at ocfs2_aiodio_wait() in ocfs2_file_aio_write(). Signed-off-by: Junxiao Bi Acked-by: Jeff Moyer Signed-off-by: Joel Becker Signed-off-by: Greg Kroah-Hartman --- include/linux/aio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/aio.h b/include/linux/aio.h index 2314ad8b3c9..b1a520ec8b5 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -140,6 +140,7 @@ struct kiocb { (x)->ki_dtor = NULL; \ (x)->ki_obj.tsk = tsk; \ (x)->ki_user_data = 0; \ + (x)->private = NULL; \ } while (0) #define AIO_RING_MAGIC 0xa10a10a1 From 47e38c598d1a3bf7d01c540c46d2039708337622 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Wed, 27 Jun 2012 17:09:55 +0800 Subject: [PATCH 0400/2357] ocfs2: clear unaligned io flag when dio fails commit 3e5d3c35a68c9a933bdbdd8685bd1a205b57e806 upstream. The unaligned io flag is set in the kiocb when an unaligned dio is issued, it should be cleared even when the dio fails, or it may affect the following io which are using the same kiocb. Signed-off-by: Junxiao Bi Signed-off-by: Joel Becker Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 061591a3ab0..98513c8ed58 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2422,8 +2422,10 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, unaligned_dio = 0; } - if (unaligned_dio) + if (unaligned_dio) { + ocfs2_iocb_clear_unaligned_aio(iocb); atomic_dec(&OCFS2_I(inode)->ip_unaligned_aio); + } out: if (rw_level != -1) From c86f7d63a7906495a6742dfe4a0cd708fd41b9e1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Jun 2012 09:36:41 +0200 Subject: [PATCH 0401/2357] iwlwifi: fix activating inactive stations commit eac9ac6d1f5d0e9d33e4ded682187b630e7606cd upstream. When authentication/association timed out, the driver would complain bitterly, printing the message ACTIVATE a non DRIVER active station id ... addr ... The cause turns out to be that when the AP station is added but we don't associate, the IWL_STA_UCODE_INPROGRESS is set but never cleared. This then causes iwl_restore_stations() to attempt to resend it because it uses the flag internally and uploads even if it didn't set it itself. To fix this issue and not upload the station again when it has already been removed by mac80211, clear the flag after adding it in case we add it only for association. Reviewed-by: Meenakshi Venkataraman Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-mac80211.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index 1018f9b8b41..e0e6c6745d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -788,6 +788,18 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw, switch (op) { case ADD: ret = iwlagn_mac_sta_add(hw, vif, sta); + if (ret) + break; + /* + * Clear the in-progress flag, the AP station entry was added + * but we'll initialize LQ only when we've associated (which + * would also clear the in-progress flag). This is necessary + * in case we never initialize LQ because association fails. + */ + spin_lock_bh(&priv->sta_lock); + priv->stations[iwl_sta_id(sta)].used &= + ~IWL_STA_UCODE_INPROGRESS; + spin_unlock_bh(&priv->sta_lock); break; case REMOVE: ret = iwlagn_mac_sta_remove(hw, vif, sta); From 1ee0932804c2526efca4c6623911b07f6992eb3f Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 26 Jun 2012 15:57:30 -0700 Subject: [PATCH 0402/2357] tcm_fc: Resolve suspicious RCU usage warnings commit 863555be0c81558b1af277addcf68acb8f778860 upstream. Use rcu_dereference_protected to tell rcu that the ft_lport_lock is held during ft_lport_create. This resolved "suspicious RCU usage" warnings when debugging options are turned on. Signed-off-by: Mark Rustad Tested-by: Ross Brattain Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/tcm_fc/tfc_sess.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index cb99da92006..87901fa74dd 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -58,7 +58,8 @@ static struct ft_tport *ft_tport_create(struct fc_lport *lport) struct ft_tport *tport; int i; - tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); + tport = rcu_dereference_protected(lport->prov[FC_TYPE_FCP], + lockdep_is_held(&ft_lport_lock)); if (tport && tport->tpg) return tport; From e10e76db80d80227dea2a55ea83613c6a4023e67 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Sat, 30 Jun 2012 20:02:42 +0000 Subject: [PATCH 0403/2357] e1000e: remove use of IP payload checksum commit 2e1706f234f86ff71056ef69683d734fbf7e9e40 upstream. Currently only used when packet split mode is enabled with jumbo frames, IP payload checksum (for fragmented UDP packets) is mutually exclusive with receive hashing offload since the hardware uses the same space in the receive descriptor for the hardware-provided packet checksum and the RSS hash, respectively. Users currently must disable jumbos when receive hashing offload is enabled, or vice versa, because of this incompatibility. Since testing has shown that IP payload checksum does not provide any real benefit, just remove it so that there is no longer a choice between jumbos or receive hashing offload but not both as done in other Intel GbE drivers (e.g. e1000, igb). Also, add a missing check for IP checksum error reported by the hardware; let the stack verify the checksum when this happens. Signed-off-by: Bruce Allan Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/defines.h | 1 + drivers/net/ethernet/intel/e1000e/netdev.c | 75 ++++----------------- 2 files changed, 15 insertions(+), 61 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 3a502591716..eb84fe7b1c0 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -101,6 +101,7 @@ #define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ #define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ #define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ +#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ #define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ #define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 00e961e42c6..a87e84f36bc 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -495,7 +495,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter, * @sk_buff: socket buffer with received data **/ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, - __le16 csum, struct sk_buff *skb) + struct sk_buff *skb) { u16 status = (u16)status_err; u8 errors = (u8)(status_err >> 24); @@ -510,8 +510,8 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, if (status & E1000_RXD_STAT_IXSM) return; - /* TCP/UDP checksum error bit is set */ - if (errors & E1000_RXD_ERR_TCPE) { + /* TCP/UDP checksum error bit or IP checksum error bit is set */ + if (errors & (E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) { /* let the stack verify checksum errors */ adapter->hw_csum_err++; return; @@ -522,19 +522,7 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, return; /* It must be a TCP or UDP packet with a valid checksum */ - if (status & E1000_RXD_STAT_TCPCS) { - /* TCP checksum is good */ - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { - /* - * IP fragment with UDP payload - * Hardware complements the payload checksum, so we undo it - * and then put the value in host order for further stack use. - */ - __sum16 sum = (__force __sum16)swab16((__force u16)csum); - skb->csum = csum_unfold(~sum); - skb->ip_summed = CHECKSUM_COMPLETE; - } + skb->ip_summed = CHECKSUM_UNNECESSARY; adapter->hw_csum_good++; } @@ -978,8 +966,7 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done, skb_put(skb, length); /* Receive Checksum Offload */ - e1000_rx_checksum(adapter, staterr, - rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); + e1000_rx_checksum(adapter, staterr, skb); e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb); @@ -1360,8 +1347,7 @@ static bool e1000_clean_rx_irq_ps(struct e1000_ring *rx_ring, int *work_done, total_rx_bytes += skb->len; total_rx_packets++; - e1000_rx_checksum(adapter, staterr, - rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); + e1000_rx_checksum(adapter, staterr, skb); e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb); @@ -1531,9 +1517,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done, } } - /* Receive Checksum Offload XXX recompute due to CRC strip? */ - e1000_rx_checksum(adapter, staterr, - rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); + /* Receive Checksum Offload */ + e1000_rx_checksum(adapter, staterr, skb); e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb); @@ -3120,19 +3105,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) /* Enable Receive Checksum Offload for TCP and UDP */ rxcsum = er32(RXCSUM); - if (adapter->netdev->features & NETIF_F_RXCSUM) { + if (adapter->netdev->features & NETIF_F_RXCSUM) rxcsum |= E1000_RXCSUM_TUOFL; - - /* - * IPv4 payload checksum for UDP fragments must be - * used in conjunction with packet-split. - */ - if (adapter->rx_ps_pages) - rxcsum |= E1000_RXCSUM_IPPCSE; - } else { + else rxcsum &= ~E1000_RXCSUM_TUOFL; - /* no need to clear IPPCSE as it defaults to 0 */ - } ew32(RXCSUM, rxcsum); if (adapter->hw.mac.type == e1000_pch2lan) { @@ -5260,22 +5236,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; /* Jumbo frame support */ - if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { - if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { - e_err("Jumbo Frames not supported.\n"); - return -EINVAL; - } - - /* - * IP payload checksum (enabled with jumbos/packet-split when - * Rx checksum is enabled) and generation of RSS hash is - * mutually exclusive in the hardware. - */ - if ((netdev->features & NETIF_F_RXCSUM) && - (netdev->features & NETIF_F_RXHASH)) { - e_err("Jumbo frames cannot be enabled when both receive checksum offload and receive hashing are enabled. Disable one of the receive offload features before enabling jumbos.\n"); - return -EINVAL; - } + if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) && + !(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { + e_err("Jumbo Frames not supported.\n"); + return -EINVAL; } /* Supported frame sizes */ @@ -6049,17 +6013,6 @@ static int e1000_set_features(struct net_device *netdev, NETIF_F_RXALL))) return 0; - /* - * IP payload checksum (enabled with jumbos/packet-split when Rx - * checksum is enabled) and generation of RSS hash is mutually - * exclusive in the hardware. - */ - if (adapter->rx_ps_pages && - (features & NETIF_F_RXCSUM) && (features & NETIF_F_RXHASH)) { - e_err("Enabling both receive checksum offload and receive hashing is not possible with jumbo frames. Disable jumbos or enable only one of the receive offload features.\n"); - return -EINVAL; - } - if (changed & NETIF_F_RXFCS) { if (features & NETIF_F_RXFCS) { adapter->flags2 &= ~FLAG2_CRC_STRIPPING; From 4f160c794702b3bca35513fd64b481e90d1c6cf1 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Sun, 1 Jul 2012 11:31:35 +0300 Subject: [PATCH 0404/2357] remoteproc/omap: fix randconfig unmet direct dependencies commit d50394266b340d930a7458fa669d36e99670f200 upstream. OMAP_REMOTEPROC selects REMOTEPROC and RPMSG, both of which depend on EXPERIMENTAL, so let's have OMAP_REMOTEPROC depend on EXPERIMENTAL too, in order to avoid the below randconfig warnings. warning: (OMAP_REMOTEPROC) selects REMOTEPROC which has unmet direct dependencies (EXPERIMENTAL) warning: (OMAP_REMOTEPROC) selects RPMSG which has unmet direct dependencies (EXPERIMENTAL) Reported-by: Tony Lindgren Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/remoteproc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 24d880e78ec..db4e39b9164 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -7,6 +7,7 @@ config REMOTEPROC config OMAP_REMOTEPROC tristate "OMAP remoteproc support" + depends on EXPERIMENTAL depends on ARCH_OMAP4 depends on OMAP_IOMMU select REMOTEPROC From 0ea4ad38312422221b1b8a4fd820f38119bfce92 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Sun, 1 Jul 2012 11:53:36 +0300 Subject: [PATCH 0405/2357] remoteproc: fix missing CONFIG_FW_LOADER configurations commit e121aefa7d9f10eee5cf26ed47129237a05d940b upstream. Remoteproc requires user space firmware loading support, so let's select FW_LOADER explicitly to avoid painful misconfigurations (which only show up in runtime). Reported-by: Mark Grosen Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/remoteproc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index db4e39b9164..f8d818abf98 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -4,6 +4,7 @@ menu "Remoteproc drivers (EXPERIMENTAL)" config REMOTEPROC tristate depends on EXPERIMENTAL + select FW_CONFIG config OMAP_REMOTEPROC tristate "OMAP remoteproc support" From 10ff23ae117665e886fed089cb5a2e015cd8b7b4 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Sat, 7 Jul 2012 13:37:42 +0300 Subject: [PATCH 0406/2357] hwspinlock/core: use global ID to register hwspinlocks on multiple devices commit 476a7eeb60e70ddab138e7cb4bc44ef5ac20782e upstream. Commit 300bab9770 (hwspinlock/core: register a bank of hwspinlocks in a single API call, 2011-09-06) introduced 'hwspin_lock_register_single()' to register numerous (a bank of) hwspinlock instances in a single API, 'hwspin_lock_register()'. At which time, 'hwspin_lock_register()' accidentally passes 'local IDs' to 'hwspin_lock_register_single()', despite that ..._single() requires 'global IDs' to register hwspinlocks. We have to convert into global IDs by supplying the missing 'base_id'. Signed-off-by: Shinya Kuribayashi [ohad: fix error path of hwspin_lock_register, too] Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/hwspinlock/hwspinlock_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 61c9cf15fa5..1201a15784c 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -345,7 +345,7 @@ int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev, spin_lock_init(&hwlock->lock); hwlock->bank = bank; - ret = hwspin_lock_register_single(hwlock, i); + ret = hwspin_lock_register_single(hwlock, base_id + i); if (ret) goto reg_failed; } @@ -354,7 +354,7 @@ int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev, reg_failed: while (--i >= 0) - hwspin_lock_unregister_single(i); + hwspin_lock_unregister_single(base_id + i); return ret; } EXPORT_SYMBOL_GPL(hwspin_lock_register); From 04e0f69d135f6cf10534282fc09cf3efd6973c5b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 3 Jul 2012 10:37:30 +1000 Subject: [PATCH 0407/2357] md/raid10: Don't try to recovery unmatched (and unused) chunks. commit fc448a18ae6219af9a73257b1fbcd009efab4a81 upstream. If a RAID10 has an odd number of chunks - as might happen when there are an odd number of devices - the last chunk has no pair and so is not mirrored. We don't store data there, but when recovering the last device in an array we retry to recover that last chunk from a non-existent location. This results in an error, and the recovery aborts. When we get to that last chunk we should just stop - there is nothing more to do anyway. This bug has been present since the introduction of RAID10, so the patch is appropriate for any -stable kernel. Reported-by: Christian Balzer Tested-by: Christian Balzer Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index d037adb295a..86b8aaf91ba 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2772,6 +2772,12 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, /* want to reconstruct this device */ rb2 = r10_bio; sect = raid10_find_virt(conf, sector_nr, i); + if (sect >= mddev->resync_max_sectors) { + /* last stripe is not complete - don't + * try to recover this sector. + */ + continue; + } /* Unless we are doing a full sync, or a replacement * we only need to recover the block if it is set in * the bitmap From 65c3f18b9032f7237fc74403ce3a92176eaebd8c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 3 Jul 2012 15:55:33 +1000 Subject: [PATCH 0408/2357] md/raid10: fix failure when trying to repair a read error. commit 055d3747dbf00ce85c6872ecca4d466638e80c22 upstream. commit 58c54fcca3bac5bf9290cfed31c76e4c4bfbabaf md/raid10: handle further errors during fix_read_error better. in 3.1 added "r10_sync_page_io" which takes an IO size in sectors. But we were passing the IO size in bytes!!! This resulting in bio_add_page failing, and empty request being sent down, and a consequent BUG_ON in scsi_lib. [fix missing space in error message at same time] This fix is suitable for 3.1.y and later. Reported-by: Christian Balzer Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 86b8aaf91ba..a954c95d7c9 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2209,7 +2209,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 if (r10_sync_page_io(rdev, r10_bio->devs[sl].addr + sect, - s<<9, conf->tmppage, WRITE) + s, conf->tmppage, WRITE) == 0) { /* Well, this device is dead */ printk(KERN_NOTICE @@ -2246,7 +2246,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 switch (r10_sync_page_io(rdev, r10_bio->devs[sl].addr + sect, - s<<9, conf->tmppage, + s, conf->tmppage, READ)) { case 0: /* Well, this device is dead */ @@ -2407,7 +2407,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio) slot = r10_bio->read_slot; printk_ratelimited( KERN_ERR - "md/raid10:%s: %s: redirecting" + "md/raid10:%s: %s: redirecting " "sector %llu to another mirror\n", mdname(mddev), bdevname(rdev->bdev, b), From 8d9369807370331cebf3e237b95ecce068af80f1 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Tue, 3 Jul 2012 12:11:54 +1000 Subject: [PATCH 0409/2357] md/raid5: In ops_run_io, inc nr_pending before calling md_wait_for_blocked_rdev commit 1850753d2e6d9ca7856581ca5d3cf09521e6a5d7 upstream. In ops_run_io(), the call to md_wait_for_blocked_rdev will decrement nr_pending so we lose the reference we hold on the rdev. So atomic_inc it first to maintain the reference. This bug was introduced by commit 73e92e51b7969ef5477d md/raid5. Don't write to known bad block on doubtful devices. which appeared in 3.0, so patch is suitable for stable kernels since then. Signed-off-by: majianpeng Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f351422938e..8fc591877dc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -583,6 +583,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) * a chance*/ md_check_recovery(conf->mddev); } + /* + * Because md_wait_for_blocked_rdev + * will dec nr_pending, we must + * increment it first. + */ + atomic_inc(&rdev->nr_pending); md_wait_for_blocked_rdev(rdev, conf->mddev); } else { /* Acknowledged bad block - skip the write */ From a712c8097b28c4c4f705db4102c0eed117806162 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Tue, 3 Jul 2012 12:55:41 +0100 Subject: [PATCH 0410/2357] dm: verity fix documentation commit 18068bdd5f59229623b2fa518a6389e346642b0d upstream. Veritysetup is now part of cryptsetup package. Remove on-disk header description (which is not parsed in kernel) and point users to cryptsetup where it the format is documented. Mention units for block size paramaters. Fix target line specification and dmsetup parameters. Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- Documentation/device-mapper/verity.txt | 131 +++++++++---------------- 1 file changed, 46 insertions(+), 85 deletions(-) diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt index 32e48797a14..9884681535e 100644 --- a/Documentation/device-mapper/verity.txt +++ b/Documentation/device-mapper/verity.txt @@ -7,39 +7,39 @@ This target is read-only. Construction Parameters ======================= - + - This is the version number of the on-disk format. + This is the type of the on-disk hash format. 0 is the original format used in the Chromium OS. - The salt is appended when hashing, digests are stored continuously and - the rest of the block is padded with zeros. + The salt is appended when hashing, digests are stored continuously and + the rest of the block is padded with zeros. 1 is the current format that should be used for new devices. - The salt is prepended when hashing and each digest is - padded with zeros to the power of two. + The salt is prepended when hashing and each digest is + padded with zeros to the power of two. - This is the device containing the data the integrity of which needs to be + This is the device containing data, the integrity of which needs to be checked. It may be specified as a path, like /dev/sdaX, or a device number, :. - This is the device that that supplies the hash tree data. It may be + This is the device that supplies the hash tree data. It may be specified similarly to the device path and may be the same device. If the - same device is used, the hash_start should be outside of the dm-verity - configured device size. + same device is used, the hash_start should be outside the configured + dm-verity device. - The block size on a data device. Each block corresponds to one digest on - the hash device. + The block size on a data device in bytes. + Each block corresponds to one digest on the hash device. - The size of a hash block. + The size of a hash block in bytes. The number of data blocks on the data device. Additional blocks are @@ -65,7 +65,7 @@ Construction Parameters Theory of operation =================== -dm-verity is meant to be setup as part of a verified boot path. This +dm-verity is meant to be set up as part of a verified boot path. This may be anything ranging from a boot using tboot or trustedgrub to just booting from a known-good device (like a USB drive or CD). @@ -73,20 +73,20 @@ When a dm-verity device is configured, it is expected that the caller has been authenticated in some way (cryptographic signatures, etc). After instantiation, all hashes will be verified on-demand during disk access. If they cannot be verified up to the root node of the -tree, the root hash, then the I/O will fail. This should identify +tree, the root hash, then the I/O will fail. This should detect tampering with any data on the device and the hash data. Cryptographic hashes are used to assert the integrity of the device on a -per-block basis. This allows for a lightweight hash computation on first read -into the page cache. Block hashes are stored linearly-aligned to the nearest -block the size of a page. +per-block basis. This allows for a lightweight hash computation on first read +into the page cache. Block hashes are stored linearly, aligned to the nearest +block size. Hash Tree --------- Each node in the tree is a cryptographic hash. If it is a leaf node, the hash -is of some block data on disk. If it is an intermediary node, then the hash is -of a number of child nodes. +of some data block on disk is calculated. If it is an intermediary node, +the hash of a number of child nodes is calculated. Each entry in the tree is a collection of neighboring nodes that fit in one block. The number is determined based on block_size and the size of the @@ -110,63 +110,23 @@ alg = sha256, num_blocks = 32768, block_size = 4096 On-disk format ============== -Below is the recommended on-disk format. The verity kernel code does not -read the on-disk header. It only reads the hash blocks which directly -follow the header. It is expected that a user-space tool will verify the -integrity of the verity_header and then call dmsetup with the correct -parameters. Alternatively, the header can be omitted and the dmsetup -parameters can be passed via the kernel command-line in a rooted chain -of trust where the command-line is verified. +The verity kernel code does not read the verity metadata on-disk header. +It only reads the hash blocks which directly follow the header. +It is expected that a user-space tool will verify the integrity of the +verity header. -The on-disk format is especially useful in cases where the hash blocks -are on a separate partition. The magic number allows easy identification -of the partition contents. Alternatively, the hash blocks can be stored -in the same partition as the data to be verified. In such a configuration -the filesystem on the partition would be sized a little smaller than -the full-partition, leaving room for the hash blocks. - -struct superblock { - uint8_t signature[8] - "verity\0\0"; - - uint8_t version; - 1 - current format - - uint8_t data_block_bits; - log2(data block size) - - uint8_t hash_block_bits; - log2(hash block size) - - uint8_t pad1[1]; - zero padding - - uint16_t salt_size; - big-endian salt size - - uint8_t pad2[2]; - zero padding - - uint32_t data_blocks_hi; - big-endian high 32 bits of the 64-bit number of data blocks - - uint32_t data_blocks_lo; - big-endian low 32 bits of the 64-bit number of data blocks - - uint8_t algorithm[16]; - cryptographic algorithm - - uint8_t salt[384]; - salt (the salt size is specified above) - - uint8_t pad3[88]; - zero padding to 512-byte boundary -} +Alternatively, the header can be omitted and the dmsetup parameters can +be passed via the kernel command-line in a rooted chain of trust where +the command-line is verified. Directly following the header (and with sector number padded to the next hash block boundary) are the hash blocks which are stored a depth at a time (starting from the root), sorted in order of increasing index. +The full specification of kernel parameters and on-disk metadata format +is available at the cryptsetup project's wiki page + http://code.google.com/p/cryptsetup/wiki/DMVerity + Status ====== V (for Valid) is returned if every check performed so far was valid. @@ -174,21 +134,22 @@ If any check failed, C (for Corruption) is returned. Example ======= - -Setup a device: - dmsetup create vroot --table \ - "0 2097152 "\ - "verity 1 /dev/sda1 /dev/sda2 4096 4096 2097152 1 "\ +Set up a device: + # dmsetup create vroot --readonly --table \ + "0 2097152 verity 1 /dev/sda1 /dev/sda2 4096 4096 262144 1 sha256 "\ "4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 "\ "1234000000000000000000000000000000000000000000000000000000000000" A command line tool veritysetup is available to compute or verify -the hash tree or activate the kernel driver. This is available from -the LVM2 upstream repository and may be supplied as a package called -device-mapper-verity-tools: - git://sources.redhat.com/git/lvm2 - http://sourceware.org/git/?p=lvm2.git - http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/verity?cvsroot=lvm2 - -veritysetup -a vroot /dev/sda1 /dev/sda2 \ - 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 +the hash tree or activate the kernel device. This is available from +the cryptsetup upstream repository http://code.google.com/p/cryptsetup/ +(as a libcryptsetup extension). + +Create hash on the device: + # veritysetup format /dev/sda1 /dev/sda2 + ... + Root hash: 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 + +Activate the device: + # veritysetup create vroot /dev/sda1 /dev/sda2 \ + 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 From 672c65731d62930439b91ff8a160830085d42a51 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 3 Jul 2012 12:55:33 +0100 Subject: [PATCH 0411/2357] dm persistent data: fix shadow_info_leak on dm_tm_destroy commit 25d7cd6faa7ae6ed2565617c3ee2500ccb8a9f7f upstream. Cleanup the shadow table before destroying the transaction manager. Reference: leak was identified with kmemleak when running test_discard_random_sectors in the thinp-test-suite. Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/persistent-data/dm-transaction-manager.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c index 6f8d38747d7..e5902d1f8c1 100644 --- a/drivers/md/persistent-data/dm-transaction-manager.c +++ b/drivers/md/persistent-data/dm-transaction-manager.c @@ -138,6 +138,9 @@ EXPORT_SYMBOL_GPL(dm_tm_create_non_blocking_clone); void dm_tm_destroy(struct dm_transaction_manager *tm) { + if (!tm->is_clone) + wipe_shadow_table(tm); + kfree(tm); } EXPORT_SYMBOL_GPL(dm_tm_destroy); From 7723bfa90d8a1f75f41ade1a13b9b32c9255b15c Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 3 Jul 2012 12:55:35 +0100 Subject: [PATCH 0412/2357] dm persistent data: handle space map checker creation failure commit 62662303e7f590fdfbb0070ab820a0ad4267c119 upstream. If CONFIG_DM_DEBUG_SPACE_MAPS is enabled and dm_sm_checker_create() fails, dm_tm_create_internal() would still return success even though it cleaned up all resources it was supposed to have created. This will lead to a kernel crash: general protection fault: 0000 [#1] SMP DEBUG_PAGEALLOC ... RIP: 0010:[] [] dm_bufio_get_block_size+0x9/0x20 Call Trace: [] dm_bm_block_size+0xe/0x10 [] sm_ll_init+0x78/0xd0 [] sm_ll_new_disk+0x16/0xa0 [] dm_sm_disk_create+0xfe/0x160 [] dm_pool_metadata_open+0x16e/0x6a0 [] pool_ctr+0x3f0/0x900 [] dm_table_add_target+0x195/0x450 [] table_load+0xe4/0x330 [] ctl_ioctl+0x15a/0x2c0 [] dm_ctl_ioctl+0x13/0x20 [] do_vfs_ioctl+0x98/0x560 [] sys_ioctl+0x91/0xa0 [] system_call_fastpath+0x16/0x1b Fix the space map checker code to return an appropriate ERR_PTR and have dm_sm_disk_create() and dm_tm_create_internal() check for it with IS_ERR. Reported-by: Vivek Goyal Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- .../md/persistent-data/dm-space-map-checker.c | 24 +++++++++---------- .../md/persistent-data/dm-space-map-disk.c | 11 ++++++++- .../persistent-data/dm-transaction-manager.c | 8 +++++-- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/md/persistent-data/dm-space-map-checker.c b/drivers/md/persistent-data/dm-space-map-checker.c index 50ed53bf4aa..6d7c8329250 100644 --- a/drivers/md/persistent-data/dm-space-map-checker.c +++ b/drivers/md/persistent-data/dm-space-map-checker.c @@ -343,25 +343,25 @@ struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm) int r; struct sm_checker *smc; - if (!sm) - return NULL; + if (IS_ERR_OR_NULL(sm)) + return ERR_PTR(-EINVAL); smc = kmalloc(sizeof(*smc), GFP_KERNEL); if (!smc) - return NULL; + return ERR_PTR(-ENOMEM); memcpy(&smc->sm, &ops_, sizeof(smc->sm)); r = ca_create(&smc->old_counts, sm); if (r) { kfree(smc); - return NULL; + return ERR_PTR(r); } r = ca_create(&smc->counts, sm); if (r) { ca_destroy(&smc->old_counts); kfree(smc); - return NULL; + return ERR_PTR(r); } smc->real_sm = sm; @@ -371,7 +371,7 @@ struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm) ca_destroy(&smc->counts); ca_destroy(&smc->old_counts); kfree(smc); - return NULL; + return ERR_PTR(r); } r = ca_commit(&smc->old_counts, &smc->counts); @@ -379,7 +379,7 @@ struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm) ca_destroy(&smc->counts); ca_destroy(&smc->old_counts); kfree(smc); - return NULL; + return ERR_PTR(r); } return &smc->sm; @@ -391,25 +391,25 @@ struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm) int r; struct sm_checker *smc; - if (!sm) - return NULL; + if (IS_ERR_OR_NULL(sm)) + return ERR_PTR(-EINVAL); smc = kmalloc(sizeof(*smc), GFP_KERNEL); if (!smc) - return NULL; + return ERR_PTR(-ENOMEM); memcpy(&smc->sm, &ops_, sizeof(smc->sm)); r = ca_create(&smc->old_counts, sm); if (r) { kfree(smc); - return NULL; + return ERR_PTR(r); } r = ca_create(&smc->counts, sm); if (r) { ca_destroy(&smc->old_counts); kfree(smc); - return NULL; + return ERR_PTR(r); } smc->real_sm = sm; diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c index fc469ba9f62..3d0ed533288 100644 --- a/drivers/md/persistent-data/dm-space-map-disk.c +++ b/drivers/md/persistent-data/dm-space-map-disk.c @@ -290,7 +290,16 @@ struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm, dm_block_t nr_blocks) { struct dm_space_map *sm = dm_sm_disk_create_real(tm, nr_blocks); - return dm_sm_checker_create_fresh(sm); + struct dm_space_map *smc; + + if (IS_ERR_OR_NULL(sm)) + return sm; + + smc = dm_sm_checker_create_fresh(sm); + if (IS_ERR(smc)) + dm_sm_destroy(sm); + + return smc; } EXPORT_SYMBOL_GPL(dm_sm_disk_create); diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c index e5902d1f8c1..ba54aacf398 100644 --- a/drivers/md/persistent-data/dm-transaction-manager.c +++ b/drivers/md/persistent-data/dm-transaction-manager.c @@ -345,8 +345,10 @@ static int dm_tm_create_internal(struct dm_block_manager *bm, } *sm = dm_sm_checker_create(inner); - if (!*sm) + if (IS_ERR(*sm)) { + r = PTR_ERR(*sm); goto bad2; + } } else { r = dm_bm_write_lock(dm_tm_get_bm(*tm), sb_location, @@ -365,8 +367,10 @@ static int dm_tm_create_internal(struct dm_block_manager *bm, } *sm = dm_sm_checker_create(inner); - if (!*sm) + if (IS_ERR(*sm)) { + r = PTR_ERR(*sm); goto bad2; + } } return 0; From 6d442d8f7e1a6920aad3d3f3ea544f6f8e6898b8 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 3 Jul 2012 12:55:37 +0100 Subject: [PATCH 0413/2357] dm persistent data: fix allocation failure in space map checker init commit b0239faaf87c38bb419c9264bf20817438ddc3a9 upstream. If CONFIG_DM_DEBUG_SPACE_MAPS is enabled and memory is fragmented and a sufficiently-large metadata device is used in a thin pool then the space map checker will fail to allocate the memory it requires. Switch from kmalloc to vmalloc to allow larger virtually contiguous allocations for the space map checker's internal count arrays. Reported-by: Vivek Goyal Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- .../md/persistent-data/dm-space-map-checker.c | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/md/persistent-data/dm-space-map-checker.c b/drivers/md/persistent-data/dm-space-map-checker.c index 6d7c8329250..fc90c11620a 100644 --- a/drivers/md/persistent-data/dm-space-map-checker.c +++ b/drivers/md/persistent-data/dm-space-map-checker.c @@ -8,6 +8,7 @@ #include #include +#include #ifdef CONFIG_DM_DEBUG_SPACE_MAPS @@ -89,13 +90,23 @@ static int ca_create(struct count_array *ca, struct dm_space_map *sm) ca->nr = nr_blocks; ca->nr_free = nr_blocks; - ca->counts = kzalloc(sizeof(*ca->counts) * nr_blocks, GFP_KERNEL); - if (!ca->counts) - return -ENOMEM; + + if (!nr_blocks) + ca->counts = NULL; + else { + ca->counts = vzalloc(sizeof(*ca->counts) * nr_blocks); + if (!ca->counts) + return -ENOMEM; + } return 0; } +static void ca_destroy(struct count_array *ca) +{ + vfree(ca->counts); +} + static int ca_load(struct count_array *ca, struct dm_space_map *sm) { int r; @@ -126,12 +137,14 @@ static int ca_load(struct count_array *ca, struct dm_space_map *sm) static int ca_extend(struct count_array *ca, dm_block_t extra_blocks) { dm_block_t nr_blocks = ca->nr + extra_blocks; - uint32_t *counts = kzalloc(sizeof(*counts) * nr_blocks, GFP_KERNEL); + uint32_t *counts = vzalloc(sizeof(*counts) * nr_blocks); if (!counts) return -ENOMEM; - memcpy(counts, ca->counts, sizeof(*counts) * ca->nr); - kfree(ca->counts); + if (ca->counts) { + memcpy(counts, ca->counts, sizeof(*counts) * ca->nr); + ca_destroy(ca); + } ca->nr = nr_blocks; ca->nr_free += extra_blocks; ca->counts = counts; @@ -151,11 +164,6 @@ static int ca_commit(struct count_array *old, struct count_array *new) return 0; } -static void ca_destroy(struct count_array *ca) -{ - kfree(ca->counts); -} - /*----------------------------------------------------------------*/ struct sm_checker { From 6dfa530c0b33f1ccd2d8b103a2dea6ec559de66c Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Mon, 11 Jun 2012 09:24:11 -0700 Subject: [PATCH 0414/2357] eCryptfs: Gracefully refuse miscdev file ops on inherited/passed files commit 8dc6780587c99286c0d3de747a2946a76989414a upstream. File operations on /dev/ecryptfs would BUG() when the operations were performed by processes other than the process that originally opened the file. This could happen with open files inherited after fork() or file descriptors passed through IPC mechanisms. Rather than calling BUG(), an error code can be safely returned in most situations. In ecryptfs_miscdev_release(), eCryptfs still needs to handle the release even if the last file reference is being held by a process that didn't originally open the file. ecryptfs_find_daemon_by_euid() will not be successful, so a pointer to the daemon is stored in the file's private_data. The private_data pointer is initialized when the miscdev file is opened and only used when the file is released. https://launchpad.net/bugs/994247 Signed-off-by: Tyler Hicks Reported-by: Sasha Levin Tested-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/miscdev.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c index 3a06f4043df..2cd9c3f4440 100644 --- a/fs/ecryptfs/miscdev.c +++ b/fs/ecryptfs/miscdev.c @@ -49,7 +49,10 @@ ecryptfs_miscdev_poll(struct file *file, poll_table *pt) mutex_lock(&ecryptfs_daemon_hash_mux); /* TODO: Just use file->private_data? */ rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); - BUG_ON(rc || !daemon); + if (rc || !daemon) { + mutex_unlock(&ecryptfs_daemon_hash_mux); + return -EINVAL; + } mutex_lock(&daemon->mux); mutex_unlock(&ecryptfs_daemon_hash_mux); if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { @@ -122,6 +125,7 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) goto out_unlock_daemon; } daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN; + file->private_data = daemon; atomic_inc(&ecryptfs_num_miscdev_opens); out_unlock_daemon: mutex_unlock(&daemon->mux); @@ -152,9 +156,9 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file) mutex_lock(&ecryptfs_daemon_hash_mux); rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); - BUG_ON(rc || !daemon); + if (rc || !daemon) + daemon = file->private_data; mutex_lock(&daemon->mux); - BUG_ON(daemon->pid != task_pid(current)); BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN)); daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN; atomic_dec(&ecryptfs_num_miscdev_opens); @@ -269,8 +273,16 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, mutex_lock(&ecryptfs_daemon_hash_mux); /* TODO: Just use file->private_data? */ rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); - BUG_ON(rc || !daemon); + if (rc || !daemon) { + mutex_unlock(&ecryptfs_daemon_hash_mux); + return -EINVAL; + } mutex_lock(&daemon->mux); + if (task_pid(current) != daemon->pid) { + mutex_unlock(&daemon->mux); + mutex_unlock(&ecryptfs_daemon_hash_mux); + return -EPERM; + } if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { rc = 0; mutex_unlock(&ecryptfs_daemon_hash_mux); @@ -307,9 +319,6 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, * message from the queue; try again */ goto check_list; } - BUG_ON(euid != daemon->euid); - BUG_ON(current_user_ns() != daemon->user_ns); - BUG_ON(task_pid(current) != daemon->pid); msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue, struct ecryptfs_msg_ctx, daemon_out_list); BUG_ON(!msg_ctx); From b6d7c70709e324e074d3a69249980bba1529fd01 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Mon, 11 Jun 2012 10:21:34 -0700 Subject: [PATCH 0415/2357] eCryptfs: Fix lockdep warning in miscdev operations commit 60d65f1f07a7d81d3eb3b91fc13fca80f2fdbb12 upstream. Don't grab the daemon mutex while holding the message context mutex. Addresses this lockdep warning: ecryptfsd/2141 is trying to acquire lock: (&ecryptfs_msg_ctx_arr[i].mux){+.+.+.}, at: [] ecryptfs_miscdev_read+0x143/0x470 [ecryptfs] but task is already holding lock: (&(*daemon)->mux){+.+...}, at: [] ecryptfs_miscdev_read+0x21c/0x470 [ecryptfs] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&(*daemon)->mux){+.+...}: [] lock_acquire+0x9d/0x220 [] __mutex_lock_common+0x5a/0x4b0 [] mutex_lock_nested+0x44/0x50 [] ecryptfs_send_miscdev+0x97/0x120 [ecryptfs] [] ecryptfs_send_message+0x134/0x1e0 [ecryptfs] [] ecryptfs_generate_key_packet_set+0x2fe/0xa80 [ecryptfs] [] ecryptfs_write_metadata+0x108/0x250 [ecryptfs] [] ecryptfs_create+0x130/0x250 [ecryptfs] [] vfs_create+0xb4/0x120 [] do_last+0x8c5/0xa10 [] path_openat+0xd9/0x460 [] do_filp_open+0x42/0xa0 [] do_sys_open+0xf8/0x1d0 [] sys_open+0x21/0x30 [] system_call_fastpath+0x16/0x1b -> #0 (&ecryptfs_msg_ctx_arr[i].mux){+.+.+.}: [] __lock_acquire+0x1bf8/0x1c50 [] lock_acquire+0x9d/0x220 [] __mutex_lock_common+0x5a/0x4b0 [] mutex_lock_nested+0x44/0x50 [] ecryptfs_miscdev_read+0x143/0x470 [ecryptfs] [] vfs_read+0xb3/0x180 [] sys_read+0x4d/0x90 [] system_call_fastpath+0x16/0x1b Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/miscdev.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c index 2cd9c3f4440..c0038f6566d 100644 --- a/fs/ecryptfs/miscdev.c +++ b/fs/ecryptfs/miscdev.c @@ -195,31 +195,32 @@ int ecryptfs_send_miscdev(char *data, size_t data_size, struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type, u16 msg_flags, struct ecryptfs_daemon *daemon) { - int rc = 0; + struct ecryptfs_message *msg; - mutex_lock(&msg_ctx->mux); - msg_ctx->msg = kmalloc((sizeof(*msg_ctx->msg) + data_size), - GFP_KERNEL); - if (!msg_ctx->msg) { - rc = -ENOMEM; + msg = kmalloc((sizeof(*msg) + data_size), GFP_KERNEL); + if (!msg) { printk(KERN_ERR "%s: Out of memory whilst attempting " "to kmalloc(%zd, GFP_KERNEL)\n", __func__, - (sizeof(*msg_ctx->msg) + data_size)); - goto out_unlock; + (sizeof(*msg) + data_size)); + return -ENOMEM; } + + mutex_lock(&msg_ctx->mux); + msg_ctx->msg = msg; msg_ctx->msg->index = msg_ctx->index; msg_ctx->msg->data_len = data_size; msg_ctx->type = msg_type; memcpy(msg_ctx->msg->data, data, data_size); msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size); - mutex_lock(&daemon->mux); list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue); + mutex_unlock(&msg_ctx->mux); + + mutex_lock(&daemon->mux); daemon->num_queued_msg_ctx++; wake_up_interruptible(&daemon->wait); mutex_unlock(&daemon->mux); -out_unlock: - mutex_unlock(&msg_ctx->mux); - return rc; + + return 0; } /* From b6855f6d78cee5d72adc8f07be2646dd83c171c3 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 12 Jun 2012 11:17:01 -0700 Subject: [PATCH 0416/2357] eCryptfs: Properly check for O_RDONLY flag before doing privileged open commit 9fe79d7600497ed8a95c3981cbe5b73ab98222f0 upstream. If the first attempt at opening the lower file read/write fails, eCryptfs will retry using a privileged kthread. However, the privileged retry should not happen if the lower file's inode is read-only because a read/write open will still be unsuccessful. The check for determining if the open should be retried was intended to be based on the access mode of the lower file's open flags being O_RDONLY, but the check was incorrectly performed. This would cause the open to be retried by the privileged kthread, resulting in a second failed open of the lower file. This patch corrects the check to determine if the open request should be handled by the privileged kthread. Signed-off-by: Tyler Hicks Reported-by: Dan Carpenter Acked-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/kthread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c index 69f994a7d52..0dbe58a8b17 100644 --- a/fs/ecryptfs/kthread.c +++ b/fs/ecryptfs/kthread.c @@ -149,7 +149,7 @@ int ecryptfs_privileged_open(struct file **lower_file, (*lower_file) = dentry_open(lower_dentry, lower_mnt, flags, cred); if (!IS_ERR(*lower_file)) goto out; - if (flags & O_RDONLY) { + if ((flags & O_ACCMODE) == O_RDONLY) { rc = PTR_ERR((*lower_file)); goto out; } From 40e0484473ac43b557796c9f392c2cb69b1f55ae Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 29 May 2012 15:06:50 -0700 Subject: [PATCH 0417/2357] mm/memblock: cleanup on duplicate VA/PA conversion commit 4e2f07750d9a94e8f23e86408df5ab95be88bf11 upstream. The overall memblock has been organized into the memory regions and reserved regions. Initially, the memory regions and reserved regions are stored in the predetermined arrays of "struct memblock _region". It's possible for the arrays to be enlarged when we have newly added regions for them, but no enough space there. Under the situation, We will created double-sized array to meet the requirement. However, the original implementation converted the VA (Virtual Address) of the newly allocated array of regions to PA (Physical Address), then translate back when we allocates the new array from slab. That's actually unnecessary. The patch removes the duplicate VA/PA conversion. Signed-off-by: Gavin Shan Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memblock.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index a44eab3157f..eae06ea3aa5 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -212,14 +212,15 @@ static int __init_memblock memblock_double_array(struct memblock_type *type) if (use_slab) { new_array = kmalloc(new_size, GFP_KERNEL); addr = new_array ? __pa(new_array) : 0; - } else + } else { addr = memblock_find_in_range(0, MEMBLOCK_ALLOC_ACCESSIBLE, new_size, sizeof(phys_addr_t)); + new_array = addr ? __va(addr) : 0; + } if (!addr) { pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n", memblock_type_name(type), type->max, type->max * 2); return -1; } - new_array = __va(addr); memblock_dbg("memblock: %s array is doubled to %ld at [%#010llx-%#010llx]", memblock_type_name(type), type->max * 2, (u64)addr, (u64)addr + new_size - 1); From 659586507ac1f4219d1b2f2d471381e39f7e6961 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 29 May 2012 15:06:50 -0700 Subject: [PATCH 0418/2357] mm/memblock: fix memory leak on extending regions commit 181eb39425f2b9275afcb015eaa547d11f71a02f upstream. The overall memblock has been organized into the memory regions and reserved regions. Initially, the memory regions and reserved regions are stored in the predetermined arrays of "struct memblock _region". It's possible for the arrays to be enlarged when we have newly added regions, but no free space left there. The policy here is to create double-sized array either by slab allocator or memblock allocator. Unfortunately, we didn't free the old array, which might be allocated through slab allocator before. That would cause memory leak. The patch introduces 2 variables to trace where (slab or memblock) the memory and reserved regions come from. The memory for the memory or reserved regions will be deallocated by kfree() if that was allocated by slab allocator. Thus to fix the memory leak issue. Signed-off-by: Gavin Shan Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memblock.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index eae06ea3aa5..952123eba43 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -37,6 +37,8 @@ struct memblock memblock __initdata_memblock = { int memblock_debug __initdata_memblock; static int memblock_can_resize __initdata_memblock; +static int memblock_memory_in_slab __initdata_memblock = 0; +static int memblock_reserved_in_slab __initdata_memblock = 0; /* inline so we don't get a warning when pr_debug is compiled out */ static inline const char *memblock_type_name(struct memblock_type *type) @@ -187,6 +189,7 @@ static int __init_memblock memblock_double_array(struct memblock_type *type) struct memblock_region *new_array, *old_array; phys_addr_t old_size, new_size, addr; int use_slab = slab_is_available(); + int *in_slab; /* We don't allow resizing until we know about the reserved regions * of memory that aren't suitable for allocation @@ -198,6 +201,12 @@ static int __init_memblock memblock_double_array(struct memblock_type *type) old_size = type->max * sizeof(struct memblock_region); new_size = old_size << 1; + /* Retrieve the slab flag */ + if (type == &memblock.memory) + in_slab = &memblock_memory_in_slab; + else + in_slab = &memblock_reserved_in_slab; + /* Try to find some space for it. * * WARNING: We assume that either slab_is_available() and we use it or @@ -235,22 +244,24 @@ static int __init_memblock memblock_double_array(struct memblock_type *type) type->regions = new_array; type->max <<= 1; - /* If we use SLAB that's it, we are done */ - if (use_slab) - return 0; - - /* Add the new reserved region now. Should not fail ! */ - BUG_ON(memblock_reserve(addr, new_size)); - - /* If the array wasn't our static init one, then free it. We only do - * that before SLAB is available as later on, we don't know whether - * to use kfree or free_bootmem_pages(). Shouldn't be a big deal - * anyways + /* Free old array. We needn't free it if the array is the + * static one */ - if (old_array != memblock_memory_init_regions && - old_array != memblock_reserved_init_regions) + if (*in_slab) + kfree(old_array); + else if (old_array != memblock_memory_init_regions && + old_array != memblock_reserved_init_regions) memblock_free(__pa(old_array), old_size); + /* Reserve the new array if that comes from the memblock. + * Otherwise, we needn't do it + */ + if (!use_slab) + BUG_ON(memblock_reserve(addr, new_size)); + + /* Update slab flag */ + *in_slab = use_slab; + return 0; } From 757fcf2b6df4814604764a4abb54d2b58f422fb5 Mon Sep 17 00:00:00 2001 From: Greg Pearson Date: Wed, 20 Jun 2012 12:53:05 -0700 Subject: [PATCH 0419/2357] mm/memblock: fix overlapping allocation when doubling reserved array commit 48c3b583bbddad2220ca4c22319ca5d1f78b2090 upstream. __alloc_memory_core_early() asks memblock for a range of memory then try to reserve it. If the reserved region array lacks space for the new range, memblock_double_array() is called to allocate more space for the array. If memblock is used to allocate memory for the new array it can end up using a range that overlaps with the range originally allocated in __alloc_memory_core_early(), leading to possible data corruption. With this patch memblock_double_array() now calls memblock_find_in_range() with a narrowed candidate range (in cases where the reserved.regions array is being doubled) so any memory allocated will not overlap with the original range that was being reserved. The range is narrowed by passing in the starting address and size of the previously allocated range. Then the range above the ending address is searched and if a candidate is not found, the range below the starting address is searched. Signed-off-by: Greg Pearson Signed-off-by: Yinghai Lu Acked-by: Tejun Heo Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memblock.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index 952123eba43..0e737d9ab2b 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -184,7 +184,24 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u } } -static int __init_memblock memblock_double_array(struct memblock_type *type) +/** + * memblock_double_array - double the size of the memblock regions array + * @type: memblock type of the regions array being doubled + * @new_area_start: starting address of memory range to avoid overlap with + * @new_area_size: size of memory range to avoid overlap with + * + * Double the size of the @type regions array. If memblock is being used to + * allocate memory for a new reserved regions array and there is a previously + * allocated memory range [@new_area_start,@new_area_start+@new_area_size] + * waiting to be reserved, ensure the memory used by the new array does + * not overlap. + * + * RETURNS: + * 0 on success, -1 on failure. + */ +static int __init_memblock memblock_double_array(struct memblock_type *type, + phys_addr_t new_area_start, + phys_addr_t new_area_size) { struct memblock_region *new_array, *old_array; phys_addr_t old_size, new_size, addr; @@ -222,7 +239,18 @@ static int __init_memblock memblock_double_array(struct memblock_type *type) new_array = kmalloc(new_size, GFP_KERNEL); addr = new_array ? __pa(new_array) : 0; } else { - addr = memblock_find_in_range(0, MEMBLOCK_ALLOC_ACCESSIBLE, new_size, sizeof(phys_addr_t)); + /* only exclude range when trying to double reserved.regions */ + if (type != &memblock.reserved) + new_area_start = new_area_size = 0; + + addr = memblock_find_in_range(new_area_start + new_area_size, + memblock.current_limit, + new_size, sizeof(phys_addr_t)); + if (!addr && new_area_size) + addr = memblock_find_in_range(0, + min(new_area_start, memblock.current_limit), + new_size, sizeof(phys_addr_t)); + new_array = addr ? __va(addr) : 0; } if (!addr) { @@ -399,7 +427,7 @@ static int __init_memblock memblock_add_region(struct memblock_type *type, */ if (!insert) { while (type->cnt + nr_new > type->max) - if (memblock_double_array(type) < 0) + if (memblock_double_array(type, obase, size) < 0) return -ENOMEM; insert = true; goto repeat; @@ -450,7 +478,7 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type, /* we'll create at most two more regions */ while (type->cnt + 2 > type->max) - if (memblock_double_array(type) < 0) + if (memblock_double_array(type, base, size) < 0) return -ENOMEM; for (i = 0; i < type->cnt; i++) { From f33f0eaff50112270a9e629569729ce5d5d620fa Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 15 May 2012 15:31:01 +0300 Subject: [PATCH 0420/2357] OMAPDSS: use DSI_FIFO_BUG workaround only for manual update displays commit 3568f2a46f2a73bab18c914df06afd98a97e0e0e upstream. There is a problem related to DSS FIFO thresholds and power management on OMAP3. It seems that when the full PM hits in, we get underflows. The core reason is unknown, but after experiments it looks like only particular FIFO thresholds work correctly. This bug is related to an earlier patch, which added special FIFO threshold configuration for OMAP3, because DSI command mode output didn't work with the normal threshold configuration. However, as the above work-around worked fine for other output types also, we currently always configure thresholds in this special way on OMAP3. In theory there should be negligible difference with this special way and the standard way. The first paragraph explains what happens in practice. This patch changes the driver to use the special threshold configuration only when the output is a manual update display on OMAP3. This does include RFBI displays also, and although it hasn't been tested (no boards using RFBI) I suspect the similar behaviour is present there also, as the DISPC side should work similarly for DSI command mode and RFBI. Signed-off-by: Tomi Valkeinen Cc: Joe Woodward Signed-off-by: Greg Kroah-Hartman --- drivers/video/omap2/dss/apply.c | 2 +- drivers/video/omap2/dss/dispc.c | 5 +++-- drivers/video/omap2/dss/dss.h | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index b10b3bc1931..cb19af2d6da 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -927,7 +927,7 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl, dssdev = ovl->manager->device; dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high, - use_fifo_merge); + use_fifo_merge, ovl_manual_update(ovl)); dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); } diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index ee30937482e..c4d0e445f41 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1063,7 +1063,8 @@ void dispc_enable_fifomerge(bool enable) } void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, - u32 *fifo_low, u32 *fifo_high, bool use_fifomerge) + u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, + bool manual_update) { /* * All sizes are in bytes. Both the buffer and burst are made of @@ -1091,7 +1092,7 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, * combined fifo size */ - if (dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { + if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { *fifo_low = ovl_fifo_size - burst_size * 2; *fifo_high = total_fifo_size - burst_size; } else { diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index d4b3dff2ead..d0638da92a9 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -424,7 +424,8 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, - u32 *fifo_low, u32 *fifo_high, bool use_fifomerge); + u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, + bool manual_update); int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, bool ilace, bool replication); int dispc_ovl_enable(enum omap_plane plane, bool enable); From e831cf2d290e1ecf7825d2ecfabeb0d6733b133d Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Sat, 26 May 2012 06:08:48 +0000 Subject: [PATCH 0421/2357] e1000e: test for valid check_reset_block function pointer commit 470a54207ccf7045a59df727573bd9d148988582 upstream. commit 44abd5c12767a8c567dc4e45fd9aec3b13ca85e0 introduced NULL pointer dereferences when attempting to access the check_reset_block function pointer on 8257x and 80003es2lan non-copper devices. This fix should be applied back through 3.4. Signed-off-by: Bruce Allan Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher Acked-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/ethtool.c | 6 ++++-- drivers/net/ethernet/intel/e1000e/mac.c | 2 +- drivers/net/ethernet/intel/e1000e/netdev.c | 4 ++-- drivers/net/ethernet/intel/e1000e/phy.c | 8 +++++--- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index db35dd5d96d..e48f2d2665c 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -258,7 +258,8 @@ static int e1000_set_settings(struct net_device *netdev, * When SoL/IDER sessions are active, autoneg/speed/duplex * cannot be changed */ - if (hw->phy.ops.check_reset_block(hw)) { + if (hw->phy.ops.check_reset_block && + hw->phy.ops.check_reset_block(hw)) { e_err("Cannot change link characteristics when SoL/IDER is " "active.\n"); return -EINVAL; @@ -1604,7 +1605,8 @@ static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data) * PHY loopback cannot be performed if SoL/IDER * sessions are active */ - if (hw->phy.ops.check_reset_block(hw)) { + if (hw->phy.ops.check_reset_block && + hw->phy.ops.check_reset_block(hw)) { e_err("Cannot do PHY loopback test when SoL/IDER is active.\n"); *data = 0; goto out; diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index decad98c105..efecb509fcd 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -709,7 +709,7 @@ s32 e1000e_setup_link_generic(struct e1000_hw *hw) * In the case of the phy reset being blocked, we already have a link. * We do not need to set it up again. */ - if (hw->phy.ops.check_reset_block(hw)) + if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw)) return 0; /* diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index a87e84f36bc..5621d5b2876 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6209,7 +6209,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->hw.phy.ms_type = e1000_ms_hw_default; } - if (hw->phy.ops.check_reset_block(hw)) + if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw)) e_info("PHY reset is blocked due to SOL/IDER session.\n"); /* Set initial default active device features */ @@ -6376,7 +6376,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, if (!(adapter->flags & FLAG_HAS_AMT)) e1000e_release_hw_control(adapter); err_eeprom: - if (!hw->phy.ops.check_reset_block(hw)) + if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw)) e1000_phy_hw_reset(&adapter->hw); err_hw_init: kfree(adapter->tx_ring); diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c index 35b45578c60..c4befb3dd26 100644 --- a/drivers/net/ethernet/intel/e1000e/phy.c +++ b/drivers/net/ethernet/intel/e1000e/phy.c @@ -2121,9 +2121,11 @@ s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw) s32 ret_val; u32 ctrl; - ret_val = phy->ops.check_reset_block(hw); - if (ret_val) - return 0; + if (phy->ops.check_reset_block) { + ret_val = phy->ops.check_reset_block(hw); + if (ret_val) + return 0; + } ret_val = phy->ops.acquire(hw); if (ret_val) From 099fddaa7a49187a9405cb05c6373814884dfcff Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 4 May 2012 14:53:46 +0200 Subject: [PATCH 0422/2357] HID: hid-multitouch: fix wrong protocol detection commit 3ac36d15557d1bedfb1151d9911b9587b2d40759 upstream. The previous implementation introduced a randomness in the splitting of the different touches reported by the device. This version is more robust as we don't rely on hi->input->absbit, but on our own structure. This also prepares hid-multitouch to better support Win8 devices. [Jiri Kosina : fix build] Signed-off-by: Benjamin Tissoires Acked-by: Henrik Rydberg Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-multitouch.c | 58 ++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 1d5b94167b5..543896dfc49 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -70,9 +70,16 @@ struct mt_class { bool is_indirect; /* true for touchpads */ }; +struct mt_fields { + unsigned usages[HID_MAX_FIELDS]; + unsigned int length; +}; + struct mt_device { struct mt_slot curdata; /* placeholder of incoming data */ struct mt_class mtclass; /* our mt device class */ + struct mt_fields *fields; /* temporary placeholder for storing the + multitouch fields */ unsigned last_field_index; /* last field index of the report */ unsigned last_slot_field; /* the last field of a slot */ __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ @@ -275,11 +282,15 @@ static void set_abs(struct input_dev *input, unsigned int code, input_set_abs_params(input, code, fmin, fmax, fuzz, 0); } -static void set_last_slot_field(struct hid_usage *usage, struct mt_device *td, +static void mt_store_field(struct hid_usage *usage, struct mt_device *td, struct hid_input *hi) { - if (!test_bit(usage->hid, hi->input->absbit)) - td->last_slot_field = usage->hid; + struct mt_fields *f = td->fields; + + if (f->length >= HID_MAX_FIELDS) + return; + + f->usages[f->length++] = usage->hid; } static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, @@ -330,7 +341,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_X, field, cls->sn_move); - set_last_slot_field(usage, td, hi); + mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_GD_Y: @@ -340,7 +351,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_Y, field, cls->sn_move); - set_last_slot_field(usage, td, hi); + mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; } @@ -349,24 +360,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_UP_DIGITIZER: switch (usage->hid) { case HID_DG_INRANGE: - set_last_slot_field(usage, td, hi); + mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_CONFIDENCE: - set_last_slot_field(usage, td, hi); + mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_TIPSWITCH: hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); input_set_capability(hi->input, EV_KEY, BTN_TOUCH); - set_last_slot_field(usage, td, hi); + mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_CONTACTID: if (!td->maxcontacts) td->maxcontacts = MT_DEFAULT_MAXCONTACT; input_mt_init_slots(hi->input, td->maxcontacts); - td->last_slot_field = usage->hid; + mt_store_field(usage, td, hi); td->last_field_index = field->index; td->touches_by_report++; return 1; @@ -375,7 +386,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_TOUCH_MAJOR); set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); - set_last_slot_field(usage, td, hi); + mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_HEIGHT: @@ -385,7 +396,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_height); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); - set_last_slot_field(usage, td, hi); + mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_TIPPRESSURE: @@ -396,7 +407,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, /* touchscreen emulation */ set_abs(hi->input, ABS_PRESSURE, field, cls->sn_pressure); - set_last_slot_field(usage, td, hi); + mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_CONTACTCOUNT: @@ -635,6 +646,16 @@ static void mt_set_maxcontacts(struct hid_device *hdev) } } +static void mt_post_parse(struct mt_device *td) +{ + struct mt_fields *f = td->fields; + + if (td->touches_by_report > 0) { + int field_count_per_touch = f->length / td->touches_by_report; + td->last_slot_field = f->usages[field_count_per_touch - 1]; + } +} + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; @@ -666,6 +687,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->maxcontact_report_id = -1; hid_set_drvdata(hdev, td); + td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL); + if (!td->fields) { + dev_err(&hdev->dev, "cannot allocate multitouch fields data\n"); + ret = -ENOMEM; + goto fail; + } + ret = hid_parse(hdev); if (ret != 0) goto fail; @@ -674,6 +702,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) goto fail; + mt_post_parse(td); + if (!id && td->touches_by_report == 1) { /* the device has been sent by hid-generic */ mtclass = &td->mtclass; @@ -697,9 +727,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) mt_set_maxcontacts(hdev); mt_set_input_mode(hdev); + kfree(td->fields); + td->fields = NULL; + return 0; fail: + kfree(td->fields); kfree(td); return ret; } From 7c2c0261ce56126b72fbff0d67d9b1ac06f3c971 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 29 May 2012 21:21:07 +0200 Subject: [PATCH 0423/2357] ACPI / PM: Make acpi_pm_device_sleep_state() follow the specification commit dbe9a2edd17d843d80faf2b99f20a691c1853418 upstream. The comparison between the system sleep state being entered and the lowest system sleep state the given device may wake up from in acpi_pm_device_sleep_state() is reversed, because the specification (ACPI 5.0) says that for wakeup to work: "The sleeping state being entered must be less than or equal to the power state declared in element 1 of the _PRW object." In other words, the state returned by _PRW is the deepest (lowest-power) system sleep state the device is capable of waking up the system from. Moreover, acpi_pm_device_sleep_state() also should check if the wakeup capability is supported through ACPI, because in principle it may be done via native PCIe PME, for example, in which case _SxW should not be evaluated. Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/sleep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index eb6fd233764..2377445f4a3 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -732,8 +732,8 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) * can wake the system. _S0W may be valid, too. */ if (acpi_target_sleep_state == ACPI_STATE_S0 || - (device_may_wakeup(dev) && - adev->wakeup.sleep_state <= acpi_target_sleep_state)) { + (device_may_wakeup(dev) && adev->wakeup.flags.valid && + adev->wakeup.sleep_state >= acpi_target_sleep_state)) { acpi_status status; acpi_method[3] = 'W'; From 5a89aae8085ef69a2ea9034ff8f5624327cd4efc Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Thu, 21 Jun 2012 12:23:42 -0700 Subject: [PATCH 0424/2357] SCSI: Fix NULL dereferences in scsi_cmd_to_driver commit 222a806af830fda34ad1f6bc991cd226916de060 upstream. Avoid crashing if the private_data pointer happens to be NULL. This has been seen sometimes when a host reset happens, notably when there are many LUNs: host3: Assigned Port ID 0c1601 scsi host3: libfc: Host reset succeeded on port (0c1601) BUG: unable to handle kernel NULL pointer dereference at 0000000000000350 IP: [] scsi_send_eh_cmnd+0x58/0x3a0 Process scsi_eh_3 (pid: 4144, threadinfo ffff88030920c000, task ffff880326b160c0) Stack: 000000010372e6ba 0000000000000282 000027100920dca0 ffffffffa0038ee0 0000000000000000 0000000000030003 ffff88030920dc80 ffff88030920dc80 00000002000e0000 0000000a00004000 ffff8803242f7760 ffff88031326ed80 Call Trace: [] ? lock_timer_base+0x70/0x70 [] scsi_eh_tur+0x3e/0xc0 [] scsi_eh_test_devices+0x76/0x170 [] scsi_eh_host_reset+0x85/0x160 [] scsi_eh_ready_devs+0x91/0x110 [] scsi_unjam_host+0xed/0x1f0 [] scsi_error_handler+0x1a8/0x200 [] ? scsi_unjam_host+0x1f0/0x1f0 [] kthread+0x9e/0xb0 [] kernel_thread_helper+0x4/0x10 [] ? kthread_freezable_should_stop+0x70/0x70 [] ? gs_change+0x13/0x13 Code: 25 28 00 00 00 48 89 45 c8 31 c0 48 8b 87 80 00 00 00 48 8d b5 60 ff ff ff 89 d1 48 89 fb 41 89 d6 4c 89 fa 48 8b 80 b8 00 00 00 <48> 8b 80 50 03 00 00 48 8b 00 48 89 85 38 ff ff ff 48 8b 07 4c RIP [] scsi_send_eh_cmnd+0x58/0x3a0 RSP CR2: 0000000000000350 Signed-off-by: Mark Rustad Tested-by: Marcus Dennis Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- include/scsi/scsi_cmnd.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 1e1198546c7..ac06cc59589 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -134,10 +134,16 @@ struct scsi_cmnd { static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) { + struct scsi_driver **sdp; + if (!cmd->request->rq_disk) return NULL; - return *(struct scsi_driver **)cmd->request->rq_disk->private_data; + sdp = (struct scsi_driver **)cmd->request->rq_disk->private_data; + if (!sdp) + return NULL; + + return *sdp; } extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); From 76c6b958de9e72947ef08b1c9509f094c34abd8f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Jun 2012 10:52:34 -0700 Subject: [PATCH 0425/2357] SCSI: libsas: fix taskfile corruption in sas_ata_qc_fill_rtf commit 6ef1b512f4e6f936d89aa20be3d97a7ec7c290ac upstream. fill_result_tf() grabs the taskfile flags from the originating qc which sas_ata_qc_fill_rtf() promptly overwrites. The presence of an ata_taskfile in the sata_device makes it tempting to just copy the full contents in sas_ata_qc_fill_rtf(). However, libata really only wants the fis contents and expects the other portions of the taskfile to not be touched by ->qc_fill_rtf. To that end store a fis buffer in the sata_device and use ata_tf_from_fis() like every other ->qc_fill_rtf() implementation. Reported-by: Praveen Murali Tested-by: Praveen Murali Signed-off-by: Dan Williams Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/aic94xx/aic94xx_task.c | 2 +- drivers/scsi/libsas/sas_ata.c | 12 ++++++------ include/scsi/libsas.h | 6 ++++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index 532d212b6b2..393e7ce8e95 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -201,7 +201,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb, if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { resp->frame_len = le16_to_cpu(*(__le16 *)(r+6)); - memcpy(&resp->ending_fis[0], r+16, 24); + memcpy(&resp->ending_fis[0], r+16, ATA_RESP_FIS_SIZE); ts->buf_valid_size = sizeof(*resp); } } diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 441d88ad99a..d109cc3a17b 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -139,12 +139,12 @@ static void sas_ata_task_done(struct sas_task *task) if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || ((stat->stat == SAM_STAT_CHECK_CONDITION && dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { - ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf); + memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE); if (!link->sactive) { - qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command); + qc->err_mask |= ac_err_mask(dev->sata_dev.fis[2]); } else { - link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.tf.command); + link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]); if (unlikely(link->eh_info.err_mask)) qc->flags |= ATA_QCFLAG_FAILED; } @@ -161,8 +161,8 @@ static void sas_ata_task_done(struct sas_task *task) qc->flags |= ATA_QCFLAG_FAILED; } - dev->sata_dev.tf.feature = 0x04; /* status err */ - dev->sata_dev.tf.command = ATA_ERR; + dev->sata_dev.fis[3] = 0x04; /* status err */ + dev->sata_dev.fis[2] = ATA_ERR; } } @@ -269,7 +269,7 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) { struct domain_device *dev = qc->ap->private_data; - memcpy(&qc->result_tf, &dev->sata_dev.tf, sizeof(qc->result_tf)); + ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf); return true; } diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index f4f1c96dca7..10ce74f589c 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -163,6 +163,8 @@ enum ata_command_set { ATAPI_COMMAND_SET = 1, }; +#define ATA_RESP_FIS_SIZE 24 + struct sata_device { enum ata_command_set command_set; struct smp_resp rps_resp; /* report_phy_sata_resp */ @@ -171,7 +173,7 @@ struct sata_device { struct ata_port *ap; struct ata_host ata_host; - struct ata_taskfile tf; + u8 fis[ATA_RESP_FIS_SIZE]; }; enum { @@ -537,7 +539,7 @@ enum exec_status { */ struct ata_task_resp { u16 frame_len; - u8 ending_fis[24]; /* dev to host or data-in */ + u8 ending_fis[ATA_RESP_FIS_SIZE]; /* dev to host or data-in */ }; #define SAS_STATUS_BUF_SIZE 96 From d63d3985914e19816e9c19faab7abe336d80be89 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Sun, 8 Jul 2012 21:55:14 +0200 Subject: [PATCH 0426/2357] ACPI / PM: Leave Bus Master Arbitration enabled for suspend/resume commit dc332fdf9f373a87b1e2f423b5b004b2a3c37e1a upstream. This is an old suspend/resume lockup fix: commit 2780cc4660e1 Author: Len Brown Date: Thu Dec 23 13:43:30 2004 -0500 [ACPI] Fix suspend/resume lockup issue by leaving Bus Master Arbitration enabled. The ACPI spec mandates it be disabled only for C3. http://bugzilla.kernel.org/show_bug.cgi?id=3599 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown The bug snuck back in in commit 2feec47d4c5f (ACPICA: ACPI 5: Support for new FADT SleepStatus, SleepControl registers, 2012-02-14), presumably by copy/pasting a copy of the code without that fix for the legacy case. On affected machines, after that commit, the machine locks up hard on resume from suspend. The same fix as seven years ago still works. Addresses . Reported-bisected-and-tested-by: Octavio Alvarez Reported-by: Adrian Knoth Signed-off-by: Jonathan Nieder Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpica/hwsleep.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 0ed85cac323..615996a36be 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -95,18 +95,6 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags) return_ACPI_STATUS(status); } - if (sleep_state != ACPI_STATE_S5) { - /* - * Disable BM arbitration. This feature is contained within an - * optional register (PM2 Control), so ignore a BAD_ADDRESS - * exception. - */ - status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); - if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) { - return_ACPI_STATUS(status); - } - } - /* * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs @@ -364,16 +352,6 @@ acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags) [ACPI_EVENT_POWER_BUTTON]. status_register_id, ACPI_CLEAR_STATUS); - /* - * Enable BM arbitration. This feature is contained within an - * optional register (PM2 Control), so ignore a BAD_ADDRESS - * exception. - */ - status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); - if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) { - return_ACPI_STATUS(status); - } - acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING); return_ACPI_STATUS(status); } From b46b5ba5e79e61732af41dde4a9fd302a5f3184d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 2 Jul 2012 12:34:24 +0200 Subject: [PATCH 0427/2357] USB: metro-usb: fix tty_flip_buffer_push use commit b7d28e32c93801d60c1a7a817f774a02b7bdde43 upstream. Do not set low_latency flag at open as tty_flip_buffer_push must not be called in IRQ context with low_latency set. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/metro-usb.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 08d16e8c002..7c14671d6bd 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -171,14 +171,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) metro_priv->throttled = 0; spin_unlock_irqrestore(&metro_priv->lock, flags); - /* - * Force low_latency on so that our tty_push actually forces the data - * through, otherwise it is scheduled, and with high data rates (like - * with OHCI) data can get lost. - */ - if (tty) - tty->low_latency = 1; - /* Clear the urb pipe. */ usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe); From b80f6db790f07c06e35bb56b1e682df1e09e2865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 2 Jul 2012 10:33:14 +0200 Subject: [PATCH 0428/2357] USB: cdc-wdm: fix lockup on error in wdm_read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b086b6b10d9f182cd8d2f0dcfd7fd11edba93fc9 upstream. Clear the WDM_READ flag on empty reads to avoid running forever in an infinite tight loop, causing lockups: Jul 1 21:58:11 nemi kernel: [ 3658.898647] qmi_wwan 2-1:1.2: Unexpected error -71 Jul 1 21:58:36 nemi kernel: [ 3684.072021] BUG: soft lockup - CPU#0 stuck for 23s! [qmi.pl:12235] Jul 1 21:58:36 nemi kernel: [ 3684.072212] CPU 0 Jul 1 21:58:36 nemi kernel: [ 3684.072355] Jul 1 21:58:36 nemi kernel: [ 3684.072367] Pid: 12235, comm: qmi.pl Tainted: P O 3.5.0-rc2+ #13 LENOVO 2776LEG/2776LEG Jul 1 21:58:36 nemi kernel: [ 3684.072383] RIP: 0010:[] [] spin_unlock_irq+0x8/0xc [cdc_wdm] Jul 1 21:58:36 nemi kernel: [ 3684.072388] RSP: 0018:ffff88022dca1e70 EFLAGS: 00000282 Jul 1 21:58:36 nemi kernel: [ 3684.072393] RAX: ffff88022fc3f650 RBX: ffffffff811c56f7 RCX: 00000001000ce8c1 Jul 1 21:58:36 nemi kernel: [ 3684.072398] RDX: 0000000000000010 RSI: 000000000267d810 RDI: ffff88022fc3f650 Jul 1 21:58:36 nemi kernel: [ 3684.072403] RBP: ffff88022dca1eb0 R08: ffffffffa063578e R09: 0000000000000000 Jul 1 21:58:36 nemi kernel: [ 3684.072407] R10: 0000000000000008 R11: 0000000000000246 R12: 0000000000000002 Jul 1 21:58:36 nemi kernel: [ 3684.072412] R13: 0000000000000246 R14: ffffffff00000002 R15: ffff8802281d8c88 Jul 1 21:58:36 nemi kernel: [ 3684.072418] FS: 00007f666a260700(0000) GS:ffff88023bc00000(0000) knlGS:0000000000000000 Jul 1 21:58:36 nemi kernel: [ 3684.072423] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 Jul 1 21:58:36 nemi kernel: [ 3684.072428] CR2: 000000000270d9d8 CR3: 000000022e865000 CR4: 00000000000007f0 Jul 1 21:58:36 nemi kernel: [ 3684.072433] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 Jul 1 21:58:36 nemi kernel: [ 3684.072438] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Jul 1 21:58:36 nemi kernel: [ 3684.072444] Process qmi.pl (pid: 12235, threadinfo ffff88022dca0000, task ffff88022ff76380) Jul 1 21:58:36 nemi kernel: [ 3684.072448] Stack: Jul 1 21:58:36 nemi kernel: [ 3684.072458] ffffffffa063592e 0000000100020000 ffff88022fc3f650 ffff88022fc3f6a8 Jul 1 21:58:36 nemi kernel: [ 3684.072466] 0000000000000200 0000000100000000 000000000267d810 0000000000000000 Jul 1 21:58:36 nemi kernel: [ 3684.072475] 0000000000000000 ffff880212cfb6d0 0000000000000200 ffff880212cfb6c0 Jul 1 21:58:36 nemi kernel: [ 3684.072479] Call Trace: Jul 1 21:58:36 nemi kernel: [ 3684.072489] [] ? wdm_read+0x1a0/0x263 [cdc_wdm] Jul 1 21:58:36 nemi kernel: [ 3684.072500] [] ? vfs_read+0xa1/0xfb Jul 1 21:58:36 nemi kernel: [ 3684.072509] [] ? alarm_setitimer+0x35/0x64 Jul 1 21:58:36 nemi kernel: [ 3684.072517] [] ? sys_read+0x45/0x6e Jul 1 21:58:36 nemi kernel: [ 3684.072525] [] ? system_call_fastpath+0x16/0x1b Jul 1 21:58:36 nemi kernel: [ 3684.072557] Code: <66> 66 90 c3 83 ff ed 89 f8 74 16 7f 06 83 ff a1 75 0a c3 83 ff f4 The WDM_READ flag is normally cleared by wdm_int_callback before resubmitting the read urb, and set by wdm_in_callback when this urb returns with data or an error. But a crashing device may cause both a read error and cancelling all urbs. Make sure that the flag is cleared by wdm_read if the buffer is empty. We don't clear the flag on errors, as there may be pending data in the buffer which should be processed. The flag will instead be cleared on the next wdm_read call. Signed-off-by: Bjørn Mork Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 83d14bfc2b2..01d247e8808 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -497,6 +497,8 @@ static ssize_t wdm_read goto retry; } if (!desc->reslength) { /* zero length read */ + dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); + clear_bit(WDM_READ, &desc->flags); spin_unlock_irq(&desc->iuspin); goto retry; } From 62e4449435b38fbb423f53de5731a18c4d8ddc54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 2 Jul 2012 19:53:55 +0200 Subject: [PATCH 0429/2357] USB: option: add ZTE MF60 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8e16e33c168a6efd0c9f7fa9dd4c1e1db9a74553 upstream. Switches into a composite device by ejecting the initial driver CD. The four interfaces are: QCDM, AT, QMI/wwan and mass storage. Let this driver manage the two serial interfaces: T: Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 28 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=19d2 ProdID=1402 Rev= 0.00 S: Manufacturer=ZTE,Incorporated S: Product=ZTE WCDMA Technologies MSM S: SerialNumber=xxxxx C:* #Ifs= 4 Cfg#= 1 Atr=c0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=83(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 3 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 956319d4e19..5d02df1f62b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -554,6 +554,10 @@ static const struct option_blacklist_info net_intf1_blacklist = { .reserved = BIT(1), }; +static const struct option_blacklist_info net_intf2_blacklist = { + .reserved = BIT(2), +}; + static const struct option_blacklist_info net_intf3_blacklist = { .reserved = BIT(3), }; @@ -1099,6 +1103,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, From 9da79f9050c87ede10fef8a2f723fdf41c5caf57 Mon Sep 17 00:00:00 2001 From: Gaosen Zhang Date: Thu, 5 Jul 2012 21:49:00 +0800 Subject: [PATCH 0430/2357] USB: option: Add MEDIATEK product ids commit aacef9c561a693341566a6850c451ce3df68cb9a upstream. Signed-off-by: Gaosen Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5d02df1f62b..49484b39cc0 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -497,6 +497,15 @@ static void option_instat_callback(struct urb *urb); /* MediaTek products */ #define MEDIATEK_VENDOR_ID 0x0e8d +#define MEDIATEK_PRODUCT_DC_1COM 0x00a0 +#define MEDIATEK_PRODUCT_DC_4COM 0x00a5 +#define MEDIATEK_PRODUCT_DC_5COM 0x00a4 +#define MEDIATEK_PRODUCT_7208_1COM 0x7101 +#define MEDIATEK_PRODUCT_7208_2COM 0x7102 +#define MEDIATEK_PRODUCT_FP_1COM 0x0003 +#define MEDIATEK_PRODUCT_FP_2COM 0x0023 +#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 +#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033 /* Cellient products */ #define CELLIENT_VENDOR_ID 0x2692 @@ -1246,6 +1255,17 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */ + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, { } /* Terminating entry */ }; From e171ce5cc675f30e226b72eb693cee6832bf0a09 Mon Sep 17 00:00:00 2001 From: Stanislaw Ledwon Date: Mon, 18 Jun 2012 15:20:00 +0200 Subject: [PATCH 0431/2357] usb: Add support for root hub port status CAS commit 8bea2bd37df08aaa599aa361a9f8b836ba98e554 upstream. The host controller port status register supports CAS (Cold Attach Status) bit. This bit could be set when USB3.0 device is connected when system is in Sx state. When the system wakes to S0 this port status with CAS bit is reported and this port can't be used by any device. When CAS bit is set the port should be reset by warm reset. This was not supported by xhci driver. The issue was found when pendrive was connected to suspended platform. The link state of "Compliance Mode" was reported together with CAS bit. This link state was also not supported by xhci and core/hub.c. The CAS bit is defined only for xhci root hub port and it is not supported on regular hubs. The link status is used to force warm reset on port. Make the USB core issue a warm reset when port is in ether the 'inactive' or 'compliance mode'. Change the xHCI driver to report 'compliance mode' when the CAS is set. This force warm reset on the root hub port. This patch should be backported to stable kernels as old as 3.2, that contain the commit 10d674a82e553cb8a1f41027bb3c3e309b3f6804 "USB: When hot reset for USB3 fails, try warm reset." Signed-off-by: Stanislaw Ledwon Signed-off-by: Sarah Sharp Acked-by: Andiry Xu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 18 ++++++++------- drivers/usb/host/xhci-hub.c | 44 ++++++++++++++++++++++++++++++++----- drivers/usb/host/xhci.h | 6 ++++- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c8e0704c6e5..6241b717042 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2102,12 +2102,16 @@ static unsigned hub_is_wusb(struct usb_hub *hub) static int hub_port_reset(struct usb_hub *hub, int port1, struct usb_device *udev, unsigned int delay, bool warm); -/* Is a USB 3.0 port in the Inactive state? */ -static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus) +/* Is a USB 3.0 port in the Inactive or Complinance Mode state? + * Port worm reset is required to recover + */ +static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus) { return hub_is_superspeed(hub->hdev) && - (portstatus & USB_PORT_STAT_LINK_STATE) == - USB_SS_PORT_LS_SS_INACTIVE; + (((portstatus & USB_PORT_STAT_LINK_STATE) == + USB_SS_PORT_LS_SS_INACTIVE) || + ((portstatus & USB_PORT_STAT_LINK_STATE) == + USB_SS_PORT_LS_COMP_MOD)) ; } static int hub_port_wait_reset(struct usb_hub *hub, int port1, @@ -2143,7 +2147,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, * * See https://bugzilla.kernel.org/show_bug.cgi?id=41752 */ - if (hub_port_inactive(hub, portstatus)) { + if (hub_port_warm_reset_required(hub, portstatus)) { int ret; if ((portchange & USB_PORT_STAT_C_CONNECTION)) @@ -3757,9 +3761,7 @@ static void hub_events(void) /* Warm reset a USB3 protocol port if it's in * SS.Inactive state. */ - if (hub_is_superspeed(hub->hdev) && - (portstatus & USB_PORT_STAT_LINK_STATE) - == USB_SS_PORT_LS_SS_INACTIVE) { + if (hub_port_warm_reset_required(hub, portstatus)) { dev_dbg(hub_dev, "warm reset port %d\n", i); hub_port_reset(hub, i, NULL, HUB_BH_RESET_TIME, true); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 89850a82d51..bbf3c0c9cde 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -462,6 +462,42 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, } } +/* Updates Link Status for super Speed port */ +static void xhci_hub_report_link_state(u32 *status, u32 status_reg) +{ + u32 pls = status_reg & PORT_PLS_MASK; + + /* resume state is a xHCI internal state. + * Do not report it to usb core. + */ + if (pls == XDEV_RESUME) + return; + + /* When the CAS bit is set then warm reset + * should be performed on port + */ + if (status_reg & PORT_CAS) { + /* The CAS bit can be set while the port is + * in any link state. + * Only roothubs have CAS bit, so we + * pretend to be in compliance mode + * unless we're already in compliance + * or the inactive state. + */ + if (pls != USB_SS_PORT_LS_COMP_MOD && + pls != USB_SS_PORT_LS_SS_INACTIVE) { + pls = USB_SS_PORT_LS_COMP_MOD; + } + /* Return also connection bit - + * hub state machine resets port + * when this bit is set. + */ + pls |= USB_PORT_STAT_CONNECTION; + } + /* update status field */ + *status |= pls; +} + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { @@ -605,13 +641,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, else status |= USB_PORT_STAT_POWER; } - /* Port Link State */ + /* Update Port Link State for super speed ports*/ if (hcd->speed == HCD_USB3) { - /* resume state is a xHCI internal state. - * Do not report it to usb core. - */ - if ((temp & PORT_PLS_MASK) != XDEV_RESUME) - status |= (temp & PORT_PLS_MASK); + xhci_hub_report_link_state(&status, temp); } if (bus_state->port_c_suspend & (1 << wIndex)) status |= 1 << USB_PORT_FEAT_C_SUSPEND; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ac142760fd3..59434fe9d7d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -341,7 +341,11 @@ struct xhci_op_regs { #define PORT_PLC (1 << 22) /* port configure error change - port failed to configure its link partner */ #define PORT_CEC (1 << 23) -/* bit 24 reserved */ +/* Cold Attach Status - xHC can set this bit to report device attached during + * Sx state. Warm port reset should be perfomed to clear this bit and move port + * to connected state. + */ +#define PORT_CAS (1 << 24) /* wake on connect (enable) */ #define PORT_WKCONN_E (1 << 25) /* wake on disconnect (enable) */ From b62d32b9166b085a487916eca514b59b5ffdf2b7 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 21 Jun 2012 16:28:30 -0700 Subject: [PATCH 0432/2357] xhci: Fix hang on back-to-back Set TR Deq Ptr commands. commit 0d9f78a92ef5e97d9fe51d9215ebe22f6f0d289d upstream. The Microsoft LifeChat 3000 USB headset was causing a very reproducible hang whenever it was plugged in. At first, I thought the host controller was producing bad transfer events, because the log was filled with errors like: xhci_hcd 0000:00:14.0: ERROR Transfer event TRB DMA ptr not part of current TD However, it turned out to be an xHCI driver bug in the ring expansion patches. The bug is triggered When there are two ring segments, and a TD that ends just before a link TRB, like so: ______________ _____________ | | ---> | setup TRB B | ______________ | _____________ | | | | data TRB B | ______________ | _____________ | setup TRB A | <-- deq | | data TRB B | ______________ | _____________ | data TRB A | | | | <-- enq, deq'' ______________ | _____________ | status TRB A | | | | ______________ | _____________ | link TRB |--------------- | link TRB | _____________ <--- deq' _____________ TD A (the first control transfer) stalls on the data phase. That halts the ring. The xHCI driver moves the hardware dequeue pointer to the first TRB after the stalled transfer, which happens to be the link TRB. Once the Set TR dequeue pointer command completes, the function update_ring_for_set_deq_completion runs. That function is supposed to update the xHCI driver's dequeue pointer to match the internal hardware dequeue pointer. On the first call this would work fine, and the software dequeue pointer would move to deq'. However, if the transfer immediately after that stalled (TD B in this case), another Set TR Dequeue command would be issued. That would move the hardware dequeue pointer to deq''. Once that command completed, update_ring_for_set_deq_completion would run again. The original code would unconditionally increment the software dequeue pointer, which moved the pointer off the ring segment into la-la-land. The while loop would happy increment the dequeue pointer (possibly wrapping it) until it matched the hardware pointer value. The while loop would also access all the memory in between the first ring segment and the second ring segment to determine if it was a link TRB. This could cause general protection faults, although it was unlikely because the ring segments came from a DMA pool, and would often have consecutive memory addresses. If nothing in that space looked like a link TRB, the deq_seg pointer for the ring would remain on the first segment. Thus, the deq_seg and the software dequeue pointer would get out of sync. When the next transfer event came in after the stalled transfer, the xHCI driver code would attempt to convert the software dequeue pointer into a DMA address in order to compare the DMA address for the completed transfer. Since the deq_seg and the dequeue pointer were out of sync, xhci_trb_virt_to_dma would return NULL. The transfer event would get ignored, the transfer would eventually timeout, and we would mistakenly convert the finished transfer to no-op TRBs. Some kernel driver (maybe xHCI?) would then get stuck in an infinite loop in interrupt context, and the whole machine would hang. This patch should be backported to kernels as old as 3.4, that contain the commit b008df60c6369ba0290fa7daa177375407a12e07 "xHCI: count free TRBs on transfer ring" Signed-off-by: Sarah Sharp Cc: Andiry Xu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 525a1ee8127..158175bfecd 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -885,6 +885,17 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, num_trbs_free_temp = ep_ring->num_trbs_free; dequeue_temp = ep_ring->dequeue; + /* If we get two back-to-back stalls, and the first stalled transfer + * ends just before a link TRB, the dequeue pointer will be left on + * the link TRB by the code in the while loop. So we have to update + * the dequeue pointer one segment further, or we'll jump off + * the segment into la-la-land. + */ + if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) { + ep_ring->deq_seg = ep_ring->deq_seg->next; + ep_ring->dequeue = ep_ring->deq_seg->trbs; + } + while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) { /* We have more usable TRBs */ ep_ring->num_trbs_free++; From 0659cf9dcd148f6771c056fa95976fda9c5abf9d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 9 Jul 2012 11:09:21 -0400 Subject: [PATCH 0433/2357] PCI: EHCI: fix crash during suspend on ASUS computers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit dbf0e4c7257f8d684ec1a3c919853464293de66e upstream. Quite a few ASUS computers experience a nasty problem, related to the EHCI controllers, when going into system suspend. It was observed that the problem didn't occur if the controllers were not put into the D3 power state before starting the suspend, and commit 151b61284776be2d6f02d48c23c3625678960b97 (USB: EHCI: fix crash during suspend on ASUS computers) was created to do this. It turned out this approach messed up other computers that didn't have the problem -- it prevented USB wakeup from working. Consequently commit c2fb8a3fa25513de8fedb38509b1f15a5bbee47b (USB: add NO_D3_DURING_SLEEP flag and revert 151b61284776be2) was merged; it reverted the earlier commit and added a whitelist of known good board names. Now we know the actual cause of the problem. Thanks to AceLan Kao for tracking it down. According to him, an engineer at ASUS explained that some of their BIOSes contain a bug that was added in an attempt to work around a problem in early versions of Windows. When the computer goes into S3 suspend, the BIOS tries to verify that the EHCI controllers were first quiesced by the OS. Nothing's wrong with this, but the BIOS does it by checking that the PCI COMMAND registers contain 0 without checking the controllers' power state. If the register isn't 0, the BIOS assumes the controller needs to be quiesced and tries to do so. This involves making various MMIO accesses to the controller, which don't work very well if the controller is already in D3. The end result is a system hang or memory corruption. Since the value in the PCI COMMAND register doesn't matter once the controller has been suspended, and since the value will be restored anyway when the controller is resumed, we can work around the BIOS bug simply by setting the register to 0 during system suspend. This patch (as1590) does so and also reverts the second commit mentioned above, which is now unnecessary. In theory we could do this for every PCI device. However to avoid introducing new problems, the patch restricts itself to EHCI host controllers. Finally the affected systems can suspend with USB wakeup working properly. Reference: https://bugzilla.kernel.org/show_bug.cgi?id=37632 Reference: https://bugzilla.kernel.org/show_bug.cgi?id=42728 Based-on-patch-by: AceLan Kao Signed-off-by: Alan Stern Tested-by: Dâniel Fraga Tested-by: Javier Marcet Tested-by: Andrey Rahmatullin Tested-by: Oleksij Rempel Tested-by: Pavel Pisa Acked-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 12 ++++++++++++ drivers/pci/pci.c | 5 ----- drivers/pci/quirks.c | 26 -------------------------- include/linux/pci.h | 2 -- 4 files changed, 12 insertions(+), 33 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 6b54b23b990..3cd3f452813 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -742,6 +742,18 @@ static int pci_pm_suspend_noirq(struct device *dev) pci_pm_set_unknown_state(pci_dev); + /* + * Some BIOSes from ASUS have a bug: If a USB EHCI host controller's + * PCI COMMAND register isn't 0, the BIOS assumes that the controller + * hasn't been quiesced and tries to turn it off. If the controller + * is already in D3, this can hang or cause memory corruption. + * + * Since the value of the COMMAND register doesn't matter once the + * device has been suspended, we can safely set it to 0 here. + */ + if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI) + pci_write_config_word(pci_dev, PCI_COMMAND, 0); + return 0; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f597a1aa5e6..111569ccab4 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1743,11 +1743,6 @@ int pci_prepare_to_sleep(struct pci_dev *dev) if (target_state == PCI_POWER_ERROR) return -EIO; - /* Some devices mustn't be in D3 during system sleep */ - if (target_state == PCI_D3hot && - (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP)) - return 0; - pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev)); error = pci_set_power_state(dev, target_state); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index bf33f0b7f95..4bf71028556 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2917,32 +2917,6 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); -/* - * The Intel 6 Series/C200 Series chipset's EHCI controllers on many - * ASUS motherboards will cause memory corruption or a system crash - * if they are in D3 while the system is put into S3 sleep. - */ -static void __devinit asus_ehci_no_d3(struct pci_dev *dev) -{ - const char *sys_info; - static const char good_Asus_board[] = "P8Z68-V"; - - if (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP) - return; - if (dev->subsystem_vendor != PCI_VENDOR_ID_ASUSTEK) - return; - sys_info = dmi_get_system_info(DMI_BOARD_NAME); - if (sys_info && memcmp(sys_info, good_Asus_board, - sizeof(good_Asus_board) - 1) == 0) - return; - - dev_info(&dev->dev, "broken D3 during system sleep on ASUS\n"); - dev->dev_flags |= PCI_DEV_FLAGS_NO_D3_DURING_SLEEP; - device_set_wakeup_capable(&dev->dev, false); -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3); - static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 8b2921ad51a..e444f5b4911 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -176,8 +176,6 @@ enum pci_dev_flags { PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2, /* Provide indication device is assigned by a Virtual Machine Manager */ PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4, - /* Device causes system crash if in D3 during S3 sleep */ - PCI_DEV_FLAGS_NO_D3_DURING_SLEEP = (__force pci_dev_flags_t) 8, }; enum pci_irq_reroute_variant { From 0e924ae7ac646cf8aa95a3bc5671d19f920417c5 Mon Sep 17 00:00:00 2001 From: Davide Gerhard Date: Mon, 25 Jun 2012 09:04:47 +0200 Subject: [PATCH 0434/2357] ipheth: add support for iPad commit 6de0298ec9c1edaf330b71b57346241ece8f3346 upstream. This adds support for the iPad to the ipheth driver. (product id = 0x129a) Signed-off-by: Davide Gerhard Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/ipheth.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index dd78c4cbd45..5cba41517f7 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -59,6 +59,7 @@ #define USB_PRODUCT_IPHONE_3G 0x1292 #define USB_PRODUCT_IPHONE_3GS 0x1294 #define USB_PRODUCT_IPHONE_4 0x1297 +#define USB_PRODUCT_IPAD 0x129a #define USB_PRODUCT_IPHONE_4_VZW 0x129c #define USB_PRODUCT_IPHONE_4S 0x12a0 @@ -100,6 +101,10 @@ static struct usb_device_id ipheth_table[] = { USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPAD, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, { USB_DEVICE_AND_INTERFACE_INFO( USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, From 0bbc9d1b4b011e83ba65852b1d652561c7f562f1 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 25 Jun 2012 16:40:07 -0400 Subject: [PATCH 0435/2357] Lockd: pass network namespace to creation and destruction routines upstream commit e3f70eadb7dddfb5a2bb9afff7abfc6ee17a29d0. v2: dereference of most probably already released nlm_host removed in nlmclnt_done() and reclaimer(). These routines are called from locks reclaimer() kernel thread. This thread works in "init_net" network context and currently relays on persence on lockd thread and it's per-net resources. Thus lockd_up() and lockd_down() can't relay on current network context. So let's pass corrent one into them. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/lockd/clntlock.c | 13 ++++++++----- fs/lockd/svc.c | 7 +++---- fs/nfsd/nfssvc.c | 6 +++--- include/linux/lockd/bind.h | 4 ++-- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index ba1dc2eebd1..ca0a0800144 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -56,7 +56,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4; int status; - status = lockd_up(); + status = lockd_up(nlm_init->net); if (status < 0) return ERR_PTR(status); @@ -65,7 +65,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) nlm_init->hostname, nlm_init->noresvport, nlm_init->net); if (host == NULL) { - lockd_down(); + lockd_down(nlm_init->net); return ERR_PTR(-ENOLCK); } @@ -80,8 +80,10 @@ EXPORT_SYMBOL_GPL(nlmclnt_init); */ void nlmclnt_done(struct nlm_host *host) { + struct net *net = host->net; + nlmclnt_release_host(host); - lockd_down(); + lockd_down(net); } EXPORT_SYMBOL_GPL(nlmclnt_done); @@ -220,11 +222,12 @@ reclaimer(void *ptr) struct nlm_wait *block; struct file_lock *fl, *next; u32 nsmstate; + struct net *net = host->net; allow_signal(SIGKILL); down_write(&host->h_rwsem); - lockd_up(); /* note: this cannot fail as lockd is already running */ + lockd_up(net); /* note: this cannot fail as lockd is already running */ dprintk("lockd: reclaiming locks for host %s\n", host->h_name); @@ -275,6 +278,6 @@ reclaimer(void *ptr) /* Release host handle after use */ nlmclnt_release_host(host); - lockd_down(); + lockd_down(net); return 0; } diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index f49b9afc443..1ead0750cdb 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -295,11 +295,10 @@ static void lockd_down_net(struct net *net) /* * Bring up the lockd process if it's not already up. */ -int lockd_up(void) +int lockd_up(struct net *net) { struct svc_serv *serv; int error = 0; - struct net *net = current->nsproxy->net_ns; mutex_lock(&nlmsvc_mutex); /* @@ -378,12 +377,12 @@ EXPORT_SYMBOL_GPL(lockd_up); * Decrement the user count and bring down lockd if we're the last. */ void -lockd_down(void) +lockd_down(struct net *net) { mutex_lock(&nlmsvc_mutex); if (nlmsvc_users) { if (--nlmsvc_users) { - lockd_down_net(current->nsproxy->net_ns); + lockd_down_net(net); goto out; } } else { diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 28dfad39f0c..78e521392df 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -220,7 +220,7 @@ static int nfsd_startup(unsigned short port, int nrservs) ret = nfsd_init_socks(port); if (ret) goto out_racache; - ret = lockd_up(); + ret = lockd_up(&init_net); if (ret) goto out_racache; ret = nfs4_state_start(); @@ -229,7 +229,7 @@ static int nfsd_startup(unsigned short port, int nrservs) nfsd_up = true; return 0; out_lockd: - lockd_down(); + lockd_down(&init_net); out_racache: nfsd_racache_shutdown(); return ret; @@ -246,7 +246,7 @@ static void nfsd_shutdown(void) if (!nfsd_up) return; nfs4_state_shutdown(); - lockd_down(); + lockd_down(&init_net); nfsd_racache_shutdown(); nfsd_up = false; } diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index 11a966e5f82..4d24d64578c 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h @@ -54,7 +54,7 @@ extern void nlmclnt_done(struct nlm_host *host); extern int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl); -extern int lockd_up(void); -extern void lockd_down(void); +extern int lockd_up(struct net *net); +extern void lockd_down(struct net *net); #endif /* LINUX_LOCKD_BIND_H */ From 10762419cafd82a9a3a6f68bef54c29f1af75842 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 25 Jun 2012 16:40:08 -0400 Subject: [PATCH 0436/2357] SUNRPC: new svc_bind() routine introduced upstream commit 9793f7c88937e7ac07305ab1af1a519225836823. This new routine is responsible for service registration in a specified network context. The idea is to separate service creation from per-net operations. Note also: since registering service with svc_bind() can fail, the service will be destroyed and during destruction it will try to unregister itself from rpcbind. In this case unregistration has to be skipped. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/lockd/svc.c | 6 ++++++ fs/nfs/callback.c | 8 ++++++++ fs/nfsd/nfssvc.c | 9 +++++++++ include/linux/sunrpc/svc.h | 1 + net/sunrpc/rpcb_clnt.c | 12 +++++++----- net/sunrpc/svc.c | 19 ++++++++++--------- 6 files changed, 41 insertions(+), 14 deletions(-) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1ead0750cdb..b7e92ed5688 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -324,6 +324,12 @@ int lockd_up(struct net *net) goto out; } + error = svc_bind(serv, net); + if (error < 0) { + printk(KERN_WARNING "lockd_up: bind service failed\n"); + goto destroy_and_out; + } + error = make_socks(serv, net); if (error < 0) goto destroy_and_out; diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index eb95f5091c1..26b38fb8102 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -253,6 +254,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) char svc_name[12]; int ret = 0; int minorversion_setup; + struct net *net = current->nsproxy->net_ns; mutex_lock(&nfs_callback_mutex); if (cb_info->users++ || cb_info->task != NULL) { @@ -265,6 +267,12 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) goto out_err; } + ret = svc_bind(serv, net); + if (ret < 0) { + printk(KERN_WARNING "NFS: bind callback service failed\n"); + goto out_err; + } + minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, serv, xprt, &rqstp, &callback_svc); if (!minorversion_setup) { diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 78e521392df..118c172463c 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -330,6 +331,8 @@ static int nfsd_get_default_max_blksize(void) int nfsd_create_serv(void) { + int error; + WARN_ON(!mutex_is_locked(&nfsd_mutex)); if (nfsd_serv) { svc_get(nfsd_serv); @@ -343,6 +346,12 @@ int nfsd_create_serv(void) if (nfsd_serv == NULL) return -ENOMEM; + error = svc_bind(nfsd_serv, current->nsproxy->net_ns); + if (error < 0) { + svc_destroy(nfsd_serv); + return error; + } + set_max_drc(); do_gettimeofday(&nfssvc_boot); /* record boot time */ return 0; diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 51b29ac45a8..2b43e021426 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -416,6 +416,7 @@ struct svc_procedure { */ int svc_rpcb_setup(struct svc_serv *serv, struct net *net); void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net); +int svc_bind(struct svc_serv *serv, struct net *net); struct svc_serv *svc_create(struct svc_program *, unsigned int, void (*shutdown)(struct svc_serv *, struct net *net)); struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 78ac39fd9fe..4c38b33ab8a 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -180,14 +180,16 @@ void rpcb_put_local(struct net *net) struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); struct rpc_clnt *clnt = sn->rpcb_local_clnt; struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; - int shutdown; + int shutdown = 0; spin_lock(&sn->rpcb_clnt_lock); - if (--sn->rpcb_users == 0) { - sn->rpcb_local_clnt = NULL; - sn->rpcb_local_clnt4 = NULL; + if (sn->rpcb_users) { + if (--sn->rpcb_users == 0) { + sn->rpcb_local_clnt = NULL; + sn->rpcb_local_clnt4 = NULL; + } + shutdown = !sn->rpcb_users; } - shutdown = !sn->rpcb_users; spin_unlock(&sn->rpcb_clnt_lock); if (shutdown) { diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 234ee39000a..c6860219a73 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -407,6 +407,14 @@ static int svc_uses_rpcbind(struct svc_serv *serv) return 0; } +int svc_bind(struct svc_serv *serv, struct net *net) +{ + if (!svc_uses_rpcbind(serv)) + return 0; + return svc_rpcb_setup(serv, net); +} +EXPORT_SYMBOL_GPL(svc_bind); + /* * Create an RPC service */ @@ -471,15 +479,8 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, spin_lock_init(&pool->sp_lock); } - if (svc_uses_rpcbind(serv)) { - if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) { - kfree(serv->sv_pools); - kfree(serv); - return NULL; - } - if (!serv->sv_shutdown) - serv->sv_shutdown = svc_rpcb_cleanup; - } + if (svc_uses_rpcbind(serv) && (!serv->sv_shutdown)) + serv->sv_shutdown = svc_rpcb_cleanup; return serv; } From ee92389156c2cdb45b94866186a4174858b820cd Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 25 Jun 2012 16:40:09 -0400 Subject: [PATCH 0437/2357] SUNRPC: move per-net operations from svc_destroy() upstream commit 786185b5f8abefa6a8a16695bb4a59c164d5a071. The idea is to separate service destruction and per-net operations, because these are two different things and the mix looks ugly. Notes: 1) For NFS server this patch looks ugly (sorry for that). But these place will be rewritten soon during NFSd containerization. 2) LockD per-net counter increase int lockd_up() was moved prior to make_socks() to make lockd_down_net() call safe in case of error. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/lockd/svc.c | 27 +++++++++++++++------------ fs/nfs/callback.c | 3 +++ fs/nfsd/nfsctl.c | 12 +++++++++--- fs/nfsd/nfssvc.c | 14 ++++++++++++++ net/sunrpc/svc.c | 4 ---- 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index b7e92ed5688..3250f280a17 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -257,7 +257,7 @@ static int lockd_up_net(struct net *net) struct svc_serv *serv = nlmsvc_rqst->rq_server; int error; - if (ln->nlmsvc_users) + if (ln->nlmsvc_users++) return 0; error = svc_rpcb_setup(serv, net); @@ -272,6 +272,7 @@ static int lockd_up_net(struct net *net) err_socks: svc_rpcb_cleanup(serv, net); err_rpcb: + ln->nlmsvc_users--; return error; } @@ -299,6 +300,7 @@ int lockd_up(struct net *net) { struct svc_serv *serv; int error = 0; + struct lockd_net *ln = net_generic(net, lockd_net_id); mutex_lock(&nlmsvc_mutex); /* @@ -330,9 +332,11 @@ int lockd_up(struct net *net) goto destroy_and_out; } + ln->nlmsvc_users++; + error = make_socks(serv, net); if (error < 0) - goto destroy_and_out; + goto err_start; /* * Create the kernel thread and wait for it to start. @@ -344,7 +348,7 @@ int lockd_up(struct net *net) printk(KERN_WARNING "lockd_up: svc_rqst allocation failed, error=%d\n", error); - goto destroy_and_out; + goto err_start; } svc_sock_update_bufs(serv); @@ -358,7 +362,7 @@ int lockd_up(struct net *net) nlmsvc_rqst = NULL; printk(KERN_WARNING "lockd_up: kthread_run failed, error=%d\n", error); - goto destroy_and_out; + goto err_start; } /* @@ -368,14 +372,14 @@ int lockd_up(struct net *net) destroy_and_out: svc_destroy(serv); out: - if (!error) { - struct lockd_net *ln = net_generic(net, lockd_net_id); - - ln->nlmsvc_users++; + if (!error) nlmsvc_users++; - } mutex_unlock(&nlmsvc_mutex); return error; + +err_start: + lockd_down_net(net); + goto destroy_and_out; } EXPORT_SYMBOL_GPL(lockd_up); @@ -386,11 +390,10 @@ void lockd_down(struct net *net) { mutex_lock(&nlmsvc_mutex); + lockd_down_net(net); if (nlmsvc_users) { - if (--nlmsvc_users) { - lockd_down_net(net); + if (--nlmsvc_users) goto out; - } } else { printk(KERN_ERR "lockd_down: no users! task=%p\n", nlmsvc_task); diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 26b38fb8102..cff39406f96 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -314,6 +314,8 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) dprintk("NFS: Couldn't create callback socket or server thread; " "err = %d\n", ret); cb_info->users--; + if (serv) + svc_shutdown_net(serv, net); goto out; } @@ -328,6 +330,7 @@ void nfs_callback_down(int minorversion) cb_info->users--; if (cb_info->users == 0 && cb_info->task != NULL) { kthread_stop(cb_info->task); + svc_shutdown_net(cb_info->serv, current->nsproxy->net_ns); svc_exit_thread(cb_info->rqst); cb_info->serv = NULL; cb_info->rqst = NULL; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 2c53be6d357..3ab12eb2967 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -651,6 +651,7 @@ static ssize_t __write_ports_addfd(char *buf) { char *mesg = buf; int fd, err; + struct net *net = &init_net; err = get_int(&mesg, &fd); if (err != 0 || fd < 0) @@ -662,6 +663,8 @@ static ssize_t __write_ports_addfd(char *buf) err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); if (err < 0) { + if (nfsd_serv->sv_nrthreads == 1) + svc_shutdown_net(nfsd_serv, net); svc_destroy(nfsd_serv); return err; } @@ -699,6 +702,7 @@ static ssize_t __write_ports_addxprt(char *buf) char transport[16]; struct svc_xprt *xprt; int port, err; + struct net *net = &init_net; if (sscanf(buf, "%15s %4u", transport, &port) != 2) return -EINVAL; @@ -710,12 +714,12 @@ static ssize_t __write_ports_addxprt(char *buf) if (err != 0) return err; - err = svc_create_xprt(nfsd_serv, transport, &init_net, + err = svc_create_xprt(nfsd_serv, transport, net, PF_INET, port, SVC_SOCK_ANONYMOUS); if (err < 0) goto out_err; - err = svc_create_xprt(nfsd_serv, transport, &init_net, + err = svc_create_xprt(nfsd_serv, transport, net, PF_INET6, port, SVC_SOCK_ANONYMOUS); if (err < 0 && err != -EAFNOSUPPORT) goto out_close; @@ -724,12 +728,14 @@ static ssize_t __write_ports_addxprt(char *buf) nfsd_serv->sv_nrthreads--; return 0; out_close: - xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port); + xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port); if (xprt != NULL) { svc_close_xprt(xprt); svc_xprt_put(xprt); } out_err: + if (nfsd_serv->sv_nrthreads == 1) + svc_shutdown_net(nfsd_serv, net); svc_destroy(nfsd_serv); return err; } diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 118c172463c..bcda12a3f08 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -382,6 +382,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) int i = 0; int tot = 0; int err = 0; + struct net *net = &init_net; WARN_ON(!mutex_is_locked(&nfsd_mutex)); @@ -426,6 +427,9 @@ int nfsd_set_nrthreads(int n, int *nthreads) if (err) break; } + + if (nfsd_serv->sv_nrthreads == 1) + svc_shutdown_net(nfsd_serv, net); svc_destroy(nfsd_serv); return err; @@ -441,6 +445,7 @@ nfsd_svc(unsigned short port, int nrservs) { int error; bool nfsd_up_before; + struct net *net = &init_net; mutex_lock(&nfsd_mutex); dprintk("nfsd: creating service\n"); @@ -473,6 +478,8 @@ nfsd_svc(unsigned short port, int nrservs) if (error < 0 && !nfsd_up_before) nfsd_shutdown(); out_destroy: + if (nfsd_serv->sv_nrthreads == 1) + svc_shutdown_net(nfsd_serv, net); svc_destroy(nfsd_serv); /* Release server */ out: mutex_unlock(&nfsd_mutex); @@ -556,6 +563,9 @@ nfsd(void *vrqstp) nfsdstats.th_cnt --; out: + if (rqstp->rq_server->sv_nrthreads == 1) + svc_shutdown_net(rqstp->rq_server, &init_net); + /* Release the thread */ svc_exit_thread(rqstp); @@ -668,8 +678,12 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file) int nfsd_pool_stats_release(struct inode *inode, struct file *file) { int ret = seq_release(inode, file); + struct net *net = &init_net; + mutex_lock(&nfsd_mutex); /* this function really, really should have been called svc_put() */ + if (nfsd_serv->sv_nrthreads == 1) + svc_shutdown_net(nfsd_serv, net); svc_destroy(nfsd_serv); mutex_unlock(&nfsd_mutex); return ret; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index c6860219a73..cb7c13fc485 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -537,8 +537,6 @@ EXPORT_SYMBOL_GPL(svc_shutdown_net); void svc_destroy(struct svc_serv *serv) { - struct net *net = current->nsproxy->net_ns; - dprintk("svc: svc_destroy(%s, %d)\n", serv->sv_program->pg_name, serv->sv_nrthreads); @@ -553,8 +551,6 @@ svc_destroy(struct svc_serv *serv) del_timer_sync(&serv->sv_temptimer); - svc_shutdown_net(serv, net); - /* * The last user is gone and thus all sockets have to be destroyed to * the point. Check this. From f183282bb88ffa944449cf3a24a649c754d9e7af Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 25 Jun 2012 16:40:10 -0400 Subject: [PATCH 0438/2357] NFS: hard-code init_net for NFS callback transports upstream commit 12918b10d59e975fd5241eef03ef9e6d5ea3dcfe. In case of destroying mount namespace on child reaper exit, nsproxy is zeroed to the point already. So, dereferencing of it is invalid. This patch hard-code "init_net" for all network namespace references for NFS callback services. This will be fixed with proper NFS callback containerization. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfs/callback.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index cff39406f96..38a44c679a0 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -107,7 +106,7 @@ nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) { int ret; - ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET, + ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET, nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); if (ret <= 0) goto out_err; @@ -115,7 +114,7 @@ nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) dprintk("NFS: Callback listener port = %u (af %u)\n", nfs_callback_tcpport, PF_INET); - ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET6, + ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6, nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); if (ret > 0) { nfs_callback_tcpport6 = ret; @@ -184,7 +183,7 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) * fore channel connection. * Returns the input port (0) and sets the svc_serv bc_xprt on success */ - ret = svc_create_xprt(serv, "tcp-bc", xprt->xprt_net, PF_INET, 0, + ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0, SVC_SOCK_ANONYMOUS); if (ret < 0) { rqstp = ERR_PTR(ret); @@ -254,7 +253,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) char svc_name[12]; int ret = 0; int minorversion_setup; - struct net *net = current->nsproxy->net_ns; + struct net *net = &init_net; mutex_lock(&nfs_callback_mutex); if (cb_info->users++ || cb_info->task != NULL) { @@ -330,7 +329,7 @@ void nfs_callback_down(int minorversion) cb_info->users--; if (cb_info->users == 0 && cb_info->task != NULL) { kthread_stop(cb_info->task); - svc_shutdown_net(cb_info->serv, current->nsproxy->net_ns); + svc_shutdown_net(cb_info->serv, &init_net); svc_exit_thread(cb_info->rqst); cb_info->serv = NULL; cb_info->rqst = NULL; From bf2370ff886b0059f574d78c7dfc9c1cb6fd38e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 27 Jun 2012 18:11:56 +0200 Subject: [PATCH 0439/2357] mac80211: fix queues stuck issue with HT bandwidth change No upstream commit, the buggy code was removed in 3.5 in commit 7213cf2cb0dfbb4d6b55a1da000d34338f76c0e3 and others. Rajkumar changed code for handling channel switching in mac80211 to stop the queues in commit 7cc44ed48d0ec0937c1f098642540b6c9ca38de5 Author: Rajkumar Manoharan Date: Fri Sep 16 15:32:34 2011 +0530 mac80211: Fix regression on queue stop during 2040 bss change which went into 3.2. In the 3.4 cycle, Paul's change commit 3117bbdb7899d43927c8ce4fe885ab7c1231c121 Author: Paul Stewart Date: Tue Mar 13 07:46:18 2012 -0700 mac80211: Don't let regulatory make us deaf went in and changed the TX/RX enable logic, but now the conditions for stopping and restarting the queues were different so that now, if the AP changes between 20/40 MHz bandwidth, it can happen that we stop but never restart the queues. This breaks the connection and the module actually has to be reloaded to get it back to work. Fix this by making sure the queues are always started when they were stopped. Reported-by: Florian Manschwetus Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 425653f464c..1197e8dd5b0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -187,7 +187,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, u32 changed = 0; int hti_cfreq; u16 ht_opmode; - bool enable_ht = true; + bool enable_ht = true, queues_stopped = false; enum nl80211_channel_type prev_chantype; enum nl80211_channel_type rx_channel_type = NL80211_CHAN_NO_HT; enum nl80211_channel_type tx_channel_type; @@ -254,6 +254,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, */ ieee80211_stop_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE); + queues_stopped = true; /* flush out all packets */ synchronize_net(); @@ -272,12 +273,12 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, IEEE80211_RC_HT_CHANGED, tx_channel_type); rcu_read_unlock(); - - if (beacon_htcap_ie) - ieee80211_wake_queues_by_reason(&sdata->local->hw, - IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE); } + if (queues_stopped) + ieee80211_wake_queues_by_reason(&sdata->local->hw, + IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE); + ht_opmode = le16_to_cpu(hti->operation_mode); /* if bss configuration changed store the new one */ From dbb3e108234bf8e4bf43d2fed8bc57792e3dbd2f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Jun 2012 08:46:25 +0200 Subject: [PATCH 0440/2357] iwlwifi: remove log_event debugfs file debugging is disabled commit 882b7b7d11d65e8eccce738f1ce97cdfdb998f9f upstream. When debugging is disabled, the event log functions aren't functional in the way that the debugfs file expects. This leads to the debugfs access crashing. Since the event log functions aren't functional then, remove the debugfs file when CONFIG_IWLWIFI_DEBUG is not set. Reported-by: Lekensteyn Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville [bwh: Backported to 3.2: adjust filename, context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 6eac984b2d0..8741048eb85 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -2000,6 +2000,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +#ifdef CONFIG_IWLWIFI_DEBUG static ssize_t iwl_dbgfs_log_event_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -2037,6 +2038,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, return count; } +#endif static ssize_t iwl_dbgfs_interrupt_read(struct file *file, char __user *user_buf, @@ -2164,7 +2166,9 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, return ret; } +#ifdef CONFIG_IWLWIFI_DEBUG DEBUGFS_READ_WRITE_FILE_OPS(log_event); +#endif DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_FILE_OPS(rx_queue); @@ -2180,7 +2184,9 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, { DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR); DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR); +#ifdef CONFIG_IWLWIFI_DEBUG DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR); +#endif DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(csr, dir, S_IWUSR); DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); From 4943d9cb7d82218d196ccc034ecaf933298e7e95 Mon Sep 17 00:00:00 2001 From: Vaibhav Nagarnaik Date: Thu, 3 May 2012 18:59:52 -0700 Subject: [PATCH 0441/2357] tracing: change CPU ring buffer state from tracing_cpumask commit 71babb2705e2203a64c27ede13ae3508a0d2c16c upstream. According to Documentation/trace/ftrace.txt: tracing_cpumask: This is a mask that lets the user only trace on specified CPUS. The format is a hex string representing the CPUS. The tracing_cpumask currently doesn't affect the tracing state of per-CPU ring buffers. This patch enables/disables CPU recording as its corresponding bit in tracing_cpumask is set/unset. Link: http://lkml.kernel.org/r/1336096792-25373-3-git-send-email-vnagarnaik@google.com Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Laurent Chavey Cc: Justin Teravest Cc: David Sharp Signed-off-by: Vaibhav Nagarnaik Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 464a96f3d4c..5fc7bfa0ccb 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -2648,10 +2648,12 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, if (cpumask_test_cpu(cpu, tracing_cpumask) && !cpumask_test_cpu(cpu, tracing_cpumask_new)) { atomic_inc(&global_trace.data[cpu]->disabled); + ring_buffer_record_disable_cpu(global_trace.buffer, cpu); } if (!cpumask_test_cpu(cpu, tracing_cpumask) && cpumask_test_cpu(cpu, tracing_cpumask_new)) { atomic_dec(&global_trace.data[cpu]->disabled); + ring_buffer_record_enable_cpu(global_trace.buffer, cpu); } } arch_spin_unlock(&ftrace_max_lock); From 445006de7c59a9086b00025f9c3c97c75effd3c5 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 3 Jul 2012 20:43:56 -0700 Subject: [PATCH 0442/2357] mwifiex: fix wrong return values in add_virtual_intf() error cases commit 858faa57dd9e2b91f3f870fbb1185982e42f5a2b upstream add_virtual_intf() needs to return an ERR_PTR(), instead of NULL, on errors, otherwise cfg80211 will crash. Reported-by: Johannes Berg Signed-off-by: Bing Zhao Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mwifiex/cfg80211.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 65050384c42..baf691949c3 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1214,11 +1214,11 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, void *mdev_priv; if (!priv) - return NULL; + return ERR_PTR(-EFAULT); adapter = priv->adapter; if (!adapter) - return NULL; + return ERR_PTR(-EFAULT); switch (type) { case NL80211_IFTYPE_UNSPECIFIED: @@ -1227,7 +1227,7 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, if (priv->bss_mode) { wiphy_err(wiphy, "cannot create multiple" " station/adhoc interfaces\n"); - return NULL; + return ERR_PTR(-EINVAL); } if (type == NL80211_IFTYPE_UNSPECIFIED) @@ -1244,14 +1244,15 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, break; default: wiphy_err(wiphy, "type not supported\n"); - return NULL; + return ERR_PTR(-EINVAL); } dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name, ether_setup, 1); if (!dev) { wiphy_err(wiphy, "no memory available for netdevice\n"); - goto error; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-ENOMEM); } dev_net_set(dev, wiphy_net(wiphy)); @@ -1276,7 +1277,9 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, /* Register network device */ if (register_netdevice(dev)) { wiphy_err(wiphy, "cannot register virtual network device\n"); - goto error; + free_netdev(dev); + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-EFAULT); } sema_init(&priv->async_sem, 1); @@ -1288,12 +1291,6 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, mwifiex_dev_debugfs_init(priv); #endif return dev; -error: - if (dev && (dev->reg_state == NETREG_UNREGISTERED)) - free_netdev(dev); - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - - return NULL; } EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); From c412589f74ab4f1e30bb25b685fe6d95f2befd4d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 5 Jul 2012 10:23:17 +0200 Subject: [PATCH 0443/2357] gspca-core: Fix buffers staying in queued state after a stream_off commit af05ef01e9cde84620c6855a8d8ab9c8a1db9009 upstream. [Backport to linux-stable by Antonio Ospite ] This fixes a regression introduced by commit f7059ea and should be backported to all supported stable kernels which have this commit. Signed-off-by: Antonio Ospite Signed-off-by: Hans de Goede Tested-by: Antonio Ospite Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/gspca/gspca.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index ca5a2b139d0..4dc88527961 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1723,7 +1723,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type buf_type) { struct gspca_dev *gspca_dev = priv; - int ret; + int i, ret; if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1754,6 +1754,8 @@ static int vidioc_streamoff(struct file *file, void *priv, wake_up_interruptible(&gspca_dev->wq); /* empty the transfer queues */ + for (i = 0; i < gspca_dev->nframes; i++) + gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS; atomic_set(&gspca_dev->fr_q, 0); atomic_set(&gspca_dev->fr_i, 0); gspca_dev->fr_o = 0; From 5bbbd747918d241b41f3220ff26323d7ed943c52 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Tue, 3 Jul 2012 15:57:19 +1000 Subject: [PATCH 0444/2357] raid5: delayed stripe fix commit fab363b5ff502d1b39ddcfec04271f5858d9f26e upstream. There isn't locking setting STRIPE_DELAYED and STRIPE_PREREAD_ACTIVE bits, but the two bits have relationship. A delayed stripe can be moved to hold list only when preread active stripe count is below IO_THRESHOLD. If a stripe has both the bits set, such stripe will be in delayed list and preread count not 0, which will make such stripe never leave delayed list. Signed-off-by: Shaohua Li Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 8fc591877dc..23e501518c4 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -196,12 +196,14 @@ static void __release_stripe(struct r5conf *conf, struct stripe_head *sh) BUG_ON(!list_empty(&sh->lru)); BUG_ON(atomic_read(&conf->active_stripes)==0); if (test_bit(STRIPE_HANDLE, &sh->state)) { - if (test_bit(STRIPE_DELAYED, &sh->state)) + if (test_bit(STRIPE_DELAYED, &sh->state) && + !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) list_add_tail(&sh->lru, &conf->delayed_list); else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && sh->bm_seq - conf->seq_write > 0) list_add_tail(&sh->lru, &conf->bitmap_list); else { + clear_bit(STRIPE_DELAYED, &sh->state); clear_bit(STRIPE_BIT_DELAY, &sh->state); list_add_tail(&sh->lru, &conf->handle_list); } From 5250def1935443f4bbddce101281e0aaf2e66838 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 7 Jun 2012 12:56:54 +0000 Subject: [PATCH 0445/2357] tg3: Apply short DMA frag workaround to 5906 commit b7abee6ef888117f92db370620ebf116a38e3f4d upstream. 5906 devices also need the short DMA fragment workaround. This patch makes the necessary change. Signed-off-by: Matt Carlson Tested-by: Christian Kujau Signed-off-by: David S. Miller Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/tg3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index ceeab8e852e..1a1b29ff814 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -14248,7 +14248,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } - if (tg3_flag(tp, 5755_PLUS)) + if (tg3_flag(tp, 5755_PLUS) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tg3_flag_set(tp, SHORT_DMA_BUG); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) From e5982925c66c542aa41b17ee35fc233ae1521898 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Wed, 27 Jun 2012 18:21:15 +0100 Subject: [PATCH 0446/2357] ath9k: fix panic caused by returning a descriptor we have queued for reuse commit 6bb51c70cabaadddc54a6454844eceba91a56083 upstream. Commit 3a2923e83c introduced a bug when a corrupt descriptor is encountered - although the following descriptor is discarded and returned to the queue for reuse the associated frame is also returned for processing. This leads to a panic: BUG: unable to handle kernel NULL pointer dereference at 000000000000003a IP: [] ath_rx_tasklet+0x165/0x1b00 [ath9k] Call Trace: [] ? map_single+0x60/0x60 [] ? ath9k_ioread32+0x34/0x90 [ath9k] [] athk9k_tasklet+0xdc/0x160 [ath9k] [] tasklet_action+0x63/0xd0 [] __do_softirq+0xc0/0x1e0 [] ? native_sched_clock+0x13/0x80 [] call_softirq+0x1c/0x30 [] do_softirq+0x75/0xb0 [] irq_exit+0xb5/0xc0 [] do_IRQ+0x63/0xe0 [] common_interrupt+0x6a/0x6a [] ? intel_idle+0xea/0x150 [] ? intel_idle+0xcb/0x150 [] cpuidle_enter+0x19/0x20 [] cpuidle_idle_call+0xa9/0x240 [] cpu_idle+0xaf/0x120 [] rest_init+0x72/0x74 [] start_kernel+0x3b7/0x3c4 [] ? repair_env_string+0x5e/0x5e [] x86_64_start_reservations+0x131/0x135 [] x86_64_start_kernel+0x100/0x10f Making sure bf is cleared to NULL in this case restores the old behaviour. Signed-off-by: Tom Hughes Signed-off-by: John W. Linville Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 1efd6c9beb3..a2f7ae81a41 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -695,9 +695,9 @@ static bool ath_edma_get_buffers(struct ath_softc *sc, __skb_unlink(skb, &rx_edma->rx_fifo); list_add_tail(&bf->list, &sc->rx.rxbuf); ath_rx_edma_buf_link(sc, qtype); - } else { - bf = NULL; } + + bf = NULL; } *dest = bf; From ff99851d5277c6131301a09f687aa3976ced31e7 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Tue, 29 May 2012 15:06:49 -0700 Subject: [PATCH 0447/2357] mm: pmd_read_atomic: fix 32bit PAE pmd walk vs pmd_populate SMP race condition commit 26c191788f18129af0eb32a358cdaea0c7479626 upstream. When holding the mmap_sem for reading, pmd_offset_map_lock should only run on a pmd_t that has been read atomically from the pmdp pointer, otherwise we may read only half of it leading to this crash. PID: 11679 TASK: f06e8000 CPU: 3 COMMAND: "do_race_2_panic" #0 [f06a9dd8] crash_kexec at c049b5ec #1 [f06a9e2c] oops_end at c083d1c2 #2 [f06a9e40] no_context at c0433ded #3 [f06a9e64] bad_area_nosemaphore at c043401a #4 [f06a9e6c] __do_page_fault at c0434493 #5 [f06a9eec] do_page_fault at c083eb45 #6 [f06a9f04] error_code (via page_fault) at c083c5d5 EAX: 01fb470c EBX: fff35000 ECX: 00000003 EDX: 00000100 EBP: 00000000 DS: 007b ESI: 9e201000 ES: 007b EDI: 01fb4700 GS: 00e0 CS: 0060 EIP: c083bc14 ERR: ffffffff EFLAGS: 00010246 #7 [f06a9f38] _spin_lock at c083bc14 #8 [f06a9f44] sys_mincore at c0507b7d #9 [f06a9fb0] system_call at c083becd start len EAX: ffffffda EBX: 9e200000 ECX: 00001000 EDX: 6228537f DS: 007b ESI: 00000000 ES: 007b EDI: 003d0f00 SS: 007b ESP: 62285354 EBP: 62285388 GS: 0033 CS: 0073 EIP: 00291416 ERR: 000000da EFLAGS: 00000286 This should be a longstanding bug affecting x86 32bit PAE without THP. Only archs with 64bit large pmd_t and 32bit unsigned long should be affected. With THP enabled the barrier() in pmd_none_or_trans_huge_or_clear_bad() would partly hide the bug when the pmd transition from none to stable, by forcing a re-read of the *pmd in pmd_offset_map_lock, but when THP is enabled a new set of problem arises by the fact could then transition freely in any of the none, pmd_trans_huge or pmd_trans_stable states. So making the barrier in pmd_none_or_trans_huge_or_clear_bad() unconditional isn't good idea and it would be a flakey solution. This should be fully fixed by introducing a pmd_read_atomic that reads the pmd in order with THP disabled, or by reading the pmd atomically with cmpxchg8b with THP enabled. Luckily this new race condition only triggers in the places that must already be covered by pmd_none_or_trans_huge_or_clear_bad() so the fix is localized there but this bug is not related to THP. NOTE: this can trigger on x86 32bit systems with PAE enabled with more than 4G of ram, otherwise the high part of the pmd will never risk to be truncated because it would be zero at all times, in turn so hiding the SMP race. This bug was discovered and fully debugged by Ulrich, quote: ---- [..] pmd_none_or_trans_huge_or_clear_bad() loads the content of edx and eax. 496 static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd) 497 { 498 /* depend on compiler for an atomic pmd read */ 499 pmd_t pmdval = *pmd; // edi = pmd pointer 0xc0507a74 : mov 0x8(%esp),%edi ... // edx = PTE page table high address 0xc0507a84 : mov 0x4(%edi),%edx ... // eax = PTE page table low address 0xc0507a8e : mov (%edi),%eax [..] Please note that the PMD is not read atomically. These are two "mov" instructions where the high order bits of the PMD entry are fetched first. Hence, the above machine code is prone to the following race. - The PMD entry {high|low} is 0x0000000000000000. The "mov" at 0xc0507a84 loads 0x00000000 into edx. - A page fault (on another CPU) sneaks in between the two "mov" instructions and instantiates the PMD. - The PMD entry {high|low} is now 0x00000003fda38067. The "mov" at 0xc0507a8e loads 0xfda38067 into eax. ---- Reported-by: Ulrich Obergfell Signed-off-by: Andrea Arcangeli Cc: Mel Gorman Cc: Hugh Dickins Cc: Larry Woodman Cc: Petr Matousek Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/pgtable-3level.h | 50 +++++++++++++++++++++++++++ include/asm-generic/pgtable.h | 22 ++++++++++-- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h index effff47a3c8..43876f16caf 100644 --- a/arch/x86/include/asm/pgtable-3level.h +++ b/arch/x86/include/asm/pgtable-3level.h @@ -31,6 +31,56 @@ static inline void native_set_pte(pte_t *ptep, pte_t pte) ptep->pte_low = pte.pte_low; } +#define pmd_read_atomic pmd_read_atomic +/* + * pte_offset_map_lock on 32bit PAE kernels was reading the pmd_t with + * a "*pmdp" dereference done by gcc. Problem is, in certain places + * where pte_offset_map_lock is called, concurrent page faults are + * allowed, if the mmap_sem is hold for reading. An example is mincore + * vs page faults vs MADV_DONTNEED. On the page fault side + * pmd_populate rightfully does a set_64bit, but if we're reading the + * pmd_t with a "*pmdp" on the mincore side, a SMP race can happen + * because gcc will not read the 64bit of the pmd atomically. To fix + * this all places running pmd_offset_map_lock() while holding the + * mmap_sem in read mode, shall read the pmdp pointer using this + * function to know if the pmd is null nor not, and in turn to know if + * they can run pmd_offset_map_lock or pmd_trans_huge or other pmd + * operations. + * + * Without THP if the mmap_sem is hold for reading, the + * pmd can only transition from null to not null while pmd_read_atomic runs. + * So there's no need of literally reading it atomically. + * + * With THP if the mmap_sem is hold for reading, the pmd can become + * THP or null or point to a pte (and in turn become "stable") at any + * time under pmd_read_atomic, so it's mandatory to read it atomically + * with cmpxchg8b. + */ +#ifndef CONFIG_TRANSPARENT_HUGEPAGE +static inline pmd_t pmd_read_atomic(pmd_t *pmdp) +{ + pmdval_t ret; + u32 *tmp = (u32 *)pmdp; + + ret = (pmdval_t) (*tmp); + if (ret) { + /* + * If the low part is null, we must not read the high part + * or we can end up with a partial pmd. + */ + smp_rmb(); + ret |= ((pmdval_t)*(tmp + 1)) << 32; + } + + return (pmd_t) { ret }; +} +#else /* CONFIG_TRANSPARENT_HUGEPAGE */ +static inline pmd_t pmd_read_atomic(pmd_t *pmdp) +{ + return (pmd_t) { atomic64_read((atomic64_t *)pmdp) }; +} +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) { set_64bit((unsigned long long *)(ptep), native_pte_val(pte)); diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 125c54e9851..fa596d9f9c2 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -446,6 +446,18 @@ static inline int pmd_write(pmd_t pmd) #endif /* __HAVE_ARCH_PMD_WRITE */ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#ifndef pmd_read_atomic +static inline pmd_t pmd_read_atomic(pmd_t *pmdp) +{ + /* + * Depend on compiler for an atomic pmd read. NOTE: this is + * only going to work, if the pmdval_t isn't larger than + * an unsigned long. + */ + return *pmdp; +} +#endif + /* * This function is meant to be used by sites walking pagetables with * the mmap_sem hold in read mode to protect against MADV_DONTNEED and @@ -459,11 +471,17 @@ static inline int pmd_write(pmd_t pmd) * undefined so behaving like if the pmd was none is safe (because it * can return none anyway). The compiler level barrier() is critically * important to compute the two checks atomically on the same pmdval. + * + * For 32bit kernels with a 64bit large pmd_t this automatically takes + * care of reading the pmd atomically to avoid SMP race conditions + * against pmd_populate() when the mmap_sem is hold for reading by the + * caller (a special atomic read not done by "gcc" as in the generic + * version above, is also needed when THP is disabled because the page + * fault can populate the pmd from under us). */ static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd) { - /* depend on compiler for an atomic pmd read */ - pmd_t pmdval = *pmd; + pmd_t pmdval = pmd_read_atomic(pmd); /* * The barrier will stabilize the pmdval in a register or on * the stack so that it will stop changing under the code. From acf8fbd7c1182204ed723dee365bc5ba9a503dd6 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 20 Jun 2012 12:52:57 -0700 Subject: [PATCH 0448/2357] thp: avoid atomic64_read in pmd_read_atomic for 32bit PAE commit e4eed03fd06578571c01d4f1478c874bb432c815 upstream. In the x86 32bit PAE CONFIG_TRANSPARENT_HUGEPAGE=y case while holding the mmap_sem for reading, cmpxchg8b cannot be used to read pmd contents under Xen. So instead of dealing only with "consistent" pmdvals in pmd_none_or_trans_huge_or_clear_bad() (which would be conceptually simpler) we let pmd_none_or_trans_huge_or_clear_bad() deal with pmdvals where the low 32bit and high 32bit could be inconsistent (to avoid having to use cmpxchg8b). The only guarantee we get from pmd_read_atomic is that if the low part of the pmd was found null, the high part will be null too (so the pmd will be considered unstable). And if the low part of the pmd is found "stable" later, then it means the whole pmd was read atomically (because after a pmd is stable, neither MADV_DONTNEED nor page faults can alter it anymore, and we read the high part after the low part). In the 32bit PAE x86 case, it is enough to read the low part of the pmdval atomically to declare the pmd as "stable" and that's true for THP and no THP, furthermore in the THP case we also have a barrier() that will prevent any inconsistent pmdvals to be cached by a later re-read of the *pmd. Signed-off-by: Andrea Arcangeli Cc: Jonathan Nieder Cc: Ulrich Obergfell Cc: Mel Gorman Cc: Hugh Dickins Cc: Larry Woodman Cc: Petr Matousek Cc: Rik van Riel Cc: Jan Beulich Cc: KOSAKI Motohiro Tested-by: Andrew Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/pgtable-3level.h | 30 +++++++++++++++------------ include/asm-generic/pgtable.h | 10 +++++++++ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h index 43876f16caf..cb00ccc7d57 100644 --- a/arch/x86/include/asm/pgtable-3level.h +++ b/arch/x86/include/asm/pgtable-3level.h @@ -47,16 +47,26 @@ static inline void native_set_pte(pte_t *ptep, pte_t pte) * they can run pmd_offset_map_lock or pmd_trans_huge or other pmd * operations. * - * Without THP if the mmap_sem is hold for reading, the - * pmd can only transition from null to not null while pmd_read_atomic runs. - * So there's no need of literally reading it atomically. + * Without THP if the mmap_sem is hold for reading, the pmd can only + * transition from null to not null while pmd_read_atomic runs. So + * we can always return atomic pmd values with this function. * * With THP if the mmap_sem is hold for reading, the pmd can become - * THP or null or point to a pte (and in turn become "stable") at any - * time under pmd_read_atomic, so it's mandatory to read it atomically - * with cmpxchg8b. + * trans_huge or none or point to a pte (and in turn become "stable") + * at any time under pmd_read_atomic. We could read it really + * atomically here with a atomic64_read for the THP enabled case (and + * it would be a whole lot simpler), but to avoid using cmpxchg8b we + * only return an atomic pmdval if the low part of the pmdval is later + * found stable (i.e. pointing to a pte). And we're returning a none + * pmdval if the low part of the pmd is none. In some cases the high + * and low part of the pmdval returned may not be consistent if THP is + * enabled (the low part may point to previously mapped hugepage, + * while the high part may point to a more recently mapped hugepage), + * but pmd_none_or_trans_huge_or_clear_bad() only needs the low part + * of the pmd to be read atomically to decide if the pmd is unstable + * or not, with the only exception of when the low part of the pmd is + * zero in which case we return a none pmd. */ -#ifndef CONFIG_TRANSPARENT_HUGEPAGE static inline pmd_t pmd_read_atomic(pmd_t *pmdp) { pmdval_t ret; @@ -74,12 +84,6 @@ static inline pmd_t pmd_read_atomic(pmd_t *pmdp) return (pmd_t) { ret }; } -#else /* CONFIG_TRANSPARENT_HUGEPAGE */ -static inline pmd_t pmd_read_atomic(pmd_t *pmdp) -{ - return (pmd_t) { atomic64_read((atomic64_t *)pmdp) }; -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) { diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index fa596d9f9c2..c7ec2cdc904 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -485,6 +485,16 @@ static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd) /* * The barrier will stabilize the pmdval in a register or on * the stack so that it will stop changing under the code. + * + * When CONFIG_TRANSPARENT_HUGEPAGE=y on x86 32bit PAE, + * pmd_read_atomic is allowed to return a not atomic pmdval + * (for example pointing to an hugepage that has never been + * mapped in the pmd). The below checks will only care about + * the low part of the pmd with 32bit PAE x86 anyway, with the + * exception of pmd_none(). So the important thing is that if + * the low part of the pmd is found null, the high part will + * be also null or the pmd_none() check below would be + * confused. */ #ifdef CONFIG_TRANSPARENT_HUGEPAGE barrier(); From 21359ac3aef0455038f6295d6f8b3aca7beabfd9 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 16 May 2012 11:06:21 +0200 Subject: [PATCH 0449/2357] rtl8187: ->brightness_set can not sleep commit 0fde0a8cfd0ede7f310d6a681c8e5a7cb3e32406 upstream. Fix: BUG: sleeping function called from invalid context at kernel/workqueue.c:2547 in_atomic(): 1, irqs_disabled(): 0, pid: 629, name: wpa_supplicant 2 locks held by wpa_supplicant/629: #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x14/0x20 #1: (&trigger->leddev_list_lock){.+.?..}, at: [] led_trigger_event+0x21/0x80 Pid: 629, comm: wpa_supplicant Not tainted 3.3.0-0.rc3.git5.1.fc17.i686 Call Trace: [] __might_sleep+0x126/0x1d0 [] wait_on_work+0x2c/0x1d0 [] __cancel_work_timer+0x6a/0x120 [] cancel_delayed_work_sync+0x10/0x20 [] rtl8187_led_brightness_set+0x82/0xf0 [rtl8187] [] led_trigger_event+0x5c/0x80 [] ieee80211_led_radio+0x1d/0x40 [mac80211] [] ieee80211_stop_device+0x13/0x230 [mac80211] Removing _sync is ok, because if led_on work is currently running it will be finished before led_off work start to perform, since they are always queued on the same mac80211 local->workqueue. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=795176 Signed-off-by: Stanislaw Gruszka Acked-by: Larry Finger Acked-by: Hin-Tak Leung Signed-off-by: John W. Linville Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtl818x/rtl8187/leds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtl818x/rtl8187/leds.c b/drivers/net/wireless/rtl818x/rtl8187/leds.c index 2e0de2f5f0f..c2d5b495c17 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/leds.c +++ b/drivers/net/wireless/rtl818x/rtl8187/leds.c @@ -117,7 +117,7 @@ static void rtl8187_led_brightness_set(struct led_classdev *led_dev, radio_on = true; } else if (radio_on) { radio_on = false; - cancel_delayed_work_sync(&priv->led_on); + cancel_delayed_work(&priv->led_on); ieee80211_queue_delayed_work(hw, &priv->led_off, 0); } } else if (radio_on) { From 6d0535e8f0406ba353c06a5417e9caa498733372 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 2 May 2012 11:42:15 +0800 Subject: [PATCH 0450/2357] macvtap: zerocopy: validate vectors before building skb commit b92946e2919134ebe2a4083e4302236295ea2a73 upstream. There're several reasons that the vectors need to be validated: - Return error when caller provides vectors whose num is greater than UIO_MAXIOV. - Linearize part of skb when userspace provides vectors grater than MAX_SKB_FRAGS. - Return error when userspace provides vectors whose total length may exceed - MAX_SKB_FRAGS * PAGE_SIZE. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/net/macvtap.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index cb8fd5069db..c1d602d5f15 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -528,9 +528,10 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, } base = (unsigned long)from->iov_base + offset1; size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT; + if (i + size > MAX_SKB_FRAGS) + return -EMSGSIZE; num_pages = get_user_pages_fast(base, size, 0, &page[i]); - if ((num_pages != size) || - (num_pages > MAX_SKB_FRAGS - skb_shinfo(skb)->nr_frags)) + if (num_pages != size) /* put_page is in skb free */ return -EFAULT; skb->data_len += len; @@ -647,7 +648,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, int err; struct virtio_net_hdr vnet_hdr = { 0 }; int vnet_hdr_len = 0; - int copylen; + int copylen = 0; bool zerocopy = false; if (q->flags & IFF_VNET_HDR) { @@ -676,15 +677,31 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, if (unlikely(len < ETH_HLEN)) goto err; + err = -EMSGSIZE; + if (unlikely(count > UIO_MAXIOV)) + goto err; + if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) zerocopy = true; if (zerocopy) { + /* Userspace may produce vectors with count greater than + * MAX_SKB_FRAGS, so we need to linearize parts of the skb + * to let the rest of data to be fit in the frags. + */ + if (count > MAX_SKB_FRAGS) { + copylen = iov_length(iv, count - MAX_SKB_FRAGS); + if (copylen < vnet_hdr_len) + copylen = 0; + else + copylen -= vnet_hdr_len; + } /* There are 256 bytes to be copied in skb, so there is enough * room for skb expand head in case it is used. * The rest buffer is mapped from userspace. */ - copylen = vnet_hdr.hdr_len; + if (copylen < vnet_hdr.hdr_len) + copylen = vnet_hdr.hdr_len; if (!copylen) copylen = GOODCOPY_LEN; } else From 5318edefb61eddf91d4c4a089644fcee3ccfda62 Mon Sep 17 00:00:00 2001 From: Stanislav Yakovlev Date: Tue, 10 Apr 2012 21:44:47 -0400 Subject: [PATCH 0451/2357] net/wireless: ipw2x00: add supported cipher suites to wiphy initialization commit a141e6a0097118bb35024485f1faffc0d9042f5c upstream. Driver doesn't report its supported cipher suites through cfg80211 interface. It still uses wext interface and probably will not work through nl80211, but will at least correctly advertise supported features. Bug was reported by Omar Siam. https://bugzilla.kernel.org/show_bug.cgi?id=43049 Signed-off-by: Stanislav Yakovlev Signed-off-by: John W. Linville Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ipw2x00/ipw.h | 23 +++++++++++++++++++++++ drivers/net/wireless/ipw2x00/ipw2100.c | 4 ++++ drivers/net/wireless/ipw2x00/ipw2200.c | 4 ++++ 3 files changed, 31 insertions(+) create mode 100644 drivers/net/wireless/ipw2x00/ipw.h diff --git a/drivers/net/wireless/ipw2x00/ipw.h b/drivers/net/wireless/ipw2x00/ipw.h new file mode 100644 index 00000000000..4007bf5ed6f --- /dev/null +++ b/drivers/net/wireless/ipw2x00/ipw.h @@ -0,0 +1,23 @@ +/* + * Intel Pro/Wireless 2100, 2200BG, 2915ABG network connection driver + * + * Copyright 2012 Stanislav Yakovlev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __IPW_H__ +#define __IPW_H__ + +#include + +static const u32 ipw_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + +#endif diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index f0551f807f6..7c8e8b11054 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -166,6 +166,7 @@ that only one external action is invoked at a time. #include #include "ipw2100.h" +#include "ipw.h" #define IPW2100_VERSION "git-1.2.2" @@ -1946,6 +1947,9 @@ static int ipw2100_wdev_init(struct net_device *dev) wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band; } + wdev->wiphy->cipher_suites = ipw_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites); + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); if (wiphy_register(wdev->wiphy)) { ipw2100_down(priv); diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 1779db3aa2b..3a6b991f023 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -34,6 +34,7 @@ #include #include #include "ipw2200.h" +#include "ipw.h" #ifndef KBUILD_EXTMOD @@ -11544,6 +11545,9 @@ static int ipw_wdev_init(struct net_device *dev) wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band; } + wdev->wiphy->cipher_suites = ipw_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites); + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); /* With that information in place, we can now register the wiphy... */ From 2c07f25ea7800adb36cd8da9b58c4ecd3fc3d064 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 Jun 2012 15:24:40 +0200 Subject: [PATCH 0452/2357] splice: fix racy pipe->buffers uses commit 047fe3605235888f3ebcda0c728cb31937eadfe6 upstream. Dave Jones reported a kernel BUG at mm/slub.c:3474! triggered by splice_shrink_spd() called from vmsplice_to_pipe() commit 35f3d14dbbc5 (pipe: add support for shrinking and growing pipes) added capability to adjust pipe->buffers. Problem is some paths don't hold pipe mutex and assume pipe->buffers doesn't change for their duration. Fix this by adding nr_pages_max field in struct splice_pipe_desc, and use it in place of pipe->buffers where appropriate. splice_shrink_spd() loses its struct pipe_inode_info argument. Reported-by: Dave Jones Signed-off-by: Eric Dumazet Cc: Jens Axboe Cc: Alexander Viro Cc: Tom Herbert Tested-by: Dave Jones Signed-off-by: Jens Axboe [bwh: Backported to 3.2: - Adjust context in vmsplice_to_pipe() - Update one more call to splice_shrink_spd(), from skb_splice_bits()] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- fs/splice.c | 35 ++++++++++++++++++++--------------- include/linux/splice.h | 8 ++++---- kernel/relay.c | 5 +++-- kernel/trace/trace.c | 6 ++++-- mm/shmem.c | 3 ++- net/core/skbuff.c | 3 ++- 6 files changed, 35 insertions(+), 25 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index f8476841eb0..5cac690f810 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -273,13 +273,16 @@ void spd_release_page(struct splice_pipe_desc *spd, unsigned int i) * Check if we need to grow the arrays holding pages and partial page * descriptions. */ -int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) +int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) { - if (pipe->buffers <= PIPE_DEF_BUFFERS) + unsigned int buffers = ACCESS_ONCE(pipe->buffers); + + spd->nr_pages_max = buffers; + if (buffers <= PIPE_DEF_BUFFERS) return 0; - spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL); - spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL); + spd->pages = kmalloc(buffers * sizeof(struct page *), GFP_KERNEL); + spd->partial = kmalloc(buffers * sizeof(struct partial_page), GFP_KERNEL); if (spd->pages && spd->partial) return 0; @@ -289,10 +292,9 @@ int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) return -ENOMEM; } -void splice_shrink_spd(struct pipe_inode_info *pipe, - struct splice_pipe_desc *spd) +void splice_shrink_spd(struct splice_pipe_desc *spd) { - if (pipe->buffers <= PIPE_DEF_BUFFERS) + if (spd->nr_pages_max <= PIPE_DEF_BUFFERS) return; kfree(spd->pages); @@ -315,6 +317,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, struct splice_pipe_desc spd = { .pages = pages, .partial = partial, + .nr_pages_max = PIPE_DEF_BUFFERS, .flags = flags, .ops = &page_cache_pipe_buf_ops, .spd_release = spd_release_page, @@ -326,7 +329,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, index = *ppos >> PAGE_CACHE_SHIFT; loff = *ppos & ~PAGE_CACHE_MASK; req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - nr_pages = min(req_pages, pipe->buffers); + nr_pages = min(req_pages, spd.nr_pages_max); /* * Lookup the (hopefully) full range of pages we need. @@ -497,7 +500,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, if (spd.nr_pages) error = splice_to_pipe(pipe, &spd); - splice_shrink_spd(pipe, &spd); + splice_shrink_spd(&spd); return error; } @@ -598,6 +601,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, struct splice_pipe_desc spd = { .pages = pages, .partial = partial, + .nr_pages_max = PIPE_DEF_BUFFERS, .flags = flags, .ops = &default_pipe_buf_ops, .spd_release = spd_release_page, @@ -608,8 +612,8 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, res = -ENOMEM; vec = __vec; - if (pipe->buffers > PIPE_DEF_BUFFERS) { - vec = kmalloc(pipe->buffers * sizeof(struct iovec), GFP_KERNEL); + if (spd.nr_pages_max > PIPE_DEF_BUFFERS) { + vec = kmalloc(spd.nr_pages_max * sizeof(struct iovec), GFP_KERNEL); if (!vec) goto shrink_ret; } @@ -617,7 +621,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, offset = *ppos & ~PAGE_CACHE_MASK; nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - for (i = 0; i < nr_pages && i < pipe->buffers && len; i++) { + for (i = 0; i < nr_pages && i < spd.nr_pages_max && len; i++) { struct page *page; page = alloc_page(GFP_USER); @@ -665,7 +669,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, shrink_ret: if (vec != __vec) kfree(vec); - splice_shrink_spd(pipe, &spd); + splice_shrink_spd(&spd); return res; err: @@ -1612,6 +1616,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, struct splice_pipe_desc spd = { .pages = pages, .partial = partial, + .nr_pages_max = PIPE_DEF_BUFFERS, .flags = flags, .ops = &user_page_pipe_buf_ops, .spd_release = spd_release_page, @@ -1627,13 +1632,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages, spd.partial, flags & SPLICE_F_GIFT, - pipe->buffers); + spd.nr_pages_max); if (spd.nr_pages <= 0) ret = spd.nr_pages; else ret = splice_to_pipe(pipe, &spd); - splice_shrink_spd(pipe, &spd); + splice_shrink_spd(&spd); return ret; } diff --git a/include/linux/splice.h b/include/linux/splice.h index 26e5b613ded..09a545a7dfa 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -51,7 +51,8 @@ struct partial_page { struct splice_pipe_desc { struct page **pages; /* page map */ struct partial_page *partial; /* pages[] may not be contig */ - int nr_pages; /* number of pages in map */ + int nr_pages; /* number of populated pages in map */ + unsigned int nr_pages_max; /* pages[] & partial[] arrays size */ unsigned int flags; /* splice flags */ const struct pipe_buf_operations *ops;/* ops associated with output pipe */ void (*spd_release)(struct splice_pipe_desc *, unsigned int); @@ -85,9 +86,8 @@ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, /* * for dynamic pipe sizing */ -extern int splice_grow_spd(struct pipe_inode_info *, struct splice_pipe_desc *); -extern void splice_shrink_spd(struct pipe_inode_info *, - struct splice_pipe_desc *); +extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *); +extern void splice_shrink_spd(struct splice_pipe_desc *); extern void spd_release_page(struct splice_pipe_desc *, unsigned int); extern const struct pipe_buf_operations page_cache_pipe_buf_ops; diff --git a/kernel/relay.c b/kernel/relay.c index ab56a1764d4..e8cd2027abb 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -1235,6 +1235,7 @@ static ssize_t subbuf_splice_actor(struct file *in, struct splice_pipe_desc spd = { .pages = pages, .nr_pages = 0, + .nr_pages_max = PIPE_DEF_BUFFERS, .partial = partial, .flags = flags, .ops = &relay_pipe_buf_ops, @@ -1302,8 +1303,8 @@ static ssize_t subbuf_splice_actor(struct file *in, ret += padding; out: - splice_shrink_spd(pipe, &spd); - return ret; + splice_shrink_spd(&spd); + return ret; } static ssize_t relay_file_splice_read(struct file *in, diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 5fc7bfa0ccb..55e4d4c5313 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3565,6 +3565,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, .pages = pages_def, .partial = partial_def, .nr_pages = 0, /* This gets updated below. */ + .nr_pages_max = PIPE_DEF_BUFFERS, .flags = flags, .ops = &tracing_pipe_buf_ops, .spd_release = tracing_spd_release_pipe, @@ -3636,7 +3637,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, ret = splice_to_pipe(pipe, &spd); out: - splice_shrink_spd(pipe, &spd); + splice_shrink_spd(&spd); return ret; out_err: @@ -4126,6 +4127,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, struct splice_pipe_desc spd = { .pages = pages_def, .partial = partial_def, + .nr_pages_max = PIPE_DEF_BUFFERS, .flags = flags, .ops = &buffer_pipe_buf_ops, .spd_release = buffer_spd_release, @@ -4213,7 +4215,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, } ret = splice_to_pipe(pipe, &spd); - splice_shrink_spd(pipe, &spd); + splice_shrink_spd(&spd); out: return ret; } diff --git a/mm/shmem.c b/mm/shmem.c index f99ff3e50bd..9d65a02a879 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1365,6 +1365,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos, struct splice_pipe_desc spd = { .pages = pages, .partial = partial, + .nr_pages_max = PIPE_DEF_BUFFERS, .flags = flags, .ops = &page_cache_pipe_buf_ops, .spd_release = spd_release_page, @@ -1453,7 +1454,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos, if (spd.nr_pages) error = splice_to_pipe(pipe, &spd); - splice_shrink_spd(pipe, &spd); + splice_shrink_spd(&spd); if (error > 0) { *ppos += error; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index e59840010d4..e99aedd9c49 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1712,6 +1712,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, struct splice_pipe_desc spd = { .pages = pages, .partial = partial, + .nr_pages_max = MAX_SKB_FRAGS, .flags = flags, .ops = &sock_pipe_buf_ops, .spd_release = sock_spd_release, @@ -1758,7 +1759,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, lock_sock(sk); } - splice_shrink_spd(pipe, &spd); + splice_shrink_spd(&spd); return ret; } From a08fae601d01ab177dbef90778f87f7c5467b792 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Apr 2012 11:56:03 +0100 Subject: [PATCH 0453/2357] drm/i915: Refactor the deferred PM_IIR handling into a single function commit fc6826d1dcd65f3d1e9a5377678882e4e08f02be upstream. This function, along with the registers and deferred work hander, are all shared with SandyBridge, IvyBridge and their variants. So remove the duplicate code into a single function. Signed-off-by: Chris Wilson Reviewed-by: Ben Widawsky Signed-Off-by: Daniel Vetter [bwh: Backported to 3.2: adjust context; drop changes for Valley View] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_irq.c | 58 ++++++++++++++++----------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f57e5cfb162..7e5a9653515 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -424,6 +424,31 @@ static void gen6_pm_rps_work(struct work_struct *work) mutex_unlock(&dev_priv->dev->struct_mutex); } +static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, + u32 pm_iir) +{ + unsigned long flags; + + /* + * IIR bits should never already be set because IMR should + * prevent an interrupt from being shown in IIR. The warning + * displays a case where we've unsafely cleared + * dev_priv->pm_iir. Although missing an interrupt of the same + * type is not a problem, it displays a problem in the logic. + * + * The mask bit in IMR is cleared by rps_work. + */ + + spin_lock_irqsave(&dev_priv->rps_lock, flags); + WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); + dev_priv->pm_iir |= pm_iir; + I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); + POSTING_READ(GEN6_PMIMR); + spin_unlock_irqrestore(&dev_priv->rps_lock, flags); + + queue_work(dev_priv->wq, &dev_priv->rps_work); +} + static void pch_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -529,16 +554,8 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) pch_irq_handler(dev, pch_iir); } - if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { - unsigned long flags; - spin_lock_irqsave(&dev_priv->rps_lock, flags); - WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); - dev_priv->pm_iir |= pm_iir; - I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); - POSTING_READ(GEN6_PMIMR); - spin_unlock_irqrestore(&dev_priv->rps_lock, flags); - queue_work(dev_priv->wq, &dev_priv->rps_work); - } + if (pm_iir & GEN6_PM_DEFERRED_EVENTS) + gen6_queue_rps_work(dev_priv, pm_iir); /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); @@ -634,25 +651,8 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) i915_handle_rps_change(dev); } - if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) { - /* - * IIR bits should never already be set because IMR should - * prevent an interrupt from being shown in IIR. The warning - * displays a case where we've unsafely cleared - * dev_priv->pm_iir. Although missing an interrupt of the same - * type is not a problem, it displays a problem in the logic. - * - * The mask bit in IMR is cleared by rps_work. - */ - unsigned long flags; - spin_lock_irqsave(&dev_priv->rps_lock, flags); - WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); - dev_priv->pm_iir |= pm_iir; - I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); - POSTING_READ(GEN6_PMIMR); - spin_unlock_irqrestore(&dev_priv->rps_lock, flags); - queue_work(dev_priv->wq, &dev_priv->rps_work); - } + if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) + gen6_queue_rps_work(dev_priv, pm_iir); /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); From c9bb51fb8c7a9d8b230c0bd184d9af919350383b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 21 Jun 2012 14:55:22 +0200 Subject: [PATCH 0454/2357] drm/i915: rip out the PM_IIR WARN commit 58bf8062d0b293b8e1028e5b0342082002886bd4 upstream. After banging my head against this for the past few months, I still don't see how this could possible race under the premise that once an irq bit is masked in PM_IMR and reset in PM_IIR it won't show up again until we unmask it in PM_IMR. Still, we have reports of this being seen in the wild. Now Bspec has this little bit of lovely language in the PMIIR register: Public SNB Docs, Vol3Part2, 2.5.14 "PMIIR": "For each bit, the IIR can store a second pending interrupt if two or more of the same interrupt conditions occur before the first condition is cleared. Upon clearing the interrupt, the IIR bit will momentarily go low, then return high to indicate there is another interrupt pending." Now if we presume that PMIMR only prevent new interrupts from being queued, we could easily end up masking an interrupt and clearing it, but the 2nd pending interrupt setting the bit in PMIIR right away again. Which leads, the next time the irq handler runs, to hitting the WARN. Also, no bad side effects of this have ever been reported. And we've tracked down our issues with the gpu turbo getting stuck to bogus interrupt generation limits in th RPLIMIT register. So let's just rip out this WARN as bogus and call it a day. The only shallow thing here is that this 2-deep irq queue in the hw makes you wonder how racy the windows irq handler is ... Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42907 Acked-by: Chris Wilson Signed-Off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_irq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7e5a9653515..26c67a78877 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -440,7 +440,6 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, */ spin_lock_irqsave(&dev_priv->rps_lock, flags); - WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); dev_priv->pm_iir |= pm_iir; I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); POSTING_READ(GEN6_PMIMR); From 0c4ad5cc8c01f62fe5211b5ce9563c27f795a4ab Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 5 Jul 2012 16:00:11 -0700 Subject: [PATCH 0455/2357] mm: Hold a file reference in madvise_remove commit 9ab4233dd08036fe34a89c7dc6f47a8bf2eb29eb upstream. Otherwise the code races with munmap (causing a use-after-free of the vma) or with close (causing a use-after-free of the struct file). The bug was introduced by commit 90ed52ebe481 ("[PATCH] holepunch: fix mmap_sem i_mutex deadlock") Cc: Hugh Dickins Cc: Miklos Szeredi Cc: Badari Pulavarty Cc: Nick Piggin Signed-off-by: Andy Lutomirski Signed-off-by: Linus Torvalds [bwh: Backported to 3.2: - Adjust context - madvise_remove() calls vmtruncate_range(), not do_fallocate()] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- mm/madvise.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mm/madvise.c b/mm/madvise.c index 1ccbba5b667..55f645c85a3 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -13,6 +13,7 @@ #include #include #include +#include /* * Any behaviour which results in changes to the vma->vm_flags needs to @@ -203,14 +204,16 @@ static long madvise_remove(struct vm_area_struct *vma, struct address_space *mapping; loff_t offset, endoff; int error; + struct file *f; *prev = NULL; /* tell sys_madvise we drop mmap_sem */ if (vma->vm_flags & (VM_LOCKED|VM_NONLINEAR|VM_HUGETLB)) return -EINVAL; - if (!vma->vm_file || !vma->vm_file->f_mapping - || !vma->vm_file->f_mapping->host) { + f = vma->vm_file; + + if (!f || !f->f_mapping || !f->f_mapping->host) { return -EINVAL; } @@ -224,9 +227,16 @@ static long madvise_remove(struct vm_area_struct *vma, endoff = (loff_t)(end - vma->vm_start - 1) + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); - /* vmtruncate_range needs to take i_mutex */ + /* + * vmtruncate_range may need to take i_mutex. We need to + * explicitly grab a reference because the vma (and hence the + * vma's reference to the file) can go away as soon as we drop + * mmap_sem. + */ + get_file(f); up_read(¤t->mm->mmap_sem); error = vmtruncate_range(mapping->host, offset, endoff); + fput(f); down_read(¤t->mm->mmap_sem); return error; } From d3f940223c31cffd977864cdc13c69e89f03ce55 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Tue, 12 Jun 2012 08:31:10 +0800 Subject: [PATCH 0456/2357] md/raid5: Do not add data_offset before call to is_badblock commit 6c0544e255dd6582a9899572e120fb55d9f672a4 upstream. In chunk_aligned_read() we are adding data_offset before calling is_badblock. But is_badblock also adds data_offset, so that is bad. So move the addition of data_offset to after the call to is_badblock. This bug was introduced by commit 31c176ecdf3563140e639 md/raid5: avoid reading from known bad blocks. which first appeared in 3.0. So that patch is suitable for any -stable kernel from 3.0.y onwards. However it will need minor revision for most of those (as the comment didn't appear until recently). Signed-off-by: majianpeng Signed-off-by: NeilBrown [bwh: Backported to 3.2: ignored missing comment] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 23e501518c4..73a58007eb9 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3850,7 +3850,6 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) raid_bio->bi_next = (void*)rdev; align_bi->bi_bdev = rdev->bdev; align_bi->bi_flags &= ~(1 << BIO_SEG_VALID); - align_bi->bi_sector += rdev->data_offset; if (!bio_fits_rdev(align_bi) || is_badblock(rdev, align_bi->bi_sector, align_bi->bi_size>>9, @@ -3861,6 +3860,9 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) return 0; } + /* No reshape active, so we can trust rdev->data_offset */ + align_bi->bi_sector += rdev->data_offset; + spin_lock_irq(&conf->device_lock); wait_event_lock_irq(conf->wait_for_stripe, conf->quiesce == 0, From a2db97f10ba81ce924323e580a223ce8d17d685c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 5 Jun 2012 18:16:31 +0200 Subject: [PATCH 0457/2357] staging:iio:ad7606: Re-add missing scale attribute commit 279bf2e57c30c9a4482b2b6ede11b31c41e35e78 upstream. Commit 50ac23be ("staging:iio:adc:ad7606 add local define for chan_spec structures.") accidentally removed the scale info_mask flag. This patch adds it back again. Signed-off-by: Lars-Peter Clausen Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman [herton: Backported to 3.4: info_mask was not used yet with another flag] Signed-off-by: Herton R. Krzesinski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/ad7606_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 97e8d3d4471..7322c168be4 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -235,6 +235,7 @@ static const struct attribute_group ad7606_attribute_group_range = { .indexed = 1, \ .channel = num, \ .address = num, \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .scan_index = num, \ .scan_type = IIO_ST('s', 16, 16, 0), \ } From 0e343dbe08acb440f7914d989bcc32c1d1576735 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 11 Jul 2012 14:01:52 -0700 Subject: [PATCH 0458/2357] memory hotplug: fix invalid memory access caused by stale kswapd pointer commit d8adde17e5f858427504725218c56aef90e90fc7 upstream. kswapd_stop() is called to destroy the kswapd work thread when all memory of a NUMA node has been offlined. But kswapd_stop() only terminates the work thread without resetting NODE_DATA(nid)->kswapd to NULL. The stale pointer will prevent kswapd_run() from creating a new work thread when adding memory to the memory-less NUMA node again. Eventually the stale pointer may cause invalid memory access. An example stack dump as below. It's reproduced with 2.6.32, but latest kernel has the same issue. BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] exit_creds+0x12/0x78 PGD 0 Oops: 0000 [#1] SMP last sysfs file: /sys/devices/system/memory/memory391/state CPU 11 Modules linked in: cpufreq_conservative cpufreq_userspace cpufreq_powersave acpi_cpufreq microcode fuse loop dm_mod tpm_tis rtc_cmos i2c_i801 rtc_core tpm serio_raw pcspkr sg tpm_bios igb i2c_core iTCO_wdt rtc_lib mptctl iTCO_vendor_support button dca bnx2 usbhid hid uhci_hcd ehci_hcd usbcore sd_mod crc_t10dif edd ext3 mbcache jbd fan ide_pci_generic ide_core ata_generic ata_piix libata thermal processor thermal_sys hwmon mptsas mptscsih mptbase scsi_transport_sas scsi_mod Pid: 7949, comm: sh Not tainted 2.6.32.12-qiuxishi-5-default #92 Tecal RH2285 RIP: 0010:exit_creds+0x12/0x78 RSP: 0018:ffff8806044f1d78 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ffff880604f22140 RCX: 0000000000019502 RDX: 0000000000000000 RSI: 0000000000000202 RDI: 0000000000000000 RBP: ffff880604f22150 R08: 0000000000000000 R09: ffffffff81a4dc10 R10: 00000000000032a0 R11: ffff880006202500 R12: 0000000000000000 R13: 0000000000c40000 R14: 0000000000008000 R15: 0000000000000001 FS: 00007fbc03d066f0(0000) GS:ffff8800282e0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000000 CR3: 000000060f029000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process sh (pid: 7949, threadinfo ffff8806044f0000, task ffff880603d7c600) Stack: ffff880604f22140 ffffffff8103aac5 ffff880604f22140 ffffffff8104d21e ffff880006202500 0000000000008000 0000000000c38000 ffffffff810bd5b1 0000000000000000 ffff880603d7c600 00000000ffffdd29 0000000000000003 Call Trace: __put_task_struct+0x5d/0x97 kthread_stop+0x50/0x58 offline_pages+0x324/0x3da memory_block_change_state+0x179/0x1db store_mem_state+0x9e/0xbb sysfs_write_file+0xd0/0x107 vfs_write+0xad/0x169 sys_write+0x45/0x6e system_call_fastpath+0x16/0x1b Code: ff 4d 00 0f 94 c0 84 c0 74 08 48 89 ef e8 1f fd ff ff 5b 5d 31 c0 41 5c c3 53 48 8b 87 20 06 00 00 48 89 fb 48 8b bf 18 06 00 00 <8b> 00 48 c7 83 18 06 00 00 00 00 00 00 f0 ff 0f 0f 94 c0 84 c0 RIP exit_creds+0x12/0x78 RSP CR2: 0000000000000000 [akpm@linux-foundation.org: add pglist_data.kswapd locking comments] Signed-off-by: Xishi Qiu Signed-off-by: Jiang Liu Acked-by: KAMEZAWA Hiroyuki Acked-by: KOSAKI Motohiro Acked-by: Mel Gorman Acked-by: David Rientjes Reviewed-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/mmzone.h | 2 +- mm/vmscan.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index dff71150966..5f6806bd6ac 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -663,7 +663,7 @@ typedef struct pglist_data { range, including holes */ int node_id; wait_queue_head_t kswapd_wait; - struct task_struct *kswapd; + struct task_struct *kswapd; /* Protected by lock_memory_hotplug() */ int kswapd_max_order; enum zone_type classzone_idx; } pg_data_t; diff --git a/mm/vmscan.c b/mm/vmscan.c index 0932dc27e19..4607cc62b1d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -3279,14 +3279,17 @@ int kswapd_run(int nid) } /* - * Called by memory hotplug when all memory in a node is offlined. + * Called by memory hotplug when all memory in a node is offlined. Caller must + * hold lock_memory_hotplug(). */ void kswapd_stop(int nid) { struct task_struct *kswapd = NODE_DATA(nid)->kswapd; - if (kswapd) + if (kswapd) { kthread_stop(kswapd); + NODE_DATA(nid)->kswapd = NULL; + } } static int __init kswapd_init(void) From 0bf51a8f8756511b382aac13a3c1c7abeb8b0bec Mon Sep 17 00:00:00 2001 From: Devendra Naga Date: Wed, 11 Jul 2012 14:01:53 -0700 Subject: [PATCH 0459/2357] drivers/rtc/rtc-spear.c: fix use-after-free in spear_rtc_remove() commit 2a643893e50fde71d7ba84b5592ec61b467b9ab6 upstream. `config' is freed and is then used in the rtc_device_unregister() call, causing a kernel panic. Signed-off-by: Devendra Naga Reviewed-by: Viresh Kumar Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-spear.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index e38da0dc418..235b0efaa34 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -457,12 +457,12 @@ static int __devexit spear_rtc_remove(struct platform_device *pdev) clk_disable(config->clk); clk_put(config->clk); iounmap(config->ioaddr); - kfree(config); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) release_mem_region(res->start, resource_size(res)); platform_set_drvdata(pdev, NULL); rtc_device_unregister(config->rtc); + kfree(config); return 0; } From a61046645665398124b7353999713c02fc4a89eb Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 11 Jul 2012 14:02:16 -0700 Subject: [PATCH 0460/2357] drivers/rtc/rtc-ab8500.c: use IRQF_ONESHOT when requesting a threaded IRQ commit 3cfd16a551dc0c188160e1765168a04baf2d3198 upstream. This driver's IRQ registration is failing because the kernel now forces IRQs to be ONESHOT if no IRQ handler is passed. Signed-off-by: Lee Jones Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-ab8500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 4bcf9ca2818..b11a2ecef3f 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -422,7 +422,7 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev) } err = request_threaded_irq(irq, NULL, rtc_alarm_handler, - IRQF_NO_SUSPEND, "ab8500-rtc", rtc); + IRQF_NO_SUSPEND | IRQF_ONESHOT, "ab8500-rtc", rtc); if (err < 0) { rtc_device_unregister(rtc); return err; From ae555e19b697bc90ea3ec004dc0e5541983593fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Wed, 11 Jul 2012 14:02:32 -0700 Subject: [PATCH 0461/2357] drivers/rtc/rtc-mxc.c: fix irq enabled interrupts warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b59f6d1febd6cbe9fae4589bf72da0ed32bc69e0 upstream. Fixes WARNING: at irq/handle.c:146 handle_irq_event_percpu+0x19c/0x1b8() irq 25 handler mxc_rtc_interrupt+0x0/0xac enabled interrupts Modules linked in: (unwind_backtrace+0x0/0xf0) from (warn_slowpath_common+0x4c/0x64) (warn_slowpath_common+0x4c/0x64) from (warn_slowpath_fmt+0x30/0x40) (warn_slowpath_fmt+0x30/0x40) from (handle_irq_event_percpu+0x19c/0x1b8) (handle_irq_event_percpu+0x19c/0x1b8) from (handle_irq_event+0x28/0x38) (handle_irq_event+0x28/0x38) from (handle_level_irq+0x80/0xc4) (handle_level_irq+0x80/0xc4) from (generic_handle_irq+0x24/0x38) (generic_handle_irq+0x24/0x38) from (handle_IRQ+0x30/0x84) (handle_IRQ+0x30/0x84) from (avic_handle_irq+0x2c/0x4c) (avic_handle_irq+0x2c/0x4c) from (__irq_svc+0x40/0x60) Exception stack(0xc050bf60 to 0xc050bfa8) bf60: 00000001 00000000 003c4208 c0018e20 c050a000 c050a000 c054a4c8 c050a000 bf80: c05157a8 4117b363 80503bb4 00000000 01000000 c050bfa8 c0018e2c c000e808 bfa0: 60000013 ffffffff (__irq_svc+0x40/0x60) from (default_idle+0x1c/0x30) (default_idle+0x1c/0x30) from (cpu_idle+0x68/0xa8) (cpu_idle+0x68/0xa8) from (start_kernel+0x22c/0x26c) Signed-off-by: Benoît Thébaudeau Cc: Alessandro Zummo Cc: Sascha Hauer Acked-by: Uwe Kleine-König Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-mxc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 5e1d64ee522..e3e50d69baf 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -202,10 +202,11 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id) struct platform_device *pdev = dev_id; struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; + unsigned long flags; u32 status; u32 events = 0; - spin_lock_irq(&pdata->rtc->irq_lock); + spin_lock_irqsave(&pdata->rtc->irq_lock, flags); status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR); /* clear interrupt sources */ writew(status, ioaddr + RTC_RTCISR); @@ -224,7 +225,7 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id) events |= (RTC_PF | RTC_IRQF); rtc_update_irq(pdata->rtc, 1, events); - spin_unlock_irq(&pdata->rtc->irq_lock); + spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); return IRQ_HANDLED; } From 7a08b440fa93e036968102597c8a2ab809a9bdc4 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Wed, 11 Jul 2012 14:02:13 -0700 Subject: [PATCH 0462/2357] mm, thp: abort compaction if migration page cannot be charged to memcg commit 4bf2bba3750f10aa9e62e6949bc7e8329990f01b upstream. If page migration cannot charge the temporary page to the memcg, migrate_pages() will return -ENOMEM. This isn't considered in memory compaction however, and the loop continues to iterate over all pageblocks trying to isolate and migrate pages. If a small number of very large memcgs happen to be oom, however, these attempts will mostly be futile leading to an enormous amout of cpu consumption due to the page migration failures. This patch will short circuit and fail memory compaction if migrate_pages() returns -ENOMEM. COMPACT_PARTIAL is returned in case some migrations were successful so that the page allocator will retry. Signed-off-by: David Rientjes Acked-by: Mel Gorman Cc: Minchan Kim Cc: Kamezawa Hiroyuki Cc: Rik van Riel Cc: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/compaction.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/compaction.c b/mm/compaction.c index 74a8c825ff2..459b0ab6052 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -594,8 +594,11 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) if (err) { putback_lru_pages(&cc->migratepages); cc->nr_migratepages = 0; + if (err == -ENOMEM) { + ret = COMPACT_PARTIAL; + goto out; + } } - } out: From 0fa627b15c842095b5147f381fa1943a6a46bb01 Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Wed, 11 Jul 2012 14:02:35 -0700 Subject: [PATCH 0463/2357] fs: ramfs: file-nommu: add SetPageUptodate() commit fea9f718b3d68147f162ed2d870183ce5e0ad8d8 upstream. There is a bug in the below scenario for !CONFIG_MMU: 1. create a new file 2. mmap the file and write to it 3. read the file can't get the correct value Because sys_read() -> generic_file_aio_read() -> simple_readpage() -> clear_page() which causes the page to be zeroed. Add SetPageUptodate() to ramfs_nommu_expand_for_mapping() so that generic_file_aio_read() do not call simple_readpage(). Signed-off-by: Bob Liu Cc: Hugh Dickins Cc: David Howells Cc: Geert Uytterhoeven Cc: Greg Ungerer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/ramfs/file-nommu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index fbb0b478a34..d5378d02858 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -110,6 +110,7 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) /* prevent the page from being discarded on memory pressure */ SetPageDirty(page); + SetPageUptodate(page); unlock_page(page); put_page(page); From 7ad71f960f0f6e06cbded278809674afc515036a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 11 Jul 2012 14:02:56 -0700 Subject: [PATCH 0464/2357] memblock: free allocated memblock_reserved_regions later commit 29f6738609e40227dabcc63bfb3b84b3726a75bd upstream. memblock_free_reserved_regions() calls memblock_free(), but memblock_free() would double reserved.regions too, so we could free the old range for reserved.regions. Also tj said there is another bug which could be related to this. | I don't think we're saving any noticeable | amount by doing this "free - give it to page allocator - reserve | again" dancing. We should just allocate regions aligned to page | boundaries and free them later when memblock is no longer in use. in that case, when DEBUG_PAGEALLOC, will get panic: memblock_free: [0x0000102febc080-0x0000102febf080] memblock_free_reserved_regions+0x37/0x39 BUG: unable to handle kernel paging request at ffff88102febd948 IP: [] __next_free_mem_range+0x9b/0x155 PGD 4826063 PUD cf67a067 PMD cf7fa067 PTE 800000102febd160 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC CPU 0 Pid: 0, comm: swapper Not tainted 3.5.0-rc2-next-20120614-sasha #447 RIP: 0010:[] [] __next_free_mem_range+0x9b/0x155 See the discussion at https://lkml.org/lkml/2012/6/13/469 So try to allocate with PAGE_SIZE alignment and free it later. Reported-by: Sasha Levin Acked-by: Tejun Heo Cc: Benjamin Herrenschmidt Signed-off-by: Yinghai Lu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/memblock.h | 4 +--- mm/memblock.c | 51 ++++++++++++++++++---------------------- mm/nobootmem.c | 38 ++++++++++++++++++------------ 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/include/linux/memblock.h b/include/linux/memblock.h index a6bb1023514..19dc455b4f3 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -50,9 +50,7 @@ phys_addr_t memblock_find_in_range_node(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid); phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align); -int memblock_free_reserved_regions(void); -int memblock_reserve_reserved_regions(void); - +phys_addr_t get_allocated_memblock_reserved_regions_info(phys_addr_t *addr); void memblock_allow_resize(void); int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid); int memblock_add(phys_addr_t base, phys_addr_t size); diff --git a/mm/memblock.c b/mm/memblock.c index 0e737d9ab2b..280d3d7835d 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -143,30 +143,6 @@ phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start, MAX_NUMNODES); } -/* - * Free memblock.reserved.regions - */ -int __init_memblock memblock_free_reserved_regions(void) -{ - if (memblock.reserved.regions == memblock_reserved_init_regions) - return 0; - - return memblock_free(__pa(memblock.reserved.regions), - sizeof(struct memblock_region) * memblock.reserved.max); -} - -/* - * Reserve memblock.reserved.regions - */ -int __init_memblock memblock_reserve_reserved_regions(void) -{ - if (memblock.reserved.regions == memblock_reserved_init_regions) - return 0; - - return memblock_reserve(__pa(memblock.reserved.regions), - sizeof(struct memblock_region) * memblock.reserved.max); -} - static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r) { type->total_size -= type->regions[r].size; @@ -184,6 +160,18 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u } } +phys_addr_t __init_memblock get_allocated_memblock_reserved_regions_info( + phys_addr_t *addr) +{ + if (memblock.reserved.regions == memblock_reserved_init_regions) + return 0; + + *addr = __pa(memblock.reserved.regions); + + return PAGE_ALIGN(sizeof(struct memblock_region) * + memblock.reserved.max); +} + /** * memblock_double_array - double the size of the memblock regions array * @type: memblock type of the regions array being doubled @@ -204,6 +192,7 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, phys_addr_t new_area_size) { struct memblock_region *new_array, *old_array; + phys_addr_t old_alloc_size, new_alloc_size; phys_addr_t old_size, new_size, addr; int use_slab = slab_is_available(); int *in_slab; @@ -217,6 +206,12 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, /* Calculate new doubled size */ old_size = type->max * sizeof(struct memblock_region); new_size = old_size << 1; + /* + * We need to allocated new one align to PAGE_SIZE, + * so we can free them completely later. + */ + old_alloc_size = PAGE_ALIGN(old_size); + new_alloc_size = PAGE_ALIGN(new_size); /* Retrieve the slab flag */ if (type == &memblock.memory) @@ -245,11 +240,11 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, addr = memblock_find_in_range(new_area_start + new_area_size, memblock.current_limit, - new_size, sizeof(phys_addr_t)); + new_alloc_size, PAGE_SIZE); if (!addr && new_area_size) addr = memblock_find_in_range(0, min(new_area_start, memblock.current_limit), - new_size, sizeof(phys_addr_t)); + new_alloc_size, PAGE_SIZE); new_array = addr ? __va(addr) : 0; } @@ -279,13 +274,13 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, kfree(old_array); else if (old_array != memblock_memory_init_regions && old_array != memblock_reserved_init_regions) - memblock_free(__pa(old_array), old_size); + memblock_free(__pa(old_array), old_alloc_size); /* Reserve the new array if that comes from the memblock. * Otherwise, we needn't do it */ if (!use_slab) - BUG_ON(memblock_reserve(addr, new_size)); + BUG_ON(memblock_reserve(addr, new_alloc_size)); /* Update slab flag */ *in_slab = use_slab; diff --git a/mm/nobootmem.c b/mm/nobootmem.c index 1983fb1c702..218e6f95d44 100644 --- a/mm/nobootmem.c +++ b/mm/nobootmem.c @@ -105,27 +105,35 @@ static void __init __free_pages_memory(unsigned long start, unsigned long end) __free_pages_bootmem(pfn_to_page(i), 0); } +static unsigned long __init __free_memory_core(phys_addr_t start, + phys_addr_t end) +{ + unsigned long start_pfn = PFN_UP(start); + unsigned long end_pfn = min_t(unsigned long, + PFN_DOWN(end), max_low_pfn); + + if (start_pfn > end_pfn) + return 0; + + __free_pages_memory(start_pfn, end_pfn); + + return end_pfn - start_pfn; +} + unsigned long __init free_low_memory_core_early(int nodeid) { unsigned long count = 0; - phys_addr_t start, end; + phys_addr_t start, end, size; u64 i; - /* free reserved array temporarily so that it's treated as free area */ - memblock_free_reserved_regions(); - - for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL) { - unsigned long start_pfn = PFN_UP(start); - unsigned long end_pfn = min_t(unsigned long, - PFN_DOWN(end), max_low_pfn); - if (start_pfn < end_pfn) { - __free_pages_memory(start_pfn, end_pfn); - count += end_pfn - start_pfn; - } - } + for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL) + count += __free_memory_core(start, end); + + /* free range that is used for reserved array if we allocate it */ + size = get_allocated_memblock_reserved_regions_info(&start); + if (size) + count += __free_memory_core(start, start + size); - /* put region array back? */ - memblock_reserve_reserved_regions(); return count; } From bb2b649805527af1d823f871e7e3a95c4e6a018e Mon Sep 17 00:00:00 2001 From: Luis Henriques Date: Wed, 11 Jul 2012 14:02:10 -0700 Subject: [PATCH 0465/2357] ocfs2: fix NULL pointer dereference in __ocfs2_change_file_space() commit a4e08d001f2e50bb8b3c4eebadcf08e5535f02ee upstream. As ocfs2_fallocate() will invoke __ocfs2_change_file_space() with a NULL as the first parameter (file), it may trigger a NULL pointer dereferrence due to a missing check. Addresses http://bugs.launchpad.net/bugs/1006012 Signed-off-by: Luis Henriques Reported-by: Bret Towe Tested-by: Bret Towe Cc: Sunil Mushran Acked-by: Joel Becker Acked-by: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 98513c8ed58..7602783d7f4 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1950,7 +1950,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, if (ret < 0) mlog_errno(ret); - if (file->f_flags & O_SYNC) + if (file && (file->f_flags & O_SYNC)) handle->h_sync = 1; ocfs2_commit_trans(osb, handle); From 763c71b1319c56272e42cf6ada6994131f0193a7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 16 Jul 2012 11:20:09 -0700 Subject: [PATCH 0466/2357] Linux 3.4.5 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 058320d6bc5..a2e69a08b7e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 4 +SUBLEVEL = 5 EXTRAVERSION = NAME = Saber-toothed Squirrel From dfd45e89bc8040c45ad5df89fb01d7d0138ec953 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 13 Jul 2012 13:35:36 -0400 Subject: [PATCH 0467/2357] Remove easily user-triggerable BUG from generic_setlease commit 8d657eb3b43861064d36241e88d9d61c709f33f0 upstream. This can be trivially triggered from userspace by passing in something unexpected. kernel BUG at fs/locks.c:1468! invalid opcode: 0000 [#1] SMP RIP: 0010:generic_setlease+0xc2/0x100 Call Trace: __vfs_setlease+0x35/0x40 fcntl_setlease+0x76/0x150 sys_fcntl+0x1c6/0x810 system_call_fastpath+0x1a/0x1f Signed-off-by: Dave Jones Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/locks.c b/fs/locks.c index 0d68f1f8179..6a64f154db0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1465,7 +1465,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) case F_WRLCK: return generic_add_lease(filp, arg, flp); default: - BUG(); + return -EINVAL; } } EXPORT_SYMBOL(generic_setlease); From 9ab2f39f3ebbd4ccf2cdd75d564ee09c77c722ab Mon Sep 17 00:00:00 2001 From: David Dillow Date: Mon, 18 Jun 2012 00:15:21 -0300 Subject: [PATCH 0468/2357] media: cx231xx: don't DMA to random addresses commit a7deca6fa79d5c65575532e780f3c93f6bf8ddad upstream. Commit 7a6f6c29d264cdd2fe0eb3d923217eed5f0ad134 (cx231xx: use URB_NO_TRANSFER_DMA_MAP) was intended to avoid mapping the DMA buffer for URB twice. This works for the URBs allocated with usb_alloc_urb(), as those are allocated from cohernent DMA pools, but the flag was also added for the VBI and audio URBs, which have a manually allocated area. This leaves the random trash in the structure after allocation as the DMA address, corrupting memory and preventing VBI and audio from working. Letting the USB core map the buffers solves the problem. Signed-off-by: David Dillow Cc: Sri Deevi Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/cx231xx/cx231xx-audio.c | 4 ++-- drivers/media/video/cx231xx/cx231xx-vbi.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c index a2c2b7d343e..e5742a0e19a 100644 --- a/drivers/media/video/cx231xx/cx231xx-audio.c +++ b/drivers/media/video/cx231xx/cx231xx-audio.c @@ -307,7 +307,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvisocpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->interval = 1; urb->complete = cx231xx_audio_isocirq; @@ -368,7 +368,7 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvbulkpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + urb->transfer_flags = 0; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->complete = cx231xx_audio_bulkirq; urb->transfer_buffer_length = sb_size; diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c index 8cdee5f78f1..9c5967e1d0c 100644 --- a/drivers/media/video/cx231xx/cx231xx-vbi.c +++ b/drivers/media/video/cx231xx/cx231xx-vbi.c @@ -452,7 +452,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, return -ENOMEM; } dev->vbi_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + urb->transfer_flags = 0; dev->vbi_mode.bulk_ctl.transfer_buffer[i] = kzalloc(sb_size, GFP_KERNEL); From 175063bccaefa0b6a4934ffaf3a9639a4a7616d0 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 12 Jul 2012 22:47:37 +0200 Subject: [PATCH 0469/2357] hwmon: (it87) Preserve configuration register bits on init commit 41002f8dd5938d5ad1d008ce5bfdbfe47fa7b4e8 upstream. We were accidentally losing one bit in the configuration register on device initialization. It was reported to freeze one specific system right away. Properly preserve all bits we don't explicitly want to change in order to prevent that. Reported-by: Stevie Trujillo Signed-off-by: Jean Delvare Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/it87.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 0b204e4cf51..f524882aaeb 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -2157,7 +2157,7 @@ static void __devinit it87_init_device(struct platform_device *pdev) /* Start monitoring */ it87_write_value(data, IT87_REG_CONFIG, - (it87_read_value(data, IT87_REG_CONFIG) & 0x36) + (it87_read_value(data, IT87_REG_CONFIG) & 0x3e) | (update_vbat ? 0x41 : 0x01)); } From e2ea6a3e16a36e26af184f781ede7a12f6cff8b5 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Thu, 12 Jul 2012 09:43:14 -0400 Subject: [PATCH 0470/2357] block: fix infinite loop in __getblk_slow commit 91f68c89d8f35fe98ea04159b9a3b42d0149478f upstream. Commit 080399aaaf35 ("block: don't mark buffers beyond end of disk as mapped") exposed a bug in __getblk_slow that causes mount to hang as it loops infinitely waiting for a buffer that lies beyond the end of the disk to become uptodate. The problem was initially reported by Torsten Hilbrich here: https://lkml.org/lkml/2012/6/18/54 and also reported independently here: http://www.sysresccd.org/forums/viewtopic.php?f=13&t=4511 and then Richard W.M. Jones and Marcos Mello noted a few separate bugzillas also associated with the same issue. This patch has been confirmed to fix: https://bugzilla.redhat.com/show_bug.cgi?id=835019 The main problem is here, in __getblk_slow: for (;;) { struct buffer_head * bh; int ret; bh = __find_get_block(bdev, block, size); if (bh) return bh; ret = grow_buffers(bdev, block, size); if (ret < 0) return NULL; if (ret == 0) free_more_memory(); } __find_get_block does not find the block, since it will not be marked as mapped, and so grow_buffers is called to fill in the buffers for the associated page. I believe the for (;;) loop is there primarily to retry in the case of memory pressure keeping grow_buffers from succeeding. However, we also continue to loop for other cases, like the block lying beond the end of the disk. So, the fix I came up with is to only loop when grow_buffers fails due to memory allocation issues (return value of 0). The attached patch was tested by myself, Torsten, and Rich, and was found to resolve the problem in call cases. Signed-off-by: Jeff Moyer Reported-and-Tested-by: Torsten Hilbrich Tested-by: Richard W.M. Jones Reviewed-by: Josh Boyer [ Jens is on vacation, taking this directly - Linus ] Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/buffer.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index ad5938ca357..0bc1bed6c4e 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1036,6 +1036,9 @@ grow_buffers(struct block_device *bdev, sector_t block, int size) static struct buffer_head * __getblk_slow(struct block_device *bdev, sector_t block, int size) { + int ret; + struct buffer_head *bh; + /* Size must be multiple of hard sectorsize */ if (unlikely(size & (bdev_logical_block_size(bdev)-1) || (size < 512 || size > PAGE_SIZE))) { @@ -1048,20 +1051,21 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) return NULL; } - for (;;) { - struct buffer_head * bh; - int ret; +retry: + bh = __find_get_block(bdev, block, size); + if (bh) + return bh; + ret = grow_buffers(bdev, block, size); + if (ret == 0) { + free_more_memory(); + goto retry; + } else if (ret > 0) { bh = __find_get_block(bdev, block, size); if (bh) return bh; - - ret = grow_buffers(bdev, block, size); - if (ret < 0) - return NULL; - if (ret == 0) - free_more_memory(); } + return NULL; } /* From a3fa551238b526b7b345da724b988650468cf36e Mon Sep 17 00:00:00 2001 From: Santosh Nayak Date: Sat, 23 Jun 2012 07:59:54 -0300 Subject: [PATCH 0471/2357] media: dvb-core: Release semaphore on error path dvb_register_device() commit 82163edcdfa4eb3d74516cc8e9f38dd3d039b67d upstream. There is a missing "up_write()" here. Semaphore should be released before returning error value. Signed-off-by: Santosh Nayak Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb/dvb-core/dvbdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 00a67326c19..39eab73b01a 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -243,6 +243,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, if (minor == MAX_DVB_MINORS) { kfree(dvbdevfops); kfree(dvbdev); + up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); return -EINVAL; } From a3a13c9974160030550ae28b3fa2c1ea8992b9c5 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Wed, 16 May 2012 16:21:52 -0300 Subject: [PATCH 0472/2357] mtd: nandsim: don't open code a do_div helper commit 596fd46268634082314b3af1ded4612e1b7f3f03 upstream. We don't need to open code the divide function, just use div_u64 that already exists and do the same job. While this is a straightforward clean up, there is more to that, the real motivation for this. While building on a cross compiling environment in armel, using gcc 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5), I was getting the following build error: ERROR: "__aeabi_uldivmod" [drivers/mtd/nand/nandsim.ko] undefined! After investigating with objdump and hand built assembly version generated with the compiler, I narrowed __aeabi_uldivmod as being generated from the divide function. When nandsim.c is built with -fno-inline-functions-called-once, that happens when CONFIG_DEBUG_SECTION_MISMATCH is enabled, the do_div optimization in arch/arm/include/asm/div64.h doesn't work as expected with the open coded divide function: even if the do_div we are using doesn't have a constant divisor, the compiler still includes the else parts of the optimized do_div macro, and translates the divisions there to use __aeabi_uldivmod, instead of only calling __do_div_asm -> __do_div64 and optimizing/removing everything else out. So to reproduce, gcc 4.6 plus CONFIG_DEBUG_SECTION_MISMATCH=y and CONFIG_MTD_NAND_NANDSIM=m should do it, building on armel. After this change, the compiler does the intended thing even with -fno-inline-functions-called-once, and optimizes out as expected the constant handling in the optimized do_div on arm. As this also avoids a build issue, I'm marking for Stable, as I think is applicable for this case. Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Nicolas Pitre Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/nandsim.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 261f478f8cc..c606b6afd7a 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -547,12 +547,6 @@ static char *get_partition_name(int i) return kstrdup(buf, GFP_KERNEL); } -static uint64_t divide(uint64_t n, uint32_t d) -{ - do_div(n, d); - return n; -} - /* * Initialize the nandsim structure. * @@ -581,7 +575,7 @@ static int init_nandsim(struct mtd_info *mtd) ns->geom.oobsz = mtd->oobsize; ns->geom.secsz = mtd->erasesize; ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; - ns->geom.pgnum = divide(ns->geom.totsz, ns->geom.pgsz); + ns->geom.pgnum = div_u64(ns->geom.totsz, ns->geom.pgsz); ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz; ns->geom.secshift = ffs(ns->geom.secsz) - 1; ns->geom.pgshift = chip->page_shift; @@ -924,7 +918,7 @@ static int setup_wear_reporting(struct mtd_info *mtd) if (!rptwear) return 0; - wear_eb_count = divide(mtd->size, mtd->erasesize); + wear_eb_count = div_u64(mtd->size, mtd->erasesize); mem = wear_eb_count * sizeof(unsigned long); if (mem / sizeof(unsigned long) != wear_eb_count) { NS_ERR("Too many erase blocks for wear reporting\n"); From e301f7b1dbbb0af6dcb8ed10c800fa95bb34917a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 9 Jul 2012 11:34:13 +1000 Subject: [PATCH 0473/2357] md/raid1: fix use-after-free bug in RAID1 data-check code. commit 2d4f4f3384d4ef4f7c571448e803a1ce721113d5 upstream. This bug has been present ever since data-check was introduce in 2.6.16. However it would only fire if a data-check were done on a degraded array, which was only possible if the array has 3 or more devices. This is certainly possible, but is quite uncommon. Since hot-replace was added in 3.3 it can happen more often as the same condition can arise if not all possible replacements are present. The problem is that as soon as we submit the last read request, the 'r1_bio' structure could be freed at any time, so we really should stop looking at it. If the last device is being read from we will stop looking at it. However if the last device is not due to be read from, we will still check the bio pointer in the r1_bio, but the r1_bio might already be free. So use the read_targets counter to make sure we stop looking for bios to submit as soon as we have submitted them all. This fix is suitable for any -stable kernel since 2.6.16. Reported-by: Arnold Schulz Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index d7e95772145..d1f74ab1396 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2486,9 +2486,10 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp */ if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { atomic_set(&r1_bio->remaining, read_targets); - for (i = 0; i < conf->raid_disks * 2; i++) { + for (i = 0; i < conf->raid_disks * 2 && read_targets; i++) { bio = r1_bio->bios[i]; if (bio->bi_end_io == end_sync_read) { + read_targets--; md_sync_acct(bio->bi_bdev, nr_sectors); generic_make_request(bio); } From 5c77ea89ed79a692b0097dbca3652fbc83e30619 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Fri, 13 Jul 2012 15:30:48 +0900 Subject: [PATCH 0474/2357] ARM: SAMSUNG: fix race in s3c_adc_start for ADC commit 8265981bb439f3ecc5356fb877a6c2a6636ac88a upstream. Checking for adc->ts_pend already claimed should be done with the lock held. Signed-off-by: Todd Poynor Acked-by: Ben Dooks Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-samsung/adc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c index 33ecd0c9f0c..b1e05ccff3a 100644 --- a/arch/arm/plat-samsung/adc.c +++ b/arch/arm/plat-samsung/adc.c @@ -157,11 +157,13 @@ int s3c_adc_start(struct s3c_adc_client *client, return -EINVAL; } - if (client->is_ts && adc->ts_pend) - return -EAGAIN; - spin_lock_irqsave(&adc->lock, flags); + if (client->is_ts && adc->ts_pend) { + spin_unlock_irqrestore(&adc->lock, flags); + return -EAGAIN; + } + client->channel = channel; client->nr_samples = nr_samples; From af3a2390c0f80345516524c3fe7e717f465ce6bd Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 4 Jul 2012 10:02:32 +0800 Subject: [PATCH 0475/2357] ACPICA: Fix possible fault in return package object repair code commit 46befd6b38d802dfc5998e7d7938854578b45d9d upstream. Fixes a problem that can occur when a lone package object is wrapped with an outer package object in order to conform to the ACPI specification. Can affect these predefined names: _ALR,_MLS,_PSS,_TRT,_TSS,_PRT,_HPX,_DLM,_CSD,_PSD,_TSD https://bugzilla.kernel.org/show_bug.cgi?id=44171 This problem was introduced in 3.4-rc1 by commit 6a99b1c94d053b3420eaa4a4bc8b2883dd90a2f9 (ACPICA: Object repair code: Support to add Package wrappers) Reported-by: Vlastimil Babka Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpica/nspredef.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 23ce0968641..fe662603549 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -638,7 +638,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data, /* Create the new outer package and populate it */ status = - acpi_ns_wrap_with_package(data, *elements, + acpi_ns_wrap_with_package(data, return_object, return_object_ptr); if (ACPI_FAILURE(status)) { return (status); From 667fb5508900340d657645e0bfc9bf210a1fc363 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Thu, 12 Jul 2012 12:24:33 +0200 Subject: [PATCH 0476/2357] cpufreq / ACPI: Fix not loading acpi-cpufreq driver regression commit c4686c71a9183f76e3ef59098da5c098748672f6 upstream. Commit d640113fe80e45ebd4a5b420b introduced a regression on SMP systems where the processor core with ACPI id zero is disabled (typically should be the case because of hyperthreading). The regression got spread through stable kernels. On 3.0.X it got introduced via 3.0.18. Such platforms may be rare, but do exist. Look out for a disabled processor with acpi_id 0 in dmesg: ACPI: LAPIC (acpi_id[0x00] lapic_id[0x10] disabled) This problem has been observed on a: HP Proliant BL280c G6 blade This patch restricts the introduced workaround to platforms with nr_cpu_ids <= 1. Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index c850de4c9a1..eff722278ff 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -189,10 +189,12 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) * Processor (CPU3, 0x03, 0x00000410, 0x06) {} * } * - * Ignores apic_id and always return 0 for CPU0's handle. + * Ignores apic_id and always returns 0 for the processor + * handle with acpi id 0 if nr_cpu_ids is 1. + * This should be the case if SMP tables are not found. * Return -1 for other CPU's handle. */ - if (acpi_id == 0) + if (nr_cpu_ids <= 1 && acpi_id == 0) return acpi_id; else return apic_id; From 7490d0a4cfefa16f9d8ce636eb5b2e13d2432db3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jun 2012 15:52:09 +0200 Subject: [PATCH 0477/2357] sched/nohz: Rewrite and fix load-avg computation -- again commit 5167e8d5417bf5c322a703d2927daec727ea40dd upstream. Thanks to Charles Wang for spotting the defects in the current code: - If we go idle during the sample window -- after sampling, we get a negative bias because we can negate our own sample. - If we wake up during the sample window we get a positive bias because we push the sample to a known active period. So rewrite the entire nohz load-avg muck once again, now adding copious documentation to the code. Reported-and-tested-by: Doug Smythies Reported-and-tested-by: Charles Wang Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/1340373782.18025.74.camel@twins [ minor edits ] Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- include/linux/sched.h | 8 ++ kernel/sched/core.c | 275 +++++++++++++++++++++++++++++---------- kernel/sched/idle_task.c | 1 - kernel/sched/sched.h | 2 - kernel/time/tick-sched.c | 2 + 5 files changed, 213 insertions(+), 75 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 81a173c0897..7b06169d724 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1933,6 +1933,14 @@ static inline int set_cpus_allowed_ptr(struct task_struct *p, } #endif +#ifdef CONFIG_NO_HZ +void calc_load_enter_idle(void); +void calc_load_exit_idle(void); +#else +static inline void calc_load_enter_idle(void) { } +static inline void calc_load_exit_idle(void) { } +#endif /* CONFIG_NO_HZ */ + #ifndef CONFIG_CPUMASK_OFFSTACK static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask) { diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 2000e069fc9..817bf701883 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2162,11 +2162,73 @@ unsigned long this_cpu_load(void) } +/* + * Global load-average calculations + * + * We take a distributed and async approach to calculating the global load-avg + * in order to minimize overhead. + * + * The global load average is an exponentially decaying average of nr_running + + * nr_uninterruptible. + * + * Once every LOAD_FREQ: + * + * nr_active = 0; + * for_each_possible_cpu(cpu) + * nr_active += cpu_of(cpu)->nr_running + cpu_of(cpu)->nr_uninterruptible; + * + * avenrun[n] = avenrun[0] * exp_n + nr_active * (1 - exp_n) + * + * Due to a number of reasons the above turns in the mess below: + * + * - for_each_possible_cpu() is prohibitively expensive on machines with + * serious number of cpus, therefore we need to take a distributed approach + * to calculating nr_active. + * + * \Sum_i x_i(t) = \Sum_i x_i(t) - x_i(t_0) | x_i(t_0) := 0 + * = \Sum_i { \Sum_j=1 x_i(t_j) - x_i(t_j-1) } + * + * So assuming nr_active := 0 when we start out -- true per definition, we + * can simply take per-cpu deltas and fold those into a global accumulate + * to obtain the same result. See calc_load_fold_active(). + * + * Furthermore, in order to avoid synchronizing all per-cpu delta folding + * across the machine, we assume 10 ticks is sufficient time for every + * cpu to have completed this task. + * + * This places an upper-bound on the IRQ-off latency of the machine. Then + * again, being late doesn't loose the delta, just wrecks the sample. + * + * - cpu_rq()->nr_uninterruptible isn't accurately tracked per-cpu because + * this would add another cross-cpu cacheline miss and atomic operation + * to the wakeup path. Instead we increment on whatever cpu the task ran + * when it went into uninterruptible state and decrement on whatever cpu + * did the wakeup. This means that only the sum of nr_uninterruptible over + * all cpus yields the correct result. + * + * This covers the NO_HZ=n code, for extra head-aches, see the comment below. + */ + /* Variables and functions for calc_load */ static atomic_long_t calc_load_tasks; static unsigned long calc_load_update; unsigned long avenrun[3]; -EXPORT_SYMBOL(avenrun); +EXPORT_SYMBOL(avenrun); /* should be removed */ + +/** + * get_avenrun - get the load average array + * @loads: pointer to dest load array + * @offset: offset to add + * @shift: shift count to shift the result left + * + * These values are estimates at best, so no need for locking. + */ +void get_avenrun(unsigned long *loads, unsigned long offset, int shift) +{ + loads[0] = (avenrun[0] + offset) << shift; + loads[1] = (avenrun[1] + offset) << shift; + loads[2] = (avenrun[2] + offset) << shift; +} static long calc_load_fold_active(struct rq *this_rq) { @@ -2183,6 +2245,9 @@ static long calc_load_fold_active(struct rq *this_rq) return delta; } +/* + * a1 = a0 * e + a * (1 - e) + */ static unsigned long calc_load(unsigned long load, unsigned long exp, unsigned long active) { @@ -2194,30 +2259,118 @@ calc_load(unsigned long load, unsigned long exp, unsigned long active) #ifdef CONFIG_NO_HZ /* - * For NO_HZ we delay the active fold to the next LOAD_FREQ update. + * Handle NO_HZ for the global load-average. + * + * Since the above described distributed algorithm to compute the global + * load-average relies on per-cpu sampling from the tick, it is affected by + * NO_HZ. + * + * The basic idea is to fold the nr_active delta into a global idle-delta upon + * entering NO_HZ state such that we can include this as an 'extra' cpu delta + * when we read the global state. + * + * Obviously reality has to ruin such a delightfully simple scheme: + * + * - When we go NO_HZ idle during the window, we can negate our sample + * contribution, causing under-accounting. + * + * We avoid this by keeping two idle-delta counters and flipping them + * when the window starts, thus separating old and new NO_HZ load. + * + * The only trick is the slight shift in index flip for read vs write. + * + * 0s 5s 10s 15s + * +10 +10 +10 +10 + * |-|-----------|-|-----------|-|-----------|-| + * r:0 0 1 1 0 0 1 1 0 + * w:0 1 1 0 0 1 1 0 0 + * + * This ensures we'll fold the old idle contribution in this window while + * accumlating the new one. + * + * - When we wake up from NO_HZ idle during the window, we push up our + * contribution, since we effectively move our sample point to a known + * busy state. + * + * This is solved by pushing the window forward, and thus skipping the + * sample, for this cpu (effectively using the idle-delta for this cpu which + * was in effect at the time the window opened). This also solves the issue + * of having to deal with a cpu having been in NOHZ idle for multiple + * LOAD_FREQ intervals. * * When making the ILB scale, we should try to pull this in as well. */ -static atomic_long_t calc_load_tasks_idle; +static atomic_long_t calc_load_idle[2]; +static int calc_load_idx; -void calc_load_account_idle(struct rq *this_rq) +static inline int calc_load_write_idx(void) { + int idx = calc_load_idx; + + /* + * See calc_global_nohz(), if we observe the new index, we also + * need to observe the new update time. + */ + smp_rmb(); + + /* + * If the folding window started, make sure we start writing in the + * next idle-delta. + */ + if (!time_before(jiffies, calc_load_update)) + idx++; + + return idx & 1; +} + +static inline int calc_load_read_idx(void) +{ + return calc_load_idx & 1; +} + +void calc_load_enter_idle(void) +{ + struct rq *this_rq = this_rq(); long delta; + /* + * We're going into NOHZ mode, if there's any pending delta, fold it + * into the pending idle delta. + */ delta = calc_load_fold_active(this_rq); - if (delta) - atomic_long_add(delta, &calc_load_tasks_idle); + if (delta) { + int idx = calc_load_write_idx(); + atomic_long_add(delta, &calc_load_idle[idx]); + } } -static long calc_load_fold_idle(void) +void calc_load_exit_idle(void) { - long delta = 0; + struct rq *this_rq = this_rq(); + + /* + * If we're still before the sample window, we're done. + */ + if (time_before(jiffies, this_rq->calc_load_update)) + return; /* - * Its got a race, we don't care... + * We woke inside or after the sample window, this means we're already + * accounted through the nohz accounting, so skip the entire deal and + * sync up for the next window. */ - if (atomic_long_read(&calc_load_tasks_idle)) - delta = atomic_long_xchg(&calc_load_tasks_idle, 0); + this_rq->calc_load_update = calc_load_update; + if (time_before(jiffies, this_rq->calc_load_update + 10)) + this_rq->calc_load_update += LOAD_FREQ; +} + +static long calc_load_fold_idle(void) +{ + int idx = calc_load_read_idx(); + long delta = 0; + + if (atomic_long_read(&calc_load_idle[idx])) + delta = atomic_long_xchg(&calc_load_idle[idx], 0); return delta; } @@ -2303,66 +2456,39 @@ static void calc_global_nohz(void) { long delta, active, n; - /* - * If we crossed a calc_load_update boundary, make sure to fold - * any pending idle changes, the respective CPUs might have - * missed the tick driven calc_load_account_active() update - * due to NO_HZ. - */ - delta = calc_load_fold_idle(); - if (delta) - atomic_long_add(delta, &calc_load_tasks); - - /* - * It could be the one fold was all it took, we done! - */ - if (time_before(jiffies, calc_load_update + 10)) - return; - - /* - * Catch-up, fold however many we are behind still - */ - delta = jiffies - calc_load_update - 10; - n = 1 + (delta / LOAD_FREQ); + if (!time_before(jiffies, calc_load_update + 10)) { + /* + * Catch-up, fold however many we are behind still + */ + delta = jiffies - calc_load_update - 10; + n = 1 + (delta / LOAD_FREQ); - active = atomic_long_read(&calc_load_tasks); - active = active > 0 ? active * FIXED_1 : 0; + active = atomic_long_read(&calc_load_tasks); + active = active > 0 ? active * FIXED_1 : 0; - avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n); - avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n); - avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n); + avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n); + avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n); + avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n); - calc_load_update += n * LOAD_FREQ; -} -#else -void calc_load_account_idle(struct rq *this_rq) -{ -} + calc_load_update += n * LOAD_FREQ; + } -static inline long calc_load_fold_idle(void) -{ - return 0; + /* + * Flip the idle index... + * + * Make sure we first write the new time then flip the index, so that + * calc_load_write_idx() will see the new time when it reads the new + * index, this avoids a double flip messing things up. + */ + smp_wmb(); + calc_load_idx++; } +#else /* !CONFIG_NO_HZ */ -static void calc_global_nohz(void) -{ -} -#endif +static inline long calc_load_fold_idle(void) { return 0; } +static inline void calc_global_nohz(void) { } -/** - * get_avenrun - get the load average array - * @loads: pointer to dest load array - * @offset: offset to add - * @shift: shift count to shift the result left - * - * These values are estimates at best, so no need for locking. - */ -void get_avenrun(unsigned long *loads, unsigned long offset, int shift) -{ - loads[0] = (avenrun[0] + offset) << shift; - loads[1] = (avenrun[1] + offset) << shift; - loads[2] = (avenrun[2] + offset) << shift; -} +#endif /* CONFIG_NO_HZ */ /* * calc_load - update the avenrun load estimates 10 ticks after the @@ -2370,11 +2496,18 @@ void get_avenrun(unsigned long *loads, unsigned long offset, int shift) */ void calc_global_load(unsigned long ticks) { - long active; + long active, delta; if (time_before(jiffies, calc_load_update + 10)) return; + /* + * Fold the 'old' idle-delta to include all NO_HZ cpus. + */ + delta = calc_load_fold_idle(); + if (delta) + atomic_long_add(delta, &calc_load_tasks); + active = atomic_long_read(&calc_load_tasks); active = active > 0 ? active * FIXED_1 : 0; @@ -2385,12 +2518,7 @@ void calc_global_load(unsigned long ticks) calc_load_update += LOAD_FREQ; /* - * Account one period with whatever state we found before - * folding in the nohz state and ageing the entire idle period. - * - * This avoids loosing a sample when we go idle between - * calc_load_account_active() (10 ticks ago) and now and thus - * under-accounting. + * In case we idled for multiple LOAD_FREQ intervals, catch up in bulk. */ calc_global_nohz(); } @@ -2407,13 +2535,16 @@ static void calc_load_account_active(struct rq *this_rq) return; delta = calc_load_fold_active(this_rq); - delta += calc_load_fold_idle(); if (delta) atomic_long_add(delta, &calc_load_tasks); this_rq->calc_load_update += LOAD_FREQ; } +/* + * End of global load-average stuff + */ + /* * The exact cpuload at various idx values, calculated at every tick would be * load = (2^idx - 1) / 2^idx * load + 1 / 2^idx * cur_load diff --git a/kernel/sched/idle_task.c b/kernel/sched/idle_task.c index 91b4c957f28..fdf75227572 100644 --- a/kernel/sched/idle_task.c +++ b/kernel/sched/idle_task.c @@ -25,7 +25,6 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int fl static struct task_struct *pick_next_task_idle(struct rq *rq) { schedstat_inc(rq, sched_goidle); - calc_load_account_idle(rq); return rq->idle; } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index fb3acba4d52..116ced06ecc 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -940,8 +940,6 @@ static inline u64 sched_avg_period(void) return (u64)sysctl_sched_time_avg * NSEC_PER_MSEC / 2; } -void calc_load_account_idle(struct rq *this_rq); - #ifdef CONFIG_SCHED_HRTICK /* diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 6a3a5b9ff56..fd4e160aa9c 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -401,6 +401,7 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts) */ if (!ts->tick_stopped) { select_nohz_load_balancer(1); + calc_load_enter_idle(); ts->idle_tick = hrtimer_get_expires(&ts->sched_timer); ts->tick_stopped = 1; @@ -591,6 +592,7 @@ void tick_nohz_idle_exit(void) account_idle_ticks(ticks); #endif + calc_load_exit_idle(); touch_softlockup_watchdog(); /* * Cancel the scheduled timer and restore the tick From 665c7a83a1a64582c4393dd45430c848150a10dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 25 Jun 2012 15:07:17 +0200 Subject: [PATCH 0478/2357] intel_ips: blacklist HP ProBook laptops commit 88ca518b0bb4161e5f20f8a1d9cc477cae294e54 upstream. intel_ips driver spews the warning message "ME failed to update for more than 1s, likely hung" at each second endlessly on HP ProBook laptops with IronLake. As this has never worked, better to blacklist the driver for now. Signed-off-by: Takashi Iwai Signed-off-by: Matthew Garrett Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/intel_ips.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 0ffdb3cde2b..9af4257d490 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -72,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -1485,6 +1486,24 @@ static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = { MODULE_DEVICE_TABLE(pci, ips_id_table); +static int ips_blacklist_callback(const struct dmi_system_id *id) +{ + pr_info("Blacklisted intel_ips for %s\n", id->ident); + return 1; +} + +static const struct dmi_system_id ips_blacklist[] = { + { + .callback = ips_blacklist_callback, + .ident = "HP ProBook", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook"), + }, + }, + { } /* terminating entry */ +}; + static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) { u64 platform_info; @@ -1494,6 +1513,9 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) u16 htshi, trc, trc_required_mask; u8 tse; + if (dmi_check_system(ips_blacklist)) + return -ENODEV; + ips = kzalloc(sizeof(struct ips_driver), GFP_KERNEL); if (!ips) return -ENOMEM; From b9311277c28fab089ee0816307035c3a5f546bcf Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Sun, 15 Jul 2012 17:14:25 -0400 Subject: [PATCH 0479/2357] fifo: Do not restart open() if it already found a partner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 05d290d66be6ef77a0b962ebecf01911bd984a78 upstream. If a parent and child process open the two ends of a fifo, and the child immediately exits, the parent may receive a SIGCHLD before its open() returns. In that case, we need to make sure that open() will return successfully after the SIGCHLD handler returns, instead of throwing EINTR or being restarted. Otherwise, the restarted open() would incorrectly wait for a second partner on the other end. The following test demonstrates the EINTR that was wrongly thrown from the parent’s open(). Change .sa_flags = 0 to .sa_flags = SA_RESTART to see a deadlock instead, in which the restarted open() waits for a second reader that will never come. (On my systems, this happens pretty reliably within about 5 to 500 iterations. Others report that it manages to loop ~forever sometimes; YMMV.) #include #include #include #include #include #include #include #include #define CHECK(x) do if ((x) == -1) {perror(#x); abort();} while(0) void handler(int signum) {} int main() { struct sigaction act = {.sa_handler = handler, .sa_flags = 0}; CHECK(sigaction(SIGCHLD, &act, NULL)); CHECK(mknod("fifo", S_IFIFO | S_IRWXU, 0)); for (;;) { int fd; pid_t pid; putc('.', stderr); CHECK(pid = fork()); if (pid == 0) { CHECK(fd = open("fifo", O_RDONLY)); _exit(0); } CHECK(fd = open("fifo", O_WRONLY)); CHECK(close(fd)); CHECK(waitpid(pid, NULL, 0)); } } This is what I suspect was causing the Git test suite to fail in t9010-svn-fe.sh: http://bugs.debian.org/678852 Signed-off-by: Anders Kaseorg Reviewed-by: Jonathan Nieder Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/fifo.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/fifo.c b/fs/fifo.c index b1a524d798e..cf6f4345ceb 100644 --- a/fs/fifo.c +++ b/fs/fifo.c @@ -14,7 +14,7 @@ #include #include -static void wait_for_partner(struct inode* inode, unsigned int *cnt) +static int wait_for_partner(struct inode* inode, unsigned int *cnt) { int cur = *cnt; @@ -23,6 +23,7 @@ static void wait_for_partner(struct inode* inode, unsigned int *cnt) if (signal_pending(current)) break; } + return cur == *cnt ? -ERESTARTSYS : 0; } static void wake_up_partner(struct inode* inode) @@ -67,8 +68,7 @@ static int fifo_open(struct inode *inode, struct file *filp) * seen a writer */ filp->f_version = pipe->w_counter; } else { - wait_for_partner(inode, &pipe->w_counter); - if(signal_pending(current)) + if (wait_for_partner(inode, &pipe->w_counter)) goto err_rd; } } @@ -90,8 +90,7 @@ static int fifo_open(struct inode *inode, struct file *filp) wake_up_partner(inode); if (!pipe->readers) { - wait_for_partner(inode, &pipe->r_counter); - if (signal_pending(current)) + if (wait_for_partner(inode, &pipe->r_counter)) goto err_wr; } break; From a3c021d25debc6278951e0112b1a06d8b7376d22 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 4 Jul 2012 13:10:02 +0200 Subject: [PATCH 0480/2357] rt2x00usb: fix indexes ordering on RX queue kick commit efd821182cec8c92babef6e00a95066d3252fda4 upstream. On rt2x00_dmastart() we increase index specified by Q_INDEX and on rt2x00_dmadone() we increase index specified by Q_INDEX_DONE. So entries between Q_INDEX_DONE and Q_INDEX are those we currently process in the hardware. Entries between Q_INDEX and Q_INDEX_DONE are those we can submit to the hardware. According to that fix rt2x00usb_kick_queue(), as we need to submit RX entries that are not processed by the hardware. It worked before only for empty queue, otherwise was broken. Note that for TX queues indexes ordering are ok. We need to kick entries that have filled skb, but was not submitted to the hardware, i.e. started from Q_INDEX_DONE and have ENTRY_DATA_PENDING bit set. From practical standpoint this fixes RX queue stall, usually reproducible in AP mode, like for example reported here: https://bugzilla.redhat.com/show_bug.cgi?id=828824 Reported-and-tested-by: Franco Miceli Reported-and-tested-by: Tom Horsley Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2x00usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 66094eb21b6..507085facb8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -436,8 +436,8 @@ void rt2x00usb_kick_queue(struct data_queue *queue) case QID_RX: if (!rt2x00queue_full(queue)) rt2x00queue_for_each_entry(queue, - Q_INDEX_DONE, Q_INDEX, + Q_INDEX_DONE, NULL, rt2x00usb_kick_rx_entry); break; From 3cc4e0e187e4187a6ec13a79dafc1b0f72e31afa Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Thu, 12 Jul 2012 08:56:56 +0000 Subject: [PATCH 0481/2357] e1000e: Correct link check logic for 82571 serdes commit d0efa8f23a644f7cb7d1f8e78dd9a223efa412a3 upstream. SYNCH bit and IV bit of RXCW register are sticky. Before examining these bits, RXCW should be read twice to filter out one-time false events and have correct values for these bits. Incorrect values of these bits in link check logic can cause weird link stability issues if auto-negotiation fails. Reported-by: Dean Nelson Signed-off-by: Tushar Dave Reviewed-by: Bruce Allan Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/82571.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c index c6d95f2031e..a9dd6a92cf5 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.c +++ b/drivers/net/ethernet/intel/e1000e/82571.c @@ -1553,6 +1553,9 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) ctrl = er32(CTRL); status = er32(STATUS); rxcw = er32(RXCW); + /* SYNCH bit and IV bit are sticky */ + udelay(10); + rxcw = er32(RXCW); if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) { From 57cff816121720c80b39e3b3fb0ef36128fdc45b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 4 Jul 2012 13:20:20 +0200 Subject: [PATCH 0482/2357] iwlegacy: always monitor for stuck queues commit c2ca7d92ed4bbd779516beb6eb226e19f7f7ab0f upstream. This is iwlegacy version of: commit 342bbf3fee2fa9a18147e74b2e3c4229a4564912 Author: Johannes Berg Date: Sun Mar 4 08:50:46 2012 -0800 iwlwifi: always monitor for stuck queues If we only monitor while associated, the following can happen: - we're associated, and the queue stuck check runs, setting the queue "touch" time to X - we disassociate, stopping the monitoring, which leaves the time set to X - almost 2s later, we associate, and enqueue a frame - before the frame is transmitted, we monitor for stuck queues, and find the time set to X, although it is now later than X + 2000ms, so we decide that the queue is stuck and erroneously restart the device Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlegacy/common.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index eaf249452e5..4bc27112cbe 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -4767,14 +4767,12 @@ il_bg_watchdog(unsigned long data) return; /* monitor and check for other stuck queues */ - if (il_is_any_associated(il)) { - for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) { - /* skip as we already checked the command queue */ - if (cnt == il->cmd_queue) - continue; - if (il_check_stuck_queue(il, cnt)) - return; - } + for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) { + /* skip as we already checked the command queue */ + if (cnt == il->cmd_queue) + continue; + if (il_check_stuck_queue(il, cnt)) + return; } mod_timer(&il->watchdog, From 1214b7852425b78a2b73b0a759ec55210340396d Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 4 Jul 2012 13:59:08 +0200 Subject: [PATCH 0483/2357] iwlegacy: don't mess up the SCD when removing a key commit b48d96652626b315229b1b82c6270eead6a77a6d upstream. When we remove a key, we put a key index which was supposed to tell the fw that we are actually removing the key. But instead the fw took that index as a valid index and messed up the SRAM of the device. This memory corruption on the device mangled the data of the SCD. The impact on the user is that SCD queue 2 got stuck after having removed keys. Reported-by: Paul Bolle Signed-off-by: Emmanuel Grumbach Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlegacy/4965-mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index c46275a9256..9aa48074ee2 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -3405,7 +3405,7 @@ il4965_remove_dynamic_key(struct il_priv *il, return 0; } - if (il->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) { + if (il->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_INVALID) { IL_WARN("Removing wrong key %d 0x%x\n", keyconf->keyidx, key_flags); spin_unlock_irqrestore(&il->sta_lock, flags); @@ -3420,7 +3420,7 @@ il4965_remove_dynamic_key(struct il_priv *il, memset(&il->stations[sta_id].sta.key, 0, sizeof(struct il4965_keyinfo)); il->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; - il->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; + il->stations[sta_id].sta.key.key_offset = keyconf->hw_key_idx; il->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; il->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; From c8ed7cf355f41b649524029c49f101d878499482 Mon Sep 17 00:00:00 2001 From: Federico Fuga Date: Mon, 16 Jul 2012 10:36:51 +0300 Subject: [PATCH 0484/2357] rpmsg: fix dependency on initialization order commit 9634252617441991b01dacaf4040866feecaf36f upstream. When rpmsg drivers are built into the kernel, they must not initialize before the rpmsg bus does, otherwise they'd trigger a BUG() in drivers/base/driver.c line 169 (driver_register()). To fix that, and to stop depending on arbitrary linkage ordering of those built-in rpmsg drivers, we make the rpmsg bus initialize at subsys_initcall. Signed-off-by: Federico Fuga [ohad: rewrite the commit log] Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/rpmsg/virtio_rpmsg_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 39d3aa41add..f56c8ba3a86 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -1085,7 +1085,7 @@ static int __init rpmsg_init(void) return ret; } -module_init(rpmsg_init); +subsys_initcall(rpmsg_init); static void __exit rpmsg_fini(void) { From 3cf16f7e388934d4458d0d6cebdf752e4424f226 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 2 Jul 2012 14:42:03 +0300 Subject: [PATCH 0485/2357] mac80211: destroy assoc_data correctly if assoc fails commit 10a9109f2705fdc3caa94d768b2559587a9a050c upstream. If association failed due to internal error (e.g. no supported rates IE), we call ieee80211_destroy_assoc_data() with assoc=true, while we actually reject the association. This results in the BSSID not being zeroed out. After passing assoc=false, we no longer have to call sta_info_destroy_addr() explicitly. While on it, move the "associated" message after the assoc_success check. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1197e8dd5b0..d132b98bd1c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2183,15 +2183,13 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sdata->name, mgmt->sa, status_code); ieee80211_destroy_assoc_data(sdata, false); } else { - printk(KERN_DEBUG "%s: associated\n", sdata->name); - if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { /* oops -- internal error -- send timeout for now */ - ieee80211_destroy_assoc_data(sdata, true); - sta_info_destroy_addr(sdata, mgmt->bssid); + ieee80211_destroy_assoc_data(sdata, false); cfg80211_put_bss(*bss); return RX_MGMT_CFG80211_ASSOC_TIMEOUT; } + printk(KERN_DEBUG "%s: associated\n", sdata->name); /* * destroy assoc_data afterwards, as otherwise an idle From b98522a7cf0ff60bcf49330d9467089515cf9dad Mon Sep 17 00:00:00 2001 From: Deepak Sikri Date: Sun, 8 Jul 2012 21:14:45 +0000 Subject: [PATCH 0486/2357] stmmac: Fix for nfs hang on multiple reboot commit 8e83989106562326bfd6aaf92174fe138efd026b upstream. It was observed that during multiple reboots nfs hangs. The status of receive descriptors shows that all the descriptors were in control of CPU, and none were assigned to DMA. Also the DMA status register confirmed that the Rx buffer is unavailable. This patch adds the fix for the same by adding the memory barriers to ascertain that the all instructions before enabling the Rx or Tx DMA are completed which involves the proper setting of the ownership bit in DMA descriptors. Signed-off-by: Deepak Sikri Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 48d56da62f0..9bdfaba4e30 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1158,6 +1158,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion); wmb(); priv->hw->desc->set_tx_owner(desc); + wmb(); } /* Interrupt on completition only for the latest segment */ @@ -1173,6 +1174,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) /* To avoid raise condition */ priv->hw->desc->set_tx_owner(first); + wmb(); priv->cur_tx++; @@ -1236,6 +1238,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv) } wmb(); priv->hw->desc->set_rx_owner(p + entry); + wmb(); } } From f4e2229ea5d49e338fce36b2c36f22b525fbeff6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 9 Jul 2012 10:52:43 +0000 Subject: [PATCH 0487/2357] bonding: debugfs and network namespaces are incompatible commit 96ca7ffe748bf91f851e6aa4479aa11c8b1122ba upstream. The bonding debugfs support has been broken in the presence of network namespaces since it has been added. The debugfs support does not handle multiple bonding devices with the same name in different network namespaces. I haven't had any bug reports, and I'm not interested in getting any. Disable the debugfs support when network namespaces are enabled. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c index 3680aa251de..2cf084eb9d5 100644 --- a/drivers/net/bonding/bond_debugfs.c +++ b/drivers/net/bonding/bond_debugfs.c @@ -6,7 +6,7 @@ #include "bonding.h" #include "bond_alb.h" -#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_NET_NS) #include #include From d418f998832c7fd8f783e05cec7da6125720360d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 9 Jul 2012 10:51:45 +0000 Subject: [PATCH 0488/2357] bonding: Manage /proc/net/bonding/ entries from the netdev events commit a64d49c3dd504b685f9742a2f3dcb11fb8e4345f upstream. It was recently reported that moving a bonding device between network namespaces causes warnings from /proc. It turns out after the move we were trying to add and to remove the /proc/net/bonding entries from the wrong network namespace. Move the bonding /proc registration code into the NETDEV_REGISTER and NETDEV_UNREGISTER events where the proc registration and unregistration will always happen at the right time. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a579a2f57c5..318a62a4db5 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3218,6 +3218,12 @@ static int bond_master_netdev_event(unsigned long event, switch (event) { case NETDEV_CHANGENAME: return bond_event_changename(event_bond); + case NETDEV_UNREGISTER: + bond_remove_proc_entry(event_bond); + break; + case NETDEV_REGISTER: + bond_create_proc_entry(event_bond); + break; default: break; } @@ -4402,8 +4408,6 @@ static void bond_uninit(struct net_device *bond_dev) bond_work_cancel_all(bond); - bond_remove_proc_entry(bond); - bond_debug_unregister(bond); __hw_addr_flush(&bond->mc_list); @@ -4805,7 +4809,6 @@ static int bond_init(struct net_device *bond_dev) bond_set_lockdep_class(bond_dev); - bond_create_proc_entry(bond); list_add_tail(&bond->bond_list, &bn->dev_list); bond_prepare_sysfs_group(bond); From edb5132a255e3f594b662018acced9037c6989b5 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Tue, 10 Jul 2012 09:43:57 -0700 Subject: [PATCH 0489/2357] Input: bcm5974 - Add support for 2012 MacBook Pro Retina commit 3dde22a98e94eb18527f0ff0068fb2fb945e58d4 upstream. Add support for the 15'' MacBook Pro Retina model (MacBookPro10,1). Patch originally written by clipcarl (forums.opensuse.org). Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/bcm5974.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index f9e2758b9f4..e410b98c227 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -79,6 +79,10 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254 +/* MacbookPro10,1 (unibody, June 2012) */ +#define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262 +#define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263 +#define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264 #define BCM5974_DEVICE(prod) { \ .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ @@ -128,6 +132,10 @@ static const struct usb_device_id bcm5974_table[] = { BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS), + /* MacbookPro10,1 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_JIS), /* Terminating entry */ {} }; @@ -354,6 +362,18 @@ static const struct bcm5974_config bcm5974_config_table[] = { { DIM_X, DIM_X / SN_COORD, -4620, 5140 }, { DIM_Y, DIM_Y / SN_COORD, -150, 6600 } }, + { + USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING7_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING7_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4750, 5280 }, + { DIM_Y, DIM_Y / SN_COORD, -150, 6730 } + }, {} }; From abee143740c3388cc34869b9320aed3fa28f9cdb Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Wed, 11 Jul 2012 00:49:18 -0700 Subject: [PATCH 0490/2357] Input: xpad - handle all variations of Mad Catz Beat Pad commit 3ffb62cb9ac2430c2504c6ff9727d0f2476ef0bd upstream. The device should be handled by xpad driver instead of generic HID driver. Signed-off-by: Yuri Khan Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/input/joystick/xpad.c | 1 + 3 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 4da66b4b977..b54a57a733d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1914,6 +1914,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) }, { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e39aecb1f9f..b32f67c0b6c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -509,6 +509,9 @@ #define USB_DEVICE_ID_CRYSTALTOUCH 0x0006 #define USB_DEVICE_ID_CRYSTALTOUCH_DUAL 0x0007 +#define USB_VENDOR_ID_MADCATZ 0x0738 +#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540 + #define USB_VENDOR_ID_MCC 0x09db #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 #define USB_DEVICE_ID_MCC_PMD1208LS 0x007a diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index fd7a0d5bc94..0369364092d 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -238,6 +238,7 @@ static struct usb_device_id xpad_table [] = { XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ + { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */ XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ From 07793cd472f688c266eedff79f46f6c512d84ce4 Mon Sep 17 00:00:00 2001 From: Ilia Katsnelson Date: Wed, 11 Jul 2012 00:54:20 -0700 Subject: [PATCH 0491/2357] Input: xpad - add signature for Razer Onza Tournament Edition commit cc71a7e899cc6b2ff41e1be48756782ed004d802 upstream. Signed-off-by: Ilia Katsnelson Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/joystick/xpad.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 0369364092d..e0665281fee 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -164,6 +164,7 @@ static const struct xpad_device { { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } }; @@ -244,7 +245,8 @@ static struct usb_device_id xpad_table [] = { XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */ XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */ - XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ + XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ + XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */ { } }; From 256cf2738cb242af70ea6f6117446a98ed949a9c Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Wed, 11 Jul 2012 22:12:31 -0700 Subject: [PATCH 0492/2357] Input: xpad - add Andamiro Pump It Up pad commit e76b8ee25e034ab601b525abb95cea14aa167ed3 upstream. I couldn't find the vendor ID in any of the online databases, but this mat has a Pump It Up logo on the top side of the controller compartment, and a disclaimer stating that Andamiro will not be liable on the bottom. Signed-off-by: Yuri Khan Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/joystick/xpad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index e0665281fee..42f7b257feb 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -142,6 +142,7 @@ static const struct xpad_device { { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX }, { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX }, + { 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX }, { 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX }, From c5e42b8d692877676fc3ba9fdf3dbcbd723b4c2b Mon Sep 17 00:00:00 2001 From: Ryan Bourgeois Date: Tue, 10 Jul 2012 09:43:33 -0700 Subject: [PATCH 0493/2357] HID: add support for 2012 MacBook Pro Retina commit b2e6ad7dfe26aac5bf136962d0b11d180b820d44 upstream. Add support for the 15'' MacBook Pro Retina. The keyboard is the same as recent models. The patch needs to be synchronized with the bcm5974 patch for the trackpad - as usual. Patch originally written by clipcarl (forums.opensuse.org). [rydberg@euromail.se: Amended mouse ignore lines] Signed-off-by: Ryan Bourgeois Signed-off-by: Henrik Rydberg Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-apple.c | 6 ++++++ drivers/hid/hid-core.c | 6 ++++++ drivers/hid/hid-ids.h | 3 +++ 3 files changed, 15 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 299d2387112..899c71200bd 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -514,6 +514,12 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS), + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b54a57a733d..054677b3d16 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1379,6 +1379,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, @@ -2009,6 +2012,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b32f67c0b6c..dfd40981c86 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -125,6 +125,9 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c #define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d #define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e +#define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262 +#define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263 +#define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b From 871d4f5e1d82cf0ad56ae076c8535004e7837416 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Fri, 8 Jun 2012 14:04:06 +0100 Subject: [PATCH 0494/2357] clk: Check parent for NULL in clk_change_rate commit bf47b4fd8f9f81cd5ce40e1945c6334d088226d1 upstream. clk_change_rate() is accessing parent's rate without checking if the parent exists at all. In case of root clocks this will cause NULL pointer dereference. This patch follows what clk_calc_new_rates() does in such situation. Signed-off-by: Pawel Moll Signed-off-by: Mike Turquette Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 2da025ee226..7f1ea568b44 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -834,18 +834,21 @@ static void clk_change_rate(struct clk *clk) { struct clk *child; unsigned long old_rate; + unsigned long best_parent_rate = 0; struct hlist_node *tmp; old_rate = clk->rate; + if (clk->parent) + best_parent_rate = clk->parent->rate; + if (clk->ops->set_rate) clk->ops->set_rate(clk->hw, clk->new_rate); if (clk->ops->recalc_rate) - clk->rate = clk->ops->recalc_rate(clk->hw, - clk->parent->rate); + clk->rate = clk->ops->recalc_rate(clk->hw, best_parent_rate); else - clk->rate = clk->parent->rate; + clk->rate = best_parent_rate; if (clk->notifier_count && old_rate != clk->rate) __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); From 738c88c1b8ebe16c3ecd1694871474b470275d82 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Jun 2012 10:55:44 +0200 Subject: [PATCH 0495/2357] cfg80211: check iface combinations only when iface is running commit f8cdddb8d61d16a156229f0910f7ecfc7a82c003 upstream. Don't validate interface combinations on a stopped interface. Otherwise we might end up being able to create a new interface with a certain type, but won't be able to change an existing interface into that type. This also skips some other functions when interface is stopped and changing interface type. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg [Fixes regression introduced by cherry pick of 463454b5dbd8] Signed-off-by: Paul Gortmaker --- net/wireless/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/util.c b/net/wireless/util.c index b5b689070ba..0eb6cc0c77d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -805,7 +805,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, ntype == NL80211_IFTYPE_P2P_CLIENT)) return -EBUSY; - if (ntype != otype) { + if (ntype != otype && netif_running(dev)) { err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, ntype); if (err) From 5e5006e64cae9603841405af9febb67064869d83 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 17 Jul 2012 02:39:50 -0400 Subject: [PATCH 0496/2357] hrtimer: Provide clock_was_set_delayed() This is a backport of f55a6faa384304c89cfef162768e88374d3312cb clock_was_set() cannot be called from hard interrupt context because it calls on_each_cpu(). For fixing the widely reported leap seconds issue it is necessary to call it from hard interrupt context, i.e. the timer tick code, which does the timekeeping updates. Provide a new function which denotes it in the hrtimer cpu base structure of the cpu on which it is called and raise the hrtimer softirq. We then execute the clock_was_set() notificiation from softirq context in run_hrtimer_softirq(). The hrtimer softirq is rarely used, so polling the flag there is not a performance issue. [ tglx: Made it depend on CONFIG_HIGH_RES_TIMERS. We really should get rid of all this ifdeffery ASAP ] Signed-off-by: John Stultz Reported-by: Jan Engelhardt Reviewed-by: Ingo Molnar Acked-by: Peter Zijlstra Acked-by: Prarit Bhargava Link: http://lkml.kernel.org/r/1341960205-56738-2-git-send-email-johnstul@us.ibm.com Signed-off-by: Thomas Gleixner Cc: Prarit Bhargava Cc: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- include/linux/hrtimer.h | 9 ++++++++- kernel/hrtimer.c | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index fd0dc30c9f1..c9ec9400ee5 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -165,6 +165,7 @@ enum hrtimer_base_type { * @lock: lock protecting the base and associated clock bases * and timers * @active_bases: Bitfield to mark bases with active timers + * @clock_was_set: Indicates that clock was set from irq context. * @expires_next: absolute time of the next event which was scheduled * via clock_set_next_event() * @hres_active: State of high resolution mode @@ -177,7 +178,8 @@ enum hrtimer_base_type { */ struct hrtimer_cpu_base { raw_spinlock_t lock; - unsigned long active_bases; + unsigned int active_bases; + unsigned int clock_was_set; #ifdef CONFIG_HIGH_RES_TIMERS ktime_t expires_next; int hres_active; @@ -286,6 +288,8 @@ extern void hrtimer_peek_ahead_timers(void); # define MONOTONIC_RES_NSEC HIGH_RES_NSEC # define KTIME_MONOTONIC_RES KTIME_HIGH_RES +extern void clock_was_set_delayed(void); + #else # define MONOTONIC_RES_NSEC LOW_RES_NSEC @@ -306,6 +310,9 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer) { return 0; } + +static inline void clock_was_set_delayed(void) { } + #endif extern void clock_was_set(void); diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index ae34bf51682..3c24fb2c25c 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -717,6 +717,19 @@ static int hrtimer_switch_to_hres(void) return 1; } +/* + * Called from timekeeping code to reprogramm the hrtimer interrupt + * device. If called from the timer interrupt context we defer it to + * softirq context. + */ +void clock_was_set_delayed(void) +{ + struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + + cpu_base->clock_was_set = 1; + __raise_softirq_irqoff(HRTIMER_SOFTIRQ); +} + #else static inline int hrtimer_hres_active(void) { return 0; } @@ -1395,6 +1408,13 @@ void hrtimer_peek_ahead_timers(void) static void run_hrtimer_softirq(struct softirq_action *h) { + struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + + if (cpu_base->clock_was_set) { + cpu_base->clock_was_set = 0; + clock_was_set(); + } + hrtimer_peek_ahead_timers(); } From 2e947d469fba2c2036ff50a2e58a1875ab2ea6b6 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 17 Jul 2012 02:39:51 -0400 Subject: [PATCH 0497/2357] timekeeping: Fix leapsecond triggered load spike issue This is a backport of 4873fa070ae84a4115f0b3c9dfabc224f1bc7c51 The timekeeping code misses an update of the hrtimer subsystem after a leap second happened. Due to that timers based on CLOCK_REALTIME are either expiring a second early or late depending on whether a leap second has been inserted or deleted until an operation is initiated which causes that update. Unless the update happens by some other means this discrepancy between the timekeeping and the hrtimer data stays forever and timers are expired either early or late. The reported immediate workaround - $ data -s "`date`" - is causing a call to clock_was_set() which updates the hrtimer data structures. See: http://www.sheeri.com/content/mysql-and-leap-second-high-cpu-and-fix Add the missing clock_was_set() call to update_wall_time() in case of a leap second event. The actual update is deferred to softirq context as the necessary smp function call cannot be invoked from hard interrupt context. Signed-off-by: John Stultz Reported-by: Jan Engelhardt Reviewed-by: Ingo Molnar Acked-by: Peter Zijlstra Acked-by: Prarit Bhargava Link: http://lkml.kernel.org/r/1341960205-56738-3-git-send-email-johnstul@us.ibm.com Signed-off-by: Thomas Gleixner Cc: Prarit Bhargava Cc: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/time/timekeeping.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index d42574df7c5..9588f0c3c36 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -965,6 +965,8 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) leap = second_overflow(timekeeper.xtime.tv_sec); timekeeper.xtime.tv_sec += leap; timekeeper.wall_to_monotonic.tv_sec -= leap; + if (leap) + clock_was_set_delayed(); } /* Accumulate raw time */ @@ -1081,6 +1083,8 @@ static void update_wall_time(void) leap = second_overflow(timekeeper.xtime.tv_sec); timekeeper.xtime.tv_sec += leap; timekeeper.wall_to_monotonic.tv_sec -= leap; + if (leap) + clock_was_set_delayed(); } timekeeping_update(false); From 7d1f07113b1b32da1eabce0dc74d9f96bbb7b90a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 17 Jul 2012 02:39:52 -0400 Subject: [PATCH 0498/2357] timekeeping: Maintain ktime_t based offsets for hrtimers This is a backport of 5b9fe759a678e05be4937ddf03d50e950207c1c0 We need to update the hrtimer clock offsets from the hrtimer interrupt context. To avoid conversions from timespec to ktime_t maintain a ktime_t based representation of those offsets in the timekeeper. This puts the conversion overhead into the code which updates the underlying offsets and provides fast accessible values in the hrtimer interrupt. Signed-off-by: Thomas Gleixner Signed-off-by: John Stultz Reviewed-by: Ingo Molnar Acked-by: Peter Zijlstra Acked-by: Prarit Bhargava Link: http://lkml.kernel.org/r/1341960205-56738-4-git-send-email-johnstul@us.ibm.com Signed-off-by: Thomas Gleixner Cc: Prarit Bhargava Cc: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/time/timekeeping.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 9588f0c3c36..615ec8d1498 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -70,6 +70,12 @@ struct timekeeper { /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ struct timespec raw_time; + /* Offset clock monotonic -> clock realtime */ + ktime_t offs_real; + + /* Offset clock monotonic -> clock boottime */ + ktime_t offs_boot; + /* Seqlock for all timekeeper values */ seqlock_t lock; }; @@ -172,6 +178,14 @@ static inline s64 timekeeping_get_ns_raw(void) return clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift); } +static void update_rt_offset(void) +{ + struct timespec tmp, *wtm = &timekeeper.wall_to_monotonic; + + set_normalized_timespec(&tmp, -wtm->tv_sec, -wtm->tv_nsec); + timekeeper.offs_real = timespec_to_ktime(tmp); +} + /* must hold write on timekeeper.lock */ static void timekeeping_update(bool clearntp) { @@ -179,6 +193,7 @@ static void timekeeping_update(bool clearntp) timekeeper.ntp_error = 0; ntp_clear(); } + update_rt_offset(); update_vsyscall(&timekeeper.xtime, &timekeeper.wall_to_monotonic, timekeeper.clock, timekeeper.mult); } @@ -606,6 +621,7 @@ void __init timekeeping_init(void) } set_normalized_timespec(&timekeeper.wall_to_monotonic, -boot.tv_sec, -boot.tv_nsec); + update_rt_offset(); timekeeper.total_sleep_time.tv_sec = 0; timekeeper.total_sleep_time.tv_nsec = 0; write_sequnlock_irqrestore(&timekeeper.lock, flags); @@ -614,6 +630,12 @@ void __init timekeeping_init(void) /* time in seconds when suspend began */ static struct timespec timekeeping_suspend_time; +static void update_sleep_time(struct timespec t) +{ + timekeeper.total_sleep_time = t; + timekeeper.offs_boot = timespec_to_ktime(t); +} + /** * __timekeeping_inject_sleeptime - Internal function to add sleep interval * @delta: pointer to a timespec delta value @@ -632,8 +654,7 @@ static void __timekeeping_inject_sleeptime(struct timespec *delta) timekeeper.xtime = timespec_add(timekeeper.xtime, *delta); timekeeper.wall_to_monotonic = timespec_sub(timekeeper.wall_to_monotonic, *delta); - timekeeper.total_sleep_time = timespec_add( - timekeeper.total_sleep_time, *delta); + update_sleep_time(timespec_add(timekeeper.total_sleep_time, *delta)); } From dd3cded0f516201d3b72999e588a6d67e00cb82f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 17 Jul 2012 02:39:53 -0400 Subject: [PATCH 0499/2357] hrtimers: Move lock held region in hrtimer_interrupt() This is a backport of 196951e91262fccda81147d2bcf7fdab08668b40 We need to update the base offsets from this code and we need to do that under base->lock. Move the lock held region around the ktime_get() calls. The ktime_get() calls are going to be replaced with a function which gets the time and the offsets atomically. Signed-off-by: Thomas Gleixner Reviewed-by: Ingo Molnar Acked-by: Peter Zijlstra Acked-by: Prarit Bhargava Signed-off-by: John Stultz Link: http://lkml.kernel.org/r/1341960205-56738-6-git-send-email-johnstul@us.ibm.com Signed-off-by: Thomas Gleixner Cc: Prarit Bhargava Cc: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/hrtimer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 3c24fb2c25c..8f320af837b 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -1263,11 +1263,10 @@ void hrtimer_interrupt(struct clock_event_device *dev) cpu_base->nr_events++; dev->next_event.tv64 = KTIME_MAX; + raw_spin_lock(&cpu_base->lock); entry_time = now = ktime_get(); retry: expires_next.tv64 = KTIME_MAX; - - raw_spin_lock(&cpu_base->lock); /* * We set expires_next to KTIME_MAX here with cpu_base->lock * held to prevent that a timer is enqueued in our queue via @@ -1344,6 +1343,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) * interrupt routine. We give it 3 attempts to avoid * overreacting on some spurious event. */ + raw_spin_lock(&cpu_base->lock); now = ktime_get(); cpu_base->nr_retries++; if (++retries < 3) @@ -1356,6 +1356,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) */ cpu_base->nr_hangs++; cpu_base->hang_detected = 1; + raw_spin_unlock(&cpu_base->lock); delta = ktime_sub(now, entry_time); if (delta.tv64 > cpu_base->max_hang_time.tv64) cpu_base->max_hang_time = delta; From 765bdc4d82fadcddfec19222a545e904633c7816 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 17 Jul 2012 02:39:54 -0400 Subject: [PATCH 0500/2357] timekeeping: Provide hrtimer update function This is a backport of f6c06abfb3972ad4914cef57d8348fcb2932bc3b To finally fix the infamous leap second issue and other race windows caused by functions which change the offsets between the various time bases (CLOCK_MONOTONIC, CLOCK_REALTIME and CLOCK_BOOTTIME) we need a function which atomically gets the current monotonic time and updates the offsets of CLOCK_REALTIME and CLOCK_BOOTTIME with minimalistic overhead. The previous patch which provides ktime_t offsets allows us to make this function almost as cheap as ktime_get() which is going to be replaced in hrtimer_interrupt(). Signed-off-by: Thomas Gleixner Reviewed-by: Ingo Molnar Acked-by: Peter Zijlstra Acked-by: Prarit Bhargava Signed-off-by: John Stultz Link: http://lkml.kernel.org/r/1341960205-56738-7-git-send-email-johnstul@us.ibm.com Signed-off-by: Thomas Gleixner Cc: Prarit Bhargava Cc: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- include/linux/hrtimer.h | 1 + kernel/time/timekeeping.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index c9ec9400ee5..cc07d2777bb 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -327,6 +327,7 @@ extern ktime_t ktime_get(void); extern ktime_t ktime_get_real(void); extern ktime_t ktime_get_boottime(void); extern ktime_t ktime_get_monotonic_offset(void); +extern ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot); DECLARE_PER_CPU(struct tick_device, tick_cpu_device); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 615ec8d1498..62e12c354ef 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1273,6 +1273,40 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, } while (read_seqretry(&timekeeper.lock, seq)); } +#ifdef CONFIG_HIGH_RES_TIMERS +/** + * ktime_get_update_offsets - hrtimer helper + * @offs_real: pointer to storage for monotonic -> realtime offset + * @offs_boot: pointer to storage for monotonic -> boottime offset + * + * Returns current monotonic time and updates the offsets + * Called from hrtimer_interupt() or retrigger_next_event() + */ +ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot) +{ + ktime_t now; + unsigned int seq; + u64 secs, nsecs; + + do { + seq = read_seqbegin(&timekeeper.lock); + + secs = timekeeper.xtime.tv_sec; + nsecs = timekeeper.xtime.tv_nsec; + nsecs += timekeeping_get_ns(); + /* If arch requires, add in gettimeoffset() */ + nsecs += arch_gettimeoffset(); + + *offs_real = timekeeper.offs_real; + *offs_boot = timekeeper.offs_boot; + } while (read_seqretry(&timekeeper.lock, seq)); + + now = ktime_add_ns(ktime_set(secs, 0), nsecs); + now = ktime_sub(now, *offs_real); + return now; +} +#endif + /** * ktime_get_monotonic_offset() - get wall_to_monotonic in ktime_t format */ From 6321a0a1a3a9d6c9cbd73d9a4159a97ac3bc0919 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 17 Jul 2012 02:39:55 -0400 Subject: [PATCH 0501/2357] hrtimer: Update hrtimer base offsets each hrtimer_interrupt This is a backport of 5baefd6d84163443215f4a99f6a20f054ef11236 The update of the hrtimer base offsets on all cpus cannot be made atomically from the timekeeper.lock held and interrupt disabled region as smp function calls are not allowed there. clock_was_set(), which enforces the update on all cpus, is called either from preemptible process context in case of do_settimeofday() or from the softirq context when the offset modification happened in the timer interrupt itself due to a leap second. In both cases there is a race window for an hrtimer interrupt between dropping timekeeper lock, enabling interrupts and clock_was_set() issuing the updates. Any interrupt which arrives in that window will see the new time but operate on stale offsets. So we need to make sure that an hrtimer interrupt always sees a consistent state of time and offsets. ktime_get_update_offsets() allows us to get the current monotonic time and update the per cpu hrtimer base offsets from hrtimer_interrupt() to capture a consistent state of monotonic time and the offsets. The function replaces the existing ktime_get() calls in hrtimer_interrupt(). The overhead of the new function vs. ktime_get() is minimal as it just adds two store operations. This ensures that any changes to realtime or boottime offsets are noticed and stored into the per-cpu hrtimer base structures, prior to any hrtimer expiration and guarantees that timers are not expired early. Signed-off-by: John Stultz Reviewed-by: Ingo Molnar Acked-by: Peter Zijlstra Acked-by: Prarit Bhargava Link: http://lkml.kernel.org/r/1341960205-56738-8-git-send-email-johnstul@us.ibm.com Signed-off-by: Thomas Gleixner Cc: Prarit Bhargava Cc: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/hrtimer.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 8f320af837b..6db7a5ed52b 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -657,6 +657,14 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, return 0; } +static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) +{ + ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset; + ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset; + + return ktime_get_update_offsets(offs_real, offs_boot); +} + /* * Retrigger next event is called after clock was set * @@ -665,22 +673,12 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, static void retrigger_next_event(void *arg) { struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases); - struct timespec realtime_offset, xtim, wtm, sleep; if (!hrtimer_hres_active()) return; - /* Optimized out for !HIGH_RES */ - get_xtime_and_monotonic_and_sleep_offset(&xtim, &wtm, &sleep); - set_normalized_timespec(&realtime_offset, -wtm.tv_sec, -wtm.tv_nsec); - - /* Adjust CLOCK_REALTIME offset */ raw_spin_lock(&base->lock); - base->clock_base[HRTIMER_BASE_REALTIME].offset = - timespec_to_ktime(realtime_offset); - base->clock_base[HRTIMER_BASE_BOOTTIME].offset = - timespec_to_ktime(sleep); - + hrtimer_update_base(base); hrtimer_force_reprogram(base, 0); raw_spin_unlock(&base->lock); } @@ -710,7 +708,6 @@ static int hrtimer_switch_to_hres(void) base->clock_base[i].resolution = KTIME_HIGH_RES; tick_setup_sched_timer(); - /* "Retrigger" the interrupt to get things going */ retrigger_next_event(NULL); local_irq_restore(flags); @@ -1264,7 +1261,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) dev->next_event.tv64 = KTIME_MAX; raw_spin_lock(&cpu_base->lock); - entry_time = now = ktime_get(); + entry_time = now = hrtimer_update_base(cpu_base); retry: expires_next.tv64 = KTIME_MAX; /* @@ -1342,9 +1339,12 @@ void hrtimer_interrupt(struct clock_event_device *dev) * We need to prevent that we loop forever in the hrtimer * interrupt routine. We give it 3 attempts to avoid * overreacting on some spurious event. + * + * Acquire base lock for updating the offsets and retrieving + * the current time. */ raw_spin_lock(&cpu_base->lock); - now = ktime_get(); + now = hrtimer_update_base(cpu_base); cpu_base->nr_retries++; if (++retries < 3) goto retry; From 3cdeda1e763ccb2287c6ee76ece14145027653a9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 17 Jul 2012 02:39:56 -0400 Subject: [PATCH 0502/2357] timekeeping: Add missing update call in timekeeping_resume() This is a backport of 3e997130bd2e8c6f5aaa49d6e3161d4d29b43ab0 The leap second rework unearthed another issue of inconsistent data. On timekeeping_resume() the timekeeper data is updated, but nothing calls timekeeping_update(), so now the update code in the timer interrupt sees stale values. This has been the case before those changes, but then the timer interrupt was using stale data as well so this went unnoticed for quite some time. Add the missing update call, so all the data is consistent everywhere. Reported-by: Andreas Schwab Reported-and-tested-by: "Rafael J. Wysocki" Reported-and-tested-by: Martin Steigerwald Cc: John Stultz Cc: Ingo Molnar Cc: Peter Zijlstra , Cc: Prarit Bhargava Signed-off-by: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Linus Torvalds Cc: Prarit Bhargava Cc: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/time/timekeeping.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 62e12c354ef..7c50de83b6f 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -719,6 +719,7 @@ static void timekeeping_resume(void) timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock); timekeeper.ntp_error = 0; timekeeping_suspended = 0; + timekeeping_update(false); write_sequnlock_irqrestore(&timekeeper.lock, flags); touch_softlockup_watchdog(); From 016e7d822a72c4cbcbf7e4bc6d590cf50879ec26 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 10 May 2012 19:45:51 +0200 Subject: [PATCH 0503/2357] NFC: Export nfc.h to userland commit dbd4fcaf8d664fab4163b1f8682e41ad8bff3444 upstream. The netlink commands and attributes, along with the socket structure definitions need to be exported. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- include/linux/Kbuild | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 50f55c77f8b..f2f73f9b986 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -272,6 +272,7 @@ header-y += netfilter_ipv4.h header-y += netfilter_ipv6.h header-y += netlink.h header-y += netrom.h +header-y += nfc.h header-y += nfs.h header-y += nfs2.h header-y += nfs3.h From 1c8f63c2758096c3b6425f4ecb274901151d6f17 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 19 Jul 2012 12:11:49 -0700 Subject: [PATCH 0504/2357] Linux 3.4.6 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a2e69a08b7e..5d0edcbd878 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 5 +SUBLEVEL = 6 EXTRAVERSION = NAME = Saber-toothed Squirrel From 2ac8a0f58a8782ff8024404a579eee260e8b2010 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 19 Jul 2012 15:59:18 +1000 Subject: [PATCH 0505/2357] md: avoid crash when stopping md array races with closing other open fds. commit a05b7ea03d72f36edb0cec05e8893803335c61a0 upstream. md will refuse to stop an array if any other fd (or mounted fs) is using it. When any fs is unmounted of when the last open fd is closed all pending IO will be flushed (e.g. sync_blockdev call in __blkdev_put) so there will be no pending IO to worry about when the array is stopped. However in order to send the STOP_ARRAY ioctl to stop the array one must first get and open fd on the block device. If some fd is being used to write to the block device and it is closed after mdadm open the block device, but before mdadm issues the STOP_ARRAY ioctl, then there will be no last-close on the md device so __blkdev_put will not call sync_blockdev. If this happens, then IO can still be in-flight while md tears down the array and bad things can happen (use-after-free and subsequent havoc). So in the case where do_md_stop is being called from an open file descriptor, call sync_block after taking the mutex to ensure there will be no new openers. This is needed when setting a read-write device to read-only too. Reported-by: majianpeng Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 2b30ffdb81b..9ee8ce3e965 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3744,8 +3744,8 @@ array_state_show(struct mddev *mddev, char *page) return sprintf(page, "%s\n", array_states[st]); } -static int do_md_stop(struct mddev * mddev, int ro, int is_open); -static int md_set_readonly(struct mddev * mddev, int is_open); +static int do_md_stop(struct mddev * mddev, int ro, struct block_device *bdev); +static int md_set_readonly(struct mddev * mddev, struct block_device *bdev); static int do_md_run(struct mddev * mddev); static int restart_array(struct mddev *mddev); @@ -3761,14 +3761,14 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) /* stopping an active array */ if (atomic_read(&mddev->openers) > 0) return -EBUSY; - err = do_md_stop(mddev, 0, 0); + err = do_md_stop(mddev, 0, NULL); break; case inactive: /* stopping an active array */ if (mddev->pers) { if (atomic_read(&mddev->openers) > 0) return -EBUSY; - err = do_md_stop(mddev, 2, 0); + err = do_md_stop(mddev, 2, NULL); } else err = 0; /* already inactive */ break; @@ -3776,7 +3776,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) break; /* not supported yet */ case readonly: if (mddev->pers) - err = md_set_readonly(mddev, 0); + err = md_set_readonly(mddev, NULL); else { mddev->ro = 1; set_disk_ro(mddev->gendisk, 1); @@ -3786,7 +3786,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) case read_auto: if (mddev->pers) { if (mddev->ro == 0) - err = md_set_readonly(mddev, 0); + err = md_set_readonly(mddev, NULL); else if (mddev->ro == 1) err = restart_array(mddev); if (err == 0) { @@ -5124,15 +5124,17 @@ void md_stop(struct mddev *mddev) } EXPORT_SYMBOL_GPL(md_stop); -static int md_set_readonly(struct mddev *mddev, int is_open) +static int md_set_readonly(struct mddev *mddev, struct block_device *bdev) { int err = 0; mutex_lock(&mddev->open_mutex); - if (atomic_read(&mddev->openers) > is_open) { + if (atomic_read(&mddev->openers) > !!bdev) { printk("md: %s still in use.\n",mdname(mddev)); err = -EBUSY; goto out; } + if (bdev) + sync_blockdev(bdev); if (mddev->pers) { __md_stop_writes(mddev); @@ -5154,18 +5156,26 @@ static int md_set_readonly(struct mddev *mddev, int is_open) * 0 - completely stop and dis-assemble array * 2 - stop but do not disassemble array */ -static int do_md_stop(struct mddev * mddev, int mode, int is_open) +static int do_md_stop(struct mddev * mddev, int mode, + struct block_device *bdev) { struct gendisk *disk = mddev->gendisk; struct md_rdev *rdev; mutex_lock(&mddev->open_mutex); - if (atomic_read(&mddev->openers) > is_open || + if (atomic_read(&mddev->openers) > !!bdev || mddev->sysfs_active) { printk("md: %s still in use.\n",mdname(mddev)); mutex_unlock(&mddev->open_mutex); return -EBUSY; } + if (bdev) + /* It is possible IO was issued on some other + * open file which was closed before we took ->open_mutex. + * As that was not the last close __blkdev_put will not + * have called sync_blockdev, so we must. + */ + sync_blockdev(bdev); if (mddev->pers) { if (mddev->ro) @@ -5239,7 +5249,7 @@ static void autorun_array(struct mddev *mddev) err = do_md_run(mddev); if (err) { printk(KERN_WARNING "md: do_md_run() returned %d\n", err); - do_md_stop(mddev, 0, 0); + do_md_stop(mddev, 0, NULL); } } @@ -6237,11 +6247,11 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, goto done_unlock; case STOP_ARRAY: - err = do_md_stop(mddev, 0, 1); + err = do_md_stop(mddev, 0, bdev); goto done_unlock; case STOP_ARRAY_RO: - err = md_set_readonly(mddev, 1); + err = md_set_readonly(mddev, bdev); goto done_unlock; case BLKROSET: From d8ae4bb4a1c12f9cfb373f215e624a9f1fca0767 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 19 Jul 2012 15:59:18 +1000 Subject: [PATCH 0506/2357] md/raid1: close some possible races on write errors during resync commit 58e94ae18478c08229626daece2fc108a4a23261 upstream. commit 4367af556133723d0f443e14ca8170d9447317cb md/raid1: clear bad-block record when write succeeds. Added a 'reschedule_retry' call possibility at the end of end_sync_write, but didn't add matching code at the end of sync_request_write. So if the writes complete very quickly, or scheduling makes it seem that way, then we can miss rescheduling the request and the resync could hang. Also commit 73d5c38a9536142e062c35997b044e89166e063b md: avoid races when stopping resync. Fix a race condition in this same code in end_sync_write but didn't make the change in sync_request_write. This patch updates sync_request_write to fix both of those. Patch is suitable for 3.1 and later kernels. Reported-by: Alexander Lyakas Original-version-by: Alexander Lyakas Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid1.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index d1f74ab1396..d7add9d5bac 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1821,8 +1821,14 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio) if (atomic_dec_and_test(&r1_bio->remaining)) { /* if we're here, all write(s) have completed, so clean up */ - md_done_sync(mddev, r1_bio->sectors, 1); - put_buf(r1_bio); + int s = r1_bio->sectors; + if (test_bit(R1BIO_MadeGood, &r1_bio->state) || + test_bit(R1BIO_WriteError, &r1_bio->state)) + reschedule_retry(r1_bio); + else { + put_buf(r1_bio); + md_done_sync(mddev, s, 1); + } } } From f952e137849253c0584a60cc2d73a220d9a091f8 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 6 Jul 2012 07:09:42 -0400 Subject: [PATCH 0507/2357] cifs: always update the inode cache with the results from a FIND_* commit cd60042cc1392e79410dc8de9e9c1abb38a29e57 upstream. When we get back a FIND_FIRST/NEXT result, we have some info about the dentry that we use to instantiate a new inode. We were ignoring and discarding that info when we had an existing dentry in the cache. Fix this by updating the inode in place when we find an existing dentry and the uniqueid is the same. Reported-and-Tested-by: Andrew Bartlett Reported-by: Bill Robertson Reported-by: Dion Edwards Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/readdir.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 0a8224d1c4c..a4217f02fab 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -86,9 +86,12 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, dentry = d_lookup(parent, name); if (dentry) { - /* FIXME: check for inode number changes? */ - if (dentry->d_inode != NULL) + inode = dentry->d_inode; + /* update inode in place if i_ino didn't change */ + if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { + cifs_fattr_to_inode(inode, fattr); return dentry; + } d_drop(dentry); dput(dentry); } From c82cd13737cfab6cb9d1b31e624896e627f9c9e4 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 11 Jul 2012 09:09:35 -0400 Subject: [PATCH 0508/2357] cifs: on CONFIG_HIGHMEM machines, limit the rsize/wsize to the kmap space commit 3ae629d98bd5ed77585a878566f04f310adbc591 upstream. We currently rely on being able to kmap all of the pages in an async read or write request. If you're on a machine that has CONFIG_HIGHMEM set then that kmap space is limited, sometimes to as low as 512 slots. With 512 slots, we can only support up to a 2M r/wsize, and that's assuming that we can get our greedy little hands on all of them. There are other users however, so it's possible we'll end up stuck with a size that large. Since we can't handle a rsize or wsize larger than that currently, cap those options at the number of kmap slots we have. We could consider capping it even lower, but we currently default to a max of 1M. Might as well allow those luddites on 32 bit arches enough rope to hang themselves. A more robust fix would be to teach the send and receive routines how to contend with an array of pages so we don't need to marshal up a kvec array at all. That's a fairly significant overhaul though, so we'll need this limit in place until that's ready. Reported-by: Jian Li Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/connect.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 402fa0f9bc0..87ce8af1ce4 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3348,6 +3348,18 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, #define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024) #define CIFS_DEFAULT_NON_POSIX_WSIZE (65536) +/* + * On hosts with high memory, we can't currently support wsize/rsize that are + * larger than we can kmap at once. Cap the rsize/wsize at + * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request + * larger than that anyway. + */ +#ifdef CONFIG_HIGHMEM +#define CIFS_KMAP_SIZE_LIMIT (LAST_PKMAP * PAGE_CACHE_SIZE) +#else /* CONFIG_HIGHMEM */ +#define CIFS_KMAP_SIZE_LIMIT (1<<24) +#endif /* CONFIG_HIGHMEM */ + static unsigned int cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) { @@ -3378,6 +3390,9 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) wsize = min_t(unsigned int, wsize, server->maxBuf - sizeof(WRITE_REQ) + 4); + /* limit to the amount that we can kmap at once */ + wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT); + /* hard limit of CIFS_MAX_WSIZE */ wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE); @@ -3419,6 +3434,9 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) if (!(server->capabilities & CAP_LARGE_READ_X)) rsize = min_t(unsigned int, CIFSMaxBufSize, rsize); + /* limit to the amount that we can kmap at once */ + rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT); + /* hard limit of CIFS_MAX_RSIZE */ rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE); From 815faab2c4b7deb2cc6495186307ceb0983214a9 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:17:10 -0700 Subject: [PATCH 0509/2357] target: Clean up returning errors in PR handling code commit d35212f3ca3bf4fb49d15e37f530c9931e2d2183 upstream. - instead of (PTR_ERR(file) < 0) just use IS_ERR(file) - return -EINVAL instead of EINVAL - all other error returns in target_scsi3_emulate_pr_out() use "goto out" -- get rid of the one remaining straight "return." Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_pr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index c3148b10b4b..89d10e6a82e 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -2038,7 +2038,7 @@ static int __core_scsi3_write_aptpl_to_file( if (IS_ERR(file) || !file || !file->f_dentry) { pr_err("filp_open(%s) for APTPL metadata" " failed\n", path); - return (PTR_ERR(file) < 0 ? PTR_ERR(file) : -ENOENT); + return IS_ERR(file) ? PTR_ERR(file) : -ENOENT; } iov[0].iov_base = &buf[0]; @@ -3826,7 +3826,7 @@ int target_scsi3_emulate_pr_out(struct se_task *task) " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - ret = EINVAL; + ret = -EINVAL; goto out; } @@ -3836,7 +3836,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task) */ if (!cmd->se_sess) { cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + ret = -EINVAL; + goto out; } if (cmd->data_length < 24) { From 5c8c9e57270fc5f54aa02144f7280f91ee2e3334 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 17:10:17 -0700 Subject: [PATCH 0510/2357] target: Fix range calculation in WRITE SAME emulation when num blocks == 0 commit 1765fe5edcb83f53fc67edeb559fcf4bc82c6460 upstream. When NUMBER OF LOGICAL BLOCKS is 0, WRITE SAME is supposed to write all the blocks from the specified LBA through the end of the device. However, dev->transport->get_blocks(dev) (perhaps confusingly) returns the last valid LBA rather than the number of blocks, so the correct number of blocks to write starting with lba is dev->transport->get_blocks(dev) - lba + 1 (nab: Backport roland's for-3.6 patch to for-3.5) Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_cdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 30a67707036..fa323f8aa17 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -1107,7 +1107,7 @@ int target_emulate_write_same(struct se_task *task) if (num_blocks != 0) range = num_blocks; else - range = (dev->transport->get_blocks(dev) - lba); + range = (dev->transport->get_blocks(dev) - lba) + 1; pr_debug("WRITE_SAME UNMAP: LBA: %llu Range: %llu\n", (unsigned long long)lba, (unsigned long long)range); From fd25080998d00a94a87bf7fc9f843291db7250a6 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 13 Jul 2012 01:21:50 -0400 Subject: [PATCH 0511/2357] ntp: Fix STA_INS/DEL clearing bug commit 6b1859dba01c7d512b72d77e3fd7da8354235189 upstream. In commit 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d, I introduced a bug that kept the STA_INS or STA_DEL bit from being cleared from time_status via adjtimex() without forcing STA_PLL first. Usually once the STA_INS is set, it isn't cleared until the leap second is applied, so its unlikely this affected anyone. However during testing I noticed it took some effort to cancel a leap second once STA_INS was set. Signed-off-by: John Stultz Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Richard Cochran Cc: Prarit Bhargava Link: http://lkml.kernel.org/r/1342156917-25092-2-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/time/ntp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index e8c867173ae..8b707100286 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -409,7 +409,9 @@ int second_overflow(unsigned long secs) time_state = TIME_DEL; break; case TIME_INS: - if (secs % 86400 == 0) { + if (!(time_status & STA_INS)) + time_state = TIME_OK; + else if (secs % 86400 == 0) { leap = -1; time_state = TIME_OOP; time_tai++; @@ -418,7 +420,9 @@ int second_overflow(unsigned long secs) } break; case TIME_DEL: - if ((secs + 1) % 86400 == 0) { + if (!(time_status & STA_DEL)) + time_state = TIME_OK; + else if ((secs + 1) % 86400 == 0) { leap = 1; time_tai--; time_state = TIME_WAIT; From 8db5153f9dca89afbeebe0b077e7cc1e5827e07a Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Fri, 13 Jul 2012 18:18:04 -0700 Subject: [PATCH 0512/2357] tcm_fc: Fix crash seen with aborts and large reads commit 3cc5d2a6b9a2fd1bf024aa5e52dd22961eecaf13 upstream. This patch fixes a crash seen when large reads have their exchange aborted by either timing out or being reset. Because the exchange abort results in the seq pointer being set to NULL, because the sequence is no longer valid, it must not be dereferenced. This patch changes the function ft_get_task_tag to return ~0 if it is unable to get the tag for this reason. Because the get_task_tag interface provides no means of returning an error, this seems like the best way to fix this issue at the moment. Signed-off-by: Mark Rustad Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/tcm_fc/tfc_cmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index a375f257aab..da90f647695 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -240,6 +240,8 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + if (cmd->aborted) + return ~0; return fc_seq_exch(cmd->seq)->rxid; } From 2dbbb550c56cbaf9d8353f4546aab9a88786d279 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 18 Jul 2012 09:31:36 +0100 Subject: [PATCH 0513/2357] ext4: fix duplicated mnt_drop_write call in EXT4_IOC_MOVE_EXT commit 331ae4962b975246944ea039697a8f1cadce42bb upstream. Caused, AFAICS, by mismerge in commit ff9cb1c4eead ("Merge branch 'for_linus' into for_linus_merged") Signed-off-by: Al Viro Cc: Theodore Ts'o Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ioctl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 1365903a514..9727522e271 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -261,7 +261,6 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) err = ext4_move_extents(filp, donor_filp, me.orig_start, me.donor_start, me.len, &me.moved_len); mnt_drop_write_file(filp); - mnt_drop_write(filp->f_path.mnt); if (copy_to_user((struct move_extent __user *)arg, &me, sizeof(me))) From 07aa70120e4be526a468b9c3ea93b45cfbe95013 Mon Sep 17 00:00:00 2001 From: Aaditya Kumar Date: Tue, 17 Jul 2012 15:48:07 -0700 Subject: [PATCH 0514/2357] mm: fix lost kswapd wakeup in kswapd_stop() commit 1c7e7f6c0703d03af6bcd5ccc11fc15d23e5ecbe upstream. Offlining memory may block forever, waiting for kswapd() to wake up because kswapd() does not check the event kthread->should_stop before sleeping. The proper pattern, from Documentation/memory-barriers.txt, is: --- waker --- event_indicated = 1; wake_up_process(event_daemon); --- sleeper --- for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); if (event_indicated) break; schedule(); } set_current_state() may be wrapped by: prepare_to_wait(); In the kswapd() case, event_indicated is kthread->should_stop. === offlining memory (waker) === kswapd_stop() kthread_stop() kthread->should_stop = 1 wake_up_process() wait_for_completion() === kswapd_try_to_sleep (sleeper) === kswapd_try_to_sleep() prepare_to_wait() . . schedule() . . finish_wait() The schedule() needs to be protected by a test of kthread->should_stop, which is wrapped by kthread_should_stop(). Reproducer: Do heavy file I/O in background. Do a memory offline/online in a tight loop Signed-off-by: Aaditya Kumar Acked-by: KOSAKI Motohiro Reviewed-by: Minchan Kim Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/vmscan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 4607cc62b1d..be5bc0af2e7 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -3013,7 +3013,10 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order, int classzone_idx) * them before going back to sleep. */ set_pgdat_percpu_threshold(pgdat, calculate_normal_threshold); - schedule(); + + if (!kthread_should_stop()) + schedule(); + set_pgdat_percpu_threshold(pgdat, calculate_pressure_threshold); } else { if (remaining) From e58cd46e372812120c547f1b311f7a1a00c22af4 Mon Sep 17 00:00:00 2001 From: Daniel Nicoletti Date: Wed, 4 Jul 2012 10:20:31 -0300 Subject: [PATCH 0515/2357] HID: add battery quirk for Apple Wireless ANSI commit 0c47935c5b5cd4916cf1c1ed4a2894807f7bcc3e upstream. Add USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, to the quirk list since it report wrong feature type and wrong percentage range. Signed-off-by: Daniel Nicoletti Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 002781c5a61..21e473e7fe2 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -290,6 +290,9 @@ static const struct hid_device_id hid_battery_quirks[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, {} }; From eb6cf92d839f43dbc2009a2440479f46f7adfd46 Mon Sep 17 00:00:00 2001 From: Frank Kunz Date: Thu, 5 Jul 2012 22:32:49 +0200 Subject: [PATCH 0516/2357] HID: add Sennheiser BTD500USB device support commit 0e050923a797c1fc46ccc1e5182fd3090f33a75d upstream. The Sennheiser BTD500USB composit device requires the HID_QUIRK_NOGET flag to be set for working proper. Without the flag the device crashes during hid intialization. Signed-off-by: Frank Kunz Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index dfd40981c86..7dc2ff72d5e 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -650,6 +650,9 @@ #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 #define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600 +#define USB_VENDOR_ID_SENNHEISER 0x1395 +#define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c + #define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f #define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 782c63955f2..82f61ee632b 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -76,6 +76,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET }, From 60d091aeb66c0b201689862bcb803c32db712d05 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 20 Apr 2012 12:15:44 +0200 Subject: [PATCH 0517/2357] HID: multitouch: Add support for Baanto touchscreen commit 9ed326951806c424b42dcf2e1125e25a98fb13d1 upstream. Reported-by: Tvrtko Ursulin Tested-by: Tvrtko Ursulin Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 054677b3d16..973c238eb9f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1391,6 +1391,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2), }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7dc2ff72d5e..bb1abf83798 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -160,6 +160,9 @@ #define USB_VENDOR_ID_AVERMEDIA 0x07ca #define USB_DEVICE_ID_AVER_FM_MR800 0xb800 +#define USB_VENDOR_ID_BAANTO 0x2453 +#define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100 + #define USB_VENDOR_ID_BELKIN 0x050d #define USB_DEVICE_ID_FLIP_KVM 0x3201 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 543896dfc49..a6197f57203 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -783,6 +783,10 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_ATMEL, USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, + /* Baanto multitouch devices */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_BAANTO, + USB_DEVICE_ID_BAANTO_MT_190W2) }, /* Cando panels */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, HID_USB_DEVICE(USB_VENDOR_ID_CANDO, From ec8348902ff82ae44f25b3127f8f3ec47e1e6a07 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 19 Jul 2012 09:11:14 +0200 Subject: [PATCH 0518/2357] MIPS: Properly align the .data..init_task section. commit 7b1c0d26a8e272787f0f9fcc5f3e8531df3b3409 upstream. Improper alignment can lead to unbootable systems and/or random crashes. [ralf@linux-mips.org: This is a lond standing bug since 6eb10bc9e2deab06630261cd05c4cb1e9a60e980 (kernel.org) rsp. c422a10917f75fd19fa7fe070aaaa23e384dae6f (lmo) [MIPS: Clean up linker script using new linker script macros.] so dates back to 2.6.32.] Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3881/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/thread_info.h | 4 ++-- arch/mips/kernel/vmlinux.lds.S | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index 0d85d8e440c..abb13e83dfd 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -60,6 +60,8 @@ struct thread_info { register struct thread_info *__current_thread_info __asm__("$28"); #define current_thread_info() __current_thread_info +#endif /* !__ASSEMBLY__ */ + /* thread information allocation */ #if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_32BIT) #define THREAD_SIZE_ORDER (1) @@ -97,8 +99,6 @@ register struct thread_info *__current_thread_info __asm__("$28"); #define free_thread_info(info) kfree(info) -#endif /* !__ASSEMBLY__ */ - #define PREEMPT_ACTIVE 0x10000000 /* diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 924da5eb703..df243a64f43 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -1,5 +1,6 @@ #include #include +#include #include #undef mips @@ -72,7 +73,7 @@ SECTIONS .data : { /* Data */ . = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */ - INIT_TASK_DATA(PAGE_SIZE) + INIT_TASK_DATA(THREAD_SIZE) NOSAVE_DATA CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT) READ_MOSTLY_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT) From 863c806617059e412ade0b1bbb6d215106be14c1 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sat, 14 Jul 2012 14:33:09 +0300 Subject: [PATCH 0519/2357] UBIFS: fix a bug in empty space fix-up commit c6727932cfdb13501108b16c38463c09d5ec7a74 upstream. UBIFS has a feature called "empty space fix-up" which is a quirk to work-around limitations of dumb flasher programs. Namely, of those flashers that are unable to skip NAND pages full of 0xFFs while flashing, resulting in empty space at the end of half-filled eraseblocks to be unusable for UBIFS. This feature is relatively new (introduced in v3.0). The fix-up routine (fixup_free_space()) is executed only once at the very first mount if the superblock has the 'space_fixup' flag set (can be done with -F option of mkfs.ubifs). It basically reads all the UBIFS data and metadata and writes it back to the same LEB. The routine assumes the image is pristine and does not have anything in the journal. There was a bug in 'fixup_free_space()' where it fixed up the log incorrectly. All but one LEB of the log of a pristine file-system are empty. And one contains just a commit start node. And 'fixup_free_space()' just unmapped this LEB, which resulted in wiping the commit start node. As a result, some users were unable to mount the file-system next time with the following symptom: UBIFS error (pid 1): replay_log_leb: first log node at LEB 3:0 is not CS node UBIFS error (pid 1): replay_log_leb: log error detected while replaying the log at LEB 3:0 The root-cause of this bug was that 'fixup_free_space()' wrongly assumed that the beginning of empty space in the log head (c->lhead_offs) was known on mount. However, it is not the case - it was always 0. UBIFS does not store in it the master node and finds out by scanning the log on every mount. The fix is simple - just pass commit start node size instead of 0 to 'fixup_leb()'. Signed-off-by: Artem Bityutskiy Reported-by: Iwo Mergler Tested-by: Iwo Mergler Reported-by: James Nute Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/sb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c index 771f7fb6ce9..a7be8e2b4b9 100644 --- a/fs/ubifs/sb.c +++ b/fs/ubifs/sb.c @@ -724,8 +724,12 @@ static int fixup_free_space(struct ubifs_info *c) lnum = ubifs_next_log_lnum(c, lnum); } - /* Fixup the current log head */ - err = fixup_leb(c, c->lhead_lnum, c->lhead_offs); + /* + * Fixup the log head which contains the only a CS node at the + * beginning. + */ + err = fixup_leb(c, c->lhead_lnum, + ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size)); if (err) goto out; From 0234af60fb13cbb7caa6f757e4d8e29cd87aaba6 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Fri, 8 Jun 2012 01:19:07 +0300 Subject: [PATCH 0520/2357] ore: Fix NFS crash by supporting any unaligned RAID IO commit 9ff19309a9623f2963ac5a136782ea4d8b5d67fb upstream. In RAID_5/6 We used to not permit an IO that it's end byte is not stripe_size aligned and spans more than one stripe. .i.e the caller must check if after submission the actual transferred bytes is shorter, and would need to resubmit a new IO with the remainder. Exofs supports this, and NFS was supposed to support this as well with it's short write mechanism. But late testing has exposed a CRASH when this is used with none-RPC layout-drivers. The change at NFS is deep and risky, in it's place the fix at ORE to lift the limitation is actually clean and simple. So here it is below. The principal here is that in the case of unaligned IO on both ends, beginning and end, we will send two read requests one like old code, before the calculation of the first stripe, and also a new site, before the calculation of the last stripe. If any "boundary" is aligned or the complete IO is within a single stripe. we do a single read like before. The code is clean and simple by splitting the old _read_4_write into 3 even parts: 1._read_4_write_first_stripe 2. _read_4_write_last_stripe 3. _read_4_write_execute And calling 1+3 at the same place as before. 2+3 before last stripe, and in the case of all in a single stripe then 1+2+3 is preformed additively. Why did I not think of it before. Well I had a strike of genius because I have stared at this code for 2 years, and did not find this simple solution, til today. Not that I did not try. This solution is much better for NFS than the previous supposedly solution because the short write was dealt with out-of-band after IO_done, which would cause for a seeky IO pattern where as in here we execute in order. At both solutions we do 2 separate reads, only here we do it within a single IO request. (And actually combine two writes into a single submission) NFS/exofs code need not change since the ORE API communicates the new shorter length on return, what will happen is that this case would not occur anymore. hurray!! [Stable this is an NFS bug since 3.2 Kernel should apply cleanly] Signed-off-by: Boaz Harrosh Signed-off-by: Greg Kroah-Hartman --- fs/exofs/ore_raid.c | 67 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/fs/exofs/ore_raid.c b/fs/exofs/ore_raid.c index d222c77cfa1..fff2070c675 100644 --- a/fs/exofs/ore_raid.c +++ b/fs/exofs/ore_raid.c @@ -461,16 +461,12 @@ static void _mark_read4write_pages_uptodate(struct ore_io_state *ios, int ret) * ios->sp2d[p][*], xor is calculated the same way. These pages are * allocated/freed and don't go through cache */ -static int _read_4_write(struct ore_io_state *ios) +static int _read_4_write_first_stripe(struct ore_io_state *ios) { - struct ore_io_state *ios_read; struct ore_striping_info read_si; struct __stripe_pages_2d *sp2d = ios->sp2d; u64 offset = ios->si.first_stripe_start; - u64 last_stripe_end; - unsigned bytes_in_stripe = ios->si.bytes_in_stripe; - unsigned i, c, p, min_p = sp2d->pages_in_unit, max_p = -1; - int ret; + unsigned c, p, min_p = sp2d->pages_in_unit, max_p = -1; if (offset == ios->offset) /* Go to start collect $200 */ goto read_last_stripe; @@ -478,6 +474,9 @@ static int _read_4_write(struct ore_io_state *ios) min_p = _sp2d_min_pg(sp2d); max_p = _sp2d_max_pg(sp2d); + ORE_DBGMSG("stripe_start=0x%llx ios->offset=0x%llx min_p=%d max_p=%d\n", + offset, ios->offset, min_p, max_p); + for (c = 0; ; c++) { ore_calc_stripe_info(ios->layout, offset, 0, &read_si); read_si.obj_offset += min_p * PAGE_SIZE; @@ -512,6 +511,18 @@ static int _read_4_write(struct ore_io_state *ios) } read_last_stripe: + return 0; +} + +static int _read_4_write_last_stripe(struct ore_io_state *ios) +{ + struct ore_striping_info read_si; + struct __stripe_pages_2d *sp2d = ios->sp2d; + u64 offset; + u64 last_stripe_end; + unsigned bytes_in_stripe = ios->si.bytes_in_stripe; + unsigned c, p, min_p = sp2d->pages_in_unit, max_p = -1; + offset = ios->offset + ios->length; if (offset % PAGE_SIZE) _add_to_r4w_last_page(ios, &offset); @@ -527,15 +538,15 @@ static int _read_4_write(struct ore_io_state *ios) c = _dev_order(ios->layout->group_width * ios->layout->mirrors_p1, ios->layout->mirrors_p1, read_si.par_dev, read_si.dev); - BUG_ON(ios->si.first_stripe_start + bytes_in_stripe != last_stripe_end); - /* unaligned IO must be within a single stripe */ - if (min_p == sp2d->pages_in_unit) { /* Didn't do it yet */ min_p = _sp2d_min_pg(sp2d); max_p = _sp2d_max_pg(sp2d); } + ORE_DBGMSG("offset=0x%llx stripe_end=0x%llx min_p=%d max_p=%d\n", + offset, last_stripe_end, min_p, max_p); + while (offset < last_stripe_end) { struct __1_page_stripe *_1ps = &sp2d->_1p_stripes[p]; @@ -568,6 +579,15 @@ static int _read_4_write(struct ore_io_state *ios) } read_it: + return 0; +} + +static int _read_4_write_execute(struct ore_io_state *ios) +{ + struct ore_io_state *ios_read; + unsigned i; + int ret; + ios_read = ios->ios_read_4_write; if (!ios_read) return 0; @@ -591,6 +611,8 @@ static int _read_4_write(struct ore_io_state *ios) } _mark_read4write_pages_uptodate(ios_read, ret); + ore_put_io_state(ios_read); + ios->ios_read_4_write = NULL; /* Might need a reuse at last stripe */ return 0; } @@ -626,8 +648,11 @@ int _ore_add_parity_unit(struct ore_io_state *ios, /* If first stripe, Read in all read4write pages * (if needed) before we calculate the first parity. */ - _read_4_write(ios); + _read_4_write_first_stripe(ios); } + if (!cur_len) /* If last stripe r4w pages of last stripe */ + _read_4_write_last_stripe(ios); + _read_4_write_execute(ios); for (i = 0; i < num_pages; i++) { pages[i] = _raid_page_alloc(); @@ -654,34 +679,14 @@ int _ore_add_parity_unit(struct ore_io_state *ios, int _ore_post_alloc_raid_stuff(struct ore_io_state *ios) { - struct ore_layout *layout = ios->layout; - if (ios->parity_pages) { + struct ore_layout *layout = ios->layout; unsigned pages_in_unit = layout->stripe_unit / PAGE_SIZE; - unsigned stripe_size = ios->si.bytes_in_stripe; - u64 last_stripe, first_stripe; if (_sp2d_alloc(pages_in_unit, layout->group_width, layout->parity, &ios->sp2d)) { return -ENOMEM; } - - /* Round io down to last full strip */ - first_stripe = div_u64(ios->offset, stripe_size); - last_stripe = div_u64(ios->offset + ios->length, stripe_size); - - /* If an IO spans more then a single stripe it must end at - * a stripe boundary. The reminder at the end is pushed into the - * next IO. - */ - if (last_stripe != first_stripe) { - ios->length = last_stripe * stripe_size - ios->offset; - - BUG_ON(!ios->length); - ios->nr_pages = (ios->length + PAGE_SIZE - 1) / - PAGE_SIZE; - ios->si.length = ios->length; /*make it consistent */ - } } return 0; } From f6ecbea43e774dfc0b3678d2cdda9d4b43cfecf8 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Fri, 8 Jun 2012 04:30:40 +0300 Subject: [PATCH 0521/2357] ore: Remove support of partial IO request (NFS crash) commit 62b62ad873f2accad9222a4d7ffbe1e93f6714c1 upstream. Do to OOM situations the ore might fail to allocate all resources needed for IO of the full request. If some progress was possible it would proceed with a partial/short request, for the sake of forward progress. Since this crashes NFS-core and exofs is just fine without it just remove this contraption, and fail. TODO: Support real forward progress with some reserved allocations of resources, such as mem pools and/or bio_sets [Bug since 3.2 Kernel] CC: Benny Halevy Signed-off-by: Boaz Harrosh Signed-off-by: Greg Kroah-Hartman --- fs/exofs/ore.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/fs/exofs/ore.c b/fs/exofs/ore.c index 49cf230554a..24a49d47e93 100644 --- a/fs/exofs/ore.c +++ b/fs/exofs/ore.c @@ -735,13 +735,7 @@ static int _prepare_for_striping(struct ore_io_state *ios) out: ios->numdevs = devs_in_group; ios->pages_consumed = cur_pg; - if (unlikely(ret)) { - if (length == ios->length) - return ret; - else - ios->length -= length; - } - return 0; + return ret; } int ore_create(struct ore_io_state *ios) From 08603bdd6b0b65248921c8be05febe574dd78905 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Fri, 8 Jun 2012 05:29:40 +0300 Subject: [PATCH 0522/2357] pnfs-obj: don't leak objio_state if ore_write/read fails commit 9909d45a8557455ca5f8ee7af0f253debc851f1a upstream. [Bug since 3.2 Kernel] Signed-off-by: Boaz Harrosh Signed-off-by: Greg Kroah-Hartman --- fs/nfs/objlayout/objio_osd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index 4bff4a3dab4..42ac1bf6fcc 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c @@ -453,7 +453,10 @@ int objio_read_pagelist(struct nfs_read_data *rdata) objios->ios->done = _read_done; dprintk("%s: offset=0x%llx length=0x%x\n", __func__, rdata->args.offset, rdata->args.count); - return ore_read(objios->ios); + ret = ore_read(objios->ios); + if (unlikely(ret)) + objio_free_result(&objios->oir); + return ret; } /* @@ -537,8 +540,10 @@ int objio_write_pagelist(struct nfs_write_data *wdata, int how) dprintk("%s: offset=0x%llx length=0x%x\n", __func__, wdata->args.offset, wdata->args.count); ret = ore_write(objios->ios); - if (unlikely(ret)) + if (unlikely(ret)) { + objio_free_result(&objios->oir); return ret; + } if (objios->sync) _write_done(objios->ios, objios); From 5b8bbc39d5678179f2fd4ee2e09005d8f277834c Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Fri, 20 Jul 2012 14:25:05 +0100 Subject: [PATCH 0523/2357] dm thin: do not send discards to shared blocks commit 650d2a06b4fe1cc1d218c20e256650f68bf0ca31 upstream. When process_discard receives a partial discard that doesn't cover a full block, it sends this discard down to that block. Unfortunately, the block can be shared and the discard would corrupt the other snapshots sharing this block. This patch detects block sharing and ends the discard with success when sending it to the shared block. The above change means that if the device supports discard it can't be guaranteed that a discard request zeroes data. Therefore, we set ti->discard_zeroes_data_unsupported. Thin target discard support with this bug arrived in commit 104655fd4dcebd50068ef30253a001da72e3a081 (dm thin: support discards). Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-thin.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index eb3d138ff55..e0a0ebe64c0 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1240,7 +1240,10 @@ static void process_discard(struct thin_c *tc, struct bio *bio) cell_release_singleton(cell, bio); cell_release_singleton(cell2, bio); - remap_and_issue(tc, bio, lookup_result.block); + if ((!lookup_result.shared) && pool->pf.discard_passdown) + remap_and_issue(tc, bio, lookup_result.block); + else + bio_endio(bio, 0); } break; @@ -2575,6 +2578,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) if (tc->pool->pf.discard_enabled) { ti->discards_supported = 1; ti->num_discard_requests = 1; + ti->discard_zeroes_data_unsupported = 1; } dm_put(pool_md); From 91aafba4414743c24c6d06ccca75113e4abd13a8 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Fri, 20 Jul 2012 14:25:03 +0100 Subject: [PATCH 0524/2357] dm raid1: fix crash with mirror recovery and discard commit 751f188dd5ab95b3f2b5f2f467c38aae5a2877eb upstream. This patch fixes a crash when a discard request is sent during mirror recovery. Firstly, some background. Generally, the following sequence happens during mirror synchronization: - function do_recovery is called - do_recovery calls dm_rh_recovery_prepare - dm_rh_recovery_prepare uses a semaphore to limit the number simultaneously recovered regions (by default the semaphore value is 1, so only one region at a time is recovered) - dm_rh_recovery_prepare calls __rh_recovery_prepare, __rh_recovery_prepare asks the log driver for the next region to recover. Then, it sets the region state to DM_RH_RECOVERING. If there are no pending I/Os on this region, the region is added to quiesced_regions list. If there are pending I/Os, the region is not added to any list. It is added to the quiesced_regions list later (by dm_rh_dec function) when all I/Os finish. - when the region is on quiesced_regions list, there are no I/Os in flight on this region. The region is popped from the list in dm_rh_recovery_start function. Then, a kcopyd job is started in the recover function. - when the kcopyd job finishes, recovery_complete is called. It calls dm_rh_recovery_end. dm_rh_recovery_end adds the region to recovered_regions or failed_recovered_regions list (depending on whether the copy operation was successful or not). The above mechanism assumes that if the region is in DM_RH_RECOVERING state, no new I/Os are started on this region. When I/O is started, dm_rh_inc_pending is called, which increases reg->pending count. When I/O is finished, dm_rh_dec is called. It decreases reg->pending count. If the count is zero and the region was in DM_RH_RECOVERING state, dm_rh_dec adds it to the quiesced_regions list. Consequently, if we call dm_rh_inc_pending/dm_rh_dec while the region is in DM_RH_RECOVERING state, it could be added to quiesced_regions list multiple times or it could be added to this list when kcopyd is copying data (it is assumed that the region is not on any list while kcopyd does its jobs). This results in memory corruption and crash. There already exist bypasses for REQ_FLUSH requests: REQ_FLUSH requests do not belong to any region, so they are always added to the sync list in do_writes. dm_rh_inc_pending does not increase count for REQ_FLUSH requests. In mirror_end_io, dm_rh_dec is never called for REQ_FLUSH requests. These bypasses avoid the crash possibility described above. These bypasses were improperly implemented for REQ_DISCARD when the mirror target gained discard support in commit 5fc2ffeabb9ee0fc0e71ff16b49f34f0ed3d05b4 (dm raid1: support discard). In do_writes, REQ_DISCARD requests is always added to the sync queue and immediately dispatched (even if the region is in DM_RH_RECOVERING). However, dm_rh_inc and dm_rh_dec is called for REQ_DISCARD resusts. So it violates the rule that no I/Os are started on DM_RH_RECOVERING regions, and causes the list corruption described above. This patch changes it so that REQ_DISCARD requests follow the same path as REQ_FLUSH. This avoids the crash. Reference: https://bugzilla.redhat.com/837607 Signed-off-by: Mikulas Patocka Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-raid1.c | 2 +- drivers/md/dm-region-hash.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index d039de8322f..ea16984c0f0 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1214,7 +1214,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, * We need to dec pending if this was a write. */ if (rw == WRITE) { - if (!(bio->bi_rw & REQ_FLUSH)) + if (!(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) dm_rh_dec(ms->rh, map_context->ll); return error; } diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 7771ed21218..69732e03eb3 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -404,6 +404,9 @@ void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio) return; } + if (bio->bi_rw & REQ_DISCARD) + return; + /* We must inform the log that the sync count has changed. */ log->type->set_region_sync(log, region, 0); @@ -524,7 +527,7 @@ void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios) struct bio *bio; for (bio = bios->head; bio; bio = bio->bi_next) { - if (bio->bi_rw & REQ_FLUSH) + if (bio->bi_rw & (REQ_FLUSH | REQ_DISCARD)) continue; rh_inc(rh, dm_rh_bio_to_region(rh, bio)); } From 5a4db9ee4f44658077a11c71d78a17573016fc0e Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Fri, 20 Jul 2012 14:25:07 +0100 Subject: [PATCH 0525/2357] dm raid1: set discard_zeroes_data_unsupported commit 7c8d3a42fe1c58a7e8fd3f6a013e7d7b474ff931 upstream. We can't guarantee that REQ_DISCARD on dm-mirror zeroes the data even if the underlying disks support zero on discard. So this patch sets ti->discard_zeroes_data_unsupported. For example, if the mirror is in the process of resynchronizing, it may happen that kcopyd reads a piece of data, then discard is sent on the same area and then kcopyd writes the piece of data to another leg. Consequently, the data is not zeroed. The flag was made available by commit 983c7db347db8ce2d8453fd1d89b7a4bb6920d56 (dm crypt: always disable discard_zeroes_data). Signed-off-by: Mikulas Patocka Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-raid1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index ea16984c0f0..b58b7a33914 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1084,6 +1084,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->split_io = dm_rh_get_region_size(ms->rh); ti->num_flush_requests = 1; ti->num_discard_requests = 1; + ti->discard_zeroes_data_unsupported = 1; ms->kmirrord_wq = alloc_workqueue("kmirrord", WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); From a22ad130fc91983ac717a24e29838bf2969a67d4 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 12 Jul 2012 18:06:28 +0900 Subject: [PATCH 0526/2357] ARM: SAMSUNG: Update default rate for xusbxti clock commit bdd3cc26ba651e33780ade33f1410320cf2d0cf4 upstream. The rate of xusbxti clock is set in individual machine files. The default value should be defined at the clock definition and individual machine files should modify it if required. Division by zero in kernel. [] (unwind_backtrace+0x1/0x9c) from [] (Ldiv0+0x9/0x12) [] (Ldiv0+0x9/0x12) from [] (s3c_setrate_clksrc+0x33/0x78) [] (s3c_setrate_clksrc+0x33/0x78) from [] (clk_set_rate+0x2f/0x78) Signed-off-by: Tushar Behera Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-s5p/clock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c index f68a9bb1194..b04279512e2 100644 --- a/arch/arm/plat-s5p/clock.c +++ b/arch/arm/plat-s5p/clock.c @@ -38,6 +38,7 @@ struct clk clk_ext_xtal_mux = { struct clk clk_xusbxti = { .name = "xusbxti", .id = -1, + .rate = 24000000, }; struct clk s5p_clk_27m = { From 5d0c7b47b27d51c45700b1153ac86752ff743aa6 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 11 Jul 2012 09:09:36 -0400 Subject: [PATCH 0527/2357] cifs: when CONFIG_HIGHMEM is set, serialize the read/write kmaps commit 3cf003c08be785af4bee9ac05891a15bcbff856a upstream. [The async read code was broadened to include uncached reads in 3.5, so the mainline patch did not apply directly. This patch is just a backport to account for that change.] Jian found that when he ran fsx on a 32 bit arch with a large wsize the process and one of the bdi writeback kthreads would sometimes deadlock with a stack trace like this: crash> bt PID: 2789 TASK: f02edaa0 CPU: 3 COMMAND: "fsx" #0 [eed63cbc] schedule at c083c5b3 #1 [eed63d80] kmap_high at c0500ec8 #2 [eed63db0] cifs_async_writev at f7fabcd7 [cifs] #3 [eed63df0] cifs_writepages at f7fb7f5c [cifs] #4 [eed63e50] do_writepages at c04f3e32 #5 [eed63e54] __filemap_fdatawrite_range at c04e152a #6 [eed63ea4] filemap_fdatawrite at c04e1b3e #7 [eed63eb4] cifs_file_aio_write at f7fa111a [cifs] #8 [eed63ecc] do_sync_write at c052d202 #9 [eed63f74] vfs_write at c052d4ee #10 [eed63f94] sys_write at c052df4c #11 [eed63fb0] ia32_sysenter_target at c0409a98 EAX: 00000004 EBX: 00000003 ECX: abd73b73 EDX: 012a65c6 DS: 007b ESI: 012a65c6 ES: 007b EDI: 00000000 SS: 007b ESP: bf8db178 EBP: bf8db1f8 GS: 0033 CS: 0073 EIP: 40000424 ERR: 00000004 EFLAGS: 00000246 Each task would kmap part of its address array before getting stuck, but not enough to actually issue the write. This patch fixes this by serializing the marshal_iov operations for async reads and writes. The idea here is to ensure that cifs aggressively tries to populate a request before attempting to fulfill another one. As soon as all of the pages are kmapped for a request, then we can unlock and allow another one to proceed. There's no need to do this serialization on non-CONFIG_HIGHMEM arches however, so optimize all of this out when CONFIG_HIGHMEM isn't set. Reported-by: Jian Li Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifssmb.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6b79efd7d75..3a75ee5a6b3 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -89,6 +89,32 @@ static struct { /* Forward declarations */ static void cifs_readv_complete(struct work_struct *work); +#ifdef CONFIG_HIGHMEM +/* + * On arches that have high memory, kmap address space is limited. By + * serializing the kmap operations on those arches, we ensure that we don't + * end up with a bunch of threads in writeback with partially mapped page + * arrays, stuck waiting for kmap to come back. That situation prevents + * progress and can deadlock. + */ +static DEFINE_MUTEX(cifs_kmap_mutex); + +static inline void +cifs_kmap_lock(void) +{ + mutex_lock(&cifs_kmap_mutex); +} + +static inline void +cifs_kmap_unlock(void) +{ + mutex_unlock(&cifs_kmap_mutex); +} +#else /* !CONFIG_HIGHMEM */ +#define cifs_kmap_lock() do { ; } while(0) +#define cifs_kmap_unlock() do { ; } while(0) +#endif /* CONFIG_HIGHMEM */ + /* Mark as invalid, all open files on tree connections since they were closed when session to server was lost */ static void mark_open_files_invalid(struct cifs_tcon *pTcon) @@ -1557,6 +1583,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0; cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index); + cifs_kmap_lock(); list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { if (remaining >= PAGE_CACHE_SIZE) { /* enough data to fill the page */ @@ -1606,6 +1633,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) page_cache_release(page); } } + cifs_kmap_unlock(); /* issue the read if we have any iovecs left to fill */ if (rdata->nr_iov > 1) { @@ -2194,7 +2222,9 @@ cifs_async_writev(struct cifs_writedata *wdata) * and set the iov_len properly for each one. It may also set * wdata->bytes too. */ + cifs_kmap_lock(); wdata->marshal_iov(iov, wdata); + cifs_kmap_unlock(); cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes); From 0d0eef55e03a76885b5d665b1f5572e1f4975886 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 29 Jul 2012 08:04:57 -0700 Subject: [PATCH 0528/2357] Linux 3.4.7 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5d0edcbd878..e17a98c3ea5 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 6 +SUBLEVEL = 7 EXTRAVERSION = NAME = Saber-toothed Squirrel From 480692b1562b07a4bb8e4d6e49bf7fd2acefbea2 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:21 -0700 Subject: [PATCH 0529/2357] target: Add generation of LOGICAL BLOCK ADDRESS OUT OF RANGE commit e2397c704429025bc6b331a970f699e52f34283e upstream. Many SCSI commands are defined to return a CHECK CONDITION / ILLEGAL REQUEST with ASC set to LOGICAL BLOCK ADDRESS OUT OF RANGE if the initiator sends a command that accesses a too-big LBA. Add an enum value and case entries so that target code can return this status. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_transport.c | 10 ++++++++++ include/target/target_core_base.h | 1 + 2 files changed, 11 insertions(+) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 443704f84fd..0686d61adea 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1976,6 +1976,7 @@ void transport_generic_request_failure(struct se_cmd *cmd) case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: case TCM_UNKNOWN_MODE_PAGE: case TCM_WRITE_PROTECTED: + case TCM_ADDRESS_OUT_OF_RANGE: case TCM_CHECK_CONDITION_ABORT_CMD: case TCM_CHECK_CONDITION_UNIT_ATTENTION: case TCM_CHECK_CONDITION_NOT_READY: @@ -4656,6 +4657,15 @@ int transport_send_check_condition_and_sense( /* WRITE PROTECTED */ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27; break; + case TCM_ADDRESS_OUT_OF_RANGE: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + /* LOGICAL BLOCK ADDRESS OUT OF RANGE */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x21; + break; case TCM_CHECK_CONDITION_UNIT_ATTENTION: /* CURRENT ERROR */ buffer[offset] = 0x70; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index aaccc5f5fc9..3ad5b33ee32 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -229,6 +229,7 @@ enum tcm_sense_reason_table { TCM_CHECK_CONDITION_UNIT_ATTENTION = 0x0e, TCM_CHECK_CONDITION_NOT_READY = 0x0f, TCM_RESERVATION_CONFLICT = 0x10, + TCM_ADDRESS_OUT_OF_RANGE = 0x11, }; enum target_sc_flags_table { From f1377fddb346729aa2fe9cdbfc54aaf2ca463bd5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Jul 2012 08:55:18 +0100 Subject: [PATCH 0530/2357] iscsi-target: Drop bogus struct file usage for iSCSI/SCTP commit bf6932f44a7b3fa7e2246a8b18a44670e5eab6c2 upstream. From Al Viro: BTW, speaking of struct file treatment related to sockets - there's this piece of code in iscsi: /* * The SCTP stack needs struct socket->file. */ if ((np->np_network_transport == ISCSI_SCTP_TCP) || (np->np_network_transport == ISCSI_SCTP_UDP)) { if (!new_sock->file) { new_sock->file = kzalloc( sizeof(struct file), GFP_KERNEL); For one thing, as far as I can see it'not true - sctp does *not* depend on socket->file being non-NULL; it does, in one place, check socket->file->f_flags for O_NONBLOCK, but there it treats NULL socket->file as "flag not set". Which is the case here anyway - the fake struct file created in __iscsi_target_login_thread() (and in iscsi_target_setup_login_socket(), with the same excuse) do *not* get that flag set. Moreover, it's a bloody serious violation of a bunch of asserts in VFS; all struct file instances should come from filp_cachep, via get_empty_filp() (or alloc_file(), which is a wrapper for it). FWIW, I'm very tempted to do this and be done with the entire mess: Signed-off-by: Al Viro Cc: Andy Grover Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/iscsi/iscsi_target.c | 22 ++------- drivers/target/iscsi/iscsi_target_core.h | 2 - drivers/target/iscsi/iscsi_target_login.c | 60 ++--------------------- 3 files changed, 6 insertions(+), 78 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 8b1d5e62ed4..e326d17e05a 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -427,19 +427,8 @@ int iscsit_reset_np_thread( int iscsit_del_np_comm(struct iscsi_np *np) { - if (!np->np_socket) - return 0; - - /* - * Some network transports allocate their own struct sock->file, - * see if we need to free any additional allocated resources. - */ - if (np->np_flags & NPF_SCTP_STRUCT_FILE) { - kfree(np->np_socket->file); - np->np_socket->file = NULL; - } - - sock_release(np->np_socket); + if (np->np_socket) + sock_release(np->np_socket); return 0; } @@ -4094,13 +4083,8 @@ int iscsit_close_connection( kfree(conn->conn_ops); conn->conn_ops = NULL; - if (conn->sock) { - if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) { - kfree(conn->sock->file); - conn->sock->file = NULL; - } + if (conn->sock) sock_release(conn->sock); - } conn->thread_set = NULL; pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 2aaee7efa68..d1c4bc22cca 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -224,7 +224,6 @@ enum iscsi_timer_flags_table { /* Used for struct iscsi_np->np_flags */ enum np_flags_table { NPF_IP_NETWORK = 0x00, - NPF_SCTP_STRUCT_FILE = 0x01 /* Bugfix */ }; /* Used for struct iscsi_np->np_thread_state */ @@ -511,7 +510,6 @@ struct iscsi_conn { u16 local_port; int net_size; u32 auth_id; -#define CONNFLAG_SCTP_STRUCT_FILE 0x01 u32 conn_flags; /* Used for iscsi_tx_login_rsp() */ u32 login_itt; diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index a3656c9903a..ae304248c8c 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -794,22 +794,6 @@ int iscsi_target_setup_login_socket( return ret; } np->np_socket = sock; - /* - * The SCTP stack needs struct socket->file. - */ - if ((np->np_network_transport == ISCSI_SCTP_TCP) || - (np->np_network_transport == ISCSI_SCTP_UDP)) { - if (!sock->file) { - sock->file = kzalloc(sizeof(struct file), GFP_KERNEL); - if (!sock->file) { - pr_err("Unable to allocate struct" - " file for SCTP\n"); - ret = -ENOMEM; - goto fail; - } - np->np_flags |= NPF_SCTP_STRUCT_FILE; - } - } /* * Setup the np->np_sockaddr from the passed sockaddr setup * in iscsi_target_configfs.c code.. @@ -869,21 +853,15 @@ int iscsi_target_setup_login_socket( fail: np->np_socket = NULL; - if (sock) { - if (np->np_flags & NPF_SCTP_STRUCT_FILE) { - kfree(sock->file); - sock->file = NULL; - } - + if (sock) sock_release(sock); - } return ret; } static int __iscsi_target_login_thread(struct iscsi_np *np) { u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0; - int err, ret = 0, set_sctp_conn_flag, stop; + int err, ret = 0, stop; struct iscsi_conn *conn = NULL; struct iscsi_login *login; struct iscsi_portal_group *tpg = NULL; @@ -894,7 +872,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) struct sockaddr_in6 sock_in6; flush_signals(current); - set_sctp_conn_flag = 0; sock = np->np_socket; spin_lock_bh(&np->np_thread_lock); @@ -917,35 +894,12 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) spin_unlock_bh(&np->np_thread_lock); goto out; } - /* - * The SCTP stack needs struct socket->file. - */ - if ((np->np_network_transport == ISCSI_SCTP_TCP) || - (np->np_network_transport == ISCSI_SCTP_UDP)) { - if (!new_sock->file) { - new_sock->file = kzalloc( - sizeof(struct file), GFP_KERNEL); - if (!new_sock->file) { - pr_err("Unable to allocate struct" - " file for SCTP\n"); - sock_release(new_sock); - /* Get another socket */ - return 1; - } - set_sctp_conn_flag = 1; - } - } - iscsi_start_login_thread_timer(np); conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL); if (!conn) { pr_err("Could not allocate memory for" " new connection\n"); - if (set_sctp_conn_flag) { - kfree(new_sock->file); - new_sock->file = NULL; - } sock_release(new_sock); /* Get another socket */ return 1; @@ -955,9 +909,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) conn->conn_state = TARG_CONN_STATE_FREE; conn->sock = new_sock; - if (set_sctp_conn_flag) - conn->conn_flags |= CONNFLAG_SCTP_STRUCT_FILE; - pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n"); conn->conn_state = TARG_CONN_STATE_XPT_UP; @@ -1205,13 +1156,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) iscsi_release_param_list(conn->param_list); conn->param_list = NULL; } - if (conn->sock) { - if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) { - kfree(conn->sock->file); - conn->sock->file = NULL; - } + if (conn->sock) sock_release(conn->sock); - } kfree(conn); if (tpg) { From c5b5af98489f4db8025baee2fc0cae7dd0d19ac3 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 3 Jul 2012 23:13:39 +0100 Subject: [PATCH 0531/2357] mmc: sdhci-pci: CaFe has broken card detection commit 55fc05b7414274f17795cd0e8a3b1546f3649d5e upstream. At http://dev.laptop.org/ticket/11980 we have determined that the Marvell CaFe SDHCI controller reports bad card presence during resume. It reports that no card is present even when it is. This is a regression -- resume worked back around 2.6.37. Around 400ms after resuming, a "card inserted" interrupt is generated, at which point it starts reporting presence. Work around this hardware oddity by setting the SDHCI_QUIRK_BROKEN_CARD_DETECTION flag. Thanks to Chris Ball for helping with diagnosis. Signed-off-by: Daniel Drake Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 69ef0beae10..504da715a41 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -157,6 +157,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = { static const struct sdhci_pci_fixes sdhci_cafe = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | + SDHCI_QUIRK_BROKEN_CARD_DETECTION | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, }; From 94c73bbcec6a77eb8a526a1230631a2cc18bf18b Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Tue, 3 Jul 2012 17:27:49 +0800 Subject: [PATCH 0532/2357] mmc: sdhci: fix incorrect command used in tuning commit 473b095a72a95ba719905b1f2e82cd18d099a427 upstream. For SD hosts using retuning mode 1, when retuning timer expired, it will need to do retuning in sdhci_request before processing the actual request. But the retuning command is fixed: cmd19 for SD card and cmd21 for eMMC card, so we can't use the original request's command to do the tuning. And since the tuning command depends on the card type attached to the host, we will need to know the card type to use the correct tuning command. Signed-off-by: Aaron Lu Reviewed-by: Philip Rakity Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ccefdebeff1..3c403aa8495 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -27,6 +27,7 @@ #include #include +#include #include "sdhci.h" @@ -1245,6 +1246,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) struct sdhci_host *host; bool present; unsigned long flags; + u32 tuning_opcode; host = mmc_priv(mmc); @@ -1292,8 +1294,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) */ if ((host->flags & SDHCI_NEEDS_RETUNING) && !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { + /* eMMC uses cmd21 while sd and sdio use cmd19 */ + tuning_opcode = mmc->card->type == MMC_TYPE_MMC ? + MMC_SEND_TUNING_BLOCK_HS200 : + MMC_SEND_TUNING_BLOCK; spin_unlock_irqrestore(&host->lock, flags); - sdhci_execute_tuning(mmc, mrq->cmd->opcode); + sdhci_execute_tuning(mmc, tuning_opcode); spin_lock_irqsave(&host->lock, flags); /* Restore original mmc_request structure */ From 2cdb31f3c09f2bdd10d520a24def87d90c0030ba Mon Sep 17 00:00:00 2001 From: roger blofeld Date: Thu, 21 Jun 2012 05:27:14 +0000 Subject: [PATCH 0533/2357] powerpc/ftrace: Fix assembly trampoline register usage commit fd5a42980e1cf327b7240adf5e7b51ea41c23437 upstream. Just like the module loader, ftrace needs to be updated to use r12 instead of r11 with newer gcc's. Signed-off-by: Roger Blofeld Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/ftrace.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index bf99cfa6bbf..63240081133 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c @@ -245,9 +245,9 @@ __ftrace_make_nop(struct module *mod, /* * On PPC32 the trampoline looks like: - * 0x3d, 0x60, 0x00, 0x00 lis r11,sym@ha - * 0x39, 0x6b, 0x00, 0x00 addi r11,r11,sym@l - * 0x7d, 0x69, 0x03, 0xa6 mtctr r11 + * 0x3d, 0x80, 0x00, 0x00 lis r12,sym@ha + * 0x39, 0x8c, 0x00, 0x00 addi r12,r12,sym@l + * 0x7d, 0x89, 0x03, 0xa6 mtctr r12 * 0x4e, 0x80, 0x04, 0x20 bctr */ @@ -262,9 +262,9 @@ __ftrace_make_nop(struct module *mod, pr_devel(" %08x %08x ", jmp[0], jmp[1]); /* verify that this is what we expect it to be */ - if (((jmp[0] & 0xffff0000) != 0x3d600000) || - ((jmp[1] & 0xffff0000) != 0x396b0000) || - (jmp[2] != 0x7d6903a6) || + if (((jmp[0] & 0xffff0000) != 0x3d800000) || + ((jmp[1] & 0xffff0000) != 0x398c0000) || + (jmp[2] != 0x7d8903a6) || (jmp[3] != 0x4e800420)) { printk(KERN_ERR "Not a trampoline\n"); return -EINVAL; From a461394c31c5aa3c8cfe98dd0dc35f6b56047770 Mon Sep 17 00:00:00 2001 From: Tiejun Chen Date: Wed, 11 Jul 2012 14:22:46 +1000 Subject: [PATCH 0534/2357] powerpc: Add "memory" attribute for mfmsr() commit b416c9a10baae6a177b4f9ee858b8d309542fbef upstream. Add "memory" attribute in inline assembly language as a compiler barrier to make sure 4.6.x GCC don't reorder mfmsr(). Signed-off-by: Tiejun Chen Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/reg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 9d7f0fb6902..cae0ed7878e 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1022,7 +1022,8 @@ /* Macros for setting and retrieving special purpose registers */ #ifndef __ASSEMBLY__ #define mfmsr() ({unsigned long rval; \ - asm volatile("mfmsr %0" : "=r" (rval)); rval;}) + asm volatile("mfmsr %0" : "=r" (rval) : \ + : "memory"); rval;}) #ifdef CONFIG_PPC_BOOK3S_64 #define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \ : : "r" (v) : "memory") From f18e28667a2a26d0ead02cc730524fa6203ec818 Mon Sep 17 00:00:00 2001 From: Kleber Sacilotto de Souza Date: Thu, 12 Jul 2012 17:14:36 +0000 Subject: [PATCH 0535/2357] powerpc/eeh: Check handle_eeh_events() return value commit 10db8d212864cb6741df7d7fafda5ab6661f6f88 upstream. Function eeh_event_handler() dereferences the pointer returned by handle_eeh_events() without checking, causing a crash if NULL was returned, which is expected in some situations. This patch fixes this bug by checking for the value returned by handle_eeh_events() before dereferencing it. Signed-off-by: Kleber Sacilotto de Souza Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/eeh_event.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 4cb375c0f8d..fb506317ebb 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -85,8 +85,10 @@ static int eeh_event_handler(void * dummy) set_current_state(TASK_INTERRUPTIBLE); /* Don't add to load average */ edev = handle_eeh_events(event); - eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); - pci_dev_put(edev->pdev); + if (edev) { + eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); + pci_dev_put(edev->pdev); + } kfree(event); mutex_unlock(&eeh_event_mutex); From 753e14ef13311122aa5a819657d17940969a6f80 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 5 Jul 2012 10:08:28 -0500 Subject: [PATCH 0536/2357] powerpc/85xx: use the BRx registers to enable indirect mode on the P1022DS commit 6bd825f02966be8ba544047cab313d6032c23819 upstream. In order to enable the DIU video controller on the P1022DS, the FPGA needs to be switched to "indirect mode", where the localbus is disabled and the FPGA is accessed via writes to localbus chip select signals CS0 and CS1. To obtain the address of CS0 and CS1, the platform driver uses an "indirect pixis mode" device tree node. This node assumes that the localbus 'ranges' property is sorted in chip-select order. That is, reg value 0 maps to CS0, reg value 1 maps to CS1, etc. This is how the 'ranges' property is supposed to be arranged. Unfortunately, the 'ranges' property is often mis-arranged, and not just on the P1022DS. Linux normally does not care, since it does not program the localbus. But the indirect-mode code on the P1022DS does care. The "proper" fix is to have U-Boot fix the 'ranges' property, but this would be too cumbersome. The names and 'reg' properties of all the localbus devices would also need to be updated, and determining which localbus device maps to which chip select is board-specific. Instead, we determine the CS0/CS1 base addresses the same way that U-boot does -- by reading the BRx registers directly and mapping them to physical addresses. This code is simpler and more reliable, and it does not require a U-boot or device tree change. Since the indirect pixis device tree node is no longer needed, the node is deleted from the DTS. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/boot/dts/p1022ds.dtsi | 16 ---- arch/powerpc/platforms/85xx/p1022_ds.c | 106 ++++++++++++++++++++++--- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi index 7cdb505036b..1b0673e3631 100644 --- a/arch/powerpc/boot/dts/p1022ds.dtsi +++ b/arch/powerpc/boot/dts/p1022ds.dtsi @@ -33,22 +33,6 @@ */ &board_lbc { - /* - * This node is used to access the pixis via "indirect" mode, - * which is done by writing the pixis register index to chip - * select 0 and the value to/from chip select 1. Indirect - * mode is the only way to access the pixis when DIU video - * is enabled. Note that this assumes that the first column - * of the 'ranges' property above is the chip select number. - */ - board-control@0,0 { - compatible = "fsl,p1022ds-indirect-pixis"; - reg = <0x0 0x0 1 /* CS0 */ - 0x1 0x0 1>; /* CS1 */ - interrupt-parent = <&mpic>; - interrupts = <8 0 0 0>; - }; - nor@0,0 { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index f700c81a132..978330ccdde 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "smp.h" #include "mpc85xx.h" @@ -142,17 +143,73 @@ static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port, { } +struct fsl_law { + u32 lawbar; + u32 reserved1; + u32 lawar; + u32 reserved[5]; +}; + +#define LAWBAR_MASK 0x00F00000 +#define LAWBAR_SHIFT 12 + +#define LAWAR_EN 0x80000000 +#define LAWAR_TGT_MASK 0x01F00000 +#define LAW_TRGT_IF_LBC (0x04 << 20) + +#define LAWAR_MASK (LAWAR_EN | LAWAR_TGT_MASK) +#define LAWAR_MATCH (LAWAR_EN | LAW_TRGT_IF_LBC) + +#define BR_BA 0xFFFF8000 + +/* + * Map a BRx value to a physical address + * + * The localbus BRx registers only store the lower 32 bits of the address. To + * obtain the upper four bits, we need to scan the LAW table. The entry which + * maps to the localbus will contain the upper four bits. + */ +static phys_addr_t lbc_br_to_phys(const void *ecm, unsigned int count, u32 br) +{ +#ifndef CONFIG_PHYS_64BIT + /* + * If we only have 32-bit addressing, then the BRx address *is* the + * physical address. + */ + return br & BR_BA; +#else + const struct fsl_law *law = ecm + 0xc08; + unsigned int i; + + for (i = 0; i < count; i++) { + u64 lawbar = in_be32(&law[i].lawbar); + u32 lawar = in_be32(&law[i].lawar); + + if ((lawar & LAWAR_MASK) == LAWAR_MATCH) + /* Extract the upper four bits */ + return (br & BR_BA) | ((lawbar & LAWBAR_MASK) << 12); + } + + return 0; +#endif +} + /** * p1022ds_set_monitor_port: switch the output to a different monitor port - * */ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) { struct device_node *guts_node; - struct device_node *indirect_node = NULL; + struct device_node *lbc_node = NULL; + struct device_node *law_node = NULL; struct ccsr_guts __iomem *guts; + struct fsl_lbc_regs *lbc = NULL; + void *ecm = NULL; u8 __iomem *lbc_lcs0_ba = NULL; u8 __iomem *lbc_lcs1_ba = NULL; + phys_addr_t cs0_addr, cs1_addr; + const __be32 *iprop; + unsigned int num_laws; u8 b; /* Map the global utilities registers. */ @@ -168,25 +225,43 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) goto exit; } - indirect_node = of_find_compatible_node(NULL, NULL, - "fsl,p1022ds-indirect-pixis"); - if (!indirect_node) { - pr_err("p1022ds: missing pixis indirect mode node\n"); + lbc_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); + if (!lbc_node) { + pr_err("p1022ds: missing localbus node\n"); goto exit; } - lbc_lcs0_ba = of_iomap(indirect_node, 0); - if (!lbc_lcs0_ba) { - pr_err("p1022ds: could not map localbus chip select 0\n"); + lbc = of_iomap(lbc_node, 0); + if (!lbc) { + pr_err("p1022ds: could not map localbus node\n"); goto exit; } - lbc_lcs1_ba = of_iomap(indirect_node, 1); - if (!lbc_lcs1_ba) { - pr_err("p1022ds: could not map localbus chip select 1\n"); + law_node = of_find_compatible_node(NULL, NULL, "fsl,ecm-law"); + if (!law_node) { + pr_err("p1022ds: missing local access window node\n"); goto exit; } + ecm = of_iomap(law_node, 0); + if (!ecm) { + pr_err("p1022ds: could not map local access window node\n"); + goto exit; + } + + iprop = of_get_property(law_node, "fsl,num-laws", 0); + if (!iprop) { + pr_err("p1022ds: LAW node is missing fsl,num-laws property\n"); + goto exit; + } + num_laws = be32_to_cpup(iprop); + + cs0_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[0].br)); + cs1_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[1].br)); + + lbc_lcs0_ba = ioremap(cs0_addr, 1); + lbc_lcs1_ba = ioremap(cs1_addr, 1); + /* Make sure we're in indirect mode first. */ if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != PMUXCR_ELBCDIU_DIU) { @@ -254,10 +329,15 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) iounmap(lbc_lcs1_ba); if (lbc_lcs0_ba) iounmap(lbc_lcs0_ba); + if (lbc) + iounmap(lbc); + if (ecm) + iounmap(ecm); if (guts) iounmap(guts); - of_node_put(indirect_node); + of_node_put(law_node); + of_node_put(lbc_node); of_node_put(guts_node); } From de0449fd59c6c6a9a523c625a014c8d8cd73810f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:36:15 -0700 Subject: [PATCH 0537/2357] SCSI: libsas: continue revalidation commit 26f2f199ff150d8876b2641c41e60d1c92d2fb81 upstream. Continue running revalidation until no more broadcast devices are discovered. Fixes cases where re-discovery completes too early in a domain with multiple expanders with pending re-discovery events. Servicing BCNs can get backed up behind error recovery. Signed-off-by: Dan Williams Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_expander.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index caa0525d252..79f9d559992 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -2109,9 +2109,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev) struct domain_device *dev = NULL; res = sas_find_bcast_dev(port_dev, &dev); - if (res) - goto out; - if (dev) { + while (res == 0 && dev) { struct expander_device *ex = &dev->ex_dev; int i = 0, phy_id; @@ -2123,8 +2121,10 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev) res = sas_rediscover(dev, phy_id); i = phy_id + 1; } while (i < ex->num_phys); + + dev = NULL; + res = sas_find_bcast_dev(port_dev, &dev); } -out: return res; } From 1c06102701a00d42f2c690d97cc2203d561ea6a4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:36:20 -0700 Subject: [PATCH 0538/2357] SCSI: libsas: fix sas_discover_devices return code handling commit b17caa174a7e1fd2e17b26e210d4ee91c4c28b37 upstream. commit 198439e4 [SCSI] libsas: do not set res = 0 in sas_ex_discover_dev() commit 19252de6 [SCSI] libsas: fix wide port hotplug issues The above commits seem to have confused the return value of sas_ex_discover_dev which is non-zero on failure and sas_ex_join_wide_port which just indicates short circuiting discovery on already established ports. The result is random discovery failures depending on configuration. Calls to sas_ex_join_wide_port are the source of the trouble as its return value is errantly assigned to 'res'. Convert it to bool and stop returning its result up the stack. Tested-by: Dan Melnic Reported-by: Dan Melnic Signed-off-by: Dan Williams Reviewed-by: Jack Wang Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_expander.c | 39 +++++++++--------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 79f9d559992..101b28e61c6 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -868,7 +868,7 @@ static struct domain_device *sas_ex_discover_end_dev( } /* See if this phy is part of a wide port */ -static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id) +static bool sas_ex_join_wide_port(struct domain_device *parent, int phy_id) { struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id]; int i; @@ -884,11 +884,11 @@ static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id) sas_port_add_phy(ephy->port, phy->phy); phy->port = ephy->port; phy->phy_state = PHY_DEVICE_DISCOVERED; - return 0; + return true; } } - return -ENODEV; + return false; } static struct domain_device *sas_ex_discover_expander( @@ -1030,8 +1030,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) return res; } - res = sas_ex_join_wide_port(dev, phy_id); - if (!res) { + if (sas_ex_join_wide_port(dev, phy_id)) { SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", phy_id, SAS_ADDR(ex_phy->attached_sas_addr)); return res; @@ -1077,8 +1076,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) == SAS_ADDR(child->sas_addr)) { ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED; - res = sas_ex_join_wide_port(dev, i); - if (!res) + if (sas_ex_join_wide_port(dev, i)) SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr)); @@ -1943,32 +1941,20 @@ static int sas_discover_new(struct domain_device *dev, int phy_id) { struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id]; struct domain_device *child; - bool found = false; - int res, i; + int res; SAS_DPRINTK("ex %016llx phy%d new device attached\n", SAS_ADDR(dev->sas_addr), phy_id); res = sas_ex_phy_discover(dev, phy_id); if (res) - goto out; - /* to support the wide port inserted */ - for (i = 0; i < dev->ex_dev.num_phys; i++) { - struct ex_phy *ex_phy_temp = &dev->ex_dev.ex_phy[i]; - if (i == phy_id) - continue; - if (SAS_ADDR(ex_phy_temp->attached_sas_addr) == - SAS_ADDR(ex_phy->attached_sas_addr)) { - found = true; - break; - } - } - if (found) { - sas_ex_join_wide_port(dev, phy_id); + return res; + + if (sas_ex_join_wide_port(dev, phy_id)) return 0; - } + res = sas_ex_discover_devices(dev, phy_id); - if (!res) - goto out; + if (res) + return res; list_for_each_entry(child, &dev->ex_dev.children, siblings) { if (SAS_ADDR(child->sas_addr) == SAS_ADDR(ex_phy->attached_sas_addr)) { @@ -1978,7 +1964,6 @@ static int sas_discover_new(struct domain_device *dev, int phy_id) break; } } -out: return res; } From bb12049078a3a69f750779a19287cd4ac5f2bc3e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:25:32 -0700 Subject: [PATCH 0539/2357] SCSI: fix eh wakeup (scsi_schedule_eh vs scsi_restart_operations) commit 57fc2e335fd3c2f898ee73570dc81426c28dc7b4 upstream. Rapid ata hotplug on a libsas controller results in cases where libsas is waiting indefinitely on eh to perform an ata probe. A race exists between scsi_schedule_eh() and scsi_restart_operations() in the case when scsi_restart_operations() issues i/o to other devices in the sas domain. When this happens the host state transitions from SHOST_RECOVERY (set by scsi_schedule_eh) back to SHOST_RUNNING and ->host_busy is non-zero so we put the eh thread to sleep even though ->host_eh_scheduled is active. Before putting the error handler to sleep we need to check if the host_state needs to return to SHOST_RECOVERY for another trip through eh. Since i/o that is released by scsi_restart_operations has been blocked for at least one eh cycle, this implementation allows those i/o's to run before another eh cycle starts to discourage hung task timeouts. Reported-by: Tom Jackson Tested-by: Tom Jackson Signed-off-by: Dan Williams Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_error.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 386f0c53bea..cc8dc8cc6d6 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1687,6 +1687,20 @@ static void scsi_restart_operations(struct Scsi_Host *shost) * requests are started. */ scsi_run_host_queues(shost); + + /* + * if eh is active and host_eh_scheduled is pending we need to re-run + * recovery. we do this check after scsi_run_host_queues() to allow + * everything pent up since the last eh run a chance to make forward + * progress before we sync again. Either we'll immediately re-run + * recovery or scsi_device_unbusy() will wake us again when these + * pending commands complete. + */ + spin_lock_irqsave(shost->host_lock, flags); + if (shost->host_eh_scheduled) + if (scsi_host_set_state(shost, SHOST_RECOVERY)) + WARN_ON(scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)); + spin_unlock_irqrestore(shost->host_lock, flags); } /** From f07d3f59e35eb0fc8847587f601f84b8cfa8dd38 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:47:28 -0700 Subject: [PATCH 0540/2357] SCSI: fix hot unplug vs async scan race commit 3b661a92e869ebe2358de8f4b3230ad84f7fce51 upstream. The following crash results from cases where the end_device has been removed before scsi_sysfs_add_sdev has had a chance to run. BUG: unable to handle kernel NULL pointer dereference at 0000000000000098 IP: [] sysfs_create_dir+0x32/0xb6 ... Call Trace: [] kobject_add_internal+0x120/0x1e3 [] ? trace_hardirqs_on+0xd/0xf [] kobject_add_varg+0x41/0x50 [] kobject_add+0x64/0x66 [] device_add+0x12d/0x63a [] ? _raw_spin_unlock_irqrestore+0x47/0x56 [] ? module_refcount+0x89/0xa0 [] scsi_sysfs_add_sdev+0x4e/0x28a [] do_scan_async+0x9c/0x145 ...teach scsi_sysfs_add_devices() to check for deleted devices() before trying to add them, and teach scsi_remove_target() how to remove targets that have not been added via device_add(). Reported-by: Dariusz Majchrzak Signed-off-by: Dan Williams Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_scan.c | 3 +++ drivers/scsi/scsi_sysfs.c | 41 +++++++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 01b03744f1f..8906557d2a2 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1714,6 +1714,9 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost) { struct scsi_device *sdev; shost_for_each_device(sdev, shost) { + /* target removed before the device could be added */ + if (sdev->sdev_state == SDEV_DEL) + continue; if (!scsi_host_scan_allowed(shost) || scsi_sysfs_add_sdev(sdev) != 0) __scsi_remove_device(sdev); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 04c2a278076..f888aadc8c2 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1000,7 +1000,6 @@ static void __scsi_remove_target(struct scsi_target *starget) struct scsi_device *sdev; spin_lock_irqsave(shost->host_lock, flags); - starget->reap_ref++; restart: list_for_each_entry(sdev, &shost->__devices, siblings) { if (sdev->channel != starget->channel || @@ -1014,14 +1013,6 @@ static void __scsi_remove_target(struct scsi_target *starget) goto restart; } spin_unlock_irqrestore(shost->host_lock, flags); - scsi_target_reap(starget); -} - -static int __remove_child (struct device * dev, void * data) -{ - if (scsi_is_target_device(dev)) - __scsi_remove_target(to_scsi_target(dev)); - return 0; } /** @@ -1034,14 +1025,34 @@ static int __remove_child (struct device * dev, void * data) */ void scsi_remove_target(struct device *dev) { - if (scsi_is_target_device(dev)) { - __scsi_remove_target(to_scsi_target(dev)); - return; + struct Scsi_Host *shost = dev_to_shost(dev->parent); + struct scsi_target *starget, *found; + unsigned long flags; + + restart: + found = NULL; + spin_lock_irqsave(shost->host_lock, flags); + list_for_each_entry(starget, &shost->__targets, siblings) { + if (starget->state == STARGET_DEL) + continue; + if (starget->dev.parent == dev || &starget->dev == dev) { + found = starget; + found->reap_ref++; + break; + } } + spin_unlock_irqrestore(shost->host_lock, flags); - get_device(dev); - device_for_each_child(dev, NULL, __remove_child); - put_device(dev); + if (found) { + __scsi_remove_target(found); + scsi_target_reap(found); + /* in the case where @dev has multiple starget children, + * continue removing. + * + * FIXME: does such a case exist? + */ + goto restart; + } } EXPORT_SYMBOL(scsi_remove_target); From bb0f467989fd14bd4bf41b9a30b49900f9223e47 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 29 Jun 2012 15:33:22 +0000 Subject: [PATCH 0541/2357] SCSI: Fix device removal NULL pointer dereference commit 67bd94130015c507011af37858989b199c52e1de upstream. Use blk_queue_dead() to test whether the queue is dead instead of !sdev. Since scsi_prep_fn() may be invoked concurrently with __scsi_remove_device(), keep the queuedata (sdev) pointer in __scsi_remove_device(). This patch fixes a kernel oops that can be triggered by USB device removal. See also http://www.spinics.net/lists/linux-scsi/msg56254.html. Other changes included in this patch: - Swap the blk_cleanup_queue() and kfree() calls in scsi_host_dev_release() to make that code easier to grasp. - Remove the queue dead check from scsi_run_queue() since the queue state can change anyway at any point in that function where the queue lock is not held. - Remove the queue dead check from the start of scsi_request_fn() since it is redundant with the scsi_device_online() check. Reported-by: Jun'ichi Nomura Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Reviewed-by: Tejun Heo Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/hosts.c | 7 ++++--- drivers/scsi/scsi_lib.c | 32 ++++---------------------------- drivers/scsi/scsi_priv.h | 1 - drivers/scsi/scsi_sysfs.c | 5 +---- 4 files changed, 9 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index a3a056a9db6..b48c24f7d21 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -290,6 +290,7 @@ static void scsi_host_dev_release(struct device *dev) struct Scsi_Host *shost = dev_to_shost(dev); struct device *parent = dev->parent; struct request_queue *q; + void *queuedata; scsi_proc_hostdir_rm(shost->hostt); @@ -299,9 +300,9 @@ static void scsi_host_dev_release(struct device *dev) destroy_workqueue(shost->work_q); q = shost->uspace_req_q; if (q) { - kfree(q->queuedata); - q->queuedata = NULL; - scsi_free_queue(q); + queuedata = q->queuedata; + blk_cleanup_queue(q); + kfree(queuedata); } scsi_destroy_command_freelist(shost); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 4037fd5b1e0..f97edb75e56 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -406,10 +406,6 @@ static void scsi_run_queue(struct request_queue *q) LIST_HEAD(starved_list); unsigned long flags; - /* if the device is dead, sdev will be NULL, so no queue to run */ - if (!sdev) - return; - shost = sdev->host; if (scsi_target(sdev)->single_lun) scsi_single_lun_run(sdev); @@ -1370,16 +1366,16 @@ static inline int scsi_host_queue_ready(struct request_queue *q, * may be changed after request stacking drivers call the function, * regardless of taking lock or not. * - * When scsi can't dispatch I/Os anymore and needs to kill I/Os - * (e.g. !sdev), scsi needs to return 'not busy'. - * Otherwise, request stacking drivers may hold requests forever. + * When scsi can't dispatch I/Os anymore and needs to kill I/Os scsi + * needs to return 'not busy'. Otherwise, request stacking drivers + * may hold requests forever. */ static int scsi_lld_busy(struct request_queue *q) { struct scsi_device *sdev = q->queuedata; struct Scsi_Host *shost; - if (!sdev) + if (blk_queue_dead(q)) return 0; shost = sdev->host; @@ -1490,12 +1486,6 @@ static void scsi_request_fn(struct request_queue *q) struct scsi_cmnd *cmd; struct request *req; - if (!sdev) { - while ((req = blk_peek_request(q)) != NULL) - scsi_kill_request(req, q); - return; - } - if(!get_device(&sdev->sdev_gendev)) /* We must be tearing the block queue down already */ return; @@ -1697,20 +1687,6 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) return q; } -void scsi_free_queue(struct request_queue *q) -{ - unsigned long flags; - - WARN_ON(q->queuedata); - - /* cause scsi_request_fn() to kill all non-finished requests */ - spin_lock_irqsave(q->queue_lock, flags); - q->request_fn(q); - spin_unlock_irqrestore(q->queue_lock, flags); - - blk_cleanup_queue(q); -} - /* * Function: scsi_block_requests() * diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index be4fa6d179b..fd9f57fd210 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -84,7 +84,6 @@ extern void scsi_next_command(struct scsi_cmnd *cmd); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_run_host_queues(struct Scsi_Host *shost); extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev); -extern void scsi_free_queue(struct request_queue *q); extern int scsi_init_queue(void); extern void scsi_exit_queue(void); struct request_queue; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index f888aadc8c2..bb7c4828acc 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -971,11 +971,8 @@ void __scsi_remove_device(struct scsi_device *sdev) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(dev); - /* cause the request function to reject all I/O requests */ - sdev->request_queue->queuedata = NULL; - /* Freeing the queue signals to block that we're done */ - scsi_free_queue(sdev->request_queue); + blk_cleanup_queue(sdev->request_queue); put_device(dev); } From 84ecccfc25f7dda4f1d2aeb6db0658368d3ef185 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 29 Jun 2012 15:34:26 +0000 Subject: [PATCH 0542/2357] SCSI: Avoid dangling pointer in scsi_requeue_command() commit 940f5d47e2f2e1fa00443921a0abf4822335b54d upstream. When we call scsi_unprep_request() the command associated with the request gets destroyed and therefore drops its reference on the device. If this was the only reference, the device may get released and we end up with a NULL pointer deref when we call blk_requeue_request. Reported-by: Mike Christie Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Reviewed-by: Tejun Heo [jejb: enhance commend and add commit log for stable] Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_lib.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f97edb75e56..19291463c55 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -479,15 +479,26 @@ void scsi_requeue_run_queue(struct work_struct *work) */ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd) { + struct scsi_device *sdev = cmd->device; struct request *req = cmd->request; unsigned long flags; + /* + * We need to hold a reference on the device to avoid the queue being + * killed after the unlock and before scsi_run_queue is invoked which + * may happen because scsi_unprep_request() puts the command which + * releases its reference on the device. + */ + get_device(&sdev->sdev_gendev); + spin_lock_irqsave(q->queue_lock, flags); scsi_unprep_request(req); blk_requeue_request(q, req); spin_unlock_irqrestore(q->queue_lock, flags); scsi_run_queue(q); + + put_device(&sdev->sdev_gendev); } void scsi_next_command(struct scsi_cmnd *cmd) From c4c3d44ab775fa457c49d7fce906df0a310bb347 Mon Sep 17 00:00:00 2001 From: Albert Pool Date: Mon, 14 May 2012 18:08:32 +0200 Subject: [PATCH 0543/2357] rt2800usb: 2001:3c17 is an RT3370 device commit 8fd9d059af12786341dec5a688e607bcdb372238 upstream. D-Link DWA-123 rev A1 Signed-off-by: Albert Pool Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 5601302d09a..f388b65fbe9 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1137,6 +1137,8 @@ static struct usb_device_id rt2800usb_device_table[] = { #ifdef CONFIG_RT2800USB_RT33XX /* Belkin */ { USB_DEVICE(0x050d, 0x945b) }, + /* D-Link */ + { USB_DEVICE(0x2001, 0x3c17) }, /* Panasonic */ { USB_DEVICE(0x083a, 0xb511) }, /* Philips */ @@ -1237,7 +1239,6 @@ static struct usb_device_id rt2800usb_device_table[] = { /* D-Link */ { USB_DEVICE(0x07d1, 0x3c0b) }, { USB_DEVICE(0x07d1, 0x3c17) }, - { USB_DEVICE(0x2001, 0x3c17) }, /* Encore */ { USB_DEVICE(0x203d, 0x14a1) }, /* Gemtek */ From 0706b27d2ff206bdbeb457a56944ca372e6a9d8e Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 18 May 2012 12:26:19 -0500 Subject: [PATCH 0544/2357] ARM: OMAP2+: OPP: Fix to ensure check of right oppdef after bad one commit b110547e586eb5825bc1d04aa9147bff83b57672 upstream. Commit 9fa2df6b90786301b175e264f5fa9846aba81a65 (ARM: OMAP2+: OPP: allow OPP enumeration to continue if device is not present) makes the logic: for (i = 0; i < opp_def_size; i++) { if (!oh || !oh->od) { continue; } opp_def++; } In short, the moment we hit a "Bad OPP", we end up looping the list comparing against the bad opp definition pointer for the rest of the iteration count. Instead, increment opp_def in the for loop itself and allow continue to be used in code without much thought so that we check the next set of OPP definition pointers :) Cc: Steve Sakoman Cc: Tony Lindgren Signed-off-by: Nishanth Menon Signed-off-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/opp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/opp.c b/arch/arm/mach-omap2/opp.c index de6d4645174..d8f6dbf45d1 100644 --- a/arch/arm/mach-omap2/opp.c +++ b/arch/arm/mach-omap2/opp.c @@ -53,7 +53,7 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def, omap_table_init = 1; /* Lets now register with OPP library */ - for (i = 0; i < opp_def_size; i++) { + for (i = 0; i < opp_def_size; i++, opp_def++) { struct omap_hwmod *oh; struct device *dev; @@ -86,7 +86,6 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def, __func__, opp_def->freq, opp_def->hwmod_name, i, r); } - opp_def++; } return 0; From a73185355e3d19694b655528811e54cc086a5bcf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 20 Jul 2012 17:29:34 +0100 Subject: [PATCH 0545/2357] ASoC: dapm: Fix _PRE and _POST events for DAPM performance improvements commit 0ff97ebf0804d2e519d578fcb4db03f104d2ca8c upstream. Ever since the DAPM performance improvements we've been marking all widgets as not dirty after each DAPM run. Since _PRE and _POST events aren't part of the DAPM graph this has rendered them non-functional, they will never be marked dirty again and thus will never be run again. Fix this by skipping them when marking widgets as not dirty. Signed-off-by: Mark Brown Acked-by: Liam Girdwood Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-dapm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1bb6d4a63cd..c41efe01a81 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1442,7 +1442,15 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) } list_for_each_entry(w, &card->widgets, list) { - list_del_init(&w->dirty); + switch (w->id) { + case snd_soc_dapm_pre: + case snd_soc_dapm_post: + /* These widgets always need to be powered */ + break; + default: + list_del_init(&w->dirty); + break; + } if (w->power) { d = w->dapm; From 8f1b438887c47d3b65fc64ca23821d69ba69ddd7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 11 Jul 2012 19:03:48 +0100 Subject: [PATCH 0546/2357] ASoC: wm8962: Redo early init of the part on resume commit e4dd76788c7e5b27165890d712c8c4f6f0abd645 upstream. Ensure robust startup of the part by going through the reset procedure prior to resyncing the full register cache, avoiding potential intermittent faults in some designs. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8962.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 15d467ff91b..08850f8fdb5 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3710,6 +3710,9 @@ static int wm8962_runtime_resume(struct device *dev) } regcache_cache_only(wm8962->regmap, false); + + wm8962_reset(wm8962); + regcache_sync(wm8962->regmap); regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP, From 4e613aa6c586c99341a3ca40fd7f872b7dee1749 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 18 Jul 2012 07:38:46 +0200 Subject: [PATCH 0547/2357] ALSA: hda - Add support for Realtek ALC282 commit 4e01ec636e64707d202a1ca21a47bbc6d53085b7 upstream. This codec has a separate dmic path (separate dmic only ADC), and thus it looks mostly like ALC275. BugLink: https://bugs.launchpad.net/bugs/1025377 Tested-by: Ray Chen Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c43264f5981..10c1bc79ad1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6977,6 +6977,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 }, { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 }, { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, + { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, From 761f186a0f94f7bd1c9c844f96cf0b8bbb6e2abb Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Thu, 19 Jul 2012 17:52:58 -0700 Subject: [PATCH 0548/2357] ALSA: hda - Turn on PIN_OUT from hdmi playback prepare. commit 9e76e6d031482194a5b24d8e9ab88063fbd6b4b5 upstream. Turn on the pin widget's PIN_OUT bit from playback prepare. The pin is enabled in open, but is disabled in hdmi_init_pin which is called during system resume. This causes a system suspend/resume during playback to mute HDMI/DP. Enabling the pin in prepare instead of open allows calling snd_pcm_prepare after a system resume to restore audio. Signed-off-by: Dylan Reid Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_hdmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 83f345f3c96..d1b805aefa5 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -876,7 +876,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, struct hdmi_spec_per_pin *per_pin; struct hdmi_eld *eld; struct hdmi_spec_per_cvt *per_cvt = NULL; - int pinctl; /* Validate hinfo */ pin_idx = hinfo_to_pin_index(spec, hinfo); @@ -912,11 +911,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, snd_hda_codec_write(codec, per_pin->pin_nid, 0, AC_VERB_SET_CONNECT_SEL, mux_idx); - pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinctl | PIN_OUT); snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid); /* Initially set the converter's capabilities */ @@ -1153,11 +1147,17 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hdmi_spec *spec = codec->spec; int pin_idx = hinfo_to_pin_index(spec, hinfo); hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid; + int pinctl; hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); hdmi_setup_audio_infoframe(codec, pin_idx, substream); + pinctl = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl | PIN_OUT); + return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); } From 2af3ad34568307d037dc7ab8f923b51e068b33c4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 4 Jul 2012 09:18:01 +0200 Subject: [PATCH 0549/2357] usbdevfs: Correct amount of data copied to user in processcompl_compat commit 2102e06a5f2e414694921f23591f072a5ba7db9f upstream. iso data buffers may have holes in them if some packets were short, so for iso urbs we should always copy the entire buffer, just like the regular processcompl does. Signed-off-by: Hans de Goede Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 4e577728ead..404413b0b93 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1615,10 +1615,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i; - if (as->userbuffer && urb->actual_length) - if (copy_to_user(as->userbuffer, urb->transfer_buffer, - urb->actual_length)) + if (as->userbuffer && urb->actual_length) { + if (urb->number_of_packets > 0) /* Isochronous */ + i = urb->transfer_buffer_length; + else /* Non-Isoc */ + i = urb->actual_length; + if (copy_to_user(as->userbuffer, urb->transfer_buffer, i)) return -EFAULT; + } if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) From 2cfe89c15298554d5cf9160bf6d8eef290d34041 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sun, 24 Jun 2012 21:11:22 -0700 Subject: [PATCH 0550/2357] usb: gadget: Fix g_ether interface link status commit 31bde1ceaa873bcaecd49e829bfabceacc4c512d upstream. A "usb0" interface that has never been connected to a host has an unknown operstate, and therefore the IFF_RUNNING flag is (incorrectly) asserted when queried by ifconfig, ifplugd, etc. This is a result of calling netif_carrier_off() too early in the probe function; it should be called after register_netdev(). Similar problems have been fixed in many other drivers, e.g.: e826eafa6 (bonding: Call netif_carrier_off after register_netdevice) 0d672e9f8 (drivers/net: Call netif_carrier_off at the end of the probe) 6a3c869a6 (cxgb4: fix reported state of interfaces without link) Fix is to move netif_carrier_off() to the end of the function. Signed-off-by: Kevin Cernekee Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/u_ether.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 29c854bbca4..4e1f0aaafcf 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -796,12 +796,6 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) SET_ETHTOOL_OPS(net, &ops); - /* two kinds of host-initiated state changes: - * - iff DATA transfer is active, carrier is "on" - * - tx queueing enabled if open *and* carrier is "on" - */ - netif_carrier_off(net); - dev->gadget = g; SET_NETDEV_DEV(net, &g->dev); SET_NETDEV_DEVTYPE(net, &gadget_type); @@ -815,6 +809,12 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) INFO(dev, "HOST MAC %pM\n", dev->host_mac); the_dev = dev; + + /* two kinds of host-initiated state changes: + * - iff DATA transfer is active, carrier is "on" + * - tx queueing enabled if open *and* carrier is "on" + */ + netif_carrier_off(net); } return status; From 11ca5d15e7a84181788c01adc4049a36e387dd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 12 Jul 2012 12:37:32 +0200 Subject: [PATCH 0551/2357] USB: option: add ZTE MF821D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 09110529780890804b22e997ae6b4fe3f0b3b158 upstream. Sold by O2 (telefonica germany) under the name "LTE4G" Tested-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 49484b39cc0..ae1a4b8c689 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -936,6 +936,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), From 22dacbd152e98dfd627664f5ee3c21d2bd32430b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 19 Jun 2012 09:54:48 +0200 Subject: [PATCH 0552/2357] Revert "usb/uas: make sure data urb is gone if we receive status before that" commit c621a81edecdee85da32c566c21836332c764fda upstream. This reverts commit e4d8318a85779b25b880187b1b1c44e797bd7d4b. This patch makes uas.c call usb_unlink_urb on data urbs. The data urbs get freed in the completion callback. This is illegal according to the usb_unlink_urb documentation. This patch also makes the code expect the data completion callback being called before the status completion callback. This isn't guaranteed to be the case, even though the actual data transfer should be finished by the time the status is received. Background: The ehci irq handler for example only know that there are finished transfers, it then has go check the QHs & TDs to see which transfers did actually finish. It has no way to figure in which order the transfers did complete. The xhci driver can call the callbacks in completion order thanks to the event queue. This does nicely explain why the driver is solid on a (usb2) xhci port whereas it goes crazy on ehci in my testing. Signed-off-by: Gerd Hoffmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas.c | 90 +++++++-------------------------------- 1 file changed, 15 insertions(+), 75 deletions(-) diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 8ec8a6e66f5..f98ba40352c 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -58,9 +58,6 @@ enum { SUBMIT_DATA_OUT_URB = (1 << 5), ALLOC_CMD_URB = (1 << 6), SUBMIT_CMD_URB = (1 << 7), - COMPLETED_DATA_IN = (1 << 8), - COMPLETED_DATA_OUT = (1 << 9), - DATA_COMPLETES_CMD = (1 << 10), }; /* Overrides scsi_pointer */ @@ -114,7 +111,6 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) { struct sense_iu *sense_iu = urb->transfer_buffer; struct scsi_device *sdev = cmnd->device; - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; if (urb->actual_length > 16) { unsigned len = be16_to_cpup(&sense_iu->len); @@ -132,15 +128,13 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) } cmnd->result = sense_iu->status; - if (!(cmdinfo->state & DATA_COMPLETES_CMD)) - cmnd->scsi_done(cmnd); + cmnd->scsi_done(cmnd); } static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) { struct sense_iu_old *sense_iu = urb->transfer_buffer; struct scsi_device *sdev = cmnd->device; - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; if (urb->actual_length > 8) { unsigned len = be16_to_cpup(&sense_iu->len) - 2; @@ -158,8 +152,7 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) } cmnd->result = sense_iu->status; - if (!(cmdinfo->state & DATA_COMPLETES_CMD)) - cmnd->scsi_done(cmnd); + cmnd->scsi_done(cmnd); } static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, @@ -184,7 +177,6 @@ static void uas_stat_cmplt(struct urb *urb) struct Scsi_Host *shost = urb->context; struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; struct scsi_cmnd *cmnd; - struct uas_cmd_info *cmdinfo; u16 tag; int ret; @@ -210,32 +202,12 @@ static void uas_stat_cmplt(struct urb *urb) dev_err(&urb->dev->dev, "failed submit status urb\n"); return; } - cmdinfo = (void *)&cmnd->SCp; switch (iu->iu_id) { case IU_ID_STATUS: if (devinfo->cmnd == cmnd) devinfo->cmnd = NULL; - if (!(cmdinfo->state & COMPLETED_DATA_IN) && - cmdinfo->data_in_urb) { - if (devinfo->use_streams) { - cmdinfo->state |= DATA_COMPLETES_CMD; - usb_unlink_urb(cmdinfo->data_in_urb); - } else { - usb_free_urb(cmdinfo->data_in_urb); - } - } - if (!(cmdinfo->state & COMPLETED_DATA_OUT) && - cmdinfo->data_out_urb) { - if (devinfo->use_streams) { - cmdinfo->state |= DATA_COMPLETES_CMD; - usb_unlink_urb(cmdinfo->data_in_urb); - } else { - usb_free_urb(cmdinfo->data_out_urb); - } - } - if (urb->actual_length < 16) devinfo->uas_sense_old = 1; if (devinfo->uas_sense_old) @@ -264,59 +236,27 @@ static void uas_stat_cmplt(struct urb *urb) dev_err(&urb->dev->dev, "failed submit status urb\n"); } -static void uas_data_out_cmplt(struct urb *urb) -{ - struct scsi_cmnd *cmnd = urb->context; - struct scsi_data_buffer *sdb = scsi_out(cmnd); - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - - cmdinfo->state |= COMPLETED_DATA_OUT; - - sdb->resid = sdb->length - urb->actual_length; - usb_free_urb(urb); - - if (cmdinfo->state & DATA_COMPLETES_CMD) - cmnd->scsi_done(cmnd); -} - -static void uas_data_in_cmplt(struct urb *urb) +static void uas_data_cmplt(struct urb *urb) { - struct scsi_cmnd *cmnd = urb->context; - struct scsi_data_buffer *sdb = scsi_in(cmnd); - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - - cmdinfo->state |= COMPLETED_DATA_IN; - + struct scsi_data_buffer *sdb = urb->context; sdb->resid = sdb->length - urb->actual_length; usb_free_urb(urb); - - if (cmdinfo->state & DATA_COMPLETES_CMD) - cmnd->scsi_done(cmnd); } static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, - unsigned int pipe, struct scsi_cmnd *cmnd, - enum dma_data_direction dir) + unsigned int pipe, u16 stream_id, + struct scsi_data_buffer *sdb, + enum dma_data_direction dir) { - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; struct usb_device *udev = devinfo->udev; struct urb *urb = usb_alloc_urb(0, gfp); - struct scsi_data_buffer *sdb; - usb_complete_t complete_fn; - u16 stream_id = cmdinfo->stream; if (!urb) goto out; - if (dir == DMA_FROM_DEVICE) { - sdb = scsi_in(cmnd); - complete_fn = uas_data_in_cmplt; - } else { - sdb = scsi_out(cmnd); - complete_fn = uas_data_out_cmplt; - } - usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, - complete_fn, cmnd); - urb->stream_id = stream_id; + usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt, + sdb); + if (devinfo->use_streams) + urb->stream_id = stream_id; urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; urb->sg = sdb->table.sgl; out: @@ -418,8 +358,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd, if (cmdinfo->state & ALLOC_DATA_IN_URB) { cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp, - devinfo->data_in_pipe, cmnd, - DMA_FROM_DEVICE); + devinfo->data_in_pipe, cmdinfo->stream, + scsi_in(cmnd), DMA_FROM_DEVICE); if (!cmdinfo->data_in_urb) return SCSI_MLQUEUE_DEVICE_BUSY; cmdinfo->state &= ~ALLOC_DATA_IN_URB; @@ -436,8 +376,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd, if (cmdinfo->state & ALLOC_DATA_OUT_URB) { cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp, - devinfo->data_out_pipe, cmnd, - DMA_TO_DEVICE); + devinfo->data_out_pipe, cmdinfo->stream, + scsi_out(cmnd), DMA_TO_DEVICE); if (!cmdinfo->data_out_urb) return SCSI_MLQUEUE_DEVICE_BUSY; cmdinfo->state &= ~ALLOC_DATA_OUT_URB; From 2830f9a08c084bcf40819942f04d0ca500faf4b8 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Fri, 20 Jul 2012 10:37:25 +0200 Subject: [PATCH 0553/2357] ALSA: hda - add dock support for Thinkpad X230 Tablet commit 108cc108a3bb42fe4705df1317ff98e1e29428a6 upstream. Also add a model/fixup string "lenovo-dock", so that other Thinkpad users will be able to test this fixup easily, to see if it enables dock I/O for them as well. BugLink: https://bugs.launchpad.net/bugs/1026953 Tested-by: John McCarron Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- Documentation/sound/alsa/HD-Audio-Models.txt | 3 ++- sound/pci/hda/patch_realtek.c | 27 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 03f7897c641..286ec04d138 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -21,10 +21,11 @@ ALC267/268 ========== N/A -ALC269 +ALC269/270/275/276/280/282 ====== laptop-amic Laptops with analog-mic input laptop-dmic Laptops with digital-mic input + lenovo-dock Enables docking station I/O for some Lenovos ALC662/663/272 ============== diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 10c1bc79ad1..88ccc0f62b1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5858,6 +5858,15 @@ static int alc269_resume(struct hda_codec *codec) } #endif /* CONFIG_PM */ +static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == ALC_FIXUP_ACT_PRE_PROBE) + spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; +} + static void alc269_fixup_hweq(struct hda_codec *codec, const struct alc_fixup *fix, int action) { @@ -5984,6 +5993,8 @@ enum { ALC269VB_FIXUP_AMIC, ALC269VB_FIXUP_DMIC, ALC269_FIXUP_MIC2_MUTE_LED, + ALC269_FIXUP_LENOVO_DOCK, + ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT, }; static const struct alc_fixup alc269_fixups[] = { @@ -6108,6 +6119,20 @@ static const struct alc_fixup alc269_fixups[] = { .type = ALC_FIXUP_FUNC, .v.func = alc269_fixup_mic2_mute, }, + [ALC269_FIXUP_LENOVO_DOCK] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x19, 0x23a11040 }, /* dock mic */ + { 0x1b, 0x2121103f }, /* dock headphone */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT + }, + [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc269_fixup_pincfg_no_hp_to_lineout, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -6131,6 +6156,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), @@ -6189,6 +6215,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { static const struct alc_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"}, {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"}, + {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"}, {} }; From 7b689c5d930f281e417597af9f817ba03dc9d898 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 11 Jul 2012 10:20:47 -0700 Subject: [PATCH 0554/2357] x86/mce: Fix siginfo_t->si_addr value for non-recoverable memory faults commit 6751ed65dc6642af64f7b8a440a75563c8aab7ae upstream. In commit dad1743e5993f1 ("x86/mce: Only restart instruction after machine check recovery if it is safe") we fixed mce_notify_process() to force a signal to the current process if it was not restartable (RIPV bit not set in MCG_STATUS). But doing it here means that the process doesn't get told the virtual address of the fault via siginfo_t->si_addr. This would prevent application level recovery from the fault. Make a new MF_MUST_KILL flag bit for memory_failure() et al. to use so that we will provide the right information with the signal. Signed-off-by: Tony Luck Acked-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce.c | 6 ++++-- include/linux/mm.h | 1 + mm/memory-failure.c | 14 ++++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 61604aefc40..0d2db0e7caf 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1180,6 +1180,7 @@ void mce_notify_process(void) { unsigned long pfn; struct mce_info *mi = mce_find_info(); + int flags = MF_ACTION_REQUIRED; if (!mi) mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL); @@ -1194,8 +1195,9 @@ void mce_notify_process(void) * doomed. We still need to mark the page as poisoned and alert any * other users of the page. */ - if (memory_failure(pfn, MCE_VECTOR, MF_ACTION_REQUIRED) < 0 || - mi->restartable == 0) { + if (!mi->restartable) + flags |= MF_MUST_KILL; + if (memory_failure(pfn, MCE_VECTOR, flags) < 0) { pr_err("Memory error not recovered"); force_sig(SIGBUS, current); } diff --git a/include/linux/mm.h b/include/linux/mm.h index 74aa71bea1e..441a5641036 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1595,6 +1595,7 @@ void vmemmap_populate_print_last(void); enum mf_flags { MF_COUNT_INCREASED = 1 << 0, MF_ACTION_REQUIRED = 1 << 1, + MF_MUST_KILL = 1 << 2, }; extern int memory_failure(unsigned long pfn, int trapno, int flags); extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 97cc2733551..0de20d7168f 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -345,14 +345,14 @@ static void add_to_kill(struct task_struct *tsk, struct page *p, * Also when FAIL is set do a force kill because something went * wrong earlier. */ -static void kill_procs(struct list_head *to_kill, int doit, int trapno, +static void kill_procs(struct list_head *to_kill, int forcekill, int trapno, int fail, struct page *page, unsigned long pfn, int flags) { struct to_kill *tk, *next; list_for_each_entry_safe (tk, next, to_kill, nd) { - if (doit) { + if (forcekill) { /* * In case something went wrong with munmapping * make sure the process doesn't catch the @@ -858,7 +858,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, struct address_space *mapping; LIST_HEAD(tokill); int ret; - int kill = 1; + int kill = 1, forcekill; struct page *hpage = compound_head(p); struct page *ppage; @@ -888,7 +888,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, * be called inside page lock (it's recommended but not enforced). */ mapping = page_mapping(hpage); - if (!PageDirty(hpage) && mapping && + if (!(flags & MF_MUST_KILL) && !PageDirty(hpage) && mapping && mapping_cap_writeback_dirty(mapping)) { if (page_mkclean(hpage)) { SetPageDirty(hpage); @@ -965,12 +965,14 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, * Now that the dirty bit has been propagated to the * struct page and all unmaps done we can decide if * killing is needed or not. Only kill when the page - * was dirty, otherwise the tokill list is merely + * was dirty or the process is not restartable, + * otherwise the tokill list is merely * freed. When there was a problem unmapping earlier * use a more force-full uncatchable kill to prevent * any accesses to the poisoned memory. */ - kill_procs(&tokill, !!PageDirty(ppage), trapno, + forcekill = PageDirty(ppage) || (flags & MF_MUST_KILL); + kill_procs(&tokill, forcekill, trapno, ret != SWAP_SUCCESS, p, pfn, flags); return ret; From fd3cca0a4e6ac0512e9122f59dfe0214b74049fb Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 23 Jul 2012 15:17:17 -0400 Subject: [PATCH 0555/2357] locks: fix checking of fcntl_setlease argument commit 0ec4f431eb56d633da3a55da67d5c4b88886ccc7 upstream. The only checks of the long argument passed to fcntl(fd,F_SETLEASE,.) are done after converting the long to an int. Thus some illegal values may be let through and cause problems in later code. [ They actually *don't* cause problems in mainline, as of Dave Jones's commit 8d657eb3b438 "Remove easily user-triggerable BUG from generic_setlease", but we should fix this anyway. And this patch will be necessary to fix real bugs on earlier kernels. ] Signed-off-by: J. Bruce Fields Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/locks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 6a64f154db0..fcc50ab71cc 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -308,7 +308,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock, return 0; } -static int assign_type(struct file_lock *fl, int type) +static int assign_type(struct file_lock *fl, long type) { switch (type) { case F_RDLCK: @@ -445,7 +445,7 @@ static const struct lock_manager_operations lease_manager_ops = { /* * Initialize a lease, use the default lock manager operations */ -static int lease_init(struct file *filp, int type, struct file_lock *fl) +static int lease_init(struct file *filp, long type, struct file_lock *fl) { if (assign_type(fl, type) != 0) return -EINVAL; @@ -463,7 +463,7 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl) } /* Allocate a file_lock initialised to this type of lease */ -static struct file_lock *lease_alloc(struct file *filp, int type) +static struct file_lock *lease_alloc(struct file *filp, long type) { struct file_lock *fl = locks_alloc_lock(); int error = -ENOMEM; From d3dd392851e014c90ce9e26d03a93188840a5a0b Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Sat, 16 Jun 2012 15:30:45 +0200 Subject: [PATCH 0556/2357] ftrace: Disable function tracing during suspend/resume and hibernation, again commit 443772d408a25af62498793f6f805ce3c559309a upstream. If function tracing is enabled for some of the low-level suspend/resume functions, it leads to triple fault during resume from suspend, ultimately ending up in a reboot instead of a resume (or a total refusal to come out of suspended state, on some machines). This issue was explained in more detail in commit f42ac38c59e0a03d (ftrace: disable tracing for suspend to ram). However, the changes made by that commit got reverted by commit cbe2f5a6e84eebb (tracing: allow tracing of suspend/resume & hibernation code again). So, unfortunately since things are not yet robust enough to allow tracing of low-level suspend/resume functions, suspend/resume is still broken when ftrace is enabled. So fix this by disabling function tracing during suspend/resume & hibernation. Signed-off-by: Srivatsa S. Bhat Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- kernel/power/hibernate.c | 6 ++++++ kernel/power/suspend.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index e09dfbfeece..52a18173c84 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -352,6 +352,7 @@ int hibernation_snapshot(int platform_mode) } suspend_console(); + ftrace_stop(); pm_restrict_gfp_mask(); error = dpm_suspend(PMSG_FREEZE); @@ -377,6 +378,7 @@ int hibernation_snapshot(int platform_mode) if (error || !in_suspend) pm_restore_gfp_mask(); + ftrace_start(); resume_console(); dpm_complete(msg); @@ -479,6 +481,7 @@ int hibernation_restore(int platform_mode) pm_prepare_console(); suspend_console(); + ftrace_stop(); pm_restrict_gfp_mask(); error = dpm_suspend_start(PMSG_QUIESCE); if (!error) { @@ -486,6 +489,7 @@ int hibernation_restore(int platform_mode) dpm_resume_end(PMSG_RECOVER); } pm_restore_gfp_mask(); + ftrace_start(); resume_console(); pm_restore_console(); return error; @@ -512,6 +516,7 @@ int hibernation_platform_enter(void) entering_platform_hibernation = true; suspend_console(); + ftrace_stop(); error = dpm_suspend_start(PMSG_HIBERNATE); if (error) { if (hibernation_ops->recover) @@ -555,6 +560,7 @@ int hibernation_platform_enter(void) Resume_devices: entering_platform_hibernation = false; dpm_resume_end(PMSG_RESTORE); + ftrace_start(); resume_console(); Close: diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 396d262b8fd..c8b7446b27d 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "power.h" @@ -212,6 +213,7 @@ int suspend_devices_and_enter(suspend_state_t state) goto Close; } suspend_console(); + ftrace_stop(); suspend_test_start(); error = dpm_suspend_start(PMSG_SUSPEND); if (error) { @@ -231,6 +233,7 @@ int suspend_devices_and_enter(suspend_state_t state) suspend_test_start(); dpm_resume_end(PMSG_RESUME); suspend_test_finish("resume devices"); + ftrace_start(); resume_console(); Close: if (suspend_ops->end) From 46dbb0f5903b71e3c7b37e4ad707a9aa70fe3eed Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 19 Jul 2012 10:38:06 +0200 Subject: [PATCH 0557/2357] PM / Sleep: call early resume handlers when suspend_noirq fails commit 064b021fbe470ecc9ca10f9f87af48c0fc0865fb upstream. Commit cf579dfb82550e34de7ccf3ef090d8b834ccd3a9 (PM / Sleep: Introduce "late suspend" and "early resume" of devices) introduced a bug where suspend_late handlers would be called, but if dpm_suspend_noirq returned an error the early_resume handlers would never be called. All devices would end up on the dpm_late_early_list, and would never be resumed again. Fix it by calling dpm_resume_early when dpm_suspend_noirq returns an error. Signed-off-by: Colin Cross Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 3085f9bcdd8..f7eff25ffe4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -979,8 +979,16 @@ static int dpm_suspend_late(pm_message_t state) int dpm_suspend_end(pm_message_t state) { int error = dpm_suspend_late(state); + if (error) + return error; - return error ? : dpm_suspend_noirq(state); + error = dpm_suspend_noirq(state); + if (error) { + dpm_resume_early(state); + return error; + } + + return 0; } EXPORT_SYMBOL_GPL(dpm_suspend_end); From ecbd55f98e07e25d4017077d0a611ce6c766257b Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Tue, 24 Apr 2012 17:38:17 -0300 Subject: [PATCH 0558/2357] TPM: chip disabled state erronously being reported as error commit 24ebe6670de3d1f0dca11c9eb372134c7ab05503 upstream. tpm_do_selftest() attempts to read a PCR in order to decide if one can rely on the TPM being used or not. The function that's used by __tpm_pcr_read() does not expect the TPM to be disabled or deactivated, and if so, reports an error. It's fine if the TPM returns this error when trying to use it for the first time after a power cycle, but it's definitely not if it already returned success for a previous attempt to read one of its PCRs. The tpm_do_selftest() was modified so that the driver only reports this return code as an error when it really is. Reported-and-tested-by: Paul Bolle Signed-off-by: Rajiv Andrade Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index ad7c7320dd1..08427abf5fa 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -827,10 +827,10 @@ EXPORT_SYMBOL_GPL(tpm_pcr_extend); int tpm_do_selftest(struct tpm_chip *chip) { int rc; - u8 digest[TPM_DIGEST_SIZE]; unsigned int loops; unsigned int delay_msec = 1000; unsigned long duration; + struct tpm_cmd_t cmd; duration = tpm_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST); @@ -845,7 +845,15 @@ int tpm_do_selftest(struct tpm_chip *chip) return rc; do { - rc = __tpm_pcr_read(chip, 0, digest); + /* Attempt to read a PCR value */ + cmd.header.in = pcrread_header; + cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0); + rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE); + + if (rc < TPM_HEADER_SIZE) + return -EFAULT; + + rc = be32_to_cpu(cmd.header.out.return_code); if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { dev_info(chip->dev, "TPM is disabled/deactivated (0x%X)\n", rc); From 20855fe2097ccfde927c6997101ae35340f1d278 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 19 Jul 2012 06:13:36 +0000 Subject: [PATCH 0559/2357] tun: fix a crash bug and a memory leak commit b09e786bd1dd66418b69348cb110f3a64764626a upstream. This patch fixes a crash tun_chr_close -> netdev_run_todo -> tun_free_netdev -> sk_release_kernel -> sock_release -> iput(SOCK_INODE(sock)) introduced by commit 1ab5ecb90cb6a3df1476e052f76a6e8f6511cb3d The problem is that this socket is embedded in struct tun_struct, it has no inode, iput is called on invalid inode, which modifies invalid memory and optionally causes a crash. sock_release also decrements sockets_in_use, this causes a bug that "sockets: used" field in /proc/*/net/sockstat keeps on decreasing when creating and closing tun devices. This patch introduces a flag SOCK_EXTERNALLY_ALLOCATED that instructs sock_release to not free the inode and not decrement sockets_in_use, fixing both memory corruption and sockets_in_use underflow. It should be backported to 3.3 an 3.4 stabke. Signed-off-by: Mikulas Patocka Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/tun.c | 3 +++ include/linux/net.h | 1 + net/socket.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index bb8c72c79c6..a06ad55d949 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -358,6 +358,8 @@ static void tun_free_netdev(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); + BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED, &tun->socket.flags)); + sk_release_kernel(tun->socket.sk); } @@ -1115,6 +1117,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) tun->flags = flags; tun->txflt.count = 0; tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr); + set_bit(SOCK_EXTERNALLY_ALLOCATED, &tun->socket.flags); err = -ENOMEM; sk = sk_alloc(&init_net, AF_UNSPEC, GFP_KERNEL, &tun_proto); diff --git a/include/linux/net.h b/include/linux/net.h index be60c7f5e14..95fea1432dd 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -72,6 +72,7 @@ struct net; #define SOCK_NOSPACE 2 #define SOCK_PASSCRED 3 #define SOCK_PASSSEC 4 +#define SOCK_EXTERNALLY_ALLOCATED 5 #ifndef ARCH_HAS_SOCKET_TYPES /** diff --git a/net/socket.c b/net/socket.c index 851edcd6b09..573b26152a3 100644 --- a/net/socket.c +++ b/net/socket.c @@ -522,6 +522,9 @@ void sock_release(struct socket *sock) if (rcu_dereference_protected(sock->wq, 1)->fasync_list) printk(KERN_ERR "sock_release: fasync list not empty!\n"); + if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags)) + return; + percpu_sub(sockets_in_use, 1); if (!sock->file) { iput(SOCK_INODE(sock)); From 79746484cab1dede1480580efe9edde68de06770 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 13 May 2012 18:07:04 +0300 Subject: [PATCH 0560/2357] mac80211: fail authentication when AP denied authentication commit dac211ec10d268b9d09000093a9fa2ac1773894f upstream. ieee80211_rx_mgmt_auth() doesn't handle denied authentication properly - it authenticates the station and waits for association (for 5 seconds) instead of failing the authentication. Fix it by destroying auth_data and bailing out instead. Signed-off-by: Eliad Peller Acked-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d132b98bd1c..25be6831ff0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1813,7 +1813,8 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", sdata->name, mgmt->sa, status_code); - goto out; + ieee80211_destroy_auth_data(sdata, false); + return RX_MGMT_CFG80211_RX_AUTH; } switch (ifmgd->auth_data->algorithm) { @@ -1835,7 +1836,6 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, } printk(KERN_DEBUG "%s: authenticated\n", sdata->name); - out: ifmgd->auth_data->done = true; ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; run_again(ifmgd, ifmgd->auth_data->timeout); From a75b6122aacd06507cae1010e0fb6b06fe53336a Mon Sep 17 00:00:00 2001 From: Meenakshi Venkataraman Date: Wed, 16 May 2012 22:40:50 +0200 Subject: [PATCH 0561/2357] iwlwifi: fix debug print in iwl_sta_calc_ht_flags commit a35e270881a5db1ec9ac8bc6d61ebc3e85c14f33 upstream. We missed passing an argument to the debug print. Fix it. Signed-off-by: Meenakshi Venkataraman Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-agn-sta.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index bef3f242434..8be535f8f6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -191,6 +191,7 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n", + sta->addr, (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? "static" : (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? From 74ec52aa07788b9bce2edd6ce9763c0d79bad38a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 11 Jul 2012 14:37:28 -0500 Subject: [PATCH 0562/2357] rtlwifi: rtl8192cu: Change buffer allocation for synchronous reads commit 3ce4d85b76010525adedcc2555fa164bf706a2f3 upstream. In commit a7959c1, the USB part of rtlwifi was switched to convert _usb_read_sync() to using a preallocated buffer rather than one that has been acquired using kmalloc. Although this routine is named as though it were synchronous, there seem to be simultaneous users, and the selection of the index to the data buffer is not multi-user safe. This situation is addressed by adding a new spinlock. The routine cannot sleep, thus a mutex is not allowed. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/usb.c | 14 +++++++++++--- drivers/net/wireless/rtlwifi/wifi.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index a6049d7d51b..aa970fc18a2 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -131,15 +131,19 @@ static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len) u8 request; u16 wvalue; u16 index; - __le32 *data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; + __le32 *data; + unsigned long flags; + spin_lock_irqsave(&rtlpriv->locks.usb_lock, flags); + if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) + rtlpriv->usb_data_index = 0; + data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; + spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags); request = REALTEK_USB_VENQT_CMD_REQ; index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ wvalue = (u16)addr; _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); - if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) - rtlpriv->usb_data_index = 0; return le32_to_cpu(*data); } @@ -951,6 +955,10 @@ int __devinit rtl_usb_probe(struct usb_interface *intf, GFP_KERNEL); if (!rtlpriv->usb_data) return -ENOMEM; + + /* this spin lock must be initialized early */ + spin_lock_init(&rtlpriv->locks.usb_lock); + rtlpriv->usb_data_index = 0; init_completion(&rtlpriv->firmware_loading_complete); SET_IEEE80211_DEV(hw, &intf->dev); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 28ebc69218a..717d3bad17d 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1555,6 +1555,7 @@ struct rtl_locks { spinlock_t rf_ps_lock; spinlock_t rf_lock; spinlock_t waitq_lock; + spinlock_t usb_lock; /*Dual mac*/ spinlock_t cck_and_rw_pagea_lock; From ae9bc43cfc53968dd628052d1c225ace8560da64 Mon Sep 17 00:00:00 2001 From: Forest Bond Date: Fri, 13 Jul 2012 12:26:06 -0400 Subject: [PATCH 0563/2357] rtlwifi: rtl8192de: Fix phy-based version calculation commit f1b00f4dab29b57bdf1bc03ef12020b280fd2a72 upstream. Commit d83579e2a50ac68389e6b4c58b845c702cf37516 incorporated some changes from the vendor driver that made it newly important that the calculated hardware version correctly include the CHIP_92D bit, as all of the IS_92D_* macros were changed to depend on it. However, this bit was being unset for dual-mac, dual-phy devices. The vendor driver behavior was modified to not do this, but unfortunately this change was not picked up along with the others. This caused scanning in the 2.4GHz band to be broken, and possibly other bugs as well. This patch brings the version calculation logic in parity with the vendor driver in this regard, and in doing so fixes the regression. However, the version calculation code in general continues to be largely incoherent and messy, and needs to be cleaned up. Signed-off-by: Forest Bond Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/rtl8192de/phy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 28fc5fb8057..46f7917fed5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3344,21 +3344,21 @@ void rtl92d_phy_config_macphymode_info(struct ieee80211_hw *hw) switch (rtlhal->macphymode) { case DUALMAC_SINGLEPHY: rtlphy->rf_type = RF_2T2R; - rtlhal->version |= CHIP_92D_SINGLEPHY; + rtlhal->version |= RF_TYPE_2T2R; rtlhal->bandset = BAND_ON_BOTH; rtlhal->current_bandtype = BAND_ON_2_4G; break; case SINGLEMAC_SINGLEPHY: rtlphy->rf_type = RF_2T2R; - rtlhal->version |= CHIP_92D_SINGLEPHY; + rtlhal->version |= RF_TYPE_2T2R; rtlhal->bandset = BAND_ON_BOTH; rtlhal->current_bandtype = BAND_ON_2_4G; break; case DUALMAC_DUALPHY: rtlphy->rf_type = RF_1T1R; - rtlhal->version &= (~CHIP_92D_SINGLEPHY); + rtlhal->version &= RF_TYPE_1T1R; /* Now we let MAC0 run on 5G band. */ if (rtlhal->interfaceindex == 0) { rtlhal->bandset = BAND_ON_5G; From 2c3fea5b8591cd8c539bff95108efc2a1f9c5f20 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 11 Jul 2012 18:12:57 -0700 Subject: [PATCH 0564/2357] mwifiex: correction in mcs index check commit fe020120cb863ba918c6d603345342a880272c4d upstream. mwifiex driver supports 2x2 chips as well. Hence valid mcs values are 0 to 15. The check for mcs index is corrected in this patch. For example: if 40MHz is enabled and mcs index is 11, "iw link" command would show "tx bitrate: 108.0 MBit/s" without this patch. Now it shows "tx bitrate: 108.0 MBit/s MCS 11 40Mhz" with the patch. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mwifiex/cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index baf691949c3..03560a8a858 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -544,9 +544,9 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, /* * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid - * MCS index values for us are 0 to 7. + * MCS index values for us are 0 to 15. */ - if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 8)) { + if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) { sinfo->txrate.mcs = priv->tx_rate; sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; /* 40MHz rate */ From 554c9a0c6f72a8a5c44962b82f495d95e547b4b3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 13 Jul 2012 15:45:33 +0200 Subject: [PATCH 0565/2357] s390/idle: fix sequence handling vs cpu hotplug commit 0008204ffe85d23382d6fd0f971f3f0fbe70bae2 upstream. The s390 idle accounting code uses a sequence counter which gets used when the per cpu idle statistics get updated and read. One assumption on read access is that only when the sequence counter is even and did not change while reading all values the result is valid. On cpu hotplug however the per cpu data structure gets initialized via a cpu hotplug notifier on CPU_ONLINE. CPU_ONLINE however is too late, since the onlined cpu is already running and might access the per cpu data. Worst case is that the data structure gets initialized while an idle thread is updating its idle statistics. This will result in an uneven sequence counter after an update. As a result user space tools like top, which access /proc/stat in order to get idle stats, will busy loop waiting for the sequence counter to become even again, which will never happen until the queried cpu will update its idle statistics again. And even then the sequence counter will only have an even value for a couple of cpu cycles. Fix this by moving the initialization of the per cpu idle statistics to cpu_init(). I prefer that solution in favor of changing the notifier to CPU_UP_PREPARE, which would be a different solution to the problem. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/processor.c | 2 ++ arch/s390/kernel/smp.c | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 6e0073e43f5..07c7bf47d61 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -26,12 +26,14 @@ static DEFINE_PER_CPU(struct cpuid, cpu_id); void __cpuinit cpu_init(void) { struct cpuid *id = &per_cpu(cpu_id, smp_processor_id()); + struct s390_idle_data *idle = &__get_cpu_var(s390_idle); get_cpu_id(id); atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; BUG_ON(current->mm); enter_lazy_tlb(&init_mm, current); + memset(idle, 0, sizeof(*idle)); } /* diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 1f77227669e..c7b8822c561 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -1034,14 +1034,11 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self, unsigned int cpu = (unsigned int)(long)hcpu; struct cpu *c = &pcpu_devices[cpu].cpu; struct device *s = &c->dev; - struct s390_idle_data *idle; int err = 0; switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: - idle = &per_cpu(s390_idle, cpu); - memset(idle, 0, sizeof(struct s390_idle_data)); err = sysfs_create_group(&s->kobj, &cpu_online_attr_group); break; case CPU_DEAD: From cd1af8b7d386e6b3991252650c16b3e9d5a03b65 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 26 Jul 2012 08:53:06 +0200 Subject: [PATCH 0566/2357] s390/mm: downgrade page table after fork of a 31 bit process commit 0f6f281b731d20bfe75c13f85d33f3f05b440222 upstream. The downgrade of the 4 level page table created by init_new_context is currently done only in start_thread31. If a 31 bit process forks the new mm uses a 4 level page table, including the task size of 2<<42 that goes along with it. This is incorrect as now a 31 bit process can map memory beyond 2GB. Define arch_dup_mmap to do the downgrade after fork. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/mmu_context.h | 14 +++++++++++++- arch/s390/include/asm/processor.h | 2 ++ arch/s390/mm/mmap.c | 12 ++++++++++-- arch/s390/mm/pgtable.c | 5 ----- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 5d09e405c54..5d211f70d83 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -13,7 +13,6 @@ #include #include #include -#include static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) @@ -93,4 +92,17 @@ static inline void activate_mm(struct mm_struct *prev, switch_mm(prev, next, current); } +static inline void arch_dup_mmap(struct mm_struct *oldmm, + struct mm_struct *mm) +{ +#ifdef CONFIG_64BIT + if (oldmm->context.asce_limit < mm->context.asce_limit) + crst_table_downgrade(mm, oldmm->context.asce_limit); +#endif +} + +static inline void arch_exit_mmap(struct mm_struct *mm) +{ +} + #endif /* __S390_MMU_CONTEXT_H */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index d499b30ea48..8b6f62e1c36 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -129,7 +129,9 @@ struct stack_frame { regs->psw.mask = psw_user_bits | PSW_MASK_BA; \ regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ regs->gprs[15] = new_stackp; \ + __tlb_flush_mm(current->mm); \ crst_table_downgrade(current->mm, 1UL << 31); \ + update_mm(current->mm, current); \ } while (0) /* Forward declaration, a strange C thing */ diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 2857c48486e..a64fe53c720 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -105,9 +105,15 @@ void arch_pick_mmap_layout(struct mm_struct *mm) int s390_mmap_check(unsigned long addr, unsigned long len) { + int rc; + if (!is_compat_task() && - len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) - return crst_table_upgrade(current->mm, 1UL << 53); + len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) { + rc = crst_table_upgrade(current->mm, 1UL << 53); + if (rc) + return rc; + update_mm(current->mm, current); + } return 0; } @@ -127,6 +133,7 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr, rc = crst_table_upgrade(mm, 1UL << 53); if (rc) return (unsigned long) rc; + update_mm(mm, current); area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); } return area; @@ -149,6 +156,7 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr, rc = crst_table_upgrade(mm, 1UL << 53); if (rc) return (unsigned long) rc; + update_mm(mm, current); area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); } diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 6e765bf0067..87f0efd0e77 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -85,7 +85,6 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) crst_table_free(mm, table); if (mm->context.asce_limit < limit) goto repeat; - update_mm(mm, current); return 0; } @@ -93,9 +92,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) { pgd_t *pgd; - if (mm->context.asce_limit <= limit) - return; - __tlb_flush_mm(mm); while (mm->context.asce_limit > limit) { pgd = mm->pgd; switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { @@ -118,7 +114,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) mm->task_size = mm->context.asce_limit; crst_table_free(mm, (unsigned long *) pgd); } - update_mm(mm, current); } #endif From 351bb0ecc5b0b9dc60d07a44078fa16971c7f3e7 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 27 Jul 2012 09:45:39 +0200 Subject: [PATCH 0567/2357] s390/mm: fix fault handling for page table walk case commit 008c2e8f247f0a8db1e8e26139da12f3a3abcda0 upstream. Make sure the kernel does not incorrectly create a SIGBUS signal during user space accesses: For user space accesses in the switched addressing mode case the kernel may walk page tables and access user address space via the kernel mapping. If a page table entry is invalid the function __handle_fault() gets called in order to emulate a page fault and trigger all the usual actions like paging in a missing page etc. by calling handle_mm_fault(). If handle_mm_fault() returns with an error fixup handling is necessary. For the switched addressing mode case all errors need to be mapped to -EFAULT, so that the calling uaccess function can return -EFAULT to user space. Unfortunately the __handle_fault() incorrectly calls do_sigbus() if VM_FAULT_SIGBUS is set. This however should only happen if a page fault was triggered by a user space instruction. For kernel mode uaccesses the correct action is to only return -EFAULT. So user space may incorrectly see SIGBUS signals because of this bug. For current machines this would only be possible for the switched addressing mode case in conjunction with futex operations. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/mm/fault.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 4e66860029f..f2b11ee3fb3 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -443,6 +443,7 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) struct pt_regs regs; int access, fault; + /* Emulate a uaccess fault from kernel mode. */ regs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK; if (!irqs_disabled()) regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT; @@ -452,12 +453,12 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) regs.int_parm_long = (uaddr & PAGE_MASK) | 2; access = write ? VM_WRITE : VM_READ; fault = do_exception(®s, access); - if (unlikely(fault)) { - if (fault & VM_FAULT_OOM) - return -EFAULT; - else if (fault & VM_FAULT_SIGBUS) - do_sigbus(®s); - } + /* + * Since the fault happened in kernel mode while performing a uaccess + * all we need to do now is emulating a fixup in case "fault" is not + * zero. + * For the calling uaccess functions this results always in -EFAULT. + */ return fault ? -EFAULT : 0; } From e6c1b59aaa759ae5374dedf8508ee14aff2f967f Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 19 Jul 2012 10:56:10 +0200 Subject: [PATCH 0568/2357] iommu/amd: Add missing spin_lock initialization commit 2c13d47a1a7ee8808796016c617aef25fd1d1925 upstream. Add missing spin_lock initialization in amd_iommu_bind_pasid() function and make lockdep happy again. Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu_v2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index 036fe9bf157..a1f1bc87604 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c @@ -681,6 +681,8 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid, atomic_set(&pasid_state->count, 1); init_waitqueue_head(&pasid_state->wq); + spin_lock_init(&pasid_state->lock); + pasid_state->task = task; pasid_state->mm = get_task_mm(task); pasid_state->device_state = dev_state; From 06e619c5073d1830f58039cd97e95ae184cf7bbb Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 19 Jul 2012 13:42:54 +0200 Subject: [PATCH 0569/2357] iommu/amd: Fix hotplug with iommu=pt commit 2c9195e990297068d0f1f1bd8e2f1d09538009da upstream. This did not work because devices are not put into the pt_domain. Fix this. Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index dfe7d37c82c..57ed244cf99 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2254,6 +2254,18 @@ static int device_change_notifier(struct notifier_block *nb, iommu_init_device(dev); + /* + * dev_data is still NULL and + * got initialized in iommu_init_device + */ + dev_data = get_dev_data(dev); + + if (iommu_pass_through || dev_data->iommu_v2) { + dev_data->passthrough = true; + attach_device(dev, pt_domain); + break; + } + domain = domain_for_device(dev); /* allocate a protection domain if a device is added */ @@ -2271,10 +2283,7 @@ static int device_change_notifier(struct notifier_block *nb, dev_data = get_dev_data(dev); - if (!dev_data->passthrough) - dev->archdata.dma_ops = &amd_iommu_dma_ops; - else - dev->archdata.dma_ops = &nommu_dma_ops; + dev->archdata.dma_ops = &amd_iommu_dma_ops; break; case BUS_NOTIFY_DEL_DEVICE: From 664634f8a03e721a7fffb5f1e21cbdd806598cda Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 10 Jul 2012 17:58:04 +0200 Subject: [PATCH 0570/2357] udf: Improve table length check to avoid possible overflow commit 57b9655d01ef057a523e810d29c37ac09b80eead upstream. When a partition table length is corrupted to be close to 1 << 32, the check for its length may overflow on 32-bit systems and we will think the length is valid. Later on the kernel can crash trying to read beyond end of buffer. Fix the check to avoid possible overflow. Reported-by: Ben Hutchings Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 8d86a8706c0..e660ffdd91b 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1283,7 +1283,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, BUG_ON(ident != TAG_IDENT_LVD); lvd = (struct logicalVolDesc *)bh->b_data; table_len = le32_to_cpu(lvd->mapTableLength); - if (sizeof(*lvd) + table_len > sb->s_blocksize) { + if (table_len > sb->s_blocksize - sizeof(*lvd)) { udf_err(sb, "error loading logical volume descriptor: " "Partition table too long (%u > %lu)\n", table_len, sb->s_blocksize - sizeof(*lvd)); From 02f5c5d768faf0417b6801a1bfebc866a6db7878 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 5 Jun 2012 11:15:50 -0400 Subject: [PATCH 0571/2357] stable: update references to older 2.6 versions for 3.x commit 2584f5212d97b664be250ad5700a2d0fee31a10d upstream. Also add information on where the respective trees are. Signed-off-by: Paul Gortmaker Acked-by: Rob Landley Signed-off-by: Greg Kroah-Hartman --- Documentation/stable_kernel_rules.txt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt index 4a7b54bd37e..b0714d8f678 100644 --- a/Documentation/stable_kernel_rules.txt +++ b/Documentation/stable_kernel_rules.txt @@ -1,4 +1,4 @@ -Everything you ever wanted to know about Linux 2.6 -stable releases. +Everything you ever wanted to know about Linux -stable releases. Rules on what kind of patches are accepted, and which ones are not, into the "-stable" tree: @@ -42,10 +42,10 @@ Procedure for submitting patches to the -stable tree: cherry-picked than this can be specified in the following format in the sign-off area: - Cc: # .32.x: a1f84a3: sched: Check for idle - Cc: # .32.x: 1b9508f: sched: Rate-limit newidle - Cc: # .32.x: fd21073: sched: Fix affinity logic - Cc: # .32.x + Cc: # 3.3.x: a1f84a3: sched: Check for idle + Cc: # 3.3.x: 1b9508f: sched: Rate-limit newidle + Cc: # 3.3.x: fd21073: sched: Fix affinity logic + Cc: # 3.3.x Signed-off-by: Ingo Molnar The tag sequence has the meaning of: @@ -79,6 +79,15 @@ Review cycle: security kernel team, and not go through the normal review cycle. Contact the kernel security team for more details on this procedure. +Trees: + + - The queues of patches, for both completed versions and in progress + versions can be found at: + http://git.kernel.org/?p=linux/kernel/git/stable/stable-queue.git + - The finalized and tagged releases of all stable kernels can be found + in separate branches per version at: + http://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git + Review committee: From c7815406caf7efdd805e893caef4a63e61b7645e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 20 Jun 2012 02:31:11 +0100 Subject: [PATCH 0572/2357] staging: zsmalloc: Finish conversion to a separate module commit 069f101fa463351f528773d73b74e9b606b3f66a upstream. ZSMALLOC is tristate, but the code has no MODULE_LICENSE and since it depends on GPL-only symbols it cannot be loaded as a module. This in turn breaks zram which now depends on it. I assume it's meant to be Dual BSD/GPL like the other z-stuff. There is also no module_exit, which will make it impossible to unload. Add the appropriate module_init and module_exit declarations suggested by comments. Reported-by: Christian Ohm References: http://bugs.debian.org/677273 Signed-off-by: Ben Hutchings Reviewed-by: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/zsmalloc/zsmalloc-main.c | 33 +++++------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c index 917461c6601..175b3c94d5a 100644 --- a/drivers/staging/zsmalloc/zsmalloc-main.c +++ b/drivers/staging/zsmalloc/zsmalloc-main.c @@ -426,12 +426,6 @@ static struct page *find_get_zspage(struct size_class *class) } -/* - * If this becomes a separate module, register zs_init() with - * module_init(), zs_exit with module_exit(), and remove zs_initialized -*/ -static int zs_initialized; - static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action, void *pcpu) { @@ -490,7 +484,7 @@ static int zs_init(void) struct zs_pool *zs_create_pool(const char *name, gfp_t flags) { - int i, error, ovhd_size; + int i, ovhd_size; struct zs_pool *pool; if (!name) @@ -517,28 +511,9 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t flags) } - /* - * If this becomes a separate module, register zs_init with - * module_init, and remove this block - */ - if (!zs_initialized) { - error = zs_init(); - if (error) - goto cleanup; - zs_initialized = 1; - } - pool->flags = flags; pool->name = name; - error = 0; /* Success */ - -cleanup: - if (error) { - zs_destroy_pool(pool); - pool = NULL; - } - return pool; } EXPORT_SYMBOL_GPL(zs_create_pool); @@ -749,3 +724,9 @@ u64 zs_get_total_size_bytes(struct zs_pool *pool) return npages << PAGE_SHIFT; } EXPORT_SYMBOL_GPL(zs_get_total_size_bytes); + +module_init(zs_init); +module_exit(zs_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Nitin Gupta "); From d3b42543cf269243ccf2add49008db879ff7f146 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 17 Jul 2012 12:39:26 -0700 Subject: [PATCH 0573/2357] workqueue: perform cpu down operations from low priority cpu_notifier() commit 6575820221f7a4dd6eadecf7bf83cdd154335eda upstream. Currently, all workqueue cpu hotplug operations run off CPU_PRI_WORKQUEUE which is higher than normal notifiers. This is to ensure that workqueue is up and running while bringing up a CPU before other notifiers try to use workqueue on the CPU. Per-cpu workqueues are supposed to remain working and bound to the CPU for normal CPU_DOWN_PREPARE notifiers. This holds mostly true even with workqueue offlining running with higher priority because workqueue CPU_DOWN_PREPARE only creates a bound trustee thread which runs the per-cpu workqueue without concurrency management without explicitly detaching the existing workers. However, if the trustee needs to create new workers, it creates unbound workers which may wander off to other CPUs while CPU_DOWN_PREPARE notifiers are in progress. Furthermore, if the CPU down is cancelled, the per-CPU workqueue may end up with workers which aren't bound to the CPU. While reliably reproducible with a convoluted artificial test-case involving scheduling and flushing CPU burning work items from CPU down notifiers, this isn't very likely to happen in the wild, and, even when it happens, the effects are likely to be hidden by the following successful CPU down. Fix it by using different priorities for up and down notifiers - high priority for up operations and low priority for down operations. Workqueue cpu hotplug operations will soon go through further cleanup. Signed-off-by: Tejun Heo Acked-by: "Rafael J. Wysocki" Signed-off-by: Greg Kroah-Hartman --- include/linux/cpu.h | 5 +++-- kernel/workqueue.c | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/include/linux/cpu.h b/include/linux/cpu.h index ee28844ae68..78ed62f3dde 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -75,8 +75,9 @@ enum { /* migration should happen before other stuff but after perf */ CPU_PRI_PERF = 20, CPU_PRI_MIGRATION = 10, - /* prepare workqueues for other notifiers */ - CPU_PRI_WORKQUEUE = 5, + /* bring up workqueues before normal notifiers and down after */ + CPU_PRI_WORKQUEUE_UP = 5, + CPU_PRI_WORKQUEUE_DOWN = -5, }; #define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 7da267c8d0d..bfe3f8a1fc3 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3582,6 +3582,41 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb, return notifier_from_errno(0); } +/* + * Workqueues should be brought up before normal priority CPU notifiers. + * This will be registered high priority CPU notifier. + */ +static int __devinit workqueue_cpu_up_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_UP_PREPARE: + case CPU_UP_CANCELED: + case CPU_DOWN_FAILED: + case CPU_ONLINE: + return workqueue_cpu_callback(nfb, action, hcpu); + } + return NOTIFY_OK; +} + +/* + * Workqueues should be brought down after normal priority CPU notifiers. + * This will be registered as low priority CPU notifier. + */ +static int __devinit workqueue_cpu_down_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_DOWN_PREPARE: + case CPU_DYING: + case CPU_POST_DEAD: + return workqueue_cpu_callback(nfb, action, hcpu); + } + return NOTIFY_OK; +} + #ifdef CONFIG_SMP struct work_for_cpu { @@ -3775,7 +3810,8 @@ static int __init init_workqueues(void) unsigned int cpu; int i; - cpu_notifier(workqueue_cpu_callback, CPU_PRI_WORKQUEUE); + cpu_notifier(workqueue_cpu_up_callback, CPU_PRI_WORKQUEUE_UP); + cpu_notifier(workqueue_cpu_down_callback, CPU_PRI_WORKQUEUE_DOWN); /* initialize gcwqs */ for_each_gcwq_cpu(cpu) { From 8ebdf76ba264031c60e8dc720775833e0ab6512d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 12 Jun 2012 10:43:28 +0200 Subject: [PATCH 0574/2357] ACPI, APEI: Fixup common access width firmware bug commit f712c71f7b2b43b894d1e92e1b77385fcad8815f upstream. Many firmwares have a common register definition bug where 8-bit access width is specified for a 32-bit register. Ideally this should be fixed in the BIOS, but earlier versions of the kernel did not complain, so fix that up silently. This closes kernel bug #43282: https://bugzilla.kernel.org/show_bug.cgi?id=43282 Signed-off-by: Jean Delvare Acked-by: Huang Ying Acked-by: Gary Hade Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/apei/apei-base.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 6686b1eaf13..00a783661d0 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -586,6 +586,11 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr, } *access_bit_width = 1UL << (access_size_code + 2); + /* Fixup common BIOS bug */ + if (bit_width == 32 && bit_offset == 0 && (*paddr & 0x03) == 0 && + *access_bit_width < 32) + *access_bit_width = 32; + if ((bit_width + bit_offset) > *access_bit_width) { pr_warning(FW_BUG APEI_PFX "Invalid bit width + offset in GAR [0x%llx/%u/%u/%u/%u]\n", From c1542109ac67110d3072fabb23e4604be0ff7554 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Fri, 20 Jul 2012 13:29:16 +0800 Subject: [PATCH 0575/2357] ACPI/AC: prevent OOPS on some boxes due to missing check power_supply_register() return value check commit f197ac13f6eeb351b31250b9ab7d0da17434ea36 upstream. In the ac.c, power_supply_register()'s return value is not checked. As a result, the driver's add() ops may return success even though the device failed to initialize. For example, some BIOS may describe two ACADs in the same DSDT. The second ACAD device will fail to register, but ACPI driver's add() ops returns sucessfully. The ACPI device will receive ACPI notification and cause OOPS. https://bugzilla.redhat.com/show_bug.cgi?id=772730 Signed-off-by: Lan Tianyu Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/ac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 6512b20aecc..d1fcbc0f6cb 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -292,7 +292,9 @@ static int acpi_ac_add(struct acpi_device *device) ac->charger.properties = ac_props; ac->charger.num_properties = ARRAY_SIZE(ac_props); ac->charger.get_property = get_ac_property; - power_supply_register(&ac->device->dev, &ac->charger); + result = power_supply_register(&ac->device->dev, &ac->charger); + if (result) + goto end; printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), acpi_device_bid(device), From d458a00f17bd1c883eaf0192e1cc33a2ae530750 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 25 Jul 2012 15:57:13 -0400 Subject: [PATCH 0576/2357] Btrfs: call the ordered free operation without any locks held commit e9fbcb42201c862fd6ab45c48ead4f47bb2dea9d upstream. Each ordered operation has a free callback, and this was called with the worker spinlock held. Josef made the free callback also call iput, which we can't do with the spinlock. This drops the spinlock for the free operation and grabs it again before moving through the rest of the list. We'll circle back around to this and find a cleaner way that doesn't bounce the lock around so much. Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/async-thread.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 42704149b72..58b7d14b08e 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -206,10 +206,17 @@ static noinline void run_ordered_completions(struct btrfs_workers *workers, work->ordered_func(work); - /* now take the lock again and call the freeing code */ + /* now take the lock again and drop our item from the list */ spin_lock(&workers->order_lock); list_del(&work->order_list); + spin_unlock(&workers->order_lock); + + /* + * we don't want to call the ordered free functions + * with the lock held though + */ work->ordered_free(work); + spin_lock(&workers->order_lock); } spin_unlock(&workers->order_lock); From da49dbd95a28bd166f8935f53ed76d406cd891ca Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 23 Jul 2012 20:34:17 -0400 Subject: [PATCH 0577/2357] cifs: reinstate sec=ntlmv2 mount option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7659624ffb550d69c87f9af9ae63e717daa874bd upstream. sec=ntlmv2 as a mount option got dropped in the mount option overhaul. Cc: Sachin Prabhu Reported-by: Günter Kukkukk Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/connect.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 87ce8af1ce4..65a78e9a5d4 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -238,8 +238,8 @@ static const match_table_t cifs_mount_option_tokens = { enum { Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p, Opt_sec_ntlmsspi, Opt_sec_ntlmssp, - Opt_ntlm, Opt_sec_ntlmi, Opt_sec_ntlmv2i, - Opt_sec_nontlm, Opt_sec_lanman, + Opt_ntlm, Opt_sec_ntlmi, Opt_sec_ntlmv2, + Opt_sec_ntlmv2i, Opt_sec_lanman, Opt_sec_none, Opt_sec_err @@ -253,8 +253,9 @@ static const match_table_t cifs_secflavor_tokens = { { Opt_sec_ntlmssp, "ntlmssp" }, { Opt_ntlm, "ntlm" }, { Opt_sec_ntlmi, "ntlmi" }, + { Opt_sec_ntlmv2, "nontlm" }, + { Opt_sec_ntlmv2, "ntlmv2" }, { Opt_sec_ntlmv2i, "ntlmv2i" }, - { Opt_sec_nontlm, "nontlm" }, { Opt_sec_lanman, "lanman" }, { Opt_sec_none, "none" }, @@ -1163,7 +1164,7 @@ static int cifs_parse_security_flavors(char *value, case Opt_sec_ntlmi: vol->secFlg |= CIFSSEC_MAY_NTLM | CIFSSEC_MUST_SIGN; break; - case Opt_sec_nontlm: + case Opt_sec_ntlmv2: vol->secFlg |= CIFSSEC_MAY_NTLMV2; break; case Opt_sec_ntlmv2i: From 7e7a57b3ea066e3caf149feb37c6487d8423c772 Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Tue, 12 Jun 2012 15:10:58 +0200 Subject: [PATCH 0578/2357] spi/pl022: disable port when unused commit fd316941cfee1fbd12746afea83720fb7823888a upstream. Commit ffbbdd21329f3e15eeca6df2d4bc11c04d9d91c0 "spi: create a message queueing infrastructure" Accidentally deleted the logic to disable the port when unused leading to higher power consumption. Fix this up. Cc: Vinit Shenoy Signed-off-by: Virupax Sadashivpetimath Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-pl022.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 400ae2121a2..469eb28e832 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -489,6 +489,11 @@ static void giveback(struct pl022 *pl022) pl022->cur_transfer = NULL; pl022->cur_chip = NULL; spi_finalize_current_message(pl022->master); + + /* disable the SPI/SSP operation */ + writew((readw(SSP_CR1(pl022->virtbase)) & + (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); + } /** From bfc41a820b085dff6048aab510a4dcb48b570d3b Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Tue, 24 Jul 2012 22:34:29 +0000 Subject: [PATCH 0579/2357] qeth: repair crash in qeth_l3_vlan_rx_kill_vid() commit eabfbe6230ee7363681e7a561948d362b87169f0 upstream. Commit efc73f4b "net: Fix memory leak - vlan_info struct" adds deletion of VLAN 0 for devices with feature NETIF_F_HW_VLAN_FILTER. For driver qeth these are the layer 3 devices. Usually there exists no separate vlan net_device for VLAN 0. Thus the qeth functions qeth_l3_free_vlan_addresses4() and qeth_l3_free_vlan_addresses6() require an extra checking if function __vlan_find_dev_deep() returns with a net_device. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_l3_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index f8592160768..951b6cf086a 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1818,6 +1818,8 @@ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card, QETH_CARD_TEXT(card, 4, "frvaddr4"); netdev = __vlan_find_dev_deep(card->dev, vid); + if (!netdev) + return; in_dev = in_dev_get(netdev); if (!in_dev) return; @@ -1846,6 +1848,8 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card, QETH_CARD_TEXT(card, 4, "frvaddr6"); netdev = __vlan_find_dev_deep(card->dev, vid); + if (!netdev) + return; in6_dev = in6_dev_get(netdev); if (!in6_dev) return; From e49e6d039117405be1c4de6ac9cce196f9aea22e Mon Sep 17 00:00:00 2001 From: Greg KH Date: Thu, 12 Jul 2012 15:39:44 +0000 Subject: [PATCH 0580/2357] tg3: add device id of Apple Thunderbolt Ethernet device commit 02eca3f5f5e458c3a5d7b772bc8042ee2a4ebedf upstream. The Apple Thunderbolt ethernet device is already listed in the driver, but not hooked up in the MODULE_DEVICE_TABLE(). This fixes that and allows it to work properly. Signed-off-by: Greg Kroah-Hartman Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 1a1b29ff814..00d52acb73e 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -298,6 +298,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5720)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57762)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, From 4593e510277fec9fbe8708b1276301ead59470f0 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 Jul 2012 19:15:42 +0000 Subject: [PATCH 0581/2357] tg3: Fix Read DMA workaround for 5719 A0. commit 10ce95d6ef36c65df7dcd3b8fcf86913f8b298bd upstream. The workaround was mis-applied to all 5719 and 5720 chips. Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/tg3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 00d52acb73e..8506c54ee16 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8949,8 +8949,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || tg3_flag(tp, 57765_PLUS)) { val = tr32(TG3_RDMA_RSRVCTRL_REG); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) { val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK | TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK | TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK); From cbb9e89c375e167d012058c82fa69dd17ec17d4c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 Jul 2012 19:15:44 +0000 Subject: [PATCH 0582/2357] tg3: Fix race condition in tg3_get_stats64() commit 0f566b208b41918053b2e67399673aaec02dde5d upstream. Spinlock should be taken before checking for tp->hw_stats. Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/tg3.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 8506c54ee16..689d2a1935b 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -12255,10 +12255,12 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, { struct tg3 *tp = netdev_priv(dev); - if (!tp->hw_stats) + spin_lock_bh(&tp->lock); + if (!tp->hw_stats) { + spin_unlock_bh(&tp->lock); return &tp->net_stats_prev; + } - spin_lock_bh(&tp->lock); tg3_get_nstats(tp, stats); spin_unlock_bh(&tp->lock); From 5d11fb27d2f819d61df7e6dc36eb27374a92abe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 3 Jul 2012 14:05:41 +0200 Subject: [PATCH 0583/2357] drm/radeon: fix fence related segfault in CS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 93bf888c5c730605e3470f5d2381f296eda88d79 upstream. Don't return success if scheduling the IB fails, otherwise we end up with an oops in ttm_eu_fence_buffer_objects. Signed-off-by: Christian König Reviewed-by: Jerome Glisse Reviewed-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 2418cf6da1c..cf723c4297a 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -377,7 +377,7 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev, if (r) { DRM_ERROR("Failed to schedule IB !\n"); } - return 0; + return r; } static int radeon_bo_vm_update_pte(struct radeon_cs_parser *parser, From 47be757968b4344dd3e46f4e62c842cc201e830d Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 12 Jul 2012 18:23:05 -0400 Subject: [PATCH 0584/2357] drm/radeon: fix bo creation retry path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d1c7871ddb1f588b8eb35affd9ee1a3d5e11cd0c upstream. Retry label was at wrong place in function leading to memory leak. Signed-off-by: Jerome Glisse Reviewed-by: Michel Dänzer Reviewed-by: Christian König Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index df6a4dbd93f..80c6e8bad65 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -136,7 +136,6 @@ int radeon_bo_create(struct radeon_device *rdev, acc_size = ttm_bo_dma_acc_size(&rdev->mman.bdev, size, sizeof(struct radeon_bo)); -retry: bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL); if (bo == NULL) return -ENOMEM; @@ -150,6 +149,8 @@ int radeon_bo_create(struct radeon_device *rdev, bo->surface_reg = -1; INIT_LIST_HEAD(&bo->list); INIT_LIST_HEAD(&bo->va); + +retry: radeon_ttm_placement_from_domain(bo, domain); /* Kernel allocation are uninterruptible */ mutex_lock(&rdev->vram_mutex); From bec6d04dc715ad9fbc0d86abb3eea125109cf98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 17 Jul 2012 19:02:09 +0200 Subject: [PATCH 0585/2357] drm/radeon: Try harder to avoid HW cursor ending on a multiple of 128 columns. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f60ec4c7df043df81e62891ac45383d012afe0da upstream. This could previously fail if either of the enabled displays was using a horizontal resolution that is a multiple of 128, and only the leftmost column of the cursor was (supposed to be) visible at the right edge of that display. The solution is to move the cursor one pixel to the left in that case. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=33183 Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_cursor.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 42acc6449dd..711e95ad39b 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -262,8 +262,14 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, if (!(cursor_end & 0x7f)) w--; } - if (w <= 0) + if (w <= 0) { w = 1; + cursor_end = x - xorigin + w; + if (!(cursor_end & 0x7f)) { + x--; + WARN_ON_ONCE(x < 0); + } + } } } From 108c49a5cd65e2edc904212e6bd365db8d2f29e8 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 17 Jul 2012 17:17:16 -0400 Subject: [PATCH 0586/2357] drm/radeon: fix non revealent error message commit 8d1c702aa0b2c4b22b0742b72a1149d91690674b upstream. We want to print link status query failed only if it's an unexepected fail. If we query to see if we need link training it might be because there is nothing connected and thus link status query have the right to fail in that case. To avoid printing failure when it's expected, move the failure message to proper place. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_dp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index c57d85664e7..886b41f44a5 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -22,6 +22,7 @@ * * Authors: Dave Airlie * Alex Deucher + * Jerome Glisse */ #include "drmP.h" #include "radeon_drm.h" @@ -637,7 +638,6 @@ static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector, ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS, link_status, DP_LINK_STATUS_SIZE, 100); if (ret <= 0) { - DRM_ERROR("displayport link status failed\n"); return false; } @@ -816,8 +816,10 @@ static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info) else mdelay(dp_info->rd_interval * 4); - if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) + if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { + DRM_ERROR("displayport link status failed\n"); break; + } if (dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) { clock_recovery = true; @@ -879,8 +881,10 @@ static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info) else mdelay(dp_info->rd_interval * 4); - if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) + if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { + DRM_ERROR("displayport link status failed\n"); break; + } if (dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) { channel_eq = true; From b7ea4b8363e16630219674b9b8178dc07e7e6022 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 19 Jul 2012 17:15:56 -0400 Subject: [PATCH 0587/2357] drm/radeon: fix hotplug of DP to DVI|HDMI passive adapters (v2) commit 266dcba541a1ef7e5d82d9e67c67fde2910636e8 upstream. No need to retrain the link for passive adapters. v2: agd5f - no passive DP to VGA adapters, update comments - assign radeon_connector_atom_dig after we are sure we have a digital connector as analog connectors have different private data. - get new sink type before checking for retrain. No need to check if it's no longer a DP connection. Signed-off-by: Jerome Glisse Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 29 ++++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 3c2e7a000a2..e4e3e4c9b4b 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -64,14 +64,27 @@ void radeon_connector_hotplug(struct drm_connector *connector) /* just deal with DP (not eDP) here. */ if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { - int saved_dpms = connector->dpms; - - /* Only turn off the display it it's physically disconnected */ - if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); - else if (radeon_dp_needs_link_train(radeon_connector)) - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - connector->dpms = saved_dpms; + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + /* if existing sink type was not DP no need to retrain */ + if (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) + return; + + /* first get sink type as it may be reset after (un)plug */ + dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); + /* don't do anything if sink is not display port, i.e., + * passive dp->(dvi|hdmi) adaptor + */ + if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { + int saved_dpms = connector->dpms; + /* Only turn off the display if it's physically disconnected */ + if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + else if (radeon_dp_needs_link_train(radeon_connector)) + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + connector->dpms = saved_dpms; + } } } From de5b1c0849465404f94ffc0574e9ec9e8dc97570 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 19 Jul 2012 17:25:55 -0400 Subject: [PATCH 0588/2357] drm/radeon: on hotplug force link training to happen (v2) commit ca2ccde5e2f24a792caa4cca919fc5c6f65d1887 upstream. To have DP behave like VGA/DVI we need to retrain the link on hotplug. For this to happen we need to force link training to happen by setting connector dpms to off before asking it turning it on again. v2: agd5f - drop the dp_get_link_status() change in atombios_dp.c for now. We still need the dpms OFF change. Signed-off-by: Jerome Glisse Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index e4e3e4c9b4b..3fb7ca92206 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -79,10 +79,16 @@ void radeon_connector_hotplug(struct drm_connector *connector) if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { int saved_dpms = connector->dpms; /* Only turn off the display if it's physically disconnected */ - if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) + if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); - else if (radeon_dp_needs_link_train(radeon_connector)) + } else if (radeon_dp_needs_link_train(radeon_connector)) { + /* set it to OFF so that drm_helper_connector_dpms() + * won't return immediately since the current state + * is ON at this point. + */ + connector->dpms = DRM_MODE_DPMS_OFF; drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + } connector->dpms = saved_dpms; } } From b6e9ffcdb09fbf28665e025aa31fda702689786c Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 24 Jul 2012 17:06:11 -0400 Subject: [PATCH 0589/2357] drm/radeon: fix dpms on/off on trinity/aruba v2 commit fcedac670c3da0d17aaa5db1708694971e8024a9 upstream. The external encoder need to be setup again before enabling the transmiter. This seems to be only needed on some trinity/aruba to fix dpms on. v2: Add comment, only setup again on dce6 ie aruba or newer. Signed-off-by: Jerome Glisse Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_encoders.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 2d39f9977e0..a3ae788a2af 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1392,10 +1392,18 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_ON: /* some early dce3.2 boards have a bug in their transmitter control table */ if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730) || - ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) + ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { + if (ASIC_IS_DCE6(rdev)) { + /* It seems we need to call ATOM_ENCODER_CMD_SETUP again + * before reenabling encoder on DPMS ON, otherwise we never + * get picture + */ + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); + } atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - else + } else { atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); + } if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { atombios_set_edp_panel_power(connector, From 27cd8f51344dcf4799c7a092c1797402b833126a Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Wed, 25 Jul 2012 10:40:34 -0400 Subject: [PATCH 0590/2357] posix_types.h: Cleanup stale __NFDBITS and related definitions commit 8ded2bbc1845e19c771eb55209aab166ef011243 upstream. Recently, glibc made a change to suppress sign-conversion warnings in FD_SET (glibc commit ceb9e56b3d1). This uncovered an issue with the kernel's definition of __NFDBITS if applications #include after including . A build failure would be seen when passing the -Werror=sign-compare and -D_FORTIFY_SOURCE=2 flags to gcc. It was suggested that the kernel should either match the glibc definition of __NFDBITS or remove that entirely. The current in-kernel uses of __NFDBITS can be replaced with BITS_PER_LONG, and there are no uses of the related __FDELT and __FDMASK defines. Given that, we'll continue the cleanup that was started with commit 8b3d1cda4f5f ("posix_types: Remove fd_set macros") and drop the remaining unused macros. Additionally, linux/time.h has similar macros defined that expand to nothing so we'll remove those at the same time. Reported-by: Jeff Law Suggested-by: Linus Torvalds Signed-off-by: Josh Boyer [ .. and fix up whitespace as per akpm ] Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/kspd.c | 2 +- fs/exec.c | 2 +- fs/select.c | 10 +++++----- include/linux/posix_types.h | 18 +++--------------- include/linux/time.h | 8 -------- kernel/exit.c | 2 +- security/selinux/hooks.c | 2 +- 7 files changed, 12 insertions(+), 32 deletions(-) diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c index 84d0639e458..b77f56bbb47 100644 --- a/arch/mips/kernel/kspd.c +++ b/arch/mips/kernel/kspd.c @@ -323,7 +323,7 @@ static void sp_cleanup(void) fdt = files_fdtable(files); for (;;) { unsigned long set; - i = j * __NFDBITS; + i = j * BITS_PER_LONG; if (i >= fdt->max_fds) break; set = fdt->open_fds[j++]; diff --git a/fs/exec.c b/fs/exec.c index 29e5f840544..126e01cb243 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1024,7 +1024,7 @@ static void flush_old_files(struct files_struct * files) unsigned long set, i; j++; - i = j * __NFDBITS; + i = j * BITS_PER_LONG; fdt = files_fdtable(files); if (i >= fdt->max_fds) break; diff --git a/fs/select.c b/fs/select.c index 17d33d09fc1..0baa0a351a1 100644 --- a/fs/select.c +++ b/fs/select.c @@ -345,8 +345,8 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds) struct fdtable *fdt; /* handle last in-complete long-word first */ - set = ~(~0UL << (n & (__NFDBITS-1))); - n /= __NFDBITS; + set = ~(~0UL << (n & (BITS_PER_LONG-1))); + n /= BITS_PER_LONG; fdt = files_fdtable(current->files); open_fds = fdt->open_fds + n; max = 0; @@ -373,7 +373,7 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds) max++; set >>= 1; } while (set); - max += n * __NFDBITS; + max += n * BITS_PER_LONG; } return max; @@ -435,11 +435,11 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) in = *inp++; out = *outp++; ex = *exp++; all_bits = in | out | ex; if (all_bits == 0) { - i += __NFDBITS; + i += BITS_PER_LONG; continue; } - for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) { + for (j = 0; j < BITS_PER_LONG; ++j, ++i, bit <<= 1) { int fput_needed; if (i >= n) break; diff --git a/include/linux/posix_types.h b/include/linux/posix_types.h index f04c98cf44f..988f76e636e 100644 --- a/include/linux/posix_types.h +++ b/include/linux/posix_types.h @@ -15,26 +15,14 @@ */ /* - * Those macros may have been defined in . But we always - * use the ones here. + * This macro may have been defined in . But we always + * use the one here. */ -#undef __NFDBITS -#define __NFDBITS (8 * sizeof(unsigned long)) - #undef __FD_SETSIZE #define __FD_SETSIZE 1024 -#undef __FDSET_LONGS -#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS) - -#undef __FDELT -#define __FDELT(d) ((d) / __NFDBITS) - -#undef __FDMASK -#define __FDMASK(d) (1UL << ((d) % __NFDBITS)) - typedef struct { - unsigned long fds_bits [__FDSET_LONGS]; + unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(long))]; } __kernel_fd_set; /* Type of a signal handler. */ diff --git a/include/linux/time.h b/include/linux/time.h index 33a92ead4d8..8da51299a7d 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -258,14 +258,6 @@ static __always_inline void timespec_add_ns(struct timespec *a, u64 ns) #endif /* __KERNEL__ */ -#define NFDBITS __NFDBITS - -#define FD_SETSIZE __FD_SETSIZE -#define FD_SET(fd,fdsetp) __FD_SET(fd,fdsetp) -#define FD_CLR(fd,fdsetp) __FD_CLR(fd,fdsetp) -#define FD_ISSET(fd,fdsetp) __FD_ISSET(fd,fdsetp) -#define FD_ZERO(fdsetp) __FD_ZERO(fdsetp) - /* * Names of the interval timers, and structure * defining a timer setting: diff --git a/kernel/exit.c b/kernel/exit.c index 9d81012290e..bfbd8566969 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -471,7 +471,7 @@ static void close_files(struct files_struct * files) rcu_read_unlock(); for (;;) { unsigned long set; - i = j * __NFDBITS; + i = j * BITS_PER_LONG; if (i >= fdt->max_fds) break; set = fdt->open_fds[j++]; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d85b793c932..56262223190 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2162,7 +2162,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, int fd; j++; - i = j * __NFDBITS; + i = j * BITS_PER_LONG; fdt = files_fdtable(files); if (i >= fdt->max_fds) break; From b4ce163953a4baab2341ba42386904a7199d11af Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Fri, 27 Jul 2012 15:07:57 +0100 Subject: [PATCH 0591/2357] dm thin: reduce endio_hook pool size commit 7768ed33ccdc02801c4483fc5682dc66ace14aea upstream. Reduce the slab size used for the dm_thin_endio_hook mempool. Allocation has been seen to fail on machines with smaller amounts of memory due to fragmentation. lvm: page allocation failure. order:5, mode:0xd0 device-mapper: table: 253:38: thin-pool: Error creating pool's endio_hook mempool Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-thin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index e0a0ebe64c0..bbb29ccc24c 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -19,7 +19,7 @@ /* * Tunable constants */ -#define ENDIO_HOOK_POOL_SIZE 10240 +#define ENDIO_HOOK_POOL_SIZE 1024 #define DEFERRED_SET_SIZE 64 #define MAPPING_POOL_SIZE 1024 #define PRISON_CELLS 1024 From e73b09d8f258df200adb6383c77c38c31f6f4baa Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Fri, 27 Jul 2012 15:08:05 +0100 Subject: [PATCH 0592/2357] dm thin: fix memory leak in process_prepared_mapping error paths commit 905386f82d08f66726912f303f3e6605248c60a3 upstream. Fix memory leak in process_prepared_mapping by always freeing the dm_thin_new_mapping structs from the mapping_pool mempool on the error paths. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-thin.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index bbb29ccc24c..1555f0b2a2b 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -855,7 +855,7 @@ static void process_prepared_mapping(struct new_mapping *m) if (m->err) { cell_error(m->cell); - return; + goto out; } /* @@ -867,7 +867,7 @@ static void process_prepared_mapping(struct new_mapping *m) if (r) { DMERR("dm_thin_insert_block() failed"); cell_error(m->cell); - return; + goto out; } /* @@ -882,6 +882,7 @@ static void process_prepared_mapping(struct new_mapping *m) } else cell_defer(tc, m->cell, m->data_block); +out: list_del(&m->list); mempool_free(m, tc->pool->mapping_pool); } From a647f0df62cc4eaa0f42b85c71843ed90e150536 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Fri, 8 Jun 2012 02:02:30 +0300 Subject: [PATCH 0593/2357] pnfs-obj: Fix __r4w_get_page when offset is beyond i_size commit c999ff68029ebd0f56ccae75444f640f6d5a27d2 upstream. It is very common for the end of the file to be unaligned on stripe size. But since we know it's beyond file's end then the XOR should be preformed with all zeros. Old code used to just read zeros out of the OSD devices, which is a great waist. But what scares me more about this situation is that, we now have pages attached to the file's mapping that are beyond i_size. I don't like the kind of bugs this calls for. Fix both birds, by returning a global zero_page, if offset is beyond i_size. TODO: Change the API to ->__r4w_get_page() so a NULL can be returned without being considered as error, since XOR API treats NULL entries as zero_pages. [Bug since 3.2. Should apply the same way to all Kernels since] Signed-off-by: Boaz Harrosh [bwh: Backported to 3.2: adjust for lack of wdata->header] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- fs/nfs/objlayout/objio_osd.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index 42ac1bf6fcc..1afe74c42c8 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c @@ -487,8 +487,16 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) struct objio_state *objios = priv; struct nfs_write_data *wdata = objios->oir.rpcdata; pgoff_t index = offset / PAGE_SIZE; - struct page *page = find_get_page(wdata->inode->i_mapping, index); + struct page *page; + loff_t i_size = i_size_read(wdata->inode); + if (offset >= i_size) { + *uptodate = true; + dprintk("%s: g_zero_page index=0x%lx\n", __func__, index); + return ZERO_PAGE(0); + } + + page = find_get_page(wdata->inode->i_mapping, index); if (!page) { page = find_or_create_page(wdata->inode->i_mapping, index, GFP_NOFS); @@ -509,8 +517,10 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) static void __r4w_put_page(void *priv, struct page *page) { - dprintk("%s: index=0x%lx\n", __func__, page->index); - page_cache_release(page); + dprintk("%s: index=0x%lx\n", __func__, + (page == ZERO_PAGE(0)) ? -1UL : page->index); + if (ZERO_PAGE(0) != page) + page_cache_release(page); return; } From f0f5dcc0020b78983061a2a674491f4eaa03e386 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 5 Jun 2012 16:52:06 -0400 Subject: [PATCH 0594/2357] nfsd4: our filesystems are normally case sensitive commit 2930d381d22b9c56f40dd4c63a8fa59719ca2c3c upstream. Actually, xfs and jfs can optionally be case insensitive; we'll handle that case in later patches. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 74c00bc92b9..283d15e9f46 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2233,7 +2233,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { if ((buflen -= 4) < 0) goto out_resource; - WRITE32(1); + WRITE32(0); } if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { if ((buflen -= 4) < 0) From 032da6abbc34272959c790941ce8705337061dbf Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 23 Jul 2012 13:58:51 -0400 Subject: [PATCH 0595/2357] nfs: skip commit in releasepage if we're freeing memory for fs-related reasons commit 5cf02d09b50b1ee1c2d536c9cf64af5a7d433f56 upstream. We've had some reports of a deadlock where rpciod ends up with a stack trace like this: PID: 2507 TASK: ffff88103691ab40 CPU: 14 COMMAND: "rpciod/14" #0 [ffff8810343bf2f0] schedule at ffffffff814dabd9 #1 [ffff8810343bf3b8] nfs_wait_bit_killable at ffffffffa038fc04 [nfs] #2 [ffff8810343bf3c8] __wait_on_bit at ffffffff814dbc2f #3 [ffff8810343bf418] out_of_line_wait_on_bit at ffffffff814dbcd8 #4 [ffff8810343bf488] nfs_commit_inode at ffffffffa039e0c1 [nfs] #5 [ffff8810343bf4f8] nfs_release_page at ffffffffa038bef6 [nfs] #6 [ffff8810343bf528] try_to_release_page at ffffffff8110c670 #7 [ffff8810343bf538] shrink_page_list.clone.0 at ffffffff81126271 #8 [ffff8810343bf668] shrink_inactive_list at ffffffff81126638 #9 [ffff8810343bf818] shrink_zone at ffffffff8112788f #10 [ffff8810343bf8c8] do_try_to_free_pages at ffffffff81127b1e #11 [ffff8810343bf958] try_to_free_pages at ffffffff8112812f #12 [ffff8810343bfa08] __alloc_pages_nodemask at ffffffff8111fdad #13 [ffff8810343bfb28] kmem_getpages at ffffffff81159942 #14 [ffff8810343bfb58] fallback_alloc at ffffffff8115a55a #15 [ffff8810343bfbd8] ____cache_alloc_node at ffffffff8115a2d9 #16 [ffff8810343bfc38] kmem_cache_alloc at ffffffff8115b09b #17 [ffff8810343bfc78] sk_prot_alloc at ffffffff81411808 #18 [ffff8810343bfcb8] sk_alloc at ffffffff8141197c #19 [ffff8810343bfce8] inet_create at ffffffff81483ba6 #20 [ffff8810343bfd38] __sock_create at ffffffff8140b4a7 #21 [ffff8810343bfd98] xs_create_sock at ffffffffa01f649b [sunrpc] #22 [ffff8810343bfdd8] xs_tcp_setup_socket at ffffffffa01f6965 [sunrpc] #23 [ffff8810343bfe38] worker_thread at ffffffff810887d0 #24 [ffff8810343bfee8] kthread at ffffffff8108dd96 #25 [ffff8810343bff48] kernel_thread at ffffffff8100c1ca rpciod is trying to allocate memory for a new socket to talk to the server. The VM ends up calling ->releasepage to get more memory, and it tries to do a blocking commit. That commit can't succeed however without a connected socket, so we deadlock. Fix this by setting PF_FSTRANS on the workqueue task prior to doing the socket allocation, and having nfs_release_page check for that flag when deciding whether to do a commit call. Also, set PF_FSTRANS unconditionally in rpc_async_schedule since that function can also do allocations sometimes. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/file.c | 7 +++++-- net/sunrpc/sched.c | 2 ++ net/sunrpc/xprtrdma/transport.c | 3 ++- net/sunrpc/xprtsock.c | 10 ++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index aa9b709fd32..f0f439dfeaa 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -451,8 +451,11 @@ static int nfs_release_page(struct page *page, gfp_t gfp) dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); - /* Only do I/O if gfp is a superset of GFP_KERNEL */ - if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) { + /* Only do I/O if gfp is a superset of GFP_KERNEL, and we're not + * doing this memory reclaim for a fs-related allocation. + */ + if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL && + !(current->flags & PF_FSTRANS)) { int how = FLUSH_SYNC; /* Don't let kswapd deadlock waiting for OOM RPC calls */ diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 994cfea2bad..eda32ae7dec 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -790,7 +790,9 @@ void rpc_execute(struct rpc_task *task) static void rpc_async_schedule(struct work_struct *work) { + current->flags |= PF_FSTRANS; __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); + current->flags &= ~PF_FSTRANS; } /** diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index b446e100286..06cdbff79e4 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -200,6 +200,7 @@ xprt_rdma_connect_worker(struct work_struct *work) int rc = 0; if (!xprt->shutdown) { + current->flags |= PF_FSTRANS; xprt_clear_connected(xprt); dprintk("RPC: %s: %sconnect\n", __func__, @@ -212,10 +213,10 @@ xprt_rdma_connect_worker(struct work_struct *work) out: xprt_wake_pending_tasks(xprt, rc); - out_clear: dprintk("RPC: %s: exit\n", __func__); xprt_clear_connecting(xprt); + current->flags &= ~PF_FSTRANS; } /* diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 890b03f8d87..b88c6bf657b 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1895,6 +1895,8 @@ static void xs_local_setup_socket(struct work_struct *work) if (xprt->shutdown) goto out; + current->flags |= PF_FSTRANS; + clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); status = __sock_create(xprt->xprt_net, AF_LOCAL, SOCK_STREAM, 0, &sock, 1); @@ -1928,6 +1930,7 @@ static void xs_local_setup_socket(struct work_struct *work) out: xprt_clear_connecting(xprt); xprt_wake_pending_tasks(xprt, status); + current->flags &= ~PF_FSTRANS; } static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) @@ -1970,6 +1973,8 @@ static void xs_udp_setup_socket(struct work_struct *work) if (xprt->shutdown) goto out; + current->flags |= PF_FSTRANS; + /* Start by resetting any existing state */ xs_reset_transport(transport); sock = xs_create_sock(xprt, transport, @@ -1988,6 +1993,7 @@ static void xs_udp_setup_socket(struct work_struct *work) out: xprt_clear_connecting(xprt); xprt_wake_pending_tasks(xprt, status); + current->flags &= ~PF_FSTRANS; } /* @@ -2113,6 +2119,8 @@ static void xs_tcp_setup_socket(struct work_struct *work) if (xprt->shutdown) goto out; + current->flags |= PF_FSTRANS; + if (!sock) { clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); sock = xs_create_sock(xprt, transport, @@ -2162,6 +2170,7 @@ static void xs_tcp_setup_socket(struct work_struct *work) case -EINPROGRESS: case -EALREADY: xprt_clear_connecting(xprt); + current->flags &= ~PF_FSTRANS; return; case -EINVAL: /* Happens, for instance, if the user specified a link @@ -2174,6 +2183,7 @@ static void xs_tcp_setup_socket(struct work_struct *work) out: xprt_clear_connecting(xprt); xprt_wake_pending_tasks(xprt, status); + current->flags &= ~PF_FSTRANS; } /** From 4d71d5a6b6931f82fa9db44214019839a0ebbb4a Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 25 Jul 2012 16:53:36 +0100 Subject: [PATCH 0596/2357] NFS: Fix a number of bugs in the idmapper commit a427b9ec4eda8cd6e641ea24541d30b641fc3140 upstream. Fix a number of bugs in the NFS idmapper code: (1) Only registered key types can be passed to the core keys code, so register the legacy idmapper key type. This is a requirement because the unregister function cleans up keys belonging to that key type so that there aren't dangling pointers to the module left behind - including the key->type pointer. (2) Rename the legacy key type. You can't have two key types with the same name, and (1) would otherwise require that. (3) complete_request_key() must be called in the error path of nfs_idmap_legacy_upcall(). (4) There is one idmap struct for each nfs_client struct. This means that idmap->idmap_key_cons is shared without the use of a lock. This is a problem because key_instantiate_and_link() - as called indirectly by idmap_pipe_downcall() - releases anyone waiting for the key to be instantiated. What happens is that idmap_pipe_downcall() running in the rpc.idmapd thread, releases the NFS filesystem in whatever thread that is running in to continue. This may then make another idmapper call, overwriting idmap_key_cons before idmap_pipe_downcall() gets the chance to call complete_request_key(). I *think* that reading idmap_key_cons only once, before key_instantiate_and_link() is called, and then caching the result in a variable is sufficient. Bug (4) is the cause of: BUG: unable to handle kernel NULL pointer dereference at (null) IP: [< (null)>] (null) PGD 0 Oops: 0010 [#1] SMP CPU 1 Modules linked in: ppdev parport_pc lp parport ip6table_filter ip6_tables ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack nfs fscache xt_CHECKSUM auth_rpcgss iptable_mangle nfs_acl bridge stp llc lockd be2iscsi iscsi_boot_sysfs bnx2i cnic uio cxgb4i cxgb4 cxgb3i libcxgbi cxgb3 mdio ib_iser rdma_cm ib_cm iw_cm ib_sa ib_mad ib_core ib_addr iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi snd_hda_codec_realtek snd_usb_audio snd_hda_intel snd_hda_codec snd_seq snd_pcm snd_hwdep snd_usbmidi_lib snd_rawmidi snd_timer uvcvideo videobuf2_core videodev media videobuf2_vmalloc snd_seq_device videobuf2_memops e1000e vhost_net iTCO_wdt joydev coretemp snd soundcore macvtap macvlan i2c_i801 snd_page_alloc tun iTCO_vendor_support microcode kvm_intel kvm sunrpc hid_logitech_dj usb_storage i915 drm_kms_helper drm i2c_algo_bit i2c_core video [last unloaded: scsi_wait_scan] Pid: 1229, comm: rpc.idmapd Not tainted 3.4.2-1.fc16.x86_64 #1 Gateway DX4710-UB801A/G33M05G1 RIP: 0010:[<0000000000000000>] [< (null)>] (null) RSP: 0018:ffff8801a3645d40 EFLAGS: 00010246 RAX: ffff880077707e30 RBX: ffff880077707f50 RCX: ffff8801a18ccd80 RDX: 0000000000000006 RSI: ffff8801a3645e75 RDI: ffff880077707f50 RBP: ffff8801a3645d88 R08: ffff8801a430f9c0 R09: ffff8801a3645db0 R10: 000000000000000a R11: 0000000000000246 R12: ffff8801a18ccd80 R13: ffff8801a3645e75 R14: ffff8801a430f9c0 R15: 0000000000000006 FS: 00007fb6fb51a700(0000) GS:ffff8801afc80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000001a49b0000 CR4: 00000000000027e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process rpc.idmapd (pid: 1229, threadinfo ffff8801a3644000, task ffff8801a3bf9710) Stack: ffffffff81260878 ffff8801a3645db0 ffff8801a3645db0 ffff880077707a90 ffff880077707f50 ffff8801a18ccd80 0000000000000006 ffff8801a3645e75 ffff8801a430f9c0 ffff8801a3645dd8 ffffffff81260983 ffff8801a3645de8 Call Trace: [] ? __key_instantiate_and_link+0x58/0x100 [] key_instantiate_and_link+0x63/0xa0 [] idmap_pipe_downcall+0x1cb/0x1e0 [nfs] [] rpc_pipe_write+0x67/0x90 [sunrpc] [] vfs_write+0xb3/0x180 [] sys_write+0x4a/0x90 [] system_call_fastpath+0x16/0x1b Code: Bad RIP value. RIP [< (null)>] (null) RSP CR2: 0000000000000000 Signed-off-by: David Howells Reviewed-by: Steve Dickson Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/idmap.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 93aa3a4c4b0..929ba011172 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -205,12 +205,18 @@ static int nfs_idmap_init_keyring(void) if (ret < 0) goto failed_put_key; + ret = register_key_type(&key_type_id_resolver_legacy); + if (ret < 0) + goto failed_reg_legacy; + set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); cred->thread_keyring = keyring; cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; id_resolver_cache = cred; return 0; +failed_reg_legacy: + unregister_key_type(&key_type_id_resolver); failed_put_key: key_put(keyring); failed_put_cred: @@ -222,6 +228,7 @@ static void nfs_idmap_quit_keyring(void) { key_revoke(id_resolver_cache->thread_keyring); unregister_key_type(&key_type_id_resolver); + unregister_key_type(&key_type_id_resolver_legacy); put_cred(id_resolver_cache); } @@ -385,7 +392,7 @@ static const struct rpc_pipe_ops idmap_upcall_ops = { }; static struct key_type key_type_id_resolver_legacy = { - .name = "id_resolver", + .name = "id_legacy", .instantiate = user_instantiate, .match = user_match, .revoke = user_revoke, @@ -658,6 +665,7 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, if (ret < 0) goto out2; + BUG_ON(idmap->idmap_key_cons != NULL); idmap->idmap_key_cons = cons; ret = rpc_queue_upcall(idmap->idmap_pipe, msg); @@ -671,8 +679,7 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, out1: kfree(msg); out0: - key_revoke(cons->key); - key_revoke(cons->authkey); + complete_request_key(cons, ret); return ret; } @@ -706,11 +713,18 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) { struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); struct idmap *idmap = (struct idmap *)rpci->private; - struct key_construction *cons = idmap->idmap_key_cons; + struct key_construction *cons; struct idmap_msg im; size_t namelen_in; int ret; + /* If instantiation is successful, anyone waiting for key construction + * will have been woken up and someone else may now have used + * idmap_key_cons - so after this point we may no longer touch it. + */ + cons = ACCESS_ONCE(idmap->idmap_key_cons); + idmap->idmap_key_cons = NULL; + if (mlen != sizeof(im)) { ret = -ENOSPC; goto out; @@ -723,7 +737,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) if (!(im.im_status & IDMAP_STATUS_SUCCESS)) { ret = mlen; - complete_request_key(idmap->idmap_key_cons, -ENOKEY); + complete_request_key(cons, -ENOKEY); goto out_incomplete; } @@ -740,7 +754,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) } out: - complete_request_key(idmap->idmap_key_cons, ret); + complete_request_key(cons, ret); out_incomplete: return ret; } From 66b68d2374b0c251224c28c69fc25eeef343e122 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 4 Jun 2012 12:00:31 +0200 Subject: [PATCH 0597/2357] nouveau: Fix alignment requirements on src and dst addresses commit ce806a30470bcd846d148bf39d46de3ad7748228 upstream. Linear copy works by adding the offset to the buffer address, which may end up not being 16-byte aligned. Some tests I've written for prime_pcopy show that the engine allows this correctly, so the restriction on lowest 4 bits of address can be lifted safely. The comments added were by envyas, I think because I used a newer version. Signed-off-by: Maarten Lankhorst Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nva3_copy.fuc | 4 +- drivers/gpu/drm/nouveau/nva3_copy.fuc.h | 94 +++++++++++++++++++++++-- drivers/gpu/drm/nouveau/nvc0_copy.fuc.h | 87 +++++++++++++++++++++-- 3 files changed, 175 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc b/drivers/gpu/drm/nouveau/nva3_copy.fuc index abc36626fef..219850d5328 100644 --- a/drivers/gpu/drm/nouveau/nva3_copy.fuc +++ b/drivers/gpu/drm/nouveau/nva3_copy.fuc @@ -119,9 +119,9 @@ dispatch_dma: // mthd 0x030c-0x0340, various stuff .b16 0xc3 14 .b32 #ctx_src_address_high ~0x000000ff -.b32 #ctx_src_address_low ~0xfffffff0 +.b32 #ctx_src_address_low ~0xffffffff .b32 #ctx_dst_address_high ~0x000000ff -.b32 #ctx_dst_address_low ~0xfffffff0 +.b32 #ctx_dst_address_low ~0xffffffff .b32 #ctx_src_pitch ~0x0007ffff .b32 #ctx_dst_pitch ~0x0007ffff .b32 #ctx_xcnt ~0x0000ffff diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc.h b/drivers/gpu/drm/nouveau/nva3_copy.fuc.h index 1f33fbdc00b..37d6de3c9d6 100644 --- a/drivers/gpu/drm/nouveau/nva3_copy.fuc.h +++ b/drivers/gpu/drm/nouveau/nva3_copy.fuc.h @@ -1,37 +1,72 @@ -uint32_t nva3_pcopy_data[] = { +u32 nva3_pcopy_data[] = { +/* 0x0000: ctx_object */ 0x00000000, +/* 0x0004: ctx_dma */ +/* 0x0004: ctx_dma_query */ 0x00000000, +/* 0x0008: ctx_dma_src */ 0x00000000, +/* 0x000c: ctx_dma_dst */ 0x00000000, +/* 0x0010: ctx_query_address_high */ 0x00000000, +/* 0x0014: ctx_query_address_low */ 0x00000000, +/* 0x0018: ctx_query_counter */ 0x00000000, +/* 0x001c: ctx_src_address_high */ 0x00000000, +/* 0x0020: ctx_src_address_low */ 0x00000000, +/* 0x0024: ctx_src_pitch */ 0x00000000, +/* 0x0028: ctx_src_tile_mode */ 0x00000000, +/* 0x002c: ctx_src_xsize */ 0x00000000, +/* 0x0030: ctx_src_ysize */ 0x00000000, +/* 0x0034: ctx_src_zsize */ 0x00000000, +/* 0x0038: ctx_src_zoff */ 0x00000000, +/* 0x003c: ctx_src_xoff */ 0x00000000, +/* 0x0040: ctx_src_yoff */ 0x00000000, +/* 0x0044: ctx_src_cpp */ 0x00000000, +/* 0x0048: ctx_dst_address_high */ 0x00000000, +/* 0x004c: ctx_dst_address_low */ 0x00000000, +/* 0x0050: ctx_dst_pitch */ 0x00000000, +/* 0x0054: ctx_dst_tile_mode */ 0x00000000, +/* 0x0058: ctx_dst_xsize */ 0x00000000, +/* 0x005c: ctx_dst_ysize */ 0x00000000, +/* 0x0060: ctx_dst_zsize */ 0x00000000, +/* 0x0064: ctx_dst_zoff */ 0x00000000, +/* 0x0068: ctx_dst_xoff */ 0x00000000, +/* 0x006c: ctx_dst_yoff */ 0x00000000, +/* 0x0070: ctx_dst_cpp */ 0x00000000, +/* 0x0074: ctx_format */ 0x00000000, +/* 0x0078: ctx_swz_const0 */ 0x00000000, +/* 0x007c: ctx_swz_const1 */ 0x00000000, +/* 0x0080: ctx_xcnt */ 0x00000000, +/* 0x0084: ctx_ycnt */ 0x00000000, 0x00000000, 0x00000000, @@ -63,6 +98,7 @@ uint32_t nva3_pcopy_data[] = { 0x00000000, 0x00000000, 0x00000000, +/* 0x0100: dispatch_table */ 0x00010000, 0x00000000, 0x00000000, @@ -73,6 +109,7 @@ uint32_t nva3_pcopy_data[] = { 0x00010162, 0x00000000, 0x00030060, +/* 0x0128: dispatch_dma */ 0x00010170, 0x00000000, 0x00010170, @@ -118,11 +155,11 @@ uint32_t nva3_pcopy_data[] = { 0x0000001c, 0xffffff00, 0x00000020, - 0x0000000f, + 0x00000000, 0x00000048, 0xffffff00, 0x0000004c, - 0x0000000f, + 0x00000000, 0x00000024, 0xfff80000, 0x00000050, @@ -146,7 +183,8 @@ uint32_t nva3_pcopy_data[] = { 0x00000800, }; -uint32_t nva3_pcopy_code[] = { +u32 nva3_pcopy_code[] = { +/* 0x0000: main */ 0x04fe04bd, 0x3517f000, 0xf10010fe, @@ -158,23 +196,31 @@ uint32_t nva3_pcopy_code[] = { 0x17f11031, 0x27f01200, 0x0012d003, +/* 0x002f: spin */ 0xf40031f4, 0x0ef40028, +/* 0x0035: ih */ 0x8001cffd, 0xf40812c4, 0x21f4060b, +/* 0x0041: ih_no_chsw */ 0x0412c472, 0xf4060bf4, +/* 0x004a: ih_no_cmd */ 0x11c4c321, 0x4001d00c, +/* 0x0052: swctx */ 0x47f101f8, 0x4bfe7700, 0x0007fe00, 0xf00204b9, 0x01f40643, 0x0604fa09, +/* 0x006b: swctx_load */ 0xfa060ef4, +/* 0x006e: swctx_done */ 0x03f80504, +/* 0x0072: chsw */ 0x27f100f8, 0x23cf1400, 0x1e3fc800, @@ -183,18 +229,22 @@ uint32_t nva3_pcopy_code[] = { 0x1e3af052, 0xf00023d0, 0x24d00147, +/* 0x0093: chsw_no_unload */ 0xcf00f880, 0x3dc84023, 0x220bf41e, 0xf40131f4, 0x57f05221, 0x0367f004, +/* 0x00a8: chsw_load_ctx_dma */ 0xa07856bc, 0xb6018068, 0x87d00884, 0x0162b600, +/* 0x00bb: chsw_finish_load */ 0xf0f018f4, 0x23d00237, +/* 0x00c3: dispatch */ 0xf100f880, 0xcf190037, 0x33cf4032, @@ -202,6 +252,7 @@ uint32_t nva3_pcopy_code[] = { 0x1024b607, 0x010057f1, 0x74bd64bd, +/* 0x00dc: dispatch_loop */ 0x58005658, 0x50b60157, 0x0446b804, @@ -211,6 +262,7 @@ uint32_t nva3_pcopy_code[] = { 0xb60276bb, 0x57bb0374, 0xdf0ef400, +/* 0x0100: dispatch_valid_mthd */ 0xb60246bb, 0x45bb0344, 0x01459800, @@ -220,31 +272,41 @@ uint32_t nva3_pcopy_code[] = { 0xb0014658, 0x1bf40064, 0x00538009, +/* 0x0127: dispatch_cmd */ 0xf4300ef4, 0x55f90132, 0xf40c01f4, +/* 0x0132: dispatch_invalid_bitfield */ 0x25f0250e, +/* 0x0135: dispatch_illegal_mthd */ 0x0125f002, +/* 0x0138: dispatch_error */ 0x100047f1, 0xd00042d0, 0x27f04043, 0x0002d040, +/* 0x0148: hostirq_wait */ 0xf08002cf, 0x24b04024, 0xf71bf400, +/* 0x0154: dispatch_done */ 0x1d0027f1, 0xd00137f0, 0x00f80023, +/* 0x0160: cmd_nop */ +/* 0x0162: cmd_pm_trigger */ 0x27f100f8, 0x34bd2200, 0xd00233f0, 0x00f80023, +/* 0x0170: cmd_dma */ 0x012842b7, 0xf00145b6, 0x43801e39, 0x0040b701, 0x0644b606, 0xf80043d0, +/* 0x0189: cmd_exec_set_format */ 0xf030f400, 0xb00001b0, 0x01b00101, @@ -256,20 +318,26 @@ uint32_t nva3_pcopy_code[] = { 0x70b63847, 0x0232f401, 0x94bd84bd, +/* 0x01b4: ncomp_loop */ 0xb60f4ac4, 0xb4bd0445, +/* 0x01bc: bpc_loop */ 0xf404a430, 0xa5ff0f18, 0x00cbbbc0, 0xf40231f4, +/* 0x01ce: cmp_c0 */ 0x1bf4220e, 0x10c7f00c, 0xf400cbbb, +/* 0x01da: cmp_c1 */ 0xa430160e, 0x0c18f406, 0xbb14c7f0, 0x0ef400cb, +/* 0x01e9: cmp_zero */ 0x80c7f107, +/* 0x01ed: bpc_next */ 0x01c83800, 0xb60180b6, 0xb5b801b0, @@ -280,6 +348,7 @@ uint32_t nva3_pcopy_code[] = { 0x98110680, 0x68fd2008, 0x0502f400, +/* 0x0216: dst_xcnt */ 0x75fd64bd, 0x1c078000, 0xf10078fd, @@ -304,6 +373,7 @@ uint32_t nva3_pcopy_code[] = { 0x980056d0, 0x56d01f06, 0x1030f440, +/* 0x0276: cmd_exec_set_surface_tiled */ 0x579800f8, 0x6879c70a, 0xb66478c7, @@ -311,9 +381,11 @@ uint32_t nva3_pcopy_code[] = { 0x0e76b060, 0xf0091bf4, 0x0ef40477, +/* 0x0291: xtile64 */ 0x027cf00f, 0xfd1170b6, 0x77f00947, +/* 0x029d: xtileok */ 0x0f5a9806, 0xfd115b98, 0xb7f000ab, @@ -371,6 +443,7 @@ uint32_t nva3_pcopy_code[] = { 0x67d00600, 0x0060b700, 0x0068d004, +/* 0x0382: cmd_exec_set_surface_linear */ 0x6cf000f8, 0x0260b702, 0x0864b602, @@ -381,13 +454,16 @@ uint32_t nva3_pcopy_code[] = { 0xb70067d0, 0x98040060, 0x67d00957, +/* 0x03ab: cmd_exec_wait */ 0xf900f800, 0xf110f900, 0xb6080007, +/* 0x03b6: loop */ 0x01cf0604, 0x0114f000, 0xfcfa1bf4, 0xf800fc10, +/* 0x03c5: cmd_exec_query */ 0x0d34c800, 0xf5701bf4, 0xf103ab21, @@ -417,6 +493,7 @@ uint32_t nva3_pcopy_code[] = { 0x47f10153, 0x44b60800, 0x0045d006, +/* 0x0438: query_counter */ 0x03ab21f5, 0x080c47f1, 0x980644b6, @@ -439,11 +516,13 @@ uint32_t nva3_pcopy_code[] = { 0x47f10153, 0x44b60800, 0x0045d006, +/* 0x0492: cmd_exec */ 0x21f500f8, 0x3fc803ab, 0x0e0bf400, 0x018921f5, 0x020047f1, +/* 0x04a7: cmd_exec_no_format */ 0xf11e0ef4, 0xb6081067, 0x77f00664, @@ -451,19 +530,24 @@ uint32_t nva3_pcopy_code[] = { 0x981c0780, 0x67d02007, 0x4067d000, +/* 0x04c2: cmd_exec_init_src_surface */ 0x32f444bd, 0xc854bd02, 0x0bf4043f, 0x8221f50a, 0x0a0ef403, +/* 0x04d4: src_tiled */ 0x027621f5, +/* 0x04db: cmd_exec_init_dst_surface */ 0xf40749f0, 0x57f00231, 0x083fc82c, 0xf50a0bf4, 0xf4038221, +/* 0x04ee: dst_tiled */ 0x21f50a0e, 0x49f00276, +/* 0x04f5: cmd_exec_kick */ 0x0057f108, 0x0654b608, 0xd0210698, @@ -473,6 +557,8 @@ uint32_t nva3_pcopy_code[] = { 0xc80054d0, 0x0bf40c3f, 0xc521f507, +/* 0x0519: cmd_exec_done */ +/* 0x051b: cmd_wrcache_flush */ 0xf100f803, 0xbd220027, 0x0133f034, diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h b/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h index a8d17458ced..cd879f31bb3 100644 --- a/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h +++ b/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h @@ -1,34 +1,65 @@ -uint32_t nvc0_pcopy_data[] = { +u32 nvc0_pcopy_data[] = { +/* 0x0000: ctx_object */ 0x00000000, +/* 0x0004: ctx_query_address_high */ 0x00000000, +/* 0x0008: ctx_query_address_low */ 0x00000000, +/* 0x000c: ctx_query_counter */ 0x00000000, +/* 0x0010: ctx_src_address_high */ 0x00000000, +/* 0x0014: ctx_src_address_low */ 0x00000000, +/* 0x0018: ctx_src_pitch */ 0x00000000, +/* 0x001c: ctx_src_tile_mode */ 0x00000000, +/* 0x0020: ctx_src_xsize */ 0x00000000, +/* 0x0024: ctx_src_ysize */ 0x00000000, +/* 0x0028: ctx_src_zsize */ 0x00000000, +/* 0x002c: ctx_src_zoff */ 0x00000000, +/* 0x0030: ctx_src_xoff */ 0x00000000, +/* 0x0034: ctx_src_yoff */ 0x00000000, +/* 0x0038: ctx_src_cpp */ 0x00000000, +/* 0x003c: ctx_dst_address_high */ 0x00000000, +/* 0x0040: ctx_dst_address_low */ 0x00000000, +/* 0x0044: ctx_dst_pitch */ 0x00000000, +/* 0x0048: ctx_dst_tile_mode */ 0x00000000, +/* 0x004c: ctx_dst_xsize */ 0x00000000, +/* 0x0050: ctx_dst_ysize */ 0x00000000, +/* 0x0054: ctx_dst_zsize */ 0x00000000, +/* 0x0058: ctx_dst_zoff */ 0x00000000, +/* 0x005c: ctx_dst_xoff */ 0x00000000, +/* 0x0060: ctx_dst_yoff */ 0x00000000, +/* 0x0064: ctx_dst_cpp */ 0x00000000, +/* 0x0068: ctx_format */ 0x00000000, +/* 0x006c: ctx_swz_const0 */ 0x00000000, +/* 0x0070: ctx_swz_const1 */ 0x00000000, +/* 0x0074: ctx_xcnt */ 0x00000000, +/* 0x0078: ctx_ycnt */ 0x00000000, 0x00000000, 0x00000000, @@ -63,6 +94,7 @@ uint32_t nvc0_pcopy_data[] = { 0x00000000, 0x00000000, 0x00000000, +/* 0x0100: dispatch_table */ 0x00010000, 0x00000000, 0x00000000, @@ -111,11 +143,11 @@ uint32_t nvc0_pcopy_data[] = { 0x00000010, 0xffffff00, 0x00000014, - 0x0000000f, + 0x00000000, 0x0000003c, 0xffffff00, 0x00000040, - 0x0000000f, + 0x00000000, 0x00000018, 0xfff80000, 0x00000044, @@ -139,7 +171,8 @@ uint32_t nvc0_pcopy_data[] = { 0x00000800, }; -uint32_t nvc0_pcopy_code[] = { +u32 nvc0_pcopy_code[] = { +/* 0x0000: main */ 0x04fe04bd, 0x3517f000, 0xf10010fe, @@ -151,15 +184,20 @@ uint32_t nvc0_pcopy_code[] = { 0x17f11031, 0x27f01200, 0x0012d003, +/* 0x002f: spin */ 0xf40031f4, 0x0ef40028, +/* 0x0035: ih */ 0x8001cffd, 0xf40812c4, 0x21f4060b, +/* 0x0041: ih_no_chsw */ 0x0412c4ca, 0xf5070bf4, +/* 0x004b: ih_no_cmd */ 0xc4010221, 0x01d00c11, +/* 0x0053: swctx */ 0xf101f840, 0xfe770047, 0x47f1004b, @@ -188,8 +226,11 @@ uint32_t nvc0_pcopy_code[] = { 0xf00204b9, 0x01f40643, 0x0604fa09, +/* 0x00c3: swctx_load */ 0xfa060ef4, +/* 0x00c6: swctx_done */ 0x03f80504, +/* 0x00ca: chsw */ 0x27f100f8, 0x23cf1400, 0x1e3fc800, @@ -198,18 +239,22 @@ uint32_t nvc0_pcopy_code[] = { 0x1e3af053, 0xf00023d0, 0x24d00147, +/* 0x00eb: chsw_no_unload */ 0xcf00f880, 0x3dc84023, 0x090bf41e, 0xf40131f4, +/* 0x00fa: chsw_finish_load */ 0x37f05321, 0x8023d002, +/* 0x0102: dispatch */ 0x37f100f8, 0x32cf1900, 0x0033cf40, 0x07ff24e4, 0xf11024b6, 0xbd010057, +/* 0x011b: dispatch_loop */ 0x5874bd64, 0x57580056, 0x0450b601, @@ -219,6 +264,7 @@ uint32_t nvc0_pcopy_code[] = { 0xbb0f08f4, 0x74b60276, 0x0057bb03, +/* 0x013f: dispatch_valid_mthd */ 0xbbdf0ef4, 0x44b60246, 0x0045bb03, @@ -229,24 +275,33 @@ uint32_t nvc0_pcopy_code[] = { 0x64b00146, 0x091bf400, 0xf4005380, +/* 0x0166: dispatch_cmd */ 0x32f4300e, 0xf455f901, 0x0ef40c01, +/* 0x0171: dispatch_invalid_bitfield */ 0x0225f025, +/* 0x0174: dispatch_illegal_mthd */ +/* 0x0177: dispatch_error */ 0xf10125f0, 0xd0100047, 0x43d00042, 0x4027f040, +/* 0x0187: hostirq_wait */ 0xcf0002d0, 0x24f08002, 0x0024b040, +/* 0x0193: dispatch_done */ 0xf1f71bf4, 0xf01d0027, 0x23d00137, +/* 0x019f: cmd_nop */ 0xf800f800, +/* 0x01a1: cmd_pm_trigger */ 0x0027f100, 0xf034bd22, 0x23d00233, +/* 0x01af: cmd_exec_set_format */ 0xf400f800, 0x01b0f030, 0x0101b000, @@ -258,20 +313,26 @@ uint32_t nvc0_pcopy_code[] = { 0x3847c701, 0xf40170b6, 0x84bd0232, +/* 0x01da: ncomp_loop */ 0x4ac494bd, 0x0445b60f, +/* 0x01e2: bpc_loop */ 0xa430b4bd, 0x0f18f404, 0xbbc0a5ff, 0x31f400cb, 0x220ef402, +/* 0x01f4: cmp_c0 */ 0xf00c1bf4, 0xcbbb10c7, 0x160ef400, +/* 0x0200: cmp_c1 */ 0xf406a430, 0xc7f00c18, 0x00cbbb14, +/* 0x020f: cmp_zero */ 0xf1070ef4, +/* 0x0213: bpc_next */ 0x380080c7, 0x80b601c8, 0x01b0b601, @@ -283,6 +344,7 @@ uint32_t nvc0_pcopy_code[] = { 0x1d08980e, 0xf40068fd, 0x64bd0502, +/* 0x023c: dst_xcnt */ 0x800075fd, 0x78fd1907, 0x1057f100, @@ -307,15 +369,18 @@ uint32_t nvc0_pcopy_code[] = { 0x1c069800, 0xf44056d0, 0x00f81030, +/* 0x029c: cmd_exec_set_surface_tiled */ 0xc7075798, 0x78c76879, 0x0380b664, 0xb06077c7, 0x1bf40e76, 0x0477f009, +/* 0x02b7: xtile64 */ 0xf00f0ef4, 0x70b6027c, 0x0947fd11, +/* 0x02c3: xtileok */ 0x980677f0, 0x5b980c5a, 0x00abfd0e, @@ -374,6 +439,7 @@ uint32_t nvc0_pcopy_code[] = { 0xb70067d0, 0xd0040060, 0x00f80068, +/* 0x03a8: cmd_exec_set_surface_linear */ 0xb7026cf0, 0xb6020260, 0x57980864, @@ -384,12 +450,15 @@ uint32_t nvc0_pcopy_code[] = { 0x0060b700, 0x06579804, 0xf80067d0, +/* 0x03d1: cmd_exec_wait */ 0xf900f900, 0x0007f110, 0x0604b608, +/* 0x03dc: loop */ 0xf00001cf, 0x1bf40114, 0xfc10fcfa, +/* 0x03eb: cmd_exec_query */ 0xc800f800, 0x1bf40d34, 0xd121f570, @@ -419,6 +488,7 @@ uint32_t nvc0_pcopy_code[] = { 0x0153f026, 0x080047f1, 0xd00644b6, +/* 0x045e: query_counter */ 0x21f50045, 0x47f103d1, 0x44b6080c, @@ -442,11 +512,13 @@ uint32_t nvc0_pcopy_code[] = { 0x080047f1, 0xd00644b6, 0x00f80045, +/* 0x04b8: cmd_exec */ 0x03d121f5, 0xf4003fc8, 0x21f50e0b, 0x47f101af, 0x0ef40200, +/* 0x04cd: cmd_exec_no_format */ 0x1067f11e, 0x0664b608, 0x800177f0, @@ -454,18 +526,23 @@ uint32_t nvc0_pcopy_code[] = { 0x1d079819, 0xd00067d0, 0x44bd4067, +/* 0x04e8: cmd_exec_init_src_surface */ 0xbd0232f4, 0x043fc854, 0xf50a0bf4, 0xf403a821, +/* 0x04fa: src_tiled */ 0x21f50a0e, 0x49f0029c, +/* 0x0501: cmd_exec_init_dst_surface */ 0x0231f407, 0xc82c57f0, 0x0bf4083f, 0xa821f50a, 0x0a0ef403, +/* 0x0514: dst_tiled */ 0x029c21f5, +/* 0x051b: cmd_exec_kick */ 0xf10849f0, 0xb6080057, 0x06980654, @@ -475,7 +552,9 @@ uint32_t nvc0_pcopy_code[] = { 0x54d00546, 0x0c3fc800, 0xf5070bf4, +/* 0x053f: cmd_exec_done */ 0xf803eb21, +/* 0x0541: cmd_wrcache_flush */ 0x0027f100, 0xf034bd22, 0x23d00133, From 2a271d6a66d1d10f001c5653da68c1f72d0ded59 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 30 Jun 2012 19:14:57 -0400 Subject: [PATCH 0598/2357] ext4: pass a char * to ext4_count_free() instead of a buffer_head ptr commit f6fb99cadcd44660c68e13f6eab28333653621e6 upstream. Make it possible for ext4_count_free to operate on buffers and not just data in buffer_heads. Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 3 ++- fs/ext4/bitmap.c | 8 +++----- fs/ext4/ext4.h | 2 +- fs/ext4/ialloc.c | 3 ++- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 8da837be0c8..df76291d692 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -584,7 +584,8 @@ ext4_fsblk_t ext4_count_free_clusters(struct super_block *sb) if (bitmap_bh == NULL) continue; - x = ext4_count_free(bitmap_bh, sb->s_blocksize); + x = ext4_count_free(bitmap_bh->b_data, + EXT4_BLOCKS_PER_GROUP(sb) / 8); printk(KERN_DEBUG "group %u: stored = %d, counted = %u\n", i, ext4_free_group_clusters(sb, gdp), x); bitmap_count += x; diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c index fa3af81ac56..012faaaec4a 100644 --- a/fs/ext4/bitmap.c +++ b/fs/ext4/bitmap.c @@ -15,15 +15,13 @@ static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; -unsigned int ext4_count_free(struct buffer_head *map, unsigned int numchars) +unsigned int ext4_count_free(char *bitmap, unsigned int numchars) { unsigned int i, sum = 0; - if (!map) - return 0; for (i = 0; i < numchars; i++) - sum += nibblemap[map->b_data[i] & 0xf] + - nibblemap[(map->b_data[i] >> 4) & 0xf]; + sum += nibblemap[bitmap[i] & 0xf] + + nibblemap[(bitmap[i] >> 4) & 0xf]; return sum; } diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0e01e90add8..962988d14bb 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1783,7 +1783,7 @@ struct mmpd_data { # define NORET_AND noreturn, /* bitmap.c */ -extern unsigned int ext4_count_free(struct buffer_head *, unsigned); +extern unsigned int ext4_count_free(char *bitmap, unsigned numchars); /* balloc.c */ extern unsigned int ext4_block_group(struct super_block *sb, diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 8900f8b2ad4..0ee374d27fd 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -1013,7 +1013,8 @@ unsigned long ext4_count_free_inodes(struct super_block *sb) if (!bitmap_bh) continue; - x = ext4_count_free(bitmap_bh, EXT4_INODES_PER_GROUP(sb) / 8); + x = ext4_count_free(bitmap_bh->b_data, + EXT4_INODES_PER_GROUP(sb) / 8); printk(KERN_DEBUG "group %lu: stored = %d, counted = %lu\n", (unsigned long) i, ext4_free_inodes_count(sb, gdp), x); bitmap_count += x; From 25471391e7a0acace5821318fc0123a0a5cfdbbe Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 9 Jul 2012 16:27:05 -0400 Subject: [PATCH 0599/2357] ext4: fix overhead calculation used by ext4_statfs() commit 952fc18ef9ec707ebdc16c0786ec360295e5ff15 upstream. Commit f975d6bcc7a introduced bug which caused ext4_statfs() to miscalculate the number of file system overhead blocks. This causes the f_blocks field in the statfs structure to be larger than it should be. This would in turn cause the "df" output to show the number of data blocks in the file system and the number of data blocks used to be larger than they should be. Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/bitmap.c | 4 -- fs/ext4/ext4.h | 4 +- fs/ext4/resize.c | 7 +- fs/ext4/super.c | 174 +++++++++++++++++++++++++++++++++-------------- 4 files changed, 132 insertions(+), 57 deletions(-) diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c index 012faaaec4a..bbde5d58297 100644 --- a/fs/ext4/bitmap.c +++ b/fs/ext4/bitmap.c @@ -11,8 +11,6 @@ #include #include "ext4.h" -#ifdef EXT4FS_DEBUG - static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; unsigned int ext4_count_free(char *bitmap, unsigned int numchars) @@ -25,5 +23,3 @@ unsigned int ext4_count_free(char *bitmap, unsigned int numchars) return sum; } -#endif /* EXT4FS_DEBUG */ - diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 962988d14bb..47d1c8cda0c 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1140,8 +1140,7 @@ struct ext4_sb_info { unsigned long s_desc_per_block; /* Number of group descriptors per block */ ext4_group_t s_groups_count; /* Number of groups in the fs */ ext4_group_t s_blockfile_groups;/* Groups acceptable for non-extent files */ - unsigned long s_overhead_last; /* Last calculated overhead */ - unsigned long s_blocks_last; /* Last seen block count */ + unsigned long s_overhead; /* # of fs overhead clusters */ unsigned int s_cluster_ratio; /* Number of blocks per cluster */ unsigned int s_cluster_bits; /* log2 of s_cluster_ratio */ loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */ @@ -1950,6 +1949,7 @@ extern int ext4_group_extend(struct super_block *sb, extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count); /* super.c */ +extern int ext4_calculate_overhead(struct super_block *sb); extern void *ext4_kvmalloc(size_t size, gfp_t flags); extern void *ext4_kvzalloc(size_t size, gfp_t flags); extern void ext4_kvfree(void *ptr); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 53589ff8824..3407a62590d 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -1141,7 +1141,7 @@ static void ext4_update_super(struct super_block *sb, struct ext4_new_group_data *group_data = flex_gd->groups; struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; - int i; + int i, ret; BUG_ON(flex_gd->count == 0 || group_data == NULL); /* @@ -1216,6 +1216,11 @@ static void ext4_update_super(struct super_block *sb, &sbi->s_flex_groups[flex_group].free_inodes); } + /* + * Update the fs overhead information + */ + ext4_calculate_overhead(sb); + if (test_opt(sb, DEBUG)) printk(KERN_DEBUG "EXT4-fs: added group %u:" "%llu blocks(%llu free %llu reserved)\n", flex_gd->count, diff --git a/fs/ext4/super.c b/fs/ext4/super.c index a68703a5610..7fe3869d33d 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2944,6 +2944,114 @@ static void ext4_destroy_lazyinit_thread(void) kthread_stop(ext4_lazyinit_task); } +/* + * Note: calculating the overhead so we can be compatible with + * historical BSD practice is quite difficult in the face of + * clusters/bigalloc. This is because multiple metadata blocks from + * different block group can end up in the same allocation cluster. + * Calculating the exact overhead in the face of clustered allocation + * requires either O(all block bitmaps) in memory or O(number of block + * groups**2) in time. We will still calculate the superblock for + * older file systems --- and if we come across with a bigalloc file + * system with zero in s_overhead_clusters the estimate will be close to + * correct especially for very large cluster sizes --- but for newer + * file systems, it's better to calculate this figure once at mkfs + * time, and store it in the superblock. If the superblock value is + * present (even for non-bigalloc file systems), we will use it. + */ +static int count_overhead(struct super_block *sb, ext4_group_t grp, + char *buf) +{ + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_group_desc *gdp; + ext4_fsblk_t first_block, last_block, b; + ext4_group_t i, ngroups = ext4_get_groups_count(sb); + int s, j, count = 0; + + first_block = le32_to_cpu(sbi->s_es->s_first_data_block) + + (grp * EXT4_BLOCKS_PER_GROUP(sb)); + last_block = first_block + EXT4_BLOCKS_PER_GROUP(sb) - 1; + for (i = 0; i < ngroups; i++) { + gdp = ext4_get_group_desc(sb, i, NULL); + b = ext4_block_bitmap(sb, gdp); + if (b >= first_block && b <= last_block) { + ext4_set_bit(EXT4_B2C(sbi, b - first_block), buf); + count++; + } + b = ext4_inode_bitmap(sb, gdp); + if (b >= first_block && b <= last_block) { + ext4_set_bit(EXT4_B2C(sbi, b - first_block), buf); + count++; + } + b = ext4_inode_table(sb, gdp); + if (b >= first_block && b + sbi->s_itb_per_group <= last_block) + for (j = 0; j < sbi->s_itb_per_group; j++, b++) { + int c = EXT4_B2C(sbi, b - first_block); + ext4_set_bit(c, buf); + count++; + } + if (i != grp) + continue; + s = 0; + if (ext4_bg_has_super(sb, grp)) { + ext4_set_bit(s++, buf); + count++; + } + for (j = ext4_bg_num_gdb(sb, grp); j > 0; j--) { + ext4_set_bit(EXT4_B2C(sbi, s++), buf); + count++; + } + } + if (!count) + return 0; + return EXT4_CLUSTERS_PER_GROUP(sb) - + ext4_count_free(buf, EXT4_CLUSTERS_PER_GROUP(sb) / 8); +} + +/* + * Compute the overhead and stash it in sbi->s_overhead + */ +int ext4_calculate_overhead(struct super_block *sb) +{ + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; + ext4_group_t i, ngroups = ext4_get_groups_count(sb); + ext4_fsblk_t overhead = 0; + char *buf = (char *) get_zeroed_page(GFP_KERNEL); + + memset(buf, 0, PAGE_SIZE); + if (!buf) + return -ENOMEM; + + /* + * Compute the overhead (FS structures). This is constant + * for a given filesystem unless the number of block groups + * changes so we cache the previous value until it does. + */ + + /* + * All of the blocks before first_data_block are overhead + */ + overhead = EXT4_B2C(sbi, le32_to_cpu(es->s_first_data_block)); + + /* + * Add the overhead found in each block group + */ + for (i = 0; i < ngroups; i++) { + int blks; + + blks = count_overhead(sb, i, buf); + overhead += blks; + if (blks) + memset(buf, 0, PAGE_SIZE); + cond_resched(); + } + sbi->s_overhead = overhead; + smp_wmb(); + free_page((unsigned long) buf); + return 0; +} + static int ext4_fill_super(struct super_block *sb, void *data, int silent) { char *orig_data = kstrdup(data, GFP_KERNEL); @@ -3558,6 +3666,18 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) percpu_counter_set(&sbi->s_dirtyclusters_counter, 0); no_journal: + /* + * Get the # of file system overhead blocks from the + * superblock if present. + */ + if (es->s_overhead_clusters) + sbi->s_overhead = le32_to_cpu(es->s_overhead_clusters); + else { + ret = ext4_calculate_overhead(sb); + if (ret) + goto failed_mount_wq; + } + /* * The maximum number of concurrent works can be high and * concurrency isn't really necessary. Limit it to 1. @@ -4421,67 +4541,21 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) return err; } -/* - * Note: calculating the overhead so we can be compatible with - * historical BSD practice is quite difficult in the face of - * clusters/bigalloc. This is because multiple metadata blocks from - * different block group can end up in the same allocation cluster. - * Calculating the exact overhead in the face of clustered allocation - * requires either O(all block bitmaps) in memory or O(number of block - * groups**2) in time. We will still calculate the superblock for - * older file systems --- and if we come across with a bigalloc file - * system with zero in s_overhead_clusters the estimate will be close to - * correct especially for very large cluster sizes --- but for newer - * file systems, it's better to calculate this figure once at mkfs - * time, and store it in the superblock. If the superblock value is - * present (even for non-bigalloc file systems), we will use it. - */ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; - struct ext4_group_desc *gdp; + ext4_fsblk_t overhead = 0; u64 fsid; s64 bfree; - if (test_opt(sb, MINIX_DF)) { - sbi->s_overhead_last = 0; - } else if (es->s_overhead_clusters) { - sbi->s_overhead_last = le32_to_cpu(es->s_overhead_clusters); - } else if (sbi->s_blocks_last != ext4_blocks_count(es)) { - ext4_group_t i, ngroups = ext4_get_groups_count(sb); - ext4_fsblk_t overhead = 0; - - /* - * Compute the overhead (FS structures). This is constant - * for a given filesystem unless the number of block groups - * changes so we cache the previous value until it does. - */ - - /* - * All of the blocks before first_data_block are - * overhead - */ - overhead = EXT4_B2C(sbi, le32_to_cpu(es->s_first_data_block)); - - /* - * Add the overhead found in each block group - */ - for (i = 0; i < ngroups; i++) { - gdp = ext4_get_group_desc(sb, i, NULL); - overhead += ext4_num_overhead_clusters(sb, i, gdp); - cond_resched(); - } - sbi->s_overhead_last = overhead; - smp_wmb(); - sbi->s_blocks_last = ext4_blocks_count(es); - } + if (!test_opt(sb, MINIX_DF)) + overhead = sbi->s_overhead; buf->f_type = EXT4_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; - buf->f_blocks = (ext4_blocks_count(es) - - EXT4_C2B(sbi, sbi->s_overhead_last)); + buf->f_blocks = ext4_blocks_count(es) - EXT4_C2B(sbi, sbi->s_overhead); bfree = percpu_counter_sum_positive(&sbi->s_freeclusters_counter) - percpu_counter_sum_positive(&sbi->s_dirtyclusters_counter); /* prevent underflow in case that few free space is available */ From 6918ff0bf4ba47ce863813fe5010796718219f8f Mon Sep 17 00:00:00 2001 From: Ashish Sangwan Date: Sun, 22 Jul 2012 22:49:08 -0400 Subject: [PATCH 0600/2357] ext4: fix hole punch failure when depth is greater than 0 commit 968dee77220768a5f52cf8b21d0bdb73486febef upstream. Whether to continue removing extents or not is decided by the return value of function ext4_ext_more_to_rm() which checks 2 conditions: a) if there are no more indexes to process. b) if the number of entries are decreased in the header of "depth -1". In case of hole punch, if the last block to be removed is not part of the last extent index than this index will not be deleted, hence the number of valid entries in the extent header of "depth - 1" will remain as it is and ext4_ext_more_to_rm will return 0 although the required blocks are not yet removed. This patch fixes the above mentioned problem as instead of removing the extents from the end of file, it starts removing the blocks from the particular extent from which removing blocks is actually required and continue backward until done. Signed-off-by: Ashish Sangwan Signed-off-by: Namjae Jeon Reviewed-by: Lukas Czerner Signed-off-by: Greg Kroah-Hartman --- fs/ext4/extents.c | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index abcdeab67f5..6b7daa45f6b 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2503,10 +2503,10 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, { struct super_block *sb = inode->i_sb; int depth = ext_depth(inode); - struct ext4_ext_path *path; + struct ext4_ext_path *path = NULL; ext4_fsblk_t partial_cluster = 0; handle_t *handle; - int i, err; + int i = 0, err; ext_debug("truncate since %u to %u\n", start, end); @@ -2539,8 +2539,12 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, } depth = ext_depth(inode); ex = path[depth].p_ext; - if (!ex) + if (!ex) { + ext4_ext_drop_refs(path); + kfree(path); + path = NULL; goto cont; + } ee_block = le32_to_cpu(ex->ee_block); @@ -2570,8 +2574,6 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, if (err < 0) goto out; } - ext4_ext_drop_refs(path); - kfree(path); } cont: @@ -2580,19 +2582,27 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, * after i_size and walking into the tree depth-wise. */ depth = ext_depth(inode); - path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS); - if (path == NULL) { - ext4_journal_stop(handle); - return -ENOMEM; - } - path[0].p_depth = depth; - path[0].p_hdr = ext_inode_hdr(inode); + if (path) { + int k = i = depth; + while (--k > 0) + path[k].p_block = + le16_to_cpu(path[k].p_hdr->eh_entries)+1; + } else { + path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), + GFP_NOFS); + if (path == NULL) { + ext4_journal_stop(handle); + return -ENOMEM; + } + path[0].p_depth = depth; + path[0].p_hdr = ext_inode_hdr(inode); - if (ext4_ext_check(inode, path[0].p_hdr, depth)) { - err = -EIO; - goto out; + if (ext4_ext_check(inode, path[0].p_hdr, depth)) { + err = -EIO; + goto out; + } } - i = err = 0; + err = 0; while (i >= 0 && err == 0) { if (i == depth) { @@ -2706,8 +2716,10 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, out: ext4_ext_drop_refs(path); kfree(path); - if (err == -EAGAIN) + if (err == -EAGAIN) { + path = NULL; goto again; + } ext4_journal_stop(handle); return err; From 2dd71727e4bf6787caa56770b99a9102ac9a65f4 Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Sun, 22 Jul 2012 23:59:40 -0400 Subject: [PATCH 0601/2357] ext4: don't let i_reserved_meta_blocks go negative commit 97795d2a5b8d3c8dc4365d4bd3404191840453ba upstream. If we hit a condition where we have allocated metadata blocks that were not appropriately reserved, we risk underflow of ei->i_reserved_meta_blocks. In turn, this can throw sbi->s_dirtyclusters_counter significantly out of whack and undermine the nondelalloc fallback logic in ext4_nonda_switch(). Warn if this occurs and set i_allocated_meta_blocks to avoid this problem. This condition is reproduced by xfstests 270 against ext2 with delalloc enabled: Mar 28 08:58:02 localhost kernel: [ 171.526344] EXT4-fs (loop1): delayed block allocation failed for inode 14 at logical offset 64486 with max blocks 64 with error -28 Mar 28 08:58:02 localhost kernel: [ 171.526346] EXT4-fs (loop1): This should not happen!! Data will be lost 270 ultimately fails with an inconsistent filesystem and requires an fsck to repair. The cause of the error is an underflow in ext4_da_update_reserve_space() due to an unreserved meta block allocation. Signed-off-by: Brian Foster Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c77b0bd2c71..b58845ce5bf 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -279,6 +279,15 @@ void ext4_da_update_reserve_space(struct inode *inode, used = ei->i_reserved_data_blocks; } + if (unlikely(ei->i_allocated_meta_blocks > ei->i_reserved_meta_blocks)) { + ext4_msg(inode->i_sb, KERN_NOTICE, "%s: ino %lu, allocated %d " + "with only %d reserved metadata blocks\n", __func__, + inode->i_ino, ei->i_allocated_meta_blocks, + ei->i_reserved_meta_blocks); + WARN_ON(1); + ei->i_allocated_meta_blocks = ei->i_reserved_meta_blocks; + } + /* Update per-inode reservations */ ei->i_reserved_data_blocks -= used; ei->i_reserved_meta_blocks -= ei->i_allocated_meta_blocks; From c0ce1fd51e122606d555dfd57f5c703b2af12146 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 23 Jul 2012 00:00:20 -0400 Subject: [PATCH 0602/2357] ext4: undo ext4_calc_metadata_amount if we fail to claim space commit 03179fe92318e7934c180d96f12eff2cb36ef7b6 upstream. The function ext4_calc_metadata_amount() has side effects, although it's not obvious from its function name. So if we fail to claim space, regardless of whether we retry to claim the space again, or return an error, we need to undo these side effects. Otherwise we can end up incorrectly calculating the number of metadata blocks needed for the operation, which was responsible for an xfstests failure for test #271 when using an ext2 file system with delalloc enabled. Reported-by: Brian Foster Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index b58845ce5bf..55a654d8618 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1113,6 +1113,17 @@ static int ext4_da_reserve_space(struct inode *inode, ext4_lblk_t lblock) struct ext4_inode_info *ei = EXT4_I(inode); unsigned int md_needed; int ret; + ext4_lblk_t save_last_lblock; + int save_len; + + /* + * We will charge metadata quota at writeout time; this saves + * us from metadata over-estimation, though we may go over by + * a small amount in the end. Here we just reserve for data. + */ + ret = dquot_reserve_block(inode, EXT4_C2B(sbi, 1)); + if (ret) + return ret; /* * recalculate the amount of metadata blocks to reserve @@ -1121,32 +1132,31 @@ static int ext4_da_reserve_space(struct inode *inode, ext4_lblk_t lblock) */ repeat: spin_lock(&ei->i_block_reservation_lock); + /* + * ext4_calc_metadata_amount() has side effects, which we have + * to be prepared undo if we fail to claim space. + */ + save_len = ei->i_da_metadata_calc_len; + save_last_lblock = ei->i_da_metadata_calc_last_lblock; md_needed = EXT4_NUM_B2C(sbi, ext4_calc_metadata_amount(inode, lblock)); trace_ext4_da_reserve_space(inode, md_needed); - spin_unlock(&ei->i_block_reservation_lock); - /* - * We will charge metadata quota at writeout time; this saves - * us from metadata over-estimation, though we may go over by - * a small amount in the end. Here we just reserve for data. - */ - ret = dquot_reserve_block(inode, EXT4_C2B(sbi, 1)); - if (ret) - return ret; /* * We do still charge estimated metadata to the sb though; * we cannot afford to run out of free blocks. */ if (ext4_claim_free_clusters(sbi, md_needed + 1, 0)) { - dquot_release_reservation_block(inode, EXT4_C2B(sbi, 1)); + ei->i_da_metadata_calc_len = save_len; + ei->i_da_metadata_calc_last_lblock = save_last_lblock; + spin_unlock(&ei->i_block_reservation_lock); if (ext4_should_retry_alloc(inode->i_sb, &retries)) { yield(); goto repeat; } + dquot_release_reservation_block(inode, EXT4_C2B(sbi, 1)); return -ENOSPC; } - spin_lock(&ei->i_block_reservation_lock); ei->i_reserved_data_blocks++; ei->i_reserved_meta_blocks += md_needed; spin_unlock(&ei->i_block_reservation_lock); From aa505bba77961634215eb8bdd8ab9f4bd0c6f1d1 Mon Sep 17 00:00:00 2001 From: Cloud Ren Date: Tue, 3 Jul 2012 16:51:48 +0000 Subject: [PATCH 0603/2357] atl1c: fix issue of transmit queue 0 timed out [ Upstream commit b94e52f62683dc0b00c6d1b58b80929a078c0fd5 ] some people report atl1c could cause system hang with following kernel trace info: --------------------------------------- WARNING: at.../net/sched/sch_generic.c:258 dev_watchdog+0x1db/0x1d0() ... NETDEV WATCHDOG: eth0 (atl1c): transmit queue 0 timed out ... --------------------------------------- This is caused by netif_stop_queue calling when cable Link is down. So remove netif_stop_queue, because link_watch will take it over. Signed-off-by: xiong Cc: stable Signed-off-by: Cloud Ren Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 1ef0c9275de..65fe6324d81 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -267,7 +267,6 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) dev_warn(&pdev->dev, "stop mac failed\n"); atl1c_set_aspm(hw, false); netif_carrier_off(netdev); - netif_stop_queue(netdev); atl1c_phy_reset(hw); atl1c_phy_init(&adapter->hw); } else { From f7a47ee34686694148f6d34a4576385853c5e33f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 3 Jul 2012 20:55:21 +0000 Subject: [PATCH 0604/2357] netem: add limitation to reordered packets [ Upstream commit 960fb66e520a405dde39ff883f17ff2669c13d85 ] Fix two netem bugs : 1) When a frame was dropped by tfifo_enqueue(), drop counter was incremented twice. 2) When reordering is triggered, we enqueue a packet without checking queue limit. This can OOM pretty fast when this is repeated enough, since skbs are orphaned, no socket limit can help in this situation. Signed-off-by: Eric Dumazet Cc: Mark Gordon Cc: Andreas Terzis Cc: Yuchung Cheng Cc: Hagen Paul Pfeifer Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_netem.c | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index ebd22966f74..992acaac5de 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -329,29 +329,22 @@ static psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sche return PSCHED_NS2TICKS(ticks); } -static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) +static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) { struct sk_buff_head *list = &sch->q; psched_time_t tnext = netem_skb_cb(nskb)->time_to_send; - struct sk_buff *skb; - - if (likely(skb_queue_len(list) < sch->limit)) { - skb = skb_peek_tail(list); - /* Optimize for add at tail */ - if (likely(!skb || tnext >= netem_skb_cb(skb)->time_to_send)) - return qdisc_enqueue_tail(nskb, sch); + struct sk_buff *skb = skb_peek_tail(list); - skb_queue_reverse_walk(list, skb) { - if (tnext >= netem_skb_cb(skb)->time_to_send) - break; - } + /* Optimize for add at tail */ + if (likely(!skb || tnext >= netem_skb_cb(skb)->time_to_send)) + return __skb_queue_tail(list, nskb); - __skb_queue_after(list, skb, nskb); - sch->qstats.backlog += qdisc_pkt_len(nskb); - return NET_XMIT_SUCCESS; + skb_queue_reverse_walk(list, skb) { + if (tnext >= netem_skb_cb(skb)->time_to_send) + break; } - return qdisc_reshape_fail(nskb, sch); + __skb_queue_after(list, skb, nskb); } /* @@ -366,7 +359,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) /* We don't fill cb now as skb_unshare() may invalidate it */ struct netem_skb_cb *cb; struct sk_buff *skb2; - int ret; int count = 1; /* Random duplication */ @@ -414,6 +406,11 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8); } + if (unlikely(skb_queue_len(&sch->q) >= sch->limit)) + return qdisc_reshape_fail(skb, sch); + + sch->qstats.backlog += qdisc_pkt_len(skb); + cb = netem_skb_cb(skb); if (q->gap == 0 || /* not doing reordering */ q->counter < q->gap - 1 || /* inside last reordering gap */ @@ -445,7 +442,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) cb->time_to_send = now + delay; ++q->counter; - ret = tfifo_enqueue(skb, sch); + tfifo_enqueue(skb, sch); } else { /* * Do re-ordering by putting one out of N packets at the front @@ -455,16 +452,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) q->counter = 0; __skb_queue_head(&sch->q, skb); - sch->qstats.backlog += qdisc_pkt_len(skb); sch->qstats.requeues++; - ret = NET_XMIT_SUCCESS; - } - - if (ret != NET_XMIT_SUCCESS) { - if (net_xmit_drop_count(ret)) { - sch->qstats.drops++; - return ret; - } } return NET_XMIT_SUCCESS; From d680c0462d9f4d96b255853364fb0bcd5c202553 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Jul 2012 11:45:13 +0000 Subject: [PATCH 0605/2357] gianfar: fix potential sk_wmem_alloc imbalance [ Upstream commit 313b037cf054ec908de92fb4c085403ffd7420d4 ] commit db83d136d7f753 (gianfar: Fix missing sock reference when processing TX time stamps) added a potential sk_wmem_alloc imbalance If the new skb has a different truesize than old one, we can get a negative sk_wmem_alloc once new skb is orphaned at TX completion. Now we no longer early orphan skbs in dev_hard_start_xmit(), this probably can lead to fatal bugs. Signed-off-by: Eric Dumazet Tested-by: Paul Gortmaker Cc: Manfred Rudigier Cc: Claudiu Manoil Cc: Jiajun Wu Cc: Andy Fleming Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/freescale/gianfar.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index e7bed530399..24381e1298e 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2065,10 +2065,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - /* Steal sock reference for processing TX time stamps */ - swap(skb_new->sk, skb->sk); - swap(skb_new->destructor, skb->destructor); - kfree_skb(skb); + if (skb->sk) + skb_set_owner_w(skb_new, skb->sk); + consume_skb(skb); skb = skb_new; } From a5b4b62d8517f12c77f912b8c249e36019d31a0c Mon Sep 17 00:00:00 2001 From: Amir Hanania Date: Mon, 9 Jul 2012 20:47:19 +0000 Subject: [PATCH 0606/2357] net: Fix memory leak - vlan_info struct [ Upstream commit efc73f4bbc238d4f579fb612c04c8e1dd8a82979 ] In driver reload test there is a memory leak. The structure vlan_info was not freed when the driver was removed. It was not released since the nr_vids var is one after last vlan was removed. The nr_vids is one, since vlan zero is added to the interface when the interface is being set, but the vlan zero is not deleted at unregister. Fix - delete vlan zero when we unregister the device. Signed-off-by: Amir Hanania Acked-by: John Fastabend Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/8021q/vlan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index efea35b02e7..cf4a49c5623 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -403,6 +403,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, break; case NETDEV_DOWN: + if (dev->features & NETIF_F_HW_VLAN_FILTER) + vlan_vid_del(dev, 0); + /* Put all VLANs for this dev in the down state too. */ for (i = 0; i < VLAN_N_VID; i++) { vlandev = vlan_group_get_device(grp, i); From af8ca6ddbb2928d5fb26f0a78710971e1210a299 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 10 Jul 2012 10:04:40 +0000 Subject: [PATCH 0607/2357] bnx2: Fix bug in bnx2_free_tx_skbs(). [ Upstream commit c1f5163de417dab01fa9daaf09a74bbb19303f3c ] In rare cases, bnx2x_free_tx_skbs() can unmap the wrong DMA address when it gets to the last entry of the tx ring. We were not using the proper macro to skip the last entry when advancing the tx index. Reported-by: Zongyun Lai Reviewed-by: Jeffrey Huang Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 8297e286873..b8ade570759 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -5372,7 +5372,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp) int k, last; if (skb == NULL) { - j++; + j = NEXT_TX_BD(j); continue; } @@ -5384,8 +5384,8 @@ bnx2_free_tx_skbs(struct bnx2 *bp) tx_buf->skb = NULL; last = tx_buf->nr_frags; - j++; - for (k = 0; k < last; k++, j++) { + j = NEXT_TX_BD(j); + for (k = 0; k < last; k++, j = NEXT_TX_BD(j)) { tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)]; dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping), From d5eeca5f5c19c472f8f221a81bb27f15a7aeed6c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 12 Jul 2012 03:39:11 +0000 Subject: [PATCH 0608/2357] sch_sfb: Fix missing NULL check [ Upstream commit 7ac2908e4b2edaec60e9090ddb4d9ceb76c05e7d ] Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=44461 Signed-off-by: Alan Cox Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_sfb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index d7eea99333e..c6a5867d35c 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -570,6 +570,8 @@ static int sfb_dump(struct Qdisc *sch, struct sk_buff *skb) sch->qstats.backlog = q->qdisc->qstats.backlog; opts = nla_nest_start(skb, TCA_OPTIONS); + if (opts == NULL) + goto nla_put_failure; NLA_PUT(skb, TCA_SFB_PARMS, sizeof(opt), &opt); return nla_nest_end(skb, opts); From 2936d35db07cc3c9e3f2d60ed90f9a72f2031130 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 16 Jul 2012 09:13:51 +0000 Subject: [PATCH 0609/2357] sctp: Fix list corruption resulting from freeing an association on a list [ Upstream commit 2eebc1e188e9e45886ee00662519849339884d6d ] A few days ago Dave Jones reported this oops: [22766.294255] general protection fault: 0000 [#1] PREEMPT SMP [22766.295376] CPU 0 [22766.295384] Modules linked in: [22766.387137] ffffffffa169f292 6b6b6b6b6b6b6b6b ffff880147c03a90 ffff880147c03a74 [22766.387135] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 00000000000 [22766.387136] Process trinity-watchdo (pid: 10896, threadinfo ffff88013e7d2000, [22766.387137] Stack: [22766.387140] ffff880147c03a10 [22766.387140] ffffffffa169f2b6 [22766.387140] ffff88013ed95728 [22766.387143] 0000000000000002 [22766.387143] 0000000000000000 [22766.387143] ffff880003fad062 [22766.387144] ffff88013c120000 [22766.387144] [22766.387145] Call Trace: [22766.387145] [22766.387150] [] ? __sctp_lookup_association+0x62/0xd0 [sctp] [22766.387154] [] __sctp_lookup_association+0x86/0xd0 [sctp] [22766.387157] [] sctp_rcv+0x207/0xbb0 [sctp] [22766.387161] [] ? trace_hardirqs_off_caller+0x28/0xd0 [22766.387163] [] ? nf_hook_slow+0x133/0x210 [22766.387166] [] ? ip_local_deliver_finish+0x4c/0x4c0 [22766.387168] [] ip_local_deliver_finish+0x18d/0x4c0 [22766.387169] [] ? ip_local_deliver_finish+0x4c/0x4c0 [22766.387171] [] ip_local_deliver+0x47/0x80 [22766.387172] [] ip_rcv_finish+0x150/0x680 [22766.387174] [] ip_rcv+0x214/0x320 [22766.387176] [] __netif_receive_skb+0x7b7/0x910 [22766.387178] [] ? __netif_receive_skb+0x11c/0x910 [22766.387180] [] ? put_lock_stats.isra.25+0xe/0x40 [22766.387182] [] netif_receive_skb+0x23/0x1f0 [22766.387183] [] ? dev_gro_receive+0x139/0x440 [22766.387185] [] napi_skb_finish+0x70/0xa0 [22766.387187] [] napi_gro_receive+0xf5/0x130 [22766.387218] [] e1000_receive_skb+0x59/0x70 [e1000e] [22766.387242] [] e1000_clean_rx_irq+0x28b/0x460 [e1000e] [22766.387266] [] e1000e_poll+0x78/0x430 [e1000e] [22766.387268] [] net_rx_action+0x1aa/0x3d0 [22766.387270] [] ? account_system_vtime+0x10f/0x130 [22766.387273] [] __do_softirq+0xe0/0x420 [22766.387275] [] call_softirq+0x1c/0x30 [22766.387278] [] do_softirq+0xd5/0x110 [22766.387279] [] irq_exit+0xd5/0xe0 [22766.387281] [] do_IRQ+0x63/0xd0 [22766.387283] [] common_interrupt+0x6f/0x6f [22766.387283] [22766.387284] [22766.387285] [] ? retint_swapgs+0x13/0x1b [22766.387285] Code: c0 90 5d c3 66 0f 1f 44 00 00 4c 89 c8 5d c3 0f 1f 00 55 48 89 e5 48 83 ec 20 48 89 5d e8 4c 89 65 f0 4c 89 6d f8 66 66 66 66 90 <0f> b7 87 98 00 00 00 48 89 fb 49 89 f5 66 c1 c0 08 66 39 46 02 [22766.387307] [22766.387307] RIP [22766.387311] [] sctp_assoc_is_match+0x19/0x90 [sctp] [22766.387311] RSP [22766.387142] ffffffffa16ab120 [22766.599537] ---[ end trace 3f6dae82e37b17f5 ]--- [22766.601221] Kernel panic - not syncing: Fatal exception in interrupt It appears from his analysis and some staring at the code that this is likely occuring because an association is getting freed while still on the sctp_assoc_hashtable. As a result, we get a gpf when traversing the hashtable while a freed node corrupts part of the list. Nominally I would think that an mibalanced refcount was responsible for this, but I can't seem to find any obvious imbalance. What I did note however was that the two places where we create an association using sctp_primitive_ASSOCIATE (__sctp_connect and sctp_sendmsg), have failure paths which free a newly created association after calling sctp_primitive_ASSOCIATE. sctp_primitive_ASSOCIATE brings us into the sctp_sf_do_prm_asoc path, which issues a SCTP_CMD_NEW_ASOC side effect, which in turn adds a new association to the aforementioned hash table. the sctp command interpreter that process side effects has not way to unwind previously processed commands, so freeing the association from the __sctp_connect or sctp_sendmsg error path would lead to a freed association remaining on this hash table. I've fixed this but modifying sctp_[un]hash_established to use hlist_del_init, which allows us to proerly use hlist_unhashed to check if the node is on a hashlist safely during a delete. That in turn alows us to safely call sctp_unhash_established in the __sctp_connect and sctp_sendmsg error paths before freeing them, regardles of what the associations state is on the hash list. I noted, while I was doing this, that the __sctp_unhash_endpoint was using hlist_unhsashed in a simmilar fashion, but never nullified any removed nodes pointers to make that function work properly, so I fixed that up in a simmilar fashion. I attempted to test this using a virtual guest running the SCTP_RR test from netperf in a loop while running the trinity fuzzer, both in a loop. I wasn't able to recreate the problem prior to this fix, nor was I able to trigger the failure after (neither of which I suppose is suprising). Given the trace above however, I think its likely that this is what we hit. Signed-off-by: Neil Horman Reported-by: davej@redhat.com CC: davej@redhat.com CC: "David S. Miller" CC: Vlad Yasevich CC: Sridhar Samudrala CC: linux-sctp@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/input.c | 7 ++----- net/sctp/socket.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/net/sctp/input.c b/net/sctp/input.c index 80f71af7138..be772c007db 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -736,15 +736,12 @@ static void __sctp_unhash_endpoint(struct sctp_endpoint *ep) epb = &ep->base; - if (hlist_unhashed(&epb->node)) - return; - epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); head = &sctp_ep_hashtable[epb->hashent]; sctp_write_lock(&head->lock); - __hlist_del(&epb->node); + hlist_del_init(&epb->node); sctp_write_unlock(&head->lock); } @@ -825,7 +822,7 @@ static void __sctp_unhash_established(struct sctp_association *asoc) head = &sctp_assoc_hashtable[epb->hashent]; sctp_write_lock(&head->lock); - __hlist_del(&epb->node); + hlist_del_init(&epb->node); sctp_write_unlock(&head->lock); } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 92ba71dfe08..dba20d6e324 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1231,8 +1231,14 @@ static int __sctp_connect(struct sock* sk, SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p" " kaddrs: %p err: %d\n", asoc, kaddrs, err); - if (asoc) + if (asoc) { + /* sctp_primitive_ASSOCIATE may have added this association + * To the hash table, try to unhash it, just in case, its a noop + * if it wasn't hashed so we're safe + */ + sctp_unhash_established(asoc); sctp_association_free(asoc); + } return err; } @@ -1942,8 +1948,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, goto out_unlock; out_free: - if (new_asoc) + if (new_asoc) { + sctp_unhash_established(asoc); sctp_association_free(asoc); + } out_unlock: sctp_release_sock(sk); From 60d2aa556cc3f00f1276ae363dc6601359180ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Date: Sun, 15 Jul 2012 10:10:14 +0000 Subject: [PATCH 0610/2357] caif: Fix access to freed pernet memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 96f80d123eff05c3cd4701463786b87952a6c3ac ] unregister_netdevice_notifier() must be called before unregister_pernet_subsys() to avoid accessing already freed pernet memory. This fixes the following oops when doing rmmod: Call Trace: [] caif_device_notify+0x4d/0x5a0 [caif] [] unregister_netdevice_notifier+0xb9/0x100 [] caif_device_exit+0x1c/0x250 [caif] [] sys_delete_module+0x1a4/0x300 [] ? trace_hardirqs_on_caller+0x15d/0x1e0 [] ? trace_hardirqs_on_thunk+0x3a/0x3 [] system_call_fastpath+0x1a/0x1f RIP [] caif_get+0x51/0xb0 [caif] Signed-off-by: Sjur Brændeland Acked-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/caif/caif_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index aa6f716524f..7bf4c21a279 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -562,9 +562,9 @@ static int __init caif_device_init(void) static void __exit caif_device_exit(void) { - unregister_pernet_subsys(&caif_net_ops); unregister_netdevice_notifier(&caif_device_notifier); dev_remove_pack(&caif_packet_type); + unregister_pernet_subsys(&caif_net_ops); } module_init(caif_device_init); From a080e65186d367508e2b4e68290656ddce493136 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Tue, 17 Jul 2012 11:07:47 +0000 Subject: [PATCH 0611/2357] cipso: don't follow a NULL pointer when setsockopt() is called [ Upstream commit 89d7ae34cdda4195809a5a987f697a517a2a3177 ] As reported by Alan Cox, and verified by Lin Ming, when a user attempts to add a CIPSO option to a socket using the CIPSO_V4_TAG_LOCAL tag the kernel dies a terrible death when it attempts to follow a NULL pointer (the skb argument to cipso_v4_validate() is NULL when called via the setsockopt() syscall). This patch fixes this by first checking to ensure that the skb is non-NULL before using it to find the incoming network interface. In the unlikely case where the skb is NULL and the user attempts to add a CIPSO option with the _TAG_LOCAL tag we return an error as this is not something we want to allow. A simple reproducer, kindly supplied by Lin Ming, although you must have the CIPSO DOI #3 configure on the system first or you will be caught early in cipso_v4_validate(): #include #include #include #include #include struct local_tag { char type; char length; char info[4]; }; struct cipso { char type; char length; char doi[4]; struct local_tag local; }; int main(int argc, char **argv) { int sockfd; struct cipso cipso = { .type = IPOPT_CIPSO, .length = sizeof(struct cipso), .local = { .type = 128, .length = sizeof(struct local_tag), }, }; memset(cipso.doi, 0, 4); cipso.doi[3] = 3; sockfd = socket(AF_INET, SOCK_DGRAM, 0); #define SOL_IP 0 setsockopt(sockfd, SOL_IP, IP_OPTIONS, &cipso, sizeof(struct cipso)); return 0; } CC: Lin Ming Reported-by: Alan Cox Signed-off-by: Paul Moore Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/cipso_ipv4.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index c48adc565e9..667c1d4ca98 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1725,8 +1725,10 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) case CIPSO_V4_TAG_LOCAL: /* This is a non-standard tag that we only allow for * local connections, so if the incoming interface is - * not the loopback device drop the packet. */ - if (!(skb->dev->flags & IFF_LOOPBACK)) { + * not the loopback device drop the packet. Further, + * there is no legitimate reason for setting this from + * userspace so reject it if skb is NULL. */ + if (skb == NULL || !(skb->dev->flags & IFF_LOOPBACK)) { err_offset = opt_iter; goto validate_return_locked; } From 4deb65e759dd2ff7dd5e40bd6d4bf0dad6d88269 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 22 Jul 2012 11:37:20 +0000 Subject: [PATCH 0612/2357] net: Fix references to out-of-scope variables in put_cmsg_compat() [ Upstream commit 818810472b129004c16fc51bf0a570b60776bfb7 ] In net/compat.c::put_cmsg_compat() we may assign 'data' the address of either the 'ctv' or 'cts' local variables inside the 'if (!COMPAT_USE_64BIT_TIME)' branch. Those variables go out of scope at the end of the 'if' statement, so when we use 'data' further down in 'copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr))' there's no telling what it may be refering to - not good. Fix the problem by simply giving 'ctv' and 'cts' function scope. Signed-off-by: Jesper Juhl Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/compat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/compat.c b/net/compat.c index e055708b8ec..ae6d67ad03b 100644 --- a/net/compat.c +++ b/net/compat.c @@ -221,6 +221,8 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat { struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control; struct compat_cmsghdr cmhdr; + struct compat_timeval ctv; + struct compat_timespec cts[3]; int cmlen; if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { @@ -229,8 +231,6 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat } if (!COMPAT_USE_64BIT_TIME) { - struct compat_timeval ctv; - struct compat_timespec cts[3]; if (level == SOL_SOCKET && type == SCM_TIMESTAMP) { struct timeval *tv = (struct timeval *)data; ctv.tv_sec = tv->tv_sec; From f63b1d926016ce39e06a9a39084d205e072541e2 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Mon, 23 Jul 2012 22:55:55 +0200 Subject: [PATCH 0613/2357] r8169: revert "add byte queue limit support". MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 17bcb684f08649a2ab6a7dcd8288332e72d208f1 ] This reverts commit 036dafa28da1e2565a8529de2ae663c37b7a0060. First it appears in bisection, then reverting it solves the usual netdev watchdog problem for different people. I don't have a proper fix yet so get rid of it. Bisected-and-reported-by: Alex Villacís Lasso Signed-off-by: Francois Romieu Cc: Josh Boyer Cc: Hayes Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 161e0451747..a73bbe7fb63 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5000,7 +5000,6 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp) { rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC); tp->cur_tx = tp->dirty_tx = 0; - netdev_reset_queue(tp->dev); } static void rtl_reset_work(struct rtl8169_private *tp) @@ -5155,8 +5154,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, txd->opts2 = cpu_to_le32(opts[1]); - netdev_sent_queue(dev, skb->len); - skb_tx_timestamp(skb); wmb(); @@ -5253,16 +5250,9 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev) rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); } -struct rtl_txc { - int packets; - int bytes; -}; - static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) { - struct rtl8169_stats *tx_stats = &tp->tx_stats; unsigned int dirty_tx, tx_left; - struct rtl_txc txc = { 0, 0 }; dirty_tx = tp->dirty_tx; smp_rmb(); @@ -5281,24 +5271,17 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb, tp->TxDescArray + entry); if (status & LastFrag) { - struct sk_buff *skb = tx_skb->skb; - - txc.packets++; - txc.bytes += skb->len; - dev_kfree_skb(skb); + u64_stats_update_begin(&tp->tx_stats.syncp); + tp->tx_stats.packets++; + tp->tx_stats.bytes += tx_skb->skb->len; + u64_stats_update_end(&tp->tx_stats.syncp); + dev_kfree_skb(tx_skb->skb); tx_skb->skb = NULL; } dirty_tx++; tx_left--; } - u64_stats_update_begin(&tx_stats->syncp); - tx_stats->packets += txc.packets; - tx_stats->bytes += txc.bytes; - u64_stats_update_end(&tx_stats->syncp); - - netdev_completed_queue(dev, txc.packets, txc.bytes); - if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; /* Sync with rtl8169_start_xmit: From 2138dede8c23f5646c81381c71aac37e67b491b0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 24 Jul 2012 02:42:14 +0000 Subject: [PATCH 0614/2357] caif: fix NULL pointer check [ Upstream commit c66b9b7d365444b433307ebb18734757cb668a02 ] Reported-by: Resolves-bug: http://bugzilla.kernel.org/show_bug?44441 Signed-off-by: Alan Cox Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/caif/caif_serial.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 8a3054b8481..5de74e76202 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -325,6 +325,9 @@ static int ldisc_open(struct tty_struct *tty) sprintf(name, "cf%s", tty->name); dev = alloc_netdev(sizeof(*ser), name, caifdev_setup); + if (!dev) + return -ENOMEM; + ser = netdev_priv(dev); ser->tty = tty_kref_get(tty); ser->dev = dev; From 1a8634186c17426f79c3bfcbc4fab75aa0f53c3b Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 24 Jul 2012 08:16:25 +0000 Subject: [PATCH 0615/2357] wanmain: comparing array with NULL [ Upstream commit 8b72ff6484fe303e01498b58621810a114f3cf09 ] gcc really should warn about these ! Signed-off-by: Alan Cox Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/wanrouter/wanmain.c | 51 +++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 788a12c1eb5..2ab785064b7 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -602,36 +602,31 @@ static int wanrouter_device_new_if(struct wan_device *wandev, * successfully, add it to the interface list. */ - if (dev->name == NULL) { - err = -EINVAL; - } else { +#ifdef WANDEBUG + printk(KERN_INFO "%s: registering interface %s...\n", + wanrouter_modname, dev->name); +#endif - #ifdef WANDEBUG - printk(KERN_INFO "%s: registering interface %s...\n", - wanrouter_modname, dev->name); - #endif - - err = register_netdev(dev); - if (!err) { - struct net_device *slave = NULL; - unsigned long smp_flags=0; - - lock_adapter_irq(&wandev->lock, &smp_flags); - - if (wandev->dev == NULL) { - wandev->dev = dev; - } else { - for (slave=wandev->dev; - DEV_TO_SLAVE(slave); - slave = DEV_TO_SLAVE(slave)) - DEV_TO_SLAVE(slave) = dev; - } - ++wandev->ndev; - - unlock_adapter_irq(&wandev->lock, &smp_flags); - err = 0; /* done !!! */ - goto out; + err = register_netdev(dev); + if (!err) { + struct net_device *slave = NULL; + unsigned long smp_flags=0; + + lock_adapter_irq(&wandev->lock, &smp_flags); + + if (wandev->dev == NULL) { + wandev->dev = dev; + } else { + for (slave=wandev->dev; + DEV_TO_SLAVE(slave); + slave = DEV_TO_SLAVE(slave)) + DEV_TO_SLAVE(slave) = dev; } + ++wandev->ndev; + + unlock_adapter_irq(&wandev->lock, &smp_flags); + err = 0; /* done !!! */ + goto out; } if (wandev->del_if) wandev->del_if(wandev, dev); From ac6b310c5f5ecd6154e07069c6b6b67b7e768d8b Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 26 Jul 2012 22:52:21 +0000 Subject: [PATCH 0616/2357] tcp: Add TCP_USER_TIMEOUT negative value check [ Upstream commit 42493570100b91ef663c4c6f0c0fdab238f9d3c2 ] TCP_USER_TIMEOUT is a TCP level socket option that takes an unsigned int. But patch "tcp: Add TCP_USER_TIMEOUT socket option"(dca43c75) didn't check the negative values. If a user assign -1 to it, the socket will set successfully and wait for 4294967295 miliseconds. This patch add a negative value check to avoid this issue. Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 6589e11d57b..d6feb1ef4f2 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2408,7 +2408,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, /* Cap the max timeout in ms TCP will retry/retrans * before giving up and aborting (ETIMEDOUT) a connection. */ - icsk->icsk_user_timeout = msecs_to_jiffies(val); + if (val < 0) + err = -EINVAL; + else + icsk->icsk_user_timeout = msecs_to_jiffies(val); break; default: err = -ENOPROTOOPT; From e5481652427aa25fc74b45d755ff678df33601c1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 27 Jul 2012 01:46:51 +0000 Subject: [PATCH 0617/2357] USB: kaweth.c: use GFP_ATOMIC under spin_lock [ Upstream commit e4c7f259c5be99dcfc3d98f913590663b0305bf8 ] The problem is that we call this with a spin lock held. The call tree is: kaweth_start_xmit() holds kaweth->device_lock. -> kaweth_async_set_rx_mode() -> kaweth_control() -> kaweth_internal_control_msg() The kaweth_internal_control_msg() function is only called from kaweth_control() which used GFP_ATOMIC for its allocations. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/kaweth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index df2a2cf35a9..7a6ccd6c3b4 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -1302,7 +1302,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, int retv; int length = 0; /* shut up GCC */ - urb = usb_alloc_urb(0, GFP_NOIO); + urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; From 202a3667cfc09edca2338a1fb5d6ffb0dddc9bcc Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Fri, 27 Jul 2012 02:58:22 +0000 Subject: [PATCH 0618/2357] net: fix rtnetlink IFF_PROMISC and IFF_ALLMULTI handling [ Upstream commit b1beb681cba5358f62e6187340660ade226a5fcc ] When device flags are set using rtnetlink, IFF_PROMISC and IFF_ALLMULTI flags are handled specially. Function dev_change_flags sets IFF_PROMISC and IFF_ALLMULTI bits in dev->gflags according to the passed value but do_setlink passes a result of rtnl_dev_combine_flags which takes those bits from dev->flags. This can be easily trigerred by doing: tcpdump -i eth0 & ip l s up eth0 ip sets IFF_UP flag in ifi_flags and ifi_change, which is combined with IFF_PROMISC by rtnl_dev_combine_flags, causing __dev_change_flags to set IFF_PROMISC in gflags. Reported-by: Max Matveev Signed-off-by: Jiri Benc Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/rtnetlink.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 90430b776ec..b8052bab69c 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -671,6 +671,12 @@ static void set_operstate(struct net_device *dev, unsigned char transition) } } +static unsigned int rtnl_dev_get_flags(const struct net_device *dev) +{ + return (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI)) | + (dev->gflags & (IFF_PROMISC | IFF_ALLMULTI)); +} + static unsigned int rtnl_dev_combine_flags(const struct net_device *dev, const struct ifinfomsg *ifm) { @@ -679,7 +685,7 @@ static unsigned int rtnl_dev_combine_flags(const struct net_device *dev, /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ if (ifm->ifi_change) flags = (flags & ifm->ifi_change) | - (dev->flags & ~ifm->ifi_change); + (rtnl_dev_get_flags(dev) & ~ifm->ifi_change); return flags; } From 2ce42ec4ef551b08d2e5d26775d838ac640f82ad Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 27 Jul 2012 10:38:50 +0000 Subject: [PATCH 0619/2357] tcp: perform DMA to userspace only if there is a task waiting for it [ Upstream commit 59ea33a68a9083ac98515e4861c00e71efdc49a1 ] Back in 2006, commit 1a2449a87b ("[I/OAT]: TCP recv offload to I/OAT") added support for receive offloading to IOAT dma engine if available. The code in tcp_rcv_established() tries to perform early DMA copy if applicable. It however does so without checking whether the userspace task is actually expecting the data in the buffer. This is not a problem under normal circumstances, but there is a corner case where this doesn't work -- and that's when MSG_TRUNC flag to recvmsg() is used. If the IOAT dma engine is not used, the code properly checks whether there is a valid ucopy.task and the socket is owned by userspace, but misses the check in the dmaengine case. This problem can be observed in real trivially -- for example 'tbench' is a good reproducer, as it makes a heavy use of MSG_TRUNC. On systems utilizing IOAT, you will soon find tbench waiting indefinitely in sk_wait_data(), as they have been already early-copied in tcp_rcv_established() using dma engine. This patch introduces the same check we are performing in the simple iovec copy case to the IOAT case as well. It fixes the indefinite recvmsg(MSG_TRUNC) hangs. Signed-off-by: Jiri Kosina Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 257b61789ee..56a9c8d0bef 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5441,7 +5441,9 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, if (tp->copied_seq == tp->rcv_nxt && len - tcp_header_len <= tp->ucopy.len) { #ifdef CONFIG_NET_DMA - if (tcp_dma_try_early_copy(sk, skb, tcp_header_len)) { + if (tp->ucopy.task == current && + sock_owned_by_user(sk) && + tcp_dma_try_early_copy(sk, skb, tcp_header_len)) { copied_early = 1; eaten = 1; } From 143d9963df6580491f9a5c38c9d4883786f78123 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 29 Jul 2012 19:45:14 +0000 Subject: [PATCH 0620/2357] net/tun: fix ioctl() based info leaks [ Upstream commits a117dacde0288f3ec60b6e5bcedae8fa37ee0dfc and 8bbb181308bc348e02bfdbebdedd4e4ec9d452ce ] The tun module leaks up to 36 bytes of memory by not fully initializing a structure located on the stack that gets copied to user memory by the TUNGETIFF and SIOCGIFHWADDR ioctl()s. Signed-off-by: Mathias Krause Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/tun.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index a06ad55d949..8f13420dd31 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1255,10 +1255,12 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, int vnet_hdr_sz; int ret; - if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) + if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) { if (copy_from_user(&ifr, argp, ifreq_len)) return -EFAULT; - + } else { + memset(&ifr, 0, sizeof(ifr)); + } if (cmd == TUNGETFEATURES) { /* Currently this just means: "what IFF flags are valid?". * This is needed because we never checked for invalid flags on From 6091e5bc36cc2d74b2c5ab1ae2dcf32cf82e242f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 30 Jul 2012 16:06:42 +0100 Subject: [PATCH 0621/2357] USB: echi-dbgp: increase the controller wait time to come out of halt. commit f96a4216e85050c0a9d41a41ecb0ae9d8e39b509 upstream. The default 10 microsecond delay for the controller to come out of halt in dbgp_ehci_startup is too short, so increase it to 1 millisecond. This is based on emperical testing on various USB debug ports on modern machines such as a Lenovo X220i and an Ivybridge development platform that needed to wait ~450-950 microseconds. Signed-off-by: Colin Ian King Signed-off-by: Jason Wessel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/early/ehci-dbgp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 1fc8f124980..347bb058e1e 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -450,7 +450,7 @@ static int dbgp_ehci_startup(void) writel(FLAG_CF, &ehci_regs->configured_flag); /* Wait until the controller is no longer halted */ - loop = 10; + loop = 1000; do { status = readl(&ehci_regs->status); if (!(status & STS_HALT)) From 6fc6d9aea32a459f96ac8678f3e25170a6a8cfa9 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 1 Aug 2012 10:16:53 +0200 Subject: [PATCH 0622/2357] ALSA: snd-usb: fix clock source validity index commit aff252a848ce21b431ba822de3dab9c4c94571cb upstream. uac_clock_source_is_valid() uses the control selector value to access the bmControls bitmap of the clock source unit. This is wrong, as control selector values start from 1, while the bitmap uses all available bits. In other words, "Clock Validity Control" is stored in D3..2, not D5..4 of the clock selector unit's bmControls. Signed-off-by: Daniel Mack Reported-by: Andreas Koch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/clock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 379baad3d5a..5e634a2eb28 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -111,7 +111,8 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) return 0; /* If a clock source can't tell us whether it's valid, we assume it is */ - if (!uac2_control_is_readable(cs_desc->bmControls, UAC2_CS_CONTROL_CLOCK_VALID)) + if (!uac2_control_is_readable(cs_desc->bmControls, + UAC2_CS_CONTROL_CLOCK_VALID - 1)) return 1; err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, From e25824fa92d90e667b4285eddf7da11c541691a0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Jul 2012 11:35:55 +0200 Subject: [PATCH 0623/2357] ALSA: mpu401: Fix missing initialization of irq field commit bc733d495267a23ef8660220d696c6e549ce30b3 upstream. The irq field of struct snd_mpu401 is supposed to be initialized to -1. Since it's set to zero as of now, a probing error before the irq installation results in a kernel warning "Trying to free already-free IRQ 0". Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=44821 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/mpu401/mpu401_uart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 1cff331a228..4608c2ca43f 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -554,6 +554,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, spin_lock_init(&mpu->output_lock); spin_lock_init(&mpu->timer_lock); mpu->hardware = hardware; + mpu->irq = -1; if (! (info_flags & MPU401_INFO_INTEGRATED)) { int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; mpu->res = request_region(port, res_size, "MPU401 UART"); From ac1d1b446e2e93305611126caa2252c8243f087f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Jul 2012 13:54:55 +0200 Subject: [PATCH 0624/2357] ALSA: hda - Fix invalid D3 of headphone DAC on VT202x codecs commit 6162552b0de6ba80937c3dd53e084967851cd199 upstream. We've got a bug report about the silent output from the headphone on a mobo with VT2021, and spotted out that this was because of the wrong D3 state on the DAC for the headphone output. The bug is triggered by the incomplete check for this DAC in set_widgets_power_state_vt1718S(). It checks only the connectivity of the primary output (0x27) but doesn't consider the path from the headphone pin (0x28). Now this patch fixes the problem by checking both pins for DAC 0x0b. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_via.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 06214fdc948..3998d09bf24 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -3233,7 +3233,7 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int imux_is_smixer; - unsigned int parm; + unsigned int parm, parm2; /* MUX6 (1eh) = stereo mixer */ imux_is_smixer = snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; @@ -3256,7 +3256,7 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) parm = AC_PWRST_D3; set_pin_power_state(codec, 0x27, &parm); update_power_state(codec, 0x1a, parm); - update_power_state(codec, 0xb, parm); + parm2 = parm; /* for pin 0x0b */ /* PW2 (26h), AOW2 (ah) */ parm = AC_PWRST_D3; @@ -3271,6 +3271,9 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) if (!spec->hp_independent_mode) /* check for redirected HP */ set_pin_power_state(codec, 0x28, &parm); update_power_state(codec, 0x8, parm); + if (!spec->hp_independent_mode && parm2 != AC_PWRST_D3) + parm = parm2; + update_power_state(codec, 0xb, parm); /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ update_power_state(codec, 0x21, imux_is_smixer ? AC_PWRST_D0 : parm); From 09f7d3b6fa3511eb0975fb40cda48f032942f49d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jul 2012 08:17:20 +0200 Subject: [PATCH 0625/2357] ALSA: hda - Fix mute-LED GPIO setup for HP Mini 210 commit a3e199732b8e2b272e82cc1ccc49c35239ed6c5a upstream. BIOS on HP Mini 210 doesn't provide the proper "HP_Mute_LED" DMI string, thus the driver doesn't initialize the GPIO, too. In the earlier kernel, the driver falls back to GPIO1, but since 3.3 we've stopped this due to other wrongly advertised machines. For fixing this particular case, add a new model type to specify the default polarity explicitly so that the fallback to GPIO1 is handled. Bugzilla: https://bugzilla.novell.com/show_bug.cgi?id=772923 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7494fbc1f26..dd83712fd74 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -100,6 +100,7 @@ enum { STAC_92HD83XXX_HP_cNB11_INTQUAD, STAC_HP_DV7_4000, STAC_HP_ZEPHYR, + STAC_92HD83XXX_HP_LED, STAC_92HD83XXX_MODELS }; @@ -1672,6 +1673,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad", [STAC_HP_DV7_4000] = "hp-dv7-4000", [STAC_HP_ZEPHYR] = "hp-zephyr", + [STAC_92HD83XXX_HP_LED] = "hp-led", }; static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -1726,6 +1728,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561, "HP", STAC_HP_ZEPHYR), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660, + "HP Mini", STAC_92HD83XXX_HP_LED), {} /* terminator */ }; @@ -5528,6 +5532,7 @@ static void stac92hd8x_fill_auto_spec(struct hda_codec *codec) static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; + int default_polarity = -1; /* no default cfg */ int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -5576,9 +5581,12 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) case STAC_HP_ZEPHYR: spec->init = stac92hd83xxx_hp_zephyr_init; break; + case STAC_92HD83XXX_HP_LED: + default_polarity = 1; + break; } - if (find_mute_led_cfg(codec, -1/*no default cfg*/)) + if (find_mute_led_cfg(codec, default_polarity)) snd_printd("mute LED gpio %d polarity %d\n", spec->gpio_led, spec->gpio_led_polarity); From 22e0422852d3aa14ad9f1793b8d7cb9e74b81608 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jul 2012 10:16:59 +0200 Subject: [PATCH 0626/2357] ALSA: hda - Fix polarity of mute LED on HP Mini 210 commit ff8a1e274cbc11da6b57849f925b895a212b56c9 upstream. The commit a3e199732b made the LED working again on HP Mini 210 but with a wrong polarity. This patch fixes the polarity for this machine, and also introduce a new model string "hp-inv-led". Bugzilla: https://bugzilla.novell.com/show_bug.cgi?id=772923 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index dd83712fd74..cf41d9219a6 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -101,6 +101,7 @@ enum { STAC_HP_DV7_4000, STAC_HP_ZEPHYR, STAC_92HD83XXX_HP_LED, + STAC_92HD83XXX_HP_INV_LED, STAC_92HD83XXX_MODELS }; @@ -1674,6 +1675,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_HP_DV7_4000] = "hp-dv7-4000", [STAC_HP_ZEPHYR] = "hp-zephyr", [STAC_92HD83XXX_HP_LED] = "hp-led", + [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", }; static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -5582,6 +5584,9 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->init = stac92hd83xxx_hp_zephyr_init; break; case STAC_92HD83XXX_HP_LED: + default_polarity = 0; + break; + case STAC_92HD83XXX_HP_INV_LED: default_polarity = 1; break; } From 2a69bac35f3667f380d83ca5ed5b880ee7133154 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jul 2012 10:40:05 +0200 Subject: [PATCH 0627/2357] ALSA: hda - Fix mute-LED GPIO initialization for IDT codecs commit 1f43f6c1bc8d740e75b4177eb29110858bb5fea2 upstream. The IDT codecs initializes the GPIO setup for mute LEDs via snd_hda_sync_vmaster_hook(). This works in most cases except for the very first call, which is called before PCM and control creations. Thus before Master switch is set manually via alsactl, the mute LED may show the wrong state, depending on the polarity. Now it's fixed by calling the LED-status update function manually when no vmaster is set yet. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index cf41d9219a6..fd533124417 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4437,7 +4437,13 @@ static int stac92xx_init(struct hda_codec *codec) snd_hda_jack_report_sync(codec); /* sync mute LED */ - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); + if (spec->gpio_led) { + if (spec->vmaster_mute.hook) + snd_hda_sync_vmaster_hook(&spec->vmaster_mute); + else /* the very first init call doesn't have vmaster yet */ + stac92xx_update_led_status(codec, false); + } + if (spec->dac_list) stac92xx_power_down(codec); return 0; From 7dcb3c5de76a8516e7f2391dfbab2727f69ed010 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Aug 2012 09:04:39 +0200 Subject: [PATCH 0628/2357] ALSA: hda - Support dock on Lenovo Thinkpad T530 with ALC269VC commit 707fba3fa76a4c8855552f5d4c1a12430c09bce8 upstream. Lenovo Thinkpad T530 with ALC269VC codec has a dock port but BIOS doesn't set up the pins properly. Enable the pins as well as on Thinkpad X230 Tablet. Reported-and-tested-by: Mario Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 88ccc0f62b1..62e1627acda 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6156,6 +6156,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), From 9966af8a7ac83cdc9aa5a054e843fdecc6689aa0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 30 Jul 2012 18:24:19 +0100 Subject: [PATCH 0629/2357] ASoC: wm8962: Allow VMID time to fully ramp commit 9d40e5582c9c4cfb6977ba2a0ca9c2ed82c56f21 upstream. Required for reliable power up from cold. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8962.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 08850f8fdb5..96f6f9faa82 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2488,6 +2488,9 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, /* VMID 2*250k */ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, WM8962_VMID_SEL_MASK, 0x100); + + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + msleep(100); break; case SND_SOC_BIAS_OFF: From 8f32469c980654a17e935dae06a3557b488910a4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 22 Jun 2012 17:21:17 +0100 Subject: [PATCH 0630/2357] ASoC: wm8994: Ensure there are enough BCLKs for four channels commit b8edf3e5522735c8ce78b81845f7a1a2d4a08626 upstream. Otherwise if someone tries to use all four channels on AIF1 with the device in master mode we won't be able to clock out all the data. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8994.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index f351b933f5c..4c471a54893 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2695,7 +2695,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - bclk_rate = params_rate(params) * 2; + bclk_rate = params_rate(params) * 4; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: bclk_rate *= 16; From 727cda365f7007f75a402f38ecd8bbf88a874e8f Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Sat, 28 Jul 2012 00:20:34 +0200 Subject: [PATCH 0631/2357] m68k: Make sys_atomic_cmpxchg_32 work on classic m68k commit 9e2760d18b3cf179534bbc27692c84879c61b97c upstream. User space access must always go through uaccess accessors, since on classic m68k user space and kernel space are completely separate. Signed-off-by: Andreas Schwab Tested-by: Thorsten Glaser Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- arch/m68k/kernel/sys_m68k.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 8623f8dc16f..9a5932ec368 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -479,9 +479,13 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5, goto bad_access; } - mem_value = *mem; + /* + * No need to check for EFAULT; we know that the page is + * present and writable. + */ + __get_user(mem_value, mem); if (mem_value == oldval) - *mem = newval; + __put_user(newval, mem); pte_unmap_unlock(pte, ptl); up_read(&mm->mmap_sem); From ef2e080c19599e3d0844f3bc599ee5dd627fc850 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Thu, 19 Apr 2012 00:53:36 +0200 Subject: [PATCH 0632/2357] m68k: Correct the Atari ALLOWINT definition commit c663600584a596b5e66258cc10716fb781a5c2c9 upstream. Booting a 3.2, 3.3, or 3.4-rc4 kernel on an Atari using the `nfeth' ethernet device triggers a WARN_ONCE() in generic irq handling code on the first irq for that device: WARNING: at kernel/irq/handle.c:146 handle_irq_event_percpu+0x134/0x142() irq 3 handler nfeth_interrupt+0x0/0x194 enabled interrupts Modules linked in: Call Trace: [<000299b2>] warn_slowpath_common+0x48/0x6a [<000299c0>] warn_slowpath_common+0x56/0x6a [<00029a4c>] warn_slowpath_fmt+0x2a/0x32 [<0005b34c>] handle_irq_event_percpu+0x134/0x142 [<0005b34c>] handle_irq_event_percpu+0x134/0x142 [<0000a584>] nfeth_interrupt+0x0/0x194 [<001ba0a8>] schedule_preempt_disabled+0x0/0xc [<0005b37a>] handle_irq_event+0x20/0x2c [<0005add4>] generic_handle_irq+0x2c/0x3a [<00002ab6>] do_IRQ+0x20/0x32 [<0000289e>] auto_irqhandler_fixup+0x4/0x6 [<00003144>] cpu_idle+0x22/0x2e [<001b8a78>] printk+0x0/0x18 [<0024d112>] start_kernel+0x37a/0x386 [<0003021d>] __do_proc_dointvec+0xb1/0x366 [<0003021d>] __do_proc_dointvec+0xb1/0x366 [<0024c31e>] _sinittext+0x31e/0x9c0 After invoking the irq's handler the kernel sees !irqs_disabled() and concludes that the handler erroneously enabled interrupts. However, debugging shows that !irqs_disabled() is true even before the handler is invoked, which indicates a problem in the platform code rather than the specific driver. The warning does not occur in 3.1 or older kernels. It turns out that the ALLOWINT definition for Atari is incorrect. The Atari definition of ALLOWINT is ~0x400, the stated purpose of that is to avoid taking HSYNC interrupts. irqs_disabled() returns true if the 3-bit ipl & 4 is non-zero. The nfeth interrupt runs at ipl 3 (it's autovector 3), but 3 & 4 is zero so irqs_disabled() is false, and the warning above is generated. When interrupts are explicitly disabled, ipl is set to 7. When they are enabled, ipl is masked with ALLOWINT. On Atari this will result in ipl = 3, which blocks interrupts at ipl 3 and below. So how come nfeth interrupts at ipl 3 are received at all? That's because ipl is reset to 2 by Atari-specific code in default_idle(), again with the stated purpose of blocking HSYNC interrupts. This discrepancy means that ipl 3 can remain blocked for longer than intended. Both default_idle() and falcon_hblhandler() identify HSYNC with ipl 2, and the "Atari ST/.../F030 Hardware Register Listing" agrees, but ALLOWINT is defined as if HSYNC was ipl 3. [As an experiment I modified default_idle() to reset ipl to 3, and as expected that resulted in all nfeth interrupts being blocked.] The fix is simple: define ALLOWINT as ~0x500 instead. This makes arch_local_irq_enable() consistent with default_idle(), and prevents the !irqs_disabled() problems for ipl 3 interrupts. Tested on Atari running in an Aranym VM. Signed-off-by: Mikael Pettersson Tested-by: Michael Schmitz Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- arch/m68k/include/asm/entry.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/m68k/include/asm/entry.h b/arch/m68k/include/asm/entry.h index 622138dc728..34c25209b66 100644 --- a/arch/m68k/include/asm/entry.h +++ b/arch/m68k/include/asm/entry.h @@ -33,8 +33,8 @@ /* the following macro is used when enabling interrupts */ #if defined(MACH_ATARI_ONLY) - /* block out HSYNC on the atari */ -#define ALLOWINT (~0x400) + /* block out HSYNC = ipl 2 on the atari */ +#define ALLOWINT (~0x500) #define MAX_NOINT_IPL 3 #else /* portable version */ From d48c1ba2979634ecbbe344a8bd65035f32777f1b Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 20 Jul 2012 11:53:29 -0700 Subject: [PATCH 0633/2357] futex: Test for pi_mutex on fault in futex_wait_requeue_pi() commit b6070a8d9853eda010a549fa9a09eb8d7269b929 upstream. If fixup_pi_state_owner() faults, pi_mutex may be NULL. Test for pi_mutex != NULL before testing the owner against current and possibly unlocking it. Signed-off-by: Darren Hart Cc: Dave Jones Cc: Dan Carpenter Link: http://lkml.kernel.org/r/dc59890338fc413606f04e5c5b131530734dae3d.1342809673.git.dvhart@linux.intel.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/futex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/futex.c b/kernel/futex.c index e2b0fb9a0b3..05018bfe21a 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2370,7 +2370,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, * fault, unlock the rt_mutex and return the fault to userspace. */ if (ret == -EFAULT) { - if (rt_mutex_owner(pi_mutex) == current) + if (pi_mutex && rt_mutex_owner(pi_mutex) == current) rt_mutex_unlock(pi_mutex); } else if (ret == -EINTR) { /* From 47b6ff731a701d898c732e2f2dd67c5178fc0960 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 20 Jul 2012 11:53:30 -0700 Subject: [PATCH 0634/2357] futex: Fix bug in WARN_ON for NULL q.pi_state commit f27071cb7fe3e1d37a9dbe6c0dfc5395cd40fa43 upstream. The WARN_ON in futex_wait_requeue_pi() for a NULL q.pi_state was testing the address (&q.pi_state) of the pointer instead of the value (q.pi_state) of the pointer. Correct it accordingly. Signed-off-by: Darren Hart Cc: Dave Jones Link: http://lkml.kernel.org/r/1c85d97f6e5f79ec389a4ead3e367363c74bd09a.1342809673.git.dvhart@linux.intel.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/futex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/futex.c b/kernel/futex.c index 05018bfe21a..5551adaf7cd 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2343,7 +2343,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, * signal. futex_unlock_pi() will not destroy the lock_ptr nor * the pi_state. */ - WARN_ON(!&q.pi_state); + WARN_ON(!q.pi_state); pi_mutex = &q.pi_state->pi_mutex; ret = rt_mutex_finish_proxy_lock(pi_mutex, to, &rt_waiter, 1); debug_rt_mutex_free_waiter(&rt_waiter); From b3f9576e98e0dfb4f9be87618da4c5f6e8640ee0 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 20 Jul 2012 11:53:31 -0700 Subject: [PATCH 0635/2357] futex: Forbid uaddr == uaddr2 in futex_wait_requeue_pi() commit 6f7b0a2a5c0fb03be7c25bd1745baa50582348ef upstream. If uaddr == uaddr2, then we have broken the rule of only requeueing from a non-pi futex to a pi futex with this call. If we attempt this, as the trinity test suite manages to do, we miss early wakeups as q.key is equal to key2 (because they are the same uaddr). We will then attempt to dereference the pi_mutex (which would exist had the futex_q been properly requeued to a pi futex) and trigger a NULL pointer dereference. Signed-off-by: Darren Hart Cc: Dave Jones Link: http://lkml.kernel.org/r/ad82bfe7f7d130247fbe2b5b4275654807774227.1342809673.git.dvhart@linux.intel.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/futex.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 5551adaf7cd..3717e7b306e 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2231,11 +2231,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, * @uaddr2: the pi futex we will take prior to returning to user-space * * The caller will wait on uaddr and will be requeued by futex_requeue() to - * uaddr2 which must be PI aware. Normal wakeup will wake on uaddr2 and - * complete the acquisition of the rt_mutex prior to returning to userspace. - * This ensures the rt_mutex maintains an owner when it has waiters; without - * one, the pi logic wouldn't know which task to boost/deboost, if there was a - * need to. + * uaddr2 which must be PI aware and unique from uaddr. Normal wakeup will wake + * on uaddr2 and complete the acquisition of the rt_mutex prior to returning to + * userspace. This ensures the rt_mutex maintains an owner when it has waiters; + * without one, the pi logic would not know which task to boost/deboost, if + * there was a need to. * * We call schedule in futex_wait_queue_me() when we enqueue and return there * via the following: @@ -2272,6 +2272,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, struct futex_q q = futex_q_init; int res, ret; + if (uaddr == uaddr2) + return -EINVAL; + if (!bitset) return -EINVAL; From 8067fa23092f2c4e18c29c90f7d5bb765dbf8954 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 9 Aug 2012 08:32:11 -0700 Subject: [PATCH 0636/2357] Linux 3.4.8 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e17a98c3ea5..a3c0c43a71d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 7 +SUBLEVEL = 8 EXTRAVERSION = NAME = Saber-toothed Squirrel From 5eaac83b7362a1944afde7e867e53c7135e36d68 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Thu, 26 Jul 2012 10:55:26 -0700 Subject: [PATCH 0637/2357] Redefine ATOMIC_INIT and ATOMIC64_INIT to drop the casts commit a119365586b0130dfea06457f584953e0ff6481d upstream. The following build error occured during a ia64 build with swap-over-NFS patches applied. net/core/sock.c:274:36: error: initializer element is not constant net/core/sock.c:274:36: error: (near initialization for 'memalloc_socks') net/core/sock.c:274:36: error: initializer element is not constant This is identical to a parisc build error. Fengguang Wu, Mel Gorman and James Bottomley did all the legwork to track the root cause of the problem. This fix and entire commit log is shamelessly copied from them with one extra detail to change a dubious runtime use of ATOMIC_INIT() to atomic_set() in drivers/char/mspec.c Dave Anglin says: > Here is the line in sock.i: > > struct static_key memalloc_socks = ((struct static_key) { .enabled = > ((atomic_t) { (0) }) }); The above line contains two compound literals. It also uses a designated initializer to initialize the field enabled. A compound literal is not a constant expression. The location of the above statement isn't fully clear, but if a compound literal occurs outside the body of a function, the initializer list must consist of constant expressions. Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman --- arch/ia64/include/asm/atomic.h | 4 ++-- drivers/char/mspec.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index 7d9116600a3..6e6fe1839f5 100644 --- a/arch/ia64/include/asm/atomic.h +++ b/arch/ia64/include/asm/atomic.h @@ -17,8 +17,8 @@ #include -#define ATOMIC_INIT(i) ((atomic_t) { (i) }) -#define ATOMIC64_INIT(i) ((atomic64_t) { (i) }) +#define ATOMIC_INIT(i) { (i) } +#define ATOMIC64_INIT(i) { (i) } #define atomic_read(v) (*(volatile int *)&(v)->counter) #define atomic64_read(v) (*(volatile long *)&(v)->counter) diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 8b78750f1ef..845f97fd183 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -283,7 +283,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, vdata->flags = flags; vdata->type = type; spin_lock_init(&vdata->lock); - vdata->refcnt = ATOMIC_INIT(1); + atomic_set(&vdata->refcnt, 1); vma->vm_private_data = vdata; vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND); From 88cdb96565315a7e127a1fcd6a8e2d1374be9aa2 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 20 Jun 2012 11:47:35 +0800 Subject: [PATCH 0638/2357] asus-wmi: use ASUS_WMI_METHODID_DSTS2 as default DSTS ID. commit 63a78bb1051b240417daad3a3fa9c1bb10646dca upstream. According to responses from the BIOS team, ASUS_WMI_METHODID_DSTS2 (0x53545344) will be used as future DSTS ID. In addition, calling asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL) returns ASUS_WMI_UNSUPPORTED_METHOD in new ASUS laptop PCs. This patch fixes no DSTS ID will be assigned in this case. Signed-off-by: Alex Hung Signed-off-by: Matthew Garrett Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/asus-wmi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 77aadde5281..556cbb455ed 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1467,14 +1467,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus) */ if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL)) asus->dsts_id = ASUS_WMI_METHODID_DSTS; - else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL)) + else asus->dsts_id = ASUS_WMI_METHODID_DSTS2; - if (!asus->dsts_id) { - pr_err("Can't find DSTS"); - return -ENODEV; - } - /* CWAP allow to define the behavior of the Fn+F2 key, * this method doesn't seems to be present on Eee PCs */ if (asus->driver->quirks->wapf >= 0) From 613975f7a65f75b6e720bfca721d2d99542c53b8 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 18 Jul 2012 11:17:11 -0700 Subject: [PATCH 0639/2357] sunrpc: clnt: Add missing braces commit cac5d07e3ca696dcacfb123553cf6c722111cfd3 upstream. Add a missing set of braces that commit 4e0038b6b24 ("SUNRPC: Move clnt->cl_server into struct rpc_xprt") forgot. Signed-off-by: Joe Perches Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/clnt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 25302c80246..57f2731d957 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1846,12 +1846,13 @@ call_timeout(struct rpc_task *task) return; } if (RPC_IS_SOFT(task)) { - if (clnt->cl_chatty) + if (clnt->cl_chatty) { rcu_read_lock(); printk(KERN_NOTICE "%s: server %s not responding, timed out\n", clnt->cl_protname, rcu_dereference(clnt->cl_xprt)->servername); rcu_read_unlock(); + } if (task->tk_flags & RPC_TASK_TIMEOUT) rpc_exit(task, -ETIMEDOUT); else From d281dc7448010256bf2e23a65e10a4f6fc786284 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 20 Jul 2012 15:57:48 +0400 Subject: [PATCH 0640/2357] SUNRPC: return negative value in case rpcbind client creation error commit caea33da898e4e14f0ba58173e3b7689981d2c0b upstream. Without this patch kernel will panic on LockD start, because lockd_up() checks lockd_up_net() result for negative value. From my pow it's better to return negative value from rpcbind routines instead of replacing all such checks like in lockd_up(). Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/rpcb_clnt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 4c38b33ab8a..4d53ad5220f 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -251,7 +251,7 @@ static int rpcb_create_local_unix(struct net *net) if (IS_ERR(clnt)) { dprintk("RPC: failed to create AF_LOCAL rpcbind " "client (errno %ld).\n", PTR_ERR(clnt)); - result = -PTR_ERR(clnt); + result = PTR_ERR(clnt); goto out; } @@ -298,7 +298,7 @@ static int rpcb_create_local_net(struct net *net) if (IS_ERR(clnt)) { dprintk("RPC: failed to create local rpcbind " "client (errno %ld).\n", PTR_ERR(clnt)); - result = -PTR_ERR(clnt); + result = PTR_ERR(clnt); goto out; } From d7c61cba59ebdb18ebe357b7952f61e4100c2d92 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 30 Jul 2012 14:42:07 -0700 Subject: [PATCH 0641/2357] nilfs2: fix deadlock issue between chcp and thaw ioctls commit 572d8b3945a31bee7c40d21556803e4807fd9141 upstream. An fs-thaw ioctl causes deadlock with a chcp or mkcp -s command: chcp D ffff88013870f3d0 0 1325 1324 0x00000004 ... Call Trace: nilfs_transaction_begin+0x11c/0x1a0 [nilfs2] wake_up_bit+0x20/0x20 copy_from_user+0x18/0x30 [nilfs2] nilfs_ioctl_change_cpmode+0x7d/0xcf [nilfs2] nilfs_ioctl+0x252/0x61a [nilfs2] do_page_fault+0x311/0x34c get_unmapped_area+0x132/0x14e do_vfs_ioctl+0x44b/0x490 __set_task_blocked+0x5a/0x61 vm_mmap_pgoff+0x76/0x87 __set_current_blocked+0x30/0x4a sys_ioctl+0x4b/0x6f system_call_fastpath+0x16/0x1b thaw D ffff88013870d890 0 1352 1351 0x00000004 ... Call Trace: rwsem_down_failed_common+0xdb/0x10f call_rwsem_down_write_failed+0x13/0x20 down_write+0x25/0x27 thaw_super+0x13/0x9e do_vfs_ioctl+0x1f5/0x490 vm_mmap_pgoff+0x76/0x87 sys_ioctl+0x4b/0x6f filp_close+0x64/0x6c system_call_fastpath+0x16/0x1b where the thaw ioctl deadlocked at thaw_super() when called while chcp was waiting at nilfs_transaction_begin() called from nilfs_ioctl_change_cpmode(). This deadlock is 100% reproducible. This is because nilfs_ioctl_change_cpmode() first locks sb->s_umount in read mode and then waits for unfreezing in nilfs_transaction_begin(), whereas thaw_super() locks sb->s_umount in write mode. The locking of sb->s_umount here was intended to make snapshot mounts and the downgrade of snapshots to checkpoints exclusive. This fixes the deadlock issue by replacing the sb->s_umount usage in nilfs_ioctl_change_cpmode() with a dedicated mutex which protects snapshot mounts. Signed-off-by: Ryusuke Konishi Cc: Fernando Luis Vazquez Cao Tested-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/nilfs2/ioctl.c | 4 ++-- fs/nilfs2/super.c | 3 +++ fs/nilfs2/the_nilfs.c | 1 + fs/nilfs2/the_nilfs.h | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 2a70fce70c6..6fe98ed5854 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -182,7 +182,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, if (copy_from_user(&cpmode, argp, sizeof(cpmode))) goto out; - down_read(&inode->i_sb->s_umount); + mutex_lock(&nilfs->ns_snapshot_mount_mutex); nilfs_transaction_begin(inode->i_sb, &ti, 0); ret = nilfs_cpfile_change_cpmode( @@ -192,7 +192,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, else nilfs_transaction_commit(inode->i_sb); /* never fails */ - up_read(&inode->i_sb->s_umount); + mutex_unlock(&nilfs->ns_snapshot_mount_mutex); out: mnt_drop_write_file(filp); return ret; diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1099a76cee5..496904b96b2 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -948,6 +948,8 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, struct nilfs_root *root; int ret; + mutex_lock(&nilfs->ns_snapshot_mount_mutex); + down_read(&nilfs->ns_segctor_sem); ret = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, cno); up_read(&nilfs->ns_segctor_sem); @@ -972,6 +974,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, ret = nilfs_get_root_dentry(s, root, root_dentry); nilfs_put_root(root); out: + mutex_unlock(&nilfs->ns_snapshot_mount_mutex); return ret; } diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 501b7f8b739..41e6a04a561 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -76,6 +76,7 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) nilfs->ns_bdev = bdev; atomic_set(&nilfs->ns_ndirtyblks, 0); init_rwsem(&nilfs->ns_sem); + mutex_init(&nilfs->ns_snapshot_mount_mutex); INIT_LIST_HEAD(&nilfs->ns_dirty_files); INIT_LIST_HEAD(&nilfs->ns_gc_inodes); spin_lock_init(&nilfs->ns_inode_lock); diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 9992b11312f..de7435f0ef5 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -47,6 +47,7 @@ enum { * @ns_flags: flags * @ns_bdev: block device * @ns_sem: semaphore for shared states + * @ns_snapshot_mount_mutex: mutex to protect snapshot mounts * @ns_sbh: buffer heads of on-disk super blocks * @ns_sbp: pointers to super block data * @ns_sbwtime: previous write time of super block @@ -99,6 +100,7 @@ struct the_nilfs { struct block_device *ns_bdev; struct rw_semaphore ns_sem; + struct mutex ns_snapshot_mount_mutex; /* * used for From 246dec1d5b521ad2cece0a4ea57a59dca2e3cf38 Mon Sep 17 00:00:00 2001 From: Luis Henriques Date: Tue, 19 Jun 2012 11:29:49 -0300 Subject: [PATCH 0642/2357] media: ene_ir: Fix driver initialisation commit b31b021988fed9e3741a46918f14ba9b063811db upstream. commit 9ef449c6b31bb6a8e6dedc24de475a3b8c79be20 ("[media] rc: Postpone ISR registration") fixed an early ISR registration on several drivers. It did however also introduced a bug by moving the invocation of pnp_port_start() to the end of the probe function. This patch fixes this issue by moving the invocation of pnp_port_start() to an earlier stage in the probe function. Signed-off-by: Luis Henriques Cc: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/ene_ir.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index bef5296173c..647dd951b0e 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1018,6 +1018,8 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) spin_lock_init(&dev->hw_lock); + dev->hw_io = pnp_port_start(pnp_dev, 0); + pnp_set_drvdata(pnp_dev, dev); dev->pnp_dev = pnp_dev; @@ -1072,7 +1074,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) /* claim the resources */ error = -EBUSY; - dev->hw_io = pnp_port_start(pnp_dev, 0); if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) { dev->hw_io = -1; dev->irq = -1; From 603cb88c3a73968a0fa498e252cbb781e62bb5b4 Mon Sep 17 00:00:00 2001 From: Greg Pearson Date: Mon, 30 Jul 2012 14:39:05 -0700 Subject: [PATCH 0643/2357] pcdp: use early_ioremap/early_iounmap to access pcdp table commit 6c4088ac3a4d82779903433bcd5f048c58fb1aca upstream. efi_setup_pcdp_console() is called during boot to parse the HCDP/PCDP EFI system table and setup an early console for printk output. The routine uses ioremap/iounmap to setup access to the HCDP/PCDP table information. The call to ioremap is happening early in the boot process which leads to a panic on x86_64 systems: panic+0x01ca do_exit+0x043c oops_end+0x00a7 no_context+0x0119 __bad_area_nosemaphore+0x0138 bad_area_nosemaphore+0x000e do_page_fault+0x0321 page_fault+0x0020 reserve_memtype+0x02a1 __ioremap_caller+0x0123 ioremap_nocache+0x0012 efi_setup_pcdp_console+0x002b setup_arch+0x03a9 start_kernel+0x00d4 x86_64_start_reservations+0x012c x86_64_start_kernel+0x00fe This replaces the calls to ioremap/iounmap in efi_setup_pcdp_console() with calls to early_ioremap/early_iounmap which can be called during early boot. This patch was tested on an x86_64 prototype system which uses the HCDP/PCDP table for early console setup. Signed-off-by: Greg Pearson Acked-by: Khalid Aziz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/pcdp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index 51e0e2d8fac..a330492e06f 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -95,7 +95,7 @@ efi_setup_pcdp_console(char *cmdline) if (efi.hcdp == EFI_INVALID_TABLE_ADDR) return -ENODEV; - pcdp = ioremap(efi.hcdp, 4096); + pcdp = early_ioremap(efi.hcdp, 4096); printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, efi.hcdp); if (strstr(cmdline, "console=hcdp")) { @@ -131,6 +131,6 @@ efi_setup_pcdp_console(char *cmdline) } out: - iounmap(pcdp); + early_iounmap(pcdp, 4096); return rc; } From ce6f0ff8d1031931df7031a88f4085e5f196a854 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Mon, 30 Jul 2012 14:39:04 -0700 Subject: [PATCH 0644/2357] mm: fix wrong argument of migrate_huge_pages() in soft_offline_huge_page() commit dc32f63453f56d07a1073a697dcd843dd3098c09 upstream. Commit a6bc32b89922 ("mm: compaction: introduce sync-light migration for use by compaction") changed the declaration of migrate_pages() and migrate_huge_pages(). But it missed changing the argument of migrate_huge_pages() in soft_offline_huge_page(). In this case, we should call migrate_huge_pages() with MIGRATE_SYNC. Additionally, there is a mismatch between type the of argument and the function declaration for migrate_pages(). Signed-off-by: Joonsoo Kim Cc: Christoph Lameter Cc: Mel Gorman Acked-by: David Rientjes Cc: "Aneesh Kumar K.V" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memory-failure.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 0de20d7168f..274c3cc5fbc 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1433,8 +1433,8 @@ static int soft_offline_huge_page(struct page *page, int flags) /* Keep page count to indicate a given hugepage is isolated. */ list_add(&hpage->lru, &pagelist); - ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, 0, - true); + ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, false, + MIGRATE_SYNC); if (ret) { struct page *page1, *page2; list_for_each_entry_safe(page1, page2, &pagelist, lru) @@ -1563,7 +1563,7 @@ int soft_offline_page(struct page *page, int flags) page_is_file_cache(page)); list_add(&page->lru, &pagelist); ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, - 0, MIGRATE_SYNC); + false, MIGRATE_SYNC); if (ret) { putback_lru_pages(&pagelist); pr_info("soft offline: %#lx: migration failed %d, type %lx\n", From 05aa0d1bc94e2809ec0ccb4be20860784e4640b1 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 13 Jul 2012 08:19:34 +0100 Subject: [PATCH 0645/2357] ARM: 7466/1: disable interrupt before spinning endlessly commit 98bd8b96b26db3399a48202318dca4aaa2515355 upstream. The CPU will endlessly spin at the end of machine_halt and machine_restart calls. However, this will lead to a soft lockup warning after about 20 seconds, if CONFIG_LOCKUP_DETECTOR is enabled, as system timer is still alive. Disable interrupt before going to spin endlessly, so that the lockup warning will never be seen. Reported-by: Marek Vasut Signed-off-by: Shawn Guo Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/process.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 2b7b017a20c..48f36246a5d 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -267,6 +267,7 @@ void machine_shutdown(void) void machine_halt(void) { machine_shutdown(); + local_irq_disable(); while (1); } @@ -288,6 +289,7 @@ void machine_restart(char *cmd) /* Whoops - the platform was unable to reboot. Tell the user! */ printk("Reboot failed -- System halted\n"); + local_irq_disable(); while (1); } From ea2ebaa71c978254c2a93bf561236aec8a167166 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 20 Jul 2012 02:03:43 +0100 Subject: [PATCH 0646/2357] ARM: 7476/1: vfp: only clear vfp state for current cpu in vfp_pm_suspend commit a84b895a2348f0dbff31b71ddf954f70a6cde368 upstream. vfp_pm_suspend runs on each cpu, only clear the hardware state pointer for the current cpu. Prevents a possible crash if one cpu clears the hw state pointer when another cpu has already checked if it is valid. Signed-off-by: Colin Cross Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/vfp/vfpmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index b0197b2c857..da3b9292f9f 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -460,7 +460,7 @@ static int vfp_pm_suspend(void) } /* clear any information we had about last context state */ - memset(vfp_current_hw_state, 0, sizeof(vfp_current_hw_state)); + vfp_current_hw_state[ti->cpu] = NULL; return 0; } From f95f7ae189b51123becde905e934954c86c8a0e2 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 20 Jul 2012 02:03:42 +0100 Subject: [PATCH 0647/2357] ARM: 7477/1: vfp: Always save VFP state in vfp_pm_suspend on UP commit 24b35521b8ddf088531258f06f681bb7b227bf47 upstream. vfp_pm_suspend should save the VFP state in suspend after any lazy context switch. If it only saves when the VFP is enabled, the state can get lost when, on a UP system: Thread 1 uses the VFP Context switch occurs to thread 2, VFP is disabled but the VFP context is not saved Thread 2 initiates suspend vfp_pm_suspend is called with the VFP disabled, and the unsaved VFP context of Thread 1 in the registers Modify vfp_pm_suspend to save the VFP context whenever vfp_current_hw_state is not NULL. Includes a fix from Ido Yariv , who pointed out that on SMP systems, the state pointer can be pointing to a freed task struct if a task exited on another cpu, fixed by using #ifndef CONFIG_SMP in the new if clause. Signed-off-by: Colin Cross Cc: Barry Song Cc: Catalin Marinas Cc: Ido Yariv Cc: Daniel Drake Cc: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/vfp/vfpmodule.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index da3b9292f9f..1ef803aa7a5 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -457,6 +457,12 @@ static int vfp_pm_suspend(void) /* disable, just in case */ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); + } else if (vfp_current_hw_state[ti->cpu]) { +#ifndef CONFIG_SMP + fmxr(FPEXC, fpexc | FPEXC_EN); + vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc); + fmxr(FPEXC, fpexc); +#endif } /* clear any information we had about last context state */ From 17c7d1468f968e153d39a94efeedd0a0e2a77c2a Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 20 Jul 2012 18:24:55 +0100 Subject: [PATCH 0648/2357] ARM: 7478/1: errata: extend workaround for erratum #720789 commit 5a783cbc48367cfc7b65afc75430953dfe60098f upstream. Commit cdf357f1 ("ARM: 6299/1: errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID") replaced by-ASID TLB flushing operations with all-ASID variants to workaround A9 erratum #720789. This patch extends the workaround to include the tlb_range operations, which were overlooked by the original patch. Tested-by: Steve Capper Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/mm/tlb-v7.S | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S index 845f461f8ec..c2021139cb5 100644 --- a/arch/arm/mm/tlb-v7.S +++ b/arch/arm/mm/tlb-v7.S @@ -38,11 +38,19 @@ ENTRY(v7wbi_flush_user_tlb_range) dsb mov r0, r0, lsr #PAGE_SHIFT @ align address mov r1, r1, lsr #PAGE_SHIFT +#ifdef CONFIG_ARM_ERRATA_720789 + mov r3, #0 +#else asid r3, r3 @ mask ASID +#endif orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA mov r1, r1, lsl #PAGE_SHIFT 1: +#ifdef CONFIG_ARM_ERRATA_720789 + ALT_SMP(mcr p15, 0, r0, c8, c3, 3) @ TLB invalidate U MVA all ASID (shareable) +#else ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable) +#endif ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA add r0, r0, #PAGE_SZ @@ -67,7 +75,11 @@ ENTRY(v7wbi_flush_kern_tlb_range) mov r0, r0, lsl #PAGE_SHIFT mov r1, r1, lsl #PAGE_SHIFT 1: +#ifdef CONFIG_ARM_ERRATA_720789 + ALT_SMP(mcr p15, 0, r0, c8, c3, 3) @ TLB invalidate U MVA all ASID (shareable) +#else ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable) +#endif ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA add r0, r0, #PAGE_SZ cmp r0, r1 From 7e49f71b7a6268bb9854b91f6fae3f070fb0222e Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 23 Jul 2012 14:18:13 +0100 Subject: [PATCH 0649/2357] ARM: 7479/1: mm: avoid NULL dereference when flushing gate_vma with VIVT caches commit b74253f78400f9a4b42da84bb1de7540b88ce7c4 upstream. The vivt_flush_cache_{range,page} functions check that the mm_struct of the VMA being flushed has been active on the current CPU before performing the cache maintenance. The gate_vma has a NULL mm_struct pointer and, as such, will cause a kernel fault if we try to flush it with the above operations. This happens during ELF core dumps, which include the gate_vma as it may be useful for debugging purposes. This patch adds checks to the VIVT cache flushing functions so that VMAs with a NULL mm_struct are flushed unconditionally (the vectors page may be dirty if we use it to store the current TLS pointer). Reported-by: Gilles Chanteperdrix Tested-by: Uros Bizjak Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/cacheflush.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 1252a2675ca..42dec04f617 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -215,7 +215,9 @@ static inline void vivt_flush_cache_mm(struct mm_struct *mm) static inline void vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) + struct mm_struct *mm = vma->vm_mm; + + if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) __cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end), vma->vm_flags); } @@ -223,7 +225,9 @@ vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned static inline void vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn) { - if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { + struct mm_struct *mm = vma->vm_mm; + + if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) { unsigned long addr = user_addr & PAGE_MASK; __cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags); } From 85869d9f5da8449613f5631961fe9309f9c2d0ad Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 28 Jul 2012 15:19:55 +0100 Subject: [PATCH 0650/2357] ARM: 7480/1: only call smp_send_stop() on SMP commit c5dff4ffd327088d85035bec535b7d0c9ea03151 upstream. On reboot or poweroff (machine_shutdown()) a call to smp_send_stop() is made (to stop the others CPU's) when CONFIG_SMP=y. arch/arm/kernel/process.c: void machine_shutdown(void) { #ifdef CONFIG_SMP smp_send_stop(); #endif } smp_send_stop() calls the function pointer smp_cross_call(), which is set on the smp_init_cpus() function for OMAP processors. arch/arm/mach-omap2/omap-smp.c: void __init smp_init_cpus(void) { ... set_smp_cross_call(gic_raise_softirq); ... } But the ARM setup_arch() function only calls smp_init_cpus() if CONFIG_SMP=y && is_smp(). arm/kernel/setup.c: void __init setup_arch(char **cmdline_p) { ... #ifdef CONFIG_SMP if (is_smp()) smp_init_cpus(); #endif ... } Newer OMAP CPU's are SMP machines so omap2plus_defconfig sets CONFIG_SMP=y. Unfortunately on an OMAP UP machine is_smp() returns false and smp_init_cpus() is never called and the smp_cross_call() function remains NULL. If the machine is rebooted or powered off, smp_send_stop() will be called (since CONFIG_SMP=y) leading to the following error: [ 42.815551] Restarting system. [ 42.819030] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 42.827667] pgd = d7a74000 [ 42.830566] [00000000] *pgd=96ce7831, *pte=00000000, *ppte=00000000 [ 42.837249] Internal error: Oops: 80000007 [#1] SMP ARM [ 42.842773] Modules linked in: [ 42.846008] CPU: 0 Not tainted (3.5.0-rc3-next-20120622-00002-g62e87ba-dirty #44) [ 42.854278] PC is at 0x0 [ 42.856994] LR is at smp_send_stop+0x4c/0xe4 [ 42.861511] pc : [<00000000>] lr : [] psr: 60000013 [ 42.861511] sp : d6c85e70 ip : 00000000 fp : 00000000 [ 42.873626] r10: 00000000 r9 : d6c84000 r8 : 00000002 [ 42.879150] r7 : c07235a0 r6 : c06dd2d0 r5 : 000f4241 r4 : d6c85e74 [ 42.886047] r3 : 00000000 r2 : 00000000 r1 : 00000006 r0 : d6c85e74 [ 42.892944] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 42.900482] Control: 10c5387d Table: 97a74019 DAC: 00000015 [ 42.906555] Process reboot (pid: 1166, stack limit = 0xd6c842f8) [ 42.912902] Stack: (0xd6c85e70 to 0xd6c86000) [ 42.917510] 5e60: c07235a0 00000000 00000000 d6c84000 [ 42.926177] 5e80: 01234567 c00143d0 4321fedc c00511bc d6c85ebc 00000168 00000460 00000000 [ 42.934814] 5ea0: c1017950 a0000013 c1017900 d8014390 d7ec3858 c0498e48 c1017950 00000000 [ 42.943481] 5ec0: d6ddde10 d6c85f78 00000003 00000000 d6ddde10 d6c84000 00000000 00000000 [ 42.952117] 5ee0: 00000002 00000000 00000000 c0088c88 00000002 00000000 00000000 c00f4b90 [ 42.960784] 5f00: 00000000 d6c85ebc d8014390 d7e311c8 60000013 00000103 00000002 d6c84000 [ 42.969421] 5f20: c00f3274 d6e00a00 00000001 60000013 d6c84000 00000000 00000000 c00895d4 [ 42.978057] 5f40: 00000002 d8007c80 d781f000 c00f6150 d8010cc0 c00f3274 d781f000 d6c84000 [ 42.986694] 5f60: c0013020 d6e00a00 00000001 20000010 0001257c ef000000 00000000 c00895d4 [ 42.995361] 5f80: 00000002 00000001 00000003 00000000 00000001 00000003 00000000 00000058 [ 43.003997] 5fa0: c00130c8 c0012f00 00000001 00000003 fee1dead 28121969 01234567 00000002 [ 43.012634] 5fc0: 00000001 00000003 00000000 00000058 00012584 0001257c 00000001 00000000 [ 43.021270] 5fe0: 000124bc bec5cc6c 00008f9c 4a2f7c40 20000010 fee1dead 00000000 00000000 [ 43.029968] [] (smp_send_stop+0x4c/0xe4) from [] (machine_restart+0xc/0x4c) [ 43.039154] [] (machine_restart+0xc/0x4c) from [] (sys_reboot+0x144/0x1f0) [ 43.048278] [] (sys_reboot+0x144/0x1f0) from [] (ret_fast_syscall+0x0/0x3c) [ 43.057464] Code: bad PC value [ 43.060760] ---[ end trace c3988d1dd0b8f0fb ]--- Add a check so smp_cross_call() is only called when there is more than one CPU on-line. Signed-off-by: Javier Martinez Canillas Acked-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/smp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 8f464465977..7babc3f98a1 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -590,7 +590,8 @@ void smp_send_stop(void) cpumask_copy(&mask, cpu_online_mask); cpumask_clear_cpu(smp_processor_id(), &mask); - smp_cross_call(&mask, IPI_CPU_STOP); + if (!cpumask_empty(&mask)) + smp_cross_call(&mask, IPI_CPU_STOP); /* Wait up to one second for other CPUs to stop */ timeout = USEC_PER_SEC; From 81155539833d8c492261a8fdd91e3e6579c274dd Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2012 19:42:10 +0100 Subject: [PATCH 0651/2357] ARM: Fix undefined instruction exception handling commit 15ac49b65024f55c4371a53214879a9c77c4fbf9 upstream. While trying to get a v3.5 kernel booted on the cubox, I noticed that VFP does not work correctly with VFP bounce handling. This is because of the confusion over 16-bit vs 32-bit instructions, and where PC is supposed to point to. The rule is that FP handlers are entered with regs->ARM_pc pointing at the _next_ instruction to be executed. However, if the exception is not handled, regs->ARM_pc points at the faulting instruction. This is easy for ARM mode, because we know that the next instruction and previous instructions are separated by four bytes. This is not true of Thumb2 though. Since all FP instructions are 32-bit in Thumb2, it makes things easy. We just need to select the appropriate adjustment. Do this by moving the adjustment out of do_undefinstr() into the assembly code, as only the assembly code knows whether it's dealing with a 32-bit or 16-bit instruction. Acked-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/entry-armv.S | 111 +++++++++++++++++++++++------------ arch/arm/kernel/traps.c | 8 --- arch/arm/vfp/entry.S | 16 ++--- arch/arm/vfp/vfphw.S | 19 +++--- 4 files changed, 92 insertions(+), 62 deletions(-) diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 7fd3ad048da..8f29865810f 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -244,6 +244,19 @@ svc_preempt: b 1b #endif +__und_fault: + @ Correct the PC such that it is pointing at the instruction + @ which caused the fault. If the faulting instruction was ARM + @ the PC will be pointing at the next instruction, and have to + @ subtract 4. Otherwise, it is Thumb, and the PC will be + @ pointing at the second half of the Thumb instruction. We + @ have to subtract 2. + ldr r2, [r0, #S_PC] + sub r2, r2, r1 + str r2, [r0, #S_PC] + b do_undefinstr +ENDPROC(__und_fault) + .align 5 __und_svc: #ifdef CONFIG_KPROBES @@ -261,25 +274,32 @@ __und_svc: @ @ r0 - instruction @ -#ifndef CONFIG_THUMB2_KERNEL +#ifndef CONFIG_THUMB2_KERNEL ldr r0, [r4, #-4] #else + mov r1, #2 ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2 cmp r0, #0xe800 @ 32-bit instruction if xx >= 0 - ldrhhs r9, [r4] @ bottom 16 bits - orrhs r0, r9, r0, lsl #16 + blo __und_svc_fault + ldrh r9, [r4] @ bottom 16 bits + add r4, r4, #2 + str r4, [sp, #S_PC] + orr r0, r9, r0, lsl #16 #endif - adr r9, BSYM(1f) + adr r9, BSYM(__und_svc_finish) mov r2, r4 bl call_fpe + mov r1, #4 @ PC correction to apply +__und_svc_fault: mov r0, sp @ struct pt_regs *regs - bl do_undefinstr + bl __und_fault @ @ IRQs off again before pulling preserved data off the stack @ -1: disable_irq_notrace +__und_svc_finish: + disable_irq_notrace @ @ restore SPSR and restart the instruction @@ -423,25 +443,33 @@ __und_usr: mov r2, r4 mov r3, r5 + @ r2 = regs->ARM_pc, which is either 2 or 4 bytes ahead of the + @ faulting instruction depending on Thumb mode. + @ r3 = regs->ARM_cpsr @ - @ fall through to the emulation code, which returns using r9 if - @ it has emulated the instruction, or the more conventional lr - @ if we are to treat this as a real undefined instruction - @ - @ r0 - instruction + @ The emulation code returns using r9 if it has emulated the + @ instruction, or the more conventional lr if we are to treat + @ this as a real undefined instruction @ adr r9, BSYM(ret_from_exception) - adr lr, BSYM(__und_usr_unknown) + tst r3, #PSR_T_BIT @ Thumb mode? - itet eq @ explicit IT needed for the 1f label - subeq r4, r2, #4 @ ARM instr at LR - 4 - subne r4, r2, #2 @ Thumb instr at LR - 2 -1: ldreqt r0, [r4] + bne __und_usr_thumb + sub r4, r2, #4 @ ARM instr at LR - 4 +1: ldrt r0, [r4] #ifdef CONFIG_CPU_ENDIAN_BE8 - reveq r0, r0 @ little endian instruction + rev r0, r0 @ little endian instruction #endif - beq call_fpe + @ r0 = 32-bit ARM instruction which caused the exception + @ r2 = PC value for the following instruction (:= regs->ARM_pc) + @ r4 = PC value for the faulting instruction + @ lr = 32-bit undefined instruction function + adr lr, BSYM(__und_usr_fault_32) + b call_fpe + +__und_usr_thumb: @ Thumb instruction + sub r4, r2, #2 @ First half of thumb instr at LR - 2 #if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7 /* * Thumb-2 instruction handling. Note that because pre-v6 and >= v6 platforms @@ -455,7 +483,7 @@ __und_usr: ldr r5, .LCcpu_architecture ldr r5, [r5] cmp r5, #CPU_ARCH_ARMv7 - blo __und_usr_unknown + blo __und_usr_fault_16 @ 16bit undefined instruction /* * The following code won't get run unless the running CPU really is v7, so * coding round the lack of ldrht on older arches is pointless. Temporarily @@ -463,15 +491,18 @@ __und_usr: */ .arch armv6t2 #endif -2: - ARM( ldrht r5, [r4], #2 ) - THUMB( ldrht r5, [r4] ) - THUMB( add r4, r4, #2 ) +2: ldrht r5, [r4] cmp r5, #0xe800 @ 32bit instruction if xx != 0 - blo __und_usr_unknown -3: ldrht r0, [r4] + blo __und_usr_fault_16 @ 16bit undefined instruction +3: ldrht r0, [r2] add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 + str r2, [sp, #S_PC] @ it's a 2x16bit instr, update orr r0, r0, r5, lsl #16 + adr lr, BSYM(__und_usr_fault_32) + @ r0 = the two 16-bit Thumb instructions which caused the exception + @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc) + @ r4 = PC value for the first 16-bit Thumb instruction + @ lr = 32bit undefined instruction function #if __LINUX_ARM_ARCH__ < 7 /* If the target arch was overridden, change it back: */ @@ -482,17 +513,13 @@ __und_usr: #endif #endif /* __LINUX_ARM_ARCH__ < 7 */ #else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */ - b __und_usr_unknown + b __und_usr_fault_16 #endif - UNWIND(.fnend ) + UNWIND(.fnend) ENDPROC(__und_usr) - @ - @ fallthrough to call_fpe - @ - /* - * The out of line fixup for the ldrt above. + * The out of line fixup for the ldrt instructions above. */ .pushsection .fixup, "ax" 4: mov pc, r9 @@ -523,11 +550,12 @@ ENDPROC(__und_usr) * NEON handler code. * * Emulators may wish to make use of the following registers: - * r0 = instruction opcode. - * r2 = PC+4 + * r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) + * r2 = PC value to resume execution after successful emulation * r9 = normal "successful" return address - * r10 = this threads thread_info structure. + * r10 = this threads thread_info structure * lr = unrecognised instruction return address + * IRQs disabled, FIQs enabled. */ @ @ Fall-through from Thumb-2 __und_usr @@ -662,12 +690,17 @@ ENTRY(no_fp) mov pc, lr ENDPROC(no_fp) -__und_usr_unknown: - enable_irq +__und_usr_fault_32: + mov r1, #4 + b 1f +__und_usr_fault_16: + mov r1, #2 +1: enable_irq mov r0, sp adr lr, BSYM(ret_from_exception) - b do_undefinstr -ENDPROC(__und_usr_unknown) + b __und_fault +ENDPROC(__und_usr_fault_32) +ENDPROC(__und_usr_fault_16) .align 5 __pabt_usr: diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 63d402f75e2..a8ad1e34902 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -370,18 +370,10 @@ static int call_undef_hook(struct pt_regs *regs, unsigned int instr) asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { - unsigned int correction = thumb_mode(regs) ? 2 : 4; unsigned int instr; siginfo_t info; void __user *pc; - /* - * According to the ARM ARM, PC is 2 or 4 bytes ahead, - * depending whether we're in Thumb mode or not. - * Correct this offset. - */ - regs->ARM_pc -= correction; - pc = (void __user *)instruction_pointer(regs); if (processor_mode(regs) == SVC_MODE) { diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index 4fa9903b83c..cc926c98598 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -7,18 +7,20 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * Basic entry code, called from the kernel's undefined instruction trap. - * r0 = faulted instruction - * r5 = faulted PC+4 - * r9 = successful return - * r10 = thread_info structure - * lr = failure return */ #include #include #include "../kernel/entry-header.S" +@ VFP entry point. +@ +@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) +@ r2 = PC value to resume execution after successful emulation +@ r9 = normal "successful" return address +@ r10 = this threads thread_info structure +@ lr = unrecognised instruction return address +@ IRQs disabled. +@ ENTRY(do_vfp) #ifdef CONFIG_PREEMPT ldr r4, [r10, #TI_PREEMPT] @ get preempt count diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 2d30c7f6edd..3a0efaad609 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -61,13 +61,13 @@ @ VFP hardware support entry point. @ -@ r0 = faulted instruction -@ r2 = faulted PC+4 -@ r9 = successful return +@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) +@ r2 = PC value to resume execution after successful emulation +@ r9 = normal "successful" return address @ r10 = vfp_state union @ r11 = CPU number -@ lr = failure return - +@ lr = unrecognised instruction return address +@ IRQs enabled. ENTRY(vfp_support_entry) DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10 @@ -161,9 +161,12 @@ vfp_hw_state_valid: @ exception before retrying branch @ out before setting an FPEXC that @ stops us reading stuff - VFPFMXR FPEXC, r1 @ restore FPEXC last - sub r2, r2, #4 - str r2, [sp, #S_PC] @ retry the instruction + VFPFMXR FPEXC, r1 @ Restore FPEXC last + sub r2, r2, #4 @ Retry current instruction - if Thumb + str r2, [sp, #S_PC] @ mode it's two 16-bit instructions, + @ else it's one 32-bit instruction, so + @ always subtract 4 from the following + @ instruction address. #ifdef CONFIG_PREEMPT get_thread_info r10 ldr r4, [r10, #TI_PREEMPT] @ get preempt count From cd5deba98060332626da3369e4798d0de51456ff Mon Sep 17 00:00:00 2001 From: "Philipp A. Mohrenweiser" Date: Mon, 6 Aug 2012 13:14:18 +0200 Subject: [PATCH 0652/2357] ALSA: hda - add dock support for Thinkpad T430s commit 4407be6ba217514b1bc01488f8b56467d309e416 upstream. Add a model/fixup string "lenovo-dock", for Thinkpad T430s, to allow sound in docking station. Tested on Lenovo T430s with ThinkPad Mini Dock Plus Series 3 Signed-off-by: Philipp A. Mohrenweiser Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 62e1627acda..a5b8d6d0ef9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6157,6 +6157,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), From 08899ba0982718342e5b2ab8dd917ab479fc7f4f Mon Sep 17 00:00:00 2001 From: Felix Kaechele Date: Mon, 6 Aug 2012 23:02:01 +0200 Subject: [PATCH 0653/2357] ALSA: hda - add dock support for Thinkpad X230 commit c8415a48fcb7a29889f4405d38c57db351e4b50a upstream. As with the ThinkPad Models X230 Tablet and T530 the X230 needs a qurik to correctly set up the pins for the dock port. Signed-off-by: Felix Kaechele Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a5b8d6d0ef9..71dd0530a89 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6157,6 +6157,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), From 55f5c43caba6cccd00840003fc0c80acc785ba83 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 7 Aug 2012 14:03:29 +0200 Subject: [PATCH 0654/2357] ALSA: hda - remove quirk for Dell Vostro 1015 commit e9fc83cb2e5877801a255a37ddbc5be996ea8046 upstream. This computer is confirmed working with model=auto on kernel 3.2. Also, parsing fails with hda-emu with the current model. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_conexant.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index d906c5b74cf..389702708ea 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -2975,7 +2975,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD), From 41a2033bf3bc1ecf19c743b452791ba492a6e75d Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 8 Aug 2012 08:43:37 +0200 Subject: [PATCH 0655/2357] ALSA: hda - Fix double quirk for Quanta FL1 / Lenovo Ideapad commit 012e7eb1e501d0120e0383b81477f63091f5e365 upstream. The same ID is twice in the quirk table, so the second one is not used. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 71dd0530a89..152d91b7e10 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6056,6 +6056,8 @@ static const struct alc_fixup alc269_fixups[] = { [ALC269_FIXUP_PCM_44K] = { .type = ALC_FIXUP_FUNC, .v.func = alc269_fixup_pcm_44k, + .chained = true, + .chain_id = ALC269_FIXUP_QUANTA_MUTE }, [ALC269_FIXUP_STEREO_DMIC] = { .type = ALC_FIXUP_FUNC, @@ -6160,8 +6162,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), #if 0 From cc9fdb9cdde35aafad3b11ce74e244f5da7ac3c0 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 31 Jul 2012 16:45:52 -0700 Subject: [PATCH 0656/2357] mm: mmu_notifier: fix freed page still mapped in secondary MMU commit 3ad3d901bbcfb15a5e4690e55350db0899095a68 upstream. mmu_notifier_release() is called when the process is exiting. It will delete all the mmu notifiers. But at this time the page belonging to the process is still present in page tables and is present on the LRU list, so this race will happen: CPU 0 CPU 1 mmu_notifier_release: try_to_unmap: hlist_del_init_rcu(&mn->hlist); ptep_clear_flush_notify: mmu nofifler not found free page !!!!!! /* * At the point, the page has been * freed, but it is still mapped in * the secondary MMU. */ mn->ops->release(mn, mm); Then the box is not stable and sometimes we can get this bug: [ 738.075923] BUG: Bad page state in process migrate-perf pfn:03bec [ 738.075931] page:ffffea00000efb00 count:0 mapcount:0 mapping: (null) index:0x8076 [ 738.075936] page flags: 0x20000000000014(referenced|dirty) The same issue is present in mmu_notifier_unregister(). We can call ->release before deleting the notifier to ensure the page has been unmapped from the secondary MMU before it is freed. Signed-off-by: Xiao Guangrong Cc: Avi Kivity Cc: Marcelo Tosatti Cc: Paul Gortmaker Cc: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mmu_notifier.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c index 9a611d3a184..862b60822d9 100644 --- a/mm/mmu_notifier.c +++ b/mm/mmu_notifier.c @@ -33,6 +33,24 @@ void __mmu_notifier_release(struct mm_struct *mm) { struct mmu_notifier *mn; + struct hlist_node *n; + + /* + * RCU here will block mmu_notifier_unregister until + * ->release returns. + */ + rcu_read_lock(); + hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) + /* + * if ->release runs before mmu_notifier_unregister it + * must be handled as it's the only way for the driver + * to flush all existing sptes and stop the driver + * from establishing any more sptes before all the + * pages in the mm are freed. + */ + if (mn->ops->release) + mn->ops->release(mn, mm); + rcu_read_unlock(); spin_lock(&mm->mmu_notifier_mm->lock); while (unlikely(!hlist_empty(&mm->mmu_notifier_mm->list))) { @@ -46,23 +64,6 @@ void __mmu_notifier_release(struct mm_struct *mm) * mmu_notifier_unregister to return. */ hlist_del_init_rcu(&mn->hlist); - /* - * RCU here will block mmu_notifier_unregister until - * ->release returns. - */ - rcu_read_lock(); - spin_unlock(&mm->mmu_notifier_mm->lock); - /* - * if ->release runs before mmu_notifier_unregister it - * must be handled as it's the only way for the driver - * to flush all existing sptes and stop the driver - * from establishing any more sptes before all the - * pages in the mm are freed. - */ - if (mn->ops->release) - mn->ops->release(mn, mm); - rcu_read_unlock(); - spin_lock(&mm->mmu_notifier_mm->lock); } spin_unlock(&mm->mmu_notifier_mm->lock); @@ -284,16 +285,13 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm) { BUG_ON(atomic_read(&mm->mm_count) <= 0); - spin_lock(&mm->mmu_notifier_mm->lock); if (!hlist_unhashed(&mn->hlist)) { - hlist_del_rcu(&mn->hlist); - /* * RCU here will force exit_mmap to wait ->release to finish * before freeing the pages. */ rcu_read_lock(); - spin_unlock(&mm->mmu_notifier_mm->lock); + /* * exit_mmap will block in mmu_notifier_release to * guarantee ->release is called before freeing the @@ -302,8 +300,11 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm) if (mn->ops->release) mn->ops->release(mn, mm); rcu_read_unlock(); - } else + + spin_lock(&mm->mmu_notifier_mm->lock); + hlist_del_rcu(&mn->hlist); spin_unlock(&mm->mmu_notifier_mm->lock); + } /* * Wait any running method to finish, of course including From fb060f3d95d29c385063151c8a09faa4d1a02f2f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 31 Jul 2012 10:05:34 +1000 Subject: [PATCH 0657/2357] md/raid1: don't abort a resync on the first badblock. commit b7219ccb33aa0df9949a60c68b5e9f712615e56f upstream. If a resync of a RAID1 array with 2 devices finds a known bad block one device it will neither read from, or write to, that device for this block offset. So there will be one read_target (The other device) and zero write targets. This condition causes md/raid1 to abort the resync assuming that it has finished - without known bad blocks this would be true. When there are no write targets because of the presence of bad blocks we should only skip over the area covered by the bad block. RAID10 already gets this right, raid1 doesn't. Or didn't. As this can cause a 'sync' to abort early and appear to have succeeded it could lead to some data corruption, so it suitable for -stable. Reported-by: Alexander Lyakas Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid1.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index d7add9d5bac..23904d23373 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2429,7 +2429,10 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp /* There is nowhere to write, so all non-sync * drives must be failed - so we are finished */ - sector_t rv = max_sector - sector_nr; + sector_t rv; + if (min_bad > 0) + max_sector = sector_nr + min_bad; + rv = max_sector - sector_nr; *skipped = 1; put_buf(r1_bio); return rv; From 8b0331a46c6aa9f853e1208b0ce137c4d1d4fc1a Mon Sep 17 00:00:00 2001 From: Alexander Holler Date: Sat, 21 Apr 2012 00:11:07 +0200 Subject: [PATCH 0658/2357] video/smscufx: fix line counting in fb_write commit 2fe2d9f47cfe1a3e66e7d087368b3d7155b04c15 upstream. Line 0 and 1 were both written to line 0 (on the display) and all subsequent lines had an offset of -1. The result was that the last line on the display was never overwritten by writes to /dev/fbN. The origin of this bug seems to have been udlfb. Signed-off-by: Alexander Holler Signed-off-by: Florian Tobias Schandinat Signed-off-by: Greg Kroah-Hartman --- drivers/video/smscufx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c index ccbfef5e828..1e1e2d267f4 100644 --- a/drivers/video/smscufx.c +++ b/drivers/video/smscufx.c @@ -904,7 +904,7 @@ static ssize_t ufx_ops_write(struct fb_info *info, const char __user *buf, result = fb_sys_write(info, buf, count, ppos); if (result > 0) { - int start = max((int)(offset / info->fix.line_length) - 1, 0); + int start = max((int)(offset / info->fix.line_length), 0); int lines = min((u32)((result / info->fix.line_length) + 1), (u32)info->var.yres); From 59c5bc1eb294df764567e29630dacbd04cb1e8ab Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Wed, 1 Aug 2012 17:48:36 +0300 Subject: [PATCH 0659/2357] ore: Fix out-of-bounds access in _ios_obj() commit 9e62bb4458ad2cf28bd701aa5fab380b846db326 upstream. _ios_obj() is accessed by group_index not device_table index. The oc->comps array is only a group_full of devices at a time it is not like ore_comp_dev() which is indexed by a global device_table index. This did not BUG until now because exofs only uses a single COMP for all devices. But with other FSs like PanFS this is not true. This bug was only in the write_path, all other users were using it correctly [This is a bug since 3.2 Kernel] Signed-off-by: Boaz Harrosh Signed-off-by: Greg Kroah-Hartman --- fs/exofs/ore.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/exofs/ore.c b/fs/exofs/ore.c index 24a49d47e93..1585db1aa36 100644 --- a/fs/exofs/ore.c +++ b/fs/exofs/ore.c @@ -837,11 +837,11 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp) bio->bi_rw |= REQ_WRITE; } - osd_req_write(or, _ios_obj(ios, dev), per_dev->offset, - bio, per_dev->length); + osd_req_write(or, _ios_obj(ios, cur_comp), + per_dev->offset, bio, per_dev->length); ORE_DBGMSG("write(0x%llx) offset=0x%llx " "length=0x%llx dev=%d\n", - _LLU(_ios_obj(ios, dev)->id), + _LLU(_ios_obj(ios, cur_comp)->id), _LLU(per_dev->offset), _LLU(per_dev->length), dev); } else if (ios->kern_buff) { @@ -853,20 +853,20 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp) (ios->si.unit_off + ios->length > ios->layout->stripe_unit)); - ret = osd_req_write_kern(or, _ios_obj(ios, per_dev->dev), + ret = osd_req_write_kern(or, _ios_obj(ios, cur_comp), per_dev->offset, ios->kern_buff, ios->length); if (unlikely(ret)) goto out; ORE_DBGMSG2("write_kern(0x%llx) offset=0x%llx " "length=0x%llx dev=%d\n", - _LLU(_ios_obj(ios, dev)->id), + _LLU(_ios_obj(ios, cur_comp)->id), _LLU(per_dev->offset), _LLU(ios->length), per_dev->dev); } else { - osd_req_set_attributes(or, _ios_obj(ios, dev)); + osd_req_set_attributes(or, _ios_obj(ios, cur_comp)); ORE_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n", - _LLU(_ios_obj(ios, dev)->id), + _LLU(_ios_obj(ios, cur_comp)->id), ios->out_attr_len, dev); } From 73ee3f4cbd1e240e53c51283a3e6110f222ef424 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Tue, 31 Jul 2012 12:44:43 +0800 Subject: [PATCH 0660/2357] ACPI processor: Fix tick_broadcast_mask online/offline regression commit b7db60f45d74497c723dc7ae1370cf0b37dfb0d8 upstream. In commit 99b725084 "ACPI processor hotplug: Delay acpi_processor_start() call for hotplugged cores", acpi_processor_hotplug(pr) was wrongly replaced by acpi_processor_cst_has_changed() inside the acpi_cpu_soft_notify(). This patch will restore it back, fixing the tick_broadcast_mask regression: https://lkml.org/lkml/2012/7/30/169 Signed-off-by: Feng Tang Cc: Thomas Renninger Reviewed-by: Rafael J. Wysocki Reviewed-by: Deepthi Dharwar Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 0734086537b..bbac51e79d1 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -442,7 +442,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, /* Normal CPU soft online event */ } else { acpi_processor_ppc_has_changed(pr, 0); - acpi_processor_cst_has_changed(pr); + acpi_processor_hotplug(pr); acpi_processor_reevaluate_tstate(pr, action); acpi_processor_tstate_has_changed(pr); } From 33db2f2ced18a4119746e8fa89a3aba13a9d2eac Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Aug 2012 21:03:21 +0200 Subject: [PATCH 0661/2357] mac80211: cancel mesh path timer commit dd4c9260e7f23f2e951cbfb2726e468c6d30306c upstream. The mesh path timer needs to be canceled when leaving the mesh as otherwise it could fire after the interface has been removed already. Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mesh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index e5fbb7cf356..e80fa33b504 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -595,6 +595,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) del_timer_sync(&sdata->u.mesh.housekeeping_timer); del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); + del_timer_sync(&sdata->u.mesh.mesh_path_timer); /* * If the timer fired while we waited for it, it will have * requeued the work. Now the work will be running again From ccf0b822f9fbbde08d56c2be07c0ab4c17036d1d Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 2 Aug 2012 11:58:50 +0530 Subject: [PATCH 0662/2357] ath9k: Add PID/VID support for AR1111 commit d4e5979c0da95791aa717c18e162540c7a596360 upstream. AR1111 is same as AR9485. The h/w difference between them is quite insignificant, Felix suggests only very few baseband features may not be available in AR1111. The h/w code for AR9485 is already present, so AR1111 should work fine with the addition of its PID/VID. Reported-by: Tim Bentley Cc: Felix Bitterli Signed-off-by: Mohammed Shafi Shajakhan Tested-by: Tim Bentley Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hw.c | 1 + drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/pci.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6dfd9644884..28a0edd57f0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -676,6 +676,7 @@ int ath9k_hw_init(struct ath_hw *ah) case AR9300_DEVID_AR9340: case AR9300_DEVID_AR9580: case AR9300_DEVID_AR9462: + case AR9485_DEVID_AR1111: break; default: if (common->bus_ops->ath_bus_type == ATH_USB) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e88f182ff45..f8e1fbbbfc5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -48,6 +48,7 @@ #define AR9300_DEVID_AR9580 0x0033 #define AR9300_DEVID_AR9462 0x0034 #define AR9300_DEVID_AR9330 0x0035 +#define AR9485_DEVID_AR1111 0x0037 #define AR5416_AR9100_DEVID 0x000b diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 77dc327def8..e44097a7529 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -35,6 +35,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */ { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */ { PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E AR9462 */ + { PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E AR1111/AR9485 */ { 0 } }; From 0295403cd835f7260c6d9262817138f9f1cd8e19 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 24 Jul 2012 08:35:39 +0200 Subject: [PATCH 0663/2357] wireless: reg: restore previous behaviour of chan->max_power calculations commit 5e31fc0815a4e2c72b1b495fe7a0d8f9bfb9e4b4 upstream. commit eccc068e8e84c8fe997115629925e0422a98e4de Author: Hong Wu Date: Wed Jan 11 20:33:39 2012 +0200 wireless: Save original maximum regulatory transmission power for the calucation of the local maximum transmit pow changed the way we calculate chan->max_power as min(chan->max_power, chan->max_reg_power). That broke rt2x00 (and perhaps some other drivers) that do not set chan->max_power. It is not so easy to fix this problem correctly in rt2x00. According to commit eccc068e8 changelog, change claim only to save maximum regulatory power - changing setting of chan->max_power was side effect. This patch restore previous calculations of chan->max_power and do not touch chan->max_reg_power. Signed-off-by: Stanislaw Gruszka Acked-by: Luis R. Rodriguez Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index baf5704740e..460af03d814 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -891,7 +891,21 @@ static void handle_channel(struct wiphy *wiphy, chan->max_antenna_gain = min(chan->orig_mag, (int) MBI_TO_DBI(power_rule->max_antenna_gain)); chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); - chan->max_power = min(chan->max_power, chan->max_reg_power); + if (chan->orig_mpwr) { + /* + * Devices that have their own custom regulatory domain + * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the + * passed country IE power settings. + */ + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + chan->max_power = chan->max_reg_power; + else + chan->max_power = min(chan->orig_mpwr, + chan->max_reg_power); + } else + chan->max_power = chan->max_reg_power; } static void handle_band(struct wiphy *wiphy, From cabf5b0af54cec6a2f9ce674cbc96fc8aa2fc468 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 25 Jul 2012 16:28:19 +0100 Subject: [PATCH 0664/2357] x86, nops: Missing break resulting in incorrect selection on Intel commit d6250a3f12edb3a86db9598ffeca3de8b4a219e9 upstream. The Intel case falls through into the generic case which then changes the values. For cases like the P6 it doesn't do the right thing so this seems to be a screwup. Signed-off-by: Alan Cox Link: http://lkml.kernel.org/n/tip-lww2uirad4skzjlmrm0vru8o@git.kernel.org Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/alternative.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 1f84794f075..73ef56c5a8b 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -219,7 +219,7 @@ void __init arch_init_ideal_nops(void) ideal_nops = intel_nops; #endif } - + break; default: #ifdef CONFIG_X86_64 ideal_nops = k8_nops; From 0110bbfbc8ed1b5240a51e8c767c44a856424139 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 2 Jul 2012 07:52:16 -0400 Subject: [PATCH 0665/2357] random: make 'add_interrupt_randomness()' do something sane commit 775f4b297b780601e61787b766f306ed3e1d23eb upstream. We've been moving away from add_interrupt_randomness() for various reasons: it's too expensive to do on every interrupt, and flooding the CPU with interrupts could theoretically cause bogus floods of entropy from a somewhat externally controllable source. This solves both problems by limiting the actual randomness addition to just once a second or after 64 interrupts, whicever comes first. During that time, the interrupt cycle data is buffered up in a per-cpu pool. Also, we make sure the the nonblocking pool used by urandom is initialized before we start feeding the normal input pool. This assures that /dev/urandom is returning unpredictable data as soon as possible. (Based on an original patch by Linus, but significantly modified by tytso.) Tested-by: Eric Wustrow Reported-by: Eric Wustrow Reported-by: Nadia Heninger Reported-by: Zakir Durumeric Reported-by: J. Alex Halderman Signed-off-by: Linus Torvalds Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 103 +++++++++++++++++++++++++++++++------- drivers/mfd/ab3100-core.c | 2 - include/linux/random.h | 2 +- kernel/irq/handle.c | 7 ++- 4 files changed, 90 insertions(+), 24 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 4ec04a75473..c59dbc6e758 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -127,19 +127,15 @@ * * void add_input_randomness(unsigned int type, unsigned int code, * unsigned int value); - * void add_interrupt_randomness(int irq); + * void add_interrupt_randomness(int irq, int irq_flags); * void add_disk_randomness(struct gendisk *disk); * * add_input_randomness() uses the input layer interrupt timing, as well as * the event type information from the hardware. * - * add_interrupt_randomness() uses the inter-interrupt timing as random - * inputs to the entropy pool. Note that not all interrupts are good - * sources of randomness! For example, the timer interrupts is not a - * good choice, because the periodicity of the interrupts is too - * regular, and hence predictable to an attacker. Network Interface - * Controller interrupts are a better measure, since the timing of the - * NIC interrupts are more unpredictable. + * add_interrupt_randomness() uses the interrupt timing as random + * inputs to the entropy pool. Using the cycle counters and the irq source + * as inputs, it feeds the randomness roughly once a second. * * add_disk_randomness() uses what amounts to the seek time of block * layer request events, on a per-disk_devt basis, as input to the @@ -248,6 +244,7 @@ #include #include #include +#include #ifdef CONFIG_GENERIC_HARDIRQS # include @@ -256,6 +253,7 @@ #include #include #include +#include #include /* @@ -421,7 +419,9 @@ struct entropy_store { spinlock_t lock; unsigned add_ptr; int entropy_count; + int entropy_total; int input_rotate; + unsigned int initialized:1; __u8 last_data[EXTRACT_SIZE]; }; @@ -454,6 +454,10 @@ static struct entropy_store nonblocking_pool = { .pool = nonblocking_pool_data }; +static __u32 const twist_table[8] = { + 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, + 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; + /* * This function adds bytes into the entropy "pool". It does not * update the entropy estimate. The caller should call @@ -467,9 +471,6 @@ static struct entropy_store nonblocking_pool = { static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, int nbytes, __u8 out[64]) { - static __u32 const twist_table[8] = { - 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, - 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; unsigned long i, j, tap1, tap2, tap3, tap4, tap5; int input_rotate; int wordmask = r->poolinfo->poolwords - 1; @@ -528,6 +529,36 @@ static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) mix_pool_bytes_extract(r, in, bytes, NULL); } +struct fast_pool { + __u32 pool[4]; + unsigned long last; + unsigned short count; + unsigned char rotate; + unsigned char last_timer_intr; +}; + +/* + * This is a fast mixing routine used by the interrupt randomness + * collector. It's hardcoded for an 128 bit pool and assumes that any + * locks that might be needed are taken by the caller. + */ +static void fast_mix(struct fast_pool *f, const void *in, int nbytes) +{ + const char *bytes = in; + __u32 w; + unsigned i = f->count; + unsigned input_rotate = f->rotate; + + while (nbytes--) { + w = rol32(*bytes++, input_rotate & 31) ^ f->pool[i & 3] ^ + f->pool[(i + 1) & 3]; + f->pool[i & 3] = (w >> 3) ^ twist_table[w & 7]; + input_rotate += (i++ & 3) ? 7 : 14; + } + f->count = i; + f->rotate = input_rotate; +} + /* * Credit (or debit) the entropy store with n bits of entropy */ @@ -551,6 +582,12 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) entropy_count = r->poolinfo->POOLBITS; r->entropy_count = entropy_count; + if (!r->initialized && nbits > 0) { + r->entropy_total += nbits; + if (r->entropy_total > 128) + r->initialized = 1; + } + /* should we wake readers? */ if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { wake_up_interruptible(&random_read_wait); @@ -700,17 +737,48 @@ void add_input_randomness(unsigned int type, unsigned int code, } EXPORT_SYMBOL_GPL(add_input_randomness); -void add_interrupt_randomness(int irq) +static DEFINE_PER_CPU(struct fast_pool, irq_randomness); + +void add_interrupt_randomness(int irq, int irq_flags) { - struct timer_rand_state *state; + struct entropy_store *r; + struct fast_pool *fast_pool = &__get_cpu_var(irq_randomness); + struct pt_regs *regs = get_irq_regs(); + unsigned long now = jiffies; + __u32 input[4], cycles = get_cycles(); + + input[0] = cycles ^ jiffies; + input[1] = irq; + if (regs) { + __u64 ip = instruction_pointer(regs); + input[2] = ip; + input[3] = ip >> 32; + } - state = get_timer_rand_state(irq); + fast_mix(fast_pool, input, sizeof(input)); - if (state == NULL) + if ((fast_pool->count & 1023) && + !time_after(now, fast_pool->last + HZ)) return; - DEBUG_ENT("irq event %d\n", irq); - add_timer_randomness(state, 0x100 + irq); + fast_pool->last = now; + + r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool; + mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool)); + /* + * If we don't have a valid cycle counter, and we see + * back-to-back timer interrupts, then skip giving credit for + * any entropy. + */ + if (cycles == 0) { + if (irq_flags & __IRQF_TIMER) { + if (fast_pool->last_timer_intr) + return; + fast_pool->last_timer_intr = 1; + } else + fast_pool->last_timer_intr = 0; + } + credit_entropy_bits(r, 1); } #ifdef CONFIG_BLOCK @@ -971,6 +1039,7 @@ static void init_std_data(struct entropy_store *r) spin_lock_irqsave(&r->lock, flags); r->entropy_count = 0; + r->entropy_total = 0; spin_unlock_irqrestore(&r->lock, flags); now = ktime_get_real(); diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 1efad20fb17..9522d6bda4f 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -409,8 +409,6 @@ static irqreturn_t ab3100_irq_handler(int irq, void *data) u32 fatevent; int err; - add_interrupt_randomness(irq); - err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, event_regs, 3); if (err) diff --git a/include/linux/random.h b/include/linux/random.h index 8f74538c96d..6ef39d7f2db 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -52,7 +52,7 @@ extern void rand_initialize_irq(int irq); extern void add_input_randomness(unsigned int type, unsigned int code, unsigned int value); -extern void add_interrupt_randomness(int irq); +extern void add_interrupt_randomness(int irq, int irq_flags); extern void get_random_bytes(void *buf, int nbytes); void generate_random_uuid(unsigned char uuid_out[16]); diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index bdb18032555..131ca176b49 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -133,7 +133,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) { irqreturn_t retval = IRQ_NONE; - unsigned int random = 0, irq = desc->irq_data.irq; + unsigned int flags = 0, irq = desc->irq_data.irq; do { irqreturn_t res; @@ -161,7 +161,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) /* Fall through to add to randomness */ case IRQ_HANDLED: - random |= action->flags; + flags |= action->flags; break; default: @@ -172,8 +172,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) action = action->next; } while (action); - if (random & IRQF_SAMPLE_RANDOM) - add_interrupt_randomness(irq); + add_interrupt_randomness(irq, flags); if (!noirqdebug) note_interrupt(irq, desc, retval); From e0604ba541f04a542ee9a7f6a468a60688ad8c72 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 4 Jul 2012 10:38:30 -0400 Subject: [PATCH 0666/2357] random: use lockless techniques in the interrupt path commit 902c098a3663de3fa18639efbb71b6080f0bcd3c upstream. The real-time Linux folks don't like add_interrupt_randomness() taking a spinlock since it is called in the low-level interrupt routine. This also allows us to reduce the overhead in the fast path, for the random driver, which is the interrupt collection path. Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index c59dbc6e758..ed784934225 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -418,9 +418,9 @@ struct entropy_store { /* read-write data: */ spinlock_t lock; unsigned add_ptr; + unsigned input_rotate; int entropy_count; int entropy_total; - int input_rotate; unsigned int initialized:1; __u8 last_data[EXTRACT_SIZE]; }; @@ -468,26 +468,24 @@ static __u32 const twist_table[8] = { * it's cheap to do so and helps slightly in the expected case where * the entropy is concentrated in the low-order bits. */ -static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, - int nbytes, __u8 out[64]) +static void __mix_pool_bytes(struct entropy_store *r, const void *in, + int nbytes, __u8 out[64]) { unsigned long i, j, tap1, tap2, tap3, tap4, tap5; int input_rotate; int wordmask = r->poolinfo->poolwords - 1; const char *bytes = in; __u32 w; - unsigned long flags; - /* Taps are constant, so we can load them without holding r->lock. */ tap1 = r->poolinfo->tap1; tap2 = r->poolinfo->tap2; tap3 = r->poolinfo->tap3; tap4 = r->poolinfo->tap4; tap5 = r->poolinfo->tap5; - spin_lock_irqsave(&r->lock, flags); - input_rotate = r->input_rotate; - i = r->add_ptr; + smp_rmb(); + input_rotate = ACCESS_ONCE(r->input_rotate); + i = ACCESS_ONCE(r->add_ptr); /* mix one byte at a time to simplify size handling and churn faster */ while (nbytes--) { @@ -514,19 +512,23 @@ static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, input_rotate += i ? 7 : 14; } - r->input_rotate = input_rotate; - r->add_ptr = i; + ACCESS_ONCE(r->input_rotate) = input_rotate; + ACCESS_ONCE(r->add_ptr) = i; + smp_wmb(); if (out) for (j = 0; j < 16; j++) ((__u32 *)out)[j] = r->pool[(i - j) & wordmask]; - - spin_unlock_irqrestore(&r->lock, flags); } -static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) +static void mix_pool_bytes(struct entropy_store *r, const void *in, + int nbytes, __u8 out[64]) { - mix_pool_bytes_extract(r, in, bytes, NULL); + unsigned long flags; + + spin_lock_irqsave(&r->lock, flags); + __mix_pool_bytes(r, in, nbytes, out); + spin_unlock_irqrestore(&r->lock, flags); } struct fast_pool { @@ -564,23 +566,22 @@ static void fast_mix(struct fast_pool *f, const void *in, int nbytes) */ static void credit_entropy_bits(struct entropy_store *r, int nbits) { - unsigned long flags; - int entropy_count; + int entropy_count, orig; if (!nbits) return; - spin_lock_irqsave(&r->lock, flags); - DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); - entropy_count = r->entropy_count; +retry: + entropy_count = orig = ACCESS_ONCE(r->entropy_count); entropy_count += nbits; if (entropy_count < 0) { DEBUG_ENT("negative entropy/overflow\n"); entropy_count = 0; } else if (entropy_count > r->poolinfo->POOLBITS) entropy_count = r->poolinfo->POOLBITS; - r->entropy_count = entropy_count; + if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) + goto retry; if (!r->initialized && nbits > 0) { r->entropy_total += nbits; @@ -593,7 +594,6 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) wake_up_interruptible(&random_read_wait); kill_fasync(&fasync, SIGIO, POLL_IN); } - spin_unlock_irqrestore(&r->lock, flags); } /********************************************************************* @@ -680,7 +680,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) sample.cycles = get_cycles(); sample.num = num; - mix_pool_bytes(&input_pool, &sample, sizeof(sample)); + mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL); /* * Calculate number of bits of randomness we probably added. @@ -764,7 +764,7 @@ void add_interrupt_randomness(int irq, int irq_flags) fast_pool->last = now; r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool; - mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool)); + __mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL); /* * If we don't have a valid cycle counter, and we see * back-to-back timer interrupts, then skip giving credit for @@ -829,7 +829,7 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) bytes = extract_entropy(r->pull, tmp, bytes, random_read_wakeup_thresh / 8, rsvd); - mix_pool_bytes(r, tmp, bytes); + mix_pool_bytes(r, tmp, bytes, NULL); credit_entropy_bits(r, bytes*8); } } @@ -890,9 +890,11 @@ static void extract_buf(struct entropy_store *r, __u8 *out) int i; __u32 hash[5], workspace[SHA_WORKSPACE_WORDS]; __u8 extract[64]; + unsigned long flags; /* Generate a hash across the pool, 16 words (512 bits) at a time */ sha_init(hash); + spin_lock_irqsave(&r->lock, flags); for (i = 0; i < r->poolinfo->poolwords; i += 16) sha_transform(hash, (__u8 *)(r->pool + i), workspace); @@ -905,7 +907,8 @@ static void extract_buf(struct entropy_store *r, __u8 *out) * brute-forcing the feedback as hard as brute-forcing the * hash. */ - mix_pool_bytes_extract(r, hash, sizeof(hash), extract); + __mix_pool_bytes(r, hash, sizeof(hash), extract); + spin_unlock_irqrestore(&r->lock, flags); /* * To avoid duplicates, we atomically extract a portion of the @@ -928,11 +931,10 @@ static void extract_buf(struct entropy_store *r, __u8 *out) } static ssize_t extract_entropy(struct entropy_store *r, void *buf, - size_t nbytes, int min, int reserved) + size_t nbytes, int min, int reserved) { ssize_t ret = 0, i; __u8 tmp[EXTRACT_SIZE]; - unsigned long flags; xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, min, reserved); @@ -941,6 +943,8 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, extract_buf(r, tmp); if (fips_enabled) { + unsigned long flags; + spin_lock_irqsave(&r->lock, flags); if (!memcmp(tmp, r->last_data, EXTRACT_SIZE)) panic("Hardware RNG duplicated output!\n"); @@ -1034,22 +1038,18 @@ EXPORT_SYMBOL(get_random_bytes); static void init_std_data(struct entropy_store *r) { int i; - ktime_t now; - unsigned long flags; + ktime_t now = ktime_get_real(); + unsigned long rv; - spin_lock_irqsave(&r->lock, flags); r->entropy_count = 0; r->entropy_total = 0; - spin_unlock_irqrestore(&r->lock, flags); - - now = ktime_get_real(); - mix_pool_bytes(r, &now, sizeof(now)); - for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof flags) { - if (!arch_get_random_long(&flags)) + mix_pool_bytes(r, &now, sizeof(now), NULL); + for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) { + if (!arch_get_random_long(&rv)) break; - mix_pool_bytes(r, &flags, sizeof(flags)); + mix_pool_bytes(r, &rv, sizeof(rv), NULL); } - mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); + mix_pool_bytes(r, utsname(), sizeof(*(utsname())), NULL); } static int rand_initialize(void) @@ -1186,7 +1186,7 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count) count -= bytes; p += bytes; - mix_pool_bytes(r, buf, bytes); + mix_pool_bytes(r, buf, bytes, NULL); cond_resched(); } From 1d0eb350ee278cb257178a14c4c9d965d7d2835e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 4 Jul 2012 11:16:01 -0400 Subject: [PATCH 0667/2357] random: create add_device_randomness() interface commit a2080a67abe9e314f9e9c2cc3a4a176e8a8f8793 upstream. Add a new interface, add_device_randomness() for adding data to the random pool that is likely to differ between two devices (or possibly even per boot). This would be things like MAC addresses or serial numbers, or the read-out of the RTC. This does *not* add any actual entropy to the pool, but it initializes the pool to different values for devices that might otherwise be identical and have very little entropy available to them (particularly common in the embedded world). [ Modified by tytso to mix in a timestamp, since there may be some variability caused by the time needed to detect/configure the hardware in question. ] Signed-off-by: Linus Torvalds Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 28 ++++++++++++++++++++++++++++ include/linux/random.h | 1 + 2 files changed, 29 insertions(+) diff --git a/drivers/char/random.c b/drivers/char/random.c index ed784934225..0b22268207b 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -125,11 +125,20 @@ * The current exported interfaces for gathering environmental noise * from the devices are: * + * void add_device_randomness(const void *buf, unsigned int size); * void add_input_randomness(unsigned int type, unsigned int code, * unsigned int value); * void add_interrupt_randomness(int irq, int irq_flags); * void add_disk_randomness(struct gendisk *disk); * + * add_device_randomness() is for adding data to the random pool that + * is likely to differ between two devices (or possibly even per boot). + * This would be things like MAC addresses or serial numbers, or the + * read-out of the RTC. This does *not* add any actual entropy to the + * pool, but it initializes the pool to different values for devices + * that might otherwise be identical and have very little entropy + * available to them (particularly common in the embedded world). + * * add_input_randomness() uses the input layer interrupt timing, as well as * the event type information from the hardware. * @@ -646,6 +655,25 @@ static void set_timer_rand_state(unsigned int irq, } #endif +/* + * Add device- or boot-specific data to the input and nonblocking + * pools to help initialize them to unique values. + * + * None of this adds any entropy, it is meant to avoid the + * problem of the nonblocking pool having similar initial state + * across largely identical devices. + */ +void add_device_randomness(const void *buf, unsigned int size) +{ + unsigned long time = get_cycles() ^ jiffies; + + mix_pool_bytes(&input_pool, buf, size, NULL); + mix_pool_bytes(&input_pool, &time, sizeof(time), NULL); + mix_pool_bytes(&nonblocking_pool, buf, size, NULL); + mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL); +} +EXPORT_SYMBOL(add_device_randomness); + static struct timer_rand_state input_timer_state; /* diff --git a/include/linux/random.h b/include/linux/random.h index 6ef39d7f2db..e14b4387354 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -50,6 +50,7 @@ struct rnd_state { extern void rand_initialize_irq(int irq); +extern void add_device_randomness(const void *, unsigned int); extern void add_input_randomness(unsigned int type, unsigned int code, unsigned int value); extern void add_interrupt_randomness(int irq, int irq_flags); From 76b9be5d7feba335f0bfd4edf0386296cdaf57f2 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 4 Jul 2012 11:22:20 -0400 Subject: [PATCH 0668/2357] usb: feed USB device information to the /dev/random driver commit b04b3156a20d395a7faa8eed98698d1e17a36000 upstream. Send the USB device's serial, product, and manufacturer strings to the /dev/random driver to help seed its pools. Cc: Linus Torvalds Acked-by: Greg KH Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6241b717042..e727b876726 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -1951,6 +1952,14 @@ int usb_new_device(struct usb_device *udev) /* Tell the world! */ announce_device(udev); + if (udev->serial) + add_device_randomness(udev->serial, strlen(udev->serial)); + if (udev->product) + add_device_randomness(udev->product, strlen(udev->product)); + if (udev->manufacturer) + add_device_randomness(udev->manufacturer, + strlen(udev->manufacturer)); + device_enable_async_suspend(&udev->dev); /* From e48fa33d22f6a28b57ade6522230755eae394548 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 4 Jul 2012 21:23:25 -0400 Subject: [PATCH 0669/2357] net: feed /dev/random with the MAC address when registering a device commit 7bf2357524408b97fec58344caf7397f8140c3fd upstream. Signed-off-by: "Theodore Ts'o" Cc: David Miller Cc: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 3 +++ net/core/rtnetlink.c | 1 + 2 files changed, 4 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 533c586c64d..c299416d0e8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1173,6 +1173,7 @@ static int __dev_open(struct net_device *dev) net_dmaengine_get(); dev_set_rx_mode(dev); dev_activate(dev); + add_device_randomness(dev->dev_addr, dev->addr_len); } return ret; @@ -4765,6 +4766,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) err = ops->ndo_set_mac_address(dev, sa); if (!err) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + add_device_randomness(dev->dev_addr, dev->addr_len); return err; } EXPORT_SYMBOL(dev_set_mac_address); @@ -5543,6 +5545,7 @@ int register_netdevice(struct net_device *dev) dev_init_scheduler(dev); dev_hold(dev); list_netdevice(dev); + add_device_randomness(dev->dev_addr, dev->addr_len); /* Notify protocols, that a new device appeared. */ ret = call_netdevice_notifiers(NETDEV_REGISTER, dev); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b8052bab69c..900fc6162c4 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1376,6 +1376,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, goto errout; send_addr_notify = 1; modified = 1; + add_device_randomness(dev->dev_addr, dev->addr_len); } if (tb[IFLA_MTU]) { From f5caa70697d4da107f8fd33fe74977a8ec192aaf Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 5 Jul 2012 10:21:01 -0400 Subject: [PATCH 0670/2357] random: use the arch-specific rng in xfer_secondary_pool commit e6d4947b12e8ad947add1032dd754803c6004824 upstream. If the CPU supports a hardware random number generator, use it in xfer_secondary_pool(), where it will significantly improve things and where we can afford it. Also, remove the use of the arch-specific rng in add_timer_randomness(), since the call is significantly slower than get_cycles(), and we're much better off using it in xfer_secondary_pool() anyway. Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 0b22268207b..2296ff16231 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -254,6 +254,7 @@ #include #include #include +#include #ifdef CONFIG_GENERIC_HARDIRQS # include @@ -702,11 +703,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) goto out; sample.jiffies = jiffies; - - /* Use arch random value, fall back to cycles */ - if (!arch_get_random_int(&sample.cycles)) - sample.cycles = get_cycles(); - + sample.cycles = get_cycles(); sample.num = num; mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL); @@ -838,7 +835,11 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, */ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) { - __u32 tmp[OUTPUT_POOL_WORDS]; + union { + __u32 tmp[OUTPUT_POOL_WORDS]; + long hwrand[4]; + } u; + int i; if (r->pull && r->entropy_count < nbytes * 8 && r->entropy_count < r->poolinfo->POOLBITS) { @@ -849,17 +850,23 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) /* pull at least as many as BYTES as wakeup BITS */ bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); /* but never more than the buffer size */ - bytes = min_t(int, bytes, sizeof(tmp)); + bytes = min_t(int, bytes, sizeof(u.tmp)); DEBUG_ENT("going to reseed %s with %d bits " "(%d of %d requested)\n", r->name, bytes * 8, nbytes * 8, r->entropy_count); - bytes = extract_entropy(r->pull, tmp, bytes, + bytes = extract_entropy(r->pull, u.tmp, bytes, random_read_wakeup_thresh / 8, rsvd); - mix_pool_bytes(r, tmp, bytes, NULL); + mix_pool_bytes(r, u.tmp, bytes, NULL); credit_entropy_bits(r, bytes*8); } + kmemcheck_mark_initialized(&u.hwrand, sizeof(u.hwrand)); + for (i = 0; i < 4; i++) + if (arch_get_random_long(&u.hwrand[i])) + break; + if (i) + mix_pool_bytes(r, &u.hwrand, sizeof(u.hwrand), 0); } /* From 29aef9dee78ac45c5bd7f91434b05144ec220abd Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 5 Jul 2012 10:35:23 -0400 Subject: [PATCH 0671/2357] random: add new get_random_bytes_arch() function commit c2557a303ab6712bb6e09447df828c557c710ac9 upstream. Create a new function, get_random_bytes_arch() which will use the architecture-specific hardware random number generator if it is present. Change get_random_bytes() to not use the HW RNG, even if it is avaiable. The reason for this is that the hw random number generator is fast (if it is present), but it requires that we trust the hardware manufacturer to have not put in a back door. (For example, an increasing counter encrypted by an AES key known to the NSA.) It's unlikely that Intel (for example) was paid off by the US Government to do this, but it's impossible for them to prove otherwise --- especially since Bull Mountain is documented to use AES as a whitener. Hence, the output of an evil, trojan-horse version of RDRAND is statistically indistinguishable from an RDRAND implemented to the specifications claimed by Intel. Short of using a tunnelling electronic microscope to reverse engineer an Ivy Bridge chip and disassembling and analyzing the CPU microcode, there's no way for us to tell for sure. Since users of get_random_bytes() in the Linux kernel need to be able to support hardware systems where the HW RNG is not present, most time-sensitive users of this interface have already created their own cryptographic RNG interface which uses get_random_bytes() as a seed. So it's much better to use the HW RNG to improve the existing random number generator, by mixing in any entropy returned by the HW RNG into /dev/random's entropy pool, but to always _use_ /dev/random's entropy pool. This way we get almost of the benefits of the HW RNG without any potential liabilities. The only benefits we forgo is the speed/performance enhancements --- and generic kernel code can't depend on depend on get_random_bytes() having the speed of a HW RNG anyway. For those places that really want access to the arch-specific HW RNG, if it is available, we provide get_random_bytes_arch(). Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 29 ++++++++++++++++++++++++----- include/linux/random.h | 1 + 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 2296ff16231..ed7e283b6cb 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1038,17 +1038,34 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, /* * This function is the exported kernel interface. It returns some - * number of good random numbers, suitable for seeding TCP sequence - * numbers, etc. + * number of good random numbers, suitable for key generation, seeding + * TCP sequence numbers, etc. It does not use the hw random number + * generator, if available; use get_random_bytes_arch() for that. */ void get_random_bytes(void *buf, int nbytes) +{ + extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); +} +EXPORT_SYMBOL(get_random_bytes); + +/* + * This function will use the architecture-specific hardware random + * number generator if it is available. The arch-specific hw RNG will + * almost certainly be faster than what we can do in software, but it + * is impossible to verify that it is implemented securely (as + * opposed, to, say, the AES encryption of a sequence number using a + * key known by the NSA). So it's useful if we need the speed, but + * only if we're willing to trust the hardware manufacturer not to + * have put in a back door. + */ +void get_random_bytes_arch(void *buf, int nbytes) { char *p = buf; while (nbytes) { unsigned long v; int chunk = min(nbytes, (int)sizeof(unsigned long)); - + if (!arch_get_random_long(&v)) break; @@ -1057,9 +1074,11 @@ void get_random_bytes(void *buf, int nbytes) nbytes -= chunk; } - extract_entropy(&nonblocking_pool, p, nbytes, 0, 0); + if (nbytes) + extract_entropy(&nonblocking_pool, p, nbytes, 0, 0); } -EXPORT_SYMBOL(get_random_bytes); +EXPORT_SYMBOL(get_random_bytes_arch); + /* * init_std_data - initialize pool with system data diff --git a/include/linux/random.h b/include/linux/random.h index e14b4387354..29e217a7e6d 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -56,6 +56,7 @@ extern void add_input_randomness(unsigned int type, unsigned int code, extern void add_interrupt_randomness(int irq, int irq_flags); extern void get_random_bytes(void *buf, int nbytes); +extern void get_random_bytes_arch(void *buf, int nbytes); void generate_random_uuid(unsigned char uuid_out[16]); #ifndef MODULE From 38e16fc638792ddc12da853c4836602a8708e166 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 4 Jul 2012 16:19:30 -0400 Subject: [PATCH 0672/2357] random: add tracepoints for easier debugging and verification commit 00ce1db1a634746040ace24c09a4e3a7949a3145 upstream. Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 26 ++++++- include/trace/events/random.h | 134 ++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 include/trace/events/random.h diff --git a/drivers/char/random.c b/drivers/char/random.c index ed7e283b6cb..45dd0470294 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -266,6 +266,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + /* * Configuration information */ @@ -478,8 +481,8 @@ static __u32 const twist_table[8] = { * it's cheap to do so and helps slightly in the expected case where * the entropy is concentrated in the low-order bits. */ -static void __mix_pool_bytes(struct entropy_store *r, const void *in, - int nbytes, __u8 out[64]) +static void _mix_pool_bytes(struct entropy_store *r, const void *in, + int nbytes, __u8 out[64]) { unsigned long i, j, tap1, tap2, tap3, tap4, tap5; int input_rotate; @@ -531,13 +534,21 @@ static void __mix_pool_bytes(struct entropy_store *r, const void *in, ((__u32 *)out)[j] = r->pool[(i - j) & wordmask]; } -static void mix_pool_bytes(struct entropy_store *r, const void *in, +static void __mix_pool_bytes(struct entropy_store *r, const void *in, int nbytes, __u8 out[64]) +{ + trace_mix_pool_bytes_nolock(r->name, nbytes, _RET_IP_); + _mix_pool_bytes(r, in, nbytes, out); +} + +static void mix_pool_bytes(struct entropy_store *r, const void *in, + int nbytes, __u8 out[64]) { unsigned long flags; + trace_mix_pool_bytes(r->name, nbytes, _RET_IP_); spin_lock_irqsave(&r->lock, flags); - __mix_pool_bytes(r, in, nbytes, out); + _mix_pool_bytes(r, in, nbytes, out); spin_unlock_irqrestore(&r->lock, flags); } @@ -585,6 +596,7 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) retry: entropy_count = orig = ACCESS_ONCE(r->entropy_count); entropy_count += nbits; + if (entropy_count < 0) { DEBUG_ENT("negative entropy/overflow\n"); entropy_count = 0; @@ -599,6 +611,9 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) r->initialized = 1; } + trace_credit_entropy_bits(r->name, nbits, entropy_count, + r->entropy_total, _RET_IP_); + /* should we wake readers? */ if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { wake_up_interruptible(&random_read_wait); @@ -971,6 +986,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, ssize_t ret = 0, i; __u8 tmp[EXTRACT_SIZE]; + trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_); xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, min, reserved); @@ -1005,6 +1021,7 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, ssize_t ret = 0, i; __u8 tmp[EXTRACT_SIZE]; + trace_extract_entropy_user(r->name, nbytes, r->entropy_count, _RET_IP_); xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, 0, 0); @@ -1062,6 +1079,7 @@ void get_random_bytes_arch(void *buf, int nbytes) { char *p = buf; + trace_get_random_bytes(nbytes, _RET_IP_); while (nbytes) { unsigned long v; int chunk = min(nbytes, (int)sizeof(unsigned long)); diff --git a/include/trace/events/random.h b/include/trace/events/random.h new file mode 100644 index 00000000000..422df19de73 --- /dev/null +++ b/include/trace/events/random.h @@ -0,0 +1,134 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM random + +#if !defined(_TRACE_RANDOM_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_RANDOM_H + +#include +#include + +DECLARE_EVENT_CLASS(random__mix_pool_bytes, + TP_PROTO(const char *pool_name, int bytes, unsigned long IP), + + TP_ARGS(pool_name, bytes, IP), + + TP_STRUCT__entry( + __field( const char *, pool_name ) + __field( int, bytes ) + __field(unsigned long, IP ) + ), + + TP_fast_assign( + __entry->pool_name = pool_name; + __entry->bytes = bytes; + __entry->IP = IP; + ), + + TP_printk("%s pool: bytes %d caller %pF", + __entry->pool_name, __entry->bytes, (void *)__entry->IP) +); + +DEFINE_EVENT(random__mix_pool_bytes, mix_pool_bytes, + TP_PROTO(const char *pool_name, int bytes, unsigned long IP), + + TP_ARGS(pool_name, bytes, IP) +); + +DEFINE_EVENT(random__mix_pool_bytes, mix_pool_bytes_nolock, + TP_PROTO(const char *pool_name, int bytes, unsigned long IP), + + TP_ARGS(pool_name, bytes, IP) +); + +TRACE_EVENT(credit_entropy_bits, + TP_PROTO(const char *pool_name, int bits, int entropy_count, + int entropy_total, unsigned long IP), + + TP_ARGS(pool_name, bits, entropy_count, entropy_total, IP), + + TP_STRUCT__entry( + __field( const char *, pool_name ) + __field( int, bits ) + __field( int, entropy_count ) + __field( int, entropy_total ) + __field(unsigned long, IP ) + ), + + TP_fast_assign( + __entry->pool_name = pool_name; + __entry->bits = bits; + __entry->entropy_count = entropy_count; + __entry->entropy_total = entropy_total; + __entry->IP = IP; + ), + + TP_printk("%s pool: bits %d entropy_count %d entropy_total %d " + "caller %pF", __entry->pool_name, __entry->bits, + __entry->entropy_count, __entry->entropy_total, + (void *)__entry->IP) +); + +TRACE_EVENT(get_random_bytes, + TP_PROTO(int nbytes, unsigned long IP), + + TP_ARGS(nbytes, IP), + + TP_STRUCT__entry( + __field( int, nbytes ) + __field(unsigned long, IP ) + ), + + TP_fast_assign( + __entry->nbytes = nbytes; + __entry->IP = IP; + ), + + TP_printk("nbytes %d caller %pF", __entry->nbytes, (void *)__entry->IP) +); + +DECLARE_EVENT_CLASS(random__extract_entropy, + TP_PROTO(const char *pool_name, int nbytes, int entropy_count, + unsigned long IP), + + TP_ARGS(pool_name, nbytes, entropy_count, IP), + + TP_STRUCT__entry( + __field( const char *, pool_name ) + __field( int, nbytes ) + __field( int, entropy_count ) + __field(unsigned long, IP ) + ), + + TP_fast_assign( + __entry->pool_name = pool_name; + __entry->nbytes = nbytes; + __entry->entropy_count = entropy_count; + __entry->IP = IP; + ), + + TP_printk("%s pool: nbytes %d entropy_count %d caller %pF", + __entry->pool_name, __entry->nbytes, __entry->entropy_count, + (void *)__entry->IP) +); + + +DEFINE_EVENT(random__extract_entropy, extract_entropy, + TP_PROTO(const char *pool_name, int nbytes, int entropy_count, + unsigned long IP), + + TP_ARGS(pool_name, nbytes, entropy_count, IP) +); + +DEFINE_EVENT(random__extract_entropy, extract_entropy_user, + TP_PROTO(const char *pool_name, int nbytes, int entropy_count, + unsigned long IP), + + TP_ARGS(pool_name, nbytes, entropy_count, IP) +); + + + +#endif /* _TRACE_RANDOM_H */ + +/* This part must be outside protection */ +#include From ba6a40b952f6384eaec33af9f6c31d3a67ac073e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 4 Jul 2012 11:32:48 -0400 Subject: [PATCH 0673/2357] MAINTAINERS: Theodore Ts'o is taking over the random driver commit 330e0a01d54c2b8606c56816f99af6ebc58ec92c upstream. Matt Mackall stepped down as the /dev/random driver maintainer last year, so Theodore Ts'o is taking back the /dev/random driver. Cc: Matt Mackall Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index b3627098650..a60009da728 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5566,7 +5566,7 @@ F: Documentation/blockdev/ramdisk.txt F: drivers/block/brd.c RANDOM NUMBER DRIVER -M: Matt Mackall +M: Theodore Ts'o" S: Maintained F: drivers/char/random.c From ec947d6fbb66bc4e55eef7550b4fc835090a42be Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 5 Jul 2012 20:19:17 +0000 Subject: [PATCH 0674/2357] rtc: wm831x: Feed the write counter into device_add_randomness() commit 9dccf55f4cb011a7552a8a2749a580662f5ed8ed upstream. The tamper evident features of the RTC include the "write counter" which is a pseudo-random number regenerated whenever we set the RTC. Since this value is unpredictable it should provide some useful seeding to the random number generator. Only do this on boot since the goal is to seed the pool rather than add useful entropy. Signed-off-by: Mark Brown Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-wm831x.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index 3b6e6a67e76..41c06fe5415 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -24,7 +24,7 @@ #include #include #include - +#include /* * R16416 (0x4020) - RTC Write Counter @@ -96,6 +96,26 @@ struct wm831x_rtc { unsigned int alarm_enabled:1; }; +static void wm831x_rtc_add_randomness(struct wm831x *wm831x) +{ + int ret; + u16 reg; + + /* + * The write counter contains a pseudo-random number which is + * regenerated every time we set the RTC so it should be a + * useful per-system source of entropy. + */ + ret = wm831x_reg_read(wm831x, WM831X_RTC_WRITE_COUNTER); + if (ret >= 0) { + reg = ret; + add_device_randomness(®, sizeof(reg)); + } else { + dev_warn(wm831x->dev, "Failed to read RTC write counter: %d\n", + ret); + } +} + /* * Read current time and date in RTC */ @@ -431,6 +451,8 @@ static int wm831x_rtc_probe(struct platform_device *pdev) alm_irq, ret); } + wm831x_rtc_add_randomness(wm831x); + return 0; err: From 12dae51a7567bb1e583ee0de6af538db256504db Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 5 Jul 2012 20:23:21 +0000 Subject: [PATCH 0675/2357] mfd: wm831x: Feed the device UUID into device_add_randomness() commit 27130f0cc3ab97560384da437e4621fc4e94f21c upstream. wm831x devices contain a unique ID value. Feed this into the newly added device_add_randomness() to add some per device seed data to the pool. Signed-off-by: Mark Brown Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/wm831x-otp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mfd/wm831x-otp.c b/drivers/mfd/wm831x-otp.c index f742745ff35..b90f3e06b6c 100644 --- a/drivers/mfd/wm831x-otp.c +++ b/drivers/mfd/wm831x-otp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,7 @@ static DEVICE_ATTR(unique_id, 0444, wm831x_unique_id_show, NULL); int wm831x_otp_init(struct wm831x *wm831x) { + char uuid[WM831X_UNIQUE_ID_LEN]; int ret; ret = device_create_file(wm831x->dev, &dev_attr_unique_id); @@ -73,6 +75,12 @@ int wm831x_otp_init(struct wm831x *wm831x) dev_err(wm831x->dev, "Unique ID attribute not created: %d\n", ret); + ret = wm831x_unique_id_read(wm831x, uuid); + if (ret == 0) + add_device_randomness(uuid, sizeof(uuid)); + else + dev_err(wm831x->dev, "Failed to read UUID: %d\n", ret); + return ret; } From 26665db4f7fa71c56eeb9205e79927cfc21e70c4 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 14 Jul 2012 20:27:52 -0400 Subject: [PATCH 0676/2357] random: remove rand_initialize_irq() commit c5857ccf293968348e5eb4ebedc68074de3dcda6 upstream. With the new interrupt sampling system, we are no longer using the timer_rand_state structure in the irq descriptor, so we can stop initializing it now. [ Merged in fixes from Sedat to find some last missing references to rand_initialize_irq() ] Signed-off-by: "Theodore Ts'o" Signed-off-by: Sedat Dilek Signed-off-by: Greg Kroah-Hartman --- arch/ia64/kernel/irq_ia64.c | 1 - drivers/char/random.c | 55 ------------------------------------- drivers/mfd/ab3100-core.c | 3 -- include/linux/irqdesc.h | 1 - include/linux/random.h | 2 -- kernel/irq/manage.c | 17 ------------ 6 files changed, 79 deletions(-) diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 5c3e0888265..1034884b77d 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -23,7 +23,6 @@ #include #include #include -#include /* for rand_initialize_irq() */ #include #include #include diff --git a/drivers/char/random.c b/drivers/char/random.c index 45dd0470294..e08be062023 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -634,43 +634,6 @@ struct timer_rand_state { unsigned dont_count_entropy:1; }; -#ifndef CONFIG_GENERIC_HARDIRQS - -static struct timer_rand_state *irq_timer_state[NR_IRQS]; - -static struct timer_rand_state *get_timer_rand_state(unsigned int irq) -{ - return irq_timer_state[irq]; -} - -static void set_timer_rand_state(unsigned int irq, - struct timer_rand_state *state) -{ - irq_timer_state[irq] = state; -} - -#else - -static struct timer_rand_state *get_timer_rand_state(unsigned int irq) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - - return desc->timer_rand_state; -} - -static void set_timer_rand_state(unsigned int irq, - struct timer_rand_state *state) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - - desc->timer_rand_state = state; -} -#endif - /* * Add device- or boot-specific data to the input and nonblocking * pools to help initialize them to unique values. @@ -1133,24 +1096,6 @@ static int rand_initialize(void) } module_init(rand_initialize); -void rand_initialize_irq(int irq) -{ - struct timer_rand_state *state; - - state = get_timer_rand_state(irq); - - if (state) - return; - - /* - * If kzalloc returns null, we just won't use that entropy - * source. - */ - state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) - set_timer_rand_state(irq, state); -} - #ifdef CONFIG_BLOCK void rand_initialize_disk(struct gendisk *disk) { diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 9522d6bda4f..1287645b984 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -931,9 +931,6 @@ static int __devinit ab3100_probe(struct i2c_client *client, err = request_threaded_irq(client->irq, NULL, ab3100_irq_handler, IRQF_ONESHOT, "ab3100-core", ab3100); - /* This real unpredictable IRQ is of course sampled for entropy */ - rand_initialize_irq(client->irq); - if (err) goto exit_no_irq; diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index f1e2527006b..9a323d12de1 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -39,7 +39,6 @@ struct module; */ struct irq_desc { struct irq_data irq_data; - struct timer_rand_state *timer_rand_state; unsigned int __percpu *kstat_irqs; irq_flow_handler_t handle_irq; #ifdef CONFIG_IRQ_PREFLOW_FASTEOI diff --git a/include/linux/random.h b/include/linux/random.h index 29e217a7e6d..ac621ce886c 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -48,8 +48,6 @@ struct rnd_state { #ifdef __KERNEL__ -extern void rand_initialize_irq(int irq); - extern void add_device_randomness(const void *, unsigned int); extern void add_input_randomness(unsigned int type, unsigned int code, unsigned int value); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 89a3ea82569..b9d1d83ec38 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -890,22 +890,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) return -ENOSYS; if (!try_module_get(desc->owner)) return -ENODEV; - /* - * Some drivers like serial.c use request_irq() heavily, - * so we have to be careful not to interfere with a - * running system. - */ - if (new->flags & IRQF_SAMPLE_RANDOM) { - /* - * This function might sleep, we want to call it first, - * outside of the atomic block. - * Yes, this might clear the entropy pool if the wrong - * driver is attempted to be loaded, without actually - * installing a new handler, but is this really a problem, - * only the sysadmin is able to do this. - */ - rand_initialize_irq(irq); - } /* * Check whether the interrupt nests into another interrupt @@ -1339,7 +1323,6 @@ EXPORT_SYMBOL(free_irq); * Flags: * * IRQF_SHARED Interrupt is shared - * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy * IRQF_TRIGGER_* Specify active edge(s) or level * */ From 73e62ae900d632d1bee9ab96c22508f8947da91a Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 23 Jul 2012 09:47:57 -0700 Subject: [PATCH 0677/2357] random: Add comment to random_initialize() commit cbc96b7594b5691d61eba2db8b2ea723645be9ca upstream. Many platforms have per-machine instance data (serial numbers, asset tags, etc.) squirreled away in areas that are accessed during early system bringup. Mixing this data into the random pools has a very high value in providing better random data, so we should allow (and even encourage) architecture code to call add_device_randomness() from the setup_arch() paths. However, this limits our options for internal structure of the random driver since random_initialize() is not called until long after setup_arch(). Add a big fat comment to rand_initialize() spelling out this requirement. Suggested-by: Theodore Ts'o Signed-off-by: Tony Luck Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/char/random.c b/drivers/char/random.c index e08be062023..9d8bcd50baf 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1087,6 +1087,16 @@ static void init_std_data(struct entropy_store *r) mix_pool_bytes(r, utsname(), sizeof(*(utsname())), NULL); } +/* + * Note that setup_arch() may call add_device_randomness() + * long before we get here. This allows seeding of the pools + * with some platform dependent data very early in the boot + * process. But it limits our options here. We must use + * statically allocated structures that already have all + * initializations complete at compile time. We should also + * take care not to overwrite the precious per platform data + * we were given. + */ static int rand_initialize(void) { init_std_data(&input_pool); From af2eb889f75b4206de39ea86f4f154498a9327f3 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 20 Jul 2012 13:15:20 -0700 Subject: [PATCH 0678/2357] dmi: Feed DMI table to /dev/random driver commit d114a33387472555188f142ed8e98acdb8181c6d upstream. Send the entire DMI (SMBIOS) table to the /dev/random driver to help seed its pools. Signed-off-by: Tony Luck Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/dmi_scan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 153980be4ee..b298158cb92 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -6,6 +6,7 @@ #include #include #include +#include #include /* @@ -111,6 +112,8 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *, dmi_table(buf, dmi_len, dmi_num, decode, NULL); + add_device_randomness(buf, dmi_len); + dmi_iounmap(buf, dmi_len); return 0; } From 7d696f0636c31f81d5cb613d45114d43896cfdb0 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 27 Jul 2012 22:26:08 -0400 Subject: [PATCH 0679/2357] random: mix in architectural randomness in extract_buf() commit d2e7c96af1e54b507ae2a6a7dd2baf588417a7e5 upstream. Mix in any architectural randomness in extract_buf() instead of xfer_secondary_buf(). This allows us to mix in more architectural randomness, and it also makes xfer_secondary_buf() faster, moving a tiny bit of additional CPU overhead to process which is extracting the randomness. [ Commit description modified by tytso to remove an extended advertisement for the RDRAND instruction. ] Signed-off-by: H. Peter Anvin Acked-by: Ingo Molnar Cc: DJ Johnston Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 56 ++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 9d8bcd50baf..d98b2a614cc 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -277,6 +277,8 @@ #define SEC_XFER_SIZE 512 #define EXTRACT_SIZE 10 +#define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) + /* * The minimum number of bits of entropy before we wake up a read on * /dev/random. Should be enough to do a significant reseed. @@ -813,11 +815,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, */ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) { - union { - __u32 tmp[OUTPUT_POOL_WORDS]; - long hwrand[4]; - } u; - int i; + __u32 tmp[OUTPUT_POOL_WORDS]; if (r->pull && r->entropy_count < nbytes * 8 && r->entropy_count < r->poolinfo->POOLBITS) { @@ -828,23 +826,17 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) /* pull at least as many as BYTES as wakeup BITS */ bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); /* but never more than the buffer size */ - bytes = min_t(int, bytes, sizeof(u.tmp)); + bytes = min_t(int, bytes, sizeof(tmp)); DEBUG_ENT("going to reseed %s with %d bits " "(%d of %d requested)\n", r->name, bytes * 8, nbytes * 8, r->entropy_count); - bytes = extract_entropy(r->pull, u.tmp, bytes, + bytes = extract_entropy(r->pull, tmp, bytes, random_read_wakeup_thresh / 8, rsvd); - mix_pool_bytes(r, u.tmp, bytes, NULL); + mix_pool_bytes(r, tmp, bytes, NULL); credit_entropy_bits(r, bytes*8); } - kmemcheck_mark_initialized(&u.hwrand, sizeof(u.hwrand)); - for (i = 0; i < 4; i++) - if (arch_get_random_long(&u.hwrand[i])) - break; - if (i) - mix_pool_bytes(r, &u.hwrand, sizeof(u.hwrand), 0); } /* @@ -901,15 +893,19 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, static void extract_buf(struct entropy_store *r, __u8 *out) { int i; - __u32 hash[5], workspace[SHA_WORKSPACE_WORDS]; + union { + __u32 w[5]; + unsigned long l[LONGS(EXTRACT_SIZE)]; + } hash; + __u32 workspace[SHA_WORKSPACE_WORDS]; __u8 extract[64]; unsigned long flags; /* Generate a hash across the pool, 16 words (512 bits) at a time */ - sha_init(hash); + sha_init(hash.w); spin_lock_irqsave(&r->lock, flags); for (i = 0; i < r->poolinfo->poolwords; i += 16) - sha_transform(hash, (__u8 *)(r->pool + i), workspace); + sha_transform(hash.w, (__u8 *)(r->pool + i), workspace); /* * We mix the hash back into the pool to prevent backtracking @@ -920,14 +916,14 @@ static void extract_buf(struct entropy_store *r, __u8 *out) * brute-forcing the feedback as hard as brute-forcing the * hash. */ - __mix_pool_bytes(r, hash, sizeof(hash), extract); + __mix_pool_bytes(r, hash.w, sizeof(hash.w), extract); spin_unlock_irqrestore(&r->lock, flags); /* * To avoid duplicates, we atomically extract a portion of the * pool while mixing, and hash one final time. */ - sha_transform(hash, extract, workspace); + sha_transform(hash.w, extract, workspace); memset(extract, 0, sizeof(extract)); memset(workspace, 0, sizeof(workspace)); @@ -936,11 +932,23 @@ static void extract_buf(struct entropy_store *r, __u8 *out) * pattern, we fold it in half. Thus, we always feed back * twice as much data as we output. */ - hash[0] ^= hash[3]; - hash[1] ^= hash[4]; - hash[2] ^= rol32(hash[2], 16); - memcpy(out, hash, EXTRACT_SIZE); - memset(hash, 0, sizeof(hash)); + hash.w[0] ^= hash.w[3]; + hash.w[1] ^= hash.w[4]; + hash.w[2] ^= rol32(hash.w[2], 16); + + /* + * If we have a architectural hardware random number + * generator, mix that in, too. + */ + for (i = 0; i < LONGS(EXTRACT_SIZE); i++) { + unsigned long v; + if (!arch_get_random_long(&v)) + break; + hash.l[i] ^= v; + } + + memcpy(out, &hash, EXTRACT_SIZE); + memset(&hash, 0, sizeof(hash)); } static ssize_t extract_entropy(struct entropy_store *r, void *buf, From 20e24cb2c6a9d72c2b1627ddd54584ec87b54082 Mon Sep 17 00:00:00 2001 From: Austin Hendrix Date: Mon, 4 Jun 2012 15:27:51 -0700 Subject: [PATCH 0680/2357] HID: multitouch: add support for Novatek touchscreen commit 4db703ead4535792ea54dba7275fdd1527848e74 upstream. Add support for a Novatek touchscreen panel as a generic HID multitouch panel. Signed-off-by: Austin Hendrix Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index bb1abf83798..18613d429cd 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -567,6 +567,9 @@ #define USB_VENDOR_ID_NINTENDO 0x057e #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 +#define USB_VENDOR_ID_NOVATEK 0x0603 +#define USB_DEVICE_ID_NOVATEK_PCT 0x0600 + #define USB_VENDOR_ID_NTRIG 0x1b96 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index a6197f57203..e754dff1da5 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -940,6 +940,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT880) }, + /* Novatek Panel */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_NOVATEK, + USB_DEVICE_ID_NOVATEK_PCT) }, + /* PenMount panels */ { .driver_data = MT_CLS_CONFIDENCE, HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, From 21bba6e1209f246ee7fd71daf7cde00aa4564832 Mon Sep 17 00:00:00 2001 From: Lionel Vaux Date: Sun, 22 Jul 2012 11:32:20 +0200 Subject: [PATCH 0681/2357] HID: add support for Cypress barcode scanner 04B4:ED81 commit 76c9d8fe2c7fc34ffc387d8022c5828d6ff9df48 upstream. Add yet another device to the list of Cypress barcode scanners needing the CP_RDESC_SWAPPED_MIN_MAX quirk. Signed-off-by: Lionel Vaux (iouri) Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-cypress.c | 2 ++ drivers/hid/hid-ids.h | 1 + 3 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 973c238eb9f..64587af1c02 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1410,6 +1410,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index 2f0be4c66af..9e43aaca977 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c @@ -129,6 +129,8 @@ static const struct hid_device_id cp_devices[] = { .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3), .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4), + .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE), .driver_data = CP_2WHEEL_MOUSE_HACK }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 18613d429cd..6e303e1b8f2 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -231,6 +231,7 @@ #define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61 #define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64 #define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1 +#define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81 #define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001 #define USB_VENDOR_ID_DEALEXTREAME 0x10c5 From 575b5ea19669112f9f7a7e2c09e9cdb914f4683e Mon Sep 17 00:00:00 2001 From: Cyrus Lien Date: Mon, 23 Jul 2012 17:11:51 +0800 Subject: [PATCH 0682/2357] HID: add ASUS AIO keyboard model AK1D commit 2d8767bb421574dfcf48e4be0751ce7d8f73d5d7 upstream. Add Asus All-In-One PC keyboard model AK1D. BugLink: https://bugs.launchpad.net/bugs/1027789 Signed-off-by: Cyrus Lien Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-chicony.c | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index b99af346fdf..a2abb8e1572 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c @@ -60,6 +60,7 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, static const struct hid_device_id ch_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, { } }; MODULE_DEVICE_TABLE(hid, ch_devices); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 64587af1c02..41d4437411c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1404,6 +1404,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 6e303e1b8f2..41ad6ff548c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -202,6 +202,7 @@ #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 #define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 +#define USB_DEVICE_ID_CHICONY_AK1D 0x1125 #define USB_VENDOR_ID_CHUNGHWAT 0x2247 #define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 From a434a3c014dfc52d07efa7817f1339124300aed4 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Sun, 6 May 2012 11:11:04 -0600 Subject: [PATCH 0683/2357] x86, microcode: microcode_core.c simple_strtoul cleanup commit e826abd523913f63eb03b59746ffb16153c53dc4 upstream. Change reload_for_cpu() in kernel/microcode_core.c to call kstrtoul() instead of calling obsoleted simple_strtoul(). Signed-off-by: Shuah Khan Reviewed-by: Borislav Petkov Link: http://lkml.kernel.org/r/1336324264.2897.9.camel@lorien2 Signed-off-by: H. Peter Anvin Cc: Henrique de Moraes Holschuh Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/microcode_core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index c9bda6d6035..fbdfc691718 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c @@ -299,12 +299,11 @@ static ssize_t reload_store(struct device *dev, { unsigned long val; int cpu = dev->id; - int ret = 0; - char *end; + ssize_t ret = 0; - val = simple_strtoul(buf, &end, 0); - if (end == buf) - return -EINVAL; + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; if (val == 1) { get_online_cpus(); From a05f127752f743db1b53e0309977573566ce5b6f Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 21 Jun 2012 14:07:16 +0200 Subject: [PATCH 0684/2357] x86, microcode: Sanitize per-cpu microcode reloading interface commit c9fc3f778a6a215ace14ee556067c73982b6d40f upstream. Microcode reloading in a per-core manner is a very bad idea for both major x86 vendors. And the thing is, we have such interface with which we can end up with different microcode versions applied on different cores of an otherwise homogeneous wrt (family,model,stepping) system. So turn off the possibility of doing that per core and allow it only system-wide. This is a minimal fix which we'd like to see in stable too thus the more-or-less arbitrary decision to allow system-wide reloading only on the BSP: $ echo 1 > /sys/devices/system/cpu/cpu0/microcode/reload ... and disable the interface on the other cores: $ echo 1 > /sys/devices/system/cpu/cpu23/microcode/reload -bash: echo: write error: Invalid argument Also, allowing the reload only from one CPU (the BSP in that case) doesn't allow the reload procedure to degenerate into an O(n^2) deal when triggering reloads from all /sys/devices/system/cpu/cpuX/microcode/reload sysfs nodes simultaneously. A more generic fix will follow. Signed-off-by: Borislav Petkov Cc: Henrique de Moraes Holschuh Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1340280437-7718-2-git-send-email-bp@amd64.org Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/microcode_core.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index fbdfc691718..24b852b61be 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c @@ -298,19 +298,31 @@ static ssize_t reload_store(struct device *dev, const char *buf, size_t size) { unsigned long val; - int cpu = dev->id; - ssize_t ret = 0; + int cpu; + ssize_t ret = 0, tmp_ret; + + /* allow reload only from the BSP */ + if (boot_cpu_data.cpu_index != dev->id) + return -EINVAL; ret = kstrtoul(buf, 0, &val); if (ret) return ret; - if (val == 1) { - get_online_cpus(); - if (cpu_online(cpu)) - ret = reload_for_cpu(cpu); - put_online_cpus(); + if (val != 1) + return size; + + get_online_cpus(); + for_each_online_cpu(cpu) { + tmp_ret = reload_for_cpu(cpu); + if (tmp_ret != 0) + pr_warn("Error reloading microcode on CPU %d\n", cpu); + + /* save retval of the first encountered reload error */ + if (!ret) + ret = tmp_ret; } + put_online_cpus(); if (!ret) ret = size; From 49ca240411df57586fecddd1152ff30cbef82d59 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Tue, 31 Jul 2012 16:46:20 -0700 Subject: [PATCH 0685/2357] mm: hugetlbfs: close race during teardown of hugetlbfs shared page tables commit d833352a4338dc31295ed832a30c9ccff5c7a183 upstream. If a process creates a large hugetlbfs mapping that is eligible for page table sharing and forks heavily with children some of whom fault and others which destroy the mapping then it is possible for page tables to get corrupted. Some teardowns of the mapping encounter a "bad pmd" and output a message to the kernel log. The final teardown will trigger a BUG_ON in mm/filemap.c. This was reproduced in 3.4 but is known to have existed for a long time and goes back at least as far as 2.6.37. It was probably was introduced in 2.6.20 by [39dde65c: shared page table for hugetlb page]. The messages look like this; [ ..........] Lots of bad pmd messages followed by this [ 127.164256] mm/memory.c:391: bad pmd ffff880412e04fe8(80000003de4000e7). [ 127.164257] mm/memory.c:391: bad pmd ffff880412e04ff0(80000003de6000e7). [ 127.164258] mm/memory.c:391: bad pmd ffff880412e04ff8(80000003de0000e7). [ 127.186778] ------------[ cut here ]------------ [ 127.186781] kernel BUG at mm/filemap.c:134! [ 127.186782] invalid opcode: 0000 [#1] SMP [ 127.186783] CPU 7 [ 127.186784] Modules linked in: af_packet cpufreq_conservative cpufreq_userspace cpufreq_powersave acpi_cpufreq mperf ext3 jbd dm_mod coretemp crc32c_intel usb_storage ghash_clmulni_intel aesni_intel i2c_i801 r8169 mii uas sr_mod cdrom sg iTCO_wdt iTCO_vendor_support shpchp serio_raw cryptd aes_x86_64 e1000e pci_hotplug dcdbas aes_generic container microcode ext4 mbcache jbd2 crc16 sd_mod crc_t10dif i915 drm_kms_helper drm i2c_algo_bit ehci_hcd ahci libahci usbcore rtc_cmos usb_common button i2c_core intel_agp video intel_gtt fan processor thermal thermal_sys hwmon ata_generic pata_atiixp libata scsi_mod [ 127.186801] [ 127.186802] Pid: 9017, comm: hugetlbfs-test Not tainted 3.4.0-autobuild #53 Dell Inc. OptiPlex 990/06D7TR [ 127.186804] RIP: 0010:[] [] __delete_from_page_cache+0x15e/0x160 [ 127.186809] RSP: 0000:ffff8804144b5c08 EFLAGS: 00010002 [ 127.186810] RAX: 0000000000000001 RBX: ffffea000a5c9000 RCX: 00000000ffffffc0 [ 127.186811] RDX: 0000000000000000 RSI: 0000000000000009 RDI: ffff88042dfdad00 [ 127.186812] RBP: ffff8804144b5c18 R08: 0000000000000009 R09: 0000000000000003 [ 127.186813] R10: 0000000000000000 R11: 000000000000002d R12: ffff880412ff83d8 [ 127.186814] R13: ffff880412ff83d8 R14: 0000000000000000 R15: ffff880412ff83d8 [ 127.186815] FS: 00007fe18ed2c700(0000) GS:ffff88042dce0000(0000) knlGS:0000000000000000 [ 127.186816] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 127.186817] CR2: 00007fe340000503 CR3: 0000000417a14000 CR4: 00000000000407e0 [ 127.186818] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 127.186819] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 127.186820] Process hugetlbfs-test (pid: 9017, threadinfo ffff8804144b4000, task ffff880417f803c0) [ 127.186821] Stack: [ 127.186822] ffffea000a5c9000 0000000000000000 ffff8804144b5c48 ffffffff810ed83b [ 127.186824] ffff8804144b5c48 000000000000138a 0000000000001387 ffff8804144b5c98 [ 127.186825] ffff8804144b5d48 ffffffff811bc925 ffff8804144b5cb8 0000000000000000 [ 127.186827] Call Trace: [ 127.186829] [] delete_from_page_cache+0x3b/0x80 [ 127.186832] [] truncate_hugepages+0x115/0x220 [ 127.186834] [] hugetlbfs_evict_inode+0x13/0x30 [ 127.186837] [] evict+0xa7/0x1b0 [ 127.186839] [] iput_final+0xd3/0x1f0 [ 127.186840] [] iput+0x39/0x50 [ 127.186842] [] d_kill+0xf8/0x130 [ 127.186843] [] dput+0xd2/0x1a0 [ 127.186845] [] __fput+0x170/0x230 [ 127.186848] [] ? rb_erase+0xce/0x150 [ 127.186849] [] fput+0x1d/0x30 [ 127.186851] [] remove_vma+0x37/0x80 [ 127.186853] [] do_munmap+0x2d2/0x360 [ 127.186855] [] sys_shmdt+0xc9/0x170 [ 127.186857] [] system_call_fastpath+0x16/0x1b [ 127.186858] Code: 0f 1f 44 00 00 48 8b 43 08 48 8b 00 48 8b 40 28 8b b0 40 03 00 00 85 f6 0f 88 df fe ff ff 48 89 df e8 e7 cb 05 00 e9 d2 fe ff ff <0f> 0b 55 83 e2 fd 48 89 e5 48 83 ec 30 48 89 5d d8 4c 89 65 e0 [ 127.186868] RIP [] __delete_from_page_cache+0x15e/0x160 [ 127.186870] RSP [ 127.186871] ---[ end trace 7cbac5d1db69f426 ]--- The bug is a race and not always easy to reproduce. To reproduce it I was doing the following on a single socket I7-based machine with 16G of RAM. $ hugeadm --pool-pages-max DEFAULT:13G $ echo $((18*1048576*1024)) > /proc/sys/kernel/shmmax $ echo $((18*1048576*1024)) > /proc/sys/kernel/shmall $ for i in `seq 1 9000`; do ./hugetlbfs-test; done On my particular machine, it usually triggers within 10 minutes but enabling debug options can change the timing such that it never hits. Once the bug is triggered, the machine is in trouble and needs to be rebooted. The machine will respond but processes accessing proc like "ps aux" will hang due to the BUG_ON. shutdown will also hang and needs a hard reset or a sysrq-b. The basic problem is a race between page table sharing and teardown. For the most part page table sharing depends on i_mmap_mutex. In some cases, it is also taking the mm->page_table_lock for the PTE updates but with shared page tables, it is the i_mmap_mutex that is more important. Unfortunately it appears to be also insufficient. Consider the following situation Process A Process B --------- --------- hugetlb_fault shmdt LockWrite(mmap_sem) do_munmap unmap_region unmap_vmas unmap_single_vma unmap_hugepage_range Lock(i_mmap_mutex) Lock(mm->page_table_lock) huge_pmd_unshare/unmap tables <--- (1) Unlock(mm->page_table_lock) Unlock(i_mmap_mutex) huge_pte_alloc ... Lock(i_mmap_mutex) ... vma_prio_walk, find svma, spte ... Lock(mm->page_table_lock) ... share spte ... Unlock(mm->page_table_lock) ... Unlock(i_mmap_mutex) ... hugetlb_no_page <--- (2) free_pgtables unlink_file_vma hugetlb_free_pgd_range remove_vma_list In this scenario, it is possible for Process A to share page tables with Process B that is trying to tear them down. The i_mmap_mutex on its own does not prevent Process A walking Process B's page tables. At (1) above, the page tables are not shared yet so it unmaps the PMDs. Process A sets up page table sharing and at (2) faults a new entry. Process B then trips up on it in free_pgtables. This patch fixes the problem by adding a new function __unmap_hugepage_range_final that is only called when the VMA is about to be destroyed. This function clears VM_MAYSHARE during unmap_hugepage_range() under the i_mmap_mutex. This makes the VMA ineligible for sharing and avoids the race. Superficially this looks like it would then be vunerable to truncate and madvise issues but hugetlbfs has its own truncate handlers so does not use unmap_mapping_range() and does not support madvise(DONTNEED). This should be treated as a -stable candidate if it is merged. Test program is as follows. The test case was mostly written by Michal Hocko with a few minor changes to reproduce this bug. ==== CUT HERE ==== static size_t huge_page_size = (2UL << 20); static size_t nr_huge_page_A = 512; static size_t nr_huge_page_B = 5632; unsigned int get_random(unsigned int max) { struct timeval tv; gettimeofday(&tv, NULL); srandom(tv.tv_usec); return random() % max; } static void play(void *addr, size_t size) { unsigned char *start = addr, *end = start + size, *a; start += get_random(size/2); /* we could itterate on huge pages but let's give it more time. */ for (a = start; a < end; a += 4096) *a = 0; } int main(int argc, char **argv) { key_t key = IPC_PRIVATE; size_t sizeA = nr_huge_page_A * huge_page_size; size_t sizeB = nr_huge_page_B * huge_page_size; int shmidA, shmidB; void *addrA = NULL, *addrB = NULL; int nr_children = 300, n = 0; if ((shmidA = shmget(key, sizeA, IPC_CREAT|SHM_HUGETLB|0660)) == -1) { perror("shmget:"); return 1; } if ((addrA = shmat(shmidA, addrA, SHM_R|SHM_W)) == (void *)-1UL) { perror("shmat"); return 1; } if ((shmidB = shmget(key, sizeB, IPC_CREAT|SHM_HUGETLB|0660)) == -1) { perror("shmget:"); return 1; } if ((addrB = shmat(shmidB, addrB, SHM_R|SHM_W)) == (void *)-1UL) { perror("shmat"); return 1; } fork_child: switch(fork()) { case 0: switch (n%3) { case 0: play(addrA, sizeA); break; case 1: play(addrB, sizeB); break; case 2: break; } break; case -1: perror("fork:"); break; default: if (++n < nr_children) goto fork_child; play(addrA, sizeA); break; } shmdt(addrA); shmdt(addrB); do { wait(NULL); } while (--n > 0); shmctl(shmidA, IPC_RMID, NULL); shmctl(shmidB, IPC_RMID, NULL); return 0; } [akpm@linux-foundation.org: name the declaration's args, fix CONFIG_HUGETLBFS=n build] Signed-off-by: Hugh Dickins Reviewed-by: Michal Hocko Signed-off-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/hugetlb.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 263e17703b3..a799df59d31 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2392,6 +2392,22 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, { mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex); __unmap_hugepage_range(vma, start, end, ref_page); + /* + * Clear this flag so that x86's huge_pmd_share page_table_shareable + * test will fail on a vma being torn down, and not grab a page table + * on its way out. We're lucky that the flag has such an appropriate + * name, and can in fact be safely cleared here. We could clear it + * before the __unmap_hugepage_range above, but all that's necessary + * is to clear it before releasing the i_mmap_mutex below. + * + * This works because in the contexts this is called, the VMA is + * going to be destroyed. It is not vunerable to madvise(DONTNEED) + * because madvise is not supported on hugetlbfs. The same applies + * for direct IO. unmap_hugepage_range() is only being called just + * before free_pgtables() so clearing VM_MAYSHARE will not cause + * surprises later. + */ + vma->vm_flags &= ~VM_MAYSHARE; mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex); } @@ -2958,9 +2974,14 @@ void hugetlb_change_protection(struct vm_area_struct *vma, } } spin_unlock(&mm->page_table_lock); - mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex); - + /* + * Must flush TLB before releasing i_mmap_mutex: x86's huge_pmd_unshare + * may have cleared our pud entry and done put_page on the page table: + * once we release i_mmap_mutex, another task can do the final put_page + * and that page table be reused and filled with junk. + */ flush_tlb_range(vma, start, end); + mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex); } int hugetlb_reserve_pages(struct inode *inode, From 74c90d4c3e5ee158cec2f6f32f6fb3cbfc0a2f47 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:22 -0700 Subject: [PATCH 0686/2357] target: Add range checking to UNMAP emulation commit 2594e29865c291db162313187612cd9f14538f33 upstream. When processing an UNMAP command, we need to make sure that the number of blocks we're asked to UNMAP does not exceed our reported maximum number of blocks per UNMAP, and that the range of blocks we're unmapping doesn't go past the end of the device. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger [bwh: Backported to 3.2: adjust filename, context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_cdb.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index fa323f8aa17..7e3135120ba 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -1053,6 +1053,18 @@ int target_emulate_unmap(struct se_task *task) pr_debug("UNMAP: Using lba: %llu and range: %u\n", (unsigned long long)lba, range); + if (range > dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count) { + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; + goto err; + } + + if (lba + range > dev->transport->get_blocks(dev) + 1) { + cmd->scsi_sense_reason = TCM_ADDRESS_OUT_OF_RANGE; + ret = -EINVAL; + goto err; + } + ret = dev->transport->do_discard(dev, lba, range); if (ret < 0) { pr_err("blkdev_issue_discard() failed: %d\n", From 6fb6469c601a80a0c883ec0be189ecf1677ecf56 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:23 -0700 Subject: [PATCH 0687/2357] target: Fix reading of data length fields for UNMAP commands commit 1a5fa4576ec8a462313c7516b31d7453481ddbe8 upstream. The UNMAP DATA LENGTH and UNMAP BLOCK DESCRIPTOR DATA LENGTH fields are in the unmap descriptor (the payload transferred to our data out buffer), not in the CDB itself. Read them from the correct place in target_emulated_unmap. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger [bwh: Backported to 3.2: adjust filename, context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_cdb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 7e3135120ba..2150d2af3dc 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -1022,7 +1022,6 @@ int target_emulate_unmap(struct se_task *task) struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf, *ptr = NULL; - unsigned char *cdb = &cmd->t_task_cdb[0]; sector_t lba; unsigned int size = cmd->data_length, range; int ret = 0, offset; @@ -1038,11 +1037,12 @@ int target_emulate_unmap(struct se_task *task) /* First UNMAP block descriptor starts at 8 byte offset */ offset = 8; size -= 8; - dl = get_unaligned_be16(&cdb[0]); - bd_dl = get_unaligned_be16(&cdb[2]); buf = transport_kmap_data_sg(cmd); + dl = get_unaligned_be16(&buf[0]); + bd_dl = get_unaligned_be16(&buf[2]); + ptr = &buf[offset]; pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); From c329e96ae86fb69c30287a434426f2083fb2430b Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:24 -0700 Subject: [PATCH 0688/2357] target: Fix possible integer underflow in UNMAP emulation commit b7fc7f3777582dea85156a821d78a522a0c083aa upstream. It's possible for an initiator to send us an UNMAP command with a descriptor that is less than 8 bytes; in that case it's really bad for us to set an unsigned int to that value, subtract 8 from it, and then use that as a limit for our loop (since the value will wrap around to a huge positive value). Fix this by making size be signed and only looping if size >= 16 (ie if we have at least a full descriptor available). Also remove offset as an obfuscated name for the constant 8. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger [bwh: Backported to 3.2: adjust filename, context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_cdb.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 2150d2af3dc..94d89f2b97d 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -1023,9 +1023,10 @@ int target_emulate_unmap(struct se_task *task) struct se_device *dev = cmd->se_dev; unsigned char *buf, *ptr = NULL; sector_t lba; - unsigned int size = cmd->data_length, range; - int ret = 0, offset; - unsigned short dl, bd_dl; + int size = cmd->data_length; + u32 range; + int ret = 0; + int dl, bd_dl; if (!dev->transport->do_discard) { pr_err("UNMAP emulation not supported for: %s\n", @@ -1034,20 +1035,19 @@ int target_emulate_unmap(struct se_task *task) return -ENOSYS; } - /* First UNMAP block descriptor starts at 8 byte offset */ - offset = 8; - size -= 8; - buf = transport_kmap_data_sg(cmd); dl = get_unaligned_be16(&buf[0]); bd_dl = get_unaligned_be16(&buf[2]); - ptr = &buf[offset]; - pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" + size = min(size - 8, bd_dl); + + /* First UNMAP block descriptor starts at 8 byte offset */ + ptr = &buf[8]; + pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u" " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); - while (size) { + while (size >= 16) { lba = get_unaligned_be64(&ptr[0]); range = get_unaligned_be32(&ptr[8]); pr_debug("UNMAP: Using lba: %llu and range: %u\n", From 6213566323948ac7ed0aa4eb78058e77d445b0f8 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:25 -0700 Subject: [PATCH 0689/2357] target: Check number of unmap descriptors against our limit commit 7409a6657aebf8be74c21d0eded80709b27275cb upstream. Fail UNMAP commands that have more than our reported limit on unmap descriptors. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger [bwh: Backported to 3.2: adjust filename] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_cdb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 94d89f2b97d..52a5f6208ac 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -1041,6 +1041,11 @@ int target_emulate_unmap(struct se_task *task) bd_dl = get_unaligned_be16(&buf[2]); size = min(size - 8, bd_dl); + if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; + goto err; + } /* First UNMAP block descriptor starts at 8 byte offset */ ptr = &buf[8]; From 87a266d5801001c09687fb4d755e336bad733c10 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 3 Aug 2012 20:54:48 +0200 Subject: [PATCH 0690/2357] ARM: mxs: Remove MMAP_MIN_ADDR setting from mxs_defconfig commit 3bed491c8d28329e34f8a31e3fe64d03f3a350f1 upstream. The CONFIG_DEFAULT_MMAP_MIN_ADDR was set to 65536 in mxs_defconfig, this caused severe breakage of userland applications since the upper limit for ARM is 32768. By default CONFIG_DEFAULT_MMAP_MIN_ADDR is set to 4096 and can also be changed via /proc/sys/vm/mmap_min_addr if needed. Quoting Russell King [1]: "4096 is also fine for ARM too. There's not much point in having defconfigs change it - that would just be pure noise in the config files." the CONFIG_DEFAULT_MMAP_MIN_ADDR can be removed from the defconfig altogether. This problem was introduced by commit cde7c41 (ARM: configs: add defconfig for mach-mxs). [1] http://marc.info/?l=linux-arm-kernel&m=134401593807820&w=2 Signed-off-by: Marek Vasut Cc: Russell King Cc: Wolfgang Denk Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- arch/arm/configs/mxs_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index 1ebbf451c48..70d0bf40c96 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -32,7 +32,6 @@ CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT_VOLUNTARY=y CONFIG_AEABI=y -CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 CONFIG_AUTO_ZRELADDR=y CONFIG_FPE_NWFPE=y CONFIG_NET=y From 0f27ec339c656ab8dc9255ac8a61a1cecd32d599 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 2 Aug 2012 22:48:39 +0800 Subject: [PATCH 0691/2357] ARM: dts: imx53-ard: add regulators for lan9220 commit 1eec0c569523782392b5e6245effddb626213b8c upstream. Since commit c7e963f (net/smsc911x: Add regulator support), the lan9220 device tree probe fails on imx53-ard board, because the commit makes VDD33A and VDDVARIO supplies mandatory for the driver. Add a fixed dummy 3V3 supplying lan9220 to fix the regression. Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/imx53-ard.dts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/boot/dts/imx53-ard.dts b/arch/arm/boot/dts/imx53-ard.dts index 2dccce46ed8..7541a91b8fa 100644 --- a/arch/arm/boot/dts/imx53-ard.dts +++ b/arch/arm/boot/dts/imx53-ard.dts @@ -70,10 +70,30 @@ interrupt-parent = <&gpio2>; interrupts = <31>; reg-io-width = <4>; + /* + * VDD33A and VDDVARIO of LAN9220 are supplied by + * SW4_3V3 of LTC3589. Before the regulator driver + * for this PMIC is available, we use a fixed dummy + * 3V3 regulator to get LAN9220 driver probing work. + */ + vdd33a-supply = <®_3p3v>; + vddvario-supply = <®_3p3v>; smsc,irq-push-pull; }; }; + regulators { + compatible = "simple-bus"; + + reg_3p3v: 3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + gpio-keys { compatible = "gpio-keys"; From 5784dff6267c788b40a2c9931b13a079e9011936 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sun, 5 Aug 2012 14:58:37 +0000 Subject: [PATCH 0692/2357] ARM: pxa: remove irq_to_gpio from ezx-pcap driver commit 59ee93a528b94ef4e81a08db252b0326feff171f upstream. The irq_to_gpio function was removed from the pxa platform in linux-3.2, and this driver has been broken since. There is actually no in-tree user of this driver that adds this platform device, but the driver can and does get enabled on some platforms. Without this patch, building ezx_defconfig results in: drivers/mfd/ezx-pcap.c: In function 'pcap_isr_work': drivers/mfd/ezx-pcap.c:205:2: error: implicit declaration of function 'irq_to_gpio' [-Werror=implicit-function-declaration] Signed-off-by: Arnd Bergmann Acked-by: Haojian Zhuang Cc: Samuel Ortiz Cc: Daniel Ribeiro Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/ezx-pcap.c | 2 +- include/linux/mfd/ezx-pcap.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 43a76c41cfc..db662e2dcfa 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -202,7 +202,7 @@ static void pcap_isr_work(struct work_struct *work) } local_irq_enable(); ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); - } while (gpio_get_value(irq_to_gpio(pcap->spi->irq))); + } while (gpio_get_value(pdata->gpio)); } static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) diff --git a/include/linux/mfd/ezx-pcap.h b/include/linux/mfd/ezx-pcap.h index 40c372165f3..32a1b5cfeba 100644 --- a/include/linux/mfd/ezx-pcap.h +++ b/include/linux/mfd/ezx-pcap.h @@ -16,6 +16,7 @@ struct pcap_subdev { struct pcap_platform_data { unsigned int irq_base; unsigned int config; + int gpio; void (*init) (void *); /* board specific init */ int num_subdevs; struct pcap_subdev *subdevs; From 25320e75fe0296dab5ae37c6b59f18899cd1c310 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 2 Aug 2012 18:41:48 +0100 Subject: [PATCH 0693/2357] cfg80211: process pending events when unregistering net device commit 1f6fc43e621167492ed4b7f3b4269c584c3d6ccc upstream. libertas currently calls cfg80211_disconnected() when it is being brought down. This causes an event to be allocated, but since the wdev is already removed from the rdev by the time that the event processing work executes, the event is never processed or freed. http://article.gmane.org/gmane.linux.kernel.wireless.general/95666 Fix this leak, and other possible situations, by processing the event queue when a device is being unregistered. Thanks to Johannes Berg for the suggestion. Signed-off-by: Daniel Drake Reviewed-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/core.c | 5 +++++ net/wireless/core.h | 1 + net/wireless/util.c | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index ccdfed89765..bb5302dd592 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -975,6 +975,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, */ synchronize_rcu(); INIT_LIST_HEAD(&wdev->list); + /* + * Ensure that all events have been processed and + * freed. + */ + cfg80211_process_wdev_events(wdev); break; case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) diff --git a/net/wireless/core.h b/net/wireless/core.h index 3ac2dd00d71..ce5597c6459 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -426,6 +426,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, struct net_device *dev, enum nl80211_iftype ntype, u32 *flags, struct vif_params *params); void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); +void cfg80211_process_wdev_events(struct wireless_dev *wdev); int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, diff --git a/net/wireless/util.c b/net/wireless/util.c index 0eb6cc0c77d..63b37d3f3c0 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -717,7 +717,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) wdev->connect_keys = NULL; } -static void cfg80211_process_wdev_events(struct wireless_dev *wdev) +void cfg80211_process_wdev_events(struct wireless_dev *wdev) { struct cfg80211_event *ev; unsigned long flags; From 510f1d143b72225df068a31b2b105edaef5f2420 Mon Sep 17 00:00:00 2001 From: Liang Li Date: Thu, 2 Aug 2012 18:55:41 -0400 Subject: [PATCH 0694/2357] cfg80211: fix interface combinations check for ADHOC(IBSS) partial of commit 8e8b41f9d8c8e63fc92f899ace8da91a490ac573 upstream. As part of commit 463454b5dbd8 ("cfg80211: fix interface combinations check"), this extra check was introduced: if ((all_iftypes & used_iftypes) != used_iftypes) goto cont; However, most wireless NIC drivers did not advertise ADHOC in wiphy.iface_combinations[i].limits[] and hence we'll get -EBUSY when we bring up a ADHOC wlan with commands similar to: # iwconfig wlan0 mode ad-hoc && ifconfig wlan0 up In commit 8e8b41f9d8c8e ("cfg80211: enforce lack of interface combinations"), the change below fixes the issue: if (total == 1) return 0; But it also introduces other dependencies for stable. For example, a full cherry pick of 8e8b41f9d8c8e would introduce additional regressions unless we also start cherry picking driver specific fixes like the following: 9b4760e ath5k: add possible wiphy interface combinations 1ae2fc2 mac80211_hwsim: advertise interface combinations 20c8e8d ath9k: add possible wiphy interface combinations And the purpose of the 'if (total == 1)' is to cover the specific use case (IBSS, adhoc) that was mentioned above. So we just pick the specific part out from 8e8b41f9d8c8e here. Doing so gives stable kernels a way to fix the change introduced by 463454b5dbd8, without having to make cherry picks specific to various NIC drivers. Signed-off-by: Liang Li Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- net/wireless/util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/wireless/util.c b/net/wireless/util.c index 63b37d3f3c0..d835377b4da 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -974,6 +974,9 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, } mutex_unlock(&rdev->devlist_mtx); + if (total == 1) + return 0; + for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { const struct ieee80211_iface_combination *c; struct ieee80211_iface_limit *limits; From c6c0038af718e3c29d5369aa799ea120d8f67112 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 9 Aug 2012 02:50:40 +0000 Subject: [PATCH 0695/2357] tun: don't zeroize sock->file on detach commit 66d1b9263a371abd15806c53f486f0645ef31a8f upstream. This is a fix for bug, introduced in 3.4 kernel by commit 1ab5ecb90cb6a3df1476e052f76a6e8f6511cb3d ("tun: don't hold network namespace by tun sockets"), which, among other things, replaced simple sock_put() by sk_release_kernel(). Below is sequence, which leads to oops for non-persistent devices: tun_chr_close() tun_detach() <== tun->socket.file = NULL tun_free_netdev() sk_release_sock() sock_release(sock->file == NULL) iput(SOCK_INODE(sock)) <== dereference on NULL pointer This patch just removes zeroing of socket's file from __tun_detach(). sock_release() will do this. Reported-by: Ruan Zhijie Tested-by: Ruan Zhijie Acked-by: Al Viro Acked-by: Eric Dumazet Acked-by: Yuchung Cheng Signed-off-by: Stanislav Kinsbursky Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/tun.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8f13420dd31..147b6284d7f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -185,7 +185,6 @@ static void __tun_detach(struct tun_struct *tun) netif_tx_lock_bh(tun->dev); netif_carrier_off(tun->dev); tun->tfile = NULL; - tun->socket.file = NULL; netif_tx_unlock_bh(tun->dev); /* Drop read queue */ From 66f3d999759fd703bf43acc0bd58b422701c77b4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 5 Aug 2012 18:31:46 +0200 Subject: [PATCH 0696/2357] iwlwifi: disable greenfield transmissions as a workaround commit 50e2a30cf6fcaeb2d27360ba614dd169a10041c5 upstream. There's a bug that causes the rate scaling to get stuck when it has to use single-stream rates with a peer that can do GF and SGI; the two are incompatible so we can't use them together, but that causes the algorithm to not work at all, it always rejects updates. Disable greenfield for now to prevent that problem. Reviewed-by: Emmanuel Grumbach Tested-by: Cesar Eduardo Barros Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index da2be3e09ee..7db5d45da23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -709,11 +709,14 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, */ static bool rs_use_green(struct ieee80211_sta *sta) { - struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - struct iwl_rxon_context *ctx = sta_priv->ctx; - - return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && - !(ctx->ht.non_gf_sta_present); + /* + * There's a bug somewhere in this code that causes the + * scaling to get stuck because GF+SGI can't be combined + * in SISO rates. Until we find that bug, disable GF, it + * has only limited benefit and we still interoperate with + * GF APs since we can always receive GF transmissions. + */ + return false; } /** From 733e9ad978a1530328ff78aff3186c20000e5b4e Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Tue, 31 Jul 2012 02:02:43 +0000 Subject: [PATCH 0697/2357] e1000e: NIC goes up and immediately goes down commit b7ec70be01a87f2c85df3ae11046e74f9b67e323 upstream. Found that commit d478eb44 was a bad commit. If the link partner is transmitting codeword (even if NULL codeword), then the RXCW.C bit will be set so check for RXCW.CW is unnecessary. Ref: RH BZ 840642 Reported-by: Fabio Futigami Signed-off-by: Tushar Dave CC: Marcelo Ricardo Leitner Tested-by: Aaron Brown Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/82571.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c index a9dd6a92cf5..c098b2495b7 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.c +++ b/drivers/net/ethernet/intel/e1000e/82571.c @@ -1582,10 +1582,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) * auto-negotiation in the TXCW register and disable * forced link in the Device Control register in an * attempt to auto-negotiate with our link partner. - * If the partner code word is null, stop forcing - * and restart auto negotiation. */ - if ((rxcw & E1000_RXCW_C) || !(rxcw & E1000_RXCW_CW)) { + if (rxcw & E1000_RXCW_C) { /* Enable autoneg, and unforce link up */ ew32(TXCW, mac->txcw); ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); From 95c92481f69cf89aa1db689940368c09fb425281 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 30 Apr 2012 16:21:37 +0000 Subject: [PATCH 0698/2357] Input: eeti_ts: pass gpio value instead of IRQ commit 4eef6cbfcc03b294d9d334368a851b35b496ce53 upstream. The EETI touchscreen asserts its IRQ line as soon as it has data in its internal buffers. The line is automatically deasserted once all data has been read via I2C. Hence, the driver has to monitor the GPIO line and cannot simply rely on the interrupt handler reception. In the current implementation of the driver, irq_to_gpio() is used to determine the GPIO number from the i2c_client's IRQ value. As irq_to_gpio() is not available on all platforms, this patch changes this and makes the driver ignore the passed in IRQ. Instead, a GPIO is added to the platform_data struct and gpio_to_irq is used to derive the IRQ from that GPIO. If this fails, bail out. The driver is only able to work in environments where the touchscreen GPIO can be mapped to an IRQ. Without this patch, building raumfeld_defconfig results in: drivers/input/touchscreen/eeti_ts.c: In function 'eeti_ts_irq_active': drivers/input/touchscreen/eeti_ts.c:65:2: error: implicit declaration of function 'irq_to_gpio' [-Werror=implicit-function-declaration] Signed-off-by: Daniel Mack Signed-off-by: Arnd Bergmann Cc: Dmitry Torokhov Cc: Sven Neumann Cc: linux-input@vger.kernel.org Cc: Haojian Zhuang Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-pxa/raumfeld.c | 2 +- drivers/input/touchscreen/eeti_ts.c | 21 +++++++++++++-------- include/linux/input/eeti_ts.h | 1 + 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 5905ed130e9..d89d87ae144 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -953,12 +953,12 @@ static struct i2c_board_info raumfeld_connector_i2c_board_info __initdata = { static struct eeti_ts_platform_data eeti_ts_pdata = { .irq_active_high = 1, + .irq_gpio = GPIO_TOUCH_IRQ, }; static struct i2c_board_info raumfeld_controller_i2c_board_info __initdata = { .type = "eeti_ts", .addr = 0x0a, - .irq = PXA_GPIO_TO_IRQ(GPIO_TOUCH_IRQ), .platform_data = &eeti_ts_pdata, }; diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 503c7096ed3..908407efc67 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -48,7 +48,7 @@ struct eeti_ts_priv { struct input_dev *input; struct work_struct work; struct mutex mutex; - int irq, irq_active_high; + int irq_gpio, irq, irq_active_high; }; #define EETI_TS_BITDEPTH (11) @@ -62,7 +62,7 @@ struct eeti_ts_priv { static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv) { - return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high; + return gpio_get_value(priv->irq_gpio) == priv->irq_active_high; } static void eeti_ts_read(struct work_struct *work) @@ -157,7 +157,7 @@ static void eeti_ts_close(struct input_dev *dev) static int __devinit eeti_ts_probe(struct i2c_client *client, const struct i2c_device_id *idp) { - struct eeti_ts_platform_data *pdata; + struct eeti_ts_platform_data *pdata = client->dev.platform_data; struct eeti_ts_priv *priv; struct input_dev *input; unsigned int irq_flags; @@ -199,9 +199,12 @@ static int __devinit eeti_ts_probe(struct i2c_client *client, priv->client = client; priv->input = input; - priv->irq = client->irq; + priv->irq_gpio = pdata->irq_gpio; + priv->irq = gpio_to_irq(pdata->irq_gpio); - pdata = client->dev.platform_data; + err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name); + if (err < 0) + goto err1; if (pdata) priv->irq_active_high = pdata->irq_active_high; @@ -215,13 +218,13 @@ static int __devinit eeti_ts_probe(struct i2c_client *client, err = input_register_device(input); if (err) - goto err1; + goto err2; err = request_irq(priv->irq, eeti_ts_isr, irq_flags, client->name, priv); if (err) { dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); - goto err2; + goto err3; } /* @@ -233,9 +236,11 @@ static int __devinit eeti_ts_probe(struct i2c_client *client, device_init_wakeup(&client->dev, 0); return 0; -err2: +err3: input_unregister_device(input); input = NULL; /* so we dont try to free it below */ +err2: + gpio_free(pdata->irq_gpio); err1: input_free_device(input); kfree(priv); diff --git a/include/linux/input/eeti_ts.h b/include/linux/input/eeti_ts.h index f875b316249..16625d799b6 100644 --- a/include/linux/input/eeti_ts.h +++ b/include/linux/input/eeti_ts.h @@ -2,6 +2,7 @@ #define LINUX_INPUT_EETI_TS_H struct eeti_ts_platform_data { + int irq_gpio; unsigned int irq_active_high; }; From 117b7f7c36e2e64d36e80d9aeadc2deff5007a3e Mon Sep 17 00:00:00 2001 From: Chris Bagwell Date: Tue, 12 Jun 2012 00:25:48 -0700 Subject: [PATCH 0699/2357] Input: wacom - Bamboo One 1024 pressure fix commit 6dc463511d4a690f01a9248df3b384db717e0b1c upstream. Bamboo One's with ID of 0x6a and 0x6b were added with correct indication of 1024 pressure levels but the Graphire packet routine was only looking at 9 bits. Increased to 10 bits. This bug caused these devices to roll over to zero pressure at half way mark. The other devices using this routine only support 256 or 512 range and look to fix unused bits at zero. Signed-off-by: Chris Bagwell Reported-by: Tushant Mirchandani Reviewed-by: Ping Cheng Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/tablet/wacom_wac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index cecd35c8f0b..c77032c943e 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -243,7 +243,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); if (wacom->tool[0] != BTN_TOOL_MOUSE) { - input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8)); + input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x03) << 8)); input_report_key(input, BTN_TOUCH, data[1] & 0x01); input_report_key(input, BTN_STYLUS, data[1] & 0x02); input_report_key(input, BTN_STYLUS2, data[1] & 0x04); From 8f3ce224466a1cf867c13cb01c3fac799aeab074 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 3 Aug 2012 12:49:14 +0200 Subject: [PATCH 0700/2357] rt61pci: fix NULL pointer dereference in config_lna_gain commit deee0214def5d8a32b8112f11d9c2b1696e9c0cb upstream. We can not pass NULL libconf->conf->channel to rt61pci_config() as it is dereferenced unconditionally in rt61pci_config_lna_gain() subroutine. Resolves: https://bugzilla.kernel.org/show_bug.cgi?id=44361 Reported-and-tested-by: Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt61pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index e0c6d117429..0f4bf8c23bf 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2243,8 +2243,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev) { - struct ieee80211_conf conf = { .flags = 0 }; - struct rt2x00lib_conf libconf = { .conf = &conf }; + struct rt2x00lib_conf libconf = { .conf = &rt2x00dev->hw->conf }; rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } From 196ad09b956e63131e3d196e490a4dfbb85e875f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 15 Aug 2012 08:17:17 -0700 Subject: [PATCH 0701/2357] Linux 3.4.9 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a3c0c43a71d..9549547614b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 8 +SUBLEVEL = 9 EXTRAVERSION = NAME = Saber-toothed Squirrel From bdac2ea27e0237b3c76b1d8a9d7f73a3d6b3ad81 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 7 Aug 2012 09:48:13 +0200 Subject: [PATCH 0702/2357] s390/compat: fix compat wrappers for process_vm system calls commit 82aabdb6f1eb61e0034ec23901480f5dd23db7c4 upstream. The compat wrappers incorrectly called the non compat versions of the system process_vm system calls. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/compat_wrapper.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index ff605a39cf4..cfe3efda69d 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1636,7 +1636,7 @@ ENTRY(compat_sys_process_vm_readv_wrapper) llgfr %r6,%r6 # unsigned long llgf %r0,164(%r15) # unsigned long stg %r0,160(%r15) - jg sys_process_vm_readv + jg compat_sys_process_vm_readv ENTRY(compat_sys_process_vm_writev_wrapper) lgfr %r2,%r2 # compat_pid_t @@ -1646,4 +1646,4 @@ ENTRY(compat_sys_process_vm_writev_wrapper) llgfr %r6,%r6 # unsigned long llgf %r0,164(%r15) # unsigned long stg %r0,160(%r15) - jg sys_process_vm_writev + jg compat_sys_process_vm_writev From a87531935d7afc5429944c89511c8acbdf467111 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 8 Aug 2012 09:32:20 +0200 Subject: [PATCH 0703/2357] s390/compat: fix mmap compat system calls commit e85871218513c54f7dfdb6009043cb638f2fecbe upstream. The native 31 bit and the compat behaviour for the mmap system calls differ: In native 31 bit mode the passed in address for the mmap system call will be unmodified passed to sys_mmap_pgoff(). In compat mode however the passed in address will be modified with compat_ptr() which masks out the most significant bit. The result is that in native 31 bit mode each mmap request (with MAP_FIXED) will fail where the most significat bit is set, while in compat mode it may succeed. This odd behaviour was introduced with d3815898 "[S390] mmap: add missing compat_ptr conversion to both mmap compat syscalls". To restore a consistent behaviour accross native and compat mode this patch functionally reverts the above mentioned commit. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/compat_linux.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index ab64bdbab2a..36e6c3092e6 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -612,7 +612,6 @@ asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg) return -EFAULT; if (a.offset & ~PAGE_MASK) return -EINVAL; - a.addr = (unsigned long) compat_ptr(a.addr); return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); } @@ -623,7 +622,6 @@ asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg) if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; - a.addr = (unsigned long) compat_ptr(a.addr); return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); } From 9ea2c02bafe276e97b592a046ac733610a6d57fd Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 3 Jul 2012 15:33:29 -0300 Subject: [PATCH 0704/2357] dma: imx-dma: Fix kernel crash due to missing clock conversion commit a2367db2ec5e7fc6fe93e221e0fcdee81b053daf upstream. With the new i.MX clock infrastructure we need to request the dma clocks seperately: ahb and ipg clocks. This fixes the following kernel crash and make audio to be functional again: root@freescale /home$ aplay audio48k16S.wav Playing WAVE 'audio48k16S.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = c7b74000 [00000000] *pgd=a7bb5831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT ARM Modules linked in: CPU: 0 Not tainted (3.5.0-rc5-next-20120702-00007-g3028b64 #1128) PC is at snd_dmaengine_pcm_get_chan+0x8/0x10 LR is at snd_imx_pcm_hw_params+0x18/0xdc pc : [] lr : [] psr: a0000013 sp : c7b45e30 ip : ffffffff fp : c7ae58e0 r10: 00000000 r9 : c7ae981c r8 : c7b88800 r7 : c7ae5a60 r6 : c7ae5b20 r5 : c7ae9810 r4 : c7afa060 r3 : 00000000 r2 : 00000001 r1 : c7b88800 r0 : c7afa060 Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 0005317f Table: a7b74000 DAC: 00000015 Process aplay (pid: 701, stack limit = 0xc7b44270) Stack: (0xc7b45e30 to 0xc7b46000) 5e20: 00100000 00000029 c7b88800 c02db870 5e40: c7ae5a60 c02d4594 00000010 01ae5a60 c7ae5a60 c7ae9810 c7ae9810 c7afa060 5e60: c7ae5b20 c7ae5a60 c7b88800 c02e3ef0 c02e3e08 c7b1e400 c7afa060 c7b88800 5e80: 00000000 c0014da8 c7b44000 00000000 bec566ac c02cd400 c7afa060 c7afa060 5ea0: bec56800 c7b88800 c0014da8 c02cdd7c c04ee710 c04ee7b8 00000003 c005fc74 5ec0: 00000000 7fffffff c7b45f00 c7afa060 c7b67420 c7ba3070 00000004 c0014da8 5ee0: c7b44000 00000000 bec566ac c02ced88 c04e95f8 b6f5ab04 c7b45fb0 0145a468 5f00: 0145a600 bec566bc bec56800 c7b67420 c7ba3070 c00d499c c7b45f18 c7b45f18 5f20: 0000001a 00000004 00000001 c7b44000 c0527f40 00000009 00000008 00000000 5f40: c7b44000 c002c9ec 00000001 c04f0ab0 c04ebec0 00000101 00000000 0000000a 5f60: 60000093 c7b67420 bec56800 c25c4111 00000004 c0014da8 c7b44000 00000000 5f80: bec566ac c00d4f38 b6ffb658 00000000 c0522d80 0145a468 b6fd5000 0145a418 5fa0: 00000036 c0014c00 0145a468 b6fd5000 00000004 c25c4111 bec56800 00020001 5fc0: 0145a468 b6fd5000 0145a418 00000036 0145a468 0145a600 bec566bc bec566ac 5fe0: 0145a468 bec56388 b6f65ce4 b6dcebec 20000010 00000004 00000000 00000000 [] (snd_dmaengine_pcm_get_chan+0x8/0x10) from [] (snd_imx_pcm_hw_params+0x18/0xdc) [] (snd_imx_pcm_hw_params+0x18/0xdc) from [] (soc_pcm_hw_params+0xe8/0x1f0) [] (soc_pcm_hw_params+0xe8/0x1f0) from [] (snd_pcm_hw_params+0x124/0x474) [] (snd_pcm_hw_params+0x124/0x474) from [] (snd_pcm_common_ioctl1+0x4b4/0xf74) [] (snd_pcm_common_ioctl1+0x4b4/0xf74) from [] (snd_pcm_playback_ioctl1+0x30/0x510) [] (snd_pcm_playback_ioctl1+0x30/0x510) from [] (do_vfs_ioctl+0x80/0x5e4) [] (do_vfs_ioctl+0x80/0x5e4) from [] (sys_ioctl+0x38/0x60) [] (sys_ioctl+0x38/0x60) from [] (ret_fast_syscall+0x0/0x2c) Code: e593000c e12fff1e e59030a0 e59330bc (e5930000) ---[ end trace fa518c8ba3a74e97 ]-- Reported-by: Javier Martin Signed-off-by: Fabio Estevam Acked-by: Sascha Hauer Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/imx-dma.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index bb787d8e152..2ca8d3f779f 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -172,7 +172,8 @@ struct imxdma_engine { struct device_dma_parameters dma_parms; struct dma_device dma_device; void __iomem *base; - struct clk *dma_clk; + struct clk *dma_ahb; + struct clk *dma_ipg; spinlock_t lock; struct imx_dma_2d_config slots_2d[IMX_DMA_2D_SLOTS]; struct imxdma_channel channel[IMX_DMA_CHANNELS]; @@ -976,10 +977,20 @@ static int __init imxdma_probe(struct platform_device *pdev) return 0; } - imxdma->dma_clk = clk_get(NULL, "dma"); - if (IS_ERR(imxdma->dma_clk)) - return PTR_ERR(imxdma->dma_clk); - clk_enable(imxdma->dma_clk); + imxdma->dma_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(imxdma->dma_ipg)) { + ret = PTR_ERR(imxdma->dma_ipg); + goto err_clk; + } + + imxdma->dma_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(imxdma->dma_ahb)) { + ret = PTR_ERR(imxdma->dma_ahb); + goto err_clk; + } + + clk_prepare_enable(imxdma->dma_ipg); + clk_prepare_enable(imxdma->dma_ahb); /* reset DMA module */ imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR); @@ -988,16 +999,14 @@ static int __init imxdma_probe(struct platform_device *pdev) ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ for DMA\n"); - kfree(imxdma); - return ret; + goto err_enable; } ret = request_irq(MX1_DMA_ERR, imxdma_err_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n"); free_irq(MX1_DMA_INT, NULL); - kfree(imxdma); - return ret; + goto err_enable; } } @@ -1094,7 +1103,10 @@ static int __init imxdma_probe(struct platform_device *pdev) free_irq(MX1_DMA_INT, NULL); free_irq(MX1_DMA_ERR, NULL); } - +err_enable: + clk_disable_unprepare(imxdma->dma_ipg); + clk_disable_unprepare(imxdma->dma_ahb); +err_clk: kfree(imxdma); return ret; } @@ -1114,7 +1126,9 @@ static int __exit imxdma_remove(struct platform_device *pdev) free_irq(MX1_DMA_ERR, NULL); } - kfree(imxdma); + clk_disable_unprepare(imxdma->dma_ipg); + clk_disable_unprepare(imxdma->dma_ahb); + kfree(imxdma); return 0; } From 90f9cb724d38bf4ac4e355d19b1ee697dceea021 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 24 Jul 2012 12:10:11 -0700 Subject: [PATCH 0705/2357] fuse: verify all ioctl retry iov elements commit fb6ccff667712c46b4501b920ea73a326e49626a upstream. Commit 7572777eef78ebdee1ecb7c258c0ef94d35bad16 attempted to verify that the total iovec from the client doesn't overflow iov_length() but it only checked the first element. The iovec could still overflow by starting with a small element. The obvious fix is to check all the elements. The overflow case doesn't look dangerous to the kernel as the copy is limited by the length after the overflow. This fix restores the intention of returning an error instead of successfully copying less than the iovec represented. I found this by code inspection. I built it but don't have a test case. I'm cc:ing stable because the initial commit did as well. Signed-off-by: Zach Brown Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 504e61b7fd7..8e6381a1426 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1698,7 +1698,7 @@ static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count) size_t n; u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT; - for (n = 0; n < count; n++) { + for (n = 0; n < count; n++, iov++) { if (iov->iov_len > (size_t) max) return -ENOMEM; max -= iov->iov_len; From b9247be526627cda981a6901c8db66f03ecb3ea8 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Wed, 23 May 2012 18:57:20 +0100 Subject: [PATCH 0706/2357] xen: mark local pages as FOREIGN in the m2p_override commit b9e0d95c041ca2d7ad297ee37c2e9cfab67a188f upstream. When the frontend and the backend reside on the same domain, even if we add pages to the m2p_override, these pages will never be returned by mfn_to_pfn because the check "get_phys_to_machine(pfn) != mfn" will always fail, so the pfn of the frontend will be returned instead (resulting in a deadlock because the frontend pages are already locked). INFO: task qemu-system-i38:1085 blocked for more than 120 seconds. "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. qemu-system-i38 D ffff8800cfc137c0 0 1085 1 0x00000000 ffff8800c47ed898 0000000000000282 ffff8800be4596b0 00000000000137c0 ffff8800c47edfd8 ffff8800c47ec010 00000000000137c0 00000000000137c0 ffff8800c47edfd8 00000000000137c0 ffffffff82213020 ffff8800be4596b0 Call Trace: [] ? __lock_page+0x70/0x70 [] schedule+0x29/0x70 [] io_schedule+0x60/0x80 [] sleep_on_page+0xe/0x20 [] __wait_on_bit_lock+0x5a/0xc0 [] __lock_page+0x67/0x70 [] ? autoremove_wake_function+0x40/0x40 [] ? bio_add_page+0x36/0x40 [] set_page_dirty_lock+0x52/0x60 [] bio_set_pages_dirty+0x51/0x70 [] do_blockdev_direct_IO+0xb24/0xeb0 [] ? ext3_get_blocks_handle+0xe00/0xe00 [] __blockdev_direct_IO+0x55/0x60 [] ? ext3_get_blocks_handle+0xe00/0xe00 [] ext3_direct_IO+0xf8/0x390 [] ? ext3_get_blocks_handle+0xe00/0xe00 [] ? xen_mc_flush+0xb0/0x1b0 [] generic_file_aio_read+0x737/0x780 [] ? gnttab_map_refs+0x15b/0x1e0 [] ? find_get_pages+0x150/0x150 [] aio_rw_vect_retry+0x7c/0x1d0 [] ? lookup_ioctx+0x90/0x90 [] aio_run_iocb+0x66/0x1a0 [] do_io_submit+0x708/0xb90 [] sys_io_submit+0x10/0x20 [] system_call_fastpath+0x16/0x1b The explanation is in the comment within the code: We need to do this because the pages shared by the frontend (xen-blkfront) can be already locked (lock_page, called by do_read_cache_page); when the userspace backend tries to use them with direct_IO, mfn_to_pfn returns the pfn of the frontend, so do_blockdev_direct_IO is going to try to lock the same pages again resulting in a deadlock. A simplified call graph looks like this: pygrub QEMU ----------------------------------------------- do_read_cache_page io_submit | | lock_page ext3_direct_IO | bio_add_page | lock_page Internally the xen-blkback uses m2p_add_override to swizzle (temporarily) a 'struct page' to have a different MFN (so that it can point to another guest). It also can easily find out whether another pfn corresponding to the mfn exists in the m2p, and can set the FOREIGN bit in the p2m, making sure that mfn_to_pfn returns the pfn of the backend. This allows the backend to perform direct_IO on these pages, but as a side effect prevents the frontend from using get_user_pages_fast on them while they are being shared with the backend. Signed-off-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/p2m.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 1b267e75158..00a038540c8 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -686,6 +686,7 @@ int m2p_add_override(unsigned long mfn, struct page *page, unsigned long uninitialized_var(address); unsigned level; pte_t *ptep = NULL; + int ret = 0; pfn = page_to_pfn(page); if (!PageHighMem(page)) { @@ -721,6 +722,24 @@ int m2p_add_override(unsigned long mfn, struct page *page, list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); spin_unlock_irqrestore(&m2p_override_lock, flags); + /* p2m(m2p(mfn)) == mfn: the mfn is already present somewhere in + * this domain. Set the FOREIGN_FRAME_BIT in the p2m for the other + * pfn so that the following mfn_to_pfn(mfn) calls will return the + * pfn from the m2p_override (the backend pfn) instead. + * We need to do this because the pages shared by the frontend + * (xen-blkfront) can be already locked (lock_page, called by + * do_read_cache_page); when the userspace backend tries to use them + * with direct_IO, mfn_to_pfn returns the pfn of the frontend, so + * do_blockdev_direct_IO is going to try to lock the same pages + * again resulting in a deadlock. + * As a side effect get_user_pages_fast might not be safe on the + * frontend pages while they are being shared with the backend, + * because mfn_to_pfn (that ends up being called by GUPF) will + * return the backend pfn rather than the frontend pfn. */ + ret = __get_user(pfn, &machine_to_phys_mapping[mfn]); + if (ret == 0 && get_phys_to_machine(pfn) == mfn) + set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)); + return 0; } EXPORT_SYMBOL_GPL(m2p_add_override); @@ -732,6 +751,7 @@ int m2p_remove_override(struct page *page, bool clear_pte) unsigned long uninitialized_var(address); unsigned level; pte_t *ptep = NULL; + int ret = 0; pfn = page_to_pfn(page); mfn = get_phys_to_machine(pfn); @@ -801,6 +821,22 @@ int m2p_remove_override(struct page *page, bool clear_pte) } else set_phys_to_machine(pfn, page->index); + /* p2m(m2p(mfn)) == FOREIGN_FRAME(mfn): the mfn is already present + * somewhere in this domain, even before being added to the + * m2p_override (see comment above in m2p_add_override). + * If there are no other entries in the m2p_override corresponding + * to this mfn, then remove the FOREIGN_FRAME_BIT from the p2m for + * the original pfn (the one shared by the frontend): the backend + * cannot do any IO on this page anymore because it has been + * unshared. Removing the FOREIGN_FRAME_BIT from the p2m entry of + * the original pfn causes mfn_to_pfn(mfn) to return the frontend + * pfn again. */ + mfn &= ~FOREIGN_FRAME_BIT; + ret = __get_user(pfn, &machine_to_phys_mapping[mfn]); + if (ret == 0 && get_phys_to_machine(pfn) == FOREIGN_FRAME(mfn) && + m2p_find_override(mfn) == NULL) + set_phys_to_machine(pfn, mfn); + return 0; } EXPORT_SYMBOL_GPL(m2p_remove_override); From 6700eb4d0af877ed46ae2e5d93d6801db7f3b58d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 21 Jun 2012 15:13:50 -0700 Subject: [PATCH 0707/2357] drm/i915: prefer wide & slow to fast & narrow in DP configs commit 2514bc510d0c3aadcc5204056bb440fa36845147 upstream. High frequency link configurations have the potential to cause trouble with long and/or cheap cables, so prefer slow and wide configurations instead. This patch has the potential to cause trouble for eDP configurations that lie about available lanes, so if we run into that we can make it conditional on eDP. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=45801 Tested-by: peter@colberg.org Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter Cc: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 68624218d05..4eedd16bc3d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -712,8 +712,8 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; - for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { - for (clock = 0; clock <= max_clock; clock++) { + for (clock = 0; clock <= max_clock; clock++) { + for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); if (intel_dp_link_required(mode->clock, bpp) From 1a475b7af63febbef784d0d2ccb6bdbb119d0245 Mon Sep 17 00:00:00 2001 From: Christoph Bumiller Date: Thu, 26 Jul 2012 20:53:19 +0200 Subject: [PATCH 0708/2357] drm/nvd0/disp: mask off high 16 bit of negative cursor x-coordinate commit af5e7d84b0ec45b2b614b0d6e3657cbdceaa21f9 upstream. Signed-off-by: Christoph Bumiller Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nvd0_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index 0247250939e..8a555fb6702 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -790,7 +790,7 @@ nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); int ch = EVO_CURS(nv_crtc->index); - evo_piow(crtc->dev, ch, 0x0084, (y << 16) | x); + evo_piow(crtc->dev, ch, 0x0084, (y << 16) | (x & 0xffff)); evo_piow(crtc->dev, ch, 0x0080, 0x00000000); return 0; } From 57ecc93ce680b1ace1f9e79d588dabe32353202c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Aug 2012 09:54:14 +0200 Subject: [PATCH 0709/2357] drm/i915: correctly order the ring init sequence commit 0d8957c8a90bbb5d34fab9a304459448a5131e06 upstream. We may only start to set up the new register values after having confirmed that the ring is truely off. Otherwise the hw might lose the newly written register values. This is caught later on in the init sequence, when we check whether the register writes have stuck. Reviewed-by: Jani Nikula Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=50522 Tested-by: Yang Guang Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 302d3d54fb4..12a9e5fd925 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -258,8 +258,6 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_WRITE_HEAD(ring, 0); ring->write_tail(ring, 0); - /* Initialize the ring. */ - I915_WRITE_START(ring, obj->gtt_offset); head = I915_READ_HEAD(ring) & HEAD_ADDR; /* G45 ring initialization fails to reset head to zero */ @@ -285,6 +283,11 @@ static int init_ring_common(struct intel_ring_buffer *ring) } } + /* Initialize the ring. This must happen _after_ we've cleared the ring + * registers with the above sequence (the readback of the HEAD registers + * also enforces ordering), otherwise the hw might lose the new ring + * register values. */ + I915_WRITE_START(ring, obj->gtt_offset); I915_WRITE_CTL(ring, ((ring->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID); From c02a29650148f353b0fc86b7eba3f99ecafd23dd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 10 Aug 2012 11:10:20 +0200 Subject: [PATCH 0710/2357] drm/i915: ignore eDP bpc settings from vbt commit 4344b813f105a19f793f1fd93ad775b784648b95 upstream. This has originally been introduced to not oversubscribe the dp links in commit 885a5fb5b120a5c7e0b3baad7b0feb5a89f76c18 Author: Zhenyu Wang Date: Tue Jan 12 05:38:31 2010 +0800 drm/i915: fix pixel color depth setting on eDP Since then we've fixed up the dp link bandwidth calculation code and should now automatically fall back to 6bpc dithering. So this is unnecessary. Furthermore it seems to break the new MacbookPro with retina display, hence let's just rip this out. Reported-by: Benoit Gschwind Cc: Benoit Gschwind Cc: Francois Rigaut Tested-by: Benoit Gschwind Tested-by: Bernhard Froemel Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman -- Testing feedback highgly welcome, and thanks for Benoit for finding out that the bpc computations are busted. -Daniel --- drivers/gpu/drm/i915/intel_display.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d4d162f6bab..3de3d9b670b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4982,17 +4982,6 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, continue; } - if (intel_encoder->type == INTEL_OUTPUT_EDP) { - /* Use VBT settings if we have an eDP panel */ - unsigned int edp_bpc = dev_priv->edp.bpp / 3; - - if (edp_bpc < display_bpc) { - DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc); - display_bpc = edp_bpc; - } - continue; - } - /* Not one of the known troublemakers, check the EDID */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { From acafb0231aeeb8648e1f2789e6dd88ea5878f61c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Aug 2012 22:17:14 +0200 Subject: [PATCH 0711/2357] drm/i915: reorder edp disabling to fix ivb MacBook Air commit 35a38556d900b9cb5dfa2529c93944b847f8a8a4 upstream. eDP is tons of fun. It turns out that at least the new MacBook Air 5,1 model absolutely doesn't like the new force vdd dance we've introduced in commit 6cb49835da0426f69a2931bc2a0a8156344b0e41 Author: Daniel Vetter Date: Sun May 20 17:14:50 2012 +0200 drm/i915: enable vdd when switching off the eDP panel But that patch also tried to fix some neat edp sequence issue with the force_vdd timings. Closer inspection reveals that we've raised force_vdd only to do the aux channel communication dp_sink_dpms. If we move the edp_panel_off below that, we don't need any force_vdd for the disable sequence, which makes the Air happy. Unfortunately the reporter of the original bug that the above commit fixed is travelling, so we can't test whether this regresses things. But my theory is that since we don't check for any power-off -> force_vdd-on delays in edp_panel_vdd_on, this was the actual root-cause of this failure. With that force_vdd dance completely eliminated, I'm hopeful the original bug stays fixed, too. For reference the old bug, which hopefully doesn't get broken by this: https://bugzilla.kernel.org/show_bug.cgi?id=43163 In any case, regression fixers win over plain bugfixes, so this needs to go in asap. v2: The crucial pieces seems to be to clear the force_vdd flag uncoditionally, too, in edp_panel_off. Looks like this is left behind by the firmware somehow. v3: The Apple firmware seems to switch off the panel on it's own, hence we still need to keep force_vdd on, but properly clear it when switching the panel off. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=45671 Tested-by: Roberto Romer Tested-by: Daniel Wagner Tested-by: Keith Packard Cc: Keith Packard Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_dp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4eedd16bc3d..069725c5c1a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1156,10 +1156,14 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); pp = ironlake_get_pp_control(dev_priv); - pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); + /* We need to switch off panel power _and_ force vdd, for otherwise some + * panels get very unhappy and cease to work. */ + pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); + intel_dp->want_panel_vdd = false; + ironlake_wait_panel_off(intel_dp); } @@ -1269,11 +1273,9 @@ static void intel_dp_prepare(struct drm_encoder *encoder) * ensure that we have vdd while we switch off the panel. */ ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_backlight_off(intel_dp); - ironlake_edp_panel_off(intel_dp); - intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + ironlake_edp_panel_off(intel_dp); intel_dp_link_down(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp, false); } static void intel_dp_commit(struct drm_encoder *encoder) @@ -1308,11 +1310,9 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) /* Switching the panel off requires vdd. */ ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_backlight_off(intel_dp); - ironlake_edp_panel_off(intel_dp); - intel_dp_sink_dpms(intel_dp, mode); + ironlake_edp_panel_off(intel_dp); intel_dp_link_down(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp, false); if (is_cpu_edp(intel_dp)) ironlake_edp_pll_off(encoder); From b248464f145eee69818dff9945096745988aa3ce Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 26 Jul 2012 13:38:52 -0400 Subject: [PATCH 0712/2357] drm/radeon: properly handle crtc powergating commit 6c0ae2ab85fc4a95cae82047a7db1f688a7737ab upstream. Need to make sure the crtc is gated on before modesetting. Explicitly gate the crtc on in prepare() and set a flag so that the dpms functions don't gate it off during mode set. Noticed by sylware on IRC. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_crtc.c | 14 ++++++++++++-- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 4 ++++ drivers/gpu/drm/radeon/radeon_mode.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index af1054f8202..a53ca30d05e 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -259,7 +259,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) /* adjust pm to dpms changes BEFORE enabling crtcs */ radeon_pm_compute_clocks(rdev); /* disable crtc pair power gating before programming */ - if (ASIC_IS_DCE6(rdev)) + if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) atombios_powergate_crtc(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) @@ -279,7 +279,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_enable_crtc(crtc, ATOM_DISABLE); radeon_crtc->enabled = false; /* power gating is per-pair */ - if (ASIC_IS_DCE6(rdev)) { + if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) { struct drm_crtc *other_crtc; struct radeon_crtc *other_radeon_crtc; list_for_each_entry(other_crtc, &rdev->ddev->mode_config.crtc_list, head) { @@ -1634,18 +1634,28 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, static void atombios_crtc_prepare(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + radeon_crtc->in_mode_set = true; /* pick pll */ radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); + /* disable crtc pair power gating before programming */ + if (ASIC_IS_DCE6(rdev)) + atombios_powergate_crtc(crtc, ATOM_DISABLE); + atombios_lock_crtc(crtc, ATOM_ENABLE); atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); } static void atombios_crtc_commit(struct drm_crtc *crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); atombios_lock_crtc(crtc, ATOM_DISABLE); + radeon_crtc->in_mode_set = false; } static void atombios_crtc_disable(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 210317c7045..9760e5addcc 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -1025,9 +1025,11 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc, static void radeon_crtc_prepare(struct drm_crtc *crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_crtc *crtci; + radeon_crtc->in_mode_set = true; /* * The hardware wedges sometimes if you reconfigure one CRTC * whilst another is running (see fdo bug #24611). @@ -1038,6 +1040,7 @@ static void radeon_crtc_prepare(struct drm_crtc *crtc) static void radeon_crtc_commit(struct drm_crtc *crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_crtc *crtci; @@ -1048,6 +1051,7 @@ static void radeon_crtc_commit(struct drm_crtc *crtc) if (crtci->enabled) radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON); } + radeon_crtc->in_mode_set = false; } static const struct drm_crtc_helper_funcs legacy_helper_funcs = { diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index f7eb5d8b9fd..778c1f0d7b8 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -266,6 +266,7 @@ struct radeon_crtc { u16 lut_r[256], lut_g[256], lut_b[256]; bool enabled; bool can_tile; + bool in_mode_set; uint32_t crtc_offset; struct drm_gem_object *cursor_bo; uint64_t cursor_addr; From 3407b51859d0e65ed66ccb0080c495a1f03cda6a Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 27 Jul 2012 16:32:24 -0400 Subject: [PATCH 0713/2357] drm/radeon: do not reenable crtc after moving vram start address commit 81ee8fb6b52ec69eeed37fe7943446af1dccecc5 upstream. It seems we can not update the crtc scanout address. After disabling crtc, update to base address do not take effect after crtc being reenable leading to at least frame being scanout from the old crtc base address. Disabling crtc display request lead to same behavior. So after changing the vram address if we don't keep crtc disabled we will have the GPU trying to read some random system memory address with some iommu this will broke the crtc engine and will lead to broken display and iommu error message. So to avoid this, disable crtc. For flicker less boot we will need to avoid moving the vram start address. This patch should also fix : https://bugs.freedesktop.org/show_bug.cgi?id=42373 Signed-off-by: Jerome Glisse Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 57 ---------------------------- drivers/gpu/drm/radeon/radeon_asic.h | 8 +--- drivers/gpu/drm/radeon/rv515.c | 13 ------- 3 files changed, 2 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e72c03ff595..ba554bf9c8f 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1117,24 +1117,8 @@ void evergreen_agp_enable(struct radeon_device *rdev) void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save) { - save->vga_control[0] = RREG32(D1VGA_CONTROL); - save->vga_control[1] = RREG32(D2VGA_CONTROL); save->vga_render_control = RREG32(VGA_RENDER_CONTROL); save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); - save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET); - save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); - if (rdev->num_crtc >= 4) { - save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL); - save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL); - save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET); - save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); - } - if (rdev->num_crtc >= 6) { - save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL); - save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL); - save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET); - save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); - } /* Stop all video */ WREG32(VGA_RENDER_CONTROL, 0); @@ -1245,47 +1229,6 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s /* Unlock host access */ WREG32(VGA_HDP_CONTROL, save->vga_hdp_control); mdelay(1); - /* Restore video state */ - WREG32(D1VGA_CONTROL, save->vga_control[0]); - WREG32(D2VGA_CONTROL, save->vga_control[1]); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]); - WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]); - WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]); - } - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); - } - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]); - } - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); - } WREG32(VGA_RENDER_CONTROL, save->vga_render_control); } diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 3d9f9f1d8f9..665df8730c8 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -262,13 +262,10 @@ extern int rs690_mc_wait_for_idle(struct radeon_device *rdev); * rv515 */ struct rv515_mc_save { - u32 d1vga_control; - u32 d2vga_control; u32 vga_render_control; u32 vga_hdp_control; - u32 d1crtc_control; - u32 d2crtc_control; }; + int rv515_init(struct radeon_device *rdev); void rv515_fini(struct radeon_device *rdev); uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg); @@ -401,11 +398,10 @@ void r700_cp_fini(struct radeon_device *rdev); * evergreen */ struct evergreen_mc_save { - u32 vga_control[6]; u32 vga_render_control; u32 vga_hdp_control; - u32 crtc_control[6]; }; + void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev); int evergreen_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index d8d78fe1794..43af363ead3 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -281,12 +281,8 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev) void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) { - save->d1vga_control = RREG32(R_000330_D1VGA_CONTROL); - save->d2vga_control = RREG32(R_000338_D2VGA_CONTROL); save->vga_render_control = RREG32(R_000300_VGA_RENDER_CONTROL); save->vga_hdp_control = RREG32(R_000328_VGA_HDP_CONTROL); - save->d1crtc_control = RREG32(R_006080_D1CRTC_CONTROL); - save->d2crtc_control = RREG32(R_006880_D2CRTC_CONTROL); /* Stop all video */ WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0); @@ -311,15 +307,6 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) /* Unlock host access */ WREG32(R_000328_VGA_HDP_CONTROL, save->vga_hdp_control); mdelay(1); - /* Restore video state */ - WREG32(R_000330_D1VGA_CONTROL, save->d1vga_control); - WREG32(R_000338_D2VGA_CONTROL, save->d2vga_control); - WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 1); - WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 1); - WREG32(R_006080_D1CRTC_CONTROL, save->d1crtc_control); - WREG32(R_006880_D2CRTC_CONTROL, save->d2crtc_control); - WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 0); - WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0); WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control); } From 844bebfd9d09f92cdf4fac108e5f0d38cd389fff Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 6 Aug 2012 10:03:59 -0400 Subject: [PATCH 0714/2357] drm/radeon: add some new SI pci ids commit 2f292004dd1fb005788dc0a9cdd5559812ed866e upstream. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_pciids.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 81368ab6c61..53392e8f956 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -217,9 +217,12 @@ {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6816, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6817, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6818, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ From e3d7a0f49568353837c51d0dbcd86cca8b7bc622 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 31 Jul 2012 11:05:11 -0400 Subject: [PATCH 0715/2357] drm/radeon: fix bank tiling parameters on cayman commit 5b23c9045a8b61352986270b2d109edf5085e113 upstream. Handle the 16 bank case. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/ni.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index ad0a38007de..9934c9d9e51 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -880,10 +880,18 @@ static void cayman_gpu_init(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_IGP) rdev->config.cayman.tile_config |= 1 << 4; else { - if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) - rdev->config.cayman.tile_config |= 1 << 4; - else + switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) { + case 0: /* four banks */ rdev->config.cayman.tile_config |= 0 << 4; + break; + case 1: /* eight banks */ + rdev->config.cayman.tile_config |= 1 << 4; + break; + case 2: /* sixteen banks */ + default: + rdev->config.cayman.tile_config |= 2 << 4; + break; + } } rdev->config.cayman.tile_config |= ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8; From 75a757189880a31759ed25c23229f085890cddb1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 31 Jul 2012 11:01:10 -0400 Subject: [PATCH 0716/2357] drm/radeon: fix bank tiling parameters on evergreen commit c8d15edc17d836686d1f071e564800e1a2724fa6 upstream. Handle the 16 bank case. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index ba554bf9c8f..e5328da70f8 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2085,10 +2085,18 @@ static void evergreen_gpu_init(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_IGP) rdev->config.evergreen.tile_config |= 1 << 4; else { - if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) - rdev->config.evergreen.tile_config |= 1 << 4; - else + switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) { + case 0: /* four banks */ rdev->config.evergreen.tile_config |= 0 << 4; + break; + case 1: /* eight banks */ + rdev->config.evergreen.tile_config |= 1 << 4; + break; + case 2: /* sixteen banks */ + default: + rdev->config.evergreen.tile_config |= 2 << 4; + break; + } } rdev->config.evergreen.tile_config |= ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8; From 8b9f3861678e35b18cef66728d0fa896bbda65b6 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 5 Aug 2012 19:04:57 -0400 Subject: [PATCH 0717/2357] ext4: make sure the journal sb is written in ext4_clear_journal_err() commit d796c52ef0b71a988364f6109aeb63d79c5b116b upstream. After we transfer set the EXT4_ERROR_FS bit in the file system superblock, it's not enough to call jbd2_journal_clear_err() to clear the error indication from journal superblock --- we need to call jbd2_journal_update_sb_errno() as well. Otherwise, when the root file system is mounted read-only, the journal is replayed, and the error indicator is transferred to the superblock --- but the s_errno field in the jbd2 superblock is left set (since although we cleared it in memory, we never flushed it out to disk). This can end up confusing e2fsck. We should make e2fsck more robust in this case, but the kernel shouldn't be leaving things in this confused state, either. Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 1 + fs/jbd2/journal.c | 3 ++- include/linux/jbd2.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 7fe3869d33d..78fb7ff3adb 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4227,6 +4227,7 @@ static void ext4_clear_journal_err(struct super_block *sb, ext4_commit_super(sb, 1); jbd2_journal_clear_err(journal); + jbd2_journal_update_sb_errno(journal); } } diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 1afb701622b..9956ac68b72 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1340,7 +1340,7 @@ static void jbd2_mark_journal_empty(journal_t *journal) * Update a journal's errno. Write updated superblock to disk waiting for IO * to complete. */ -static void jbd2_journal_update_sb_errno(journal_t *journal) +void jbd2_journal_update_sb_errno(journal_t *journal) { journal_superblock_t *sb = journal->j_superblock; @@ -1352,6 +1352,7 @@ static void jbd2_journal_update_sb_errno(journal_t *journal) jbd2_write_superblock(journal, WRITE_SYNC); } +EXPORT_SYMBOL(jbd2_journal_update_sb_errno); /* * Read the superblock for a given journal, performing initial diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 912c30a8ddb..2ed66ef2e68 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -1091,6 +1091,7 @@ extern int jbd2_journal_destroy (journal_t *); extern int jbd2_journal_recover (journal_t *journal); extern int jbd2_journal_wipe (journal_t *, int); extern int jbd2_journal_skip_recovery (journal_t *); +extern void jbd2_journal_update_sb_errno(journal_t *); extern void jbd2_journal_update_sb_log_tail (journal_t *, tid_t, unsigned long, int); extern void __jbd2_journal_abort_hard (journal_t *); From 9a321bec4fb122cb2bd60febfd9dc71eed7ee5b2 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 5 Aug 2012 23:28:16 -0400 Subject: [PATCH 0718/2357] ext4: avoid kmemcheck complaint from reading uninitialized memory commit 7e731bc9a12339f344cddf82166b82633d99dd86 upstream. Commit 03179fe923 introduced a kmemcheck complaint in ext4_da_get_block_prep() because we save and restore ei->i_da_metadata_calc_last_lblock even though it is left uninitialized in the case where i_da_metadata_calc_len is zero. This doesn't hurt anything, but silencing the kmemcheck complaint makes it easier for people to find real bugs. Addresses https://bugzilla.kernel.org/show_bug.cgi?id=45631 (which is marked as a regression). Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 78fb7ff3adb..0eeac284126 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -932,6 +932,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) ei->i_reserved_meta_blocks = 0; ei->i_allocated_meta_blocks = 0; ei->i_da_metadata_calc_len = 0; + ei->i_da_metadata_calc_last_lblock = 0; spin_lock_init(&(ei->i_block_reservation_lock)); #ifdef CONFIG_QUOTA ei->i_reserved_quota = 0; From e1b5abaa966c9baaaf90c975c4ca377dd7ab4483 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 16 Aug 2012 11:59:04 -0400 Subject: [PATCH 0719/2357] ext4: fix long mount times on very big file systems commit 0548bbb85337e532ca2ed697c3e9b227ff2ed4b4 upstream. Commit 8aeb00ff85a: "ext4: fix overhead calculation used by ext4_statfs()" introduced a O(n**2) calculation which makes very large file systems take forever to mount. Fix this with an optimization for non-bigalloc file systems. (For bigalloc file systems the overhead needs to be set in the the superblock.) Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 0eeac284126..12a278ff82a 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2969,6 +2969,10 @@ static int count_overhead(struct super_block *sb, ext4_group_t grp, ext4_group_t i, ngroups = ext4_get_groups_count(sb); int s, j, count = 0; + if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_BIGALLOC)) + return (ext4_bg_has_super(sb, grp) + ext4_bg_num_gdb(sb, grp) + + sbi->s_itb_per_group + 2); + first_block = le32_to_cpu(sbi->s_es->s_first_data_block) + (grp * EXT4_BLOCKS_PER_GROUP(sb)); last_block = first_block + EXT4_BLOCKS_PER_GROUP(sb) - 1; From d8b868fd75825114c23bc28d63ee2b87033df609 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 17 Aug 2012 08:54:52 -0400 Subject: [PATCH 0720/2357] ext4: fix kernel BUG on large-scale rm -rf commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 89a4e48f8479f8145eca9698f39fe188c982212f upstream. Commit 968dee7722: "ext4: fix hole punch failure when depth is greater than 0" introduced a regression in v3.5.1/v3.6-rc1 which caused kernel crashes when users ran run "rm -rf" on large directory hierarchy on ext4 filesystems on RAID devices: BUG: unable to handle kernel NULL pointer dereference at 0000000000000028 Process rm (pid: 18229, threadinfo ffff8801276bc000, task ffff880123631710) Call Trace: [] ? __ext4_handle_dirty_metadata+0x83/0x110 [] ext4_ext_truncate+0x193/0x1d0 [] ? ext4_mark_inode_dirty+0x7f/0x1f0 [] ext4_truncate+0xf5/0x100 [] ext4_evict_inode+0x461/0x490 [] evict+0xa2/0x1a0 [] iput+0x103/0x1f0 [] do_unlinkat+0x154/0x1c0 [] ? sys_newfstatat+0x2a/0x40 [] sys_unlinkat+0x1b/0x50 [] system_call_fastpath+0x16/0x1b Code: 8b 4d 20 0f b7 41 02 48 8d 04 40 48 8d 04 81 49 89 45 18 0f b7 49 02 48 83 c1 01 49 89 4d 00 e9 ae f8 ff ff 0f 1f 00 49 8b 45 28 <48> 8b 40 28 49 89 45 20 e9 85 f8 ff ff 0f 1f 80 00 00 00 RIP [] ext4_ext_remove_space+0xa34/0xdf0 This could be reproduced as follows: The problem in commit 968dee7722 was that caused the variable 'i' to be left uninitialized if the truncate required more space than was available in the journal. This resulted in the function ext4_ext_truncate_extend_restart() returning -EAGAIN, which caused ext4_ext_remove_space() to restart the truncate operation after starting a new jbd2 handle. Reported-by: Maciej Żenczykowski Reported-by: Marti Raudsepp Tested-by: Fengguang Wu Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/extents.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 6b7daa45f6b..8b384cc3b75 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2596,6 +2596,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, } path[0].p_depth = depth; path[0].p_hdr = ext_inode_hdr(inode); + i = 0; if (ext4_ext_check(inode, path[0].p_hdr, depth)) { err = -EIO; From 40c293d87cc9a6e4b0b8e54cd8faabf9fa4bbb95 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 2 Jul 2012 13:36:23 -0700 Subject: [PATCH 0721/2357] xhci: Add Etron XHCI_TRUST_TX_LENGTH quirk. commit 5cb7df2b2d3afee7638b3ef23a5bcb89c6f07bd9 upstream. Gary reports that with recent kernels, he notices more xHCI driver warnings: xhci_hcd 0000:03:00.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? We think his Etron xHCI host controller may have the same buggy behavior as the Fresco Logic xHCI host. When a short transfer is received, the host will mark the transfer as successfully completed when it should be marking it with a short completion. Fix this by turning on the XHCI_TRUST_TX_LENGTH quirk when the Etron host is discovered. Note that Gary has revision 1, but if Etron fixes this bug in future revisions, the quirk will have no effect. This patch should be backported to kernels as old as 2.6.36, that contain a backported version of commit 1530bbc6272d9da1e39ef8e06190d42c13a02733 "xhci: Add new short TX quirk for Fresco Logic host." Signed-off-by: Sarah Sharp Reported-by: Gary E. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 19e89216436..fccebc05b65 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -95,6 +95,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == PCI_DEVICE_ID_ASROCK_P67) { xhci->quirks |= XHCI_RESET_ON_RESUME; xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); + xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; From ebd311e08218713c46f6894648084c84c48e220d Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 23 Jul 2012 16:06:08 -0700 Subject: [PATCH 0722/2357] xhci: Increase reset timeout for Renesas 720201 host. commit 22ceac191211cf6688b1bf6ecd93c8b6bf80ed9b upstream. The NEC/Renesas 720201 xHCI host controller does not complete its reset within 250 milliseconds. In fact, it takes about 9 seconds to reset the host controller, and 1 second for the host to be ready for doorbell rings. Extend the reset and CNR polling timeout to 10 seconds each. This patch should be backported to kernels as old as 2.6.31, that contain the commit 66d4eadd8d067269ea8fead1a50fe87c2979a80d "USB: xhci: BIOS handoff and HW initialization." Signed-off-by: Sarah Sharp Reported-by: Edwin Klein Mentink Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9248d496cb8..4cc855dda4f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -166,7 +166,7 @@ int xhci_reset(struct xhci_hcd *xhci) xhci_writel(xhci, command, &xhci->op_regs->command); ret = handshake(xhci, &xhci->op_regs->command, - CMD_RESET, 0, 250 * 1000); + CMD_RESET, 0, 10 * 1000 * 1000); if (ret) return ret; @@ -175,7 +175,8 @@ int xhci_reset(struct xhci_hcd *xhci) * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. */ - ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); + ret = handshake(xhci, &xhci->op_regs->status, + STS_CNR, 0, 10 * 1000 * 1000); for (i = 0; i < 2; ++i) { xhci->bus_state[i].port_c_suspend = 0; From 0adf7a085fae52b18202a95722fc05d644fa7a42 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 23 Jul 2012 18:59:30 +0300 Subject: [PATCH 0723/2357] xhci: Switch PPT ports to EHCI on shutdown. commit e95829f474f0db3a4d940cae1423783edd966027 upstream. The Intel desktop boards DH77EB and DH77DF have a hardware issue that can be worked around by BIOS. If the USB ports are switched to xHCI on shutdown, the xHCI host will send a spurious interrupt, which will wake the system. Some BIOS will work around this, but not all. The bug can be avoided if the USB ports are switched back to EHCI on shutdown. The Intel Windows driver switches the ports back to EHCI, so change the Linux xHCI driver to do the same. Unfortunately, we can't tell the two effected boards apart from other working motherboards, because the vendors will change the DMI strings for the DH77EB and DH77DF boards to their own custom names. One example is Compulab's mini-desktop, the Intense-PC. Instead, key off the Panther Point xHCI host PCI vendor and device ID, and switch the ports over for all PPT xHCI hosts. The only impact this will have on non-effected boards is to add a couple hundred milliseconds delay on boot when the BIOS has to switch the ports over from EHCI to xHCI. This patch should be backported to kernels as old as 3.0, that contain the commit 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support EHCI/xHCI port switching." Signed-off-by: Sarah Sharp Reported-by: Denis Turischev Tested-by: Denis Turischev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 7 +++++++ drivers/usb/host/pci-quirks.h | 1 + drivers/usb/host/xhci-pci.c | 9 +++++++++ drivers/usb/host/xhci.c | 3 +++ drivers/usb/host/xhci.h | 1 + 5 files changed, 21 insertions(+) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index df0828cb2aa..c5e9e4a76f1 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -800,6 +800,13 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) } EXPORT_SYMBOL_GPL(usb_enable_xhci_ports); +void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) +{ + pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, 0x0); + pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, 0x0); +} +EXPORT_SYMBOL_GPL(usb_disable_xhci_ports); + /** * PCI Quirks for xHCI. * diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index b1002a8ef96..ef004a5de20 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -10,6 +10,7 @@ void usb_amd_quirk_pll_disable(void); void usb_amd_quirk_pll_enable(void); bool usb_is_intel_switchable_xhci(struct pci_dev *pdev); void usb_enable_xhci_ports(struct pci_dev *xhci_pdev); +void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); #else static inline void usb_amd_quirk_pll_disable(void) {} static inline void usb_amd_quirk_pll_enable(void) {} diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index fccebc05b65..f1527404617 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -90,6 +90,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_EP_LIMIT_QUIRK; xhci->limit_active_eps = 64; xhci->quirks |= XHCI_SW_BW_CHECKING; + /* + * PPT desktop boards DH77EB and DH77DF will power back on after + * a few seconds of being shutdown. The fix for this is to + * switch the ports from xHCI to EHCI on shutdown. We can't use + * DMI information to find those particular boards (since each + * vendor will change the board name), so we have to key off all + * PPT chipsets. + */ + xhci->quirks |= XHCI_SPURIOUS_REBOOT; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 4cc855dda4f..7beed536e6b 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -659,6 +659,9 @@ void xhci_shutdown(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); + if (xhci->quirks && XHCI_SPURIOUS_REBOOT) + usb_disable_xhci_ports(to_pci_dev(hcd->self.controller)); + spin_lock_irq(&xhci->lock); xhci_halt(xhci); spin_unlock_irq(&xhci->lock); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 59434fe9d7d..19ae30f1d84 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1486,6 +1486,7 @@ struct xhci_hcd { #define XHCI_SW_BW_CHECKING (1 << 8) #define XHCI_AMD_0x96_HOST (1 << 9) #define XHCI_TRUST_TX_LENGTH (1 << 10) +#define XHCI_SPURIOUS_REBOOT (1 << 13) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ From 1aac2e73a8af6ce1cd6e938967dd17e2c8d38994 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 26 Jul 2012 12:03:59 -0700 Subject: [PATCH 0724/2357] xhci: Fix bug after deq ptr set to link TRB. commit 50d0206fcaea3e736f912fd5b00ec6233fb4ce44 upstream. This patch fixes a particularly nasty bug that was revealed by the ring expansion patches. The bug has been present since the very beginning of the xHCI driver history, and could have caused general protection faults from bad memory accesses. The first thing to note is that a Set TR Dequeue Pointer command can move the dequeue pointer to a link TRB, if the canceled or stalled transfer TD ended just before a link TRB. The function to increment the dequeue pointer, inc_deq, was written before cancellation and stall support was added. It assumed that the dequeue pointer could never point to a link TRB. It would unconditionally increment the dequeue pointer at the start of the function, check if the pointer was now on a link TRB, and move it to the top of the next segment if so. This means that if a Set TR Dequeue Point command moved the dequeue pointer to a link TRB, a subsequent call to inc_deq() would move the pointer off the segment and into la-la-land. It would then read from that memory to determine if it was a link TRB. Other functions would often call inc_deq() until the dequeue pointer matched some other pointer, which means this function would quite happily read all of system memory before wrapping around to the right pointer value. Often, there would be another endpoint segment from a different ring allocated from the same DMA pool, which would be contiguous to the segment inc_deq just stepped off of. inc_deq would eventually find the link TRB in that segment, and blindly move the dequeue pointer back to the top of the correct ring segment. The only reason the original code worked at all is because there was only one ring segment. With the ring expansion patches, the dequeue pointer would eventually wrap into place, but the dequeue segment would be out-of-sync. On the second TD after the dequeue pointer was moved to a link TRB, trb_in_td() would fail (because the dequeue pointer and dequeue segment were out-of-sync), and this message would appear: ERROR Transfer event TRB DMA ptr not part of current TD This fixes bugzilla entry 4333 (option-based modem unhappy on USB 3.0 port: "Transfer event TRB DMA ptr not part of current TD", "rejecting I/O to offline device"), https://bugzilla.kernel.org/show_bug.cgi?id=43333 and possibly other general protection fault bugs as well. This patch should be backported to kernels as old as 2.6.31. A separate patch will be created for kernels older than 3.4, since inc_deq was modified in 3.4 and this patch will not apply. Signed-off-by: Sarah Sharp Tested-by: James Ettle Tested-by: Matthew Hall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 158175bfecd..203ba315c72 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -145,29 +145,37 @@ static void next_trb(struct xhci_hcd *xhci, */ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) { - union xhci_trb *next; unsigned long long addr; ring->deq_updates++; - /* If this is not event ring, there is one more usable TRB */ + /* + * If this is not event ring, and the dequeue pointer + * is not on a link TRB, there is one more usable TRB + */ if (ring->type != TYPE_EVENT && !last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) ring->num_trbs_free++; - next = ++(ring->dequeue); - /* Update the dequeue pointer further if that was a link TRB or we're at - * the end of an event ring segment (which doesn't have link TRBS) - */ - while (last_trb(xhci, ring, ring->deq_seg, next)) { - if (ring->type == TYPE_EVENT && last_trb_on_last_seg(xhci, - ring, ring->deq_seg, next)) { - ring->cycle_state = (ring->cycle_state ? 0 : 1); + do { + /* + * Update the dequeue pointer further if that was a link TRB or + * we're at the end of an event ring segment (which doesn't have + * link TRBS) + */ + if (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) { + if (ring->type == TYPE_EVENT && + last_trb_on_last_seg(xhci, ring, + ring->deq_seg, ring->dequeue)) { + ring->cycle_state = (ring->cycle_state ? 0 : 1); + } + ring->deq_seg = ring->deq_seg->next; + ring->dequeue = ring->deq_seg->trbs; + } else { + ring->dequeue++; } - ring->deq_seg = ring->deq_seg->next; - ring->dequeue = ring->deq_seg->trbs; - next = ring->dequeue; - } + } while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)); + addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue); } From 952227d5c4d522502b7b815b16be6e991bbaeaed Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 10 Jul 2012 19:10:06 -0300 Subject: [PATCH 0725/2357] USB: add USB_VENDOR_AND_INTERFACE_INFO() macro commit d81a5d1956731c453b85c141458d4ff5d6cc5366 upstream. A lot of Broadcom Bluetooth devices provides vendor specific interface class and we are getting flooded by patches adding new device support. This change will help us enable support for any other Broadcom with vendor specific device that arrives in the future. Only the product id changes for those devices, so this macro would be perfect for us: { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) } Signed-off-by: Marcel Holtmann Signed-off-by: Gustavo Padovan Acked-by: Henrik Rydberg Signed-off-by: Greg Kroah-Hartman --- include/linux/usb.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/linux/usb.h b/include/linux/usb.h index 26229fd8d61..4e8e6685f51 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -783,6 +783,27 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) .bInterfaceSubClass = (sc), \ .bInterfaceProtocol = (pr) +/** + * USB_VENDOR_AND_INTERFACE_INFO - describe a specific usb vendor with a class of usb interfaces + * @vend: the 16 bit USB Vendor ID + * @cl: bInterfaceClass value + * @sc: bInterfaceSubClass value + * @pr: bInterfaceProtocol value + * + * This macro is used to create a struct usb_device_id that matches a + * specific vendor with a specific class of interfaces. + * + * This is especially useful when explicitly matching devices that have + * vendor specific bDeviceClass values, but standards-compliant interfaces. + */ +#define USB_VENDOR_AND_INTERFACE_INFO(vend, cl, sc, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ + | USB_DEVICE_ID_MATCH_VENDOR, \ + .idVendor = (vend), \ + .bInterfaceClass = (cl), \ + .bInterfaceSubClass = (sc), \ + .bInterfaceProtocol = (pr) + /* ----------------------------------------------------------------------- */ /* Stuff for dynamic usb ids */ From a8e480349f91581d93eff8728fc41cbcd1c3eca1 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Sun, 12 Aug 2012 07:16:43 -0500 Subject: [PATCH 0726/2357] pmac_zilog,kdb: Fix console poll hook to return instead of loop commit 38f8eefccf3a23c4058a570fa2938a4f553cf8e0 upstream. kdb <-> kgdb transitioning does not work properly with this UART driver because the get character routine loops indefinitely as opposed to returning NO_POLL_CHAR per the expectation of the KDB I/O driver API. The symptom is a kernel hang when trying to switch debug modes. Signed-off-by: Jason Wessel Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pmac_zilog.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 654755a990d..333c8d012b0 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1348,10 +1348,16 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser) static int pmz_poll_get_char(struct uart_port *port) { struct uart_pmac_port *uap = (struct uart_pmac_port *)port; + int tries = 2; - while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) - udelay(5); - return read_zsdata(uap); + while (tries) { + if ((read_zsreg(uap, R0) & Rx_CH_AV) != 0) + return read_zsdata(uap); + if (tries--) + udelay(5); + } + + return NO_POLL_CHAR; } static void pmz_poll_put_char(struct uart_port *port, unsigned char c) From ddffad3427e2e80fff78d2fc77f21afbba3d11b0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 14 Aug 2012 13:18:53 +0000 Subject: [PATCH 0727/2357] IB/srp: Fix a race condition commit 220329916c72ee3d54ae7262b215a050f04a18fc upstream. Avoid a crash caused by the scmnd->scsi_done(scmnd) call in srp_process_rsp() being invoked with scsi_done == NULL. This can happen if a reply is received during or after a command abort. Reported-by: Joseph Glanville Reference: http://marc.info/?l=linux-rdma&m=134314367801595 Acked-by: David Dillow Signed-off-by: Bart Van Assche Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srp/ib_srp.c | 87 +++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 24 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index bcbf22ee0aa..1b5b0c73005 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -586,24 +586,62 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, scmnd->sc_data_direction); } -static void srp_remove_req(struct srp_target_port *target, - struct srp_request *req, s32 req_lim_delta) +/** + * srp_claim_req - Take ownership of the scmnd associated with a request. + * @target: SRP target port. + * @req: SRP request. + * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take + * ownership of @req->scmnd if it equals @scmnd. + * + * Return value: + * Either NULL or a pointer to the SCSI command the caller became owner of. + */ +static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target, + struct srp_request *req, + struct scsi_cmnd *scmnd) +{ + unsigned long flags; + + spin_lock_irqsave(&target->lock, flags); + if (!scmnd) { + scmnd = req->scmnd; + req->scmnd = NULL; + } else if (req->scmnd == scmnd) { + req->scmnd = NULL; + } else { + scmnd = NULL; + } + spin_unlock_irqrestore(&target->lock, flags); + + return scmnd; +} + +/** + * srp_free_req() - Unmap data and add request to the free request list. + */ +static void srp_free_req(struct srp_target_port *target, + struct srp_request *req, struct scsi_cmnd *scmnd, + s32 req_lim_delta) { unsigned long flags; - srp_unmap_data(req->scmnd, target, req); + srp_unmap_data(scmnd, target, req); + spin_lock_irqsave(&target->lock, flags); target->req_lim += req_lim_delta; - req->scmnd = NULL; list_add_tail(&req->list, &target->free_reqs); spin_unlock_irqrestore(&target->lock, flags); } static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) { - req->scmnd->result = DID_RESET << 16; - req->scmnd->scsi_done(req->scmnd); - srp_remove_req(target, req, 0); + struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL); + + if (scmnd) { + scmnd->result = DID_RESET << 16; + scmnd->scsi_done(scmnd); + srp_free_req(target, req, scmnd, 0); + } } static int srp_reconnect_target(struct srp_target_port *target) @@ -1073,11 +1111,18 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) complete(&target->tsk_mgmt_done); } else { req = &target->req_ring[rsp->tag]; - scmnd = req->scmnd; - if (!scmnd) + scmnd = srp_claim_req(target, req, NULL); + if (!scmnd) { shost_printk(KERN_ERR, target->scsi_host, "Null scmnd for RSP w/tag %016llx\n", (unsigned long long) rsp->tag); + + spin_lock_irqsave(&target->lock, flags); + target->req_lim += be32_to_cpu(rsp->req_lim_delta); + spin_unlock_irqrestore(&target->lock, flags); + + return; + } scmnd->result = rsp->status; if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { @@ -1092,7 +1137,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); - srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta)); + srp_free_req(target, req, scmnd, + be32_to_cpu(rsp->req_lim_delta)); + scmnd->host_scribble = NULL; scmnd->scsi_done(scmnd); } @@ -1631,25 +1678,17 @@ static int srp_abort(struct scsi_cmnd *scmnd) { struct srp_target_port *target = host_to_target(scmnd->device->host); struct srp_request *req = (struct srp_request *) scmnd->host_scribble; - int ret = SUCCESS; shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); - if (!req || target->qp_in_error) + if (!req || target->qp_in_error || !srp_claim_req(target, req, scmnd)) return FAILED; - if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, - SRP_TSK_ABORT_TASK)) - return FAILED; - - if (req->scmnd) { - if (!target->tsk_mgmt_status) { - srp_remove_req(target, req, 0); - scmnd->result = DID_ABORT << 16; - } else - ret = FAILED; - } + srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, + SRP_TSK_ABORT_TASK); + srp_free_req(target, req, scmnd, 0); + scmnd->result = DID_ABORT << 16; - return ret; + return SUCCESS; } static int srp_reset_device(struct scsi_cmnd *scmnd) From c638628c4aafdd2c6bb555331e5dcb099df7f59c Mon Sep 17 00:00:00 2001 From: fangxiaozhi Date: Wed, 8 Aug 2012 09:24:45 +0000 Subject: [PATCH 0728/2357] USB: support the new interfaces of Huawei Data Card devices in option driver commit ee6f827df9107139e8960326e49e1376352ced4d upstream. In this patch, we add new declarations into option.c to support the new interfaces of Huawei Data Card devices. And at the same time, remove the redundant declarations from option.c. Signed-off-by: fangxiaozhi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 279 ++++++++++++++---------------------- 1 file changed, 111 insertions(+), 168 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ae1a4b8c689..87d13546ee8 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -80,85 +80,9 @@ static void option_instat_callback(struct urb *urb); #define OPTION_PRODUCT_GTM380_MODEM 0x7201 #define HUAWEI_VENDOR_ID 0x12D1 -#define HUAWEI_PRODUCT_E600 0x1001 -#define HUAWEI_PRODUCT_E220 0x1003 -#define HUAWEI_PRODUCT_E220BIS 0x1004 -#define HUAWEI_PRODUCT_E1401 0x1401 -#define HUAWEI_PRODUCT_E1402 0x1402 -#define HUAWEI_PRODUCT_E1403 0x1403 -#define HUAWEI_PRODUCT_E1404 0x1404 -#define HUAWEI_PRODUCT_E1405 0x1405 -#define HUAWEI_PRODUCT_E1406 0x1406 -#define HUAWEI_PRODUCT_E1407 0x1407 -#define HUAWEI_PRODUCT_E1408 0x1408 -#define HUAWEI_PRODUCT_E1409 0x1409 -#define HUAWEI_PRODUCT_E140A 0x140A -#define HUAWEI_PRODUCT_E140B 0x140B -#define HUAWEI_PRODUCT_E140C 0x140C -#define HUAWEI_PRODUCT_E140D 0x140D -#define HUAWEI_PRODUCT_E140E 0x140E -#define HUAWEI_PRODUCT_E140F 0x140F -#define HUAWEI_PRODUCT_E1410 0x1410 -#define HUAWEI_PRODUCT_E1411 0x1411 -#define HUAWEI_PRODUCT_E1412 0x1412 -#define HUAWEI_PRODUCT_E1413 0x1413 -#define HUAWEI_PRODUCT_E1414 0x1414 -#define HUAWEI_PRODUCT_E1415 0x1415 -#define HUAWEI_PRODUCT_E1416 0x1416 -#define HUAWEI_PRODUCT_E1417 0x1417 -#define HUAWEI_PRODUCT_E1418 0x1418 -#define HUAWEI_PRODUCT_E1419 0x1419 -#define HUAWEI_PRODUCT_E141A 0x141A -#define HUAWEI_PRODUCT_E141B 0x141B -#define HUAWEI_PRODUCT_E141C 0x141C -#define HUAWEI_PRODUCT_E141D 0x141D -#define HUAWEI_PRODUCT_E141E 0x141E -#define HUAWEI_PRODUCT_E141F 0x141F -#define HUAWEI_PRODUCT_E1420 0x1420 -#define HUAWEI_PRODUCT_E1421 0x1421 -#define HUAWEI_PRODUCT_E1422 0x1422 -#define HUAWEI_PRODUCT_E1423 0x1423 -#define HUAWEI_PRODUCT_E1424 0x1424 -#define HUAWEI_PRODUCT_E1425 0x1425 -#define HUAWEI_PRODUCT_E1426 0x1426 -#define HUAWEI_PRODUCT_E1427 0x1427 -#define HUAWEI_PRODUCT_E1428 0x1428 -#define HUAWEI_PRODUCT_E1429 0x1429 -#define HUAWEI_PRODUCT_E142A 0x142A -#define HUAWEI_PRODUCT_E142B 0x142B -#define HUAWEI_PRODUCT_E142C 0x142C -#define HUAWEI_PRODUCT_E142D 0x142D -#define HUAWEI_PRODUCT_E142E 0x142E -#define HUAWEI_PRODUCT_E142F 0x142F -#define HUAWEI_PRODUCT_E1430 0x1430 -#define HUAWEI_PRODUCT_E1431 0x1431 -#define HUAWEI_PRODUCT_E1432 0x1432 -#define HUAWEI_PRODUCT_E1433 0x1433 -#define HUAWEI_PRODUCT_E1434 0x1434 -#define HUAWEI_PRODUCT_E1435 0x1435 -#define HUAWEI_PRODUCT_E1436 0x1436 -#define HUAWEI_PRODUCT_E1437 0x1437 -#define HUAWEI_PRODUCT_E1438 0x1438 -#define HUAWEI_PRODUCT_E1439 0x1439 -#define HUAWEI_PRODUCT_E143A 0x143A -#define HUAWEI_PRODUCT_E143B 0x143B -#define HUAWEI_PRODUCT_E143C 0x143C -#define HUAWEI_PRODUCT_E143D 0x143D -#define HUAWEI_PRODUCT_E143E 0x143E -#define HUAWEI_PRODUCT_E143F 0x143F #define HUAWEI_PRODUCT_K4505 0x1464 #define HUAWEI_PRODUCT_K3765 0x1465 -#define HUAWEI_PRODUCT_E14AC 0x14AC -#define HUAWEI_PRODUCT_K3806 0x14AE #define HUAWEI_PRODUCT_K4605 0x14C6 -#define HUAWEI_PRODUCT_K5005 0x14C8 -#define HUAWEI_PRODUCT_K3770 0x14C9 -#define HUAWEI_PRODUCT_K3771 0x14CA -#define HUAWEI_PRODUCT_K4510 0x14CB -#define HUAWEI_PRODUCT_K4511 0x14CC -#define HUAWEI_PRODUCT_ETS1220 0x1803 -#define HUAWEI_PRODUCT_E353 0x1506 -#define HUAWEI_PRODUCT_E173S 0x1C05 #define QUANTA_VENDOR_ID 0x0408 #define QUANTA_PRODUCT_Q101 0xEA02 @@ -615,104 +539,123 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1402, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1404, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1407, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1420, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1421, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1422, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1423, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1424, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1425, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1426, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1427, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1428, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1429, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1430, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1431, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1432, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1433, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1434, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1435, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1436, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1437, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1438, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1439, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x33) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x10) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x12) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x13) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x01) }, /* E398 3G Modem */ - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x02) }, /* E398 3G PC UI Interface */ - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x03) }, /* E398 3G Application Interface */ + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) }, + + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, From 7c65b87f22d8a7819879363ef9fc3e6d838925d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 15 Aug 2012 15:43:33 +0200 Subject: [PATCH 0729/2357] USB: option: add ZTE K5006-Z MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f1b5c997e68533df1f96dcd3068a231bca495603 upstream. The ZTE (Vodafone) K5006-Z use the following interface layout: 00 DIAG 01 secondary 02 modem 03 networkcard 04 storage Ignoring interface #3 which is handled by the qmi_wwan driver. Signed-off-by: Bjørn Mork Cc: Thomas Schäfer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 87d13546ee8..ee693ccfdeb 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -886,6 +886,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, From d3d31e57513f7f66fe66accd88837e021a1b96b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ozan=20=C3=87a=C4=9Flayan?= Date: Fri, 10 Aug 2012 17:25:10 +0300 Subject: [PATCH 0730/2357] USB: ftdi_sio: Add VID/PID for Kondo Serial USB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7724a1edbe463b06d4e7831a41149ba095b16c53 upstream. This adds VID/PID for Kondo Kagaku Co. Ltd. Serial USB Adapter interface: http://www.kondo-robot.com/EN/wp/?cat=28 Tested by controlling an RCB3 board using libRCB3. Signed-off-by: Ozan Çağlayan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 53e3e2c5b33..f5819cb4dcf 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -811,6 +811,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, { USB_DEVICE(PI_VID, PI_E861_PID) }, + { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) }, { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 5661c7e2d41..5dd96ca6c38 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -794,6 +794,13 @@ #define PI_VID 0x1a72 /* Vendor ID */ #define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */ +/* + * Kondo Kagaku Co.Ltd. + * http://www.kondo-robot.com/EN + */ +#define KONDO_VID 0x165c +#define KONDO_USB_SERIAL_PID 0x0002 + /* * Bayer Ascensia Contour blood glucose meter USB-converter cable. * http://winglucofacts.com/cables/ From 4893ce51af5c2ccdfabf8f7d34dd28cf84a8a06e Mon Sep 17 00:00:00 2001 From: Mark Ferrell Date: Tue, 24 Jul 2012 14:15:13 -0500 Subject: [PATCH 0731/2357] usb: serial: mos7840: Fixup mos7840_chars_in_buffer() commit 5c263b92f828af6a8cf54041db45ceae5af8f2ab upstream. * Use the buffer content length as opposed to the total buffer size. This can be a real problem when using the mos7840 as a usb serial-console as all kernel output is truncated during boot. Signed-off-by: Mark Ferrell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 62739ff58c7..c1505c3c557 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1189,9 +1189,12 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) } spin_lock_irqsave(&mos7840_port->pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) - if (mos7840_port->busy[i]) - chars += URB_TRANSFER_BUFFER_SIZE; + for (i = 0; i < NUM_URBS; ++i) { + if (mos7840_port->busy[i]) { + struct urb *urb = mos7840_port->write_urb_pool[i]; + chars += urb->transfer_buffer_length; + } + } spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); dbg("%s - returns %d", __func__, chars); return chars; From 4cfb77e8eeddabbca1173a0a704c4065c62c4d05 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 8 Aug 2012 11:48:10 +0200 Subject: [PATCH 0732/2357] usb: gadget: u_ether: fix kworker 100% CPU issue with still used interfaces in eth_stop commit b1b552a69b8805e7e338074a9e8b670b4a795218 upstream. This patch fixes an issue introduced by patch: 72c973d usb: gadget: add usb_endpoint_descriptor to struct usb_ep Without this patch we see a kworker taking 100% CPU, after this sequence: - Connect gadget to a windows host - load g_ether - ifconfig up ; ifconfig down; ifconfig up - ping The "ifconfig down" results in calling eth_stop(), which will call usb_ep_disable() and, if the carrier is still ok, usb_ep_enable(): usb_ep_disable(link->in_ep); usb_ep_disable(link->out_ep); if (netif_carrier_ok(net)) { usb_ep_enable(link->in_ep); usb_ep_enable(link->out_ep); } The ep should stay enabled, but will not, as ep_disable set the desc pointer to NULL, therefore the subsequent ep_enable will fail. This leads to permanent rescheduling of the eth_work() worker as usb_ep_queue() (called by the worker) will fail due to the unconfigured endpoint. We fix this issue by saving the ep descriptors and re-assign them before usb_ep_enable(). Cc: Tatyana Brokhman Signed-off-by: Michael Grzeschik Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/u_ether.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 4e1f0aaafcf..9a2a1ae9b66 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -669,6 +669,8 @@ static int eth_stop(struct net_device *net) spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) { struct gether *link = dev->port_usb; + const struct usb_endpoint_descriptor *in; + const struct usb_endpoint_descriptor *out; if (link->close) link->close(link); @@ -682,10 +684,14 @@ static int eth_stop(struct net_device *net) * their own pace; the network stack can handle old packets. * For the moment we leave this here, since it works. */ + in = link->in_ep->desc; + out = link->out_ep->desc; usb_ep_disable(link->in_ep); usb_ep_disable(link->out_ep); if (netif_carrier_ok(net)) { DBG(dev, "host still using in/out endpoints\n"); + link->in_ep->desc = in; + link->out_ep->desc = out; usb_ep_enable(link->in_ep); usb_ep_enable(link->out_ep); } From e19001248f898e24b4ec08f9f853b49e661328fe Mon Sep 17 00:00:00 2001 From: Jeongdo Son Date: Fri, 15 Jun 2012 02:28:01 +0900 Subject: [PATCH 0733/2357] rt2x00: Add support for BUFFALO WLI-UC-GNM2 to rt2800usb. commit a769f9577232afe2c754606a83aad85127e7052a upstream. This is a RT3070 based device. Signed-off-by: Jeongdo Son Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f388b65fbe9..7e1a492680c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -971,6 +971,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0411, 0x015d) }, { USB_DEVICE(0x0411, 0x016f) }, { USB_DEVICE(0x0411, 0x01a2) }, + { USB_DEVICE(0x0411, 0x01ee) }, /* Corega */ { USB_DEVICE(0x07aa, 0x002f) }, { USB_DEVICE(0x07aa, 0x003c) }, From f95b978981a7d154ba40d14c18e8ed5c694e6124 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 26 Aug 2012 15:02:10 -0700 Subject: [PATCH 0734/2357] Linux 3.4.10 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9549547614b..a1624b99130 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 9 +SUBLEVEL = 10 EXTRAVERSION = NAME = Saber-toothed Squirrel From 61fe808721d1b13c811f6d9a2809628e4ef6bf06 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Aug 2012 17:48:33 -0700 Subject: [PATCH 0735/2357] USB: vt6656: remove __devinit* from the struct usb_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4d088876f24887cd15a29db923f5f37db6a99f21 upstream. This structure needs to always stick around, even if CONFIG_HOTPLUG is disabled, otherwise we can oops when trying to probe a device that was added after the structure is thrown away. Thanks to Fengguang Wu and Bjørn Mork for tracking this issue down. Reported-by: Fengguang Wu Reported-by: Bjørn Mork CC: Forest Bond CC: Marcos Paulo de Souza CC: "David S. Miller" CC: Jesper Juhl CC: Jiri Pirko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/main_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 763e028a5cc..87394541d71 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -222,7 +222,7 @@ DEVICE_PARAM(b80211hEnable, "802.11h mode"); // Static vars definitions // -static struct usb_device_id vt6656_table[] __devinitdata = { +static struct usb_device_id vt6656_table[] = { {USB_DEVICE(VNT_USB_VENDOR_ID, VNT_USB_PRODUCT_ID)}, {} }; From 7d79cc4869cd9fdc47736a5fe44c195813cef4cd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Aug 2012 17:48:41 -0700 Subject: [PATCH 0736/2357] USB: emi62: remove __devinit* from the struct usb_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 83957df21dd94655d2b026e0944a69ff37b83988 upstream. This structure needs to always stick around, even if CONFIG_HOTPLUG is disabled, otherwise we can oops when trying to probe a device that was added after the structure is thrown away. Thanks to Fengguang Wu and Bjørn Mork for tracking this issue down. Reported-by: Fengguang Wu Reported-by: Bjørn Mork CC: Paul Gortmaker CC: Andrew Morton CC: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/emi62.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c index 4e0f167a6c4..8be96de5f6e 100644 --- a/drivers/usb/misc/emi62.c +++ b/drivers/usb/misc/emi62.c @@ -256,7 +256,7 @@ static int emi62_load_firmware (struct usb_device *dev) return err; } -static const struct usb_device_id id_table[] __devinitconst = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(EMI62_VENDOR_ID, EMI62_PRODUCT_ID) }, { } /* Terminating entry */ }; From 5ed0dc3c88fd7586d5ea0b615007bbcf1c7cf7ea Mon Sep 17 00:00:00 2001 From: Wang Xingchao Date: Mon, 13 Aug 2012 14:11:10 +0800 Subject: [PATCH 0737/2357] ALSA: hda - fix Copyright debug message commit 088c820b732dbfd515fc66d459d5f5777f79b406 upstream. As spec said, 1 indicates no copyright is asserted. Signed-off-by: Wang Xingchao Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index e59e2f059b6..0074aee6d39 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -412,7 +412,7 @@ static void print_digital_conv(struct snd_info_buffer *buffer, if (digi1 & AC_DIG1_EMPHASIS) snd_iprintf(buffer, " Preemphasis"); if (digi1 & AC_DIG1_COPYRIGHT) - snd_iprintf(buffer, " Copyright"); + snd_iprintf(buffer, " Non-Copyright"); if (digi1 & AC_DIG1_NONAUDIO) snd_iprintf(buffer, " Non-Audio"); if (digi1 & AC_DIG1_PROFESSIONAL) From 7de4da6fedad1267970c6640e47561c2d38ec0b4 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 3 Aug 2012 17:24:14 +0100 Subject: [PATCH 0738/2357] ARM: 7483/1: vfp: only advertise VFPv4 in hwcaps if CONFIG_VFPv3 is enabled commit 3d9fb0038a9b02febb01efc79a4a5d97f1822a90 upstream. VFPv4 support depends on the VFPv3 context save/restore code, so only advertise support in the hwcaps if the kernel can actually handle it. Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/vfp/vfpmodule.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 1ef803aa7a5..1f8241da03b 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -719,8 +719,10 @@ static int __init vfp_init(void) if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) elf_hwcap |= HWCAP_NEON; #endif +#ifdef CONFIG_VFPv3 if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000) elf_hwcap |= HWCAP_VFPv4; +#endif } } return 0; From aa2e66e8fc1a25b9ff6f6f448a025b3599a90662 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 10 Aug 2012 17:51:18 +0100 Subject: [PATCH 0739/2357] ARM: 7487/1: mm: avoid setting nG bit for user mappings that aren't present commit 47f1204329237a0f8655f5a9f14a38ac81946ca1 upstream. Swap entries are encoding in ptes such that !pte_present(pte) and pte_file(pte). The remaining bits of the descriptor are used to identify the swapfile and offset within it to the swap entry. When writing such a pte for a user virtual address, set_pte_at unconditionally sets the nG bit, which (in the case of LPAE) will corrupt the swapfile offset and lead to a BUG: [ 140.494067] swap_free: Unused swap offset entry 000763b4 [ 140.509989] BUG: Bad page map in process rs:main Q:Reg pte:0ec76800 pmd:8f92e003 This patch fixes the problem by only setting the nG bit for user mappings that are actually present. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/pgtable.h | 34 ++++++++++++++++++---------------- arch/arm/mm/flush.c | 2 -- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index f66626d71e7..d88f9f049e9 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -195,6 +195,18 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd) #define pte_clear(mm,addr,ptep) set_pte_ext(ptep, __pte(0), 0) +#define pte_none(pte) (!pte_val(pte)) +#define pte_present(pte) (pte_val(pte) & L_PTE_PRESENT) +#define pte_write(pte) (!(pte_val(pte) & L_PTE_RDONLY)) +#define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY) +#define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG) +#define pte_exec(pte) (!(pte_val(pte) & L_PTE_XN)) +#define pte_special(pte) (0) + +#define pte_present_user(pte) \ + ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \ + (L_PTE_PRESENT | L_PTE_USER)) + #if __LINUX_ARM_ARCH__ < 6 static inline void __sync_icache_dcache(pte_t pteval) { @@ -206,25 +218,15 @@ extern void __sync_icache_dcache(pte_t pteval); static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval) { - if (addr >= TASK_SIZE) - set_pte_ext(ptep, pteval, 0); - else { + unsigned long ext = 0; + + if (addr < TASK_SIZE && pte_present_user(pteval)) { __sync_icache_dcache(pteval); - set_pte_ext(ptep, pteval, PTE_EXT_NG); + ext |= PTE_EXT_NG; } -} -#define pte_none(pte) (!pte_val(pte)) -#define pte_present(pte) (pte_val(pte) & L_PTE_PRESENT) -#define pte_write(pte) (!(pte_val(pte) & L_PTE_RDONLY)) -#define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY) -#define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG) -#define pte_exec(pte) (!(pte_val(pte) & L_PTE_XN)) -#define pte_special(pte) (0) - -#define pte_present_user(pte) \ - ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \ - (L_PTE_PRESENT | L_PTE_USER)) + set_pte_ext(ptep, pteval, ext); +} #define PTE_BIT_FUNC(fn,op) \ static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 77458548e03..40ca11ed6e5 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -231,8 +231,6 @@ void __sync_icache_dcache(pte_t pteval) struct page *page; struct address_space *mapping; - if (!pte_present_user(pteval)) - return; if (cache_is_vipt_nonaliasing() && !pte_exec(pteval)) /* only flush non-aliasing VIPT caches for exec mappings */ return; From 635a2a845fb26b32b179d7cb7cfb288c91f39933 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 10 Aug 2012 17:51:19 +0100 Subject: [PATCH 0740/2357] ARM: 7488/1: mm: use 5 bits for swapfile type encoding commit f5f2025ef3e2cdb593707cbf87378761f17befbe upstream. Page migration encodes the pfn in the offset field of a swp_entry_t. For LPAE, we support physical addresses of up to 36 bits (due to sparsemem limitations with the size of page flags), requiring 24 bits to represent a pfn. A further 3 bits are used to encode a swp_entry into a pte, leaving 5 bits for the type field. Furthermore, the core code defines MAX_SWAPFILES_SHIFT as 5, so the additional type bit does not get used. This patch reduces the width of the type field to 5 bits, allowing us to create up to 31 swapfiles of 64GB each. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/pgtable.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index d88f9f049e9..41dc31f834c 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -253,13 +253,13 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * <--------------- offset --------------------> <- type --> 0 0 0 + * <--------------- offset ----------------------> < type -> 0 0 0 * - * This gives us up to 63 swap files and 32GB per swap file. Note that + * This gives us up to 31 swap files and 64GB per swap file. Note that * the offset field is always non-zero. */ #define __SWP_TYPE_SHIFT 3 -#define __SWP_TYPE_BITS 6 +#define __SWP_TYPE_BITS 5 #define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) #define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) From 88b67cb1f21cf5059bfbbc2bca7a597b9c58c312 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 10 Aug 2012 19:13:36 +0100 Subject: [PATCH 0741/2357] ARM: 7489/1: errata: fix workaround for erratum #720789 on UP systems commit 730a8128cd8978467eb1cf546b11014acb57d433 upstream. Commit 5a783cbc4836 ("ARM: 7478/1: errata: extend workaround for erratum #720789") added workarounds for erratum #720789 to the range TLB invalidation functions with the observation that the erratum only affects SMP platforms. However, when running an SMP_ON_UP kernel on a uniprocessor platform we must take care to preserve the ASID as the workaround is not required. This patch ensures that we don't set the ASID to 0 when flushing the TLB on such a system, preserving the original behaviour with the workaround disabled. Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/mm/tlb-v7.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S index c2021139cb5..ea94765acf9 100644 --- a/arch/arm/mm/tlb-v7.S +++ b/arch/arm/mm/tlb-v7.S @@ -38,10 +38,10 @@ ENTRY(v7wbi_flush_user_tlb_range) dsb mov r0, r0, lsr #PAGE_SHIFT @ align address mov r1, r1, lsr #PAGE_SHIFT -#ifdef CONFIG_ARM_ERRATA_720789 - mov r3, #0 -#else asid r3, r3 @ mask ASID +#ifdef CONFIG_ARM_ERRATA_720789 + ALT_SMP(W(mov) r3, #0 ) + ALT_UP(W(nop) ) #endif orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA mov r1, r1, lsl #PAGE_SHIFT From 8c17041815762b385631d3a680128dca5a9be31b Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 13 Jul 2012 15:12:03 -0500 Subject: [PATCH 0742/2357] ARM: OMAP2+: Fix dmtimer set source clock failure commit 54f32a35f4d3a653a18a2c8c239f19ae060bd803 upstream. Calling the dmtimer function omap_dm_timer_set_source() fails if following a call to pm_runtime_put() to disable the timer. For example the following sequence would fail to set the parent clock ... omap_dm_timer_stop(gptimer); omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ); The following error message would be seen ... omap_dm_timer_set_source: failed to set timer_32k_ck as parent The problem is that, by design, pm_runtime_put() simply decrements the usage count and returns before the timer has actually been disabled. Therefore, setting the parent clock failed because the timer was still active when the trying to set the parent clock. Setting a parent clock will fail if the clock you are setting the parent of has a non-zero usage count. To ensure that this does not fail use pm_runtime_put_sync() when disabling the timer. Note that this will not be seen on OMAP1 devices, because these devices do not use the clock framework for dmtimers. Signed-off-by: Jon Hunter Acked-by: Kevin Hilman Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-omap/dmtimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 652139c0339..7ac301ee283 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -238,7 +238,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_enable); void omap_dm_timer_disable(struct omap_dm_timer *timer) { - pm_runtime_put(&timer->pdev->dev); + pm_runtime_put_sync(&timer->pdev->dev); } EXPORT_SYMBOL_GPL(omap_dm_timer_disable); From cef2cf5590819d565db994008a6bbb9f27dd9b41 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 7 Aug 2012 19:11:33 +0900 Subject: [PATCH 0743/2357] ARM: S3C24XX: Add missing DMACH_DT_PROP commit e1267371eacf2cbcf580e41f9e64a986cdaf5c1d upstream. Commit 2b90807549 (spi: s3c64xx: add device tree support) requires the DMACH_DT_PROP element in the dma_ch enum. It's not used on non-DT platforms but has to be present nevertheless. So mimic the dummy-add of DMACH_DT_PROP on s3c64xx for s3c24xx machines, to correct the build breakage for the s3c24xx variants using the s3c64xx-spi-driver. Signed-off-by: Heiko Stuebner Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-s3c24xx/include/mach/dma.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c24xx/include/mach/dma.h b/arch/arm/mach-s3c24xx/include/mach/dma.h index acbdfecd418..ccaaafc65c1 100644 --- a/arch/arm/mach-s3c24xx/include/mach/dma.h +++ b/arch/arm/mach-s3c24xx/include/mach/dma.h @@ -24,7 +24,8 @@ */ enum dma_ch { - DMACH_XD0, + DMACH_DT_PROP = -1, /* not yet supported, do not use */ + DMACH_XD0 = 0, DMACH_XD1, DMACH_SDI, DMACH_SPI0, From 588d6b125faae8f369352dedaa4632071b93e78e Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 7 Aug 2012 19:12:05 +0900 Subject: [PATCH 0744/2357] ARM: S3C24XX: Fix s3c2410_dma_enqueue parameters commit b01858c7806e7e6f6121da2e51c9222fc4d21dc6 upstream. Commit d670ac019f60 (ARM: SAMSUNG: DMA Cleanup as per sparse) changed the prototype of the s3c2410_dma_* functions to use the enum dma_ch instead of an generic unsigned int. In the s3c24xx dma.c s3c2410_dma_enqueue seems to have been forgotten, the other functions there were changed correctly. Signed-off-by: Heiko Stuebner Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-s3c24xx/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 28f898f7538..db98e7021f0 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -430,7 +430,7 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan) * when necessary. */ -int s3c2410_dma_enqueue(unsigned int channel, void *id, +int s3c2410_dma_enqueue(enum dma_ch channel, void *id, dma_addr_t data, int size) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); From 449daa0ed24c186c7fd014e698f37cbb8aaf7a4c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 3 Jul 2012 15:33:29 -0300 Subject: [PATCH 0745/2357] Revert dma: imx-dma: Fix kernel crash due to missing clock conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts 9ea2c02bafe276e97b592a046ac733610a6d57fd, which was commit a2367db2ec5e7fc6fe93e221e0fcdee81b053daf upstream. It broke the build on 3.4, and was not needed there. Reported-by: Eric Bénard Cc: Javier Martin Cc: Fabio Estevam Cc: Sascha Hauer Cc: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/imx-dma.c | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 2ca8d3f779f..bb787d8e152 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -172,8 +172,7 @@ struct imxdma_engine { struct device_dma_parameters dma_parms; struct dma_device dma_device; void __iomem *base; - struct clk *dma_ahb; - struct clk *dma_ipg; + struct clk *dma_clk; spinlock_t lock; struct imx_dma_2d_config slots_2d[IMX_DMA_2D_SLOTS]; struct imxdma_channel channel[IMX_DMA_CHANNELS]; @@ -977,20 +976,10 @@ static int __init imxdma_probe(struct platform_device *pdev) return 0; } - imxdma->dma_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(imxdma->dma_ipg)) { - ret = PTR_ERR(imxdma->dma_ipg); - goto err_clk; - } - - imxdma->dma_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(imxdma->dma_ahb)) { - ret = PTR_ERR(imxdma->dma_ahb); - goto err_clk; - } - - clk_prepare_enable(imxdma->dma_ipg); - clk_prepare_enable(imxdma->dma_ahb); + imxdma->dma_clk = clk_get(NULL, "dma"); + if (IS_ERR(imxdma->dma_clk)) + return PTR_ERR(imxdma->dma_clk); + clk_enable(imxdma->dma_clk); /* reset DMA module */ imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR); @@ -999,14 +988,16 @@ static int __init imxdma_probe(struct platform_device *pdev) ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ for DMA\n"); - goto err_enable; + kfree(imxdma); + return ret; } ret = request_irq(MX1_DMA_ERR, imxdma_err_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n"); free_irq(MX1_DMA_INT, NULL); - goto err_enable; + kfree(imxdma); + return ret; } } @@ -1103,10 +1094,7 @@ static int __init imxdma_probe(struct platform_device *pdev) free_irq(MX1_DMA_INT, NULL); free_irq(MX1_DMA_ERR, NULL); } -err_enable: - clk_disable_unprepare(imxdma->dma_ipg); - clk_disable_unprepare(imxdma->dma_ahb); -err_clk: + kfree(imxdma); return ret; } @@ -1126,9 +1114,7 @@ static int __exit imxdma_remove(struct platform_device *pdev) free_irq(MX1_DMA_ERR, NULL); } - clk_disable_unprepare(imxdma->dma_ipg); - clk_disable_unprepare(imxdma->dma_ahb); - kfree(imxdma); + kfree(imxdma); return 0; } From 47bca6a5021332b17aa5efc2d66af1018af70ba1 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 17 Aug 2012 16:43:28 -0400 Subject: [PATCH 0746/2357] xen/setup: Fix one-off error when adding for-balloon PFNs to the P2M. commit c96aae1f7f393387d160211f60398d58463a7e65 upstream. When we are finished with return PFNs to the hypervisor, then populate it back, and also mark the E820 MMIO and E820 gaps as IDENTITY_FRAMEs, we then call P2M to set areas that can be used for ballooning. We were off by one, and ended up over-writting a P2M entry that most likely was an IDENTITY_FRAME. For example: 1-1 mapping on 40000->40200 1-1 mapping on bc558->bc5ac 1-1 mapping on bc5b4->bc8c5 1-1 mapping on bc8c6->bcb7c 1-1 mapping on bcd00->100000 Released 614 pages of unused memory Set 277889 page(s) to 1-1 mapping Populating 40200-40466 pfn range: 614 pages added => here we set from 40466 up to bc559 P2M tree to be INVALID_P2M_ENTRY. We should have done it up to bc558. The end result is that if anybody is trying to construct a PTE for PFN bc558 they end up with ~PAGE_PRESENT. Reported-by-and-Tested-by: Andre Przywara Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/setup.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 1ba8dff2675..99de967762a 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -79,9 +79,16 @@ static void __init xen_add_extra_mem(u64 start, u64 size) memblock_reserve(start, size); xen_max_p2m_pfn = PFN_DOWN(start + size); + for (pfn = PFN_DOWN(start); pfn < xen_max_p2m_pfn; pfn++) { + unsigned long mfn = pfn_to_mfn(pfn); + + if (WARN(mfn == pfn, "Trying to over-write 1-1 mapping (pfn: %lx)\n", pfn)) + continue; + WARN(mfn != INVALID_P2M_ENTRY, "Trying to remove %lx which has %lx mfn!\n", + pfn, mfn); - for (pfn = PFN_DOWN(start); pfn <= xen_max_p2m_pfn; pfn++) __set_phys_to_machine(pfn, INVALID_P2M_ENTRY); + } } static unsigned long __init xen_release_chunk(unsigned long start, From 830cb0da378e5ec143613069faf250b742456021 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 18 Aug 2012 14:27:32 +0800 Subject: [PATCH 0747/2357] ARM: imx6: spin the cpu until hardware takes it down commit c944b0b9354ea06ffb0c8a7178949f1185f9f499 upstream. Though commit 602bf40 (ARM: imx6: exit coherency when shutting down a cpu) improves the stability of imx6q cpu hotplug a lot, there are still hangs seen with a more stressful hotplug testing. It's expected that once imx_enable_cpu(cpu, false) is called, the cpu will be taken down by hardware immediately, and the code after that will not get any chance to execute. However, this is not always the case from the testing. The cpu could possibly be alive for a few cycles before hardware actually takes it down. So rather than letting cpu execute some code that could cause a hang in these cycles, let's make the cpu spin there and wait for hardware to take it down. Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-imx/hotplug.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index 20ed2d56c1a..f8f7437c83b 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -42,22 +42,6 @@ static inline void cpu_enter_lowpower(void) : "cc"); } -static inline void cpu_leave_lowpower(void) -{ - unsigned int v; - - asm volatile( - "mrc p15, 0, %0, c1, c0, 0\n" - " orr %0, %0, %1\n" - " mcr p15, 0, %0, c1, c0, 0\n" - " mrc p15, 0, %0, c1, c0, 1\n" - " orr %0, %0, %2\n" - " mcr p15, 0, %0, c1, c0, 1\n" - : "=&r" (v) - : "Ir" (CR_C), "Ir" (0x40) - : "cc"); -} - /* * platform-specific code to shutdown a CPU * @@ -67,11 +51,10 @@ void platform_cpu_die(unsigned int cpu) { cpu_enter_lowpower(); imx_enable_cpu(cpu, false); - cpu_do_idle(); - cpu_leave_lowpower(); - /* We should never return from idle */ - panic("cpu %d unexpectedly exit from shutdown\n", cpu); + /* spin here until hardware takes it down */ + while (1) + ; } int platform_cpu_disable(unsigned int cpu) From e78e9b4a7848cc1b52678161cbfaa7530efba251 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 16 Aug 2012 10:40:40 +0000 Subject: [PATCH 0748/2357] ARM: imx: select CPU_FREQ_TABLE when needed commit f637c4c9405e21f44cf0045eaf77eddd3a79ca5a upstream. The i.MX cpufreq implementation uses the CPU_FREQ_TABLE helpers, so it needs to select that code to be built. This problem has apparently existed since the i.MX cpufreq code was first merged in v2.6.37. Building IMX without CPU_FREQ_TABLE results in: arch/arm/plat-mxc/built-in.o: In function `mxc_cpufreq_exit': arch/arm/plat-mxc/cpufreq.c:173: undefined reference to `cpufreq_frequency_table_put_attr' arch/arm/plat-mxc/built-in.o: In function `mxc_set_target': arch/arm/plat-mxc/cpufreq.c:84: undefined reference to `cpufreq_frequency_table_target' arch/arm/plat-mxc/built-in.o: In function `mxc_verify_speed': arch/arm/plat-mxc/cpufreq.c:65: undefined reference to `cpufreq_frequency_table_verify' arch/arm/plat-mxc/built-in.o: In function `mxc_cpufreq_init': arch/arm/plat-mxc/cpufreq.c:154: undefined reference to `cpufreq_frequency_table_cpuinfo' arch/arm/plat-mxc/cpufreq.c:162: undefined reference to `cpufreq_frequency_table_get_attr' Signed-off-by: Arnd Bergmann Acked-by: Shawn Guo Cc: Sascha Hauer Cc: Yong Shen Signed-off-by: Greg Kroah-Hartman --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7a8660a2f26..352322a6765 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2113,6 +2113,7 @@ source "drivers/cpufreq/Kconfig" config CPU_FREQ_IMX tristate "CPUfreq driver for i.MX CPUs" depends on ARCH_MXC && CPU_FREQ + select CPU_FREQ_TABLE help This enables the CPUfreq driver for i.MX CPUs. From 73f34fe608cbbba09fa8c74959b7ac5e05973036 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Aug 2012 22:36:04 +0100 Subject: [PATCH 0749/2357] ASoC: wm9712: Fix microphone source selection commit ccf795847a38235ee4a56a24129ce75147d6ba8f upstream. Currently the microphone input source is not selectable as while there is a DAPM widget it's not connected to anything so it won't be properly instantiated. Add something more correct for the input structure to get things going, even though it's not hooked into the rest of the routing map and so won't actually achieve anything except allowing the relevant register bits to be written. Reported-by: Christop Fritz Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm9712.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index b342ae50bcd..b9567bc16ae 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -272,7 +272,7 @@ SOC_DAPM_ENUM("Route", wm9712_enum[9]); /* Mic select */ static const struct snd_kcontrol_new wm9712_mic_src_controls = -SOC_DAPM_ENUM("Route", wm9712_enum[7]); +SOC_DAPM_ENUM("Mic Source Select", wm9712_enum[7]); /* diff select */ static const struct snd_kcontrol_new wm9712_diff_sel_controls = @@ -291,7 +291,9 @@ SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0, &wm9712_capture_selectl_controls), SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0, &wm9712_capture_selectr_controls), -SND_SOC_DAPM_MUX("Mic Select Source", SND_SOC_NOPM, 0, 0, +SND_SOC_DAPM_MUX("Left Mic Select Source", SND_SOC_NOPM, 0, 0, + &wm9712_mic_src_controls), +SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0, &wm9712_mic_src_controls), SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0, &wm9712_diff_sel_controls), @@ -319,6 +321,7 @@ SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0), SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0), SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0), SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0), +SND_SOC_DAPM_PGA("Differential Mic", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1), SND_SOC_DAPM_OUTPUT("MONOOUT"), SND_SOC_DAPM_OUTPUT("HPOUTL"), @@ -379,6 +382,18 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = { {"Mic PGA", NULL, "MIC1"}, {"Mic PGA", NULL, "MIC2"}, + /* microphones */ + {"Differential Mic", NULL, "MIC1"}, + {"Differential Mic", NULL, "MIC2"}, + {"Left Mic Select Source", "Mic 1", "MIC1"}, + {"Left Mic Select Source", "Mic 2", "MIC2"}, + {"Left Mic Select Source", "Stereo", "MIC1"}, + {"Left Mic Select Source", "Differential", "Differential Mic"}, + {"Right Mic Select Source", "Mic 1", "MIC1"}, + {"Right Mic Select Source", "Mic 2", "MIC2"}, + {"Right Mic Select Source", "Stereo", "MIC2"}, + {"Right Mic Select Source", "Differential", "Differential Mic"}, + /* left capture selector */ {"Left Capture Select", "Mic", "MIC1"}, {"Left Capture Select", "Speaker Mixer", "Speaker Mixer"}, From 7b6d36dda04aaa8a87576ba5752e988448f88043 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 7 Aug 2012 15:37:47 +0300 Subject: [PATCH 0750/2357] ASoC: omap-mcbsp: Fix 6pin mux configuration commit d0db84e713eaaccea2a435e1625fb3150b335f4a upstream. The check for the mux_signal callback was wrong which prevents us to configure the 6pin port's FSR/CLKR signal mux. Reported-by: CF Adad Signed-off-by: Peter Ujfalusi Acked-by: Jarkko Nikula Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/omap/mcbsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index e5f44440d1b..fb67772130b 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -691,7 +691,7 @@ int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux) { const char *signal, *src; - if (mcbsp->pdata->mux_signal) + if (!mcbsp->pdata->mux_signal) return -EINVAL; switch (mux) { From 1e6cec2253d5159a5f4e758114fd3c26a98b00a4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Aug 2012 15:28:00 +0100 Subject: [PATCH 0751/2357] vfs: missed source of ->f_pos races commit 0e665d5d1125f9f4ccff56a75e814f10f88861a2 upstream. compat_sys_{read,write}v() need the same "pass a copy of file->f_pos" thing as sys_{read,write}{,v}(). Signed-off-by: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/compat.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/compat.c b/fs/compat.c index f2944ace7a7..2b371b38911 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1160,11 +1160,14 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, struct file *file; int fput_needed; ssize_t ret; + loff_t pos; file = fget_light(fd, &fput_needed); if (!file) return -EBADF; - ret = compat_readv(file, vec, vlen, &file->f_pos); + pos = file->f_pos; + ret = compat_readv(file, vec, vlen, &pos); + file->f_pos = pos; fput_light(file, fput_needed); return ret; } @@ -1226,11 +1229,14 @@ compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, struct file *file; int fput_needed; ssize_t ret; + loff_t pos; file = fget_light(fd, &fput_needed); if (!file) return -EBADF; - ret = compat_writev(file, vec, vlen, &file->f_pos); + pos = file->f_pos; + ret = compat_writev(file, vec, vlen, &pos); + file->f_pos = pos; fput_light(file, fput_needed); return ret; } From b030a2c4a494ff09a9ca84a3280f6a327dd7a02f Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 15 Aug 2012 13:01:24 +0200 Subject: [PATCH 0752/2357] vfs: canonicalize create mode in build_open_flags() commit e68726ff72cf7ba5e7d789857fcd9a75ca573f03 upstream. Userspace can pass weird create mode in open(2) that we canonicalize to "(mode & S_IALLUGO) | S_IFREG" in vfs_create(). The problem is that we use the uncanonicalized mode before calling vfs_create() with unforseen consequences. So do the canonicalization early in build_open_flags(). Signed-off-by: Miklos Szeredi Tested-by: Richard W.M. Jones Signed-off-by: Greg Kroah-Hartman --- fs/open.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/open.c b/fs/open.c index 3f1108b1914..cf1d34fc5e6 100644 --- a/fs/open.c +++ b/fs/open.c @@ -882,9 +882,10 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o int lookup_flags = 0; int acc_mode; - if (!(flags & O_CREAT)) - mode = 0; - op->mode = mode; + if (flags & O_CREAT) + op->mode = (mode & S_IALLUGO) | S_IFREG; + else + op->mode = 0; /* Must never be set by userspace */ flags &= ~FMODE_NONOTIFY; From f998ff53548d95327b6b1543d7b524db26a54d89 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 19 Aug 2012 14:41:02 +1200 Subject: [PATCH 0753/2357] alpha: fix fpu.h usage in userspace commit 0be421862b857e61964435ffcaa7499cf77a5e5a upstream. After commit ec2212088c42 ("Disintegrate asm/system.h for Alpha"), the fpu.h header which we install for userland started depending on special_insns.h which is not installed. However, fpu.h only uses that for __KERNEL__ code, so protect the inclusion the same way to avoid build breakage in glibc: /usr/include/asm/fpu.h:4:31: fatal error: asm/special_insns.h: No such file or directory Reported-by: Matt Turner Signed-off-by: Mike Frysinger Signed-off-by: Michael Cree Acked-by: Matt Turner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/alpha/include/asm/fpu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/alpha/include/asm/fpu.h b/arch/alpha/include/asm/fpu.h index db00f7885fa..e477bcd5b94 100644 --- a/arch/alpha/include/asm/fpu.h +++ b/arch/alpha/include/asm/fpu.h @@ -1,7 +1,9 @@ #ifndef __ASM_ALPHA_FPU_H #define __ASM_ALPHA_FPU_H +#ifdef __KERNEL__ #include +#endif /* * Alpha floating-point control register defines: From 660345c4411ec182f2b735c3e19106ea468a9184 Mon Sep 17 00:00:00 2001 From: Michael Cree Date: Sun, 19 Aug 2012 14:40:56 +1200 Subject: [PATCH 0754/2357] alpha: Don't export SOCK_NONBLOCK to user space. commit a2fa3ccd7b43665fe14cb562761a6c3d26a1d13f upstream. Currently we export SOCK_NONBLOCK to user space but that conflicts with the definition from glibc leading to compilation errors in user programs (e.g. see Debian bug #658460). The generic socket.h restricts the definition of SOCK_NONBLOCK to the kernel, as does the MIPS specific socket.h, so let's do the same on Alpha. Signed-off-by: Michael Cree Acked-by: Matt Turner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/alpha/include/asm/socket.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index dcb221a4b5b..7d2f75be932 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -76,9 +76,11 @@ /* Instruct lower device to use last 4-bytes of skb data as FCS */ #define SO_NOFCS 43 +#ifdef __KERNEL__ /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ #define SOCK_NONBLOCK 0x40000000 +#endif /* __KERNEL__ */ #endif /* _ASM_SOCKET_H */ From 5be8fc241c52f469cd8f2c9e4ebd66ce4ab9df34 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Aug 2012 17:48:37 -0700 Subject: [PATCH 0755/2357] USB: winbond: remove __devinit* from the struct usb_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 43a34695d9cd79c6659f09da6d3b0624f3dd169f upstream. This structure needs to always stick around, even if CONFIG_HOTPLUG is disabled, otherwise we can oops when trying to probe a device that was added after the structure is thrown away. Thanks to Fengguang Wu and Bjørn Mork for tracking this issue down. Reported-by: Fengguang Wu Reported-by: Bjørn Mork CC: Pavel Machek CC: Paul Gortmaker CC: "John W. Linville" CC: Eliad Peller CC: Devendra Naga Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/wbusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index c3751a71838..9160049ff54 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -25,7 +25,7 @@ MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1"); -static const struct usb_device_id wb35_table[] __devinitconst = { +static const struct usb_device_id wb35_table[] = { { USB_DEVICE(0x0416, 0x0035) }, { USB_DEVICE(0x18E8, 0x6201) }, { USB_DEVICE(0x18E8, 0x6206) }, From c3a0afddee7ed8979b8d14346376848e0a306850 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 21 Aug 2012 16:15:52 -0700 Subject: [PATCH 0756/2357] mm: hugetlbfs: correctly populate shared pmd commit eb48c071464757414538c68a6033c8f8c15196f8 upstream. Each page mapped in a process's address space must be correctly accounted for in _mapcount. Normally the rules for this are straightforward but hugetlbfs page table sharing is different. The page table pages at the PMD level are reference counted while the mapcount remains the same. If this accounting is wrong, it causes bugs like this one reported by Larry Woodman: kernel BUG at mm/filemap.c:135! invalid opcode: 0000 [#1] SMP CPU 22 Modules linked in: bridge stp llc sunrpc binfmt_misc dcdbas microcode pcspkr acpi_pad acpi] Pid: 18001, comm: mpitest Tainted: G W 3.3.0+ #4 Dell Inc. PowerEdge R620/07NDJ2 RIP: 0010:[] [] __delete_from_page_cache+0x15d/0x170 Process mpitest (pid: 18001, threadinfo ffff880428972000, task ffff880428b5cc20) Call Trace: delete_from_page_cache+0x40/0x80 truncate_hugepages+0x115/0x1f0 hugetlbfs_evict_inode+0x18/0x30 evict+0x9f/0x1b0 iput_final+0xe3/0x1e0 iput+0x3e/0x50 d_kill+0xf8/0x110 dput+0xe2/0x1b0 __fput+0x162/0x240 During fork(), copy_hugetlb_page_range() detects if huge_pte_alloc() shared page tables with the check dst_pte == src_pte. The logic is if the PMD page is the same, they must be shared. This assumes that the sharing is between the parent and child. However, if the sharing is with a different process entirely then this check fails as in this diagram: parent | ------------>pmd src_pte----------> data page ^ other--------->pmd--------------------| ^ child-----------| dst_pte For this situation to occur, it must be possible for Parent and Other to have faulted and failed to share page tables with each other. This is possible due to the following style of race. PROC A PROC B copy_hugetlb_page_range copy_hugetlb_page_range src_pte == huge_pte_offset src_pte == huge_pte_offset !src_pte so no sharing !src_pte so no sharing (time passes) hugetlb_fault hugetlb_fault huge_pte_alloc huge_pte_alloc huge_pmd_share huge_pmd_share LOCK(i_mmap_mutex) find nothing, no sharing UNLOCK(i_mmap_mutex) LOCK(i_mmap_mutex) find nothing, no sharing UNLOCK(i_mmap_mutex) pmd_alloc pmd_alloc LOCK(instantiation_mutex) fault UNLOCK(instantiation_mutex) LOCK(instantiation_mutex) fault UNLOCK(instantiation_mutex) These two processes are not poing to the same data page but are not sharing page tables because the opportunity was missed. When either process later forks, the src_pte == dst pte is potentially insufficient. As the check falls through, the wrong PTE information is copied in (harmless but wrong) and the mapcount is bumped for a page mapped by a shared page table leading to the BUG_ON. This patch addresses the issue by moving pmd_alloc into huge_pmd_share which guarantees that the shared pud is populated in the same critical section as pmd. This also means that huge_pte_offset test in huge_pmd_share is serialized correctly now which in turn means that the success of the sharing will be higher as the racing tasks see the pud and pmd populated together. Race identified and changelog written mostly by Mel Gorman. {akpm@linux-foundation.org: attempt to make the huge_pmd_share() comment comprehensible, clean up coding style] Reported-by: Larry Woodman Tested-by: Larry Woodman Reviewed-by: Mel Gorman Signed-off-by: Michal Hocko Reviewed-by: Rik van Riel Cc: David Gibson Cc: Ken Chen Cc: Cong Wang Cc: Hillf Danton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/hugetlbpage.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c index f6679a7fb8c..b91e4851242 100644 --- a/arch/x86/mm/hugetlbpage.c +++ b/arch/x86/mm/hugetlbpage.c @@ -56,9 +56,16 @@ static int vma_shareable(struct vm_area_struct *vma, unsigned long addr) } /* - * search for a shareable pmd page for hugetlb. + * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc() + * and returns the corresponding pte. While this is not necessary for the + * !shared pmd case because we can allocate the pmd later as well, it makes the + * code much cleaner. pmd allocation is essential for the shared case because + * pud has to be populated inside the same i_mmap_mutex section - otherwise + * racing tasks could either miss the sharing (see huge_pte_offset) or select a + * bad pmd for sharing. */ -static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud) +static pte_t * +huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud) { struct vm_area_struct *vma = find_vma(mm, addr); struct address_space *mapping = vma->vm_file->f_mapping; @@ -68,9 +75,10 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud) struct vm_area_struct *svma; unsigned long saddr; pte_t *spte = NULL; + pte_t *pte; if (!vma_shareable(vma, addr)) - return; + return (pte_t *)pmd_alloc(mm, pud, addr); mutex_lock(&mapping->i_mmap_mutex); vma_prio_tree_foreach(svma, &iter, &mapping->i_mmap, idx, idx) { @@ -97,7 +105,9 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud) put_page(virt_to_page(spte)); spin_unlock(&mm->page_table_lock); out: + pte = (pte_t *)pmd_alloc(mm, pud, addr); mutex_unlock(&mapping->i_mmap_mutex); + return pte; } /* @@ -142,8 +152,9 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, } else { BUG_ON(sz != PMD_SIZE); if (pud_none(*pud)) - huge_pmd_share(mm, addr, pud); - pte = (pte_t *) pmd_alloc(mm, pud, addr); + pte = huge_pmd_share(mm, addr, pud); + else + pte = (pte_t *)pmd_alloc(mm, pud, addr); } } BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte)); From 69b9b6d1966c9d2a3c610401eee3491b28e8a935 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Mon, 20 Aug 2012 11:17:00 +0200 Subject: [PATCH 0757/2357] ALSA: hda - don't create dysfunctional mixer controls for ca0132 commit c41999a23929f30808bae6009d8065052d4d73fd upstream. It's possible that these amps are settable somehow, e g through secret codec verbs, but for now, don't create the controls (as they won't be working anyway, and cause errors in amixer). BugLink: https://bugs.launchpad.net/bugs/1038651 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_ca0132.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 21d91d580da..70b4f02da2c 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -276,6 +276,10 @@ static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, int type = dir ? HDA_INPUT : HDA_OUTPUT; struct snd_kcontrol_new knew = HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); + if ((query_amp_caps(codec, nid, type) & AC_AMPCAP_MUTE) == 0) { + snd_printdd("Skipping '%s %s Switch' (no mute on node 0x%x)\n", pfx, dirstr[dir], nid); + return 0; + } sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); } @@ -287,6 +291,10 @@ static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, int type = dir ? HDA_INPUT : HDA_OUTPUT; struct snd_kcontrol_new knew = HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); + if ((query_amp_caps(codec, nid, type) & AC_AMPCAP_NUM_STEPS) == 0) { + snd_printdd("Skipping '%s %s Volume' (no amp on node 0x%x)\n", pfx, dirstr[dir], nid); + return 0; + } sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); } From 94a6f1787e1f896585a093aa2f45cefbbef80f24 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Tue, 14 Aug 2012 16:06:43 -0700 Subject: [PATCH 0758/2357] target: fix NULL pointer dereference bug alloc_page() fails to get memory commit d0e27c88d795fb9647153063ec48051fd84e1731 upstream. I am hitting this bug when the target is low in memory that fails the alloc_page() for the newly submitted command. This is a sort of off-by-one bug causing NULL pointer dereference in __free_page() since 'i' here is really the counter of total pages that have been successfully allocated here. Signed-off-by: Yi Zou Cc: Andy Grover Cc: Nicholas Bellinger Cc: Open-FCoE.org Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0686d61adea..222f1c5ff94 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3675,9 +3675,9 @@ transport_generic_get_mem(struct se_cmd *cmd) return 0; out: - while (i >= 0) { - __free_page(sg_page(&cmd->t_data_sg[i])); + while (i > 0) { i--; + __free_page(sg_page(&cmd->t_data_sg[i])); } kfree(cmd->t_data_sg); cmd->t_data_sg = NULL; From 73b8b9f59d61e0c0e2beaada246f1ed41df0c8fd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 20 Aug 2012 12:42:15 -0400 Subject: [PATCH 0759/2357] NFSv3: Ensure that do_proc_get_root() reports errors correctly commit 086600430493e04b802bee6e5b3ce0458e4eb77f upstream. If the rpc call to NFS3PROC_FSINFO fails, then we need to report that error so that the mount fails. Otherwise we can end up with a superblock with completely unusable values for block sizes, maxfilesize, etc. Reported-by: Yuanming Chen Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs3proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 5242eae6711..a1e416b7bae 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -69,7 +69,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, nfs_fattr_init(info->fattr); status = rpc_call_sync(client, &msg, 0); dprintk("%s: reply fsinfo: %d\n", __func__, status); - if (!(info->fattr->valid & NFS_ATTR_FATTR)) { + if (status == 0 && !(info->fattr->valid & NFS_ATTR_FATTR)) { msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; msg.rpc_resp = info->fattr; status = rpc_call_sync(client, &msg, 0); From c2bf322ed7e21107609d44bc914afba3aed35b85 Mon Sep 17 00:00:00 2001 From: Idan Kedar Date: Thu, 2 Aug 2012 11:47:10 +0300 Subject: [PATCH 0760/2357] pnfs: defer release of pages in layoutget commit 8554116e17eef055d9dd58a94b3427cb2ad1c317 upstream. we have encountered a bug whereby reading a lot of files (copying fedora's /bin) from a pNFS mount and hitting Ctrl+C in the middle caused a general protection fault in xdr_shrink_bufhead. this function is called when decoding the response from LAYOUTGET. the decoding is done by a worker thread, and the caller of LAYOUTGET waits for the worker thread to complete. hitting Ctrl+C caused the synchronous wait to end and the next thing the caller does is to free the pages, so when the worker thread calls xdr_shrink_bufhead, the pages are gone. therefore, the cleanup of these pages has been moved to nfs4_layoutget_release. Signed-off-by: Idan Kedar Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++- fs/nfs/pnfs.c | 39 +------------------------------- fs/nfs/pnfs.h | 2 +- 3 files changed, 58 insertions(+), 40 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d60c2d870ab..4063dc5c176 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5966,11 +5966,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) dprintk("<-- %s\n", __func__); } +static size_t max_response_pages(struct nfs_server *server) +{ + u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; + return nfs_page_array_len(0, max_resp_sz); +} + +static void nfs4_free_pages(struct page **pages, size_t size) +{ + int i; + + if (!pages) + return; + + for (i = 0; i < size; i++) { + if (!pages[i]) + break; + __free_page(pages[i]); + } + kfree(pages); +} + +static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) +{ + struct page **pages; + int i; + + pages = kcalloc(size, sizeof(struct page *), gfp_flags); + if (!pages) { + dprintk("%s: can't alloc array of %zu pages\n", __func__, size); + return NULL; + } + + for (i = 0; i < size; i++) { + pages[i] = alloc_page(gfp_flags); + if (!pages[i]) { + dprintk("%s: failed to allocate page\n", __func__); + nfs4_free_pages(pages, size); + return NULL; + } + } + + return pages; +} + static void nfs4_layoutget_release(void *calldata) { struct nfs4_layoutget *lgp = calldata; + struct nfs_server *server = NFS_SERVER(lgp->args.inode); + size_t max_pages = max_response_pages(server); dprintk("--> %s\n", __func__); + nfs4_free_pages(lgp->args.layout.pages, max_pages); put_nfs_open_context(lgp->args.ctx); kfree(calldata); dprintk("<-- %s\n", __func__); @@ -5982,9 +6029,10 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = { .rpc_release = nfs4_layoutget_release, }; -int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) +int nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) { struct nfs_server *server = NFS_SERVER(lgp->args.inode); + size_t max_pages = max_response_pages(server); struct rpc_task *task; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], @@ -6002,6 +6050,13 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) dprintk("--> %s\n", __func__); + lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags); + if (!lgp->args.layout.pages) { + nfs4_layoutget_release(lgp); + return -ENOMEM; + } + lgp->args.layout.pglen = max_pages * PAGE_SIZE; + lgp->res.layoutp = &lgp->args.layout; lgp->res.seq_res.sr_slot = NULL; nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 38512bcd2e9..059e2c350ad 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -574,9 +574,6 @@ send_layoutget(struct pnfs_layout_hdr *lo, struct nfs_server *server = NFS_SERVER(ino); struct nfs4_layoutget *lgp; struct pnfs_layout_segment *lseg = NULL; - struct page **pages = NULL; - int i; - u32 max_resp_sz, max_pages; dprintk("--> %s\n", __func__); @@ -585,20 +582,6 @@ send_layoutget(struct pnfs_layout_hdr *lo, if (lgp == NULL) return NULL; - /* allocate pages for xdr post processing */ - max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; - max_pages = nfs_page_array_len(0, max_resp_sz); - - pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); - if (!pages) - goto out_err_free; - - for (i = 0; i < max_pages; i++) { - pages[i] = alloc_page(gfp_flags); - if (!pages[i]) - goto out_err_free; - } - lgp->args.minlength = PAGE_CACHE_SIZE; if (lgp->args.minlength > range->length) lgp->args.minlength = range->length; @@ -607,39 +590,19 @@ send_layoutget(struct pnfs_layout_hdr *lo, lgp->args.type = server->pnfs_curr_ld->id; lgp->args.inode = ino; lgp->args.ctx = get_nfs_open_context(ctx); - lgp->args.layout.pages = pages; - lgp->args.layout.pglen = max_pages * PAGE_SIZE; lgp->lsegpp = &lseg; lgp->gfp_flags = gfp_flags; /* Synchronously retrieve layout information from server and * store in lseg. */ - nfs4_proc_layoutget(lgp); + nfs4_proc_layoutget(lgp, gfp_flags); if (!lseg) { /* remember that LAYOUTGET failed and suspend trying */ set_bit(lo_fail_bit(range->iomode), &lo->plh_flags); } - /* free xdr pages */ - for (i = 0; i < max_pages; i++) - __free_page(pages[i]); - kfree(pages); - return lseg; - -out_err_free: - /* free any allocated xdr pages, lgp as it's not used */ - if (pages) { - for (i = 0; i < max_pages; i++) { - if (!pages[i]) - break; - __free_page(pages[i]); - } - kfree(pages); - } - kfree(lgp); - return NULL; } /* Initiates a LAYOUTRETURN(FILE) */ diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 442ebf68eee..8d95818330c 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -161,7 +161,7 @@ extern int nfs4_proc_getdevicelist(struct nfs_server *server, struct pnfs_devicelist *devlist); extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *dev); -extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp); +extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags); extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); /* pnfs.c */ From f401b102e87f77b81c041a06f37e3f764ed1a8e7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 8 Aug 2012 16:03:13 -0400 Subject: [PATCH 0761/2357] NFSv4.1: Remove a bogus BUG_ON() in nfs4_layoutreturn_done commit 47fbf7976e0b7d9dcdd799e2a1baba19064d9631 upstream. Ever since commit 0a57cdac3f (NFSv4.1 send layoutreturn to fence disconnected data server) we've been sending layoutreturn calls while there is potentially still outstanding I/O to the data servers. The reason we do this is to avoid races between replayed writes to the MDS and the original writes to the DS. When this happens, the BUG_ON() in nfs4_layoutreturn_done can be triggered because it assumes that we would never call layoutreturn without knowing that all I/O to the DS is finished. The fix is to remove the BUG_ON() now that the assumptions behind the test are obsolete. Reported-by: Boaz Harrosh Reported-by: Tigran Mkrtchyan Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4063dc5c176..dc573245eea 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -6102,12 +6102,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) return; } spin_lock(&lo->plh_inode->i_lock); - if (task->tk_status == 0) { - if (lrp->res.lrs_present) { - pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); - } else - BUG_ON(!list_empty(&lo->plh_segs)); - } + if (task->tk_status == 0 && lrp->res.lrs_present) + pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); lo->plh_block_lgets--; spin_unlock(&lo->plh_inode->i_lock); dprintk("<-- %s\n", __func__); From 797d03b980a559cd3312f7df3b41bb265cddcd8b Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 9 Aug 2012 14:05:49 -0400 Subject: [PATCH 0762/2357] NFS: Clear key construction data if the idmap upcall fails commit c5066945b7ea346a11424dbeb7830b7d7d00c206 upstream. idmap_pipe_downcall already clears this field if the upcall succeeds, but if it fails (rpc.idmapd isn't running) the field will still be set on the next call triggering a BUG_ON(). This patch tries to handle all possible ways that the upcall could fail and clear the idmap key data for each one. Signed-off-by: Bryan Schumaker Tested-by: William Dauchy Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/idmap.c | 56 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 929ba011172..98d664349f7 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -63,6 +63,12 @@ struct idmap { struct mutex idmap_mutex; }; +struct idmap_legacy_upcalldata { + struct rpc_pipe_msg pipe_msg; + struct idmap_msg idmap_msg; + struct idmap *idmap; +}; + /** * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields * @fattr: fully initialised struct nfs_fattr @@ -326,6 +332,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, name, namelen, type, data, data_size, idmap); + idmap->idmap_key_cons = NULL; mutex_unlock(&idmap->idmap_mutex); } return ret; @@ -383,11 +390,13 @@ static const match_table_t nfs_idmap_tokens = { static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *); static ssize_t idmap_pipe_downcall(struct file *, const char __user *, size_t); +static void idmap_release_pipe(struct inode *); static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); static const struct rpc_pipe_ops idmap_upcall_ops = { .upcall = rpc_pipe_generic_upcall, .downcall = idmap_pipe_downcall, + .release_pipe = idmap_release_pipe, .destroy_msg = idmap_pipe_destroy_msg, }; @@ -603,7 +612,8 @@ void nfs_idmap_quit(void) nfs_idmap_quit_keyring(); } -static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im, +static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap, + struct idmap_msg *im, struct rpc_pipe_msg *msg) { substring_t substr; @@ -646,6 +656,7 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, const char *op, void *aux) { + struct idmap_legacy_upcalldata *data; struct rpc_pipe_msg *msg; struct idmap_msg *im; struct idmap *idmap = (struct idmap *)aux; @@ -653,15 +664,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, int ret = -ENOMEM; /* msg and im are freed in idmap_pipe_destroy_msg */ - msg = kmalloc(sizeof(*msg), GFP_KERNEL); - if (!msg) - goto out0; - - im = kmalloc(sizeof(*im), GFP_KERNEL); - if (!im) + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) goto out1; - ret = nfs_idmap_prepare_message(key->description, im, msg); + msg = &data->pipe_msg; + im = &data->idmap_msg; + data->idmap = idmap; + + ret = nfs_idmap_prepare_message(key->description, idmap, im, msg); if (ret < 0) goto out2; @@ -670,15 +681,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, ret = rpc_queue_upcall(idmap->idmap_pipe, msg); if (ret < 0) - goto out2; + goto out3; return ret; +out3: + idmap->idmap_key_cons = NULL; out2: - kfree(im); + kfree(data); out1: - kfree(msg); -out0: complete_request_key(cons, ret); return ret; } @@ -762,9 +773,26 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) { + struct idmap_legacy_upcalldata *data = container_of(msg, + struct idmap_legacy_upcalldata, + pipe_msg); + struct idmap *idmap = data->idmap; + struct key_construction *cons; + if (msg->errno) { + cons = ACCESS_ONCE(idmap->idmap_key_cons); + idmap->idmap_key_cons = NULL; + complete_request_key(cons, msg->errno); + } /* Free memory allocated in nfs_idmap_legacy_upcall() */ - kfree(msg->data); - kfree(msg); + kfree(data); +} + +static void +idmap_release_pipe(struct inode *inode) +{ + struct rpc_inode *rpci = RPC_I(inode); + struct idmap *idmap = (struct idmap *)rpci->private; + idmap->idmap_key_cons = NULL; } int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) From d3078898b6f08028ee5ab8f6e8d12216d7f707ee Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 9 Aug 2012 14:05:50 -0400 Subject: [PATCH 0763/2357] NFS: return -ENOKEY when the upcall fails to map the name commit 12dfd080556124088ed61a292184947711b46cbe upstream. This allows the normal error-paths to handle the error, rather than making a special call to complete_request_key() just for this instance. Signed-off-by: Bryan Schumaker Tested-by: William Dauchy Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/idmap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 98d664349f7..9131b17f3a7 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -747,9 +747,8 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) } if (!(im.im_status & IDMAP_STATUS_SUCCESS)) { - ret = mlen; - complete_request_key(cons, -ENOKEY); - goto out_incomplete; + ret = -ENOKEY; + goto out; } namelen_in = strnlen(im.im_name, IDMAP_NAMESZ); @@ -766,7 +765,6 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) out: complete_request_key(cons, ret); -out_incomplete: return ret; } From 4c795fe18aa1d2756a82c46ca29d4bfad2704d4d Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 21 Aug 2012 21:50:58 +0300 Subject: [PATCH 0764/2357] UBIFS: fix complaints about too small debug buffer size commit 65b455b123c7e2b835a0b7148f9bae584f95000e upstream. When debugging is enabled, we use a temporary on-stack buffer for formatting the key strings like "(11368871, direntry, 0xcd0750)". The buffer size is 32 bytes and sometimes it is not enough to fit the key string - e.g., when inode numbers are high. This is not fatal, but the key strings are incomplete and UBIFS complains like this: UBIFS assert failed in dbg_snprintf_key at 137 (pid 1) This is a regression caused by "515315a UBIFS: fix key printing". Fix the issue by increasing the buffer to 48 bytes. Reported-by: Michael Hench Signed-off-by: Artem Bityutskiy Tested-by: Michael Hench Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 9f717655df1..28e3de1892b 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -170,7 +170,7 @@ struct ubifs_global_debug_info { #define ubifs_dbg_msg(type, fmt, ...) \ pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__) -#define DBG_KEY_BUF_LEN 32 +#define DBG_KEY_BUF_LEN 48 #define ubifs_dbg_msg_key(type, key, fmt, ...) do { \ char __tmp_key_buf[DBG_KEY_BUF_LEN]; \ pr_debug("UBIFS DBG " type ": " fmt "%s\n", ##__VA_ARGS__, \ From a431bd57a95921188f61096e5ce29d1b769be118 Mon Sep 17 00:00:00 2001 From: Ram Malovany Date: Thu, 19 Jul 2012 10:26:09 +0300 Subject: [PATCH 0765/2357] Bluetooth: Fix using NULL inquiry entry commit c810089c27e48b816181b454fcc493d19fdbc2ba upstream. If entry wasn't found in the hci_inquiry_cache_lookup_resolve do not resolve the name.This will fix a kernel crash when trying to use NULL pointer. Signed-off-by: Ram Malovany Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_event.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1266f78fa8e..866fc3b22fb 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1357,6 +1357,9 @@ static bool hci_resolve_next_name(struct hci_dev *hdev) return false; e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); + if (!e) + return false; + if (hci_resolve_name(hdev, e) == 0) { e->name_state = NAME_PENDING; return true; From a8b8ad6dcf49c84c7a8633082191c6fd7539c355 Mon Sep 17 00:00:00 2001 From: Ram Malovany Date: Thu, 19 Jul 2012 10:26:10 +0300 Subject: [PATCH 0766/2357] Bluetooth: Fix using a NULL inquiry cache entry commit 7cc8380eb10347016d95bf6f9d842c2ae6d12932 upstream. If the device was not found in a list of found devices names of which are pending.This may happen in a case when HCI Remote Name Request was sent as a part of incoming connection establishment procedure. Hence there is no need to continue resolving a next name as it will be done upon receiving another Remote Name Request Complete Event. This will fix a kernel crash when trying to use this entry to resolve the next name. Signed-off-by: Ram Malovany Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_event.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 866fc3b22fb..df2615d59eb 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1388,12 +1388,18 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, return; e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING); - if (e) { + /* If the device was not found in a list of found devices names of which + * are pending. there is no need to continue resolving a next name as it + * will be done upon receiving another Remote Name Request Complete + * Event */ + if (!e) + return; + + list_del(&e->list); + if (name) { e->name_state = NAME_KNOWN; - list_del(&e->list); - if (name) - mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00, - e->data.rssi, name, name_len); + mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00, + e->data.rssi, name, name_len); } if (hci_resolve_next_name(hdev)) From 4a20bce04ec14c74f5b77c73d7d8d476ace74cea Mon Sep 17 00:00:00 2001 From: Ram Malovany Date: Thu, 19 Jul 2012 10:26:11 +0300 Subject: [PATCH 0767/2357] Bluetooth: Set name_state to unknown when entry name is empty commit c3e7c0d90b14a3e7ac091d24cef09efb516d587b upstream. When the name of the given entry is empty , the state needs to be updated accordingly. Signed-off-by: Ram Malovany Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_event.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index df2615d59eb..9cdcfd9f907 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1400,6 +1400,8 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, e->name_state = NAME_KNOWN; mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00, e->data.rssi, name, name_len); + } else { + e->name_state = NAME_NOT_KNOWN; } if (hci_resolve_next_name(hdev)) From 3cf3cfc448c480c86c439ba7c707a7b4f73ba9d9 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Thu, 19 Jul 2012 14:46:08 +0200 Subject: [PATCH 0768/2357] Bluetooth: Fix legacy pairing with some devices commit a9ea3ed9b71cc3271dd59e76f65748adcaa76422 upstream. Some devices e.g. some Android based phones don't do SDP search before pairing and cancel legacy pairing when ACL is disconnected. PIN Code Request event which changes ACL timeout to HCI_PAIRING_TIMEOUT is only received after remote user entered PIN. In that case no L2CAP is connected so default HCI_DISCONN_TIMEOUT (2 seconds) is being used to timeout ACL connection. This results in problems with legacy pairing as remote user has only few seconds to enter PIN before ACL is disconnected. Increase disconnect timeout for incomming connection to HCI_PAIRING_TIMEOUT if SSP is disabled and no linkey exists. To avoid keeping ACL alive for too long after SDP search set ACL timeout back to HCI_DISCONN_TIMEOUT when L2CAP is connected. 2012-07-19 13:24:43.413521 < HCI Command: Create Connection (0x01|0x0005) plen 13 bdaddr 00:02:72:D6:6A:3F ptype 0xcc18 rswitch 0x01 clkoffset 0x0000 Packet type: DM1 DM3 DM5 DH1 DH3 DH5 2012-07-19 13:24:43.425224 > HCI Event: Command Status (0x0f) plen 4 Create Connection (0x01|0x0005) status 0x00 ncmd 1 2012-07-19 13:24:43.885222 > HCI Event: Role Change (0x12) plen 8 status 0x00 bdaddr 00:02:72:D6:6A:3F role 0x01 Role: Slave 2012-07-19 13:24:44.054221 > HCI Event: Connect Complete (0x03) plen 11 status 0x00 handle 42 bdaddr 00:02:72:D6:6A:3F type ACL encrypt 0x00 2012-07-19 13:24:44.054313 < HCI Command: Read Remote Supported Features (0x01|0x001b) plen 2 handle 42 2012-07-19 13:24:44.055176 > HCI Event: Page Scan Repetition Mode Change (0x20) plen 7 bdaddr 00:02:72:D6:6A:3F mode 0 2012-07-19 13:24:44.056217 > HCI Event: Max Slots Change (0x1b) plen 3 handle 42 slots 5 2012-07-19 13:24:44.059218 > HCI Event: Command Status (0x0f) plen 4 Read Remote Supported Features (0x01|0x001b) status 0x00 ncmd 0 2012-07-19 13:24:44.062192 > HCI Event: Command Status (0x0f) plen 4 Unknown (0x00|0x0000) status 0x00 ncmd 1 2012-07-19 13:24:44.067219 > HCI Event: Read Remote Supported Features (0x0b) plen 11 status 0x00 handle 42 Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87 2012-07-19 13:24:44.067248 < HCI Command: Read Remote Extended Features (0x01|0x001c) plen 3 handle 42 page 1 2012-07-19 13:24:44.071217 > HCI Event: Command Status (0x0f) plen 4 Read Remote Extended Features (0x01|0x001c) status 0x00 ncmd 1 2012-07-19 13:24:44.076218 > HCI Event: Read Remote Extended Features (0x23) plen 13 status 0x00 handle 42 page 1 max 1 Features: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 2012-07-19 13:24:44.076249 < HCI Command: Remote Name Request (0x01|0x0019) plen 10 bdaddr 00:02:72:D6:6A:3F mode 2 clkoffset 0x0000 2012-07-19 13:24:44.081218 > HCI Event: Command Status (0x0f) plen 4 Remote Name Request (0x01|0x0019) status 0x00 ncmd 1 2012-07-19 13:24:44.105214 > HCI Event: Remote Name Req Complete (0x07) plen 255 status 0x00 bdaddr 00:02:72:D6:6A:3F name 'uw000951-0' 2012-07-19 13:24:44.105284 < HCI Command: Authentication Requested (0x01|0x0011) plen 2 handle 42 2012-07-19 13:24:44.111207 > HCI Event: Command Status (0x0f) plen 4 Authentication Requested (0x01|0x0011) status 0x00 ncmd 1 2012-07-19 13:24:44.112220 > HCI Event: Link Key Request (0x17) plen 6 bdaddr 00:02:72:D6:6A:3F 2012-07-19 13:24:44.112249 < HCI Command: Link Key Request Negative Reply (0x01|0x000c) plen 6 bdaddr 00:02:72:D6:6A:3F 2012-07-19 13:24:44.115215 > HCI Event: Command Complete (0x0e) plen 10 Link Key Request Negative Reply (0x01|0x000c) ncmd 1 status 0x00 bdaddr 00:02:72:D6:6A:3F 2012-07-19 13:24:44.116215 > HCI Event: PIN Code Request (0x16) plen 6 bdaddr 00:02:72:D6:6A:3F 2012-07-19 13:24:48.099184 > HCI Event: Auth Complete (0x06) plen 3 status 0x13 handle 42 Error: Remote User Terminated Connection 2012-07-19 13:24:48.179182 > HCI Event: Disconn Complete (0x05) plen 4 status 0x00 handle 42 reason 0x13 Reason: Remote User Terminated Connection Signed-off-by: Szymon Janc Acked-by: Johan Hedberg Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_event.c | 7 ++++++- net/bluetooth/l2cap_core.c | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9cdcfd9f907..25edda03645 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1760,7 +1760,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (conn->type == ACL_LINK) { conn->state = BT_CONFIG; hci_conn_hold(conn); - conn->disc_timeout = HCI_DISCONN_TIMEOUT; + + if (!conn->out && !hci_conn_ssp_enabled(conn) && + !hci_find_link_key(hdev, &ev->bdaddr)) + conn->disc_timeout = HCI_PAIRING_TIMEOUT; + else + conn->disc_timeout = HCI_DISCONN_TIMEOUT; } else conn->state = BT_CONNECTED; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6f9c25b633a..9a86759a7e6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -893,6 +893,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) sk = chan->sk; hci_conn_hold(conn->hcon); + conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT; bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); From e5cd679ea475fd731686fa3c632c2d30b9d59a6d Mon Sep 17 00:00:00 2001 From: "bjschuma@gmail.com" Date: Wed, 8 Aug 2012 13:57:10 -0400 Subject: [PATCH 0769/2357] NFS: Alias the nfs module to nfs4 commit 425e776d93a7a5070b77d4f458a5bab0f924652c upstream. This allows distros to remove the line from their modprobe configuration. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- fs/nfs/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 4ac7fca7e4b..7b55f51137e 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -3146,4 +3146,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, return res; } +MODULE_ALIAS("nfs4"); + #endif /* CONFIG_NFS_V4 */ From ae2a5dd19bccd4fa52ee6bb78ad88b960d92c606 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 15 Aug 2012 12:55:22 +0200 Subject: [PATCH 0770/2357] audit: don't free_chunk() after fsnotify_add_mark() commit 0fe33aae0e94b4097dd433c9399e16e17d638cd8 upstream. Don't do free_chunk() after fsnotify_add_mark(). That one does a delayed unref via the destroy list and this results in use-after-free. Signed-off-by: Miklos Szeredi Acked-by: Eric Paris Signed-off-by: Greg Kroah-Hartman --- kernel/audit_tree.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 5bf0790497e..d52d247b07a 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -259,7 +259,7 @@ static void untag_chunk(struct node *p) fsnotify_duplicate_mark(&new->mark, entry); if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) { - free_chunk(new); + fsnotify_put_mark(&new->mark); goto Fallback; } @@ -322,7 +322,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree) entry = &chunk->mark; if (fsnotify_add_mark(entry, audit_tree_group, inode, NULL, 0)) { - free_chunk(chunk); + fsnotify_put_mark(entry); return -ENOSPC; } @@ -396,7 +396,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) fsnotify_duplicate_mark(chunk_entry, old_entry); if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, NULL, 1)) { spin_unlock(&old_entry->lock); - free_chunk(chunk); + fsnotify_put_mark(chunk_entry); fsnotify_put_mark(old_entry); return -ENOSPC; } From 47b8bbd6c2aab324fa57f004f89abb40bb8478be Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 15 Aug 2012 12:55:22 +0200 Subject: [PATCH 0771/2357] audit: fix refcounting in audit-tree commit a2140fc0cb0325bb6384e788edd27b9a568714e2 upstream. Refcounting of fsnotify_mark in audit tree is broken. E.g: refcount create_chunk alloc_chunk 1 fsnotify_add_mark 2 untag_chunk fsnotify_get_mark 3 fsnotify_destroy_mark audit_tree_freeing_mark 2 fsnotify_put_mark 1 fsnotify_put_mark 0 via destroy_list fsnotify_mark_destroy -1 This was reported by various people as triggering Oops when stopping auditd. We could just remove the put_mark from audit_tree_freeing_mark() but that would break freeing via inode destruction. So this patch simply omits a put_mark after calling destroy_mark or adds a get_mark before. The additional get_mark is necessary where there's no other put_mark after fsnotify_destroy_mark() since it assumes that the caller is holding a reference (or the inode is keeping the mark pinned, not the case here AFAICS). Signed-off-by: Miklos Szeredi Reported-by: Valentin Avram Reported-by: Peter Moody Acked-by: Eric Paris Signed-off-by: Greg Kroah-Hartman --- kernel/audit_tree.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index d52d247b07a..31fdc480b5c 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -250,7 +250,6 @@ static void untag_chunk(struct node *p) spin_unlock(&hash_lock); spin_unlock(&entry->lock); fsnotify_destroy_mark(entry); - fsnotify_put_mark(entry); goto out; } @@ -293,7 +292,6 @@ static void untag_chunk(struct node *p) spin_unlock(&hash_lock); spin_unlock(&entry->lock); fsnotify_destroy_mark(entry); - fsnotify_put_mark(entry); goto out; Fallback: @@ -332,6 +330,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree) spin_unlock(&hash_lock); chunk->dead = 1; spin_unlock(&entry->lock); + fsnotify_get_mark(entry); fsnotify_destroy_mark(entry); fsnotify_put_mark(entry); return 0; @@ -412,6 +411,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) spin_unlock(&chunk_entry->lock); spin_unlock(&old_entry->lock); + fsnotify_get_mark(chunk_entry); fsnotify_destroy_mark(chunk_entry); fsnotify_put_mark(chunk_entry); @@ -445,7 +445,6 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) spin_unlock(&old_entry->lock); fsnotify_destroy_mark(old_entry); fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ - fsnotify_put_mark(old_entry); /* and kill it */ return 0; } From e51f2ce36e978380402105199577cfb807a8ba16 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 20 Aug 2012 14:44:52 +0000 Subject: [PATCH 0772/2357] drm: stop vmgfx driver explosion commit f5869a8308f77e3dfdc2e3640842b285aa788ff8 upstream. If you do a page flip with no flags set then event is NULL. If event is NULL then the vmw_gfx driver likes to go digging into NULL and extracts NULL->base.file_priv. On a modern kernel with NULL mapping protection it's just another oops, without it there are some "intriguing" possibilities. What it should do is an open question but that for the driver owners to sort out. Signed-off-by: Alan Cox Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 2286d47e502..00fb5aa2bf7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1688,15 +1688,19 @@ int vmw_du_page_flip(struct drm_crtc *crtc, struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct drm_framebuffer *old_fb = crtc->fb; struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); - struct drm_file *file_priv = event->base.file_priv; + struct drm_file *file_priv ; struct vmw_fence_obj *fence = NULL; struct drm_clip_rect clips; int ret; + if (event == NULL) + return -EINVAL; + /* require ScreenObject support for page flipping */ if (!dev_priv->sou_priv) return -ENOSYS; + file_priv = event->base.file_priv; if (!vmw_kms_screen_object_flippable(dev_priv, crtc)) return -EINVAL; From cbd3df71bb6563fe9ab2a16dc57937c0b59c3976 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 21 Aug 2012 09:55:01 -0400 Subject: [PATCH 0773/2357] Revert "drm/radeon: fix bo creation retry path" commit 676bc2e1e4f9072f7a640d5b7c99ffdf9709a6e7 upstream. This reverts commit d1c7871ddb1f588b8eb35affd9ee1a3d5e11cd0c. ttm_bo_init() destroys the BO on failure. So this patch makes the retry path work with freed memory. This ends up causing kernel panics when this path is hit. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_object.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 80c6e8bad65..df6a4dbd93f 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -136,6 +136,7 @@ int radeon_bo_create(struct radeon_device *rdev, acc_size = ttm_bo_dma_acc_size(&rdev->mman.bdev, size, sizeof(struct radeon_bo)); +retry: bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL); if (bo == NULL) return -ENOMEM; @@ -149,8 +150,6 @@ int radeon_bo_create(struct radeon_device *rdev, bo->surface_reg = -1; INIT_LIST_HEAD(&bo->list); INIT_LIST_HEAD(&bo->va); - -retry: radeon_ttm_placement_from_domain(bo, domain); /* Kernel allocation are uninterruptible */ mutex_lock(&rdev->vram_mutex); From 389aec33837aeaf7e7e3cb31b6f1c6da6b009fb6 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 9 Aug 2012 18:12:28 -0400 Subject: [PATCH 0774/2357] svcrpc: fix BUG() in svc_tcp_clear_pages commit be1e44441a560c43c136a562d49a1c9623c91197 upstream. Examination of svc_tcp_clear_pages shows that it assumes sk_tcplen is consistent with sk_pages[] (in particular, sk_pages[n] can't be NULL if sk_tcplen would lead us to expect n pages of data). svc_tcp_restore_pages zeroes out sk_pages[] while leaving sk_tcplen. This is OK, since both functions are serialized by XPT_BUSY. However, that means the inconsistency must be repaired before dropping XPT_BUSY. Therefore we should be ensuring that svc_tcp_save_pages repairs the problem before exiting svc_tcp_recv_record on error. Symptoms were a BUG() in svc_tcp_clear_pages. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/svcsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 824d32fb312..f190ea96f11 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1137,9 +1137,9 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) if (len >= 0) svsk->sk_tcplen += len; if (len != want) { + svc_tcp_save_pages(svsk, rqstp); if (len < 0 && len != -EAGAIN) goto err_other; - svc_tcp_save_pages(svsk, rqstp); dprintk("svc: incomplete TCP record (%d of %d)\n", svsk->sk_tcplen, svsk->sk_reclen); goto err_noclose; From 973caa9ec69452d87f65e67019429be5265f2534 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 17 Aug 2012 17:31:53 -0400 Subject: [PATCH 0775/2357] svcrpc: fix svc_xprt_enqueue/svc_recv busy-looping commit d10f27a750312ed5638c876e4bd6aa83664cccd8 upstream. The rpc server tries to ensure that there will be room to send a reply before it receives a request. It does this by tracking, in xpt_reserved, an upper bound on the total size of the replies that is has already committed to for the socket. Currently it is adding in the estimate for a new reply *before* it checks whether there is space available. If it finds that there is not space, it then subtracts the estimate back out. This may lead the subsequent svc_xprt_enqueue to decide that there is space after all. The results is a svc_recv() that will repeatedly return -EAGAIN, causing server threads to loop without doing any actual work. Reported-by: Michael Tokarev Tested-by: Michael Tokarev Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/svc_xprt.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 4bda09d7e1a..9c9131bef48 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -316,7 +316,6 @@ static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) */ void svc_xprt_enqueue(struct svc_xprt *xprt) { - struct svc_serv *serv = xprt->xpt_server; struct svc_pool *pool; struct svc_rqst *rqstp; int cpu; @@ -362,8 +361,6 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) rqstp, rqstp->rq_xprt); rqstp->rq_xprt = xprt; svc_xprt_get(xprt); - rqstp->rq_reserved = serv->sv_max_mesg; - atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); pool->sp_stats.threads_woken++; wake_up(&rqstp->rq_wait); } else { @@ -643,8 +640,6 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) if (xprt) { rqstp->rq_xprt = xprt; svc_xprt_get(xprt); - rqstp->rq_reserved = serv->sv_max_mesg; - atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); /* As there is a shortage of threads and this request * had to be queued, don't allow the thread to wait so @@ -741,6 +736,8 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) else len = xprt->xpt_ops->xpo_recvfrom(rqstp); dprintk("svc: got len=%d\n", len); + rqstp->rq_reserved = serv->sv_max_mesg; + atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); } svc_xprt_received(xprt); From 234c04ccc3c86c1da2f4173fdafb805bb6160380 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 20 Aug 2012 16:04:40 -0400 Subject: [PATCH 0776/2357] svcrpc: sends on closed socket should stop immediately commit f06f00a24d76e168ecb38d352126fd203937b601 upstream. svc_tcp_sendto sets XPT_CLOSE if we fail to transmit the entire reply. However, the XPT_CLOSE won't be acted on immediately. Meanwhile other threads could send further replies before the socket is really shut down. This can manifest as data corruption: for example, if a truncated read reply is followed by another rpc reply, that second reply will look to the client like further read data. Symptoms were data corruption preceded by svc_tcp_sendto logging something like kernel: rpc-srv/tcp: nfsd: sent only 963696 when sending 1048708 bytes - shutting down socket Reported-by: Malahal Naineni Tested-by: Malahal Naineni Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/svc_xprt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 9c9131bef48..fd9b2889aa9 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -794,7 +794,8 @@ int svc_send(struct svc_rqst *rqstp) /* Grab mutex to serialize outgoing data. */ mutex_lock(&xprt->xpt_mutex); - if (test_bit(XPT_DEAD, &xprt->xpt_flags)) + if (test_bit(XPT_DEAD, &xprt->xpt_flags) + || test_bit(XPT_CLOSE, &xprt->xpt_flags)) len = -ENOTCONN; else len = xprt->xpt_ops->xpo_sendto(rqstp); From 8b340965ad3da83146684a9b68657374c5a8bfa4 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 21 Aug 2012 16:15:49 -0700 Subject: [PATCH 0777/2357] cciss: fix incorrect scsi status reporting commit b0cf0b118c90477d1a6811f2cd2307f6a5578362 upstream. Delete code which sets SCSI status incorrectly as it's already been set correctly above this incorrect code. The bug was introduced in 2009 by commit b0e15f6db111 ("cciss: fix typo that causes scsi status to be lost.") Signed-off-by: Stephen M. Cameron Reported-by: Roel van Meer Tested-by: Roel van Meer Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/block/cciss_scsi.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index acda773b372..38aa6dda6b8 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -763,16 +763,7 @@ static void complete_scsi_command(CommandList_struct *c, int timeout, { case CMD_TARGET_STATUS: /* Pass it up to the upper layers... */ - if( ei->ScsiStatus) - { -#if 0 - printk(KERN_WARNING "cciss: cmd %p " - "has SCSI Status = %x\n", - c, ei->ScsiStatus); -#endif - cmd->result |= (ei->ScsiStatus << 1); - } - else { /* scsi status is zero??? How??? */ + if (!ei->ScsiStatus) { /* Ordinarily, this case should never happen, but there is a bug in some released firmware revisions that allows it to happen From 4500d525ad74c4195cdaf270bcc1f96dd0fd95ed Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 20 Aug 2012 10:57:22 -0400 Subject: [PATCH 0778/2357] ACPI: export symbol acpi_get_table_with_size commit 4f81f986761a7663db7d24d24cd6ae68008f1fc2 upstream. We need it in the radeon drm module to fetch and verify the vbios image on UEFI systems. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpica/tbxface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index abcc6412c24..33214d77888 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -436,6 +436,7 @@ acpi_get_table_with_size(char *signature, return (AE_NOT_FOUND); } +ACPI_EXPORT_SYMBOL(acpi_get_table_with_size) acpi_status acpi_get_table(char *signature, From 459243191d5ba70a94d74b604b91bf82bb9f0772 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 10 Aug 2012 11:00:24 +0200 Subject: [PATCH 0779/2357] ath9k: fix decrypt_error initialization in ath_rx_tasklet() commit e1352fde5682ab1bdd2a9e5d75c22d1fe210ef77 upstream. ath_rx_tasklet() calls ath9k_rx_skb_preprocess() and ath9k_rx_skb_postprocess() in a loop over the received frames. The decrypt_error flag is initialized to false just outside ath_rx_tasklet() loop. ath9k_rx_accept(), called by ath9k_rx_skb_preprocess(), only sets decrypt_error to true and never to false. Then ath_rx_tasklet() calls ath9k_rx_skb_postprocess() and passes decrypt_error to it. So, after a decryption error, in ath9k_rx_skb_postprocess(), we can have a leftover value from another processed frame. In that case, the frame will not be marked with RX_FLAG_DECRYPTED even if it is decrypted correctly. When using CCMP encryption this issue can lead to connection stuck because of CCMP PN corruption and a waste of CPU time since mac80211 tries to decrypt an already deciphered frame with ieee80211_aes_ccm_decrypt. Fix the issue initializing decrypt_error flag at the begging of the ath_rx_tasklet() loop. Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a2f7ae81a41..90b8527154e 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1774,7 +1774,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) struct ieee80211_hw *hw = sc->hw; struct ieee80211_hdr *hdr; int retval; - bool decrypt_error = false; struct ath_rx_status rs; enum ath9k_rx_qtype qtype; bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); @@ -1796,6 +1795,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) tsf_lower = tsf & 0xffffffff; do { + bool decrypt_error = false; /* If handling rx interrupt and flush is in progress => exit */ if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) break; From 81d030df8597288a2fd12950aaf0842dbfa0b216 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 12 Aug 2012 23:26:07 +0200 Subject: [PATCH 0780/2357] PCI: EHCI: Fix crash during hibernation on ASUS computers commit 0b68c8e2c3afaf9807eb1ebe0ccfb3b809570aa4 upstream. Commit dbf0e4c (PCI: EHCI: fix crash during suspend on ASUS computers) added a workaround for an ASUS suspend issue related to USB EHCI and a bug in a number of ASUS BIOSes that attempt to shut down the EHCI controller during system suspend if its PCI command register doesn't contain 0 at that time. It turns out that the same workaround is necessary in the analogous hibernation code path, so add it. References: https://bugzilla.kernel.org/show_bug.cgi?id=45811 Reported-and-tested-by: Oleksij Rempel Signed-off-by: Rafael J. Wysocki Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 3cd3f452813..54fc9880e39 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -952,6 +952,13 @@ static int pci_pm_poweroff_noirq(struct device *dev) if (!pci_dev->state_saved && !pci_is_bridge(pci_dev)) pci_prepare_to_sleep(pci_dev); + /* + * The reason for doing this here is the same as for the analogous code + * in pci_pm_suspend_noirq(). + */ + if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI) + pci_write_config_word(pci_dev, PCI_COMMAND, 0); + return 0; } From 3465c32ced49e3c04b7e280843f1a93ec8de8aff Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Thu, 23 Aug 2012 12:17:36 +0200 Subject: [PATCH 0781/2357] block: replace __getblk_slow misfix by grow_dev_page fix commit 676ce6d5ca3098339c028d44fe0427d1566a4d2d upstream. Commit 91f68c89d8f3 ("block: fix infinite loop in __getblk_slow") is not good: a successful call to grow_buffers() cannot guarantee that the page won't be reclaimed before the immediate next call to __find_get_block(), which is why there was always a loop there. Yesterday I got "EXT4-fs error (device loop0): __ext4_get_inode_loc:3595: inode #19278: block 664: comm cc1: unable to read itable block" on console, which pointed to this commit. I've been trying to bisect for weeks, why kbuild-on-ext4-on-loop-on-tmpfs sometimes fails from a missing header file, under memory pressure on ppc G5. I've never seen this on x86, and I've never seen it on 3.5-rc7 itself, despite that commit being in there: bisection pointed to an irrelevant pinctrl merge, but hard to tell when failure takes between 18 minutes and 38 hours (but so far it's happened quicker on 3.6-rc2). (I've since found such __ext4_get_inode_loc errors in /var/log/messages from previous weeks: why the message never appeared on console until yesterday morning is a mystery for another day.) Revert 91f68c89d8f3, restoring __getblk_slow() to how it was (plus a checkpatch nitfix). Simplify the interface between grow_buffers() and grow_dev_page(), and avoid the infinite loop beyond end of device by instead checking init_page_buffers()'s end_block there (I presume that's more efficient than a repeated call to blkdev_max_block()), returning -ENXIO to __getblk_slow() in that case. And remove akpm's ten-year-old "__getblk() cannot fail ... weird" comment, but that is worrying: are all users of __getblk() really now prepared for a NULL bh beyond end of device, or will some oops?? Signed-off-by: Hugh Dickins Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- fs/buffer.c | 66 ++++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 0bc1bed6c4e..18669e92b67 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -914,7 +914,7 @@ link_dev_buffers(struct page *page, struct buffer_head *head) /* * Initialise the state of a blockdev page's buffers. */ -static void +static sector_t init_page_buffers(struct page *page, struct block_device *bdev, sector_t block, int size) { @@ -936,33 +936,41 @@ init_page_buffers(struct page *page, struct block_device *bdev, block++; bh = bh->b_this_page; } while (bh != head); + + /* + * Caller needs to validate requested block against end of device. + */ + return end_block; } /* * Create the page-cache page that contains the requested block. * - * This is user purely for blockdev mappings. + * This is used purely for blockdev mappings. */ -static struct page * +static int grow_dev_page(struct block_device *bdev, sector_t block, - pgoff_t index, int size) + pgoff_t index, int size, int sizebits) { struct inode *inode = bdev->bd_inode; struct page *page; struct buffer_head *bh; + sector_t end_block; + int ret = 0; /* Will call free_more_memory() */ page = find_or_create_page(inode->i_mapping, index, (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE); if (!page) - return NULL; + return ret; BUG_ON(!PageLocked(page)); if (page_has_buffers(page)) { bh = page_buffers(page); if (bh->b_size == size) { - init_page_buffers(page, bdev, block, size); - return page; + end_block = init_page_buffers(page, bdev, + index << sizebits, size); + goto done; } if (!try_to_free_buffers(page)) goto failed; @@ -982,14 +990,14 @@ grow_dev_page(struct block_device *bdev, sector_t block, */ spin_lock(&inode->i_mapping->private_lock); link_dev_buffers(page, bh); - init_page_buffers(page, bdev, block, size); + end_block = init_page_buffers(page, bdev, index << sizebits, size); spin_unlock(&inode->i_mapping->private_lock); - return page; - +done: + ret = (block < end_block) ? 1 : -ENXIO; failed: unlock_page(page); page_cache_release(page); - return NULL; + return ret; } /* @@ -999,7 +1007,6 @@ grow_dev_page(struct block_device *bdev, sector_t block, static int grow_buffers(struct block_device *bdev, sector_t block, int size) { - struct page *page; pgoff_t index; int sizebits; @@ -1023,22 +1030,14 @@ grow_buffers(struct block_device *bdev, sector_t block, int size) bdevname(bdev, b)); return -EIO; } - block = index << sizebits; + /* Create a page with the proper size buffers.. */ - page = grow_dev_page(bdev, block, index, size); - if (!page) - return 0; - unlock_page(page); - page_cache_release(page); - return 1; + return grow_dev_page(bdev, block, index, size, sizebits); } static struct buffer_head * __getblk_slow(struct block_device *bdev, sector_t block, int size) { - int ret; - struct buffer_head *bh; - /* Size must be multiple of hard sectorsize */ if (unlikely(size & (bdev_logical_block_size(bdev)-1) || (size < 512 || size > PAGE_SIZE))) { @@ -1051,21 +1050,20 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) return NULL; } -retry: - bh = __find_get_block(bdev, block, size); - if (bh) - return bh; + for (;;) { + struct buffer_head *bh; + int ret; - ret = grow_buffers(bdev, block, size); - if (ret == 0) { - free_more_memory(); - goto retry; - } else if (ret > 0) { bh = __find_get_block(bdev, block, size); if (bh) return bh; + + ret = grow_buffers(bdev, block, size); + if (ret < 0) + return NULL; + if (ret == 0) + free_more_memory(); } - return NULL; } /* @@ -1321,10 +1319,6 @@ EXPORT_SYMBOL(__find_get_block); * which corresponds to the passed block_device, block and size. The * returned buffer has its reference count incremented. * - * __getblk() cannot fail - it just keeps trying. If you pass it an - * illegal block number, __getblk() will happily return a buffer_head - * which represents the non-existent block. Very weird. - * * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers() * attempt is failing. FIXME, perhaps? */ From 0f342b96d471d48fb151ae9073e58e0510e0a58f Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Tue, 7 Aug 2012 05:00:13 +0200 Subject: [PATCH 0782/2357] sched,cgroup: Fix up task_groups list commit 35cf4e50b16331def6cfcbee11e49270b6db07f5 upstream. With multiple instances of task_groups, for_each_rt_rq() is a noop, no task groups having been added to the rt.c list instance. This renders __enable/disable_runtime() and print_rt_stats() noop, the user (non) visible effect being that rt task groups are missing in /proc/sched_debug. Signed-off-by: Mike Galbraith Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1344308413.6846.7.camel@marge.simpson.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/sched/core.c | 1 + kernel/sched/sched.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 817bf701883..f70b975c85a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7011,6 +7011,7 @@ int in_sched_functions(unsigned long addr) #ifdef CONFIG_CGROUP_SCHED struct task_group root_task_group; +LIST_HEAD(task_groups); #endif DECLARE_PER_CPU(cpumask_var_t, load_balance_tmpmask); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 116ced06ecc..d9637f4c43d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -80,7 +80,7 @@ extern struct mutex sched_domains_mutex; struct cfs_rq; struct rt_rq; -static LIST_HEAD(task_groups); +extern struct list_head task_groups; struct cfs_bandwidth { #ifdef CONFIG_CFS_BANDWIDTH From ebad30a797a5e5093d69e39bc046edab9452fe00 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 8 Aug 2012 11:27:15 +0200 Subject: [PATCH 0783/2357] sched: fix divide by zero at {thread_group,task}_times commit bea6832cc8c4a0a9a65dd17da6aaa657fe27bc3e upstream. On architectures where cputime_t is 64 bit type, is possible to trigger divide by zero on do_div(temp, (__force u32) total) line, if total is a non zero number but has lower 32 bit's zeroed. Removing casting is not a good solution since some do_div() implementations do cast to u32 internally. This problem can be triggered in practice on very long lived processes: PID: 2331 TASK: ffff880472814b00 CPU: 2 COMMAND: "oraagent.bin" #0 [ffff880472a51b70] machine_kexec at ffffffff8103214b #1 [ffff880472a51bd0] crash_kexec at ffffffff810b91c2 #2 [ffff880472a51ca0] oops_end at ffffffff814f0b00 #3 [ffff880472a51cd0] die at ffffffff8100f26b #4 [ffff880472a51d00] do_trap at ffffffff814f03f4 #5 [ffff880472a51d60] do_divide_error at ffffffff8100cfff #6 [ffff880472a51e00] divide_error at ffffffff8100be7b [exception RIP: thread_group_times+0x56] RIP: ffffffff81056a16 RSP: ffff880472a51eb8 RFLAGS: 00010046 RAX: bc3572c9fe12d194 RBX: ffff880874150800 RCX: 0000000110266fad RDX: 0000000000000000 RSI: ffff880472a51eb8 RDI: 001038ae7d9633dc RBP: ffff880472a51ef8 R8: 00000000b10a3a64 R9: ffff880874150800 R10: 00007fcba27ab680 R11: 0000000000000202 R12: ffff880472a51f08 R13: ffff880472a51f10 R14: 0000000000000000 R15: 0000000000000007 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffff880472a51f00] do_sys_times at ffffffff8108845d #8 [ffff880472a51f40] sys_times at ffffffff81088524 #9 [ffff880472a51f80] system_call_fastpath at ffffffff8100b0f2 RIP: 0000003808caac3a RSP: 00007fcba27ab6d8 RFLAGS: 00000202 RAX: 0000000000000064 RBX: ffffffff8100b0f2 RCX: 0000000000000000 RDX: 00007fcba27ab6e0 RSI: 000000000076d58e RDI: 00007fcba27ab6e0 RBP: 00007fcba27ab700 R8: 0000000000000020 R9: 000000000000091b R10: 00007fcba27ab680 R11: 0000000000000202 R12: 00007fff9ca41940 R13: 0000000000000000 R14: 00007fcba27ac9c0 R15: 00007fff9ca41940 ORIG_RAX: 0000000000000064 CS: 0033 SS: 002b Signed-off-by: Stanislaw Gruszka Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20120808092714.GA3580@redhat.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/sched/core.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f70b975c85a..ef6a8f2eeff 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3084,6 +3084,20 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st) # define nsecs_to_cputime(__nsecs) nsecs_to_jiffies(__nsecs) #endif +static cputime_t scale_utime(cputime_t utime, cputime_t rtime, cputime_t total) +{ + u64 temp = (__force u64) rtime; + + temp *= (__force u64) utime; + + if (sizeof(cputime_t) == 4) + temp = div_u64(temp, (__force u32) total); + else + temp = div64_u64(temp, (__force u64) total); + + return (__force cputime_t) temp; +} + void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st) { cputime_t rtime, utime = p->utime, total = utime + p->stime; @@ -3093,13 +3107,9 @@ void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st) */ rtime = nsecs_to_cputime(p->se.sum_exec_runtime); - if (total) { - u64 temp = (__force u64) rtime; - - temp *= (__force u64) utime; - do_div(temp, (__force u32) total); - utime = (__force cputime_t) temp; - } else + if (total) + utime = scale_utime(utime, rtime, total); + else utime = rtime; /* @@ -3126,13 +3136,9 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st) total = cputime.utime + cputime.stime; rtime = nsecs_to_cputime(cputime.sum_exec_runtime); - if (total) { - u64 temp = (__force u64) rtime; - - temp *= (__force u64) cputime.utime; - do_div(temp, (__force u32) total); - utime = (__force cputime_t) temp; - } else + if (total) + utime = scale_utime(cputime.utime, rtime, total); + else utime = rtime; sig->prev_utime = max(sig->prev_utime, utime); From 190d60406f1e111bd212e271076bdab9e104ebe6 Mon Sep 17 00:00:00 2001 From: Jayakrishnan Memana Date: Sun, 15 Jul 2012 10:54:03 -0300 Subject: [PATCH 0784/2357] uvcvideo: Reset the bytesused field when recycling an erroneous buffer commit 8a3f0ede2b3f5477122060af1a816c6bbf09fcd2 upstream. Buffers marked as erroneous are recycled immediately by the driver if the nodrop module parameter isn't set. The buffer payload size is reset to 0, but the buffer bytesused field isn't. This results in the buffer being immediately considered as complete, leading to an infinite loop in interrupt context. Fix the problem by resetting the bytesused field when recycling the buffer. Signed-off-by: Jayakrishnan Memana Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/uvc/uvc_queue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 8f54e24e3f3..4261bf23193 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -355,6 +355,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) { buf->error = 0; buf->state = UVC_BUF_STATE_QUEUED; + buf->bytesused = 0; vb2_set_plane_payload(&buf->buf, 0, 0); return buf; } From 8d30b9939e38e55035bad49f964ff6a3f671179e Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Tue, 21 Aug 2012 16:16:11 -0700 Subject: [PATCH 0785/2357] rapidio/tsi721: fix inbound doorbell interrupt handling commit 3670e7e12e582c6d67761275d148171feb7a9004 upstream. Make sure that there is no doorbell messages left behind due to disabled interrupts during inbound doorbell processing. The most common case for this bug is loss of rionet JOIN messages in systems with three or more rionet participants and MSI or MSI-X enabled. As result, requests for packet transfers may finish with "destination unreachable" error message. This patch is applicable to kernel versions starting from v3.2. Signed-off-by: Alexandre Bounine Cc: Matt Porter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rapidio/devices/tsi721.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index 30d2072f480..91e0f316b61 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c @@ -439,6 +439,9 @@ static void tsi721_db_dpc(struct work_struct *work) " info %4.4x\n", DBELL_SID(idb.bytes), DBELL_TID(idb.bytes), DBELL_INF(idb.bytes)); } + + wr_ptr = ioread32(priv->regs + + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE; } iowrite32(rd_ptr & (IDB_QSIZE - 1), @@ -449,6 +452,10 @@ static void tsi721_db_dpc(struct work_struct *work) regval |= TSI721_SR_CHINT_IDBQRCV; iowrite32(regval, priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); + + wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE; + if (wr_ptr != rd_ptr) + schedule_work(&priv->idb_work); } /** From 3ad3bc52af22aa08b703c57f494e6d7f9beabe7b Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Tue, 21 Aug 2012 16:16:12 -0700 Subject: [PATCH 0786/2357] rapidio/tsi721: fix unused variable compiler warning commit 9a9a9a7adafe62a34de8b4fb48936c1c5f9bafa5 upstream. Fix unused variable compiler warning when built with CONFIG_RAPIDIO_DEBUG option off. This patch is applicable to kernel versions starting from v3.2 Signed-off-by: Alexandre Bounine Cc: Matt Porter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rapidio/devices/tsi721.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index 91e0f316b61..33471e11a73 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c @@ -2162,7 +2162,7 @@ static int __devinit tsi721_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct tsi721_device *priv; - int i, cap; + int cap; int err; u32 regval; @@ -2182,12 +2182,15 @@ static int __devinit tsi721_probe(struct pci_dev *pdev, priv->pdev = pdev; #ifdef DEBUG + { + int i; for (i = 0; i <= PCI_STD_RESOURCE_END; i++) { dev_dbg(&pdev->dev, "res[%d] @ 0x%llx (0x%lx, 0x%lx)\n", i, (unsigned long long)pci_resource_start(pdev, i), (unsigned long)pci_resource_len(pdev, i), pci_resource_flags(pdev, i)); } + } #endif /* * Verify BAR configuration From 0522ba5d15022bca061c7c73c811eaed916bb369 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 15 Aug 2012 01:10:04 +0300 Subject: [PATCH 0787/2357] regulator: twl-regulator: fix up VINTANA1/VINTANA2 commit 908d6d52928a7f2a4b317aac47542c5fbef43d88 upstream. It seems commit 2098e95ce9bb039ff2e7bf836df358d18a176139 (regulator: twl: adapt twl-regulator driver to dt) accidentally deleted VINTANA1. Also the same commit defines VINTANA2 twice with TWL4030_ADJUSTABLE_LDO and TWL4030_FIXED_LDO. This patch changes the fixed one to be VINTANA1. I noticed this when auditing my N900 boot logs. I could not notice any change in device behaviour, though, except that the boot logs are now like before: ... [ 0.282928] VDAC: 1800 mV normal standby [ 0.284027] VCSI: 1800 mV normal standby [ 0.285400] VINTANA1: 1500 mV normal standby [ 0.286865] VINTANA2: 2750 mV normal standby [ 0.288208] VINTDIG: 1500 mV normal standby [ 0.289978] VSDI_CSI: 1800 mV normal standby ... Signed-off-by: Aaro Koskinen Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/regulator/twl-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 9cdfc389ca2..1eb7a151093 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -1085,7 +1085,7 @@ TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300); TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300); TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300); TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300); -TWL4030_FIXED_LDO(VINTANA2, 0x3f, 1500, 11, 100, 0x08); +TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08); TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08); TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08); TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08); @@ -1166,7 +1166,7 @@ static const struct of_device_id twl_of_match[] __devinitconst = { TWL6025_OF_MATCH("ti,twl6025-ldo6", LDO6), TWL6025_OF_MATCH("ti,twl6025-ldoln", LDOLN), TWL6025_OF_MATCH("ti,twl6025-ldousb", LDOUSB), - TWLFIXED_OF_MATCH("ti,twl4030-vintana2", VINTANA2), + TWLFIXED_OF_MATCH("ti,twl4030-vintana1", VINTANA1), TWLFIXED_OF_MATCH("ti,twl4030-vintdig", VINTDIG), TWLFIXED_OF_MATCH("ti,twl4030-vusb1v5", VUSB1V5), TWLFIXED_OF_MATCH("ti,twl4030-vusb1v8", VUSB1V8), From e9497730c0f0b2b15006a869a2d3ed6febce5f1b Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 18 Aug 2012 16:11:37 -0400 Subject: [PATCH 0788/2357] x32: Use compat shims for {g,s}etsockopt commit 515c7af85ed92696c311c53d53cb4898ff32d784 upstream. Some of the arguments to {g,s}etsockopt are passed in userland pointers. If we try to use the 64bit entry point, we end up sometimes failing. For example, dhcpcd doesn't run in x32: # dhcpcd eth0 dhcpcd[1979]: version 5.5.6 starting dhcpcd[1979]: eth0: broadcasting for a lease dhcpcd[1979]: eth0: open_socket: Invalid argument dhcpcd[1979]: eth0: send_raw_packet: Bad file descriptor The code in particular is getting back EINVAL when doing: struct sock_fprog pf; setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)); Diving into the kernel code, we can see: include/linux/filter.h: struct sock_fprog { unsigned short len; struct sock_filter __user *filter; }; net/core/sock.c: case SO_ATTACH_FILTER: ret = -EINVAL; if (optlen == sizeof(struct sock_fprog)) { struct sock_fprog fprog; ret = -EFAULT; if (copy_from_user(&fprog, optval, sizeof(fprog))) break; ret = sk_attach_filter(&fprog, sk); } break; arch/x86/syscalls/syscall_64.tbl: 54 common setsockopt sys_setsockopt 55 common getsockopt sys_getsockopt So for x64, sizeof(sock_fprog) is 16 bytes. For x86/x32, it's 8 bytes. This comes down to the pointer being 32bit for x32, which means we need to do structure size translation. But since x32 comes in directly to sys_setsockopt, it doesn't get translated like x86. After changing the syscall table and rebuilding glibc with the new kernel headers, dhcp runs fine in an x32 userland. Oddly, it seems like Linus noted the same thing during the initial port, but I guess that was missed/lost along the way: https://lkml.org/lkml/2011/8/26/452 [ hpa: tagging for -stable since this is an ABI fix. ] Bugzilla: https://bugs.gentoo.org/423649 Reported-by: Mads Signed-off-by: Mike Frysinger Link: http://lkml.kernel.org/r/1345320697-15713-1-git-send-email-vapier@gentoo.org Cc: H. J. Lu Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/syscalls/syscall_64.tbl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index dd29a9ea27c..fd1f1034813 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl @@ -60,8 +60,8 @@ 51 common getsockname sys_getsockname 52 common getpeername sys_getpeername 53 common socketpair sys_socketpair -54 common setsockopt sys_setsockopt -55 common getsockopt sys_getsockopt +54 64 setsockopt sys_setsockopt +55 64 getsockopt sys_getsockopt 56 common clone stub_clone 57 common fork stub_fork 58 common vfork stub_vfork @@ -351,3 +351,5 @@ 538 x32 sendmmsg compat_sys_sendmmsg 539 x32 process_vm_readv compat_sys_process_vm_readv 540 x32 process_vm_writev compat_sys_process_vm_writev +541 x32 setsockopt compat_sys_setsockopt +542 x32 getsockopt compat_sys_getsockopt From 3c8ac60ddf5f8efaa1b65466fa357954259e387d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Aug 2012 17:48:27 -0700 Subject: [PATCH 0789/2357] USB: spca506: remove __devinit* from the struct usb_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e694d518886c7afedcdd1732477832b2e32744e4 upstream. This structure needs to always stick around, even if CONFIG_HOTPLUG is disabled, otherwise we can oops when trying to probe a device that was added after the structure is thrown away. Thanks to Fengguang Wu and Bjørn Mork for tracking this issue down. Reported-by: Fengguang Wu Reported-by: Bjørn Mork CC: Hans de Goede CC: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/gspca/spca506.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index 54eed87672d..21e6a37bc7a 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c @@ -685,7 +685,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const struct usb_device_id device_table[] __devinitconst = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x06e1, 0xa190)}, /*fixme: may be IntelPCCameraPro BRIDGE_SPCA505 {USB_DEVICE(0x0733, 0x0430)}, */ From 3ecad65934b8d33eeab93f2230f6418642013d27 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Aug 2012 17:48:27 -0700 Subject: [PATCH 0790/2357] USB: jl2005bcd: remove __devinit* from the struct usb_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ec063351684298e295dc9444d143ddfd6ab02df8 upstream. This structure needs to always stick around, even if CONFIG_HOTPLUG is disabled, otherwise we can oops when trying to probe a device that was added after the structure is thrown away. Thanks to Fengguang Wu and Bjørn Mork for tracking this issue down. Reported-by: Fengguang Wu Reported-by: Bjørn Mork CC: Hans de Goede CC: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/gspca/jl2005bcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c index 53f58ef367c..3264d878cfd 100644 --- a/drivers/media/video/gspca/jl2005bcd.c +++ b/drivers/media/video/gspca/jl2005bcd.c @@ -510,7 +510,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0979, 0x0227)}, {} }; From 37037e1533d34db1256977fe2363142b8287780b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Aug 2012 17:48:28 -0700 Subject: [PATCH 0791/2357] USB: p54usb: remove __devinit* from the struct usb_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b9c4167cbbafddac3462134013bc15e63e4c53ef upstream. This structure needs to always stick around, even if CONFIG_HOTPLUG is disabled, otherwise we can oops when trying to probe a device that was added after the structure is thrown away. Thanks to Fengguang Wu and Bjørn Mork for tracking this issue down. Reported-by: Fengguang Wu Reported-by: Bjørn Mork CC: Christian Lamparter CC: "John W. Linville" Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/p54/p54usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index f4d28c39aac..a337a50d402 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -42,7 +42,7 @@ MODULE_FIRMWARE("isl3887usb"); * whenever you add a new device. */ -static struct usb_device_id p54u_table[] __devinitdata = { +static struct usb_device_id p54u_table[] = { /* Version 1 devices (pci chip + net2280) */ {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */ {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */ From 98ad260d991f75b38ac1fbce0a10b4a45799f97b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Aug 2012 17:48:29 -0700 Subject: [PATCH 0792/2357] USB: rtl8187: remove __devinit* from the struct usb_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a3433179d0822ccfa8e80aa4d1d52843bd2dcc63 upstream. This structure needs to always stick around, even if CONFIG_HOTPLUG is disabled, otherwise we can oops when trying to probe a device that was added after the structure is thrown away. Thanks to Fengguang Wu and Bjørn Mork for tracking this issue down. Reported-by: Fengguang Wu Reported-by: Bjørn Mork CC: Herton Ronaldo Krzesinski CC: Hin-Tak Leung CC: Larry Finger CC: "John W. Linville" Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtl818x/rtl8187/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index cf53ac9d6f2..86467a20c5b 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -44,7 +44,7 @@ MODULE_AUTHOR("Larry Finger "); MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); MODULE_LICENSE("GPL"); -static struct usb_device_id rtl8187_table[] __devinitdata = { +static struct usb_device_id rtl8187_table[] = { /* Asus */ {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, /* Belkin */ From 5750abb9208ee301f0ae9c6c6cb231460feddf0e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Aug 2012 17:48:26 -0700 Subject: [PATCH 0793/2357] USB: smsusb: remove __devinit* from the struct usb_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d04dbd1c0ec17a13326c8f2279399c225836a79f upstream. This structure needs to always stick around, even if CONFIG_HOTPLUG is disabled, otherwise we can oops when trying to probe a device that was added after the structure is thrown away. Thanks to Fengguang Wu and Bjørn Mork for tracking this issue down. Reported-by: Fengguang Wu Reported-by: Bjørn Mork CC: Mauro Carvalho Chehab CC: Michael Krufky CC: Paul Gortmaker CC: Doron Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb/siano/smsusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index 664e460f247..aac622200e9 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -481,7 +481,7 @@ static int smsusb_resume(struct usb_interface *intf) return 0; } -static const struct usb_device_id smsusb_id_table[] __devinitconst = { +static const struct usb_device_id smsusb_id_table[] = { { USB_DEVICE(0x187f, 0x0010), .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, { USB_DEVICE(0x187f, 0x0100), From a9959bb7e1510edb3326beb354e59da0a6a0dab1 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Fri, 17 Aug 2012 21:43:43 +0200 Subject: [PATCH 0794/2357] USB: CDC ACM: Fix NULL pointer dereference commit 99f347caa4568cb803862730b3b1f1942639523f upstream. If a device specifies zero endpoints in its interface descriptor, the kernel oopses in acm_probe(). Even though that's clearly an invalid descriptor, we should test wether we have all endpoints. This is especially bad as this oops can be triggered by just plugging a USB device in. Signed-off-by: Sven Schnelle Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 640cf7983b0..1b632cb88ac 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1104,7 +1104,8 @@ static int acm_probe(struct usb_interface *intf, } - if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) + if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 || + control_interface->cur_altsetting->desc.bNumEndpoints == 0) return -EINVAL; epctrl = &control_interface->cur_altsetting->endpoint[0].desc; From 652f43702b224351b790fd9182744d7946d4cdf6 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Sep 2012 16:47:56 +0000 Subject: [PATCH 0795/2357] powerpc: Update DSCR on all CPUs when writing sysfs dscr_default commit 1b6ca2a6fe56e7697d57348646e07df08f43b1bb upstream. Writing to dscr_default in sysfs doesn't actually change the DSCR - we rely on a context switch on each CPU to do the work. There is no guarantee we will get a context switch in a reasonable amount of time so fire off an IPI to force an immediate change. This issue was found with the following test case: http://ozlabs.org/~anton/junkcode/dscr_explicit_test.c Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/sysfs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 3529446c2ab..d4cbbd1fa75 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -194,6 +194,12 @@ static ssize_t show_dscr_default(struct device *dev, return sprintf(buf, "%lx\n", dscr_default); } +static void update_dscr(void *dummy) +{ + if (!current->thread.dscr_inherit) + mtspr(SPRN_DSCR, dscr_default); +} + static ssize_t __used store_dscr_default(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -206,6 +212,8 @@ static ssize_t __used store_dscr_default(struct device *dev, return -EINVAL; dscr_default = val; + on_each_cpu(update_dscr, NULL, 1); + return count; } From 59d0622a07571c6344f0e3c71e7a1a71eb8db9e9 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Sep 2012 16:48:46 +0000 Subject: [PATCH 0796/2357] powerpc: Keep thread.dscr and thread.dscr_inherit in sync commit 00ca0de02f80924dfff6b4f630e1dff3db005e35 upstream. When we update the DSCR either via emulation of mtspr(DSCR) or via a change to dscr_default in sysfs we don't update thread.dscr. We will eventually update it at context switch time but there is a period where thread.dscr is incorrect. If we fork at this point we will copy the old value of thread.dscr into the child. To avoid this, always keep thread.dscr in sync with reality. This issue was found with the following testcase: http://ozlabs.org/~anton/junkcode/dscr_inherit_test.c Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/sysfs.c | 4 +++- arch/powerpc/kernel/traps.c | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index d4cbbd1fa75..8302af64921 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -196,8 +196,10 @@ static ssize_t show_dscr_default(struct device *dev, static void update_dscr(void *dummy) { - if (!current->thread.dscr_inherit) + if (!current->thread.dscr_inherit) { + current->thread.dscr = dscr_default; mtspr(SPRN_DSCR, dscr_default); + } } static ssize_t __used store_dscr_default(struct device *dev, diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 158972341a2..ae0843fa7a6 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -972,8 +972,9 @@ static int emulate_instruction(struct pt_regs *regs) cpu_has_feature(CPU_FTR_DSCR)) { PPC_WARN_EMULATED(mtdscr, regs); rd = (instword >> 21) & 0x1f; - mtspr(SPRN_DSCR, regs->gpr[rd]); + current->thread.dscr = regs->gpr[rd]; current->thread.dscr_inherit = 1; + mtspr(SPRN_DSCR, current->thread.dscr); return 0; } #endif From c68ef2b5cb50b54e7be25f53186ebf20220c6476 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Sep 2012 16:49:47 +0000 Subject: [PATCH 0797/2357] powerpc: Fix DSCR inheritance in copy_thread() commit 1021cb268b3025573c4811f1dee4a11260c4507b upstream. If the default DSCR is non zero we set thread.dscr_inherit in copy_thread() meaning the new thread and all its children will ignore future updates to the default DSCR. This is not intended and is a change in behaviour that a number of our users have hit. We just need to inherit thread.dscr and thread.dscr_inherit from the parent which ends up being much simpler. This was found with the following test case: http://ozlabs.org/~anton/junkcode/dscr_default_test.c Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/process.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 4937c969009..94178e55f49 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -799,16 +799,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, #endif /* CONFIG_PPC_STD_MMU_64 */ #ifdef CONFIG_PPC64 if (cpu_has_feature(CPU_FTR_DSCR)) { - if (current->thread.dscr_inherit) { - p->thread.dscr_inherit = 1; - p->thread.dscr = current->thread.dscr; - } else if (0 != dscr_default) { - p->thread.dscr_inherit = 1; - p->thread.dscr = dscr_default; - } else { - p->thread.dscr_inherit = 0; - p->thread.dscr = 0; - } + p->thread.dscr_inherit = current->thread.dscr_inherit; + p->thread.dscr = current->thread.dscr; } #endif From fe83a638356c2a7ea4e429ea5ce627d5001757fe Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Sep 2012 16:51:10 +0000 Subject: [PATCH 0798/2357] powerpc: Restore correct DSCR in context switch commit 714332858bfd40dcf8f741498336d93875c23aa7 upstream. During a context switch we always restore the per thread DSCR value. If we aren't doing explicit DSCR management (ie thread.dscr_inherit == 0) and the default DSCR changed while the process has been sleeping we end up with the wrong value. Check thread.dscr_inherit and select the default DSCR or per thread DSCR as required. This was found with the following test case, when running with more threads than CPUs (ie forcing context switching): http://ozlabs.org/~anton/junkcode/dscr_default_test.c With the four patches applied I can run a combination of all test cases successfully at the same time: http://ozlabs.org/~anton/junkcode/dscr_default_test.c http://ozlabs.org/~anton/junkcode/dscr_explicit_test.c http://ozlabs.org/~anton/junkcode/dscr_inherit_test.c Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kernel/entry_64.S | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 34b8afe94a5..ec0b529c395 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -76,6 +76,7 @@ int main(void) DEFINE(SIGSEGV, SIGSEGV); DEFINE(NMI_MASK, NMI_MASK); DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr)); + DEFINE(THREAD_DSCR_INHERIT, offsetof(struct thread_struct, dscr_inherit)); #else DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index ef2074c3e90..e500969bea0 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -373,6 +373,12 @@ _GLOBAL(ret_from_fork) li r3,0 b syscall_exit + .section ".toc","aw" +DSCR_DEFAULT: + .tc dscr_default[TC],dscr_default + + .section ".text" + /* * This routine switches between two different tasks. The process * state of one is saved on its kernel stack. Then the state @@ -512,9 +518,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) mr r1,r8 /* start using new stack pointer */ std r7,PACAKSAVE(r13) - ld r6,_CCR(r1) - mtcrf 0xFF,r6 - #ifdef CONFIG_ALTIVEC BEGIN_FTR_SECTION ld r0,THREAD_VRSAVE(r4) @@ -523,14 +526,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_PPC64 BEGIN_FTR_SECTION + lwz r6,THREAD_DSCR_INHERIT(r4) + ld r7,DSCR_DEFAULT@toc(2) ld r0,THREAD_DSCR(r4) - cmpd r0,r25 - beq 1f + cmpwi r6,0 + bne 1f + ld r0,0(r7) +1: cmpd r0,r25 + beq 2f mtspr SPRN_DSCR,r0 -1: +2: END_FTR_SECTION_IFSET(CPU_FTR_DSCR) #endif + ld r6,_CCR(r1) + mtcrf 0xFF,r6 + /* r3-r13 are destroyed -- Cort */ REST_8GPRS(14, r1) REST_10GPRS(22, r1) From 242fa18ad8d4665c151bdd5c34ac34a8e701fff7 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 4 Sep 2012 18:33:08 +0000 Subject: [PATCH 0799/2357] powerpc: Make sure IPI handlers see data written by IPI senders commit 9fb1b36ca1234e64a5d1cc573175303395e3354d upstream. We have been observing hangs, both of KVM guest vcpu tasks and more generally, where a process that is woken doesn't properly wake up and continue to run, but instead sticks in TASK_WAKING state. This happens because the update of rq->wake_list in ttwu_queue_remote() is not ordered with the update of ipi_message in smp_muxed_ipi_message_pass(), and the reading of rq->wake_list in scheduler_ipi() is not ordered with the reading of ipi_message in smp_ipi_demux(). Thus it is possible for the IPI receiver not to see the updated rq->wake_list and therefore conclude that there is nothing for it to do. In order to make sure that anything done before smp_send_reschedule() is ordered before anything done in the resulting call to scheduler_ipi(), this adds barriers in smp_muxed_message_pass() and smp_ipi_demux(). The barrier in smp_muxed_message_pass() is a full barrier to ensure that there is a full ordering between the smp_send_reschedule() caller and scheduler_ipi(). In smp_ipi_demux(), we use xchg() rather than xchg_local() because xchg() includes release and acquire barriers. Using xchg() rather than xchg_local() makes sense given that ipi_message is not just accessed locally. This moves the barrier between setting the message and calling the cause_ipi() function into the individual cause_ipi implementations. Most of them -- those that used outb, out_8 or similar -- already had a full barrier because out_8 etc. include a sync before the MMIO store. This adds an explicit barrier in the two remaining cases. These changes made no measurable difference to the speed of IPIs as measured using a simple ping-pong latency test across two CPUs on different cores of a POWER7 machine. The analysis of the reason why processes were not waking up properly is due to Milton Miller. Reported-by: Milton Miller Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/dbell.c | 2 ++ arch/powerpc/kernel/smp.c | 11 +++++++++-- arch/powerpc/sysdev/xics/icp-hv.c | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 5b25c8060fd..a892680668d 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -28,6 +28,8 @@ void doorbell_setup_this_cpu(void) void doorbell_cause_ipi(int cpu, unsigned long data) { + /* Order previous accesses vs. msgsnd, which is treated as a store */ + mb(); ppc_msgsnd(PPC_DBELL, 0, data); } diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index d9f94410fd7..ab24aee19bc 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -215,8 +215,15 @@ void smp_muxed_ipi_message_pass(int cpu, int msg) struct cpu_messages *info = &per_cpu(ipi_message, cpu); char *message = (char *)&info->messages; + /* + * Order previous accesses before accesses in the IPI handler. + */ + smp_mb(); message[msg] = 1; - mb(); + /* + * cause_ipi functions are required to include a full barrier + * before doing whatever causes the IPI. + */ smp_ops->cause_ipi(cpu, info->data); } @@ -228,7 +235,7 @@ irqreturn_t smp_ipi_demux(void) mb(); /* order any irq clear */ do { - all = xchg_local(&info->messages, 0); + all = xchg(&info->messages, 0); #ifdef __BIG_ENDIAN if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION))) diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c index 253dce98c16..762c5ca3760 100644 --- a/arch/powerpc/sysdev/xics/icp-hv.c +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -65,7 +65,11 @@ static inline void icp_hv_set_xirr(unsigned int value) static inline void icp_hv_set_qirr(int n_cpu , u8 value) { int hw_cpu = get_hard_smp_processor_id(n_cpu); - long rc = plpar_hcall_norets(H_IPI, hw_cpu, value); + long rc; + + /* Make sure all previous accesses are ordered before IPI sending */ + mb(); + rc = plpar_hcall_norets(H_IPI, hw_cpu, value); if (rc != H_SUCCESS) { pr_err("%s: bad return code qirr cpu=%d hw_cpu=%d mfrr=0x%x " "returned %ld\n", __func__, n_cpu, hw_cpu, value, rc); From 05d71a5a25da396f76ee942af6682dfaecc73e84 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 6 Sep 2012 12:01:00 -0400 Subject: [PATCH 0800/2357] Remove user-triggerable BUG from mpol_to_str commit 80de7c3138ee9fd86a98696fd2cf7ad89b995d0a upstream. Trivially triggerable, found by trinity: kernel BUG at mm/mempolicy.c:2546! Process trinity-child2 (pid: 23988, threadinfo ffff88010197e000, task ffff88007821a670) Call Trace: show_numa_map+0xd5/0x450 show_pid_numa_map+0x13/0x20 traverse+0xf2/0x230 seq_read+0x34b/0x3e0 vfs_read+0xac/0x180 sys_pread64+0xa2/0xc0 system_call_fastpath+0x1a/0x1f RIP: mpol_to_str+0x156/0x360 Signed-off-by: Dave Jones Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index bf5b485ecd3..9afcbad632e 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2536,7 +2536,7 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context) break; default: - BUG(); + return -EINVAL; } l = strlen(policy_modes[mode]); From 43da476d7f734a1b55680668246d0237dde4ea57 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sat, 1 Sep 2012 12:34:07 -0400 Subject: [PATCH 0801/2357] Fix order of arguments to compat_put_time[spec|val] commit ed6fe9d614fc1bca95eb8c0ccd0e92db00ef9d5d upstream. Commit 644595f89620 ("compat: Handle COMPAT_USE_64BIT_TIME in net/socket.c") introduced a bug where the helper functions to take either a 64-bit or compat time[spec|val] got the arguments in the wrong order, passing the kernel stack pointer off as a user pointer (and vice versa). Because of the user address range check, that in turn then causes an EFAULT due to the user pointer range checking failing for the kernel address. Incorrectly resuling in a failed system call for 32-bit processes with a 64-bit kernel. On odder architectures like HP-PA (with separate user/kernel address spaces), it can be used read kernel memory. Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- net/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/socket.c b/net/socket.c index 573b26152a3..06ffa0f2839 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2605,7 +2605,7 @@ static int do_siocgstamp(struct net *net, struct socket *sock, err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); set_fs(old_fs); if (!err) - err = compat_put_timeval(up, &ktv); + err = compat_put_timeval(&ktv, up); return err; } @@ -2621,7 +2621,7 @@ static int do_siocgstampns(struct net *net, struct socket *sock, err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); set_fs(old_fs); if (!err) - err = compat_put_timespec(up, &kts); + err = compat_put_timespec(&kts, up); return err; } From dc0c0a9fc1f7ce1051f144c749f75921085fc869 Mon Sep 17 00:00:00 2001 From: Kashyap Desai Date: Tue, 17 Jul 2012 18:20:44 -0700 Subject: [PATCH 0802/2357] SCSI: megaraid_sas: Move poll_aen_lock initializer commit bd8d6dd43a77bfd2b8fef5b094b9d6095e169dee upstream. The following patch moves the poll_aen_lock initializer from megasas_probe_one() to megasas_init(). This prevents a crash when a user loads the driver and tries to issue a poll() system call on the ioctl interface with no adapters present. Signed-off-by: Kashyap Desai Signed-off-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/megaraid/megaraid_sas_base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 8b300be4428..6308a8ddf6f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4066,7 +4066,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&instance->cmd_pool_lock); spin_lock_init(&instance->hba_lock); spin_lock_init(&instance->completion_lock); - spin_lock_init(&poll_aen_lock); mutex_init(&instance->aen_mutex); mutex_init(&instance->reset_mutex); @@ -5392,6 +5391,8 @@ static int __init megasas_init(void) printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION, MEGASAS_EXT_VERSION); + spin_lock_init(&poll_aen_lock); + support_poll_for_event = 2; support_device_change = 1; From 797efad403c63c9a94a8f78e06ccb3aa5b4980a9 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 31 May 2012 15:05:33 -0400 Subject: [PATCH 0803/2357] SCSI: scsi_lib: fix scsi_io_completion's SG_IO error propagation commit 27c419739b67decced4650440829b8d51bef954b upstream. The following v3.4-rc1 commit unmasked an existing bug in scsi_io_completion's SG_IO error handling: 47ac56d [SCSI] scsi_error: classify some ILLEGAL_REQUEST sense as a permanent TARGET_ERROR Given that certain ILLEGAL_REQUEST are now properly categorized as TARGET_ERROR the host_byte is being set (before host_byte wasn't ever set for these ILLEGAL_REQUEST). In scsi_io_completion, initialize req->errors with cmd->result _after_ the SG_IO block that calls __scsi_error_from_host_byte (which may modify the host_byte). Before this fix: cdb to send: 12 01 01 00 00 00 ioctl(3, SG_IO, {'S', SG_DXFER_NONE, cmd[6]=[12, 01, 01, 00, 00, 00], mx_sb_len=32, iovec_count=0, dxfer_len=0, timeout=20000, flags=0, status=02, masked_status=01, sb[19]=[70, 00, 05, 00, 00, 00, 00, 0b, 00, 00, 00, 00, 24, 00, 00, 00, 00, 00, 00], host_status=0x10, driver_status=0x8, resid=0, duration=0, info=0x1}) = 0 SCSI Status: Check Condition Sense Information: sense buffer empty After: cdb to send: 12 01 01 00 00 00 ioctl(3, SG_IO, {'S', SG_DXFER_NONE, cmd[6]=[12, 01, 01, 00, 00, 00], mx_sb_len=32, iovec_count=0, dxfer_len=0, timeout=20000, flags=0, status=02, masked_status=01, sb[19]=[70, 00, 05, 00, 00, 00, 00, 0b, 00, 00, 00, 00, 24, 00, 00, 00, 00, 00, 00], host_status=0, driver_status=0x8, resid=0, duration=0, info=0x1}) = 0 SCSI Status: Check Condition Sense Information: Fixed format, current; Sense key: Illegal Request Additional sense: Invalid field in cdb Raw sense data (in hex): 70 00 05 00 00 00 00 0b 00 00 00 00 24 00 00 00 00 00 00 Reported-by: Paolo Bonzini Tested-by: Paolo Bonzini Signed-off-by: Mike Snitzer Reviewed-by: Babu Moger Signed-off-by: Greg Kroah-Hartman Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 19291463c55..2bc036292d9 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -760,7 +760,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* SG_IO ioctl from block level */ - req->errors = result; if (result) { if (sense_valid && req->sense) { /* @@ -776,6 +775,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) if (!sense_deferred) error = __scsi_error_from_host_byte(cmd, result); } + /* + * __scsi_error_from_host_byte may have reset the host_byte + */ + req->errors = cmd->result; req->resid_len = scsi_get_resid(cmd); From 7a4601c0bfde4ed50c54f30c32c5677e3daec4f9 Mon Sep 17 00:00:00 2001 From: "sreekanth.reddy@lsi.com" Date: Tue, 17 Jul 2012 15:57:05 +0530 Subject: [PATCH 0804/2357] SCSI: mpt2sas: Fix for Driver oops, when loading driver with max_queue_depth command line option to a very small value commit 338b131a3269881c7431234855c93c219b0979b6 upstream. If the specified max_queue_depth setting is less than the expected number of internal commands, then driver will calculate the queue depth size to a negitive number. This negitive number is actually a very large number because variable is unsigned 16bit integer. So, the driver will ask for a very large amount of memory for message frames and resulting into oops as memory allocation routines will not able to handle such a large request. So, in order to limit this kind of oops, The driver need to set the max_queue_depth to a scsi mid layer's can_queue value. Then the overall message frames required for IO is minimum of either (max_queue_depth plus internal commands) or the IOC global credits. Signed-off-by: Sreekanth Reddy Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt2sas/mpt2sas_base.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 3f03342b303..c4cef569540 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -2417,10 +2417,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) } /* command line tunables for max controller queue depth */ - if (max_queue_depth != -1) - max_request_credit = (max_queue_depth < facts->RequestCredit) - ? max_queue_depth : facts->RequestCredit; - else + if (max_queue_depth != -1 && max_queue_depth != 0) { + max_request_credit = min_t(u16, max_queue_depth + + ioc->hi_priority_depth + ioc->internal_depth, + facts->RequestCredit); + if (max_request_credit > MAX_HBA_QUEUE_DEPTH) + max_request_credit = MAX_HBA_QUEUE_DEPTH; + } else max_request_credit = min_t(u16, facts->RequestCredit, MAX_HBA_QUEUE_DEPTH); @@ -2495,7 +2498,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) /* set the scsi host can_queue depth * with some internal commands that could be outstanding */ - ioc->shost->can_queue = ioc->scsiio_depth - (2); + ioc->shost->can_queue = ioc->scsiio_depth; dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: " "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue)); From d3ed1731ba6bca32ac0ac96377cae8fd735e16e6 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 25 Jul 2012 23:55:55 +0400 Subject: [PATCH 0805/2357] SCSI: Fix 'Device not ready' issue on mpt2sas commit 14216561e164671ce147458653b1fea06a4ada1e upstream. This is a particularly nasty SCSI ATA Translation Layer (SATL) problem. SAT-2 says (section 8.12.2) if the device is in the stopped state as the result of processing a START STOP UNIT command (see 9.11), then the SATL shall terminate the TEST UNIT READY command with CHECK CONDITION status with the sense key set to NOT READY and the additional sense code of LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED; mpt2sas internal SATL seems to implement this. The result is very confusing standby behaviour (using hdparm -y). If you suspend a drive and then send another command, usually it wakes up. However, if the next command is a TEST UNIT READY, the SATL sees that the drive is suspended and proceeds to follow the SATL rules for this, returning NOT READY to all subsequent commands. This means that the ordering of TEST UNIT READY is crucial: if you send TUR and then a command, you get a NOT READY to both back. If you send a command and then a TUR, you get GOOD status because the preceeding command woke the drive. This bit us badly because commit 85ef06d1d252f6a2e73b678591ab71caad4667bb Author: Tejun Heo Date: Fri Jul 1 16:17:47 2011 +0200 block: flush MEDIA_CHANGE from drivers on close(2) Changed our ordering on TEST UNIT READY commands meaning that SATA drives connected to an mpt2sas now suspend and refuse to wake (because the mpt2sas SATL sees the suspend *before* the drives get awoken by the next ATA command) resulting in lots of failed commands. The standard is completely nuts forcing this inconsistent behaviour, but we have to work around it. The fix for this is twofold: 1. Set the allow_restart flag so we wake the drive when we see it has been suspended 2. Return all TEST UNIT READY status directly to the mid layer without any further error handling which prevents us causing error handling which may offline the device just because of a media check TUR. Reported-by: Matthias Prager Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_error.c | 10 ++++++++++ drivers/scsi/scsi_scan.c | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index cc8dc8cc6d6..b3f0b0f6d44 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -42,6 +42,8 @@ #include +static void scsi_eh_done(struct scsi_cmnd *scmd); + #define SENSE_TIMEOUT (10*HZ) /* @@ -241,6 +243,14 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) if (! scsi_command_normalize_sense(scmd, &sshdr)) return FAILED; /* no valid sense data */ + if (scmd->cmnd[0] == TEST_UNIT_READY && scmd->scsi_done != scsi_eh_done) + /* + * nasty: for mid-layer issued TURs, we need to return the + * actual sense data without any recovery attempt. For eh + * issued ones, we need to try to recover and interpret + */ + return SUCCESS; + if (scsi_sense_is_deferred(&sshdr)) return NEEDS_RETRY; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 8906557d2a2..348840e8092 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -776,6 +776,16 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, sdev->model = (char *) (sdev->inquiry + 16); sdev->rev = (char *) (sdev->inquiry + 32); + if (strncmp(sdev->vendor, "ATA ", 8) == 0) { + /* + * sata emulation layer device. This is a hack to work around + * the SATL power management specifications which state that + * when the SATL detects the device has gone into standby + * mode, it shall respond with NOT READY. + */ + sdev->allow_restart = 1; + } + if (*bflags & BLIST_ISROM) { sdev->type = TYPE_ROM; sdev->removable = 1; From d027dffcc66f749ee34c74edbd77efaaea573e4d Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 5 Sep 2012 15:48:23 +0200 Subject: [PATCH 0806/2357] udf: Fix data corruption for files in ICB commit 9c2fc0de1a6e638fe58c354a463f544f42a90a09 upstream. When a file is stored in ICB (inode), we overwrite part of the file, and the page containing file's data is not in page cache, we end up corrupting file's data by overwriting them with zeros. The problem is we use simple_write_begin() which simply zeroes parts of the page which are not written to. The problem has been introduced by be021ee4 (udf: convert to new aops). Fix the problem by providing a ->write_begin function which makes the page properly uptodate. Reported-by: Ian Abbott Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/file.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/fs/udf/file.c b/fs/udf/file.c index 7f3f7ba3df6..d1c6093fd3d 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -39,20 +39,24 @@ #include "udf_i.h" #include "udf_sb.h" -static int udf_adinicb_readpage(struct file *file, struct page *page) +static void __udf_adinicb_readpage(struct page *page) { struct inode *inode = page->mapping->host; char *kaddr; struct udf_inode_info *iinfo = UDF_I(inode); - BUG_ON(!PageLocked(page)); - kaddr = kmap(page); - memset(kaddr, 0, PAGE_CACHE_SIZE); memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size); + memset(kaddr + inode->i_size, 0, PAGE_CACHE_SIZE - inode->i_size); flush_dcache_page(page); SetPageUptodate(page); kunmap(page); +} + +static int udf_adinicb_readpage(struct file *file, struct page *page) +{ + BUG_ON(!PageLocked(page)); + __udf_adinicb_readpage(page); unlock_page(page); return 0; @@ -77,6 +81,25 @@ static int udf_adinicb_writepage(struct page *page, return 0; } +static int udf_adinicb_write_begin(struct file *file, + struct address_space *mapping, loff_t pos, + unsigned len, unsigned flags, struct page **pagep, + void **fsdata) +{ + struct page *page; + + if (WARN_ON_ONCE(pos >= PAGE_CACHE_SIZE)) + return -EIO; + page = grab_cache_page_write_begin(mapping, 0, flags); + if (!page) + return -ENOMEM; + *pagep = page; + + if (!PageUptodate(page) && len != PAGE_CACHE_SIZE) + __udf_adinicb_readpage(page); + return 0; +} + static int udf_adinicb_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, @@ -98,8 +121,8 @@ static int udf_adinicb_write_end(struct file *file, const struct address_space_operations udf_adinicb_aops = { .readpage = udf_adinicb_readpage, .writepage = udf_adinicb_writepage, - .write_begin = simple_write_begin, - .write_end = udf_adinicb_write_end, + .write_begin = udf_adinicb_write_begin, + .write_end = udf_adinicb_write_end, }; static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, From 6cbe67f990c723facaeed94e29a1d854dc5930ec Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 3 Sep 2012 16:50:42 +0200 Subject: [PATCH 0807/2357] ext3: Fix fdatasync() for files with only i_size changes commit 156bddd8e505b295540f3ca0e27dda68cb0d49aa upstream. Code tracking when transaction needs to be committed on fdatasync(2) forgets to handle a situation when only inode's i_size is changed. Thus in such situations fdatasync(2) doesn't force transaction with new i_size to disk and that can result in wrong i_size after a crash. Fix the issue by updating inode's i_datasync_tid whenever its size is updated. Reported-by: Kristian Nielsen Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/ext3/inode.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 10d7812f602..075281734fc 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -3068,6 +3068,8 @@ static int ext3_do_update_inode(handle_t *handle, struct ext3_inode_info *ei = EXT3_I(inode); struct buffer_head *bh = iloc->bh; int err = 0, rc, block; + int need_datasync = 0; + __le32 disksize; again: /* we can't allow multiple procs in here at once, its a bit racey */ @@ -3105,7 +3107,11 @@ static int ext3_do_update_inode(handle_t *handle, raw_inode->i_gid_high = 0; } raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); - raw_inode->i_size = cpu_to_le32(ei->i_disksize); + disksize = cpu_to_le32(ei->i_disksize); + if (disksize != raw_inode->i_size) { + need_datasync = 1; + raw_inode->i_size = disksize; + } raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); @@ -3121,8 +3127,11 @@ static int ext3_do_update_inode(handle_t *handle, if (!S_ISREG(inode->i_mode)) { raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl); } else { - raw_inode->i_size_high = - cpu_to_le32(ei->i_disksize >> 32); + disksize = cpu_to_le32(ei->i_disksize >> 32); + if (disksize != raw_inode->i_size_high) { + raw_inode->i_size_high = disksize; + need_datasync = 1; + } if (ei->i_disksize > 0x7fffffffULL) { struct super_block *sb = inode->i_sb; if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, @@ -3175,6 +3184,8 @@ static int ext3_do_update_inode(handle_t *handle, ext3_clear_inode_state(inode, EXT3_STATE_NEW); atomic_set(&ei->i_sync_tid, handle->h_transaction->t_tid); + if (need_datasync) + atomic_set(&ei->i_datasync_tid, handle->h_transaction->t_tid); out_brelse: brelse (bh); ext3_std_error(inode->i_sb, err); From b4b55ff702c3551ba39ccec0b1dda9e3b57429be Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 4 Sep 2012 18:45:54 +0200 Subject: [PATCH 0808/2357] fuse: fix retrieve length commit c9e67d483776d8d2a5f3f70491161b205930ffe1 upstream. In some cases fuse_retrieve() would return a short byte count if offset was non-zero. The data returned was correct, though. Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 7df2b5e8fbe..f4246cfc8d8 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1576,6 +1576,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, req->pages[req->num_pages] = page; req->num_pages++; + offset = 0; num -= this_num; total_len += this_num; index++; From f313f5b440c874dbee75922e30736b9069f0a1d1 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 10 Sep 2012 10:14:02 +0200 Subject: [PATCH 0809/2357] i2c-designware: Fix build error if CONFIG_I2C_DESIGNWARE_PLATFORM=y && CONFIG_I2C_DESIGNWARE_PCI=y commit e68bb91baa0bb9817567bd45d560919e8e26373b upstream. This patch adds config I2C_DESIGNWARE_CORE in Kconfig, and let I2C_DESIGNWARE_PLATFORM and I2C_DESIGNWARE_PCI select I2C_DESIGNWARE_CORE. Because both I2C_DESIGNWARE_PLATFORM and I2C_DESIGNWARE_PCI can be built as built-in or module, we also need to export the functions in i2c-designware-core. This fixes below build error when CONFIG_I2C_DESIGNWARE_PLATFORM=y && CONFIG_I2C_DESIGNWARE_PCI=y: LD drivers/i2c/busses/built-in.o drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_clear_int': i2c-designware-core.c:(.text+0xa10): multiple definition of `i2c_dw_clear_int' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x928): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_init': i2c-designware-core.c:(.text+0x178): multiple definition of `i2c_dw_init' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x90): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `dw_readl': i2c-designware-core.c:(.text+0xe8): multiple definition of `dw_readl' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x0): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_isr': i2c-designware-core.c:(.text+0x724): multiple definition of `i2c_dw_isr' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x63c): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_xfer': i2c-designware-core.c:(.text+0x4b0): multiple definition of `i2c_dw_xfer' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x3c8): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_is_enabled': i2c-designware-core.c:(.text+0x9d4): multiple definition of `i2c_dw_is_enabled' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x8ec): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `dw_writel': i2c-designware-core.c:(.text+0x124): multiple definition of `dw_writel' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x3c): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_xfer_msg': i2c-designware-core.c:(.text+0x2e8): multiple definition of `i2c_dw_xfer_msg' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x200): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_enable': i2c-designware-core.c:(.text+0x9c8): multiple definition of `i2c_dw_enable' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x8e0): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_read_comp_param': i2c-designware-core.c:(.text+0xa24): multiple definition of `i2c_dw_read_comp_param' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x93c): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_disable': i2c-designware-core.c:(.text+0x9dc): multiple definition of `i2c_dw_disable' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x8f4): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_func': i2c-designware-core.c:(.text+0x710): multiple definition of `i2c_dw_func' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x628): first defined here drivers/i2c/busses/i2c-designware-pci.o: In function `i2c_dw_disable_int': i2c-designware-core.c:(.text+0xa18): multiple definition of `i2c_dw_disable_int' drivers/i2c/busses/i2c-designware-platform.o:i2c-designware-platdrv.c:(.text+0x930): first defined here make[3]: *** [drivers/i2c/busses/built-in.o] Error 1 make[2]: *** [drivers/i2c/busses] Error 2 make[1]: *** [drivers/i2c] Error 2 make: *** [drivers] Error 2 Signed-off-by: Axel Lin Signed-off-by: Jean Delvare Tested-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/Kconfig | 5 +++++ drivers/i2c/busses/Makefile | 5 +++-- drivers/i2c/busses/i2c-designware-core.c | 11 +++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d2c5095deea..489a2a7bf2f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -350,9 +350,13 @@ config I2C_DAVINCI devices such as DaVinci NIC. For details please see http://www.ti.com/davinci +config I2C_DESIGNWARE_CORE + tristate + config I2C_DESIGNWARE_PLATFORM tristate "Synopsys DesignWare Platfrom" depends on HAVE_CLK + select I2C_DESIGNWARE_CORE help If you say yes to this option, support will be included for the Synopsys DesignWare I2C adapter. Only master mode is supported. @@ -363,6 +367,7 @@ config I2C_DESIGNWARE_PLATFORM config I2C_DESIGNWARE_PCI tristate "Synopsys DesignWare PCI" depends on PCI + select I2C_DESIGNWARE_CORE help If you say yes to this option, support will be included for the Synopsys DesignWare I2C adapter. Only master mode is supported. diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 569567b0d02..2f05d7b6c41 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -33,10 +33,11 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o +obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o -i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o +i2c-designware-platform-objs := i2c-designware-platdrv.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o -i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o +i2c-designware-pci-objs := i2c-designware-pcidrv.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index df879924100..619334994df 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -25,6 +25,7 @@ * ---------------------------------------------------------------------------- * */ +#include #include #include #include @@ -305,6 +306,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) dw_writel(dev, dev->master_cfg , DW_IC_CON); return 0; } +EXPORT_SYMBOL_GPL(i2c_dw_init); /* * Waiting for bus not busy @@ -557,12 +559,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) return ret; } +EXPORT_SYMBOL_GPL(i2c_dw_xfer); u32 i2c_dw_func(struct i2c_adapter *adap) { struct dw_i2c_dev *dev = i2c_get_adapdata(adap); return dev->functionality; } +EXPORT_SYMBOL_GPL(i2c_dw_func); static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) { @@ -667,17 +671,20 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(i2c_dw_isr); void i2c_dw_enable(struct dw_i2c_dev *dev) { /* Enable the adapter */ dw_writel(dev, 1, DW_IC_ENABLE); } +EXPORT_SYMBOL_GPL(i2c_dw_enable); u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev) { return dw_readl(dev, DW_IC_ENABLE); } +EXPORT_SYMBOL_GPL(i2c_dw_is_enabled); void i2c_dw_disable(struct dw_i2c_dev *dev) { @@ -688,18 +695,22 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) dw_writel(dev, 0, DW_IC_INTR_MASK); dw_readl(dev, DW_IC_CLR_INTR); } +EXPORT_SYMBOL_GPL(i2c_dw_disable); void i2c_dw_clear_int(struct dw_i2c_dev *dev) { dw_readl(dev, DW_IC_CLR_INTR); } +EXPORT_SYMBOL_GPL(i2c_dw_clear_int); void i2c_dw_disable_int(struct dw_i2c_dev *dev) { dw_writel(dev, 0, DW_IC_INTR_MASK); } +EXPORT_SYMBOL_GPL(i2c_dw_disable_int); u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev) { return dw_readl(dev, DW_IC_COMP_PARAM_1); } +EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); From 7db3f56f37640c88387dfda6fad1e930d589d0e3 Mon Sep 17 00:00:00 2001 From: James Ralston Date: Mon, 10 Sep 2012 10:14:02 +0200 Subject: [PATCH 0810/2357] i2c-i801: Add Device IDs for Intel Lynx Point-LP PCH commit 4a8f1ddde942e232387e6129ce4f4c412e43802f upstream. Add the SMBus Device IDs for the Intel Lynx Point-LP PCH. Signed-off-by: James Ralston Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/i2c/busses/i2c-i801 | 1 + drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 71f55bbcefc..99d4e442b77 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -21,6 +21,7 @@ Supported adapters: * Intel DH89xxCC (PCH) * Intel Panther Point (PCH) * Intel Lynx Point (PCH) + * Intel Lynx Point-LP (PCH) Datasheets: Publicly available at the Intel website On Intel Patsburg and later chipsets, both the normal host SMBus controller diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 489a2a7bf2f..ea8736bc257 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -104,6 +104,7 @@ config I2C_I801 DH89xxCC (PCH) Panther Point (PCH) Lynx Point (PCH) + Lynx Point-LP (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ae2945a5e00..d88ec812160 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -52,6 +52,7 @@ DH89xxCC (PCH) 0x2330 32 hard yes yes yes Panther Point (PCH) 0x1e22 32 hard yes yes yes Lynx Point (PCH) 0x8c22 32 hard yes yes yes + Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -147,6 +148,7 @@ #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 struct i801_priv { struct i2c_adapter adapter; @@ -636,6 +638,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, { 0, } }; From 7d60f877b38866c5b46162256207891c45057b39 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 23 Aug 2012 10:51:55 -0400 Subject: [PATCH 0811/2357] HID: add NOGET quirk for Eaton Ellipse MAX UPS commit 67ddbb3e6568fb1820b2cc45b00c50702b114801 upstream. This patch (as1603) adds a NOGET quirk for the Eaton Ellipse MAX UPS device. (The USB IDs were already present in hid-ids.h, apparently under a different name.) Signed-off-by: Alan Stern Reported-by: Laurent Bigonville Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/usbhid/hid-quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 82f61ee632b..dc9697c2764 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -70,6 +70,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS }, From ae2e2906541827de51f896e3b035bf3b1c660e73 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 21 Aug 2012 21:57:15 -0700 Subject: [PATCH 0812/2357] Input: i8042 - add Gigabyte T1005 series netbooks to noloop table commit 7b125b94ca16b7e618c6241cb02c4c8060cea5e3 upstream. They all define their chassis type as "Other" and therefore are not categorized as "laptops" by the driver, which tries to perform AUX IRQ delivery test which fails and causes touchpad not working. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42620 Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/i8042-x86ia64io.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 5ec774d6c82..6918773ce02 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -176,6 +176,20 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Spring Peak"), }, }, + { + /* Gigabyte T1005 - defines wrong chassis type ("Other") */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "T1005"), + }, + }, + { + /* Gigabyte T1005M/P - defines wrong chassis type ("Other") */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "T1005M/P"), + }, + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), From df0b962e0900ec0b2b93eac2795e3e65cc18052f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 28 Aug 2012 21:40:51 -0400 Subject: [PATCH 0813/2357] drm/vmwgfx: add MODULE_DEVICE_TABLE so vmwgfx loads at boot commit c4903429a92be60e6fe59868924a65eca4cd1a38 upstream. This will cause udev to load vmwgfx instead of waiting for X to do it. Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index ee24d216aa8..7279b3ec012 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -182,6 +182,7 @@ static struct pci_device_id vmw_pci_id_list[] = { {0x15ad, 0x0405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VMWGFX_CHIP_SVGAII}, {0, 0, 0} }; +MODULE_DEVICE_TABLE(pci, vmw_pci_id_list); static int enable_fbdev; From 9db2bc1e0363bb9401e6407b198463c01f32dd84 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Mon, 23 Jul 2012 12:16:19 +0100 Subject: [PATCH 0814/2357] PARISC: Redefine ATOMIC_INIT and ATOMIC64_INIT to drop the casts commit bba3d8c3b3c0f2123be5bc687d1cddc13437c923 upstream. The following build error occured during a parisc build with swap-over-NFS patches applied. net/core/sock.c:274:36: error: initializer element is not constant net/core/sock.c:274:36: error: (near initialization for 'memalloc_socks') net/core/sock.c:274:36: error: initializer element is not constant Dave Anglin says: > Here is the line in sock.i: > > struct static_key memalloc_socks = ((struct static_key) { .enabled = > ((atomic_t) { (0) }) }); The above line contains two compound literals. It also uses a designated initializer to initialize the field enabled. A compound literal is not a constant expression. The location of the above statement isn't fully clear, but if a compound literal occurs outside the body of a function, the initializer list must consist of constant expressions. Reported-by: Fengguang Wu Signed-off-by: Mel Gorman Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- arch/parisc/include/asm/atomic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 6c6defc2461..af9cf30ed47 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -141,7 +141,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0) -#define ATOMIC_INIT(i) ((atomic_t) { (i) }) +#define ATOMIC_INIT(i) { (i) } #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() @@ -150,7 +150,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) #ifdef CONFIG_64BIT -#define ATOMIC64_INIT(i) ((atomic64_t) { (i) }) +#define ATOMIC64_INIT(i) { (i) } static __inline__ s64 __atomic64_add_return(s64 i, atomic64_t *v) From 095ac020be339cad6f158508cc3b9f740c60b53a Mon Sep 17 00:00:00 2001 From: Ronny Hegewald Date: Fri, 31 Aug 2012 09:57:52 +0000 Subject: [PATCH 0815/2357] xen: Use correct masking in xen_swiotlb_alloc_coherent. commit b5031ed1be0aa419250557123633453753181643 upstream. When running 32-bit pvops-dom0 and a driver tries to allocate a coherent DMA-memory the xen swiotlb-implementation returned memory beyond 4GB. The underlaying reason is that if the supplied driver passes in a DMA_BIT_MASK(64) ( hwdev->coherent_dma_mask is set to 0xffffffffffffffff) our dma_mask will be u64 set to 0xffffffffffffffff even if we set it to DMA_BIT_MASK(32) previously. Meaning we do not reset the upper bits. By using the dma_alloc_coherent_mask function - it does the proper casting and we get 0xfffffffff. This caused not working sound on a system with 4 GB and a 64-bit compatible sound-card with sets the DMA-mask to 64bit. On bare-metal and the forward-ported xen-dom0 patches from OpenSuse a coherent DMA-memory is always allocated inside the 32-bit address-range by calling dma_alloc_coherent_mask. This patch adds the same functionality to xen swiotlb and is a rebase of the original patch from Ronny Hegewald which never got upstream b/c the underlaying reason was not understood until now. The original email with the original patch is in: http://old-list-archives.xen.org/archives/html/xen-devel/2010-02/msg00038.html the original thread from where the discussion started is in: http://old-list-archives.xen.org/archives/html/xen-devel/2010-01/msg00928.html Signed-off-by: Ronny Hegewald Signed-off-by: Stefano Panella Acked-By: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/swiotlb-xen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 1afb4fba11b..4d519488d30 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -232,7 +232,7 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, return ret; if (hwdev && hwdev->coherent_dma_mask) - dma_mask = hwdev->coherent_dma_mask; + dma_mask = dma_alloc_coherent_mask(hwdev, flags); phys = virt_to_phys(ret); dev_addr = xen_phys_to_bus(phys); From bbebafa0d9507206793a05fbeb010eafb1fdb0d0 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 5 Sep 2012 16:35:20 -0400 Subject: [PATCH 0816/2357] xen/pciback: Fix proper FLR steps. commit 80ba77dfbce85f2d1be54847de3c866de1b18a9a upstream. When we do FLR and save PCI config we did it in the wrong order. The end result was that if a PCI device was unbind from its driver, then binded to xen-pciback, and then back to its driver we would get: > lspci -s 04:00.0 04:00.0 Ethernet controller: Intel Corporation 82574L Gigabit Network Connection 13:42:12 # 4 :~/ > echo "0000:04:00.0" > /sys/bus/pci/drivers/pciback/unbind > modprobe e1000e e1000e: Intel(R) PRO/1000 Network Driver - 2.0.0-k e1000e: Copyright(c) 1999 - 2012 Intel Corporation. e1000e 0000:04:00.0: Disabling ASPM L0s L1 e1000e 0000:04:00.0: enabling device (0000 -> 0002) xen: registering gsi 48 triggering 0 polarity 1 Already setup the GSI :48 e1000e 0000:04:00.0: Interrupt Throttling Rate (ints/sec) set to dynamic conservative mode e1000e: probe of 0000:04:00.0 failed with error -2 This fixes it by first saving the PCI configuration space, then doing the FLR. Reported-by: Ren, Yongjie Reported-and-Tested-by: Tobias Geiger Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/xen-pciback/pci_stub.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 097e536e867..03342728bf2 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -353,16 +353,16 @@ static int __devinit pcistub_init_device(struct pci_dev *dev) if (err) goto config_release; - dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n"); - __pci_reset_function_locked(dev); - /* We need the device active to save the state. */ dev_dbg(&dev->dev, "save state of device\n"); pci_save_state(dev); dev_data->pci_saved_state = pci_store_saved_state(dev); if (!dev_data->pci_saved_state) dev_err(&dev->dev, "Could not store PCI conf saved state!\n"); - + else { + dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n"); + __pci_reset_function_locked(dev); + } /* Now disable the device (this also ensures some private device * data is setup before we export) */ From 72961d91696071841fa013f11f686eaa7e2d0996 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 31 Jul 2012 15:41:45 +0200 Subject: [PATCH 0817/2357] x86, microcode, AMD: Fix broken ucode patch size check commit 36bf50d7697be18c6bfd0401e037df10bff1e573 upstream. This issue was recently observed on an AMD C-50 CPU where a patch of maximum size was applied. Commit be62adb49294 ("x86, microcode, AMD: Simplify ucode verification") added current_size in get_matching_microcode(). This is calculated as size of the ucode patch + 8 (ie. size of the header). Later this is compared against the maximum possible ucode patch size for a CPU family. And of course this fails if the patch has already maximum size. Signed-off-by: Andreas Herrmann Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/1344361461-10076-1-git-send-email-bp@amd64.org Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/microcode_amd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 8a2ce8fd41c..82746f942cd 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -143,11 +143,12 @@ static int get_matching_microcode(int cpu, const u8 *ucode_ptr, unsigned int *current_size) { struct microcode_header_amd *mc_hdr; - unsigned int actual_size; + unsigned int actual_size, patch_size; u16 equiv_cpu_id; /* size of the current patch we're staring at */ - *current_size = *(u32 *)(ucode_ptr + 4) + SECTION_HDR_SIZE; + patch_size = *(u32 *)(ucode_ptr + 4); + *current_size = patch_size + SECTION_HDR_SIZE; equiv_cpu_id = find_equiv_id(); if (!equiv_cpu_id) @@ -174,7 +175,7 @@ static int get_matching_microcode(int cpu, const u8 *ucode_ptr, /* * now that the header looks sane, verify its size */ - actual_size = verify_ucode_size(cpu, *current_size, leftover_size); + actual_size = verify_ucode_size(cpu, patch_size, leftover_size); if (!actual_size) return 0; From af843972724e172827266e91ba326c069c8c088c Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:54 +0000 Subject: [PATCH 0818/2357] dccp: check ccid before dereferencing commit 276bdb82dedb290511467a5a4fdbe9f0b52dce6f upstream. ccid_hc_rx_getsockopt() and ccid_hc_tx_getsockopt() might be called with a NULL ccid pointer leading to a NULL pointer dereference. This could lead to a privilege escalation if the attacker is able to map page 0 and prepare it with a fake ccid_ops pointer. Signed-off-by: Mathias Krause Cc: Gerrit Renker Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/ccid.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h index 75c3582a767..fb85d371a8d 100644 --- a/net/dccp/ccid.h +++ b/net/dccp/ccid.h @@ -246,7 +246,7 @@ static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk, u32 __user *optval, int __user *optlen) { int rc = -ENOPROTOOPT; - if (ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL) + if (ccid != NULL && ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL) rc = ccid->ccid_ops->ccid_hc_rx_getsockopt(sk, optname, len, optval, optlen); return rc; @@ -257,7 +257,7 @@ static inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk, u32 __user *optval, int __user *optlen) { int rc = -ENOPROTOOPT; - if (ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL) + if (ccid != NULL && ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL) rc = ccid->ccid_ops->ccid_hc_tx_getsockopt(sk, optname, len, optval, optlen); return rc; From e18625cacb8e252e3e4a9dea3db4dbca523276bc Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Tue, 21 Aug 2012 17:36:28 +0200 Subject: [PATCH 0819/2357] hwmon: (asus_atk0110) Add quirk for Asus M5A78L MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 43ca6cb28c871f2fbad10117b0648e5ae3b0f638 upstream. The old interface is bugged and reads the wrong sensor when retrieving the reading for the chassis fan (it reads the CPU sensor); the new interface works fine. Reported-by: Göran Uddeborg Tested-by: Göran Uddeborg Signed-off-by: Luca Tettamanti Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/asus_atk0110.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 351d1f4593e..4ee57894872 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -34,6 +34,12 @@ static const struct dmi_system_id __initconst atk_force_new_if[] = { .matches = { DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58") } + }, { + /* Old interface reads the same sensor for fan0 and fan1 */ + .ident = "Asus M5A78L", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "M5A78L") + } }, { } }; From 00709f7f01c3a10252f030f0bdacecbb349d7be4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 14 Sep 2012 15:18:55 -0700 Subject: [PATCH 0820/2357] Linux 3.4.11 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a1624b99130..22345c01622 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 10 +SUBLEVEL = 11 EXTRAVERSION = NAME = Saber-toothed Squirrel From 2dc3b21fbca98bd3c8d9e53acf5d966add3c7606 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 30 Jul 2012 15:57:00 +0000 Subject: [PATCH 0821/2357] net: Allow driver to limit number of GSO segments per skb [ Upstream commit 30b678d844af3305cda5953467005cebb5d7b687 ] A peer (or local user) may cause TCP to use a nominal MSS of as little as 88 (actual MSS of 76 with timestamps). Given that we have a sufficiently prodigious local sender and the peer ACKs quickly enough, it is nevertheless possible to grow the window for such a connection to the point that we will try to send just under 64K at once. This results in a single skb that expands to 861 segments. In some drivers with TSO support, such an skb will require hundreds of DMA descriptors; a substantial fraction of a TX ring or even more than a full ring. The TX queue selected for the skb may stall and trigger the TX watchdog repeatedly (since the problem skb will be retried after the TX reset). This particularly affects sfc, for which the issue is designated as CVE-2012-3412. Therefore: 1. Add the field net_device::gso_max_segs holding the device-specific limit. 2. In netif_skb_features(), if the number of segments is too high then mask out GSO features to force fall back to software GSO. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 33900a53c99..79596d6dd85 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1279,6 +1279,8 @@ struct net_device { /* for setting kernel sock attribute on TCP connection setup */ #define GSO_MAX_SIZE 65536 unsigned int gso_max_size; +#define GSO_MAX_SEGS 65535 + u16 gso_max_segs; #ifdef CONFIG_DCB /* Data Center Bridging netlink ops */ diff --git a/net/core/dev.c b/net/core/dev.c index c299416d0e8..665730f06f3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2121,6 +2121,9 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) __be16 protocol = skb->protocol; netdev_features_t features = skb->dev->features; + if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs) + features &= ~NETIF_F_GSO_MASK; + if (protocol == htons(ETH_P_8021Q)) { struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; protocol = veh->h_vlan_encapsulated_proto; @@ -5909,6 +5912,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, dev_net_set(dev, &init_net); dev->gso_max_size = GSO_MAX_SIZE; + dev->gso_max_segs = GSO_MAX_SEGS; INIT_LIST_HEAD(&dev->napi_list); INIT_LIST_HEAD(&dev->unreg_list); From 0a1f711681e0d7068b69c0697c4ba284fbf1b2bf Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 30 Jul 2012 15:57:44 +0000 Subject: [PATCH 0822/2357] sfc: Fix maximum number of TSO segments and minimum TX queue size [ Upstream commit 7e6d06f0de3f74ca929441add094518ae332257c ] Currently an skb requiring TSO may not fit within a minimum-size TX queue. The TX queue selected for the skb may stall and trigger the TX watchdog repeatedly (since the problem skb will be retried after the TX reset). This issue is designated as CVE-2012-3412. Set the maximum number of TSO segments for our devices to 100. This should make no difference to behaviour unless the actual MSS is less than about 700. Increase the minimum TX queue size accordingly to allow for 2 worst-case skbs, so that there will definitely be space to add an skb after we wake a queue. To avoid invalidating existing configurations, change efx_ethtool_set_ringparam() to fix up values that are too small rather than returning -EINVAL. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/sfc/efx.c | 6 ++++++ drivers/net/ethernet/sfc/efx.h | 14 ++++++++++---- drivers/net/ethernet/sfc/ethtool.c | 16 +++++++++++----- drivers/net/ethernet/sfc/tx.c | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 4a0005342e6..954b8854b25 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1498,6 +1498,11 @@ static int efx_probe_all(struct efx_nic *efx) goto fail2; } + BUILD_BUG_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_RXQ_MIN_ENT); + if (WARN_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_TXQ_MIN_ENT(efx))) { + rc = -EINVAL; + goto fail3; + } efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; rc = efx_probe_filters(efx); @@ -2065,6 +2070,7 @@ static int efx_register_netdev(struct efx_nic *efx) net_dev->irq = efx->pci_dev->irq; net_dev->netdev_ops = &efx_netdev_ops; SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops); + net_dev->gso_max_segs = EFX_TSO_MAX_SEGS; rtnl_lock(); diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index be8f9158a71..70755c97251 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -30,6 +30,7 @@ extern netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); extern int efx_setup_tc(struct net_device *net_dev, u8 num_tc); +extern unsigned int efx_tx_max_skb_descs(struct efx_nic *efx); /* RX */ extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); @@ -52,10 +53,15 @@ extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue); #define EFX_MAX_EVQ_SIZE 16384UL #define EFX_MIN_EVQ_SIZE 512UL -/* The smallest [rt]xq_entries that the driver supports. Callers of - * efx_wake_queue() assume that they can subsequently send at least one - * skb. Falcon/A1 may require up to three descriptors per skb_frag. */ -#define EFX_MIN_RING_SIZE (roundup_pow_of_two(2 * 3 * MAX_SKB_FRAGS)) +/* Maximum number of TCP segments we support for soft-TSO */ +#define EFX_TSO_MAX_SEGS 100 + +/* The smallest [rt]xq_entries that the driver supports. RX minimum + * is a bit arbitrary. For TX, we must have space for at least 2 + * TSO skbs. + */ +#define EFX_RXQ_MIN_ENT 128U +#define EFX_TXQ_MIN_ENT(efx) (2 * efx_tx_max_skb_descs(efx)) /* Filters */ extern int efx_probe_filters(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index f22f45f515a..b7b37d46a60 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -680,21 +680,27 @@ static int efx_ethtool_set_ringparam(struct net_device *net_dev, struct ethtool_ringparam *ring) { struct efx_nic *efx = netdev_priv(net_dev); + u32 txq_entries; if (ring->rx_mini_pending || ring->rx_jumbo_pending || ring->rx_pending > EFX_MAX_DMAQ_SIZE || ring->tx_pending > EFX_MAX_DMAQ_SIZE) return -EINVAL; - if (ring->rx_pending < EFX_MIN_RING_SIZE || - ring->tx_pending < EFX_MIN_RING_SIZE) { + if (ring->rx_pending < EFX_RXQ_MIN_ENT) { netif_err(efx, drv, efx->net_dev, - "TX and RX queues cannot be smaller than %ld\n", - EFX_MIN_RING_SIZE); + "RX queues cannot be smaller than %u\n", + EFX_RXQ_MIN_ENT); return -EINVAL; } - return efx_realloc_channels(efx, ring->rx_pending, ring->tx_pending); + txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx)); + if (txq_entries != ring->tx_pending) + netif_warn(efx, drv, efx->net_dev, + "increasing TX queue size to minimum of %u\n", + txq_entries); + + return efx_realloc_channels(efx, ring->rx_pending, txq_entries); } static int efx_ethtool_set_pauseparam(struct net_device *net_dev, diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 94d0365b31c..305430da48f 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -119,6 +119,25 @@ efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr) return len; } +unsigned int efx_tx_max_skb_descs(struct efx_nic *efx) +{ + /* Header and payload descriptor for each output segment, plus + * one for every input fragment boundary within a segment + */ + unsigned int max_descs = EFX_TSO_MAX_SEGS * 2 + MAX_SKB_FRAGS; + + /* Possibly one more per segment for the alignment workaround */ + if (EFX_WORKAROUND_5391(efx)) + max_descs += EFX_TSO_MAX_SEGS; + + /* Possibly more for PCIe page boundaries within input fragments */ + if (PAGE_SIZE > EFX_PAGE_SIZE) + max_descs += max_t(unsigned int, MAX_SKB_FRAGS, + DIV_ROUND_UP(GSO_MAX_SIZE, EFX_PAGE_SIZE)); + + return max_descs; +} + /* * Add a socket buffer to a TX queue * From 4658b24b2dd0e4c6215db2203743fa999765e8a0 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 30 Jul 2012 16:11:42 +0000 Subject: [PATCH 0823/2357] tcp: Apply device TSO segment limit earlier [ Upstream commit 1485348d2424e1131ea42efc033cbd9366462b01 ] Cache the device gso_max_segs in sock::sk_gso_max_segs and use it to limit the size of TSO skbs. This avoids the need to fall back to software GSO for local TCP senders. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/sock.h | 2 ++ net/core/sock.c | 1 + net/ipv4/tcp.c | 4 +++- net/ipv4/tcp_cong.c | 3 ++- net/ipv4/tcp_output.c | 21 ++++++++++++--------- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 5a0a58ac412..5878118e3ce 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -216,6 +216,7 @@ struct cg_proto; * @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK) * @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4) * @sk_gso_max_size: Maximum GSO segment size to build + * @sk_gso_max_segs: Maximum number of GSO segments * @sk_lingertime: %SO_LINGER l_linger setting * @sk_backlog: always used with the per-socket spinlock held * @sk_callback_lock: used with the callbacks in the end of this struct @@ -335,6 +336,7 @@ struct sock { netdev_features_t sk_route_nocaps; int sk_gso_type; unsigned int sk_gso_max_size; + u16 sk_gso_max_segs; int sk_rcvlowat; unsigned long sk_lingertime; struct sk_buff_head sk_error_queue; diff --git a/net/core/sock.c b/net/core/sock.c index 0f8402ea434..d3e0a5201d4 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1411,6 +1411,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) } else { sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; sk->sk_gso_max_size = dst->dev->gso_max_size; + sk->sk_gso_max_segs = dst->dev->gso_max_segs; } } } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index d6feb1ef4f2..367bdaf9a56 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -740,7 +740,9 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, old_size_goal + mss_now > xmit_size_goal)) { xmit_size_goal = old_size_goal; } else { - tp->xmit_size_goal_segs = xmit_size_goal / mss_now; + tp->xmit_size_goal_segs = + min_t(u16, xmit_size_goal / mss_now, + sk->sk_gso_max_segs); xmit_size_goal = tp->xmit_size_goal_segs * mss_now; } } diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 272a84593c8..69251dde750 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -291,7 +291,8 @@ int tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight) left = tp->snd_cwnd - in_flight; if (sk_can_gso(sk) && left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd && - left * tp->mss_cache < sk->sk_gso_max_size) + left * tp->mss_cache < sk->sk_gso_max_size && + left < sk->sk_gso_max_segs) return 1; return left <= tcp_max_tso_deferred_mss(tp); } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7ac6423117a..2d27e1af930 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1318,21 +1318,21 @@ static void tcp_cwnd_validate(struct sock *sk) * when we would be allowed to send the split-due-to-Nagle skb fully. */ static unsigned int tcp_mss_split_point(const struct sock *sk, const struct sk_buff *skb, - unsigned int mss_now, unsigned int cwnd) + unsigned int mss_now, unsigned int max_segs) { const struct tcp_sock *tp = tcp_sk(sk); - u32 needed, window, cwnd_len; + u32 needed, window, max_len; window = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq; - cwnd_len = mss_now * cwnd; + max_len = mss_now * max_segs; - if (likely(cwnd_len <= window && skb != tcp_write_queue_tail(sk))) - return cwnd_len; + if (likely(max_len <= window && skb != tcp_write_queue_tail(sk))) + return max_len; needed = min(skb->len, window); - if (cwnd_len <= needed) - return cwnd_len; + if (max_len <= needed) + return max_len; return needed - needed % mss_now; } @@ -1560,7 +1560,8 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) limit = min(send_win, cong_win); /* If a full-sized TSO skb can be sent, do it. */ - if (limit >= sk->sk_gso_max_size) + if (limit >= min_t(unsigned int, sk->sk_gso_max_size, + sk->sk_gso_max_segs * tp->mss_cache)) goto send_now; /* Middle in queue won't get any more data, full sendable already? */ @@ -1786,7 +1787,9 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, limit = mss_now; if (tso_segs > 1 && !tcp_urg_mode(tp)) limit = tcp_mss_split_point(sk, skb, mss_now, - cwnd_quota); + min_t(unsigned int, + cwnd_quota, + sk->sk_gso_max_segs)); if (skb->len > limit && unlikely(tso_fragment(sk, skb, limit, mss_now, gfp))) From 7e0c71a9a5a23f9433eac1d0aabbc9d54da3428b Mon Sep 17 00:00:00 2001 From: Hiroaki SHIMODA Date: Fri, 3 Aug 2012 19:57:52 +0900 Subject: [PATCH 0824/2357] net_sched: gact: Fix potential panic in tcf_gact(). [ Upstream commit 696ecdc10622d86541f2e35cc16e15b6b3b1b67e ] gact_rand array is accessed by gact->tcfg_ptype whose value is assumed to less than MAX_RAND, but any range checks are not performed. So add a check in tcf_gact_init(). And in tcf_gact(), we can reduce a branch. Signed-off-by: Hiroaki SHIMODA Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_gact.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index b77f5a06a65..bdacd8df318 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -67,6 +67,9 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est, struct tcf_common *pc; int ret = 0; int err; +#ifdef CONFIG_GACT_PROB + struct tc_gact_p *p_parm = NULL; +#endif if (nla == NULL) return -EINVAL; @@ -82,6 +85,12 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est, #ifndef CONFIG_GACT_PROB if (tb[TCA_GACT_PROB] != NULL) return -EOPNOTSUPP; +#else + if (tb[TCA_GACT_PROB]) { + p_parm = nla_data(tb[TCA_GACT_PROB]); + if (p_parm->ptype >= MAX_RAND) + return -EINVAL; + } #endif pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info); @@ -103,8 +112,7 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est, spin_lock_bh(&gact->tcf_lock); gact->tcf_action = parm->action; #ifdef CONFIG_GACT_PROB - if (tb[TCA_GACT_PROB] != NULL) { - struct tc_gact_p *p_parm = nla_data(tb[TCA_GACT_PROB]); + if (p_parm) { gact->tcfg_paction = p_parm->paction; gact->tcfg_pval = p_parm->pval; gact->tcfg_ptype = p_parm->ptype; @@ -133,7 +141,7 @@ static int tcf_gact(struct sk_buff *skb, const struct tc_action *a, spin_lock(&gact->tcf_lock); #ifdef CONFIG_GACT_PROB - if (gact->tcfg_ptype && gact_rand[gact->tcfg_ptype] != NULL) + if (gact->tcfg_ptype) action = gact_rand[gact->tcfg_ptype](gact); else action = gact->tcf_action; From bc3f72433351e278a92a38c2090aacff982ce558 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 2 Aug 2012 23:10:01 +0000 Subject: [PATCH 0825/2357] isdnloop: fix and simplify isdnloop_init() [ Upstream commit 77f00f6324cb97cf1df6f9c4aaeea6ada23abdb2 ] Fix a buffer overflow bug by removing the revision and printk. [ 22.016214] isdnloop-ISDN-driver Rev 1.11.6.7 [ 22.097508] isdnloop: (loop0) virtual card added [ 22.174400] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffffff83244972 [ 22.174400] [ 22.436157] Pid: 1, comm: swapper Not tainted 3.5.0-bisect-00018-gfa8bbb1-dirty #129 [ 22.624071] Call Trace: [ 22.720558] [] ? CallcNew+0x56/0x56 [ 22.815248] [] panic+0x110/0x329 [ 22.914330] [] ? isdnloop_init+0xaf/0xb1 [ 23.014800] [] ? CallcNew+0x56/0x56 [ 23.090763] [] __stack_chk_fail+0x2b/0x30 [ 23.185748] [] isdnloop_init+0xaf/0xb1 Signed-off-by: Fengguang Wu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/isdnloop/isdnloop.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index 5405ec644db..baf2686aa8e 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -16,7 +16,6 @@ #include #include "isdnloop.h" -static char *revision = "$Revision: 1.11.6.7 $"; static char *isdnloop_id = "loop0"; MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card"); @@ -1494,17 +1493,6 @@ isdnloop_addcard(char *id1) static int __init isdnloop_init(void) { - char *p; - char rev[10]; - - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; - } else - strcpy(rev, " ??? "); - printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev); - if (isdnloop_id) return (isdnloop_addcard(isdnloop_id)); From a348ed02b367a8a8307444724db5c8e96c90ac78 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Tue, 7 Aug 2012 00:23:11 +0000 Subject: [PATCH 0826/2357] pptp: lookup route with the proper net namespace [ Upstream commit 08252b32311c3fa84219ad794d640af7399b5485 ] pptp always use init_net as the net namespace to lookup route, this will cause route lookup failed in container. because we already set the correct net namespace to struct sock in pptp_create,so fix this by using sock_net(sk) to replace &init_net. Signed-off-by: Gao feng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ppp/pptp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 885dbdd9c39..f617566bbba 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -189,7 +189,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (sk_pppox(po)->sk_state & PPPOX_DEAD) goto tx_error; - rt = ip_route_output_ports(&init_net, &fl4, NULL, + rt = ip_route_output_ports(sock_net(sk), &fl4, NULL, opt->dst_addr.sin_addr.s_addr, opt->src_addr.sin_addr.s_addr, 0, 0, IPPROTO_GRE, @@ -468,7 +468,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.private = sk; po->chan.ops = &pptp_chan_ops; - rt = ip_route_output_ports(&init_net, &fl4, sk, + rt = ip_route_output_ports(sock_net(sk), &fl4, sk, opt->dst_addr.sin_addr.s_addr, opt->src_addr.sin_addr.s_addr, 0, 0, From caf2630c41a183b72e5d6211e5efd1457ac0c463 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Wed, 8 Aug 2012 00:33:25 +0000 Subject: [PATCH 0827/2357] net/core: Fix potential memory leak in dev_set_alias() [ Upstream commit 7364e445f62825758fa61195d237a5b8ecdd06ec ] Do not leak memory by updating pointer with potentially NULL realloc return value. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 665730f06f3..a1e0355908e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1056,6 +1056,8 @@ int dev_change_name(struct net_device *dev, const char *newname) */ int dev_set_alias(struct net_device *dev, const char *alias, size_t len) { + char *new_ifalias; + ASSERT_RTNL(); if (len >= IFALIASZ) @@ -1069,9 +1071,10 @@ int dev_set_alias(struct net_device *dev, const char *alias, size_t len) return 0; } - dev->ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL); - if (!dev->ifalias) + new_ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL); + if (!new_ifalias) return -ENOMEM; + dev->ifalias = new_ifalias; strlcpy(dev->ifalias, alias, len+1); return len; From c8cca9d90b953a0a2b5d0edab789f5c52ae983f5 Mon Sep 17 00:00:00 2001 From: "danborkmann@iogearbox.net" Date: Fri, 10 Aug 2012 22:48:54 +0000 Subject: [PATCH 0828/2357] af_packet: remove BUG statement in tpacket_destruct_skb [ Upstream commit 7f5c3e3a80e6654cf48dfba7cf94f88c6b505467 ] Here's a quote of the comment about the BUG macro from asm-generic/bug.h: Don't use BUG() or BUG_ON() unless there's really no way out; one example might be detecting data structure corruption in the middle of an operation that can't be backed out of. If the (sub)system can somehow continue operating, perhaps with reduced functionality, it's probably not BUG-worthy. If you're tempted to BUG(), think again: is completely giving up really the *only* solution? There are usually better options, where users don't need to reboot ASAP and can mostly shut down cleanly. In our case, the status flag of a ring buffer slot is managed from both sides, the kernel space and the user space. This means that even though the kernel side might work as expected, the user space screws up and changes this flag right between the send(2) is triggered when the flag is changed to TP_STATUS_SENDING and a given skb is destructed after some time. Then, this will hit the BUG macro. As David suggested, the best solution is to simply remove this statement since it cannot be used for kernel side internal consistency checks. I've tested it and the system still behaves /stable/ in this case, so in accordance with the above comment, we should rather remove it. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 4f2c0df7956..cd0d9bb2091 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1943,7 +1943,6 @@ static void tpacket_destruct_skb(struct sk_buff *skb) if (likely(po->tx_ring.pg_vec)) { ph = skb_shinfo(skb)->destructor_arg; - BUG_ON(__packet_get_status(po, ph) != TP_STATUS_SENDING); BUG_ON(atomic_read(&po->tx_ring.pending) == 0); atomic_dec(&po->tx_ring.pending); __packet_set_status(po, ph, TP_STATUS_AVAILABLE); From 84a2d3c44cce71152f3555af83bafea6ec5ef23c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 14 Aug 2012 08:54:51 +0000 Subject: [PATCH 0829/2357] ipv6: addrconf: Avoid calling netdevice notifiers with RCU read-side lock [ Upstream commit 4acd4945cd1e1f92b20d14e349c6c6a52acbd42d ] Cong Wang reports that lockdep detected suspicious RCU usage while enabling IPV6 forwarding: [ 1123.310275] =============================== [ 1123.442202] [ INFO: suspicious RCU usage. ] [ 1123.558207] 3.6.0-rc1+ #109 Not tainted [ 1123.665204] ------------------------------- [ 1123.768254] include/linux/rcupdate.h:430 Illegal context switch in RCU read-side critical section! [ 1123.992320] [ 1123.992320] other info that might help us debug this: [ 1123.992320] [ 1124.307382] [ 1124.307382] rcu_scheduler_active = 1, debug_locks = 0 [ 1124.522220] 2 locks held by sysctl/5710: [ 1124.648364] #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_trylock+0x15/0x17 [ 1124.882211] #1: (rcu_read_lock){.+.+.+}, at: [] rcu_lock_acquire+0x0/0x29 [ 1125.085209] [ 1125.085209] stack backtrace: [ 1125.332213] Pid: 5710, comm: sysctl Not tainted 3.6.0-rc1+ #109 [ 1125.441291] Call Trace: [ 1125.545281] [] lockdep_rcu_suspicious+0x109/0x112 [ 1125.667212] [] rcu_preempt_sleep_check+0x45/0x47 [ 1125.781838] [] __might_sleep+0x1e/0x19b [...] [ 1127.445223] [] call_netdevice_notifiers+0x4a/0x4f [...] [ 1127.772188] [] dev_disable_lro+0x32/0x6b [ 1127.885174] [] dev_forward_change+0x30/0xcb [ 1128.013214] [] addrconf_forward_change+0x85/0xc5 [...] addrconf_forward_change() uses RCU iteration over the netdev list, which is unnecessary since it already holds the RTNL lock. We also cannot reasonably require netdevice notifier functions not to sleep. Reported-by: Cong Wang Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/addrconf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 7d5cb975cc6..2c69eca4b61 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -493,8 +493,7 @@ static void addrconf_forward_change(struct net *net, __s32 newf) struct net_device *dev; struct inet6_dev *idev; - rcu_read_lock(); - for_each_netdev_rcu(net, dev) { + for_each_netdev(net, dev) { idev = __in6_dev_get(dev); if (idev) { int changed = (!idev->cnf.forwarding) ^ (!newf); @@ -503,7 +502,6 @@ static void addrconf_forward_change(struct net *net, __s32 newf) dev_forward_change(idev); } } - rcu_read_unlock(); } static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) From 5b26dbdd5f22871c21fc2ea4afedfe4ecad62d72 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:44 +0000 Subject: [PATCH 0830/2357] atm: fix info leak in getsockopt(SO_ATMPVC) [ Upstream commit e862f1a9b7df4e8196ebec45ac62295138aa3fc2 ] The ATM code fails to initialize the two padding bytes of struct sockaddr_atmpvc inserted for alignment. Add an explicit memset(0) before filling the structure to avoid the info leak. Signed-off-by: Mathias Krause Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/atm/common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/atm/common.c b/net/atm/common.c index b4b44dbed64..0c0ad930a63 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -812,6 +812,7 @@ int vcc_getsockopt(struct socket *sock, int level, int optname, if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags)) return -ENOTCONN; + memset(&pvc, 0, sizeof(pvc)); pvc.sap_family = AF_ATMPVC; pvc.sap_addr.itf = vcc->dev->number; pvc.sap_addr.vpi = vcc->vpi; From 458ed5622e976848aacdea07d4bfcb84a350c460 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:45 +0000 Subject: [PATCH 0831/2357] atm: fix info leak via getsockname() [ Upstream commit 3c0c5cfdcd4d69ffc4b9c0907cec99039f30a50a ] The ATM code fails to initialize the two padding bytes of struct sockaddr_atmpvc inserted for alignment. Add an explicit memset(0) before filling the structure to avoid the info leak. Signed-off-by: Mathias Krause Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/atm/pvc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 3a734919c36..ae032402140 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -95,6 +95,7 @@ static int pvc_getname(struct socket *sock, struct sockaddr *sockaddr, return -ENOTCONN; *sockaddr_len = sizeof(struct sockaddr_atmpvc); addr = (struct sockaddr_atmpvc *)sockaddr; + memset(addr, 0, sizeof(*addr)); addr->sap_family = AF_ATMPVC; addr->sap_addr.itf = vcc->dev->number; addr->sap_addr.vpi = vcc->vpi; From 87c42a1dfd5939d0a24795cd99b3d63daa4e1eff Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:46 +0000 Subject: [PATCH 0832/2357] Bluetooth: HCI - Fix info leak in getsockopt(HCI_FILTER) [ Upstream commit e15ca9a0ef9a86f0477530b0f44a725d67f889ee ] The HCI code fails to initialize the two padding bytes of struct hci_ufilter before copying it to userland -- that for leaking two bytes kernel stack. Add an explicit memset(0) before filling the structure to avoid the info leak. Signed-off-by: Mathias Krause Cc: Marcel Holtmann Cc: Gustavo Padovan Cc: Johan Hedberg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_sock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 5914623f426..2f6ab5b8f21 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -1016,6 +1016,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char { struct hci_filter *f = &hci_pi(sk)->filter; + memset(&uf, 0, sizeof(uf)); uf.type_mask = f->type_mask; uf.opcode = f->opcode; uf.event_mask[0] = *((u32 *) f->event_mask + 0); From 639edee79eb2035b6fe3976f50a1c5364acc7352 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:47 +0000 Subject: [PATCH 0833/2357] Bluetooth: HCI - Fix info leak via getsockname() [ Upstream commit 3f68ba07b1da811bf383b4b701b129bfcb2e4988 ] The HCI code fails to initialize the hci_channel member of struct sockaddr_hci and that for leaks two bytes kernel stack via the getsockname() syscall. Initialize hci_channel with 0 to avoid the info leak. Signed-off-by: Mathias Krause Cc: Marcel Holtmann Cc: Gustavo Padovan Cc: Johan Hedberg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_sock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 2f6ab5b8f21..bedc768c8cd 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -706,6 +706,7 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *add *addr_len = sizeof(*haddr); haddr->hci_family = AF_BLUETOOTH; haddr->hci_dev = hdev->id; + haddr->hci_channel= 0; release_sock(sk); return 0; From 745dcdb0fd330f0cc984bd8a7764a81f04e44780 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:48 +0000 Subject: [PATCH 0834/2357] Bluetooth: RFCOMM - Fix info leak in getsockopt(BT_SECURITY) [ Upstream commit 9ad2de43f1aee7e7274a4e0d41465489299e344b ] The RFCOMM code fails to initialize the key_size member of struct bt_security before copying it to userland -- that for leaking one byte kernel stack. Initialize key_size with 0 to avoid the info leak. Signed-off-by: Mathias Krause Cc: Marcel Holtmann Cc: Gustavo Padovan Cc: Johan Hedberg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/rfcomm/sock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index a55a43e9f70..dfa3dd96106 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -836,6 +836,7 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c } sec.level = rfcomm_pi(sk)->sec_level; + sec.key_size = 0; len = min_t(unsigned int, len, sizeof(sec)); if (copy_to_user(optval, (char *) &sec, len)) From 279d3f5b2d402034dee1a81b7f5e3f678aa46d21 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:49 +0000 Subject: [PATCH 0835/2357] Bluetooth: RFCOMM - Fix info leak in ioctl(RFCOMMGETDEVLIST) [ Upstream commit f9432c5ec8b1e9a09b9b0e5569e3c73db8de432a ] The RFCOMM code fails to initialize the two padding bytes of struct rfcomm_dev_list_req inserted for alignment before copying it to userland. Additionally there are two padding bytes in each instance of struct rfcomm_dev_info. The ioctl() that for disclosures two bytes plus dev_num times two bytes uninitialized kernel heap memory. Allocate the memory using kzalloc() to fix this issue. Signed-off-by: Mathias Krause Cc: Marcel Holtmann Cc: Gustavo Padovan Cc: Johan Hedberg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/rfcomm/tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 4bf54b37725..95a0f60fc6e 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -467,7 +467,7 @@ static int rfcomm_get_dev_list(void __user *arg) size = sizeof(*dl) + dev_num * sizeof(*di); - dl = kmalloc(size, GFP_KERNEL); + dl = kzalloc(size, GFP_KERNEL); if (!dl) return -ENOMEM; From 8717cd3d63233ee5591bf8e8d6e5960a1f6252b1 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:50 +0000 Subject: [PATCH 0836/2357] Bluetooth: RFCOMM - Fix info leak via getsockname() [ Upstream commit 9344a972961d1a6d2c04d9008b13617bcb6ec2ef ] The RFCOMM code fails to initialize the trailing padding byte of struct sockaddr_rc added for alignment. It that for leaks one byte kernel stack via the getsockname() syscall. Add an explicit memset(0) before filling the structure to avoid the info leak. Signed-off-by: Mathias Krause Cc: Marcel Holtmann Cc: Gustavo Padovan Cc: Johan Hedberg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/rfcomm/sock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index dfa3dd96106..717c43ac0c7 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -546,6 +546,7 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int * BT_DBG("sock %p, sk %p", sock, sk); + memset(sa, 0, sizeof(*sa)); sa->rc_family = AF_BLUETOOTH; sa->rc_channel = rfcomm_pi(sk)->channel; if (peer) From dbcba7a54a0327f0ef6d6a3ec53b67d0969109b6 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:51 +0000 Subject: [PATCH 0837/2357] Bluetooth: L2CAP - Fix info leak via getsockname() [ Upstream commit 792039c73cf176c8e39a6e8beef2c94ff46522ed ] The L2CAP code fails to initialize the l2_bdaddr_type member of struct sockaddr_l2 and the padding byte added for alignment. It that for leaks two bytes kernel stack via the getsockname() syscall. Add an explicit memset(0) before filling the structure to avoid the info leak. Signed-off-by: Mathias Krause Cc: Marcel Holtmann Cc: Gustavo Padovan Cc: Johan Hedberg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/l2cap_sock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 04e7c172d49..615b26e0650 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -242,6 +242,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l BT_DBG("sock %p, sk %p", sock, sk); + memset(la, 0, sizeof(struct sockaddr_l2)); addr->sa_family = AF_BLUETOOTH; *len = sizeof(struct sockaddr_l2); From 00ed5b8f397447a944a3305274b74049bfcd633f Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:53 +0000 Subject: [PATCH 0838/2357] llc: fix info leak via getsockname() [ Upstream commit 3592aaeb80290bda0f2cf0b5456c97bfc638b192 ] The LLC code wrongly returns 0, i.e. "success", when the socket is zapped. Together with the uninitialized uaddrlen pointer argument from sys_getsockname this leads to an arbitrary memory leak of up to 128 bytes kernel stack via the getsockname() syscall. Return an error instead when the socket is zapped to prevent the info leak. Also remove the unnecessary memset(0). We don't directly write to the memory pointed by uaddr but memcpy() a local structure at the end of the function that is properly initialized. Signed-off-by: Mathias Krause Cc: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/llc/af_llc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index b9bef2c7502..df08d7779e1 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -971,14 +971,13 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr, struct sockaddr_llc sllc; struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); - int rc = 0; + int rc = -EBADF; memset(&sllc, 0, sizeof(sllc)); lock_sock(sk); if (sock_flag(sk, SOCK_ZAPPED)) goto out; *uaddrlen = sizeof(sllc); - memset(uaddr, 0, *uaddrlen); if (peer) { rc = -ENOTCONN; if (sk->sk_state != TCP_ESTABLISHED) From 59039dc90bb7879bd4c8c959109d27131f0ce40f Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:55 +0000 Subject: [PATCH 0839/2357] dccp: fix info leak via getsockopt(DCCP_SOCKOPT_CCID_TX_INFO) [ Upstream commit 7b07f8eb75aa3097cdfd4f6eac3da49db787381d ] The CCID3 code fails to initialize the trailing padding bytes of struct tfrc_tx_info added for alignment on 64 bit architectures. It that for potentially leaks four bytes kernel stack via the getsockopt() syscall. Add an explicit memset(0) before filling the structure to avoid the info leak. Signed-off-by: Mathias Krause Cc: Gerrit Renker Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/ccids/ccid3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 70bfaf2d196..b658f3b8a23 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -531,6 +531,7 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, case DCCP_SOCKOPT_CCID_TX_INFO: if (len < sizeof(tfrc)) return -EINVAL; + memset(&tfrc, 0, sizeof(tfrc)); tfrc.tfrctx_x = hc->tx_x; tfrc.tfrctx_x_recv = hc->tx_x_recv; tfrc.tfrctx_x_calc = hc->tx_x_calc; From 62b4d90b525c6c11e467a2eadb12fcf64a6f0829 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:56 +0000 Subject: [PATCH 0840/2357] ipvs: fix info leak in getsockopt(IP_VS_SO_GET_TIMEOUT) [ Upstream commit 2d8a041b7bfe1097af21441cb77d6af95f4f4680 ] If at least one of CONFIG_IP_VS_PROTO_TCP or CONFIG_IP_VS_PROTO_UDP is not set, __ip_vs_get_timeouts() does not fully initialize the structure that gets copied to userland and that for leaks up to 12 bytes of kernel stack. Add an explicit memset(0) before passing the structure to __ip_vs_get_timeouts() to avoid the info leak. Signed-off-by: Mathias Krause Cc: Wensong Zhang Cc: Simon Horman Cc: Julian Anastasov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipvs/ip_vs_ctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index f5589987fc8..97e73806bac 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2713,6 +2713,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) { struct ip_vs_timeout_user t; + memset(&t, 0, sizeof(t)); __ip_vs_get_timeouts(net, &t); if (copy_to_user(user, &t, sizeof(t)) != 0) ret = -EFAULT; From d09b3b2b1183848e287bc0b6397f8d05945becc4 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 15 Aug 2012 11:31:57 +0000 Subject: [PATCH 0841/2357] net: fix info leak in compat dev_ifconf() [ Upstream commit 43da5f2e0d0c69ded3d51907d9552310a6b545e8 ] The implementation of dev_ifconf() for the compat ioctl interface uses an intermediate ifc structure allocated in userland for the duration of the syscall. Though, it fails to initialize the padding bytes inserted for alignment and that for leaks four bytes of kernel stack. Add an explicit memset(0) before filling the structure to avoid the info leak. Signed-off-by: Mathias Krause Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/socket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/socket.c b/net/socket.c index 06ffa0f2839..dab317686ad 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2658,6 +2658,7 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf))) return -EFAULT; + memset(&ifc, 0, sizeof(ifc)); if (ifc32.ifcbuf == 0) { ifc32.ifc_len = 0; ifc.ifc_len = 0; From 9e296becde8a8da5bcc1a8e22f27bdf9bd8636fe Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 16 Aug 2012 22:02:58 +0000 Subject: [PATCH 0842/2357] af_packet: don't emit packet on orig fanout group [ Upstream commit c0de08d04215031d68fa13af36f347a6cfa252ca ] If a packet is emitted on one socket in one group of fanout sockets, it is transmitted again. It is thus read again on one of the sockets of the fanout group. This result in a loop for software which generate packets when receiving one. This retransmission is not the intended behavior: a fanout group must behave like a single socket. The packet should not be transmitted on a socket if it originates from a socket belonging to the same fanout group. This patch fixes the issue by changing the transmission check to take fanout group info account. Reported-by: Aleksandr Kotov Signed-off-by: Eric Leblond Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 16 ++++++++++++++-- net/packet/af_packet.c | 9 +++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 79596d6dd85..e517695704c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1496,6 +1496,8 @@ struct packet_type { struct sk_buff **(*gro_receive)(struct sk_buff **head, struct sk_buff *skb); int (*gro_complete)(struct sk_buff *skb); + bool (*id_match)(struct packet_type *ptype, + struct sock *sk); void *af_packet_priv; struct list_head list; }; diff --git a/net/core/dev.c b/net/core/dev.c index a1e0355908e..40d5ab15bef 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1641,6 +1641,19 @@ static inline int deliver_skb(struct sk_buff *skb, return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); } +static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb) +{ + if (ptype->af_packet_priv == NULL) + return false; + + if (ptype->id_match) + return ptype->id_match(ptype, skb->sk); + else if ((struct sock *)ptype->af_packet_priv == skb->sk) + return true; + + return false; +} + /* * Support routine. Sends outgoing frames to any network * taps currently in use. @@ -1658,8 +1671,7 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) * they originated from - MvS (miquels@drinkel.ow.org) */ if ((ptype->dev == dev || !ptype->dev) && - (ptype->af_packet_priv == NULL || - (struct sock *)ptype->af_packet_priv != skb->sk)) { + (!skb_loop_sk(ptype, skb))) { if (pt_prev) { deliver_skb(skb2, pt_prev, skb->dev); pt_prev = ptype; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index cd0d9bb2091..078fdffcd55 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1280,6 +1280,14 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po) spin_unlock(&f->lock); } +bool match_fanout_group(struct packet_type *ptype, struct sock * sk) +{ + if (ptype->af_packet_priv == (void*)((struct packet_sock *)sk)->fanout) + return true; + + return false; +} + static int fanout_add(struct sock *sk, u16 id, u16 type_flags) { struct packet_sock *po = pkt_sk(sk); @@ -1332,6 +1340,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) match->prot_hook.dev = po->prot_hook.dev; match->prot_hook.func = packet_rcv_fanout; match->prot_hook.af_packet_priv = match; + match->prot_hook.id_match = match_fanout_group; dev_add_pack(&match->prot_hook); list_add(&match->list, &fanout_list); } From 7c799a1e1ca2bc766574078b684c14474da9f704 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Aug 2012 06:21:17 +0000 Subject: [PATCH 0843/2357] af_netlink: force credentials passing [CVE-2012-3520] [ Upstream commit e0e3cea46d31d23dc40df0a49a7a2c04fe8edfea ] Pablo Neira Ayuso discovered that avahi and potentially NetworkManager accept spoofed Netlink messages because of a kernel bug. The kernel passes all-zero SCM_CREDENTIALS ancillary data to the receiver if the sender did not provide such data, instead of not including any such data at all or including the correct data from the peer (as it is the case with AF_UNIX). This bug was introduced in commit 16e572626961 (af_unix: dont send SCM_CREDENTIALS by default) This patch forces passing credentials for netlink, as before the regression. Another fix would be to not add SCM_CREDENTIALS in netlink messages if not provided by the sender, but it might break some programs. With help from Florian Weimer & Petr Matousek This issue is designated as CVE-2012-3520 Signed-off-by: Eric Dumazet Cc: Petr Matousek Cc: Florian Weimer Cc: Pablo Neira Ayuso Signed-off-by: David S. Miller --- include/net/scm.h | 4 +++- net/netlink/af_netlink.c | 2 +- net/unix/af_unix.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/net/scm.h b/include/net/scm.h index d456f4c71a3..0c0017ce23b 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -71,9 +71,11 @@ static __inline__ void scm_destroy(struct scm_cookie *scm) } static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, - struct scm_cookie *scm) + struct scm_cookie *scm, bool forcecreds) { memset(scm, 0, sizeof(*scm)); + if (forcecreds) + scm_set_cred(scm, task_tgid(current), current_cred()); unix_get_peersec_dgram(sock, scm); if (msg->msg_controllen <= 0) return 0; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index faa48f70b7c..59debb73ba7 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1329,7 +1329,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, if (NULL == siocb->scm) siocb->scm = &scm; - err = scm_send(sock, msg, siocb->scm); + err = scm_send(sock, msg, siocb->scm, true); if (err < 0) return err; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index d510353ef43..109e30beaa6 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1446,7 +1446,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, if (NULL == siocb->scm) siocb->scm = &tmp_scm; wait_for_unix_gc(); - err = scm_send(sock, msg, siocb->scm); + err = scm_send(sock, msg, siocb->scm, false); if (err < 0) return err; @@ -1607,7 +1607,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, if (NULL == siocb->scm) siocb->scm = &tmp_scm; wait_for_unix_gc(); - err = scm_send(sock, msg, siocb->scm); + err = scm_send(sock, msg, siocb->scm, false); if (err < 0) return err; From 912af4d4433a29aa51bcbc33c4275541d8ccc4b1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 23 Aug 2012 02:09:11 +0000 Subject: [PATCH 0844/2357] netlink: fix possible spoofing from non-root processes [ Upstream commit 20e1db19db5d6b9e4e83021595eab0dc8f107bef ] Non-root user-space processes can send Netlink messages to other processes that are well-known for being subscribed to Netlink asynchronous notifications. This allows ilegitimate non-root process to send forged messages to Netlink subscribers. The userspace process usually verifies the legitimate origin in two ways: a) Socket credentials. If UID != 0, then the message comes from some ilegitimate process and the message needs to be dropped. b) Netlink portID. In general, portID == 0 means that the origin of the messages comes from the kernel. Thus, discarding any message not coming from the kernel. However, ctnetlink sets the portID in event messages that has been triggered by some user-space process, eg. conntrack utility. So other processes subscribed to ctnetlink events, eg. conntrackd, know that the event was triggered by some user-space action. Neither of the two ways to discard ilegitimate messages coming from non-root processes can help for ctnetlink. This patch adds capability validation in case that dst_pid is set in netlink_sendmsg(). This approach is aggressive since existing applications using any Netlink bus to deliver messages between two user-space processes will break. Note that the exception is NETLINK_USERSOCK, since it is reserved for netlink-to-netlink userspace communication. Still, if anyone wants that his Netlink bus allows netlink-to-netlink userspace, then they can set NL_NONROOT_SEND. However, by default, I don't think it makes sense to allow to use NETLINK_ROUTE to communicate two processes that are sending no matter what information that is not related to link/neighbouring/routing. They should be using NETLINK_USERSOCK instead for that. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 59debb73ba7..bba6ba176ab 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1340,7 +1340,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, dst_pid = addr->nl_pid; dst_group = ffs(addr->nl_groups); err = -EPERM; - if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND)) + if ((dst_group || dst_pid) && + !netlink_capable(sock, NL_NONROOT_SEND)) goto out; } else { dst_pid = nlk->dst_pid; @@ -2115,6 +2116,7 @@ static void __init netlink_add_usersock_entry(void) rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners); nl_table[NETLINK_USERSOCK].module = THIS_MODULE; nl_table[NETLINK_USERSOCK].registered = 1; + nl_table[NETLINK_USERSOCK].nl_nonroot = NL_NONROOT_SEND; netlink_table_ungrab(); } From fbc350126994de9682e0400b969ab84437768894 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 23 Aug 2012 07:05:17 +0000 Subject: [PATCH 0845/2357] tcp: fix cwnd reduction for non-sack recovery [ Upstream commit 7c4a56fec379ac0d7754e0d4da6a7361f1a4fe64 ] The cwnd reduction in fast recovery is based on the number of packets newly delivered per ACK. For non-sack connections every DUPACK signifies a packet has been delivered, but the sender mistakenly skips counting them for cwnd reduction. The fix is to compute newly_acked_sacked after DUPACKs are accounted in sacked_out for non-sack connections. Signed-off-by: Yuchung Cheng Acked-by: Nandita Dukkipati Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 56a9c8d0bef..3acebbd15ba 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3037,13 +3037,14 @@ static void tcp_update_cwnd_in_recovery(struct sock *sk, int newly_acked_sacked, * tcp_xmit_retransmit_queue(). */ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, - int newly_acked_sacked, bool is_dupack, + int prior_sacked, bool is_dupack, int flag) { struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) && (tcp_fackets_out(tp) > tp->reordering)); + int newly_acked_sacked = 0; int fast_rexmit = 0, mib_idx; if (WARN_ON(!tp->packets_out && tp->sacked_out)) @@ -3103,6 +3104,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, tcp_add_reno_sack(sk); } else do_lost = tcp_try_undo_partial(sk, pkts_acked); + newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked; break; case TCP_CA_Loss: if (flag & FLAG_DATA_ACKED) @@ -3124,6 +3126,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, if (is_dupack) tcp_add_reno_sack(sk); } + newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked; if (icsk->icsk_ca_state <= TCP_CA_Disorder) tcp_try_undo_dsack(sk); @@ -3695,7 +3698,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) int prior_packets; int prior_sacked = tp->sacked_out; int pkts_acked = 0; - int newly_acked_sacked = 0; int frto_cwnd = 0; /* If the ack is older than previous acks @@ -3768,8 +3770,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una); pkts_acked = prior_packets - tp->packets_out; - newly_acked_sacked = (prior_packets - prior_sacked) - - (tp->packets_out - tp->sacked_out); if (tp->frto_counter) frto_cwnd = tcp_process_frto(sk, flag); @@ -3783,7 +3783,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) tcp_may_raise_cwnd(sk, flag)) tcp_cong_avoid(sk, ack, prior_in_flight); is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); - tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked, + tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, is_dupack, flag); } else { if ((flag & FLAG_DATA_ACKED) && !frto_cwnd) @@ -3798,7 +3798,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) no_queue: /* If data was DSACKed, see if we can undo a cwnd reduction. */ if (flag & FLAG_DSACKING_ACK) - tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked, + tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, is_dupack, flag); /* If this ack opens up a zero window, clear backoff. It was * being used to time the probes, and is probably far higher than @@ -3818,8 +3818,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) */ if (TCP_SKB_CB(skb)->sacked) { flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una); - newly_acked_sacked = tp->sacked_out - prior_sacked; - tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked, + tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, is_dupack, flag); } From fa1dcb6f0d338629cf1e3939227135ce0ea17b50 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 15 Aug 2012 18:09:15 +0100 Subject: [PATCH 0846/2357] sfc: Fix reporting of IPv4 full filters through ethtool [ Upstream commit ac70b2e9a13423b5efa0178e081936ce6979aea5 ] ETHTOOL_GRXCLSRULE returns filters for a TCP/IPv4 or UDP/IPv4 4-tuple with source and destination swapped. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index b7b37d46a60..ff64def0ffd 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -863,8 +863,8 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, &ip_entry->ip4dst, &ip_entry->pdst); if (rc != 0) { rc = efx_filter_get_ipv4_full( - &spec, &proto, &ip_entry->ip4src, &ip_entry->psrc, - &ip_entry->ip4dst, &ip_entry->pdst); + &spec, &proto, &ip_entry->ip4dst, &ip_entry->pdst, + &ip_entry->ip4src, &ip_entry->psrc); EFX_WARN_ON_PARANOID(rc); ip_mask->ip4src = ~0; ip_mask->psrc = ~0; From c5ca1d03c29df5dc550f71bd1669af8bc30e32f8 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 23 Aug 2012 21:46:25 +0000 Subject: [PATCH 0847/2357] gianfar: fix default tx vlan offload feature flag [ Upstream commit e2c53be223aca36cf93eb6a0f6bafa079e78f52b ] Commit - "b852b72 gianfar: fix bug caused by 87c288c6e9aa31720b72e2bc2d665e24e1653c3e" disables by default (on mac init) the hw vlan tag insertion. The "features" flags were not updated to reflect this, and "ethtool -K" shows tx-vlan-offload to be "on" by default. Cc: Sebastian Poehn Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 24381e1298e..0819a740384 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1037,7 +1037,7 @@ static int gfar_probe(struct platform_device *ofdev) if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->features |= NETIF_F_HW_VLAN_RX; } if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) { From fae286b0e547ed0379d93ace7664ea6f55cce0e0 Mon Sep 17 00:00:00 2001 From: "xeb@mail.ru" Date: Fri, 24 Aug 2012 01:07:38 +0000 Subject: [PATCH 0848/2357] l2tp: avoid to use synchronize_rcu in tunnel free function [ Upstream commit 99469c32f79a32d8481f87be0d3c66dad286f4ec ] Avoid to use synchronize_rcu in l2tp_tunnel_free because context may be atomic. Signed-off-by: Dmitry Kozlov Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 3 +-- net/l2tp/l2tp_core.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 89ff8c67943..7501b22b9c5 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1253,11 +1253,10 @@ static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) /* Remove from tunnel list */ spin_lock_bh(&pn->l2tp_tunnel_list_lock); list_del_rcu(&tunnel->list); + kfree_rcu(tunnel, rcu); spin_unlock_bh(&pn->l2tp_tunnel_list_lock); - synchronize_rcu(); atomic_dec(&l2tp_tunnel_count); - kfree(tunnel); } /* Create a socket for the tunnel, if one isn't set up by diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index a16a48e79fa..439379484bf 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -157,6 +157,7 @@ struct l2tp_tunnel_cfg { struct l2tp_tunnel { int magic; /* Should be L2TP_TUNNEL_MAGIC */ + struct rcu_head rcu; rwlock_t hlist_lock; /* protect session_hlist */ struct hlist_head session_hlist[L2TP_HASH_SIZE]; /* hashed list of sessions, From b9d798a996cddfc4c1045e9af97ee434ccab4956 Mon Sep 17 00:00:00 2001 From: Francesco Ruggeri Date: Fri, 24 Aug 2012 07:38:35 +0000 Subject: [PATCH 0849/2357] net: ipv4: ipmr_expire_timer causes crash when removing net namespace [ Upstream commit acbb219d5f53821b2d0080d047800410c0420ea1 ] When tearing down a net namespace, ipv4 mr_table structures are freed without first deactivating their timers. This can result in a crash in run_timer_softirq. This patch mimics the corresponding behaviour in ipv6. Locking and synchronization seem to be adequate. We are about to kfree mrt, so existing code should already make sure that no other references to mrt are pending or can be created by incoming traffic. The functions invoked here do not cause new references to mrt or other race conditions to be created. Invoking del_timer_sync guarantees that ipmr_expire_timer is inactive. Both ipmr_expire_process (whose completion we may have to wait in del_timer_sync) and mroute_clean_tables internally use mfc_unres_lock or other synchronizations when needed, and they both only modify mrt. Tested in Linux 3.4.8. Signed-off-by: Francesco Ruggeri Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 960fbfc3e97..8626b645ec6 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -124,6 +124,8 @@ static DEFINE_SPINLOCK(mfc_unres_lock); static struct kmem_cache *mrt_cachep __read_mostly; static struct mr_table *ipmr_new_table(struct net *net, u32 id); +static void ipmr_free_table(struct mr_table *mrt); + static int ip_mr_forward(struct net *net, struct mr_table *mrt, struct sk_buff *skb, struct mfc_cache *cache, int local); @@ -131,6 +133,7 @@ static int ipmr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, vifi_t vifi, int assert); static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); +static void mroute_clean_tables(struct mr_table *mrt); static void ipmr_expire_process(unsigned long arg); #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES @@ -271,7 +274,7 @@ static void __net_exit ipmr_rules_exit(struct net *net) list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { list_del(&mrt->list); - kfree(mrt); + ipmr_free_table(mrt); } fib_rules_unregister(net->ipv4.mr_rules_ops); } @@ -299,7 +302,7 @@ static int __net_init ipmr_rules_init(struct net *net) static void __net_exit ipmr_rules_exit(struct net *net) { - kfree(net->ipv4.mrt); + ipmr_free_table(net->ipv4.mrt); } #endif @@ -336,6 +339,13 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) return mrt; } +static void ipmr_free_table(struct mr_table *mrt) +{ + del_timer_sync(&mrt->ipmr_expire_timer); + mroute_clean_tables(mrt); + kfree(mrt); +} + /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) From 6cacd608448898cf0b7bb4353e1a92c6dc7d5dd9 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Sun, 26 Aug 2012 00:35:45 +0000 Subject: [PATCH 0850/2357] bnx2x: fix 57840_MF pci id [ Upstream commit 5c879d2094946081af934739850c7260e8b25d3c ] Commit c3def943c7117d42caaed3478731ea7c3c87190e have added support for new pci ids of the 57840 board, while failing to change the obsolete value in 'pci_ids.h'. This patch does so, allowing the probe of such devices. Signed-off-by: Yuval Mintz Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- include/linux/pci_ids.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3329965ed63..19ca550ff66 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2148,7 +2148,7 @@ #define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 #define PCI_DEVICE_ID_NX2_57800_VF 0x16a9 #define PCI_DEVICE_ID_NX2_5706S 0x16aa -#define PCI_DEVICE_ID_NX2_57840_MF 0x16ab +#define PCI_DEVICE_ID_NX2_57840_MF 0x16a4 #define PCI_DEVICE_ID_NX2_5708S 0x16ac #define PCI_DEVICE_ID_NX2_57840_VF 0x16ad #define PCI_DEVICE_ID_NX2_57810_MF 0x16ae From 2ff0cd9f615bae1de9d812de92eff6426aad26c9 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 25 May 2012 11:29:30 -0700 Subject: [PATCH 0851/2357] openvswitch: Reset upper layer protocol info on internal devices. [ Upstream commit 7fe99e2d434eafeac0c57b279a77e5de39212636 ] It's possible that packets that are sent on internal devices (from the OVS perspective) have already traversed the local IP stack. After they go through the internal device, they will again travel through the IP stack which may get confused by the presence of existing information in the skb. The problem can be observed when switching between namespaces. This clears out that information to avoid problems but deliberately leaves other metadata alone. This is to provide maximum flexibility in chaining together OVS and other Linux components. Signed-off-by: Jesse Gross Signed-off-by: Greg Kroah-Hartman --- net/openvswitch/vport-internal_dev.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index b6b1d7daa3c..ce5348f5f60 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -24,6 +24,9 @@ #include #include +#include +#include + #include "datapath.h" #include "vport-internal_dev.h" #include "vport-netdev.h" @@ -209,6 +212,11 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb) int len; len = skb->len; + + skb_dst_drop(skb); + nf_reset(skb); + secpath_reset(skb); + skb->dev = netdev; skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, netdev); From fc7da7e1c4356e4ffc7c30423325b7f0da3311b2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 18 Sep 2012 12:48:43 -0700 Subject: [PATCH 0852/2357] workqueue: reimplement work_on_cpu() using system_wq commit ed48ece27cd3d5ee0354c32bbaec0f3e1d4715c3 upstream. The existing work_on_cpu() implementation is hugely inefficient. It creates a new kthread, execute that single function and then let the kthread die on each invocation. Now that system_wq can handle concurrent executions, there's no advantage of doing this. Reimplement work_on_cpu() using system_wq which makes it simpler and way more efficient. stable: While this isn't a fix in itself, it's needed to fix a workqueue related bug in cpufreq/powernow-k8. AFAICS, this shouldn't break other existing users. Signed-off-by: Tejun Heo Acked-by: Jiri Kosina Cc: Linus Torvalds Cc: Bjorn Helgaas Cc: Len Brown Cc: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- kernel/workqueue.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index bfe3f8a1fc3..f483dd0bc9c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3620,18 +3620,17 @@ static int __devinit workqueue_cpu_down_callback(struct notifier_block *nfb, #ifdef CONFIG_SMP struct work_for_cpu { - struct completion completion; + struct work_struct work; long (*fn)(void *); void *arg; long ret; }; -static int do_work_for_cpu(void *_wfc) +static void work_for_cpu_fn(struct work_struct *work) { - struct work_for_cpu *wfc = _wfc; + struct work_for_cpu *wfc = container_of(work, struct work_for_cpu, work); + wfc->ret = wfc->fn(wfc->arg); - complete(&wfc->completion); - return 0; } /** @@ -3646,19 +3645,11 @@ static int do_work_for_cpu(void *_wfc) */ long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg) { - struct task_struct *sub_thread; - struct work_for_cpu wfc = { - .completion = COMPLETION_INITIALIZER_ONSTACK(wfc.completion), - .fn = fn, - .arg = arg, - }; + struct work_for_cpu wfc = { .fn = fn, .arg = arg }; - sub_thread = kthread_create(do_work_for_cpu, &wfc, "work_for_cpu"); - if (IS_ERR(sub_thread)) - return PTR_ERR(sub_thread); - kthread_bind(sub_thread, cpu); - wake_up_process(sub_thread); - wait_for_completion(&wfc.completion); + INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn); + schedule_work_on(cpu, &wfc.work); + flush_work(&wfc.work); return wfc.ret; } EXPORT_SYMBOL_GPL(work_on_cpu); From 3b4a9ccbdc75c6c014383b8656b57afd249d65cf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 18 Sep 2012 14:24:59 -0700 Subject: [PATCH 0853/2357] cpufreq/powernow-k8: workqueue user shouldn't migrate the kworker to another CPU commit 6889125b8b4e09c5e53e6ecab3433bed1ce198c9 upstream. powernowk8_target() runs off a per-cpu work item and if the cpufreq_policy->cpu is different from the current one, it migrates the kworker to the target CPU by manipulating current->cpus_allowed. The function migrates the kworker back to the original CPU but this is still broken. Workqueue concurrency management requires the kworkers to stay on the same CPU and powernowk8_target() ends up triggerring BUG_ON(rq != this_rq()) in try_to_wake_up_local() if it contends on fidvid_mutex and sleeps. It is unclear why this bug is being reported now. Duncan says it appeared to be a regression of 3.6-rc1 and couldn't reproduce it on 3.5. Bisection seemed to point to 63d95a91 "workqueue: use @pool instead of @gcwq or @cpu where applicable" which is an non-functional change. Given that the reproduce case sometimes took upto days to trigger, it's easy to be misled while bisecting. Maybe something made contention on fidvid_mutex more likely? I don't know. This patch fixes the bug by using work_on_cpu() instead if @pol->cpu isn't the same as the current one. The code assumes that cpufreq_policy->cpu is kept online by the caller, which Rafael tells me is the case. stable: ed48ece27c ("workqueue: reimplement work_on_cpu() using system_wq") should be applied before this; otherwise, the behavior could be horrible. Signed-off-by: Tejun Heo Reported-by: Duncan <1i5t5.duncan@cox.net> Tested-by: Duncan <1i5t5.duncan@cox.net> Cc: Rafael J. Wysocki Cc: Andreas Herrmann Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=47301 Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/powernow-k8.c | 63 +++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index c0e816468e3..1a40935c85f 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -35,7 +35,6 @@ #include #include #include -#include /* for current / set_cpus_allowed() */ #include #include @@ -1139,16 +1138,23 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, return res; } -/* Driver entry point to switch to the target frequency */ -static int powernowk8_target(struct cpufreq_policy *pol, - unsigned targfreq, unsigned relation) +struct powernowk8_target_arg { + struct cpufreq_policy *pol; + unsigned targfreq; + unsigned relation; +}; + +static long powernowk8_target_fn(void *arg) { - cpumask_var_t oldmask; + struct powernowk8_target_arg *pta = arg; + struct cpufreq_policy *pol = pta->pol; + unsigned targfreq = pta->targfreq; + unsigned relation = pta->relation; struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); u32 checkfid; u32 checkvid; unsigned int newstate; - int ret = -EIO; + int ret; if (!data) return -EINVAL; @@ -1156,29 +1162,16 @@ static int powernowk8_target(struct cpufreq_policy *pol, checkfid = data->currfid; checkvid = data->currvid; - /* only run on specific CPU from here on. */ - /* This is poor form: use a workqueue or smp_call_function_single */ - if (!alloc_cpumask_var(&oldmask, GFP_KERNEL)) - return -ENOMEM; - - cpumask_copy(oldmask, tsk_cpus_allowed(current)); - set_cpus_allowed_ptr(current, cpumask_of(pol->cpu)); - - if (smp_processor_id() != pol->cpu) { - printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); - goto err_out; - } - if (pending_bit_stuck()) { printk(KERN_ERR PFX "failing targ, change pending bit set\n"); - goto err_out; + return -EIO; } pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", pol->cpu, targfreq, pol->min, pol->max, relation); if (query_current_values_with_pending_wait(data)) - goto err_out; + return -EIO; if (cpu_family != CPU_HW_PSTATE) { pr_debug("targ: curr fid 0x%x, vid 0x%x\n", @@ -1196,7 +1189,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate)) - goto err_out; + return -EIO; mutex_lock(&fidvid_mutex); @@ -1209,9 +1202,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, ret = transition_frequency_fidvid(data, newstate); if (ret) { printk(KERN_ERR PFX "transition frequency failed\n"); - ret = 1; mutex_unlock(&fidvid_mutex); - goto err_out; + return 1; } mutex_unlock(&fidvid_mutex); @@ -1220,12 +1212,25 @@ static int powernowk8_target(struct cpufreq_policy *pol, data->powernow_table[newstate].index); else pol->cur = find_khz_freq_from_fid(data->currfid); - ret = 0; -err_out: - set_cpus_allowed_ptr(current, oldmask); - free_cpumask_var(oldmask); - return ret; + return 0; +} + +/* Driver entry point to switch to the target frequency */ +static int powernowk8_target(struct cpufreq_policy *pol, + unsigned targfreq, unsigned relation) +{ + struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq, + .relation = relation }; + + /* + * Must run on @pol->cpu. cpufreq core is responsible for ensuring + * that we're bound to the current CPU and pol->cpu stays online. + */ + if (smp_processor_id() == pol->cpu) + return powernowk8_target_fn(&pta); + else + return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta); } /* Driver entry point to verify the policy and range of frequencies */ From f2742791b906afefa8f20906824d594e56afa20c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Fri, 14 Sep 2012 16:35:10 -0500 Subject: [PATCH 0854/2357] cciss: fix handling of protocol error commit 2453f5f992717251cfadab6184fbb3ec2f2e8b40 upstream. If a command completes with a status of CMD_PROTOCOL_ERR, this information should be conveyed to the SCSI mid layer, not dropped on the floor. Unlike a similar bug in the hpsa driver, this bug only affects tape drives and CD and DVD ROM drives in the cciss driver, and to induce it, you have to disconnect (or damage) a cable, so it is not a very likely scenario (which would explain why the bug has gone undetected for the last 10 years.) Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/cciss_scsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 38aa6dda6b8..da3311129a0 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -795,6 +795,7 @@ static void complete_scsi_command(CommandList_struct *c, int timeout, } break; case CMD_PROTOCOL_ERR: + cmd->result = DID_ERROR << 16; dev_warn(&h->pdev->dev, "%p has protocol error\n", c); break; From 5975bc201acbe121eaf22ee41076a08b92abc26f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 14 Sep 2012 14:48:21 -0700 Subject: [PATCH 0855/2357] vfs: make O_PATH file descriptors usable for 'fstat()' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 55815f70147dcfa3ead5738fd56d3574e2e3c1c2 upstream. We already use them for openat() and friends, but fstat() also wants to be able to use O_PATH file descriptors. This should make it more directly comparable to the O_SEARCH of Solaris. Note that you could already do the same thing with "fstatat()" and an empty path, but just doing "fstat()" directly is simpler and faster, so there is no reason not to just allow it directly. See also commit 332a2e1244bd, which did the same thing for fchdir, for the same reasons. Reported-by: ольга крыжановская Cc: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/stat.c b/fs/stat.c index c733dc5753a..dc6d0be300c 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -57,7 +57,7 @@ EXPORT_SYMBOL(vfs_getattr); int vfs_fstat(unsigned int fd, struct kstat *stat) { - struct file *f = fget(fd); + struct file *f = fget_raw(fd); int error = -EBADF; if (f) { From f92e8b0ddb85dfe7d8d2547516c873ec8dd9838e Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 17 Sep 2012 22:31:38 +0200 Subject: [PATCH 0856/2357] vfs: dcache: use DCACHE_DENTRY_KILLED instead of DCACHE_DISCONNECTED in d_kill() commit b161dfa6937ae46d50adce8a7c6b12233e96e7bd upstream. IBM reported a soft lockup after applying the fix for the rename_lock deadlock. Commit c83ce989cb5f ("VFS: Fix the nfs sillyrename regression in kernel 2.6.38") was found to be the culprit. The nfs sillyrename fix used DCACHE_DISCONNECTED to indicate that the dentry was killed. This flag can be set on non-killed dentries too, which results in infinite retries when trying to traverse the dentry tree. This patch introduces a separate flag: DCACHE_DENTRY_KILLED, which is only set in d_kill() and makes try_to_ascend() test only this flag. IBM reported successful test results with this patch. Signed-off-by: Miklos Szeredi Cc: Trond Myklebust Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/dcache.c | 4 ++-- include/linux/dcache.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index b80531c9177..10fab266627 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -373,7 +373,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) * Inform try_to_ascend() that we are no longer attached to the * dentry tree */ - dentry->d_flags |= DCACHE_DISCONNECTED; + dentry->d_flags |= DCACHE_DENTRY_KILLED; if (parent) spin_unlock(&parent->d_lock); dentry_iput(dentry); @@ -1030,7 +1030,7 @@ static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq * or deletion */ if (new != old->d_parent || - (old->d_flags & DCACHE_DISCONNECTED) || + (old->d_flags & DCACHE_DENTRY_KILLED) || (!locked && read_seqretry(&rename_lock, seq))) { spin_unlock(&new->d_lock); new = NULL; diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 7e11f141820..1332df02d8f 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -191,6 +191,8 @@ struct dentry_operations { #define DCACHE_MANAGED_DENTRY \ (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) +#define DCACHE_DENTRY_KILLED 0x100000 + extern seqlock_t rename_lock; static inline int dname_external(struct dentry *dentry) From 25941570aadb0f03270acab13bab1378eec5ea21 Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Sat, 18 Aug 2012 07:02:20 +0000 Subject: [PATCH 0857/2357] netconsole: remove a redundant netconsole_target_put() commit 72d3eb13b5c0abe7d63efac41f39c5b644c7bbaa upstream. This netconsole_target_put() is obviously redundant, and it causes a kernel segfault when removing a bridge device which has netconsole running on it. This is caused by: commit 8d8fc29d02a33e4bd5f4fa47823c1fd386346093 Author: Amerigo Wang Date: Thu May 19 21:39:10 2011 +0000 netpoll: disable netpoll when enslave a device Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/netconsole.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index f9347ea3d38..63ffbdfe36c 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -648,7 +648,6 @@ static int netconsole_netdev_event(struct notifier_block *this, flags); dev_put(nt->np.dev); nt->np.dev = NULL; - netconsole_target_put(nt); } nt->enabled = 0; stopped = true; From 2d4d5e8eefbfb75feac2f2d98b70399f4c5c09a5 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 13 Sep 2012 12:00:56 -0700 Subject: [PATCH 0858/2357] eCryptfs: Copy up attributes of the lower target inode after rename commit 8335eafc2859e1a26282bef7c3d19f3d68868b8a upstream. After calling into the lower filesystem to do a rename, the lower target inode's attributes were not copied up to the eCryptfs target inode. This resulted in the eCryptfs target inode staying around, rather than being evicted, because i_nlink was not updated for the eCryptfs inode. This also meant that eCryptfs didn't do the final iput() on the lower target inode so it stayed around, as well. This would result in a failure to free up space occupied by the target file in the rename() operation. Both target inodes would eventually be evicted when the eCryptfs filesystem was unmounted. This patch calls fsstack_copy_attr_all() after the lower filesystem does its ->rename() so that important inode attributes, such as i_nlink, are updated at the eCryptfs layer. ecryptfs_evict_inode() is now called and eCryptfs can drop its final reference on the lower inode. http://launchpad.net/bugs/561129 Signed-off-by: Tyler Hicks Tested-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/inode.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index ab35b113003..6f5fb1a0d90 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -621,6 +621,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; struct dentry *trap = NULL; + struct inode *target_inode; lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); @@ -628,6 +629,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); + target_inode = new_dentry->d_inode; trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { @@ -643,6 +645,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (rc) goto out_lock; + if (target_inode) + fsstack_copy_attr_all(target_inode, + ecryptfs_inode_to_lower(target_inode)); fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); From a18a65bd69dfdb28e729f22f9ca171fa81544dc4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 16 Aug 2012 15:33:10 -0700 Subject: [PATCH 0859/2357] target: Fix ->data_length re-assignment bug with SCSI overflow commit 4c054ba63ad47ef244cfcfa1cea38134620a5bae upstream. This patch fixes a long-standing bug with SCSI overflow handling where se_cmd->data_length was incorrectly being re-assigned to the larger CDB extracted allocation length, resulting in a number of fabric level errors that would end up causing a session reset in most cases. So instead now: - Only re-assign se_cmd->data_length durining UNDERFLOW (to use the smaller value) - Use existing se_cmd->data_length for OVERFLOW (to use the smaller value) This fix has been tested with the following CDB to generate an SCSI overflow: sg_raw -r512 /dev/sdc 28 0 0 0 0 0 0 0 9 0 Tested using iscsi-target, tcm_qla2xxx, loopback and tcm_vhost fabric ports. Here is a bit more detail on each case: - iscsi-target: Bug with open-iscsi with overflow, sg_raw returns -3584 bytes of data. - tcm_qla2xxx: Working as expected, returnins 512 bytes of data - loopback: sg_raw returns CHECK_CONDITION, from overflow rejection in transport_generic_map_mem_to_cmd() - tcm_vhost: Same as loopback Reported-by: Roland Dreier Cc: Roland Dreier Cc: Christoph Hellwig Cc: Boaz Harrosh Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_transport.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 222f1c5ff94..d594460ed98 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3167,15 +3167,20 @@ static int transport_generic_cmd_sequencer( /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ goto out_invalid_cdb_field; } - + /* + * For the overflow case keep the existing fabric provided + * ->data_length. Otherwise for the underflow case, reset + * ->data_length to the smaller SCSI expected data transfer + * length. + */ if (size > cmd->data_length) { cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; cmd->residual_count = (size - cmd->data_length); } else { cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; cmd->residual_count = (cmd->data_length - size); + cmd->data_length = size; } - cmd->data_length = size; } if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB && From 3518fd322d6b13b278830cc41e26d6011c3641fa Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 16 Aug 2012 18:55:44 +0100 Subject: [PATCH 0860/2357] ARM: 7496/1: hw_breakpoint: don't rely on dfsr to show watchpoint access type commit bf8801145c01ab600f8df66e8c879ac642fa5846 upstream. From ARM debug architecture v7.1 onwards, a watchpoint exception causes the DFAR to be updated with the faulting data address. However, DFSR.WnR takes an UNKNOWN value and therefore cannot be used in general to determine the access type that triggered the watchpoint. This patch forbids watchpoints without an overflow handler from specifying a specific access type (load/store). Those with overflow handlers must be able to handle false positives potentially triggered by a watchpoint of a different access type on the same address. For SIGTRAP-based handlers (i.e. ptrace), this should have no impact. Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/hw_breakpoint.c | 55 ++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index ba386bd9410..18d39ea4c02 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -159,6 +159,12 @@ static int debug_arch_supported(void) arch >= ARM_DEBUG_ARCH_V7_1; } +/* Can we determine the watchpoint access type from the fsr? */ +static int debug_exception_updates_fsr(void) +{ + return 0; +} + /* Determine number of WRP registers available. */ static int get_num_wrp_resources(void) { @@ -619,18 +625,35 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) info->address &= ~alignment_mask; info->ctrl.len <<= offset; - /* - * Currently we rely on an overflow handler to take - * care of single-stepping the breakpoint when it fires. - * In the case of userspace breakpoints on a core with V7 debug, - * we can use the mismatch feature as a poor-man's hardware - * single-step, but this only works for per-task breakpoints. - */ - if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) || - !core_has_mismatch_brps() || !bp->hw.bp_target)) { - pr_warning("overflow handler required but none found\n"); - ret = -EINVAL; + if (!bp->overflow_handler) { + /* + * Mismatch breakpoints are required for single-stepping + * breakpoints. + */ + if (!core_has_mismatch_brps()) + return -EINVAL; + + /* We don't allow mismatch breakpoints in kernel space. */ + if (arch_check_bp_in_kernelspace(bp)) + return -EPERM; + + /* + * Per-cpu breakpoints are not supported by our stepping + * mechanism. + */ + if (!bp->hw.bp_target) + return -EINVAL; + + /* + * We only support specific access types if the fsr + * reports them. + */ + if (!debug_exception_updates_fsr() && + (info->ctrl.type == ARM_BREAKPOINT_LOAD || + info->ctrl.type == ARM_BREAKPOINT_STORE)) + return -EINVAL; } + out: return ret; } @@ -706,10 +729,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr, goto unlock; /* Check that the access type matches. */ - access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W : - HW_BREAKPOINT_R; - if (!(access & hw_breakpoint_type(wp))) - goto unlock; + if (debug_exception_updates_fsr()) { + access = (fsr & ARM_FSR_ACCESS_MASK) ? + HW_BREAKPOINT_W : HW_BREAKPOINT_R; + if (!(access & hw_breakpoint_type(wp))) + goto unlock; + } /* We have a winner. */ info->trigger = addr; From dab510cf4641187bf69e1b5e1be014848c1b473f Mon Sep 17 00:00:00 2001 From: David Brown Date: Tue, 4 Sep 2012 21:36:37 +0100 Subject: [PATCH 0861/2357] ARM: 7513/1: Make sure dtc is built before running it commit 70b0476a2394de4f4e32e0b67288d80ff71ca963 upstream. 'make dtbs' in a clean tree will try running the dtc before actually building it. Make these rules depend upon the scripts to build it. Signed-off-by: David Brown Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 047a20780fc..1d6402cbf4b 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -283,10 +283,10 @@ zImage Image xipImage bootpImage uImage: vmlinux zinstall uinstall install: vmlinux $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ -%.dtb: +%.dtb: scripts $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ -dtbs: +dtbs: scripts $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ # We use MRPROPER_FILES and CLEAN_FILES now From eff605bb6c699aae80b199010f0beb26563fc399 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 7 Sep 2012 18:21:44 +0100 Subject: [PATCH 0862/2357] ARM: 7526/1: traps: send SIGILL if get_user fails on undef handling path commit 2b2040af0b64cd93e5d4df2494c4486cf604090d upstream. get_user may fail to load from the provided __user address due to an unhandled fault generated by the access. In the case of the undefined instruction trap, this results in failure to load the faulting instruction, in which case we should send SIGILL to the task rather than continue with potentially uninitialised data. Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/traps.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index a8ad1e34902..a53a5a3c3c2 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -388,20 +388,23 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) #endif instr = *(u32 *) pc; } else if (thumb_mode(regs)) { - get_user(instr, (u16 __user *)pc); + if (get_user(instr, (u16 __user *)pc)) + goto die_sig; if (is_wide_instruction(instr)) { unsigned int instr2; - get_user(instr2, (u16 __user *)pc+1); + if (get_user(instr2, (u16 __user *)pc+1)) + goto die_sig; instr <<= 16; instr |= instr2; } - } else { - get_user(instr, (u32 __user *)pc); + } else if (get_user(instr, (u32 __user *)pc)) { + goto die_sig; } if (call_undef_hook(regs, instr) == 0) return; +die_sig: #ifdef CONFIG_DEBUG_USER if (user_debug & UDBG_UNDEFINED) { printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n", From 8cc876def310b034ab0e0775a14d1a49472d7f5f Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 7 Sep 2012 18:22:28 +0100 Subject: [PATCH 0863/2357] ARM: 7527/1: uaccess: explicitly check __user pointer when !CPU_USE_DOMAINS commit 8404663f81d212918ff85f493649a7991209fa04 upstream. The {get,put}_user macros don't perform range checking on the provided __user address when !CPU_HAS_DOMAINS. This patch reworks the out-of-line assembly accessors to check the user address against a specified limit, returning -EFAULT if is is out of range. [will: changed get_user register allocation to match put_user] [rmk: fixed building on older ARM architectures] Reported-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/assembler.h | 8 +++++++ arch/arm/include/asm/uaccess.h | 40 +++++++++++++++++++++----------- arch/arm/lib/getuser.S | 23 +++++++++++------- arch/arm/lib/putuser.S | 6 +++++ 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 03fb93621d0..5c8b3bf4d82 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -320,4 +320,12 @@ .size \name , . - \name .endm + .macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req +#ifndef CONFIG_CPU_USE_DOMAINS + adds \tmp, \addr, #\size - 1 + sbcccs \tmp, \tmp, \limit + bcs \bad +#endif + .endm + #endif /* __ASM_ASSEMBLER_H__ */ diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 71f6536d17a..0a070e98625 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -101,28 +101,39 @@ extern int __get_user_1(void *); extern int __get_user_2(void *); extern int __get_user_4(void *); -#define __get_user_x(__r2,__p,__e,__s,__i...) \ +#define __GUP_CLOBBER_1 "lr", "cc" +#ifdef CONFIG_CPU_USE_DOMAINS +#define __GUP_CLOBBER_2 "ip", "lr", "cc" +#else +#define __GUP_CLOBBER_2 "lr", "cc" +#endif +#define __GUP_CLOBBER_4 "lr", "cc" + +#define __get_user_x(__r2,__p,__e,__l,__s) \ __asm__ __volatile__ ( \ __asmeq("%0", "r0") __asmeq("%1", "r2") \ + __asmeq("%3", "r1") \ "bl __get_user_" #__s \ : "=&r" (__e), "=r" (__r2) \ - : "0" (__p) \ - : __i, "cc") + : "0" (__p), "r" (__l) \ + : __GUP_CLOBBER_##__s) #define get_user(x,p) \ ({ \ + unsigned long __limit = current_thread_info()->addr_limit - 1; \ register const typeof(*(p)) __user *__p asm("r0") = (p);\ register unsigned long __r2 asm("r2"); \ + register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ case 1: \ - __get_user_x(__r2, __p, __e, 1, "lr"); \ - break; \ + __get_user_x(__r2, __p, __e, __l, 1); \ + break; \ case 2: \ - __get_user_x(__r2, __p, __e, 2, "r3", "lr"); \ + __get_user_x(__r2, __p, __e, __l, 2); \ break; \ case 4: \ - __get_user_x(__r2, __p, __e, 4, "lr"); \ + __get_user_x(__r2, __p, __e, __l, 4); \ break; \ default: __e = __get_user_bad(); break; \ } \ @@ -135,31 +146,34 @@ extern int __put_user_2(void *, unsigned int); extern int __put_user_4(void *, unsigned int); extern int __put_user_8(void *, unsigned long long); -#define __put_user_x(__r2,__p,__e,__s) \ +#define __put_user_x(__r2,__p,__e,__l,__s) \ __asm__ __volatile__ ( \ __asmeq("%0", "r0") __asmeq("%2", "r2") \ + __asmeq("%3", "r1") \ "bl __put_user_" #__s \ : "=&r" (__e) \ - : "0" (__p), "r" (__r2) \ + : "0" (__p), "r" (__r2), "r" (__l) \ : "ip", "lr", "cc") #define put_user(x,p) \ ({ \ + unsigned long __limit = current_thread_info()->addr_limit - 1; \ register const typeof(*(p)) __r2 asm("r2") = (x); \ register const typeof(*(p)) __user *__p asm("r0") = (p);\ + register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ case 1: \ - __put_user_x(__r2, __p, __e, 1); \ + __put_user_x(__r2, __p, __e, __l, 1); \ break; \ case 2: \ - __put_user_x(__r2, __p, __e, 2); \ + __put_user_x(__r2, __p, __e, __l, 2); \ break; \ case 4: \ - __put_user_x(__r2, __p, __e, 4); \ + __put_user_x(__r2, __p, __e, __l, 4); \ break; \ case 8: \ - __put_user_x(__r2, __p, __e, 8); \ + __put_user_x(__r2, __p, __e, __l, 8); \ break; \ default: __e = __put_user_bad(); break; \ } \ diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index 11093a7c3e3..9b06bb41fca 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -16,8 +16,9 @@ * __get_user_X * * Inputs: r0 contains the address + * r1 contains the address limit, which must be preserved * Outputs: r0 is the error code - * r2, r3 contains the zero-extended value + * r2 contains the zero-extended value * lr corrupted * * No other registers must be altered. (see @@ -27,33 +28,39 @@ * Note also that it is intended that __get_user_bad is not global. */ #include +#include #include #include ENTRY(__get_user_1) + check_uaccess r0, 1, r1, r2, __get_user_bad 1: TUSER(ldrb) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__get_user_1) ENTRY(__get_user_2) -#ifdef CONFIG_THUMB2_KERNEL -2: TUSER(ldrb) r2, [r0] -3: TUSER(ldrb) r3, [r0, #1] + check_uaccess r0, 2, r1, r2, __get_user_bad +#ifdef CONFIG_CPU_USE_DOMAINS +rb .req ip +2: ldrbt r2, [r0], #1 +3: ldrbt rb, [r0], #0 #else -2: TUSER(ldrb) r2, [r0], #1 -3: TUSER(ldrb) r3, [r0] +rb .req r0 +2: ldrb r2, [r0] +3: ldrb rb, [r0, #1] #endif #ifndef __ARMEB__ - orr r2, r2, r3, lsl #8 + orr r2, r2, rb, lsl #8 #else - orr r2, r3, r2, lsl #8 + orr r2, rb, r2, lsl #8 #endif mov r0, #0 mov pc, lr ENDPROC(__get_user_2) ENTRY(__get_user_4) + check_uaccess r0, 4, r1, r2, __get_user_bad 4: TUSER(ldr) r2, [r0] mov r0, #0 mov pc, lr diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S index 7db25990c58..3d73dcb959b 100644 --- a/arch/arm/lib/putuser.S +++ b/arch/arm/lib/putuser.S @@ -16,6 +16,7 @@ * __put_user_X * * Inputs: r0 contains the address + * r1 contains the address limit, which must be preserved * r2, r3 contains the value * Outputs: r0 is the error code * lr corrupted @@ -27,16 +28,19 @@ * Note also that it is intended that __put_user_bad is not global. */ #include +#include #include #include ENTRY(__put_user_1) + check_uaccess r0, 1, r1, ip, __put_user_bad 1: TUSER(strb) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__put_user_1) ENTRY(__put_user_2) + check_uaccess r0, 2, r1, ip, __put_user_bad mov ip, r2, lsr #8 #ifdef CONFIG_THUMB2_KERNEL #ifndef __ARMEB__ @@ -60,12 +64,14 @@ ENTRY(__put_user_2) ENDPROC(__put_user_2) ENTRY(__put_user_4) + check_uaccess r0, 4, r1, ip, __put_user_bad 4: TUSER(str) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__put_user_4) ENTRY(__put_user_8) + check_uaccess r0, 8, r1, ip, __put_user_bad #ifdef CONFIG_THUMB2_KERNEL 5: TUSER(str) r2, [r0] 6: TUSER(str) r3, [r0, #4] From 6252fbdc0a40c20a21b24d7bfccf3c08ea9b10dc Mon Sep 17 00:00:00 2001 From: "Dae S. Kim" Date: Fri, 31 Aug 2012 02:00:51 +0200 Subject: [PATCH 0864/2357] Staging: Android alarm: IOCTL command encoding fix commit 6bd4a5d96c08dc2380f8053b1bd4f879f55cd3c9 upstream. Fixed a bug. Data was being written to user space using an IOCTL command encoded with _IOC_WRITE access mode. Signed-off-by: Dae S. Kim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/android_alarm.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h index 6eecbde2ef6..66b6e3decc6 100644 --- a/drivers/staging/android/android_alarm.h +++ b/drivers/staging/android/android_alarm.h @@ -110,10 +110,12 @@ enum android_alarm_return_flags { #define ANDROID_ALARM_WAIT _IO('a', 1) #define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size) +#define ALARM_IOR(c, type, size) _IOR('a', (c) | ((type) << 4), size) + /* Set alarm */ #define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec) #define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec) -#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec) +#define ANDROID_ALARM_GET_TIME(type) ALARM_IOR(4, type, struct timespec) #define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec) #define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0))) #define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4) From 4dbbba47b19e4e2902a3b5115569e97c210c3297 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Aug 2012 09:03:15 +0100 Subject: [PATCH 0865/2357] ARM: Fix ioremap() of address zero commit a849088aa1552b1a28eea3daff599ee22a734ae3 upstream. Murali Nalajala reports a regression that ioremapping address zero results in an oops dump: Unable to handle kernel paging request at virtual address fa200000 pgd = d4f80000 [fa200000] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 Tainted: G W (3.4.0-g3b5f728-00009-g638207a #13) PC is at msm_pm_config_rst_vector_before_pc+0x8/0x30 LR is at msm_pm_boot_config_before_pc+0x18/0x20 pc : [] lr : [] psr: a0000093 sp : c0837ef0 ip : cfe00000 fp : 0000000d r10: da7efc17 r9 : 225c4278 r8 : 00000006 r7 : 0003c000 r6 : c085c824 r5 : 00000001 r4 : fa101000 r3 : fa200000 r2 : c095080c r1 : 002250fc r0 : 00000000 Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5387d Table: 25180059 DAC: 00000015 [] (msm_pm_config_rst_vector_before_pc+0x8/0x30) from [] (msm_pm_boot_config_before_pc+0x18/0x20) [] (msm_pm_boot_config_before_pc+0x18/0x20) from [] (msm_pm_power_collapse+0x410/0xb04) [] (msm_pm_power_collapse+0x410/0xb04) from [] (arch_idle+0x294/0x3e0) [] (arch_idle+0x294/0x3e0) from [] (default_idle+0x18/0x2c) [] (default_idle+0x18/0x2c) from [] (cpu_idle+0x90/0xe4) [] (cpu_idle+0x90/0xe4) from [] (rest_init+0x88/0xa0) [] (rest_init+0x88/0xa0) from [] (start_kernel+0x3a8/0x40c) Code: c0704256 e12fff1e e59f2020 e5923000 (e5930000) This is caused by the 'reserved' entries which we insert (see 19b52abe3c5d7 - ARM: 7438/1: fill possible PMD empty section gaps) which get matched for physical address zero. Resolve this by marking these reserved entries with a different flag. Tested-by: Murali Nalajala Acked-by: Nicolas Pitre Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/mm/mm.h | 3 +++ arch/arm/mm/mmu.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 27f4a619b35..d3f25c9aaf8 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -55,6 +55,9 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page /* permanent static mappings from iotable_init() */ #define VM_ARM_STATIC_MAPPING 0x40000000 +/* empty mapping */ +#define VM_ARM_EMPTY_MAPPING 0x20000000 + /* mapping type (attributes) for permanent static mappings */ #define VM_ARM_MTYPE(mt) ((mt) << 20) #define VM_ARM_MTYPE_MASK (0x1f << 20) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 75f9f9d6709..7d419193d49 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -805,7 +805,7 @@ static void __init pmd_empty_section_gap(unsigned long addr) vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm)); vm->addr = (void *)addr; vm->size = SECTION_SIZE; - vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; + vm->flags = VM_IOREMAP | VM_ARM_EMPTY_MAPPING; vm->caller = pmd_empty_section_gap; vm_area_add_early(vm); } @@ -818,7 +818,7 @@ static void __init fill_pmd_gaps(void) /* we're still single threaded hence no lock needed here */ for (vm = vmlist; vm; vm = vm->next) { - if (!(vm->flags & VM_ARM_STATIC_MAPPING)) + if (!(vm->flags & (VM_ARM_STATIC_MAPPING | VM_ARM_EMPTY_MAPPING))) continue; addr = (unsigned long)vm->addr; if (addr < next) From 68983b9dae341fbca6b74be02248adb86e105818 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Sep 2012 10:10:11 +0200 Subject: [PATCH 0866/2357] ALSA: hda - Fix missing Master volume for STAC9200/925x commit ab548d2dba63ba947287965e525cc02a15d9853d upstream. With the commit [2faa3bf: ALSA: hda - Rewrite the mute-LED hook with vmaster hook in patch_sigmatel.c], the former Master volume control was converted to PCM. This was supposed to be covered by the vmaster control. But due to the lack of "PCM" slave definition, this didn't happen properly. The patch fixes the missing entry. Reported-by: Andrew Shadura Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index fd533124417..04cd44fa224 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1072,7 +1072,7 @@ static struct snd_kcontrol_new stac_smux_mixer = { static const char * const slave_pfxs[] = { "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", "IEC958", + "Headphone", "Speaker", "IEC958", "PCM", NULL }; From 6172ace501d10b1c629c5e82af26d0b87773c1ef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Sep 2012 09:39:31 +0200 Subject: [PATCH 0867/2357] ALSA: hda - Fix Oops at codec reset/reconfig commit 07dc59f0988cb54fd87bd373b3b27eb2401dd811 upstream. snd_hda_codec_reset() calls restore_pincfgs() where the codec is powered up again, which eventually tries to resume and initialize via the callbacks of the codec. However, it's the place just after codec free callback, thus no codec callbacks should be called after that. On a codec like CS4206, it results in Oops due to the access in init callback. This patch fixes the issue by clearing the codec callbacks properly after freeing codec. Reported-by: Daniel J Blueman Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 926b455392c..cec747998e5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2279,6 +2279,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) } if (codec->patch_ops.free) codec->patch_ops.free(codec); + memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); snd_hda_jack_tbl_clear(codec); codec->proc_widget_hook = NULL; codec->spec = NULL; @@ -2292,7 +2293,6 @@ int snd_hda_codec_reset(struct hda_codec *codec) codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; - memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); codec->slave_dig_outs = NULL; codec->spdif_status_reset = 0; module_put(codec->owner); From 23b5a5da4f07b887adce9b42daa7aa14a72a5427 Mon Sep 17 00:00:00 2001 From: Matteo Frigo Date: Wed, 12 Sep 2012 10:12:06 -0400 Subject: [PATCH 0868/2357] ALSA: ice1724: Use linear scale for AK4396 volume control. commit 3737e2be505d872bf2b3c1cd4151b2d2b413d7b5 upstream. The AK4396 DAC has a linear-scale attentuator, but sound/pci/ice1712/prodigy_hifi.c used a log scale instead, which is not quite right. This patch restores the correct scale, borrowing from the ak4396 code in sound/pci/oxygen/oxygen.c. Signed-off-by: Matteo Frigo Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/ice1712/prodigy_hifi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 764cc93dbca..075d5aa1fee 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -297,6 +297,7 @@ static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem } static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); +static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = { { @@ -307,7 +308,7 @@ static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = { .info = ak4396_dac_vol_info, .get = ak4396_dac_vol_get, .put = ak4396_dac_vol_put, - .tlv = { .p = db_scale_wm_dac }, + .tlv = { .p = ak4396_db_scale }, }, }; From 4386363312d70a764a376f1635467bab8e26965a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Sep 2012 07:44:11 +0200 Subject: [PATCH 0869/2357] ALSA: hda - Workaround for silent output on VAIO Z with ALC889 commit e427c2375646789ecd0ccaef1a1e41458559ab2d upstream. On recent kernels, Realtek codec parser tries to optimize the routing aggressively and take the headphone output as primary at first. This caused a regression on VAIO Z with ALC889, the silent output from the speaker. The problem seems that the speaker pin must be connected to the first DAC (0x02) on this machine by some reason although the codec itself advertises the flexible routing with any DACs. This patch adds a fix-up for choosing the speaker pin as the primary so that the right DAC is assigned on this device. Reported-and-tested-by: Adam Williamson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + sound/pci/hda/patch_realtek.c | 22 +++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 286ec04d138..82dd174396d 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -47,6 +47,7 @@ ALC882/883/885/888/889 acer-aspire-4930g Acer Aspire 4930G/5930G/6530G/6930G/7730G acer-aspire-8930g Acer Aspire 8330G/6935G acer-aspire Acer Aspire others + no-primary-hp VAIO Z workaround (for fixed speaker DAC) ALC861/660 ========== diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 152d91b7e10..52e7a45f6e5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -188,6 +188,7 @@ struct alc_spec { unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ + unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ /* auto-mute control */ int automute_mode; @@ -4365,7 +4366,8 @@ static int alc_parse_auto_config(struct hda_codec *codec, return 0; /* can't find valid BIOS pin config */ } - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && + if (!spec->no_primary_hp && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->line_outs <= cfg->hp_outs) { /* use HP as primary out */ cfg->speaker_outs = cfg->line_outs; @@ -5076,6 +5078,7 @@ enum { ALC889_FIXUP_DAC_ROUTE, ALC889_FIXUP_MBP_VREF, ALC889_FIXUP_IMAC91_VREF, + ALC882_FIXUP_NO_PRIMARY_HP, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -5199,6 +5202,17 @@ static void alc889_fixup_imac91_vref(struct hda_codec *codec, spec->keep_vref_in_automute = 1; } +/* Don't take HP output as primary + * strangely, the speaker output doesn't work on VAIO Z through DAC 0x05 + */ +static void alc882_fixup_no_primary_hp(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action == ALC_FIXUP_ACT_PRE_PROBE) + spec->no_primary_hp = 1; +} + static const struct alc_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { .type = ALC_FIXUP_PINS, @@ -5381,6 +5395,10 @@ static const struct alc_fixup alc882_fixups[] = { .chained = true, .chain_id = ALC882_FIXUP_GPIO1, }, + [ALC882_FIXUP_NO_PRIMARY_HP] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc882_fixup_no_primary_hp, + }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -5415,6 +5433,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC), SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), + SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), /* All Apple entries are in codec SSIDs */ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), @@ -5455,6 +5474,7 @@ static const struct alc_model_fixup alc882_fixup_models[] = { {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"}, {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"}, {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, + {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"}, {} }; From 18e64a0a0dfc533ab56f7aa198316b4ea11adca9 Mon Sep 17 00:00:00 2001 From: Christopher Brannon Date: Sat, 16 Jun 2012 16:55:20 -0500 Subject: [PATCH 0870/2357] Staging: speakup: fix an improperly-declared variable. commit 4ea418b8b2fa8a70d0fcc8231b65e67b3a72984b upstream. A local static variable was declared as a pointer to a string constant. We're assigning to the underlying memory, so it needs to be an array instead. Signed-off-by: Christopher Brannon Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c index 92b34e29ad0..40e2488b967 100644 --- a/drivers/staging/speakup/main.c +++ b/drivers/staging/speakup/main.c @@ -1854,7 +1854,7 @@ static void speakup_bits(struct vc_data *vc) static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key) { - static u_char *goto_buf = "\0\0\0\0\0\0"; + static u_char goto_buf[8]; static int num; int maxlen, go_pos; char *cp; From 6d4960ed8247d763e9022bda9f068fec7000af3f Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Wed, 29 Aug 2012 16:58:45 -0500 Subject: [PATCH 0871/2357] staging: zcache: fix cleancache race condition with shrinker commit 6d7d9798ad5c97ee4e911dd070dc12dc5ae55bd0 upstream. This patch fixes a race condition that results in memory corruption when using cleancache. The race exists between the zcache shrinker handler, shrink_zcache_memory() and cleancache_get_page(). In most cases, the shrinker will both evict a zbpg from its buddy list and flush it from tmem before a cleancache_get_page() occurs on that page. A subsequent cleancache_get_page() will fail in the tmem layer. In the rare case that two occur together and the cleancache_get_page() path gets through the tmem layer before the shrinker path can flush tmem, zbud_decompress() does a check to see if the zbpg is a "zombie", i.e. not on a buddy list, which means the shrinker is in the process of reclaiming it. If the zbpg is a zombie, zbud_decompress() returns -EINVAL. However, this return code is being ignored by the caller, zcache_pampd_get_data_and_free(), which results in the caller of cleancache_get_page() thinking that the page has been properly retrieved when it has not. This patch modifies zcache_pampd_get_data_and_free() to convey the failure up the stack so that the caller of cleancache_get_page() knows the page retrieval failed. This needs to be applied to stable trees as well. zcache-main.c was named zcache.c before v3.1, so I'm not sure how you want to handle trees earlier than that. Signed-off-by: Seth Jennings Reviewed-by: Konrad Rzeszutek Wilk Reviewed-by: Minchan Kim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/zcache/zcache-main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index 2734dacacba..1812bedab32 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c @@ -1259,13 +1259,12 @@ static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw, void *pampd, struct tmem_pool *pool, struct tmem_oid *oid, uint32_t index) { - int ret = 0; - BUG_ON(!is_ephemeral(pool)); - zbud_decompress((struct page *)(data), pampd); + if (zbud_decompress((struct page *)(data), pampd) < 0) + return -EINVAL; zbud_free_and_delist((struct zbud_hdr *)pampd); atomic_dec(&zcache_curr_eph_pampd_count); - return ret; + return 0; } /* From 191ee4172f0a89b85ce1daad00d88f33b66e07e6 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 29 Aug 2012 23:08:21 +0100 Subject: [PATCH 0872/2357] staging: vt6656: [BUG] - Failed connection, incorrect endian. commit aa209eef3ce8419ff2926c2fa944dfbfb5afbacb upstream. Hi, This patch fixes a bug with driver failing to negotiate a connection. The bug was traced to commit 203e4615ee9d9fa8d3506b9d0ef30095e4d5bc90 staging: vt6656: removed custom definitions of Ethernet packet types In that patch, definitions in include/linux/if_ether.h replaced ones in tether.h which had both big and little endian definitions. include/linux/if_ether.h only refers to big endian values, cpu_to_be16 should be used for the correct endian architectures. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/dpc.c | 2 +- drivers/staging/vt6656/rxtx.c | 38 +++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c index c0edf97535d..08021f4d523 100644 --- a/drivers/staging/vt6656/dpc.c +++ b/drivers/staging/vt6656/dpc.c @@ -200,7 +200,7 @@ s_vProcessRxMACHeader ( } else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) { cbHeaderSize += 6; pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize); - if ((*pwType == cpu_to_le16(ETH_P_IPX)) || + if ((*pwType == cpu_to_be16(ETH_P_IPX)) || (*pwType == cpu_to_le16(0xF380))) { cbHeaderSize -= 8; pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize); diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index 9b64b102f55..fe218689a0a 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -1701,7 +1701,7 @@ s_bPacketToWirelessUsb( // 802.1H if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) { if (pDevice->dwDiagRefCount == 0) { - if ((psEthHeader->wType == cpu_to_le16(ETH_P_IPX)) || + if ((psEthHeader->wType == cpu_to_be16(ETH_P_IPX)) || (psEthHeader->wType == cpu_to_le16(0xF380))) { memcpy((PBYTE) (pbyPayloadHead), abySNAP_Bridgetunnel, 6); @@ -2840,10 +2840,10 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) Packet_Type = skb->data[ETH_HLEN+1]; Descriptor_type = skb->data[ETH_HLEN+1+1+2]; Key_info = (skb->data[ETH_HLEN+1+1+2+1] << 8)|(skb->data[ETH_HLEN+1+1+2+2]); - if (pDevice->sTxEthHeader.wType == cpu_to_le16(ETH_P_PAE)) { - /* 802.1x OR eapol-key challenge frame transfer */ - if (((Protocol_Version == 1) || (Protocol_Version == 2)) && - (Packet_Type == 3)) { + if (pDevice->sTxEthHeader.wType == cpu_to_be16(ETH_P_PAE)) { + /* 802.1x OR eapol-key challenge frame transfer */ + if (((Protocol_Version == 1) || (Protocol_Version == 2)) && + (Packet_Type == 3)) { bTxeapol_key = TRUE; if(!(Key_info & BIT3) && //WPA or RSN group-key challenge (Key_info & BIT8) && (Key_info & BIT9)) { //send 2/2 key @@ -2989,19 +2989,19 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) } } - if (pDevice->sTxEthHeader.wType == cpu_to_le16(ETH_P_PAE)) { - if (pDevice->byBBType != BB_TYPE_11A) { - pDevice->wCurrentRate = RATE_1M; - pDevice->byACKRate = RATE_1M; - pDevice->byTopCCKBasicRate = RATE_1M; - pDevice->byTopOFDMBasicRate = RATE_6M; - } else { - pDevice->wCurrentRate = RATE_6M; - pDevice->byACKRate = RATE_6M; - pDevice->byTopCCKBasicRate = RATE_1M; - pDevice->byTopOFDMBasicRate = RATE_6M; - } - } + if (pDevice->sTxEthHeader.wType == cpu_to_be16(ETH_P_PAE)) { + if (pDevice->byBBType != BB_TYPE_11A) { + pDevice->wCurrentRate = RATE_1M; + pDevice->byACKRate = RATE_1M; + pDevice->byTopCCKBasicRate = RATE_1M; + pDevice->byTopOFDMBasicRate = RATE_6M; + } else { + pDevice->wCurrentRate = RATE_6M; + pDevice->byACKRate = RATE_6M; + pDevice->byTopCCKBasicRate = RATE_1M; + pDevice->byTopOFDMBasicRate = RATE_6M; + } + } DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dma_tx: pDevice->wCurrentRate = %d\n", @@ -3017,7 +3017,7 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) if (bNeedEncryption == TRUE) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.wType)); - if ((pDevice->sTxEthHeader.wType) == cpu_to_le16(ETH_P_PAE)) { + if ((pDevice->sTxEthHeader.wType) == cpu_to_be16(ETH_P_PAE)) { bNeedEncryption = FALSE; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Pkt Type=%04x\n", (pDevice->sTxEthHeader.wType)); if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) { From 8fae345eec6e2fff49e634b108f3318d88205c6c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 10 Sep 2012 21:22:11 +0200 Subject: [PATCH 0873/2357] staging: r8712u: fix bug in r8712_recv_indicatepkt() commit abf02cfc179bb4bd30d05f582d61b3b8f429b813 upstream. 64bit arches have a buggy r8712u driver, let's fix it. skb->tail must be set properly or network stack behavior is undefined. Addresses https://bugzilla.redhat.com/show_bug.cgi?id=847525 Addresses https://bugzilla.kernel.org/show_bug.cgi?id=45071 Signed-off-by: Eric Dumazet Cc: Dave Jones Acked-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/recv_linux.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c index 0e26d5f6cf2..495ee1205e0 100644 --- a/drivers/staging/rtl8712/recv_linux.c +++ b/drivers/staging/rtl8712/recv_linux.c @@ -117,13 +117,8 @@ void r8712_recv_indicatepkt(struct _adapter *padapter, if (skb == NULL) goto _recv_indicatepkt_drop; skb->data = precv_frame->u.hdr.rx_data; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb->tail = (sk_buff_data_t)(precv_frame->u.hdr.rx_tail - - precv_frame->u.hdr.rx_head); -#else - skb->tail = (sk_buff_data_t)precv_frame->u.hdr.rx_tail; -#endif skb->len = precv_frame->u.hdr.len; + skb_set_tail_pointer(skb, skb->len); if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1)) skb->ip_summed = CHECKSUM_UNNECESSARY; else From 8ef2b61115a3baeb3dc60782af32a3f6c46ed7a4 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 31 Aug 2012 20:41:30 +0100 Subject: [PATCH 0874/2357] staging: comedi: das08: Correct AO output for das08jr-16-ao commit 61ed59ed09e6ad2b8395178ea5ad5f653bba08e3 upstream. Don't zero out bits 15..12 of the data value in `das08jr_ao_winsn()` as that knobbles the upper three-quarters of the output range for the 'das08jr-16-ao' board. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/das08.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index c2dd0ed36a7..d2dd75e2af7 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -653,7 +653,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev, int chan; lsb = data[0] & 0xff; - msb = (data[0] >> 8) & 0xf; + msb = (data[0] >> 8) & 0xff; chan = CR_CHAN(insn->chanspec); From 125c4c2a41ac9249b54602db68b81a5ad398bbb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Tue, 11 Sep 2012 09:40:31 +0200 Subject: [PATCH 0875/2357] USB: option: replace ZTE K5006-Z entry with vendor class rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ba9edaa468869a8cea242a411066b0f490751798 upstream. Fix the ZTE K5006-Z entry so that it actually matches anything commit f1b5c997 USB: option: add ZTE K5006-Z added a device specific entry assuming that the device would use class/subclass/proto == ff/ff/ff like other ZTE devices. It turns out that ZTE has started using vendor specific subclass and protocol codes: T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=19d2 ProdID=1018 Rev= 0.00 S: Manufacturer=ZTE,Incorporated S: Product=ZTE LTE Technologies MSM S: SerialNumber=MF821Vxxxxxxx C:* #Ifs= 5 Cfg#= 1 Atr=c0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=86 Prot=10 Driver=(none) E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=02 Prot=05 Driver=(none) E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=02 Prot=01 Driver=(none) E: Ad=83(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=06 Prot=00 Driver=qmi_wwan E: Ad=85(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 4 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms We do not have any information on how ZTE intend to use these codes, but let us assume for now that the 3 sets matching serial functions in the K5006-Z always will identify a serial function in a ZTE device. Cc: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ee693ccfdeb..a49099da93e 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -886,8 +886,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, @@ -1092,6 +1090,10 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, + { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) }, + { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */ From 2ad98b042313307859bf2f332b95b6588ec0ba0d Mon Sep 17 00:00:00 2001 From: Francesco Ruggeri Date: Thu, 13 Sep 2012 15:03:37 -0700 Subject: [PATCH 0876/2357] fs/proc: fix potential unregister_sysctl_table hang commit 6bf6104573482570f7103d3e5ddf9574db43a363 upstream. The unregister_sysctl_table() function hangs if all references to its ctl_table_header structure are not dropped. This can happen sometimes because of a leak in proc_sys_lookup(): proc_sys_lookup() gets a reference to the table via lookup_entry(), but it does not release it when a subsequent call to sysctl_follow_link() fails. This patch fixes this leak by making sure the reference is always dropped on return. See also commit 076c3eed2c31 ("sysctl: Rewrite proc_sys_lookup introducing find_entry and lookup_entry") which reorganized this code in 3.4. Tested in Linux 3.4.4. Signed-off-by: Francesco Ruggeri Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/proc_sysctl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 21d836f4029..ab5352101db 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -462,9 +462,6 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, err = ERR_PTR(-ENOMEM); inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p); - if (h) - sysctl_head_finish(h); - if (!inode) goto out; @@ -473,6 +470,8 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, d_add(dentry, inode); out: + if (h) + sysctl_head_finish(h); sysctl_head_finish(head); return err; } From 9b52a3b313497af37dcdba4ba4c0c95809db525c Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 24 Aug 2012 21:20:15 -0600 Subject: [PATCH 0877/2357] sound: tegra_alc5632: remove HP detect GPIO inversion commit c921928661eda599d73a6a86e58bdd5aecfa18cb upstream. Both the schematics and practical testing show that the HP detect GPIO is high when the headphones are plugged in. Hence, the snd_soc_jack_gpio should not specify to invert the signal. Signed-off-by: Stephen Warren Acked-by: Andrey Danin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/tegra/tegra_alc5632.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index e45ccd851f6..76d759ec40a 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -95,7 +95,6 @@ static struct snd_soc_jack_gpio tegra_alc5632_hp_jack_gpio = { .name = "Headset detection", .report = SND_JACK_HEADSET, .debounce_time = 150, - .invert = 1, }; static const struct snd_soc_dapm_widget tegra_alc5632_dapm_widgets[] = { From d156b47c4242843096e4a13f8ace5a0626bde3e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Aug 2012 14:59:25 +0100 Subject: [PATCH 0878/2357] perf_event: Switch to internal refcount, fix race with close() commit a6fa941d94b411bbd2b6421ffbde6db3c93e65ab upstream. Don't mess with file refcounts (or keep a reference to file, for that matter) in perf_event. Use explicit refcount of its own instead. Deal with the race between the final reference to event going away and new children getting created for it by use of atomic_long_inc_not_zero() in inherit_event(); just have the latter free what it had allocated and return NULL, that works out just fine (children of siblings of something doomed are created as singletons, same as if the child of leader had been created and immediately killed). Signed-off-by: Al Viro Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20120820135925.GG23464@ZenIV.linux.org.uk Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- include/linux/perf_event.h | 2 +- kernel/events/core.c | 62 ++++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ddbb6a901f6..f18d537fd4b 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -925,7 +925,7 @@ struct perf_event { struct hw_perf_event hw; struct perf_event_context *ctx; - struct file *filp; + atomic_long_t refcount; /* * These accumulate total time (in nanoseconds) that children diff --git a/kernel/events/core.c b/kernel/events/core.c index fd126f82b57..228fdb042fa 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2929,12 +2929,12 @@ EXPORT_SYMBOL_GPL(perf_event_release_kernel); /* * Called when the last reference to the file is gone. */ -static int perf_release(struct inode *inode, struct file *file) +static void put_event(struct perf_event *event) { - struct perf_event *event = file->private_data; struct task_struct *owner; - file->private_data = NULL; + if (!atomic_long_dec_and_test(&event->refcount)) + return; rcu_read_lock(); owner = ACCESS_ONCE(event->owner); @@ -2969,7 +2969,13 @@ static int perf_release(struct inode *inode, struct file *file) put_task_struct(owner); } - return perf_event_release_kernel(event); + perf_event_release_kernel(event); +} + +static int perf_release(struct inode *inode, struct file *file) +{ + put_event(file->private_data); + return 0; } u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) @@ -3222,7 +3228,7 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg) static const struct file_operations perf_fops; -static struct perf_event *perf_fget_light(int fd, int *fput_needed) +static struct file *perf_fget_light(int fd, int *fput_needed) { struct file *file; @@ -3236,7 +3242,7 @@ static struct perf_event *perf_fget_light(int fd, int *fput_needed) return ERR_PTR(-EBADF); } - return file->private_data; + return file; } static int perf_event_set_output(struct perf_event *event, @@ -3268,19 +3274,21 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case PERF_EVENT_IOC_SET_OUTPUT: { + struct file *output_file = NULL; struct perf_event *output_event = NULL; int fput_needed = 0; int ret; if (arg != -1) { - output_event = perf_fget_light(arg, &fput_needed); - if (IS_ERR(output_event)) - return PTR_ERR(output_event); + output_file = perf_fget_light(arg, &fput_needed); + if (IS_ERR(output_file)) + return PTR_ERR(output_file); + output_event = output_file->private_data; } ret = perf_event_set_output(event, output_event); if (output_event) - fput_light(output_event->filp, fput_needed); + fput_light(output_file, fput_needed); return ret; } @@ -5920,6 +5928,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, mutex_init(&event->mmap_mutex); + atomic_long_set(&event->refcount, 1); event->cpu = cpu; event->attr = *attr; event->group_leader = group_leader; @@ -6230,12 +6239,12 @@ SYSCALL_DEFINE5(perf_event_open, return event_fd; if (group_fd != -1) { - group_leader = perf_fget_light(group_fd, &fput_needed); - if (IS_ERR(group_leader)) { - err = PTR_ERR(group_leader); + group_file = perf_fget_light(group_fd, &fput_needed); + if (IS_ERR(group_file)) { + err = PTR_ERR(group_file); goto err_fd; } - group_file = group_leader->filp; + group_leader = group_file->private_data; if (flags & PERF_FLAG_FD_OUTPUT) output_event = group_leader; if (flags & PERF_FLAG_FD_NO_GROUP) @@ -6370,7 +6379,6 @@ SYSCALL_DEFINE5(perf_event_open, put_ctx(gctx); } - event->filp = event_file; WARN_ON_ONCE(ctx->parent_ctx); mutex_lock(&ctx->mutex); @@ -6460,7 +6468,6 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, goto err_free; } - event->filp = NULL; WARN_ON_ONCE(ctx->parent_ctx); mutex_lock(&ctx->mutex); perf_install_in_context(ctx, event, cpu); @@ -6509,7 +6516,7 @@ static void sync_child_event(struct perf_event *child_event, * Release the parent event, if this was the last * reference to it. */ - fput(parent_event->filp); + put_event(parent_event); } static void @@ -6585,9 +6592,8 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn) * * __perf_event_exit_task() * sync_child_event() - * fput(parent_event->filp) - * perf_release() - * mutex_lock(&ctx->mutex) + * put_event() + * mutex_lock(&ctx->mutex) * * But since its the parent context it won't be the same instance. */ @@ -6655,7 +6661,7 @@ static void perf_free_event(struct perf_event *event, list_del_init(&event->child_list); mutex_unlock(&parent->child_mutex); - fput(parent->filp); + put_event(parent); perf_group_detach(event); list_del_event(event, ctx); @@ -6735,6 +6741,12 @@ inherit_event(struct perf_event *parent_event, NULL, NULL); if (IS_ERR(child_event)) return child_event; + + if (!atomic_long_inc_not_zero(&parent_event->refcount)) { + free_event(child_event); + return NULL; + } + get_ctx(child_ctx); /* @@ -6775,14 +6787,6 @@ inherit_event(struct perf_event *parent_event, add_event_to_ctx(child_event, child_ctx); raw_spin_unlock_irqrestore(&child_ctx->lock, flags); - /* - * Get a reference to the parent filp - we will fput it - * when the child event exits. This is safe to do because - * we are in the parent and we know that the filp still - * exists and has a nonzero count: - */ - atomic_long_inc(&parent_event->filp->f_count); - /* * Link this into the parent event's child list */ From 2bafdfd612901af70fcea3cf1866e388eb68fdf0 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Fri, 14 Sep 2012 00:26:33 +0200 Subject: [PATCH 0879/2357] ACPI / PM: Fix resource_lock dead lock in acpi_power_on_device commit 40bf66ec9791f1452b90b82aadc3b6e6aee201f5 upstream. Commit 0090def("ACPI: Add interface to register/unregister device to/from power resources") used resource_lock to protect the devices list that relies on power resource. It caused a mutex dead lock, as below acpi_power_on ---> lock resource_lock __acpi_power_on acpi_power_on_device acpi_power_get_inferred_state acpi_power_get_list_state ---> lock resource_lock This patch adds a new mutex "devices_lock" to protect the devices list and calls acpi_power_on_device in acpi_power_on, instead of __acpi_power_on, after the resource_lock is released. [rjw: Changed data type of a boolean variable to bool.] Signed-off-by: Lin Ming Signed-off-by: Aaron Lu Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/power.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 0500f719f63..7bdb676b089 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -103,6 +103,7 @@ struct acpi_power_resource { /* List of devices relying on this power resource */ struct acpi_power_resource_device *devices; + struct mutex devices_lock; }; static struct list_head acpi_power_resource_list; @@ -221,7 +222,6 @@ static void acpi_power_on_device(struct acpi_power_managed_device *device) static int __acpi_power_on(struct acpi_power_resource *resource) { - struct acpi_power_resource_device *device_list = resource->devices; acpi_status status = AE_OK; status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); @@ -234,19 +234,15 @@ static int __acpi_power_on(struct acpi_power_resource *resource) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", resource->name)); - while (device_list) { - acpi_power_on_device(device_list->device); - - device_list = device_list->next; - } - return 0; } static int acpi_power_on(acpi_handle handle) { int result = 0; + bool resume_device = false; struct acpi_power_resource *resource = NULL; + struct acpi_power_resource_device *device_list; result = acpi_power_get_context(handle, &resource); if (result) @@ -262,10 +258,25 @@ static int acpi_power_on(acpi_handle handle) result = __acpi_power_on(resource); if (result) resource->ref_count--; + else + resume_device = true; } mutex_unlock(&resource->resource_lock); + if (!resume_device) + return result; + + mutex_lock(&resource->devices_lock); + + device_list = resource->devices; + while (device_list) { + acpi_power_on_device(device_list->device); + device_list = device_list->next; + } + + mutex_unlock(&resource->devices_lock); + return result; } @@ -351,7 +362,7 @@ static void __acpi_power_resource_unregister_device(struct device *dev, if (acpi_power_get_context(res_handle, &resource)) return; - mutex_lock(&resource->resource_lock); + mutex_lock(&resource->devices_lock); prev = NULL; curr = resource->devices; while (curr) { @@ -368,7 +379,7 @@ static void __acpi_power_resource_unregister_device(struct device *dev, prev = curr; curr = curr->next; } - mutex_unlock(&resource->resource_lock); + mutex_unlock(&resource->devices_lock); } /* Unlink dev from all power resources in _PR0 */ @@ -409,10 +420,10 @@ static int __acpi_power_resource_register_device( power_resource_device->device = powered_device; - mutex_lock(&resource->resource_lock); + mutex_lock(&resource->devices_lock); power_resource_device->next = resource->devices; resource->devices = power_resource_device; - mutex_unlock(&resource->resource_lock); + mutex_unlock(&resource->devices_lock); return 0; } @@ -715,6 +726,7 @@ static int acpi_power_add(struct acpi_device *device) resource->device = device; mutex_init(&resource->resource_lock); + mutex_init(&resource->devices_lock); strcpy(resource->name, device->pnp.bus_id); strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_POWER_CLASS); From 8889866c58f77c557e79a30853ee4fd5f50780ef Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Fri, 14 Sep 2012 20:54:44 +0200 Subject: [PATCH 0880/2357] ACPI / PM: Use KERN_DEBUG when no power resources are found commit f25b70613c048ceb1df052576fda03321ebf41cf upstream. commit a606dac368eed5696fb38e16b1394f1d049c09e9 adds support to link devices which have _PRx, if a device does not have _PRx, a warning message will be printed. This commit is for ZPODD on Intel ZPODD capable platforms, on other platforms, it has no problem if there is no power resource for this device, so a warning here is not appropriate, change it to debug. Reported-by: Borislav Petkov Signed-off-by: Aaron Lu Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 7bdb676b089..2adef535f15 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -468,7 +468,7 @@ int acpi_power_resource_register_device(struct device *dev, acpi_handle handle) return ret; no_power_resource: - printk(KERN_WARNING PREFIX "Invalid Power Resource to register!"); + printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!"); return -ENODEV; } From 3a4781e12d0e6264c76bfd110783321450138169 Mon Sep 17 00:00:00 2001 From: Lauri Hintsala Date: Tue, 17 Jul 2012 17:16:09 +0300 Subject: [PATCH 0881/2357] mmc: mxs-mmc: fix deadlock in SDIO IRQ case commit 1af36b2a993dddfa3d6860ec4879c9e8abc9b976 upstream. Release the lock before mmc_signal_sdio_irq is called by mxs_mmc_irq_handler. Backtrace: [ 79.660000] ============================================= [ 79.660000] [ INFO: possible recursive locking detected ] [ 79.660000] 3.4.0-00009-g3e96082-dirty #11 Not tainted [ 79.660000] --------------------------------------------- [ 79.660000] swapper/0 is trying to acquire lock: [ 79.660000] (&(&host->lock)->rlock#2){-.....}, at: [] mxs_mmc_enable_sdio_irq+0x18/0xd4 [ 79.660000] [ 79.660000] but task is already holding lock: [ 79.660000] (&(&host->lock)->rlock#2){-.....}, at: [] mxs_mmc_irq_handler+0x1c/0xe8 [ 79.660000] [ 79.660000] other info that might help us debug this: [ 79.660000] Possible unsafe locking scenario: [ 79.660000] [ 79.660000] CPU0 [ 79.660000] ---- [ 79.660000] lock(&(&host->lock)->rlock#2); [ 79.660000] lock(&(&host->lock)->rlock#2); [ 79.660000] [ 79.660000] *** DEADLOCK *** [ 79.660000] [ 79.660000] May be due to missing lock nesting notation [ 79.660000] [ 79.660000] 1 lock held by swapper/0: [ 79.660000] #0: (&(&host->lock)->rlock#2){-.....}, at: [] mxs_mmc_irq_handler+0x1c/0xe8 [ 79.660000] [ 79.660000] stack backtrace: [ 79.660000] [] (unwind_backtrace+0x0/0xf4) from [] (__lock_acquire+0x1948/0x1d48) [ 79.660000] [] (__lock_acquire+0x1948/0x1d48) from [] (lock_acquire+0xe0/0xf8) [ 79.660000] [] (lock_acquire+0xe0/0xf8) from [] (_raw_spin_lock_irqsave+0x44/0x58) [ 79.660000] [] (_raw_spin_lock_irqsave+0x44/0x58) from [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) [ 79.660000] [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) from [] (mxs_mmc_irq_handler+0xd4/0xe8) [ 79.660000] [] (mxs_mmc_irq_handler+0xd4/0xe8) from [] (handle_irq_event_percpu+0x70/0x254) [ 79.660000] [] (handle_irq_event_percpu+0x70/0x254) from [] (handle_irq_event+0x3c/0x5c) [ 79.660000] [] (handle_irq_event+0x3c/0x5c) from [] (handle_level_irq+0x90/0x110) [ 79.660000] [] (handle_level_irq+0x90/0x110) from [] (generic_handle_irq+0x38/0x50) [ 79.660000] [] (generic_handle_irq+0x38/0x50) from [] (handle_IRQ+0x30/0x84) [ 79.660000] [] (handle_IRQ+0x30/0x84) from [] (__irq_svc+0x38/0x60) [ 79.660000] [] (__irq_svc+0x38/0x60) from [] (default_idle+0x2c/0x40) [ 79.660000] [] (default_idle+0x2c/0x40) from [] (cpu_idle+0x64/0xcc) [ 79.660000] [] (cpu_idle+0x64/0xcc) from [] (start_kernel+0x244/0x2c8) [ 79.660000] BUG: spinlock lockup on CPU#0, swapper/0 [ 79.660000] lock: c398cb2c, .magic: dead4ead, .owner: swapper/0, .owner_cpu: 0 [ 79.660000] [] (unwind_backtrace+0x0/0xf4) from [] (do_raw_spin_lock+0xf0/0x144) [ 79.660000] [] (do_raw_spin_lock+0xf0/0x144) from [] (_raw_spin_lock_irqsave+0x4c/0x58) [ 79.660000] [] (_raw_spin_lock_irqsave+0x4c/0x58) from [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) [ 79.660000] [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) from [] (mxs_mmc_irq_handler+0xd4/0xe8) [ 79.660000] [] (mxs_mmc_irq_handler+0xd4/0xe8) from [] (handle_irq_event_percpu+0x70/0x254) [ 79.660000] [] (handle_irq_event_percpu+0x70/0x254) from [] (handle_irq_event+0x3c/0x5c) [ 79.660000] [] (handle_irq_event+0x3c/0x5c) from [] (handle_level_irq+0x90/0x110) [ 79.660000] [] (handle_level_irq+0x90/0x110) from [] (generic_handle_irq+0x38/0x50) [ 79.660000] [] (generic_handle_irq+0x38/0x50) from [] (handle_IRQ+0x30/0x84) [ 79.660000] [] (handle_IRQ+0x30/0x84) from [] (__irq_svc+0x38/0x60) [ 79.660000] [] (__irq_svc+0x38/0x60) from [] (default_idle+0x2c/0x40) [ 79.660000] [] (default_idle+0x2c/0x40) from [] (cpu_idle+0x64/0xcc) [ 79.660000] [] (cpu_idle+0x64/0xcc) from [] (start_kernel+0x244/0x2c8) Signed-off-by: Lauri Hintsala Acked-by: Shawn Guo Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/mxs-mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index e3f5af96ab8..b6def202bf4 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -280,11 +280,11 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id) writel(stat & MXS_MMC_IRQ_BITS, host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); + spin_unlock(&host->lock); + if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) mmc_signal_sdio_irq(host->mmc); - spin_unlock(&host->lock); - if (stat & BM_SSP_CTRL1_RESP_TIMEOUT_IRQ) cmd->error = -ETIMEDOUT; else if (stat & BM_SSP_CTRL1_RESP_ERR_IRQ) From e66a381518f9ebf98cdc583d20ae706aa5d1dc28 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 22 Aug 2012 23:10:01 +0800 Subject: [PATCH 0882/2357] mmc: sdhci-esdhc: break out early if clock is 0 commit 74f330bceaa7b88d06062e1cac3d519a3dfc041e upstream. Since commit 30832ab56 ("mmc: sdhci: Always pass clock request value zero to set_clock host op") was merged, esdhc_set_clock starts hitting "if (clock == 0)" where ESDHC_SYSTEM_CONTROL has been operated. This causes SDHCI card-detection function being broken. Fix the regression by moving "if (clock == 0)" above ESDHC_SYSTEM_CONTROL operation. Signed-off-by: Shawn Guo Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-esdhc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index b97b2f5dafd..d25f9ab9a54 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -48,14 +48,14 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) int div = 1; u32 temp; + if (clock == 0) + goto out; + temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - if (clock == 0) - goto out; - while (host->max_clk / pre_div / 16 > clock && pre_div < 256) pre_div *= 2; From d409354d1b8a1e47b8f29887179949ec951ffe83 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Wed, 29 Aug 2012 15:05:36 +0900 Subject: [PATCH 0883/2357] mmc: card: Skip secure erase on MoviNAND; causes unrecoverable corruption. commit 3550ccdb9d8d350e526b809bf3dd92b550a74fe1 upstream. For several MoviNAND eMMC parts, there are known issues with secure erase and secure trim. For these specific MoviNAND devices, we skip these operations. Specifically, there is a bug in the eMMC firmware that causes unrecoverable corruption when the MMC is erased with MMC_CAP_ERASE enabled. References: http://forum.xda-developers.com/showthread.php?t=1644364 https://plus.google.com/111398485184813224730/posts/21pTYfTsCkB#111398485184813224730/posts/21pTYfTsCkB Signed-off-by: Ian Chen Reviewed-by: Namjae Jeon Acked-by: Jaehoon Chung Reviewed-by: Linus Walleij Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/card/block.c | 26 +++++++++++++++++++++++++- include/linux/mmc/card.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index dabec556ebb..833ff16f5fe 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1430,7 +1430,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) /* complete ongoing async transfer before issuing discard */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - if (req->cmd_flags & REQ_SECURE) + if (req->cmd_flags & REQ_SECURE && + !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN)) ret = mmc_blk_issue_secdiscard_rq(mq, req); else ret = mmc_blk_issue_discard_rq(mq, req); @@ -1730,6 +1731,7 @@ static int mmc_add_disk(struct mmc_blk_data *md) #define CID_MANFID_SANDISK 0x2 #define CID_MANFID_TOSHIBA 0x11 #define CID_MANFID_MICRON 0x13 +#define CID_MANFID_SAMSUNG 0x15 static const struct mmc_fixup blk_fixups[] = { @@ -1766,6 +1768,28 @@ static const struct mmc_fixup blk_fixups[] = MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, MMC_QUIRK_LONG_READ_TIME), + /* + * On these Samsung MoviNAND parts, performing secure erase or + * secure trim can result in unrecoverable corruption due to a + * firmware bug. + */ + MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + END_FIXUP }; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 629b823f883..b5292f317f4 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -234,6 +234,7 @@ struct mmc_card { #define MMC_QUIRK_BLK_NO_CMD23 (1<<7) /* Avoid CMD23 for regular multiblock */ #define MMC_QUIRK_BROKEN_BYTE_MODE_512 (1<<8) /* Avoid sending 512 bytes in */ #define MMC_QUIRK_LONG_READ_TIME (1<<9) /* Data read time > CSD says */ +#define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */ /* byte mode */ unsigned int poweroff_notify_state; /* eMMC4.5 notify feature */ #define MMC_NO_POWER_NOTIFICATION 0 From 93ee70835a254181a9d9c5750e9301b70899ad90 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 19 Jul 2012 18:28:26 +0200 Subject: [PATCH 0884/2357] oprofile, s390: Fix uninitialized memory access when writing to oprofilefs commit 81ff3478d9ba7f0b48b0abef740e542fd83adf79 upstream. If oprofilefs_ulong_from_user() is called with count equals zero, *val remains unchanged. Depending on the implementation it might be uninitialized. Fixing users of oprofilefs_ulong_ from_user(). We missed these s390 changes with: 913050b oprofile: Fix uninitialized memory access when writing to writing to oprofilefs Signed-off-by: Robert Richter Signed-off-by: Greg Kroah-Hartman --- arch/s390/oprofile/init.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index 2297be406c6..abe8722adda 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c @@ -171,7 +171,7 @@ static ssize_t hw_interval_write(struct file *file, char const __user *buf, if (*offset) return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; if (val < oprofile_min_interval) oprofile_hw_interval = oprofile_min_interval; @@ -214,7 +214,7 @@ static ssize_t hwsampler_zero_write(struct file *file, char const __user *buf, return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; if (val != 0) return -EINVAL; @@ -245,7 +245,7 @@ static ssize_t hwsampler_kernel_write(struct file *file, char const __user *buf, return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; if (val != 0 && val != 1) @@ -280,7 +280,7 @@ static ssize_t hwsampler_user_write(struct file *file, char const __user *buf, return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; if (val != 0 && val != 1) @@ -319,7 +319,7 @@ static ssize_t timer_enabled_write(struct file *file, char const __user *buf, return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; if (val != 0 && val != 1) From f0868b703758f19c2ced945c2c3fce1c151ab369 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 4 Sep 2012 16:07:18 +0100 Subject: [PATCH 0885/2357] ahci: Add alternate identifier for the 88SE9172 commit 17c60c6b763cb5b83b0185e7d38d01d18e55a05a upstream. This can also appear as 0x9192. Reported in bugzilla and confirmed with the board documentation for these boards. Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=42970 Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ahci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ebaf67e4b2b..93cbc4484cc 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -396,6 +396,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { .driver_data = board_ahci_yes_fbs }, /* 88se9125 */ { PCI_DEVICE(0x1b4b, 0x917a), .driver_data = board_ahci_yes_fbs }, /* 88se9172 */ + { PCI_DEVICE(0x1b4b, 0x9192), + .driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */ { PCI_DEVICE(0x1b4b, 0x91a3), .driver_data = board_ahci_yes_fbs }, From cf499a04f9b5c8d2218257046b66b3062401673a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sun, 2 Sep 2012 15:41:34 +0200 Subject: [PATCH 0886/2357] kobject: fix oops with "input0: bad kobj_uevent_env content in show_uevent()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 60e233a56609fd963c59e99bd75c663d63fa91b6 upstream. Fengguang Wu writes: > After the __devinit* removal series, I can still get kernel panic in > show_uevent(). So there are more sources of bug.. > > Debug patch: > > @@ -343,8 +343,11 @@ static ssize_t show_uevent(struct device > goto out; > > /* copy keys to file */ > - for (i = 0; i < env->envp_idx; i++) > + dev_err(dev, "uevent %d env[%d]: %s/.../%s\n", env->buflen, env->envp_idx, top_kobj->name, dev->kobj.name); > + for (i = 0; i < env->envp_idx; i++) { > + printk(KERN_ERR "uevent %d env[%d]: %s\n", (int)count, i, env->envp[i]); > count += sprintf(&buf[count], "%s\n", env->envp[i]); > + } > > Oops message, the env[] is again not properly initilized: > > [ 44.068623] input input0: uevent 61 env[805306368]: input0/.../input0 > [ 44.069552] uevent 0 env[0]: (null) This is a completely different CONFIG_HOTPLUG problem, only demonstrating another reason why CONFIG_HOTPLUG should go away. I had a hard time trying to disable it anyway ;-) The problem this time is lots of code assuming that a call to add_uevent_var() will guarantee that env->buflen > 0. This is not true if CONFIG_HOTPLUG is unset. So things like this end up overwriting env->envp_idx because the array index is -1: if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; len = input_print_modalias(&env->buf[env->buflen - 1], sizeof(env->buf) - env->buflen, dev, 0); Don't know what the best action is, given that there seem to be a *lot* of this around the kernel. This patch "fixes" the problem for me, but I don't know if it can be considered an appropriate fix. [ It is the correct fix for now, for 3.7 forcing CONFIG_HOTPLUG to always be on is the longterm fix, but it's too late for 3.6 and older kernels to resolve this that way - gregkh ] Reported-by: Fengguang Wu Signed-off-by: Bjørn Mork Tested-by: Fengguang Wu Signed-off-by: Greg Kroah-Hartman --- include/linux/kobject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/kobject.h b/include/linux/kobject.h index fc615a97e2d..1e57449395b 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -224,7 +224,7 @@ static inline int kobject_uevent_env(struct kobject *kobj, static inline __printf(2, 3) int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) -{ return 0; } +{ return -ENOMEM; } static inline int kobject_action_type(const char *buf, size_t count, enum kobject_action *type) From e3c9398035cbf79a2ab75c2f43de999fc9a726f4 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Sun, 19 Aug 2012 14:41:03 +1200 Subject: [PATCH 0887/2357] Redefine ATOMIC_INIT and ATOMIC64_INIT to drop the casts commit 67a806d9499353fabd5b5ff07337f3aa88a1c3ba upstream. The following build error occurred during an alpha build: net/core/sock.c:274:36: error: initializer element is not constant Dave Anglin says: > Here is the line in sock.i: > > struct static_key memalloc_socks = ((struct static_key) { .enabled = > ((atomic_t) { (0) }) }); The above line contains two compound literals. It also uses a designated initializer to initialize the field enabled. A compound literal is not a constant expression. The location of the above statement isn't fully clear, but if a compound literal occurs outside the body of a function, the initializer list must consist of constant expressions. Signed-off-by: Mel Gorman Signed-off-by: Fengguang Wu Signed-off-by: Michael Cree Acked-by: Matt Turner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/alpha/include/asm/atomic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 3bb7ffeae3b..c2cbe4fc391 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -14,8 +14,8 @@ */ -#define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) -#define ATOMIC64_INIT(i) ( (atomic64_t) { (i) } ) +#define ATOMIC_INIT(i) { (i) } +#define ATOMIC64_INIT(i) { (i) } #define atomic_read(v) (*(volatile int *)&(v)->counter) #define atomic64_read(v) (*(volatile long *)&(v)->counter) From dd8121960467e40388876403758334fa91516db2 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Wed, 12 Sep 2012 13:26:55 +0300 Subject: [PATCH 0888/2357] digsig: add hash size comparision on signature verification commit bc01637a80f5b670bd70a0279d3f93fa8de1c96d upstream. When pkcs_1_v1_5_decode_emsa() returns without error and hash sizes do not match, hash comparision is not done and digsig_verify_rsa() returns no error. This is a bug and this patch fixes it. The bug was introduced in v3.3 by commit b35e286a640f ("lib/digsig: pkcs_1_v1_5_decode_emsa cleanup"). Signed-off-by: Dmitry Kasatkin Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- lib/digsig.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/digsig.c b/lib/digsig.c index 286d558033e..8c0e62975c8 100644 --- a/lib/digsig.c +++ b/lib/digsig.c @@ -163,9 +163,11 @@ static int digsig_verify_rsa(struct key *key, memcpy(out1 + head, p, l); err = pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len); + if (err) + goto err; - if (!err && len == hlen) - err = memcmp(out2, h, hlen); + if (len != hlen || memcmp(out2, h, hlen)) + err = -EINVAL; err: mpi_free(in); From 1c55a12c2a3d5b54598e7ba04e2d0fcf858b9023 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Aug 2012 16:46:12 +1000 Subject: [PATCH 0889/2357] md: Don't truncate size at 4TB for RAID0 and Linear commit 667a5313ecd7308d79629c0738b0db588b0b0a4e upstream. commit 27a7b260f71439c40546b43588448faac01adb93 md: Fix handling for devices from 2TB to 4TB in 0.90 metadata. changed 0.90 metadata handling to truncated size to 4TB as that is all that 0.90 can record. However for RAID0 and Linear, 0.90 doesn't need to record the size, so this truncation is not needed and causes working arrays to become too small. So avoid the truncation for RAID0 and Linear This bug was introduced in 3.1 and is suitable for any stable kernels from then onwards. As the offending commit was tagged for 'stable', any stable kernel that it was applied to should also get this patch. That includes at least 2.6.32, 2.6.33 and 3.0. (Thanks to Ben Hutchings for providing that list). Signed-off-by: Neil Brown Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 9ee8ce3e965..34f2c9378d0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1143,8 +1143,11 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor ret = 0; } rdev->sectors = rdev->sb_start; - /* Limit to 4TB as metadata cannot record more than that */ - if (rdev->sectors >= (2ULL << 32)) + /* Limit to 4TB as metadata cannot record more than that. + * (not needed for Linear and RAID0 as metadata doesn't + * record this size) + */ + if (rdev->sectors >= (2ULL << 32) && sb->level >= 1) rdev->sectors = (2ULL << 32) - 2; if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1) @@ -1426,7 +1429,7 @@ super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors) /* Limit to 4TB as metadata cannot record more than that. * 4TB == 2^32 KB, or 2*2^32 sectors. */ - if (num_sectors >= (2ULL << 32)) + if (num_sectors >= (2ULL << 32) && rdev->mddev->level >= 1) num_sectors = (2ULL << 32) - 2; md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size, rdev->sb_page); From d765682ea82fb83fd8d01b7663f78b5d2f9fd839 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 19 Sep 2012 12:54:22 +1000 Subject: [PATCH 0890/2357] md: make sure metadata is updated when spares are activated or removed. commit 6dafab6b1383e912cd252fa809570b484eb6e0dc upstream. It isn't always necessary to update the metadata when spares are removed as the presence-or-not of a spare isn't really important to the integrity of an array. Also activating a spare doesn't always require updating the metadata as the update on 'recovery-completed' is usually sufficient. However the introduction of 'replacement' devices have made these transitions sometimes more important. For example the 'Replacement' flag isn't cleared until the original device is removed, so we need to ensure a metadata update after that 'spare' is removed. So set MD_CHANGE_DEVS whenever a spare is activated or removed, to complement the current situation where it is set when a spare is added or a device is failed (or a number of other less common situations). This is suitable for -stable as out-of-data metadata could lead to data corruption. This is only relevant for 3.3 and later 9when 'replacement' as introduced. Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 34f2c9378d0..529ce89b30b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7420,6 +7420,8 @@ static int remove_and_add_spares(struct mddev *mddev) } } } + if (removed) + set_bit(MD_CHANGE_DEVS, &mddev->flags); return spares; } @@ -7433,9 +7435,11 @@ static void reap_sync_thread(struct mddev *mddev) !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { /* success...*/ /* activate any spares */ - if (mddev->pers->spare_active(mddev)) + if (mddev->pers->spare_active(mddev)) { sysfs_notify(&mddev->kobj, NULL, "degraded"); + set_bit(MD_CHANGE_DEVS, &mddev->flags); + } } if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && mddev->pers->finish_reshape) From 9fd0132a29b4e40e5cf5ff82a02227b7f603bba7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 19 Sep 2012 12:52:30 +1000 Subject: [PATCH 0891/2357] md/raid5: fix calculate of 'degraded' when a replacement becomes active. commit e5c86471f933608db5d43679f84cb4346c32033e upstream. When a replacement device becomes active, we mark the device that it replaces as 'faulty' so that it can subsequently get removed. However 'calc_degraded' only pays attention to the primary device, not the replacement, so the array appears to become degraded, which is wrong. So teach 'calc_degraded' to consider any replacement if a primary device is faulty. This is suitable for -stable as an incorrect 'degraded' value can confuse md and could lead to data corruption. This is only relevant for 3.3 and later. Reported-by: Robin Hill Reported-by: John Drescher Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 73a58007eb9..0240576564d 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -380,6 +380,8 @@ static int calc_degraded(struct r5conf *conf) degraded = 0; for (i = 0; i < conf->previous_raid_disks; i++) { struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); + if (rdev && test_bit(Faulty, &rdev->flags)) + rdev = rcu_dereference(conf->disks[i].replacement); if (!rdev || test_bit(Faulty, &rdev->flags)) degraded++; else if (test_bit(In_sync, &rdev->flags)) @@ -404,6 +406,8 @@ static int calc_degraded(struct r5conf *conf) degraded2 = 0; for (i = 0; i < conf->raid_disks; i++) { struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); + if (rdev && test_bit(Faulty, &rdev->flags)) + rdev = rcu_dereference(conf->disks[i].replacement); if (!rdev || test_bit(Faulty, &rdev->flags)) degraded2++; else if (test_bit(In_sync, &rdev->flags)) From 547ee164a63242ef14c41410615aa60aa164fce2 Mon Sep 17 00:00:00 2001 From: Paul Clements Date: Mon, 17 Sep 2012 14:09:02 -0700 Subject: [PATCH 0892/2357] nbd: clear waiting_queue on shutdown commit fded4e090c60100d709318896c79816d68d5b47d upstream. Fix a serious but uncommon bug in nbd which occurs when there is heavy I/O going to the nbd device while, at the same time, a failure (server, network) or manual disconnect of the nbd connection occurs. There is a small window between the time that the nbd_thread is stopped and the socket is shutdown where requests can continue to be queued to nbd's internal waiting_queue. When this happens, those requests are never completed or freed. The fix is to clear the waiting_queue on shutdown of the nbd device, in the same way that the nbd request queue (queue_head) is already being cleared. Signed-off-by: Paul Clements Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/block/nbd.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 061427a75d3..3c4c225d198 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -445,6 +445,14 @@ static void nbd_clear_que(struct nbd_device *nbd) req->errors++; nbd_end_request(req); } + + while (!list_empty(&nbd->waiting_queue)) { + req = list_entry(nbd->waiting_queue.next, struct request, + queuelist); + list_del_init(&req->queuelist); + req->errors++; + nbd_end_request(req); + } } @@ -594,6 +602,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, nbd->file = NULL; nbd_clear_que(nbd); BUG_ON(!list_empty(&nbd->queue_head)); + BUG_ON(!list_empty(&nbd->waiting_queue)); if (file) fput(file); return 0; From a4dd7e6c27a37237f09d437a515a3330093d4f70 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Sat, 1 Sep 2012 01:38:19 -0700 Subject: [PATCH 0893/2357] ASoC: samsung dma - Don't indicate support for pause/resume. commit 57b2d68863f281737d8596cb3d76d89d9cc54fd8 upstream. The pause and resume operations indicate that the stream can be un-paused/resumed from the exact location they were paused/suspended. This is not true for this driver, the pause and suspend triggers share the same code path with stop, they flush all pending DMA transfers. This drops all pending samples. The pause_release/resume triggers are the same as start, except that prepare won't be called beforehand, nothing will be enqueued to the DMA engine and nothing will happen (no audio). Removing the pause flag will let apps know that it isn't supported. Removing the resume flag will cause user space to call prepare and start instead of resume, so audio will continue playing when the system wakes up. Before removing the pause and resume flags, I tested this on an exynos 5250, using 'aplay -i'. Pause/un-pause leads to silence followed by a write error. Suspend/resume testing led to the same result. Removing the two flags fixes suspend/resume (since snd_pcm_prepare is called again). And leads to a proper reporting of pause not supported. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/samsung/dma.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index ddc6cde14e2..2526ecada5f 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -34,9 +34,7 @@ static const struct snd_pcm_hardware dma_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, + SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U8 | @@ -246,15 +244,11 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: prtd->state |= ST_RUNNING; prtd->params->ops->trigger(prtd->params->ch); break; case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: prtd->state &= ~ST_RUNNING; prtd->params->ops->stop(prtd->params->ch); break; From aa7994f281a5e705b5f9cb13b3219fc346263872 Mon Sep 17 00:00:00 2001 From: Li Haifeng Date: Mon, 17 Sep 2012 14:09:21 -0700 Subject: [PATCH 0894/2357] mm/page_alloc: fix the page address of higher page's buddy calculation commit 0ba8f2d59304dfe69b59c034de723ad80f7ab9ac upstream. The heuristic method for buddy has been introduced since commit 43506fad21ca ("mm/page_alloc.c: simplify calculation of combined index of adjacent buddy lists"). But the page address of higher page's buddy was wrongly calculated, which will lead page_is_buddy to fail for ever. IOW, the heuristic method would be disabled with the wrong page address of higher page's buddy. Calculating the page address of higher page's buddy should be based higher_page with the offset between index of higher page and index of higher page's buddy. Signed-off-by: Haifeng Li Signed-off-by: Gavin Shan Reviewed-by: Michal Hocko Cc: KyongHo Cho Cc: Mel Gorman Cc: Minchan Kim Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 918330f71db..88a6d87041d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -579,7 +579,7 @@ static inline void __free_one_page(struct page *page, combined_idx = buddy_idx & page_idx; higher_page = page + (combined_idx - page_idx); buddy_idx = __find_buddy_index(combined_idx, order + 1); - higher_buddy = page + (buddy_idx - combined_idx); + higher_buddy = higher_page + (buddy_idx - combined_idx); if (page_is_buddy(higher_page, higher_buddy, order + 1)) { list_add_tail(&page->lru, &zone->free_area[order].free_list[migratetype]); From 6093dd2f5a10b5a071aa623be7927a6421762adb Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Mon, 17 Sep 2012 14:09:17 -0700 Subject: [PATCH 0895/2357] drivers/rtc/rtc-twl.c: ensure all interrupts are disabled during probe commit 8dcebaa9a0ae8a0487f4342f3d56d2cb1c980860 upstream. On some platforms, bootloaders are known to do some interesting RTC programming. Without going into the obscurities as to why this may be the case, suffice it to say the the driver should not make any assumptions about the state of the RTC when the driver loads. In particular, the driver probe should be sure that all interrupts are disabled until otherwise programmed. This was discovered when finding bursty I2C traffic every second on Overo platforms. This I2C overhead was keeping the SoC from hitting deep power states. The cause was found to be the RTC firing every second on the I2C-connected TWL PMIC. Special thanks to Felipe Balbi for suggesting to look for a rogue driver as the source of the I2C traffic rather than the I2C driver itself. Special thanks to Steve Sakoman for helping track down the source of the continuous RTC interrups on the Overo boards. Signed-off-by: Kevin Hilman Cc: Felipe Balbi Tested-by: Steve Sakoman Cc: Alessandro Zummo Tested-by: Shubhrajyoti Datta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-twl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 258abeabf62..63ccc0f9427 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -495,6 +495,11 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) if (ret < 0) goto out1; + /* ensure interrupts are disabled, bootloaders can be strange */ + ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG); + if (ret < 0) + dev_warn(&pdev->dev, "unable to disable interrupt\n"); + /* init cached IRQ enable bits */ ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); if (ret < 0) From a95bb54b6345874159a82b93c67c49244d2433f2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 19 Jun 2012 08:00:00 -0700 Subject: [PATCH 0896/2357] hwmon: (twl4030-madc-hwmon) Initialize uninitialized structure elements commit 73d7c119255615a26070f9d6cdb722a166a29015 upstream. twl4030_madc_conversion uses do_avg and type structure elements of twl4030_madc_request. Initialize structure to avoid random operation. Fix for: Coverity CID 200794 Uninitialized scalar variable. Cc: Keerthy Signed-off-by: Guenter Roeck Acked-by: Jean Delvare Acked-by: Keerthy Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/twl4030-madc-hwmon.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index 0018c7dd009..1a174f0a3cd 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -44,12 +44,13 @@ static ssize_t madc_read(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct twl4030_madc_request req; + struct twl4030_madc_request req = { + .channels = 1 << attr->index, + .method = TWL4030_MADC_SW2, + .type = TWL4030_MADC_WAIT, + }; long val; - req.channels = (1 << attr->index); - req.method = TWL4030_MADC_SW2; - req.func_cb = NULL; val = twl4030_madc_conversion(&req); if (val < 0) return val; From 48f0f14ffb6ff4852922994d11fbda418d40100e Mon Sep 17 00:00:00 2001 From: Charles Wang Date: Mon, 20 Aug 2012 16:02:33 +0800 Subject: [PATCH 0897/2357] sched: Add missing call to calc_load_exit_idle() commit 749c8814f08f12baa4a9c2812a7c6ede7d69507d upstream. Azat Khuzhin reported high loadavg in Linux v3.6 After checking the upstream scheduler code, I found Peter's commit: 5167e8d5417b sched/nohz: Rewrite and fix load-avg computation -- again not fully applied, missing the call to calc_load_exit_idle(). After that idle exit in sampling window will always be calculated to non-idle, and the load will be higher than normal. This patch adds the missing call to calc_load_exit_idle(). Signed-off-by: Charles Wang Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1345449754-27130-1-git-send-email-muming.wq@gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/time/tick-sched.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index fd4e160aa9c..e6034779735 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -145,6 +145,7 @@ static void tick_nohz_update_jiffies(ktime_t now) tick_do_update_jiffies64(now); local_irq_restore(flags); + calc_load_exit_idle(); touch_softlockup_watchdog(); } From fea0071c60870fbebc605ef72d87668d72dbbd81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Locher?= Date: Mon, 27 Aug 2012 15:02:45 +0200 Subject: [PATCH 0898/2357] can: mcp251x: avoid repeated frame bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit cab32f39dcc5b35db96497dc0a026b5dea76e4e7 upstream. The MCP2515 has a silicon bug causing repeated frame transmission, see section 5 of MCP2515 Rev. B Silicon Errata Revision G (March 2007). Basically, setting TXBnCTRL.TXREQ in either SPI mode (00 or 11) will eventually cause the bug. The workaround proposed by Microchip is to use mode 00 and send a RTS command on the SPI bus to initiate the transmission. Signed-off-by: Benoît Locher Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/mcp251x.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 346785c56a2..9d6074273ca 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -83,6 +83,11 @@ #define INSTRUCTION_LOAD_TXB(n) (0x40 + 2 * (n)) #define INSTRUCTION_READ_RXB(n) (((n) == 0) ? 0x90 : 0x94) #define INSTRUCTION_RESET 0xC0 +#define RTS_TXB0 0x01 +#define RTS_TXB1 0x02 +#define RTS_TXB2 0x04 +#define INSTRUCTION_RTS(n) (0x80 | ((n) & 0x07)) + /* MPC251x registers */ #define CANSTAT 0x0e @@ -397,6 +402,7 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf, static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame, int tx_buf_idx) { + struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); u32 sid, eid, exide, rtr; u8 buf[SPI_TRANSFER_BUF_LEN]; @@ -418,7 +424,10 @@ static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame, buf[TXBDLC_OFF] = (rtr << DLC_RTR_SHIFT) | frame->can_dlc; memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc); mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx); - mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ); + + /* use INSTRUCTION_RTS, to avoid "repeated frame problem" */ + priv->spi_tx_buf[0] = INSTRUCTION_RTS(1 << tx_buf_idx); + mcp251x_spi_trans(priv->spi, 1); } static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf, From 32e653056d900d3ecc984733dbfcea34c92bf6d0 Mon Sep 17 00:00:00 2001 From: Jianguo Wu Date: Mon, 17 Sep 2012 14:08:56 -0700 Subject: [PATCH 0899/2357] mm/ia64: fix a memory block size bug commit 05cf96398e1b6502f9e191291b715c7463c9d5dd upstream. I found following definition in include/linux/memory.h, in my IA64 platform, SECTION_SIZE_BITS is equal to 32, and MIN_MEMORY_BLOCK_SIZE will be 0. #define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS) Because MIN_MEMORY_BLOCK_SIZE is int type and length of 32bits, so MIN_MEMORY_BLOCK_SIZE(1 << 32) will will equal to 0. Actually when SECTION_SIZE_BITS >= 31, MIN_MEMORY_BLOCK_SIZE will be wrong. This will cause wrong system memory infomation in sysfs. I think it should be: #define MIN_MEMORY_BLOCK_SIZE (1UL << SECTION_SIZE_BITS) And "echo offline > memory0/state" will cause following call trace: kernel BUG at mm/memory_hotplug.c:885! sh[6455]: bugcheck! 0 [1] Pid: 6455, CPU 0, comm: sh psr : 0000101008526030 ifs : 8000000000000fa4 ip : [] Not tainted (3.6.0-rc1) ip is at offline_pages+0x210/0xee0 Call Trace: show_stack+0x80/0xa0 show_regs+0x640/0x920 die+0x190/0x2c0 die_if_kernel+0x50/0x80 ia64_bad_break+0x3d0/0x6e0 ia64_native_leave_kernel+0x0/0x270 offline_pages+0x210/0xee0 alloc_pages_current+0x180/0x2a0 Signed-off-by: Jianguo Wu Signed-off-by: Jiang Liu Cc: "Luck, Tony" Reviewed-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/memory.h b/include/linux/memory.h index 1ac7f6e405f..ff9a9f8e0ed 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -19,7 +19,7 @@ #include #include -#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS) +#define MIN_MEMORY_BLOCK_SIZE (1UL << SECTION_SIZE_BITS) struct memory_block { unsigned long start_section_nr; From 967c0e4ab954d228ca87d85c523ae8a65c03cc5e Mon Sep 17 00:00:00 2001 From: qiuxishi Date: Mon, 17 Sep 2012 14:09:24 -0700 Subject: [PATCH 0900/2357] memory hotplug: fix section info double registration bug commit f14851af0ebb32745c6c5a2e400aa0549f9d20df upstream. There may be a bug when registering section info. For example, on my Itanium platform, the pfn range of node0 includes the other nodes, so other nodes' section info will be double registered, and memmap's page count will equal to 3. node0: start_pfn=0x100, spanned_pfn=0x20fb00, present_pfn=0x7f8a3, => 0x000100-0x20fc00 node1: start_pfn=0x80000, spanned_pfn=0x80000, present_pfn=0x80000, => 0x080000-0x100000 node2: start_pfn=0x100000, spanned_pfn=0x80000, present_pfn=0x80000, => 0x100000-0x180000 node3: start_pfn=0x180000, spanned_pfn=0x80000, present_pfn=0x80000, => 0x180000-0x200000 free_all_bootmem_node() register_page_bootmem_info_node() register_page_bootmem_info_section() When hot remove memory, we can't free the memmap's page because page_count() is 2 after put_page_bootmem(). sparse_remove_one_section() free_section_usemap() free_map_bootmem() put_page_bootmem() [akpm@linux-foundation.org: add code comment] Signed-off-by: Xishi Qiu Signed-off-by: Jiang Liu Acked-by: Mel Gorman Cc: "Luck, Tony" Cc: Yasuaki Ishimatsu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memory_hotplug.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 6629fafd6ce..9ad7d1ef6ac 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -127,9 +127,6 @@ static void register_page_bootmem_info_section(unsigned long start_pfn) struct mem_section *ms; struct page *page, *memmap; - if (!pfn_valid(start_pfn)) - return; - section_nr = pfn_to_section_nr(start_pfn); ms = __nr_to_section(section_nr); @@ -188,9 +185,16 @@ void register_page_bootmem_info_node(struct pglist_data *pgdat) end_pfn = pfn + pgdat->node_spanned_pages; /* register_section info */ - for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) - register_page_bootmem_info_section(pfn); - + for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) { + /* + * Some platforms can assign the same pfn to multiple nodes - on + * node0 as well as nodeN. To avoid registering a pfn against + * multiple nodes we check that this pfn does not already + * reside in some other node. + */ + if (pfn_valid(pfn) && (pfn_to_nid(pfn) == node)) + register_page_bootmem_info_section(pfn); + } } #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ From 449efd1d33fcf40a81f902ceed6a21a406f8d105 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Wed, 12 Sep 2012 12:44:30 +0100 Subject: [PATCH 0901/2357] xen/m2p: do not reuse kmap_op->dev_bus_addr commit 2fc136eecd0c647a6b13fcd00d0c41a1a28f35a5 upstream. If the caller passes a valid kmap_op to m2p_add_override, we use kmap_op->dev_bus_addr to store the original mfn, but dev_bus_addr is part of the interface with Xen and if we are batching the hypercalls it might not have been written by the hypervisor yet. That means that later on Xen will write to it and we'll think that the original mfn is actually what Xen has written to it. Rather than "stealing" struct members from kmap_op, keep using page->index to store the original mfn and add another parameter to m2p_remove_override to get the corresponding kmap_op instead. It is now responsibility of the caller to keep track of which kmap_op corresponds to a particular page in the m2p_override (gntdev, the only user of this interface that passes a valid kmap_op, is already doing that). Reported-and-Tested-By: Sander Eikelenboom Signed-off-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/xen/page.h | 3 ++- arch/x86/xen/p2m.c | 27 +++++++++++---------------- drivers/block/xen-blkback/blkback.c | 2 +- drivers/xen/gntdev.c | 5 +++-- drivers/xen/grant-table.c | 6 ++++-- include/xen/grant_table.h | 3 ++- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index c34f96c2f7a..1bd321d00f2 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -50,7 +50,8 @@ extern unsigned long set_phys_range_identity(unsigned long pfn_s, extern int m2p_add_override(unsigned long mfn, struct page *page, struct gnttab_map_grant_ref *kmap_op); -extern int m2p_remove_override(struct page *page, bool clear_pte); +extern int m2p_remove_override(struct page *page, + struct gnttab_map_grant_ref *kmap_op); extern struct page *m2p_find_override(unsigned long mfn); extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 00a038540c8..3ace8176947 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -714,9 +714,6 @@ int m2p_add_override(unsigned long mfn, struct page *page, xen_mc_issue(PARAVIRT_LAZY_MMU); } - /* let's use dev_bus_addr to record the old mfn instead */ - kmap_op->dev_bus_addr = page->index; - page->index = (unsigned long) kmap_op; } spin_lock_irqsave(&m2p_override_lock, flags); list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); @@ -743,7 +740,8 @@ int m2p_add_override(unsigned long mfn, struct page *page, return 0; } EXPORT_SYMBOL_GPL(m2p_add_override); -int m2p_remove_override(struct page *page, bool clear_pte) +int m2p_remove_override(struct page *page, + struct gnttab_map_grant_ref *kmap_op) { unsigned long flags; unsigned long mfn; @@ -773,10 +771,8 @@ int m2p_remove_override(struct page *page, bool clear_pte) WARN_ON(!PagePrivate(page)); ClearPagePrivate(page); - if (clear_pte) { - struct gnttab_map_grant_ref *map_op = - (struct gnttab_map_grant_ref *) page->index; - set_phys_to_machine(pfn, map_op->dev_bus_addr); + set_phys_to_machine(pfn, page->index); + if (kmap_op != NULL) { if (!PageHighMem(page)) { struct multicall_space mcs; struct gnttab_unmap_grant_ref *unmap_op; @@ -788,13 +784,13 @@ int m2p_remove_override(struct page *page, bool clear_pte) * issued. In this case handle is going to -1 because * it hasn't been modified yet. */ - if (map_op->handle == -1) + if (kmap_op->handle == -1) xen_mc_flush(); /* - * Now if map_op->handle is negative it means that the + * Now if kmap_op->handle is negative it means that the * hypercall actually returned an error. */ - if (map_op->handle == GNTST_general_error) { + if (kmap_op->handle == GNTST_general_error) { printk(KERN_WARNING "m2p_remove_override: " "pfn %lx mfn %lx, failed to modify kernel mappings", pfn, mfn); @@ -804,8 +800,8 @@ int m2p_remove_override(struct page *page, bool clear_pte) mcs = xen_mc_entry( sizeof(struct gnttab_unmap_grant_ref)); unmap_op = mcs.args; - unmap_op->host_addr = map_op->host_addr; - unmap_op->handle = map_op->handle; + unmap_op->host_addr = kmap_op->host_addr; + unmap_op->handle = kmap_op->handle; unmap_op->dev_bus_addr = 0; MULTI_grant_table_op(mcs.mc, @@ -816,10 +812,9 @@ int m2p_remove_override(struct page *page, bool clear_pte) set_pte_at(&init_mm, address, ptep, pfn_pte(pfn, PAGE_KERNEL)); __flush_tlb_single(address); - map_op->host_addr = 0; + kmap_op->host_addr = 0; } - } else - set_phys_to_machine(pfn, page->index); + } /* p2m(m2p(mfn)) == FOREIGN_FRAME(mfn): the mfn is already present * somewhere in this domain, even before being added to the diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 73f196ca713..c6decb901e5 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -337,7 +337,7 @@ static void xen_blkbk_unmap(struct pending_req *req) invcount++; } - ret = gnttab_unmap_refs(unmap, pages, invcount, false); + ret = gnttab_unmap_refs(unmap, NULL, pages, invcount); BUG_ON(ret); } diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 1ffd03bf8e1..7f124160848 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -314,8 +314,9 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) } } - err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, - pages, true); + err = gnttab_unmap_refs(map->unmap_ops + offset, + use_ptemod ? map->kmap_ops + offset : NULL, map->pages + offset, + pages); if (err) return err; diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index f100ce20b16..fda491cd53c 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -774,7 +774,8 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, EXPORT_SYMBOL_GPL(gnttab_map_refs); int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, - struct page **pages, unsigned int count, bool clear_pte) + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count) { int i, ret; @@ -786,7 +787,8 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, return ret; for (i = 0; i < count; i++) { - ret = m2p_remove_override(pages[i], clear_pte); + ret = m2p_remove_override(pages[i], kmap_ops ? + &kmap_ops[i] : NULL); if (ret) return ret; } diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index 15f8a00ff00..f0037a89f7d 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h @@ -185,6 +185,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, struct gnttab_map_grant_ref *kmap_ops, struct page **pages, unsigned int count); int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, - struct page **pages, unsigned int count, bool clear_pte); + struct gnttab_map_grant_ref *kunmap_ops, + struct page **pages, unsigned int count); #endif /* __ASM_GNTTAB_H__ */ From 02fc6e74ca8c7751b7764894fb4c9da5609c79b5 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 17 Aug 2012 10:22:37 -0400 Subject: [PATCH 0902/2357] xen/boot: Disable NUMA for PV guests. commit 8d54db795dfb1049d45dc34f0dddbc5347ec5642 upstream. The hypervisor is in charge of allocating the proper "NUMA" memory and dealing with the CPU scheduler to keep them bound to the proper NUMA node. The PV guests (and PVHVM) have no inkling of where they run and do not need to know that right now. In the future we will need to inject NUMA configuration data (if a guest spans two or more NUMA nodes) so that the kernel can make the right choices. But those patches are not yet present. In the meantime, disable the NUMA capability in the PV guest, which also fixes a bootup issue. Andre says: "we see Dom0 crashes due to the kernel detecting the NUMA topology not by ACPI, but directly from the northbridge (CONFIG_AMD_NUMA). This will detect the actual NUMA config of the physical machine, but will crash about the mismatch with Dom0's virtual memory. Variation of the theme: Dom0 sees what it's not supposed to see. This happens with the said config option enabled and on a machine where this scanning is still enabled (K8 and Fam10h, not Bulldozer class) We have this dump then: NUMA: Warning: node ids are out of bound, from=-1 to=-1 distance=10 Scanning NUMA topology in Northbridge 24 Number of physical nodes 4 Node 0 MemBase 0000000000000000 Limit 0000000040000000 Node 1 MemBase 0000000040000000 Limit 0000000138000000 Node 2 MemBase 0000000138000000 Limit 00000001f8000000 Node 3 MemBase 00000001f8000000 Limit 0000000238000000 Initmem setup node 0 0000000000000000-0000000040000000 NODE_DATA [000000003ffd9000 - 000000003fffffff] Initmem setup node 1 0000000040000000-0000000138000000 NODE_DATA [0000000137fd9000 - 0000000137ffffff] Initmem setup node 2 0000000138000000-00000001f8000000 NODE_DATA [00000001f095e000 - 00000001f0984fff] Initmem setup node 3 00000001f8000000-0000000238000000 Cannot find 159744 bytes in node 3 BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] __alloc_bootmem_node+0x43/0x96 Pid: 0, comm: swapper Not tainted 3.3.6 #1 AMD Dinar/Dinar RIP: e030:[] [] __alloc_bootmem_node+0x43/0x96 .. snip.. [] sparse_early_usemaps_alloc_node+0x64/0x178 [] sparse_init+0xe4/0x25a [] paging_init+0x13/0x22 [] setup_arch+0x9c6/0xa9b [] ? printk+0x3c/0x3e [] start_kernel+0xe5/0x468 [] x86_64_start_reservations+0xba/0xc1 [] ? xen_setup_runstate_info+0x2c/0x36 [] xen_start_kernel+0x565/0x56c " so we just disable NUMA scanning by setting numa_off=1. Reported-and-Tested-by: Andre Przywara Acked-by: Andre Przywara Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 99de967762a..017d48a26a0 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -431,4 +432,7 @@ void __init xen_arch_setup(void) disable_cpufreq(); WARN_ON(set_pm_idle_to_default()); fiddle_vdso(); +#ifdef CONFIG_NUMA + numa_off = 1; +#endif } From b5b937dae933e1997300ffa2f6c45759a849bee0 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Sun, 23 Sep 2012 20:27:32 +0200 Subject: [PATCH 0903/2357] hwmon: (fam15h_power) Tweak runavg_range on resume commit 5f0ecb907deb1e6f28071ee3bd568903b9da1be4 upstream. The quirk introduced with commit 00250ec90963b7ef6678438888f3244985ecde14 (hwmon: fam15h_power: fix bogus values with current BIOSes) is not only required during driver load but also when system resumes from suspend. The BIOS might set the previously recommended (but unsuitable) initilization value for the running average range register during resume. Signed-off-by: Andreas Herrmann Tested-by: Andreas Hartmann Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/fam15h_power.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index e8e18cab1fb..ac2d6cb39e7 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -128,12 +128,12 @@ static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4) * counter saturations resulting in bogus power readings. * We correct this value ourselves to cope with older BIOSes. */ -static DEFINE_PCI_DEVICE_TABLE(affected_device) = { +static const struct pci_device_id affected_device[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, { 0 } }; -static void __devinit tweak_runavg_range(struct pci_dev *pdev) +static void tweak_runavg_range(struct pci_dev *pdev) { u32 val; @@ -157,6 +157,16 @@ static void __devinit tweak_runavg_range(struct pci_dev *pdev) REG_TDP_RUNNING_AVERAGE, val); } +#ifdef CONFIG_PM +static int fam15h_power_resume(struct pci_dev *pdev) +{ + tweak_runavg_range(pdev); + return 0; +} +#else +#define fam15h_power_resume NULL +#endif + static void __devinit fam15h_power_init_data(struct pci_dev *f4, struct fam15h_power_data *data) { @@ -255,6 +265,7 @@ static struct pci_driver fam15h_power_driver = { .id_table = fam15h_power_id_table, .probe = fam15h_power_probe, .remove = __devexit_p(fam15h_power_remove), + .resume = fam15h_power_resume, }; static int __init fam15h_power_init(void) From 17c7900f51d4cef95f95bbf3743bc9d19075052d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 11 Sep 2012 13:39:08 -0700 Subject: [PATCH 0904/2357] hwmon: (ads7871) Add 'name' sysfs attribute commit 4e21f4eaa49f78d3e977e316514c941053871c76 upstream. The 'name' sysfs attribute is mandatory for hwmon devices, but was missing in this driver. Cc: Paul Thomas Signed-off-by: Guenter Roeck Acked-by: Jean Delvare Acked-by: Paul Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/ads7871.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c index e65c6e45d36..7bf4ce3d405 100644 --- a/drivers/hwmon/ads7871.c +++ b/drivers/hwmon/ads7871.c @@ -139,6 +139,12 @@ static ssize_t show_voltage(struct device *dev, } } +static ssize_t ads7871_show_name(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); +} + static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0); static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1); static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2); @@ -148,6 +154,8 @@ static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 5); static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6); static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7); +static DEVICE_ATTR(name, S_IRUGO, ads7871_show_name, NULL); + static struct attribute *ads7871_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, @@ -157,6 +165,7 @@ static struct attribute *ads7871_attributes[] = { &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in7_input.dev_attr.attr, + &dev_attr_name.attr, NULL }; From 3f4d6d765aedf4c52195d1d3938b6c404a2f6555 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 11 Sep 2012 13:43:17 -0700 Subject: [PATCH 0905/2357] hwmon: (ad7314) Add 'name' sysfs attribute commit 3ceefe4319636d89d4bdf40dca9471970f942e4f upstream. The 'name' sysfs attribute is mandatory for hwmon devices, but was missing in this driver. Cc: Jonathan Cameron Signed-off-by: Guenter Roeck Acked-by: Jean Delvare Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/ad7314.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index f85ce70d967..9815f9cc8f7 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c @@ -94,10 +94,18 @@ static ssize_t ad7314_show_temperature(struct device *dev, } } +static ssize_t ad7314_show_name(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); +} + +static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ad7314_show_temperature, NULL, 0); static struct attribute *ad7314_attributes[] = { + &dev_attr_name.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, NULL, }; From a3bd94a4566b2c107c3d9661076ba184af9f83ba Mon Sep 17 00:00:00 2001 From: Nestor Lopez Casado Date: Fri, 21 Sep 2012 12:21:34 +0200 Subject: [PATCH 0906/2357] HID: Fix logitech-dj: missing Unifying device issue commit 596264082f10dd4a567c43d4526b2f54ac5520bc upstream. This patch fixes an issue introduced after commit 4ea5454203d991ec ("HID: Fix race condition between driver core and ll-driver"). After that commit, hid-core discards any incoming packet that arrives while hid driver's probe function is being executed. This broke the enumeration process of hid-logitech-dj, that must receive control packets in-band with the mouse and keyboard packets. Discarding mouse or keyboard data at the very begining is usually fine, but it is not the case for control packets. This patch forces a re-enumeration of the paired devices when a packet arrives that comes from an unknown device. Based on a patch originally written by Benjamin Tissoires. Signed-off-by: Nestor Lopez Casado Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-logitech-dj.c | 41 +++++++++++++++++++++++++++++++++++ drivers/hid/hid-logitech-dj.h | 1 + 2 files changed, 42 insertions(+) diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index d44ea58c597..88d20101f85 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -185,6 +185,7 @@ static struct hid_ll_driver logi_dj_ll_driver; static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, size_t count, unsigned char report_type); +static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev); static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, struct dj_report *dj_report) @@ -225,6 +226,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & SPFUNCTION_DEVICE_LIST_EMPTY) { dbg_hid("%s: device list is empty\n", __func__); + djrcv_dev->querying_devices = false; return; } @@ -235,6 +237,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, return; } + if (djrcv_dev->paired_dj_devices[dj_report->device_index]) { + /* The device is already known. No need to reallocate it. */ + dbg_hid("%s: device is already known\n", __func__); + return; + } + dj_hiddev = hid_allocate_device(); if (IS_ERR(dj_hiddev)) { dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", @@ -298,6 +306,7 @@ static void delayedwork_callback(struct work_struct *work) struct dj_report dj_report; unsigned long flags; int count; + int retval; dbg_hid("%s\n", __func__); @@ -330,6 +339,25 @@ static void delayedwork_callback(struct work_struct *work) logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); break; default: + /* A normal report (i. e. not belonging to a pair/unpair notification) + * arriving here, means that the report arrived but we did not have a + * paired dj_device associated to the report's device_index, this + * means that the original "device paired" notification corresponding + * to this dj_device never arrived to this driver. The reason is that + * hid-core discards all packets coming from a device while probe() is + * executing. */ + if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) { + /* ok, we don't know the device, just re-ask the + * receiver for the list of connected devices. */ + retval = logi_dj_recv_query_paired_devices(djrcv_dev); + if (!retval) { + /* everything went fine, so just leave */ + break; + } + dev_err(&djrcv_dev->hdev->dev, + "%s:logi_dj_recv_query_paired_devices " + "error:%d\n", __func__, retval); + } dbg_hid("%s: unexpected report type\n", __func__); } } @@ -360,6 +388,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev, if (!djdev) { dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" " is NULL, index %d\n", dj_report->device_index); + kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report)); + + if (schedule_work(&djrcv_dev->work) == 0) { + dbg_hid("%s: did not schedule the work item, was already " + "queued\n", __func__); + } return; } @@ -390,6 +424,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev, if (dj_device == NULL) { dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" " is NULL, index %d\n", dj_report->device_index); + kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report)); + + if (schedule_work(&djrcv_dev->work) == 0) { + dbg_hid("%s: did not schedule the work item, was already " + "queued\n", __func__); + } return; } @@ -437,6 +477,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) return logi_dj_recv_send_report(djrcv_dev, &dj_report); } + static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, unsigned timeout) { diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h index fd28a5e0ca3..4a4000340ce 100644 --- a/drivers/hid/hid-logitech-dj.h +++ b/drivers/hid/hid-logitech-dj.h @@ -101,6 +101,7 @@ struct dj_receiver_dev { struct work_struct work; struct kfifo notif_fifo; spinlock_t lock; + bool querying_devices; }; struct dj_device { From 2ae637123f49eea55c12e2871f7acc28a601dccc Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 18 Sep 2012 14:21:01 -0400 Subject: [PATCH 0907/2357] cifs: fix return value in cifsConvertToUTF16 commit c73f693989d7a7d99ec66a7065295a0c93d0b127 upstream. This function returns the wrong value, which causes the callers to get the length of the resulting pathname wrong when it contains non-ASCII characters. This seems to fix https://bugzilla.samba.org/show_bug.cgi?id=6767 Reported-by: Baldvin Kovacs Reported-and-Tested-by: Nicolas Lefebvre Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifs_unicode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index fbb9da95184..33ef60d8e2f 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -328,6 +328,6 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, } ctoUTF16_out: - return i; + return j; } From 1db67b66e816cc91335ce18179d97eb125e5a769 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 28 Aug 2012 01:53:54 +0000 Subject: [PATCH 0908/2357] vmwgfx: add dumb ioctl support commit 5e1782d224c79b26ab7d5c31e3f87657000714fb upstream. Testing and works with the -modesetting driver, Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 5 ++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 10 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 73 ++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 7279b3ec012..3a4b15acd76 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1159,6 +1159,11 @@ static struct drm_driver driver = { .open = vmw_driver_open, .preclose = vmw_preclose, .postclose = vmw_postclose, + + .dumb_create = vmw_dumb_create, + .dumb_map_offset = vmw_dumb_map_offset, + .dumb_destroy = vmw_dumb_destroy, + .fops = &vmwgfx_driver_fops, .name = VMWGFX_DRIVER_NAME, .desc = VMWGFX_DRIVER_DESC, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d0f2c079ee2..29c984ff7f2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -645,6 +645,16 @@ int vmw_kms_readback(struct vmw_private *dev_priv, int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int vmw_dumb_create(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args); + +int vmw_dumb_map_offset(struct drm_file *file_priv, + struct drm_device *dev, uint32_t handle, + uint64_t *offset); +int vmw_dumb_destroy(struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle); /** * Overlay control - vmwgfx_overlay.c */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index a37abb581cb..059b32c6f22 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1917,3 +1917,76 @@ int vmw_user_stream_lookup(struct vmw_private *dev_priv, vmw_resource_unreference(&res); return ret; } + + +int vmw_dumb_create(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_master *vmaster = vmw_master(file_priv->master); + struct vmw_user_dma_buffer *vmw_user_bo; + struct ttm_buffer_object *tmp; + int ret; + + args->pitch = args->width * ((args->bpp + 7) / 8); + args->size = args->pitch * args->height; + + vmw_user_bo = kzalloc(sizeof(*vmw_user_bo), GFP_KERNEL); + if (vmw_user_bo == NULL) + return -ENOMEM; + + ret = ttm_read_lock(&vmaster->lock, true); + if (ret != 0) { + kfree(vmw_user_bo); + return ret; + } + + ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, args->size, + &vmw_vram_sys_placement, true, + &vmw_user_dmabuf_destroy); + if (ret != 0) + goto out_no_dmabuf; + + tmp = ttm_bo_reference(&vmw_user_bo->dma.base); + ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile, + &vmw_user_bo->base, + false, + ttm_buffer_type, + &vmw_user_dmabuf_release, NULL); + if (unlikely(ret != 0)) + goto out_no_base_object; + + args->handle = vmw_user_bo->base.hash.key; + +out_no_base_object: + ttm_bo_unref(&tmp); +out_no_dmabuf: + ttm_read_unlock(&vmaster->lock); + return ret; +} + +int vmw_dumb_map_offset(struct drm_file *file_priv, + struct drm_device *dev, uint32_t handle, + uint64_t *offset) +{ + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_dma_buffer *out_buf; + int ret; + + ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf); + if (ret != 0) + return -EINVAL; + + *offset = out_buf->base.addr_space_offset; + vmw_dmabuf_unreference(&out_buf); + return 0; +} + +int vmw_dumb_destroy(struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle) +{ + return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, + handle, TTM_REF_USAGE); +} From 0bf2a827d745808dde90001134ecc6a4af39b361 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Tue, 4 Sep 2012 14:41:37 +0000 Subject: [PATCH 0909/2357] ibmveth: Fix alignment of rx queue bug commit d90c92fee89ccd75ef2646f3bde0b4c0450666c3 upstream. This patch fixes a bug found by Nish Aravamudan (https://lkml.org/lkml/2012/5/15/220) where the driver is not following the spec (it is not aligning the rx buffer on a 16-byte boundary) and the hypervisor aborts the registration, making the device unusable. The fix follows BenH's recommendation (https://lkml.org/lkml/2012/7/20/461) to replace the kmalloc+map for a single call to dma_alloc_coherent() because that function always aligns to a 16-byte boundary. The stable trees will run into this bug whenever the rx buffer kmalloc call returns something not aligned on a 16-byte boundary. Signed-off-by: Santiago Leon Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ibm/ibmveth.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 9010cea68bc..b68d28a130e 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -472,14 +472,9 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) } if (adapter->rx_queue.queue_addr != NULL) { - if (!dma_mapping_error(dev, adapter->rx_queue.queue_dma)) { - dma_unmap_single(dev, - adapter->rx_queue.queue_dma, - adapter->rx_queue.queue_len, - DMA_BIDIRECTIONAL); - adapter->rx_queue.queue_dma = DMA_ERROR_CODE; - } - kfree(adapter->rx_queue.queue_addr); + dma_free_coherent(dev, adapter->rx_queue.queue_len, + adapter->rx_queue.queue_addr, + adapter->rx_queue.queue_dma); adapter->rx_queue.queue_addr = NULL; } @@ -556,10 +551,13 @@ static int ibmveth_open(struct net_device *netdev) goto err_out; } + dev = &adapter->vdev->dev; + adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) * rxq_entries; - adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len, - GFP_KERNEL); + adapter->rx_queue.queue_addr = + dma_alloc_coherent(dev, adapter->rx_queue.queue_len, + &adapter->rx_queue.queue_dma, GFP_KERNEL); if (!adapter->rx_queue.queue_addr) { netdev_err(netdev, "unable to allocate rx queue pages\n"); @@ -567,19 +565,13 @@ static int ibmveth_open(struct net_device *netdev) goto err_out; } - dev = &adapter->vdev->dev; - adapter->buffer_list_dma = dma_map_single(dev, adapter->buffer_list_addr, 4096, DMA_BIDIRECTIONAL); adapter->filter_list_dma = dma_map_single(dev, adapter->filter_list_addr, 4096, DMA_BIDIRECTIONAL); - adapter->rx_queue.queue_dma = dma_map_single(dev, - adapter->rx_queue.queue_addr, - adapter->rx_queue.queue_len, DMA_BIDIRECTIONAL); if ((dma_mapping_error(dev, adapter->buffer_list_dma)) || - (dma_mapping_error(dev, adapter->filter_list_dma)) || - (dma_mapping_error(dev, adapter->rx_queue.queue_dma))) { + (dma_mapping_error(dev, adapter->filter_list_dma))) { netdev_err(netdev, "unable to map filter or buffer list " "pages\n"); rc = -ENOMEM; From ba41a6df9e32ee5752165496017cadf700c14ca9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 4 Sep 2012 17:44:45 +0300 Subject: [PATCH 0910/2357] mac80211: clear bssid on auth/assoc failure commit 3d2abdfdf14f4d6decc2023708211e19b096f4ca upstream. ifmgd->bssid wasn't cleared properly in some auth/assoc failure cases, causing mac80211 and the low-level driver to go out of sync. Clear ifmgd->bssid on failure, and notify the driver. Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 25be6831ff0..abc31d7bd2a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3232,6 +3232,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, goto out_unlock; err_clear: + memset(ifmgd->bssid, 0, ETH_ALEN); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); ifmgd->auth_data = NULL; err_free: kfree(auth_data); @@ -3410,6 +3412,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, err = 0; goto out; err_clear: + memset(ifmgd->bssid, 0, ETH_ALEN); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); ifmgd->assoc_data = NULL; err_free: kfree(assoc_data); From 7c4a26d507774d22b7e6eb792046c203f71a0ab0 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Tue, 11 Sep 2012 21:16:47 +0200 Subject: [PATCH 0911/2357] brcmfmac: fix big endian bug in i-scan. commit ed205b361956c96e0d8c09a8c9135a6a79cd9541 upstream. ssid len is 32 bit and needs endian conversion for big endian systems. Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index d13ae9c299f..e360939f790 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -500,8 +500,10 @@ static void wl_iscan_prep(struct brcmf_scan_params_le *params_le, params_le->active_time = cpu_to_le32(-1); params_le->passive_time = cpu_to_le32(-1); params_le->home_time = cpu_to_le32(-1); - if (ssid && ssid->SSID_len) - memcpy(¶ms_le->ssid_le, ssid, sizeof(struct brcmf_ssid)); + if (ssid && ssid->SSID_len) { + params_le->ssid_le.SSID_len = cpu_to_le32(ssid->SSID_len); + memcpy(¶ms_le->ssid_le.SSID, ssid->SSID, ssid->SSID_len); + } } static s32 From d5217650d6e48503466a9192e2cd72c91c696f50 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Tue, 11 Sep 2012 21:16:48 +0200 Subject: [PATCH 0912/2357] brcmfmac: Fix big endian host configuration data. commit e020a83d0942a5aceac35986500c9834efc8707d upstream. Fixes big endian host configuration parameters. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- .../wireless/brcm80211/brcmfmac/dhd_common.c | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 4187435220f..4db878dfc36 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -764,8 +764,11 @@ static void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode) { char iovbuf[32]; int retcode; + __le32 arp_mode_le; - brcmf_c_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); + arp_mode_le = cpu_to_le32(arp_mode); + brcmf_c_mkiovar("arp_ol", (char *)&arp_mode_le, 4, iovbuf, + sizeof(iovbuf)); retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); retcode = retcode >= 0 ? 0 : retcode; @@ -781,8 +784,11 @@ static void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable) { char iovbuf[32]; int retcode; + __le32 arp_enable_le; - brcmf_c_mkiovar("arpoe", (char *)&arp_enable, 4, + arp_enable_le = cpu_to_le32(arp_enable); + + brcmf_c_mkiovar("arpoe", (char *)&arp_enable_le, 4, iovbuf, sizeof(iovbuf)); retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); @@ -803,10 +809,10 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) char buf[128], *ptr; u32 dongle_align = drvr->bus_if->align; u32 glom = 0; - u32 roaming = 1; - uint bcn_timeout = 3; - int scan_assoc_time = 40; - int scan_unassoc_time = 40; + __le32 roaming_le = cpu_to_le32(1); + __le32 bcn_timeout_le = cpu_to_le32(3); + __le32 scan_assoc_time_le = cpu_to_le32(40); + __le32 scan_unassoc_time_le = cpu_to_le32(40); int i; mutex_lock(&drvr->proto_block); @@ -841,14 +847,14 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) /* Setup timeout if Beacons are lost and roam is off to report link down */ - brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, + brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout_le, 4, iovbuf, sizeof(iovbuf)); brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); /* Enable/Disable build-in roaming to allowed ext supplicant to take of romaing */ - brcmf_c_mkiovar("roam_off", (char *)&roaming, 4, + brcmf_c_mkiovar("roam_off", (char *)&roaming_le, 4, iovbuf, sizeof(iovbuf)); brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); @@ -863,9 +869,9 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) sizeof(iovbuf)); brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME, - (char *)&scan_assoc_time, sizeof(scan_assoc_time)); + (char *)&scan_assoc_time_le, sizeof(scan_assoc_time_le)); brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME, - (char *)&scan_unassoc_time, sizeof(scan_unassoc_time)); + (char *)&scan_unassoc_time_le, sizeof(scan_unassoc_time_le)); /* Set and enable ARP offload feature */ brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE); From c68f32825bc8c3e046493262422e134a03adb6c6 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 21 Jun 2012 07:50:02 +0000 Subject: [PATCH 0913/2357] SCSI: lpfc: fix problems with -Werror commit 4bdd03e61b7a5c4c6bc2b25d46fcd491788fdfb3 upstream. Commit d38bd3aef ("Add -Werror compilation flag") is causing build breakage with random gcc incarnations. These look like gcc problems, but we shouldn't break the build because of a bad gcc. Fix this by adding a make flag WARNINGS_BECOME_ERRORS=1 which is the same as aic7xxx uses so ordinarily the build doesn't use -Werror Reported-by: Fengguang Wu Cc: Alex Iannicelli Cc: James Smart Cc: Jonathan Nieder Cc: Mike Pagano Signed-off-by: James Bottomley --- drivers/scsi/lpfc/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index fe5d396aca7..e2516ba8ebf 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile @@ -22,7 +22,9 @@ ccflags-$(GCOV) := -fprofile-arcs -ftest-coverage ccflags-$(GCOV) += -O0 +ifdef WARNINGS_BECOME_ERRORS ccflags-y += -Werror +endif obj-$(CONFIG_SCSI_LPFC) := lpfc.o From d39bdd32d086d55a4adf228a0af2874ee489cd61 Mon Sep 17 00:00:00 2001 From: "sreekanth.reddy@lsi.com" Date: Wed, 22 Aug 2012 16:55:13 +0530 Subject: [PATCH 0914/2357] SCSI: mpt2sas: Fix for issue - Unable to boot from the drive connected to HBA commit 10cce6d8b5af0b32bc4254ae4a28423a74c0921c upstream. This patch checks whether HBA is SAS2008 B0 controller. if it is a SAS2008 B0 controller then it use IO-APIC interrupt instead of MSIX, as SAS2008 B0 controller doesn't support MSIX interrupts. [jejb: fix whitespace problems] Signed-off-by: Sreekanth Reddy Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt2sas/mpt2sas_base.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index c4cef569540..db793621c40 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1202,6 +1202,13 @@ _base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) u16 message_control; + /* Check whether controller SAS2008 B0 controller, + if it is SAS2008 B0 controller use IO-APIC instead of MSIX */ + if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && + ioc->pdev->revision == 0x01) { + return -EINVAL; + } + base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); if (!base) { dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " From 4f04e027f76aefbcfc987af72e6727d40d8c654d Mon Sep 17 00:00:00 2001 From: Eddie Wai Date: Tue, 21 Aug 2012 10:35:53 -0700 Subject: [PATCH 0915/2357] SCSI: bnx2i: Fixed NULL ptr deference for 1G bnx2 Linux iSCSI offload commit d6532207116307eb7ecbfa7b9e02c53230096a50 upstream. This patch fixes the following kernel panic invoked by uninitialized fields in the chip initialization for the 1G bnx2 iSCSI offload. One of the bits in the chip initialization is being used by the latest firmware to control overflow packets. When this control bit gets enabled erroneously, it would ultimately result in a bad packet placement which would cause the bnx2 driver to dereference a NULL ptr in the placement handler. This can happen under certain stress I/O environment under the Linux iSCSI offload operation. This change only affects Broadcom's 5709 chipset. Unable to handle kernel NULL pointer dereference at 0000000000000008 RIP: [] :bnx2:bnx2_poll_work+0xd0d/0x13c5 Pid: 0, comm: swapper Tainted: G ---- 2.6.18-333.el5debug #2 RIP: 0010:[] [] :bnx2:bnx2_poll_work+0xd0d/0x13c5 RSP: 0018:ffff8101b575bd50 EFLAGS: 00010216 RAX: 0000000000000005 RBX: ffff81007c5fb180 RCX: 0000000000000000 RDX: 0000000000000ffc RSI: 00000000817e8000 RDI: 0000000000000220 RBP: ffff81015bbd7ec0 R08: ffff8100817e9000 R09: 0000000000000000 R10: ffff81007c5fb180 R11: 00000000000000c8 R12: 000000007a25a010 R13: 0000000000000000 R14: 0000000000000005 R15: ffff810159f80558 FS: 0000000000000000(0000) GS:ffff8101afebc240(0000) knlGS:0000000000000000 CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b CR2: 0000000000000008 CR3: 0000000000201000 CR4: 00000000000006a0 Process swapper (pid: 0, threadinfo ffff8101b5754000, task ffff8101afebd820) Stack: 000000000000000b ffff810159f80000 0000000000000040 ffff810159f80520 ffff810159f80500 00cf00cf8008e84b ffffc200100939e0 ffff810009035b20 0000502900000000 000000be00000001 ffff8100817e7810 00d08101b575bea8 Call Trace: [] show_schedstat+0x1c2/0x25b [] :bnx2:bnx2_poll+0xf6/0x231 [] net_rx_action+0xac/0x1b1 [] __do_softirq+0x89/0x133 [] call_softirq+0x1c/0x28 [] do_softirq+0x2c/0x7d [] do_IRQ+0xee/0xf7 [] ret_from_intr+0x0/0xa [] acpi_processor_idle_simple+0x1c5/0x341 [] acpi_processor_idle_simple+0x182/0x341 [] acpi_processor_idle_simple+0x0/0x341 [] cpu_idle+0x95/0xb8 [] start_secondary+0x479/0x488 Signed-off-by: Eddie Wai Reviewed-by: Mike Christie Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/bnx2i/bnx2i_hwi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index f9d6f412909..72de3ba5165 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1264,6 +1264,9 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba) int rc = 0; u64 mask64; + memset(&iscsi_init, 0x00, sizeof(struct iscsi_kwqe_init1)); + memset(&iscsi_init2, 0x00, sizeof(struct iscsi_kwqe_init2)); + bnx2i_adjust_qp_size(hba); iscsi_init.flags = From c2cf6b0d20d0febfead4b29d87f9fc2e903127c0 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Fri, 14 Sep 2012 16:34:25 -0500 Subject: [PATCH 0916/2357] SCSI: hpsa: fix handling of protocol error commit 256d0eaac87da1e993190846064f339f4c7a63f5 upstream. If a command status of CMD_PROTOCOL_ERR is received, this information should be conveyed to the SCSI mid layer, not dropped on the floor. CMD_PROTOCOL_ERR may be received from the Smart Array for any commands destined for an external RAID controller such as a P2000, or commands destined for tape drives or CD/DVD-ROM drives, if for instance a cable is disconnected. This mostly affects multipath configurations, as disconnecting a cable on a non-multipath configuration is not going to do anything good regardless of whether CMD_PROTOCOL_ERR is handled correctly or not. Not handling CMD_PROTOCOL_ERR correctly in a multipath configaration involving external RAID controllers may cause data corruption, so this is quite a serious bug. This bug should not normally cause a problem for direct attached disk storage. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/hpsa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 500e20dd56e..7c49e0ab90e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1264,8 +1264,9 @@ static void complete_scsi_command(struct CommandList *cp) } break; case CMD_PROTOCOL_ERR: + cmd->result = DID_ERROR << 16; dev_warn(&h->pdev->dev, "cp %p has " - "protocol error \n", cp); + "protocol error\n", cp); break; case CMD_HARDWARE_ERR: cmd->result = DID_ERROR << 16; From f51909c0af2ebc533eaf48c7daff503b3e54d983 Mon Sep 17 00:00:00 2001 From: Wang Sen Date: Mon, 30 Jul 2012 14:25:06 +0800 Subject: [PATCH 0917/2357] SCSI: scsi: virtio-scsi: Fix address translation failure of HighMem pages used by sg list commit 27e99ade81368e6fdda3212bff9345177cf9e57a upstream. When using the commands below to write some data to a virtio-scsi LUN of the QEMU guest(32-bit) with 1G physical memory(qemu -m 1024), the qemu will crash. # sudo mkfs.ext4 /dev/sdb (/dev/sdb is the virtio-scsi LUN.) # sudo mount /dev/sdb /mnt # dd if=/dev/zero of=/mnt/file bs=1M count=1024 In current implementation, sg_set_buf is called to add buffers to sg list which is put into the virtqueue eventually. But if there are some HighMem pages in table->sgl you can not get virtual address by sg_virt. So, sg_virt(sg_elem) may return NULL value. This will cause QEMU exit when virtqueue_map_sg is called in QEMU because an invalid GPA is passed by virtqueue. Two solutions are discussed here: http://lkml.indiana.edu/hypermail/linux/kernel/1207.3/00675.html Finally, value assignment approach was adopted because: Value assignment creates a well-formed scatterlist, because the termination marker in source sg_list has been set in blk_rq_map_sg(). The last entry of the source sg_list is just copied to the the last entry in destination list. Note that, for now, virtio_ring does not care about the form of the scatterlist and simply processes the first out_num + in_num consecutive elements of the sg[] array. I have tested the patch on my workstation. QEMU would not crash any more. Signed-off-by: Wang Sen Acked-by: Paolo Bonzini Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/virtio_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 1b384311726..6661610c752 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -198,7 +198,7 @@ static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx, int i; for_each_sg(table->sgl, sg_elem, table->nents, i) - sg_set_buf(&sg[idx++], sg_virt(sg_elem), sg_elem->length); + sg[idx++] = *sg_elem; *p_idx = idx; } From dcc8dbc21ff2052c0df6dee3e1a36c3ef4f1133c Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 29 Aug 2012 10:02:08 +0200 Subject: [PATCH 0918/2357] Bluetooth: mgmt: Fix enabling SSP while powered off commit 3d1cbdd6aefff711bcf389fdabc4af9bc22e8201 upstream. When new BT USB adapter is plugged in it's configured while still being powered off (HCI_AUTO_OFF flag is set), thus Set SSP will only set dev_flags but won't write changes to controller. As a result remote devices won't use Secure Simple Pairing with our device due to SSP Host Support flag disabled in extended features and may also reject SSP attempt from our side (with possible fallback to legacy pairing). This patch ensures HCI Write Simple Pairing Mode is sent when Set Powered is called to power on controller and clear HCI_AUTO_OFF flag. Signed-off-by: Andrzej Kaczmarek Acked-by: Johan Hedberg Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4bb03b11112..78186b08386 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2801,6 +2801,12 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) if (scan) hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { + u8 ssp = 1; + + hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp); + } + update_class(hdev); update_name(hdev, hdev->dev_name); update_eir(hdev); From ec4d417c66a406bb464598220faf9f561d5b6d25 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 14 Sep 2012 16:34:46 -0300 Subject: [PATCH 0919/2357] Bluetooth: Fix not removing power_off delayed work commit 78c04c0bf52360dc2f7185e99c8e9aa05d73ae5a upstream. For example, when a usb reset is received (I could reproduce it running something very similar to this[1] in a loop) it could be that the device is unregistered while the power_off delayed work is still scheduled to run. Backtrace: WARNING: at lib/debugobjects.c:261 debug_print_object+0x7c/0x8d() Hardware name: To Be Filled By O.E.M. ODEBUG: free active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x26 Modules linked in: nouveau mxm_wmi btusb wmi bluetooth ttm coretemp drm_kms_helper Pid: 2114, comm: usb-reset Not tainted 3.5.0bt-next #2 Call Trace: [] ? free_obj_work+0x57/0x91 [] warn_slowpath_common+0x7e/0x97 [] warn_slowpath_fmt+0x41/0x43 [] debug_print_object+0x7c/0x8d [] ? __queue_work+0x259/0x259 [] ? debug_check_no_obj_freed+0x6f/0x1b5 [] debug_check_no_obj_freed+0x98/0x1b5 [] ? bt_host_release+0x10/0x1e [bluetooth] [] kfree+0x90/0xe6 [] bt_host_release+0x10/0x1e [bluetooth] [] device_release+0x4a/0x7e [] kobject_release+0x11d/0x154 [] kobject_put+0x4a/0x4f [] put_device+0x12/0x14 [] hci_free_dev+0x22/0x26 [bluetooth] [] btusb_disconnect+0x96/0x9f [btusb] [] usb_unbind_interface+0x57/0x106 [] __device_release_driver+0x83/0xd6 [] device_release_driver+0x20/0x2d [] usb_driver_release_interface+0x44/0x7b [] usb_forced_unbind_intf+0x45/0x4e [] usb_reset_device+0xa6/0x12e [] usbdev_do_ioctl+0x319/0xe20 [] ? avc_has_perm_flags+0xc9/0x12e [] ? avc_has_perm_flags+0x25/0x12e [] ? do_page_fault+0x31e/0x3a1 [] usbdev_ioctl+0x9/0xd [] vfs_ioctl+0x21/0x34 [] do_vfs_ioctl+0x408/0x44b [] ? file_has_perm+0x76/0x81 [] sys_ioctl+0x51/0x76 [] system_call_fastpath+0x16/0x1b [1] http://cpansearch.perl.org/src/DPAVLIN/Biblio-RFID-0.03/examples/usbreset.c Signed-off-by: Vinicius Costa Gomes Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d6dc44cd15b..0a30ec10d40 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -750,6 +750,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) cancel_work_sync(&hdev->le_scan); + cancel_delayed_work(&hdev->power_off); + hci_req_cancel(hdev, ENODEV); hci_req_lock(hdev); From a6be20b8cd1e5e847c4191b8f249b939aaabf987 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 29 Aug 2012 10:02:09 +0200 Subject: [PATCH 0920/2357] Bluetooth: mgmt: Fix enabling LE while powered off commit 562fcc246ebe31ade6e1be08585673b9b2785498 upstream. When new BT USB adapter is plugged in it's configured while still being powered off (HCI_AUTO_OFF flag is set), thus Set LE will only set dev_flags but won't write changes to controller. As a result it's not possible to start device discovery session on LE controller as it uses interleaved discovery which requires LE Supported Host flag in extended features. This patch ensures HCI Write LE Host Supported is sent when Set Powered is called to power on controller and clear HCI_AUTO_OFF flag. Signed-off-by: Andrzej Kaczmarek Acked-by: Johan Hedberg Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/mgmt.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 78186b08386..8f3d9dc7013 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2807,6 +2807,16 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp); } + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + struct hci_cp_write_le_host_supported cp; + + cp.le = 1; + cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); + + hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, + sizeof(cp), &cp); + } + update_class(hdev); update_name(hdev, hdev->dev_name); update_eir(hdev); From 9f8a301630c67302cab77da0c4cb06272a95459d Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Mon, 27 Aug 2012 12:52:24 -0600 Subject: [PATCH 0921/2357] hpwdt: Fix kdump issue in hpwdt commit 308b135e4fcc00c80c07e0e04e7afa8edf78583c upstream. kdump can be interrupted by watchdog timer when the timer is left activated on the crash kernel. Changed the hpwdt driver to disable watchdog timer at boot-time. This assures that watchdog timer is disabled until /dev/watchdog is opened, and prevents watchdog timer to be left running on the crash kernel. Signed-off-by: Toshi Kani Tested-by: Lisa Mitchell Signed-off-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/hpwdt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 9f13b897fd6..6019929a54a 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -806,6 +806,9 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, hpwdt_timer_reg = pci_mem_addr + 0x70; hpwdt_timer_con = pci_mem_addr + 0x72; + /* Make sure that timer is disabled until /dev/watchdog is opened */ + hpwdt_stop(); + /* Make sure that we have a valid soft_margin */ if (hpwdt_change_timer(soft_margin)) hpwdt_change_timer(DEFAULT_MARGIN); From dca2dd18c62e3b90cb71534e0a715d246ce7196d Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Tue, 11 Sep 2012 17:56:57 +0100 Subject: [PATCH 0922/2357] ARM: 7532/1: decompressor: reset SCTLR.TRE for VMSA ARMv7 cores commit e1e5b7e4251c7538ca08c2c5545b0c2fbd8a6635 upstream. This patch zeroes the SCTLR.TRE bit prior to setting the mapping as cacheable for ARMv7 cores in the decompressor, ensuring that the memory region attributes are obtained from the C and B bits, not from the page tables. Cc: Nicolas Pitre Reviewed-by: Will Deacon Signed-off-by: Matthew Leach Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/compressed/head.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index dc7e8ce8e6b..87278fc80d9 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -648,6 +648,7 @@ __armv7_mmu_cache_on: mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs #endif mrc p15, 0, r0, c1, c0, 0 @ read control reg + bic r0, r0, #1 << 28 @ clear SCTLR.TRE orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement orr r0, r0, #0x003c @ write buffer #ifdef CONFIG_MMU From c648535596087f7d17458c293d69829ff6e60a6c Mon Sep 17 00:00:00 2001 From: Wen Congyang Date: Thu, 20 Sep 2012 14:04:47 +0800 Subject: [PATCH 0923/2357] tracing: Don't call page_to_pfn() if page is NULL commit 85f2a2ef1d0ab99523e0b947a2b723f5650ed6aa upstream. When allocating memory fails, page is NULL. page_to_pfn() will cause the kernel panicked if we don't use sparsemem vmemmap. Link: http://lkml.kernel.org/r/505AB1FF.8020104@cn.fujitsu.com Acked-by: Mel Gorman Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Andrew Morton Reviewed-by: Minchan Kim Signed-off-by: Wen Congyang Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- include/trace/events/kmem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h index 5f889f16b0c..08fa27244da 100644 --- a/include/trace/events/kmem.h +++ b/include/trace/events/kmem.h @@ -214,7 +214,7 @@ TRACE_EVENT(mm_page_alloc, TP_printk("page=%p pfn=%lu order=%d migratetype=%d gfp_flags=%s", __entry->page, - page_to_pfn(__entry->page), + __entry->page ? page_to_pfn(__entry->page) : 0, __entry->order, __entry->migratetype, show_gfp_flags(__entry->gfp_flags)) @@ -240,7 +240,7 @@ DECLARE_EVENT_CLASS(mm_page, TP_printk("page=%p pfn=%lu order=%u migratetype=%d percpu_refill=%d", __entry->page, - page_to_pfn(__entry->page), + __entry->page ? page_to_pfn(__entry->page) : 0, __entry->order, __entry->migratetype, __entry->order == 0) From 0ed92b21f3807633c70f7565f92b034ef8bf4b1c Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Wed, 19 Sep 2012 11:10:48 -0700 Subject: [PATCH 0924/2357] Input: i8042 - disable mux on Toshiba C850D commit 8669cf6793bb38307a30fb6b9565ddc8840ebd3f upstream. On Toshiba Satellite C850D, the touchpad and the keyboard might randomly not work at boot. Preventing MUX mode activation solves this issue. Signed-off-by: Anisse Astier Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/i8042-x86ia64io.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 6918773ce02..d6cc77a53c7 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -333,6 +333,12 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"), + }, + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), From 870fefcd916e9766ff3ac689aa87e9f3abbe9381 Mon Sep 17 00:00:00 2001 From: Jovi Zhang Date: Wed, 22 Aug 2012 10:34:08 +0800 Subject: [PATCH 0925/2357] MIPS: mm: Add compound tail page _mapcount when mapped commit af89fa3986b9d034a286544ab1ed95096496a2f9 upstream. See commit b6999b191 which did the same modification for x86's mm/gup, Quote from commit b6999b191: "If compound pages are used and the page is a tail page, gup_huge_pmd() increases _mapcount to record tail page are mapped while gup_huge_pud does not do that." [ralf@linux-mips.org: fixed rejects caused by the original patch getting linewrapped.] Signed-off-by: Jovi Zhang Cc: Youquan Song Cc: Andi Kleen Patchwork: https://patchwork.linux-mips.org/patch/4291/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman --- arch/mips/mm/gup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c index 33aadbcf170..dcfd573871c 100644 --- a/arch/mips/mm/gup.c +++ b/arch/mips/mm/gup.c @@ -152,6 +152,8 @@ static int gup_huge_pud(pud_t pud, unsigned long addr, unsigned long end, do { VM_BUG_ON(compound_head(page) != head); pages[*nr] = page; + if (PageTail(page)) + get_huge_page_tail(page); (*nr)++; page++; refs++; From b9e8ad48eca69a02b03ea2beea38383d5f3f0b3f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 11 Sep 2012 11:11:13 -0500 Subject: [PATCH 0926/2357] rtlwifi: rtl8192ce: Log message that B_CUT device may not work commit 022e1d0680c7b4366017393417b8758be5abcee8 upstream. There are a number of problems that occur for the latest version of the Realtek RTL8188CE device with the in-kernel driver. These include selection of the wrong firmware, and system lockup. A full fix is known, but is too invasive for inclusion in stable. This patch fixes the problem with loading the wrong firmware, and logs a message that the device may not work for kernels 3.6 and older. Signed-off-by: Larry Finger Cc: Anisse Astier Cc: Li Chaoming Tested-by: Anisse Astier Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/rtl8192ce/def.h | 1 + drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 12 ++++++++++-- drivers/net/wireless/rtlwifi/rtl8192ce/sw.c | 6 ++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h index 04c3aef8a4f..2925094b2d9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h @@ -117,6 +117,7 @@ #define CHIP_VER_B BIT(4) #define CHIP_92C_BITMASK BIT(0) +#define CHIP_UNKNOWN BIT(7) #define CHIP_92C_1T2R 0x03 #define CHIP_92C 0x01 #define CHIP_88C 0x00 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 5c4d9bc040f..509f66195f2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -995,8 +995,16 @@ static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw) version = (value32 & TYPE_ID) ? VERSION_A_CHIP_92C : VERSION_A_CHIP_88C; } else { - version = (value32 & TYPE_ID) ? VERSION_B_CHIP_92C : - VERSION_B_CHIP_88C; + version = (enum version_8192c) (CHIP_VER_B | + ((value32 & TYPE_ID) ? CHIP_92C_BITMASK : 0) | + ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0)); + if ((!IS_CHIP_VENDOR_UMC(version)) && (value32 & + CHIP_VER_RTL_MASK)) { + version = (enum version_8192c)(version | + ((((value32 & CHIP_VER_RTL_MASK) == BIT(12)) + ? CHIP_VENDOR_UMC_B_CUT : CHIP_UNKNOWN) | + CHIP_VENDOR_UMC)); + } } switch (version) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index 2c3b73366cd..4e2a45839ed 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -162,10 +162,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) /* request fw */ if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && - !IS_92C_SERIAL(rtlhal->version)) + !IS_92C_SERIAL(rtlhal->version)) { rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin"; - else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) + } else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) { rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin"; + pr_info("****** This B_CUT device may not work with kernels 3.6 and earlier\n"); + } rtlpriv->max_fw_size = 0x4000; pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); From d83e6a4819844782ac16591a89c598342eef8627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Holm?= Date: Mon, 17 Sep 2012 21:50:57 +0000 Subject: [PATCH 0927/2357] asix: Support DLink DUB-E100 H/W Ver C1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ed3770a9cd5764a575b83810ea679bbff2b03082 upstream. Signed-off-by: Søren Holm Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/asix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 609fcc33159..ef84a586c17 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -1603,6 +1603,10 @@ static const struct usb_device_id products [] = { // DLink DUB-E100 H/W Ver B1 Alternate USB_DEVICE (0x2001, 0x3c05), .driver_info = (unsigned long) &ax88772_info, +}, { + // DLink DUB-E100 H/W Ver C1 + USB_DEVICE (0x2001, 0x1a02), + .driver_info = (unsigned long) &ax88772_info, }, { // Linksys USB1000 USB_DEVICE (0x1737, 0x0039), From 4a3aa6ef866b7128e57358858e053450ab97c41a Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 19 Sep 2012 14:58:45 +0200 Subject: [PATCH 0928/2357] can: ti_hecc: fix oops during rmmod commit ab04c8bd423edb03e2148350a091836c196107fc upstream. This patch fixes an oops which occurs when unloading the driver, while the network interface is still up. The problem is that first the io mapping is teared own, then the CAN device is unregistered, resulting in accessing the hardware's iomem: [ 172.744232] Unable to handle kernel paging request at virtual address c88b0040 [ 172.752441] pgd = c7be4000 [ 172.755645] [c88b0040] *pgd=87821811, *pte=00000000, *ppte=00000000 [ 172.762207] Internal error: Oops: 807 [#1] PREEMPT ARM [ 172.767517] Modules linked in: ti_hecc(-) can_dev [ 172.772430] CPU: 0 Not tainted (3.5.0alpha-00037-g3554cc0 #126) [ 172.778961] PC is at ti_hecc_close+0xb0/0x100 [ti_hecc] [ 172.784423] LR is at __dev_close_many+0x90/0xc0 [ 172.789123] pc : [] lr : [] psr: 60000013 [ 172.789123] sp : c5c1de68 ip : 00040081 fp : 00000000 [ 172.801025] r10: 00000001 r9 : c5c1c000 r8 : 00100100 [ 172.806457] r7 : c5d0a48c r6 : c5d0a400 r5 : 00000000 r4 : c5d0a000 [ 172.813232] r3 : c88b0000 r2 : 00000001 r1 : c5d0a000 r0 : c5d0a000 [ 172.820037] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 172.827423] Control: 10c5387d Table: 87be4019 DAC: 00000015 [ 172.833404] Process rmmod (pid: 600, stack limit = 0xc5c1c2f0) [ 172.839447] Stack: (0xc5c1de68 to 0xc5c1e000) [ 172.843994] de60: bf00c6b8 c5c1dec8 c5d0a000 c5d0a000 00200200 c033be58 [ 172.852478] de80: c5c1de44 c5c1dec8 c5c1dec8 c033bf2c c5c1de90 c5c1de90 c5d0a084 c5c1de44 [ 172.860992] dea0: c5c1dec8 c033c098 c061d3dc c5d0a000 00000000 c05edf28 c05edb34 c000d724 [ 172.869476] dec0: 00000000 c033c2f8 c5d0a084 c5d0a084 00000000 c033c370 00000000 c5d0a000 [ 172.877990] dee0: c05edb00 c033c3b8 c5d0a000 bf00d3ac c05edb00 bf00d7c8 bf00d7c8 c02842dc [ 172.886474] df00: c02842c8 c0282f90 c5c1c000 c05edb00 bf00d7c8 c0283668 bf00d7c8 00000000 [ 172.894989] df20: c0611f98 befe2f80 c000d724 c0282d10 bf00d804 00000000 00000013 c0068a8c [ 172.903472] df40: c5c538e8 685f6974 00636365 c61571a8 c5cb9980 c61571a8 c6158a20 c00c9bc4 [ 172.911987] df60: 00000000 00000000 c5cb9980 00000000 c5cb9980 00000000 c7823680 00000006 [ 172.920471] df80: bf00d804 00000880 c5c1df8c 00000000 000d4267 befe2f80 00000001 b6d90068 [ 172.928985] dfa0: 00000081 c000d5a0 befe2f80 00000001 befe2f80 00000880 b6d90008 00000008 [ 172.937469] dfc0: befe2f80 00000001 b6d90068 00000081 00000001 00000000 befe2eac 00000000 [ 172.945983] dfe0: 00000000 befe2b18 00023ba4 b6e6addc 60000010 befe2f80 a8e00190 86d2d344 [ 172.954498] [] (ti_hecc_close+0xb0/0x100 [ti_hecc]) from [] (__dev__registered_many+0xc0/0x2a0) [ 172.984161] [] (rollback_registered_many+0xc0/0x2a0) from [] (rollback_registered+0x20/0x30) [ 172.994750] [] (rollback_registered+0x20/0x30) from [] (unregister_netdevice_queue+0x68/0x98) [ 173.005401] [] (unregister_netdevice_queue+0x68/0x98) from [] (unregister_netdev+0x18/0x20) [ 173.015899] [] (unregister_netdev+0x18/0x20) from [] (ti_hecc_remove+0x60/0x80 [ti_hecc]) [ 173.026245] [] (ti_hecc_remove+0x60/0x80 [ti_hecc]) from [] (platform_drv_remove+0x14/0x18) [ 173.036712] [] (platform_drv_remove+0x14/0x18) from [] (__device_release_driver+0x7c/0xbc) Tested-by: Jan Luebbe Cc: Anant Gole Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/ti_hecc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 4accd7ec695..5ec27008ab4 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -984,12 +984,12 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct ti_hecc_priv *priv = netdev_priv(ndev); + unregister_candev(ndev); clk_disable(priv->clk); clk_put(priv->clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap(priv->base); release_mem_region(res->start, resource_size(res)); - unregister_candev(ndev); free_candev(ndev); platform_set_drvdata(pdev, NULL); From 12e58ca43097b5330e028f4087e7e4789c08abf7 Mon Sep 17 00:00:00 2001 From: "Ira W. Snyder" Date: Tue, 11 Sep 2012 15:58:15 -0700 Subject: [PATCH 0929/2357] can: janz-ican3: fix support for older hardware revisions commit e21093ef6fb4cbecdf926102286dbe280ae965db upstream. The Revision 1.0 Janz CMOD-IO Carrier Board does not have support for the reset registers. To support older hardware, the code is changed to use the hardware reset register on the Janz VMOD-ICAN3 hardware itself. Signed-off-by: Ira W. Snyder Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/janz-ican3.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 08c893cb789..e7823dd989f 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -1250,7 +1250,6 @@ static irqreturn_t ican3_irq(int irq, void *dev_id) */ static int ican3_reset_module(struct ican3_dev *mod) { - u8 val = 1 << mod->num; unsigned long start; u8 runold, runnew; @@ -1264,8 +1263,7 @@ static int ican3_reset_module(struct ican3_dev *mod) runold = ioread8(mod->dpm + TARGET_RUNNING); /* reset the module */ - iowrite8(val, &mod->ctrl->reset_assert); - iowrite8(val, &mod->ctrl->reset_deassert); + iowrite8(0x00, &mod->dpmctrl->hwreset); /* wait until the module has finished resetting and is running */ start = jiffies; From 7334e402a35e0379933e8b0442f0baeed1104217 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 14 Sep 2012 15:36:57 -0700 Subject: [PATCH 0930/2357] cfg80211: fix possible circular lock on reg_regdb_search() commit a85d0d7f3460b1a123b78e7f7e39bf72c37dfb78 upstream. When call_crda() is called we kick off a witch hunt search for the same regulatory domain on our internal regulatory database and that work gets kicked off on a workqueue, this is done while the cfg80211_mutex is held. If that workqueue kicks off it will first lock reg_regdb_search_mutex and later cfg80211_mutex but to ensure two CPUs will not contend against cfg80211_mutex the right thing to do is to have the reg_regdb_search() wait until the cfg80211_mutex is let go. The lockdep report is pasted below. cfg80211: Calling CRDA to update world regulatory domain ====================================================== [ INFO: possible circular locking dependency detected ] 3.3.8 #3 Tainted: G O ------------------------------------------------------- kworker/0:1/235 is trying to acquire lock: (cfg80211_mutex){+.+...}, at: [<816468a4>] set_regdom+0x78c/0x808 [cfg80211] but task is already holding lock: (reg_regdb_search_mutex){+.+...}, at: [<81646828>] set_regdom+0x710/0x808 [cfg80211] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (reg_regdb_search_mutex){+.+...}: [<800a8384>] lock_acquire+0x60/0x88 [<802950a8>] mutex_lock_nested+0x54/0x31c [<81645778>] is_world_regdom+0x9f8/0xc74 [cfg80211] -> #1 (reg_mutex#2){+.+...}: [<800a8384>] lock_acquire+0x60/0x88 [<802950a8>] mutex_lock_nested+0x54/0x31c [<8164539c>] is_world_regdom+0x61c/0xc74 [cfg80211] -> #0 (cfg80211_mutex){+.+...}: [<800a77b8>] __lock_acquire+0x10d4/0x17bc [<800a8384>] lock_acquire+0x60/0x88 [<802950a8>] mutex_lock_nested+0x54/0x31c [<816468a4>] set_regdom+0x78c/0x808 [cfg80211] other info that might help us debug this: Chain exists of: cfg80211_mutex --> reg_mutex#2 --> reg_regdb_search_mutex Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(reg_regdb_search_mutex); lock(reg_mutex#2); lock(reg_regdb_search_mutex); lock(cfg80211_mutex); *** DEADLOCK *** 3 locks held by kworker/0:1/235: #0: (events){.+.+..}, at: [<80089a00>] process_one_work+0x230/0x460 #1: (reg_regdb_work){+.+...}, at: [<80089a00>] process_one_work+0x230/0x460 #2: (reg_regdb_search_mutex){+.+...}, at: [<81646828>] set_regdom+0x710/0x808 [cfg80211] stack backtrace: Call Trace: [<80290fd4>] dump_stack+0x8/0x34 [<80291bc4>] print_circular_bug+0x2ac/0x2d8 [<800a77b8>] __lock_acquire+0x10d4/0x17bc [<800a8384>] lock_acquire+0x60/0x88 [<802950a8>] mutex_lock_nested+0x54/0x31c [<816468a4>] set_regdom+0x78c/0x808 [cfg80211] Reported-by: Felix Fietkau Tested-by: Felix Fietkau Signed-off-by: Luis R. Rodriguez Reviewed-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 460af03d814..b01449f01bb 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -340,6 +340,9 @@ static void reg_regdb_search(struct work_struct *work) struct reg_regdb_search_request *request; const struct ieee80211_regdomain *curdom, *regdom; int i, r; + bool set_reg = false; + + mutex_lock(&cfg80211_mutex); mutex_lock(®_regdb_search_mutex); while (!list_empty(®_regdb_search_list)) { @@ -355,9 +358,7 @@ static void reg_regdb_search(struct work_struct *work) r = reg_copy_regd(®dom, curdom); if (r) break; - mutex_lock(&cfg80211_mutex); - set_regdom(regdom); - mutex_unlock(&cfg80211_mutex); + set_reg = true; break; } } @@ -365,6 +366,11 @@ static void reg_regdb_search(struct work_struct *work) kfree(request); } mutex_unlock(®_regdb_search_mutex); + + if (set_reg) + set_regdom(regdom); + + mutex_unlock(&cfg80211_mutex); } static DECLARE_WORK(reg_regdb_work, reg_regdb_search); From fe9803b58dce15848465ab0270ccea29f4a5c4bb Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 17 Sep 2012 15:20:22 +0530 Subject: [PATCH 0931/2357] DMA: PL330: Fix potential NULL pointer dereference in pl330_submit_req() commit 2e2c682becb20416c140aa0d6d3137b51a5c76da upstream. 'r->cfg' is being checked for NULL. However, it is dereferenced in the previous statements. Thus moving those statements within the check. Signed-off-by: Sachin Kamat Acked-by: Jassi Brar Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/pl330.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 8c44f17a99e..69f1c4dc4b8 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1568,17 +1568,19 @@ static int pl330_submit_req(void *ch_id, struct pl330_req *r) goto xfer_exit; } - /* Prefer Secure Channel */ - if (!_manager_ns(thrd)) - r->cfg->nonsecure = 0; - else - r->cfg->nonsecure = 1; /* Use last settings, if not provided */ - if (r->cfg) + if (r->cfg) { + /* Prefer Secure Channel */ + if (!_manager_ns(thrd)) + r->cfg->nonsecure = 0; + else + r->cfg->nonsecure = 1; + ccr = _prepare_ccr(r->cfg); - else + } else { ccr = readl(regs + CC(thrd->id)); + } /* If this req doesn't have valid xfer settings */ if (!_is_valid(ccr)) { From 570d1520c48a9033c62b9ae552b250d2822c6f9e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 17 Sep 2012 15:20:23 +0530 Subject: [PATCH 0932/2357] DMA: PL330: Check the pointer returned by kzalloc commit 61c6e7531d3b66b33187b8cdd700fd8ab93ffd62 upstream. kzalloc could return NULL. Hence add a check to avoid NULL pointer dereference. Signed-off-by: Sachin Kamat Acked-by: Jassi Brar Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/pl330.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 69f1c4dc4b8..758122f33a9 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2937,6 +2937,11 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan); pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); + if (!pdmac->peripherals) { + ret = -ENOMEM; + dev_err(&adev->dev, "unable to allocate pdmac->peripherals\n"); + goto probe_err5; + } for (i = 0; i < num_chan; i++) { pch = &pdmac->peripherals[i]; From 8dd47c73d93505aee90bc56d56965ef82b535f93 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 11 Sep 2012 17:21:44 +0200 Subject: [PATCH 0933/2357] dmaengine: at_hdmac: fix comment in atc_prep_slave_sg() commit c618a9be0e8c0f36baee2560860a0118a428fb26 upstream. s/dma_memcpy/slave_sg/ and it is sg length that we are talking about. Signed-off-by: Nicolas Ferre Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/at_hdmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index bf0d7e4e345..6a089828d25 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -664,7 +664,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, flags); if (unlikely(!atslave || !sg_len)) { - dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n"); + dev_dbg(chan2dev(chan), "prep_slave_sg: sg length is zero!\n"); return NULL; } From 87a34202d070db674e215091e98d21881af56f22 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 11 Sep 2012 17:21:45 +0200 Subject: [PATCH 0934/2357] dmaengine: at_hdmac: check that each sg data length is non-null commit c456797681db814f4f5b36909e8e94047bf53d9c upstream. Avoid the construction of a malformed DMA request sent to the DMA controller. Log message is for debug only because this condition is unlikely to append and may only trigger at driver development time. Signed-off-by: Nicolas Ferre Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/at_hdmac.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 6a089828d25..9ec3943b123 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -691,6 +691,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, mem = sg_dma_address(sg); len = sg_dma_len(sg); + if (unlikely(!len)) { + dev_dbg(chan2dev(chan), + "prep_slave_sg: sg(%d) data length is zero\n", i); + goto err; + } mem_width = 2; if (unlikely(mem & 3 || len & 3)) mem_width = 0; @@ -726,6 +731,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, mem = sg_dma_address(sg); len = sg_dma_len(sg); + if (unlikely(!len)) { + dev_dbg(chan2dev(chan), + "prep_slave_sg: sg(%d) data length is zero\n", i); + goto err; + } mem_width = 2; if (unlikely(mem & 3 || len & 3)) mem_width = 0; @@ -759,6 +769,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, err_desc_get: dev_err(chan2dev(chan), "not enough descriptors available\n"); +err: atc_desc_put(atchan, first); return NULL; } From 117fe26c51421653d28bfbf91fe71027e9abb253 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 31 Aug 2012 19:22:09 +0200 Subject: [PATCH 0935/2357] rt2x00: Identify ASUS USB-N53 device. commit 177ef8360fabdc49ff08d2598c06e7f7a36b53e3 upstream. This is an RT3572 based device. Signed-off-by: Maximilian Engelhardt Signed-off-by: Gertjan van Wingerde Acked-by: Ivo Van Doorn Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 7e1a492680c..bec1c60cb7f 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1157,6 +1157,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x1690, 0x0744) }, { USB_DEVICE(0x1690, 0x0761) }, { USB_DEVICE(0x1690, 0x0764) }, + /* ASUS */ + { USB_DEVICE(0x0b05, 0x179d) }, /* Cisco */ { USB_DEVICE(0x167b, 0x4001) }, /* EnGenius */ @@ -1222,7 +1224,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1760) }, { USB_DEVICE(0x0b05, 0x1761) }, { USB_DEVICE(0x0b05, 0x1790) }, - { USB_DEVICE(0x0b05, 0x179d) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3262) }, { USB_DEVICE(0x13d3, 0x3284) }, From c0b4947b6456ca77865b296d6b80eaf8c76fa722 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 31 Aug 2012 19:22:10 +0200 Subject: [PATCH 0936/2357] rt2x00: Fix word size of rt2500usb MAC_CSR19 register. commit 6ced58a5dbb94dbfbea1b33ca3c56d1e929cd548 upstream. The register is 16 bits wide, not 32. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo Van Doorn Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 1de9c752c88..b66b8b4e912 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -283,7 +283,7 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) u16 reg; rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); - return rt2x00_get_field32(reg, MAC_CSR19_BIT7); + return rt2x00_get_field16(reg, MAC_CSR19_BIT7); } #ifdef CONFIG_RT2X00_LIB_LEDS diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index b493306a7ee..192531db0b6 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -189,14 +189,14 @@ * MAC_CSR19: GPIO control register. */ #define MAC_CSR19 0x0426 -#define MAC_CSR19_BIT0 FIELD32(0x0001) -#define MAC_CSR19_BIT1 FIELD32(0x0002) -#define MAC_CSR19_BIT2 FIELD32(0x0004) -#define MAC_CSR19_BIT3 FIELD32(0x0008) -#define MAC_CSR19_BIT4 FIELD32(0x0010) -#define MAC_CSR19_BIT5 FIELD32(0x0020) -#define MAC_CSR19_BIT6 FIELD32(0x0040) -#define MAC_CSR19_BIT7 FIELD32(0x0080) +#define MAC_CSR19_BIT0 FIELD16(0x0001) +#define MAC_CSR19_BIT1 FIELD16(0x0002) +#define MAC_CSR19_BIT2 FIELD16(0x0004) +#define MAC_CSR19_BIT3 FIELD16(0x0008) +#define MAC_CSR19_BIT4 FIELD16(0x0010) +#define MAC_CSR19_BIT5 FIELD16(0x0020) +#define MAC_CSR19_BIT6 FIELD16(0x0040) +#define MAC_CSR19_BIT7 FIELD16(0x0080) /* * MAC_CSR20: LED control register. From 010ec57f5f6706fbafe9b198846c35500de7aa91 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 31 Aug 2012 19:22:11 +0200 Subject: [PATCH 0937/2357] rt2x00: Fix rfkill polling prior to interface start. commit a396e10019eaf3809b0219c966865aaafec12630 upstream. We need to program the rfkill switch GPIO pin direction to input at device initialization time, not only when the interface is brought up. Doing this only when the interface is brought up could lead to rfkill detecting the switch is turned on erroneously and inability to create the interface and bringing it up. Reported-and-tested-by: Andreas Messer Signed-off-by: Gertjan van Wingerde Acked-by: Ivo Van Doorn Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2400pci.c | 9 +++++++++ drivers/net/wireless/rt2x00/rt2400pci.h | 1 + drivers/net/wireless/rt2x00/rt2500pci.c | 9 +++++++++ drivers/net/wireless/rt2x00/rt2500usb.c | 9 +++++++++ drivers/net/wireless/rt2x00/rt2500usb.h | 1 + drivers/net/wireless/rt2x00/rt2800pci.c | 9 +++++++++ drivers/net/wireless/rt2x00/rt2800usb.c | 9 +++++++++ drivers/net/wireless/rt2x00/rt61pci.c | 9 +++++++++ drivers/net/wireless/rt2x00/rt61pci.h | 1 + drivers/net/wireless/rt2x00/rt73usb.c | 9 +++++++++ drivers/net/wireless/rt2x00/rt73usb.h | 3 +++ 11 files changed, 69 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 3a6b40239bc..0ea85f46659 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1611,6 +1611,7 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + u32 reg; /* * Allocate eeprom data. @@ -1623,6 +1624,14 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * Enable rfkill polling by setting GPIO direction of the + * rfkill switch GPIO pin correctly. + */ + rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); + rt2x00_set_field32(®, GPIOCSR_BIT8, 1); + rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg); + /* * Initialize hw specifications. */ diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index d3a4a68cc43..7564ae992b7 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -670,6 +670,7 @@ #define GPIOCSR_BIT5 FIELD32(0x00000020) #define GPIOCSR_BIT6 FIELD32(0x00000040) #define GPIOCSR_BIT7 FIELD32(0x00000080) +#define GPIOCSR_BIT8 FIELD32(0x00000100) /* * BBPPCSR: BBP Pin control register. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index dcc0e1fcca7..aa10c48c0df 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1929,6 +1929,7 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + u32 reg; /* * Allocate eeprom data. @@ -1941,6 +1942,14 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * Enable rfkill polling by setting GPIO direction of the + * rfkill switch GPIO pin correctly. + */ + rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); + rt2x00_set_field32(®, GPIOCSR_DIR0, 1); + rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg); + /* * Initialize hw specifications. */ diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b66b8b4e912..e0a7efccb73 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1768,6 +1768,7 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + u16 reg; /* * Allocate eeprom data. @@ -1780,6 +1781,14 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * Enable rfkill polling by setting GPIO direction of the + * rfkill switch GPIO pin correctly. + */ + rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); + rt2x00_set_field16(®, MAC_CSR19_BIT8, 0); + rt2500usb_register_write(rt2x00dev, MAC_CSR19, reg); + /* * Initialize hw specifications. */ diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 192531db0b6..196bd5103e4 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -197,6 +197,7 @@ #define MAC_CSR19_BIT5 FIELD16(0x0020) #define MAC_CSR19_BIT6 FIELD16(0x0040) #define MAC_CSR19_BIT7 FIELD16(0x0080) +#define MAC_CSR19_BIT8 FIELD16(0x0100) /* * MAC_CSR20: LED control register. diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 0397bbf0ce0..ff81e761d20 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -973,6 +973,7 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + u32 reg; /* * Allocate eeprom data. @@ -985,6 +986,14 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * Enable rfkill polling by setting GPIO direction of the + * rfkill switch GPIO pin correctly. + */ + rt2x00pci_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + rt2x00_set_field32(®, GPIO_CTRL_CFG_GPIOD_BIT2, 1); + rt2x00pci_register_write(rt2x00dev, GPIO_CTRL_CFG, reg); + /* * Initialize hw specifications. */ diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index bec1c60cb7f..a9d124bd80d 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -736,6 +736,7 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + u32 reg; /* * Allocate eeprom data. @@ -748,6 +749,14 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * Enable rfkill polling by setting GPIO direction of the + * rfkill switch GPIO pin correctly. + */ + rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + rt2x00_set_field32(®, GPIO_CTRL_CFG_GPIOD_BIT2, 1); + rt2x00usb_register_write(rt2x00dev, GPIO_CTRL_CFG, reg); + /* * Initialize hw specifications. */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 0f4bf8c23bf..bdaba3fddd9 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2832,6 +2832,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + u32 reg; /* * Disable power saving. @@ -2849,6 +2850,14 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * Enable rfkill polling by setting GPIO direction of the + * rfkill switch GPIO pin correctly. + */ + rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); + rt2x00_set_field32(®, MAC_CSR13_BIT13, 1); + rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg); + /* * Initialize hw specifications. */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index e3cd6db76b0..8f3da5a5676 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -372,6 +372,7 @@ struct hw_pairwise_ta_entry { #define MAC_CSR13_BIT10 FIELD32(0x00000400) #define MAC_CSR13_BIT11 FIELD32(0x00000800) #define MAC_CSR13_BIT12 FIELD32(0x00001000) +#define MAC_CSR13_BIT13 FIELD32(0x00002000) /* * MAC_CSR14: LED control register. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index e477a964081..fda8671474d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2177,6 +2177,7 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + u32 reg; /* * Allocate eeprom data. @@ -2189,6 +2190,14 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * Enable rfkill polling by setting GPIO direction of the + * rfkill switch GPIO pin correctly. + */ + rt2x00usb_register_read(rt2x00dev, MAC_CSR13, ®); + rt2x00_set_field32(®, MAC_CSR13_BIT15, 0); + rt2x00usb_register_write(rt2x00dev, MAC_CSR13, reg); + /* * Initialize hw specifications. */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 9f6b470414d..df1cc116b83 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -282,6 +282,9 @@ struct hw_pairwise_ta_entry { #define MAC_CSR13_BIT10 FIELD32(0x00000400) #define MAC_CSR13_BIT11 FIELD32(0x00000800) #define MAC_CSR13_BIT12 FIELD32(0x00001000) +#define MAC_CSR13_BIT13 FIELD32(0x00002000) +#define MAC_CSR13_BIT14 FIELD32(0x00004000) +#define MAC_CSR13_BIT15 FIELD32(0x00008000) /* * MAC_CSR14: LED control register. From f15e72437813a8943aaa3f7528e464923c31437f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 3 Sep 2012 14:56:02 -0400 Subject: [PATCH 0938/2357] NFS: Fix the initialisation of the readdir 'cookieverf' array commit c3f52af3e03013db5237e339c817beaae5ec9e3a upstream. When the NFS_COOKIEVERF helper macro was converted into a static inline function in commit 99fadcd764 (nfs: convert NFS_*(inode) helpers to static inline), we broke the initialisation of the readdir cookies, since that depended on doing a memset with an argument of 'sizeof(NFS_COOKIEVERF(inode))' which therefore changed from sizeof(be32 cookieverf[2]) to sizeof(be32 *). At this point, NFS_COOKIEVERF seems to be more of an obfuscation than a helper, so the best thing would be to just get rid of it. Also see: https://bugzilla.kernel.org/show_bug.cgi?id=46881 Reported-by: Andi Kleen Reported-by: David Binderman Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/inode.c | 2 +- fs/nfs/nfs3proc.c | 2 +- fs/nfs/nfs4proc.c | 4 ++-- include/linux/nfs_fs.h | 5 ----- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index e8bbfa5b350..edf411988bf 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -152,7 +152,7 @@ static void nfs_zap_caches_locked(struct inode *inode) nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo_timestamp = jiffies; - memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); + memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; else diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index a1e416b7bae..a7a043d272d 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -644,7 +644,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page **pages, unsigned int count, int plus) { struct inode *dir = dentry->d_inode; - __be32 *verf = NFS_COOKIEVERF(dir); + __be32 *verf = NFS_I(dir)->cookieverf; struct nfs3_readdirargs arg = { .fh = NFS_FH(dir), .cookie = cookie, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index dc573245eea..b106b9729bc 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3150,11 +3150,11 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, dentry->d_parent->d_name.name, dentry->d_name.name, (unsigned long long)cookie); - nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); + nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args); res.pgbase = args.pgbase; status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); if (status >= 0) { - memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); + memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE); status += args.pgbase; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 52a1bdb4ee2..941d688c203 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -264,11 +264,6 @@ static inline const struct nfs_rpc_ops *NFS_PROTO(const struct inode *inode) return NFS_SERVER(inode)->nfs_client->rpc_ops; } -static inline __be32 *NFS_COOKIEVERF(const struct inode *inode) -{ - return NFS_I(inode)->cookieverf; -} - static inline unsigned NFS_MINATTRTIMEO(const struct inode *inode) { struct nfs_server *nfss = NFS_SERVER(inode); From 3672dff93b8c5c7d2ebaf18eb32c98b06e942dac Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 4 Sep 2012 11:05:07 -0400 Subject: [PATCH 0939/2357] NFS: Fix a problem with the legacy binary mount code commit 872ece86ea5c367aa92f44689c2d01a1c767aeb3 upstream. Apparently, am-utils is still using the legacy binary mountdata interface, and is having trouble parsing /proc/mounts due to the 'port=' field being incorrectly set. The following patch should fix up the regression. Reported-by: Marius Tolzmann Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 7b55f51137e..5976e243d24 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1886,6 +1886,7 @@ static int nfs_validate_mount_data(void *options, memcpy(sap, &data->addr, sizeof(data->addr)); args->nfs_server.addrlen = sizeof(data->addr); + args->nfs_server.port = ntohs(data->addr.sin_port); if (!nfs_verify_server_address(sap)) goto out_no_address; @@ -2598,6 +2599,7 @@ static int nfs4_validate_mount_data(void *options, return -EFAULT; if (!nfs_verify_server_address(sap)) goto out_no_address; + args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port); if (data->auth_flavourlen) { if (data->auth_flavourlen > 1) From 6da04d620105c54d37de139f9b09e62196b5d0c3 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Thu, 6 Sep 2012 15:54:27 -0400 Subject: [PATCH 0940/2357] NFS: return error from decode_getfh in decode open commit 01913b49cf1dc6409a07dd2a4cc6af2e77f3c410 upstream. If decode_getfh failed, nfs4_xdr_dec_open would return 0 since the last decode_* call must have succeeded. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4xdr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index c54aae364be..c8ac9a1461c 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -6081,7 +6081,8 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr, status = decode_open(xdr, res); if (status) goto out; - if (decode_getfh(xdr, &res->fh) != 0) + status = decode_getfh(xdr, &res->fh); + if (status) goto out; if (decode_getfattr(xdr, res->f_attr, res->server) != 0) goto out; From 7fe0451922d30d1e540edaa26c95dd708ae55e1a Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Fri, 7 Sep 2012 11:23:28 +0530 Subject: [PATCH 0941/2357] EHCI: Update qTD next pointer in QH overlay region during unlink commit 3d037774b42ed677f699b1dce7d548d55f4e4c2b upstream. There is a possibility of QH overlay region having reference to a stale qTD pointer during unlink. Consider an endpoint having two pending qTD before unlink process begins. The endpoint's QH queue looks like this. qTD1 --> qTD2 --> Dummy To unlink qTD2, QH is removed from asynchronous list and Asynchronous Advance Doorbell is programmed. The qTD1's next qTD pointer is set to qTD2'2 next qTD pointer and qTD2 is retired upon controller's doorbell interrupt. If QH's current qTD pointer points to qTD1, transfer overlay region still have reference to qTD2. But qtD2 is just unlinked and freed. This may cause EHCI system error. Fix this by updating qTD next pointer in QH overlay region with the qTD next pointer of the current qTD. Signed-off-by: Pavankumar Kondeti Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 36ca5077cdf..7261e8fc857 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -128,9 +128,17 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) else { qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list); - /* first qtd may already be partially processed */ - if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) + /* + * first qtd may already be partially processed. + * If we come here during unlink, the QH overlay region + * might have reference to the just unlinked qtd. The + * qtd is updated in qh_completions(). Update the QH + * overlay here. + */ + if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) { + qh->hw->hw_qtd_next = qtd->hw_next; qtd = NULL; + } } if (qtd) From 7d9088f7173dc7e93d73bbe1b3fdc8f2ea107275 Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Fri, 31 Aug 2012 00:00:28 +0200 Subject: [PATCH 0942/2357] USB: ftdi_sio: PID for NZR SEM 16+ USB commit 26a538b9ea2a3ee10dafc0068f0560dfd7b7ba37 upstream. This adds the USB PID for the NZR SEM 16+ USB energy monitor device . It works perfectly with the GPL software on . Signed-off-by: Horst Schirmeier Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f5819cb4dcf..5b066be62a3 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -704,6 +704,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) }, { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) }, { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) }, { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 5dd96ca6c38..117f42ba770 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -75,6 +75,9 @@ #define FTDI_OPENDCC_GATEWAY_PID 0xBFDB #define FTDI_OPENDCC_GBM_PID 0xBFDC +/* NZR SEM 16+ USB (http://www.nzr.de) */ +#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */ + /* * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) */ From c5a79afd07d3aa476eb62851df56fe53f5c07d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 10 Sep 2012 12:01:05 +0200 Subject: [PATCH 0943/2357] USB: ftdi_sio: do not claim CDC ACM function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f08dea734844aa42ec57c229b0b73b3d7d21f810 upstream. The Microchip vid:pid 04d8:000a is used for their CDC ACM demo firmware application. This is a device with a single function conforming to the CDC ACM specification and with the intention of demonstrating CDC ACM class firmware and driver interaction. The demo is used on a number of development boards, and may also be used unmodified by vendors using Microchip hardware. Some vendors have re-used this vid:pid for other types of firmware, emulating FTDI chips. Attempting to continue to support such devices without breaking class based applications that by matching on interface class/subclass/proto being ff/ff/00. I have no information about the actual device or interface descriptors, but this will at least make the proper CDC ACM devices work again. Anyone having details of the offending device's descriptors should update this entry with the details. Reported-by: Florian Wöhrl Reported-by: Xiaofan Chen Cc: Alan Cox Cc: Bruno Thomsen Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 4 +++- drivers/usb/serial/ftdi_sio_ids.h | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 5b066be62a3..d0d97ca4473 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -805,7 +805,9 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID) }, + { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID, + USB_CLASS_VENDOR_SPEC, + USB_SUBCLASS_VENDOR_SPEC, 0x00) }, { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 117f42ba770..899b65ae290 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -542,7 +542,10 @@ /* * Microchip Technology, Inc. * - * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are also used by: + * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are + * used by single function CDC ACM class based firmware demo + * applications. The VID/PID has also been used in firmware + * emulating FTDI serial chips by: * Hornby Elite - Digital Command Control Console * http://www.hornby.com/hornby-dcc/controllers/ */ From 1ea39e97a7cebcb8ab8c969ba05ac1e8b1b0457d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Piel?= Date: Tue, 4 Sep 2012 17:25:06 +0200 Subject: [PATCH 0944/2357] USB: ftdi-sio: add support for more Physik Instrumente devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit dafc4f7be1a556ca3868d343c00127728b397068 upstream. Commit b69cc672052540 added support for the E-861. After acquiring a C-867, I realised that every Physik Instrumente's device has a different PID. They are listed in the Windows device driver's .inf file. So here are all PIDs for the current (and probably future) USB devices from Physik Instrumente. Compiled, but only actually tested on the E-861 and C-867. Signed-off-by: Éric Piel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 17 +++++++++++++++++ drivers/usb/serial/ftdi_sio_ids.h | 21 ++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d0d97ca4473..4d2b7d31fc6 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -813,7 +813,24 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, + { USB_DEVICE(FTDI_VID, PI_C865_PID) }, + { USB_DEVICE(FTDI_VID, PI_C857_PID) }, + { USB_DEVICE(PI_VID, PI_C866_PID) }, + { USB_DEVICE(PI_VID, PI_C663_PID) }, + { USB_DEVICE(PI_VID, PI_C725_PID) }, + { USB_DEVICE(PI_VID, PI_E517_PID) }, + { USB_DEVICE(PI_VID, PI_C863_PID) }, { USB_DEVICE(PI_VID, PI_E861_PID) }, + { USB_DEVICE(PI_VID, PI_C867_PID) }, + { USB_DEVICE(PI_VID, PI_E609_PID) }, + { USB_DEVICE(PI_VID, PI_E709_PID) }, + { USB_DEVICE(PI_VID, PI_100F_PID) }, + { USB_DEVICE(PI_VID, PI_1011_PID) }, + { USB_DEVICE(PI_VID, PI_1012_PID) }, + { USB_DEVICE(PI_VID, PI_1013_PID) }, + { USB_DEVICE(PI_VID, PI_1014_PID) }, + { USB_DEVICE(PI_VID, PI_1015_PID) }, + { USB_DEVICE(PI_VID, PI_1016_PID) }, { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) }, { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 899b65ae290..41fe5826100 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -797,8 +797,27 @@ * Physik Instrumente * http://www.physikinstrumente.com/en/products/ */ +/* These two devices use the VID of FTDI */ +#define PI_C865_PID 0xe0a0 /* PI C-865 Piezomotor Controller */ +#define PI_C857_PID 0xe0a1 /* PI Encoder Trigger Box */ + #define PI_VID 0x1a72 /* Vendor ID */ -#define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */ +#define PI_C866_PID 0x1000 /* PI C-866 Piezomotor Controller */ +#define PI_C663_PID 0x1001 /* PI C-663 Mercury-Step */ +#define PI_C725_PID 0x1002 /* PI C-725 Piezomotor Controller */ +#define PI_E517_PID 0x1005 /* PI E-517 Digital Piezo Controller Operation Module */ +#define PI_C863_PID 0x1007 /* PI C-863 */ +#define PI_E861_PID 0x1008 /* PI E-861 Piezomotor Controller */ +#define PI_C867_PID 0x1009 /* PI C-867 Piezomotor Controller */ +#define PI_E609_PID 0x100D /* PI E-609 Digital Piezo Controller */ +#define PI_E709_PID 0x100E /* PI E-709 Digital Piezo Controller */ +#define PI_100F_PID 0x100F /* PI Digital Piezo Controller */ +#define PI_1011_PID 0x1011 /* PI Digital Piezo Controller */ +#define PI_1012_PID 0x1012 /* PI Motion Controller */ +#define PI_1013_PID 0x1013 /* PI Motion Controller */ +#define PI_1014_PID 0x1014 /* PI Device */ +#define PI_1015_PID 0x1015 /* PI Device */ +#define PI_1016_PID 0x1016 /* PI Digital Servo Module */ /* * Kondo Kagaku Co.Ltd. From 7acab78d0fc555fb57cc8b5a5080b5f637f447a1 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 10 Aug 2012 13:42:16 +0530 Subject: [PATCH 0945/2357] usb: dwc3: ep0: correct cache sync issue in case of ep0_bounced commit 0416e494ce7dc84e2719bc9fb7daecb330476074 upstream. In case of ep0 out, if length is not aligned to maxpacket size then we use dwc->ep_bounce_addr for dma transfer and not request->dma. Since, we have alreday done memcpy from dwc->ep0_bounce to request->buf, so we do not need to issue cache sync function. In fact, cache sync function will bring wrong data in request->buf from request->dma in this scenario. So, cache sync function must not be executed in case of ep0 bounced. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/ep0.c | 1 - drivers/usb/dwc3/gadget.c | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3584a169886..e4d87d70055 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -569,7 +569,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, transferred = min_t(u32, ur->length, transfer_size - length); memcpy(ur->buf, dwc->ep0_bounce, transferred); - dwc->ep0_bounced = false; } else { transferred = ur->length - length; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5255fe975ea..b8d46978fc5 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -238,8 +238,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, if (req->request.status == -EINPROGRESS) req->request.status = status; - usb_gadget_unmap_request(&dwc->gadget, &req->request, - req->direction); + if (dwc->ep0_bounced && dep->number == 0) + dwc->ep0_bounced = false; + else + usb_gadget_unmap_request(&dwc->gadget, &req->request, + req->direction); dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n", req, dep->name, req->request.actual, From 5527f1341645e192145f7e581230dcf4447dd8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 10 Sep 2012 22:17:34 +0200 Subject: [PATCH 0946/2357] USB: cdc-wdm: fix wdm_find_device* return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6a44886899ef8cc396e230e492e6a56a883889f3 upstream. A logic error made the wdm_find_device* functions return a bogus pointer into static data instead of the intended NULL no matching device was found. Signed-off-by: Bjørn Mork Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 01d247e8808..524fe240fcd 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -134,12 +134,14 @@ static struct usb_driver wdm_driver; /* return intfdata if we own the interface, else look up intf in the list */ static struct wdm_device *wdm_find_device(struct usb_interface *intf) { - struct wdm_device *desc = NULL; + struct wdm_device *desc; spin_lock(&wdm_device_list_lock); list_for_each_entry(desc, &wdm_device_list, device_list) if (desc->intf == intf) - break; + goto found; + desc = NULL; +found: spin_unlock(&wdm_device_list_lock); return desc; @@ -147,12 +149,14 @@ static struct wdm_device *wdm_find_device(struct usb_interface *intf) static struct wdm_device *wdm_find_device_by_minor(int minor) { - struct wdm_device *desc = NULL; + struct wdm_device *desc; spin_lock(&wdm_device_list_lock); list_for_each_entry(desc, &wdm_device_list, device_list) if (desc->intf->minor == minor) - break; + goto found; + desc = NULL; +found: spin_unlock(&wdm_device_list_lock); return desc; From 61fee2c3e35d8496685317c4e17c98e8905ba762 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 29 Aug 2012 11:49:18 +0200 Subject: [PATCH 0947/2357] USB: ohci-at91: fix PIO handling in relation with number of ports commit 6fffb77c8393151b0cf8cef1b9c2ba90587dd2e8 upstream. If the number of ports present on the SoC/board is not the maximum and that the platform data is not filled with all data, there is an easy way to mess the PIO setup for this interface. This quick fix addresses mis-configuration in USB host platform data that is common in at91 boards since commit 0ee6d1e (USB: ohci-at91: change maximum number of ports) that did not modified the associatd board files. Reported-by: Klaus Falkner Signed-off-by: Nicolas Ferre Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 55d3d641447..50bd3f1e330 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -569,6 +569,16 @@ static int __devinit ohci_hcd_at91_drv_probe(struct platform_device *pdev) if (pdata) { at91_for_each_port(i) { + /* + * do not configure PIO if not in relation with + * real USB port on board + */ + if (i >= pdata->ports) { + pdata->vbus_pin[i] = -EINVAL; + pdata->overcurrent_pin[i] = -EINVAL; + break; + } + if (!gpio_is_valid(pdata->vbus_pin[i])) continue; gpio = pdata->vbus_pin[i]; From adc7b2b36a6fb6854f2146d86f08d362b6aa0b83 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 4 Sep 2012 10:41:02 -0400 Subject: [PATCH 0948/2357] USB: add device quirk for Joss Optical touchboard commit 92fc7a8b0f20bdb243c706daf42658e8e0cd2ef0 upstream. This patch (as1604) adds a CONFIG_INTF_STRINGS quirk for the Joss infrared touchboard device. The device doesn't like to be asked for its interface strings. Signed-off-by: Alan Stern Reported-by: adam ? Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 32d3adc315f..8b2a9d83090 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -96,6 +96,10 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x04b4, 0x0526), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Microchip Joss Optical infrared touchboard device */ + { USB_DEVICE(0x04d8, 0x000c), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Samsung Android phone modem - ID conflict with SPH-I500 */ { USB_DEVICE(0x04e8, 0x6601), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, From 1f92c25123b256e3c8d892fcb0d71760445ccb90 Mon Sep 17 00:00:00 2001 From: Sergei Poselenov Date: Sun, 2 Sep 2012 13:14:32 +0400 Subject: [PATCH 0949/2357] rt2800usb: Added rx packet length validity check commit efd5d6b03bd9c9e0df646c56fb5f4f3e25e5c1ac upstream. On our system (ARM Cortex-M3 SOC running linux-2.6.33) frequent crashes were observed in the rt2800usb module because of the invalid length of the received packet (3392, 46920...). This patch adds the sanity check on the packet legth. Also, changed WARNING to ERROR in rt2x00lib_rxdone() so that the bad packet condition would be noticed. The fix was tested on the latest compat-wireless-3.5.1-1-snpc. Signed-off-by: Sergei Poselenov Acked-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800usb.c | 10 +++++++++- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index a9d124bd80d..65cb4250259 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -667,8 +667,16 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, skb_pull(entry->skb, RXINFO_DESC_SIZE); /* - * FIXME: we need to check for rx_pkt_len validity + * Check for rx_pkt_len validity. Return if invalid, leaving + * rxdesc->size zeroed out by the upper level. */ + if (unlikely(rx_pkt_len == 0 || + rx_pkt_len > entry->queue->data_size)) { + ERROR(entry->queue->rt2x00dev, + "Bad frame size %d, forcing to 0\n", rx_pkt_len); + return; + } + rxd = (__le32 *)(entry->skb->data + rx_pkt_len); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 90cc5e77265..12b1ff5a6a3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -628,7 +628,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry) */ if (unlikely(rxdesc.size == 0 || rxdesc.size > entry->queue->data_size)) { - WARNING(rt2x00dev, "Wrong frame size %d max %d.\n", + ERROR(rt2x00dev, "Wrong frame size %d max %d.\n", rxdesc.size, entry->queue->data_size); dev_kfree_skb(entry->skb); goto renew_skb; From dadc5da6b79314943a7e5eda6369c70e3c7a1d26 Mon Sep 17 00:00:00 2001 From: "Alexis R. Cortes" Date: Fri, 3 Aug 2012 14:00:27 -0500 Subject: [PATCH 0950/2357] usb: host: xhci: Fix Compliance Mode on SN65LVPE502CP Hardware commit 71c731a296f1b08a3724bd1b514b64f1bda87a23 upstream. This patch is intended to work around a known issue on the SN65LVPE502CP USB3.0 re-driver that can delay the negotiation between a device and the host past the usual handshake timeout. If that happens on the first insertion, the host controller port will enter in Compliance Mode and NO port status event will be generated (as per xHCI Spec) making impossible to detect this event by software. The port will remain in compliance mode until a warm reset is applied to it. As a result of this, the port will seem "dead" to the user and no device connections or disconnections will be detected. For solving this, the patch creates a timer which polls every 2 seconds the link state of each host controller's port (this by reading the PORTSC register) and recovers the port by issuing a Warm reset every time Compliance mode is detected. If a xHC USB3.0 port has previously entered to U0, the compliance mode issue will NOT occur only until system resumes from sleep/hibernate, therefore, the compliance mode timer is stopped when all xHC USB 3.0 ports have entered U0. The timer is initialized again after each system resume. Since the issue is being caused by a piece of hardware, the timer will be enabled ONLY on those systems that have the SN65LVPE502CP installed (this patch uses DMI strings for detecting those systems) therefore making this patch to act as a quirk (XHCI_COMP_MODE_QUIRK has been added to the xhci stack). This patch applies for these systems: Vendor: Hewlett-Packard. System Models: Z420, Z620 and Z820. This patch should be backported to kernels as old as 3.2, as that was the first kernel to support warm reset. The kernels will need to contain both commit 10d674a82e553cb8a1f41027bb3c3e309b3f6804 "USB: When hot reset for USB3 fails, try warm reset" and commit 8bea2bd37df08aaa599aa361a9f8b836ba98e554 "usb: Add support for root hub port status CAS". The first patch add warm reset support, and the second patch modifies the USB core to issue a warm reset when the port is in compliance mode. Signed-off-by: Alexis R. Cortes Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 42 +++++++++++++ drivers/usb/host/xhci.c | 121 ++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 6 ++ 3 files changed, 169 insertions(+) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index bbf3c0c9cde..de07b7556d4 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -493,11 +493,48 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg) * when this bit is set. */ pls |= USB_PORT_STAT_CONNECTION; + } else { + /* + * If CAS bit isn't set but the Port is already at + * Compliance Mode, fake a connection so the USB core + * notices the Compliance state and resets the port. + * This resolves an issue generated by the SN65LVPE502CP + * in which sometimes the port enters compliance mode + * caused by a delay on the host-device negotiation. + */ + if (pls == USB_SS_PORT_LS_COMP_MOD) + pls |= USB_PORT_STAT_CONNECTION; } + /* update status field */ *status |= pls; } +/* + * Function for Compliance Mode Quirk. + * + * This Function verifies if all xhc USB3 ports have entered U0, if so, + * the compliance mode timer is deleted. A port won't enter + * compliance mode if it has previously entered U0. + */ +void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) +{ + u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1); + bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0); + + if (!(xhci->quirks & XHCI_COMP_MODE_QUIRK)) + return; + + if ((xhci->port_status_u0 != all_ports_seen_u0) && port_in_u0) { + xhci->port_status_u0 |= 1 << wIndex; + if (xhci->port_status_u0 == all_ports_seen_u0) { + del_timer_sync(&xhci->comp_mode_recovery_timer); + xhci_dbg(xhci, "All USB3 ports have entered U0 already!\n"); + xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted.\n"); + } + } +} + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { @@ -644,6 +681,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* Update Port Link State for super speed ports*/ if (hcd->speed == HCD_USB3) { xhci_hub_report_link_state(&status, temp); + /* + * Verify if all USB3 Ports Have entered U0 already. + * Delete Compliance Mode Timer if so. + */ + xhci_del_comp_mod_timer(xhci, temp, wIndex); } if (bus_state->port_c_suspend & (1 << wIndex)) status |= 1 << USB_PORT_FEAT_C_SUSPEND; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7beed536e6b..4afe3af319d 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "xhci.h" @@ -398,6 +399,95 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) #endif +static void compliance_mode_recovery(unsigned long arg) +{ + struct xhci_hcd *xhci; + struct usb_hcd *hcd; + u32 temp; + int i; + + xhci = (struct xhci_hcd *)arg; + + for (i = 0; i < xhci->num_usb3_ports; i++) { + temp = xhci_readl(xhci, xhci->usb3_ports[i]); + if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) { + /* + * Compliance Mode Detected. Letting USB Core + * handle the Warm Reset + */ + xhci_dbg(xhci, "Compliance Mode Detected->Port %d!\n", + i + 1); + xhci_dbg(xhci, "Attempting Recovery routine!\n"); + hcd = xhci->shared_hcd; + + if (hcd->state == HC_STATE_SUSPENDED) + usb_hcd_resume_root_hub(hcd); + + usb_hcd_poll_rh_status(hcd); + } + } + + if (xhci->port_status_u0 != ((1 << xhci->num_usb3_ports)-1)) + mod_timer(&xhci->comp_mode_recovery_timer, + jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); +} + +/* + * Quirk to work around issue generated by the SN65LVPE502CP USB3.0 re-driver + * that causes ports behind that hardware to enter compliance mode sometimes. + * The quirk creates a timer that polls every 2 seconds the link state of + * each host controller's port and recovers it by issuing a Warm reset + * if Compliance mode is detected, otherwise the port will become "dead" (no + * device connections or disconnections will be detected anymore). Becasue no + * status event is generated when entering compliance mode (per xhci spec), + * this quirk is needed on systems that have the failing hardware installed. + */ +static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci) +{ + xhci->port_status_u0 = 0; + init_timer(&xhci->comp_mode_recovery_timer); + + xhci->comp_mode_recovery_timer.data = (unsigned long) xhci; + xhci->comp_mode_recovery_timer.function = compliance_mode_recovery; + xhci->comp_mode_recovery_timer.expires = jiffies + + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS); + + set_timer_slack(&xhci->comp_mode_recovery_timer, + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); + add_timer(&xhci->comp_mode_recovery_timer); + xhci_dbg(xhci, "Compliance Mode Recovery Timer Initialized.\n"); +} + +/* + * This function identifies the systems that have installed the SN65LVPE502CP + * USB3.0 re-driver and that need the Compliance Mode Quirk. + * Systems: + * Vendor: Hewlett-Packard -> System Models: Z420, Z620 and Z820 + */ +static bool compliance_mode_recovery_timer_quirk_check(void) +{ + const char *dmi_product_name, *dmi_sys_vendor; + + dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); + dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR); + + if (!(strstr(dmi_sys_vendor, "Hewlett-Packard"))) + return false; + + if (strstr(dmi_product_name, "Z420") || + strstr(dmi_product_name, "Z620") || + strstr(dmi_product_name, "Z820")) + return true; + + return false; +} + +static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci) +{ + return (xhci->port_status_u0 == ((1 << xhci->num_usb3_ports)-1)); +} + + /* * Initialize memory for HCD and xHC (one-time init). * @@ -421,6 +511,12 @@ int xhci_init(struct usb_hcd *hcd) retval = xhci_mem_init(xhci, GFP_KERNEL); xhci_dbg(xhci, "Finished xhci_init\n"); + /* Initializing Compliance Mode Recovery Data If Needed */ + if (compliance_mode_recovery_timer_quirk_check()) { + xhci->quirks |= XHCI_COMP_MODE_QUIRK; + compliance_mode_recovery_timer_init(xhci); + } + return retval; } @@ -629,6 +725,11 @@ void xhci_stop(struct usb_hcd *hcd) del_timer_sync(&xhci->event_ring_timer); #endif + /* Deleting Compliance Mode Recovery Timer */ + if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && + (!(xhci_all_ports_seen_u0(xhci)))) + del_timer_sync(&xhci->comp_mode_recovery_timer); + if (xhci->quirks & XHCI_AMD_PLL_FIX) usb_amd_dev_put(); @@ -806,6 +907,16 @@ int xhci_suspend(struct xhci_hcd *xhci) } spin_unlock_irq(&xhci->lock); + /* + * Deleting Compliance Mode Recovery Timer because the xHCI Host + * is about to be suspended. + */ + if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && + (!(xhci_all_ports_seen_u0(xhci)))) { + del_timer_sync(&xhci->comp_mode_recovery_timer); + xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted!\n"); + } + /* step 5: remove core well power */ /* synchronize irq when using MSI-X */ xhci_msix_sync_irqs(xhci); @@ -938,6 +1049,16 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(xhci->shared_hcd); } + + /* + * If system is subject to the Quirk, Compliance Mode Timer needs to + * be re-initialized Always after a system resume. Ports are subject + * to suffer the Compliance Mode issue again. It doesn't matter if + * ports have entered previously to U0 before system's suspension. + */ + if (xhci->quirks & XHCI_COMP_MODE_QUIRK) + compliance_mode_recovery_timer_init(xhci); + return retval; } #endif /* CONFIG_PM */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 19ae30f1d84..6e77f3b5a7f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1487,6 +1487,7 @@ struct xhci_hcd { #define XHCI_AMD_0x96_HOST (1 << 9) #define XHCI_TRUST_TX_LENGTH (1 << 10) #define XHCI_SPURIOUS_REBOOT (1 << 13) +#define XHCI_COMP_MODE_QUIRK (1 << 14) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ @@ -1503,6 +1504,11 @@ struct xhci_hcd { unsigned sw_lpm_support:1; /* support xHCI 1.0 spec USB2 hardware LPM */ unsigned hw_lpm_support:1; + /* Compliance Mode Recovery Data */ + struct timer_list comp_mode_recovery_timer; + u32 port_status_u0; +/* Compliance Mode Timer Triggered every 2 seconds */ +#define COMP_MODE_RCVRY_MSECS 2000 }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ From 3c4154bb097ffc933a70771e976949d00969d451 Mon Sep 17 00:00:00 2001 From: Keng-Yu Lin Date: Fri, 10 Aug 2012 01:39:23 +0800 Subject: [PATCH 0951/2357] Intel xhci: Only switch the switchable ports commit a96874a2a92feaef607ddd3137277a788cb927a6 upstream. With a previous patch to enable the EHCI/XHCI port switching, it switches all the available ports. The assumption is not correct because the BIOS may expect some ports not switchable by the OS. There are two more registers that contains the information of the switchable and non-switchable ports. This patch adds the checking code for the two register so that only the switchable ports are altered. This patch should be backported to kernels as old as 3.0, that contain commit ID 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support EHCI/xHCI port switching." Signed-off-by: Keng-Yu Lin Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c5e9e4a76f1..b586863e050 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -75,7 +75,9 @@ #define NB_PIF0_PWRDOWN_1 0x01100013 #define USB_INTEL_XUSB2PR 0xD0 +#define USB_INTEL_USB2PRM 0xD4 #define USB_INTEL_USB3_PSSEN 0xD8 +#define USB_INTEL_USB3PRM 0xDC static struct amd_chipset_info { struct pci_dev *nb_dev; @@ -772,10 +774,18 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) return; } - ports_available = 0xffffffff; + /* Read USB3PRM, the USB 3.0 Port Routing Mask Register + * Indicate the ports that can be changed from OS. + */ + pci_read_config_dword(xhci_pdev, USB_INTEL_USB3PRM, + &ports_available); + + dev_dbg(&xhci_pdev->dev, "Configurable ports to enable SuperSpeed: 0x%x\n", + ports_available); + /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable - * Register, to turn on SuperSpeed terminations for all - * available ports. + * Register, to turn on SuperSpeed terminations for the + * switchable ports. */ pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, cpu_to_le32(ports_available)); @@ -785,7 +795,16 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled " "under xHCI: 0x%x\n", ports_available); - ports_available = 0xffffffff; + /* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register + * Indicate the USB 2.0 ports to be controlled by the xHCI host. + */ + + pci_read_config_dword(xhci_pdev, USB_INTEL_USB2PRM, + &ports_available); + + dev_dbg(&xhci_pdev->dev, "Configurable USB 2.0 ports to hand over to xCHI: 0x%x\n", + ports_available); + /* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to * switch the USB 2.0 power and data lines over to the xHCI * host. From 40fd8822f49ad6ac2b7a575e3b2020e7382db431 Mon Sep 17 00:00:00 2001 From: Ruchika Kharwar Date: Fri, 10 Aug 2012 09:58:30 +0300 Subject: [PATCH 0952/2357] usb: host: xhci-plat: use ioremap_nocache commit 319acdfc064169023cd9ada5085b434fbcdacec2 upstream. Use the ioremap_nocache variant of the ioremap API in order to make sure our memory will be marked uncachable. This patch should be backported to kernels as old as 3.4, that contain the commit 3429e91a661e1f383aecc86c6bbcf65afb15c892 "usb: host: xhci: add platform driver support". Signed-off-by: Ruchika Kharwar Signed-off-by: Felipe Balbi Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 689bc18b051..df90fe51b4a 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -118,7 +118,7 @@ static int xhci_plat_probe(struct platform_device *pdev) goto put_hcd; } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_dbg(&pdev->dev, "error mapping memory\n"); ret = -EFAULT; From 3dd2f0bb418f24a3b9a0b9b93b1ba104c2e6d140 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 13 Aug 2012 19:57:03 +0300 Subject: [PATCH 0953/2357] xhci: Fix a logical vs bitwise AND bug commit 052c7f9ffb0e95843e75448d02664459253f9ff8 upstream. The intent was to test whether the flag was set. This patch should be backported to stable kernels as old as 3.0, since it fixes a bug in commit e95829f474f0db3a4d940cae1423783edd966027 "xhci: Switch PPT ports to EHCI on shutdown.", which was marked for stable. Signed-off-by: Dan Carpenter Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 4afe3af319d..6467d79d760 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -760,7 +760,7 @@ void xhci_shutdown(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - if (xhci->quirks && XHCI_SPURIOUS_REBOOT) + if (xhci->quirks & XHCI_SPURIOUS_REBOOT) usb_disable_xhci_ports(to_pci_dev(hcd->self.controller)); spin_lock_irq(&xhci->lock); From 279412b46d186d0cb6badb02e3bfd4d03beff43e Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 14 Aug 2012 16:44:49 -0400 Subject: [PATCH 0954/2357] xhci: Make handover code more robust commit e955a1cd086de4d165ae0f4c7be7289d84b63bdc upstream. My test platform (Intel DX79SI) boots reliably under BIOS, but frequently crashes when booting via UEFI. I finally tracked this down to the xhci handoff code. It seems that reads from the device occasionally just return 0xff, resulting in xhci_find_next_cap_offset generating a value that's larger than the resource region. We then oops when attempting to read the value. Sanity checking that value lets us avoid the crash. I've no idea what's causing the underlying problem, and xhci still doesn't actually *work* even with this, but the machine at least boots which will probably make further debugging easier. This should be backported to kernels as old as 2.6.31, that contain the commit 66d4eadd8d067269ea8fead1a50fe87c2979a80d "USB: xhci: BIOS handoff and HW initialization." Signed-off-by: Matthew Garrett Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index b586863e050..e3a9e0b3f1e 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -841,12 +841,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) void __iomem *op_reg_base; u32 val; int timeout; + int len = pci_resource_len(pdev, 0); if (!mmio_resource_enabled(pdev, 0)) return; - base = ioremap_nocache(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); + base = ioremap_nocache(pci_resource_start(pdev, 0), len); if (base == NULL) return; @@ -856,9 +856,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) */ ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); do { + if ((ext_cap_offset + sizeof(val)) > len) { + /* We're reading garbage from the controller */ + dev_warn(&pdev->dev, + "xHCI controller failing to respond"); + return; + } + if (!ext_cap_offset) /* We've reached the end of the extended capabilities */ goto hc_init; + val = readl(base + ext_cap_offset); if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) break; From fa544a230c9ce8b56bef4ea64f2d606f95cee37b Mon Sep 17 00:00:00 2001 From: Manoj Iyer Date: Wed, 22 Aug 2012 11:53:18 -0500 Subject: [PATCH 0955/2357] xhci: Recognize USB 3.0 devices as superspeed at powerup commit 29d214576f936db627ff62afb9ef438eea18bcd2 upstream. On Intel Panther Point chipset USB 3.0 devices show up as high-speed devices on powerup, but after an s3 cycle they are correctly recognized as SuperSpeed. At powerup switch the port to xHCI so that USB 3.0 devices are correctly recognized. BugLink: http://bugs.launchpad.net/bugs/1000424 This patch should be backported to kernels as old as 3.0, that contain commit ID 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support EHCI/xHCI port switching." Signed-off-by: Manoj Iyer Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index e3a9e0b3f1e..966d1484ee7 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -897,9 +897,10 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) /* Disable any BIOS SMIs and clear all SMI events*/ writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); +hc_init: if (usb_is_intel_switchable_xhci(pdev)) usb_enable_xhci_ports(pdev); -hc_init: + op_reg_base = base + XHCI_HC_LENGTH(readl(base)); /* Wait for the host controller to be ready before writing any From 48877fe63db63f981cc64d597369fb489ae2e556 Mon Sep 17 00:00:00 2001 From: Moiz Sonasath Date: Wed, 5 Sep 2012 08:34:26 +0300 Subject: [PATCH 0956/2357] usb: host: xhci: fix compilation error for non-PCI based stacks commit 296365781903226a3fb8758901eaeec09d2798e4 upstream. For non PCI-based stacks, this function call usb_disable_xhci_ports(to_pci_dev(hcd->self.controller)); made from xhci_shutdown is not applicable. Ideally, we wouldn't have any PCI-specific code on a generic driver such as the xHCI stack, but it looks like we should just stub usb_disable_xhci_ports() out for non-PCI devices. [ balbi@ti.com: slight improvement to commit log ] This patch should be backported to kernels as old as 3.0, since the commit it fixes (e95829f474f0db3a4d940cae1423783edd966027 "xhci: Switch PPT ports to EHCI on shutdown.") was marked for stable. Signed-off-by: Moiz Sonasath Signed-off-by: Ruchika Kharwar Signed-off-by: Felipe Balbi Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index ef004a5de20..7f69a39163c 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -15,6 +15,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); static inline void usb_amd_quirk_pll_disable(void) {} static inline void usb_amd_quirk_pll_enable(void) {} static inline void usb_amd_dev_put(void) {} +static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} #endif /* CONFIG_PCI */ #endif /* __LINUX_USB_PCI_QUIRKS_H */ From 86236252d2449313bdbac790023cbc957bf6e426 Mon Sep 17 00:00:00 2001 From: Xinyu Chen Date: Mon, 27 Aug 2012 09:36:51 +0200 Subject: [PATCH 0957/2357] tty: serial: imx: console write routing is unsafe on SMP commit 9ec1882df244c4ee1baa692676fef5e8b0f5487d upstream. The console feature's write routing is unsafe on SMP with the startup/shutdown call. There could be several consumers of the console * the kernel printk * the init process using /dev/kmsg to call printk to show log * shell, which open /dev/console and write with sys_write() The shell goes into the normal uart open/write routing, but the other two go into the console operations. The open routing calls imx serial startup, which will write USR1/2 register without any lock and critical with imx_console_write call. Add a spin_lock for startup/shutdown/console_write routing. This patch is a port from Freescale's Android kernel. Signed-off-by: Xinyu Chen Tested-by: Dirk Behme CC: Sascha Hauer Acked-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e7feceeebc2..0de7ed78863 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -756,6 +756,7 @@ static int imx_startup(struct uart_port *port) } } + spin_lock_irqsave(&sport->port.lock, flags); /* * Finally, clear and enable interrupts */ @@ -809,7 +810,6 @@ static int imx_startup(struct uart_port *port) /* * Enable modem status interrupts */ - spin_lock_irqsave(&sport->port.lock,flags); imx_enable_ms(&sport->port); spin_unlock_irqrestore(&sport->port.lock,flags); @@ -839,10 +839,13 @@ static void imx_shutdown(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + unsigned long flags; + spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR2); temp &= ~(UCR2_TXEN); writel(temp, sport->port.membase + UCR2); + spin_unlock_irqrestore(&sport->port.lock, flags); if (USE_IRDA(sport)) { struct imxuart_platform_data *pdata; @@ -871,12 +874,14 @@ static void imx_shutdown(struct uart_port *port) * Disable all interrupts, port and break condition. */ + spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); if (USE_IRDA(sport)) temp &= ~(UCR1_IREN); writel(temp, sport->port.membase + UCR1); + spin_unlock_irqrestore(&sport->port.lock, flags); } static void @@ -1219,6 +1224,9 @@ imx_console_write(struct console *co, const char *s, unsigned int count) struct imx_port *sport = imx_ports[co->index]; struct imx_port_ucrs old_ucr; unsigned int ucr1; + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); /* * First, save UCR1/2/3 and then disable interrupts @@ -1244,6 +1252,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count) while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); imx_port_ucrs_restore(&sport->port, &old_ucr); + + spin_unlock_irqrestore(&sport->port.lock, flags); } /* From e60b883144de35ea312a7570460cfe6a42af61c1 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 10 Aug 2012 15:22:09 +0100 Subject: [PATCH 0958/2357] mutex: Place lock in contended state after fastpath_lock failure commit 0bce9c46bf3b15f485d82d7e81dabed6ebcc24b1 upstream. ARM recently moved to asm-generic/mutex-xchg.h for its mutex implementation after the previous implementation was found to be missing some crucial memory barriers. However, this has revealed some problems running hackbench on SMP platforms due to the way in which the MUTEX_SPIN_ON_OWNER code operates. The symptoms are that a bunch of hackbench tasks are left waiting on an unlocked mutex and therefore never get woken up to claim it. This boils down to the following sequence of events: Task A Task B Task C Lock value 0 1 1 lock() 0 2 lock() 0 3 spin(A) 0 4 unlock() 1 5 lock() 0 6 cmpxchg(1,0) 0 7 contended() -1 8 lock() 0 9 spin(C) 0 10 unlock() 1 11 cmpxchg(1,0) 0 12 unlock() 1 At this point, the lock is unlocked, but Task B is in an uninterruptible sleep with nobody to wake it up. This patch fixes the problem by ensuring we put the lock into the contended state if we fail to acquire it on the fastpath, ensuring that any blocked waiters are woken up when the mutex is released. Signed-off-by: Will Deacon Cc: Arnd Bergmann Cc: Chris Mason Cc: Ingo Molnar Reviewed-by: Nicolas Pitre Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-6e9lrw2avczr0617fzl5vqb8@git.kernel.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- include/asm-generic/mutex-xchg.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/asm-generic/mutex-xchg.h b/include/asm-generic/mutex-xchg.h index 580a6d35c70..c04e0db8a2d 100644 --- a/include/asm-generic/mutex-xchg.h +++ b/include/asm-generic/mutex-xchg.h @@ -26,7 +26,13 @@ static inline void __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) { if (unlikely(atomic_xchg(count, 0) != 1)) - fail_fn(count); + /* + * We failed to acquire the lock, so mark it contended + * to ensure that any waiting tasks are woken up by the + * unlock slow path. + */ + if (likely(atomic_xchg(count, -1) != 1)) + fail_fn(count); } /** @@ -43,7 +49,8 @@ static inline int __mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) { if (unlikely(atomic_xchg(count, 0) != 1)) - return fail_fn(count); + if (likely(atomic_xchg(count, -1) != 1)) + return fail_fn(count); return 0; } From 5e5891d1fe77e50428913ab69ff8cc8c5695a560 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 21 Aug 2012 16:16:10 -0700 Subject: [PATCH 0959/2357] drivers/rtc/rtc-rs5c348.c: fix hour decoding in 12-hour mode commit 7dbfb315b2aaef0a115765946bf3026d074c33a7 upstream. Correct the offset by subtracting 20 from tm_hour before taking the modulo 12. [ "Why 20?" I hear you ask. Or at least I did. Here's the reason why: RS5C348_BIT_PM is 32, and is - stupidly - included in the RS5C348_HOURS_MASK define. So it's really subtracting out that bit to get "hour+12". But then because it does things modulo 12, it needs to add the 12 in again afterwards anyway. This code is confused. It would be much clearer if RS5C348_HOURS_MASK just didn't include the RS5C348_BIT_PM bit at all, then it wouldn't need to do the silly subtract either. Whatever. It's all just math, the end result is the same. - Linus ] Reported-by: James Nute Tested-by: James Nute Signed-off-by: Atsushi Nemoto Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-rs5c348.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index 77074ccd285..fd5c7af04ae 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c @@ -122,9 +122,12 @@ rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_min = bcd2bin(rxbuf[RS5C348_REG_MINS] & RS5C348_MINS_MASK); tm->tm_hour = bcd2bin(rxbuf[RS5C348_REG_HOURS] & RS5C348_HOURS_MASK); if (!pdata->rtc_24h) { - tm->tm_hour %= 12; - if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM) + if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM) { + tm->tm_hour -= 20; + tm->tm_hour %= 12; tm->tm_hour += 12; + } else + tm->tm_hour %= 12; } tm->tm_wday = bcd2bin(rxbuf[RS5C348_REG_WDAY] & RS5C348_WDAY_MASK); tm->tm_mday = bcd2bin(rxbuf[RS5C348_REG_DAY] & RS5C348_DAY_MASK); From a0bfb9191135a16c84df7ba580ea839aefff4a0f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 15 Aug 2012 21:31:45 +0200 Subject: [PATCH 0960/2357] PM / Runtime: Fix rpm_resume() return value for power.no_callbacks set commit 7f321c26c04807834fef4c524d2b21573423fc74 upstream. For devices whose power.no_callbacks flag is set, rpm_resume() should return 1 if the device's parent is already active, so that the callers of pm_runtime_get() don't think that they have to wait for the device to resume (asynchronously) in that case (the core won't queue up an asynchronous resume in that case, so there's nothing to wait for anyway). Modify the code accordingly (and make sure that an idle notification will be queued up on success, even if 1 is to be returned). Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/runtime.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index bd0f3949bcf..7f4567c45fa 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -652,6 +652,7 @@ static int rpm_resume(struct device *dev, int rpmflags) || dev->parent->power.runtime_status == RPM_ACTIVE) { atomic_inc(&dev->parent->power.child_count); spin_unlock(&dev->parent->power.lock); + retval = 1; goto no_callback; /* Assume success. */ } spin_unlock(&dev->parent->power.lock); @@ -735,7 +736,7 @@ static int rpm_resume(struct device *dev, int rpmflags) } wake_up_all(&dev->power.wait_queue); - if (!retval) + if (retval >= 0) rpm_idle(dev, RPM_ASYNC); out: From 7f2e6defbe27240e9d51e4eee2f2568d31956b79 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 15 Aug 2012 21:31:55 +0200 Subject: [PATCH 0961/2357] PM / Runtime: Clear power.deferred_resume on success in rpm_suspend() commit 58a34de7b1a920d287d17d2ca08bc9aaf7e6d35b upstream. The power.deferred_resume can only be set if the runtime PM status of device is RPM_SUSPENDING and it should be cleared after its status has been changed, regardless of whether or not the runtime suspend has been successful. However, it only is cleared on suspend failure, while it may remain set on successful suspend and is happily leaked to rpm_resume() executed in that case. That shouldn't happen, so if power.deferred_resume is set in rpm_suspend() after the status has been changed to RPM_SUSPENDED, clear it before calling rpm_resume(). Then, it doesn't need to be cleared before changing the status to RPM_SUSPENDING any more, because it's always cleared after the status has been changed to either RPM_SUSPENDED (on success) or RPM_ACTIVE (on failure). Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 7f4567c45fa..bb82b1817ae 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -430,7 +430,6 @@ static int rpm_suspend(struct device *dev, int rpmflags) goto repeat; } - dev->power.deferred_resume = false; if (dev->power.no_callbacks) goto no_callback; /* Assume success. */ @@ -506,6 +505,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) wake_up_all(&dev->power.wait_queue); if (dev->power.deferred_resume) { + dev->power.deferred_resume = false; rpm_resume(dev, 0); retval = -EAGAIN; goto out; From 95c1d943a1e7515643dcd8466ba82c3566f778b6 Mon Sep 17 00:00:00 2001 From: Robin Holt Date: Tue, 21 Aug 2012 16:16:02 -0700 Subject: [PATCH 0962/2357] drivers/misc/sgi-xp/xpc_uv.c: SGI XPC fails to load when cpu 0 is out of IRQ resources commit 7838f994b4fceff24c343f4e26a6cf4393869579 upstream. On many of our larger systems, CPU 0 has had all of its IRQ resources consumed before XPC loads. Worst cases on machines with multiple 10 GigE cards and multiple IB cards have depleted the entire first socket of IRQs. This patch makes selecting the node upon which IRQs are allocated (as well as all the other GRU Message Queue structures) specifiable as a module load param and has a default behavior of searching all nodes/cpus for an available resources. [akpm@linux-foundation.org: fix build: include cpu.h and module.h] Signed-off-by: Robin Holt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-xp/xpc_uv.c | 84 ++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 19 deletions(-) diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 17bbacb1b4b..cc2ae7ec0d2 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -59,6 +61,8 @@ static struct xpc_heartbeat_uv *xpc_heartbeat_uv; XPC_NOTIFY_MSG_SIZE_UV) #define XPC_NOTIFY_IRQ_NAME "xpc_notify" +static int xpc_mq_node = -1; + static struct xpc_gru_mq_uv *xpc_activate_mq_uv; static struct xpc_gru_mq_uv *xpc_notify_mq_uv; @@ -109,11 +113,8 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name) #if defined CONFIG_X86_64 mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset, UV_AFFINITY_CPU); - if (mq->irq < 0) { - dev_err(xpc_part, "uv_setup_irq() returned error=%d\n", - -mq->irq); + if (mq->irq < 0) return mq->irq; - } mq->mmr_value = uv_read_global_mmr64(mmr_pnode, mq->mmr_offset); @@ -238,8 +239,9 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, mq->mmr_blade = uv_cpu_to_blade_id(cpu); nid = cpu_to_node(cpu); - page = alloc_pages_exact_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, - pg_order); + page = alloc_pages_exact_node(nid, + GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, + pg_order); if (page == NULL) { dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d " "bytes of memory on nid=%d for GRU mq\n", mq_size, nid); @@ -1731,9 +1733,50 @@ static struct xpc_arch_operations xpc_arch_ops_uv = { .notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_uv, }; +static int +xpc_init_mq_node(int nid) +{ + int cpu; + + get_online_cpus(); + + for_each_cpu(cpu, cpumask_of_node(nid)) { + xpc_activate_mq_uv = + xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, nid, + XPC_ACTIVATE_IRQ_NAME, + xpc_handle_activate_IRQ_uv); + if (!IS_ERR(xpc_activate_mq_uv)) + break; + } + if (IS_ERR(xpc_activate_mq_uv)) { + put_online_cpus(); + return PTR_ERR(xpc_activate_mq_uv); + } + + for_each_cpu(cpu, cpumask_of_node(nid)) { + xpc_notify_mq_uv = + xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, nid, + XPC_NOTIFY_IRQ_NAME, + xpc_handle_notify_IRQ_uv); + if (!IS_ERR(xpc_notify_mq_uv)) + break; + } + if (IS_ERR(xpc_notify_mq_uv)) { + xpc_destroy_gru_mq_uv(xpc_activate_mq_uv); + put_online_cpus(); + return PTR_ERR(xpc_notify_mq_uv); + } + + put_online_cpus(); + return 0; +} + int xpc_init_uv(void) { + int nid; + int ret = 0; + xpc_arch_ops = xpc_arch_ops_uv; if (sizeof(struct xpc_notify_mq_msghdr_uv) > XPC_MSG_HDR_MAX_SIZE) { @@ -1742,21 +1785,21 @@ xpc_init_uv(void) return -E2BIG; } - xpc_activate_mq_uv = xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, 0, - XPC_ACTIVATE_IRQ_NAME, - xpc_handle_activate_IRQ_uv); - if (IS_ERR(xpc_activate_mq_uv)) - return PTR_ERR(xpc_activate_mq_uv); + if (xpc_mq_node < 0) + for_each_online_node(nid) { + ret = xpc_init_mq_node(nid); - xpc_notify_mq_uv = xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, 0, - XPC_NOTIFY_IRQ_NAME, - xpc_handle_notify_IRQ_uv); - if (IS_ERR(xpc_notify_mq_uv)) { - xpc_destroy_gru_mq_uv(xpc_activate_mq_uv); - return PTR_ERR(xpc_notify_mq_uv); - } + if (!ret) + break; + } + else + ret = xpc_init_mq_node(xpc_mq_node); - return 0; + if (ret < 0) + dev_err(xpc_part, "xpc_init_mq_node() returned error=%d\n", + -ret); + + return ret; } void @@ -1765,3 +1808,6 @@ xpc_exit_uv(void) xpc_destroy_gru_mq_uv(xpc_notify_mq_uv); xpc_destroy_gru_mq_uv(xpc_activate_mq_uv); } + +module_param(xpc_mq_node, int, 0); +MODULE_PARM_DESC(xpc_mq_node, "Node number on which to allocate message queues."); From 13e902acc58ef41e6516f160bd55976891d3b9cb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 21 Aug 2012 16:29:47 +1000 Subject: [PATCH 0963/2357] fbcon: fix race condition between console lock and cursor timer (v1.1) commit d8636a2717bb3da2a7ce2154bf08de90bb8c87b0 upstream. So we've had a fair few reports of fbcon handover breakage between efi/vesafb and i915 surface recently, so I dedicated a couple of days to finding the problem. Essentially the last thing we saw was the conflicting framebuffer message and that was all. So after much tracing with direct netconsole writes (printks under console_lock not so useful), I think I found the race. Thread A (driver load) Thread B (timer thread) unbind_con_driver -> | bind_con_driver -> | vc->vc_sw->con_deinit -> | fbcon_deinit -> | console_lock() | | | | fbcon_flashcursor timer fires | console_lock() <- blocked for A | | fbcon_del_cursor_timer -> del_timer_sync (BOOM) Of course because all of this is under the console lock, we never see anything, also since we also just unbound the active console guess what we never see anything. Hopefully this fixes the problem for anyone seeing vesafb->kms driver handoff. v1.1: add comment suggestion from Alan. Signed-off-by: Dave Airlie Acked-by: Alan Cox Tested-by: Josh Boyer Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/fbcon.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 2e471c22abf..88e92041d8f 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -372,8 +372,15 @@ static void fb_flashcursor(struct work_struct *work) struct vc_data *vc = NULL; int c; int mode; + int ret; + + /* FIXME: we should sort out the unbind locking instead */ + /* instead we just fail to flash the cursor if we can't get + * the lock instead of blocking fbcon deinit */ + ret = console_trylock(); + if (ret == 0) + return; - console_lock(); if (ops && ops->currcon != -1) vc = vc_cons[ops->currcon].d; From 8ff63613670a03eaa3524f4a55742c17ed105bc5 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 17 Aug 2012 14:40:04 -0400 Subject: [PATCH 0964/2357] drm/radeon: avoid turning off spread spectrum for used pll commit 5efcc76c13a745f98e7b6604d6aca49761be1970 upstream. If spread spectrum is enabled and in use for a given pll we should not turn it off as it will lead to turning off display for crtc that use the pll (this behavior was observed on chelsea edp). Signed-off-by: Jerome Glisse Reviewed-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_crtc.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index a53ca30d05e..064742cf113 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -444,11 +444,28 @@ union atom_enable_ss { static void atombios_crtc_program_ss(struct radeon_device *rdev, int enable, int pll_id, + int crtc_id, struct radeon_atom_ss *ss) { + unsigned i; int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); union atom_enable_ss args; + if (!enable) { + for (i = 0; i < 6; i++) { + if (rdev->mode_info.crtcs[i] && + rdev->mode_info.crtcs[i]->enabled && + i != crtc_id && + pll_id == rdev->mode_info.crtcs[i]->pll_id) { + /* one other crtc is using this pll don't turn + * off spread spectrum as it might turn off + * display on active crtc + */ + return; + } + } + } + memset(&args, 0, sizeof(args)); if (ASIC_IS_DCE5(rdev)) { @@ -1039,7 +1056,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, &ref_div, &post_div); - atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, &ss); + atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, radeon_crtc->crtc_id, &ss); atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, encoder_mode, radeon_encoder->encoder_id, mode->clock, @@ -1062,7 +1079,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode ss.step = step_size; } - atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, &ss); + atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, radeon_crtc->crtc_id, &ss); } } @@ -1571,11 +1588,11 @@ void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev) ASIC_INTERNAL_SS_ON_DCPLL, rdev->clock.default_dispclk); if (ss_enabled) - atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, &ss); + atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss); /* XXX: DCE5, make sure voltage, dispclk is high enough */ atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); if (ss_enabled) - atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, &ss); + atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss); } } From 53c6c871480eb31207906a2c7e7e3a859339a8a3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 21 Aug 2012 18:52:56 -0400 Subject: [PATCH 0965/2357] drm/radeon/ss: use num_crtc rather than hardcoded 6 commit 5317670692f61675394db2eb6713484b67383750 upstream. When checking if a pll is in use. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 064742cf113..d86f948b388 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -452,7 +452,7 @@ static void atombios_crtc_program_ss(struct radeon_device *rdev, union atom_enable_ss args; if (!enable) { - for (i = 0; i < 6; i++) { + for (i = 0; i < rdev->num_crtc; i++) { if (rdev->mode_info.crtcs[i] && rdev->mode_info.crtcs[i]->enabled && i != crtc_id && From 0a1d9a860832a5ca43114cdebf0e8650463cc1f0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 16 Aug 2012 15:39:09 -0400 Subject: [PATCH 0966/2357] drm/radeon: split ATRM support out from the ATPX handler (v3) commit c61e2775873f603148e8e998a938721b7d222d24 upstream. There are systems that use ATRM, but not ATPX. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=41265 V2: fix #ifdefs as per Greg's comments V3: fix it harder Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon.h | 15 ---- drivers/gpu/drm/radeon/radeon_atpx_handler.c | 56 +------------- drivers/gpu/drm/radeon/radeon_bios.c | 80 +++++++++++++++++++- 3 files changed, 77 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 138b95216d8..66150f0ffc7 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -138,21 +138,6 @@ struct radeon_device; /* * BIOS. */ -#define ATRM_BIOS_PAGE 4096 - -#if defined(CONFIG_VGA_SWITCHEROO) -bool radeon_atrm_supported(struct pci_dev *pdev); -int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len); -#else -static inline bool radeon_atrm_supported(struct pci_dev *pdev) -{ - return false; -} - -static inline int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len){ - return -EINVAL; -} -#endif bool radeon_get_bios(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 98724fcb008..2a2cf0b88a2 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -30,57 +30,8 @@ static struct radeon_atpx_priv { /* handle for device - and atpx */ acpi_handle dhandle; acpi_handle atpx_handle; - acpi_handle atrm_handle; } radeon_atpx_priv; -/* retrieve the ROM in 4k blocks */ -static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios, - int offset, int len) -{ - acpi_status status; - union acpi_object atrm_arg_elements[2], *obj; - struct acpi_object_list atrm_arg; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; - - atrm_arg.count = 2; - atrm_arg.pointer = &atrm_arg_elements[0]; - - atrm_arg_elements[0].type = ACPI_TYPE_INTEGER; - atrm_arg_elements[0].integer.value = offset; - - atrm_arg_elements[1].type = ACPI_TYPE_INTEGER; - atrm_arg_elements[1].integer.value = len; - - status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer); - if (ACPI_FAILURE(status)) { - printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status)); - return -ENODEV; - } - - obj = (union acpi_object *)buffer.pointer; - memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length); - len = obj->buffer.length; - kfree(buffer.pointer); - return len; -} - -bool radeon_atrm_supported(struct pci_dev *pdev) -{ - /* get the discrete ROM only via ATRM */ - if (!radeon_atpx_priv.atpx_detected) - return false; - - if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) - return false; - return true; -} - - -int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len) -{ - return radeon_atrm_call(radeon_atpx_priv.atrm_handle, bios, offset, len); -} - static int radeon_atpx_get_version(acpi_handle handle) { acpi_status status; @@ -198,7 +149,7 @@ static int radeon_atpx_power_state(enum vga_switcheroo_client_id id, static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) { - acpi_handle dhandle, atpx_handle, atrm_handle; + acpi_handle dhandle, atpx_handle; acpi_status status; dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); @@ -209,13 +160,8 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) if (ACPI_FAILURE(status)) return false; - status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); - if (ACPI_FAILURE(status)) - return false; - radeon_atpx_priv.dhandle = dhandle; radeon_atpx_priv.atpx_handle = atpx_handle; - radeon_atpx_priv.atrm_handle = atrm_handle; return true; } diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 501f4881e5a..f9b7f05f541 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -98,16 +98,81 @@ static bool radeon_read_bios(struct radeon_device *rdev) return true; } +#ifdef CONFIG_ACPI /* ATRM is used to get the BIOS on the discrete cards in * dual-gpu systems. */ +/* retrieve the ROM in 4k blocks */ +#define ATRM_BIOS_PAGE 4096 +/** + * radeon_atrm_call - fetch a chunk of the vbios + * + * @atrm_handle: acpi ATRM handle + * @bios: vbios image pointer + * @offset: offset of vbios image data to fetch + * @len: length of vbios image data to fetch + * + * Executes ATRM to fetch a chunk of the discrete + * vbios image on PX systems (all asics). + * Returns the length of the buffer fetched. + */ +static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios, + int offset, int len) +{ + acpi_status status; + union acpi_object atrm_arg_elements[2], *obj; + struct acpi_object_list atrm_arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; + + atrm_arg.count = 2; + atrm_arg.pointer = &atrm_arg_elements[0]; + + atrm_arg_elements[0].type = ACPI_TYPE_INTEGER; + atrm_arg_elements[0].integer.value = offset; + + atrm_arg_elements[1].type = ACPI_TYPE_INTEGER; + atrm_arg_elements[1].integer.value = len; + + status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer); + if (ACPI_FAILURE(status)) { + printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status)); + return -ENODEV; + } + + obj = (union acpi_object *)buffer.pointer; + memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length); + len = obj->buffer.length; + kfree(buffer.pointer); + return len; +} + static bool radeon_atrm_get_bios(struct radeon_device *rdev) { int ret; int size = 256 * 1024; int i; + struct pci_dev *pdev = NULL; + acpi_handle dhandle, atrm_handle; + acpi_status status; + bool found = false; - if (!radeon_atrm_supported(rdev->pdev)) + /* ATRM is for the discrete card only */ + if (rdev->flags & RADEON_IS_IGP) + return false; + + while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { + dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); + if (!dhandle) + continue; + + status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); + if (!ACPI_FAILURE(status)) { + found = true; + break; + } + } + + if (!found) return false; rdev->bios = kmalloc(size, GFP_KERNEL); @@ -117,9 +182,10 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) } for (i = 0; i < size / ATRM_BIOS_PAGE; i++) { - ret = radeon_atrm_get_bios_chunk(rdev->bios, - (i * ATRM_BIOS_PAGE), - ATRM_BIOS_PAGE); + ret = radeon_atrm_call(atrm_handle, + rdev->bios, + (i * ATRM_BIOS_PAGE), + ATRM_BIOS_PAGE); if (ret < ATRM_BIOS_PAGE) break; } @@ -130,6 +196,12 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) } return true; } +#else +static inline bool radeon_atrm_get_bios(struct radeon_device *rdev) +{ + return false; +} +#endif static bool ni_read_disabled_bios(struct radeon_device *rdev) { From 25413e693f697f801e1cc8fd10e90a7821a3a04b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 16 Aug 2012 15:45:20 -0400 Subject: [PATCH 0967/2357] drm/radeon: implement ACPI VFCT vbios fetch (v3) commit 268ba0a99f89a84dc5eb312470896113d0709c74 upstream. This is required for pure UEFI systems. The vbios is stored in ACPI rather than at the legacy vga location. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=26891 V2: fix #ifdefs as per Greg's comments V3: fix it harder Signed-off-by: Alex Deucher Reviewed-by: Jerome Glisse Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_bios.c | 60 ++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index f9b7f05f541..602898dd166 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -32,6 +32,7 @@ #include #include +#include /* * BIOS. */ @@ -548,6 +549,63 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev) return legacy_read_disabled_bios(rdev); } +#ifdef CONFIG_ACPI +static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) +{ + bool ret = false; + struct acpi_table_header *hdr; + /* acpi_get_table_with_size is not exported :( */ + acpi_size tbl_size = 0x7fffffff; + UEFI_ACPI_VFCT *vfct; + GOP_VBIOS_CONTENT *vbios; + VFCT_IMAGE_HEADER *vhdr; + + if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) + return false; + if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { + DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n"); + goto out_unmap; + } + + vfct = (UEFI_ACPI_VFCT *)hdr; + if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) { + DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n"); + goto out_unmap; + } + + vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset); + vhdr = &vbios->VbiosHeader; + DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n", + vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction, + vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength); + + if (vhdr->PCIBus != rdev->pdev->bus->number || + vhdr->PCIDevice != PCI_SLOT(rdev->pdev->devfn) || + vhdr->PCIFunction != PCI_FUNC(rdev->pdev->devfn) || + vhdr->VendorID != rdev->pdev->vendor || + vhdr->DeviceID != rdev->pdev->device) { + DRM_INFO("ACPI VFCT table is not for this card\n"); + goto out_unmap; + }; + + if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) { + DRM_ERROR("ACPI VFCT image truncated\n"); + goto out_unmap; + } + + rdev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL); + ret = !!rdev->bios; + +out_unmap: + /* uh, no idea what to do here... */ + return ret; +} +#else +static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev) +{ + return false; +} +#endif bool radeon_get_bios(struct radeon_device *rdev) { @@ -555,6 +613,8 @@ bool radeon_get_bios(struct radeon_device *rdev) uint16_t tmp; r = radeon_atrm_get_bios(rdev); + if (r == false) + r = radeon_acpi_vfct_bios(rdev); if (r == false) r = igp_read_bios_from_vram(rdev); if (r == false) From 9e4f7198fda9c9d9effccff1a9d56ea2b0b3d4b4 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 20 Aug 2012 15:16:04 +0100 Subject: [PATCH 0968/2357] drm/radeon/kms: extend the Fujitsu D3003-S2 board connector quirk to cover later silicon stepping commit 52e9b39d9a89ae33662596bd30e62dd56bddbe73 upstream. There is a more recent APU stepping with a new PCI ID shipping in the same board by Fujitsu which needs the same quirk to correctly mark the back plane connectors. Signed-off-by: Tvrtko Ursulin Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_atombios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index b1e3820df36..5e30e126bfe 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -452,7 +452,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ - if ((dev->pdev->device == 0x9802) && + if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) && (dev->pdev->subsystem_vendor == 0x1734) && (dev->pdev->subsystem_device == 0x11bd)) { if (*connector_type == DRM_MODE_CONNECTOR_VGA) { From 33822abf1d7190dd8dab1da87661bde5208de6c8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Aug 2012 13:22:34 +0300 Subject: [PATCH 0969/2357] drm/i915: extract connector update from intel_ddc_get_modes() for reuse commit 4eab81366465aedcfd26de960c595bc03599c09f upstream. Refactor the connector update part of intel_ddc_get_modes() into a separate intel_connector_update_modes() function for reuse. No functional changes. Signed-off-by: Jani Nikula Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=45881 Tested-by: Alex Ferrando Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_modes.c | 31 +++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 715afa15302..2cae72d1749 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -288,6 +288,8 @@ struct intel_fbc_work { int interval; }; +int intel_connector_update_modes(struct drm_connector *connector, + struct edid *edid); int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus); diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index d1928e79d9b..9a2b27031a4 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -59,6 +59,25 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus) return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2; } +/** + * intel_connector_update_modes - update connector from edid + * @connector: DRM connector device to use + * @edid: previously read EDID information + */ +int intel_connector_update_modes(struct drm_connector *connector, + struct edid *edid) +{ + int ret; + + drm_mode_connector_update_edid_property(connector, edid); + ret = drm_add_edid_modes(connector, edid); + drm_edid_to_eld(connector, edid); + connector->display_info.raw_edid = NULL; + kfree(edid); + + return ret; +} + /** * intel_ddc_get_modes - get modelist from monitor * @connector: DRM connector device to use @@ -70,18 +89,12 @@ int intel_ddc_get_modes(struct drm_connector *connector, struct i2c_adapter *adapter) { struct edid *edid; - int ret = 0; edid = drm_get_edid(connector, adapter); - if (edid) { - drm_mode_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - drm_edid_to_eld(connector, edid); - connector->display_info.raw_edid = NULL; - kfree(edid); - } + if (!edid) + return 0; - return ret; + return intel_connector_update_modes(connector, edid); } static const struct drm_prop_enum_list force_audio_names[] = { From 91a1da919e60a62ed3dfb10296e8eed4eb2b03bd Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 20 Aug 2012 23:01:51 +0200 Subject: [PATCH 0970/2357] asus-laptop: HRWS/HWRS typo commit 8871e99f89b7d7b1ea99de550eea2a56273f42ab upstream. Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=24222 Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/asus-laptop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index e38f91be0b1..110c7778cbf 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -863,9 +863,9 @@ static ssize_t show_infos(struct device *dev, * The significance of others is yet to be found. * If we don't find the method, we assume the device are present. */ - rv = acpi_evaluate_integer(asus->handle, "HRWS", NULL, &temp); + rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp); if (!ACPI_FAILURE(rv)) - len += sprintf(page + len, "HRWS value : %#x\n", + len += sprintf(page + len, "HWRS value : %#x\n", (uint) temp); /* * Another value for userspace: the ASYM method returns 0x02 for @@ -1751,9 +1751,9 @@ static int asus_laptop_get_info(struct asus_laptop *asus) * The significance of others is yet to be found. */ status = - acpi_evaluate_integer(asus->handle, "HRWS", NULL, &hwrs_result); + acpi_evaluate_integer(asus->handle, "HWRS", NULL, &hwrs_result); if (!ACPI_FAILURE(status)) - pr_notice(" HRWS returned %x", (int)hwrs_result); + pr_notice(" HWRS returned %x", (int)hwrs_result); if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) asus->have_rsts = true; From 4368ade3ff2bfff1033f9e5758630b3d4e8f7e71 Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Wed, 4 Jul 2012 15:20:14 +0800 Subject: [PATCH 0971/2357] asus-nb-wmi: add some video toggle keys commit 3766054fff4af1b58a1440a284907887f4d2e8be upstream. There are some new video switch keys that used by newer machines. 0xA0 - SDSP HDMI only 0xA1 - SDSP LCD + HDMI 0xA2 - SDSP CRT + HDMI 0xA3 - SDSP TV + HDMI But in Linux, there is no suitable userspace application to handle this, so, mapping them all to KEY_SWITCHVIDEOMODE. Signed-off-by: AceLan Kao Signed-off-by: Matthew Garrett Cc: Tim Gardner Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/asus-nb-wmi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 99a30b51313..6de14fd090a 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -94,6 +94,10 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x8A, { KEY_PROG1 } }, { KE_KEY, 0x95, { KEY_MEDIA } }, { KE_KEY, 0x99, { KEY_PHONE } }, + { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */ + { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */ + { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */ + { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */ { KE_KEY, 0xb5, { KEY_CALC } }, { KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, From 2607b9407db4cbc16d5a130c8c16702711c3b7be Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 16 Aug 2012 08:29:03 +0000 Subject: [PATCH 0972/2357] drm: Check for invalid cursor flags commit 7c4eaca4162d0b5ad4fb39f974d7ffd71b9daa09 upstream. Signed-off-by: Jakob Bornecrantz Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_crtc.c | 2 +- include/drm/drm_mode.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index c79870a75c2..7e479a42af0 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1981,7 +1981,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - if (!req->flags) + if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) return -EINVAL; mutex_lock(&dev->mode_config.mutex); diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index 4a0aae38e16..9242310b47c 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -343,8 +343,9 @@ struct drm_mode_mode_cmd { struct drm_mode_modeinfo mode; }; -#define DRM_MODE_CURSOR_BO (1<<0) -#define DRM_MODE_CURSOR_MOVE (1<<1) +#define DRM_MODE_CURSOR_BO 0x01 +#define DRM_MODE_CURSOR_MOVE 0x02 +#define DRM_MODE_CURSOR_FLAGS 0x03 /* * depending on the value in flags different members are used. From d468e2150f5f52ea7b0c459366028f28cc1cf96b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 22 Aug 2012 09:54:56 -0400 Subject: [PATCH 0973/2357] drm/radeon/atom: rework DIG modesetting on DCE3+ commit 8d1af57ae3c4458ed0de93ef97f388dd1b3239c7 upstream. The ordering is important and the current drm code wasn't cutting it for modern DIG encoders. We need to have information about crtc before setting up the encoders so I've shifted the ordering a bit. Probably we'll need a full rework akin to danvet's recent intel patchs. This patch fixes numerous issues with DP bridge chips and makes link training much more reliable. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_encoders.c | 109 +++++++++------------ 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index a3ae788a2af..39b36252ca3 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1379,6 +1379,8 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); struct radeon_connector *radeon_connector = NULL; struct radeon_connector_atom_dig *radeon_dig_connector = NULL; @@ -1390,19 +1392,37 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) switch (mode) { case DRM_MODE_DPMS_ON: - /* some early dce3.2 boards have a bug in their transmitter control table */ - if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730) || - ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { - if (ASIC_IS_DCE6(rdev)) { - /* It seems we need to call ATOM_ENCODER_CMD_SETUP again - * before reenabling encoder on DPMS ON, otherwise we never - * get picture - */ - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); + if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { + if (!connector) + dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; + else + dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector); + + /* setup and enable the encoder */ + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); + atombios_dig_encoder_setup(encoder, + ATOM_ENCODER_CMD_SETUP_PANEL_MODE, + dig->panel_mode); + if (ext_encoder) { + if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); } atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } else { + } else if (ASIC_IS_DCE4(rdev)) { + /* setup and enable the encoder */ + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); + /* enable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); + } else { + /* setup and enable the encoder and transmitter */ + atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + /* some early dce3.2 boards have a bug in their transmitter control table */ + if ((rdev->family != CHIP_RV710) || (rdev->family != CHIP_RV730)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); } if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { @@ -1420,10 +1440,19 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) + if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { + /* disable the transmitter */ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - else + } else if (ASIC_IS_DCE4(rdev)) { + /* disable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + } else { + /* disable the encoder and transmitter */ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); + } if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); @@ -1848,10 +1877,12 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); radeon_encoder->pixel_clock = adjusted_mode->clock; + /* need to call this here rather than in prepare() since we need some crtc info */ + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) { if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) atombios_yuv_setup(encoder, true); @@ -1870,38 +1901,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - - if (!connector) - dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; - else - dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector); - - /* setup and enable the encoder */ - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); - atombios_dig_encoder_setup(encoder, - ATOM_ENCODER_CMD_SETUP_PANEL_MODE, - dig->panel_mode); - } else if (ASIC_IS_DCE4(rdev)) { - /* disable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - /* setup and enable the encoder */ - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); - - /* enable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } else { - /* disable the encoder and transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); - - /* setup and enable the encoder and transmitter */ - atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } + /* handled in dpms */ break; case ENCODER_OBJECT_ID_INTERNAL_DDI: case ENCODER_OBJECT_ID_INTERNAL_DVO1: @@ -1922,14 +1922,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, break; } - if (ext_encoder) { - if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); - else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); - } - atombios_apply_encoder_quirks(encoder, adjusted_mode); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { @@ -2102,7 +2094,6 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) } radeon_atom_output_lock(encoder, true); - radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); if (connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -2123,6 +2114,7 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) static void radeon_atom_encoder_commit(struct drm_encoder *encoder) { + /* need to call this here as we need the crtc set up */ radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); radeon_atom_output_lock(encoder, false); } @@ -2163,14 +2155,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - if (ASIC_IS_DCE4(rdev)) - /* disable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - else { - /* disable the encoder and transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); - } + /* handled in dpms */ break; case ENCODER_OBJECT_ID_INTERNAL_DDI: case ENCODER_OBJECT_ID_INTERNAL_DVO1: From 853a847c89384d47afcad59beeecb535fe733402 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 24 Aug 2012 18:21:21 -0400 Subject: [PATCH 0974/2357] drm/radeon/atom: powergating fixes for DCE6 commit c205b232a64fed6d26edd7e40985b396de99a27f upstream. Power gating is per crtc pair, but the powergating registers should be called individually. The hw handles power up/down properly. The pair is powered up if either crtc in the pair is powered up and the pair is not powered down until both crtcs in the pair are powered down. This simplifies programming and should save additional power as the previous code never actually power gated the crtc pair. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_crtc.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index d86f948b388..71bd61c33b7 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -258,7 +258,6 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) radeon_crtc->enabled = true; /* adjust pm to dpms changes BEFORE enabling crtcs */ radeon_pm_compute_clocks(rdev); - /* disable crtc pair power gating before programming */ if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) atombios_powergate_crtc(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_ENABLE); @@ -278,25 +277,8 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); radeon_crtc->enabled = false; - /* power gating is per-pair */ - if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) { - struct drm_crtc *other_crtc; - struct radeon_crtc *other_radeon_crtc; - list_for_each_entry(other_crtc, &rdev->ddev->mode_config.crtc_list, head) { - other_radeon_crtc = to_radeon_crtc(other_crtc); - if (((radeon_crtc->crtc_id == 0) && (other_radeon_crtc->crtc_id == 1)) || - ((radeon_crtc->crtc_id == 1) && (other_radeon_crtc->crtc_id == 0)) || - ((radeon_crtc->crtc_id == 2) && (other_radeon_crtc->crtc_id == 3)) || - ((radeon_crtc->crtc_id == 3) && (other_radeon_crtc->crtc_id == 2)) || - ((radeon_crtc->crtc_id == 4) && (other_radeon_crtc->crtc_id == 5)) || - ((radeon_crtc->crtc_id == 5) && (other_radeon_crtc->crtc_id == 4))) { - /* if both crtcs in the pair are off, enable power gating */ - if (other_radeon_crtc->enabled == false) - atombios_powergate_crtc(crtc, ATOM_ENABLE); - break; - } - } - } + if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) + atombios_powergate_crtc(crtc, ATOM_ENABLE); /* adjust pm to dpms changes AFTER disabling crtcs */ radeon_pm_compute_clocks(rdev); break; From 6992255930809bc988366e7177126dab74e7df95 Mon Sep 17 00:00:00 2001 From: "Xu, Anhua" Date: Mon, 13 Aug 2012 03:08:33 +0000 Subject: [PATCH 0975/2357] drm/i915: fix wrong order of parameters in port checking functions commit b70ad586162609141f0aa9eb34790f31a8954f89 upstream. Wrong order of parameters passed-in when calling hdmi/adpa /lvds_pipe_enabled(), 2nd and 3rd parameters are reversed. This bug was indroduced by commit 1519b9956eb4b4180fa3f47c73341463cdcfaa37 Author: Keith Packard Date: Sat Aug 6 10:35:34 2011 -0700 drm/i915: Fix PCH port pipe select in CPT disable paths The reachable tag for this commit is v3.1-rc1-3-g1519b99 Signed-off-by: Anhua Xu Reviewed-by: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44876 Tested-by: Daniel Schroeder Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3de3d9b670b..498bcbeb992 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1099,7 +1099,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = I915_READ(reg); - WARN(hdmi_pipe_enabled(dev_priv, val, pipe), + WARN(hdmi_pipe_enabled(dev_priv, pipe, val), "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); } @@ -1116,13 +1116,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, reg = PCH_ADPA; val = I915_READ(reg); - WARN(adpa_pipe_enabled(dev_priv, val, pipe), + WARN(adpa_pipe_enabled(dev_priv, pipe, val), "PCH VGA enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); reg = PCH_LVDS; val = I915_READ(reg); - WARN(lvds_pipe_enabled(dev_priv, val, pipe), + WARN(lvds_pipe_enabled(dev_priv, pipe, val), "PCH LVDS enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); @@ -1487,7 +1487,7 @@ static void disable_pch_hdmi(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = I915_READ(reg); - if (hdmi_pipe_enabled(dev_priv, val, pipe)) { + if (hdmi_pipe_enabled(dev_priv, pipe, val)) { DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n", reg, pipe); I915_WRITE(reg, val & ~PORT_ENABLE); @@ -1509,12 +1509,12 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, reg = PCH_ADPA; val = I915_READ(reg); - if (adpa_pipe_enabled(dev_priv, val, pipe)) + if (adpa_pipe_enabled(dev_priv, pipe, val)) I915_WRITE(reg, val & ~ADPA_DAC_ENABLE); reg = PCH_LVDS; val = I915_READ(reg); - if (lvds_pipe_enabled(dev_priv, val, pipe)) { + if (lvds_pipe_enabled(dev_priv, pipe, val)) { DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val); I915_WRITE(reg, val & ~LVDS_PORT_EN); POSTING_READ(reg); From ea708eb2c1843004a41d0beeac724451202513ff Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 20 Aug 2012 11:06:21 -0400 Subject: [PATCH 0976/2357] drm/radeon: convert radeon vfct code to use acpi_get_table_with_size commit 7c3906d04a4587dceaa78cc1ae6b14e6454ee02a upstream. Allows us to verify the table size. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_bios.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 602898dd166..d306cc8fdea 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -554,13 +554,12 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) { bool ret = false; struct acpi_table_header *hdr; - /* acpi_get_table_with_size is not exported :( */ - acpi_size tbl_size = 0x7fffffff; + acpi_size tbl_size; UEFI_ACPI_VFCT *vfct; GOP_VBIOS_CONTENT *vbios; VFCT_IMAGE_HEADER *vhdr; - if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) + if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size))) return false; if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n"); @@ -597,7 +596,6 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) ret = !!rdev->bios; out_unmap: - /* uh, no idea what to do here... */ return ret; } #else From 5f566f0b27ebddb41b5bd42484047ae96d645704 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 21 Aug 2012 19:06:21 -0400 Subject: [PATCH 0977/2357] drm/radeon: don't disable plls that are in use by other crtcs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4e58591c8961b3e31709313f75819f2eec06e322 upstream. Some plls are shared for DP. Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_crtc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 71bd61c33b7..19f4082c618 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1663,9 +1663,22 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_atom_ss ss; + int i; atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + for (i = 0; i < rdev->num_crtc; i++) { + if (rdev->mode_info.crtcs[i] && + rdev->mode_info.crtcs[i]->enabled && + i != radeon_crtc->crtc_id && + radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) { + /* one other crtc is using this pll don't turn + * off the pll + */ + goto done; + } + } + switch (radeon_crtc->pll_id) { case ATOM_PPLL1: case ATOM_PPLL2: @@ -1682,6 +1695,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) default: break; } +done: radeon_crtc->pll_id = -1; } From d6ce9c9ced227fde03cd1377f190c2cd469e09e0 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 28 Aug 2012 16:50:22 -0400 Subject: [PATCH 0978/2357] drm/radeon: force dma32 to fix regression rs4xx,rs6xx,rs740 commit 4a2b6662c3632176b4fdf012243dd3751367bf1f upstream. It seems some of those IGP dislike non dma32 page despite what documentation says. Fix regression since we allowed non dma32 pages. It seems it only affect some revision of those IGP chips as we don't know which one just force dma32 for all of them. https://bugzilla.redhat.com/show_bug.cgi?id=785375 Signed-off-by: Jerome Glisse Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 5992502a344..de5e0b51dc6 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -772,7 +772,7 @@ int radeon_device_init(struct radeon_device *rdev, if (rdev->flags & RADEON_IS_AGP) rdev->need_dma32 = true; if ((rdev->flags & RADEON_IS_PCI) && - (rdev->family < CHIP_RS400)) + (rdev->family <= CHIP_RS740)) rdev->need_dma32 = true; dma_bits = rdev->need_dma32 ? 32 : 40; From fcb836f584992f104bcbae16829760e3db876491 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 29 Aug 2012 19:48:26 -0400 Subject: [PATCH 0979/2357] drm/radeon: fix dig encoder selection on DCE61 commit 41fa54377057ab38bc3e08ebb46168a7daf2e63b upstream. Was using the DCE41 code which was wrong. Fixes blank displays on a number of Trinity systems. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_encoders.c | 31 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 39b36252ca3..2d07fbf2c27 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1769,13 +1769,34 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_encoder *test_encoder; - struct radeon_encoder_atom_dig *dig; + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; uint32_t dig_enc_in_use = 0; - /* DCE4/5 */ - if (ASIC_IS_DCE4(rdev)) { - dig = radeon_encoder->enc_priv; - if (ASIC_IS_DCE41(rdev)) { + if (ASIC_IS_DCE6(rdev)) { + /* DCE6 */ + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + if (dig->linkb) + return 1; + else + return 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + if (dig->linkb) + return 3; + else + return 2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (dig->linkb) + return 5; + else + return 4; + break; + } + } else if (ASIC_IS_DCE4(rdev)) { + /* DCE4/5 */ + if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) { /* ontario follows DCE4 */ if (rdev->family == CHIP_PALM) { if (dig->linkb) From 4b4ceb8aca588b3ea3e385a31cef9b92f18021af Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 14 Sep 2012 13:28:23 +1000 Subject: [PATCH 0980/2357] drm/nouveau: fix booting with plymouth + dumb support commit 610bd7da160f76f1644ecb4cd7f39511b49a22cc upstream. We noticed a plymouth bug on Fedora 18, and I then noticed this stupid thinko, fixing it fixed the problem with plymouth. Acked-by: Ben Skeggs Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index a85e112863d..f233b8fe2da 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -586,7 +586,7 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, args->size = args->pitch * args->height; args->size = roundup(args->size, PAGE_SIZE); - ret = nouveau_gem_new(dev, args->size, 0, TTM_PL_FLAG_VRAM, 0, 0, &bo); + ret = nouveau_gem_new(dev, args->size, 0, NOUVEAU_GEM_DOMAIN_VRAM, 0, 0, &bo); if (ret) return ret; From 1f7edfcc0a87e5daf273981135e376ed61d284e4 Mon Sep 17 00:00:00 2001 From: Wang Xingchao Date: Thu, 13 Sep 2012 07:43:22 +0800 Subject: [PATCH 0981/2357] drm/i915: HDMI - Clear Audio Enable bit for Hot Plug commit b98b60167279df3acac9422c3c9820d9ebbcf9fb upstream. Clear Audio Enable bit to trigger unsolicated event to notify Audio Driver part the HDMI hot plug change. The patch fixed the bug when remove HDMI cable the bit was not cleared correctly. In intel_hdmi_dpms(), if intel_hdmi->has_audio been true, the "Audio enable bit" will be set to trigger unsolicated event to notify Alsa driver the change. intel_hdmi->has_audio will be reset to false from intel_hdmi_detect() after remove the hdmi cable, here's debug log: [ 187.494153] [drm:output_poll_execute], [CONNECTOR:17:HDMI-A-1] status updated from 1 to 2 [ 187.525349] [drm:intel_hdmi_detect], HDMI: has_audio = 0 so when comes back to intel_hdmi_dpms(), the "Audio enable bit" will not be cleared. And this cause the eld infomation and pin presence doesnot update accordingly in alsa driver side. This patch will also trigger unsolicated event to alsa driver to notify the hot plug event: [ 187.853159] ALSA sound/pci/hda/patch_hdmi.c:772 HDMI hot plug event: Codec=3 Pin=5 Presence_Detect=0 ELD_Valid=1 [ 187.853268] ALSA sound/pci/hda/patch_hdmi.c:990 HDMI status: Codec=3 Pin=5 Presence_Detect=0 ELD_Valid=0 Signed-off-by: Wang Xingchao Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 2d7f47b56b6..fb44e9d116e 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -271,7 +271,7 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) u32 temp; u32 enable_bits = SDVO_ENABLE; - if (intel_hdmi->has_audio) + if (intel_hdmi->has_audio || mode != DRM_MODE_DPMS_ON) enable_bits |= SDVO_AUDIO_ENABLE; temp = I915_READ(intel_hdmi->sdvox_reg); From 956b165f9e89e37aff44d615321d1e3166589701 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 18 Aug 2012 09:51:42 +1000 Subject: [PATCH 0982/2357] md/raid10: fix problem with on-stack allocation of r10bio structure. commit e0ee778528bbaad28a5c69d2e219269a3a096607 upstream. A 'struct r10bio' has an array of per-copy information at the end. This array is declared with size [0] and r10bio_pool_alloc allocates enough extra space to store the per-copy information depending on the number of copies needed. So declaring a 'struct r10bio on the stack isn't going to work. It won't allocate enough space, and memory corruption will ensue. So in the two places where this is done, declare a sufficiently large structure and use that instead. The two call-sites of this bug were introduced in 3.4 and 3.5 so this is suitable for both those kernels. The patch will have to be modified for 3.4 as it only has one bug. Reported-by: Ivan Vasilyev Tested-by: Ivan Vasilyev Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 16 ++++++++++------ drivers/md/raid10.h | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a954c95d7c9..1f7e8cd44e5 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -612,20 +612,24 @@ static int raid10_mergeable_bvec(struct request_queue *q, max = biovec->bv_len; if (mddev->merge_check_needed) { - struct r10bio r10_bio; + struct { + struct r10bio r10_bio; + struct r10dev devs[conf->copies]; + } on_stack; + struct r10bio *r10_bio = &on_stack.r10_bio; int s; - r10_bio.sector = sector; - raid10_find_phys(conf, &r10_bio); + r10_bio->sector = sector; + raid10_find_phys(conf, r10_bio); rcu_read_lock(); for (s = 0; s < conf->copies; s++) { - int disk = r10_bio.devs[s].devnum; + int disk = r10_bio->devs[s].devnum; struct md_rdev *rdev = rcu_dereference( conf->mirrors[disk].rdev); if (rdev && !test_bit(Faulty, &rdev->flags)) { struct request_queue *q = bdev_get_queue(rdev->bdev); if (q->merge_bvec_fn) { - bvm->bi_sector = r10_bio.devs[s].addr + bvm->bi_sector = r10_bio->devs[s].addr + rdev->data_offset; bvm->bi_bdev = rdev->bdev; max = min(max, q->merge_bvec_fn( @@ -637,7 +641,7 @@ static int raid10_mergeable_bvec(struct request_queue *q, struct request_queue *q = bdev_get_queue(rdev->bdev); if (q->merge_bvec_fn) { - bvm->bi_sector = r10_bio.devs[s].addr + bvm->bi_sector = r10_bio->devs[s].addr + rdev->data_offset; bvm->bi_bdev = rdev->bdev; max = min(max, q->merge_bvec_fn( diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index 7c615613c38..24d45b8af5c 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -104,7 +104,7 @@ struct r10bio { * We choose the number when they are allocated. * We sometimes need an extra bio to write to the replacement. */ - struct { + struct r10dev { struct bio *bio; union { struct bio *repl_bio; /* used for resync and From 6adebb0e1d4820435e0c6739b0de20a196cc20d5 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Sun, 2 Sep 2012 00:28:19 +0800 Subject: [PATCH 0983/2357] workqueue: UNBOUND -> REBIND morphing in rebind_workers() should be atomic commit 96e65306b81351b656835c15931d1d237b252f27 upstream. The compiler may compile the following code into TWO write/modify instructions. worker->flags &= ~WORKER_UNBOUND; worker->flags |= WORKER_REBIND; so the other CPU may temporarily see worker->flags which doesn't have either WORKER_UNBOUND or WORKER_REBIND set and perform local wakeup prematurely. Fix it by using single explicit assignment via ACCESS_ONCE(). Because idle workers have another WORKER_NOT_RUNNING flag, this bug doesn't exist for them; however, update it to use the same pattern for consistency. tj: Applied the change to idle workers too and updated comments and patch description a bit. Signed-off-by: Lai Jiangshan Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/workqueue.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index f483dd0bc9c..7584322349c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3433,14 +3433,17 @@ static int __cpuinit trustee_thread(void *__gcwq) for_each_busy_worker(worker, i, pos, gcwq) { struct work_struct *rebind_work = &worker->rebind_work; + unsigned long worker_flags = worker->flags; /* * Rebind_work may race with future cpu hotplug * operations. Use a separate flag to mark that - * rebinding is scheduled. + * rebinding is scheduled. The morphing should + * be atomic. */ - worker->flags |= WORKER_REBIND; - worker->flags &= ~WORKER_ROGUE; + worker_flags |= WORKER_REBIND; + worker_flags &= ~WORKER_ROGUE; + ACCESS_ONCE(worker->flags) = worker_flags; /* queue rebind_work, wq doesn't matter, use the default one */ if (test_and_set_bit(WORK_STRUCT_PENDING_BIT, From 6c9e62877051270d20e34c0c3652e36f1cc37c04 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 15 May 2012 18:44:15 +0100 Subject: [PATCH 0984/2357] x86: Fix boot on Twinhead H12Y commit 80b3e557371205566a71e569fbfcce5b11f92dbe upstream. Despite lots of investigation into why this is needed we don't know or have an elegant cure. The only answer found on this laptop is to mark a problem region as used so that Linux doesn't put anything there. Currently all the users add reserve= command lines and anyone not knowing this needs to find the magic page that documents it. Automate it instead. Signed-off-by: Alan Cox Tested-and-bugfixed-by: Arne Fitzenreiter Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=10231 Link: http://lkml.kernel.org/r/20120515174347.5109.94551.stgit@bluebook Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/fixup.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index d0e6e403b4f..5dd467bd612 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -519,3 +519,20 @@ static void sb600_disable_hpet_bar(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar); + +/* + * Twinhead H12Y needs us to block out a region otherwise we map devices + * there and any access kills the box. + * + * See: https://bugzilla.kernel.org/show_bug.cgi?id=10231 + * + * Match off the LPC and svid/sdid (older kernels lose the bridge subvendor) + */ +static void __devinit twinhead_reserve_killing_zone(struct pci_dev *dev) +{ + if (dev->subsystem_vendor == 0x14FF && dev->subsystem_device == 0xA003) { + pr_info("Reserving memory on Twinhead H12Y\n"); + request_mem_region(0xFFB00000, 0x100000, "twinhead"); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone); From 2b9ec261e3f247dc84b50263564778bcbefec79b Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 2 May 2012 11:41:30 +0800 Subject: [PATCH 0985/2357] macvtap: zerocopy: fix offset calculation when building skb commit 3afc9621f15701c557e60f61eba9242bac2771dd upstream. This patch fixes the offset calculation when building skb: - offset1 were used as skb data offset not vector offset - reset offset to zero only when we advance to next vector Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/macvtap.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index c1d602d5f15..0302bc5adc6 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -506,10 +506,11 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, if (copy > size) { ++from; --count; - } + offset = 0; + } else + offset += size; copy -= size; offset1 += size; - offset = 0; } if (len == offset1) @@ -520,13 +521,13 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, int num_pages; unsigned long base; - len = from->iov_len - offset1; + len = from->iov_len - offset; if (!len) { - offset1 = 0; + offset = 0; ++from; continue; } - base = (unsigned long)from->iov_base + offset1; + base = (unsigned long)from->iov_base + offset; size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT; if (i + size > MAX_SKB_FRAGS) return -EMSGSIZE; @@ -548,7 +549,7 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, len -= size; i++; } - offset1 = 0; + offset = 0; ++from; } return 0; From bfd1678ca0143060686d87ae0c07bebab6f0245b Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 2 May 2012 11:41:44 +0800 Subject: [PATCH 0986/2357] macvtap: zerocopy: fix truesize underestimation commit 4ef67ebedffa44ed9939b34708ac2fee06d2f65f upstream. As the skb fragment were pinned/built from user pages, we should account the page instead of length for truesize. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/macvtap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 0302bc5adc6..cf096e0693e 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -520,6 +520,7 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, struct page *page[MAX_SKB_FRAGS]; int num_pages; unsigned long base; + unsigned long truesize; len = from->iov_len - offset; if (!len) { @@ -535,10 +536,11 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, if (num_pages != size) /* put_page is in skb free */ return -EFAULT; + truesize = size * PAGE_SIZE; skb->data_len += len; skb->len += len; - skb->truesize += len; - atomic_add(len, &skb->sk->sk_wmem_alloc); + skb->truesize += truesize; + atomic_add(truesize, &skb->sk->sk_wmem_alloc); while (len) { int off = base & ~PAGE_MASK; int size = min_t(int, len, PAGE_SIZE - off); From 61f26eb401b04a9312c422a5dcc7436246f37b58 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 2 May 2012 11:41:58 +0800 Subject: [PATCH 0987/2357] macvtap: zerocopy: put page when fail to get all requested user pages commit 02ce04bb3d28c3333231f43bca677228dbc686fe upstream. When get_user_pages_fast() fails to get all requested pages, we could not use kfree_skb() to free it as it has not been put in the skb fragments. So we need to call put_page() instead. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/macvtap.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index cf096e0693e..7cd750f4c6a 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -533,9 +533,10 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, if (i + size > MAX_SKB_FRAGS) return -EMSGSIZE; num_pages = get_user_pages_fast(base, size, 0, &page[i]); - if (num_pages != size) - /* put_page is in skb free */ - return -EFAULT; + if (num_pages != size) { + for (i = 0; i < num_pages; i++) + put_page(page[i]); + } truesize = size * PAGE_SIZE; skb->data_len += len; skb->len += len; From 2b3c7134014a200279e7ed31716e528cd009dfb0 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 2 May 2012 11:42:06 +0800 Subject: [PATCH 0988/2357] macvtap: zerocopy: set SKBTX_DEV_ZEROCOPY only when skb is built successfully commit 01d6657b388438def19c8baaea28e742b6ed32ec upstream. Current the SKBTX_DEV_ZEROCOPY is set unconditionally after zerocopy_sg_from_iovec(), this would lead NULL pointer when macvtap fails to build zerocopy skb because destructor_arg was not initialized. Solve this by set this flag after the skb were built successfully. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/macvtap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 7cd750f4c6a..b99c418d6b2 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -716,10 +716,9 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, if (!skb) goto err; - if (zerocopy) { + if (zerocopy) err = zerocopy_sg_from_iovec(skb, iv, vnet_hdr_len, count); - skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; - } else + else err = skb_copy_datagram_from_iovec(skb, 0, iv, vnet_hdr_len, len); if (err) @@ -738,8 +737,10 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, rcu_read_lock_bh(); vlan = rcu_dereference_bh(q->vlan); /* copy skb_ubuf_info for callback when skb has no error */ - if (zerocopy) + if (zerocopy) { skb_shinfo(skb)->destructor_arg = m->msg_control; + skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; + } if (vlan) macvlan_start_xmit(skb, vlan->dev); else From ef3914b1b84739c721bcbecd0e519509ccde388c Mon Sep 17 00:00:00 2001 From: Manoj Iyer Date: Tue, 10 Jul 2012 14:07:38 -0500 Subject: [PATCH 0989/2357] Bluetooth: btusb: Add vendor specific ID (0a5c:21f4) BCM20702A0 commit 61c964ba1748e984cb232b431582815899bf10fe upstream. Patch adds support for BCM20702A0 device id (0a5c:21f4). usb-devices after patch was applied: T: Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0a5c ProdID=21f4 Rev=01.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=E4D53DF154D6 C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) usb-devices before patch was applied: T: Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0a5c ProdID=21f4 Rev=01.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=E4D53DF154D6 C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none) I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none) I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Signed-off-by: Manoj Iyer Tested-by: Chris Gagnon Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 9217121362e..daa7cf38907 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -106,6 +106,7 @@ static struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0a5c, 0x21e6) }, { USB_DEVICE(0x0a5c, 0x21e8) }, { USB_DEVICE(0x0a5c, 0x21f3) }, + { USB_DEVICE(0x0a5c, 0x21f4) }, { USB_DEVICE(0x413c, 0x8197) }, /* Foxconn - Hon Hai */ From 004251b52ce7f5079a70220b30bd99c5010f2c6e Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 6 Aug 2012 15:36:49 -0300 Subject: [PATCH 0990/2357] Bluetooth: Use USB_VENDOR_AND_INTERFACE() for Broadcom devices commit 92c385f46b30f4954e9dd2d2005c12d233b479ea upstream. Many Broadcom devices has a vendor specific devices class, with this rule we match all existent and future controllers with this behavior. We also remove old rules to that matches product id for Broadcom devices. Tested-by: John Hommel Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index daa7cf38907..1cb0a30ab5b 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -102,16 +102,14 @@ static struct usb_device_id btusb_table[] = { /* Broadcom BCM20702A0 */ { USB_DEVICE(0x0489, 0xe042) }, - { USB_DEVICE(0x0a5c, 0x21e3) }, - { USB_DEVICE(0x0a5c, 0x21e6) }, - { USB_DEVICE(0x0a5c, 0x21e8) }, - { USB_DEVICE(0x0a5c, 0x21f3) }, - { USB_DEVICE(0x0a5c, 0x21f4) }, { USB_DEVICE(0x413c, 0x8197) }, /* Foxconn - Hon Hai */ { USB_DEVICE(0x0489, 0xe033) }, + /*Broadcom devices with vendor specific id */ + { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, + { } /* Terminating entry */ }; From 403c9ebee757d7ec82e3e06e456ae2445f0b9f40 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 25 Aug 2012 19:28:06 +0200 Subject: [PATCH 0991/2357] Bluetooth: Add support for Apple vendor-specific devices commit 1fa6535faf055cd71311ab887e94fc234f04ee18 upstream. As pointed out by Gustavo and Marcel, all Apple-specific Broadcom devices seen so far have the same interface class, subclass and protocol numbers. This patch adds an entry which matches all of them, using the new USB_VENDOR_AND_INTERFACE_INFO() macro. In particular, this patch adds support for the MacBook Pro Retina (05ac:8286), which is not in the present list. Signed-off-by: Henrik Rydberg Tested-by: Shea Levy Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 1cb0a30ab5b..29d31ff7331 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -60,6 +60,9 @@ static struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, + /* Apple-specific (Broadcom) devices */ + { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) }, + /* Broadcom SoftSailing reporting vendor specific */ { USB_DEVICE(0x0a5c, 0x21e1) }, From 27d50469825fd267f44e13fb0627b011c0da6abd Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 1 Aug 2012 20:34:15 -0300 Subject: [PATCH 0992/2357] Bluetooth: Fix use-after-free bug in SMP commit 61a0cfb008f57ecf7eb28ee762952fb42dc15d15 upstream. If SMP fails, we should always cancel security_timer delayed work. Otherwise, security_timer function may run after l2cap_conn object has been freed. This patch fixes the following warning reported by ODEBUG: WARNING: at lib/debugobjects.c:261 debug_print_object+0x7c/0x8d() Hardware name: Bochs ODEBUG: free active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x27 Modules linked in: btusb bluetooth Pid: 440, comm: kworker/u:2 Not tainted 3.5.0-rc1+ #4 Call Trace: [] ? free_obj_work+0x4a/0x7f [] warn_slowpath_common+0x7e/0x97 [] warn_slowpath_fmt+0x41/0x43 [] debug_print_object+0x7c/0x8d [] ? __queue_work+0x241/0x241 [] debug_check_no_obj_freed+0x92/0x159 [] slab_free_hook+0x6f/0x77 [] ? l2cap_conn_del+0x148/0x157 [bluetooth] [] kfree+0x59/0xac [] l2cap_conn_del+0x148/0x157 [bluetooth] [] l2cap_recv_frame+0xa77/0xfa4 [bluetooth] [] ? trace_hardirqs_on_caller+0x112/0x1ad [] l2cap_recv_acldata+0xe2/0x264 [bluetooth] [] hci_rx_work+0x235/0x33c [bluetooth] [] ? process_one_work+0x126/0x2fe [] process_one_work+0x185/0x2fe [] ? process_one_work+0x126/0x2fe [] ? lock_acquired+0x1b5/0x1cf [] ? le_scan_work+0x11d/0x11d [bluetooth] [] ? spin_lock_irq+0x9/0xb [] worker_thread+0xcf/0x175 [] ? rescuer_thread+0x175/0x175 [] kthread+0x95/0x9d [] kernel_threadi_helper+0x4/0x10 [] ? retint_restore_args+0x13/0x13 [] ? flush_kthread_worker+0xdb/0xdb [] ? gs_change+0x13/0x13 This bug can be reproduced using hctool lecc or l2test tools and bluetoothd not running. Signed-off-by: Andre Guedes Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/smp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index deb119875fd..65127223833 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -266,10 +266,10 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type, hcon->dst_type, reason); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { - cancel_delayed_work_sync(&conn->security_timer); + cancel_delayed_work_sync(&conn->security_timer); + + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) smp_chan_destroy(conn); - } } #define JUST_WORKS 0x00 From 0fcc0805df9cf7483e927cf6a4dc94938318c06a Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 23 Aug 2012 21:32:43 -0300 Subject: [PATCH 0993/2357] Bluetooth: Change signature of smp_conn_security() commit cc110922da7e902b62d18641a370fec01a9fa794 upstream. To make it clear that it may be called from contexts that may not have any knowledge of L2CAP, we change the connection parameter, to receive a hci_conn. This also makes it clear that it is checking the security of the link. Signed-off-by: Vinicius Costa Gomes Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- include/net/bluetooth/smp.h | 2 +- net/bluetooth/l2cap_core.c | 11 ++++++----- net/bluetooth/l2cap_sock.c | 2 +- net/bluetooth/smp.c | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h index 7b3acdd2913..1bf9bec8e4f 100644 --- a/include/net/bluetooth/smp.h +++ b/include/net/bluetooth/smp.h @@ -136,7 +136,7 @@ struct smp_chan { }; /* SMP Commands */ -int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level); +int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); int smp_distribute_keys(struct l2cap_conn *conn, __u8 force); int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9a86759a7e6..627c35445a1 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -937,14 +937,15 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) static void l2cap_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan *chan; + struct hci_conn *hcon = conn->hcon; BT_DBG("conn %p", conn); - if (!conn->hcon->out && conn->hcon->type == LE_LINK) + if (!hcon->out && hcon->type == LE_LINK) l2cap_le_conn_ready(conn); - if (conn->hcon->out && conn->hcon->type == LE_LINK) - smp_conn_security(conn, conn->hcon->pending_sec_level); + if (hcon->out && hcon->type == LE_LINK) + smp_conn_security(hcon, hcon->pending_sec_level); mutex_lock(&conn->chan_lock); @@ -952,8 +953,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) l2cap_chan_lock(chan); - if (conn->hcon->type == LE_LINK) { - if (smp_conn_security(conn, chan->sec_level)) + if (hcon->type == LE_LINK) { + if (smp_conn_security(hcon, chan->sec_level)) l2cap_chan_ready(chan); } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 615b26e0650..4a26348444b 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -588,7 +588,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch break; } - if (smp_conn_security(conn, sec.level)) + if (smp_conn_security(conn->hcon, sec.level)) break; sk->sk_state = BT_CONFIG; chan->state = BT_CONFIG; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 65127223833..1f6cb1f1cd2 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -753,9 +753,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } -int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) +int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) { - struct hci_conn *hcon = conn->hcon; + struct l2cap_conn *conn = hcon->l2cap_data; struct smp_chan *smp = conn->smp_chan; __u8 authreq; From c031edca540afb66764db24eed10eb149ac6c852 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 23 Aug 2012 21:32:44 -0300 Subject: [PATCH 0994/2357] Bluetooth: Fix sending a HCI Authorization Request over LE links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d8343f125710fb596f7a88cd756679f14f4e77b9 upstream. In the case that the link is already in the connected state and a Pairing request arrives from the mgmt interface, hci_conn_security() would be called but it was not considering LE links. Reported-by: João Paulo Rechi Vita Signed-off-by: Vinicius Costa Gomes Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_conn.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5238b6b3ea6..39b2baf6c1d 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -42,6 +42,7 @@ #include #include +#include static void hci_le_connect(struct hci_conn *conn) { @@ -661,6 +662,9 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) { BT_DBG("conn %p", conn); + if (conn->type == LE_LINK) + return smp_conn_security(conn, sec_level); + /* For sdp we don't need the link key. */ if (sec_level == BT_SECURITY_SDP) return 1; From e6da94be68b025bdbbee3764428769a85367aa79 Mon Sep 17 00:00:00 2001 From: "Rustad, Mark D" Date: Wed, 18 Jul 2012 09:06:07 +0000 Subject: [PATCH 0995/2357] net: Statically initialize init_net.dev_base_head commit 734b65417b24d6eea3e3d7457e1f11493890ee1d upstream. This change eliminates an initialization-order hazard most recently seen when netprio_cgroup is built into the kernel. With thanks to Eric Dumazet for catching a bug. Signed-off-by: Mark Rustad Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 3 ++- net/core/net_namespace.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 40d5ab15bef..3fd9cae3ccb 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6303,7 +6303,8 @@ static struct hlist_head *netdev_create_hash(void) /* Initialize per network namespace state */ static int __net_init netdev_init(struct net *net) { - INIT_LIST_HEAD(&net->dev_base_head); + if (net != &init_net) + INIT_LIST_HEAD(&net->dev_base_head); net->dev_name_head = netdev_create_hash(); if (net->dev_name_head == NULL) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 31a5ae51a45..dd00b71dd09 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -25,7 +25,9 @@ static DEFINE_MUTEX(net_mutex); LIST_HEAD(net_namespace_list); EXPORT_SYMBOL_GPL(net_namespace_list); -struct net init_net; +struct net init_net = { + .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head), +}; EXPORT_SYMBOL(init_net); #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ From 0d19c30f548369606cce202224c86cf3ae1d20ea Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 18 Jul 2012 13:41:11 -0300 Subject: [PATCH 0996/2357] media: cx25821: Remove bad strcpy to read-only char* commit c854d8883fec59332f0662917f8c94dcfb1c405d upstream. The strcpy was being used to set the name of the board. This was both wrong and redundant, since the destination char* was read-only and the name is set statically at compile time. The type of the name field is changed to const char* to prevent future errors. Reported-by: Radek Masin Signed-off-by: Ezequiel Garcia Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/cx25821/cx25821-core.c | 3 --- drivers/media/video/cx25821/cx25821.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c index 7930ca58349..235bf7da6c0 100644 --- a/drivers/media/video/cx25821/cx25821-core.c +++ b/drivers/media/video/cx25821/cx25821-core.c @@ -912,9 +912,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) list_add_tail(&dev->devlist, &cx25821_devlist); mutex_unlock(&cx25821_devlist_mutex); - strcpy(cx25821_boards[UNKNOWN_BOARD].name, "unknown"); - strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821"); - if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h index b9aa801b00a..029f2934a6d 100644 --- a/drivers/media/video/cx25821/cx25821.h +++ b/drivers/media/video/cx25821/cx25821.h @@ -187,7 +187,7 @@ enum port { }; struct cx25821_board { - char *name; + const char *name; enum port porta; enum port portb; enum port portc; From 11266a8e031a3782241760850f002c79ee2887e1 Mon Sep 17 00:00:00 2001 From: Li Zhong Date: Tue, 24 Jul 2012 15:02:49 -0700 Subject: [PATCH 0997/2357] Fix a dead loop in async_synchronize_full() [Fixed upstream by commits 2955b47d2c1983998a8c5915cb96884e67f7cb53 and a4683487f90bfe3049686fc5c566bdc1ad03ace6 from Dan Williams, but they are much more intrusive than this tiny fix, according to Andrew - gregkh] This patch tries to fix a dead loop in async_synchronize_full(), which could be seen when preemption is disabled on a single cpu machine. void async_synchronize_full(void) { do { async_synchronize_cookie(next_cookie); } while (!list_empty(&async_running) || ! list_empty(&async_pending)); } async_synchronize_cookie() calls async_synchronize_cookie_domain() with &async_running as the default domain to synchronize. However, there might be some works in the async_pending list from other domains. On a single cpu system, without preemption, there is no chance for the other works to finish, so async_synchronize_full() enters a dead loop. It seems async_synchronize_full() wants to synchronize all entries in all running lists(domains), so maybe we could just check the entry_count to know whether all works are finished. Currently, async_synchronize_cookie_domain() expects a non-NULL running list ( if NULL, there would be NULL pointer dereference ), so maybe a NULL pointer could be used as an indication for the functions to synchronize all works in all domains. Reported-by: Paul E. McKenney Signed-off-by: Li Zhong Tested-by: Paul E. McKenney Tested-by: Christian Kujau Cc: Andrew Morton Cc: Dan Williams Cc: Christian Kujau Cc: Andrew Morton Cc: Cong Wang Signed-off-by: Greg Kroah-Hartman --- kernel/async.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/async.c b/kernel/async.c index bd0c168a3bb..32d8dc96026 100644 --- a/kernel/async.c +++ b/kernel/async.c @@ -86,6 +86,13 @@ static async_cookie_t __lowest_in_progress(struct list_head *running) { struct async_entry *entry; + if (!running) { /* just check the entry count */ + if (atomic_read(&entry_count)) + return 0; /* smaller than any cookie */ + else + return next_cookie; + } + if (!list_empty(running)) { entry = list_first_entry(running, struct async_entry, list); @@ -236,9 +243,7 @@ EXPORT_SYMBOL_GPL(async_schedule_domain); */ void async_synchronize_full(void) { - do { - async_synchronize_cookie(next_cookie); - } while (!list_empty(&async_running) || !list_empty(&async_pending)); + async_synchronize_cookie_domain(next_cookie, NULL); } EXPORT_SYMBOL_GPL(async_synchronize_full); @@ -258,7 +263,7 @@ EXPORT_SYMBOL_GPL(async_synchronize_full_domain); /** * async_synchronize_cookie_domain - synchronize asynchronous function calls within a certain domain with cookie checkpointing * @cookie: async_cookie_t to use as checkpoint - * @running: running list to synchronize on + * @running: running list to synchronize on, NULL indicates all lists * * This function waits until all asynchronous function calls for the * synchronization domain specified by the running list @list submitted From b2c1fcae0409fec6d96351fe2793a502870f4370 Mon Sep 17 00:00:00 2001 From: Weiping Pan Date: Mon, 23 Jul 2012 10:37:48 +0800 Subject: [PATCH 0998/2357] rds: set correct msg_namelen commit 06b6a1cf6e776426766298d055bb3991957d90a7 upstream. Jay Fenlason (fenlason@redhat.com) found a bug, that recvfrom() on an RDS socket can return the contents of random kernel memory to userspace if it was called with a address length larger than sizeof(struct sockaddr_in). rds_recvmsg() also fails to set the addr_len paramater properly before returning, but that's just a bug. There are also a number of cases wher recvfrom() can return an entirely bogus address. Anything in rds_recvmsg() that returns a non-negative value but does not go through the "sin = (struct sockaddr_in *)msg->msg_name;" code path at the end of the while(1) loop will return up to 128 bytes of kernel memory to userspace. And I write two test programs to reproduce this bug, you will see that in rds_server, fromAddr will be overwritten and the following sock_fd will be destroyed. Yes, it is the programmer's fault to set msg_namelen incorrectly, but it is better to make the kernel copy the real length of address to user space in such case. How to run the test programs ? I test them on 32bit x86 system, 3.5.0-rc7. 1 compile gcc -o rds_client rds_client.c gcc -o rds_server rds_server.c 2 run ./rds_server on one console 3 run ./rds_client on another console 4 you will see something like: server is waiting to receive data... old socket fd=3 server received data from client:data from client msg.msg_namelen=32 new socket fd=-1067277685 sendmsg() : Bad file descriptor /***************** rds_client.c ********************/ int main(void) { int sock_fd; struct sockaddr_in serverAddr; struct sockaddr_in toAddr; char recvBuffer[128] = "data from client"; struct msghdr msg; struct iovec iov; sock_fd = socket(AF_RDS, SOCK_SEQPACKET, 0); if (sock_fd < 0) { perror("create socket error\n"); exit(1); } memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); serverAddr.sin_port = htons(4001); if (bind(sock_fd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { perror("bind() error\n"); close(sock_fd); exit(1); } memset(&toAddr, 0, sizeof(toAddr)); toAddr.sin_family = AF_INET; toAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); toAddr.sin_port = htons(4000); msg.msg_name = &toAddr; msg.msg_namelen = sizeof(toAddr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_iov->iov_base = recvBuffer; msg.msg_iov->iov_len = strlen(recvBuffer) + 1; msg.msg_control = 0; msg.msg_controllen = 0; msg.msg_flags = 0; if (sendmsg(sock_fd, &msg, 0) == -1) { perror("sendto() error\n"); close(sock_fd); exit(1); } printf("client send data:%s\n", recvBuffer); memset(recvBuffer, '\0', 128); msg.msg_name = &toAddr; msg.msg_namelen = sizeof(toAddr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_iov->iov_base = recvBuffer; msg.msg_iov->iov_len = 128; msg.msg_control = 0; msg.msg_controllen = 0; msg.msg_flags = 0; if (recvmsg(sock_fd, &msg, 0) == -1) { perror("recvmsg() error\n"); close(sock_fd); exit(1); } printf("receive data from server:%s\n", recvBuffer); close(sock_fd); return 0; } /***************** rds_server.c ********************/ int main(void) { struct sockaddr_in fromAddr; int sock_fd; struct sockaddr_in serverAddr; unsigned int addrLen; char recvBuffer[128]; struct msghdr msg; struct iovec iov; sock_fd = socket(AF_RDS, SOCK_SEQPACKET, 0); if(sock_fd < 0) { perror("create socket error\n"); exit(0); } memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); serverAddr.sin_port = htons(4000); if (bind(sock_fd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { perror("bind error\n"); close(sock_fd); exit(1); } printf("server is waiting to receive data...\n"); msg.msg_name = &fromAddr; /* * I add 16 to sizeof(fromAddr), ie 32, * and pay attention to the definition of fromAddr, * recvmsg() will overwrite sock_fd, * since kernel will copy 32 bytes to userspace. * * If you just use sizeof(fromAddr), it works fine. * */ msg.msg_namelen = sizeof(fromAddr) + 16; /* msg.msg_namelen = sizeof(fromAddr); */ msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_iov->iov_base = recvBuffer; msg.msg_iov->iov_len = 128; msg.msg_control = 0; msg.msg_controllen = 0; msg.msg_flags = 0; while (1) { printf("old socket fd=%d\n", sock_fd); if (recvmsg(sock_fd, &msg, 0) == -1) { perror("recvmsg() error\n"); close(sock_fd); exit(1); } printf("server received data from client:%s\n", recvBuffer); printf("msg.msg_namelen=%d\n", msg.msg_namelen); printf("new socket fd=%d\n", sock_fd); strcat(recvBuffer, "--data from server"); if (sendmsg(sock_fd, &msg, 0) == -1) { perror("sendmsg()\n"); close(sock_fd); exit(1); } } close(sock_fd); return 0; } Signed-off-by: Weiping Pan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rds/recv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/rds/recv.c b/net/rds/recv.c index 5c6e9f13202..9f0f17cf6bf 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -410,6 +410,8 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, rdsdebug("size %zu flags 0x%x timeo %ld\n", size, msg_flags, timeo); + msg->msg_namelen = 0; + if (msg_flags & MSG_OOB) goto out; @@ -485,6 +487,7 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, sin->sin_port = inc->i_hdr.h_sport; sin->sin_addr.s_addr = inc->i_saddr; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + msg->msg_namelen = sizeof(*sin); } break; } From 9dd30d194e2e83be4e14d7b4bdf21087f389318b Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Mon, 23 Jul 2012 12:22:37 +0800 Subject: [PATCH 0999/2357] libata: Prevent interface errors with Seagate FreeAgent GoFlex commit c531077f40abc9f2129c4c83a30b3f8d6ce1c0e7 upstream. When using my Seagate FreeAgent GoFlex eSATAp external disk enclosure, interface errors are always seen until 1.5Gbps is negotiated [1]. This occurs using any disk in the enclosure, and when the disk is connected directly with a generic passive eSATAp cable, we see stable 3Gbps operation as expected. Blacklist 3Gbps mode to avoid dataloss and the ~30s delay bus reset and renegotiation incurs. Signed-off-by: Daniel J Blueman Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d31ee557b39..cf4837f3ded 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4125,6 +4125,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Devices which aren't very happy with higher link speeds */ { "WD My Book", NULL, ATA_HORKAGE_1_5_GBPS, }, + { "Seagate FreeAgent GoFlex", NULL, ATA_HORKAGE_1_5_GBPS, }, /* * Devices which choke on SETXFER. Applies only if both the From 6418cc471b5d8a64ce22d2aa827fcb275e61449c Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Wed, 20 Jun 2012 12:09:18 +0000 Subject: [PATCH 1000/2357] r8169: RxConfig hack for the 8168evl. commit eb2dc35d99028b698cdedba4f5522bc43e576bd2 upstream. The 8168evl (RTL_GIGA_MAC_VER_34) based Gigabyte GA-990FXA motherboards are very prone to NETDEV watchdog problems without this change. See https://bugzilla.kernel.org/show_bug.cgi?id=42899 for instance. I don't know why it *works*. It's depressingly effective though. For the record: - the problem may go along IOMMU (AMD-Vi) errors but it really looks like a red herring. - the patch sets the RX_MULTI_EN bit. If the 8168c doc is any guide, the chipset now fetches several Rx descriptors at a time. - long ago the driver ignored the RX_MULTI_EN bit. e542a2269f232d61270ceddd42b73a4348dee2bb changed the RxConfig settings. Whatever the problem it's now labeled a regression. - Realtek's own driver can identify two different 8168evl devices (CFG_METHOD_16 and CFG_METHOD_17) where the r8169 driver only sees one. It sucks. Signed-off-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index a73bbe7fb63..5fb74c4298f 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -3737,6 +3737,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_22: case RTL_GIGA_MAC_VER_23: case RTL_GIGA_MAC_VER_24: + case RTL_GIGA_MAC_VER_34: RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST); break; default: From e194fab8d7ebe95db5609f1cb6794c2afcc3118f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jun 2012 13:36:05 +0200 Subject: [PATCH 1001/2357] sched: Fix race in task_group() commit 8323f26ce3425460769605a6aece7a174edaa7d1 upstream. Stefan reported a crash on a kernel before a3e5d1091c1 ("sched: Don't call task_group() too many times in set_task_rq()"), he found the reason to be that the multiple task_group() invocations in set_task_rq() returned different values. Looking at all that I found a lack of serialization and plain wrong comments. The below tries to fix it using an extra pointer which is updated under the appropriate scheduler locks. Its not pretty, but I can't really see another way given how all the cgroup stuff works. Reported-and-tested-by: Stefan Bader Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1340364965.18025.71.camel@twins Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- include/linux/init_task.h | 12 +++++++++++- include/linux/sched.h | 5 ++++- kernel/sched/core.c | 9 ++++++++- kernel/sched/sched.h | 23 ++++++++++------------- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index e4baff5f7ff..e7bafa432aa 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -123,8 +123,17 @@ extern struct group_info init_groups; extern struct cred init_cred; +extern struct task_group root_task_group; + +#ifdef CONFIG_CGROUP_SCHED +# define INIT_CGROUP_SCHED(tsk) \ + .sched_task_group = &root_task_group, +#else +# define INIT_CGROUP_SCHED(tsk) +#endif + #ifdef CONFIG_PERF_EVENTS -# define INIT_PERF_EVENTS(tsk) \ +# define INIT_PERF_EVENTS(tsk) \ .perf_event_mutex = \ __MUTEX_INITIALIZER(tsk.perf_event_mutex), \ .perf_event_list = LIST_HEAD_INIT(tsk.perf_event_list), @@ -161,6 +170,7 @@ extern struct cred init_cred; }, \ .tasks = LIST_HEAD_INIT(tsk.tasks), \ INIT_PUSHABLE_TASKS(tsk) \ + INIT_CGROUP_SCHED(tsk) \ .ptraced = LIST_HEAD_INIT(tsk.ptraced), \ .ptrace_entry = LIST_HEAD_INIT(tsk.ptrace_entry), \ .real_parent = &tsk, \ diff --git a/include/linux/sched.h b/include/linux/sched.h index 7b06169d724..48241aa976c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1279,6 +1279,9 @@ struct task_struct { const struct sched_class *sched_class; struct sched_entity se; struct sched_rt_entity rt; +#ifdef CONFIG_CGROUP_SCHED + struct task_group *sched_task_group; +#endif #ifdef CONFIG_PREEMPT_NOTIFIERS /* list of struct preempt_notifier: */ @@ -2744,7 +2747,7 @@ extern int sched_group_set_rt_period(struct task_group *tg, extern long sched_group_rt_period(struct task_group *tg); extern int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk); #endif -#endif +#endif /* CONFIG_CGROUP_SCHED */ extern int task_can_switch_user(struct user_struct *up, struct task_struct *tsk); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index ef6a8f2eeff..593087b2baf 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1098,7 +1098,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) * a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks. * * sched_move_task() holds both and thus holding either pins the cgroup, - * see set_task_rq(). + * see task_group(). * * Furthermore, all task_rq users should acquire both locks, see * task_rq_lock(). @@ -7427,6 +7427,7 @@ void sched_destroy_group(struct task_group *tg) */ void sched_move_task(struct task_struct *tsk) { + struct task_group *tg; int on_rq, running; unsigned long flags; struct rq *rq; @@ -7441,6 +7442,12 @@ void sched_move_task(struct task_struct *tsk) if (unlikely(running)) tsk->sched_class->put_prev_task(rq, tsk); + tg = container_of(task_subsys_state_check(tsk, cpu_cgroup_subsys_id, + lockdep_is_held(&tsk->sighand->siglock)), + struct task_group, css); + tg = autogroup_task_group(tsk, tg); + tsk->sched_task_group = tg; + #ifdef CONFIG_FAIR_GROUP_SCHED if (tsk->sched_class->task_move_group) tsk->sched_class->task_move_group(tsk, on_rq); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index d9637f4c43d..acfa7017eb0 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -536,22 +536,19 @@ DECLARE_PER_CPU(int, sd_llc_id); /* * Return the group to which this tasks belongs. * - * We use task_subsys_state_check() and extend the RCU verification with - * pi->lock and rq->lock because cpu_cgroup_attach() holds those locks for each - * task it moves into the cgroup. Therefore by holding either of those locks, - * we pin the task to the current cgroup. + * We cannot use task_subsys_state() and friends because the cgroup + * subsystem changes that value before the cgroup_subsys::attach() method + * is called, therefore we cannot pin it and might observe the wrong value. + * + * The same is true for autogroup's p->signal->autogroup->tg, the autogroup + * core changes this before calling sched_move_task(). + * + * Instead we use a 'copy' which is updated from sched_move_task() while + * holding both task_struct::pi_lock and rq::lock. */ static inline struct task_group *task_group(struct task_struct *p) { - struct task_group *tg; - struct cgroup_subsys_state *css; - - css = task_subsys_state_check(p, cpu_cgroup_subsys_id, - lockdep_is_held(&p->pi_lock) || - lockdep_is_held(&task_rq(p)->lock)); - tg = container_of(css, struct task_group, css); - - return autogroup_task_group(p, tg); + return p->sched_task_group; } /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */ From 391c314928c37b0c946061c0adddd5bd5730c8b7 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 11 Jul 2012 14:02:53 -0700 Subject: [PATCH 1002/2357] mm: sparse: fix usemap allocation above node descriptor section commit 99ab7b19440a72ebdf225f99b20f8ef40decee86 upstream. After commit f5bf18fa22f8 ("bootmem/sparsemem: remove limit constraint in alloc_bootmem_section"), usemap allocations may easily be placed outside the optimal section that holds the node descriptor, even if there is space available in that section. This results in unnecessary hotplug dependencies that need to have the node unplugged before the section holding the usemap. The reason is that the bootmem allocator doesn't guarantee a linear search starting from the passed allocation goal but may start out at a much higher address absent an upper limit. Fix this by trying the allocation with the limit at the section end, then retry without if that fails. This keeps the fix from f5bf18fa22f8 of not panicking if the allocation does not fit in the section, but still makes sure to try to stay within the section at first. [rewritten massively by Johannes to apply to 3.4] Signed-off-by: Yinghai Lu Signed-off-by: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/bootmem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mm/bootmem.c b/mm/bootmem.c index 0131170c9d5..53cf62b186b 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -766,13 +766,17 @@ void * __init alloc_bootmem_section(unsigned long size, unsigned long section_nr) { bootmem_data_t *bdata; - unsigned long pfn, goal; + unsigned long pfn, goal, limit; pfn = section_nr_to_pfn(section_nr); goal = pfn << PAGE_SHIFT; + limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT; bdata = &bootmem_node_data[early_pfn_to_nid(pfn)]; - return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, 0); + if (goal + size > limit) + limit = 0; + + return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, limit); } #endif From 504471eb5044e4a1dd10950d1a3efab39ba2083a Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 4 Jun 2012 13:05:24 -0300 Subject: [PATCH 1003/2357] media: lirc_sir: make device registration work commit 4b71ca6bce8fab3d08c61bf330e781f957934ae1 upstream. For one, the driver device pointer needs to be filled in, or the lirc core will refuse to load the driver. And we really need to wire up all the platform_device bits. This has been tested via the lirc sourceforge tree and verified to work, been sitting there for months, finally getting around to sending it. :\ Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab CC: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/media/lirc/lirc_sir.c | 60 ++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c index 945d9623550..4afc3b41973 100644 --- a/drivers/staging/media/lirc/lirc_sir.c +++ b/drivers/staging/media/lirc/lirc_sir.c @@ -52,6 +52,7 @@ #include #include #include +#include #ifdef LIRC_ON_SA1100 #include #ifdef CONFIG_SA1100_COLLIE @@ -487,9 +488,11 @@ static struct lirc_driver driver = { .owner = THIS_MODULE, }; +static struct platform_device *lirc_sir_dev; static int init_chrdev(void) { + driver.dev = &lirc_sir_dev->dev; driver.minor = lirc_register_driver(&driver); if (driver.minor < 0) { printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); @@ -1215,20 +1218,71 @@ static int init_lirc_sir(void) return 0; } +static int __devinit lirc_sir_probe(struct platform_device *dev) +{ + return 0; +} + +static int __devexit lirc_sir_remove(struct platform_device *dev) +{ + return 0; +} + +static struct platform_driver lirc_sir_driver = { + .probe = lirc_sir_probe, + .remove = __devexit_p(lirc_sir_remove), + .driver = { + .name = "lirc_sir", + .owner = THIS_MODULE, + }, +}; static int __init lirc_sir_init(void) { int retval; + retval = platform_driver_register(&lirc_sir_driver); + if (retval) { + printk(KERN_ERR LIRC_DRIVER_NAME ": Platform driver register " + "failed!\n"); + return -ENODEV; + } + + lirc_sir_dev = platform_device_alloc("lirc_dev", 0); + if (!lirc_sir_dev) { + printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device alloc " + "failed!\n"); + retval = -ENOMEM; + goto pdev_alloc_fail; + } + + retval = platform_device_add(lirc_sir_dev); + if (retval) { + printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device add " + "failed!\n"); + retval = -ENODEV; + goto pdev_add_fail; + } + retval = init_chrdev(); if (retval < 0) - return retval; + goto fail; + retval = init_lirc_sir(); if (retval) { drop_chrdev(); - return retval; + goto fail; } + return 0; + +fail: + platform_device_del(lirc_sir_dev); +pdev_add_fail: + platform_device_put(lirc_sir_dev); +pdev_alloc_fail: + platform_driver_unregister(&lirc_sir_driver); + return retval; } static void __exit lirc_sir_exit(void) @@ -1236,6 +1290,8 @@ static void __exit lirc_sir_exit(void) drop_hardware(); drop_chrdev(); drop_port(); + platform_device_unregister(lirc_sir_dev); + platform_driver_unregister(&lirc_sir_driver); printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); } From 8e878154f5658ba93cf9bb2b491a930ec195de3d Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 11 Sep 2012 15:04:17 -0400 Subject: [PATCH 1004/2357] time: Improve sanity checking of timekeeping inputs commit 4e8b14526ca7fb046a81c94002c1c43b6fdf0e9b upstream. Unexpected behavior could occur if the time is set to a value large enough to overflow a 64bit ktime_t (which is something larger then the year 2262). Also unexpected behavior could occur if large negative offsets are injected via adjtimex. So this patch improves the sanity check timekeeping inputs by improving the timespec_valid() check, and then makes better use of timespec_valid() to make sure we don't set the time to an invalid negative value or one that overflows ktime_t. Note: This does not protect from setting the time close to overflowing ktime_t and then letting natural accumulation cause the overflow. Reported-by: CAI Qian Reported-by: Sasha Levin Signed-off-by: John Stultz Cc: Peter Zijlstra Cc: Prarit Bhargava Cc: Zhouping Liu Cc: Ingo Molnar Link: http://lkml.kernel.org/r/1344454580-17031-1-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- include/linux/ktime.h | 7 ------- include/linux/time.h | 22 ++++++++++++++++++++-- kernel/time/timekeeping.c | 26 ++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/include/linux/ktime.h b/include/linux/ktime.h index 603bec2913b..06177ba10a1 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -58,13 +58,6 @@ union ktime { typedef union ktime ktime_t; /* Kill this */ -#define KTIME_MAX ((s64)~((u64)1 << 63)) -#if (BITS_PER_LONG == 64) -# define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) -#else -# define KTIME_SEC_MAX LONG_MAX -#endif - /* * ktime_t definitions when using the 64-bit scalar representation: */ diff --git a/include/linux/time.h b/include/linux/time.h index 8da51299a7d..ac3118640e5 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -107,11 +107,29 @@ static inline struct timespec timespec_sub(struct timespec lhs, return ts_delta; } +#define KTIME_MAX ((s64)~((u64)1 << 63)) +#if (BITS_PER_LONG == 64) +# define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) +#else +# define KTIME_SEC_MAX LONG_MAX +#endif + /* * Returns true if the timespec is norm, false if denorm: */ -#define timespec_valid(ts) \ - (((ts)->tv_sec >= 0) && (((unsigned long) (ts)->tv_nsec) < NSEC_PER_SEC)) +static inline bool timespec_valid(const struct timespec *ts) +{ + /* Dates before 1970 are bogus */ + if (ts->tv_sec < 0) + return false; + /* Can't have more nanoseconds then a second */ + if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) + return false; + /* Disallow values that could overflow ktime_t */ + if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) + return false; + return true; +} extern void read_persistent_clock(struct timespec *ts); extern void read_boot_clock(struct timespec *ts); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 7c50de83b6f..dd31d0e96bc 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -385,7 +385,7 @@ int do_settimeofday(const struct timespec *tv) struct timespec ts_delta; unsigned long flags; - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + if (!timespec_valid(tv)) return -EINVAL; write_seqlock_irqsave(&timekeeper.lock, flags); @@ -420,6 +420,8 @@ EXPORT_SYMBOL(do_settimeofday); int timekeeping_inject_offset(struct timespec *ts) { unsigned long flags; + struct timespec tmp; + int ret = 0; if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) return -EINVAL; @@ -428,10 +430,17 @@ int timekeeping_inject_offset(struct timespec *ts) timekeeping_forward_now(); + tmp = timespec_add(timekeeper.xtime, *ts); + if (!timespec_valid(&tmp)) { + ret = -EINVAL; + goto error; + } + timekeeper.xtime = timespec_add(timekeeper.xtime, *ts); timekeeper.wall_to_monotonic = timespec_sub(timekeeper.wall_to_monotonic, *ts); +error: /* even if we error out, we forwarded the time, so call update */ timekeeping_update(true); write_sequnlock_irqrestore(&timekeeper.lock, flags); @@ -439,7 +448,7 @@ int timekeeping_inject_offset(struct timespec *ts) /* signal hrtimers about time change */ clock_was_set(); - return 0; + return ret; } EXPORT_SYMBOL(timekeeping_inject_offset); @@ -599,7 +608,20 @@ void __init timekeeping_init(void) struct timespec now, boot; read_persistent_clock(&now); + if (!timespec_valid(&now)) { + pr_warn("WARNING: Persistent clock returned invalid value!\n" + " Check your CMOS/BIOS settings.\n"); + now.tv_sec = 0; + now.tv_nsec = 0; + } + read_boot_clock(&boot); + if (!timespec_valid(&boot)) { + pr_warn("WARNING: Boot clock returned invalid value!\n" + " Check your CMOS/BIOS settings.\n"); + boot.tv_sec = 0; + boot.tv_nsec = 0; + } seqlock_init(&timekeeper.lock); From 80257cbe62ea0919153c43421746269ab68473bf Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 11 Sep 2012 15:04:18 -0400 Subject: [PATCH 1005/2357] time: Avoid making adjustments if we haven't accumulated anything commit bf2ac312195155511a0f79325515cbb61929898a upstream. If update_wall_time() is called and the current offset isn't large enough to accumulate, avoid re-calling timekeeping_adjust which may change the clock freq and can cause 1ns inconsistencies with CLOCK_REALTIME_COARSE/CLOCK_MONOTONIC_COARSE. Signed-off-by: John Stultz Cc: Prarit Bhargava Cc: Ingo Molnar Link: http://lkml.kernel.org/r/1345595449-34965-5-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/time/timekeeping.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index dd31d0e96bc..104d549f9df 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1057,9 +1057,12 @@ static void update_wall_time(void) #else offset = (clock->read(clock) - clock->cycle_last) & clock->mask; #endif + /* Check if there's really nothing to do */ + if (offset < timekeeper.cycle_interval) + goto out; + timekeeper.xtime_nsec = (s64)timekeeper.xtime.tv_nsec << timekeeper.shift; - /* * With NO_HZ we may have to accumulate many cycle_intervals * (think "ticks") worth of time at once. To do this efficiently, From 9a227fcb842a03fce5b8a6da0da40f5601ec6908 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 11 Sep 2012 15:04:19 -0400 Subject: [PATCH 1006/2357] time: Move ktime_t overflow checking into timespec_valid_strict commit cee58483cf56e0ba355fdd97ff5e8925329aa936 upstream Andreas Bombe reported that the added ktime_t overflow checking added to timespec_valid in commit 4e8b14526ca7 ("time: Improve sanity checking of timekeeping inputs") was causing problems with X.org because it caused timeouts larger then KTIME_T to be invalid. Previously, these large timeouts would be clamped to KTIME_MAX and would never expire, which is valid. This patch splits the ktime_t overflow checking into a new timespec_valid_strict function, and converts the timekeeping codes internal checking to use this more strict function. Reported-and-tested-by: Andreas Bombe Cc: Zhouping Liu Cc: Ingo Molnar Cc: Prarit Bhargava Cc: Thomas Gleixner Signed-off-by: John Stultz Signed-off-by: Linus Torvalds Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- include/linux/time.h | 7 +++++++ kernel/time/timekeeping.c | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/linux/time.h b/include/linux/time.h index ac3118640e5..03dce74e217 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -125,6 +125,13 @@ static inline bool timespec_valid(const struct timespec *ts) /* Can't have more nanoseconds then a second */ if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) return false; + return true; +} + +static inline bool timespec_valid_strict(const struct timespec *ts) +{ + if (!timespec_valid(ts)) + return false; /* Disallow values that could overflow ktime_t */ if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) return false; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 104d549f9df..12843e9f6d5 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -385,7 +385,7 @@ int do_settimeofday(const struct timespec *tv) struct timespec ts_delta; unsigned long flags; - if (!timespec_valid(tv)) + if (!timespec_valid_strict(tv)) return -EINVAL; write_seqlock_irqsave(&timekeeper.lock, flags); @@ -431,7 +431,7 @@ int timekeeping_inject_offset(struct timespec *ts) timekeeping_forward_now(); tmp = timespec_add(timekeeper.xtime, *ts); - if (!timespec_valid(&tmp)) { + if (!timespec_valid_strict(&tmp)) { ret = -EINVAL; goto error; } @@ -608,7 +608,7 @@ void __init timekeeping_init(void) struct timespec now, boot; read_persistent_clock(&now); - if (!timespec_valid(&now)) { + if (!timespec_valid_strict(&now)) { pr_warn("WARNING: Persistent clock returned invalid value!\n" " Check your CMOS/BIOS settings.\n"); now.tv_sec = 0; @@ -616,7 +616,7 @@ void __init timekeeping_init(void) } read_boot_clock(&boot); - if (!timespec_valid(&boot)) { + if (!timespec_valid_strict(&boot)) { pr_warn("WARNING: Boot clock returned invalid value!\n" " Check your CMOS/BIOS settings.\n"); boot.tv_sec = 0; @@ -667,7 +667,7 @@ static void update_sleep_time(struct timespec t) */ static void __timekeeping_inject_sleeptime(struct timespec *delta) { - if (!timespec_valid(delta)) { + if (!timespec_valid_strict(delta)) { printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid " "sleep delta value!\n"); return; From a31c99713bb3e130d34039a7a073a9d815af90a0 Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Fri, 6 Jul 2012 23:27:57 -0300 Subject: [PATCH 1007/2357] media: Avoid sysfs oops when an rc_dev's raw device is absent commit 720bb6436ff30fccad05cf5bdf961ea5b1f5686d upstream. For some reason, when the lirc daemon learns that a usb remote control has been unplugged, it wants to read the sysfs attributes of the disappearing device. This is useful for uncovering transient inconsistencies, but less so for keeping the system running when such inconsistencies exist. Under some circumstances (like every time I unplug my dvb stick from my laptop), lirc catches an rc_dev whose raw event handler has been removed (presumably by ir_raw_event_unregister), and proceeds to interrogate the raw protocols supported by the NULL pointer. This patch avoids the NULL dereference, and ignores the issue of how this state of affairs came about in the first place. Version 2 incorporates changes recommended by Mauro Carvalho Chehab (-ENODEV instead of -EINVAL, and a signed-off-by). Signed-off-by: Douglas Bagnall Signed-off-by: Mauro Carvalho Chehab Cc: Herton Ronaldo Krzesinski Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/rc-main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 6e16b09c24a..cabc19c1051 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -775,10 +775,11 @@ static ssize_t show_protocols(struct device *device, if (dev->driver_type == RC_DRIVER_SCANCODE) { enabled = dev->rc_map.rc_type; allowed = dev->allowed_protos; - } else { + } else if (dev->raw) { enabled = dev->raw->enabled_protocols; allowed = ir_raw_get_allowed_protocols(); - } + } else + return -ENODEV; IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", (long long)allowed, From 17361b3edc6e84fbbc996ad9bb350be41739f457 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 2 Jul 2012 18:51:38 +0100 Subject: [PATCH 1008/2357] pch_uart: Fix missing break for 16 byte fifo commit 9bc03743fff0770dc5a5324ba92e67cc377f16ca upstream. Otherwise we fall back to the wrong value. Reported-by: Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=44091 Signed-off-by: Alan Cox Signed-off-by: Tomoya MORINAGA Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index c2816f49480..44cf438356e 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1255,6 +1255,7 @@ static int pch_uart_startup(struct uart_port *port) break; case 16: fifo_size = PCH_UART_HAL_FIFO16; + break; case 1: default: fifo_size = PCH_UART_HAL_FIFO_DIS; From 439ec7b975d17a097414671ef2aaa6037448c3f6 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 6 Jul 2012 17:19:42 +0900 Subject: [PATCH 1009/2357] pch_uart: Fix rx error interrupt setting issue commit 9539dfb7ac1c84522fe1f79bb7dac2990f3de44a upstream. Rx Error interrupt(E.G. parity error) is not enabled. So, when parity error occurs, error interrupt is not occurred. As a result, the received data is not dropped. This patch adds enable/disable rx error interrupt code. Signed-off-by: Tomoya MORINAGA Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 44cf438356e..20001b749b2 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -754,7 +754,8 @@ static void pch_dma_rx_complete(void *arg) tty_flip_buffer_push(tty); tty_kref_put(tty); async_tx_ack(priv->desc_rx); - pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT); + pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); } static void pch_dma_tx_complete(void *arg) @@ -809,7 +810,8 @@ static int handle_rx_to(struct eg20t_port *priv) int rx_size; int ret; if (!priv->start_rx) { - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); return 0; } buf = &priv->rxbuf; @@ -1071,11 +1073,13 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) case PCH_UART_IID_RDR: /* Received Data Ready */ if (priv->use_dma) { pch_uart_hal_disable_interrupt(priv, - PCH_UART_HAL_RX_INT); + PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); ret = dma_handle_rx(priv); if (!ret) pch_uart_hal_enable_interrupt(priv, - PCH_UART_HAL_RX_INT); + PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); } else { ret = handle_rx(priv); } @@ -1199,7 +1203,8 @@ static void pch_uart_stop_rx(struct uart_port *port) struct eg20t_port *priv; priv = container_of(port, struct eg20t_port, port); priv->start_rx = 0; - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); priv->int_dis_flag = 1; } @@ -1293,7 +1298,8 @@ static int pch_uart_startup(struct uart_port *port) pch_request_dma(port); priv->start_rx = 1; - pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT); + pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); uart_update_timeout(port, CS8, default_baud); return 0; From 3dcb53637949c288a1ff2a06ee3c0a212ace6ef1 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 6 Jul 2012 17:19:43 +0900 Subject: [PATCH 1010/2357] pch_uart: Fix parity setting issue commit 38bd2a1ac736901d1cf4971c78ef952ba92ef78b upstream. Parity Setting value is reverse. E.G. In case of setting ODD parity, EVEN value is set. This patch inverts "if" condition. Signed-off-by: Tomoya MORINAGA Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 20001b749b2..103a25f77d1 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1357,7 +1357,7 @@ static void pch_uart_set_termios(struct uart_port *port, stb = PCH_UART_HAL_STB1; if (termios->c_cflag & PARENB) { - if (!(termios->c_cflag & PARODD)) + if (termios->c_cflag & PARODD) parity = PCH_UART_HAL_PARITY_ODD; else parity = PCH_UART_HAL_PARITY_EVEN; From e85f60c9fc3d5ecc66e6598c0e487aa5c4b7feeb Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 13 Jul 2012 14:28:42 -0500 Subject: [PATCH 1011/2357] powerpc/85xx: p1022ds: disable the NAND flash node if video is enabled commit 6269f2584a359766f53005c676daff8aee60cbed upstream. The Freescale P1022 has a unique pin muxing "feature" where the DIU video controller's video signals are muxed with 24 of the local bus address signals. When the DIU is enabled, the bulk of the local bus is disabled, preventing access to memory-mapped devices like NAND flash and the pixis FPGA. Therefore, if the DIU is going to be enabled, then memory-mapped devices on the localbus, like NAND flash, need to be disabled. This patch is similar to "powerpc/85xx: p1022ds: disable the NOR flash node if video is enabled", except that it disables the NAND flash node instead. This PIXIS node needs to remain enabled because it is used by platform code to switch into indirect mode. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/85xx/p1022_ds.c | 38 ++++++++++++++++++++------ 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 978330ccdde..f867ae42fae 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -435,6 +435,8 @@ static void __init disable_one_node(struct device_node *np, struct property *new prom_update_property(np, new, old); else prom_add_property(np, new); + + pr_info("p1022ds: disabling %s node\n", np->full_name); } /* TRUE if there is a "video=fslfb" command-line parameter. */ @@ -499,28 +501,46 @@ static void __init p1022_ds_setup_arch(void) diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; /* - * Disable the NOR flash node if there is video=fslfb... command-line - * parameter. When the DIU is active, NOR flash is unavailable, so we - * have to disable the node before the MTD driver loads. + * Disable the NOR and NAND flash nodes if there is video=fslfb... + * command-line parameter. When the DIU is active, the localbus is + * unavailable, so we have to disable these nodes before the MTD + * driver loads. */ if (fslfb) { struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); if (np) { - np = of_find_compatible_node(np, NULL, "cfi-flash"); - if (np) { + struct device_node *np2; + + of_node_get(np); + np2 = of_find_compatible_node(np, NULL, "cfi-flash"); + if (np2) { static struct property nor_status = { .name = "status", .value = "disabled", .length = sizeof("disabled"), }; - pr_info("p1022ds: disabling %s node", - np->full_name); - disable_one_node(np, &nor_status); - of_node_put(np); + disable_one_node(np2, &nor_status); + of_node_put(np2); + } + + of_node_get(np); + np2 = of_find_compatible_node(np, NULL, + "fsl,elbc-fcm-nand"); + if (np2) { + static struct property nand_status = { + .name = "status", + .value = "disabled", + .length = sizeof("disabled"), + }; + + disable_one_node(np2, &nand_status); + of_node_put(np2); } + + of_node_put(np); } } From cb2184097168d9ee97126d8284a501759f6d1367 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Mon, 23 Jul 2012 15:43:32 -0500 Subject: [PATCH 1012/2357] powerpc/85xx: p1022ds: fix DIU/LBC switching with NAND enabled commit 896c01cb4bb3cfc2c0ea9873fa7a9f8bd0a7c8d8 upstream. In order for indirect mode on the PIXIS to work properly, both chip selects need to be set to GPCM mode, otherwise writes to the chip select base addresses will not actually post to the local bus -- they'll go to the NAND controller instead. Therefore, we need to set BR0 and BR1 to GPCM mode before switching to indirect mode. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/85xx/p1022_ds.c | 64 +++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index f867ae42fae..f80887f40f0 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -208,6 +208,7 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) u8 __iomem *lbc_lcs0_ba = NULL; u8 __iomem *lbc_lcs1_ba = NULL; phys_addr_t cs0_addr, cs1_addr; + u32 br0, or0, br1, or1; const __be32 *iprop; unsigned int num_laws; u8 b; @@ -256,11 +257,70 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) } num_laws = be32_to_cpup(iprop); - cs0_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[0].br)); - cs1_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[1].br)); + /* + * Indirect mode requires both BR0 and BR1 to be set to "GPCM", + * otherwise writes to these addresses won't actually appear on the + * local bus, and so the PIXIS won't see them. + * + * In FCM mode, writes go to the NAND controller, which does not pass + * them to the localbus directly. So we force BR0 and BR1 into GPCM + * mode, since we don't care about what's behind the localbus any + * more. + */ + br0 = in_be32(&lbc->bank[0].br); + br1 = in_be32(&lbc->bank[1].br); + or0 = in_be32(&lbc->bank[0].or); + or1 = in_be32(&lbc->bank[1].or); + + /* Make sure CS0 and CS1 are programmed */ + if (!(br0 & BR_V) || !(br1 & BR_V)) { + pr_err("p1022ds: CS0 and/or CS1 is not programmed\n"); + goto exit; + } + + /* + * Use the existing BRx/ORx values if it's already GPCM. Otherwise, + * force the values to simple 32KB GPCM windows with the most + * conservative timing. + */ + if ((br0 & BR_MSEL) != BR_MS_GPCM) { + br0 = (br0 & BR_BA) | BR_V; + or0 = 0xFFFF8000 | 0xFF7; + out_be32(&lbc->bank[0].br, br0); + out_be32(&lbc->bank[0].or, or0); + } + if ((br1 & BR_MSEL) != BR_MS_GPCM) { + br1 = (br1 & BR_BA) | BR_V; + or1 = 0xFFFF8000 | 0xFF7; + out_be32(&lbc->bank[1].br, br1); + out_be32(&lbc->bank[1].or, or1); + } + + cs0_addr = lbc_br_to_phys(ecm, num_laws, br0); + if (!cs0_addr) { + pr_err("p1022ds: could not determine physical address for CS0" + " (BR0=%08x)\n", br0); + goto exit; + } + cs1_addr = lbc_br_to_phys(ecm, num_laws, br1); + if (!cs0_addr) { + pr_err("p1022ds: could not determine physical address for CS1" + " (BR1=%08x)\n", br1); + goto exit; + } lbc_lcs0_ba = ioremap(cs0_addr, 1); + if (!lbc_lcs0_ba) { + pr_err("p1022ds: could not ioremap CS0 address %llx\n", + (unsigned long long)cs0_addr); + goto exit; + } lbc_lcs1_ba = ioremap(cs1_addr, 1); + if (!lbc_lcs1_ba) { + pr_err("p1022ds: could not ioremap CS1 address %llx\n", + (unsigned long long)cs1_addr); + goto exit; + } /* Make sure we're in indirect mode first. */ if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != From 61df44523230af4f6aaeb4b0aa8131c74cc47ec3 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Tue, 19 Jun 2012 14:00:18 -0700 Subject: [PATCH 1013/2357] pch_uart: Add eg20t_port lock field, avoid recursive spinlocks commit 2588aba002d14e938c2f56d299ecf3e7ce1302a5 upstream. pch_uart_interrupt() takes priv->port.lock which leads to two recursive spinlock calls if low_latency==1 or CONFIG_PREEMPT_RT_FULL=y (one otherwise): pch_uart_interrupt spin_lock_irqsave(priv->port.lock, flags) case PCH_UART_IID_RDR_TO (data ready) handle_rx_to push_rx tty_port_tty_get spin_lock_irqsave(&port->lock, flags) <--- already hold this lock ... tty_flip_buffer_push ... flush_to_ldisc spin_lock_irqsave(&tty->buf.lock) spin_lock_irqsave(&tty->buf.lock) disc->ops->receive_buf(tty, char_buf) n_tty_receive_buf tty->ops->flush_chars() uart_flush_chars uart_start spin_lock_irqsave(&port->lock) <--- already hold this lock Avoid this by using a dedicated lock to protect the eg20t_port structure and IO access to its membase. This is more consistent with the 8250 driver. Ensure priv->lock is always take prior to priv->port.lock when taken at the same time. V2: Remove inadvertent whitespace change. V3: Account for oops_in_progress for the private lock in pch_console_write(). Note: Like the 8250 driver, if a printk is introduced anywhere inside the pch_console_write() critical section, the kernel will hang on a recursive spinlock on the private lock. The oops case is handled by using a trylock in the oops_in_progress case. Signed-off-by: Darren Hart CC: Tomoya MORINAGA CC: Feng Tang CC: Alexander Stein Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 38 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 103a25f77d1..7d4751474da 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -252,6 +252,9 @@ struct eg20t_port { dma_addr_t rx_buf_dma; struct dentry *debugfs; + + /* protect the eg20t_port private structure and io access to membase */ + spinlock_t lock; }; /** @@ -1058,7 +1061,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) unsigned int iid; unsigned long flags; - spin_lock_irqsave(&priv->port.lock, flags); + spin_lock_irqsave(&priv->lock, flags); handled = 0; while ((iid = pch_uart_hal_get_iid(priv)) > 1) { switch (iid) { @@ -1111,7 +1114,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) priv->int_dis_flag = 0; } - spin_unlock_irqrestore(&priv->port.lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); return IRQ_RETVAL(handled); } @@ -1223,9 +1226,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl) unsigned long flags; priv = container_of(port, struct eg20t_port, port); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&priv->lock, flags); pch_uart_hal_set_break(priv, ctl); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); } /* Grab any interrupt resources and initialise any low level driver state. */ @@ -1375,7 +1378,8 @@ static void pch_uart_set_termios(struct uart_port *port, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&priv->lock, flags); + spin_lock(&port->lock); uart_update_timeout(port, termios->c_cflag, baud); rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); @@ -1388,7 +1392,8 @@ static void pch_uart_set_termios(struct uart_port *port, tty_termios_encode_baud_rate(termios, baud, baud); out: - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock(&port->lock); + spin_unlock_irqrestore(&priv->lock, flags); } static const char *pch_uart_type(struct uart_port *port) @@ -1538,8 +1543,9 @@ pch_console_write(struct console *co, const char *s, unsigned int count) { struct eg20t_port *priv; unsigned long flags; + int priv_locked = 1; + int port_locked = 1; u8 ier; - int locked = 1; priv = pch_uart_ports[co->index]; @@ -1547,12 +1553,16 @@ pch_console_write(struct console *co, const char *s, unsigned int count) local_irq_save(flags); if (priv->port.sysrq) { - /* serial8250_handle_port() already took the lock */ - locked = 0; + spin_lock(&priv->lock); + /* serial8250_handle_port() already took the port lock */ + port_locked = 0; } else if (oops_in_progress) { - locked = spin_trylock(&priv->port.lock); - } else + priv_locked = spin_trylock(&priv->lock); + port_locked = spin_trylock(&priv->port.lock); + } else { + spin_lock(&priv->lock); spin_lock(&priv->port.lock); + } /* * First save the IER then disable the interrupts @@ -1570,8 +1580,10 @@ pch_console_write(struct console *co, const char *s, unsigned int count) wait_for_xmitr(priv, BOTH_EMPTY); iowrite8(ier, priv->membase + UART_IER); - if (locked) + if (port_locked) spin_unlock(&priv->port.lock); + if (priv_locked) + spin_unlock(&priv->lock); local_irq_restore(flags); } @@ -1669,6 +1681,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, pci_enable_msi(pdev); pci_set_master(pdev); + spin_lock_init(&priv->lock); + iobase = pci_resource_start(pdev, 0); mapbase = pci_resource_start(pdev, 1); priv->mapbase = mapbase; From 11cbc507a8451655bd0445a0ca8f9018ce8d20a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sat, 19 May 2012 07:20:31 +0000 Subject: [PATCH 1014/2357] net: qmi_wwan: Add Vodafone/Huawei K5005 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 88c16dc3bb61a1c1e9d4c78f45cc2107bc8d5249 upstream. Tested-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index c2ae4266617..4be2d7f9174 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -407,6 +407,14 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */ .driver_info = (unsigned long)&qmi_wwan_info, }, + { /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = HUAWEI_VENDOR_ID, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 56, /* NOTE: This is the *slave* interface of the CDC Union! */ + .driver_info = (unsigned long)&qmi_wwan_info, + }, { /* Huawei E392, E398 and possibly others in "Windows mode" * using a combined control and data interface without any CDC * functional descriptors From 4bf003851ca52d2b1cb6f96817f7fe335e1fd849 Mon Sep 17 00:00:00 2001 From: "Andrew Bird (Sphere Systems)" Date: Sat, 19 May 2012 22:28:37 +0000 Subject: [PATCH 1015/2357] USB: qmi_wwan: Add ZTE (Vodafone) K3765-Z MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8965c98fdebedce077257241957b205515dd1a5f upstream. Add the ZTE (Vodafone) K3765-Z to the whitelist. This requires the previous patch to make the whitelist with forced interface 4 generic or the device fails to initialise. After applying this patch and loading the Option driver without usb-modeswitch's bind all interfaces trick, a wwan0 net interface and /dev/cdc-wdm0 device file were created. Using Bjorn Mork's perl connection script a connection was made to a mobile network using QMI and the network interface's IPv4 address was configured OK. Signed-off-by: Andrew Bird Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 4be2d7f9174..6e06fbb20b3 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -480,6 +480,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K3765-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x2002, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int4, + }, { /* ZTE (Vodafone) K4505-Z */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, From bf5ebae622cc4b0df483488ec8648831705f6465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 23 May 2012 23:19:32 +0000 Subject: [PATCH 1016/2357] net: qmi_wwan: Add Sierra Wireless device IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5e071b5d1aa6928f8d695c15f52a949d70b8d7fb upstream. Some additional Gobi3K IDs found in the BSD/GPL licensed out-of-tree GobiNet driver from Sierra Wireless. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 6e06fbb20b3..739e56d305b 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -548,6 +548,8 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ + {QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ + {QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ { } /* END */ }; MODULE_DEVICE_TABLE(usb, products); From e7f558cc5068b40428b048d8e6e338fef29fd5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 5 Jul 2012 01:13:33 +0000 Subject: [PATCH 1017/2357] net: qmi_wwan: add ZTE MF60 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6fecd35d4cd79fc75e8290abb86734c18500d2a2 upstream. Adding a device with limited QMI support. It does not support normal QMI_WDS commands for connection management. Instead, sending a QMI_CTL SET_INSTANCE_ID command is required to enable the network interface: 01 0f 00 00 00 00 00 00 20 00 04 00 01 01 00 00 A number of QMI_DMS and QMI_NAS commands are also supported for optional device management. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 739e56d305b..f2df274103e 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -346,6 +346,15 @@ static const struct driver_info qmi_wwan_force_int1 = { .data = BIT(1), /* interface whitelist bitmap */ }; +static const struct driver_info qmi_wwan_force_int2 = { + .description = "Qualcomm WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_shared, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(2), /* interface whitelist bitmap */ +}; + static const struct driver_info qmi_wwan_force_int3 = { .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, @@ -498,6 +507,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE MF60 */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x1402, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int2, + }, { /* Sierra Wireless MC77xx in QMI mode */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x1199, From e7861ce75b60e23d4d0a0b08c6f20fb3dc236c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 12 Jul 2012 01:18:26 +0000 Subject: [PATCH 1018/2357] net: qmi_wwan: add ZTE MF821D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit db8dacf953a70274172236957a4b97d4fdb376f0 upstream. Sold by O2 (telefonica germany) under the name "LTE4G" Tested-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index f2df274103e..23378fb14ae 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -453,6 +453,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE MF821D */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x0326, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int4, + }, { /* ZTE (Vodafone) K3520-Z */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, From 8d3362715e0c0d29274b1689d87914e7c64f0032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 23 Aug 2012 12:13:57 +0200 Subject: [PATCH 1019/2357] net: qmi_wwan: add Sierra Wireless devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9b469a60d68b13c288d5c3fc23de29d9d482dbe6 upstream. Add 6 new devices and one modified device, based on information from laptop vendor Windows drivers. Sony provides a driver with two new devices using a Gobi 2k+ layout (1199:68a5 and 1199:68a9). The Sony driver also adds a non-standard QMI/net interface to the already supported 1199:9011 Gobi device. We do not know whether this is an alternate interface number or an additional interface which might be present, but that doesn't really matter. Lenovo provides a driver supporting 4 new devices: - MC7770 (1199:901b) with standard Gobi 2k+ layout - MC7700 (0f3d:68a2) with layout similar to MC7710 - MC7750 (114f:68a2) with layout similar to MC7710 - EM7700 (1199:901c) with layout similar to MC7710 Note regaring the three devices similar to MC7710: The Windows drivers only support interface #8 on these devices. The MC7710 can support QMI/net functions on interface #19 and #20 as well, and this driver is verified to work on interface #19 (a firmware bug is suspected to prevent #20 from working). We do not enable these additional interfaces until they either show up in a Windows driver or are verified to work in some other way. Therefore limiting the new devices to interface #8 for now. [bmork: backported to 3.4: use driver whitelisting] Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 23378fb14ae..b1c3740c9fd 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -534,6 +534,33 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_sierra, }, + { /* Sierra Wireless MC7700 */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0f3d, + .idProduct = 0x68a2, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_sierra, + }, + { /* Sierra Wireless MC7750 */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x114f, + .idProduct = 0x68a2, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_sierra, + }, + { /* Sierra Wireless EM7700 */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1199, + .idProduct = 0x901c, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_sierra, + }, /* Gobi 1000 devices */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ @@ -561,6 +588,8 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */ {QMI_GOBI_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */ {QMI_GOBI_DEVICE(0x05c6, 0x9275)}, /* iRex Technologies Gobi 2000 Modem device (VR307) */ + {QMI_GOBI_DEVICE(0x1199, 0x68a5)}, /* Sierra Wireless Modem */ + {QMI_GOBI_DEVICE(0x1199, 0x68a9)}, /* Sierra Wireless Modem */ {QMI_GOBI_DEVICE(0x1199, 0x9001)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ {QMI_GOBI_DEVICE(0x1199, 0x9002)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ {QMI_GOBI_DEVICE(0x1199, 0x9003)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ @@ -577,6 +606,8 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ {QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ + {QMI_GOBI_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */ + { } /* END */ }; MODULE_DEVICE_TABLE(usb, products); From 642550436c8b3a933550468996ef547630344a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 23 Aug 2012 12:13:58 +0200 Subject: [PATCH 1020/2357] net: qmi_wwan: new devices: UML290 and K5006-Z MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 10cbc1d97a7c7f9ae862fffe27b771ef0da9c461 upstream. Newer firmware versions for the Pantech UML290 use a different subclass ID. The Windows driver match on both IDs, so we do that as well. The ZTE (Vodafone) K5006-Z is a new device. Signed-off-by: Bjørn Mork Cc: Dan Williams Cc: Thomas Schäfer [bmork: backported to 3.4: use driver whitelisting] Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index b1c3740c9fd..8669c77fa7c 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -444,6 +444,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_shared, }, + { /* Pantech UML290 - newer firmware */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x106c, + .idProduct = 0x3718, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xf1, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_shared, + }, { /* ZTE MF820D */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, @@ -516,6 +525,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K5006-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x1018, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int3, + }, { /* ZTE MF60 */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, From 49194d4e7d8c14fb83f213c54a476685f8389c70 Mon Sep 17 00:00:00 2001 From: Satoru Moriya Date: Tue, 29 May 2012 15:06:47 -0700 Subject: [PATCH 1021/2357] mm: avoid swapping out with swappiness==0 commit fe35004fbf9eaf67482b074a2e032abb9c89b1dd upstream. Sometimes we'd like to avoid swapping out anonymous memory. In particular, avoid swapping out pages of important process or process groups while there is a reasonable amount of pagecache on RAM so that we can satisfy our customers' requirements. OTOH, we can control how aggressive the kernel will swap memory pages with /proc/sys/vm/swappiness for global and /sys/fs/cgroup/memory/memory.swappiness for each memcg. But with current reclaim implementation, the kernel may swap out even if we set swappiness=0 and there is pagecache in RAM. This patch changes the behavior with swappiness==0. If we set swappiness==0, the kernel does not swap out completely (for global reclaim until the amount of free pages and filebacked pages in a zone has been reduced to something very very small (nr_free + nr_filebacked < high watermark)). Signed-off-by: Satoru Moriya Acked-by: Minchan Kim Reviewed-by: Rik van Riel Acked-by: Jerome Marchand Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/vmscan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index be5bc0af2e7..e989ee22f10 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1983,10 +1983,10 @@ static void get_scan_count(struct mem_cgroup_zone *mz, struct scan_control *sc, * proportional to the fraction of recently scanned pages on * each list that were recently referenced and in active use. */ - ap = (anon_prio + 1) * (reclaim_stat->recent_scanned[0] + 1); + ap = anon_prio * (reclaim_stat->recent_scanned[0] + 1); ap /= reclaim_stat->recent_rotated[0] + 1; - fp = (file_prio + 1) * (reclaim_stat->recent_scanned[1] + 1); + fp = file_prio * (reclaim_stat->recent_scanned[1] + 1); fp /= reclaim_stat->recent_rotated[1] + 1; spin_unlock_irq(&mz->zone->lru_lock); @@ -1999,7 +1999,7 @@ static void get_scan_count(struct mem_cgroup_zone *mz, struct scan_control *sc, unsigned long scan; scan = zone_nr_lru_pages(mz, lru); - if (priority || noswap) { + if (priority || noswap || !vmscan_swappiness(mz, sc)) { scan >>= priority; if (!scan && force_scan) scan = SWAP_CLUSTER_MAX; From 77d13a088343c507a8d5bb924abc730c603f1f6b Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Wed, 8 Aug 2012 08:27:03 -0500 Subject: [PATCH 1022/2357] irq_remap: disable IRQ remapping if any IOAPIC lacks an IOMMU commit 32ab31e01e2def6f48294d872d9bb42573aae00f upstream. The ACPI tables in the Macbook Air 5,1 define a single IOAPIC with id 2, but the only remapping unit described in the DMAR table matches id 0. Interrupt remapping fails as a result, and the kernel panics with the message "timer doesn't work through Interrupt-remapped IO-APIC." To fix this, check each IOAPIC for a corresponding IOMMU. If an IOMMU is not found, do not allow IRQ remapping to be enabled. v2: Move check to parse_ioapics_under_ir(), raise log level to KERN_ERR, and add FW_BUG to the log message v3: Skip check if IOMMU doesn't support interrupt remapping and remove existing check that the IOMMU count equals the IOAPIC count Acked-by: Suresh Siddha Signed-off-by: Seth Forshee Acked-by: Yinghai Lu Signed-off-by: Joerg Roedel Acked-by: Cho, Yu-Chen Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intr_remapping.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/intr_remapping.c b/drivers/iommu/intr_remapping.c index 6777ca04947..73ca321f330 100644 --- a/drivers/iommu/intr_remapping.c +++ b/drivers/iommu/intr_remapping.c @@ -752,6 +752,7 @@ int __init parse_ioapics_under_ir(void) { struct dmar_drhd_unit *drhd; int ir_supported = 0; + int ioapic_idx; for_each_drhd_unit(drhd) { struct intel_iommu *iommu = drhd->iommu; @@ -764,13 +765,20 @@ int __init parse_ioapics_under_ir(void) } } - if (ir_supported && ir_ioapic_num != nr_ioapics) { - printk(KERN_WARNING - "Not all IO-APIC's listed under remapping hardware\n"); - return -1; + if (!ir_supported) + return 0; + + for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) { + int ioapic_id = mpc_ioapic_id(ioapic_idx); + if (!map_ioapic_to_ir(ioapic_id)) { + pr_err(FW_BUG "ioapic %d has no mapping iommu, " + "interrupt remapping will be disabled\n", + ioapic_id); + return -1; + } } - return ir_supported; + return 1; } int __init ir_dev_scope_init(void) From 1d22d5660b961c6b36fa361e1e394f64b068c763 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 12 Sep 2012 09:05:22 +0200 Subject: [PATCH 1023/2357] UBI: fix a horrible memory deallocation bug commit 78b495c39add820ab66ab897af9bd77a5f2e91f6 upstream UBI was mistakingly using 'kfree()' instead of 'kmem_cache_free()' when freeing "attach eraseblock" structures in vtbl.c. Thankfully, this happened only when we were doing auto-format, so many systems were unaffected. However, there are still many users affected. It is strange, but the system did not crash and nothing bad happened when the SLUB memory allocator was used. However, in case of SLOB we observed an crash right away. This problem was introduced in 2.6.39 by commit "6c1e875 UBI: add slab cache for ubi_scan_leb objects" Reported-by: Richard Genoud Signed-off-by: Artem Bityutskiy Signed-off-by: Richard Genoud Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/vtbl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 17cec0c0154..c015fc0a76d 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -346,7 +346,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si, */ err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec, vid_hdr, 0); - kfree(new_seb); + kmem_cache_free(si->scan_leb_slab, new_seb); ubi_free_vid_hdr(ubi, vid_hdr); return err; @@ -359,7 +359,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si, list_add(&new_seb->u.list, &si->erase); goto retry; } - kfree(new_seb); + kmem_cache_free(si->scan_leb_slab, new_seb); out_free: ubi_free_vid_hdr(ubi, vid_hdr); return err; From 6a4ebdb6be2ac2ad0e03ca9131573a1f0eadd7d5 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 3 Jul 2012 16:46:41 +0400 Subject: [PATCH 1024/2357] NFSd: introduce nfsd_destroy() helper commit 19f7e2ca44dfc3c1b3f499fc46801f98d403500f upstream. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfsctl.c | 8 ++------ fs/nfsd/nfsd.h | 9 +++++++++ fs/nfsd/nfssvc.c | 14 +++----------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 3ab12eb2967..d014727fc8f 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -663,9 +663,7 @@ static ssize_t __write_ports_addfd(char *buf) err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); if (err < 0) { - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); + nfsd_destroy(net); return err; } @@ -734,9 +732,7 @@ static ssize_t __write_ports_addxprt(char *buf) svc_xprt_put(xprt); } out_err: - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); + nfsd_destroy(net); return err; } diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 1671429ffa6..e3339ca2b65 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -73,6 +73,15 @@ int nfsd_nrpools(void); int nfsd_get_nrthreads(int n, int *); int nfsd_set_nrthreads(int n, int *); +static inline void nfsd_destroy(struct net *net) +{ + int destroy = (nfsd_serv->sv_nrthreads == 1); + + if (destroy) + svc_shutdown_net(nfsd_serv, net); + svc_destroy(nfsd_serv); +} + #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) #ifdef CONFIG_NFSD_V2_ACL extern struct svc_version nfsd_acl_version2; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index bcda12a3f08..a7042fc1b09 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -427,11 +427,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) if (err) break; } - - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); - + nfsd_destroy(net); return err; } @@ -478,9 +474,7 @@ nfsd_svc(unsigned short port, int nrservs) if (error < 0 && !nfsd_up_before) nfsd_shutdown(); out_destroy: - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); /* Release server */ + nfsd_destroy(net); /* Release server */ out: mutex_unlock(&nfsd_mutex); return error; @@ -682,9 +676,7 @@ int nfsd_pool_stats_release(struct inode *inode, struct file *file) mutex_lock(&nfsd_mutex); /* this function really, really should have been called svc_put() */ - if (nfsd_serv->sv_nrthreads == 1) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); + nfsd_destroy(net); mutex_unlock(&nfsd_mutex); return ret; } From c717dcaf750cd0a43609d8c2016a380e542b28ed Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 3 Jul 2012 16:46:41 +0400 Subject: [PATCH 1025/2357] NFSd: set nfsd_serv to NULL after service destruction commit 57c8b13e3cd0f94944c9691ce7f58e5fcef8a12d upstream. In nfsd_destroy(): if (destroy) svc_shutdown_net(nfsd_serv, net); svc_destroy(nfsd_server); svc_shutdown_net(nfsd_serv, net) calls nfsd_last_thread(), which sets nfsd_serv to NULL, causing a NULL dereference on the following line. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfsd.h | 2 ++ fs/nfsd/nfssvc.c | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index e3339ca2b65..1336a6512cd 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -80,6 +80,8 @@ static inline void nfsd_destroy(struct net *net) if (destroy) svc_shutdown_net(nfsd_serv, net); svc_destroy(nfsd_serv); + if (destroy) + nfsd_serv = NULL; } #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index a7042fc1b09..b6f8e65f85b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -254,8 +254,6 @@ static void nfsd_shutdown(void) static void nfsd_last_thread(struct svc_serv *serv, struct net *net) { - /* When last nfsd thread exits we need to do some clean-up */ - nfsd_serv = NULL; nfsd_shutdown(); svc_rpcb_cleanup(serv, net); @@ -332,6 +330,7 @@ static int nfsd_get_default_max_blksize(void) int nfsd_create_serv(void) { int error; + struct net *net = current->nsproxy->net_ns; WARN_ON(!mutex_is_locked(&nfsd_mutex)); if (nfsd_serv) { @@ -346,7 +345,7 @@ int nfsd_create_serv(void) if (nfsd_serv == NULL) return -ENOMEM; - error = svc_bind(nfsd_serv, current->nsproxy->net_ns); + error = svc_bind(nfsd_serv, net); if (error < 0) { svc_destroy(nfsd_serv); return error; @@ -557,12 +556,13 @@ nfsd(void *vrqstp) nfsdstats.th_cnt --; out: - if (rqstp->rq_server->sv_nrthreads == 1) - svc_shutdown_net(rqstp->rq_server, &init_net); + rqstp->rq_server = NULL; /* Release the thread */ svc_exit_thread(rqstp); + nfsd_destroy(&init_net); + /* Release module */ mutex_unlock(&nfsd_mutex); module_put_and_exit(0); From 34b6567e91b3ff6209c16b3868ec95e0e1cddc1f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 19 Jul 2012 13:52:53 -0700 Subject: [PATCH 1026/2357] kthread_worker: reorganize to prepare for flush_kthread_work() reimplementation commit 9a2e03d8ed518a61154f18d83d6466628e519f94 upstream. Make the following two non-functional changes. * Separate out insert_kthread_work() from queue_kthread_work(). * Relocate struct kthread_flush_work and kthread_flush_work_fn() definitions above flush_kthread_work(). v2: Added lockdep_assert_held() in insert_kthread_work() as suggested by Andy Walls. Signed-off-by: Tejun Heo Acked-by: Andy Walls Cc: Colin Cross Signed-off-by: Greg Kroah-Hartman --- kernel/kthread.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/kernel/kthread.c b/kernel/kthread.c index 3d3de633702..4bfbff36d44 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -378,6 +378,19 @@ int kthread_worker_fn(void *worker_ptr) } EXPORT_SYMBOL_GPL(kthread_worker_fn); +/* insert @work before @pos in @worker */ +static void insert_kthread_work(struct kthread_worker *worker, + struct kthread_work *work, + struct list_head *pos) +{ + lockdep_assert_held(&worker->lock); + + list_add_tail(&work->node, pos); + work->queue_seq++; + if (likely(worker->task)) + wake_up_process(worker->task); +} + /** * queue_kthread_work - queue a kthread_work * @worker: target kthread_worker @@ -395,10 +408,7 @@ bool queue_kthread_work(struct kthread_worker *worker, spin_lock_irqsave(&worker->lock, flags); if (list_empty(&work->node)) { - list_add_tail(&work->node, &worker->work_list); - work->queue_seq++; - if (likely(worker->task)) - wake_up_process(worker->task); + insert_kthread_work(worker, work, &worker->work_list); ret = true; } spin_unlock_irqrestore(&worker->lock, flags); @@ -406,6 +416,18 @@ bool queue_kthread_work(struct kthread_worker *worker, } EXPORT_SYMBOL_GPL(queue_kthread_work); +struct kthread_flush_work { + struct kthread_work work; + struct completion done; +}; + +static void kthread_flush_work_fn(struct kthread_work *work) +{ + struct kthread_flush_work *fwork = + container_of(work, struct kthread_flush_work, work); + complete(&fwork->done); +} + /** * flush_kthread_work - flush a kthread_work * @work: work to flush @@ -436,18 +458,6 @@ void flush_kthread_work(struct kthread_work *work) } EXPORT_SYMBOL_GPL(flush_kthread_work); -struct kthread_flush_work { - struct kthread_work work; - struct completion done; -}; - -static void kthread_flush_work_fn(struct kthread_work *work) -{ - struct kthread_flush_work *fwork = - container_of(work, struct kthread_flush_work, work); - complete(&fwork->done); -} - /** * flush_kthread_worker - flush all current works on a kthread_worker * @worker: worker to flush From 97ed537eaa6ff11c9a1df342364e25d0996bc117 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 19 Jul 2012 13:52:53 -0700 Subject: [PATCH 1027/2357] kthread_worker: reimplement flush_kthread_work() to allow freeing the work item being executed commit 46f3d976213452350f9d10b0c2780c2681f7075b upstream. kthread_worker provides minimalistic workqueue-like interface for users which need a dedicated worker thread (e.g. for realtime priority). It has basic queue, flush_work, flush_worker operations which mostly match the workqueue counterparts; however, due to the way flush_work() is implemented, it has a noticeable difference of not allowing work items to be freed while being executed. While the current users of kthread_worker are okay with the current behavior, the restriction does impede some valid use cases. Also, removing this difference isn't difficult and actually makes the code easier to understand. This patch reimplements flush_kthread_work() such that it uses a flush_work item instead of queue/done sequence numbers. Signed-off-by: Tejun Heo Cc: Colin Cross Signed-off-by: Greg Kroah-Hartman --- include/linux/kthread.h | 8 ++----- kernel/kthread.c | 48 +++++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/include/linux/kthread.h b/include/linux/kthread.h index 0714b24c0e4..22ccf9dee17 100644 --- a/include/linux/kthread.h +++ b/include/linux/kthread.h @@ -49,8 +49,6 @@ extern int tsk_fork_get_node(struct task_struct *tsk); * can be queued and flushed using queue/flush_kthread_work() * respectively. Queued kthread_works are processed by a kthread * running kthread_worker_fn(). - * - * A kthread_work can't be freed while it is executing. */ struct kthread_work; typedef void (*kthread_work_func_t)(struct kthread_work *work); @@ -59,15 +57,14 @@ struct kthread_worker { spinlock_t lock; struct list_head work_list; struct task_struct *task; + struct kthread_work *current_work; }; struct kthread_work { struct list_head node; kthread_work_func_t func; wait_queue_head_t done; - atomic_t flushing; - int queue_seq; - int done_seq; + struct kthread_worker *worker; }; #define KTHREAD_WORKER_INIT(worker) { \ @@ -79,7 +76,6 @@ struct kthread_work { .node = LIST_HEAD_INIT((work).node), \ .func = (fn), \ .done = __WAIT_QUEUE_HEAD_INITIALIZER((work).done), \ - .flushing = ATOMIC_INIT(0), \ } #define DEFINE_KTHREAD_WORKER(worker) \ diff --git a/kernel/kthread.c b/kernel/kthread.c index 4bfbff36d44..b579af57ea1 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -360,16 +360,12 @@ int kthread_worker_fn(void *worker_ptr) struct kthread_work, node); list_del_init(&work->node); } + worker->current_work = work; spin_unlock_irq(&worker->lock); if (work) { __set_current_state(TASK_RUNNING); work->func(work); - smp_wmb(); /* wmb worker-b0 paired with flush-b1 */ - work->done_seq = work->queue_seq; - smp_mb(); /* mb worker-b1 paired with flush-b0 */ - if (atomic_read(&work->flushing)) - wake_up_all(&work->done); } else if (!freezing(current)) schedule(); @@ -386,7 +382,7 @@ static void insert_kthread_work(struct kthread_worker *worker, lockdep_assert_held(&worker->lock); list_add_tail(&work->node, pos); - work->queue_seq++; + work->worker = worker; if (likely(worker->task)) wake_up_process(worker->task); } @@ -436,25 +432,35 @@ static void kthread_flush_work_fn(struct kthread_work *work) */ void flush_kthread_work(struct kthread_work *work) { - int seq = work->queue_seq; + struct kthread_flush_work fwork = { + KTHREAD_WORK_INIT(fwork.work, kthread_flush_work_fn), + COMPLETION_INITIALIZER_ONSTACK(fwork.done), + }; + struct kthread_worker *worker; + bool noop = false; + +retry: + worker = work->worker; + if (!worker) + return; - atomic_inc(&work->flushing); + spin_lock_irq(&worker->lock); + if (work->worker != worker) { + spin_unlock_irq(&worker->lock); + goto retry; + } - /* - * mb flush-b0 paired with worker-b1, to make sure either - * worker sees the above increment or we see done_seq update. - */ - smp_mb__after_atomic_inc(); + if (!list_empty(&work->node)) + insert_kthread_work(worker, &fwork.work, work->node.next); + else if (worker->current_work == work) + insert_kthread_work(worker, &fwork.work, worker->work_list.next); + else + noop = true; - /* A - B <= 0 tests whether B is in front of A regardless of overflow */ - wait_event(work->done, seq - work->done_seq <= 0); - atomic_dec(&work->flushing); + spin_unlock_irq(&worker->lock); - /* - * rmb flush-b1 paired with worker-b0, to make sure our caller - * sees every change made by work->func(). - */ - smp_mb__after_atomic_dec(); + if (!noop) + wait_for_completion(&fwork.done); } EXPORT_SYMBOL_GPL(flush_kthread_work); From feab18eb28ec4c93c0762b7407b616d19ab9ad8b Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 25 Apr 2012 18:22:40 +0400 Subject: [PATCH 1028/2357] LockD: pass service to per-net up and down functions commit 4db77695bf5738bdafa83d1b58b64cbecc6f55e7 upstream. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields Cc: Jason Wessel Signed-off-by: Greg Kroah-Hartman --- fs/lockd/svc.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 3250f280a17..58ddc38cfcc 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -251,10 +251,9 @@ static int make_socks(struct svc_serv *serv, struct net *net) return err; } -static int lockd_up_net(struct net *net) +static int lockd_up_net(struct svc_serv *serv, struct net *net) { struct lockd_net *ln = net_generic(net, lockd_net_id); - struct svc_serv *serv = nlmsvc_rqst->rq_server; int error; if (ln->nlmsvc_users++) @@ -276,10 +275,9 @@ static int lockd_up_net(struct net *net) return error; } -static void lockd_down_net(struct net *net) +static void lockd_down_net(struct svc_serv *serv, struct net *net) { struct lockd_net *ln = net_generic(net, lockd_net_id); - struct svc_serv *serv = nlmsvc_rqst->rq_server; if (ln->nlmsvc_users) { if (--ln->nlmsvc_users == 0) { @@ -307,7 +305,7 @@ int lockd_up(struct net *net) * Check whether we're already up and running. */ if (nlmsvc_rqst) { - error = lockd_up_net(net); + error = lockd_up_net(nlmsvc_rqst->rq_server, net); goto out; } @@ -378,7 +376,7 @@ int lockd_up(struct net *net) return error; err_start: - lockd_down_net(net); + lockd_down_net(serv, net); goto destroy_and_out; } EXPORT_SYMBOL_GPL(lockd_up); @@ -390,7 +388,7 @@ void lockd_down(struct net *net) { mutex_lock(&nlmsvc_mutex); - lockd_down_net(net); + lockd_down_net(nlmsvc_rqst->rq_server, net); if (nlmsvc_users) { if (--nlmsvc_users) goto out; From 0f36cbb3364497fce45f40f295847f2de7cceeb7 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sun, 23 Sep 2012 22:56:00 +0200 Subject: [PATCH 1029/2357] USB: ohci-at91: fix null pointer in ohci_hcd_at91_overcurrent_irq commit 01bb6501779ed0b6dc6c55be34b49eaa6306fdd8 upstream. Fixes the following NULL pointer dereference: [ 7.740000] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver [ 7.810000] Unable to handle kernel NULL pointer dereference at virtual address 00000028 [ 7.810000] pgd = c3a38000 [ 7.810000] [00000028] *pgd=23a8c831, *pte=00000000, *ppte=00000000 [ 7.810000] Internal error: Oops: 17 [#1] PREEMPT ARM [ 7.810000] Modules linked in: ohci_hcd(+) regmap_i2c snd_pcm usbcore snd_page_alloc at91_cf snd_timer pcmcia_rsrc snd soundcore gpio_keys regmap_spi pcmcia_core usb_common nls_base [ 7.810000] CPU: 0 Not tainted (3.6.0-rc6-mpa+ #264) [ 7.810000] PC is at __gpio_to_irq+0x18/0x40 [ 7.810000] LR is at ohci_hcd_at91_overcurrent_irq+0x24/0xb4 [ohci_hcd] [ 7.810000] pc : [] lr : [] psr: 40000093 [ 7.810000] sp : c3a11c40 ip : c3a11c50 fp : c3a11c4c [ 7.810000] r10: 00000000 r9 : c02dcd6e r8 : fefff400 [ 7.810000] r7 : 00000000 r6 : c02cc928 r5 : 00000030 r4 : c02dd168 [ 7.810000] r3 : c02e7350 r2 : ffffffea r1 : c02cc928 r0 : 00000000 [ 7.810000] Flags: nZcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user [ 7.810000] Control: c000717f Table: 23a38000 DAC: 00000015 [ 7.810000] Process modprobe (pid: 285, stack limit = 0xc3a10270) [ 7.810000] Stack: (0xc3a11c40 to 0xc3a12000) [ 7.810000] 1c40: c3a11c6c c3a11c50 bf08f694 c01392cc c3a11c84 c2c38b00 c3806900 00000030 [ 7.810000] 1c60: c3a11ca4 c3a11c70 c0051264 bf08f680 c3a11cac c3a11c80 c003e764 c3806900 [ 7.810000] 1c80: c2c38b00 c02cb05c c02cb000 fefff400 c3806930 c3a11cf4 c3a11cbc c3a11ca8 [ 7.810000] 1ca0: c005142c c005123c c3806900 c3805a00 c3a11cd4 c3a11cc0 c0053f24 c00513e4 [ 7.810000] 1cc0: c3a11cf4 00000030 c3a11cec c3a11cd8 c005120c c0053e88 00000000 00000000 [ 7.810000] 1ce0: c3a11d1c c3a11cf0 c00124d0 c00511e0 01400000 00000001 00000012 00000000 [ 7.810000] 1d00: ffffffff c3a11d94 00000030 00000000 c3a11d34 c3a11d20 c005120c c0012438 [ 7.810000] 1d20: c001dac4 00000012 c3a11d4c c3a11d38 c0009b08 c00511e0 c00523fc 60000013 [ 7.810000] 1d40: c3a11d5c c3a11d50 c0008510 c0009ab4 c3a11ddc c3a11d60 c0008eb4 c00084f0 [ 7.810000] 1d60: 00000000 00000030 00000000 00000080 60000013 bf08f670 c3806900 c2c38b00 [ 7.810000] 1d80: 00000030 c3806930 00000000 c3a11ddc c3a11d88 c3a11da8 c0054190 c00523fc [ 7.810000] 1da0: 60000013 ffffffff c3a11dec c3a11db8 00000000 c2c38b00 bf08f670 c3806900 [ 7.810000] 1dc0: 00000000 00000080 c02cc928 00000030 c3a11e0c c3a11de0 c0052764 c00520d8 [ 7.810000] 1de0: c3a11dfc 00000000 00000000 00000002 bf090f61 00000004 c02cc930 c02cc928 [ 7.810000] 1e00: c3a11e4c c3a11e10 bf090978 c005269c bf090f61 c02cc928 bf093000 c02dd170 [ 7.810000] 1e20: c3a11e3c c02cc930 c02cc930 bf0911d0 bf0911d0 bf093000 c3a10000 00000000 [ 7.810000] 1e40: c3a11e5c c3a11e50 c0155b7c bf090808 c3a11e7c c3a11e60 c0154690 c0155b6c [ 7.810000] 1e60: c02cc930 c02cc964 bf0911d0 c3a11ea0 c3a11e9c c3a11e80 c015484c c01545e8 [ 7.810000] 1e80: 00000000 00000000 c01547e4 bf0911d0 c3a11ec4 c3a11ea0 c0152e58 c01547f4 [ 7.810000] 1ea0: c381b88c c384ab10 c2c10540 bf0911d0 00000000 c02d7518 c3a11ed4 c3a11ec8 [ 7.810000] 1ec0: c01544c0 c0152e0c c3a11efc c3a11ed8 c01536cc c01544b0 bf091075 c3a11ee8 [ 7.810000] 1ee0: bf049af0 bf09120c bf0911d0 00000000 c3a11f1c c3a11f00 c0154e9c c0153628 [ 7.810000] 1f00: bf049af0 bf09120c 000ae190 00000000 c3a11f2c c3a11f20 c0155f58 c0154e04 [ 7.810000] 1f20: c3a11f44 c3a11f30 bf093054 c0155f1c 00000000 00006a4f c3a11f7c c3a11f48 [ 7.810000] 1f40: c0008638 bf093010 bf09120c 000ae190 00000000 c00093c4 00006a4f bf09120c [ 7.810000] 1f60: 000ae190 00000000 c00093c4 00000000 c3a11fa4 c3a11f80 c004fdc4 c000859c [ 7.810000] 1f80: c3a11fa4 000ae190 00006a4f 00016eb8 000ad018 00000080 00000000 c3a11fa8 [ 7.810000] 1fa0: c0009260 c004fd58 00006a4f 00016eb8 000ae190 00006a4f 000ae100 00000000 [ 7.810000] 1fc0: 00006a4f 00016eb8 000ad018 00000080 000adba0 000ad208 00000000 000ad3d8 [ 7.810000] 1fe0: beaf7ae8 beaf7ad8 000172b8 b6e4e940 20000010 000ae190 00000000 00000000 [ 7.810000] Backtrace: [ 7.810000] [] (__gpio_to_irq+0x0/0x40) from [] (ohci_hcd_at91_overcurrent_irq+0x24/0xb4 [ohci_hcd]) [ 7.810000] [] (ohci_hcd_at91_overcurrent_irq+0x0/0xb4 [ohci_hcd]) from [] (handle_irq_event_percpu+0x38/0x1a8) [ 7.810000] r6:00000030 r5:c3806900 r4:c2c38b00 [ 7.810000] [] (handle_irq_event_percpu+0x0/0x1a8) from [] (handle_irq_event+0x58/0x7c) [ 7.810000] [] (handle_irq_event+0x0/0x7c) from [] (handle_simple_irq+0xac/0xd8) [ 7.810000] r5:c3805a00 r4:c3806900 [ 7.810000] [] (handle_simple_irq+0x0/0xd8) from [] (generic_handle_irq+0x3c/0x48) [ 7.810000] r4:00000030 [ 7.810000] [] (generic_handle_irq+0x0/0x48) from [] (gpio_irq_handler+0xa8/0xfc) [ 7.810000] r4:00000000 [ 7.810000] [] (gpio_irq_handler+0x0/0xfc) from [] (generic_handle_irq+0x3c/0x48) [ 7.810000] [] (generic_handle_irq+0x0/0x48) from [] (handle_IRQ+0x64/0x88) [ 7.810000] r4:00000012 [ 7.810000] [] (handle_IRQ+0x0/0x88) from [] (at91_aic_handle_irq+0x30/0x38) [ 7.810000] r5:60000013 r4:c00523fc [ 7.810000] [] (at91_aic_handle_irq+0x0/0x38) from [] (__irq_svc+0x34/0x60) [ 7.810000] Exception stack(0xc3a11d60 to 0xc3a11da8) [ 7.810000] 1d60: 00000000 00000030 00000000 00000080 60000013 bf08f670 c3806900 c2c38b00 [ 7.810000] 1d80: 00000030 c3806930 00000000 c3a11ddc c3a11d88 c3a11da8 c0054190 c00523fc [ 7.810000] 1da0: 60000013 ffffffff [ 7.810000] [] (__setup_irq+0x0/0x458) from [] (request_threaded_irq+0xd8/0x134) [ 7.810000] [] (request_threaded_irq+0x0/0x134) from [] (ohci_hcd_at91_drv_probe+0x180/0x41c [ohci_hcd]) [ 7.810000] [] (ohci_hcd_at91_drv_probe+0x0/0x41c [ohci_hcd]) from [] (platform_drv_probe+0x20/0x24) [ 7.810000] [] (platform_drv_probe+0x0/0x24) from [] (driver_probe_device+0xb8/0x20c) [ 7.810000] [] (driver_probe_device+0x0/0x20c) from [] (__driver_attach+0x68/0x88) [ 7.810000] r7:c3a11ea0 r6:bf0911d0 r5:c02cc964 r4:c02cc930 [ 7.810000] [] (__driver_attach+0x0/0x88) from [] (bus_for_each_dev+0x5c/0x9c) [ 7.810000] r6:bf0911d0 r5:c01547e4 r4:00000000 [ 7.810000] [] (bus_for_each_dev+0x0/0x9c) from [] (driver_attach+0x20/0x28) [ 7.810000] r7:c02d7518 r6:00000000 r5:bf0911d0 r4:c2c10540 [ 7.810000] [] (driver_attach+0x0/0x28) from [] (bus_add_driver+0xb4/0x22c) [ 7.810000] [] (bus_add_driver+0x0/0x22c) from [] (driver_register+0xa8/0x144) [ 7.810000] r7:00000000 r6:bf0911d0 r5:bf09120c r4:bf049af0 [ 7.810000] [] (driver_register+0x0/0x144) from [] (platform_driver_register+0x4c/0x60) [ 7.810000] r7:00000000 r6:000ae190 r5:bf09120c r4:bf049af0 [ 7.810000] [] (platform_driver_register+0x0/0x60) from [] (ohci_hcd_mod_init+0x54/0x8c [ohci_hcd]) [ 7.810000] [] (ohci_hcd_mod_init+0x0/0x8c [ohci_hcd]) from [] (do_one_initcall+0xac/0x174) [ 7.810000] r4:00006a4f [ 7.810000] [] (do_one_initcall+0x0/0x174) from [] (sys_init_module+0x7c/0x1a0) [ 7.810000] [] (sys_init_module+0x0/0x1a0) from [] (ret_fast_syscall+0x0/0x2c) [ 7.810000] r7:00000080 r6:000ad018 r5:00016eb8 r4:00006a4f [ 7.810000] Code: e24cb004 e59f3028 e1a02000 e7930180 (e5903028) [ 7.810000] ---[ end trace 85aa37ed128143b5 ]--- [ 7.810000] Kernel panic - not syncing: Fatal exception in interrupt Commit 6fffb77c (USB: ohci-at91: fix PIO handling in relation with number of ports) started setting unused pins to EINVAL. But this exposed a bug in the ohci_hcd_at91_overcurrent_irq function where the gpio was used without being checked to see if it is valid. This patches fixed the issue by adding the gpio valid check. Signed-off-by: Joachim Eastwood Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 50bd3f1e330..7841b0aa407 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -466,7 +466,8 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) /* From the GPIO notifying the over-current situation, find * out the corresponding port */ at91_for_each_port(port) { - if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) { + if (gpio_is_valid(pdata->overcurrent_pin[port]) && + gpio_to_irq(pdata->overcurrent_pin[port]) == irq) { gpio = pdata->overcurrent_pin[port]; break; } From 1437cb571cacaf18ce2da7dd8c858fac57806d37 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 26 Sep 2012 13:09:53 -0400 Subject: [PATCH 1030/2357] USB: Fix race condition when removing host controllers commit 0d00dc2611abbe6ad244d50569c2ee82ce42846c upstream. This patch (as1607) fixes a race that can occur if a USB host controller is removed while a process is reading the /sys/kernel/debug/usb/devices file. The usb_device_read() routine uses the bus->root_hub pointer to determine whether or not the root hub is registered. The is not a valid test, because the pointer is set before the root hub gets registered and remains set even after the root hub is unregistered and deallocated. As a result, usb_device_read() or usb_device_dump() can access freed memory, causing an oops. The patch changes the test to use the hcd->rh_registered flag, which does get set and cleared at the appropriate times. It also makes sure to hold the usb_bus_list_lock mutex while setting the flag, so that usb_device_read() will become aware of new root hubs as soon as they are registered. Signed-off-by: Alan Stern Reported-by: Don Zickus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devices.c | 2 +- drivers/usb/core/hcd.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index d9569658476..3440812b4a8 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -624,7 +624,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, /* print devices for all busses */ list_for_each_entry(bus, &usb_bus_list, bus_list) { /* recurse through all children of the root hub */ - if (!bus->root_hub) + if (!bus_to_hcd(bus)->rh_registered) continue; usb_lock_device(bus->root_hub); ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 140d3e11f21..e2cc8df3d87 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1002,10 +1002,7 @@ static int register_root_hub(struct usb_hcd *hcd) if (retval) { dev_err (parent_dev, "can't register root hub for %s, %d\n", dev_name(&usb_dev->dev), retval); - } - mutex_unlock(&usb_bus_list_lock); - - if (retval == 0) { + } else { spin_lock_irq (&hcd_root_hub_lock); hcd->rh_registered = 1; spin_unlock_irq (&hcd_root_hub_lock); @@ -1014,6 +1011,7 @@ static int register_root_hub(struct usb_hcd *hcd) if (HCD_DEAD(hcd)) usb_hc_died (hcd); /* This time clean up */ } + mutex_unlock(&usb_bus_list_lock); return retval; } From d20ff72cdeb4cbb586a1ee1a3f4f1bbade52414a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Sep 2012 11:57:30 +0100 Subject: [PATCH 1031/2357] ASoC: wm2000: Correct register size commit d0e12f3ff3472cbd8f52d3c0e6ee07a841787c40 upstream. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm2000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index a75c3766aed..ae6f26f25a6 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -692,7 +692,7 @@ static int wm2000_resume(struct snd_soc_codec *codec) #endif static const struct regmap_config wm2000_regmap = { - .reg_bits = 8, + .reg_bits = 16, .val_bits = 8, }; From 66801463734e49416a9b013d3eb8f9eb8cd851e0 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Thu, 20 Sep 2012 10:48:03 +0200 Subject: [PATCH 1032/2357] gpio-lpc32xx: Fix value handling of gpio_direction_output() commit b1268d3737c6316016026245eef276eda6b0a621 upstream. For GPIOs of gpio-lpc32xx, gpio_direction_output() ignores the value argument (initial value of output). This patch fixes this by setting the level accordingly. Signed-off-by: Roland Stigge Acked-by: Alexandre Pereira da Silva Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-lpc32xx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 61c2d08d37b..e42e4b84016 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -304,6 +304,7 @@ static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin, { struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + __set_gpio_level_p012(group, pin, value); __set_gpio_dir_p012(group, pin, 0); return 0; @@ -314,6 +315,7 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin, { struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + __set_gpio_level_p3(group, pin, value); __set_gpio_dir_p3(group, pin, 0); return 0; @@ -322,6 +324,9 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin, static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin, int value) { + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + __set_gpo_level_p3(group, pin, value); return 0; } From bd1d3d8331af11cc1abf5e907a9a963037530281 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 25 Sep 2012 16:17:43 +1000 Subject: [PATCH 1033/2357] drm/udl: limit modes to the sku pixel limits. commit 3a75885848996baab5276ff37ebf7295c3c753f0 upstream. Otherwise when X starts we commonly get a black screen scanning out nothing, its wierd dpms on/off from userspace brings it back, With this on F18, multi-seat works again with my 1920x1200 monitor which is above the sku limit for the device I have. Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_connector.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index ba055e9ca00..8d9dc44f1f9 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -69,6 +69,13 @@ static int udl_get_modes(struct drm_connector *connector) static int udl_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct udl_device *udl = connector->dev->dev_private; + if (!udl->sku_pixel_limit) + return 0; + + if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit) + return MODE_VIRTUAL_Y; + return 0; } From 03c4c80ee30ae2c965cd838dd0f21c97a877366d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Aug 2012 13:22:35 +0300 Subject: [PATCH 1034/2357] drm/i915: fall back to bit-banging if GMBUS fails in CRT EDID reads commit f1a2f5b7c5f0941d23eef0a095c0b99bf8d051e6 upstream. GMBUS was enabled over bit-banging as the default in commits: commit c3dfefa0a6d235bd465309e12f4c56ea16e71111 Author: Daniel Vetter Date: Tue Feb 14 22:37:25 2012 +0100 drm/i915: reenable gmbus on gen3+ again and commit 0fb3f969c8683505fb7323c06bf8a999a5a45a15 Author: Daniel Vetter Date: Fri Mar 2 19:38:30 2012 +0100 drm/i915: enable gmbus on gen2 Unfortunately, GMBUS seems to fail on some CRT displays. Add a bit-banging fallback to CRT EDID reads. LKML-Reference: <201207251020.47637.maciej.rutecki@gmail.com> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=45881 Signed-off-by: Jani Nikula Tested-by: Alex Ferrando Cc: stable@vger.kernel.org (for 3.4+3.5) Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_crt.c | 36 +++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 90b9793fd5d..342ffb7ec3d 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -266,6 +266,36 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) return ret; } +static struct edid *intel_crt_get_edid(struct drm_connector *connector, + struct i2c_adapter *i2c) +{ + struct edid *edid; + + edid = drm_get_edid(connector, i2c); + + if (!edid && !intel_gmbus_is_forced_bit(i2c)) { + DRM_DEBUG_KMS("CRT GMBUS EDID read failed, retry using GPIO bit-banging\n"); + intel_gmbus_force_bit(i2c, true); + edid = drm_get_edid(connector, i2c); + intel_gmbus_force_bit(i2c, false); + } + + return edid; +} + +/* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */ +static int intel_crt_ddc_get_modes(struct drm_connector *connector, + struct i2c_adapter *adapter) +{ + struct edid *edid; + + edid = intel_crt_get_edid(connector, adapter); + if (!edid) + return 0; + + return intel_connector_update_modes(connector, edid); +} + static bool intel_crt_detect_ddc(struct drm_connector *connector) { struct intel_crt *crt = intel_attached_crt(connector); @@ -279,7 +309,7 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) struct edid *edid; bool is_digital = false; - edid = drm_get_edid(connector, + edid = intel_crt_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); /* * This may be a DVI-I connector with a shared DDC @@ -477,13 +507,13 @@ static int intel_crt_get_modes(struct drm_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ret = intel_ddc_get_modes(connector, + ret = intel_crt_ddc_get_modes(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); if (ret || !IS_G4X(dev)) return ret; /* Try to probe digital port for output in DVI-I -> VGA mode. */ - return intel_ddc_get_modes(connector, + return intel_crt_ddc_get_modes(connector, &dev_priv->gmbus[GMBUS_PORT_DPB].adapter); } From 9a266f619f8b9994b0c2bd9bb79605ddfa4ac32a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 23 Sep 2012 19:33:55 +0300 Subject: [PATCH 1035/2357] vmwgfx: corruption in vmw_event_fence_action_create() commit 68c4fce737c4b963e336435f225621dc21138397 upstream. We don't allocate enough data for this struct. As soon as we start modifying event->event on the next lines, then we're going beyond the end of the memory we allocated. Signed-off-by: Dan Carpenter Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index f2fb8f15e2f..7e0743358df 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -1018,7 +1018,7 @@ int vmw_event_fence_action_create(struct drm_file *file_priv, } - event = kzalloc(sizeof(event->event), GFP_KERNEL); + event = kzalloc(sizeof(*event), GFP_KERNEL); if (unlikely(event == NULL)) { DRM_ERROR("Failed to allocate an event.\n"); ret = -ENOMEM; From 446d14d4c51010379f7f12f3616773e7e7fb47d9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 28 Sep 2012 09:06:10 -0700 Subject: [PATCH 1036/2357] Revert: drm/i915: correctly order the ring init sequence This reverts commit 57ecc93ce680b1ace1f9e79d588dabe32353202c which really is commit 0d8957c8a90bbb5d34fab9a304459448a5131e06 upstream as it has been reported to cause problems in the 3.4.y kernel series. Reported-by: Herton Ronaldo Krzesinski Cc: Andreas Sturmlechner Cc: Jani Nikula Cc: Yang Guang Cc: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 12a9e5fd925..302d3d54fb4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -258,6 +258,8 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_WRITE_HEAD(ring, 0); ring->write_tail(ring, 0); + /* Initialize the ring. */ + I915_WRITE_START(ring, obj->gtt_offset); head = I915_READ_HEAD(ring) & HEAD_ADDR; /* G45 ring initialization fails to reset head to zero */ @@ -283,11 +285,6 @@ static int init_ring_common(struct intel_ring_buffer *ring) } } - /* Initialize the ring. This must happen _after_ we've cleared the ring - * registers with the above sequence (the readback of the HEAD registers - * also enforces ordering), otherwise the hw might lose the new ring - * register values. */ - I915_WRITE_START(ring, obj->gtt_offset); I915_WRITE_CTL(ring, ((ring->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID); From 9effb1b2599c3ae0be3c5bf3f6187667fe2a6e70 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 13 Jul 2012 19:15:40 +0100 Subject: [PATCH 1037/2357] ARM: 7467/1: mutex: use generic xchg-based implementation for ARMv6+ commit a76d7bd96d65fa5119adba97e1b58d95f2e78829 upstream. The open-coded mutex implementation for ARMv6+ cores suffers from a severe lack of barriers, so in the uncontended case we don't actually protect any accesses performed during the critical section. Furthermore, the code is largely a duplication of the ARMv6+ atomic_dec code but optimised to remove a branch instruction, as the mutex fastpath was previously inlined. Now that this is executed out-of-line, we can reuse the atomic access code for the locking (in fact, we use the xchg code as this produces shorter critical sections). This patch uses the generic xchg based implementation for mutexes on ARMv6+, which introduces barriers to the lock/unlock operations and also has the benefit of removing a fair amount of inline assembly code. Acked-by: Arnd Bergmann Acked-by: Nicolas Pitre Reported-by: Shan Kang Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/mutex.h | 119 ++--------------------------------- 1 file changed, 4 insertions(+), 115 deletions(-) diff --git a/arch/arm/include/asm/mutex.h b/arch/arm/include/asm/mutex.h index 93226cf23ae..b1479fd04a9 100644 --- a/arch/arm/include/asm/mutex.h +++ b/arch/arm/include/asm/mutex.h @@ -7,121 +7,10 @@ */ #ifndef _ASM_MUTEX_H #define _ASM_MUTEX_H - -#if __LINUX_ARM_ARCH__ < 6 -/* On pre-ARMv6 hardware the swp based implementation is the most efficient. */ -# include -#else - /* - * Attempting to lock a mutex on ARMv6+ can be done with a bastardized - * atomic decrement (it is not a reliable atomic decrement but it satisfies - * the defined semantics for our purpose, while being smaller and faster - * than a real atomic decrement or atomic swap. The idea is to attempt - * decrementing the lock value only once. If once decremented it isn't zero, - * or if its store-back fails due to a dispute on the exclusive store, we - * simply bail out immediately through the slow path where the lock will be - * reattempted until it succeeds. + * On pre-ARMv6 hardware this results in a swp-based implementation, + * which is the most efficient. For ARMv6+, we emit a pair of exclusive + * accesses instead. */ -static inline void -__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) -{ - int __ex_flag, __res; - - __asm__ ( - - "ldrex %0, [%2] \n\t" - "sub %0, %0, #1 \n\t" - "strex %1, %0, [%2] " - - : "=&r" (__res), "=&r" (__ex_flag) - : "r" (&(count)->counter) - : "cc","memory" ); - - __res |= __ex_flag; - if (unlikely(__res != 0)) - fail_fn(count); -} - -static inline int -__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) -{ - int __ex_flag, __res; - - __asm__ ( - - "ldrex %0, [%2] \n\t" - "sub %0, %0, #1 \n\t" - "strex %1, %0, [%2] " - - : "=&r" (__res), "=&r" (__ex_flag) - : "r" (&(count)->counter) - : "cc","memory" ); - - __res |= __ex_flag; - if (unlikely(__res != 0)) - __res = fail_fn(count); - return __res; -} - -/* - * Same trick is used for the unlock fast path. However the original value, - * rather than the result, is used to test for success in order to have - * better generated assembly. - */ -static inline void -__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) -{ - int __ex_flag, __res, __orig; - - __asm__ ( - - "ldrex %0, [%3] \n\t" - "add %1, %0, #1 \n\t" - "strex %2, %1, [%3] " - - : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag) - : "r" (&(count)->counter) - : "cc","memory" ); - - __orig |= __ex_flag; - if (unlikely(__orig != 0)) - fail_fn(count); -} - -/* - * If the unlock was done on a contended lock, or if the unlock simply fails - * then the mutex remains locked. - */ -#define __mutex_slowpath_needs_to_unlock() 1 - -/* - * For __mutex_fastpath_trylock we use another construct which could be - * described as a "single value cmpxchg". - * - * This provides the needed trylock semantics like cmpxchg would, but it is - * lighter and less generic than a true cmpxchg implementation. - */ -static inline int -__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) -{ - int __ex_flag, __res, __orig; - - __asm__ ( - - "1: ldrex %0, [%3] \n\t" - "subs %1, %0, #1 \n\t" - "strexeq %2, %1, [%3] \n\t" - "movlt %0, #0 \n\t" - "cmpeq %2, #0 \n\t" - "bgt 1b " - - : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag) - : "r" (&count->counter) - : "cc", "memory" ); - - return __orig; -} - -#endif +#include #endif From 1c7eb28096b50831697a9cf6f8bf1af0e5b234bc Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 2 Oct 2012 10:35:08 -0700 Subject: [PATCH 1038/2357] Linux 3.4.12 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 22345c01622..bcf5bc455a9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 11 +SUBLEVEL = 12 EXTRAVERSION = NAME = Saber-toothed Squirrel From 9316bed3701438b79644e80cc4dd4903a40c756b Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 17 Sep 2012 22:23:30 +0200 Subject: [PATCH 1039/2357] vfs: dcache: fix deadlock in tree traversal commit 8110e16d42d587997bcaee0c864179e6d93603fe upstream. IBM reported a deadlock in select_parent(). This was found to be caused by taking rename_lock when already locked when restarting the tree traversal. There are two cases when the traversal needs to be restarted: 1) concurrent d_move(); this can only happen when not already locked, since taking rename_lock protects against concurrent d_move(). 2) racing with final d_put() on child just at the moment of ascending to parent; rename_lock doesn't protect against this rare race, so it can happen when already locked. Because of case 2, we need to be able to handle restarting the traversal when rename_lock is already held. This patch fixes all three callers of try_to_ascend(). IBM reported that the deadlock is gone with this patch. [ I rewrote the patch to be smaller and just do the "goto again" if the lock was already held, but credit goes to Miklos for the real work. - Linus ] Signed-off-by: Miklos Szeredi Cc: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/dcache.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/dcache.c b/fs/dcache.c index 10fab266627..f104945dcc7 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1116,6 +1116,8 @@ int have_submounts(struct dentry *parent) return 1; rename_retry: + if (locked) + goto again; locked = 1; write_seqlock(&rename_lock); goto again; @@ -1218,6 +1220,8 @@ static int select_parent(struct dentry *parent, struct list_head *dispose) rename_retry: if (found) return found; + if (locked) + goto again; locked = 1; write_seqlock(&rename_lock); goto again; @@ -2963,6 +2967,8 @@ void d_genocide(struct dentry *root) return; rename_retry: + if (locked) + goto again; locked = 1; write_seqlock(&rename_lock); goto again; From f9954ca80cc595852db6e913e65808819b9dc413 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Wed, 26 Sep 2012 23:45:42 +0100 Subject: [PATCH 1040/2357] dm: handle requests beyond end of device instead of using BUG_ON commit ba1cbad93dd47223b1f3b8edd50dd9ef2abcb2ed upstream. The access beyond the end of device BUG_ON that was introduced to dm_request_fn via commit 29e4013de7ad950280e4b2208 ("dm: implement REQ_FLUSH/FUA support for request-based dm") was an overly drastic (but simple) response to this situation. I have received a report that this BUG_ON was hit and now think it would be better to use dm_kill_unmapped_request() to fail the clone and original request with -EIO. map_request() will assign the valid target returned by dm_table_find_target to tio->ti. But when the target isn't valid tio->ti is never assigned (because map_request isn't called); so add a check for tio->ti != NULL to dm_done(). Reported-by: Mike Christie Signed-off-by: Mike Snitzer Signed-off-by: Jun'ichi Nomura Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm.c | 56 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index e24143cc204..9ff3019790d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -865,10 +865,14 @@ static void dm_done(struct request *clone, int error, bool mapped) { int r = error; struct dm_rq_target_io *tio = clone->end_io_data; - dm_request_endio_fn rq_end_io = tio->ti->type->rq_end_io; + dm_request_endio_fn rq_end_io = NULL; - if (mapped && rq_end_io) - r = rq_end_io(tio->ti, clone, error, &tio->info); + if (tio->ti) { + rq_end_io = tio->ti->type->rq_end_io; + + if (mapped && rq_end_io) + r = rq_end_io(tio->ti, clone, error, &tio->info); + } if (r <= 0) /* The target wants to complete the I/O */ @@ -1566,15 +1570,6 @@ static int map_request(struct dm_target *ti, struct request *clone, int r, requeued = 0; struct dm_rq_target_io *tio = clone->end_io_data; - /* - * Hold the md reference here for the in-flight I/O. - * We can't rely on the reference count by device opener, - * because the device may be closed during the request completion - * when all bios are completed. - * See the comment in rq_completed() too. - */ - dm_get(md); - tio->ti = ti; r = ti->type->map_rq(ti, clone, &tio->info); switch (r) { @@ -1606,6 +1601,26 @@ static int map_request(struct dm_target *ti, struct request *clone, return requeued; } +static struct request *dm_start_request(struct mapped_device *md, struct request *orig) +{ + struct request *clone; + + blk_start_request(orig); + clone = orig->special; + atomic_inc(&md->pending[rq_data_dir(clone)]); + + /* + * Hold the md reference here for the in-flight I/O. + * We can't rely on the reference count by device opener, + * because the device may be closed during the request completion + * when all bios are completed. + * See the comment in rq_completed() too. + */ + dm_get(md); + + return clone; +} + /* * q->request_fn for request-based dm. * Called with the queue lock held. @@ -1635,14 +1650,21 @@ static void dm_request_fn(struct request_queue *q) pos = blk_rq_pos(rq); ti = dm_table_find_target(map, pos); - BUG_ON(!dm_target_is_valid(ti)); + if (!dm_target_is_valid(ti)) { + /* + * Must perform setup, that dm_done() requires, + * before calling dm_kill_unmapped_request + */ + DMERR_LIMIT("request attempted access beyond the end of device"); + clone = dm_start_request(md, rq); + dm_kill_unmapped_request(clone, -EIO); + continue; + } if (ti->type->busy && ti->type->busy(ti)) goto delay_and_out; - blk_start_request(rq); - clone = rq->special; - atomic_inc(&md->pending[rq_data_dir(clone)]); + clone = dm_start_request(md, rq); spin_unlock(q->queue_lock); if (map_request(ti, clone, md)) @@ -1662,8 +1684,6 @@ static void dm_request_fn(struct request_queue *q) blk_delay_queue(q, HZ / 10); out: dm_table_put(map); - - return; } int dm_underlying_device_busy(struct request_queue *q) From 7d77f4776e3fc8770f90244f1f5d1c9181b834c7 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Wed, 26 Sep 2012 23:45:43 +0100 Subject: [PATCH 1041/2357] dm table: clear add_random unless all devices have it set commit c3c4555edd10dbc0b388a0125b9c50de5e79af05 upstream. Always clear QUEUE_FLAG_ADD_RANDOM if any underlying device does not have it set. Otherwise devices with predictable characteristics may contribute entropy. QUEUE_FLAG_ADD_RANDOM specifies whether or not queue IO timings contribute to the random pool. For bio-based targets this flag is always 0 because such devices have no real queue. For request-based devices this flag was always set to 1 by default. Now set it according to the flags on underlying devices. If there is at least one device which should not contribute, set the flag to zero: If a device, such as fast SSD storage, is not suitable for supplying entropy, a request-based queue stacked over it will not be either. Because the checking logic is exactly same as for the rotational flag, share the iteration function with device_is_nonrot(). Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-table.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 2e227fbf162..f220a695a4b 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1351,17 +1351,25 @@ static int device_is_nonrot(struct dm_target *ti, struct dm_dev *dev, return q && blk_queue_nonrot(q); } -static bool dm_table_is_nonrot(struct dm_table *t) +static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev, + sector_t start, sector_t len, void *data) +{ + struct request_queue *q = bdev_get_queue(dev->bdev); + + return q && !blk_queue_add_random(q); +} + +static bool dm_table_all_devices_attribute(struct dm_table *t, + iterate_devices_callout_fn func) { struct dm_target *ti; unsigned i = 0; - /* Ensure that all underlying device are non-rotational. */ while (i < dm_table_get_num_targets(t)) { ti = dm_table_get_target(t, i++); if (!ti->type->iterate_devices || - !ti->type->iterate_devices(ti, device_is_nonrot, NULL)) + !ti->type->iterate_devices(ti, func, NULL)) return 0; } @@ -1393,13 +1401,23 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, if (!dm_table_discard_zeroes_data(t)) q->limits.discard_zeroes_data = 0; - if (dm_table_is_nonrot(t)) + /* Ensure that all underlying devices are non-rotational. */ + if (dm_table_all_devices_attribute(t, device_is_nonrot)) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); else queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q); dm_table_set_integrity(t); + /* + * Determine whether or not this queue's I/O timings contribute + * to the entropy pool, Only request-based targets use this. + * Clear QUEUE_FLAG_ADD_RANDOM if any underlying device does not + * have it set. + */ + if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random)) + queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, q); + /* * QUEUE_FLAG_STACKABLE must be set after all queue settings are * visible to other CPUs because, once the flag is set, incoming bios From c0b50b292c41e0a1c6a1ef6df665fe7fb8eac2e1 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 26 Sep 2012 23:45:48 +0100 Subject: [PATCH 1042/2357] dm verity: fix overflow check commit 1d55f6bcc0331d744cd5b56c4ee79e3809438161 upstream. This patch fixes sector_t overflow checking in dm-verity. Without this patch, the code checks for overflow only if sector_t is smaller than long long, not if sector_t and long long have the same size. Signed-off-by: Mikulas Patocka Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-verity.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index fa365d39b61..68bf5c37c3f 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -718,8 +718,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) v->hash_dev_block_bits = ffs(num) - 1; if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 || - num_ll << (v->data_dev_block_bits - SECTOR_SHIFT) != - (sector_t)num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) { + (sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) + >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll) { ti->error = "Invalid data blocks"; r = -EINVAL; goto bad; @@ -733,8 +733,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) } if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 || - num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT) != - (sector_t)num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT)) { + (sector_t)(num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT)) + >> (v->hash_dev_block_bits - SECTOR_SHIFT) != num_ll) { ti->error = "Invalid hash start"; r = -EINVAL; goto bad; From 47c8e86e3869d7b7d159b069ad80cc621c2b1199 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Sun, 19 Aug 2012 21:54:58 +0200 Subject: [PATCH 1043/2357] usb: gadget: dummy_hcd: fixup error probe path commit 1b68a4ca2d038addb7314211d122fb6d7002b38b upstream. If USB2 host controller probes fine but USB3 does not then we don't remove the USB controller properly and lock up the system while the HUB code will try to enumerate the USB2 controller and access memory which is no longer available in case the dummy_hcd was compiled as a module. This is a problem since 448b6eb1 ("USB: Make sure to fetch the BOS desc for roothubs.) if used in USB3 mode because dummy does not provide this descriptor and explodes later. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 170cbe89d9f..2d277a2bc33 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -2505,10 +2505,8 @@ static int dummy_hcd_probe(struct platform_device *pdev) hs_hcd->has_tt = 1; retval = usb_add_hcd(hs_hcd, 0, 0); - if (retval != 0) { - usb_put_hcd(hs_hcd); - return retval; - } + if (retval) + goto put_usb2_hcd; if (mod_data.is_super_speed) { ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev, @@ -2527,6 +2525,8 @@ static int dummy_hcd_probe(struct platform_device *pdev) put_usb3_hcd: usb_put_hcd(ss_hcd); dealloc_usb2_hcd: + usb_remove_hcd(hs_hcd); +put_usb2_hcd: usb_put_hcd(hs_hcd); the_controller.hs_hcd = the_controller.ss_hcd = NULL; return retval; From 58bd65bfa47cf7dec02c8a1e2201dad0003acfb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 19 Sep 2012 22:02:12 +0200 Subject: [PATCH 1044/2357] USB: option: blacklist QMI interface on ZTE MF683 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 160c9425ac52cb30502be2d9c5e848cec91bb115 upstream. Interface #5 on ZTE MF683 is a QMI/wwan interface. Signed-off-by: Bjørn Mork Cc: Shawn J. Goff Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index a49099da93e..57de73462f0 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -870,7 +870,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, From e59f498dc3f7679f236b2aec4a6c23173de78a65 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Sun, 23 Sep 2012 09:57:25 +0200 Subject: [PATCH 1045/2357] USB: ftdi_sio: add TIAO USB Multi-Protocol Adapter (TUMPA) support commit 54575b05af36959dfb6a49a3e9ca0c2b456b7126 upstream. TIAO/DIYGADGET USB Multi-Protocol Adapter (TUMPA) is an FTDI FT2232H based device which provides an easily accessible JTAG, SPI, I2C, serial breakout. http://www.diygadget.com/tiao-usb-multi-protocol-adapter-jtag-spi-i2c-serial.html http://www.tiaowiki.com/w/TIAO_USB_Multi_Protocol_Adapter_User%27s_Manual FTDI FT2232H provides two serial channels (A and B), but on the TUMPA channel A is dedicated to JTAG/SPI while channel B can be used for UART/RS-232: use the ftdi_jtag_quirk to expose only channel B as a usb-serial interface to userspace. Signed-off-by: Antonio Ospite Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 4d2b7d31fc6..25bb9350396 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -584,6 +584,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, /* * ELV devices: */ diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 41fe5826100..57c12ef6625 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -517,6 +517,11 @@ */ #define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */ +/* + * TIAO product ids (FTDI_VID) + * http://www.tiaowiki.com/w/Main_Page + */ +#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */ /********************************/ From 28939e9a0972df8eff635a92c0c0a62efe97d9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 19 Sep 2012 22:02:03 +0200 Subject: [PATCH 1046/2357] USB: qcaux: add Pantech vendor class match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c638eb2872b3af079501e7ee44cbb8a5cce9b4b5 upstream. The three Pantech devices UML190 (106c:3716), UML290 (106c:3718) and P4200 (106c:3721) all use the same subclasses to identify vendor specific functions. Replace the existing device specific entries with generic vendor matching, adding support for the P4200. Signed-off-by: Bjørn Mork Cc: Thomas Schäfer Acked-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcaux.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index 966245680f5..b223381da32 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -36,8 +36,6 @@ #define UTSTARCOM_PRODUCT_UM175_V1 0x3712 #define UTSTARCOM_PRODUCT_UM175_V2 0x3714 #define UTSTARCOM_PRODUCT_UM175_ALLTEL 0x3715 -#define PANTECH_PRODUCT_UML190_VZW 0x3716 -#define PANTECH_PRODUCT_UML290_VZW 0x3718 /* CMOTECH devices */ #define CMOTECH_VENDOR_ID 0x16d8 @@ -68,11 +66,9 @@ static struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xfe, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfd, 0xff) }, /* NMEA */ - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfe, 0xff) }, /* WMC */ - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) }, /* DIAG */ + { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfd, 0xff) }, /* NMEA */ + { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfe, 0xff) }, /* WMC */ + { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xff, 0xff) }, /* DIAG */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); From 1d64560a29d149803a119527ad6b3d80b83a85a8 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Sat, 22 Sep 2012 18:11:19 +0530 Subject: [PATCH 1047/2357] usb: host: xhci: Fix Null pointer dereferencing with 71c731a for non-x86 systems commit 457a73d346187c2cc5d599072f38676f18f130e0 upstream. In 71c731a: usb: host: xhci: Fix Compliance Mode on SN65LVPE502CP Hardware when extracting DMI strings (vendor or product_name) to mark them as quirk we may get NULL pointer in case of non-x86 systems which won't define CONFIG_DMI. Hence susbsequent strstr() calls crash while driver probing. So, returning 'false' here in case we get a NULL vendor or product_name. This is tested with ARM (exynos) system. This patch should be backported to stable kernels as old as 3.6, that contain the commit 71c731a296f1b08a3724bd1b514b64f1bda87a23 "usb: host: xhci: Fix Compliance Mode on SN65LVPE502CP Hardware" Signed-off-by: Vivek Gautam Signed-off-by: Sarah Sharp Reported-by: Sebastian Gottschall (DD-WRT) Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6467d79d760..495c7a3a997 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -470,6 +470,8 @@ static bool compliance_mode_recovery_timer_quirk_check(void) dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR); + if (!dmi_product_name || !dmi_sys_vendor) + return false; if (!(strstr(dmi_sys_vendor, "Hewlett-Packard"))) return false; From f7d978ef5d1cdbbb7bd7dba5fb995d56b7640b37 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 16 Sep 2012 04:18:50 +0100 Subject: [PATCH 1048/2357] staging: speakup_soft: Fix reading of init string commit 40fe4f89671fb3c7ded94190fb267402a38b0261 upstream. softsynth_read() reads a character at a time from the init string; when it finds the null terminator it sets the initialized flag but then repeats the last character. Additionally, if the read() buffer is not big enough for the init string, the next read() will start reading from the beginning again. So the caller may never progress to reading anything else. Replace the simple initialized flag with the current position in the init string, carried over between calls. Switch to reading real data once this reaches the null terminator. (This assumes that the length of the init string can't change, which seems to be the case. Really, the string and position belong together in a per-file private struct.) Tested-by: Samuel Thibault Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/speakup_soft.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c index 42cdafeea35..b5130c8bcb6 100644 --- a/drivers/staging/speakup/speakup_soft.c +++ b/drivers/staging/speakup/speakup_soft.c @@ -40,7 +40,7 @@ static int softsynth_is_alive(struct spk_synth *synth); static unsigned char get_index(void); static struct miscdevice synth_device; -static int initialized; +static int init_pos; static int misc_registered; static struct var_t vars[] = { @@ -194,7 +194,7 @@ static int softsynth_close(struct inode *inode, struct file *fp) unsigned long flags; spk_lock(flags); synth_soft.alive = 0; - initialized = 0; + init_pos = 0; spk_unlock(flags); /* Make sure we let applications go before leaving */ speakup_start_ttys(); @@ -239,13 +239,8 @@ static ssize_t softsynth_read(struct file *fp, char *buf, size_t count, ch = '\x18'; } else if (synth_buffer_empty()) { break; - } else if (!initialized) { - if (*init) { - ch = *init; - init++; - } else { - initialized = 1; - } + } else if (init[init_pos]) { + ch = init[init_pos++]; } else { ch = synth_buffer_getc(); } From 0f2c427a4f4a994526bea7ce3855284fc5a7940a Mon Sep 17 00:00:00 2001 From: Christopher Brannon Date: Fri, 22 Jun 2012 08:16:34 -0500 Subject: [PATCH 1049/2357] tty: keyboard.c: Remove locking from vt_get_leds. commit 157a4b311c45c9aba75a990464d9680867dc8805 upstream. There are three call sites for this function, and all three are called within a keyboard handler. kbd_event_lock is already held within keyboard handlers, so attempting to lock it in vt_get_leds causes deadlock. Signed-off-by: Christopher Brannon Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 3b0c4e32ed7..a6d5d51fcbc 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1053,13 +1053,10 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) */ int vt_get_leds(int console, int flag) { - unsigned long flags; struct kbd_struct * kbd = kbd_table + console; int ret; - spin_lock_irqsave(&kbd_event_lock, flags); ret = vc_kbd_led(kbd, flag); - spin_unlock_irqrestore(&kbd_event_lock, flags); return ret; } From 28675586f391fc14960de13c63359b25542ddec4 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 26 Sep 2012 14:01:31 -0500 Subject: [PATCH 1050/2357] staging: r8712u: Do not queue cloned skb commit fa16e5ea25d7dd83f663f333e70713aa2fa5dffe upstream. Some post-3.4 kernels have a problem when a cloned skb is used in the RX path. This patch handles one such case for r8712u. The patch was suggested by Eric Dumazet. Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl8712_recv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index fa6dc9c09b3..887a80709ab 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -1126,6 +1126,9 @@ static void recv_tasklet(void *priv) recvbuf2recvframe(padapter, pskb); skb_reset_tail_pointer(pskb); pskb->len = 0; - skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + if (!skb_cloned(pskb)) + skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + else + consume_skb(pskb); } } From b5697de62b79060f59a5d7780aa4c16fdcfaa929 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 24 Sep 2012 17:20:52 +0100 Subject: [PATCH 1051/2357] staging: comedi: s626: don't dereference insn->data commit b655c2c4782ed3e2e71d2608154e295a3e860311 upstream. `s626_enc_insn_config()` is incorrectly dereferencing `insn->data` which is a pointer to user memory. It should be dereferencing the separate `data` parameter that points to a copy of the data in kernel memory. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/s626.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 23fc64b9988..c72128f30f1 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -2370,7 +2370,7 @@ static int s626_enc_insn_config(struct comedi_device *dev, /* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ k->SetMode(dev, k, Setup, TRUE); - Preload(dev, k, *(insn->data)); + Preload(dev, k, data[0]); k->PulseIndex(dev, k); SetLatchSource(dev, k, valueSrclatch); k->SetEnable(dev, k, (uint16_t) (enab != 0)); From 4483c56613f9ca0cff15d231975b240d3f3e8a10 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 27 Sep 2012 17:45:27 +0100 Subject: [PATCH 1052/2357] staging: comedi: jr3_pci: fix iomem dereference commit e1878957b4676a17cf398f7f5723b365e9a2ca48 upstream. Correct a direct dereference of I/O memory to use an appropriate I/O memory access function. Note that the pointer being dereferenced is not currently tagged with `__iomem` but I plan to correct that for 3.7. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/jr3_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 6a79ba10630..d7e63419e61 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -905,7 +905,7 @@ static int jr3_pci_attach(struct comedi_device *dev, } /* Reset DSP card */ - devpriv->iobase->channel[0].reset = 0; + writel(0, &devpriv->iobase->channel[0].reset); result = comedi_load_firmware(dev, "jr3pci.idm", jr3_download_firmware); dev_dbg(dev->hw_dev, "Firmare load %d\n", result); From 19dcf415184e1ef6d9641d76e3248d3b2677b3df Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Tue, 18 Sep 2012 19:46:58 +0100 Subject: [PATCH 1053/2357] staging: comedi: don't dereference user memory for INSN_INTTRIG commit 5d06e3df280bd230e2eadc16372e62818c63e894 upstream. `parse_insn()` is dereferencing the user-space pointer `insn->data` directly when handling the `INSN_INTTRIG` comedi instruction. It shouldn't be using `insn->data` at all; it should be using the separate `data` pointer passed to the function. Fix it. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index a796964bfff..28811890d70 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -843,7 +843,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, ret = -EAGAIN; break; } - ret = s->async->inttrig(dev, s, insn->data[0]); + ret = s->async->inttrig(dev, s, data[0]); if (ret >= 0) ret = 1; break; From f810716cd61810278caee8eefed22e8706e49125 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 19 Sep 2012 19:37:39 +0100 Subject: [PATCH 1054/2357] staging: comedi: fix memory leak for saved channel list commit c8cad4c89ee3b15935c532210ae6ebb5c0a2734d upstream. When `do_cmd_ioctl()` allocates memory for the kernel copy of a channel list, it frees any previously allocated channel list in `async->cmd.chanlist` and replaces it with the new one. However, if the device is ever removed (or "detached") the cleanup code in `cleanup_device()` in "drivers.c" does not free this memory so it is lost. A sensible place to free the kernel copy of the channel list is in `do_become_nonbusy()` as at that point the comedi asynchronous command associated with the channel list is no longer valid. Free the channel list in `do_become_nonbusy()` instead of `do_cmd_ioctl()` and clear the pointer to prevent it being freed more than once. Note that `cleanup_device()` could be called at an inappropriate time while the comedi device is open, but that's a separate bug not related to this this patch. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 28811890d70..b719460c4ec 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1088,7 +1088,6 @@ static int do_cmd_ioctl(struct comedi_device *dev, goto cleanup; } - kfree(async->cmd.chanlist); async->cmd = user_cmd; async->cmd.data = NULL; /* load channel/gain list */ @@ -1833,6 +1832,8 @@ void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) if (async) { comedi_reset_async_buf(async); async->inttrig = NULL; + kfree(async->cmd.chanlist); + async->cmd.chanlist = NULL; } else { printk(KERN_ERR "BUG: (?) do_become_nonbusy called with async=0\n"); From e2a43abf3d9c6a3828d9a02c3de0d8bf16bd4b90 Mon Sep 17 00:00:00 2001 From: Stanislav Kozina Date: Thu, 16 Aug 2012 12:01:47 +0100 Subject: [PATCH 1055/2357] Remove BUG_ON from n_tty_read() commit e9490e93c1978b6669f3e993caa3189be13ce459 upstream. Change the BUG_ON to WARN_ON and return in case of tty->read_buf==NULL. We want to track a couple of long standing reports of this but at the same time we can avoid killing the box. Signed-off-by: Stanislav Kozina Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 94b6eda87af..2303a02e9dc 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1727,7 +1727,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, do_it_again: - BUG_ON(!tty->read_buf); + if (WARN_ON(!tty->read_buf)) + return -EAGAIN; c = job_control(tty, file); if (c < 0) From 804f6a4a4745ce54f3afa76b3d2270b385f565f8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:39 +0200 Subject: [PATCH 1056/2357] TTY: ttyprintk, don't touch behind tty->write_buf commit ee8b593affdf893012e57f4c54a21984d1b0d92e upstream. If a user provides a buffer larger than a tty->write_buf chunk and passes '\r' at the end of the buffer, we touch an out-of-bound memory. Add a check there to prevent this. Signed-off-by: Jiri Slaby Cc: Samo Pogacnik Signed-off-by: Greg Kroah-Hartman --- drivers/char/ttyprintk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 46b77ede84c..a7c6d6a07d3 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count) tmp[tpk_curr + 1] = '\0'; printk(KERN_INFO "%s%s", tpk_tag, tmp); tpk_curr = 0; - if (buf[i + 1] == '\n') + if ((i + 1) < count && buf[i + 1] == '\n') i++; break; case '\n': From bba5a67bba4c56ab0ce632d7a3e1a651d9162b9e Mon Sep 17 00:00:00 2001 From: Vikram Pandita Date: Thu, 6 Sep 2012 15:45:37 +0300 Subject: [PATCH 1057/2357] serial: omap: fix software flow control commit 957ee7270d632245b43f6feb0e70d9a5e9ea6cf6 upstream. Software flow control register bits were not defined correctly. Also clarify the IXON and IXOFF logic to reflect what userspace wants. Tested-by: Shubhrajyoti D Signed-off-by: Vikram Pandita Signed-off-by: Shubhrajyoti D Acked-by: Tony Lindgren Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-omap/include/plat/omap-serial.h | 4 ++-- drivers/tty/serial/omap-serial.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index 9ff444469f3..c369c9d242a 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -42,10 +42,10 @@ #define OMAP_UART_WER_MOD_WKUP 0X7F /* Enable XON/XOFF flow control on output */ -#define OMAP_UART_SW_TX 0x04 +#define OMAP_UART_SW_TX 0x8 /* Enable XON/XOFF flow control on input */ -#define OMAP_UART_SW_RX 0x04 +#define OMAP_UART_SW_RX 0x2 #define OMAP_UART_SYSC_RESET 0X07 #define OMAP_UART_TCR_TRIG 0X0F diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d00b38eb268..6189923eb19 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -649,19 +649,19 @@ serial_omap_configure_xonxoff /* * IXON Flag: - * Enable XON/XOFF flow control on output. - * Transmit XON1, XOFF1 + * Flow control for OMAP.TX + * OMAP.RX should listen for XON/XOFF */ if (termios->c_iflag & IXON) - up->efr |= OMAP_UART_SW_TX; + up->efr |= OMAP_UART_SW_RX; /* * IXOFF Flag: - * Enable XON/XOFF flow control on input. - * Receiver compares XON1, XOFF1. + * Flow control for OMAP.RX + * OMAP.TX should send XON/XOFF */ if (termios->c_iflag & IXOFF) - up->efr |= OMAP_UART_SW_RX; + up->efr |= OMAP_UART_SW_TX; serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); From c5500c74ff1414578161b796557b382d5cbaf024 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 26 Sep 2012 17:21:36 +0200 Subject: [PATCH 1058/2357] serial: pl011: handle corruption at high clock speeds commit c5dd553b9fd069892c9e2de734f4f604e280fa7a upstream. This works around a few glitches in the ST version of the PL011 serial driver when using very high baud rates, as we do in the Ux500: 3, 3.25, 4 and 4.05 Mbps. Problem Observed/rootcause: When using high baud-rates, and the baudrate*8 is getting close to the provided clock frequency (so a division factor close to 1), when using bursts of characters (so they are abutted), then it seems as if there is not enough time to detect the beginning of the start-bit which is a timing reference for the entire character, and thus the sampling moment of character bits is moving towards the end of each bit, instead of the middle. Fix: Increase slightly the RX baud rate of the UART above the theoretical baudrate by 5%. This will definitely give more margin time to the UART_RX to correctly sample the data at the middle of the bit period. Also fix the ages old copy-paste error in the very stressed comment, it's referencing the registers used in the PL010 driver rather than the PL011 ones. Signed-off-by: Guillaume Jaunet Signed-off-by: Christophe Arnal Signed-off-by: Matthias Locher Signed-off-by: Rajanikanth HV Cc: Bibek Basu Cc: Par-Gunnar Hjalmdahl Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 3d569cd68f5..b69356c227c 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1654,13 +1654,26 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, old_cr &= ~ST_UART011_CR_OVSFACT; } + /* + * Workaround for the ST Micro oversampling variants to + * increase the bitrate slightly, by lowering the divisor, + * to avoid delayed sampling of start bit at high speeds, + * else we see data corruption. + */ + if (uap->vendor->oversampling) { + if ((baud >= 3000000) && (baud < 3250000) && (quot > 1)) + quot -= 1; + else if ((baud > 3250000) && (quot > 2)) + quot -= 2; + } /* Set baud rate */ writew(quot & 0x3f, port->membase + UART011_FBRD); writew(quot >> 6, port->membase + UART011_IBRD); /* * ----------v----------v----------v----------v----- - * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L + * NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER + * UART011_FBRD & UART011_IBRD. * ----------^----------^----------^----------^----- */ writew(lcr_h, port->membase + uap->lcrh_rx); From 268b7d491c88845b410b2dfc84af54075db35c4d Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Fri, 21 Sep 2012 21:04:34 -0300 Subject: [PATCH 1059/2357] serial: set correct baud_base for EXSYS EX-41092 Dual 16950 commit 26e8220adb0aec43b7acafa0f1431760eee28522 upstream. Apparently the same card model has two IDs, so this patch complements the commit 39aced68d664291db3324d0fcf0985ab5626aac2 adding the missing one. Signed-off-by: Flavio Leitner Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 9 +++++++-- include/linux/pci_ids.h | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 3614973c999..40747feed34 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1125,6 +1125,8 @@ pci_xr17c154_setup(struct serial_private *priv, #define PCI_SUBDEVICE_ID_OCTPRO422 0x0208 #define PCI_SUBDEVICE_ID_POCTAL232 0x0308 #define PCI_SUBDEVICE_ID_POCTAL422 0x0408 +#define PCI_SUBDEVICE_ID_SIIG_DUAL_00 0x2500 +#define PCI_SUBDEVICE_ID_SIIG_DUAL_30 0x2530 #define PCI_VENDOR_ID_ADVANTECH 0x13fe #define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66 #define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 @@ -3187,8 +3189,11 @@ static struct pci_device_id serial_pci_tbl[] = { * For now just used the hex ID 0x950a. */ { PCI_VENDOR_ID_OXSEMI, 0x950a, - PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0, - pbn_b0_2_115200 }, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00, + 0, 0, pbn_b0_2_115200 }, + { PCI_VENDOR_ID_OXSEMI, 0x950a, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30, + 0, 0, pbn_b0_2_115200 }, { PCI_VENDOR_ID_OXSEMI, 0x950a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_2_1130000 }, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 19ca550ff66..bf7934f4268 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1846,7 +1846,6 @@ #define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081 #define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082 #define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050 -#define PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL 0x2530 #define PCI_VENDOR_ID_RADISYS 0x1331 From 37b6d804b3b5e2a255d2182ce00e1f25c568d7e9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 5 Sep 2012 14:37:35 -0700 Subject: [PATCH 1060/2357] tools/hv: Fix file handle leak commit d5ab482799e7c4c4b7c0aa67e8710dce28115d03 upstream. Match up each fopen() with an fclose(). Signed-off-by: Ben Hutchings Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index d9834b36294..a08213b2250 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -144,7 +144,7 @@ static void kvp_update_file(int pool) sizeof(struct kvp_record), kvp_file_info[pool].num_records, filep); - fflush(filep); + fclose(filep); kvp_release_lock(pool); } @@ -191,6 +191,7 @@ static void kvp_update_mem_state(int pool) kvp_file_info[pool].records = record; kvp_file_info[pool].num_records = records_read; + fclose(filep); kvp_release_lock(pool); } static int kvp_file_init(void) From de5d66e635460e27d678df99f9cb97e263d3bbe7 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 5 Sep 2012 14:37:36 -0700 Subject: [PATCH 1061/2357] tools/hv: Fix exit() error code commit 6bb22fea25624ab593eee376fa5fb82d1b13f45a upstream. Linux native exit codes are 8-bit unsigned values. exit(-1) results in an exit code of 255, which is usually reserved for shells reporting 'command not found'. Use the portable value EXIT_FAILURE. (Not that this matters much for a daemon.) Signed-off-by: Ben Hutchings Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index a08213b2250..edab6e90038 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -106,7 +106,7 @@ static void kvp_acquire_lock(int pool) if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) { syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool); - exit(-1); + exit(EXIT_FAILURE); } } @@ -118,7 +118,7 @@ static void kvp_release_lock(int pool) if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { perror("fcntl"); syslog(LOG_ERR, "Failed to release the lock pool: %d", pool); - exit(-1); + exit(EXIT_FAILURE); } } @@ -137,7 +137,7 @@ static void kvp_update_file(int pool) if (!filep) { kvp_release_lock(pool); syslog(LOG_ERR, "Failed to open file, pool: %d", pool); - exit(-1); + exit(EXIT_FAILURE); } bytes_written = fwrite(kvp_file_info[pool].records, @@ -163,7 +163,7 @@ static void kvp_update_mem_state(int pool) if (!filep) { kvp_release_lock(pool); syslog(LOG_ERR, "Failed to open file, pool: %d", pool); - exit(-1); + exit(EXIT_FAILURE); } while (!feof(filep)) { readp = &record[records_read]; @@ -180,7 +180,7 @@ static void kvp_update_mem_state(int pool) if (record == NULL) { syslog(LOG_ERR, "malloc failed"); - exit(-1); + exit(EXIT_FAILURE); } continue; } @@ -209,7 +209,7 @@ static int kvp_file_init(void) if (access("/var/opt/hyperv", F_OK)) { if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) { syslog(LOG_ERR, " Failed to create /var/opt/hyperv"); - exit(-1); + exit(EXIT_FAILURE); } } @@ -658,13 +658,13 @@ int main(void) if (kvp_file_init()) { syslog(LOG_ERR, "Failed to initialize the pools"); - exit(-1); + exit(EXIT_FAILURE); } fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (fd < 0) { syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); - exit(-1); + exit(EXIT_FAILURE); } addr.nl_family = AF_NETLINK; addr.nl_pad = 0; @@ -676,7 +676,7 @@ int main(void) if (error < 0) { syslog(LOG_ERR, "bind failed; error:%d", error); close(fd); - exit(-1); + exit(EXIT_FAILURE); } sock_opt = addr.nl_groups; setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt)); @@ -696,7 +696,7 @@ int main(void) if (len < 0) { syslog(LOG_ERR, "netlink_send failed; error:%d", len); close(fd); - exit(-1); + exit(EXIT_FAILURE); } pfd.fd = fd; @@ -864,7 +864,7 @@ int main(void) len = netlink_send(fd, incoming_cn_msg); if (len < 0) { syslog(LOG_ERR, "net_link send failed; error:%d", len); - exit(-1); + exit(EXIT_FAILURE); } } From 1eafb0280d1275629da54c350c7d9842f7785577 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 5 Sep 2012 14:37:37 -0700 Subject: [PATCH 1062/2357] tools/hv: Check for read/write errors commit 436473bc2173499ae274d0f50111d1e355006caf upstream. hv_kvp_daemon currently does not check whether fread() or fwrite() succeed. Add the necessary checks. Also, remove the incorrect use of feof() before fread(). Signed-off-by: Ben Hutchings Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index edab6e90038..2984ffb7bac 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -144,7 +144,12 @@ static void kvp_update_file(int pool) sizeof(struct kvp_record), kvp_file_info[pool].num_records, filep); - fclose(filep); + if (ferror(filep) || fclose(filep)) { + kvp_release_lock(pool); + syslog(LOG_ERR, "Failed to write file, pool: %d", pool); + exit(EXIT_FAILURE); + } + kvp_release_lock(pool); } @@ -165,12 +170,17 @@ static void kvp_update_mem_state(int pool) syslog(LOG_ERR, "Failed to open file, pool: %d", pool); exit(EXIT_FAILURE); } - while (!feof(filep)) { + for (;;) { readp = &record[records_read]; records_read += fread(readp, sizeof(struct kvp_record), ENTRIES_PER_BLOCK * num_blocks, filep); + if (ferror(filep)) { + syslog(LOG_ERR, "Failed to read file, pool: %d", pool); + exit(EXIT_FAILURE); + } + if (!feof(filep)) { /* * We have more data to read. @@ -233,12 +243,18 @@ static int kvp_file_init(void) fclose(filep); return 1; } - while (!feof(filep)) { + for (;;) { readp = &record[records_read]; records_read += fread(readp, sizeof(struct kvp_record), ENTRIES_PER_BLOCK, filep); + if (ferror(filep)) { + syslog(LOG_ERR, "Failed to read file, pool: %d", + i); + exit(EXIT_FAILURE); + } + if (!feof(filep)) { /* * We have more data to read. From dc8276b241ad415b2602c4a7309e5b518bb09c32 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 26 Sep 2012 12:32:02 -0500 Subject: [PATCH 1063/2357] b43legacy: Fix crash on unload when firmware not available commit 2d838bb608e2d1f6cb4280e76748cb812dc822e7 upstream. When b43legacy is loaded without the firmware being available, a following unload generates a kernel NULL pointer dereference BUG as follows: [ 214.330789] BUG: unable to handle kernel NULL pointer dereference at 0000004c [ 214.330997] IP: [] drain_workqueue+0x15/0x170 [ 214.331179] *pde = 00000000 [ 214.331311] Oops: 0000 [#1] SMP [ 214.331471] Modules linked in: b43legacy(-) ssb pcmcia mac80211 cfg80211 af_packet mperf arc4 ppdev sr_mod cdrom sg shpchp yenta_socket pcmcia_rsrc pci_hotplug pcmcia_core battery parport_pc parport floppy container ac button edd autofs4 ohci_hcd ehci_hcd usbcore usb_common thermal processor scsi_dh_rdac scsi_dh_hp_sw scsi_dh_emc scsi_dh_alua scsi_dh fan thermal_sys hwmon ata_generic pata_ali libata [last unloaded: cfg80211] [ 214.333421] Pid: 3639, comm: modprobe Not tainted 3.6.0-rc6-wl+ #163 Source Technology VIC 9921/ALI Based Notebook [ 214.333580] EIP: 0060:[] EFLAGS: 00010246 CPU: 0 [ 214.333687] EIP is at drain_workqueue+0x15/0x170 [ 214.333788] EAX: c162ac40 EBX: cdfb8360 ECX: 0000002a EDX: 00002a2a [ 214.333890] ESI: 00000000 EDI: 00000000 EBP: cd767e7c ESP: cd767e5c [ 214.333957] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [ 214.333957] CR0: 8005003b CR2: 0000004c CR3: 0c96a000 CR4: 00000090 [ 214.333957] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [ 214.333957] DR6: ffff0ff0 DR7: 00000400 [ 214.333957] Process modprobe (pid: 3639, ti=cd766000 task=cf802e90 task.ti=cd766000) [ 214.333957] Stack: [ 214.333957] 00000292 cd767e74 c12c5e09 00000296 00000296 cdfb8360 cdfb9220 00000000 [ 214.333957] cd767e90 c104c4fd cdfb8360 cdfb9220 cd682800 cd767ea4 d0c10184 cd682800 [ 214.333957] cd767ea4 cba31064 cd767eb8 d0867908 cba31064 d087e09c cd96f034 cd767ec4 [ 214.333957] Call Trace: [ 214.333957] [] ? skb_dequeue+0x49/0x60 [ 214.333957] [] destroy_workqueue+0xd/0x150 [ 214.333957] [] ieee80211_unregister_hw+0xc4/0x100 [mac80211] [ 214.333957] [] b43legacy_remove+0x78/0x80 [b43legacy] [ 214.333957] [] ssb_device_remove+0x1d/0x30 [ssb] [ 214.333957] [] __device_release_driver+0x5a/0xb0 [ 214.333957] [] driver_detach+0x87/0x90 [ 214.333957] [] bus_remove_driver+0x6c/0xe0 [ 214.333957] [] driver_unregister+0x40/0x70 [ 214.333957] [] ssb_driver_unregister+0xb/0x10 [ssb] [ 214.333957] [] b43legacy_exit+0xd/0xf [b43legacy] [ 214.333957] [] sys_delete_module+0x14e/0x2b0 [ 214.333957] [] ? vfs_write+0xf7/0x150 [ 214.333957] [] ? tty_write_lock+0x50/0x50 [ 214.333957] [] ? sys_write+0x38/0x70 [ 214.333957] [] syscall_call+0x7/0xb [ 214.333957] Code: bc 27 00 00 00 00 a1 74 61 56 c1 55 89 e5 e8 a3 fc ff ff 5d c3 90 55 89 e5 57 56 89 c6 53 b8 40 ac 62 c1 83 ec 14 e8 bb b7 34 00 <8b> 46 4c 8d 50 01 85 c0 89 56 4c 75 03 83 0e 40 80 05 40 ac 62 [ 214.333957] EIP: [] drain_workqueue+0x15/0x170 SS:ESP 0068:cd767e5c [ 214.333957] CR2: 000000000000004c [ 214.341110] ---[ end trace c7e90ec026d875a6 ]---Index: wireless-testing/drivers/net/wireless/b43legacy/main.c The problem is fixed by making certain that the ucode pointer is not NULL before deregistering the driver in mac80211. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/b43legacy/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index a98db30b7ac..0f30c07e919 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3892,6 +3892,8 @@ static void b43legacy_remove(struct ssb_device *dev) cancel_work_sync(&wl->firmware_load); B43legacy_WARN_ON(!wl); + if (!wldev->fw.ucode) + return; /* NULL if fw never loaded */ if (wl->current_dev == wldev) ieee80211_unregister_hw(wl->hw); From ed02004f896be60f6d5dc3af403999f56a3e6d37 Mon Sep 17 00:00:00 2001 From: Khalid Aziz Date: Mon, 10 Sep 2012 12:52:42 -0600 Subject: [PATCH 1064/2357] firmware: Add missing attributes to EFI variable attribute print out from sysfs commit 7083909023bbe29b3176e92d2d089def1aa7aa1e upstream. Some of the EFI variable attributes are missing from print out from /sys/firmware/efi/vars/*/attributes. This patch adds those in. It also updates code to use pre-defined constants for masking current value of attributes. Signed-off-by: Khalid Aziz Reviewed-by: Kees Cook Acked-by: Matthew Garrett Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/efivars.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 47408e802ab..d10c9873dd9 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -435,12 +435,23 @@ efivar_attr_read(struct efivar_entry *entry, char *buf) if (status != EFI_SUCCESS) return -EIO; - if (var->Attributes & 0x1) + if (var->Attributes & EFI_VARIABLE_NON_VOLATILE) str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n"); - if (var->Attributes & 0x2) + if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n"); - if (var->Attributes & 0x4) + if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n"); + if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) + str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n"); + if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) + str += sprintf(str, + "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n"); + if (var->Attributes & + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) + str += sprintf(str, + "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n"); + if (var->Attributes & EFI_VARIABLE_APPEND_WRITE) + str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n"); return str - buf; } From 59b91d284b24d4ec17f917421b169fcb40805544 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 19 Sep 2012 16:27:26 -0700 Subject: [PATCH 1065/2357] xhci: Intel Panther Point BEI quirk. commit 80fab3b244a22e0ca539d2439bdda50e81e5666f upstream. When a device with an isochronous endpoint is behind a hub plugged into the Intel Panther Point xHCI host controller, and the driver submits multiple frames per URB, the xHCI driver will set the Block Event Interrupt (BEI) flag on all but the last TD for the URB. This causes the host controller to place an event on the event ring, but not send an interrupt. When the last TD for the URB completes, BEI is cleared, and we get an interrupt for the whole URB. However, under a Panther Point xHCI host controller, if the parent hub is unplugged when one or more events from transfers with BEI set are on the event ring, a port status change event is placed on the event ring, but no interrupt is generated. This means URBs stop completing, and the USB device disconnect is not noticed. Something like a USB headset will cause mplayer to hang when the device is disconnected. If another transfer is sent (such as running `sudo lsusb -v`), the next transfer event seems to "unstick" the event ring, the xHCI driver gets an interrupt, and the disconnect is reported to the USB core. The fix is not to use the BEI flag under the Panther Point xHCI host. This will impact power consumption and system responsiveness, because the xHCI driver will receive an interrupt for every frame in all isochronous URBs instead of once per URB. Intel chipset developers confirm that this bug will be hit if the BEI flag is used on any endpoint, not just ones that are behind a hub. This patch should be backported to kernels as old as 3.0, that contain the commit 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support EHCI/xHCI port switching." Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 1 + drivers/usb/host/xhci-ring.c | 4 +++- drivers/usb/host/xhci.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index f1527404617..4211017b889 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -99,6 +99,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) * PPT chipsets. */ xhci->quirks |= XHCI_SPURIOUS_REBOOT; + xhci->quirks |= XHCI_AVOID_BEI; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 203ba315c72..17383aa6924 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3400,7 +3400,9 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } else { td->last_trb = ep_ring->enqueue; field |= TRB_IOC; - if (xhci->hci_version == 0x100) { + if (xhci->hci_version == 0x100 && + !(xhci->quirks & + XHCI_AVOID_BEI)) { /* Set BEI bit except for the last td */ if (i < num_tds - 1) field |= TRB_BEI; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 6e77f3b5a7f..eeeef474ce6 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1488,6 +1488,7 @@ struct xhci_hcd { #define XHCI_TRUST_TX_LENGTH (1 << 10) #define XHCI_SPURIOUS_REBOOT (1 << 13) #define XHCI_COMP_MODE_QUIRK (1 << 14) +#define XHCI_AVOID_BEI (1 << 15) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ From 1976fffe9dc839e9d25c903a65723600f7641a50 Mon Sep 17 00:00:00 2001 From: Elric Fu Date: Wed, 27 Jun 2012 16:30:57 +0800 Subject: [PATCH 1066/2357] xHCI: add cmd_ring_state commit c181bc5b5d5c79b71203cd10cef97f802fb6f9c1 upstream. Adding cmd_ring_state for command ring. It helps to verify the current command ring state for controlling the command ring operations. This patch should be backported to kernels as old as 3.0. The commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an assertion to check for virt_dev=0 bug." papers over the NULL pointer dereference that I now believe is related to a timed out Set Address command. This (and the four patches that follow it) contain the real fix that also allows VIA USB 3.0 hubs to consistently re-enumerate during the plug/unplug stress tests. Signed-off-by: Elric Fu Signed-off-by: Sarah Sharp Tested-by: Miroslav Sabljic Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 3 +++ drivers/usb/host/xhci.c | 6 ++++-- drivers/usb/host/xhci.h | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 17383aa6924..f98dfedbc64 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -280,6 +280,9 @@ static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, /* Ring the host controller doorbell after placing a command on the ring */ void xhci_ring_cmd_db(struct xhci_hcd *xhci) { + if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) + return; + xhci_dbg(xhci, "// Ding dong!\n"); xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]); /* Flush PCI posted writes */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 495c7a3a997..e209b682898 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -105,9 +105,10 @@ int xhci_halt(struct xhci_hcd *xhci) ret = handshake(xhci, &xhci->op_regs->status, STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); - if (!ret) + if (!ret) { xhci->xhc_state |= XHCI_STATE_HALTED; - else + xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; + } else xhci_warn(xhci, "Host not halted after %u microseconds.\n", XHCI_MAX_HALT_USEC); return ret; @@ -583,6 +584,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci) return -ENODEV; } xhci->shared_hcd->state = HC_STATE_RUNNING; + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; if (xhci->quirks & XHCI_NEC_HOST) xhci_ring_cmd_db(xhci); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index eeeef474ce6..75722b70bba 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1417,6 +1417,10 @@ struct xhci_hcd { /* data structures */ struct xhci_device_context_array *dcbaa; struct xhci_ring *cmd_ring; + unsigned int cmd_ring_state; +#define CMD_RING_STATE_RUNNING (1 << 0) +#define CMD_RING_STATE_ABORTED (1 << 1) +#define CMD_RING_STATE_STOPPED (1 << 2) unsigned int cmd_ring_reserved_trbs; struct xhci_ring *event_ring; struct xhci_erst erst; From 2818247b6565b7adfbcd53b74509448a8e1fad84 Mon Sep 17 00:00:00 2001 From: Elric Fu Date: Wed, 27 Jun 2012 16:31:12 +0800 Subject: [PATCH 1067/2357] xHCI: add aborting command ring function commit b92cc66c047ff7cf587b318fe377061a353c120f upstream. Software have to abort command ring and cancel command when a command is failed or hang. Otherwise, the command ring will hang up and can't handle the others. An example of a command that may hang is the Address Device Command, because waiting for a SET_ADDRESS request to be acknowledged by a USB device is outside of the xHC's ability to control. To cancel a command, software will initialize a command descriptor for the cancel command, and add it into a cancel_cmd_list of xhci. Sarah: Fixed missing newline on "Have the command ring been stopped?" debugging statement. This patch should be backported to kernels as old as 3.0, that contain the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an assertion to check for virt_dev=0 bug." That commit papers over a NULL pointer dereference, and this patch fixes the underlying issue that caused the NULL pointer dereference. Signed-off-by: Elric Fu Signed-off-by: Sarah Sharp Tested-by: Miroslav Sabljic Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 7 +++ drivers/usb/host/xhci-ring.c | 108 +++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.c | 2 +- drivers/usb/host/xhci.h | 12 ++++ 4 files changed, 128 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 6b908249b01..cbed50ad9c1 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1772,6 +1772,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); struct dev_info *dev_info, *next; + struct xhci_cd *cur_cd, *next_cd; unsigned long flags; int size; int i, j, num_ports; @@ -1793,6 +1794,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; xhci_dbg(xhci, "Freed command ring\n"); + list_for_each_entry_safe(cur_cd, next_cd, + &xhci->cancel_cmd_list, cancel_cmd_list) { + list_del(&cur_cd->cancel_cmd_list); + kfree(cur_cd); + } for (i = 1; i < MAX_HC_SLOTS; ++i) xhci_free_virt_device(xhci, i); @@ -2338,6 +2344,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags); if (!xhci->cmd_ring) goto fail; + INIT_LIST_HEAD(&xhci->cancel_cmd_list); xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); xhci_dbg(xhci, "First segment DMA is 0x%llx\n", (unsigned long long)xhci->cmd_ring->first_seg->dma); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f98dfedbc64..729330e1ac3 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -289,6 +289,114 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci) xhci_readl(xhci, &xhci->dba->doorbell[0]); } +static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) +{ + u64 temp_64; + int ret; + + xhci_dbg(xhci, "Abort command ring\n"); + + if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) { + xhci_dbg(xhci, "The command ring isn't running, " + "Have the command ring been stopped?\n"); + return 0; + } + + temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); + if (!(temp_64 & CMD_RING_RUNNING)) { + xhci_dbg(xhci, "Command ring had been stopped\n"); + return 0; + } + xhci->cmd_ring_state = CMD_RING_STATE_ABORTED; + xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, + &xhci->op_regs->cmd_ring); + + /* Section 4.6.1.2 of xHCI 1.0 spec says software should + * time the completion od all xHCI commands, including + * the Command Abort operation. If software doesn't see + * CRR negated in a timely manner (e.g. longer than 5 + * seconds), then it should assume that the there are + * larger problems with the xHC and assert HCRST. + */ + ret = handshake(xhci, &xhci->op_regs->cmd_ring, + CMD_RING_RUNNING, 0, 5 * 1000 * 1000); + if (ret < 0) { + xhci_err(xhci, "Stopped the command ring failed, " + "maybe the host is dead\n"); + xhci->xhc_state |= XHCI_STATE_DYING; + xhci_quiesce(xhci); + xhci_halt(xhci); + return -ESHUTDOWN; + } + + return 0; +} + +static int xhci_queue_cd(struct xhci_hcd *xhci, + struct xhci_command *command, + union xhci_trb *cmd_trb) +{ + struct xhci_cd *cd; + cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC); + if (!cd) + return -ENOMEM; + INIT_LIST_HEAD(&cd->cancel_cmd_list); + + cd->command = command; + cd->cmd_trb = cmd_trb; + list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list); + + return 0; +} + +/* + * Cancel the command which has issue. + * + * Some commands may hang due to waiting for acknowledgement from + * usb device. It is outside of the xHC's ability to control and + * will cause the command ring is blocked. When it occurs software + * should intervene to recover the command ring. + * See Section 4.6.1.1 and 4.6.1.2 + */ +int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, + union xhci_trb *cmd_trb) +{ + int retval = 0; + unsigned long flags; + + spin_lock_irqsave(&xhci->lock, flags); + + if (xhci->xhc_state & XHCI_STATE_DYING) { + xhci_warn(xhci, "Abort the command ring," + " but the xHCI is dead.\n"); + retval = -ESHUTDOWN; + goto fail; + } + + /* queue the cmd desriptor to cancel_cmd_list */ + retval = xhci_queue_cd(xhci, command, cmd_trb); + if (retval) { + xhci_warn(xhci, "Queuing command descriptor failed.\n"); + goto fail; + } + + /* abort command ring */ + retval = xhci_abort_cmd_ring(xhci); + if (retval) { + xhci_err(xhci, "Abort command ring failed\n"); + if (unlikely(retval == -ESHUTDOWN)) { + spin_unlock_irqrestore(&xhci->lock, flags); + usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); + xhci_dbg(xhci, "xHCI host controller is dead.\n"); + return retval; + } + } + +fail: + spin_unlock_irqrestore(&xhci->lock, flags); + return retval; +} + void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index e209b682898..9cc368731c8 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -52,7 +52,7 @@ MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); * handshake done). There are two failure modes: "usec" have passed (major * hardware flakeout), or the register reads as all-ones (hardware removed). */ -static int handshake(struct xhci_hcd *xhci, void __iomem *ptr, +int handshake(struct xhci_hcd *xhci, void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 75722b70bba..6456a56e6d2 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1252,6 +1252,13 @@ struct xhci_td { union xhci_trb *last_trb; }; +/* command descriptor */ +struct xhci_cd { + struct list_head cancel_cmd_list; + struct xhci_command *command; + union xhci_trb *cmd_trb; +}; + struct xhci_dequeue_state { struct xhci_segment *new_deq_seg; union xhci_trb *new_deq_ptr; @@ -1421,6 +1428,7 @@ struct xhci_hcd { #define CMD_RING_STATE_RUNNING (1 << 0) #define CMD_RING_STATE_ABORTED (1 << 1) #define CMD_RING_STATE_STOPPED (1 << 2) + struct list_head cancel_cmd_list; unsigned int cmd_ring_reserved_trbs; struct xhci_ring *event_ring; struct xhci_erst erst; @@ -1699,6 +1707,8 @@ static inline void xhci_unregister_plat(void) /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); +int handshake(struct xhci_hcd *xhci, void __iomem *ptr, + u32 mask, u32 done, int usec); void xhci_quiesce(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci); int xhci_reset(struct xhci_hcd *xhci); @@ -1789,6 +1799,8 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_dequeue_state *deq_state); void xhci_stop_endpoint_command_watchdog(unsigned long arg); +int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, + union xhci_trb *cmd_trb); void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id); From 75382341d888ba0132c5eeb94711840acf972034 Mon Sep 17 00:00:00 2001 From: Elric Fu Date: Wed, 27 Jun 2012 16:31:52 +0800 Subject: [PATCH 1068/2357] xHCI: cancel command after command timeout commit 6e4468b9a0793dfb53eb80d9fe52c739b13b27fd upstream. The patch is used to cancel command when the command isn't acknowledged and a timeout occurs. This patch should be backported to kernels as old as 3.0, that contain the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an assertion to check for virt_dev=0 bug." That commit papers over a NULL pointer dereference, and this patch fixes the underlying issue that caused the NULL pointer dereference. Signed-off-by: Elric Fu Signed-off-by: Sarah Sharp Tested-by: Miroslav Sabljic Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 26 +++++++++++++++++++------- drivers/usb/host/xhci.h | 3 +++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9cc368731c8..dc24c37b1ad 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2525,6 +2525,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, struct completion *cmd_completion; u32 *cmd_status; struct xhci_virt_device *virt_dev; + union xhci_trb *cmd_trb; spin_lock_irqsave(&xhci->lock, flags); virt_dev = xhci->devs[udev->slot_id]; @@ -2570,6 +2571,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, } init_completion(cmd_completion); + cmd_trb = xhci->cmd_ring->dequeue; if (!ctx_change) ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, udev->slot_id, must_succeed); @@ -2591,14 +2593,17 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, /* Wait for the configure endpoint command to complete */ timeleft = wait_for_completion_interruptible_timeout( cmd_completion, - USB_CTRL_SET_TIMEOUT); + XHCI_CMD_DEFAULT_TIMEOUT); if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for %s command\n", timeleft == 0 ? "Timeout" : "Signal", ctx_change == 0 ? "configure endpoint" : "evaluate context"); - /* FIXME cancel the configure endpoint command */ + /* cancel the configure endpoint command */ + ret = xhci_cancel_cmd(xhci, command, cmd_trb); + if (ret < 0) + return ret; return -ETIME; } @@ -3547,8 +3552,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) unsigned long flags; int timeleft; int ret; + union xhci_trb *cmd_trb; spin_lock_irqsave(&xhci->lock, flags); + cmd_trb = xhci->cmd_ring->dequeue; ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0); if (ret) { spin_unlock_irqrestore(&xhci->lock, flags); @@ -3560,12 +3567,12 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) /* XXX: how much time for xHC slot assignment? */ timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, - USB_CTRL_SET_TIMEOUT); + XHCI_CMD_DEFAULT_TIMEOUT); if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for a slot\n", timeleft == 0 ? "Timeout" : "Signal"); - /* FIXME cancel the enable slot request */ - return 0; + /* cancel the enable slot request */ + return xhci_cancel_cmd(xhci, NULL, cmd_trb); } if (!xhci->slot_id) { @@ -3626,6 +3633,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_slot_ctx *slot_ctx; struct xhci_input_control_ctx *ctrl_ctx; u64 temp_64; + union xhci_trb *cmd_trb; if (!udev->slot_id) { xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id); @@ -3664,6 +3672,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); spin_lock_irqsave(&xhci->lock, flags); + cmd_trb = xhci->cmd_ring->dequeue; ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, udev->slot_id); if (ret) { @@ -3676,7 +3685,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */ timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, - USB_CTRL_SET_TIMEOUT); + XHCI_CMD_DEFAULT_TIMEOUT); /* FIXME: From section 4.3.4: "Software shall be responsible for timing * the SetAddress() "recovery interval" required by USB and aborting the * command on a timeout. @@ -3684,7 +3693,10 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for address device command\n", timeleft == 0 ? "Timeout" : "Signal"); - /* FIXME cancel the address device command */ + /* cancel the address device command */ + ret = xhci_cancel_cmd(xhci, NULL, cmd_trb); + if (ret < 0) + return ret; return -ETIME; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 6456a56e6d2..5361fd8dfea 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1252,6 +1252,9 @@ struct xhci_td { union xhci_trb *last_trb; }; +/* xHCI command default timeout value */ +#define XHCI_CMD_DEFAULT_TIMEOUT (5 * HZ) + /* command descriptor */ struct xhci_cd { struct list_head cancel_cmd_list; From c4f132c4c23d6b822242c98def8be15182c24ff4 Mon Sep 17 00:00:00 2001 From: Elric Fu Date: Wed, 27 Jun 2012 16:55:43 +0800 Subject: [PATCH 1069/2357] xHCI: handle command after aborting the command ring commit b63f4053cc8aa22a98e3f9a97845afe6c15d0a0d upstream. According to xHCI spec section 4.6.1.1 and section 4.6.1.2, after aborting a command on the command ring, xHC will generate a command completion event with its completion code set to Command Ring Stopped at least. If a command is currently executing at the time of aborting a command, xHC also generate a command completion event with its completion code set to Command Abort. When the command ring is stopped, software may remove, add, or rearrage Command Descriptors. To cancel a command, software will initialize a command descriptor for the cancel command, and add it into a cancel_cmd_list of xhci. When the command ring is stopped, software will find the command trbs described by command descriptors in cancel_cmd_list and modify it to No Op command. If software can't find the matched trbs, we can think it had been finished. This patch should be backported to kernels as old as 3.0, that contain the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an assertion to check for virt_dev=0 bug." That commit papers over a NULL pointer dereference, and this patch fixes the underlying issue that caused the NULL pointer dereference. Signed-off-by: Elric Fu Signed-off-by: Sarah Sharp Tested-by: Miroslav Sabljic Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 171 +++++++++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 729330e1ac3..a23d71bba75 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1170,6 +1170,20 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci, } } +/* Complete the command and detele it from the devcie's command queue. + */ +static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, + struct xhci_command *command, u32 status) +{ + command->status = status; + list_del(&command->cmd_list); + if (command->completion) + complete(command->completion); + else + xhci_free_command(xhci, command); +} + + /* Check to see if a command in the device's command queue matches this one. * Signal the completion or free the command, and return 1. Return 0 if the * completed command isn't at the head of the command list. @@ -1188,15 +1202,144 @@ static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, if (xhci->cmd_ring->dequeue != command->command_trb) return 0; - command->status = GET_COMP_CODE(le32_to_cpu(event->status)); - list_del(&command->cmd_list); - if (command->completion) - complete(command->completion); - else - xhci_free_command(xhci, command); + xhci_complete_cmd_in_cmd_wait_list(xhci, command, + GET_COMP_CODE(le32_to_cpu(event->status))); return 1; } +/* + * Finding the command trb need to be cancelled and modifying it to + * NO OP command. And if the command is in device's command wait + * list, finishing and freeing it. + * + * If we can't find the command trb, we think it had already been + * executed. + */ +static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd) +{ + struct xhci_segment *cur_seg; + union xhci_trb *cmd_trb; + u32 cycle_state; + + if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue) + return; + + /* find the current segment of command ring */ + cur_seg = find_trb_seg(xhci->cmd_ring->first_seg, + xhci->cmd_ring->dequeue, &cycle_state); + + /* find the command trb matched by cd from command ring */ + for (cmd_trb = xhci->cmd_ring->dequeue; + cmd_trb != xhci->cmd_ring->enqueue; + next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) { + /* If the trb is link trb, continue */ + if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3])) + continue; + + if (cur_cd->cmd_trb == cmd_trb) { + + /* If the command in device's command list, we should + * finish it and free the command structure. + */ + if (cur_cd->command) + xhci_complete_cmd_in_cmd_wait_list(xhci, + cur_cd->command, COMP_CMD_STOP); + + /* get cycle state from the origin command trb */ + cycle_state = le32_to_cpu(cmd_trb->generic.field[3]) + & TRB_CYCLE; + + /* modify the command trb to NO OP command */ + cmd_trb->generic.field[0] = 0; + cmd_trb->generic.field[1] = 0; + cmd_trb->generic.field[2] = 0; + cmd_trb->generic.field[3] = cpu_to_le32( + TRB_TYPE(TRB_CMD_NOOP) | cycle_state); + break; + } + } +} + +static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci) +{ + struct xhci_cd *cur_cd, *next_cd; + + if (list_empty(&xhci->cancel_cmd_list)) + return; + + list_for_each_entry_safe(cur_cd, next_cd, + &xhci->cancel_cmd_list, cancel_cmd_list) { + xhci_cmd_to_noop(xhci, cur_cd); + list_del(&cur_cd->cancel_cmd_list); + kfree(cur_cd); + } +} + +/* + * traversing the cancel_cmd_list. If the command descriptor according + * to cmd_trb is found, the function free it and return 1, otherwise + * return 0. + */ +static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci, + union xhci_trb *cmd_trb) +{ + struct xhci_cd *cur_cd, *next_cd; + + if (list_empty(&xhci->cancel_cmd_list)) + return 0; + + list_for_each_entry_safe(cur_cd, next_cd, + &xhci->cancel_cmd_list, cancel_cmd_list) { + if (cur_cd->cmd_trb == cmd_trb) { + if (cur_cd->command) + xhci_complete_cmd_in_cmd_wait_list(xhci, + cur_cd->command, COMP_CMD_STOP); + list_del(&cur_cd->cancel_cmd_list); + kfree(cur_cd); + return 1; + } + } + + return 0; +} + +/* + * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the + * trb pointed by the command ring dequeue pointer is the trb we want to + * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will + * traverse the cancel_cmd_list to trun the all of the commands according + * to command descriptor to NO-OP trb. + */ +static int handle_stopped_cmd_ring(struct xhci_hcd *xhci, + int cmd_trb_comp_code) +{ + int cur_trb_is_good = 0; + + /* Searching the cmd trb pointed by the command ring dequeue + * pointer in command descriptor list. If it is found, free it. + */ + cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci, + xhci->cmd_ring->dequeue); + + if (cmd_trb_comp_code == COMP_CMD_ABORT) + xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; + else if (cmd_trb_comp_code == COMP_CMD_STOP) { + /* traversing the cancel_cmd_list and canceling + * the command according to command descriptor + */ + xhci_cancel_cmd_in_cd_list(xhci); + + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; + /* + * ring command ring doorbell again to restart the + * command ring + */ + if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) + xhci_ring_cmd_db(xhci); + } + return cur_trb_is_good; +} + static void handle_cmd_completion(struct xhci_hcd *xhci, struct xhci_event_cmd *event) { @@ -1222,6 +1365,22 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, xhci->error_bitmask |= 1 << 5; return; } + + if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) || + (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) { + /* If the return value is 0, we think the trb pointed by + * command ring dequeue pointer is a good trb. The good + * trb means we don't want to cancel the trb, but it have + * been stopped by host. So we should handle it normally. + * Otherwise, driver should invoke inc_deq() and return. + */ + if (handle_stopped_cmd_ring(xhci, + GET_COMP_CODE(le32_to_cpu(event->status)))) { + inc_deq(xhci, xhci->cmd_ring); + return; + } + } + switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3]) & TRB_TYPE_BITMASK) { case TRB_TYPE(TRB_ENABLE_SLOT): From e3a63e8c061c486ce46d8d825b3fdd45c14140de Mon Sep 17 00:00:00 2001 From: Michael Spang Date: Fri, 14 Sep 2012 13:05:49 -0400 Subject: [PATCH 1070/2357] Increase XHCI suspend timeout to 16ms commit a6e097dfdfd189b6929af6efa1d289af61858386 upstream. The Intel XHCI specification says that after clearing the run/stop bit the controller may take up to 16ms to halt. We've seen a device take 14ms, which with the current timeout of 10ms causes the kernel to abort the suspend. Increasing the timeout to the recommended value fixes the problem. This patch should be backported to kernels as old as 2.6.37, that contain the commit 5535b1d5f8885695c6ded783c692e3c0d0eda8ca "USB: xHCI: PCI power management implementation". Signed-off-by: Michael Spang Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index dc24c37b1ad..f7562315530 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -890,7 +890,7 @@ int xhci_suspend(struct xhci_hcd *xhci) command &= ~CMD_RUN; xhci_writel(xhci, command, &xhci->op_regs->command); if (handshake(xhci, &xhci->op_regs->status, - STS_HALT, STS_HALT, 100*100)) { + STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) { xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; From 92d9a683c431081038d715585e7da9d953cb09f2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 22 Sep 2012 00:14:28 +0530 Subject: [PATCH 1071/2357] ath9k: Disable ASPM only for AR9285 commit 046b6802c8d3c8a57448485513bf7291633e0fa3 upstream. Currently, ASPM is disabled for all WLAN+BT combo chipsets when BTCOEX is enabled. This is incorrect since the workaround is required only for WB195, which is a AR9285+AR3011 combo solution. Fix this by checking for the HW version when enabling the workaround. Signed-off-by: Sujith Manoharan Tested-by: Paul Stewart Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index e44097a7529..0e7d6c188cc 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -122,8 +122,9 @@ static void ath_pci_aspm_init(struct ath_common *common) if (!parent) return; - if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { - /* Bluetooth coexistance requires disabling ASPM. */ + if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && + (AR_SREV_9285(ah))) { + /* Bluetooth coexistance requires disabling ASPM for AR9285. */ pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm); aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm); From aa821c51dc6167556a3dc39fc518754f8650265c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Sep 2012 11:34:50 +1000 Subject: [PATCH 1072/2357] coredump: prevent double-free on an error path in core dumper commit f34f9d186df35e5c39163444c43b4fc6255e39c5 upstream. In !CORE_DUMP_USE_REGSET case, if elf_note_info_init fails to allocate memory for info->fields, it frees already allocated stuff and returns error to its caller, fill_note_info. Which in turn returns error to its caller, elf_core_dump. Which jumps to cleanup label and calls free_note_info, which will happily try to free all info->fields again. BOOM. This is the fix. Signed-off-by: Oleg Nesterov Signed-off-by: Denys Vlasenko Cc: Venu Byravarasu Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- fs/binfmt_elf.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 16f73541707..a009b9e322a 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1698,30 +1698,19 @@ static int elf_note_info_init(struct elf_note_info *info) return 0; info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); if (!info->psinfo) - goto notes_free; + return 0; info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL); if (!info->prstatus) - goto psinfo_free; + return 0; info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL); if (!info->fpu) - goto prstatus_free; + return 0; #ifdef ELF_CORE_COPY_XFPREGS info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL); if (!info->xfpu) - goto fpu_free; + return 0; #endif return 1; -#ifdef ELF_CORE_COPY_XFPREGS - fpu_free: - kfree(info->fpu); -#endif - prstatus_free: - kfree(info->prstatus); - psinfo_free: - kfree(info->psinfo); - notes_free: - kfree(info->notes); - return 0; } static int fill_note_info(struct elfhdr *elf, int phdrs, From 3e6ef23fbf8c22163602cd52729de2fe370fba8f Mon Sep 17 00:00:00 2001 From: xiaojin Date: Mon, 13 Aug 2012 13:43:15 +0100 Subject: [PATCH 1073/2357] n_gsm.c: Implement 3GPP27.010 DLC start-up procedure in MUX commit 7e8ac7b23b67416700dfb8b4136a4e81ce675b48 upstream. In 3GPP27.010 5.8.1, it defined: The TE multiplexer initiates the establishment of the multiplexer control channel by sending a SABM frame on DLCI 0 using the procedures of clause 5.4.1. Once the multiplexer channel is established other DLCs may be established using the procedures of clause 5.4.1. This patch implement 5.8.1 in MUX level, it make sure DLC0 is the first channel to be setup. [or for those not familiar with the specification: it was possible to try and open a data connection while the control channel was not yet fully open, which is a spec violation and confuses some modems] Signed-off-by: xiaojin Tested-by: Yin, Fengwei [tweaked the order we check things and error code] Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c43b683b6eb..0a73b59f797 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2889,6 +2889,10 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) gsm = gsm_mux[mux]; if (gsm->dead) return -EL2HLT; + /* If DLCI 0 is not yet fully open return an error. This is ok from a locking + perspective as we don't have to worry about this if DLCI0 is lost */ + if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) + return -EL2NSYNC; dlci = gsm->dlci[line]; if (dlci == NULL) dlci = gsm_dlci_alloc(gsm, line); From b0a3c588df225ee719bd82ab303d02f7cc0d5805 Mon Sep 17 00:00:00 2001 From: Russ Gorby Date: Mon, 13 Aug 2012 13:43:36 +0100 Subject: [PATCH 1074/2357] n_gsm: uplink SKBs accumulate on list commit 192b6041e75bb4a2aae73834037038cea139a92d upstream. gsm_dlci_data_kick will not call any output function if tx_bytes > THRESH_LO furthermore it will call the output function only once if tx_bytes == 0 If the size of the IP writes are on the order of THRESH_LO we can get into a situation where skbs accumulate on the outbound list being starved for events to call the output function. gsm_dlci_data_kick now calls the sweep function when tx_bytes==0 Signed-off-by: Russ Gorby Tested-by: Kappel, LaurentX Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 0a73b59f797..1720055ca97 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -971,16 +971,19 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) static void gsm_dlci_data_kick(struct gsm_dlci *dlci) { unsigned long flags; + int sweep; spin_lock_irqsave(&dlci->gsm->tx_lock, flags); /* If we have nothing running then we need to fire up */ + sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO); if (dlci->gsm->tx_bytes == 0) { if (dlci->net) gsm_dlci_data_output_framed(dlci->gsm, dlci); else gsm_dlci_data_output(dlci->gsm, dlci); - } else if (dlci->gsm->tx_bytes < TX_THRESH_LO) - gsm_dlci_data_sweep(dlci->gsm); + } + if (sweep) + gsm_dlci_data_sweep(dlci->gsm); spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags); } From 119bd47785006d185e8247f63f44c43eaf345ed9 Mon Sep 17 00:00:00 2001 From: Russ Gorby Date: Mon, 13 Aug 2012 13:44:40 +0100 Subject: [PATCH 1075/2357] n_gsm: added interlocking for gsm_data_lock for certain code paths commit 5e44708f75b0f8712da715d6babb0c21089b2317 upstream. There were some locking holes in the management of the MUX's message queue for 2 code paths: 1) gsmld_write_wakeup 2) receipt of CMD_FCON flow-control message In both cases gsm_data_kick is called w/o locking so it can collide with other other instances of gsm_data_kick (pulling messages tx_tail) or potentially other instances of __gsm_data_queu (adding messages to tx_head) Changed to take the tx_lock in these 2 cases Signed-off-by: Russ Gorby Tested-by: Yin, Fengwei Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 1720055ca97..671fbc2d793 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1193,6 +1193,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, u8 *data, int clen) { u8 buf[1]; + unsigned long flags; + switch (command) { case CMD_CLD: { struct gsm_dlci *dlci = gsm->dlci[0]; @@ -1218,7 +1220,9 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, gsm->constipated = 0; gsm_control_reply(gsm, CMD_FCOFF, NULL, 0); /* Kick the link in case it is idling */ + spin_lock_irqsave(&gsm->tx_lock, flags); gsm_data_kick(gsm); + spin_unlock_irqrestore(&gsm->tx_lock, flags); break; case CMD_MSC: /* Out of band modem line change indicator for a DLCI */ @@ -2380,12 +2384,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty) /* Queue poll */ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + spin_lock_irqsave(&gsm->tx_lock, flags); gsm_data_kick(gsm); if (gsm->tx_bytes < TX_THRESH_LO) { - spin_lock_irqsave(&gsm->tx_lock, flags); gsm_dlci_data_sweep(gsm); - spin_unlock_irqrestore(&gsm->tx_lock, flags); } + spin_unlock_irqrestore(&gsm->tx_lock, flags); } /** From 1168fb4bf41d55b04c07d82cb5c1e0fde9be3cf9 Mon Sep 17 00:00:00 2001 From: Russ Gorby Date: Mon, 13 Aug 2012 13:45:30 +0100 Subject: [PATCH 1076/2357] n_gsm: memory leak in uplink error path commit 88ed2a60610974443335c924d7cb8e5dcf9dbdc1 upstream. Uplink (TX) network data will go through gsm_dlci_data_output_framed there is a bug where if memory allocation fails, the skb which has already been pulled off the list will be lost. In addition TX skbs were being processed in LIFO order Fixed the memory leak, and changed to FIFO order processing Signed-off-by: Russ Gorby Tested-by: Kappel, LaurentX Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 671fbc2d793..90dff8233ef 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -875,7 +875,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, /* dlci->skb is locked by tx_lock */ if (dlci->skb == NULL) { - dlci->skb = skb_dequeue(&dlci->skb_list); + dlci->skb = skb_dequeue_tail(&dlci->skb_list); if (dlci->skb == NULL) return 0; first = 1; @@ -899,8 +899,11 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, /* FIXME: need a timer or something to kick this so it can't get stuck with no work outstanding and no buffer free */ - if (msg == NULL) + if (msg == NULL) { + skb_queue_tail(&dlci->skb_list, dlci->skb); + dlci->skb = NULL; return -ENOMEM; + } dp = msg->data; if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */ From 56a631f3bf36641133afeb3db7c1ec5721c8dd04 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sat, 18 Aug 2012 14:11:42 +0200 Subject: [PATCH 1077/2357] UBI: fix autoresize handling in R/O mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit abb3e01103eb4e2ea5c15e6fedbc74e08bd4cc2b upstream. Currently UBI fails in autoresize when it is in R/O mode (e.g., because the underlying MTD device is R/O). This patch fixes the issue - we just skip autoresize and print a warning. Reported-by: Pali Rohár Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/build.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 0fde9fc7d2e..83bab2c7983 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -816,6 +816,11 @@ static int autoresize(struct ubi_device *ubi, int vol_id) struct ubi_volume *vol = ubi->volumes[vol_id]; int err, old_reserved_pebs = vol->reserved_pebs; + if (ubi->ro_mode) { + ubi_warn("skip auto-resize because of R/O mode"); + return 0; + } + /* * Clear the auto-resize flag in the volume in-memory copy of the * volume table, and 'ubi_resize_volume()' will propagate this change From 7d0fcfec4c491eb3c815929be5512ae8d1886553 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 27 Aug 2012 11:38:13 -0700 Subject: [PATCH 1078/2357] Yama: handle 32-bit userspace prctl commit 2e4930eb7c8fb20a39dfb5f8a8f80402710dcea8 upstream. When running a 64-bit kernel and receiving prctls from a 32-bit userspace, the "-1" used as an unsigned long will end up being misdetected. The kernel is looking for 0xffffffffffffffff instead of 0xffffffff. Since prctl lacks a distinct compat interface, Yama needs to handle this translation itself. As such, support either value as meaning PR_SET_PTRACER_ANY, to avoid breaking the ABI for 64-bit. Signed-off-by: Kees Cook Acked-by: John Johansen Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- security/yama/yama_lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 573723843a0..1d6bf24c117 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -138,7 +138,7 @@ static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, if (arg2 == 0) { yama_ptracer_del(NULL, myself); rc = 0; - } else if (arg2 == PR_SET_PTRACER_ANY) { + } else if (arg2 == PR_SET_PTRACER_ANY || (int)arg2 == -1) { rc = yama_ptracer_add(NULL, myself); } else { struct task_struct *tracer; From 54ce2fb86f0b78808c7fcc1d581ebbf15ca36e91 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 30 Jul 2012 11:33:05 +1000 Subject: [PATCH 1079/2357] SCSI: ibmvscsi: Fix host config length field overflow commit 225c56960fcafeccc2b6304f96cd3f0dbf42a16a upstream. The length field in the host config packet is only 16-bit long, so passing it 0x10000 (64K which is our standard PAGE_SIZE) doesn't work and result in an empty config from the server. Signed-off-by: Benjamin Herrenschmidt Acked-by: Robert Jennings Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ibmvscsi/ibmvscsi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 3a6c4742951..337e8b33d9a 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1541,6 +1541,9 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, host_config = &evt_struct->iu.mad.host_config; + /* The transport length field is only 16-bit */ + length = min(0xffff, length); + /* Set up a lun reset SRP command */ memset(host_config, 0x00, sizeof(*host_config)); host_config->common.type = VIOSRP_HOST_CONFIG_TYPE; From 7b5c87e0163ad33aabb1a725b0b5444a7e0b5c73 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 26 Jul 2012 11:34:10 -0500 Subject: [PATCH 1080/2357] SCSI: hpsa: Use LUN reset instead of target reset commit 21e89afd325849eb38adccf382df16cc895911f9 upstream. It turns out Smart Array logical drives do not support target reset and when the target reset fails, the logical drive will be taken off line. Symptoms look like this: hpsa 0000:03:00.0: Abort request on C1:B0:T0:L0 hpsa 0000:03:00.0: resetting device 1:0:0:0 hpsa 0000:03:00.0: cp ffff880037c56000 is reported invalid (probably means target device no longer present) hpsa 0000:03:00.0: resetting device failed. sd 1:0:0:0: Device offlined - not ready after error recovery sd 1:0:0:0: rejecting I/O to offline device EXT3-fs error (device sdb1): read_block_bitmap: LUN reset is supported though, and is what we should be using. Target reset is also disruptive in shared SAS situations, for example, an external MSA1210m which does support target reset attached to Smart Arrays in multiple hosts -- a target reset from one host is disruptive to other hosts as all LUNs on the target will be reset and will abort all outstanding i/os back to all the attached hosts. So we should use LUN reset, not target reset. Tested this with Smart Array logical drives and with tape drives. Not sure how this bug survived since 2009, except it must be very rare for a Smart Array to require more than 30s to complete a request. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7c49e0ab90e..8a5e25d2f21 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2943,7 +2943,7 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.Timeout = 0; /* Don't time out */ memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); c->Request.CDB[0] = cmd; - c->Request.CDB[1] = 0x03; /* Reset target above */ + c->Request.CDB[1] = HPSA_RESET_TYPE_LUN; /* If bytes 4-7 are zero, it means reset the */ /* LunID device */ c->Request.CDB[4] = 0x00; From 0f0c5909d4cf6016c536fceddd5ca7bded0e5219 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 21 Sep 2012 15:09:47 +0800 Subject: [PATCH 1081/2357] can: mscan-mpc5xxx: fix return value check in mpc512x_can_get_clock() commit f61bd0585dfc7d99db4936d7467de4ca8e2f7ea0 upstream. In case of error, the function clk_get() returns ERR_PTR() and never returns NULL pointer. The NULL test in the error handling should be replaced with IS_ERR(). dpatch engine is used to auto generated this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Acked-by: Wolfgang Grandegger Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/mscan/mpc5xxx_can.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index 5caa572d71e..957f000263d 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -181,7 +181,7 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, if (!clock_name || !strcmp(clock_name, "sys")) { sys_clk = clk_get(&ofdev->dev, "sys_clk"); - if (!sys_clk) { + if (IS_ERR(sys_clk)) { dev_err(&ofdev->dev, "couldn't get sys_clk\n"); goto exit_unmap; } @@ -204,7 +204,7 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, if (clocksrc < 0) { ref_clk = clk_get(&ofdev->dev, "ref_clk"); - if (!ref_clk) { + if (IS_ERR(ref_clk)) { dev_err(&ofdev->dev, "couldn't get ref_clk\n"); goto exit_unmap; } From abe988511dc075dab47ba9283c791299f7285aaa Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Sun, 30 Sep 2012 10:25:34 +0200 Subject: [PATCH 1082/2357] remoteproc: select VIRTIO to avoid build breakage commit 2ed6d29c725c4aead510b5c23f563795b265acf5 upstream. drivers/built-in.o: In function `rproc_virtio_finalize_features': remoteproc_virtio.c:(.text+0x2f9a02): undefined reference to `vring_transport_features' drivers/built-in.o: In function `rproc_virtio_del_vqs': remoteproc_virtio.c:(.text+0x2f9a74): undefined reference to `vring_del_virtqueue' drivers/built-in.o: In function `rproc_virtio_find_vqs': remoteproc_virtio.c:(.text+0x2f9c44): undefined reference to `vring_new_virtqueue' drivers/built-in.o: In function `rproc_add_virtio_dev': (.text+0x2f9e2c): undefined reference to `register_virtio_device' drivers/built-in.o: In function `rproc_vq_interrupt': (.text+0x2f9db7): undefined reference to `vring_interrupt' drivers/built-in.o: In function `rproc_remove_virtio_dev': (.text+0x2f9e9f): undefined reference to `unregister_virtio_device' Reported-by: Randy Dunlap Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/remoteproc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index f8d818abf98..811ff72df4d 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -5,6 +5,7 @@ config REMOTEPROC tristate depends on EXPERIMENTAL select FW_CONFIG + select VIRTIO config OMAP_REMOTEPROC tristate "OMAP remoteproc support" From cbc7a8263c6e2d8f7354b4c06e21607d6dffd6bd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 25 Sep 2012 10:01:56 +0300 Subject: [PATCH 1083/2357] remoteproc: fix a potential NULL-dereference on cleanup commit 7168d914a782086e217214c57ddfc7cc4b738c0c upstream. We only need to allocate mapping if there is an IOMMU domain. Otherwise, when the mappings are released, the assumption that an IOMMU domain is there will crash and burn. Signed-off-by: Dan Carpenter [ohad: revise commit log] Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- drivers/remoteproc/remoteproc_core.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 7591b9774d0..837cc40180a 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -643,17 +643,10 @@ static int rproc_handle_carveout(struct rproc *rproc, dev_dbg(dev, "carveout rsc: da %x, pa %x, len %x, flags %x\n", rsc->da, rsc->pa, rsc->len, rsc->flags); - mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); - if (!mapping) { - dev_err(dev, "kzalloc mapping failed\n"); - return -ENOMEM; - } - carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); if (!carveout) { dev_err(dev, "kzalloc carveout failed\n"); - ret = -ENOMEM; - goto free_mapping; + return -ENOMEM; } va = dma_alloc_coherent(dev, rsc->len, &dma, GFP_KERNEL); @@ -683,11 +676,18 @@ static int rproc_handle_carveout(struct rproc *rproc, * physical address in this case. */ if (rproc->domain) { + mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); + if (!mapping) { + dev_err(dev, "kzalloc mapping failed\n"); + ret = -ENOMEM; + goto dma_free; + } + ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len, rsc->flags); if (ret) { dev_err(dev, "iommu_map failed: %d\n", ret); - goto dma_free; + goto free_mapping; } /* @@ -728,12 +728,12 @@ static int rproc_handle_carveout(struct rproc *rproc, return 0; +free_mapping: + kfree(mapping); dma_free: dma_free_coherent(dev, rsc->len, va, dma); free_carv: kfree(carveout); -free_mapping: - kfree(mapping); return ret; } From 350f3edb0a05c340853c75f4c5007a72ebd9e32f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 30 Aug 2012 07:01:30 +0000 Subject: [PATCH 1084/2357] IPoIB: Fix use-after-free of multicast object commit bea1e22df494a729978e7f2c54f7bda328f74bc3 upstream. Fix a crash in ipoib_mcast_join_task(). (with help from Or Gerlitz) Commit c8c2afe360b7 ("IPoIB: Use rtnl lock/unlock when changing device flags") added a call to rtnl_lock() in ipoib_mcast_join_task(), which is run from the ipoib_workqueue, and hence the workqueue can't be flushed from the context of ipoib_stop(). In the current code, ipoib_stop() (which doesn't flush the workqueue) calls ipoib_mcast_dev_flush(), which goes and deletes all the multicast entries. This takes place without any synchronization with a possible running instance of ipoib_mcast_join_task() for the same ipoib device, leading to a crash due to NULL pointer dereference. Fix this by making sure that the workqueue is flushed before ipoib_mcast_dev_flush() is called. To make that possible, we move the RTNL-lock wrapped code to ipoib_mcast_join_finish(). Signed-off-by: Patrick McHardy Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 +- .../infiniband/ulp/ipoib/ipoib_multicast.c | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 3974c290b66..69b23c22d4e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -148,7 +148,7 @@ static int ipoib_stop(struct net_device *dev) netif_stop_queue(dev); - ipoib_ib_dev_down(dev, 0); + ipoib_ib_dev_down(dev, 1); ipoib_ib_dev_stop(dev, 0); if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 20ebc6fd1bb..213965d5bc8 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -190,7 +190,9 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, mcast->mcmember = *mcmember; - /* Set the cached Q_Key before we attach if it's the broadcast group */ + /* Set the multicast MTU and cached Q_Key before we attach if it's + * the broadcast group. + */ if (!memcmp(mcast->mcmember.mgid.raw, priv->dev->broadcast + 4, sizeof (union ib_gid))) { spin_lock_irq(&priv->lock); @@ -198,10 +200,17 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, spin_unlock_irq(&priv->lock); return -EAGAIN; } + priv->mcast_mtu = IPOIB_UD_MTU(ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu)); priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey); spin_unlock_irq(&priv->lock); priv->tx_wr.wr.ud.remote_qkey = priv->qkey; set_qkey = 1; + + if (!ipoib_cm_admin_enabled(dev)) { + rtnl_lock(); + dev_set_mtu(dev, min(priv->mcast_mtu, priv->admin_mtu)); + rtnl_unlock(); + } } if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { @@ -589,14 +598,6 @@ void ipoib_mcast_join_task(struct work_struct *work) return; } - priv->mcast_mtu = IPOIB_UD_MTU(ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu)); - - if (!ipoib_cm_admin_enabled(dev)) { - rtnl_lock(); - dev_set_mtu(dev, min(priv->mcast_mtu, priv->admin_mtu)); - rtnl_unlock(); - } - ipoib_dbg_mcast(priv, "successfully joined all multicast groups\n"); clear_bit(IPOIB_MCAST_RUN, &priv->flags); From 0e4765fd9c0f8df577e0b8cbea927c2051710f27 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 24 Aug 2012 10:27:54 +0000 Subject: [PATCH 1085/2357] IB/srp: Fix use-after-free in srp_reset_req() commit 9b796d06d5d1b1e85ae2316a283ea11dd739ef96 upstream. srp_free_req() uses the scsi_cmnd structure contents to unmap buffers, so we must invoke srp_free_req() before we release ownership of that structure. Signed-off-by: Bart Van Assche Acked-by: David Dillow Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srp/ib_srp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 1b5b0c73005..ac66e6b43ee 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -638,9 +638,9 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL); if (scmnd) { + srp_free_req(target, req, scmnd, 0); scmnd->result = DID_RESET << 16; scmnd->scsi_done(scmnd); - srp_free_req(target, req, scmnd, 0); } } From 22fb582405002812d8fb89d0ed1264e97d3d25ad Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 24 Aug 2012 10:29:11 +0000 Subject: [PATCH 1086/2357] IB/srp: Avoid having aborted requests hang commit d8536670916a685df116b5c2cb256573fd25e4e3 upstream. We need to call scsi_done() for commands after we abort them. Signed-off-by: Bart Van Assche Acked-by: David Dillow Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srp/ib_srp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index ac66e6b43ee..922d845f76b 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1687,6 +1687,7 @@ static int srp_abort(struct scsi_cmnd *scmnd) SRP_TSK_ABORT_TASK); srp_free_req(target, req, scmnd, 0); scmnd->result = DID_ABORT << 16; + scmnd->scsi_done(scmnd); return SUCCESS; } From b4d4dc33a372aaee2205d4506b4c7ead6275067d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Jun 2012 11:31:14 -0700 Subject: [PATCH 1087/2357] isci: fix isci_pci_probe() generates warning on efi failure path commit 6d70a74ffd616073a68ae0974d98819bfa8e6da6 upstream. The oem parameter image embedded in the efi variable is at an offset from the start of the variable. However, in the failure path we try to free the 'orom' pointer which is only valid when the paramaters are being read from the legacy option-rom space. Since failure to load the oem parameters is unlikely and we keep the memory around in the success case just defer all de-allocation to devm. Reported-by: Don Morris Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/isci/init.c | 1 - drivers/scsi/isci/probe_roms.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index bc6cf888631..4c150dffb1a 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -481,7 +481,6 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic orom->hdr.version)) { dev_warn(&pdev->dev, "[%d]: invalid oem parameters detected, falling back to firmware\n", i); - devm_kfree(&pdev->dev, orom); orom = NULL; break; } diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c index 9b8117b9d75..4c66f4682fd 100644 --- a/drivers/scsi/isci/probe_roms.c +++ b/drivers/scsi/isci/probe_roms.c @@ -104,7 +104,6 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev) if (i >= len) { dev_err(&pdev->dev, "oprom parse error\n"); - devm_kfree(&pdev->dev, rom); rom = NULL; } pci_unmap_biosrom(oprom); From 4a3bb116ee8ab2f912fdb6d2af40028b15825151 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 22 Aug 2012 13:03:48 +0300 Subject: [PATCH 1088/2357] x86/alternatives: Fix p6 nops on non-modular kernels commit cb09cad44f07044d9810f18f6f9a6a6f3771f979 upstream. Probably a leftover from the early days of self-patching, p6nops are marked __initconst_or_module, which causes them to be discarded in a non-modular kernel. If something later triggers patching, it will overwrite kernel code with garbage. Reported-by: Tomas Racek Signed-off-by: Avi Kivity Cc: Michael Tokarev Cc: Borislav Petkov Cc: Marcelo Tosatti Cc: qemu-devel@nongnu.org Cc: Anthony Liguori Cc: H. Peter Anvin Cc: Alan Cox Cc: Alan Cox Link: http://lkml.kernel.org/r/5034AE84.90708@redhat.com Signed-off-by: Ingo Molnar Cc: Ben Jencks Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/alternative.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 73ef56c5a8b..bda833c5f6c 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -160,7 +160,7 @@ static const unsigned char * const k7_nops[ASM_NOP_MAX+2] = #endif #ifdef P6_NOP1 -static const unsigned char __initconst_or_module p6nops[] = +static const unsigned char p6nops[] = { P6_NOP1, P6_NOP2, From b8d54c01874da4e548a531b77a29c21236ce8a31 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 28 Aug 2012 22:12:10 -0700 Subject: [PATCH 1089/2357] SCSI: scsi_remove_target: fix softlockup regression on hot remove commit bc3f02a795d3b4faa99d37390174be2a75d091bd upstream. John reports: BUG: soft lockup - CPU#2 stuck for 23s! [kworker/u:8:2202] [..] Call Trace: [] scsi_remove_target+0xda/0x1f0 [] sas_rphy_remove+0x55/0x60 [] sas_rphy_delete+0x11/0x20 [] sas_port_delete+0x25/0x160 [] mptsas_del_end_device+0x183/0x270 ...introduced by commit 3b661a9 "[SCSI] fix hot unplug vs async scan race". Don't restart lookup of more stargets in the multi-target case, just arrange to traverse the list once, on the assumption that new targets are always added at the end. There is no guarantee that the target will change state in scsi_target_reap() so we can end up spinning if we restart. Acked-by: Jack Wang LKML-Reference: Reported-by: John Drescher Tested-by: John Drescher Signed-off-by: Dan Williams Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_sysfs.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index bb7c4828acc..08d48a3b767 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1023,33 +1023,31 @@ static void __scsi_remove_target(struct scsi_target *starget) void scsi_remove_target(struct device *dev) { struct Scsi_Host *shost = dev_to_shost(dev->parent); - struct scsi_target *starget, *found; + struct scsi_target *starget, *last = NULL; unsigned long flags; - restart: - found = NULL; + /* remove targets being careful to lookup next entry before + * deleting the last + */ spin_lock_irqsave(shost->host_lock, flags); list_for_each_entry(starget, &shost->__targets, siblings) { if (starget->state == STARGET_DEL) continue; if (starget->dev.parent == dev || &starget->dev == dev) { - found = starget; - found->reap_ref++; - break; + /* assuming new targets arrive at the end */ + starget->reap_ref++; + spin_unlock_irqrestore(shost->host_lock, flags); + if (last) + scsi_target_reap(last); + last = starget; + __scsi_remove_target(starget); + spin_lock_irqsave(shost->host_lock, flags); } } spin_unlock_irqrestore(shost->host_lock, flags); - if (found) { - __scsi_remove_target(found); - scsi_target_reap(found); - /* in the case where @dev has multiple starget children, - * continue removing. - * - * FIXME: does such a case exist? - */ - goto restart; - } + if (last) + scsi_target_reap(last); } EXPORT_SYMBOL(scsi_remove_target); From ead94148559d54f0aae235dda91dfb98dfb1eae7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 24 Aug 2012 09:08:41 +0000 Subject: [PATCH 1090/2357] SCSI: scsi_dh_alua: Enable STPG for unavailable ports commit e47f8976d8e573928824a06748f7bc82c58d747f upstream. A quote from SPC-4: "While in the unavailable primary target port asymmetric access state, the device server shall support those of the following commands that it supports while in the active/optimized state: [ ... ] d) SET TARGET PORT GROUPS; [ ... ]". Hence enable sending STPG to a target port group that is in the unavailable state. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Acked-by: Hannes Reinecke Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/device_handler/scsi_dh_alua.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 04c5cea47a2..3a8ba3e433d 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -583,8 +583,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) h->state = TPGS_STATE_STANDBY; break; case TPGS_STATE_OFFLINE: - case TPGS_STATE_UNAVAILABLE: - /* Path unusable for unavailable/offline */ + /* Path unusable */ err = SCSI_DH_DEV_OFFLINED; break; default: From 399abb8918aa5cef74a1d5c582bc7c08c8c99757 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 7 Oct 2012 08:32:45 -0700 Subject: [PATCH 1091/2357] Linux 3.4.13 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bcf5bc455a9..75b37ce4f1e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 12 +SUBLEVEL = 13 EXTRAVERSION = NAME = Saber-toothed Squirrel From 605843502b0573c0c865b13f770d971aadaf0c41 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 4 Oct 2012 17:11:13 -0700 Subject: [PATCH 1092/2357] mn10300: only add -mmem-funcs to KBUILD_CFLAGS if gcc supports it commit 9957423f035c2071f6d1c5d2f095cdafbeb25ad7 upstream. It seems the current (gcc 4.6.3) no longer provides this so make it conditional. As reported by Tony before, the mn10300 architecture cross-compiles with gcc-4.6.3 if -mmem-funcs is not added to KBUILD_CFLAGS. Reported-by: Tony Breeds Signed-off-by: Geert Uytterhoeven Cc: David Howells Cc: Koichi Yasutake Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/mn10300/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mn10300/Makefile b/arch/mn10300/Makefile index 7120282bf0d..3eb4a52ff9a 100644 --- a/arch/mn10300/Makefile +++ b/arch/mn10300/Makefile @@ -26,7 +26,7 @@ CHECKFLAGS += PROCESSOR := unset UNIT := unset -KBUILD_CFLAGS += -mam33 -mmem-funcs -DCPU=AM33 +KBUILD_CFLAGS += -mam33 -DCPU=AM33 $(call cc-option,-mmem-funcs,) KBUILD_AFLAGS += -mam33 -DCPU=AM33 ifeq ($(CONFIG_MN10300_CURRENT_IN_E2),y) From f15977883584e7b52832518c3fef115957d3203b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 4 Oct 2012 17:11:17 -0700 Subject: [PATCH 1093/2357] kbuild: make: fix if_changed when command contains backslashes commit c353acba28fb3fa1fd05fd6b85a9fc7938330f9c upstream. The call if_changed mechanism does not work when the command contains backslashes. This basically is an issue with lzo and bzip2 compressed kernels. The compressed binaries do not contain the uncompressed image size, so these use size_append to append the size. This results in backslashes in the executed command. With this if_changed always detects a change in the command and rebuilds the compressed image even if nothing has changed. Fix this by escaping backslashes in make-cmd Signed-off-by: Sascha Hauer Signed-off-by: Jan Luebbe Cc: Sam Ravnborg Cc: Bernhard Walle Cc: Michal Marek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- scripts/Kbuild.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 6a3ee981931..afa44595f34 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -209,7 +209,7 @@ endif # >$< substitution to preserve $ when reloading .cmd file # note: when using inline perl scripts [perl -e '...$$t=1;...'] # in $(cmd_xxx) double $$ your perl vars -make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))) +make-cmd = $(subst \\,\\\\,$(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))) # Find any prerequisites that is newer than target or that does not exist. # PHONY targets skipped in both cases. From 4893cf612a68d26cdbe0e16ba9c42772136e2340 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 2 Oct 2012 16:42:36 +0200 Subject: [PATCH 1094/2357] kbuild: Fix gcc -x syntax commit b1e0d8b70fa31821ebca3965f2ef8619d7c5e316 upstream. The correct syntax for gcc -x is "gcc -x assembler", not "gcc -xassembler". Even though the latter happens to work, the former is what is documented in the manual page and thus what gcc wrappers such as icecream do expect. This isn't a cosmetic change. The missing space prevents icecream from recognizing compilation tasks it can't handle, leading to silent kernel miscompilations. Besides me, credits go to Michael Matz and Dirk Mueller for investigating the miscompilation issue and tracking it down to this incorrect -x parameter syntax. Signed-off-by: Jean Delvare Acked-by: Ingo Molnar Cc: Bernhard Walle Cc: Michal Marek Cc: Ralf Baechle Signed-off-by: Michal Marek Signed-off-by: Greg Kroah-Hartman --- arch/mips/Makefile | 2 +- arch/mips/kernel/Makefile | 2 +- arch/x86/Makefile | 2 +- scripts/Kbuild.include | 12 ++++++------ scripts/gcc-version.sh | 6 +++--- scripts/gcc-x86_32-has-stack-protector.sh | 2 +- scripts/gcc-x86_64-has-stack-protector.sh | 2 +- scripts/kconfig/check.sh | 2 +- scripts/kconfig/lxdialog/check-lxdialog.sh | 2 +- tools/perf/Makefile | 2 +- tools/power/cpupower/Makefile | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 4fedf5a51d9..5c1e75d1c41 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -225,7 +225,7 @@ KBUILD_CPPFLAGS += -D"DATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)" LDFLAGS += -m $(ld-emul) ifdef CONFIG_MIPS -CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -xc /dev/null | \ +CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \ egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \ sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/") ifdef CONFIG_64BIT diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 0c6877ea900..d3d6fa97c09 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -104,7 +104,7 @@ obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o obj-$(CONFIG_OF) += prom.o -CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) +CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -x c /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o diff --git a/arch/x86/Makefile b/arch/x86/Makefile index b1c611e6da6..f1276aaeffd 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -85,7 +85,7 @@ endif ifdef CONFIG_X86_X32 x32_ld_ok := $(call try-run,\ /bin/echo -e '1: .quad 1b' | \ - $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" - && \ + $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" - && \ $(OBJCOPY) -O elf32-x86-64 "$$TMP" "$$TMPO" && \ $(LD) -m elf32_x86_64 "$$TMPO" -o "$$TMP",y,n) ifeq ($(x32_ld_ok),y) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index afa44595f34..978416dd31c 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -98,24 +98,24 @@ try-run = $(shell set -e; \ # Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) as-option = $(call try-run,\ - $(CC) $(KBUILD_CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2)) # as-instr # Usage: cflags-y += $(call as-instr,instr,option1,option2) as-instr = $(call try-run,\ - printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3)) + printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3)) # cc-option # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) cc-option = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) # cc-option-yn # Usage: flag := $(call cc-option-yn,-march=winchip-c6) cc-option-yn = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) # cc-option-align # Prefix align with either -falign or -malign @@ -125,7 +125,7 @@ cc-option-align = $(subst -functions=0,,\ # cc-disable-warning # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) cc-disable-warning = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1))) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) # cc-version # Usage gcc-ver := $(call cc-version) @@ -143,7 +143,7 @@ cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3)) # cc-ldoption # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) cc-ldoption = $(call try-run,\ - $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) # ld-option # Usage: LDFLAGS += $(call ld-option, -X) diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh index debecb5561c..7f2126df91f 100644 --- a/scripts/gcc-version.sh +++ b/scripts/gcc-version.sh @@ -22,10 +22,10 @@ if [ ${#compiler} -eq 0 ]; then exit 1 fi -MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1) -MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1) +MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1) +MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1) if [ "x$with_patchlevel" != "x" ] ; then - PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1) + PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1) printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL else printf "%02d%02d\\n" $MAJOR $MINOR diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh index 29493dc4528..12dbd0b11ea 100644 --- a/scripts/gcc-x86_32-has-stack-protector.sh +++ b/scripts/gcc-x86_32-has-stack-protector.sh @@ -1,6 +1,6 @@ #!/bin/sh -echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" +echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" if [ "$?" -eq "0" ] ; then echo y else diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh index afaec618b39..973e8c14156 100644 --- a/scripts/gcc-x86_64-has-stack-protector.sh +++ b/scripts/gcc-x86_64-has-stack-protector.sh @@ -1,6 +1,6 @@ #!/bin/sh -echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" +echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" if [ "$?" -eq "0" ] ; then echo y else diff --git a/scripts/kconfig/check.sh b/scripts/kconfig/check.sh index fa59cbf9d62..854d9c7c675 100755 --- a/scripts/kconfig/check.sh +++ b/scripts/kconfig/check.sh @@ -1,6 +1,6 @@ #!/bin/sh # Needed for systems without gettext -$* -xc -o /dev/null - > /dev/null 2>&1 << EOF +$* -x c -o /dev/null - > /dev/null 2>&1 << EOF #include int main() { diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh index 82cc3a85e7f..50df490fe1d 100644 --- a/scripts/kconfig/lxdialog/check-lxdialog.sh +++ b/scripts/kconfig/lxdialog/check-lxdialog.sh @@ -38,7 +38,7 @@ trap "rm -f $tmp" 0 1 2 3 15 # Check if we can link to ncurses check() { - $cc -xc - -o $tmp 2>/dev/null <<'EOF' + $cc -x c - -o $tmp 2>/dev/null <<'EOF' #include CURSES_LOC main() {} EOF diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 92271d32bc3..c3dd3d4424f 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -70,7 +70,7 @@ ifeq ($(ARCH),x86_64) ARCH := x86 IS_X86_64 := 0 ifeq (, $(findstring m32,$(EXTRA_CFLAGS))) - IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1) + IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) endif ifeq (${IS_X86_64}, 1) RAW_ARCH := x86_64 diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index a93e06cfcc2..cf397bd26d0 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile @@ -111,7 +111,7 @@ GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS # check if compiler option is supported -cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} +cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} # use '-Os' optimization if available, else use -O2 OPTIMIZATION := $(call cc-supports,-Os,-O2) From 750025ab1950b5e32e308c446de32c399cf2d6f6 Mon Sep 17 00:00:00 2001 From: Michael Wang Date: Wed, 5 Sep 2012 10:33:18 +0800 Subject: [PATCH 1095/2357] slab: fix the DEADLOCK issue on l3 alien lock commit 947ca1856a7e60aa6d20536785e6a42dff25aa6e upstream. DEADLOCK will be report while running a kernel with NUMA and LOCKDEP enabled, the process of this fake report is: kmem_cache_free() //free obj in cachep -> cache_free_alien() //acquire cachep's l3 alien lock -> __drain_alien_cache() -> free_block() -> slab_destroy() -> kmem_cache_free() //free slab in cachep->slabp_cache -> cache_free_alien() //acquire cachep->slabp_cache's l3 alien lock Since the cachep and cachep->slabp_cache's l3 alien are in the same lock class, fake report generated. This should not happen since we already have init_lock_keys() which will reassign the lock class for both l3 list and l3 alien. However, init_lock_keys() was invoked at a wrong position which is before we invoke enable_cpucache() on each cache. Since until set slab_state to be FULL, we won't invoke enable_cpucache() on caches to build their l3 alien while creating them, so although we invoked init_lock_keys(), the l3 alien lock class won't change since we don't have them until invoked enable_cpucache() later. This patch will invoke init_lock_keys() after we done enable_cpucache() instead of before to avoid the fake DEADLOCK report. Michael traced the problem back to a commit in release 3.0.0: commit 30765b92ada267c5395fc788623cb15233276f5c Author: Peter Zijlstra Date: Thu Jul 28 23:22:56 2011 +0200 slab, lockdep: Annotate the locks before using them Fernando found we hit the regular OFF_SLAB 'recursion' before we annotate the locks, cure this. The relevant portion of the stack-trace: > [ 0.000000] [] rt_spin_lock+0x50/0x56 > [ 0.000000] [] __cache_free+0x43/0xc3 > [ 0.000000] [] kmem_cache_free+0x6c/0xdc > [ 0.000000] [] slab_destroy+0x4f/0x53 > [ 0.000000] [] free_block+0x94/0xc1 > [ 0.000000] [] do_tune_cpucache+0x10b/0x2bb > [ 0.000000] [] enable_cpucache+0x7b/0xa7 > [ 0.000000] [] kmem_cache_init_late+0x1f/0x61 > [ 0.000000] [] start_kernel+0x24c/0x363 > [ 0.000000] [] i386_start_kernel+0xa9/0xaf Reported-by: Fernando Lopez-Lezcano Acked-by: Pekka Enberg Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1311888176.2617.379.camel@laptop Signed-off-by: Ingo Molnar The commit moved init_lock_keys() before we build up the alien, so we failed to reclass it. Acked-by: Christoph Lameter Tested-by: Paul E. McKenney Signed-off-by: Michael Wang Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- mm/slab.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index e901a36e252..da2bb689a00 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1685,9 +1685,6 @@ void __init kmem_cache_init_late(void) g_cpucache_up = LATE; - /* Annotate slab for lockdep -- annotate the malloc caches */ - init_lock_keys(); - /* 6) resize the head arrays to their final sizes */ mutex_lock(&cache_chain_mutex); list_for_each_entry(cachep, &cache_chain, next) @@ -1695,6 +1692,9 @@ void __init kmem_cache_init_late(void) BUG(); mutex_unlock(&cache_chain_mutex); + /* Annotate slab for lockdep -- annotate the malloc caches */ + init_lock_keys(); + /* Done! */ g_cpucache_up = FULL; From 63b2f08626e0cacaa038c296df52a7cb504ae318 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 11 Nov 2011 17:26:44 -0700 Subject: [PATCH 1096/2357] intel-iommu: Default to non-coherent for domains unattached to iommus commit 2e12bc29fc5a12242d68e11875db3dd58efad9ff upstream. domain_update_iommu_coherency() currently defaults to setting domains as coherent when the domain is not attached to any iommus. This allows for a window in domain_context_mapping_one() where such a domain can update context entries non-coherently, and only after update the domain capability to clear iommu_coherency. This can be seen using KVM device assignment on VT-d systems that do not support coherency in the ecap register. When a device is added to a guest, a domain is created (iommu_coherency = 0), the device is attached, and ranges are mapped. If we then hot unplug the device, the coherency is updated and set to the default (1) since no iommus are attached to the domain. A subsequent attach of a device makes use of the same dmar domain (now marked coherent) updates context entries with coherency enabled, and only disables coherency as the last step in the process. To fix this, switch domain_update_iommu_coherency() to use the safer, non-coherent default for domains not attached to iommus. Signed-off-by: Alex Williamson Tested-by: Donald Dutile Acked-by: Donald Dutile Acked-by: Chris Wright Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-iommu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 5fda348702c..0d251d301be 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -588,7 +588,9 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain) { int i; - domain->iommu_coherency = 1; + i = find_first_bit(domain->iommu_bmp, g_num_of_iommus); + + domain->iommu_coherency = i < g_num_of_iommus ? 1 : 0; for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) { if (!ecap_coherent(g_iommus[i]->ecap)) { From 63c486377c32dcfd5775c04b4d0cc5bc53990787 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 19 Aug 2012 19:32:27 -0300 Subject: [PATCH 1097/2357] media: rc: ite-cir: Initialise ite_dev::rdev earlier commit 4b961180ef275035b1538317ffd0e21e80e63e77 upstream. ite_dev::rdev is currently initialised in ite_probe() after rc_register_device() returns. If a newly registered device is opened quickly enough, we may enable interrupts and try to use ite_dev::rdev before it has been initialised. Move it up to the earliest point we can, right after calling rc_allocate_device(). Reported-and-tested-by: YunQiang Su Signed-off-by: Ben Hutchings Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/ite-cir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 0e49c99abf6..c06992e1320 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1473,6 +1473,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id rdev = rc_allocate_device(); if (!rdev) goto failure; + itdev->rdev = rdev; ret = -ENODEV; @@ -1604,7 +1605,6 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id if (ret) goto failure; - itdev->rdev = rdev; ite_pr(KERN_NOTICE, "driver has been successfully loaded\n"); return 0; From 991e71944f30eb7debd2d00abb749657b409b357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Sch=C3=A4fer?= Date: Sun, 9 Sep 2012 15:02:19 -0300 Subject: [PATCH 1098/2357] media: gspca_pac7302: add support for device 1ae7:2001 Speedlink Snappy Microphone SL-6825-SBK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 97d2fbf501e3cf105ac957086c7e40e62e15cdf8 upstream. Signed-off-by: Frank Schäfer Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/gspca/pac7302.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 30662fccb0c..63f571b7cc2 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -945,6 +945,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x262a)}, {USB_DEVICE(0x093a, 0x262c)}, {USB_DEVICE(0x145f, 0x013c)}, + {USB_DEVICE(0x1ae7, 0x2001)}, /* SpeedLink Snappy Mic SL-6825-SBK */ {} }; MODULE_DEVICE_TABLE(usb, device_table); From 2006e6f75e7cb88e0508eeff066834c847ce91b3 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 16 Jul 2012 16:30:21 +0800 Subject: [PATCH 1099/2357] ACPI: run _OSC after ACPI_FULL_INITIALIZATION commit fc54ab72959edbf229b65ac74b2f122d799ca002 upstream. The _OSC method may exist in module level code, so it must be called after ACPI_FULL_INITIALIZATION On some new platforms with Zero-Power-Optical-Disk-Drive (ZPODD) support, this fix is necessary to save power. Signed-off-by: Lin Ming Tested-by: Aaron Lu Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/bus.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 3188da3df8d..cf02e971467 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -954,14 +954,18 @@ static int __init acpi_bus_init(void) status = acpi_ec_ecdt_probe(); /* Ignore result. Not having an ECDT is not fatal. */ - acpi_bus_osc_support(); - status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n"); goto error1; } + /* + * _OSC method may exist in module level code, + * so it must be run after ACPI_FULL_INITIALIZATION + */ + acpi_bus_osc_support(); + /* * _PDC control method may load dynamic SSDT tables, * and we need to install the table handler before that. From 95482ba9494658e69aecf0f97b64f3f2ab82af62 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 20 Jun 2012 16:18:29 -0600 Subject: [PATCH 1100/2357] PCI: acpiphp: check whether _ADR evaluation succeeded commit dfb117b3e50c52c7b3416db4a4569224b8db80bb upstream. Check whether we evaluated _ADR successfully. Previously we ignored failure, so we would have used garbage data from the stack as the device and function number. We return AE_OK so that we ignore only this slot and continue looking for other slots. Found by Coverity (CID 113981). Signed-off-by: Bjorn Helgaas Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 806c44fa645..09bf3772184 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -132,6 +132,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) return AE_OK; + status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); + if (ACPI_FAILURE(status)) { + warn("can't evaluate _ADR (%#x)\n", status); + return AE_OK; + } + + device = (adr >> 16) & 0xffff; + function = adr & 0xffff; + pdev = pbus->self; if (pdev && pci_is_pcie(pdev)) { tmp = acpi_find_root_bridge_handle(pdev); @@ -144,10 +153,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) } } - acpi_evaluate_integer(handle, "_ADR", NULL, &adr); - device = (adr >> 16) & 0xffff; - function = adr & 0xffff; - newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); if (!newfunc) return AE_NO_MEMORY; From 03c4441b88fd2614580eeda598623e2b21ec5822 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Aug 2012 19:42:43 +0100 Subject: [PATCH 1101/2357] mfd: max8925: Move _IO resources out of ioport_ioresource commit bee6e1fa617b1fb7f6f91033428410e05f5ab0ed upstream. The removal of mach/io.h from most ARM platforms also set the range of valid IO ports to be empty for most platforms when previously any 32 bit integer had been valid. This makes it impossible to add IO resources as the added range is smaller than that of the root resource for IO ports. Since we're not really using IO memory at all fix this by defining our own root resource outside the normal tree and make that the parent of all IO resources. This also ensures we won't conflict with read IO ports if we ever run on a platform which happens to use them. Signed-off-by: Mark Brown Acked-by: Arnd Bergmann Acked-by: Haojian Zhuang Tested-by: Haojian Zhuang Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/max8925-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index ca881efedf7..746a59c29fe 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -18,12 +18,19 @@ #include #include +static struct resource io_parent = { + .start = 0, + .end = 0xffffffff, + .flags = IORESOURCE_IO, +}; + static struct resource backlight_resources[] = { { .name = "max8925-backlight", .start = MAX8925_WLED_MODE_CNTL, .end = MAX8925_WLED_CNTL, .flags = IORESOURCE_IO, + .parent = &io_parent, }, }; @@ -42,6 +49,7 @@ static struct resource touch_resources[] = { .start = MAX8925_TSC_IRQ, .end = MAX8925_ADC_RES_END, .flags = IORESOURCE_IO, + .parent = &io_parent, }, }; @@ -60,6 +68,7 @@ static struct resource power_supply_resources[] = { .start = MAX8925_CHG_IRQ1, .end = MAX8925_CHG_IRQ1_MASK, .flags = IORESOURCE_IO, + .parent = &io_parent, }, }; @@ -118,6 +127,7 @@ static struct mfd_cell onkey_devs[] = { .start = MAX8925_##_start, \ .end = MAX8925_##_end, \ .flags = IORESOURCE_IO, \ + .parent = &io_parent, \ } static struct resource regulator_resources[] = { From 6d36a9dd1dcdd053ab32f303b94cc1bae5a47f22 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Thu, 4 Oct 2012 17:13:18 -0700 Subject: [PATCH 1102/2357] lib/gcd.c: prevent possible div by 0 commit e96875677fb2b7cb739c5d7769824dff7260d31d upstream. Account for all properties when a and/or b are 0: gcd(0, 0) = 0 gcd(a, 0) = a gcd(0, b) = b Fixes no known problems in current kernels. Signed-off-by: Davidlohr Bueso Cc: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- lib/gcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/gcd.c b/lib/gcd.c index cce4f3cd14b..3657f129d7b 100644 --- a/lib/gcd.c +++ b/lib/gcd.c @@ -9,6 +9,9 @@ unsigned long gcd(unsigned long a, unsigned long b) if (a < b) swap(a, b); + + if (!b) + return a; while ((r = a % b) != 0) { a = b; b = r; From 3fc49ce67fefd3de38aa72a215eb1a2b68a7e89b Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 4 Oct 2012 17:12:23 -0700 Subject: [PATCH 1103/2357] kernel/sys.c: call disable_nonboot_cpus() in kernel_restart() commit f96972f2dc6365421cf2366ebd61ee4cf060c8d5 upstream. As kernel_power_off() calls disable_nonboot_cpus(), we may also want to have kernel_restart() call disable_nonboot_cpus(). Doing so can help machines that require boot cpu be the last alive cpu during reboot to survive with kernel restart. This fixes one reboot issue seen on imx6q (Cortex-A9 Quad). The machine requires that the restart routine be run on the primary cpu rather than secondary ones. Otherwise, the secondary core running the restart routine will fail to come to online after reboot. Signed-off-by: Shawn Guo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/sys.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/sys.c b/kernel/sys.c index e7006eb6c1e..898a84c9df5 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -365,6 +365,7 @@ EXPORT_SYMBOL(unregister_reboot_notifier); void kernel_restart(char *cmd) { kernel_restart_prepare(cmd); + disable_nonboot_cpus(); if (!cmd) printk(KERN_EMERG "Restarting system.\n"); else From 03f0a11553d06002af53f2d399da6c711e7d3b40 Mon Sep 17 00:00:00 2001 From: Martin Michlmayr Date: Thu, 4 Oct 2012 17:11:25 -0700 Subject: [PATCH 1104/2357] drivers/scsi/atp870u.c: fix bad use of udelay commit 0f6d93aa9d96cc9022b51bd10d462b03296be146 upstream. The ACARD driver calls udelay() with a value > 2000, which leads to to the following compilation error on ARM: ERROR: "__bad_udelay" [drivers/scsi/atp870u.ko] undefined! make[1]: *** [__modpost] Error 1 This is because udelay is defined on ARM, roughly speaking, as #define udelay(n) ((n) > 2000 ? __bad_udelay() : \ __const_udelay((n) * ((2199023U*HZ)>>11))) The argument to __const_udelay is the number of jiffies to wait divided by 4, but this does not work unless the multiplication does not overflow, and that is what the build error is designed to prevent. The intended behavior can be achieved by using mdelay to call udelay multiple times in a loop. [jrnieder@gmail.com: adding context] Signed-off-by: Martin Michlmayr Signed-off-by: Jonathan Nieder Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/atp870u.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 68ce08552f6..a540162ac59 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -1173,7 +1173,16 @@ static void tscam(struct Scsi_Host *host) outw(val, tmport); outb(2, 0x80); TCM_SYNC: - udelay(0x800); + /* + * The funny division into multiple delays is to accomodate + * arches like ARM where udelay() multiplies its argument by + * a large number to initialize a loop counter. To avoid + * overflow, the maximum supported udelay is 2000 microseconds. + * + * XXX it would be more polite to find a way to use msleep() + */ + mdelay(2); + udelay(48); if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */ outw(0, tmport--); outb(0, tmport); From 0c0b534583fb1c02809e0a3978413fe79f7dac8f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 4 Oct 2012 17:11:16 -0700 Subject: [PATCH 1105/2357] drivers/dma/dmaengine.c: lower the priority of 'failed to get' dma channel message commit 0eb5a35801df3c438ce3fc91310a415ea4452c00 upstream. Do the same as commit a03a202e95fd ("dmaengine: failure to get a specific DMA channel is not critical") to get rid of the following messages during kernel boot: dmaengine_get: failed to get dma1chan0: (-22) dmaengine_get: failed to get dma1chan1: (-22) dmaengine_get: failed to get dma1chan2: (-22) dmaengine_get: failed to get dma1chan3: (-22) .. Signed-off-by: Fabio Estevam Cc: Vinod Koul Cc: Dan Williams Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/dma/dmaengine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 2397f6f451b..6c87d676c62 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -578,7 +578,7 @@ void dmaengine_get(void) list_del_rcu(&device->global_node); break; } else if (err) - pr_err("%s: failed to get %s: (%d)\n", + pr_debug("%s: failed to get %s: (%d)\n", __func__, dma_chan_name(chan), err); } } From 9825e3158e302980b71c54b72e90f0624e1cfab3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 4 Oct 2012 12:03:25 +0930 Subject: [PATCH 1106/2357] lguest: fix occasional crash in example launcher. commit ca16f580a5db7e60bfafe59a50bb133bd3347491 upstream. We usually got away with ->next on the final entry being NULL, but it finally bit me. Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman --- tools/lguest/lguest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index f759f4f097c..fd2f9221b24 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c @@ -1299,6 +1299,7 @@ static struct device *new_device(const char *name, u16 type) dev->feature_len = 0; dev->num_vq = 0; dev->running = false; + dev->next = NULL; /* * Append to device list. Prepending to a single-linked list is From ed55202fda5c68e44464cd5afdc819a8721b601a Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 17 Sep 2012 04:34:28 +0000 Subject: [PATCH 1107/2357] powerpc/eeh: Fix crash on converting OF node to edev commit 1e38b7140185e384da216aff66a711df09b5afc9 upstream. The kernel crash was reported by Alexy. He was testing some feature with private kernel, in which Alexy added some code in pci_pm_reset() to read the CSR after writting it. The bug could be reproduced on Fiber Channel card (Fibre Channel: Emulex Corporation Saturn-X: LightPulse Fibre Channel Host Adapter (rev 03)) by the following commands. # echo 1 > /sys/devices/pci0004:01/0004:01:00.0/reset # rmmod lpfc # modprobe lpfc The history behind the test case is that those additional config space reading operations in pci_pm_reset() would cause EEH error, but we didn't detect EEH error until "modprobe lpfc". For the case, all the PCI devices on PCI bus (0004:01) were removed and added after PE reset. Then the EEH devices would be figured out again based on the OF nodes. Unfortunately, there were some child OF nodes under PCI device (0004:01:00.0), but they didn't have attached PCI_DN since they're invisible from PCI domain. However, we were still trying to convert OF node to EEH device without checking on the attached PCI_DN. Eventually, it caused the kernel crash as follows: Unable to handle kernel paging request for data at address 0x00000030 Faulting instruction address: 0xc00000000004d888 cpu 0x0: Vector: 300 (Data Access) at [c000000fc797b950] pc: c00000000004d888: .eeh_add_device_tree_early+0x78/0x140 lr: c00000000004d880: .eeh_add_device_tree_early+0x70/0x140 sp: c000000fc797bbd0 msr: 8000000000009032 dar: 30 dsisr: 40000000 current = 0xc000000fc78d9f70 paca = 0xc00000000edb0000 softe: 0 irq_happened: 0x00 pid = 2951, comm = eehd enter ? for help [c000000fc797bc50] c00000000004d848 .eeh_add_device_tree_early+0x38/0x140 [c000000fc797bcd0] c00000000004d848 .eeh_add_device_tree_early+0x38/0x140 [c000000fc797bd50] c000000000051b54 .pcibios_add_pci_devices+0x34/0x190 [c000000fc797bde0] c00000000004fb10 .eeh_reset_device+0x100/0x160 [c000000fc797be70] c0000000000502dc .eeh_handle_event+0x19c/0x300 [c000000fc797bf00] c000000000050570 .eeh_event_handler+0x130/0x1a0 [c000000fc797bf90] c000000000020138 .kernel_thread+0x54/0x70 The patch changes of_node_to_eeh_dev() and just returns NULL if the passed OF node doesn't have attached PCI_DN. Reported-by: Alexey Kardashevskiy Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/pci-bridge.h | 8 ++++++++ arch/powerpc/platforms/pseries/eeh.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index ac39e6a3b25..2974edd999d 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -181,6 +181,14 @@ static inline int pci_device_from_OF_node(struct device_node *np, #if defined(CONFIG_EEH) static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn) { + /* + * For those OF nodes whose parent isn't PCI bridge, they + * don't have PCI_DN actually. So we have to skip them for + * any EEH operations. + */ + if (!dn || !PCI_DN(dn)) + return NULL; + return PCI_DN(dn)->edev; } #endif diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index a75e37dc41a..41d4b163c06 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -1029,7 +1029,7 @@ static void eeh_add_device_early(struct device_node *dn) { struct pci_controller *phb; - if (!dn || !of_node_to_eeh_dev(dn)) + if (!of_node_to_eeh_dev(dn)) return; phb = of_node_to_eeh_dev(dn)->phb; From a332509fcd9064cae48d26e09aec46e08247223b Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Thu, 4 Oct 2012 17:15:48 -0700 Subject: [PATCH 1108/2357] rapidio/rionet: fix multicast packet transmit logic commit 7c4a6106d6451fc03c491e61df37c044505d843a upstream. Fix multicast packet transmit logic to account for repetitive transmission of single skb: - correct check for available buffers (this bug may produce NULL pointer crash dump in case of heavy traffic); - update skb user count (incorrect user counter causes a warning dump from net_tx_action routine during multicast transfers in systems with three or more rionet participants). Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: David S. Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/net/rionet.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 91d25888a1b..1470d3e86e3 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -79,6 +79,7 @@ static int rionet_capable = 1; * on system trade-offs. */ static struct rio_dev **rionet_active; +static int nact; /* total number of active rionet peers */ #define is_rionet_capable(src_ops, dst_ops) \ ((src_ops & RIO_SRC_OPS_DATA_MSG) && \ @@ -175,6 +176,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct ethhdr *eth = (struct ethhdr *)skb->data; u16 destid; unsigned long flags; + int add_num = 1; local_irq_save(flags); if (!spin_trylock(&rnet->tx_lock)) { @@ -182,7 +184,10 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_LOCKED; } - if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) { + if (is_multicast_ether_addr(eth->h_dest)) + add_num = nact; + + if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) { netif_stop_queue(ndev); spin_unlock_irqrestore(&rnet->tx_lock, flags); printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", @@ -191,11 +196,16 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) } if (is_multicast_ether_addr(eth->h_dest)) { + int count = 0; for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size); i++) - if (rionet_active[i]) + if (rionet_active[i]) { rionet_queue_tx_msg(skb, ndev, rionet_active[i]); + if (count) + atomic_inc(&skb->users); + count++; + } } else if (RIONET_MAC_MATCH(eth->h_dest)) { destid = RIONET_GET_DESTID(eth->h_dest); if (rionet_active[destid]) @@ -220,14 +230,17 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u if (info == RIONET_DOORBELL_JOIN) { if (!rionet_active[sid]) { list_for_each_entry(peer, &rionet_peers, node) { - if (peer->rdev->destid == sid) + if (peer->rdev->destid == sid) { rionet_active[sid] = peer->rdev; + nact++; + } } rio_mport_send_doorbell(mport, sid, RIONET_DOORBELL_JOIN); } } else if (info == RIONET_DOORBELL_LEAVE) { rionet_active[sid] = NULL; + nact--; } else { if (netif_msg_intr(rnet)) printk(KERN_WARNING "%s: unhandled doorbell\n", @@ -523,6 +536,7 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) rc = rionet_setup_netdev(rdev->net->hport, ndev); rionet_check = 1; + nact = 0; } /* From 24a0c2063c805e9cf1f3f418bb7f444b5b3f0e4e Mon Sep 17 00:00:00 2001 From: Feng Hong Date: Wed, 19 Sep 2012 14:16:00 +0200 Subject: [PATCH 1109/2357] PM / Sleep: use resume event when call dpm_resume_early commit 997a031107ec962967ce36db9bc500f1fad491c1 upstream. When dpm_suspend_noirq fail, state is PMSG_SUSPEND, should change to PMSG_RESUME when dpm_resume_early is called Signed-off-by: Feng Hong Signed-off-by: Raul Xiong Signed-off-by: Neil Zhang Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index f7eff25ffe4..ebc272f8cf2 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -984,7 +984,7 @@ int dpm_suspend_end(pm_message_t state) error = dpm_suspend_noirq(state); if (error) { - dpm_resume_early(state); + dpm_resume_early(resume_event(state)); return error; } From 66307aef43a3a51cccf03f4ca8063cfce1bd4ac1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 3 Aug 2012 10:30:45 -0700 Subject: [PATCH 1110/2357] workqueue: add missing smp_wmb() in process_one_work() commit 959d1af8cffc8fd38ed53e8be1cf4ab8782f9c00 upstream. WORK_STRUCT_PENDING is used to claim ownership of a work item and process_one_work() releases it before starting execution. When someone else grabs PENDING, all pre-release updates to the work item should be visible and all updates made by the new owner should happen afterwards. Grabbing PENDING uses test_and_set_bit() and thus has a full barrier; however, clearing doesn't have a matching wmb. Given the preceding spin_unlock and use of clear_bit, I don't believe this can be a problem on an actual machine and there hasn't been any related report but it still is theretically possible for clear_pending to permeate upwards and happen before work->entry update. Add an explicit smp_wmb() before work_clear_pending(). Signed-off-by: Tejun Heo Cc: Oleg Nesterov Signed-off-by: Greg Kroah-Hartman --- kernel/workqueue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 7584322349c..56f793d044a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1864,7 +1864,9 @@ __acquires(&gcwq->lock) spin_unlock_irq(&gcwq->lock); + smp_wmb(); /* paired with test_and_set_bit(PENDING) */ work_clear_pending(work); + lock_map_acquire_read(&cwq->wq->lockdep_map); lock_map_acquire(&lockdep_map); trace_workqueue_execute_start(work); From 0699c6dd66e7083f837cfe620837ddcf10649b89 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Sat, 18 Aug 2012 22:29:40 -0400 Subject: [PATCH 1111/2357] jbd2: don't write superblock when if its empty commit eeecef0af5ea4efd763c9554cf2bd80fc4a0efd3 upstream. This sequence: # truncate --size=1g fsfile # mkfs.ext4 -F fsfile # mount -o loop,ro fsfile /mnt # umount /mnt # dmesg | tail results in an IO error when unmounting the RO filesystem: [ 318.020828] Buffer I/O error on device loop1, logical block 196608 [ 318.027024] lost page write due to I/O error on loop1 [ 318.032088] JBD2: Error -5 detected when updating journal superblock for loop1-8. This was a regression introduced by commit 24bcc89c7e7c: "jbd2: split updating of journal superblock and marking journal empty". Signed-off-by: Eric Sandeen Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/journal.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 9956ac68b72..e5bfb1150cf 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1317,6 +1317,11 @@ static void jbd2_mark_journal_empty(journal_t *journal) BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); read_lock(&journal->j_state_lock); + /* Is it already empty? */ + if (sb->s_start == 0) { + read_unlock(&journal->j_state_lock); + return; + } jbd_debug(1, "JBD2: Marking journal as empty (seq %d)\n", journal->j_tail_sequence); From e878ead68937be79e530ea9bf568766ab454e3ee Mon Sep 17 00:00:00 2001 From: Yuta Ando Date: Mon, 1 Oct 2012 23:24:30 +0900 Subject: [PATCH 1112/2357] localmodconfig: Fix localyesconfig to set to 'y' not 'm' commit 4eae518d4b01b0cbf2f0d8edb5a6f3d6245ee8fb upstream. The kbuild target 'localyesconfig' has been same as 'localmodconfig' since the commit 50bce3e "kconfig/streamline_config.pl: merge local{mod,yes}config". The commit expects this script generates different configure depending on target, but it was not yet implemented. So I added code that sets to 'yes' when target is 'localyesconfig'. Link: http://lkml.kernel.org/r/1349101470-12243-1-git-send-email-yuta.and@gmail.com Signed-off-by: Yuta Ando Cc: linux-kbuild@vger.kernel.org Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- scripts/kconfig/streamline_config.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index bccf07ddd0b..3346f4236eb 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -463,6 +463,8 @@ sub parse_config_dep_select if (defined($configs{$1})) { if ($localyesconfig) { $setconfigs{$1} = 'y'; + print "$1=y\n"; + next; } else { $setconfigs{$1} = $2; } From 657197486950474bf30290344339fd0914fe99c9 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Thu, 13 Sep 2012 12:59:44 +0000 Subject: [PATCH 1113/2357] bnx2x: fix rx checksum validation for IPv6 [ Upstream commit e488921f44765e8ab6c48ca35e3f6b78df9819df ] Commit d6cb3e41 "bnx2x: fix checksum validation" caused a performance regression for IPv6. Rx checksum offload does not work. IPv6 packets are passed to the stack with CHECKSUM_NONE. The hardware obviously cannot perform IP checksum validation for IPv6, because there is no checksum in the IPv6 header. This should not prevent us from setting CHECKSUM_UNNECESSARY. Tested on BCM57711. Signed-off-by: Michal Schmidt Acked-by: Eric Dumazet Acked-by: Eilon Greenstein Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 41bb34fcf68..acd82466036 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -571,14 +571,16 @@ static inline void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, static void bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe, struct bnx2x_fastpath *fp) { - /* Do nothing if no IP/L4 csum validation was done */ - + /* Do nothing if no L4 csum validation was done. + * We do not check whether IP csum was validated. For IPv4 we assume + * that if the card got as far as validating the L4 csum, it also + * validated the IP csum. IPv6 has no IP csum. + */ if (cqe->fast_path_cqe.status_flags & - (ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG | - ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG)) + ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG) return; - /* If both IP/L4 validation were done, check if an error was found. */ + /* If L4 validation was done, check if an error was found. */ if (cqe->fast_path_cqe.type_error_flags & (ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG | From 20eb20851385e53d27dff9ed79c4e68e58e3d9da Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Tue, 4 Sep 2012 00:03:29 +0000 Subject: [PATCH 1114/2357] xfrm: Workaround incompatibility of ESN and async crypto [ Upstream commit 3b59df46a449ec9975146d71318c4777ad086744 ] ESN for esp is defined in RFC 4303. This RFC assumes that the sequence number counters are always up to date. However, this is not true if an async crypto algorithm is employed. If the sequence number counters are not up to date on sequence number check, we may incorrectly update the upper 32 bit of the sequence number. This leads to a DOS. We workaround this by comparing the upper sequence number, (used for authentication) with the upper sequence number computed after the async processing. We drop the packet if these numbers are different. To do this, we introduce a recheck function that does this check in the ESN case. Signed-off-by: Steffen Klassert Acked-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/xfrm.h | 3 +++ net/xfrm/xfrm_input.c | 2 +- net/xfrm/xfrm_replay.c | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 96239e78e62..9f7e94ba669 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -269,6 +269,9 @@ struct xfrm_replay { int (*check)(struct xfrm_state *x, struct sk_buff *skb, __be32 net_seq); + int (*recheck)(struct xfrm_state *x, + struct sk_buff *skb, + __be32 net_seq); void (*notify)(struct xfrm_state *x, int event); int (*overflow)(struct xfrm_state *x, struct sk_buff *skb); }; diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 54a0dc2e2f8..ab2bb42fe09 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -212,7 +212,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) /* only the first xfrm gets the encap type */ encap_type = 0; - if (async && x->repl->check(x, skb, seq)) { + if (async && x->repl->recheck(x, skb, seq)) { XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR); goto drop_unlock; } diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index 2f6d11d04a2..3efb07d3eb2 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c @@ -420,6 +420,18 @@ static int xfrm_replay_check_esn(struct xfrm_state *x, return -EINVAL; } +static int xfrm_replay_recheck_esn(struct xfrm_state *x, + struct sk_buff *skb, __be32 net_seq) +{ + if (unlikely(XFRM_SKB_CB(skb)->seq.input.hi != + htonl(xfrm_replay_seqhi(x, net_seq)))) { + x->stats.replay_window++; + return -EINVAL; + } + + return xfrm_replay_check_esn(x, skb, net_seq); +} + static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq) { unsigned int bitnr, nr, i; @@ -479,6 +491,7 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq) static struct xfrm_replay xfrm_replay_legacy = { .advance = xfrm_replay_advance, .check = xfrm_replay_check, + .recheck = xfrm_replay_check, .notify = xfrm_replay_notify, .overflow = xfrm_replay_overflow, }; @@ -486,6 +499,7 @@ static struct xfrm_replay xfrm_replay_legacy = { static struct xfrm_replay xfrm_replay_bmp = { .advance = xfrm_replay_advance_bmp, .check = xfrm_replay_check_bmp, + .recheck = xfrm_replay_check_bmp, .notify = xfrm_replay_notify_bmp, .overflow = xfrm_replay_overflow_bmp, }; @@ -493,6 +507,7 @@ static struct xfrm_replay xfrm_replay_bmp = { static struct xfrm_replay xfrm_replay_esn = { .advance = xfrm_replay_advance_esn, .check = xfrm_replay_check_esn, + .recheck = xfrm_replay_recheck_esn, .notify = xfrm_replay_notify_bmp, .overflow = xfrm_replay_overflow_esn, }; From 555144b63d57c0df7a2677868f83957a34135207 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Thu, 13 Sep 2012 11:41:26 +0000 Subject: [PATCH 1115/2357] xfrm_user: return error pointer instead of NULL [ Upstream commit 864745d291b5ba80ea0bd0edcbe67273de368836 ] When dump_one_state() returns an error, e.g. because of a too small buffer to dump the whole xfrm state, xfrm_state_netlink() returns NULL instead of an error pointer. But its callers expect an error pointer and therefore continue to operate on a NULL skbuff. This could lead to a privilege escalation (execution of user code in kernel context) if the attacker has CAP_NET_ADMIN and is able to map address 0. Signed-off-by: Mathias Krause Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7128dde0fe1..c1537f0b406 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -862,6 +862,7 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, { struct xfrm_dump_info info; struct sk_buff *skb; + int err; skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!skb) @@ -872,9 +873,10 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, info.nlmsg_seq = seq; info.nlmsg_flags = 0; - if (dump_one_state(x, 0, &info)) { + err = dump_one_state(x, 0, &info); + if (err) { kfree_skb(skb); - return NULL; + return ERR_PTR(err); } return skb; From f38b334adca51bbf18ad549a9736c0f86bb4a375 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Fri, 14 Sep 2012 09:58:32 +0000 Subject: [PATCH 1116/2357] xfrm_user: return error pointer instead of NULL #2 [ Upstream commit c25463722509fef0ed630b271576a8c9a70236f3 ] When dump_one_policy() returns an error, e.g. because of a too small buffer to dump the whole xfrm policy, xfrm_policy_netlink() returns NULL instead of an error pointer. But its caller expects an error pointer and therefore continues to operate on a NULL skbuff. Signed-off-by: Mathias Krause Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c1537f0b406..4cae47d8dc4 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1531,6 +1531,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, { struct xfrm_dump_info info; struct sk_buff *skb; + int err; skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!skb) @@ -1541,9 +1542,10 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, info.nlmsg_seq = seq; info.nlmsg_flags = 0; - if (dump_one_policy(xp, dir, 0, &info) < 0) { + err = dump_one_policy(xp, dir, 0, &info); + if (err) { kfree_skb(skb); - return NULL; + return ERR_PTR(err); } return skb; From a91af73f445cacfb0db4df3eb2e3d0ddeff43893 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Mon, 17 Sep 2012 22:40:10 +0000 Subject: [PATCH 1117/2357] xfrm: fix a read lock imbalance in make_blackhole [ Upstream commit 433a19548061bb5457b6ab77ed7ea58ca6e43ddb ] if xfrm_policy_get_afinfo returns 0, it has already released the read lock, xfrm_policy_put_afinfo should not be called again. Signed-off-by: Li RongQing Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index a15d2a03172..71c80c763d5 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1761,7 +1761,7 @@ static struct dst_entry *make_blackhole(struct net *net, u16 family, if (!afinfo) { dst_release(dst_orig); - ret = ERR_PTR(-EINVAL); + return ERR_PTR(-EINVAL); } else { ret = afinfo->blackhole_route(net, dst_orig); } From 37d61a27a59671d88279dcc4d331f950d4901d4d Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 19 Sep 2012 11:33:38 +0000 Subject: [PATCH 1118/2357] xfrm_user: fix info leak in copy_to_user_auth() [ Upstream commit 4c87308bdea31a7b4828a51f6156e6f721a1fcc9 ] copy_to_user_auth() fails to initialize the remainder of alg_name and therefore discloses up to 54 bytes of heap memory via netlink to userland. Use strncpy() instead of strcpy() to fill the trailing bytes of alg_name with null bytes. Signed-off-by: Mathias Krause Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 4cae47d8dc4..f5936d84655 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -742,7 +742,7 @@ static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb) return -EMSGSIZE; algo = nla_data(nla); - strcpy(algo->alg_name, auth->alg_name); + strncpy(algo->alg_name, auth->alg_name, sizeof(algo->alg_name)); memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8); algo->alg_key_len = auth->alg_key_len; From d5f1f7c230df5f2a198fb231547f1b298594c709 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 19 Sep 2012 11:33:39 +0000 Subject: [PATCH 1119/2357] xfrm_user: fix info leak in copy_to_user_state() [ Upstream commit f778a636713a435d3a922c60b1622a91136560c1 ] The memory reserved to dump the xfrm state includes the padding bytes of struct xfrm_usersa_info added by the compiler for alignment (7 for amd64, 3 for i386). Add an explicit memset(0) before filling the buffer to avoid the info leak. Signed-off-by: Mathias Krause Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index f5936d84655..9e5c07eb292 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -689,6 +689,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) { + memset(p, 0, sizeof(*p)); memcpy(&p->id, &x->id, sizeof(p->id)); memcpy(&p->sel, &x->sel, sizeof(p->sel)); memcpy(&p->lft, &x->lft, sizeof(p->lft)); From 97f96eab8eb32f3178439f73acca4e286c091435 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 19 Sep 2012 11:33:40 +0000 Subject: [PATCH 1120/2357] xfrm_user: fix info leak in copy_to_user_policy() [ Upstream commit 7b789836f434c87168eab067cfbed1ec4783dffd ] The memory reserved to dump the xfrm policy includes multiple padding bytes added by the compiler for alignment (padding bytes in struct xfrm_selector and struct xfrm_userpolicy_info). Add an explicit memset(0) before filling the buffer to avoid the heap info leak. Signed-off-by: Mathias Krause Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 9e5c07eb292..4ec3ccd7d51 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1300,6 +1300,7 @@ static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir) { + memset(p, 0, sizeof(*p)); memcpy(&p->sel, &xp->selector, sizeof(p->sel)); memcpy(&p->lft, &xp->lft, sizeof(p->lft)); memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); From 0c5e37586ef83845acbae1738e693bc97c12d4c3 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 19 Sep 2012 11:33:41 +0000 Subject: [PATCH 1121/2357] xfrm_user: fix info leak in copy_to_user_tmpl() [ Upstream commit 1f86840f897717f86d523a13e99a447e6a5d2fa5 ] The memory used for the template copy is a local stack variable. As struct xfrm_user_tmpl contains multiple holes added by the compiler for alignment, not initializing the memory will lead to leaking stack bytes to userland. Add an explicit memset(0) to avoid the info leak. Initial version of the patch by Brad Spengler. Signed-off-by: Mathias Krause Cc: Brad Spengler Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 4ec3ccd7d51..74ea70f5f35 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1405,6 +1405,7 @@ static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb) struct xfrm_user_tmpl *up = &vec[i]; struct xfrm_tmpl *kp = &xp->xfrm_vec[i]; + memset(up, 0, sizeof(*up)); memcpy(&up->id, &kp->id, sizeof(up->id)); up->family = kp->encap_family; memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr)); From 743b911d8b2214bfa9ecd1631edbe6f61f8fdced Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 19 Sep 2012 11:33:43 +0000 Subject: [PATCH 1122/2357] xfrm_user: don't copy esn replay window twice for new states [ Upstream commit e3ac104d41a97b42316915020ba228c505447d21 ] The ESN replay window was already fully initialized in xfrm_alloc_replay_state_esn(). No need to copy it again. Signed-off-by: Mathias Krause Cc: Steffen Klassert Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 74ea70f5f35..e0972b26a59 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -442,10 +442,11 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * * somehow made shareable and move it to xfrm_state.c - JHS * */ -static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs) +static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs, + int update_esn) { struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; - struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL]; + struct nlattr *re = update_esn ? attrs[XFRMA_REPLAY_ESN_VAL] : NULL; struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; @@ -555,7 +556,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, goto error; /* override default values from above */ - xfrm_update_ae_params(x, attrs); + xfrm_update_ae_params(x, attrs, 0); return x; @@ -1801,7 +1802,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, goto out; spin_lock_bh(&x->lock); - xfrm_update_ae_params(x, attrs); + xfrm_update_ae_params(x, attrs, 1); spin_unlock_bh(&x->lock); c.event = nlh->nlmsg_type; From 53bf1469924e07385b4493d3cbd78551d4afaaa3 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Thu, 20 Sep 2012 10:01:49 +0000 Subject: [PATCH 1123/2357] xfrm_user: ensure user supplied esn replay window is valid [ Upstream commit ecd7918745234e423dd87fcc0c077da557909720 ] The current code fails to ensure that the netlink message actually contains as many bytes as the header indicates. If a user creates a new state or updates an existing one but does not supply the bytes for the whole ESN replay window, the kernel copies random heap bytes into the replay bitmap, the ones happen to follow the XFRMA_REPLAY_ESN_VAL netlink attribute. This leads to following issues: 1. The replay window has random bits set confusing the replay handling code later on. 2. A malicious user could use this flaw to leak up to ~3.5kB of heap memory when she has access to the XFRM netlink interface (requires CAP_NET_ADMIN). Known users of the ESN replay window are strongSwan and Steffen's iproute2 patch (). The latter uses the interface with a bitmap supplied while the former does not. strongSwan is therefore prone to run into issue 1. To fix both issues without breaking existing userland allow using the XFRMA_REPLAY_ESN_VAL netlink attribute with either an empty bitmap or a fully specified one. For the former case we initialize the in-kernel bitmap with zero, for the latter we copy the user supplied bitmap. For state updates the full bitmap must be supplied. To prevent overflows in the bitmap length calculation the maximum size of bmp_len is limited to 128 by this patch -- resulting in a maximum replay window of 4096 packets. This should be sufficient for all real life scenarios (RFC 4303 recommends a default replay window size of 64). Signed-off-by: Mathias Krause Cc: Steffen Klassert Cc: Martin Willi Cc: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/xfrm.h | 2 ++ net/xfrm/xfrm_user.c | 31 +++++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 22e61fdf75a..28e493b5b94 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -84,6 +84,8 @@ struct xfrm_replay_state { __u32 bitmap; }; +#define XFRMA_REPLAY_ESN_MAX 4096 + struct xfrm_replay_state_esn { unsigned int bmp_len; __u32 oseq; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index e0972b26a59..c8b903df943 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -123,9 +123,21 @@ static inline int verify_replay(struct xfrm_usersa_info *p, struct nlattr **attrs) { struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; + struct xfrm_replay_state_esn *rs; - if ((p->flags & XFRM_STATE_ESN) && !rt) - return -EINVAL; + if (p->flags & XFRM_STATE_ESN) { + if (!rt) + return -EINVAL; + + rs = nla_data(rt); + + if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) + return -EINVAL; + + if (nla_len(rt) < xfrm_replay_state_esn_len(rs) && + nla_len(rt) != sizeof(*rs)) + return -EINVAL; + } if (!rt) return 0; @@ -370,14 +382,15 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es struct nlattr *rp) { struct xfrm_replay_state_esn *up; + int ulen; if (!replay_esn || !rp) return 0; up = nla_data(rp); + ulen = xfrm_replay_state_esn_len(up); - if (xfrm_replay_state_esn_len(replay_esn) != - xfrm_replay_state_esn_len(up)) + if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen) return -EINVAL; return 0; @@ -388,22 +401,28 @@ static int xfrm_alloc_replay_state_esn(struct xfrm_replay_state_esn **replay_esn struct nlattr *rta) { struct xfrm_replay_state_esn *p, *pp, *up; + int klen, ulen; if (!rta) return 0; up = nla_data(rta); + klen = xfrm_replay_state_esn_len(up); + ulen = nla_len(rta) >= klen ? klen : sizeof(*up); - p = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL); + p = kzalloc(klen, GFP_KERNEL); if (!p) return -ENOMEM; - pp = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL); + pp = kzalloc(klen, GFP_KERNEL); if (!pp) { kfree(p); return -ENOMEM; } + memcpy(p, up, ulen); + memcpy(pp, up, ulen); + *replay_esn = p; *preplay_esn = pp; From f7ee46fb594cf2c3dd3a96457a028336fb34d5a6 Mon Sep 17 00:00:00 2001 From: htbegin Date: Mon, 1 Oct 2012 16:42:43 +0000 Subject: [PATCH 1124/2357] net: ethernet: davinci_cpdma: decrease the desc count when cleaning up the remaining packets [ Upstream commit ffb5ba90017505a19e238e986e6d33f09e4df765 ] chan->count is used by rx channel. If the desc count is not updated by the clean up loop in cpdma_chan_stop, the value written to the rxfree register in cpdma_chan_start will be incorrect. Signed-off-by: Tao Hou Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ti/davinci_cpdma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index 34558766cbf..06f2b495428 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -851,6 +851,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan) next_dma = desc_read(desc, hw_next); chan->head = desc_from_phys(pool, next_dma); + chan->count--; chan->stats.teardown_dequeue++; /* issue callback without locks held */ From ec7fd138e2e690efff5eaec279ebc2c4740589e4 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 10 Sep 2012 14:06:58 +0200 Subject: [PATCH 1125/2357] ixp4xx_hss: fix build failure due to missing linux/module.h inclusion [ Upstream commit 0b836ddde177bdd5790ade83772860940bd481ea ] Commit 36a1211970193ce215de50ed1e4e1272bc814df1 (netprio_cgroup.h: dont include module.h from other includes) made the following build error on ixp4xx_hss pop up: CC [M] drivers/net/wan/ixp4xx_hss.o drivers/net/wan/ixp4xx_hss.c:1412:20: error: expected ';', ',' or ')' before string constant drivers/net/wan/ixp4xx_hss.c:1413:25: error: expected ';', ',' or ')' before string constant drivers/net/wan/ixp4xx_hss.c:1414:21: error: expected ';', ',' or ')' before string constant drivers/net/wan/ixp4xx_hss.c:1415:19: error: expected ';', ',' or ')' before string constant make[8]: *** [drivers/net/wan/ixp4xx_hss.o] Error 1 This was previously hidden because ixp4xx_hss includes linux/hdlc.h which includes linux/netdevice.h which includes linux/netprio_cgroup.h which used to include linux/module.h. The real issue was actually present since the initial commit that added this driver since it uses macros from linux/module.h without including this file. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/wan/ixp4xx_hss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index aaaca9aa229..3f575afd8cf 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include From 6720119023f635bd8c285530a7092716c23bdfcc Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 14 Sep 2012 05:50:03 +0000 Subject: [PATCH 1126/2357] netxen: check for root bus in netxen_mask_aer_correctable [ Upstream commit e4d1aa40e363ed3e0486aeeeb0d173f7f822737e ] Add a check if pdev->bus->self == NULL (root bus). When attaching a netxen NIC to a VM it can be on the root bus and the guest would crash in netxen_mask_aer_correctable() because of a NULL pointer dereference if CONFIG_PCIEAER is present. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 65a718f9ccd..22b399a9db9 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -1370,6 +1370,10 @@ static void netxen_mask_aer_correctable(struct netxen_adapter *adapter) struct pci_dev *root = pdev->bus->self; u32 aer_pos; + /* root bus? */ + if (!root) + return; + if (adapter->ahw.board_type != NETXEN_BRDTYPE_P3_4_GB_MM && adapter->ahw.board_type != NETXEN_BRDTYPE_P3_10G_TP) return; From 52ee75479f2aea816d8bb6a9d6caf5c1ebb36724 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 11 Sep 2012 13:11:12 +0000 Subject: [PATCH 1127/2357] net-sched: sch_cbq: avoid infinite loop [ Upstream commit bdfc87f7d1e253e0a61e2fc6a75ea9d76f7fc03a ] Its possible to setup a bad cbq configuration leading to an infinite loop in cbq_classify() DEV_OUT=eth0 ICMP="match ip protocol 1 0xff" U32="protocol ip u32" DST="match ip dst" tc qdisc add dev $DEV_OUT root handle 1: cbq avpkt 1000 \ bandwidth 100mbit tc class add dev $DEV_OUT parent 1: classid 1:1 cbq \ rate 512kbit allot 1500 prio 5 bounded isolated tc filter add dev $DEV_OUT parent 1: prio 3 $U32 \ $ICMP $DST 192.168.3.234 flowid 1: Reported-by: Denys Fedoryschenko Tested-by: Denys Fedoryschenko Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_cbq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 24d94c097b3..599f67ada1e 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -250,10 +250,11 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) else if ((cl = defmap[res.classid & TC_PRIO_MAX]) == NULL) cl = defmap[TC_PRIO_BESTEFFORT]; - if (cl == NULL || cl->level >= head->level) + if (cl == NULL) goto fallback; } - + if (cl->level >= head->level) + goto fallback; #ifdef CONFIG_NET_CLS_ACT switch (result) { case TC_ACT_QUEUED: From 5ee708f19bd6a1da1d7bab5916382bbbfba4edbb Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Sat, 15 Sep 2012 00:41:35 +0000 Subject: [PATCH 1128/2357] pkt_sched: fix virtual-start-time update in QFQ [ Upstream commit 71261956973ba9e0637848a5adb4a5819b4bae83 ] If the old timestamps of a class, say cl, are stale when the class becomes active, then QFQ may assign to cl a much higher start time than the maximum value allowed. This may happen when QFQ assigns to the start time of cl the finish time of a group whose classes are characterized by a higher value of the ratio max_class_pkt/weight_of_the_class with respect to that of cl. Inserting a class with a too high start time into the bucket list corrupts the data structure and may eventually lead to crashes. This patch limits the maximum start time assigned to a class. Signed-off-by: Paolo Valente Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_qfq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index e68cb440756..cdd474afbbd 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -830,7 +830,10 @@ static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl) if (mask) { struct qfq_group *next = qfq_ffs(q, mask); if (qfq_gt(roundedF, next->F)) { - cl->S = next->F; + if (qfq_gt(limit, next->F)) + cl->S = next->F; + else /* preserve timestamp correctness */ + cl->S = limit; return; } } From 97d5d3295198279362552d9b810c088d3410da23 Mon Sep 17 00:00:00 2001 From: Lennart Sorensen Date: Fri, 7 Sep 2012 12:14:02 +0000 Subject: [PATCH 1129/2357] sierra_net: Endianess bug fix. [ Upstream commit 2120c52da6fe741454a60644018ad2a6abd957ac ] I discovered I couldn't get sierra_net to work on a powerpc. Turns out the firmware attribute check assumes the system is little endian and hence fails because the attributes is a 16 bit value. Signed-off-by: Len Sorensen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/sierra_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index cc9776c2a39..8789bc58b17 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -678,7 +678,7 @@ static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap) return -EIO; } - *datap = *attrdata; + *datap = le16_to_cpu(*attrdata); kfree(attrdata); return result; From 2ab08687cf48805c5abd0f9a785e09181eda9492 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 2 Oct 2012 06:14:17 +0000 Subject: [PATCH 1130/2357] 8021q: fix mac_len recomputation in vlan_untag() [ Upstream commit 5316cf9a5197eb80b2800e1acadde287924ca975 ] skb_reset_mac_len() relies on the value of the skb->network_header pointer, therefore we must wait for such pointer to be recalculated before computing the new mac_len value. Signed-off-by: Antonio Quartulli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/8021q/vlan_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 4d39d802be2..f36463087ba 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -106,7 +106,6 @@ static struct sk_buff *vlan_reorder_header(struct sk_buff *skb) return NULL; memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN); skb->mac_header += VLAN_HLEN; - skb_reset_mac_len(skb); return skb; } @@ -140,6 +139,8 @@ struct sk_buff *vlan_untag(struct sk_buff *skb) skb_reset_network_header(skb); skb_reset_transport_header(skb); + skb_reset_mac_len(skb); + return skb; err_free: From 17de307472bf21479e6d7c35211204b6ea186a7c Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 19 Sep 2012 19:25:34 +0000 Subject: [PATCH 1131/2357] ipv6: release reference of ip6_null_entry's dst entry in __ip6_del_rt [ Upstream commit 6825a26c2dc21eb4f8df9c06d3786ddec97cf53b ] as we hold dst_entry before we call __ip6_del_rt, so we should alse call dst_release not only return -ENOENT when the rt6_info is ip6_null_entry. and we already hold the dst entry, so I think it's safe to call dst_release out of the write-read lock. Signed-off-by: Gao feng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c4920ca83f5..2796b374cb2 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1485,17 +1485,18 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) struct fib6_table *table; struct net *net = dev_net(rt->dst.dev); - if (rt == net->ipv6.ip6_null_entry) - return -ENOENT; + if (rt == net->ipv6.ip6_null_entry) { + err = -ENOENT; + goto out; + } table = rt->rt6i_table; write_lock_bh(&table->tb6_lock); - err = fib6_del(rt, info); - dst_release(&rt->dst); - write_unlock_bh(&table->tb6_lock); +out: + dst_release(&rt->dst); return err; } From d5e36b089edcc8179d4640e1a8e5bca6fb74409e Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 26 Sep 2012 00:04:55 +0000 Subject: [PATCH 1132/2357] ipv6: del unreachable route when an addr is deleted on lo [ Upstream commit 64c6d08e6490fb18cea09bb03686c149946bd818 ] When an address is added on loopback (ip -6 a a 2002::1/128 dev lo), two routes are added: - one in the local table: local 2002::1 via :: dev lo proto none metric 0 - one the in main table (for the prefix): unreachable 2002::1 dev lo proto kernel metric 256 error -101 When the address is deleted, the route inserted in the main table remains because we use rt6_lookup(), which returns NULL when dst->error is set, which is the case here! Thus, it is better to use ip6_route_lookup() to avoid this kind of filter. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/addrconf.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2c69eca4b61..5ec60699c67 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -793,10 +793,16 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) struct in6_addr prefix; struct rt6_info *rt; struct net *net = dev_net(ifp->idev->dev); + struct flowi6 fl6 = {}; + ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); - rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1); + fl6.flowi6_oif = ifp->idev->dev->ifindex; + fl6.daddr = prefix; + rt = (struct rt6_info *)ip6_route_lookup(net, &fl6, + RT6_LOOKUP_F_IFACE); - if (rt && addrconf_is_prefix_route(rt)) { + if (rt != net->ipv6.ip6_null_entry && + addrconf_is_prefix_route(rt)) { if (onlink == 0) { ip6_del_rt(rt); rt = NULL; From 410eafac650a906e990351a01ec70451064df83d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 20 Sep 2012 18:29:56 +0000 Subject: [PATCH 1133/2357] ipv6: fix return value check in fib6_add() [ Upstream commit f950c0ecc78f745e490d615280e031de4dbb1306 ] In case of error, the function fib6_add_1() returns ERR_PTR() or NULL pointer. The ERR_PTR() case check is missing in fib6_add(). dpatch engine is used to generated this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_fib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 92bb9cba5c3..c3a007dc37c 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -818,6 +818,10 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) offsetof(struct rt6_info, rt6i_src), allow_create, replace_required); + if (IS_ERR(sn)) { + err = PTR_ERR(sn); + sn = NULL; + } if (!sn) { /* If it is failed, discard just allocated root, and then (in st_failure) stale node From 2033554a2fe3c5e54764f2f1dba0baff3261f8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kube=C4=8Dek?= Date: Fri, 14 Sep 2012 04:59:52 +0000 Subject: [PATCH 1134/2357] tcp: flush DMA queue before sk_wait_data if rcv_wnd is zero [ Upstream commit 15c041759bfcd9ab0a4e43f1c16e2644977d0467 ] If recv() syscall is called for a TCP socket so that - IOAT DMA is used - MSG_WAITALL flag is used - requested length is bigger than sk_rcvbuf - enough data has already arrived to bring rcv_wnd to zero then when tcp_recvmsg() gets to calling sk_wait_data(), receive window can be still zero while sk_async_wait_queue exhausts enough space to keep it zero. As this queue isn't cleaned until the tcp_service_net_dma() call, sk_wait_data() cannot receive any data and blocks forever. If zero receive window and non-empty sk_async_wait_queue is detected before calling sk_wait_data(), process the queue first. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 367bdaf9a56..8fbe2e20e7c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1594,8 +1594,14 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } #ifdef CONFIG_NET_DMA - if (tp->ucopy.dma_chan) - dma_async_memcpy_issue_pending(tp->ucopy.dma_chan); + if (tp->ucopy.dma_chan) { + if (tp->rcv_wnd == 0 && + !skb_queue_empty(&sk->sk_async_wait_queue)) { + tcp_service_net_dma(sk, true); + tcp_cleanup_rbuf(sk, copied); + } else + dma_async_memcpy_issue_pending(tp->ucopy.dma_chan); + } #endif if (copied >= target) { /* Do not sleep, just process backlog. */ From 8d16c6268b7c3af2ce4f58de903588489e037fcf Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 3 Sep 2012 04:27:42 +0000 Subject: [PATCH 1135/2357] sctp: Don't charge for data in sndbuf again when transmitting packet [ Upstream commit 4c3a5bdae293f75cdf729c6c00124e8489af2276 ] SCTP charges wmem_alloc via sctp_set_owner_w() in sctp_sendmsg() and via skb_set_owner_w() in sctp_packet_transmit(). If a sender runs out of sndbuf it will sleep in sctp_wait_for_sndbuf() and expects to be waken up by __sctp_write_space(). Buffer space charged via sctp_set_owner_w() is released in sctp_wfree() which calls __sctp_write_space() directly. Buffer space charged via skb_set_owner_w() is released via sock_wfree() which calls sk->sk_write_space() _if_ SOCK_USE_WRITE_QUEUE is not set. sctp_endpoint_init() sets SOCK_USE_WRITE_QUEUE on all sockets. Therefore if sctp_packet_transmit() manages to queue up more than sndbuf bytes, sctp_wait_for_sndbuf() will never be woken up again unless it is interrupted by a signal. This could be fixed by clearing the SOCK_USE_WRITE_QUEUE flag but ... Charging for the data twice does not make sense in the first place, it leads to overcharging sndbuf by a factor 2. Therefore this patch only charges a single byte in wmem_alloc when transmitting an SCTP packet to ensure that the socket stays alive until the packet has been released. This means that control chunks are no longer accounted for in wmem_alloc which I believe is not a problem as skb->truesize will typically lead to overcharging anyway and thus compensates for any control overhead. Signed-off-by: Thomas Graf CC: Vlad Yasevich CC: Neil Horman CC: David Miller Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/output.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/net/sctp/output.c b/net/sctp/output.c index 8fc4dcd294a..32ba8d0e50e 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -334,6 +334,25 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, return retval; } +static void sctp_packet_release_owner(struct sk_buff *skb) +{ + sk_free(skb->sk); +} + +static void sctp_packet_set_owner_w(struct sk_buff *skb, struct sock *sk) +{ + skb_orphan(skb); + skb->sk = sk; + skb->destructor = sctp_packet_release_owner; + + /* + * The data chunks have already been accounted for in sctp_sendmsg(), + * therefore only reserve a single byte to keep socket around until + * the packet has been transmitted. + */ + atomic_inc(&sk->sk_wmem_alloc); +} + /* All packets are sent to the network through this function from * sctp_outq_tail(). * @@ -375,7 +394,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) /* Set the owning socket so that we know where to get the * destination IP address. */ - skb_set_owner_w(nskb, sk); + sctp_packet_set_owner_w(nskb, sk); if (!sctp_transport_dst_check(tp)) { sctp_transport_route(tp, NULL, sctp_sk(sk)); From e043257dde697ded17ed99f280cdb7643fdc007a Mon Sep 17 00:00:00 2001 From: Xiaodong Xu Date: Sat, 22 Sep 2012 00:09:32 +0000 Subject: [PATCH 1136/2357] pppoe: drop PPPOX_ZOMBIEs in pppoe_release [ Upstream commit 2b018d57ff18e5405823e5cb59651a5b4d946d7b ] When PPPOE is running over a virtual ethernet interface (e.g., a bonding interface) and the user tries to delete the interface in case the PPPOE state is ZOMBIE, the kernel will loop forever while unregistering net_device for the reference count is not decreased to zero which should have been done with dev_put(). Signed-off-by: Xiaodong Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ppp/pppoe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 2fa1a9b6f49..2e0d8762bb5 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -576,7 +576,7 @@ static int pppoe_release(struct socket *sock) po = pppox_sk(sk); - if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { + if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { dev_put(po->pppoe_dev); po->pppoe_dev = NULL; } From 6b8fc5c4eba92b5cd3c9ca0d926e99831604f81e Mon Sep 17 00:00:00 2001 From: Chema Gonzalez Date: Fri, 7 Sep 2012 13:40:50 +0000 Subject: [PATCH 1137/2357] net: small bug on rxhash calculation [ Upstream commit 6862234238e84648c305526af2edd98badcad1e0 ] In the current rxhash calculation function, while the sorting of the ports/addrs is coherent (you get the same rxhash for packets sharing the same 4-tuple, in both directions), ports and addrs are sorted independently. This implies packets from a connection between the same addresses but crossed ports hash to the same rxhash. For example, traffic between A=S:l and B=L:s is hashed (in both directions) from {L, S, {s, l}}. The same rxhash is obtained for packets between C=S:s and D=L:l. This patch ensures that you either swap both addrs and ports, or you swap none. Traffic between A and B, and traffic between C and D, get their rxhash from different sources ({L, S, {l, s}} for A<->B, and {L, S, {s, l}} for C<->D) The patch is co-written with Eric Dumazet Signed-off-by: Chema Gonzalez Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 3fd9cae3ccb..f9ae3975f6b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2617,15 +2617,16 @@ void __skb_get_rxhash(struct sk_buff *skb) if (!skb_flow_dissect(skb, &keys)) return; - if (keys.ports) { - if ((__force u16)keys.port16[1] < (__force u16)keys.port16[0]) - swap(keys.port16[0], keys.port16[1]); + if (keys.ports) skb->l4_rxhash = 1; - } /* get a consistent hash (same value on both flow directions) */ - if ((__force u32)keys.dst < (__force u32)keys.src) + if (((__force u32)keys.dst < (__force u32)keys.src) || + (((__force u32)keys.dst == (__force u32)keys.src) && + ((__force u16)keys.port16[1] < (__force u16)keys.port16[0]))) { swap(keys.dst, keys.src); + swap(keys.port16[0], keys.port16[1]); + } hash = jhash_3words((__force u32)keys.dst, (__force u32)keys.src, From 09c6cf7f980f1e8dbf58dc9ae0ebf4f6eb93cc0d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 24 Sep 2012 07:00:11 +0000 Subject: [PATCH 1138/2357] net: guard tcp_set_keepalive() to tcp sockets [ Upstream commit 3e10986d1d698140747fcfc2761ec9cb64c1d582 ] Its possible to use RAW sockets to get a crash in tcp_set_keepalive() / sk_reset_timer() Fix is to make sure socket is a SOCK_STREAM one. Reported-by: Dave Jones Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/sock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index d3e0a5201d4..4b469e36792 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -644,7 +644,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname, case SO_KEEPALIVE: #ifdef CONFIG_INET - if (sk->sk_protocol == IPPROTO_TCP) + if (sk->sk_protocol == IPPROTO_TCP && + sk->sk_type == SOCK_STREAM) tcp_set_keepalive(sk, valbool); #endif sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool); From 514ddfedb89c19c57de82aedec8da2bd8ff3802c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 22 Sep 2012 00:08:29 +0000 Subject: [PATCH 1139/2357] ipv4: raw: fix icmp_filter() [ Upstream commit ab43ed8b7490cb387782423ecf74aeee7237e591 ] icmp_filter() should not modify its input, or else its caller would need to recompute ip_hdr() if skb->head is reallocated. Use skb_header_pointer() instead of pskb_may_pull() and change the prototype to make clear both sk and skb are const. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/raw.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index bbd604c68e6..2fe0dc28ea9 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -131,18 +131,20 @@ static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, * 0 - deliver * 1 - block */ -static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb) +static int icmp_filter(const struct sock *sk, const struct sk_buff *skb) { - int type; + struct icmphdr _hdr; + const struct icmphdr *hdr; - if (!pskb_may_pull(skb, sizeof(struct icmphdr))) + hdr = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_hdr), &_hdr); + if (!hdr) return 1; - type = icmp_hdr(skb)->type; - if (type < 32) { + if (hdr->type < 32) { __u32 data = raw_sk(sk)->filter.data; - return ((1 << type) & data) != 0; + return ((1U << hdr->type) & data) != 0; } /* Do not block unknown ICMP types */ From 7a20f9c5fa76e602bf9dda7f610c8de04e7afa04 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 25 Sep 2012 07:03:40 +0000 Subject: [PATCH 1140/2357] ipv6: raw: fix icmpv6_filter() [ Upstream commit 1b05c4b50edbddbdde715c4a7350629819f6655e ] icmpv6_filter() should not modify its input, or else its caller would need to recompute ipv6_hdr() if skb->head is reallocated. Use skb_header_pointer() instead of pskb_may_pull() and change the prototype to make clear both sk and skb are const. Also, if icmpv6 header cannot be found, do not deliver the packet, as we do in IPv4. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/raw.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 5bddea77884..3ee28700de4 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -107,21 +107,20 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, * 0 - deliver * 1 - block */ -static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb) +static int icmpv6_filter(const struct sock *sk, const struct sk_buff *skb) { - struct icmp6hdr *icmph; - struct raw6_sock *rp = raw6_sk(sk); - - if (pskb_may_pull(skb, sizeof(struct icmp6hdr))) { - __u32 *data = &rp->filter.data[0]; - int bit_nr; + struct icmp6hdr *_hdr; + const struct icmp6hdr *hdr; - icmph = (struct icmp6hdr *) skb->data; - bit_nr = icmph->icmp6_type; + hdr = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_hdr), &_hdr); + if (hdr) { + const __u32 *data = &raw6_sk(sk)->filter.data[0]; + unsigned int type = hdr->icmp6_type; - return (data[bit_nr >> 5] & (1 << (bit_nr & 31))) != 0; + return (data[type >> 5] & (1U << (type & 31))) != 0; } - return 0; + return 1; } #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) From 28ad5c792deb17e1274cef32c59049d2062ed1b3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 25 Sep 2012 22:01:28 +0200 Subject: [PATCH 1141/2357] ipv6: mip6: fix mip6_mh_filter() [ Upstream commit 96af69ea2a83d292238bdba20e4508ee967cf8cb ] mip6_mh_filter() should not modify its input, or else its caller would need to recompute ipv6_hdr() if skb->head is reallocated. Use skb_header_pointer() instead of pskb_may_pull() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/mip6.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 7e1e0fbfef2..740c919e0b6 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -84,28 +84,30 @@ static int mip6_mh_len(int type) static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) { - struct ip6_mh *mh; + struct ip6_mh _hdr; + const struct ip6_mh *mh; - if (!pskb_may_pull(skb, (skb_transport_offset(skb)) + 8) || - !pskb_may_pull(skb, (skb_transport_offset(skb) + - ((skb_transport_header(skb)[1] + 1) << 3)))) + mh = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_hdr), &_hdr); + if (!mh) return -1; - mh = (struct ip6_mh *)skb_transport_header(skb); + if (((mh->ip6mh_hdrlen + 1) << 3) > skb->len) + return -1; if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) { LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n", mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type)); - mip6_param_prob(skb, 0, ((&mh->ip6mh_hdrlen) - - skb_network_header(skb))); + mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_hdrlen) + + skb_network_header_len(skb)); return -1; } if (mh->ip6mh_proto != IPPROTO_NONE) { LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n", mh->ip6mh_proto); - mip6_param_prob(skb, 0, ((&mh->ip6mh_proto) - - skb_network_header(skb))); + mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_proto) + + skb_network_header_len(skb)); return -1; } From bc0b2168aed1ecf0d71975af12d4f0ffecb92bfc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 4 Sep 2012 15:54:55 -0400 Subject: [PATCH 1142/2357] l2tp: fix a typo in l2tp_eth_dev_recv() [ Upstream commit c0cc88a7627c333de50b07b7c60b1d49d9d2e6cc ] While investigating l2tp bug, I hit a bug in eth_type_trans(), because not enough bytes were pulled in skb head. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 7446038e6b4..5c829077b25 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -132,7 +132,7 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, printk("\n"); } - if (!pskb_may_pull(skb, sizeof(ETH_HLEN))) + if (!pskb_may_pull(skb, ETH_HLEN)) goto error; secpath_reset(skb); From 782d596c84bf4239b24906132ba6367ca7dca865 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 4 Sep 2012 04:13:18 +0000 Subject: [PATCH 1143/2357] netrom: copy_datagram_iovec can fail [ Upstream commit 6cf5c951175abcec4da470c50565cc0afe6cd11d ] Check for an error from this and if so bail properly. Signed-off-by: Alan Cox Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netrom/af_netrom.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 06592d8b4a2..1b9024ee963 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1169,7 +1169,12 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock, msg->msg_flags |= MSG_TRUNC; } - skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + er = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (er < 0) { + skb_free_datagram(sk, skb); + release_sock(sk); + return er; + } if (sax != NULL) { sax->sax25_family = AF_NETROM; From 2583c9724757046ed749ec7d1fef2e371b02f203 Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 19 Sep 2012 15:49:00 +0000 Subject: [PATCH 1144/2357] net: do not disable sg for packets requiring no checksum [ Upstream commit c0d680e577ff171e7b37dbdb1b1bf5451e851f04 ] A change in a series of VLAN-related changes appears to have inadvertently disabled the use of the scatter gather feature of network cards for transmission of non-IP ethernet protocols like ATA over Ethernet (AoE). Below is a reference to the commit that introduces a "harmonize_features" function that turns off scatter gather when the NIC does not support hardware checksumming for the ethernet protocol of an sk buff. commit f01a5236bd4b140198fbcc550f085e8361fd73fa Author: Jesse Gross Date: Sun Jan 9 06:23:31 2011 +0000 net offloading: Generalize netif_get_vlan_features(). The can_checksum_protocol function is not equipped to consider a protocol that does not require checksumming. Calling it for a protocol that requires no checksum is inappropriate. The patch below has harmonize_features call can_checksum_protocol when the protocol needs a checksum, so that the network layer is not forced to perform unnecessary skb linearization on the transmission of AoE packets. Unnecessary linearization results in decreased performance and increased memory pressure, as reported here: http://www.spinics.net/lists/linux-mm/msg15184.html The problem has probably not been widely experienced yet, because only recently has the kernel.org-distributed aoe driver acquired the ability to use payloads of over a page in size, with the patchset recently included in the mm tree: https://lkml.org/lkml/2012/8/28/140 The coraid.com-distributed aoe driver already could use payloads of greater than a page in size, but its users generally do not use the newest kernels. Signed-off-by: Ed Cashin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index f9ae3975f6b..086bc2e578c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2121,7 +2121,8 @@ static bool can_checksum_protocol(netdev_features_t features, __be16 protocol) static netdev_features_t harmonize_features(struct sk_buff *skb, __be16 protocol, netdev_features_t features) { - if (!can_checksum_protocol(features, protocol)) { + if (skb->ip_summed != CHECKSUM_NONE && + !can_checksum_protocol(features, protocol)) { features &= ~NETIF_F_ALL_CSUM; features &= ~NETIF_F_SG; } else if (illegal_highdma(skb->dev, skb)) { From fa9a48a7bed7d785a98356d4d06090500ec00c82 Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 19 Sep 2012 15:46:39 +0000 Subject: [PATCH 1145/2357] aoe: assert AoE packets marked as requiring no checksum [ Upstream commit 8babe8cc6570ed896b7b596337eb8fe730c3ff45 ] In order for the network layer to see that AoE requires no checksumming in a generic way, the packets must be marked as requiring no checksum, so we make this requirement explicit with the assertion. Signed-off-by: Ed Cashin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoecmd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index de0435e63b0..887f68f6d79 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -35,6 +35,7 @@ new_skb(ulong len) skb_reset_mac_header(skb); skb_reset_network_header(skb); skb->protocol = __constant_htons(ETH_P_AOE); + skb_checksum_none_assert(skb); } return skb; } From 194cca171bc5a062974d96b0246cde0c65ac33d0 Mon Sep 17 00:00:00 2001 From: Florian Zumbiehl Date: Tue, 2 Oct 2012 12:20:37 +0000 Subject: [PATCH 1146/2357] drm/savage: re-add busmaster enable, regression fix commit df86b5765a48d5f557489577652bd6df145b0e1b upstream. 466e69b8b03b8c1987367912782bc12988ad8794 dropped busmaster enable from the global drm code and moved it to the individual drivers, but missed the savage driver. So, this re-adds busmaster enable to the savage driver, fixing the regression. Signed-off-by: Florian Zumbiehl Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/savage/savage_bci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index cb1ee4e0050..2a258887e41 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -547,6 +547,8 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->chipset = (enum savage_family)chipset; + pci_set_master(dev->pdev); + return 0; } From ab617446730e46080235b9e158d364bab233e9ee Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Tue, 4 Sep 2012 15:23:29 +0200 Subject: [PATCH 1147/2357] SCSI: zfcp: Adapt to new FC_PORTSPEED semantics commit d22019778cd9ea04c1dadf7bf453920d5288f8d9 upstream. Commit a9277e7783651d4e0a849f7988340b1c1cf748a4 "[SCSI] scsi_transport_fc: Getting FC Port Speed in sync with FC-GS" changed the semantics of FC_PORTSPEED defines to FDMI port attributes of FC-HBA/SM-HBA which is different from the previous bit reversed Report Port Speed Capabilities (RPSC) ELS of FC-GS/FC-LS. Zfcp showed "10 Gbit" instead of "4 Gbit" for supported_speeds. It now uses explicit bit conversion as the other LLDs already do, in order to be independent of the kernel bit semantics. See also http://marc.info/?l=linux-scsi&m=134452926830730&w=2 Signed-off-by: Steffen Maier Reviewed-by: Martin Peschke Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_fsf.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index e9a787e2e6a..613ce11d06c 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -437,6 +437,34 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) } } +#define ZFCP_FSF_PORTSPEED_1GBIT (1 << 0) +#define ZFCP_FSF_PORTSPEED_2GBIT (1 << 1) +#define ZFCP_FSF_PORTSPEED_4GBIT (1 << 2) +#define ZFCP_FSF_PORTSPEED_10GBIT (1 << 3) +#define ZFCP_FSF_PORTSPEED_8GBIT (1 << 4) +#define ZFCP_FSF_PORTSPEED_16GBIT (1 << 5) +#define ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED (1 << 15) + +static u32 zfcp_fsf_convert_portspeed(u32 fsf_speed) +{ + u32 fdmi_speed = 0; + if (fsf_speed & ZFCP_FSF_PORTSPEED_1GBIT) + fdmi_speed |= FC_PORTSPEED_1GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_2GBIT) + fdmi_speed |= FC_PORTSPEED_2GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_4GBIT) + fdmi_speed |= FC_PORTSPEED_4GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_10GBIT) + fdmi_speed |= FC_PORTSPEED_10GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_8GBIT) + fdmi_speed |= FC_PORTSPEED_8GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_16GBIT) + fdmi_speed |= FC_PORTSPEED_16GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED) + fdmi_speed |= FC_PORTSPEED_NOT_NEGOTIATED; + return fdmi_speed; +} + static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) { struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config; @@ -456,7 +484,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) fc_host_port_name(shost) = nsp->fl_wwpn; fc_host_node_name(shost) = nsp->fl_wwnn; fc_host_port_id(shost) = ntoh24(bottom->s_id); - fc_host_speed(shost) = bottom->fc_link_speed; + fc_host_speed(shost) = + zfcp_fsf_convert_portspeed(bottom->fc_link_speed); fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; adapter->hydra_version = bottom->adapter_type; @@ -580,7 +609,8 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req) } else fc_host_permanent_port_name(shost) = fc_host_port_name(shost); fc_host_maxframe_size(shost) = bottom->maximum_frame_size; - fc_host_supported_speeds(shost) = bottom->supported_speed; + fc_host_supported_speeds(shost) = + zfcp_fsf_convert_portspeed(bottom->supported_speed); memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types, FC_FC4_LIST_SIZE); memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types, From 1afbcbdd1c0761ca9e807e78fa106efc465c3925 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Tue, 4 Sep 2012 15:23:30 +0200 Subject: [PATCH 1148/2357] SCSI: zfcp: Make trace record tags unique commit 0100998dbfe6dfcd90a6e912ca7ed6f255d48f25 upstream. Duplicate fssrh_2 from a54ca0f62f953898b05549391ac2a8a4dad6482b "[SCSI] zfcp: Redesign of the debug tracing for HBA records." complicates distinction of generic status read response from local link up. Duplicate fsscth1 from 2c55b750a884b86dea8b4cc5f15e1484cc47a25c "[SCSI] zfcp: Redesign of the debug tracing for SAN records." complicates distinction of good common transport response from invalid port handle. Signed-off-by: Steffen Maier Reviewed-by: Martin Peschke Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_fsf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 613ce11d06c..e9d10f45241 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -219,7 +219,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) return; } - zfcp_dbf_hba_fsf_uss("fssrh_2", req); + zfcp_dbf_hba_fsf_uss("fssrh_4", req); switch (sr_buf->status_type) { case FSF_STATUS_READ_PORT_CLOSED: @@ -915,7 +915,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_GOOD: - zfcp_dbf_san_res("fsscth1", req); + zfcp_dbf_san_res("fsscth2", req); ct->status = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: From 2872405ba2729853da43865893469f8cb80b69b2 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Tue, 4 Sep 2012 15:23:31 +0200 Subject: [PATCH 1149/2357] SCSI: zfcp: Bounds checking for deferred error trace commit 01e60527f0a49b3d7df603010bd6079bb4b6cf07 upstream. The pl vector has scount elements, i.e. pl[scount-1] is the last valid element. For maximum sized requests, payload->counter == scount after the last loop iteration. Therefore, do bounds checking first (with boolean shortcut) to not access the invalid element pl[scount]. Do not trust the maximum sbale->scount value from the HBA but ensure we won't access the pl vector out of our allocated bounds. While at it, clean up scoping and prevent unnecessary memset. Minor fix for 86a9668a8d29ea711613e1cb37efa68e7c4db564 "[SCSI] zfcp: support for hardware data router" Signed-off-by: Steffen Maier Reviewed-by: Martin Peschke Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_dbf.c | 2 +- drivers/s390/scsi/zfcp_qdio.c | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index a9a816e4aa5..bdca8e69290 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -191,7 +191,7 @@ void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount, length = min((u16)sizeof(struct qdio_buffer), (u16)ZFCP_DBF_PAY_MAX_REC); - while ((char *)pl[payload->counter] && payload->counter < scount) { + while (payload->counter < scount && (char *)pl[payload->counter]) { memcpy(payload->data, (char *)pl[payload->counter], length); debug_event(dbf->pay, 1, payload, zfcp_dbf_plen(length)); payload->counter++; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index e14da5751d3..e76d003ebdb 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -102,18 +102,22 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, { struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; struct zfcp_adapter *adapter = qdio->adapter; - struct qdio_buffer_element *sbale; int sbal_no, sbal_idx; - void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1]; - u64 req_id; - u8 scount; if (unlikely(qdio_err)) { - memset(pl, 0, ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *)); if (zfcp_adapter_multi_buffer_active(adapter)) { + void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1]; + struct qdio_buffer_element *sbale; + u64 req_id; + u8 scount; + + memset(pl, 0, + ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *)); sbale = qdio->res_q[idx]->element; req_id = (u64) sbale->addr; - scount = sbale->scount + 1; /* incl. signaling SBAL */ + scount = min(sbale->scount + 1, + ZFCP_QDIO_MAX_SBALS_PER_REQ + 1); + /* incl. signaling SBAL */ for (sbal_no = 0; sbal_no < scount; sbal_no++) { sbal_idx = (idx + sbal_no) % From 530bab7e87951aea1ae20706174021c3355f305a Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Tue, 4 Sep 2012 15:23:32 +0200 Subject: [PATCH 1150/2357] SCSI: zfcp: Do not wakeup while suspended commit cb45214960bc989af8b911ebd77da541c797717d upstream. If the mapping of FCP device bus ID and corresponding subchannel is modified while the Linux image is suspended, the resume of FCP devices can fail. During resume, zfcp gets callbacks from cio regarding the modified subchannels but they can be arbitrarily mixed with the restore/resume callback. Since the cio callbacks would trigger adapter recovery, zfcp could wakeup before the resume callback. Therefore, ignore the cio callbacks regarding subchannels while being suspended. We can safely do so, since zfcp does not deal itself with subchannels. For problem determination purposes, we still trace the ignored callback events. The following kernel messages could be seen on resume: kernel: : parent should not be sleeping As part of adapter reopen recovery, zfcp performs auto port scanning which can erroneously try to register new remote ports with scsi_transport_fc and the device core code complains about the parent (adapter) still sleeping. kernel: zfcp.3dff9c: :\ Setting up the QDIO connection to the FCP adapter failed kernel: zfcp.574d43: :\ ERP cannot recover an error on the FCP device In such cases, the adapter gave up recovery and remained blocked along with its child objects: remote ports and LUNs/scsi devices. Even the adapter shutdown as part of giving up recovery failed because the ccw device state remained disconnected. Later, the corresponding remote ports ran into dev_loss_tmo. As a result, the LUNs were erroneously not available again after resume. Even a manually triggered adapter recovery (e.g. sysfs attribute failed, or device offline/online via sysfs) could not recover the adapter due to the remaining disconnected state of the corresponding ccw device. Signed-off-by: Steffen Maier Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_ccw.c | 73 +++++++++++++++++++++++++++++++----- drivers/s390/scsi/zfcp_dbf.c | 20 ++++++++++ drivers/s390/scsi/zfcp_dbf.h | 1 + drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_ext.h | 1 + 5 files changed, 86 insertions(+), 10 deletions(-) diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 96f13ad8812..79a6afe0212 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -39,17 +39,23 @@ void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter) spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); } -static int zfcp_ccw_activate(struct ccw_device *cdev) - +/** + * zfcp_ccw_activate - activate adapter and wait for it to finish + * @cdev: pointer to belonging ccw device + * @clear: Status flags to clear. + * @tag: s390dbf trace record tag + */ +static int zfcp_ccw_activate(struct ccw_device *cdev, int clear, char *tag) { struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); if (!adapter) return 0; + zfcp_erp_clear_adapter_status(adapter, clear); zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "ccresu2"); + tag); zfcp_erp_wait(adapter); flush_work(&adapter->scan_work); @@ -164,32 +170,47 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev) BUG_ON(!zfcp_reqlist_isempty(adapter->req_list)); adapter->req_no = 0; - zfcp_ccw_activate(cdev); + zfcp_ccw_activate(cdev, 0, "ccsonl1"); zfcp_ccw_adapter_put(adapter); return 0; } /** - * zfcp_ccw_set_offline - set_offline function of zfcp driver + * zfcp_ccw_offline_sync - shut down adapter and wait for it to finish * @cdev: pointer to belonging ccw device + * @set: Status flags to set. + * @tag: s390dbf trace record tag * * This function gets called by the common i/o layer and sets an adapter * into state offline. */ -static int zfcp_ccw_set_offline(struct ccw_device *cdev) +static int zfcp_ccw_offline_sync(struct ccw_device *cdev, int set, char *tag) { struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); if (!adapter) return 0; - zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1"); + zfcp_erp_set_adapter_status(adapter, set); + zfcp_erp_adapter_shutdown(adapter, 0, tag); zfcp_erp_wait(adapter); zfcp_ccw_adapter_put(adapter); return 0; } +/** + * zfcp_ccw_set_offline - set_offline function of zfcp driver + * @cdev: pointer to belonging ccw device + * + * This function gets called by the common i/o layer and sets an adapter + * into state offline. + */ +static int zfcp_ccw_set_offline(struct ccw_device *cdev) +{ + return zfcp_ccw_offline_sync(cdev, 0, "ccsoff1"); +} + /** * zfcp_ccw_notify - ccw notify function * @cdev: pointer to belonging ccw device @@ -207,6 +228,11 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event) switch (event) { case CIO_GONE: + if (atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */ + zfcp_dbf_hba_basic("ccnigo1", adapter); + break; + } dev_warn(&cdev->dev, "The FCP device has been detached\n"); zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1"); break; @@ -216,6 +242,11 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event) zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2"); break; case CIO_OPER: + if (atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */ + zfcp_dbf_hba_basic("ccniop1", adapter); + break; + } dev_info(&cdev->dev, "The FCP device is operational again\n"); zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); @@ -251,6 +282,28 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) zfcp_ccw_adapter_put(adapter); } +static int zfcp_ccw_suspend(struct ccw_device *cdev) +{ + zfcp_ccw_offline_sync(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccsusp1"); + return 0; +} + +static int zfcp_ccw_thaw(struct ccw_device *cdev) +{ + /* trace records for thaw and final shutdown during suspend + can only be found in system dump until the end of suspend + but not after resume because it's based on the memory image + right after the very first suspend (freeze) callback */ + zfcp_ccw_activate(cdev, 0, "ccthaw1"); + return 0; +} + +static int zfcp_ccw_resume(struct ccw_device *cdev) +{ + zfcp_ccw_activate(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccresu1"); + return 0; +} + struct ccw_driver zfcp_ccw_driver = { .driver = { .owner = THIS_MODULE, @@ -263,7 +316,7 @@ struct ccw_driver zfcp_ccw_driver = { .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, .shutdown = zfcp_ccw_shutdown, - .freeze = zfcp_ccw_set_offline, - .thaw = zfcp_ccw_activate, - .restore = zfcp_ccw_activate, + .freeze = zfcp_ccw_suspend, + .thaw = zfcp_ccw_thaw, + .restore = zfcp_ccw_resume, }; diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index bdca8e69290..79b98482547 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -200,6 +200,26 @@ void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount, spin_unlock_irqrestore(&dbf->pay_lock, flags); } +/** + * zfcp_dbf_hba_basic - trace event for basic adapter events + * @adapter: pointer to struct zfcp_adapter + */ +void zfcp_dbf_hba_basic(char *tag, struct zfcp_adapter *adapter) +{ + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_dbf_hba *rec = &dbf->hba_buf; + unsigned long flags; + + spin_lock_irqsave(&dbf->hba_lock, flags); + memset(rec, 0, sizeof(*rec)); + + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + rec->id = ZFCP_DBF_HBA_BASIC; + + debug_event(dbf->hba, 1, rec, sizeof(*rec)); + spin_unlock_irqrestore(&dbf->hba_lock, flags); +} + static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec, struct zfcp_adapter *adapter, struct zfcp_port *port, diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 714f087eb7a..3ac7a4b30dd 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -154,6 +154,7 @@ enum zfcp_dbf_hba_id { ZFCP_DBF_HBA_RES = 1, ZFCP_DBF_HBA_USS = 2, ZFCP_DBF_HBA_BIT = 3, + ZFCP_DBF_HBA_BASIC = 4, }; /** diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index ed5d921e82c..6009c3bf31c 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -77,6 +77,7 @@ struct zfcp_reqlist; #define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004 #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 +#define ZFCP_STATUS_ADAPTER_SUSPENDED 0x00000040 #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 #define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED 0x00000400 diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 2302e1cfb76..1564ba24de6 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -54,6 +54,7 @@ extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **); +extern void zfcp_dbf_hba_basic(char *, struct zfcp_adapter *); extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); From ab37eb284ac88f092187f7c4ee4a42c28cdaf3e5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 4 Sep 2012 15:23:33 +0200 Subject: [PATCH 1151/2357] SCSI: zfcp: remove invalid reference to list iterator variable commit ca579c9f136af4274ccfd1bcaee7f38a29a0e2e9 upstream. If list_for_each_entry, etc complete a traversal of the list, the iterator variable ends up pointing to an address at an offset from the list head, and not a meaningful structure. Thus this value should not be used after the end of the iterator. Replace port->adapter->scsi_host by adapter->scsi_host. This problem was found using Coccinelle (http://coccinelle.lip6.fr/). Oversight in upsteam commit of v2.6.37 a1ca48319a9aa1c5b57ce142f538e76050bb8972 "[SCSI] zfcp: Move ACL/CFDC code to zfcp_cfdc.c" which merged the content of zfcp_erp_port_access_changed(). Signed-off-by: Julia Lawall Signed-off-by: Steffen Maier Reviewed-by: Martin Peschke Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_cfdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index fab2c2592a9..8ed63aa9abe 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -293,7 +293,7 @@ void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter) } read_unlock_irqrestore(&adapter->port_list_lock, flags); - shost_for_each_device(sdev, port->adapter->scsi_host) { + shost_for_each_device(sdev, adapter->scsi_host) { zfcp_sdev = sdev_to_zfcp(sdev); status = atomic_read(&zfcp_sdev->status); if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) || From 960e8a5e0257c26bb5d5b14c8c89919e1293e76c Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Tue, 4 Sep 2012 15:23:34 +0200 Subject: [PATCH 1152/2357] SCSI: zfcp: restore refcount check on port_remove commit d99b601b63386f3395dc26a699ae703a273d9982 upstream. Upstream commit f3450c7b917201bb49d67032e9f60d5125675d6a "[SCSI] zfcp: Replace local reference counting with common kref" accidentally dropped a reference count check before tearing down zfcp_ports that are potentially in use by zfcp_units. Even remote ports in use can be removed causing unreachable garbage objects zfcp_ports with zfcp_units. Thus units won't come back even after a manual port_rescan. The kref of zfcp_port->dev.kobj is already used by the driver core. We cannot re-use it to track the number of zfcp_units. Re-introduce our own counter for units per port and check on port_remove. Signed-off-by: Steffen Maier Reviewed-by: Heiko Carstens Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_aux.c | 1 + drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_ext.h | 1 + drivers/s390/scsi/zfcp_sysfs.c | 18 +++++++++++++++-- drivers/s390/scsi/zfcp_unit.c | 36 ++++++++++++++++++++++++---------- 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 08601810966..4f1b10b7dea 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -519,6 +519,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, rwlock_init(&port->unit_list_lock); INIT_LIST_HEAD(&port->unit_list); + atomic_set(&port->units, 0); INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 6009c3bf31c..f172b844217 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -205,6 +205,7 @@ struct zfcp_port { struct zfcp_adapter *adapter; /* adapter used to access port */ struct list_head unit_list; /* head of logical unit list */ rwlock_t unit_list_lock; /* unit list lock */ + atomic_t units; /* zfcp_unit count */ atomic_t status; /* status of this remote port */ u64 wwnn; /* WWNN if known */ u64 wwpn; /* WWPN */ diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 1564ba24de6..ef9e50225ee 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -159,6 +159,7 @@ extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int); extern struct attribute_group zfcp_sysfs_unit_attrs; extern struct attribute_group zfcp_sysfs_adapter_attrs; extern struct attribute_group zfcp_sysfs_port_attrs; +extern struct mutex zfcp_sysfs_port_units_mutex; extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; extern struct device_attribute *zfcp_sysfs_shost_attrs[]; diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index cdc4ff78a7b..9e62210b294 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -227,6 +227,8 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, zfcp_sysfs_port_rescan_store); +DEFINE_MUTEX(zfcp_sysfs_port_units_mutex); + static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -249,6 +251,16 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, else retval = 0; + mutex_lock(&zfcp_sysfs_port_units_mutex); + if (atomic_read(&port->units) > 0) { + retval = -EBUSY; + mutex_unlock(&zfcp_sysfs_port_units_mutex); + goto out; + } + /* port is about to be removed, so no more unit_add */ + atomic_set(&port->units, -1); + mutex_unlock(&zfcp_sysfs_port_units_mutex); + write_lock_irq(&adapter->port_list_lock); list_del(&port->list); write_unlock_irq(&adapter->port_list_lock); @@ -289,12 +301,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, { struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); u64 fcp_lun; + int retval; if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) return -EINVAL; - if (zfcp_unit_add(port, fcp_lun)) - return -EINVAL; + retval = zfcp_unit_add(port, fcp_lun); + if (retval) + return retval; return count; } diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c index 20796ebc33c..4e6a5356bdb 100644 --- a/drivers/s390/scsi/zfcp_unit.c +++ b/drivers/s390/scsi/zfcp_unit.c @@ -104,7 +104,7 @@ static void zfcp_unit_release(struct device *dev) { struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); - put_device(&unit->port->dev); + atomic_dec(&unit->port->units); kfree(unit); } @@ -119,16 +119,27 @@ static void zfcp_unit_release(struct device *dev) int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) { struct zfcp_unit *unit; + int retval = 0; + + mutex_lock(&zfcp_sysfs_port_units_mutex); + if (atomic_read(&port->units) == -1) { + /* port is already gone */ + retval = -ENODEV; + goto out; + } unit = zfcp_unit_find(port, fcp_lun); if (unit) { put_device(&unit->dev); - return -EEXIST; + retval = -EEXIST; + goto out; } unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); - if (!unit) - return -ENOMEM; + if (!unit) { + retval = -ENOMEM; + goto out; + } unit->port = port; unit->fcp_lun = fcp_lun; @@ -139,28 +150,33 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) if (dev_set_name(&unit->dev, "0x%016llx", (unsigned long long) fcp_lun)) { kfree(unit); - return -ENOMEM; + retval = -ENOMEM; + goto out; } - get_device(&port->dev); - if (device_register(&unit->dev)) { put_device(&unit->dev); - return -ENOMEM; + retval = -ENOMEM; + goto out; } if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) { device_unregister(&unit->dev); - return -EINVAL; + retval = -EINVAL; + goto out; } + atomic_inc(&port->units); /* under zfcp_sysfs_port_units_mutex ! */ + write_lock_irq(&port->unit_list_lock); list_add_tail(&unit->list, &port->unit_list); write_unlock_irq(&port->unit_list_lock); zfcp_unit_scsi_scan(unit); - return 0; +out: + mutex_unlock(&zfcp_sysfs_port_units_mutex); + return retval; } /** From 82e0551186fd455d792fccae805470f222339c06 Mon Sep 17 00:00:00 2001 From: Martin Peschke Date: Tue, 4 Sep 2012 15:23:36 +0200 Subject: [PATCH 1153/2357] SCSI: zfcp: only access zfcp_scsi_dev for valid scsi_device commit d436de8ce25f53a8a880a931886821f632247943 upstream. __scsi_remove_device (e.g. due to dev_loss_tmo) calls zfcp_scsi_slave_destroy which in turn sends a close LUN FSF request to the adapter. After 30 seconds without response, zfcp_erp_timeout_handler kicks the ERP thread failing the close LUN ERP action. zfcp_erp_wait in zfcp_erp_lun_shutdown_wait and thus zfcp_scsi_slave_destroy returns and then scsi_device is no longer valid. Sometime later the response to the close LUN FSF request may finally come in. However, commit b62a8d9b45b971a67a0f8413338c230e3117dff5 "[SCSI] zfcp: Use SCSI device data zfcp_scsi_dev instead of zfcp_unit" introduced a number of attempts to unconditionally access struct zfcp_scsi_dev through struct scsi_device causing a use-after-free. This leads to an Oops due to kernel page fault in one of: zfcp_fsf_abort_fcp_command_handler, zfcp_fsf_open_lun_handler, zfcp_fsf_close_lun_handler, zfcp_fsf_req_trace, zfcp_fsf_fcp_handler_common. Move dereferencing of zfcp private data zfcp_scsi_dev allocated in scsi_device via scsi_transport_reserve_device after the check for potentially aborted FSF request and thus no longer valid scsi_device. Only then assign sdev_to_zfcp(sdev) to the local auto variable struct zfcp_scsi_dev *zfcp_sdev. Signed-off-by: Martin Peschke Signed-off-by: Steffen Maier Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_fsf.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index e9d10f45241..2136fc2178e 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -801,12 +801,14 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio) static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) { struct scsi_device *sdev = req->data; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_scsi_dev *zfcp_sdev; union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; + zfcp_sdev = sdev_to_zfcp(sdev); + switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: if (fsq->word[0] == fsq->word[1]) { @@ -1769,13 +1771,15 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; struct scsi_device *sdev = req->data; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_scsi_dev *zfcp_sdev; struct fsf_qtcb_header *header = &req->qtcb->header; struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; + zfcp_sdev = sdev_to_zfcp(sdev); + atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_COMMON_ACCESS_BOXED | ZFCP_STATUS_LUN_SHARED | @@ -1886,11 +1890,13 @@ int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action) static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) { struct scsi_device *sdev = req->data; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_scsi_dev *zfcp_sdev; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; + zfcp_sdev = sdev_to_zfcp(sdev); + switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1"); @@ -1980,7 +1986,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) { struct fsf_qual_latency_info *lat_in; struct latency_cont *lat = NULL; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scsi->device); + struct zfcp_scsi_dev *zfcp_sdev; struct zfcp_blk_drv_data blktrc; int ticks = req->adapter->timer_ticks; @@ -1995,6 +2001,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA && !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { + zfcp_sdev = sdev_to_zfcp(scsi->device); blktrc.flags |= ZFCP_BLK_LAT_VALID; blktrc.channel_lat = lat_in->channel_lat * ticks; blktrc.fabric_lat = lat_in->fabric_lat * ticks; @@ -2032,12 +2039,14 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) { struct scsi_cmnd *scmnd = req->data; struct scsi_device *sdev = scmnd->device; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_scsi_dev *zfcp_sdev; struct fsf_qtcb_header *header = &req->qtcb->header; if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) return; + zfcp_sdev = sdev_to_zfcp(sdev); + switch (header->fsf_status) { case FSF_HANDLE_MISMATCH: case FSF_PORT_HANDLE_NOT_VALID: From b790ef23cd1fd3fece4777e90d85a945c4820ae7 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 10 Sep 2012 17:19:33 -0700 Subject: [PATCH 1154/2357] PCI: Check P2P bridge for invalid secondary/subordinate range commit 1965f66e7db08d1ebccd24a59043eba826cc1ce8 upstream. For bridges with "secondary > subordinate", i.e., invalid bus number apertures, we don't enumerate anything behind the bridge unless the user specified "pci=assign-busses". This patch makes us automatically try to reassign the downstream bus numbers in this case (just for that bridge, not for all bridges as "pci=assign-busses" does). We don't discover all the devices on the Intel DP43BF motherboard without this change (or "pci=assign-busses") because its BIOS configures a bridge as: pci 0000:00:1e.0: PCI bridge to [bus 20-08] (subtractive decode) [bhelgaas: changelog, change message to dev_info] Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=18412 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=625754 Reported-by: Brian C. Huffman Reported-by: VL Tested-by: VL Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5e1ca3c58a7..63e0199f7c7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -749,8 +749,10 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, /* Check if setup is sensible at all */ if (!pass && - (primary != bus->number || secondary <= bus->number)) { - dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n"); + (primary != bus->number || secondary <= bus->number || + secondary > subordinate)) { + dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n", + secondary, subordinate); broken = 1; } From 2d5a1fbc0c25ab4a2e2770a5c729467893407009 Mon Sep 17 00:00:00 2001 From: Yongqiang Yang Date: Wed, 5 Sep 2012 01:21:50 -0400 Subject: [PATCH 1155/2357] ext4: ignore last group w/o enough space when resizing instead of BUG'ing commit 03c1c29053f678234dbd51bf3d65f3b7529021de upstream. If the last group does not have enough space for group tables, ignore it instead of calling BUG_ON(). Reported-by: Daniel Drake Signed-off-by: Yongqiang Yang Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/resize.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 3407a62590d..46d9ec8453f 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -200,8 +200,11 @@ static void free_flex_gd(struct ext4_new_flex_group_data *flex_gd) * be a partial of a flex group. * * @sb: super block of fs to which the groups belongs + * + * Returns 0 on a successful allocation of the metadata blocks in the + * block group. */ -static void ext4_alloc_group_tables(struct super_block *sb, +static int ext4_alloc_group_tables(struct super_block *sb, struct ext4_new_flex_group_data *flex_gd, int flexbg_size) { @@ -226,6 +229,8 @@ static void ext4_alloc_group_tables(struct super_block *sb, (last_group & ~(flexbg_size - 1)))); next_group: group = group_data[0].group; + if (src_group >= group_data[0].group + flex_gd->count) + return -ENOSPC; start_blk = ext4_group_first_block_no(sb, src_group); last_blk = start_blk + group_data[src_group - group].blocks_count; @@ -235,7 +240,6 @@ static void ext4_alloc_group_tables(struct super_block *sb, start_blk += overhead; - BUG_ON(src_group >= group_data[0].group + flex_gd->count); /* We collect contiguous blocks as much as possible. */ src_group++; for (; src_group <= last_group; src_group++) @@ -300,6 +304,7 @@ static void ext4_alloc_group_tables(struct super_block *sb, group_data[i].free_blocks_count); } } + return 0; } static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, @@ -1676,7 +1681,8 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) */ while (ext4_setup_next_flex_gd(sb, flex_gd, n_blocks_count, flexbg_size)) { - ext4_alloc_group_tables(sb, flex_gd, flexbg_size); + if (ext4_alloc_group_tables(sb, flex_gd, flexbg_size) != 0) + break; err = ext4_flex_group_add(sb, resize_inode, flex_gd); if (unlikely(err)) break; From 1079d76f47379886ebfd3ae0f79a9f6cd62df29e Mon Sep 17 00:00:00 2001 From: Yongqiang Yang Date: Wed, 5 Sep 2012 01:25:50 -0400 Subject: [PATCH 1156/2357] ext4: don't copy non-existent gdt blocks when resizing commit 6df935ad2fced9033ab52078825fcaf6365f34b7 upstream. The resize code was copying blocks at the beginning of each block group in order to copy the superblock and block group descriptor table (gdt) blocks. This was, unfortunately, being done even for block groups that did not have super blocks or gdt blocks. This is a complete waste of perfectly good I/O bandwidth, to skip writing those blocks for sparse bg's. Signed-off-by: Yongqiang Yang Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/resize.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 46d9ec8453f..257d2f00311 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -456,6 +456,9 @@ static int setup_new_flex_group_blocks(struct super_block *sb, gdblocks = ext4_bg_num_gdb(sb, group); start = ext4_group_first_block_no(sb, group); + if (!ext4_bg_has_super(sb, group)) + goto handle_itb; + /* Copy all of the GDT blocks into the backup in this group */ for (j = 0, block = start + 1; j < gdblocks; j++, block++) { struct buffer_head *gdb; @@ -498,6 +501,7 @@ static int setup_new_flex_group_blocks(struct super_block *sb, goto out; } +handle_itb: /* Initialize group tables of the grop @group */ if (!(bg_flags[i] & EXT4_BG_INODE_ZEROED)) goto handle_bb; From 2de1ece4de710668bb53eff74bffe80bb267087f Mon Sep 17 00:00:00 2001 From: Yongqiang Yang Date: Wed, 5 Sep 2012 01:27:50 -0400 Subject: [PATCH 1157/2357] ext4: avoid duplicate writes of the backup bg descriptor blocks commit 2ebd1704ded88a8ae29b5f3998b13959c715c4be upstream. The resize code was needlessly writing the backup block group descriptor blocks multiple times (once per block group) during an online resize. Signed-off-by: Yongqiang Yang Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/resize.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 257d2f00311..231cacb8f64 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -1302,13 +1302,15 @@ static int ext4_flex_group_add(struct super_block *sb, err = err2; if (!err) { - int i; + int gdb_num = group / EXT4_DESC_PER_BLOCK(sb); + int gdb_num_end = ((group + flex_gd->count - 1) / + EXT4_DESC_PER_BLOCK(sb)); + update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, sizeof(struct ext4_super_block)); - for (i = 0; i < flex_gd->count; i++, group++) { + for (; gdb_num <= gdb_num_end; gdb_num++) { struct buffer_head *gdb_bh; - int gdb_num; - gdb_num = group / EXT4_BLOCKS_PER_GROUP(sb); + gdb_bh = sbi->s_group_desc[gdb_num]; update_backups(sb, gdb_bh->b_blocknr, gdb_bh->b_data, gdb_bh->b_size); From 78790d120fd2a6ffa39dc23e57fdf9133e67b14c Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 19 Sep 2012 22:42:36 -0400 Subject: [PATCH 1158/2357] ext4: fix potential deadlock in ext4_nonda_switch() commit 00d4e7362ed01987183e9528295de3213031309c upstream. In ext4_nonda_switch(), if the file system is getting full we used to call writeback_inodes_sb_if_idle(). The problem is that we can be holding i_mutex already, and this causes a potential deadlock when writeback_inodes_sb_if_idle() when it tries to take s_umount. (See lockdep output below). As it turns out we don't need need to hold s_umount; the fact that we are in the middle of the write(2) system call will keep the superblock pinned. Unfortunately writeback_inodes_sb() checks to make sure s_umount is taken, and the VFS uses a different mechanism for making sure the file system doesn't get unmounted out from under us. The simplest way of dealing with this is to just simply grab s_umount using a trylock, and skip kicking the writeback flusher thread in the very unlikely case that we can't take a read lock on s_umount without blocking. Also, we now check the cirteria for kicking the writeback thread before we decide to whether to fall back to non-delayed writeback, so if there are any outstanding delayed allocation writes, we try to get them resolved as soon as possible. [ INFO: possible circular locking dependency detected ] 3.6.0-rc1-00042-gce894ca #367 Not tainted ------------------------------------------------------- dd/8298 is trying to acquire lock: (&type->s_umount_key#18){++++..}, at: [] writeback_inodes_sb_if_idle+0x28/0x46 but task is already holding lock: (&sb->s_type->i_mutex_key#8){+.+...}, at: [] generic_file_aio_write+0x5f/0xd3 which lock already depends on the new lock. 2 locks held by dd/8298: #0: (sb_writers#2){.+.+.+}, at: [] generic_file_aio_write+0x56/0xd3 #1: (&sb->s_type->i_mutex_key#8){+.+...}, at: [] generic_file_aio_write+0x5f/0xd3 stack backtrace: Pid: 8298, comm: dd Not tainted 3.6.0-rc1-00042-gce894ca #367 Call Trace: [] ? console_unlock+0x345/0x372 [] print_circular_bug+0x190/0x19d [] __lock_acquire+0x86d/0xb6c [] ? mark_held_locks+0x5c/0x7b [] lock_acquire+0x66/0xb9 [] ? writeback_inodes_sb_if_idle+0x28/0x46 [] down_read+0x28/0x58 [] ? writeback_inodes_sb_if_idle+0x28/0x46 [] writeback_inodes_sb_if_idle+0x28/0x46 [] ext4_nonda_switch+0xe1/0xf4 [] ext4_da_write_begin+0x27/0x193 [] generic_file_buffered_write+0xc8/0x1bb [] __generic_file_aio_write+0x1dd/0x205 [] generic_file_aio_write+0x78/0xd3 [] ext4_file_write+0x480/0x4a6 [] ? __lock_acquire+0x41e/0xb6c [] ? sched_clock_cpu+0x11a/0x13e [] ? trace_hardirqs_off+0xb/0xd [] ? local_clock+0x37/0x4e [] do_sync_write+0x67/0x9d [] ? wait_on_retry_sync_kiocb+0x44/0x44 [] vfs_write+0x7b/0xe6 [] sys_write+0x3b/0x64 [] syscall_call+0x7/0xb Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 17 ++++++++++------- fs/fs-writeback.c | 1 + 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 55a654d8618..45c544fe3ae 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2386,6 +2386,16 @@ static int ext4_nonda_switch(struct super_block *sb) free_blocks = EXT4_C2B(sbi, percpu_counter_read_positive(&sbi->s_freeclusters_counter)); dirty_blocks = percpu_counter_read_positive(&sbi->s_dirtyclusters_counter); + /* + * Start pushing delalloc when 1/2 of free blocks are dirty. + */ + if (dirty_blocks && (free_blocks < 2 * dirty_blocks) && + !writeback_in_progress(sb->s_bdi) && + down_read_trylock(&sb->s_umount)) { + writeback_inodes_sb(sb, WB_REASON_FS_FREE_SPACE); + up_read(&sb->s_umount); + } + if (2 * free_blocks < 3 * dirty_blocks || free_blocks < (dirty_blocks + EXT4_FREECLUSTERS_WATERMARK)) { /* @@ -2394,13 +2404,6 @@ static int ext4_nonda_switch(struct super_block *sb) */ return 1; } - /* - * Even if we don't switch but are nearing capacity, - * start pushing delalloc when 1/2 of free blocks are dirty. - */ - if (free_blocks < 2 * dirty_blocks) - writeback_inodes_sb_if_idle(sb, WB_REASON_FS_FREE_SPACE); - return 0; } diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 539f36cf3e4..b35bd64fb54 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -68,6 +68,7 @@ int writeback_in_progress(struct backing_dev_info *bdi) { return test_bit(BDI_writeback_running, &bdi->state); } +EXPORT_SYMBOL(writeback_in_progress); static inline struct backing_dev_info *inode_to_bdi(struct inode *inode) { From d49765a2110de8ac18aa74373ae89c1e4484b5d6 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Sun, 23 Sep 2012 22:49:12 -0400 Subject: [PATCH 1159/2357] ext4: fix crash when accessing /proc/mounts concurrently commit 50df9fd55e4271e89a7adf3b1172083dd0ca199d upstream. The crash was caused by a variable being erronously declared static in token2str(). In addition to /proc/mounts, the problem can also be easily replicated by accessing /proc/fs/ext4//options in parallel: $ cat /proc/fs/ext4//options > options.txt ... and then running the following command in two different terminals: $ while diff /proc/fs/ext4//options options.txt; do true; done This is also the cause of the following a crash while running xfstests #234, as reported in the following bug reports: https://bugs.launchpad.net/bugs/1053019 https://bugzilla.kernel.org/show_bug.cgi?id=47731 Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: "Theodore Ts'o" Cc: Brad Figg Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 12a278ff82a..b1c28f18701 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1692,7 +1692,7 @@ static inline void ext4_show_quota_options(struct seq_file *seq, static const char *token2str(int token) { - static const struct match_token *t; + const struct match_token *t; for (t = tokens; t->token != Opt_err; t++) if (t->token == token && !strchr(t->pattern, '=')) From 67bec353575f1205425c07bd76dbe5dfeb950a1e Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov Date: Wed, 26 Sep 2012 12:32:19 -0400 Subject: [PATCH 1160/2357] ext4: move_extent code cleanup commit 03bd8b9b896c8e940f282f540e6b4de90d666b7c upstream. - Remove usless checks, because it is too late to check that inode != NULL at the moment it was referenced several times. - Double lock routines looks very ugly and locking ordering relays on order of i_ino, but other kernel code rely on order of pointers. Let's make them simple and clean. - check that inodes belongs to the same SB as soon as possible. Signed-off-by: Dmitry Monakhov Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/move_extent.c | 167 ++++++++++++------------------------------ 1 file changed, 47 insertions(+), 120 deletions(-) diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index c5826c623e7..df5cde5130c 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -140,56 +140,22 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path, return 1; } -/** - * mext_check_null_inode - NULL check for two inodes - * - * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0. - */ -static int -mext_check_null_inode(struct inode *inode1, struct inode *inode2, - const char *function, unsigned int line) -{ - int ret = 0; - - if (inode1 == NULL) { - __ext4_error(inode2->i_sb, function, line, - "Both inodes should not be NULL: " - "inode1 NULL inode2 %lu", inode2->i_ino); - ret = -EIO; - } else if (inode2 == NULL) { - __ext4_error(inode1->i_sb, function, line, - "Both inodes should not be NULL: " - "inode1 %lu inode2 NULL", inode1->i_ino); - ret = -EIO; - } - return ret; -} - /** * double_down_write_data_sem - Acquire two inodes' write lock of i_data_sem * - * @orig_inode: original inode structure - * @donor_inode: donor inode structure - * Acquire write lock of i_data_sem of the two inodes (orig and donor) by - * i_ino order. + * Acquire write lock of i_data_sem of the two inodes */ static void -double_down_write_data_sem(struct inode *orig_inode, struct inode *donor_inode) +double_down_write_data_sem(struct inode *first, struct inode *second) { - struct inode *first = orig_inode, *second = donor_inode; + if (first < second) { + down_write(&EXT4_I(first)->i_data_sem); + down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING); + } else { + down_write(&EXT4_I(second)->i_data_sem); + down_write_nested(&EXT4_I(first)->i_data_sem, SINGLE_DEPTH_NESTING); - /* - * Use the inode number to provide the stable locking order instead - * of its address, because the C language doesn't guarantee you can - * compare pointers that don't come from the same array. - */ - if (donor_inode->i_ino < orig_inode->i_ino) { - first = donor_inode; - second = orig_inode; } - - down_write(&EXT4_I(first)->i_data_sem); - down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING); } /** @@ -969,14 +935,6 @@ mext_check_arguments(struct inode *orig_inode, return -EINVAL; } - /* Files should be in the same ext4 FS */ - if (orig_inode->i_sb != donor_inode->i_sb) { - ext4_debug("ext4 move extent: The argument files " - "should be in same FS [ino:orig %lu, donor %lu]\n", - orig_inode->i_ino, donor_inode->i_ino); - return -EINVAL; - } - /* Ext4 move extent supports only extent based file */ if (!(ext4_test_inode_flag(orig_inode, EXT4_INODE_EXTENTS))) { ext4_debug("ext4 move extent: orig file is not extents " @@ -1072,35 +1030,19 @@ mext_check_arguments(struct inode *orig_inode, * @inode1: the inode structure * @inode2: the inode structure * - * Lock two inodes' i_mutex by i_ino order. - * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0. + * Lock two inodes' i_mutex */ -static int +static void mext_inode_double_lock(struct inode *inode1, struct inode *inode2) { - int ret = 0; - - BUG_ON(inode1 == NULL && inode2 == NULL); - - ret = mext_check_null_inode(inode1, inode2, __func__, __LINE__); - if (ret < 0) - goto out; - - if (inode1 == inode2) { - mutex_lock(&inode1->i_mutex); - goto out; - } - - if (inode1->i_ino < inode2->i_ino) { + BUG_ON(inode1 == inode2); + if (inode1 < inode2) { mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD); } else { mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD); } - -out: - return ret; } /** @@ -1109,28 +1051,13 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2) * @inode1: the inode that is released first * @inode2: the inode that is released second * - * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0. */ -static int +static void mext_inode_double_unlock(struct inode *inode1, struct inode *inode2) { - int ret = 0; - - BUG_ON(inode1 == NULL && inode2 == NULL); - - ret = mext_check_null_inode(inode1, inode2, __func__, __LINE__); - if (ret < 0) - goto out; - - if (inode1) - mutex_unlock(&inode1->i_mutex); - - if (inode2 && inode2 != inode1) - mutex_unlock(&inode2->i_mutex); - -out: - return ret; + mutex_unlock(&inode1->i_mutex); + mutex_unlock(&inode2->i_mutex); } /** @@ -1187,16 +1114,23 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, ext4_lblk_t block_end, seq_start, add_blocks, file_end, seq_blocks = 0; ext4_lblk_t rest_blocks; pgoff_t orig_page_offset = 0, seq_end_page; - int ret1, ret2, depth, last_extent = 0; + int ret, depth, last_extent = 0; int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; int data_offset_in_page; int block_len_in_page; int uninit; - /* orig and donor should be different file */ - if (orig_inode->i_ino == donor_inode->i_ino) { + if (orig_inode->i_sb != donor_inode->i_sb) { + ext4_debug("ext4 move extent: The argument files " + "should be in same FS [ino:orig %lu, donor %lu]\n", + orig_inode->i_ino, donor_inode->i_ino); + return -EINVAL; + } + + /* orig and donor should be different inodes */ + if (orig_inode == donor_inode) { ext4_debug("ext4 move extent: The argument files should not " - "be same file [ino:orig %lu, donor %lu]\n", + "be same inode [ino:orig %lu, donor %lu]\n", orig_inode->i_ino, donor_inode->i_ino); return -EINVAL; } @@ -1210,16 +1144,14 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, } /* Protect orig and donor inodes against a truncate */ - ret1 = mext_inode_double_lock(orig_inode, donor_inode); - if (ret1 < 0) - return ret1; + mext_inode_double_lock(orig_inode, donor_inode); /* Protect extent tree against block allocations via delalloc */ double_down_write_data_sem(orig_inode, donor_inode); /* Check the filesystem environment whether move_extent can be done */ - ret1 = mext_check_arguments(orig_inode, donor_inode, orig_start, + ret = mext_check_arguments(orig_inode, donor_inode, orig_start, donor_start, &len); - if (ret1) + if (ret) goto out; file_end = (i_size_read(orig_inode) - 1) >> orig_inode->i_blkbits; @@ -1227,13 +1159,13 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, if (file_end < block_end) len -= block_end - file_end; - ret1 = get_ext_path(orig_inode, block_start, &orig_path); - if (ret1) + ret = get_ext_path(orig_inode, block_start, &orig_path); + if (ret) goto out; /* Get path structure to check the hole */ - ret1 = get_ext_path(orig_inode, block_start, &holecheck_path); - if (ret1) + ret = get_ext_path(orig_inode, block_start, &holecheck_path); + if (ret) goto out; depth = ext_depth(orig_inode); @@ -1252,13 +1184,13 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, last_extent = mext_next_extent(orig_inode, holecheck_path, &ext_cur); if (last_extent < 0) { - ret1 = last_extent; + ret = last_extent; goto out; } last_extent = mext_next_extent(orig_inode, orig_path, &ext_dummy); if (last_extent < 0) { - ret1 = last_extent; + ret = last_extent; goto out; } seq_start = le32_to_cpu(ext_cur->ee_block); @@ -1272,7 +1204,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, if (le32_to_cpu(ext_cur->ee_block) > block_end) { ext4_debug("ext4 move extent: The specified range of file " "may be the hole\n"); - ret1 = -EINVAL; + ret = -EINVAL; goto out; } @@ -1292,7 +1224,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, last_extent = mext_next_extent(orig_inode, holecheck_path, &ext_cur); if (last_extent < 0) { - ret1 = last_extent; + ret = last_extent; break; } add_blocks = ext4_ext_get_actual_len(ext_cur); @@ -1349,18 +1281,18 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, orig_page_offset, data_offset_in_page, block_len_in_page, uninit, - &ret1); + &ret); /* Count how many blocks we have exchanged */ *moved_len += block_len_in_page; - if (ret1 < 0) + if (ret < 0) break; if (*moved_len > len) { EXT4_ERROR_INODE(orig_inode, "We replaced blocks too much! " "sum of replaced: %llu requested: %llu", *moved_len, len); - ret1 = -EIO; + ret = -EIO; break; } @@ -1374,22 +1306,22 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, } double_down_write_data_sem(orig_inode, donor_inode); - if (ret1 < 0) + if (ret < 0) break; /* Decrease buffer counter */ if (holecheck_path) ext4_ext_drop_refs(holecheck_path); - ret1 = get_ext_path(orig_inode, seq_start, &holecheck_path); - if (ret1) + ret = get_ext_path(orig_inode, seq_start, &holecheck_path); + if (ret) break; depth = holecheck_path->p_depth; /* Decrease buffer counter */ if (orig_path) ext4_ext_drop_refs(orig_path); - ret1 = get_ext_path(orig_inode, seq_start, &orig_path); - if (ret1) + ret = get_ext_path(orig_inode, seq_start, &orig_path); + if (ret) break; ext_cur = holecheck_path[depth].p_ext; @@ -1412,12 +1344,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, kfree(holecheck_path); } double_up_write_data_sem(orig_inode, donor_inode); - ret2 = mext_inode_double_unlock(orig_inode, donor_inode); + mext_inode_double_unlock(orig_inode, donor_inode); - if (ret1) - return ret1; - else if (ret2) - return ret2; - - return 0; + return ret; } From a4bf81c2bf891cbd46d6a69ba15dd7d4350b62f3 Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov Date: Wed, 26 Sep 2012 12:32:54 -0400 Subject: [PATCH 1161/2357] ext4: online defrag is not supported for journaled files commit f066055a3449f0e5b0ae4f3ceab4445bead47638 upstream. Proper block swap for inodes with full journaling enabled is truly non obvious task. In order to be on a safe side let's explicitly disable it for now. Signed-off-by: Dmitry Monakhov Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/move_extent.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index df5cde5130c..e2016f34b58 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -1142,7 +1142,12 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, orig_inode->i_ino, donor_inode->i_ino); return -EINVAL; } - + /* TODO: This is non obvious task to swap blocks for inodes with full + jornaling enabled */ + if (ext4_should_journal_data(orig_inode) || + ext4_should_journal_data(donor_inode)) { + return -EINVAL; + } /* Protect orig and donor inodes against a truncate */ mext_inode_double_lock(orig_inode, donor_inode); From 7061315f57c1dfa81d3d9b2f0efb50ce2b6f3371 Mon Sep 17 00:00:00 2001 From: Bernd Schubert Date: Wed, 26 Sep 2012 21:24:57 -0400 Subject: [PATCH 1162/2357] ext4: always set i_op in ext4_mknod() commit 6a08f447facb4f9e29fcc30fb68060bb5a0d21c2 upstream. ext4_special_inode_operations have their own ifdef CONFIG_EXT4_FS_XATTR to mask those methods. And ext4_iget also always sets it, so there is an inconsistency. Signed-off-by: Bernd Schubert Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/namei.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 0a94cbbe882..ac769399b14 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1801,9 +1801,7 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry, err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, inode->i_mode, rdev); -#ifdef CONFIG_EXT4_FS_XATTR inode->i_op = &ext4_special_inode_operations; -#endif err = ext4_add_nondir(handle, dentry, inode); } ext4_journal_stop(handle); From e87ba35f1fba828bb198bdf89704eb9583932da8 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 26 Sep 2012 21:52:20 -0400 Subject: [PATCH 1163/2357] ext4: fix fdatasync() for files with only i_size changes commit b71fc079b5d8f42b2a52743c8d2f1d35d655b1c5 upstream. Code tracking when transaction needs to be committed on fdatasync(2) forgets to handle a situation when only inode's i_size is changed. Thus in such situations fdatasync(2) doesn't force transaction with new i_size to disk and that can result in wrong i_size after a crash. Fix the issue by updating inode's i_datasync_tid whenever its size is updated. Reported-by: Kristian Nielsen Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 45c544fe3ae..dcd08e48576 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3892,6 +3892,7 @@ static int ext4_do_update_inode(handle_t *handle, struct ext4_inode_info *ei = EXT4_I(inode); struct buffer_head *bh = iloc->bh; int err = 0, rc, block; + int need_datasync = 0; /* For fields not not tracking in the in-memory inode, * initialise them to zero for new inodes. */ @@ -3940,7 +3941,10 @@ static int ext4_do_update_inode(handle_t *handle, raw_inode->i_file_acl_high = cpu_to_le16(ei->i_file_acl >> 32); raw_inode->i_file_acl_lo = cpu_to_le32(ei->i_file_acl); - ext4_isize_set(raw_inode, ei->i_disksize); + if (ei->i_disksize != ext4_isize(raw_inode)) { + ext4_isize_set(raw_inode, ei->i_disksize); + need_datasync = 1; + } if (ei->i_disksize > 0x7fffffffULL) { struct super_block *sb = inode->i_sb; if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, @@ -3991,7 +3995,7 @@ static int ext4_do_update_inode(handle_t *handle, err = rc; ext4_clear_inode_state(inode, EXT4_STATE_NEW); - ext4_update_inode_fsync_trans(handle, inode, 0); + ext4_update_inode_fsync_trans(handle, inode, need_datasync); out_brelse: brelse(bh); ext4_std_error(inode->i_sb, err); From 62bd817182be053f1c6dde95748d34fd7be27bb0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 31 Jul 2012 18:37:29 +0100 Subject: [PATCH 1164/2357] ASoC: wm9712: Fix name of Capture Switch commit 689185b78ba6fbe0042f662a468b5565909dff7a upstream. Help UIs associate it with the matching gain control. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm9712.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index b9567bc16ae..757a52aed80 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -146,7 +146,7 @@ SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0), SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1), SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1), -SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1), +SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1), SOC_ENUM("Capture Volume Steps", wm9712_enum[6]), SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1), SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0), From 70fb727d0900836b71ebf7a7badaa7b7c9068102 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Mon, 8 Oct 2012 16:33:47 -0700 Subject: [PATCH 1165/2357] kpageflags: fix wrong KPF_THP on non-huge compound pages commit 7a71932d5676b7410ab64d149bad8bde6b0d8632 upstream. KPF_THP can be set on non-huge compound pages (like slab pages or pages allocated by drivers with __GFP_COMP) because PageTransCompound only checks PG_head and PG_tail. Obviously this is a bug and breaks user space applications which look for thp via /proc/kpageflags. This patch rules out setting KPF_THP wrongly by additionally checking PageLRU on the head pages. Signed-off-by: Naoya Horiguchi Acked-by: KOSAKI Motohiro Acked-by: David Rientjes Reviewed-by: Fengguang Wu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/page.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/proc/page.c b/fs/proc/page.c index 7fcd0d60a96..b8730d9ebae 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -115,7 +115,13 @@ u64 stable_page_flags(struct page *page) u |= 1 << KPF_COMPOUND_TAIL; if (PageHuge(page)) u |= 1 << KPF_HUGE; - else if (PageTransCompound(page)) + /* + * PageTransCompound can be true for non-huge compound pages (slab + * pages or pages allocated by drivers with __GFP_COMP) because it + * just checks PG_head/PG_tail, so we need to check PageLRU to make + * sure a given page is a thp, not a non-huge compound page. + */ + else if (PageTransCompound(page) && PageLRU(compound_trans_head(page))) u |= 1 << KPF_THP; /* From 26fc07d8da4aa118cfe44776c2d2ddef8ef5f641 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Mon, 8 Oct 2012 16:33:31 -0700 Subject: [PATCH 1166/2357] hugetlb: do not use vma_hugecache_offset() for vma_prio_tree_foreach commit 36e4f20af833d1ce196e6a4ade05dc26c44652d1 upstream. Commit 0c176d52b0b2 ("mm: hugetlb: fix pgoff computation when unmapping page from vma") fixed pgoff calculation but it has replaced it by vma_hugecache_offset() which is not approapriate for offsets used for vma_prio_tree_foreach() because that one expects index in page units rather than in huge_page_shift. Johannes said: : The resulting index may not be too big, but it can be too small: assume : hpage size of 2M and the address to unmap to be 0x200000. This is regular : page index 512 and hpage index 1. If you have a VMA that maps the file : only starting at the second huge page, that VMAs vm_pgoff will be 512 but : you ask for offset 1 and miss it even though it does map the page of : interest. hugetlb_cow() will try to unmap, miss the vma, and retry the : cow until the allocation succeeds or the skipped vma(s) go away. Signed-off-by: Michal Hocko Acked-by: Hillf Danton Cc: Mel Gorman Cc: KAMEZAWA Hiroyuki Cc: Andrea Arcangeli Cc: David Rientjes Acked-by: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/hugetlb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index a799df59d31..c384e0901f9 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2431,7 +2431,8 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma, * from page cache lookup which is in HPAGE_SIZE units. */ address = address & huge_page_mask(h); - pgoff = vma_hugecache_offset(h, vma, address); + pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + + vma->vm_pgoff; mapping = vma->vm_file->f_dentry->d_inode->i_mapping; /* From 6a91e161a7f1b0125822b1693ea8fe46035b0f1b Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Mon, 8 Oct 2012 16:33:14 -0700 Subject: [PATCH 1167/2357] mm: fix invalidate_complete_page2() lock ordering commit ec4d9f626d5908b6052c2973f37992f1db52e967 upstream. In fuzzing with trinity, lockdep protested "possible irq lock inversion dependency detected" when isolate_lru_page() reenabled interrupts while still holding the supposedly irq-safe tree_lock: invalidate_inode_pages2 invalidate_complete_page2 spin_lock_irq(&mapping->tree_lock) clear_page_mlock isolate_lru_page spin_unlock_irq(&zone->lru_lock) isolate_lru_page() is correct to enable interrupts unconditionally: invalidate_complete_page2() is incorrect to call clear_page_mlock() while holding tree_lock, which is supposed to nest inside lru_lock. Both truncate_complete_page() and invalidate_complete_page() call clear_page_mlock() before taking tree_lock to remove page from radix_tree. I guess invalidate_complete_page2() preferred to test PageDirty (again) under tree_lock before committing to the munlock; but since the page has already been unmapped, its state is already somewhat inconsistent, and no worse if clear_page_mlock() moved up. Reported-by: Sasha Levin Deciphered-by: Andrew Morton Signed-off-by: Hugh Dickins Acked-by: Mel Gorman Cc: Rik van Riel Cc: Johannes Weiner Cc: Michel Lespinasse Cc: Ying Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/truncate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/truncate.c b/mm/truncate.c index 61a183b89df..4224627695b 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -394,11 +394,12 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page) if (page_has_private(page) && !try_to_release_page(page, GFP_KERNEL)) return 0; + clear_page_mlock(page); + spin_lock_irq(&mapping->tree_lock); if (PageDirty(page)) goto failed; - clear_page_mlock(page); BUG_ON(page_has_private(page)); __delete_from_page_cache(page); spin_unlock_irq(&mapping->tree_lock); From c3b9446604af20c426b37b8191d9d089b40f5899 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Mon, 8 Oct 2012 16:33:27 -0700 Subject: [PATCH 1168/2357] mm: thp: fix pmd_present for split_huge_page and PROT_NONE with THP commit 027ef6c87853b0a9df53175063028edb4950d476 upstream. In many places !pmd_present has been converted to pmd_none. For pmds that's equivalent and pmd_none is quicker so using pmd_none is better. However (unless we delete pmd_present) we should provide an accurate pmd_present too. This will avoid the risk of code thinking the pmd is non present because it's under __split_huge_page_map, see the pmd_mknotpresent there and the comment above it. If the page has been mprotected as PROT_NONE, it would also lead to a pmd_present false negative in the same way as the race with split_huge_page. Because the PSE bit stays on at all times (both during split_huge_page and when the _PAGE_PROTNONE bit get set), we could only check for the PSE bit, but checking the PROTNONE bit too is still good to remember pmd_present must always keep PROT_NONE into account. This explains a not reproducible BUG_ON that was seldom reported on the lists. The same issue is in pmd_large, it would go wrong with both PROT_NONE and if it races with split_huge_page. Signed-off-by: Andrea Arcangeli Acked-by: Rik van Riel Cc: Johannes Weiner Cc: Hugh Dickins Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/pgtable.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 49afb3f41eb..c3520d76820 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -146,8 +146,7 @@ static inline unsigned long pmd_pfn(pmd_t pmd) static inline int pmd_large(pmd_t pte) { - return (pmd_flags(pte) & (_PAGE_PSE | _PAGE_PRESENT)) == - (_PAGE_PSE | _PAGE_PRESENT); + return pmd_flags(pte) & _PAGE_PSE; } #ifdef CONFIG_TRANSPARENT_HUGEPAGE @@ -415,7 +414,13 @@ static inline int pte_hidden(pte_t pte) static inline int pmd_present(pmd_t pmd) { - return pmd_flags(pmd) & _PAGE_PRESENT; + /* + * Checking for _PAGE_PSE is needed too because + * split_huge_page will temporarily clear the present bit (but + * the _PAGE_PSE flag will remain set at all times while the + * _PAGE_PRESENT bit is clear). + */ + return pmd_flags(pmd) & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_PSE); } static inline int pmd_none(pmd_t pmd) From 4ca1a84f737e7f8166aed08ba87f5acc49120da9 Mon Sep 17 00:00:00 2001 From: Omair Mohammed Abdullah Date: Sat, 29 Sep 2012 12:24:05 +0530 Subject: [PATCH 1169/2357] ALSA: aloop - add locking to timer access commit d4f1e48bd11e3df6a26811f7a1f06c4225d92f7d upstream. When the loopback timer handler is running, calling del_timer() (for STOP trigger) will not wait for the handler to complete before deactivating the timer. The timer gets rescheduled in the handler as usual. Then a subsequent START trigger will try to start the timer using add_timer() with a timer pending leading to a kernel panic. Serialize the calls to add_timer() and del_timer() using a spin lock to avoid this. Signed-off-by: Omair Mohammed Abdullah Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/aloop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index ad079b63b8b..bdc963e722a 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -119,6 +119,7 @@ struct loopback_pcm { unsigned int period_size_frac; unsigned long last_jiffies; struct timer_list timer; + spinlock_t timer_lock; }; static struct platform_device *devices[SNDRV_CARDS]; @@ -169,6 +170,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm) unsigned long tick; unsigned int rate_shift = get_rate_shift(dpcm); + spin_lock(&dpcm->timer_lock); if (rate_shift != dpcm->pcm_rate_shift) { dpcm->pcm_rate_shift = rate_shift; dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); @@ -181,12 +183,15 @@ static void loopback_timer_start(struct loopback_pcm *dpcm) tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; dpcm->timer.expires = jiffies + tick; add_timer(&dpcm->timer); + spin_unlock(&dpcm->timer_lock); } static inline void loopback_timer_stop(struct loopback_pcm *dpcm) { + spin_lock(&dpcm->timer_lock); del_timer(&dpcm->timer); dpcm->timer.expires = 0; + spin_unlock(&dpcm->timer_lock); } #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) @@ -659,6 +664,7 @@ static int loopback_open(struct snd_pcm_substream *substream) dpcm->substream = substream; setup_timer(&dpcm->timer, loopback_timer_function, (unsigned long)dpcm); + spin_lock_init(&dpcm->timer_lock); cable = loopback->cables[substream->number][dev]; if (!cable) { From c8ab5d973cd5439ae0223ca259f0e20963905bef Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Thu, 27 Sep 2012 10:38:14 -0300 Subject: [PATCH 1170/2357] ALSA: hda/realtek - Fix detection of ALC271X codec commit 9f720bb9409ea5923361fbd3fdbc505ca36cf012 upstream. In commit af741c1 ("ALSA: hda/realtek - Call alc_auto_parse_customize_define() always after fixup"), alc_auto_parse_customize_define was moved after detection of ALC271X. The problem is that detection of ALC271X relies on spec->cdefine.platform_type, and it's set on alc_auto_parse_customize_define. Move the alc_auto_parse_customize_define and its required fixup setup before the block doing the ALC271X and other codec setup. BugLink: https://bugs.launchpad.net/bugs/1006690 Signed-off-by: Herton Ronaldo Krzesinski Reviewed-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 52e7a45f6e5..e7cb4bd25d2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6307,6 +6307,12 @@ static int patch_alc269(struct hda_codec *codec) if (err < 0) goto error; + alc_pick_fixup(codec, alc269_fixup_models, + alc269_fixup_tbl, alc269_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + + alc_auto_parse_customize_define(codec); + if (codec->vendor_id == 0x10ec0269) { spec->codec_variant = ALC269_TYPE_ALC269VA; switch (alc_get_coef0(codec) & 0x00f0) { @@ -6331,12 +6337,6 @@ static int patch_alc269(struct hda_codec *codec) alc269_fill_coef(codec); } - alc_pick_fixup(codec, alc269_fixup_models, - alc269_fixup_tbl, alc269_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - - alc_auto_parse_customize_define(codec); - /* automatic parse from the BIOS config */ err = alc269_parse_auto_config(codec); if (err < 0) From 92c635bfcd86aa182b9a6734426e61e1420579d7 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 20 Sep 2012 10:20:41 +0200 Subject: [PATCH 1171/2357] ALSA: usb - disable broken hw volume for Tenx TP6911 commit c10514394ef9e8de93a4ad8c8904d71dcd82c122 upstream. While going through Ubuntu bugs, I discovered this patch being posted and a confirmation that the patch works as expected. Finding out how the hw volume really works would be preferrable to just disabling the broken one, but this would be better than nothing. Credit: sndfnsdfin (qawsnews) BugLink: https://bugs.launchpad.net/bugs/559939 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/mixer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index ab23869c01b..8a818a4573a 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1247,6 +1247,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void /* disable non-functional volume control */ master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME); break; + case USB_ID(0x1130, 0xf211): + snd_printk(KERN_INFO + "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n"); + /* disable non-functional volume control */ + channels = 0; + break; + } if (channels > 0) first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize); From 3e0f62d7750436e35540df761dcc2d8b01a9a5bf Mon Sep 17 00:00:00 2001 From: Marko Friedemann Date: Mon, 3 Sep 2012 10:12:40 +0200 Subject: [PATCH 1172/2357] ALSA: USB: Support for (original) Xbox Communicator commit c05fce586d4da2dfe0309bef3795a8586e967bc3 upstream. Added support for Xbox Communicator to USB quirks. Signed-off-by: Marko Friedemann Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/quirks-table.h | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index d89ab4c7d44..63128cd6254 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2751,6 +2751,59 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* Microsoft XboxLive Headset/Xbox Communicator */ +{ + USB_DEVICE(0x045e, 0x0283), + .bInterfaceClass = USB_CLASS_PER_INTERFACE, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Microsoft", + .product_name = "XboxLive Headset/Xbox Communicator", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = &(const struct snd_usb_audio_quirk[]) { + { + /* playback */ + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 1, + .iface = 0, + .altsetting = 0, + .altset_idx = 0, + .attributes = 0, + .endpoint = 0x04, + .ep_attr = 0x05, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 22050, + .rate_max = 22050 + } + }, + { + /* capture */ + .ifnum = 1, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 1, + .iface = 1, + .altsetting = 0, + .altset_idx = 0, + .attributes = 0, + .endpoint = 0x85, + .ep_attr = 0x05, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 16000, + .rate_max = 16000 + } + }, + { + .ifnum = -1 + } + } + } +}, + { /* * Some USB MIDI devices don't have an audio control interface, From 507130a9e351f5662785a8a09ccdc5687b01aabe Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 17 Sep 2012 09:38:03 +0000 Subject: [PATCH 1173/2357] drm: Destroy the planes prior to destroying the associated CRTC commit 3184009c36da413724f283e3c7ac9cc60c623bc4 upstream. As during the plane cleanup, we wish to disable the hardware and so may modify state on the associated CRTC, that CRTC must continue to exist until we are finished. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=54101 Signed-off-by: Chris Wilson Cc: Jesse Barnes Reviewed-by: Jesse Barnes Tested-by: lu hua Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_crtc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7e479a42af0..4fd363f1656 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1028,15 +1028,15 @@ void drm_mode_config_cleanup(struct drm_device *dev) fb->funcs->destroy(fb); } - list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { - crtc->funcs->destroy(crtc); - } - list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, head) { plane->funcs->destroy(plane); } + list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { + crtc->funcs->destroy(crtc); + } + idr_remove_all(&dev->mode_config.crtc_idr); idr_destroy(&dev->mode_config.crtc_idr); } From 47c3ae0b3b5b360387602c49d7076e6114d05879 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 14 Sep 2012 10:59:26 -0400 Subject: [PATCH 1174/2357] drm/radeon: only adjust default clocks on NI GPUs commit 2e3b3b105ab3bb5b6a37198da4f193cd13781d13 upstream. SI asics store voltage information differently so we don't have a way to deal with it properly yet. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_pm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index caa55d68f31..b8459bdce42 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -567,7 +567,9 @@ void radeon_pm_suspend(struct radeon_device *rdev) void radeon_pm_resume(struct radeon_device *rdev) { /* set up the default clocks if the MC ucode is loaded */ - if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { + if ((rdev->family >= CHIP_BARTS) && + (rdev->family <= CHIP_CAYMAN) && + rdev->mc_fw) { if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, SET_VOLTAGE_TYPE_ASIC_VDDC); @@ -622,7 +624,9 @@ int radeon_pm_init(struct radeon_device *rdev) radeon_pm_print_states(rdev); radeon_pm_init_profile(rdev); /* set up the default clocks if the MC ucode is loaded */ - if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { + if ((rdev->family >= CHIP_BARTS) && + (rdev->family <= CHIP_CAYMAN) && + rdev->mc_fw) { if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, SET_VOLTAGE_TYPE_ASIC_VDDC); From 60a601fda771cf25df2b702dbba1a3e22e81fa2c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 26 Sep 2012 12:31:45 -0400 Subject: [PATCH 1175/2357] drm/radeon: Add MSI quirk for gateway RS690 commit 3a6d59df80897cc87812b6826d70085905bed013 upstream. Fixes another system on: https://bugs.freedesktop.org/show_bug.cgi?id=37679 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 65060b77c80..a574faab067 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -147,6 +147,12 @@ static bool radeon_msi_ok(struct radeon_device *rdev) (rdev->pdev->subsystem_device == 0x01fd)) return true; + /* Gateway RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x107b) && + (rdev->pdev->subsystem_device == 0x0185)) + return true; + /* RV515 seems to have MSI issues where it loses * MSI rearms occasionally. This leads to lockups and freezes. * disable it by default. From d59316ee086133955a993855655b24925c0e6b05 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 26 Sep 2012 12:40:45 -0400 Subject: [PATCH 1176/2357] drm/radeon: force MSIs on RS690 asics commit fb6ca6d154cdcd53e7f27f8dbba513830372699b upstream. There are so many quirks, lets just try and force this for all RS690s. See: https://bugs.freedesktop.org/show_bug.cgi?id=37679 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index a574faab067..645dcbf6490 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -153,6 +153,10 @@ static bool radeon_msi_ok(struct radeon_device *rdev) (rdev->pdev->subsystem_device == 0x0185)) return true; + /* try and enable MSIs by default on all RS690s */ + if (rdev->family == CHIP_RS690) + return true; + /* RV515 seems to have MSI issues where it loses * MSI rearms occasionally. This leads to lockups and freezes. * disable it by default. From c5a3f2e9981b6da91e70765d0a958a0ac9d14a53 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 24 Aug 2012 13:22:13 -0700 Subject: [PATCH 1177/2357] ia64: Add missing RCU idle APIs on idle loop commit 93482f4ef1093f5961a63359a34612183d6beea0 upstream. Traditionally, the entire idle task served as an RCU quiescent state. But when RCU read side critical sections started appearing within the idle loop, this traditional strategy became untenable. The fix was to create new RCU APIs named rcu_idle_enter() and rcu_idle_exit(), which must be called by each architecture's idle loop so that RCU can tell when it is safe to ignore a given idle CPU. Unfortunately, this fix was never applied to ia64, a shortcoming remedied by this commit. Reported by: Tony Luck Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Tested by: Tony Luck Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/ia64/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index ce74e143aea..86d74ab9800 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -301,6 +302,7 @@ cpu_idle (void) /* endless idle loop with no priority at all */ while (1) { + rcu_idle_enter(); if (can_do_pal_halt) { current_thread_info()->status &= ~TS_POLLING; /* @@ -331,6 +333,7 @@ cpu_idle (void) normal_xtp(); #endif } + rcu_idle_exit(); schedule_preempt_disabled(); check_pgt_cache(); if (cpu_is_offline(cpu)) From 699d26ccee4e22e324468e94eb648cc89964a15d Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1178/2357] h8300: Add missing RCU idle APIs on idle loop commit b2fe1430d4115c74d007c825cb9dc3317f28bb16 upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the h8300's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Cc: Yoshinori Sato Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/h8300/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index 0e9c315be10..f153ed1a4c0 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -78,8 +79,10 @@ void (*idle)(void) = default_idle; void cpu_idle(void) { while (1) { + rcu_idle_enter(); while (!need_resched()) idle(); + rcu_idle_exit(); schedule_preempt_disabled(); } } From d2d41b722e5faf418c1a660eaa602d06e50402eb Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1179/2357] parisc: Add missing RCU idle APIs on idle loop commit fbe752188d5589e7fcbb8e79824e560f77dccc92 upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the parisc's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Cc: James E.J. Bottomley Cc: Helge Deller Cc: Parisc Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index d4b94b395c1..c54a4dbcb38 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -69,8 +70,10 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while (1) { + rcu_idle_enter(); while (!need_resched()) barrier(); + rcu_idle_exit(); schedule_preempt_disabled(); check_pgt_cache(); } From 2ddcad1f012eb832b5ad61f27888bf36eb495e83 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1180/2357] xtensa: Add missing RCU idle APIs on idle loop commit 11ad47a0edbd62bfc0547cfcdf227a911433f207 upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the xtensa's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Cc: Chris Zankel Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 6a2d6edf8f7..7a41d9ec8ac 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -110,8 +111,10 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while (1) { + rcu_idle_enter(); while (!need_resched()) platform_idle(); + rcu_idle_exit(); schedule_preempt_disabled(); } } From c272355732aaf718ba4c05b0693c0d327ea0de45 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1181/2357] frv: Add missing RCU idle APIs on idle loop commit 41d8fe5bb3cf91ce2716ac8f43e4b40d802a99c8 upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the Frv's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Cc: David Howells Acked-by: David Howells Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/frv/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c index d4de48bd5ef..3941cbc91ff 100644 --- a/arch/frv/kernel/process.c +++ b/arch/frv/kernel/process.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -84,12 +85,14 @@ void cpu_idle(void) { /* endless idle loop with no priority at all */ while (1) { + rcu_idle_enter(); while (!need_resched()) { check_pgt_cache(); if (!frv_dma_inprogress && idle) idle(); } + rcu_idle_exit(); schedule_preempt_disabled(); } From c7cc1fa9594f1c7fe4de4418dbe9d85c3a4727ee Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1182/2357] mn10300: Add missing RCU idle APIs on idle loop commit 5b0753a90b7a98bc613c3767e9263a1a76d4f900 upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the mn10300's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Cc: David Howells Cc: Koichi Yasutake Signed-off-by: Paul E. McKenney Acked-by: David Howells Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/mn10300/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index 14707f25153..675d8f2c32e 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -107,6 +108,7 @@ void cpu_idle(void) { /* endless idle loop with no priority at all */ for (;;) { + rcu_idle_enter(); while (!need_resched()) { void (*idle)(void); @@ -121,6 +123,7 @@ void cpu_idle(void) } idle(); } + rcu_idle_exit(); schedule_preempt_disabled(); } From ce6ccabd21d356ac22973d275f122d3d8efc96d7 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1183/2357] m68k: Add missing RCU idle APIs on idle loop commit 5b57ba37e82a15f345a6a2eb8c01a2b2d94c5eeb upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the m68k's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Acked-by: Geert Uytterhoeven Cc: m68k Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/m68k/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index c488e3cfab5..ac2892e49c7 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -75,8 +76,10 @@ void cpu_idle(void) { /* endless idle loop with no priority at all */ while (1) { + rcu_idle_enter(); while (!need_resched()) idle(); + rcu_idle_exit(); schedule_preempt_disabled(); } } From 3b30d3182fbf026578fbad09877d78c338562f4c Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1184/2357] alpha: Add missing RCU idle APIs on idle loop commit 4c94cada48f7c660eca582be6032427a5e367117 upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the Alpha's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Tested-by: Michael Cree Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Cc: alpha Cc: Paul E. McKenney Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/alpha/kernel/process.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 153d3fce3e8..8e3d91be76b 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -54,8 +55,11 @@ cpu_idle(void) /* FIXME -- EV6 and LCA45 know how to power down the CPU. */ + rcu_idle_enter(); while (!need_resched()) cpu_relax(); + + rcu_idle_exit(); schedule(); } } From a3e9082a19d723e7be0bc51d851b5689eee67c9c Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1185/2357] cris: Add missing RCU idle APIs on idle loop commit c633f9e788928e91ad11f44df29b47bbbe9550b0 upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the Cris's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Cc: Mikael Starvik Cc: Jesper Nilsson Cc: Cris Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/cris/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c index 891dad85e8b..c722027d69a 100644 --- a/arch/cris/kernel/process.c +++ b/arch/cris/kernel/process.c @@ -25,6 +25,7 @@ #include #include #include +#include //#define DEBUG @@ -102,6 +103,7 @@ void cpu_idle (void) { /* endless idle loop with no priority at all */ while (1) { + rcu_idle_enter(); while (!need_resched()) { void (*idle)(void); /* @@ -114,6 +116,7 @@ void cpu_idle (void) idle = default_idle; idle(); } + rcu_idle_exit(); schedule_preempt_disabled(); } } From 1b5124a305593deffd6186540546b8bfba429570 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1186/2357] m32r: Add missing RCU idle APIs on idle loop commit 48ae077cfce72591b8fc80e1dcc87806f86fed7f upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the m32r's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Cc: Hirokazu Takata Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/m32r/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index 3a4a32b2720..384e63f3a4c 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -82,6 +83,7 @@ void cpu_idle (void) { /* endless idle loop with no priority at all */ while (1) { + rcu_idle_enter(); while (!need_resched()) { void (*idle)(void) = pm_idle; @@ -90,6 +92,7 @@ void cpu_idle (void) idle(); } + rcu_idle_exit(); schedule_preempt_disabled(); } } From 4a94001bd83f18ff3f3b998899d250d96f60a503 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: [PATCH 1187/2357] score: Add missing RCU idle APIs on idle loop commit 0ee23fda59740767324b4340247ca41a2f498ca6 upstream. In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in scores's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Cc: Chen Liqin Cc: Lennox Wu Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett Signed-off-by: Greg Kroah-Hartman --- arch/score/kernel/process.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c index 2707023c756..637970cfd3f 100644 --- a/arch/score/kernel/process.c +++ b/arch/score/kernel/process.c @@ -27,6 +27,7 @@ #include #include #include +#include void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); @@ -50,9 +51,10 @@ void __noreturn cpu_idle(void) { /* endless idle loop with no priority at all */ while (1) { + rcu_idle_enter(); while (!need_resched()) barrier(); - + rcu_idle_exit(); schedule_preempt_disabled(); } } From f5260a7c89bf5146c0d52b036ac58eb192537a84 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Sep 2012 13:55:30 -0700 Subject: [PATCH 1188/2357] rcu: Fix day-one dyntick-idle stall-warning bug commit a10d206ef1a83121ab7430cb196e0376a7145b22 upstream. Each grace period is supposed to have at least one callback waiting for that grace period to complete. However, if CONFIG_NO_HZ=n, an extra callback-free grace period is no big problem -- it will chew up a tiny bit of CPU time, but it will complete normally. In contrast, CONFIG_NO_HZ=y kernels have the potential for all the CPUs to go to sleep indefinitely, in turn indefinitely delaying completion of the callback-free grace period. Given that nothing is waiting on this grace period, this is also not a problem. That is, unless RCU CPU stall warnings are also enabled, as they are in recent kernels. In this case, if a CPU wakes up after at least one minute of inactivity, an RCU CPU stall warning will result. The reason that no one noticed until quite recently is that most systems have enough OS noise that they will never remain absolutely idle for a full minute. But there are some embedded systems with cut-down userspace configurations that consistently get into this situation. All this begs the question of exactly how a callback-free grace period gets started in the first place. This can happen due to the fact that CPUs do not necessarily agree on which grace period is in progress. If a CPU still believes that the grace period that just completed is still ongoing, it will believe that it has callbacks that need to wait for another grace period, never mind the fact that the grace period that they were waiting for just completed. This CPU can therefore erroneously decide to start a new grace period. Note that this can happen in TREE_RCU and TREE_PREEMPT_RCU even on a single-CPU system: Deadlock considerations mean that the CPU that detected the end of the grace period is not necessarily officially informed of this fact for some time. Once this CPU notices that the earlier grace period completed, it will invoke its callbacks. It then won't have any callbacks left. If no other CPU has any callbacks, we now have a callback-free grace period. This commit therefore makes CPUs check more carefully before starting a new grace period. This new check relies on an array of tail pointers into each CPU's list of callbacks. If the CPU is up to date on which grace periods have completed, it checks to see if any callbacks follow the RCU_DONE_TAIL segment, otherwise it checks to see if any callbacks follow the RCU_WAIT_TAIL segment. The reason that this works is that the RCU_WAIT_TAIL segment will be promoted to the RCU_DONE_TAIL segment as soon as the CPU is officially notified that the old grace period has ended. This change is to cpu_needs_another_gp(), which is called in a number of places. The only one that really matters is in rcu_start_gp(), where the root rcu_node structure's ->lock is held, which prevents any other CPU from starting or completing a grace period, so that the comparison that determines whether the CPU is missing the completion of a grace period is stable. Reported-by: Becky Bruce Reported-by: Subodh Nijsure Reported-by: Paul Walmsley Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Tested-by: Paul Walmsley Signed-off-by: Greg Kroah-Hartman --- kernel/rcutree.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d0c5baf1ab1..4eec66e0350 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -295,7 +295,9 @@ cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp) static int cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp) { - return *rdp->nxttail[RCU_DONE_TAIL] && !rcu_gp_in_progress(rsp); + return *rdp->nxttail[RCU_DONE_TAIL + + ACCESS_ONCE(rsp->completed) != rdp->completed] && + !rcu_gp_in_progress(rsp); } /* From 34ffca41fc0a205bb00382be7bbefbf2fc63436d Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sat, 6 Oct 2012 11:19:52 +0200 Subject: [PATCH 1189/2357] r8169: Config1 is read-only on 8168c and later. commit 851e60221926a53344b4227879858bef841b0477 upstream. Suggested by Hayes. Signed-off-by: Francois Romieu Cc: Hayes Wang Acked-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 5fb74c4298f..adf496d0ce4 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -1400,7 +1400,6 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) u16 reg; u8 mask; } cfg[] = { - { WAKE_ANY, Config1, PMEnable }, { WAKE_PHY, Config3, LinkUp }, { WAKE_MAGIC, Config3, MagicPacket }, { WAKE_UCAST, Config5, UWF }, @@ -1408,16 +1407,28 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) { WAKE_MCAST, Config5, MWF }, { WAKE_ANY, Config5, LanWake } }; + u8 options; RTL_W8(Cfg9346, Cfg9346_Unlock); for (i = 0; i < ARRAY_SIZE(cfg); i++) { - u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask; + options = RTL_R8(cfg[i].reg) & ~cfg[i].mask; if (wolopts & cfg[i].opt) options |= cfg[i].mask; RTL_W8(cfg[i].reg, options); } + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17: + options = RTL_R8(Config1) & ~PMEnable; + if (wolopts) + options |= PMEnable; + RTL_W8(Config1, options); + break; + default: + break; + } + RTL_W8(Cfg9346, Cfg9346_Lock); } From 160f00fefef1e5b72be0745236d2b65d14b99ed4 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sat, 6 Oct 2012 11:19:53 +0200 Subject: [PATCH 1190/2357] r8169: 8168c and later require bit 0x20 to be set in Config2 for PME signaling. commit d387b427c973974dd619a33549c070ac5d0e089f upstream. The new 84xx stopped flying below the radars. Signed-off-by: Francois Romieu Cc: Hayes Wang Acked-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index adf496d0ce4..482dcd3a7ad 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -319,6 +319,8 @@ enum rtl_registers { Config0 = 0x51, Config1 = 0x52, Config2 = 0x53, +#define PME_SIGNAL (1 << 5) /* 8168c and later */ + Config3 = 0x54, Config4 = 0x55, Config5 = 0x56, @@ -1426,6 +1428,10 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) RTL_W8(Config1, options); break; default: + options = RTL_R8(Config2) & ~PME_SIGNAL; + if (wolopts) + options |= PME_SIGNAL; + RTL_W8(Config2, options); break; } From 14cfd9f986d521f3f97139fa2ae5db67886059d1 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Mon, 8 Oct 2012 16:29:14 -0700 Subject: [PATCH 1191/2357] revert "mm: mempolicy: Let vma_merge and vma_split handle vma->vm_policy linkages" commit 8d34694c1abf29df1f3c7317936b7e3e2e308d9b upstream. Commit 05f144a0d5c2 ("mm: mempolicy: Let vma_merge and vma_split handle vma->vm_policy linkages") removed vma->vm_policy updates code but it is the purpose of mbind_range(). Now, mbind_range() is virtually a no-op and while it does not allow memory corruption it is not the right fix. This patch is a revert. [mgorman@suse.de: Edited changelog] Signed-off-by: KOSAKI Motohiro Signed-off-by: Mel Gorman Cc: Christoph Lameter Cc: Josh Boyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 9afcbad632e..ed3cc1bea49 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -607,6 +607,27 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, return first; } +/* Apply policy to a single VMA */ +static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new) +{ + int err = 0; + struct mempolicy *old = vma->vm_policy; + + pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n", + vma->vm_start, vma->vm_end, vma->vm_pgoff, + vma->vm_ops, vma->vm_file, + vma->vm_ops ? vma->vm_ops->set_policy : NULL); + + if (vma->vm_ops && vma->vm_ops->set_policy) + err = vma->vm_ops->set_policy(vma, new); + if (!err) { + mpol_get(new); + vma->vm_policy = new; + mpol_put(old); + } + return err; +} + /* Step 2: apply policy to a range and do splits. */ static int mbind_range(struct mm_struct *mm, unsigned long start, unsigned long end, struct mempolicy *new_pol) @@ -655,23 +676,9 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, if (err) goto out; } - - /* - * Apply policy to a single VMA. The reference counting of - * policy for vma_policy linkages has already been handled by - * vma_merge and split_vma as necessary. If this is a shared - * policy then ->set_policy will increment the reference count - * for an sp node. - */ - pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff, - vma->vm_ops, vma->vm_file, - vma->vm_ops ? vma->vm_ops->set_policy : NULL); - if (vma->vm_ops && vma->vm_ops->set_policy) { - err = vma->vm_ops->set_policy(vma, new_pol); - if (err) - goto out; - } + err = policy_vma(vma, new_pol); + if (err) + goto out; } out: From 33efe2910bf7865a7d1fba4b06c9fa4b6fda6856 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Mon, 8 Oct 2012 16:29:16 -0700 Subject: [PATCH 1192/2357] mempolicy: remove mempolicy sharing commit 869833f2c5c6e4dd09a5378cfc665ffb4615e5d2 upstream. Dave Jones' system call fuzz testing tool "trinity" triggered the following bug error with slab debugging enabled ============================================================================= BUG numa_policy (Not tainted): Poison overwritten ----------------------------------------------------------------------------- INFO: 0xffff880146498250-0xffff880146498250. First byte 0x6a instead of 0x6b INFO: Allocated in mpol_new+0xa3/0x140 age=46310 cpu=6 pid=32154 __slab_alloc+0x3d3/0x445 kmem_cache_alloc+0x29d/0x2b0 mpol_new+0xa3/0x140 sys_mbind+0x142/0x620 system_call_fastpath+0x16/0x1b INFO: Freed in __mpol_put+0x27/0x30 age=46268 cpu=6 pid=32154 __slab_free+0x2e/0x1de kmem_cache_free+0x25a/0x260 __mpol_put+0x27/0x30 remove_vma+0x68/0x90 exit_mmap+0x118/0x140 mmput+0x73/0x110 exit_mm+0x108/0x130 do_exit+0x162/0xb90 do_group_exit+0x4f/0xc0 sys_exit_group+0x17/0x20 system_call_fastpath+0x16/0x1b INFO: Slab 0xffffea0005192600 objects=27 used=27 fp=0x (null) flags=0x20000000004080 INFO: Object 0xffff880146498250 @offset=592 fp=0xffff88014649b9d0 The problem is that the structure is being prematurely freed due to a reference count imbalance. In the following case mbind(addr, len) should replace the memory policies of both vma1 and vma2 and thus they will become to share the same mempolicy and the new mempolicy will have the MPOL_F_SHARED flag. +-------------------+-------------------+ | vma1 | vma2(shmem) | +-------------------+-------------------+ | | addr addr+len alloc_pages_vma() uses get_vma_policy() and mpol_cond_put() pair for maintaining the mempolicy reference count. The current rule is that get_vma_policy() only increments refcount for shmem VMA and mpol_conf_put() only decrements refcount if the policy has MPOL_F_SHARED. In above case, vma1 is not shmem vma and vma->policy has MPOL_F_SHARED! The reference count will be decreased even though was not increased whenever alloc_page_vma() is called. This has been broken since commit [52cd3b07: mempolicy: rework mempolicy Reference Counting] in 2008. There is another serious bug with the sharing of memory policies. Currently, mempolicy rebind logic (it is called from cpuset rebinding) ignores a refcount of mempolicy and override it forcibly. Thus, any mempolicy sharing may cause mempolicy corruption. The bug was introduced by commit [68860ec1: cpusets: automatic numa mempolicy rebinding]. Ideally, the shared policy handling would be rewritten to either properly handle COW of the policy structures or at least reference count MPOL_F_SHARED based exclusively on information within the policy. However, this patch takes the easier approach of disabling any policy sharing between VMAs. Each new range allocated with sp_alloc will allocate a new policy, set the reference count to 1 and drop the reference count of the old policy. This increases the memory footprint but is not expected to be a major problem as mbind() is unlikely to be used for fine-grained ranges. It is also inefficient because it means we allocate a new policy even in cases where mbind_range() could use the new_policy passed to it. However, it is more straight-forward and the change should be invisible to the user. [mgorman@suse.de: Edited changelog] Reported-by: Dave Jones Cc: Christoph Lameter Reviewed-by: Christoph Lameter Signed-off-by: KOSAKI Motohiro Signed-off-by: Mel Gorman Cc: Josh Boyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 52 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index ed3cc1bea49..c2efa3ddf62 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -607,24 +607,39 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, return first; } -/* Apply policy to a single VMA */ -static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new) +/* + * Apply policy to a single VMA + * This must be called with the mmap_sem held for writing. + */ +static int vma_replace_policy(struct vm_area_struct *vma, + struct mempolicy *pol) { - int err = 0; - struct mempolicy *old = vma->vm_policy; + int err; + struct mempolicy *old; + struct mempolicy *new; pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n", vma->vm_start, vma->vm_end, vma->vm_pgoff, vma->vm_ops, vma->vm_file, vma->vm_ops ? vma->vm_ops->set_policy : NULL); - if (vma->vm_ops && vma->vm_ops->set_policy) + new = mpol_dup(pol); + if (IS_ERR(new)) + return PTR_ERR(new); + + if (vma->vm_ops && vma->vm_ops->set_policy) { err = vma->vm_ops->set_policy(vma, new); - if (!err) { - mpol_get(new); - vma->vm_policy = new; - mpol_put(old); + if (err) + goto err_out; } + + old = vma->vm_policy; + vma->vm_policy = new; /* protected by mmap_sem */ + mpol_put(old); + + return 0; + err_out: + mpol_put(new); return err; } @@ -676,7 +691,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, if (err) goto out; } - err = policy_vma(vma, new_pol); + err = vma_replace_policy(vma, new_pol); if (err) goto out; } @@ -2127,15 +2142,24 @@ static void sp_delete(struct shared_policy *sp, struct sp_node *n) static struct sp_node *sp_alloc(unsigned long start, unsigned long end, struct mempolicy *pol) { - struct sp_node *n = kmem_cache_alloc(sn_cache, GFP_KERNEL); + struct sp_node *n; + struct mempolicy *newpol; + n = kmem_cache_alloc(sn_cache, GFP_KERNEL); if (!n) return NULL; + + newpol = mpol_dup(pol); + if (IS_ERR(newpol)) { + kmem_cache_free(sn_cache, n); + return NULL; + } + newpol->flags |= MPOL_F_SHARED; + n->start = start; n->end = end; - mpol_get(pol); - pol->flags |= MPOL_F_SHARED; /* for unref */ - n->policy = pol; + n->policy = newpol; + return n; } From 04a30bd9dccbeee2cc6b035e42a37e9be0fa8c6c Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Mon, 8 Oct 2012 16:29:17 -0700 Subject: [PATCH 1193/2357] mempolicy: fix a race in shared_policy_replace() commit b22d127a39ddd10d93deee3d96e643657ad53a49 upstream. shared_policy_replace() use of sp_alloc() is unsafe. 1) sp_node cannot be dereferenced if sp->lock is not held and 2) another thread can modify sp_node between spin_unlock for allocating a new sp node and next spin_lock. The bug was introduced before 2.6.12-rc2. Kosaki's original patch for this problem was to allocate an sp node and policy within shared_policy_replace and initialise it when the lock is reacquired. I was not keen on this approach because it partially duplicates sp_alloc(). As the paths were sp->lock is taken are not that performance critical this patch converts sp->lock to sp->mutex so it can sleep when calling sp_alloc(). [kosaki.motohiro@jp.fujitsu.com: Original patch] Signed-off-by: Mel Gorman Acked-by: KOSAKI Motohiro Reviewed-by: Christoph Lameter Cc: Josh Boyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/mempolicy.h | 2 +- mm/mempolicy.c | 37 ++++++++++++++++--------------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 7c727a90d70..0abf1d436b1 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -188,7 +188,7 @@ struct sp_node { struct shared_policy { struct rb_root root; - spinlock_t lock; + struct mutex mutex; }; void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index c2efa3ddf62..30850253c06 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2057,7 +2057,7 @@ bool __mpol_equal(struct mempolicy *a, struct mempolicy *b) */ /* lookup first element intersecting start-end */ -/* Caller holds sp->lock */ +/* Caller holds sp->mutex */ static struct sp_node * sp_lookup(struct shared_policy *sp, unsigned long start, unsigned long end) { @@ -2121,13 +2121,13 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx) if (!sp->root.rb_node) return NULL; - spin_lock(&sp->lock); + mutex_lock(&sp->mutex); sn = sp_lookup(sp, idx, idx+1); if (sn) { mpol_get(sn->policy); pol = sn->policy; } - spin_unlock(&sp->lock); + mutex_unlock(&sp->mutex); return pol; } @@ -2167,10 +2167,10 @@ static struct sp_node *sp_alloc(unsigned long start, unsigned long end, static int shared_policy_replace(struct shared_policy *sp, unsigned long start, unsigned long end, struct sp_node *new) { - struct sp_node *n, *new2 = NULL; + struct sp_node *n; + int ret = 0; -restart: - spin_lock(&sp->lock); + mutex_lock(&sp->mutex); n = sp_lookup(sp, start, end); /* Take care of old policies in the same range. */ while (n && n->start < end) { @@ -2183,16 +2183,14 @@ static int shared_policy_replace(struct shared_policy *sp, unsigned long start, } else { /* Old policy spanning whole new range. */ if (n->end > end) { + struct sp_node *new2; + new2 = sp_alloc(end, n->end, n->policy); if (!new2) { - spin_unlock(&sp->lock); - new2 = sp_alloc(end, n->end, n->policy); - if (!new2) - return -ENOMEM; - goto restart; + ret = -ENOMEM; + goto out; } n->end = start; sp_insert(sp, new2); - new2 = NULL; break; } else n->end = start; @@ -2203,12 +2201,9 @@ static int shared_policy_replace(struct shared_policy *sp, unsigned long start, } if (new) sp_insert(sp, new); - spin_unlock(&sp->lock); - if (new2) { - mpol_put(new2->policy); - kmem_cache_free(sn_cache, new2); - } - return 0; +out: + mutex_unlock(&sp->mutex); + return ret; } /** @@ -2226,7 +2221,7 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol) int ret; sp->root = RB_ROOT; /* empty tree == default mempolicy */ - spin_lock_init(&sp->lock); + mutex_init(&sp->mutex); if (mpol) { struct vm_area_struct pvma; @@ -2292,7 +2287,7 @@ void mpol_free_shared_policy(struct shared_policy *p) if (!p->root.rb_node) return; - spin_lock(&p->lock); + mutex_lock(&p->mutex); next = rb_first(&p->root); while (next) { n = rb_entry(next, struct sp_node, nd); @@ -2301,7 +2296,7 @@ void mpol_free_shared_policy(struct shared_policy *p) mpol_put(n->policy); kmem_cache_free(sn_cache, n); } - spin_unlock(&p->lock); + mutex_unlock(&p->mutex); } /* assumes fs == KERNEL_DS */ From 04ea8a8388992ad12bc1b32cc16f4220300ea167 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Mon, 8 Oct 2012 16:29:19 -0700 Subject: [PATCH 1194/2357] mempolicy: fix refcount leak in mpol_set_shared_policy() commit 63f74ca21f1fad36d075e063f06dcc6d39fe86b2 upstream. When shared_policy_replace() fails to allocate new->policy is not freed correctly by mpol_set_shared_policy(). The problem is that shared mempolicy code directly call kmem_cache_free() in multiple places where it is easy to make a mistake. This patch creates an sp_free wrapper function and uses it. The bug was introduced pre-git age (IOW, before 2.6.12-rc2). [mgorman@suse.de: Editted changelog] Signed-off-by: KOSAKI Motohiro Signed-off-by: Mel Gorman Reviewed-by: Christoph Lameter Cc: Josh Boyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 30850253c06..06531fc365e 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2131,12 +2131,17 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx) return pol; } +static void sp_free(struct sp_node *n) +{ + mpol_put(n->policy); + kmem_cache_free(sn_cache, n); +} + static void sp_delete(struct shared_policy *sp, struct sp_node *n) { pr_debug("deleting %lx-l%lx\n", n->start, n->end); rb_erase(&n->nd, &sp->root); - mpol_put(n->policy); - kmem_cache_free(sn_cache, n); + sp_free(n); } static struct sp_node *sp_alloc(unsigned long start, unsigned long end, @@ -2275,7 +2280,7 @@ int mpol_set_shared_policy(struct shared_policy *info, } err = shared_policy_replace(info, vma->vm_pgoff, vma->vm_pgoff+sz, new); if (err && new) - kmem_cache_free(sn_cache, new); + sp_free(new); return err; } @@ -2292,9 +2297,7 @@ void mpol_free_shared_policy(struct shared_policy *p) while (next) { n = rb_entry(next, struct sp_node, nd); next = rb_next(&n->nd); - rb_erase(&n->nd, &p->root); - mpol_put(n->policy); - kmem_cache_free(sn_cache, n); + sp_delete(p, n); } mutex_unlock(&p->mutex); } From d9302b128e4640df707c99335b3f3ad0e13d0148 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Mon, 8 Oct 2012 16:29:20 -0700 Subject: [PATCH 1195/2357] mempolicy: fix a memory corruption by refcount imbalance in alloc_pages_vma() commit 00442ad04a5eac08a98255697c510e708f6082e2 upstream. Commit cc9a6c877661 ("cpuset: mm: reduce large amounts of memory barrier related damage v3") introduced a potential memory corruption. shmem_alloc_page() uses a pseudo vma and it has one significant unique combination, vma->vm_ops=NULL and vma->policy->flags & MPOL_F_SHARED. get_vma_policy() does NOT increase a policy ref when vma->vm_ops=NULL and mpol_cond_put() DOES decrease a policy ref when a policy has MPOL_F_SHARED. Therefore, when a cpuset update race occurs, alloc_pages_vma() falls in 'goto retry_cpuset' path, decrements the reference count and frees the policy prematurely. Signed-off-by: KOSAKI Motohiro Signed-off-by: Mel Gorman Reviewed-by: Christoph Lameter Cc: Josh Boyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 06531fc365e..d1e4beffbe1 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1532,8 +1532,18 @@ struct mempolicy *get_vma_policy(struct task_struct *task, addr); if (vpol) pol = vpol; - } else if (vma->vm_policy) + } else if (vma->vm_policy) { pol = vma->vm_policy; + + /* + * shmem_alloc_page() passes MPOL_F_SHARED policy with + * a pseudo vma whose vma->vm_ops=NULL. Take a reference + * count on these policies which will be dropped by + * mpol_cond_put() later + */ + if (mpol_needs_cond_ref(pol)) + mpol_get(pol); + } } if (!pol) pol = &default_policy; From b4bec66863ab1c55ccc1a9b01988b8b6b5abac87 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 26 Jul 2012 18:00:00 -0400 Subject: [PATCH 1196/2357] efi: Build EFI stub with EFI-appropriate options commit 9dead5bbb825d7c25c0400e61de83075046322d0 upstream. We can't assume the presence of the red zone while we're still in a boot services environment, so we should build with -fno-red-zone to avoid problems. Change the size of wchar at the same time to make string handling simpler. Signed-off-by: Matthew Garrett Signed-off-by: Matt Fleming Acked-by: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- arch/x86/boot/compressed/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index e398bb5d63b..8a84501acb1 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -28,6 +28,9 @@ VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \ $(obj)/piggy.o +$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone +$(obj)/efi_stub_$(BITS).o: KBUILD_CLFAGS += -fshort-wchar -mno-red-zone + ifeq ($(CONFIG_EFI_STUB), y) VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o endif From 0c9673834740afdfa7c172b1b19c6b3ec5bc3907 Mon Sep 17 00:00:00 2001 From: Seiji Aguchi Date: Tue, 24 Jul 2012 13:27:23 +0000 Subject: [PATCH 1197/2357] efi: initialize efi.runtime_version to make query_variable_info/update_capsule workable commit d6cf86d8f23253225fe2a763d627ecf7dfee9dae upstream. A value of efi.runtime_version is checked before calling update_capsule()/query_variable_info() as follows. But it isn't initialized anywhere. static efi_status_t virt_efi_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space, u64 *max_variable_size) { if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; This patch initializes a value of efi.runtime_version at boot time. Signed-off-by: Seiji Aguchi Acked-by: Matthew Garrett Signed-off-by: Matt Fleming Signed-off-by: Ivan Hu Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/efi/efi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 92660edaa1e..f55a4ce6dc4 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -890,6 +890,7 @@ void __init efi_enter_virtual_mode(void) * * Call EFI services through wrapper functions. */ + efi.runtime_version = efi_systab.fw_revision; efi.get_time = virt_efi_get_time; efi.set_time = virt_efi_set_time; efi.get_wakeup_time = virt_efi_get_wakeup_time; From c62f9945efea31db203fd4fb77e830ddffdcabf6 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Thu, 24 May 2012 19:46:26 +0530 Subject: [PATCH 1198/2357] CPU hotplug, cpusets, suspend: Don't modify cpusets during suspend/resume commit d35be8bab9b0ce44bed4b9453f86ebf64062721e upstream. In the event of CPU hotplug, the kernel modifies the cpusets' cpus_allowed masks as and when necessary to ensure that the tasks belonging to the cpusets have some place (online CPUs) to run on. And regular CPU hotplug is destructive in the sense that the kernel doesn't remember the original cpuset configurations set by the user, across hotplug operations. However, suspend/resume (which uses CPU hotplug) is a special case in which the kernel has the responsibility to restore the system (during resume), to exactly the same state it was in before suspend. In order to achieve that, do the following: 1. Don't modify cpusets during suspend/resume. At all. In particular, don't move the tasks from one cpuset to another, and don't modify any cpuset's cpus_allowed mask. So, simply ignore cpusets during the CPU hotplug operations that are carried out in the suspend/resume path. 2. However, cpusets and sched domains are related. We just want to avoid altering cpusets alone. So, to keep the sched domains updated, build a single sched domain (containing all active cpus) during each of the CPU hotplug operations carried out in s/r path, effectively ignoring the cpusets' cpus_allowed masks. (Since userspace is frozen while doing all this, it will go unnoticed.) 3. During the last CPU online operation during resume, build the sched domains by looking up the (unaltered) cpusets' cpus_allowed masks. That will bring back the system to the same original state as it was in before suspend. Ultimately, this will not only solve the cpuset problem related to suspend resume (ie., restores the cpusets to exactly what it was before suspend, by not touching it at all) but also speeds up suspend/resume because we avoid running cpuset update code for every CPU being offlined/onlined. Signed-off-by: Srivatsa S. Bhat Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Cc: Andrew Morton Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20120524141611.3692.20155.stgit@srivatsabhat.in.ibm.com Signed-off-by: Ingo Molnar Signed-off-by: Preeti U Murthy Signed-off-by: Greg Kroah-Hartman --- kernel/cpuset.c | 3 +++ kernel/sched/core.c | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 14f7070b4ba..5fc1570e64c 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -2065,6 +2065,9 @@ static void scan_for_empty_cpusets(struct cpuset *root) * (of no affect) on systems that are actively using CPU hotplug * but making no active use of cpusets. * + * The only exception to this is suspend/resume, where we don't + * modify cpusets at all. + * * This routine ensures that top_cpuset.cpus_allowed tracks * cpu_active_mask on each CPU hotplug (cpuhp) event. * diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 593087b2baf..1d22981cd43 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -6937,34 +6937,66 @@ int __init sched_create_sysfs_power_savings_entries(struct device *dev) } #endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ +static int num_cpus_frozen; /* used to mark begin/end of suspend/resume */ + /* * Update cpusets according to cpu_active mask. If cpusets are * disabled, cpuset_update_active_cpus() becomes a simple wrapper * around partition_sched_domains(). + * + * If we come here as part of a suspend/resume, don't touch cpusets because we + * want to restore it back to its original state upon resume anyway. */ static int cpuset_cpu_active(struct notifier_block *nfb, unsigned long action, void *hcpu) { - switch (action & ~CPU_TASKS_FROZEN) { + switch (action) { + case CPU_ONLINE_FROZEN: + case CPU_DOWN_FAILED_FROZEN: + + /* + * num_cpus_frozen tracks how many CPUs are involved in suspend + * resume sequence. As long as this is not the last online + * operation in the resume sequence, just build a single sched + * domain, ignoring cpusets. + */ + num_cpus_frozen--; + if (likely(num_cpus_frozen)) { + partition_sched_domains(1, NULL, NULL); + break; + } + + /* + * This is the last CPU online operation. So fall through and + * restore the original sched domains by considering the + * cpuset configurations. + */ + case CPU_ONLINE: case CPU_DOWN_FAILED: cpuset_update_active_cpus(); - return NOTIFY_OK; + break; default: return NOTIFY_DONE; } + return NOTIFY_OK; } static int cpuset_cpu_inactive(struct notifier_block *nfb, unsigned long action, void *hcpu) { - switch (action & ~CPU_TASKS_FROZEN) { + switch (action) { case CPU_DOWN_PREPARE: cpuset_update_active_cpus(); - return NOTIFY_OK; + break; + case CPU_DOWN_PREPARE_FROZEN: + num_cpus_frozen++; + partition_sched_domains(1, NULL, NULL); + break; default: return NOTIFY_DONE; } + return NOTIFY_OK; } void __init sched_init_smp(void) From e82df24e733c04385e8d8c32d3062292668bf8c0 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Sat, 18 Aug 2012 13:07:41 -0400 Subject: [PATCH 1199/2357] mtd: mtdpart: break it as soon as we parse out the partitions commit c51803ddba10d80d9f246066802c6e359cf1d44c upstream. We may cause a memory leak when the @types has more then one parser. Take the `default_mtd_part_types` for example. The default_mtd_part_types has two parsers now: `cmdlinepart` and `ofpart`. Assume the following case: The kernel command line sets the partitions like: #gpmi-nand:20m(boot),20m(kernel),1g(rootfs),-(user) But the devicetree file(such as arch/arm/boot/dts/imx28-evk.dts) also sets the same partitions as the kernel command line does. In the current code, the partitions parsed out by the `ofpart` will overwrite the @pparts which has already set by the `cmdlinepart` parser, and the the partitions parsed out by the `cmdlinepart` is missed. A memory leak occurs. So we should break the code as soon as we parse out the partitions, In actually, this patch makes a priority order between the parsers. If one parser has already parsed out the partitions successfully, it's no need to use another parser anymore. Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtdpart.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 9651c06de0a..bf24aa77175 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -709,6 +709,8 @@ static const char *default_mtd_part_types[] = { * partition parsers, specified in @types. However, if @types is %NULL, then * the default list of parsers is used. The default list contains only the * "cmdlinepart" and "ofpart" parsers ATM. + * Note: If there are more then one parser in @types, the kernel only takes the + * partitions parsed out by the first parser. * * This function may return: * o a negative error code in case of failure @@ -733,11 +735,12 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, if (!parser) continue; ret = (*parser->parse_fn)(master, pparts, data); + put_partition_parser(parser); if (ret > 0) { printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", ret, parser->name, master->name); + break; } - put_partition_parser(parser); } return ret; } From 2640a717145425d59c066e7de9350719912bd418 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 15 Aug 2012 20:28:05 +0400 Subject: [PATCH 1200/2357] mtd: autcpu12-nvram: Fix compile breakage commit d1f55c680e5d021e7066f4461dd678d42af18898 upstream. Update driver autcpu12-nvram.c so it compiles; map_read32/map_write32 no longer exist in the kernel so the driver is totally broken. Additionally, map_info name passed to simple_map_init is incorrect. Signed-off-by: Alexander Shiyan Acked-by: Arnd Bergmann Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/maps/autcpu12-nvram.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index e5bfd0e093b..0598d52eaf9 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c @@ -43,7 +43,8 @@ struct map_info autcpu12_sram_map = { static int __init init_autcpu12_sram (void) { - int err, save0, save1; + map_word tmp, save0, save1; + int err; autcpu12_sram_map.virt = ioremap(0x12000000, SZ_128K); if (!autcpu12_sram_map.virt) { @@ -51,7 +52,7 @@ static int __init init_autcpu12_sram (void) err = -EIO; goto out; } - simple_map_init(&autcpu_sram_map); + simple_map_init(&autcpu12_sram_map); /* * Check for 32K/128K @@ -61,20 +62,22 @@ static int __init init_autcpu12_sram (void) * Read and check result on ofs 0x0 * Restore contents */ - save0 = map_read32(&autcpu12_sram_map,0); - save1 = map_read32(&autcpu12_sram_map,0x10000); - map_write32(&autcpu12_sram_map,~save0,0x10000); + save0 = map_read(&autcpu12_sram_map, 0); + save1 = map_read(&autcpu12_sram_map, 0x10000); + tmp.x[0] = ~save0.x[0]; + map_write(&autcpu12_sram_map, tmp, 0x10000); /* if we find this pattern on 0x0, we have 32K size * restore contents and exit */ - if ( map_read32(&autcpu12_sram_map,0) != save0) { - map_write32(&autcpu12_sram_map,save0,0x0); + tmp = map_read(&autcpu12_sram_map, 0); + if (!map_word_equal(&autcpu12_sram_map, tmp, save0)) { + map_write(&autcpu12_sram_map, save0, 0x0); goto map; } /* We have a 128K found, restore 0x10000 and set size * to 128K */ - map_write32(&autcpu12_sram_map,save1,0x10000); + map_write(&autcpu12_sram_map, save1, 0x10000); autcpu12_sram_map.size = SZ_128K; map: From 70b22c795bbe61ab4935649bb6b4135f29d164bd Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Wed, 12 Sep 2012 14:26:26 +0200 Subject: [PATCH 1201/2357] mtd: nandsim: bugfix: fail if overridesize is too big commit bb0a13a13411c4ce24c48c8ff3cdf7b48d237240 upstream. If override size is too big, the module was actually loaded instead of failing, because retval was not set. This lead to memory corruption with the use of the freed structs nandsim and nand_chip. Signed-off-by: Richard Genoud Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/nandsim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c606b6afd7a..b9cbd65f49b 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -2355,6 +2355,7 @@ static int __init ns_init_module(void) uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize; if (new_size >> overridesize != nsmtd->erasesize) { NS_ERR("overridesize is too big\n"); + retval = -EINVAL; goto err_exit; } /* N.B. This relies on nand_scan not doing anything with the size before we change it */ From 196f9c71e5f46965325f31532f1d55c4a809f6ff Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Sun, 10 Jun 2012 13:58:12 +0300 Subject: [PATCH 1202/2357] mtd: nand: Use the mirror BBT descriptor when reading its version commit 7bb9c75436212813b38700c34df4bbb6eb82debe upstream. The code responsible for reading the version of the mirror bbt was incorrectly using the descriptor of the main bbt. Pass the mirror bbt descriptor to 'scan_read_raw' when reading the version of the mirror bbt. Signed-off-by: Shmulik Ladkani Acked-by: Sebastian Andrzej Siewior Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/nand_bbt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 30d1319ff06..c126469b064 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -390,7 +390,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, - mtd->writesize, td); + mtd->writesize, md); md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; pr_info("Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); From 7c6313717892eabf93b53d8a112263f41646ed4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Bie=C3=9Fmann?= Date: Fri, 31 Aug 2012 13:35:41 +0200 Subject: [PATCH 1203/2357] mtd: omap2: fix omap_nand_remove segfault MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7d9b110269253b1d5858cfa57d68dfc7bf50dd77 upstream. Do not kfree() the mtd_info; it is handled in the mtd subsystem and already freed by nand_release(). Instead kfree() the struct omap_nand_info allocated in omap_nand_probe which was not freed before. This patch fixes following error when unloading the omap2 module: ---8<--- ~ $ rmmod omap2 ------------[ cut here ]------------ kernel BUG at mm/slab.c:3126! Internal error: Oops - BUG: 0 [#1] PREEMPT ARM Modules linked in: omap2(-) CPU: 0 Not tainted (3.6.0-rc3-00230-g155e36d-dirty #3) PC is at cache_free_debugcheck+0x2d4/0x36c LR is at kfree+0xc8/0x2ac pc : [] lr : [] psr: 200d0193 sp : c521fe08 ip : c0e8ef90 fp : c521fe5c r10: bf0001fc r9 : c521e000 r8 : c0d99c8c r7 : c661ebc0 r6 : c065d5a4 r5 : c65c4060 r4 : c78005c0 r3 : 00000000 r2 : 00001000 r1 : c65c4000 r0 : 00000001 Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c5387d Table: 86694019 DAC: 00000015 Process rmmod (pid: 549, stack limit = 0xc521e2f0) Stack: (0xc521fe08 to 0xc5220000) fe00: c008a874 c00bf44c c515c6d0 200d0193 c65c4860 c515c240 fe20: c521fe3c c521fe30 c008a9c0 c008a854 c521fe5c c65c4860 c78005c0 bf0001fc fe40: c780ff40 a00d0113 c521e000 00000000 c521fe84 c521fe60 c0112efc c01122d8 fe60: c65c4860 c0673778 c06737ac 00000000 00070013 00000000 c521fe9c c521fe88 fe80: bf0001fc c0112e40 c0673778 bf001ca8 c521feac c521fea0 c02ca11c bf0001ac fea0: c521fec4 c521feb0 c02c82c4 c02ca100 c0673778 bf001ca8 c521fee4 c521fec8 fec0: c02c8dd8 c02c8250 00000000 bf001ca8 bf001ca8 c0804ee0 c521ff04 c521fee8 fee0: c02c804c c02c8d20 bf001924 00000000 bf001ca8 c521e000 c521ff1c c521ff08 ff00: c02c950c c02c7fbc bf001d48 00000000 c521ff2c c521ff20 c02ca3a4 c02c94b8 ff20: c521ff3c c521ff30 bf001938 c02ca394 c521ffa4 c521ff40 c009beb4 bf001930 ff40: c521ff6c 70616d6f b6fe0032 c0014f84 70616d6f b6fe0032 00000081 60070010 ff60: c521ff84 c521ff70 c008e1f4 c00bf328 0001a004 70616d6f c521ff94 0021ff88 ff80: c008e368 0001a004 70616d6f b6fe0032 00000081 c0015028 00000000 c521ffa8 ffa0: c0014dc0 c009bcd0 0001a004 70616d6f bec2ab38 00000880 bec2ab38 00000880 ffc0: 0001a004 70616d6f b6fe0032 00000081 00000319 00000000 b6fe1000 00000000 ffe0: bec2ab30 bec2ab20 00019f00 b6f539c0 60070010 bec2ab38 aaaaaaaa aaaaaaaa Backtrace: [] (cache_free_debugcheck+0x0/0x36c) from [] (kfree+0xc8/0x2ac) [] (kfree+0x0/0x2ac) from [] (omap_nand_remove+0x5c/0x64 [omap2]) [] (omap_nand_remove+0x0/0x64 [omap2]) from [] (platform_drv_remove+0x28/0x2c) r5:bf001ca8 r4:c0673778 [] (platform_drv_remove+0x0/0x2c) from [] (__device_release_driver+0x80/0xdc) [] (__device_release_driver+0x0/0xdc) from [] (driver_detach+0xc4/0xc8) r5:bf001ca8 r4:c0673778 [] (driver_detach+0x0/0xc8) from [] (bus_remove_driver+0x9c/0x104) r6:c0804ee0 r5:bf001ca8 r4:bf001ca8 r3:00000000 [] (bus_remove_driver+0x0/0x104) from [] (driver_unregister+0x60/0x80) r6:c521e000 r5:bf001ca8 r4:00000000 r3:bf001924 [] (driver_unregister+0x0/0x80) from [] (platform_driver_unregister+0x1c/0x20) r5:00000000 r4:bf001d48 [] (platform_driver_unregister+0x0/0x20) from [] (omap_nand_driver_exit+0x14/0x1c [omap2]) [] (omap_nand_driver_exit+0x0/0x1c [omap2]) from [] (sys_delete_module+0x1f0/0x2ec) [] (sys_delete_module+0x0/0x2ec) from [] (ret_fast_syscall+0x0/0x48) r8:c0015028 r7:00000081 r6:b6fe0032 r5:70616d6f r4:0001a004 Code: e1a00005 eb0d9172 e7f001f2 e7f001f2 (e7f001f2) ---[ end trace 6a30b24d8c0cc2ee ]--- Segmentation fault --->8--- This error was introduced in 67ce04bf2746f8a1f8c2a104b313d20c63f68378 which was the first commit of this driver. Signed-off-by: Andreas Bießmann Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/omap2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index c2b0bba9d8b..618d3475dd8 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1133,7 +1133,7 @@ static int omap_nand_remove(struct platform_device *pdev) /* Release NAND device, its internal structures and partitions */ nand_release(&info->mtd); iounmap(info->nand.IO_ADDR_R); - kfree(&info->mtd); + kfree(info); return 0; } From dbb28ef5cf5318b0abb95712f1cfafaa032796e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Bie=C3=9Fmann?= Date: Fri, 31 Aug 2012 13:35:42 +0200 Subject: [PATCH 1204/2357] mtd: omap2: fix module loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4d3d688da8e7016f15483e9319b41311e1db9515 upstream. Unloading the omap2 nand driver missed to release the memory region which will result in not being able to request it again if one want to load the driver later on. This patch fixes following error when loading omap2 module after unloading: ---8<--- ~ $ rmmod omap2 ~ $ modprobe omap2 [ 37.420928] omap2-nand: probe of omap2-nand.0 failed with error -16 ~ $ --->8--- This error was introduced in 67ce04bf2746f8a1f8c2a104b313d20c63f68378 which was the first commit of this driver. Signed-off-by: Andreas Bießmann Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/omap2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 618d3475dd8..62d039af102 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1133,6 +1133,7 @@ static int omap_nand_remove(struct platform_device *pdev) /* Release NAND device, its internal structures and partitions */ nand_release(&info->mtd); iounmap(info->nand.IO_ADDR_R); + release_mem_region(info->phys_base, NAND_IO_SIZE); kfree(info); return 0; } From 3883e2826411675a47cab6e8e8f49288c4452e34 Mon Sep 17 00:00:00 2001 From: Vaibhav Bedia Date: Thu, 13 Sep 2012 06:31:03 +0000 Subject: [PATCH 1205/2357] mmc: omap_hsmmc: Pass on the suspend failure to the PM core commit c4c8eeb4df00aabb641553d6fbcd46f458e56cd9 upstream. In some cases mmc_suspend_host() is not able to claim the host and proceed with the suspend process. The core returns -EBUSY to the host controller driver. Unfortunately, the host controller driver does not pass on this information to the PM core and hence the system suspend process continues. ret = mmc_suspend_host(host->mmc); if (ret) { host->suspended = 0; if (host->pdata->resume) { ret = host->pdata->resume(dev, host->slot_id); The return status from mmc_suspend_host() is overwritten by return status from host->pdata->resume. So the original return status is lost. In these cases the MMC core gets to an unexpected state during resume and multiple issues related to MMC crop up. 1. Host controller driver starts accessing the device registers before the clocks are enabled which leads to a prefetch abort. 2. A file copy thread which was launched before suspend gets stuck due to the host not being reclaimed during resume. To avoid such problems pass on the -EBUSY status to the PM core from the host controller driver. With this change, MMC core suspend might still fail but it does not end up making the system unusable. Suspend gets aborted and the user can try suspending the system again. Signed-off-by: Vaibhav Bedia Signed-off-by: Hebbar, Gururaja Acked-by: Venkatraman S Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/omap_hsmmc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 71a0c4ea1bc..10253773348 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2097,8 +2097,7 @@ static int omap_hsmmc_suspend(struct device *dev) if (ret) { host->suspended = 0; if (host->pdata->resume) { - ret = host->pdata->resume(dev, host->slot_id); - if (ret) + if (host->pdata->resume(dev, host->slot_id)) dev_dbg(dev, "Unmask interrupt failed\n"); } goto err; From 719740d5deffe22dfdb2bbb06717c1763ebf178e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 18 Sep 2012 06:42:42 +0000 Subject: [PATCH 1206/2357] mmc: sh-mmcif: avoid oops on spurious interrupts commit 8464dd52d3198dd05cafb005371d76e5339eb842 upstream. On some systems, e.g., kzm9g, MMCIF interfaces can produce spurious interrupts without any active request. To prevent the Oops, that results in such cases, don't dereference the mmc request pointer until we make sure, that we are indeed processing such a request. Reported-by: Tetsuyuki Kobayashi Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sh_mmcif.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 724b35e85a2..3b8236bedee 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1191,6 +1191,10 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) host->sd_error = true; dev_dbg(&host->pd->dev, "int err state = %08x\n", state); } + if (host->state == STATE_IDLE) { + dev_info(&host->pd->dev, "Spurious IRQ status 0x%x", state); + return IRQ_HANDLED; + } if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { if (!host->dma_active) return IRQ_WAKE_THREAD; From b9190164feb7046a23029eb00d0bb67f500d03b7 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 31 Aug 2012 15:01:19 -0700 Subject: [PATCH 1207/2357] JFFS2: don't fail on bitflips in OOB commit 74d83beaa229aac7d126ac1ed9414658ff1a89d2 upstream. JFFS2 was designed without thought for OOB bitflips, it seems, but they can occur and will be reported to JFFS2 via mtd_read_oob()[1]. We don't want to fail on these transactions, since the data was corrected. [1] Few drivers report bitflips for OOB-only transactions. With such drivers, this patch should have no effect. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- fs/jffs2/wbuf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 74d9be19df3..6bec5c0bc26 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -1043,10 +1043,10 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c, ops.datbuf = NULL; ret = mtd_read_oob(c->mtd, jeb->offset, &ops); - if (ret || ops.oobretlen != ops.ooblen) { + if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) { pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n", jeb->offset, ops.ooblen, ops.oobretlen, ret); - if (!ret) + if (!ret || mtd_is_bitflip(ret)) ret = -EIO; return ret; } @@ -1085,10 +1085,10 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, ops.datbuf = NULL; ret = mtd_read_oob(c->mtd, jeb->offset, &ops); - if (ret || ops.oobretlen != ops.ooblen) { + if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) { pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n", jeb->offset, ops.ooblen, ops.oobretlen, ret); - if (!ret) + if (!ret || mtd_is_bitflip(ret)) ret = -EIO; return ret; } From 84b7167f1ab14715edb851b17c011d645dbdd312 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 3 Oct 2012 16:02:36 -0400 Subject: [PATCH 1208/2357] cifs: reinstate the forcegid option commit 72bd481f860f0125c810bb43d878ce5f9c060c58 upstream. Apparently this was lost when we converted to the standard option parser in 8830d7e07a5e38bc47650a7554b7c1cfd49902bf Reported-by: Gregory Lee Bartholomew Cc: Sachin Prabhu Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/connect.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 65a78e9a5d4..f771e9f98f9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -70,6 +70,7 @@ enum { /* Mount options that take no arguments */ Opt_user_xattr, Opt_nouser_xattr, Opt_forceuid, Opt_noforceuid, + Opt_forcegid, Opt_noforcegid, Opt_noblocksend, Opt_noautotune, Opt_hard, Opt_soft, Opt_perm, Opt_noperm, Opt_mapchars, Opt_nomapchars, Opt_sfu, @@ -121,6 +122,8 @@ static const match_table_t cifs_mount_option_tokens = { { Opt_nouser_xattr, "nouser_xattr" }, { Opt_forceuid, "forceuid" }, { Opt_noforceuid, "noforceuid" }, + { Opt_forcegid, "forcegid" }, + { Opt_noforcegid, "noforcegid" }, { Opt_noblocksend, "noblocksend" }, { Opt_noautotune, "noautotune" }, { Opt_hard, "hard" }, @@ -1287,6 +1290,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, case Opt_noforceuid: override_uid = 0; break; + case Opt_forcegid: + override_gid = 1; + break; + case Opt_noforcegid: + override_gid = 0; + break; case Opt_noblocksend: vol->noblocksnd = 1; break; From a71d78897ad4b0df7239269f5772bd059a0a2541 Mon Sep 17 00:00:00 2001 From: Frediano Ziglio Date: Tue, 7 Aug 2012 04:33:03 -0500 Subject: [PATCH 1209/2357] Convert properly UTF-8 to UTF-16 commit fd3ba42c76d3d4b776120c2b24c1791e7bb3deb1 upstream. wchar_t is currently 16bit so converting a utf8 encoded characters not in plane 0 (>= 0x10000) to wchar_t (that is calling char2uni) lead to a -EINVAL return. This patch detect utf8 in cifs_strtoUTF16 and add special code calling utf8s_to_utf16s. Signed-off-by: Frediano Ziglio Acked-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifs_unicode.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 33ef60d8e2f..6a8568c6466 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -203,6 +203,27 @@ cifs_strtoUTF16(__le16 *to, const char *from, int len, int i; wchar_t wchar_to; /* needed to quiet sparse */ + /* special case for utf8 to handle no plane0 chars */ + if (!strcmp(codepage->charset, "utf8")) { + /* + * convert utf8 -> utf16, we assume we have enough space + * as caller should have assumed conversion does not overflow + * in destination len is length in wchar_t units (16bits) + */ + i = utf8s_to_utf16s(from, len, UTF16_LITTLE_ENDIAN, + (wchar_t *) to, len); + + /* if success terminate and exit */ + if (i >= 0) + goto success; + /* + * if fails fall back to UCS encoding as this + * function should not return negative values + * currently can fail only if source contains + * invalid encoded characters + */ + } + for (i = 0; len && *from; i++, from += charlen, len -= charlen) { charlen = codepage->char2uni(from, len, &wchar_to); if (charlen < 1) { @@ -215,6 +236,7 @@ cifs_strtoUTF16(__le16 *to, const char *from, int len, put_unaligned_le16(wchar_to, &to[i]); } +success: put_unaligned_le16(0, &to[i]); return i; } From e08ea4c7d4e90aab75307c3c8018d2d4bbeebc0b Mon Sep 17 00:00:00 2001 From: Nikola Pajkovsky Date: Wed, 15 Aug 2012 00:38:08 +0200 Subject: [PATCH 1210/2357] udf: fix retun value on error path in udf_load_logicalvol commit 68766a2edcd5cd744262a70a2f67a320ac944760 upstream. In case we detect a problem and bail out, we fail to set "ret" to a nonzero value, and udf_load_logicalvol will mistakenly report success. Signed-off-by: Nikola Pajkovsky Signed-off-by: Jan Kara Cc: Herton Ronaldo Krzesinski Signed-off-by: Greg Kroah-Hartman --- fs/udf/super.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index e660ffdd91b..4988a8afcc8 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1287,6 +1287,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, udf_err(sb, "error loading logical volume descriptor: " "Partition table too long (%u > %lu)\n", table_len, sb->s_blocksize - sizeof(*lvd)); + ret = 1; goto out_bh; } @@ -1331,8 +1332,10 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) { if (udf_load_sparable_map(sb, map, - (struct sparablePartitionMap *)gpm) < 0) + (struct sparablePartitionMap *)gpm) < 0) { + ret = 1; goto out_bh; + } } else if (!strncmp(upm2->partIdent.ident, UDF_ID_METADATA, strlen(UDF_ID_METADATA))) { From 93875bc33f71bf7a4851b44d387743866b13b130 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Sat, 4 Aug 2012 05:44:14 +0200 Subject: [PATCH 1211/2357] sched: Fix migration thread runtime bogosity commit 8f6189684eb4e85e6c593cd710693f09c944450a upstream. Make stop scheduler class do the same accounting as other classes, Migration threads can be caught in the act while doing exec balancing, leading to the below due to use of unmaintained ->se.exec_start. The load that triggered this particular instance was an apparently out of control heavily threaded application that does system monitoring in what equated to an exec bomb, with one of the VERY frequently migrated tasks being ps. %CPU PID USER CMD 99.3 45 root [migration/10] 97.7 53 root [migration/12] 97.0 57 root [migration/13] 90.1 49 root [migration/11] 89.6 65 root [migration/15] 88.7 17 root [migration/3] 80.4 37 root [migration/8] 78.1 41 root [migration/9] 44.2 13 root [migration/2] Signed-off-by: Mike Galbraith Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1344051854.6739.19.camel@marge.simpson.net Signed-off-by: Thomas Gleixner Cc: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/sched/stop_task.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/kernel/sched/stop_task.c b/kernel/sched/stop_task.c index 7b386e86fd2..da5eb5bed84 100644 --- a/kernel/sched/stop_task.c +++ b/kernel/sched/stop_task.c @@ -27,8 +27,10 @@ static struct task_struct *pick_next_task_stop(struct rq *rq) { struct task_struct *stop = rq->stop; - if (stop && stop->on_rq) + if (stop && stop->on_rq) { + stop->se.exec_start = rq->clock_task; return stop; + } return NULL; } @@ -52,6 +54,21 @@ static void yield_task_stop(struct rq *rq) static void put_prev_task_stop(struct rq *rq, struct task_struct *prev) { + struct task_struct *curr = rq->curr; + u64 delta_exec; + + delta_exec = rq->clock_task - curr->se.exec_start; + if (unlikely((s64)delta_exec < 0)) + delta_exec = 0; + + schedstat_set(curr->se.statistics.exec_max, + max(curr->se.statistics.exec_max, delta_exec)); + + curr->se.sum_exec_runtime += delta_exec; + account_group_exec_runtime(curr, delta_exec); + + curr->se.exec_start = rq->clock_task; + cpuacct_charge(curr, delta_exec); } static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued) @@ -60,6 +77,9 @@ static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued) static void set_curr_task_stop(struct rq *rq) { + struct task_struct *stop = rq->stop; + + stop->se.exec_start = rq->clock_task; } static void switched_to_stop(struct rq *rq, struct task_struct *p) From e3f681ae691bd64d1dc06bab9ad4c98ad4effa82 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 13 Oct 2012 05:44:59 +0900 Subject: [PATCH 1212/2357] Linux 3.4.14 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 75b37ce4f1e..d174c84cc73 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 13 +SUBLEVEL = 14 EXTRAVERSION = NAME = Saber-toothed Squirrel From db0a62c4cce1011c6412648cdd9c8767206befc7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 9 Oct 2012 11:13:26 +0100 Subject: [PATCH 1213/2357] ARM: vfp: fix saving d16-d31 vfp registers on v6+ kernels commit 846a136881b8f73c1f74250bf6acfaa309cab1f2 upstream. Michael Olbrich reported that his test program fails when built with -O2 -mcpu=cortex-a8 -mfpu=neon, and a kernel which supports v6 and v7 CPUs: volatile int x = 2; volatile int64_t y = 2; int main() { volatile int a = 0; volatile int64_t b = 0; while (1) { a = (a + x) % (1 << 30); b = (b + y) % (1 << 30); assert(a == b); } } and two instances are run. When built for just v7 CPUs, this program works fine. It uses the "vadd.i64 d19, d18, d16" VFP instruction. It appears that we do not save the high-16 double VFP registers across context switches when the kernel is built for v6 CPUs. Fix that. Tested-By: Michael Olbrich Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/vfpmacros.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h index 3d5fc41ae8d..bf5304797c7 100644 --- a/arch/arm/include/asm/vfpmacros.h +++ b/arch/arm/include/asm/vfpmacros.h @@ -28,7 +28,7 @@ ldr \tmp, =elf_hwcap @ may not have MVFR regs ldr \tmp, [\tmp, #0] tst \tmp, #HWCAP_VFPv3D16 - ldceq p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} + ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} addne \base, \base, #32*4 @ step over unused register space #else VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 @@ -52,7 +52,7 @@ ldr \tmp, =elf_hwcap @ may not have MVFR regs ldr \tmp, [\tmp, #0] tst \tmp, #HWCAP_VFPv3D16 - stceq p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} + stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} addne \base, \base, #32*4 @ step over unused register space #else VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 From 17170f0bbf4842a5a52dc61cf4d66a824fee9aaf Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 29 Aug 2012 15:21:58 -0700 Subject: [PATCH 1214/2357] nfsd4: fix nfs4 stateid leak commit cf9182e90b2af04245ac4fae497fe73fc71285b4 upstream. Processes that open and close multiple files may end up setting this oo_last_closed_stid without freeing what was previously pointed to. This can result in a major leak, visible for example by watching the nfsd4_stateids line of /proc/slabinfo. Reported-by: Cyril B. Tested-by: Cyril B. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e79c24e232f..a2f99d15584 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3783,6 +3783,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); nfsd4_close_open_stateid(stp); + release_last_closed_stateid(oo); oo->oo_last_closed_stid = stp; /* place unused nfs4_stateowners on so_close_lru list to be From 2bb06038d0dfb47acb64de01a13a7bf963d216f4 Mon Sep 17 00:00:00 2001 From: Malahal Naineni Date: Sun, 9 Sep 2012 10:25:47 -0500 Subject: [PATCH 1215/2357] NFSD: pass null terminated buf to kstrtouint() commit 9959ba0c241a71c7ed8133401cfbbee2720da0b5 upstream. The 'buf' is prepared with null termination with intention of using it for this purpose, but 'name' is passed instead! Signed-off-by: Malahal Naineni Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4idmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 322d11ce06a..01b090d135b 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -581,7 +581,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel /* Just to make sure it's null-terminated: */ memcpy(buf, name, namelen); buf[namelen] = '\0'; - ret = kstrtouint(name, 10, id); + ret = kstrtouint(buf, 10, id); return ret == 0; } From 586046257ea1a0e09a58e2d756e760102a60d6d3 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 18 Sep 2012 13:37:18 +0400 Subject: [PATCH 1216/2357] lockd: use rpc client's cl_nodename for id encoding commit 303a7ce92064c285a04c870f2dc0192fdb2968cb upstream. Taking hostname from uts namespace if not safe, because this cuold be performind during umount operation on child reaper death. And in this case current->nsproxy is NULL already. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/lockd/mon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 7ef14b3c5be..606a8dd8818 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -40,6 +40,7 @@ struct nsm_args { u32 proc; char *mon_name; + char *nodename; }; struct nsm_res { @@ -94,6 +95,7 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, .vers = 3, .proc = NLMPROC_NSM_NOTIFY, .mon_name = nsm->sm_mon_name, + .nodename = utsname()->nodename, }; struct rpc_message msg = { .rpc_argp = &args, @@ -430,7 +432,7 @@ static void encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp) { __be32 *p; - encode_nsm_string(xdr, utsname()->nodename); + encode_nsm_string(xdr, argp->nodename); p = xdr_reserve_space(xdr, 4 + 4 + 4); *p++ = cpu_to_be32(argp->prog); *p++ = cpu_to_be32(argp->vers); From 11a464392c21789b03f08cfd35a3e1b21ae2eaf4 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Fri, 28 Sep 2012 15:22:00 +0800 Subject: [PATCH 1217/2357] ACPI: EC: Make the GPE storm threshold a module parameter commit a520d52e99b14ba7db135e916348f12f2a6e09be upstream. The Linux EC driver includes a mechanism to detect GPE storms, and switch from interrupt-mode to polling mode. However, polling mode sometimes doesn't work, so the workaround is problematic. Also, different systems seem to need the threshold for detecting the GPE storm at different levels. ACPI_EC_STORM_THRESHOLD was initially 20 when it's created, and was changed to 8 in 2.6.28 commit 06cf7d3c7 "ACPI: EC: lower interrupt storm threshold" to fix kernel bug 11892 by forcing the laptop in that bug to work in polling mode. However in bug 45151, it works fine in interrupt mode if we lift the threshold back to 20. This patch makes the threshold a module parameter so that user has a flexible option to debug/workaround this issue. The default is unchanged. This is also a preparation patch to fix specific systems: https://bugzilla.kernel.org/show_bug.cgi?id=45151 Signed-off-by: Feng Tang Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/ec.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7edaccce664..615264c89c3 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -71,9 +71,6 @@ enum ec_command { #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */ -#define ACPI_EC_STORM_THRESHOLD 8 /* number of false interrupts - per one transaction */ - enum { EC_FLAGS_QUERY_PENDING, /* Query is pending */ EC_FLAGS_GPE_STORM, /* GPE storm detected */ @@ -87,6 +84,15 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY; module_param(ec_delay, uint, 0644); MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes"); +/* + * If the number of false interrupts per one transaction exceeds + * this threshold, will think there is a GPE storm happened and + * will disable the GPE for normal transaction. + */ +static unsigned int ec_storm_threshold __read_mostly = 8; +module_param(ec_storm_threshold, uint, 0644); +MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm"); + /* If we find an EC via the ECDT, we need to keep a ptr to its context */ /* External interfaces use first EC only, so remember */ typedef int (*acpi_ec_query_func) (void *data); @@ -319,7 +325,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) msleep(1); /* It is safe to enable the GPE outside of the transaction. */ acpi_enable_gpe(NULL, ec->gpe); - } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { + } else if (t->irq_count > ec_storm_threshold) { pr_info(PREFIX "GPE storm detected, " "transactions will use polling mode\n"); set_bit(EC_FLAGS_GPE_STORM, &ec->flags); From b9d5c7a86da8517506a2a8f3f9ee2ce94ffbd3e2 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Fri, 28 Sep 2012 15:22:01 +0800 Subject: [PATCH 1218/2357] ACPI: EC: Add a quirk for CLEVO M720T/M730T laptop commit 67bfa9b60bd689601554526d144b21d529f78a09 upstream. By enlarging the GPE storm threshold back to 20, that laptop's EC works fine with interrupt mode instead of polling mode. https://bugzilla.kernel.org/show_bug.cgi?id=45151 Reported-and-Tested-by: Francesco Signed-off-by: Feng Tang Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/ec.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 615264c89c3..a51df968131 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -930,6 +930,17 @@ static int ec_flag_msi(const struct dmi_system_id *id) return 0; } +/* + * Clevo M720 notebook actually works ok with IRQ mode, if we lifted + * the GPE storm threshold back to 20 + */ +static int ec_enlarge_storm_threshold(const struct dmi_system_id *id) +{ + pr_debug("Setting the EC GPE storm threshold to 20\n"); + ec_storm_threshold = 20; + return 0; +} + static struct dmi_system_id __initdata ec_dmi_table[] = { { ec_skip_dsdt_scan, "Compal JFL92", { @@ -961,10 +972,13 @@ static struct dmi_system_id __initdata ec_dmi_table[] = { { ec_validate_ecdt, "ASUS hardware", { DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc.") }, NULL}, + { + ec_enlarge_storm_threshold, "CLEVO hardware", { + DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."), + DMI_MATCH(DMI_PRODUCT_NAME, "M720T/M730T"),}, NULL}, {}, }; - int __init acpi_ec_ecdt_probe(void) { acpi_status status; From ccb6ce1dde608e368df136e7776a1d992b8c3001 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 10 Oct 2012 16:32:09 +0200 Subject: [PATCH 1219/2357] ALSA: hda - do not detect jack on internal speakers for Realtek commit f7f4b2322bf7b8c5929b7eb5a667091f32592580 upstream. This caused the internal speaker to mute itself because it was present, which happened after powersave. It was found on Dell XPS 15 (L502x), ALC665. Reported-by: Da Fox Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e7cb4bd25d2..94747f8a249 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -602,6 +602,8 @@ static void alc_line_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) + return; /* check LO jack only when it's different from HP */ if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) return; From 531db9f3addc4664300aa14af6130f160150970f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Oct 2012 08:50:35 +0200 Subject: [PATCH 1220/2357] ALSA: hda - Fix memory leaks at error path in patch_cirrus.c commit c5e0b6dbad9b4d18c561af90b384d02373f1c994 upstream. The proper destructor should be called at the error path. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_cirrus.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index c83ccdba1e5..2bc6c51f58e 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1427,7 +1427,7 @@ static int patch_cs420x(struct hda_codec *codec) return 0; error: - kfree(codec->spec); + cs_free(codec); codec->spec = NULL; return err; } @@ -1984,7 +1984,7 @@ static int patch_cs4210(struct hda_codec *codec) return 0; error: - kfree(codec->spec); + cs_free(codec); codec->spec = NULL; return err; } @@ -2009,7 +2009,7 @@ static int patch_cs4213(struct hda_codec *codec) return 0; error: - kfree(codec->spec); + cs_free(codec); codec->spec = NULL; return err; } From fb2ca533f518dabf814c6aab3b7ce3c236959a68 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Fri, 10 Aug 2012 12:21:15 -0500 Subject: [PATCH 1221/2357] mips,kgdb: fix recursive page fault with CONFIG_KPROBES commit f0a996eeeda214f4293e234df33b29bec003b536 upstream. This fault was detected using the kgdb test suite on boot and it crashes recursively due to the fact that CONFIG_KPROBES on mips adds an extra die notifier in the page fault handler. The crash signature looks like this: kgdbts:RUN bad memory access test KGDB: re-enter exception: ALL breakpoints killed Call Trace: [<807b7548>] dump_stack+0x20/0x54 [<807b7548>] dump_stack+0x20/0x54 The fix for now is to have kgdb return immediately if the fault type is DIE_PAGE_FAULT and allow the kprobe code to decide what is supposed to happen. Signed-off-by: Jason Wessel Cc: Masami Hiramatsu Cc: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/kgdb.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index f4546e97c60..23817a6e32b 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c @@ -283,6 +283,15 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd, struct pt_regs *regs = args->regs; int trap = (regs->cp0_cause & 0x7c) >> 2; +#ifdef CONFIG_KPROBES + /* + * Return immediately if the kprobes fault notifier has set + * DIE_PAGE_FAULT. + */ + if (cmd == DIE_PAGE_FAULT) + return NOTIFY_DONE; +#endif /* CONFIG_KPROBES */ + /* Userspace events, ignore. */ if (user_mode(regs)) return NOTIFY_DONE; From 530258fceacd8c17075906c648c1ba20928c940b Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Sun, 7 Oct 2012 20:32:51 -0700 Subject: [PATCH 1222/2357] tmpfs,ceph,gfs2,isofs,reiserfs,xfs: fix fh_len checking commit 35c2a7f4908d404c9124c2efc6ada4640ca4d5d5 upstream. Fuzzing with trinity oopsed on the 1st instruction of shmem_fh_to_dentry(), u64 inum = fid->raw[2]; which is unhelpfully reported as at the end of shmem_alloc_inode(): BUG: unable to handle kernel paging request at ffff880061cd3000 IP: [] shmem_alloc_inode+0x40/0x40 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Call Trace: [] ? exportfs_decode_fh+0x79/0x2d0 [] do_handle_open+0x163/0x2c0 [] sys_open_by_handle_at+0xc/0x10 [] tracesys+0xe1/0xe6 Right, tmpfs is being stupid to access fid->raw[2] before validating that fh_len includes it: the buffer kmalloc'ed by do_sys_name_to_handle() may fall at the end of a page, and the next page not be present. But some other filesystems (ceph, gfs2, isofs, reiserfs, xfs) are being careless about fh_len too, in fh_to_dentry() and/or fh_to_parent(), and could oops in the same way: add the missing fh_len checks to those. Reported-by: Sasha Levin Signed-off-by: Hugh Dickins Cc: Al Viro Cc: Sage Weil Cc: Steven Whitehouse Cc: Christoph Hellwig Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/ceph/export.c | 18 ++++++++++++++---- fs/gfs2/export.c | 4 ++++ fs/isofs/export.c | 2 +- fs/reiserfs/inode.c | 6 +++++- fs/xfs/xfs_export.c | 3 +++ mm/shmem.c | 6 ++++-- 6 files changed, 31 insertions(+), 8 deletions(-) diff --git a/fs/ceph/export.c b/fs/ceph/export.c index fbb2a643ef1..4098ccf8cb9 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -89,7 +89,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len, * FIXME: we should try harder by querying the mds for the ino. */ static struct dentry *__fh_to_dentry(struct super_block *sb, - struct ceph_nfs_fh *fh) + struct ceph_nfs_fh *fh, int fh_len) { struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc; struct inode *inode; @@ -97,6 +97,9 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, struct ceph_vino vino; int err; + if (fh_len < sizeof(*fh) / 4) + return ERR_PTR(-ESTALE); + dout("__fh_to_dentry %llx\n", fh->ino); vino.ino = fh->ino; vino.snap = CEPH_NOSNAP; @@ -140,7 +143,7 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, * convert connectable fh to dentry */ static struct dentry *__cfh_to_dentry(struct super_block *sb, - struct ceph_nfs_confh *cfh) + struct ceph_nfs_confh *cfh, int fh_len) { struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc; struct inode *inode; @@ -148,6 +151,9 @@ static struct dentry *__cfh_to_dentry(struct super_block *sb, struct ceph_vino vino; int err; + if (fh_len < sizeof(*cfh) / 4) + return ERR_PTR(-ESTALE); + dout("__cfh_to_dentry %llx (%llx/%x)\n", cfh->ino, cfh->parent_ino, cfh->parent_name_hash); @@ -197,9 +203,11 @@ static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { if (fh_type == 1) - return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw); + return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw, + fh_len); else - return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw); + return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw, + fh_len); } /* @@ -220,6 +228,8 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb, if (fh_type == 1) return ERR_PTR(-ESTALE); + if (fh_len < sizeof(*cfh) / 4) + return ERR_PTR(-ESTALE); pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino, cfh->parent_name_hash); diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index 70ba891654f..fdef7f0e28a 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -168,6 +168,8 @@ static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid, case GFS2_SMALL_FH_SIZE: case GFS2_LARGE_FH_SIZE: case GFS2_OLD_FH_SIZE: + if (fh_len < GFS2_SMALL_FH_SIZE) + return NULL; this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32; this.no_formal_ino |= be32_to_cpu(fh[1]); this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32; @@ -187,6 +189,8 @@ static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid, switch (fh_type) { case GFS2_LARGE_FH_SIZE: case GFS2_OLD_FH_SIZE: + if (fh_len < GFS2_LARGE_FH_SIZE) + return NULL; parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32; parent.no_formal_ino |= be32_to_cpu(fh[5]); parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32; diff --git a/fs/isofs/export.c b/fs/isofs/export.c index dd4687ff30d..516eb21895c 100644 --- a/fs/isofs/export.c +++ b/fs/isofs/export.c @@ -179,7 +179,7 @@ static struct dentry *isofs_fh_to_parent(struct super_block *sb, { struct isofs_fid *ifid = (struct isofs_fid *)fid; - if (fh_type != 2) + if (fh_len < 2 || fh_type != 2) return NULL; return isofs_export_iget(sb, diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 494c315c741..f99c1b4fa5f 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1573,8 +1573,10 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid, reiserfs_warning(sb, "reiserfs-13077", "nfsd/reiserfs, fhtype=%d, len=%d - odd", fh_type, fh_len); - fh_type = 5; + fh_type = fh_len; } + if (fh_len < 2) + return NULL; return reiserfs_get_dentry(sb, fid->raw[0], fid->raw[1], (fh_type == 3 || fh_type >= 5) ? fid->raw[2] : 0); @@ -1583,6 +1585,8 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid, struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { + if (fh_type > fh_len) + fh_type = fh_len; if (fh_type < 4) return NULL; diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c index 558910f5e3c..5703fb85f6b 100644 --- a/fs/xfs/xfs_export.c +++ b/fs/xfs/xfs_export.c @@ -195,6 +195,9 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid, struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid; struct inode *inode = NULL; + if (fh_len < xfs_fileid_length(fileid_type)) + return NULL; + switch (fileid_type) { case FILEID_INO32_GEN_PARENT: inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino, diff --git a/mm/shmem.c b/mm/shmem.c index 9d65a02a879..40383cddc91 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2018,12 +2018,14 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb, { struct inode *inode; struct dentry *dentry = NULL; - u64 inum = fid->raw[2]; - inum = (inum << 32) | fid->raw[1]; + u64 inum; if (fh_len < 3) return NULL; + inum = fid->raw[2]; + inum = (inum << 32) | fid->raw[1]; + inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]), shmem_match, fid->raw); if (inode) { From 8892290fcc4476db20bbe591d9c0d401096d6275 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 1 May 2012 11:43:42 -0500 Subject: [PATCH 1223/2357] SCSI: hpsa: dial down lockup detection during firmware flash commit e85c59746957fd6e3595d02cf614370056b5816e upstream. Dial back the aggressiveness of the controller lockup detection thread. Currently it will declare the controller to be locked up if it goes for 10 seconds with no interrupts and no change in the heartbeat register. Dial back this to 30 seconds with no heartbeat change, and also snoop the ioctl path and if a firmware flash command is detected, dial it back further to 4 minutes until the firmware flash command completes. The reason for this is that during the firmware flash operation, the controller apparently doesn't update the heartbeat register as frequently as it is supposed to, and we can get a false positive. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/hpsa.c | 39 ++++++++++++++++++++++++++++++++++----- drivers/scsi/hpsa.h | 2 ++ drivers/scsi/hpsa_cmd.h | 1 + 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8a5e25d2f21..b0fefc435c0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -548,12 +548,42 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c) c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); } +static int is_firmware_flash_cmd(u8 *cdb) +{ + return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE; +} + +/* + * During firmware flash, the heartbeat register may not update as frequently + * as it should. So we dial down lockup detection during firmware flash. and + * dial it back up when firmware flash completes. + */ +#define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ) +#define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ) +static void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h, + struct CommandList *c) +{ + if (!is_firmware_flash_cmd(c->Request.CDB)) + return; + atomic_inc(&h->firmware_flash_in_progress); + h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH; +} + +static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, + struct CommandList *c) +{ + if (is_firmware_flash_cmd(c->Request.CDB) && + atomic_dec_and_test(&h->firmware_flash_in_progress)) + h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; +} + static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { unsigned long flags; set_performant_mode(h, c); + dial_down_lockup_detection_during_fw_flash(h, c); spin_lock_irqsave(&h->lock, flags); addQ(&h->reqQ, c); h->Qdepth++; @@ -3049,6 +3079,7 @@ static inline int bad_tag(struct ctlr_info *h, u32 tag_index, static inline void finish_cmd(struct CommandList *c, u32 raw_tag) { removeQ(c); + dial_up_lockup_detection_on_fw_flash_complete(c->h, c); if (likely(c->cmd_type == CMD_SCSI)) complete_scsi_command(c); else if (c->cmd_type == CMD_IOCTL_PEND) @@ -4189,9 +4220,6 @@ static void controller_lockup_detected(struct ctlr_info *h) spin_unlock_irqrestore(&h->lock, flags); } -#define HEARTBEAT_SAMPLE_INTERVAL (10 * HZ) -#define HEARTBEAT_CHECK_MINIMUM_INTERVAL (HEARTBEAT_SAMPLE_INTERVAL / 2) - static void detect_controller_lockup(struct ctlr_info *h) { u64 now; @@ -4202,7 +4230,7 @@ static void detect_controller_lockup(struct ctlr_info *h) now = get_jiffies_64(); /* If we've received an interrupt recently, we're ok. */ if (time_after64(h->last_intr_timestamp + - (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now)) + (h->heartbeat_sample_interval), now)) return; /* @@ -4211,7 +4239,7 @@ static void detect_controller_lockup(struct ctlr_info *h) * otherwise don't care about signals in this thread. */ if (time_after64(h->last_heartbeat_timestamp + - (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now)) + (h->heartbeat_sample_interval), now)) return; /* If heartbeat has not changed since we last looked, we're not ok. */ @@ -4253,6 +4281,7 @@ static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h) { unsigned long flags; + h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; spin_lock_irqsave(&lockup_detector_lock, flags); list_add_tail(&h->lockup_list, &hpsa_ctlr_list); spin_unlock_irqrestore(&lockup_detector_lock, flags); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 7b28d54fa87..6f30a6f477c 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -123,6 +123,8 @@ struct ctlr_info { u64 last_intr_timestamp; u32 last_heartbeat; u64 last_heartbeat_timestamp; + u32 heartbeat_sample_interval; + atomic_t firmware_flash_in_progress; u32 lockup_detected; struct list_head lockup_list; }; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 8049815d8c1..cdd742e4406 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -162,6 +162,7 @@ struct SenseSubsystem_info { #define BMIC_WRITE 0x27 #define BMIC_CACHE_FLUSH 0xc2 #define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */ +#define BMIC_FLASH_FIRMWARE 0xF7 /* Command List Structure */ union SCSI3Addr { From 1faef9285ad868082403da1cec5adefc0c505c2e Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 22 Sep 2012 17:21:06 -0700 Subject: [PATCH 1224/2357] iscsi-target: Correctly set 0xffffffff field within ISCSI_OP_REJECT PDU commit f25590f39d543272f7ae7b00d533359c8d7ff331 upstream. This patch adds a missing iscsi_reject->ffffffff assignment within iscsit_send_reject() code to properly follow RFC-3720 Section 10.17 Bytes 16 -> 19 for the PDU format definition of ISCSI_OP_REJECT. We've not seen any initiators care about this bytes in practice, but as Ronnie reported this was causing trouble with wireshark packet decoding lets go ahead and fix this up now. Reported-by: Ronnie Sahlberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/iscsi/iscsi_target.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index e326d17e05a..20572be9414 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -3349,6 +3349,7 @@ static int iscsit_send_reject( hdr->opcode = ISCSI_OP_REJECT; hdr->flags |= ISCSI_FLAG_CMD_FINAL; hton24(hdr->dlength, ISCSI_HDR_LEN); + hdr->ffffffff = 0xffffffff; cmd->stat_sn = conn->stat_sn++; hdr->statsn = cpu_to_be32(cmd->stat_sn); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); From b095d61243b5f2333e2ae11a9051cd9d47597002 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 26 Sep 2012 08:00:37 -0400 Subject: [PATCH 1225/2357] iscsit: remove incorrect unlock in iscsit_build_sendtargets_resp commit 904753da183566c71211d23c169a80184648c121 upstream. Fix a potential multiple spin-unlock -> deadlock scenario during the overflow check within iscsit_build_sendtargets_resp() as found by sparse static checking. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/iscsi/iscsi_target.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 20572be9414..23e122a5daf 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -3196,7 +3196,6 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) len += 1; if ((len + payload_len) > buffer_len) { - spin_unlock(&tiqn->tiqn_tpg_lock); end_of_buf = 1; goto eob; } From a114a8b43b038c327aff0298cfb69509469e84b4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 30 Sep 2012 12:20:02 -0700 Subject: [PATCH 1226/2357] iscsi-target: Add explicit set of cache_dynamic_acls=1 for TPG demo-mode commit 38b11bae6ba02da352340aff12ee25755977b222 upstream. We've had reports in the past about this specific case, so it's time to go ahead and explicitly set cache_dynamic_acls=1 for generate_node_acls=1 (TPG demo-mode) operation. During normal generate_node_acls=0 operation with explicit NodeACLs -> se_node_acl memory is persistent to the configfs group located at /sys/kernel/config/target/$TARGETNAME/$TPGT/acls/$INITIATORNAME, so in the generate_node_acls=1 case we want the reservation logic to reference existing per initiator IQN se_node_acl memory (not to generate a new se_node_acl), so go ahead and always set cache_dynamic_acls=1 when TPG demo-mode is enabled. Reported-by: Ronnie Sahlberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/iscsi/iscsi_target_tpg.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 879d8d0fa3f..c3d7bf54f3d 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -672,6 +672,12 @@ int iscsit_ta_generate_node_acls( pr_debug("iSCSI_TPG[%hu] - Generate Initiator Portal Group ACLs: %s\n", tpg->tpgt, (a->generate_node_acls) ? "Enabled" : "Disabled"); + if (flag == 1 && a->cache_dynamic_acls == 0) { + pr_debug("Explicitly setting cache_dynamic_acls=1 when " + "generate_node_acls=1\n"); + a->cache_dynamic_acls = 1; + } + return 0; } @@ -711,6 +717,12 @@ int iscsit_ta_cache_dynamic_acls( return -EINVAL; } + if (a->generate_node_acls == 1 && flag == 0) { + pr_debug("Skipping cache_dynamic_acls=0 when" + " generate_node_acls=1\n"); + return 0; + } + a->cache_dynamic_acls = flag; pr_debug("iSCSI_TPG[%hu] - Cache Dynamic Initiator Portal Group" " ACLs %s\n", tpg->tpgt, (a->cache_dynamic_acls) ? From 2a7c11208e542071eee2240dde98e1673f5c01d4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 3 Oct 2012 15:42:48 -0700 Subject: [PATCH 1227/2357] iscsi-target: Bump defaults for nopin_timeout + nopin_response_timeout values commit cf0eb28d3ba60098865bf7dbcbfdd6b1cc483e3b upstream. This patch increases the default for nopin_timeout to 15 seconds (wait between sending a new NopIN ping) and nopin_response_timeout to 30 seconds (wait for NopOUT response before failing the connection) in order to avoid false positives by iSCSI Initiators who are not always able (under load) to respond to NopIN echo PING requests within the current 5 second window. False positives have been observed recently using Open-iSCSI code on v3.3.x with heavy large-block READ workloads over small MTU 1 Gb/sec ports, and increasing these values to more reasonable defaults significantly reduces the possibility of false positive NopIN response timeout events under this specific workload. Historically these have been set low to initiate connection recovery as soon as possible if we don't hear a ping back, but for modern v3.x code on 1 -> 10 Gb/sec ports these new defaults make alot more sense. Signed-off-by: Nicholas Bellinger Cc: Christoph Hellwig Cc: Andy Grover Cc: Mike Christie Cc: Hannes Reinecke Signed-off-by: Greg Kroah-Hartman --- drivers/target/iscsi/iscsi_target_core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index d1c4bc22cca..1596aec0c3d 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -25,10 +25,10 @@ #define NA_DATAOUT_TIMEOUT_RETRIES 5 #define NA_DATAOUT_TIMEOUT_RETRIES_MAX 15 #define NA_DATAOUT_TIMEOUT_RETRIES_MIN 1 -#define NA_NOPIN_TIMEOUT 5 +#define NA_NOPIN_TIMEOUT 15 #define NA_NOPIN_TIMEOUT_MAX 60 #define NA_NOPIN_TIMEOUT_MIN 3 -#define NA_NOPIN_RESPONSE_TIMEOUT 5 +#define NA_NOPIN_RESPONSE_TIMEOUT 30 #define NA_NOPIN_RESPONSE_TIMEOUT_MAX 60 #define NA_NOPIN_RESPONSE_TIMEOUT_MIN 3 #define NA_RANDOM_DATAIN_PDU_OFFSETS 0 From 791f153c5bea0636537ceb417bfea78f0f232d4f Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 2 Oct 2012 11:03:31 -0700 Subject: [PATCH 1228/2357] SCSI: storvsc: Account for in-transit packets in the RESET path commit 5c1b10ab7f93d24f29b5630286e323d1c5802d5c upstream. Properly account for I/O in transit before returning from the RESET call. In the absense of this patch, we could have a situation where the host may respond to a command that was issued prior to the issuance of the RESET command at some arbitrary time after responding to the RESET command. Currently, the host does not do anything with the RESET command. Signed-off-by: K. Y. Srinivasan Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/storvsc_drv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 83a1972a199..40a45700c8d 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1211,7 +1211,12 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) /* * At this point, all outstanding requests in the adapter * should have been flushed out and return to us + * There is a potential race here where the host may be in + * the process of responding when we return from here. + * Just wait for all in-transit packets to be accounted for + * before we return from here. */ + storvsc_wait_to_drain(stor_device); return SUCCESS; } From 023f18fee60cd9ef86c8299dd9debccad1f93351 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Thu, 16 Aug 2012 16:38:45 +0200 Subject: [PATCH 1229/2357] SCSI: scsi_debug: Fix off-by-one bug when unmapping region commit bc977749e967daa56de1922cf4cb38525631c51c upstream. Currently it is possible to unmap one more block than user requested to due to the off-by-one error in unmap_region(). This is probably due to the fact that the end variable despite its name actually points to the last block to unmap + 1. However in the condition it is handled as the last block of the region to unmap. The bug was not previously spotted probably due to the fact that the region was not zeroed, which has changed with commit be1dd78de5686c062bb3103f9e86d444a10ed783. With that commit we were able to corrupt the ext4 file system on 256M scsi_debug device with LBPRZ enabled using fstrim. Since the 'end' semantic is the same in several functions there this commit just fixes the condition to use the 'end' variable correctly in that context. Reported-by: Paolo Bonzini Signed-off-by: Lukas Czerner Reviewed-by: Martin K. Petersen Acked-by: Douglas Gilbert Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 182d5a57ab7..f4cc4139ada 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -2054,7 +2054,7 @@ static void unmap_region(sector_t lba, unsigned int len) block = lba + alignment; rem = do_div(block, granularity); - if (rem == 0 && lba + granularity <= end && block < map_size) { + if (rem == 0 && lba + granularity < end && block < map_size) { clear_bit(block, map_storep); if (scsi_debug_lbprz) memset(fake_storep + From 90e4ed1b7de612e4ed18029e61134ab2fea6233e Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 28 Sep 2012 02:12:45 +0100 Subject: [PATCH 1230/2357] ARM: 7541/1: Add ARM ERRATA 775420 workaround commit 7253b85cc62d6ff84143d96fe6cd54f73736f4d7 upstream. arm: Add ARM ERRATA 775420 workaround Workaround for the 775420 Cortex-A9 (r2p2, r2p6,r2p8,r2p10,r3p0) erratum. In case a date cache maintenance operation aborts with MMU exception, it might cause the processor to deadlock. This workaround puts DSB before executing ISB if an abort may occur on cache maintenance. Based on work by Kouei Abe and feedback from Catalin Marinas. Signed-off-by: Kouei Abe [ horms@verge.net.au: Changed to implementation suggested by catalin.marinas@arm.com ] Acked-by: Catalin Marinas Signed-off-by: Simon Horman Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/Kconfig | 10 ++++++++++ arch/arm/mm/cache-v7.S | 3 +++ 2 files changed, 13 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 352322a6765..e14ae114142 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1405,6 +1405,16 @@ config PL310_ERRATA_769419 on systems with an outer cache, the store buffer is drained explicitly. +config ARM_ERRATA_775420 + bool "ARM errata: A data cache maintenance operation which aborts, might lead to deadlock" + depends on CPU_V7 + help + This option enables the workaround for the 775420 Cortex-A9 (r2p2, + r2p6,r2p8,r2p10,r3p0) erratum. In case a date cache maintenance + operation aborts with MMU exception, it might cause the processor + to deadlock. This workaround puts DSB before executing ISB if + an abort may occur on cache maintenance. + endmenu source "arch/arm/common/Kconfig" diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index a655d3da386..82ab2c5b4ac 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -211,6 +211,9 @@ ENTRY(v7_coherent_user_range) * isn't mapped, just try the next page. */ 9001: +#ifdef CONFIG_ARM_ERRATA_775420 + dsb +#endif mov r12, r12, lsr #12 mov r12, r12, lsl #12 add r12, r12, #4096 From 0bd1ed9ead1a2b7fc1534bff04729c3712a6fb25 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 6 Oct 2012 14:12:56 +0200 Subject: [PATCH 1231/2357] firewire: cdev: fix user memory corruption (i386 userland on amd64 kernel) commit 790198f74c9d1b46b6a89504361b1a844670d050 upstream. Fix two bugs of the /dev/fw* character device concerning the FW_CDEV_IOC_GET_INFO ioctl with nonzero fw_cdev_get_info.bus_reset. (Practically all /dev/fw* clients issue this ioctl right after opening the device.) Both bugs are caused by sizeof(struct fw_cdev_event_bus_reset) being 36 without natural alignment and 40 with natural alignment. 1) Memory corruption, affecting i386 userland on amd64 kernel: Userland reserves a 36 bytes large buffer, kernel writes 40 bytes. This has been first found and reported against libraw1394 if compiled with gcc 4.7 which happens to order libraw1394's stack such that the bug became visible as data corruption. 2) Information leak, affecting all kernel architectures except i386: 4 bytes of random kernel stack data were leaked to userspace. Hence limit the respective copy_to_user() to the 32-bit aligned size of struct fw_cdev_event_bus_reset. Reported-by: Simon Kirby Signed-off-by: Stefan Richter Signed-off-by: Greg Kroah-Hartman --- drivers/firewire/core-cdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 2e6b24547e2..b8e4809cae0 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -471,8 +471,8 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg) client->bus_reset_closure = a->bus_reset_closure; if (a->bus_reset != 0) { fill_bus_reset_event(&bus_reset, client); - ret = copy_to_user(u64_to_uptr(a->bus_reset), - &bus_reset, sizeof(bus_reset)); + /* unaligned size of bus_reset is 36 bytes */ + ret = copy_to_user(u64_to_uptr(a->bus_reset), &bus_reset, 36); } if (ret == 0 && list_empty(&client->link)) list_add_tail(&client->link, &client->device->client_list); From b77a7a0e9f3ed51b523857f26c42e350faf43add Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 12 Sep 2012 16:49:15 -0400 Subject: [PATCH 1232/2357] SUNRPC: Ensure that the TCP socket is closed when in CLOSE_WAIT commit a519fc7a70d1a918574bb826cc6905b87b482eb9 upstream. Instead of doing a shutdown() call, we need to do an actual close(). Ditto if/when the server is sending us junk RPC headers. Signed-off-by: Trond Myklebust Tested-by: Simon Kirby Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtsock.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index b88c6bf657b..00ff34343ba 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1028,6 +1028,16 @@ static void xs_udp_data_ready(struct sock *sk, int len) read_unlock_bh(&sk->sk_callback_lock); } +/* + * Helper function to force a TCP close if the server is sending + * junk and/or it has put us in CLOSE_WAIT + */ +static void xs_tcp_force_close(struct rpc_xprt *xprt) +{ + set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); + xprt_force_disconnect(xprt); +} + static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); @@ -1054,7 +1064,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea /* Sanity check of the record length */ if (unlikely(transport->tcp_reclen < 8)) { dprintk("RPC: invalid TCP record fragment length\n"); - xprt_force_disconnect(xprt); + xs_tcp_force_close(xprt); return; } dprintk("RPC: reading TCP record fragment of length %d\n", @@ -1135,7 +1145,7 @@ static inline void xs_tcp_read_calldir(struct sock_xprt *transport, break; default: dprintk("RPC: invalid request message type\n"); - xprt_force_disconnect(&transport->xprt); + xs_tcp_force_close(&transport->xprt); } xs_tcp_check_fraghdr(transport); } @@ -1458,6 +1468,8 @@ static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt) static void xs_sock_mark_closed(struct rpc_xprt *xprt) { smp_mb__before_clear_bit(); + clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); + clear_bit(XPRT_CONNECTION_CLOSE, &xprt->state); clear_bit(XPRT_CLOSE_WAIT, &xprt->state); clear_bit(XPRT_CLOSING, &xprt->state); smp_mb__after_clear_bit(); @@ -1515,8 +1527,8 @@ static void xs_tcp_state_change(struct sock *sk) break; case TCP_CLOSE_WAIT: /* The server initiated a shutdown of the socket */ - xprt_force_disconnect(xprt); xprt->connect_cookie++; + xs_tcp_force_close(xprt); case TCP_CLOSING: /* * If the server closed down the connection, make sure that @@ -2159,8 +2171,7 @@ static void xs_tcp_setup_socket(struct work_struct *work) /* We're probably in TIME_WAIT. Get rid of existing socket, * and retry */ - set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); - xprt_force_disconnect(xprt); + xs_tcp_force_close(xprt); break; case -ECONNREFUSED: case -ECONNRESET: From e1621ec4754097582c73c0ed8c394dcc50b1e0fd Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Mon, 17 Sep 2012 20:05:33 +0200 Subject: [PATCH 1233/2357] target: fix return code in target_core_init_configfs error path commit 37bb7899ca366dc212b71b150e78566d04808cc0 upstream. This patch fixes error cases within target_core_init_configfs() to properly set ret = -ENOMEM before jumping to the out_global exception path. This was originally discovered with the following Coccinelle semantic match information: Convert a nonnegative error return code to a negative one, as returned elsewhere in the function. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // ( if@p1 (\(ret < 0\|ret != 0\)) { ... return ret; } | ret@p1 = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Peter Senna Tschudin Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_configfs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index cbb66537d23..3f90d4b03e6 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3115,6 +3115,7 @@ static int __init target_core_init_configfs(void) GFP_KERNEL); if (!target_cg->default_groups) { pr_err("Unable to allocate target_cg->default_groups\n"); + ret = -ENOMEM; goto out_global; } @@ -3130,6 +3131,7 @@ static int __init target_core_init_configfs(void) GFP_KERNEL); if (!hba_cg->default_groups) { pr_err("Unable to allocate hba_cg->default_groups\n"); + ret = -ENOMEM; goto out_global; } config_group_init_type_name(&alua_group, @@ -3145,6 +3147,7 @@ static int __init target_core_init_configfs(void) GFP_KERNEL); if (!alua_cg->default_groups) { pr_err("Unable to allocate alua_cg->default_groups\n"); + ret = -ENOMEM; goto out_global; } @@ -3156,14 +3159,17 @@ static int __init target_core_init_configfs(void) * Add core/alua/lu_gps/default_lu_gp */ lu_gp = core_alua_allocate_lu_gp("default_lu_gp", 1); - if (IS_ERR(lu_gp)) + if (IS_ERR(lu_gp)) { + ret = -ENOMEM; goto out_global; + } lu_gp_cg = &alua_lu_gps_group; lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, GFP_KERNEL); if (!lu_gp_cg->default_groups) { pr_err("Unable to allocate lu_gp_cg->default_groups\n"); + ret = -ENOMEM; goto out_global; } From c525d8ee0c7701d72d8144f536d47a5bd30159e9 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 10 Oct 2012 13:25:48 -0400 Subject: [PATCH 1234/2357] xen/bootup: allow {read|write}_cr8 pvops call. commit 1a7bbda5b1ab0e02622761305a32dc38735b90b2 upstream. We actually do not do anything about it. Just return a default value of zero and if the kernel tries to write anything but 0 we BUG_ON. This fixes the case when an user tries to suspend the machine and it blows up in save_processor_state b/c 'read_cr8' is set to NULL and we get: kernel BUG at /home/konrad/ssd/linux/arch/x86/include/asm/paravirt.h:100! invalid opcode: 0000 [#1] SMP Pid: 2687, comm: init.late Tainted: G O 3.6.0upstream-00002-gac264ac-dirty #4 Bochs Bochs RIP: e030:[] [] save_processor_state+0x212/0x270 .. snip.. Call Trace: [] do_suspend_lowlevel+0xf/0xac [] ? x86_acpi_suspend_lowlevel+0x10c/0x150 [] acpi_suspend_enter+0x57/0xd5 Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/enlighten.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 40edfc37a6f..5fa38a80000 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -942,7 +942,16 @@ static void xen_write_cr4(unsigned long cr4) native_write_cr4(cr4); } - +#ifdef CONFIG_X86_64 +static inline unsigned long xen_read_cr8(void) +{ + return 0; +} +static inline void xen_write_cr8(unsigned long val) +{ + BUG_ON(val); +} +#endif static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) { int ret; @@ -1111,6 +1120,11 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .read_cr4_safe = native_read_cr4_safe, .write_cr4 = xen_write_cr4, +#ifdef CONFIG_X86_64 + .read_cr8 = xen_read_cr8, + .write_cr8 = xen_write_cr8, +#endif + .wbinvd = native_wbinvd, .read_msr = native_read_msr_safe, From e299f8abb241b52fe0de458143a537ac91b269a2 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 10 Oct 2012 13:30:47 -0400 Subject: [PATCH 1235/2357] xen/bootup: allow read_tscp call for Xen PV guests. commit cd0608e71e9757f4dae35bcfb4e88f4d1a03a8ab upstream. The hypervisor will trap it. However without this patch, we would crash as the .read_tscp is set to NULL. This patch fixes it and sets it to the native_read_tscp call. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/enlighten.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 5fa38a80000..59100548cbd 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1135,6 +1135,8 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, + .read_tscp = native_read_tscp, + .iret = xen_iret, .irq_enable_sysexit = xen_sysexit, #ifdef CONFIG_X86_64 From 7fce34e1a40c49a2f579ffd1342884cf8bca8e96 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2012 14:09:30 -0700 Subject: [PATCH 1236/2357] block: fix request_queue->flags initialization commit 60ea8226cbd5c8301f9a39edc574ddabcb8150e0 upstream. A queue newly allocated with blk_alloc_queue_node() has only QUEUE_FLAG_BYPASS set. For request-based drivers, blk_init_allocated_queue() is called and q->queue_flags is overwritten with QUEUE_FLAG_DEFAULT which doesn't include BYPASS even though the initial bypass is still in effect. In blk_init_allocated_queue(), or QUEUE_FLAG_DEFAULT to q->queue_flags instead of overwriting. Signed-off-by: Tejun Heo Acked-by: Vivek Goyal Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-core.c b/block/blk-core.c index 1f61b74867e..85fd4100343 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -601,7 +601,7 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn, q->request_fn = rfn; q->prep_rq_fn = NULL; q->unprep_rq_fn = NULL; - q->queue_flags = QUEUE_FLAG_DEFAULT; + q->queue_flags |= QUEUE_FLAG_DEFAULT; /* Override internal queue lock with supplied lock pointer */ if (lock) From 865221d84f23dafcf63485e9081fe972646fef0a Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Thu, 11 Oct 2012 08:00:33 +0800 Subject: [PATCH 1237/2357] autofs4 - fix reset pending flag on mount fail commit 49999ab27eab6289a8e4f450e148bdab521361b2 upstream. In autofs4_d_automount(), if a mount fail occurs the AUTOFS_INF_PENDING mount pending flag is not cleared. One effect of this is when using the "browse" option, directory entry attributes show up with all "?"s due to the incorrect callback and subsequent failure return (when in fact no callback should be made). Signed-off-by: Ian Kent Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/autofs4/root.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 75e5f1c8e02..8c4292f89ee 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -392,10 +392,12 @@ static struct vfsmount *autofs4_d_automount(struct path *path) ino->flags |= AUTOFS_INF_PENDING; spin_unlock(&sbi->fs_lock); status = autofs4_mount_wait(dentry); - if (status) - return ERR_PTR(status); spin_lock(&sbi->fs_lock); ino->flags &= ~AUTOFS_INF_PENDING; + if (status) { + spin_unlock(&sbi->fs_lock); + return ERR_PTR(status); + } } done: if (!(ino->flags & AUTOFS_INF_EXPIRING)) { From 08de372d6c39473773fc303b9253a2be938badbd Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 22 Jun 2012 13:49:31 -0400 Subject: [PATCH 1238/2357] module: taint kernel when lve module is loaded commit c99af3752bb52ba3aece5315279a57a477edfaf1 upstream. Cloudlinux have a product called lve that includes a kernel module. This was previously GPLed but is now under a proprietary license, but the module continues to declare MODULE_LICENSE("GPL") and makes use of some EXPORT_SYMBOL_GPL symbols. Forcibly taint it in order to avoid this. Signed-off-by: Matthew Garrett Cc: Alex Lyashkov Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman --- kernel/module.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/module.c b/kernel/module.c index 78ac6ec1e42..61ea75eaeec 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2729,6 +2729,10 @@ static int check_module_license_and_versions(struct module *mod) if (strcmp(mod->name, "driverloader") == 0) add_taint_module(mod, TAINT_PROPRIETARY_MODULE); + /* lve claims to be GPL but upstream won't provide source */ + if (strcmp(mod->name, "lve") == 0) + add_taint_module(mod, TAINT_PROPRIETARY_MODULE); + #ifdef CONFIG_MODVERSIONS if ((mod->num_syms && !mod->crcs) || (mod->num_gpl_syms && !mod->gpl_crcs) From a065f95a851f18c2b4531808c0a9503f14aa9624 Mon Sep 17 00:00:00 2001 From: Alexander Holler Date: Tue, 14 Aug 2012 09:11:09 +0200 Subject: [PATCH 1239/2357] video/udlfb: fix line counting in fb_write commit b8c4321f3d194469007f5f5f2b34ec278c264a04 upstream. Line 0 and 1 were both written to line 0 (on the display) and all subsequent lines had an offset of -1. The result was that the last line on the display was never overwritten by writes to /dev/fbN. Signed-off-by: Alexander Holler Acked-by: Bernie Thompson Signed-off-by: Florian Tobias Schandinat Signed-off-by: Greg Kroah-Hartman --- drivers/video/udlfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index a159b63e18b..85d81103c1f 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -647,7 +647,7 @@ static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf, result = fb_sys_write(info, buf, count, ppos); if (result > 0) { - int start = max((int)(offset / info->fix.line_length) - 1, 0); + int start = max((int)(offset / info->fix.line_length), 0); int lines = min((u32)((result / info->fix.line_length) + 1), (u32)info->var.yres); From 3dca360fc8484e40f50205a09f6dbbb591791663 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 4 Sep 2012 11:45:32 -0400 Subject: [PATCH 1240/2357] viafb: don't touch clock state on OLPC XO-1.5 commit 012a1211845eab69a5488d59eb87d24cc518c627 upstream. As detailed in the thread titled "viafb PLL/clock tweaking causes XO-1.5 instability," enabling or disabling the IGA1/IGA2 clocks causes occasional stability problems during suspend/resume cycles on this platform. This is rather odd, as the documentation suggests that clocks have two states (on/off) and the default (stable) configuration is configured to enable the clock only when it is needed. However, explicitly enabling *or* disabling the clock triggers this system instability, suggesting that there is a 3rd state at play here. Leaving the clock enable/disable registers alone solves this problem. This fixes spurious reboots during suspend/resume behaviour introduced by commit b692a63a. Signed-off-by: Daniel Drake Signed-off-by: Florian Tobias Schandinat Signed-off-by: Greg Kroah-Hartman --- drivers/video/via/via_clock.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/video/via/via_clock.c b/drivers/video/via/via_clock.c index af8f26b643c..db1e39277e3 100644 --- a/drivers/video/via/via_clock.c +++ b/drivers/video/via/via_clock.c @@ -25,6 +25,7 @@ #include #include +#include #include "via_clock.h" #include "global.h" #include "debug.h" @@ -289,6 +290,10 @@ static void dummy_set_pll(struct via_pll_config config) printk(KERN_INFO "Using undocumented set PLL.\n%s", via_slap); } +static void noop_set_clock_state(u8 state) +{ +} + void via_clock_init(struct via_clock *clock, int gfx_chip) { switch (gfx_chip) { @@ -346,4 +351,18 @@ void via_clock_init(struct via_clock *clock, int gfx_chip) break; } + + if (machine_is_olpc()) { + /* The OLPC XO-1.5 cannot suspend/resume reliably if the + * IGA1/IGA2 clocks are set as on or off (memory rot + * occasionally happens during suspend under such + * configurations). + * + * The only known stable scenario is to leave this bits as-is, + * which in their default states are documented to enable the + * clock only when it is needed. + */ + clock->set_primary_clock_state = noop_set_clock_state; + clock->set_secondary_clock_state = noop_set_clock_state; + } } From 00dff266efe889d4fc6569f3e39ae7195cb83da7 Mon Sep 17 00:00:00 2001 From: "Hildner, Christian" Date: Mon, 8 Oct 2012 15:49:03 +0200 Subject: [PATCH 1241/2357] timers: Fix endless looping between cascade() and internal_add_timer() commit 26cff4e2aa4d666dc6a120ea34336b5057e3e187 upstream. Adding two (or more) timers with large values for "expires" (they have to reside within tv5 in the same list) leads to endless looping between cascade() and internal_add_timer() in case CONFIG_BASE_SMALL is one and jiffies are crossing the value 1 << 18. The bug was introduced between 2.6.11 and 2.6.12 (and survived for quite some time). This patch ensures that when cascade() is called timers within tv5 are not added endlessly to their own list again, instead they are added to the next lower tv level tv4 (as expected). Signed-off-by: Christian Hildner Reviewed-by: Jan Kiszka Link: http://lkml.kernel.org/r/98673C87CB31274881CFFE0B65ECC87B0F5FC1963E@DEFTHW99EA4MSX.ww902.siemens.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/timer.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kernel/timer.c b/kernel/timer.c index a297ffcf888..6dfdb72828f 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -63,6 +63,7 @@ EXPORT_SYMBOL(jiffies_64); #define TVR_SIZE (1 << TVR_BITS) #define TVN_MASK (TVN_SIZE - 1) #define TVR_MASK (TVR_SIZE - 1) +#define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4*TVN_BITS)) - 1)) struct tvec { struct list_head vec[TVN_SIZE]; @@ -356,11 +357,12 @@ static void internal_add_timer(struct tvec_base *base, struct timer_list *timer) vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK); } else { int i; - /* If the timeout is larger than 0xffffffff on 64-bit - * architectures then we use the maximum timeout: + /* If the timeout is larger than MAX_TVAL (on 64-bit + * architectures or with CONFIG_BASE_SMALL=1) then we + * use the maximum timeout. */ - if (idx > 0xffffffffUL) { - idx = 0xffffffffUL; + if (idx > MAX_TVAL) { + idx = MAX_TVAL; expires = idx + base->timer_jiffies; } i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; From a0fee8de3ae5784d4308b7bd18c303a4144ece18 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 3 Oct 2012 21:07:52 +0200 Subject: [PATCH 1242/2357] ath9k: use ieee80211_free_txskb commit 249ee72249140fe5b9adc988f97298f0aa5db2fc upstream. Using ieee80211_free_txskb for tx frames is required, since mac80211 clones skbs for which socket tx status is requested. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/ath/ath9k/xmit.c | 53 ++++++++++++++----------- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 626418222c8..5eb53c98d75 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -121,7 +121,7 @@ static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) if (ath_tx_start(hw, skb, &txctl) != 0) { ath_dbg(common, XMIT, "CABQ TX failed\n"); - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d5dabcb61a0..91e2c4f53d1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1147,7 +1147,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return; exit: - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } static void ath9k_stop(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 4d571394c7a..b78773b48db 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -64,8 +64,7 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct sk_buff *skb, - bool dequeue); + struct sk_buff *skb); enum { MCS_HT20, @@ -201,7 +200,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) fi = get_frame_info(skb); bf = fi->bf; - if (bf && fi->retries) { + if (!bf) { + bf = ath_tx_setup_buffer(sc, txq, tid, skb); + if (!bf) { + ieee80211_free_txskb(sc->hw, skb); + continue; + } + } + + if (fi->retries) { list_add_tail(&bf->list, &bf_head); ath_tx_update_baw(sc, tid, bf->bf_state.seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); @@ -812,10 +819,13 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, fi = get_frame_info(skb); bf = fi->bf; if (!fi->bf) - bf = ath_tx_setup_buffer(sc, txq, tid, skb, true); + bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) + if (!bf) { + __skb_unlink(skb, &tid->buf_q); + ieee80211_free_txskb(sc->hw, skb); continue; + } bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; seqno = bf->bf_state.seqno; @@ -1717,9 +1727,11 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, return; } - bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false); - if (!bf) + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) { + ieee80211_free_txskb(sc->hw, skb); return; + } bf->bf_state.bf_type = BUF_AMPDU; INIT_LIST_HEAD(&bf_head); @@ -1743,11 +1755,6 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf; bf = fi->bf; - if (!bf) - bf = ath_tx_setup_buffer(sc, txq, tid, skb, false); - - if (!bf) - return; INIT_LIST_HEAD(&bf_head); list_add_tail(&bf->list, &bf_head); @@ -1820,8 +1827,7 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct sk_buff *skb, - bool dequeue) + struct sk_buff *skb) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_frame_info *fi = get_frame_info(skb); @@ -1833,7 +1839,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, bf = ath_tx_get_buffer(sc); if (!bf) { ath_dbg(common, XMIT, "TX buffers are full\n"); - goto error; + return NULL; } ATH_TXBUF_RESET(bf); @@ -1862,18 +1868,12 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, ath_err(ath9k_hw_common(sc->sc_ah), "dma_mapping_error() on TX\n"); ath_tx_return_buffer(sc, bf); - goto error; + return NULL; } fi->bf = bf; return bf; - -error: - if (dequeue) - __skb_unlink(skb, &tid->buf_q); - dev_kfree_skb_any(skb); - return NULL; } /* FIXME: tx power */ @@ -1902,9 +1902,14 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, */ ath_tx_send_ampdu(sc, tid, skb, txctl); } else { - bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false); - if (!bf) + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) { + if (txctl->paprd) + dev_kfree_skb_any(skb); + else + ieee80211_free_txskb(sc->hw, skb); return; + } bf->bf_state.bfs_paprd = txctl->paprd; From 9b38cc4a70f2c83857fd37707570a18c1027effe Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 11 Oct 2012 14:20:58 +1100 Subject: [PATCH 1243/2357] md/raid10: use correct limit variable commit 91502f099dfc5a1e8812898e26ee280713e1d002 upstream. Clang complains that we are assigning a variable to itself. This should be using bad_sectors like the similar earlier check does. Bug has been present since 3.1-rc1. It is minor but could conceivably cause corruption or other bad behaviour. Signed-off-by: Dan Carpenter Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1f7e8cd44e5..4a038cdc0b5 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3019,7 +3019,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, else { bad_sectors -= (sector - first_bad); if (max_sync > bad_sectors) - max_sync = max_sync; + max_sync = bad_sectors; continue; } } From c4c493a4adcee75e1e44af044d0b7fc1b5192b61 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Sun, 26 Aug 2012 22:37:03 -0500 Subject: [PATCH 1244/2357] kdb,vt_console: Fix missed data due to pager overruns commit 17b572e82032bc246324ce136696656b66d4e3f1 upstream. It is possible to miss data when using the kdb pager. The kdb pager does not pay attention to the maximum column constraint of the screen or serial terminal. This result is not incrementing the shown lines correctly and the pager will print more lines that fit on the screen. Obviously that is less than useful when using a VGA console where you cannot scroll back. The pager will now look at the kdb_buffer string to see how many characters are printed. It might not be perfect considering you can output ASCII that might move the cursor position, but it is a substantially better approximation for viewing dmesg and trace logs. This also means that the vt screen needs to set the kdb COLUMNS variable. Signed-off-by: Jason Wessel Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 13 +++++++++++++ kernel/debug/kdb/kdb_io.c | 33 ++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 2156188db4a..18d06be8c9b 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3475,6 +3475,19 @@ int con_debug_enter(struct vc_data *vc) kdb_set(2, setargs); } } + if (vc->vc_cols < 999) { + int colcount; + char cols[4]; + const char *setargs[3] = { + "set", + "COLUMNS", + cols, + }; + if (kdbgetintenv(setargs[0], &colcount)) { + snprintf(cols, 4, "%i", vc->vc_cols); + kdb_set(2, setargs); + } + } #endif /* CONFIG_KGDB_KDB */ return ret; } diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index bb9520f0f6f..572e604c562 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -552,6 +552,7 @@ int vkdb_printf(const char *fmt, va_list ap) { int diag; int linecount; + int colcount; int logging, saved_loglevel = 0; int saved_trap_printk; int got_printf_lock = 0; @@ -584,6 +585,10 @@ int vkdb_printf(const char *fmt, va_list ap) if (diag || linecount <= 1) linecount = 24; + diag = kdbgetintenv("COLUMNS", &colcount); + if (diag || colcount <= 1) + colcount = 80; + diag = kdbgetintenv("LOGGING", &logging); if (diag) logging = 0; @@ -690,7 +695,7 @@ int vkdb_printf(const char *fmt, va_list ap) gdbstub_msg_write(kdb_buffer, retlen); } else { if (dbg_io_ops && !dbg_io_ops->is_console) { - len = strlen(kdb_buffer); + len = retlen; cp = kdb_buffer; while (len--) { dbg_io_ops->write_char(*cp); @@ -709,11 +714,29 @@ int vkdb_printf(const char *fmt, va_list ap) printk(KERN_INFO "%s", kdb_buffer); } - if (KDB_STATE(PAGER) && strchr(kdb_buffer, '\n')) - kdb_nextline++; + if (KDB_STATE(PAGER)) { + /* + * Check printed string to decide how to bump the + * kdb_nextline to control when the more prompt should + * show up. + */ + int got = 0; + len = retlen; + while (len--) { + if (kdb_buffer[len] == '\n') { + kdb_nextline++; + got = 0; + } else if (kdb_buffer[len] == '\r') { + got = 0; + } else { + got++; + } + } + kdb_nextline += got / (colcount + 1); + } /* check for having reached the LINES number of printed lines */ - if (kdb_nextline == linecount) { + if (kdb_nextline >= linecount) { char buf1[16] = ""; #if defined(CONFIG_SMP) char buf2[32]; @@ -776,7 +799,7 @@ int vkdb_printf(const char *fmt, va_list ap) kdb_grepping_flag = 0; kdb_printf("\n"); } else if (buf1[0] == ' ') { - kdb_printf("\n"); + kdb_printf("\r"); suspend_grep = 1; /* for this recursion */ } else if (buf1[0] == '\n') { kdb_nextline = linecount - 1; From c8479435f2191c22871a4b27e7eb2d501f4661e8 Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Tue, 9 Oct 2012 17:48:16 +0000 Subject: [PATCH 1245/2357] pktgen: fix crash when generating IPv6 packets commit 5aa8b572007c4bca1e6d3dd4c4820f1ae49d6bb2 upstream. For IPv6, sizeof(struct ipv6hdr) = 40, thus the following expression will result negative: datalen = pkt_dev->cur_pkt_size - 14 - sizeof(struct ipv6hdr) - sizeof(struct udphdr) - pkt_dev->pkt_overhead; And, the check "if (datalen < sizeof(struct pktgen_hdr))" will be passed as "datalen" is promoted to unsigned, therefore will cause a crash later. This is a quick fix by checking if "datalen" is negative. The following patch will increase the default value of 'min_pkt_size' for IPv6. This bug should exist for a long time, so Cc -stable too. Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/pktgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b81369b6ddc..8dae76f481e 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2932,7 +2932,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, sizeof(struct ipv6hdr) - sizeof(struct udphdr) - pkt_dev->pkt_overhead; - if (datalen < sizeof(struct pktgen_hdr)) { + if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) { datalen = sizeof(struct pktgen_hdr); if (net_ratelimit()) pr_info("increased datalen to %d\n", datalen); From 486aaeb0b972820ed704bdf416270ec4b0950da3 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sat, 7 Jul 2012 20:30:11 +0300 Subject: [PATCH 1246/2357] ipvs: fix oops in ip_vs_dst_event on rmmod commit 283283c4da91adc44b03519f434ee1e7e91d6fdb upstream. After commit 39f618b4fd95ae243d940ec64c961009c74e3333 (3.4) "ipvs: reset ipvs pointer in netns" we can oops in ip_vs_dst_event on rmmod ip_vs because ip_vs_control_cleanup is called after the ipvs_core_ops subsys is unregistered and net->ipvs is NULL. Fix it by exiting early from ip_vs_dst_event if ipvs is NULL. It is safe because all services and dests for the net are already freed. Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso Acked-by: David Miller Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipvs/ip_vs_ctl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 97e73806bac..cbc5bfd8c8e 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1521,11 +1521,12 @@ static int ip_vs_dst_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = ptr; struct net *net = dev_net(dev); + struct netns_ipvs *ipvs = net_ipvs(net); struct ip_vs_service *svc; struct ip_vs_dest *dest; unsigned int idx; - if (event != NETDEV_UNREGISTER) + if (event != NETDEV_UNREGISTER || !ipvs) return NOTIFY_DONE; IP_VS_DBG(3, "%s() dev=%s\n", __func__, dev->name); EnterFunction(2); @@ -1551,7 +1552,7 @@ static int ip_vs_dst_event(struct notifier_block *this, unsigned long event, } } - list_for_each_entry(dest, &net_ipvs(net)->dest_trash, n_list) { + list_for_each_entry(dest, &ipvs->dest_trash, n_list) { __ip_vs_dev_reset(dest, dev); } mutex_unlock(&__ip_vs_mutex); From 7fcbcdc96302e9d3e3b36df4fbc86a4c82761092 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 29 Aug 2012 16:25:49 +0000 Subject: [PATCH 1247/2357] netfilter: nf_conntrack: fix racy timer handling with reliable events commit 5b423f6a40a0327f9d40bc8b97ce9be266f74368 upstream. Existing code assumes that del_timer returns true for alive conntrack entries. However, this is not true if reliable events are enabled. In that case, del_timer may return true for entries that were just inserted in the dying list. Note that packets / ctnetlink may hold references to conntrack entries that were just inserted to such list. This patch fixes the issue by adding an independent timer for event delivery. This increases the size of the ecache extension. Still we can revisit this later and use variable size extensions to allocate this area on demand. Tested-by: Oliver Smith Signed-off-by: Pablo Neira Ayuso Acked-by: David Miller Signed-off-by: Greg Kroah-Hartman --- include/net/netfilter/nf_conntrack_ecache.h | 1 + net/netfilter/nf_conntrack_core.c | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index a88fb693938..ea6f8a48ffe 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -18,6 +18,7 @@ struct nf_conntrack_ecache { u16 ctmask; /* bitmask of ct events to be delivered */ u16 expmask; /* bitmask of expect events to be delivered */ u32 pid; /* netlink pid of destroyer */ + struct timer_list timeout; }; static inline struct nf_conntrack_ecache * diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 729f157a0ef..9a171b2445b 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -249,12 +249,15 @@ static void death_by_event(unsigned long ul_conntrack) { struct nf_conn *ct = (void *)ul_conntrack; struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct); + + BUG_ON(ecache == NULL); if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { /* bad luck, let's retry again */ - ct->timeout.expires = jiffies + + ecache->timeout.expires = jiffies + (random32() % net->ct.sysctl_events_retry_timeout); - add_timer(&ct->timeout); + add_timer(&ecache->timeout); return; } /* we've got the event delivered, now it's dying */ @@ -268,6 +271,9 @@ static void death_by_event(unsigned long ul_conntrack) void nf_ct_insert_dying_list(struct nf_conn *ct) { struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct); + + BUG_ON(ecache == NULL); /* add this conntrack to the dying list */ spin_lock_bh(&nf_conntrack_lock); @@ -275,10 +281,10 @@ void nf_ct_insert_dying_list(struct nf_conn *ct) &net->ct.dying); spin_unlock_bh(&nf_conntrack_lock); /* set a new timer to retry event delivery */ - setup_timer(&ct->timeout, death_by_event, (unsigned long)ct); - ct->timeout.expires = jiffies + + setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct); + ecache->timeout.expires = jiffies + (random32() % net->ct.sysctl_events_retry_timeout); - add_timer(&ct->timeout); + add_timer(&ecache->timeout); } EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list); From 0fc58b2ff3f70a6bcfac562c68ec62939c37268a Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Mon, 7 May 2012 02:35:44 +0000 Subject: [PATCH 1248/2357] netfilter: ipset: fix timeout value overflow bug commit 127f559127f5175e4bec3dab725a34845d956591 upstream. Large timeout parameters could result wrong timeout values due to an overflow at msec to jiffies conversion (reported by Andreas Herz) [ This patch was mangled by Pablo Neira Ayuso since David Laight and Eric Dumazet noticed that we were using hardcoded 1000 instead of MSEC_PER_SEC to calculate the timeout ] Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Acked-by: David Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/ipset/ip_set_timeout.h | 4 ++++ net/netfilter/xt_set.c | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/linux/netfilter/ipset/ip_set_timeout.h b/include/linux/netfilter/ipset/ip_set_timeout.h index 47923205a4a..41d9cfa0816 100644 --- a/include/linux/netfilter/ipset/ip_set_timeout.h +++ b/include/linux/netfilter/ipset/ip_set_timeout.h @@ -30,6 +30,10 @@ ip_set_timeout_uget(struct nlattr *tb) { unsigned int timeout = ip_set_get_h32(tb); + /* Normalize to fit into jiffies */ + if (timeout > UINT_MAX/MSEC_PER_SEC) + timeout = UINT_MAX/MSEC_PER_SEC; + /* Userspace supplied TIMEOUT parameter: adjust crazy size */ return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout; } diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c index 0ec8138aa47..035960ec5cb 100644 --- a/net/netfilter/xt_set.c +++ b/net/netfilter/xt_set.c @@ -44,6 +44,14 @@ const struct ip_set_adt_opt n = { \ .cmdflags = cfs, \ .timeout = t, \ } +#define ADT_MOPT(n, f, d, fs, cfs, t) \ +struct ip_set_adt_opt n = { \ + .family = f, \ + .dim = d, \ + .flags = fs, \ + .cmdflags = cfs, \ + .timeout = t, \ +} /* Revision 0 interface: backward compatible with netfilter/iptables */ @@ -296,11 +304,14 @@ static unsigned int set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_set_info_target_v2 *info = par->targinfo; - ADT_OPT(add_opt, par->family, info->add_set.dim, - info->add_set.flags, info->flags, info->timeout); + ADT_MOPT(add_opt, par->family, info->add_set.dim, + info->add_set.flags, info->flags, info->timeout); ADT_OPT(del_opt, par->family, info->del_set.dim, info->del_set.flags, 0, UINT_MAX); + /* Normalize to fit into jiffies */ + if (add_opt.timeout > UINT_MAX/MSEC_PER_SEC) + add_opt.timeout = UINT_MAX/MSEC_PER_SEC; if (info->add_set.index != IPSET_INVALID_ID) ip_set_add(info->add_set.index, skb, par, &add_opt); if (info->del_set.index != IPSET_INVALID_ID) From 285ff6c4a762f556275182bcef767b61174c0424 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Fri, 29 Jun 2012 09:42:28 +0000 Subject: [PATCH 1249/2357] netfilter: ipset: timeout fixing bug broke SET target special timeout value commit a73f89a61f92b364f0b4a3be412b5b70553afc23 upstream. The patch "127f559 netfilter: ipset: fix timeout value overflow bug" broke the SET target when no timeout was specified. Reported-by: Jean-Philippe Menil Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Acked-by: David Miller Signed-off-by: Greg Kroah-Hartman --- net/netfilter/xt_set.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c index 035960ec5cb..c6f7db720d8 100644 --- a/net/netfilter/xt_set.c +++ b/net/netfilter/xt_set.c @@ -16,6 +16,7 @@ #include #include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik "); @@ -310,7 +311,8 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) info->del_set.flags, 0, UINT_MAX); /* Normalize to fit into jiffies */ - if (add_opt.timeout > UINT_MAX/MSEC_PER_SEC) + if (add_opt.timeout != IPSET_NO_TIMEOUT && + add_opt.timeout > UINT_MAX/MSEC_PER_SEC) add_opt.timeout = UINT_MAX/MSEC_PER_SEC; if (info->add_set.index != IPSET_INVALID_ID) ip_set_add(info->add_set.index, skb, par, &add_opt); From 0b0ea6a363eb3f5802adcb07c8c23e052a10d6bb Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Sat, 7 Jul 2012 18:26:10 +0800 Subject: [PATCH 1250/2357] ipvs: fix oops on NAT reply in br_nf context commit 9e33ce453f8ac8452649802bee1f410319408f4b upstream. IPVS should not reset skb->nf_bridge in FORWARD hook by calling nf_reset for NAT replies. It triggers oops in br_nf_forward_finish. [ 579.781508] BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 [ 579.781669] IP: [] br_nf_forward_finish+0x58/0x112 [ 579.781792] PGD 218f9067 PUD 0 [ 579.781865] Oops: 0000 [#1] SMP [ 579.781945] CPU 0 [ 579.781983] Modules linked in: [ 579.782047] [ 579.782080] [ 579.782114] Pid: 4644, comm: qemu Tainted: G W 3.5.0-rc5-00006-g95e69f9 #282 Hewlett-Packard /30E8 [ 579.782300] RIP: 0010:[] [] br_nf_forward_finish+0x58/0x112 [ 579.782455] RSP: 0018:ffff88007b003a98 EFLAGS: 00010287 [ 579.782541] RAX: 0000000000000008 RBX: ffff8800762ead00 RCX: 000000000001670a [ 579.782653] RDX: 0000000000000000 RSI: 000000000000000a RDI: ffff8800762ead00 [ 579.782845] RBP: ffff88007b003ac8 R08: 0000000000016630 R09: ffff88007b003a90 [ 579.782957] R10: ffff88007b0038e8 R11: ffff88002da37540 R12: ffff88002da01a02 [ 579.783066] R13: ffff88002da01a80 R14: ffff88002d83c000 R15: ffff88002d82a000 [ 579.783177] FS: 0000000000000000(0000) GS:ffff88007b000000(0063) knlGS:00000000f62d1b70 [ 579.783306] CS: 0010 DS: 002b ES: 002b CR0: 000000008005003b [ 579.783395] CR2: 0000000000000004 CR3: 00000000218fe000 CR4: 00000000000027f0 [ 579.783505] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 579.783684] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 579.783795] Process qemu (pid: 4644, threadinfo ffff880021b20000, task ffff880021aba760) [ 579.783919] Stack: [ 579.783959] ffff88007693cedc ffff8800762ead00 ffff88002da01a02 ffff8800762ead00 [ 579.784110] ffff88002da01a02 ffff88002da01a80 ffff88007b003b18 ffffffff817b26c7 [ 579.784260] ffff880080000000 ffffffff81ef59f0 ffff8800762ead00 ffffffff81ef58b0 [ 579.784477] Call Trace: [ 579.784523] [ 579.784562] [ 579.784603] [] br_nf_forward_ip+0x275/0x2c8 [ 579.784707] [] nf_iterate+0x47/0x7d [ 579.784797] [] ? br_dev_queue_push_xmit+0xae/0xae [ 579.784906] [] nf_hook_slow+0x6d/0x102 [ 579.784995] [] ? br_dev_queue_push_xmit+0xae/0xae [ 579.785175] [] ? _raw_write_unlock_bh+0x19/0x1b [ 579.785179] [] __br_forward+0x97/0xa2 [ 579.785179] [] br_handle_frame_finish+0x1a6/0x257 [ 579.785179] [] br_nf_pre_routing_finish+0x26d/0x2cb [ 579.785179] [] br_nf_pre_routing+0x55d/0x5c1 [ 579.785179] [] nf_iterate+0x47/0x7d [ 579.785179] [] ? br_handle_local_finish+0x44/0x44 [ 579.785179] [] nf_hook_slow+0x6d/0x102 [ 579.785179] [] ? br_handle_local_finish+0x44/0x44 [ 579.785179] [] ? sky2_poll+0xb35/0xb54 [ 579.785179] [] br_handle_frame+0x213/0x229 [ 579.785179] [] ? br_handle_frame_finish+0x257/0x257 [ 579.785179] [] __netif_receive_skb+0x2b4/0x3f1 [ 579.785179] [] process_backlog+0x99/0x1e2 [ 579.785179] [] net_rx_action+0xdf/0x242 [ 579.785179] [] __do_softirq+0xc1/0x1e0 [ 579.785179] [] ? trace_hardirqs_off_thunk+0x3a/0x6c [ 579.785179] [] call_softirq+0x1c/0x30 The steps to reproduce as follow, 1. On Host1, setup brige br0(192.168.1.106) 2. Boot a kvm guest(192.168.1.105) on Host1 and start httpd 3. Start IPVS service on Host1 ipvsadm -A -t 192.168.1.106:80 -s rr ipvsadm -a -t 192.168.1.106:80 -r 192.168.1.105:80 -m 4. Run apache benchmark on Host2(192.168.1.101) ab -n 1000 http://192.168.1.106/ ip_vs_reply4 ip_vs_out handle_response ip_vs_notrack nf_reset() { skb->nf_bridge = NULL; } Actually, IPVS wants in this case just to replace nfct with untracked version. So replace the nf_reset(skb) call in ip_vs_notrack() with a nf_conntrack_put(skb->nfct) call. Signed-off-by: Lin Ming Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso Acked-by: David Miller Signed-off-by: Greg Kroah-Hartman --- include/net/ip_vs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 72522f08737..2389959464c 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -1356,7 +1356,7 @@ static inline void ip_vs_notrack(struct sk_buff *skb) struct nf_conn *ct = nf_ct_get(skb, &ctinfo); if (!ct || !nf_ct_is_untracked(ct)) { - nf_reset(skb); + nf_conntrack_put(skb->nfct); skb->nfct = &nf_ct_untracked_get()->ct_general; skb->nfctinfo = IP_CT_NEW; nf_conntrack_get(skb->nfct); From 6ebe631c590aa6c5e61ccec9ab1808f99705f9d5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 29 Aug 2012 15:24:09 +0000 Subject: [PATCH 1251/2357] netfilter: nf_nat_sip: fix incorrect handling of EBUSY for RTCP expectation commit 3f509c689a07a4aa989b426893d8491a7ffcc410 upstream. We're hitting bug while trying to reinsert an already existing expectation: kernel BUG at kernel/timer.c:895! invalid opcode: 0000 [#1] SMP [...] Call Trace: [] nf_ct_expect_related_report+0x4a0/0x57a [nf_conntrack] [] ? in4_pton+0x72/0x131 [] ip_nat_sdp_media+0xeb/0x185 [nf_nat_sip] [] set_expected_rtp_rtcp+0x32d/0x39b [nf_conntrack_sip] [] process_sdp+0x30c/0x3ec [nf_conntrack_sip] [] ? irq_exit+0x9a/0x9c [] ? ip_nat_sdp_media+0x185/0x185 [nf_nat_sip] We have to remove the RTP expectation if the RTCP expectation hits EBUSY since we keep trying with other ports until we succeed. Reported-by: Rafal Fitt Acked-by: David Miller Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/ipv4/netfilter/nf_nat_sip.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 57932c43960..0ba0394bb2c 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -501,7 +501,10 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff, ret = nf_ct_expect_related(rtcp_exp); if (ret == 0) break; - else if (ret != -EBUSY) { + else if (ret == -EBUSY) { + nf_ct_unexpect_related(rtp_exp); + continue; + } else if (ret < 0) { nf_ct_unexpect_related(rtp_exp); port = 0; break; From 7ea0513ee0bc8c8e85ade576caaf13a58b2cb55d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 9 Aug 2012 10:08:47 +0000 Subject: [PATCH 1252/2357] netfilter: nf_nat_sip: fix via header translation with multiple parameters commit f22eb25cf5b1157b29ef88c793b71972efc47143 upstream. Via-headers are parsed beginning at the first character after the Via-address. When the address is translated first and its length decreases, the offset to start parsing at is incorrect and header parameters might be missed. Update the offset after translating the Via-address to fix this. Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso Acked-by: David Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/netfilter/nf_nat_sip.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 0ba0394bb2c..566be2dd73f 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -148,7 +148,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, hdr, NULL, &matchoff, &matchlen, &addr, &port) > 0) { - unsigned int matchend, poff, plen, buflen, n; + unsigned int olen, matchend, poff, plen, buflen, n; char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; /* We're only interested in headers related to this @@ -163,11 +163,12 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, goto next; } + olen = *datalen; if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, &addr, port)) return NF_DROP; - matchend = matchoff + matchlen; + matchend = matchoff + matchlen + *datalen - olen; /* The maddr= parameter (RFC 2361) specifies where to send * the reply. */ From 29f0d1b362fcdcd7bb3071782184f4035d5784bd Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 16 Aug 2012 02:25:24 +0200 Subject: [PATCH 1253/2357] netfilter: nf_ct_expect: fix possible access to uninitialized timer commit 2614f86490122bf51eb7c12ec73927f1900f4e7d upstream. In __nf_ct_expect_check, the function refresh_timer returns 1 if a matching expectation is found and its timer is successfully refreshed. This results in nf_ct_expect_related returning 0. Note that at this point: - the passed expectation is not inserted in the expectation table and its timer was not initialized, since we have refreshed one matching/existing expectation. - nf_ct_expect_alloc uses kmem_cache_alloc, so the expectation timer is in some undefined state just after the allocation, until it is appropriately initialized. This can be a problem for the SIP helper during the expectation addition: ... if (nf_ct_expect_related(rtp_exp) == 0) { if (nf_ct_expect_related(rtcp_exp) != 0) nf_ct_unexpect_related(rtp_exp); ... Note that nf_ct_expect_related(rtp_exp) may return 0 for the timer refresh case that is detailed above. Then, if nf_ct_unexpect_related(rtcp_exp) returns != 0, nf_ct_unexpect_related(rtp_exp) is called, which does: spin_lock_bh(&nf_conntrack_lock); if (del_timer(&exp->timeout)) { nf_ct_unlink_expect(exp); nf_ct_expect_put(exp); } spin_unlock_bh(&nf_conntrack_lock); Note that del_timer always returns false if the timer has been initialized. However, the timer was not initialized since setup_timer was not called, therefore, the expectation timer remains in some undefined state. If I'm not missing anything, this may lead to the removal an unexistent expectation. To fix this, the optimization that allows refreshing an expectation is removed. Now nf_conntrack_expect_related looks more consistent to me since it always add the expectation in case that it returns success. Thanks to Patrick McHardy for participating in the discussion of this patch. I think this may be the source of the problem described by: http://marc.info/?l=netfilter-devel&m=134073514719421&w=2 Reported-by: Rafal Fitt Acked-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso Acked-by: David Miller Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_conntrack_expect.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 4147ba3f653..e41ec849120 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -361,23 +361,6 @@ static void evict_oldest_expect(struct nf_conn *master, } } -static inline int refresh_timer(struct nf_conntrack_expect *i) -{ - struct nf_conn_help *master_help = nfct_help(i->master); - const struct nf_conntrack_expect_policy *p; - - if (!del_timer(&i->timeout)) - return 0; - - p = &rcu_dereference_protected( - master_help->helper, - lockdep_is_held(&nf_conntrack_lock) - )->expect_policy[i->class]; - i->timeout.expires = jiffies + p->timeout * HZ; - add_timer(&i->timeout); - return 1; -} - static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) { const struct nf_conntrack_expect_policy *p; @@ -386,7 +369,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) struct nf_conn_help *master_help = nfct_help(master); struct nf_conntrack_helper *helper; struct net *net = nf_ct_exp_net(expect); - struct hlist_node *n; + struct hlist_node *n, *next; unsigned int h; int ret = 1; @@ -395,12 +378,12 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) goto out; } h = nf_ct_expect_dst_hash(&expect->tuple); - hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) { + hlist_for_each_entry_safe(i, n, next, &net->ct.expect_hash[h], hnode) { if (expect_matches(i, expect)) { - /* Refresh timer: if it's dying, ignore.. */ - if (refresh_timer(i)) { - ret = 0; - goto out; + if (del_timer(&i->timeout)) { + nf_ct_unlink_expect(i); + nf_ct_expect_put(i); + break; } } else if (expect_clash(i, expect)) { ret = -EBUSY; From aee054fb840f6fca8067a42f44df0e2a22e0378c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 7 May 2012 10:51:43 +0000 Subject: [PATCH 1254/2357] netfilter: limit, hashlimit: avoid duplicated inline commit 7a909ac70f6b0823d9f23a43f19598d4b57ac901 upstream. credit_cap can be set to credit, which avoids inlining user2credits twice. Also, remove inline keyword and let compiler decide. old: 684 192 0 876 36c net/netfilter/xt_limit.o 4927 344 32 5303 14b7 net/netfilter/xt_hashlimit.o now: 668 192 0 860 35c net/netfilter/xt_limit.o 4793 344 32 5169 1431 net/netfilter/xt_hashlimit.o Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Acked-by: David Miller Signed-off-by: Greg Kroah-Hartman --- net/netfilter/xt_hashlimit.c | 8 +++----- net/netfilter/xt_limit.c | 5 ++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index d95f9c963cd..2195eb0727a 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -389,8 +389,7 @@ static void htable_put(struct xt_hashlimit_htable *hinfo) #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) /* Precision saver. */ -static inline u_int32_t -user2credits(u_int32_t user) +static u32 user2credits(u32 user) { /* If multiplying would overflow... */ if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) @@ -400,7 +399,7 @@ user2credits(u_int32_t user) return (user * HZ * CREDITS_PER_JIFFY) / XT_HASHLIMIT_SCALE; } -static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) +static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) { dh->rateinfo.credit += (now - dh->rateinfo.prev) * CREDITS_PER_JIFFY; if (dh->rateinfo.credit > dh->rateinfo.credit_cap) @@ -535,8 +534,7 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) dh->rateinfo.prev = jiffies; dh->rateinfo.credit = user2credits(hinfo->cfg.avg * hinfo->cfg.burst); - dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * - hinfo->cfg.burst); + dh->rateinfo.credit_cap = dh->rateinfo.credit; dh->rateinfo.cost = user2credits(hinfo->cfg.avg); } else { /* update expiration timeout */ diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index 32b7a579a03..5c22ce8ab30 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c @@ -88,8 +88,7 @@ limit_mt(const struct sk_buff *skb, struct xt_action_param *par) } /* Precision saver. */ -static u_int32_t -user2credits(u_int32_t user) +static u32 user2credits(u32 user) { /* If multiplying would overflow... */ if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) @@ -123,7 +122,7 @@ static int limit_mt_check(const struct xt_mtchk_param *par) 128. */ priv->prev = jiffies; priv->credit = user2credits(r->avg * r->burst); /* Credits full. */ - r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ + r->credit_cap = priv->credit; /* Credits full. */ r->cost = user2credits(r->avg); } return 0; From 7ae3bb7d050f8c7e3ef46c830968f3bb5ca2e232 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 21 Sep 2012 22:26:52 +0000 Subject: [PATCH 1255/2357] netfilter: xt_limit: have r->cost != 0 case work commit 82e6bfe2fbc4d48852114c4f979137cd5bf1d1a8 upstream. Commit v2.6.19-rc1~1272^2~41 tells us that r->cost != 0 can happen when a running state is saved to userspace and then reinstated from there. Make sure that private xt_limit area is initialized with correct values. Otherwise, random matchings due to use of uninitialized memory. Signed-off-by: Jan Engelhardt Signed-off-by: Pablo Neira Ayuso Acked-by: David Miller Signed-off-by: Greg Kroah-Hartman --- net/netfilter/xt_limit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index 5c22ce8ab30..a4c1e4528ca 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c @@ -117,11 +117,11 @@ static int limit_mt_check(const struct xt_mtchk_param *par) /* For SMP, we only want to use one set of state. */ r->master = priv; + /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * + 128. */ + priv->prev = jiffies; + priv->credit = user2credits(r->avg * r->burst); /* Credits full. */ if (r->cost == 0) { - /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * - 128. */ - priv->prev = jiffies; - priv->credit = user2credits(r->avg * r->burst); /* Credits full. */ r->credit_cap = priv->credit; /* Credits full. */ r->cost = user2credits(r->avg); } From 525383548a58de3cf3c1f35abfebed453d3d190c Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz Date: Wed, 10 Oct 2012 12:49:02 +0000 Subject: [PATCH 1256/2357] Add CDC-ACM support for the CX93010-2x UCMxx USB Modem commit e7d491a19d3e3aac544070293891a2542ae0c565 upstream. This USB V.92/V.32bis Controllered Modem have the USB vendor ID 0x0572 and device ID 0x1340. It need the NO_UNION_NORMAL quirk to be recognized. Reference: http://www.conexant.com/servlets/DownloadServlet/DSH-201723-005.pdf?docid=1725&revid=5 See idVendor and idProduct in table 6-1. Device Descriptors Signed-off-by: Jean-Christian de Rivaz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 1b632cb88ac..7f2fac162a7 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1551,6 +1551,9 @@ static const struct usb_device_id acm_ids[] = { Maybe we should define a new quirk for this. */ }, + { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ + .driver_info = NO_UNION_NORMAL, + }, { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ }, From ab8cd49a6e1984398984e1657f7b6787c37a9a45 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Mon, 15 Oct 2012 08:21:39 +0200 Subject: [PATCH 1257/2357] drm/radeon: Don't destroy I2C Bus Rec in radeon_ext_tmds_enc_destroy(). commit 082918471139b07964967cfe5f70230909c82ae1 upstream. radeon_i2c_fini() walks thru the list of I2C bus recs rdev->i2c_bus[] to destroy each of them. radeon_ext_tmds_enc_destroy() however also has code to destroy it's associated I2C bus rec which has been obtained by radeon_i2c_lookup() and is therefore also in the i2c_bus[] list. This causes a double free resulting in a kernel panic when unloading the radeon driver. Removing destroy code from radeon_ext_tmds_enc_destroy() fixes this problem. agd5f: fix compiler warning Signed-off-by: Egbert Eich Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 42db254f6bb..1461e2ce359 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -973,11 +973,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, static void radeon_ext_tmds_enc_destroy(struct drm_encoder *encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_ext_tmds *tmds = radeon_encoder->enc_priv; - if (tmds) { - if (tmds->i2c_bus) - radeon_i2c_destroy(tmds->i2c_bus); - } + /* don't destroy the i2c bus record here, this will be done in radeon_i2c_fini */ kfree(radeon_encoder->enc_priv); drm_encoder_cleanup(encoder); kfree(radeon_encoder); From 6a52f3c682cf4c191885d1029449d68fd60b40e6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 26 Sep 2012 18:43:10 +0300 Subject: [PATCH 1258/2357] drm/i915: use adjusted_mode instead of mode for checking the 6bpc force flag commit 0c96c65b48fba3ffe9822a554cbc0cd610765cd5 upstream. The dithering introduced in commit 3b5c78a35cf7511c15e09a9b0ffab290a42d9bcf Author: Adam Jackson Date: Tue Dec 13 15:41:00 2011 -0800 drm/i915/dp: Dither down to 6bpc if it makes the mode fit stores the INTEL_MODE_DP_FORCE_6BPC flag in the private_flags of the adjusted mode, while i9xx_crtc_mode_set() and ironlake_crtc_mode_set() use the original mode, without the flag, so it would never have any effect. However, the BPC was clamped by VBT settings, making things work by coincidence, until that part was removed in commit 4344b813f105a19f793f1fd93ad775b784648b95 Author: Daniel Vetter Date: Fri Aug 10 11:10:20 2012 +0200 Use adjusted_mode instead of mode when checking for INTEL_MODE_DP_FORCE_6BPC to make the flag have effect. v2: Don't forget to fix this in i9xx_crtc_mode_set() also, pointed out by Daniel both before and after sending the first patch. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=47621 CC: Adam Jackson Signed-off-by: Jani Nikula Reviewed-by: Adam Jackson Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 498bcbeb992..f3b06f04e01 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5318,7 +5318,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, /* default to 8bpc */ pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN); if (is_dp) { - if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { + if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { pipeconf |= PIPECONF_BPP_6 | PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP; @@ -5782,7 +5782,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* determine panel color depth */ temp = I915_READ(PIPECONF(pipe)); temp &= ~PIPE_BPC_MASK; - dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode); + dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, adjusted_mode); switch (pipe_bpp) { case 18: temp |= PIPE_6BPC; From ea05dc56faeea5a3e0eaafe6de9fae196ed7f036 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 11 Jul 2012 23:16:25 +0200 Subject: [PATCH 1259/2357] jbd: Fix assertion failure in commit code due to lacking transaction credits commit 09e05d4805e6c524c1af74e524e5d0528bb3fef3 upstream. ext3 users of data=journal mode with blocksize < pagesize were occasionally hitting assertion failure in journal_commit_transaction() checking whether the transaction has at least as many credits reserved as buffers attached. The core of the problem is that when a file gets truncated, buffers that still need checkpointing or that are attached to the committing transaction are left with buffer_mapped set. When this happens to buffers beyond i_size attached to a page stradding i_size, subsequent write extending the file will see these buffers and as they are mapped (but underlying blocks were freed) things go awry from here. The assertion failure just coincidentally (and in this case luckily as we would start corrupting filesystem) triggers due to journal_head not being properly cleaned up as well. Under some rare circumstances this bug could even hit data=ordered mode users. There the assertion won't trigger and we would end up corrupting the filesystem. We fix the problem by unmapping buffers if possible (in lots of cases we just need a buffer attached to a transaction as a place holder but it must not be written out anyway). And in one case, we just have to bite the bullet and wait for transaction commit to finish. Reviewed-by: Josef Bacik Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/jbd/commit.c | 45 +++++++++++++++++++++++-------- fs/jbd/transaction.c | 64 ++++++++++++++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 31 deletions(-) diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index f2b9a571f4c..9626bc8cbbd 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -86,7 +86,12 @@ static void release_buffer_page(struct buffer_head *bh) static void release_data_buffer(struct buffer_head *bh) { if (buffer_freed(bh)) { + WARN_ON_ONCE(buffer_dirty(bh)); clear_buffer_freed(bh); + clear_buffer_mapped(bh); + clear_buffer_new(bh); + clear_buffer_req(bh); + bh->b_bdev = NULL; release_buffer_page(bh); } else put_bh(bh); @@ -853,17 +858,35 @@ void journal_commit_transaction(journal_t *journal) * there's no point in keeping a checkpoint record for * it. */ - /* A buffer which has been freed while still being - * journaled by a previous transaction may end up still - * being dirty here, but we want to avoid writing back - * that buffer in the future after the "add to orphan" - * operation been committed, That's not only a performance - * gain, it also stops aliasing problems if the buffer is - * left behind for writeback and gets reallocated for another - * use in a different page. */ - if (buffer_freed(bh) && !jh->b_next_transaction) { - clear_buffer_freed(bh); - clear_buffer_jbddirty(bh); + /* + * A buffer which has been freed while still being journaled by + * a previous transaction. + */ + if (buffer_freed(bh)) { + /* + * If the running transaction is the one containing + * "add to orphan" operation (b_next_transaction != + * NULL), we have to wait for that transaction to + * commit before we can really get rid of the buffer. + * So just clear b_modified to not confuse transaction + * credit accounting and refile the buffer to + * BJ_Forget of the running transaction. If the just + * committed transaction contains "add to orphan" + * operation, we can completely invalidate the buffer + * now. We are rather throughout in that since the + * buffer may be still accessible when blocksize < + * pagesize and it is attached to the last partial + * page. + */ + jh->b_modified = 0; + if (!jh->b_next_transaction) { + clear_buffer_freed(bh); + clear_buffer_jbddirty(bh); + clear_buffer_mapped(bh); + clear_buffer_new(bh); + clear_buffer_req(bh); + bh->b_bdev = NULL; + } } if (buffer_jbddirty(bh)) { diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index b2a7e5244e3..841cabc94df 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1845,15 +1845,16 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) * We're outside-transaction here. Either or both of j_running_transaction * and j_committing_transaction may be NULL. */ -static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) +static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, + int partial_page) { transaction_t *transaction; struct journal_head *jh; int may_free = 1; - int ret; BUFFER_TRACE(bh, "entry"); +retry: /* * It is safe to proceed here without the j_list_lock because the * buffers cannot be stolen by try_to_free_buffers as long as we are @@ -1881,10 +1882,18 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) * clear the buffer dirty bit at latest at the moment when the * transaction marking the buffer as freed in the filesystem * structures is committed because from that moment on the - * buffer can be reallocated and used by a different page. + * block can be reallocated and used by a different page. * Since the block hasn't been freed yet but the inode has * already been added to orphan list, it is safe for us to add * the buffer to BJ_Forget list of the newest transaction. + * + * Also we have to clear buffer_mapped flag of a truncated buffer + * because the buffer_head may be attached to the page straddling + * i_size (can happen only when blocksize < pagesize) and thus the + * buffer_head can be reused when the file is extended again. So we end + * up keeping around invalidated buffers attached to transactions' + * BJ_Forget list just to stop checkpointing code from cleaning up + * the transaction this buffer was modified in. */ transaction = jh->b_transaction; if (transaction == NULL) { @@ -1911,13 +1920,9 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) * committed, the buffer won't be needed any * longer. */ JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); - ret = __dispose_buffer(jh, + may_free = __dispose_buffer(jh, journal->j_running_transaction); - journal_put_journal_head(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - spin_unlock(&journal->j_state_lock); - return ret; + goto zap_buffer; } else { /* There is no currently-running transaction. So the * orphan record which we wrote for this file must have @@ -1925,13 +1930,9 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) * the committing transaction, if it exists. */ if (journal->j_committing_transaction) { JBUFFER_TRACE(jh, "give to committing trans"); - ret = __dispose_buffer(jh, + may_free = __dispose_buffer(jh, journal->j_committing_transaction); - journal_put_journal_head(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - spin_unlock(&journal->j_state_lock); - return ret; + goto zap_buffer; } else { /* The orphan record's transaction has * committed. We can cleanse this buffer */ @@ -1952,10 +1953,24 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) } /* * The buffer is committing, we simply cannot touch - * it. So we just set j_next_transaction to the - * running transaction (if there is one) and mark - * buffer as freed so that commit code knows it should - * clear dirty bits when it is done with the buffer. + * it. If the page is straddling i_size we have to wait + * for commit and try again. + */ + if (partial_page) { + tid_t tid = journal->j_committing_transaction->t_tid; + + journal_put_journal_head(jh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); + log_wait_commit(journal, tid); + goto retry; + } + /* + * OK, buffer won't be reachable after truncate. We just set + * j_next_transaction to the running transaction (if there is + * one) and mark buffer as freed so that commit code knows it + * should clear dirty bits when it is done with the buffer. */ set_buffer_freed(bh); if (journal->j_running_transaction && buffer_jbddirty(bh)) @@ -1978,6 +1993,14 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) } zap_buffer: + /* + * This is tricky. Although the buffer is truncated, it may be reused + * if blocksize < pagesize and it is attached to the page straddling + * EOF. Since the buffer might have been added to BJ_Forget list of the + * running transaction, journal_get_write_access() won't clear + * b_modified and credit accounting gets confused. So clear b_modified + * here. */ + jh->b_modified = 0; journal_put_journal_head(jh); zap_buffer_no_jh: spin_unlock(&journal->j_list_lock); @@ -2026,7 +2049,8 @@ void journal_invalidatepage(journal_t *journal, if (offset <= curr_off) { /* This block is wholly outside the truncation point */ lock_buffer(bh); - may_free &= journal_unmap_buffer(journal, bh); + may_free &= journal_unmap_buffer(journal, bh, + offset > 0); unlock_buffer(bh); } curr_off = next_off; From f5e37c549d200e3b899b66d6a84e99c8e2cf5e59 Mon Sep 17 00:00:00 2001 From: Hiroaki SHIMODA Date: Wed, 10 Oct 2012 15:34:20 +0000 Subject: [PATCH 1260/2357] e1000e: Change wthresh to 1 to avoid possible Tx stalls commit 8edc0e624db3756783233e464879eb2e3b904c13 upstream. This patch originated from Hiroaki SHIMODA but has been modified by Intel with some minor cleanups and additional commit log text. Denys Fedoryshchenko and others reported Tx stalls on e1000e with BQL enabled. Issue was root caused to hardware delays. They were introduced because some of the e1000e hardware with transmit writeback bursting enabled, waits until the driver does an explict flush OR there are WTHRESH descriptors to write back. Sometimes the delays in question were on the order of seconds, causing visible lag for ssh sessions and unacceptable tx completion latency, especially for BQL enabled kernels. To avoid possible Tx stalls, change WTHRESH back to 1. The current plan is to investigate a method for re-enabling WTHRESH while not harming BQL, but those patches will be later for net-next if they work. please enqueue for stable since v3.3 as this bug was introduced in commit 3f0cfa3bc11e7f00c9994e0f469cbc0e7da7b00c Author: Tom Herbert Date: Mon Nov 28 16:33:16 2011 +0000 e1000e: Support for byte queue limits Changes to e1000e to use byte queue limits. Reported-by: Denys Fedoryshchenko Tested-by: Denys Fedoryshchenko Signed-off-by: Hiroaki SHIMODA CC: eric.dumazet@gmail.com CC: therbert@google.com Signed-off-by: Jesse Brandeburg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/e1000.h | 6 +++--- drivers/net/ethernet/intel/e1000e/netdev.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index b83897f76ee..1ab8067b028 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -175,13 +175,13 @@ struct e1000_info; /* * in the case of WTHRESH, it appears at least the 82571/2 hardware * writes back 4 descriptors when WTHRESH=5, and 3 descriptors when - * WTHRESH=4, and since we want 64 bytes at a time written back, set - * it to 5 + * WTHRESH=4, so a setting of 5 gives the most efficient bus + * utilization but to avoid possible Tx stalls, set it to 1 */ #define E1000_TXDCTL_DMA_BURST_ENABLE \ (E1000_TXDCTL_GRAN | /* set descriptor granularity */ \ E1000_TXDCTL_COUNT_DESC | \ - (5 << 16) | /* wthresh must be +1 more than desired */\ + (1 << 16) | /* wthresh must be +1 more than desired */\ (1 << 8) | /* hthresh */ \ 0x1f) /* pthresh */ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 5621d5b2876..7e88aaff6ec 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -2806,7 +2806,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) * set up some performance related parameters to encourage the * hardware to use the bus more efficiently in bursts, depends * on the tx_int_delay to be enabled, - * wthresh = 5 ==> burst write a cacheline (64 bytes) at a time + * wthresh = 1 ==> burst write is disabled to avoid Tx stalls * hthresh = 1 ==> prefetch when one or more available * pthresh = 0x1f ==> prefetch if internal cache 31 or less * BEWARE: this seems to work but should be considered first if From 8abffa895c8a6c6079e93db68f5eb5e4a2332a82 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Thu, 27 Sep 2012 16:09:33 +0200 Subject: [PATCH 1261/2357] tpm: Propagate error from tpm_transmit to fix a timeout hang commit abce9ac292e13da367bbd22c1f7669f988d931ac upstream. tpm_write calls tpm_transmit without checking the return value and assigns the return value unconditionally to chip->pending_data, even if it's an error value. This causes three bugs. So if we write to /dev/tpm0 with a tpm_param_size bigger than TPM_BUFSIZE=0x1000 (e.g. 0x100a) and a bufsize also bigger than TPM_BUFSIZE (e.g. 0x100a) tpm_transmit returns -E2BIG which is assigned to chip->pending_data as -7, but tpm_write returns that TPM_BUFSIZE bytes have been successfully been written to the TPM, altough this is not true (bug #1). As we did write more than than TPM_BUFSIZE bytes but tpm_write reports that only TPM_BUFSIZE bytes have been written the vfs tries to write the remaining bytes (in this case 10 bytes) to the tpm device driver via tpm_write which then blocks at /* cannot perform a write until the read has cleared either via tpm_read or a user_read_timer timeout */ while (atomic_read(&chip->data_pending) != 0) msleep(TPM_TIMEOUT); for 60 seconds, since data_pending is -7 and nobody is able to read it (since tpm_read luckily checks if data_pending is greater than 0) (#bug 2). After that the remaining bytes are written to the TPM which are interpreted by the tpm as a normal command. (bug #3) So if the last bytes of the command stream happen to be a e.g. tpm_force_clear this gets accidentally sent to the TPM. This patch fixes all three bugs, by propagating the error code of tpm_write and returning -E2BIG if the input buffer is too big, since the response from the tpm for a truncated value is bogus anyway. Moreover it returns -EBUSY to userspace if there is a response ready to be read. Signed-off-by: Peter Huewe Signed-off-by: Kent Yoder Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 08427abf5fa..27f8ddf09d4 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1186,17 +1186,20 @@ ssize_t tpm_write(struct file *file, const char __user *buf, size_t size, loff_t *off) { struct tpm_chip *chip = file->private_data; - size_t in_size = size, out_size; + size_t in_size = size; + ssize_t out_size; /* cannot perform a write until the read has cleared - either via tpm_read or a user_read_timer timeout */ - while (atomic_read(&chip->data_pending) != 0) - msleep(TPM_TIMEOUT); - - mutex_lock(&chip->buffer_mutex); + either via tpm_read or a user_read_timer timeout. + This also prevents splitted buffered writes from blocking here. + */ + if (atomic_read(&chip->data_pending) != 0) + return -EBUSY; if (in_size > TPM_BUFSIZE) - in_size = TPM_BUFSIZE; + return -E2BIG; + + mutex_lock(&chip->buffer_mutex); if (copy_from_user (chip->data_buffer, (void __user *) buf, in_size)) { @@ -1206,6 +1209,10 @@ ssize_t tpm_write(struct file *file, const char __user *buf, /* atomic tpm command send and result receive */ out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); + if (out_size < 0) { + mutex_unlock(&chip->buffer_mutex); + return out_size; + } atomic_set(&chip->data_pending, out_size); mutex_unlock(&chip->buffer_mutex); From 4fd441539be925bf3cbbfe88f9371317a952529b Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 22 May 2012 15:09:50 -0500 Subject: [PATCH 1262/2357] eCryptfs: Unlink lower inode when ecryptfs_create() fails commit 8bc2d3cf612994a960c2e8eaea37f6676f67082a upstream. ecryptfs_create() creates a lower inode, allocates an eCryptfs inode, initializes the eCryptfs inode and cryptographic metadata attached to the inode, and then writes the metadata to the header of the file. If an error was to occur after the lower inode was created, an empty lower file would be left in the lower filesystem. This is a problem because ecryptfs_open() refuses to open any lower files which do not have the appropriate metadata in the file header. This patch properly unlinks the lower inode when an error occurs in the later stages of ecryptfs_create(), reducing the chance that an empty lower file will be left in the lower filesystem. https://launchpad.net/bugs/872905 Signed-off-by: Tyler Hicks Cc: John Johansen Cc: Colin Ian King Cc: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/inode.c | 55 ++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 6f5fb1a0d90..fb4a9d8f225 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -143,6 +143,31 @@ static int ecryptfs_interpose(struct dentry *lower_dentry, return 0; } +static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry, + struct inode *inode) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); + struct dentry *lower_dir_dentry; + int rc; + + dget(lower_dentry); + lower_dir_dentry = lock_parent(lower_dentry); + rc = vfs_unlink(lower_dir_inode, lower_dentry); + if (rc) { + printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); + goto out_unlock; + } + fsstack_copy_attr_times(dir, lower_dir_inode); + set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink); + inode->i_ctime = dir->i_ctime; + d_drop(dentry); +out_unlock: + unlock_dir(lower_dir_dentry); + dput(lower_dentry); + return rc; +} + /** * ecryptfs_do_create * @directory_inode: inode of the new file's dentry's parent in ecryptfs @@ -182,8 +207,10 @@ ecryptfs_do_create(struct inode *directory_inode, } inode = __ecryptfs_get_inode(lower_dentry->d_inode, directory_inode->i_sb); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { + vfs_unlink(lower_dir_dentry->d_inode, lower_dentry); goto out_lock; + } fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode); fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode); out_lock: @@ -265,7 +292,9 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, * that this on disk file is prepared to be an ecryptfs file */ rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { - drop_nlink(ecryptfs_inode); + ecryptfs_do_unlink(directory_inode, ecryptfs_dentry, + ecryptfs_inode); + make_bad_inode(ecryptfs_inode); unlock_new_inode(ecryptfs_inode); iput(ecryptfs_inode); goto out; @@ -477,27 +506,7 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) { - int rc = 0; - struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); - struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); - struct dentry *lower_dir_dentry; - - dget(lower_dentry); - lower_dir_dentry = lock_parent(lower_dentry); - rc = vfs_unlink(lower_dir_inode, lower_dentry); - if (rc) { - printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); - goto out_unlock; - } - fsstack_copy_attr_times(dir, lower_dir_inode); - set_nlink(dentry->d_inode, - ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink); - dentry->d_inode->i_ctime = dir->i_ctime; - d_drop(dentry); -out_unlock: - unlock_dir(lower_dir_dentry); - dput(lower_dentry); - return rc; + return ecryptfs_do_unlink(dir, dentry, dentry->d_inode); } static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, From 47bd3aa366784c052e7e9a1acf80cd8c8e9df10b Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Wed, 20 Jun 2012 23:50:59 -0700 Subject: [PATCH 1263/2357] eCryptfs: Initialize empty lower files when opening them commit e3ccaa9761200952cc269b1f4b7d7bb77a5e071b upstream. Historically, eCryptfs has only initialized lower files in the ecryptfs_create() path. Lower file initialization is the act of writing the cryptographic metadata from the inode's crypt_stat to the header of the file. The ecryptfs_open() path already expects that metadata to be in the header of the file. A number of users have reported empty lower files in beneath their eCryptfs mounts. Most of the causes for those empty files being left around have been addressed, but the presence of empty files causes problems due to the lack of proper cryptographic metadata. To transparently solve this problem, this patch initializes empty lower files in the ecryptfs_open() error path. If the metadata is unreadable due to the lower inode size being 0, plaintext passthrough support is not in use, and the metadata is stored in the header of the file (as opposed to the user.ecryptfs extended attribute), the lower file will be initialized. The number of nested conditionals in ecryptfs_open() was getting out of hand, so a helper function was created. To avoid the same nested conditional problem, the conditional logic was reversed inside of the helper function. https://launchpad.net/bugs/911507 Signed-off-by: Tyler Hicks Cc: John Johansen Cc: Colin Ian King Cc: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/ecryptfs_kernel.h | 2 + fs/ecryptfs/file.c | 71 ++++++++++++++++++++++------------- fs/ecryptfs/inode.c | 4 +- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index 867b64c5d84..56e3aa57e18 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -568,6 +568,8 @@ struct ecryptfs_open_req { struct inode *ecryptfs_get_inode(struct inode *lower_inode, struct super_block *sb); void ecryptfs_i_size_init(const char *page_virt, struct inode *inode); +int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, + struct inode *ecryptfs_inode); int ecryptfs_decode_and_decrypt_filename(char **decrypted_name, size_t *decrypted_name_size, struct dentry *ecryptfs_dentry, diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 2b17f2f9b12..baf8b055039 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -161,6 +161,48 @@ static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma) struct kmem_cache *ecryptfs_file_info_cache; +static int read_or_initialize_metadata(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat; + struct ecryptfs_crypt_stat *crypt_stat; + int rc; + + crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + mount_crypt_stat = &ecryptfs_superblock_to_private( + inode->i_sb)->mount_crypt_stat; + mutex_lock(&crypt_stat->cs_mutex); + + if (crypt_stat->flags & ECRYPTFS_POLICY_APPLIED && + crypt_stat->flags & ECRYPTFS_KEY_VALID) { + rc = 0; + goto out; + } + + rc = ecryptfs_read_metadata(dentry); + if (!rc) + goto out; + + if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) { + crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED + | ECRYPTFS_ENCRYPTED); + rc = 0; + goto out; + } + + if (!(mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) && + !i_size_read(ecryptfs_inode_to_lower(inode))) { + rc = ecryptfs_initialize_file(dentry, inode); + if (!rc) + goto out; + } + + rc = -EIO; +out: + mutex_unlock(&crypt_stat->cs_mutex); + return rc; +} + /** * ecryptfs_open * @inode: inode speciying file to open @@ -236,32 +278,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file) rc = 0; goto out; } - mutex_lock(&crypt_stat->cs_mutex); - if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) - || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { - rc = ecryptfs_read_metadata(ecryptfs_dentry); - if (rc) { - ecryptfs_printk(KERN_DEBUG, - "Valid headers not found\n"); - if (!(mount_crypt_stat->flags - & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { - rc = -EIO; - printk(KERN_WARNING "Either the lower file " - "is not in a valid eCryptfs format, " - "or the key could not be retrieved. " - "Plaintext passthrough mode is not " - "enabled; returning -EIO\n"); - mutex_unlock(&crypt_stat->cs_mutex); - goto out_put; - } - rc = 0; - crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED - | ECRYPTFS_ENCRYPTED); - mutex_unlock(&crypt_stat->cs_mutex); - goto out; - } - } - mutex_unlock(&crypt_stat->cs_mutex); + rc = read_or_initialize_metadata(ecryptfs_dentry); + if (rc) + goto out_put; ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = " "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, (unsigned long long)i_size_read(inode)); diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index fb4a9d8f225..66bd60f6077 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -227,8 +227,8 @@ ecryptfs_do_create(struct inode *directory_inode, * * Returns zero on success */ -static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, - struct inode *ecryptfs_inode) +int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, + struct inode *ecryptfs_inode) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; From 068478a54bcd742e34b80f316472f3b06cacd8c6 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 3 Jul 2012 16:50:57 -0700 Subject: [PATCH 1264/2357] eCryptfs: Revert to a writethrough cache model commit 821f7494a77627fb1ab539591c57b22cdca702d6 upstream. A change was made about a year ago to get eCryptfs to better utilize its page cache during writes. The idea was to do the page encryption operations during page writeback, rather than doing them when initially writing into the page cache, to reduce the number of page encryption operations during sequential writes. This meant that the encrypted page would only be written to the lower filesystem during page writeback, which was a change from how eCryptfs had previously wrote to the lower filesystem in ecryptfs_write_end(). The change caused a few eCryptfs-internal bugs that were shook out. Unfortunately, more grave side effects have been identified that will force changes outside of eCryptfs. Because the lower filesystem isn't consulted until page writeback, eCryptfs has no way to pass lower write errors (ENOSPC, mainly) back to userspace. Additionaly, it was reported that quotas could be bypassed because of the way eCryptfs may sometimes open the lower filesystem using a privileged kthread. It would be nice to resolve the latest issues, but it is best if the eCryptfs commits be reverted to the old behavior in the meantime. This reverts: 32001d6f "eCryptfs: Flush file in vma close" 5be79de2 "eCryptfs: Flush dirty pages in setattr" 57db4e8d "ecryptfs: modify write path to encrypt page in writepage" Signed-off-by: Tyler Hicks Tested-by: Colin King Cc: Colin King Cc: Thieu Le Cc: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/file.c | 33 ++------------------------------- fs/ecryptfs/inode.c | 6 ------ fs/ecryptfs/mmap.c | 39 +++++++++++++-------------------------- 3 files changed, 15 insertions(+), 63 deletions(-) diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index baf8b055039..44ce5c6a541 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -138,27 +138,6 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir) return rc; } -static void ecryptfs_vma_close(struct vm_area_struct *vma) -{ - filemap_write_and_wait(vma->vm_file->f_mapping); -} - -static const struct vm_operations_struct ecryptfs_file_vm_ops = { - .close = ecryptfs_vma_close, - .fault = filemap_fault, -}; - -static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma) -{ - int rc; - - rc = generic_file_mmap(file, vma); - if (!rc) - vma->vm_ops = &ecryptfs_file_vm_ops; - - return rc; -} - struct kmem_cache *ecryptfs_file_info_cache; static int read_or_initialize_metadata(struct dentry *dentry) @@ -311,15 +290,7 @@ static int ecryptfs_release(struct inode *inode, struct file *file) static int ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) { - int rc = 0; - - rc = generic_file_fsync(file, start, end, datasync); - if (rc) - goto out; - rc = vfs_fsync_range(ecryptfs_file_to_lower(file), start, end, - datasync); -out: - return rc; + return vfs_fsync(ecryptfs_file_to_lower(file), datasync); } static int ecryptfs_fasync(int fd, struct file *file, int flag) @@ -388,7 +359,7 @@ const struct file_operations ecryptfs_main_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ecryptfs_compat_ioctl, #endif - .mmap = ecryptfs_file_mmap, + .mmap = generic_file_mmap, .open = ecryptfs_open, .flush = ecryptfs_flush, .release = ecryptfs_release, diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 66bd60f6077..11030b2fd3b 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -1016,12 +1016,6 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) goto out; } - if (S_ISREG(inode->i_mode)) { - rc = filemap_write_and_wait(inode->i_mapping); - if (rc) - goto out; - fsstack_copy_attr_all(inode, lower_inode); - } memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file); diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index a46b3a8fee1..bd1d57f98f7 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -66,18 +66,6 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) { int rc; - /* - * Refuse to write the page out if we are called from reclaim context - * since our writepage() path may potentially allocate memory when - * calling into the lower fs vfs_write() which may in turn invoke - * us again. - */ - if (current->flags & PF_MEMALLOC) { - redirty_page_for_writepage(wbc, page); - rc = 0; - goto out; - } - rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting " @@ -498,7 +486,6 @@ static int ecryptfs_write_end(struct file *file, struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; int rc; - int need_unlock_page = 1; ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" "(page w/ index = [0x%.16lx], to = [%d])\n", index, to); @@ -519,26 +506,26 @@ static int ecryptfs_write_end(struct file *file, "zeros in page with index = [0x%.16lx]\n", index); goto out; } - set_page_dirty(page); - unlock_page(page); - need_unlock_page = 0; + rc = ecryptfs_encrypt_page(page); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " + "index [0x%.16lx])\n", index); + goto out; + } if (pos + copied > i_size_read(ecryptfs_inode)) { i_size_write(ecryptfs_inode, pos + copied); ecryptfs_printk(KERN_DEBUG, "Expanded file size to " "[0x%.16llx]\n", (unsigned long long)i_size_read(ecryptfs_inode)); - balance_dirty_pages_ratelimited(mapping); - rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); - if (rc) { - printk(KERN_ERR "Error writing inode size to metadata; " - "rc = [%d]\n", rc); - goto out; - } } - rc = copied; + rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); + if (rc) + printk(KERN_ERR "Error writing inode size to metadata; " + "rc = [%d]\n", rc); + else + rc = copied; out: - if (need_unlock_page) - unlock_page(page); + unlock_page(page); page_cache_release(page); return rc; } From e7ba1a13e4c4d315d94afb45e6dfaa7c543d9ba2 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Wed, 12 Sep 2012 18:02:46 -0700 Subject: [PATCH 1265/2357] eCryptfs: Write out all dirty pages just before releasing the lower file commit 7149f2558d5b5b988726662fe58b1c388337805b upstream. Fixes a regression caused by: 821f749 eCryptfs: Revert to a writethrough cache model That patch reverted some code (specifically, 32001d6f) that was necessary to properly handle open() -> mmap() -> close() -> dirty pages -> munmap(), because the lower file could be closed before the dirty pages are written out. Rather than reapplying 32001d6f, this approach is a better way of ensuring that the lower file is still open in order to handle writing out the dirty pages. It is called from ecryptfs_release(), while we have a lock on the lower file pointer, just before the lower file gets the final fput() and we overwrite the pointer. https://launchpad.net/bugs/1047261 Signed-off-by: Tyler Hicks Reported-by: Artemy Tregubenko Tested-by: Artemy Tregubenko Tested-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 68954937a07..0f04d2eb9a6 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -162,6 +162,7 @@ void ecryptfs_put_lower_file(struct inode *inode) inode_info = ecryptfs_inode_to_private(inode); if (atomic_dec_and_mutex_lock(&inode_info->lower_file_count, &inode_info->lower_file_mutex)) { + filemap_write_and_wait(inode->i_mapping); fput(inode_info->lower_file); inode_info->lower_file = NULL; mutex_unlock(&inode_info->lower_file_mutex); From a5b9aa5533324fc9e3c2abe24ef335245473c331 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Wed, 12 Sep 2012 18:38:00 -0700 Subject: [PATCH 1266/2357] eCryptfs: Call lower ->flush() from ecryptfs_flush() commit 64e6651dcc10e9d2cc6230208a8e6c2cfd19ae18 upstream. Since eCryptfs only calls fput() on the lower file in ecryptfs_release(), eCryptfs should call the lower filesystem's ->flush() from ecryptfs_flush(). If the lower filesystem implements ->flush(), then eCryptfs should try to flush out any dirty pages prior to calling the lower ->flush(). If the lower filesystem does not implement ->flush(), then eCryptfs has no need to do anything in ecryptfs_flush() since dirty pages are now written out to the lower filesystem in ecryptfs_release(). Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/file.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 44ce5c6a541..d45ba456812 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -275,8 +275,14 @@ static int ecryptfs_open(struct inode *inode, struct file *file) static int ecryptfs_flush(struct file *file, fl_owner_t td) { - return file->f_mode & FMODE_WRITE - ? filemap_write_and_wait(file->f_mapping) : 0; + struct file *lower_file = ecryptfs_file_to_lower(file); + + if (lower_file->f_op && lower_file->f_op->flush) { + filemap_write_and_wait(file->f_mapping); + return lower_file->f_op->flush(lower_file, td); + } + + return 0; } static int ecryptfs_release(struct inode *inode, struct file *file) From 7ec51fc74149ac5caafffce2b065e25ef621e2c1 Mon Sep 17 00:00:00 2001 From: Fabio Porcedda Date: Fri, 7 Sep 2012 15:27:42 +0200 Subject: [PATCH 1267/2357] usb: gadget: at91_udc: fix dt support commit 9c6d196d5aa35e07482f23c3e37755e7a82140e0 upstream. Don't fail the initialization check for the platform_data if there is avaiable an associated device tree node. Signed-off-by: Fabio Porcedda Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 9d7bcd91007..be6952e2fc5 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1735,7 +1735,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) int retval; struct resource *res; - if (!dev->platform_data) { + if (!dev->platform_data && !pdev->dev.of_node) { /* small (so we copy it) but critical! */ DBG("missing platform_data\n"); return -ENODEV; From bb4e97376e84d98994a5f576e2bd080d3aeee232 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 17 Oct 2012 12:43:44 +0200 Subject: [PATCH 1268/2357] ALSA: hda - Always check array bounds in alc_get_line_out_pfx commit 71aa5ebe36a4e936eff281b375a4707b6a8320f2 upstream. Even when CONFIG_SND_DEBUG is not enabled, we don't want to return an arbitrary memory location when the channel count is larger than we expected. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 94747f8a249..94b765b31ea 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2665,8 +2665,10 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, return "PCM"; break; } - if (snd_BUG_ON(ch >= ARRAY_SIZE(channel_name))) + if (ch >= ARRAY_SIZE(channel_name)) { + snd_BUG(); return "PCM"; + } return channel_name[ch]; } From e9eeac8fd06a74dfcadac8970b7d5797dab652c1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 3 Oct 2012 14:33:50 +0200 Subject: [PATCH 1269/2357] ASoC: fsi: don't reschedule DMA from an atomic context commit 57451e437796548d658d03c2c4aab659eafcd799 upstream. shdma doesn't support transfer re-scheduling or triggering from callbacks or from atomic context. The fsi driver issues DMA transfers from a tasklet context, which is a bug. To fix it convert tasklet to a work. Reported-by: Do Q.Thang Tested-by: Do Q.Thang Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/sh/fsi.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 74ed2dffbff..91b728774db 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -199,7 +200,7 @@ struct fsi_stream { */ struct dma_chan *chan; struct sh_dmae_slave slave; /* see fsi_handler_init() */ - struct tasklet_struct tasklet; + struct work_struct work; dma_addr_t dma; }; @@ -968,9 +969,9 @@ static dma_addr_t fsi_dma_get_area(struct fsi_stream *io) return io->dma + samples_to_bytes(runtime, io->buff_sample_pos); } -static void fsi_dma_do_tasklet(unsigned long data) +static void fsi_dma_do_work(struct work_struct *work) { - struct fsi_stream *io = (struct fsi_stream *)data; + struct fsi_stream *io = container_of(work, struct fsi_stream, work); struct fsi_priv *fsi = fsi_stream_to_priv(io); struct dma_chan *chan; struct snd_soc_dai *dai; @@ -1023,7 +1024,7 @@ static void fsi_dma_do_tasklet(unsigned long data) * FIXME * * In DMAEngine case, codec and FSI cannot be started simultaneously - * since FSI is using tasklet. + * since FSI is using the scheduler work queue. * Therefore, in capture case, probably FSI FIFO will have got * overflow error in this point. * in that case, DMA cannot start transfer until error was cleared. @@ -1047,7 +1048,7 @@ static bool fsi_dma_filter(struct dma_chan *chan, void *param) static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) { - tasklet_schedule(&io->tasklet); + schedule_work(&io->work); return 0; } @@ -1087,14 +1088,14 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) if (!io->chan) return -EIO; - tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io); + INIT_WORK(&io->work, fsi_dma_do_work); return 0; } static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) { - tasklet_kill(&io->tasklet); + cancel_work_sync(&io->work); fsi_stream_stop(fsi, io); From efd9aa3512ecac932b8b9baebd4ca00c3a44394f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Oct 2012 12:02:48 +0100 Subject: [PATCH 1270/2357] ASoC: wm2200: Use rev A register patches on rev B commit 5ae9eb4cbdfd640269dbd66aa3c92ea8e11cc838 upstream. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm2200.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 32682c1b7cd..58ab97a143d 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2091,6 +2091,7 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, switch (wm2200->rev) { case 0: + case 1: ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch, ARRAY_SIZE(wm2200_reva_patch)); if (ret != 0) { From eb695eec8d6fc5b757c05c6538346ef04d091055 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Oct 2012 19:10:43 +0100 Subject: [PATCH 1271/2357] ASoC: wm2200: Fix non-inverted OUT2 mute control commit a1b98e12b7f8fad2f0aa3c08a3302bcac7ae1ec7 upstream. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 58ab97a143d..c8bff6da532 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1028,7 +1028,7 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L, WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0, digital_tlv), SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT, - WM2200_SPK1R_MUTE_SHIFT, 1, 0), + WM2200_SPK1R_MUTE_SHIFT, 1, 1), }; WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE); From 60dd77abe18a5a3eb21c4041f6ea02b45c421cc5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Oct 2012 15:31:16 +0300 Subject: [PATCH 1272/2357] ASoC: omap-abe-twl6040: Fix typo of Vibrator commit 034940a6b3afbe79022ab6922dd9d2982b78e6d5 upstream. It is not Vinrator but Vibrator. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/omap/omap-abe-twl6040.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 93bb8eee22b..9c2f090167c 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -181,7 +181,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); - twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); + twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vibrator"); twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); From e503f73ae9607b0d4854a40a2f437cfbee529fa3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Oct 2012 16:43:40 +0200 Subject: [PATCH 1273/2357] ALSA: ac97 - Fix missing NULL check in snd_ac97_cvol_new() commit 733a48e5ae5bf28b046fad984d458c747cbb8c21 upstream. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=44721 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/ac97/ac97_codec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 9473fca9681..8b0f9968830 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1271,6 +1271,8 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne tmp.index = ac97->num; kctl = snd_ctl_new1(&tmp, ac97); } + if (!kctl) + return -ENOMEM; if (reg >= AC97_PHONE && reg <= AC97_PCM) set_tlv_db_scale(kctl, db_scale_5bit_12db_max); else From a6b5c98460148487422c5ceb5bcc88cfdb0a850f Mon Sep 17 00:00:00 2001 From: Maxim Kachur Date: Wed, 17 Oct 2012 18:18:10 +0200 Subject: [PATCH 1274/2357] ALSA: emu10k1: add chip details for E-mu 1010 PCIe card commit 10f571d09106c3eb85951896522c9650596eff2e upstream. Add chip details for E-mu 1010 PCIe card. It has the same chip as found in E-mu 1010b but it uses different PCI id. Signed-off-by: Maxim Kachur Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/emu10k1/emu10k1_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 754924081d0..a78fdf466fa 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1416,6 +1416,15 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0108_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */ + /* Tested by Maxim Kachur 17th Oct 2012. */ + /* This is MAEM8986, 0202 is MAEM8980 */ + {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40071102, + .driver = "Audigy2", .name = "E-mu 1010 PCIe [MAEM8986]", + .id = "EMU1010", + .emu10k2_chip = 1, + .ca0108_chip = 1, + .spk71 = 1, + .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 PCIe */ /* Tested by James@superbug.co.uk 8th July 2005. */ /* This is MAEM8810, 0202 is MAEM8820 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, From 553f672df76c6213b9a7e644b1d878204a61e013 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 21 Oct 2012 09:28:17 -0700 Subject: [PATCH 1275/2357] Linux 3.4.15 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d174c84cc73..fe9ea67db86 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 14 +SUBLEVEL = 15 EXTRAVERSION = NAME = Saber-toothed Squirrel From 4319fd00002630a761fa5559a086f11ed7623006 Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov Date: Wed, 10 Oct 2012 01:04:58 -0400 Subject: [PATCH 1276/2357] ext4: race-condition protection for ext4_convert_unwritten_extents_endio commit dee1f973ca341c266229faa5a1a5bb268bed3531 upstream. We assumed that at the time we call ext4_convert_unwritten_extents_endio() extent in question is fully inside [map.m_lblk, map->m_len] because it was already split during submission. But this may not be true due to a race between writeback vs fallocate. If extent in question is larger than requested we will split it again. Special precautions should being done if zeroout required because [map.m_lblk, map->m_len] already contains valid data. Signed-off-by: Dmitry Monakhov Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/extents.c | 57 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 8b384cc3b75..c2159854258 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -52,6 +52,9 @@ #define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */ #define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */ +#define EXT4_EXT_DATA_VALID1 0x8 /* first half contains valid data */ +#define EXT4_EXT_DATA_VALID2 0x10 /* second half contains valid data */ + static int ext4_split_extent(handle_t *handle, struct inode *inode, struct ext4_ext_path *path, @@ -2829,6 +2832,9 @@ static int ext4_split_extent_at(handle_t *handle, unsigned int ee_len, depth; int err = 0; + BUG_ON((split_flag & (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)) == + (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)); + ext_debug("ext4_split_extents_at: inode %lu, logical" "block %llu\n", inode->i_ino, (unsigned long long)split); @@ -2887,7 +2893,14 @@ static int ext4_split_extent_at(handle_t *handle, err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) { - err = ext4_ext_zeroout(inode, &orig_ex); + if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) { + if (split_flag & EXT4_EXT_DATA_VALID1) + err = ext4_ext_zeroout(inode, ex2); + else + err = ext4_ext_zeroout(inode, ex); + } else + err = ext4_ext_zeroout(inode, &orig_ex); + if (err) goto fix_extent_len; /* update the extent length and mark as initialized */ @@ -2940,12 +2953,13 @@ static int ext4_split_extent(handle_t *handle, uninitialized = ext4_ext_is_uninitialized(ex); if (map->m_lblk + map->m_len < ee_block + ee_len) { - split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT ? - EXT4_EXT_MAY_ZEROOUT : 0; + split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT; flags1 = flags | EXT4_GET_BLOCKS_PRE_IO; if (uninitialized) split_flag1 |= EXT4_EXT_MARK_UNINIT1 | EXT4_EXT_MARK_UNINIT2; + if (split_flag & EXT4_EXT_DATA_VALID2) + split_flag1 |= EXT4_EXT_DATA_VALID1; err = ext4_split_extent_at(handle, inode, path, map->m_lblk + map->m_len, split_flag1, flags1); if (err) @@ -2958,8 +2972,8 @@ static int ext4_split_extent(handle_t *handle, return PTR_ERR(path); if (map->m_lblk >= ee_block) { - split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT ? - EXT4_EXT_MAY_ZEROOUT : 0; + split_flag1 = split_flag & (EXT4_EXT_MAY_ZEROOUT | + EXT4_EXT_DATA_VALID2); if (uninitialized) split_flag1 |= EXT4_EXT_MARK_UNINIT1; if (split_flag & EXT4_EXT_MARK_UNINIT2) @@ -3237,26 +3251,47 @@ static int ext4_split_unwritten_extents(handle_t *handle, split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0; split_flag |= EXT4_EXT_MARK_UNINIT2; - + if (flags & EXT4_GET_BLOCKS_CONVERT) + split_flag |= EXT4_EXT_DATA_VALID2; flags |= EXT4_GET_BLOCKS_PRE_IO; return ext4_split_extent(handle, inode, path, map, split_flag, flags); } static int ext4_convert_unwritten_extents_endio(handle_t *handle, - struct inode *inode, - struct ext4_ext_path *path) + struct inode *inode, + struct ext4_map_blocks *map, + struct ext4_ext_path *path) { struct ext4_extent *ex; + ext4_lblk_t ee_block; + unsigned int ee_len; int depth; int err = 0; depth = ext_depth(inode); ex = path[depth].p_ext; + ee_block = le32_to_cpu(ex->ee_block); + ee_len = ext4_ext_get_actual_len(ex); ext_debug("ext4_convert_unwritten_extents_endio: inode %lu, logical" "block %llu, max_blocks %u\n", inode->i_ino, - (unsigned long long)le32_to_cpu(ex->ee_block), - ext4_ext_get_actual_len(ex)); + (unsigned long long)ee_block, ee_len); + + /* If extent is larger than requested then split is required */ + if (ee_block != map->m_lblk || ee_len > map->m_len) { + err = ext4_split_unwritten_extents(handle, inode, map, path, + EXT4_GET_BLOCKS_CONVERT); + if (err < 0) + goto out; + ext4_ext_drop_refs(path); + path = ext4_ext_find_extent(inode, map->m_lblk, path); + if (IS_ERR(path)) { + err = PTR_ERR(path); + goto out; + } + depth = ext_depth(inode); + ex = path[depth].p_ext; + } err = ext4_ext_get_access(handle, inode, path + depth); if (err) @@ -3564,7 +3599,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, } /* IO end_io complete, convert the filled extent to written */ if ((flags & EXT4_GET_BLOCKS_CONVERT)) { - ret = ext4_convert_unwritten_extents_endio(handle, inode, + ret = ext4_convert_unwritten_extents_endio(handle, inode, map, path); if (ret >= 0) { ext4_update_inode_fsync_trans(handle, inode, 1); From 2807664df50419f56b596aa49da8a22102c0e0a3 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Mon, 22 Oct 2012 18:01:19 -0400 Subject: [PATCH 1277/2357] ext4: Avoid underflow in ext4_trim_fs() commit 5de35e8d5c02d271c20e18337e01bc20e6ef472e upstream. Currently if len argument in ext4_trim_fs() is smaller than one block, the 'end' variable underflow. Avoid that by returning EINVAL if len is smaller than file system block. Also remove useless unlikely(). Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/mballoc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 6b0a57eafb5..e77c4fe665a 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -4984,8 +4984,9 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) end = start + (range->len >> sb->s_blocksize_bits) - 1; minlen = range->minlen >> sb->s_blocksize_bits; - if (unlikely(minlen > EXT4_CLUSTERS_PER_GROUP(sb)) || - unlikely(start >= max_blks)) + if (minlen > EXT4_CLUSTERS_PER_GROUP(sb) || + start >= max_blks || + range->len < sb->s_blocksize) return -EINVAL; if (end >= max_blks) end = max_blks - 1; From d39bd2701f0f414aba1376ae61202b526ec7e128 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Wed, 10 Oct 2012 11:51:09 +0530 Subject: [PATCH 1278/2357] nohz: Fix idle ticks in cpu summary line of /proc/stat commit 7386cdbf2f57ea8cff3c9fde93f206e58b9fe13f upstream. Git commit 09a1d34f8535ecf9 "nohz: Make idle/iowait counter update conditional" introduced a bug in regard to cpu hotplug. The effect is that the number of idle ticks in the cpu summary line in /proc/stat is still counting ticks for offline cpus. Reproduction is easy, just start a workload that keeps all cpus busy, switch off one or more cpus and then watch the idle field in top. On a dual-core with one cpu 100% busy and one offline cpu you will get something like this: %Cpu(s): 48.7 us, 1.3 sy, 0.0 ni, 50.0 id, 0.0 wa, 0.0 hi, 0.0 si, %0.0 st The problem is that an offline cpu still has ts->idle_active == 1. To fix this we should make sure that the cpu is online when calling get_cpu_idle_time_us and get_cpu_iowait_time_us. [Srivatsa: Rebased to current mainline] Reported-by: Martin Schwidefsky Signed-off-by: Michal Hocko Reviewed-by: Srivatsa S. Bhat Signed-off-by: Srivatsa S. Bhat Link: http://lkml.kernel.org/r/20121010061820.8999.57245.stgit@srivatsabhat.in.ibm.com Cc: deepthi@linux.vnet.ibm.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- fs/proc/stat.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 64c3b317236..e296572c73e 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c @@ -45,10 +45,13 @@ static cputime64_t get_iowait_time(int cpu) static u64 get_idle_time(int cpu) { - u64 idle, idle_time = get_cpu_idle_time_us(cpu, NULL); + u64 idle, idle_time = -1ULL; + + if (cpu_online(cpu)) + idle_time = get_cpu_idle_time_us(cpu, NULL); if (idle_time == -1ULL) - /* !NO_HZ so we can rely on cpustat.idle */ + /* !NO_HZ or cpu offline so we can rely on cpustat.idle */ idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; else idle = usecs_to_cputime64(idle_time); @@ -58,10 +61,13 @@ static u64 get_idle_time(int cpu) static u64 get_iowait_time(int cpu) { - u64 iowait, iowait_time = get_cpu_iowait_time_us(cpu, NULL); + u64 iowait, iowait_time = -1ULL; + + if (cpu_online(cpu)) + iowait_time = get_cpu_iowait_time_us(cpu, NULL); if (iowait_time == -1ULL) - /* !NO_HZ so we can rely on cpustat.iowait */ + /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */ iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT]; else iowait = usecs_to_cputime64(iowait_time); From 75383fac9206c9dc57a5f153ffabcd5341ad0c28 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Fri, 19 Oct 2012 11:43:11 -0400 Subject: [PATCH 1279/2357] arch/tile: avoid generating .eh_frame information in modules commit 627072b06c362bbe7dc256f618aaa63351f0cfe6 upstream. The tile tool chain uses the .eh_frame information for backtracing. The vmlinux build drops any .eh_frame sections at link time, but when present in kernel modules, it causes a module load failure due to the presence of unsupported pc-relative relocations. When compiling to use compiler feedback support, the compiler by default omits .eh_frame information, so we don't see this problem. But when not using feedback, we need to explicitly suppress the .eh_frame. Signed-off-by: Chris Metcalf Signed-off-by: Greg Kroah-Hartman --- arch/tile/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/tile/Makefile b/arch/tile/Makefile index 9520bc5a4b7..99f461d8d9d 100644 --- a/arch/tile/Makefile +++ b/arch/tile/Makefile @@ -26,6 +26,10 @@ $(error Set TILERA_ROOT or CROSS_COMPILE when building $(ARCH) on $(HOST_ARCH)) endif endif +# The tile compiler may emit .eh_frame information for backtracing. +# In kernel modules, this causes load failures due to unsupported relocations. +KBUILD_CFLAGS += -fno-asynchronous-unwind-tables + ifneq ($(CONFIG_DEBUG_EXTRA_FLAGS),"") KBUILD_CFLAGS += $(CONFIG_DEBUG_EXTRA_FLAGS) endif From 08eaf6a4ee82eb566c188f71b33f52e780fab57d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 13 Oct 2012 00:30:28 -0400 Subject: [PATCH 1280/2357] NLM: nlm_lookup_file() may return NLMv4-specific error codes commit cd0b16c1c3cda12dbed1f8de8f1a9b0591990724 upstream. If the filehandle is stale, or open access is denied for some reason, nlm_fopen() may return one of the NLMv4-specific error codes nlm4_stale_fh or nlm4_failed. These get passed right through nlm_lookup_file(), and so when nlmsvc_retrieve_args() calls the latter, it needs to filter the result through the cast_status() machinery. Failure to do so, will trigger the BUG_ON() in encode_nlm_stat... Signed-off-by: Trond Myklebust Reported-by: Larry McVoy Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/lockd/clntxdr.c | 2 +- fs/lockd/svcproc.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/lockd/clntxdr.c b/fs/lockd/clntxdr.c index d269ada7670..982d2676e1f 100644 --- a/fs/lockd/clntxdr.c +++ b/fs/lockd/clntxdr.c @@ -223,7 +223,7 @@ static void encode_nlm_stat(struct xdr_stream *xdr, { __be32 *p; - BUG_ON(be32_to_cpu(stat) > NLM_LCK_DENIED_GRACE_PERIOD); + WARN_ON_ONCE(be32_to_cpu(stat) > NLM_LCK_DENIED_GRACE_PERIOD); p = xdr_reserve_space(xdr, 4); *p = stat; } diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index d27aab11f32..d413af338da 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -67,7 +67,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain file pointer. Not used by FREE_ALL call. */ if (filp != NULL) { - if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0) + error = cast_status(nlm_lookup_file(rqstp, &file, &lock->fh)); + if (error != 0) goto no_locks; *filp = file; From d641457de0939adaa140161127f2f72bcfe50b37 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 10 Oct 2012 10:18:35 +0300 Subject: [PATCH 1281/2357] oprofile, x86: Fix wrapping bug in op_x86_get_ctrl() commit 44009105081b51417f311f4c3be0061870b6b8ed upstream. The "event" variable is a u16 so the shift will always wrap to zero making the line a no-op. Signed-off-by: Dan Carpenter Signed-off-by: Robert Richter Signed-off-by: Greg Kroah-Hartman --- arch/x86/oprofile/nmi_int.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 26b8a8514ee..48768df2471 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -55,7 +55,7 @@ u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, val |= counter_config->extra; event &= model->event_mask ? model->event_mask : 0xFF; val |= event & 0xFF; - val |= (event & 0x0F00) << 24; + val |= (u64)(event & 0x0F00) << 24; return val; } From 1b91a891bc337ecec08dea5436be0bbb03fec12b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 18 Oct 2012 11:11:01 +0200 Subject: [PATCH 1282/2357] s390: fix linker script for 31 bit builds commit c985cb37f1b39c2c8035af741a2a0b79f1fbaca7 upstream. Because of a change in the s390 arch backend of binutils (commit 23ecd77 "Pick the default arch depending on the target size" in binutils repo) 31 bit builds will fail since the linker would now try to create 64 bit binary output. Fix this by setting OUTPUT_ARCH to s390:31-bit instead of s390. Thanks to Andreas Krebbel for figuring out the issue. Fixes this build error: LD init/built-in.o s390x-4.7.2-ld: s390:31-bit architecture of input file `arch/s390/kernel/head.o' is incompatible with s390:64-bit output Cc: Andreas Krebbel Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/boot/compressed/vmlinux.lds.S | 2 +- arch/s390/kernel/vmlinux.lds.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/boot/compressed/vmlinux.lds.S b/arch/s390/boot/compressed/vmlinux.lds.S index d80f79d8dd9..8e1fb823928 100644 --- a/arch/s390/boot/compressed/vmlinux.lds.S +++ b/arch/s390/boot/compressed/vmlinux.lds.S @@ -5,7 +5,7 @@ OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390") OUTPUT_ARCH(s390:64-bit) #else OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390") -OUTPUT_ARCH(s390) +OUTPUT_ARCH(s390:31-bit) #endif ENTRY(startup) diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 21109c63eb1..1343d7cf444 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -8,7 +8,7 @@ #ifndef CONFIG_64BIT OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390") -OUTPUT_ARCH(s390) +OUTPUT_ARCH(s390:31-bit) ENTRY(startup) jiffies = jiffies_64 + 4; #else From baecc6ef799c7ab9a5fc0ba29ee560a5c264f306 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Tue, 17 Jul 2012 00:01:26 +0200 Subject: [PATCH 1283/2357] SUNRPC: Prevent kernel stack corruption on long values of flush commit 212ba90696ab4884e2025b0b13726d67aadc2cd4 upstream. The buffer size in read_flush() is too small for the longest possible values for it. This can lead to a kernel stack corruption: [ 43.047329] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffffff833e64b4 [ 43.047329] [ 43.049030] Pid: 6015, comm: trinity-child18 Tainted: G W 3.5.0-rc7-next-20120716-sasha #221 [ 43.050038] Call Trace: [ 43.050435] [] panic+0xcd/0x1f4 [ 43.050931] [] ? read_flush.isra.7+0xe4/0x100 [ 43.051602] [] __stack_chk_fail+0x16/0x20 [ 43.052206] [] read_flush.isra.7+0xe4/0x100 [ 43.052951] [] ? read_flush_pipefs+0x30/0x30 [ 43.053594] [] read_flush_procfs+0x2c/0x30 [ 43.053596] [] proc_reg_read+0x9c/0xd0 [ 43.053596] [] ? proc_reg_write+0xd0/0xd0 [ 43.053596] [] do_loop_readv_writev+0x4b/0x90 [ 43.053596] [] do_readv_writev+0xf6/0x1d0 [ 43.053596] [] vfs_readv+0x3e/0x60 [ 43.053596] [] sys_readv+0x48/0xb0 [ 43.053596] [] system_call_fastpath+0x1a/0x1f Signed-off-by: Sasha Levin Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/cache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index de0b0f39d9d..76cb304f3f1 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1406,11 +1406,11 @@ static ssize_t read_flush(struct file *file, char __user *buf, size_t count, loff_t *ppos, struct cache_detail *cd) { - char tbuf[20]; + char tbuf[22]; unsigned long p = *ppos; size_t len; - sprintf(tbuf, "%lu\n", convert_to_wallclock(cd->flush_time)); + snprintf(tbuf, sizeof(tbuf), "%lu\n", convert_to_wallclock(cd->flush_time)); len = strlen(tbuf); if (p >= len) return 0; From 9b62355a6daff8696ec7f7b1283b6a39650b9f14 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 22 Oct 2012 12:56:58 -0400 Subject: [PATCH 1284/2357] SUNRPC: Fix a UDP transport regression commit f39c1bfb5a03e2d255451bff05be0d7255298fa4 and commit 84e28a307e376f271505af65a7b7e212dd6f61f4 upstream. Commit 43cedbf0e8dfb9c5610eb7985d5f21263e313802 (SUNRPC: Ensure that we grab the XPRT_LOCK before calling xprt_alloc_slot) is causing hangs in the case of NFS over UDP mounts. Since neither the UDP or the RDMA transport mechanism use dynamic slot allocation, we can skip grabbing the socket lock for those transports. Add a new rpc_xprt_op to allow switching between the TCP and UDP/RDMA case. Note that the NFSv4.1 back channel assigns the slot directly through rpc_run_bc_task, so we can ignore that case. Reported-by: Dick Streefland Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- include/linux/sunrpc/xprt.h | 3 +++ net/sunrpc/xprt.c | 34 +++++++++++++++++++-------------- net/sunrpc/xprtrdma/transport.c | 1 + net/sunrpc/xprtsock.c | 4 ++++ 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 77d278defa7..005b507d6d7 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -114,6 +114,7 @@ struct rpc_xprt_ops { void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); int (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); + void (*alloc_slot)(struct rpc_xprt *xprt, struct rpc_task *task); void (*rpcbind)(struct rpc_task *task); void (*set_port)(struct rpc_xprt *xprt, unsigned short port); void (*connect)(struct rpc_task *task); @@ -279,6 +280,8 @@ void xprt_connect(struct rpc_task *task); void xprt_reserve(struct rpc_task *task); int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task); int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); +void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); +void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); int xprt_prepare_transmit(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); void xprt_end_transmit(struct rpc_task *task); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index da72492360b..176a24f0153 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -969,11 +969,11 @@ static bool xprt_dynamic_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) return false; } -static void xprt_alloc_slot(struct rpc_task *task) +void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) { - struct rpc_xprt *xprt = task->tk_xprt; struct rpc_rqst *req; + spin_lock(&xprt->reserve_lock); if (!list_empty(&xprt->free)) { req = list_entry(xprt->free.next, struct rpc_rqst, rq_list); list_del(&req->rq_list); @@ -994,12 +994,29 @@ static void xprt_alloc_slot(struct rpc_task *task) default: task->tk_status = -EAGAIN; } + spin_unlock(&xprt->reserve_lock); return; out_init_req: task->tk_status = 0; task->tk_rqstp = req; xprt_request_init(task, xprt); + spin_unlock(&xprt->reserve_lock); +} +EXPORT_SYMBOL_GPL(xprt_alloc_slot); + +void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) +{ + /* Note: grabbing the xprt_lock_write() ensures that we throttle + * new slot allocation if the transport is congested (i.e. when + * reconnecting a stream transport or when out of socket write + * buffer space). + */ + if (xprt_lock_write(xprt, task)) { + xprt_alloc_slot(xprt, task); + xprt_release_write(xprt, task); + } } +EXPORT_SYMBOL_GPL(xprt_lock_and_alloc_slot); static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) { @@ -1083,20 +1100,9 @@ void xprt_reserve(struct rpc_task *task) if (task->tk_rqstp != NULL) return; - /* Note: grabbing the xprt_lock_write() here is not strictly needed, - * but ensures that we throttle new slot allocation if the transport - * is congested (e.g. if reconnecting or if we're out of socket - * write buffer space). - */ task->tk_timeout = 0; task->tk_status = -EAGAIN; - if (!xprt_lock_write(xprt, task)) - return; - - spin_lock(&xprt->reserve_lock); - xprt_alloc_slot(task); - spin_unlock(&xprt->reserve_lock); - xprt_release_write(xprt, task); + xprt->ops->alloc_slot(xprt, task); } static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt) diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 06cdbff79e4..5d9202dc7cb 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -713,6 +713,7 @@ static void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) static struct rpc_xprt_ops xprt_rdma_procs = { .reserve_xprt = xprt_rdma_reserve_xprt, .release_xprt = xprt_release_xprt_cong, /* sunrpc/xprt.c */ + .alloc_slot = xprt_alloc_slot, .release_request = xprt_release_rqst_cong, /* ditto */ .set_retrans_timeout = xprt_set_retrans_timeout_def, /* ditto */ .rpcbind = rpcb_getport_async, /* sunrpc/rpcb_clnt.c */ diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 00ff34343ba..a4a6586f403 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2444,6 +2444,7 @@ static void bc_destroy(struct rpc_xprt *xprt) static struct rpc_xprt_ops xs_local_ops = { .reserve_xprt = xprt_reserve_xprt, .release_xprt = xs_tcp_release_xprt, + .alloc_slot = xprt_alloc_slot, .rpcbind = xs_local_rpcbind, .set_port = xs_local_set_port, .connect = xs_connect, @@ -2460,6 +2461,7 @@ static struct rpc_xprt_ops xs_udp_ops = { .set_buffer_size = xs_udp_set_buffer_size, .reserve_xprt = xprt_reserve_xprt_cong, .release_xprt = xprt_release_xprt_cong, + .alloc_slot = xprt_alloc_slot, .rpcbind = rpcb_getport_async, .set_port = xs_set_port, .connect = xs_connect, @@ -2477,6 +2479,7 @@ static struct rpc_xprt_ops xs_udp_ops = { static struct rpc_xprt_ops xs_tcp_ops = { .reserve_xprt = xprt_reserve_xprt, .release_xprt = xs_tcp_release_xprt, + .alloc_slot = xprt_lock_and_alloc_slot, .rpcbind = rpcb_getport_async, .set_port = xs_set_port, .connect = xs_connect, @@ -2496,6 +2499,7 @@ static struct rpc_xprt_ops xs_tcp_ops = { static struct rpc_xprt_ops bc_tcp_ops = { .reserve_xprt = xprt_reserve_xprt, .release_xprt = xprt_release_xprt, + .alloc_slot = xprt_alloc_slot, .rpcbind = xs_local_rpcbind, .buf_alloc = bc_malloc, .buf_free = bc_free, From 6eca486b8d28b1fe1d147cf55dfb8832099bb0a2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 30 Apr 2012 13:50:56 +0000 Subject: [PATCH 1285/2357] pcmcia: sharpsl: don't discard sharpsl_pcmcia_ops commit fdc858a466b738d35d3492bc7cf77b1dac98bf7c upstream. The sharpsl_pcmcia_ops structure gets passed into sa11xx_drv_pcmcia_probe, where it gets accessed at run-time, unlike all other pcmcia drivers that pass their structures into platform_device_add_data, which makes a copy. This means the gcc warning is valid and the structure must not be marked as __initdata. Without this patch, building collie_defconfig results in: drivers/pcmcia/pxa2xx_sharpsl.c:22:31: fatal error: mach-pxa/hardware.h: No such file or directory compilation terminated. make[3]: *** [drivers/pcmcia/pxa2xx_sharpsl.o] Error 1 make[2]: *** [drivers/pcmcia] Error 2 make[1]: *** [drivers] Error 2 make: *** [sub-make] Error 2 Signed-off-by: Arnd Bergmann Cc: Dominik Brodowski Cc: Russell King Cc: Pavel Machek Cc: linux-pcmcia@lists.infradead.org Cc: Jochen Friedrich Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/pxa2xx_sharpsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index b066273b6b4..7dd879ce514 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -194,7 +194,7 @@ static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) sharpsl_pcmcia_init_reset(skt); } -static struct pcmcia_low_level sharpsl_pcmcia_ops __initdata = { +static struct pcmcia_low_level sharpsl_pcmcia_ops = { .owner = THIS_MODULE, .hw_init = sharpsl_pcmcia_hw_init, .socket_state = sharpsl_pcmcia_socket_state, From 643fde8ed4ea75f5d113803084806eff14d97454 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 19 Oct 2012 13:56:51 -0700 Subject: [PATCH 1286/2357] kernel/sys.c: fix stack memory content leak via UNAME26 commit 2702b1526c7278c4d65d78de209a465d4de2885e upstream. Calling uname() with the UNAME26 personality set allows a leak of kernel stack contents. This fixes it by defensively calculating the length of copy_to_user() call, making the len argument unsigned, and initializing the stack buffer to zero (now technically unneeded, but hey, overkill). CVE-2012-0957 Reported-by: PaX Team Signed-off-by: Kees Cook Cc: Andi Kleen Cc: PaX Team Cc: Brad Spengler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/sys.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/kernel/sys.c b/kernel/sys.c index 898a84c9df5..d041cc720c6 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1180,15 +1180,16 @@ DECLARE_RWSEM(uts_sem); * Work around broken programs that cannot handle "Linux 3.0". * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40 */ -static int override_release(char __user *release, int len) +static int override_release(char __user *release, size_t len) { int ret = 0; - char buf[65]; if (current->personality & UNAME26) { - char *rest = UTS_RELEASE; + const char *rest = UTS_RELEASE; + char buf[65] = { 0 }; int ndots = 0; unsigned v; + size_t copy; while (*rest) { if (*rest == '.' && ++ndots >= 3) @@ -1198,8 +1199,9 @@ static int override_release(char __user *release, int len) rest++; } v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40; - snprintf(buf, len, "2.6.%u%s", v, rest); - ret = copy_to_user(release, buf, len); + copy = min(sizeof(buf), max_t(size_t, 1, len)); + copy = scnprintf(buf, copy, "2.6.%u%s", v, rest); + ret = copy_to_user(release, buf, copy + 1); } return ret; } From 3680030e9747dfa51fe9c1850361c29ae0ad20fe Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 19 Oct 2012 18:45:53 -0700 Subject: [PATCH 1287/2357] use clamp_t in UNAME26 fix commit 31fd84b95eb211d5db460a1dda85e004800a7b52 upstream. The min/max call needed to have explicit types on some architectures (e.g. mn10300). Use clamp_t instead to avoid the warning: kernel/sys.c: In function 'override_release': kernel/sys.c:1287:10: warning: comparison of distinct pointer types lacks a cast [enabled by default] Reported-by: Fengguang Wu Signed-off-by: Kees Cook Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sys.c b/kernel/sys.c index d041cc720c6..b0003db7fea 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1199,7 +1199,7 @@ static int override_release(char __user *release, size_t len) rest++; } v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40; - copy = min(sizeof(buf), max_t(size_t, 1, len)); + copy = clamp_t(size_t, len, 1, sizeof(buf)); copy = scnprintf(buf, copy, "2.6.%u%s", v, rest); ret = copy_to_user(release, buf, copy + 1); } From efd5fa0c1a1d1b46846ea6e8d1a783d0d8a6a721 Mon Sep 17 00:00:00 2001 From: Jacob Shin Date: Thu, 20 Oct 2011 16:15:26 -0500 Subject: [PATCH 1288/2357] x86: Exclude E820_RESERVED regions and memory holes above 4 GB from direct mapping. commit 1bbbbe779aabe1f0768c2bf8f8c0a5583679b54a upstream. On systems with very large memory (1 TB in our case), BIOS may report a reserved region or a hole in the E820 map, even above the 4 GB range. Exclude these from the direct mapping. [ hpa: this should be done not just for > 4 GB but for everything above the legacy region (1 MB), at the very least. That, however, turns out to require significant restructuring. That work is well underway, but is not suitable for rc/stable. ] Signed-off-by: Jacob Shin Link: http://lkml.kernel.org/r/1319145326-13902-1-git-send-email-jacob.shin@amd.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/setup.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 1a290156205..fbbd1eb6c68 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -927,8 +927,21 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_X86_64 if (max_pfn > max_low_pfn) { - max_pfn_mapped = init_memory_mapping(1UL<<32, - max_pfn<addr + ei->size <= 1UL << 32) + continue; + + if (ei->type == E820_RESERVED) + continue; + + max_pfn_mapped = init_memory_mapping( + ei->addr < 1UL << 32 ? 1UL << 32 : ei->addr, + ei->addr + ei->size); + } + /* can we preseve max_low_pfn ?*/ max_low_pfn = max_pfn; } From cf32a3a3e7b9a449e3b51bc8114d623d52fa9c5f Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Fri, 19 Oct 2012 17:29:07 +0100 Subject: [PATCH 1289/2357] xen/x86: don't corrupt %eip when returning from a signal handler commit a349e23d1cf746f8bdc603dcc61fae9ee4a695f6 upstream. In 32 bit guests, if a userspace process has %eax == -ERESTARTSYS (-512) or -ERESTARTNOINTR (-513) when it is interrupted by an event /and/ the process has a pending signal then %eip (and %eax) are corrupted when returning to the main process after handling the signal. The application may then crash with SIGSEGV or a SIGILL or it may have subtly incorrect behaviour (depending on what instruction it returned to). The occurs because handle_signal() is incorrectly thinking that there is a system call that needs to restarted so it adjusts %eip and %eax to re-execute the system call instruction (even though user space had not done a system call). If %eax == -514 (-ERESTARTNOHAND (-514) or -ERESTART_RESTARTBLOCK (-516) then handle_signal() only corrupted %eax (by setting it to -EINTR). This may cause the application to crash or have incorrect behaviour. handle_signal() assumes that regs->orig_ax >= 0 means a system call so any kernel entry point that is not for a system call must push a negative value for orig_ax. For example, for physical interrupts on bare metal the inverse of the vector is pushed and page_fault() sets regs->orig_ax to -1, overwriting the hardware provided error code. xen_hypervisor_callback() was incorrectly pushing 0 for orig_ax instead of -1. Classic Xen kernels pushed %eax which works as %eax cannot be both non-negative and -RESTARTSYS (etc.), but using -1 is consistent with other non-system call entry points and avoids some of the tests in handle_signal(). There were similar bugs in xen_failsafe_callback() of both 32 and 64-bit guests. If the fault was corrected and the normal return path was used then 0 was incorrectly pushed as the value for orig_ax. Signed-off-by: David Vrabel Acked-by: Jan Beulich Acked-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/entry_32.S | 8 +++++--- arch/x86/kernel/entry_64.S | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 7b784f4ef1e..6d4f7ba227f 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -1025,7 +1025,7 @@ ENTRY(xen_sysenter_target) ENTRY(xen_hypervisor_callback) CFI_STARTPROC - pushl_cfi $0 + pushl_cfi $-1 /* orig_ax = -1 => not a system call */ SAVE_ALL TRACE_IRQS_OFF @@ -1067,14 +1067,16 @@ ENTRY(xen_failsafe_callback) 2: mov 8(%esp),%es 3: mov 12(%esp),%fs 4: mov 16(%esp),%gs + /* EAX == 0 => Category 1 (Bad segment) + EAX != 0 => Category 2 (Bad IRET) */ testl %eax,%eax popl_cfi %eax lea 16(%esp),%esp CFI_ADJUST_CFA_OFFSET -16 jz 5f addl $16,%esp - jmp iret_exc # EAX != 0 => Category 2 (Bad IRET) -5: pushl_cfi $0 # EAX == 0 => Category 1 (Bad segment) + jmp iret_exc +5: pushl_cfi $-1 /* orig_ax = -1 => not a system call */ SAVE_ALL jmp ret_from_exception CFI_ENDPROC diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index cdc79b5cfcd..bd6f59203b5 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -1351,7 +1351,7 @@ ENTRY(xen_failsafe_callback) CFI_RESTORE r11 addq $0x30,%rsp CFI_ADJUST_CFA_OFFSET -0x30 - pushq_cfi $0 + pushq_cfi $-1 /* orig_ax = -1 => not a system call */ SAVE_ALL jmp error_exit CFI_ENDPROC From e83863d3e7ead8c66c1cabb53d95ebd3c7f1805e Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 16 Oct 2012 21:21:21 +0800 Subject: [PATCH 1290/2357] USB: cdc-acm: fix pipe type of write endpoint commit c5211187f7ff8e8dbff4ebf7c011ac4c0ffe319c upstream. If the write endpoint is interrupt type, usb_sndintpipe() should be passed to usb_fill_int_urb() instead of usb_sndbulkpipe(). Signed-off-by: Ming Lei Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7f2fac162a7..3b70aade056 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1234,7 +1234,7 @@ static int acm_probe(struct usb_interface *intf, if (usb_endpoint_xfer_int(epwrite)) usb_fill_int_urb(snd->urb, usb_dev, - usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), + usb_sndintpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); else usb_fill_bulk_urb(snd->urb, usb_dev, From a5204466fa5da21c4431d391101439d7f5f2b828 Mon Sep 17 00:00:00 2001 From: Nicolas Boullis Date: Tue, 16 Oct 2012 00:06:23 +0200 Subject: [PATCH 1291/2357] usb: acm: fix the computation of the number of data bits commit 301a29da6e891e7eb95c843af0ecdbe86d01f723 upstream. The current code assumes that CSIZE is 0000060, which appears to be wrong on some arches (such as powerpc). Signed-off-by: Nicolas Boullis Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3b70aade056..c5f7eae429e 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -818,10 +818,6 @@ static const __u32 acm_tty_speed[] = { 2500000, 3000000, 3500000, 4000000 }; -static const __u8 acm_tty_size[] = { - 5, 6, 7, 8 -}; - static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) { @@ -835,7 +831,21 @@ static void acm_tty_set_termios(struct tty_struct *tty, newline.bParityType = termios->c_cflag & PARENB ? (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; - newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; + switch (termios->c_cflag & CSIZE) { + case CS5: + newline.bDataBits = 5; + break; + case CS6: + newline.bDataBits = 6; + break; + case CS7: + newline.bDataBits = 7; + break; + case CS8: + default: + newline.bDataBits = 8; + break; + } /* FIXME: Needs to clear unsupported bits in the termios */ acm->clocal = ((termios->c_cflag & CLOCAL) != 0); From 045b361901efac992f4ffd773db7c32319ffe177 Mon Sep 17 00:00:00 2001 From: "Alexis R. Cortes" Date: Wed, 17 Oct 2012 14:09:12 -0500 Subject: [PATCH 1292/2357] usb: host: xhci: New system added for Compliance Mode Patch on SN65LVPE502CP commit 470809741a28c3092279f4e1f3f432e534d46068 upstream. This minor change adds a new system to which the "Fix Compliance Mode on SN65LVPE502CP Hardware" patch has to be applied also. System added: Vendor: Hewlett-Packard. System Model: Z1 Signed-off-by: Alexis R. Cortes Acked-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f7562315530..e52ddfe0548 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -479,7 +479,8 @@ static bool compliance_mode_recovery_timer_quirk_check(void) if (strstr(dmi_product_name, "Z420") || strstr(dmi_product_name, "Z620") || - strstr(dmi_product_name, "Z820")) + strstr(dmi_product_name, "Z820") || + strstr(dmi_product_name, "Z1")) return true; return false; From f9353fb64e1cfb7a1218fbd610df1980a40b1c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 18 Oct 2012 17:19:53 +0200 Subject: [PATCH 1293/2357] USB: option: blacklist net interface on ZTE devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1452df6f1b7e396d89c2a1fdbdc0e0e839f97671 upstream. Based on information from the ZTE Windows drivers. Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 68 ++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 57de73462f0..2a90a0e283a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -503,11 +503,19 @@ static const struct option_blacklist_info net_intf5_blacklist = { .reserved = BIT(5), }; +static const struct option_blacklist_info net_intf6_blacklist = { + .reserved = BIT(6), +}; + static const struct option_blacklist_info zte_mf626_blacklist = { .sendsetup = BIT(0) | BIT(1), .reserved = BIT(4), }; +static const struct option_blacklist_info zte_1255_blacklist = { + .reserved = BIT(3) | BIT(4), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -853,13 +861,19 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0122, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0128, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0142, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0143, 0xff, 0xff, 0xff) }, @@ -872,7 +886,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) }, @@ -886,7 +901,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, @@ -1002,18 +1018,24 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1169, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1170, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1244, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1246, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1248, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1249, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1250, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1251, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1253, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_1255_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1257, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1258, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1259, 0xff, 0xff, 0xff) }, @@ -1071,15 +1093,21 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, From 9b1ca55bf3ff5fa1c3ff87bac9c7183bc421dc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 18 Oct 2012 17:14:17 +0200 Subject: [PATCH 1294/2357] USB: option: add more ZTE devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4b35f1c52943851b310afb09047bfe991ac8f5ae upstream. Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 2a90a0e283a..17ec21ee7d0 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -895,6 +895,12 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0191, 0xff, 0xff, 0xff), /* ZTE EuFi890 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0199, 0xff, 0xff, 0xff), /* ZTE MF820S */ + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff), @@ -903,6 +909,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1021, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, @@ -1080,8 +1088,16 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1401, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1424, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1425, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff), /* ZTE MF91 */ + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, From 9a55fef20afb3d7362b0c9d19ba1e78dfe482d3d Mon Sep 17 00:00:00 2001 From: Daisuke Nishimura Date: Thu, 4 Oct 2012 16:37:16 +0900 Subject: [PATCH 1295/2357] cgroup: notify_on_release may not be triggered in some cases commit 1f5320d5972aa50d3e8d2b227b636b370e608359 upstream. notify_on_release must be triggered when the last process in a cgroup is move to another. But if the first(and only) process in a cgroup is moved to another, notify_on_release is not triggered. # mkdir /cgroup/cpu/SRC # mkdir /cgroup/cpu/DST # # echo 1 >/cgroup/cpu/SRC/notify_on_release # echo 1 >/cgroup/cpu/DST/notify_on_release # # sleep 300 & [1] 8629 # # echo 8629 >/cgroup/cpu/SRC/tasks # echo 8629 >/cgroup/cpu/DST/tasks -> notify_on_release for /SRC must be triggered at this point, but it isn't. This is because put_css_set() is called before setting CGRP_RELEASABLE in cgroup_task_migrate(), and is a regression introduce by the commit:74a1166d(cgroups: make procs file writable), which was merged into v3.0. Acked-by: Li Zefan Cc: Ben Blum Signed-off-by: Daisuke Nishimura Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index ed64ccac67c..b76dd5862a8 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1868,9 +1868,8 @@ static void cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp, * trading it for newcg is protected by cgroup_mutex, we're safe to drop * it here; it will be freed under RCU. */ - put_css_set(oldcg); - set_bit(CGRP_RELEASABLE, &oldcgrp->flags); + put_css_set(oldcg); } /** From 5993bba302a1a6df9c73690a08346411ff7cd56e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 18 Oct 2012 17:40:30 -0700 Subject: [PATCH 1296/2357] Revert "cgroup: Remove task_lock() from cgroup_post_fork()" commit d87838321124061f6c935069d97f37010fa417e6 upstream. This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9. The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock(). threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks. Revert the incorrect optimization. Signed-off-by: Tejun Heo LKML-Reference: <20121008020000.GB2575@localhost> Acked-by: Li Zefan Cc: Frederic Weisbecker Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index b76dd5862a8..5cb488065dc 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -4539,19 +4539,10 @@ void cgroup_post_fork(struct task_struct *child) */ if (use_task_css_set_links) { write_lock(&css_set_lock); - if (list_empty(&child->cg_list)) { - /* - * It's safe to use child->cgroups without task_lock() - * here because we are protected through - * threadgroup_change_begin() against concurrent - * css_set change in cgroup_task_migrate(). Also - * the task can't exit at that point until - * wake_up_new_task() is called, so we are protected - * against cgroup_exit() setting child->cgroup to - * init_css_set. - */ + task_lock(child); + if (list_empty(&child->cg_list)) list_add(&child->cg_list, &child->cgroups->tasks); - } + task_unlock(child); write_unlock(&css_set_lock); } } From 727fa37e405a71dc1c7208ea7352be55e0310eca Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 18 Oct 2012 17:52:07 -0700 Subject: [PATCH 1297/2357] Revert "cgroup: Drop task_lock(parent) on cgroup_fork()" commit 9bb71308b8133d643648776243e4d5599b1c193d upstream. This reverts commit 7e381b0eb1e1a9805c37335562e8dc02e7d7848c. The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock(). threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks. Revert the incorrect optimization. Signed-off-by: Tejun Heo LKML-Reference: <20121008020000.GB2575@localhost> Acked-by: Li Zefan Bitterly-Acked-by: Frederic Weisbecker Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 5cb488065dc..762f7cc753a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -4462,31 +4462,20 @@ static const struct file_operations proc_cgroupstats_operations = { * * A pointer to the shared css_set was automatically copied in * fork.c by dup_task_struct(). However, we ignore that copy, since - * it was not made under the protection of RCU, cgroup_mutex or - * threadgroup_change_begin(), so it might no longer be a valid - * cgroup pointer. cgroup_attach_task() might have already changed - * current->cgroups, allowing the previously referenced cgroup - * group to be removed and freed. - * - * Outside the pointer validity we also need to process the css_set - * inheritance between threadgoup_change_begin() and - * threadgoup_change_end(), this way there is no leak in any process - * wide migration performed by cgroup_attach_proc() that could otherwise - * miss a thread because it is too early or too late in the fork stage. + * it was not made under the protection of RCU or cgroup_mutex, so + * might no longer be a valid cgroup pointer. cgroup_attach_task() might + * have already changed current->cgroups, allowing the previously + * referenced cgroup group to be removed and freed. * * At the point that cgroup_fork() is called, 'current' is the parent * task, and the passed argument 'child' points to the child task. */ void cgroup_fork(struct task_struct *child) { - /* - * We don't need to task_lock() current because current->cgroups - * can't be changed concurrently here. The parent obviously hasn't - * exited and called cgroup_exit(), and we are synchronized against - * cgroup migration through threadgroup_change_begin(). - */ + task_lock(current); child->cgroups = current->cgroups; get_css_set(child->cgroups); + task_unlock(current); INIT_LIST_HEAD(&child->cg_list); } From 409dcaefb5c287d68c36e2598154b979a67a9447 Mon Sep 17 00:00:00 2001 From: Pritesh Raithatha Date: Wed, 17 Oct 2012 11:51:37 +0530 Subject: [PATCH 1298/2357] pinctrl: tegra: correct bank for pingroup and drv pingroup commit a03690e44468dcd3088f6600ab036d17bd2130ff upstream. Signed-off-by: Pritesh Raithatha Acked-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/pinctrl-tegra30.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c index 4d7571d4a43..636d96c4b3e 100644 --- a/drivers/pinctrl/pinctrl-tegra30.c +++ b/drivers/pinctrl/pinctrl-tegra30.c @@ -3343,10 +3343,10 @@ static const struct tegra_function tegra30_functions[] = { FUNCTION(vi_alt3), }; -#define MUXCTL_REG_A 0x3000 -#define PINGROUP_REG_A 0x868 +#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */ +#define PINGROUP_REG_A 0x3000 /* bank 1 */ -#define PINGROUP_REG_Y(r) ((r) - MUXCTL_REG_A) +#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A) #define PINGROUP_REG_N(r) -1 #define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior) \ @@ -3362,25 +3362,25 @@ static const struct tegra_function tegra30_functions[] = { }, \ .func_safe = TEGRA_MUX_ ## f_safe, \ .mux_reg = PINGROUP_REG_Y(r), \ - .mux_bank = 0, \ + .mux_bank = 1, \ .mux_bit = 0, \ .pupd_reg = PINGROUP_REG_Y(r), \ - .pupd_bank = 0, \ + .pupd_bank = 1, \ .pupd_bit = 2, \ .tri_reg = PINGROUP_REG_Y(r), \ - .tri_bank = 0, \ + .tri_bank = 1, \ .tri_bit = 4, \ .einput_reg = PINGROUP_REG_Y(r), \ - .einput_bank = 0, \ + .einput_bank = 1, \ .einput_bit = 5, \ .odrain_reg = PINGROUP_REG_##od(r), \ - .odrain_bank = 0, \ + .odrain_bank = 1, \ .odrain_bit = 6, \ .lock_reg = PINGROUP_REG_Y(r), \ - .lock_bank = 0, \ + .lock_bank = 1, \ .lock_bit = 7, \ .ioreset_reg = PINGROUP_REG_##ior(r), \ - .ioreset_bank = 0, \ + .ioreset_bank = 1, \ .ioreset_bit = 8, \ .drv_reg = -1, \ } @@ -3399,8 +3399,8 @@ static const struct tegra_function tegra30_functions[] = { .odrain_reg = -1, \ .lock_reg = -1, \ .ioreset_reg = -1, \ - .drv_reg = ((r) - PINGROUP_REG_A), \ - .drv_bank = 1, \ + .drv_reg = ((r) - DRV_PINGROUP_REG_A), \ + .drv_bank = 0, \ .hsm_bit = hsm_b, \ .schmitt_bit = schmitt_b, \ .lpmd_bit = lpmd_b, \ From 248ada294174583d918564de33bc5504311c69bb Mon Sep 17 00:00:00 2001 From: Pritesh Raithatha Date: Wed, 17 Oct 2012 17:09:36 +0530 Subject: [PATCH 1299/2357] pinctrl: tegra: set low power mode bank width to 2 commit 154f3ebf53edcfbe28728452b4ab37a118581125 upstream. Signed-off-by: Pritesh Raithatha Acked-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/pinctrl-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index 9b329688120..2a32a2ff732 100644 --- a/drivers/pinctrl/pinctrl-tegra.c +++ b/drivers/pinctrl/pinctrl-tegra.c @@ -259,7 +259,7 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx, *bank = g->drv_bank; *reg = g->drv_reg; *bit = g->lpmd_bit; - *width = 1; + *width = 2; break; case TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH: *bank = g->drv_bank; From 5a58f4890e681eadbb617cace87cfdac948c7edd Mon Sep 17 00:00:00 2001 From: Hiro Sugawara Date: Thu, 18 Oct 2012 08:35:10 +0300 Subject: [PATCH 1300/2357] iommu/tegra: smmu: Fix deadly typo commit d0078e72314df2e5ede03f2102cddde06767c374 upstream. Fix a deadly typo in macro definition. Signed-off-by: Hiro Sugawara Signed-off-by: Hiroshi Doyu Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/tegra-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 17ef6c49366..035f28edf8f 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -148,7 +148,7 @@ #define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12) #define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22) -#define SMMU_PDN_TO_ADDR(addr) ((pdn) << 22) +#define SMMU_PDN_TO_ADDR(pdn) ((pdn) << 22) #define _READABLE (1 << SMMU_PTB_DATA_ASID_READABLE_SHIFT) #define _WRITABLE (1 << SMMU_PTB_DATA_ASID_WRITABLE_SHIFT) From 8538f9c30a098c87bb806e80f43b2203a997a4d9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 23 Oct 2012 14:09:39 -0700 Subject: [PATCH 1301/2357] amd64_edac:__amd64_set_scrub_rate(): avoid overindexing scrubrates[] commit 168bfeef7bba3f9784f7540b053e4ac72b769ce9 upstream. If none of the elements in scrubrates[] matches, this loop will cause __amd64_set_scrub_rate() to incorrectly use the n+1th element. As the function is designed to use the final scrubrates[] element in the case of no match, we can fix this bug by simply terminating the array search at the n-1th element. Boris: this code is fragile anyway, see here why: http://marc.info/?l=linux-kernel&m=135102834131236&w=2 It will be rewritten more robustly soonish. Reported-by: Denis Kirjanov Cc: Doug Thompson Signed-off-by: Andrew Morton Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman --- drivers/edac/amd64_edac.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 7ef73c919c5..a8bfe1c5378 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -170,8 +170,11 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate) * memory controller and apply to register. Search for the first * bandwidth entry that is greater or equal than the setting requested * and program that. If at last entry, turn off DRAM scrubbing. + * + * If no suitable bandwidth is found, turn off DRAM scrubbing entirely + * by falling back to the last element in scrubrates[]. */ - for (i = 0; i < ARRAY_SIZE(scrubrates); i++) { + for (i = 0; i < ARRAY_SIZE(scrubrates) - 1; i++) { /* * skip scrub rates which aren't recommended * (see F10 BKDG, F3x58) @@ -181,12 +184,6 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate) if (scrubrates[i].bandwidth <= new_bw) break; - - /* - * if no suitable bandwidth found, turn off DRAM scrubbing - * entirely by falling back to the last element in the - * scrubrates array. - */ } scrubval = scrubrates[i].scrubval; From bfbd61ec59fae6f633db1d139015c3dd81e453be Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 4 Oct 2012 11:58:00 +0300 Subject: [PATCH 1302/2357] usb: dwc3: gadget: fix 'endpoint always busy' bug commit 041d81f493d90c940ec41f0ec98bc7c4f2fba431 upstream. If a USB transfer has already been started, meaning we have already issued StartTransfer command to that particular endpoint, DWC3_EP_BUSY flag has also already been set. When we try to cancel this transfer which is already in controller's cache, we will not receive XferComplete event and we must clear DWC3_EP_BUSY in order to allow subsequent requests to be properly started. The best place to clear that flag is right after issuing DWC3_DEPCMD_ENDTRANSFER. Reported-by: Moiz Sonasath Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b8d46978fc5..cee0c3e8ab3 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1777,6 +1777,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); WARN_ON_ONCE(ret); dep->res_trans_idx = 0; + dep->flags &= ~DWC3_EP_BUSY; } } From f0dc514c8a0fd7ee7b1f6a3ccdae3b38e6ee1578 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 6 Aug 2012 22:47:03 -0300 Subject: [PATCH 1303/2357] media: au0828: fix case where STREAMOFF being called on stopped stream causes BUG() commit a595c1ce4c9d572cf53513570b9f1a263d7867f2 upstream. We weren't checking whether the resource was in use before calling res_free(), so applications which called STREAMOFF on a v4l2 device that wasn't already streaming would cause a BUG() to be hit (MythTV). Reported-by: Larry Finger Reported-by: Jay Harbeston Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/au0828/au0828-video.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c index 0b3e481ffe8..eab06419473 100644 --- a/drivers/media/video/au0828/au0828-video.c +++ b/drivers/media/video/au0828/au0828-video.c @@ -1692,14 +1692,18 @@ static int vidioc_streamoff(struct file *file, void *priv, (AUVI_INPUT(i).audio_setup)(dev, 0); } - videobuf_streamoff(&fh->vb_vidq); - res_free(fh, AU0828_RESOURCE_VIDEO); + if (res_check(fh, AU0828_RESOURCE_VIDEO)) { + videobuf_streamoff(&fh->vb_vidq); + res_free(fh, AU0828_RESOURCE_VIDEO); + } } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { dev->vbi_timeout_running = 0; del_timer_sync(&dev->vbi_timeout); - videobuf_streamoff(&fh->vb_vbiq); - res_free(fh, AU0828_RESOURCE_VBI); + if (res_check(fh, AU0828_RESOURCE_VBI)) { + videobuf_streamoff(&fh->vb_vbiq); + res_free(fh, AU0828_RESOURCE_VBI); + } } return 0; From 70f7f1c70af637a23ca09ba1d2d7c966d1bd5990 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Thu, 4 Oct 2012 20:15:48 +0000 Subject: [PATCH 1304/2357] netlink: add reference of module in netlink_dump_start [ Upstream commit 6dc878a8ca39e93f70c42f3dd7260bde10c1e0f1 ] I get a panic when I use ss -a and rmmod inet_diag at the same time. It's because netlink_dump uses inet_diag_dump which belongs to module inet_diag. I search the codes and find many modules have the same problem. We need to add a reference to the module which the cb->dump belongs to. Thanks for all help from Stephen,Jan,Eric,Steffen and Pablo. Change From v3: change netlink_dump_start to inline,suggestion from Pablo and Eric. Change From v2: delete netlink_dump_done,and call module_put in netlink_dump and netlink_sock_destruct. Signed-off-by: Gao feng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/netlink.h | 21 +++++++++++++++++---- net/netlink/af_netlink.c | 29 +++++++++++++++++++++-------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index a2092f582a7..b23e9cd6a88 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -153,6 +153,7 @@ struct nlattr { #include #include +#include struct net; @@ -226,6 +227,8 @@ struct netlink_callback { struct netlink_callback *cb); int (*done)(struct netlink_callback *cb); void *data; + /* the module that dump function belong to */ + struct module *module; u16 family; u16 min_dump_alloc; unsigned int prev_seq, seq; @@ -251,14 +254,24 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) struct netlink_dump_control { int (*dump)(struct sk_buff *skb, struct netlink_callback *); - int (*done)(struct netlink_callback*); + int (*done)(struct netlink_callback *); void *data; + struct module *module; u16 min_dump_alloc; }; -extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - const struct nlmsghdr *nlh, - struct netlink_dump_control *control); +extern int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, + const struct nlmsghdr *nlh, + struct netlink_dump_control *control); +static inline int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, + const struct nlmsghdr *nlh, + struct netlink_dump_control *control) +{ + if (!control->module) + control->module = THIS_MODULE; + + return __netlink_dump_start(ssk, skb, nlh, control); +} #define NL_NONROOT_RECV 0x1 diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index bba6ba176ab..edce424048d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -156,6 +156,8 @@ static void netlink_sock_destruct(struct sock *sk) if (nlk->cb) { if (nlk->cb->done) nlk->cb->done(nlk->cb); + + module_put(nlk->cb->module); netlink_destroy_callback(nlk->cb); } @@ -1728,6 +1730,7 @@ static int netlink_dump(struct sock *sk) nlk->cb = NULL; mutex_unlock(nlk->cb_mutex); + module_put(cb->module); netlink_destroy_callback(cb); return 0; @@ -1737,9 +1740,9 @@ static int netlink_dump(struct sock *sk) return err; } -int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - const struct nlmsghdr *nlh, - struct netlink_dump_control *control) +int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, + const struct nlmsghdr *nlh, + struct netlink_dump_control *control) { struct netlink_callback *cb; struct sock *sk; @@ -1754,6 +1757,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, cb->done = control->done; cb->nlh = nlh; cb->data = control->data; + cb->module = control->module; cb->min_dump_alloc = control->min_dump_alloc; atomic_inc(&skb->users); cb->skb = skb; @@ -1764,19 +1768,28 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, return -ECONNREFUSED; } nlk = nlk_sk(sk); - /* A dump is in progress... */ + mutex_lock(nlk->cb_mutex); + /* A dump is in progress... */ if (nlk->cb) { mutex_unlock(nlk->cb_mutex); netlink_destroy_callback(cb); - sock_put(sk); - return -EBUSY; + ret = -EBUSY; + goto out; } + /* add reference of module which cb->dump belongs to */ + if (!try_module_get(cb->module)) { + mutex_unlock(nlk->cb_mutex); + netlink_destroy_callback(cb); + ret = -EPROTONOSUPPORT; + goto out; + } + nlk->cb = cb; mutex_unlock(nlk->cb_mutex); ret = netlink_dump(sk); - +out: sock_put(sk); if (ret) @@ -1787,7 +1800,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, */ return -EINTR; } -EXPORT_SYMBOL(netlink_dump_start); +EXPORT_SYMBOL(__netlink_dump_start); void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) { From 6114941a295ff186d29ab7462cce6a41a089c354 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Thu, 4 Oct 2012 20:15:49 +0000 Subject: [PATCH 1305/2357] infiniband: pass rdma_cm module to netlink_dump_start [ Upstream commit 809d5fc9bf6589276a12bd4fd611e4c7ff9940c3 ] set netlink_dump_control.module to avoid panic. Signed-off-by: Gao feng Cc: Roland Dreier Cc: Sean Hefty Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/cma.c | 3 ++- drivers/infiniband/core/netlink.c | 1 + include/rdma/rdma_netlink.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index e3e470fecaa..67432e200c6 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -3451,7 +3451,8 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb) } static const struct ibnl_client_cbs cma_cb_table[] = { - [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats }, + [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats, + .module = THIS_MODULE }, }; static int __init cma_init(void) diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c index 396e2937030..8c3b08ac496 100644 --- a/drivers/infiniband/core/netlink.c +++ b/drivers/infiniband/core/netlink.c @@ -151,6 +151,7 @@ static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { struct netlink_dump_control c = { .dump = client->cb_table[op].dump, + .module = client->cb_table[op].module, }; return netlink_dump_start(nls, skb, nlh, &c); } diff --git a/include/rdma/rdma_netlink.h b/include/rdma/rdma_netlink.h index 3c5363ab867..bd3d8b24b42 100644 --- a/include/rdma/rdma_netlink.h +++ b/include/rdma/rdma_netlink.h @@ -39,6 +39,7 @@ struct rdma_cm_id_stats { struct ibnl_client_cbs { int (*dump)(struct sk_buff *skb, struct netlink_callback *nlcb); + struct module *module; }; int ibnl_init(void); From 742bd2b3cef97a6eea8168b8e356ca2f16b7f3eb Mon Sep 17 00:00:00 2001 From: "ramesh.nagappa@gmail.com" Date: Fri, 5 Oct 2012 19:10:15 +0000 Subject: [PATCH 1306/2357] net: Fix skb_under_panic oops in neigh_resolve_output [ Upstream commit e1f165032c8bade3a6bdf546f8faf61fda4dd01c ] The retry loop in neigh_resolve_output() and neigh_connected_output() call dev_hard_header() with out reseting the skb to network_header. This causes the retry to fail with skb_under_panic. The fix is to reset the network_header within the retry loop. Signed-off-by: Ramesh Nagappa Reviewed-by: Shawn Lu Reviewed-by: Robert Coulson Reviewed-by: Billie Alsup Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/neighbour.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 73b90351df5..ac88107d1bc 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1285,8 +1285,6 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb) if (!dst) goto discard; - __skb_pull(skb, skb_network_offset(skb)); - if (!neigh_event_send(neigh, skb)) { int err; struct net_device *dev = neigh->dev; @@ -1296,6 +1294,7 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb) neigh_hh_init(neigh, dst); do { + __skb_pull(skb, skb_network_offset(skb)); seq = read_seqbegin(&neigh->ha_lock); err = dev_hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len); @@ -1326,9 +1325,8 @@ int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb) unsigned int seq; int err; - __skb_pull(skb, skb_network_offset(skb)); - do { + __skb_pull(skb, skb_network_offset(skb)); seq = read_seqbegin(&neigh->ha_lock); err = dev_hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len); From 14a547a85a7fa2b6473eaa73b83e2055b476a5dc Mon Sep 17 00:00:00 2001 From: Graham Gower Date: Mon, 8 Oct 2012 08:34:50 +0000 Subject: [PATCH 1307/2357] skge: Add DMA mask quirk for Marvell 88E8001 on ASUS P5NSLI motherboard [ Upstream commit a2af139ff1cd85df586690ff626619ab1ee88b0a ] Marvell 88E8001 on an ASUS P5NSLI motherboard is unable to send/receive packets on a system with >4gb ram unless a 32bit DMA mask is used. This issue has been around for years and a fix was sent 3.5 years ago, but there was some debate as to whether it should instead be fixed as a PCI quirk. http://www.spinics.net/lists/netdev/msg88670.html However, 18 months later a similar workaround was introduced for another chipset exhibiting the same problem. http://www.spinics.net/lists/netdev/msg142287.html Signed-off-by: Graham Gower Signed-off-by: Jan Ceuleers Acked-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/marvell/skge.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index 5a30bf82309..f4be8f7c286 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c @@ -4153,6 +4153,13 @@ static struct dmi_system_id skge_32bit_dma_boards[] = { DMI_MATCH(DMI_BOARD_NAME, "nForce"), }, }, + { + .ident = "ASUS P5NSLI", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "P5NSLI") + }, + }, {} }; From 2d2f242f248f19c4618bde9091d20416e2c9a1f6 Mon Sep 17 00:00:00 2001 From: Florian Zumbiehl Date: Sun, 7 Oct 2012 15:51:58 +0000 Subject: [PATCH 1308/2357] vlan: don't deliver frames for unknown vlans to protocols [ Upstream commit 48cc32d38a52d0b68f91a171a8d00531edc6a46e ] 6a32e4f9dd9219261f8856f817e6655114cfec2f made the vlan code skip marking vlan-tagged frames for not locally configured vlans as PACKET_OTHERHOST if there was an rx_handler, as the rx_handler could cause the frame to be received on a different (virtual) vlan-capable interface where that vlan might be configured. As rx_handlers do not necessarily return RX_HANDLER_ANOTHER, this could cause frames for unknown vlans to be delivered to the protocol stack as if they had been received untagged. For example, if an ipv6 router advertisement that's tagged for a locally not configured vlan is received on an interface with macvlan interfaces attached, macvlan's rx_handler returns RX_HANDLER_PASS after delivering the frame to the macvlan interfaces, which caused it to be passed to the protocol stack, leading to ipv6 addresses for the announced prefix being configured even though those are completely unusable on the underlying interface. The fix moves marking as PACKET_OTHERHOST after the rx_handler so the rx_handler, if there is one, sees the frame unchanged, but afterwards, before the frame is delivered to the protocol stack, it gets marked whether there is an rx_handler or not. Signed-off-by: Florian Zumbiehl Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/if_vlan.h | 8 ++++---- net/8021q/vlan_core.c | 10 ++-------- net/core/dev.c | 7 +++++-- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index a810987cb80..561e130df0b 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -82,6 +82,8 @@ static inline int is_vlan_dev(struct net_device *dev) } #define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT) +#define vlan_tx_nonzero_tag_present(__skb) \ + (vlan_tx_tag_present(__skb) && ((__skb)->vlan_tci & VLAN_VID_MASK)) #define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) @@ -91,7 +93,7 @@ extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev, extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); extern u16 vlan_dev_vlan_id(const struct net_device *dev); -extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler); +extern bool vlan_do_receive(struct sk_buff **skb); extern struct sk_buff *vlan_untag(struct sk_buff *skb); extern int vlan_vid_add(struct net_device *dev, unsigned short vid); @@ -120,10 +122,8 @@ static inline u16 vlan_dev_vlan_id(const struct net_device *dev) return 0; } -static inline bool vlan_do_receive(struct sk_buff **skb, bool last_handler) +static inline bool vlan_do_receive(struct sk_buff **skb) { - if (((*skb)->vlan_tci & VLAN_VID_MASK) && last_handler) - (*skb)->pkt_type = PACKET_OTHERHOST; return false; } diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index f36463087ba..912613c566c 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -5,7 +5,7 @@ #include #include "vlan.h" -bool vlan_do_receive(struct sk_buff **skbp, bool last_handler) +bool vlan_do_receive(struct sk_buff **skbp) { struct sk_buff *skb = *skbp; u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK; @@ -13,14 +13,8 @@ bool vlan_do_receive(struct sk_buff **skbp, bool last_handler) struct vlan_pcpu_stats *rx_stats; vlan_dev = vlan_find_dev(skb->dev, vlan_id); - if (!vlan_dev) { - /* Only the last call to vlan_do_receive() should change - * pkt_type to PACKET_OTHERHOST - */ - if (vlan_id && last_handler) - skb->pkt_type = PACKET_OTHERHOST; + if (!vlan_dev) return false; - } skb = *skbp = skb_share_check(skb, GFP_ATOMIC); if (unlikely(!skb)) diff --git a/net/core/dev.c b/net/core/dev.c index 086bc2e578c..82ca51bc29e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3209,18 +3209,18 @@ static int __netif_receive_skb(struct sk_buff *skb) ncls: #endif - rx_handler = rcu_dereference(skb->dev->rx_handler); if (vlan_tx_tag_present(skb)) { if (pt_prev) { ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = NULL; } - if (vlan_do_receive(&skb, !rx_handler)) + if (vlan_do_receive(&skb)) goto another_round; else if (unlikely(!skb)) goto out; } + rx_handler = rcu_dereference(skb->dev->rx_handler); if (rx_handler) { if (pt_prev) { ret = deliver_skb(skb, pt_prev, orig_dev); @@ -3240,6 +3240,9 @@ static int __netif_receive_skb(struct sk_buff *skb) } } + if (vlan_tx_nonzero_tag_present(skb)) + skb->pkt_type = PACKET_OTHERHOST; + /* deliver only exact match when indicated */ null_or_dev = deliver_exact ? skb->dev : NULL; From 04c592343f478826bf1e5d0d178bb295d848c428 Mon Sep 17 00:00:00 2001 From: "jeff.liu" Date: Mon, 8 Oct 2012 18:57:27 +0000 Subject: [PATCH 1309/2357] RDS: fix rds-ping spinlock recursion [ Upstream commit 5175a5e76bbdf20a614fb47ce7a38f0f39e70226 ] This is the revised patch for fixing rds-ping spinlock recursion according to Venkat's suggestions. RDS ping/pong over TCP feature has been broken for years(2.6.39 to 3.6.0) since we have to set TCP cork and call kernel_sendmsg() between ping/pong which both need to lock "struct sock *sk". However, this lock has already been hold before rds_tcp_data_ready() callback is triggerred. As a result, we always facing spinlock resursion which would resulting in system panic. Given that RDS ping is only used to test the connectivity and not for serious performance measurements, we can queue the pong transmit to rds_wq as a delayed response. Reported-by: Dan Carpenter CC: Venkat Venkatsubra CC: David S. Miller CC: James Morris Signed-off-by: Jie Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rds/send.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rds/send.c b/net/rds/send.c index 96531d4033a..88eace57dd6 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -1122,7 +1122,7 @@ rds_send_pong(struct rds_connection *conn, __be16 dport) rds_stats_inc(s_send_pong); if (!test_bit(RDS_LL_SEND_FULL, &conn->c_flags)) - rds_send_xmit(conn); + queue_delayed_work(rds_wq, &conn->c_send_w, 0); rds_message_put(rm); return 0; From 259c5a7fd824ebca122f04fc4202b88896f31d26 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Fri, 12 Oct 2012 04:34:17 +0000 Subject: [PATCH 1310/2357] tcp: resets are misrouted [ Upstream commit 4c67525849e0b7f4bd4fab2487ec9e43ea52ef29 ] After commit e2446eaa ("tcp_v4_send_reset: binding oif to iif in no sock case").. tcp resets are always lost, when routing is asymmetric. Yes, backing out that patch will result in misrouting of resets for dead connections which used interface binding when were alive, but we actually cannot do anything here. What's died that's died and correct handling normal unbound connections is obviously a priority. Comment to comment: > This has few benefits: > 1. tcp_v6_send_reset already did that. It was done to route resets for IPv6 link local addresses. It was a mistake to do so for global addresses. The patch fixes this as well. Actually, the problem appears to be even more serious than guaranteed loss of resets. As reported by Sergey Soloviev , those misrouted resets create a lot of arp traffic and huge amount of unresolved arp entires putting down to knees NAT firewalls which use asymmetric routing. Signed-off-by: Alexey Kuznetsov Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_ipv4.c | 7 ++++--- net/ipv6/tcp_ipv6.c | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0cb86ceb652..8f2458df19f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -678,10 +678,11 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.csumoffset = offsetof(struct tcphdr, check) / 2; arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0; /* When socket is gone, all binding information is lost. - * routing might fail in this case. using iif for oif to - * make sure we can deliver it + * routing might fail in this case. No choice here, if we choose to force + * input interface, we will misroute in case of asymmetric route. */ - arg.bound_dev_if = sk ? sk->sk_bound_dev_if : inet_iif(skb); + if (sk) + arg.bound_dev_if = sk->sk_bound_dev_if; net = dev_net(skb_dst(skb)->dev); arg.tos = ip_hdr(skb)->tos; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 98256cf72f9..8a8fa2dd149 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -896,7 +896,8 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, __tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr); fl6.flowi6_proto = IPPROTO_TCP; - fl6.flowi6_oif = inet6_iif(skb); + if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL) + fl6.flowi6_oif = inet6_iif(skb); fl6.fl6_dport = t1->dest; fl6.fl6_sport = t1->source; security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); From dd2c50efa9941fe7393b5f490eeef68f18916211 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 16 Oct 2012 07:37:27 +0000 Subject: [PATCH 1311/2357] ipv6: addrconf: fix /proc/net/if_inet6 [ Upstream commit 9f0d3c2781baa1102108e16efbe640dd74564a7c ] Commit 1d5783030a1 (ipv6/addrconf: speedup /proc/net/if_inet6 filling) added bugs hiding some devices from if_inet6 and breaking applications. "ip -6 addr" could still display all IPv6 addresses, while "ifconfig -a" couldnt. One way to reproduce the bug is by starting in a shell : unshare -n /bin/bash ifconfig lo up And in original net namespace, lo device disappeared from if_inet6 Reported-by: Jan Hinnerk Stosch Tested-by: Jan Hinnerk Stosch Signed-off-by: Eric Dumazet Cc: Mihai Maruseac Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/addrconf.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 5ec60699c67..468a5ce6e9d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3095,14 +3095,15 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq, loff_t pos) struct hlist_node *n; hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket], addr_lst) { + if (!net_eq(dev_net(ifa->idev->dev), net)) + continue; /* sync with offset */ if (p < state->offset) { p++; continue; } state->offset++; - if (net_eq(dev_net(ifa->idev->dev), net)) - return ifa; + return ifa; } /* prepare for next bucket */ @@ -3120,18 +3121,20 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct hlist_node *n = &ifa->addr_lst; hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst) { + if (!net_eq(dev_net(ifa->idev->dev), net)) + continue; state->offset++; - if (net_eq(dev_net(ifa->idev->dev), net)) - return ifa; + return ifa; } while (++state->bucket < IN6_ADDR_HSIZE) { state->offset = 0; hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket], addr_lst) { + if (!net_eq(dev_net(ifa->idev->dev), net)) + continue; state->offset++; - if (net_eq(dev_net(ifa->idev->dev), net)) - return ifa; + return ifa; } } From 01afdbe150a888b20b24a427e010214530176cf5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 10 Oct 2012 17:25:00 -0700 Subject: [PATCH 1312/2357] sparc64: fix ptrace interaction with force_successful_syscall_return() [ Upstream commit 55c2770e413e96871147b9406a9c41fe9bc5209c ] we want syscall_trace_leave() called on exit from any syscall; skipping its call in case we'd done force_successful_syscall_return() is broken... Signed-off-by: Al Viro Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/syscalls.S | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index 1d7e274f3f2..7f5f65d0b3f 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -212,24 +212,20 @@ linux_sparc_syscall: 3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] ret_sys_call: ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3 - ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc sra %o0, 0, %o0 mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 sllx %g2, 32, %g2 - /* Check if force_successful_syscall_return() - * was invoked. - */ - ldub [%g6 + TI_SYS_NOERROR], %l2 - brnz,a,pn %l2, 80f - stb %g0, [%g6 + TI_SYS_NOERROR] - cmp %o0, -ERESTART_RESTARTBLOCK bgeu,pn %xcc, 1f - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %l6 -80: + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %g0 + ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc + +2: + stb %g0, [%g6 + TI_SYS_NOERROR] /* System call success, clear Carry condition code. */ andn %g3, %g2, %g3 +3: stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] bne,pn %icc, linux_syscall_trace2 add %l1, 0x4, %l2 ! npc = npc+4 @@ -238,20 +234,20 @@ ret_sys_call: stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] 1: + /* Check if force_successful_syscall_return() + * was invoked. + */ + ldub [%g6 + TI_SYS_NOERROR], %l2 + brnz,pn %l2, 2b + ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc /* System call failure, set Carry condition code. * Also, get abs(errno) to return to the process. */ - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %l6 sub %g0, %o0, %o0 - or %g3, %g2, %g3 stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] - stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] - bne,pn %icc, linux_syscall_trace2 - add %l1, 0x4, %l2 ! npc = npc+4 - stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] + ba,pt %xcc, 3b + or %g3, %g2, %g3 - b,pt %xcc, rtrap - stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] linux_syscall_trace2: call syscall_trace_leave add %sp, PTREGS_OFF, %o0 From 846514fcb8f4518aa88636542bb7aa8453faacb2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 14 Oct 2012 17:59:40 -0700 Subject: [PATCH 1313/2357] sparc64: Like x86 we should check current->mm during perf backtrace generation. [ Upstream commit 08280e6c4c2e8049ac61d9e8e3536ec1df629c0d ] If the MM is not active, only report the top-level PC. Do not try to access the address space. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/perf_event.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 28559ce5eeb..db344c4bc51 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -1428,8 +1428,6 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry, { unsigned long ufp; - perf_callchain_store(entry, regs->tpc); - ufp = regs->u_regs[UREG_I6] + STACK_BIAS; do { struct sparc_stackf *usf, sf; @@ -1450,8 +1448,6 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry, { unsigned long ufp; - perf_callchain_store(entry, regs->tpc); - ufp = regs->u_regs[UREG_I6] & 0xffffffffUL; do { struct sparc_stackf32 *usf, sf; @@ -1470,6 +1466,11 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry, void perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) { + perf_callchain_store(entry, regs->tpc); + + if (!current->mm) + return; + flushw_user(); if (test_thread_flag(TIF_32BIT)) perf_callchain_user_32(entry, regs); From f603fa368be8342b2bee401ac6c815e6e34b3373 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 16 Oct 2012 13:05:25 -0700 Subject: [PATCH 1314/2357] sparc64: Fix bit twiddling in sparc_pmu_enable_event(). [ Upstream commit e793d8c6740f8fe704fa216e95685f4d92c4c4b9 ] There was a serious disconnect in the logic happening in sparc_pmu_disable_event() vs. sparc_pmu_enable_event(). Event disable is implemented by programming a NOP event into the PCR. However, event enable was not reversing this operation. Instead, it was setting the User/Priv/Hypervisor trace enable bits. That's not sparc_pmu_enable_event()'s job, that's what sparc_pmu_enable() and sparc_pmu_disable() do . The intent of sparc_pmu_enable_event() is clear, since it first clear out the event type encoding field. So fix this by OR'ing in the event encoding rather than the trace enable bits. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/perf_event.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index db344c4bc51..602eca8ef8c 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -557,11 +557,13 @@ static u64 nop_for_index(int idx) static inline void sparc_pmu_enable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx) { - u64 val, mask = mask_for_index(idx); + u64 enc, val, mask = mask_for_index(idx); + + enc = perf_event_get_enc(cpuc->events[idx]); val = cpuc->pcr; val &= ~mask; - val |= hwc->config; + val |= event_encoding(enc, idx); cpuc->pcr = val; pcr_ops->write(cpuc->pcr); From d37bcccee1b807af77b5c6767cb0df295f9dfbdb Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 1 Aug 2012 21:10:51 +0200 Subject: [PATCH 1315/2357] sparc64: do not clobber personality flags in sys_sparc64_personality() [ Upstream commit a27032eee8cb6e16516f13c8a9752e9d5d4cc430 ] There are multiple errors in how sys_sparc64_personality() handles personality flags stored in top three bytes. - directly comparing current->personality against PER_LINUX32 doesn't work in cases when any of the personality flags stored in the top three bytes are used. - directly forcefully setting personality to PER_LINUX32 or PER_LINUX discards any flags stored in the top three bytes Fix the first one by properly using personality() macro to compare only PER_MASK bytes. Fix the second one by setting only the bits that should be set, instead of overwriting the whole value. Signed-off-by: Jiri Kosina Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/sys_sparc_64.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 3ee51f189a5..57b7cab1e26 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -519,12 +519,12 @@ SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality) { int ret; - if (current->personality == PER_LINUX32 && - personality == PER_LINUX) - personality = PER_LINUX32; + if (personality(current->personality) == PER_LINUX32 && + personality(personality) == PER_LINUX) + personality |= PER_LINUX32; ret = sys_personality(personality); - if (ret == PER_LINUX32) - ret = PER_LINUX; + if (personality(ret) == PER_LINUX32) + ret &= ~PER_LINUX32; return ret; } From 3ba595416b15151d2eaa12578c17cbfd64c06aec Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 15 Aug 2012 00:37:29 -0700 Subject: [PATCH 1316/2357] sparc64: Be less verbose during vmemmap population. [ Upstream commit 2856cc2e4d0852c3ddaae9dcb19cb9396512eb08 ] On a 2-node machine with 256GB of ram we get 512 lines of console output, which is just too much. This mimicks Yinghai Lu's x86 commit c2b91e2eec9678dbda274e906cc32ea8f711da3b (x86_64/mm: check and print vmemmap allocation continuous) except that we aren't ever going to get contiguous block pointers in between calls so just print when the virtual address or node changes. This decreases the output by an order of 16. Also demote this to KERN_DEBUG. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/mm/init_64.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 21faaeea85d..07916182387 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -2099,6 +2099,9 @@ EXPORT_SYMBOL(_PAGE_CACHE); #ifdef CONFIG_SPARSEMEM_VMEMMAP unsigned long vmemmap_table[VMEMMAP_SIZE]; +static long __meminitdata addr_start, addr_end; +static int __meminitdata node_start; + int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) { unsigned long vstart = (unsigned long) start; @@ -2129,15 +2132,30 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) *vmem_pp = pte_base | __pa(block); - printk(KERN_INFO "[%p-%p] page_structs=%lu " - "node=%d entry=%lu/%lu\n", start, block, nr, - node, - addr >> VMEMMAP_CHUNK_SHIFT, - VMEMMAP_SIZE); + /* check to see if we have contiguous blocks */ + if (addr_end != addr || node_start != node) { + if (addr_start) + printk(KERN_DEBUG " [%lx-%lx] on node %d\n", + addr_start, addr_end-1, node_start); + addr_start = addr; + node_start = node; + } + addr_end = addr + VMEMMAP_CHUNK; } } return 0; } + +void __meminit vmemmap_populate_print_last(void) +{ + if (addr_start) { + printk(KERN_DEBUG " [%lx-%lx] on node %d\n", + addr_start, addr_end-1, node_start); + addr_start = 0; + addr_end = 0; + node_start = 0; + } +} #endif /* CONFIG_SPARSEMEM_VMEMMAP */ static void prot_init_common(unsigned long page_none, From f2a713d25e8b95e065c90af72f461e99427e20f8 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 13 Jul 2012 09:28:24 -0700 Subject: [PATCH 1317/2357] mtd: nand: allow NAND_NO_SUBPAGE_WRITE to be set from driver commit bf7a01bf7987b63b121d572b240c132ec44129c4 upstream. The NAND_CHIPOPTIONS_MSK has limited utility and is causing real bugs. It silently masks off at least one flag that might be set by the driver (NAND_NO_SUBPAGE_WRITE). This breaks the GPMI NAND driver and possibly others. Really, as long as driver writers exercise a small amount of care with NAND_* options, this mask is not necessary at all; it was only here to prevent certain options from accidentally being set by the driver. But the original thought turns out to be a bad idea occasionally. Thus, kill it. Note, this patch fixes some major gpmi-nand breakage. Signed-off-by: Brian Norris Tested-by: Huang Shijie Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/nand_base.c | 9 +++------ include/linux/mtd/nand.h | 3 --- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 47b19c0bb07..eb9f5fb02ee 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2897,9 +2897,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, if (le16_to_cpu(p->features) & 1) *busw = NAND_BUSWIDTH_16; - chip->options &= ~NAND_CHIPOPTIONS_MSK; - chip->options |= (NAND_NO_READRDY | - NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK; + chip->options |= NAND_NO_READRDY | NAND_NO_AUTOINCR; pr_info("ONFI flash detected\n"); return 1; @@ -3064,9 +3062,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, mtd->erasesize <<= ((id_data[3] & 0x03) << 1); } } - /* Get chip options, preserve non chip based options */ - chip->options &= ~NAND_CHIPOPTIONS_MSK; - chip->options |= type->options & NAND_CHIPOPTIONS_MSK; + /* Get chip options */ + chip->options |= type->options; /* * Check if chip is not a Samsung device. Do not clear the diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 1482340d3d9..24835134471 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -215,9 +215,6 @@ typedef enum { #define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \ && (chip->page_shift > 9)) -/* Mask to zero out the chip options, which come from the id table */ -#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) - /* Non chip related options */ /* This option skips the bbt scan during initialization. */ #define NAND_SKIP_BBTSCAN 0x00010000 From f88df5ff96f5ea632aa2d193d2c9019aa4c728d9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 28 Oct 2012 10:36:33 -0700 Subject: [PATCH 1318/2357] Linux 3.4.16 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fe9ea67db86..470d96b8ba6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 15 +SUBLEVEL = 16 EXTRAVERSION = NAME = Saber-toothed Squirrel From 8357dde8b780b426d398f9e3701fdc16f0856766 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Oct 2012 12:51:45 -0400 Subject: [PATCH 1319/2357] drm/radeon: add some new SI PCI ids commit b6aa22db7857ab7ed042d6c56b800bfc727cfdff upstream. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_pciids.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 53392e8f956..efc66f2d096 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -209,6 +209,8 @@ {0x1002, 0x6788, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x678A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6790, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6791, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6792, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ @@ -221,6 +223,7 @@ {0x1002, 0x6808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6816, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6817, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6818, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ From 1c1e11543381f3ff0cee52b69903928ff881c0cb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 19 Oct 2012 13:27:04 -0400 Subject: [PATCH 1320/2357] drm/radeon: add error output if VM CS fails on cayman commit c71721324c612f7f040657ce9917d87f530f9784 upstream. So we know why the CS was rejected. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen_cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index ea69daeffac..977b22d4f47 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -2775,6 +2775,7 @@ static bool evergreen_vm_reg_valid(u32 reg) case CAYMAN_SQ_EX_ALLOC_TABLE_SLOTS: return true; default: + DRM_ERROR("Invalid register 0x%x in CS\n", reg); return false; } } From 218246de04389b7aa0d1e799ed8b0115f342ee37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stef=C3=A1n=20Freyr?= Date: Fri, 19 Oct 2012 22:46:00 +0200 Subject: [PATCH 1321/2357] ALSA: hda - add dock support for Thinkpad T430 commit 84f98fdf7865fbd35b312eb39ea91e5618c514c7 upstream. I have a Lenovo ThinkPad T430 and an UltraBase Series 3 docking station. Without this patch, if I plug my headphones into the jack on the computer, everything works fine. The computer speakers mute and the audio is played in the headphones. However, if I plug into the docking station headphone jack the computer speakers are muted but there is no audio in the headphones. Addresses https://bugs.launchpad.net/bugs/1060372 Signed-off-by: Joseph Salisbury Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 94b765b31ea..6ecf1d4fa8a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6184,6 +6184,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), From 419cbf261a717df51878cadd00488ec2a9d9b3a4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 25 Oct 2012 13:38:14 -0700 Subject: [PATCH 1322/2357] gen_init_cpio: avoid stack overflow when expanding commit 20f1de659b77364d55d4e7fad2ef657e7730323f upstream. Fix possible overflow of the buffer used for expanding environment variables when building file list. In the extremely unlikely case of an attacker having control over the environment variables visible to gen_init_cpio, control over the contents of the file gen_init_cpio parses, and gen_init_cpio was built without compiler hardening, the attacker can gain arbitrary execution control via a stack buffer overflow. $ cat usr/crash.list file foo ${BIG}${BIG}${BIG}${BIG}${BIG}${BIG} 0755 0 0 $ BIG=$(perl -e 'print "A" x 4096;') ./usr/gen_init_cpio usr/crash.list *** buffer overflow detected ***: ./usr/gen_init_cpio terminated This also replaces the space-indenting with tabs. Patch based on existing fix extracted from grsecurity. Signed-off-by: Kees Cook Cc: Michal Marek Cc: Brad Spengler Cc: PaX Team Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- usr/gen_init_cpio.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index af0f22fb1ef..aca6edcbbc6 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -303,7 +303,7 @@ static int cpio_mkfile(const char *name, const char *location, int retval; int rc = -1; int namesize; - int i; + unsigned int i; mode |= S_IFREG; @@ -381,25 +381,28 @@ static int cpio_mkfile(const char *name, const char *location, static char *cpio_replace_env(char *new_location) { - char expanded[PATH_MAX + 1]; - char env_var[PATH_MAX + 1]; - char *start; - char *end; - - for (start = NULL; (start = strstr(new_location, "${")); ) { - end = strchr(start, '}'); - if (start < end) { - *env_var = *expanded = '\0'; - strncat(env_var, start + 2, end - start - 2); - strncat(expanded, new_location, start - new_location); - strncat(expanded, getenv(env_var), PATH_MAX); - strncat(expanded, end + 1, PATH_MAX); - strncpy(new_location, expanded, PATH_MAX); - } else - break; - } - - return new_location; + char expanded[PATH_MAX + 1]; + char env_var[PATH_MAX + 1]; + char *start; + char *end; + + for (start = NULL; (start = strstr(new_location, "${")); ) { + end = strchr(start, '}'); + if (start < end) { + *env_var = *expanded = '\0'; + strncat(env_var, start + 2, end - start - 2); + strncat(expanded, new_location, start - new_location); + strncat(expanded, getenv(env_var), + PATH_MAX - strlen(expanded)); + strncat(expanded, end + 1, + PATH_MAX - strlen(expanded)); + strncpy(new_location, expanded, PATH_MAX); + new_location[PATH_MAX] = 0; + } else + break; + } + + return new_location; } From 6fddae5c4eda4ebc63ae47f3d47e142ca08b31ff Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 25 Oct 2012 13:38:16 -0700 Subject: [PATCH 1323/2357] fs/compat_ioctl.c: VIDEO_SET_SPU_PALETTE missing error check commit 12176503366885edd542389eed3aaf94be163fdb upstream. The compat ioctl for VIDEO_SET_SPU_PALETTE was missing an error check while converting ioctl arguments. This could lead to leaking kernel stack contents into userspace. Patch extracted from existing fix in grsecurity. Signed-off-by: Kees Cook Cc: David Miller Cc: Brad Spengler Cc: PaX Team Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/compat_ioctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index debdfe0fc80..5d2069ff635 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -210,6 +210,8 @@ static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd, err = get_user(palp, &up->palette); err |= get_user(length, &up->length); + if (err) + return -EFAULT; up_native = compat_alloc_user_space(sizeof(struct video_spu_palette)); err = put_user(compat_ptr(palp), &up_native->palette); From 3146a25c513a1a3d5452db06d711a0a816e76584 Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Thu, 25 Oct 2012 13:38:11 -0700 Subject: [PATCH 1324/2357] drivers/rtc/rtc-imxdi.c: add missing spin lock initialization commit fee0de7791f967c2c5f0d43eb7b7261761b45e64 upstream. Signed-off-by: Jan Luebbe Cc: Alessandro Zummo Cc: Roland Stigge Cc: Grant Likely Tested-by: Roland Stigge Cc: Sascha Hauer Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-imxdi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index d93a9608b1f..bc744b490b0 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -392,6 +392,8 @@ static int dryice_rtc_probe(struct platform_device *pdev) if (imxdi->ioaddr == NULL) return -ENOMEM; + spin_lock_init(&imxdi->irq_lock); + imxdi->irq = platform_get_irq(pdev, 0); if (imxdi->irq < 0) return imxdi->irq; From 24d1745f4d77918e78ff0095ab233ff4f786287c Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Thu, 25 Oct 2012 13:37:51 -0700 Subject: [PATCH 1325/2357] genalloc: stop crashing the system when destroying a pool commit eedce141cd2dad8d0cefc5468ef41898949a7031 upstream. The genalloc code uses the bitmap API from include/linux/bitmap.h and lib/bitmap.c, which is based on long values. Both bitmap_set from lib/bitmap.c and bitmap_set_ll, which is the lockless version from genalloc.c, use BITMAP_LAST_WORD_MASK to set the first bits in a long in the bitmap. That one uses (1 << bits) - 1, 0b111, if you are setting the first three bits. This means that the API counts from the least significant bits (LSB from now on) to the MSB. The LSB in the first long is bit 0, then. The same works for the lookup functions. The genalloc code uses longs for the bitmap, as it should. In include/linux/genalloc.h, struct gen_pool_chunk has unsigned long bits[0] as its last member. When allocating the struct, genalloc should reserve enough space for the bitmap. This should be a proper number of longs that can fit the amount of bits in the bitmap. However, genalloc allocates an integer number of bytes that fit the amount of bits, but may not be an integer amount of longs. 9 bytes, for example, could be allocated for 70 bits. This is a problem in itself if the Least Significat Bit in a long is in the byte with the largest address, which happens in Big Endian machines. This means genalloc is not allocating the byte in which it will try to set or check for a bit. This may end up in memory corruption, where genalloc will try to set the bits it has not allocated. In fact, genalloc may not set these bits because it may find them already set, because they were not zeroed since they were not allocated. And that's what causes a BUG when gen_pool_destroy is called and check for any set bits. What really happens is that genalloc uses kmalloc_node with __GFP_ZERO on gen_pool_add_virt. With SLAB and SLUB, this means the whole slab will be cleared, not only the requested bytes. Since struct gen_pool_chunk has a size that is a multiple of 8, and slab sizes are multiples of 8, we get lucky and allocate and clear the right amount of bytes. Hower, this is not the case with SLOB or with older code that did memset after allocating instead of using __GFP_ZERO. So, a simple module as this (running 3.6.0), will cause a crash when rmmod'ed. [root@phantom-lp2 foo]# cat foo.c #include #include #include #include MODULE_LICENSE("GPL"); MODULE_VERSION("0.1"); static struct gen_pool *foo_pool; static __init int foo_init(void) { int ret; foo_pool = gen_pool_create(10, -1); if (!foo_pool) return -ENOMEM; ret = gen_pool_add(foo_pool, 0xa0000000, 32 << 10, -1); if (ret) { gen_pool_destroy(foo_pool); return ret; } return 0; } static __exit void foo_exit(void) { gen_pool_destroy(foo_pool); } module_init(foo_init); module_exit(foo_exit); [root@phantom-lp2 foo]# zcat /proc/config.gz | grep SLOB CONFIG_SLOB=y [root@phantom-lp2 foo]# insmod ./foo.ko [root@phantom-lp2 foo]# rmmod foo ------------[ cut here ]------------ kernel BUG at lib/genalloc.c:243! cpu 0x4: Vector: 700 (Program Check) at [c0000000bb0e7960] pc: c0000000003cb50c: .gen_pool_destroy+0xac/0x110 lr: c0000000003cb4fc: .gen_pool_destroy+0x9c/0x110 sp: c0000000bb0e7be0 msr: 8000000000029032 current = 0xc0000000bb0e0000 paca = 0xc000000006d30e00 softe: 0 irq_happened: 0x01 pid = 13044, comm = rmmod kernel BUG at lib/genalloc.c:243! [c0000000bb0e7ca0] d000000004b00020 .foo_exit+0x20/0x38 [foo] [c0000000bb0e7d20] c0000000000dff98 .SyS_delete_module+0x1a8/0x290 [c0000000bb0e7e30] c0000000000097d4 syscall_exit+0x0/0x94 --- Exception: c00 (System Call) at 000000800753d1a0 SP (fffd0b0e640) is in userspace Signed-off-by: Thadeu Lima de Souza Cascardo Cc: Paul Gortmaker Cc: Benjamin Gaignard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- lib/genalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/genalloc.c b/lib/genalloc.c index 6bc04aab6ec..7cb7a5dac09 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -176,7 +176,7 @@ int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phy struct gen_pool_chunk *chunk; int nbits = size >> pool->min_alloc_order; int nbytes = sizeof(struct gen_pool_chunk) + - (nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + BITS_TO_LONGS(nbits) * sizeof(long); chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid); if (unlikely(chunk == NULL)) From c87ece5a158f3907193202d84f2a316a4c363768 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 19 Oct 2012 17:53:01 +0100 Subject: [PATCH 1326/2357] ARM: 7559/1: smp: switch away from the idmap before updating init_mm.mm_count commit 5f40b909728ad784eb43aa309d3c4e9bdf050781 upstream. When booting a secondary CPU, the primary CPU hands two sets of page tables via the secondary_data struct: (1) swapper_pg_dir: a normal, cacheable, shared (if SMP) mapping of the kernel image (i.e. the tables used by init_mm). (2) idmap_pgd: an uncached mapping of the .idmap.text ELF section. The idmap is generally used when enabling and disabling the MMU, which includes early CPU boot. In this case, the secondary CPU switches to swapper as soon as it enters C code: struct mm_struct *mm = &init_mm; unsigned int cpu = smp_processor_id(); /* * All kernel threads share the same mm context; grab a * reference and switch to it. */ atomic_inc(&mm->mm_count); current->active_mm = mm; cpumask_set_cpu(cpu, mm_cpumask(mm)); cpu_switch_mm(mm->pgd, mm); This causes a problem on ARMv7, where the identity mapping is treated as strongly-ordered leading to architecturally UNPREDICTABLE behaviour of exclusive accesses, such as those used by atomic_inc. This patch re-orders the secondary_start_kernel function so that we switch to swapper before performing any exclusive accesses. Reported-by: Gilles Chanteperdrix Cc: David McKay Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/smp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 7babc3f98a1..8f14a1b8975 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -249,18 +249,24 @@ static void percpu_timer_setup(void); asmlinkage void __cpuinit secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; - unsigned int cpu = smp_processor_id(); + unsigned int cpu; + + /* + * The identity mapping is uncached (strongly ordered), so + * switch away from it before attempting any exclusive accesses. + */ + cpu_switch_mm(mm->pgd, mm); + enter_lazy_tlb(mm, current); + local_flush_tlb_all(); /* * All kernel threads share the same mm context; grab a * reference and switch to it. */ + cpu = smp_processor_id(); atomic_inc(&mm->mm_count); current->active_mm = mm; cpumask_set_cpu(cpu, mm_cpumask(mm)); - cpu_switch_mm(mm->pgd, mm); - enter_lazy_tlb(mm, current); - local_flush_tlb_all(); printk("CPU%u: Booted secondary processor\n", cpu); From 368845fde9e704288f370df57988767aab6042b4 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 22 Oct 2012 16:35:18 -0700 Subject: [PATCH 1327/2357] x86, mm: Trim memory in memblock to be page aligned commit 6ede1fd3cb404c0016de6ac529df46d561bd558b upstream. We will not map partial pages, so need to make sure memblock allocation will not allocate those bytes out. Also we will use for_each_mem_pfn_range() to loop to map memory range to keep them consistent. Signed-off-by: Yinghai Lu Link: http://lkml.kernel.org/r/CAE9FiQVZirvaBMFYRfXMmWEcHbKSicQEHz4VAwUv0xFCk51ZNw@mail.gmail.com Acked-by: Jacob Shin Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/e820.c | 3 +++ include/linux/memblock.h | 1 + mm/memblock.c | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 62d61e9976e..298dc000378 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -1076,6 +1076,9 @@ void __init memblock_x86_fill(void) memblock_add(ei->addr, ei->size); } + /* throw away partial pages */ + memblock_trim_memory(PAGE_SIZE); + memblock_dump_all(); } diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 19dc455b4f3..c948c440ea2 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -57,6 +57,7 @@ int memblock_add(phys_addr_t base, phys_addr_t size); int memblock_remove(phys_addr_t base, phys_addr_t size); int memblock_free(phys_addr_t base, phys_addr_t size); int memblock_reserve(phys_addr_t base, phys_addr_t size); +void memblock_trim_memory(phys_addr_t align); #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn, diff --git a/mm/memblock.c b/mm/memblock.c index 280d3d7835d..11e5bd174f3 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -908,6 +908,30 @@ int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t si return memblock_overlaps_region(&memblock.reserved, base, size) >= 0; } +void __init_memblock memblock_trim_memory(phys_addr_t align) +{ + int i; + phys_addr_t start, end, orig_start, orig_end; + struct memblock_type *mem = &memblock.memory; + + for (i = 0; i < mem->cnt; i++) { + orig_start = mem->regions[i].base; + orig_end = mem->regions[i].base + mem->regions[i].size; + start = round_up(orig_start, align); + end = round_down(orig_end, align); + + if (start == orig_start && end == orig_end) + continue; + + if (start < end) { + mem->regions[i].base = start; + mem->regions[i].size = end - start; + } else { + memblock_remove_region(mem, i); + i--; + } + } +} void __init_memblock memblock_set_current_limit(phys_addr_t limit) { From 71a36b53c81c3ecd1359af68ca4373e7d941a4c5 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 25 Oct 2012 13:37:31 -0700 Subject: [PATCH 1328/2357] mm: fix XFS oops due to dirty pages without buffers on s390 commit ef5d437f71afdf4afdbab99213add99f4b1318fd upstream. On s390 any write to a page (even from kernel itself) sets architecture specific page dirty bit. Thus when a page is written to via buffered write, HW dirty bit gets set and when we later map and unmap the page, page_remove_rmap() finds the dirty bit and calls set_page_dirty(). Dirtying of a page which shouldn't be dirty can cause all sorts of problems to filesystems. The bug we observed in practice is that buffers from the page get freed, so when the page gets later marked as dirty and writeback writes it, XFS crashes due to an assertion BUG_ON(!PagePrivate(page)) in page_buffers() called from xfs_count_page_state(). Similar problem can also happen when zero_user_segment() call from xfs_vm_writepage() (or block_write_full_page() for that matter) set the hardware dirty bit during writeback, later buffers get freed, and then page unmapped. Fix the issue by ignoring s390 HW dirty bit for page cache pages of mappings with mapping_cap_account_dirty(). This is safe because for such mappings when a page gets marked as writeable in PTE it is also marked dirty in do_wp_page() or do_page_fault(). When the dirty bit is cleared by clear_page_dirty_for_io(), the page gets writeprotected in page_mkclean(). So pagecache page is writeable if and only if it is dirty. Thanks to Hugh Dickins for pointing out mapping has to have mapping_cap_account_dirty() for things to work and proposing a cleaned up variant of the patch. The patch has survived about two hours of running fsx-linux on tmpfs while heavily swapping and several days of running on out build machines where the original problem was triggered. Signed-off-by: Jan Kara Cc: Martin Schwidefsky Cc: Mel Gorman Cc: Hugh Dickins Cc: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/rmap.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/mm/rmap.c b/mm/rmap.c index 5b5ad584ffb..bfca52c9699 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -56,6 +56,7 @@ #include #include #include +#include #include @@ -977,11 +978,8 @@ int page_mkclean(struct page *page) if (page_mapped(page)) { struct address_space *mapping = page_mapping(page); - if (mapping) { + if (mapping) ret = page_mkclean_file(mapping, page); - if (page_test_and_clear_dirty(page_to_pfn(page), 1)) - ret = 1; - } } return ret; @@ -1167,6 +1165,7 @@ void page_add_file_rmap(struct page *page) */ void page_remove_rmap(struct page *page) { + struct address_space *mapping = page_mapping(page); bool anon = PageAnon(page); bool locked; unsigned long flags; @@ -1189,8 +1188,19 @@ void page_remove_rmap(struct page *page) * this if the page is anon, so about to be freed; but perhaps * not if it's in swapcache - there might be another pte slot * containing the swap entry, but page not yet written to swap. + * + * And we can skip it on file pages, so long as the filesystem + * participates in dirty tracking; but need to catch shm and tmpfs + * and ramfs pages which have been modified since creation by read + * fault. + * + * Note that mapping must be decided above, before decrementing + * mapcount (which luckily provides a barrier): once page is unmapped, + * it could be truncated and page->mapping reset to NULL at any moment. + * Note also that we are relying on page_mapping(page) to set mapping + * to &swapper_space when PageSwapCache(page). */ - if ((!anon || PageSwapCache(page)) && + if (mapping && !mapping_cap_account_dirty(mapping) && page_test_and_clear_dirty(page_to_pfn(page), 1)) set_page_dirty(page); /* From 9f659caf90048296ca120143964222c3f8b6dae7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 22 Oct 2012 17:14:36 -0400 Subject: [PATCH 1329/2357] SUNRPC: Get rid of the xs_error_report socket callback commit f878b657ce8e7d3673afe48110ec208a29e38c4a upstream. Chris Perl reports that we're seeing races between the wakeup call in xs_error_report and the connect attempts. Basically, Chris has shown that in certain circumstances, the call to xs_error_report causes the rpc_task that is responsible for reconnecting to wake up early, thus triggering a disconnect and retry. Since the sk->sk_error_report() calls in the socket layer are always followed by a tcp_done() in the cases where we care about waking up the rpc_tasks, just let the state_change callbacks take responsibility for those wake ups. Reported-by: Chris Perl Signed-off-by: Trond Myklebust Tested-by: Chris Perl Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtsock.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index a4a6586f403..6581a9de579 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -254,7 +254,6 @@ struct sock_xprt { void (*old_data_ready)(struct sock *, int); void (*old_state_change)(struct sock *); void (*old_write_space)(struct sock *); - void (*old_error_report)(struct sock *); }; /* @@ -781,7 +780,6 @@ static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk) transport->old_data_ready = sk->sk_data_ready; transport->old_state_change = sk->sk_state_change; transport->old_write_space = sk->sk_write_space; - transport->old_error_report = sk->sk_error_report; } static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk) @@ -789,7 +787,6 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s sk->sk_data_ready = transport->old_data_ready; sk->sk_state_change = transport->old_state_change; sk->sk_write_space = transport->old_write_space; - sk->sk_error_report = transport->old_error_report; } static void xs_reset_transport(struct sock_xprt *transport) @@ -1552,25 +1549,6 @@ static void xs_tcp_state_change(struct sock *sk) read_unlock_bh(&sk->sk_callback_lock); } -/** - * xs_error_report - callback mainly for catching socket errors - * @sk: socket - */ -static void xs_error_report(struct sock *sk) -{ - struct rpc_xprt *xprt; - - read_lock_bh(&sk->sk_callback_lock); - if (!(xprt = xprt_from_sock(sk))) - goto out; - dprintk("RPC: %s client %p...\n" - "RPC: error %d\n", - __func__, xprt, sk->sk_err); - xprt_wake_pending_tasks(xprt, -EAGAIN); -out: - read_unlock_bh(&sk->sk_callback_lock); -} - static void xs_write_space(struct sock *sk) { struct socket *sock; @@ -1870,7 +1848,6 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt, sk->sk_user_data = xprt; sk->sk_data_ready = xs_local_data_ready; sk->sk_write_space = xs_udp_write_space; - sk->sk_error_report = xs_error_report; sk->sk_allocation = GFP_ATOMIC; xprt_clear_connected(xprt); @@ -1959,7 +1936,6 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) sk->sk_user_data = xprt; sk->sk_data_ready = xs_udp_data_ready; sk->sk_write_space = xs_udp_write_space; - sk->sk_error_report = xs_error_report; sk->sk_no_check = UDP_CSUM_NORCV; sk->sk_allocation = GFP_ATOMIC; @@ -2075,7 +2051,6 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) sk->sk_data_ready = xs_tcp_data_ready; sk->sk_state_change = xs_tcp_state_change; sk->sk_write_space = xs_tcp_write_space; - sk->sk_error_report = xs_error_report; sk->sk_allocation = GFP_ATOMIC; /* socket options */ From ea2887242aafd45727ca22564105fd244f4c6584 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 23 Oct 2012 11:35:47 -0400 Subject: [PATCH 1330/2357] SUNRPC: Clear the connect flag when socket state is TCP_CLOSE_WAIT commit d0bea455dd48da1ecbd04fedf00eb89437455fdc upstream. This is needed to ensure that we call xprt_connect() upon the next call to call_connect(). Signed-off-by: Trond Myklebust Tested-by: Chris Perl Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtsock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 6581a9de579..b34cf303d91 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1525,6 +1525,7 @@ static void xs_tcp_state_change(struct sock *sk) case TCP_CLOSE_WAIT: /* The server initiated a shutdown of the socket */ xprt->connect_cookie++; + clear_bit(XPRT_CONNECTED, &xprt->state); xs_tcp_force_close(xprt); case TCP_CLOSING: /* From dedf1c2d17cd81796fc25190fd194e8dd0269817 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 23 Oct 2012 11:40:02 -0400 Subject: [PATCH 1331/2357] Revert "SUNRPC: Ensure we close the socket on EPIPE errors too..." commit b9d2bb2ee537424a7f855e1f93eed44eb9ee0854 upstream. This reverts commit 55420c24a0d4d1fce70ca713f84aa00b6b74a70e. Now that we clear the connected flag when entering TCP_CLOSE_WAIT, the deadlock described in this commit is no longer possible. Instead, the resulting call to xs_tcp_shutdown() can interfere with pending reconnection attempts. Reported-by: Chris Perl Signed-off-by: Trond Myklebust Tested-by: Chris Perl Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index b34cf303d91..fc197c275e1 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -736,10 +736,10 @@ static int xs_tcp_send_request(struct rpc_task *task) dprintk("RPC: sendmsg returned unrecognized error %d\n", -status); case -ECONNRESET: - case -EPIPE: xs_tcp_shutdown(xprt); case -ECONNREFUSED: case -ENOTCONN: + case -EPIPE: clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); } From 6c6dff65535906e5a7a27010447fad0cb316a1fb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 23 Oct 2012 17:50:07 -0400 Subject: [PATCH 1332/2357] SUNRPC: Prevent races in xs_abort_connection() commit 4bc1e68ed6a8b59be8a79eb719be515a55c7bc68 upstream. The call to xprt_disconnect_done() that is triggered by a successful connection reset will trigger another automatic wakeup of all tasks on the xprt->pending rpc_wait_queue. In particular it will cause an early wake up of the task that called xprt_connect(). All we really want to do here is clear all the socket-specific state flags, so we split that functionality out of xs_sock_mark_closed() into a helper that can be called by xs_abort_connection() Reported-by: Chris Perl Signed-off-by: Trond Myklebust Tested-by: Chris Perl Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtsock.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index fc197c275e1..79064471cd0 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1462,7 +1462,7 @@ static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt) xprt_clear_connecting(xprt); } -static void xs_sock_mark_closed(struct rpc_xprt *xprt) +static void xs_sock_reset_connection_flags(struct rpc_xprt *xprt) { smp_mb__before_clear_bit(); clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); @@ -1470,6 +1470,11 @@ static void xs_sock_mark_closed(struct rpc_xprt *xprt) clear_bit(XPRT_CLOSE_WAIT, &xprt->state); clear_bit(XPRT_CLOSING, &xprt->state); smp_mb__after_clear_bit(); +} + +static void xs_sock_mark_closed(struct rpc_xprt *xprt) +{ + xs_sock_reset_connection_flags(xprt); /* Mark transport as closed and wake up all pending tasks */ xprt_disconnect_done(xprt); } @@ -2004,10 +2009,8 @@ static void xs_abort_connection(struct sock_xprt *transport) any.sa_family = AF_UNSPEC; result = kernel_connect(transport->sock, &any, sizeof(any), 0); if (!result) - xs_sock_mark_closed(&transport->xprt); - else - dprintk("RPC: AF_UNSPEC connect return code %d\n", - result); + xs_sock_reset_connection_flags(&transport->xprt); + dprintk("RPC: AF_UNSPEC connect return code %d\n", result); } static void xs_tcp_reuse_connection(struct sock_xprt *transport) From 325c6bf91fd3c2e4fea473e9ca4eb30666dadb52 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 16 Oct 2012 13:17:43 -0700 Subject: [PATCH 1333/2357] xhci: Fix potential NULL ptr deref in command cancellation. commit 43a09f7fb01fa1e091416a2aa49b6c666458c1ee upstream. The command cancellation code doesn't check whether find_trb_seg() couldn't find the segment that contains the TRB to be canceled. This could cause a NULL pointer deference later in the function when next_trb is called. It's unlikely to happen unless something is wrong with the command ring pointers, so add some debugging in case it happens. This patch should be backported to stable kernels as old as 3.0, that contain the commit b63f4053cc8aa22a98e3f9a97845afe6c15d0a0d "xHCI: handle command after aborting the command ring". Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a23d71bba75..23aebcb4ee2 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1228,6 +1228,17 @@ static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd) cur_seg = find_trb_seg(xhci->cmd_ring->first_seg, xhci->cmd_ring->dequeue, &cycle_state); + if (!cur_seg) { + xhci_warn(xhci, "Command ring mismatch, dequeue = %p %llx (dma)\n", + xhci->cmd_ring->dequeue, + (unsigned long long) + xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, + xhci->cmd_ring->dequeue)); + xhci_debug_ring(xhci, xhci->cmd_ring); + xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); + return; + } + /* find the command trb matched by cd from command ring */ for (cmd_trb = xhci->cmd_ring->dequeue; cmd_trb != xhci->cmd_ring->enqueue; From fa3b39b05f40bf7273bcd6c152f0b59005b83480 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 29 Sep 2012 22:23:19 +0200 Subject: [PATCH 1334/2357] sysfs: sysfs_pathname/sysfs_add_one: Use strlcat() instead of strcat() commit 66081a72517a131430dcf986775f3268aafcb546 upstream. The warning check for duplicate sysfs entries can cause a buffer overflow when printing the warning, as strcat() doesn't check buffer sizes. Use strlcat() instead. Since strlcat() doesn't return a pointer to the passed buffer, unlike strcat(), I had to convert the nested concatenation in sysfs_add_one() to an admittedly more obscure comma operator construct, to avoid emitting code for the concatenation if CONFIG_BUG is disabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 35a36d39fa2..a545d819b49 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -457,20 +457,18 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) /** * sysfs_pathname - return full path to sysfs dirent * @sd: sysfs_dirent whose path we want - * @path: caller allocated buffer + * @path: caller allocated buffer of size PATH_MAX * * Gives the name "/" to the sysfs_root entry; any path returned * is relative to wherever sysfs is mounted. - * - * XXX: does no error checking on @path size */ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) { if (sd->s_parent) { sysfs_pathname(sd->s_parent, path); - strcat(path, "/"); + strlcat(path, "/", PATH_MAX); } - strcat(path, sd->s_name); + strlcat(path, sd->s_name, PATH_MAX); return path; } @@ -503,9 +501,11 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) char *path = kzalloc(PATH_MAX, GFP_KERNEL); WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n", - (path == NULL) ? sd->s_name : - strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"), - sd->s_name)); + (path == NULL) ? sd->s_name + : (sysfs_pathname(acxt->parent_sd, path), + strlcat(path, "/", PATH_MAX), + strlcat(path, sd->s_name, PATH_MAX), + path)); kfree(path); } From c70fc22aa9f442379b1f64e863b8adf8da2356e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Tue, 16 Oct 2012 15:29:54 -0700 Subject: [PATCH 1335/2357] Staging: android: binder: Fix memory leak on thread/process exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 675d66b0ed5fd170d6a44cf8dbb3fa56a5347bdb upstream. If a thread or process exited while a reply, one-way transaction or death notification was pending, the struct holding the pending work was leaked. Signed-off-by: Arve Hjønnevåg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/binder.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index c2832124bb3..80acd0e6a57 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -2507,14 +2507,38 @@ static void binder_release_work(struct list_head *list) struct binder_transaction *t; t = container_of(w, struct binder_transaction, work); - if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) + if (t->buffer->target_node && + !(t->flags & TF_ONE_WAY)) { binder_send_failed_reply(t, BR_DEAD_REPLY); + } else { + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "binder: undelivered transaction %d\n", + t->debug_id); + t->buffer->transaction = NULL; + kfree(t); + binder_stats_deleted(BINDER_STAT_TRANSACTION); + } } break; case BINDER_WORK_TRANSACTION_COMPLETE: { + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "binder: undelivered TRANSACTION_COMPLETE\n"); kfree(w); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); } break; + case BINDER_WORK_DEAD_BINDER_AND_CLEAR: + case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { + struct binder_ref_death *death; + + death = container_of(w, struct binder_ref_death, work); + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "binder: undelivered death notification, %p\n", + death->cookie); + kfree(death); + binder_stats_deleted(BINDER_STAT_DEATH); + } break; default: + pr_err("binder: unexpected work type, %d, not freed\n", + w->type); break; } } @@ -2984,6 +3008,7 @@ static void binder_deferred_release(struct binder_proc *proc) nodes++; rb_erase(&node->rb_node, &proc->nodes); list_del_init(&node->work.entry); + binder_release_work(&node->async_todo); if (hlist_empty(&node->refs)) { kfree(node); binder_stats_deleted(BINDER_STAT_NODE); @@ -3022,6 +3047,7 @@ static void binder_deferred_release(struct binder_proc *proc) binder_delete_ref(ref); } binder_release_work(&proc->todo); + binder_release_work(&proc->delivered_death); buffers = 0; while ((n = rb_first(&proc->allocated_buffers))) { From 7b76336ec39f1af832ebd29add93cfe21e839581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Tue, 16 Oct 2012 15:29:55 -0700 Subject: [PATCH 1336/2357] Staging: android: binder: Allow using highmem for binder buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 585650dcec88e704a19bb226a34b6a7166111623 upstream. The default kernel mapping for the pages allocated for the binder buffers is never used. Set the __GFP_HIGHMEM flag when allocating these pages so we don't needlessly use low memory pages that may be required elsewhere. Signed-off-by: Arve Hjønnevåg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/binder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 80acd0e6a57..223639a73b0 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -655,7 +655,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; BUG_ON(*page); - *page = alloc_page(GFP_KERNEL | __GFP_ZERO); + *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); if (*page == NULL) { printk(KERN_ERR "binder: %d: binder_alloc_buf failed " "for page at %p\n", proc->pid, page_addr); From 057f0772b32f9a162c5104b1928b5886f1b85059 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 12 Oct 2012 13:22:42 -0700 Subject: [PATCH 1337/2357] Drivers: hv: Cleanup error handling in vmbus_open() commit 1392550240aaa72ce3a094a38bd23525cd67ce60 upstream. Fix a memory leak in the error handling path in the function vmbus_open(). Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Reported-by: Jason Wang Acked-by: Jason Wang Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 406537420ff..f4c3d28cd1f 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -146,14 +146,14 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, if (ret != 0) { err = ret; - goto errorout; + goto error0; } ret = hv_ringbuffer_init( &newchannel->inbound, in, recv_ringbuffer_size); if (ret != 0) { err = ret; - goto errorout; + goto error0; } @@ -168,7 +168,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, if (ret != 0) { err = ret; - goto errorout; + goto error0; } /* Create and init the channel open message */ @@ -177,7 +177,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, GFP_KERNEL); if (!open_info) { err = -ENOMEM; - goto errorout; + goto error0; } init_completion(&open_info->waitevent); @@ -193,7 +193,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, if (userdatalen > MAX_USER_DEFINED_BYTES) { err = -EINVAL; - goto errorout; + goto error0; } if (userdatalen) @@ -208,19 +208,18 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, sizeof(struct vmbus_channel_open_channel)); if (ret != 0) - goto cleanup; + goto error1; t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ); if (t == 0) { err = -ETIMEDOUT; - goto errorout; + goto error1; } if (open_info->response.open_result.status) err = open_info->response.open_result.status; -cleanup: spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&open_info->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); @@ -228,9 +227,12 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, kfree(open_info); return err; -errorout: - hv_ringbuffer_cleanup(&newchannel->outbound); - hv_ringbuffer_cleanup(&newchannel->inbound); +error1: + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); + list_del(&open_info->msglistentry); + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); + +error0: free_pages((unsigned long)out, get_order(send_ringbuffer_size + recv_ringbuffer_size)); kfree(open_info); From a8091a3cbabad7616b565a4d7148e8e6c565cdeb Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Tue, 9 Oct 2012 12:22:36 +0200 Subject: [PATCH 1338/2357] ehci: fix Lucid nohandoff pci quirk to be more generic with BIOS versions commit c323dc023b9501e5d09582ec7efd1d40a9001d99 upstream. BIOS vendors keep changing the BIOS versions. Only match the beginning of the string to match all Lucid tablets with board name M11JB. Signed-off-by: Anisse Astier Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 966d1484ee7..ead45259bf1 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -545,7 +545,7 @@ static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = { /* Pegatron Lucid (Ordissimo AIRIS) */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "M11JB"), - DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"), + DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"), }, }, { } From 145f944257416e38ef00505f07cac17e86ef9655 Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Tue, 9 Oct 2012 12:22:37 +0200 Subject: [PATCH 1339/2357] ehci: Add yet-another Lucid nohandoff pci quirk commit 8daf8b6086f9d575200cd0aa3797e26137255609 upstream. Board name changed on another shipping Lucid tablet. Signed-off-by: Anisse Astier Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index ead45259bf1..39f9e4a9a2d 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -548,6 +548,13 @@ static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"), }, }, + { + /* Pegatron Lucid (Ordissimo) */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "Ordissimo"), + DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"), + }, + }, { } }; From 313f0fd814835c64b90d14be716a6fedbbd4b08e Mon Sep 17 00:00:00 2001 From: Michael Shigorin Date: Mon, 22 Oct 2012 12:18:56 +0300 Subject: [PATCH 1340/2357] usb-storage: add unusual_devs entry for Casio EX-N1 digital camera commit d7870af7e2e3a91b462075ec1ca669b482215187 upstream. This commit sets removable subclass for Casio EX-N1 digital camera. The patch has been tested within an ALT Linux kernel: http://git.altlinux.org/people/led/packages/?p=kernel-image-3.0.git;a=commitdiff;h=c0fd891836e89fe0c93a4d536a59216d90e4e3e7 See also https://bugzilla.kernel.org/show_bug.cgi?id=49221 Signed-off-by: Oleksandr Chumachenko Signed-off-by: Michael Shigorin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 8f3cbb8dc81..5ffa11640de 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1004,6 +1004,12 @@ UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9999, USB_SC_8070, USB_PR_CB, NULL, US_FL_NEED_OVERRIDE | US_FL_FIX_INQUIRY ), +/* Submitted by Oleksandr Chumachenko */ +UNUSUAL_DEV( 0x07cf, 0x1167, 0x0100, 0x0100, + "Casio", + "EX-N1 DigitalCamera", + USB_SC_8070, USB_PR_DEVICE, NULL, 0), + /* Submitted by Hartmut Wahl */ UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001, "Samsung", From 891fe9688fbd2ef1c04d8314b74c0037be2adb89 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Mon, 1 Oct 2012 22:21:12 +0300 Subject: [PATCH 1341/2357] usb hub: send clear_tt_buffer_complete events when canceling TT clear work commit 3b6054da68f9b0d5ed6a7ed0f42a79e61904352c upstream. There is a race condition in the USB hub code with regard to handling TT clear requests that can get the HCD driver in a deadlock. Usually when an TT clear request is scheduled it will be executed immediately: <7>[ 6.077583] usb 2-1.3: unlink qh1-0e01/f4d4db00 start 0 [1/2 us] <3>[ 6.078041] usb 2-1: clear tt buffer port 3, a3 ep2 t04048d82 <7>[ 6.078299] hub_tt_work:731 <7>[ 9.309089] usb 2-1.5: link qh1-0e01/f4d506c0 start 0 [1/2 us] <7>[ 9.324526] ehci_hcd 0000:00:1d.0: reused qh f4d4db00 schedule <7>[ 9.324539] usb 2-1.3: link qh1-0e01/f4d4db00 start 0 [1/2 us] <7>[ 9.341530] usb 1-1.1: link qh4-0e01/f397aec0 start 2 [1/2 us] <7>[ 10.116159] usb 2-1.3: unlink qh1-0e01/f4d4db00 start 0 [1/2 us] <3>[ 10.116459] usb 2-1: clear tt buffer port 3, a3 ep2 t04048d82 <7>[ 10.116537] hub_tt_work:731 However, if a suspend operation is triggered before hub_tt_work is scheduled, hub_quiesce will cancel the work without notifying the HCD driver: <3>[ 35.033941] usb 2-1: clear tt buffer port 3, a3 ep2 t04048d80 <5>[ 35.034022] sd 0:0:0:0: [sda] Stopping disk <7>[ 35.034039] hub 2-1:1.0: hub_suspend <7>[ 35.034067] usb 2-1: unlink qh256-0001/f3b1ab00 start 1 [1/0 us] <7>[ 35.035085] hub 1-0:1.0: hub_suspend <7>[ 35.035102] usb usb1: bus suspend, wakeup 0 <7>[ 35.035106] ehci_hcd 0000:00:1a.0: suspend root hub <7>[ 35.035298] hub 2-0:1.0: hub_suspend <7>[ 35.035313] usb usb2: bus suspend, wakeup 0 <7>[ 35.035315] ehci_hcd 0000:00:1d.0: suspend root hub <6>[ 35.250017] PM: suspend of devices complete after 216.979 msecs <6>[ 35.250822] PM: late suspend of devices complete after 0.799 msecs <7>[ 35.252343] ehci_hcd 0000:00:1d.0: wakeup: 1 <7>[ 35.262923] ehci_hcd 0000:00:1d.0: --> PCI D3hot <7>[ 35.263302] ehci_hcd 0000:00:1a.0: wakeup: 1 <7>[ 35.273912] ehci_hcd 0000:00:1a.0: --> PCI D3hot <6>[ 35.274254] PM: noirq suspend of devices complete after 23.442 msecs <6>[ 35.274975] ACPI: Preparing to enter system sleep state S3 <6>[ 35.292666] PM: Saving platform NVS memory <7>[ 35.295030] Disabling non-boot CPUs ... <6>[ 35.297351] CPU 1 is now offline <6>[ 35.300345] CPU 2 is now offline <6>[ 35.303929] CPU 3 is now offline <7>[ 35.303931] lockdep: fixing up alternatives. <6>[ 35.304825] Extended CMOS year: 2000 When the device will resume the EHCI driver will get stuck in ehci_endpoint_disable waiting for the tt_clearing flag to reset: <0>[ 47.610967] usb 2-1.3: **** DPM device timeout **** <7>[ 47.610972] f2f11c60 00000092 f2f11c0c c10624a5 00000003 f4c6e880 c1c8a4c0 c1c8a4c0 <7>[ 47.610983] 15c55698 0000000b f56b34c0 f2a45b70 f4c6e880 00000082 f2a4602c f2f11c30 <7>[ 47.610993] c10787f8 f4cac000 f2a45b70 00000000 f4cac010 f2f11c58 00000046 00000001 <7>[ 47.611004] Call Trace: <7>[ 47.611006] [] ? sched_clock_cpu+0xf5/0x160 <7>[ 47.611019] [] ? lock_release_holdtime.part.22+0x88/0xf0 <7>[ 47.611026] [] ? lock_timer_base.isra.35+0x26/0x50 <7>[ 47.611034] [] ? schedule_timeout+0x133/0x290 <7>[ 47.611044] [] schedule+0x1e/0x50 <7>[ 47.611051] [] schedule_timeout+0x138/0x290 <7>[ 47.611057] [] ? sched_clock_cpu+0xf5/0x160 <7>[ 47.611063] [] ? usleep_range+0x40/0x40 <7>[ 47.611070] [] schedule_timeout_uninterruptible+0x15/0x20 <7>[ 47.611077] [] ehci_endpoint_disable+0x64/0x160 <7>[ 47.611084] [] ? usb_hcd_flush_endpoint+0x10e/0x1d0 <7>[ 47.611092] [] ? sysfs_add_file+0x13/0x20 <7>[ 47.611100] [] usb_hcd_disable_endpoint+0x29/0x40 <7>[ 47.611107] [] usb_disable_endpoint+0x5c/0x80 <7>[ 47.611111] [] usb_disable_interface+0x37/0x50 <7>[ 47.611116] [] usb_reset_and_verify_device+0x4b0/0x640 <7>[ 47.611122] [] ? hub_port_status+0xb5/0x100 <7>[ 47.611129] [] usb_port_resume+0xd5/0x220 <7>[ 47.611136] [] generic_resume+0xf/0x30 <7>[ 47.611142] [] usb_resume+0x133/0x180 <7>[ 47.611147] [] ? usb_dev_thaw+0x10/0x10 <7>[ 47.611152] [] usb_dev_resume+0xd/0x10 <7>[ 47.611157] [] dpm_run_callback+0x40/0xb0 <7>[ 47.611164] [] ? pm_runtime_enable+0x43/0x70 <7>[ 47.611171] [] device_resume+0x1a6/0x2c0 <7>[ 47.611177] [] ? dpm_show_time+0xe0/0xe0 <7>[ 47.611183] [] async_resume+0x19/0x40 <7>[ 47.611189] [] async_run_entry_fn+0x64/0x160 <7>[ 47.611196] [] ? process_one_work+0x104/0x480 <7>[ 47.611203] [] ? process_one_work+0x10c/0x480 <7>[ 47.611209] [] process_one_work+0x180/0x480 <7>[ 47.611215] [] ? process_one_work+0x104/0x480 <7>[ 47.611220] [] ? async_schedule+0x10/0x10 <7>[ 47.611226] [] worker_thread+0x11c/0x2f0 <7>[ 47.611233] [] ? manage_workers.isra.27+0x1f0/0x1f0 <7>[ 47.611239] [] kthread+0x78/0x80 <7>[ 47.611244] [] ? timer_cpu_notify+0xd6/0x20d <7>[ 47.611253] [] ? __init_kthread_worker+0x60/0x60 <7>[ 47.611258] [] kernel_thread_helper+0x6/0xd <7>[ 47.611283] ------------[ cut here ]------------ This patch changes hub_quiesce behavior to flush the TT clear work instead of canceling it, to make sure that no TT clear request remains uncompleted before suspend. Signed-off-by: Octavian Purdila Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e727b876726..11344bcc175 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -507,13 +507,16 @@ static void hub_tt_work(struct work_struct *work) int limit = 100; spin_lock_irqsave (&hub->tt.lock, flags); - while (--limit && !list_empty (&hub->tt.clear_list)) { + while (!list_empty(&hub->tt.clear_list)) { struct list_head *next; struct usb_tt_clear *clear; struct usb_device *hdev = hub->hdev; const struct hc_driver *drv; int status; + if (!hub->quiescing && --limit < 0) + break; + next = hub->tt.clear_list.next; clear = list_entry (next, struct usb_tt_clear, clear_list); list_del (&clear->clear_list); @@ -978,7 +981,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) if (hub->has_indicators) cancel_delayed_work_sync(&hub->leds); if (hub->tt.hub) - cancel_work_sync(&hub->tt.clear_work); + flush_work_sync(&hub->tt.clear_work); } /* caller has locked the hub device */ From 02c6b1fd52e8987597f847aecc3a74c09a48083b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 10:29:01 +0200 Subject: [PATCH 1342/2357] USB: whiteheat: fix memory leak in error path commit c129197c99550d356cf5f69b046994dd53cd1b9d upstream. Make sure command buffer is deallocated in case of errors during attach. Signed-off-by: Johan Hovold Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/whiteheat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 407e23c8794..171226ab56f 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -525,6 +525,7 @@ static int whiteheat_attach(struct usb_serial *serial) "%s: please contact support@connecttech.com\n", serial->type->description); kfree(result); + kfree(command); return -ENODEV; no_command_private: From ce11958aa9b27e162fe2c1a23e50e318de0319c4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 10:29:11 +0200 Subject: [PATCH 1343/2357] USB: opticon: fix DMA from stack commit ea0dbebffe118724cd4df7d9b071ea8ee48d48f0 upstream. Make sure to allocate the control-message buffer dynamically as some platforms cannot do DMA from stack. Note that only the first byte of the old buffer was used. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/opticon.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 82cc9d202b8..c661c9c2998 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -160,7 +160,11 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype, { struct usb_serial *serial = port->serial; int retval; - u8 buffer[2]; + u8 *buffer; + + buffer = kzalloc(1, GFP_KERNEL); + if (!buffer) + return -ENOMEM; buffer[0] = val; /* Send the message to the vendor control endpoint @@ -169,6 +173,7 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype, requesttype, USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, 0, 0, buffer, 1, 0); + kfree(buffer); return retval; } From ed7d272780f5185e9ca38cd63effd06a43c00cb1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 10:29:12 +0200 Subject: [PATCH 1344/2357] USB: opticon: fix memory leak in error path commit acbf0e5263de563e25f7c104868e4490b9e72b13 upstream. Fix memory leak in write error path. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/opticon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index c661c9c2998..1f850065d15 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -297,7 +297,7 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, if (!dr) { dev_err(&port->dev, "out of memory\n"); count = -ENOMEM; - goto error; + goto error_no_dr; } dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT; @@ -327,6 +327,8 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, return count; error: + kfree(dr); +error_no_dr: usb_free_urb(urb); error_no_urb: kfree(buffer); From a58af76b5dbe701c2d194648c579690ac6c29efd Mon Sep 17 00:00:00 2001 From: Lennart Sorensen Date: Wed, 24 Oct 2012 10:23:09 -0400 Subject: [PATCH 1345/2357] USB: serial: Fix memory leak in sierra_release() commit f7bc5051667b74c3861f79eed98c60d5c3b883f7 upstream. I found a memory leak in sierra_release() (well sierra_probe() I guess) that looses 8 bytes each time the driver releases a device. Signed-off-by: Len Sorensen Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 449bf6d31e2..0223ca77d2d 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -992,6 +992,7 @@ static void sierra_release(struct usb_serial *serial) continue; kfree(portdata); } + kfree(serial->private); } #ifdef CONFIG_PM From 96e42e6acf74ad78cf9f37c2f2f2998ad7814929 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 10:29:17 +0200 Subject: [PATCH 1346/2357] USB: sierra: fix memory leak in attach error path commit 7e41f9bcdd2e813ea2a3c40db291d87ea06b559f upstream. Make sure port private data is deallocated on errors in attach. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 0223ca77d2d..3942f12f2ef 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -936,7 +936,7 @@ static int sierra_startup(struct usb_serial *serial) dev_dbg(&port->dev, "%s: kmalloc for " "sierra_port_private (%d) failed!\n", __func__, i); - return -ENOMEM; + goto err; } spin_lock_init(&portdata->lock); init_usb_anchor(&portdata->active); @@ -973,6 +973,13 @@ static int sierra_startup(struct usb_serial *serial) } return 0; +err: + for (--i; i >= 0; --i) { + portdata = usb_get_serial_port_data(serial->port[i]); + kfree(portdata); + } + + return -ENOMEM; } static void sierra_release(struct usb_serial *serial) From 5b312595bebcd2216f8617778a55ccaa93fc5a51 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 10:29:18 +0200 Subject: [PATCH 1347/2357] USB: sierra: fix memory leak in probe error path commit 084817d79399ab5ccab2f90a148b0369912a8369 upstream. Move interface data allocation to attach so that it is deallocated on errors in usb-serial probe. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 3942f12f2ef..b622d695fdb 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -171,7 +171,6 @@ static int sierra_probe(struct usb_serial *serial, { int result = 0; struct usb_device *udev; - struct sierra_intf_private *data; u8 ifnum; udev = serial->dev; @@ -199,11 +198,6 @@ static int sierra_probe(struct usb_serial *serial, return -ENODEV; } - data = serial->private = kzalloc(sizeof(struct sierra_intf_private), GFP_KERNEL); - if (!data) - return -ENOMEM; - spin_lock_init(&data->susp_lock); - return result; } @@ -914,6 +908,7 @@ static void sierra_dtr_rts(struct usb_serial_port *port, int on) static int sierra_startup(struct usb_serial *serial) { struct usb_serial_port *port; + struct sierra_intf_private *intfdata; struct sierra_port_private *portdata; struct sierra_iface_info *himemoryp = NULL; int i; @@ -921,6 +916,14 @@ static int sierra_startup(struct usb_serial *serial) dev_dbg(&serial->dev->dev, "%s\n", __func__); + intfdata = kzalloc(sizeof(*intfdata), GFP_KERNEL); + if (!intfdata) + return -ENOMEM; + + spin_lock_init(&intfdata->susp_lock); + + usb_set_serial_data(serial, intfdata); + /* Set Device mode to D0 */ sierra_set_power_state(serial->dev, 0x0000); @@ -978,6 +981,7 @@ static int sierra_startup(struct usb_serial *serial) portdata = usb_get_serial_port_data(serial->port[i]); kfree(portdata); } + kfree(intfdata); return -ENOMEM; } From b296aacfcceb3e6511b5d5fe77b22f5840ebe290 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 13:35:09 +0200 Subject: [PATCH 1348/2357] USB: mos7840: fix urb leak at release commit 65a4cdbb170e4ec1a7fa0e94936d47e24a17b0e8 upstream. Make sure control urb is freed at release. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c1505c3c557..1d87d9d88d9 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2657,6 +2657,7 @@ static void mos7840_release(struct usb_serial *serial) mos7840_port = mos7840_get_port_private(serial->port[i]); dbg("mos7840_port %d = %p", i, mos7840_port); if (mos7840_port) { + usb_free_urb(mos7840_port->control_urb); kfree(mos7840_port->ctrl_buf); kfree(mos7840_port->dr); kfree(mos7840_port); From 45af0b209e5bdd66804a07b06dec30b5ccaef2de Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 13:35:10 +0200 Subject: [PATCH 1349/2357] USB: mos7840: fix port-device leak in error path commit 3eb55cc4ed88eee3b5230f66abcdbd2a91639eda upstream. The driver set the usb-serial port pointers to NULL on errors in attach, effectively preventing usb-serial core from decrementing the port ref counters and releasing the port devices and associated data. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 1d87d9d88d9..672894f7312 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2590,7 +2590,6 @@ static int mos7840_startup(struct usb_serial *serial) kfree(mos7840_port->ctrl_buf); usb_free_urb(mos7840_port->control_urb); kfree(mos7840_port); - serial->port[i] = NULL; } return status; } From 380c05e97c6393557757dc180c04bc405de9b620 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 18:56:32 +0200 Subject: [PATCH 1350/2357] USB: mos7840: remove NULL-urb submission commit 28c3ae9a8cf45f439c9a0779ebd0256e2ae72813 upstream. The private int_urb is never allocated so the submission from the control completion handler will always fail. Remove this odd piece of broken code. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 672894f7312..6f07880552f 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -235,7 +235,6 @@ struct moschip_port { int port_num; /*Actual port number in the device(1,2,etc) */ struct urb *write_urb; /* write URB for this port */ struct urb *read_urb; /* read URB for this port */ - struct urb *int_urb; __u8 shadowLCR; /* last LCR value received */ __u8 shadowMCR; /* last MCR value received */ char open; @@ -505,7 +504,6 @@ static void mos7840_control_callback(struct urb *urb) unsigned char *data; struct moschip_port *mos7840_port; __u8 regval = 0x0; - int result = 0; int status = urb->status; mos7840_port = urb->context; @@ -524,7 +522,7 @@ static void mos7840_control_callback(struct urb *urb) default: dbg("%s - nonzero urb status received: %d", __func__, status); - goto exit; + return; } dbg("%s urb buffer size is %d", __func__, urb->actual_length); @@ -537,17 +535,6 @@ static void mos7840_control_callback(struct urb *urb) mos7840_handle_new_msr(mos7840_port, regval); else if (mos7840_port->MsrLsr == 1) mos7840_handle_new_lsr(mos7840_port, regval); - -exit: - spin_lock(&mos7840_port->pool_lock); - if (!mos7840_port->zombie) - result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC); - spin_unlock(&mos7840_port->pool_lock); - if (result) { - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); - } } static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, From 8d649dd97f1ec8fd9c8ffd94877c5c806a202e8a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 18:56:33 +0200 Subject: [PATCH 1351/2357] USB: mos7840: remove invalid disconnect handling commit e681b66f2e19fadbe8a7e2a17900978cb6bc921f upstream. Remove private zombie flag used to signal disconnect and to prevent control urb from being submitted from interrupt urb completion handler. The control urb will not be re-submitted as both the control urb and the interrupt urb is killed on disconnect. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 6f07880552f..0179d348c26 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -239,7 +239,6 @@ struct moschip_port { __u8 shadowMCR; /* last MCR value received */ char open; char open_ports; - char zombie; wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ int delta_msr_cond; @@ -642,14 +641,7 @@ static void mos7840_interrupt_callback(struct urb *urb) wreg = MODEM_STATUS_REGISTER; break; } - spin_lock(&mos7840_port->pool_lock); - if (!mos7840_port->zombie) { - rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data); - } else { - spin_unlock(&mos7840_port->pool_lock); - return; - } - spin_unlock(&mos7840_port->pool_lock); + rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data); } } } @@ -2607,9 +2599,6 @@ static void mos7840_disconnect(struct usb_serial *serial) mos7840_port = mos7840_get_port_private(serial->port[i]); dbg ("mos7840_port %d = %p", i, mos7840_port); if (mos7840_port) { - spin_lock_irqsave(&mos7840_port->pool_lock, flags); - mos7840_port->zombie = 1; - spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); usb_kill_urb(mos7840_port->control_urb); } } From 02b21626c5e97ab2286ed5b5a7e35181b16b9382 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 24 Oct 2012 20:37:51 +0200 Subject: [PATCH 1352/2357] vhost: fix mergeable bufs on BE hosts commit 910a578f7e9400a78a3b13aba0b4d2df16a2cb05 upstream. We copy head count to a 16 bit field, this works by chance on LE but on BE guest gets 0. Fix it up. Signed-off-by: Michael S. Tsirkin Tested-by: Alexander Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/net.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 5c170100de9..4134e53d731 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -376,7 +376,8 @@ static void handle_rx(struct vhost_net *net) .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE }; size_t total_len = 0; - int err, headcount, mergeable; + int err, mergeable; + s16 headcount; size_t vhost_hlen, sock_hlen; size_t vhost_len, sock_len; /* TODO: check that we are running from vhost_worker? */ From baa526f45d3f096a1cd9f14b668203a03bbab6f9 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 17 Oct 2012 16:47:11 +0900 Subject: [PATCH 1353/2357] ARM: SAMSUNG: Add naming of s3c64xx-spi devices commit 308b3afb97dc342e9c4f958d8b4c459ae0e22bd7 upstream. Commit a5238e360b71 (spi: s3c64xx: move controller information into driver data) introduced separate device names for the different subtypes of the spi controller but forgot to set these in the relevant machines. To fix this introduce a s3c64xx_spi_setname function and populate all Samsung arches with the correct names. The function resides in a new header, as the s3c64xx-spi.h contains driver platform data and should therefore at some later point move out of the Samsung include dir. Tested on a s3c2416-based machine. Signed-off-by: Heiko Stuebner Reviewed-by: Sylwester Nawrocki [s.nawrocki@samsung.com: tested on mach-exynos] Tested-by: Sylwester Nawrocki Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-exynos/common.c | 5 ++++ arch/arm/mach-s3c24xx/s3c2416.c | 2 ++ arch/arm/mach-s3c24xx/s3c2443.c | 4 +++ arch/arm/mach-s5p64x0/common.c | 3 ++ arch/arm/mach-s5pc100/common.c | 3 ++ arch/arm/mach-s5pv210/common.c | 3 ++ arch/arm/plat-samsung/include/plat/spi-core.h | 30 +++++++++++++++++++ 7 files changed, 50 insertions(+) create mode 100644 arch/arm/plat-samsung/include/plat/spi-core.h diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 5ccd6e80a60..c2b77e5a542 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include "common.h" @@ -338,6 +339,8 @@ static void __init exynos4_map_io(void) s5p_fb_setname(0, "exynos4-fb"); s5p_hdmi_setname("exynos4-hdmi"); + + s3c64xx_spi_setname("exynos4210-spi"); } static void __init exynos5_map_io(void) @@ -358,6 +361,8 @@ static void __init exynos5_map_io(void) s3c_i2c0_setname("s3c2440-i2c"); s3c_i2c1_setname("s3c2440-i2c"); s3c_i2c2_setname("s3c2440-i2c"); + + s3c64xx_spi_setname("exynos4210-spi"); } static void __init exynos4_init_clocks(int xtal) diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c index 7743fade50d..f74818da580 100644 --- a/arch/arm/mach-s3c24xx/s3c2416.c +++ b/arch/arm/mach-s3c24xx/s3c2416.c @@ -61,6 +61,7 @@ #include #include #include +#include static struct map_desc s3c2416_iodesc[] __initdata = { IODESC_ENT(WATCHDOG), @@ -131,6 +132,7 @@ void __init s3c2416_map_io(void) /* initialize device information early */ s3c2416_default_sdhci0(); s3c2416_default_sdhci1(); + s3c64xx_spi_setname("s3c2443-spi"); iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc)); } diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c index ab648ad8fa5..165b6a6b3da 100644 --- a/arch/arm/mach-s3c24xx/s3c2443.c +++ b/arch/arm/mach-s3c24xx/s3c2443.c @@ -43,6 +43,7 @@ #include #include #include +#include static struct map_desc s3c2443_iodesc[] __initdata = { IODESC_ENT(WATCHDOG), @@ -100,6 +101,9 @@ void __init s3c2443_map_io(void) s3c24xx_gpiocfg_default.set_pull = s3c2443_gpio_setpull; s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull; + /* initialize device information early */ + s3c64xx_spi_setname("s3c2443-spi"); + iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc)); } diff --git a/arch/arm/mach-s5p64x0/common.c b/arch/arm/mach-s5p64x0/common.c index 6e6a0a9d677..111e404a81f 100644 --- a/arch/arm/mach-s5p64x0/common.c +++ b/arch/arm/mach-s5p64x0/common.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -179,6 +180,7 @@ void __init s5p6440_map_io(void) /* initialize any device information early */ s3c_adc_setname("s3c64xx-adc"); s3c_fb_setname("s5p64x0-fb"); + s3c64xx_spi_setname("s5p64x0-spi"); s5p64x0_default_sdhci0(); s5p64x0_default_sdhci1(); @@ -193,6 +195,7 @@ void __init s5p6450_map_io(void) /* initialize any device information early */ s3c_adc_setname("s3c64xx-adc"); s3c_fb_setname("s5p64x0-fb"); + s3c64xx_spi_setname("s5p64x0-spi"); s5p64x0_default_sdhci0(); s5p64x0_default_sdhci1(); diff --git a/arch/arm/mach-s5pc100/common.c b/arch/arm/mach-s5pc100/common.c index 62190865886..cc6e561c995 100644 --- a/arch/arm/mach-s5pc100/common.c +++ b/arch/arm/mach-s5pc100/common.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -165,6 +166,8 @@ void __init s5pc100_map_io(void) s3c_onenand_setname("s5pc100-onenand"); s3c_fb_setname("s5pc100-fb"); s3c_cfcon_setname("s5pc100-pata"); + + s3c64xx_spi_setname("s5pc100-spi"); } void __init s5pc100_init_clocks(int xtal) diff --git a/arch/arm/mach-s5pv210/common.c b/arch/arm/mach-s5pv210/common.c index 4c9e9027df9..a0c50efe814 100644 --- a/arch/arm/mach-s5pv210/common.c +++ b/arch/arm/mach-s5pv210/common.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include "common.h" @@ -196,6 +197,8 @@ void __init s5pv210_map_io(void) /* setup TV devices */ s5p_hdmi_setname("s5pv210-hdmi"); + + s3c64xx_spi_setname("s5pv210-spi"); } void __init s5pv210_init_clocks(int xtal) diff --git a/arch/arm/plat-samsung/include/plat/spi-core.h b/arch/arm/plat-samsung/include/plat/spi-core.h new file mode 100644 index 00000000000..0b9428ab3fc --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/spi-core.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 Heiko Stuebner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __PLAT_S3C_SPI_CORE_H +#define __PLAT_S3C_SPI_CORE_H + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c64xx_spi_setname(char *name) +{ +#ifdef CONFIG_S3C64XX_DEV_SPI0 + s3c64xx_device_spi0.name = name; +#endif +#ifdef CONFIG_S3C64XX_DEV_SPI1 + s3c64xx_device_spi1.name = name; +#endif +#ifdef CONFIG_S3C64XX_DEV_SPI2 + s3c64xx_device_spi2.name = name; +#endif +} + +#endif /* __PLAT_S3C_SPI_CORE_H */ From 0a6904a552465521b33d25d767a7db06ad04e434 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 14 Sep 2012 17:01:29 +0800 Subject: [PATCH 1354/2357] ARM: at91/tc: fix typo in the DT document commit 11930c530f3edf81160e4962e363d579f5cdce7e upstream. Signed-off-by: Josh Wu Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/arm/atmel-at91.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index ecc81e36871..d187e9f7cf1 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -8,7 +8,7 @@ PIT Timer required properties: shared across all System Controller members. TC/TCLIB Timer required properties: -- compatible: Should be "atmel,-pit". +- compatible: Should be "atmel,-tcb". can be "at91rm9200" or "at91sam9x5" - reg: Should contain registers location and length - interrupts: Should contain all interrupts for the TC block From 6ff5ef252d9903de2b29dd2cdcea587d192d7635 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Mon, 15 Oct 2012 17:30:27 +0800 Subject: [PATCH 1355/2357] ARM: at91/i2c: change id to let i2c-gpio work commit 7840487cd6298f9f931103b558290d8d98d41c49 upstream. The i2c core driver will turn the platform device ID to busnum When using platfrom device ID as -1, it means dynamically assigned the busnum. When writing code, we need to make sure the busnum, and call i2c_register_board_info(int busnum, ...) to register device if using -1, we do not know the value of busnum In order to solve this issue, set the platform device ID as a fix number Here using 0 to match the busnum used in i2c_regsiter_board_info() Signed-off-by: Bo Shen Acked-by: Jean Delvare Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Ludovic Desroches Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-at91/at91rm9200_devices.c | 2 +- arch/arm/mach-at91/at91sam9260_devices.c | 2 +- arch/arm/mach-at91/at91sam9261_devices.c | 2 +- arch/arm/mach-at91/at91sam9263_devices.c | 2 +- arch/arm/mach-at91/at91sam9rl_devices.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 05774e5b1cb..3b0c719f9fe 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -463,7 +463,7 @@ static struct i2c_gpio_platform_data pdata = { static struct platform_device at91rm9200_twi_device = { .name = "i2c-gpio", - .id = -1, + .id = 0, .dev.platform_data = &pdata, }; diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 5652dde4bbe..151fec4ccf2 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -468,7 +468,7 @@ static struct i2c_gpio_platform_data pdata = { static struct platform_device at91sam9260_twi_device = { .name = "i2c-gpio", - .id = -1, + .id = 0, .dev.platform_data = &pdata, }; diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 4db961a9308..8a29c6cbe08 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -285,7 +285,7 @@ static struct i2c_gpio_platform_data pdata = { static struct platform_device at91sam9261_twi_device = { .name = "i2c-gpio", - .id = -1, + .id = 0, .dev.platform_data = &pdata, }; diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index fe99206de88..8d443225266 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -542,7 +542,7 @@ static struct i2c_gpio_platform_data pdata = { static struct platform_device at91sam9263_twi_device = { .name = "i2c-gpio", - .id = -1, + .id = 0, .dev.platform_data = &pdata, }; diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index fe4ae22e856..b8d4114ea22 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -314,7 +314,7 @@ static struct i2c_gpio_platform_data pdata = { static struct platform_device at91sam9rl_twi_device = { .name = "i2c-gpio", - .id = -1, + .id = 0, .dev.platform_data = &pdata, }; From adb91f6de096f878fb1cb9e0ff5839b2d432e67e Mon Sep 17 00:00:00 2001 From: Ivan Shugov Date: Wed, 24 Oct 2012 11:02:44 +0200 Subject: [PATCH 1356/2357] ARM: at91: at91sam9g10: fix SOC type detection commit 3d9a0183dd3423353e9e363bcc261c1220d05f9f upstream. Newer at91sam9g10 SoC revision can't be detected, so the kernel can't boot with this kind of kernel panic: "AT91: Impossible to detect the SOC type" CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177 CPU: VIVT data cache, VIVT instruction cache Machine: Atmel AT91SAM9G10-EK Ignoring tag cmdline (using the default kernel command line) bootconsole [earlycon0] enabled Memory policy: ECC disabled, Data cache writeback Kernel panic - not syncing: AT91: Impossible to detect the SOC type [] (unwind_backtrace+0x0/0xe0) from [] (panic+0x78/0x1cc) [] (panic+0x78/0x1cc) from [] (at91_map_io+0x90/0xc8) [] (at91_map_io+0x90/0xc8) from [] (paging_init+0x564/0x6d0) [] (paging_init+0x564/0x6d0) from [] (setup_arch+0x464/0x704) [] (setup_arch+0x464/0x704) from [] (start_kernel+0x6c/0x2d4) [] (start_kernel+0x6c/0x2d4) from [<20008040>] (0x20008040) The reason for this is that the Debug Unit Chip ID Register has changed between Engineering Sample and definitive revision of the SoC. Changing the check of cidr to socid will address the problem. We do not integrate this check to the list just above because we also have to make sure that the extended id is disregarded. Signed-off-by: Ivan Shugov [nicolas.ferre@atmel.com: change commit message] Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-at91/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index f44a2e7272e..582142e049a 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -146,7 +146,7 @@ static void __init soc_detect(u32 dbgu_base) } /* at91sam9g10 */ - if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) { + if ((socid & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) { at91_soc_initdata.type = AT91_SOC_SAM9G10; at91_boot_soc = at91sam9261_soc; } From 5a01241c81ac4bf6a7a486051699f791634e7b22 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 2 Oct 2012 21:34:23 +0200 Subject: [PATCH 1357/2357] mac80211: check if key has TKIP type before updating IV commit 4045f72bcf3c293c7c5932ef001742d8bb5ded76 upstream. This patch fix corruption which can manifest itself by following crash when switching on rfkill switch with rt2x00 driver: https://bugzilla.redhat.com/attachment.cgi?id=615362 Pointer key->u.ccmp.tfm of group key get corrupted in: ieee80211_rx_h_michael_mic_verify(): /* update IV in key information to be able to detect replays */ rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32; rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16; because rt2x00 always set RX_FLAG_MMIC_STRIPPED, even if key is not TKIP. We already check type of the key in different path in ieee80211_rx_h_michael_mic_verify() function, so adding additional check here is reasonable. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/wpa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 0ae23c60968..ea6d03bd5d5 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -106,7 +106,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) if (status->flag & RX_FLAG_MMIC_ERROR) goto mic_fail; - if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key) + if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key && + rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP) goto update_iv; return RX_CONTINUE; From 0fb0773f2da4ffa566e0c813dc295c44208debb5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 11 Oct 2012 16:26:06 +0200 Subject: [PATCH 1358/2357] Bluetooth: SMP: Fix setting unknown auth_req bits commit 065a13e2cc665f6547dc7e8a9d6b6565badf940a upstream. When sending a pairing request or response we should not just blindly copy the value that the remote device sent. Instead we should at least make sure to mask out any unknown bits. This is particularly critical from the upcoming LE Secure Connections feature perspective as incorrectly indicating support for it (by copying the remote value) would cause a failure to pair with devices that support it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/smp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1f6cb1f1cd2..208edc0cc60 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -31,6 +31,8 @@ #define SMP_TIMEOUT msecs_to_jiffies(30000) +#define AUTH_REQ_MASK 0x07 + static inline void swap128(u8 src[16], u8 dst[16]) { int i; @@ -229,7 +231,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, req->max_key_size = SMP_MAX_ENC_KEY_SIZE; req->init_key_dist = 0; req->resp_key_dist = dist_keys; - req->auth_req = authreq; + req->auth_req = (authreq & AUTH_REQ_MASK); return; } @@ -238,7 +240,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; rsp->init_key_dist = 0; rsp->resp_key_dist = req->resp_key_dist & dist_keys; - rsp->auth_req = authreq; + rsp->auth_req = (authreq & AUTH_REQ_MASK); } static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) From a2c439d432f759533d396b31f856fcb484268104 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Thu, 25 Oct 2012 22:28:12 +0200 Subject: [PATCH 1359/2357] freezer: exec should clear PF_NOFREEZE along with PF_KTHREAD commit b40a79591ca918e7b91b0d9b6abd5d00f2e88c19 upstream. flush_old_exec() clears PF_KTHREAD but forgets about PF_NOFREEZE. Signed-off-by: Oleg Nesterov Acked-by: Tejun Heo Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- fs/exec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/exec.c b/fs/exec.c index 126e01cb243..6c4791d4634 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1114,7 +1114,8 @@ int flush_old_exec(struct linux_binprm * bprm) bprm->mm = NULL; /* We're using it now */ set_fs(USER_DS); - current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD); + current->flags &= + ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD | PF_NOFREEZE); flush_thread(); current->personality &= ~bprm->per_clear; From 16642956664f3e93c88e9e2a22713d5456568822 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 27 Sep 2012 16:35:38 +0800 Subject: [PATCH 1360/2357] dmaengine: sirf: fix a typo in dma_prep_interleaved commit 5997e089e4c3a7f0958a8fb0a54ec2b5a6f06168 upstream. either DEV_TO_MEM or MEM_TO_DEV is supported, so change OR to AND. Signed-off-by: Barry Song Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/sirf-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c index 434ad31174f..35a329da97f 100644 --- a/drivers/dma/sirf-dma.c +++ b/drivers/dma/sirf-dma.c @@ -428,7 +428,7 @@ static struct dma_async_tx_descriptor *sirfsoc_dma_prep_interleaved( unsigned long iflags; int ret; - if ((xt->dir != DMA_MEM_TO_DEV) || (xt->dir != DMA_DEV_TO_MEM)) { + if ((xt->dir != DMA_MEM_TO_DEV) && (xt->dir != DMA_DEV_TO_MEM)) { ret = -EINVAL; goto err_dir; } From 73cb40932358f82d55117a70a0d38026923e823f Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 27 Sep 2012 16:36:10 +0800 Subject: [PATCH 1361/2357] dmaengine: sirf: fix a typo in moving running dma_desc to active queue commit 26fd12209c08fe947be1828896ef4ffc5bd0e6df upstream. list_move_tail(&schan->queued, &schan->active) makes the list_empty(schan->queued) undefined, we either should change it to: list_move_tail(schan->queued.next, &schan->active) or list_move_tail(&sdesc->node, &schan->active) Signed-off-by: Barry Song Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/sirf-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c index 35a329da97f..c4394892eda 100644 --- a/drivers/dma/sirf-dma.c +++ b/drivers/dma/sirf-dma.c @@ -109,7 +109,7 @@ static void sirfsoc_dma_execute(struct sirfsoc_dma_chan *schan) sdesc = list_first_entry(&schan->queued, struct sirfsoc_dma_desc, node); /* Move the first queued descriptor to active list */ - list_move_tail(&schan->queued, &schan->active); + list_move_tail(&sdesc->node, &schan->active); /* Start the DMA transfer */ writel_relaxed(sdesc->width, sdma->base + SIRFSOC_DMA_WIDTH_0 + From 7e8cec32110be45739569e04f35d83d47064dd86 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 21 Oct 2012 19:58:30 +0800 Subject: [PATCH 1362/2357] dmaengine: imx-dma: fix missing unlock on error in imxdma_xfer_desc() commit 720dfd250e48a8c7fd1b2b8645955413989c4ee0 upstream. Add the missing unlock on the error handling path in function imxdma_xfer_desc(). Signed-off-by: Wei Yongjun Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/imx-dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index bb787d8e152..180f5235acc 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -473,8 +473,10 @@ static int imxdma_xfer_desc(struct imxdma_desc *d) slot = i; break; } - if (slot < 0) + if (slot < 0) { + spin_unlock_irqrestore(&imxdma->lock, flags); return -EBUSY; + } imxdma->slots_2d[slot].xsr = d->x; imxdma->slots_2d[slot].ysr = d->y; From 44b977a87305bb075adb5b764f115237e474e626 Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Thu, 11 Oct 2012 14:05:15 +0200 Subject: [PATCH 1363/2357] bcma: fix unregistration of cores commit 1fffa905adffbf0d3767fc978ef09afb830275eb upstream. When cores are unregistered, entries need to be removed from cores list in a safe manner. Reported-by: Stanislaw Gruszka Reviewed-by: Arend Van Spriel Signed-off-by: Piotr Haber Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/bcma/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 7e138ec2135..edb9233b26d 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -131,9 +131,10 @@ static int bcma_register_cores(struct bcma_bus *bus) static void bcma_unregister_cores(struct bcma_bus *bus) { - struct bcma_device *core; + struct bcma_device *core, *tmp; - list_for_each_entry(core, &bus->cores, list) { + list_for_each_entry_safe(core, tmp, &bus->cores, list) { + list_del(&core->list); if (core->dev_registered) device_unregister(&core->dev); } From 0b79a8a53612672adf053aaebb74ebc51a44e321 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 23 Oct 2012 00:55:10 +0200 Subject: [PATCH 1364/2357] cpufreq / powernow-k8: Remove usage of smp_processor_id() in preemptible code commit e4df1cbcc1f329e53a1fff7450b2229e0addff20 upstream. Commit 6889125b8b4e09c5e53e6ecab3433bed1ce198c9 (cpufreq/powernow-k8: workqueue user shouldn't migrate the kworker to another CPU) causes powernow-k8 to trigger a preempt warning, e.g.: BUG: using smp_processor_id() in preemptible [00000000] code: cpufreq/3776 caller is powernowk8_target+0x20/0x49 Pid: 3776, comm: cpufreq Not tainted 3.6.0 #9 Call Trace: [] debug_smp_processor_id+0xc7/0xe0 [] powernowk8_target+0x20/0x49 [] __cpufreq_driver_target+0x82/0x8a [] cpufreq_governor_performance+0x4e/0x54 [] __cpufreq_governor+0x8c/0xc9 [] __cpufreq_set_policy+0x1a9/0x21e [] store_scaling_governor+0x16f/0x19b [] ? cpufreq_update_policy+0x124/0x124 [] ? _raw_spin_unlock_irqrestore+0x2c/0x49 [] store+0x60/0x88 [] sysfs_write_file+0xf4/0x130 [] vfs_write+0xb5/0x151 [] sys_write+0x4a/0x71 [] system_call_fastpath+0x16/0x1b Fix this by by always using work_on_cpu(). Signed-off-by: Andreas Herrmann Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/powernow-k8.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 1a40935c85f..c671369a05b 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -1223,14 +1223,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq, .relation = relation }; - /* - * Must run on @pol->cpu. cpufreq core is responsible for ensuring - * that we're bound to the current CPU and pol->cpu stays online. - */ - if (smp_processor_id() == pol->cpu) - return powernowk8_target_fn(&pta); - else - return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta); + return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta); } /* Driver entry point to verify the policy and range of frequencies */ From 6c422bb689034ce2c2b781754b03fb93bc67fa78 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 17 Oct 2012 13:50:43 +0200 Subject: [PATCH 1365/2357] Revert "ath9k_hw: Updated AR9003 tx gain table for 5GHz" commit 73b26df5fa1a6245d6fc982362518b620bc7c2fe upstream. This reverts commit a240dc7b3c7463bd60cf0a9b2a90f52f78aae0fd. This commit is reducing tx power by at least 10 db on some devices, e.g. the Buffalo WZR-HP-G450H. Signed-off-by: Felix Fietkau Cc: rmanohar@qca.qualcomm.com Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- .../wireless/ath/ath9k/ar9003_2p2_initvals.h | 164 +++++++++--------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 46c79a3d473..2b4b63318da 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -533,107 +533,107 @@ static const u32 ar9300_2p2_baseband_core[][2] = { static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, - {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, - {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, - {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, - {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5a08442e, 0x5a08442e, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x5e0a4431, 0x5e0a4431, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400}, - {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402}, - {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603}, - {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02}, - {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04}, - {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20}, - {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20}, - {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22}, - {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24}, - {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640}, - {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660}, - {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861}, - {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81}, - {0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83}, - {0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84}, - {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3}, - {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5}, - {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9}, - {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb}, - {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, - {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, - {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, - {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, - {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, - {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, - {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, + {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, - {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, - {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, - {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, - {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, - {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, - {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, - {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, - {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, - {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, - {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, + {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, + {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, - {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, - {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, + {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, + {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, + {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; From 3fd37d2b84e53427b10e6900f7039f9ea9c3a408 Mon Sep 17 00:00:00 2001 From: Jacob Shin Date: Wed, 24 Oct 2012 14:24:44 -0500 Subject: [PATCH 1366/2357] x86, mm: Find_early_table_space based on ranges that are actually being mapped commit 844ab6f993b1d32eb40512503d35ff6ad0c57030 upstream. Current logic finds enough space for direct mapping page tables from 0 to end. Instead, we only need to find enough space to cover mr[0].start to mr[nr_range].end -- the range that is actually being mapped by init_memory_mapping() This is needed after 1bbbbe779aabe1f0768c2bf8f8c0a5583679b54a, to address the panic reported here: https://lkml.org/lkml/2012/10/20/160 https://lkml.org/lkml/2012/10/21/157 Signed-off-by: Jacob Shin Link: http://lkml.kernel.org/r/20121024195311.GB11779@jshin-Toonie Tested-by: Tom Rini Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/init.c | 73 +++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 4f0cec7e4ff..6ef7a6344fa 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -29,36 +29,54 @@ int direct_gbpages #endif ; -static void __init find_early_table_space(unsigned long end, int use_pse, - int use_gbpages) +struct map_range { + unsigned long start; + unsigned long end; + unsigned page_size_mask; +}; + +/* + * First calculate space needed for kernel direct mapping page tables to cover + * mr[0].start to mr[nr_range - 1].end, while accounting for possible 2M and 1GB + * pages. Then find enough contiguous space for those page tables. + */ +static void __init find_early_table_space(struct map_range *mr, int nr_range) { - unsigned long puds, pmds, ptes, tables, start = 0, good_end = end; + int i; + unsigned long puds = 0, pmds = 0, ptes = 0, tables; + unsigned long start = 0, good_end; phys_addr_t base; - puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; - tables = roundup(puds * sizeof(pud_t), PAGE_SIZE); + for (i = 0; i < nr_range; i++) { + unsigned long range, extra; - if (use_gbpages) { - unsigned long extra; + range = mr[i].end - mr[i].start; + puds += (range + PUD_SIZE - 1) >> PUD_SHIFT; - extra = end - ((end>>PUD_SHIFT) << PUD_SHIFT); - pmds = (extra + PMD_SIZE - 1) >> PMD_SHIFT; - } else - pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; - - tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE); + if (mr[i].page_size_mask & (1 << PG_LEVEL_1G)) { + extra = range - ((range >> PUD_SHIFT) << PUD_SHIFT); + pmds += (extra + PMD_SIZE - 1) >> PMD_SHIFT; + } else { + pmds += (range + PMD_SIZE - 1) >> PMD_SHIFT; + } - if (use_pse) { - unsigned long extra; - - extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); + if (mr[i].page_size_mask & (1 << PG_LEVEL_2M)) { + extra = range - ((range >> PMD_SHIFT) << PMD_SHIFT); #ifdef CONFIG_X86_32 - extra += PMD_SIZE; + extra += PMD_SIZE; #endif - ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT; - } else - ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT; + /* The first 2/4M doesn't use large pages. */ + if (mr[i].start < PMD_SIZE) + extra += range; + + ptes += (extra + PAGE_SIZE - 1) >> PAGE_SHIFT; + } else { + ptes += (range + PAGE_SIZE - 1) >> PAGE_SHIFT; + } + } + tables = roundup(puds * sizeof(pud_t), PAGE_SIZE); + tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE); tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE); #ifdef CONFIG_X86_32 @@ -75,8 +93,9 @@ static void __init find_early_table_space(unsigned long end, int use_pse, pgt_buf_end = pgt_buf_start; pgt_buf_top = pgt_buf_start + (tables >> PAGE_SHIFT); - printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n", - end, pgt_buf_start << PAGE_SHIFT, pgt_buf_top << PAGE_SHIFT); + printk(KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx]\n", + mr[nr_range - 1].end - 1, pgt_buf_start << PAGE_SHIFT, + (pgt_buf_top << PAGE_SHIFT) - 1); } void __init native_pagetable_reserve(u64 start, u64 end) @@ -84,12 +103,6 @@ void __init native_pagetable_reserve(u64 start, u64 end) memblock_reserve(start, end - start); } -struct map_range { - unsigned long start; - unsigned long end; - unsigned page_size_mask; -}; - #ifdef CONFIG_X86_32 #define NR_RANGE_MR 3 #else /* CONFIG_X86_64 */ @@ -261,7 +274,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, * nodes are discovered. */ if (!after_bootmem) - find_early_table_space(end, use_pse, use_gbpages); + find_early_table_space(mr, nr_range); for (i = 0; i < nr_range; i++) ret = kernel_physical_mapping_init(mr[i].start, mr[i].end, From 7a32a0b9985742493575ffa1c6fedf043d966708 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 25 Oct 2012 15:45:26 -0700 Subject: [PATCH 1367/2357] x86, mm: Undo incorrect revert in arch/x86/mm/init.c commit f82f64dd9f485e13f29f369772d4a0e868e5633a upstream. Commit 844ab6f9 x86, mm: Find_early_table_space based on ranges that are actually being mapped added back some lines back wrongly that has been removed in commit 7b16bbf97 Revert "x86/mm: Fix the size calculation of mapping tables" remove them again. Signed-off-by: Yinghai Lu Link: http://lkml.kernel.org/r/CAE9FiQW_vuaYQbmagVnxT2DGsYc=9tNeAbdBq53sYkitPOwxSQ@mail.gmail.com Acked-by: Jacob Shin Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/init.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 6ef7a6344fa..fae70904ed0 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -65,10 +65,6 @@ static void __init find_early_table_space(struct map_range *mr, int nr_range) #ifdef CONFIG_X86_32 extra += PMD_SIZE; #endif - /* The first 2/4M doesn't use large pages. */ - if (mr[i].start < PMD_SIZE) - extra += range; - ptes += (extra + PAGE_SIZE - 1) >> PAGE_SHIFT; } else { ptes += (range + PAGE_SIZE - 1) >> PAGE_SHIFT; From a57a57aea0ad2ced60a8aa59d49fe542f23efb72 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 28 Sep 2012 17:55:44 -0700 Subject: [PATCH 1368/2357] efi: Defer freeing boot services memory until after ACPI init commit 785107923a83d8456bbd8564e288a24d84109a46 upstream. Some new ACPI 5.0 tables reference resources stored in boot services memory, so keep that memory around until we have ACPI and can extract data from it. Signed-off-by: Josh Triplett Link: http://lkml.kernel.org/r/baaa6d44bdc4eb0c58e5d1b4ccd2c729f854ac55.1348876882.git.josh@joshtriplett.org Signed-off-by: H. Peter Anvin Cc: Matt Fleming Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/efi/efi.c | 31 ++++++++++++++++++------------- include/linux/efi.h | 5 +++++ init/main.c | 3 +++ 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index f55a4ce6dc4..b3dbbdbd2a4 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -419,10 +419,21 @@ void __init efi_reserve_boot_services(void) } } -static void __init efi_free_boot_services(void) +static void __init efi_unmap_memmap(void) +{ + if (memmap.map) { + early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); + memmap.map = NULL; + } +} + +void __init efi_free_boot_services(void) { void *p; + if (!efi_native) + return; + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { efi_memory_desc_t *md = p; unsigned long long start = md->phys_addr; @@ -438,6 +449,8 @@ static void __init efi_free_boot_services(void) free_bootmem_late(start, size); } + + efi_unmap_memmap(); } static int __init efi_systab_init(void *phys) @@ -787,8 +800,10 @@ void __init efi_enter_virtual_mode(void) * non-native EFI */ - if (!efi_native) - goto out; + if (!efi_native) { + efi_unmap_memmap(); + return; + } /* Merge contiguous regions of the same type and attribute */ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { @@ -877,13 +892,6 @@ void __init efi_enter_virtual_mode(void) panic("EFI call to SetVirtualAddressMap() failed!"); } - /* - * Thankfully, it does seem that no runtime services other than - * SetVirtualAddressMap() will touch boot services code, so we can - * get rid of it all at this point - */ - efi_free_boot_services(); - /* * Now that EFI is in virtual mode, update the function * pointers in the runtime service table to the new virtual addresses. @@ -907,9 +915,6 @@ void __init efi_enter_virtual_mode(void) if (__supported_pte_mask & _PAGE_NX) runtime_code_page_mkexec(); -out: - early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); - memmap.map = NULL; kfree(new_memmap); } diff --git a/include/linux/efi.h b/include/linux/efi.h index ec45ccd8708..5782114f483 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -496,6 +496,11 @@ extern void efi_map_pal_code (void); extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); extern void efi_gettimeofday (struct timespec *ts); extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ +#ifdef CONFIG_X86 +extern void efi_free_boot_services(void); +#else +static inline void efi_free_boot_services(void) {} +#endif extern u64 efi_get_iobase (void); extern u32 efi_mem_type (unsigned long phys_addr); extern u64 efi_mem_attributes (unsigned long phys_addr); diff --git a/init/main.c b/init/main.c index b08c5f75974..c2178d267c1 100644 --- a/init/main.c +++ b/init/main.c @@ -630,6 +630,9 @@ asmlinkage void __init start_kernel(void) acpi_early_init(); /* before LAPIC and SMP init */ sfi_init_late(); + if (efi_enabled) + efi_free_boot_services(); + ftrace_init(); /* Do the rest non-__init'ed, we're now alive */ From 775dc1a3fd51abc6e459aa92e049fd3687b66c2f Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 24 Oct 2012 10:00:44 -0700 Subject: [PATCH 1369/2357] x86: efi: Turn off efi_enabled after setup on mixed fw/kernel commit 5189c2a7c7769ee9d037d76c1a7b8550ccf3481c upstream. When 32-bit EFI is used with 64-bit kernel (or vice versa), turn off efi_enabled once setup is done. Beyond setup, it is normally used to determine if runtime services are available and we will have none. This will resolve issues stemming from efivars modprobe panicking on a 32/64-bit setup, as well as some reboot issues on similar setups. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=45991 Reported-by: Marko Kohtala Reported-by: Maxim Kammerer Signed-off-by: Olof Johansson Acked-by: Maarten Lankhorst Cc: Matthew Garrett Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/efi.h | 1 + arch/x86/kernel/setup.c | 12 ++++++++++++ arch/x86/platform/efi/efi.c | 18 ++++++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index c9dcc181d4d..029189db84d 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -98,6 +98,7 @@ extern void efi_set_executable(efi_memory_desc_t *md, bool executable); extern int efi_memblock_x86_reserve_range(void); extern void efi_call_phys_prelog(void); extern void efi_call_phys_epilog(void); +extern void efi_unmap_memmap(void); #ifndef CONFIG_EFI /* diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index fbbd1eb6c68..03197984036 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1053,6 +1053,18 @@ void __init setup_arch(char **cmdline_p) mcheck_init(); arch_init_ideal_nops(); + +#ifdef CONFIG_EFI + /* Once setup is done above, disable efi_enabled on mismatched + * firmware/kernel archtectures since there is no support for + * runtime services. + */ + if (efi_enabled && IS_ENABLED(CONFIG_X86_64) != efi_64bit) { + pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n"); + efi_unmap_memmap(); + efi_enabled = 0; + } +#endif } #ifdef CONFIG_X86_32 diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index b3dbbdbd2a4..72d88992f38 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -69,11 +69,15 @@ EXPORT_SYMBOL(efi); struct efi_memory_map memmap; bool efi_64bit; -static bool efi_native; static struct efi efi_phys __initdata; static efi_system_table_t efi_systab __initdata; +static inline bool efi_is_native(void) +{ + return IS_ENABLED(CONFIG_X86_64) == efi_64bit; +} + static int __init setup_noefi(char *arg) { efi_enabled = 0; @@ -419,7 +423,7 @@ void __init efi_reserve_boot_services(void) } } -static void __init efi_unmap_memmap(void) +void __init efi_unmap_memmap(void) { if (memmap.map) { early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); @@ -431,7 +435,7 @@ void __init efi_free_boot_services(void) { void *p; - if (!efi_native) + if (!efi_is_native()) return; for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { @@ -683,12 +687,10 @@ void __init efi_init(void) return; } efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; - efi_native = !efi_64bit; #else efi_phys.systab = (efi_system_table_t *) (boot_params.efi_info.efi_systab | ((__u64)boot_params.efi_info.efi_systab_hi<<32)); - efi_native = efi_64bit; #endif if (efi_systab_init(efi_phys.systab)) { @@ -722,7 +724,7 @@ void __init efi_init(void) * that doesn't match the kernel 32/64-bit mode. */ - if (!efi_native) + if (!efi_is_native()) pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); else if (efi_runtime_init()) { efi_enabled = 0; @@ -734,7 +736,7 @@ void __init efi_init(void) return; } #ifdef CONFIG_X86_32 - if (efi_native) { + if (efi_is_native()) { x86_platform.get_wallclock = efi_get_time; x86_platform.set_wallclock = efi_set_rtc_mmss; } @@ -800,7 +802,7 @@ void __init efi_enter_virtual_mode(void) * non-native EFI */ - if (!efi_native) { + if (!efi_is_native()) { efi_unmap_memmap(); return; } From a0419caba889d9a5f743a51b7cf9269c16c397a5 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 3 Oct 2012 16:25:17 +0100 Subject: [PATCH 1370/2357] staging: comedi: amplc_pc236: fix invalid register access during detach commit aaeb61a97b7159ebe30b18a422d04eeabfa8790b upstream. `pc236_detach()` is called by the comedi core if it attempted to attach a device and failed. `pc236_detach()` calls `pc236_intr_disable()` if the comedi device private data pointer (`devpriv`) is non-null. This test is insufficient as `pc236_intr_disable()` accesses hardware registers and the attach routine may have failed before it has saved their I/O base addresses. Fix it by checking `dev->iobase` is non-zero before calling `pc236_intr_disable()` as that means the I/O base addresses have been saved and the hardware registers can be accessed. It also implies the comedi device private data pointer is valid, so there is no need to check it. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/amplc_pc236.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 7972cadd403..9a23d20938a 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -468,7 +468,7 @@ static int pc236_detach(struct comedi_device *dev) { printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, PC236_DRIVER_NAME); - if (devpriv) + if (dev->iobase) pc236_intr_disable(dev); if (dev->irq) From 0187c24809c9590412c0112dab88f28621a961ed Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 22 Oct 2012 16:35:18 -0700 Subject: [PATCH 1371/2357] x86, mm: Use memblock memory loop instead of e820_RAM commit 1f2ff682ac951ed82cc043cf140d2851084512df upstream. We need to handle E820_RAM and E820_RESERVED_KERNEL at the same time. Also memblock has page aligned range for ram, so we could avoid mapping partial pages. Signed-off-by: Yinghai Lu Link: http://lkml.kernel.org/r/CAE9FiQVZirvaBMFYRfXMmWEcHbKSicQEHz4VAwUv0xFCk51ZNw@mail.gmail.com Acked-by: Jacob Shin Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/setup.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 03197984036..ae98dbb5b8c 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -928,18 +928,19 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_X86_64 if (max_pfn > max_low_pfn) { int i; - for (i = 0; i < e820.nr_map; i++) { - struct e820entry *ei = &e820.map[i]; + unsigned long start, end; + unsigned long start_pfn, end_pfn; - if (ei->addr + ei->size <= 1UL << 32) - continue; + for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, + NULL) { - if (ei->type == E820_RESERVED) + end = PFN_PHYS(end_pfn); + if (end <= (1UL<<32)) continue; + start = PFN_PHYS(start_pfn); max_pfn_mapped = init_memory_mapping( - ei->addr < 1UL << 32 ? 1UL << 32 : ei->addr, - ei->addr + ei->size); + max((1UL<<32), start), end); } /* can we preseve max_low_pfn ?*/ From 1f94bd43033d37549313c2b3cc2447800a20291c Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Fri, 22 Jun 2012 09:43:07 +0200 Subject: [PATCH 1372/2357] drm/i915: no lvds quirk for Zotac ZDBOX SD ID12/ID13 commit 9756fe38d10b2bf90c81dc4d2f17d5632e135364 upstream. This box claims to have an LVDS interface but doesn't actually have one. Signed-off-by: Sjoerd Simons Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 9fadd643181..4ff7d5f06da 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -777,6 +777,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "MS-7469"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "ZOTAC ZBOXSD-ID12/ID13", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ZOTAC"), + DMI_MATCH(DMI_BOARD_NAME, "ZBOXSD-ID12/ID13"), + }, + }, { } /* terminating entry */ }; From 5390967b2f98e6aa46f20eae09580e7db73826b9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 31 Oct 2012 10:05:17 -0700 Subject: [PATCH 1373/2357] Linux 3.4.17 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 470d96b8ba6..3f9f0762e88 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 16 +SUBLEVEL = 17 EXTRAVERSION = NAME = Saber-toothed Squirrel From 0d819068496793d2f8ef48a6fcec4c7d329d8b8a Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Sun, 28 Oct 2012 22:24:57 -0400 Subject: [PATCH 1374/2357] ext4: fix unjournaled inode bitmap modification commit ffb5387e85d528fb6d0d924abfa3fbf0fc484071 upstream. commit 119c0d4460b001e44b41dcf73dc6ee794b98bd31 changed ext4_new_inode() such that the inode bitmap was being modified outside a transaction, which could lead to corruption, and was discovered when journal_checksum found a bad checksum in the journal during log replay. Nix ran into this when using the journal_async_commit mount option, which enables journal checksumming. The ensuing journal replay failures due to the bad checksums led to filesystem corruption reported as the now infamous "Apparent serious progressive ext4 data corruption bug" [ Changed by tytso to only call ext4_journal_get_write_access() only when we're fairly certain that we're going to allocate the inode. ] I've tested this by mounting with journal_checksum and running fsstress then dropping power; I've also tested by hacking DM to create snapshots w/o first quiescing, which allows me to test journal replay repeatedly w/o actually power-cycling the box. Without the patch I hit a journal checksum error every time. With this fix it survives many iterations. Reported-by: Nix Signed-off-by: Eric Sandeen Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ialloc.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 0ee374d27fd..556cc821652 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -697,6 +697,10 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode, "inode=%lu", ino + 1); continue; } + BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); + err = ext4_journal_get_write_access(handle, inode_bitmap_bh); + if (err) + goto fail; ext4_lock_group(sb, group); ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data); ext4_unlock_group(sb, group); @@ -710,6 +714,11 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode, goto out; got: + BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata"); + err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh); + if (err) + goto fail; + /* We may have to initialize the block bitmap if it isn't already */ if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { @@ -742,11 +751,6 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode, goto fail; } - BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, inode_bitmap_bh); - if (err) - goto fail; - BUFFER_TRACE(group_desc_bh, "get_write_access"); err = ext4_journal_get_write_access(handle, group_desc_bh); if (err) @@ -789,11 +793,6 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode, ext4_unlock_group(sb, group); } - BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh); - if (err) - goto fail; - BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata"); err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh); if (err) From 0659a3107481012c778d9e249a3561474a4b4a7d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 11 Oct 2012 09:56:35 +0300 Subject: [PATCH 1375/2357] gpio-timberdale: fix a potential wrapping issue commit d79550a7bc35c16476ebdc27c78378d8093390ec upstream. ->last_ier is an unsigned long but the high bits can't be used int the original code because the shift wraps. Signed-off-by: Dan Carpenter Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-timberdale.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 031c6adf5b6..1a3e2b9b477 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -116,7 +116,7 @@ static void timbgpio_irq_disable(struct irq_data *d) unsigned long flags; spin_lock_irqsave(&tgpio->lock, flags); - tgpio->last_ier &= ~(1 << offset); + tgpio->last_ier &= ~(1UL << offset); iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); spin_unlock_irqrestore(&tgpio->lock, flags); } @@ -128,7 +128,7 @@ static void timbgpio_irq_enable(struct irq_data *d) unsigned long flags; spin_lock_irqsave(&tgpio->lock, flags); - tgpio->last_ier |= 1 << offset; + tgpio->last_ier |= 1UL << offset; iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); spin_unlock_irqrestore(&tgpio->lock, flags); } From e7355f1112773a015e914b4f815460b7bbe88954 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 25 Oct 2012 14:03:03 +0300 Subject: [PATCH 1376/2357] gpiolib: Don't return -EPROBE_DEFER to sysfs, or for invalid gpios commit ad2fab36d7922401c4576fb7ea9b21a47a29a17f upstream. gpios requested with invalid numbers, or gpios requested from userspace via sysfs should not try to be deferred on failure. Signed-off-by: Mathias Nyman Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5a75510d66b..112c16e0847 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -623,9 +623,11 @@ static ssize_t export_store(struct class *class, */ status = gpio_request(gpio, "sysfs"); - if (status < 0) + if (status < 0) { + if (status == -EPROBE_DEFER) + status = -ENODEV; goto done; - + } status = gpio_export(gpio, true); if (status < 0) gpio_free(gpio); @@ -1191,8 +1193,10 @@ int gpio_request(unsigned gpio, const char *label) spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) + if (!gpio_is_valid(gpio)) { + status = -EINVAL; goto done; + } desc = &gpio_desc[gpio]; chip = desc->chip; if (chip == NULL) From 32f25ea28ad28fbb4080d0b7a279279c7e21b1d0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 31 Oct 2012 11:42:03 +1100 Subject: [PATCH 1377/2357] md/raid1: Fix assembling of arrays containing Replacements. commit 02b898f2f04e418094f0093a3ad0b415bcdbe8eb upstream. setup_conf in raid1.c uses conf->raid_disks before assigning a value. It is used when including 'Replacement' devices. The consequence is that assembling an array which contains a replacement will misbehave and either not include the replacement, or not include the device being replaced. Though this doesn't lead directly to data corruption, it could lead to reduced data safety. So use mddev->raid_disks, which is initialised, instead. Bug was introduced by commit c19d57980b38a5bb613a898937a1cf85f422fb9b md/raid1: recognise replacements when assembling arrays. in 3.3, so fix is suitable for 3.3.y thru 3.6.y. Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 23904d23373..df445091384 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2564,7 +2564,7 @@ static struct r1conf *setup_conf(struct mddev *mddev) || disk_idx < 0) continue; if (test_bit(Replacement, &rdev->flags)) - disk = conf->mirrors + conf->raid_disks + disk_idx; + disk = conf->mirrors + mddev->raid_disks + disk_idx; else disk = conf->mirrors + disk_idx; From 7db4c1707a323c62fa3d8e6c58d197d23c02fdfc Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 27 Aug 2012 20:56:52 -0300 Subject: [PATCH 1378/2357] floppy: do put_disk on current dr if blk_init_queue fails commit 238ab78469c6ab7845b43d5061cd3c92331b2452 upstream. If blk_init_queue fails, we do not call put_disk on the current dr (dr is decremented first in the error handling loop). Reviewed-by: Ben Hutchings Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Jiri Kosina Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/floppy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index b0b00d70c16..c82f06e639f 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4161,6 +4161,7 @@ static int __init floppy_init(void) disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock); if (!disks[dr]->queue) { + put_disk(disks[dr]); err = -ENOMEM; goto out_put_disk; } From 4bd1d456218f48e77be45feaadcacce29ce6e3ac Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 24 Oct 2012 08:57:16 -0500 Subject: [PATCH 1379/2357] b43: Fix oops on unload when firmware not found commit f89ff6441df06abc2d95f3ef67525923032d6283 upstream. When b43 fails to find firmware when loaded, a subsequent unload will oops due to calling ieee80211_unregister_hw() when the corresponding register call was never made. Commit 2d838bb608e2d1f6cb4280e76748cb812dc822e7 fixed the same problem for b43legacy. Signed-off-by: Larry Finger Tested-by: Markus Kanet Cc: Markus Kanet Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/b43/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e4d6dc2e37d..d6ffd434f41 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -5430,6 +5430,8 @@ static void b43_ssb_remove(struct ssb_device *sdev) cancel_work_sync(&wldev->restart_work); B43_WARN_ON(!wl); + if (!wldev->fw.ucode.data) + return; /* NULL if firmware never loaded */ if (wl->current_dev == wldev) { /* Restore the queues count before unregistering, because firmware detect * might have modified it. Restoring is important, so the networking From 8c9c9dfcd1d31e2f149ea991f15bfdd4b5e1496e Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 26 Oct 2012 15:35:45 -0700 Subject: [PATCH 1380/2357] target: Fix double-free of se_cmd in target_complete_tmr_failure commit e13d5fef88c40b87c8430f8274c3a9ca32ef90bc upstream. Fabric drivers currently expect to internally release se_cmd in the event of a TMR failure during target_submit_tmr(), which means the immediate call to transport_generic_free_cmd() after TFO->queue_tm_rsp() from within target_complete_tmr_failure() workqueue context is wrong. This is done as some fabrics expect TMR operations to be acknowledged before releasing the descriptor, so the assumption that core is releasing se_cmd associated TMR memory is incorrect. This fixes a OOPs where transport_generic_free_cmd() was being called more than once. This bug was originally observed with tcm_qla2xxx fabric ports. Signed-off-by: Nicholas Bellinger Cc: Christoph Hellwig Cc: Roland Dreier Cc: Andy Grover Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_transport.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d594460ed98..69f3f7d53a0 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1748,7 +1748,6 @@ static void target_complete_tmr_failure(struct work_struct *work) se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; se_cmd->se_tfo->queue_tm_rsp(se_cmd); - transport_generic_free_cmd(se_cmd, 0); } /** From ac219f9df7c4dc152bc33e7dbe0573a1764d741c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 19 Oct 2012 13:28:46 +0200 Subject: [PATCH 1381/2357] HID: microsoft: fix invalid rdesc for 3k kbd commit 3ccc60f9d8c39180c205dba1a020735bda1b2491 upstream. Microsoft Digital Media Keyboard 3000 has two interfaces, and the second one has a report descriptor with a bug. The second collection says: 05 01 -- global; usage page -- 01 -- Generic Desktop Controls 09 80 -- local; usage -- 80 -- System Control a1 01 -- main; collection -- 01 -- application 85 03 -- global; report ID -- 03 19 00 -- local; Usage Minimum -- 00 29 ff -- local; Usage Maximum -- ff 15 00 -- global; Logical Minimum -- 0 26 ff 00 -- global; Logical Maximum -- ff 81 00 -- main; input c0 -- main; End Collection I.e. it makes us think that there are all kinds of usages of system control. That the keyboard is a not only a keyboard, but also a joystick, mouse, gamepad, keypad, etc. The same as for the Wireless Desktop Receiver, this should be Physical Min/Max. So fix that appropriately. References: https://bugzilla.novell.com/show_bug.cgi?id=776834 Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-microsoft.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index e5c699b6c6f..38999898d04 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -29,22 +29,30 @@ #define MS_RDESC 0x08 #define MS_NOGET 0x10 #define MS_DUPLICATE_USAGES 0x20 +#define MS_RDESC_3K 0x40 -/* - * Microsoft Wireless Desktop Receiver (Model 1028) has - * 'Usage Min/Max' where it ought to have 'Physical Min/Max' - */ static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + /* + * Microsoft Wireless Desktop Receiver (Model 1028) has + * 'Usage Min/Max' where it ought to have 'Physical Min/Max' + */ if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 && rdesc[559] == 0x29) { hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n"); rdesc[557] = 0x35; rdesc[559] = 0x45; } + /* the same as above (s/usage/physical/) */ + if ((quirks & MS_RDESC_3K) && *rsize == 106 && + !memcmp((char []){ 0x19, 0x00, 0x29, 0xff }, + &rdesc[94], 4)) { + rdesc[94] = 0x35; + rdesc[96] = 0x45; + } return rdesc; } @@ -193,7 +201,7 @@ static const struct hid_device_id ms_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB), .driver_data = MS_PRESENTER }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K), - .driver_data = MS_ERGONOMY }, + .driver_data = MS_ERGONOMY | MS_RDESC_3K }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0), .driver_data = MS_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), From ba76a5d4ee853b23e8bbc2d6a5acbb6f8d743dcd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 29 Oct 2012 09:03:07 +1000 Subject: [PATCH 1382/2357] drm/nouveau: silence modesetting spam on pre-gf8 chipsets commit cee59f15a60cc6269a25e3f6fbf1a577d6ab8115 upstream. Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nv04_dac.c | 8 ++++---- drivers/gpu/drm/nouveau/nv04_dfp.c | 6 +++--- drivers/gpu/drm/nouveau/nv04_tv.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c index 8300266ffae..f180dcfb12f 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c @@ -210,7 +210,7 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder, NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode); if (blue == 0x18) { - NV_INFO(dev, "Load detected on head A\n"); + NV_DEBUG(dev, "Load detected on head A\n"); return connector_status_connected; } @@ -323,7 +323,7 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) if (nv17_dac_sample_load(encoder) & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { - NV_INFO(dev, "Load detected on output %c\n", + NV_DEBUG(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); return connector_status_connected; } else { @@ -398,7 +398,7 @@ static void nv04_dac_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); - NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", + NV_DEBUG(dev, "Output %s is running on CRTC %d using output %c\n", drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } @@ -447,7 +447,7 @@ static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) return; nv_encoder->last_dpms = mode; - NV_INFO(dev, "Setting dpms mode %d on vga encoder (output %d)\n", + NV_DEBUG(dev, "Setting dpms mode %d on vga encoder (output %d)\n", mode, nv_encoder->dcb->index); nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 2258746016f..473f30a4194 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -476,7 +476,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); - NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", + NV_DEBUG(dev, "Output %s is running on CRTC %d using output %c\n", drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } @@ -519,7 +519,7 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) return; nv_encoder->last_dpms = mode; - NV_INFO(dev, "Setting dpms mode %d on lvds encoder (output %d)\n", + NV_DEBUG(dev, "Setting dpms mode %d on lvds encoder (output %d)\n", mode, nv_encoder->dcb->index); if (was_powersaving && is_powersaving_dpms(mode)) @@ -564,7 +564,7 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode) return; nv_encoder->last_dpms = mode; - NV_INFO(dev, "Setting dpms mode %d on tmds encoder (output %d)\n", + NV_DEBUG(dev, "Setting dpms mode %d on tmds encoder (output %d)\n", mode, nv_encoder->dcb->index); nv04_dfp_update_backlight(encoder, mode); diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index 3eb605ddfd0..4de1fbeb849 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -69,7 +69,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode) struct nv04_mode_state *state = &dev_priv->mode_reg; uint8_t crtc1A; - NV_INFO(dev, "Setting dpms mode %d on TV encoder (output %d)\n", + NV_DEBUG(dev, "Setting dpms mode %d on TV encoder (output %d)\n", mode, nv_encoder->dcb->index); state->pllsel &= ~(PLLSEL_TV_CRTC1_MASK | PLLSEL_TV_CRTC2_MASK); @@ -162,7 +162,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); - NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", + NV_DEBUG(dev, "Output %s is running on CRTC %d using output %c\n", drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } From de540b704e2ba5681f5e697aa14cfd4e739b42ef Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 1 Nov 2012 16:16:31 +1000 Subject: [PATCH 1383/2357] drm/nouveau: fix suspend/resume when in headless mode Backport of fixes from upstream commit: 9430738d80223a1cd791a2baa74fa170d3df1262 Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_drv.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 4f2030bd567..b5232582d1e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -186,11 +186,13 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - NV_INFO(dev, "Disabling display...\n"); - nouveau_display_fini(dev); + if (dev->mode_config.num_crtc) { + NV_INFO(dev, "Disabling display...\n"); + nouveau_display_fini(dev); - NV_INFO(dev, "Disabling fbcon...\n"); - nouveau_fbcon_set_suspend(dev, 1); + NV_INFO(dev, "Disabling fbcon...\n"); + nouveau_fbcon_set_suspend(dev, 1); + } NV_INFO(dev, "Unpinning framebuffer(s)...\n"); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -363,10 +365,12 @@ nouveau_pci_resume(struct pci_dev *pdev) NV_ERROR(dev, "Could not pin/map cursor.\n"); } - nouveau_fbcon_set_suspend(dev, 0); - nouveau_fbcon_zfill_all(dev); + if (dev->mode_config.num_crtc) { + nouveau_fbcon_set_suspend(dev, 0); + nouveau_fbcon_zfill_all(dev); - nouveau_display_init(dev); + nouveau_display_init(dev); + } /* Force CLUT to get re-loaded during modeset */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { From 88f002cc7c9c55f40bdaaa720a39b6484cdfbb3f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 1 Nov 2012 16:16:32 +1000 Subject: [PATCH 1384/2357] drm/nouveau: headless mode by default if pci class != vga display This is to prevent nouveau from taking over the console on headless boards such as Tesla. Backport of upstream commit: e412e95a268fa8544858ebfe066826b290430d51 Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_drv.c | 2 -- drivers/gpu/drm/nouveau/nouveau_state.c | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index b5232582d1e..05091c22a03 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -472,9 +472,7 @@ static int __init nouveau_init(void) #ifdef CONFIG_VGA_CONSOLE if (vgacon_text_force()) nouveau_modeset = 0; - else #endif - nouveau_modeset = 1; } if (!nouveau_modeset) diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index c2a8511e855..b096cf28213 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -47,6 +47,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->engine; + u32 pclass = dev->pdev->class >> 8; switch (dev_priv->chipset & 0xf0) { case 0x00: @@ -526,7 +527,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) } /* headless mode */ - if (nouveau_modeset == 2) { + if (nouveau_modeset == 2 || + (nouveau_modeset < 0 && pclass != PCI_CLASS_DISPLAY_VGA)) { engine->display.early_init = nouveau_stub_init; engine->display.late_takedown = nouveau_stub_takedown; engine->display.create = nouveau_stub_init; From 0b1743f0b0e1f8db0be800c301c0cf83add46fe9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 17 Oct 2012 16:47:11 +0900 Subject: [PATCH 1385/2357] Revert: ARM: SAMSUNG: Add naming of s3c64xx-spi devices This reverts commit baa526f45d3f096a1cd9f14b668203a03bbab6f9, which is commit 308b3afb97dc342e9c4f958d8b4c459ae0e22bd7 upstream. To quote Colin Cross: This patch breaks Exynos5 spi on 3.4.17. The patch with the bug that this patch was supposed to address went in to 3.6 and not 3.4, so this patch causes a driver name mismatch when applied to 3.4. Cc: Colin Cross Cc: Heiko Stuebner Cc: Sylwester Nawrocki Cc: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-exynos/common.c | 5 ---- arch/arm/mach-s3c24xx/s3c2416.c | 2 -- arch/arm/mach-s3c24xx/s3c2443.c | 4 --- arch/arm/mach-s5p64x0/common.c | 3 -- arch/arm/mach-s5pc100/common.c | 3 -- arch/arm/mach-s5pv210/common.c | 3 -- arch/arm/plat-samsung/include/plat/spi-core.h | 30 ------------------- 7 files changed, 50 deletions(-) delete mode 100644 arch/arm/plat-samsung/include/plat/spi-core.h diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index c2b77e5a542..5ccd6e80a60 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include "common.h" @@ -339,8 +338,6 @@ static void __init exynos4_map_io(void) s5p_fb_setname(0, "exynos4-fb"); s5p_hdmi_setname("exynos4-hdmi"); - - s3c64xx_spi_setname("exynos4210-spi"); } static void __init exynos5_map_io(void) @@ -361,8 +358,6 @@ static void __init exynos5_map_io(void) s3c_i2c0_setname("s3c2440-i2c"); s3c_i2c1_setname("s3c2440-i2c"); s3c_i2c2_setname("s3c2440-i2c"); - - s3c64xx_spi_setname("exynos4210-spi"); } static void __init exynos4_init_clocks(int xtal) diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c index f74818da580..7743fade50d 100644 --- a/arch/arm/mach-s3c24xx/s3c2416.c +++ b/arch/arm/mach-s3c24xx/s3c2416.c @@ -61,7 +61,6 @@ #include #include #include -#include static struct map_desc s3c2416_iodesc[] __initdata = { IODESC_ENT(WATCHDOG), @@ -132,7 +131,6 @@ void __init s3c2416_map_io(void) /* initialize device information early */ s3c2416_default_sdhci0(); s3c2416_default_sdhci1(); - s3c64xx_spi_setname("s3c2443-spi"); iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc)); } diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c index 165b6a6b3da..ab648ad8fa5 100644 --- a/arch/arm/mach-s3c24xx/s3c2443.c +++ b/arch/arm/mach-s3c24xx/s3c2443.c @@ -43,7 +43,6 @@ #include #include #include -#include static struct map_desc s3c2443_iodesc[] __initdata = { IODESC_ENT(WATCHDOG), @@ -101,9 +100,6 @@ void __init s3c2443_map_io(void) s3c24xx_gpiocfg_default.set_pull = s3c2443_gpio_setpull; s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull; - /* initialize device information early */ - s3c64xx_spi_setname("s3c2443-spi"); - iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc)); } diff --git a/arch/arm/mach-s5p64x0/common.c b/arch/arm/mach-s5p64x0/common.c index 111e404a81f..6e6a0a9d677 100644 --- a/arch/arm/mach-s5p64x0/common.c +++ b/arch/arm/mach-s5p64x0/common.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -180,7 +179,6 @@ void __init s5p6440_map_io(void) /* initialize any device information early */ s3c_adc_setname("s3c64xx-adc"); s3c_fb_setname("s5p64x0-fb"); - s3c64xx_spi_setname("s5p64x0-spi"); s5p64x0_default_sdhci0(); s5p64x0_default_sdhci1(); @@ -195,7 +193,6 @@ void __init s5p6450_map_io(void) /* initialize any device information early */ s3c_adc_setname("s3c64xx-adc"); s3c_fb_setname("s5p64x0-fb"); - s3c64xx_spi_setname("s5p64x0-spi"); s5p64x0_default_sdhci0(); s5p64x0_default_sdhci1(); diff --git a/arch/arm/mach-s5pc100/common.c b/arch/arm/mach-s5pc100/common.c index cc6e561c995..62190865886 100644 --- a/arch/arm/mach-s5pc100/common.c +++ b/arch/arm/mach-s5pc100/common.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include @@ -166,8 +165,6 @@ void __init s5pc100_map_io(void) s3c_onenand_setname("s5pc100-onenand"); s3c_fb_setname("s5pc100-fb"); s3c_cfcon_setname("s5pc100-pata"); - - s3c64xx_spi_setname("s5pc100-spi"); } void __init s5pc100_init_clocks(int xtal) diff --git a/arch/arm/mach-s5pv210/common.c b/arch/arm/mach-s5pv210/common.c index a0c50efe814..4c9e9027df9 100644 --- a/arch/arm/mach-s5pv210/common.c +++ b/arch/arm/mach-s5pv210/common.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include "common.h" @@ -197,8 +196,6 @@ void __init s5pv210_map_io(void) /* setup TV devices */ s5p_hdmi_setname("s5pv210-hdmi"); - - s3c64xx_spi_setname("s5pv210-spi"); } void __init s5pv210_init_clocks(int xtal) diff --git a/arch/arm/plat-samsung/include/plat/spi-core.h b/arch/arm/plat-samsung/include/plat/spi-core.h deleted file mode 100644 index 0b9428ab3fc..00000000000 --- a/arch/arm/plat-samsung/include/plat/spi-core.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2012 Heiko Stuebner - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __PLAT_S3C_SPI_CORE_H -#define __PLAT_S3C_SPI_CORE_H - -/* These functions are only for use with the core support code, such as - * the cpu specific initialisation code - */ - -/* re-define device name depending on support. */ -static inline void s3c64xx_spi_setname(char *name) -{ -#ifdef CONFIG_S3C64XX_DEV_SPI0 - s3c64xx_device_spi0.name = name; -#endif -#ifdef CONFIG_S3C64XX_DEV_SPI1 - s3c64xx_device_spi1.name = name; -#endif -#ifdef CONFIG_S3C64XX_DEV_SPI2 - s3c64xx_device_spi2.name = name; -#endif -} - -#endif /* __PLAT_S3C_SPI_CORE_H */ From 8ddd4813010397b5aa3bf9f81de1994c415dfc10 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 5 Nov 2012 09:50:52 +0100 Subject: [PATCH 1386/2357] Linux 3.4.18 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3f9f0762e88..95de44764c4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 17 +SUBLEVEL = 18 EXTRAVERSION = NAME = Saber-toothed Squirrel From ccd37ab3230af7b32db1a139d9fe95918813bc23 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 24 Oct 2012 12:39:02 +0100 Subject: [PATCH 1387/2357] xen/gntdev: don't leak memory from IOCTL_GNTDEV_MAP_GRANT_REF commit a67baeb77375199bbd842fa308cb565164dd1f19 upstream. map->kmap_ops allocated in gntdev_alloc_map() wasn't freed by gntdev_put_map(). Add a gntdev_free_map() helper function to free everything allocated by gntdev_alloc_map(). Signed-off-by: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/gntdev.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 7f124160848..9a113b714b4 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -105,6 +105,21 @@ static void gntdev_print_maps(struct gntdev_priv *priv, #endif } +static void gntdev_free_map(struct grant_map *map) +{ + if (map == NULL) + return; + + if (map->pages) + free_xenballooned_pages(map->count, map->pages); + kfree(map->pages); + kfree(map->grants); + kfree(map->map_ops); + kfree(map->unmap_ops); + kfree(map->kmap_ops); + kfree(map); +} + static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) { struct grant_map *add; @@ -142,12 +157,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) return add; err: - kfree(add->pages); - kfree(add->grants); - kfree(add->map_ops); - kfree(add->unmap_ops); - kfree(add->kmap_ops); - kfree(add); + gntdev_free_map(add); return NULL; } @@ -198,17 +208,9 @@ static void gntdev_put_map(struct grant_map *map) evtchn_put(map->notify.event); } - if (map->pages) { - if (!use_ptemod) - unmap_grant_pages(map, 0, map->count); - - free_xenballooned_pages(map->count, map->pages); - } - kfree(map->pages); - kfree(map->grants); - kfree(map->map_ops); - kfree(map->unmap_ops); - kfree(map); + if (map->pages && !use_ptemod) + unmap_grant_pages(map, 0, map->count); + gntdev_free_map(map); } /* ------------------------------------------------------------------ */ From da205c80275a7f7a90c2baab423783c55c406878 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 31 Oct 2012 12:38:31 -0400 Subject: [PATCH 1388/2357] xen/mmu: Use Xen specific TLB flush instead of the generic one. commit 95a7d76897c1e7243d4137037c66d15cbf2cce76 upstream. As Mukesh explained it, the MMUEXT_TLB_FLUSH_ALL allows the hypervisor to do a TLB flush on all active vCPUs. If instead we were using the generic one (which ends up being xen_flush_tlb) we end up making the MMUEXT_TLB_FLUSH_LOCAL hypercall. But before we make that hypercall the kernel will IPI all of the vCPUs (even those that were asleep from the hypervisor perspective). The end result is that we needlessly wake them up and do a TLB flush when we can just let the hypervisor do it correctly. This patch gives around 50% speed improvement when migrating idle guest's from one host to another. Oracle-bug: 14630170 Tested-by: Jingjie Jiang Suggested-by: Mukesh Rathor Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/mmu.c | 21 ++++++++++++++++++++- include/trace/events/xen.h | 8 ++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 69f5857660a..5cb8e27d43d 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1203,6 +1203,25 @@ unsigned long xen_read_cr2_direct(void) return this_cpu_read(xen_vcpu_info.arch.cr2); } +void xen_flush_tlb_all(void) +{ + struct mmuext_op *op; + struct multicall_space mcs; + + trace_xen_mmu_flush_tlb_all(0); + + preempt_disable(); + + mcs = xen_mc_entry(sizeof(*op)); + + op = mcs.args; + op->cmd = MMUEXT_TLB_FLUSH_ALL; + MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); + + xen_mc_issue(PARAVIRT_LAZY_MMU); + + preempt_enable(); +} static void xen_flush_tlb(void) { struct mmuext_op *op; @@ -2364,7 +2383,7 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, err = 0; out: - flush_tlb_all(); + xen_flush_tlb_all(); return err; } diff --git a/include/trace/events/xen.h b/include/trace/events/xen.h index 92f1a796829..348c4febdcb 100644 --- a/include/trace/events/xen.h +++ b/include/trace/events/xen.h @@ -377,6 +377,14 @@ DECLARE_EVENT_CLASS(xen_mmu_pgd, DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_pin); DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_unpin); +TRACE_EVENT(xen_mmu_flush_tlb_all, + TP_PROTO(int x), + TP_ARGS(x), + TP_STRUCT__entry(__array(char, x, 0)), + TP_fast_assign((void)x), + TP_printk("%s", "") + ); + TRACE_EVENT(xen_mmu_flush_tlb, TP_PROTO(int x), TP_ARGS(x), From 180bed351c02841004ee1c9d45a7efb1e207acf1 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Tue, 30 Oct 2012 23:39:10 -0700 Subject: [PATCH 1389/2357] Input: tsc40 - remove wrong announcement of pressure support commit 32ed1911fc79908d704023317d4ddeb3883fd07e upstream. The tsc40 driver announces it supports the pressure event, but will never send one. The announcement will cause tslib to wait for such events and sending all touch events with a pressure of 0. Removing the announcement will make tslib fall back to emulating the pressure on touch events so everything works as expected. Signed-off-by: Rolf Eike Beer Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/tsc40.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c index 29d5ed4dd31..80d46100d37 100644 --- a/drivers/input/touchscreen/tsc40.c +++ b/drivers/input/touchscreen/tsc40.c @@ -107,7 +107,6 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv) __set_bit(BTN_TOUCH, input_dev->keybit); input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0); input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0); - input_set_abs_params(ptsc->dev, ABS_PRESSURE, 0, 0, 0, 0); serio_set_drvdata(serio, ptsc); From a2fad9a26b1a8a6e9732925cd97bd7b9ee25d6cc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 26 Oct 2012 00:31:11 +0200 Subject: [PATCH 1390/2357] ath9k: fix stale pointers potentially causing access to free'd skbs commit 8c6e30936a7893a85f6222084f0f26aceb81137a upstream. bf->bf_next is only while buffers are chained as part of an A-MPDU in the tx queue. When a tid queue is flushed (e.g. on tearing down an aggregation session), frames can be enqueued again as normal transmission, without bf_next being cleared. This can lead to the old pointer being dereferenced again later. This patch might fix crashes and "Failed to stop TX DMA!" messages. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/xmit.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b78773b48db..11f252f88bd 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -337,6 +337,7 @@ static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) } bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + bf->bf_next = NULL; list_del(&bf->list); spin_unlock_bh(&sc->tx.txbuflock); @@ -1760,6 +1761,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, list_add_tail(&bf->list, &bf_head); bf->bf_state.bf_type = 0; + bf->bf_next = NULL; bf->bf_lastbf = bf; ath_tx_fill_desc(sc, bf, txq, fi->framelen); ath_tx_txqaddbuf(sc, txq, &bf_head, false); From 7bbaeecbffccbb38fcaf5f7c6af466c16e095d4b Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 29 Oct 2012 13:25:20 +0100 Subject: [PATCH 1391/2357] ath9k: Test for TID only in BlockAcks while checking tx status commit 6fe7cc71bbf3a0bc28c9cec3c00bc11e81344412 upstream. The ath9k xmit functions for AMPDUs can send frames as non-aggregate in case only one frame is currently available. The client will then answer using a normal Ack instead of a BlockAck. This acknowledgement has no TID stored and therefore the hardware is not able to provide us the corresponding TID. The TID set by the hardware in the tx status descriptor has to be seen as undefined and not as a valid TID value for normal acknowledgements. Doing otherwise results in a massive amount of retransmissions and stalls of connections. Users may experience low bandwidth and complete connection stalls in environments with transfers using multiple TIDs. This regression was introduced in b11b160defc48e4daa283f785192ea3a23a51f8e ("ath9k: validate the TID in the tx status information"). Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich Acked-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/xmit.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 11f252f88bd..12a42f2c1e8 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -419,7 +419,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; - bool rc_update = true; + bool rc_update = true, isba; struct ieee80211_tx_rate rates[4]; struct ath_frame_info *fi; int nframes; @@ -463,13 +463,17 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tid = ATH_AN_2_TID(an, tidno); seq_first = tid->seq_start; + isba = ts->ts_flags & ATH9K_TX_BA; /* * The hardware occasionally sends a tx status for the wrong TID. * In this case, the BA status cannot be considered valid and all * subframes need to be retransmitted + * + * Only BlockAcks have a TID and therefore normal Acks cannot be + * checked */ - if (tidno != ts->tid) + if (isba && tidno != ts->tid) txok = false; isaggr = bf_isaggr(bf); From 75d1ac720f8e92d2334ff7cc4e9a58ddb5213636 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 25 Oct 2012 09:51:39 +0200 Subject: [PATCH 1392/2357] rt2800: validate step value for temperature compensation commit bf7e1abe434ba9e22e8dc04a4cba4ab504b788b8 upstream. Some hardware has correct (!= 0xff) value of tssi_bounds[4] in the EEPROM, but step is equal to 0xff. This results on ridiculous delta calculations and completely broke TX power settings. Reported-and-tested-by: Pavel Lucik Signed-off-by: Stanislaw Gruszka Acked-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 6c0a12ea6a1..2ce6bf5b671 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2235,7 +2235,7 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) /* * Check if temperature compensation is supported. */ - if (tssi_bounds[4] == 0xff) + if (tssi_bounds[4] == 0xff || step == 0xff) return 0; /* From 506485a3c6d926cc01e6d05088eac94adf1d6ae5 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 31 Oct 2012 09:16:44 -0700 Subject: [PATCH 1393/2357] target: Don't return success from module_init() if setup fails commit 0d0f9dfb31e0a6c92063e235417b42df185b3275 upstream. If the call to core_dev_release_virtual_lun0() fails, then nothing sets ret to anything other than 0, so even though everything is torn down and freed, target_core_init_configfs() will seem to succeed and the module will be loaded. Fix this by passing the return value on up the chain. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_configfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 3f90d4b03e6..dbcede31ff8 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3197,7 +3197,8 @@ static int __init target_core_init_configfs(void) if (ret < 0) goto out; - if (core_dev_setup_virtual_lun0() < 0) + ret = core_dev_setup_virtual_lun0(); + if (ret < 0) goto out; return 0; From 227ab73196544a25f0c03338c5b49d3fdc1d1e38 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 31 Oct 2012 09:16:45 -0700 Subject: [PATCH 1394/2357] target: Avoid integer overflow in se_dev_align_max_sectors() commit 3e03989b5868acf69a391a424dc71fcd6cc48167 upstream. The expression (max_sectors * block_size) might overflow a u32 (indeed, since iblock sets max_hw_sectors to UINT_MAX, it is guaranteed to overflow and end up with a much-too-small result in many common cases). Fix this by doing an equivalent calculation that doesn't require multiplication. While we're touching this code, avoid splitting a printk format across two lines and use pr_info(...) instead of printk(KERN_INFO ...). Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_device.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index aa626774638..4df8022fe3c 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -826,20 +826,20 @@ int se_dev_check_shutdown(struct se_device *dev) u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) { - u32 tmp, aligned_max_sectors; + u32 aligned_max_sectors; + u32 alignment; /* * Limit max_sectors to a PAGE_SIZE aligned value for modern * transport_allocate_data_tasks() operation. */ - tmp = rounddown((max_sectors * block_size), PAGE_SIZE); - aligned_max_sectors = (tmp / block_size); - if (max_sectors != aligned_max_sectors) { - printk(KERN_INFO "Rounding down aligned max_sectors from %u" - " to %u\n", max_sectors, aligned_max_sectors); - return aligned_max_sectors; - } + alignment = max(1ul, PAGE_SIZE / block_size); + aligned_max_sectors = rounddown(max_sectors, alignment); + + if (max_sectors != aligned_max_sectors) + pr_info("Rounding down aligned max_sectors from %u to %u\n", + max_sectors, aligned_max_sectors); - return max_sectors; + return aligned_max_sectors; } void se_dev_set_default_attribs( From 7f83bc1f1bff2e9b89b3a505750b067f0073fe5c Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 31 Oct 2012 09:16:46 -0700 Subject: [PATCH 1395/2357] iscsi-target: Fix missed wakeup race in TX thread commit d5627acba9ae584cf4928af19f7ddf5f6837de32 upstream. The sleeping code in iscsi_target_tx_thread() is susceptible to the classic missed wakeup race: - TX thread finishes handle_immediate_queue() and handle_response_queue(), thinks both queues are empty. - Another thread adds a queue entry and does wake_up_process(), which does nothing because the TX thread is still awake. - TX thread does schedule_timeout() and sleeps forever. In practice this can kill an iSCSI connection if for example an initiator does single-threaded writes and the target misses the wakeup window when queueing an R2T; in this case the connection will be stuck until the initiator loses patience and does some task management operation (or kills the connection entirely). Fix this by converting to wait_event_interruptible(), which does not suffer from this sort of race. Signed-off-by: Roland Dreier Cc: Andy Grover Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/iscsi/iscsi_target.c | 4 +++- drivers/target/iscsi/iscsi_target_core.h | 1 + drivers/target/iscsi/iscsi_target_login.c | 1 + drivers/target/iscsi/iscsi_target_util.c | 22 ++++++++++++++++++++-- drivers/target/iscsi/iscsi_target_util.h | 1 + 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 23e122a5daf..ad202b342bf 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -3514,7 +3514,9 @@ int iscsi_target_tx_thread(void *arg) */ iscsit_thread_check_cpumask(conn, current, 1); - schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); + wait_event_interruptible(conn->queues_wq, + !iscsit_conn_all_queues_empty(conn) || + ts->status == ISCSI_THREAD_SET_RESET); if ((ts->status == ISCSI_THREAD_SET_RESET) || signal_pending(current)) diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 1596aec0c3d..2e46ea404ca 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -491,6 +491,7 @@ struct iscsi_tmr_req { }; struct iscsi_conn { + wait_queue_head_t queues_wq; /* Authentication Successful for this connection */ u8 auth_complete; /* State connection is currently in */ diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index ae304248c8c..3cb7a4f5b98 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -45,6 +45,7 @@ extern spinlock_t sess_idr_lock; static int iscsi_login_init_conn(struct iscsi_conn *conn) { + init_waitqueue_head(&conn->queues_wq); INIT_LIST_HEAD(&conn->conn_list); INIT_LIST_HEAD(&conn->conn_cmd_list); INIT_LIST_HEAD(&conn->immed_queue_list); diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 4eba86d2bd8..4c05ed6becc 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -656,7 +656,7 @@ void iscsit_add_cmd_to_immediate_queue( atomic_set(&conn->check_immediate_queue, 1); spin_unlock_bh(&conn->immed_queue_lock); - wake_up_process(conn->thread_set->tx_thread); + wake_up(&conn->queues_wq); } struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn) @@ -730,7 +730,7 @@ void iscsit_add_cmd_to_response_queue( atomic_inc(&cmd->response_queue_count); spin_unlock_bh(&conn->response_queue_lock); - wake_up_process(conn->thread_set->tx_thread); + wake_up(&conn->queues_wq); } struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn) @@ -784,6 +784,24 @@ static void iscsit_remove_cmd_from_response_queue( } } +bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn) +{ + bool empty; + + spin_lock_bh(&conn->immed_queue_lock); + empty = list_empty(&conn->immed_queue_list); + spin_unlock_bh(&conn->immed_queue_lock); + + if (!empty) + return empty; + + spin_lock_bh(&conn->response_queue_lock); + empty = list_empty(&conn->response_queue_list); + spin_unlock_bh(&conn->response_queue_lock); + + return empty; +} + void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) { struct iscsi_queue_req *qr, *qr_tmp; diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 835bf7de028..cfac698fb3c 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -28,6 +28,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_ extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8); extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *); extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *); +extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *); extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *); extern void iscsit_release_cmd(struct iscsi_cmd *); extern void iscsit_free_cmd(struct iscsi_cmd *); From bfc5de3bc907e97b9aabce6d6517a55d5ed6d791 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 31 Oct 2012 10:24:02 -0700 Subject: [PATCH 1396/2357] target: Fix incorrect usage of nested IRQ spinlocks in ABORT_TASK path commit ab74b3d62f05192bf8fb8f169e7999d1183b2e08 upstream. This patch changes core_tmr_abort_task() to use spin_lock -> spin_unlock around se_cmd->t_state_lock while spin_lock_irqsave is held via se_sess->sess_cmd_lock. Signed-off-by: Steve Hodgson Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_tmr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index f015839aef8..4a5c6d758c4 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -140,15 +140,15 @@ void core_tmr_abort_task( printk("ABORT_TASK: Found referenced %s task_tag: %u\n", se_cmd->se_tfo->get_fabric_name(), ref_tag); - spin_lock_irq(&se_cmd->t_state_lock); + spin_lock(&se_cmd->t_state_lock); if (se_cmd->transport_state & CMD_T_COMPLETE) { printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag); - spin_unlock_irq(&se_cmd->t_state_lock); + spin_unlock(&se_cmd->t_state_lock); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); goto out; } se_cmd->transport_state |= CMD_T_ABORTED; - spin_unlock_irq(&se_cmd->t_state_lock); + spin_unlock(&se_cmd->t_state_lock); list_del_init(&se_cmd->se_cmd_list); kref_get(&se_cmd->cmd_kref); From 91721d4a83437f183d29ae6397a3934fcfa28436 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 17 Oct 2012 13:56:19 +0200 Subject: [PATCH 1397/2357] cfg80211: fix antenna gain handling commit c4a9fafc77a5318f5ed26c509bbcddf03e18c201 upstream. No driver initializes chan->max_antenna_gain to something sensible, and the only place where it is being used right now is inside ath9k. This leads to ath9k potentially using less tx power than it can use, which can decrease performance/range in some rare cases. Rather than going through every single driver, this patch initializes chan->orig_mag in wiphy_register(), ignoring whatever value the driver left in there. If a driver for some reason wishes to limit it independent from regulatory rulesets, it can do so internally. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index bb5302dd592..7917c74b25b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -552,8 +552,7 @@ int wiphy_register(struct wiphy *wiphy) for (i = 0; i < sband->n_channels; i++) { sband->channels[i].orig_flags = sband->channels[i].flags; - sband->channels[i].orig_mag = - sband->channels[i].max_antenna_gain; + sband->channels[i].orig_mag = INT_MAX; sband->channels[i].orig_mpwr = sband->channels[i].max_power; sband->channels[i].band = band; From 2404ce30fd4e4c46d3c3869093a5987c0d56fee6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 25 Oct 2012 21:51:59 +0200 Subject: [PATCH 1398/2357] wireless: drop invalid mesh address extension frames commit 7dd111e8ee10cc6816669eabcad3334447673236 upstream. The mesh header can have address extension by a 4th or a 5th and 6th address, but never both. Drop such frames in 802.11 -> 802.3 conversion along with any frames that have the wrong extension. Reviewed-by: Javier Cardona Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/util.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/wireless/util.c b/net/wireless/util.c index d835377b4da..d39a6c239c2 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -293,18 +293,15 @@ EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) { int ae = meshhdr->flags & MESH_FLAGS_AE; - /* 7.1.3.5a.2 */ + /* 802.11-2012, 8.2.4.7.3 */ switch (ae) { + default: case 0: return 6; case MESH_FLAGS_AE_A4: return 12; case MESH_FLAGS_AE_A5_A6: return 18; - case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): - return 24; - default: - return 6; } } @@ -354,6 +351,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, /* make sure meshdr->flags is on the linear part */ if (!pskb_may_pull(skb, hdrlen + 1)) return -1; + if (meshdr->flags & MESH_FLAGS_AE_A4) + return -1; if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { skb_copy_bits(skb, hdrlen + offsetof(struct ieee80211s_hdr, eaddr1), @@ -378,6 +377,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, /* make sure meshdr->flags is on the linear part */ if (!pskb_may_pull(skb, hdrlen + 1)) return -1; + if (meshdr->flags & MESH_FLAGS_AE_A5_A6) + return -1; if (meshdr->flags & MESH_FLAGS_AE_A4) skb_copy_bits(skb, hdrlen + offsetof(struct ieee80211s_hdr, eaddr1), From fec9a0c8f048db2807646fea92bdd87dc8adbade Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 Oct 2012 14:19:53 +0200 Subject: [PATCH 1399/2357] mac80211: use blacklist for duplicate IE check commit 9690fb169b433a66485c808e4fc352b8a0f8d866 upstream. Instead of the current whitelist which accepts duplicates only for the quiet and vendor IEs, use a blacklist of all IEs (that we currently parse) that can't be duplicated. This avoids detecting a beacon as corrupt in the future when new IEs are added that can be duplicated. Signed-off-by: Paul Stewart Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/util.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index eb9d7c0529b..266d0925ba2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -592,13 +592,38 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, break; } - if (id != WLAN_EID_VENDOR_SPECIFIC && - id != WLAN_EID_QUIET && - test_bit(id, seen_elems)) { - elems->parse_error = true; - left -= elen; - pos += elen; - continue; + switch (id) { + case WLAN_EID_SSID: + case WLAN_EID_SUPP_RATES: + case WLAN_EID_FH_PARAMS: + case WLAN_EID_DS_PARAMS: + case WLAN_EID_CF_PARAMS: + case WLAN_EID_TIM: + case WLAN_EID_IBSS_PARAMS: + case WLAN_EID_CHALLENGE: + case WLAN_EID_RSN: + case WLAN_EID_ERP_INFO: + case WLAN_EID_EXT_SUPP_RATES: + case WLAN_EID_HT_CAPABILITY: + case WLAN_EID_MESH_ID: + case WLAN_EID_MESH_CONFIG: + case WLAN_EID_PEER_MGMT: + case WLAN_EID_PREQ: + case WLAN_EID_PREP: + case WLAN_EID_PERR: + case WLAN_EID_RANN: + case WLAN_EID_CHANNEL_SWITCH: + case WLAN_EID_EXT_CHANSWITCH_ANN: + case WLAN_EID_COUNTRY: + case WLAN_EID_PWR_CONSTRAINT: + case WLAN_EID_TIMEOUT_INTERVAL: + if (test_bit(id, seen_elems)) { + elems->parse_error = true; + left -= elen; + pos += elen; + continue; + } + break; } if (calc_crc && id < 64 && (filter & (1ULL << id))) From 739b9fa801cab6bd63d51de7d7a97b7bd8bbbdc8 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Wed, 24 Oct 2012 12:43:30 -0700 Subject: [PATCH 1400/2357] mac80211: Only process mesh config header on frames that RA_MATCH commit 555cb715be8ef98b8ec362b23dfc254d432a35b1 upstream. Doing otherwise is wrong, and may wreak havoc on the mpp tables, specially if the frame is encrypted. Reported-by: Chaoxing Lin Signed-off-by: Javier Cardona Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c9b508ea9d6..94b6f397fd3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1900,7 +1900,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata)) return RX_DROP_MONITOR; - if (!ieee80211_is_data(hdr->frame_control)) + if (!ieee80211_is_data(hdr->frame_control) || + !(status->rx_flags & IEEE80211_RX_RA_MATCH)) return RX_CONTINUE; if (!mesh_hdr->ttl) @@ -1944,9 +1945,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) } skb_set_queue_mapping(skb, q); - if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) - goto out; - if (!--mesh_hdr->ttl) { IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); return RX_DROP_MONITOR; From 7be001e0fa58fa84e81fcc8a7951a3f3fe7c642c Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 25 Oct 2012 11:10:18 -0700 Subject: [PATCH 1401/2357] mac80211: don't inspect Sequence Control field on control frames commit f7fbf70ee9db6da6033ae50d100e017ac1f26555 upstream. Per IEEE Std. 802.11-2012, Sec 8.2.4.4.1, the sequence Control field is not present in control frames. We noticed this problem when processing Block Ack Requests. Signed-off-by: Javier Cardona Signed-off-by: Javier Lopez Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 94b6f397fd3..d58a3285233 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1465,6 +1465,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) hdr = (struct ieee80211_hdr *)rx->skb->data; fc = hdr->frame_control; + + if (ieee80211_is_ctl(fc)) + return RX_CONTINUE; + sc = le16_to_cpu(hdr->seq_ctrl); frag = sc & IEEE80211_SCTL_FRAG; From f93a53b38d63be316156ad8a332ed982ad33a59d Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 24 Oct 2012 18:29:49 +0200 Subject: [PATCH 1402/2357] DRM/Radeon: Fix Load Detection on legacy primary DAC. commit 83325d072185899b706de2956170b246585aaec9 upstream. An uninitialized variable led to broken load detection. Signed-off-by: Egbert Eich Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 1461e2ce359..d92f483fed4 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -650,6 +650,7 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; WREG32(RADEON_DAC_CNTL, tmp); + tmp = dac_macro_cntl; tmp &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B); From 4b51c17efde8501badb4bf7355172eb262407ad8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 1 Nov 2012 13:47:09 +1000 Subject: [PATCH 1403/2357] drm/udl: fix stride issues scanning out stride != width*bpp commit 3916e1d71b62b120888aa50bcc8d9a6200fc19a7 upstream. When buffer sharing with the i915 and using a 1680x1050 monitor, the i915 gives is a 6912 buffer for the 6720 width, the code doesn't render this properly as it uses one value to set the base address for reading from the vmap and for where to start on the device. This fixes it by calculating the values correctly for the device and for the pixmap. No idea how I haven't seen this before now. Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_drv.h | 2 +- drivers/gpu/drm/udl/udl_fb.c | 12 +++++++----- drivers/gpu/drm/udl/udl_transfer.c | 5 +++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 96820d03a30..e7605758661 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -103,7 +103,7 @@ udl_fb_user_fb_create(struct drm_device *dev, int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, - u32 byte_offset, u32 byte_width, + u32 byte_offset, u32 device_byte_offset, u32 byte_width, int *ident_ptr, int *sent_ptr); int udl_dumb_create(struct drm_file *file_priv, diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 4d9c3a5d8a4..b9282cf7aea 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -114,9 +114,10 @@ static void udlfb_dpy_deferred_io(struct fb_info *info, list_for_each_entry(cur, &fbdefio->pagelist, lru) { if (udl_render_hline(dev, (ufbdev->ufb.base.bits_per_pixel / 8), - &urb, (char *) info->fix.smem_start, - &cmd, cur->index << PAGE_SHIFT, - PAGE_SIZE, &bytes_identical, &bytes_sent)) + &urb, (char *) info->fix.smem_start, + &cmd, cur->index << PAGE_SHIFT, + cur->index << PAGE_SHIFT, + PAGE_SIZE, &bytes_identical, &bytes_sent)) goto error; bytes_rendered += PAGE_SIZE; } @@ -178,10 +179,11 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, for (i = y; i < y + height ; i++) { const int line_offset = fb->base.pitches[0] * i; const int byte_offset = line_offset + (x * bpp); - + const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp); if (udl_render_hline(dev, bpp, &urb, (char *) fb->obj->vmapping, - &cmd, byte_offset, width * bpp, + &cmd, byte_offset, dev_byte_offset, + width * bpp, &bytes_identical, &bytes_sent)) goto error; } diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index b9320e2608d..fc1134416bc 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -213,11 +213,12 @@ static void udl_compress_hline16( */ int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, - u32 byte_offset, u32 byte_width, + u32 byte_offset, u32 device_byte_offset, + u32 byte_width, int *ident_ptr, int *sent_ptr) { const u8 *line_start, *line_end, *next_pixel; - u32 base16 = 0 + (byte_offset / bpp) * 2; + u32 base16 = 0 + (device_byte_offset / bpp) * 2; struct urb *urb = *urb_ptr; u8 *cmd = *urb_buf_ptr; u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; From 537d86c490a03bcb56dfa24c0327c18e61b1ced5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 26 Oct 2012 00:33:36 +0200 Subject: [PATCH 1404/2357] mac80211: check management frame header length commit 4a4f1a5808c8bb0b72a4f6e5904c53fb8c9cd966 upstream. Due to pskb_may_pull() checking the skb length, all non-management frames are checked on input whether their 802.11 header is fully present. Also add that check for management frames and remove a check that is now duplicate. This prevents accessing skb data beyond the frame end. Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rx.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d58a3285233..06025a9065f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1473,7 +1473,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) frag = sc & IEEE80211_SCTL_FRAG; if (likely((!ieee80211_has_morefrags(fc) && frag == 0) || - (rx->skb)->len < 24 || is_multicast_ether_addr(hdr->addr1))) { /* not fragmented */ goto out; @@ -2929,10 +2928,15 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, test_bit(SCAN_SW_SCANNING, &local->scanning))) status->rx_flags |= IEEE80211_RX_IN_SCAN; - if (ieee80211_is_mgmt(fc)) - err = skb_linearize(skb); - else + if (ieee80211_is_mgmt(fc)) { + /* drop frame if too short for header */ + if (skb->len < ieee80211_hdrlen(fc)) + err = -ENOBUFS; + else + err = skb_linearize(skb); + } else { err = !pskb_may_pull(skb, ieee80211_hdrlen(fc)); + } if (err) { dev_kfree_skb(skb); From 4435990b6d456a8c5cac203c025d1f10e0b48a93 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 26 Oct 2012 00:36:40 +0200 Subject: [PATCH 1405/2357] mac80211: verify that skb data is present commit 9b395bc3be1cebf0144a127c7e67d56dbdac0930 upstream. A number of places in the mesh code don't check that the frame data is present and in the skb header when trying to access. Add those checks and the necessary pskb_may_pull() calls. This prevents accessing data that doesn't actually exist. To do this, export ieee80211_get_mesh_hdrlen() to be able to use it in mac80211. Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- include/net/cfg80211.h | 9 +++++++++ net/mac80211/rx.c | 32 +++++++++++++++++++++++++++++++- net/wireless/util.c | 3 ++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 83d800c31e3..b4de1942c6f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2479,6 +2479,15 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); */ unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc); +/** + * ieee80211_get_mesh_hdrlen - get mesh extension header length + * @meshhdr: the mesh extension header, only the flags field + * (first byte) will be accessed + * Returns the length of the extension header, which is always at + * least 6 bytes and at most 18 if address 5 and 6 are present. + */ +unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); + /** * DOC: Data path helpers * diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 06025a9065f..efe1b98fa3f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -513,6 +513,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (ieee80211_is_action(hdr->frame_control)) { u8 category; + + /* make sure category field is present */ + if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE) + return RX_DROP_MONITOR; + mgmt = (struct ieee80211_mgmt *)hdr; category = mgmt->u.action.category; if (category != WLAN_CATEGORY_MESH_ACTION && @@ -1895,6 +1900,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_hdrlen(hdr->frame_control); + + /* make sure fixed part of mesh header is there, also checks skb len */ + if (!pskb_may_pull(rx->skb, hdrlen + 6)) + return RX_DROP_MONITOR; + + mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); + + /* make sure full mesh header is there, also checks skb len */ + if (!pskb_may_pull(rx->skb, + hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr))) + return RX_DROP_MONITOR; + + /* reload pointers */ + hdr = (struct ieee80211_hdr *) skb->data; mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); /* frame is in RMC, don't forward */ @@ -1918,9 +1937,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) if (is_multicast_ether_addr(hdr->addr1)) { mpp_addr = hdr->addr3; proxied_addr = mesh_hdr->eaddr1; - } else { + } else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) { + /* has_a4 already checked in ieee80211_rx_mesh_check */ mpp_addr = hdr->addr4; proxied_addr = mesh_hdr->eaddr2; + } else { + return RX_DROP_MONITOR; } rcu_read_lock(); @@ -2362,6 +2384,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) } break; case WLAN_CATEGORY_SELF_PROTECTED: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.self_prot.action_code))) + break; + switch (mgmt->u.action.u.self_prot.action_code) { case WLAN_SP_MESH_PEERING_OPEN: case WLAN_SP_MESH_PEERING_CLOSE: @@ -2380,6 +2406,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) } break; case WLAN_CATEGORY_MESH_ACTION: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.mesh_action.action_code))) + break; + if (!ieee80211_vif_is_mesh(&sdata->vif)) break; if (mesh_action_is_path_sel(mgmt) && diff --git a/net/wireless/util.c b/net/wireless/util.c index d39a6c239c2..d22dce7b8b8 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -290,7 +290,7 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) } EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); -static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) +unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) { int ae = meshhdr->flags & MESH_FLAGS_AE; /* 802.11-2012, 8.2.4.7.3 */ @@ -304,6 +304,7 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) return 18; } } +EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, enum nl80211_iftype iftype) From d39904cae2cb6e0dcbee3f80692b6052515e43ea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 26 Oct 2012 00:41:23 +0200 Subject: [PATCH 1406/2357] mac80211: make sure data is accessible in EAPOL check commit 6dbda2d00d466225f9db1dc695ff852443f28832 upstream. The code to allow EAPOL frames even when the station isn't yet marked associated needs to check that the incoming frame is long enough and due to paged RX it also can't assume skb->data contains the right data, it must use skb_copy_bits(). Fix this to avoid using data that doesn't really exist. Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rx.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index efe1b98fa3f..8ce9feb1301 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -874,14 +874,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) */ if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION && ieee80211_is_data_present(hdr->frame_control)) { - u16 ethertype; - u8 *payload; - - payload = rx->skb->data + - ieee80211_hdrlen(hdr->frame_control); - ethertype = (payload[6] << 8) | payload[7]; - if (cpu_to_be16(ethertype) == - rx->sdata->control_port_protocol) + unsigned int hdrlen; + __be16 ethertype; + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + + if (rx->skb->len < hdrlen + 8) + return RX_DROP_MONITOR; + + skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2); + if (ethertype == rx->sdata->control_port_protocol) return RX_CONTINUE; } From 1feb89af489539f927fc9ff0de99c945eec181c2 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 26 Oct 2012 18:54:25 +0200 Subject: [PATCH 1407/2357] mac80211: fix SSID copy on IBSS JOIN commit badecb001a310408d3473b1fc2ed5aefd0bc92a9 upstream. The 'ssid' field of the cfg80211_ibss_params is a u8 pointer and its length is likely to be less than IEEE80211_MAX_SSID_LEN most of the time. This patch fixes the ssid copy in ieee80211_ibss_join() by using the SSID length to prevent it from reading beyond the string. Signed-off-by: Antonio Quartulli [rewrapped commit message, small rewording] Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ibss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index cef7c29214a..4a3666b678e 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1110,7 +1110,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; sdata->u.ibss.ibss_join_req = jiffies; - memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); + memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len); sdata->u.ibss.ssid_len = params->ssid_len; mutex_unlock(&sdata->u.ibss.mtx); From b37d05604ce92f1c118fb6aeb2af8af71998d3e7 Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Tue, 16 Oct 2012 13:22:19 -0400 Subject: [PATCH 1408/2357] nfsv3: Make v3 mounts fail with ETIMEDOUTs instead EIO on mountd timeouts commit acce94e68a0f346115fd41cdc298197d2d5a59ad upstream. In very busy v3 environment, rpc.mountd can respond to the NULL procedure but not the MNT procedure in a timely manner causing the MNT procedure to time out. The problem is the mount system call returns EIO which causes the mount to fail, instead of ETIMEDOUT, which would cause the mount to be retried. This patch sets the RPC_TASK_SOFT|RPC_TASK_TIMEOUT flags to the rpc_call_sync() call in nfs_mount() which causes ETIMEDOUT to be returned on timed out connections. Signed-off-by: Steve Dickson Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/mount_clnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 8e65c7f1f87..015f71f8f62 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -181,7 +181,7 @@ int nfs_mount(struct nfs_mount_request *info) else msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT]; - status = rpc_call_sync(mnt_clnt, &msg, 0); + status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT); rpc_shutdown_client(mnt_clnt); if (status < 0) From 43113027b701f7b3f63c577056a9160dd3053f37 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 21 Oct 2012 19:23:52 +0100 Subject: [PATCH 1409/2357] nfs: Show original device name verbatim in /proc/*/mount{s,info} commit 97a54868262da1629a3e65121e65b8e8c4419d9f upstream. Since commit c7f404b ('vfs: new superblock methods to override /proc/*/mount{s,info}'), nfs_path() is used to generate the mounted device name reported back to userland. nfs_path() always generates a trailing slash when the given dentry is the root of an NFS mount, but userland may expect the original device name to be returned verbatim (as it used to be). Make this canonicalisation optional and change the callers accordingly. [jrnieder@gmail.com: use flag instead of bool argument] Reported-and-tested-by: Chris Hiestand Reference: http://bugs.debian.org/669314 Signed-off-by: Ben Hutchings Signed-off-by: Jonathan Nieder Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/internal.h | 5 +++-- fs/nfs/namespace.c | 19 ++++++++++++++----- fs/nfs/nfs4namespace.c | 3 ++- fs/nfs/super.c | 2 +- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index b777bdaba4c..33aa76fec3a 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -277,8 +277,9 @@ extern void nfs_sb_active(struct super_block *sb); extern void nfs_sb_deactive(struct super_block *sb); /* namespace.c */ +#define NFS_PATH_CANONICAL 1 extern char *nfs_path(char **p, struct dentry *dentry, - char *buffer, ssize_t buflen); + char *buffer, ssize_t buflen, unsigned flags); extern struct vfsmount *nfs_d_automount(struct path *path); #ifdef CONFIG_NFS_V4 rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); @@ -371,7 +372,7 @@ static inline char *nfs_devname(struct dentry *dentry, char *buffer, ssize_t buflen) { char *dummy; - return nfs_path(&dummy, dentry, buffer, buflen); + return nfs_path(&dummy, dentry, buffer, buflen, NFS_PATH_CANONICAL); } /* diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index d51868e5683..2257d1f33e3 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -37,6 +37,7 @@ static struct vfsmount *nfs_do_submount(struct dentry *dentry, * @dentry - pointer to dentry * @buffer - result buffer * @buflen - length of buffer + * @flags - options (see below) * * Helper function for constructing the server pathname * by arbitrary hashed dentry. @@ -44,8 +45,14 @@ static struct vfsmount *nfs_do_submount(struct dentry *dentry, * This is mainly for use in figuring out the path on the * server side when automounting on top of an existing partition * and in generating /proc/mounts and friends. + * + * Supported flags: + * NFS_PATH_CANONICAL: ensure there is exactly one slash after + * the original device (export) name + * (if unset, the original name is returned verbatim) */ -char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) +char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen, + unsigned flags) { char *end; int namelen; @@ -78,7 +85,7 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) rcu_read_unlock(); goto rename_retry; } - if (*end != '/') { + if ((flags & NFS_PATH_CANONICAL) && *end != '/') { if (--buflen < 0) { spin_unlock(&dentry->d_lock); rcu_read_unlock(); @@ -95,9 +102,11 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) return end; } namelen = strlen(base); - /* Strip off excess slashes in base string */ - while (namelen > 0 && base[namelen - 1] == '/') - namelen--; + if (flags & NFS_PATH_CANONICAL) { + /* Strip off excess slashes in base string */ + while (namelen > 0 && base[namelen - 1] == '/') + namelen--; + } buflen -= namelen; if (buflen < 0) { spin_unlock(&dentry->d_lock); diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index a7f3dedc4ec..b604be2dae6 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -81,7 +81,8 @@ static char *nfs_path_component(const char *nfspath, const char *end) static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) { char *limit; - char *path = nfs_path(&limit, dentry, buffer, buflen); + char *path = nfs_path(&limit, dentry, buffer, buflen, + NFS_PATH_CANONICAL); if (!IS_ERR(path)) { char *path_component = nfs_path_component(path, limit); if (path_component) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 5976e243d24..feabe7a394c 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -812,7 +812,7 @@ static int nfs_show_devname(struct seq_file *m, struct dentry *root) int err = 0; if (!page) return -ENOMEM; - devname = nfs_path(&dummy, root, page, PAGE_SIZE); + devname = nfs_path(&dummy, root, page, PAGE_SIZE, 0); if (IS_ERR(devname)) err = PTR_ERR(devname); else From 8827f3112b5f3bd0ffa21dc647cb22b197558c59 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 29 Oct 2012 18:53:23 -0400 Subject: [PATCH 1410/2357] NFSv4: nfs4_locku_done must release the sequence id commit 2b1bc308f492589f7d49012ed24561534ea2be8c upstream. If the state recovery machinery is triggered by the call to nfs4_async_handle_error() then we can deadlock. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b106b9729bc..3b005ebb468 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -4306,6 +4306,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) rpc_restart_call_prepare(task); } + nfs_release_seqid(calldata->arg.seqid); } static void nfs4_locku_prepare(struct rpc_task *task, void *data) From 0ada2107a13f1b1ae8bdd5fec32912bc40f4e679 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 29 Oct 2012 18:37:40 -0400 Subject: [PATCH 1411/2357] NFSv4.1: We must release the sequence id when we fail to get a session slot commit 2240a9e2d013d8269ea425b73e1d7a54c7bc141f upstream. If we do not release the sequence id in cases where we fail to get a session slot, then we can deadlock if we hit a recovery scenario. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3b005ebb468..5e801803072 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1478,9 +1478,11 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) data->timestamp = jiffies; if (nfs4_setup_sequence(data->o_arg.server, &data->o_arg.seq_args, - &data->o_res.seq_res, task)) - return; - rpc_call_start(task); + &data->o_res.seq_res, + task) != 0) + nfs_release_seqid(data->o_arg.seqid); + else + rpc_call_start(task); return; unlock_no_action: rcu_read_unlock(); @@ -2097,9 +2099,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) if (nfs4_setup_sequence(NFS_SERVER(calldata->inode), &calldata->arg.seq_args, &calldata->res.seq_res, - task)) - goto out; - rpc_call_start(task); + task) != 0) + nfs_release_seqid(calldata->arg.seqid); + else + rpc_call_start(task); out: dprintk("%s: done!\n", __func__); } @@ -4323,9 +4326,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) calldata->timestamp = jiffies; if (nfs4_setup_sequence(calldata->server, &calldata->arg.seq_args, - &calldata->res.seq_res, task)) - return; - rpc_call_start(task); + &calldata->res.seq_res, + task) != 0) + nfs_release_seqid(calldata->arg.seqid); + else + rpc_call_start(task); } static const struct rpc_call_ops nfs4_locku_ops = { @@ -4470,7 +4475,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) /* Do we need to do an open_to_lock_owner? */ if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) - return; + goto out_release_lock_seqid; data->arg.open_stateid = &state->stateid; data->arg.new_lock_owner = 1; data->res.open_seqid = data->arg.open_seqid; @@ -4479,10 +4484,15 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) data->timestamp = jiffies; if (nfs4_setup_sequence(data->server, &data->arg.seq_args, - &data->res.seq_res, task)) + &data->res.seq_res, + task) == 0) { + rpc_call_start(task); return; - rpc_call_start(task); - dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); + } + nfs_release_seqid(data->arg.open_seqid); +out_release_lock_seqid: + nfs_release_seqid(data->arg.lock_seqid); + dprintk("%s: done!, ret = %d\n", __func__, task->tk_status); } static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) From 588c72e88125b1abe50efb3f1b6b768b98302e2c Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 12 Jun 2012 16:54:16 -0400 Subject: [PATCH 1412/2357] nfsd: add get_uint for u32's commit a007c4c3e943ecc054a806c259d95420a188754b upstream. I don't think there's a practical difference for the range of values these interfaces should see, but it would be safer to be unambiguous. Signed-off-by: J. Bruce Fields Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/export.c | 6 +++--- include/linux/sunrpc/cache.h | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 8e9689abbc0..e9a020f283f 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -401,7 +401,7 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) int migrated, i, err; /* listsize */ - err = get_int(mesg, &fsloc->locations_count); + err = get_uint(mesg, &fsloc->locations_count); if (err) return err; if (fsloc->locations_count > MAX_FS_LOCATIONS) @@ -459,7 +459,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) return -EINVAL; for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) { - err = get_int(mesg, &f->pseudoflavor); + err = get_uint(mesg, &f->pseudoflavor); if (err) return err; /* @@ -468,7 +468,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) * problem at export time instead of when a client fails * to authenticate. */ - err = get_int(mesg, &f->flags); + err = get_uint(mesg, &f->flags); if (err) return err; /* Only some flags are allowed to differ between flavors: */ diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index f5fd6160dbc..dd2bb84526a 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -228,6 +228,22 @@ static inline int get_int(char **bpp, int *anint) return 0; } +static inline int get_uint(char **bpp, unsigned int *anint) +{ + char buf[50]; + int len = qword_get(bpp, buf, sizeof(buf)); + + if (len < 0) + return -EINVAL; + if (len == 0) + return -ENOENT; + + if (kstrtouint(buf, 0, anint)) + return -EINVAL; + + return 0; +} + /* * timestamps kept in the cache are expressed in seconds * since boot. This is the best for measuring differences in From 088eb1bed178645788538611ac31ba9991cd88c4 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 31 Oct 2012 12:16:01 +1100 Subject: [PATCH 1413/2357] NFS: fix bug in legacy DNS resolver. commit 8d96b10639fb402357b75b055b1e82a65ff95050 upstream. The DNS resolver's use of the sunrpc cache involves a 'ttl' number (relative) rather that a timeout (absolute). This confused me when I wrote commit c5b29f885afe890f953f7f23424045cdad31d3e4 "sunrpc: use seconds since boot in expiry cache" and I managed to break it. The effect is that any TTL is interpreted as 0, and nothing useful gets into the cache. This patch removes the use of get_expiry() - which really expects an expiry time - and uses get_uint() instead, treating the int correctly as a ttl. This fixes a regression that has been present since 2.6.37, causing certain NFS accesses in certain environments to incorrectly fail. Reported-by: Chuck Lever Tested-by: Chuck Lever Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/dns_resolve.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index b3924b8a600..786cd653371 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c @@ -214,7 +214,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) { char buf1[NFS_DNS_HOSTNAME_MAXLEN+1]; struct nfs_dns_ent key, *item; - unsigned long ttl; + unsigned int ttl; ssize_t len; int ret = -EINVAL; @@ -237,7 +237,8 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) key.namelen = len; memset(&key.h, 0, sizeof(key.h)); - ttl = get_expiry(&buf); + if (get_uint(&buf, &ttl) < 0) + goto out; if (ttl == 0) goto out; key.h.expiry_time = ttl + seconds_since_boot(); From cde52501359fecbcb5832c77c49f11af2cfaa21b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Aug 2012 16:08:17 -0400 Subject: [PATCH 1414/2357] NFS: Fix Oopses in nfs_lookup_revalidate and nfs4_lookup_revalidate [Fixed upstream as part of 0b728e1911c, but that's a much larger patch, this is only the nfs portion backported as needed.] Fix the following Oops in 3.5.1: BUG: unable to handle kernel NULL pointer dereference at 0000000000000038 IP: [] nfs_lookup_revalidate+0x2d/0x480 [nfs] PGD 337c63067 PUD 0 Oops: 0000 [#1] SMP CPU 5 Modules linked in: nfs fscache nfsd lockd nfs_acl auth_rpcgss sunrpc af_packet binfmt_misc cpufreq_conservative cpufreq_userspace cpufreq_powersave dm_mod acpi_cpufreq mperf coretemp gpio_ich kvm_intel joydev kvm ioatdma hid_generic igb lpc_ich i7core_edac edac_core ptp serio_raw dca pcspkr i2c_i801 mfd_core sg pps_core usbhid crc32c_intel microcode button autofs4 uhci_hcd ttm drm_kms_helper drm i2c_algo_bit sysimgblt sysfillrect syscopyarea ehci_hcd usbcore usb_common scsi_dh_rdac scsi_dh_emc scsi_dh_hp_sw scsi_dh_alua scsi_dh edd fan ata_piix thermal processor thermal_sys Pid: 30431, comm: java Not tainted 3.5.1-2-default #1 Supermicro X8DTT/X8DTT RIP: 0010:[] [] nfs_lookup_revalidate+0x2d/0x480 [nfs] RSP: 0018:ffff8801b418bd38 EFLAGS: 00010292 RAX: 00000000fffffff6 RBX: ffff88032016d800 RCX: 0000000000000020 RDX: ffffffff00000000 RSI: 0000000000000000 RDI: ffff8801824a7b00 RBP: ffff8801b418bdf8 R08: 7fffff0034323030 R09: fffffffff04c03ed R10: ffff8801824a7b00 R11: 0000000000000002 R12: ffff8801824a7b00 R13: ffff8801824a7b00 R14: 0000000000000000 R15: ffff8803201725d0 FS: 00002b53a46cb700(0000) GS:ffff88033fc20000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000038 CR3: 000000020a426000 CR4: 00000000000007e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process java (pid: 30431, threadinfo ffff8801b418a000, task ffff8801b5d20600) Stack: ffff8801b418be44 ffff88032016d800 ffff8801b418bdf8 0000000000000000 ffff8801824a7b00 ffff8801b418bdd7 ffff8803201725d0 ffffffff8116a9c0 ffff8801b5c38dc0 0000000000000007 ffff88032016d800 0000000000000000 Call Trace: [] lookup_dcache+0x80/0xe0 [] __lookup_hash+0x23/0x90 [] lookup_one_len+0xc5/0x100 [] nfs_sillyrename+0xe3/0x210 [nfs] [] vfs_unlink.part.25+0x7f/0xe0 [] do_unlinkat+0x1ac/0x1d0 [] system_call_fastpath+0x16/0x1b [<00002b5348b5f527>] 0x2b5348b5f526 Code: ec 38 b8 f6 ff ff ff 4c 89 64 24 18 4c 89 74 24 28 49 89 fc 48 89 5c 24 08 48 89 6c 24 10 49 89 f6 4c 89 6c 24 20 4c 89 7c 24 30 46 38 40 0f 85 d1 00 00 00 e8 c4 c4 df e0 48 8b 58 30 49 89 RIP [] nfs_lookup_revalidate+0x2d/0x480 [nfs] RSP CR2: 0000000000000038 ---[ end trace 845113ed191985dd ]--- This Oops affects 3.5 kernels and older, and is due to lookup_one_len() calling down to the dentry revalidation code with a NULL pointer to struct nameidata. It is fixed upstream by commit 0b728e1911c (stop passing nameidata * to ->d_revalidate()) Reported-by: Richard Ems Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 8789210c690..53ad9d1c37e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1103,7 +1103,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) struct nfs_fattr *fattr = NULL; int error; - if (nd->flags & LOOKUP_RCU) + if (nd && (nd->flags & LOOKUP_RCU)) return -ECHILD; parent = dget_parent(dentry); @@ -1502,7 +1502,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) struct iattr attr; int openflags, ret = 0; - if (nd->flags & LOOKUP_RCU) + if (nd && (nd->flags & LOOKUP_RCU)) return -ECHILD; inode = dentry->d_inode; From 47baf0d8ba90a5765f8f51130f9b20dc49ff6da4 Mon Sep 17 00:00:00 2001 From: Ilija Hadzic Date: Mon, 29 Oct 2012 17:35:00 +0000 Subject: [PATCH 1415/2357] drm: restore open_count if drm_setup fails commit 0f1cb1bd94a9c967cd4ad3de51cfdabe61eb5dcc upstream. If drm_setup (called at first open) fails, the whole open call has failed, so we should not keep the open_count incremented. Signed-off-by: Ilija Hadzic Reviewed-by: Thomas Hellstrom Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_fops.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 123de28f94e..b90abff1934 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -139,8 +139,11 @@ int drm_open(struct inode *inode, struct file *filp) retcode = drm_open_helper(inode, filp, dev); if (!retcode) { atomic_inc(&dev->counts[_DRM_STAT_OPENS]); - if (!dev->open_count++) + if (!dev->open_count++) { retcode = drm_setup(dev); + if (retcode) + dev->open_count--; + } } if (!retcode) { mutex_lock(&dev->struct_mutex); From 45820dcb6cfe07b7ebb6ae5a5688f06b83996478 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 5 Nov 2012 21:54:39 +0100 Subject: [PATCH 1416/2357] hwmon: (w83627ehf) Force initial bank selection commit 3300fb4f88688029fff8dfb9ec0734f6e4cba3e7 upstream. Don't assume bank 0 is selected at device probe time. This may not be the case. Force bank selection at first register access to guarantee that we read the right registers upon driver loading. Signed-off-by: Jean Delvare Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627ehf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 54922ed1297..88effda1919 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -2082,6 +2082,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) mutex_init(&data->lock); mutex_init(&data->update_lock); data->name = w83627ehf_device_names[sio_data->kind]; + data->bank = 0xff; /* Force initial bank selection */ platform_set_drvdata(pdev, data); /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ From 5fee99c200f8138f3eb1cd6b3d69b199b3d86686 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Nov 2012 12:39:51 +0100 Subject: [PATCH 1417/2357] ALSA: PCM: Fix some races at disconnection commit 9b0573c07f278e9888c352aa9724035c75784ea0 upstream. Fix races at PCM disconnection: - while a PCM device is being opened or closed - while the PCM state is being changed without lock in prepare, hw_params, hw_free ops Reported-by: Matthieu CASTET Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/pcm.c | 7 ++++++- sound/core/pcm_native.c | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 1a3070b4e5b..099f3fdd120 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1086,11 +1086,15 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) if (list_empty(&pcm->list)) goto unlock; + mutex_lock(&pcm->open_mutex); list_del_init(&pcm->list); for (cidx = 0; cidx < 2; cidx++) - for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) + for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { + snd_pcm_stream_lock_irq(substream); if (substream->runtime) substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; + snd_pcm_stream_unlock_irq(substream); + } list_for_each_entry(notify, &snd_pcm_notify_list, list) { notify->n_disconnect(pcm); } @@ -1106,6 +1110,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) } snd_unregister_device(devtype, pcm->card, pcm->device); } + mutex_unlock(&pcm->open_mutex); unlock: mutex_unlock(®ister_mutex); return 0; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 3fe99e644eb..608a2e18d6d 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -369,6 +369,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime) return usecs; } +static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state) +{ + snd_pcm_stream_lock_irq(substream); + if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED) + substream->runtime->status->state = state; + snd_pcm_stream_unlock_irq(substream); +} + static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -452,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, runtime->boundary *= 2; snd_pcm_timer_resolution_change(substream); - runtime->status->state = SNDRV_PCM_STATE_SETUP; + snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP); if (pm_qos_request_active(&substream->latency_pm_qos_req)) pm_qos_remove_request(&substream->latency_pm_qos_req); @@ -464,7 +472,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, /* hardware might be unusable from this time, so we force application to retry to set the correct hardware parameter settings */ - runtime->status->state = SNDRV_PCM_STATE_OPEN; + snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); if (substream->ops->hw_free != NULL) substream->ops->hw_free(substream); return err; @@ -512,7 +520,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) return -EBADFD; if (substream->ops->hw_free) result = substream->ops->hw_free(substream); - runtime->status->state = SNDRV_PCM_STATE_OPEN; + snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); pm_qos_remove_request(&substream->latency_pm_qos_req); return result; } @@ -1320,7 +1328,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) { struct snd_pcm_runtime *runtime = substream->runtime; runtime->control->appl_ptr = runtime->status->hw_ptr; - runtime->status->state = SNDRV_PCM_STATE_PREPARED; + snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED); } static struct action_ops snd_pcm_action_prepare = { From 799c92f2aecb348e4a4c6dab80c7206e48caf201 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Nov 2012 12:42:44 +0100 Subject: [PATCH 1418/2357] ALSA: usb-audio: Fix races at disconnection commit 978520b75f0a1ce82b17e1e8186417250de6d545 upstream. Close some races at disconnection of a USB audio device by adding the chip->shutdown_mutex and chip->shutdown check at appropriate places. The spots to put bandaids are: - PCM prepare, hw_params and hw_free - where the usb device is accessed for communication or get speed, in mixer.c and others; the device speed is now cached in subs->speed instead of accessing to chip->dev The accesses in PCM open and close don't need the mutex protection because these are already handled in the core PCM disconnection code. The autosuspend/autoresume codes are still uncovered by this patch because of possible mutex deadlocks. They'll be covered by the upcoming change to rwsem. Also the mixer codes are untouched, too. These will be fixed in another patch, too. Reported-by: Matthieu CASTET Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/card.h | 1 + sound/usb/endpoint.c | 9 ++++-- sound/usb/mixer.c | 65 +++++++++++++++++++++++++++++--------------- sound/usb/pcm.c | 31 ++++++++++++++++----- sound/usb/proc.c | 4 +-- 5 files changed, 76 insertions(+), 34 deletions(-) diff --git a/sound/usb/card.h b/sound/usb/card.h index da5fa1ac4ed..7932b2ac0de 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -87,6 +87,7 @@ struct snd_usb_substream { struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */ char *syncbuf; /* sync buffer for all sync URBs */ dma_addr_t sync_dma; /* DMA address of syncbuf */ + unsigned int speed; /* USB_SPEED_XXX */ u64 formats; /* format bitmasks (all or'ed) */ unsigned int num_formats; /* number of supported audio formats (list) */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 08dcce53720..24c511491b4 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -148,8 +148,10 @@ void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force) int i; /* stop urbs (to be sure) */ - deactivate_urbs(subs, force, 1); - wait_clear_urbs(subs); + if (!subs->stream->chip->shutdown) { + deactivate_urbs(subs, force, 1); + wait_clear_urbs(subs); + } for (i = 0; i < MAX_URBS; i++) release_urb_ctx(&subs->dataurb[i]); @@ -895,7 +897,8 @@ void snd_usb_init_substream(struct snd_usb_stream *as, subs->dev = as->chip->dev; subs->txfr_quirk = as->chip->txfr_quirk; subs->ops = audio_urb_ops[stream]; - if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH) + subs->speed = snd_usb_get_speed(subs->dev); + if (subs->speed >= USB_SPEED_HIGH) subs->ops.prepare_sync = prepare_capture_sync_urb_hs; snd_usb_set_pcm_ops(as->pcm, stream); diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 8a818a4573a..b3b63f76991 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -287,25 +287,32 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v unsigned char buf[2]; int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; int timeout = 10; - int err; + int idx = 0, err; err = snd_usb_autoresume(cval->mixer->chip); if (err < 0) return -EIO; + mutex_lock(&chip->shutdown_mutex); while (timeout-- > 0) { + if (chip->shutdown) + break; + idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), - buf, val_len) >= val_len) { + validx, idx, buf, val_len) >= val_len) { *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); - snd_usb_autosuspend(cval->mixer->chip); - return 0; + err = 0; + goto out; } } - snd_usb_autosuspend(cval->mixer->chip); snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", - request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); - return -EINVAL; + request, validx, idx, cval->val_type); + err = -EINVAL; + + out: + mutex_unlock(&chip->shutdown_mutex); + snd_usb_autosuspend(cval->mixer->chip); + return err; } static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) @@ -313,7 +320,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v struct snd_usb_audio *chip = cval->mixer->chip; unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ unsigned char *val; - int ret, size; + int idx = 0, ret, size; __u8 bRequest; if (request == UAC_GET_CUR) { @@ -330,16 +337,22 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v if (ret) goto error; - ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, + mutex_lock(&chip->shutdown_mutex); + if (chip->shutdown) + ret = -ENODEV; + else { + idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); + ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), - buf, size); + validx, idx, buf, size); + } + mutex_unlock(&chip->shutdown_mutex); snd_usb_autosuspend(chip); if (ret < 0) { error: snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", - request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); + request, validx, idx, cval->val_type); return ret; } @@ -417,7 +430,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, { struct snd_usb_audio *chip = cval->mixer->chip; unsigned char buf[2]; - int val_len, err, timeout = 10; + int idx = 0, val_len, err, timeout = 10; if (cval->mixer->protocol == UAC_VERSION_1) { val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; @@ -440,19 +453,27 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, err = snd_usb_autoresume(chip); if (err < 0) return -EIO; - while (timeout-- > 0) + mutex_lock(&chip->shutdown_mutex); + while (timeout-- > 0) { + if (chip->shutdown) + break; + idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); if (snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), - buf, val_len) >= 0) { - snd_usb_autosuspend(chip); - return 0; + validx, idx, buf, val_len) >= 0) { + err = 0; + goto out; } - snd_usb_autosuspend(chip); + } snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", - request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]); - return -EINVAL; + request, validx, idx, cval->val_type, buf[0], buf[1]); + err = -EINVAL; + + out: + mutex_unlock(&chip->shutdown_mutex); + snd_usb_autosuspend(chip); + return err; } static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 67a4d6dbb32..4f49ca75d6f 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -67,6 +67,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream unsigned int hwptr_done; subs = (struct snd_usb_substream *)substream->runtime->private_data; + if (subs->stream->chip->shutdown) + return SNDRV_PCM_POS_XRUN; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; substream->runtime->delay = snd_usb_pcm_delay(subs, @@ -373,8 +375,14 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, changed = subs->cur_audiofmt != fmt || subs->period_bytes != params_period_bytes(hw_params) || subs->cur_rate != rate; + + mutex_lock(&subs->stream->chip->shutdown_mutex); + if (subs->stream->chip->shutdown) { + ret = -ENODEV; + goto unlock; + } if ((ret = set_format(subs, fmt)) < 0) - return ret; + goto unlock; if (subs->cur_rate != rate) { struct usb_host_interface *alts; @@ -383,12 +391,11 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, alts = &iface->altsetting[fmt->altset_idx]; ret = snd_usb_init_sample_rate(subs->stream->chip, subs->interface, alts, fmt, rate); if (ret < 0) - return ret; + goto unlock; subs->cur_rate = rate; } if (changed) { - mutex_lock(&subs->stream->chip->shutdown_mutex); /* format changed */ snd_usb_release_substream_urbs(subs, 0); /* influenced: period_bytes, channels, rate, format, */ @@ -396,9 +403,10 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, params_rate(hw_params), snd_pcm_format_physical_width(params_format(hw_params)) * params_channels(hw_params)); - mutex_unlock(&subs->stream->chip->shutdown_mutex); } +unlock: + mutex_unlock(&subs->stream->chip->shutdown_mutex); return ret; } @@ -429,12 +437,18 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_usb_substream *subs = runtime->private_data; + int ret = 0; if (! subs->cur_audiofmt) { snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); return -ENXIO; } + mutex_lock(&subs->stream->chip->shutdown_mutex); + if (subs->stream->chip->shutdown) { + ret = -ENODEV; + goto unlock; + } /* some unit conversions in runtime */ subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); @@ -447,7 +461,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->last_frame_number = 0; runtime->delay = 0; - return snd_usb_substream_prepare(subs, runtime); + ret = snd_usb_substream_prepare(subs, runtime); + unlock: + mutex_unlock(&subs->stream->chip->shutdown_mutex); + return ret; } static struct snd_pcm_hardware snd_usb_hardware = @@ -500,7 +517,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, return 0; } /* check whether the period time is >= the data packet interval */ - if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { + if (subs->speed != USB_SPEED_FULL) { ptime = 125 * (1 << fp->datainterval); if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); @@ -778,7 +795,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre return err; param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; - if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) + if (subs->speed == USB_SPEED_FULL) /* full speed devices have fixed data packet interval */ ptmin = 1000; if (ptmin == 1000) diff --git a/sound/usb/proc.c b/sound/usb/proc.c index 961c9a25068..aef03db3870 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s } snd_iprintf(buffer, "\n"); } - if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) + if (subs->speed != USB_SPEED_FULL) snd_iprintf(buffer, " Data packet interval: %d us\n", 125 * (1 << fp->datainterval)); // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); @@ -128,7 +128,7 @@ static void proc_dump_substream_status(struct snd_usb_substream *subs, struct sn snd_iprintf(buffer, "]\n"); snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", - snd_usb_get_speed(subs->dev) == USB_SPEED_FULL + subs->speed == USB_SPEED_FULL ? get_full_speed_hz(subs->freqm) : get_high_speed_hz(subs->freqm), subs->freqm >> 16, subs->freqm & 0xffff); From 49e44e317fdb73d75a00a058df75a6b6fe172c08 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Nov 2012 12:42:45 +0100 Subject: [PATCH 1419/2357] ALSA: usb-audio: Use rwsem for disconnect protection commit 34f3c89fda4fba9fe689db22253ca8db2f5e6386 upstream. Replace mutex with rwsem for codec->shutdown protection so that concurrent accesses are allowed. Also add the protection to snd_usb_autosuspend() and snd_usb_autoresume(), too. Reported-by: Matthieu CASTET Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/card.c | 12 ++++++++---- sound/usb/mixer.c | 12 ++++++------ sound/usb/pcm.c | 12 ++++++------ sound/usb/usbaudio.h | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 4a7be7b9833..147a5c42b95 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -336,7 +336,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, return -ENOMEM; } - mutex_init(&chip->shutdown_mutex); + init_rwsem(&chip->shutdown_rwsem); chip->index = idx; chip->dev = dev; chip->card = card; @@ -556,7 +556,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, card = chip->card; mutex_lock(®ister_mutex); - mutex_lock(&chip->shutdown_mutex); + down_write(&chip->shutdown_rwsem); chip->shutdown = 1; chip->num_interfaces--; if (chip->num_interfaces <= 0) { @@ -574,11 +574,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, snd_usb_mixer_disconnect(p); } usb_chip[chip->index] = NULL; - mutex_unlock(&chip->shutdown_mutex); + up_write(&chip->shutdown_rwsem); mutex_unlock(®ister_mutex); snd_card_free_when_closed(card); } else { - mutex_unlock(&chip->shutdown_mutex); + up_write(&chip->shutdown_rwsem); mutex_unlock(®ister_mutex); } } @@ -610,16 +610,20 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) { int err = -ENODEV; + down_read(&chip->shutdown_rwsem); if (!chip->shutdown && !chip->probing) err = usb_autopm_get_interface(chip->pm_intf); + up_read(&chip->shutdown_rwsem); return err; } void snd_usb_autosuspend(struct snd_usb_audio *chip) { + down_read(&chip->shutdown_rwsem); if (!chip->shutdown && !chip->probing) usb_autopm_put_interface(chip->pm_intf); + up_read(&chip->shutdown_rwsem); } static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index b3b63f76991..29ae209344d 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -292,7 +292,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v err = snd_usb_autoresume(cval->mixer->chip); if (err < 0) return -EIO; - mutex_lock(&chip->shutdown_mutex); + down_read(&chip->shutdown_rwsem); while (timeout-- > 0) { if (chip->shutdown) break; @@ -310,7 +310,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v err = -EINVAL; out: - mutex_unlock(&chip->shutdown_mutex); + up_read(&chip->shutdown_rwsem); snd_usb_autosuspend(cval->mixer->chip); return err; } @@ -337,7 +337,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v if (ret) goto error; - mutex_lock(&chip->shutdown_mutex); + down_read(&chip->shutdown_rwsem); if (chip->shutdown) ret = -ENODEV; else { @@ -346,7 +346,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, buf, size); } - mutex_unlock(&chip->shutdown_mutex); + up_read(&chip->shutdown_rwsem); snd_usb_autosuspend(chip); if (ret < 0) { @@ -453,7 +453,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, err = snd_usb_autoresume(chip); if (err < 0) return -EIO; - mutex_lock(&chip->shutdown_mutex); + down_read(&chip->shutdown_rwsem); while (timeout-- > 0) { if (chip->shutdown) break; @@ -471,7 +471,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, err = -EINVAL; out: - mutex_unlock(&chip->shutdown_mutex); + up_read(&chip->shutdown_rwsem); snd_usb_autosuspend(chip); return err; } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 4f49ca75d6f..4a99f6ca4b6 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -376,7 +376,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, subs->period_bytes != params_period_bytes(hw_params) || subs->cur_rate != rate; - mutex_lock(&subs->stream->chip->shutdown_mutex); + down_read(&subs->stream->chip->shutdown_rwsem); if (subs->stream->chip->shutdown) { ret = -ENODEV; goto unlock; @@ -406,7 +406,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, } unlock: - mutex_unlock(&subs->stream->chip->shutdown_mutex); + up_read(&subs->stream->chip->shutdown_rwsem); return ret; } @@ -422,9 +422,9 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->cur_audiofmt = NULL; subs->cur_rate = 0; subs->period_bytes = 0; - mutex_lock(&subs->stream->chip->shutdown_mutex); + down_read(&subs->stream->chip->shutdown_rwsem); snd_usb_release_substream_urbs(subs, 0); - mutex_unlock(&subs->stream->chip->shutdown_mutex); + up_read(&subs->stream->chip->shutdown_rwsem); return snd_pcm_lib_free_vmalloc_buffer(substream); } @@ -444,7 +444,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) return -ENXIO; } - mutex_lock(&subs->stream->chip->shutdown_mutex); + down_read(&subs->stream->chip->shutdown_rwsem); if (subs->stream->chip->shutdown) { ret = -ENODEV; goto unlock; @@ -463,7 +463,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) ret = snd_usb_substream_prepare(subs, runtime); unlock: - mutex_unlock(&subs->stream->chip->shutdown_mutex); + up_read(&subs->stream->chip->shutdown_rwsem); return ret; } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 3e2b0357793..6c805a51d7d 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -36,7 +36,7 @@ struct snd_usb_audio { struct snd_card *card; struct usb_interface *pm_intf; u32 usb_id; - struct mutex shutdown_mutex; + struct rw_semaphore shutdown_rwsem; unsigned int shutdown:1; unsigned int probing:1; unsigned int autosuspended:1; From 1c694ffc72666085a5ad880fef913ee2c8c69c4a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Nov 2012 12:42:46 +0100 Subject: [PATCH 1420/2357] ALSA: usb-audio: Fix races at disconnection in mixer_quirks.c commit 888ea7d5ac6815ba16b3b3a20f665a92c7af6724 upstream. Similar like the previous commit, cover with chip->shutdown_rwsem and chip->shutdown checks. Reported-by: Matthieu CASTET Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/mixer_quirks.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index ab125ee0b0f..38a607a7ae2 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -186,6 +186,11 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e if (value > 1) return -EINVAL; changed = value != mixer->audigy2nx_leds[index]; + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) { + err = -ENODEV; + goto out; + } if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, @@ -202,6 +207,8 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, value, index + 2, NULL, 0); + out: + up_read(&mixer->chip->shutdown_rwsem); if (err < 0) return err; mixer->audigy2nx_leds[index] = value; @@ -295,11 +302,16 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, for (i = 0; jacks[i].name; ++i) { snd_iprintf(buffer, "%s: ", jacks[i].name); - err = snd_usb_ctl_msg(mixer->chip->dev, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + err = 0; + else + err = snd_usb_ctl_msg(mixer->chip->dev, usb_rcvctrlpipe(mixer->chip->dev, 0), UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, jacks[i].unitid << 8, buf, 3); + up_read(&mixer->chip->shutdown_rwsem); if (err == 3 && (buf[0] == 3 || buf[0] == 6)) snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); else @@ -329,10 +341,15 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, else new_status = old_status & ~0x02; changed = new_status != old_status; - err = snd_usb_ctl_msg(mixer->chip->dev, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + err = -ENODEV; + else + err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 50, 0, &new_status, 1); + up_read(&mixer->chip->shutdown_rwsem); if (err < 0) return err; mixer->xonar_u1_status = new_status; @@ -371,11 +388,17 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, u8 bRequest = (kcontrol->private_value >> 16) & 0xff; u16 wIndex = kcontrol->private_value & 0xffff; u8 tmp; + int ret; - int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + ret = -ENODEV; + else + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0, cpu_to_le16(wIndex), &tmp, sizeof(tmp), 1000); + up_read(&mixer->chip->shutdown_rwsem); if (ret < 0) { snd_printk(KERN_ERR @@ -396,11 +419,17 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, u8 bRequest = (kcontrol->private_value >> 16) & 0xff; u16 wIndex = kcontrol->private_value & 0xffff; u16 wValue = ucontrol->value.integer.value[0]; + int ret; - int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + ret = -ENODEV; + else + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, cpu_to_le16(wValue), cpu_to_le16(wIndex), NULL, 0, 1000); + up_read(&mixer->chip->shutdown_rwsem); if (ret < 0) { snd_printk(KERN_ERR From 41a496238dae4c117548be819b0a3b3edbc48dc8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Nov 2012 12:42:47 +0100 Subject: [PATCH 1421/2357] ALSA: Add a reference counter to card instance commit a0830dbd4e42b38aefdf3fb61ba5019a1a99ea85 upstream. For more strict protection for wild disconnections, a refcount is introduced to the card instance, and let it up/down when an object is referred via snd_lookup_*() in the open ops. The free-after-last-close check is also changed to check this refcount instead of the empty list, too. Reported-by: Matthieu CASTET Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/sound/core.h | 3 +++ sound/core/compress_offload.c | 9 +++++-- sound/core/control.c | 3 +++ sound/core/hwdep.c | 5 +++- sound/core/init.c | 50 +++++++++++++++++++++-------------- sound/core/oss/mixer_oss.c | 10 +++++-- sound/core/oss/pcm_oss.c | 2 ++ sound/core/pcm_native.c | 9 +++++-- sound/core/rawmidi.c | 6 ++++- sound/core/sound.c | 11 ++++++-- sound/core/sound_oss.c | 10 +++++-- 11 files changed, 86 insertions(+), 32 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index bc056687f64..93896ad1fcd 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -132,6 +132,7 @@ struct snd_card { int shutdown; /* this card is going down */ int free_on_last_close; /* free in context of file_release */ wait_queue_head_t shutdown_sleep; + atomic_t refcount; /* refcount for disconnection */ struct device *dev; /* device assigned to this card */ struct device *card_dev; /* cardX object for sysfs */ @@ -189,6 +190,7 @@ struct snd_minor { const struct file_operations *f_ops; /* file operations */ void *private_data; /* private data for f_ops->open */ struct device *dev; /* device for sysfs */ + struct snd_card *card_ptr; /* assigned card instance */ }; /* return a device pointer linked to each sound device as a parent */ @@ -295,6 +297,7 @@ int snd_card_info_done(void); int snd_component_add(struct snd_card *card, const char *component); int snd_card_file_add(struct snd_card *card, struct file *file); int snd_card_file_remove(struct snd_card *card, struct file *file); +void snd_card_unref(struct snd_card *card); #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr)) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index a68aed7fce0..a58cf359413 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -102,12 +102,15 @@ static int snd_compr_open(struct inode *inode, struct file *f) if (dirn != compr->direction) { pr_err("this device doesn't support this direction\n"); + snd_card_unref(compr->card); return -EINVAL; } data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) + if (!data) { + snd_card_unref(compr->card); return -ENOMEM; + } data->stream.ops = compr->ops; data->stream.direction = dirn; data->stream.private_data = compr->private_data; @@ -115,6 +118,7 @@ static int snd_compr_open(struct inode *inode, struct file *f) runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); if (!runtime) { kfree(data); + snd_card_unref(compr->card); return -ENOMEM; } runtime->state = SNDRV_PCM_STATE_OPEN; @@ -128,7 +132,8 @@ static int snd_compr_open(struct inode *inode, struct file *f) kfree(runtime); kfree(data); } - return ret; + snd_card_unref(compr->card); + return 0; } static int snd_compr_free(struct inode *inode, struct file *f) diff --git a/sound/core/control.c b/sound/core/control.c index 2487a6bb1c5..151597b431a 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -86,6 +86,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) write_lock_irqsave(&card->ctl_files_rwlock, flags); list_add_tail(&ctl->list, &card->ctl_files); write_unlock_irqrestore(&card->ctl_files_rwlock, flags); + snd_card_unref(card); return 0; __error: @@ -93,6 +94,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file) __error2: snd_card_file_remove(card, file); __error1: + if (card) + snd_card_unref(card); return err; } diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 75ea16f35b1..53a6ba5ad61 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -100,8 +100,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) if (hw == NULL) return -ENODEV; - if (!try_module_get(hw->card->module)) + if (!try_module_get(hw->card->module)) { + snd_card_unref(hw->card); return -EFAULT; + } init_waitqueue_entry(&wait, current); add_wait_queue(&hw->open_wait, &wait); @@ -148,6 +150,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) mutex_unlock(&hw->open_mutex); if (err < 0) module_put(hw->card->module); + snd_card_unref(hw->card); return err; } diff --git a/sound/core/init.c b/sound/core/init.c index d8ec849af12..7b012d15c2c 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -213,6 +213,7 @@ int snd_card_create(int idx, const char *xid, spin_lock_init(&card->files_lock); INIT_LIST_HEAD(&card->files_list); init_waitqueue_head(&card->shutdown_sleep); + atomic_set(&card->refcount, 0); #ifdef CONFIG_PM mutex_init(&card->power_lock); init_waitqueue_head(&card->power_sleep); @@ -446,21 +447,36 @@ static int snd_card_do_free(struct snd_card *card) return 0; } +/** + * snd_card_unref - release the reference counter + * @card: the card instance + * + * Decrements the reference counter. When it reaches to zero, wake up + * the sleeper and call the destructor if needed. + */ +void snd_card_unref(struct snd_card *card) +{ + if (atomic_dec_and_test(&card->refcount)) { + wake_up(&card->shutdown_sleep); + if (card->free_on_last_close) + snd_card_do_free(card); + } +} +EXPORT_SYMBOL(snd_card_unref); + int snd_card_free_when_closed(struct snd_card *card) { - int free_now = 0; - int ret = snd_card_disconnect(card); - if (ret) - return ret; + int ret; - spin_lock(&card->files_lock); - if (list_empty(&card->files_list)) - free_now = 1; - else - card->free_on_last_close = 1; - spin_unlock(&card->files_lock); + atomic_inc(&card->refcount); + ret = snd_card_disconnect(card); + if (ret) { + atomic_dec(&card->refcount); + return ret; + } - if (free_now) + card->free_on_last_close = 1; + if (atomic_dec_and_test(&card->refcount)) snd_card_do_free(card); return 0; } @@ -474,7 +490,7 @@ int snd_card_free(struct snd_card *card) return ret; /* wait, until all devices are ready for the free operation */ - wait_event(card->shutdown_sleep, list_empty(&card->files_list)); + wait_event(card->shutdown_sleep, !atomic_read(&card->refcount)); snd_card_do_free(card); return 0; } @@ -886,6 +902,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file) return -ENODEV; } list_add(&mfile->list, &card->files_list); + atomic_inc(&card->refcount); spin_unlock(&card->files_lock); return 0; } @@ -908,7 +925,6 @@ EXPORT_SYMBOL(snd_card_file_add); int snd_card_file_remove(struct snd_card *card, struct file *file) { struct snd_monitor_file *mfile, *found = NULL; - int last_close = 0; spin_lock(&card->files_lock); list_for_each_entry(mfile, &card->files_list, list) { @@ -923,19 +939,13 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) break; } } - if (list_empty(&card->files_list)) - last_close = 1; spin_unlock(&card->files_lock); - if (last_close) { - wake_up(&card->shutdown_sleep); - if (card->free_on_last_close) - snd_card_do_free(card); - } if (!found) { snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); return -ENOENT; } kfree(found); + snd_card_unref(card); return 0; } diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 18297f7f2c5..05395aaeaa3 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -52,14 +52,19 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) SNDRV_OSS_DEVICE_TYPE_MIXER); if (card == NULL) return -ENODEV; - if (card->mixer_oss == NULL) + if (card->mixer_oss == NULL) { + snd_card_unref(card); return -ENODEV; + } err = snd_card_file_add(card, file); - if (err < 0) + if (err < 0) { + snd_card_unref(card); return err; + } fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL); if (fmixer == NULL) { snd_card_file_remove(card, file); + snd_card_unref(card); return -ENOMEM; } fmixer->card = card; @@ -68,6 +73,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) if (!try_module_get(card->module)) { kfree(fmixer); snd_card_file_remove(card, file); + snd_card_unref(card); return -EFAULT; } return 0; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 08fde0060fd..2529e01538e 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2457,6 +2457,8 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) __error2: snd_card_file_remove(pcm->card, file); __error1: + if (pcm) + snd_card_unref(pcm->card); return err; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 608a2e18d6d..98e7591de6e 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1631,6 +1631,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); _nolock: + snd_card_unref(substream1->pcm->card); fput(file); if (res < 0) kfree(group); @@ -2105,7 +2106,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file) return err; pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_PLAYBACK); - return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); + err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); + snd_card_unref(pcm->card); + return err; } static int snd_pcm_capture_open(struct inode *inode, struct file *file) @@ -2116,7 +2119,9 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file) return err; pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_CAPTURE); - return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); + err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); + snd_card_unref(pcm->card); + return err; } static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index ebf6e49ad3d..7d4f62ab671 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -379,8 +379,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) if (rmidi == NULL) return -ENODEV; - if (!try_module_get(rmidi->card->module)) + if (!try_module_get(rmidi->card->module)) { + snd_card_unref(rmidi->card); return -ENXIO; + } mutex_lock(&rmidi->open_mutex); card = rmidi->card; @@ -440,6 +442,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) #endif file->private_data = rawmidi_file; mutex_unlock(&rmidi->open_mutex); + snd_card_unref(rmidi->card); return 0; __error: @@ -447,6 +450,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) __error_card: mutex_unlock(&rmidi->open_mutex); module_put(rmidi->card->module); + snd_card_unref(rmidi->card); return err; } diff --git a/sound/core/sound.c b/sound/core/sound.c index 28f35593a75..7c0640eeee5 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -99,6 +99,10 @@ static void snd_request_other(int minor) * * Checks that a minor device with the specified type is registered, and returns * its user data pointer. + * + * This function increments the reference counter of the card instance + * if an associated instance with the given minor number and type is found. + * The caller must call snd_card_unref() appropriately later. */ void *snd_lookup_minor_data(unsigned int minor, int type) { @@ -109,9 +113,11 @@ void *snd_lookup_minor_data(unsigned int minor, int type) return NULL; mutex_lock(&sound_mutex); mreg = snd_minors[minor]; - if (mreg && mreg->type == type) + if (mreg && mreg->type == type) { private_data = mreg->private_data; - else + if (mreg->card_ptr) + atomic_inc(&mreg->card_ptr->refcount); + } else private_data = NULL; mutex_unlock(&sound_mutex); return private_data; @@ -276,6 +282,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev, preg->device = dev; preg->f_ops = f_ops; preg->private_data = private_data; + preg->card_ptr = card; mutex_lock(&sound_mutex); #ifdef CONFIG_SND_DYNAMIC_MINORS minor = snd_find_free_minor(type); diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index c7009204306..7442c7ac246 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -40,6 +40,9 @@ static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS]; static DEFINE_MUTEX(sound_oss_mutex); +/* NOTE: This function increments the refcount of the associated card like + * snd_lookup_minor_data(); the caller must call snd_card_unref() appropriately + */ void *snd_lookup_oss_minor_data(unsigned int minor, int type) { struct snd_minor *mreg; @@ -49,9 +52,11 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) return NULL; mutex_lock(&sound_oss_mutex); mreg = snd_oss_minors[minor]; - if (mreg && mreg->type == type) + if (mreg && mreg->type == type) { private_data = mreg->private_data; - else + if (mreg->card_ptr) + atomic_inc(&mreg->card_ptr->refcount); + } else private_data = NULL; mutex_unlock(&sound_oss_mutex); return private_data; @@ -123,6 +128,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, preg->device = dev; preg->f_ops = f_ops; preg->private_data = private_data; + preg->card_ptr = card; mutex_lock(&sound_oss_mutex); snd_oss_minors[minor] = preg; minor_unit = SNDRV_MINOR_OSS_DEVICE(minor); From 9de4f2694044af68a826a568f0c97b1b83b5b173 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Nov 2012 12:42:48 +0100 Subject: [PATCH 1422/2357] ALSA: Avoid endless sleep after disconnect commit 0914f7961babbf28aaa2f19b453951fb4841c03f upstream. When disconnect callback is called, each component should wake up sleepers and check card->shutdown flag for avoiding the endless sleep blocking the proper resource release. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/control.c | 2 ++ sound/core/hwdep.c | 7 +++++++ sound/core/oss/pcm_oss.c | 4 ++++ sound/core/pcm.c | 6 +++++- sound/core/pcm_native.c | 8 ++++++++ sound/core/rawmidi.c | 20 ++++++++++++++++++++ 6 files changed, 46 insertions(+), 1 deletion(-) diff --git a/sound/core/control.c b/sound/core/control.c index 151597b431a..daa4fc8872f 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1436,6 +1436,8 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, spin_unlock_irq(&ctl->read_lock); schedule(); remove_wait_queue(&ctl->change_sleep, &wait); + if (ctl->card->shutdown) + return -ENODEV; if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irq(&ctl->read_lock); diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 53a6ba5ad61..3f7f6628cf7 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -131,6 +131,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) mutex_unlock(&hw->open_mutex); schedule(); mutex_lock(&hw->open_mutex); + if (hw->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; @@ -462,12 +466,15 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) mutex_unlock(®ister_mutex); return -EINVAL; } + mutex_lock(&hwdep->open_mutex); + wake_up(&hwdep->open_wait); #ifdef CONFIG_SND_OSSEMUL if (hwdep->ossreg) snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); #endif snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); list_del_init(&hwdep->list); + mutex_unlock(&hwdep->open_mutex); mutex_unlock(®ister_mutex); return 0; } diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 2529e01538e..f337b66a020 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2441,6 +2441,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) mutex_unlock(&pcm->open_mutex); schedule(); mutex_lock(&pcm->open_mutex); + if (pcm->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 099f3fdd120..e30e1be30a2 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1087,12 +1087,16 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) goto unlock; mutex_lock(&pcm->open_mutex); + wake_up(&pcm->open_wait); list_del_init(&pcm->list); for (cidx = 0; cidx < 2; cidx++) for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { snd_pcm_stream_lock_irq(substream); - if (substream->runtime) + if (substream->runtime) { substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; + wake_up(&substream->runtime->sleep); + wake_up(&substream->runtime->tsleep); + } snd_pcm_stream_unlock_irq(substream); } list_for_each_entry(notify, &snd_pcm_notify_list, list) { diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 98e7591de6e..0844444eb10 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1508,6 +1508,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, down_read(&snd_pcm_link_rwsem); snd_pcm_stream_lock_irq(substream); remove_wait_queue(&to_check->sleep, &wait); + if (card->shutdown) { + result = -ENODEV; + break; + } if (tout == 0) { if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) result = -ESTRPIPE; @@ -2158,6 +2162,10 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) mutex_unlock(&pcm->open_mutex); schedule(); mutex_lock(&pcm->open_mutex); + if (pcm->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 7d4f62ab671..1bb95aeea08 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -424,6 +424,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) mutex_unlock(&rmidi->open_mutex); schedule(); mutex_lock(&rmidi->open_mutex); + if (rmidi->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; @@ -995,6 +999,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun spin_unlock_irq(&runtime->lock); schedule(); remove_wait_queue(&runtime->sleep, &wait); + if (rfile->rmidi->card->shutdown) + return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail) @@ -1238,6 +1244,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, spin_unlock_irq(&runtime->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); + if (rfile->rmidi->card->shutdown) + return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail && !timeout) @@ -1613,9 +1621,20 @@ static int snd_rawmidi_dev_register(struct snd_device *device) static int snd_rawmidi_dev_disconnect(struct snd_device *device) { struct snd_rawmidi *rmidi = device->device_data; + int dir; mutex_lock(®ister_mutex); + mutex_lock(&rmidi->open_mutex); + wake_up(&rmidi->open_wait); list_del_init(&rmidi->list); + for (dir = 0; dir < 2; dir++) { + struct snd_rawmidi_substream *s; + list_for_each_entry(s, &rmidi->streams[dir].substreams, list) { + if (s->runtime) + wake_up(&s->runtime->sleep); + } + } + #ifdef CONFIG_SND_OSSEMUL if (rmidi->ossreg) { if ((int)rmidi->device == midi_map[rmidi->card->number]) { @@ -1630,6 +1649,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) } #endif /* CONFIG_SND_OSSEMUL */ snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); + mutex_unlock(&rmidi->open_mutex); mutex_unlock(®ister_mutex); return 0; } From c2f5b7507ac5d808f29287d77ee6148358d7fbfe Mon Sep 17 00:00:00 2001 From: Zijie Pan Date: Mon, 15 Oct 2012 03:56:39 +0000 Subject: [PATCH 1423/2357] sctp: fix call to SCTP_CMD_PROCESS_SACK in sctp_cmd_interpreter() [ Upstream commit f6e80abeab928b7c47cc1fbf53df13b4398a2bec ] Bug introduced by commit edfee0339e681a784ebacec7e8c2dc97dc6d2839 (sctp: check src addr when processing SACK to update transport state) Signed-off-by: Zijie Pan Signed-off-by: Nicolas Dichtel Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/sm_sideeffect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 1ff51c9d18d..2fdb05d8aac 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1610,8 +1610,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, asoc->outqueue.outstanding_bytes; sackh.num_gap_ack_blocks = 0; sackh.num_dup_tsns = 0; + chunk->subh.sack_hdr = &sackh; sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, - SCTP_SACKH(&sackh)); + SCTP_CHUNK(chunk)); break; case SCTP_CMD_DISCARD_PACKET: From 0f04b9af7ce98a3db1c4401cced1fef321a9dd57 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 18 Oct 2012 03:21:55 +0000 Subject: [PATCH 1424/2357] netlink: use kfree_rcu() in netlink_release() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 6d772ac5578f711d1ce7b03535d1c95bffb21dff ] On some suspend/resume operations involving wimax device, we have noticed some intermittent memory corruptions in netlink code. Stéphane Marchesin tracked this corruption in netlink_update_listeners() and suggested a patch. It appears netlink_release() should use kfree_rcu() instead of kfree() for the listeners structure as it may be used by other cpus using RCU protection. netlink_release() must set to NULL the listeners pointer when it is about to be freed. Also have to protect netlink_update_listeners() and netlink_has_listeners() if listeners is NULL. Add a nl_deref_protected() lockdep helper to properly document which locks protects us. Reported-by: Jonathan Kliegman Signed-off-by: Eric Dumazet Cc: Stéphane Marchesin Cc: Sam Leffler Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/af_netlink.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index edce424048d..9017e3ef8fe 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -137,6 +137,8 @@ static void netlink_destroy_callback(struct netlink_callback *cb); static DEFINE_RWLOCK(nl_table_lock); static atomic_t nl_table_users = ATOMIC_INIT(0); +#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock)); + static ATOMIC_NOTIFIER_HEAD(netlink_chain); static inline u32 netlink_group_mask(u32 group) @@ -332,6 +334,11 @@ netlink_update_listeners(struct sock *sk) struct hlist_node *node; unsigned long mask; unsigned int i; + struct listeners *listeners; + + listeners = nl_deref_protected(tbl->listeners); + if (!listeners) + return; for (i = 0; i < NLGRPLONGS(tbl->groups); i++) { mask = 0; @@ -339,7 +346,7 @@ netlink_update_listeners(struct sock *sk) if (i < NLGRPLONGS(nlk_sk(sk)->ngroups)) mask |= nlk_sk(sk)->groups[i]; } - tbl->listeners->masks[i] = mask; + listeners->masks[i] = mask; } /* this function is only called with the netlink table "grabbed", which * makes sure updates are visible before bind or setsockopt return. */ @@ -520,7 +527,11 @@ static int netlink_release(struct socket *sock) if (netlink_is_kernel(sk)) { BUG_ON(nl_table[sk->sk_protocol].registered == 0); if (--nl_table[sk->sk_protocol].registered == 0) { - kfree(nl_table[sk->sk_protocol].listeners); + struct listeners *old; + + old = nl_deref_protected(nl_table[sk->sk_protocol].listeners); + RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL); + kfree_rcu(old, rcu); nl_table[sk->sk_protocol].module = NULL; nl_table[sk->sk_protocol].registered = 0; } @@ -950,7 +961,7 @@ int netlink_has_listeners(struct sock *sk, unsigned int group) rcu_read_lock(); listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); - if (group - 1 < nl_table[sk->sk_protocol].groups) + if (listeners && group - 1 < nl_table[sk->sk_protocol].groups) res = test_bit(group - 1, listeners->masks); rcu_read_unlock(); @@ -1582,7 +1593,7 @@ int __netlink_change_ngroups(struct sock *sk, unsigned int groups) new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC); if (!new) return -ENOMEM; - old = rcu_dereference_protected(tbl->listeners, 1); + old = nl_deref_protected(tbl->listeners); memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups)); rcu_assign_pointer(tbl->listeners, new); From d1a94e022b36342cbdb156a9693bca95aab11ca4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 18 Oct 2012 09:14:12 +0000 Subject: [PATCH 1425/2357] tcp: fix FIONREAD/SIOCINQ [ Upstream commit a3374c42aa5f7237e87ff3b0622018636b0c847e ] tcp_ioctl() tries to take into account if tcp socket received a FIN to report correct number bytes in receive queue. But its flaky because if the application ate the last skb, we return 1 instead of 0. Correct way to detect that FIN was received is to test SOCK_DONE. Reported-by: Elliot Hughes Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Tom Herbert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8fbe2e20e7c..01870bd2919 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -481,14 +481,12 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) !tp->urg_data || before(tp->urg_seq, tp->copied_seq) || !before(tp->urg_seq, tp->rcv_nxt)) { - struct sk_buff *skb; answ = tp->rcv_nxt - tp->copied_seq; - /* Subtract 1, if FIN is in queue. */ - skb = skb_peek_tail(&sk->sk_receive_queue); - if (answ && skb) - answ -= tcp_hdr(skb)->fin; + /* Subtract 1, if FIN was received */ + if (answ && sock_flag(sk, SOCK_DONE)) + answ--; } else answ = tp->urg_seq - tp->copied_seq; release_sock(sk); From d707b52912bfa83176b75efd40da193c18eef1e0 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Wed, 24 Oct 2012 14:01:18 +0800 Subject: [PATCH 1426/2357] ipv6: Set default hoplimit as zero. [ Upstream commit 14edd87dc67311556f1254a8f29cf4dd6cb5b7d1 ] Commit a02e4b7dae4551(Demark default hoplimit as zero) only changes the hoplimit checking condition and default value in ip6_dst_hoplimit, not zeros all hoplimit default value. Keep the zeroing ip6_template_metrics[RTAX_HOPLIMIT - 1] to force it as const, cause as a37e6e344910(net: force dst_default_metrics to const section) Signed-off-by: Li RongQing Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 2796b374cb2..b84cba19550 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -203,7 +203,7 @@ static struct dst_ops ip6_dst_blackhole_ops = { }; static const u32 ip6_template_metrics[RTAX_MAX] = { - [RTAX_HOPLIMIT - 1] = 255, + [RTAX_HOPLIMIT - 1] = 0, }; static struct rt6_info ip6_null_entry_template = { @@ -1135,7 +1135,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, rt->rt6i_dst.addr = fl6->daddr; rt->rt6i_dst.plen = 128; rt->rt6i_idev = idev; - dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); + dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0); spin_lock_bh(&icmp6_dst_lock); rt->dst.next = icmp6_dst_gc_list; From 545bc464cb07b204fbfb387a7010f31352e03625 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 25 Oct 2012 18:17:54 +0000 Subject: [PATCH 1427/2357] net: usb: Fix memory leak on Tx data path [ Upstream commit 39707c2a3ba5011038b363f84d37c8a98d2d9db1 ] Driver anchors the tx urbs and defers the urb submission if a transmit request comes when the interface is suspended. Anchoring urb increments the urb reference count. These deferred urbs are later accessed by calling usb_get_from_anchor() for submission during interface resume. usb_get_from_anchor() unanchors the urb but urb reference count remains same. This causes the urb reference count to remain non-zero after usb_free_urb() gets called and urb never gets freed. Hence call usb_put_urb() after anchoring the urb to properly balance the reference count for these deferred urbs. Also, unanchor these deferred urbs during disconnect, to free them up. Signed-off-by: Hemant Kumar Acked-by: Oliver Neukum Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/usbnet.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index b38db48b1ce..174aece3b90 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1158,6 +1158,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, usb_anchor_urb(urb, &dev->deferred); /* no use to process more packets */ netif_stop_queue(net); + usb_put_urb(urb); spin_unlock_irqrestore(&dev->txq.lock, flags); netdev_dbg(dev->net, "Delaying transmission for resumption\n"); goto deferred; @@ -1299,6 +1300,8 @@ void usbnet_disconnect (struct usb_interface *intf) cancel_work_sync(&dev->kevent); + usb_scuttle_anchored_urbs(&dev->deferred); + if (dev->driver_info->unbind) dev->driver_info->unbind (dev, intf); From b97ecda6f44e089c4a25be7aaa44b3337c860d56 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Wed, 31 Oct 2012 02:45:32 +0000 Subject: [PATCH 1428/2357] net: fix divide by zero in tcp algorithm illinois [ Upstream commit 8f363b77ee4fbf7c3bbcf5ec2c5ca482d396d664 ] Reading TCP stats when using TCP Illinois congestion control algorithm can cause a divide by zero kernel oops. The division by zero occur in tcp_illinois_info() at: do_div(t, ca->cnt_rtt); where ca->cnt_rtt can become zero (when rtt_reset is called) Steps to Reproduce: 1. Register tcp_illinois: # sysctl -w net.ipv4.tcp_congestion_control=illinois 2. Monitor internal TCP information via command "ss -i" # watch -d ss -i 3. Establish new TCP conn to machine Either it fails at the initial conn, or else it needs to wait for a loss or a reset. This is only related to reading stats. The function avg_delay() also performs the same divide, but is guarded with a (ca->cnt_rtt > 0) at its calling point in update_params(). Thus, simply fix tcp_illinois_info(). Function tcp_illinois_info() / get_info() is called without socket lock. Thus, eliminate any race condition on ca->cnt_rtt by using a local stack variable. Simply reuse info.tcpv_rttcnt, as its already set to ca->cnt_rtt. Function avg_delay() is not affected by this race condition, as its called with the socket lock. Cc: Petr Matousek Signed-off-by: Jesper Dangaard Brouer Acked-by: Eric Dumazet Acked-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_illinois.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 813b43a76fe..834857f3c87 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -313,11 +313,13 @@ static void tcp_illinois_info(struct sock *sk, u32 ext, .tcpv_rttcnt = ca->cnt_rtt, .tcpv_minrtt = ca->base_rtt, }; - u64 t = ca->sum_rtt; - do_div(t, ca->cnt_rtt); - info.tcpv_rtt = t; + if (info.tcpv_rttcnt > 0) { + u64 t = ca->sum_rtt; + do_div(t, info.tcpv_rttcnt); + info.tcpv_rtt = t; + } nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); } } From 808235fefa3de34ff292cc86b0edfad17a6f056e Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Sun, 28 Oct 2012 06:12:00 +0000 Subject: [PATCH 1429/2357] drivers/net/ethernet/nxp/lpc_eth.c: Call mdiobus_unregister before mdiobus_free [ Upstream commit 57c10b61c84bfed68b1b317d6f507a392724b9c4 ] Based on commit b27393aecf66199f5ddad37c302d3e0cfadbe6c0 Calling mdiobus_free without calling mdiobus_unregister causes BUG_ON(). This patch fixes the issue. The semantic patch that found this issue(http://coccinelle.lip6.fr/): // @@ expression E; @@ ... when != mdiobus_unregister(E); + mdiobus_unregister(E); mdiobus_free(E); // Signed-off-by: Peter Senna Tschudin Tested-by: Roland Stigge Tested-by: Alexandre Pereira da Silva Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/nxp/lpc_eth.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 0c5edc17a1e..077bb00cbac 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1523,6 +1523,7 @@ static int lpc_eth_drv_remove(struct platform_device *pdev) pldat->dma_buff_base_p); free_irq(ndev->irq, ndev); iounmap(pldat->net_base); + mdiobus_unregister(pldat->mii_bus); mdiobus_free(pldat->mii_bus); clk_disable(pldat->clk); clk_put(pldat->clk); From 988aaa6d344cdd838db420919dc26b3c0248e65a Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Mon, 29 Oct 2012 23:41:48 +0000 Subject: [PATCH 1430/2357] l2tp: fix oops in l2tp_eth_create() error path [ Upstream commit 789336360e0a2aeb9750c16ab704a02cbe035e9e ] When creating an L2TPv3 Ethernet session, if register_netdev() should fail for any reason (for example, automatic naming for "l2tpeth%d" interfaces hits the 32k-interface limit), the netdev is freed in the error path. However, the l2tp_eth_sess structure's dev pointer is left uncleared, and this results in l2tp_eth_delete() then attempting to unregister the same netdev later in the session teardown. This results in an oops. To avoid this, clear the session dev pointer in the error path. Signed-off-by: Tom Parkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_eth.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 5c829077b25..ab9a293ad03 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -269,6 +269,7 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p out_del_dev: free_netdev(dev); + spriv->dev = NULL; out_del_session: l2tp_session_delete(session); out: From ecdebbf0aedbedc96ee784046d06d0be8152d5a4 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 3 Nov 2012 09:30:34 +0000 Subject: [PATCH 1431/2357] net: inet_diag -- Return error code if protocol handler is missed [ Upstream commit cacb6ba0f36ab14a507f4ee7697e8332899015d2 ] We've observed that in case if UDP diag module is not supported in kernel the netlink returns NLMSG_DONE without notifying a caller that handler is missed. This patch makes __inet_diag_dump to return error code instead. So as example it become possible to detect such situation and handle it gracefully on userspace level. Signed-off-by: Cyrill Gorcunov CC: David Miller CC: Eric Dumazet CC: Pavel Emelyanov Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/inet_diag.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 8f8db724bfa..dda5383a6f0 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -875,13 +875,16 @@ static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, struct inet_diag_req_v2 *r, struct nlattr *bc) { const struct inet_diag_handler *handler; + int err = 0; handler = inet_diag_lock_handler(r->sdiag_protocol); if (!IS_ERR(handler)) handler->dump(skb, cb, r, bc); + else + err = PTR_ERR(handler); inet_diag_unlock_handler(handler); - return skb->len; + return err ? : skb->len; } static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) From 0f2835b0b762391fb8e1d1da3bdb8f1d90a5d53e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 6 Nov 2012 02:10:10 +0000 Subject: [PATCH 1432/2357] af-packet: fix oops when socket is not present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a3d744e995d2b936c500585ae39d99ee251c89b4 ] Due to a NULL dereference, the following patch is causing oops in normal trafic condition: commit c0de08d04215031d68fa13af36f347a6cfa252ca Author: Eric Leblond Date:   Thu Aug 16 22:02:58 2012 +0000     af_packet: don't emit packet on orig fanout group This buggy patch was a feature fix and has reached most stable branches. When skb->sk is NULL and when packet fanout is used, there is a crash in match_fanout_group where skb->sk is accessed. This patch fixes the issue by returning false as soon as the socket is NULL: this correspond to the wanted behavior because the kernel as to resend the skb to all the listening socket in this case. Signed-off-by: Eric Leblond Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 82ca51bc29e..24a21f36a47 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1643,7 +1643,7 @@ static inline int deliver_skb(struct sk_buff *skb, static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb) { - if (ptype->af_packet_priv == NULL) + if (!ptype->af_packet_priv || !skb->sk) return false; if (ptype->id_match) From f0d6767af2ece14b24064258dffbc816c4258ae5 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Tue, 6 Nov 2012 16:18:41 +0000 Subject: [PATCH 1433/2357] ipv6: send unsolicited neighbour advertisements to all-nodes [ Upstream commit 60713a0ca7fd6651b951cc1b4dbd528d1fc0281b ] As documented in RFC4861 (Neighbor Discovery for IP version 6) 7.2.6., unsolicited neighbour advertisements should be sent to the all-nodes multicast address. Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ndisc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 176b469322a..843d6ebc525 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -593,7 +593,7 @@ static void ndisc_send_unsol_na(struct net_device *dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; - struct in6_addr mcaddr; + struct in6_addr mcaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT; idev = in6_dev_get(dev); if (!idev) @@ -601,7 +601,6 @@ static void ndisc_send_unsol_na(struct net_device *dev) read_lock_bh(&idev->lock); list_for_each_entry(ifa, &idev->addr_list, if_list) { - addrconf_addr_solict_mult(&ifa->addr, &mcaddr); ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr, /*router=*/ !!idev->cnf.forwarding, /*solicited=*/ false, /*override=*/ true, From c4cbedfda2227df82126c9dd5e7593565bf45d21 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Oct 2012 22:29:38 +0200 Subject: [PATCH 1434/2357] futex: Handle futex_pi OWNER_DIED take over correctly commit 59fa6245192159ab5e1e17b8e31f15afa9cff4bf upstream. Siddhesh analyzed a failure in the take over of pi futexes in case the owner died and provided a workaround. See: http://sourceware.org/bugzilla/show_bug.cgi?id=14076 The detailed problem analysis shows: Futex F is initialized with PTHREAD_PRIO_INHERIT and PTHREAD_MUTEX_ROBUST_NP attributes. T1 lock_futex_pi(F); T2 lock_futex_pi(F); --> T2 blocks on the futex and creates pi_state which is associated to T1. T1 exits --> exit_robust_list() runs --> Futex F userspace value TID field is set to 0 and FUTEX_OWNER_DIED bit is set. T3 lock_futex_pi(F); --> Succeeds due to the check for F's userspace TID field == 0 --> Claims ownership of the futex and sets its own TID into the userspace TID field of futex F --> returns to user space T1 --> exit_pi_state_list() --> Transfers pi_state to waiter T2 and wakes T2 via rt_mutex_unlock(&pi_state->mutex) T2 --> acquires pi_state->mutex and gains real ownership of the pi_state --> Claims ownership of the futex and sets its own TID into the userspace TID field of futex F --> returns to user space T3 --> observes inconsistent state This problem is independent of UP/SMP, preemptible/non preemptible kernels, or process shared vs. private. The only difference is that certain configurations are more likely to expose it. So as Siddhesh correctly analyzed the following check in futex_lock_pi_atomic() is the culprit: if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) { We check the userspace value for a TID value of 0 and take over the futex unconditionally if that's true. AFAICT this check is there as it is correct for a different corner case of futexes: the WAITERS bit became stale. Now the proposed change - if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) { + if (unlikely(ownerdied || + !(curval & (FUTEX_TID_MASK | FUTEX_WAITERS)))) { solves the problem, but it's not obvious why and it wreckages the "stale WAITERS bit" case. What happens is, that due to the WAITERS bit being set (T2 is blocked on that futex) it enforces T3 to go through lookup_pi_state(), which in the above case returns an existing pi_state and therefor forces T3 to legitimately fight with T2 over the ownership of the pi_state (via pi_state->mutex). Probelm solved! Though that does not work for the "WAITERS bit is stale" problem because if lookup_pi_state() does not find existing pi_state it returns -ERSCH (due to TID == 0) which causes futex_lock_pi() to return -ESRCH to user space because the OWNER_DIED bit is not set. Now there is a different solution to that problem. Do not look at the user space value at all and enforce a lookup of possibly available pi_state. If pi_state can be found, then the new incoming locker T3 blocks on that pi_state and legitimately races with T2 to acquire the rt_mutex and the pi_state and therefor the proper ownership of the user space futex. lookup_pi_state() has the correct order of checks. It first tries to find a pi_state associated with the user space futex and only if that fails it checks for futex TID value = 0. If no pi_state is available nothing can create new state at that point because this happens with the hash bucket lock held. So the above scenario changes to: T1 lock_futex_pi(F); T2 lock_futex_pi(F); --> T2 blocks on the futex and creates pi_state which is associated to T1. T1 exits --> exit_robust_list() runs --> Futex F userspace value TID field is set to 0 and FUTEX_OWNER_DIED bit is set. T3 lock_futex_pi(F); --> Finds pi_state and blocks on pi_state->rt_mutex T1 --> exit_pi_state_list() --> Transfers pi_state to waiter T2 and wakes it via rt_mutex_unlock(&pi_state->mutex) T2 --> acquires pi_state->mutex and gains ownership of the pi_state --> Claims ownership of the futex and sets its own TID into the userspace TID field of futex F --> returns to user space This covers all gazillion points on which T3 might come in between T1's exit_robust_list() clearing the TID field and T2 fixing it up. It also solves the "WAITERS bit stale" problem by forcing the take over. Another benefit of changing the code this way is that it makes it less dependent on untrusted user space values and therefor minimizes the possible wreckage which might be inflicted. As usual after staring for too long at the futex code my brain hurts so much that I really want to ditch that whole optimization of avoiding the syscall for the non contended case for PI futexes and rip out the maze of corner case handling code. Unfortunately we can't as user space relies on that existing behaviour, but at least thinking about it helps me to preserve my mental sanity. Maybe we should nevertheless :) Reported-and-tested-by: Siddhesh Poyarekar Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1210232138540.2756@ionos Acked-by: Darren Hart Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/futex.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 3717e7b306e..20ef219bbe9 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -716,7 +716,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, struct futex_pi_state **ps, struct task_struct *task, int set_waiters) { - int lock_taken, ret, ownerdied = 0; + int lock_taken, ret, force_take = 0; u32 uval, newval, curval, vpid = task_pid_vnr(task); retry: @@ -755,17 +755,15 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, newval = curval | FUTEX_WAITERS; /* - * There are two cases, where a futex might have no owner (the - * owner TID is 0): OWNER_DIED. We take over the futex in this - * case. We also do an unconditional take over, when the owner - * of the futex died. - * - * This is safe as we are protected by the hash bucket lock ! + * Should we force take the futex? See below. */ - if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) { - /* Keep the OWNER_DIED bit */ + if (unlikely(force_take)) { + /* + * Keep the OWNER_DIED and the WAITERS bit and set the + * new TID value. + */ newval = (curval & ~FUTEX_TID_MASK) | vpid; - ownerdied = 0; + force_take = 0; lock_taken = 1; } @@ -775,7 +773,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, goto retry; /* - * We took the lock due to owner died take over. + * We took the lock due to forced take over. */ if (unlikely(lock_taken)) return 1; @@ -790,20 +788,25 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, switch (ret) { case -ESRCH: /* - * No owner found for this futex. Check if the - * OWNER_DIED bit is set to figure out whether - * this is a robust futex or not. + * We failed to find an owner for this + * futex. So we have no pi_state to block + * on. This can happen in two cases: + * + * 1) The owner died + * 2) A stale FUTEX_WAITERS bit + * + * Re-read the futex value. */ if (get_futex_value_locked(&curval, uaddr)) return -EFAULT; /* - * We simply start over in case of a robust - * futex. The code above will take the futex - * and return happy. + * If the owner died or we have a stale + * WAITERS bit the owner TID in the user space + * futex is 0. */ - if (curval & FUTEX_OWNER_DIED) { - ownerdied = 1; + if (!(curval & FUTEX_TID_MASK)) { + force_take = 1; goto retry; } default: From f1e729c67400d3a766befa6f739f971021788878 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 5 Nov 2012 14:29:49 -0500 Subject: [PATCH 1435/2357] mmc: sdhci: fix NULL dereference in sdhci_request() tuning commit 14efd957209461bbdf285bf0d67e931955d04a4c upstream. Commit 473b095a72a9 ("mmc: sdhci: fix incorrect command used in tuning") introduced a NULL dereference at resume-time if an SD 3.0 host controller raises the SDHCI_NEEDS_TUNING flag while no card is inserted. Seen on an OLPC XO-4 with sdhci-pxav3, but presumably affects other controllers too. Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3c403aa8495..1fe0ca9c10a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1294,16 +1294,19 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) */ if ((host->flags & SDHCI_NEEDS_RETUNING) && !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { - /* eMMC uses cmd21 while sd and sdio use cmd19 */ - tuning_opcode = mmc->card->type == MMC_TYPE_MMC ? - MMC_SEND_TUNING_BLOCK_HS200 : - MMC_SEND_TUNING_BLOCK; - spin_unlock_irqrestore(&host->lock, flags); - sdhci_execute_tuning(mmc, tuning_opcode); - spin_lock_irqsave(&host->lock, flags); - - /* Restore original mmc_request structure */ - host->mrq = mrq; + if (mmc->card) { + /* eMMC uses cmd21 but sd and sdio use cmd19 */ + tuning_opcode = + mmc->card->type == MMC_TYPE_MMC ? + MMC_SEND_TUNING_BLOCK_HS200 : + MMC_SEND_TUNING_BLOCK; + spin_unlock_irqrestore(&host->lock, flags); + sdhci_execute_tuning(mmc, tuning_opcode); + spin_lock_irqsave(&host->lock, flags); + + /* Restore original mmc_request structure */ + host->mrq = mrq; + } } if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) From 9feda1930e8fed6bb74d9375d00581f7c9ff2995 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 9 Nov 2012 10:05:57 +0100 Subject: [PATCH 1436/2357] drm/vmwgfx: Fix hibernation device reset commit 95e8f6a21996c4cc2c4574b231c6e858b749dce3 upstream. The device would not reset properly when resuming from hibernation. Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul Reviewed-by: Dmitry Torokhov Cc: linux-graphics-maintainer@vmware.com Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 3a4b15acd76..db50604ac21 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1102,6 +1102,11 @@ static void vmw_pm_complete(struct device *kdev) struct drm_device *dev = pci_get_drvdata(pdev); struct vmw_private *dev_priv = vmw_priv(dev); + mutex_lock(&dev_priv->hw_mutex); + vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); + (void) vmw_read(dev_priv, SVGA_REG_ID); + mutex_unlock(&dev_priv->hw_mutex); + /** * Reclaim 3d reference held by fbdev and potentially * start fifo. From 4fa1f62322efae688e5412a6e483777553898cf6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 9 Nov 2012 10:45:14 +0100 Subject: [PATCH 1437/2357] drm/vmwgfx: Fix a case where the code would BUG when trying to pin GMR memory commit afcc87aa6a233e52df73552dc1dc9ae3881b7cc8 upstream. Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul Reviewed-by: Dmitry Torokhov Cc: linux-graphics-maintainer@vmware.com Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index 3fa884db08a..27151f74fec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -306,7 +306,7 @@ void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin) BUG_ON(!atomic_read(&bo->reserved)); BUG_ON(old_mem_type != TTM_PL_VRAM && - old_mem_type != VMW_PL_FLAG_GMR); + old_mem_type != VMW_PL_GMR); pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED; if (pin) From c436fd2bc1d4255f888dfd68a9f73098cebf30a7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 8 Nov 2012 10:08:04 -0500 Subject: [PATCH 1438/2357] drm/radeon/cayman: add some missing regs to the VM reg checker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 860fe2f05fa2eacac84368e23547ec8cf3cc6652 upstream. These regs were being wronly rejected leading to rendering issues. fixes: https://bugs.freedesktop.org/show_bug.cgi?id=56876 Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen_cs.c | 3 +++ drivers/gpu/drm/radeon/evergreend.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 977b22d4f47..22c84bcfaeb 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -2671,6 +2671,9 @@ static bool evergreen_vm_reg_valid(u32 reg) /* check config regs */ switch (reg) { case GRBM_GFX_INDEX: + case CP_STRMOUT_CNTL: + case CP_COHER_CNTL: + case CP_COHER_SIZE: case VGT_VTX_VECT_EJECT_REG: case VGT_CACHE_INVALIDATION: case VGT_GS_VERTEX_REUSE: diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index f62ccd3555d..2eaaea061d6 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -77,6 +77,10 @@ #define CONFIG_MEMSIZE 0x5428 +#define CP_STRMOUT_CNTL 0x84FC + +#define CP_COHER_CNTL 0x85F0 +#define CP_COHER_SIZE 0x85F4 #define CP_COHER_BASE 0x85F8 #define CP_ME_CNTL 0x86D8 #define CP_ME_HALT (1 << 28) From 511c41c7b657821172b6b1cde7f1f2ce7a73d43e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 8 Nov 2012 10:13:24 -0500 Subject: [PATCH 1439/2357] drm/radeon/si: add some missing regs to the VM reg checker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f418b88aad0c42b4caf4d79a0cf8d14a5d0a2284 upstream. This register is needed for streamout to work properly. Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/si.c | 1 + drivers/gpu/drm/radeon/sid.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 2af1ce69e6e..1197f2187d7 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2593,6 +2593,7 @@ static bool si_vm_reg_valid(u32 reg) /* check config regs */ switch (reg) { case GRBM_GFX_INDEX: + case CP_STRMOUT_CNTL: case VGT_VTX_VECT_EJECT_REG: case VGT_CACHE_INVALIDATION: case VGT_ESGS_RING_SIZE: diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 53ea2c42dbd..2c2bc63d6da 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -413,6 +413,7 @@ # define RDERR_INT_ENABLE (1 << 0) # define GUI_IDLE_INT_ENABLE (1 << 19) +#define CP_STRMOUT_CNTL 0x84FC #define SCRATCH_REG0 0x8500 #define SCRATCH_REG1 0x8504 #define SCRATCH_REG2 0x8508 From c97430309917c78fd47def652ec1573f6e53c735 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 12 May 2012 20:22:00 +0200 Subject: [PATCH 1440/2357] drm/i915: fixup infoframe support for sdvo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 81014b9d0b55fb0b48f26cd2a943359750d532db upstream. At least the worst offenders: - SDVO specifies that the encoder should compute the ecc. Testing also shows that we must not send the ecc field, so copy the dip_infoframe struct to a temporay place and avoid the ecc field. This way the avi infoframe is exactly 17 bytes long, which agrees with what the spec mandates as a minimal storage capacity (with the ecc field it would be 18 bytes). - Only 17 when sending the avi infoframe. The SDVO spec explicitly says that sending more data than what the device announces results in undefined behaviour. - Add __attribute__((packed)) to the avi and spd infoframes, for otherwise they're wrongly aligned. Noticed because the avi infoframe ended up being 18 bytes large instead of 17. We haven't noticed this yet because we don't use the uint16_t fields yet (which are the only ones that would be wrongly aligned). This regression has been introduce by 3c17fe4b8f40a112a85758a9ab2aebf772bdd647 is the first bad commit commit 3c17fe4b8f40a112a85758a9ab2aebf772bdd647 Author: David Härdeman Date: Fri Sep 24 21:44:32 2010 +0200 i915: enable AVI infoframe for intel_hdmi.c [v4] Patch tested on my g33 with a sdvo hdmi adaptor. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=25732 Tested-by: Peter Ross (G35 SDVO-HDMI) Reviewed-by: Eugeni Dodonov Signed-Off-by: Daniel Vetter Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_drv.h | 4 ++-- drivers/gpu/drm/i915/intel_sdvo.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2cae72d1749..cd623e899f5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -247,12 +247,12 @@ struct dip_infoframe { uint16_t bottom_bar_start; uint16_t left_bar_end; uint16_t right_bar_start; - } avi; + } __attribute__ ((packed)) avi; struct { uint8_t vn[8]; uint8_t pd[16]; uint8_t sdi; - } spd; + } __attribute__ ((packed)) spd; uint8_t payload[27]; } __attribute__ ((packed)) body; } __attribute__((packed)); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index eea58c6cb05..d0c1d1e6b41 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -877,17 +877,24 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) }; uint8_t tx_rate = SDVO_HBUF_TX_VSYNC; uint8_t set_buf_index[2] = { 1, 0 }; - uint64_t *data = (uint64_t *)&avi_if; + uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; + uint64_t *data = (uint64_t *)sdvo_data; unsigned i; intel_dip_infoframe_csum(&avi_if); + /* sdvo spec says that the ecc is handled by the hw, and it looks like + * we must not send the ecc field, either. */ + memcpy(sdvo_data, &avi_if, 3); + sdvo_data[3] = avi_if.checksum; + memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi)); + if (!intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, set_buf_index, 2)) return false; - for (i = 0; i < sizeof(avi_if); i += 8) { + for (i = 0; i < sizeof(sdvo_data); i += 8) { if (!intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8)) From 6903f0a9f2370fced066ad21c757b364a962bfea Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 21 Oct 2012 12:52:39 +0200 Subject: [PATCH 1441/2357] drm/i915: clear the entire sdvo infoframe buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b6e0e543f75729f207b9c72b0162ae61170635b2 upstream. Like in the case of native hdmi, which is fixed already in commit adf00b26d18e1b3570451296e03bcb20e4798cdd Author: Paulo Zanoni Date: Tue Sep 25 13:23:34 2012 -0300 drm/i915: make sure we write all the DIP data bytes we need to clear the entire sdvo buffer to avoid upsetting the display. Since infoframe buffer writing is now a bit more elaborate, extract it into it's own function. This will be useful if we ever get around to properly update the ELD for sdvo. Also #define proper names for the two buffer indexes with fixed usage. v2: Cite the right commit above, spotted by Paulo Zanoni. v3: I'm too stupid to paste the right commit. v4: Ben Hutchings noticed that I've failed to handle an underflow in my loop logic, breaking it for i >= length + 8. Since I've just lost C programmer license, use his solution. Also, make the frustrated 0-base buffer size a notch more clear. Reported-and-tested-by: Jürg Billeter Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=25732 Cc: Paulo Zanoni Cc: Ben Hutchings Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_sdvo.c | 62 +++++++++++++++++--------- drivers/gpu/drm/i915/intel_sdvo_regs.h | 2 + 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index d0c1d1e6b41..b96e8c835c8 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -868,6 +868,45 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) } #endif +static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, + unsigned if_index, uint8_t tx_rate, + uint8_t *data, unsigned length) +{ + uint8_t set_buf_index[2] = { if_index, 0 }; + uint8_t hbuf_size, tmp[8]; + int i; + + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_INDEX, + set_buf_index, 2)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO, + &hbuf_size, 1)) + return false; + + /* Buffer size is 0 based, hooray! */ + hbuf_size++; + + DRM_DEBUG_KMS("writing sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n", + if_index, length, hbuf_size); + + for (i = 0; i < hbuf_size; i += 8) { + memset(tmp, 0, 8); + if (i < length) + memcpy(tmp, data + i, min_t(unsigned, 8, length - i)); + + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_DATA, + tmp, 8)) + return false; + } + + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_TXRATE, + &tx_rate, 1); +} + static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) { struct dip_infoframe avi_if = { @@ -875,11 +914,7 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) .ver = DIP_VERSION_AVI, .len = DIP_LEN_AVI, }; - uint8_t tx_rate = SDVO_HBUF_TX_VSYNC; - uint8_t set_buf_index[2] = { 1, 0 }; uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; - uint64_t *data = (uint64_t *)sdvo_data; - unsigned i; intel_dip_infoframe_csum(&avi_if); @@ -889,22 +924,9 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) sdvo_data[3] = avi_if.checksum; memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi)); - if (!intel_sdvo_set_value(intel_sdvo, - SDVO_CMD_SET_HBUF_INDEX, - set_buf_index, 2)) - return false; - - for (i = 0; i < sizeof(sdvo_data); i += 8) { - if (!intel_sdvo_set_value(intel_sdvo, - SDVO_CMD_SET_HBUF_DATA, - data, 8)) - return false; - data++; - } - - return intel_sdvo_set_value(intel_sdvo, - SDVO_CMD_SET_HBUF_TXRATE, - &tx_rate, 1); + return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF, + SDVO_HBUF_TX_VSYNC, + sdvo_data, sizeof(sdvo_data)); } static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 9d030142ee4..770bdd6ecd9 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -708,6 +708,8 @@ struct intel_sdvo_enhancements_arg { #define SDVO_CMD_SET_AUDIO_STAT 0x91 #define SDVO_CMD_GET_AUDIO_STAT 0x92 #define SDVO_CMD_SET_HBUF_INDEX 0x93 + #define SDVO_HBUF_INDEX_ELD 0 + #define SDVO_HBUF_INDEX_AVI_IF 1 #define SDVO_CMD_GET_HBUF_INDEX 0x94 #define SDVO_CMD_GET_HBUF_INFO 0x95 #define SDVO_CMD_SET_HBUF_AV_SPLIT 0x96 From 2834bc7007eb6e8e375f8edbf7f6f52b2a14db13 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 8 Nov 2012 18:28:59 +0100 Subject: [PATCH 1442/2357] USB: mos7840: remove unused variable Fix warning about unused variable introduced by commit e681b66f2e19fa ("USB: mos7840: remove invalid disconnect handling") upstream. A subsequent fix which removed the disconnect function got rid of the warning but that one was only backported to v3.6. Reported-by: Jiri Slaby Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 0179d348c26..c8542356898 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2581,7 +2581,6 @@ static int mos7840_startup(struct usb_serial *serial) static void mos7840_disconnect(struct usb_serial *serial) { int i; - unsigned long flags; struct moschip_port *mos7840_port; dbg("%s", " disconnect :entering.........."); From 13ec0431e7523a5a2d45dd6513b12b5f6b4ddec9 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 2 Nov 2012 11:38:44 +1100 Subject: [PATCH 1443/2357] xfs: fix reading of wrapped log data commit 6ce377afd1755eae5c93410ca9a1121dfead7b87 upstream. Commit 4439647 ("xfs: reset buffer pointers before freeing them") in 3.0-rc1 introduced a regression when recovering log buffers that wrapped around the end of log. The second part of the log buffer at the start of the physical log was being read into the header buffer rather than the data buffer, and hence recovery was seeing garbage in the data buffer when it got to the region of the log buffer that was incorrectly read. Reported-by: Torsten Kaiser Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Mark Tinguely Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_log_recover.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 8ecad5bad66..0abb1623a7c 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -3514,7 +3514,7 @@ xlog_do_recovery_pass( * - order is important. */ error = xlog_bread_offset(log, 0, - bblks - split_bblks, hbp, + bblks - split_bblks, dbp, offset + BBTOB(split_bblks)); if (error) goto bread_err2; From 32896690903c576809f21724115612a82a102a52 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Nov 2012 14:36:18 +0100 Subject: [PATCH 1444/2357] ALSA: Fix card refcount unbalance commit 8bb4d9ce08b0a92ca174e41d92c180328f86173f upstream. There are uncovered cases whether the card refcount introduced by the commit a0830dbd isn't properly increased or decreased: - OSS PCM and mixer success paths - When lookup function gets NULL This patch fixes these places. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=50251 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/mixer_oss.c | 1 + sound/core/oss/pcm_oss.c | 1 + sound/core/pcm_native.c | 6 ++++-- sound/core/sound.c | 2 +- sound/core/sound_oss.c | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 05395aaeaa3..c353768854e 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -76,6 +76,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) snd_card_unref(card); return -EFAULT; } + snd_card_unref(card); return 0; } diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index f337b66a020..4c1cc51772e 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2454,6 +2454,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) mutex_unlock(&pcm->open_mutex); if (err < 0) goto __error; + snd_card_unref(pcm->card); return err; __error: diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 0844444eb10..d535b341aa8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2111,7 +2111,8 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file) pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_PLAYBACK); err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); - snd_card_unref(pcm->card); + if (pcm) + snd_card_unref(pcm->card); return err; } @@ -2124,7 +2125,8 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file) pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_CAPTURE); err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); - snd_card_unref(pcm->card); + if (pcm) + snd_card_unref(pcm->card); return err; } diff --git a/sound/core/sound.c b/sound/core/sound.c index 7c0640eeee5..3700d96fb3f 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -115,7 +115,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type) mreg = snd_minors[minor]; if (mreg && mreg->type == type) { private_data = mreg->private_data; - if (mreg->card_ptr) + if (private_data && mreg->card_ptr) atomic_inc(&mreg->card_ptr->refcount); } else private_data = NULL; diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 7442c7ac246..ec86009141d 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -54,7 +54,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) mreg = snd_oss_minors[minor]; if (mreg && mreg->type == type) { private_data = mreg->private_data; - if (mreg->card_ptr) + if (private_data && mreg->card_ptr) atomic_inc(&mreg->card_ptr->refcount); } else private_data = NULL; From 2ce3809e3420701b66bb4a6bebc69ddaf850394f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 13 Nov 2012 11:22:48 +0100 Subject: [PATCH 1445/2357] ALSA: usb-audio: Fix mutex deadlock at disconnection commit 10e44239f67d0b6fb74006e61a7e883b8075247a upstream. The recent change for USB-audio disconnection race fixes introduced a mutex deadlock again. There is a circular dependency between chip->shutdown_rwsem and pcm->open_mutex, depicted like below, when a device is opened during the disconnection operation: A. snd_usb_audio_disconnect() -> card.c::register_mutex -> chip->shutdown_rwsem (write) -> snd_card_disconnect() -> pcm.c::register_mutex -> pcm->open_mutex B. snd_pcm_open() -> pcm->open_mutex -> snd_usb_pcm_open() -> chip->shutdown_rwsem (read) Since the chip->shutdown_rwsem protection in the case A is required only for turning on the chip->shutdown flag and it doesn't have to be taken for the whole operation, we can reduce its window in snd_usb_audio_disconnect(). Reported-by: Jiri Slaby Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/card.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 147a5c42b95..388460d2731 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -555,9 +555,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, return; card = chip->card; - mutex_lock(®ister_mutex); down_write(&chip->shutdown_rwsem); chip->shutdown = 1; + up_write(&chip->shutdown_rwsem); + + mutex_lock(®ister_mutex); chip->num_interfaces--; if (chip->num_interfaces <= 0) { snd_card_disconnect(card); @@ -574,11 +576,9 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, snd_usb_mixer_disconnect(p); } usb_chip[chip->index] = NULL; - up_write(&chip->shutdown_rwsem); mutex_unlock(®ister_mutex); snd_card_free_when_closed(card); } else { - up_write(&chip->shutdown_rwsem); mutex_unlock(®ister_mutex); } } From 16286083befef95045f84ecc10f19b1a14fc7283 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 17 Nov 2012 13:16:56 -0800 Subject: [PATCH 1446/2357] Linux 3.4.19 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 95de44764c4..e264929291e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 18 +SUBLEVEL = 19 EXTRAVERSION = NAME = Saber-toothed Squirrel From 3f874ecc49208f3635e29c3a08ade01778ad85e4 Mon Sep 17 00:00:00 2001 From: Takamori Yamaguchi Date: Thu, 8 Nov 2012 15:53:39 -0800 Subject: [PATCH 1447/2357] mm: bugfix: set current->reclaim_state to NULL while returning from kswapd() commit b0a8cc58e6b9aaae3045752059e5e6260c0b94bc upstream. In kswapd(), set current->reclaim_state to NULL before returning, as current->reclaim_state holds reference to variable on kswapd()'s stack. In rare cases, while returning from kswapd() during memory offlining, __free_slab() and freepages() can access the dangling pointer of current->reclaim_state. Signed-off-by: Takamori Yamaguchi Signed-off-by: Aaditya Kumar Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/vmscan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/vmscan.c b/mm/vmscan.c index e989ee22f10..e6ca5051c02 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -3128,6 +3128,8 @@ static int kswapd(void *p) &balanced_classzone_idx); } } + + current->reclaim_state = NULL; return 0; } From 0244d2ed647d788233ad72d32986bc0ee9a71d5b Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 12 Nov 2012 22:09:46 +1100 Subject: [PATCH 1448/2357] xfs: drop buffer io reference when a bad bio is built commit d69043c42d8c6414fa28ad18d99973aa6c1c2e24 upstream. Error handling in xfs_buf_ioapply_map() does not handle IO reference counts correctly. We increment the b_io_remaining count before building the bio, but then fail to decrement it in the failure case. This leads to the buffer never running IO completion and releasing the reference that the IO holds, so at unmount we can leak the buffer. This leak is captured by this assert failure during unmount: XFS: Assertion failed: atomic_read(&pag->pag_ref) == 0, file: fs/xfs/xfs_mount.c, line: 273 This is not a new bug - the b_io_remaining accounting has had this problem for a long, long time - it's just very hard to get a zero length bio being built by this code... Further, the buffer IO error can be overwritten on a multi-segment buffer by subsequent bio completions for partial sections of the buffer. Hence we should only set the buffer error status if the buffer is not already carrying an error status. This ensures that a partial IO error on a multi-segment buffer will not be lost. This part of the problem is a regression, however. Signed-off-by: Dave Chinner Reviewed-by: Mark Tinguely Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_buf.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 6819b5163e3..bb76128b5f4 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1165,9 +1165,14 @@ xfs_buf_bio_end_io( { xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; - xfs_buf_ioerror(bp, -error); + /* + * don't overwrite existing errors - otherwise we can lose errors on + * buffers that require multiple bios to complete. + */ + if (!bp->b_error) + xfs_buf_ioerror(bp, -error); - if (!error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) + if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); _xfs_buf_ioend(bp, 1); @@ -1243,6 +1248,11 @@ _xfs_buf_ioapply( if (size) goto next_chunk; } else { + /* + * This is guaranteed not to be the last io reference count + * because the caller (xfs_buf_iorequest) holds a count itself. + */ + atomic_dec(&bp->b_io_remaining); xfs_buf_ioerror(bp, EIO); bio_put(bio); } From 1cbc74e7edf24ac527c502e3e936bc4350ec4622 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 5 Nov 2012 10:27:52 +0200 Subject: [PATCH 1449/2357] mac80211: sync acccess to tx_filtered/ps_tx_buf queues commit 987c285c2ae2e4e32aca3a9b3252d28171c75711 upstream. These are accessed without a lock when ending STA PSM. If the sta_cleanup timer accesses these lists at the same time, we might crash. This may fix some mysterious crashes we had during ieee80211_sta_ps_deliver_wakeup. Signed-off-by: Arik Nemtsov Signed-off-by: Ido Yariv Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/sta_info.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d93d39b8434..6e36aafbf5e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -959,6 +959,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) struct ieee80211_local *local = sdata->local; struct sk_buff_head pending; int filtered = 0, buffered = 0, ac; + unsigned long flags; clear_sta_flag(sta, WLAN_STA_SP); @@ -974,12 +975,16 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { int count = skb_queue_len(&pending), tmp; + spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags); skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending); + spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags); tmp = skb_queue_len(&pending); filtered += tmp - count; count = tmp; + spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags); skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending); + spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags); tmp = skb_queue_len(&pending); buffered += tmp - count; } From ab4e547760de676be22d61c5d73230356b383a31 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Nov 2012 14:06:28 +0100 Subject: [PATCH 1450/2357] mac80211: don't send null data packet when not associated commit 20f544eea03db4b498942558b882d463ce575c3e upstream. On resume or firmware recovery, mac80211 sends a null data packet to see if the AP is still around and hasn't disconnected us. However, it always does this even if it wasn't even connected before, leading to a warning in the new channel context code. Fix this by checking that it's associated. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 266d0925ba2..73ef163a039 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1341,6 +1341,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type != NL80211_IFTYPE_STATION) continue; + if (!sdata->u.mgd.associated) + continue; ieee80211_send_nullfunc(local, sdata, 0); } From bb1d6871282e191752d4d8396808ed25ac3500fb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 10 Nov 2012 03:44:14 +0100 Subject: [PATCH 1451/2357] mac80211: call skb_dequeue/ieee80211_free_txskb instead of __skb_queue_purge commit 1f98ab7fef48a2968f37f422c256c9fbd978c3f0 upstream. Fixes more wifi status skb leaks, leading to hostapd/wpa_supplicant hangs. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/sta_info.c | 6 +++--- net/mac80211/status.c | 9 +++++++++ net/mac80211/tx.c | 9 ++++++--- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index db8fae51714..498e87bcb3e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1297,6 +1297,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); +void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, + struct sk_buff_head *skbs); /* HT */ bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 6e36aafbf5e..6d25d7796fc 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -738,8 +738,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); - __skb_queue_purge(&sta->ps_tx_buf[ac]); - __skb_queue_purge(&sta->tx_filtered[ac]); + ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]); + ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]); } #ifdef CONFIG_MAC80211_MESH @@ -774,7 +774,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); if (!tid_tx) continue; - __skb_queue_purge(&tid_tx->pending); + ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); kfree(tid_tx); } diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 5f8f89e89d6..47b117f3f56 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -660,3 +660,12 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) dev_kfree_skb_any(skb); } EXPORT_SYMBOL(ieee80211_free_txskb); + +void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, + struct sk_buff_head *skbs) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(skbs))) + ieee80211_free_txskb(hw, skb); +} diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e76facc69e9..eace7664c80 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1357,7 +1357,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) if (tx->skb) dev_kfree_skb(tx->skb); else - __skb_queue_purge(&tx->skbs); + ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs); return -1; } else if (unlikely(res == TX_QUEUED)) { I802_DEBUG_INC(tx->local->tx_handlers_queued); @@ -2126,10 +2126,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, */ void ieee80211_clear_tx_pending(struct ieee80211_local *local) { + struct sk_buff *skb; int i; - for (i = 0; i < local->hw.queues; i++) - skb_queue_purge(&local->pending[i]); + for (i = 0; i < local->hw.queues; i++) { + while ((skb = skb_dequeue(&local->pending[i])) != NULL) + ieee80211_free_txskb(&local->hw, skb); + } } /* From a6a19e36b35fcb17d6c2bf9a49014e9461dfcef2 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 8 Nov 2012 15:53:37 -0800 Subject: [PATCH 1452/2357] fanotify: fix missing break commit 848561d368751a1c0f679b9f045a02944506a801 upstream. Anders Blomdell noted in 2010 that Fanotify lost events and provided a test case. Eric Paris confirmed it was a bug and posted a fix to the list https://groups.google.com/forum/?fromgroups=#!topic/linux.kernel/RrJfTfyW2BE but never applied it. Repeated attempts over time to actually get him to apply it have never had a reply from anyone who has raised it So apply it anyway Signed-off-by: Alan Cox Reported-by: Anders Blomdell Cc: Eric Paris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/notify/fanotify/fanotify.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index f35794b97e8..a5063602536 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -21,6 +21,7 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new) if ((old->path.mnt == new->path.mnt) && (old->path.dentry == new->path.dentry)) return true; + break; case (FSNOTIFY_EVENT_NONE): return true; default: From 0de578d014506a662b239708f4a0ded7e083292c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 25 Oct 2012 10:49:25 +1030 Subject: [PATCH 1453/2357] module: fix out-by-one error in kallsyms commit 59ef28b1f14899b10d6b2682c7057ca00a9a3f47 upstream. Masaki found and patched a kallsyms issue: the last symbol in a module's symtab wasn't transferred. This is because we manually copy the zero'th entry (which is always empty) then copy the rest in a loop starting at 1, though from src[0]. His fix was minimal, I prefer to rewrite the loops in more standard form. There are two loops: one to get the size, and one to copy. Make these identical: always count entry 0 and any defined symbol in an allocated non-init section. This bug exists since the following commit was introduced. module: reduce symbol table for loaded modules (v2) commit: 4a4962263f07d14660849ec134ee42b63e95ea9a LKML: http://lkml.org/lkml/2012/10/24/27 Reported-by: Masaki Kimura Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman --- kernel/module.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index 61ea75eaeec..85972171ecd 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2273,12 +2273,17 @@ static void layout_symtab(struct module *mod, struct load_info *info) src = (void *)info->hdr + symsect->sh_offset; nsrc = symsect->sh_size / sizeof(*src); + /* strtab always starts with a nul, so offset 0 is the empty string. */ + strtab_size = 1; + /* Compute total space required for the core symbols' strtab. */ - for (ndst = i = strtab_size = 1; i < nsrc; ++i, ++src) - if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) { - strtab_size += strlen(&info->strtab[src->st_name]) + 1; + for (ndst = i = 0; i < nsrc; i++) { + if (i == 0 || + is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) { + strtab_size += strlen(&info->strtab[src[i].st_name])+1; ndst++; } + } /* Append room for core symbols at end of core part. */ info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1); @@ -2312,15 +2317,15 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) mod->core_symtab = dst = mod->module_core + info->symoffs; mod->core_strtab = s = mod->module_core + info->stroffs; src = mod->symtab; - *dst = *src; *s++ = 0; - for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) { - if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) - continue; - - dst[ndst] = *src; - dst[ndst++].st_name = s - mod->core_strtab; - s += strlcpy(s, &mod->strtab[src->st_name], KSYM_NAME_LEN) + 1; + for (ndst = i = 0; i < mod->num_symtab; i++) { + if (i == 0 || + is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) { + dst[ndst] = src[i]; + dst[ndst++].st_name = s - mod->core_strtab; + s += strlcpy(s, &mod->strtab[src[i].st_name], + KSYM_NAME_LEN) + 1; + } } mod->core_num_syms = ndst; } From bb60c07c75a9087303779324be4e5de771a7687b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Sat, 3 Nov 2012 09:37:28 -0400 Subject: [PATCH 1454/2357] cifs: fix potential buffer overrun in cifs.idmap handling code commit 36960e440ccf94349c09fb944930d3bfe4bc473f upstream. The userspace cifs.idmap program generally works with the wbclient libs to generate binary SIDs in userspace. That program defines the struct that holds these values as having a max of 15 subauthorities. The kernel idmapping code however limits that value to 5. When the kernel copies those values around though, it doesn't sanity check the num_subauths value handed back from userspace or from the server. It's possible therefore for userspace to hand us back a bogus num_subauths value (or one that's valid, but greater than 5) that could cause the kernel to walk off the end of the cifs_sid->sub_auths array. Fix this by defining a new routine for copying sids and using that in all of the places that copy it. If we end up with a sid that's longer than expected then this approach will just lop off the "extra" subauths, but that's basically what the code does today already. Better approaches might be to fix this code to reject SIDs with >5 subauths, or fix it to handle the subauths array dynamically. At the same time, change the kernel to check the length of the data returned by userspace. If it's shorter than struct cifs_sid, reject it and return -EIO. If that happens we'll end up with fields that are basically uninitialized. Long term, it might make sense to redefine cifs_sid using a flexarray at the end, to allow for variable-length subauth lists, and teach the code to handle the case where the subauths array being passed in from userspace is shorter than 5 elements. Note too, that I don't consider this a security issue since you'd need a compromised cifs.idmap program. If you have that, you can do all sorts of nefarious stuff. Still, this is probably reasonable for stable. Reviewed-by: Shirish Pargaonkar Signed-off-by: Jeff Layton Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsacl.c | 49 +++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 3cc1b251ca0..6ccf176427f 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -224,6 +224,13 @@ sid_to_str(struct cifs_sid *sidptr, char *sidstr) } } +static void +cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src) +{ + memcpy(dst, src, sizeof(*dst)); + dst->num_subauth = min_t(u8, src->num_subauth, NUM_SUBAUTHS); +} + static void id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, struct cifs_sid_id **psidid, char *typestr) @@ -248,7 +255,7 @@ id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, } } - memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid)); + cifs_copy_sid(&(*psidid)->sid, sidptr); (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); (*psidid)->refcount = 0; @@ -354,7 +361,7 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid) * any fields of the node after a reference is put . */ if (test_bit(SID_ID_MAPPED, &psidid->state)) { - memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); + cifs_copy_sid(ssid, &psidid->sid); psidid->time = jiffies; /* update ts for accessing */ goto id_sid_out; } @@ -370,14 +377,14 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid) if (IS_ERR(sidkey)) { rc = -EINVAL; cFYI(1, "%s: Can't map and id to a SID", __func__); + } else if (sidkey->datalen < sizeof(struct cifs_sid)) { + rc = -EIO; + cFYI(1, "%s: Downcall contained malformed key " + "(datalen=%hu)", __func__, sidkey->datalen); } else { lsid = (struct cifs_sid *)sidkey->payload.data; - memcpy(&psidid->sid, lsid, - sidkey->datalen < sizeof(struct cifs_sid) ? - sidkey->datalen : sizeof(struct cifs_sid)); - memcpy(ssid, &psidid->sid, - sidkey->datalen < sizeof(struct cifs_sid) ? - sidkey->datalen : sizeof(struct cifs_sid)); + cifs_copy_sid(&psidid->sid, lsid); + cifs_copy_sid(ssid, &psidid->sid); set_bit(SID_ID_MAPPED, &psidid->state); key_put(sidkey); kfree(psidid->sidstr); @@ -396,7 +403,7 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid) return rc; } if (test_bit(SID_ID_MAPPED, &psidid->state)) - memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); + cifs_copy_sid(ssid, &psidid->sid); else rc = -EINVAL; } @@ -675,8 +682,6 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) static void copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, __u32 sidsoffset) { - int i; - struct cifs_sid *owner_sid_ptr, *group_sid_ptr; struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; @@ -692,26 +697,14 @@ static void copy_sec_desc(const struct cifs_ntsd *pntsd, owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + le32_to_cpu(pntsd->osidoffset)); nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset); - - nowner_sid_ptr->revision = owner_sid_ptr->revision; - nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth; - for (i = 0; i < 6; i++) - nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i]; - for (i = 0; i < 5; i++) - nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i]; + cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr); /* copy group sid */ group_sid_ptr = (struct cifs_sid *)((char *)pntsd + le32_to_cpu(pntsd->gsidoffset)); ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset + sizeof(struct cifs_sid)); - - ngroup_sid_ptr->revision = group_sid_ptr->revision; - ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth; - for (i = 0; i < 6; i++) - ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i]; - for (i = 0; i < 5; i++) - ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i]; + cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr); return; } @@ -1120,8 +1113,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, kfree(nowner_sid_ptr); return rc; } - memcpy(owner_sid_ptr, nowner_sid_ptr, - sizeof(struct cifs_sid)); + cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr); kfree(nowner_sid_ptr); *aclflag = CIFS_ACL_OWNER; } @@ -1139,8 +1131,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, kfree(ngroup_sid_ptr); return rc; } - memcpy(group_sid_ptr, ngroup_sid_ptr, - sizeof(struct cifs_sid)); + cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr); kfree(ngroup_sid_ptr); *aclflag = CIFS_ACL_GROUP; } From 30966dbf8217223b017514ca684c633e5c31a13a Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Sun, 21 Oct 2012 20:42:28 +0300 Subject: [PATCH 1455/2357] crypto: cryptd - disable softirqs in cryptd_queue_worker to prevent data corruption commit 9efade1b3e981f5064f9db9ca971b4dc7557ae42 upstream. cryptd_queue_worker attempts to prevent simultaneous accesses to crypto workqueue by cryptd_enqueue_request using preempt_disable/preempt_enable. However cryptd_enqueue_request might be called from softirq context, so add local_bh_disable/local_bh_enable to prevent data corruption and panics. Bug report at http://marc.info/?l=linux-crypto-vger&m=134858649616319&w=2 v2: - Disable software interrupts instead of hardware interrupts Reported-by: Gurucharan Shetty Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/cryptd.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crypto/cryptd.c b/crypto/cryptd.c index 671d4d6d14d..7bdd61b867c 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -137,13 +137,18 @@ static void cryptd_queue_worker(struct work_struct *work) struct crypto_async_request *req, *backlog; cpu_queue = container_of(work, struct cryptd_cpu_queue, work); - /* Only handle one request at a time to avoid hogging crypto - * workqueue. preempt_disable/enable is used to prevent - * being preempted by cryptd_enqueue_request() */ + /* + * Only handle one request at a time to avoid hogging crypto workqueue. + * preempt_disable/enable is used to prevent being preempted by + * cryptd_enqueue_request(). local_bh_disable/enable is used to prevent + * cryptd_enqueue_request() being accessed from software interrupts. + */ + local_bh_disable(); preempt_disable(); backlog = crypto_get_backlog(&cpu_queue->queue); req = crypto_dequeue_request(&cpu_queue->queue); preempt_enable(); + local_bh_enable(); if (!req) return; From 2a1d20c8d31dd4d2b83838e4de3e15ebbb442806 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 1 Nov 2012 13:42:37 +0100 Subject: [PATCH 1456/2357] ALSA: hda: Cirrus: Fix coefficient index for beep configuration commit 5a83b4b5a391f07141b157ac9daa51c409e71ab5 upstream. Signed-off-by: Alexander Stein Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_cirrus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 2bc6c51f58e..d7ba0f124d5 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1112,7 +1112,7 @@ static const struct hda_verb cs_coef_init_verbs[] = { | 0x0400 /* Disable Coefficient Auto increment */ )}, /* Beep */ - {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, + {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG}, {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */ {} /* terminator */ From 1289a3ebfb5de7d1eb093352e977fd5dbb414946 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Sun, 4 Nov 2012 13:19:03 +0800 Subject: [PATCH 1457/2357] ALSA: HDA: Fix digital microphone on CS420x commit 16337e028a6dae9fbdd718c0d42161540a668ff3 upstream. Correctly enable the digital microphones with the right bits in the right coeffecient registers on Cirrus CS4206/7 codecs. It also prevents misconfiguring ADC1/2. This fixes the digital mic on the Macbook Pro 10,1/Retina. Based-on-patch-by: Alexander Stein Signed-off-by: Daniel J Blueman Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_cirrus.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d7ba0f124d5..057f95a2bbb 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -95,8 +95,8 @@ enum { #define CS420X_VENDOR_NID 0x11 #define CS_DIG_OUT1_PIN_NID 0x10 #define CS_DIG_OUT2_PIN_NID 0x15 -#define CS_DMIC1_PIN_NID 0x12 -#define CS_DMIC2_PIN_NID 0x0e +#define CS_DMIC1_PIN_NID 0x0e +#define CS_DMIC2_PIN_NID 0x12 /* coef indices */ #define IDX_SPDIF_STAT 0x0000 @@ -1084,14 +1084,18 @@ static void init_input(struct hda_codec *codec) cs_automic(codec); coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ + cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); + + coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG); if (is_active_pin(codec, CS_DMIC2_PIN_NID)) - coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */ + coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */ if (is_active_pin(codec, CS_DMIC1_PIN_NID)) - coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off + coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off * No effect if SPDIF_OUT2 is * selected in IDX_SPDIF_CTL. */ - cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); + + cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef); } else { if (spec->mic_detect) cs_automic(codec); From f283494905eb2aab38911af461563c985c1a1115 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 5 Nov 2012 12:32:46 +0100 Subject: [PATCH 1458/2357] ALSA: hda - Force to reset IEC958 status bits for AD codecs commit ae24c3191ba2ab03ec6b4be323e730e00404b4b6 upstream. Several bug reports suggest that the forcibly resetting IEC958 status bits is required for AD codecs to get the SPDIF output working properly after changing streams. Original fix credit to Javeed Shaikh. BugLink: https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/359361 Reported-by: Robin Kreis Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_analog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 7143393927d..e23ad3f045f 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -544,6 +544,7 @@ static int ad198x_build_pcms(struct hda_codec *codec) if (spec->multiout.dig_out_nid) { info++; codec->num_pcms++; + codec->spdif_status_reset = 1; info->name = "AD198x Digital"; info->pcm_type = HDA_PCM_TYPE_SPDIF; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; From 9562c79dcc0f30e353b52936b0408114c269d350 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Nov 2012 10:32:47 +0100 Subject: [PATCH 1459/2357] ALSA: hda - Fix empty DAC filling in patch_via.c commit 5b3761954dac2d1393beef8210eb8cee81d16b8d upstream. In via_auto_fill_adc_nids(), the parser tries to fill dac_nids[] at the point of the current line-out (i). When no valid path is found for this output, this results in dac = 0, thus it creates a hole in dac_nids[]. This confuses is_empty_dac() and trims the detected DAC in later reference. This patch fixes the bug by appending DAC properly to dac_nids[] in via_auto_fill_adc_nids(). Reported-by: Massimo Del Fedele Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_via.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 3998d09bf24..c63c3be0fd0 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1868,11 +1868,11 @@ static int via_auto_fill_dac_nids(struct hda_codec *codec) { struct via_spec *spec = codec->spec; const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, dac_num; + int i; hda_nid_t nid; + spec->multiout.num_dacs = 0; spec->multiout.dac_nids = spec->private_dac_nids; - dac_num = 0; for (i = 0; i < cfg->line_outs; i++) { hda_nid_t dac = 0; nid = cfg->line_out_pins[i]; @@ -1883,16 +1883,13 @@ static int via_auto_fill_dac_nids(struct hda_codec *codec) if (!i && parse_output_path(codec, nid, dac, 1, &spec->out_mix_path)) dac = spec->out_mix_path.path[0]; - if (dac) { - spec->private_dac_nids[i] = dac; - dac_num++; - } + if (dac) + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } if (!spec->out_path[0].depth && spec->out_mix_path.depth) { spec->out_path[0] = spec->out_mix_path; spec->out_mix_path.depth = 0; } - spec->multiout.num_dacs = dac_num; return 0; } From d2d0adce41aacfe4b08dee4fd32daad490c8ed3e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Nov 2012 10:37:48 +0100 Subject: [PATCH 1460/2357] ALSA: hda - Fix invalid connections in VT1802 codec commit ef4da45828603df57e5e21b8aa21a66ce309f79b upstream. VT1802 codec provides the invalid connection lists of NID 0x24 and 0x33 containing the routes to a non-exist widget 0x3e. This confuses the auto-parser. Fix it up in the driver by overriding these connections. Reported-by: Massimo Del Fedele Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_via.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index c63c3be0fd0..9dafacdb519 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -3665,6 +3665,18 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) update_power_state(codec, 0x21, AC_PWRST_D3); } +/* NIDs 0x24 and 0x33 on VT1802 have connections to non-existing NID 0x3e + * Replace this with mixer NID 0x1c + */ +static void fix_vt1802_connections(struct hda_codec *codec) +{ + static hda_nid_t conn_24[] = { 0x14, 0x1c }; + static hda_nid_t conn_33[] = { 0x1c }; + + snd_hda_override_conn_list(codec, 0x24, ARRAY_SIZE(conn_24), conn_24); + snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33); +} + /* patch for vt2002P */ static int patch_vt2002P(struct hda_codec *codec) { @@ -3679,6 +3691,8 @@ static int patch_vt2002P(struct hda_codec *codec) spec->aa_mix_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); + if (spec->codec_type == VT1802) + fix_vt1802_connections(codec); add_secret_dac_path(codec); /* automatic parse from the BIOS config */ From 2302f5e1a612ada83bb179203736008bac383fc7 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 8 Nov 2012 10:25:37 +0100 Subject: [PATCH 1461/2357] ALSA: hda - Add new codec ALC668 and ALC900 (default name ALC1150) commit 19a62823eae453619604636082085812c14ee391 upstream. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6ecf1d4fa8a..5430a6de742 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7047,6 +7047,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { .patch = patch_alc662 }, { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, + { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 }, { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 }, { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, @@ -7064,6 +7065,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 }, { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 }, { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 }, + { .id = 0x10ec0900, .name = "ALC1150", .patch = patch_alc882 }, {} /* terminator */ }; From c2628a3b472500b59def16491041e6b13bd5309e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 12 Nov 2012 10:07:36 +0100 Subject: [PATCH 1462/2357] ALSA: hda - Add a missing quirk entry for iMac 9,1 commit 05193639ca977cc889668718adb38db6d585045b upstream. This is another variant of iMac 9,1 with a different codec SSID. Reported-and-tested-by: Everaldo Canuto Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5430a6de742..257fe87c4c0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5458,6 +5458,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF), From b6d806539cdf76b1d0ad2411dff4cae227de4942 Mon Sep 17 00:00:00 2001 From: Eric Millbrandt Date: Fri, 2 Nov 2012 17:05:44 -0400 Subject: [PATCH 1463/2357] ASoC: wm8978: pll incorrectly configured when codec is master commit 55c6f4cb6ef49afbb86222c6a3ff85329199c729 upstream. When MCLK is supplied externally and BCLK and LRC are configured as outputs (codec is master), the PLL values are only calculated correctly on the first transmission. On subsequent transmissions, at differenct sample rates, the wrong PLL values are used. Test for f_opclk instead of f_pllout to determine if the PLL values are needed. Signed-off-by: Eric Millbrandt Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8978.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 72d5fdcd3cc..6c37c7c2327 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -783,7 +783,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream, wm8978->mclk_idx = -1; f_sel = wm8978->f_mclk; } else { - if (!wm8978->f_pllout) { + if (!wm8978->f_opclk) { /* We only enter here, if OPCLK is not used */ int ret = wm8978_configure_pll(codec); if (ret < 0) From 647a9dbec6ab9bf9789b2dcfb589cf4dbb13e379 Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Thu, 8 Nov 2012 12:03:12 -0600 Subject: [PATCH 1464/2357] ASoC: dapm: Use card_list during DAPM shutdown commit 445632ad6dda42f4d3f9df2569a852ca0d4ea608 upstream. DAPM shutdown incorrectly uses "list" field of codec struct while iterating over probed components (codec_dev_list). "list" field refers to codecs registered in the system, "card_list" field is used for probed components. Signed-off-by: Misael Lopez Cruz Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c41efe01a81..9ae82a4eb71 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3253,7 +3253,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card) { struct snd_soc_codec *codec; - list_for_each_entry(codec, &card->codec_dev_list, list) { + list_for_each_entry(codec, &card->codec_dev_list, card_list) { soc_dapm_shutdown_codec(&codec->dapm); if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) snd_soc_dapm_set_bias_level(&codec->dapm, From 151de639411e60bbf9d8fbb5e7b78bb2c5eb0972 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 9 Oct 2012 16:20:15 +0300 Subject: [PATCH 1465/2357] UBIFS: fix mounting problems after power cuts commit a28ad42a4a0c6f302f488f26488b8b37c9b30024 upstream. This is a bugfix for a problem with the following symptoms: 1. A power cut happens 2. After reboot, we try to mount UBIFS 3. Mount fails with "No space left on device" error message UBIFS complains like this: UBIFS error (pid 28225): grab_empty_leb: could not find an empty LEB The root cause of this problem is that when we mount, not all LEBs are categorized. Only those which were read are. However, the 'ubifs_find_free_leb_for_idx()' function assumes that all LEBs were categorized and 'c->freeable_cnt' is valid, which is a false assumption. This patch fixes the problem by teaching 'ubifs_find_free_leb_for_idx()' to always fall back to LPT scanning if no freeable LEBs were found. This problem was reported by few people in the past, but Brent Taylor was able to reproduce it and send me a flash image which cannot be mounted, which made it easy to hunt the bug. Kudos to Brent. Reported-by: Brent Taylor Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/find.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c index 2559d174e00..5dc48cacb5a 100644 --- a/fs/ubifs/find.c +++ b/fs/ubifs/find.c @@ -681,8 +681,16 @@ int ubifs_find_free_leb_for_idx(struct ubifs_info *c) if (!lprops) { lprops = ubifs_fast_find_freeable(c); if (!lprops) { - ubifs_assert(c->freeable_cnt == 0); - if (c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) { + /* + * The first condition means the following: go scan the + * LPT if there are uncategorized lprops, which means + * there may be freeable LEBs there (UBIFS does not + * store the information about freeable LEBs in the + * master node). + */ + if (c->in_a_category_cnt != c->main_lebs || + c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) { + ubifs_assert(c->freeable_cnt == 0); lprops = scan_for_leb_for_idx(c); if (IS_ERR(lprops)) { err = PTR_ERR(lprops); From 07126218d445ea1fea9952c6f801e5d05117e223 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 10 Oct 2012 10:55:28 +0300 Subject: [PATCH 1466/2357] UBIFS: introduce categorized lprops counter commit 98a1eebda3cb2a84ecf1f219bb3a95769033d1bf upstream. This commit is a preparation for a subsequent bugfix. We introduce a counter for categorized lprops. Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/lprops.c | 6 ++++++ fs/ubifs/ubifs.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c index f8a181e647c..ea9d49164ff 100644 --- a/fs/ubifs/lprops.c +++ b/fs/ubifs/lprops.c @@ -300,8 +300,11 @@ void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops, default: ubifs_assert(0); } + lprops->flags &= ~LPROPS_CAT_MASK; lprops->flags |= cat; + c->in_a_category_cnt += 1; + ubifs_assert(c->in_a_category_cnt <= c->main_lebs); } /** @@ -334,6 +337,9 @@ static void ubifs_remove_from_cat(struct ubifs_info *c, default: ubifs_assert(0); } + + c->in_a_category_cnt -= 1; + ubifs_assert(c->in_a_category_cnt >= 0); } /** diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 93d59aceaae..4971cb23b6c 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1184,6 +1184,8 @@ struct ubifs_debug_info; * @freeable_list: list of freeable non-index LEBs (free + dirty == @leb_size) * @frdi_idx_list: list of freeable index LEBs (free + dirty == @leb_size) * @freeable_cnt: number of freeable LEBs in @freeable_list + * @in_a_category_cnt: count of lprops which are in a certain category, which + * basically meants that they were loaded from the flash * * @ltab_lnum: LEB number of LPT's own lprops table * @ltab_offs: offset of LPT's own lprops table @@ -1413,6 +1415,7 @@ struct ubifs_info { struct list_head freeable_list; struct list_head frdi_idx_list; int freeable_cnt; + int in_a_category_cnt; int ltab_lnum; int ltab_offs; From 87dd2c484ae11e2e0a34996d96bfbfaf20f57b45 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 7 Nov 2012 18:21:51 -0800 Subject: [PATCH 1467/2357] Revert "Staging: Android alarm: IOCTL command encoding fix" commit d38e0e3fed4f58bcddef4dc93a591dfe2f651cb0 upstream. Commit 6bd4a5d96c08dc2380f8053b1bd4f879f55cd3c9 changed the ANDROID_ALARM_GET_TIME ioctls from IOW to IOR. While technically correct, the _IOC_DIR bits are ignored by alarm_ioctl, so the commit breaks a userspace ABI used by all existing Android devices for a purely cosmetic reason. Revert it. Cc: Dae S. Kim Signed-off-by: Colin Cross Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/android_alarm.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h index 66b6e3decc6..6eecbde2ef6 100644 --- a/drivers/staging/android/android_alarm.h +++ b/drivers/staging/android/android_alarm.h @@ -110,12 +110,10 @@ enum android_alarm_return_flags { #define ANDROID_ALARM_WAIT _IO('a', 1) #define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size) -#define ALARM_IOR(c, type, size) _IOR('a', (c) | ((type) << 4), size) - /* Set alarm */ #define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec) #define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec) -#define ANDROID_ALARM_GET_TIME(type) ALARM_IOR(4, type, struct timespec) +#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec) #define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec) #define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0))) #define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4) From 3e31ee155e0963e42bb02d33a2a9e44d5b91a45b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 22 Oct 2012 15:49:02 +0200 Subject: [PATCH 1468/2357] s390/gup: add missing TASK_SIZE check to get_user_pages_fast() commit d55c4c613fc4d4ad2ba0fc6fa2b57176d420f7e4 upstream. When walking page tables we need to make sure that everything is within bounds of the ASCE limit of the task's address space. Otherwise we might calculate e.g. a pud pointer which is not within a pud and dereference it. So check against TASK_SIZE (which is the ASCE limit) before walking page tables. Reviewed-by: Gerald Schaefer Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/mm/gup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index 65cb06e2af4..4ccf9f54355 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c @@ -183,7 +183,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, addr = start; len = (unsigned long) nr_pages << PAGE_SHIFT; end = start + len; - if (end < start) + if ((end < start) || (end > TASK_SIZE)) goto slow_irqon; /* From 47ccee3020fc998e27dbdd04cc575bfb6b927886 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 8 Nov 2012 11:56:42 -0600 Subject: [PATCH 1469/2357] USB: option: add Novatel E362 and Dell Wireless 5800 USB IDs commit fcb21645f1bd86d2be29baf48aa1b298de52ccc7 upstream. The Dell 5800 appears to be a simple rebrand of the Novatel E362. Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 17ec21ee7d0..e26bd428a46 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -157,6 +157,7 @@ static void option_instat_callback(struct urb *urb); #define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001 #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000 #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 +#define NOVATELWIRELESS_PRODUCT_E362 0x9010 #define NOVATELWIRELESS_PRODUCT_G1 0xA001 #define NOVATELWIRELESS_PRODUCT_G1_M 0xA002 #define NOVATELWIRELESS_PRODUCT_G2 0xA010 @@ -192,6 +193,9 @@ static void option_instat_callback(struct urb *urb); #define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181 #define DELL_PRODUCT_5730_MINICARD_VZW 0x8182 +#define DELL_PRODUCT_5800_MINICARD_VZW 0x8195 /* Novatel E362 */ +#define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */ + #define KYOCERA_VENDOR_ID 0x0c88 #define KYOCERA_PRODUCT_KPC650 0x17da #define KYOCERA_PRODUCT_KPC680 0x180a @@ -705,6 +709,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) }, /* Novatel Ovation MC551 a.k.a. Verizon USB551L */ { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, @@ -727,6 +732,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_SPRINT) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_TELUS) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, From 3bf0d107e137043aa3c6a872ee542b3f0e85a30a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 8 Nov 2012 11:56:53 -0600 Subject: [PATCH 1470/2357] USB: option: add Alcatel X220/X500D USB IDs commit c0bc3098871dd9b964f6b45ec1e4d70d87811744 upstream. Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e26bd428a46..43aa36bcd39 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -286,6 +286,7 @@ static void option_instat_callback(struct urb *urb); /* ALCATEL PRODUCTS */ #define ALCATEL_VENDOR_ID 0x1bbb #define ALCATEL_PRODUCT_X060S_X200 0x0000 +#define ALCATEL_PRODUCT_X220_X500D 0x0017 #define PIRELLI_VENDOR_ID 0x1266 #define PIRELLI_PRODUCT_C100_1 0x1002 @@ -1163,6 +1164,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) }, { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), From cfb62e2f3c407c91a4c4707006ad47183baf4ff1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 14 Nov 2012 09:10:39 -0500 Subject: [PATCH 1471/2357] drm/radeon: fix logic error in atombios_encoders.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b9196395c905edec512dfd6690428084228c16ec upstream. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=50431 Reported-by: David Binderman Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_encoders.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 2d07fbf2c27..f6176bc90f1 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1421,7 +1421,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); /* some early dce3.2 boards have a bug in their transmitter control table */ - if ((rdev->family != CHIP_RV710) || (rdev->family != CHIP_RV730)) + if ((rdev->family != CHIP_RV710) && (rdev->family != CHIP_RV730)) atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); } if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { From 9098e8785685bd245027447b5628fa872babd3b8 Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Tue, 13 Nov 2012 18:31:55 +0000 Subject: [PATCH 1472/2357] ttm: Clear the ttm page allocated from high memory zone correctly commit ac207ed2471150e06af0afc76e4becc701fa2733 upstream. The TTM page can be allocated from high memory. In such case it is wrong to use the page_address(page) as the virtual address for the high memory page. bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=50241 Signed-off-by: Zhao Yakui Reviewed-by: Thomas Hellstrom Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/ttm/ttm_page_alloc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index ebc6fac96e3..578207ecc43 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -749,7 +749,10 @@ static int ttm_get_pages(struct page **pages, unsigned npages, int flags, /* clear the pages coming from the pool if requested */ if (flags & TTM_PAGE_FLAG_ZERO_ALLOC) { list_for_each_entry(p, &plist, lru) { - clear_page(page_address(p)); + if (PageHighMem(p)) + clear_highpage(p); + else + clear_page(page_address(p)); } } From e5c4ee6a081ec04e8ba54b00a4385391ab77e2f8 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Fri, 16 Nov 2012 14:14:49 -0800 Subject: [PATCH 1473/2357] memcg: oom: fix totalpages calculation for memory.swappiness==0 commit 9a5a8f19b43430752067ecaee62fc59e11e88fa6 upstream. oom_badness() takes a totalpages argument which says how many pages are available and it uses it as a base for the score calculation. The value is calculated by mem_cgroup_get_limit which considers both limit and total_swap_pages (resp. memsw portion of it). This is usually correct but since fe35004fbf9e ("mm: avoid swapping out with swappiness==0") we do not swap when swappiness is 0 which means that we cannot really use up all the totalpages pages. This in turn confuses oom score calculation if the memcg limit is much smaller than the available swap because the used memory (capped by the limit) is negligible comparing to totalpages so the resulting score is too small if adj!=0 (typically task with CAP_SYS_ADMIN or non zero oom_score_adj). A wrong process might be selected as result. The problem can be worked around by checking mem_cgroup_swappiness==0 and not considering swap at all in such a case. Signed-off-by: Michal Hocko Acked-by: David Rientjes Acked-by: Johannes Weiner Acked-by: KOSAKI Motohiro Acked-by: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- Documentation/cgroups/memory.txt | 4 ++++ mm/memcontrol.c | 21 +++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index 9b1067afb22..68c5411d70a 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -466,6 +466,10 @@ Note: 5.3 swappiness Similar to /proc/sys/vm/swappiness, but affecting a hierarchy of groups only. +Please note that unlike the global swappiness, memcg knob set to 0 +really prevents from any swapping even if there is a swap storage +available. This might lead to memcg OOM killer if there are no file +pages to reclaim. Following cgroups' swappiness can't be changed. - root cgroup (uses /proc/sys/vm/swappiness). diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 7685d4a0b3c..81c275b3afe 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1489,17 +1489,26 @@ static int mem_cgroup_count_children(struct mem_cgroup *memcg) u64 mem_cgroup_get_limit(struct mem_cgroup *memcg) { u64 limit; - u64 memsw; limit = res_counter_read_u64(&memcg->res, RES_LIMIT); - limit += total_swap_pages << PAGE_SHIFT; - memsw = res_counter_read_u64(&memcg->memsw, RES_LIMIT); /* - * If memsw is finite and limits the amount of swap space available - * to this memcg, return that limit. + * Do not consider swap space if we cannot swap due to swappiness */ - return min(limit, memsw); + if (mem_cgroup_swappiness(memcg)) { + u64 memsw; + + limit += total_swap_pages << PAGE_SHIFT; + memsw = res_counter_read_u64(&memcg->memsw, RES_LIMIT); + + /* + * If memsw is finite and limits the amount of swap space + * available to this memcg, return that limit. + */ + limit = min(limit, memsw); + } + + return limit; } static unsigned long mem_cgroup_reclaim(struct mem_cgroup *memcg, From dd361b498741bd9b23a2f2238cf1c6af6cd49b67 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 12 Nov 2012 10:51:34 +0100 Subject: [PATCH 1474/2357] wireless: allow 40 MHz on world roaming channels 12/13 commit 43c771a1963ab461a2f194e3c97fded1d5fe262f upstream. When in world roaming mode, allow 40 MHz to be used on channels 12 and 13 so that an AP that is, e.g., using HT40+ on channel 9 (in the UK) can be used. Reported-by: Eddie Chapman Tested-by: Eddie Chapman Acked-by: Luis R. Rodriguez Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b01449f01bb..4dc83474db2 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -134,9 +134,8 @@ static const struct ieee80211_regdomain world_regdom = { .reg_rules = { /* IEEE 802.11b/g, channels 1..11 */ REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), - /* IEEE 802.11b/g, channels 12..13. No HT40 - * channel fits here. */ - REG_RULE(2467-10, 2472+10, 20, 6, 20, + /* IEEE 802.11b/g, channels 12..13. */ + REG_RULE(2467-10, 2472+10, 40, 6, 20, NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), /* IEEE 802.11 channel 14 - Only JP enables From 999d6a5194c9707b081869f40306ac5e1727edf4 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Sat, 17 Nov 2012 22:27:04 +0100 Subject: [PATCH 1475/2357] m68k: fix sigset_t accessor functions commit 34fa78b59c52d1db3513db4c1a999db26b2e9ac2 upstream. The sigaddset/sigdelset/sigismember functions that are implemented with bitfield insn cannot allow the sigset argument to be placed in a data register since the sigset is wider than 32 bits. Remove the "d" constraint from the asm statements. The effect of the bug is that sending RT signals does not work, the signal number is truncated modulo 32. Signed-off-by: Andreas Schwab Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- arch/m68k/include/asm/signal.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h index 60e88660169..93fe83e7ffb 100644 --- a/arch/m68k/include/asm/signal.h +++ b/arch/m68k/include/asm/signal.h @@ -156,7 +156,7 @@ typedef struct sigaltstack { static inline void sigaddset(sigset_t *set, int _sig) { asm ("bfset %0{%1,#1}" - : "+od" (*set) + : "+o" (*set) : "id" ((_sig - 1) ^ 31) : "cc"); } @@ -164,7 +164,7 @@ static inline void sigaddset(sigset_t *set, int _sig) static inline void sigdelset(sigset_t *set, int _sig) { asm ("bfclr %0{%1,#1}" - : "+od" (*set) + : "+o" (*set) : "id" ((_sig - 1) ^ 31) : "cc"); } @@ -180,7 +180,7 @@ static inline int __gen_sigismember(sigset_t *set, int _sig) int ret; asm ("bfextu %1{%2,#1},%0" : "=d" (ret) - : "od" (*set), "id" ((_sig-1) ^ 31) + : "o" (*set), "id" ((_sig-1) ^ 31) : "cc"); return ret; } From 0fa89335e494872552e8e1d4e594c18559922e5c Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Sun, 11 Nov 2012 11:20:01 +0000 Subject: [PATCH 1476/2357] ipv4: avoid undefined behavior in do_ip_setsockopt() [ Upstream commit 0c9f79be295c99ac7e4b569ca493d75fdcc19e4e ] (1< Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_sockglue.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 2fd0fba7712..59ef40abf50 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -456,19 +456,28 @@ static int do_ip_setsockopt(struct sock *sk, int level, struct inet_sock *inet = inet_sk(sk); int val = 0, err; - if (((1<= sizeof(int)) { if (get_user(val, (int __user *) optval)) return -EFAULT; From 798f49e632f38abcb51dea6014b078798c1cc6ee Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Sat, 10 Nov 2012 19:52:34 +0000 Subject: [PATCH 1477/2357] ipv6: setsockopt(IPIPPROTO_IPV6, IPV6_MINHOPCOUNT) forgot to set return value [ Upstream commit d4596bad2a713fcd0def492b1960e6d899d5baa8 ] Cc: Stephen Hemminger Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ipv6_sockglue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 63dd1f89ed7..34c1109d346 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -828,6 +828,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, if (val < 0 || val > 255) goto e_inval; np->min_hopcount = val; + retv = 0; break; case IPV6_DONTFRAG: np->dontfrag = valbool; From 4e95708469b3b36b123c9ebfe4fed2b9de601e7a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 14 Nov 2012 02:51:04 +0000 Subject: [PATCH 1478/2357] net: correct check in dev_addr_del() [ Upstream commit a652208e0b52c190e57f2a075ffb5e897fe31c3b ] Check (ha->addr == dev->dev_addr) is always true because dev_addr_init() sets this. Correct the check to behave properly on addr removal. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev_addr_lists.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index 626698f0db8..76f6d0b02f2 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c @@ -308,7 +308,8 @@ int dev_addr_del(struct net_device *dev, unsigned char *addr, */ ha = list_first_entry(&dev->dev_addrs.list, struct netdev_hw_addr, list); - if (ha->addr == dev->dev_addr && ha->refcount == 1) + if (!memcmp(ha->addr, addr, dev->addr_len) && + ha->type == addr_type && ha->refcount == 1) return -ENOENT; err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len, From f86c309e326f800e8fb028df35051aac5a26ef8d Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Fri, 16 Nov 2012 09:04:15 +0000 Subject: [PATCH 1479/2357] net-rps: Fix brokeness causing OOO packets [ Upstream commit baefa31db2f2b13a05d1b81bdf2d20d487f58b0a ] In commit c445477d74ab3779 which adds aRFS to the kernel, the CPU selected for RFS is not set correctly when CPU is changing. This is causing OOO packets and probably other issues. Signed-off-by: Tom Herbert Acked-by: Eric Dumazet Acked-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 24a21f36a47..eb858dc6ab8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2763,8 +2763,10 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, if (unlikely(tcpu != next_cpu) && (tcpu == RPS_NO_CPU || !cpu_online(tcpu) || ((int)(per_cpu(softnet_data, tcpu).input_queue_head - - rflow->last_qtail)) >= 0)) + rflow->last_qtail)) >= 0)) { + tcpu = next_cpu; rflow = set_rps_cpu(dev, skb, rflow, next_cpu); + } if (tcpu != RPS_NO_CPU && cpu_online(tcpu)) { *rflowp = rflow; From ec5924204b7fa09a679c4456ac8e2176a2950ce6 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Fri, 16 Nov 2012 14:15:04 -0800 Subject: [PATCH 1480/2357] tmpfs: change final i_blocks BUG to WARNING commit 0f3c42f522dc1ad7e27affc0a4aa8c790bce0a66 upstream. Under a particular load on one machine, I have hit shmem_evict_inode()'s BUG_ON(inode->i_blocks), enough times to narrow it down to a particular race between swapout and eviction. It comes from the "if (freed > 0)" asymmetry in shmem_recalc_inode(), and the lack of coherent locking between mapping's nrpages and shmem's swapped count. There's a window in shmem_writepage(), between lowering nrpages in shmem_delete_from_page_cache() and then raising swapped count, when the freed count appears to be +1 when it should be 0, and then the asymmetry stops it from being corrected with -1 before hitting the BUG. One answer is coherent locking: using tree_lock throughout, without info->lock; reasonable, but the raw_spin_lock in percpu_counter_add() on used_blocks makes that messier than expected. Another answer may be a further effort to eliminate the weird shmem_recalc_inode() altogether, but previous attempts at that failed. So far undecided, but for now change the BUG_ON to WARN_ON: in usual circumstances it remains a useful consistency check. Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/shmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/shmem.c b/mm/shmem.c index 40383cddc91..a859b06d573 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -595,7 +595,7 @@ static void shmem_evict_inode(struct inode *inode) kfree(xattr->name); kfree(xattr); } - BUG_ON(inode->i_blocks); + WARN_ON(inode->i_blocks); shmem_free_inode(inode->i_sb); end_writeback(inode); } From 56cb8f7e4324410e9acb0b307efd2f846c06cf69 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Sun, 9 Sep 2012 13:55:26 +0000 Subject: [PATCH 1481/2357] r8169: use unlimited DMA burst for TX commit aee77e4accbeb2c86b1d294cd84fec4a12dde3bd upstream. The r8169 driver currently limits the DMA burst for TX to 1024 bytes. I have a box where this prevents the interface from using the gigabit line to its full potential. This patch solves the problem by setting TX_DMA_BURST to unlimited. The box has an ASRock B75M motherboard with on-board RTL8168evl/8111evl (XID 0c900880). TSO is enabled. I used netperf (TCP_STREAM test) to measure the dependency of TX throughput on MTU. I did it for three different values of TX_DMA_BURST ('5'=512, '6'=1024, '7'=unlimited). This chart shows the results: http://michich.fedorapeople.org/r8169/r8169-effects-of-TX_DMA_BURST.png Interesting points: - With the current DMA burst limit (1024): - at the default MTU=1500 I get only 842 Mbit/s. - when going from small MTU, the performance rises monotonically with increasing MTU only up to a peak at MTU=1076 (908 MBit/s). Then there's a sudden drop to 762 MBit/s from which the throughput rises monotonically again with further MTU increases. - With a smaller DMA burst limit (512): - there's a similar peak at MTU=1076 and another one at MTU=564. - With unlimited DMA burst: - at the default MTU=1500 I get nice 940 Mbit/s. - the throughput rises monotonically with increasing MTU with no strange peaks. Notice that the peaks occur at MTU sizes that are multiples of the DMA burst limit plus 52. Why 52? Because: 20 (IP header) + 20 (TCP header) + 12 (TCP options) = 52 The Realtek-provided r8168 driver (v8.032.00) uses unlimited TX DMA burst too, except for CFG_METHOD_1 where the TX DMA burst is set to 512 bytes. CFG_METHOD_1 appears to be the oldest MAC version of "RTL8168B/8111B", i.e. RTL_GIGA_MAC_VER_11 in r8169. Not sure if this MAC version really needs the smaller burst limit, or if any other versions have similar requirements. Signed-off-by: Michal Schmidt Acked-by: Francois Romieu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 482dcd3a7ad..3fd8cdeeccd 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -73,7 +73,7 @@ static const int multicast_filter_limit = 32; #define MAX_READ_REQUEST_SHIFT 12 -#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ +#define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */ #define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ From f5a93eaffacc75908abcb9b94e2367a824d5953f Mon Sep 17 00:00:00 2001 From: Mojiong Qiu Date: Tue, 6 Nov 2012 16:08:15 +0800 Subject: [PATCH 1482/2357] xen/events: fix RCU warning, or Call idle notifier after irq_enter() commit 772aebcefeff310f80e32b874988af0076cb799d upstream. exit_idle() should be called after irq_enter(), otherwise it throws: [ INFO: suspicious RCU usage. ] 3.6.5 #1 Not tainted ------------------------------- include/linux/rcupdate.h:725 rcu_read_lock() used illegally while idle! other info that might help us debug this: RCU used illegally from idle CPU! rcu_scheduler_active = 1, debug_locks = 1 RCU used illegally from extended quiescent state! 1 lock held by swapper/0/0: #0: (rcu_read_lock){......}, at: [] __atomic_notifier_call_chain+0x0/0x140 stack backtrace: Pid: 0, comm: swapper/0 Not tainted 3.6.5 #1 Call Trace: [] lockdep_rcu_suspicious+0xe2/0x130 [] __atomic_notifier_call_chain+0x12c/0x140 [] ? atomic_notifier_chain_unregister+0x90/0x90 [] ? trace_hardirqs_off+0xd/0x10 [] atomic_notifier_call_chain+0x16/0x20 [] exit_idle+0x43/0x50 [] xen_evtchn_do_upcall+0x25/0x50 [] xen_do_hypervisor_callback+0x1e/0x30 [] ? hypercall_page+0x3aa/0x1000 [] ? hypercall_page+0x3aa/0x1000 [] ? xen_safe_halt+0x10/0x20 [] ? default_idle+0xba/0x570 [] ? cpu_idle+0xdf/0x140 [] ? rest_init+0x135/0x144 [] ? csum_partial_copy_generic+0x16c/0x16c [] ? start_kernel+0x3db/0x3e8 [] ? repair_env_string+0x5a/0x5a [] ? x86_64_start_reservations+0x131/0x135 [] ? xen_start_kernel+0x465/0x46 Git commit 98ad1cc14a5c4fd658f9d72c6ba5c86dfd3ce0d5 Author: Frederic Weisbecker Date: Fri Oct 7 18:22:09 2011 +0200 x86: Call idle notifier after irq_enter() did this, but it missed the Xen code. Signed-off-by: Mojiong Qiu Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 6908e4ce2a0..26c47a4c426 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1365,8 +1365,8 @@ void xen_evtchn_do_upcall(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); - exit_idle(); irq_enter(); + exit_idle(); __xen_evtchn_do_upcall(); From cfc2c996141d487273c63af8954a3f3f03b16229 Mon Sep 17 00:00:00 2001 From: Cyril Brulebois Date: Wed, 31 Oct 2012 14:00:46 +0000 Subject: [PATCH 1483/2357] r8169: Fix WoL on RTL8168d/8111d. commit b00e69dee4ccbb3a19989e3d4f1385bc2e3406cd upstream. This regression was spotted between Debian squeeze and Debian wheezy kernels (respectively based on 2.6.32 and 3.2). More info about Wake-on-LAN issues with Realtek's 816x chipsets can be found in the following thread: http://marc.info/?t=132079219400004 Probable regression from d4ed95d796e5126bba51466dc07e287cebc8bd19; more chipsets are likely affected. Tested on top of a 3.2.23 kernel. Reported-by: Florent Fourcot Tested-by: Florent Fourcot Hinted-by: Francois Romieu Signed-off-by: Cyril Brulebois Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 3fd8cdeeccd..74a516c7213 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -3488,6 +3488,8 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_25: + case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_29: case RTL_GIGA_MAC_VER_30: case RTL_GIGA_MAC_VER_32: From 1b10e0be50067689f53e566d5e1cfad6170e89c3 Mon Sep 17 00:00:00 2001 From: Nathan Walp Date: Thu, 1 Nov 2012 12:08:47 +0000 Subject: [PATCH 1484/2357] r8169: allow multicast packets on sub-8168f chipset. commit 0481776b7a70f09acf7d9d97c288c3a8403fbfe4 upstream. RTL_GIGA_MAC_VER_35 includes no multicast hardware filter. Signed-off-by: Nathan Walp Suggested-by: Hayes Wang Acked-by: Francois Romieu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 74a516c7213..0dc70c21767 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -4131,6 +4131,9 @@ static void rtl_set_rx_mode(struct net_device *dev) mc_filter[1] = swab32(data); } + if (tp->mac_version == RTL_GIGA_MAC_VER_35) + mc_filter[1] = mc_filter[0] = 0xffffffff; + RTL_W32(MAR0 + 4, mc_filter[1]); RTL_W32(MAR0 + 0, mc_filter[0]); From c581c7c77d5685829bf620dc6e194e2aa2afae00 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Fri, 31 Aug 2012 09:55:54 +0000 Subject: [PATCH 1485/2357] netfilter: Validate the sequence number of dataless ACK packets as well commit 4a70bbfaef0361d27272629d1a250a937edcafe4 upstream. We spare nothing by not validating the sequence number of dataless ACK packets and enabling it makes harder off-path attacks. See: "Reflection scan: an Off-Path Attack on TCP" by Jan Wrobel, http://arxiv.org/abs/1201.2074 Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_conntrack_proto_tcp.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 0d07a1dcf60..5644c8468d0 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -627,15 +627,9 @@ static bool tcp_in_window(const struct nf_conn *ct, ack = sack = receiver->td_end; } - if (seq == end - && (!tcph->rst - || (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT))) + if (tcph->rst && seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT) /* - * Packets contains no data: we assume it is valid - * and check the ack value only. - * However RST segments are always validated by their - * SEQ number, except when seq == 0 (reset sent answering - * SYN. + * RST sent answering SYN. */ seq = end = sender->td_end; From b3e991ea9222c3ec71d74b37d105cea115055c4d Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Fri, 31 Aug 2012 09:55:53 +0000 Subject: [PATCH 1486/2357] netfilter: Mark SYN/ACK packets as invalid from original direction commit 64f509ce71b08d037998e93dd51180c19b2f464c upstream. Clients should not send such packets. By accepting them, we open up a hole by wich ephemeral ports can be discovered in an off-path attack. See: "Reflection scan: an Off-Path Attack on TCP" by Jan Wrobel, http://arxiv.org/abs/1201.2074 Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_conntrack_proto_tcp.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 5644c8468d0..e0221238e74 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -158,21 +158,18 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sCL -> sSS */ /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ -/*synack*/ { sIV, sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, sSR }, +/*synack*/ { sIV, sIV, sSR, sIV, sIV, sIV, sIV, sIV, sIV, sSR }, /* * sNO -> sIV Too late and no reason to do anything * sSS -> sIV Client can't send SYN and then SYN/ACK * sS2 -> sSR SYN/ACK sent to SYN2 in simultaneous open - * sSR -> sIG - * sES -> sIG Error: SYNs in window outside the SYN_SENT state - * are errors. Receiver will reply with RST - * and close the connection. - * Or we are not in sync and hold a dead connection. - * sFW -> sIG - * sCW -> sIG - * sLA -> sIG - * sTW -> sIG - * sCL -> sIG + * sSR -> sSR Late retransmitted SYN/ACK in simultaneous open + * sES -> sIV Invalid SYN/ACK packets sent by the client + * sFW -> sIV + * sCW -> sIV + * sLA -> sIV + * sTW -> sIV + * sCL -> sIV */ /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, From a39bdce2f2a9aebda1b9438c4b2e91c0dd507a34 Mon Sep 17 00:00:00 2001 From: Ulrich Weber Date: Thu, 25 Oct 2012 05:34:45 +0000 Subject: [PATCH 1487/2357] netfilter: nf_nat: don't check for port change on ICMP tuples commit 38fe36a248ec3228f8e6507955d7ceb0432d2000 upstream. ICMP tuples have id in src and type/code in dst. So comparing src.u.all with dst.u.all will always fail here and ip_xfrm_me_harder() is called for every ICMP packet, even if there was no NAT. Signed-off-by: Ulrich Weber Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/ipv4/netfilter/nf_nat_standalone.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 3828a422982..da4098f0878 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -194,7 +194,8 @@ nf_nat_out(unsigned int hooknum, if ((ct->tuplehash[dir].tuple.src.u3.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) || - (ct->tuplehash[dir].tuple.src.u.all != + (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && + ct->tuplehash[dir].tuple.src.u.all != ct->tuplehash[!dir].tuple.dst.u.all) ) return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP; @@ -230,7 +231,8 @@ nf_nat_local_fn(unsigned int hooknum, ret = NF_DROP; } #ifdef CONFIG_XFRM - else if (ct->tuplehash[dir].tuple.dst.u.all != + else if (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && + ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[!dir].tuple.src.u.all) if (ip_xfrm_me_harder(skb)) ret = NF_DROP; From 9dbd3418ff461025e904e65326aeeb5389f65799 Mon Sep 17 00:00:00 2001 From: Jan Safrata Date: Tue, 22 May 2012 14:04:50 +0200 Subject: [PATCH 1488/2357] usb: use usb_serial_put in usb_serial_probe errors commit 0658a3366db7e27fa32c12e886230bb58c414c92 upstream. The use of kfree(serial) in error cases of usb_serial_probe was invalid - usb_serial structure allocated in create_serial() gets reference of usb_device that needs to be put, so we need to use usb_serial_put() instead of simple kfree(). Signed-off-by: Jan Safrata Acked-by: Johan Hovold Cc: Richard Retanubun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index bcf261778d0..c627ba21b1e 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -768,7 +768,7 @@ int usb_serial_probe(struct usb_interface *interface, if (retval) { dbg("sub driver rejected device"); - kfree(serial); + usb_serial_put(serial); module_put(type->driver.owner); return retval; } @@ -840,7 +840,7 @@ int usb_serial_probe(struct usb_interface *interface, */ if (num_bulk_in == 0 || num_bulk_out == 0) { dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); - kfree(serial); + usb_serial_put(serial); module_put(type->driver.owner); return -ENODEV; } @@ -854,7 +854,7 @@ int usb_serial_probe(struct usb_interface *interface, if (num_ports == 0) { dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); - kfree(serial); + usb_serial_put(serial); module_put(type->driver.owner); return -EIO; } From c8a1ae7c0030e936470a4701a46f775a2bc7012b Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Mon, 11 Jun 2012 15:42:32 -0700 Subject: [PATCH 1489/2357] eCryptfs: Copy up POSIX ACL and read-only flags from lower mount commit 069ddcda37b2cf5bb4b6031a944c0e9359213262 upstream. When the eCryptfs mount options do not include '-o acl', but the lower filesystem's mount options do include 'acl', the MS_POSIXACL flag is not flipped on in the eCryptfs super block flags. This flag is what the VFS checks in do_last() when deciding if the current umask should be applied to a newly created inode's mode or not. When a default POSIX ACL mask is set on a directory, the current umask is incorrectly applied to new inodes created in the directory. This patch ignores the MS_POSIXACL flag passed into ecryptfs_mount() and sets the flag on the eCryptfs super block depending on the flag's presence on the lower super block. Additionally, it is incorrect to allow a writeable eCryptfs mount on top of a read-only lower mount. This missing check did not allow writes to the read-only lower mount because permissions checks are still performed on the lower filesystem's objects but it is best to simply not allow a rw mount on top of ro mount. However, a ro eCryptfs mount on top of a rw mount is valid and still allowed. https://launchpad.net/bugs/1009207 Signed-off-by: Tyler Hicks Reported-by: Stefan Beller Cc: John Johansen Cc: Herton Ronaldo Krzesinski Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 0f04d2eb9a6..c2a9c39300c 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -506,7 +506,6 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags goto out; } - s->s_flags = flags; rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs", BDI_CAP_MAP_COPY); if (rc) goto out1; @@ -542,6 +541,15 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags } ecryptfs_set_superblock_lower(s, path.dentry->d_sb); + + /** + * Set the POSIX ACL flag based on whether they're enabled in the lower + * mount. Force a read-only eCryptfs mount if the lower mount is ro. + * Allow a ro eCryptfs mount even when the lower mount is rw. + */ + s->s_flags = flags & ~MS_POSIXACL; + s->s_flags |= path.dentry->d_sb->s_flags & (MS_RDONLY | MS_POSIXACL); + s->s_maxbytes = path.dentry->d_sb->s_maxbytes; s->s_blocksize = path.dentry->d_sb->s_blocksize; s->s_magic = ECRYPTFS_SUPER_MAGIC; From 122fd46fccafa6d839118815141179f1a90cfb48 Mon Sep 17 00:00:00 2001 From: Tim Sally Date: Thu, 12 Jul 2012 19:10:24 -0400 Subject: [PATCH 1490/2357] eCryptfs: check for eCryptfs cipher support at mount commit 5f5b331d5c21228a6519dcb793fc1629646c51a6 upstream. The issue occurs when eCryptfs is mounted with a cipher supported by the crypto subsystem but not by eCryptfs. The mount succeeds and an error does not occur until a write. This change checks for eCryptfs cipher support at mount time. Resolves Launchpad issue #338914, reported by Tyler Hicks in 03/2009. https://bugs.launchpad.net/ecryptfs/+bug/338914 Signed-off-by: Tim Sally Signed-off-by: Tyler Hicks Cc: Herton Ronaldo Krzesinski Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index c2a9c39300c..240832e8b28 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -280,6 +280,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, char *fnek_src; char *cipher_key_bytes_src; char *fn_cipher_key_bytes_src; + u8 cipher_code; *check_ruid = 0; @@ -421,6 +422,18 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, && !fn_cipher_key_bytes_set) mount_crypt_stat->global_default_fn_cipher_key_bytes = mount_crypt_stat->global_default_cipher_key_size; + + cipher_code = ecryptfs_code_for_cipher_string( + mount_crypt_stat->global_default_cipher_name, + mount_crypt_stat->global_default_cipher_key_size); + if (!cipher_code) { + ecryptfs_printk(KERN_ERR, + "eCryptfs doesn't support cipher: %s", + mount_crypt_stat->global_default_cipher_name); + rc = -EINVAL; + goto out; + } + mutex_lock(&key_tfm_list_mutex); if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name, NULL)) { From 39220c9e67cbfbc1a7ac17a51afd77eb06b62fa9 Mon Sep 17 00:00:00 2001 From: Mirko Lindner Date: Tue, 3 Jul 2012 23:38:46 +0000 Subject: [PATCH 1491/2357] sky2: Fix for interrupt handler commit d663d181b9e92d80c2455e460e932d34e7a2a7ae upstream. Re-enable interrupts if it is not our interrupt Signed-off-by: Mirko Lindner Signed-off-by: David S. Miller Cc: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/marvell/sky2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 589753fb673..2b78ddd5d63 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -3079,8 +3079,10 @@ static irqreturn_t sky2_intr(int irq, void *dev_id) /* Reading this mask interrupts as side effect */ status = sky2_read32(hw, B0_Y2_SP_ISRC2); - if (status == 0 || status == ~0) + if (status == 0 || status == ~0) { + sky2_write32(hw, B0_Y2_SP_ICR, 2); return IRQ_NONE; + } prefetch(&hw->st_le[hw->st_idx]); From 37a42f991f36aae9b064bc3f39b760006bd17131 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 7 Nov 2012 10:44:08 +0100 Subject: [PATCH 1492/2357] s390/signal: set correct address space control commit fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2f upstream. If user space is running in primary mode it can switch to secondary or access register mode, this is used e.g. in the clock_gettime code of the vdso. If a signal is delivered to the user space process while it has been running in access register mode the signal handler is executed in access register mode as well which will result in a crash most of the time. Set the address space control bits in the PSW to the default for the execution of the signal handler and make sure that the previous address space control is restored on signal return. Take care that user space can not switch to the kernel address space by modifying the registers in the signal frame. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/compat.h | 2 +- arch/s390/include/asm/ptrace.h | 4 ++-- arch/s390/kernel/compat_signal.c | 14 ++++++++++++-- arch/s390/kernel/signal.c | 14 ++++++++++++-- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index 234f1d859ce..2e0a15b4359 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -20,7 +20,7 @@ #define PSW32_MASK_CC 0x00003000UL #define PSW32_MASK_PM 0x00000f00UL -#define PSW32_MASK_USER 0x00003F00UL +#define PSW32_MASK_USER 0x0000FF00UL #define PSW32_ADDR_AMODE 0x80000000UL #define PSW32_ADDR_INSN 0x7FFFFFFFUL diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index aeb77f01798..d3750e79fcc 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -240,7 +240,7 @@ typedef struct #define PSW_MASK_EA 0x00000000UL #define PSW_MASK_BA 0x00000000UL -#define PSW_MASK_USER 0x00003F00UL +#define PSW_MASK_USER 0x0000FF00UL #define PSW_ADDR_AMODE 0x80000000UL #define PSW_ADDR_INSN 0x7FFFFFFFUL @@ -269,7 +269,7 @@ typedef struct #define PSW_MASK_EA 0x0000000100000000UL #define PSW_MASK_BA 0x0000000080000000UL -#define PSW_MASK_USER 0x00003F0180000000UL +#define PSW_MASK_USER 0x0000FF0180000000UL #define PSW_ADDR_AMODE 0x0000000000000000UL #define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 28040fd5e8a..0bdca3ac9a6 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -313,6 +313,10 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 | (__u64)(regs32.psw.addr & PSW32_ADDR_AMODE); + /* Check for invalid user address space control. */ + if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC)) + regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) | + (regs->psw.mask & ~PSW_MASK_ASC); regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN); for (i = 0; i < NUM_GPRS; i++) regs->gprs[i] = (__u64) regs32.gprs[i]; @@ -494,7 +498,10 @@ static int setup_frame32(int sig, struct k_sigaction *ka, /* Set up registers for signal handler */ regs->gprs[15] = (__force __u64) frame; - regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */ + /* Force 31 bit amode and default user address space control. */ + regs->psw.mask = PSW_MASK_BA | + (psw_user_bits & PSW_MASK_ASC) | + (regs->psw.mask & ~PSW_MASK_ASC); regs->psw.addr = (__force __u64) ka->sa.sa_handler; regs->gprs[2] = map_signal(sig); @@ -562,7 +569,10 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, /* Set up registers for signal handler */ regs->gprs[15] = (__force __u64) frame; - regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */ + /* Force 31 bit amode and default user address space control. */ + regs->psw.mask = PSW_MASK_BA | + (psw_user_bits & PSW_MASK_ASC) | + (regs->psw.mask & ~PSW_MASK_ASC); regs->psw.addr = (__u64) ka->sa.sa_handler; regs->gprs[2] = map_signal(sig); diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index f7582b27f60..74f58e211ac 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -148,6 +148,10 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) /* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */ regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | (user_sregs.regs.psw.mask & PSW_MASK_USER); + /* Check for invalid user address space control. */ + if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC)) + regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) | + (regs->psw.mask & ~PSW_MASK_ASC); /* Check for invalid amode */ if (regs->psw.mask & PSW_MASK_EA) regs->psw.mask |= PSW_MASK_BA; @@ -294,7 +298,10 @@ static int setup_frame(int sig, struct k_sigaction *ka, /* Set up registers for signal handler */ regs->gprs[15] = (unsigned long) frame; - regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */ + /* Force default amode and default user address space control. */ + regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | + (psw_user_bits & PSW_MASK_ASC) | + (regs->psw.mask & ~PSW_MASK_ASC); regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; regs->gprs[2] = map_signal(sig); @@ -367,7 +374,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* Set up registers for signal handler */ regs->gprs[15] = (unsigned long) frame; - regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */ + /* Force default amode and default user address space control. */ + regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | + (psw_user_bits & PSW_MASK_ASC) | + (regs->psw.mask & ~PSW_MASK_ASC); regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; regs->gprs[2] = map_signal(sig); From d1b28a26ed24cec32801bfddb48796f914f48d47 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 22 Oct 2012 12:55:55 +0200 Subject: [PATCH 1493/2357] drm/i915: fix overlay on i830M MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a9193983f4f292a82a00c72971c17ec0ee8c6c15 upstream. The overlay on the i830M has a peculiar failure mode: It works the first time around after boot-up, but consistenly hangs the second time it's used. Chris Wilson has dug out a nice errata: "1.5.12 Clock Gating Disable for Display Register Address Offset: 06200h–06203h "Bit 3 Ovrunit Clock Gating Disable. 0 = Clock gating controlled by unit enabling logic 1 = Disable clock gating function DevALM Errata ALM049: Overlay Clock Gating Must be Disabled: Overlay & L2 Cache clock gating must be disabled in order to prevent device hangs when turning off overlay.SW must turn off Ovrunit clock gating (6200h) and L2 Cache clock gating (C8h)." Now I've nowhere found that 0xc8 register and hence couldn't apply the l2 cache workaround. But I've remembered that part of the magic that the OVERLAY_ON/OFF commands are supposed to do is to rearrange cache allocations so that the overlay scaler has some scratch space. And while pondering how that could explain the hang the 2nd time we enable the overlay, I've remembered that the old ums overlay code did _not_ issue the OVERLAY_OFF cmd. And indeed, disabling the OFF cmd results in the overlay working flawlessly, so I guess we can workaround the lack of the above workaround by simply never disabling the overlay engine once it's enabled. Note that we have the first part of the above w/a already implemented in i830_init_clock_gating - leave that as-is to avoid surprises. v2: Add a comment in the code. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=47827 Tested-by: Rhys Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter [bwh: Backported to 3.2: - Adjust context - s/intel_ring_emit(ring, /OUT_RING(/] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_overlay.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 80b331c322f..5ba5e66fa07 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -427,9 +427,17 @@ static int intel_overlay_off(struct intel_overlay *overlay) OUT_RING(flip_addr); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); /* turn overlay off */ - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); - OUT_RING(flip_addr); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + if (IS_I830(dev)) { + /* Workaround: Don't disable the overlay fully, since otherwise + * it dies on the next OVERLAY_ON cmd. */ + OUT_RING(MI_NOOP); + OUT_RING(MI_NOOP); + OUT_RING(MI_NOOP); + } else { + OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); + OUT_RING(flip_addr); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + } ADVANCE_LP_RING(); return intel_overlay_do_wait_request(overlay, request, From 824904ce9efd5665024b03217372ca82170687d2 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Tue, 30 Oct 2012 16:06:35 -0400 Subject: [PATCH 1494/2357] NFS: Wait for session recovery to finish before returning commit 399f11c3d872bd748e1575574de265a6304c7c43 upstream. Currently, we will schedule session recovery and then return to the caller of nfs4_handle_exception. This works for most cases, but causes a hang on the following test case: Client Server ------ ------ Open file over NFS v4.1 Write to file Expire client Try to lock file The server will return NFS4ERR_BADSESSION, prompting the client to schedule recovery. However, the client will continue placing lock attempts and the open recovery never seems to be scheduled. The simplest solution is to wait for session recovery to run before retrying the lock. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5e801803072..8955e364200 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -307,8 +307,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc dprintk("%s ERROR: %d Reset session\n", __func__, errorcode); nfs4_schedule_session_recovery(clp->cl_session); - exception->retry = 1; - break; + goto wait_on_recovery; #endif /* defined(CONFIG_NFS_V4_1) */ case -NFS4ERR_FILE_OPEN: if (exception->timeout > HZ) { From 394cbbc4417c009f2831122e9d64c975c8249123 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 13 Nov 2012 14:55:52 +0100 Subject: [PATCH 1495/2357] reiserfs: Fix lock ordering during remount commit 3bb3e1fc47aca554e7e2cc4deeddc24750987ac2 upstream. When remounting reiserfs dquot_suspend() or dquot_resume() can be called. These functions take dqonoff_mutex which ranks above write lock so we have to drop it before calling into quota code. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/super.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 8b7616ef06d..f4f83bfc571 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1292,7 +1292,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) kfree(qf_names[i]); #endif err = -EINVAL; - goto out_err; + goto out_unlock; } #ifdef CONFIG_QUOTA handle_quota_files(s, qf_names, &qfmt); @@ -1336,7 +1336,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) if (blocks) { err = reiserfs_resize(s, blocks); if (err != 0) - goto out_err; + goto out_unlock; } if (*mount_flags & MS_RDONLY) { @@ -1346,9 +1346,15 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) /* it is read-only already */ goto out_ok; + /* + * Drop write lock. Quota will retake it when needed and lock + * ordering requires calling dquot_suspend() without it. + */ + reiserfs_write_unlock(s); err = dquot_suspend(s, -1); if (err < 0) goto out_err; + reiserfs_write_lock(s); /* try to remount file system with read-only permissions */ if (sb_umount_state(rs) == REISERFS_VALID_FS @@ -1358,7 +1364,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) err = journal_begin(&th, s, 10); if (err) - goto out_err; + goto out_unlock; /* Mounting a rw partition read-only. */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); @@ -1373,7 +1379,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) if (reiserfs_is_journal_aborted(journal)) { err = journal->j_errno; - goto out_err; + goto out_unlock; } handle_data_mode(s, mount_options); @@ -1382,7 +1388,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) s->s_flags &= ~MS_RDONLY; /* now it is safe to call journal_begin */ err = journal_begin(&th, s, 10); if (err) - goto out_err; + goto out_unlock; /* Mount a partition which is read-only, read-write */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); @@ -1399,11 +1405,17 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) SB_JOURNAL(s)->j_must_wait = 1; err = journal_end(&th, s, 10); if (err) - goto out_err; + goto out_unlock; s->s_dirt = 0; if (!(*mount_flags & MS_RDONLY)) { + /* + * Drop write lock. Quota will retake it when needed and lock + * ordering requires calling dquot_resume() without it. + */ + reiserfs_write_unlock(s); dquot_resume(s, -1); + reiserfs_write_lock(s); finish_unfinished(s); reiserfs_xattr_init(s, *mount_flags); } @@ -1413,9 +1425,10 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) reiserfs_write_unlock(s); return 0; +out_unlock: + reiserfs_write_unlock(s); out_err: kfree(new_opts); - reiserfs_write_unlock(s); return err; } From 8ed4d1ceb26e7f1011314a4f2db93897fb8949e2 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 13 Nov 2012 16:34:17 +0100 Subject: [PATCH 1496/2357] reiserfs: Protect reiserfs_quota_on() with write lock commit b9e06ef2e8706fe669b51f4364e3aeed58639eb2 upstream. In reiserfs_quota_on() we do quite some work - for example unpacking tail of a quota file. Thus we have to hold write lock until a moment we call back into the quota code. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/super.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index f4f83bfc571..107f7bd75e9 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -2170,8 +2170,11 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, struct reiserfs_transaction_handle th; int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA; - if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) - return -EINVAL; + reiserfs_write_lock(sb); + if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) { + err = -EINVAL; + goto out; + } /* Quotafile not on the same filesystem? */ if (path->dentry->d_sb != sb) { @@ -2213,8 +2216,10 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, if (err) goto out; } - err = dquot_quota_on(sb, type, format_id, path); + reiserfs_write_unlock(sb); + return dquot_quota_on(sb, type, format_id, path); out: + reiserfs_write_unlock(sb); return err; } From 8c7dcc4819098b0166e4559fbfd6fa661fbb5755 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 13 Nov 2012 17:05:14 +0100 Subject: [PATCH 1497/2357] reiserfs: Move quota calls out of write lock commit 7af11686933726e99af22901d622f9e161404e6b upstream. Calls into highlevel quota code cannot happen under the write lock. These calls take dqio_mutex which ranks above write lock. So drop write lock before calling back into quota code. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/inode.c | 10 +++++++--- fs/reiserfs/stree.c | 4 ++++ fs/reiserfs/super.c | 18 ++++++++++++++---- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index f99c1b4fa5f..c11db5134b7 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1788,8 +1788,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, BUG_ON(!th->t_trans_id); - dquot_initialize(inode); + reiserfs_write_unlock(inode->i_sb); err = dquot_alloc_inode(inode); + reiserfs_write_lock(inode->i_sb); if (err) goto out_end_trans; if (!dir->i_nlink) { @@ -1985,8 +1986,10 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, out_end_trans: journal_end(th, th->t_super, th->t_blocks_allocated); + reiserfs_write_unlock(inode->i_sb); /* Drop can be outside and it needs more credits so it's better to have it outside */ dquot_drop(inode); + reiserfs_write_lock(inode->i_sb); inode->i_flags |= S_NOQUOTA; make_bad_inode(inode); @@ -3109,10 +3112,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) /* must be turned off for recursive notify_change calls */ ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); - depth = reiserfs_write_lock_once(inode->i_sb); if (is_quota_modification(inode, attr)) dquot_initialize(inode); - + depth = reiserfs_write_lock_once(inode->i_sb); if (attr->ia_valid & ATTR_SIZE) { /* version 2 items will be caught by the s_maxbytes check ** done for us in vmtruncate @@ -3176,7 +3178,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) error = journal_begin(&th, inode->i_sb, jbegin_count); if (error) goto out; + reiserfs_write_unlock_once(inode->i_sb, depth); error = dquot_transfer(inode, attr); + depth = reiserfs_write_lock_once(inode->i_sb); if (error) { journal_end(&th, inode->i_sb, jbegin_count); goto out; diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index f8afa4b162b..2f40a4c70a4 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -1968,7 +1968,9 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree key2type(&(key->on_disk_key))); #endif + reiserfs_write_unlock(inode->i_sb); retval = dquot_alloc_space_nodirty(inode, pasted_size); + reiserfs_write_lock(inode->i_sb); if (retval) { pathrelse(search_path); return retval; @@ -2061,9 +2063,11 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, "reiserquota insert_item(): allocating %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(ih)); #endif + reiserfs_write_unlock(inode->i_sb); /* We can't dirty inode here. It would be immediately written but * appropriate stat item isn't inserted yet... */ retval = dquot_alloc_space_nodirty(inode, quota_bytes); + reiserfs_write_lock(inode->i_sb); if (retval) { pathrelse(path); return retval; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 107f7bd75e9..72a06365e9d 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -256,7 +256,9 @@ static int finish_unfinished(struct super_block *s) retval = remove_save_link_only(s, &save_link_key, 0); continue; } + reiserfs_write_unlock(s); dquot_initialize(inode); + reiserfs_write_lock(s); if (truncate && S_ISDIR(inode->i_mode)) { /* We got a truncate request for a dir which is impossible. @@ -2062,13 +2064,15 @@ static int reiserfs_write_dquot(struct dquot *dquot) REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); if (ret) goto out; + reiserfs_write_unlock(dquot->dq_sb); ret = dquot_commit(dquot); + reiserfs_write_lock(dquot->dq_sb); err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); if (!ret && err) ret = err; - out: +out: reiserfs_write_unlock(dquot->dq_sb); return ret; } @@ -2084,13 +2088,15 @@ static int reiserfs_acquire_dquot(struct dquot *dquot) REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); if (ret) goto out; + reiserfs_write_unlock(dquot->dq_sb); ret = dquot_acquire(dquot); + reiserfs_write_lock(dquot->dq_sb); err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); if (!ret && err) ret = err; - out: +out: reiserfs_write_unlock(dquot->dq_sb); return ret; } @@ -2104,19 +2110,21 @@ static int reiserfs_release_dquot(struct dquot *dquot) ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); + reiserfs_write_unlock(dquot->dq_sb); if (ret) { /* Release dquot anyway to avoid endless cycle in dqput() */ dquot_release(dquot); goto out; } ret = dquot_release(dquot); + reiserfs_write_lock(dquot->dq_sb); err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); if (!ret && err) ret = err; - out: reiserfs_write_unlock(dquot->dq_sb); +out: return ret; } @@ -2141,11 +2149,13 @@ static int reiserfs_write_info(struct super_block *sb, int type) ret = journal_begin(&th, sb, 2); if (ret) goto out; + reiserfs_write_unlock(sb); ret = dquot_commit_info(sb, type); + reiserfs_write_lock(sb); err = journal_end(&th, sb, 2); if (!ret && err) ret = err; - out: +out: reiserfs_write_unlock(sb); return ret; } From a23d6310a6fbe4a2a1d3a40251a6d5b8ae39ec22 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 13 Nov 2012 18:25:38 +0100 Subject: [PATCH 1498/2357] reiserfs: Protect reiserfs_quota_write() with write lock commit 361d94a338a3fd0cee6a4ea32bbc427ba228e628 upstream. Calls into reiserfs journalling code and reiserfs_get_block() need to be protected with write lock. We remove write lock around calls to high level quota code in the next patch so these paths would suddently become unprotected. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/super.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 72a06365e9d..8169be93ac0 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -2303,7 +2303,9 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, tocopy = sb->s_blocksize - offset < towrite ? sb->s_blocksize - offset : towrite; tmp_bh.b_state = 0; + reiserfs_write_lock(sb); err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE); + reiserfs_write_unlock(sb); if (err) goto out; if (offset || tocopy != sb->s_blocksize) @@ -2319,10 +2321,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, flush_dcache_page(bh->b_page); set_buffer_uptodate(bh); unlock_buffer(bh); + reiserfs_write_lock(sb); reiserfs_prepare_for_journal(sb, bh, 1); journal_mark_dirty(current->journal_info, sb, bh); if (!journal_quota) reiserfs_add_ordered_list(inode, bh); + reiserfs_write_unlock(sb); brelse(bh); offset = 0; towrite -= tocopy; From 55649211861616c26aa25c9e710c5691837975e4 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 8 Nov 2012 16:09:27 -0800 Subject: [PATCH 1499/2357] selinux: fix sel_netnode_insert() suspicious rcu dereference commit 88a693b5c1287be4da937699cb82068ce9db0135 upstream. =============================== [ INFO: suspicious RCU usage. ] 3.5.0-rc1+ #63 Not tainted ------------------------------- security/selinux/netnode.c:178 suspicious rcu_dereference_check() usage! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 0 1 lock held by trinity-child1/8750: #0: (sel_netnode_lock){+.....}, at: [] sel_netnode_sid+0x16a/0x3e0 stack backtrace: Pid: 8750, comm: trinity-child1 Not tainted 3.5.0-rc1+ #63 Call Trace: [] lockdep_rcu_suspicious+0xfd/0x130 [] sel_netnode_sid+0x3b1/0x3e0 [] ? sel_netnode_find+0x1a0/0x1a0 [] selinux_socket_bind+0xf6/0x2c0 [] ? trace_hardirqs_off+0xd/0x10 [] ? lock_release_holdtime.part.9+0x15/0x1a0 [] ? lock_hrtimer_base+0x31/0x60 [] security_socket_bind+0x16/0x20 [] sys_bind+0x7a/0x100 [] ? sysret_check+0x22/0x5d [] ? trace_hardirqs_on_caller+0x10d/0x1a0 [] ? trace_hardirqs_on_thunk+0x3a/0x3f [] system_call_fastpath+0x16/0x1b This patch below does what Paul McKenney suggested in the previous thread. Signed-off-by: Dave Jones Reviewed-by: Paul E. McKenney Acked-by: Paul Moore Cc: Eric Paris Signed-off-by: Andrew Morton Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- security/selinux/netnode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 86365857c08..04aa5c8adf7 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c @@ -174,7 +174,8 @@ static void sel_netnode_insert(struct sel_netnode *node) if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) { struct sel_netnode *tail; tail = list_entry( - rcu_dereference(sel_netnode_hash[idx].list.prev), + rcu_dereference_protected(sel_netnode_hash[idx].list.prev, + lockdep_is_held(&sel_netnode_lock)), struct sel_netnode, list); list_del_rcu(&tail->list); kfree_rcu(tail, rcu); From 506b4672ace55889c16d4e9d5515e0c1ae7832d5 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 7 May 2012 15:38:35 -0700 Subject: [PATCH 1500/2357] crush: clean up types, const-ness (cherry picked from commit 8b12d47b80c7a34dffdd98244d99316db490ec58) Move various types from int -> __u32 (or similar), and add const as appropriate. This reflects changes that have been present in the userland implementation for some time. Reviewed-by: Alex Elder Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/crush/crush.h | 2 +- include/linux/crush/mapper.h | 6 +++--- net/ceph/crush/crush.c | 8 ++++---- net/ceph/crush/mapper.c | 31 ++++++++++++++++--------------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/include/linux/crush/crush.h b/include/linux/crush/crush.h index 97e435b191f..3f50369a50e 100644 --- a/include/linux/crush/crush.h +++ b/include/linux/crush/crush.h @@ -168,7 +168,7 @@ struct crush_map { /* crush.c */ -extern int crush_get_bucket_item_weight(struct crush_bucket *b, int pos); +extern int crush_get_bucket_item_weight(const struct crush_bucket *b, int pos); extern void crush_calc_parents(struct crush_map *map); extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b); extern void crush_destroy_bucket_list(struct crush_bucket_list *b); diff --git a/include/linux/crush/mapper.h b/include/linux/crush/mapper.h index c46b99c18bb..9322ab8bccd 100644 --- a/include/linux/crush/mapper.h +++ b/include/linux/crush/mapper.h @@ -10,11 +10,11 @@ #include "crush.h" -extern int crush_find_rule(struct crush_map *map, int pool, int type, int size); -extern int crush_do_rule(struct crush_map *map, +extern int crush_find_rule(const struct crush_map *map, int ruleset, int type, int size); +extern int crush_do_rule(const struct crush_map *map, int ruleno, int x, int *result, int result_max, int forcefeed, /* -1 for none */ - __u32 *weights); + const __u32 *weights); #endif diff --git a/net/ceph/crush/crush.c b/net/ceph/crush/crush.c index d6ebb13a18a..8dd19a0deed 100644 --- a/net/ceph/crush/crush.c +++ b/net/ceph/crush/crush.c @@ -26,9 +26,9 @@ const char *crush_bucket_alg_name(int alg) * @b: bucket pointer * @p: item index in bucket */ -int crush_get_bucket_item_weight(struct crush_bucket *b, int p) +int crush_get_bucket_item_weight(const struct crush_bucket *b, int p) { - if (p >= b->size) + if ((__u32)p >= b->size) return 0; switch (b->alg) { @@ -124,10 +124,9 @@ void crush_destroy_bucket(struct crush_bucket *b) */ void crush_destroy(struct crush_map *map) { - int b; - /* buckets */ if (map->buckets) { + __s32 b; for (b = 0; b < map->max_buckets; b++) { if (map->buckets[b] == NULL) continue; @@ -138,6 +137,7 @@ void crush_destroy(struct crush_map *map) /* rules */ if (map->rules) { + __u32 b; for (b = 0; b < map->max_rules; b++) kfree(map->rules[b]); kfree(map->rules); diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c index b79747c4b64..436102a8a46 100644 --- a/net/ceph/crush/mapper.c +++ b/net/ceph/crush/mapper.c @@ -32,9 +32,9 @@ * @type: storage ruleset type (user defined) * @size: output set size */ -int crush_find_rule(struct crush_map *map, int ruleset, int type, int size) +int crush_find_rule(const struct crush_map *map, int ruleset, int type, int size) { - int i; + __u32 i; for (i = 0; i < map->max_rules; i++) { if (map->rules[i] && @@ -72,7 +72,7 @@ static int bucket_perm_choose(struct crush_bucket *bucket, unsigned i, s; /* start a new permutation if @x has changed */ - if (bucket->perm_x != x || bucket->perm_n == 0) { + if (bucket->perm_x != (__u32)x || bucket->perm_n == 0) { dprintk("bucket %d new x=%d\n", bucket->id, x); bucket->perm_x = x; @@ -219,7 +219,7 @@ static int bucket_tree_choose(struct crush_bucket_tree *bucket, static int bucket_straw_choose(struct crush_bucket_straw *bucket, int x, int r) { - int i; + __u32 i; int high = 0; __u64 high_draw = 0; __u64 draw; @@ -262,7 +262,7 @@ static int crush_bucket_choose(struct crush_bucket *in, int x, int r) * true if device is marked "out" (failed, fully offloaded) * of the cluster */ -static int is_out(struct crush_map *map, __u32 *weight, int item, int x) +static int is_out(const struct crush_map *map, const __u32 *weight, int item, int x) { if (weight[item] >= 0x10000) return 0; @@ -287,16 +287,16 @@ static int is_out(struct crush_map *map, __u32 *weight, int item, int x) * @recurse_to_leaf: true if we want one device under each item of given type * @out2: second output vector for leaf items (if @recurse_to_leaf) */ -static int crush_choose(struct crush_map *map, +static int crush_choose(const struct crush_map *map, struct crush_bucket *bucket, - __u32 *weight, + const __u32 *weight, int x, int numrep, int type, int *out, int outpos, int firstn, int recurse_to_leaf, int *out2) { int rep; - int ftotal, flocal; + unsigned int ftotal, flocal; int retry_descent, retry_bucket, skip_rep; struct crush_bucket *in = bucket; int r; @@ -304,7 +304,7 @@ static int crush_choose(struct crush_map *map, int item = 0; int itemtype; int collide, reject; - const int orig_tries = 5; /* attempts before we fall back to search */ + const unsigned int orig_tries = 5; /* attempts before we fall back to search */ dprintk("CHOOSE%s bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "", bucket->id, x, outpos, numrep); @@ -325,7 +325,7 @@ static int crush_choose(struct crush_map *map, r = rep; if (in->alg == CRUSH_BUCKET_UNIFORM) { /* be careful */ - if (firstn || numrep >= in->size) + if (firstn || (__u32)numrep >= in->size) /* r' = r + f_total */ r += ftotal; else if (in->size % numrep == 0) @@ -425,7 +425,7 @@ static int crush_choose(struct crush_map *map, /* else give up */ skip_rep = 1; dprintk(" reject %d collide %d " - "ftotal %d flocal %d\n", + "ftotal %u flocal %u\n", reject, collide, ftotal, flocal); } @@ -456,9 +456,9 @@ static int crush_choose(struct crush_map *map, * @result_max: maximum result size * @force: force initial replica choice; -1 for none */ -int crush_do_rule(struct crush_map *map, +int crush_do_rule(const struct crush_map *map, int ruleno, int x, int *result, int result_max, - int force, __u32 *weight) + int force, const __u32 *weight) { int result_len; int force_context[CRUSH_MAX_DEPTH]; @@ -473,7 +473,7 @@ int crush_do_rule(struct crush_map *map, int osize; int *tmp; struct crush_rule *rule; - int step; + __u32 step; int i, j; int numrep; int firstn; @@ -488,7 +488,8 @@ int crush_do_rule(struct crush_map *map, /* * determine hierarchical context of force, if any. note * that this may or may not correspond to the specific types - * referenced by the crush rule. + * referenced by the crush rule. it will also only affect + * the first descent (TAKE). */ if (force >= 0 && force < map->max_devices && From 9926776ca573b23914d5265457202307a3715748 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 7 May 2012 15:35:09 -0700 Subject: [PATCH 1501/2357] crush: adjust local retry threshold (cherry picked from commit c90f95ed46393e29d843686e21947d1c6fcb1164) This small adjustment reflects a change that was made in ceph.git commit af6a9f30696c900a2a8bd7ae24e8ed15fb4964bb, about 6 months ago. An N-1 search is not exhaustive. Fixed ceph.git bug #1594. Reviewed-by: Alex Elder Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/crush/mapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c index 436102a8a46..583f644b0e2 100644 --- a/net/ceph/crush/mapper.c +++ b/net/ceph/crush/mapper.c @@ -415,7 +415,7 @@ static int crush_choose(const struct crush_map *map, if (collide && flocal < 3) /* retry locally a few times */ retry_bucket = 1; - else if (flocal < in->size + orig_tries) + else if (flocal <= in->size + orig_tries) /* exhaustive bucket search */ retry_bucket = 1; else if (ftotal < 20) From 20501b9e6e1db8e7ab6668ef15d697b1c057a50a Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 7 May 2012 15:35:24 -0700 Subject: [PATCH 1502/2357] crush: be more tolerant of nonsensical crush maps (cherry picked from commit a1f4895be8bf1ba56c2306b058f51619e9b0e8f8) If we get a map that doesn't make sense, error out or ignore the badness instead of BUGging out. This reflects the ceph.git commits 9895f0bff7dc68e9b49b572613d242315fb11b6c and 8ded26472058d5205803f244c2f33cb6cb10de79. Reviewed-by: Alex Elder Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/crush/mapper.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c index 583f644b0e2..00baad5d3bd 100644 --- a/net/ceph/crush/mapper.c +++ b/net/ceph/crush/mapper.c @@ -152,8 +152,8 @@ static int bucket_list_choose(struct crush_bucket_list *bucket, return bucket->h.items[i]; } - BUG_ON(1); - return 0; + dprintk("bad list sums for bucket %d\n", bucket->h.id); + return bucket->h.items[0]; } @@ -239,6 +239,7 @@ static int bucket_straw_choose(struct crush_bucket_straw *bucket, static int crush_bucket_choose(struct crush_bucket *in, int x, int r) { dprintk(" crush_bucket_choose %d x=%d r=%d\n", in->id, x, r); + BUG_ON(in->size == 0); switch (in->alg) { case CRUSH_BUCKET_UNIFORM: return bucket_uniform_choose((struct crush_bucket_uniform *)in, @@ -253,7 +254,7 @@ static int crush_bucket_choose(struct crush_bucket *in, int x, int r) return bucket_straw_choose((struct crush_bucket_straw *)in, x, r); default: - BUG_ON(1); + dprintk("unknown bucket %d alg %d\n", in->id, in->alg); return in->items[0]; } } @@ -354,7 +355,11 @@ static int crush_choose(const struct crush_map *map, item = bucket_perm_choose(in, x, r); else item = crush_bucket_choose(in, x, r); - BUG_ON(item >= map->max_devices); + if (item >= map->max_devices) { + dprintk(" bad item %d\n", item); + skip_rep = 1; + break; + } /* desired type? */ if (item < 0) @@ -365,8 +370,12 @@ static int crush_choose(const struct crush_map *map, /* keep going? */ if (itemtype != type) { - BUG_ON(item >= 0 || - (-1-item) >= map->max_buckets); + if (item >= 0 || + (-1-item) >= map->max_buckets) { + dprintk(" bad item type %d\n", type); + skip_rep = 1; + break; + } in = map->buckets[-1-item]; retry_bucket = 1; continue; @@ -478,7 +487,10 @@ int crush_do_rule(const struct crush_map *map, int numrep; int firstn; - BUG_ON(ruleno >= map->max_rules); + if ((__u32)ruleno >= map->max_rules) { + dprintk(" bad ruleno %d\n", ruleno); + return 0; + } rule = map->rules[ruleno]; result_len = 0; @@ -528,7 +540,8 @@ int crush_do_rule(const struct crush_map *map, firstn = 1; case CRUSH_RULE_CHOOSE_LEAF_INDEP: case CRUSH_RULE_CHOOSE_INDEP: - BUG_ON(wsize == 0); + if (wsize == 0) + break; recurse_to_leaf = rule->steps[step].op == @@ -597,7 +610,9 @@ int crush_do_rule(const struct crush_map *map, break; default: - BUG_ON(1); + dprintk(" unknown op %d at step %d\n", + curstep->op, step); + break; } } return result_len; From 9a0117ae53308d0d8284ba5664ed4c1d0ec54176 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 7 May 2012 15:36:49 -0700 Subject: [PATCH 1503/2357] crush: fix tree node weight lookup (cherry picked from commit f671d4cd9b36691ac4ef42cde44c1b7a84e13631) Fix the node weight lookup for tree buckets by using a correct accessor. Reflects ceph.git commit d287ade5bcbdca82a3aef145b92924cf1e856733. Reviewed-by: Alex Elder Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/crush/crush.h | 5 +++++ net/ceph/crush/crush.c | 4 +--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/linux/crush/crush.h b/include/linux/crush/crush.h index 3f50369a50e..e7a8c9055cb 100644 --- a/include/linux/crush/crush.h +++ b/include/linux/crush/crush.h @@ -177,4 +177,9 @@ extern void crush_destroy_bucket_straw(struct crush_bucket_straw *b); extern void crush_destroy_bucket(struct crush_bucket *b); extern void crush_destroy(struct crush_map *map); +static inline int crush_calc_tree_node(int i) +{ + return ((i+1) << 1)-1; +} + #endif diff --git a/net/ceph/crush/crush.c b/net/ceph/crush/crush.c index 8dd19a0deed..f23611d0cde 100644 --- a/net/ceph/crush/crush.c +++ b/net/ceph/crush/crush.c @@ -37,9 +37,7 @@ int crush_get_bucket_item_weight(const struct crush_bucket *b, int p) case CRUSH_BUCKET_LIST: return ((struct crush_bucket_list *)b)->item_weights[p]; case CRUSH_BUCKET_TREE: - if (p & 1) - return ((struct crush_bucket_tree *)b)->node_weights[p]; - return 0; + return ((struct crush_bucket_tree *)b)->node_weights[crush_calc_tree_node(p)]; case CRUSH_BUCKET_STRAW: return ((struct crush_bucket_straw *)b)->item_weights[p]; } From cf34fc7d48d9600665e570b5c8a297a52bbe5fc5 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 7 May 2012 15:37:05 -0700 Subject: [PATCH 1504/2357] crush: fix memory leak when destroying tree buckets (cherry picked from commit 6eb43f4b5a2a74599b4ff17a97c03a342327ca65) Reflects ceph.git commit 46d63d98434b3bc9dad2fc9ab23cbaedc3bcb0e4. Reported-by: Alexander Lyakas Reviewed-by: Alex Elder Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/crush/crush.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ceph/crush/crush.c b/net/ceph/crush/crush.c index f23611d0cde..fbda0521a00 100644 --- a/net/ceph/crush/crush.c +++ b/net/ceph/crush/crush.c @@ -85,6 +85,8 @@ void crush_destroy_bucket_list(struct crush_bucket_list *b) void crush_destroy_bucket_tree(struct crush_bucket_tree *b) { + kfree(b->h.perm); + kfree(b->h.items); kfree(b->node_weights); kfree(b); } From f77637d9f603dd74cf1b4366d7bb1938a6715ab2 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 20 Apr 2012 15:49:43 -0500 Subject: [PATCH 1505/2357] ceph: osd_client: fix endianness bug in osd_req_encode_op() (cherry picked from commit 065a68f9167e20f321a62d044cb2c3024393d455) From Al Viro Al Viro noticed that we were using a non-cpu-encoded value in a switch statement in osd_req_encode_op(). The result would clearly not work correctly on a big-endian machine. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 5e254055c91..daa2716a0c3 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -278,7 +278,7 @@ static void osd_req_encode_op(struct ceph_osd_request *req, { dst->op = cpu_to_le16(src->op); - switch (dst->op) { + switch (src->op) { case CEPH_OSD_OP_READ: case CEPH_OSD_OP_WRITE: dst->extent.offset = From d0d7af68e9da4d8ad24052151d5d4add6464f505 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 10 May 2012 10:29:50 -0500 Subject: [PATCH 1506/2357] ceph: messenger: use read_partial() in read_partial_message() (cherry picked from commit 57dac9d1620942608306d8c17c98a9d1568ffdf4) There are two blocks of code in read_partial_message()--those that read the header and footer of the message--that can be replaced by a call to read_partial(). Do that. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index f0993af2ae4..673133ee318 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1628,7 +1628,7 @@ static int read_partial_message(struct ceph_connection *con) { struct ceph_msg *m = con->in_msg; int ret; - int to, left; + int to; unsigned front_len, middle_len, data_len; bool do_datacrc = !con->msgr->nocrc; int skip; @@ -1638,15 +1638,10 @@ static int read_partial_message(struct ceph_connection *con) dout("read_partial_message con %p msg %p\n", con, m); /* header */ - while (con->in_base_pos < sizeof(con->in_hdr)) { - left = sizeof(con->in_hdr) - con->in_base_pos; - ret = ceph_tcp_recvmsg(con->sock, - (char *)&con->in_hdr + con->in_base_pos, - left); - if (ret <= 0) - return ret; - con->in_base_pos += ret; - } + to = 0; + ret = read_partial(con, &to, sizeof (con->in_hdr), &con->in_hdr); + if (ret <= 0) + return ret; crc = crc32c(0, &con->in_hdr, offsetof(struct ceph_msg_header, crc)); if (cpu_to_le32(crc) != con->in_hdr.crc) { @@ -1759,16 +1754,11 @@ static int read_partial_message(struct ceph_connection *con) } /* footer */ - to = sizeof(m->hdr) + sizeof(m->footer); - while (con->in_base_pos < to) { - left = to - con->in_base_pos; - ret = ceph_tcp_recvmsg(con->sock, (char *)&m->footer + - (con->in_base_pos - sizeof(m->hdr)), - left); - if (ret <= 0) - return ret; - con->in_base_pos += ret; - } + to = sizeof (m->hdr); + ret = read_partial(con, &to, sizeof (m->footer), &m->footer); + if (ret <= 0) + return ret; + dout("read_partial_message got msg %p %d (%u) + %d (%u) + %d (%u)\n", m, front_len, m->footer.front_crc, middle_len, m->footer.middle_crc, data_len, m->footer.data_crc); From dd22ce515dc6f8a69957473f1ce0d0d8f043b06a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 10 May 2012 10:29:50 -0500 Subject: [PATCH 1507/2357] ceph: messenger: update "to" in read_partial() caller (cherry picked from commit e6cee71fac27c946a0bbad754dd076e66c4e9dbd) read_partial() always increases whatever "to" value is supplied by adding the requested size to it, and that's the only thing it does with that pointed-to value. Do that pointer advance in the caller (and then only when the updated value will be subsequently used), and change the "to" parameter to be an in-only and non-pointer value. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 673133ee318..37fd2aece23 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -992,11 +992,12 @@ static int prepare_read_message(struct ceph_connection *con) static int read_partial(struct ceph_connection *con, - int *to, int size, void *object) + int to, int size, void *object) { - *to += size; - while (con->in_base_pos < *to) { - int left = *to - con->in_base_pos; + int end = to + size; + + while (con->in_base_pos < end) { + int left = end - con->in_base_pos; int have = size - left; int ret = ceph_tcp_recvmsg(con->sock, object + have, left); if (ret <= 0) @@ -1017,14 +1018,16 @@ static int read_partial_banner(struct ceph_connection *con) dout("read_partial_banner %p at %d\n", con, con->in_base_pos); /* peer's banner */ - ret = read_partial(con, &to, strlen(CEPH_BANNER), con->in_banner); + ret = read_partial(con, to, strlen(CEPH_BANNER), con->in_banner); if (ret <= 0) goto out; - ret = read_partial(con, &to, sizeof(con->actual_peer_addr), + to += strlen(CEPH_BANNER); + ret = read_partial(con, to, sizeof(con->actual_peer_addr), &con->actual_peer_addr); if (ret <= 0) goto out; - ret = read_partial(con, &to, sizeof(con->peer_addr_for_me), + to += sizeof(con->actual_peer_addr); + ret = read_partial(con, to, sizeof(con->peer_addr_for_me), &con->peer_addr_for_me); if (ret <= 0) goto out; @@ -1038,10 +1041,11 @@ static int read_partial_connect(struct ceph_connection *con) dout("read_partial_connect %p at %d\n", con, con->in_base_pos); - ret = read_partial(con, &to, sizeof(con->in_reply), &con->in_reply); + ret = read_partial(con, to, sizeof(con->in_reply), &con->in_reply); if (ret <= 0) goto out; - ret = read_partial(con, &to, le32_to_cpu(con->in_reply.authorizer_len), + to += sizeof(con->in_reply); + ret = read_partial(con, to, le32_to_cpu(con->in_reply.authorizer_len), con->auth_reply_buf); if (ret <= 0) goto out; @@ -1491,9 +1495,7 @@ static int process_connect(struct ceph_connection *con) */ static int read_partial_ack(struct ceph_connection *con) { - int to = 0; - - return read_partial(con, &to, sizeof(con->in_temp_ack), + return read_partial(con, 0, sizeof(con->in_temp_ack), &con->in_temp_ack); } @@ -1638,8 +1640,7 @@ static int read_partial_message(struct ceph_connection *con) dout("read_partial_message con %p msg %p\n", con, m); /* header */ - to = 0; - ret = read_partial(con, &to, sizeof (con->in_hdr), &con->in_hdr); + ret = read_partial(con, 0, sizeof (con->in_hdr), &con->in_hdr); if (ret <= 0) return ret; @@ -1755,7 +1756,7 @@ static int read_partial_message(struct ceph_connection *con) /* footer */ to = sizeof (m->hdr); - ret = read_partial(con, &to, sizeof (m->footer), &m->footer); + ret = read_partial(con, to, sizeof (m->footer), &m->footer); if (ret <= 0) return ret; From 1f7631fba2a763f45bfec34bdf731e2089ca3d87 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 10 May 2012 10:29:50 -0500 Subject: [PATCH 1508/2357] ceph: messenger: change read_partial() to take "end" arg (cherry picked from commit fd51653f78cf40a0516e521b6de22f329c5bad8d) Make the second argument to read_partial() be the ending input byte position rather than the beginning offset it now represents. This amounts to moving the addition "to + size" into the caller. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 60 ++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 37fd2aece23..a659b4de64a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -992,10 +992,8 @@ static int prepare_read_message(struct ceph_connection *con) static int read_partial(struct ceph_connection *con, - int to, int size, void *object) + int end, int size, void *object) { - int end = to + size; - while (con->in_base_pos < end) { int left = end - con->in_base_pos; int have = size - left; @@ -1013,40 +1011,52 @@ static int read_partial(struct ceph_connection *con, */ static int read_partial_banner(struct ceph_connection *con) { - int ret, to = 0; + int size; + int end; + int ret; dout("read_partial_banner %p at %d\n", con, con->in_base_pos); /* peer's banner */ - ret = read_partial(con, to, strlen(CEPH_BANNER), con->in_banner); + size = strlen(CEPH_BANNER); + end = size; + ret = read_partial(con, end, size, con->in_banner); if (ret <= 0) goto out; - to += strlen(CEPH_BANNER); - ret = read_partial(con, to, sizeof(con->actual_peer_addr), - &con->actual_peer_addr); + + size = sizeof (con->actual_peer_addr); + end += size; + ret = read_partial(con, end, size, &con->actual_peer_addr); if (ret <= 0) goto out; - to += sizeof(con->actual_peer_addr); - ret = read_partial(con, to, sizeof(con->peer_addr_for_me), - &con->peer_addr_for_me); + + size = sizeof (con->peer_addr_for_me); + end += size; + ret = read_partial(con, end, size, &con->peer_addr_for_me); if (ret <= 0) goto out; + out: return ret; } static int read_partial_connect(struct ceph_connection *con) { - int ret, to = 0; + int size; + int end; + int ret; dout("read_partial_connect %p at %d\n", con, con->in_base_pos); - ret = read_partial(con, to, sizeof(con->in_reply), &con->in_reply); + size = sizeof (con->in_reply); + end = size; + ret = read_partial(con, end, size, &con->in_reply); if (ret <= 0) goto out; - to += sizeof(con->in_reply); - ret = read_partial(con, to, le32_to_cpu(con->in_reply.authorizer_len), - con->auth_reply_buf); + + size = le32_to_cpu(con->in_reply.authorizer_len); + end += size; + ret = read_partial(con, end, size, con->auth_reply_buf); if (ret <= 0) goto out; @@ -1495,8 +1505,10 @@ static int process_connect(struct ceph_connection *con) */ static int read_partial_ack(struct ceph_connection *con) { - return read_partial(con, 0, sizeof(con->in_temp_ack), - &con->in_temp_ack); + int size = sizeof (con->in_temp_ack); + int end = size; + + return read_partial(con, end, size, &con->in_temp_ack); } @@ -1629,8 +1641,9 @@ static int read_partial_message_bio(struct ceph_connection *con, static int read_partial_message(struct ceph_connection *con) { struct ceph_msg *m = con->in_msg; + int size; + int end; int ret; - int to; unsigned front_len, middle_len, data_len; bool do_datacrc = !con->msgr->nocrc; int skip; @@ -1640,7 +1653,9 @@ static int read_partial_message(struct ceph_connection *con) dout("read_partial_message con %p msg %p\n", con, m); /* header */ - ret = read_partial(con, 0, sizeof (con->in_hdr), &con->in_hdr); + size = sizeof (con->in_hdr); + end = size; + ret = read_partial(con, end, size, &con->in_hdr); if (ret <= 0) return ret; @@ -1755,8 +1770,9 @@ static int read_partial_message(struct ceph_connection *con) } /* footer */ - to = sizeof (m->hdr); - ret = read_partial(con, to, sizeof (m->footer), &m->footer); + size = sizeof (m->footer); + end += size; + ret = read_partial(con, end, size, &m->footer); if (ret <= 0) return ret; From 6b7cc02849d47abf3077e27aec841dbd140b8b35 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:38 -0500 Subject: [PATCH 1509/2357] libceph: don't reset kvec in prepare_write_banner() (cherry picked from commit d329156f16306449c273002486c28de3ddddfd89) Move the kvec reset for a connection out of prepare_write_banner and into its only caller. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index a659b4de64a..bcbd409b5ca 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -686,7 +686,6 @@ static int prepare_connect_authorizer(struct ceph_connection *con) static void prepare_write_banner(struct ceph_messenger *msgr, struct ceph_connection *con) { - ceph_con_out_kvec_reset(con); ceph_con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER); ceph_con_out_kvec_add(con, sizeof (msgr->my_enc_addr), &msgr->my_enc_addr); @@ -726,10 +725,9 @@ static int prepare_write_connect(struct ceph_messenger *msgr, con->out_connect.protocol_version = cpu_to_le32(proto); con->out_connect.flags = 0; + ceph_con_out_kvec_reset(con); if (include_banner) prepare_write_banner(msgr, con); - else - ceph_con_out_kvec_reset(con); ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); con->out_more = 0; From 726644c635924f48f1bc9f64087e92915bc61fc7 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:38 -0500 Subject: [PATCH 1510/2357] ceph: messenger: reset connection kvec caller (cherry picked from commit 84fb3adf6413862cff51d8af3fce5f0b655586a2) Reset a connection's kvec fields in the caller rather than in prepare_write_connect(). This ends up repeating a few lines of code but it's improving the separation between distinct operations on the connection, which we can take advantage of later. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index bcbd409b5ca..cca3cf341d7 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -725,7 +725,6 @@ static int prepare_write_connect(struct ceph_messenger *msgr, con->out_connect.protocol_version = cpu_to_le32(proto); con->out_connect.flags = 0; - ceph_con_out_kvec_reset(con); if (include_banner) prepare_write_banner(msgr, con); ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); @@ -1389,6 +1388,7 @@ static int process_connect(struct ceph_connection *con) return -1; } con->auth_retry = 1; + ceph_con_out_kvec_reset(con); ret = prepare_write_connect(con->msgr, con, 0); if (ret < 0) return ret; @@ -1409,6 +1409,7 @@ static int process_connect(struct ceph_connection *con) ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr)); reset_connection(con); + ceph_con_out_kvec_reset(con); prepare_write_connect(con->msgr, con, 0); prepare_read_connect(con); @@ -1432,6 +1433,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->out_connect.connect_seq), le32_to_cpu(con->in_connect.connect_seq)); con->connect_seq = le32_to_cpu(con->in_connect.connect_seq); + ceph_con_out_kvec_reset(con); prepare_write_connect(con->msgr, con, 0); prepare_read_connect(con); break; @@ -1446,6 +1448,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->in_connect.global_seq)); get_global_seq(con->msgr, le32_to_cpu(con->in_connect.global_seq)); + ceph_con_out_kvec_reset(con); prepare_write_connect(con->msgr, con, 0); prepare_read_connect(con); break; @@ -1851,6 +1854,7 @@ static int try_write(struct ceph_connection *con) /* open the socket first? */ if (con->sock == NULL) { + ceph_con_out_kvec_reset(con); prepare_write_connect(msgr, con, 1); prepare_read_banner(con); set_bit(CONNECTING, &con->state); From d4ac74c3222ae545e62bb1ab2bd7306d71ba5379 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:38 -0500 Subject: [PATCH 1511/2357] ceph: messenger: send banner in process_connect() (cherry picked from commit 41b90c00858129f52d08e6a05c9cfdb0f2bd074d) prepare_write_connect() has an argument indicating whether a banner should be sent out before sending out a connection message. It's only ever set in one of its callers, so move the code that arranges to send the banner into that caller and drop the "include_banner" argument from prepare_write_connect(). Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index cca3cf341d7..6b38b6fbb25 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -695,8 +695,7 @@ static void prepare_write_banner(struct ceph_messenger *msgr, } static int prepare_write_connect(struct ceph_messenger *msgr, - struct ceph_connection *con, - int include_banner) + struct ceph_connection *con) { unsigned global_seq = get_global_seq(con->msgr, 0); int proto; @@ -725,8 +724,6 @@ static int prepare_write_connect(struct ceph_messenger *msgr, con->out_connect.protocol_version = cpu_to_le32(proto); con->out_connect.flags = 0; - if (include_banner) - prepare_write_banner(msgr, con); ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); con->out_more = 0; @@ -1389,7 +1386,7 @@ static int process_connect(struct ceph_connection *con) } con->auth_retry = 1; ceph_con_out_kvec_reset(con); - ret = prepare_write_connect(con->msgr, con, 0); + ret = prepare_write_connect(con->msgr, con); if (ret < 0) return ret; prepare_read_connect(con); @@ -1410,7 +1407,7 @@ static int process_connect(struct ceph_connection *con) ceph_pr_addr(&con->peer_addr.in_addr)); reset_connection(con); ceph_con_out_kvec_reset(con); - prepare_write_connect(con->msgr, con, 0); + prepare_write_connect(con->msgr, con); prepare_read_connect(con); /* Tell ceph about it. */ @@ -1434,7 +1431,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->in_connect.connect_seq)); con->connect_seq = le32_to_cpu(con->in_connect.connect_seq); ceph_con_out_kvec_reset(con); - prepare_write_connect(con->msgr, con, 0); + prepare_write_connect(con->msgr, con); prepare_read_connect(con); break; @@ -1449,7 +1446,7 @@ static int process_connect(struct ceph_connection *con) get_global_seq(con->msgr, le32_to_cpu(con->in_connect.global_seq)); ceph_con_out_kvec_reset(con); - prepare_write_connect(con->msgr, con, 0); + prepare_write_connect(con->msgr, con); prepare_read_connect(con); break; @@ -1855,7 +1852,8 @@ static int try_write(struct ceph_connection *con) /* open the socket first? */ if (con->sock == NULL) { ceph_con_out_kvec_reset(con); - prepare_write_connect(msgr, con, 1); + prepare_write_banner(msgr, con); + prepare_write_connect(msgr, con); prepare_read_banner(con); set_bit(CONNECTING, &con->state); clear_bit(NEGOTIATING, &con->state); From 7dd07ab6bdc7634e99747557d6ba342b639b13d9 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:38 -0500 Subject: [PATCH 1512/2357] ceph: drop msgr argument from prepare_write_connect() (cherry picked from commit e825a66df97776d30a48a187e3a986736af43945) In all cases, the value passed as the msgr argument to prepare_write_connect() is just con->msgr. Just get the msgr value from the ceph connection and drop the unneeded argument. The only msgr passed to prepare_write_banner() is also therefore just the one from con->msgr, so change that function to drop the msgr argument as well. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 6b38b6fbb25..47499dc0e41 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -683,19 +683,17 @@ static int prepare_connect_authorizer(struct ceph_connection *con) /* * We connected to a peer and are saying hello. */ -static void prepare_write_banner(struct ceph_messenger *msgr, - struct ceph_connection *con) +static void prepare_write_banner(struct ceph_connection *con) { ceph_con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER); - ceph_con_out_kvec_add(con, sizeof (msgr->my_enc_addr), - &msgr->my_enc_addr); + ceph_con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr), + &con->msgr->my_enc_addr); con->out_more = 0; set_bit(WRITE_PENDING, &con->state); } -static int prepare_write_connect(struct ceph_messenger *msgr, - struct ceph_connection *con) +static int prepare_write_connect(struct ceph_connection *con) { unsigned global_seq = get_global_seq(con->msgr, 0); int proto; @@ -717,7 +715,7 @@ static int prepare_write_connect(struct ceph_messenger *msgr, dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con, con->connect_seq, global_seq, proto); - con->out_connect.features = cpu_to_le64(msgr->supported_features); + con->out_connect.features = cpu_to_le64(con->msgr->supported_features); con->out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT); con->out_connect.connect_seq = cpu_to_le32(con->connect_seq); con->out_connect.global_seq = cpu_to_le32(global_seq); @@ -1386,7 +1384,7 @@ static int process_connect(struct ceph_connection *con) } con->auth_retry = 1; ceph_con_out_kvec_reset(con); - ret = prepare_write_connect(con->msgr, con); + ret = prepare_write_connect(con); if (ret < 0) return ret; prepare_read_connect(con); @@ -1407,7 +1405,7 @@ static int process_connect(struct ceph_connection *con) ceph_pr_addr(&con->peer_addr.in_addr)); reset_connection(con); ceph_con_out_kvec_reset(con); - prepare_write_connect(con->msgr, con); + prepare_write_connect(con); prepare_read_connect(con); /* Tell ceph about it. */ @@ -1431,7 +1429,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->in_connect.connect_seq)); con->connect_seq = le32_to_cpu(con->in_connect.connect_seq); ceph_con_out_kvec_reset(con); - prepare_write_connect(con->msgr, con); + prepare_write_connect(con); prepare_read_connect(con); break; @@ -1446,7 +1444,7 @@ static int process_connect(struct ceph_connection *con) get_global_seq(con->msgr, le32_to_cpu(con->in_connect.global_seq)); ceph_con_out_kvec_reset(con); - prepare_write_connect(con->msgr, con); + prepare_write_connect(con); prepare_read_connect(con); break; @@ -1840,7 +1838,6 @@ static void process_message(struct ceph_connection *con) */ static int try_write(struct ceph_connection *con) { - struct ceph_messenger *msgr = con->msgr; int ret = 1; dout("try_write start %p state %lu nref %d\n", con, con->state, @@ -1852,8 +1849,8 @@ static int try_write(struct ceph_connection *con) /* open the socket first? */ if (con->sock == NULL) { ceph_con_out_kvec_reset(con); - prepare_write_banner(msgr, con); - prepare_write_connect(msgr, con); + prepare_write_banner(con); + prepare_write_connect(con); prepare_read_banner(con); set_bit(CONNECTING, &con->state); clear_bit(NEGOTIATING, &con->state); From 59a521ebc05d2bd826d19c4a9a6fb00c313f6a52 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:38 -0500 Subject: [PATCH 1513/2357] ceph: don't set WRITE_PENDING too early (cherry picked from commit e10c758e4031a801ea4d2f8fb39bf14c2658d74b) prepare_write_connect() prepares a connect message, then sets WRITE_PENDING on the connection. Then *after* this, it calls prepare_connect_authorizer(), which updates the content of the connection buffer already queued for sending. It's also possible it will result in prepare_write_connect() returning -EAGAIN despite the WRITE_PENDING big getting set. Fix this by preparing the connect authorizer first, setting the WRITE_PENDING bit only after that is done. Partially addresses http://tracker.newdream.net/issues/2424 Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 47499dc0e41..cf292939dd1 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -697,6 +697,7 @@ static int prepare_write_connect(struct ceph_connection *con) { unsigned global_seq = get_global_seq(con->msgr, 0); int proto; + int ret; switch (con->peer_name.type) { case CEPH_ENTITY_TYPE_MON: @@ -723,11 +724,14 @@ static int prepare_write_connect(struct ceph_connection *con) con->out_connect.flags = 0; ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); + ret = prepare_connect_authorizer(con); + if (ret) + return ret; con->out_more = 0; set_bit(WRITE_PENDING, &con->state); - return prepare_connect_authorizer(con); + return 0; } /* From 59336e08468a9485e499b1449ebc3d68331233db Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 21:51:59 -0500 Subject: [PATCH 1514/2357] ceph: messenger: check prepare_write_connect() result (cherry picked from commit 5a0f8fdd8a0ebe320952a388331dc043d7e14ced) prepare_write_connect() can return an error, but only one of its callers checks for it. All the rest are in functions that already return errors, so it should be fine to return the error if one gets returned. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index cf292939dd1..8e76936a8c1 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1409,7 +1409,9 @@ static int process_connect(struct ceph_connection *con) ceph_pr_addr(&con->peer_addr.in_addr)); reset_connection(con); ceph_con_out_kvec_reset(con); - prepare_write_connect(con); + ret = prepare_write_connect(con); + if (ret < 0) + return ret; prepare_read_connect(con); /* Tell ceph about it. */ @@ -1433,7 +1435,9 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->in_connect.connect_seq)); con->connect_seq = le32_to_cpu(con->in_connect.connect_seq); ceph_con_out_kvec_reset(con); - prepare_write_connect(con); + ret = prepare_write_connect(con); + if (ret < 0) + return ret; prepare_read_connect(con); break; @@ -1448,7 +1452,9 @@ static int process_connect(struct ceph_connection *con) get_global_seq(con->msgr, le32_to_cpu(con->in_connect.global_seq)); ceph_con_out_kvec_reset(con); - prepare_write_connect(con); + ret = prepare_write_connect(con); + if (ret < 0) + return ret; prepare_read_connect(con); break; @@ -1854,7 +1860,9 @@ static int try_write(struct ceph_connection *con) if (con->sock == NULL) { ceph_con_out_kvec_reset(con); prepare_write_banner(con); - prepare_write_connect(con); + ret = prepare_write_connect(con); + if (ret < 0) + goto out; prepare_read_banner(con); set_bit(CONNECTING, &con->state); clear_bit(NEGOTIATING, &con->state); From 29e1a95eb5de3d6745e6eebb7d22dfaea437783c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:38 -0500 Subject: [PATCH 1515/2357] ceph: messenger: rework prepare_connect_authorizer() (cherry picked from commit b1c6b9803f5491e94041e6da96bc9dec3870e792) Change prepare_connect_authorizer() so it returns without dropping the connection mutex if the connection has no get_authorizer method. Use the symbolic CEPH_AUTH_UNKNOWN instead of 0 when assigning authorization protocols. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 8e76936a8c1..09409a3d950 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -656,19 +656,29 @@ static void prepare_write_keepalive(struct ceph_connection *con) static int prepare_connect_authorizer(struct ceph_connection *con) { void *auth_buf; - int auth_len = 0; - int auth_protocol = 0; + int auth_len; + int auth_protocol; + + if (!con->ops->get_authorizer) { + con->out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; + con->out_connect.authorizer_len = 0; + + return 0; + } + + /* Can't hold the mutex while getting authorizer */ mutex_unlock(&con->mutex); - if (con->ops->get_authorizer) - con->ops->get_authorizer(con, &auth_buf, &auth_len, - &auth_protocol, &con->auth_reply_buf, - &con->auth_reply_buf_len, - con->auth_retry); + + auth_buf = NULL; + auth_len = 0; + auth_protocol = CEPH_AUTH_UNKNOWN; + con->ops->get_authorizer(con, &auth_buf, &auth_len, &auth_protocol, + &con->auth_reply_buf, &con->auth_reply_buf_len, + con->auth_retry); mutex_lock(&con->mutex); - if (test_bit(CLOSED, &con->state) || - test_bit(OPENING, &con->state)) + if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) return -EAGAIN; con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol); From 33f0577a991d6d00805450ea29da5a91f6acd1a8 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:38 -0500 Subject: [PATCH 1516/2357] ceph: messenger: check return from get_authorizer (cherry picked from commit ed96af646011412c2bf1ffe860db170db355fae5) In prepare_connect_authorizer(), a connection's get_authorizer method is called but ignores its return value. This function can return an error, so check for it and return it if that ever occurs. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 09409a3d950..e0532d5b22f 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -658,6 +658,7 @@ static int prepare_connect_authorizer(struct ceph_connection *con) void *auth_buf; int auth_len; int auth_protocol; + int ret; if (!con->ops->get_authorizer) { con->out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; @@ -673,11 +674,14 @@ static int prepare_connect_authorizer(struct ceph_connection *con) auth_buf = NULL; auth_len = 0; auth_protocol = CEPH_AUTH_UNKNOWN; - con->ops->get_authorizer(con, &auth_buf, &auth_len, &auth_protocol, - &con->auth_reply_buf, &con->auth_reply_buf_len, - con->auth_retry); + ret = con->ops->get_authorizer(con, &auth_buf, &auth_len, + &auth_protocol, &con->auth_reply_buf, + &con->auth_reply_buf_len, con->auth_retry); mutex_lock(&con->mutex); + if (ret) + return ret; + if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) return -EAGAIN; From 0f56a54fced6bee6e56a8b84f9adb65a41032866 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:38 -0500 Subject: [PATCH 1517/2357] ceph: define ceph_auth_handshake type (cherry picked from commit 6c4a19158b96ea1fb8acbe0c1d5493d9dcd2f147) The definitions for the ceph_mds_session and ceph_osd both contain five fields related only to "authorizers." Encapsulate those fields into their own struct type, allowing for better isolation in some upcoming patches. Fix the #includes in "linux/ceph/osd_client.h" to lay out their more complete canonical path. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 32 ++++++++++++++++---------------- fs/ceph/mds_client.h | 5 ++--- include/linux/ceph/auth.h | 8 ++++++++ include/linux/ceph/osd_client.h | 11 +++++------ net/ceph/osd_client.c | 32 ++++++++++++++++---------------- 5 files changed, 47 insertions(+), 41 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 89971e137aa..42013c62048 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -334,10 +334,10 @@ void ceph_put_mds_session(struct ceph_mds_session *s) dout("mdsc put_session %p %d -> %d\n", s, atomic_read(&s->s_ref), atomic_read(&s->s_ref)-1); if (atomic_dec_and_test(&s->s_ref)) { - if (s->s_authorizer) + if (s->s_auth.authorizer) s->s_mdsc->fsc->client->monc.auth->ops->destroy_authorizer( s->s_mdsc->fsc->client->monc.auth, - s->s_authorizer); + s->s_auth.authorizer); kfree(s); } } @@ -3404,29 +3404,29 @@ static int get_authorizer(struct ceph_connection *con, struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth; int ret = 0; - if (force_new && s->s_authorizer) { - ac->ops->destroy_authorizer(ac, s->s_authorizer); - s->s_authorizer = NULL; + if (force_new && s->s_auth.authorizer) { + ac->ops->destroy_authorizer(ac, s->s_auth.authorizer); + s->s_auth.authorizer = NULL; } - if (s->s_authorizer == NULL) { + if (s->s_auth.authorizer == NULL) { if (ac->ops->create_authorizer) { ret = ac->ops->create_authorizer( ac, CEPH_ENTITY_TYPE_MDS, - &s->s_authorizer, - &s->s_authorizer_buf, - &s->s_authorizer_buf_len, - &s->s_authorizer_reply_buf, - &s->s_authorizer_reply_buf_len); + &s->s_auth.authorizer, + &s->s_auth.authorizer_buf, + &s->s_auth.authorizer_buf_len, + &s->s_auth.authorizer_reply_buf, + &s->s_auth.authorizer_reply_buf_len); if (ret) return ret; } } *proto = ac->protocol; - *buf = s->s_authorizer_buf; - *len = s->s_authorizer_buf_len; - *reply_buf = s->s_authorizer_reply_buf; - *reply_len = s->s_authorizer_reply_buf_len; + *buf = s->s_auth.authorizer_buf; + *len = s->s_auth.authorizer_buf_len; + *reply_buf = s->s_auth.authorizer_reply_buf; + *reply_len = s->s_auth.authorizer_reply_buf_len; return 0; } @@ -3437,7 +3437,7 @@ static int verify_authorizer_reply(struct ceph_connection *con, int len) struct ceph_mds_client *mdsc = s->s_mdsc; struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth; - return ac->ops->verify_authorizer_reply(ac, s->s_authorizer, len); + return ac->ops->verify_authorizer_reply(ac, s->s_auth.authorizer, len); } static int invalidate_authorizer(struct ceph_connection *con) diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 8c7c04ebb59..dd26846dd71 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -11,6 +11,7 @@ #include #include #include +#include /* * Some lock dependencies: @@ -113,9 +114,7 @@ struct ceph_mds_session { struct ceph_connection s_con; - struct ceph_authorizer *s_authorizer; - void *s_authorizer_buf, *s_authorizer_reply_buf; - size_t s_authorizer_buf_len, s_authorizer_reply_buf_len; + struct ceph_auth_handshake s_auth; /* protected by s_gen_ttl_lock */ spinlock_t s_gen_ttl_lock; diff --git a/include/linux/ceph/auth.h b/include/linux/ceph/auth.h index aa13392a7ef..5b774d141e0 100644 --- a/include/linux/ceph/auth.h +++ b/include/linux/ceph/auth.h @@ -14,6 +14,14 @@ struct ceph_auth_client; struct ceph_authorizer; +struct ceph_auth_handshake { + struct ceph_authorizer *authorizer; + void *authorizer_buf; + size_t authorizer_buf_len; + void *authorizer_reply_buf; + size_t authorizer_reply_buf_len; +}; + struct ceph_auth_client_ops { const char *name; diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index 7c05ac202d9..cedfb1a8434 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -6,9 +6,10 @@ #include #include -#include "types.h" -#include "osdmap.h" -#include "messenger.h" +#include +#include +#include +#include /* * Maximum object name size @@ -40,9 +41,7 @@ struct ceph_osd { struct list_head o_requests; struct list_head o_linger_requests; struct list_head o_osd_lru; - struct ceph_authorizer *o_authorizer; - void *o_authorizer_buf, *o_authorizer_reply_buf; - size_t o_authorizer_buf_len, o_authorizer_reply_buf_len; + struct ceph_auth_handshake o_auth; unsigned long lru_ttl; int o_marked_for_keepalive; struct list_head o_keepalive_item; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index daa2716a0c3..66b09d6a153 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -667,8 +667,8 @@ static void put_osd(struct ceph_osd *osd) if (atomic_dec_and_test(&osd->o_ref)) { struct ceph_auth_client *ac = osd->o_osdc->client->monc.auth; - if (osd->o_authorizer) - ac->ops->destroy_authorizer(ac, osd->o_authorizer); + if (osd->o_auth.authorizer) + ac->ops->destroy_authorizer(ac, osd->o_auth.authorizer); kfree(osd); } } @@ -2117,27 +2117,27 @@ static int get_authorizer(struct ceph_connection *con, struct ceph_auth_client *ac = osdc->client->monc.auth; int ret = 0; - if (force_new && o->o_authorizer) { - ac->ops->destroy_authorizer(ac, o->o_authorizer); - o->o_authorizer = NULL; + if (force_new && o->o_auth.authorizer) { + ac->ops->destroy_authorizer(ac, o->o_auth.authorizer); + o->o_auth.authorizer = NULL; } - if (o->o_authorizer == NULL) { + if (o->o_auth.authorizer == NULL) { ret = ac->ops->create_authorizer( ac, CEPH_ENTITY_TYPE_OSD, - &o->o_authorizer, - &o->o_authorizer_buf, - &o->o_authorizer_buf_len, - &o->o_authorizer_reply_buf, - &o->o_authorizer_reply_buf_len); + &o->o_auth.authorizer, + &o->o_auth.authorizer_buf, + &o->o_auth.authorizer_buf_len, + &o->o_auth.authorizer_reply_buf, + &o->o_auth.authorizer_reply_buf_len); if (ret) return ret; } *proto = ac->protocol; - *buf = o->o_authorizer_buf; - *len = o->o_authorizer_buf_len; - *reply_buf = o->o_authorizer_reply_buf; - *reply_len = o->o_authorizer_reply_buf_len; + *buf = o->o_auth.authorizer_buf; + *len = o->o_auth.authorizer_buf_len; + *reply_buf = o->o_auth.authorizer_reply_buf; + *reply_len = o->o_auth.authorizer_reply_buf_len; return 0; } @@ -2148,7 +2148,7 @@ static int verify_authorizer_reply(struct ceph_connection *con, int len) struct ceph_osd_client *osdc = o->o_osdc; struct ceph_auth_client *ac = osdc->client->monc.auth; - return ac->ops->verify_authorizer_reply(ac, o->o_authorizer, len); + return ac->ops->verify_authorizer_reply(ac, o->o_auth.authorizer, len); } static int invalidate_authorizer(struct ceph_connection *con) From 018a2a13f3cb5e205618b1357124ff25eb3a8223 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:39 -0500 Subject: [PATCH 1518/2357] ceph: messenger: reduce args to create_authorizer (cherry picked from commit 74f1869f76d043bad12ec03b4d5f04a8c3d1f157) Make use of the new ceph_auth_handshake structure in order to reduce the number of arguments passed to the create_authorizor method in ceph_auth_client_ops. Use a local variable of that type as a shorthand in the get_authorizer method definitions. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 27 ++++++++++++--------------- include/linux/ceph/auth.h | 4 +--- net/ceph/auth_none.c | 15 +++++++-------- net/ceph/auth_x.c | 15 +++++++-------- net/ceph/osd_client.c | 28 ++++++++++++---------------- 5 files changed, 39 insertions(+), 50 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 42013c62048..b71ffd2c809 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3402,31 +3402,28 @@ static int get_authorizer(struct ceph_connection *con, struct ceph_mds_session *s = con->private; struct ceph_mds_client *mdsc = s->s_mdsc; struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth; + struct ceph_auth_handshake *auth = &s->s_auth; int ret = 0; - if (force_new && s->s_auth.authorizer) { - ac->ops->destroy_authorizer(ac, s->s_auth.authorizer); - s->s_auth.authorizer = NULL; + if (force_new && auth->authorizer) { + ac->ops->destroy_authorizer(ac, auth->authorizer); + auth->authorizer = NULL; } - if (s->s_auth.authorizer == NULL) { + if (auth->authorizer == NULL) { if (ac->ops->create_authorizer) { - ret = ac->ops->create_authorizer( - ac, CEPH_ENTITY_TYPE_MDS, - &s->s_auth.authorizer, - &s->s_auth.authorizer_buf, - &s->s_auth.authorizer_buf_len, - &s->s_auth.authorizer_reply_buf, - &s->s_auth.authorizer_reply_buf_len); + ret = ac->ops->create_authorizer(ac, + CEPH_ENTITY_TYPE_MDS, auth); if (ret) return ret; } } *proto = ac->protocol; - *buf = s->s_auth.authorizer_buf; - *len = s->s_auth.authorizer_buf_len; - *reply_buf = s->s_auth.authorizer_reply_buf; - *reply_len = s->s_auth.authorizer_reply_buf_len; + *buf = auth->authorizer_buf; + *len = auth->authorizer_buf_len; + *reply_buf = auth->authorizer_reply_buf; + *reply_len = auth->authorizer_reply_buf_len; + return 0; } diff --git a/include/linux/ceph/auth.h b/include/linux/ceph/auth.h index 5b774d141e0..d4080f309b5 100644 --- a/include/linux/ceph/auth.h +++ b/include/linux/ceph/auth.h @@ -51,9 +51,7 @@ struct ceph_auth_client_ops { * the response to authenticate the service. */ int (*create_authorizer)(struct ceph_auth_client *ac, int peer_type, - struct ceph_authorizer **a, - void **buf, size_t *len, - void **reply_buf, size_t *reply_len); + struct ceph_auth_handshake *auth); int (*verify_authorizer_reply)(struct ceph_auth_client *ac, struct ceph_authorizer *a, size_t len); void (*destroy_authorizer)(struct ceph_auth_client *ac, diff --git a/net/ceph/auth_none.c b/net/ceph/auth_none.c index 214c2bb43d6..925ca583c09 100644 --- a/net/ceph/auth_none.c +++ b/net/ceph/auth_none.c @@ -59,9 +59,7 @@ static int handle_reply(struct ceph_auth_client *ac, int result, */ static int ceph_auth_none_create_authorizer( struct ceph_auth_client *ac, int peer_type, - struct ceph_authorizer **a, - void **buf, size_t *len, - void **reply_buf, size_t *reply_len) + struct ceph_auth_handshake *auth) { struct ceph_auth_none_info *ai = ac->private; struct ceph_none_authorizer *au = &ai->au; @@ -82,11 +80,12 @@ static int ceph_auth_none_create_authorizer( dout("built authorizer len %d\n", au->buf_len); } - *a = (struct ceph_authorizer *)au; - *buf = au->buf; - *len = au->buf_len; - *reply_buf = au->reply_buf; - *reply_len = sizeof(au->reply_buf); + auth->authorizer = (struct ceph_authorizer *) au; + auth->authorizer_buf = au->buf; + auth->authorizer_buf_len = au->buf_len; + auth->authorizer_reply_buf = au->reply_buf; + auth->authorizer_reply_buf_len = sizeof (au->reply_buf); + return 0; bad2: diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c index 1587dc6010c..a16bf14eb02 100644 --- a/net/ceph/auth_x.c +++ b/net/ceph/auth_x.c @@ -526,9 +526,7 @@ static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result, static int ceph_x_create_authorizer( struct ceph_auth_client *ac, int peer_type, - struct ceph_authorizer **a, - void **buf, size_t *len, - void **reply_buf, size_t *reply_len) + struct ceph_auth_handshake *auth) { struct ceph_x_authorizer *au; struct ceph_x_ticket_handler *th; @@ -548,11 +546,12 @@ static int ceph_x_create_authorizer( return ret; } - *a = (struct ceph_authorizer *)au; - *buf = au->buf->vec.iov_base; - *len = au->buf->vec.iov_len; - *reply_buf = au->reply_buf; - *reply_len = sizeof(au->reply_buf); + auth->authorizer = (struct ceph_authorizer *) au; + auth->authorizer_buf = au->buf->vec.iov_base; + auth->authorizer_buf_len = au->buf->vec.iov_len; + auth->authorizer_reply_buf = au->reply_buf; + auth->authorizer_reply_buf_len = sizeof (au->reply_buf); + return 0; } diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 66b09d6a153..2da4b9e97dc 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -2115,29 +2115,25 @@ static int get_authorizer(struct ceph_connection *con, struct ceph_osd *o = con->private; struct ceph_osd_client *osdc = o->o_osdc; struct ceph_auth_client *ac = osdc->client->monc.auth; + struct ceph_auth_handshake *auth = &o->o_auth; int ret = 0; - if (force_new && o->o_auth.authorizer) { - ac->ops->destroy_authorizer(ac, o->o_auth.authorizer); - o->o_auth.authorizer = NULL; - } - if (o->o_auth.authorizer == NULL) { - ret = ac->ops->create_authorizer( - ac, CEPH_ENTITY_TYPE_OSD, - &o->o_auth.authorizer, - &o->o_auth.authorizer_buf, - &o->o_auth.authorizer_buf_len, - &o->o_auth.authorizer_reply_buf, - &o->o_auth.authorizer_reply_buf_len); + if (force_new && auth->authorizer) { + ac->ops->destroy_authorizer(ac, auth->authorizer); + auth->authorizer = NULL; + } + if (auth->authorizer == NULL) { + ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_OSD, auth); if (ret) return ret; } *proto = ac->protocol; - *buf = o->o_auth.authorizer_buf; - *len = o->o_auth.authorizer_buf_len; - *reply_buf = o->o_auth.authorizer_reply_buf; - *reply_len = o->o_auth.authorizer_reply_buf_len; + *buf = auth->authorizer_buf; + *len = auth->authorizer_buf_len; + *reply_buf = auth->authorizer_reply_buf; + *reply_len = auth->authorizer_reply_buf_len; + return 0; } From 83d28f7956228e0dd1774aed1096392d3bfc0597 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:39 -0500 Subject: [PATCH 1519/2357] ceph: ensure auth ops are defined before use (cherry picked from commit a255651d4cad89f1a606edd36135af892ada4f20) In the create_authorizer method for both the mds and osd clients, the auth_client->ops pointer is blindly dereferenced. There is no obvious guarantee that this pointer has been assigned. And furthermore, even if the ops pointer is non-null there is definitely no guarantee that the create_authorizer or destroy_authorizer methods are defined. Add checks in both routines to make sure they are defined (non-null) before use. Add similar checks in a few other spots in these files while we're at it. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 14 ++++++-------- net/ceph/osd_client.c | 15 ++++++++++----- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index b71ffd2c809..462281742ae 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3406,16 +3406,14 @@ static int get_authorizer(struct ceph_connection *con, int ret = 0; if (force_new && auth->authorizer) { - ac->ops->destroy_authorizer(ac, auth->authorizer); + if (ac->ops && ac->ops->destroy_authorizer) + ac->ops->destroy_authorizer(ac, auth->authorizer); auth->authorizer = NULL; } - if (auth->authorizer == NULL) { - if (ac->ops->create_authorizer) { - ret = ac->ops->create_authorizer(ac, - CEPH_ENTITY_TYPE_MDS, auth); - if (ret) - return ret; - } + if (!auth->authorizer && ac->ops && ac->ops->create_authorizer) { + ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_MDS, auth); + if (ret) + return ret; } *proto = ac->protocol; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 2da4b9e97dc..f640bdf027e 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -664,10 +664,10 @@ static void put_osd(struct ceph_osd *osd) { dout("put_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref), atomic_read(&osd->o_ref) - 1); - if (atomic_dec_and_test(&osd->o_ref)) { + if (atomic_dec_and_test(&osd->o_ref) && osd->o_auth.authorizer) { struct ceph_auth_client *ac = osd->o_osdc->client->monc.auth; - if (osd->o_auth.authorizer) + if (ac->ops && ac->ops->destroy_authorizer) ac->ops->destroy_authorizer(ac, osd->o_auth.authorizer); kfree(osd); } @@ -2119,10 +2119,11 @@ static int get_authorizer(struct ceph_connection *con, int ret = 0; if (force_new && auth->authorizer) { - ac->ops->destroy_authorizer(ac, auth->authorizer); + if (ac->ops && ac->ops->destroy_authorizer) + ac->ops->destroy_authorizer(ac, auth->authorizer); auth->authorizer = NULL; } - if (auth->authorizer == NULL) { + if (!auth->authorizer && ac->ops && ac->ops->create_authorizer) { ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_OSD, auth); if (ret) return ret; @@ -2144,6 +2145,10 @@ static int verify_authorizer_reply(struct ceph_connection *con, int len) struct ceph_osd_client *osdc = o->o_osdc; struct ceph_auth_client *ac = osdc->client->monc.auth; + /* + * XXX If ac->ops or ac->ops->verify_authorizer_reply is null, + * XXX which do we do: succeed or fail? + */ return ac->ops->verify_authorizer_reply(ac, o->o_auth.authorizer, len); } @@ -2153,7 +2158,7 @@ static int invalidate_authorizer(struct ceph_connection *con) struct ceph_osd_client *osdc = o->o_osdc; struct ceph_auth_client *ac = osdc->client->monc.auth; - if (ac->ops->invalidate_authorizer) + if (ac->ops && ac->ops->invalidate_authorizer) ac->ops->invalidate_authorizer(ac, CEPH_ENTITY_TYPE_OSD); return ceph_monc_validate_auth(&osdc->client->monc); From 4f33c7ed3796a5078cd9eef0d3af4ebf8f7e1b99 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:39 -0500 Subject: [PATCH 1520/2357] ceph: have get_authorizer methods return pointers (cherry picked from commit a3530df33eb91d787d08c7383a0a9982690e42d0) Have the get_authorizer auth_client method return a ceph_auth pointer rather than an integer, pointer-encoding any returned error value. This is to pave the way for making use of the returned value in an upcoming patch. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 20 +++++++++++++------- include/linux/ceph/messenger.h | 8 +++++--- net/ceph/messenger.c | 8 ++++---- net/ceph/osd_client.c | 19 ++++++++++++------- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 462281742ae..67938a9d049 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3395,15 +3395,20 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg) /* * authentication */ -static int get_authorizer(struct ceph_connection *con, - void **buf, int *len, int *proto, - void **reply_buf, int *reply_len, int force_new) + +/* + * Note: returned pointer is the address of a structure that's + * managed separately. Caller must *not* attempt to free it. + */ +static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, + void **buf, int *len, int *proto, + void **reply_buf, int *reply_len, + int force_new) { struct ceph_mds_session *s = con->private; struct ceph_mds_client *mdsc = s->s_mdsc; struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth; struct ceph_auth_handshake *auth = &s->s_auth; - int ret = 0; if (force_new && auth->authorizer) { if (ac->ops && ac->ops->destroy_authorizer) @@ -3411,9 +3416,10 @@ static int get_authorizer(struct ceph_connection *con, auth->authorizer = NULL; } if (!auth->authorizer && ac->ops && ac->ops->create_authorizer) { - ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_MDS, auth); + int ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_MDS, + auth); if (ret) - return ret; + return ERR_PTR(ret); } *proto = ac->protocol; @@ -3422,7 +3428,7 @@ static int get_authorizer(struct ceph_connection *con, *reply_buf = auth->authorizer_reply_buf; *reply_len = auth->authorizer_reply_buf_len; - return 0; + return auth; } diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 3bff047f6b0..b10b55f8f30 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -25,9 +25,11 @@ struct ceph_connection_operations { void (*dispatch) (struct ceph_connection *con, struct ceph_msg *m); /* authorize an outgoing connection */ - int (*get_authorizer) (struct ceph_connection *con, - void **buf, int *len, int *proto, - void **reply_buf, int *reply_len, int force_new); + struct ceph_auth_handshake *(*get_authorizer) ( + struct ceph_connection *con, + void **buf, int *len, int *proto, + void **reply_buf, int *reply_len, + int force_new); int (*verify_authorizer_reply) (struct ceph_connection *con, int len); int (*invalidate_authorizer)(struct ceph_connection *con); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index e0532d5b22f..ac27a2c0694 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -658,7 +658,7 @@ static int prepare_connect_authorizer(struct ceph_connection *con) void *auth_buf; int auth_len; int auth_protocol; - int ret; + struct ceph_auth_handshake *auth; if (!con->ops->get_authorizer) { con->out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; @@ -674,13 +674,13 @@ static int prepare_connect_authorizer(struct ceph_connection *con) auth_buf = NULL; auth_len = 0; auth_protocol = CEPH_AUTH_UNKNOWN; - ret = con->ops->get_authorizer(con, &auth_buf, &auth_len, + auth = con->ops->get_authorizer(con, &auth_buf, &auth_len, &auth_protocol, &con->auth_reply_buf, &con->auth_reply_buf_len, con->auth_retry); mutex_lock(&con->mutex); - if (ret) - return ret; + if (IS_ERR(auth)) + return PTR_ERR(auth); if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) return -EAGAIN; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index f640bdf027e..fa74ae0ea91 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -2108,15 +2108,19 @@ static void put_osd_con(struct ceph_connection *con) /* * authentication */ -static int get_authorizer(struct ceph_connection *con, - void **buf, int *len, int *proto, - void **reply_buf, int *reply_len, int force_new) +/* + * Note: returned pointer is the address of a structure that's + * managed separately. Caller must *not* attempt to free it. + */ +static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, + void **buf, int *len, int *proto, + void **reply_buf, int *reply_len, + int force_new) { struct ceph_osd *o = con->private; struct ceph_osd_client *osdc = o->o_osdc; struct ceph_auth_client *ac = osdc->client->monc.auth; struct ceph_auth_handshake *auth = &o->o_auth; - int ret = 0; if (force_new && auth->authorizer) { if (ac->ops && ac->ops->destroy_authorizer) @@ -2124,9 +2128,10 @@ static int get_authorizer(struct ceph_connection *con, auth->authorizer = NULL; } if (!auth->authorizer && ac->ops && ac->ops->create_authorizer) { - ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_OSD, auth); + int ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_OSD, + auth); if (ret) - return ret; + return ERR_PTR(ret); } *proto = ac->protocol; @@ -2135,7 +2140,7 @@ static int get_authorizer(struct ceph_connection *con, *reply_buf = auth->authorizer_reply_buf; *reply_len = auth->authorizer_reply_buf_len; - return 0; + return auth; } From ed35fbcd3cf73dfbff59bf8c20c772925562bc45 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:39 -0500 Subject: [PATCH 1521/2357] ceph: use info returned by get_authorizer (cherry picked from commit 8f43fb53894079bf0caab6e348ceaffe7adc651a) Rather than passing a bunch of arguments to be filled in with the content of the ceph_auth_handshake buffer now returned by the get_authorizer method, just use the returned information in the caller, and drop the unnecessary arguments. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 9 +-------- include/linux/ceph/messenger.h | 4 +--- net/ceph/messenger.c | 13 +++++++------ net/ceph/osd_client.c | 9 +-------- 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 67938a9d049..200bc87eceb 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3401,9 +3401,7 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg) * managed separately. Caller must *not* attempt to free it. */ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, - void **buf, int *len, int *proto, - void **reply_buf, int *reply_len, - int force_new) + int *proto, int force_new) { struct ceph_mds_session *s = con->private; struct ceph_mds_client *mdsc = s->s_mdsc; @@ -3421,12 +3419,7 @@ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, if (ret) return ERR_PTR(ret); } - *proto = ac->protocol; - *buf = auth->authorizer_buf; - *len = auth->authorizer_buf_len; - *reply_buf = auth->authorizer_reply_buf; - *reply_len = auth->authorizer_reply_buf_len; return auth; } diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index b10b55f8f30..2521a95fa6d 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -27,9 +27,7 @@ struct ceph_connection_operations { /* authorize an outgoing connection */ struct ceph_auth_handshake *(*get_authorizer) ( struct ceph_connection *con, - void **buf, int *len, int *proto, - void **reply_buf, int *reply_len, - int force_new); + int *proto, int force_new); int (*verify_authorizer_reply) (struct ceph_connection *con, int len); int (*invalidate_authorizer)(struct ceph_connection *con); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index ac27a2c0694..6d82c1a1a89 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -671,20 +671,21 @@ static int prepare_connect_authorizer(struct ceph_connection *con) mutex_unlock(&con->mutex); - auth_buf = NULL; - auth_len = 0; auth_protocol = CEPH_AUTH_UNKNOWN; - auth = con->ops->get_authorizer(con, &auth_buf, &auth_len, - &auth_protocol, &con->auth_reply_buf, - &con->auth_reply_buf_len, con->auth_retry); + auth = con->ops->get_authorizer(con, &auth_protocol, con->auth_retry); + mutex_lock(&con->mutex); if (IS_ERR(auth)) return PTR_ERR(auth); - if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) return -EAGAIN; + auth_buf = auth->authorizer_buf; + auth_len = auth->authorizer_buf_len; + con->auth_reply_buf = auth->authorizer_reply_buf; + con->auth_reply_buf_len = auth->authorizer_reply_buf_len; + con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol); con->out_connect.authorizer_len = cpu_to_le32(auth_len); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index fa74ae0ea91..b7d633cc96a 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -2113,9 +2113,7 @@ static void put_osd_con(struct ceph_connection *con) * managed separately. Caller must *not* attempt to free it. */ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, - void **buf, int *len, int *proto, - void **reply_buf, int *reply_len, - int force_new) + int *proto, int force_new) { struct ceph_osd *o = con->private; struct ceph_osd_client *osdc = o->o_osdc; @@ -2133,12 +2131,7 @@ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, if (ret) return ERR_PTR(ret); } - *proto = ac->protocol; - *buf = auth->authorizer_buf; - *len = auth->authorizer_buf_len; - *reply_buf = auth->authorizer_reply_buf; - *reply_len = auth->authorizer_reply_buf_len; return auth; } From 8d19055c84e89980a0e60604bd925bf7cf4cb9e4 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:39 -0500 Subject: [PATCH 1522/2357] ceph: return pointer from prepare_connect_authorizer() (cherry picked from commit 729796be9190f57ca40ccca315e8ad34a1eb8fef) Change prepare_connect_authorizer() so it returns a pointer (or pointer-coded error). Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 6d82c1a1a89..f92d564c150 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -653,7 +653,7 @@ static void prepare_write_keepalive(struct ceph_connection *con) * Connection negotiation. */ -static int prepare_connect_authorizer(struct ceph_connection *con) +static struct ceph_auth_handshake *prepare_connect_authorizer(struct ceph_connection *con) { void *auth_buf; int auth_len; @@ -664,7 +664,7 @@ static int prepare_connect_authorizer(struct ceph_connection *con) con->out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; con->out_connect.authorizer_len = 0; - return 0; + return NULL; } /* Can't hold the mutex while getting authorizer */ @@ -677,9 +677,9 @@ static int prepare_connect_authorizer(struct ceph_connection *con) mutex_lock(&con->mutex); if (IS_ERR(auth)) - return PTR_ERR(auth); + return auth; if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) - return -EAGAIN; + return ERR_PTR(-EAGAIN); auth_buf = auth->authorizer_buf; auth_len = auth->authorizer_buf_len; @@ -692,7 +692,7 @@ static int prepare_connect_authorizer(struct ceph_connection *con) if (auth_len) ceph_con_out_kvec_add(con, auth_len, auth_buf); - return 0; + return auth; } /* @@ -712,7 +712,7 @@ static int prepare_write_connect(struct ceph_connection *con) { unsigned global_seq = get_global_seq(con->msgr, 0); int proto; - int ret; + struct ceph_auth_handshake *auth; switch (con->peer_name.type) { case CEPH_ENTITY_TYPE_MON: @@ -739,9 +739,9 @@ static int prepare_write_connect(struct ceph_connection *con) con->out_connect.flags = 0; ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); - ret = prepare_connect_authorizer(con); - if (ret) - return ret; + auth = prepare_connect_authorizer(con); + if (IS_ERR(auth)) + return PTR_ERR(auth); con->out_more = 0; set_bit(WRITE_PENDING, &con->state); From 3f13447d2c90842c9ea5ceb6b4f8b8b7737f04da Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:39 -0500 Subject: [PATCH 1523/2357] ceph: rename prepare_connect_authorizer() (cherry picked from commit dac1e716c60161867a47745bca592987ca3a9cb2) Change the name of prepare_connect_authorizer(). The next patch is going to make this function no longer add anything to the connection's out_kvec, so it will no longer fit the pattern of the rest of the prepare_connect_*() functions. In addition, pass the address of a variable that will hold the authorization protocol to use. Move the assignment of that to the connection's out_connect structure into prepare_write_connect(). Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index f92d564c150..bfddd87db78 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -653,11 +653,11 @@ static void prepare_write_keepalive(struct ceph_connection *con) * Connection negotiation. */ -static struct ceph_auth_handshake *prepare_connect_authorizer(struct ceph_connection *con) +static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection *con, + int *auth_proto) { void *auth_buf; int auth_len; - int auth_protocol; struct ceph_auth_handshake *auth; if (!con->ops->get_authorizer) { @@ -671,8 +671,7 @@ static struct ceph_auth_handshake *prepare_connect_authorizer(struct ceph_connec mutex_unlock(&con->mutex); - auth_protocol = CEPH_AUTH_UNKNOWN; - auth = con->ops->get_authorizer(con, &auth_protocol, con->auth_retry); + auth = con->ops->get_authorizer(con, auth_proto, con->auth_retry); mutex_lock(&con->mutex); @@ -686,7 +685,6 @@ static struct ceph_auth_handshake *prepare_connect_authorizer(struct ceph_connec con->auth_reply_buf = auth->authorizer_reply_buf; con->auth_reply_buf_len = auth->authorizer_reply_buf_len; - con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol); con->out_connect.authorizer_len = cpu_to_le32(auth_len); if (auth_len) @@ -712,6 +710,7 @@ static int prepare_write_connect(struct ceph_connection *con) { unsigned global_seq = get_global_seq(con->msgr, 0); int proto; + int auth_proto; struct ceph_auth_handshake *auth; switch (con->peer_name.type) { @@ -739,9 +738,11 @@ static int prepare_write_connect(struct ceph_connection *con) con->out_connect.flags = 0; ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); - auth = prepare_connect_authorizer(con); + auth_proto = CEPH_AUTH_UNKNOWN; + auth = get_connect_authorizer(con, &auth_proto); if (IS_ERR(auth)) return PTR_ERR(auth); + con->out_connect.authorizer_protocol = cpu_to_le32(auth_proto); con->out_more = 0; set_bit(WRITE_PENDING, &con->state); From 1d3df0e26616d97a798950eb5fb908b14b1839da Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 16 May 2012 15:16:39 -0500 Subject: [PATCH 1524/2357] ceph: add auth buf in prepare_write_connect() (cherry picked from commit 3da54776e2c0385c32d143fd497a7f40a88e29dd) Move the addition of the authorizer buffer to a connection's out_kvec out of get_connect_authorizer() and into its caller. This way, the caller--prepare_write_connect()--can avoid adding the connect header to out_kvec before it has been fully initialized. Prior to this patch, it was possible for a connect header to be sent over the wire before the authorizer protocol or buffer length fields were initialized. An authorizer buffer associated with that header could also be queued to send only after the connection header that describes it was on the wire. Fixes http://tracker.newdream.net/issues/2424 Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index bfddd87db78..1a80907282c 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -656,8 +656,6 @@ static void prepare_write_keepalive(struct ceph_connection *con) static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection *con, int *auth_proto) { - void *auth_buf; - int auth_len; struct ceph_auth_handshake *auth; if (!con->ops->get_authorizer) { @@ -680,15 +678,9 @@ static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) return ERR_PTR(-EAGAIN); - auth_buf = auth->authorizer_buf; - auth_len = auth->authorizer_buf_len; con->auth_reply_buf = auth->authorizer_reply_buf; con->auth_reply_buf_len = auth->authorizer_reply_buf_len; - con->out_connect.authorizer_len = cpu_to_le32(auth_len); - - if (auth_len) - ceph_con_out_kvec_add(con, auth_len, auth_buf); return auth; } @@ -737,12 +729,20 @@ static int prepare_write_connect(struct ceph_connection *con) con->out_connect.protocol_version = cpu_to_le32(proto); con->out_connect.flags = 0; - ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); auth_proto = CEPH_AUTH_UNKNOWN; auth = get_connect_authorizer(con, &auth_proto); if (IS_ERR(auth)) return PTR_ERR(auth); + con->out_connect.authorizer_protocol = cpu_to_le32(auth_proto); + con->out_connect.authorizer_len = auth ? + cpu_to_le32(auth->authorizer_buf_len) : 0; + + ceph_con_out_kvec_add(con, sizeof (con->out_connect), + &con->out_connect); + if (auth && auth->authorizer_buf_len) + ceph_con_out_kvec_add(con, auth->authorizer_buf_len, + auth->authorizer_buf); con->out_more = 0; set_bit(WRITE_PENDING, &con->state); From 15ba38ebcee664a5a5de57300ee721e0d65b2dd5 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 16 May 2012 15:16:38 -0500 Subject: [PATCH 1525/2357] libceph: avoid unregistering osd request when not registered (cherry picked from commit 35f9f8a09e1e88e31bd34a1e645ca0e5f070dd5c) There is a race between two __unregister_request() callers: the reply path and the ceph_osdc_wait_request(). If we get a reply *and* the timeout expires at roughly the same time, both callers will try to unregister the request, and the second one will do bad things. Simply check if the request is still already unregistered; if so, return immediately and do nothing. Fixes http://tracker.newdream.net/issues/2420 Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index b7d633cc96a..b098e7b591f 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -841,6 +841,12 @@ static void register_request(struct ceph_osd_client *osdc, static void __unregister_request(struct ceph_osd_client *osdc, struct ceph_osd_request *req) { + if (RB_EMPTY_NODE(&req->r_node)) { + dout("__unregister_request %p tid %lld not registered\n", + req, req->r_tid); + return; + } + dout("__unregister_request %p tid %lld\n", req, req->r_tid); rb_erase(&req->r_node, &osdc->requests); osdc->num_requests--; From 1c201dffa3f4ef8e53dca7bffb8987a43e3e9139 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 21 May 2012 09:45:23 -0700 Subject: [PATCH 1526/2357] libceph: fix pg_temp updates (cherry picked from commit 6bd9adbdf9ca6a052b0b7455ac67b925eb38cfad) Usually, we are adding pg_temp entries or removing them. Occasionally they update. In that case, osdmap_apply_incremental() was failing because the rbtree entry already exists. Fix by removing the existing entry before inserting a new one. Fixes http://tracker.newdream.net/issues/2446 Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/osdmap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 29ad46ec9dc..7173ad54d23 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -890,8 +890,12 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, pglen = ceph_decode_32(p); if (pglen) { - /* insert */ ceph_decode_need(p, end, pglen*sizeof(u32), bad); + + /* removing existing (if any) */ + (void) __remove_pg_mapping(&map->pg_temp, pgid); + + /* insert */ pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS); if (!pg) { err = -ENOMEM; From 40971fcf1578d743cde0272ad20539f5ea34725a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 4 Jun 2012 14:43:32 -0500 Subject: [PATCH 1527/2357] libceph: osd_client: don't drop reply reference too early (cherry picked from commit ab8cb34a4b2f60281a4b18b1f1ad23bc2313d91b) In ceph_osdc_release_request(), a reference to the r_reply message is dropped. But just after that, that same message is revoked if it was in use to receive an incoming reply. Reorder these so we are sure we hold a reference until we're actually done with the message. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 680584fab05efff732b5ae16ad601ba994d7b505) --- net/ceph/osd_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index b098e7b591f..67ed1a58d94 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -139,8 +139,6 @@ void ceph_osdc_release_request(struct kref *kref) if (req->r_request) ceph_msg_put(req->r_request); - if (req->r_reply) - ceph_msg_put(req->r_reply); if (req->r_con_filling_msg) { dout("release_request revoking pages %p from con %p\n", req->r_pages, req->r_con_filling_msg); @@ -148,6 +146,8 @@ void ceph_osdc_release_request(struct kref *kref) req->r_reply); ceph_con_put(req->r_con_filling_msg); } + if (req->r_reply) + ceph_msg_put(req->r_reply); if (req->r_own_pages) ceph_release_page_vector(req->r_pages, req->r_num_pages); From acecca48781a79040dca822cf96d505904c282c3 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 31 May 2012 20:22:18 -0700 Subject: [PATCH 1528/2357] libceph: use con get/put ops from osd_client (cherry picked from commit 0d47766f14211a73eaf54cab234db134ece79f49) There were a few direct calls to ceph_con_{get,put}() instead of the con ops from osd_client.c. This is a bug since those ops aren't defined to be ceph_con_get/put. This breaks refcounting on the ceph_osd structs that contain the ceph_connections, and could lead to all manner of strangeness. The purpose of the ->get and ->put methods in a ceph connection are to allow the connection to indicate it has a reference to something external to the messaging system, *not* to indicate something external has a reference to the connection. [elder@inktank.com: added that last sentence] Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 88ed6ea0b295f8e2383d599a04027ec596cdf97b) --- net/ceph/osd_client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 67ed1a58d94..f4e2a4665d9 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -144,7 +144,7 @@ void ceph_osdc_release_request(struct kref *kref) req->r_pages, req->r_con_filling_msg); ceph_con_revoke_message(req->r_con_filling_msg, req->r_reply); - ceph_con_put(req->r_con_filling_msg); + req->r_con_filling_msg->ops->put(req->r_con_filling_msg); } if (req->r_reply) ceph_msg_put(req->r_reply); @@ -1216,7 +1216,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg, if (req->r_con_filling_msg == con && req->r_reply == msg) { dout(" dropping con_filling_msg ref %p\n", con); req->r_con_filling_msg = NULL; - ceph_con_put(con); + con->ops->put(con); } if (!req->r_got_reply) { @@ -2028,7 +2028,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, dout("get_reply revoking msg %p from old con %p\n", req->r_reply, req->r_con_filling_msg); ceph_con_revoke_message(req->r_con_filling_msg, req->r_reply); - ceph_con_put(req->r_con_filling_msg); + req->r_con_filling_msg->ops->put(req->r_con_filling_msg); req->r_con_filling_msg = NULL; } @@ -2063,7 +2063,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, #endif } *skip = 0; - req->r_con_filling_msg = ceph_con_get(con); + req->r_con_filling_msg = con->ops->get(con); dout("get_reply tid %lld %p\n", tid, m); out: From 576e428b246271f0f078079c68a9f11679c7db8a Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 6 Jun 2012 19:35:55 -0500 Subject: [PATCH 1529/2357] rbd: Clear ceph_msg->bio_iter for retransmitted message (cherry picked from commit 43643528cce60ca184fe8197efa8e8da7c89a037) (cherry picked from commit b132cf4c733f91bb4dd2277ea049243cf16e8b66) The bug can cause NULL pointer dereference in write_partial_msg_pages Signed-off-by: Zheng Yan Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 1a80907282c..375ae3953e2 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -563,6 +563,10 @@ static void prepare_write_message(struct ceph_connection *con) m->hdr.seq = cpu_to_le64(++con->out_seq); m->needs_out_seq = false; } +#ifdef CONFIG_BLOCK + else + m->bio_iter = NULL; +#endif dout("prepare_write_message %p seq %lld type %d len %d+%d+%d %d pgs\n", m, con->out_seq, le16_to_cpu(m->hdr.type), From 21cbad59b07693104dda76ee4afef41302b2b8fb Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 10 Jun 2012 20:43:56 -0700 Subject: [PATCH 1530/2357] libceph: flush msgr queue during mon_client shutdown (cherry picked from commit f3dea7edd3d449fe7a6d402c1ce56a294b985261) (cherry picked from commit 642c0dbde32f34baa7886e988a067089992adc8f) We need to flush the msgr workqueue during mon_client shutdown to ensure that any work affecting our embedded ceph_connection is finished so that we can be safely destroyed. Previously, we were flushing the work queue after osd_client shutdown and before mon_client shutdown to ensure that any osd connection refs to authorizers are flushed. Remove the redundant flush, and document in the comment that the mon_client flush is needed to cover that case as well. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/ceph_common.c | 7 ------- net/ceph/mon_client.c | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index cc913193d99..5dedac58faf 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -504,13 +504,6 @@ void ceph_destroy_client(struct ceph_client *client) /* unmount */ ceph_osdc_stop(&client->osdc); - /* - * make sure osd connections close out before destroying the - * auth module, which is needed to free those connections' - * ceph_authorizers. - */ - ceph_msgr_flush(); - ceph_monc_stop(&client->monc); ceph_debugfs_client_cleanup(client); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 1845cde2622..852dbb4a4e6 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -847,6 +847,14 @@ void ceph_monc_stop(struct ceph_mon_client *monc) mutex_unlock(&monc->mutex); + /* + * flush msgr queue before we destroy ourselves to ensure that: + * - any work that references our embedded con is finished. + * - any osd_client or other work that may reference an authorizer + * finishes before we shut down the auth subsystem. + */ + ceph_msgr_flush(); + ceph_auth_destroy(monc->auth); ceph_msg_put(monc->m_auth); From 49da293c7dc4401c2c7963a2c70f633b1c8fa8c5 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 10 Jul 2012 11:53:34 -0700 Subject: [PATCH 1531/2357] libceph: fix messenger retry (cherry picked from commit 5bdca4e0768d3e0f4efa43d9a2cc8210aeb91ab9) In ancient times, the messenger could both initiate and accept connections. An artifact if that was data structures to store/process an incoming ceph_msg_connect request and send an outgoing ceph_msg_connect_reply. Sadly, the negotiation code was referencing those structures and ignoring important information (like the peer's connect_seq) from the correct ones. Among other things, this fixes tight reconnect loops where the server sends RETRY_SESSION and we (the client) retries with the same connect_seq as last time. This bug pretty easily triggered by injecting socket failures on the MDS and running some fs workload like workunits/direct_io/test_sync_io. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 12 ++---------- net/ceph/messenger.c | 12 ++++++------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 2521a95fa6d..44c87e731e9 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -163,16 +163,8 @@ struct ceph_connection { /* connection negotiation temps */ char in_banner[CEPH_BANNER_MAX_LEN]; - union { - struct { /* outgoing connection */ - struct ceph_msg_connect out_connect; - struct ceph_msg_connect_reply in_reply; - }; - struct { /* incoming */ - struct ceph_msg_connect in_connect; - struct ceph_msg_connect_reply out_reply; - }; - }; + struct ceph_msg_connect out_connect; + struct ceph_msg_connect_reply in_reply; struct ceph_entity_addr actual_peer_addr; /* message out temps */ diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 375ae3953e2..0e270166f72 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1423,7 +1423,7 @@ static int process_connect(struct ceph_connection *con) * dropped messages. */ dout("process_connect got RESET peer seq %u\n", - le32_to_cpu(con->in_connect.connect_seq)); + le32_to_cpu(con->in_reply.connect_seq)); pr_err("%s%lld %s connection reset\n", ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr)); @@ -1450,10 +1450,10 @@ static int process_connect(struct ceph_connection *con) * If we sent a smaller connect_seq than the peer has, try * again with a larger value. */ - dout("process_connect got RETRY my seq = %u, peer_seq = %u\n", + dout("process_connect got RETRY_SESSION my seq %u, peer %u\n", le32_to_cpu(con->out_connect.connect_seq), - le32_to_cpu(con->in_connect.connect_seq)); - con->connect_seq = le32_to_cpu(con->in_connect.connect_seq); + le32_to_cpu(con->in_reply.connect_seq)); + con->connect_seq = le32_to_cpu(con->in_reply.connect_seq); ceph_con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) @@ -1468,9 +1468,9 @@ static int process_connect(struct ceph_connection *con) */ dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n", con->peer_global_seq, - le32_to_cpu(con->in_connect.global_seq)); + le32_to_cpu(con->in_reply.global_seq)); get_global_seq(con->msgr, - le32_to_cpu(con->in_connect.global_seq)); + le32_to_cpu(con->in_reply.global_seq)); ceph_con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) From 095cb2142dfb10daea5a3351ed9646d3178a6823 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 4 Apr 2012 13:35:44 -0500 Subject: [PATCH 1532/2357] rbd: don't hold spinlock during messenger flush (cherry picked from commit cd9d9f5df6098c50726200d4185e9e8da32785b3) A recent change made changes to the rbd_client_list be protected by a spinlock. Unfortunately in rbd_put_client(), the lock is taken before possibly dropping the last reference to an rbd_client, and on the last reference that eventually calls flush_workqueue() which can sleep. The problem was flagged by a debug spinlock warning: BUG: spinlock wrong CPU on CPU#3, rbd/27814 The solution is to move the spinlock acquisition and release inside rbd_client_release(), which is the spot where it's really needed for protecting the removal of the rbd_client from the client list. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 013c7a549fb..c1f77013165 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -450,7 +450,9 @@ static void rbd_client_release(struct kref *kref) struct rbd_client *rbdc = container_of(kref, struct rbd_client, kref); dout("rbd_release_client %p\n", rbdc); + spin_lock(&rbd_client_list_lock); list_del(&rbdc->node); + spin_unlock(&rbd_client_list_lock); ceph_destroy_client(rbdc->client); kfree(rbdc->rbd_opts); @@ -463,9 +465,7 @@ static void rbd_client_release(struct kref *kref) */ static void rbd_put_client(struct rbd_device *rbd_dev) { - spin_lock(&rbd_client_list_lock); kref_put(&rbd_dev->rbd_client->kref, rbd_client_release); - spin_unlock(&rbd_client_list_lock); rbd_dev->rbd_client = NULL; } From 45739514727c294e843269d515b952d5dbd911bf Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 5 Dec 2011 10:47:13 -0800 Subject: [PATCH 1533/2357] rbd: protect read of snapshot sequence number (cherry picked from commit 403f24d3d51760a8b9368d595fa5f48c309f1a0f) This is updated whenever a snapshot is added or deleted, and the snapc pointer is changed with every refresh of the header. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder Reviewed-by: Yehuda Sadeh Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index c1f77013165..ff224baf0ff 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1683,7 +1683,9 @@ static int rbd_header_add_snap(struct rbd_device *dev, if (ret < 0) return ret; - dev->header.snapc->seq = new_snapid; + down_write(&dev->header_rwsem); + dev->header.snapc->seq = new_snapid; + up_write(&dev->header_rwsem); return 0; bad: From 6448acf6e6b603c4fa21697931cd400ebee21d4a Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 21 Nov 2011 13:04:42 -0800 Subject: [PATCH 1534/2357] rbd: store snapshot id instead of index (cherry picked from commit 77dfe99fe3cb0b2b0545e19e2d57b7a9134ee3c0) When a device was open at a snapshot, and snapshots were deleted or added, data from the wrong snapshot could be read. Instead of assuming the snap context is constant, store the actual snap id when the device is initialized, and rely on the OSDs to signal an error if we try reading from a snapshot that was deleted. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder Reviewed-by: Yehuda Sadeh Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index ff224baf0ff..d074ed9e233 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -175,8 +175,7 @@ struct rbd_device { /* protects updating the header */ struct rw_semaphore header_rwsem; char snap_name[RBD_MAX_SNAP_NAME_LEN]; - u32 cur_snap; /* index+1 of current snapshot within snap context - 0 - for the head */ + u64 snap_id; /* current snapshot id */ int read_only; struct list_head node; @@ -552,21 +551,6 @@ static int rbd_header_from_disk(struct rbd_image_header *header, return -ENOMEM; } -static int snap_index(struct rbd_image_header *header, int snap_num) -{ - return header->total_snaps - snap_num; -} - -static u64 cur_snap_id(struct rbd_device *rbd_dev) -{ - struct rbd_image_header *header = &rbd_dev->header; - - if (!rbd_dev->cur_snap) - return 0; - - return header->snapc->snaps[snap_index(header, rbd_dev->cur_snap)]; -} - static int snap_by_name(struct rbd_image_header *header, const char *snap_name, u64 *seq, u64 *size) { @@ -605,7 +589,7 @@ static int rbd_header_set_snap(struct rbd_device *dev, u64 *size) snapc->seq = header->snap_seq; else snapc->seq = 0; - dev->cur_snap = 0; + dev->snap_id = CEPH_NOSNAP; dev->read_only = 0; if (size) *size = header->image_size; @@ -613,8 +597,7 @@ static int rbd_header_set_snap(struct rbd_device *dev, u64 *size) ret = snap_by_name(header, dev->snap_name, &snapc->seq, size); if (ret < 0) goto done; - - dev->cur_snap = header->total_snaps - ret; + dev->snap_id = snapc->seq; dev->read_only = 1; } @@ -1521,7 +1504,7 @@ static void rbd_rq_fn(struct request_queue *q) coll, cur_seg); else rbd_req_read(rq, rbd_dev, - cur_snap_id(rbd_dev), + rbd_dev->snap_id, ofs, op_size, bio, coll, cur_seg); @@ -1656,7 +1639,7 @@ static int rbd_header_add_snap(struct rbd_device *dev, struct ceph_mon_client *monc; /* we should create a snapshot only if we're pointing at the head */ - if (dev->cur_snap) + if (dev->snap_id != CEPH_NOSNAP) return -EINVAL; monc = &dev->rbd_client->client->monc; From 9923ad77a69ab565af2746262989cc0340943668 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 6 Jun 2012 09:15:33 -0500 Subject: [PATCH 1535/2357] rbd: Fix ceph_snap_context size calculation (cherry picked from commit f9f9a1904467816452fc70740165030e84c2c659) ceph_snap_context->snaps is an u64 array Signed-off-by: Zheng Yan Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index d074ed9e233..7b331366a8a 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -497,7 +497,7 @@ static int rbd_header_from_disk(struct rbd_image_header *header, snap_count = le32_to_cpu(ondisk->snap_count); header->snapc = kmalloc(sizeof(struct ceph_snap_context) + - snap_count * sizeof (*ondisk), + snap_count * sizeof(u64), gfp_flags); if (!header->snapc) return -ENOMEM; From e7fda85c9dab7396c5ed7345ab7c6fcdf4ffc366 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 28 May 2012 14:44:30 +0800 Subject: [PATCH 1536/2357] ceph: check PG_Private flag before accessing page->private (cherry picked from commit 28c0254ede13ab575d2df5c6585ed3d4817c3e6b) I got lots of NULL pointer dereference Oops when compiling kernel on ceph. The bug is because the kernel page migration routine replaces some pages in the page cache with new pages, these new pages' private can be non-zero. Signed-off-by: Zheng Yan Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/addr.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 173b1d22e59..8b67304e4b8 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -54,7 +54,12 @@ (CONGESTION_ON_THRESH(congestion_kb) - \ (CONGESTION_ON_THRESH(congestion_kb) >> 2)) - +static inline struct ceph_snap_context *page_snap_context(struct page *page) +{ + if (PagePrivate(page)) + return (void *)page->private; + return NULL; +} /* * Dirty a page. Optimistically adjust accounting, on the assumption @@ -142,10 +147,9 @@ static void ceph_invalidatepage(struct page *page, unsigned long offset) { struct inode *inode; struct ceph_inode_info *ci; - struct ceph_snap_context *snapc = (void *)page->private; + struct ceph_snap_context *snapc = page_snap_context(page); BUG_ON(!PageLocked(page)); - BUG_ON(!page->private); BUG_ON(!PagePrivate(page)); BUG_ON(!page->mapping); @@ -182,7 +186,6 @@ static int ceph_releasepage(struct page *page, gfp_t g) struct inode *inode = page->mapping ? page->mapping->host : NULL; dout("%p releasepage %p idx %lu\n", inode, page, page->index); WARN_ON(PageDirty(page)); - WARN_ON(page->private); WARN_ON(PagePrivate(page)); return 0; } @@ -443,7 +446,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) osdc = &fsc->client->osdc; /* verify this is a writeable snap context */ - snapc = (void *)page->private; + snapc = page_snap_context(page); if (snapc == NULL) { dout("writepage %p page %p not dirty?\n", inode, page); goto out; @@ -451,7 +454,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) oldest = get_oldest_context(inode, &snap_size); if (snapc->seq > oldest->seq) { dout("writepage %p page %p snapc %p not writeable - noop\n", - inode, page, (void *)page->private); + inode, page, snapc); /* we should only noop if called by kswapd */ WARN_ON((current->flags & PF_MEMALLOC) == 0); ceph_put_snap_context(oldest); @@ -591,7 +594,7 @@ static void writepages_finish(struct ceph_osd_request *req, clear_bdi_congested(&fsc->backing_dev_info, BLK_RW_ASYNC); - ceph_put_snap_context((void *)page->private); + ceph_put_snap_context(page_snap_context(page)); page->private = 0; ClearPagePrivate(page); dout("unlocking %d %p\n", i, page); @@ -795,7 +798,7 @@ static int ceph_writepages_start(struct address_space *mapping, } /* only if matching snap context */ - pgsnapc = (void *)page->private; + pgsnapc = page_snap_context(page); if (pgsnapc->seq > snapc->seq) { dout("page snapc %p %lld > oldest %p %lld\n", pgsnapc, pgsnapc->seq, snapc, snapc->seq); @@ -984,7 +987,7 @@ static int ceph_update_writeable_page(struct file *file, BUG_ON(!ci->i_snap_realm); down_read(&mdsc->snap_rwsem); BUG_ON(!ci->i_snap_realm->cached_context); - snapc = (void *)page->private; + snapc = page_snap_context(page); if (snapc && snapc != ci->i_head_snapc) { /* * this page is already dirty in another (older) snap From ac7a42681718cd7474cec70f198f0684ba7444eb Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 22 May 2012 11:41:43 -0500 Subject: [PATCH 1537/2357] libceph: eliminate connection state "DEAD" (cherry picked from commit e5e372da9a469dfe3ece40277090a7056c566838) The ceph connection state "DEAD" is never set and is therefore not needed. Eliminate it. Signed-off-by: Alex Elder Reviewed-by: Yehuda Sadeh Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 1 - net/ceph/messenger.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 44c87e731e9..6a1dc80cf1e 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -119,7 +119,6 @@ struct ceph_msg_pos { #define CLOSED 10 /* we've closed the connection */ #define SOCK_CLOSED 11 /* socket state changed to closed */ #define OPENING 13 /* open connection w/ (possibly new) peer */ -#define DEAD 14 /* dead, about to kfree */ #define BACKOFF 15 /* diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 0e270166f72..4054adb6651 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2091,12 +2091,6 @@ static int try_read(struct ceph_connection *con) */ static void queue_con(struct ceph_connection *con) { - if (test_bit(DEAD, &con->state)) { - dout("queue_con %p ignoring: DEAD\n", - con); - return; - } - if (!con->ops->get(con)) { dout("queue_con %p ref count 0\n", con); return; From 809c58f1bd5fa3d3e9ff1d3614c00c1a1239abf1 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 29 May 2012 21:47:38 -0500 Subject: [PATCH 1538/2357] libceph: kill bad_proto ceph connection op (cherry picked from commit 6384bb8b8e88a9c6bf2ae0d9517c2c0199177c34) No code sets a bad_proto method in its ceph connection operations vector, so just get rid of it. Signed-off-by: Alex Elder Reviewed-by: Yehuda Sadeh Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 3 --- net/ceph/messenger.c | 5 ----- 2 files changed, 8 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 6a1dc80cf1e..ce7a4830529 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -31,9 +31,6 @@ struct ceph_connection_operations { int (*verify_authorizer_reply) (struct ceph_connection *con, int len); int (*invalidate_authorizer)(struct ceph_connection *con); - /* protocol version mismatch */ - void (*bad_proto) (struct ceph_connection *con); - /* there was some error on the socket (disconnect, whatever) */ void (*fault) (struct ceph_connection *con); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 4054adb6651..b408ea7cce9 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1360,11 +1360,6 @@ static void fail_protocol(struct ceph_connection *con) { reset_connection(con); set_bit(CLOSED, &con->state); /* in case there's queued work */ - - mutex_unlock(&con->mutex); - if (con->ops->bad_proto) - con->ops->bad_proto(con); - mutex_lock(&con->mutex); } static int process_connect(struct ceph_connection *con) From f5e79a443054452866bba4856ed243faf502d708 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 22 May 2012 11:41:43 -0500 Subject: [PATCH 1539/2357] libceph: rename socket callbacks (cherry picked from commit 327800bdc2cb9b71f4b458ca07aa9d522668dde0) Change the names of the three socket callback functions to make it more obvious they're specifically associated with a connection's socket (not the ceph connection that uses it). Signed-off-by: Alex Elder Reviewed-by: Yehuda Sadeh Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index b408ea7cce9..1250b157b9d 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -153,46 +153,46 @@ EXPORT_SYMBOL(ceph_msgr_flush); */ /* data available on socket, or listen socket received a connect */ -static void ceph_data_ready(struct sock *sk, int count_unused) +static void ceph_sock_data_ready(struct sock *sk, int count_unused) { struct ceph_connection *con = sk->sk_user_data; if (sk->sk_state != TCP_CLOSE_WAIT) { - dout("ceph_data_ready on %p state = %lu, queueing work\n", + dout("%s on %p state = %lu, queueing work\n", __func__, con, con->state); queue_con(con); } } /* socket has buffer space for writing */ -static void ceph_write_space(struct sock *sk) +static void ceph_sock_write_space(struct sock *sk) { struct ceph_connection *con = sk->sk_user_data; /* only queue to workqueue if there is data we want to write, * and there is sufficient space in the socket buffer to accept - * more data. clear SOCK_NOSPACE so that ceph_write_space() + * more data. clear SOCK_NOSPACE so that ceph_sock_write_space() * doesn't get called again until try_write() fills the socket * buffer. See net/ipv4/tcp_input.c:tcp_check_space() * and net/core/stream.c:sk_stream_write_space(). */ if (test_bit(WRITE_PENDING, &con->state)) { if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { - dout("ceph_write_space %p queueing write work\n", con); + dout("%s %p queueing write work\n", __func__, con); clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); queue_con(con); } } else { - dout("ceph_write_space %p nothing to write\n", con); + dout("%s %p nothing to write\n", __func__, con); } } /* socket's state has changed */ -static void ceph_state_change(struct sock *sk) +static void ceph_sock_state_change(struct sock *sk) { struct ceph_connection *con = sk->sk_user_data; - dout("ceph_state_change %p state = %lu sk_state = %u\n", + dout("%s %p state = %lu sk_state = %u\n", __func__, con, con->state, sk->sk_state); if (test_bit(CLOSED, &con->state)) @@ -200,9 +200,9 @@ static void ceph_state_change(struct sock *sk) switch (sk->sk_state) { case TCP_CLOSE: - dout("ceph_state_change TCP_CLOSE\n"); + dout("%s TCP_CLOSE\n", __func__); case TCP_CLOSE_WAIT: - dout("ceph_state_change TCP_CLOSE_WAIT\n"); + dout("%s TCP_CLOSE_WAIT\n", __func__); if (test_and_set_bit(SOCK_CLOSED, &con->state) == 0) { if (test_bit(CONNECTING, &con->state)) con->error_msg = "connection failed"; @@ -212,7 +212,7 @@ static void ceph_state_change(struct sock *sk) } break; case TCP_ESTABLISHED: - dout("ceph_state_change TCP_ESTABLISHED\n"); + dout("%s TCP_ESTABLISHED\n", __func__); queue_con(con); break; default: /* Everything else is uninteresting */ @@ -228,9 +228,9 @@ static void set_sock_callbacks(struct socket *sock, { struct sock *sk = sock->sk; sk->sk_user_data = con; - sk->sk_data_ready = ceph_data_ready; - sk->sk_write_space = ceph_write_space; - sk->sk_state_change = ceph_state_change; + sk->sk_data_ready = ceph_sock_data_ready; + sk->sk_write_space = ceph_sock_write_space; + sk->sk_state_change = ceph_sock_state_change; } From 4874ba9c07e2fa418cd7272d657f5cc883efd35a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 23 May 2012 14:35:23 -0500 Subject: [PATCH 1540/2357] libceph: rename kvec_reset and kvec_add functions (cherry picked from commit e22004235a900213625acd6583ac913d5a30c155) The functions ceph_con_out_kvec_reset() and ceph_con_out_kvec_add() are entirely private functions, so drop the "ceph_" prefix in their name to make them slightly more wieldy. Signed-off-by: Alex Elder Reviewed-by: Yehuda Sadeh Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 48 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 1250b157b9d..2a8f3d3ec1a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -486,14 +486,14 @@ static u32 get_global_seq(struct ceph_messenger *msgr, u32 gt) return ret; } -static void ceph_con_out_kvec_reset(struct ceph_connection *con) +static void con_out_kvec_reset(struct ceph_connection *con) { con->out_kvec_left = 0; con->out_kvec_bytes = 0; con->out_kvec_cur = &con->out_kvec[0]; } -static void ceph_con_out_kvec_add(struct ceph_connection *con, +static void con_out_kvec_add(struct ceph_connection *con, size_t size, void *data) { int index; @@ -534,7 +534,7 @@ static void prepare_write_message(struct ceph_connection *con) struct ceph_msg *m; u32 crc; - ceph_con_out_kvec_reset(con); + con_out_kvec_reset(con); con->out_kvec_is_msg = true; con->out_msg_done = false; @@ -542,9 +542,9 @@ static void prepare_write_message(struct ceph_connection *con) * TCP packet that's a good thing. */ if (con->in_seq > con->in_seq_acked) { con->in_seq_acked = con->in_seq; - ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); + con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); con->out_temp_ack = cpu_to_le64(con->in_seq_acked); - ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack), + con_out_kvec_add(con, sizeof (con->out_temp_ack), &con->out_temp_ack); } @@ -576,12 +576,12 @@ static void prepare_write_message(struct ceph_connection *con) BUG_ON(le32_to_cpu(m->hdr.front_len) != m->front.iov_len); /* tag + hdr + front + middle */ - ceph_con_out_kvec_add(con, sizeof (tag_msg), &tag_msg); - ceph_con_out_kvec_add(con, sizeof (m->hdr), &m->hdr); - ceph_con_out_kvec_add(con, m->front.iov_len, m->front.iov_base); + con_out_kvec_add(con, sizeof (tag_msg), &tag_msg); + con_out_kvec_add(con, sizeof (m->hdr), &m->hdr); + con_out_kvec_add(con, m->front.iov_len, m->front.iov_base); if (m->middle) - ceph_con_out_kvec_add(con, m->middle->vec.iov_len, + con_out_kvec_add(con, m->middle->vec.iov_len, m->middle->vec.iov_base); /* fill in crc (except data pages), footer */ @@ -630,12 +630,12 @@ static void prepare_write_ack(struct ceph_connection *con) con->in_seq_acked, con->in_seq); con->in_seq_acked = con->in_seq; - ceph_con_out_kvec_reset(con); + con_out_kvec_reset(con); - ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); + con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); con->out_temp_ack = cpu_to_le64(con->in_seq_acked); - ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack), + con_out_kvec_add(con, sizeof (con->out_temp_ack), &con->out_temp_ack); con->out_more = 1; /* more will follow.. eventually.. */ @@ -648,8 +648,8 @@ static void prepare_write_ack(struct ceph_connection *con) static void prepare_write_keepalive(struct ceph_connection *con) { dout("prepare_write_keepalive %p\n", con); - ceph_con_out_kvec_reset(con); - ceph_con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive); + con_out_kvec_reset(con); + con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive); set_bit(WRITE_PENDING, &con->state); } @@ -694,8 +694,8 @@ static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection */ static void prepare_write_banner(struct ceph_connection *con) { - ceph_con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER); - ceph_con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr), + con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER); + con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr), &con->msgr->my_enc_addr); con->out_more = 0; @@ -742,10 +742,10 @@ static int prepare_write_connect(struct ceph_connection *con) con->out_connect.authorizer_len = auth ? cpu_to_le32(auth->authorizer_buf_len) : 0; - ceph_con_out_kvec_add(con, sizeof (con->out_connect), + con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); if (auth && auth->authorizer_buf_len) - ceph_con_out_kvec_add(con, auth->authorizer_buf_len, + con_out_kvec_add(con, auth->authorizer_buf_len, auth->authorizer_buf); con->out_more = 0; @@ -939,7 +939,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) /* prepare and queue up footer, too */ if (!do_datacrc) con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC; - ceph_con_out_kvec_reset(con); + con_out_kvec_reset(con); prepare_write_message_footer(con); ret = 1; out: @@ -1402,7 +1402,7 @@ static int process_connect(struct ceph_connection *con) return -1; } con->auth_retry = 1; - ceph_con_out_kvec_reset(con); + con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1423,7 +1423,7 @@ static int process_connect(struct ceph_connection *con) ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr)); reset_connection(con); - ceph_con_out_kvec_reset(con); + con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1449,7 +1449,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->out_connect.connect_seq), le32_to_cpu(con->in_reply.connect_seq)); con->connect_seq = le32_to_cpu(con->in_reply.connect_seq); - ceph_con_out_kvec_reset(con); + con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1466,7 +1466,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->in_reply.global_seq)); get_global_seq(con->msgr, le32_to_cpu(con->in_reply.global_seq)); - ceph_con_out_kvec_reset(con); + con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1873,7 +1873,7 @@ static int try_write(struct ceph_connection *con) /* open the socket first? */ if (con->sock == NULL) { - ceph_con_out_kvec_reset(con); + con_out_kvec_reset(con); prepare_write_banner(con); ret = prepare_write_connect(con); if (ret < 0) From d910c114b6da5b78c88889eff1b3f9e83c6f81cb Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 26 May 2012 23:26:43 -0500 Subject: [PATCH 1541/2357] libceph: embed ceph messenger structure in ceph_client (cherry picked from commit 15d9882c336db2db73ccf9871ae2398e452f694c) A ceph client has a pointer to a ceph messenger structure in it. There is always exactly one ceph messenger for a ceph client, so there is no need to allocate it separate from the ceph client structure. Switch the ceph_client structure to embed its ceph_messenger structure. Signed-off-by: Alex Elder Reviewed-by: Yehuda Sadeh Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 2 +- include/linux/ceph/libceph.h | 2 +- include/linux/ceph/messenger.h | 9 +++++---- net/ceph/ceph_common.c | 18 +++++------------- net/ceph/messenger.c | 30 +++++++++--------------------- net/ceph/mon_client.c | 6 +++--- net/ceph/osd_client.c | 4 ++-- 7 files changed, 26 insertions(+), 45 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 200bc87eceb..ad30261cd4c 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -394,7 +394,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, s->s_seq = 0; mutex_init(&s->s_mutex); - ceph_con_init(mdsc->fsc->client->msgr, &s->s_con); + ceph_con_init(&mdsc->fsc->client->msgr, &s->s_con); s->s_con.private = s; s->s_con.ops = &mds_con_ops; s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS; diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index e71d683982a..98ec36ae8a3 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -132,7 +132,7 @@ struct ceph_client { u32 supported_features; u32 required_features; - struct ceph_messenger *msgr; /* messenger instance */ + struct ceph_messenger msgr; /* messenger instance */ struct ceph_mon_client monc; struct ceph_osd_client osdc; diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index ce7a4830529..771b2edd471 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -203,10 +203,11 @@ extern int ceph_msgr_init(void); extern void ceph_msgr_exit(void); extern void ceph_msgr_flush(void); -extern struct ceph_messenger *ceph_messenger_create( - struct ceph_entity_addr *myaddr, - u32 features, u32 required); -extern void ceph_messenger_destroy(struct ceph_messenger *); +extern void ceph_messenger_init(struct ceph_messenger *msgr, + struct ceph_entity_addr *myaddr, + u32 supported_features, + u32 required_features, + bool nocrc); extern void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con); diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 5dedac58faf..c815f31a1a3 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -468,19 +468,15 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private, /* msgr */ if (ceph_test_opt(client, MYIP)) myaddr = &client->options->my_addr; - client->msgr = ceph_messenger_create(myaddr, - client->supported_features, - client->required_features); - if (IS_ERR(client->msgr)) { - err = PTR_ERR(client->msgr); - goto fail; - } - client->msgr->nocrc = ceph_test_opt(client, NOCRC); + ceph_messenger_init(&client->msgr, myaddr, + client->supported_features, + client->required_features, + ceph_test_opt(client, NOCRC)); /* subsystems */ err = ceph_monc_init(&client->monc, client); if (err < 0) - goto fail_msgr; + goto fail; err = ceph_osdc_init(&client->osdc, client); if (err < 0) goto fail_monc; @@ -489,8 +485,6 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private, fail_monc: ceph_monc_stop(&client->monc); -fail_msgr: - ceph_messenger_destroy(client->msgr); fail: kfree(client); return ERR_PTR(err); @@ -508,8 +502,6 @@ void ceph_destroy_client(struct ceph_client *client) ceph_debugfs_client_cleanup(client); - ceph_messenger_destroy(client->msgr); - ceph_destroy_options(client->options); kfree(client); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 2a8f3d3ec1a..9570c762879 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2249,18 +2249,14 @@ static void ceph_fault(struct ceph_connection *con) /* - * create a new messenger instance + * initialize a new messenger instance */ -struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr, - u32 supported_features, - u32 required_features) +void ceph_messenger_init(struct ceph_messenger *msgr, + struct ceph_entity_addr *myaddr, + u32 supported_features, + u32 required_features, + bool nocrc) { - struct ceph_messenger *msgr; - - msgr = kzalloc(sizeof(*msgr), GFP_KERNEL); - if (msgr == NULL) - return ERR_PTR(-ENOMEM); - msgr->supported_features = supported_features; msgr->required_features = required_features; @@ -2273,19 +2269,11 @@ struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr, msgr->inst.addr.type = 0; get_random_bytes(&msgr->inst.addr.nonce, sizeof(msgr->inst.addr.nonce)); encode_my_addr(msgr); + msgr->nocrc = nocrc; - dout("messenger_create %p\n", msgr); - return msgr; -} -EXPORT_SYMBOL(ceph_messenger_create); - -void ceph_messenger_destroy(struct ceph_messenger *msgr) -{ - dout("destroy %p\n", msgr); - kfree(msgr); - dout("destroyed messenger %p\n", msgr); + dout("%s %p\n", __func__, msgr); } -EXPORT_SYMBOL(ceph_messenger_destroy); +EXPORT_SYMBOL(ceph_messenger_init); static void clear_standby(struct ceph_connection *con) { diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 852dbb4a4e6..b2d9ce4d80d 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -763,7 +763,7 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl) monc->con = kmalloc(sizeof(*monc->con), GFP_KERNEL); if (!monc->con) goto out_monmap; - ceph_con_init(monc->client->msgr, monc->con); + ceph_con_init(&monc->client->msgr, monc->con); monc->con->private = monc; monc->con->ops = &mon_con_ops; @@ -888,8 +888,8 @@ static void handle_auth_reply(struct ceph_mon_client *monc, } else if (!was_auth && monc->auth->ops->is_authenticated(monc->auth)) { dout("authenticated, starting session\n"); - monc->client->msgr->inst.name.type = CEPH_ENTITY_TYPE_CLIENT; - monc->client->msgr->inst.name.num = + monc->client->msgr.inst.name.type = CEPH_ENTITY_TYPE_CLIENT; + monc->client->msgr.inst.name.num = cpu_to_le64(monc->auth->global_id); __send_subscribe(monc); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index f4e2a4665d9..6c948dc4d77 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -639,7 +639,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc) INIT_LIST_HEAD(&osd->o_osd_lru); osd->o_incarnation = 1; - ceph_con_init(osdc->client->msgr, &osd->o_con); + ceph_con_init(&osdc->client->msgr, &osd->o_con); osd->o_con.private = osd; osd->o_con.ops = &osd_con_ops; osd->o_con.peer_name.type = CEPH_ENTITY_TYPE_OSD; @@ -1391,7 +1391,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) epoch, maplen); newmap = osdmap_apply_incremental(&p, next, osdc->osdmap, - osdc->client->msgr); + &osdc->client->msgr); if (IS_ERR(newmap)) { err = PTR_ERR(newmap); goto bad; From bc327474a0c9f3477be61b2d3e33833ef7b01bf9 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 22 May 2012 11:41:43 -0500 Subject: [PATCH 1542/2357] libceph: start separating connection flags from state (cherry picked from commit 928443cd9644e7cfd46f687dbeffda2d1a357ff9) A ceph_connection holds a mixture of connection state (as in "state machine" state) and connection flags in a single "state" field. To make the distinction more clear, define a new "flags" field and use it rather than the "state" field to hold Boolean flag values. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 18 ++++++++---- net/ceph/messenger.c | 50 +++++++++++++++++----------------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 771b2edd471..34e9506be6b 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -103,20 +103,25 @@ struct ceph_msg_pos { #define MAX_DELAY_INTERVAL (5 * 60 * HZ) /* - * ceph_connection state bit flags + * ceph_connection flag bits */ + #define LOSSYTX 0 /* we can close channel or drop messages on errors */ -#define CONNECTING 1 -#define NEGOTIATING 2 #define KEEPALIVE_PENDING 3 #define WRITE_PENDING 4 /* we have data ready to send */ +#define SOCK_CLOSED 11 /* socket state changed to closed */ +#define BACKOFF 15 + +/* + * ceph_connection states + */ +#define CONNECTING 1 +#define NEGOTIATING 2 #define STANDBY 8 /* no outgoing messages, socket closed. we keep * the ceph_connection around to maintain shared * state with the peer. */ #define CLOSED 10 /* we've closed the connection */ -#define SOCK_CLOSED 11 /* socket state changed to closed */ #define OPENING 13 /* open connection w/ (possibly new) peer */ -#define BACKOFF 15 /* * A single connection with another host. @@ -133,7 +138,8 @@ struct ceph_connection { struct ceph_messenger *msgr; struct socket *sock; - unsigned long state; /* connection state (see flags above) */ + unsigned long flags; + unsigned long state; const char *error_msg; /* error message, if any */ struct ceph_entity_addr peer_addr; /* peer address */ diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 9570c762879..27e4e58922b 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -176,7 +176,7 @@ static void ceph_sock_write_space(struct sock *sk) * buffer. See net/ipv4/tcp_input.c:tcp_check_space() * and net/core/stream.c:sk_stream_write_space(). */ - if (test_bit(WRITE_PENDING, &con->state)) { + if (test_bit(WRITE_PENDING, &con->flags)) { if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { dout("%s %p queueing write work\n", __func__, con); clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); @@ -203,7 +203,7 @@ static void ceph_sock_state_change(struct sock *sk) dout("%s TCP_CLOSE\n", __func__); case TCP_CLOSE_WAIT: dout("%s TCP_CLOSE_WAIT\n", __func__); - if (test_and_set_bit(SOCK_CLOSED, &con->state) == 0) { + if (test_and_set_bit(SOCK_CLOSED, &con->flags) == 0) { if (test_bit(CONNECTING, &con->state)) con->error_msg = "connection failed"; else @@ -395,9 +395,9 @@ void ceph_con_close(struct ceph_connection *con) ceph_pr_addr(&con->peer_addr.in_addr)); set_bit(CLOSED, &con->state); /* in case there's queued work */ clear_bit(STANDBY, &con->state); /* avoid connect_seq bump */ - clear_bit(LOSSYTX, &con->state); /* so we retry next connect */ - clear_bit(KEEPALIVE_PENDING, &con->state); - clear_bit(WRITE_PENDING, &con->state); + clear_bit(LOSSYTX, &con->flags); /* so we retry next connect */ + clear_bit(KEEPALIVE_PENDING, &con->flags); + clear_bit(WRITE_PENDING, &con->flags); mutex_lock(&con->mutex); reset_connection(con); con->peer_global_seq = 0; @@ -618,7 +618,7 @@ static void prepare_write_message(struct ceph_connection *con) prepare_write_message_footer(con); } - set_bit(WRITE_PENDING, &con->state); + set_bit(WRITE_PENDING, &con->flags); } /* @@ -639,7 +639,7 @@ static void prepare_write_ack(struct ceph_connection *con) &con->out_temp_ack); con->out_more = 1; /* more will follow.. eventually.. */ - set_bit(WRITE_PENDING, &con->state); + set_bit(WRITE_PENDING, &con->flags); } /* @@ -650,7 +650,7 @@ static void prepare_write_keepalive(struct ceph_connection *con) dout("prepare_write_keepalive %p\n", con); con_out_kvec_reset(con); con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive); - set_bit(WRITE_PENDING, &con->state); + set_bit(WRITE_PENDING, &con->flags); } /* @@ -679,7 +679,7 @@ static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection if (IS_ERR(auth)) return auth; - if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) + if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->flags)) return ERR_PTR(-EAGAIN); con->auth_reply_buf = auth->authorizer_reply_buf; @@ -699,7 +699,7 @@ static void prepare_write_banner(struct ceph_connection *con) &con->msgr->my_enc_addr); con->out_more = 0; - set_bit(WRITE_PENDING, &con->state); + set_bit(WRITE_PENDING, &con->flags); } static int prepare_write_connect(struct ceph_connection *con) @@ -749,7 +749,7 @@ static int prepare_write_connect(struct ceph_connection *con) auth->authorizer_buf); con->out_more = 0; - set_bit(WRITE_PENDING, &con->state); + set_bit(WRITE_PENDING, &con->flags); return 0; } @@ -1496,7 +1496,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->in_reply.connect_seq)); if (con->in_reply.flags & CEPH_MSG_CONNECT_LOSSY) - set_bit(LOSSYTX, &con->state); + set_bit(LOSSYTX, &con->flags); prepare_read_tag(con); break; @@ -1937,14 +1937,14 @@ static int try_write(struct ceph_connection *con) prepare_write_ack(con); goto more; } - if (test_and_clear_bit(KEEPALIVE_PENDING, &con->state)) { + if (test_and_clear_bit(KEEPALIVE_PENDING, &con->flags)) { prepare_write_keepalive(con); goto more; } } /* Nothing to do! */ - clear_bit(WRITE_PENDING, &con->state); + clear_bit(WRITE_PENDING, &con->flags); dout("try_write nothing else to write.\n"); ret = 0; out: @@ -2110,7 +2110,7 @@ static void con_work(struct work_struct *work) mutex_lock(&con->mutex); restart: - if (test_and_clear_bit(BACKOFF, &con->state)) { + if (test_and_clear_bit(BACKOFF, &con->flags)) { dout("con_work %p backing off\n", con); if (queue_delayed_work(ceph_msgr_wq, &con->work, round_jiffies_relative(con->delay))) { @@ -2139,7 +2139,7 @@ static void con_work(struct work_struct *work) con_close_socket(con); } - if (test_and_clear_bit(SOCK_CLOSED, &con->state)) + if (test_and_clear_bit(SOCK_CLOSED, &con->flags)) goto fault; ret = try_read(con); @@ -2178,7 +2178,7 @@ static void ceph_fault(struct ceph_connection *con) dout("fault %p state %lu to peer %s\n", con, con->state, ceph_pr_addr(&con->peer_addr.in_addr)); - if (test_bit(LOSSYTX, &con->state)) { + if (test_bit(LOSSYTX, &con->flags)) { dout("fault on LOSSYTX channel\n"); goto out; } @@ -2200,9 +2200,9 @@ static void ceph_fault(struct ceph_connection *con) /* If there are no messages queued or keepalive pending, place * the connection in a STANDBY state */ if (list_empty(&con->out_queue) && - !test_bit(KEEPALIVE_PENDING, &con->state)) { + !test_bit(KEEPALIVE_PENDING, &con->flags)) { dout("fault %p setting STANDBY clearing WRITE_PENDING\n", con); - clear_bit(WRITE_PENDING, &con->state); + clear_bit(WRITE_PENDING, &con->flags); set_bit(STANDBY, &con->state); } else { /* retry after a delay. */ @@ -2226,7 +2226,7 @@ static void ceph_fault(struct ceph_connection *con) * that when con_work restarts we schedule the * delay then. */ - set_bit(BACKOFF, &con->state); + set_bit(BACKOFF, &con->flags); } } @@ -2282,8 +2282,8 @@ static void clear_standby(struct ceph_connection *con) mutex_lock(&con->mutex); dout("clear_standby %p and ++connect_seq\n", con); con->connect_seq++; - WARN_ON(test_bit(WRITE_PENDING, &con->state)); - WARN_ON(test_bit(KEEPALIVE_PENDING, &con->state)); + WARN_ON(test_bit(WRITE_PENDING, &con->flags)); + WARN_ON(test_bit(KEEPALIVE_PENDING, &con->flags)); mutex_unlock(&con->mutex); } } @@ -2321,7 +2321,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg) /* if there wasn't anything waiting to send before, queue * new work */ clear_standby(con); - if (test_and_set_bit(WRITE_PENDING, &con->state) == 0) + if (test_and_set_bit(WRITE_PENDING, &con->flags) == 0) queue_con(con); } EXPORT_SYMBOL(ceph_con_send); @@ -2388,8 +2388,8 @@ void ceph_con_keepalive(struct ceph_connection *con) { dout("con_keepalive %p\n", con); clear_standby(con); - if (test_and_set_bit(KEEPALIVE_PENDING, &con->state) == 0 && - test_and_set_bit(WRITE_PENDING, &con->state) == 0) + if (test_and_set_bit(KEEPALIVE_PENDING, &con->flags) == 0 && + test_and_set_bit(WRITE_PENDING, &con->flags) == 0) queue_con(con); } EXPORT_SYMBOL(ceph_con_keepalive); From 0bcd15777405bf024a3ec591731582f7263ea1c0 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 22 May 2012 22:15:49 -0500 Subject: [PATCH 1543/2357] libceph: start tracking connection socket state (cherry picked from commit ce2c8903e76e690846a00a0284e4bd9ee954d680) Start explicitly keeping track of the state of a ceph connection's socket, separate from the state of the connection itself. Create placeholder functions to encapsulate the state transitions. -------- | NEW* | transient initial state -------- | con_sock_state_init() v ---------- | CLOSED | initialized, but no socket (and no ---------- TCP connection) ^ \ | \ con_sock_state_connecting() | ---------------------- | \ + con_sock_state_closed() \ |\ \ | \ \ | ----------- \ | | CLOSING | socket event; \ | ----------- await close \ | ^ | | | | | + con_sock_state_closing() | | / \ | | / --------------- | | / \ v | / -------------- | / -----------------| CONNECTING | socket created, TCP | | / -------------- connect initiated | | | con_sock_state_connected() | | v ------------- | CONNECTED | TCP connection established ------------- Make the socket state an atomic variable, reinforcing that it's a distinct transtion with no possible "intermediate/both" states. This is almost certainly overkill at this point, though the transitions into CONNECTED and CLOSING state do get called via socket callback (the rest of the transitions occur with the connection mutex held). We can back out the atomicity later. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 8 +++-- net/ceph/messenger.c | 64 ++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 34e9506be6b..5f30c81d474 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -137,14 +137,18 @@ struct ceph_connection { const struct ceph_connection_operations *ops; struct ceph_messenger *msgr; + + atomic_t sock_state; struct socket *sock; + struct ceph_entity_addr peer_addr; /* peer address */ + struct ceph_entity_addr peer_addr_for_me; + unsigned long flags; unsigned long state; const char *error_msg; /* error message, if any */ - struct ceph_entity_addr peer_addr; /* peer address */ struct ceph_entity_name peer_name; /* peer name */ - struct ceph_entity_addr peer_addr_for_me; + unsigned peer_features; u32 connect_seq; /* identify the most recent connection attempt for this connection, client */ diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 27e4e58922b..2ad67994e43 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -29,6 +29,14 @@ * the sender. */ +/* State values for ceph_connection->sock_state; NEW is assumed to be 0 */ + +#define CON_SOCK_STATE_NEW 0 /* -> CLOSED */ +#define CON_SOCK_STATE_CLOSED 1 /* -> CONNECTING */ +#define CON_SOCK_STATE_CONNECTING 2 /* -> CONNECTED or -> CLOSING */ +#define CON_SOCK_STATE_CONNECTED 3 /* -> CLOSING or -> CLOSED */ +#define CON_SOCK_STATE_CLOSING 4 /* -> CLOSED */ + /* static tag bytes (protocol control messages) */ static char tag_msg = CEPH_MSGR_TAG_MSG; static char tag_ack = CEPH_MSGR_TAG_ACK; @@ -147,6 +155,55 @@ void ceph_msgr_flush(void) } EXPORT_SYMBOL(ceph_msgr_flush); +/* Connection socket state transition functions */ + +static void con_sock_state_init(struct ceph_connection *con) +{ + int old_state; + + old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSED); + if (WARN_ON(old_state != CON_SOCK_STATE_NEW)) + printk("%s: unexpected old state %d\n", __func__, old_state); +} + +static void con_sock_state_connecting(struct ceph_connection *con) +{ + int old_state; + + old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CONNECTING); + if (WARN_ON(old_state != CON_SOCK_STATE_CLOSED)) + printk("%s: unexpected old state %d\n", __func__, old_state); +} + +static void con_sock_state_connected(struct ceph_connection *con) +{ + int old_state; + + old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CONNECTED); + if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTING)) + printk("%s: unexpected old state %d\n", __func__, old_state); +} + +static void con_sock_state_closing(struct ceph_connection *con) +{ + int old_state; + + old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSING); + if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTING && + old_state != CON_SOCK_STATE_CONNECTED && + old_state != CON_SOCK_STATE_CLOSING)) + printk("%s: unexpected old state %d\n", __func__, old_state); +} + +static void con_sock_state_closed(struct ceph_connection *con) +{ + int old_state; + + old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSED); + if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTED && + old_state != CON_SOCK_STATE_CLOSING)) + printk("%s: unexpected old state %d\n", __func__, old_state); +} /* * socket callback functions @@ -203,6 +260,7 @@ static void ceph_sock_state_change(struct sock *sk) dout("%s TCP_CLOSE\n", __func__); case TCP_CLOSE_WAIT: dout("%s TCP_CLOSE_WAIT\n", __func__); + con_sock_state_closing(con); if (test_and_set_bit(SOCK_CLOSED, &con->flags) == 0) { if (test_bit(CONNECTING, &con->state)) con->error_msg = "connection failed"; @@ -213,6 +271,7 @@ static void ceph_sock_state_change(struct sock *sk) break; case TCP_ESTABLISHED: dout("%s TCP_ESTABLISHED\n", __func__); + con_sock_state_connected(con); queue_con(con); break; default: /* Everything else is uninteresting */ @@ -277,6 +336,7 @@ static int ceph_tcp_connect(struct ceph_connection *con) return ret; } con->sock = sock; + con_sock_state_connecting(con); return 0; } @@ -343,6 +403,7 @@ static int con_close_socket(struct ceph_connection *con) sock_release(con->sock); con->sock = NULL; clear_bit(SOCK_CLOSED, &con->state); + con_sock_state_closed(con); return rc; } @@ -462,6 +523,9 @@ void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con) memset(con, 0, sizeof(*con)); atomic_set(&con->nref, 1); con->msgr = msgr; + + con_sock_state_init(con); + mutex_init(&con->mutex); INIT_LIST_HEAD(&con->out_queue); INIT_LIST_HEAD(&con->out_sent); From d39319ee9b0381848a7e2261d53914e2732191d7 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 26 May 2012 23:26:43 -0500 Subject: [PATCH 1544/2357] libceph: provide osd number when creating osd (cherry picked from commit e10006f807ffc4d5b1d861305d18d9e8145891ca) Pass the osd number to the create_osd() routine, and move the initialization of fields that depend on it therein. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 6c948dc4d77..5b41a6929cd 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -624,7 +624,7 @@ static void osd_reset(struct ceph_connection *con) /* * Track open sessions with osds. */ -static struct ceph_osd *create_osd(struct ceph_osd_client *osdc) +static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum) { struct ceph_osd *osd; @@ -634,6 +634,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc) atomic_set(&osd->o_ref, 1); osd->o_osdc = osdc; + osd->o_osd = onum; INIT_LIST_HEAD(&osd->o_requests); INIT_LIST_HEAD(&osd->o_linger_requests); INIT_LIST_HEAD(&osd->o_osd_lru); @@ -643,6 +644,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc) osd->o_con.private = osd; osd->o_con.ops = &osd_con_ops; osd->o_con.peer_name.type = CEPH_ENTITY_TYPE_OSD; + osd->o_con.peer_name.num = cpu_to_le64(onum); INIT_LIST_HEAD(&osd->o_keepalive_item); return osd; @@ -998,15 +1000,13 @@ static int __map_request(struct ceph_osd_client *osdc, req->r_osd = __lookup_osd(osdc, o); if (!req->r_osd && o >= 0) { err = -ENOMEM; - req->r_osd = create_osd(osdc); + req->r_osd = create_osd(osdc, o); if (!req->r_osd) { list_move(&req->r_req_lru_item, &osdc->req_notarget); goto out; } dout("map_request osd %p is osd%d\n", req->r_osd, o); - req->r_osd->o_osd = o; - req->r_osd->o_con.peer_name.num = cpu_to_le64(o); __insert_osd(osdc, req->r_osd); ceph_con_open(&req->r_osd->o_con, &osdc->osdmap->osd_addr[o]); From 51588ed26f489e50bfd2359d55abcb4d907149bc Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 29 May 2012 11:04:58 -0500 Subject: [PATCH 1545/2357] libceph: set CLOSED state bit in con_init (cherry picked from commit a5988c490ef66cb04ea2f610681949b25c773b3c) Once a connection is fully initialized, it is really in a CLOSED state, so make that explicit by setting the bit in its state field. It is possible for a connection in NEGOTIATING state to get a failure, leading to ceph_fault() and ultimately ceph_con_close(). Clear that bits if it is set in that case, to reflect that the connection truly is closed and is no longer participating in a connect sequence. Issue a warning if ceph_con_open() is called on a connection that is not in CLOSED state. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 2ad67994e43..ca0e4c126f4 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -454,11 +454,14 @@ void ceph_con_close(struct ceph_connection *con) { dout("con_close %p peer %s\n", con, ceph_pr_addr(&con->peer_addr.in_addr)); - set_bit(CLOSED, &con->state); /* in case there's queued work */ + clear_bit(NEGOTIATING, &con->state); clear_bit(STANDBY, &con->state); /* avoid connect_seq bump */ + set_bit(CLOSED, &con->state); + clear_bit(LOSSYTX, &con->flags); /* so we retry next connect */ clear_bit(KEEPALIVE_PENDING, &con->flags); clear_bit(WRITE_PENDING, &con->flags); + mutex_lock(&con->mutex); reset_connection(con); con->peer_global_seq = 0; @@ -475,7 +478,8 @@ void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr) { dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr)); set_bit(OPENING, &con->state); - clear_bit(CLOSED, &con->state); + WARN_ON(!test_and_clear_bit(CLOSED, &con->state)); + memcpy(&con->peer_addr, addr, sizeof(*addr)); con->delay = 0; /* reset backoff memory */ queue_con(con); @@ -530,6 +534,8 @@ void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con) INIT_LIST_HEAD(&con->out_queue); INIT_LIST_HEAD(&con->out_sent); INIT_DELAYED_WORK(&con->work, con_work); + + set_bit(CLOSED, &con->state); } EXPORT_SYMBOL(ceph_con_init); @@ -1937,14 +1943,15 @@ static int try_write(struct ceph_connection *con) /* open the socket first? */ if (con->sock == NULL) { + clear_bit(NEGOTIATING, &con->state); + set_bit(CONNECTING, &con->state); + con_out_kvec_reset(con); prepare_write_banner(con); ret = prepare_write_connect(con); if (ret < 0) goto out; prepare_read_banner(con); - set_bit(CONNECTING, &con->state); - clear_bit(NEGOTIATING, &con->state); BUG_ON(con->in_msg); con->in_tag = CEPH_MSGR_TAG_READY; From 31a84d83433edc79151e28762c1992c0708b222c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 26 May 2012 23:26:43 -0500 Subject: [PATCH 1546/2357] libceph: embed ceph connection structure in mon_client (cherry picked from commit 67130934fb579fdf0f2f6d745960264378b57dc8) A monitor client has a pointer to a ceph connection structure in it. This is the only one of the three ceph client types that do it this way; the OSD and MDS clients embed the connection into their main structures. There is always exactly one ceph connection for a monitor client, so there is no need to allocate it separate from the monitor client structure. So switch the ceph_mon_client structure to embed its ceph_connection structure. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/mon_client.h | 2 +- net/ceph/mon_client.c | 47 ++++++++++++++------------------- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/include/linux/ceph/mon_client.h b/include/linux/ceph/mon_client.h index 545f8591778..2113e3850a4 100644 --- a/include/linux/ceph/mon_client.h +++ b/include/linux/ceph/mon_client.h @@ -70,7 +70,7 @@ struct ceph_mon_client { bool hunting; int cur_mon; /* last monitor i contacted */ unsigned long sub_sent, sub_renew_after; - struct ceph_connection *con; + struct ceph_connection con; bool have_fsid; /* pending generic requests */ diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index b2d9ce4d80d..5cdd8f6d38d 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -106,9 +106,9 @@ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len) monc->pending_auth = 1; monc->m_auth->front.iov_len = len; monc->m_auth->hdr.front_len = cpu_to_le32(len); - ceph_con_revoke(monc->con, monc->m_auth); + ceph_con_revoke(&monc->con, monc->m_auth); ceph_msg_get(monc->m_auth); /* keep our ref */ - ceph_con_send(monc->con, monc->m_auth); + ceph_con_send(&monc->con, monc->m_auth); } /* @@ -117,8 +117,8 @@ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len) static void __close_session(struct ceph_mon_client *monc) { dout("__close_session closing mon%d\n", monc->cur_mon); - ceph_con_revoke(monc->con, monc->m_auth); - ceph_con_close(monc->con); + ceph_con_revoke(&monc->con, monc->m_auth); + ceph_con_close(&monc->con); monc->cur_mon = -1; monc->pending_auth = 0; ceph_auth_reset(monc->auth); @@ -142,9 +142,9 @@ static int __open_session(struct ceph_mon_client *monc) monc->want_next_osdmap = !!monc->want_next_osdmap; dout("open_session mon%d opening\n", monc->cur_mon); - monc->con->peer_name.type = CEPH_ENTITY_TYPE_MON; - monc->con->peer_name.num = cpu_to_le64(monc->cur_mon); - ceph_con_open(monc->con, + monc->con.peer_name.type = CEPH_ENTITY_TYPE_MON; + monc->con.peer_name.num = cpu_to_le64(monc->cur_mon); + ceph_con_open(&monc->con, &monc->monmap->mon_inst[monc->cur_mon].addr); /* initiatiate authentication handshake */ @@ -226,8 +226,8 @@ static void __send_subscribe(struct ceph_mon_client *monc) msg->front.iov_len = p - msg->front.iov_base; msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); - ceph_con_revoke(monc->con, msg); - ceph_con_send(monc->con, ceph_msg_get(msg)); + ceph_con_revoke(&monc->con, msg); + ceph_con_send(&monc->con, ceph_msg_get(msg)); monc->sub_sent = jiffies | 1; /* never 0 */ } @@ -247,7 +247,7 @@ static void handle_subscribe_ack(struct ceph_mon_client *monc, if (monc->hunting) { pr_info("mon%d %s session established\n", monc->cur_mon, - ceph_pr_addr(&monc->con->peer_addr.in_addr)); + ceph_pr_addr(&monc->con.peer_addr.in_addr)); monc->hunting = false; } dout("handle_subscribe_ack after %d seconds\n", seconds); @@ -461,7 +461,7 @@ static int do_generic_request(struct ceph_mon_client *monc, req->request->hdr.tid = cpu_to_le64(req->tid); __insert_generic_request(monc, req); monc->num_generic_requests++; - ceph_con_send(monc->con, ceph_msg_get(req->request)); + ceph_con_send(&monc->con, ceph_msg_get(req->request)); mutex_unlock(&monc->mutex); err = wait_for_completion_interruptible(&req->completion); @@ -684,8 +684,8 @@ static void __resend_generic_request(struct ceph_mon_client *monc) for (p = rb_first(&monc->generic_request_tree); p; p = rb_next(p)) { req = rb_entry(p, struct ceph_mon_generic_request, node); - ceph_con_revoke(monc->con, req->request); - ceph_con_send(monc->con, ceph_msg_get(req->request)); + ceph_con_revoke(&monc->con, req->request); + ceph_con_send(&monc->con, ceph_msg_get(req->request)); } } @@ -705,7 +705,7 @@ static void delayed_work(struct work_struct *work) __close_session(monc); __open_session(monc); /* continue hunting */ } else { - ceph_con_keepalive(monc->con); + ceph_con_keepalive(&monc->con); __validate_auth(monc); @@ -760,19 +760,16 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl) goto out; /* connection */ - monc->con = kmalloc(sizeof(*monc->con), GFP_KERNEL); - if (!monc->con) - goto out_monmap; - ceph_con_init(&monc->client->msgr, monc->con); - monc->con->private = monc; - monc->con->ops = &mon_con_ops; + ceph_con_init(&monc->client->msgr, &monc->con); + monc->con.private = monc; + monc->con.ops = &mon_con_ops; /* authentication */ monc->auth = ceph_auth_init(cl->options->name, cl->options->key); if (IS_ERR(monc->auth)) { err = PTR_ERR(monc->auth); - goto out_con; + goto out_monmap; } monc->auth->want_keys = CEPH_ENTITY_TYPE_AUTH | CEPH_ENTITY_TYPE_MON | @@ -824,8 +821,6 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl) ceph_msg_put(monc->m_subscribe_ack); out_auth: ceph_auth_destroy(monc->auth); -out_con: - monc->con->ops->put(monc->con); out_monmap: kfree(monc->monmap); out: @@ -841,9 +836,7 @@ void ceph_monc_stop(struct ceph_mon_client *monc) mutex_lock(&monc->mutex); __close_session(monc); - monc->con->private = NULL; - monc->con->ops->put(monc->con); - monc->con = NULL; + monc->con.private = NULL; mutex_unlock(&monc->mutex); @@ -1029,7 +1022,7 @@ static void mon_fault(struct ceph_connection *con) if (!monc->hunting) pr_info("mon%d %s session lost, " "hunting for new mon\n", monc->cur_mon, - ceph_pr_addr(&monc->con->peer_addr.in_addr)); + ceph_pr_addr(&monc->con.peer_addr.in_addr)); __close_session(monc); if (!monc->hunting) { From a2b87615e2acfb851ec43603d0061f631381301a Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 31 May 2012 20:27:50 -0700 Subject: [PATCH 1547/2357] libceph: drop connection refcounting for mon_client (cherry picked from commit ec87ef4309d33bd9c87a53bb5152a86ae7a65f25) All references to the embedded ceph_connection come from the msgr workqueue, which is drained prior to mon_client destruction. That means we can ignore con refcounting entirely. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/mon_client.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 5cdd8f6d38d..bbb2c660fd6 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -1037,9 +1037,23 @@ static void mon_fault(struct ceph_connection *con) mutex_unlock(&monc->mutex); } +/* + * We can ignore refcounting on the connection struct, as all references + * will come from the messenger workqueue, which is drained prior to + * mon_client destruction. + */ +static struct ceph_connection *con_get(struct ceph_connection *con) +{ + return con; +} + +static void con_put(struct ceph_connection *con) +{ +} + static const struct ceph_connection_operations mon_con_ops = { - .get = ceph_con_get, - .put = ceph_con_put, + .get = con_get, + .put = con_put, .dispatch = dispatch, .fault = mon_fault, .alloc_msg = mon_alloc_msg, From 9403ae33bf946342b23cfe3dbf3e4c9b86860c97 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 26 May 2012 23:26:43 -0500 Subject: [PATCH 1548/2357] libceph: init monitor connection when opening (cherry picked from commit 20581c1faf7b15ae1f8b80c0ec757877b0b53151) Hold off initializing a monitor client's connection until just before it gets opened for use. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/mon_client.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index bbb2c660fd6..1b03493f874 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -119,6 +119,7 @@ static void __close_session(struct ceph_mon_client *monc) dout("__close_session closing mon%d\n", monc->cur_mon); ceph_con_revoke(&monc->con, monc->m_auth); ceph_con_close(&monc->con); + monc->con.private = NULL; monc->cur_mon = -1; monc->pending_auth = 0; ceph_auth_reset(monc->auth); @@ -141,9 +142,13 @@ static int __open_session(struct ceph_mon_client *monc) monc->sub_renew_after = jiffies; /* i.e., expired */ monc->want_next_osdmap = !!monc->want_next_osdmap; - dout("open_session mon%d opening\n", monc->cur_mon); + ceph_con_init(&monc->client->msgr, &monc->con); + monc->con.private = monc; + monc->con.ops = &mon_con_ops; monc->con.peer_name.type = CEPH_ENTITY_TYPE_MON; monc->con.peer_name.num = cpu_to_le64(monc->cur_mon); + + dout("open_session mon%d opening\n", monc->cur_mon); ceph_con_open(&monc->con, &monc->monmap->mon_inst[monc->cur_mon].addr); @@ -760,10 +765,6 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl) goto out; /* connection */ - ceph_con_init(&monc->client->msgr, &monc->con); - monc->con.private = monc; - monc->con.ops = &mon_con_ops; - /* authentication */ monc->auth = ceph_auth_init(cl->options->name, cl->options->key); @@ -836,8 +837,6 @@ void ceph_monc_stop(struct ceph_mon_client *monc) mutex_lock(&monc->mutex); __close_session(monc); - monc->con.private = NULL; - mutex_unlock(&monc->mutex); /* From 6880138c03448b3c375a3d7a8ef6acd688e6fb40 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 26 May 2012 23:26:43 -0500 Subject: [PATCH 1549/2357] libceph: fully initialize connection in con_init() (cherry picked from commit 1bfd89f4e6e1adc6a782d94aa5d4c53be1e404d7) Move the initialization of a ceph connection's private pointer, operations vector pointer, and peer name information into ceph_con_init(). Rearrange the arguments so the connection pointer is first. Hide the byte-swapping of the peer entity number inside ceph_con_init() Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 7 ++----- include/linux/ceph/messenger.h | 6 ++++-- net/ceph/messenger.c | 9 ++++++++- net/ceph/mon_client.c | 8 +++----- net/ceph/osd_client.c | 7 ++----- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index ad30261cd4c..ecd7f15741c 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -394,11 +394,8 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, s->s_seq = 0; mutex_init(&s->s_mutex); - ceph_con_init(&mdsc->fsc->client->msgr, &s->s_con); - s->s_con.private = s; - s->s_con.ops = &mds_con_ops; - s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS; - s->s_con.peer_name.num = cpu_to_le64(mds); + ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr, + CEPH_ENTITY_TYPE_MDS, mds); spin_lock_init(&s->s_gen_ttl_lock); s->s_cap_gen = 0; diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 5f30c81d474..7ed7a87aa6b 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -219,8 +219,10 @@ extern void ceph_messenger_init(struct ceph_messenger *msgr, u32 required_features, bool nocrc); -extern void ceph_con_init(struct ceph_messenger *msgr, - struct ceph_connection *con); +extern void ceph_con_init(struct ceph_connection *con, void *private, + const struct ceph_connection_operations *ops, + struct ceph_messenger *msgr, __u8 entity_type, + __u64 entity_num); extern void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr); extern bool ceph_con_opened(struct ceph_connection *con); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index ca0e4c126f4..6e21e609d79 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -521,15 +521,22 @@ void ceph_con_put(struct ceph_connection *con) /* * initialize a new connection. */ -void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con) +void ceph_con_init(struct ceph_connection *con, void *private, + const struct ceph_connection_operations *ops, + struct ceph_messenger *msgr, __u8 entity_type, __u64 entity_num) { dout("con_init %p\n", con); memset(con, 0, sizeof(*con)); + con->private = private; + con->ops = ops; atomic_set(&con->nref, 1); con->msgr = msgr; con_sock_state_init(con); + con->peer_name.type = (__u8) entity_type; + con->peer_name.num = cpu_to_le64(entity_num); + mutex_init(&con->mutex); INIT_LIST_HEAD(&con->out_queue); INIT_LIST_HEAD(&con->out_sent); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 1b03493f874..d3c22b7218c 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -142,11 +142,9 @@ static int __open_session(struct ceph_mon_client *monc) monc->sub_renew_after = jiffies; /* i.e., expired */ monc->want_next_osdmap = !!monc->want_next_osdmap; - ceph_con_init(&monc->client->msgr, &monc->con); - monc->con.private = monc; - monc->con.ops = &mon_con_ops; - monc->con.peer_name.type = CEPH_ENTITY_TYPE_MON; - monc->con.peer_name.num = cpu_to_le64(monc->cur_mon); + ceph_con_init(&monc->con, monc, &mon_con_ops, + &monc->client->msgr, + CEPH_ENTITY_TYPE_MON, monc->cur_mon); dout("open_session mon%d opening\n", monc->cur_mon); ceph_con_open(&monc->con, diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 5b41a6929cd..448c9da8bef 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -640,11 +640,8 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum) INIT_LIST_HEAD(&osd->o_osd_lru); osd->o_incarnation = 1; - ceph_con_init(&osdc->client->msgr, &osd->o_con); - osd->o_con.private = osd; - osd->o_con.ops = &osd_con_ops; - osd->o_con.peer_name.type = CEPH_ENTITY_TYPE_OSD; - osd->o_con.peer_name.num = cpu_to_le64(onum); + ceph_con_init(&osd->o_con, osd, &osd_con_ops, &osdc->client->msgr, + CEPH_ENTITY_TYPE_OSD, onum); INIT_LIST_HEAD(&osd->o_keepalive_item); return osd; From 35067a20685e5f51513c3633256e658fc71e847e Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 4 Jun 2012 14:43:32 -0500 Subject: [PATCH 1550/2357] libceph: tweak ceph_alloc_msg() (cherry picked from commit 1c20f2d26795803fc4f5155fe4fca5717a5944b6) The function ceph_alloc_msg() is only used to allocate a message that will be assigned to a connection's in_msg pointer. Rename the function so this implied usage is more clear. In addition, make that assignment inside the function (again, since that's precisely what it's intended to be used for). This allows us to return what is now provided via the passed-in address of a "skip" variable. The return type is now Boolean to be explicit that there are only two possible outcomes. Make sure the result of an ->alloc_msg method call always sets the value of *skip properly. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 61 ++++++++++++++++++++++++------------------- net/ceph/mon_client.c | 3 +++ net/ceph/osd_client.c | 1 + 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 6e21e609d79..31e8a15fa28 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1659,9 +1659,8 @@ static int read_partial_message_section(struct ceph_connection *con, return 1; } -static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con, - struct ceph_msg_header *hdr, - int *skip); +static bool ceph_con_in_msg_alloc(struct ceph_connection *con, + struct ceph_msg_header *hdr); static int read_partial_message_pages(struct ceph_connection *con, @@ -1744,7 +1743,6 @@ static int read_partial_message(struct ceph_connection *con) int ret; unsigned front_len, middle_len, data_len; bool do_datacrc = !con->msgr->nocrc; - int skip; u64 seq; u32 crc; @@ -1797,9 +1795,7 @@ static int read_partial_message(struct ceph_connection *con) if (!con->in_msg) { dout("got hdr type %d front %d data %d\n", con->in_hdr.type, con->in_hdr.front_len, con->in_hdr.data_len); - skip = 0; - con->in_msg = ceph_alloc_msg(con, &con->in_hdr, &skip); - if (skip) { + if (ceph_con_in_msg_alloc(con, &con->in_hdr)) { /* skip this message */ dout("alloc_msg said skip message\n"); BUG_ON(con->in_msg); @@ -2581,46 +2577,57 @@ static int ceph_alloc_middle(struct ceph_connection *con, struct ceph_msg *msg) } /* - * Generic message allocator, for incoming messages. + * Allocate a message for receiving an incoming message on a + * connection, and save the result in con->in_msg. Uses the + * connection's private alloc_msg op if available. + * + * Returns true if the message should be skipped, false otherwise. + * If true is returned (skip message), con->in_msg will be NULL. + * If false is returned, con->in_msg will contain a pointer to the + * newly-allocated message, or NULL in case of memory exhaustion. */ -static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con, - struct ceph_msg_header *hdr, - int *skip) +static bool ceph_con_in_msg_alloc(struct ceph_connection *con, + struct ceph_msg_header *hdr) { int type = le16_to_cpu(hdr->type); int front_len = le32_to_cpu(hdr->front_len); int middle_len = le32_to_cpu(hdr->middle_len); - struct ceph_msg *msg = NULL; int ret; + BUG_ON(con->in_msg != NULL); + if (con->ops->alloc_msg) { + int skip = 0; + mutex_unlock(&con->mutex); - msg = con->ops->alloc_msg(con, hdr, skip); + con->in_msg = con->ops->alloc_msg(con, hdr, &skip); mutex_lock(&con->mutex); - if (!msg || *skip) - return NULL; + if (skip) + con->in_msg = NULL; + + if (!con->in_msg) + return skip != 0; } - if (!msg) { - *skip = 0; - msg = ceph_msg_new(type, front_len, GFP_NOFS, false); - if (!msg) { + if (!con->in_msg) { + con->in_msg = ceph_msg_new(type, front_len, GFP_NOFS, false); + if (!con->in_msg) { pr_err("unable to allocate msg type %d len %d\n", type, front_len); - return NULL; + return false; } - msg->page_alignment = le16_to_cpu(hdr->data_off); + con->in_msg->page_alignment = le16_to_cpu(hdr->data_off); } - memcpy(&msg->hdr, &con->in_hdr, sizeof(con->in_hdr)); + memcpy(&con->in_msg->hdr, &con->in_hdr, sizeof(con->in_hdr)); - if (middle_len && !msg->middle) { - ret = ceph_alloc_middle(con, msg); + if (middle_len && !con->in_msg->middle) { + ret = ceph_alloc_middle(con, con->in_msg); if (ret < 0) { - ceph_msg_put(msg); - return NULL; + ceph_msg_put(con->in_msg); + con->in_msg = NULL; } } - return msg; + return false; } diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index d3c22b7218c..674f191341a 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -442,6 +442,7 @@ static struct ceph_msg *get_generic_reply(struct ceph_connection *con, m = NULL; } else { dout("get_generic_reply %lld got %p\n", tid, req->reply); + *skip = 0; m = ceph_msg_get(req->reply); /* * we don't need to track the connection reading into @@ -990,6 +991,8 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con, case CEPH_MSG_MDS_MAP: case CEPH_MSG_OSD_MAP: m = ceph_msg_new(type, front_len, GFP_NOFS, false); + if (!m) + return NULL; /* ENOMEM--return skip == 0 */ break; } diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 448c9da8bef..24b427b1eca 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -2077,6 +2077,7 @@ static struct ceph_msg *alloc_msg(struct ceph_connection *con, int type = le16_to_cpu(hdr->type); int front = le32_to_cpu(hdr->front_len); + *skip = 0; switch (type) { case CEPH_MSG_OSD_MAP: case CEPH_MSG_WATCH_NOTIFY: From e84e066e5c8c858d3954b2ef1da25c14309e4cef Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Jun 2012 14:56:43 -0500 Subject: [PATCH 1551/2357] libceph: have messages point to their connection (cherry picked from commit 38941f8031bf042dba3ced6394ba3a3b16c244ea) When a ceph message is queued for sending it is placed on a list of pending messages (ceph_connection->out_queue). When they are actually sent over the wire, they are moved from that list to another (ceph_connection->out_sent). When acknowledgement for the message is received, it is removed from the sent messages list. During that entire time the message is "in the possession" of a single ceph connection. Keep track of that connection in the message. This will be used in the next patch (and is a helpful bit of information for debugging anyway). Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 3 +++ net/ceph/messenger.c | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 7ed7a87aa6b..7d48ffc02c7 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -77,7 +77,10 @@ struct ceph_msg { unsigned nr_pages; /* size of page array */ unsigned page_alignment; /* io offset in first page */ struct ceph_pagelist *pagelist; /* instead of pages */ + + struct ceph_connection *con; struct list_head list_head; + struct kref kref; struct bio *bio; /* instead of pages/pagelist */ struct bio *bio_iter; /* bio iterator */ diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 31e8a15fa28..51cf7318026 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -414,6 +414,9 @@ static int con_close_socket(struct ceph_connection *con) static void ceph_msg_remove(struct ceph_msg *msg) { list_del_init(&msg->list_head); + BUG_ON(msg->con == NULL); + msg->con = NULL; + ceph_msg_put(msg); } static void ceph_msg_remove_list(struct list_head *head) @@ -433,6 +436,8 @@ static void reset_connection(struct ceph_connection *con) ceph_msg_remove_list(&con->out_sent); if (con->in_msg) { + BUG_ON(con->in_msg->con != con); + con->in_msg->con = NULL; ceph_msg_put(con->in_msg); con->in_msg = NULL; } @@ -625,8 +630,10 @@ static void prepare_write_message(struct ceph_connection *con) &con->out_temp_ack); } + BUG_ON(list_empty(&con->out_queue)); m = list_first_entry(&con->out_queue, struct ceph_msg, list_head); con->out_msg = m; + BUG_ON(m->con != con); /* put message on sent list */ ceph_msg_get(m); @@ -1810,6 +1817,8 @@ static int read_partial_message(struct ceph_connection *con) "error allocating memory for incoming message"; return -ENOMEM; } + + BUG_ON(con->in_msg->con != con); m = con->in_msg; m->front.iov_len = 0; /* haven't read it yet */ if (m->middle) @@ -1905,6 +1914,8 @@ static void process_message(struct ceph_connection *con) { struct ceph_msg *msg; + BUG_ON(con->in_msg->con != con); + con->in_msg->con = NULL; msg = con->in_msg; con->in_msg = NULL; @@ -2264,6 +2275,8 @@ static void ceph_fault(struct ceph_connection *con) con_close_socket(con); if (con->in_msg) { + BUG_ON(con->in_msg->con != con); + con->in_msg->con = NULL; ceph_msg_put(con->in_msg); con->in_msg = NULL; } @@ -2382,6 +2395,8 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg) /* queue */ mutex_lock(&con->mutex); + BUG_ON(msg->con != NULL); + msg->con = con; BUG_ON(!list_empty(&msg->list_head)); list_add_tail(&msg->list_head, &con->out_queue); dout("----- %p to %s%lld %d=%s len %d+%d+%d -----\n", msg, @@ -2407,13 +2422,16 @@ void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg) { mutex_lock(&con->mutex); if (!list_empty(&msg->list_head)) { - dout("con_revoke %p msg %p - was on queue\n", con, msg); + dout("%s %p msg %p - was on queue\n", __func__, con, msg); list_del_init(&msg->list_head); + BUG_ON(msg->con == NULL); + msg->con = NULL; + ceph_msg_put(msg); msg->hdr.seq = 0; } if (con->out_msg == msg) { - dout("con_revoke %p msg %p - was sending\n", con, msg); + dout("%s %p msg %p - was sending\n", __func__, con, msg); con->out_msg = NULL; if (con->out_kvec_is_msg) { con->out_skip = con->out_kvec_bytes; @@ -2482,6 +2500,8 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags, if (m == NULL) goto out; kref_init(&m->kref); + + m->con = NULL; INIT_LIST_HEAD(&m->list_head); m->hdr.tid = 0; @@ -2602,6 +2622,8 @@ static bool ceph_con_in_msg_alloc(struct ceph_connection *con, mutex_unlock(&con->mutex); con->in_msg = con->ops->alloc_msg(con, hdr, &skip); mutex_lock(&con->mutex); + if (con->in_msg) + con->in_msg->con = con; if (skip) con->in_msg = NULL; @@ -2615,6 +2637,7 @@ static bool ceph_con_in_msg_alloc(struct ceph_connection *con, type, front_len); return false; } + con->in_msg->con = con; con->in_msg->page_alignment = le16_to_cpu(hdr->data_off); } memcpy(&con->in_msg->hdr, &con->in_hdr, sizeof(con->in_hdr)); From bfd357201d3ffc6cc621e4c69fd47e7d457e5f3a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 4 Jun 2012 14:43:33 -0500 Subject: [PATCH 1552/2357] libceph: have messages take a connection reference (cherry picked from commit 92ce034b5a740046cc643a21ea21eaad589e0043) There are essentially two types of ceph messages: incoming and outgoing. Outgoing messages are always allocated via ceph_msg_new(), and at the time of their allocation they are not associated with any particular connection. Incoming messages are always allocated via ceph_con_in_msg_alloc(), and they are initially associated with the connection from which incoming data will be placed into the message. When an outgoing message gets sent, it becomes associated with a connection and remains that way until the message is successfully sent. The association of an incoming message goes away at the point it is sent to an upper layer via a con->ops->dispatch method. This patch implements reference counting for all ceph messages, such that every message holds a reference (and a pointer) to a connection if and only if it is associated with that connection (as described above). For background, here is an explanation of the ceph message lifecycle, emphasizing when an association exists between a message and a connection. Outgoing Messages An outgoing message is "owned" by its allocator, from the time it is allocated in ceph_msg_new() up to the point it gets queued for sending in ceph_con_send(). Prior to that point the message's msg->con pointer is null; at the point it is queued for sending its message pointer is assigned to refer to the connection. At that time the message is inserted into a connection's out_queue list. When a message on the out_queue list has been sent to the socket layer to be put on the wire, it is transferred out of that list and into the connection's out_sent list. At that point it is still owned by the connection, and will remain so until an acknowledgement is received from the recipient that indicates the message was successfully transferred. When such an acknowledgement is received (in process_ack()), the message is removed from its list (in ceph_msg_remove()), at which point it is no longer associated with the connection. So basically, any time a message is on one of a connection's lists, it is associated with that connection. Reference counting outgoing messages can thus be done at the points a message is added to the out_queue (in ceph_con_send()) and the point it is removed from either its two lists (in ceph_msg_remove())--at which point its connection pointer becomes null. Incoming Messages When an incoming message on a connection is getting read (in read_partial_message()) and there is no message in con->in_msg, a new one is allocated using ceph_con_in_msg_alloc(). At that point the message is associated with the connection. Once that message has been completely and successfully read, it is passed to upper layer code using the connection's con->ops->dispatch method. At that point the association between the message and the connection no longer exists. Reference counting of connections for incoming messages can be done by taking a reference to the connection when the message gets allocated, and releasing that reference when it gets handed off using the dispatch method. We should never fail to get a connection reference for a message--the since the caller should already hold one. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 51cf7318026..9e7da4b8579 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -415,6 +415,7 @@ static void ceph_msg_remove(struct ceph_msg *msg) { list_del_init(&msg->list_head); BUG_ON(msg->con == NULL); + ceph_con_put(msg->con); msg->con = NULL; ceph_msg_put(msg); @@ -440,6 +441,7 @@ static void reset_connection(struct ceph_connection *con) con->in_msg->con = NULL; ceph_msg_put(con->in_msg); con->in_msg = NULL; + ceph_con_put(con->in_msg->con); } con->connect_seq = 0; @@ -1918,6 +1920,7 @@ static void process_message(struct ceph_connection *con) con->in_msg->con = NULL; msg = con->in_msg; con->in_msg = NULL; + ceph_con_put(con); /* if first message, set peer_name */ if (con->peer_name.type == 0) @@ -2279,6 +2282,7 @@ static void ceph_fault(struct ceph_connection *con) con->in_msg->con = NULL; ceph_msg_put(con->in_msg); con->in_msg = NULL; + ceph_con_put(con); } /* Requeue anything that hasn't been acked */ @@ -2395,8 +2399,11 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg) /* queue */ mutex_lock(&con->mutex); + BUG_ON(msg->con != NULL); - msg->con = con; + msg->con = ceph_con_get(con); + BUG_ON(msg->con == NULL); + BUG_ON(!list_empty(&msg->list_head)); list_add_tail(&msg->list_head, &con->out_queue); dout("----- %p to %s%lld %d=%s len %d+%d+%d -----\n", msg, @@ -2425,10 +2432,11 @@ void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg) dout("%s %p msg %p - was on queue\n", __func__, con, msg); list_del_init(&msg->list_head); BUG_ON(msg->con == NULL); + ceph_con_put(msg->con); msg->con = NULL; + msg->hdr.seq = 0; ceph_msg_put(msg); - msg->hdr.seq = 0; } if (con->out_msg == msg) { dout("%s %p msg %p - was sending\n", __func__, con, msg); @@ -2437,8 +2445,9 @@ void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg) con->out_skip = con->out_kvec_bytes; con->out_kvec_is_msg = false; } - ceph_msg_put(msg); msg->hdr.seq = 0; + + ceph_msg_put(msg); } mutex_unlock(&con->mutex); } @@ -2622,8 +2631,10 @@ static bool ceph_con_in_msg_alloc(struct ceph_connection *con, mutex_unlock(&con->mutex); con->in_msg = con->ops->alloc_msg(con, hdr, &skip); mutex_lock(&con->mutex); - if (con->in_msg) - con->in_msg->con = con; + if (con->in_msg) { + con->in_msg->con = ceph_con_get(con); + BUG_ON(con->in_msg->con == NULL); + } if (skip) con->in_msg = NULL; @@ -2637,7 +2648,8 @@ static bool ceph_con_in_msg_alloc(struct ceph_connection *con, type, front_len); return false; } - con->in_msg->con = con; + con->in_msg->con = ceph_con_get(con); + BUG_ON(con->in_msg->con == NULL); con->in_msg->page_alignment = le16_to_cpu(hdr->data_off); } memcpy(&con->in_msg->hdr, &con->in_hdr, sizeof(con->in_hdr)); From ae048538ab62c31f67d42e00a3183b8870809a3c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Jun 2012 14:56:43 -0500 Subject: [PATCH 1553/2357] libceph: make ceph_con_revoke() a msg operation (cherry picked from commit 6740a845b2543cc46e1902ba21bac743fbadd0dc) ceph_con_revoke() is passed both a message and a ceph connection. Now that any message associated with a connection holds a pointer to that connection, there's no need to provide the connection when revoking a message. This has the added benefit of precluding the possibility of the providing the wrong connection pointer. If the message's connection pointer is null, it is not being tracked by any connection, so revoking it is a no-op. This is supported as a convenience for upper layers, so they can revoke a message that is not actually "in flight." Rename the function ceph_msg_revoke() to reflect that it is really an operation on a message, not a connection. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 3 ++- net/ceph/messenger.c | 7 ++++++- net/ceph/mon_client.c | 8 ++++---- net/ceph/osd_client.c | 4 ++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 7d48ffc02c7..13bd9cdbeb0 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -231,7 +231,8 @@ extern void ceph_con_open(struct ceph_connection *con, extern bool ceph_con_opened(struct ceph_connection *con); extern void ceph_con_close(struct ceph_connection *con); extern void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg); -extern void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg); + +extern void ceph_msg_revoke(struct ceph_msg *msg); extern void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg); extern void ceph_con_keepalive(struct ceph_connection *con); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 9e7da4b8579..96d3eaec7d3 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2425,8 +2425,13 @@ EXPORT_SYMBOL(ceph_con_send); /* * Revoke a message that was previously queued for send */ -void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg) +void ceph_msg_revoke(struct ceph_msg *msg) { + struct ceph_connection *con = msg->con; + + if (!con) + return; /* Message not in our possession */ + mutex_lock(&con->mutex); if (!list_empty(&msg->list_head)) { dout("%s %p msg %p - was on queue\n", __func__, con, msg); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 674f191341a..dc16595d688 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -106,7 +106,7 @@ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len) monc->pending_auth = 1; monc->m_auth->front.iov_len = len; monc->m_auth->hdr.front_len = cpu_to_le32(len); - ceph_con_revoke(&monc->con, monc->m_auth); + ceph_msg_revoke(monc->m_auth); ceph_msg_get(monc->m_auth); /* keep our ref */ ceph_con_send(&monc->con, monc->m_auth); } @@ -117,7 +117,7 @@ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len) static void __close_session(struct ceph_mon_client *monc) { dout("__close_session closing mon%d\n", monc->cur_mon); - ceph_con_revoke(&monc->con, monc->m_auth); + ceph_msg_revoke(monc->m_auth); ceph_con_close(&monc->con); monc->con.private = NULL; monc->cur_mon = -1; @@ -229,7 +229,7 @@ static void __send_subscribe(struct ceph_mon_client *monc) msg->front.iov_len = p - msg->front.iov_base; msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); - ceph_con_revoke(&monc->con, msg); + ceph_msg_revoke(msg); ceph_con_send(&monc->con, ceph_msg_get(msg)); monc->sub_sent = jiffies | 1; /* never 0 */ @@ -688,7 +688,7 @@ static void __resend_generic_request(struct ceph_mon_client *monc) for (p = rb_first(&monc->generic_request_tree); p; p = rb_next(p)) { req = rb_entry(p, struct ceph_mon_generic_request, node); - ceph_con_revoke(&monc->con, req->request); + ceph_msg_revoke(req->request); ceph_con_send(&monc->con, ceph_msg_get(req->request)); } } diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 24b427b1eca..ad78705a4af 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -852,7 +852,7 @@ static void __unregister_request(struct ceph_osd_client *osdc, if (req->r_osd) { /* make sure the original request isn't in flight. */ - ceph_con_revoke(&req->r_osd->o_con, req->r_request); + ceph_msg_revoke(req->r_request); list_del_init(&req->r_osd_item); if (list_empty(&req->r_osd->o_requests) && @@ -879,7 +879,7 @@ static void __unregister_request(struct ceph_osd_client *osdc, static void __cancel_request(struct ceph_osd_request *req) { if (req->r_sent && req->r_osd) { - ceph_con_revoke(&req->r_osd->o_con, req->r_request); + ceph_msg_revoke(req->r_request); req->r_sent = 0; } } From ce4516fbb42d2ad5adba4699ebc1703d4e08e821 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Jun 2012 14:56:43 -0500 Subject: [PATCH 1554/2357] libceph: make ceph_con_revoke_message() a msg op (cherry picked from commit 8921d114f5574c6da2cdd00749d185633ecf88f3) ceph_con_revoke_message() is passed both a message and a ceph connection. A ceph_msg allocated for incoming messages on a connection always has a pointer to that connection, so there's no need to provide the connection when revoking such a message. Note that the existing logic does not preclude the message supplied being a null/bogus message pointer. The only user of this interface is the OSD client, and the only value an osd client passes is a request's r_reply field. That is always non-null (except briefly in an error path in ceph_osdc_alloc_request(), and that drops the only reference so the request won't ever have a reply to revoke). So we can safely assume the passed-in message is non-null, but add a BUG_ON() to make it very obvious we are imposing this restriction. Rename the function ceph_msg_revoke_incoming() to reflect that it is really an operation on an incoming message. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 4 ++-- net/ceph/messenger.c | 22 ++++++++++++++++------ net/ceph/osd_client.c | 9 ++++----- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 13bd9cdbeb0..9c1f755e5c0 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -233,8 +233,8 @@ extern void ceph_con_close(struct ceph_connection *con); extern void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg); extern void ceph_msg_revoke(struct ceph_msg *msg); -extern void ceph_con_revoke_message(struct ceph_connection *con, - struct ceph_msg *msg); +extern void ceph_msg_revoke_incoming(struct ceph_msg *msg); + extern void ceph_con_keepalive(struct ceph_connection *con); extern struct ceph_connection *ceph_con_get(struct ceph_connection *con); extern void ceph_con_put(struct ceph_connection *con); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 96d3eaec7d3..5ae586813f3 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2460,17 +2460,27 @@ void ceph_msg_revoke(struct ceph_msg *msg) /* * Revoke a message that we may be reading data into */ -void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg) +void ceph_msg_revoke_incoming(struct ceph_msg *msg) { + struct ceph_connection *con; + + BUG_ON(msg == NULL); + if (!msg->con) { + dout("%s msg %p null con\n", __func__, msg); + + return; /* Message not in our possession */ + } + + con = msg->con; mutex_lock(&con->mutex); - if (con->in_msg && con->in_msg == msg) { + if (con->in_msg == msg) { unsigned front_len = le32_to_cpu(con->in_hdr.front_len); unsigned middle_len = le32_to_cpu(con->in_hdr.middle_len); unsigned data_len = le32_to_cpu(con->in_hdr.data_len); /* skip rest of message */ - dout("con_revoke_pages %p msg %p revoked\n", con, msg); - con->in_base_pos = con->in_base_pos - + dout("%s %p msg %p revoked\n", __func__, con, msg); + con->in_base_pos = con->in_base_pos - sizeof(struct ceph_msg_header) - front_len - middle_len - @@ -2481,8 +2491,8 @@ void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg) con->in_tag = CEPH_MSGR_TAG_READY; con->in_seq++; } else { - dout("con_revoke_pages %p msg %p pages %p no-op\n", - con, con->in_msg, msg); + dout("%s %p in_msg %p msg %p no-op\n", + __func__, con, con->in_msg, msg); } mutex_unlock(&con->mutex); } diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index ad78705a4af..c178c770acb 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -140,10 +140,9 @@ void ceph_osdc_release_request(struct kref *kref) if (req->r_request) ceph_msg_put(req->r_request); if (req->r_con_filling_msg) { - dout("release_request revoking pages %p from con %p\n", + dout("%s revoking pages %p from con %p\n", __func__, req->r_pages, req->r_con_filling_msg); - ceph_con_revoke_message(req->r_con_filling_msg, - req->r_reply); + ceph_msg_revoke_incoming(req->r_reply); req->r_con_filling_msg->ops->put(req->r_con_filling_msg); } if (req->r_reply) @@ -2022,9 +2021,9 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, } if (req->r_con_filling_msg) { - dout("get_reply revoking msg %p from old con %p\n", + dout("%s revoking msg %p from old con %p\n", __func__, req->r_reply, req->r_con_filling_msg); - ceph_con_revoke_message(req->r_con_filling_msg, req->r_reply); + ceph_msg_revoke_incoming(req->r_reply); req->r_con_filling_msg->ops->put(req->r_con_filling_msg); req->r_con_filling_msg = NULL; } From c66a9c7c10955499d96df63ffd87feaee6b01754 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Wed, 6 Jun 2012 19:35:55 -0500 Subject: [PATCH 1555/2357] libceph: fix overflow in __decode_pool_names() (cherry picked from commit ad3b904c07dfa88603689bf9a67bffbb9b99beb5) `len' is read from network and thus needs validation. Otherwise a large `len' would cause out-of-bounds access via the memcpy() call. In addition, len = 0xffffffff would overflow the kmalloc() size, leading to out-of-bounds write. This patch adds a check of `len' via ceph_decode_need(). Also use kstrndup rather than kmalloc/memcpy. [elder@inktank.com: added -ENOMEM return for null kstrndup() result] Signed-off-by: Xi Wang Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/osdmap.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 7173ad54d23..77abb131586 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -495,15 +495,16 @@ static int __decode_pool_names(void **p, void *end, struct ceph_osdmap *map) ceph_decode_32_safe(p, end, pool, bad); ceph_decode_32_safe(p, end, len, bad); dout(" pool %d len %d\n", pool, len); + ceph_decode_need(p, end, len, bad); pi = __lookup_pg_pool(&map->pg_pools, pool); if (pi) { + char *name = kstrndup(*p, len, GFP_NOFS); + + if (!name) + return -ENOMEM; kfree(pi->name); - pi->name = kmalloc(len + 1, GFP_NOFS); - if (pi->name) { - memcpy(pi->name, *p, len); - pi->name[len] = '\0'; - dout(" name is %s\n", pi->name); - } + pi->name = name; + dout(" name is %s\n", pi->name); } *p += len; } From 6b71f61c321b1fe8d35b75ab573ff46c51e59acc Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Wed, 6 Jun 2012 19:35:55 -0500 Subject: [PATCH 1556/2357] libceph: fix overflow in osdmap_decode() (cherry picked from commit e91a9b639a691e0982088b5954eaafb5a25c8f1c) On 32-bit systems, a large `n' would overflow `n * sizeof(u32)' and bypass the check ceph_decode_need(p, end, n * sizeof(u32), bad). It would also overflow the subsequent kmalloc() size, leading to out-of-bounds write. Signed-off-by: Xi Wang Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/osdmap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 77abb131586..a38ce3f5695 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -674,6 +674,9 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) ceph_decode_need(p, end, sizeof(u32) + sizeof(u64), bad); ceph_decode_copy(p, &pgid, sizeof(pgid)); n = ceph_decode_32(p); + err = -EINVAL; + if (n > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) + goto bad; ceph_decode_need(p, end, n * sizeof(u32), bad); err = -ENOMEM; pg = kmalloc(sizeof(*pg) + n*sizeof(u32), GFP_NOFS); From f4d29a959aa619f3d46e2b685cfb8acac41503db Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Wed, 6 Jun 2012 19:35:55 -0500 Subject: [PATCH 1557/2357] libceph: fix overflow in osdmap_apply_incremental() (cherry picked from commit a5506049500b30dbc5edb4d07a3577477c1f3643) On 32-bit systems, a large `pglen' would overflow `pglen*sizeof(u32)' and bypass the check ceph_decode_need(p, end, pglen*sizeof(u32), bad). It would also overflow the subsequent kmalloc() size, leading to out-of-bounds write. Signed-off-by: Xi Wang Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/osdmap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index a38ce3f5695..c77133405ff 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -900,6 +900,10 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, (void) __remove_pg_mapping(&map->pg_temp, pgid); /* insert */ + if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) { + err = -EINVAL; + goto bad; + } pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS); if (!pg) { err = -ENOMEM; From fccbf066b35a05606cdb96eb574eaf310c422125 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sat, 9 Jun 2012 14:19:21 -0700 Subject: [PATCH 1558/2357] libceph: transition socket state prior to actual connect (cherry picked from commit 89a86be0ce20022f6ede8bccec078dbb3d63caaa) Once we call ->connect(), we are racing against the actual connection, and a subsequent transition from CONNECTING -> CONNECTED. Set the state to CONNECTING before that, under the protection of the mutex, to avoid the race. This was introduced in 928443cd9644e7cfd46f687dbeffda2d1a357ff9, with the original socket state code. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 5ae586813f3..59e418b3597 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -321,6 +321,7 @@ static int ceph_tcp_connect(struct ceph_connection *con) dout("connect %s\n", ceph_pr_addr(&con->peer_addr.in_addr)); + con_sock_state_connecting(con); ret = sock->ops->connect(sock, (struct sockaddr *)paddr, sizeof(*paddr), O_NONBLOCK); if (ret == -EINPROGRESS) { @@ -336,8 +337,6 @@ static int ceph_tcp_connect(struct ceph_connection *con) return ret; } con->sock = sock; - con_sock_state_connecting(con); - return 0; } From 8124d55a2d2c8d738c6ac5b95e6171fe3d1b5af3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Jun 2012 08:52:33 -0500 Subject: [PATCH 1559/2357] libceph: fix NULL dereference in reset_connection() (cherry picked from commit 26ce171915f348abd1f41da1ed139d93750d987f) We dereference "con->in_msg" on the line after it was set to NULL. Signed-off-by: Dan Carpenter Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 59e418b3597..7e208969cc4 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -440,7 +440,7 @@ static void reset_connection(struct ceph_connection *con) con->in_msg->con = NULL; ceph_msg_put(con->in_msg); con->in_msg = NULL; - ceph_con_put(con->in_msg->con); + ceph_con_put(con); } con->connect_seq = 0; From 1c623b046a6c72666d81afa004f8bf7f70cd4391 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 21 Jun 2012 12:47:08 -0700 Subject: [PATCH 1560/2357] libceph: use con get/put methods (cherry picked from commit 36eb71aa57e6a33d61fd90a2fd87f00c6844bc86) The ceph_con_get/put() helpers manipulate the embedded con ref count, which isn't used now that ceph_connections are embedded in other structures. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 7e208969cc4..eddec08e787 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -414,7 +414,7 @@ static void ceph_msg_remove(struct ceph_msg *msg) { list_del_init(&msg->list_head); BUG_ON(msg->con == NULL); - ceph_con_put(msg->con); + msg->con->ops->put(msg->con); msg->con = NULL; ceph_msg_put(msg); @@ -440,7 +440,7 @@ static void reset_connection(struct ceph_connection *con) con->in_msg->con = NULL; ceph_msg_put(con->in_msg); con->in_msg = NULL; - ceph_con_put(con); + con->ops->put(con); } con->connect_seq = 0; @@ -1919,7 +1919,7 @@ static void process_message(struct ceph_connection *con) con->in_msg->con = NULL; msg = con->in_msg; con->in_msg = NULL; - ceph_con_put(con); + con->ops->put(con); /* if first message, set peer_name */ if (con->peer_name.type == 0) @@ -2281,7 +2281,7 @@ static void ceph_fault(struct ceph_connection *con) con->in_msg->con = NULL; ceph_msg_put(con->in_msg); con->in_msg = NULL; - ceph_con_put(con); + con->ops->put(con); } /* Requeue anything that hasn't been acked */ @@ -2400,7 +2400,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg) mutex_lock(&con->mutex); BUG_ON(msg->con != NULL); - msg->con = ceph_con_get(con); + msg->con = con->ops->get(con); BUG_ON(msg->con == NULL); BUG_ON(!list_empty(&msg->list_head)); @@ -2436,7 +2436,7 @@ void ceph_msg_revoke(struct ceph_msg *msg) dout("%s %p msg %p - was on queue\n", __func__, con, msg); list_del_init(&msg->list_head); BUG_ON(msg->con == NULL); - ceph_con_put(msg->con); + msg->con->ops->put(msg->con); msg->con = NULL; msg->hdr.seq = 0; @@ -2646,7 +2646,7 @@ static bool ceph_con_in_msg_alloc(struct ceph_connection *con, con->in_msg = con->ops->alloc_msg(con, hdr, &skip); mutex_lock(&con->mutex); if (con->in_msg) { - con->in_msg->con = ceph_con_get(con); + con->in_msg->con = con->ops->get(con); BUG_ON(con->in_msg->con == NULL); } if (skip) @@ -2662,7 +2662,7 @@ static bool ceph_con_in_msg_alloc(struct ceph_connection *con, type, front_len); return false; } - con->in_msg->con = ceph_con_get(con); + con->in_msg->con = con->ops->get(con); BUG_ON(con->in_msg->con == NULL); con->in_msg->page_alignment = le16_to_cpu(hdr->data_off); } From 9021a42c794bf96156be9ad556ef707814a361ff Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 21 Jun 2012 12:49:23 -0700 Subject: [PATCH 1561/2357] libceph: drop ceph_con_get/put helpers and nref member (cherry picked from commit d59315ca8c0de00df9b363f94a2641a30961ca1c) These are no longer used. Every ceph_connection instance is embedded in another structure, and refcounts manipulated via the get/put ops. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 1 - net/ceph/messenger.c | 28 +--------------------------- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 9c1f755e5c0..f624b752e82 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -135,7 +135,6 @@ struct ceph_msg_pos { */ struct ceph_connection { void *private; - atomic_t nref; const struct ceph_connection_operations *ops; diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index eddec08e787..bc43a042b3e 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -500,30 +500,6 @@ bool ceph_con_opened(struct ceph_connection *con) return con->connect_seq > 0; } -/* - * generic get/put - */ -struct ceph_connection *ceph_con_get(struct ceph_connection *con) -{ - int nref = __atomic_add_unless(&con->nref, 1, 0); - - dout("con_get %p nref = %d -> %d\n", con, nref, nref + 1); - - return nref ? con : NULL; -} - -void ceph_con_put(struct ceph_connection *con) -{ - int nref = atomic_dec_return(&con->nref); - - BUG_ON(nref < 0); - if (nref == 0) { - BUG_ON(con->sock); - kfree(con); - } - dout("con_put %p nref = %d -> %d\n", con, nref + 1, nref); -} - /* * initialize a new connection. */ @@ -535,7 +511,6 @@ void ceph_con_init(struct ceph_connection *con, void *private, memset(con, 0, sizeof(*con)); con->private = private; con->ops = ops; - atomic_set(&con->nref, 1); con->msgr = msgr; con_sock_state_init(con); @@ -1951,8 +1926,7 @@ static int try_write(struct ceph_connection *con) { int ret = 1; - dout("try_write start %p state %lu nref %d\n", con, con->state, - atomic_read(&con->nref)); + dout("try_write start %p state %lu\n", con, con->state); more: dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes); From 4ecff48cef44be80eccfa0b3864d55f446006dc5 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 11 Jun 2012 14:57:13 -0500 Subject: [PATCH 1562/2357] libceph: encapsulate out message data setup (cherry picked from commit 739c905baa018c99003564ebc367d93aa44d4861) Move the code that prepares to write the data portion of a message into its own function. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index bc43a042b3e..3c5e2061e19 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -565,6 +565,24 @@ static void con_out_kvec_add(struct ceph_connection *con, con->out_kvec_bytes += size; } +static void prepare_write_message_data(struct ceph_connection *con) +{ + struct ceph_msg *msg = con->out_msg; + + BUG_ON(!msg); + BUG_ON(!msg->hdr.data_len); + + /* initialize page iterator */ + con->out_msg_pos.page = 0; + if (msg->pages) + con->out_msg_pos.page_pos = msg->page_alignment; + else + con->out_msg_pos.page_pos = 0; + con->out_msg_pos.data_pos = 0; + con->out_msg_pos.did_page_crc = false; + con->out_more = 1; /* data + footer will follow */ +} + /* * Prepare footer for currently outgoing message, and finish things * off. Assumes out_kvec* are already valid.. we just add on to the end. @@ -657,26 +675,17 @@ static void prepare_write_message(struct ceph_connection *con) con->out_msg->footer.middle_crc = cpu_to_le32(crc); } else con->out_msg->footer.middle_crc = 0; - con->out_msg->footer.data_crc = 0; - dout("prepare_write_message front_crc %u data_crc %u\n", + dout("%s front_crc %u middle_crc %u\n", __func__, le32_to_cpu(con->out_msg->footer.front_crc), le32_to_cpu(con->out_msg->footer.middle_crc)); /* is there a data payload? */ - if (le32_to_cpu(m->hdr.data_len) > 0) { - /* initialize page iterator */ - con->out_msg_pos.page = 0; - if (m->pages) - con->out_msg_pos.page_pos = m->page_alignment; - else - con->out_msg_pos.page_pos = 0; - con->out_msg_pos.data_pos = 0; - con->out_msg_pos.did_page_crc = false; - con->out_more = 1; /* data + footer will follow */ - } else { + con->out_msg->footer.data_crc = 0; + if (m->hdr.data_len) + prepare_write_message_data(con); + else /* no, queue up footer too and be done */ prepare_write_message_footer(con); - } set_bit(WRITE_PENDING, &con->flags); } From 3c968ed12fad908a5d3676b8d3150b9ac167841c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 11 Jun 2012 14:57:13 -0500 Subject: [PATCH 1563/2357] libceph: encapsulate advancing msg page (cherry picked from commit 84ca8fc87fcf4ab97bb8acdb59bf97bb4820cb14) In write_partial_msg_pages(), once all the data from a page has been sent we advance to the next one. Put the code that takes care of this into its own function. While modifying write_partial_msg_pages(), make its local variable "in_trail" be Boolean, and use the local variable "msg" (which is just the connection's current out_msg pointer) consistently. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 58 ++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 3c5e2061e19..55ccd99558b 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -891,6 +891,33 @@ static void iter_bio_next(struct bio **bio_iter, int *seg) } #endif +static void out_msg_pos_next(struct ceph_connection *con, struct page *page, + size_t len, size_t sent, bool in_trail) +{ + struct ceph_msg *msg = con->out_msg; + + BUG_ON(!msg); + BUG_ON(!sent); + + con->out_msg_pos.data_pos += sent; + con->out_msg_pos.page_pos += sent; + if (sent == len) { + con->out_msg_pos.page_pos = 0; + con->out_msg_pos.page++; + con->out_msg_pos.did_page_crc = false; + if (in_trail) + list_move_tail(&page->lru, + &msg->trail->head); + else if (msg->pagelist) + list_move_tail(&page->lru, + &msg->pagelist->head); +#ifdef CONFIG_BLOCK + else if (msg->bio) + iter_bio_next(&msg->bio_iter, &msg->bio_seg); +#endif + } +} + /* * Write as much message data payload as we can. If we finish, queue * up the footer. @@ -906,11 +933,11 @@ static int write_partial_msg_pages(struct ceph_connection *con) bool do_datacrc = !con->msgr->nocrc; int ret; int total_max_write; - int in_trail = 0; + bool in_trail = false; size_t trail_len = (msg->trail ? msg->trail->length : 0); dout("write_partial_msg_pages %p msg %p page %d/%d offset %d\n", - con, con->out_msg, con->out_msg_pos.page, con->out_msg->nr_pages, + con, msg, con->out_msg_pos.page, msg->nr_pages, con->out_msg_pos.page_pos); #ifdef CONFIG_BLOCK @@ -934,13 +961,12 @@ static int write_partial_msg_pages(struct ceph_connection *con) /* have we reached the trail part of the data? */ if (con->out_msg_pos.data_pos >= data_len - trail_len) { - in_trail = 1; + in_trail = true; total_max_write = data_len - con->out_msg_pos.data_pos; page = list_first_entry(&msg->trail->head, struct page, lru); - max_write = PAGE_SIZE; } else if (msg->pages) { page = msg->pages[con->out_msg_pos.page]; } else if (msg->pagelist) { @@ -964,14 +990,14 @@ static int write_partial_msg_pages(struct ceph_connection *con) if (do_datacrc && !con->out_msg_pos.did_page_crc) { void *base; u32 crc; - u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc); + u32 tmpcrc = le32_to_cpu(msg->footer.data_crc); char *kaddr; kaddr = kmap(page); BUG_ON(kaddr == NULL); base = kaddr + con->out_msg_pos.page_pos + bio_offset; crc = crc32c(tmpcrc, base, len); - con->out_msg->footer.data_crc = cpu_to_le32(crc); + msg->footer.data_crc = cpu_to_le32(crc); con->out_msg_pos.did_page_crc = true; } ret = ceph_tcp_sendpage(con->sock, page, @@ -984,30 +1010,14 @@ static int write_partial_msg_pages(struct ceph_connection *con) if (ret <= 0) goto out; - con->out_msg_pos.data_pos += ret; - con->out_msg_pos.page_pos += ret; - if (ret == len) { - con->out_msg_pos.page_pos = 0; - con->out_msg_pos.page++; - con->out_msg_pos.did_page_crc = false; - if (in_trail) - list_move_tail(&page->lru, - &msg->trail->head); - else if (msg->pagelist) - list_move_tail(&page->lru, - &msg->pagelist->head); -#ifdef CONFIG_BLOCK - else if (msg->bio) - iter_bio_next(&msg->bio_iter, &msg->bio_seg); -#endif - } + out_msg_pos_next(con, page, len, (size_t) ret, in_trail); } dout("write_partial_msg_pages %p msg %p done\n", con, msg); /* prepare and queue up footer, too */ if (!do_datacrc) - con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC; + msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC; con_out_kvec_reset(con); prepare_write_message_footer(con); ret = 1; From 3b17b0bb2b1dcfa3e8aee9ce7ee5c239b1109b72 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 11 Jun 2012 14:57:13 -0500 Subject: [PATCH 1564/2357] libceph: don't mark footer complete before it is (cherry picked from commit fd154f3c75465abd83b7a395033e3755908a1e6e) This is a nit, but prepare_write_message() sets the FOOTER_COMPLETE flag before the CRC for the data portion (recorded in the footer) has been completely computed. Hold off setting the complete flag until we've decided it's ready to send. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 55ccd99558b..95f2cda3c37 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -592,6 +592,8 @@ static void prepare_write_message_footer(struct ceph_connection *con) struct ceph_msg *m = con->out_msg; int v = con->out_kvec_left; + m->footer.flags |= CEPH_MSG_FOOTER_COMPLETE; + dout("prepare_write_message_footer %p\n", con); con->out_kvec_is_msg = true; con->out_kvec[v].iov_base = &m->footer; @@ -665,7 +667,7 @@ static void prepare_write_message(struct ceph_connection *con) /* fill in crc (except data pages), footer */ crc = crc32c(0, &m->hdr, offsetof(struct ceph_msg_header, crc)); con->out_msg->hdr.crc = cpu_to_le32(crc); - con->out_msg->footer.flags = CEPH_MSG_FOOTER_COMPLETE; + con->out_msg->footer.flags = 0; crc = crc32c(0, m->front.iov_base, m->front.iov_len); con->out_msg->footer.front_crc = cpu_to_le32(crc); From ec53635e8f11ddf452f69d93eb562c3c5eada75f Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 11 Jun 2012 14:57:13 -0500 Subject: [PATCH 1565/2357] libceph: move init_bio_*() functions up (cherry picked from commit df6ad1f97342ebc4270128222e896541405eecdb) Move init_bio_iter() and iter_bio_next() up in their source file so the'll be defined before they're needed. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 50 ++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 95f2cda3c37..f35f0c382c6 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -565,6 +565,31 @@ static void con_out_kvec_add(struct ceph_connection *con, con->out_kvec_bytes += size; } +#ifdef CONFIG_BLOCK +static void init_bio_iter(struct bio *bio, struct bio **iter, int *seg) +{ + if (!bio) { + *iter = NULL; + *seg = 0; + return; + } + *iter = bio; + *seg = bio->bi_idx; +} + +static void iter_bio_next(struct bio **bio_iter, int *seg) +{ + if (*bio_iter == NULL) + return; + + BUG_ON(*seg >= (*bio_iter)->bi_vcnt); + + (*seg)++; + if (*seg == (*bio_iter)->bi_vcnt) + init_bio_iter((*bio_iter)->bi_next, bio_iter, seg); +} +#endif + static void prepare_write_message_data(struct ceph_connection *con) { struct ceph_msg *msg = con->out_msg; @@ -868,31 +893,6 @@ static int write_partial_kvec(struct ceph_connection *con) return ret; /* done! */ } -#ifdef CONFIG_BLOCK -static void init_bio_iter(struct bio *bio, struct bio **iter, int *seg) -{ - if (!bio) { - *iter = NULL; - *seg = 0; - return; - } - *iter = bio; - *seg = bio->bi_idx; -} - -static void iter_bio_next(struct bio **bio_iter, int *seg) -{ - if (*bio_iter == NULL) - return; - - BUG_ON(*seg >= (*bio_iter)->bi_vcnt); - - (*seg)++; - if (*seg == (*bio_iter)->bi_vcnt) - init_bio_iter((*bio_iter)->bi_next, bio_iter, seg); -} -#endif - static void out_msg_pos_next(struct ceph_connection *con, struct page *page, size_t len, size_t sent, bool in_trail) { From 67e5007aca705782360373d36613827ebe9e2f36 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 11 Jun 2012 14:57:13 -0500 Subject: [PATCH 1566/2357] libceph: move init of bio_iter (cherry picked from commit 572c588edadaa3da3992bd8a0fed830bbcc861f8) If a message has a non-null bio pointer, its bio_iter field is initialized in write_partial_msg_pages() if this has not been done already. This is really a one-time setup operation for sending a message's (bio) data, so move that initialization code into prepare_write_message_data() which serves that purpose. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index f35f0c382c6..0c097b0dba9 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -603,6 +603,10 @@ static void prepare_write_message_data(struct ceph_connection *con) con->out_msg_pos.page_pos = msg->page_alignment; else con->out_msg_pos.page_pos = 0; +#ifdef CONFIG_BLOCK + if (msg->bio && !msg->bio_iter) + init_bio_iter(msg->bio, &msg->bio_iter, &msg->bio_seg); +#endif con->out_msg_pos.data_pos = 0; con->out_msg_pos.did_page_crc = false; con->out_more = 1; /* data + footer will follow */ @@ -942,11 +946,6 @@ static int write_partial_msg_pages(struct ceph_connection *con) con, msg, con->out_msg_pos.page, msg->nr_pages, con->out_msg_pos.page_pos); -#ifdef CONFIG_BLOCK - if (msg->bio && !msg->bio_iter) - init_bio_iter(msg->bio, &msg->bio_iter, &msg->bio_seg); -#endif - while (data_len > con->out_msg_pos.data_pos) { struct page *page = NULL; int max_write = PAGE_SIZE; From f8920642ec1913872f1af07aa8bcb3570bf6ec77 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 11 Jun 2012 14:57:13 -0500 Subject: [PATCH 1567/2357] libceph: don't use bio_iter as a flag (cherry picked from commit abdaa6a849af1d63153682c11f5bbb22dacb1f6b) Recently a bug was fixed in which the bio_iter field in a ceph message was not being properly re-initialized when a message got re-transmitted: commit 43643528cce60ca184fe8197efa8e8da7c89a037 Author: Yan, Zheng rbd: Clear ceph_msg->bio_iter for retransmitted message We are now only initializing the bio_iter field when we are about to start to write message data (in prepare_write_message_data()), rather than every time we are attempting to write any portion of the message data (in write_partial_msg_pages()). This means we no longer need to use the msg->bio_iter field as a flag. So just don't do that any more. Trust prepare_write_message_data() to ensure msg->bio_iter is properly initialized, every time we are about to begin writing (or re-writing) a message's bio data. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 0c097b0dba9..f0499fe069a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -604,7 +604,7 @@ static void prepare_write_message_data(struct ceph_connection *con) else con->out_msg_pos.page_pos = 0; #ifdef CONFIG_BLOCK - if (msg->bio && !msg->bio_iter) + if (msg->bio) init_bio_iter(msg->bio, &msg->bio_iter, &msg->bio_seg); #endif con->out_msg_pos.data_pos = 0; @@ -672,10 +672,6 @@ static void prepare_write_message(struct ceph_connection *con) m->hdr.seq = cpu_to_le64(++con->out_seq); m->needs_out_seq = false; } -#ifdef CONFIG_BLOCK - else - m->bio_iter = NULL; -#endif dout("prepare_write_message %p seq %lld type %d len %d+%d+%d %d pgs\n", m, con->out_seq, le16_to_cpu(m->hdr.type), From eb8c5642db57af9577ebfea7ff9e96eadbf596b8 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 20 Jun 2012 21:53:53 -0500 Subject: [PATCH 1568/2357] libceph: SOCK_CLOSED is a flag, not a state (cherry picked from commit a8d00e3cdef4c1c4f194414b72b24cd995439a05) The following commit changed it so SOCK_CLOSED bit was stored in a connection's new "flags" field rather than its "state" field. libceph: start separating connection flags from state commit 928443cd That bit is used in con_close_socket() to protect against setting an error message more than once in the socket event handler function. Unfortunately, the field being operated on in that function was not updated to be "flags" as it should have been. This fixes that error. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index f0499fe069a..edcf5eb22b4 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -397,11 +397,11 @@ static int con_close_socket(struct ceph_connection *con) dout("con_close_socket on %p sock %p\n", con, con->sock); if (!con->sock) return 0; - set_bit(SOCK_CLOSED, &con->state); + set_bit(SOCK_CLOSED, &con->flags); rc = con->sock->ops->shutdown(con->sock, SHUT_RDWR); sock_release(con->sock); con->sock = NULL; - clear_bit(SOCK_CLOSED, &con->state); + clear_bit(SOCK_CLOSED, &con->flags); con_sock_state_closed(con); return rc; } From 54942c5326f039a40c407a251175cd3925ce2951 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 20 Jun 2012 21:53:53 -0500 Subject: [PATCH 1569/2357] libceph: don't change socket state on sock event (cherry picked from commit 188048bce311ee41e5178bc3255415d0eae28423) Currently the socket state change event handler records an error message on a connection to distinguish a close while connecting from a close while a connection was already established. Changing connection information during handling of a socket event is not very clean, so instead move this assignment inside con_work(), where it can be done during normal connection-level processing (and under protection of the connection mutex as well). Move the handling of a socket closed event up to the top of the processing loop in con_work(); there's no point in handling backoff etc. if we have a newly-closed socket to take care of. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index edcf5eb22b4..ed922b7c05b 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -261,13 +261,8 @@ static void ceph_sock_state_change(struct sock *sk) case TCP_CLOSE_WAIT: dout("%s TCP_CLOSE_WAIT\n", __func__); con_sock_state_closing(con); - if (test_and_set_bit(SOCK_CLOSED, &con->flags) == 0) { - if (test_bit(CONNECTING, &con->state)) - con->error_msg = "connection failed"; - else - con->error_msg = "socket closed"; + if (!test_and_set_bit(SOCK_CLOSED, &con->flags)) queue_con(con); - } break; case TCP_ESTABLISHED: dout("%s TCP_ESTABLISHED\n", __func__); @@ -2187,6 +2182,14 @@ static void con_work(struct work_struct *work) mutex_lock(&con->mutex); restart: + if (test_and_clear_bit(SOCK_CLOSED, &con->flags)) { + if (test_bit(CONNECTING, &con->state)) + con->error_msg = "connection failed"; + else + con->error_msg = "socket closed"; + goto fault; + } + if (test_and_clear_bit(BACKOFF, &con->flags)) { dout("con_work %p backing off\n", con); if (queue_delayed_work(ceph_msgr_wq, &con->work, @@ -2216,9 +2219,6 @@ static void con_work(struct work_struct *work) con_close_socket(con); } - if (test_and_clear_bit(SOCK_CLOSED, &con->flags)) - goto fault; - ret = try_read(con); if (ret == -EAGAIN) goto restart; From 70b06043cd9aebf15319ce3917196ff032dc20dd Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 20 Jun 2012 21:53:53 -0500 Subject: [PATCH 1570/2357] libceph: just set SOCK_CLOSED when state changes (cherry picked from commit d65c9e0b9eb43d14ece9dd843506ccba06162ee7) When a TCP_CLOSE or TCP_CLOSE_WAIT event occurs, the SOCK_CLOSED connection flag bit is set, and if it had not been previously set queue_con() is called to ensure con_work() will get a chance to handle the changed state. con_work() atomically checks--and if set, clears--the SOCK_CLOSED bit if it was set. This means that even if the bit were set repeatedly, the related processing in con_work() only gets called once per transition of the bit from 0 to 1. What's important then is that we ensure con_work() gets called *at least* once when a socket close event occurs, not that it gets called *exactly* once. The work queue mechanism already takes care of queueing work only if it is not already queued, so there's no need for us to call queue_con() conditionally. So this patch just makes it so the SOCK_CLOSED flag gets set unconditionally in ceph_sock_state_change(). Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index ed922b7c05b..f8ca57805b1 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -261,8 +261,8 @@ static void ceph_sock_state_change(struct sock *sk) case TCP_CLOSE_WAIT: dout("%s TCP_CLOSE_WAIT\n", __func__); con_sock_state_closing(con); - if (!test_and_set_bit(SOCK_CLOSED, &con->flags)) - queue_con(con); + set_bit(SOCK_CLOSED, &con->flags); + queue_con(con); break; case TCP_ESTABLISHED: dout("%s TCP_ESTABLISHED\n", __func__); From 8a62c3339d5455c46c1da1e9fb9b60df20e59905 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 20 Jun 2012 21:53:53 -0500 Subject: [PATCH 1571/2357] libceph: don't touch con state in con_close_socket() (cherry picked from commit 456ea46865787283088b23a8a7f69244513b95f0) In con_close_socket(), a connection's SOCK_CLOSED flag gets set and then cleared while its shutdown method is called and its reference gets dropped. Previously, that flag got set only if it had not already been set, so setting it in con_close_socket() might have prevented additional processing being done on a socket being shut down. We no longer set SOCK_CLOSED in the socket event routine conditionally, so setting that bit here no longer provides whatever benefit it might have provided before. A race condition could still leave the SOCK_CLOSED bit set even after we've issued the call to con_close_socket(), so we still clear that bit after shutting the socket down. Add a comment explaining the reason for this. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index f8ca57805b1..8edd3052d34 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -392,10 +392,16 @@ static int con_close_socket(struct ceph_connection *con) dout("con_close_socket on %p sock %p\n", con, con->sock); if (!con->sock) return 0; - set_bit(SOCK_CLOSED, &con->flags); rc = con->sock->ops->shutdown(con->sock, SHUT_RDWR); sock_release(con->sock); con->sock = NULL; + + /* + * Forcibly clear the SOCK_CLOSE flag. It gets set + * independent of the connection mutex, and we could have + * received a socket close event before we had the chance to + * shut the socket down. + */ clear_bit(SOCK_CLOSED, &con->flags); con_sock_state_closed(con); return rc; From 2a281c7aa696af085db44154d053a169e4b07449 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 20 Jun 2012 21:53:53 -0500 Subject: [PATCH 1572/2357] libceph: clear CONNECTING in ceph_con_close() (cherry picked from commit bb9e6bba5d8b85b631390f8dbe8a24ae1ff5b48a) A connection that is closed will no longer be connecting. So clear the CONNECTING state bit in ceph_con_close(). Similarly, if the socket has been closed we no longer are in connecting state (a new connect sequence will need to be initiated). Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 8edd3052d34..7d3ce898e6d 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -462,6 +462,7 @@ void ceph_con_close(struct ceph_connection *con) dout("con_close %p peer %s\n", con, ceph_pr_addr(&con->peer_addr.in_addr)); clear_bit(NEGOTIATING, &con->state); + clear_bit(CONNECTING, &con->state); clear_bit(STANDBY, &con->state); /* avoid connect_seq bump */ set_bit(CLOSED, &con->state); @@ -2189,7 +2190,7 @@ static void con_work(struct work_struct *work) mutex_lock(&con->mutex); restart: if (test_and_clear_bit(SOCK_CLOSED, &con->flags)) { - if (test_bit(CONNECTING, &con->state)) + if (test_and_clear_bit(CONNECTING, &con->state)) con->error_msg = "connection failed"; else con->error_msg = "socket closed"; From abb46df87f784b398bcdb5091175d24456e42f11 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 23 May 2012 14:35:23 -0500 Subject: [PATCH 1573/2357] libceph: clear NEGOTIATING when done (cherry picked from commit 3ec50d1868a9e0493046400bb1fdd054c7f64ebd) A connection state's NEGOTIATING bit gets set while in CONNECTING state after we have successfully exchanged a ceph banner and IP addresses with the connection's peer (the server). But that bit is not cleared again--at least not until another connection attempt is initiated. Instead, clear it as soon as the connection is fully established. Also, clear it when a socket connection gets prematurely closed in the midst of establishing a ceph connection (in case we had reached the point where it was set). Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 7d3ce898e6d..aa911e22edb 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1562,6 +1562,7 @@ static int process_connect(struct ceph_connection *con) fail_protocol(con); return -1; } + clear_bit(NEGOTIATING, &con->state); clear_bit(CONNECTING, &con->state); con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq); con->connect_seq++; @@ -1951,7 +1952,6 @@ static int try_write(struct ceph_connection *con) /* open the socket first? */ if (con->sock == NULL) { - clear_bit(NEGOTIATING, &con->state); set_bit(CONNECTING, &con->state); con_out_kvec_reset(con); @@ -2190,10 +2190,12 @@ static void con_work(struct work_struct *work) mutex_lock(&con->mutex); restart: if (test_and_clear_bit(SOCK_CLOSED, &con->flags)) { - if (test_and_clear_bit(CONNECTING, &con->state)) + if (test_and_clear_bit(CONNECTING, &con->state)) { + clear_bit(NEGOTIATING, &con->state); con->error_msg = "connection failed"; - else + } else { con->error_msg = "socket closed"; + } goto fault; } From a94af04be86f81d5e3973a37e6a861f329418f1e Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 23 May 2012 14:35:23 -0500 Subject: [PATCH 1574/2357] libceph: define and use an explicit CONNECTED state (cherry picked from commit e27947c767f5bed15048f4e4dad3e2eb69133697) There is no state explicitly defined when a ceph connection is fully operational. So define one. It's set when the connection sequence completes successfully, and is cleared when the connection gets closed. Be a little more careful when examining the old state when a socket disconnect event is reported. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 1 + net/ceph/messenger.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index f624b752e82..6a00acc61d4 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -120,6 +120,7 @@ struct ceph_msg_pos { */ #define CONNECTING 1 #define NEGOTIATING 2 +#define CONNECTED 5 #define STANDBY 8 /* no outgoing messages, socket closed. we keep * the ceph_connection around to maintain shared * state with the peer. */ diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index aa911e22edb..2a78d5c47b1 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -463,6 +463,7 @@ void ceph_con_close(struct ceph_connection *con) ceph_pr_addr(&con->peer_addr.in_addr)); clear_bit(NEGOTIATING, &con->state); clear_bit(CONNECTING, &con->state); + clear_bit(CONNECTED, &con->state); clear_bit(STANDBY, &con->state); /* avoid connect_seq bump */ set_bit(CLOSED, &con->state); @@ -1564,6 +1565,7 @@ static int process_connect(struct ceph_connection *con) } clear_bit(NEGOTIATING, &con->state); clear_bit(CONNECTING, &con->state); + set_bit(CONNECTED, &con->state); con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq); con->connect_seq++; con->peer_features = server_feat; @@ -2114,6 +2116,7 @@ static int try_read(struct ceph_connection *con) prepare_read_ack(con); break; case CEPH_MSGR_TAG_CLOSE: + clear_bit(CONNECTED, &con->state); set_bit(CLOSED, &con->state); /* fixme */ goto out; default: @@ -2190,11 +2193,13 @@ static void con_work(struct work_struct *work) mutex_lock(&con->mutex); restart: if (test_and_clear_bit(SOCK_CLOSED, &con->flags)) { - if (test_and_clear_bit(CONNECTING, &con->state)) { + if (test_and_clear_bit(CONNECTED, &con->state)) + con->error_msg = "socket closed"; + else if (test_and_clear_bit(CONNECTING, &con->state)) { clear_bit(NEGOTIATING, &con->state); con->error_msg = "connection failed"; } else { - con->error_msg = "socket closed"; + con->error_msg = "unrecognized con state"; } goto fault; } From 05a24ecce18262f17aa0b28a6bf1191a2a456975 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 31 May 2012 11:37:29 -0500 Subject: [PATCH 1575/2357] libceph: separate banner and connect writes (cherry picked from commit ab166d5aa3bc036fba7efaca6e4e43a7e9510acf) There are two phases in the process of linking together the two ends of a ceph connection. The first involves exchanging a banner and IP addresses, and if that is successful a second phase exchanges some detail about each side's connection capabilities. When initiating a connection, the client side now queues to send its information for both phases of this process at the same time. This is probably a bit more efficient, but it is slightly messier from a layering perspective in the code. So rearrange things so that the client doesn't send the connection information until it has received and processed the response in the initial banner phase (in process_banner()). Move the code (in the (con->sock == NULL) case in try_write()) that prepares for writing the connection information, delaying doing that until the banner exchange has completed. Move the code that begins the transition to this second "NEGOTIATING" phase out of process_banner() and into its caller, so preparing to write the connection information and preparing to read the response are adjacent to each other. Finally, preparing to write the connection information now requires the output kvec to be reset in all cases, so move that into the prepare_write_connect() and delete it from all callers. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 2a78d5c47b1..7df64aed5f1 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -841,6 +841,7 @@ static int prepare_write_connect(struct ceph_connection *con) con->out_connect.authorizer_len = auth ? cpu_to_le32(auth->authorizer_buf_len) : 0; + con_out_kvec_reset(con); con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); if (auth && auth->authorizer_buf_len) @@ -1430,8 +1431,6 @@ static int process_banner(struct ceph_connection *con) ceph_pr_addr(&con->msgr->inst.addr.in_addr)); } - set_bit(NEGOTIATING, &con->state); - prepare_read_connect(con); return 0; } @@ -1481,7 +1480,6 @@ static int process_connect(struct ceph_connection *con) return -1; } con->auth_retry = 1; - con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1502,7 +1500,6 @@ static int process_connect(struct ceph_connection *con) ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr)); reset_connection(con); - con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1528,7 +1525,6 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->out_connect.connect_seq), le32_to_cpu(con->in_reply.connect_seq)); con->connect_seq = le32_to_cpu(con->in_reply.connect_seq); - con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1545,7 +1541,6 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->in_reply.global_seq)); get_global_seq(con->msgr, le32_to_cpu(con->in_reply.global_seq)); - con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1958,9 +1953,6 @@ static int try_write(struct ceph_connection *con) con_out_kvec_reset(con); prepare_write_banner(con); - ret = prepare_write_connect(con); - if (ret < 0) - goto out; prepare_read_banner(con); BUG_ON(con->in_msg); @@ -2073,6 +2065,16 @@ static int try_read(struct ceph_connection *con) ret = process_banner(con); if (ret < 0) goto out; + + /* Banner is good, exchange connection info */ + ret = prepare_write_connect(con); + if (ret < 0) + goto out; + prepare_read_connect(con); + set_bit(NEGOTIATING, &con->state); + + /* Send connection info before awaiting response */ + goto out; } ret = read_partial_connect(con); if (ret <= 0) From 8a0566f6aac534a20ed436e3bed56b736cef4c40 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 24 May 2012 11:55:03 -0500 Subject: [PATCH 1576/2357] libceph: distinguish two phases of connect sequence (cherry picked from commit 7593af920baac37752190a0db703d2732bed4a3b) Currently a ceph connection enters a "CONNECTING" state when it begins the process of (re-)connecting with its peer. Once the two ends have successfully exchanged their banner and addresses, an additional NEGOTIATING bit is set in the ceph connection's state to indicate the connection information exhange has begun. The CONNECTING bit/state continues to be set during this phase. Rather than have the CONNECTING state continue while the NEGOTIATING bit is set, interpret these two phases as distinct states. In other words, when NEGOTIATING is set, clear CONNECTING. That way only one of them will be active at a time. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 52 ++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 7df64aed5f1..1db6b68c2e4 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1559,7 +1559,6 @@ static int process_connect(struct ceph_connection *con) return -1; } clear_bit(NEGOTIATING, &con->state); - clear_bit(CONNECTING, &con->state); set_bit(CONNECTED, &con->state); con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq); con->connect_seq++; @@ -2000,7 +1999,8 @@ static int try_write(struct ceph_connection *con) } do_next: - if (!test_bit(CONNECTING, &con->state)) { + if (!test_bit(CONNECTING, &con->state) && + !test_bit(NEGOTIATING, &con->state)) { /* is anything else pending? */ if (!list_empty(&con->out_queue)) { prepare_write_message(con); @@ -2057,25 +2057,29 @@ static int try_read(struct ceph_connection *con) } if (test_bit(CONNECTING, &con->state)) { - if (!test_bit(NEGOTIATING, &con->state)) { - dout("try_read connecting\n"); - ret = read_partial_banner(con); - if (ret <= 0) - goto out; - ret = process_banner(con); - if (ret < 0) - goto out; - - /* Banner is good, exchange connection info */ - ret = prepare_write_connect(con); - if (ret < 0) - goto out; - prepare_read_connect(con); - set_bit(NEGOTIATING, &con->state); - - /* Send connection info before awaiting response */ + dout("try_read connecting\n"); + ret = read_partial_banner(con); + if (ret <= 0) goto out; - } + ret = process_banner(con); + if (ret < 0) + goto out; + + clear_bit(CONNECTING, &con->state); + set_bit(NEGOTIATING, &con->state); + + /* Banner is good, exchange connection info */ + ret = prepare_write_connect(con); + if (ret < 0) + goto out; + prepare_read_connect(con); + + /* Send connection info before awaiting response */ + goto out; + } + + if (test_bit(NEGOTIATING, &con->state)) { + dout("try_read negotiating\n"); ret = read_partial_connect(con); if (ret <= 0) goto out; @@ -2197,12 +2201,12 @@ static void con_work(struct work_struct *work) if (test_and_clear_bit(SOCK_CLOSED, &con->flags)) { if (test_and_clear_bit(CONNECTED, &con->state)) con->error_msg = "socket closed"; - else if (test_and_clear_bit(CONNECTING, &con->state)) { - clear_bit(NEGOTIATING, &con->state); + else if (test_and_clear_bit(NEGOTIATING, &con->state)) + con->error_msg = "negotiation failed"; + else if (test_and_clear_bit(CONNECTING, &con->state)) con->error_msg = "connection failed"; - } else { + else con->error_msg = "unrecognized con state"; - } goto fault; } From a8651271bb5d77402251bf35554d1f320463c949 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 11 Jun 2012 14:57:13 -0500 Subject: [PATCH 1577/2357] libceph: small changes to messenger.c (cherry picked from commit 5821bd8ccdf5d17ab2c391c773756538603838c3) This patch gathers a few small changes in "net/ceph/messenger.c": out_msg_pos_next() - small logic change that mostly affects indentation write_partial_msg_pages(). - use a local variable trail_off to represent the offset into a message of the trail portion of the data (if present) - once we are in the trail portion we will always be there, so we don't always need to check against our data position - avoid computing len twice after we've reached the trail - get rid of the variable tmpcrc, which is not needed - trail_off and trail_len never change so mark them const - update some comments read_partial_message_bio() - bio_iovec_idx() will never return an error, so don't bother checking for it Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 63 ++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 1db6b68c2e4..73e2ee847be 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -907,21 +907,23 @@ static void out_msg_pos_next(struct ceph_connection *con, struct page *page, con->out_msg_pos.data_pos += sent; con->out_msg_pos.page_pos += sent; - if (sent == len) { - con->out_msg_pos.page_pos = 0; - con->out_msg_pos.page++; - con->out_msg_pos.did_page_crc = false; - if (in_trail) - list_move_tail(&page->lru, - &msg->trail->head); - else if (msg->pagelist) - list_move_tail(&page->lru, - &msg->pagelist->head); + if (sent < len) + return; + + BUG_ON(sent != len); + con->out_msg_pos.page_pos = 0; + con->out_msg_pos.page++; + con->out_msg_pos.did_page_crc = false; + if (in_trail) + list_move_tail(&page->lru, + &msg->trail->head); + else if (msg->pagelist) + list_move_tail(&page->lru, + &msg->pagelist->head); #ifdef CONFIG_BLOCK - else if (msg->bio) - iter_bio_next(&msg->bio_iter, &msg->bio_seg); + else if (msg->bio) + iter_bio_next(&msg->bio_iter, &msg->bio_seg); #endif - } } /* @@ -940,30 +942,31 @@ static int write_partial_msg_pages(struct ceph_connection *con) int ret; int total_max_write; bool in_trail = false; - size_t trail_len = (msg->trail ? msg->trail->length : 0); + const size_t trail_len = (msg->trail ? msg->trail->length : 0); + const size_t trail_off = data_len - trail_len; dout("write_partial_msg_pages %p msg %p page %d/%d offset %d\n", con, msg, con->out_msg_pos.page, msg->nr_pages, con->out_msg_pos.page_pos); + /* + * Iterate through each page that contains data to be + * written, and send as much as possible for each. + * + * If we are calculating the data crc (the default), we will + * need to map the page. If we have no pages, they have + * been revoked, so use the zero page. + */ while (data_len > con->out_msg_pos.data_pos) { struct page *page = NULL; int max_write = PAGE_SIZE; int bio_offset = 0; - total_max_write = data_len - trail_len - - con->out_msg_pos.data_pos; - - /* - * if we are calculating the data crc (the default), we need - * to map the page. if our pages[] has been revoked, use the - * zero page. - */ - - /* have we reached the trail part of the data? */ - if (con->out_msg_pos.data_pos >= data_len - trail_len) { - in_trail = true; + in_trail = in_trail || con->out_msg_pos.data_pos >= trail_off; + if (!in_trail) + total_max_write = trail_off - con->out_msg_pos.data_pos; + if (in_trail) { total_max_write = data_len - con->out_msg_pos.data_pos; page = list_first_entry(&msg->trail->head, @@ -990,14 +993,13 @@ static int write_partial_msg_pages(struct ceph_connection *con) if (do_datacrc && !con->out_msg_pos.did_page_crc) { void *base; - u32 crc; - u32 tmpcrc = le32_to_cpu(msg->footer.data_crc); + u32 crc = le32_to_cpu(msg->footer.data_crc); char *kaddr; kaddr = kmap(page); BUG_ON(kaddr == NULL); base = kaddr + con->out_msg_pos.page_pos + bio_offset; - crc = crc32c(tmpcrc, base, len); + crc = crc32c(crc, base, len); msg->footer.data_crc = cpu_to_le32(crc); con->out_msg_pos.did_page_crc = true; } @@ -1702,9 +1704,6 @@ static int read_partial_message_bio(struct ceph_connection *con, void *p; int ret, left; - if (IS_ERR(bv)) - return PTR_ERR(bv); - left = min((int)(data_len - con->in_msg_pos.data_pos), (int)(bv->bv_len - con->in_msg_pos.page_pos)); From db90f992eb77188ce3e2b95d36f99ba194e04e66 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 20 Jun 2012 21:53:53 -0500 Subject: [PATCH 1578/2357] libceph: add some fine ASCII art (cherry picked from commit bc18f4b1c850ab355e38373fbb60fd28568d84b5) Sage liked the state diagram I put in my commit description so I'm putting it in with the code. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 73e2ee847be..c40d1d5b304 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -29,7 +29,47 @@ * the sender. */ -/* State values for ceph_connection->sock_state; NEW is assumed to be 0 */ +/* + * We track the state of the socket on a given connection using + * values defined below. The transition to a new socket state is + * handled by a function which verifies we aren't coming from an + * unexpected state. + * + * -------- + * | NEW* | transient initial state + * -------- + * | con_sock_state_init() + * v + * ---------- + * | CLOSED | initialized, but no socket (and no + * ---------- TCP connection) + * ^ \ + * | \ con_sock_state_connecting() + * | ---------------------- + * | \ + * + con_sock_state_closed() \ + * |\ \ + * | \ \ + * | ----------- \ + * | | CLOSING | socket event; \ + * | ----------- await close \ + * | ^ | + * | | | + * | + con_sock_state_closing() | + * | / \ | + * | / --------------- | + * | / \ v + * | / -------------- + * | / -----------------| CONNECTING | socket created, TCP + * | | / -------------- connect initiated + * | | | con_sock_state_connected() + * | | v + * ------------- + * | CONNECTED | TCP connection established + * ------------- + * + * State values for ceph_connection->sock_state; NEW is assumed to be 0. + */ #define CON_SOCK_STATE_NEW 0 /* -> CLOSED */ #define CON_SOCK_STATE_CLOSED 1 /* -> CONNECTING */ From 638ba1765d03bdc3a972bfca69fd0a4a4eda717c Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 27 Jun 2012 12:24:08 -0700 Subject: [PATCH 1579/2357] libceph: set peer name on con_open, not init (cherry picked from commit b7a9e5dd40f17a48a72f249b8bbc989b63bae5fd) The peer name may change on each open attempt, even when the connection is reused. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 7 ++++--- include/linux/ceph/messenger.h | 4 ++-- net/ceph/messenger.c | 12 +++++++----- net/ceph/mon_client.c | 4 ++-- net/ceph/osd_client.c | 10 ++++++---- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index ecd7f15741c..5ac6434185a 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -394,8 +394,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, s->s_seq = 0; mutex_init(&s->s_mutex); - ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr, - CEPH_ENTITY_TYPE_MDS, mds); + ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr); spin_lock_init(&s->s_gen_ttl_lock); s->s_cap_gen = 0; @@ -437,7 +436,8 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, mdsc->sessions[mds] = s; atomic_inc(&s->s_ref); /* one ref to sessions[], one to caller */ - ceph_con_open(&s->s_con, ceph_mdsmap_get_addr(mdsc->mdsmap, mds)); + ceph_con_open(&s->s_con, CEPH_ENTITY_TYPE_MDS, mds, + ceph_mdsmap_get_addr(mdsc->mdsmap, mds)); return s; @@ -2529,6 +2529,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, session->s_seq = 0; ceph_con_open(&session->s_con, + CEPH_ENTITY_TYPE_MDS, mds, ceph_mdsmap_get_addr(mdsc->mdsmap, mds)); /* replay unsafe requests */ diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 6a00acc61d4..ec22abd51fa 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -224,9 +224,9 @@ extern void ceph_messenger_init(struct ceph_messenger *msgr, extern void ceph_con_init(struct ceph_connection *con, void *private, const struct ceph_connection_operations *ops, - struct ceph_messenger *msgr, __u8 entity_type, - __u64 entity_num); + struct ceph_messenger *msgr); extern void ceph_con_open(struct ceph_connection *con, + __u8 entity_type, __u64 entity_num, struct ceph_entity_addr *addr); extern bool ceph_con_opened(struct ceph_connection *con); extern void ceph_con_close(struct ceph_connection *con); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index c40d1d5b304..e7cb279162f 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -523,12 +523,17 @@ EXPORT_SYMBOL(ceph_con_close); /* * Reopen a closed connection, with a new peer address. */ -void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr) +void ceph_con_open(struct ceph_connection *con, + __u8 entity_type, __u64 entity_num, + struct ceph_entity_addr *addr) { dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr)); set_bit(OPENING, &con->state); WARN_ON(!test_and_clear_bit(CLOSED, &con->state)); + con->peer_name.type = (__u8) entity_type; + con->peer_name.num = cpu_to_le64(entity_num); + memcpy(&con->peer_addr, addr, sizeof(*addr)); con->delay = 0; /* reset backoff memory */ queue_con(con); @@ -548,7 +553,7 @@ bool ceph_con_opened(struct ceph_connection *con) */ void ceph_con_init(struct ceph_connection *con, void *private, const struct ceph_connection_operations *ops, - struct ceph_messenger *msgr, __u8 entity_type, __u64 entity_num) + struct ceph_messenger *msgr) { dout("con_init %p\n", con); memset(con, 0, sizeof(*con)); @@ -558,9 +563,6 @@ void ceph_con_init(struct ceph_connection *con, void *private, con_sock_state_init(con); - con->peer_name.type = (__u8) entity_type; - con->peer_name.num = cpu_to_le64(entity_num); - mutex_init(&con->mutex); INIT_LIST_HEAD(&con->out_queue); INIT_LIST_HEAD(&con->out_sent); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index dc16595d688..39d772fdfab 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -143,11 +143,11 @@ static int __open_session(struct ceph_mon_client *monc) monc->want_next_osdmap = !!monc->want_next_osdmap; ceph_con_init(&monc->con, monc, &mon_con_ops, - &monc->client->msgr, - CEPH_ENTITY_TYPE_MON, monc->cur_mon); + &monc->client->msgr); dout("open_session mon%d opening\n", monc->cur_mon); ceph_con_open(&monc->con, + CEPH_ENTITY_TYPE_MON, monc->cur_mon, &monc->monmap->mon_inst[monc->cur_mon].addr); /* initiatiate authentication handshake */ diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index c178c770acb..474a52d9b4a 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -639,8 +639,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum) INIT_LIST_HEAD(&osd->o_osd_lru); osd->o_incarnation = 1; - ceph_con_init(&osd->o_con, osd, &osd_con_ops, &osdc->client->msgr, - CEPH_ENTITY_TYPE_OSD, onum); + ceph_con_init(&osd->o_con, osd, &osd_con_ops, &osdc->client->msgr); INIT_LIST_HEAD(&osd->o_keepalive_item); return osd; @@ -750,7 +749,8 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) ret = -EAGAIN; } else { ceph_con_close(&osd->o_con); - ceph_con_open(&osd->o_con, &osdc->osdmap->osd_addr[osd->o_osd]); + ceph_con_open(&osd->o_con, CEPH_ENTITY_TYPE_OSD, osd->o_osd, + &osdc->osdmap->osd_addr[osd->o_osd]); osd->o_incarnation++; } return ret; @@ -1005,7 +1005,9 @@ static int __map_request(struct ceph_osd_client *osdc, dout("map_request osd %p is osd%d\n", req->r_osd, o); __insert_osd(osdc, req->r_osd); - ceph_con_open(&req->r_osd->o_con, &osdc->osdmap->osd_addr[o]); + ceph_con_open(&req->r_osd->o_con, + CEPH_ENTITY_TYPE_OSD, o, + &osdc->osdmap->osd_addr[o]); } if (req->r_osd) { From a5b0662bb814837139bb73249463e199528101b5 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 27 Jun 2012 12:24:34 -0700 Subject: [PATCH 1580/2357] libceph: initialize mon_client con only once (cherry picked from commit 735a72ef952d42a256f79ae3e6dc1c17a45c041b) Do not re-initialize the con on every connection attempt. When we ceph_con_close, there may still be work queued on the socket (e.g., to close it), and re-initializing will clobber the work_struct state. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/mon_client.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 39d772fdfab..9f00d6cd93e 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -119,7 +119,6 @@ static void __close_session(struct ceph_mon_client *monc) dout("__close_session closing mon%d\n", monc->cur_mon); ceph_msg_revoke(monc->m_auth); ceph_con_close(&monc->con); - monc->con.private = NULL; monc->cur_mon = -1; monc->pending_auth = 0; ceph_auth_reset(monc->auth); @@ -142,9 +141,6 @@ static int __open_session(struct ceph_mon_client *monc) monc->sub_renew_after = jiffies; /* i.e., expired */ monc->want_next_osdmap = !!monc->want_next_osdmap; - ceph_con_init(&monc->con, monc, &mon_con_ops, - &monc->client->msgr); - dout("open_session mon%d opening\n", monc->cur_mon); ceph_con_open(&monc->con, CEPH_ENTITY_TYPE_MON, monc->cur_mon, @@ -798,6 +794,9 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl) if (!monc->m_auth) goto out_auth_reply; + ceph_con_init(&monc->con, monc, &mon_con_ops, + &monc->client->msgr); + monc->cur_mon = -1; monc->hunting = true; monc->sub_renew_after = jiffies; From d92d11da1dd8531150823ff429ae29a0cf5e438d Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 27 Jun 2012 12:31:02 -0700 Subject: [PATCH 1581/2357] libceph: allow sock transition from CONNECTING to CLOSED (cherry picked from commit fbb85a478f6d4cce6942f1c25c6a68ec5b1e7e7f) It is possible to close a socket that is in the OPENING state. For example, it can happen if ceph_con_close() is called on the con before the TCP connection is established. con_work() will come around and shut down the socket. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index e7cb279162f..866645fa857 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -48,17 +48,17 @@ * | ---------------------- * | \ * + con_sock_state_closed() \ - * |\ \ - * | \ \ - * | ----------- \ - * | | CLOSING | socket event; \ - * | ----------- await close \ - * | ^ | - * | | | - * | + con_sock_state_closing() | - * | / \ | - * | / --------------- | - * | / \ v + * |+--------------------------- \ + * | \ \ \ + * | ----------- \ \ + * | | CLOSING | socket event; \ \ + * | ----------- await close \ \ + * | ^ \ | + * | | \ | + * | + con_sock_state_closing() \ | + * | / \ | | + * | / --------------- | | + * | / \ v v * | / -------------- * | / -----------------| CONNECTING | socket created, TCP * | | / -------------- connect initiated @@ -241,7 +241,8 @@ static void con_sock_state_closed(struct ceph_connection *con) old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSED); if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTED && - old_state != CON_SOCK_STATE_CLOSING)) + old_state != CON_SOCK_STATE_CLOSING && + old_state != CON_SOCK_STATE_CONNECTING)) printk("%s: unexpected old state %d\n", __func__, old_state); } From 9beb73fcb83317786226b4203d7e56c6b0f43adb Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 9 Jul 2012 14:22:34 -0700 Subject: [PATCH 1582/2357] libceph: initialize msgpool message types (cherry picked from commit d50b409fb8698571d8209e5adfe122e287e31290) Initialize the type field for messages in a msgpool. The caller was doing this for osd ops, but not for the reply messages. Reported-by: Alex Elder Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/msgpool.h | 3 ++- net/ceph/msgpool.c | 7 ++++--- net/ceph/osd_client.c | 7 ++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/linux/ceph/msgpool.h b/include/linux/ceph/msgpool.h index a362605f936..09fa96b4343 100644 --- a/include/linux/ceph/msgpool.h +++ b/include/linux/ceph/msgpool.h @@ -11,10 +11,11 @@ struct ceph_msgpool { const char *name; mempool_t *pool; + int type; /* preallocated message type */ int front_len; /* preallocated payload size */ }; -extern int ceph_msgpool_init(struct ceph_msgpool *pool, +extern int ceph_msgpool_init(struct ceph_msgpool *pool, int type, int front_len, int size, bool blocking, const char *name); extern void ceph_msgpool_destroy(struct ceph_msgpool *pool); diff --git a/net/ceph/msgpool.c b/net/ceph/msgpool.c index 11d5f4196a7..ddec1c10ac8 100644 --- a/net/ceph/msgpool.c +++ b/net/ceph/msgpool.c @@ -12,7 +12,7 @@ static void *msgpool_alloc(gfp_t gfp_mask, void *arg) struct ceph_msgpool *pool = arg; struct ceph_msg *msg; - msg = ceph_msg_new(0, pool->front_len, gfp_mask, true); + msg = ceph_msg_new(pool->type, pool->front_len, gfp_mask, true); if (!msg) { dout("msgpool_alloc %s failed\n", pool->name); } else { @@ -32,10 +32,11 @@ static void msgpool_free(void *element, void *arg) ceph_msg_put(msg); } -int ceph_msgpool_init(struct ceph_msgpool *pool, +int ceph_msgpool_init(struct ceph_msgpool *pool, int type, int front_len, int size, bool blocking, const char *name) { dout("msgpool %s init\n", name); + pool->type = type; pool->front_len = front_len; pool->pool = mempool_create(size, msgpool_alloc, msgpool_free, pool); if (!pool->pool) @@ -61,7 +62,7 @@ struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool, WARN_ON(1); /* try to alloc a fresh message */ - return ceph_msg_new(0, front_len, GFP_NOFS, false); + return ceph_msg_new(pool->type, front_len, GFP_NOFS, false); } msg = mempool_alloc(pool->pool, GFP_NOFS); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 474a52d9b4a..408ca51ffcf 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -242,6 +242,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, } ceph_pagelist_init(req->r_trail); } + /* create request message; allow space for oid */ msg_size += MAX_OBJ_NAME_SIZE; if (snapc) @@ -255,7 +256,6 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, return NULL; } - msg->hdr.type = cpu_to_le16(CEPH_MSG_OSD_OP); memset(msg->front.iov_base, 0, msg->front.iov_len); req->r_request = msg; @@ -1837,11 +1837,12 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client) if (!osdc->req_mempool) goto out; - err = ceph_msgpool_init(&osdc->msgpool_op, OSD_OP_FRONT_LEN, 10, true, + err = ceph_msgpool_init(&osdc->msgpool_op, CEPH_MSG_OSD_OP, + OSD_OP_FRONT_LEN, 10, true, "osd_op"); if (err < 0) goto out_mempool; - err = ceph_msgpool_init(&osdc->msgpool_op_reply, + err = ceph_msgpool_init(&osdc->msgpool_op_reply, CEPH_MSG_OSD_OPREPLY, OSD_OPREPLY_FRONT_LEN, 10, true, "osd_op_reply"); if (err < 0) From 59d02721bb2838893596d5617659fe907dd45518 Mon Sep 17 00:00:00 2001 From: Guanjun He Date: Sun, 8 Jul 2012 19:50:33 -0700 Subject: [PATCH 1583/2357] libceph: prevent the race of incoming work during teardown (cherry picked from commit a2a3258417eb6a1799cf893350771428875a8287) Add an atomic variable 'stopping' as flag in struct ceph_messenger, set this flag to 1 in function ceph_destroy_client(), and add the condition code in function ceph_data_ready() to test the flag value, if true(1), just return. Signed-off-by: Guanjun He Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 1 + net/ceph/ceph_common.c | 2 ++ net/ceph/messenger.c | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index ec22abd51fa..de39cda6bd5 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -50,6 +50,7 @@ struct ceph_messenger { struct ceph_entity_inst inst; /* my name+address */ struct ceph_entity_addr my_enc_addr; + atomic_t stopping; bool nocrc; /* diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index c815f31a1a3..52fe52cde60 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -495,6 +495,8 @@ void ceph_destroy_client(struct ceph_client *client) { dout("destroy_client %p\n", client); + atomic_set(&client->msgr.stopping, 1); + /* unmount */ ceph_osdc_stop(&client->osdc); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 866645fa857..edd51321ae1 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -254,6 +254,9 @@ static void con_sock_state_closed(struct ceph_connection *con) static void ceph_sock_data_ready(struct sock *sk, int count_unused) { struct ceph_connection *con = sk->sk_user_data; + if (atomic_read(&con->msgr->stopping)) { + return; + } if (sk->sk_state != TCP_CLOSE_WAIT) { dout("%s on %p state = %lu, queueing work\n", __func__, @@ -2413,6 +2416,8 @@ void ceph_messenger_init(struct ceph_messenger *msgr, encode_my_addr(msgr); msgr->nocrc = nocrc; + atomic_set(&msgr->stopping, 0); + dout("%s %p\n", __func__, msgr); } EXPORT_SYMBOL(ceph_messenger_init); From b3fd00b73452353444c768b19bb175ec95410c8f Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 16:24:21 -0700 Subject: [PATCH 1584/2357] libceph: report socket read/write error message (cherry picked from commit 3a140a0d5c4b9e35373b016e41dfc85f1e526bdb) We need to set error_msg to something useful before calling ceph_fault(); do so here for try_{read,write}(). This is more informative than libceph: osd0 192.168.106.220:6801 (null) Signed-off-by: Sage Weil Reviewed-by: Alex Elder Reviewed-by: Yehuda Sadeh Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index edd51321ae1..96d9c9960aa 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2287,14 +2287,18 @@ static void con_work(struct work_struct *work) ret = try_read(con); if (ret == -EAGAIN) goto restart; - if (ret < 0) + if (ret < 0) { + con->error_msg = "socket error on read"; goto fault; + } ret = try_write(con); if (ret == -EAGAIN) goto restart; - if (ret < 0) + if (ret < 0) { + con->error_msg = "socket error on write"; goto fault; + } done: mutex_unlock(&con->mutex); From 7621822a64ee40c0ab4181e7281ef06f241782cb Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 16:24:37 -0700 Subject: [PATCH 1585/2357] libceph: fix mutex coverage for ceph_con_close (cherry picked from commit 8c50c817566dfa4581f82373aac39f3e608a7dc8) Hold the mutex while twiddling all of the state bits to avoid possible races. While we're here, make not of why we cannot close the socket directly. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Reviewed-by: Yehuda Sadeh Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 96d9c9960aa..7ccecf3915a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -503,6 +503,7 @@ static void reset_connection(struct ceph_connection *con) */ void ceph_con_close(struct ceph_connection *con) { + mutex_lock(&con->mutex); dout("con_close %p peer %s\n", con, ceph_pr_addr(&con->peer_addr.in_addr)); clear_bit(NEGOTIATING, &con->state); @@ -515,11 +516,16 @@ void ceph_con_close(struct ceph_connection *con) clear_bit(KEEPALIVE_PENDING, &con->flags); clear_bit(WRITE_PENDING, &con->flags); - mutex_lock(&con->mutex); reset_connection(con); con->peer_global_seq = 0; cancel_delayed_work(&con->work); mutex_unlock(&con->mutex); + + /* + * We cannot close the socket directly from here because the + * work threads use it without holding the mutex. Instead, let + * con_work() do it. + */ queue_con(con); } EXPORT_SYMBOL(ceph_con_close); From d43841ef768a78f2cbc7e819f1a2838a4838f566 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 16:19:28 -0700 Subject: [PATCH 1586/2357] libceph: resubmit linger ops when pg mapping changes (cherry picked from commit 6194ea895e447fdf4adfd23f67873a32bf4f15ae) The linger op registration (i.e., watch) modifies the object state. As such, the OSD will reply with success if it has already applied without doing the associated side-effects (setting up the watch session state). If we lose the ACK and resubmit, we will see success but the watch will not be correctly registered and we won't get notifies. To fix this, always resubmit the linger op with a new tid. We accomplish this by re-registering as a linger (i.e., 'registered') if we are not yet registered. Then the second loop will treat this just like a normal case of re-registering. This mirrors a similar fix on the userland ceph.git, commit 5dd68b95, and ceph bug #2796. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Reviewed-by: Yehuda Sadeh Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 408ca51ffcf..56fd974b765 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -888,7 +888,9 @@ static void __register_linger_request(struct ceph_osd_client *osdc, { dout("__register_linger_request %p\n", req); list_add_tail(&req->r_linger_item, &osdc->req_linger); - list_add_tail(&req->r_linger_osd, &req->r_osd->o_linger_requests); + if (req->r_osd) + list_add_tail(&req->r_linger_osd, + &req->r_osd->o_linger_requests); } static void __unregister_linger_request(struct ceph_osd_client *osdc, @@ -1302,8 +1304,9 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) dout("kick_requests %s\n", force_resend ? " (force resend)" : ""); mutex_lock(&osdc->request_mutex); - for (p = rb_first(&osdc->requests); p; p = rb_next(p)) { + for (p = rb_first(&osdc->requests); p; ) { req = rb_entry(p, struct ceph_osd_request, r_node); + p = rb_next(p); err = __map_request(osdc, req, force_resend); if (err < 0) continue; /* error */ @@ -1311,10 +1314,23 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) dout("%p tid %llu maps to no osd\n", req, req->r_tid); needmap++; /* request a newer map */ } else if (err > 0) { - dout("%p tid %llu requeued on osd%d\n", req, req->r_tid, - req->r_osd ? req->r_osd->o_osd : -1); - if (!req->r_linger) + if (!req->r_linger) { + dout("%p tid %llu requeued on osd%d\n", req, + req->r_tid, + req->r_osd ? req->r_osd->o_osd : -1); req->r_flags |= CEPH_OSD_FLAG_RETRY; + } + } + if (req->r_linger && list_empty(&req->r_linger_item)) { + /* + * register as a linger so that we will + * re-submit below and get a new tid + */ + dout("%p tid %llu restart on osd%d\n", + req, req->r_tid, + req->r_osd ? req->r_osd->o_osd : -1); + __register_linger_request(osdc, req); + __unregister_request(osdc, req); } } From 175c4c20d29322b9e882c052025e72644ca00e2d Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 16:20:25 -0700 Subject: [PATCH 1587/2357] libceph: (re)initialize bio_iter on start of message receive (cherry picked from commit a4107026976f06c9a6ce8cc84a763564ee39d901) Previously, we were opportunistically initializing the bio_iter if it appeared to be uninitialized in the middle of the read path. The problem is that a sequence like: - start reading message - initialize bio_iter - read half a message - messenger fault, reconnect - restart reading message - ** bio_iter now non-NULL, not reinitialized ** - read past end of bio, crash Instead, initialize the bio_iter unconditionally when we allocate/claim the message for read. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Reviewed-by: Yehuda Sadeh Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 7ccecf3915a..c5df88364f2 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1872,6 +1872,11 @@ static int read_partial_message(struct ceph_connection *con) else con->in_msg_pos.page_pos = 0; con->in_msg_pos.data_pos = 0; + +#ifdef CONFIG_BLOCK + if (m->bio) + init_bio_iter(m->bio, &m->bio_iter, &m->bio_seg); +#endif } /* front */ @@ -1888,10 +1893,6 @@ static int read_partial_message(struct ceph_connection *con) if (ret <= 0) return ret; } -#ifdef CONFIG_BLOCK - if (m->bio && !m->bio_iter) - init_bio_iter(m->bio, &m->bio_iter, &m->bio_seg); -#endif /* (page) data */ while (con->in_msg_pos.data_pos < data_len) { @@ -1902,7 +1903,7 @@ static int read_partial_message(struct ceph_connection *con) return ret; #ifdef CONFIG_BLOCK } else if (m->bio) { - + BUG_ON(!m->bio_iter); ret = read_partial_message_bio(con, &m->bio_iter, &m->bio_seg, data_len, do_datacrc); From eea8ed97626254429d4679c567035effdf9983a8 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 16:21:40 -0700 Subject: [PATCH 1588/2357] libceph: protect ceph_con_open() with mutex (cherry picked from commit 5469155f2bc83bb2c88b0a0370c3d54d87eed06e) Take the con mutex while we are initiating a ceph open. This is necessary because the may have previously been in use and then closed, which could result in a racing workqueue running con_work(). Signed-off-by: Sage Weil Reviewed-by: Yehuda Sadeh Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index c5df88364f2..b59e64a7b24 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -537,6 +537,7 @@ void ceph_con_open(struct ceph_connection *con, __u8 entity_type, __u64 entity_num, struct ceph_entity_addr *addr) { + mutex_lock(&con->mutex); dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr)); set_bit(OPENING, &con->state); WARN_ON(!test_and_clear_bit(CLOSED, &con->state)); @@ -546,6 +547,7 @@ void ceph_con_open(struct ceph_connection *con, memcpy(&con->peer_addr, addr, sizeof(*addr)); con->delay = 0; /* reset backoff memory */ + mutex_unlock(&con->mutex); queue_con(con); } EXPORT_SYMBOL(ceph_con_open); From ed447f04ee3240371aa8a199588107fd521240d3 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 16:22:05 -0700 Subject: [PATCH 1589/2357] libceph: reset connection retry on successfully negotiation (cherry picked from commit 85effe183dd45854d1ad1a370b88cddb403c4c91) We exponentially back off when we encounter connection errors. If several errors accumulate, we will eventually wait ages before even trying to reconnect. Fix this by resetting the backoff counter after a successful negotiation/ connection with the remote node. Fixes ceph issue #2802. Signed-off-by: Sage Weil Reviewed-by: Yehuda Sadeh Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index b59e64a7b24..9da18929c58 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1629,6 +1629,8 @@ static int process_connect(struct ceph_connection *con) if (con->in_reply.flags & CEPH_MSG_CONNECT_LOSSY) set_bit(LOSSYTX, &con->flags); + con->delay = 0; /* reset backoff memory */ + prepare_read_tag(con); break; From da6a81eb5a2671f12551953d1843a0f53416d185 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 20 Jul 2012 15:22:53 -0700 Subject: [PATCH 1590/2357] libceph: fix fault locking; close socket on lossy fault (cherry picked from commit 3b5ede07b55b52c3be27749d183d87257d032065) If we fault on a lossy connection, we should still close the socket immediately, and do so under the con mutex. We should also take the con mutex before printing out the state bits in the debug output. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 9da18929c58..d769a73e080 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2330,22 +2330,23 @@ static void con_work(struct work_struct *work) */ static void ceph_fault(struct ceph_connection *con) { + mutex_lock(&con->mutex); + pr_err("%s%lld %s %s\n", ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr), con->error_msg); dout("fault %p state %lu to peer %s\n", con, con->state, ceph_pr_addr(&con->peer_addr.in_addr)); - if (test_bit(LOSSYTX, &con->flags)) { - dout("fault on LOSSYTX channel\n"); - goto out; - } - - mutex_lock(&con->mutex); if (test_bit(CLOSED, &con->state)) goto out_unlock; con_close_socket(con); + if (test_bit(LOSSYTX, &con->flags)) { + dout("fault on LOSSYTX channel\n"); + goto out_unlock; + } + if (con->in_msg) { BUG_ON(con->in_msg->con != con); con->in_msg->con = NULL; @@ -2392,7 +2393,6 @@ static void ceph_fault(struct ceph_connection *con) out_unlock: mutex_unlock(&con->mutex); -out: /* * in case we faulted due to authentication, invalidate our * current tickets so that we can get new ones. From 67c6fc1932a705f61f98d8092375622b8dffea6a Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 20 Jul 2012 15:33:04 -0700 Subject: [PATCH 1591/2357] libceph: move msgr clear_standby under con mutex protection (cherry picked from commit 00650931e52e97fe64096bec167f5a6780dfd94a) Avoid dropping and retaking con->mutex in the ceph_con_send() case by leaving locking up to the caller. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index d769a73e080..14d24b778ca 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2441,12 +2441,10 @@ static void clear_standby(struct ceph_connection *con) { /* come back from STANDBY? */ if (test_and_clear_bit(STANDBY, &con->state)) { - mutex_lock(&con->mutex); dout("clear_standby %p and ++connect_seq\n", con); con->connect_seq++; WARN_ON(test_bit(WRITE_PENDING, &con->flags)); WARN_ON(test_bit(KEEPALIVE_PENDING, &con->flags)); - mutex_unlock(&con->mutex); } } @@ -2483,11 +2481,12 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg) le32_to_cpu(msg->hdr.front_len), le32_to_cpu(msg->hdr.middle_len), le32_to_cpu(msg->hdr.data_len)); + + clear_standby(con); mutex_unlock(&con->mutex); /* if there wasn't anything waiting to send before, queue * new work */ - clear_standby(con); if (test_and_set_bit(WRITE_PENDING, &con->flags) == 0) queue_con(con); } @@ -2574,7 +2573,9 @@ void ceph_msg_revoke_incoming(struct ceph_msg *msg) void ceph_con_keepalive(struct ceph_connection *con) { dout("con_keepalive %p\n", con); + mutex_lock(&con->mutex); clear_standby(con); + mutex_unlock(&con->mutex); if (test_and_set_bit(KEEPALIVE_PENDING, &con->flags) == 0 && test_and_set_bit(WRITE_PENDING, &con->flags) == 0) queue_con(con); From 5d0f354b3183d005024d43b567335701d928995a Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 20 Jul 2012 15:34:04 -0700 Subject: [PATCH 1592/2357] libceph: move ceph_con_send() closed check under the con mutex (cherry picked from commit a59b55a602b6c741052d79c1e3643f8440cddd27) Take the con mutex before checking whether the connection is closed to avoid racing with someone else closing it. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 14d24b778ca..cb871fc7286 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2453,22 +2453,20 @@ static void clear_standby(struct ceph_connection *con) */ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg) { - if (test_bit(CLOSED, &con->state)) { - dout("con_send %p closed, dropping %p\n", con, msg); - ceph_msg_put(msg); - return; - } - /* set src+dst */ msg->hdr.src = con->msgr->inst.name; - BUG_ON(msg->front.iov_len != le32_to_cpu(msg->hdr.front_len)); - msg->needs_out_seq = true; - /* queue */ mutex_lock(&con->mutex); + if (test_bit(CLOSED, &con->state)) { + dout("con_send %p closed, dropping %p\n", con, msg); + ceph_msg_put(msg); + mutex_unlock(&con->mutex); + return; + } + BUG_ON(msg->con != NULL); msg->con = con->ops->get(con); BUG_ON(msg->con == NULL); From 1c5b33b852ab372d4538821db998561d5e4d7212 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 20 Jul 2012 15:40:04 -0700 Subject: [PATCH 1593/2357] libceph: drop gratuitous socket close calls in con_work (cherry picked from commit 2e8cb10063820af7ed7638e3fd9013eee21266e7) If the state is CLOSED or OPENING, we shouldn't have a socket. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index cb871fc7286..7bd757cb01a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2284,15 +2284,15 @@ static void con_work(struct work_struct *work) dout("con_work %p STANDBY\n", con); goto done; } - if (test_bit(CLOSED, &con->state)) { /* e.g. if we are replaced */ - dout("con_work CLOSED\n"); - con_close_socket(con); + if (test_bit(CLOSED, &con->state)) { + dout("con_work %p CLOSED\n", con); + BUG_ON(con->sock); goto done; } if (test_and_clear_bit(OPENING, &con->state)) { /* reopen w/ new peer */ dout("con_work OPENING\n"); - con_close_socket(con); + BUG_ON(con->sock); } ret = try_read(con); From 3b5a9ead0b4845aaa7e80fcd6166f2c6740a1c6f Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 20 Jul 2012 16:45:49 -0700 Subject: [PATCH 1594/2357] libceph: close socket directly from ceph_con_close() (cherry picked from commit ee76e0736db8455e3b11827d6899bd2a4e1d0584) It is simpler to do this immediately, since we already hold the con mutex. It also avoids the need to deal with a not-quite-CLOSED socket in con_work. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 7bd757cb01a..49f78ff6247 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -519,14 +519,8 @@ void ceph_con_close(struct ceph_connection *con) reset_connection(con); con->peer_global_seq = 0; cancel_delayed_work(&con->work); + con_close_socket(con); mutex_unlock(&con->mutex); - - /* - * We cannot close the socket directly from here because the - * work threads use it without holding the mutex. Instead, let - * con_work() do it. - */ - queue_con(con); } EXPORT_SYMBOL(ceph_con_close); From cb9f8855591613dff0909c99d46a29e10eb39b25 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 20 Jul 2012 17:19:43 -0700 Subject: [PATCH 1595/2357] libceph: drop unnecessary CLOSED check in socket state change callback (cherry picked from commit d7353dd5aaf22ed611fbcd0d4a4a12fb30659290) If we are CLOSED, the socket is closed and we won't get these. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 49f78ff6247..7df72fff886 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -296,9 +296,6 @@ static void ceph_sock_state_change(struct sock *sk) dout("%s %p state = %lu sk_state = %u\n", __func__, con, con->state, sk->sk_state); - if (test_bit(CLOSED, &con->state)) - return; - switch (sk->sk_state) { case TCP_CLOSE: dout("%s TCP_CLOSE\n", __func__); From 265fb7c177f9db75d628b3479b6223c1c8110e67 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 20 Jul 2012 17:24:40 -0700 Subject: [PATCH 1596/2357] libceph: replace connection state bits with states (cherry picked from commit 8dacc7da69a491c515851e68de6036f21b5663ce) Use a simple set of 6 enumerated values for the socket states (CON_STATE_*) and use those instead of the state bits. All of the con->state checks are now under the protection of the con mutex, so this is safe. It also simplifies many of the state checks because we can check for anything other than the expected state instead of various bits for races we can think of. This appears to hold up well to stress testing both with and without socket failure injection on the server side. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 12 --- net/ceph/messenger.c | 130 +++++++++++++++++---------------- 2 files changed, 68 insertions(+), 74 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index de39cda6bd5..dc684f6bc55 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -116,18 +116,6 @@ struct ceph_msg_pos { #define SOCK_CLOSED 11 /* socket state changed to closed */ #define BACKOFF 15 -/* - * ceph_connection states - */ -#define CONNECTING 1 -#define NEGOTIATING 2 -#define CONNECTED 5 -#define STANDBY 8 /* no outgoing messages, socket closed. we keep - * the ceph_connection around to maintain shared - * state with the peer. */ -#define CLOSED 10 /* we've closed the connection */ -#define OPENING 13 /* open connection w/ (possibly new) peer */ - /* * A single connection with another host. * diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 7df72fff886..8c239390c21 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -77,6 +77,17 @@ #define CON_SOCK_STATE_CONNECTED 3 /* -> CLOSING or -> CLOSED */ #define CON_SOCK_STATE_CLOSING 4 /* -> CLOSED */ +/* + * connection states + */ +#define CON_STATE_CLOSED 1 /* -> PREOPEN */ +#define CON_STATE_PREOPEN 2 /* -> CONNECTING, CLOSED */ +#define CON_STATE_CONNECTING 3 /* -> NEGOTIATING, CLOSED */ +#define CON_STATE_NEGOTIATING 4 /* -> OPEN, CLOSED */ +#define CON_STATE_OPEN 5 /* -> STANDBY, CLOSED */ +#define CON_STATE_STANDBY 6 /* -> PREOPEN, CLOSED */ + + /* static tag bytes (protocol control messages) */ static char tag_msg = CEPH_MSGR_TAG_MSG; static char tag_ack = CEPH_MSGR_TAG_ACK; @@ -503,11 +514,7 @@ void ceph_con_close(struct ceph_connection *con) mutex_lock(&con->mutex); dout("con_close %p peer %s\n", con, ceph_pr_addr(&con->peer_addr.in_addr)); - clear_bit(NEGOTIATING, &con->state); - clear_bit(CONNECTING, &con->state); - clear_bit(CONNECTED, &con->state); - clear_bit(STANDBY, &con->state); /* avoid connect_seq bump */ - set_bit(CLOSED, &con->state); + con->state = CON_STATE_CLOSED; clear_bit(LOSSYTX, &con->flags); /* so we retry next connect */ clear_bit(KEEPALIVE_PENDING, &con->flags); @@ -530,8 +537,9 @@ void ceph_con_open(struct ceph_connection *con, { mutex_lock(&con->mutex); dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr)); - set_bit(OPENING, &con->state); - WARN_ON(!test_and_clear_bit(CLOSED, &con->state)); + + BUG_ON(con->state != CON_STATE_CLOSED); + con->state = CON_STATE_PREOPEN; con->peer_name.type = (__u8) entity_type; con->peer_name.num = cpu_to_le64(entity_num); @@ -571,7 +579,7 @@ void ceph_con_init(struct ceph_connection *con, void *private, INIT_LIST_HEAD(&con->out_sent); INIT_DELAYED_WORK(&con->work, con_work); - set_bit(CLOSED, &con->state); + con->state = CON_STATE_CLOSED; } EXPORT_SYMBOL(ceph_con_init); @@ -809,27 +817,21 @@ static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection if (!con->ops->get_authorizer) { con->out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; con->out_connect.authorizer_len = 0; - return NULL; } /* Can't hold the mutex while getting authorizer */ - mutex_unlock(&con->mutex); - auth = con->ops->get_authorizer(con, auth_proto, con->auth_retry); - mutex_lock(&con->mutex); if (IS_ERR(auth)) return auth; - if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->flags)) + if (con->state != CON_STATE_NEGOTIATING) return ERR_PTR(-EAGAIN); con->auth_reply_buf = auth->authorizer_reply_buf; con->auth_reply_buf_len = auth->authorizer_reply_buf_len; - - return auth; } @@ -1484,7 +1486,8 @@ static int process_banner(struct ceph_connection *con) static void fail_protocol(struct ceph_connection *con) { reset_connection(con); - set_bit(CLOSED, &con->state); /* in case there's queued work */ + BUG_ON(con->state != CON_STATE_NEGOTIATING); + con->state = CON_STATE_CLOSED; } static int process_connect(struct ceph_connection *con) @@ -1558,8 +1561,7 @@ static int process_connect(struct ceph_connection *con) if (con->ops->peer_reset) con->ops->peer_reset(con); mutex_lock(&con->mutex); - if (test_bit(CLOSED, &con->state) || - test_bit(OPENING, &con->state)) + if (con->state != CON_STATE_NEGOTIATING) return -EAGAIN; break; @@ -1605,8 +1607,10 @@ static int process_connect(struct ceph_connection *con) fail_protocol(con); return -1; } - clear_bit(NEGOTIATING, &con->state); - set_bit(CONNECTED, &con->state); + + BUG_ON(con->state != CON_STATE_NEGOTIATING); + con->state = CON_STATE_OPEN; + con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq); con->connect_seq++; con->peer_features = server_feat; @@ -1994,8 +1998,9 @@ static int try_write(struct ceph_connection *con) dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes); /* open the socket first? */ - if (con->sock == NULL) { - set_bit(CONNECTING, &con->state); + if (con->state == CON_STATE_PREOPEN) { + BUG_ON(con->sock); + con->state = CON_STATE_CONNECTING; con_out_kvec_reset(con); prepare_write_banner(con); @@ -2046,8 +2051,7 @@ static int try_write(struct ceph_connection *con) } do_next: - if (!test_bit(CONNECTING, &con->state) && - !test_bit(NEGOTIATING, &con->state)) { + if (con->state == CON_STATE_OPEN) { /* is anything else pending? */ if (!list_empty(&con->out_queue)) { prepare_write_message(con); @@ -2081,29 +2085,19 @@ static int try_read(struct ceph_connection *con) { int ret = -1; - if (!con->sock) - return 0; - - if (test_bit(STANDBY, &con->state)) +more: + dout("try_read start on %p state %lu\n", con, con->state); + if (con->state != CON_STATE_CONNECTING && + con->state != CON_STATE_NEGOTIATING && + con->state != CON_STATE_OPEN) return 0; - dout("try_read start on %p\n", con); + BUG_ON(!con->sock); -more: dout("try_read tag %d in_base_pos %d\n", (int)con->in_tag, con->in_base_pos); - /* - * process_connect and process_message drop and re-take - * con->mutex. make sure we handle a racing close or reopen. - */ - if (test_bit(CLOSED, &con->state) || - test_bit(OPENING, &con->state)) { - ret = -EAGAIN; - goto out; - } - - if (test_bit(CONNECTING, &con->state)) { + if (con->state == CON_STATE_CONNECTING) { dout("try_read connecting\n"); ret = read_partial_banner(con); if (ret <= 0) @@ -2112,8 +2106,8 @@ static int try_read(struct ceph_connection *con) if (ret < 0) goto out; - clear_bit(CONNECTING, &con->state); - set_bit(NEGOTIATING, &con->state); + BUG_ON(con->state != CON_STATE_CONNECTING); + con->state = CON_STATE_NEGOTIATING; /* Banner is good, exchange connection info */ ret = prepare_write_connect(con); @@ -2125,7 +2119,7 @@ static int try_read(struct ceph_connection *con) goto out; } - if (test_bit(NEGOTIATING, &con->state)) { + if (con->state == CON_STATE_NEGOTIATING) { dout("try_read negotiating\n"); ret = read_partial_connect(con); if (ret <= 0) @@ -2136,6 +2130,8 @@ static int try_read(struct ceph_connection *con) goto more; } + BUG_ON(con->state != CON_STATE_OPEN); + if (con->in_base_pos < 0) { /* * skipping + discarding content. @@ -2169,8 +2165,8 @@ static int try_read(struct ceph_connection *con) prepare_read_ack(con); break; case CEPH_MSGR_TAG_CLOSE: - clear_bit(CONNECTED, &con->state); - set_bit(CLOSED, &con->state); /* fixme */ + con_close_socket(con); + con->state = CON_STATE_CLOSED; goto out; default: goto bad_tag; @@ -2246,14 +2242,21 @@ static void con_work(struct work_struct *work) mutex_lock(&con->mutex); restart: if (test_and_clear_bit(SOCK_CLOSED, &con->flags)) { - if (test_and_clear_bit(CONNECTED, &con->state)) - con->error_msg = "socket closed"; - else if (test_and_clear_bit(NEGOTIATING, &con->state)) - con->error_msg = "negotiation failed"; - else if (test_and_clear_bit(CONNECTING, &con->state)) + switch (con->state) { + case CON_STATE_CONNECTING: con->error_msg = "connection failed"; - else + break; + case CON_STATE_NEGOTIATING: + con->error_msg = "negotiation failed"; + break; + case CON_STATE_OPEN: + con->error_msg = "socket closed"; + break; + default: + dout("unrecognized con state %d\n", (int)con->state); con->error_msg = "unrecognized con state"; + BUG(); + } goto fault; } @@ -2271,17 +2274,16 @@ static void con_work(struct work_struct *work) } } - if (test_bit(STANDBY, &con->state)) { + if (con->state == CON_STATE_STANDBY) { dout("con_work %p STANDBY\n", con); goto done; } - if (test_bit(CLOSED, &con->state)) { + if (con->state == CON_STATE_CLOSED) { dout("con_work %p CLOSED\n", con); BUG_ON(con->sock); goto done; } - if (test_and_clear_bit(OPENING, &con->state)) { - /* reopen w/ new peer */ + if (con->state == CON_STATE_PREOPEN) { dout("con_work OPENING\n"); BUG_ON(con->sock); } @@ -2328,13 +2330,15 @@ static void ceph_fault(struct ceph_connection *con) dout("fault %p state %lu to peer %s\n", con, con->state, ceph_pr_addr(&con->peer_addr.in_addr)); - if (test_bit(CLOSED, &con->state)) - goto out_unlock; + BUG_ON(con->state != CON_STATE_CONNECTING && + con->state != CON_STATE_NEGOTIATING && + con->state != CON_STATE_OPEN); con_close_socket(con); if (test_bit(LOSSYTX, &con->flags)) { - dout("fault on LOSSYTX channel\n"); + dout("fault on LOSSYTX channel, marking CLOSED\n"); + con->state = CON_STATE_CLOSED; goto out_unlock; } @@ -2355,9 +2359,10 @@ static void ceph_fault(struct ceph_connection *con) !test_bit(KEEPALIVE_PENDING, &con->flags)) { dout("fault %p setting STANDBY clearing WRITE_PENDING\n", con); clear_bit(WRITE_PENDING, &con->flags); - set_bit(STANDBY, &con->state); + con->state = CON_STATE_STANDBY; } else { /* retry after a delay. */ + con->state = CON_STATE_PREOPEN; if (con->delay == 0) con->delay = BASE_DELAY_INTERVAL; else if (con->delay < MAX_DELAY_INTERVAL) @@ -2431,8 +2436,9 @@ EXPORT_SYMBOL(ceph_messenger_init); static void clear_standby(struct ceph_connection *con) { /* come back from STANDBY? */ - if (test_and_clear_bit(STANDBY, &con->state)) { + if (con->state == CON_STATE_STANDBY) { dout("clear_standby %p and ++connect_seq\n", con); + con->state = CON_STATE_PREOPEN; con->connect_seq++; WARN_ON(test_bit(WRITE_PENDING, &con->flags)); WARN_ON(test_bit(KEEPALIVE_PENDING, &con->flags)); @@ -2451,7 +2457,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg) mutex_lock(&con->mutex); - if (test_bit(CLOSED, &con->state)) { + if (con->state == CON_STATE_CLOSED) { dout("con_send %p closed, dropping %p\n", con, msg); ceph_msg_put(msg); mutex_unlock(&con->mutex); From 63c1362476141f4fb340e8236d41674be9fc1983 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 20 Jul 2012 17:29:55 -0700 Subject: [PATCH 1597/2357] libceph: clean up con flags (cherry picked from commit 4a8616920860920abaa51193146fe36b38ef09aa) Rename flags with CON_FLAG prefix, move the definitions into the c file, and (better) document their meaning. Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 10 ------ net/ceph/messenger.c | 62 ++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index dc684f6bc55..98442411c58 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -106,16 +106,6 @@ struct ceph_msg_pos { #define BASE_DELAY_INTERVAL (HZ/2) #define MAX_DELAY_INTERVAL (5 * 60 * HZ) -/* - * ceph_connection flag bits - */ - -#define LOSSYTX 0 /* we can close channel or drop messages on errors */ -#define KEEPALIVE_PENDING 3 -#define WRITE_PENDING 4 /* we have data ready to send */ -#define SOCK_CLOSED 11 /* socket state changed to closed */ -#define BACKOFF 15 - /* * A single connection with another host. * diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 8c239390c21..ca703f131e9 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -87,6 +87,15 @@ #define CON_STATE_OPEN 5 /* -> STANDBY, CLOSED */ #define CON_STATE_STANDBY 6 /* -> PREOPEN, CLOSED */ +/* + * ceph_connection flag bits + */ +#define CON_FLAG_LOSSYTX 0 /* we can close channel or drop + * messages on errors */ +#define CON_FLAG_KEEPALIVE_PENDING 1 /* we need to send a keepalive */ +#define CON_FLAG_WRITE_PENDING 2 /* we have data ready to send */ +#define CON_FLAG_SOCK_CLOSED 3 /* socket state changed to closed */ +#define CON_FLAG_BACKOFF 4 /* need to retry queuing delayed work */ /* static tag bytes (protocol control messages) */ static char tag_msg = CEPH_MSGR_TAG_MSG; @@ -288,7 +297,7 @@ static void ceph_sock_write_space(struct sock *sk) * buffer. See net/ipv4/tcp_input.c:tcp_check_space() * and net/core/stream.c:sk_stream_write_space(). */ - if (test_bit(WRITE_PENDING, &con->flags)) { + if (test_bit(CON_FLAG_WRITE_PENDING, &con->flags)) { if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { dout("%s %p queueing write work\n", __func__, con); clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); @@ -313,7 +322,7 @@ static void ceph_sock_state_change(struct sock *sk) case TCP_CLOSE_WAIT: dout("%s TCP_CLOSE_WAIT\n", __func__); con_sock_state_closing(con); - set_bit(SOCK_CLOSED, &con->flags); + set_bit(CON_FLAG_SOCK_CLOSED, &con->flags); queue_con(con); break; case TCP_ESTABLISHED: @@ -449,12 +458,12 @@ static int con_close_socket(struct ceph_connection *con) con->sock = NULL; /* - * Forcibly clear the SOCK_CLOSE flag. It gets set + * Forcibly clear the SOCK_CLOSED flag. It gets set * independent of the connection mutex, and we could have * received a socket close event before we had the chance to * shut the socket down. */ - clear_bit(SOCK_CLOSED, &con->flags); + clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags); con_sock_state_closed(con); return rc; } @@ -516,9 +525,9 @@ void ceph_con_close(struct ceph_connection *con) ceph_pr_addr(&con->peer_addr.in_addr)); con->state = CON_STATE_CLOSED; - clear_bit(LOSSYTX, &con->flags); /* so we retry next connect */ - clear_bit(KEEPALIVE_PENDING, &con->flags); - clear_bit(WRITE_PENDING, &con->flags); + clear_bit(CON_FLAG_LOSSYTX, &con->flags); /* so we retry next connect */ + clear_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags); + clear_bit(CON_FLAG_WRITE_PENDING, &con->flags); reset_connection(con); con->peer_global_seq = 0; @@ -770,7 +779,7 @@ static void prepare_write_message(struct ceph_connection *con) /* no, queue up footer too and be done */ prepare_write_message_footer(con); - set_bit(WRITE_PENDING, &con->flags); + set_bit(CON_FLAG_WRITE_PENDING, &con->flags); } /* @@ -791,7 +800,7 @@ static void prepare_write_ack(struct ceph_connection *con) &con->out_temp_ack); con->out_more = 1; /* more will follow.. eventually.. */ - set_bit(WRITE_PENDING, &con->flags); + set_bit(CON_FLAG_WRITE_PENDING, &con->flags); } /* @@ -802,7 +811,7 @@ static void prepare_write_keepalive(struct ceph_connection *con) dout("prepare_write_keepalive %p\n", con); con_out_kvec_reset(con); con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive); - set_bit(WRITE_PENDING, &con->flags); + set_bit(CON_FLAG_WRITE_PENDING, &con->flags); } /* @@ -845,7 +854,7 @@ static void prepare_write_banner(struct ceph_connection *con) &con->msgr->my_enc_addr); con->out_more = 0; - set_bit(WRITE_PENDING, &con->flags); + set_bit(CON_FLAG_WRITE_PENDING, &con->flags); } static int prepare_write_connect(struct ceph_connection *con) @@ -896,7 +905,7 @@ static int prepare_write_connect(struct ceph_connection *con) auth->authorizer_buf); con->out_more = 0; - set_bit(WRITE_PENDING, &con->flags); + set_bit(CON_FLAG_WRITE_PENDING, &con->flags); return 0; } @@ -1622,7 +1631,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->in_reply.connect_seq)); if (con->in_reply.flags & CEPH_MSG_CONNECT_LOSSY) - set_bit(LOSSYTX, &con->flags); + set_bit(CON_FLAG_LOSSYTX, &con->flags); con->delay = 0; /* reset backoff memory */ @@ -2061,14 +2070,15 @@ static int try_write(struct ceph_connection *con) prepare_write_ack(con); goto more; } - if (test_and_clear_bit(KEEPALIVE_PENDING, &con->flags)) { + if (test_and_clear_bit(CON_FLAG_KEEPALIVE_PENDING, + &con->flags)) { prepare_write_keepalive(con); goto more; } } /* Nothing to do! */ - clear_bit(WRITE_PENDING, &con->flags); + clear_bit(CON_FLAG_WRITE_PENDING, &con->flags); dout("try_write nothing else to write.\n"); ret = 0; out: @@ -2241,7 +2251,7 @@ static void con_work(struct work_struct *work) mutex_lock(&con->mutex); restart: - if (test_and_clear_bit(SOCK_CLOSED, &con->flags)) { + if (test_and_clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags)) { switch (con->state) { case CON_STATE_CONNECTING: con->error_msg = "connection failed"; @@ -2260,7 +2270,7 @@ static void con_work(struct work_struct *work) goto fault; } - if (test_and_clear_bit(BACKOFF, &con->flags)) { + if (test_and_clear_bit(CON_FLAG_BACKOFF, &con->flags)) { dout("con_work %p backing off\n", con); if (queue_delayed_work(ceph_msgr_wq, &con->work, round_jiffies_relative(con->delay))) { @@ -2336,7 +2346,7 @@ static void ceph_fault(struct ceph_connection *con) con_close_socket(con); - if (test_bit(LOSSYTX, &con->flags)) { + if (test_bit(CON_FLAG_LOSSYTX, &con->flags)) { dout("fault on LOSSYTX channel, marking CLOSED\n"); con->state = CON_STATE_CLOSED; goto out_unlock; @@ -2356,9 +2366,9 @@ static void ceph_fault(struct ceph_connection *con) /* If there are no messages queued or keepalive pending, place * the connection in a STANDBY state */ if (list_empty(&con->out_queue) && - !test_bit(KEEPALIVE_PENDING, &con->flags)) { + !test_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags)) { dout("fault %p setting STANDBY clearing WRITE_PENDING\n", con); - clear_bit(WRITE_PENDING, &con->flags); + clear_bit(CON_FLAG_WRITE_PENDING, &con->flags); con->state = CON_STATE_STANDBY; } else { /* retry after a delay. */ @@ -2383,7 +2393,7 @@ static void ceph_fault(struct ceph_connection *con) * that when con_work restarts we schedule the * delay then. */ - set_bit(BACKOFF, &con->flags); + set_bit(CON_FLAG_BACKOFF, &con->flags); } } @@ -2440,8 +2450,8 @@ static void clear_standby(struct ceph_connection *con) dout("clear_standby %p and ++connect_seq\n", con); con->state = CON_STATE_PREOPEN; con->connect_seq++; - WARN_ON(test_bit(WRITE_PENDING, &con->flags)); - WARN_ON(test_bit(KEEPALIVE_PENDING, &con->flags)); + WARN_ON(test_bit(CON_FLAG_WRITE_PENDING, &con->flags)); + WARN_ON(test_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags)); } } @@ -2482,7 +2492,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg) /* if there wasn't anything waiting to send before, queue * new work */ - if (test_and_set_bit(WRITE_PENDING, &con->flags) == 0) + if (test_and_set_bit(CON_FLAG_WRITE_PENDING, &con->flags) == 0) queue_con(con); } EXPORT_SYMBOL(ceph_con_send); @@ -2571,8 +2581,8 @@ void ceph_con_keepalive(struct ceph_connection *con) mutex_lock(&con->mutex); clear_standby(con); mutex_unlock(&con->mutex); - if (test_and_set_bit(KEEPALIVE_PENDING, &con->flags) == 0 && - test_and_set_bit(WRITE_PENDING, &con->flags) == 0) + if (test_and_set_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags) == 0 && + test_and_set_bit(CON_FLAG_WRITE_PENDING, &con->flags) == 0) queue_con(con); } EXPORT_SYMBOL(ceph_con_keepalive); From 8992551d85934e0dc4683068612758831d1d4899 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 20 Jul 2012 17:30:40 -0700 Subject: [PATCH 1598/2357] libceph: clear all flags on con_close Signed-off-by: Sage Weil (cherry picked from commit 43c7427d100769451601b8a36988ac0528ce0124) --- net/ceph/messenger.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index ca703f131e9..e97bb59db1a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -528,6 +528,8 @@ void ceph_con_close(struct ceph_connection *con) clear_bit(CON_FLAG_LOSSYTX, &con->flags); /* so we retry next connect */ clear_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags); clear_bit(CON_FLAG_WRITE_PENDING, &con->flags); + clear_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags); + clear_bit(CON_FLAG_BACKOFF, &con->flags); reset_connection(con); con->peer_global_seq = 0; From 6cdaef1be27bc05ab4197b3ab4e3ee1d326cf04c Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 18:16:16 -0700 Subject: [PATCH 1599/2357] libceph: fix handling of immediate socket connect failure (cherry picked from commit 8007b8d626b49c34fb146ec16dc639d8b10c862f) If the connect() call immediately fails such that sock == NULL, we still need con_close_socket() to reset our socket state to CLOSED. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index e97bb59db1a..8edc0c14f1c 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -224,6 +224,8 @@ static void con_sock_state_init(struct ceph_connection *con) old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSED); if (WARN_ON(old_state != CON_SOCK_STATE_NEW)) printk("%s: unexpected old state %d\n", __func__, old_state); + dout("%s con %p sock %d -> %d\n", __func__, con, old_state, + CON_SOCK_STATE_CLOSED); } static void con_sock_state_connecting(struct ceph_connection *con) @@ -233,6 +235,8 @@ static void con_sock_state_connecting(struct ceph_connection *con) old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CONNECTING); if (WARN_ON(old_state != CON_SOCK_STATE_CLOSED)) printk("%s: unexpected old state %d\n", __func__, old_state); + dout("%s con %p sock %d -> %d\n", __func__, con, old_state, + CON_SOCK_STATE_CONNECTING); } static void con_sock_state_connected(struct ceph_connection *con) @@ -242,6 +246,8 @@ static void con_sock_state_connected(struct ceph_connection *con) old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CONNECTED); if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTING)) printk("%s: unexpected old state %d\n", __func__, old_state); + dout("%s con %p sock %d -> %d\n", __func__, con, old_state, + CON_SOCK_STATE_CONNECTED); } static void con_sock_state_closing(struct ceph_connection *con) @@ -253,6 +259,8 @@ static void con_sock_state_closing(struct ceph_connection *con) old_state != CON_SOCK_STATE_CONNECTED && old_state != CON_SOCK_STATE_CLOSING)) printk("%s: unexpected old state %d\n", __func__, old_state); + dout("%s con %p sock %d -> %d\n", __func__, con, old_state, + CON_SOCK_STATE_CLOSING); } static void con_sock_state_closed(struct ceph_connection *con) @@ -262,8 +270,11 @@ static void con_sock_state_closed(struct ceph_connection *con) old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSED); if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTED && old_state != CON_SOCK_STATE_CLOSING && - old_state != CON_SOCK_STATE_CONNECTING)) + old_state != CON_SOCK_STATE_CONNECTING && + old_state != CON_SOCK_STATE_CLOSED)) printk("%s: unexpected old state %d\n", __func__, old_state); + dout("%s con %p sock %d -> %d\n", __func__, con, old_state, + CON_SOCK_STATE_CLOSED); } /* @@ -448,14 +459,14 @@ static int ceph_tcp_sendpage(struct socket *sock, struct page *page, */ static int con_close_socket(struct ceph_connection *con) { - int rc; + int rc = 0; dout("con_close_socket on %p sock %p\n", con, con->sock); - if (!con->sock) - return 0; - rc = con->sock->ops->shutdown(con->sock, SHUT_RDWR); - sock_release(con->sock); - con->sock = NULL; + if (con->sock) { + rc = con->sock->ops->shutdown(con->sock, SHUT_RDWR); + sock_release(con->sock); + con->sock = NULL; + } /* * Forcibly clear the SOCK_CLOSED flag. It gets set @@ -464,6 +475,7 @@ static int con_close_socket(struct ceph_connection *con) * shut the socket down. */ clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags); + con_sock_state_closed(con); return rc; } From da75ae3c0d4c40587fa7583952b98072d811a7d2 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 18:16:40 -0700 Subject: [PATCH 1600/2357] libceph: revoke mon_client messages on session restart (cherry picked from commit 4f471e4a9c7db0256834e1b376ea50c82e345c3c) Revoke all mon_client messages when we shut down the old connection. This is mostly moot since we are re-using the same ceph_connection, but it is cleaner. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/mon_client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 9f00d6cd93e..275aec2f175 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -118,6 +118,9 @@ static void __close_session(struct ceph_mon_client *monc) { dout("__close_session closing mon%d\n", monc->cur_mon); ceph_msg_revoke(monc->m_auth); + ceph_msg_revoke_incoming(monc->m_auth_reply); + ceph_msg_revoke(monc->m_subscribe); + ceph_msg_revoke_incoming(monc->m_subscribe_ack); ceph_con_close(&monc->con); monc->cur_mon = -1; monc->pending_auth = 0; @@ -685,6 +688,7 @@ static void __resend_generic_request(struct ceph_mon_client *monc) for (p = rb_first(&monc->generic_request_tree); p; p = rb_next(p)) { req = rb_entry(p, struct ceph_mon_generic_request, node); ceph_msg_revoke(req->request); + ceph_msg_revoke_incoming(req->reply); ceph_con_send(&monc->con, ceph_msg_get(req->request)); } } From 900fbd910f53a417a6b0859bd2cde7ae48ac4bb2 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 18:16:56 -0700 Subject: [PATCH 1601/2357] libceph: verify state after retaking con lock after dispatch (cherry picked from commit 7b862e07b1a4d5c963d19027f10ea78085f27f9b) We drop the con mutex when delivering a message. When we retake the lock, we need to verify we are still in the OPEN state before preparing to read the next tag, or else we risk stepping on a connection that has been closed. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 8edc0c14f1c..bb21e5b0fb5 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2003,7 +2003,6 @@ static void process_message(struct ceph_connection *con) con->ops->dispatch(con, msg); mutex_lock(&con->mutex); - prepare_read_tag(con); } @@ -2213,6 +2212,8 @@ static int try_read(struct ceph_connection *con) if (con->in_tag == CEPH_MSGR_TAG_READY) goto more; process_message(con); + if (con->state == CON_STATE_OPEN) + prepare_read_tag(con); goto more; } if (con->in_tag == CEPH_MSGR_TAG_ACK) { From 328677c24bbae17f3f91ffce3b2351a27933741c Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 18:17:13 -0700 Subject: [PATCH 1602/2357] libceph: avoid dropping con mutex before fault (cherry picked from commit 8636ea672f0c5ab7478c42c5b6705ebd1db7eb6a) The ceph_fault() function takes the con mutex, so we should avoid dropping it before calling it. This fixes a potential race with another thread calling ceph_con_close(), or _open(), or similar (we don't reverify con->state after retaking the lock). Add annotation so that lockdep realizes we will drop the mutex before returning. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index bb21e5b0fb5..c2f0ca36f4a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2336,7 +2336,6 @@ static void con_work(struct work_struct *work) return; fault: - mutex_unlock(&con->mutex); ceph_fault(con); /* error/fault path */ goto done_unlocked; } @@ -2347,9 +2346,8 @@ static void con_work(struct work_struct *work) * exponential backoff */ static void ceph_fault(struct ceph_connection *con) + __releases(con->mutex) { - mutex_lock(&con->mutex); - pr_err("%s%lld %s %s\n", ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr), con->error_msg); dout("fault %p state %lu to peer %s\n", From 7389a76f02bf56340f26fa933b9fc6a1dece9148 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 18:19:30 -0700 Subject: [PATCH 1603/2357] libceph: change ceph_con_in_msg_alloc convention to be less weird (cherry picked from commit 4740a623d20c51d167da7f752b63e2b8714b2543) This function's calling convention is very limiting. In particular, we can't return any error other than ENOMEM (and only implicitly), which is a problem (see next patch). Instead, return an normal 0 or error code, and make the skip a pointer output parameter. Drop the useless in_hdr argument (we have the con pointer). Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 56 ++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index c2f0ca36f4a..bfd0878c5c4 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1733,9 +1733,7 @@ static int read_partial_message_section(struct ceph_connection *con, return 1; } -static bool ceph_con_in_msg_alloc(struct ceph_connection *con, - struct ceph_msg_header *hdr); - +static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip); static int read_partial_message_pages(struct ceph_connection *con, struct page **pages, @@ -1864,9 +1862,14 @@ static int read_partial_message(struct ceph_connection *con) /* allocate message? */ if (!con->in_msg) { + int skip = 0; + dout("got hdr type %d front %d data %d\n", con->in_hdr.type, con->in_hdr.front_len, con->in_hdr.data_len); - if (ceph_con_in_msg_alloc(con, &con->in_hdr)) { + ret = ceph_con_in_msg_alloc(con, &skip); + if (ret < 0) + return ret; + if (skip) { /* skip this message */ dout("alloc_msg said skip message\n"); BUG_ON(con->in_msg); @@ -1876,12 +1879,8 @@ static int read_partial_message(struct ceph_connection *con) con->in_seq++; return 0; } - if (!con->in_msg) { - con->error_msg = - "error allocating memory for incoming message"; - return -ENOMEM; - } + BUG_ON(!con->in_msg); BUG_ON(con->in_msg->con != con); m = con->in_msg; m->front.iov_len = 0; /* haven't read it yet */ @@ -2715,43 +2714,50 @@ static int ceph_alloc_middle(struct ceph_connection *con, struct ceph_msg *msg) * connection, and save the result in con->in_msg. Uses the * connection's private alloc_msg op if available. * - * Returns true if the message should be skipped, false otherwise. - * If true is returned (skip message), con->in_msg will be NULL. - * If false is returned, con->in_msg will contain a pointer to the - * newly-allocated message, or NULL in case of memory exhaustion. + * Returns 0 on success, or a negative error code. + * + * On success, if we set *skip = 1: + * - the next message should be skipped and ignored. + * - con->in_msg == NULL + * or if we set *skip = 0: + * - con->in_msg is non-null. + * On error (ENOMEM, EAGAIN, ...), + * - con->in_msg == NULL */ -static bool ceph_con_in_msg_alloc(struct ceph_connection *con, - struct ceph_msg_header *hdr) +static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip) { + struct ceph_msg_header *hdr = &con->in_hdr; int type = le16_to_cpu(hdr->type); int front_len = le32_to_cpu(hdr->front_len); int middle_len = le32_to_cpu(hdr->middle_len); - int ret; + int ret = 0; BUG_ON(con->in_msg != NULL); if (con->ops->alloc_msg) { - int skip = 0; - mutex_unlock(&con->mutex); - con->in_msg = con->ops->alloc_msg(con, hdr, &skip); + con->in_msg = con->ops->alloc_msg(con, hdr, skip); mutex_lock(&con->mutex); if (con->in_msg) { con->in_msg->con = con->ops->get(con); BUG_ON(con->in_msg->con == NULL); } - if (skip) + if (*skip) { con->in_msg = NULL; - - if (!con->in_msg) - return skip != 0; + return 0; + } + if (!con->in_msg) { + con->error_msg = + "error allocating memory for incoming message"; + return -ENOMEM; + } } if (!con->in_msg) { con->in_msg = ceph_msg_new(type, front_len, GFP_NOFS, false); if (!con->in_msg) { pr_err("unable to allocate msg type %d len %d\n", type, front_len); - return false; + return -ENOMEM; } con->in_msg->con = con->ops->get(con); BUG_ON(con->in_msg->con == NULL); @@ -2767,7 +2773,7 @@ static bool ceph_con_in_msg_alloc(struct ceph_connection *con, } } - return false; + return ret; } From 59238927cc8ea6c1e4a8a1136e17598648832db0 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 18:19:45 -0700 Subject: [PATCH 1604/2357] libceph: recheck con state after allocating incoming message (cherry picked from commit 6139919133377652992a5fe134e22abce3e9c25e) We drop the lock when calling the ->alloc_msg() con op, which means we need to (a) not clobber con->in_msg without the mutex held, and (b) we need to verify that we are still in the OPEN state when we retake it to avoid causing any mayhem. If the state does change, -EAGAIN will get us back to con_work() and loop. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index bfd0878c5c4..0de5a706f2b 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2735,9 +2735,16 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip) BUG_ON(con->in_msg != NULL); if (con->ops->alloc_msg) { + struct ceph_msg *msg; + mutex_unlock(&con->mutex); - con->in_msg = con->ops->alloc_msg(con, hdr, skip); + msg = con->ops->alloc_msg(con, hdr, skip); mutex_lock(&con->mutex); + if (con->state != CON_STATE_OPEN) { + ceph_msg_put(msg); + return -EAGAIN; + } + con->in_msg = msg; if (con->in_msg) { con->in_msg->con = con->ops->get(con); BUG_ON(con->in_msg->con == NULL); From b8e03e320f9156e870f8cc66b0d9fca9f24d36c8 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 2 Aug 2012 09:12:59 -0700 Subject: [PATCH 1605/2357] libceph: fix crypto key null deref, memory leak (cherry picked from commit f0666b1ac875ff32fe290219b150ec62eebbe10e) Avoid crashing if the crypto key payload was NULL, as when it was not correctly allocated and initialized. Also, avoid leaking it. Signed-off-by: Sylvain Munaut Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/crypto.c | 1 + net/ceph/crypto.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index b780cb7947d..9da7fdd3cd8 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c @@ -466,6 +466,7 @@ void ceph_key_destroy(struct key *key) { struct ceph_crypto_key *ckey = key->payload.data; ceph_crypto_key_destroy(ckey); + kfree(ckey); } struct key_type key_type_ceph = { diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h index 1919d1550d7..3572dc518bc 100644 --- a/net/ceph/crypto.h +++ b/net/ceph/crypto.h @@ -16,7 +16,8 @@ struct ceph_crypto_key { static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key) { - kfree(key->key); + if (key) + kfree(key->key); } extern int ceph_crypto_key_clone(struct ceph_crypto_key *dst, From 523693067608f067bcbe94f23a4feb4dfcfa2db8 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 19 Aug 2012 12:29:16 -0700 Subject: [PATCH 1606/2357] libceph: delay debugfs initialization until we learn global_id (cherry picked from commit d1c338a509cea5378df59629ad47382810c38623) The debugfs directory includes the cluster fsid and our unique global_id. We need to delay the initialization of the debug entry until we have learned both the fsid and our global_id from the monitor or else the second client can't create its debugfs entry and will fail (and multiple client instances aren't properly reflected in debugfs). Reported by: Yan, Zheng Signed-off-by: Sage Weil Reviewed-by: Yehuda Sadeh Signed-off-by: Greg Kroah-Hartman --- fs/ceph/debugfs.c | 1 + net/ceph/ceph_common.c | 1 - net/ceph/debugfs.c | 4 ++++ net/ceph/mon_client.c | 51 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index fb962efdace..6d59006bfa2 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -201,6 +201,7 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc) int err = -ENOMEM; dout("ceph_fs_debugfs_init\n"); + BUG_ON(!fsc->client->debugfs_dir); fsc->debugfs_congestion_kb = debugfs_create_file("writeback_congestion_kb", 0600, diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 52fe52cde60..8e74e8c5a77 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -83,7 +83,6 @@ int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid) return -1; } } else { - pr_info("client%lld fsid %pU\n", ceph_client_id(client), fsid); memcpy(&client->fsid, fsid, sizeof(*fsid)); } return 0; diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c index 27d4ea315d1..680978d0044 100644 --- a/net/ceph/debugfs.c +++ b/net/ceph/debugfs.c @@ -189,6 +189,9 @@ int ceph_debugfs_client_init(struct ceph_client *client) snprintf(name, sizeof(name), "%pU.client%lld", &client->fsid, client->monc.auth->global_id); + dout("ceph_debugfs_client_init %p %s\n", client, name); + + BUG_ON(client->debugfs_dir); client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir); if (!client->debugfs_dir) goto out; @@ -234,6 +237,7 @@ int ceph_debugfs_client_init(struct ceph_client *client) void ceph_debugfs_client_cleanup(struct ceph_client *client) { + dout("ceph_debugfs_client_cleanup %p\n", client); debugfs_remove(client->debugfs_osdmap); debugfs_remove(client->debugfs_monmap); debugfs_remove(client->osdc.debugfs_file); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 275aec2f175..89a6409b4e1 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -310,6 +310,17 @@ int ceph_monc_open_session(struct ceph_mon_client *monc) } EXPORT_SYMBOL(ceph_monc_open_session); +/* + * We require the fsid and global_id in order to initialize our + * debugfs dir. + */ +static bool have_debugfs_info(struct ceph_mon_client *monc) +{ + dout("have_debugfs_info fsid %d globalid %lld\n", + (int)monc->client->have_fsid, monc->auth->global_id); + return monc->client->have_fsid && monc->auth->global_id > 0; +} + /* * The monitor responds with mount ack indicate mount success. The * included client ticket allows the client to talk to MDSs and OSDs. @@ -320,9 +331,12 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc, struct ceph_client *client = monc->client; struct ceph_monmap *monmap = NULL, *old = monc->monmap; void *p, *end; + int had_debugfs_info, init_debugfs = 0; mutex_lock(&monc->mutex); + had_debugfs_info = have_debugfs_info(monc); + dout("handle_monmap\n"); p = msg->front.iov_base; end = p + msg->front.iov_len; @@ -344,12 +358,22 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc, if (!client->have_fsid) { client->have_fsid = true; + if (!had_debugfs_info && have_debugfs_info(monc)) { + pr_info("client%lld fsid %pU\n", + ceph_client_id(monc->client), + &monc->client->fsid); + init_debugfs = 1; + } mutex_unlock(&monc->mutex); - /* - * do debugfs initialization without mutex to avoid - * creating a locking dependency - */ - ceph_debugfs_client_init(client); + + if (init_debugfs) { + /* + * do debugfs initialization without mutex to avoid + * creating a locking dependency + */ + ceph_debugfs_client_init(monc->client); + } + goto out_unlocked; } out: @@ -865,8 +889,10 @@ static void handle_auth_reply(struct ceph_mon_client *monc, { int ret; int was_auth = 0; + int had_debugfs_info, init_debugfs = 0; mutex_lock(&monc->mutex); + had_debugfs_info = have_debugfs_info(monc); if (monc->auth->ops) was_auth = monc->auth->ops->is_authenticated(monc->auth); monc->pending_auth = 0; @@ -889,7 +915,22 @@ static void handle_auth_reply(struct ceph_mon_client *monc, __send_subscribe(monc); __resend_generic_request(monc); } + + if (!had_debugfs_info && have_debugfs_info(monc)) { + pr_info("client%lld fsid %pU\n", + ceph_client_id(monc->client), + &monc->client->fsid); + init_debugfs = 1; + } mutex_unlock(&monc->mutex); + + if (init_debugfs) { + /* + * do debugfs initialization without mutex to avoid + * creating a locking dependency + */ + ceph_debugfs_client_init(monc->client); + } } static int __validate_auth(struct ceph_mon_client *monc) From 76cb69279f83889cf98fd9f16f5d50bcc2779442 Mon Sep 17 00:00:00 2001 From: Jim Schutt Date: Fri, 10 Aug 2012 10:37:38 -0700 Subject: [PATCH 1607/2357] libceph: avoid truncation due to racing banners (cherry picked from commit 6d4221b53707486dfad3f5bfe568d2ce7f4c9863) Because the Ceph client messenger uses a non-blocking connect, it is possible for the sending of the client banner to race with the arrival of the banner sent by the peer. When ceph_sock_state_change() notices the connect has completed, it schedules work to process the socket via con_work(). During this time the peer is writing its banner, and arrival of the peer banner races with con_work(). If con_work() calls try_read() before the peer banner arrives, there is nothing for it to do, after which con_work() calls try_write() to send the client's banner. In this case Ceph's protocol negotiation can complete succesfully. The server-side messenger immediately sends its banner and addresses after accepting a connect request, *before* actually attempting to read or verify the banner from the client. As a result, it is possible for the banner from the server to arrive before con_work() calls try_read(). If that happens, try_read() will read the banner and prepare protocol negotiation info via prepare_write_connect(). prepare_write_connect() calls con_out_kvec_reset(), which discards the as-yet-unsent client banner. Next, con_work() calls try_write(), which sends the protocol negotiation info rather than the banner that the peer is expecting. The result is that the peer sees an invalid banner, and the client reports "negotiation failed". Fix this by moving con_out_kvec_reset() out of prepare_write_connect() to its callers at all locations except the one where the banner might still need to be sent. [elder@inktak.com: added note about server-side behavior] Signed-off-by: Jim Schutt Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 0de5a706f2b..5f312510f49 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -911,7 +911,6 @@ static int prepare_write_connect(struct ceph_connection *con) con->out_connect.authorizer_len = auth ? cpu_to_le32(auth->authorizer_buf_len) : 0; - con_out_kvec_reset(con); con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); if (auth && auth->authorizer_buf_len) @@ -1553,6 +1552,7 @@ static int process_connect(struct ceph_connection *con) return -1; } con->auth_retry = 1; + con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1573,6 +1573,7 @@ static int process_connect(struct ceph_connection *con) ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr)); reset_connection(con); + con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1597,6 +1598,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->out_connect.connect_seq), le32_to_cpu(con->in_reply.connect_seq)); con->connect_seq = le32_to_cpu(con->in_reply.connect_seq); + con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -1613,6 +1615,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->in_reply.global_seq)); get_global_seq(con->msgr, le32_to_cpu(con->in_reply.global_seq)); + con_out_kvec_reset(con); ret = prepare_write_connect(con); if (ret < 0) return ret; @@ -2131,7 +2134,11 @@ static int try_read(struct ceph_connection *con) BUG_ON(con->state != CON_STATE_CONNECTING); con->state = CON_STATE_NEGOTIATING; - /* Banner is good, exchange connection info */ + /* + * Received banner is good, exchange connection info. + * Do not reset out_kvec, as sending our banner raced + * with receiving peer banner after connect completed. + */ ret = prepare_write_connect(con); if (ret < 0) goto out; From 21e292e34c48c03fb6638c2d1295ca12dac97b03 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 21 Sep 2012 17:59:58 -0500 Subject: [PATCH 1608/2357] libceph: only kunmap kmapped pages (cherry picked from commit 5ce765a540f34d1e2005e1210f49f67fdf11e997) In write_partial_msg_pages(), pages need to be kmapped in order to perform a CRC-32c calculation on them. As an artifact of the way this code used to be structured, the kunmap() call was separated from the kmap() call and both were done conditionally. But the conditions under which the kmap() and kunmap() calls were made differed, so there was a chance a kunmap() call would be done on a page that had not been mapped. The symptom of this was tripping a BUG() in kunmap_high() when pkmap_count[nr] became 0. Reported-by: Bryan K. Wright Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 5f312510f49..6577a9fc6ce 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1069,16 +1069,13 @@ static int write_partial_msg_pages(struct ceph_connection *con) BUG_ON(kaddr == NULL); base = kaddr + con->out_msg_pos.page_pos + bio_offset; crc = crc32c(crc, base, len); + kunmap(page); msg->footer.data_crc = cpu_to_le32(crc); con->out_msg_pos.did_page_crc = true; } ret = ceph_tcp_sendpage(con->sock, page, con->out_msg_pos.page_pos + bio_offset, len, 1); - - if (do_datacrc) - kunmap(page); - if (ret <= 0) goto out; From a872024581f2e73edbea6eece56361ce508ea881 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 8 Oct 2012 20:37:30 -0700 Subject: [PATCH 1609/2357] rbd: reset BACKOFF if unable to re-queue (cherry picked from commit 588377d6199034c36d335e7df5818b731fea072c) If ceph_fault() is unable to queue work after a delay, it sets the BACKOFF connection flag so con_work() will attempt to do so. In con_work(), when BACKOFF is set, if queue_delayed_work() doesn't result in newly-queued work, it simply ignores this condition and proceeds as if no backoff delay were desired. There are two problems with this--one of which is a bug. The first problem is simply that the intended behavior is to back off, and if we aren't able queue the work item to run after a delay we're not doing that. The only reason queue_delayed_work() won't queue work is if the provided work item is already queued. In the messenger, this means that con_work() is already scheduled to be run again. So if we simply set the BACKOFF flag again when this occurs, we know the next con_work() call will again attempt to hold off activity on the connection until after the delay. The second problem--the bug--is a leak of a reference count. If queue_delayed_work() returns 0 in con_work(), con->ops->put() drops the connection reference held on entry to con_work(). However, processing is (was) allowed to continue, and at the end of the function a second con->ops->put() is called. This patch fixes both problems. Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 6577a9fc6ce..84f34c3f3e9 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2296,10 +2296,11 @@ static void con_work(struct work_struct *work) mutex_unlock(&con->mutex); return; } else { - con->ops->put(con); dout("con_work %p FAILED to back off %lu\n", con, con->delay); + set_bit(CON_FLAG_BACKOFF, &con->flags); } + goto done; } if (con->state == CON_STATE_STANDBY) { From 631015e45ee3bdcde1fe75e7d04fdfece6e42016 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 24 Oct 2012 16:12:58 -0700 Subject: [PATCH 1610/2357] libceph: avoid NULL kref_put when osd reset races with alloc_msg (cherry picked from commit 9bd952615a42d7e2ce3fa2c632e808e804637a1a) The ceph_on_in_msg_alloc() method drops con->mutex while it allocates a message. If that races with a timeout that resends a zillion messages and resets the connection, and the ->alloc_msg() method returns a NULL message, it will call ceph_msg_put(NULL) and BUG. Fix by only calling put if msg is non-NULL. Fixes http://tracker.newdream.net/issues/3142 Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 84f34c3f3e9..aa71a67450a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2746,7 +2746,8 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip) msg = con->ops->alloc_msg(con, hdr, skip); mutex_lock(&con->mutex); if (con->state != CON_STATE_OPEN) { - ceph_msg_put(msg); + if (msg) + ceph_msg_put(msg); return -EAGAIN; } con->in_msg = msg; From 73bba6fc44591587254fec8e867a99b5a2a28ba7 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Thu, 20 Sep 2012 17:42:25 +0800 Subject: [PATCH 1611/2357] ceph: Fix oops when handling mdsmap that decreases max_mds (cherry picked from commit 3e8f43a089f06279c5f76a9ccd42578eebf7bfa5) When i >= newmap->m_max_mds, ceph_mdsmap_get_addr(newmap, i) return NULL. Passing NULL to memcmp() triggers oops. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 5ac6434185a..7f1682da29a 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2634,7 +2634,8 @@ static void check_new_map(struct ceph_mds_client *mdsc, ceph_mdsmap_is_laggy(newmap, i) ? " (laggy)" : "", session_state_name(s->s_state)); - if (memcmp(ceph_mdsmap_get_addr(oldmap, i), + if (i >= newmap->m_max_mds || + memcmp(ceph_mdsmap_get_addr(oldmap, i), ceph_mdsmap_get_addr(newmap, i), sizeof(struct ceph_entity_addr))) { if (s->s_state == CEPH_MDS_SESSION_OPENING) { From dfae3b3451c6da14df1fa62d76c8a4345d21bdb2 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 24 Sep 2012 20:59:48 -0700 Subject: [PATCH 1612/2357] libceph: check for invalid mapping (cherry picked from commit d63b77f4c552cc3a20506871046ab0fcbc332609) If we encounter an invalid (e.g., zeroed) mapping, return an error and avoid a divide by zero. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/osd_client.h | 2 +- include/linux/ceph/osdmap.h | 6 +++--- net/ceph/osd_client.c | 32 ++++++++++++++++++++------------ net/ceph/osdmap.c | 18 ++++++++++++++++-- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index cedfb1a8434..d9b880e977e 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -207,7 +207,7 @@ extern void ceph_osdc_handle_reply(struct ceph_osd_client *osdc, extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg); -extern void ceph_calc_raw_layout(struct ceph_osd_client *osdc, +extern int ceph_calc_raw_layout(struct ceph_osd_client *osdc, struct ceph_file_layout *layout, u64 snapid, u64 off, u64 *plen, u64 *bno, diff --git a/include/linux/ceph/osdmap.h b/include/linux/ceph/osdmap.h index ba4c205cbb0..11db454f786 100644 --- a/include/linux/ceph/osdmap.h +++ b/include/linux/ceph/osdmap.h @@ -111,9 +111,9 @@ extern struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, extern void ceph_osdmap_destroy(struct ceph_osdmap *map); /* calculate mapping of a file extent to an object */ -extern void ceph_calc_file_object_mapping(struct ceph_file_layout *layout, - u64 off, u64 *plen, - u64 *bno, u64 *oxoff, u64 *oxlen); +extern int ceph_calc_file_object_mapping(struct ceph_file_layout *layout, + u64 off, u64 *plen, + u64 *bno, u64 *oxoff, u64 *oxlen); /* calculate mapping of object to a placement group */ extern int ceph_calc_object_layout(struct ceph_object_layout *ol, diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 56fd974b765..a79dbae3ea9 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -52,7 +52,7 @@ static int op_has_extent(int op) op == CEPH_OSD_OP_WRITE); } -void ceph_calc_raw_layout(struct ceph_osd_client *osdc, +int ceph_calc_raw_layout(struct ceph_osd_client *osdc, struct ceph_file_layout *layout, u64 snapid, u64 off, u64 *plen, u64 *bno, @@ -62,12 +62,15 @@ void ceph_calc_raw_layout(struct ceph_osd_client *osdc, struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base; u64 orig_len = *plen; u64 objoff, objlen; /* extent in object */ + int r; reqhead->snapid = cpu_to_le64(snapid); /* object extent? */ - ceph_calc_file_object_mapping(layout, off, plen, bno, - &objoff, &objlen); + r = ceph_calc_file_object_mapping(layout, off, plen, bno, + &objoff, &objlen); + if (r < 0) + return r; if (*plen < orig_len) dout(" skipping last %llu, final file extent %llu~%llu\n", orig_len - *plen, off, *plen); @@ -83,7 +86,7 @@ void ceph_calc_raw_layout(struct ceph_osd_client *osdc, dout("calc_layout bno=%llx %llu~%llu (%d pages)\n", *bno, objoff, objlen, req->r_num_pages); - + return 0; } EXPORT_SYMBOL(ceph_calc_raw_layout); @@ -112,20 +115,25 @@ EXPORT_SYMBOL(ceph_calc_raw_layout); * * fill osd op in request message. */ -static void calc_layout(struct ceph_osd_client *osdc, - struct ceph_vino vino, - struct ceph_file_layout *layout, - u64 off, u64 *plen, - struct ceph_osd_request *req, - struct ceph_osd_req_op *op) +static int calc_layout(struct ceph_osd_client *osdc, + struct ceph_vino vino, + struct ceph_file_layout *layout, + u64 off, u64 *plen, + struct ceph_osd_request *req, + struct ceph_osd_req_op *op) { u64 bno; + int r; - ceph_calc_raw_layout(osdc, layout, vino.snap, off, - plen, &bno, req, op); + r = ceph_calc_raw_layout(osdc, layout, vino.snap, off, + plen, &bno, req, op); + if (r < 0) + return r; snprintf(req->r_oid, sizeof(req->r_oid), "%llx.%08llx", vino.ino, bno); req->r_oid_len = strlen(req->r_oid); + + return r; } /* diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index c77133405ff..430076ee938 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -952,7 +952,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, * for now, we write only a single su, until we can * pass a stride back to the caller. */ -void ceph_calc_file_object_mapping(struct ceph_file_layout *layout, +int ceph_calc_file_object_mapping(struct ceph_file_layout *layout, u64 off, u64 *plen, u64 *ono, u64 *oxoff, u64 *oxlen) @@ -966,11 +966,17 @@ void ceph_calc_file_object_mapping(struct ceph_file_layout *layout, dout("mapping %llu~%llu osize %u fl_su %u\n", off, *plen, osize, su); + if (su == 0 || sc == 0) + goto invalid; su_per_object = osize / su; + if (su_per_object == 0) + goto invalid; dout("osize %u / su %u = su_per_object %u\n", osize, su, su_per_object); - BUG_ON((su & ~PAGE_MASK) != 0); + if ((su & ~PAGE_MASK) != 0) + goto invalid; + /* bl = *off / su; */ t = off; do_div(t, su); @@ -998,6 +1004,14 @@ void ceph_calc_file_object_mapping(struct ceph_file_layout *layout, *plen = *oxlen; dout(" obj extent %llu~%llu\n", *oxoff, *oxlen); + return 0; + +invalid: + dout(" invalid layout\n"); + *ono = 0; + *oxoff = 0; + *oxlen = 0; + return -EINVAL; } EXPORT_SYMBOL(ceph_calc_file_object_mapping); From b7d68a7434bbfd57049927ca713d57e44e0eee04 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 2 Oct 2012 10:25:51 -0500 Subject: [PATCH 1613/2357] ceph: avoid 32-bit page index overflow (cherry picked from commit 6285bc231277419255f3498d3eb5ddc9f8e7fe79) A pgoff_t is defined (by default) to have type (unsigned long). On architectures such as i686 that's a 32-bit type. The ceph address space code was attempting to produce 64 bit offsets by shifting a page's index by PAGE_CACHE_SHIFT, but the result was not what was desired because the shift occurred before the result got promoted to 64 bits. Fix this by converting all uses of page->index used in this way to use the page_offset() macro, which ensures the 64-bit result has the intended value. This fixes http://tracker.newdream.net/issues/3112 Reported-by: Mohamed Pakkeer Signed-off-by: Alex Elder Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman --- fs/ceph/addr.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 8b67304e4b8..32ee086c259 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -205,7 +205,7 @@ static int readpage_nounlock(struct file *filp, struct page *page) dout("readpage inode %p file %p page %p index %lu\n", inode, filp, page, page->index); err = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout, - page->index << PAGE_CACHE_SHIFT, &len, + (u64) page_offset(page), &len, ci->i_truncate_seq, ci->i_truncate_size, &page, 1, 0); if (err == -ENOENT) @@ -286,7 +286,7 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) int nr_pages = 0; int ret; - off = page->index << PAGE_CACHE_SHIFT; + off = (u64) page_offset(page); /* count pages */ next_index = page->index; @@ -426,7 +426,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) struct ceph_inode_info *ci; struct ceph_fs_client *fsc; struct ceph_osd_client *osdc; - loff_t page_off = page->index << PAGE_CACHE_SHIFT; + loff_t page_off = page_offset(page); int len = PAGE_CACHE_SIZE; loff_t i_size; int err = 0; @@ -817,8 +817,7 @@ static int ceph_writepages_start(struct address_space *mapping, /* ok */ if (locked_pages == 0) { /* prepare async write request */ - offset = (unsigned long long)page->index - << PAGE_CACHE_SHIFT; + offset = (u64) page_offset(page); len = wsize; req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, @@ -1180,7 +1179,7 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) struct inode *inode = vma->vm_file->f_dentry->d_inode; struct page *page = vmf->page; struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; - loff_t off = page->index << PAGE_CACHE_SHIFT; + loff_t off = page_offset(page); loff_t size, len; int ret; From 8217df07c9d8debd39a6d8e1e2271e97a3c899c7 Mon Sep 17 00:00:00 2001 From: Igor Murzov Date: Sat, 13 Oct 2012 04:41:25 +0400 Subject: [PATCH 1614/2357] ACPI video: Ignore errors after _DOD evaluation. commit fba4e087361605d1eed63343bb08811f097c83ee upstream. There are systems where video module known to work fine regardless of broken _DOD and ignoring returned value here doesn't cause any issues later. This should fix brightness controls on some laptops. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=47861 Signed-off-by: Igor Murzov Reviewed-by: Sergey V Signed-off-by: Zhang Rui Signed-off-by: Abdallah Chatila --- drivers/acpi/video.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 48b5a3cda37..62d9ee6d077 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1345,12 +1345,15 @@ static int acpi_video_bus_get_devices(struct acpi_video_bus *video, struct acpi_device *device) { - int status; + int status = 0; struct acpi_device *dev; - status = acpi_video_device_enumerate(video); - if (status) - return status; + /* + * There are systems where video module known to work fine regardless + * of broken _DOD and ignoring returned value here doesn't cause + * any issues later. + */ + acpi_video_device_enumerate(video); list_for_each_entry(dev, &device->children, node) { From 51b8318a818623899f9eb24ce697d43301bbe349 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 16 Oct 2012 17:09:22 +0300 Subject: [PATCH 1615/2357] Revert "serial: omap: fix software flow control" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a4f743851f74fc3e0cc40c13082e65c24139f481 upstream. This reverts commit 957ee7270d632245b43f6feb0e70d9a5e9ea6cf6 (serial: omap: fix software flow control). As Russell has pointed out, that commit isn't fixing Software Flow Control at all, and it actually makes it even more broken. It was agreed to revert this commit and use Russell's latest UART patches instead. Signed-off-by: Felipe Balbi Cc: Russell King Acked-by: Tony Lindgren Cc: Andreas Bießmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-omap/include/plat/omap-serial.h | 4 ++-- drivers/tty/serial/omap-serial.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index c369c9d242a..9ff444469f3 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -42,10 +42,10 @@ #define OMAP_UART_WER_MOD_WKUP 0X7F /* Enable XON/XOFF flow control on output */ -#define OMAP_UART_SW_TX 0x8 +#define OMAP_UART_SW_TX 0x04 /* Enable XON/XOFF flow control on input */ -#define OMAP_UART_SW_RX 0x2 +#define OMAP_UART_SW_RX 0x04 #define OMAP_UART_SYSC_RESET 0X07 #define OMAP_UART_TCR_TRIG 0X0F diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 6189923eb19..d00b38eb268 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -649,19 +649,19 @@ serial_omap_configure_xonxoff /* * IXON Flag: - * Flow control for OMAP.TX - * OMAP.RX should listen for XON/XOFF + * Enable XON/XOFF flow control on output. + * Transmit XON1, XOFF1 */ if (termios->c_iflag & IXON) - up->efr |= OMAP_UART_SW_RX; + up->efr |= OMAP_UART_SW_TX; /* * IXOFF Flag: - * Flow control for OMAP.RX - * OMAP.TX should send XON/XOFF + * Enable XON/XOFF flow control on input. + * Receiver compares XON1, XOFF1. */ if (termios->c_iflag & IXOFF) - up->efr |= OMAP_UART_SW_TX; + up->efr |= OMAP_UART_SW_RX; serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); From d0e85e04fb57a65a6096a0b18c97ba5892d676d9 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 21 Jun 2012 12:49:23 -0700 Subject: [PATCH 1616/2357] libceph: drop declaration of ceph_con_get() commit 261030215d970c62f799e6e508e3c68fc7ec2aa9 upstream. For some reason the declaration of ceph_con_get() and ceph_con_put() did not get deleted in this commit: d59315ca libceph: drop ceph_con_get/put helpers and nref member Clean that up. Signed-off-by: Alex Elder Cc: Herton Ronaldo Krzesinski Signed-off-by: Greg Kroah-Hartman --- include/linux/ceph/messenger.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 98442411c58..189ae063763 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -215,8 +215,6 @@ extern void ceph_msg_revoke(struct ceph_msg *msg); extern void ceph_msg_revoke_incoming(struct ceph_msg *msg); extern void ceph_con_keepalive(struct ceph_connection *con); -extern struct ceph_connection *ceph_con_get(struct ceph_connection *con); -extern void ceph_con_put(struct ceph_connection *con); extern struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags, bool can_fail); From 0f4475cfaaf80e34ea5496a93ce579fe8c6950d5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 26 Nov 2012 11:40:05 -0800 Subject: [PATCH 1617/2357] Linux 3.4.20 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e264929291e..9c895596748 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 19 +SUBLEVEL = 20 EXTRAVERSION = NAME = Saber-toothed Squirrel From 32e11d55e7997fe45c452b71014ee934054a1245 Mon Sep 17 00:00:00 2001 From: Alexandre Pereira da Silva Date: Mon, 25 Jun 2012 17:47:49 -0300 Subject: [PATCH 1618/2357] UBIFS: fix compilation warning commit 782759b9f5f5223e0962af60c3457c912fab755f upstream. Fix the following compilation warning: fs/ubifs/dir.c: In function 'ubifs_rename': fs/ubifs/dir.c:972:15: warning: 'saved_nlink' may be used uninitialized in this function Use the 'uninitialized_var()' macro to get rid of this false-positive. Artem: massaged the patch a bit. Signed-off-by: Alexandre Pereira da Silva Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index ec9f1870ab7..8640a12f065 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -977,7 +977,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, struct ubifs_budget_req ino_req = { .dirtied_ino = 1, .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; struct timespec time; - unsigned int saved_nlink; + unsigned int uninitialized_var(saved_nlink); /* * Budget request settings: deletion direntry, new direntry, removing From 4f442c50be050521667a8974fcc80cc8b881b2a6 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Fri, 27 Jul 2012 11:53:28 -0600 Subject: [PATCH 1619/2357] NVMe: Fix uninitialized iod compiler warning commit c7d36ab8fa04c213328119a9c0d66985fe204ee5 upstream. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox Signed-off-by: Greg Kroah-Hartman --- drivers/block/nvme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c index 38a2d063188..9782340b669 100644 --- a/drivers/block/nvme.c +++ b/drivers/block/nvme.c @@ -1153,7 +1153,7 @@ static int nvme_user_admin_cmd(struct nvme_ns *ns, struct nvme_admin_cmd cmd; struct nvme_command c; int status, length; - struct nvme_iod *iod; + struct nvme_iod *uninitialized_var(iod); if (!capable(CAP_SYS_ADMIN)) return -EACCES; From 2214cc8d585df2bbfc894d0a3acc5a629fa1a985 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Fri, 8 Jun 2012 11:33:33 +0200 Subject: [PATCH 1620/2357] Bluetooth: Fix using uninitialized option in RFCMode commit 8f321f853ea33330c7141977cd34804476e2e07e upstream. If remote device sends bogus RFC option with invalid length, undefined options values are used. Fix this by using defaults when remote misbehaves. This also fixes the following warning reported by gcc 4.7.0: net/bluetooth/l2cap_core.c: In function 'l2cap_config_rsp': net/bluetooth/l2cap_core.c:3302:13: warning: 'rfc.max_pdu_size' may be used uninitialized in this function [-Wmaybe-uninitialized] net/bluetooth/l2cap_core.c:3266:24: note: 'rfc.max_pdu_size' was declared here net/bluetooth/l2cap_core.c:3298:25: warning: 'rfc.monitor_timeout' may be used uninitialized in this function [-Wmaybe-uninitialized] net/bluetooth/l2cap_core.c:3266:24: note: 'rfc.monitor_timeout' was declared here net/bluetooth/l2cap_core.c:3297:25: warning: 'rfc.retrans_timeout' may be used uninitialized in this function [-Wmaybe-uninitialized] net/bluetooth/l2cap_core.c:3266:24: note: 'rfc.retrans_timeout' was declared here net/bluetooth/l2cap_core.c:3295:2: warning: 'rfc.mode' may be used uninitialized in this function [-Wmaybe-uninitialized] net/bluetooth/l2cap_core.c:3266:24: note: 'rfc.mode' was declared here Signed-off-by: Szymon Janc Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/l2cap_core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 627c35445a1..fa07aed3983 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2585,12 +2585,14 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); - switch (type) { - case L2CAP_CONF_RFC: - if (olen == sizeof(rfc)) - memcpy(&rfc, (void *)val, olen); - goto done; - } + if (type != L2CAP_CONF_RFC) + continue; + + if (olen != sizeof(rfc)) + break; + + memcpy(&rfc, (void *)val, olen); + goto done; } /* Use sane default values in case a misbehaving remote device From d4cad86a445a5229b58bbb7beaa0753f09314855 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 18 Jun 2012 21:16:31 +0200 Subject: [PATCH 1621/2357] ALSA: snd-usb-caiaq: initialize card pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit da185443c12f5ef7416af50293833a5654854186 upstream. Fixes the following warning: CC [M] sound/usb/caiaq/device.o sound/usb/caiaq/device.c: In function ‘snd_probe’: sound/usb/caiaq/device.c:500:16: warning: ‘card’ may be used uninitialized in this function [-Wmaybe-uninitialized] Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/caiaq/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index 64aed432ae2..7da0d0aa72c 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -485,7 +485,7 @@ static int __devinit snd_probe(struct usb_interface *intf, const struct usb_device_id *id) { int ret; - struct snd_card *card; + struct snd_card *card = NULL; struct usb_device *device = interface_to_usbdev(intf); ret = create_card(device, intf, &card); From 896c631494d7ed4e609ef7b7b312b8a19b21f394 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 29 May 2012 15:07:26 -0700 Subject: [PATCH 1622/2357] drivers/leds/leds-lp5521.c: fix lp5521_read() error handling commit 5bc9ad774c063f6b41965e7314f2c26aa5e465a0 upstream. Gcc 4.6.2 complains that: drivers/leds/leds-lp5521.c: In function `lp5521_load_program': drivers/leds/leds-lp5521.c:214:21: warning: `mode' may be used uninitialized in this function [-Wuninitialized] drivers/leds/leds-lp5521.c: In function `lp5521_probe': drivers/leds/leds-lp5521.c:788:5: warning: `buf' may be used uninitialized in this function [-Wuninitialized] drivers/leds/leds-lp5521.c:740:6: warning: `ret' may be used uninitialized in this function [-Wuninitialized] These are real problems if lp5521_read() returns an error. When that happens we should handle it, instead of ignoring it or doing a bitwise OR with all the other error codes and continuing. Signed-off-by: Dan Carpenter Cc: Milo Cc: Richard Purdie Cc: Bryan Wu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/leds/leds-lp5521.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 410a723b869..23815624f35 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -193,9 +193,14 @@ static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern) /* move current engine to direct mode and remember the state */ ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT); + if (ret) + return ret; + /* Mode change requires min 500 us delay. 1 - 2 ms with margin */ usleep_range(1000, 2000); - ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode); + ret = lp5521_read(client, LP5521_REG_OP_MODE, &mode); + if (ret) + return ret; /* For loading, all the engines to load mode */ lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); @@ -211,8 +216,7 @@ static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern) LP5521_PROG_MEM_SIZE, pattern); - ret |= lp5521_write(client, LP5521_REG_OP_MODE, mode); - return ret; + return lp5521_write(client, LP5521_REG_OP_MODE, mode); } static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr) @@ -785,7 +789,7 @@ static int __devinit lp5521_probe(struct i2c_client *client, * LP5521_REG_ENABLE register will not have any effect - strange! */ ret = lp5521_read(client, LP5521_REG_R_CURRENT, &buf); - if (buf != LP5521_REG_R_CURR_DEFAULT) { + if (ret || buf != LP5521_REG_R_CURR_DEFAULT) { dev_err(&client->dev, "error in resetting chip\n"); goto fail2; } From cbe6d9bd065c64cb9eac67d9a12001e095f875b9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 21 Jun 2012 23:36:35 -0700 Subject: [PATCH 1623/2357] mvsas: remove unused variable in mvs_task_exec() commit cca85013ef54f66eb4616e6f3860549a96c8338b upstream. We don't use "dev" any more after 07ec747a5f ("libsas: remove ata_port.lock management duties from lldds") and it causes a compile warning. Signed-off-by: Dan Carpenter Cc: Xiangliang Yu Signed-off-by: Dan Williams Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mvsas/mv_sas.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index fd3b2839843..3006ec9aa69 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -885,7 +885,6 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, struct completion *completion, int is_tmf, struct mvs_tmf_task *tmf) { - struct domain_device *dev = task->dev; struct mvs_info *mvi = NULL; u32 rc = 0; u32 pass = 0; From 6df5eea2553e9b66c2ef1f68dfd4b8867e2ff740 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczynski Date: Wed, 2 May 2012 11:34:01 +0100 Subject: [PATCH 1624/2357] scsi: aha152x: Fix sparse warning and make printing pointer address more portable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b631cf1f899f9d2e449884dbccc34940637c639f upstream. This is to change use of "0x%08x" in favour of "%p" as per ../Documentation/printk-formats.txt, which also takes care about the following warning during compilation time: drivers/scsi/aha152x.c: In function ‘get_command’: drivers/scsi/aha152x.c:2987: warning: cast from pointer to integer of different size Signed-off-by: Krzysztof Wilczynski Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/aha152x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 19a36945e6f..dd4547bf688 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -2984,8 +2984,8 @@ static int get_command(char *pos, Scsi_Cmnd * ptr) char *start = pos; int i; - SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ", - (unsigned int) ptr, ptr->device->id, ptr->device->lun); + SPRINTF("%p: target=%d; lun=%d; cmnd=( ", + ptr, ptr->device->id, ptr->device->lun); for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) SPRINTF("0x%02x ", ptr->cmnd[i]); From 3ec1dc266051fc58d977a269f9807b4f987a93ef Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 20 Jun 2012 11:47:26 -0500 Subject: [PATCH 1625/2357] rtlwifi: rtl8192se: Fix gcc 4.7.x warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f761b6947dde42890beea59b020e1be87491809e upstream. With gcc 4.7.x, the following warning is issued as the routine that sets the array has the possibility of not initializing the values: CC [M] drivers/net/wireless/rtlwifi/rtl8192se/phy.o drivers/net/wireless/rtlwifi/rtl8192se/phy.c: In function ‘rtl92s_phy_set_txpower’: drivers/net/wireless/rtlwifi/rtl8192se/phy.c:1268:23: warning: ‘ofdmpowerLevel[0]’ may be used uninitialized in this function [-Wuninitialized] Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/rtl8192se/phy.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index 4a499928e4c..a2a5c92a180 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -1247,6 +1247,9 @@ static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel, /* Read HT 40 OFDM TX power */ ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index]; ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index]; + } else { + ofdmpowerLevel[0] = 0; + ofdmpowerLevel[1] = 0; } } From 9d4f96299744ee7b8e2c4ad30ee915f1671e9fba Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 3 Sep 2012 20:54:48 +0200 Subject: [PATCH 1626/2357] x86-32: Fix invalid stack address while in softirq commit 1022623842cb72ee4d0dbf02f6937f38c92c3f41 upstream. In 32 bit the stack address provided by kernel_stack_pointer() may point to an invalid range causing NULL pointer access or page faults while in NMI (see trace below). This happens if called in softirq context and if the stack is empty. The address at ®s->sp is then out of range. Fixing this by checking if regs and ®s->sp are in the same stack context. Otherwise return the previous stack pointer stored in struct thread_info. If that address is invalid too, return address of regs. BUG: unable to handle kernel NULL pointer dereference at 0000000a IP: [] print_context_stack+0x6e/0x8d *pde = 00000000 Oops: 0000 [#1] SMP Modules linked in: Pid: 4434, comm: perl Not tainted 3.6.0-rc3-oprofile-i386-standard-g4411a05 #4 Hewlett-Packard HP xw9400 Workstation/0A1Ch EIP: 0060:[] EFLAGS: 00010093 CPU: 0 EIP is at print_context_stack+0x6e/0x8d EAX: ffffe000 EBX: 0000000a ECX: f4435f94 EDX: 0000000a ESI: f4435f94 EDI: f4435f94 EBP: f5409ec0 ESP: f5409ea0 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 CR0: 8005003b CR2: 0000000a CR3: 34ac9000 CR4: 000007d0 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Process perl (pid: 4434, ti=f5408000 task=f5637850 task.ti=f4434000) Stack: 000003e8 ffffe000 00001ffc f4e39b00 00000000 0000000a f4435f94 c155198c f5409ef0 c1003723 c155198c f5409f04 00000000 f5409edc 00000000 00000000 f5409ee8 f4435f94 f5409fc4 00000001 f5409f1c c12dce1c 00000000 c155198c Call Trace: [] dump_trace+0x7b/0xa1 [] x86_backtrace+0x40/0x88 [] ? oprofile_add_sample+0x56/0x84 [] oprofile_add_sample+0x75/0x84 [] op_amd_check_ctrs+0x46/0x260 [] profile_exceptions_notify+0x23/0x4c [] nmi_handle+0x31/0x4a [] ? ftrace_define_fields_irq_handler_entry+0x45/0x45 [] do_nmi+0xa0/0x2ff [] ? ftrace_define_fields_irq_handler_entry+0x45/0x45 [] nmi_stack_correct+0x28/0x2d [] ? ftrace_define_fields_irq_handler_entry+0x45/0x45 [] ? do_softirq+0x4b/0x7f [] irq_exit+0x35/0x5b [] smp_apic_timer_interrupt+0x6c/0x7a [] apic_timer_interrupt+0x2a/0x30 Code: 89 fe eb 08 31 c9 8b 45 0c ff 55 ec 83 c3 04 83 7d 10 00 74 0c 3b 5d 10 73 26 3b 5d e4 73 0c eb 1f 3b 5d f0 76 1a 3b 5d e8 73 15 <8b> 13 89 d0 89 55 e0 e8 ad 42 03 00 85 c0 8b 55 e0 75 a6 eb cc EIP: [] print_context_stack+0x6e/0x8d SS:ESP 0068:f5409ea0 CR2: 000000000000000a ---[ end trace 62afee3481b00012 ]--- Kernel panic - not syncing: Fatal exception in interrupt V2: * add comments to kernel_stack_pointer() * always return a valid stack address by falling back to the address of regs Reported-by: Yang Wei Signed-off-by: Robert Richter Link: http://lkml.kernel.org/r/20120912135059.GZ8285@erda.amd.com Signed-off-by: H. Peter Anvin Cc: Jun Zhang Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/ptrace.h | 15 ++++----------- arch/x86/kernel/ptrace.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index dcfde52979c..19f16ebaf4f 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -205,21 +205,14 @@ static inline bool user_64bit_mode(struct pt_regs *regs) } #endif -/* - * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode - * when it traps. The previous stack will be directly underneath the saved - * registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. - * - * This is valid only for kernel mode traps. - */ -static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) -{ #ifdef CONFIG_X86_32 - return (unsigned long)(®s->sp); +extern unsigned long kernel_stack_pointer(struct pt_regs *regs); #else +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ return regs->sp; -#endif } +#endif #define GET_IP(regs) ((regs)->ip) #define GET_FP(regs) ((regs)->bp) diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index cf1178332bc..d3e115297fe 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -165,6 +165,34 @@ static inline bool invalid_selector(u16 value) #define FLAG_MASK FLAG_MASK_32 +/* + * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode + * when it traps. The previous stack will be directly underneath the saved + * registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. + * + * Now, if the stack is empty, '®s->sp' is out of range. In this + * case we try to take the previous stack. To always return a non-null + * stack pointer we fall back to regs as stack if no previous stack + * exists. + * + * This is valid only for kernel mode traps. + */ +unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ + unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1); + unsigned long sp = (unsigned long)®s->sp; + struct thread_info *tinfo; + + if (context == (sp & ~(THREAD_SIZE - 1))) + return sp; + + tinfo = (struct thread_info *)context; + if (tinfo->previous_esp) + return tinfo->previous_esp; + + return (unsigned long)regs; +} + static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno) { BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0); From 8433fcce61cd330b1096e2e4d7601d5251d95b6c Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Tue, 20 Nov 2012 13:07:46 +0000 Subject: [PATCH 1627/2357] x86, efi: Fix processor-specific memcpy() build error commit 0f905a43ce955b638139bd84486194770a6a2c08 upstream. Building for Athlon/Duron/K7 results in the following build error, arch/x86/boot/compressed/eboot.o: In function `__constant_memcpy3d': eboot.c:(.text+0x385): undefined reference to `_mmx_memcpy' arch/x86/boot/compressed/eboot.o: In function `efi_main': eboot.c:(.text+0x1a22): undefined reference to `_mmx_memcpy' because the boot stub code doesn't link with the kernel proper, and therefore doesn't have access to the 3DNow version of memcpy. So, follow the example of misc.c and #undef memcpy so that we use the version provided by misc.c. See https://bugzilla.kernel.org/show_bug.cgi?id=50391 Reported-by: Al Viro Reported-by: Ryan Underwood Cc: H. Peter Anvin Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman --- arch/x86/boot/compressed/eboot.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 0cdfc0d2315..8bb90707cb5 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -12,6 +12,8 @@ #include #include +#undef memcpy /* Use memcpy from misc.c */ + #include "eboot.h" static efi_system_table_t *sys_table; From 82c0abae22f37f93655b8adfa304e207f2ffbfa3 Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Thu, 15 Nov 2012 13:41:50 -0500 Subject: [PATCH 1628/2357] x86, microcode, AMD: Add support for family 16h processors commit 36c46ca4f322a7bf89aad5462a3a1f61713edce7 upstream. Add valid patch size for family 16h processors. [ hpa: promoting to urgent/stable since it is hw enabling and trivial ] Signed-off-by: Boris Ostrovsky Acked-by: Andreas Herrmann Link: http://lkml.kernel.org/r/1353004910-2204-1-git-send-email-boris.ostrovsky@amd.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/microcode_amd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 82746f942cd..5d8cf0d6796 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -97,6 +97,7 @@ static unsigned int verify_ucode_size(int cpu, u32 patch_size, #define F1XH_MPB_MAX_SIZE 2048 #define F14H_MPB_MAX_SIZE 1824 #define F15H_MPB_MAX_SIZE 4096 +#define F16H_MPB_MAX_SIZE 3458 switch (c->x86) { case 0x14: @@ -105,6 +106,9 @@ static unsigned int verify_ucode_size(int cpu, u32 patch_size, case 0x15: max_size = F15H_MPB_MAX_SIZE; break; + case 0x16: + max_size = F16H_MPB_MAX_SIZE; + break; default: max_size = F1XH_MPB_MAX_SIZE; break; From 383072079d8f54041bf183a2fa70144bebb82ed8 Mon Sep 17 00:00:00 2001 From: Albert Pool Date: Tue, 30 Oct 2012 20:58:06 +0100 Subject: [PATCH 1629/2357] rtlwifi: rtl8192cu: Add new USB ID commit a485e827f07bfdd0762059386e6e787bed6e81ee upstream. This is an ISY IWL 2000. Probably a clone of Belkin F7D1102 050d:1102. Its FCC ID is the same. Signed-off-by: Albert Pool Acked-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 5bd40856635..61e57689a05 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -297,6 +297,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { /*=== Customer ID ===*/ /****** 8188CU ********/ {RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/ + {RTL_USB_DEVICE(0x050d, 0x11f2, rtl92cu_hal_cfg)}, /*Belkin - ISY*/ {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ From 6966e1b95a3b866bf076176f7cd3f6898e00ee68 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 15 Nov 2012 15:58:48 -0800 Subject: [PATCH 1630/2357] mwifiex: report error to MMC core if we cannot suspend commit dd321acddc3be1371263b8c9e6c6f2af89f63d57 upstream. When host_sleep_config command fails we should return error to MMC core to indicate the failure for our device. The misspelled variable is also removed as it's redundant. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mwifiex/sdio.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index f8012e2b7f7..7d00a87e9a1 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -158,7 +158,6 @@ static int mwifiex_sdio_suspend(struct device *dev) struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; - int hs_actived = 0; int i; int ret = 0; @@ -185,12 +184,14 @@ static int mwifiex_sdio_suspend(struct device *dev) adapter = card->adapter; /* Enable the Host Sleep */ - hs_actived = mwifiex_enable_hs(adapter); - if (hs_actived) { - pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); - ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (!mwifiex_enable_hs(adapter)) { + dev_err(adapter->dev, "cmd: failed to suspend\n"); + return -EFAULT; } + dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + /* Indicate device suspended */ adapter->is_suspended = true; From 8d8c210794bb574b1d04492332a399e679caaa63 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 15 Nov 2012 15:58:47 -0800 Subject: [PATCH 1631/2357] mwifiex: fix system hang issue in cmd timeout error case commit b1a47aa5e1e159e2cb06d7dfcc17ef5149b09299 upstream. Reported by Tim Shepard: I was seeing sporadic failures (wedgeups), and the majority of those failures I saw printed the printouts in mwifiex_cmd_timeout_func with cmd = 0xe5 which is CMD_802_11_HS_CFG_ENH. When this happens, two minutes later I get notified that the rtcwake thread is blocked, like this: INFO: task rtcwake:3495 blocked for more than 120 seconds. To get the hung thread unblocked we wake up the cmd wait queue and cancel the ioctl. Reported-by: Tim Shepard Signed-off-by: Bing Zhao Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mwifiex/cmdevt.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 07f6e009255..2977a12410c 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -816,9 +816,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) return; } cmd_node = adapter->curr_cmd; - if (cmd_node->wait_q_enabled) - adapter->cmd_wait_q.status = -ETIMEDOUT; - if (cmd_node) { adapter->dbg.timeout_cmd_id = adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; @@ -864,6 +861,14 @@ mwifiex_cmd_timeout_func(unsigned long function_context) dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", adapter->ps_mode, adapter->ps_state); + + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -ETIMEDOUT; + wake_up_interruptible(&adapter->cmd_wait_q.wait); + mwifiex_cancel_pending_ioctl(adapter); + /* reset cmd_sent flag to unblock new commands */ + adapter->cmd_sent = false; + } } if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) mwifiex_init_fw_complete(adapter); From 6417635908e7643800141fc1d6cf7fe43f4fb5e3 Mon Sep 17 00:00:00 2001 From: Maciej Patelczyk Date: Mon, 15 Oct 2012 14:29:03 +0200 Subject: [PATCH 1632/2357] SCSI: isci: copy fis 0x34 response into proper buffer commit 49bd665c5407a453736d3232ee58f2906b42e83c upstream. SATA MICROCODE DOWNALOAD fails on isci driver. After receiving Register Device to Host (FIS 0x34) frame Initiator resets phy. In the frame handler routine response (FIS 0x34) was copied into wrong buffer and upper layer did not receive any answer which resulted in timeout and reset. This patch corrects this bug. Signed-off-by: Maciej Patelczyk Signed-off-by: Lukasz Dorau Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/isci/request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 2def1e3960f..05c3fc0ce27 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1970,7 +1970,7 @@ sci_io_request_frame_handler(struct isci_request *ireq, frame_index, (void **)&frame_buffer); - sci_controller_copy_sata_response(&ireq->stp.req, + sci_controller_copy_sata_response(&ireq->stp.rsp, frame_header, frame_buffer); From 9cbecb443503ba3dd6a620e8e43a0273e14dc204 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 21 Nov 2012 18:37:38 -0500 Subject: [PATCH 1633/2357] drm/radeon: add new SI pci id commit 0181bd5dea2ed0696f84591a92da0b6a1f1a2e62 upstream. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_pciids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index efc66f2d096..7207a99bdf8 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -214,6 +214,7 @@ {0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x679B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ From 75c23fc13e0f252cc4f3e52d45116b8642c6c61a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 31 Oct 2012 16:35:30 +0100 Subject: [PATCH 1634/2357] ALSA: ua101, usx2y: fix broken MIDI output commit e99ddfde6ae0dd2662bb40435696002b590e4057 upstream. Commit 88a8516a2128 (ALSA: usbaudio: implement USB autosuspend) added autosuspend code to all files making up the snd-usb-audio driver. However, midi.c is part of snd-usb-lib and is also used by other drivers, not all of which support autosuspend. Thus, calls to usb_autopm_get_interface() could fail, and this unexpected error would result in the MIDI output being completely unusable. Make it work by ignoring the error that is expected with drivers that do not support autosuspend. Reported-by: Colin Fletcher Reported-by: Devin Venable Reported-by: Dr Nick Bailey Reported-by: Jannis Achstetter Reported-by: Rui Nuno Capela Cc: Oliver Neukum Signed-off-by: Clemens Ladisch Signed-off-by: Greg Kroah-Hartman --- sound/usb/midi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/usb/midi.c b/sound/usb/midi.c index c83f6143c0e..eeefbce3873 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -148,6 +148,7 @@ struct snd_usb_midi_out_endpoint { struct snd_usb_midi_out_endpoint* ep; struct snd_rawmidi_substream *substream; int active; + bool autopm_reference; uint8_t cable; /* cable number << 4 */ uint8_t state; #define STATE_UNKNOWN 0 @@ -1076,7 +1077,8 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) return -ENXIO; } err = usb_autopm_get_interface(umidi->iface); - if (err < 0) + port->autopm_reference = err >= 0; + if (err < 0 && err != -EACCES) return -EIO; substream->runtime->private_data = port; port->state = STATE_UNKNOWN; @@ -1087,9 +1089,11 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct usbmidi_out_port *port = substream->runtime->private_data; substream_open(substream, 0); - usb_autopm_put_interface(umidi->iface); + if (port->autopm_reference) + usb_autopm_put_interface(umidi->iface); return 0; } From de134053d4084ef640a44f9fd848cb607d2d0457 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 21 Nov 2012 10:03:10 +0100 Subject: [PATCH 1635/2357] ALSA: hda - Cirrus: Correctly clear line_out_pins when moving to speaker commit 34c3d1926bdaf45d3a891dd577482abcdd9faa34 upstream. If this array is not cleared, the jack related code later might fail to create "Internal Speaker Phantom Jack" on Dell Inspiron 3420 and Dell Vostro 2420. BugLink: https://bugs.launchpad.net/bugs/1076840 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_cirrus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 057f95a2bbb..3605fbb6ef1 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -460,6 +460,7 @@ static int parse_output(struct hda_codec *codec) memcpy(cfg->speaker_pins, cfg->line_out_pins, sizeof(cfg->speaker_pins)); cfg->line_outs = 0; + memset(cfg->line_out_pins, 0, sizeof(cfg->line_out_pins)); } return 0; From 7c06237754a52bb98462ee787f9b001854d884df Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 2 Nov 2012 12:30:53 +0000 Subject: [PATCH 1636/2357] PARISC: fix virtual aliasing issue in get_shared_area() commit 949a05d03490e39e773e8652ccab9157e6f595b4 upstream. On Thu, 2012-11-01 at 16:45 -0700, Michel Lespinasse wrote: > Looking at the arch/parisc/kernel/sys_parisc.c implementation of > get_shared_area(), I do have a concern though. The function basically > ignores the pgoff argument, so that if one creates a shared mapping of > pages 0-N of a file, and then a separate shared mapping of pages 1-N > of that same file, both will have the same cache offset for their > starting address. > > This looks like this would create obvious aliasing issues. Am I > misreading this ? I can't understand how this could work good enough > to be undetected, so there must be something I'm missing here ??? This turns out to be correct and we need to pay attention to the pgoff as well as the address when creating the virtual address for the area. Fortunately, the bug is rarely triggered as most applications which use pgoff tend to use large values (git being the primary one, and it uses pgoff in multiples of 16MB) which are larger than our cache coherency modulus, so the problem isn't often seen in practise. Reported-by: Michel Lespinasse Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/sys_parisc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index c9b932260f4..7ea75d14aa6 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -73,6 +73,8 @@ static unsigned long get_shared_area(struct address_space *mapping, struct vm_area_struct *vma; int offset = mapping ? get_offset(mapping) : 0; + offset = (offset + (pgoff << PAGE_SHIFT)) & 0x3FF000; + addr = DCACHE_ALIGN(addr - offset) + offset; for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { From e939e24a7d18f47001ca2e16c4028807120337b3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 21 Nov 2012 19:27:23 +0000 Subject: [PATCH 1637/2357] PARISC: fix user-triggerable panic on parisc commit 441a179dafc0f99fc8b3a8268eef66958621082e upstream. int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset, unsigned int sigsetsize) { sigset_t old_set, new_set; int ret; if (set && get_sigset32(set, &new_set, sigsetsize)) ... static int get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) { compat_sigset_t s; int r; if (sz != sizeof *set) panic("put_sigset32()"); In other words, rt_sigprocmask(69, (void *)69, 69) done by 32bit process will promptly panic the box. Signed-off-by: Al Viro Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/signal32.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index e1413243076..d0ea054bd3d 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -67,7 +67,8 @@ put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) { compat_sigset_t s; - if (sz != sizeof *set) panic("put_sigset32()"); + if (sz != sizeof *set) + return -EINVAL; sigset_64to32(&s, set); return copy_to_user(up, &s, sizeof s); @@ -79,7 +80,8 @@ get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) compat_sigset_t s; int r; - if (sz != sizeof *set) panic("put_sigset32()"); + if (sz != sizeof *set) + return -EINVAL; if ((r = copy_from_user(&s, up, sz)) == 0) { sigset_32to64(set, &s); From 02bbebe27638111d18f63fa7438231def916bd15 Mon Sep 17 00:00:00 2001 From: Jiri Engelthaler Date: Thu, 20 Sep 2012 16:49:50 +0200 Subject: [PATCH 1638/2357] mtd: slram: invalid checking of absolute end address commit c36a7ff4578ab6294885aef5ef241aeec4cdb1f0 upstream. Fixed parsing end absolute address. Signed-off-by: Jiri Engelthaler Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/devices/slram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 8f52fc858e4..5a5cd2ace4a 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -240,7 +240,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) if (*(szlength) != '+') { devlength = simple_strtoul(szlength, &buffer, 0); - devlength = handle_unit(devlength, buffer) - devstart; + devlength = handle_unit(devlength, buffer); if (devlength < devstart) goto err_out; From 11371ec0a92756cbaa84b86fbbaa3aeae7457658 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 25 Sep 2012 15:27:13 +0530 Subject: [PATCH 1639/2357] mtd: ofpart: Fix incorrect NULL check in parse_ofoldpart_partitions() commit 5a6ea4af0907f995dc06df21a9c9ef764c7cd3bc upstream. The pointer returned by kzalloc should be tested for NULL to avoid potential NULL pointer dereference later. Incorrect pointer was being tested for NULL. Bug introduced by commit fbcf62a3 (mtd: physmap_of: move parse_obsolete_partitions to become separate parser). This patch fixes this bug. Signed-off-by: Sachin Kamat Cc: Dmitry Eremin-Solenikov Cc: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ofpart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 64be8f0848b..d9127e2ed80 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -121,7 +121,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, nr_parts = plen / sizeof(part[0]); *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL); - if (!pparts) + if (!*pparts) return -ENOMEM; names = of_get_property(dp, "partition-names", &plen); From 262a70e8fbf870359ced2059becf116a249bb2d5 Mon Sep 17 00:00:00 2001 From: Thomas Betker Date: Wed, 17 Oct 2012 22:59:30 +0200 Subject: [PATCH 1640/2357] jffs2: Fix lock acquisition order bug in jffs2_write_begin commit 5ffd3412ae5536a4c57469cb8ea31887121dcb2e upstream. jffs2_write_begin() first acquires the page lock, then f->sem. This causes an AB-BA deadlock with jffs2_garbage_collect_live(), which first acquires f->sem, then the page lock: jffs2_garbage_collect_live mutex_lock(&f->sem) (A) jffs2_garbage_collect_dnode jffs2_gc_fetch_page read_cache_page_async do_read_cache_page lock_page(page) (B) jffs2_write_begin grab_cache_page_write_begin find_lock_page lock_page(page) (B) mutex_lock(&f->sem) (A) We fix this by restructuring jffs2_write_begin() to take f->sem before the page lock. However, we make sure that f->sem is not held when calling jffs2_reserve_space(), as this is not permitted by the locking rules. The deadlock above was observed multiple times on an SoC with a dual ARMv7 (Cortex-A9), running the long-term 3.4.11 kernel; it occurred when using scp to copy files from a host system to the ARM target system. The fix was heavily tested on the same target system. Signed-off-by: Thomas Betker Acked-by: Joakim Tjernlund Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- fs/jffs2/file.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index db3889ba881..8608f877914 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -138,33 +138,39 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, struct page *pg; struct inode *inode = mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_raw_inode ri; + uint32_t alloc_len = 0; pgoff_t index = pos >> PAGE_CACHE_SHIFT; uint32_t pageofs = index << PAGE_CACHE_SHIFT; int ret = 0; + jffs2_dbg(1, "%s()\n", __func__); + + if (pageofs > inode->i_size) { + ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + if (ret) + return ret; + } + + mutex_lock(&f->sem); pg = grab_cache_page_write_begin(mapping, index, flags); - if (!pg) + if (!pg) { + if (alloc_len) + jffs2_complete_reservation(c); + mutex_unlock(&f->sem); return -ENOMEM; + } *pagep = pg; - jffs2_dbg(1, "%s()\n", __func__); - - if (pageofs > inode->i_size) { + if (alloc_len) { /* Make new hole frag from old EOF to new page */ - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; - uint32_t alloc_len; jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", (unsigned int)inode->i_size, pageofs); - ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); - if (ret) - goto out_page; - - mutex_lock(&f->sem); memset(&ri, 0, sizeof(ri)); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -191,7 +197,6 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, if (IS_ERR(fn)) { ret = PTR_ERR(fn); jffs2_complete_reservation(c); - mutex_unlock(&f->sem); goto out_page; } ret = jffs2_add_full_dnode_to_inode(c, f, fn); @@ -206,12 +211,10 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); jffs2_complete_reservation(c); - mutex_unlock(&f->sem); goto out_page; } jffs2_complete_reservation(c); inode->i_size = pageofs; - mutex_unlock(&f->sem); } /* @@ -220,18 +223,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, * case of a short-copy. */ if (!PageUptodate(pg)) { - mutex_lock(&f->sem); ret = jffs2_do_readpage_nolock(inode, pg); - mutex_unlock(&f->sem); if (ret) goto out_page; } + mutex_unlock(&f->sem); jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); return ret; out_page: unlock_page(pg); page_cache_release(pg); + mutex_unlock(&f->sem); return ret; } From 45bc5c6913e04f1346bfe3401d2f52ad2164b3b2 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Tue, 6 Nov 2012 17:13:44 +0800 Subject: [PATCH 1641/2357] md: Reassigned the parameters if read_seqretry returned true in func md_is_badblock. commit ab05613a0646dcc11049692d54bae76ca9ffa910 upstream. This bug was introduced by commit(v3.0-rc7-126-g2230dfe). So fix is suitable for 3.0.y thru 3.6.y. Signed-off-by: Jianpeng Ma Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 529ce89b30b..2b399da4bba 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7694,9 +7694,9 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors, sector_t *first_bad, int *bad_sectors) { int hi; - int lo = 0; + int lo; u64 *p = bb->page; - int rv = 0; + int rv; sector_t target = s + sectors; unsigned seq; @@ -7711,7 +7711,8 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors, retry: seq = read_seqbegin(&bb->lock); - + lo = 0; + rv = 0; hi = bb->count; /* Binary search between lo and hi for 'target' From 8c98fbaa55508732bb5a9f46b3c6cf60daa8e526 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Thu, 8 Nov 2012 08:56:27 +0800 Subject: [PATCH 1642/2357] md: Avoid write invalid address if read_seqretry returned true. commit 35f9ac2dcec8f79d7059ce174fd7b7ee3290d620 upstream. If read_seqretry returned true and bbp was changed, it will write invalid address which can cause some serious problem. This bug was introduced by commit v3.0-rc7-130-g2699b67. So fix is suitable for 3.0.y thru 3.6.y. Reported-by: zhuwenfeng@kedacom.com Tested-by: zhuwenfeng@kedacom.com Signed-off-by: Jianpeng Ma Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 2b399da4bba..0a447a1be2c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1805,10 +1805,10 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev) memset(bbp, 0xff, PAGE_SIZE); for (i = 0 ; i < bb->count ; i++) { - u64 internal_bb = *p++; + u64 internal_bb = p[i]; u64 store_bb = ((BB_OFFSET(internal_bb) << 10) | BB_LEN(internal_bb)); - *bbp++ = cpu_to_le64(store_bb); + bbp[i] = cpu_to_le64(store_bb); } bb->changed = 0; if (read_seqretry(&bb->lock, seq)) From ecf049ce86e1d93bc9a3376facf31d7244338089 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 22 Nov 2012 15:12:09 +1100 Subject: [PATCH 1643/2357] md/raid10: decrement correct pending counter when writing to replacement. commit 884162df2aadd7414bef4935e1a54976fd4e3988 upstream. When a write to a replacement device completes, we carefully and correctly found the rdev that the write actually went to and the blithely called rdev_dec_pending on the primary rdev, even if this write was to the replacement. This means that any writes to an array while a replacement was ongoing would cause the nr_pending count for the primary device to go negative, so it could never be removed. This bug has been present since replacement was introduced in 3.3, so it is suitable for any -stable kernel since then. Reported-by: "George Spelvin" Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 4a038cdc0b5..a2b5304b4eb 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -476,7 +476,7 @@ static void raid10_end_write_request(struct bio *bio, int error) */ one_write_done(r10_bio); if (dec_rdev) - rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); + rdev_dec_pending(rdev, conf->mddev); } /* From f42513b9fd98a0f3afa8fe9bc23700b4226e1f6f Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 6 Nov 2012 12:24:26 +0100 Subject: [PATCH 1644/2357] dm: fix deadlock with request based dm and queue request_fn recursion commit a8c32a5c98943d370ea606a2e7dc04717eb92206 upstream. Request based dm attempts to re-run the request queue off the request completion path. If used with a driver that potentially does end_io from its request_fn, we could deadlock trying to recurse back into request dispatch. Fix this by punting the request queue run to kblockd. Tested to fix a quickly reproducible deadlock in such a scenario. Acked-by: Alasdair G Kergon Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 9ff3019790d..32370ea32e2 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -754,8 +754,14 @@ static void rq_completed(struct mapped_device *md, int rw, int run_queue) if (!md_in_flight(md)) wake_up(&md->wait); + /* + * Run this off this callpath, as drivers could invoke end_io while + * inside their request_fn (and holding the queue lock). Calling + * back into ->request_fn() could deadlock attempting to grab the + * queue lock again. + */ if (run_queue) - blk_run_queue(md->queue); + blk_run_queue_async(md->queue); /* * dm_put() must be at the end of this function. See the comment above From fceca5e72e787dd0a8ea29e22a874e363389356c Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Mon, 26 Nov 2012 16:29:56 -0800 Subject: [PATCH 1645/2357] futex: avoid wake_futex() for a PI futex_q commit aa10990e028cac3d5e255711fb9fb47e00700e35 upstream. Dave Jones reported a bug with futex_lock_pi() that his trinity test exposed. Sometime between queue_me() and taking the q.lock_ptr, the lock_ptr became NULL, resulting in a crash. While futex_wake() is careful to not call wake_futex() on futex_q's with a pi_state or an rt_waiter (which are either waiting for a futex_unlock_pi() or a PI futex_requeue()), futex_wake_op() and futex_requeue() do not perform the same test. Update futex_wake_op() and futex_requeue() to test for q.pi_state and q.rt_waiter and abort with -EINVAL if detected. To ensure any future breakage is caught, add a WARN() to wake_futex() if the same condition is true. This fix has seen 3 hours of testing with "trinity -c futex" on an x86_64 VM with 4 CPUS. [akpm@linux-foundation.org: tidy up the WARN()] Signed-off-by: Darren Hart Reported-by: Dave Jones Cc: Thomas Gleixner Cc: Peter Zijlstra Cc: Ingo Molnar Cc: John Kacur Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/futex.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/kernel/futex.c b/kernel/futex.c index 20ef219bbe9..19eb089ca00 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -843,6 +843,9 @@ static void wake_futex(struct futex_q *q) { struct task_struct *p = q->task; + if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n")) + return; + /* * We set q->lock_ptr = NULL _before_ we wake up the task. If * a non-futex wake up happens on another CPU then the task @@ -1078,6 +1081,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2, plist_for_each_entry_safe(this, next, head, list) { if (match_futex (&this->key, &key1)) { + if (this->pi_state || this->rt_waiter) { + ret = -EINVAL; + goto out_unlock; + } wake_futex(this); if (++ret >= nr_wake) break; @@ -1090,6 +1097,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2, op_ret = 0; plist_for_each_entry_safe(this, next, head, list) { if (match_futex (&this->key, &key2)) { + if (this->pi_state || this->rt_waiter) { + ret = -EINVAL; + goto out_unlock; + } wake_futex(this); if (++op_ret >= nr_wake2) break; @@ -1098,6 +1109,7 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2, ret += op_ret; } +out_unlock: double_unlock_hb(hb1, hb2); out_put_keys: put_futex_key(&key2); @@ -1387,9 +1399,13 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, /* * FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always * be paired with each other and no other futex ops. + * + * We should never be requeueing a futex_q with a pi_state, + * which is awaiting a futex_unlock_pi(). */ if ((requeue_pi && !this->rt_waiter) || - (!requeue_pi && this->rt_waiter)) { + (!requeue_pi && this->rt_waiter) || + this->pi_state) { ret = -EINVAL; break; } From e41cd8f166f6b9a0767dce3cbce65d1f4941b8ba Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Tue, 13 Nov 2012 18:43:03 +0100 Subject: [PATCH 1646/2357] mac80211: deinitialize ibss-internals after emptiness check commit b78a4932f5fb11fadf41e69c606a33fa6787574c upstream. The check whether the IBSS is active and can be removed should be performed before deinitializing the fields used for the check/search. Otherwise, the configured BSS will not be found and removed properly. To make it more clear for the future, rename sdata->u.ibss to the local pointer ifibss which is used within the checks. This behaviour was introduced by f3209bea110cade12e2b133da8b8499689cb0e2e ("mac80211: fix IBSS teardown race") Signed-off-by: Simon Wunderlich Cc: Ignacy Gawedzki Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ibss.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 4a3666b678e..7c51bae7f1c 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1153,10 +1153,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) mutex_lock(&sdata->u.ibss.mtx); - sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; - memset(sdata->u.ibss.bssid, 0, ETH_ALEN); - sdata->u.ibss.ssid_len = 0; - active_ibss = ieee80211_sta_active_ibss(sdata); if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { @@ -1177,6 +1173,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) } } + ifibss->state = IEEE80211_IBSS_MLME_SEARCH; + memset(ifibss->bssid, 0, ETH_ALEN); + ifibss->ssid_len = 0; + sta_info_flush(sdata->local, sdata); spin_lock_bh(&ifibss->incomplete_lock); From d6e782e1275740a5ca4c1a32cc9acfe1b6f82203 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Mon, 19 Nov 2012 21:17:31 +0100 Subject: [PATCH 1647/2357] radeon: add AGPMode 1 quirk for RV250 commit 45171002b01b2e2ec4f991eca81ffd8430fd0aec upstream. The Intel 82855PM host bridge / Mobility FireGL 9000 RV250 combination in an (outdated) ThinkPad T41 needs AGPMode 1 for suspend/resume (under KMS, that is). So add a quirk for it. (Change R250 to RV250 in comment for preceding quirk too.) Signed-off-by: Paul Bolle Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_agp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index bd2f33e5c91..bc6b64fe0e0 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -70,9 +70,12 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { /* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/ { PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59, PCI_VENDOR_ID_DELL, 0x00e3, 2}, - /* Intel 82852/82855 host bridge / Mobility FireGL 9000 R250 Needs AGPMode 1 (lp #296617) */ + /* Intel 82852/82855 host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 (lp #296617) */ { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66, PCI_VENDOR_ID_DELL, 0x0149, 1}, + /* Intel 82855PM host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 for suspend/resume */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66, + PCI_VENDOR_ID_IBM, 0x0531, 1}, /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */ { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, 0x1025, 0x0061, 1}, From 5e937c8ffe7d6ba56a699684a4bc5f6b3edd05a5 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 21 Nov 2012 22:43:59 +0100 Subject: [PATCH 1648/2357] can: peak_usb: fix hwtstamp assignment commit c9faaa09e2a1335678f09c70a0d0eda095564bab upstream. The skb->tstamp is set to the hardware timestamp when available in the USB urb message. This leads to user visible timestamps which contain the 'uptime' of the USB adapter - and not the usual system generated timestamp. Fix this wrong assignment by applying the available hardware timestamp to the skb_shared_hwtstamps data structure - which is intended for this purpose. Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/usb/peak_usb/pcan_usb.c | 8 ++++++-- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 86f26a1ede4..25723d8ee20 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -519,8 +519,10 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, mc->pdev->dev.can.state = new_state; if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) { + struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb); + peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts->hwtstamp = timeval_to_ktime(tv); } netif_rx(skb); @@ -605,6 +607,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) struct sk_buff *skb; struct can_frame *cf; struct timeval tv; + struct skb_shared_hwtstamps *hwts; skb = alloc_can_skb(mc->netdev, &cf); if (!skb) @@ -652,7 +655,8 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) /* convert timestamp into kernel time */ peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); /* push the skb */ netif_rx(skb); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 629c4ba5d49..c95913a0973 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -532,6 +532,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, struct can_frame *can_frame; struct sk_buff *skb; struct timeval tv; + struct skb_shared_hwtstamps *hwts; skb = alloc_can_skb(netdev, &can_frame); if (!skb) @@ -549,7 +550,8 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, memcpy(can_frame->data, rx->data, can_frame->can_dlc); peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(rx->ts32), &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); netif_rx(skb); netdev->stats.rx_packets++; @@ -570,6 +572,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, u8 err_mask = 0; struct sk_buff *skb; struct timeval tv; + struct skb_shared_hwtstamps *hwts; /* nothing should be sent while in BUS_OFF state */ if (dev->can.state == CAN_STATE_BUS_OFF) @@ -664,7 +667,8 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, dev->can.state = new_state; peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); netif_rx(skb); netdev->stats.rx_packets++; netdev->stats.rx_bytes += can_frame->can_dlc; From c9fa3f41a91e5c279968e5c9962b578aca003c98 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Mon, 26 Nov 2012 22:24:23 +0100 Subject: [PATCH 1649/2357] can: bcm: initialize ifindex for timeouts without previous frame reception commit 81b401100c01d2357031e874689f89bd788d13cd upstream. Set in the rx_ifindex to pass the correct interface index in the case of a message timeout detection. Usually the rx_ifindex value is set at receive time. But when no CAN frame has been received the RX_TIMEOUT notification did not contain a valid value. Reported-by: Andre Naujoks Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- net/can/bcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/can/bcm.c b/net/can/bcm.c index 151b7730c12..3910c1fefd0 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1084,6 +1084,9 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, op->sk = sk; op->ifindex = ifindex; + /* ifindex for timeout events w/o previous frame reception */ + op->rx_ifindex = ifindex; + /* initialize uninitialized (kzalloc) structure */ hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); op->timer.function = bcm_rx_timeout_handler; From acaf0ed4bdd03d31d0df0bf33816bdaceecbe7cc Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 23 Nov 2012 14:03:04 +0100 Subject: [PATCH 1650/2357] jbd: Fix lock ordering bug in journal_unmap_buffer() commit 25389bb207987b5774182f763b9fb65ff08761c8 upstream. Commit 09e05d48 introduced a wait for transaction commit into journal_unmap_buffer() in the case we are truncating a buffer undergoing commit in the page stradding i_size on a filesystem with blocksize < pagesize. Sadly we forgot to drop buffer lock before waiting for transaction commit and thus deadlock is possible when kjournald wants to lock the buffer. Fix the problem by dropping the buffer lock before waiting for transaction commit. Since we are still holding page lock (and that is OK), buffer cannot disappear under us. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/jbd/transaction.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 841cabc94df..ee959a9fed6 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1963,7 +1963,9 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); spin_unlock(&journal->j_state_lock); + unlock_buffer(bh); log_wait_commit(journal, tid); + lock_buffer(bh); goto retry; } /* From 98165e2b0d355759c16bae8d9ae09b445149cfbd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 18 Nov 2012 22:27:03 -0500 Subject: [PATCH 1651/2357] sparc64: not any error from do_sigaltstack() should fail rt_sigreturn() commit fae2ae2a900a5c7bb385fe4075f343e7e2d5daa2 upstream. If a signal handler is executed on altstack and another signal comes, we will end up with rt_sigreturn() on return from the second handler getting -EPERM from do_sigaltstack(). It's perfectly OK, since we are not asking to change the settings; in fact, they couldn't have been changed during the second handler execution exactly because we'd been on altstack all along. 64bit sigreturn on sparc treats any error from do_sigaltstack() as "SIGSEGV now"; we need to switch to the same semantics we are using on other architectures. Signed-off-by: Al Viro Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/signal_64.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 48b0f57b65f..40837f07143 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -309,9 +309,7 @@ void do_rt_sigreturn(struct pt_regs *regs) err |= restore_fpu_state(regs, fpu_save); err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); - err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf); - - if (err) + if (err || do_sigaltstack(&sf->stack, NULL, (unsigned long)sf) == -EFAULT) goto segv; err |= __get_user(rwin_save, &sf->rwin_save); From c4e9e580078376f7fd53fcf3a27f3a1259ebe463 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 23 Nov 2012 20:55:06 +0100 Subject: [PATCH 1652/2357] PM / QoS: fix wrong error-checking condition commit a7227a0faa117d0bc532aea546ae5ac5f89e8ed7 upstream. dev_pm_qos_add_request() can return 0, 1, or a negative error code, therefore the correct error test is "if (error < 0)." Checking just for non-zero return code leads to erroneous setting of the req->dev pointer to NULL, which then leads to a repeated call to dev_pm_qos_add_ancestor_request() in st1232_ts_irq_handler(). This in turn leads to an Oops, when the I2C host adapter is unloaded and reloaded again because of the inconsistent state of its QoS request list. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/qos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 71855570922..c365c93abe1 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -446,7 +446,7 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, if (ancestor) error = dev_pm_qos_add_request(ancestor, req, value); - if (error) + if (error < 0) req->dev = NULL; return error; From e5f56030f487d3dbcc28be40cdecb8e43888dfa0 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Sat, 6 Oct 2012 17:02:30 +0200 Subject: [PATCH 1653/2357] ALSA: hda - Add new codec ALC283 ALC290 support commit 7ff34ad80b7080fafaac8efa9ef0061708eddd51 upstream. These are compatible with standard ALC269 parser. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 257fe87c4c0..e6e44205bb2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7035,6 +7035,8 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 }, { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, + { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, + { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, From 510add68ecdbc4ec3731248acf575753945f43ac Mon Sep 17 00:00:00 2001 From: Duncan Roe Date: Wed, 10 Oct 2012 14:19:50 +0200 Subject: [PATCH 1654/2357] ALSA: hda - Fix missing beep on ASUS X43U notebook commit 7110005e8d5c3cd418fc4b64f9f124f004422a9a upstream. Signed-off-by: Duncan Roe Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e6e44205bb2..d297fa73770 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4322,6 +4322,7 @@ static void alc_auto_init_std(struct hda_codec *codec) ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) static const struct snd_pci_quirk beep_white_list[] = { + SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), From 06096cf239242e915ee13c48c10306828c828527 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 21 Nov 2012 08:57:58 +0100 Subject: [PATCH 1655/2357] ALSA: hda - Add support for Realtek ALC292 commit af02dde8a609d8d071c4b31a82df811a55690a4a upstream. We found a new codec ID 292, and that just a simple quirk would enable sound output/input on this ALC292 chip. BugLink: https://bugs.launchpad.net/bugs/1081466 Tested-by: Acelan Kao Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d297fa73770..29774e22bda 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7038,6 +7038,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, + { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, From 6495a1b5bc6f9e55eff414975609fef9e4a73662 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 24 Oct 2012 08:44:32 +0000 Subject: [PATCH 1656/2357] bas_gigaset: fix pre_reset handling commit c6fdd8e5d0c65bb8821dc6da26ee1a2ddd58b3cc upstream. The delayed work function int_in_work() may call usb_reset_device() and thus, indirectly, the driver's pre_reset method. Trying to cancel the work synchronously in that situation would deadlock. Fix by avoiding cancel_work_sync() in the pre_reset method. If the reset was NOT initiated by int_in_work() this might cause int_in_work() to run after the post_reset method, with urb_int_in already resubmitted, so handle that case gracefully. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/gigaset/bas-gigaset.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index afa080258bf..5e1bf61e80e 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -616,7 +616,13 @@ static void int_in_work(struct work_struct *work) if (rc == 0) /* success, resubmit interrupt read URB */ rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc != 0 && rc != -ENODEV) { + + switch (rc) { + case 0: /* success */ + case -ENODEV: /* device gone */ + case -EINVAL: /* URB already resubmitted, or terminal badness */ + break; + default: /* failure: try to recover by resetting the device */ dev_err(cs->dev, "clear halt failed: %s\n", get_usb_rcmsg(rc)); rc = usb_lock_device_for_reset(ucs->udev, ucs->interface); if (rc == 0) { @@ -2437,7 +2443,9 @@ static void gigaset_disconnect(struct usb_interface *interface) } /* gigaset_suspend - * This function is called before the USB connection is suspended. + * This function is called before the USB connection is suspended + * or before the USB device is reset. + * In the latter case, message == PMSG_ON. */ static int gigaset_suspend(struct usb_interface *intf, pm_message_t message) { @@ -2493,7 +2501,12 @@ static int gigaset_suspend(struct usb_interface *intf, pm_message_t message) del_timer_sync(&ucs->timer_atrdy); del_timer_sync(&ucs->timer_cmd_in); del_timer_sync(&ucs->timer_int_in); - cancel_work_sync(&ucs->int_in_wq); + + /* don't try to cancel int_in_wq from within reset as it + * might be the one requesting the reset + */ + if (message.event != PM_EVENT_ON) + cancel_work_sync(&ucs->int_in_wq); gig_dbg(DEBUG_SUSPEND, "suspend complete"); return 0; From 5042a551a4805f73c82b5fba0a3c4cc2e372665c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 15 Jun 2012 12:52:46 +0200 Subject: [PATCH 1657/2357] scsi: Silence unnecessary warnings about ioctl to partition commit 6d9359280753d2955f86d6411047516a9431eb51 upstream. Sometimes, warnings about ioctls to partition happen often enough that they form majority of the warnings in the kernel log and users complain. In some cases warnings are about ioctls such as SG_IO so it's not good to get rid of the warnings completely as they can ease debugging of userspace problems when ioctl is refused. Since I have seen warnings from lots of commands, including some proprietary userspace applications, I don't think disallowing the ioctls for processes with CAP_SYS_RAWIO will happen in the near future if ever. So lets just stop warning for processes with CAP_SYS_RAWIO for which ioctl is allowed. Acked-by: Paolo Bonzini CC: Paolo Bonzini CC: James Bottomley Signed-off-by: Jan Kara Signed-off-by: Jens Axboe Cc: satoru takeuchi Signed-off-by: Greg Kroah-Hartman --- block/scsi_ioctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 260fa80ef57..9a87daa6f4f 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -721,11 +721,14 @@ int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd) break; } + if (capable(CAP_SYS_RAWIO)) + return 0; + /* In particular, rule out all resets and host-specific ioctls. */ printk_ratelimited(KERN_WARNING "%s: sending ioctl %x to a partition!\n", current->comm, cmd); - return capable(CAP_SYS_RAWIO) ? 0 : -ENOIOCTLCMD; + return -ENOIOCTLCMD; } EXPORT_SYMBOL(scsi_verify_blk_ioctl); From 865c6f7f4ddc972735cb6bc34a70370df537c650 Mon Sep 17 00:00:00 2001 From: Petr Matousek Date: Tue, 6 Nov 2012 19:24:07 +0100 Subject: [PATCH 1658/2357] KVM: x86: invalid opcode oops on SET_SREGS with OSXSAVE bit set (CVE-2012-4461) commit 6d1068b3a98519247d8ba4ec85cd40ac136dbdf9 upstream. On hosts without the XSAVE support unprivileged local user can trigger oops similar to the one below by setting X86_CR4_OSXSAVE bit in guest cr4 register using KVM_SET_SREGS ioctl and later issuing KVM_RUN ioctl. invalid opcode: 0000 [#2] SMP Modules linked in: tun ip6table_filter ip6_tables ebtable_nat ebtables ... Pid: 24935, comm: zoog_kvm_monito Tainted: G D 3.2.0-3-686-pae EIP: 0060:[] EFLAGS: 00210246 CPU: 0 EIP is at kvm_arch_vcpu_ioctl_run+0x92a/0xd13 [kvm] EAX: 00000001 EBX: 000f387e ECX: 00000000 EDX: 00000000 ESI: 00000000 EDI: 00000000 EBP: ef5a0060 ESP: d7c63e70 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Process zoog_kvm_monito (pid: 24935, ti=d7c62000 task=ed84a0c0 task.ti=d7c62000) Stack: 00000001 f70a1200 f8b940a9 ef5a0060 00000000 00200202 f8769009 00000000 ef5a0060 000f387e eda5c020 8722f9c8 00015bae 00000000 ed84a0c0 ed84a0c0 c12bf02d 0000ae80 ef7f8740 fffffffb f359b740 ef5a0060 f8b85dc1 0000ae80 Call Trace: [] ? kvm_arch_vcpu_ioctl_set_sregs+0x2fe/0x308 [kvm] ... [] ? syscall_call+0x7/0xb Code: 89 e8 e8 14 ee ff ff ba 00 00 04 00 89 e8 e8 98 48 ff ff 85 c0 74 1e 83 7d 48 00 75 18 8b 85 08 07 00 00 31 c9 8b 95 0c 07 00 00 <0f> 01 d1 c7 45 48 01 00 00 00 c7 45 1c 01 00 00 00 0f ae f0 89 EIP: [] kvm_arch_vcpu_ioctl_run+0x92a/0xd13 [kvm] SS:ESP 0068:d7c63e70 QEMU first retrieves the supported features via KVM_GET_SUPPORTED_CPUID and then sets them later. So guest's X86_FEATURE_XSAVE should be masked out on hosts without X86_FEATURE_XSAVE, making kvm_set_cr4 with X86_CR4_OSXSAVE fail. Userspaces that allow specifying guest cpuid with X86_FEATURE_XSAVE even on hosts that do not support it, might be susceptible to this attack from inside the guest as well. Allow setting X86_CR4_OSXSAVE bit only if host has XSAVE support. Signed-off-by: Petr Matousek Signed-off-by: Marcelo Tosatti Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/cpuid.h | 3 +++ arch/x86/kvm/x86.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 26d1fb437eb..638de3efd7a 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -23,6 +23,9 @@ static inline bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; + if (!static_cpu_has(X86_FEATURE_XSAVE)) + return 0; + best = kvm_find_cpuid_entry(vcpu, 1, 0); return best && (best->ecx & bit(X86_FEATURE_XSAVE)); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 185a2b823a2..e28fb97a1a8 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5697,6 +5697,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, int pending_vec, max_bits, idx; struct desc_ptr dt; + if (!guest_cpuid_has_xsave(vcpu) && (sregs->cr4 & X86_CR4_OSXSAVE)) + return -EINVAL; + dt.size = sregs->idt.limit; dt.address = sregs->idt.base; kvm_x86_ops->set_idt(vcpu, &dt); From 65c03b4c0598a71e125a96985f5a402347f7ffb3 Mon Sep 17 00:00:00 2001 From: "joshua.a.hay@intel.com" Date: Fri, 21 Sep 2012 00:08:21 +0000 Subject: [PATCH 1659/2357] ixgbe: add support for X540-AT1 commit df376f0de167754da9b3ece4afdb5bb8bf3fbf3e upstream. This patch adds device support for Ethernet Controller X540-AT1. Signed-off-by: Josh Hay Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher Signed-off-by: Abdallah Chatila Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 ++ drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 1 + 4 files changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 49aa41fe7b8..ab4d4d219e3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -3216,6 +3216,7 @@ static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) switch (hw->device_id) { case IXGBE_DEV_ID_X540T: + case IXGBE_DEV_ID_X540T1: return 0; case IXGBE_DEV_ID_82599_T3_LOM: return 0; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index cfe7d269590..6757d6c30fe 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2006,6 +2006,7 @@ static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter, retval = 0; break; case IXGBE_DEV_ID_X540T: + case IXGBE_DEV_ID_X540T1: /* check eeprom to see if enabled wol */ if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) || ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) && diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index a66c2159b1f..6d1f6c51262 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -114,6 +114,7 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = { {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599EN_SFP), board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF_QP), board_82599 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T1), board_X540 }, /* required last entry */ {0, } }; @@ -7060,6 +7061,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, adapter->wol = IXGBE_WUFC_MAG; break; case IXGBE_DEV_ID_X540T: + case IXGBE_DEV_ID_X540T1: /* Check eeprom to see if it is enabled */ hw->eeprom.ops.read(hw, 0x2c, &adapter->eeprom_cap); wol_cap = adapter->eeprom_cap & IXGBE_DEVICE_CAPS_WOL_MASK; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 8636e8344fc..37eb39c013a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -67,6 +67,7 @@ #define IXGBE_DEV_ID_82599_LS 0x154F #define IXGBE_DEV_ID_X540T 0x1528 #define IXGBE_DEV_ID_82599_SFP_SF_QP 0x154A +#define IXGBE_DEV_ID_X540T1 0x1560 /* VF Device IDs */ #define IXGBE_DEV_ID_82599_VF 0x10ED From 08ecfb7dd2e41f8aa9bd57468e09fdc5bbbc2ec6 Mon Sep 17 00:00:00 2001 From: David Milburn Date: Mon, 29 Oct 2012 18:00:22 -0500 Subject: [PATCH 1660/2357] sata_svw: check DMA start bit before reset commit b03e66a6be91f8389fcd902ab6c1563db1c9c06b upstream. If kdump is triggered with pending IO, controller may not respond causing kdump to fail. http://marc.info/?l=linux-ide&m=133032255424658&w=2 During error recovery ata_do_dev_read_id never completes due hang in mmio_insw. ata_do_dev_read_id ata_sff_data_xfer ioread16_rep mmio_insw if DMA start bit is cleared before reset, PIO command is successful and kdump succeeds. Signed-off-by: David Milburn Signed-off-by: Jeff Garzik Cc: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/ata/sata_svw.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index c646118943f..833607f5ae4 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -142,6 +142,39 @@ static int k2_sata_scr_write(struct ata_link *link, return 0; } +static int k2_sata_softreset(struct ata_link *link, + unsigned int *class, unsigned long deadline) +{ + u8 dmactl; + void __iomem *mmio = link->ap->ioaddr.bmdma_addr; + + dmactl = readb(mmio + ATA_DMA_CMD); + + /* Clear the start bit */ + if (dmactl & ATA_DMA_START) { + dmactl &= ~ATA_DMA_START; + writeb(dmactl, mmio + ATA_DMA_CMD); + } + + return ata_sff_softreset(link, class, deadline); +} + +static int k2_sata_hardreset(struct ata_link *link, + unsigned int *class, unsigned long deadline) +{ + u8 dmactl; + void __iomem *mmio = link->ap->ioaddr.bmdma_addr; + + dmactl = readb(mmio + ATA_DMA_CMD); + + /* Clear the start bit */ + if (dmactl & ATA_DMA_START) { + dmactl &= ~ATA_DMA_START; + writeb(dmactl, mmio + ATA_DMA_CMD); + } + + return sata_sff_hardreset(link, class, deadline); +} static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { @@ -346,6 +379,8 @@ static struct scsi_host_template k2_sata_sht = { static struct ata_port_operations k2_sata_ops = { .inherits = &ata_bmdma_port_ops, + .softreset = k2_sata_softreset, + .hardreset = k2_sata_hardreset, .sff_tf_load = k2_sata_tf_load, .sff_tf_read = k2_sata_tf_read, .sff_check_status = k2_stat_check_status, From 9cfb66219d6e5840df9c4cf06fff70e072be1409 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 28 Sep 2012 16:16:00 -0300 Subject: [PATCH 1661/2357] get_dvb_firmware: fix download site for tda10046 firmware commit 25ec43d3e6306978cf66060ed18c4160ce8fc302 upstream. The previous website doesn't exist anymore. Update it to one site that actually exists. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- Documentation/dvb/get_dvb_firmware | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index d1d4a179a38..b361e08570f 100755 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -115,7 +115,7 @@ sub tda10045 { sub tda10046 { my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip"; - my $url = "http://www.tt-download.com/download/updates/219/$sourcefile"; + my $url = "http://technotrend.com.ua/download/software/219/$sourcefile"; my $hash = "6a7e1e2f2644b162ff0502367553c72d"; my $outfile = "dvb-fe-tda10046.fw"; my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); From c09221cefdbd669883f94ff62f055d270df85feb Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 29 Oct 2012 14:04:43 +0100 Subject: [PATCH 1662/2357] NFC: pn533: Fix use after free commit 770f750bc2b8312489c8e45306f551d08a319d3c upstream. cmd was freed in pn533_dep_link_up regardless of pn533_send_cmd_frame_async return code. Cmd is passed as argument to pn533_in_dep_link_up_complete callback and should be freed there. Signed-off-by: Szymon Janc Signed-off-by: Samuel Ortiz Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/nfc/pn533.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index cb6204f7830..eeb0d59e17f 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1385,12 +1385,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx, rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame, dev->in_maxlen, pn533_in_dep_link_up_complete, cmd, GFP_KERNEL); - if (rc) - goto out; - - -out: - kfree(cmd); + if (rc < 0) + kfree(cmd); return rc; } From b127f3f930bbeedc3b10b150a4f43a6abeb75836 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 11 Oct 2012 14:04:00 +0200 Subject: [PATCH 1663/2357] NFC: pn533: Fix mem leak in pn533_in_dep_link_up commit 70418e6efcf4f8652cc08e3f2ab8ae35f0948fd9 upstream. cmd is allocated in pn533_dep_link_up and passed as an arg to pn533_send_cmd_frame_async together with a complete cb. arg is passed to the cb and must be kfreed there. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/nfc/pn533.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index eeb0d59e17f..692bd1e8d6b 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1278,11 +1278,14 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, u8 *params, int params_len) { - struct pn533_cmd_jump_dep *cmd; struct pn533_cmd_jump_dep_response *resp; struct nfc_target nfc_target; u8 target_gt_len; int rc; + struct pn533_cmd_jump_dep *cmd = (struct pn533_cmd_jump_dep *)arg; + u8 active = cmd->active; + + kfree(arg); if (params_len == -ENOENT) { nfc_dev_dbg(&dev->interface->dev, ""); @@ -1304,7 +1307,6 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, } resp = (struct pn533_cmd_jump_dep_response *) params; - cmd = (struct pn533_cmd_jump_dep *) arg; rc = resp->status & PN533_CMD_RET_MASK; if (rc != PN533_CMD_RET_SUCCESS) { nfc_dev_err(&dev->interface->dev, @@ -1334,7 +1336,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, if (rc == 0) rc = nfc_dep_link_is_up(dev->nfc_dev, dev->nfc_dev->targets[0].idx, - !cmd->active, NFC_RF_INITIATOR); + !active, NFC_RF_INITIATOR); return 0; } From 47abf714aab1e2f5c293f54a3bd3f0ef7534c38e Mon Sep 17 00:00:00 2001 From: Thierry Escande Date: Fri, 12 Oct 2012 15:25:43 +0200 Subject: [PATCH 1664/2357] NFC: Fix nfc_llcp_local chained list insertion commit 16a78e9fed5e8baa8480ae3413f4328c4537c599 upstream. list_add was called with swapped parameters Signed-off-by: Thierry Escande Signed-off-by: Samuel Ortiz Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- net/nfc/llcp/llcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 17a578f641f..c40112c39e1 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -966,7 +966,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) local->remote_lto = LLCP_DEFAULT_LTO; local->remote_rw = LLCP_DEFAULT_RW; - list_add(&llcp_devices, &local->list); + list_add(&local->list, &llcp_devices); return 0; From 368c8c73d4648843bece41f7c083f11fa4d1aa36 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Oct 2012 10:29:14 +0200 Subject: [PATCH 1665/2357] USB: mct_u232: fix broken close commit 5260e458f5eff269a43e4f1e9c47186c57b88ddb upstream. Make sure generic close is called at close. The driver relies on the generic write implementation but did not call generic close. Note that the call to kill the read urb is not redundant, as mct_u232 uses an interrupt urb from the second port as the read urb and that generic close therefore fails to kill it. Compile-only tested. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings --- drivers/usb/serial/mct_u232.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index ef4d7adfbd9..d0bf56dba07 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -533,12 +533,14 @@ static void mct_u232_close(struct usb_serial_port *port) { dbg("%s port %d", __func__, port->number); - if (port->serial->dev) { - /* shutdown our urbs */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - } + /* + * Must kill the read urb as it is actually an interrupt urb, which + * generic close thus fails to kill. + */ + usb_kill_urb(port->read_urb); + usb_kill_urb(port->interrupt_in_urb); + + usb_serial_generic_close(port); } /* mct_u232_close */ From 53b360c604575070c83d2da83636af4e5c5de35a Mon Sep 17 00:00:00 2001 From: Chuansheng Liu Date: Mon, 26 Nov 2012 16:29:54 -0800 Subject: [PATCH 1666/2357] watchdog: using u64 in get_sample_period() commit 8ffeb9b0e6369135bf03a073514f571ef10606b9 upstream. In get_sample_period(), unsigned long is not enough: watchdog_thresh * 2 * (NSEC_PER_SEC / 5) case1: watchdog_thresh is 10 by default, the sample value will be: 0xEE6B2800 case2: set watchdog_thresh is 20, the sample value will be: 0x1 DCD6 5000 In case2, we need use u64 to express the sample period. Otherwise, changing the threshold thru proc often can not be successful. Signed-off-by: liu chuansheng Acked-by: Don Zickus Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- kernel/watchdog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index df30ee08bdd..991aa9381a4 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -112,7 +112,7 @@ static unsigned long get_timestamp(int this_cpu) return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */ } -static unsigned long get_sample_period(void) +static u64 get_sample_period(void) { /* * convert watchdog_thresh from seconds to ns @@ -121,7 +121,7 @@ static unsigned long get_sample_period(void) * and hard thresholds) to increment before the * hardlockup detector generates a warning */ - return get_softlockup_thresh() * (NSEC_PER_SEC / 5); + return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5); } /* Commands for resetting the watchdog */ From 7da2f8907ba51acd7d13dd62e71f14972e9b5161 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Thu, 22 Nov 2012 11:58:22 +0100 Subject: [PATCH 1667/2357] MPI: Fix compilation on MIPS with GCC 4.4 and newer commit a3cea9894157c20a5b1ec08b7e0b5f2019740c10 upstream. Since 4.4 GCC on MIPS no longer recognizes the "h" constraint, leading to this build failure: CC lib/mpi/generic_mpih-mul1.o lib/mpi/generic_mpih-mul1.c: In function 'mpihelp_mul_1': lib/mpi/generic_mpih-mul1.c:50:3: error: impossible constraint in 'asm' This patch updates MPI with the latest umul_ppm implementations for MIPS. Signed-off-by: Manuel Lauss Cc: Linux-MIPS Cc: Dmitry Kasatkin Cc: James Morris Patchwork: https://patchwork.linux-mips.org/patch/4612/ Signed-off-by: Ralf Baechle Cc: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- lib/mpi/longlong.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h index 29f98624ef9..280405b47e7 100644 --- a/lib/mpi/longlong.h +++ b/lib/mpi/longlong.h @@ -703,7 +703,14 @@ do { \ ************** MIPS ***************** ***************************************/ #if defined(__mips__) && W_TYPE_SIZE == 32 -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#define umul_ppmm(w1, w0, u, v) \ +do { \ + UDItype __ll = (UDItype)(u) * (v); \ + w1 = __ll >> 32; \ + w0 = __ll; \ +} while (0) +#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7 #define umul_ppmm(w1, w0, u, v) \ __asm__ ("multu %2,%3" \ : "=l" ((USItype)(w0)), \ @@ -728,7 +735,15 @@ do { \ ************** MIPS/64 ************** ***************************************/ #if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64 -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#define umul_ppmm(w1, w0, u, v) \ +do { \ + typedef unsigned int __ll_UTItype __attribute__((mode(TI))); \ + __ll_UTItype __ll = (__ll_UTItype)(u) * (v); \ + w1 = __ll >> 64; \ + w0 = __ll; \ +} while (0) +#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7 #define umul_ppmm(w1, w0, u, v) \ __asm__ ("dmultu %2,%3" \ : "=l" ((UDItype)(w0)), \ From ee746ff6943cea07e9866e78307154f539440c57 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 17 Sep 2012 04:34:27 +0000 Subject: [PATCH 1668/2357] powerpc/eeh: Lock module while handling EEH event commit feadf7c0a1a7c08c74bebb4a13b755f8c40e3bbc upstream. The EEH core is talking with the PCI device driver to determine the action (purely reset, or PCI device removal). During the period, the driver might be unloaded and in turn causes kernel crash as follows: EEH: Detected PCI bus error on PHB#4-PE#10000 EEH: This PCI device has failed 3 times in the last hour lpfc 0004:01:00.0: 0:2710 PCI channel disable preparing for reset Unable to handle kernel paging request for data at address 0x00000490 Faulting instruction address: 0xd00000000e682c90 cpu 0x1: Vector: 300 (Data Access) at [c000000fc75ffa20] pc: d00000000e682c90: .lpfc_io_error_detected+0x30/0x240 [lpfc] lr: d00000000e682c8c: .lpfc_io_error_detected+0x2c/0x240 [lpfc] sp: c000000fc75ffca0 msr: 8000000000009032 dar: 490 dsisr: 40000000 current = 0xc000000fc79b88b0 paca = 0xc00000000edb0380 softe: 0 irq_happened: 0x00 pid = 3386, comm = eehd enter ? for help [c000000fc75ffca0] c000000fc75ffd30 (unreliable) [c000000fc75ffd30] c00000000004fd3c .eeh_report_error+0x7c/0xf0 [c000000fc75ffdc0] c00000000004ee00 .eeh_pe_dev_traverse+0xa0/0x180 [c000000fc75ffe70] c00000000004ffd8 .eeh_handle_event+0x68/0x300 [c000000fc75fff00] c0000000000503a0 .eeh_event_handler+0x130/0x1a0 [c000000fc75fff90] c000000000020138 .kernel_thread+0x54/0x70 1:mon> The patch increases the reference of the corresponding driver modules while EEH core does the negotiation with PCI device driver so that the corresponding driver modules can't be unloaded during the period and we're safe to refer the callbacks. Reported-by: Alexey Kardashevskiy Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt [ herton: backported for 3.5, adjusted driver assignments, return 0 instead of NULL, assume dev is not NULL ] Signed-off-by: Herton Ronaldo Krzesinski Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/eeh_driver.c | 95 ++++++++++++++++----- 1 file changed, 74 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index baf92cd9dfa..041e28d0e70 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,41 @@ static inline const char *eeh_pcid_name(struct pci_dev *pdev) return ""; } +/** + * eeh_pcid_get - Get the PCI device driver + * @pdev: PCI device + * + * The function is used to retrieve the PCI device driver for + * the indicated PCI device. Besides, we will increase the reference + * of the PCI device driver to prevent that being unloaded on + * the fly. Otherwise, kernel crash would be seen. + */ +static inline struct pci_driver *eeh_pcid_get(struct pci_dev *pdev) +{ + if (!pdev || !pdev->driver) + return NULL; + + if (!try_module_get(pdev->driver->driver.owner)) + return NULL; + + return pdev->driver; +} + +/** + * eeh_pcid_put - Dereference on the PCI device driver + * @pdev: PCI device + * + * The function is called to do dereference on the PCI device + * driver of the indicated PCI device. + */ +static inline void eeh_pcid_put(struct pci_dev *pdev) +{ + if (!pdev || !pdev->driver) + return; + + module_put(pdev->driver->driver.owner); +} + #if 0 static void print_device_node_tree(struct pci_dn *pdn, int dent) { @@ -126,18 +162,20 @@ static void eeh_enable_irq(struct pci_dev *dev) static int eeh_report_error(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; - struct pci_driver *driver = dev->driver; + struct pci_driver *driver; dev->error_state = pci_channel_io_frozen; - if (!driver) - return 0; + driver = eeh_pcid_get(dev); + if (!driver) return 0; eeh_disable_irq(dev); if (!driver->err_handler || - !driver->err_handler->error_detected) + !driver->err_handler->error_detected) { + eeh_pcid_put(dev); return 0; + } rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); @@ -145,6 +183,7 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; if (*res == PCI_ERS_RESULT_NONE) *res = rc; + eeh_pcid_put(dev); return 0; } @@ -160,12 +199,16 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; - struct pci_driver *driver = dev->driver; + struct pci_driver *driver; + + driver = eeh_pcid_get(dev); + if (!driver) return 0; - if (!driver || - !driver->err_handler || - !driver->err_handler->mmio_enabled) + if (!driver->err_handler || + !driver->err_handler->mmio_enabled) { + eeh_pcid_put(dev); return 0; + } rc = driver->err_handler->mmio_enabled(dev); @@ -173,6 +216,7 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; if (*res == PCI_ERS_RESULT_NONE) *res = rc; + eeh_pcid_put(dev); return 0; } @@ -189,18 +233,20 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) static int eeh_report_reset(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; - struct pci_driver *driver = dev->driver; - - if (!driver) - return 0; + struct pci_driver *driver; dev->error_state = pci_channel_io_normal; + driver = eeh_pcid_get(dev); + if (!driver) return 0; + eeh_enable_irq(dev); if (!driver->err_handler || - !driver->err_handler->slot_reset) + !driver->err_handler->slot_reset) { + eeh_pcid_put(dev); return 0; + } rc = driver->err_handler->slot_reset(dev); if ((*res == PCI_ERS_RESULT_NONE) || @@ -208,6 +254,7 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata) if (*res == PCI_ERS_RESULT_DISCONNECT && rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; + eeh_pcid_put(dev); return 0; } @@ -222,21 +269,24 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata) */ static int eeh_report_resume(struct pci_dev *dev, void *userdata) { - struct pci_driver *driver = dev->driver; + struct pci_driver *driver; dev->error_state = pci_channel_io_normal; - if (!driver) - return 0; + driver = eeh_pcid_get(dev); + if (!driver) return 0; eeh_enable_irq(dev); if (!driver->err_handler || - !driver->err_handler->resume) + !driver->err_handler->resume) { + eeh_pcid_put(dev); return 0; + } driver->err_handler->resume(dev); + eeh_pcid_put(dev); return 0; } @@ -250,21 +300,24 @@ static int eeh_report_resume(struct pci_dev *dev, void *userdata) */ static int eeh_report_failure(struct pci_dev *dev, void *userdata) { - struct pci_driver *driver = dev->driver; + struct pci_driver *driver; dev->error_state = pci_channel_io_perm_failure; - if (!driver) - return 0; + driver = eeh_pcid_get(dev); + if (!driver) return 0; eeh_disable_irq(dev); if (!driver->err_handler || - !driver->err_handler->error_detected) + !driver->err_handler->error_detected) { + eeh_pcid_put(dev); return 0; + } driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); + eeh_pcid_put(dev); return 0; } From fc6058e1a4cc1f76aab5c580322e109cf448ec9b Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Wed, 19 Sep 2012 14:43:33 +0800 Subject: [PATCH 1669/2357] mmc: sdhci-s3c: fix the wrong number of max bus clocks commit 5feb54a1ab91a237e247c013b8c4fb100ea347b1 upstream. We can use up to four bus-clocks; but on module remove, we didn't disable the fourth bus clock. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Signed-off-by: Chris Ball Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-s3c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 55a164fcaa1..9e2c5585efa 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -656,7 +656,7 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - for (ptr = 0; ptr < 3; ptr++) { + for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { if (sc->clk_bus[ptr]) { clk_disable(sc->clk_bus[ptr]); clk_put(sc->clk_bus[ptr]); From e84ad739d8a2143e5cd284a4c0462278587e4aa3 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 8 Oct 2012 14:01:12 -0700 Subject: [PATCH 1670/2357] ARM: OMAP: counter: add locking to read_persistent_clock commit 9d7d6e363b06934221b81a859d509844c97380df upstream. read_persistent_clock uses a global variable, use a spinlock to ensure non-atomic updates to the variable don't overlap and cause time to move backwards. Signed-off-by: Colin Cross Signed-off-by: R Sricharan Signed-off-by: Tony Lindgren [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-omap/counter_32k.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c index 5068fe5a691..fd433e7a25f 100644 --- a/arch/arm/plat-omap/counter_32k.c +++ b/arch/arm/plat-omap/counter_32k.c @@ -50,22 +50,29 @@ static u32 notrace omap_32k_read_sched_clock(void) * nsecs and adds to a monotonically increasing timespec. */ static struct timespec persistent_ts; -static cycles_t cycles, last_cycles; +static cycles_t cycles; static unsigned int persistent_mult, persistent_shift; +static DEFINE_SPINLOCK(read_persistent_clock_lock); + void read_persistent_clock(struct timespec *ts) { unsigned long long nsecs; - cycles_t delta; - struct timespec *tsp = &persistent_ts; + cycles_t last_cycles; + unsigned long flags; + + spin_lock_irqsave(&read_persistent_clock_lock, flags); last_cycles = cycles; cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0; - delta = cycles - last_cycles; - nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift); + nsecs = clocksource_cyc2ns(cycles - last_cycles, + persistent_mult, persistent_shift); + + timespec_add_ns(&persistent_ts, nsecs); + + *ts = persistent_ts; - timespec_add_ns(tsp, nsecs); - *ts = *tsp; + spin_unlock_irqrestore(&read_persistent_clock_lock, flags); } int __init omap_init_clocksource_32k(void) From 1103ef8e70a1725b7fd9e0cb18a8b1edb6e5c42d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Oct 2012 10:18:23 +0300 Subject: [PATCH 1671/2357] timekeeping: Cast raw_interval to u64 to avoid shift overflow commit 5b3900cd409466c0070b234d941650685ad0c791 upstream. We fixed a bunch of integer overflows in timekeeping code during the 3.6 cycle. I did an audit based on that and found this potential overflow. Signed-off-by: Dan Carpenter Acked-by: John Stultz Link: http://lkml.kernel.org/r/20121009071823.GA19159@elgon.mountain Signed-off-by: Thomas Gleixner Cc: Ben Hutchings [ herton: adapt for 3.5, timekeeper instead of tk pointer ] Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Greg Kroah-Hartman --- kernel/time/timekeeping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 12843e9f6d5..eff0b1e9633 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1014,7 +1014,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) } /* Accumulate raw time */ - raw_nsecs = timekeeper.raw_interval << shift; + raw_nsecs = (u64)timekeeper.raw_interval << shift; raw_nsecs += timekeeper.raw_time.tv_nsec; if (raw_nsecs >= NSEC_PER_SEC) { u64 raw_secs = raw_nsecs; From bffeb2a91830ad2ad841b3d1203d6c7724099d8d Mon Sep 17 00:00:00 2001 From: Stanislav Yakovlev Date: Mon, 15 Oct 2012 14:14:32 +0000 Subject: [PATCH 1672/2357] net/wireless: ipw2200: Fix panic occurring in ipw_handle_promiscuous_tx() commit bf11315eeda510ea4fc1a2bf972d8155d31d89b4 upstream. The driver does not count space of radiotap fields when allocating skb for radiotap packet. This leads to kernel panic with the following call trace: ... [67607.676067] [] error_code+0x67/0x6c [67607.676067] [] ? skb_put+0x91/0xa0 [67607.676067] [] ? ipw_handle_promiscuous_tx+0x16b/0x2d0 [ipw2200] [67607.676067] [] ipw_handle_promiscuous_tx+0x16b/0x2d0 [ipw2200] [67607.676067] [] ipw_net_hard_start_xmit+0x8b/0x90 [ipw2200] [67607.676067] [] libipw_xmit+0x55a/0x980 [libipw] [67607.676067] [] dev_hard_start_xmit+0x218/0x4d0 ... This bug was found by VittGam. https://bugzilla.kernel.org/show_bug.cgi?id=43255 Signed-off-by: Stanislav Yakovlev Signed-off-by: John W. Linville Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ipw2x00/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 3a6b991f023..3dd80dfdcfd 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -10471,7 +10471,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, } else len = src->len; - dst = alloc_skb(len + sizeof(*rt_hdr), GFP_ATOMIC); + dst = alloc_skb(len + sizeof(*rt_hdr) + sizeof(u16)*2, GFP_ATOMIC); if (!dst) continue; From 0c4528e770362d3497f59e9d15484ce24dd65ba9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Sep 2012 16:40:12 +0200 Subject: [PATCH 1673/2357] iwlwifi: fix 6000 series channel switch command commit 8f7b8db6e0557c8437adf9371e020cd89a7e85dc upstream. The channel switch command for 6000 series devices is larger than the maximum inline command size of 320 bytes. The command is therefore refused with a warning. Fix this by allocating the command and using the NOCOPY mechanism. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-6000.c | 33 ++++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c0cfa4e652c..2067bdff83a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -170,7 +170,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, * See iwlagn_mac_channel_switch. */ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct iwl6000_channel_switch_cmd cmd; + struct iwl6000_channel_switch_cmd *cmd; const struct iwl_channel_info *ch_info; u32 switch_time_in_usec, ucode_switch_time; u16 ch; @@ -180,18 +180,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, struct ieee80211_vif *vif = ctx->vif; struct iwl_host_cmd hcmd = { .id = REPLY_CHANNEL_SWITCH, - .len = { sizeof(cmd), }, + .len = { sizeof(*cmd), }, .flags = CMD_SYNC, - .data = { &cmd, }, + .dataflags[0] = IWL_HCMD_DFL_NOCOPY, }; + int err; - cmd.band = priv->band == IEEE80211_BAND_2GHZ; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + hcmd.data[0] = cmd; + + cmd->band = priv->band == IEEE80211_BAND_2GHZ; ch = ch_switch->channel->hw_value; IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", ctx->active.channel, ch); - cmd.channel = cpu_to_le16(ch); - cmd.rxon_flags = ctx->staging.flags; - cmd.rxon_filter_flags = ctx->staging.filter_flags; + cmd->channel = cpu_to_le16(ch); + cmd->rxon_flags = ctx->staging.flags; + cmd->rxon_filter_flags = ctx->staging.filter_flags; switch_count = ch_switch->count; tsf_low = ch_switch->timestamp & 0x0ffffffff; /* @@ -207,30 +214,32 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, switch_count = 0; } if (switch_count <= 1) - cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + cmd->switch_time = cpu_to_le32(priv->ucode_beacon_time); else { switch_time_in_usec = vif->bss_conf.beacon_int * switch_count * TIME_UNIT; ucode_switch_time = iwl_usecs_to_beacons(priv, switch_time_in_usec, beacon_interval); - cmd.switch_time = iwl_add_beacon_time(priv, + cmd->switch_time = iwl_add_beacon_time(priv, priv->ucode_beacon_time, ucode_switch_time, beacon_interval); } IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", - cmd.switch_time); + cmd->switch_time); ch_info = iwl_get_channel_info(priv, priv->band, ch); if (ch_info) - cmd.expect_beacon = is_channel_radar(ch_info); + cmd->expect_beacon = is_channel_radar(ch_info); else { IWL_ERR(priv, "invalid channel switch from %u to %u\n", ctx->active.channel, ch); return -EFAULT; } - return iwl_dvm_send_cmd(priv, &hcmd); + err = iwl_dvm_send_cmd(priv, &hcmd); + kfree(cmd); + return err; } static struct iwl_lib_ops iwl6000_lib = { From 3d514b82fc30a1425eba9e7b8f24620a4ec8a633 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 Dec 2012 12:18:42 -0800 Subject: [PATCH 1674/2357] Linux 3.4.21 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9c895596748..7f9f6491c81 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 20 +SUBLEVEL = 21 EXTRAVERSION = NAME = Saber-toothed Squirrel From 4d064b9c790a24c65e878fe0faba3490e8a7b342 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 20 Nov 2012 22:21:02 -0800 Subject: [PATCH 1675/2357] x86-32: Export kernel_stack_pointer() for modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit cb57a2b4cff7edf2a4e32c0163200e9434807e0a upstream. Modules, in particular oprofile (and possibly other similar tools) need kernel_stack_pointer(), so export it using EXPORT_SYMBOL_GPL(). Cc: Yang Wei Cc: Robert Richter Cc: Jun Zhang Link: http://lkml.kernel.org/r/20120912135059.GZ8285@erda.amd.com Signed-off-by: H. Peter Anvin Cc: Robert Richter Cc: Herton Ronaldo Krzesinski Cc: Philip Müller Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/ptrace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index d3e115297fe..c4410fb4938 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -192,6 +193,7 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs) return (unsigned long)regs; } +EXPORT_SYMBOL_GPL(kernel_stack_pointer); static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno) { From edc7a368636e2a48da92e059505c905737faf1c8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 5 Dec 2012 18:39:09 -0800 Subject: [PATCH 1676/2357] Linux 3.4.22 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7f9f6491c81..320663d2409 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 21 +SUBLEVEL = 22 EXTRAVERSION = NAME = Saber-toothed Squirrel From 99e48f99066295c88c95058ecdfdd07145bef156 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 18 Nov 2012 16:29:44 +0000 Subject: [PATCH 1677/2357] Dove: Attempt to fix PMU/RTC interrupts commit 5d3df935426271016b895aecaa247101b4bfa35e upstream. Fix the acknowledgement of PMU interrupts on Dove: some Dove hardware has not been sensibly designed so that interrupts can be handled in a race free manner. The PMU is one such instance. The pending (aka 'cause') register is a bunch of RW bits, meaning that these bits can be both cleared and set by software (confirmed on the Armada-510 on the cubox.) Hardware sets the appropriate bit when an interrupt is asserted, and software is required to clear the bits which are to be processed. If we write ~(1 << bit), then we end up asserting every other interrupt except the one we're processing. So, we need to do a read-modify-write cycle to clear the asserted bit. However, any interrupts which occur in the middle of this cycle will also be written back as zero, which will also clear the new interrupts. The upshot of this is: there is _no_ way to safely clear down interrupts in this register (and other similarly behaving interrupt pending registers on this device.) The patch below at least stops us creating new interrupts. Signed-off-by: Russell King Signed-off-by: Jason Cooper Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-dove/irq.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c index f07fd16e0c9..9f2fd100174 100644 --- a/arch/arm/mach-dove/irq.c +++ b/arch/arm/mach-dove/irq.c @@ -61,8 +61,20 @@ static void pmu_irq_ack(struct irq_data *d) int pin = irq_to_pmu(d->irq); u32 u; + /* + * The PMU mask register is not RW0C: it is RW. This means that + * the bits take whatever value is written to them; if you write + * a '1', you will set the interrupt. + * + * Unfortunately this means there is NO race free way to clear + * these interrupts. + * + * So, let's structure the code so that the window is as small as + * possible. + */ u = ~(1 << (pin & 31)); - writel(u, PMU_INTERRUPT_CAUSE); + u &= readl_relaxed(PMU_INTERRUPT_CAUSE); + writel_relaxed(u, PMU_INTERRUPT_CAUSE); } static struct irq_chip pmu_irq_chip = { From c004e0d6faac4da0488b72f0791a5f3de26c4e4e Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 18 Nov 2012 16:39:32 +0000 Subject: [PATCH 1678/2357] Dove: Fix irq_to_pmu() commit d356cf5a74afa32b40decca3c9dd88bc3cd63eb5 upstream. PMU interrupts start at IRQ_DOVE_PMU_START, not IRQ_DOVE_PMU_START + 1. Fix the condition. (It may have been less likely to occur had the code been written "if (irq >= IRQ_DOVE_PMU_START" which imho is the easier to understand notation, and matches the normal way of thinking about these things.) Signed-off-by: Russell King Signed-off-by: Jason Cooper Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-dove/include/mach/pm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-dove/include/mach/pm.h b/arch/arm/mach-dove/include/mach/pm.h index 3ad9f946a9e..11799c33475 100644 --- a/arch/arm/mach-dove/include/mach/pm.h +++ b/arch/arm/mach-dove/include/mach/pm.h @@ -45,7 +45,7 @@ static inline int pmu_to_irq(int pin) static inline int irq_to_pmu(int irq) { - if (IRQ_DOVE_PMU_START < irq && irq < NR_IRQS) + if (IRQ_DOVE_PMU_START <= irq && irq < NR_IRQS) return irq - IRQ_DOVE_PMU_START; return -EINVAL; From dfbc8b9eab0b50753a397de1abed62d4397e13ca Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 15 Aug 2012 17:13:53 -0400 Subject: [PATCH 1679/2357] drm/radeon/dce4+: don't use radeon_crtc for vblank callback commit 4a15903db02026728d0cf2755c6fabae16b8db6a upstream. This might be called before we've allocated the radeon_crtcs Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e5328da70f8..9f5c943b8bf 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -37,6 +37,16 @@ #define EVERGREEN_PFP_UCODE_SIZE 1120 #define EVERGREEN_PM4_UCODE_SIZE 1376 +static const u32 crtc_offsets[6] = +{ + EVERGREEN_CRTC0_REGISTER_OFFSET, + EVERGREEN_CRTC1_REGISTER_OFFSET, + EVERGREEN_CRTC2_REGISTER_OFFSET, + EVERGREEN_CRTC3_REGISTER_OFFSET, + EVERGREEN_CRTC4_REGISTER_OFFSET, + EVERGREEN_CRTC5_REGISTER_OFFSET +}; + static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); void evergreen_pcie_gen2_enable(struct radeon_device *rdev); @@ -101,17 +111,19 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev) void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc) { - struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; int i; - if (RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_MASTER_EN) { + if (crtc >= rdev->num_crtc) + return; + + if (RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN) { for (i = 0; i < rdev->usec_timeout; i++) { - if (!(RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK)) + if (!(RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK)) break; udelay(1); } for (i = 0; i < rdev->usec_timeout; i++) { - if (RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK) + if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK) break; udelay(1); } From a0c246c82dc5d1a9ab857364522ec56627a858eb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 15 Aug 2012 17:18:42 -0400 Subject: [PATCH 1680/2357] drm/radeon: properly handle mc_stop/mc_resume on evergreen+ (v2) commit 62444b7462a2b98bc78d68736c03a7c4e66ba7e2 upstream. - Stop the displays from accessing the FB - Block CPU access - Turn off MC client access This should fix issues some users have seen, especially with UEFI, when changing the MC FB location that result in hangs or display corruption. v2: fix crtc enabled check noticed by Luca Tettamanti Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 169 ++++++++++++------------- drivers/gpu/drm/radeon/evergreen_reg.h | 2 + drivers/gpu/drm/radeon/evergreend.h | 7 + drivers/gpu/drm/radeon/radeon_asic.h | 1 + 4 files changed, 88 insertions(+), 91 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 9f5c943b8bf..497c265a93b 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1129,116 +1129,103 @@ void evergreen_agp_enable(struct radeon_device *rdev) void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save) { + u32 crtc_enabled, tmp, frame_count, blackout; + int i, j; + save->vga_render_control = RREG32(VGA_RENDER_CONTROL); save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); - /* Stop all video */ + /* disable VGA render */ WREG32(VGA_RENDER_CONTROL, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); - } - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); - } - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + /* blank the display controllers */ + for (i = 0; i < rdev->num_crtc; i++) { + crtc_enabled = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN; + if (crtc_enabled) { + save->crtc_enabled[i] = true; + if (ASIC_IS_DCE6(rdev)) { + tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); + if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) { + radeon_wait_for_vblank(rdev, i); + tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; + WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + } + } else { + tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); + if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) { + radeon_wait_for_vblank(rdev, i); + tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + } + } + /* wait for the next frame */ + frame_count = radeon_get_vblank_counter(rdev, i); + for (j = 0; j < rdev->usec_timeout; j++) { + if (radeon_get_vblank_counter(rdev, i) != frame_count) + break; + udelay(1); + } + } } - WREG32(D1VGA_CONTROL, 0); - WREG32(D2VGA_CONTROL, 0); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_D3VGA_CONTROL, 0); - WREG32(EVERGREEN_D4VGA_CONTROL, 0); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_D5VGA_CONTROL, 0); - WREG32(EVERGREEN_D6VGA_CONTROL, 0); + radeon_mc_wait_for_idle(rdev); + + blackout = RREG32(MC_SHARED_BLACKOUT_CNTL); + if ((blackout & BLACKOUT_MODE_MASK) != 1) { + /* Block CPU access */ + WREG32(BIF_FB_EN, 0); + /* blackout the MC */ + blackout &= ~BLACKOUT_MODE_MASK; + WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1); } } void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save) { - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); + u32 tmp, frame_count; + int i, j; - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, + /* update crtc base addresses */ + for (i = 0; i < rdev->num_crtc; i++) { + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i], upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i], upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i], (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i], (u32)rdev->mc.vram_start); } - WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); - /* Unlock host access */ + + /* unblackout the MC */ + tmp = RREG32(MC_SHARED_BLACKOUT_CNTL); + tmp &= ~BLACKOUT_MODE_MASK; + WREG32(MC_SHARED_BLACKOUT_CNTL, tmp); + /* allow CPU access */ + WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN); + + for (i = 0; i < rdev->num_crtc; i++) { + if (save->crtc_enabled) { + if (ASIC_IS_DCE6(rdev)) { + tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); + tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; + WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + } else { + tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); + tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + } + /* wait for the next frame */ + frame_count = radeon_get_vblank_counter(rdev, i); + for (j = 0; j < rdev->usec_timeout; j++) { + if (radeon_get_vblank_counter(rdev, i) != frame_count) + break; + udelay(1); + } + } + } + /* Unlock vga access */ WREG32(VGA_HDP_CONTROL, save->vga_hdp_control); mdelay(1); WREG32(VGA_RENDER_CONTROL, save->vga_render_control); diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 96c10b3991a..34a0e856069 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -218,6 +218,8 @@ #define EVERGREEN_CRTC_CONTROL 0x6e70 # define EVERGREEN_CRTC_MASTER_EN (1 << 0) # define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) +#define EVERGREEN_CRTC_BLANK_CONTROL 0x6e74 +# define EVERGREEN_CRTC_BLANK_DATA_EN (1 << 8) #define EVERGREEN_CRTC_STATUS 0x6e8c # define EVERGREEN_CRTC_V_BLANK (1 << 0) #define EVERGREEN_CRTC_STATUS_POSITION 0x6e90 diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 2eaaea061d6..81e744fab31 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -77,6 +77,10 @@ #define CONFIG_MEMSIZE 0x5428 +#define BIF_FB_EN 0x5490 +#define FB_READ_EN (1 << 0) +#define FB_WRITE_EN (1 << 1) + #define CP_STRMOUT_CNTL 0x84FC #define CP_COHER_CNTL 0x85F0 @@ -200,6 +204,9 @@ #define NOOFCHAN_MASK 0x00003000 #define MC_SHARED_CHREMAP 0x2008 +#define MC_SHARED_BLACKOUT_CNTL 0x20ac +#define BLACKOUT_MODE_MASK 0x00000007 + #define MC_ARB_RAMCFG 0x2760 #define NOOFBANK_SHIFT 0 #define NOOFBANK_MASK 0x00000003 diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 665df8730c8..917e49cb490 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -400,6 +400,7 @@ void r700_cp_fini(struct radeon_device *rdev); struct evergreen_mc_save { u32 vga_render_control; u32 vga_hdp_control; + bool crtc_enabled[RADEON_MAX_CRTCS]; }; void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev); From 86d80959eb81b931a509fe9ea78b31f319882637 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 19 Nov 2012 09:11:27 -0500 Subject: [PATCH 1681/2357] drm/radeon: properly track the crtc not_enabled case evergreen_mc_stop() commit 804cc4a0ad3a896ca295f771a28c6eb36ced7903 upstream. The save struct is not initialized previously so explicitly mark the crtcs as not used when they are not in use. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 497c265a93b..4a1d8f3457c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1164,6 +1164,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav break; udelay(1); } + } else { + save->crtc_enabled[i] = false; } } From 25a30e7cc1562e110c401f286f41c801d80b2b0a Mon Sep 17 00:00:00 2001 From: Jianguo Wu Date: Thu, 29 Nov 2012 13:54:21 -0800 Subject: [PATCH 1682/2357] mm/vmemmap: fix wrong use of virt_to_page commit ae64ffcac35de0db628ba9631edf8ff34c5cd7ac upstream. I enable CONFIG_DEBUG_VIRTUAL and CONFIG_SPARSEMEM_VMEMMAP, when doing memory hotremove, there is a kernel BUG at arch/x86/mm/physaddr.c:20. It is caused by free_section_usemap()->virt_to_page(), virt_to_page() is only used for kernel direct mapping address, but sparse-vmemmap uses vmemmap address, so it is going wrong here. ------------[ cut here ]------------ kernel BUG at arch/x86/mm/physaddr.c:20! invalid opcode: 0000 [#1] SMP Modules linked in: acpihp_drv acpihp_slot edd cpufreq_conservative cpufreq_userspace cpufreq_powersave acpi_cpufreq mperf fuse vfat fat loop dm_mod coretemp kvm crc32c_intel ipv6 ixgbe igb iTCO_wdt i7core_edac edac_core pcspkr iTCO_vendor_support ioatdma microcode joydev sr_mod i2c_i801 dca lpc_ich mfd_core mdio tpm_tis i2c_core hid_generic tpm cdrom sg tpm_bios rtc_cmos button ext3 jbd mbcache usbhid hid uhci_hcd ehci_hcd usbcore usb_common sd_mod crc_t10dif processor thermal_sys hwmon scsi_dh_alua scsi_dh_hp_sw scsi_dh_rdac scsi_dh_emc scsi_dh ata_generic ata_piix libata megaraid_sas scsi_mod CPU 39 Pid: 6454, comm: sh Not tainted 3.7.0-rc1-acpihp-final+ #45 QCI QSSC-S4R/QSSC-S4R RIP: 0010:[] [] __phys_addr+0x88/0x90 RSP: 0018:ffff8804440d7c08 EFLAGS: 00010006 RAX: 0000000000000006 RBX: ffffea0012000000 RCX: 000000000000002c ... Signed-off-by: Jianguo Wu Signed-off-by: Jiang Liu Reviewd-by: Wen Congyang Acked-by: Johannes Weiner Reviewed-by: Yasuaki Ishimatsu Reviewed-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/sparse.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mm/sparse.c b/mm/sparse.c index a8bc7d364de..290dba25a7e 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -619,7 +619,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages) { return; /* XXX: Not implemented yet */ } -static void free_map_bootmem(struct page *page, unsigned long nr_pages) +static void free_map_bootmem(struct page *memmap, unsigned long nr_pages) { } #else @@ -660,10 +660,11 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages) get_order(sizeof(struct page) * nr_pages)); } -static void free_map_bootmem(struct page *page, unsigned long nr_pages) +static void free_map_bootmem(struct page *memmap, unsigned long nr_pages) { unsigned long maps_section_nr, removing_section_nr, i; unsigned long magic; + struct page *page = virt_to_page(memmap); for (i = 0; i < nr_pages; i++, page++) { magic = (unsigned long) page->lru.next; @@ -712,13 +713,10 @@ static void free_section_usemap(struct page *memmap, unsigned long *usemap) */ if (memmap) { - struct page *memmap_page; - memmap_page = virt_to_page(memmap); - nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page)) >> PAGE_SHIFT; - free_map_bootmem(memmap_page, nr_pages); + free_map_bootmem(memmap, nr_pages); } } From 0b4d372b78bef8ebbccca2e310973b550f1dc6f2 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Thu, 29 Nov 2012 13:54:34 -0800 Subject: [PATCH 1683/2357] mm: soft offline: split thp at the beginning of soft_offline_page() commit 783657a7dc20e5c0efbc9a09a9dd38e238a723da upstream. When we try to soft-offline a thp tail page, put_page() is called on the tail page unthinkingly and VM_BUG_ON is triggered in put_compound_page(). This patch splits thp before going into the main body of soft-offlining. Signed-off-by: Naoya Horiguchi Cc: Andi Kleen Cc: Tony Luck Cc: Andi Kleen Cc: Wu Fengguang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memory-failure.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 274c3cc5fbc..d86fb205735 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1481,9 +1481,17 @@ int soft_offline_page(struct page *page, int flags) { int ret; unsigned long pfn = page_to_pfn(page); + struct page *hpage = compound_trans_head(page); if (PageHuge(page)) return soft_offline_huge_page(page, flags); + if (PageTransHuge(hpage)) { + if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) { + pr_info("soft offline: %#lx: failed to split THP\n", + pfn); + return -EBUSY; + } + } ret = get_any_page(page, pfn, flags); if (ret < 0) From 659cca40ff27f7d73a0c49ac6c8d8b3838202524 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 21 Nov 2012 00:19:06 -0700 Subject: [PATCH 1684/2357] ARM: Kirkwood: Update PCI-E fixup commit 1dc831bf53fddcc6443f74a39e72db5bcea4f15d upstream. - The code relies on rc_pci_fixup being called, which only happens when CONFIG_PCI_QUIRKS is enabled, so add that to Kconfig. Omitting this causes a booting failure with a non-obvious cause. - Update rc_pci_fixup to set the class properly, copying the more modern style from other places - Correct the rc_pci_fixup comment Signed-off-by: Jason Gunthorpe Signed-off-by: Jason Cooper Signed-off-by: Greg Kroah-Hartman --- arch/arm/Kconfig | 1 + arch/arm/mach-kirkwood/pcie.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e14ae114142..7fe19a38ba1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -579,6 +579,7 @@ config ARCH_KIRKWOOD bool "Marvell Kirkwood" select CPU_FEROCEON select PCI + select PCI_QUIRKS select ARCH_REQUIRE_GPIOLIB select GENERIC_CLOCKEVENTS select NEED_MACH_IO_H diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c index f56a0118c1b..c46d20e5f3f 100644 --- a/arch/arm/mach-kirkwood/pcie.c +++ b/arch/arm/mach-kirkwood/pcie.c @@ -212,14 +212,19 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys) return 1; } +/* + * The root complex has a hardwired class of PCI_CLASS_MEMORY_OTHER, when it + * is operating as a root complex this needs to be switched to + * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on + * the device. Decoding setup is handled by the orion code. + */ static void __devinit rc_pci_fixup(struct pci_dev *dev) { - /* - * Prevent enumeration of root complex. - */ if (dev->bus->parent == NULL && dev->devfn == 0) { int i; + dev->class &= 0xff; + dev->class |= PCI_CLASS_BRIDGE_HOST << 8; for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { dev->resource[i].start = 0; dev->resource[i].end = 0; From 1b9dd61a10bed126661645cbf2623965fbbdefb3 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Fri, 30 Nov 2012 12:15:32 -0800 Subject: [PATCH 1685/2357] x86, fpu: Avoid FPU lazy restore after suspend commit 644c154186386bb1fa6446bc5e037b9ed098db46 upstream. When a cpu enters S3 state, the FPU state is lost. After resuming for S3, if we try to lazy restore the FPU for a process running on the same CPU, this will result in a corrupted FPU context. Ensure that "fpu_owner_task" is properly invalided when (re-)initializing a CPU, so nobody will try to lazy restore a state which doesn't exist in the hardware. Tested with a 64-bit kernel on a 4-core Ivybridge CPU with eagerfpu=off, by doing thousands of suspend/resume cycles with 4 processes doing FPU operations running. Without the patch, a process is killed after a few hundreds cycles by a SIGFPE. Signed-off-by: Vincent Palatin Cc: Duncan Laurie Cc: Olof Johansson Link: http://lkml.kernel.org/r/1354306532-1014-1-git-send-email-vpalatin@chromium.org Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/fpu-internal.h | 15 +++++++++------ arch/x86/kernel/smpboot.c | 5 +++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h index 4fa88154e4d..92e05b6c84f 100644 --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -334,14 +334,17 @@ static inline void __thread_fpu_begin(struct task_struct *tsk) typedef struct { int preload; } fpu_switch_t; /* - * FIXME! We could do a totally lazy restore, but we need to - * add a per-cpu "this was the task that last touched the FPU - * on this CPU" variable, and the task needs to have a "I last - * touched the FPU on this CPU" and check them. + * Must be run with preemption disabled: this clears the fpu_owner_task, + * on this CPU. * - * We don't do that yet, so "fpu_lazy_restore()" always returns - * false, but some day.. + * This will disable any lazy FPU state restore of the current FPU state, + * but if the current thread owns the FPU, it will still be saved by. */ +static inline void __cpu_disable_lazy_restore(unsigned int cpu) +{ + per_cpu(fpu_owner_task, cpu) = NULL; +} + static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu) { return new == percpu_read_stable(fpu_owner_task) && diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 6e1e406038c..849cdcf2e76 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -66,6 +66,8 @@ #include #include #include +#include +#include #include #include #include @@ -851,6 +853,9 @@ int __cpuinit native_cpu_up(unsigned int cpu) per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; + /* the FPU context is blank, nobody can own it */ + __cpu_disable_lazy_restore(cpu); + err = do_boot_cpu(apicid, cpu); if (err) { pr_debug("do_boot_cpu failed %d\n", err); From dbdd7f0c98e8ee0d49da5e8b462ad2ba07d0f358 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Wed, 28 Nov 2012 07:17:18 +0100 Subject: [PATCH 1686/2357] workqueue: exit rescuer_thread() as TASK_RUNNING commit 412d32e6c98527078779e5b515823b2810e40324 upstream. A rescue thread exiting TASK_INTERRUPTIBLE can lead to a task scheduling off, never to be seen again. In the case where this occurred, an exiting thread hit reiserfs homebrew conditional resched while holding a mutex, bringing the box to its knees. PID: 18105 TASK: ffff8807fd412180 CPU: 5 COMMAND: "kdmflush" #0 [ffff8808157e7670] schedule at ffffffff8143f489 #1 [ffff8808157e77b8] reiserfs_get_block at ffffffffa038ab2d [reiserfs] #2 [ffff8808157e79a8] __block_write_begin at ffffffff8117fb14 #3 [ffff8808157e7a98] reiserfs_write_begin at ffffffffa0388695 [reiserfs] #4 [ffff8808157e7ad8] generic_perform_write at ffffffff810ee9e2 #5 [ffff8808157e7b58] generic_file_buffered_write at ffffffff810eeb41 #6 [ffff8808157e7ba8] __generic_file_aio_write at ffffffff810f1a3a #7 [ffff8808157e7c58] generic_file_aio_write at ffffffff810f1c88 #8 [ffff8808157e7cc8] do_sync_write at ffffffff8114f850 #9 [ffff8808157e7dd8] do_acct_process at ffffffff810a268f [exception RIP: kernel_thread_helper] RIP: ffffffff8144a5c0 RSP: ffff8808157e7f58 RFLAGS: 00000202 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffffffff8107af60 RDI: ffff8803ee491d18 RBP: 0000000000000000 R8: 0000000000000000 R9: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 Signed-off-by: Mike Galbraith Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/workqueue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 56f793d044a..bcb9d342714 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -2040,8 +2040,10 @@ static int rescuer_thread(void *__wq) repeat: set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) + if (kthread_should_stop()) { + __set_current_state(TASK_RUNNING); return 0; + } /* * See whether any cpu is asking for help. Unbounded From f3921710aa40ae72bd2580282548f763b008a1d0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 22 Nov 2012 14:42:49 +1100 Subject: [PATCH 1687/2357] md/raid10: close race that lose writes lost when replacement completes. commit e7c0c3fa29280d62aa5e11101a674bb3064bd791 upstream. When a replacement operation completes there is a small window when the original device is marked 'faulty' and the replacement still looks like a replacement. The faulty should be removed and the replacement moved in place very quickly, bit it isn't instant. So the code write out to the array must handle the possibility that the only working device for some slot in the replacement - but it doesn't. If the primary device is faulty it just gives up. This can lead to corruption. So make the code more robust: if either the primary or the replacement is present and working, write to them. Only when neither are present do we give up. This bug has been present since replacement was introduced in 3.3, so it is suitable for any -stable kernel since then. Reported-by: "George Spelvin" Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 100 +++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a2b5304b4eb..6137d0041d4 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1182,18 +1182,21 @@ static void make_request(struct mddev *mddev, struct bio * bio) blocked_rdev = rrdev; break; } + if (rdev && (test_bit(Faulty, &rdev->flags) + || test_bit(Unmerged, &rdev->flags))) + rdev = NULL; if (rrdev && (test_bit(Faulty, &rrdev->flags) || test_bit(Unmerged, &rrdev->flags))) rrdev = NULL; r10_bio->devs[i].bio = NULL; r10_bio->devs[i].repl_bio = NULL; - if (!rdev || test_bit(Faulty, &rdev->flags) || - test_bit(Unmerged, &rdev->flags)) { + + if (!rdev && !rrdev) { set_bit(R10BIO_Degraded, &r10_bio->state); continue; } - if (test_bit(WriteErrorSeen, &rdev->flags)) { + if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) { sector_t first_bad; sector_t dev_sector = r10_bio->devs[i].addr; int bad_sectors; @@ -1235,8 +1238,10 @@ static void make_request(struct mddev *mddev, struct bio * bio) max_sectors = good_sectors; } } - r10_bio->devs[i].bio = bio; - atomic_inc(&rdev->nr_pending); + if (rdev) { + r10_bio->devs[i].bio = bio; + atomic_inc(&rdev->nr_pending); + } if (rrdev) { r10_bio->devs[i].repl_bio = bio; atomic_inc(&rrdev->nr_pending); @@ -1292,51 +1297,52 @@ static void make_request(struct mddev *mddev, struct bio * bio) for (i = 0; i < conf->copies; i++) { struct bio *mbio; int d = r10_bio->devs[i].devnum; - if (!r10_bio->devs[i].bio) - continue; - - mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); - r10_bio->devs[i].bio = mbio; - - mbio->bi_sector = (r10_bio->devs[i].addr+ - conf->mirrors[d].rdev->data_offset); - mbio->bi_bdev = conf->mirrors[d].rdev->bdev; - mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua; - mbio->bi_private = r10_bio; - - atomic_inc(&r10_bio->remaining); - spin_lock_irqsave(&conf->device_lock, flags); - bio_list_add(&conf->pending_bio_list, mbio); - conf->pending_count++; - spin_unlock_irqrestore(&conf->device_lock, flags); - - if (!r10_bio->devs[i].repl_bio) - continue; + if (r10_bio->devs[i].bio) { + struct md_rdev *rdev = conf->mirrors[d].rdev; + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); + md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); + r10_bio->devs[i].bio = mbio; + + mbio->bi_sector = (r10_bio->devs[i].addr+ + rdev->data_offset); + mbio->bi_bdev = rdev->bdev; + mbio->bi_end_io = raid10_end_write_request; + mbio->bi_rw = WRITE | do_sync | do_fua; + mbio->bi_private = r10_bio; - mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); - r10_bio->devs[i].repl_bio = mbio; + atomic_inc(&r10_bio->remaining); + spin_lock_irqsave(&conf->device_lock, flags); + bio_list_add(&conf->pending_bio_list, mbio); + conf->pending_count++; + spin_unlock_irqrestore(&conf->device_lock, flags); + } - /* We are actively writing to the original device - * so it cannot disappear, so the replacement cannot - * become NULL here - */ - mbio->bi_sector = (r10_bio->devs[i].addr+ - conf->mirrors[d].replacement->data_offset); - mbio->bi_bdev = conf->mirrors[d].replacement->bdev; - mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua; - mbio->bi_private = r10_bio; + if (r10_bio->devs[i].repl_bio) { + struct md_rdev *rdev = conf->mirrors[d].replacement; + if (rdev == NULL) { + /* Replacement just got moved to main 'rdev' */ + smp_mb(); + rdev = conf->mirrors[d].rdev; + } + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); + md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); + r10_bio->devs[i].repl_bio = mbio; + + mbio->bi_sector = (r10_bio->devs[i].addr+ + rdev->data_offset); + mbio->bi_bdev = rdev->bdev; + mbio->bi_end_io = raid10_end_write_request; + mbio->bi_rw = WRITE | do_sync | do_fua; + mbio->bi_private = r10_bio; - atomic_inc(&r10_bio->remaining); - spin_lock_irqsave(&conf->device_lock, flags); - bio_list_add(&conf->pending_bio_list, mbio); - conf->pending_count++; - spin_unlock_irqrestore(&conf->device_lock, flags); + atomic_inc(&r10_bio->remaining); + spin_lock_irqsave(&conf->device_lock, flags); + bio_list_add(&conf->pending_bio_list, mbio); + conf->pending_count++; + spin_unlock_irqrestore(&conf->device_lock, flags); + } } /* Don't remove the bias on 'remaining' (one_write_done) until From 43477d60e75490b168627aaafccb7032b28d2574 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 18 Oct 2012 15:54:45 +0200 Subject: [PATCH 1688/2357] i7300_edac: Fix error flag testing commit 7e06b7a3333f5c7a0cec12aff20d39c5c87c0795 upstream. * Right-shift the values in GET_FBD_FAT_IDX and GET_FBD_NF_IDX, so that the callers get the result they expect. * Fix definition of FERR_FAT_FBD_ERR_MASK. * Call GET_FBD_NF_IDX, not GET_FBD_FAT_IDX, when operating on register FERR_NF_FBD. We were lucky they have the same definition. This fixes kernel bug #44131: https://bugzilla.kernel.org/show_bug.cgi?id=44131 Signed-off-by: Jean Delvare Cc: Mauro Carvalho Chehab Cc: Doug Thompson Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/edac/i7300_edac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index 3bafa3bca14..f4059e9da30 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -215,8 +215,8 @@ static const char *ferr_fat_fbd_name[] = { [0] = "Memory Write error on non-redundant retry or " "FBD configuration Write error on retry", }; -#define GET_FBD_FAT_IDX(fbderr) (fbderr & (3 << 28)) -#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)) +#define GET_FBD_FAT_IDX(fbderr) (((fbderr) >> 28) & 3) +#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 22)) #define FERR_NF_FBD 0xa0 static const char *ferr_nf_fbd_name[] = { @@ -243,7 +243,7 @@ static const char *ferr_nf_fbd_name[] = { [1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC", [0] = "Uncorrectable Data ECC on Replay", }; -#define GET_FBD_NF_IDX(fbderr) (fbderr & (3 << 28)) +#define GET_FBD_NF_IDX(fbderr) (((fbderr) >> 28) & 3) #define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\ (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\ (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\ @@ -485,7 +485,7 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci) errnum = find_first_bit(&errors, ARRAY_SIZE(ferr_nf_fbd_name)); specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum); - branch = (GET_FBD_FAT_IDX(error_reg) == 2) ? 1 : 0; + branch = (GET_FBD_NF_IDX(error_reg) == 2) ? 1 : 0; pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, REDMEMA, &syndrome); From 3d81da8645585b9c116a7ac20b99ac8909677c80 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Mon, 3 Dec 2012 06:25:25 +0100 Subject: [PATCH 1689/2357] Revert "sched, autogroup: Stop going ahead if autogroup is disabled" commit fd8ef11730f1d03d5d6555aa53126e9e34f52f12 upstream. This reverts commit 800d4d30c8f20bd728e5741a3b77c4859a613f7c. Between commits 8323f26ce342 ("sched: Fix race in task_group()") and 800d4d30c8f2 ("sched, autogroup: Stop going ahead if autogroup is disabled"), autogroup is a wreck. With both applied, all you have to do to crash a box is disable autogroup during boot up, then reboot.. boom, NULL pointer dereference due to commit 800d4d30c8f2 not allowing autogroup to move things, and commit 8323f26ce342 making that the only way to switch runqueues: BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] effective_load.isra.43+0x50/0x90 Pid: 7047, comm: systemd-user-se Not tainted 3.6.8-smp #7 MEDIONPC MS-7502/MS-7502 RIP: effective_load.isra.43+0x50/0x90 Process systemd-user-se (pid: 7047, threadinfo ffff880221dde000, task ffff88022618b3a0) Call Trace: select_task_rq_fair+0x255/0x780 try_to_wake_up+0x156/0x2c0 wake_up_state+0xb/0x10 signal_wake_up+0x28/0x40 complete_signal+0x1d6/0x250 __send_signal+0x170/0x310 send_signal+0x40/0x80 do_send_sig_info+0x47/0x90 group_send_sig_info+0x4a/0x70 kill_pid_info+0x3a/0x60 sys_kill+0x97/0x1a0 ? vfs_read+0x120/0x160 ? sys_read+0x45/0x90 system_call_fastpath+0x16/0x1b Code: 49 0f af 41 50 31 d2 49 f7 f0 48 83 f8 01 48 0f 46 c6 48 2b 07 48 8b bf 40 01 00 00 48 85 ff 74 3a 45 31 c0 48 8b 8f 50 01 00 00 <48> 8b 11 4c 8b 89 80 00 00 00 49 89 d2 48 01 d0 45 8b 59 58 4c RIP [] effective_load.isra.43+0x50/0x90 RSP CR2: 0000000000000000 Signed-off-by: Mike Galbraith Acked-by: Ingo Molnar Cc: Yong Zhang Cc: Peter Zijlstra Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/sched/auto_group.c | 4 ---- kernel/sched/auto_group.h | 5 ----- 2 files changed, 9 deletions(-) diff --git a/kernel/sched/auto_group.c b/kernel/sched/auto_group.c index 0984a21076a..15f60d01198 100644 --- a/kernel/sched/auto_group.c +++ b/kernel/sched/auto_group.c @@ -143,15 +143,11 @@ autogroup_move_group(struct task_struct *p, struct autogroup *ag) p->signal->autogroup = autogroup_kref_get(ag); - if (!ACCESS_ONCE(sysctl_sched_autogroup_enabled)) - goto out; - t = p; do { sched_move_task(t); } while_each_thread(p, t); -out: unlock_task_sighand(p, &flags); autogroup_kref_put(prev); } diff --git a/kernel/sched/auto_group.h b/kernel/sched/auto_group.h index 8bd04714281..443232ebbb5 100644 --- a/kernel/sched/auto_group.h +++ b/kernel/sched/auto_group.h @@ -4,11 +4,6 @@ #include struct autogroup { - /* - * reference doesn't mean how many thread attach to this - * autogroup now. It just stands for the number of task - * could use this autogroup. - */ struct kref kref; struct task_group *tg; struct rw_semaphore lock; From e3c8a4858ca78c5da18cd77660ba23ada1c938a9 Mon Sep 17 00:00:00 2001 From: Ariel Elior Date: Thu, 22 Nov 2012 07:16:17 +0000 Subject: [PATCH 1690/2357] bnx2x: remove redundant warning log commit 4a25417c20fac00b3afd58ce27408f964d19e708 upstream. fix bug where a register which was only meant to be read in 578xx/57712 devices causes a bogus error message to be logged when read from other devices. Signed-off-by: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 6af310195ba..b8e7f3e082e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9131,10 +9131,13 @@ static int __devinit bnx2x_prev_unload_common(struct bnx2x *bp) */ static void __devinit bnx2x_prev_interrupted_dmae(struct bnx2x *bp) { - u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); - if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { - BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing"); - REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, 1 << BP_FUNC(bp)); + if (!CHIP_IS_E1x(bp)) { + u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { + BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing"); + REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, + 1 << BP_FUNC(bp)); + } } } From cd81606a09d4ee84de72f02293f826508d1581b0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 26 Oct 2012 01:05:56 +0200 Subject: [PATCH 1691/2357] ACPI: missing break commit 879dca019dc43a1622edca3e7dde644b14b5acc5 upstream. We handle NOTIFY_THROTTLING so don't then fall through to unsupported event. Signed-off-by: Alan Cox Signed-off-by: Rafael J. Wysocki Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index bbac51e79d1..4a2c131bf08 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -407,6 +407,7 @@ static void acpi_processor_notify(struct acpi_device *device, u32 event) acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); + break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); From 693023b7b8b1a869a7dc2b52a235f77080feed24 Mon Sep 17 00:00:00 2001 From: Calvin Walton Date: Fri, 24 Aug 2012 07:56:31 -0400 Subject: [PATCH 1692/2357] i915: Quirk no_lvds on Gigabyte GA-D525TUD ITX motherboard commit a51d4ed01e5bb39d2cf36a12f9976ab08872c192 upstream. This board is incorrectly detected as having an LVDS connector, resulting in the VGA output (the only available output on the board) showing the console only in the top-left 1024x768 pixels, and an extra LVDS connector appearing in X. It's a desktop Mini-ITX board using an Atom D525 CPU with an NM10 chipset. I've had this board for about a year, but this is the first time I noticed the issue because I've been running it headless for most of its life. Signed-off-by: Calvin Walton Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 4ff7d5f06da..648afcbc153 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -785,6 +785,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "ZBOXSD-ID12/ID13"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Gigabyte GA-D525TUD", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "D525TUD"), + }, + }, { } /* terminating entry */ }; From f036099aa85d361fd062384c8e831b580de7bbb2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 18 Oct 2012 21:07:01 +0100 Subject: [PATCH 1693/2357] drm/i915: Add no-lvds quirk for Supermicro X7SPA-H commit c31407a3672aaebb4acddf90944a114fa5c8af7b upstream. Reported-and-tested-by: Francois Tigeot Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55375 Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 648afcbc153..802fec20ff8 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -793,6 +793,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "D525TUD"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Supermicro X7SPA-H", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"), + DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"), + }, + }, { } /* terminating entry */ }; From 0e252d8f530e5d322c53d014ce07b8115dfdac78 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Fri, 24 Aug 2012 00:27:51 +0800 Subject: [PATCH 1694/2357] pnfsblock: fix partial page buffer wirte commit fe6e1e8d9fad86873eb74a26e80a8f91f9e870b5 upstream. If applications use flock to protect its write range, generic NFS will not do read-modify-write cycle at page cache level. Therefore LD should know how to handle non-sector aligned writes. Otherwise there will be data corruption. Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/blocklayout/blocklayout.c | 176 ++++++++++++++++++++++++++++--- fs/nfs/blocklayout/blocklayout.h | 1 + 2 files changed, 165 insertions(+), 12 deletions(-) diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 7f6a23f0244..d16dae2a9b2 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -162,25 +162,39 @@ static struct bio *bl_alloc_init_bio(int npg, sector_t isect, return bio; } -static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw, +static struct bio *do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect, struct page *page, struct pnfs_block_extent *be, void (*end_io)(struct bio *, int err), - struct parallel_io *par) + struct parallel_io *par, + unsigned int offset, int len) { + isect = isect + (offset >> SECTOR_SHIFT); + dprintk("%s: npg %d rw %d isect %llu offset %u len %d\n", __func__, + npg, rw, (unsigned long long)isect, offset, len); retry: if (!bio) { bio = bl_alloc_init_bio(npg, isect, be, end_io, par); if (!bio) return ERR_PTR(-ENOMEM); } - if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { + if (bio_add_page(bio, page, len, offset) < len) { bio = bl_submit_bio(rw, bio); goto retry; } return bio; } +static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw, + sector_t isect, struct page *page, + struct pnfs_block_extent *be, + void (*end_io)(struct bio *, int err), + struct parallel_io *par) +{ + return do_add_page_to_bio(bio, npg, rw, isect, page, be, + end_io, par, 0, PAGE_CACHE_SIZE); +} + /* This is basically copied from mpage_end_io_read */ static void bl_end_io_read(struct bio *bio, int err) { @@ -443,6 +457,107 @@ map_block(struct buffer_head *bh, sector_t isect, struct pnfs_block_extent *be) return; } +static void +bl_read_single_end_io(struct bio *bio, int error) +{ + struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + struct page *page = bvec->bv_page; + + /* Only one page in bvec */ + unlock_page(page); +} + +static int +bl_do_readpage_sync(struct page *page, struct pnfs_block_extent *be, + unsigned int offset, unsigned int len) +{ + struct bio *bio; + struct page *shadow_page; + sector_t isect; + char *kaddr, *kshadow_addr; + int ret = 0; + + dprintk("%s: offset %u len %u\n", __func__, offset, len); + + shadow_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); + if (shadow_page == NULL) + return -ENOMEM; + + bio = bio_alloc(GFP_NOIO, 1); + if (bio == NULL) + return -ENOMEM; + + isect = (page->index << PAGE_CACHE_SECTOR_SHIFT) + + (offset / SECTOR_SIZE); + + bio->bi_sector = isect - be->be_f_offset + be->be_v_offset; + bio->bi_bdev = be->be_mdev; + bio->bi_end_io = bl_read_single_end_io; + + lock_page(shadow_page); + if (bio_add_page(bio, shadow_page, + SECTOR_SIZE, round_down(offset, SECTOR_SIZE)) == 0) { + unlock_page(shadow_page); + bio_put(bio); + return -EIO; + } + + submit_bio(READ, bio); + wait_on_page_locked(shadow_page); + if (unlikely(!test_bit(BIO_UPTODATE, &bio->bi_flags))) { + ret = -EIO; + } else { + kaddr = kmap_atomic(page); + kshadow_addr = kmap_atomic(shadow_page); + memcpy(kaddr + offset, kshadow_addr + offset, len); + kunmap_atomic(kshadow_addr); + kunmap_atomic(kaddr); + } + __free_page(shadow_page); + bio_put(bio); + + return ret; +} + +static int +bl_read_partial_page_sync(struct page *page, struct pnfs_block_extent *be, + unsigned int dirty_offset, unsigned int dirty_len, + bool full_page) +{ + int ret = 0; + unsigned int start, end; + + if (full_page) { + start = 0; + end = PAGE_CACHE_SIZE; + } else { + start = round_down(dirty_offset, SECTOR_SIZE); + end = round_up(dirty_offset + dirty_len, SECTOR_SIZE); + } + + dprintk("%s: offset %u len %d\n", __func__, dirty_offset, dirty_len); + if (!be) { + zero_user_segments(page, start, dirty_offset, + dirty_offset + dirty_len, end); + if (start == 0 && end == PAGE_CACHE_SIZE && + trylock_page(page)) { + SetPageUptodate(page); + unlock_page(page); + } + return ret; + } + + if (start != dirty_offset) + ret = bl_do_readpage_sync(page, be, start, + dirty_offset - start); + + if (!ret && (dirty_offset + dirty_len < end)) + ret = bl_do_readpage_sync(page, be, dirty_offset + dirty_len, + end - dirty_offset - dirty_len); + + return ret; +} + /* Given an unmapped page, zero it or read in page for COW, page is locked * by caller. */ @@ -476,7 +591,6 @@ init_page_for_write(struct page *page, struct pnfs_block_extent *cow_read) SetPageUptodate(page); cleanup: - bl_put_extent(cow_read); if (bh) free_buffer_head(bh); if (ret) { @@ -547,6 +661,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) struct parallel_io *par; loff_t offset = wdata->args.offset; size_t count = wdata->args.count; + unsigned int pg_offset, pg_len, saved_len; struct page **pages = wdata->args.pages; struct page *page; pgoff_t index; @@ -651,10 +766,11 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) if (!extent_length) { /* We've used up the previous extent */ bl_put_extent(be); + bl_put_extent(cow_read); bio = bl_submit_bio(WRITE, bio); /* Get the next one */ be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg), - isect, NULL); + isect, &cow_read); if (!be || !is_writable(be, isect)) { wdata->pnfs_error = -EINVAL; goto out; @@ -671,7 +787,26 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) extent_length = be->be_length - (isect - be->be_f_offset); } - if (be->be_state == PNFS_BLOCK_INVALID_DATA) { + + dprintk("%s offset %lld count %Zu\n", __func__, offset, count); + pg_offset = offset & ~PAGE_CACHE_MASK; + if (pg_offset + count > PAGE_CACHE_SIZE) + pg_len = PAGE_CACHE_SIZE - pg_offset; + else + pg_len = count; + + saved_len = pg_len; + if (be->be_state == PNFS_BLOCK_INVALID_DATA && + !bl_is_sector_init(be->be_inval, isect)) { + ret = bl_read_partial_page_sync(pages[i], cow_read, + pg_offset, pg_len, true); + if (ret) { + dprintk("%s bl_read_partial_page_sync fail %d\n", + __func__, ret); + wdata->pnfs_error = ret; + goto out; + } + ret = bl_mark_sectors_init(be->be_inval, isect, PAGE_CACHE_SECTORS); if (unlikely(ret)) { @@ -680,15 +815,33 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) wdata->pnfs_error = ret; goto out; } + + /* Expand to full page write */ + pg_offset = 0; + pg_len = PAGE_CACHE_SIZE; + } else if ((pg_offset & (SECTOR_SIZE - 1)) || + (pg_len & (SECTOR_SIZE - 1))) { + /* ahh, nasty case. We have to do sync full sector + * read-modify-write cycles. + */ + unsigned int saved_offset = pg_offset; + ret = bl_read_partial_page_sync(pages[i], be, pg_offset, + pg_len, false); + pg_offset = round_down(pg_offset, SECTOR_SIZE); + pg_len = round_up(saved_offset + pg_len, SECTOR_SIZE) + - pg_offset; } - bio = bl_add_page_to_bio(bio, wdata->npages - i, WRITE, + bio = do_add_page_to_bio(bio, wdata->npages - i, WRITE, isect, pages[i], be, - bl_end_io_write, par); + bl_end_io_write, par, + pg_offset, pg_len); if (IS_ERR(bio)) { wdata->pnfs_error = PTR_ERR(bio); bio = NULL; goto out; } + offset += saved_len; + count -= saved_len; isect += PAGE_CACHE_SECTORS; last_isect = isect; extent_length -= PAGE_CACHE_SECTORS; @@ -706,17 +859,16 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) } write_done: - wdata->res.count = (last_isect << SECTOR_SHIFT) - (offset); - if (count < wdata->res.count) { - wdata->res.count = count; - } + wdata->res.count = wdata->args.count; out: bl_put_extent(be); + bl_put_extent(cow_read); bl_submit_bio(WRITE, bio); put_parallel(par); return PNFS_ATTEMPTED; out_mds: bl_put_extent(be); + bl_put_extent(cow_read); kfree(par); return PNFS_NOT_ATTEMPTED; } diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index 03350690118..39bb51a8dd1 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h @@ -41,6 +41,7 @@ #define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT) #define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT) +#define SECTOR_SIZE (1 << SECTOR_SHIFT) struct block_mount_id { spinlock_t bm_lock; /* protects list */ From cc7c332b34cb936b4a27c1c185700c9a0f7c7bf0 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 25 Sep 2012 16:03:03 +0200 Subject: [PATCH 1695/2357] kbuild: Do not package /boot and /lib in make tar-pkg commit fe04ddf7c2910362f3817c8156e41cbd6c0ee35d upstream. There were reports of users destroying their Fedora installs by a kernel tarball that replaces the /lib -> /usr/lib symlink. Let's remove the toplevel directories from the tarball to prevent this from happening. Reported-by: Andi Kleen Suggested-by: Ben Hutchings Signed-off-by: Michal Marek [bwh: Fold in commit 3ce9e53e788881da0d5f3912f80e0dd6b501f304 to avoid conflicts] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- scripts/package/buildtar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/package/buildtar b/scripts/package/buildtar index 8a7b15598ea..d0d748e7291 100644 --- a/scripts/package/buildtar +++ b/scripts/package/buildtar @@ -109,7 +109,7 @@ esac if tar --owner=root --group=root --help >/dev/null 2>&1; then opts="--owner=root --group=root" fi - tar cf - . $opts | ${compress} > "${tarball}${file_ext}" + tar cf - boot/* lib/* $opts | ${compress} > "${tarball}${file_ext}" ) echo "Tarball successfully created in ${tarball}${file_ext}" From b947fcbcca85da6ad3ec79f6aa86b550f458e049 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 10 Dec 2012 10:59:56 -0800 Subject: [PATCH 1696/2357] Linux 3.4.23 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 320663d2409..bf1df55f4f9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 22 +SUBLEVEL = 23 EXTRAVERSION = NAME = Saber-toothed Squirrel From 78a685beb044864de000a6f7339bce57513172bb Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 5 Dec 2012 14:01:41 -0800 Subject: [PATCH 1697/2357] tmpfs: fix shared mempolicy leak commit 18a2f371f5edf41810f6469cb9be39931ef9deb9 upstream. This fixes a regression in 3.7-rc, which has since gone into stable. Commit 00442ad04a5e ("mempolicy: fix a memory corruption by refcount imbalance in alloc_pages_vma()") changed get_vma_policy() to raise the refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went on expecting alloc_page_vma() to drop the refcount it had acquired. This deserves a rework: but for now fix the leak in shmem_alloc_page(). Hugh: shmem_swapin() did not need a fix, but surely it's clearer to use the same refcounting there as in shmem_alloc_page(), delete its onstack mempolicy, and the strange mpol_cond_copy() and __mpol_cond_copy() - those were invented to let swapin_readahead() make an unknown number of calls to alloc_pages_vma() with one mempolicy; but since 00442ad04a5e, alloc_pages_vma() has kept refcount in balance, so now no problem. Reported-and-tested-by: Tommi Rantala Signed-off-by: Mel Gorman Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/mempolicy.h | 16 ---------------- mm/mempolicy.c | 22 ---------------------- mm/shmem.c | 26 ++++++++++++++++---------- 3 files changed, 16 insertions(+), 48 deletions(-) diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 0abf1d436b1..fe07e5a9056 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -137,16 +137,6 @@ static inline void mpol_cond_put(struct mempolicy *pol) __mpol_put(pol); } -extern struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol, - struct mempolicy *frompol); -static inline struct mempolicy *mpol_cond_copy(struct mempolicy *tompol, - struct mempolicy *frompol) -{ - if (!frompol) - return frompol; - return __mpol_cond_copy(tompol, frompol); -} - extern struct mempolicy *__mpol_dup(struct mempolicy *pol); static inline struct mempolicy *mpol_dup(struct mempolicy *pol) { @@ -270,12 +260,6 @@ static inline void mpol_cond_put(struct mempolicy *pol) { } -static inline struct mempolicy *mpol_cond_copy(struct mempolicy *to, - struct mempolicy *from) -{ - return from; -} - static inline void mpol_get(struct mempolicy *pol) { } diff --git a/mm/mempolicy.c b/mm/mempolicy.c index d1e4beffbe1..458dedef9ee 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2009,28 +2009,6 @@ struct mempolicy *__mpol_dup(struct mempolicy *old) return new; } -/* - * If *frompol needs [has] an extra ref, copy *frompol to *tompol , - * eliminate the * MPOL_F_* flags that require conditional ref and - * [NOTE!!!] drop the extra ref. Not safe to reference *frompol directly - * after return. Use the returned value. - * - * Allows use of a mempolicy for, e.g., multiple allocations with a single - * policy lookup, even if the policy needs/has extra ref on lookup. - * shmem_readahead needs this. - */ -struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol, - struct mempolicy *frompol) -{ - if (!mpol_needs_cond_ref(frompol)) - return frompol; - - *tompol = *frompol; - tompol->flags &= ~MPOL_F_SHARED; /* copy doesn't need unref */ - __mpol_put(frompol); - return tompol; -} - /* Slow path of a mempolicy comparison */ bool __mpol_equal(struct mempolicy *a, struct mempolicy *b) { diff --git a/mm/shmem.c b/mm/shmem.c index a859b06d573..a409bd81781 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -798,24 +798,28 @@ static struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo) static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp, struct shmem_inode_info *info, pgoff_t index) { - struct mempolicy mpol, *spol; struct vm_area_struct pvma; - - spol = mpol_cond_copy(&mpol, - mpol_shared_policy_lookup(&info->policy, index)); + struct page *page; /* Create a pseudo vma that just contains the policy */ pvma.vm_start = 0; pvma.vm_pgoff = index; pvma.vm_ops = NULL; - pvma.vm_policy = spol; - return swapin_readahead(swap, gfp, &pvma, 0); + pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index); + + page = swapin_readahead(swap, gfp, &pvma, 0); + + /* Drop reference taken by mpol_shared_policy_lookup() */ + mpol_cond_put(pvma.vm_policy); + + return page; } static struct page *shmem_alloc_page(gfp_t gfp, struct shmem_inode_info *info, pgoff_t index) { struct vm_area_struct pvma; + struct page *page; /* Create a pseudo vma that just contains the policy */ pvma.vm_start = 0; @@ -823,10 +827,12 @@ static struct page *shmem_alloc_page(gfp_t gfp, pvma.vm_ops = NULL; pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index); - /* - * alloc_page_vma() will drop the shared policy reference - */ - return alloc_page_vma(gfp, &pvma, 0); + page = alloc_page_vma(gfp, &pvma, 0); + + /* Drop reference taken by mpol_shared_policy_lookup() */ + mpol_cond_put(pvma.vm_policy); + + return page; } #else /* !CONFIG_NUMA */ #ifdef CONFIG_TMPFS From e07aa3cc22bef722b29b247287d8e47d4c6c2b22 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 3 Dec 2012 09:17:19 -0500 Subject: [PATCH 1698/2357] Revert misapplied "mmc: sh-mmcif: avoid oops on spurious interrupts" commit 6984f3c31bb57cb7491dbec1be44b74bd00f4648 upstream. This reverts commit 8464dd52d3198dd05, which was a misapplied debugging version of the patch, not the final patch itself. Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sh_mmcif.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 3b8236bedee..724b35e85a2 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1191,10 +1191,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) host->sd_error = true; dev_dbg(&host->pd->dev, "int err state = %08x\n", state); } - if (host->state == STATE_IDLE) { - dev_info(&host->pd->dev, "Spurious IRQ status 0x%x", state); - return IRQ_HANDLED; - } if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { if (!host->dma_active) return IRQ_WAKE_THREAD; From 47dc7057a276a3394c94803dd66b395664ebc8f0 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 22 Aug 2012 06:49:47 +0000 Subject: [PATCH 1699/2357] mmc: sh-mmcif: avoid oops on spurious interrupts (second try) commit 91ab252ac5a5c3461dd6910797611e9172626aed upstream. On some systems, e.g., kzm9g, MMCIF interfaces can produce spurious interrupts without any active request. To prevent the Oops, that results in such cases, don't dereference the mmc request pointer until we make sure, that we are indeed processing such a request. Reported-by: Tetsuyuki Kobayashi Signed-off-by: Guennadi Liakhovetski Tested-by: Tetsuyuki Kobayashi Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sh_mmcif.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 724b35e85a2..a5786a837a2 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1066,7 +1066,6 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) { struct sh_mmcif_host *host = dev_id; struct mmc_request *mrq = host->mrq; - struct mmc_data *data = mrq->data; cancel_delayed_work_sync(&host->timeout_work); @@ -1114,13 +1113,14 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) case MMCIF_WAIT_FOR_READ_END: case MMCIF_WAIT_FOR_WRITE_END: if (host->sd_error) - data->error = sh_mmcif_error_manage(host); + mrq->data->error = sh_mmcif_error_manage(host); break; default: BUG(); } if (host->wait_for != MMCIF_WAIT_FOR_STOP) { + struct mmc_data *data = mrq->data; if (!mrq->cmd->error && data && !data->error) data->bytes_xfered = data->blocks * data->blksz; From 1b59789b7d3aca70cca0a7b66e57a4a78fcd12d4 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 23 Oct 2012 20:32:59 +0100 Subject: [PATCH 1700/2357] ARM: 7566/1: vfp: fix save and restore when running on pre-VFPv3 and CONFIG_VFPv3 set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 39141ddfb63a664f26d3f42f64ee386e879b492c upstream. After commit 846a136881b8f73c1f74250bf6acfaa309cab1f2 ("ARM: vfp: fix saving d16-d31 vfp registers on v6+ kernels"), the OMAP 2430SDP board started crashing during boot with omap2plus_defconfig: [ 3.875122] mmcblk0: mmc0:e624 SD04G 3.69 GiB [ 3.915954] mmcblk0: p1 [ 4.086639] Internal error: Oops - undefined instruction: 0 [#1] SMP ARM [ 4.093719] Modules linked in: [ 4.096954] CPU: 0 Not tainted (3.6.0-02232-g759e00b #570) [ 4.103149] PC is at vfp_reload_hw+0x1c/0x44 [ 4.107666] LR is at __und_usr_fault_32+0x0/0x8 It turns out that the context save/restore fix unmasked a latent bug in commit 5aaf254409f8d58229107b59507a8235b715a960 ("ARM: 6203/1: Make VFPv3 usable on ARMv6"). When CONFIG_VFPv3 is set, but the kernel is booted on a pre-VFPv3 core, the code attempts to save and restore the d16-d31 VFP registers. These are only present on non-D16 VFPv3+, so this results in an undefined instruction exception. The code didn't crash before commit 846a136 because the save and restore code was only touching d0-d15, present on all VFP. Fix by implementing a request from Russell King to add a new HWCAP flag that affirmatively indicates the presence of the d16-d31 registers: http://marc.info/?l=linux-arm-kernel&m=135013547905283&w=2 and some feedback from Måns to clarify the name of the HWCAP flag. Signed-off-by: Paul Walmsley Cc: Tony Lindgren Cc: Catalin Marinas Cc: Dave Martin Cc: Måns Rullgård Signed-off-by: Russell King Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/hwcap.h | 3 ++- arch/arm/include/asm/vfpmacros.h | 12 ++++++------ arch/arm/vfp/vfpmodule.c | 9 ++++++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/arch/arm/include/asm/hwcap.h b/arch/arm/include/asm/hwcap.h index 917626128a1..a2fe893802a 100644 --- a/arch/arm/include/asm/hwcap.h +++ b/arch/arm/include/asm/hwcap.h @@ -18,11 +18,12 @@ #define HWCAP_THUMBEE (1 << 11) #define HWCAP_NEON (1 << 12) #define HWCAP_VFPv3 (1 << 13) -#define HWCAP_VFPv3D16 (1 << 14) +#define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */ #define HWCAP_TLS (1 << 15) #define HWCAP_VFPv4 (1 << 16) #define HWCAP_IDIVA (1 << 17) #define HWCAP_IDIVT (1 << 18) +#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */ #define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) #if defined(__KERNEL__) diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h index bf5304797c7..c49c8f778b5 100644 --- a/arch/arm/include/asm/vfpmacros.h +++ b/arch/arm/include/asm/vfpmacros.h @@ -27,9 +27,9 @@ #if __LINUX_ARM_ARCH__ <= 6 ldr \tmp, =elf_hwcap @ may not have MVFR regs ldr \tmp, [\tmp, #0] - tst \tmp, #HWCAP_VFPv3D16 - ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} - addne \base, \base, #32*4 @ step over unused register space + tst \tmp, #HWCAP_VFPD32 + ldcnel p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} + addeq \base, \base, #32*4 @ step over unused register space #else VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field @@ -51,9 +51,9 @@ #if __LINUX_ARM_ARCH__ <= 6 ldr \tmp, =elf_hwcap @ may not have MVFR regs ldr \tmp, [\tmp, #0] - tst \tmp, #HWCAP_VFPv3D16 - stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} - addne \base, \base, #32*4 @ step over unused register space + tst \tmp, #HWCAP_VFPD32 + stcnel p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} + addeq \base, \base, #32*4 @ step over unused register space #else VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 1f8241da03b..3b360625af7 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -701,11 +701,14 @@ static int __init vfp_init(void) elf_hwcap |= HWCAP_VFPv3; /* - * Check for VFPv3 D16. CPUs in this configuration - * only have 16 x 64bit registers. + * Check for VFPv3 D16 and VFPv4 D16. CPUs in + * this configuration only have 16 x 64bit + * registers. */ if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) - elf_hwcap |= HWCAP_VFPv3D16; + elf_hwcap |= HWCAP_VFPv3D16; /* also v4-D16 */ + else + elf_hwcap |= HWCAP_VFPD32; } #endif /* From a11bf0aa146b60e917dc30348e301d6a7d13dcbd Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Oct 2012 12:29:26 +0300 Subject: [PATCH 1701/2357] ASoC: dmaengine: Correct Makefile when sound is built as module commit 961a7aeafab477f63d9eef26afde9cbb8badcd0f upstream. soc-dmaengine-pcm library need to be part of the snd-soc-core in order to be able to compile ASoC as modules when dmaengine is enabled on the platform. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown Cc: Florian Fainelli Signed-off-by: Greg Kroah-Hartman --- sound/soc/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 2feaf376e94..0f370861bba 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,8 +1,9 @@ snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o snd-soc-core-objs += soc-pcm.o soc-io.o -snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o -obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o +ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),) +snd-soc-core-objs += soc-dmaengine-pcm.o +endif obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ From 4afca924c03e95345be979bfb7abbfa85963fada Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 4 Dec 2012 07:40:39 -0800 Subject: [PATCH 1702/2357] workqueue: convert BUG_ON()s in __queue_delayed_work() to WARN_ON_ONCE()s commit fc4b514f2727f74a4587c31db87e0e93465518c3 upstream. 8852aac25e ("workqueue: mod_delayed_work_on() shouldn't queue timer on 0 delay") unexpectedly uncovered a very nasty abuse of delayed_work in megaraid - it allocated work_struct, casted it to delayed_work and then pass that into queue_delayed_work(). Previously, this was okay because 0 @delay short-circuited to queue_work() before doing anything with delayed_work. 8852aac25e moved 0 @delay test into __queue_delayed_work() after sanity check on delayed_work making megaraid trigger BUG_ON(). Although megaraid is already fixed by c1d390d8e6 ("megaraid: fix BUG_ON() from incorrect use of delayed work"), this patch converts BUG_ON()s in __queue_delayed_work() to WARN_ON_ONCE()s so that such abusers, if there are more, trigger warning but don't crash the machine. Signed-off-by: Tejun Heo Cc: Xiaotian Feng Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- kernel/workqueue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index bcb9d342714..a64b94e3c27 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1141,8 +1141,8 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) { unsigned int lcpu; - BUG_ON(timer_pending(timer)); - BUG_ON(!list_empty(&work->entry)); + WARN_ON_ONCE(timer_pending(timer)); + WARN_ON_ONCE(!list_empty(&work->entry)); timer_stats_timer_set_start_info(&dwork->timer); From 11b73096b67cde81ba05125cecb06fe9884e4cb7 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 12 Nov 2012 14:33:44 +0200 Subject: [PATCH 1703/2357] drm/i915: do not ignore eDP bpc settings from vbt commit 2f4f649a69a9eb51f6e98130e19dd90a260a4145 upstream. There are laptops out there that need the eDP bpc from VBT. This is effectively a revert of commit 4344b813f105a19f793f1fd93ad775b784648b95 Author: Daniel Vetter Date: Fri Aug 10 11:10:20 2012 +0200 drm/i915: ignore eDP bpc settings from vbt but putting the VBT check after the EDID check to see them both in dmesg if this clamps more than the EDID. We have enough history with bpc clamping to warrant the extra debug info. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=47641 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=56401 Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f3b06f04e01..c9ea4fba447 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4996,6 +4996,17 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, } } + if (intel_encoder->type == INTEL_OUTPUT_EDP) { + /* Use VBT settings if we have an eDP panel */ + unsigned int edp_bpc = dev_priv->edp.bpp / 3; + + if (edp_bpc < display_bpc) { + DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc); + display_bpc = edp_bpc; + } + continue; + } + /* * HDMI is either 12 or 8, so if the display lets 10bpc sneak * through, clamp it down. (Note: >12bpc will be caught below.) From d7ba8dff3e8afc83efe19c52ac7bd9ee2b65720b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 12 Nov 2012 14:33:45 +0200 Subject: [PATCH 1704/2357] drm/i915: do not default to 18 bpp for eDP if missing from VBT commit 9a30a61f3516871c5c638fd7c025fbaa11ddf7fe upstream. commit 500a8cc466a24e2fbc4c86ef9c6467ae2ffdeb0c Author: Zhenyu Wang Date: Wed Jan 13 11:19:52 2010 +0800 drm/i915: parse eDP panel color depth from VBT block originally introduced parsing bpp for eDP from VBT, with a default of 18 bpp if the eDP BIOS data block is not present. Turns out that default seems to break the Macbook Pro with retina display, as noted in commit 4344b813f105a19f793f1fd93ad775b784648b95 Author: Daniel Vetter Date: Fri Aug 10 11:10:20 2012 +0200 drm/i915: ignore eDP bpc settings from vbt Since we can't ignore bpc settings from VBT completely after all, get rid of the default. Do not clamp eDP to 18 bpp by default if the eDP BDB is missing from VBT. Signed-off-by: Jani Nikula Tested-by: Henrik Rydberg [danvet: paste in the updated commit message from irc.] Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_bios.c | 11 ++--------- drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index b48fc2a8410..3fe05245d3f 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -459,12 +459,8 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) edp = find_section(bdb, BDB_EDP); if (!edp) { - if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) { - DRM_DEBUG_KMS("No eDP BDB found but eDP panel " - "supported, assume %dbpp panel color " - "depth.\n", - dev_priv->edp.bpp); - } + if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) + DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); return; } @@ -617,9 +613,6 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) dev_priv->lvds_use_ssc = 1; dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq); - - /* eDP data */ - dev_priv->edp.bpp = 18; } static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c9ea4fba447..dd3e7e44023 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5000,7 +5000,7 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, /* Use VBT settings if we have an eDP panel */ unsigned int edp_bpc = dev_priv->edp.bpp / 3; - if (edp_bpc < display_bpc) { + if (edp_bpc && edp_bpc < display_bpc) { DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc); display_bpc = edp_bpc; } From ead8c6b3697c9d45c16ecad17e5b4101573767f9 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 7 Nov 2012 15:37:07 +0100 Subject: [PATCH 1705/2357] mm: dmapool: use provided gfp flags for all dma_alloc_coherent() calls commit 387870f2d6d679746020fa8e25ef786ff338dc98 upstream. dmapool always calls dma_alloc_coherent() with GFP_ATOMIC flag, regardless the flags provided by the caller. This causes excessive pruning of emergency memory pools without any good reason. Additionaly, on ARM architecture any driver which is using dmapools will sooner or later trigger the following error: "ERROR: 256 KiB atomic DMA coherent pool is too small! Please increase it with coherent_pool= kernel parameter!". Increasing the coherent pool size usually doesn't help much and only delays such error, because all GFP_ATOMIC DMA allocations are always served from the special, very limited memory pool. This patch changes the dmapool code to correctly use gfp flags provided by the dmapool caller. Reported-by: Soeren Moch Reported-by: Thomas Petazzoni Signed-off-by: Marek Szyprowski Tested-by: Andrew Lunn Tested-by: Soeren Moch Signed-off-by: Greg Kroah-Hartman --- mm/dmapool.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/mm/dmapool.c b/mm/dmapool.c index c5ab33bca0a..da1b0f0b870 100644 --- a/mm/dmapool.c +++ b/mm/dmapool.c @@ -50,7 +50,6 @@ struct dma_pool { /* the pool */ size_t allocation; size_t boundary; char name[32]; - wait_queue_head_t waitq; struct list_head pools; }; @@ -62,8 +61,6 @@ struct dma_page { /* cacheable header for 'allocation' bytes */ unsigned int offset; }; -#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) - static DEFINE_MUTEX(pools_lock); static ssize_t @@ -172,7 +169,6 @@ struct dma_pool *dma_pool_create(const char *name, struct device *dev, retval->size = size; retval->boundary = boundary; retval->allocation = allocation; - init_waitqueue_head(&retval->waitq); if (dev) { int ret; @@ -227,7 +223,6 @@ static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags) memset(page->vaddr, POOL_POISON_FREED, pool->allocation); #endif pool_initialise_page(pool, page); - list_add(&page->page_list, &pool->page_list); page->in_use = 0; page->offset = 0; } else { @@ -315,30 +310,21 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, might_sleep_if(mem_flags & __GFP_WAIT); spin_lock_irqsave(&pool->lock, flags); - restart: list_for_each_entry(page, &pool->page_list, page_list) { if (page->offset < pool->allocation) goto ready; } - page = pool_alloc_page(pool, GFP_ATOMIC); - if (!page) { - if (mem_flags & __GFP_WAIT) { - DECLARE_WAITQUEUE(wait, current); - __set_current_state(TASK_UNINTERRUPTIBLE); - __add_wait_queue(&pool->waitq, &wait); - spin_unlock_irqrestore(&pool->lock, flags); + /* pool_alloc_page() might sleep, so temporarily drop &pool->lock */ + spin_unlock_irqrestore(&pool->lock, flags); - schedule_timeout(POOL_TIMEOUT_JIFFIES); + page = pool_alloc_page(pool, mem_flags); + if (!page) + return NULL; - spin_lock_irqsave(&pool->lock, flags); - __remove_wait_queue(&pool->waitq, &wait); - goto restart; - } - retval = NULL; - goto done; - } + spin_lock_irqsave(&pool->lock, flags); + list_add(&page->page_list, &pool->page_list); ready: page->in_use++; offset = page->offset; @@ -348,7 +334,6 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, #ifdef DMAPOOL_DEBUG memset(retval, POOL_POISON_ALLOCATED, pool->size); #endif - done: spin_unlock_irqrestore(&pool->lock, flags); return retval; } @@ -435,8 +420,6 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma) page->in_use--; *(int *)vaddr = page->offset; page->offset = offset; - if (waitqueue_active(&pool->waitq)) - wake_up_locked(&pool->waitq); /* * Resist a temptation to do * if (!is_page_busy(page)) pool_free_page(pool, page); From 5678ad746ce7654007d3fd521015ff93ef907747 Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Wed, 5 Dec 2012 06:12:42 -0500 Subject: [PATCH 1706/2357] x86,AMD: Power driver support for AMD's family 16h processors commit 22e32f4f57778ebc6e17812fa3008361c05d64f9 upstream. Add family 16h PCI ID to AMD's power driver to allow it report power consumption on these processors. Signed-off-by: Boris Ostrovsky Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/fam15h_power.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index ac2d6cb39e7..770e95951a5 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -31,6 +31,9 @@ MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor"); MODULE_AUTHOR("Andreas Herrmann "); MODULE_LICENSE("GPL"); +/* Family 16h Northbridge's function 4 PCI ID */ +#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534 + /* D18F3 */ #define REG_NORTHBRIDGE_CAP 0xe8 @@ -256,6 +259,7 @@ static void __devexit fam15h_power_remove(struct pci_dev *pdev) static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) }, {} }; MODULE_DEVICE_TABLE(pci, fam15h_power_id_table); From 2ee75ba7f69754ee04e723b037b15715c0483d50 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 3 Dec 2012 22:05:12 +0300 Subject: [PATCH 1707/2357] telephony: ijx: buffer overflow in ixj_write_cid() [Not needed in 3.8 or newer as this driver is removed there. - gregkh] We get this from user space and nothing has been done to ensure that these strings are NUL terminated. Reported-by: Chen Gang Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/telephony/ixj.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/staging/telephony/ixj.c b/drivers/staging/telephony/ixj.c index f96027921f6..638d2b8c687 100644 --- a/drivers/staging/telephony/ixj.c +++ b/drivers/staging/telephony/ixj.c @@ -3190,12 +3190,12 @@ static void ixj_write_cid(IXJ *j) ixj_fsk_alloc(j); - strcpy(sdmf1, j->cid_send.month); - strcat(sdmf1, j->cid_send.day); - strcat(sdmf1, j->cid_send.hour); - strcat(sdmf1, j->cid_send.min); - strcpy(sdmf2, j->cid_send.number); - strcpy(sdmf3, j->cid_send.name); + strlcpy(sdmf1, j->cid_send.month, sizeof(sdmf1)); + strlcat(sdmf1, j->cid_send.day, sizeof(sdmf1)); + strlcat(sdmf1, j->cid_send.hour, sizeof(sdmf1)); + strlcat(sdmf1, j->cid_send.min, sizeof(sdmf1)); + strlcpy(sdmf2, j->cid_send.number, sizeof(sdmf2)); + strlcpy(sdmf3, j->cid_send.name, sizeof(sdmf3)); len1 = strlen(sdmf1); len2 = strlen(sdmf2); @@ -3340,12 +3340,12 @@ static void ixj_write_cidcw(IXJ *j) ixj_pre_cid(j); } j->flags.cidcw_ack = 0; - strcpy(sdmf1, j->cid_send.month); - strcat(sdmf1, j->cid_send.day); - strcat(sdmf1, j->cid_send.hour); - strcat(sdmf1, j->cid_send.min); - strcpy(sdmf2, j->cid_send.number); - strcpy(sdmf3, j->cid_send.name); + strlcpy(sdmf1, j->cid_send.month, sizeof(sdmf1)); + strlcat(sdmf1, j->cid_send.day, sizeof(sdmf1)); + strlcat(sdmf1, j->cid_send.hour, sizeof(sdmf1)); + strlcat(sdmf1, j->cid_send.min, sizeof(sdmf1)); + strlcpy(sdmf2, j->cid_send.number, sizeof(sdmf2)); + strlcpy(sdmf3, j->cid_send.name, sizeof(sdmf3)); len1 = strlen(sdmf1); len2 = strlen(sdmf2); From 280c7a49c54e1191ddff18db0f44f1f404408829 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 2 Nov 2012 14:02:40 +0000 Subject: [PATCH 1708/2357] x86: hpet: Fix masking of MSI interrupts commit 6acf5a8c931da9d26c8dd77d784daaf07fa2bff0 upstream. HPET_TN_FSB is not a proper mask bit; it merely toggles between MSI and legacy interrupt delivery. The proper mask bit is HPET_TN_ENABLE, so use both bits when (un)masking the interrupt. Signed-off-by: Jan Beulich Link: http://lkml.kernel.org/r/5093E09002000078000A60E6@nat28.tlf.novell.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/hpet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index ad0de0c2714..2861b4cafd2 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -431,7 +431,7 @@ void hpet_msi_unmask(struct irq_data *data) /* unmask it */ cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); - cfg |= HPET_TN_FSB; + cfg |= HPET_TN_ENABLE | HPET_TN_FSB; hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); } @@ -442,7 +442,7 @@ void hpet_msi_mask(struct irq_data *data) /* mask it */ cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); - cfg &= ~HPET_TN_FSB; + cfg &= ~(HPET_TN_ENABLE | HPET_TN_FSB); hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); } From d1687be63d3037bd98ab8e0e5e34fc724f0863a1 Mon Sep 17 00:00:00 2001 From: "li.rui27@zte.com.cn" Date: Tue, 20 Nov 2012 14:31:47 +0800 Subject: [PATCH 1709/2357] USB: add new zte 3g-dongle's pid to option.c commit 31b6a1048b7292efff8b5b53ae3d9d29adde385e upstream. Signed-off-by: Rui li Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 43aa36bcd39..329fe2b8e53 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -883,6 +883,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0128, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0135, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0136, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0137, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0139, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0142, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0143, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0144, 0xff, 0xff, 0xff) }, @@ -903,20 +907,34 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0189, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0191, 0xff, 0xff, 0xff), /* ZTE EuFi890 */ .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0196, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0197, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0199, 0xff, 0xff, 0xff), /* ZTE MF820S */ .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0200, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0201, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0254, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0330, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0395, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1021, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, @@ -1096,6 +1114,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1301, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1302, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1303, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1333, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1401, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), From 249d474cd9320f25ab04832e5b03b98462930362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sun, 25 Nov 2012 17:05:10 +0100 Subject: [PATCH 1710/2357] USB: option: blacklist network interface on Huawei E173 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f36446cf9bbebaa03a80d95cfeeafbaf68218249 upstream. The Huawei E173 will normally appear as 12d1:1436 in Linux. But the modem has another mode with different device ID and a slightly different set of descriptors. This is the mode used by Windows like this: 3Modem: USB\VID_12D1&PID_140C&MI_00\6&3A1D2012&0&0000 Networkcard: USB\VID_12D1&PID_140C&MI_01\6&3A1D2012&0&0001 Appli.Inter: USB\VID_12D1&PID_140C&MI_02\6&3A1D2012&0&0002 PC UI Inter: USB\VID_12D1&PID_140C&MI_03\6&3A1D2012&0&0003 All interfaces have the same ff/ff/ff class codes in this mode. Blacklisting the network interface to allow it to be picked up by the network driver. Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 329fe2b8e53..0c3d2903481 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -80,6 +80,7 @@ static void option_instat_callback(struct urb *urb); #define OPTION_PRODUCT_GTM380_MODEM 0x7201 #define HUAWEI_VENDOR_ID 0x12D1 +#define HUAWEI_PRODUCT_E173 0x140C #define HUAWEI_PRODUCT_K4505 0x1464 #define HUAWEI_PRODUCT_K3765 0x1465 #define HUAWEI_PRODUCT_K4605 0x14C6 @@ -552,6 +553,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), From c36337a3562352a753995cb220b58f81f5e81e74 Mon Sep 17 00:00:00 2001 From: Martin Teichmann Date: Wed, 21 Nov 2012 16:45:07 +0100 Subject: [PATCH 1711/2357] USB: ftdi_sio: Add support for Newport AGILIS motor drivers commit d7e14b375b40c04cd735b115713043b69a2c68ac upstream. The Newport AGILIS model AG-UC8 compact piezo motor controller (http://search.newport.com/?q=*&x2=sku&q2=AG-UC8) is yet another device using an FTDI USB-to-serial chip. It works fine with the ftdi_sio driver when adding options ftdi-sio product=0x3000 vendor=0x104d to modprobe.d. udevadm reports "Newport" as the manufacturer, and "Agilis" as the product name. Signed-off-by: Martin Teichmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 25bb9350396..dd6b0270f68 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -197,6 +197,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, + { USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 57c12ef6625..049b6e715fa 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -752,6 +752,12 @@ #define TTI_VID 0x103E /* Vendor Id */ #define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */ +/* + * Newport Cooperation (www.newport.com) + */ +#define NEWPORT_VID 0x104D +#define NEWPORT_AGILIS_PID 0x3000 + /* Interbiometrics USB I/O Board */ /* Developed for Interbiometrics by Rudolf Gugler */ #define INTERBIOMETRICS_VID 0x1209 From 73b01ef413e7311e5dff622a1e50fe86d7253273 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 22 Nov 2012 16:30:46 +0100 Subject: [PATCH 1712/2357] usb: ftdi_sio: fixup BeagleBone A5+ quirk commit 1a88d5eee2ef2ad1d3c4e32043e9c4c5347d4fc1 upstream. BeagleBone A5+ devices ended up getting shipped with the 'BeagleBone/XDS100V2' product string, and not XDS100 like it was agreed, so adjust the quirk to match. For details, see the thread on the beagle list: https://groups.google.com/forum/#!msg/beagleboard/zrFPew9_Wvo/ibWr1-eE8JwJ Signed-off-by: Peter Korsgaard Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index dd6b0270f68..25903f54c1d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1811,7 +1811,7 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) dbg("%s", __func__); if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || - (udev->product && !strcmp(udev->product, "BeagleBone/XDS100"))) + (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2"))) return ftdi_jtag_probe(serial); return 0; From 7052793cd192c09b47c4fb307bc3c2afbdf3c5df Mon Sep 17 00:00:00 2001 From: Markus Becker Date: Thu, 22 Nov 2012 09:41:23 +0100 Subject: [PATCH 1713/2357] USB: cp210x: add Virtenio Preon32 device id commit 356fe44f4b8ece867bdb9876b1854d7adbef9de2 upstream. Signed-off-by: Markus Becker Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 53e7e692d61..f38a2783146 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -120,6 +120,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ + { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ From 46c117c706ef4f4086cbe24d24fd0f19551e96bd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 28 Nov 2012 10:19:16 -0800 Subject: [PATCH 1714/2357] USB: mark uas driver as BROKEN commit fb37ef98015f864d22be223a0e0d93547cd1d4ef upstream. As reported https://bugzilla.kernel.org/show_bug.cgi?id=51031, the UAS driver causes problems and has been asked to be not built into any of the major distributions. To prevent users from running into problems with it, and for distros that were not notified, just mark the whole thing as broken. Acked-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 7691c866637..685edc87265 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -203,7 +203,7 @@ config USB_STORAGE_ENE_UB6250 config USB_UAS tristate "USB Attached SCSI" - depends on USB && SCSI + depends on USB && SCSI && BROKEN help The USB Attached SCSI protocol is supported by some USB storage devices. It permits higher performance by supporting From b49dc13a7f10e003e176263215411ccea99380f1 Mon Sep 17 00:00:00 2001 From: Kamil Iskra Date: Fri, 16 Nov 2012 22:28:58 +0100 Subject: [PATCH 1715/2357] ACPI / battery: Correct battery capacity values on Thinkpads commit 4000e626156935dfb626321ce09cae2c833eabbb upstream. Add a quirk to correctly report battery capacity on 2010 and 2011 Lenovo Thinkpad models. The affected models that I tested (x201, t410, t410s, and x220) exhibit a problem where, when battery capacity reporting unit is mAh, the values being reported are wrong. Pre-2010 and 2012 models appear to always report in mWh and are thus unaffected. Also, in mid-2012 Lenovo issued a BIOS update for the 2011 models that fixes the issue (tested on x220 with a post-1.29 BIOS). No such update is available for the 2010 models, so those still need this patch. Problem description: for some reason, the affected Thinkpads switch the reporting unit between mAh and mWh; generally, mAh is used when a laptop is plugged in and mWh when it's unplugged, although a suspend/resume or rmmod/modprobe is needed for the switch to take effect. The values reported in mAh are *always* wrong. This does not appear to be a kernel regression; I believe that the values were never reported correctly. I tested back to kernel 2.6.34, with multiple machines and BIOS versions. Simply plugging a laptop into mains before turning it on is enough to reproduce the problem. Here's a sample /proc/acpi/battery/BAT0/info from Thinkpad x220 (before a BIOS update) with a 4-cell battery: present: yes design capacity: 2886 mAh last full capacity: 2909 mAh battery technology: rechargeable design voltage: 14800 mV design capacity warning: 145 mAh design capacity low: 13 mAh cycle count: 0 capacity granularity 1: 1 mAh capacity granularity 2: 1 mAh model number: 42T4899 serial number: 21064 battery type: LION OEM info: SANYO Once the laptop switches the unit to mWh (unplug from mains, suspend, resume), the output changes to: present: yes design capacity: 28860 mWh last full capacity: 29090 mWh battery technology: rechargeable design voltage: 14800 mV design capacity warning: 1454 mWh design capacity low: 200 mWh cycle count: 0 capacity granularity 1: 1 mWh capacity granularity 2: 1 mWh model number: 42T4899 serial number: 21064 battery type: LION OEM info: SANYO Can you see how the values for "design capacity", etc., differ by a factor of 10 instead of 14.8 (the design voltage of this battery)? On the battery itself it says: 14.8V, 1.95Ah, 29Wh, so clearly the values reported in mWh are correct and the ones in mAh are not. My guess is that this problem has been around ever since those machines were released, but because the most common Thinkpad batteries are rated at 10.8V, the error (8%) is small enough that it simply hasn't been noticed or at least nobody could be bothered to look into it. My patch works around the problem by adjusting the incorrectly reported mAh values by "10000 / design_voltage". The patch also has code to figure out if it should be activated or not. It only activates on Lenovo Thinkpads, only when the unit is mAh, and, as an extra precaution, only when the battery capacity reported through ACPI does not match what is reported through DMI (I've never encountered a machine where the first two conditions would be true but the last would not, but better safe than sorry). I've been using this patch for close to a year on several systems without any problems. References: https://bugzilla.kernel.org/show_bug.cgi?id=41062 Acked-by: Henrique de Moraes Holschuh Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/battery.c | 77 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 7dd3f9fb9f3..6ea287e2229 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI_PROCFS_POWER #include @@ -95,6 +96,18 @@ enum { ACPI_BATTERY_ALARM_PRESENT, ACPI_BATTERY_XINFO_PRESENT, ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, + /* On Lenovo Thinkpad models from 2010 and 2011, the power unit + switches between mWh and mAh depending on whether the system + is running on battery or not. When mAh is the unit, most + reported values are incorrect and need to be adjusted by + 10000/design_voltage. Verified on x201, t410, t410s, and x220. + Pre-2010 and 2012 models appear to always report in mWh and + are thus unaffected (tested with t42, t61, t500, x200, x300, + and x230). Also, in mid-2012 Lenovo issued a BIOS update for + the 2011 models that fixes the issue (tested on x220 with a + post-1.29 BIOS), but as of Nov. 2012, no such update is + available for the 2010 models. */ + ACPI_BATTERY_QUIRK_THINKPAD_MAH, }; struct acpi_battery { @@ -429,6 +442,21 @@ static int acpi_battery_get_info(struct acpi_battery *battery) kfree(buffer.pointer); if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) battery->full_charge_capacity = battery->design_capacity; + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) && + battery->power_unit && battery->design_voltage) { + battery->design_capacity = battery->design_capacity * + 10000 / battery->design_voltage; + battery->full_charge_capacity = battery->full_charge_capacity * + 10000 / battery->design_voltage; + battery->design_capacity_warning = + battery->design_capacity_warning * + 10000 / battery->design_voltage; + /* Curiously, design_capacity_low, unlike the rest of them, + is correct. */ + /* capacity_granularity_* equal 1 on the systems tested, so + it's impossible to tell if they would need an adjustment + or not if their values were higher. */ + } return result; } @@ -477,6 +505,11 @@ static int acpi_battery_get_state(struct acpi_battery *battery) && battery->capacity_now >= 0 && battery->capacity_now <= 100) battery->capacity_now = (battery->capacity_now * battery->full_charge_capacity) / 100; + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) && + battery->power_unit && battery->design_voltage) { + battery->capacity_now = battery->capacity_now * + 10000 / battery->design_voltage; + } return result; } @@ -586,6 +619,24 @@ static void sysfs_remove_battery(struct acpi_battery *battery) mutex_unlock(&battery->sysfs_lock); } +static void find_battery(const struct dmi_header *dm, void *private) +{ + struct acpi_battery *battery = (struct acpi_battery *)private; + /* Note: the hardcoded offsets below have been extracted from + the source code of dmidecode. */ + if (dm->type == DMI_ENTRY_PORTABLE_BATTERY && dm->length >= 8) { + const u8 *dmi_data = (const u8 *)(dm + 1); + int dmi_capacity = get_unaligned((const u16 *)(dmi_data + 6)); + if (dm->length >= 18) + dmi_capacity *= dmi_data[17]; + if (battery->design_capacity * battery->design_voltage / 1000 + != dmi_capacity && + battery->design_capacity * 10 == dmi_capacity) + set_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, + &battery->flags); + } +} + /* * According to the ACPI spec, some kinds of primary batteries can * report percentage battery remaining capacity directly to OS. @@ -611,6 +662,32 @@ static void acpi_battery_quirks(struct acpi_battery *battery) battery->capacity_now = (battery->capacity_now * battery->full_charge_capacity) / 100; } + + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags)) + return ; + + if (battery->power_unit && dmi_name_in_vendors("LENOVO")) { + const char *s; + s = dmi_get_system_info(DMI_PRODUCT_VERSION); + if (s && !strnicmp(s, "ThinkPad", 8)) { + dmi_walk(find_battery, battery); + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, + &battery->flags) && + battery->design_voltage) { + battery->design_capacity = + battery->design_capacity * + 10000 / battery->design_voltage; + battery->full_charge_capacity = + battery->full_charge_capacity * + 10000 / battery->design_voltage; + battery->design_capacity_warning = + battery->design_capacity_warning * + 10000 / battery->design_voltage; + battery->capacity_now = battery->capacity_now * + 10000 / battery->design_voltage; + } + } + } } static int acpi_battery_update(struct acpi_battery *battery) From b54b1f3b656a93e874b38d88c513769c2f29bf6b Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 21 Nov 2012 23:12:12 +0100 Subject: [PATCH 1716/2357] ACPI / PM: Add Sony Vaio VPCEB1S1E to nonvs blacklist. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 876ab79055019e248508cfd0dee7caa3c0c831ed upstream. Sony Vaio VPCEB1S1E does not resume correctly without acpi_sleep=nonvs, so add it to the ACPI sleep blacklist. References: https://bugzilla.kernel.org/show_bug.cgi?id=48781 Reported-by: Sébastien Wilmet Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/sleep.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 2377445f4a3..480b648b9a1 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -508,6 +508,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { }, { .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB1S1E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"), + }, + }, + { + .callback = init_nvs_nosave, .ident = "Sony Vaio VGN-FW520F", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), From fe1fa6761bdc53fd7be7524436ad00907100c054 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 Nov 2012 13:05:05 +0100 Subject: [PATCH 1717/2357] ACPI / PNP: Do not crash due to stale pointer use during system resume commit a6b5e88c0e42093b9057856f35770966c8c591e3 upstream. During resume from system suspend the 'data' field of struct pnp_dev in pnpacpi_set_resources() may be a stale pointer, due to removal of the associated ACPI device node object in the previous suspend-resume cycle. This happens, for example, if a dockable machine is booted in the docking station and then suspended and resumed and suspended again. If that happens, pnpacpi_build_resource_template() called from pnpacpi_set_resources() attempts to use that pointer and crashes. However, pnpacpi_set_resources() actually checks the device's ACPI handle, attempts to find the ACPI device node object attached to it and returns an error code if that fails, so in fact it knows what the correct value of dev->data should be. Use this observation to update dev->data with the correct value if necessary and dump a call trace if that's the case (once). We still need to fix the root cause of this issue, but preventing systems from crashing because of it is an improvement too. Reported-and-tested-by: Zdenek Kabelac References: https://bugzilla.kernel.org/show_bug.cgi?id=51071 Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/pnp/pnpacpi/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index d21e8f59c84..e3537888db7 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -95,6 +95,9 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) return -ENODEV; } + if (WARN_ON_ONCE(acpi_dev != dev->data)) + dev->data = acpi_dev; + ret = pnpacpi_build_resource_template(dev, &buffer); if (ret) return ret; From a5e247e527586e4edee5f24d5e8f85ecf1905ea7 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 4 Dec 2012 23:30:19 +0100 Subject: [PATCH 1718/2357] ACPI / video: ignore BIOS initial backlight value for HP Folio 13-2000 commit 129ff8f8d58297b04f47b5d6fad81aa2d08404e1 upstream. Or else the laptop will boot with a dimmed screen. References: https://bugzilla.kernel.org/show_bug.cgi?id=51141 Tested-by: Stefan Nagy Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/video.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 62d9ee6d077..91357e1a1a8 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -389,6 +389,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d) return 0; } +static int video_ignore_initial_backlight(const struct dmi_system_id *d) +{ + use_bios_initial_backlight = 0; + return 0; +} + static struct dmi_system_id video_dmi_table[] __initdata = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 @@ -433,6 +439,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"), }, }, + { + .callback = video_ignore_initial_backlight, + .ident = "HP Folio 13-2000", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13 - 2000 Notebook PC"), + }, + }, {} }; From 96d791a8023037c312072a5a9d735417a07a6c5a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 26 Nov 2012 12:36:21 -0500 Subject: [PATCH 1719/2357] USB: OHCI: workaround for hardware bug: retired TDs not added to the Done Queue commit 50ce5c0683aa83eb161624ea89daa5a9eee0c2ce upstream. This patch (as1636) is a partial workaround for a hardware bug affecting OHCI controllers by NVIDIA at least, maybe others too. When the controller retires a Transfer Descriptor, it is supposed to add the TD onto the Done Queue. But sometimes this doesn't happen, with the result that ohci-hcd never realizes the corresponding transfer has finished. Symptoms can vary; a typical result is that USB audio stops working after a while. The patch works around the problem by recognizing that TDs are always processed in order. Therefore, if a later TD is found on the Done Queue than all the earlier TDs for the same endpoint must be finished as well. Unfortunately this won't solve the problem in cases where the missing TD is the last one in the endpoint's queue. A complete fix would require a signficant amount of change to the driver. Signed-off-by: Alan Stern Tested-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-q.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index c5a1ea9145f..9d00d4721bc 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -1128,6 +1128,25 @@ dl_done_list (struct ohci_hcd *ohci) while (td) { struct td *td_next = td->next_dl_td; + struct ed *ed = td->ed; + + /* + * Some OHCI controllers (NVIDIA for sure, maybe others) + * occasionally forget to add TDs to the done queue. Since + * TDs for a given endpoint are always processed in order, + * if we find a TD on the donelist then all of its + * predecessors must be finished as well. + */ + for (;;) { + struct td *td2; + + td2 = list_first_entry(&ed->td_list, struct td, + td_list); + if (td2 == td) + break; + takeback_td(ohci, td2); + } + takeback_td(ohci, td); td = td_next; } From 31fdb19eb968995b3c5f4337918bd51442f992ec Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 17 Oct 2012 13:44:06 -0700 Subject: [PATCH 1720/2357] xhci: Extend Fresco Logic MSI quirk. commit bba18e33f25072ebf70fd8f7f0cdbf8cdb59a746 upstream. Ali reports that plugging a device into the Fresco Logic xHCI host with PCI device ID 1400 produces an IRQ error: do_IRQ: 3.176 No irq handler for vector (irq -1) Other early Fresco Logic host revisions don't support MSI, even though their PCI config space claims they do. Extend the quirk to disabling MSI to this chipset revision. Also enable the short transfer quirk, since it's likely this revision also has that quirk, and it should be harmless to enable. 04:00.0 0c03: 1b73:1400 (rev 01) (prog-if 30 [XHCI]) Subsystem: 1d5c:1000 Physical Slot: 3 Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+ Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- SERR- Reported-by: A Sh Tested-by: A Sh Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 4211017b889..84e82dc7b79 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -29,6 +29,7 @@ /* Device for a quirk */ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 +#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400 #define PCI_VENDOR_ID_ETRON 0x1b6f #define PCI_DEVICE_ID_ASROCK_P67 0x7023 @@ -58,8 +59,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) /* Look for vendor-specific quirks */ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && - pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK) { - if (pdev->revision == 0x0) { + (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK || + pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1400)) { + if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && + pdev->revision == 0x0) { xhci->quirks |= XHCI_RESET_EP_QUIRK; xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" " endpoint cmd after reset endpoint\n"); From 455d8953951baf0d38673b010100241e508b765c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 9 Jun 2012 19:10:27 +0300 Subject: [PATCH 1721/2357] ftrace: Clear bits properly in reset_iter_read() commit 70f77b3f7ec010ff9624c1f2e39a81babc9e2429 upstream. There is a typo here where '&' is used instead of '|' and it turns the statement into a noop. The original code is equivalent to: iter->flags &= ~((1 << 2) & (1 << 4)); Link: http://lkml.kernel.org/r/20120609161027.GD6488@elgon.mountain Signed-off-by: Dan Carpenter Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/ftrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 0fa92f677c9..100b7fd1a64 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2368,7 +2368,7 @@ static void reset_iter_read(struct ftrace_iterator *iter) { iter->pos = 0; iter->func_pos = 0; - iter->flags &= ~(FTRACE_ITER_PRINTALL & FTRACE_ITER_HASH); + iter->flags &= ~(FTRACE_ITER_PRINTALL | FTRACE_ITER_HASH); } static void *t_start(struct seq_file *m, loff_t *pos) From 1229a83d1ea3d11b4433f7080825d05044af45a9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 8 Nov 2012 12:47:41 -0600 Subject: [PATCH 1722/2357] cdc-acm: implement TIOCSSERIAL to avoid blocking close(2) commit ba2d8ce9db0a61505362bb17b8899df3d3326146 upstream. Some devices (ex Nokia C7) simply don't respond at all when data is sent to some of their USB interfaces. The data gets stuck in the TTYs queue and sits there until close(2), which them blocks because closing_wait defaults to 30 seconds (even though the fd is O_NONBLOCK). This is rarely desired. Implement the standard mechanism to adjust closing_wait and let applications handle it how they want to. See also 02303f73373aa1da19dbec510ec5a4e2576f9610 for usb_wwan.c. Signed-off-by: Dan Williams Acked-by: Oliver Neukum Tested-by: Aleksander Morgado Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index c5f7eae429e..b4e87cfa73a 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -788,6 +788,10 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) tmp.flags = ASYNC_LOW_LATENCY; tmp.xmit_fifo_size = acm->writesize; tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); + tmp.close_delay = acm->port.close_delay / 10; + tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : + acm->port.closing_wait / 10; if (copy_to_user(info, &tmp, sizeof(tmp))) return -EFAULT; @@ -795,6 +799,37 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) return 0; } +static int set_serial_info(struct acm *acm, + struct serial_struct __user *newinfo) +{ + struct serial_struct new_serial; + unsigned int closing_wait, close_delay; + int retval = 0; + + if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) + return -EFAULT; + + close_delay = new_serial.close_delay * 10; + closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + + mutex_lock(&acm->port.mutex); + + if (!capable(CAP_SYS_ADMIN)) { + if ((close_delay != acm->port.close_delay) || + (closing_wait != acm->port.closing_wait)) + retval = -EPERM; + else + retval = -EOPNOTSUPP; + } else { + acm->port.close_delay = close_delay; + acm->port.closing_wait = closing_wait; + } + + mutex_unlock(&acm->port.mutex); + return retval; +} + static int acm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -805,6 +840,9 @@ static int acm_tty_ioctl(struct tty_struct *tty, case TIOCGSERIAL: /* gets serial port data */ rv = get_serial_info(acm, (struct serial_struct __user *) arg); break; + case TIOCSSERIAL: + rv = set_serial_info(acm, (struct serial_struct __user *) arg); + break; } return rv; From d5a79aa30b7e6cd68dfee6a76acbe6c7f7905f51 Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Thu, 8 Nov 2012 16:58:46 -0800 Subject: [PATCH 1723/2357] perf test: fix a build error on builtin-test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 12f8f74b2a4d26c4facfa7ef99487cf0930f6ef7 upstream. Recently I build perf and get a build error on builtin-test.c. The error is as following: $ make CC perf.o CC builtin-test.o cc1: warnings being treated as errors builtin-test.c: In function ‘sched__get_first_possible_cpu’: builtin-test.c:977: warning: implicit declaration of function ‘CPU_ALLOC’ builtin-test.c:977: warning: nested extern declaration of ‘CPU_ALLOC’ builtin-test.c:977: warning: assignment makes pointer from integer without a cast builtin-test.c:978: warning: implicit declaration of function ‘CPU_ALLOC_SIZE’ builtin-test.c:978: warning: nested extern declaration of ‘CPU_ALLOC_SIZE’ builtin-test.c:979: warning: implicit declaration of function ‘CPU_ZERO_S’ builtin-test.c:979: warning: nested extern declaration of ‘CPU_ZERO_S’ builtin-test.c:982: warning: implicit declaration of function ‘CPU_FREE’ builtin-test.c:982: warning: nested extern declaration of ‘CPU_FREE’ builtin-test.c:992: warning: implicit declaration of function ‘CPU_ISSET_S’ builtin-test.c:992: warning: nested extern declaration of ‘CPU_ISSET_S’ builtin-test.c:998: warning: implicit declaration of function ‘CPU_CLR_S’ builtin-test.c:998: warning: nested extern declaration of ‘CPU_CLR_S’ make: *** [builtin-test.o] Error 1 This problem is introduced in 3e7c439a. CPU_ALLOC and related macros are missing in sched__get_first_possible_cpu function. In 54489c18, commiter mentioned that CPU_ALLOC has been removed. So CPU_ALLOC calls in this function are removed to let perf to be built. Signed-off-by: Vinson Lee Signed-off-by: Zheng Liu Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Vinson Lee Cc: Zheng Liu Link: http://lkml.kernel.org/r/1352422726-31114-1-git-send-email-vlee@twitter.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-test.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 223ffdcc0fd..3487b4b4211 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -1154,19 +1154,13 @@ static int test__parse_events(void) return ret; } -static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp, - size_t *sizep) +static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp) { - cpu_set_t *mask; - size_t size; int i, cpu = -1, nrcpus = 1024; realloc: - mask = CPU_ALLOC(nrcpus); - size = CPU_ALLOC_SIZE(nrcpus); - CPU_ZERO_S(size, mask); + CPU_ZERO(maskp); - if (sched_getaffinity(pid, size, mask) == -1) { - CPU_FREE(mask); + if (sched_getaffinity(pid, sizeof(*maskp), maskp) == -1) { if (errno == EINVAL && nrcpus < (1024 << 8)) { nrcpus = nrcpus << 2; goto realloc; @@ -1176,19 +1170,14 @@ static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp, } for (i = 0; i < nrcpus; i++) { - if (CPU_ISSET_S(i, size, mask)) { - if (cpu == -1) { + if (CPU_ISSET(i, maskp)) { + if (cpu == -1) cpu = i; - *maskp = mask; - *sizep = size; - } else - CPU_CLR_S(i, size, mask); + else + CPU_CLR(i, maskp); } } - if (cpu == -1) - CPU_FREE(mask); - return cpu; } @@ -1199,8 +1188,8 @@ static int test__PERF_RECORD(void) .freq = 10, .mmap_pages = 256, }; - cpu_set_t *cpu_mask = NULL; - size_t cpu_mask_size = 0; + cpu_set_t cpu_mask; + size_t cpu_mask_size = sizeof(cpu_mask); struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); struct perf_evsel *evsel; struct perf_sample sample; @@ -1265,8 +1254,7 @@ static int test__PERF_RECORD(void) evsel->attr.sample_type |= PERF_SAMPLE_TIME; perf_evlist__config_attrs(evlist, &opts); - err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask, - &cpu_mask_size); + err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); if (err < 0) { pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); goto out_delete_evlist; @@ -1277,9 +1265,9 @@ static int test__PERF_RECORD(void) /* * So that we can check perf_sample.cpu on all the samples. */ - if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) { + if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { pr_debug("sched_setaffinity: %s\n", strerror(errno)); - goto out_free_cpu_mask; + goto out_delete_evlist; } /* @@ -1472,8 +1460,6 @@ static int test__PERF_RECORD(void) } out_err: perf_evlist__munmap(evlist); -out_free_cpu_mask: - CPU_FREE(cpu_mask); out_delete_evlist: perf_evlist__delete(evlist); out: From 29251de53e1712158c29b3626a008d8b93a6e024 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 18 Oct 2012 04:55:36 -0700 Subject: [PATCH 1724/2357] rcu: Fix batch-limit size problem commit 878d7439d0f45a95869e417576774673d1fa243f upstream. Commit 29c00b4a1d9e27 (rcu: Add event-tracing for RCU callback invocation) added a regression in rcu_do_batch() Under stress, RCU is supposed to allow to process all items in queue, instead of a batch of 10 items (blimit), but an integer overflow makes the effective limit being 1. So, unless there is frequent idle periods (during which RCU ignores batch limits), RCU can be forced into a state where it cannot keep up with the callback-generation rate, eventually resulting in OOM. This commit therefore converts a few variables in rcu_do_batch() from int to long to fix this problem, along with the module parameters controlling the batch limits. Signed-off-by: Eric Dumazet Signed-off-by: Paul E. McKenney Signed-off-by: Greg Kroah-Hartman --- kernel/rcutree.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 4eec66e0350..62c5e9cf6fc 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -202,13 +202,13 @@ DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { .dynticks = ATOMIC_INIT(1), }; -static int blimit = 10; /* Maximum callbacks per rcu_do_batch. */ -static int qhimark = 10000; /* If this many pending, ignore blimit. */ -static int qlowmark = 100; /* Once only this many pending, use blimit. */ +static long blimit = 10; /* Maximum callbacks per rcu_do_batch. */ +static long qhimark = 10000; /* If this many pending, ignore blimit. */ +static long qlowmark = 100; /* Once only this many pending, use blimit. */ -module_param(blimit, int, 0); -module_param(qhimark, int, 0); -module_param(qlowmark, int, 0); +module_param(blimit, long, 0); +module_param(qhimark, long, 0); +module_param(qlowmark, long, 0); int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */ int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT; @@ -1476,7 +1476,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) { unsigned long flags; struct rcu_head *next, *list, **tail; - int bl, count, count_lazy; + long bl, count, count_lazy; /* If no callbacks are ready, just return.*/ if (!cpu_has_callbacks_ready_to_invoke(rdp)) { From e56f8b7aeb0b8135ee29b0612b192a784450739e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 17 Dec 2012 10:38:05 -0800 Subject: [PATCH 1725/2357] Linux 3.4.24 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bf1df55f4f9..a3e12e687c6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 23 +SUBLEVEL = 24 EXTRAVERSION = NAME = Saber-toothed Squirrel From 1789172140b7b61955b87b3070fb30da1a701d7c Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Wed, 21 Nov 2012 04:35:03 +0000 Subject: [PATCH 1726/2357] bonding: Bonding driver does not consider the gso_max_size/gso_max_segs setting of slave devices. [ Upstream commit 0e376bd0b791ac6ac6bdb051492df0769c840848 ] Patch sets the lowest gso_max_size and gso_max_segs values of the slave devices during enslave and detach. Signed-off-by: Sarveshwar Bandi Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 318a62a4db5..6df52c9ba49 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1383,6 +1383,8 @@ static void bond_compute_features(struct bonding *bond) struct net_device *bond_dev = bond->dev; netdev_features_t vlan_features = BOND_VLAN_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; + unsigned int gso_max_size = GSO_MAX_SIZE; + u16 gso_max_segs = GSO_MAX_SEGS; int i; read_lock(&bond->lock); @@ -1396,11 +1398,16 @@ static void bond_compute_features(struct bonding *bond) if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; + + gso_max_size = min(gso_max_size, slave->dev->gso_max_size); + gso_max_segs = min(gso_max_segs, slave->dev->gso_max_segs); } done: bond_dev->vlan_features = vlan_features; bond_dev->hard_header_len = max_hard_header_len; + bond_dev->gso_max_segs = gso_max_segs; + netif_set_gso_max_size(bond_dev, gso_max_size); read_unlock(&bond->lock); From 1097b6a83df844d5145a1f9821300028857d8ca9 Mon Sep 17 00:00:00 2001 From: "nikolay@redhat.com" Date: Thu, 29 Nov 2012 01:37:59 +0000 Subject: [PATCH 1727/2357] bonding: fix race condition in bonding_store_slaves_active [ Upstream commit e196c0e579902f42cf72414461fb034e5a1ffbf7 ] Race between bonding_store_slaves_active() and slave manipulation functions. The bond_for_each_slave use in bonding_store_slaves_active() is not protected by any synchronization mechanism. NULL pointer dereference is easy to reach. Fixed by acquiring the bond->lock for the slave walk. v2: Make description text < 75 columns Signed-off-by: Nikolay Aleksandrov Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_sysfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index aef42f04532..6734737c953 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1578,6 +1578,7 @@ static ssize_t bonding_store_slaves_active(struct device *d, goto out; } + read_lock(&bond->lock); bond_for_each_slave(bond, slave, i) { if (!bond_is_active_slave(slave)) { if (new_value) @@ -1586,6 +1587,7 @@ static ssize_t bonding_store_slaves_active(struct device *d, slave->inactive = 1; } } + read_unlock(&bond->lock); out: return ret; } From d0804c62db373041db42aa976edf2b9e5f5ae9ed Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Tue, 27 Nov 2012 04:01:46 +0000 Subject: [PATCH 1728/2357] sctp: fix memory leak in sctp_datamsg_from_user() when copy from user space fails [ Upstream commit be364c8c0f17a3dd42707b5a090b318028538eb9 ] Trinity (the syscall fuzzer) discovered a memory leak in SCTP, reproducible e.g. with the sendto() syscall by passing invalid user space pointer in the second argument: #include #include #include int main(void) { int fd; struct sockaddr_in sa; fd = socket(AF_INET, SOCK_STREAM, 132 /*IPPROTO_SCTP*/); if (fd < 0) return 1; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr("127.0.0.1"); sa.sin_port = htons(11111); sendto(fd, NULL, 1, 0, (struct sockaddr *)&sa, sizeof(sa)); return 0; } As far as I can tell, the leak has been around since ~2003. Signed-off-by: Tommi Rantala Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/chunk.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 6c8556459a7..9534bf9a14e 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -284,7 +284,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, goto errout; err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); if (err < 0) - goto errout; + goto errout_chunk_free; offset += len; @@ -324,7 +324,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr - (__u8 *)chunk->skb->data); if (err < 0) - goto errout; + goto errout_chunk_free; sctp_datamsg_assign(msg, chunk); list_add_tail(&chunk->frag_list, &msg->chunks); @@ -332,6 +332,9 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, return msg; +errout_chunk_free: + sctp_chunk_free(chunk); + errout: list_for_each_safe(pos, temp, &msg->chunks) { list_del_init(pos); From dff343c7f4dfa5650d5d3a78f58f080ec9f14a25 Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Thu, 22 Nov 2012 03:23:16 +0000 Subject: [PATCH 1729/2357] sctp: fix -ENOMEM result with invalid user space pointer in sendto() syscall [ Upstream commit 6e51fe7572590d8d86e93b547fab6693d305fd0d ] Consider the following program, that sets the second argument to the sendto() syscall incorrectly: #include #include #include int main(void) { int fd; struct sockaddr_in sa; fd = socket(AF_INET, SOCK_STREAM, 132 /*IPPROTO_SCTP*/); if (fd < 0) return 1; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr("127.0.0.1"); sa.sin_port = htons(11111); sendto(fd, NULL, 1, 0, (struct sockaddr *)&sa, sizeof(sa)); return 0; } We get -ENOMEM: $ strace -e sendto ./demo sendto(3, NULL, 1, 0, {sa_family=AF_INET, sin_port=htons(11111), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ENOMEM (Cannot allocate memory) Propagate the error code from sctp_user_addto_chunk(), so that we will tell user space what actually went wrong: $ strace -e sendto ./demo sendto(3, NULL, 1, 0, {sa_family=AF_INET, sin_port=htons(11111), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EFAULT (Bad address) Noticed while running Trinity (the syscall fuzzer). Signed-off-by: Tommi Rantala Acked-by: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/chunk.c | 13 +++++++++---- net/sctp/socket.c | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 9534bf9a14e..0018b653cb1 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -183,7 +183,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, msg = sctp_datamsg_new(GFP_KERNEL); if (!msg) - return NULL; + return ERR_PTR(-ENOMEM); /* Note: Calculate this outside of the loop, so that all fragments * have the same expiration. @@ -280,8 +280,11 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); - if (!chunk) + if (!chunk) { + err = -ENOMEM; goto errout; + } + err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); if (err < 0) goto errout_chunk_free; @@ -315,8 +318,10 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); - if (!chunk) + if (!chunk) { + err = -ENOMEM; goto errout; + } err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); @@ -342,7 +347,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, sctp_chunk_free(chunk); } sctp_datamsg_put(msg); - return NULL; + return ERR_PTR(err); } /* Check whether this message has expired. */ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index dba20d6e324..74053554a85 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1908,8 +1908,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, /* Break the message into multiple chunks of maximum size. */ datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len); - if (!datamsg) { - err = -ENOMEM; + if (IS_ERR(datamsg)) { + err = PTR_ERR(datamsg); goto out_free; } From aa335048531c58da34fed27b69a7ba0faf9a1eee Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 20 Nov 2012 06:31:57 +0000 Subject: [PATCH 1730/2357] ne2000: add the right platform device [ Upstream commit da9da01d9199b5bb15289d0859053c9aa3a34ac0 ] Without this udev doesn't have a way to key the ne device to the platform device. Signed-off-by: Alan Cox Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/8390/ne.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index d04911d33b6..47618e50535 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -813,6 +813,7 @@ static int __init ne_drv_probe(struct platform_device *pdev) dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; } + SET_NETDEV_DEV(dev, &pdev->dev); err = do_ne_probe(dev); if (err) { free_netdev(dev); From 6b015f351d9c8a1800f4e234fbfbcc0198bf0b5f Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 20 Nov 2012 09:59:11 +0000 Subject: [PATCH 1731/2357] irda: sir_dev: Fix copy/paste typo [ Upstream commit 2355a62bcbdcc4b567425bab036bfab6ade87eed ] Signed-off-by: Alexander Shiyan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/irda/sir_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 5039f08f5a5..43e9ab4f4d7 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -222,7 +222,7 @@ static void sirdev_config_fsm(struct work_struct *work) break; case SIRDEV_STATE_DONGLE_SPEED: - if (dev->dongle_drv->reset) { + if (dev->dongle_drv->set_speed) { ret = dev->dongle_drv->set_speed(dev, fsm->param); if (ret < 0) { fsm->result = ret; From eab34a33cfdda79711f6c66a9f9d7a558238eed8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 9 Dec 2012 23:41:06 +0000 Subject: [PATCH 1732/2357] ipv4: ip_check_defrag must not modify skb before unsharing [ Upstream commit 1bf3751ec90cc3174e01f0d701e8449ce163d113 ] ip_check_defrag() might be called from af_packet within the RX path where shared SKBs are used, so it must not modify the input SKB before it has unshared it for defragmentation. Use skb_copy_bits() to get the IP header and only pull in everything later. The same is true for the other caller in macvlan as it is called from dev->rx_handler which can also get a shared SKB. Reported-by: Eric Leblond Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_fragment.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 3727e234c88..b7bf6e30adb 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -685,28 +685,27 @@ EXPORT_SYMBOL(ip_defrag); struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) { - const struct iphdr *iph; + struct iphdr iph; u32 len; if (skb->protocol != htons(ETH_P_IP)) return skb; - if (!pskb_may_pull(skb, sizeof(struct iphdr))) + if (!skb_copy_bits(skb, 0, &iph, sizeof(iph))) return skb; - iph = ip_hdr(skb); - if (iph->ihl < 5 || iph->version != 4) + if (iph.ihl < 5 || iph.version != 4) return skb; - if (!pskb_may_pull(skb, iph->ihl*4)) - return skb; - iph = ip_hdr(skb); - len = ntohs(iph->tot_len); - if (skb->len < len || len < (iph->ihl * 4)) + + len = ntohs(iph.tot_len); + if (skb->len < len || len < (iph.ihl * 4)) return skb; - if (ip_is_fragment(ip_hdr(skb))) { + if (ip_is_fragment(&iph)) { skb = skb_share_check(skb, GFP_ATOMIC); if (skb) { + if (!pskb_may_pull(skb, iph.ihl*4)) + return skb; if (pskb_trim_rcsum(skb, len)) return skb; memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); From 1755fd2e38a0541dab207df5d42d92b567695497 Mon Sep 17 00:00:00 2001 From: Jay Purohit Date: Sun, 14 Oct 2012 07:07:21 +0000 Subject: [PATCH 1733/2357] usb/ipheth: Add iPhone 5 support [ Upstream commit af1b85e49089f945deb46258b0fc4bc9910afb22 ] I noticed that the iPhone ethernet driver did not support iPhone 5. I quickly added support to it in my kernel, here's a patch. Signed-off-by: Jay Purohit Acked-by: Valdis Kletnieks Signed-off-by: Jan Ceuleers Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/ipheth.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 5cba41517f7..32e47918e59 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -62,6 +62,7 @@ #define USB_PRODUCT_IPAD 0x129a #define USB_PRODUCT_IPHONE_4_VZW 0x129c #define USB_PRODUCT_IPHONE_4S 0x12a0 +#define USB_PRODUCT_IPHONE_5 0x12a8 #define IPHETH_USBINTF_CLASS 255 #define IPHETH_USBINTF_SUBCLASS 253 @@ -113,6 +114,10 @@ static struct usb_device_id ipheth_table[] = { USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4S, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_5, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, { } }; MODULE_DEVICE_TABLE(usb, ipheth_table); From 457a04b96314023464f8249975b1efb4eef1c925 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Sat, 8 Dec 2012 19:43:21 +0000 Subject: [PATCH 1734/2357] inet_diag: fix oops for IPv4 AF_INET6 TCP SYN-RECV state [ Upstream commit 1c95df85ca49640576de2f0a850925957b547b84 ] Fix inet_diag to be aware of the fact that AF_INET6 TCP connections instantiated for IPv4 traffic and in the SYN-RECV state were actually created with inet_reqsk_alloc(), instead of inet6_reqsk_alloc(). This means that for such connections inet6_rsk(req) returns a pointer to a random spot in memory up to roughly 64KB beyond the end of the request_sock. With this bug, for a server using AF_INET6 TCP sockets and serving IPv4 traffic, an inet_diag user like `ss state SYN-RECV` would lead to inet_diag_fill_req() causing an oops or the export to user space of 16 bytes of kernel memory as a garbage IPv6 address, depending on where the garbage inet6_rsk(req) pointed. Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/inet_diag.c | 53 ++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index dda5383a6f0..06fe2fef268 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -44,6 +44,10 @@ struct inet_diag_entry { u16 dport; u16 family; u16 userlocks; +#if IS_ENABLED(CONFIG_IPV6) + struct in6_addr saddr_storage; /* for IPv4-mapped-IPv6 addresses */ + struct in6_addr daddr_storage; /* for IPv4-mapped-IPv6 addresses */ +#endif }; #define INET_DIAG_PUT(skb, attrtype, attrlen) \ @@ -586,6 +590,36 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw, cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); } +/* Get the IPv4, IPv6, or IPv4-mapped-IPv6 local and remote addresses + * from a request_sock. For IPv4-mapped-IPv6 we must map IPv4 to IPv6. + */ +static inline void inet_diag_req_addrs(const struct sock *sk, + const struct request_sock *req, + struct inet_diag_entry *entry) +{ + struct inet_request_sock *ireq = inet_rsk(req); + +#if IS_ENABLED(CONFIG_IPV6) + if (sk->sk_family == AF_INET6) { + if (req->rsk_ops->family == AF_INET6) { + entry->saddr = inet6_rsk(req)->loc_addr.s6_addr32; + entry->daddr = inet6_rsk(req)->rmt_addr.s6_addr32; + } else if (req->rsk_ops->family == AF_INET) { + ipv6_addr_set_v4mapped(ireq->loc_addr, + &entry->saddr_storage); + ipv6_addr_set_v4mapped(ireq->rmt_addr, + &entry->daddr_storage); + entry->saddr = entry->saddr_storage.s6_addr32; + entry->daddr = entry->daddr_storage.s6_addr32; + } + } else +#endif + { + entry->saddr = &ireq->loc_addr; + entry->daddr = &ireq->rmt_addr; + } +} + static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk, struct request_sock *req, u32 pid, u32 seq, const struct nlmsghdr *unlh) @@ -624,8 +658,10 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk, r->idiag_inode = 0; #if IS_ENABLED(CONFIG_IPV6) if (r->idiag_family == AF_INET6) { - *(struct in6_addr *)r->id.idiag_src = inet6_rsk(req)->loc_addr; - *(struct in6_addr *)r->id.idiag_dst = inet6_rsk(req)->rmt_addr; + struct inet_diag_entry entry; + inet_diag_req_addrs(sk, req, &entry); + memcpy(r->id.idiag_src, entry.saddr, sizeof(struct in6_addr)); + memcpy(r->id.idiag_dst, entry.daddr, sizeof(struct in6_addr)); } #endif nlh->nlmsg_len = skb_tail_pointer(skb) - b; @@ -683,18 +719,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk, continue; if (bc) { - entry.saddr = -#if IS_ENABLED(CONFIG_IPV6) - (entry.family == AF_INET6) ? - inet6_rsk(req)->loc_addr.s6_addr32 : -#endif - &ireq->loc_addr; - entry.daddr = -#if IS_ENABLED(CONFIG_IPV6) - (entry.family == AF_INET6) ? - inet6_rsk(req)->rmt_addr.s6_addr32 : -#endif - &ireq->rmt_addr; + inet_diag_req_addrs(sk, req, &entry); entry.dport = ntohs(ireq->rmt_port); if (!inet_diag_bc_run(bc, &entry)) From 879fc99ecd078f64849b95c47cf7e28705ac8884 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Sat, 8 Dec 2012 19:43:22 +0000 Subject: [PATCH 1735/2357] inet_diag: validate byte code to prevent oops in inet_diag_bc_run() [ Upstream commit 405c005949e47b6e91359159c24753519ded0c67 ] Add logic to validate INET_DIAG_BC_S_COND and INET_DIAG_BC_D_COND operations. Previously we did not validate the inet_diag_hostcond, address family, address length, and prefix length. So a malicious user could make the kernel read beyond the end of the bytecode array by claiming to have a whole inet_diag_hostcond when the bytecode was not long enough to contain a whole inet_diag_hostcond of the given address family. Or they could make the kernel read up to about 27 bytes beyond the end of a connection address by passing a prefix length that exceeded the length of addresses of the given family. Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/inet_diag.c | 48 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 06fe2fef268..35b2dfc092a 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -504,6 +504,44 @@ static int valid_cc(const void *bc, int len, int cc) return 0; } +/* Validate an inet_diag_hostcond. */ +static bool valid_hostcond(const struct inet_diag_bc_op *op, int len, + int *min_len) +{ + int addr_len; + struct inet_diag_hostcond *cond; + + /* Check hostcond space. */ + *min_len += sizeof(struct inet_diag_hostcond); + if (len < *min_len) + return false; + cond = (struct inet_diag_hostcond *)(op + 1); + + /* Check address family and address length. */ + switch (cond->family) { + case AF_UNSPEC: + addr_len = 0; + break; + case AF_INET: + addr_len = sizeof(struct in_addr); + break; + case AF_INET6: + addr_len = sizeof(struct in6_addr); + break; + default: + return false; + } + *min_len += addr_len; + if (len < *min_len) + return false; + + /* Check prefix length (in bits) vs address length (in bytes). */ + if (cond->prefix_len > 8 * addr_len) + return false; + + return true; +} + static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) { const void *bc = bytecode; @@ -511,18 +549,22 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) while (len > 0) { const struct inet_diag_bc_op *op = bc; + int min_len = sizeof(struct inet_diag_bc_op); //printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len); switch (op->code) { - case INET_DIAG_BC_AUTO: case INET_DIAG_BC_S_COND: case INET_DIAG_BC_D_COND: + if (!valid_hostcond(bc, len, &min_len)) + return -EINVAL; + /* fall through */ + case INET_DIAG_BC_AUTO: case INET_DIAG_BC_S_GE: case INET_DIAG_BC_S_LE: case INET_DIAG_BC_D_GE: case INET_DIAG_BC_D_LE: case INET_DIAG_BC_JMP: - if (op->no < 4 || op->no > len + 4 || op->no & 3) + if (op->no < min_len || op->no > len + 4 || op->no & 3) return -EINVAL; if (op->no < len && !valid_cc(bytecode, bytecode_len, len - op->no)) @@ -533,7 +575,7 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) default: return -EINVAL; } - if (op->yes < 4 || op->yes > len + 4 || op->yes & 3) + if (op->yes < min_len || op->yes > len + 4 || op->yes & 3) return -EINVAL; bc += op->yes; len -= op->yes; From b2aa2e70f9d6d5c4aadccdda5956991e8d1869e8 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Sat, 8 Dec 2012 19:43:23 +0000 Subject: [PATCH 1736/2357] inet_diag: avoid unsafe and nonsensical prefix matches in inet_diag_bc_run() [ Upstream commit f67caec9068cee426ec23cf9005a1dee2ecad187 ] Add logic to check the address family of the user-supplied conditional and the address family of the connection entry. We now do not do prefix matching of addresses from different address families (AF_INET vs AF_INET6), except for the previously existing support for having an IPv4 prefix match an IPv4-mapped IPv6 address (which this commit maintains as-is). This change is needed for two reasons: (1) The addresses are different lengths, so comparing a 128-bit IPv6 prefix match condition to a 32-bit IPv4 connection address can cause us to unwittingly walk off the end of the IPv4 address and read garbage or oops. (2) The IPv4 and IPv6 address spaces are semantically distinct, so a simple bit-wise comparison of the prefixes is not meaningful, and would lead to bogus results (except for the IPv4-mapped IPv6 case, which this commit maintains). Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/inet_diag.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 35b2dfc092a..8b20ca64208 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -423,25 +423,31 @@ static int inet_diag_bc_run(const struct nlattr *_bc, break; } - if (cond->prefix_len == 0) - break; - if (op->code == INET_DIAG_BC_S_COND) addr = entry->saddr; else addr = entry->daddr; + if (cond->family != AF_UNSPEC && + cond->family != entry->family) { + if (entry->family == AF_INET6 && + cond->family == AF_INET) { + if (addr[0] == 0 && addr[1] == 0 && + addr[2] == htonl(0xffff) && + bitstring_match(addr + 3, + cond->addr, + cond->prefix_len)) + break; + } + yes = 0; + break; + } + + if (cond->prefix_len == 0) + break; if (bitstring_match(addr, cond->addr, cond->prefix_len)) break; - if (entry->family == AF_INET6 && - cond->family == AF_INET) { - if (addr[0] == 0 && addr[1] == 0 && - addr[2] == htonl(0xffff) && - bitstring_match(addr + 3, cond->addr, - cond->prefix_len)) - break; - } yes = 0; break; } From f762136f85f60e7d9e8a0422f078bb187fbfc9f0 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Sun, 9 Dec 2012 11:09:54 +0000 Subject: [PATCH 1737/2357] inet_diag: validate port comparison byte code to prevent unsafe reads [ Upstream commit 5e1f54201cb481f40a04bc47e1bc8c093a189e23 ] Add logic to verify that a port comparison byte code operation actually has the second inet_diag_bc_op from which we read the port for such operations. Previously the code blindly referenced op[1] without first checking whether a second inet_diag_bc_op struct could fit there. So a malicious user could make the kernel read 4 bytes beyond the end of the bytecode array by claiming to have a whole port comparison byte code (2 inet_diag_bc_op structs) when in fact the bytecode was not long enough to hold both. Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/inet_diag.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 8b20ca64208..d7b862ad4be 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -548,6 +548,17 @@ static bool valid_hostcond(const struct inet_diag_bc_op *op, int len, return true; } +/* Validate a port comparison operator. */ +static inline bool valid_port_comparison(const struct inet_diag_bc_op *op, + int len, int *min_len) +{ + /* Port comparisons put the port in a follow-on inet_diag_bc_op. */ + *min_len += sizeof(struct inet_diag_bc_op); + if (len < *min_len) + return false; + return true; +} + static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) { const void *bc = bytecode; @@ -563,24 +574,30 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) case INET_DIAG_BC_D_COND: if (!valid_hostcond(bc, len, &min_len)) return -EINVAL; - /* fall through */ - case INET_DIAG_BC_AUTO: + break; case INET_DIAG_BC_S_GE: case INET_DIAG_BC_S_LE: case INET_DIAG_BC_D_GE: case INET_DIAG_BC_D_LE: - case INET_DIAG_BC_JMP: - if (op->no < min_len || op->no > len + 4 || op->no & 3) - return -EINVAL; - if (op->no < len && - !valid_cc(bytecode, bytecode_len, len - op->no)) + if (!valid_port_comparison(bc, len, &min_len)) return -EINVAL; break; + case INET_DIAG_BC_AUTO: + case INET_DIAG_BC_JMP: case INET_DIAG_BC_NOP: break; default: return -EINVAL; } + + if (op->code != INET_DIAG_BC_NOP) { + if (op->no < min_len || op->no > len + 4 || op->no & 3) + return -EINVAL; + if (op->no < len && + !valid_cc(bytecode, bytecode_len, len - op->no)) + return -EINVAL; + } + if (op->yes < min_len || op->yes > len + 4 || op->yes & 3) return -EINVAL; bc += op->yes; From 0752c77c0f04ac2649d5175fbc25dd3c5d414870 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 6 Dec 2012 21:55:16 -0600 Subject: [PATCH 1738/2357] b43legacy: Fix firmware loading when driver is built into the kernel commit 576d28a7c73013717311cfcb514dbcae27c82eeb upstream. Recent versions of udev cause synchronous firmware loading from the probe routine to fail because the request to user space times out. The original fix for b43legacy (commit a3ea2c7) moved the firmware load from the probe routine to a work queue, but it still used synchronous firmware loading. This method is OK when b43legacy is built as a module; however, it fails when the driver is compiled into the kernel. This version changes the code to load the initial firmware file using request_firmware_nowait(). A completion event is used to hold the work queue until that file is available. The remaining firmware files are read synchronously. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/b43legacy/b43legacy.h | 5 +++ drivers/net/wireless/b43legacy/main.c | 37 ++++++++++++++++++---- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index a29da674e69..482476fdb1f 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -13,6 +13,7 @@ #include #include +#include #include @@ -733,6 +734,10 @@ struct b43legacy_wldev { /* Firmware data */ struct b43legacy_firmware fw; + const struct firmware *fwp; /* needed to pass fw pointer */ + + /* completion struct for firmware loading */ + struct completion fw_load_complete; /* Devicelist in struct b43legacy_wl (all 802.11 cores) */ struct list_head list; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 0f30c07e919..53696efbe15 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1511,9 +1511,17 @@ static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl) "and download the correct firmware (version 3).\n"); } +static void b43legacy_fw_cb(const struct firmware *firmware, void *context) +{ + struct b43legacy_wldev *dev = context; + + dev->fwp = firmware; + complete(&dev->fw_load_complete); +} + static int do_request_fw(struct b43legacy_wldev *dev, const char *name, - const struct firmware **fw) + const struct firmware **fw, bool async) { char path[sizeof(modparam_fwpostfix) + 32]; struct b43legacy_fw_header *hdr; @@ -1526,7 +1534,24 @@ static int do_request_fw(struct b43legacy_wldev *dev, snprintf(path, ARRAY_SIZE(path), "b43legacy%s/%s.fw", modparam_fwpostfix, name); - err = request_firmware(fw, path, dev->dev->dev); + b43legacyinfo(dev->wl, "Loading firmware %s\n", path); + if (async) { + init_completion(&dev->fw_load_complete); + err = request_firmware_nowait(THIS_MODULE, 1, path, + dev->dev->dev, GFP_KERNEL, + dev, b43legacy_fw_cb); + if (err) { + b43legacyerr(dev->wl, "Unable to load firmware\n"); + return err; + } + /* stall here until fw ready */ + wait_for_completion(&dev->fw_load_complete); + if (!dev->fwp) + err = -EINVAL; + *fw = dev->fwp; + } else { + err = request_firmware(fw, path, dev->dev->dev); + } if (err) { b43legacyerr(dev->wl, "Firmware file \"%s\" not found " "or load failed.\n", path); @@ -1578,7 +1603,7 @@ static void b43legacy_request_firmware(struct work_struct *work) filename = "ucode4"; else filename = "ucode5"; - err = do_request_fw(dev, filename, &fw->ucode); + err = do_request_fw(dev, filename, &fw->ucode, true); if (err) goto err_load; } @@ -1587,7 +1612,7 @@ static void b43legacy_request_firmware(struct work_struct *work) filename = "pcm4"; else filename = "pcm5"; - err = do_request_fw(dev, filename, &fw->pcm); + err = do_request_fw(dev, filename, &fw->pcm, false); if (err) goto err_load; } @@ -1605,7 +1630,7 @@ static void b43legacy_request_firmware(struct work_struct *work) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals); + err = do_request_fw(dev, filename, &fw->initvals, false); if (err) goto err_load; } @@ -1625,7 +1650,7 @@ static void b43legacy_request_firmware(struct work_struct *work) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals_band); + err = do_request_fw(dev, filename, &fw->initvals_band, false); if (err) goto err_load; } From 6afc22ba722253aafc389264edc7134e73700e60 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 10 Dec 2012 17:40:21 +0100 Subject: [PATCH 1739/2357] b43: fix tx path skb leaks commit 78f18df4b323d2ac14d6c82e2fc3c8dc4556bccc upstream. ieee80211_free_txskb() needs to be used instead of dev_kfree_skb_any for tx packets passed to the driver from mac80211 Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/b43/dma.c | 7 +++++-- drivers/net/wireless/b43/main.c | 12 ++++++++---- drivers/net/wireless/b43/pio.c | 4 ++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index b5f1b91002b..65f831faf2a 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -409,7 +409,10 @@ static inline struct b43_dmadesc_meta *meta) { if (meta->skb) { - dev_kfree_skb_any(meta->skb); + if (ring->tx) + ieee80211_free_txskb(ring->dev->wl->hw, meta->skb); + else + dev_kfree_skb_any(meta->skb); meta->skb = NULL; } } @@ -1454,7 +1457,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ - dev_kfree_skb_any(skb); + ieee80211_free_txskb(dev->wl->hw, skb); err = 0; goto out; } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d6ffd434f41..4e465c5b2df 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3393,7 +3393,7 @@ static void b43_tx_work(struct work_struct *work) break; } if (unlikely(err)) - dev_kfree_skb(skb); /* Drop it */ + ieee80211_free_txskb(wl->hw, skb); err = 0; } @@ -3414,7 +3414,7 @@ static void b43_op_tx(struct ieee80211_hw *hw, if (unlikely(skb->len < 2 + 2 + 6)) { /* Too short, this can't be a valid frame. */ - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); return; } B43_WARN_ON(skb_shinfo(skb)->nr_frags); @@ -4210,8 +4210,12 @@ static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev) /* Drain all TX queues. */ for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) { - while (skb_queue_len(&wl->tx_queue[queue_num])) - dev_kfree_skb(skb_dequeue(&wl->tx_queue[queue_num])); + while (skb_queue_len(&wl->tx_queue[queue_num])) { + struct sk_buff *skb; + + skb = skb_dequeue(&wl->tx_queue[queue_num]); + ieee80211_free_txskb(wl->hw, skb); + } } b43_mac_suspend(dev); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 3533ab86bd3..a73ff8c9deb 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -196,7 +196,7 @@ static void b43_pio_cancel_tx_packets(struct b43_pio_txqueue *q) for (i = 0; i < ARRAY_SIZE(q->packets); i++) { pack = &(q->packets[i]); if (pack->skb) { - dev_kfree_skb_any(pack->skb); + ieee80211_free_txskb(q->dev->wl->hw, pack->skb); pack->skb = NULL; } } @@ -552,7 +552,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ - dev_kfree_skb_any(skb); + ieee80211_free_txskb(dev->wl->hw, skb); err = 0; goto out; } From 745a4b9a8bedb82d56e23a2e14452ab71df9cf60 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 7 Dec 2012 23:11:14 +0100 Subject: [PATCH 1740/2357] pnpacpi: fix incorrect TEST_ALPHA() test commit cdc87c5a30f407ed1ce43d8a22261116873d5ef1 upstream. TEST_ALPHA() is broken and always returns 0. [akpm@linux-foundation.org: return false for '@' as well, per Bjorn] Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/pnp/pnpacpi/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index e3537888db7..291906e8e9a 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -58,7 +58,7 @@ static inline int __init is_exclusive_device(struct acpi_device *dev) if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \ return 0 #define TEST_ALPHA(c) \ - if (!('@' <= (c) || (c) <= 'Z')) \ + if (!('A' <= (c) && (c) <= 'Z')) \ return 0 static int __init ispnpidacpi(const char *id) { From 5a76bf41fe85c0ebdf4fe1fcdf729697b11a5338 Mon Sep 17 00:00:00 2001 From: Robin Holt Date: Thu, 20 Dec 2012 15:05:50 -0800 Subject: [PATCH 1741/2357] SGI-XP: handle non-fatal traps commit 891348ca0f66206f1dc0e30d63757e3df1ae2d15 upstream. We found a user code which was raising a divide-by-zero trap. That trap would lead to XPC connections between system-partitions being torn down due to the die_chain notifier callouts it received. This also revealed a different issue where multiple callers into xpc_die_deactivate() would all attempt to do the disconnect in parallel which would sometimes lock up but often overwhelm the console on very large machines as each would print at least one line of output at the end of the deactivate. I reviewed all the users of the die_chain notifier and changed the code to ignore the notifier callouts for reasons which will not actually lead to a system to continue on to call die(). [akpm@linux-foundation.org: fix ia64] Signed-off-by: Robin Holt Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-xp/xpc_main.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 8d082b46426..d971817182f 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -53,6 +53,10 @@ #include #include "xpc.h" +#ifdef CONFIG_X86_64 +#include +#endif + /* define two XPC debug device structures to be used with dev_dbg() et al */ struct device_driver xpc_dbg_name = { @@ -1079,6 +1083,9 @@ xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused) return NOTIFY_DONE; } +/* Used to only allow one cpu to complete disconnect */ +static unsigned int xpc_die_disconnecting; + /* * Notify other partitions to deactivate from us by first disengaging from all * references to our memory. @@ -1092,6 +1099,9 @@ xpc_die_deactivate(void) long keep_waiting; long wait_to_print; + if (cmpxchg(&xpc_die_disconnecting, 0, 1)) + return; + /* keep xpc_hb_checker thread from doing anything (just in case) */ xpc_exiting = 1; @@ -1159,7 +1169,7 @@ xpc_die_deactivate(void) * about the lack of a heartbeat. */ static int -xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) +xpc_system_die(struct notifier_block *nb, unsigned long event, void *_die_args) { #ifdef CONFIG_IA64 /* !!! temporary kludge */ switch (event) { @@ -1191,7 +1201,27 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) break; } #else - xpc_die_deactivate(); + struct die_args *die_args = _die_args; + + switch (event) { + case DIE_TRAP: + if (die_args->trapnr == X86_TRAP_DF) + xpc_die_deactivate(); + + if (((die_args->trapnr == X86_TRAP_MF) || + (die_args->trapnr == X86_TRAP_XF)) && + !user_mode_vm(die_args->regs)) + xpc_die_deactivate(); + + break; + case DIE_INT3: + case DIE_DEBUG: + break; + case DIE_OOPS: + case DIE_GPF: + default: + xpc_die_deactivate(); + } #endif return NOTIFY_DONE; From 7361a9019ff8d45dc835f987ccefbbeb4f560f09 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 20 Dec 2012 15:05:16 -0800 Subject: [PATCH 1742/2357] exec: do not leave bprm->interp on stack commit b66c5984017533316fd1951770302649baf1aa33 upstream. If a series of scripts are executed, each triggering module loading via unprintable bytes in the script header, kernel stack contents can leak into the command line. Normally execution of binfmt_script and binfmt_misc happens recursively. However, when modules are enabled, and unprintable bytes exist in the bprm->buf, execution will restart after attempting to load matching binfmt modules. Unfortunately, the logic in binfmt_script and binfmt_misc does not expect to get restarted. They leave bprm->interp pointing to their local stack. This means on restart bprm->interp is left pointing into unused stack memory which can then be copied into the userspace argv areas. After additional study, it seems that both recursion and restart remains the desirable way to handle exec with scripts, misc, and modules. As such, we need to protect the changes to interp. This changes the logic to require allocation for any changes to the bprm->interp. To avoid adding a new kmalloc to every exec, the default value is left as-is. Only when passing through binfmt_script or binfmt_misc does an allocation take place. For a proof of concept, see DoTest.sh from: http://www.halfdog.net/Security/2012/LinuxKernelBinfmtScriptStackDataDisclosure/ Signed-off-by: Kees Cook Cc: halfdog Cc: P J P Cc: Alexander Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/binfmt_misc.c | 5 ++++- fs/binfmt_script.c | 4 +++- fs/exec.c | 15 +++++++++++++++ include/linux/binfmts.h | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 613aa061823..e1724392d05 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -176,7 +176,10 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) goto _error; bprm->argc ++; - bprm->interp = iname; /* for binfmt_script */ + /* Update interp in case binfmt_script needs it. */ + retval = bprm_change_interp(iname, bprm); + if (retval < 0) + goto _error; interp_file = open_exec (iname); retval = PTR_ERR (interp_file); diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index d3b8c1f6315..df49d486b0c 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -82,7 +82,9 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) retval = copy_strings_kernel(1, &i_name, bprm); if (retval) return retval; bprm->argc++; - bprm->interp = interp; + retval = bprm_change_interp(interp, bprm); + if (retval < 0) + return retval; /* * OK, now restart the process with the interpreter's dentry. diff --git a/fs/exec.c b/fs/exec.c index 6c4791d4634..51d86297363 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1206,9 +1206,24 @@ void free_bprm(struct linux_binprm *bprm) mutex_unlock(¤t->signal->cred_guard_mutex); abort_creds(bprm->cred); } + /* If a binfmt changed the interp, free it. */ + if (bprm->interp != bprm->filename) + kfree(bprm->interp); kfree(bprm); } +int bprm_change_interp(char *interp, struct linux_binprm *bprm) +{ + /* If a binfmt changed the interp, free it first. */ + if (bprm->interp != bprm->filename) + kfree(bprm->interp); + bprm->interp = kstrdup(interp, GFP_KERNEL); + if (!bprm->interp) + return -ENOMEM; + return 0; +} +EXPORT_SYMBOL(bprm_change_interp); + /* * install the new credentials for this executable */ diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 366422bc163..eb53e15ede6 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -128,6 +128,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm, unsigned long stack_top, int executable_stack); extern int bprm_mm_init(struct linux_binprm *bprm); +extern int bprm_change_interp(char *interp, struct linux_binprm *bprm); extern int copy_strings_kernel(int argc, const char *const *argv, struct linux_binprm *bprm); extern int prepare_bprm_creds(struct linux_binprm *bprm); From 4511ba021ea5ee7f2b76d954fc23c3814ac07cba Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 11 Dec 2012 22:18:05 +0100 Subject: [PATCH 1743/2357] x86, 8042: Enable A20 using KBC to fix S3 resume on some MSI laptops commit ad68652412276f68ad4fe3e1ecf5ee6880876783 upstream. Some MSI laptop BIOSes are broken - INT 15h code uses port 92h to enable A20 line but resume code assumes that KBC was used. The laptop will not resume from S3 otherwise but powers off after a while and then powers on again stuck with a blank screen. Fix it by enabling A20 using KBC in i8042_platform_init for x86. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=12878 Signed-off-by: Ondrej Zary Cc: Dmitry Torokhov Cc: Alan Cox Cc: Rafael J. Wysocki Link: http://lkml.kernel.org/r/201212112218.06551.linux@rainbow-software.org Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/i8042-x86ia64io.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index d6cc77a53c7..5f306f79da0 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -921,6 +921,7 @@ static int __init i8042_platform_init(void) int retval; #ifdef CONFIG_X86 + u8 a20_on = 0xdf; /* Just return if pre-detection shows no i8042 controller exist */ if (!x86_platform.i8042_detect()) return -ENODEV; @@ -960,6 +961,14 @@ static int __init i8042_platform_init(void) if (dmi_check_system(i8042_dmi_dritek_table)) i8042_dritek = true; + + /* + * A20 was already enabled during early kernel init. But some buggy + * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to + * resume from S3. So we do it here and hope that nothing breaks. + */ + i8042_command(&a20_on, 0x10d1); + i8042_command(NULL, 0x00ff); /* Null command for SMM firmware */ #endif /* CONFIG_X86 */ return retval; From 6cb6a94380506d9e5491b8e145811bd676ce6f3d Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 19 Oct 2012 14:03:33 +0100 Subject: [PATCH 1744/2357] virtio: force vring descriptors to be allocated from lowmem commit b92b1b89a33c172c075edccf6afb0edc41d851fd upstream. Virtio devices may attempt to add descriptors to a virtqueue from atomic context using GFP_ATOMIC allocation. This is problematic because such allocations can fall outside of the lowmem mapping, causing virt_to_phys to report bogus physical addresses which are subsequently passed to userspace via the buffers for the virtual device. This patch masks out __GFP_HIGH and __GFP_HIGHMEM from the requested flags when allocating descriptors for a virtqueue. If an atomic allocation is requested and later fails, we will return -ENOSPC which will be handled by the driver. Signed-off-by: Will Deacon Cc: Sasha Levin Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman --- drivers/virtio/virtio_ring.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 5aa43c3392a..52bfd0786fc 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -132,6 +132,13 @@ static int vring_add_indirect(struct vring_virtqueue *vq, unsigned head; int i; + /* + * We require lowmem mappings for the descriptors because + * otherwise virt_to_phys will give us bogus addresses in the + * virtqueue. + */ + gfp &= ~(__GFP_HIGHMEM | __GFP_HIGH); + desc = kmalloc((out + in) * sizeof(struct vring_desc), gfp); if (!desc) return -ENOMEM; From 711cf004f2148f1d1967bc5eca025019e5001212 Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Thu, 20 Dec 2012 15:05:07 -0800 Subject: [PATCH 1745/2357] mm: fix calculation of dirtyable memory commit c8b74c2f6604923de91f8aa6539f8bb934736754 upstream. The system uses global_dirtyable_memory() to calculate number of dirtyable pages/pages that can be allocated to the page cache. A bug causes an underflow thus making the page count look like a big unsigned number. This in turn confuses the dirty writeback throttling to aggressively write back pages as they become dirty (usually 1 page at a time). This generally only affects systems with highmem because the underflowed count gets subtracted from the global count of dirtyable memory. The problem was introduced with v3.2-4896-gab8fabd Fix is to ensure we don't get an underflowed total of either highmem or global dirtyable memory. Signed-off-by: Sonny Rao Signed-off-by: Puneet Kumar Acked-by: Johannes Weiner Tested-by: Damien Wyart Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/page-writeback.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 26adea8ca2e..bc8465f579a 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -186,6 +186,18 @@ static unsigned long highmem_dirtyable_memory(unsigned long total) x += zone_page_state(z, NR_FREE_PAGES) + zone_reclaimable_pages(z) - z->dirty_balance_reserve; } + /* + * Unreclaimable memory (kernel memory or anonymous memory + * without swap) can bring down the dirtyable pages below + * the zone's dirty balance reserve and the above calculation + * will underflow. However we still want to add in nodes + * which are below threshold (negative values) to get a more + * accurate calculation but make sure that the total never + * underflows. + */ + if ((long)x < 0) + x = 0; + /* * Make sure that the number of highmem pages is never larger * than the number of the total dirtyable memory. This can only @@ -208,8 +220,8 @@ unsigned long global_dirtyable_memory(void) { unsigned long x; - x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages() - - dirty_balance_reserve; + x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages(); + x -= min(x, dirty_balance_reserve); if (!vm_highmem_is_dirtyable) x -= highmem_dirtyable_memory(x); @@ -276,9 +288,12 @@ static unsigned long zone_dirtyable_memory(struct zone *zone) * highmem zone can hold its share of dirty pages, so we don't * care about vm_highmem_is_dirtyable here. */ - return zone_page_state(zone, NR_FREE_PAGES) + - zone_reclaimable_pages(zone) - - zone->dirty_balance_reserve; + unsigned long nr_pages = zone_page_state(zone, NR_FREE_PAGES) + + zone_reclaimable_pages(zone); + + /* don't allow this to underflow */ + nr_pages -= min(nr_pages, zone->dirty_balance_reserve); + return nr_pages; } /** From 25747cc45825ffc0192779a224d3bb9bc4b9edbd Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Fri, 21 Dec 2012 13:03:50 -0500 Subject: [PATCH 1746/2357] mm: Fix PageHead when !CONFIG_PAGEFLAGS_EXTENDED commit ad4b3fb7ff9940bcdb1e4cd62bd189d10fa636ba upstream. Unfortunately with !CONFIG_PAGEFLAGS_EXTENDED, (!PageHead) is false, and (PageHead) is true, for tail pages. If this is indeed the intended behavior, which I doubt because it breaks cache cleaning on some ARM systems, then the nomenclature is highly problematic. This patch makes sure PageHead is only true for head pages and PageTail is only true for tail pages, and neither is true for non-compound pages. [ This buglet seems ancient - seems to have been introduced back in Apr 2008 in commit 6a1e7f777f61: "pageflags: convert to the use of new macros". And the reason nobody noticed is because the PageHead() tests are almost all about just sanity-checking, and only used on pages that are actual page heads. The fact that the old code returned true for tail pages too was thus not really noticeable. - Linus ] Signed-off-by: Christoffer Dall Acked-by: Andrea Arcangeli Cc: Andrew Morton Cc: Will Deacon Cc: Steve Capper Cc: Christoph Lameter Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/page-flags.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index c88d2a9451a..4dabf0fe527 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -361,7 +361,7 @@ static inline void ClearPageCompound(struct page *page) * pages on the LRU and/or pagecache. */ TESTPAGEFLAG(Compound, compound) -__PAGEFLAG(Head, compound) +__SETPAGEFLAG(Head, compound) __CLEARPAGEFLAG(Head, compound) /* * PG_reclaim is used in combination with PG_compound to mark the @@ -373,8 +373,14 @@ __PAGEFLAG(Head, compound) * PG_compound & PG_reclaim => Tail page * PG_compound & ~PG_reclaim => Head page */ +#define PG_head_mask ((1L << PG_compound)) #define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim)) +static inline int PageHead(struct page *page) +{ + return ((page->flags & PG_head_tail_mask) == PG_head_mask); +} + static inline int PageTail(struct page *page) { return ((page->flags & PG_head_tail_mask) == PG_head_tail_mask); From 6718272b115afbf5d80ea1e0a4d18f9fcb32351f Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 2 Jan 2013 02:01:33 -0800 Subject: [PATCH 1747/2357] tmpfs mempolicy: fix /proc/mounts corrupting memory commit f2a07f40dbc603c15f8b06e6ec7f768af67b424f upstream. Recently I suggested using "mount -o remount,mpol=local /tmp" in NUMA mempolicy testing. Very nasty. Reading /proc/mounts, /proc/pid/mounts or /proc/pid/mountinfo may then corrupt one bit of kernel memory, often in a page table (causing "Bad swap" or "Bad page map" warning or "Bad pagetable" oops), sometimes in a vm_area_struct or rbnode or somewhere worse. "mpol=prefer" and "mpol=prefer:Node" are equally toxic. Recent NUMA enhancements are not to blame: this dates back to 2.6.35, when commit e17f74af351c "mempolicy: don't call mpol_set_nodemask() when no_context" skipped mpol_parse_str()'s call to mpol_set_nodemask(), which used to initialize v.preferred_node, or set MPOL_F_LOCAL in flags. With slab poisoning, you can then rely on mpol_to_str() to set the bit for node 0x6b6b, probably in the next page above the caller's stack. mpol_parse_str() is only called from shmem_parse_options(): no_context is always true, so call it unused for now, and remove !no_context code. Set v.nodes or v.preferred_node or MPOL_F_LOCAL as mpol_to_str() might expect. Then mpol_to_str() can ignore its no_context argument also, the mpol being appropriately initialized whether contextualized or not. Rename its no_context unused too, and let subsequent patch remove them (that's not needed for stable backporting, which would involve rejects). I don't understand why MPOL_LOCAL is described as a pseudo-policy: it's a reasonable policy which suffers from a confusing implementation in terms of MPOL_PREFERRED with MPOL_F_LOCAL. I believe this would be much more robust if MPOL_LOCAL were recognized in switch statements throughout, MPOL_F_LOCAL deleted, and MPOL_PREFERRED use the (possibly empty) nodes mask like everyone else, instead of its preferred_node variant (I presume an optimization from the days before MPOL_LOCAL). But that would take me too long to get right and fully tested. Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 64 ++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 458dedef9ee..82f1b027ba1 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2344,8 +2344,7 @@ void numa_default_policy(void) */ /* - * "local" is pseudo-policy: MPOL_PREFERRED with MPOL_F_LOCAL flag - * Used only for mpol_parse_str() and mpol_to_str() + * "local" is implemented internally by MPOL_PREFERRED with MPOL_F_LOCAL flag. */ #define MPOL_LOCAL MPOL_MAX static const char * const policy_modes[] = @@ -2360,28 +2359,21 @@ static const char * const policy_modes[] = #ifdef CONFIG_TMPFS /** - * mpol_parse_str - parse string to mempolicy + * mpol_parse_str - parse string to mempolicy, for tmpfs mpol mount option. * @str: string containing mempolicy to parse * @mpol: pointer to struct mempolicy pointer, returned on success. - * @no_context: flag whether to "contextualize" the mempolicy + * @unused: redundant argument, to be removed later. * * Format of input: * [=][:] * - * if @no_context is true, save the input nodemask in w.user_nodemask in - * the returned mempolicy. This will be used to "clone" the mempolicy in - * a specific context [cpuset] at a later time. Used to parse tmpfs mpol - * mount option. Note that if 'static' or 'relative' mode flags were - * specified, the input nodemask will already have been saved. Saving - * it again is redundant, but safe. - * * On success, returns 0, else 1 */ -int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) +int mpol_parse_str(char *str, struct mempolicy **mpol, int unused) { struct mempolicy *new = NULL; unsigned short mode; - unsigned short uninitialized_var(mode_flags); + unsigned short mode_flags; nodemask_t nodes; char *nodelist = strchr(str, ':'); char *flags = strchr(str, '='); @@ -2469,24 +2461,23 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) if (IS_ERR(new)) goto out; - if (no_context) { - /* save for contextualization */ - new->w.user_nodemask = nodes; - } else { - int ret; - NODEMASK_SCRATCH(scratch); - if (scratch) { - task_lock(current); - ret = mpol_set_nodemask(new, &nodes, scratch); - task_unlock(current); - } else - ret = -ENOMEM; - NODEMASK_SCRATCH_FREE(scratch); - if (ret) { - mpol_put(new); - goto out; - } - } + /* + * Save nodes for mpol_to_str() to show the tmpfs mount options + * for /proc/mounts, /proc/pid/mounts and /proc/pid/mountinfo. + */ + if (mode != MPOL_PREFERRED) + new->v.nodes = nodes; + else if (nodelist) + new->v.preferred_node = first_node(nodes); + else + new->flags |= MPOL_F_LOCAL; + + /* + * Save nodes for contextualization: this will be used to "clone" + * the mempolicy in a specific context [cpuset] at a later time. + */ + new->w.user_nodemask = nodes; + err = 0; out: @@ -2506,13 +2497,13 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) * @buffer: to contain formatted mempolicy string * @maxlen: length of @buffer * @pol: pointer to mempolicy to be formatted - * @no_context: "context free" mempolicy - use nodemask in w.user_nodemask + * @unused: redundant argument, to be removed later. * * Convert a mempolicy into a string. * Returns the number of characters in buffer (if positive) * or an error (negative) */ -int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context) +int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int unused) { char *p = buffer; int l; @@ -2538,7 +2529,7 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context) case MPOL_PREFERRED: nodes_clear(nodes); if (flags & MPOL_F_LOCAL) - mode = MPOL_LOCAL; /* pseudo-policy */ + mode = MPOL_LOCAL; else node_set(pol->v.preferred_node, nodes); break; @@ -2546,10 +2537,7 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context) case MPOL_BIND: /* Fall through */ case MPOL_INTERLEAVE: - if (no_context) - nodes = pol->w.user_nodemask; - else - nodes = pol->v.nodes; + nodes = pol->v.nodes; break; default: From 929cfe920d276f8d09b89c83f4ee0c721652d921 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Dec 2012 11:12:46 +0100 Subject: [PATCH 1748/2357] ALSA: usb-audio: Avoid autopm calls after disconnection commit 59866da9e4ae54819e3c4e0a8f426bdb0c2ef993 upstream. Add a similar protection against the disconnection race and the invalid use of usb instance after disconnection, as well as we've done for the USB audio PCM. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=51201 Reviewd-by: Clemens Ladisch Tested-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/midi.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/sound/usb/midi.c b/sound/usb/midi.c index eeefbce3873..c0054ee9389 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -116,6 +116,7 @@ struct snd_usb_midi { struct list_head list; struct timer_list error_timer; spinlock_t disc_lock; + struct rw_semaphore disc_rwsem; struct mutex mutex; u32 usb_id; int next_midi_device; @@ -1038,6 +1039,12 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open) struct snd_usb_midi* umidi = substream->rmidi->private_data; struct snd_kcontrol *ctl; + down_read(&umidi->disc_rwsem); + if (umidi->disconnected) { + up_read(&umidi->disc_rwsem); + return; + } + mutex_lock(&umidi->mutex); if (open) { if (umidi->opened++ == 0 && umidi->roland_load_ctl) { @@ -1056,6 +1063,7 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open) } } mutex_unlock(&umidi->mutex); + up_read(&umidi->disc_rwsem); } static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) @@ -1076,8 +1084,15 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) snd_BUG(); return -ENXIO; } + + down_read(&umidi->disc_rwsem); + if (umidi->disconnected) { + up_read(&umidi->disc_rwsem); + return -ENODEV; + } err = usb_autopm_get_interface(umidi->iface); port->autopm_reference = err >= 0; + up_read(&umidi->disc_rwsem); if (err < 0 && err != -EACCES) return -EIO; substream->runtime->private_data = port; @@ -1092,8 +1107,10 @@ static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) struct usbmidi_out_port *port = substream->runtime->private_data; substream_open(substream, 0); - if (port->autopm_reference) + down_read(&umidi->disc_rwsem); + if (!umidi->disconnected && port->autopm_reference) usb_autopm_put_interface(umidi->iface); + up_read(&umidi->disc_rwsem); return 0; } @@ -1403,9 +1420,12 @@ void snd_usbmidi_disconnect(struct list_head* p) * a timer may submit an URB. To reliably break the cycle * a flag under lock must be used */ + down_write(&umidi->disc_rwsem); spin_lock_irq(&umidi->disc_lock); umidi->disconnected = 1; spin_unlock_irq(&umidi->disc_lock); + up_write(&umidi->disc_rwsem); + for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->out) @@ -2117,6 +2137,7 @@ int snd_usbmidi_create(struct snd_card *card, umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); spin_lock_init(&umidi->disc_lock); + init_rwsem(&umidi->disc_rwsem); mutex_init(&umidi->mutex); umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), le16_to_cpu(umidi->dev->descriptor.idProduct)); From 740ccbaa57110e49f2296c4c610d745baaecc530 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Dec 2012 11:30:50 +0100 Subject: [PATCH 1749/2357] ALSA: usb-audio: Fix missing autopm for MIDI input commit f5f165418cabf2218eb466c0e94693b8b1aee88b upstream. The commit [88a8516a: ALSA: usbaudio: implement USB autosuspend] added the support of autopm for USB MIDI output, but it didn't take the MIDI input into account. This patch adds the following for fixing the autopm: - Manage the URB start at the first MIDI input stream open, instead of the time of instance creation - Move autopm code to the common substream_open() - Make snd_usbmidi_input_start/_stop() more robust and add the running state check Reviewd-by: Clemens Ladisch Tested-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/midi.c | 88 +++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/sound/usb/midi.c b/sound/usb/midi.c index c0054ee9389..34b9bb7fe87 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -126,8 +126,10 @@ struct snd_usb_midi { struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; - unsigned int opened; + bool autopm_reference; + unsigned int opened[2]; unsigned char disconnected; + unsigned char input_running; struct snd_kcontrol *roland_load_ctl; }; @@ -149,7 +151,6 @@ struct snd_usb_midi_out_endpoint { struct snd_usb_midi_out_endpoint* ep; struct snd_rawmidi_substream *substream; int active; - bool autopm_reference; uint8_t cable; /* cable number << 4 */ uint8_t state; #define STATE_UNKNOWN 0 @@ -1034,36 +1035,58 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi) snd_usbmidi_input_start(&umidi->list); } -static void substream_open(struct snd_rawmidi_substream *substream, int open) +static int substream_open(struct snd_rawmidi_substream *substream, int dir, + int open) { struct snd_usb_midi* umidi = substream->rmidi->private_data; struct snd_kcontrol *ctl; + int err; down_read(&umidi->disc_rwsem); if (umidi->disconnected) { up_read(&umidi->disc_rwsem); - return; + return open ? -ENODEV : 0; } mutex_lock(&umidi->mutex); if (open) { - if (umidi->opened++ == 0 && umidi->roland_load_ctl) { - ctl = umidi->roland_load_ctl; - ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(umidi->card, + if (!umidi->opened[0] && !umidi->opened[1]) { + err = usb_autopm_get_interface(umidi->iface); + umidi->autopm_reference = err >= 0; + if (err < 0 && err != -EACCES) { + mutex_unlock(&umidi->mutex); + up_read(&umidi->disc_rwsem); + return -EIO; + } + if (umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); - update_roland_altsetting(umidi); + update_roland_altsetting(umidi); + } } + umidi->opened[dir]++; + if (umidi->opened[1]) + snd_usbmidi_input_start(&umidi->list); } else { - if (--umidi->opened == 0 && umidi->roland_load_ctl) { - ctl = umidi->roland_load_ctl; - ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(umidi->card, + umidi->opened[dir]--; + if (!umidi->opened[1]) + snd_usbmidi_input_stop(&umidi->list); + if (!umidi->opened[0] && !umidi->opened[1]) { + if (umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } + if (umidi->autopm_reference) + usb_autopm_put_interface(umidi->iface); } } mutex_unlock(&umidi->mutex); up_read(&umidi->disc_rwsem); + return 0; } static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) @@ -1071,7 +1094,6 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) struct snd_usb_midi* umidi = substream->rmidi->private_data; struct usbmidi_out_port* port = NULL; int i, j; - int err; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) if (umidi->endpoints[i].out) @@ -1085,33 +1107,14 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) return -ENXIO; } - down_read(&umidi->disc_rwsem); - if (umidi->disconnected) { - up_read(&umidi->disc_rwsem); - return -ENODEV; - } - err = usb_autopm_get_interface(umidi->iface); - port->autopm_reference = err >= 0; - up_read(&umidi->disc_rwsem); - if (err < 0 && err != -EACCES) - return -EIO; substream->runtime->private_data = port; port->state = STATE_UNKNOWN; - substream_open(substream, 1); - return 0; + return substream_open(substream, 0, 1); } static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { - struct snd_usb_midi* umidi = substream->rmidi->private_data; - struct usbmidi_out_port *port = substream->runtime->private_data; - - substream_open(substream, 0); - down_read(&umidi->disc_rwsem); - if (!umidi->disconnected && port->autopm_reference) - usb_autopm_put_interface(umidi->iface); - up_read(&umidi->disc_rwsem); - return 0; + return substream_open(substream, 0, 0); } static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) @@ -1164,14 +1167,12 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) { - substream_open(substream, 1); - return 0; + return substream_open(substream, 1, 1); } static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) { - substream_open(substream, 0); - return 0; + return substream_open(substream, 1, 0); } static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) @@ -2080,12 +2081,15 @@ void snd_usbmidi_input_stop(struct list_head* p) unsigned int i, j; umidi = list_entry(p, struct snd_usb_midi, list); + if (!umidi->input_running) + return; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->in) for (j = 0; j < INPUT_URBS; ++j) usb_kill_urb(ep->in->urbs[j]); } + umidi->input_running = 0; } static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) @@ -2110,8 +2114,11 @@ void snd_usbmidi_input_start(struct list_head* p) int i; umidi = list_entry(p, struct snd_usb_midi, list); + if (umidi->input_running || !umidi->opened[1]) + return; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) snd_usbmidi_input_start_ep(umidi->endpoints[i].in); + umidi->input_running = 1; } /* @@ -2250,9 +2257,6 @@ int snd_usbmidi_create(struct snd_card *card, } list_add_tail(&umidi->list, midi_list); - - for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) - snd_usbmidi_input_start_ep(umidi->endpoints[i].in); return 0; } From 37cb3a0366a60bca8f0bb4123639404c36402f70 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 17 Dec 2012 20:06:49 +0100 Subject: [PATCH 1750/2357] ALSA: hda - Fix the wrong pincaps set in ALC861VD dallas/hp fixup commit b78562b10fa66175e30b76073e32a0ad8d92aa83 upstream. The workaround to force VREF50 for dallas/hp model with ALC861VD was introduced in commit 8fdcb6fe4204bdb4c6991652717ab5063751414e, but it contained wrong pincap override bits. This patch fixes to exclude VREF80 pincap bit correctly. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 29774e22bda..7f2a10901ae 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6520,8 +6520,8 @@ static void alc861vd_fixup_dallas(struct hda_codec *codec, const struct alc_fixup *fix, int action) { if (action == ALC_FIXUP_ACT_PRE_PROBE) { - snd_hda_override_pin_caps(codec, 0x18, 0x00001714); - snd_hda_override_pin_caps(codec, 0x19, 0x0000171c); + snd_hda_override_pin_caps(codec, 0x18, 0x00000734); + snd_hda_override_pin_caps(codec, 0x19, 0x0000073c); } } From 73396089a501bdaa98a70efbd358c29daa7af0d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Dec 2012 14:33:42 +0100 Subject: [PATCH 1751/2357] ALSA: hda - Fix pin configuration of HP Pavilion dv7 commit 8ae5865ec77c22462c736846a0679947a6953548 upstream. Fix the quirk entry for HP Pavilion dv7 in order to make the bass speaker working. Reported-and-tested-by: Tomas Pospisek Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 04cd44fa224..137b67f8e69 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1695,7 +1695,7 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + "HP Pavilion dv7", STAC_HP_DV7_4000), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, From a86cd75b2fd681c71dd4a04877bc62151648e8c0 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 20 Dec 2012 16:24:43 +0200 Subject: [PATCH 1752/2357] rtlwifi: fix incorrect use of usb_alloc_coherent with usb_control_msg commit 4c3de5920c486b8eefa6187ee6a181864c161100 upstream. Incorrect use of usb_alloc_coherent memory as input buffer to usb_control_msg can cause problems in arch DMA code, for example kernel BUG at 'arch/arm/include/asm/dma-mapping.h:321' on ARM (linux-3.4). Change _usb_writeN_sync use kmalloc'd buffer instead. Signed-off-by: Jussi Kivilinna Acked-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/usb.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index aa970fc18a2..8fa144fa0c9 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -210,17 +210,16 @@ static void _usb_writeN_sync(struct rtl_priv *rtlpriv, u32 addr, void *data, u16 index = REALTEK_USB_VENQT_CMD_IDX; int pipe = usb_sndctrlpipe(udev, 0); /* write_out */ u8 *buffer; - dma_addr_t dma_addr; - wvalue = (u16)(addr&0x0000ffff); - buffer = usb_alloc_coherent(udev, (size_t)len, GFP_ATOMIC, &dma_addr); + wvalue = (u16)(addr & 0x0000ffff); + buffer = kmalloc(len, GFP_ATOMIC); if (!buffer) return; memcpy(buffer, data, len); usb_control_msg(udev, pipe, request, reqtype, wvalue, index, buffer, len, 50); - usb_free_coherent(udev, (size_t)len, buffer, dma_addr); + kfree(buffer); } static void _rtl_usb_io_handler_init(struct device *dev, From 0e70111a128bd15f7ff90186deca1b6306a793e6 Mon Sep 17 00:00:00 2001 From: Tomasz Guszkowski Date: Sat, 22 Dec 2012 18:30:01 +0100 Subject: [PATCH 1753/2357] p54usb: add USB ID for T-Com Sinus 154 data II commit 3194b7fcdf6caea338b5d2c72d76fed80437649c upstream. Added USB ID for T-Com Sinus 154 data II. Signed-off-by: Tomasz Guszkowski Acked-by: Christian Lamparter Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/p54/p54usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index a337a50d402..27e0a1ff836 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -82,6 +82,7 @@ static struct usb_device_id p54u_table[] = { {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */ {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ + {USB_DEVICE(0x083a, 0x4503)}, /* T-Com Sinus 154 data II */ {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */ {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */ From 44c818b94f8b3d3ad173ef9556414944e6da6efb Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 27 Dec 2012 15:18:20 +0100 Subject: [PATCH 1754/2357] p54usb: add USBIDs for two more p54usb devices commit 4010fe21a315b4223c25376714c6a2b61b722e5c upstream. This patch adds USBIDs for: - DrayTek Vigor 530 - Zoom 4410a It also adds a note about Gemtek WUBI-100GW and SparkLAN WL-682 USBID conflict [WUBI-100GW is a ISL3886+NET2280 (LM86 firmare) solution, whereas WL-682 is a ISL3887 (LM87 firmware)] device. Source: Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/p54/p54usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 27e0a1ff836..be20cf765bc 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -47,6 +47,7 @@ static struct usb_device_id p54u_table[] = { {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */ {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */ {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ + {USB_DEVICE(0x0675, 0x0530)}, /* DrayTek Vigor 530 */ {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */ {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */ @@ -82,6 +83,7 @@ static struct usb_device_id p54u_table[] = { {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */ {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ + {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */ {USB_DEVICE(0x083a, 0x4503)}, /* T-Com Sinus 154 data II */ {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */ @@ -102,6 +104,7 @@ static struct usb_device_id p54u_table[] = { {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ + /* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */ {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */ {USB_DEVICE(0x1740, 0x1000)}, /* Senao NUB-350 */ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ From 9784404f31f7001186c5fc1f8e4a3c8091711dfa Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 22 Oct 2012 22:15:02 +0200 Subject: [PATCH 1755/2357] usb: gadget: midi: free hs descriptors commit d185039f7982eb82cf8d03b6fb6689587ca5af24 upstream. The HS descriptors are only created if HS is supported by the UDC but we never free them. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_midi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 2f7e8f2930c..1bf95964056 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -416,6 +416,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) midi->id = NULL; usb_free_descriptors(f->descriptors); + usb_free_descriptors(f->hs_descriptors); kfree(midi); } From bb355e4833e30947197b58c8886dff40a5f6ee50 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 22 Oct 2012 22:15:04 +0200 Subject: [PATCH 1756/2357] usb: gadget: phonet: free requests in pn_bind()'s error path commit d0eca719dd11ad0619e8dd6a1f3eceb95b0216dd upstream. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_phonet.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 965a6293206..16512f921bc 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -531,7 +531,7 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f) req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL); if (!req) - goto err; + goto err_req; req->complete = pn_rx_complete; fp->out_reqv[i] = req; @@ -540,14 +540,18 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f) /* Outgoing USB requests */ fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL); if (!fp->in_req) - goto err; + goto err_req; INFO(cdev, "USB CDC Phonet function\n"); INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name, fp->out_ep->name, fp->in_ep->name); return 0; +err_req: + for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++) + usb_ep_free_request(fp->out_ep, fp->out_reqv[i]); err: + if (fp->out_ep) fp->out_ep->driver_data = NULL; if (fp->in_ep) From e7a4b0efe62e56a0acc81d16091c6efc2a282be8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 22 Oct 2012 22:15:05 +0200 Subject: [PATCH 1757/2357] usb: gadget: uvc: fix error path in uvc_function_bind() commit 0f9df939385527049c8062a099fbfa1479fe7ce0 upstream. The "video->minor = -1" assigment is done in V4L2 by video_register_device() so it is removed here. Now. uvc_function_bind() calls in error case uvc_function_unbind() for cleanup. The problem is that uvc_function_unbind() frees the uvc struct and uvc_bind_config() does as well in error case of usb_add_function(). Removing kfree() in usb_add_function() would make the patch smaller but it would look odd because the new allocated memory is not cleaned up. However it is not guaranteed that if we call usb_add_function() we also get to the bind function. Therefore the patch extracts the conditional cleanup from uvc_function_unbind() applies to uvc_function_bind(). uvc_function_unbind() now contains only the complete cleanup which is required once everything has been registrated. Signed-off-by: Sebastian Andrzej Siewior Cc: Laurent Pinchart Cc: Bhupesh Sharma Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_uvc.c | 39 ++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index 2022fe49214..a0abc65ecbe 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -335,7 +335,6 @@ uvc_register_video(struct uvc_device *uvc) return -ENOMEM; video->parent = &cdev->gadget->dev; - video->minor = -1; video->fops = &uvc_v4l2_fops; video->release = video_device_release; strncpy(video->name, cdev->gadget->name, sizeof(video->name)); @@ -462,23 +461,12 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) INFO(cdev, "uvc_function_unbind\n"); - if (uvc->vdev) { - if (uvc->vdev->minor == -1) - video_device_release(uvc->vdev); - else - video_unregister_device(uvc->vdev); - uvc->vdev = NULL; - } - - if (uvc->control_ep) - uvc->control_ep->driver_data = NULL; - if (uvc->video.ep) - uvc->video.ep->driver_data = NULL; + video_unregister_device(uvc->vdev); + uvc->control_ep->driver_data = NULL; + uvc->video.ep->driver_data = NULL; - if (uvc->control_req) { - usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); - kfree(uvc->control_buf); - } + usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); + kfree(uvc->control_buf); kfree(f->descriptors); kfree(f->hs_descriptors); @@ -563,7 +551,22 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) return 0; error: - uvc_function_unbind(c, f); + if (uvc->vdev) + video_device_release(uvc->vdev); + + if (uvc->control_ep) + uvc->control_ep->driver_data = NULL; + if (uvc->video.ep) + uvc->video.ep->driver_data = NULL; + + if (uvc->control_req) { + usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); + kfree(uvc->control_buf); + } + + kfree(f->descriptors); + kfree(f->hs_descriptors); + kfree(f->ss_descriptors); return ret; } From c96158c87f8f3bc41ff6e1343c680a10fb747d31 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 22 Oct 2012 22:15:00 +0200 Subject: [PATCH 1758/2357] usb: gadget: network: fix bind() error path commit e79cc615a9bb44da72c499ccfa2c9c4bbea3aa84 upstream. I think this is wrong since 72c973dd ("usb: gadget: add usb_endpoint_descriptor to struct usb_ep"). If we fail to allocate an ep or bail out early we shouldn't check for the descriptor which is assigned at ep_enable() time. Signed-off-by: Sebastian Andrzej Siewior Cc: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_ecm.c | 4 ++-- drivers/usb/gadget/f_eem.c | 5 ++--- drivers/usb/gadget/f_ncm.c | 4 ++-- drivers/usb/gadget/f_rndis.c | 4 ++-- drivers/usb/gadget/f_subset.c | 4 ++-- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 30b908f2a53..672c66aad6b 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -808,9 +808,9 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) /* we might as well release our claims on endpoints */ if (ecm->notify) ecm->notify->driver_data = NULL; - if (ecm->port.out_ep->desc) + if (ecm->port.out_ep) ecm->port.out_ep->driver_data = NULL; - if (ecm->port.in_ep->desc) + if (ecm->port.in_ep) ecm->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 1a7b2dd7d40..a9cf20522ff 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -319,10 +319,9 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) if (f->hs_descriptors) usb_free_descriptors(f->hs_descriptors); - /* we might as well release our claims on endpoints */ - if (eem->port.out_ep->desc) + if (eem->port.out_ep) eem->port.out_ep->driver_data = NULL; - if (eem->port.in_ep->desc) + if (eem->port.in_ep) eem->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index aab8eded045..d7811ae2972 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -1259,9 +1259,9 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) /* we might as well release our claims on endpoints */ if (ncm->notify) ncm->notify->driver_data = NULL; - if (ncm->port.out_ep->desc) + if (ncm->port.out_ep) ncm->port.out_ep->driver_data = NULL; - if (ncm->port.in_ep->desc) + if (ncm->port.in_ep) ncm->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 52343654f5d..345f8388cd3 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -803,9 +803,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) /* we might as well release our claims on endpoints */ if (rndis->notify) rndis->notify->driver_data = NULL; - if (rndis->port.out_ep->desc) + if (rndis->port.out_ep) rndis->port.out_ep->driver_data = NULL; - if (rndis->port.in_ep->desc) + if (rndis->port.in_ep) rndis->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 21ab474aca0..e5bb9662863 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -370,9 +370,9 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) usb_free_descriptors(f->hs_descriptors); /* we might as well release our claims on endpoints */ - if (geth->port.out_ep->desc) + if (geth->port.out_ep) geth->port.out_ep->driver_data = NULL; - if (geth->port.in_ep->desc) + if (geth->port.in_ep) geth->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); From dc2306834bff03132beb1f18d7a13b6e5080e488 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 Nov 2012 12:57:03 +0100 Subject: [PATCH 1759/2357] ACPI: do acpisleep dmi check when CONFIG_ACPI_SLEEP is set commit 0ac1b1d7b7424cd6f129b5454b504b3cae746f0e upstream. The current acpisleep DMI checks only run when CONFIG_SUSPEND is set. And this may break hibernation on some platforms when CONFIG_SUSPEND is cleared. Move acpisleep DMI check into #ifdef CONFIG_ACPI_SLEEP instead. [rjw: Added acpi_sleep_dmi_check() and rebased on top of earlier patches adding entries to acpisleep_dmi_table[].] References: https://bugzilla.kernel.org/show_bug.cgi?id=45921 Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/sleep.c | 348 ++++++++++++++++++++++--------------------- 1 file changed, 177 insertions(+), 171 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 480b648b9a1..aa0a904e563 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -138,6 +138,180 @@ void __init acpi_old_suspend_ordering(void) old_suspend_ordering = true; } +static int __init init_old_suspend_ordering(const struct dmi_system_id *d) +{ + acpi_old_suspend_ordering(); + return 0; +} + +static int __init init_nvs_nosave(const struct dmi_system_id *d) +{ + acpi_nvs_nosave(); + return 0; +} + +static struct dmi_system_id __initdata acpisleep_dmi_table[] = { + { + .callback = init_old_suspend_ordering, + .ident = "Abit KN9 (nForce4 variant)", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"), + DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "HP xw4600 Workstation", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "M2N8L"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Panasonic CF51-2L", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "Matsushita Electric Industrial Co.,Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-FW21E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB17FX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR11M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Everex StepNote Series", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB1Z1E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-NW130D", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCCW29FX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Averatec AV1020-ED2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus A8N-SLI DELUXE", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus A8N-SLI Premium", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR26GN_P", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB1S1E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-FW520F", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Asus K54C", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "K54C"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Asus K54HR", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), + }, + }, + {}, +}; + +static void acpi_sleep_dmi_check(void) +{ + dmi_check_system(acpisleep_dmi_table); +} + /** * acpi_pm_freeze - Disable the GPEs and suspend EC transactions. */ @@ -227,6 +401,7 @@ static void acpi_pm_end(void) } #else /* !CONFIG_ACPI_SLEEP */ #define acpi_target_sleep_state ACPI_STATE_S0 +static inline void acpi_sleep_dmi_check(void) {} #endif /* CONFIG_ACPI_SLEEP */ #ifdef CONFIG_SUSPEND @@ -371,175 +546,6 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = { .end = acpi_pm_end, .recover = acpi_pm_finish, }; - -static int __init init_old_suspend_ordering(const struct dmi_system_id *d) -{ - old_suspend_ordering = true; - return 0; -} - -static int __init init_nvs_nosave(const struct dmi_system_id *d) -{ - acpi_nvs_nosave(); - return 0; -} - -static struct dmi_system_id __initdata acpisleep_dmi_table[] = { - { - .callback = init_old_suspend_ordering, - .ident = "Abit KN9 (nForce4 variant)", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"), - DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "HP xw4600 Workstation", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "M2N8L"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Panasonic CF51-2L", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, - "Matsushita Electric Industrial Co.,Ltd."), - DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-FW21E", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCEB17FX", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-SR11M", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Everex StepNote Series", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCEB1Z1E", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-NW130D", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCCW29FX", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Averatec AV1020-ED2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"), - DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus A8N-SLI DELUXE", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus A8N-SLI Premium", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-SR26GN_P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCEB1S1E", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-FW520F", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Asus K54C", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "K54C"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Asus K54HR", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), - }, - }, - {}, -}; #endif /* CONFIG_SUSPEND */ #ifdef CONFIG_HIBERNATION @@ -880,13 +886,13 @@ int __init acpi_sleep_init(void) u8 type_a, type_b; #ifdef CONFIG_SUSPEND int i = 0; - - dmi_check_system(acpisleep_dmi_table); #endif if (acpi_disabled) return 0; + acpi_sleep_dmi_check(); + sleep_states[ACPI_STATE_S0] = 1; printk(KERN_INFO PREFIX "(supports S0"); From eb9422b448fdd814ca566c0509f72dc41971ba6b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 4 Jan 2013 23:00:54 +0100 Subject: [PATCH 1760/2357] ACPI / scan: Do not use dummy HID for system bus ACPI nodes commit 4f5f64cf0cc916220aaa055992e31195470cfe37 upstream. At one point acpi_device_set_id() checks if acpi_device_hid(device) returns NULL, but that never happens, so system bus devices with an empty list of PNP IDs are given the dummy HID ("device") instead of the "system bus HID" ("LNXSYBUS"). Fix the code to use the right check. Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 85cbfdccc97..bd3199ce5b2 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1157,7 +1157,7 @@ static void acpi_device_set_id(struct acpi_device *device) acpi_add_id(device, ACPI_DOCK_HID); else if (!acpi_ibm_smbus_match(device)) acpi_add_id(device, ACPI_SMBUS_IBM_HID); - else if (!acpi_device_hid(device) && + else if (list_empty(&device->pnp.ids) && ACPI_IS_ROOT_DEVICE(device->parent)) { acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); From d1967aac70c3eaf8f93710035b313904deabf6a9 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Mon, 12 Nov 2012 16:55:38 -0500 Subject: [PATCH 1761/2357] NFS: Add sequence_priviliged_ops for nfs4_proc_sequence() commit 6bdb5f213c4344324f600dde885f25768fbd14db upstream. If I mount an NFS v4.1 server to a single client multiple times and then run xfstests over each mountpoint I usually get the client into a state where recovery deadlocks. The server informs the client of a cb_path_down sequence error, the client then does a bind_connection_to_session and checks the status of the lease. I found that bind_connection_to_session sets the NFS4_SESSION_DRAINING flag on the client, but this flag is never unset before nfs4_check_lease() reaches nfs4_proc_sequence(). This causes the client to deadlock, halting all NFS activity to the server. nfs4_proc_sequence() is only called by the state manager, so I can change it to run in privileged mode to bypass the NFS4_SESSION_DRAINING check and avoid the deadlock. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8955e364200..30351877aee 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5739,13 +5739,26 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) rpc_call_start(task); } +static void nfs41_sequence_prepare_privileged(struct rpc_task *task, void *data) +{ + rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); + nfs41_sequence_prepare(task, data); +} + static const struct rpc_call_ops nfs41_sequence_ops = { .rpc_call_done = nfs41_sequence_call_done, .rpc_call_prepare = nfs41_sequence_prepare, .rpc_release = nfs41_sequence_release, }; -static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) +static const struct rpc_call_ops nfs41_sequence_privileged_ops = { + .rpc_call_done = nfs41_sequence_call_done, + .rpc_call_prepare = nfs41_sequence_prepare_privileged, + .rpc_release = nfs41_sequence_release, +}; + +static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred, + const struct rpc_call_ops *seq_ops) { struct nfs4_sequence_data *calldata; struct rpc_message msg = { @@ -5755,7 +5768,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_ struct rpc_task_setup task_setup_data = { .rpc_client = clp->cl_rpcclient, .rpc_message = &msg, - .callback_ops = &nfs41_sequence_ops, + .callback_ops = seq_ops, .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, }; @@ -5782,7 +5795,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) return 0; - task = _nfs41_proc_sequence(clp, cred); + task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_ops); if (IS_ERR(task)) ret = PTR_ERR(task); else @@ -5796,7 +5809,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) struct rpc_task *task; int ret; - task = _nfs41_proc_sequence(clp, cred); + task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_privileged_ops); if (IS_ERR(task)) { ret = PTR_ERR(task); goto out; From 1627e18aed860a61cc740e9ec9883c63059ae2a3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 13 Dec 2012 15:14:36 +1100 Subject: [PATCH 1762/2357] NFS: avoid NULL dereference in nfs_destroy_server commit f259613a1e4b44a0cf85a5dafd931be96ee7c9e5 upstream. In rare circumstances, nfs_clone_server() of a v2 or v3 server can get an error between setting server->destory (to nfs_destroy_server), and calling nfs_start_lockd (which will set server->nlm_host). If this happens, nfs_clone_server will call nfs_free_server which will call nfs_destroy_server and thence nlmclnt_done(NULL). This causes the NULL to be dereferenced. So add a guard to only call nlmclnt_done() if ->nlm_host is not NULL. The other guards there are irrelevant as nlm_host can only be non-NULL if one of these flags are set - so remove those tests. (Thanks to Trond for this suggestion). This is suitable for any stable kernel since 2.6.25. Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/client.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 60f7e4ec842..37f6de36973 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -694,8 +694,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, */ static void nfs_destroy_server(struct nfs_server *server) { - if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) || - !(server->flags & NFS_MOUNT_LOCAL_FCNTL)) + if (server->nlm_host) nlmclnt_done(server->nlm_host); } From 0d965378563d9e73e52b11fcd8576a90f071b2af Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 14 Dec 2012 16:38:46 -0500 Subject: [PATCH 1763/2357] NFS: Fix calls to drop_nlink() commit 1f018458b30b0d5c535c94e577aa0acbb92e1395 upstream. It is almost always wrong for NFS to call drop_nlink() after removing a file. What we really want is to mark the inode's attributes for revalidation, and we want to ensure that the VFS drops it if we're reasonably sure that this is the final unlink(). Do the former using the usual cache validity flags, and the latter by testing if inode->i_nlink == 1, and clearing it in that case. This also fixes the following warning reported by Neil Brown and Jeff Layton (among others). [634155.004438] WARNING: at /home/abuild/rpmbuild/BUILD/kernel-desktop-3.5.0/lin [634155.004442] Hardware name: Latitude E6510 [634155.004577] crc_itu_t crc32c_intel snd_hwdep snd_pcm snd_timer snd soundcor [634155.004609] Pid: 13402, comm: bash Tainted: G W 3.5.0-36-desktop # [634155.004611] Call Trace: [634155.004630] [] dump_trace+0xaa/0x2b0 [634155.004641] [] dump_stack+0x69/0x6f [634155.004653] [] warn_slowpath_common+0x7b/0xc0 [634155.004662] [] drop_nlink+0x34/0x40 [634155.004687] [] nfs_dentry_iput+0x33/0x70 [nfs] [634155.004714] [] dput+0x12e/0x230 [634155.004726] [] __fput+0x170/0x230 [634155.004735] [] filp_close+0x5f/0x90 [634155.004743] [] sys_close+0x97/0x100 [634155.004754] [] system_call_fastpath+0x16/0x1b [634155.004767] [<00007f2a73a0d110>] 0x7f2a73a0d10f Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/dir.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 53ad9d1c37e..a0daac7ad50 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1219,11 +1219,14 @@ static int nfs_dentry_delete(const struct dentry *dentry) } +/* Ensure that we revalidate inode->i_nlink */ static void nfs_drop_nlink(struct inode *inode) { spin_lock(&inode->i_lock); - if (inode->i_nlink > 0) - drop_nlink(inode); + /* drop the inode if we're reasonably sure this is the last link */ + if (inode->i_nlink == 1) + clear_nlink(inode); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR; spin_unlock(&inode->i_lock); } @@ -1238,8 +1241,8 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { - drop_nlink(inode); nfs_complete_unlink(dentry, inode); + nfs_drop_nlink(inode); } iput(inode); } @@ -1800,10 +1803,8 @@ static int nfs_safe_remove(struct dentry *dentry) if (inode != NULL) { nfs_inode_return_delegation(inode); error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); - /* The VFS may want to delete this inode */ if (error == 0) nfs_drop_nlink(inode); - nfs_mark_for_revalidate(inode); } else error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); if (error == -ENOENT) From aa8dc4af9a1ed18d71da58e883bb8260ba47afb5 Mon Sep 17 00:00:00 2001 From: Yanchuan Nian Date: Wed, 24 Oct 2012 14:44:19 +0800 Subject: [PATCH 1764/2357] nfs: fix wrong object type in lockowner_slab commit 3c40794b2dd0f355ef4e6bf8d85af5dcd7da7ece upstream. The object type in the cache of lockowner_slab is wrong, and it is better to fix it. Signed-off-by: Yanchuan Nian Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a2f99d15584..537731e4c16 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2356,7 +2356,7 @@ nfsd4_init_slabs(void) if (openowner_slab == NULL) goto out_nomem; lockowner_slab = kmem_cache_create("nfsd4_lockowners", - sizeof(struct nfs4_openowner), 0, 0, NULL); + sizeof(struct nfs4_lockowner), 0, 0, NULL); if (lockowner_slab == NULL) goto out_nomem; file_slab = kmem_cache_create("nfsd4_files", From 12c93e196764a2092f35b30a1e924a5071f164ee Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 16 Nov 2012 15:22:43 -0500 Subject: [PATCH 1765/2357] nfsd: fix v4 reply caching commit 57d276d71aef7d8305ff002a070cb98deb2edced upstream. Very embarassing: 1091006c5eb15cba56785bd5b498a8d0b9546903 "nfsd: turn on reply cache for NFSv4" missed a line, effectively leaving the reply cache off in the v4 case. I thought I'd tested that, but I guess not. This time, wrote a pynfs test to confirm it works. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfssvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index b6f8e65f85b..53459b055cf 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -650,7 +650,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) } /* Store reply in cache. */ - nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); + nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); return 1; } From 4cbb3d03810a50cb5d9eab0a6cfe3152a65911f2 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 4 Dec 2012 18:25:10 -0500 Subject: [PATCH 1766/2357] nfsd4: fix oops on unusual readlike compound commit d5f50b0c290431c65377c4afa1c764e2c3fe5305 upstream. If the argument and reply together exceed the maximum payload size, then a reply with a read-like operation can overlow the rq_pages array. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4xdr.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 283d15e9f46..967d68eef28 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2920,11 +2920,16 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, len = maxcount; v = 0; while (len > 0) { - pn = resp->rqstp->rq_resused++; + pn = resp->rqstp->rq_resused; + if (!resp->rqstp->rq_respages[pn]) { /* ran out of pages */ + maxcount -= len; + break; + } resp->rqstp->rq_vec[v].iov_base = page_address(resp->rqstp->rq_respages[pn]); resp->rqstp->rq_vec[v].iov_len = len < PAGE_SIZE ? len : PAGE_SIZE; + resp->rqstp->rq_resused++; v++; len -= PAGE_SIZE; } @@ -2970,6 +2975,8 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd return nfserr; if (resp->xbuf->page_len) return nfserr_resource; + if (!resp->rqstp->rq_respages[resp->rqstp->rq_resused]) + return nfserr_resource; page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); @@ -3019,6 +3026,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 return nfserr; if (resp->xbuf->page_len) return nfserr_resource; + if (!resp->rqstp->rq_respages[resp->rqstp->rq_resused]) + return nfserr_resource; RESERVE_SPACE(NFS4_VERIFIER_SIZE); savep = p; From 59d6ce4370c17dbd3db789740a036f158e8ba9a0 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Fri, 7 Dec 2012 15:40:55 -0500 Subject: [PATCH 1767/2357] nfsd: avoid permission checks on EXCLUSIVE_CREATE replay commit 7007c90fb9fef593b4aeaeee57e6a6754276c97c upstream. With NFSv4, if we create a file then open it we explicit avoid checking the permissions on the file during the open because the fact that we created it ensures we should be allow to open it (the create and the open should appear to be a single operation). However if the reply to an EXCLUSIVE create gets lots and the client resends the create, the current code will perform the permission check - because it doesn't realise that it did the open already.. This patch should fix this. Note that I haven't actually seen this cause a problem. I was just looking at the code trying to figure out a different EXCLUSIVE open related issue, and this looked wrong. (Fix confirmed with pynfs 4.0 test OPEN4--bfields) Signed-off-by: NeilBrown [bfields: use OWNER_OVERRIDE and update for 4.1] Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4proc.c | 8 +++++--- fs/nfsd/vfs.c | 10 ++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 987e719fbae..dd0308d65f6 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -194,6 +194,7 @@ static __be32 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) { struct svc_fh *resfh; + int accmode; __be32 status; resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); @@ -253,9 +254,10 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o /* set reply cache */ fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, &resfh->fh_handle); - if (!open->op_created) - status = do_open_permission(rqstp, resfh, open, - NFSD_MAY_NOP); + accmode = NFSD_MAY_NOP; + if (open->op_created) + accmode |= NFSD_MAY_OWNER_OVERRIDE; + status = do_open_permission(rqstp, resfh, open, accmode); set_change_info(&open->op_cinfo, current_fh); fh_dup2(current_fh, resfh); out: diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 568666156ea..f03160106b9 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1477,13 +1477,19 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, case NFS3_CREATE_EXCLUSIVE: if ( dchild->d_inode->i_mtime.tv_sec == v_mtime && dchild->d_inode->i_atime.tv_sec == v_atime - && dchild->d_inode->i_size == 0 ) + && dchild->d_inode->i_size == 0 ) { + if (created) + *created = 1; break; + } case NFS4_CREATE_EXCLUSIVE4_1: if ( dchild->d_inode->i_mtime.tv_sec == v_mtime && dchild->d_inode->i_atime.tv_sec == v_atime - && dchild->d_inode->i_size == 0 ) + && dchild->d_inode->i_size == 0 ) { + if (created) + *created = 1; goto set_attr; + } /* fallthru */ case NFS3_CREATE_GUARDED: err = nfserr_exist; From 042cf2fb1d2ac4b4b27b2ccc4ac317a2f53df3c3 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Fri, 4 Jan 2013 03:22:57 -0500 Subject: [PATCH 1768/2357] nfs: fix null checking in nfs_get_option_str() commit e25fbe380c4e3c09afa98bcdcd9d3921443adab8 upstream. The following null pointer check is broken. *option = match_strdup(args); return !option; The pointer `option' must be non-null, and thus `!option' is always false. Use `!*option' instead. The bug was introduced in commit c5cb09b6f8 ("Cleanup: Factor out some cut-and-paste code."). Signed-off-by: Xi Wang Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index feabe7a394c..c252161e7b1 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1138,7 +1138,7 @@ static int nfs_get_option_str(substring_t args[], char **option) { kfree(*option); *option = match_strdup(args); - return !option; + return !*option; } static int nfs_get_option_ul(substring_t args[], unsigned long *option) From c815c83dfd1aef11d4197dc46b21a2471b81af2c Mon Sep 17 00:00:00 2001 From: Peter Popovec Date: Fri, 14 Dec 2012 22:57:25 -0800 Subject: [PATCH 1769/2357] Input: walkera0701 - fix crash on startup commit a455e2985f57e2a71566bb8850094af38b2c932d upstream. The driver's timer must be set up before enabling IRQ handler, otherwise bad things may happen. Reported-and-tested-by: Fengguang Wu Signed-off-by: Peter Popovec Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/joystick/walkera0701.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c index 4dfa1eed4b7..f8f892b076e 100644 --- a/drivers/input/joystick/walkera0701.c +++ b/drivers/input/joystick/walkera0701.c @@ -196,6 +196,7 @@ static void walkera0701_close(struct input_dev *dev) struct walkera_dev *w = input_get_drvdata(dev); parport_disable_irq(w->parport); + hrtimer_cancel(&w->timer); } static int walkera0701_connect(struct walkera_dev *w, int parport) @@ -224,6 +225,9 @@ static int walkera0701_connect(struct walkera_dev *w, int parport) if (parport_claim(w->pardevice)) goto init_err1; + hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + w->timer.function = timer_handler; + w->input_dev = input_allocate_device(); if (!w->input_dev) goto init_err2; @@ -254,8 +258,6 @@ static int walkera0701_connect(struct walkera_dev *w, int parport) if (err) goto init_err3; - hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - w->timer.function = timer_handler; return 0; init_err3: @@ -271,7 +273,6 @@ static int walkera0701_connect(struct walkera_dev *w, int parport) static void walkera0701_disconnect(struct walkera_dev *w) { - hrtimer_cancel(&w->timer); input_unregister_device(w->input_dev); parport_release(w->pardevice); parport_unregister_device(w->pardevice); From 1a37441ae4ad38d98c39b349137c0fb7f76b32ad Mon Sep 17 00:00:00 2001 From: Christophe TORDEUX Date: Mon, 24 Dec 2012 09:20:40 -0800 Subject: [PATCH 1770/2357] Input: sentelic - only report position of first finger as ST coordinates commit a25461659050b913e114d282bf58823682eb56b6 upstream. Report only the position of the first finger as absolute non-MT coordinates, instead of reporting both fingers alternatively. Actual MT events are unaffected. This fixes horizontal and improves vertical scrolling with the touchpad. Signed-off-by: Christophe TORDEUX Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/sentelic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index 661a0ca3b3d..1257ce8147f 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -759,7 +759,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) fsp_set_slot(dev, 0, fgrs > 0, abs_x, abs_y); fsp_set_slot(dev, 1, false, 0, 0); } - if (fgrs > 0) { + if (fgrs == 1 || (fgrs == 2 && !(packet[0] & FSP_PB0_MFMC_FGR2))) { input_report_abs(dev, ABS_X, abs_x); input_report_abs(dev, ABS_Y, abs_y); } From 09c4161c8a1fe8900561029a5d1dce8887231afd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 3 Nov 2012 11:52:09 +0100 Subject: [PATCH 1771/2357] genirq: Always force thread affinity commit 04aa530ec04f61875b99c12721162e2964e3318c upstream. Sankara reported that the genirq core code fails to adjust the affinity of an interrupt thread in several cases: 1) On request/setup_irq() the call to setup_affinity() happens before the new action is registered, so the new thread is not notified. 2) For secondary shared interrupts nothing notifies the new thread to change its affinity. 3) Interrupts which have the IRQ_NO_BALANCE flag set are not moving the thread either. Fix this by setting the thread affinity flag right on thread creation time. This ensures that under all circumstances the thread moves to the right place. Requires a check in irq_thread_check_affinity for an existing affinity mask (CONFIG_CPU_MASK_OFFSTACK=y) Reported-and-tested-by: Sankara Muthukrishnan Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1209041738200.2754@ionos Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/irq/manage.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index b9d1d83ec38..7684920f4f6 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -708,6 +708,7 @@ static void irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) { cpumask_var_t mask; + bool valid = true; if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags)) return; @@ -722,10 +723,18 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) } raw_spin_lock_irq(&desc->lock); - cpumask_copy(mask, desc->irq_data.affinity); + /* + * This code is triggered unconditionally. Check the affinity + * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out. + */ + if (desc->irq_data.affinity) + cpumask_copy(mask, desc->irq_data.affinity); + else + valid = false; raw_spin_unlock_irq(&desc->lock); - set_cpus_allowed_ptr(current, mask); + if (valid) + set_cpus_allowed_ptr(current, mask); free_cpumask_var(mask); } #else @@ -933,6 +942,16 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) */ get_task_struct(t); new->thread = t; + /* + * Tell the thread to set its affinity. This is + * important for shared interrupt handlers as we do + * not invoke setup_affinity() for the secondary + * handlers as everything is already set up. Even for + * interrupts marked with IRQF_NO_BALANCE this is + * correct as we want the thread to move to the cpu(s) + * on which the requesting code placed the interrupt. + */ + set_bit(IRQTF_AFFINITY, &new->thread_flags); } if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { From 9044dea3b603b7f0246aa7bed4039df3666fc611 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Mon, 5 Nov 2012 22:26:40 +0300 Subject: [PATCH 1772/2357] usb: musb: cppi_dma: export cppi_interrupt() commit 8b416b0b25d5d8ddb3a91c1d20e1373582c50405 upstream. Now that DaVinci glue layer can be modular, we must export cppi_interrupt() that it may call... Signed-off-by: Sergei Shtylyov Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/cppi_dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 66bc376005d..319cfcf372a 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -1313,6 +1313,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(cppi_interrupt); /* Instantiate a software object representing a DMA controller. */ struct dma_controller *__init From 363cfe8903364aed741cc5c7f31610581a135be8 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 25 Oct 2012 13:44:12 -0700 Subject: [PATCH 1773/2357] xhci: Fix conditional check in bandwidth calculation. commit 392a07ae3316f2b90b39ce41e66d6f6b5c95de90 upstream. David reports that at drivers/usb/host/xhci.c:2257: static bool xhci_is_sync_in_ep(unsigned int ep_type) { return (ep_type == ISOC_IN_EP || ep_type != INT_IN_EP); } The static analyser cppcheck says [linux-3.7-rc2/drivers/usb/host/xhci.c:2257]: (style) Redundant condition: If ep_type == 5, the comparison ep_type != 7 is always true. Maybe the original programmer intention was something like static bool xhci_is_sync_in_ep(unsigned int ep_type) { return (ep_type == ISOC_IN_EP || ep_type == INT_IN_EP); } Fix this. This patch should be backported to stable kernels as old as 3.2, that contain the commit 2b69899934c63b7b9432568584fb4c4a2924f40c "xhci: USB 3.0 BW checking." Signed-off-by: Sarah Sharp Reported-by: David Binderman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index e52ddfe0548..1722e218ee2 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2253,7 +2253,7 @@ static bool xhci_is_async_ep(unsigned int ep_type) static bool xhci_is_sync_in_ep(unsigned int ep_type) { - return (ep_type == ISOC_IN_EP || ep_type != INT_IN_EP); + return (ep_type == ISOC_IN_EP || ep_type == INT_IN_EP); } static unsigned int xhci_get_ss_bw_consumed(struct xhci_bw_info *ep_bw) From ceb58b9ffa579690f6124fd49dc1734071544f50 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 25 Oct 2012 15:56:40 -0700 Subject: [PATCH 1774/2357] xHCI: Fix TD Size calculation on 1.0 hosts. commit 4525c0a10dff7ad3669763c28016c7daffc3900e upstream. The xHCI 1.0 specification made a change to the TD Size field in TRBs. The value is now the number of packets that remain to be sent in the TD, not including this TRB. The TD Size value for the last TRB in a TD must always be zero. The xHCI function xhci_v1_0_td_remainder() attempts to calculate this, but it gets it wrong. First, it erroneously reuses the old xhci_td_remainder function, which will right shift the value by 10. The xHCI 1.0 spec as of June 2011 says nothing about right shifting by 10. Second, it does not set the TD size for the last TRB in a TD to zero. Third, it uses roundup instead of DIV_ROUND_UP. The total packet count is supposed to be the total number of bytes in this TD, divided by the max packet size, rounded up. DIV_ROUND_UP is the right function to use in that case. With the old code, a TD on an endpoint with max packet size 1024 would be set up like so: TRB 1, TRB length = 600 bytes, TD size = 0 TRB 1, TRB length = 200 bytes, TD size = 0 TRB 1, TRB length = 100 bytes, TD size = 0 With the new code, the TD would be set up like this: TRB 1, TRB length = 600 bytes, TD size = 1 TRB 1, TRB length = 200 bytes, TD size = 1 TRB 1, TRB length = 100 bytes, TD size = 0 This commit should be backported to kernels as old as 3.0, that contain the commit 4da6e6f247a2601ab9f1e63424e4d944ed4124f3 "xhci 1.0: Update TD size field format." Signed-off-by: Sarah Sharp Reported-by: Chintan Mehta Reported-by: Shimmer Huang Tested-by: Bhavik Kothari Tested-by: Shimmer Huang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 23aebcb4ee2..bf8bcc4dd78 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3069,11 +3069,11 @@ static u32 xhci_td_remainder(unsigned int remainder) } /* - * For xHCI 1.0 host controllers, TD size is the number of packets remaining in - * the TD (*not* including this TRB). + * For xHCI 1.0 host controllers, TD size is the number of max packet sized + * packets remaining in the TD (*not* including this TRB). * * Total TD packet count = total_packet_count = - * roundup(TD size in bytes / wMaxPacketSize) + * DIV_ROUND_UP(TD size in bytes / wMaxPacketSize) * * Packets transferred up to and including this TRB = packets_transferred = * rounddown(total bytes transferred including this TRB / wMaxPacketSize) @@ -3081,15 +3081,16 @@ static u32 xhci_td_remainder(unsigned int remainder) * TD size = total_packet_count - packets_transferred * * It must fit in bits 21:17, so it can't be bigger than 31. + * The last TRB in a TD must have the TD size set to zero. */ - static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len, - unsigned int total_packet_count, struct urb *urb) + unsigned int total_packet_count, struct urb *urb, + unsigned int num_trbs_left) { int packets_transferred; /* One TRB with a zero-length data packet. */ - if (running_total == 0 && trb_buff_len == 0) + if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len == 0)) return 0; /* All the TRB queueing functions don't count the current TRB in @@ -3098,7 +3099,9 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len, packets_transferred = (running_total + trb_buff_len) / usb_endpoint_maxp(&urb->ep->desc); - return xhci_td_remainder(total_packet_count - packets_transferred); + if ((total_packet_count - packets_transferred) > 31) + return 31 << 17; + return (total_packet_count - packets_transferred) << 17; } static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, @@ -3125,7 +3128,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, num_trbs = count_sg_trbs_needed(xhci, urb); num_sgs = urb->num_mapped_sgs; - total_packet_count = roundup(urb->transfer_buffer_length, + total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length, usb_endpoint_maxp(&urb->ep->desc)); trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], @@ -3208,7 +3211,8 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, running_total); } else { remainder = xhci_v1_0_td_remainder(running_total, - trb_buff_len, total_packet_count, urb); + trb_buff_len, total_packet_count, urb, + num_trbs - 1); } length_field = TRB_LEN(trb_buff_len) | remainder | @@ -3316,7 +3320,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, start_cycle = ep_ring->cycle_state; running_total = 0; - total_packet_count = roundup(urb->transfer_buffer_length, + total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length, usb_endpoint_maxp(&urb->ep->desc)); /* How much data is in the first TRB? */ addr = (u64) urb->transfer_dma; @@ -3362,7 +3366,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, running_total); } else { remainder = xhci_v1_0_td_remainder(running_total, - trb_buff_len, total_packet_count, urb); + trb_buff_len, total_packet_count, urb, + num_trbs - 1); } length_field = TRB_LEN(trb_buff_len) | remainder | @@ -3625,7 +3630,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, addr = start_addr + urb->iso_frame_desc[i].offset; td_len = urb->iso_frame_desc[i].length; td_remain_len = td_len; - total_packet_count = roundup(td_len, + total_packet_count = DIV_ROUND_UP(td_len, usb_endpoint_maxp(&urb->ep->desc)); /* A zero-length transfer still involves at least one packet. */ if (total_packet_count == 0) @@ -3704,7 +3709,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } else { remainder = xhci_v1_0_td_remainder( running_total, trb_buff_len, - total_packet_count, urb); + total_packet_count, urb, + (trbs_per_td - j - 1)); } length_field = TRB_LEN(trb_buff_len) | remainder | From a50afb91545b5a7e32a508b3eecaffe9538f018b Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Thu, 1 Nov 2012 12:47:59 -0700 Subject: [PATCH 1775/2357] xhci: fix null-pointer dereference when destroying half-built segment rings commit 68e5254adb88bede68285f11fb442a4d34fb550c upstream. xhci_alloc_segments_for_ring() builds a list of xhci_segments and links the tail to head at the end (forming a ring). When it bails out for OOM reasons half-way through, it tries to destroy its half-built list with xhci_free_segments_for_ring(), even though it is not a ring yet. This causes a null-pointer dereference upon hitting the last element. Furthermore, one of its callers (xhci_ring_alloc()) mistakenly believes the output parameters to be valid upon this kind of OOM failure, and calls xhci_ring_free() on them. Since the (incomplete) list/ring should already be destroyed in that case, this would lead to a use after free. This patch fixes those issues by having xhci_alloc_segments_for_ring() destroy its half-built, non-circular list manually and destroying the invalid struct xhci_ring in xhci_ring_alloc() with a plain kfree(). This patch should be backported to kernels as old as 2.6.31, that contains the commit 0ebbab37422315a5d0cb29792271085bafdf38c0 "USB: xhci: Ring allocation and initialization." A separate patch will need to be developed for kernels older than 3.4, since the ring allocation code was refactored in that kernel. Signed-off-by: Julius Werner Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index cbed50ad9c1..3e16f1c160a 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -205,7 +205,12 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, next = xhci_segment_alloc(xhci, cycle_state, flags); if (!next) { - xhci_free_segments_for_ring(xhci, *first); + prev = *first; + while (prev) { + next = prev->next; + xhci_segment_free(xhci, prev); + prev = next; + } return -ENOMEM; } xhci_link_segments(xhci, prev, next, type); @@ -258,7 +263,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, return ring; fail: - xhci_ring_free(xhci, ring); + kfree(ring); return NULL; } From 4b2e61048c2c51882dc268dc2916a5b3bfab00ea Mon Sep 17 00:00:00 2001 From: "Alexis R. Cortes" Date: Thu, 8 Nov 2012 16:59:27 -0600 Subject: [PATCH 1776/2357] usb: host: xhci: Stricter conditional for Z1 system models for Compliance Mode Patch commit b0e4e606ff6ff26da0f60826e75577b56ba4e463 upstream. This minor patch creates a more stricter conditional for the Z1 sytems for applying the Compliance Mode Patch, this to avoid the quirk to be applied to models that contain a "Z1" in their dmi product string but are different from Z1 systems. This patch should be backported to stable kernels as old as 3.2, that contain the commit 71c731a296f1b08a3724bd1b514b64f1bda87a23 "usb: host: xhci: Fix Compliance Mode on SN65LVPE502CP Hardware" Signed-off-by: Alexis R. Cortes Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1722e218ee2..b4063fc72b4 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -480,7 +480,7 @@ static bool compliance_mode_recovery_timer_quirk_check(void) if (strstr(dmi_product_name, "Z420") || strstr(dmi_product_name, "Z620") || strstr(dmi_product_name, "Z820") || - strstr(dmi_product_name, "Z1")) + strstr(dmi_product_name, "Z1 Workstation")) return true; return false; From 66f8b956aeeeea9e5b3024f860251687f13f9013 Mon Sep 17 00:00:00 2001 From: Russell Webb Date: Fri, 9 Nov 2012 13:58:49 -0800 Subject: [PATCH 1777/2357] xhci: Add Lynx Point LP to list of Intel switchable hosts commit bb1e5dd7113d2fd178d3af9aca8f480ae0468edf upstream. Like Lynx Point, Lynx Point LP is also switchable. See 1c12443ab8eba71a658fae4572147e56d1f84f66 for more details. This patch should be backported to stable kernels as old as 3.0, that contain commit 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support EHCI/xHCI port switching." Signed-off-by: Russell Webb Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 3 ++- drivers/usb/host/pci-quirks.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 123481793a4..0909783a034 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -362,7 +362,8 @@ static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == 0x1E26 || pdev->device == 0x8C2D || - pdev->device == 0x8C26); + pdev->device == 0x8C26 || + pdev->device == 0x9C26); } static void ehci_enable_xhci_companion(void) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 39f9e4a9a2d..eb5563ac58b 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -723,6 +723,7 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, } #define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31 +#define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI 0x9C31 bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev) { @@ -736,7 +737,8 @@ bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev) { return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI; + (pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI); } bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) From 475261dbbf5d85e1a298886385d859ada787ae1f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 19 Nov 2012 08:13:35 -0800 Subject: [PATCH 1778/2357] cgroup: remove incorrect dget/dput() pair in cgroup_create_dir() commit 175431635ec09b1d1bba04979b006b99e8305a83 upstream. cgroup_create_dir() does weird dancing with dentry refcnt. On success, it gets and then puts it achieving nothing. On failure, it puts but there isn't no matching get anywhere leading to the following oops if cgroup_create_file() fails for whatever reason. ------------[ cut here ]------------ kernel BUG at /work/os/work/fs/dcache.c:552! invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Modules linked in: CPU 2 Pid: 697, comm: mkdir Not tainted 3.7.0-rc4-work+ #3 Bochs Bochs RIP: 0010:[] [] dput+0x1dc/0x1e0 RSP: 0018:ffff88001a3ebef8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff88000e5b1ef8 RCX: 0000000000000403 RDX: 0000000000000303 RSI: 2000000000000000 RDI: ffff88000e5b1f58 RBP: ffff88001a3ebf18 R08: ffffffff82c76960 R09: 0000000000000001 R10: ffff880015022080 R11: ffd9bed70f48a041 R12: 00000000ffffffea R13: 0000000000000001 R14: ffff88000e5b1f58 R15: 00007fff57656d60 FS: 00007ff05fcb3800(0000) GS:ffff88001fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000004046f0 CR3: 000000001315f000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process mkdir (pid: 697, threadinfo ffff88001a3ea000, task ffff880015022080) Stack: ffff88001a3ebf48 00000000ffffffea 0000000000000001 0000000000000000 ffff88001a3ebf38 ffffffff811cc889 0000000000000001 ffff88000e5b1ef8 ffff88001a3ebf68 ffffffff811d1fc9 ffff8800198d7f18 ffff880019106ef8 Call Trace: [] done_path_create+0x19/0x50 [] sys_mkdirat+0x59/0x80 [] sys_mkdir+0x19/0x20 [] system_call_fastpath+0x16/0x1b Code: 00 48 8d 90 18 01 00 00 48 89 93 c0 00 00 00 4c 89 a0 18 01 00 00 48 8b 83 a0 00 00 00 83 80 28 01 00 00 01 e8 e6 6f a0 00 eb 92 <0f> 0b 66 90 0f 1f 44 00 00 55 48 89 e5 41 57 41 56 49 89 fe 41 RIP [] dput+0x1dc/0x1e0 RSP ---[ end trace 1277bcfd9561ddb0 ]--- Fix it by dropping the unnecessary dget/dput() pair. Signed-off-by: Tejun Heo Acked-by: Li Zefan Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 762f7cc753a..a5dccd4c236 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2568,9 +2568,7 @@ static int cgroup_create_dir(struct cgroup *cgrp, struct dentry *dentry, dentry->d_fsdata = cgrp; inc_nlink(parent->d_inode); rcu_assign_pointer(cgrp->dentry, dentry); - dget(dentry); } - dput(dentry); return error; } From cd924e960d3c2ae1654109b5b9e88cec334f7126 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 16 Oct 2012 15:03:14 -0700 Subject: [PATCH 1779/2357] freezer: add missing mb's to freezer_count() and freezer_should_skip() commit dd67d32dbc5de299d70cc9e10c6c1e29ffa56b92 upstream. A task is considered frozen enough between freezer_do_not_count() and freezer_count() and freezers use freezer_should_skip() to test this condition. This supposedly works because freezer_count() always calls try_to_freezer() after clearing %PF_FREEZER_SKIP. However, there currently is nothing which guarantees that freezer_count() sees %true freezing() after clearing %PF_FREEZER_SKIP when freezing is in progress, and vice-versa. A task can escape the freezing condition in effect by freezer_count() seeing !freezing() and freezer_should_skip() seeing %PF_FREEZER_SKIP. This patch adds smp_mb()'s to freezer_count() and freezer_should_skip() such that either %true freezing() is visible to freezer_count() or !PF_FREEZER_SKIP is visible to freezer_should_skip(). Signed-off-by: Tejun Heo Cc: Oleg Nesterov Cc: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- include/linux/freezer.h | 50 ++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/include/linux/freezer.h b/include/linux/freezer.h index d09af4b67cf..ee899329e65 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -75,28 +75,62 @@ static inline bool cgroup_freezing(struct task_struct *task) */ -/* Tell the freezer not to count the current task as freezable. */ +/** + * freezer_do_not_count - tell freezer to ignore %current + * + * Tell freezers to ignore the current task when determining whether the + * target frozen state is reached. IOW, the current task will be + * considered frozen enough by freezers. + * + * The caller shouldn't do anything which isn't allowed for a frozen task + * until freezer_cont() is called. Usually, freezer[_do_not]_count() pair + * wrap a scheduling operation and nothing much else. + */ static inline void freezer_do_not_count(void) { current->flags |= PF_FREEZER_SKIP; } -/* - * Tell the freezer to count the current task as freezable again and try to - * freeze it. +/** + * freezer_count - tell freezer to stop ignoring %current + * + * Undo freezer_do_not_count(). It tells freezers that %current should be + * considered again and tries to freeze if freezing condition is already in + * effect. */ static inline void freezer_count(void) { current->flags &= ~PF_FREEZER_SKIP; + /* + * If freezing is in progress, the following paired with smp_mb() + * in freezer_should_skip() ensures that either we see %true + * freezing() or freezer_should_skip() sees !PF_FREEZER_SKIP. + */ + smp_mb(); try_to_freeze(); } -/* - * Check if the task should be counted as freezable by the freezer +/** + * freezer_should_skip - whether to skip a task when determining frozen + * state is reached + * @p: task in quesion + * + * This function is used by freezers after establishing %true freezing() to + * test whether a task should be skipped when determining the target frozen + * state is reached. IOW, if this function returns %true, @p is considered + * frozen enough. */ -static inline int freezer_should_skip(struct task_struct *p) +static inline bool freezer_should_skip(struct task_struct *p) { - return !!(p->flags & PF_FREEZER_SKIP); + /* + * The following smp_mb() paired with the one in freezer_count() + * ensures that either freezer_count() sees %true freezing() or we + * see cleared %PF_FREEZER_SKIP and return %false. This makes it + * impossible for a task to slip frozen state testing after + * clearing %PF_FREEZER_SKIP. + */ + smp_mb(); + return p->flags & PF_FREEZER_SKIP; } /* From af445c0d36202fe86bc50f0a1831c5661f5b1189 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 31 Oct 2012 17:20:50 +0100 Subject: [PATCH 1780/2357] x86, amd: Disable way access filter on Piledriver CPUs commit 2bbf0a1427c377350f001fbc6260995334739ad7 upstream. The Way Access Filter in recent AMD CPUs may hurt the performance of some workloads, caused by aliasing issues in the L1 cache. This patch disables it on the affected CPUs. The issue is similar to that one of last year: http://lkml.indiana.edu/hypermail/linux/kernel/1107.3/00041.html This new patch does not replace the old one, we just need another quirk for newer CPUs. The performance penalty without the patch depends on the circumstances, but is a bit less than the last year's 3%. The workloads affected would be those that access code from the same physical page under different virtual addresses, so different processes using the same libraries with ASLR or multiple instances of PIE-binaries. The code needs to be accessed simultaneously from both cores of the same compute unit. More details can be found here: http://developer.amd.com/Assets/SharedL1InstructionCacheonAMD15hCPU.pdf CPUs affected are anything with the core known as Piledriver. That includes the new parts of the AMD A-Series (aka Trinity) and the just released new CPUs of the FX-Series (aka Vishera). The model numbering is a bit odd here: FX CPUs have model 2, A-Series has model 10h, with possible extensions to 1Fh. Hence the range of model ids. Signed-off-by: Andre Przywara Link: http://lkml.kernel.org/r/1351700450-9277-1-git-send-email-osp@andrep.de Signed-off-by: H. Peter Anvin Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/amd.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 146bb6218ee..6b4976b0cbb 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -598,6 +598,20 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) } } + /* + * The way access filter has a performance penalty on some workloads. + * Disable it on the affected CPUs. + */ + if ((c->x86 == 0x15) && + (c->x86_model >= 0x02) && (c->x86_model < 0x20)) { + u64 val; + + if (!rdmsrl_safe(0xc0011021, &val) && !(val & 0x1E)) { + val |= 0x1E; + checking_wrmsrl(0xc0011021, val); + } + } + cpu_detect_cache_sizes(c); /* Multi core CPU? */ From a9b876220838f045ab3c365f668477771e149c3c Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Mon, 17 Dec 2012 11:52:47 -0600 Subject: [PATCH 1781/2357] sparc: huge_ptep_set_* functions need to call set_huge_pte_at() [ Upstream commit 6cb9c3697585c47977c42c5cc1b9fc49247ac530 ] Modifying the huge pte's requires that all the underlying pte's be modified. Version 2: added missing flush_tlb_page() Signed-off-by: Dave Kleikamp Cc: "David S. Miller" Cc: sparclinux@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/include/asm/hugetlb.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/sparc/include/asm/hugetlb.h b/arch/sparc/include/asm/hugetlb.h index 177061064ee..f368cef0379 100644 --- a/arch/sparc/include/asm/hugetlb.h +++ b/arch/sparc/include/asm/hugetlb.h @@ -58,14 +58,20 @@ static inline pte_t huge_pte_wrprotect(pte_t pte) static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - ptep_set_wrprotect(mm, addr, ptep); + pte_t old_pte = *ptep; + set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte)); } static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep, pte_t pte, int dirty) { - return ptep_set_access_flags(vma, addr, ptep, pte, dirty); + int changed = !pte_same(*ptep, pte); + if (changed) { + set_huge_pte_at(vma->vm_mm, addr, ptep, pte); + flush_tlb_page(vma, addr); + } + return changed; } static inline pte_t huge_ptep_get(pte_t *ptep) From 6eec2413cb320bdd0139ba0db3888d27f746ea2b Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 26 Dec 2012 02:32:10 +0000 Subject: [PATCH 1782/2357] batman-adv: fix random jitter calculation [ Upstream commit 143cdd8f33909ff5a153e3f02048738c5964ba26 ] batadv_iv_ogm_emit_send_time() attempts to calculates a random integer in the range of 'orig_interval +- BATADV_JITTER' by the below lines. msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER; msecs += (random32() % 2 * BATADV_JITTER); But it actually gets 'orig_interval' or 'orig_interval - BATADV_JITTER' because '%' and '*' have same precedence and associativity is left-to-right. This adds the parentheses at the appropriate position so that it matches original intension. Signed-off-by: Akinobu Mita Acked-by: Antonio Quartulli Cc: Marek Lindner Cc: Simon Wunderlich Cc: Antonio Quartulli Cc: b.a.t.m.a.n@lists.open-mesh.org Cc: "David S. Miller" Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/batman-adv/bat_iv_ogm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index a6d5d63fb6a..fa701b6f794 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -72,7 +72,7 @@ static unsigned long bat_iv_ogm_emit_send_time(const struct bat_priv *bat_priv) { return jiffies + msecs_to_jiffies( atomic_read(&bat_priv->orig_interval) - - JITTER + (random32() % 2*JITTER)); + JITTER + (random32() % (2*JITTER))); } /* when do we schedule a ogm packet to be sent */ From d46699a94ddf2dd4d83e986a759b64981b37fc5b Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Fri, 14 Dec 2012 04:07:58 +0000 Subject: [PATCH 1783/2357] inet: Fix kmemleak in tcp_v4/6_syn_recv_sock and dccp_v4/6_request_recv_sock [ Upstream commit e337e24d6624e74a558aa69071e112a65f7b5758 ] If in either of the above functions inet_csk_route_child_sock() or __inet_inherit_port() fails, the newsk will not be freed: unreferenced object 0xffff88022e8a92c0 (size 1592): comm "softirq", pid 0, jiffies 4294946244 (age 726.160s) hex dump (first 32 bytes): 0a 01 01 01 0a 01 01 02 00 00 00 00 a7 cc 16 00 ................ 02 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] kmemleak_alloc+0x21/0x3e [] kmem_cache_alloc+0xb5/0xc5 [] sk_prot_alloc.isra.53+0x2b/0xcd [] sk_clone_lock+0x16/0x21e [] inet_csk_clone_lock+0x10/0x7b [] tcp_create_openreq_child+0x21/0x481 [] tcp_v4_syn_recv_sock+0x3a/0x23b [] tcp_check_req+0x29f/0x416 [] tcp_v4_do_rcv+0x161/0x2bc [] tcp_v4_rcv+0x6c9/0x701 [] ip_local_deliver_finish+0x70/0xc4 [] ip_local_deliver+0x4e/0x7f [] ip_rcv_finish+0x1fc/0x233 [] ip_rcv+0x217/0x267 [] __netif_receive_skb+0x49e/0x553 [] netif_receive_skb+0x50/0x82 This happens, because sk_clone_lock initializes sk_refcnt to 2, and thus a single sock_put() is not enough to free the memory. Additionally, things like xfrm, memcg, cookie_values,... may have been initialized. We have to free them properly. This is fixed by forcing a call to tcp_done(), ending up in inet_csk_destroy_sock, doing the final sock_put(). tcp_done() is necessary, because it ends up doing all the cleanup on xfrm, memcg, cookie_values, xfrm,... Before calling tcp_done, we have to set the socket to SOCK_DEAD, to force it entering inet_csk_destroy_sock. To avoid the warning in inet_csk_destroy_sock, inet_num has to be set to 0. As inet_csk_destroy_sock does a dec on orphan_count, we first have to increase it. Calling tcp_done() allows us to remove the calls to tcp_clear_xmit_timer() and tcp_cleanup_congestion_control(). A similar approach is taken for dccp by calling dccp_done(). This is in the kernel since 093d282321 (tproxy: fix hash locking issue when using port redirection in __inet_inherit_port()), thus since version >= 2.6.37. Signed-off-by: Christoph Paasch Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/inet_connection_sock.h | 1 + net/dccp/ipv4.c | 4 ++-- net/dccp/ipv6.c | 3 ++- net/ipv4/inet_connection_sock.c | 16 ++++++++++++++++ net/ipv4/tcp_ipv4.c | 6 ++---- net/ipv6/tcp_ipv6.c | 3 ++- 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index dbf9aab34c8..e9b05ded948 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -317,6 +317,7 @@ extern void inet_csk_reqsk_queue_prune(struct sock *parent, const unsigned long max_rto); extern void inet_csk_destroy_sock(struct sock *sk); +extern void inet_csk_prepare_forced_close(struct sock *sk); /* * LISTEN is a special case for poll.. diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index caf6e1734b6..c6f6e425b2e 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -435,8 +435,8 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; put_and_exit: - bh_unlock_sock(newsk); - sock_put(newsk); + inet_csk_prepare_forced_close(newsk); + dccp_done(newsk); goto exit; } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 4dc588f520e..aaa8f8bee9e 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -611,7 +611,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, newinet->inet_rcv_saddr = LOOPBACK4_IPV6; if (__inet_inherit_port(sk, newsk) < 0) { - sock_put(newsk); + inet_csk_prepare_forced_close(newsk); + dccp_done(newsk); goto out; } __inet6_hash(newsk, NULL); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 19d66cefd7d..3f404325854 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -659,6 +659,22 @@ void inet_csk_destroy_sock(struct sock *sk) } EXPORT_SYMBOL(inet_csk_destroy_sock); +/* This function allows to force a closure of a socket after the call to + * tcp/dccp_create_openreq_child(). + */ +void inet_csk_prepare_forced_close(struct sock *sk) +{ + /* sk_clone_lock locked the socket and set refcnt to 2 */ + bh_unlock_sock(sk); + sock_put(sk); + + /* The below has to be done to allow calling inet_csk_destroy_sock */ + sock_set_flag(sk, SOCK_DEAD); + percpu_counter_inc(sk->sk_prot->orphan_count); + inet_sk(sk)->inet_num = 0; +} +EXPORT_SYMBOL(inet_csk_prepare_forced_close); + int inet_csk_listen_start(struct sock *sk, const int nr_table_entries) { struct inet_sock *inet = inet_sk(sk); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 8f2458df19f..76f50e1b53a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1524,10 +1524,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; put_and_exit: - tcp_clear_xmit_timers(newsk); - tcp_cleanup_congestion_control(newsk); - bh_unlock_sock(newsk); - sock_put(newsk); + inet_csk_prepare_forced_close(newsk); + tcp_done(newsk); goto exit; } EXPORT_SYMBOL(tcp_v4_syn_recv_sock); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8a8fa2dd149..3889e020418 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1411,7 +1411,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, #endif if (__inet_inherit_port(sk, newsk) < 0) { - sock_put(newsk); + inet_csk_prepare_forced_close(newsk); + tcp_done(newsk); goto out; } __inet6_hash(newsk, NULL); From c7078c2c5da80e387420795a5a0857b1cd711fc9 Mon Sep 17 00:00:00 2001 From: Stefan Hasko Date: Fri, 21 Dec 2012 15:04:59 +0000 Subject: [PATCH 1784/2357] net: sched: integer overflow fix [ Upstream commit d2fe85da52e89b8012ffad010ef352a964725d5f ] Fixed integer overflow in function htb_dequeue Signed-off-by: Stefan Hasko Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_htb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 29b942ce9e8..f08b9166119 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -876,7 +876,7 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) q->now = psched_get_time(); start_at = jiffies; - next_event = q->now + 5 * PSCHED_TICKS_PER_SEC; + next_event = q->now + 5LLU * PSCHED_TICKS_PER_SEC; for (level = 0; level < TC_HTB_MAXDEPTH; level++) { /* common case optimization - skip event handler quickly */ From c87b45599a4e0d8741abeb85d1d8d5f0c1fb13be Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 6 Jan 2013 18:21:49 +0000 Subject: [PATCH 1785/2357] tcp: fix MSG_SENDPAGE_NOTLAST logic [ Upstream commit ae62ca7b03217be5e74759dc6d7698c95df498b3 ] commit 35f9c09fe9c72e (tcp: tcp_sendpages() should call tcp_push() once) added an internal flag : MSG_SENDPAGE_NOTLAST meant to be set on all frags but the last one for a splice() call. The condition used to set the flag in pipe_to_sendpage() relied on splice() user passing the exact number of bytes present in the pipe, or a smaller one. But some programs pass an arbitrary high value, and the test fails. The effect of this bug is a lack of tcp_push() at the end of a splice(pipe -> socket) call, and possibly very slow or erratic TCP sessions. We should both test sd->total_len and fact that another fragment is in the pipe (pipe->nrbufs > 1) Many thanks to Willy for providing very clear bug report, bisection and test programs. Reported-by: Willy Tarreau Bisected-by: Willy Tarreau Tested-by: Willy Tarreau Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- fs/splice.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/splice.c b/fs/splice.c index 5cac690f810..bed6a3c2935 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -696,8 +696,10 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe, return -EINVAL; more = (sd->flags & SPLICE_F_MORE) ? MSG_MORE : 0; - if (sd->len < sd->total_len) + + if (sd->len < sd->total_len && pipe->nrbufs > 1) more |= MSG_SENDPAGE_NOTLAST; + return file->f_op->sendpage(file, buf->page, buf->offset, sd->len, &pos, more); } From 34fb350281ced2a72707a5c0064f69992d440edb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 17 Jul 2012 10:13:05 +0200 Subject: [PATCH 1786/2357] tcp: implement RFC 5961 3.2 [ Upstream commit 282f23c6ee343126156dd41218b22ece96d747e3 ] Implement the RFC 5691 mitigation against Blind Reset attack using RST bit. Idea is to validate incoming RST sequence, to match RCV.NXT value, instead of previouly accepted window : (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) If sequence is in window but not an exact match, send a "challenge ACK", so that the other part can resend an RST with the appropriate sequence. Add a new sysctl, tcp_challenge_ack_limit, to limit number of challenge ACK sent per second. Add a new SNMP counter to count number of challenge acks sent. (netstat -s | grep TCPChallengeACK) Signed-off-by: Eric Dumazet Cc: Kiran Kumar Kella Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- Documentation/networking/ip-sysctl.txt | 5 +++++ include/linux/snmp.h | 1 + include/net/tcp.h | 1 + net/ipv4/proc.c | 1 + net/ipv4/sysctl_net_ipv4.c | 7 ++++++ net/ipv4/tcp_input.c | 31 +++++++++++++++++++++++++- 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 1619a8c8087..797715397f4 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -537,6 +537,11 @@ tcp_thin_dupack - BOOLEAN Documentation/networking/tcp-thin.txt Default: 0 +tcp_challenge_ack_limit - INTEGER + Limits number of Challenge ACK sent per second, as recommended + in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks) + Default: 100 + UDP variables: udp_mem - vector of 3 INTEGERs: min, pressure, max diff --git a/include/linux/snmp.h b/include/linux/snmp.h index 2e68f5ba038..594638ec5ac 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -234,6 +234,7 @@ enum LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */ LINUX_MIB_TCPRETRANSFAIL, /* TCPRetransFail */ LINUX_MIB_TCPRCVCOALESCE, /* TCPRcvCoalesce */ + LINUX_MIB_TCPCHALLENGEACK, /* TCPChallengeACK */ __LINUX_MIB_MAX }; diff --git a/include/net/tcp.h b/include/net/tcp.h index f75a04d752c..2757a115514 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -252,6 +252,7 @@ extern int sysctl_tcp_max_ssthresh; extern int sysctl_tcp_cookie_size; extern int sysctl_tcp_thin_linear_timeouts; extern int sysctl_tcp_thin_dupack; +extern int sysctl_tcp_challenge_ack_limit; extern atomic_long_t tcp_memory_allocated; extern struct percpu_counter tcp_sockets_allocated; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 8af0d44e4e2..d589468fd40 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -258,6 +258,7 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPReqQFullDrop", LINUX_MIB_TCPREQQFULLDROP), SNMP_MIB_ITEM("TCPRetransFail", LINUX_MIB_TCPRETRANSFAIL), SNMP_MIB_ITEM("TCPRcvCoalesce", LINUX_MIB_TCPRCVCOALESCE), + SNMP_MIB_ITEM("TCPChallengeACK", LINUX_MIB_TCPCHALLENGEACK), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 7a7724da9bf..bf7a604c695 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -590,6 +590,13 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "tcp_challenge_ack_limit", + .data = &sysctl_tcp_challenge_ack_limit, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, #ifdef CONFIG_NET_DMA { .procname = "tcp_dma_copybreak", diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3acebbd15ba..390541858e4 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -88,6 +88,9 @@ int sysctl_tcp_app_win __read_mostly = 31; int sysctl_tcp_adv_win_scale __read_mostly = 1; EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); +/* rfc5961 challenge ack rate limiting */ +int sysctl_tcp_challenge_ack_limit = 100; + int sysctl_tcp_stdurg __read_mostly; int sysctl_tcp_rfc1337 __read_mostly; int sysctl_tcp_max_orphans __read_mostly = NR_FILE; @@ -5265,6 +5268,23 @@ static int tcp_dma_try_early_copy(struct sock *sk, struct sk_buff *skb, } #endif /* CONFIG_NET_DMA */ +static void tcp_send_challenge_ack(struct sock *sk) +{ + /* unprotected vars, we dont care of overwrites */ + static u32 challenge_timestamp; + static unsigned int challenge_count; + u32 now = jiffies / HZ; + + if (now != challenge_timestamp) { + challenge_timestamp = now; + challenge_count = 0; + } + if (++challenge_count <= sysctl_tcp_challenge_ack_limit) { + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); + tcp_send_ack(sk); + } +} + /* Does PAWS and seqno based validation of an incoming segment, flags will * play significant role here. */ @@ -5301,7 +5321,16 @@ static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, /* Step 2: check RST bit */ if (th->rst) { - tcp_reset(sk); + /* RFC 5961 3.2 : + * If sequence number exactly matches RCV.NXT, then + * RESET the connection + * else + * Send a challenge ACK + */ + if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) + tcp_reset(sk); + else + tcp_send_challenge_ack(sk); goto discard; } From d21383fcbb535f90b429279852988d675ed22d67 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 17 Jul 2012 01:41:30 +0000 Subject: [PATCH 1787/2357] tcp: implement RFC 5961 4.2 [ Upstream commit 0c24604b68fc7810d429d6c3657b6f148270e528 ] Implement the RFC 5691 mitigation against Blind Reset attack using SYN bit. Section 4.2 of RFC 5961 advises to send a Challenge ACK and drop incoming packet, instead of resetting the session. Add a new SNMP counter to count number of challenge acks sent in response to SYN packets. (netstat -s | grep TCPSYNChallenge) Remove obsolete TCPAbortOnSyn, since we no longer abort a TCP session because of a SYN flag. Signed-off-by: Eric Dumazet Cc: Kiran Kumar Kella Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/snmp.h | 2 +- net/ipv4/proc.c | 2 +- net/ipv4/tcp_input.c | 32 +++++++++++++++----------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/include/linux/snmp.h b/include/linux/snmp.h index 594638ec5ac..a33f70fa1bf 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -208,7 +208,6 @@ enum LINUX_MIB_TCPDSACKOFOSENT, /* TCPDSACKOfoSent */ LINUX_MIB_TCPDSACKRECV, /* TCPDSACKRecv */ LINUX_MIB_TCPDSACKOFORECV, /* TCPDSACKOfoRecv */ - LINUX_MIB_TCPABORTONSYN, /* TCPAbortOnSyn */ LINUX_MIB_TCPABORTONDATA, /* TCPAbortOnData */ LINUX_MIB_TCPABORTONCLOSE, /* TCPAbortOnClose */ LINUX_MIB_TCPABORTONMEMORY, /* TCPAbortOnMemory */ @@ -235,6 +234,7 @@ enum LINUX_MIB_TCPRETRANSFAIL, /* TCPRetransFail */ LINUX_MIB_TCPRCVCOALESCE, /* TCPRcvCoalesce */ LINUX_MIB_TCPCHALLENGEACK, /* TCPChallengeACK */ + LINUX_MIB_TCPSYNCHALLENGE, /* TCPSYNChallenge */ __LINUX_MIB_MAX }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index d589468fd40..212897517b8 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -232,7 +232,6 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPDSACKOfoSent", LINUX_MIB_TCPDSACKOFOSENT), SNMP_MIB_ITEM("TCPDSACKRecv", LINUX_MIB_TCPDSACKRECV), SNMP_MIB_ITEM("TCPDSACKOfoRecv", LINUX_MIB_TCPDSACKOFORECV), - SNMP_MIB_ITEM("TCPAbortOnSyn", LINUX_MIB_TCPABORTONSYN), SNMP_MIB_ITEM("TCPAbortOnData", LINUX_MIB_TCPABORTONDATA), SNMP_MIB_ITEM("TCPAbortOnClose", LINUX_MIB_TCPABORTONCLOSE), SNMP_MIB_ITEM("TCPAbortOnMemory", LINUX_MIB_TCPABORTONMEMORY), @@ -259,6 +258,7 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPRetransFail", LINUX_MIB_TCPRETRANSFAIL), SNMP_MIB_ITEM("TCPRcvCoalesce", LINUX_MIB_TCPRCVCOALESCE), SNMP_MIB_ITEM("TCPChallengeACK", LINUX_MIB_TCPCHALLENGEACK), + SNMP_MIB_ITEM("TCPSYNChallenge", LINUX_MIB_TCPSYNCHALLENGE), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 390541858e4..2dc2e153132 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5288,8 +5288,8 @@ static void tcp_send_challenge_ack(struct sock *sk) /* Does PAWS and seqno based validation of an incoming segment, flags will * play significant role here. */ -static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, - const struct tcphdr *th, int syn_inerr) +static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, + const struct tcphdr *th, int syn_inerr) { const u8 *hash_location; struct tcp_sock *tp = tcp_sk(sk); @@ -5341,20 +5341,22 @@ static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, /* step 3: check security and precedence [ignored] */ - /* step 4: Check for a SYN in window. */ - if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { + /* step 4: Check for a SYN + * RFC 5691 4.2 : Send a challenge ack + */ + if (th->syn) { if (syn_inerr) TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN); - tcp_reset(sk); - return -1; + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNCHALLENGE); + tcp_send_challenge_ack(sk); + goto discard; } - return 1; + return true; discard: __kfree_skb(skb); - return 0; + return false; } /* @@ -5384,7 +5386,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, const struct tcphdr *th, unsigned int len) { struct tcp_sock *tp = tcp_sk(sk); - int res; /* * Header prediction. @@ -5564,9 +5565,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, * Standard slow path. */ - res = tcp_validate_incoming(sk, skb, th, 1); - if (res <= 0) - return -res; + if (!tcp_validate_incoming(sk, skb, th, 1)) + return 0; step5: if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) @@ -5876,7 +5876,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); int queued = 0; - int res; tp->rx_opt.saw_tstamp = 0; @@ -5931,9 +5930,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, return 0; } - res = tcp_validate_incoming(sk, skb, th, 0); - if (res <= 0) - return -res; + if (!tcp_validate_incoming(sk, skb, th, 0)) + return 0; /* step 5: check the ACK field */ if (th->ack) { From f451931e294c83d811783799f8a6c29929fc8e85 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 17 Jul 2012 12:29:30 +0000 Subject: [PATCH 1788/2357] tcp: refine SYN handling in tcp_validate_incoming [ Upstream commit e371589917011efe6ff8c7dfb4e9e81934ac5855 ] Followup of commit 0c24604b68fc (tcp: implement RFC 5961 4.2) As reported by Vijay Subramanian, we should send a challenge ACK instead of a dup ack if a SYN flag is set on a packet received out of window. This permits the ratelimiting to work as intended, and to increase correct SNMP counters. Suggested-by: Vijay Subramanian Signed-off-by: Eric Dumazet Acked-by: Vijay Subramanian Cc: Kiran Kumar Kella Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2dc2e153132..0070b9fafff 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5314,8 +5314,11 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, * an acknowledgment should be sent in reply (unless the RST * bit is set, if so drop the segment and return)". */ - if (!th->rst) + if (!th->rst) { + if (th->syn) + goto syn_challenge; tcp_send_dupack(sk, skb); + } goto discard; } @@ -5345,6 +5348,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, * RFC 5691 4.2 : Send a challenge ack */ if (th->syn) { +syn_challenge: if (syn_inerr) TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNCHALLENGE); From 29eac3795e2bb2a319f84438d45a4dbcc500cc6c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Nov 2012 05:37:18 +0000 Subject: [PATCH 1789/2357] tcp: tcp_replace_ts_recent() should not be called from tcp_validate_incoming() [ Upstream commit bd090dfc634ddd711a5fbd0cadc6e0ab4977bcaf ] We added support for RFC 5961 in latest kernels but TCP fails to perform exhaustive check of ACK sequence. We can update our view of peer tsval from a frame that is later discarded by tcp_ack() This makes timestamps enabled sessions vulnerable to injection of a high tsval : peers start an ACK storm, since the victim sends a dupack each time it receives an ACK from the other peer. As tcp_validate_incoming() is called before tcp_ack(), we should not peform tcp_replace_ts_recent() from it, and let callers do it at the right time. Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Yuchung Cheng Cc: Nandita Dukkipati Cc: H.K. Jerry Chu Cc: Romain Francoise Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0070b9fafff..ac8866c6244 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5337,11 +5337,6 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, goto discard; } - /* ts_recent update must be made after we are sure that the packet - * is in window. - */ - tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); - /* step 3: check security and precedence [ignored] */ /* step 4: Check for a SYN @@ -5576,6 +5571,11 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) goto discard; + /* ts_recent update must be made after we are sure that the packet + * is in window. + */ + tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); + tcp_rcv_rtt_measure_ts(sk, skb); /* Process urgent data. */ @@ -6046,6 +6046,11 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, } else goto discard; + /* ts_recent update must be made after we are sure that the packet + * is in window. + */ + tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); + /* step 6: check the URG bit */ tcp_urg(sk, skb, th); From 2ee4432e82437a7c051c254b065fbf5d4581e1a3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 21 Oct 2012 19:57:11 +0000 Subject: [PATCH 1790/2357] tcp: RFC 5961 5.2 Blind Data Injection Attack Mitigation [ Upstream commit 354e4aa391ed50a4d827ff6fc11e0667d0859b25 ] RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] All TCP stacks MAY implement the following mitigation. TCP stacks that implement this mitigation MUST add an additional input check to any incoming segment. The ACK value is considered acceptable only if it is in the range of ((SND.UNA - MAX.SND.WND) <= SEG.ACK <= SND.NXT). All incoming segments whose ACK value doesn't satisfy the above condition MUST be discarded and an ACK sent back. Move tcp_send_challenge_ack() before tcp_ack() to avoid a forward declaration. Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Yuchung Cheng Cc: Jerry Chu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ac8866c6244..0e0b6d0e9a6 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3687,6 +3687,24 @@ static int tcp_process_frto(struct sock *sk, int flag) return 0; } +/* RFC 5961 7 [ACK Throttling] */ +static void tcp_send_challenge_ack(struct sock *sk) +{ + /* unprotected vars, we dont care of overwrites */ + static u32 challenge_timestamp; + static unsigned int challenge_count; + u32 now = jiffies / HZ; + + if (now != challenge_timestamp) { + challenge_timestamp = now; + challenge_count = 0; + } + if (++challenge_count <= sysctl_tcp_challenge_ack_limit) { + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); + tcp_send_ack(sk); + } +} + /* This routine deals with incoming acks, but not outgoing ones. */ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) { @@ -3706,8 +3724,14 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) /* If the ack is older than previous acks * then we can probably ignore it. */ - if (before(ack, prior_snd_una)) + if (before(ack, prior_snd_una)) { + /* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */ + if (before(ack, prior_snd_una - tp->max_window)) { + tcp_send_challenge_ack(sk); + return -1; + } goto old_ack; + } /* If the ack includes data we haven't sent yet, discard * this segment (RFC793 Section 3.9). @@ -5268,23 +5292,6 @@ static int tcp_dma_try_early_copy(struct sock *sk, struct sk_buff *skb, } #endif /* CONFIG_NET_DMA */ -static void tcp_send_challenge_ack(struct sock *sk) -{ - /* unprotected vars, we dont care of overwrites */ - static u32 challenge_timestamp; - static unsigned int challenge_count; - u32 now = jiffies / HZ; - - if (now != challenge_timestamp) { - challenge_timestamp = now; - challenge_count = 0; - } - if (++challenge_count <= sysctl_tcp_challenge_ack_limit) { - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); - tcp_send_ack(sk); - } -} - /* Does PAWS and seqno based validation of an incoming segment, flags will * play significant role here. */ From 99574fa03e407cad20953d7cbfcb0056f02e811e Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 18 Sep 2012 19:18:35 +0100 Subject: [PATCH 1791/2357] ARM: mm: use pteval_t to represent page protection values commit 864aa04cd02979c2c755cb28b5f4fe56039171c0 upstream. When updating the page protection map after calculating the user_pgprot value, the base protection map is temporarily stored in an unsigned long type, causing truncation of the protection bits when LPAE is enabled. This effectively means that calls to mprotect() will corrupt the upper page attributes, clearing the XN bit unconditionally. This patch uses pteval_t to store the intermediate protection values, preserving the upper bits for 64-bit descriptors. Acked-by: Nicolas Pitre Acked-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- arch/arm/mm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 7d419193d49..5df549244d6 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -497,7 +497,7 @@ static void __init build_mem_type_table(void) #endif for (i = 0; i < 16; i++) { - unsigned long v = pgprot_val(protection_map[i]); + pteval_t v = pgprot_val(protection_map[i]); protection_map[i] = __pgprot(v | user_pgprot); } From ebd3b1a320baa264c7662363fa4b930634470a4b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 16 Dec 2012 00:25:57 +0000 Subject: [PATCH 1792/2357] ARM: missing ->mmap_sem around find_vma() in swp_emulate.c commit 7bf9b7bef881aac820bf1f2e9951a17b09bd7e04 upstream. find_vma() is *not* safe when somebody else is removing vmas. Not just the return value might get bogus just as you are getting it (this instance doesn't try to dereference the resulting vma), the search itself can get buggered in rather spectacular ways. IOW, ->mmap_sem really, really is not optional here. Signed-off-by: Al Viro Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/swp_emulate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index df745188f5d..ab1017bd166 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -109,10 +109,12 @@ static void set_segfault(struct pt_regs *regs, unsigned long addr) { siginfo_t info; + down_read(¤t->mm->mmap_sem); if (find_vma(current->mm, addr) == NULL) info.si_code = SEGV_MAPERR; else info.si_code = SEGV_ACCERR; + up_read(¤t->mm->mmap_sem); info.si_signo = SIGSEGV; info.si_errno = 0; From 042279bf26576ada65948ea45ab7ac86e0490c0a Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 19 Dec 2012 15:01:50 +0100 Subject: [PATCH 1793/2357] ARM: 7607/1: realview: fix private peripheral memory base for EB rev. B boards commit e6ee4b2b57a8e0d8e551031173de080b338d3969 upstream. Commit 34ae6c96a6a7 ("ARM: 7298/1: realview: fix mapping of MPCore private memory region") accidentally broke the definition for the base address of the private peripheral region on revision B Realview-EB boards. This patch uses the correct address for REALVIEW_EB11MP_PRIV_MEM_BASE. Acked-by: Marc Zyngier Tested-by: Florian Fainelli Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-realview/include/mach/board-eb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-realview/include/mach/board-eb.h b/arch/arm/mach-realview/include/mach/board-eb.h index 124bce6b4d7..a301e61a555 100644 --- a/arch/arm/mach-realview/include/mach/board-eb.h +++ b/arch/arm/mach-realview/include/mach/board-eb.h @@ -47,7 +47,7 @@ #define REALVIEW_EB_USB_BASE 0x4F000000 /* USB */ #ifdef CONFIG_REALVIEW_EB_ARM11MP_REVB -#define REALVIEW_EB11MP_PRIV_MEM_BASE 0x1F000000 +#define REALVIEW_EB11MP_PRIV_MEM_BASE 0x10100000 #define REALVIEW_EB11MP_L220_BASE 0x10102000 /* L220 registers */ #define REALVIEW_EB11MP_SYS_PLD_CTRL1 0xD8 /* Register offset for MPCore sysctl */ #else From fdbe6fecef94b6171de7a2ccfe543a694c9c41bc Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 11 Dec 2012 14:57:14 +0000 Subject: [PATCH 1794/2357] solos-pci: fix double-free of TX skb in DMA mode commit cae49ede00ec3d0cda290b03fee55b72b49efc11 upstream. We weren't clearing card->tx_skb[port] when processing the TX done interrupt. If there wasn't another skb ready to transmit immediately, this led to a double-free because we'd free it *again* next time we did have a packet to send. Signed-off-by: David Woodhouse Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/atm/solos-pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 98510931c81..1853a45c668 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -967,10 +967,11 @@ static uint32_t fpga_tx(struct solos_card *card) for (port = 0; tx_pending; tx_pending >>= 1, port++) { if (tx_pending & 1) { struct sk_buff *oldskb = card->tx_skb[port]; - if (oldskb) + if (oldskb) { pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr, oldskb->len, PCI_DMA_TODEVICE); - + card->tx_skb[port] = NULL; + } spin_lock(&card->tx_queue_lock); skb = skb_dequeue(&card->tx_queue[port]); if (!skb) From 7164ac211086207dc371e3b32165226e28e2dcfa Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sat, 1 Dec 2012 12:37:20 -0800 Subject: [PATCH 1795/2357] PCI: Reduce Ricoh 0xe822 SD card reader base clock frequency to 50MHz commit 812089e01b9f65f90fc8fc670d8cce72a0e01fbb upstream. Otherwise it fails like this on cards like the Transcend 16GB SDHC card: mmc0: new SDHC card at address b368 mmcblk0: mmc0:b368 SDC 15.0 GiB mmcblk0: error -110 sending status command, retrying mmcblk0: error -84 transferring data, sector 0, nr 8, cmd response 0x900, card status 0xb0 Tested on my Lenovo x200 laptop. [bhelgaas: changelog] Signed-off-by: Andy Lutomirski Signed-off-by: Bjorn Helgaas Acked-by: Chris Ball CC: Manoj Iyer Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 7 +++++-- include/linux/pci_ids.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4bf71028556..680dbfa1b61 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2708,7 +2708,7 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev) if (PCI_FUNC(dev->devfn)) return; /* - * RICOH 0xe823 SD/MMC card reader fails to recognize + * RICOH 0xe822 and 0xe823 SD/MMC card readers fail to recognize * certain types of SD/MMC cards. Lowering the SD base * clock frequency from 200Mhz to 50Mhz fixes this issue. * @@ -2719,7 +2719,8 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev) * 0xf9 - Key register for 0x150 * 0xfc - key register for 0xe1 */ - if (dev->device == PCI_DEVICE_ID_RICOH_R5CE823) { + if (dev->device == PCI_DEVICE_ID_RICOH_R5CE822 || + dev->device == PCI_DEVICE_ID_RICOH_R5CE823) { pci_write_config_byte(dev, 0xf9, 0xfc); pci_write_config_byte(dev, 0x150, 0x10); pci_write_config_byte(dev, 0xf9, 0x00); @@ -2746,6 +2747,8 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev) } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE822, ricoh_mmc_fixup_r5c832); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE822, ricoh_mmc_fixup_r5c832); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE823, ricoh_mmc_fixup_r5c832); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE823, ricoh_mmc_fixup_r5c832); #endif /*CONFIG_MMC_RICOH_MMC*/ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index bf7934f4268..d7dbf4ec89d 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1565,6 +1565,7 @@ #define PCI_DEVICE_ID_RICOH_RL5C476 0x0476 #define PCI_DEVICE_ID_RICOH_RL5C478 0x0478 #define PCI_DEVICE_ID_RICOH_R5C822 0x0822 +#define PCI_DEVICE_ID_RICOH_R5CE822 0xe822 #define PCI_DEVICE_ID_RICOH_R5CE823 0xe823 #define PCI_DEVICE_ID_RICOH_R5C832 0x0832 #define PCI_DEVICE_ID_RICOH_R5C843 0x0843 From 2145cea1e0be3262768fef384a87f426ecad06fe Mon Sep 17 00:00:00 2001 From: Marcos Chaparro Date: Tue, 6 Nov 2012 16:19:11 -0300 Subject: [PATCH 1796/2357] Bluetooth: ath3k: Add support for VAIO VPCEH [0489:e027] commit acd9454433e28c1a365d8b069813c35c1c3a8ac3 upstream. Added Atheros AR3011 internal bluetooth device found in Sony VAIO VPCEH to the devices list. Before this, the bluetooth module was identified as an Foxconn / Hai bluetooth device [0489:e027], now it claims to be an AtherosAR3011 Bluetooth [0cf3:3005]. T: Bus=01 Lev=02 Prnt=02 Port=04 Cnt=02 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e027 Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Marcos Chaparro Signed-off-by: Gustavo Padovan Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/ath3k.c | 1 + drivers/bluetooth/btusb.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 57fd867553d..1ae7039f067 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -66,6 +66,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x13d3, 0x3304) }, { USB_DEVICE(0x0930, 0x0215) }, { USB_DEVICE(0x0489, 0xE03D) }, + { USB_DEVICE(0x0489, 0xE027) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 29d31ff7331..27f9d9fc5a0 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -130,6 +130,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, From 7e2741804be03faf0eaba1df228e2ba5c07ecdd7 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 20 Nov 2012 23:25:54 -0200 Subject: [PATCH 1797/2357] Bluetooth: Add missing lock nesting notation commit dc2a0e20fbc85a71c63aa4330b496fda33f6bf80 upstream. This patch fixes the following report, it happens when accepting rfcomm connections: [ 228.165378] ============================================= [ 228.165378] [ INFO: possible recursive locking detected ] [ 228.165378] 3.7.0-rc1-00536-gc1d5dc4 #120 Tainted: G W [ 228.165378] --------------------------------------------- [ 228.165378] bluetoothd/1341 is trying to acquire lock: [ 228.165378] (sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM){+.+...}, at: [] bt_accept_dequeue+0xa0/0x180 [bluetooth] [ 228.165378] [ 228.165378] but task is already holding lock: [ 228.165378] (sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM){+.+...}, at: [] rfcomm_sock_accept+0x58/0x2d0 [rfcomm] [ 228.165378] [ 228.165378] other info that might help us debug this: [ 228.165378] Possible unsafe locking scenario: [ 228.165378] [ 228.165378] CPU0 [ 228.165378] ---- [ 228.165378] lock(sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM); [ 228.165378] lock(sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM); [ 228.165378] [ 228.165378] *** DEADLOCK *** [ 228.165378] [ 228.165378] May be due to missing lock nesting notation Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/rfcomm/sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 717c43ac0c7..8d1edd7207d 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -485,7 +485,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f long timeo; int err = 0; - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); if (sk->sk_type != SOCK_STREAM) { err = -EINVAL; @@ -522,7 +522,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f release_sock(sk); timeo = schedule_timeout(timeo); - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); } __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); From 1a0da46b46bc9b27414fcb1f1ad6f0eeee311f5e Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 21 Nov 2012 00:50:21 -0200 Subject: [PATCH 1798/2357] Bluetooth: cancel power_on work when unregistering the device commit b9b5ef188e5a2222cfc16ef62a4703080750b451 upstream. We need to cancel the hci_power_on work in order to avoid it run when we try to free the hdev. [ 1434.201149] ------------[ cut here ]------------ [ 1434.204998] WARNING: at lib/debugobjects.c:261 debug_print_object+0x8e/0xb0() [ 1434.208324] ODEBUG: free active (active state 0) object type: work_struct hint: hci _power_on+0x0/0x90 [ 1434.210386] Pid: 8564, comm: trinity-child25 Tainted: G W 3.7.0-rc5-next- 20121112-sasha-00018-g2f4ce0e #127 [ 1434.210760] Call Trace: [ 1434.210760] [] ? debug_print_object+0x8e/0xb0 [ 1434.210760] [] warn_slowpath_common+0x87/0xb0 [ 1434.210760] [] warn_slowpath_fmt+0x41/0x50 [ 1434.210760] [] debug_print_object+0x8e/0xb0 [ 1434.210760] [] ? hci_dev_open+0x310/0x310 [ 1434.210760] [] ? _raw_spin_unlock_irqrestore+0x55/0xa0 [ 1434.210760] [] __debug_check_no_obj_freed+0xa5/0x230 [ 1434.210760] [] ? bt_host_release+0x10/0x20 [ 1434.210760] [] debug_check_no_obj_freed+0x15/0x20 [ 1434.210760] [] kfree+0x227/0x330 [ 1434.210760] [] bt_host_release+0x10/0x20 [ 1434.210760] [] device_release+0x65/0xc0 [ 1434.210760] [] kobject_cleanup+0x145/0x190 [ 1434.210760] [] kobject_release+0xd/0x10 [ 1434.210760] [] kobject_put+0x4c/0x60 [ 1434.210760] [] put_device+0x12/0x20 [ 1434.210760] [] hci_free_dev+0x24/0x30 [ 1434.210760] [] vhci_release+0x31/0x60 [ 1434.210760] [] __fput+0x122/0x250 [ 1434.210760] [] ? rcu_user_exit+0x9d/0xd0 [ 1434.210760] [] ____fput+0x9/0x10 [ 1434.210760] [] task_work_run+0xb2/0xf0 [ 1434.210760] [] do_notify_resume+0x77/0xa0 [ 1434.210760] [] int_signal+0x12/0x17 [ 1434.210760] ---[ end trace a6d57fefbc8a8cc7 ]--- Reported-by: Sasha Levin Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0a30ec10d40..13b6c28df1f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1866,6 +1866,8 @@ void hci_unregister_dev(struct hci_dev *hdev) for (i = 0; i < NUM_REASSEMBLY; i++) kfree_skb(hdev->reassembly[i]); + cancel_work_sync(&hdev->power_on); + if (!test_bit(HCI_INIT, &hdev->flags) && !test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); From 0f7ac9c81bdb08763e7ca02317592281e22542bc Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 19 Dec 2012 23:39:48 -0800 Subject: [PATCH 1799/2357] lib: atomic64: Initialize locks statically to fix early users commit fcc16882ac4532aaa644bff444f0c5d6228ba71e upstream. The atomic64 library uses a handful of static spin locks to implement atomic 64-bit operations on architectures without support for atomic 64-bit instructions. Unfortunately, the spinlocks are initialized in a pure initcall and that is too late for the vfs namespace code which wants to use atomic64 operations before the initcall is run. This became a problem as of commit 8823c079ba71: "vfs: Add setns support for the mount namespace". This leads to BUG messages such as: BUG: spinlock bad magic on CPU#0, swapper/0/0 lock: atomic64_lock+0x240/0x400, .magic: 00000000, .owner: /-1, .owner_cpu: 0 do_raw_spin_lock+0x158/0x198 _raw_spin_lock_irqsave+0x4c/0x58 atomic64_add_return+0x30/0x5c alloc_mnt_ns.clone.14+0x44/0xac create_mnt_ns+0xc/0x54 mnt_init+0x120/0x1d4 vfs_caches_init+0xe0/0x10c start_kernel+0x29c/0x300 coming out early on during boot when spinlock debugging is enabled. Fix this by initializing the spinlocks statically at compile time. Reported-and-tested-by: Vaibhav Bedia Tested-by: Tony Lindgren Cc: Eric W. Biederman Signed-off-by: Stephen Boyd Signed-off-by: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- lib/atomic64.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/lib/atomic64.c b/lib/atomic64.c index 978537809d8..08a4f068e61 100644 --- a/lib/atomic64.c +++ b/lib/atomic64.c @@ -31,7 +31,11 @@ static union { raw_spinlock_t lock; char pad[L1_CACHE_BYTES]; -} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp; +} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp = { + [0 ... (NR_LOCKS - 1)] = { + .lock = __RAW_SPIN_LOCK_UNLOCKED(atomic64_lock.lock), + }, +}; static inline raw_spinlock_t *lock_addr(const atomic64_t *v) { @@ -173,14 +177,3 @@ int atomic64_add_unless(atomic64_t *v, long long a, long long u) return ret; } EXPORT_SYMBOL(atomic64_add_unless); - -static int init_atomic64_lock(void) -{ - int i; - - for (i = 0; i < NR_LOCKS; ++i) - raw_spin_lock_init(&atomic64_lock[i].lock); - return 0; -} - -pure_initcall(init_atomic64_lock); From 850fcad11762fae7b25c6a9d3fdb5ff4d7a39420 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 18 Dec 2012 14:21:19 -0800 Subject: [PATCH 1800/2357] CRIS: fix I/O macros commit c24bf9b4cc6a0f330ea355d73bfdf1dae7e63a05 upstream. The inb/outb macros for CRIS are broken from a number of points of view, missing () around parameters and they have an unprotected if statement in them. This was breaking the compile of IPMI on CRIS and thus I was being annoyed by build regressions, so I fixed them. Plus I don't think they would have worked at all, since the data values were missing "&" and the outsl had a "3" instead of a "4" for the size. From what I can tell, this stuff is not used at all, so this can't be any more broken than it was before, anyway. Signed-off-by: Corey Minyard Cc: Jesper Nilsson Cc: Mikael Starvik Acked-by: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/cris/include/asm/io.h | 39 ++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/arch/cris/include/asm/io.h b/arch/cris/include/asm/io.h index 32567bc2a42..ac12ae2b928 100644 --- a/arch/cris/include/asm/io.h +++ b/arch/cris/include/asm/io.h @@ -133,12 +133,39 @@ static inline void writel(unsigned int b, volatile void __iomem *addr) #define insb(port,addr,count) (cris_iops ? cris_iops->read_io(port,addr,1,count) : 0) #define insw(port,addr,count) (cris_iops ? cris_iops->read_io(port,addr,2,count) : 0) #define insl(port,addr,count) (cris_iops ? cris_iops->read_io(port,addr,4,count) : 0) -#define outb(data,port) if (cris_iops) cris_iops->write_io(port,(void*)(unsigned)data,1,1) -#define outw(data,port) if (cris_iops) cris_iops->write_io(port,(void*)(unsigned)data,2,1) -#define outl(data,port) if (cris_iops) cris_iops->write_io(port,(void*)(unsigned)data,4,1) -#define outsb(port,addr,count) if(cris_iops) cris_iops->write_io(port,(void*)addr,1,count) -#define outsw(port,addr,count) if(cris_iops) cris_iops->write_io(port,(void*)addr,2,count) -#define outsl(port,addr,count) if(cris_iops) cris_iops->write_io(port,(void*)addr,3,count) +static inline void outb(unsigned char data, unsigned int port) +{ + if (cris_iops) + cris_iops->write_io(port, (void *) &data, 1, 1); +} +static inline void outw(unsigned short data, unsigned int port) +{ + if (cris_iops) + cris_iops->write_io(port, (void *) &data, 2, 1); +} +static inline void outl(unsigned int data, unsigned int port) +{ + if (cris_iops) + cris_iops->write_io(port, (void *) &data, 4, 1); +} +static inline void outsb(unsigned int port, const void *addr, + unsigned long count) +{ + if (cris_iops) + cris_iops->write_io(port, (void *)addr, 1, count); +} +static inline void outsw(unsigned int port, const void *addr, + unsigned long count) +{ + if (cris_iops) + cris_iops->write_io(port, (void *)addr, 2, count); +} +static inline void outsl(unsigned int port, const void *addr, + unsigned long count) +{ + if (cris_iops) + cris_iops->write_io(port, (void *)addr, 4, count); +} /* * Convert a physical pointer to a virtual kernel pointer for /dev/mem From 8f4d9c2f748cab8ef5a30e9d9e5261679af3462f Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Fri, 4 Jan 2013 15:35:47 -0800 Subject: [PATCH 1801/2357] drivers/rtc/rtc-vt8500.c: correct handling of CR_24H bitfield commit 532db570e5181abc8f4f7bfa6c77c69ec2240198 upstream. Control register bitfield for 12H/24H mode is handled incorrectly. Setting CR_24H actually enables 12H mode. This patch renames the define and changes the initialization code to correctly set 24H mode. Signed-off-by: Tony Prisk Cc: Edgar Toernig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-vt8500.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 9e94fb147c2..5641ac5c65f 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -69,7 +69,7 @@ | ALARM_SEC_BIT) #define VT8500_RTC_CR_ENABLE (1 << 0) /* Enable RTC */ -#define VT8500_RTC_CR_24H (1 << 1) /* 24h time format */ +#define VT8500_RTC_CR_12H (1 << 1) /* 12h time format */ #define VT8500_RTC_CR_SM_ENABLE (1 << 2) /* Enable periodic irqs */ #define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */ #define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */ @@ -248,7 +248,7 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) } /* Enable RTC and set it to 24-hour mode */ - writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H, + writel(VT8500_RTC_CR_ENABLE, vt8500_rtc->regbase + VT8500_RTC_CR); vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev, From e0996e350216f727b0f0e6219e79c8da5b3d1416 Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Fri, 4 Jan 2013 15:35:48 -0800 Subject: [PATCH 1802/2357] drivers/rtc/rtc-vt8500.c: fix handling of data passed in struct rtc_time commit 2f90b68309683f2c5765a1b04ca23d71e51f1494 upstream. tm_mon is 0..11, whereas vt8500 expects 1..12 for the month field, causing invalid date errors for January, and causing the day field to roll over incorrectly. The century flag is only handled in vt8500_rtc_read_time, but not set in vt8500_rtc_set_time. This patch corrects the behaviour of the century flag. Signed-off-by: Edgar Toernig Signed-off-by: Tony Prisk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-vt8500.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 5641ac5c65f..44878da1f06 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -118,7 +118,7 @@ static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S); tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S); tm->tm_mday = bcd2bin(date & DATE_DAY_MASK); - tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S); + tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S) - 1; tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S) + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100); tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S; @@ -137,8 +137,9 @@ static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm) } writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S) - | (bin2bcd(tm->tm_mon) << DATE_MONTH_S) - | (bin2bcd(tm->tm_mday)), + | (bin2bcd(tm->tm_mon + 1) << DATE_MONTH_S) + | (bin2bcd(tm->tm_mday)) + | ((tm->tm_year >= 200) << DATE_CENTURY_S), vt8500_rtc->regbase + VT8500_RTC_DS); writel((bin2bcd(tm->tm_wday) << TIME_DOW_S) | (bin2bcd(tm->tm_hour) << TIME_HOUR_S) From b14d552774ed848ca1ca94d8adedcd743e3aa671 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Fri, 4 Jan 2013 15:35:12 -0800 Subject: [PATCH 1803/2357] mm: limit mmu_gather batching to fix soft lockups on !CONFIG_PREEMPT commit 53a59fc67f97374758e63a9c785891ec62324c81 upstream. Since commit e303297e6c3a ("mm: extended batches for generic mmu_gather") we are batching pages to be freed until either tlb_next_batch cannot allocate a new batch or we are done. This works just fine most of the time but we can get in troubles with non-preemptible kernel (CONFIG_PREEMPT_NONE or CONFIG_PREEMPT_VOLUNTARY) on large machines where too aggressive batching might lead to soft lockups during process exit path (exit_mmap) because there are no scheduling points down the free_pages_and_swap_cache path and so the freeing can take long enough to trigger the soft lockup. The lockup is harmless except when the system is setup to panic on softlockup which is not that unusual. The simplest way to work around this issue is to limit the maximum number of batches in a single mmu_gather. 10k of collected pages should be safe to prevent from soft lockups (we would have 2ms for one) even if they are all freed without an explicit scheduling point. This patch doesn't add any new explicit scheduling points because it relies on zap_pmd_range during page tables zapping which calls cond_resched per PMD. The following lockup has been reported for 3.0 kernel with a huge process (in order of hundreds gigs but I do know any more details). BUG: soft lockup - CPU#56 stuck for 22s! [kernel:31053] Modules linked in: af_packet nfs lockd fscache auth_rpcgss nfs_acl sunrpc mptctl mptbase autofs4 binfmt_misc dm_round_robin dm_multipath bonding cpufreq_conservative cpufreq_userspace cpufreq_powersave pcc_cpufreq mperf microcode fuse loop osst sg sd_mod crc_t10dif st qla2xxx scsi_transport_fc scsi_tgt netxen_nic i7core_edac iTCO_wdt joydev e1000e serio_raw pcspkr edac_core iTCO_vendor_support acpi_power_meter rtc_cmos hpwdt hpilo button container usbhid hid dm_mirror dm_region_hash dm_log linear uhci_hcd ehci_hcd usbcore usb_common scsi_dh_emc scsi_dh_alua scsi_dh_hp_sw scsi_dh_rdac scsi_dh dm_snapshot pcnet32 mii edd dm_mod raid1 ext3 mbcache jbd fan thermal processor thermal_sys hwmon cciss scsi_mod Supported: Yes CPU 56 Pid: 31053, comm: kernel Not tainted 3.0.31-0.9-default #1 HP ProLiant DL580 G7 RIP: 0010: _raw_spin_unlock_irqrestore+0x8/0x10 RSP: 0018:ffff883ec1037af0 EFLAGS: 00000206 RAX: 0000000000000e00 RBX: ffffea01a0817e28 RCX: ffff88803ffd9e80 RDX: 0000000000000200 RSI: 0000000000000206 RDI: 0000000000000206 RBP: 0000000000000002 R08: 0000000000000001 R09: ffff887ec724a400 R10: 0000000000000000 R11: dead000000200200 R12: ffffffff8144c26e R13: 0000000000000030 R14: 0000000000000297 R15: 000000000000000e FS: 00007ed834282700(0000) GS:ffff88c03f200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 000000000068b240 CR3: 0000003ec13c5000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process kernel (pid: 31053, threadinfo ffff883ec1036000, task ffff883ebd5d4100) Call Trace: release_pages+0xc5/0x260 free_pages_and_swap_cache+0x9d/0xc0 tlb_flush_mmu+0x5c/0x80 tlb_finish_mmu+0xe/0x50 exit_mmap+0xbd/0x120 mmput+0x49/0x120 exit_mm+0x122/0x160 do_exit+0x17a/0x430 do_group_exit+0x3d/0xb0 get_signal_to_deliver+0x247/0x480 do_signal+0x71/0x1b0 do_notify_resume+0x98/0xb0 int_signal+0x12/0x17 DWARF2 unwinder stuck at int_signal+0x12/0x17 Signed-off-by: Michal Hocko Cc: Mel Gorman Cc: Rik van Riel Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/asm-generic/tlb.h | 9 +++++++++ mm/memory.c | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index f96a5b58a97..979ed15724a 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h @@ -78,6 +78,14 @@ struct mmu_gather_batch { #define MAX_GATHER_BATCH \ ((PAGE_SIZE - sizeof(struct mmu_gather_batch)) / sizeof(void *)) +/* + * Limit the maximum number of mmu_gather batches to reduce a risk of soft + * lockups for non-preemptible kernels on huge machines when a lot of memory + * is zapped during unmapping. + * 10K pages freed at once should be safe even without a preemption point. + */ +#define MAX_GATHER_BATCH_COUNT (10000UL/MAX_GATHER_BATCH) + /* struct mmu_gather is an opaque type used by the mm code for passing around * any data needed by arch specific code for tlb_remove_page. */ @@ -94,6 +102,7 @@ struct mmu_gather { struct mmu_gather_batch *active; struct mmu_gather_batch local; struct page *__pages[MMU_GATHER_BUNDLE]; + unsigned int batch_count; }; #define HAVE_GENERIC_MMU_GATHER diff --git a/mm/memory.c b/mm/memory.c index 6105f475fa8..024b4afc41f 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -182,10 +182,14 @@ static int tlb_next_batch(struct mmu_gather *tlb) return 1; } + if (tlb->batch_count == MAX_GATHER_BATCH_COUNT) + return 0; + batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); if (!batch) return 0; + tlb->batch_count++; batch->next = NULL; batch->nr = 0; batch->max = MAX_GATHER_BATCH; @@ -212,6 +216,7 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm) tlb->local.nr = 0; tlb->local.max = ARRAY_SIZE(tlb->__pages); tlb->active = &tlb->local; + tlb->batch_count = 0; #ifdef CONFIG_HAVE_RCU_TABLE_FREE tlb->batch = NULL; From c0c7cf289528474c46ce4e851ed33c467c32720c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 2 Dec 2012 14:38:23 +0000 Subject: [PATCH 1804/2357] HID: Add Apple wireless keyboard 2011 ANSI to special driver list commit f9af7b9edccb87d4d80b58687ab63e58f3b64c4c upstream. Commit 0a97e1e9f9a6 ('HID: apple: Add Apple wireless keyboard 2011 ANSI PID') did not update the special driver list in hid-core.c, so hid-generic may still bind to this device. Reported-by: Ari Pollak References: http://bugs.debian.org/694546 Signed-off-by: Ben Hutchings Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 41d4437411c..1a92a271adb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1385,6 +1385,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, From 4ca05c86fde5ea8fd6b1929cb0e14b7993de9ba1 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 27 Nov 2012 08:52:34 +0100 Subject: [PATCH 1805/2357] can: Do not call dev_put if restart timer is running upon close commit ab48b03ec9ae1840a1e427e2375bd0d9d554b4ed upstream. If the restart timer is running due to BUS-OFF and the device is disconnected an dev_put will decrease the usage counter to -1 thus blocking the interface removal, resulting in the following dmesg lines repeating every 10s: can: notifier: receive list not found for dev can0 can: notifier: receive list not found for dev can0 can: notifier: receive list not found for dev can0 unregister_netdevice: waiting for can0 to become free. Usage count = -1 Signed-off-by: Alexander Stein Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index c5fe3a3db8c..e86f4c37f98 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -576,8 +576,7 @@ void close_candev(struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - if (del_timer_sync(&priv->restart_timer)) - dev_put(dev); + del_timer_sync(&priv->restart_timer); can_flush_echo_skb(dev); } EXPORT_SYMBOL_GPL(close_candev); From 0ba1cd8da86b7c4717852e786bacc7154b62d95c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 11 Jan 2013 09:09:13 -0800 Subject: [PATCH 1806/2357] Linux 3.4.25 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a3e12e687c6..0913881e456 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 24 +SUBLEVEL = 25 EXTRAVERSION = NAME = Saber-toothed Squirrel From 7e7791e17f932363b8194a68f531d11952861993 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 20 Nov 2012 10:02:06 +0900 Subject: [PATCH 1807/2357] regulator: wm831x: Set the new rather than old value for DVS VSEL commit 13ae633cf729b0ecb677b75b04886ff8fada8fad upstream. Reported-by: Guennadi Liakhovetski Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/regulator/wm831x-dcdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index ff810e787ea..97bb31d0bbe 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -330,7 +330,7 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, if (vsel > dcdc->dvs_vsel) { ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, - dcdc->dvs_vsel); + vsel); if (ret == 0) dcdc->dvs_vsel = vsel; else From 2686f897e696630f02455b5fa269dd90312f5c8d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 10 Dec 2012 16:40:41 +0100 Subject: [PATCH 1808/2357] ath5k: fix tx path skb leaks commit 596ab5ec3bf10a22be30d7cb1d903a4b83fd607c upstream. ieee80211_free_txskb() needs to be used instead of dev_kfree_skb_any for tx packets passed to the driver from mac80211 Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath5k/base.c | 4 ++-- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 0e643b016b3..c7d1437c770 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -843,7 +843,7 @@ ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf) return; dma_unmap_single(ah->dev, bf->skbaddr, bf->skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(bf->skb); + ieee80211_free_txskb(ah->hw, bf->skb); bf->skb = NULL; bf->skbaddr = 0; bf->desc->ds_data = 0; @@ -1570,7 +1570,7 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, return; drop_packet: - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } static void diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 5c532995541..5d1be4daa56 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -59,7 +59,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) u16 qnum = skb_get_queue_mapping(skb); if (WARN_ON(qnum >= ah->ah_capabilities.cap_queues.q_tx_num)) { - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); return; } From 8fcd6a440a3d01216bd6d88ce00e7353b1813ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 10 Dec 2012 07:53:56 +0100 Subject: [PATCH 1809/2357] bcma: mips: fix clearing device IRQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit cbbc0138efe1dcd5426b8fc5d87741f5057aee72 upstream. We were using wrong IRQ number so clearing wasn't working at all. Depending on a platform this could result in a one device having two interrupts assigned. On BCM4706 this resulted in all IRQs being broken. Signed-off-by: Rafał Miłecki Cc: Hauke Mehrtens Acked-by: Hauke Mehrtens Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/bcma/driver_mips.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index c3e9dff4224..041fddfd01a 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c @@ -115,7 +115,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) & ~(1 << irqflag)); else - bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0); + bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0); /* assign the new one */ if (irq == 0) { From 55800cd51f64300f66c9c0e6eda015e1d6626a57 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 11 Nov 2012 19:01:05 +0000 Subject: [PATCH 1810/2357] powerpc: Fix CONFIG_RELOCATABLE=y CONFIG_CRASH_DUMP=n build commit 11ee7e99f35ecb15f59b21da6a82d96d2cd3fcc8 upstream. If we build a kernel with CONFIG_RELOCATABLE=y CONFIG_CRASH_DUMP=n, the kernel fails when we run at a non zero offset. It turns out we were incorrectly wrapping some of the relocatable kernel code with CONFIG_CRASH_DUMP. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/head_64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 58bddee8e1e..9e07bd038dd 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -422,7 +422,7 @@ _STATIC(__after_prom_start) tovirt(r6,r6) /* on booke, we already run at PAGE_OFFSET */ #endif -#ifdef CONFIG_CRASH_DUMP +#ifdef CONFIG_RELOCATABLE /* * Check if the kernel has to be running as relocatable kernel based on the * variable __run_at_load, if it is set the kernel is treated as relocatable From 23c4e04a835e6b538efc431e7310af9e924d6978 Mon Sep 17 00:00:00 2001 From: Shan Hai Date: Thu, 8 Nov 2012 15:57:49 +0000 Subject: [PATCH 1811/2357] powerpc/vdso: Remove redundant locking in update_vsyscall_tz() commit ce73ec6db47af84d1466402781ae0872a9e7873c upstream. The locking in update_vsyscall_tz() is not only unnecessary because the vdso code copies the data unproteced in __kernel_gettimeofday() but also introduces a hard to reproduce race condition between update_vsyscall() and update_vsyscall_tz(), which causes user space process to loop forever in vdso code. The following patch removes the locking from update_vsyscall_tz(). Locking is not only unnecessary because the vdso code copies the data unprotected in __kernel_gettimeofday() but also erroneous because updating the tb_update_count is not atomic and introduces a hard to reproduce race condition between update_vsyscall() and update_vsyscall_tz(), which further causes user space process to loop forever in vdso code. The below scenario describes the race condition, x==0 Boot CPU other CPU proc_P: x==0 timer interrupt update_vsyscall x==1 x++;sync settimeofday update_vsyscall_tz x==2 x++;sync x==3 sync;x++ sync;x++ proc_P: x==3 (loops until x becomes even) Because the ++ operator would be implemented as three instructions and not atomic on powerpc. A similar change was made for x86 in commit 6c260d58634 ("x86: vdso: Remove bogus locking in update_vsyscall_tz") Signed-off-by: Shan Hai Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/time.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 730e69cb7e9..e7dba0b2a17 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -749,13 +749,8 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, void update_vsyscall_tz(void) { - /* Make userspace gettimeofday spin until we're done. */ - ++vdso_data->tb_update_count; - smp_mb(); vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; vdso_data->tz_dsttime = sys_tz.tz_dsttime; - smp_mb(); - ++vdso_data->tb_update_count; } static void __init clocksource_init(void) From 91534f7365982fa0c29192e73416dd798397310a Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 20 Dec 2012 03:44:28 +0000 Subject: [PATCH 1812/2357] powerpc: Add missing NULL terminator to avoid boot panic on PPC40x commit e6449c9b2d90c1bd9a5985bf05ddebfd1631cd6b upstream. The missing NULL terminator can cause a panic on PPC405 boards during boot: Linux/PowerPC load: console=ttyS0,115200 root=/dev/mtdblock1 rootfstype=squashfs,jffs2 noinitrd init=/etc/preinit Finalizing device tree... flat tree at 0x6a5160 bootconsole [udbg0] enabled Page fault in user mode with in_atomic() = 1 mm = (null) NIP = c0275f50 MSR = fffffffe Oops: Weird page fault, sig: 11 [#1] PowerPC 40x Platform Modules linked in: NIP: c0275f50 LR: c0275f60 CTR: c0280000 REGS: c0275eb0 TRAP: 636f7265 Not tainted (3.7.1) MSR: fffffffe CR: c06a6190 XER: 00000001 TASK = c02662a8[0] 'swapper' THREAD: c0274000 GPR00: c0275ec0 c000c658 c027c4bf 00000000 c0275ee0 c000a0ec c020a1a8 c020a1f0 GPR08: c020f631 c020f404 c025f078 c025f080 c0275f10 Call Trace: ---[ end trace 31fd0ba7d8756001 ]--- Kernel panic - not syncing: Attempted to kill the idle task! The panic happens since commit 9597abe00c1bab2aedce6b49866bf6d1e81c9eed (sections: fix section conflicts in arch/powerpc), however the root cause of this is that the NULL terminator were not added in commit a4f740cf33f7f6c164bbde3c0cdbcc77b0c4997c (of/flattree: Add of_flat_dt_match() helper function). Signed-off-by: Gabor Juhos Cc: Grant Likely Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/40x/ppc40x_simple.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c index 97612068fae..f0eee75ac05 100644 --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c @@ -57,7 +57,8 @@ static const char *board[] __initdata = { "amcc,makalu", "apm,klondike", "est,hotfoot", - "plathome,obs600" + "plathome,obs600", + NULL }; static int __init ppc40x_probe(void) From 9d4c74b86237ac64376b92c54cf7b471e7e75f76 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 29 Nov 2012 14:07:59 -0700 Subject: [PATCH 1813/2357] KVM: Fix user memslot overlap check commit 5419369ed6bd4cf711fdda5e52a5999b940413f5 upstream. Prior to memory slot sorting this loop compared all of the user memory slots for overlap with new entries. With memory slot sorting, we're just checking some number of entries in the array that may or may not be user slots. Instead, walk all the slots with kvm_for_each_memslot, which has the added benefit of terminating early when we hit the first empty slot, and skip comparison to private slots. Signed-off-by: Alex Williamson Signed-off-by: Marcelo Tosatti Signed-off-by: Greg Kroah-Hartman --- virt/kvm/kvm_main.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 9739b533ca2..71b9036644a 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -693,8 +693,7 @@ int __kvm_set_memory_region(struct kvm *kvm, int r; gfn_t base_gfn; unsigned long npages; - unsigned long i; - struct kvm_memory_slot *memslot; + struct kvm_memory_slot *memslot, *slot; struct kvm_memory_slot old, new; struct kvm_memslots *slots, *old_memslots; @@ -741,13 +740,11 @@ int __kvm_set_memory_region(struct kvm *kvm, /* Check for overlaps */ r = -EEXIST; - for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { - struct kvm_memory_slot *s = &kvm->memslots->memslots[i]; - - if (s == memslot || !s->npages) + kvm_for_each_memslot(slot, kvm->memslots) { + if (slot->id >= KVM_MEMORY_SLOTS || slot == memslot) continue; - if (!((base_gfn + npages <= s->base_gfn) || - (base_gfn >= s->base_gfn + s->npages))) + if (!((base_gfn + npages <= slot->base_gfn) || + (base_gfn >= slot->base_gfn + slot->npages))) goto out_free; } From 4305c46a628974e21e7939893476e4e735cd603c Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 30 Nov 2012 16:48:59 +0100 Subject: [PATCH 1814/2357] s390/cio: fix pgid reserved check commit d99e79ec5574fc556c988f613ed6175f6de66f4a upstream. The check to whom a device is reserved is done by checking the path state of the affected channel paths. If it turns out that one path is flagged as reserved by someone else the whole device is marked as such. However the meaning of the RESVD_ELSE bit is that the addressed device is reserved to a different pathgroup (and not reserved to a different LPAR). If we do this test on a path which is currently not a member of the pathgroup we could erroneously mark the device as reserved to someone else. To fix this collect the reserved state for all potential members of the pathgroup and only mark the device as reserved if all of those potential members have the RESVD_ELSE bit set. Acked-by: Peter Oberparleiter Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/device_pgid.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 07a4fd29f09..daa6b903aa9 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -234,7 +234,7 @@ static int pgid_cmp(struct pgid *p1, struct pgid *p2) * Determine pathgroup state from PGID data. */ static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, - int *mismatch, int *reserved, u8 *reset) + int *mismatch, u8 *reserved, u8 *reset) { struct pgid *pgid = &cdev->private->pgid[0]; struct pgid *first = NULL; @@ -248,7 +248,7 @@ static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, if ((cdev->private->pgid_valid_mask & lpm) == 0) continue; if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE) - *reserved = 1; + *reserved |= lpm; if (pgid_is_reset(pgid)) { *reset |= lpm; continue; @@ -316,14 +316,14 @@ static void snid_done(struct ccw_device *cdev, int rc) struct subchannel *sch = to_subchannel(cdev->dev.parent); struct pgid *pgid; int mismatch = 0; - int reserved = 0; + u8 reserved = 0; u8 reset = 0; u8 donepm; if (rc) goto out; pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset); - if (reserved) + if (reserved == cdev->private->pgid_valid_mask) rc = -EUSERS; else if (mismatch) rc = -EOPNOTSUPP; @@ -336,7 +336,7 @@ static void snid_done(struct ccw_device *cdev, int rc) } out: CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x " - "todo=%02x mism=%d rsvd=%d reset=%02x\n", id->ssid, + "todo=%02x mism=%d rsvd=%02x reset=%02x\n", id->ssid, id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm, cdev->private->pgid_todo_mask, mismatch, reserved, reset); switch (rc) { From b1ca420793e505d04f3a47a74651af7c037774b7 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Mon, 13 Aug 2012 20:52:24 +0800 Subject: [PATCH 1815/2357] MIPS: Fix poweroff failure when HOTPLUG_CPU configured. commit 8add1ecb81f541ef2fcb0b85a5470ad9ecfb4a84 upstream. When poweroff machine, kernel_power_off() call disable_nonboot_cpus(). And if we have HOTPLUG_CPU configured, disable_nonboot_cpus() is not an empty function but attempt to actually disable the nonboot cpus. Since system state is SYSTEM_POWER_OFF, play_dead() won't be called and thus disable_nonboot_cpus() hangs. Therefore, we make this patch to avoid poweroff failure. Signed-off-by: Huacai Chen Signed-off-by: Hongliang Tao Signed-off-by: Hua Yan Cc: Yong Zhang Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/4211/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/process.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index e9a5fd7277f..69b17a92004 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -72,9 +72,7 @@ void __noreturn cpu_idle(void) } } #ifdef CONFIG_HOTPLUG_CPU - if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map) && - (system_state == SYSTEM_RUNNING || - system_state == SYSTEM_BOOTING)) + if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map)) play_dead(); #endif rcu_idle_exit(); From c0b96525363543a1ba6a277546ebc26ad9a53aa1 Mon Sep 17 00:00:00 2001 From: Jason Liu Date: Fri, 11 Jan 2013 14:31:47 -0800 Subject: [PATCH 1816/2357] mm: compaction: fix echo 1 > compact_memory return error issue commit 7964c06d66c76507d8b6b662bffea770c29ef0ce upstream. when run the folloing command under shell, it will return error sh/$ echo 1 > /proc/sys/vm/compact_memory sh/$ sh: write error: Bad address After strace, I found the following log: ... write(1, "1\n", 2) = 3 write(1, "", 4294967295) = -1 EFAULT (Bad address) write(2, "echo: write error: Bad address\n", 31echo: write error: Bad address ) = 31 This tells system return 3(COMPACT_COMPLETE) after write data to compact_memory. The fix is to make the system just return 0 instead 3(COMPACT_COMPLETE) from sysctl_compaction_handler after compaction_nodes finished. Signed-off-by: Jason Liu Suggested-by: David Rientjes Acked-by: Mel Gorman Cc: Rik van Riel Cc: Minchan Kim Cc: KAMEZAWA Hiroyuki Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/compaction.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index 459b0ab6052..3c8d7fe4410 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -736,7 +736,7 @@ static int compact_node(int nid) } /* Compact all nodes in the system */ -static int compact_nodes(void) +static void compact_nodes(void) { int nid; @@ -745,8 +745,6 @@ static int compact_nodes(void) for_each_online_node(nid) compact_node(nid); - - return COMPACT_COMPLETE; } /* The written value is actually unused, all memory is compacted */ @@ -757,7 +755,7 @@ int sysctl_compaction_handler(struct ctl_table *table, int write, void __user *buffer, size_t *length, loff_t *ppos) { if (write) - return compact_nodes(); + compact_nodes(); return 0; } From ce19422296fb5fb5997d81e1b0043d771def7996 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Fri, 11 Jan 2013 14:31:51 -0800 Subject: [PATCH 1817/2357] mm: use aligned zone start for pfn_to_bitidx calculation commit c060f943d0929f3e429c5d9522290584f6281d6e upstream. The current calculation in pfn_to_bitidx assumes that (pfn - zone->zone_start_pfn) >> pageblock_order will return the same bit for all pfn in a pageblock. If zone_start_pfn is not aligned to pageblock_nr_pages, this may not always be correct. Consider the following with pageblock order = 10, zone start 2MB: pfn | pfn - zone start | (pfn - zone start) >> page block order ---------------------------------------------------------------- 0x26000 | 0x25e00 | 0x97 0x26100 | 0x25f00 | 0x97 0x26200 | 0x26000 | 0x98 0x26300 | 0x26100 | 0x98 This means that calling {get,set}_pageblock_migratetype on a single page will not set the migratetype for the full block. Fix this by rounding down zone_start_pfn when doing the bitidx calculation. For our use case, the effects of this bug were mostly tied to the fact that CMA allocations would either take a long time or fail to happen. Depending on the driver using CMA, this could result in anything from visual glitches to application failures. Signed-off-by: Laura Abbott Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 88a6d87041d..691b8ecdaa6 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5340,7 +5340,7 @@ static inline int pfn_to_bitidx(struct zone *zone, unsigned long pfn) pfn &= (PAGES_PER_SECTION-1); return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; #else - pfn = pfn - zone->zone_start_pfn; + pfn = pfn - round_down(zone->zone_start_pfn, pageblock_nr_pages); return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; #endif /* CONFIG_SPARSEMEM */ } From 867f263c648dee508e0cdd857a44f69a1bc2fad7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 6 Dec 2012 18:40:11 +0100 Subject: [PATCH 1818/2357] Revert "ath9k_hw: Update AR9003 high_power tx gain table" commit 9c170e068636deb3e3f96114034bb711675f0faa upstream. This reverts commit f74b9d365ddd33a375802b064f96a5d0e99af7c0. Turns out reverting commit a240dc7b3c7463bd60cf0a9b2a90f52f78aae0fd "ath9k_hw: Updated AR9003 tx gain table for 5GHz" was not enough to bring the tx power back to normal levels on devices like the Buffalo WZR-HP-G450H, this one needs to be reverted as well. This revert improves tx power by ~10 db on that device Signed-off-by: Felix Fietkau Cc: rmanohar@qca.qualcomm.com Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- .../wireless/ath/ath9k/ar9003_2p2_initvals.h | 172 +++++++++--------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 2b4b63318da..4e2a52c342d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -533,98 +533,98 @@ static const u32 ar9300_2p2_baseband_core[][2] = { static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, - {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, - {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, - {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, - {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402}, - {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, - {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, - {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, - {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, - {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, - {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, - {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, - {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, - {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, - {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861}, - {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81}, - {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83}, - {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84}, - {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3}, - {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5}, - {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9}, - {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb}, - {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, - {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, - {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, - {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, - {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, From 324b9bebea9e335c8588bf5eefdcca7d932508e6 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 9 Dec 2012 23:57:09 +0100 Subject: [PATCH 1819/2357] ath9k: ar9003: fix OTP register offsets for AR9340 commit b3cd8021379306c0be6932e4d3b4b01efc681769 upstream. Trying to access the OTP memory on the AR9340 causes a data bus error like this: Data bus error, epc == 86e84164, ra == 86e84164 Oops[#1]: Cpu 0 $ 0 : 00000000 00000061 deadc0de 00000000 $ 4 : b8115f18 00015f18 00000007 00000004 $ 8 : 00000001 7c7c3c7c 7c7c7c7c 7c7c7c7c $12 : 7c7c3c7c 001f0041 00000000 7c7c7c3c $16 : 86ee0000 00015f18 00000000 00000007 $20 : 00000004 00000064 00000004 86d71c44 $24 : 00000000 86e6ca00 $28 : 86d70000 86d71b20 86ece0c0 86e84164 Hi : 00000000 Lo : 00000064 epc : 86e84164 ath9k_hw_wait+0x58/0xb0 [ath9k_hw] Tainted: G O ra : 86e84164 ath9k_hw_wait+0x58/0xb0 [ath9k_hw] Status: 1100d403 KERNEL EXL IE Cause : 4080801c PrId : 0001974c (MIPS 74Kc) Modules linked in: ath9k(O+) ath9k_common(O) ath9k_hw(O) ath(O) ar934x_nfc mac80211(O) usbcore usb_common scsi_mod nls_base nand nand_ecc nand_ids crc_ccitt cfg80211(O) compat(O) arc4 aes_generic crypto_blkcipher cryptomgr aead crypto_hash crypto_algapi ledtrig_timer ledtrig_default_on leds_gpio Process insmod (pid: 459, threadinfo=86d70000, task=87942140, tls=779ac440) Stack : 802fb500 000200da 804db150 804e0000 87816130 86ee0000 00010000 86d71b88 86d71bc0 00000004 00000003 86e9fcd0 80305300 0002c0d0 86e74c50 800b4c20 000003e8 00000001 00000000 86ee0000 000003ff 86e9fd64 80305300 80123938 fffffffc 00000004 000058bc 00000000 86ea0000 86ee0000 000001ff 878d6000 99999999 86e9fdc0 86ee0fcc 86e9e664 0000c0d0 86ee0000 0000700000007000 ... Call Trace: [<86e84164>] ath9k_hw_wait+0x58/0xb0 [ath9k_hw] [<86e9fcd0>] ath9k_hw_setup_statusring+0x16b8/0x1c7c [ath9k_hw] Code: 0000a812 0040f809 00000000 <00531024> 1054000b 24020001 0c05b5dc 2404000a 26520001 The cause of the error is that the OTP register offsets are different on the AR9340 than the actually used values. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index bb223fe8281..582ebc4bc5e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -69,13 +69,13 @@ #define AR9300_BASE_ADDR 0x3ff #define AR9300_BASE_ADDR_512 0x1ff -#define AR9300_OTP_BASE 0x14000 -#define AR9300_OTP_STATUS 0x15f18 +#define AR9300_OTP_BASE (AR_SREV_9340(ah) ? 0x30000 : 0x14000) +#define AR9300_OTP_STATUS (AR_SREV_9340(ah) ? 0x30018 : 0x15f18) #define AR9300_OTP_STATUS_TYPE 0x7 #define AR9300_OTP_STATUS_VALID 0x4 #define AR9300_OTP_STATUS_ACCESS_BUSY 0x2 #define AR9300_OTP_STATUS_SM_BUSY 0x1 -#define AR9300_OTP_READ_DATA 0x15f1c +#define AR9300_OTP_READ_DATA (AR_SREV_9340(ah) ? 0x3001c : 0x15f1c) enum targetPowerHTRates { HT_TARGET_RATE_0_8_16, From 5004c75870b05d2ffd5974d1fd681a5a1b0d9f4c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 10 Dec 2012 14:03:17 +0100 Subject: [PATCH 1820/2357] ath9k_hw: Fix signal strength / channel noise reporting commit b7c0c238898d200e80487516e2b67aba2a522cc0 upstream. While AR_PHY_CCA_NOM_VAL_* does contain the expected internal noise floor for a chip measured in clean air, it refers to the lowest expected reading. Depending on the frequency, this measurement can vary by about 6db, thus causing a higher reported channel noise and signal strength. Factor in the 6db offset when converting internal noisefloor to channel noise. This patch makes the reported values more accurate for all chips without affecting NF calibration behavior. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/calib.c | 1 + drivers/net/wireless/ath/ath9k/calib.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index e5cceb07757..bbd249df23e 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -69,6 +69,7 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) if (chan && chan->noisefloor) { s8 delta = chan->noisefloor - + ATH9K_NF_CAL_NOISE_THRESH - ath9k_hw_get_default_nf(ah, chan); if (delta > 0) noise += delta; diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 3b33996d97d..1f2e01a96d2 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -21,6 +21,9 @@ #define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 +/* Internal noise floor can vary by about 6db depending on the frequency */ +#define ATH9K_NF_CAL_NOISE_THRESH 6 + #define NUM_NF_READINGS 6 #define ATH9K_NF_CAL_HIST_MAX 5 From 2d2b65eeb598b687403aa0f06d4d7da97661958a Mon Sep 17 00:00:00 2001 From: Stephan Gatzka Date: Wed, 28 Nov 2012 20:04:32 +0100 Subject: [PATCH 1821/2357] firewire: net: Fix handling of fragmented multicast/broadcast packets. commit 9d2373420900a39f5212a3b289331aa3535b1000 upstream. This patch fixes both the transmit and receive portion of sending fragmented mutlicast and broadcast packets. The transmit section was broken because the offset for INTFRAG and LASTFRAG packets were just miscalculated by IEEE1394_GASP_HDR_SIZE (which was reserved with skb_push() in fwnet_send_packet). The receive section was broken because in fwnet_incoming_packet is a call to fwnet_peer_find_by_node_id(). Called with generation == -1 it will not find a peer and the partial datagrams are associated to a peer. [Stefan R: The fix to use context->card->generation is not perfect. It relies on the IR tasklet which processes packets from the prior bus generation to run before the self-ID-complete worklet which sets the current card generation. Alas, there is no simple way of a race-free implementation. Let's do it this way for now.] Signed-off-by: Stephan Gatzka Signed-off-by: Stefan Richter Signed-off-by: Greg Kroah-Hartman --- drivers/firewire/net.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 08c674957af..638e1f71284 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -861,8 +861,8 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, if (specifier_id == IANA_SPECIFIER_ID && ver == RFC2734_SW_VERSION) { buf_ptr += 2; length -= IEEE1394_GASP_HDR_SIZE; - fwnet_incoming_packet(dev, buf_ptr, length, - source_node_id, -1, true); + fwnet_incoming_packet(dev, buf_ptr, length, source_node_id, + context->card->generation, true); } packet.payload_length = dev->rcv_buffer_size; @@ -958,7 +958,12 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) break; } - skb_pull(skb, ptask->max_payload); + if (ptask->dest_node == IEEE1394_ALL_NODES) { + skb_pull(skb, + ptask->max_payload + IEEE1394_GASP_HDR_SIZE); + } else { + skb_pull(skb, ptask->max_payload); + } if (ptask->outstanding_pkts > 1) { fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG, dg_size, fg_off, datagram_label); @@ -1062,7 +1067,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) smp_rmb(); node_id = dev->card->node_id; - p = skb_push(ptask->skb, 8); + p = skb_push(ptask->skb, IEEE1394_GASP_HDR_SIZE); put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p); put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24 | RFC2734_SW_VERSION, &p[4]); From a565623f44aeafafc74a5763f765d5c8224bc4ad Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Dec 2012 18:30:51 +0100 Subject: [PATCH 1822/2357] ASoC: sigmadsp: Fix endianness conversion issue commit a3adb1432d7a3ad86bb17a1638e44414537e4118 upstream. The 'addr' field of the sigma_action struct is stored as big endian in the firmware file. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/sigmadsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 5be42bf5699..4068f249123 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -225,7 +225,7 @@ EXPORT_SYMBOL(process_sigma_firmware); static int sigma_action_write_regmap(void *control_data, const struct sigma_action *sa, size_t len) { - return regmap_raw_write(control_data, le16_to_cpu(sa->addr), + return regmap_raw_write(control_data, be16_to_cpu(sa->addr), sa->payload, len - 2); } From 8f735b2774f5e200a65c5fe9143fb431023a5267 Mon Sep 17 00:00:00 2001 From: Jianpeng Ma Date: Sat, 4 Aug 2012 10:34:14 +0800 Subject: [PATCH 1823/2357] SCSI: mvsas: Fix oops when ata commond timeout. commit 95ab000388974d8ffef8257306b4be6e8778b768 upstream. Kernel message follows: [ 511.712011] sd 11:0:0:0: [sdf] command ffff8800a4e81400 timed out [ 511.712022] sas: Enter sas_scsi_recover_host busy: 1 failed: 1 [ 511.712024] sas: trying to find task 0xffff8800a4d24c80 [ 511.712026] sas: sas_scsi_find_task: aborting task 0xffff8800a4d24c80 [ 511.712029] drivers/scsi/mvsas/mv_sas.c 1631:mvs_abort_task() mvi=ffff8800b5300000 task=ffff8800a4d24c80 slot=ffff8800b5325038 slot_idx=x0 [ 511.712035] BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 [ 511.712040] IP: [] _raw_spin_lock_irqsave+0xc/0x30 [ 511.712047] PGD 0 [ 511.712049] Oops: 0002 [#1] SMP [ 511.712052] Modules linked in: mvsas libsas scsi_transport_sas raid456 async_pq async_xor xor async_memcpy async_raid6_recov raid6_pq async_tx [last unloaded: mvsas] [ 511.712062] CPU 3 [ 511.712066] Pid: 7322, comm: scsi_eh_11 Not tainted 3.5.0+ #106 To Be Filled By O.E.M. To Be Filled By O.E.M./To be filled by O.E.M. [ 511.712068] RIP: 0010:[] [] _raw_spin_lock_irqsave+0xc/0x30 [ 511.712073] RSP: 0018:ffff880098d3bcb0 EFLAGS: 00010086 [ 511.712074] RAX: 0000000000000286 RBX: 0000000000000058 RCX: 00000000000000c3 [ 511.712076] RDX: 0000000000000100 RSI: 0000000000000046 RDI: 0000000000000058 [ 511.712078] RBP: ffff880098d3bcb0 R08: 000000000000000a R09: 0000000000000000 [ 511.712080] R10: 00000000000004e8 R11: 00000000000004e7 R12: ffff8800a4d24c80 [ 511.712082] R13: 0000000000000050 R14: ffff8800b5325038 R15: ffff8800a4eafe00 [ 511.712084] FS: 0000000000000000(0000) GS:ffff8800bdb80000(0000) knlGS:0000000000000000 [ 511.712086] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 511.712088] CR2: 0000000000000058 CR3: 00000000a4ce6000 CR4: 00000000000407e0 [ 511.712090] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 511.712091] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 511.712093] Process scsi_eh_11 (pid: 7322, threadinfo ffff880098d3a000, task ffff8800a61dde40) [ 511.712095] Stack: [ 511.712096] ffff880098d3bce0 ffffffff81060683 ffff880000000000 0000000000000000 [ 511.712099] ffff8800a4d24c80 ffff8800b5300000 ffff880098d3bcf0 ffffffffa0076a88 [ 511.712102] ffff880098d3bd50 ffffffffa0079bb5 ffff880000000000 ffff880000000018 [ 511.712106] Call Trace: [ 511.712110] [] complete+0x23/0x60 [ 511.712115] [] mvs_tmf_timedout+0x18/0x20 [mvsas] [ 511.712119] [] mvs_slot_complete+0x765/0x7d0 [mvsas] [ 511.712125] [] sas_scsi_recover_host+0x55d/0xdb0 [libsas] [ 511.712128] [] ? idle_balance+0xe0/0x130 [ 511.712133] [] scsi_error_handler+0xcc/0x470 [ 511.712136] [] ? __schedule+0x370/0x730 [ 511.712139] [] ? __wake_up_common+0x58/0x90 [ 511.712142] [] ? scsi_eh_get_sense+0x110/0x110 [ 511.712146] [] kthread+0x8e/0xa0 [ 511.712150] [] kernel_thread_helper+0x4/0x10 [ 511.712153] [] ? flush_kthread_work+0x120/0x120 [ 511.712156] [] ? gs_change+0xb/0xb [ 511.712157] Code: 8a 00 01 00 00 89 d0 f0 66 0f b1 0f 66 39 d0 0f 94 c0 0f b6 c0 5d c3 0f 1f 84 00 00 00 00 00 55 48 89 e5 9c 58 fa ba 00 01 00 00 66 0f c1 17 0f b6 ce 38 d1 74 11 0f 1f 84 00 00 00 00 00 f3 [ 511.712191] RIP [] _raw_spin_lock_irqsave+0xc/0x30 [ 511.712194] RSP [ 511.712196] CR2: 0000000000000058 [ 511.712198] ---[ end trace a781c7b1e65db92c ]--- Signed-off-by: Jianpeng Ma Signed-off-by: James Bottomley Cc: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mvsas/mv_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 3006ec9aa69..dbb8edfc8ba 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1629,7 +1629,7 @@ int mvs_abort_task(struct sas_task *task) mv_dprintk("mvs_abort_task() mvi=%p task=%p " "slot=%p slot_idx=x%x\n", mvi, task, slot, slot_idx); - mvs_tmf_timedout((unsigned long)task); + task->task_state_flags |= SAS_TASK_STATE_ABORTED; mvs_slot_task_free(mvi, task, slot, slot_idx); rc = TMF_RESP_FUNC_COMPLETE; goto out; From 3814b31a89b1fbb5c6f92c11c8371a2e4c97d2f1 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Fri, 16 Nov 2012 14:40:03 -0500 Subject: [PATCH 1824/2357] SCSI: mvsas: fix undefined bit shift commit beecadea1b8d67f591b13f7099559f32f3fd601d upstream. The macro bit(n) is defined as ((u32)1 << n), and thus it doesn't work with n >= 32, such as in mvs_94xx_assign_reg_set(): if (i >= 32) { mvi->sata_reg_set |= bit(i); ... } The shift ((u32)1 << n) with n >= 32 also leads to undefined behavior. The result varies depending on the architecture. This patch changes bit(n) to do a 64-bit shift. It also simplifies mv_ffc64() using __ffs64(), since invoking ffz() with ~0 is undefined. Signed-off-by: Xi Wang Acked-by: Xiangliang Yu Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mvsas/mv_94xx.h | 14 ++------------ drivers/scsi/mvsas/mv_sas.h | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h index 8f7eb4f2114..487aa6f9741 100644 --- a/drivers/scsi/mvsas/mv_94xx.h +++ b/drivers/scsi/mvsas/mv_94xx.h @@ -258,21 +258,11 @@ enum sas_sata_phy_regs { #define SPI_ADDR_VLD_94XX (1U << 1) #define SPI_CTRL_SpiStart_94XX (1U << 0) -#define mv_ffc(x) ffz(x) - static inline int mv_ffc64(u64 v) { - int i; - i = mv_ffc((u32)v); - if (i >= 0) - return i; - i = mv_ffc((u32)(v>>32)); - - if (i != 0) - return 32 + i; - - return -1; + u64 x = ~v; + return x ? __ffs64(x) : -1; } #define r_reg_set_enable(i) \ diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index c04a4f5b597..da249553858 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -69,7 +69,7 @@ extern struct kmem_cache *mvs_task_list_cache; #define DEV_IS_EXPANDER(type) \ ((type == EDGE_DEV) || (type == FANOUT_DEV)) -#define bit(n) ((u32)1 << n) +#define bit(n) ((u64)1 << n) #define for_each_phy(__lseq_mask, __mc, __lseq) \ for ((__mc) = (__lseq_mask), (__lseq) = 0; \ From e21c4b90fb7881357c81a5f68d676747b7dddbb1 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 15 Nov 2012 15:51:46 -0500 Subject: [PATCH 1825/2357] SCSI: prevent stack buffer overflow in host_reset commit 072f19b4bea31cdd482d79f805413f2f9ac9e233 upstream. store_host_reset() has tried to re-invent the wheel to compare sysfs strings. Unfortunately it did so poorly and never bothered to check the input from userspace before overwriting stack with it, so something simple as: echo "WoopsieWoopsie" > /sys/devices/pseudo_0/adapter0/host0/scsi_host/host0/host_reset would result in: [ 316.310101] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffffff81f5bac7 [ 316.310101] [ 316.320051] Pid: 6655, comm: sh Tainted: G W 3.7.0-rc5-next-20121114-sasha-00016-g5c9d68d-dirty #129 [ 316.320051] Call Trace: [ 316.340058] pps pps0: PPS event at 1352918752.620355751 [ 316.340062] pps pps0: capture assert seq #303 [ 316.320051] [] panic+0xcd/0x1f4 [ 316.320051] [] ? store_host_reset+0xd7/0x100 [ 316.320051] [] __stack_chk_fail+0x16/0x20 [ 316.320051] [] store_host_reset+0xd7/0x100 [ 316.320051] [] dev_attr_store+0x13/0x30 [ 316.320051] [] sysfs_write_file+0x101/0x170 [ 316.320051] [] vfs_write+0xb8/0x180 [ 316.320051] [] sys_write+0x50/0xa0 [ 316.320051] [] tracesys+0xe1/0xe6 Fix this by uninventing whatever was going on there and just use sysfs_streq. Bug introduced by 29443691 ("[SCSI] scsi: Added support for adapter and firmware reset"). [jejb: added necessary const to prevent compile warnings] Signed-off-by: Sasha Levin Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_sysfs.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 08d48a3b767..72ca515a430 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -246,11 +246,11 @@ show_shost_active_mode(struct device *dev, static DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL); -static int check_reset_type(char *str) +static int check_reset_type(const char *str) { - if (strncmp(str, "adapter", 10) == 0) + if (sysfs_streq(str, "adapter")) return SCSI_ADAPTER_RESET; - else if (strncmp(str, "firmware", 10) == 0) + else if (sysfs_streq(str, "firmware")) return SCSI_FIRMWARE_RESET; else return 0; @@ -263,12 +263,9 @@ store_host_reset(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct scsi_host_template *sht = shost->hostt; int ret = -EINVAL; - char str[10]; int type; - sscanf(buf, "%s", str); - type = check_reset_type(str); - + type = check_reset_type(buf); if (!type) goto exit_store_host_reset; From 2e4be18823cb686f1316ac856ce1fbc651dd28e1 Mon Sep 17 00:00:00 2001 From: David Jeffery Date: Wed, 21 Nov 2012 02:39:54 -0500 Subject: [PATCH 1826/2357] SCSI: qla2xxx: Test and clear FCPORT_UPDATE_NEEDED atomically. commit a394aac88506159e047630fc90dc2242568382d8 upstream. When the qla2xxx driver loses access to multiple, remote ports, there is a race condition which can occur which will keep the request stuck on a scsi request queue indefinitely. This bad state occurred do to a race condition with how the FCPORT_UPDATE_NEEDED bit is set in qla2x00_schedule_rport_del(), and how it is cleared in qla2x00_do_dpc(). The problem port has its drport pointer set, but it has never been processed by the driver to inform the fc transport that the port has been lost. qla2x00_schedule_rport_del() sets drport, and then sets the FCPORT_UPDATE_NEEDED bit. In qla2x00_do_dpc(), the port lists are walked and any drport pointer is handled and the fc transport informed of the port loss, then the FCPORT_UPDATE_NEEDED bit is cleared. This leaves a race where the dpc thread is processing one port removal, another port removal is marked with a call to qla2x00_schedule_rport_del(), and the dpc thread clears the bit for both removals, even though only the first removal was actually handled. Until another event occurs to set FCPORT_UPDATE_NEEDED, the later port removal is never finished and qla2xxx stays in a bad state which causes requests to become stuck on request queues. This patch updates the driver to test and clear FCPORT_UPDATE_NEEDED atomically. This ensures the port state changes are processed and not lost. Signed-off-by: David Jeffery Signed-off-by: Chad Dupuis Signed-off-by: Saurav Kashyap Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 7db803377c6..da1315ede00 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3735,9 +3735,9 @@ qla2x00_do_dpc(void *data) "ISP abort end.\n"); } - if (test_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags)) { + if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, + &base_vha->dpc_flags)) { qla2x00_update_fcports(base_vha); - clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); } if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) { From 370caef9e8e2800a759d9c29e2c4d41375bdad62 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 23 Nov 2012 12:07:39 +0800 Subject: [PATCH 1827/2357] iscsit: use GFP_ATOMIC under spin lock commit 3c989d7603872bf878840f7ce3ea49b73bea4c6c upstream. The function iscsit_build_conn_drop_async_message() is called from iscsit_close_connection() with spin lock 'sess->conn_lock' held, so we should use GFP_ATOMIC instead of GFP_KERNEL. Signed-off-by: Wei Yongjun Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/iscsi/iscsi_target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index ad202b342bf..486c5dd4501 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -2359,7 +2359,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn) if (!conn_p) return; - cmd = iscsit_allocate_cmd(conn_p, GFP_KERNEL); + cmd = iscsit_allocate_cmd(conn_p, GFP_ATOMIC); if (!cmd) { iscsit_dec_conn_usage_count(conn_p); return; From 4b693aca7e346fcff0ea5c1548e7b5545bfbfd04 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Sun, 16 Sep 2012 20:53:43 +0200 Subject: [PATCH 1828/2357] sata_promise: fix hardreset lockdep error commit 3100d49d3cd236443faae9d81137c81b22d36003 upstream. sata_promise's pdc_hard_reset_port() needs to serialize because it flips a port-specific bit in controller register that's shared by all ports. The code takes the ata host lock for this, but that's broken because an interrupt may arrive on our irq during the hard reset sequence, and that too will take the ata host lock. With lockdep enabled a big nasty warning is seen. Fixed by adding private state to the ata host structure, containing a second lock used only for serializing the hard reset sequences. This eliminated the lockdep warnings both on my test rig and on the original reporter's machine. Signed-off-by: Mikael Pettersson Tested-by: Adko Branil Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/sata_promise.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 000fcc99e01..ef6e328784e 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -147,6 +147,10 @@ struct pdc_port_priv { dma_addr_t pkt_dma; }; +struct pdc_host_priv { + spinlock_t hard_reset_lock; +}; + static int pdc_sata_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int pdc_sata_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); @@ -801,9 +805,10 @@ static void pdc_hard_reset_port(struct ata_port *ap) void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR]; void __iomem *pcictl_b1_mmio = host_mmio + PDC_PCI_CTL + 1; unsigned int ata_no = pdc_ata_port_to_ata_no(ap); + struct pdc_host_priv *hpriv = ap->host->private_data; u8 tmp; - spin_lock(&ap->host->lock); + spin_lock(&hpriv->hard_reset_lock); tmp = readb(pcictl_b1_mmio); tmp &= ~(0x10 << ata_no); @@ -814,7 +819,7 @@ static void pdc_hard_reset_port(struct ata_port *ap) writeb(tmp, pcictl_b1_mmio); readb(pcictl_b1_mmio); /* flush */ - spin_unlock(&ap->host->lock); + spin_unlock(&hpriv->hard_reset_lock); } static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class, @@ -1182,6 +1187,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev, const struct ata_port_info *pi = &pdc_port_info[ent->driver_data]; const struct ata_port_info *ppi[PDC_MAX_PORTS]; struct ata_host *host; + struct pdc_host_priv *hpriv; void __iomem *host_mmio; int n_ports, i, rc; int is_sataii_tx4; @@ -1218,6 +1224,11 @@ static int pdc_ata_init_one(struct pci_dev *pdev, dev_err(&pdev->dev, "failed to allocate host\n"); return -ENOMEM; } + hpriv = devm_kzalloc(&pdev->dev, sizeof *hpriv, GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + spin_lock_init(&hpriv->hard_reset_lock); + host->private_data = hpriv; host->iomap = pcim_iomap_table(pdev); is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags); From d8876cb61d0bd9002cedcd720ce13ad7f2e32cf7 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Mon, 3 Dec 2012 11:35:02 +0800 Subject: [PATCH 1829/2357] libata: set dma_mode to 0xff in reset commit 5416912af75de9cba5d1c75b99a7888b0bbbd2fb upstream. ata_device->dma_mode's initial value is zero, which is not a valid dma mode, but ata_dma_enabled will return true for this value. This patch sets dma_mode to 0xff in reset function, so that ata_dma_enabled will not return true for this case, or it will cause problem for pata_acpi. The corrsponding bugzilla page is at: https://bugzilla.kernel.org/show_bug.cgi?id=49151 Reported-by: Phillip Wood Signed-off-by: Aaron Lu Tested-by: Szymon Janc Tested-by: Dutra Julio Acked-by: Alan Cox Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 1 + drivers/ata/libata-eh.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cf4837f3ded..4b4caa3db6c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2536,6 +2536,7 @@ int ata_bus_probe(struct ata_port *ap) * bus as we may be talking too fast. */ dev->pio_mode = XFER_PIO_0; + dev->dma_mode = 0xff; /* If the controller has a pio mode setup function * then use it to set the chipset to rights. Don't diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index d1fbd59ead1..e47c224d7c2 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2600,6 +2600,7 @@ int ata_eh_reset(struct ata_link *link, int classify, * bus as we may be talking too fast. */ dev->pio_mode = XFER_PIO_0; + dev->dma_mode = 0xff; /* If the controller has a pio mode setup function * then use it to set the chipset to rights. Don't From 93269101285d5bfd18b1f3b7078a76ed87e7a834 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Thu, 13 Dec 2012 16:12:18 +0800 Subject: [PATCH 1830/2357] libata: fix Null pointer dereference on disk error commit 26cd4d65deba587f3cf2329b6869ce02bcbe68ec upstream. Following oops were observed when disk error happened: [ 4272.896937] sd 0:0:0:0: [sda] Unhandled error code [ 4272.896939] sd 0:0:0:0: [sda] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK [ 4272.896942] sd 0:0:0:0: [sda] CDB: Read(10): 28 00 00 5a de a7 00 00 08 00 [ 4272.896951] end_request: I/O error, dev sda, sector 5955239 [ 4291.574947] BUG: unable to handle kernel NULL pointer dereference at (null) [ 4291.658305] IP: [] ahci_activity_show+0x1/0x40 [ 4291.730090] PGD 76dbbc067 PUD 6c4fba067 PMD 0 [ 4291.783408] Oops: 0000 [#1] SMP [ 4291.822100] last sysfs file: /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/sw_activity [ 4291.934235] CPU 9 [ 4291.958301] Pid: 27942, comm: hwinfo ...... ata_scsi_find_dev could return NULL, so ata_scsi_activity_{show,store} should check if atadev is NULL. Signed-off-by: Xiaotian Feng Cc: James Bottomley Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-scsi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 22226350cd0..15863a4b619 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -309,7 +309,8 @@ ata_scsi_activity_show(struct device *dev, struct device_attribute *attr, struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *atadev = ata_scsi_find_dev(ap, sdev); - if (ap->ops->sw_activity_show && (ap->flags & ATA_FLAG_SW_ACTIVITY)) + if (atadev && ap->ops->sw_activity_show && + (ap->flags & ATA_FLAG_SW_ACTIVITY)) return ap->ops->sw_activity_show(atadev, buf); return -EINVAL; } @@ -324,7 +325,8 @@ ata_scsi_activity_store(struct device *dev, struct device_attribute *attr, enum sw_activity val; int rc; - if (ap->ops->sw_activity_store && (ap->flags & ATA_FLAG_SW_ACTIVITY)) { + if (atadev && ap->ops->sw_activity_store && + (ap->flags & ATA_FLAG_SW_ACTIVITY)) { val = simple_strtoul(buf, NULL, 0); switch (val) { case OFF: case BLINK_ON: case BLINK_OFF: From 28a63b67b3d52e40826d82425307e8f067551106 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 10 Dec 2012 17:04:00 -0800 Subject: [PATCH 1831/2357] target/tcm_fc: fix the lockdep warning due to inconsistent lock state commit 9f4ad44b264f8bb61ffdd607148215566568430d upstream. The lockdep warning below is in theory correct but it will be in really weird rare situation that ends up that deadlock since the tcm fc session is hashed based the rport id. Nonetheless, the complaining below is about rcu callback that does the transport_deregister_session() is happening in softirq, where transport_register_session() that happens earlier is not. This triggers the lockdep warning below. So, just fix this to make lockdep happy by disabling the soft irq before calling transport_register_session() in ft_prli. BTW, this was found in FCoE VN2VN over two VMs, couple of create and destroy would get this triggered. v1: was enforcing register to be in softirq context which was not righ. See, http://www.spinics.net/lists/target-devel/msg03614.html v2: following comments from Roland&Nick (thanks), it seems we don't have to do transport_deregister_session() in rcu callback, so move it into ft_sess_free() but still do kfree() of the corresponding ft_sess struct in rcu callback to make sure the ft_sess is not freed till the rcu callback. ... [ 1328.370592] scsi2 : FCoE Driver [ 1328.383429] fcoe: No FDMI support. [ 1328.384509] host2: libfc: Link up on port (000000) [ 1328.934229] host2: Assigned Port ID 00a292 [ 1357.232132] host2: rport 00a393: Remove port [ 1357.232568] host2: rport 00a393: Port sending LOGO from Ready state [ 1357.233692] host2: rport 00a393: Delete port [ 1357.234472] host2: rport 00a393: work event 3 [ 1357.234969] host2: rport 00a393: callback ev 3 [ 1357.235979] host2: rport 00a393: Received a LOGO response closed [ 1357.236706] host2: rport 00a393: work delete [ 1357.237481] [ 1357.237631] ================================= [ 1357.238064] [ INFO: inconsistent lock state ] [ 1357.238450] 3.7.0-rc7-yikvm+ #3 Tainted: G O [ 1357.238450] --------------------------------- [ 1357.238450] inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. [ 1357.238450] ksoftirqd/0/3 [HC0[0]:SC1[1]:HE0:SE0] takes: [ 1357.238450] (&(&se_tpg->session_lock)->rlock){+.?...}, at: [] transport_deregister_session+0x41/0x148 [target_core_mod] [ 1357.238450] {SOFTIRQ-ON-W} state was registered at: [ 1357.238450] [] mark_held_locks+0x6d/0x95 [ 1357.238450] [] trace_hardirqs_on_caller+0x12d/0x197 [ 1357.238450] [] trace_hardirqs_on+0xd/0xf [ 1357.238450] [] _raw_spin_unlock_irq+0x2d/0x45 [ 1357.238450] [] __transport_register_session+0xb8/0x122 [target_core_mod] [ 1357.238450] [] transport_register_session+0x44/0x5a [target_core_mod] [ 1357.238450] [] ft_prli+0x1e3/0x275 [tcm_fc] [ 1357.238450] [] fc_rport_recv_req+0x95e/0xdc5 [libfc] [ 1357.238450] [] fc_lport_recv_els_req+0xc4/0xd5 [libfc] [ 1357.238450] [] fc_lport_recv_req+0x12f/0x18f [libfc] [ 1357.238450] [] fc_exch_recv+0x8ba/0x981 [libfc] [ 1357.238450] [] fcoe_percpu_receive_thread+0x47a/0x4e2 [fcoe] [ 1357.238450] [] kthread+0xb1/0xb9 [ 1357.238450] [] ret_from_fork+0x7c/0xb0 [ 1357.238450] irq event stamp: 275411 [ 1357.238450] hardirqs last enabled at (275410): [] rcu_process_callbacks+0x229/0x42a [ 1357.238450] hardirqs last disabled at (275411): [] _raw_spin_lock_irqsave+0x22/0x8e [ 1357.238450] softirqs last enabled at (275394): [] __do_softirq+0x246/0x26f [ 1357.238450] softirqs last disabled at (275399): [] run_ksoftirqd+0x29/0x62 [ 1357.238450] [ 1357.238450] other info that might help us debug this: [ 1357.238450] Possible unsafe locking scenario: [ 1357.238450] [ 1357.238450] CPU0 [ 1357.238450] ---- [ 1357.238450] lock(&(&se_tpg->session_lock)->rlock); [ 1357.238450] [ 1357.238450] lock(&(&se_tpg->session_lock)->rlock); [ 1357.238450] [ 1357.238450] *** DEADLOCK *** [ 1357.238450] [ 1357.238450] no locks held by ksoftirqd/0/3. [ 1357.238450] [ 1357.238450] stack backtrace: [ 1357.238450] Pid: 3, comm: ksoftirqd/0 Tainted: G O 3.7.0-rc7-yikvm+ #3 [ 1357.238450] Call Trace: [ 1357.238450] [] print_usage_bug+0x1f5/0x206 [ 1357.238450] [] ? save_stack_trace+0x2c/0x49 [ 1357.238450] [] ? print_irq_inversion_bug.part.14+0x1ae/0x1ae [ 1357.238450] [] mark_lock+0x106/0x258 [ 1357.238450] [] __lock_acquire+0x2e7/0xe53 [ 1357.238450] [] ? pvclock_clocksource_read+0x48/0xb4 [ 1357.238450] [] ? rcu_process_gp_end+0xc0/0xc9 [ 1357.238450] [] ? transport_deregister_session+0x41/0x148 [target_core_mod] [ 1357.238450] [] lock_acquire+0x119/0x143 [ 1357.238450] [] ? transport_deregister_session+0x41/0x148 [target_core_mod] [ 1357.238450] [] _raw_spin_lock_irqsave+0x54/0x8e [ 1357.238450] [] ? transport_deregister_session+0x41/0x148 [target_core_mod] [ 1357.238450] [] transport_deregister_session+0x41/0x148 [target_core_mod] [ 1357.238450] [] ? rcu_process_callbacks+0x229/0x42a [ 1357.238450] [] ft_sess_rcu_free+0x17/0x24 [tcm_fc] [ 1357.238450] [] ? ft_sess_free+0x1b/0x1b [tcm_fc] [ 1357.238450] [] rcu_process_callbacks+0x260/0x42a [ 1357.238450] [] __do_softirq+0x13a/0x26f [ 1357.238450] [] ? __schedule+0x65f/0x68e [ 1357.238450] [] run_ksoftirqd+0x29/0x62 [ 1357.238450] [] smpboot_thread_fn+0x1a5/0x1aa [ 1357.238450] [] ? smpboot_unregister_percpu_thread+0x47/0x47 [ 1357.238450] [] kthread+0xb1/0xb9 [ 1357.238450] [] ? wait_for_common+0xbb/0x10a [ 1357.238450] [] ? __init_kthread_worker+0x59/0x59 [ 1357.238450] [] ret_from_fork+0x7c/0xb0 [ 1357.238450] [] ? __init_kthread_worker+0x59/0x59 [ 1417.440099] rport-2:0-0: blocked FC remote port time out: removing rport Signed-off-by: Yi Zou Cc: Open-FCoE Cc: Nicholas A. Bellinger Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/tcm_fc/tfc_sess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 87901fa74dd..a426c4020be 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -431,7 +431,6 @@ static void ft_sess_rcu_free(struct rcu_head *rcu) { struct ft_sess *sess = container_of(rcu, struct ft_sess, rcu); - transport_deregister_session(sess->se_sess); kfree(sess); } @@ -439,6 +438,7 @@ static void ft_sess_free(struct kref *kref) { struct ft_sess *sess = container_of(kref, struct ft_sess, kref); + transport_deregister_session(sess->se_sess); call_rcu(&sess->rcu, ft_sess_rcu_free); } From 4bc4d7ec50d4811610197ee7707559022250724a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 23 Nov 2012 12:05:33 +0900 Subject: [PATCH 1832/2357] mfd: wm8994: Add support for WM1811 rev E commit fee546ce8cfd9dea1f53175f627e17ef5ff05df4 upstream. This is supported identically to the previous revisions. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/wm8994-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 9d7ca1e978f..8d46e68cb17 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -541,6 +541,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) case 1: case 2: case 3: + case 4: regmap_patch = wm1811_reva_patch; patch_regs = ARRAY_SIZE(wm1811_reva_patch); break; From af713fb8e79809aa46f16de4f209245c39b9d7eb Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 9 Nov 2012 16:15:28 +0000 Subject: [PATCH 1833/2357] mfd: Only unregister platform devices allocated by the mfd core commit b9fbb62eb61452d728c39b2e5020739c575aac53 upstream. mfd_remove_devices would iterate over all devices sharing a parent with an mfd device regardless of whether they were allocated by the mfd core or not. This especially caused problems when the device structure was not contained within a platform_device, because to_platform_device is used on each device pointer. This patch defines a device_type for mfd devices and checks this is present from mfd_remove_devices_fn before processing the device. Signed-off-by: Charles Keepax Tested-by: Peter Tyser Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/mfd-core.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index ffc3d48676a..ef80da67eb5 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -19,6 +19,10 @@ #include #include +static struct device_type mfd_dev_type = { + .name = "mfd_device", +}; + int mfd_cell_enable(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); @@ -88,6 +92,7 @@ static int mfd_add_device(struct device *parent, int id, goto fail_device; pdev->dev.parent = parent; + pdev->dev.type = &mfd_dev_type; if (cell->pdata_size) { ret = platform_device_add_data(pdev, @@ -183,10 +188,16 @@ EXPORT_SYMBOL(mfd_add_devices); static int mfd_remove_devices_fn(struct device *dev, void *c) { - struct platform_device *pdev = to_platform_device(dev); - const struct mfd_cell *cell = mfd_get_cell(pdev); + struct platform_device *pdev; + const struct mfd_cell *cell; atomic_t **usage_count = c; + if (dev->type != &mfd_dev_type) + return 0; + + pdev = to_platform_device(dev); + cell = mfd_get_cell(pdev); + /* find the base address of usage_count pointers (for freeing) */ if (!*usage_count || (cell->usage_count < *usage_count)) *usage_count = cell->usage_count; From aadee0f004ac85d2afd1cd03279d3dc01363258c Mon Sep 17 00:00:00 2001 From: Eugene Shatokhin Date: Thu, 8 Nov 2012 15:11:11 -0500 Subject: [PATCH 1834/2357] ext4: fix memory leak in ext4_xattr_set_acl()'s error path commit 24ec19b0ae83a385ad9c55520716da671274b96c upstream. In ext4_xattr_set_acl(), if ext4_journal_start() returns an error, posix_acl_release() will not be called for 'acl' which may result in a memory leak. This patch fixes that. Reviewed-by: Lukas Czerner Signed-off-by: Eugene Shatokhin Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/acl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index a5c29bb3b83..8535c45dfce 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -410,8 +410,10 @@ ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, retry: handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); + if (IS_ERR(handle)) { + error = PTR_ERR(handle); + goto release_and_out; + } error = ext4_set_acl(handle, inode, type, acl); ext4_journal_stop(handle); if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) From 6b4b4679f40d6d112eda435a9dde937bb41c9bfc Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 29 Nov 2012 21:21:22 -0500 Subject: [PATCH 1835/2357] ext4: fix possible use after free with metadata csum commit aeb1e5d69a5be592e86a926be73efb38c55af404 upstream. Commit fa77dcfafeaa introduces block bitmap checksum calculation into ext4_new_inode() in the case that block group was uninitialized. However we brelse() the bitmap buffer before we attempt to checksum it so we have no guarantee that the buffer is still there. Fix this by releasing the buffer after the possible checksum computation. Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" Acked-by: Darrick J. Wong Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ialloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 556cc821652..902544e7ee5 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -734,7 +734,6 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode, BUFFER_TRACE(block_bitmap_bh, "dirty block bitmap"); err = ext4_handle_dirty_metadata(handle, NULL, block_bitmap_bh); - brelse(block_bitmap_bh); /* recheck and clear flag under lock if we still need to */ ext4_lock_group(sb, group); @@ -746,6 +745,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode, gdp); } ext4_unlock_group(sb, group); + brelse(block_bitmap_bh); if (err) goto fail; From 272965fcdaf55d0930dbc594fdfd93cd13fcc8cd Mon Sep 17 00:00:00 2001 From: Nathan Williams Date: Thu, 22 Nov 2012 10:42:52 +1100 Subject: [PATCH 1836/2357] mtd cs553x_nand: Initialise ecc.strength before nand_scan() commit d1f3b65d2d6fdb4bf0edd4b67e86e191af48daee upstream. Loading cs553x_nand with Hynix H27U1G8F2BTR NAND flash causes this bug: kernel BUG at drivers/mtd/nand/nand_base.c:3345! invalid opcode: 0000 [#1] Modules linked in: cs553x_nand(+) vfat fat usb_storage ehci_hcd usbcore usb_comr Pid: 436, comm: modprobe Not tainted 3.6.7 #1 EIP: 0060:[] EFLAGS: 00010296 CPU: 0 EIP is at nand_scan_tail+0x64c/0x69c EAX: 00000034 EBX: cea6ed98 ECX: 00000000 EDX: 00000000 ESI: cea6ec00 EDI: cea6ec00 EBP: 20000000 ESP: cdd17e48 DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 CR0: 8005003b CR2: 0804e119 CR3: 0d850000 CR4: 00000090 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Process modprobe (pid: 436, ti=cdd16000 task=cdd1c320 task.ti=cdd16000) Stack: c12e962c c118f7ef 00000003 cea6ed98 d014b25c 20000000 fffff007 00000001 00000000 cdd53b00 d014b000 c1001021 cdd53b00 d01493c0 cdd53b00 cdd53b00 d01493c0 c1047f83 d014b4a0 00000000 cdd17f9c ce4be454 cdd17f48 cdd1c320 Call Trace: [] ? nand_scan+0x1b/0x4d [] ? init_module+0x25c/0x2de [cs553x_nand] [] ? 0xd014afff [] ? do_one_initcall+0x21/0x111 [] ? sys_init_module+0xe4/0x1261 [] ? task_work_run+0x36/0x43 [] ? syscall_call+0x7/0xb Code: fa ff ff c7 86 d8 00 00 00 01 00 00 00 e9 5f fc ff ff 68 f8 26 2e c1 e8 a7 EIP: [] nand_scan_tail+0x64c/0x69c SS:ESP 0068:cdd17e48 Initialising ecc.strength before the call to nand_scan() fixes this. Signed-off-by: Nathan Williams Acked-by: Brian Norris Acked-by: Mike Dunn Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/cs553x_nand.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 821c34c6250..0b9b472b52b 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -237,6 +237,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) this->ecc.hwctl = cs_enable_hwecc; this->ecc.calculate = cs_calculate_ecc; this->ecc.correct = nand_correct_data; + this->ecc.strength = 1; /* Enable the following for a flash based bad block table */ this->bbt_options = NAND_BBT_USE_FLASH; @@ -248,8 +249,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) goto out_ior; } - this->ecc.strength = 1; - new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs); cs553x_mtd[cs] = new_mtd; From b53673dcf8a31a4b2f41fdf2fa168b7c693fd7b3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 5 Dec 2012 21:46:02 +0100 Subject: [PATCH 1837/2357] mtd: nand: gpmi: reset BCH earlier, too, to avoid NAND startup problems commit 6f2a6a52560ad8d85710aabd92b7a3239b3a6b07 upstream. It could happen (1 out of 100 times) that NAND did not start up correctly after warm rebooting, so the kernel could not find the UBI or DMA timed out due to a stalled BCH. When resetting BCH together with GPMI, the issue could not be observed anymore (after 10000+ reboots). We probably need the consistent state already before sending any command to NAND, even when no ECC is needed. I chose to keep the extra reset for BCH when changing the flash layout to be on the safe side. Signed-off-by: Wolfram Sang Acked-by: Huang Shijie Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index e8ea7107932..022feb45c15 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -135,6 +135,15 @@ int gpmi_init(struct gpmi_nand_data *this) if (ret) goto err_out; + /* + * Reset BCH here, too. We got failures otherwise :( + * See later BCH reset for explanation of MX23 handling + */ + ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this)); + if (ret) + goto err_out; + + /* Choose NAND mode. */ writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); From 65ac5efcd7e36ddf4cbe7d9e7f844a016dba4f7d Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 17 Dec 2012 20:18:52 +0300 Subject: [PATCH 1838/2357] SUNRPC: continue run over clients list on PipeFS event instead of break commit cd6c5968582a273561464fe6b1e8cc8214be02df upstream. There are SUNRPC clients, which program doesn't have pipe_dir_name. These clients can be skipped on PipeFS events, because nothing have to be created or destroyed. But instead of breaking in case of such a client was found, search for suitable client over clients list have to be continued. Otherwise some clients could not be covered by PipeFS event handler. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/clnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 57f2731d957..a28a2111297 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -236,7 +236,7 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) spin_lock(&sn->rpc_client_lock); list_for_each_entry(clnt, &sn->all_clients, cl_clients) { if (clnt->cl_program->pipe_dir_name == NULL) - break; + continue; if (rpc_clnt_skip_event(clnt, event)) continue; if (atomic_inc_not_zero(&clnt->cl_count) == 0) From d5b319960ab9e0770b6ecae94045b512cd3029b7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 4 Jan 2013 12:23:21 -0500 Subject: [PATCH 1839/2357] SUNRPC: Ensure that we free the rpc_task after cleanups are done commit c6567ed1402c55e19b012e66a8398baec2a726f3 upstream. This patch ensures that we free the rpc_task after the cleanup callbacks are done in order to avoid a deadlock problem that can be triggered if the callback needs to wait for another workqueue item to complete. Signed-off-by: Trond Myklebust Cc: Weston Andros Adamson Cc: Tejun Heo Cc: Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/sched.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index eda32ae7dec..fe2cf2f18d2 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -915,16 +915,35 @@ struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) return task; } +/* + * rpc_free_task - release rpc task and perform cleanups + * + * Note that we free up the rpc_task _after_ rpc_release_calldata() + * in order to work around a workqueue dependency issue. + * + * Tejun Heo states: + * "Workqueue currently considers two work items to be the same if they're + * on the same address and won't execute them concurrently - ie. it + * makes a work item which is queued again while being executed wait + * for the previous execution to complete. + * + * If a work function frees the work item, and then waits for an event + * which should be performed by another work item and *that* work item + * recycles the freed work item, it can create a false dependency loop. + * There really is no reliable way to detect this short of verifying + * every memory free." + * + */ static void rpc_free_task(struct rpc_task *task) { - const struct rpc_call_ops *tk_ops = task->tk_ops; - void *calldata = task->tk_calldata; + unsigned short tk_flags = task->tk_flags; + + rpc_release_calldata(task->tk_ops, task->tk_calldata); - if (task->tk_flags & RPC_TASK_DYNAMIC) { + if (tk_flags & RPC_TASK_DYNAMIC) { dprintk("RPC: %5u freeing task\n", task->tk_pid); mempool_free(task, rpc_task_mempool); } - rpc_release_calldata(tk_ops, calldata); } static void rpc_async_release(struct work_struct *work) From 11d607dd94b7e1e4190f20581643555e620e3366 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 7 Jan 2013 14:30:46 -0500 Subject: [PATCH 1840/2357] SUNRPC: Ensure we release the socket write lock if the rpc_task exits early commit 87ed50036b866db2ec2ba16b2a7aec4a2b0b7c39 upstream. If the rpc_task exits while holding the socket write lock before it has allocated an rpc slot, then the usual mechanism for releasing the write lock in xprt_release() is defeated. The problem occurs if the call to xprt_lock_write() initially fails, so that the rpc_task is put on the xprt->sending wait queue. If the task exits after being assigned the lock by __xprt_lock_write_func, but before it has retried the call to xprt_lock_and_alloc_slot(), then it calls xprt_release() while holding the write lock, but will immediately exit due to the test for task->tk_rqstp != NULL. Reported-by: Chris Perl Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/sched.c | 3 +-- net/sunrpc/xprt.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index fe2cf2f18d2..85b9235fbee 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -953,8 +953,7 @@ static void rpc_async_release(struct work_struct *work) static void rpc_release_resources_task(struct rpc_task *task) { - if (task->tk_rqstp) - xprt_release(task); + xprt_release(task); if (task->tk_msg.rpc_cred) { put_rpccred(task->tk_msg.rpc_cred); task->tk_msg.rpc_cred = NULL; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 176a24f0153..feea4741edd 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1139,10 +1139,18 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) void xprt_release(struct rpc_task *task) { struct rpc_xprt *xprt; - struct rpc_rqst *req; + struct rpc_rqst *req = task->tk_rqstp; - if (!(req = task->tk_rqstp)) + if (req == NULL) { + if (task->tk_client) { + rcu_read_lock(); + xprt = rcu_dereference(task->tk_client->cl_xprt); + if (xprt->snd_task == task) + xprt_release_write(xprt, task); + rcu_read_unlock(); + } return; + } xprt = req->rq_xprt; if (task->tk_ops->rpc_count_stats != NULL) From 7e94f31b2b9c1a1e976a7123ca9b96dddb3eeaae Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Mon, 5 Nov 2012 22:40:14 +0400 Subject: [PATCH 1841/2357] jffs2: hold erase_completion_lock on exit commit 2cbba75a56ea78e6876b4e2547a882f10b3fe72b upstream. Users of jffs2_do_reserve_space() expect they still held erase_completion_lock after call to it. But there is a path where jffs2_do_reserve_space() leaves erase_completion_lock unlocked. The patch fixes it. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- fs/jffs2/nodemgmt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 6784d1e7a7e..ffa8f12c7a5 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -375,14 +375,16 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, spin_unlock(&c->erase_completion_lock); ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); - if (ret) - return ret; + /* Just lock it again and continue. Nothing much can change because we hold c->alloc_sem anyway. In fact, it's not entirely clear why we hold c->erase_completion_lock in the majority of this function... but that's a question for another (more caffeine-rich) day. */ spin_lock(&c->erase_completion_lock); + if (ret) + return ret; + waste = jeb->free_size; jffs2_link_node_ref(c, jeb, (jeb->offset + c->sector_size - waste) | REF_OBSOLETE, From 9aba4c8888212a4a281107fec875eb1fd14cbb43 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 14 Dec 2012 13:10:50 +0000 Subject: [PATCH 1842/2357] i2400m: add Intel 6150 device IDs commit 999a7c5776a0ed2133645fa7e008bec05bda9254 upstream. Add device IDs for WiMAX function of Intel 6150 cards. Signed-off-by: Dan Williams Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/wimax/i2400m/i2400m-usb.h | 3 +++ drivers/net/wimax/i2400m/usb.c | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/net/wimax/i2400m/i2400m-usb.h b/drivers/net/wimax/i2400m/i2400m-usb.h index 6650fde99e1..9f1e947f355 100644 --- a/drivers/net/wimax/i2400m/i2400m-usb.h +++ b/drivers/net/wimax/i2400m/i2400m-usb.h @@ -152,6 +152,9 @@ enum { /* Device IDs */ USB_DEVICE_ID_I6050 = 0x0186, USB_DEVICE_ID_I6050_2 = 0x0188, + USB_DEVICE_ID_I6150 = 0x07d6, + USB_DEVICE_ID_I6150_2 = 0x07d7, + USB_DEVICE_ID_I6150_3 = 0x07d9, USB_DEVICE_ID_I6250 = 0x0187, }; diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 29b1e033a10..f0f16e0c612 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -510,6 +510,9 @@ int i2400mu_probe(struct usb_interface *iface, switch (id->idProduct) { case USB_DEVICE_ID_I6050: case USB_DEVICE_ID_I6050_2: + case USB_DEVICE_ID_I6150: + case USB_DEVICE_ID_I6150_2: + case USB_DEVICE_ID_I6150_3: case USB_DEVICE_ID_I6250: i2400mu->i6050 = 1; break; @@ -759,6 +762,9 @@ static struct usb_device_id i2400mu_id_table[] = { { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) }, { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) }, + { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150) }, + { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150_2) }, + { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150_3) }, { USB_DEVICE(0x8086, USB_DEVICE_ID_I6250) }, { USB_DEVICE(0x8086, 0x0181) }, { USB_DEVICE(0x8086, 0x1403) }, From 16639bce521c713cf623ac4a4ff085c18a48674e Mon Sep 17 00:00:00 2001 From: "Woodhouse, David" Date: Wed, 19 Dec 2012 13:25:35 +0000 Subject: [PATCH 1843/2357] intel-iommu: Free old page tables before creating superpage commit 6491d4d02893d9787ba67279595990217177b351 upstream. The dma_pte_free_pagetable() function will only free a page table page if it is asked to free the *entire* 2MiB range that it covers. So if a page table page was used for one or more small mappings, it's likely to end up still present in the page tables... but with no valid PTEs. This was fine when we'd only be repopulating it with 4KiB PTEs anyway but the same virtual address range can end up being reused for a *large-page* mapping. And in that case were were trying to insert the large page into the second-level page table, and getting a complaint from the sanity check in __domain_mapping() because there was already a corresponding entry. This was *relatively* harmless; it led to a memory leak of the old page table page, but no other ill-effects. Fix it by calling dma_pte_clear_range (hopefully redundant) and dma_pte_free_pagetable() before setting up the new large page. Signed-off-by: David Woodhouse Tested-by: Ravi Murty Tested-by: Sudeep Dutt Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-iommu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 0d251d301be..9c34db8e729 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1826,10 +1826,17 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, if (!pte) return -ENOMEM; /* It is large page*/ - if (largepage_lvl > 1) + if (largepage_lvl > 1) { pteval |= DMA_PTE_LARGE_PAGE; - else + /* Ensure that old small page tables are removed to make room + for superpage, if they exist. */ + dma_pte_clear_range(domain, iov_pfn, + iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1); + dma_pte_free_pagetable(domain, iov_pfn, + iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1); + } else { pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE; + } } /* We don't need lock here, nobody else From a98843e161b490b91fac1b7e0daa4ba9517bf65a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 4 Dec 2012 16:50:28 -0500 Subject: [PATCH 1844/2357] drm/radeon: fix eDP clk and lane setup for scaled modes commit 93927f9c1db5f55085457e820f0631064c7bfa34 upstream. Need to use the adjusted mode since we are sending native timing and using the scaler for non-native modes. Signed-off-by: Alex Deucher Reviewed-by: Jerome Glisse Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_encoders.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index f6176bc90f1..23e3ea6ba14 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -95,7 +95,7 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE))) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - radeon_dp_set_link_config(connector, mode); + radeon_dp_set_link_config(connector, adjusted_mode); } return true; From e4a5d6d17f6dff0174ba1c0b2041d73ec7d0c1dd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 20 Dec 2012 21:19:32 -0500 Subject: [PATCH 1845/2357] drm/radeon: add WAIT_UNTIL to evergreen VM safe reg list commit 668bbc81baf0f34df832d8aca5c7d5e19a493c68 upstream. It's used in a recent mesa commit: http://cgit.freedesktop.org/mesa/mesa/commit/?id=24b1206ab2dcd506aaac3ef656aebc8bc20cd27a and there may be some other cases in the future where it's required. Signed-off-by: Alex Deucher Reviewed-by: Jerome Glisse Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen_cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 22c84bcfaeb..2cbd369e0fc 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -2670,6 +2670,7 @@ static bool evergreen_vm_reg_valid(u32 reg) /* check config regs */ switch (reg) { + case WAIT_UNTIL: case GRBM_GFX_INDEX: case CP_STRMOUT_CNTL: case CP_COHER_CNTL: From 5df148ba552817a8d3eb9d2ace557deb178192e6 Mon Sep 17 00:00:00 2001 From: Niels Ole Salscheider Date: Thu, 3 Jan 2013 19:09:28 +0100 Subject: [PATCH 1846/2357] drm/radeon: Properly handle DDC probe for DP bridges commit 0a9069d34918659bc8a89e21e69e60b2b83291a3 upstream. DDC information can be accessed using AUX CH Fixes failure to probe monitors on some systems with DP bridge chips. agd5f: minor fixes Signed-off-by: Niels Ole Salscheider Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 10 ++++++---- drivers/gpu/drm/radeon/radeon_display.c | 13 +++++++++---- drivers/gpu/drm/radeon/radeon_i2c.c | 10 ++++++++-- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 3fb7ca92206..ab63bcd1727 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -689,7 +689,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) ret = connector_status_disconnected; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector); + dret = radeon_ddc_probe(radeon_connector, false); if (dret) { radeon_connector->detected_by_load = false; if (radeon_connector->edid) { @@ -895,7 +895,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) return connector->status; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector); + dret = radeon_ddc_probe(radeon_connector, false); if (dret) { radeon_connector->detected_by_load = false; if (radeon_connector->edid) { @@ -1335,7 +1335,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (encoder) { /* setup ddc on the bridge */ radeon_atom_ext_encoder_setup_ddc(encoder); - if (radeon_ddc_probe(radeon_connector)) /* try DDC */ + /* bridge chips are always aux */ + if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */ ret = connector_status_connected; else if (radeon_connector->dac_load_detect) { /* try load detection */ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -1353,7 +1354,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; } else { - if (radeon_ddc_probe(radeon_connector)) + /* try non-aux ddc (DP to DVI/HMDI/etc. adapter) */ + if (radeon_ddc_probe(radeon_connector, false)) ret = connector_status_connected; } } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 0a1d4bd65ed..173b97b2819 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -713,10 +713,15 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); - if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || - (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) || - (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != - ENCODER_OBJECT_ID_NONE)) { + if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != + ENCODER_OBJECT_ID_NONE) { + struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; + + if (dig->dp_i2c_bus) + radeon_connector->edid = drm_get_edid(&radeon_connector->base, + &dig->dp_i2c_bus->adapter); + } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || + (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 3edec1c198e..6076e85aa5d 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -39,7 +39,7 @@ extern u32 radeon_atom_hw_i2c_func(struct i2c_adapter *adap); * radeon_ddc_probe * */ -bool radeon_ddc_probe(struct radeon_connector *radeon_connector) +bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux) { u8 out = 0x0; u8 buf[8]; @@ -63,7 +63,13 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector) if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); - ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); + if (use_aux) { + struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; + ret = i2c_transfer(&dig->dp_i2c_bus->adapter, msgs, 2); + } else { + ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); + } + if (ret != 2) /* Couldn't find an accessible DDC on this connector */ return false; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 778c1f0d7b8..dabfefda8f5 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -527,7 +527,7 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c, u8 val); extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); -extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); +extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux); extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); From 297456d8fe2b141f0f05b5d6ff48a4cd0b5f5889 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 20 Nov 2012 13:27:41 -0200 Subject: [PATCH 1847/2357] drm/i915: make the panel fitter work on pipes B and C on IVB commit 13888d78c664a1f61d7b09d282f5916993827a40 upstream. I actually found this problem on Haswell, but then discovered Ivy Bridge also has it by reading the spec. I don't have the hardware to test this. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_display.c | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 29bfd899573..cd1a85a6880 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3015,6 +3015,8 @@ #define _PFA_CTL_1 0x68080 #define _PFB_CTL_1 0x68880 #define PF_ENABLE (1<<31) +#define PF_PIPE_SEL_MASK_IVB (3<<29) +#define PF_PIPE_SEL_IVB(pipe) ((pipe)<<29) #define PF_FILTER_MASK (3<<23) #define PF_FILTER_PROGRAMMED (0<<23) #define PF_FILTER_MED_3x3 (1<<23) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dd3e7e44023..fd150a98a62 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3095,7 +3095,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) * as some pre-programmed values are broken, * e.g. x201. */ - I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); + if (IS_IVYBRIDGE(dev)) + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | + PF_PIPE_SEL_IVB(pipe)); + else + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos); I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); } From c7cde2b3d27a5417021d7fc6da0f7941eab63769 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 8 Nov 2012 10:01:26 -0500 Subject: [PATCH 1848/2357] SUNRPC: Fix validity issues with rpc_pipefs sb->s_fs_info commit 642fe4d00db56d65060ce2fd4c105884414acb16 upstream. rpc_kill_sb() must defer calling put_net() until after the notifier has been called, since most (all?) of the notifier callbacks assume that sb->s_fs_info points to a valid net namespace. It also must not call put_net() if the call to rpc_fill_super was unsuccessful. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=48421 Signed-off-by: Trond Myklebust Cc: Stanislav Kinsbursky Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/rpc_pipe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index faa078f74b2..b8bda4434c0 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1157,14 +1157,19 @@ static void rpc_kill_sb(struct super_block *sb) struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); mutex_lock(&sn->pipefs_sb_lock); + if (sn->pipefs_sb != sb) { + mutex_unlock(&sn->pipefs_sb_lock); + goto out; + } sn->pipefs_sb = NULL; mutex_unlock(&sn->pipefs_sb_lock); - put_net(net); dprintk("RPC: sending pipefs UMOUNT notification for net %p%s\n", net, NET_NAME(net)); blocking_notifier_call_chain(&rpc_pipefs_notifier_list, RPC_PIPEFS_UMOUNT, sb); + put_net(net); +out: kill_litter_super(sb); } From e5ca2896f817ef43802387ae2f41a9c70e30ee86 Mon Sep 17 00:00:00 2001 From: Tatyana Nikolova Date: Thu, 6 Dec 2012 20:05:02 +0000 Subject: [PATCH 1849/2357] RDMA/nes: Fix for crash when registering zero length MR for CQ commit 7d9c199a55200c9b9fcad08e150470d02fb385be upstream. Signed-off-by: Tatyana Nikolova Signed-off-by: Roland Dreier Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/nes/nes_verbs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 8b8812de4b5..7082c36d57c 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -2559,6 +2559,11 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return ibmr; case IWNES_MEMREG_TYPE_QP: case IWNES_MEMREG_TYPE_CQ: + if (!region->length) { + nes_debug(NES_DBG_MR, "Unable to register zero length region for CQ\n"); + ib_umem_release(region); + return ERR_PTR(-EINVAL); + } nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL); if (!nespbl) { nes_debug(NES_DBG_MR, "Unable to allocate PBL\n"); From 0d38a8789caf511e5b997caf76eb32fddbff051c Mon Sep 17 00:00:00 2001 From: Tatyana Nikolova Date: Thu, 6 Dec 2012 19:58:27 +0000 Subject: [PATCH 1850/2357] RDMA/nes: Fix for terminate timer crash commit 7bfcfa51c35cdd2d37e0d70fc11790642dd11fb3 upstream. The terminate timer needs to be initialized just once. Signed-off-by: Tatyana Nikolova Signed-off-by: Roland Dreier Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/nes/nes.h | 1 + drivers/infiniband/hw/nes/nes_hw.c | 9 ++------- drivers/infiniband/hw/nes/nes_verbs.c | 4 +++- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index c438e4691b3..3f41d9f5f70 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -524,6 +524,7 @@ void nes_iwarp_ce_handler(struct nes_device *, struct nes_hw_cq *); int nes_destroy_cqp(struct nes_device *); int nes_nic_cm_xmit(struct sk_buff *, struct net_device *); void nes_recheck_link_status(struct work_struct *work); +void nes_terminate_timeout(unsigned long context); /* nes_nic.c */ struct net_device *nes_netdev_init(struct nes_device *, void __iomem *); diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index d42c9f435b1..96801c3a1fe 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -75,7 +75,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, static void process_critical_error(struct nes_device *nesdev); static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number); static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode); -static void nes_terminate_timeout(unsigned long context); static void nes_terminate_start_timer(struct nes_qp *nesqp); #ifdef CONFIG_INFINIBAND_NES_DEBUG @@ -3522,7 +3521,7 @@ static void nes_terminate_received(struct nes_device *nesdev, } /* Timeout routine in case terminate fails to complete */ -static void nes_terminate_timeout(unsigned long context) +void nes_terminate_timeout(unsigned long context) { struct nes_qp *nesqp = (struct nes_qp *)(unsigned long)context; @@ -3532,11 +3531,7 @@ static void nes_terminate_timeout(unsigned long context) /* Set a timer in case hw cannot complete the terminate sequence */ static void nes_terminate_start_timer(struct nes_qp *nesqp) { - init_timer(&nesqp->terminate_timer); - nesqp->terminate_timer.function = nes_terminate_timeout; - nesqp->terminate_timer.expires = jiffies + HZ; - nesqp->terminate_timer.data = (unsigned long)nesqp; - add_timer(&nesqp->terminate_timer); + mod_timer(&nesqp->terminate_timer, (jiffies + HZ)); } /** diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 7082c36d57c..da84ea383f9 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1404,6 +1404,9 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, } nesqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR); + init_timer(&nesqp->terminate_timer); + nesqp->terminate_timer.function = nes_terminate_timeout; + nesqp->terminate_timer.data = (unsigned long)nesqp; /* update the QP table */ nesdev->nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = nesqp; @@ -1413,7 +1416,6 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, return &nesqp->ibqp; } - /** * nes_clean_cq */ From 4d7981bfc21f7b6ef48f9a819d2c9969ad6eea71 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 29 Nov 2012 22:31:16 -0500 Subject: [PATCH 1851/2357] ring-buffer: Fix race between integrity check and readers commit 9366c1ba13fbc41bdb57702e75ca4382f209c82f upstream. The function rb_check_pages() was added to make sure the ring buffer's pages were sane. This check is done when the ring buffer size is modified as well as when the iterator is released (closing the "trace" file), as that was considered a non fast path and a good place to do a sanity check. The problem is that the check does not have any locks around it. If one process were to read the trace file, and another were to read the raw binary file, the check could happen while the reader is reading the file. The issues with this is that the check requires to clear the HEAD page before doing the full check and it restores it afterward. But readers require the HEAD page to exist before it can read the buffer, otherwise it gives a nasty warning and disables the buffer. By adding the reader lock around the check, this keeps the race from happening. Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/ring_buffer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index cf8d11e91ef..28667834181 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2708,7 +2708,7 @@ unsigned long ring_buffer_oldest_event_ts(struct ring_buffer *buffer, int cpu) unsigned long flags; struct ring_buffer_per_cpu *cpu_buffer; struct buffer_page *bpage; - unsigned long ret; + unsigned long ret = 0; if (!cpumask_test_cpu(cpu, buffer->cpumask)) return 0; @@ -2723,7 +2723,8 @@ unsigned long ring_buffer_oldest_event_ts(struct ring_buffer *buffer, int cpu) bpage = cpu_buffer->reader_page; else bpage = rb_set_head_page(cpu_buffer); - ret = bpage->page->time_stamp; + if (bpage) + ret = bpage->page->time_stamp; raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); return ret; @@ -3030,6 +3031,8 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) * Splice the empty reader page into the list around the head. */ reader = rb_set_head_page(cpu_buffer); + if (!reader) + goto out; cpu_buffer->reader_page->list.next = rb_list_head(reader->list.next); cpu_buffer->reader_page->list.prev = reader->list.prev; From 38d67580f65e46ec13c65c8ebb0666134f167658 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Fri, 21 Dec 2012 20:23:30 +0000 Subject: [PATCH 1852/2357] dm persistent data: rename node to btree_node commit 550929faf89e2e2cdb3e9945ea87d383989274cf upstream. This patch fixes a compilation failure on sparc32 by renaming struct node. struct node is already defined in include/linux/node.h. On sparc32, it happens to be included through other dependencies and persistent-data doesn't compile because of conflicting declarations. Signed-off-by: Mikulas Patocka Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- .../md/persistent-data/dm-btree-internal.h | 16 +++--- drivers/md/persistent-data/dm-btree-remove.c | 50 +++++++++---------- drivers/md/persistent-data/dm-btree-spine.c | 6 +-- drivers/md/persistent-data/dm-btree.c | 22 ++++---- 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/md/persistent-data/dm-btree-internal.h b/drivers/md/persistent-data/dm-btree-internal.h index 5709bfeab1e..accbb05f17b 100644 --- a/drivers/md/persistent-data/dm-btree-internal.h +++ b/drivers/md/persistent-data/dm-btree-internal.h @@ -36,13 +36,13 @@ struct node_header { __le32 padding; } __packed; -struct node { +struct btree_node { struct node_header header; __le64 keys[0]; } __packed; -void inc_children(struct dm_transaction_manager *tm, struct node *n, +void inc_children(struct dm_transaction_manager *tm, struct btree_node *n, struct dm_btree_value_type *vt); int new_block(struct dm_btree_info *info, struct dm_block **result); @@ -64,7 +64,7 @@ struct ro_spine { void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info); int exit_ro_spine(struct ro_spine *s); int ro_step(struct ro_spine *s, dm_block_t new_child); -struct node *ro_node(struct ro_spine *s); +struct btree_node *ro_node(struct ro_spine *s); struct shadow_spine { struct dm_btree_info *info; @@ -98,17 +98,17 @@ int shadow_root(struct shadow_spine *s); /* * Some inlines. */ -static inline __le64 *key_ptr(struct node *n, uint32_t index) +static inline __le64 *key_ptr(struct btree_node *n, uint32_t index) { return n->keys + index; } -static inline void *value_base(struct node *n) +static inline void *value_base(struct btree_node *n) { return &n->keys[le32_to_cpu(n->header.max_entries)]; } -static inline void *value_ptr(struct node *n, uint32_t index) +static inline void *value_ptr(struct btree_node *n, uint32_t index) { uint32_t value_size = le32_to_cpu(n->header.value_size); return value_base(n) + (value_size * index); @@ -117,7 +117,7 @@ static inline void *value_ptr(struct node *n, uint32_t index) /* * Assumes the values are suitably-aligned and converts to core format. */ -static inline uint64_t value64(struct node *n, uint32_t index) +static inline uint64_t value64(struct btree_node *n, uint32_t index) { __le64 *values_le = value_base(n); @@ -127,7 +127,7 @@ static inline uint64_t value64(struct node *n, uint32_t index) /* * Searching for a key within a single node. */ -int lower_bound(struct node *n, uint64_t key); +int lower_bound(struct btree_node *n, uint64_t key); extern struct dm_block_validator btree_node_validator; diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index aa71e2359a0..c4f28133ef8 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -53,7 +53,7 @@ /* * Some little utilities for moving node data around. */ -static void node_shift(struct node *n, int shift) +static void node_shift(struct btree_node *n, int shift) { uint32_t nr_entries = le32_to_cpu(n->header.nr_entries); uint32_t value_size = le32_to_cpu(n->header.value_size); @@ -79,7 +79,7 @@ static void node_shift(struct node *n, int shift) } } -static void node_copy(struct node *left, struct node *right, int shift) +static void node_copy(struct btree_node *left, struct btree_node *right, int shift) { uint32_t nr_left = le32_to_cpu(left->header.nr_entries); uint32_t value_size = le32_to_cpu(left->header.value_size); @@ -108,7 +108,7 @@ static void node_copy(struct node *left, struct node *right, int shift) /* * Delete a specific entry from a leaf node. */ -static void delete_at(struct node *n, unsigned index) +static void delete_at(struct btree_node *n, unsigned index) { unsigned nr_entries = le32_to_cpu(n->header.nr_entries); unsigned nr_to_copy = nr_entries - (index + 1); @@ -128,7 +128,7 @@ static void delete_at(struct node *n, unsigned index) n->header.nr_entries = cpu_to_le32(nr_entries - 1); } -static unsigned merge_threshold(struct node *n) +static unsigned merge_threshold(struct btree_node *n) { return le32_to_cpu(n->header.max_entries) / 3; } @@ -136,7 +136,7 @@ static unsigned merge_threshold(struct node *n) struct child { unsigned index; struct dm_block *block; - struct node *n; + struct btree_node *n; }; static struct dm_btree_value_type le64_type = { @@ -147,7 +147,7 @@ static struct dm_btree_value_type le64_type = { .equal = NULL }; -static int init_child(struct dm_btree_info *info, struct node *parent, +static int init_child(struct dm_btree_info *info, struct btree_node *parent, unsigned index, struct child *result) { int r, inc; @@ -177,7 +177,7 @@ static int exit_child(struct dm_btree_info *info, struct child *c) return dm_tm_unlock(info->tm, c->block); } -static void shift(struct node *left, struct node *right, int count) +static void shift(struct btree_node *left, struct btree_node *right, int count) { uint32_t nr_left = le32_to_cpu(left->header.nr_entries); uint32_t nr_right = le32_to_cpu(right->header.nr_entries); @@ -203,11 +203,11 @@ static void shift(struct node *left, struct node *right, int count) right->header.nr_entries = cpu_to_le32(nr_right + count); } -static void __rebalance2(struct dm_btree_info *info, struct node *parent, +static void __rebalance2(struct dm_btree_info *info, struct btree_node *parent, struct child *l, struct child *r) { - struct node *left = l->n; - struct node *right = r->n; + struct btree_node *left = l->n; + struct btree_node *right = r->n; uint32_t nr_left = le32_to_cpu(left->header.nr_entries); uint32_t nr_right = le32_to_cpu(right->header.nr_entries); unsigned threshold = 2 * merge_threshold(left) + 1; @@ -239,7 +239,7 @@ static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info, unsigned left_index) { int r; - struct node *parent; + struct btree_node *parent; struct child left, right; parent = dm_block_data(shadow_current(s)); @@ -270,9 +270,9 @@ static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info, * in right, then rebalance2. This wastes some cpu, but I want something * simple atm. */ -static void delete_center_node(struct dm_btree_info *info, struct node *parent, +static void delete_center_node(struct dm_btree_info *info, struct btree_node *parent, struct child *l, struct child *c, struct child *r, - struct node *left, struct node *center, struct node *right, + struct btree_node *left, struct btree_node *center, struct btree_node *right, uint32_t nr_left, uint32_t nr_center, uint32_t nr_right) { uint32_t max_entries = le32_to_cpu(left->header.max_entries); @@ -301,9 +301,9 @@ static void delete_center_node(struct dm_btree_info *info, struct node *parent, /* * Redistributes entries among 3 sibling nodes. */ -static void redistribute3(struct dm_btree_info *info, struct node *parent, +static void redistribute3(struct dm_btree_info *info, struct btree_node *parent, struct child *l, struct child *c, struct child *r, - struct node *left, struct node *center, struct node *right, + struct btree_node *left, struct btree_node *center, struct btree_node *right, uint32_t nr_left, uint32_t nr_center, uint32_t nr_right) { int s; @@ -343,12 +343,12 @@ static void redistribute3(struct dm_btree_info *info, struct node *parent, *key_ptr(parent, r->index) = right->keys[0]; } -static void __rebalance3(struct dm_btree_info *info, struct node *parent, +static void __rebalance3(struct dm_btree_info *info, struct btree_node *parent, struct child *l, struct child *c, struct child *r) { - struct node *left = l->n; - struct node *center = c->n; - struct node *right = r->n; + struct btree_node *left = l->n; + struct btree_node *center = c->n; + struct btree_node *right = r->n; uint32_t nr_left = le32_to_cpu(left->header.nr_entries); uint32_t nr_center = le32_to_cpu(center->header.nr_entries); @@ -371,7 +371,7 @@ static int rebalance3(struct shadow_spine *s, struct dm_btree_info *info, unsigned left_index) { int r; - struct node *parent = dm_block_data(shadow_current(s)); + struct btree_node *parent = dm_block_data(shadow_current(s)); struct child left, center, right; /* @@ -421,7 +421,7 @@ static int get_nr_entries(struct dm_transaction_manager *tm, { int r; struct dm_block *block; - struct node *n; + struct btree_node *n; r = dm_tm_read_lock(tm, b, &btree_node_validator, &block); if (r) @@ -438,7 +438,7 @@ static int rebalance_children(struct shadow_spine *s, { int i, r, has_left_sibling, has_right_sibling; uint32_t child_entries; - struct node *n; + struct btree_node *n; n = dm_block_data(shadow_current(s)); @@ -483,7 +483,7 @@ static int rebalance_children(struct shadow_spine *s, return r; } -static int do_leaf(struct node *n, uint64_t key, unsigned *index) +static int do_leaf(struct btree_node *n, uint64_t key, unsigned *index) { int i = lower_bound(n, key); @@ -506,7 +506,7 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info, uint64_t key, unsigned *index) { int i = *index, r; - struct node *n; + struct btree_node *n; for (;;) { r = shadow_step(s, root, vt); @@ -556,7 +556,7 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root, unsigned level, last_level = info->levels - 1; int index = 0, r = 0; struct shadow_spine spine; - struct node *n; + struct btree_node *n; init_shadow_spine(&spine, info); for (level = 0; level < info->levels; level++) { diff --git a/drivers/md/persistent-data/dm-btree-spine.c b/drivers/md/persistent-data/dm-btree-spine.c index d9a7912ee8e..2f0805c3263 100644 --- a/drivers/md/persistent-data/dm-btree-spine.c +++ b/drivers/md/persistent-data/dm-btree-spine.c @@ -23,7 +23,7 @@ static void node_prepare_for_write(struct dm_block_validator *v, struct dm_block *b, size_t block_size) { - struct node *n = dm_block_data(b); + struct btree_node *n = dm_block_data(b); struct node_header *h = &n->header; h->blocknr = cpu_to_le64(dm_block_location(b)); @@ -38,7 +38,7 @@ static int node_check(struct dm_block_validator *v, struct dm_block *b, size_t block_size) { - struct node *n = dm_block_data(b); + struct btree_node *n = dm_block_data(b); struct node_header *h = &n->header; size_t value_size; __le32 csum_disk; @@ -164,7 +164,7 @@ int ro_step(struct ro_spine *s, dm_block_t new_child) return r; } -struct node *ro_node(struct ro_spine *s) +struct btree_node *ro_node(struct ro_spine *s) { struct dm_block *block; diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index d12b2cc51f1..371f3d49d18 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -38,7 +38,7 @@ static void array_insert(void *base, size_t elt_size, unsigned nr_elts, /*----------------------------------------------------------------*/ /* makes the assumption that no two keys are the same. */ -static int bsearch(struct node *n, uint64_t key, int want_hi) +static int bsearch(struct btree_node *n, uint64_t key, int want_hi) { int lo = -1, hi = le32_to_cpu(n->header.nr_entries); @@ -58,12 +58,12 @@ static int bsearch(struct node *n, uint64_t key, int want_hi) return want_hi ? hi : lo; } -int lower_bound(struct node *n, uint64_t key) +int lower_bound(struct btree_node *n, uint64_t key) { return bsearch(n, key, 0); } -void inc_children(struct dm_transaction_manager *tm, struct node *n, +void inc_children(struct dm_transaction_manager *tm, struct btree_node *n, struct dm_btree_value_type *vt) { unsigned i; @@ -77,7 +77,7 @@ void inc_children(struct dm_transaction_manager *tm, struct node *n, vt->inc(vt->context, value_ptr(n, i)); } -static int insert_at(size_t value_size, struct node *node, unsigned index, +static int insert_at(size_t value_size, struct btree_node *node, unsigned index, uint64_t key, void *value) __dm_written_to_disk(value) { @@ -122,7 +122,7 @@ int dm_btree_empty(struct dm_btree_info *info, dm_block_t *root) { int r; struct dm_block *b; - struct node *n; + struct btree_node *n; size_t block_size; uint32_t max_entries; @@ -154,7 +154,7 @@ EXPORT_SYMBOL_GPL(dm_btree_empty); #define MAX_SPINE_DEPTH 64 struct frame { struct dm_block *b; - struct node *n; + struct btree_node *n; unsigned level; unsigned nr_children; unsigned current_child; @@ -295,7 +295,7 @@ EXPORT_SYMBOL_GPL(dm_btree_del); /*----------------------------------------------------------------*/ static int btree_lookup_raw(struct ro_spine *s, dm_block_t block, uint64_t key, - int (*search_fn)(struct node *, uint64_t), + int (*search_fn)(struct btree_node *, uint64_t), uint64_t *result_key, void *v, size_t value_size) { int i, r; @@ -406,7 +406,7 @@ static int btree_split_sibling(struct shadow_spine *s, dm_block_t root, size_t size; unsigned nr_left, nr_right; struct dm_block *left, *right, *parent; - struct node *ln, *rn, *pn; + struct btree_node *ln, *rn, *pn; __le64 location; left = shadow_current(s); @@ -491,7 +491,7 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key) size_t size; unsigned nr_left, nr_right; struct dm_block *left, *right, *new_parent; - struct node *pn, *ln, *rn; + struct btree_node *pn, *ln, *rn; __le64 val; new_parent = shadow_current(s); @@ -576,7 +576,7 @@ static int btree_insert_raw(struct shadow_spine *s, dm_block_t root, uint64_t key, unsigned *index) { int r, i = *index, top = 1; - struct node *node; + struct btree_node *node; for (;;) { r = shadow_step(s, root, vt); @@ -643,7 +643,7 @@ static int insert(struct dm_btree_info *info, dm_block_t root, unsigned level, index = -1, last_level = info->levels - 1; dm_block_t block = root; struct shadow_spine spine; - struct node *n; + struct btree_node *n; struct dm_btree_value_type le64_type; le64_type.context = NULL; From 61652b1acea31009aff707b975a171567095df81 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Fri, 21 Dec 2012 20:23:30 +0000 Subject: [PATCH 1853/2357] dm ioctl: prevent unsafe change to dm_ioctl data_size commit e910d7ebecd1aac43125944a8641b6cb1a0dfabe upstream. Abort dm ioctl processing if userspace changes the data_size parameter after we validated it but before we finished copying the data buffer from userspace. The dm ioctl parameters are processed in the following sequence: 1. ctl_ioctl() calls copy_params(); 2. copy_params() makes a first copy of the fixed-sized portion of the userspace parameters into the local variable "tmp"; 3. copy_params() then validates tmp.data_size and allocates a new structure big enough to hold the complete data and copies the whole userspace buffer there; 4. ctl_ioctl() reads userspace data the second time and copies the whole buffer into the pointer "param"; 5. ctl_ioctl() reads param->data_size without any validation and stores it in the variable "input_param_size"; 6. "input_param_size" is further used as the authoritative size of the kernel buffer. The problem is that userspace code could change the contents of user memory between steps 2 and 4. In particular, the data_size parameter can be changed to an invalid value after the kernel has validated it. This lets userspace force the kernel to access invalid kernel memory. The fix is to ensure that the size has not changed at step 4. This patch shouldn't have a security impact because CAP_SYS_ADMIN is required to run this code, but it should be fixed anyway. Reported-by: Mikulas Patocka Signed-off-by: Alasdair G Kergon Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-ioctl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index a1a3e6df17b..f011d4b3c13 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1563,6 +1563,14 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) if (copy_from_user(dmi, user, tmp.data_size)) goto bad; + /* + * Abort if something changed the ioctl data while it was being copied. + */ + if (dmi->data_size != tmp.data_size) { + DMERR("rejecting ioctl: data size modified while processing parameters"); + goto bad; + } + /* Wipe the user buffer so we do not return it to userspace */ if (secure_data && clear_user(user, tmp.data_size)) goto bad; From 97e3cb7f7a27f4902fe75880149517713570da0e Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 7 Oct 2012 08:27:00 +0100 Subject: [PATCH 1854/2357] staging: vt6656: [BUG] out of bound array reference in RFbSetPower. commit ab1dd9963137a1e122004d5378a581bf16ae9bc8 upstream. Calling RFbSetPower with uCH zero value will cause out of bound array reference. This causes 64 bit kernels to oops on boot. Note: Driver does not function on 64 bit kernels and should be blacklisted on them. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/rf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/vt6656/rf.c b/drivers/staging/vt6656/rf.c index 3fd0478a9a5..8cf0881888b 100644 --- a/drivers/staging/vt6656/rf.c +++ b/drivers/staging/vt6656/rf.c @@ -769,6 +769,9 @@ BYTE byPwr = pDevice->byCCKPwr; return TRUE; } + if (uCH == 0) + return -EINVAL; + switch (uRATE) { case RATE_1M: case RATE_2M: From 27c1026faf863a716c5dcd61e479c10f215dce39 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 11 Nov 2012 15:32:05 +0000 Subject: [PATCH 1855/2357] staging: vt6656: 64 bit fixes: use u32 for QWORD definition. commit a552397d5e4ef0cc0bd3e9595d6acc9a3b381171 upstream. Size of long issues replace with u32. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/ttype.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/vt6656/ttype.h b/drivers/staging/vt6656/ttype.h index 8e9450ef399..0f70562c056 100644 --- a/drivers/staging/vt6656/ttype.h +++ b/drivers/staging/vt6656/ttype.h @@ -29,6 +29,8 @@ #ifndef __TTYPE_H__ #define __TTYPE_H__ +#include + /******* Common definitions and typedefs ***********************************/ typedef int BOOL; @@ -51,8 +53,8 @@ typedef unsigned long DWORD; // 32-bit // which is NOT really a floating point number. typedef union tagUQuadWord { struct { - DWORD dwLowDword; - DWORD dwHighDword; + u32 dwLowDword; + u32 dwHighDword; } u; double DoNotUseThisField; } UQuadWord; From a17de003d22c2dc9ddce8278d3c2be740e15da43 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 11 Nov 2012 15:41:25 +0000 Subject: [PATCH 1856/2357] staging: vt6656: 64 bit fixes : correct all type sizes commit 7730492855a2f9c828599bcd8d62760f96d319e4 upstream. After this patch all BYTE/WORD/DWORD types can be replaced with the appropriate u sizes. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/ttype.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/vt6656/ttype.h b/drivers/staging/vt6656/ttype.h index 0f70562c056..dfbf74713a8 100644 --- a/drivers/staging/vt6656/ttype.h +++ b/drivers/staging/vt6656/ttype.h @@ -44,9 +44,9 @@ typedef int BOOL; /****** Simple typedefs ***************************************************/ -typedef unsigned char BYTE; // 8-bit -typedef unsigned short WORD; // 16-bit -typedef unsigned long DWORD; // 32-bit +typedef u8 BYTE; +typedef u16 WORD; +typedef u32 DWORD; // QWORD is for those situation that we want // an 8-byte-aligned 8 byte long structure @@ -62,8 +62,8 @@ typedef UQuadWord QWORD; // 64-bit /****** Common pointer types ***********************************************/ -typedef unsigned long ULONG_PTR; // 32-bit -typedef unsigned long DWORD_PTR; // 32-bit +typedef u32 ULONG_PTR; +typedef u32 DWORD_PTR; // boolean pointer From 4a3e24ba6b9f06ccfb1f583cad23dc6f508e1752 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 11 Nov 2012 15:45:52 +0000 Subject: [PATCH 1857/2357] staging: vt6656: 64 bit fixes: fix long warning messages. commit b4dc03af5513774277c9c36b12a25cd3f25f4404 upstream. Fixes long warning messages from patch [PATCH 08/14] staging: vt6656: 64 bit fixes : correct all type sizes Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/dpc.c | 4 +-- drivers/staging/vt6656/key.c | 47 ++++++++++++++++++++++++----------- drivers/staging/vt6656/mac.c | 6 +++-- drivers/staging/vt6656/rxtx.c | 18 +++++++++----- 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c index 08021f4d523..4664e9d81d0 100644 --- a/drivers/staging/vt6656/dpc.c +++ b/drivers/staging/vt6656/dpc.c @@ -1238,7 +1238,7 @@ static BOOL s_bHandleRxEncryption ( PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc *pdwRxTSC47_16 = cpu_to_le32(*(PDWORD)(pbyIV + 4)); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %lx\n",*pdwRxTSC47_16); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %x\n", *pdwRxTSC47_16); if (byDecMode == KEY_CTL_TKIP) { *pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV)); } else { @@ -1349,7 +1349,7 @@ static BOOL s_bHostWepRxEncryption ( PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc *pdwRxTSC47_16 = cpu_to_le32(*(PDWORD)(pbyIV + 4)); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %lx\n",*pdwRxTSC47_16); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %x\n", *pdwRxTSC47_16); if (byDecMode == KEY_CTL_TKIP) { *pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV)); diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c index ee62a06a75f..94b3e67658c 100644 --- a/drivers/staging/vt6656/key.c +++ b/drivers/staging/vt6656/key.c @@ -235,7 +235,8 @@ BOOL KeybSetKey( PSKeyItem pKey; unsigned int uKeyIdx; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetKey: %lX\n", dwKeyIndex); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "Enter KeybSetKey: %X\n", dwKeyIndex); j = (MAX_KEY_TABLE-1); for (i=0;i<(MAX_KEY_TABLE-1);i++) { @@ -261,7 +262,9 @@ BOOL KeybSetKey( if ((dwKeyIndex & TRANSMIT_KEY) != 0) { // Group transmit key pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "Group transmit key(R)[%X]: %d\n", + pTable->KeyTable[i].dwGTKeyIndex, i); } pTable->KeyTable[i].wKeyCtl &= 0xFF0F; // clear group key control filed pTable->KeyTable[i].wKeyCtl |= (byKeyDecMode << 4); @@ -302,9 +305,12 @@ BOOL KeybSetKey( } DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %x\n ", + pKey->dwTSC47_16); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", + pKey->wTSC15_0); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %x\n ", + pKey->dwKeyIndex); return (TRUE); } @@ -326,7 +332,9 @@ BOOL KeybSetKey( if ((dwKeyIndex & TRANSMIT_KEY) != 0) { // Group transmit key pTable->KeyTable[j].dwGTKeyIndex = dwKeyIndex; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(N)[%lX]: %d\n", pTable->KeyTable[j].dwGTKeyIndex, j); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "Group transmit key(N)[%X]: %d\n", + pTable->KeyTable[j].dwGTKeyIndex, j); } pTable->KeyTable[j].wKeyCtl &= 0xFF0F; // clear group key control filed pTable->KeyTable[j].wKeyCtl |= (byKeyDecMode << 4); @@ -367,9 +375,11 @@ BOOL KeybSetKey( } DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %x\n ", + pKey->dwTSC47_16); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %x\n ", + pKey->dwKeyIndex); return (TRUE); } @@ -597,7 +607,8 @@ BOOL KeybGetTransmitKey(PSKeyManagement pTable, PBYTE pbyBSSID, DWORD dwKeyType, DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x ", pTable->KeyTable[i].abyBSSID[ii]); } DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"dwGTKeyIndex: %lX\n", pTable->KeyTable[i].dwGTKeyIndex); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"dwGTKeyIndex: %X\n", + pTable->KeyTable[i].dwGTKeyIndex); return (TRUE); } @@ -696,7 +707,10 @@ BOOL KeybSetDefaultKey( if ((dwKeyIndex & TRANSMIT_KEY) != 0) { // Group transmit key pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = dwKeyIndex; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex, MAX_KEY_TABLE-1); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "Group transmit key(R)[%X]: %d\n", + pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex, + MAX_KEY_TABLE-1); } pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl &= 0x7F00; // clear all key control filed @@ -747,9 +761,11 @@ BOOL KeybSetDefaultKey( } DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n", pKey->dwTSC47_16); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %x\n", + pKey->dwTSC47_16); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n", pKey->wTSC15_0); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n", pKey->dwKeyIndex); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %x\n", + pKey->dwKeyIndex); return (TRUE); } @@ -787,7 +803,8 @@ BOOL KeybSetAllGroupKey( PSKeyItem pKey; unsigned int uKeyIdx; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetAllGroupKey: %lX\n", dwKeyIndex); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetAllGroupKey: %X\n", + dwKeyIndex); if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key @@ -804,7 +821,9 @@ BOOL KeybSetAllGroupKey( if ((dwKeyIndex & TRANSMIT_KEY) != 0) { // Group transmit key pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "Group transmit key(R)[%X]: %d\n", + pTable->KeyTable[i].dwGTKeyIndex, i); } pTable->KeyTable[i].wKeyCtl &= 0xFF0F; // clear group key control filed diff --git a/drivers/staging/vt6656/mac.c b/drivers/staging/vt6656/mac.c index af4a29d1477..8fddc7b3930 100644 --- a/drivers/staging/vt6656/mac.c +++ b/drivers/staging/vt6656/mac.c @@ -260,7 +260,8 @@ BYTE pbyData[24]; dwData1 <<= 16; dwData1 |= MAKEWORD(*(pbyAddr+4), *(pbyAddr+5)); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %lX, KeyCtl:%X\n", wOffset, dwData1, wKeyCtl); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %X,"\ + " KeyCtl:%X\n", wOffset, dwData1, wKeyCtl); //VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); //VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); @@ -277,7 +278,8 @@ BYTE pbyData[24]; dwData2 <<= 8; dwData2 |= *(pbyAddr+0); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2. wOffset: %d, Data: %lX\n", wOffset, dwData2); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2. wOffset: %d, Data: %X\n", + wOffset, dwData2); //VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); //VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index fe218689a0a..3beb126e90f 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -377,7 +377,8 @@ s_vFillTxKey ( *(pbyIVHead+3) = (BYTE)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV // Append IV&ExtIV after Mac Header *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFillTxKey()---- pdwExtIV: %lx\n", *pdwExtIV); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFillTxKey()---- pdwExtIV: %x\n", + *pdwExtIV); } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) { pTransmitKey->wTSC15_0++; @@ -1753,7 +1754,8 @@ s_bPacketToWirelessUsb( MIC_vAppend((PBYTE)&(psEthHeader->abyDstAddr[0]), 12); dwMIC_Priority = 0; MIC_vAppend((PBYTE)&dwMIC_Priority, 4); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC KEY: %X, %X\n", + dwMICKey0, dwMICKey1); /////////////////////////////////////////////////////////////////// @@ -2635,7 +2637,8 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb) { MIC_vAppend((PBYTE)&(sEthHeader.abyDstAddr[0]), 12); dwMIC_Priority = 0; MIC_vAppend((PBYTE)&dwMIC_Priority, 4); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"DMA0_tx_8021:MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"DMA0_tx_8021:MIC KEY:"\ + " %X, %X\n", dwMICKey0, dwMICKey1); uLength = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen; @@ -2655,7 +2658,8 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"uLength: %d, %d\n", uLength, cbFrameBodySize); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"cbReqCount:%d, %d, %d, %d\n", cbReqCount, cbHeaderSize, uPadding, cbIVlen); - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC:%x, %x\n", + *pdwMIC_L, *pdwMIC_R); } @@ -3029,7 +3033,8 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"error: KEY is GTK!!~~\n"); } else { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%lX]\n", pTransmitKey->dwKeyIndex); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%X]\n", + pTransmitKey->dwKeyIndex); bNeedEncryption = TRUE; } } @@ -3043,7 +3048,8 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) if (pDevice->bEnableHostWEP) { if ((uNodeIndex != 0) && (pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex & PAIRWISE_KEY)) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%lX]\n", pTransmitKey->dwKeyIndex); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%X]\n", + pTransmitKey->dwKeyIndex); bNeedEncryption = TRUE; } } From 82b2729dac2da860dd30d46753ac18ba7ad8888f Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 11 Nov 2012 15:49:59 +0000 Subject: [PATCH 1858/2357] staging: vt6656: 64bit fixes: key.c/h change unsigned long to u32 commit c0d05b305b00c698b0a8c1b3d46c9380bce9db45 upstream. Fixes long issues. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/key.c | 6 +++--- drivers/staging/vt6656/key.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c index 94b3e67658c..ba3a561a79a 100644 --- a/drivers/staging/vt6656/key.c +++ b/drivers/staging/vt6656/key.c @@ -223,7 +223,7 @@ BOOL KeybSetKey( PSKeyManagement pTable, PBYTE pbyBSSID, DWORD dwKeyIndex, - unsigned long uKeyLength, + u32 uKeyLength, PQWORD pKeyRSC, PBYTE pbyKey, BYTE byKeyDecMode @@ -675,7 +675,7 @@ BOOL KeybSetDefaultKey( void *pDeviceHandler, PSKeyManagement pTable, DWORD dwKeyIndex, - unsigned long uKeyLength, + u32 uKeyLength, PQWORD pKeyRSC, PBYTE pbyKey, BYTE byKeyDecMode @@ -791,7 +791,7 @@ BOOL KeybSetAllGroupKey( void *pDeviceHandler, PSKeyManagement pTable, DWORD dwKeyIndex, - unsigned long uKeyLength, + u32 uKeyLength, PQWORD pKeyRSC, PBYTE pbyKey, BYTE byKeyDecMode diff --git a/drivers/staging/vt6656/key.h b/drivers/staging/vt6656/key.h index f749c7a027d..bd35d39621a 100644 --- a/drivers/staging/vt6656/key.h +++ b/drivers/staging/vt6656/key.h @@ -58,7 +58,7 @@ typedef struct tagSKeyItem { BOOL bKeyValid; - unsigned long uKeyLength; + u32 uKeyLength; BYTE abyKey[MAX_KEY_LEN]; QWORD KeyRSC; DWORD dwTSC47_16; @@ -107,7 +107,7 @@ BOOL KeybSetKey( PSKeyManagement pTable, PBYTE pbyBSSID, DWORD dwKeyIndex, - unsigned long uKeyLength, + u32 uKeyLength, PQWORD pKeyRSC, PBYTE pbyKey, BYTE byKeyDecMode @@ -146,7 +146,7 @@ BOOL KeybSetDefaultKey( void *pDeviceHandler, PSKeyManagement pTable, DWORD dwKeyIndex, - unsigned long uKeyLength, + u32 uKeyLength, PQWORD pKeyRSC, PBYTE pbyKey, BYTE byKeyDecMode @@ -156,7 +156,7 @@ BOOL KeybSetAllGroupKey( void *pDeviceHandler, PSKeyManagement pTable, DWORD dwKeyIndex, - unsigned long uKeyLength, + u32 uKeyLength, PQWORD pKeyRSC, PBYTE pbyKey, BYTE byKeyDecMode From e239d2d4ea630ddec326a99252888b867d196f5b Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 11 Nov 2012 16:07:57 +0000 Subject: [PATCH 1859/2357] staging: vt6656: 64bit fixes: vCommandTimerWait change calculation of timer. commit 70e227790d4ee4590023d8041a3485f8053593fc upstream. The timer appears to run too fast/race on 64 bit systems. Using msecs_to_jiffies seems to cause a deadlock on 64 bit. A calculation of (MSecond * HZ) / 1000 appears to run satisfactory. Change BSSIDInfoCount to u32. After this patch the driver can be successfully connect on little endian 64/32 bit systems. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/wcmd.c | 20 +++++++++++--------- drivers/staging/vt6656/wpa2.h | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c index 78ea121b7e2..31fb96a54cf 100644 --- a/drivers/staging/vt6656/wcmd.c +++ b/drivers/staging/vt6656/wcmd.c @@ -316,17 +316,19 @@ s_MgrMakeProbeRequest( return pTxPacket; } -void vCommandTimerWait(void *hDeviceContext, unsigned int MSecond) +void vCommandTimerWait(void *hDeviceContext, unsigned long MSecond) { - PSDevice pDevice = (PSDevice)hDeviceContext; + PSDevice pDevice = (PSDevice)hDeviceContext; - init_timer(&pDevice->sTimerCommand); - pDevice->sTimerCommand.data = (unsigned long)pDevice; - pDevice->sTimerCommand.function = (TimerFunction)vRunCommand; - // RUN_AT :1 msec ~= (HZ/1024) - pDevice->sTimerCommand.expires = (unsigned int)RUN_AT((MSecond * HZ) >> 10); - add_timer(&pDevice->sTimerCommand); - return; + init_timer(&pDevice->sTimerCommand); + + pDevice->sTimerCommand.data = (unsigned long)pDevice; + pDevice->sTimerCommand.function = (TimerFunction)vRunCommand; + pDevice->sTimerCommand.expires = RUN_AT((MSecond * HZ) / 1000); + + add_timer(&pDevice->sTimerCommand); + + return; } void vRunCommand(void *hDeviceContext) diff --git a/drivers/staging/vt6656/wpa2.h b/drivers/staging/vt6656/wpa2.h index 46c295905b4..c359252a6b0 100644 --- a/drivers/staging/vt6656/wpa2.h +++ b/drivers/staging/vt6656/wpa2.h @@ -45,8 +45,8 @@ typedef struct tagsPMKIDInfo { } PMKIDInfo, *PPMKIDInfo; typedef struct tagSPMKIDCache { - unsigned long BSSIDInfoCount; - PMKIDInfo BSSIDInfo[MAX_PMKID_CACHE]; + u32 BSSIDInfoCount; + PMKIDInfo BSSIDInfo[MAX_PMKID_CACHE]; } SPMKIDCache, *PSPMKIDCache; From fac3e9ef05d5ed0ab475bad3985ff017f5aa79be Mon Sep 17 00:00:00 2001 From: Chris Verges Date: Fri, 21 Dec 2012 01:58:34 -0800 Subject: [PATCH 1860/2357] hwmon: (lm73} Detect and report i2c bus errors commit 0602934f302e016e2ea5dc6951681bfac77455ef upstream. If an LM73 device does not exist on an I2C bus, attempts to communicate with the device result in an error code returned from the i2c read/write functions. The current lm73 driver casts that return value from a s32 type to a s16 type, then converts it to a temperature in celsius. Because negative temperatures are valid, it is difficult to distinguish between an error code printed to the response buffer and a negative temperature recorded by the sensor. The solution is to evaluate the return value from the i2c functions before performing any temperature calculations. If the i2c function did not succeed, the error code should be passed back through the virtual file system layer instead of being printed into the response buffer. Before: $ cat /sys/class/hwmon/hwmon0/device/temp1_input -46 After: $ cat /sys/class/hwmon/hwmon0/device/temp1_input cat: read error: No such device or address Signed-off-by: Chris Verges Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/lm73.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 8fa2632cbba..7272176a9ec 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -49,6 +49,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, struct i2c_client *client = to_i2c_client(dev); long temp; short value; + s32 err; int status = kstrtol(buf, 10, &temp); if (status < 0) @@ -57,8 +58,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, /* Write value */ value = (short) SENSORS_LIMIT(temp/250, (LM73_TEMP_MIN*4), (LM73_TEMP_MAX*4)) << 5; - i2c_smbus_write_word_swapped(client, attr->index, value); - return count; + err = i2c_smbus_write_word_swapped(client, attr->index, value); + return (err < 0) ? err : count; } static ssize_t show_temp(struct device *dev, struct device_attribute *da, @@ -66,11 +67,16 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); + int temp; + + s32 err = i2c_smbus_read_word_swapped(client, attr->index); + if (err < 0) + return err; + /* use integer division instead of equivalent right shift to guarantee arithmetic shift and preserve the sign */ - int temp = ((s16) (i2c_smbus_read_word_swapped(client, - attr->index))*250) / 32; - return sprintf(buf, "%d\n", temp); + temp = (((s16) err) * 250) / 32; + return scnprintf(buf, PAGE_SIZE, "%d\n", temp); } From e80bd5af8e6dc699516696be47bd63b529acc268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Thu, 22 Nov 2012 13:49:14 +0100 Subject: [PATCH 1861/2357] video: mxsfb: fix crash when unblanking the display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6c1ecba8d84841277d68140ef485335d5be28485 upstream. The VDCTRL4 register does not provide the MXS SET/CLR/TOGGLE feature. The write in mxsfb_disable_controller() sets the data_cnt for the LCD DMA to 0 which obviously means the max. count for the LCD DMA and leads to overwriting arbitrary memory when the display is unblanked. Signed-off-by: Lothar Waßmann Acked-by: Juergen Beisert Tested-by: Lauri Hintsala Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- drivers/video/mxsfb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index 4a89f889852..9f8999223f6 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -366,7 +366,8 @@ static void mxsfb_disable_controller(struct fb_info *fb_info) loop--; } - writel(VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4 + REG_CLR); + reg = readl(host->base + LCDC_VDCTRL4); + writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4); clk_disable_unprepare(host->clk); From 2c3a3718da77839d08925a4705802f045faaea06 Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Wed, 5 Dec 2012 16:08:33 -0600 Subject: [PATCH 1862/2357] samsung-laptop: Add quirk for broken acpi_video backlight on N250P commit e04c200f1f2de8eaa2f5af6d97e7e213a1abb424 upstream. BugLink: http://bugs.launchpad.net/bugs/1086921 Signed-off-by: Seth Forshee Signed-off-by: Matthew Garrett Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/samsung-laptop.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index e2a34b42ddc..1afbe5e0a34 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -1506,6 +1506,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { }, .driver_data = &samsung_broken_acpi_video, }, + { + .callback = samsung_dmi_matched, + .ident = "N250P", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), + DMI_MATCH(DMI_BOARD_NAME, "N250P"), + }, + .driver_data = &samsung_broken_acpi_video, + }, { }, }; MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); From cb832988d64ff38921359cce89093abc60f299b5 Mon Sep 17 00:00:00 2001 From: Forrest Liu Date: Mon, 17 Dec 2012 09:55:39 -0500 Subject: [PATCH 1863/2357] ext4: fix extent tree corruption caused by hole punch commit c36575e663e302dbaa4d16b9c72d2c9a913a9aef upstream. When depth of extent tree is greater than 1, logical start value of interior node is not correctly updated in ext4_ext_rm_idx. Signed-off-by: Forrest Liu Signed-off-by: "Theodore Ts'o" Reviewed-by: Ashish Sangwan Signed-off-by: Greg Kroah-Hartman --- fs/ext4/extents.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index c2159854258..852d4c257ac 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2110,13 +2110,14 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block, * removes index from the index block. */ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, - struct ext4_ext_path *path) + struct ext4_ext_path *path, int depth) { int err; ext4_fsblk_t leaf; /* free index block */ - path--; + depth--; + path = path + depth; leaf = ext4_idx_pblock(path->p_idx); if (unlikely(path->p_hdr->eh_entries == 0)) { EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0"); @@ -2141,6 +2142,19 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, ext4_free_blocks(handle, inode, NULL, leaf, 1, EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); + + while (--depth >= 0) { + if (path->p_idx != EXT_FIRST_INDEX(path->p_hdr)) + break; + path--; + err = ext4_ext_get_access(handle, inode, path); + if (err) + break; + path->p_idx->ei_block = (path+1)->p_idx->ei_block; + err = ext4_ext_dirty(handle, inode, path); + if (err) + break; + } return err; } @@ -2474,7 +2488,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, /* if this leaf is free, then we should * remove it from index block above */ if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL) - err = ext4_ext_rm_idx(handle, inode, path + depth); + err = ext4_ext_rm_idx(handle, inode, path, depth); out: return err; @@ -2675,7 +2689,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, /* index is empty, remove it; * handle must be already prepared by the * truncatei_leaf() */ - err = ext4_ext_rm_idx(handle, inode, path + i); + err = ext4_ext_rm_idx(handle, inode, path, i); } /* root level has p_bh == NULL, brelse() eats this */ brelse(path[i].p_bh); From e307ec213a97ddc33ac6921ba37246548245d027 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 20 Dec 2012 00:07:18 -0500 Subject: [PATCH 1864/2357] ext4: check dioread_nolock on remount commit 261cb20cb2f0737a247aaf08dff7eb065e3e5b66 upstream. Currently we allow enabling dioread_nolock mount option on remount for filesystems where blocksize < PAGE_CACHE_SIZE. This isn't really supported so fix the bug by moving the check for blocksize != PAGE_CACHE_SIZE into parse_options(). Change the original PAGE_SIZE to PAGE_CACHE_SIZE along the way because that's what we are really interested in. Signed-off-by: Jan Kara Signed-off-by: "Theodore Ts'o" Reviewed-by: Eric Sandeen Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b1c28f18701..9e4177d6905 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1599,9 +1599,7 @@ static int parse_options(char *options, struct super_block *sb, unsigned int *journal_ioprio, int is_remount) { -#ifdef CONFIG_QUOTA struct ext4_sb_info *sbi = EXT4_SB(sb); -#endif char *p; substring_t args[MAX_OPT_ARGS]; int token; @@ -1650,6 +1648,16 @@ static int parse_options(char *options, struct super_block *sb, } } #endif + if (test_opt(sb, DIOREAD_NOLOCK)) { + int blocksize = + BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); + + if (blocksize < PAGE_CACHE_SIZE) { + ext4_msg(sb, KERN_ERR, "can't mount with " + "dioread_nolock if block size != PAGE_SIZE"); + return 0; + } + } return 1; } @@ -3226,15 +3234,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) clear_opt(sb, DELALLOC); } - blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); - if (test_opt(sb, DIOREAD_NOLOCK)) { - if (blocksize < PAGE_SIZE) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "dioread_nolock if block size != PAGE_SIZE"); - goto failed_mount; - } - } - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0); @@ -3276,6 +3275,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) if (!ext4_feature_set_ok(sb, (sb->s_flags & MS_RDONLY))) goto failed_mount; + blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); if (blocksize < EXT4_MIN_BLOCK_SIZE || blocksize > EXT4_MAX_BLOCK_SIZE) { ext4_msg(sb, KERN_ERR, From b5f0e251211531180989a32ba598968104562c84 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 21 Dec 2012 00:15:51 -0500 Subject: [PATCH 1865/2357] jbd2: fix assertion failure in jbd2_journal_flush() commit d7961c7fa4d2e3c3f12be67e21ba8799b5a7238a upstream. The following race is possible between start_this_handle() and someone calling jbd2_journal_flush(). Process A Process B start_this_handle(). if (journal->j_barrier_count) # false if (!journal->j_running_transaction) { #true read_unlock(&journal->j_state_lock); jbd2_journal_lock_updates() jbd2_journal_flush() write_lock(&journal->j_state_lock); if (journal->j_running_transaction) { # false ... wait for committing trans ... write_unlock(&journal->j_state_lock); ... write_lock(&journal->j_state_lock); if (!journal->j_running_transaction) { # true jbd2_get_transaction(journal, new_transaction); write_unlock(&journal->j_state_lock); goto repeat; # eventually blocks on j_barrier_count > 0 ... J_ASSERT(!journal->j_running_transaction); # fails We fix the race by rechecking j_barrier_count after reacquiring j_state_lock in exclusive mode. Reported-by: yjwsignal@empal.com Signed-off-by: Jan Kara Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/transaction.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index ddcd3549c6c..de8b4cb7c31 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -209,7 +209,8 @@ static int start_this_handle(journal_t *journal, handle_t *handle, if (!new_transaction) goto alloc_transaction; write_lock(&journal->j_state_lock); - if (!journal->j_running_transaction) { + if (!journal->j_running_transaction && + !journal->j_barrier_count) { jbd2_get_transaction(journal, new_transaction); new_transaction = NULL; } From bd06aeb0ff9b22598851276403a1e90f0b4c2d38 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Tue, 25 Dec 2012 14:08:16 -0500 Subject: [PATCH 1866/2357] ext4: do not try to write superblock on ro remount w/o journal commit d096ad0f79a782935d2e06ae8fb235e8c5397775 upstream. When a journal-less ext4 filesystem is mounted on a read-only block device (blockdev --setro will do), each remount (for other, unrelated, flags, like suid=>nosuid etc) results in a series of scary messages from kernel telling about I/O errors on the device. This is becauese of the following code ext4_remount(): if (sbi->s_journal == NULL) ext4_commit_super(sb, 1); at the end of remount procedure, which forces writing (flushing) of a superblock regardless whenever it is dirty or not, if the filesystem is readonly or not, and whenever the device itself is readonly or not. We only need call ext4_commit_super when the file system had been previously mounted read/write. Thanks to Eric Sandeen for help in diagnosing this issue. Signed-off-By: Michael Tokarev Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 9e4177d6905..889577332ba 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4506,7 +4506,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) } ext4_setup_system_zone(sb); - if (sbi->s_journal == NULL) + if (sbi->s_journal == NULL && !(old_sb_flags & MS_RDONLY)) ext4_commit_super(sb, 1); #ifdef CONFIG_QUOTA From ed8e1a67302762d7a1e56e52ea00dc4a36c6cbf5 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 27 Dec 2012 01:42:48 -0500 Subject: [PATCH 1867/2357] ext4: lock i_mutex when truncating orphan inodes commit 721e3eba21e43532e438652dd8f1fcdfce3187e7 upstream. Commit c278531d39 added a warning when ext4_flush_unwritten_io() is called without i_mutex being taken. It had previously not been taken during orphan cleanup since races weren't possible at that point in the mount process, but as a result of this c278531d39, we will now see a kernel WARN_ON in this case. Take the i_mutex in ext4_orphan_cleanup() to suppress this warning. Reported-by: Alexander Beregalov Signed-off-by: "Theodore Ts'o" Reviewed-by: Zheng Liu Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 889577332ba..288f4c61e97 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2120,7 +2120,9 @@ static void ext4_orphan_cleanup(struct super_block *sb, __func__, inode->i_ino, inode->i_size); jbd_debug(2, "truncating inode %lu to %lld bytes\n", inode->i_ino, inode->i_size); + mutex_lock(&inode->i_mutex); ext4_truncate(inode); + mutex_unlock(&inode->i_mutex); nr_truncates++; } else { ext4_msg(sb, KERN_DEBUG, From a0e0e463b14280c8b5cb26114ac321d69c6f2aa5 Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Sat, 12 Jan 2013 06:43:35 -0500 Subject: [PATCH 1868/2357] aoe: do not call bdi_init after blk_alloc_queue commit 0a41409c518083133e79015092585d68915865be upstream, but doesn't apply, so this version is different for older kernels than 3.7.x blk_alloc_queue has already done a bdi_init, so do not bdi_init again in aoeblk_gdalloc. The extra call causes list corruption in the per-CPU backing dev info stats lists. Affected users see console WARNINGs about list_del corruption on percpu_counter_destroy when doing "rmmod aoe" or "aoeflush -a" when AoE targets have been detected and initialized by the system. The patch below applies to v3.6.11, with its v47 aoe driver. It is expected to apply to all currently maintained stable kernels except 3.7.y. A related but different fix has been posted for 3.7.y. References: RedHat bugzilla ticket with original report https://bugzilla.redhat.com/show_bug.cgi?id=853064 LKML discussion of bug and fix http://thread.gmane.org/gmane.linux.kernel/1416336/focus=1416497 Reported-by: Josh Boyer Signed-off-by: Ed Cashin Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoe.h | 2 +- drivers/block/aoe/aoeblk.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index db195abad69..e49ddd0aea1 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,5 +1,5 @@ /* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "47" +#define VERSION "47q" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 321de7b6c44..7eca46349c4 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -276,8 +276,6 @@ aoeblk_gdalloc(void *vp) goto err_mempool; blk_queue_make_request(d->blkq, aoeblk_make_request); d->blkq->backing_dev_info.name = "aoe"; - if (bdi_init(&d->blkq->backing_dev_info)) - goto err_blkq; spin_lock_irqsave(&d->lock, flags); gd->major = AOE_MAJOR; gd->first_minor = d->sysminor * AOE_PARTITIONS; @@ -298,9 +296,6 @@ aoeblk_gdalloc(void *vp) aoedisk_add_sysfs(d); return; -err_blkq: - blk_cleanup_queue(d->blkq); - d->blkq = NULL; err_mempool: mempool_destroy(d->bufpool); err_disk: From 8d00c77065819b747c6fc0b56234afea72f17332 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 10 Oct 2012 00:08:56 +0900 Subject: [PATCH 1869/2357] udf: fix memory leak while allocating blocks during write commit 2fb7d99d0de3fd8ae869f35ab682581d8455887a upstream. Need to brelse the buffer_head stored in cur_epos and next_epos. Signed-off-by: Namjae Jeon Signed-off-by: Ashish Sangwan Signed-off-by: Jan Kara Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- fs/udf/inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 7d752800835..ad68793e46b 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -738,6 +738,8 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, goal, err); if (!newblocknum) { brelse(prev_epos.bh); + brelse(cur_epos.bh); + brelse(next_epos.bh); *err = -ENOSPC; return 0; } @@ -768,6 +770,8 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); brelse(prev_epos.bh); + brelse(cur_epos.bh); + brelse(next_epos.bh); newblock = udf_get_pblock(inode->i_sb, newblocknum, iinfo->i_location.partitionReferenceNum, 0); From 4faf067ae71be3d652e09c3119ce8125498cdf64 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 10 Oct 2012 00:09:12 +0900 Subject: [PATCH 1870/2357] udf: don't increment lenExtents while writing to a hole commit fb719c59bdb4fca86ee1fd1f42ab3735ca12b6b2 upstream. Incrementing lenExtents even while writing to a hole is bad for performance as calls to udf_discard_prealloc and udf_truncate_tail_extent would not return from start if isize != lenExtents Signed-off-by: Namjae Jeon Signed-off-by: Ashish Sangwan Signed-off-by: Jan Kara Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- fs/udf/inode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index ad68793e46b..aa70035fb40 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -574,6 +574,7 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, struct udf_inode_info *iinfo = UDF_I(inode); int goal = 0, pgoal = iinfo->i_location.logicalBlockNum; int lastblock = 0; + bool isBeyondEOF; *err = 0; *new = 0; @@ -653,7 +654,7 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, /* Are we beyond EOF? */ if (etype == -1) { int ret; - + isBeyondEOF = 1; if (count) { if (c) laarr[0] = laarr[1]; @@ -696,6 +697,7 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, endnum = c + 1; lastblock = 1; } else { + isBeyondEOF = 0; endnum = startnum = ((count > 2) ? 2 : count); /* if the current extent is in position 0, @@ -743,7 +745,8 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, *err = -ENOSPC; return 0; } - iinfo->i_lenExtents += inode->i_sb->s_blocksize; + if (isBeyondEOF) + iinfo->i_lenExtents += inode->i_sb->s_blocksize; } /* if the extent the requsted block is located in contains multiple From 9035b20988416173a48ad2f00190846faf15ccb7 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 29 May 2012 15:06:23 -0700 Subject: [PATCH 1871/2357] thp, memcg: split hugepage for memcg oom on cow commit 1f1d06c34f7675026326cd9f39ff91e4555cf355 upstream. On COW, a new hugepage is allocated and charged to the memcg. If the system is oom or the charge to the memcg fails, however, the fault handler will return VM_FAULT_OOM which results in an oom kill. Instead, it's possible to fallback to splitting the hugepage so that the COW results only in an order-0 page being allocated and charged to the memcg which has a higher liklihood to succeed. This is expensive because the hugepage must be split in the page fault handler, but it is much better than unnecessarily oom killing a process. Signed-off-by: David Rientjes Cc: Andrea Arcangeli Cc: Johannes Weiner Acked-by: KAMEZAWA Hiroyuki Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/huge_memory.c | 3 +++ mm/memory.c | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index f0e5306eeb5..caf15b6fa75 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -950,6 +950,8 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, count_vm_event(THP_FAULT_FALLBACK); ret = do_huge_pmd_wp_page_fallback(mm, vma, address, pmd, orig_pmd, page, haddr); + if (ret & VM_FAULT_OOM) + split_huge_page(page); put_page(page); goto out; } @@ -957,6 +959,7 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) { put_page(new_page); + split_huge_page(page); put_page(page); ret |= VM_FAULT_OOM; goto out; diff --git a/mm/memory.c b/mm/memory.c index 024b4afc41f..2f42aab50e9 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3494,6 +3494,7 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, if (unlikely(is_vm_hugetlb_page(vma))) return hugetlb_fault(mm, vma, address, flags); +retry: pgd = pgd_offset(mm, address); pud = pud_alloc(mm, pgd, address); if (!pud) @@ -3507,13 +3508,24 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, pmd, flags); } else { pmd_t orig_pmd = *pmd; + int ret; + barrier(); if (pmd_trans_huge(orig_pmd)) { if (flags & FAULT_FLAG_WRITE && !pmd_write(orig_pmd) && - !pmd_trans_splitting(orig_pmd)) - return do_huge_pmd_wp_page(mm, vma, address, - pmd, orig_pmd); + !pmd_trans_splitting(orig_pmd)) { + ret = do_huge_pmd_wp_page(mm, vma, address, pmd, + orig_pmd); + /* + * If COW results in an oom, the huge pmd will + * have been split, so retry the fault on the + * pte for a smaller charge. + */ + if (unlikely(ret & VM_FAULT_OOM)) + goto retry; + return ret; + } return 0; } } From a0f8b51494051c7bf5d994ac33d2b8ce7c0d5867 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 31 Oct 2012 17:20:50 +0100 Subject: [PATCH 1872/2357] x86, amd: Disable way access filter on Piledriver CPUs commit 2bbf0a1427c377350f001fbc6260995334739ad7 upstream. The Way Access Filter in recent AMD CPUs may hurt the performance of some workloads, caused by aliasing issues in the L1 cache. This patch disables it on the affected CPUs. The issue is similar to that one of last year: http://lkml.indiana.edu/hypermail/linux/kernel/1107.3/00041.html This new patch does not replace the old one, we just need another quirk for newer CPUs. The performance penalty without the patch depends on the circumstances, but is a bit less than the last year's 3%. The workloads affected would be those that access code from the same physical page under different virtual addresses, so different processes using the same libraries with ASLR or multiple instances of PIE-binaries. The code needs to be accessed simultaneously from both cores of the same compute unit. More details can be found here: http://developer.amd.com/Assets/SharedL1InstructionCacheonAMD15hCPU.pdf CPUs affected are anything with the core known as Piledriver. That includes the new parts of the AMD A-Series (aka Trinity) and the just released new CPUs of the FX-Series (aka Vishera). The model numbering is a bit odd here: FX CPUs have model 2, A-Series has model 10h, with possible extensions to 1Fh. Hence the range of model ids. Signed-off-by: Andre Przywara Link: http://lkml.kernel.org/r/1351700450-9277-1-git-send-email-osp@andrep.de Signed-off-by: H. Peter Anvin Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/amd.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 6b4976b0cbb..a9c8a46dd7d 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -612,6 +612,20 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) } } + /* + * The way access filter has a performance penalty on some workloads. + * Disable it on the affected CPUs. + */ + if ((c->x86 == 0x15) && + (c->x86_model >= 0x02) && (c->x86_model < 0x20)) { + u64 val; + + if (!rdmsrl_safe(0xc0011021, &val) && !(val & 0x1E)) { + val |= 0x1E; + checking_wrmsrl(0xc0011021, val); + } + } + cpu_detect_cache_sizes(c); /* Multi core CPU? */ From dc4a02c677c9667dcd7d118cee09a99ede9c64f4 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 4 Dec 2012 23:23:16 +0100 Subject: [PATCH 1873/2357] ACPI : do not use Lid and Sleep button for S5 wakeup commit b7e383046c2c7c13ad928cd7407eafff758ddd4b upstream. When system enters power off, the _PSW of Lid device is enabled. But this may cause the system to reboot instead of power off. A proper way to fix this is to always disable lid wakeup capability for S5. References: https://bugzilla.kernel.org/show_bug.cgi?id=35262 Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki Cc: Joseph Salisbury Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/scan.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index bd3199ce5b2..619a2e4402d 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -789,8 +789,8 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, static void acpi_bus_set_run_wake_flags(struct acpi_device *device) { struct acpi_device_id button_device_ids[] = { - {"PNP0C0D", 0}, {"PNP0C0C", 0}, + {"PNP0C0D", 0}, {"PNP0C0E", 0}, {"", 0}, }; @@ -802,6 +802,11 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) /* Power button, Lid switch always enable wakeup */ if (!acpi_match_device_ids(device, button_device_ids)) { device->wakeup.flags.run_wake = 1; + if (!acpi_match_device_ids(device, &button_device_ids[1])) { + /* Do not use Lid/sleep button for S5 wakeup */ + if (device->wakeup.sleep_state == ACPI_STATE_S5) + device->wakeup.sleep_state = ACPI_STATE_S4; + } device_set_wakeup_capable(&device->dev, true); return; } From ba1de754297ed6756f0a6281f3e41a0ef9ff0d77 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 11 Dec 2012 01:14:11 +0900 Subject: [PATCH 1874/2357] regmap: debugfs: Avoid overflows for very small reads commit db04328c167ff8e7c57f4a3532214aeada3a82fd upstream. If count is less than the size of a register then we may hit integer wraparound when trying to move backwards to check if we're still in the buffer. Instead move the position forwards to check if it's still in the buffer, we are unlikely to be able to allocate a buffer sufficiently big to overflow here. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/base/regmap/regmap-debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 251eb70f83e..8ab1eab90be 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -90,7 +90,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, /* If we're in the region the user is trying to read */ if (p >= *ppos) { /* ...but not beyond it */ - if (buf_pos >= count - 1 - tot_len) + if (buf_pos + 1 + tot_len >= count) break; /* Format the register */ From cbedcb6121561ec79d4cda359e834ca6229786a8 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 1 Jan 2013 21:20:27 +0000 Subject: [PATCH 1875/2357] epoll: prevent missed events on EPOLL_CTL_MOD commit 128dd1759d96ad36c379240f8b9463e8acfd37a1 upstream. EPOLL_CTL_MOD sets the interest mask before calling f_op->poll() to ensure events are not missed. Since the modifications to the interest mask are not protected by the same lock as ep_poll_callback, we need to ensure the change is visible to other CPUs calling ep_poll_callback. We also need to ensure f_op->poll() has an up-to-date view of past events which occured before we modified the interest mask. So this barrier also pairs with the barrier in wq_has_sleeper(). This should guarantee either ep_poll_callback or f_op->poll() (or both) will notice the readiness of a recently-ready/modified item. This issue was encountered by Andreas Voellmy and Junchang(Jason) Wang in: http://thread.gmane.org/gmane.linux.kernel/1408782/ Signed-off-by: Eric Wong Cc: Hans Verkuil Cc: Jiri Olsa Cc: Jonathan Corbet Cc: Al Viro Cc: Davide Libenzi Cc: Hans de Goede Cc: Mauro Carvalho Chehab Cc: David Miller Cc: Eric Dumazet Cc: Andrew Morton Cc: Andreas Voellmy Tested-by: "Junchang(Jason) Wang" Cc: netdev@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/eventpoll.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index c0b3c70ee87..33c9599c14e 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1226,10 +1226,30 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even * otherwise we might miss an event that happens between the * f_op->poll() call and the new event set registering. */ - epi->event.events = event->events; + epi->event.events = event->events; /* need barrier below */ pt._key = event->events; epi->event.data = event->data; /* protected by mtx */ + /* + * The following barrier has two effects: + * + * 1) Flush epi changes above to other CPUs. This ensures + * we do not miss events from ep_poll_callback if an + * event occurs immediately after we call f_op->poll(). + * We need this because we did not take ep->lock while + * changing epi above (but ep_poll_callback does take + * ep->lock). + * + * 2) We also need to ensure we do not miss _past_ events + * when calling f_op->poll(). This barrier also + * pairs with the barrier in wq_has_sleeper (see + * comments for wq_has_sleeper). + * + * This barrier will now guarantee ep_poll_callback or f_op->poll + * (or both) will notice the readiness of an item. + */ + smp_mb(); + /* * Get current event bits. We can safely use the file* here because * its usage count has been increased by the caller of this function. From 48f678d27107d31f2ec9ac9c6230883dfaebccb1 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 24 Nov 2012 06:15:57 +0100 Subject: [PATCH 1876/2357] HID: add quirk for Freescale i.MX23 ROM recovery commit 436136cec650d661eb662fcb508a99878606d050 upstream. The USB recovery mode present in i.MX23 ROM emulates USB HID. It needs this quirk to behave properly. Even if the official branding of the chip is Freescale i.MX23, I named it Sigmatel STMP3780 since that's what the chip really is and it even reports itself as STMP3780. Signed-off-by: Marek Vasut Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 41ad6ff548c..55838995eca 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -664,6 +664,9 @@ #define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f #define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002 +#define USB_VENDOR_ID_SIGMATEL 0x066F +#define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780 + #define USB_VENDOR_ID_SKYCABLE 0x1223 #define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index dc9697c2764..9fea98f7c37 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -78,6 +78,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET }, From 4548554e7ca5192d5905a11219afb7de439b17d8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Jan 2013 21:18:12 +0000 Subject: [PATCH 1877/2357] ASoC: wm2000: Fix sense of speech clarity enable commit 267f8fa2e1eef0612b2007e1f1846bcbc35cc1fa upstream. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm2000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index ae6f26f25a6..bb9f0703748 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -190,9 +190,9 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY); if (wm2000->speech_clarity) - ret &= ~WM2000_SPEECH_CLARITY; - else ret |= WM2000_SPEECH_CLARITY; + else + ret &= ~WM2000_SPEECH_CLARITY; wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret); wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33); From bc85643d2ff065c0303a1a0edfd748da4805295e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Dec 2012 16:28:37 +0800 Subject: [PATCH 1878/2357] ASoC: wm2200: Fix setting dai format in wm2200_set_fmt commit 2a5f431592343b78896013b055582f94c12a5049 upstream. According to the defines in wm2200.h: /* * R1284 (0x504) - Audio IF 1_5 */ We should not left shift 1 bit for fmt_val when setting dai format. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c8bff6da532..201fc583217 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1440,7 +1440,7 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV, lrclk); snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5, - WM2200_AIF1_FMT_MASK << 1, fmt_val << 1); + WM2200_AIF1_FMT_MASK, fmt_val); return 0; } From 6d445a511e85a702a63197a2034c21c1461a1212 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Jan 2013 10:48:10 +0000 Subject: [PATCH 1879/2357] ASoC: wm2200: Remove DSP B and left justified AIF modes commit 0cc411b934c4317b363d1af993549f391852b980 upstream. These are not supported. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm2200.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 201fc583217..86b84a18ba2 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1380,15 +1380,9 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_DSP_A: fmt_val = 0; break; - case SND_SOC_DAIFMT_DSP_B: - fmt_val = 1; - break; case SND_SOC_DAIFMT_I2S: fmt_val = 2; break; - case SND_SOC_DAIFMT_LEFT_J: - fmt_val = 3; - break; default: dev_err(codec->dev, "Unsupported DAI format %d\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); From d6ec6c9385c874cc8bdeba4346cf6275a6c811ca Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Jan 2013 21:06:08 +0000 Subject: [PATCH 1880/2357] ASoC: wm5100: Remove DSP B and left justified formats commit 5f960294e2031d12f10c8488c3446fecbf59628d upstream. These are not supported Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm5100.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index b9c185ce64e..a8d03ab5ea2 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1296,15 +1296,9 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_DSP_A: mask = 0; break; - case SND_SOC_DAIFMT_DSP_B: - mask = 1; - break; case SND_SOC_DAIFMT_I2S: mask = 2; break; - case SND_SOC_DAIFMT_LEFT_J: - mask = 3; - break; default: dev_err(codec->dev, "Unsupported DAI format %d\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); From c876baa8a8eda4a9ffcc6bdc144bb9d0fc3397a0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 11 Jan 2013 12:08:56 +0100 Subject: [PATCH 1881/2357] udldrmfb: Fix EDID not working with monitors with EDID extension blocks commit c930812fe5ebe725760422c9c351d1f6fde1502d upstream. udldrmfb only reads the main EDID block, and if that advertises extensions the drm_edid code expects them to be present, and starts reading beyond the buffer udldrmfb passes it. Although it may be possible to read more EDID info with the udl we simpy don't know how, and even if trial and error gets it working on one device, that is no guarantee it will work on other revisions. So this patch does a simple fix in the form of patching the EDID info to report 0 extension blocks, this fixes udldrmfb only doing 1024x768 on monitors with EDID extension blocks. Signed-off-by: Hans de Goede Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_connector.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 8d9dc44f1f9..1230bc0ffb0 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -59,6 +59,14 @@ static int udl_get_modes(struct drm_connector *connector) connector->display_info.raw_edid = (char *)edid; + /* + * We only read the main block, but if the monitor reports extension + * blocks then the drm edid code expects them to be present, so patch + * the extension count to 0. + */ + edid->checksum += edid->extensions; + edid->extensions = 0; + drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); connector->display_info.raw_edid = NULL; From b756902ec26992d285937d1b706fc50c9743903d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 11 Jan 2013 12:08:57 +0100 Subject: [PATCH 1882/2357] udldrmfb: udl_get_edid: usb_control_msg buffer must not be on the stack commit 242187b362555849e8c971dfbbfd55f8bd9fa717 upstream. The buffer passed to usb_control_msg may end up in scatter-gather list, and may thus not be on the stack. Having it on the stack usually works on x86, but not on other archs. Signed-off-by: Hans de Goede Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_connector.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 1230bc0ffb0..b7780dd9132 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -22,13 +22,17 @@ static u8 *udl_get_edid(struct udl_device *udl) { u8 *block; - char rbuf[3]; + char *rbuf; int ret, i; block = kmalloc(EDID_LENGTH, GFP_KERNEL); if (block == NULL) return NULL; + rbuf = kmalloc(2, GFP_KERNEL); + if (rbuf == NULL) + goto error; + for (i = 0; i < EDID_LENGTH; i++) { ret = usb_control_msg(udl->ddev->usbdev, usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02), @@ -42,10 +46,12 @@ static u8 *udl_get_edid(struct udl_device *udl) block[i] = rbuf[1]; } + kfree(rbuf); return block; error: kfree(block); + kfree(rbuf); return NULL; } From f9df20c6468862772f8f63b72b021f62a492548f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 11 Jan 2013 12:08:58 +0100 Subject: [PATCH 1883/2357] udldrmfb: udl_get_edid: drop unneeded i-- commit 7b4cf994e4c6ba48872bb25253cc393b7fb74c82 upstream. This is a left-over from when udl_get_edid returned the amount of bytes successfully read, which it no longer does. Signed-off-by: Hans de Goede Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_connector.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index b7780dd9132..32342247d91 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -40,7 +40,6 @@ static u8 *udl_get_edid(struct udl_device *udl) HZ); if (ret < 1) { DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); - i--; goto error; } block[i] = rbuf[1]; From b66c35dd91a7476f42134fb44250d24f68181c7b Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Mon, 7 Jan 2013 13:55:12 -0800 Subject: [PATCH 1884/2357] ALSA: pxa27x: fix ac97 cold reset commit 41b645c8624df6ace020a8863ad1449d69140f7d upstream. Cold reset on the pxa27x currently fails and pxa2xx_ac97_try_cold_reset: cold reset timeout (GSR=0x44) appears in the kernel log. Through trial-and-error (the pxa270 developer's manual is mostly incoherent on the topic of ac97 reset), I got cold reset to complete by setting the WARM_RST bit in the GCR register (and later noticed that pxa3xx does this for cold reset as well). Also, a timeout loop is needed to wait for the reset to complete. Tested on a palm treo 680 machine. Signed-off-by: Mike Dunn Acked-by: Igor Grinberg Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/arm/pxa2xx-ac97-lib.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 48d7c0aa507..8cfb2c0efcb 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -148,6 +148,8 @@ static inline void pxa_ac97_warm_pxa27x(void) static inline void pxa_ac97_cold_pxa27x(void) { + unsigned int timeout; + GCR &= GCR_COLD_RST; /* clear everything but nCRST */ GCR &= ~GCR_COLD_RST; /* then assert nCRST */ @@ -157,8 +159,10 @@ static inline void pxa_ac97_cold_pxa27x(void) clk_enable(ac97conf_clk); udelay(5); clk_disable(ac97conf_clk); - GCR = GCR_COLD_RST; - udelay(50); + GCR = GCR_COLD_RST | GCR_WARM_RST; + timeout = 100; /* wait for the codec-ready bit to be set */ + while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(1); } #endif From 1d757c9abbfb218c89d6b0586ff89b4032a3601d Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Mon, 7 Jan 2013 13:55:13 -0800 Subject: [PATCH 1885/2357] ALSA: pxa27x: fix ac97 warm reset commit 3b4bc7bccc7857274705b05cf81a0c72cfd0b0dd upstream. This patch fixes some code that implements a work-around to a hardware bug in the ac97 controller on the pxa27x. A bug in the controller's warm reset functionality requires that the mfp used by the controller as the AC97_nRESET line be temporarily reconfigured as a generic output gpio (AF0) and manually held high for the duration of the warm reset cycle. This is what was done in the original code, but it was broken long ago by commit fb1bf8cd ([ARM] pxa: introduce processor specific pxa27x_assert_ac97reset()) which changed the mfp to a GPIO input instead of a high output. The fix requires the ac97 controller to obtain the gpio via gpio_request_one(), with arguments that configure the gpio as an output initially driven high. Tested on a palm treo 680 machine. Reportedly, this broken code only prevents a warm reset on hardware that lacks a pull-up on the line, which appears to be the case for me. Signed-off-by: Mike Dunn Signed-off-by: Igor Grinberg Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-pxa/include/mach/mfp-pxa27x.h | 3 +++ arch/arm/mach-pxa/pxa27x.c | 4 ++-- sound/arm/pxa2xx-ac97-lib.c | 18 +++++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h index a65867209aa..b4eb3daf037 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h @@ -462,6 +462,9 @@ GPIO76_LCD_PCLK, \ GPIO77_LCD_BIAS +/* these enable a work-around for a hw bug in pxa27x during ac97 warm reset */ +#define GPIO113_AC97_nRESET_GPIO_HIGH MFP_CFG_OUT(GPIO113, AF0, DEFAULT) +#define GPIO95_AC97_nRESET_GPIO_HIGH MFP_CFG_OUT(GPIO95, AF0, DEFAULT) extern int keypad_set_wake(unsigned int on); #endif /* __ASM_ARCH_MFP_PXA27X_H */ diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 4726c246dcd..a2fe795bae1 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -47,9 +47,9 @@ void pxa27x_clear_otgph(void) EXPORT_SYMBOL(pxa27x_clear_otgph); static unsigned long ac97_reset_config[] = { - GPIO113_GPIO, + GPIO113_AC97_nRESET_GPIO_HIGH, GPIO113_AC97_nRESET, - GPIO95_GPIO, + GPIO95_AC97_nRESET_GPIO_HIGH, GPIO95_AC97_nRESET, }; diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 8cfb2c0efcb..bd3ba8812e1 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -344,8 +345,21 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) } if (cpu_is_pxa27x()) { - /* Use GPIO 113 as AC97 Reset on Bulverde */ + /* + * This gpio is needed for a work-around to a bug in the ac97 + * controller during warm reset. The direction and level is set + * here so that it is an output driven high when switching from + * AC97_nRESET alt function to generic gpio. + */ + ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH, + "pxa27x ac97 reset"); + if (ret < 0) { + pr_err("%s: gpio_request_one() failed: %d\n", + __func__, ret); + goto err_conf; + } pxa27x_assert_ac97reset(reset_gpio, 0); + ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); if (IS_ERR(ac97conf_clk)) { ret = PTR_ERR(ac97conf_clk); @@ -388,6 +402,8 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); void pxa2xx_ac97_hw_remove(struct platform_device *dev) { + if (cpu_is_pxa27x()) + gpio_free(reset_gpio); GCR |= GCR_ACLINK_OFF; free_irq(IRQ_AC97, NULL); if (ac97conf_clk) { From e7b67acb37508a8a173038a928816d9e826b6363 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Tue, 4 Dec 2012 15:59:55 +0000 Subject: [PATCH 1886/2357] staging: comedi: prevent auto-unconfig of manually configured devices commit 7d3135af399e92cf4c9bbc5f86b6c140aab3b88c upstream. When a low-level comedi driver auto-configures a device, a `struct comedi_dev_file_info` is allocated (as well as a `struct comedi_device`) by `comedi_alloc_board_minor()`. A pointer to the hardware `struct device` is stored as a cookie in the `struct comedi_dev_file_info`. When the low-level comedi driver auto-unconfigures the device, `comedi_auto_unconfig()` uses the cookie to find the `struct comedi_dev_file_info` so it can detach the comedi device from the driver, clean it up and free it. A problem arises if the user manually unconfigures and reconfigures the comedi device using the `COMEDI_DEVCONFIG` ioctl so that is no longer associated with the original hardware device. The problem is that the cookie is not cleared, so that a call to `comedi_auto_unconfig()` from the low-level driver will still find it, detach it, clean it up and free it. Stop this problem occurring by always clearing the `hardware_device` cookie in the `struct comedi_dev_file_info` whenever the `COMEDI_DEVCONFIG` ioctl call is successful. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index b719460c4ec..3fd9772d7a7 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -138,6 +138,9 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, if (cmd == COMEDI_DEVCONFIG) { rc = do_devconfig_ioctl(dev, (struct comedi_devconfig __user *)arg); + if (rc == 0) + /* Evade comedi_auto_unconfig(). */ + dev_file_info->hardware_device = NULL; goto done; } From a72725d609f46f4099fb2f4bbfb128d2ce84074e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Piel?= Date: Wed, 19 Dec 2012 13:03:13 +0100 Subject: [PATCH 1887/2357] staging: comedi: fix minimum AO period for NI 625x and NI 628x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 34b55d8c48f4f76044d8f4d6ec3dc786cf210312 upstream. The minimum period was set to 357 ns, while the divider for these boards is 50 ns. This prevented to output at maximum speed as ni_ao_cmdtest() would return 357 but would not accept it. Not sure why it was set to 357 ns (this was done before the git history, which starts 5 years ago). My guess is that it comes from reading the specification stating a 2.8 MHz rate (~ 357 ns). The latest specification states a 2.86 MHz rate (~ 350 ns), which makes a lot more sense. Tested on a pci-6251. Signed-off-by: Éric Piel Acked-By: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ni_pcimio.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 27baefa32b1..59c1f88894a 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -1023,7 +1023,7 @@ static const struct ni_board_struct ni_boards[] = { .ao_range_table = &range_ni_M_625x_ao, .reg_type = ni_reg_625x, .ao_unipolar = 0, - .ao_speed = 357, + .ao_speed = 350, .num_p0_dio_channels = 8, .caldac = {caldac_none}, .has_8255 = 0, @@ -1042,7 +1042,7 @@ static const struct ni_board_struct ni_boards[] = { .ao_range_table = &range_ni_M_625x_ao, .reg_type = ni_reg_625x, .ao_unipolar = 0, - .ao_speed = 357, + .ao_speed = 350, .num_p0_dio_channels = 8, .caldac = {caldac_none}, .has_8255 = 0, @@ -1061,7 +1061,7 @@ static const struct ni_board_struct ni_boards[] = { .ao_range_table = &range_ni_M_625x_ao, .reg_type = ni_reg_625x, .ao_unipolar = 0, - .ao_speed = 357, + .ao_speed = 350, .num_p0_dio_channels = 8, .caldac = {caldac_none}, .has_8255 = 0, @@ -1097,7 +1097,7 @@ static const struct ni_board_struct ni_boards[] = { .ao_range_table = &range_ni_M_625x_ao, .reg_type = ni_reg_625x, .ao_unipolar = 0, - .ao_speed = 357, + .ao_speed = 350, .num_p0_dio_channels = 32, .caldac = {caldac_none}, .has_8255 = 0, @@ -1116,7 +1116,7 @@ static const struct ni_board_struct ni_boards[] = { .ao_range_table = &range_ni_M_625x_ao, .reg_type = ni_reg_625x, .ao_unipolar = 0, - .ao_speed = 357, + .ao_speed = 350, .num_p0_dio_channels = 32, .caldac = {caldac_none}, .has_8255 = 0, @@ -1152,7 +1152,7 @@ static const struct ni_board_struct ni_boards[] = { .ao_range_table = &range_ni_M_628x_ao, .reg_type = ni_reg_628x, .ao_unipolar = 1, - .ao_speed = 357, + .ao_speed = 350, .num_p0_dio_channels = 8, .caldac = {caldac_none}, .has_8255 = 0, @@ -1171,7 +1171,7 @@ static const struct ni_board_struct ni_boards[] = { .ao_range_table = &range_ni_M_628x_ao, .reg_type = ni_reg_628x, .ao_unipolar = 1, - .ao_speed = 357, + .ao_speed = 350, .num_p0_dio_channels = 8, .caldac = {caldac_none}, .has_8255 = 0, @@ -1207,7 +1207,7 @@ static const struct ni_board_struct ni_boards[] = { .ao_range_table = &range_ni_M_628x_ao, .reg_type = ni_reg_628x, .ao_unipolar = 1, - .ao_speed = 357, + .ao_speed = 350, .num_p0_dio_channels = 32, .caldac = {caldac_none}, .has_8255 = 0, From 9a194265172c86fa49299c9fcce7fe9590d66220 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 4 Jan 2013 11:33:21 +0000 Subject: [PATCH 1888/2357] staging: comedi: comedi_test: fix race when cancelling command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c0729eeefdcd76db338f635162bf0739fd2c5f6f upstream. Éric Piel reported a kernel oops in the "comedi_test" module. It was a NULL pointer dereference within `waveform_ai_interrupt()` (actually a timer function) that sometimes occurred when a running asynchronous command is cancelled (either by the `COMEDI_CANCEL` ioctl or by closing the device file). This seems to be a race between the caller of `waveform_ai_cancel()` which on return from that function goes and tears down the running command, and the timer function which uses the command. In particular, `async->cmd.chanlist` gets freed (and the pointer set to NULL) by `do_become_nonbusy()` in "comedi_fops.c" but a previously scheduled `waveform_ai_interrupt()` timer function will dereference that pointer regardless, leading to the oops. Fix it by replacing the `del_timer()` call in `waveform_ai_cancel()` with `del_timer_sync()`. Signed-off-by: Ian Abbott Reported-by: Éric Piel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/comedi_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index a804742b802..2567f9ab416 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -461,7 +461,7 @@ static int waveform_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { devpriv->timer_running = 0; - del_timer(&devpriv->timer); + del_timer_sync(&devpriv->timer); return 0; } From bef86636513cdbdbdd8eeb53ad4403a3e71e5e94 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 29 Dec 2012 11:36:53 -0600 Subject: [PATCH 1889/2357] staging: r8712u: Add new device ID commit da849a92d3bafaf24d770e971c2c9e5c3f60b5d1 upstream. The ISY IWL 1000 USB WLAN stick with USB ID 050d:11f1 is a clone of the Belkin F7D1101 V1 device. Reported-by: Thomas Hartmann Signed-off-by: Larry Finger Cc: Thomas Hartmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/usb_intf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 2c80745a446..7b3ae00ac54 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -66,6 +66,8 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = { {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ /* Belkin */ {USB_DEVICE(0x050D, 0x945A)}, + /* ISY IWL - Belkin clone */ + {USB_DEVICE(0x050D, 0x11F1)}, /* Corega */ {USB_DEVICE(0x07AA, 0x0047)}, /* D-Link */ From 16557f3521d980a2b88c53f9cf3c7d36fbb308a5 Mon Sep 17 00:00:00 2001 From: Nickolai Zeldovich Date: Sat, 5 Jan 2013 14:17:45 -0500 Subject: [PATCH 1890/2357] staging: speakup: avoid out-of-range access in synth_init() commit ae428655b826f2755a8101b27beda42a275ef8ad upstream. Check that array index is in-bounds before accessing the synths[] array. Signed-off-by: Nickolai Zeldovich Cc: Samuel Thibault Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/synth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index 331eae78870..217fd4a49bd 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c @@ -342,7 +342,7 @@ int synth_init(char *synth_name) mutex_lock(&spk_mutex); /* First, check if we already have it loaded. */ - for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) + for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) if (strcmp(synths[i]->name, synth_name) == 0) synth = synths[i]; From 95afecc15423d5ceaeaf26b943cb8891f9e36e26 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Mon, 7 Jan 2013 22:03:51 +0100 Subject: [PATCH 1891/2357] staging: speakup: avoid out-of-range access in synth_add() commit 6102c48bd421074a33e102f2ebda3724e8d275f9 upstream. Check that array index is in-bounds before accessing the synths[] array. Signed-off-by: Samuel Thibault Cc: Nickolai Zeldovich Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/synth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index 217fd4a49bd..5710fc582be 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c @@ -423,7 +423,7 @@ int synth_add(struct spk_synth *in_synth) int i; int status = 0; mutex_lock(&spk_mutex); - for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) + for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) /* synth_remove() is responsible for rotating the array down */ if (in_synth == synths[i]) { mutex_unlock(&spk_mutex); From 4a3b5681d6b64611375903695481641debd1c308 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 8 Jan 2013 18:41:01 -0500 Subject: [PATCH 1892/2357] radeon/kms: force rn50 chip to always report connected on analog output commit 51861d4eebc2ddc25c77084343d060fa79f6e291 upstream. Those rn50 chip are often connected to console remoting hw and load detection often fails with those. Just don't try to load detect and report connect. Signed-off-by: Jerome Glisse Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index d92f483fed4..53b07a3a8bb 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -617,6 +617,14 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc enum drm_connector_status found = connector_status_disconnected; bool color = true; + /* just don't bother on RN50 those chip are often connected to remoting + * console hw and often we get failure to load detect those. So to make + * everyone happy report the encoder as always connected. + */ + if (ASIC_IS_RN50(rdev)) { + return connector_status_connected; + } + /* save the regs we need */ vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); From 5ca99e71a9a6cf33a217690f5d87bc0129d1effd Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 11 Dec 2012 10:48:23 +0100 Subject: [PATCH 1893/2357] mac80211: fix ibss scanning commit 34bcf71502413f8903ade93746f2d0f04b937a78 upstream. Do not scan on no-IBSS and disabled channels in IBSS mode. Doing this can trigger Microcode errors on iwlwifi and iwlegacy drivers. Also rename ieee80211_request_internal_scan() function since it is only used in IBSS mode and simplify calling it from ieee80211_sta_find_ibss(). This patch should address: https://bugzilla.redhat.com/show_bug.cgi?id=883414 https://bugzilla.kernel.org/show_bug.cgi?id=49411 Reported-by: Jesse Kahtava Reported-by: Mikko Rapeli Signed-off-by: Stanislaw Gruszka Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ibss.c | 9 ++++----- net/mac80211/ieee80211_i.h | 6 +++--- net/mac80211/scan.c | 34 ++++++++++++++++++++++++---------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 7c51bae7f1c..50191a30207 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -664,8 +664,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " "IBSS networks with same SSID (merge)\n", sdata->name); - ieee80211_request_internal_scan(sdata, - ifibss->ssid, ifibss->ssid_len, NULL); + ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, + NULL); } static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) @@ -772,9 +772,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " "join\n", sdata->name); - ieee80211_request_internal_scan(sdata, - ifibss->ssid, ifibss->ssid_len, - ifibss->fixed_channel ? ifibss->channel : NULL); + ieee80211_request_ibss_scan(sdata, ifibss->ssid, + ifibss->ssid_len, chan); } else { int interval = IEEE80211_SCAN_INTERVAL; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 498e87bcb3e..f8b5e75be8c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1233,9 +1233,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* scan/BSS handling */ void ieee80211_scan_work(struct work_struct *work); -int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, - const u8 *ssid, u8 ssid_len, - struct ieee80211_channel *chan); +int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, + const u8 *ssid, u8 ssid_len, + struct ieee80211_channel *chan); int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req); void ieee80211_scan_cancel(struct ieee80211_local *local); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index c70e1767713..e95d494f36e 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -761,9 +761,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, return res; } -int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, - const u8 *ssid, u8 ssid_len, - struct ieee80211_channel *chan) +int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, + const u8 *ssid, u8 ssid_len, + struct ieee80211_channel *chan) { struct ieee80211_local *local = sdata->local; int ret = -EBUSY; @@ -777,22 +777,36 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, /* fill internal scan request */ if (!chan) { - int i, nchan = 0; + int i, max_n; + int n_ch = 0; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!local->hw.wiphy->bands[band]) continue; - for (i = 0; - i < local->hw.wiphy->bands[band]->n_channels; - i++) { - local->int_scan_req->channels[nchan] = + + max_n = local->hw.wiphy->bands[band]->n_channels; + for (i = 0; i < max_n; i++) { + struct ieee80211_channel *tmp_ch = &local->hw.wiphy->bands[band]->channels[i]; - nchan++; + + if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_DISABLED)) + continue; + + local->int_scan_req->channels[n_ch] = tmp_ch; + n_ch++; } } - local->int_scan_req->n_channels = nchan; + if (WARN_ON_ONCE(n_ch == 0)) + goto unlock; + + local->int_scan_req->n_channels = n_ch; } else { + if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_DISABLED))) + goto unlock; + local->int_scan_req->channels[0] = chan; local->int_scan_req->n_channels = 1; } From 848842e67d24fed13a2aece3d03e235267e5a3a6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Dec 2012 23:08:52 +0100 Subject: [PATCH 1894/2357] mac80211: use del_timer_sync for final sta cleanup timer deletion commit a56f992cdabc63f56b4b142885deebebf936ff76 upstream. This is a very old bug, but there's nothing that prevents the timer from running while the module is being removed when we only do del_timer() instead of del_timer_sync(). The timer should normally not be running at this point, but it's not clearly impossible (or we could just remove this.) Tested-by: Ben Greear Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/sta_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 6d25d7796fc..e2e0e0bc662 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -844,7 +844,7 @@ void sta_info_init(struct ieee80211_local *local) void sta_info_stop(struct ieee80211_local *local) { - del_timer(&local->sta_cleanup); + del_timer_sync(&local->sta_cleanup); sta_info_flush(local, NULL); } From 99dd9a98065129261e24ad44f41b26e3a841f654 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 2 Jan 2013 16:07:35 -0800 Subject: [PATCH 1895/2357] mwifiex: check wait_event_interruptible return value commit 9c969d8ccb1e17bd20742f4ac9f00c1a64487234 upstream. wait_event_interruptible function returns -ERESTARTSYS if it's interrupted by a signal. Driver should check the return value and handle this case properly. In mwifiex_wait_queue_complete() routine, as we are now checking wait_event_interruptible return value, the condition check is not required. Also, we have removed mwifiex_cancel_pending_ioctl() call to avoid a chance of sending second command to FW by other path as soon as we clear current command node. FW can not handle two commands simultaneously. Signed-off-by: Bing Zhao Signed-off-by: Amitkumar Karwar Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mwifiex/sta_ioctl.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index d7b11defafe..4fb146a8fac 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -53,7 +53,6 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, */ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) { - bool cancel_flag = false; int status; struct cmd_ctrl_node *cmd_queued; @@ -70,14 +69,11 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) queue_work(adapter->workqueue, &adapter->main_work); /* Wait for completion */ - wait_event_interruptible(adapter->cmd_wait_q.wait, - *(cmd_queued->condition)); - if (!*(cmd_queued->condition)) - cancel_flag = true; - - if (cancel_flag) { - mwifiex_cancel_pending_ioctl(adapter); - dev_dbg(adapter->dev, "cmd cancel\n"); + status = wait_event_interruptible(adapter->cmd_wait_q.wait, + *(cmd_queued->condition)); + if (status) { + dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status); + return status; } status = adapter->cmd_wait_q.status; @@ -436,8 +432,11 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) return false; } - wait_event_interruptible(adapter->hs_activate_wait_q, - adapter->hs_activate_wait_q_woken); + if (wait_event_interruptible(adapter->hs_activate_wait_q, + adapter->hs_activate_wait_q_woken)) { + dev_err(adapter->dev, "hs_activate_wait_q terminated\n"); + return false; + } return true; } From 16fc9b0aa12763fb66e1bd702714c7e3da38cd0f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 20 Dec 2012 15:55:01 -0600 Subject: [PATCH 1896/2357] b43: Fix firmware loading when driver is built into the kernel commit 5e20a4b53094651d80f856ff55a916b999dbb57a upstream. Recent versions of udev cause synchronous firmware loading from the probe routine to fail because the request to user space would time out. The original fix for b43 (commit 6b6fa58) moved the firmware load from the probe routine to a work queue, but it still used synchronous firmware loading. This method is OK when b43 is built as a module; however, it fails when the driver is compiled into the kernel. This version changes the code to load the initial firmware file using request_firmware_nowait(). A completion event is used to hold the work queue until that file is available. This driver reads several firmware files - the remainder can be read synchronously. On some test systems, the async read fails; however, a following synch read works, thus the async failure falls through to the sync try. Reported-and-Tested by: Felix Janda Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/b43/b43.h | 5 +++ drivers/net/wireless/b43/main.c | 54 +++++++++++++++++++++++++-------- drivers/net/wireless/b43/main.h | 5 ++- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 67c13af6f20..05cb5f6b8d4 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "debugfs.h" @@ -718,6 +719,10 @@ enum b43_firmware_file_type { struct b43_request_fw_context { /* The device we are requesting the fw for. */ struct b43_wldev *dev; + /* a completion event structure needed if this call is asynchronous */ + struct completion fw_load_complete; + /* a pointer to the firmware object */ + const struct firmware *blob; /* The type of firmware to request. */ enum b43_firmware_file_type req_type; /* Error messages for each firmware type. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 4e465c5b2df..14fd2caa1f9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2088,11 +2088,18 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) b43warn(wl, text); } +static void b43_fw_cb(const struct firmware *firmware, void *context) +{ + struct b43_request_fw_context *ctx = context; + + ctx->blob = firmware; + complete(&ctx->fw_load_complete); +} + int b43_do_request_fw(struct b43_request_fw_context *ctx, const char *name, - struct b43_firmware_file *fw) + struct b43_firmware_file *fw, bool async) { - const struct firmware *blob; struct b43_fw_header *hdr; u32 size; int err; @@ -2131,11 +2138,31 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, B43_WARN_ON(1); return -ENOSYS; } - err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev); + if (async) { + /* do this part asynchronously */ + init_completion(&ctx->fw_load_complete); + err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, + ctx->dev->dev->dev, GFP_KERNEL, + ctx, b43_fw_cb); + if (err < 0) { + pr_err("Unable to load firmware\n"); + return err; + } + /* stall here until fw ready */ + wait_for_completion(&ctx->fw_load_complete); + if (ctx->blob) + goto fw_ready; + /* On some ARM systems, the async request will fail, but the next sync + * request works. For this reason, we dall through here + */ + } + err = request_firmware(&ctx->blob, ctx->fwname, + ctx->dev->dev->dev); if (err == -ENOENT) { snprintf(ctx->errors[ctx->req_type], sizeof(ctx->errors[ctx->req_type]), - "Firmware file \"%s\" not found\n", ctx->fwname); + "Firmware file \"%s\" not found\n", + ctx->fwname); return err; } else if (err) { snprintf(ctx->errors[ctx->req_type], @@ -2144,14 +2171,15 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, ctx->fwname, err); return err; } - if (blob->size < sizeof(struct b43_fw_header)) +fw_ready: + if (ctx->blob->size < sizeof(struct b43_fw_header)) goto err_format; - hdr = (struct b43_fw_header *)(blob->data); + hdr = (struct b43_fw_header *)(ctx->blob->data); switch (hdr->type) { case B43_FW_TYPE_UCODE: case B43_FW_TYPE_PCM: size = be32_to_cpu(hdr->size); - if (size != blob->size - sizeof(struct b43_fw_header)) + if (size != ctx->blob->size - sizeof(struct b43_fw_header)) goto err_format; /* fallthrough */ case B43_FW_TYPE_IV: @@ -2162,7 +2190,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, goto err_format; } - fw->data = blob; + fw->data = ctx->blob; fw->filename = name; fw->type = ctx->req_type; @@ -2172,7 +2200,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, snprintf(ctx->errors[ctx->req_type], sizeof(ctx->errors[ctx->req_type]), "Firmware file \"%s\" format error.\n", ctx->fwname); - release_firmware(blob); + release_firmware(ctx->blob); return -EPROTO; } @@ -2223,7 +2251,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) goto err_no_ucode; } } - err = b43_do_request_fw(ctx, filename, &fw->ucode); + err = b43_do_request_fw(ctx, filename, &fw->ucode, true); if (err) goto err_load; @@ -2235,7 +2263,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) else goto err_no_pcm; fw->pcm_request_failed = false; - err = b43_do_request_fw(ctx, filename, &fw->pcm); + err = b43_do_request_fw(ctx, filename, &fw->pcm, false); if (err == -ENOENT) { /* We did not find a PCM file? Not fatal, but * core rev <= 10 must do without hwcrypto then. */ @@ -2296,7 +2324,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) default: goto err_no_initvals; } - err = b43_do_request_fw(ctx, filename, &fw->initvals); + err = b43_do_request_fw(ctx, filename, &fw->initvals, false); if (err) goto err_load; @@ -2355,7 +2383,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) default: goto err_no_initvals; } - err = b43_do_request_fw(ctx, filename, &fw->initvals_band); + err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false); if (err) goto err_load; diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 8c684cd3352..abac25ee958 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -137,9 +137,8 @@ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on); struct b43_request_fw_context; -int b43_do_request_fw(struct b43_request_fw_context *ctx, - const char *name, - struct b43_firmware_file *fw); +int b43_do_request_fw(struct b43_request_fw_context *ctx, const char *name, + struct b43_firmware_file *fw, bool async); void b43_do_release_fw(struct b43_firmware_file *fw); #endif /* B43_MAIN_H_ */ From d6e362f53991a42b64b5fac902274b328d817e47 Mon Sep 17 00:00:00 2001 From: Dzianis Kahanovich Date: Mon, 3 Dec 2012 16:06:26 +0300 Subject: [PATCH 1897/2357] USB: option: add Nexpring NP10T terminal id commit ad86e58661b38b279b7519d4e49c7a19dc1654bb upstream. Hyundai Petatel Inc. Nexpring NP10T terminal (EV-DO rev.A USB modem) ID Signed-off-by: Denis Kaganovich Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0c3d2903481..136580dd9d2 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -441,6 +441,10 @@ static void option_instat_callback(struct urb *urb); #define CELLIENT_VENDOR_ID 0x2692 #define CELLIENT_PRODUCT_MEN200 0x9005 +/* Hyundai Petatel Inc. products */ +#define PETATEL_VENDOR_ID 0x1ff4 +#define PETATEL_PRODUCT_NP10T 0x600e + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -1295,6 +1299,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, + { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); From b80a67da576ee645568ecc1305743662809090d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 19 Dec 2012 15:15:17 +0100 Subject: [PATCH 1898/2357] USB: option: blacklist network interface on ZTE MF880 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit fab38246f318edcd0dcb8fd3852a47cf8938878a upstream. The driver description files gives these names to the vendor specific functions on this modem: diag: VID_19D2&PID_0284&MI_00 nmea: VID_19D2&PID_0284&MI_01 at: VID_19D2&PID_0284&MI_02 mdm: VID_19D2&PID_0284&MI_03 net: VID_19D2&PID_0284&MI_04 Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 136580dd9d2..17630e1cc6d 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -927,7 +927,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff), /* ZTE MF880 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, From 719d0cdd2c42bf0d272d285e89cb9ad4d2d01728 Mon Sep 17 00:00:00 2001 From: "Quentin.Li" Date: Wed, 26 Dec 2012 16:58:22 +0800 Subject: [PATCH 1899/2357] USB: option: Add new MEDIATEK PID support commit 94a85b633829b946eef53fc1825d526312fb856f upstream. In option.c, add some new MEDIATEK PIDs support for MEDIATEK new products. This is a MEDIATEK inc. release patch. Signed-off-by: Quentin.Li Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 17630e1cc6d..b7d98c54dab 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -429,9 +429,12 @@ static void option_instat_callback(struct urb *urb); #define MEDIATEK_VENDOR_ID 0x0e8d #define MEDIATEK_PRODUCT_DC_1COM 0x00a0 #define MEDIATEK_PRODUCT_DC_4COM 0x00a5 +#define MEDIATEK_PRODUCT_DC_4COM2 0x00a7 #define MEDIATEK_PRODUCT_DC_5COM 0x00a4 #define MEDIATEK_PRODUCT_7208_1COM 0x7101 #define MEDIATEK_PRODUCT_7208_2COM 0x7102 +#define MEDIATEK_PRODUCT_7103_2COM 0x7103 +#define MEDIATEK_PRODUCT_7106_2COM 0x7106 #define MEDIATEK_PRODUCT_FP_1COM 0x0003 #define MEDIATEK_PRODUCT_FP_2COM 0x0023 #define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 @@ -1299,6 +1302,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7103_2COM, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7106_2COM, 0x02, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) }, { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) }, { } /* Terminating entry */ From 1aaa39456c16f3f290811312d2ac81c0bdfdd1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Fri, 28 Dec 2012 17:29:52 +0100 Subject: [PATCH 1900/2357] USB: option: add Telekom Speedstick LTE II MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5ec0085440ef8c2cf50002b34d5a504ee12aa2bf upstream. also known as Alcatel One Touch L100V LTE The driver description files gives these names to the vendor specific functions on this modem: Application1: VID_1BBB&PID_011E&MI_00 Application2: VID_1BBB&PID_011E&MI_01 Modem: VID_1BBB&PID_011E&MI_03 Ethernet: VID_1BBB&PID_011E&MI_04 Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index b7d98c54dab..ba23ad55f41 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -288,6 +288,7 @@ static void option_instat_callback(struct urb *urb); #define ALCATEL_VENDOR_ID 0x1bbb #define ALCATEL_PRODUCT_X060S_X200 0x0000 #define ALCATEL_PRODUCT_X220_X500D 0x0017 +#define ALCATEL_PRODUCT_L100V 0x011e #define PIRELLI_VENDOR_ID 0x1266 #define PIRELLI_PRODUCT_C100_1 0x1002 @@ -1198,6 +1199,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), From 91d816cd00e5de594a1ec62893edbd9b84c5c252 Mon Sep 17 00:00:00 2001 From: Tomasz Mloduchowski Date: Sun, 13 Jan 2013 23:32:53 +0100 Subject: [PATCH 1901/2357] usb: ftdi_sio: Crucible Technologies COMET Caller ID - pid added commit 8cf65dc386f3634a43312f436cc7a935476a40c4 upstream. Simple fix to add support for Crucible Technologies COMET Caller ID USB decoder - a device containing FTDI USB/Serial converter chip, handling 1200bps CallerID messages decoded from the phone line - adding correct USB PID is sufficient. Tested to apply cleanly and work flawlessly against 3.6.9, 3.7.0-rc8 and 3.8.0-rc3 on both amd64 and x86 arches. Signed-off-by: Tomasz Mloduchowski Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 25903f54c1d..3fbf39d66a7 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -881,6 +881,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, + /* Crucible Devices */ + { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 049b6e715fa..fa5d5603827 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1259,3 +1259,9 @@ * ATI command output: Cinterion MC55i */ #define FTDI_CINTERION_MC55I_PID 0xA951 + +/* + * Product: Comet Caller ID decoder + * Manufacturer: Crucible Technologies + */ +#define FTDI_CT_COMET_PID 0x8e08 From b756d75a459f351e43d1d71295d5f6b94ec811c3 Mon Sep 17 00:00:00 2001 From: Denis N Ladin Date: Wed, 26 Dec 2012 18:29:44 +0500 Subject: [PATCH 1902/2357] USB: cdc-acm: Add support for "PSC Scanning, Magellan 800i" commit 036915a7a402753c05b8d0529f5fd08805ab46d0 upstream. Adding support "PSC Scanning, Magellan 800i" in cdc-acm Very simple, but very necessary. Suitable for all versions of the kernel > 2.6 Signed-off-by: Denis N Ladin Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index b4e87cfa73a..3a7a95084cc 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1602,6 +1602,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ .driver_info = NO_UNION_NORMAL, }, + { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */ + .driver_info = NO_UNION_NORMAL, + }, { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ }, From 98bea5234411352182c84918640629fe05bf64b5 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 20 Nov 2012 13:23:15 +0100 Subject: [PATCH 1903/2357] usb: gadget: dummy: fix enumeration with g_multi commit 1d16638e3b9cc195bac18a8fcbca748f33c1bc24 upstream. If we do have endpoints named like "ep-a" then bEndpointAddress is counted internally by the gadget framework. If we do have endpoints named like "ep-1" then bEndpointAddress is assigned from the digit after "ep-". If we do have both, then it is likely that after we used up the "generic" endpoints we will use the digits and thus assign one bEndpointAddress to multiple endpoints. This theory can be proofed by using the completely enabled g_multi. Without this patch, the mass storage won't enumerate and times out because it shares endpoints with RNDIS. This patch also adds fills up the endpoints list so we have in total endpoints 1 to 15 in + out available while some of them are restricted to certain types like BULK or ISO. Without this change the nokia gadget won't load because the system does not provide enough (BULK) endpoints but it did before ep-a - ep-f were removed. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Alan Stern Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 2d277a2bc33..9a7b436bd92 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -126,10 +126,7 @@ static const char ep0name[] = "ep0"; static const char *const ep_name[] = { ep0name, /* everyone has ep0 */ - /* act like a net2280: high speed, six configurable endpoints */ - "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", - - /* or like pxa250: fifteen fixed function endpoints */ + /* act like a pxa250: fifteen fixed function endpoints */ "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", @@ -137,6 +134,10 @@ static const char *const ep_name[] = { /* or like sa1100: two fixed function endpoints */ "ep1out-bulk", "ep2in-bulk", + + /* and now some generic EPs so we have enough in multi config */ + "ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in", + "ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out", }; #define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) From 1353cac7123b29dc169e775a7f3cf20929d0ef72 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 14 Nov 2012 18:49:50 +0300 Subject: [PATCH 1904/2357] usb: musb: core: print new line in the driver banner again commit 2ac788f705e5118dd45204e7a5bc8d5bb6873835 upstream. Commit 5c8a86e10a7c164f44537fabdc169fd8b4e7a440 (usb: musb: drop unneeded musb_debug trickery) erroneously removed '\n' from the driver's banner. Concatenate all the banner substrings while adding it back... Signed-off-by: Sergei Shtylyov Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 66aaccf0449..a2b4008dc06 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2400,10 +2400,7 @@ static int __init musb_init(void) if (usb_disabled()) return 0; - pr_info("%s: version " MUSB_VERSION ", " - "?dma?" - ", " - "otg (peripheral+host)", + pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n", musb_driver_name); return platform_driver_register(&musb_driver); } From e5583b77083d74c988dfd8572cd8f7d246bf63ac Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Tue, 18 Dec 2012 20:30:47 +0100 Subject: [PATCH 1905/2357] drm/nouveau: fix blank LVDS screen regression on pre-nv50 cards commit 92441b2263866c27ef48137be5aa6c8c692652fc upstream. Commit 2a44e499 ("drm/nouveau/disp: introduce proper init/fini, separate from create/destroy") started to call display init routines on pre-nv50 hardware on module load. But LVDS init code sets driver state in a way which prevents modesetting code from operating properly. nv04_display_init calls nv04_dfp_restore, which sets encoder->last_dpms to NV_DPMS_CLEARED. drm_crtc_helper_set_mode nv04_dfp_prepare nv04_lvds_dpms(DRM_MODE_DPMS_OFF) nv04_lvds_dpms checks last_dpms mode (which is NV_DPMS_CLEARED) and wrongly assumes it's a "powersaving mode", the new one (DRM_MODE_DPMS_OFF) is too, so it skips calling some crucial lvds scripts. Reported-by: Chris Paulson-Ellis Signed-off-by: Marcin Slusarz Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nv04_dfp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 473f30a4194..71b62352315 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -504,7 +504,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) static inline bool is_powersaving_dpms(int mode) { - return (mode != DRM_MODE_DPMS_ON); + return mode != DRM_MODE_DPMS_ON && mode != NV_DPMS_CLEARED; } static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) From 98e5587b9abe155e356d9eef3be6b1472c508c96 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 14 Nov 2012 15:58:52 -0800 Subject: [PATCH 1906/2357] USB: Handle auto-transition from hot to warm reset. commit 1c7439c61fa6516419c32a9824976334ea969d47 upstream. USB 3.0 hubs and roothubs will automatically transition a failed hot reset to a warm (BH) reset. In that case, the warm reset change bit will be set, and the link state change bit may also be set. Change hub_port_finish_reset to unconditionally clear those change bits for USB 3.0 hubs. If these bits are not cleared, we may lose port change events from the roothub. This commit should be backported to kernels as old as 3.2, that contain the commit 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine warm reset logic". Signed-off-by: Sarah Sharp Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 11344bcc175..8dee90becf0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2249,16 +2249,16 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_RESET); /* FIXME need disconnect() for NOTATTACHED device */ - if (warm) { + if (hub_is_superspeed(hub->hdev)) { clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_BH_PORT_RESET); clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_PORT_LINK_STATE); - } else { + } + if (!warm) usb_set_device_state(udev, *status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); - } break; } } From 36f037316ff169ca111917d6b1d2546d243a2f78 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 14 Nov 2012 16:10:49 -0800 Subject: [PATCH 1907/2357] USB: Ignore xHCI Reset Device status. commit 8b8132bc3d1cc3d4c0687e4d638a482fa920d98a upstream. When the USB core finishes reseting a USB device, the xHCI driver sends a Reset Device command to the host. The xHC then updates its internal representation of the USB device to the 'Default' device state. If the device was already in the Default state, the xHC will complete the command with an error status. If a device needs to be reset several times during enumeration, the second reset will always fail because of the xHCI Reset Device command. This can cause issues during enumeration. For example, usb_reset_and_verify_device calls into hub_port_init in a loop. Say that on the first call into hub_port_init, the device is successfully reset, but doesn't respond to several set address control transfers. Then the port will be disabled, but the udev will remain in tact. usb_reset_and_verify_device will call into hub_port_init again. On the second call into hub_port_init, the device will be reset, and the xHCI driver will issue a Reset Device command. This command will fail (because the device is already in the Default state), and usb_reset_and_verify_device will fail. The port will be disabled, and the device won't be able to enumerate. Fix this by ignoring the return value of the HCD reset_device callback. This commit should be backported to kernels as old as 3.2, that contain the commit 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine warm reset logic". Signed-off-by: Sarah Sharp Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8dee90becf0..2a369d3fc3a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2234,14 +2234,11 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, msleep(10 + 40); update_devnum(udev, 0); hcd = bus_to_hcd(udev->bus); - if (hcd->driver->reset_device) { - *status = hcd->driver->reset_device(hcd, udev); - if (*status < 0) { - dev_err(&udev->dev, "Cannot reset " - "HCD device state\n"); - break; - } - } + /* The xHC may think the device is already reset, + * so ignore the status. + */ + if (hcd->driver->reset_device) + hcd->driver->reset_device(hcd, udev); } /* FALL THROUGH */ case -ENOTCONN: From a723a6cf79aa2e283d5134adf2787b8a35e0b8f3 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 14 Nov 2012 16:42:32 -0800 Subject: [PATCH 1908/2357] USB: Allow USB 3.0 ports to be disabled. commit 41e7e056cdc662f704fa9262e5c6e213b4ab45dd upstream. If hot and warm reset fails, or a port remains in the Compliance Mode, the USB core needs to be able to disable a USB 3.0 port. Unlike USB 2.0 ports, once the port is placed into the Disabled link state, it will not report any new device connects. To get device connect notifications, we need to put the link into the Disabled state, and then the RxDetect state. The xHCI driver needs to atomically clear all change bits on USB 3.0 port disable, so that we get Port Status Change Events for future port changes. We could technically do this in the USB core instead of in the xHCI roothub code, since the port state machine can't advance out of the disabled state until we set the link state to RxDetect. However, external USB 3.0 hubs don't need this code. They are level-triggered, not edge-triggered like xHCI, so they will continue to send interrupt events when any change bit is set. Therefore it doesn't make sense to put this code in the USB core. This patch is part of a series to fix several reports of infinite loops on device enumeration failure. This includes John, when he boots with a USB 3.0 device (Roseweil eusb3 enclosure) attached to his NEC 0.96 host controller. The fix requires warm reset support, so it does not make sense to backport this patch to stable kernels without warm reset support. This patch should be backported to kernels as old as 3.2, contain the commit ID 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine warm reset logic" Signed-off-by: Sarah Sharp Acked-by: Alan Stern Reported-by: John Covici Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 63 +++++++++++++++++++++++++++++++++++-- drivers/usb/host/xhci-hub.c | 31 ++++++++++++++++-- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2a369d3fc3a..0e330a1de06 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -644,6 +644,60 @@ static int hub_hub_status(struct usb_hub *hub, return ret; } +static int hub_set_port_link_state(struct usb_hub *hub, int port1, + unsigned int link_status) +{ + return set_port_feature(hub->hdev, + port1 | (link_status << 3), + USB_PORT_FEAT_LINK_STATE); +} + +/* + * If USB 3.0 ports are placed into the Disabled state, they will no longer + * detect any device connects or disconnects. This is generally not what the + * USB core wants, since it expects a disabled port to produce a port status + * change event when a new device connects. + * + * Instead, set the link state to Disabled, wait for the link to settle into + * that state, clear any change bits, and then put the port into the RxDetect + * state. + */ +static int hub_usb3_port_disable(struct usb_hub *hub, int port1) +{ + int ret; + int total_time; + u16 portchange, portstatus; + + if (!hub_is_superspeed(hub->hdev)) + return -EINVAL; + + ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); + if (ret) { + dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", + port1, ret); + return ret; + } + + /* Wait for the link to enter the disabled state. */ + for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { + ret = hub_port_status(hub, port1, &portstatus, &portchange); + if (ret < 0) + return ret; + + if ((portstatus & USB_PORT_STAT_LINK_STATE) == + USB_SS_PORT_LS_SS_DISABLED) + break; + if (total_time >= HUB_DEBOUNCE_TIMEOUT) + break; + msleep(HUB_DEBOUNCE_STEP); + } + if (total_time >= HUB_DEBOUNCE_TIMEOUT) + dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n", + port1, total_time); + + return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT); +} + static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) { struct usb_device *hdev = hub->hdev; @@ -652,8 +706,13 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) if (hdev->children[port1-1] && set_state) usb_set_device_state(hdev->children[port1-1], USB_STATE_NOTATTACHED); - if (!hub->error && !hub_is_superspeed(hub->hdev)) - ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); + if (!hub->error) { + if (hub_is_superspeed(hub->hdev)) + ret = hub_usb3_port_disable(hub, port1); + else + ret = clear_port_feature(hdev, port1, + USB_PORT_FEAT_ENABLE); + } if (ret) dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", port1, ret); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index de07b7556d4..0efc857ed1e 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -753,12 +753,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case USB_PORT_FEAT_LINK_STATE: temp = xhci_readl(xhci, port_array[wIndex]); + + /* Disable port */ + if (link_state == USB_SS_PORT_LS_SS_DISABLED) { + xhci_dbg(xhci, "Disable port %d\n", wIndex); + temp = xhci_port_state_to_neutral(temp); + /* + * Clear all change bits, so that we get a new + * connection event. + */ + temp |= PORT_CSC | PORT_PEC | PORT_WRC | + PORT_OCC | PORT_RC | PORT_PLC | + PORT_CEC; + xhci_writel(xhci, temp | PORT_PE, + port_array[wIndex]); + temp = xhci_readl(xhci, port_array[wIndex]); + break; + } + + /* Put link in RxDetect (enable port) */ + if (link_state == USB_SS_PORT_LS_RX_DETECT) { + xhci_dbg(xhci, "Enable port %d\n", wIndex); + xhci_set_link_state(xhci, port_array, wIndex, + link_state); + temp = xhci_readl(xhci, port_array[wIndex]); + break; + } + /* Software should not attempt to set - * port link state above '5' (Rx.Detect) and the port + * port link state above '3' (U3) and the port * must be enabled. */ if ((temp & PORT_PE) == 0 || - (link_state > USB_SS_PORT_LS_RX_DETECT)) { + (link_state > USB_SS_PORT_LS_U3)) { xhci_warn(xhci, "Cannot set link state.\n"); goto error; } From 7bcaf3b265ae4d197d265916268bceed044d289c Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 14 Nov 2012 17:16:52 -0800 Subject: [PATCH 1909/2357] USB: Increase reset timeout. commit 77c7f072c87fa951e9a74805febf26466f31170c upstream. John's NEC 0.96 xHCI host controller needs a longer timeout for a warm reset to complete. The logs show it takes 650ms to complete the warm reset, so extend the hub reset timeout to 800ms to be on the safe side. This commit should be backported to kernels as old as 3.2, that contain the commit 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine warm reset logic". Signed-off-by: Sarah Sharp Acked-by: Alan Stern Reported-by: John Covici Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0e330a1de06..12d2b4f5778 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2168,7 +2168,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define HUB_SHORT_RESET_TIME 10 #define HUB_BH_RESET_TIME 50 #define HUB_LONG_RESET_TIME 200 -#define HUB_RESET_TIMEOUT 500 +#define HUB_RESET_TIMEOUT 800 static int hub_port_reset(struct usb_hub *hub, int port1, struct usb_device *udev, unsigned int delay, bool warm); From 870826a75318bfee80967140ce3eb6b55e1e9759 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 15 Nov 2012 14:58:04 -0800 Subject: [PATCH 1910/2357] USB: Ignore port state until reset completes. commit 4f43447e62b37ee19c82a13f72f35b1ca60a74d3 upstream. The port reset code bails out early if the current connect status is cleared (device disconnected). If we're issuing a hot reset, it may also look at the link state before the reset is finished. Section 10.14.2.6 of the USB 3.0 spec says that when a port enters the Error state or Resetting state, the port connection bit retains the value from the previous state. Therefore we can't trust it until the reset finishes. Also, the xHCI spec section 4.19.1.2.5 says software shall ignore the link state while the port is resetting, as it can be in an unknown state. The port state during reset is also unknown for USB 2.0 hubs. The hub sends a reset signal by driving the bus into an SE0 state. This overwhelms the "connect" signal from the device, so the port can't tell whether anything is connected or not. Fix the port reset code to ignore the port link state and current connect bit until the reset finishes, and USB_PORT_STAT_RESET is cleared. Remove the check for USB_PORT_STAT_C_BH_RESET in the warm reset case, because it's redundant. When the warm reset finishes, the port reset bit will be cleared at the same time USB_PORT_STAT_C_BH_RESET is set. Remove the now-redundant check for a cleared USB_PORT_STAT_RESET bit in the code to deal with the finished reset. This patch should be backported to all stable kernels. Signed-off-by: Sarah Sharp Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 12d2b4f5778..c444c901ec5 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2203,6 +2203,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, if (ret < 0) return ret; + /* The port state is unknown until the reset completes. */ + if ((portstatus & USB_PORT_STAT_RESET)) + goto delay; + /* * Some buggy devices require a warm reset to be issued even * when the port appears not to be connected. @@ -2248,11 +2252,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, if ((portchange & USB_PORT_STAT_C_CONNECTION)) return -ENOTCONN; - /* if we`ve finished resetting, then break out of - * the loop - */ - if (!(portstatus & USB_PORT_STAT_RESET) && - (portstatus & USB_PORT_STAT_ENABLE)) { + if ((portstatus & USB_PORT_STAT_ENABLE)) { if (hub_is_wusb(hub)) udev->speed = USB_SPEED_WIRELESS; else if (hub_is_superspeed(hub->hdev)) @@ -2266,10 +2266,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, return 0; } } else { - if (portchange & USB_PORT_STAT_C_BH_RESET) - return 0; + return 0; } +delay: /* switch to the long delay after two short delay failures */ if (delay_time >= 2 * HUB_SHORT_RESET_TIME) delay = HUB_LONG_RESET_TIME; From 9dbcaec830cd97f44a0b91b315844e0d7144746b Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 14 Nov 2012 17:58:04 -0800 Subject: [PATCH 1911/2357] USB: Handle warm reset failure on empty port. commit 65bdac5effd15d6af619b3b7218627ef4d84ed6a upstream. An empty port can transition to either Inactive or Compliance Mode if a newly connected USB 3.0 device fails to link train. In that case, we issue a warm reset. Some devices, such as John's Roseweil eusb3 enclosure, slip back into Compliance Mode after the warm reset. The current warm reset code does not check for device connect status on warm reset completion, and it incorrectly reports the warm reset succeeded. This causes the USB core to attempt to send a Set Address control transfer to a port in Compliance Mode, which will always fail. Make hub_port_wait_reset check the current connect status and link state after the warm reset completes. Return a failure status if the device is disconnected or the link state is Compliance Mode or SS.Inactive. Make hub_events disable the port if warm reset fails. This will disable the port, and then bring it back into the RxDetect state. Make the USB core ignore the connect change until the device reconnects. Note that this patch does NOT handle connected devices slipping into the Inactive state very well. This is a concern, because devices can go into the Inactive state on U1/U2 exit failure. However, the fix for that case is too large for stable, so it will be submitted in a separate patch. This patch should be backported to kernels as old as 3.2, contain the commit ID 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine warm reset logic" Signed-off-by: Sarah Sharp Acked-by: Alan Stern Reported-by: John Covici Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c444c901ec5..dbc4bf75374 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2266,6 +2266,11 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, return 0; } } else { + if (!(portstatus & USB_PORT_STAT_CONNECTION) || + hub_port_warm_reset_required(hub, + portstatus)) + return -ENOTCONN; + return 0; } @@ -3830,9 +3835,14 @@ static void hub_events(void) * SS.Inactive state. */ if (hub_port_warm_reset_required(hub, portstatus)) { + int status; + dev_dbg(hub_dev, "warm reset port %d\n", i); - hub_port_reset(hub, i, NULL, + status = hub_port_reset(hub, i, NULL, HUB_BH_RESET_TIME, true); + if (status < 0) + hub_port_disable(hub, i, 1); + connect_change = 0; } if (connect_change) From 4ceac47e41f4d587fa71a26dc87335d639a32520 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 27 Nov 2012 12:30:23 -0800 Subject: [PATCH 1912/2357] xhci: Avoid "dead ports", add roothub port polling. commit c52804a472649b2e5005342308739434cbd51119 upstream. The USB core hub thread (khubd) is designed with external USB hubs in mind. It expects that if a port status change bit is set, the hub will continue to send a notification through the hub status data transfer. Basically, it expects hub notifications to be level-triggered. The xHCI host controller is designed to be edge-triggered on the logical 'OR' of all the port status change bits. When all port status change bits are clear, and a new change bit is set, the xHC will generate a Port Status Change Event. If another change bit is set in the same port status register before the first bit is cleared, it will not send another event. This means that the hub code may lose port status changes because of race conditions between clearing change bits. The user sees this as a "dead port" that doesn't react to device connects. The fix is to turn on port polling whenever a new change bit is set. Once the USB core issues a hub status request that shows that no change bits are set in any USB ports, turn off port polling. We can't allow the USB core to poll the roothub for port events during host suspend because if the PCI host is in D3cold, the port registers will be all f's. Instead, stop the port polling timer, and unconditionally restart it when the host resumes. If there are no port change bits set after the resume, the first call to hub_status_data will disable polling. This patch should be backported to stable kernels with the first xHCI support, 2.6.31 and newer, that include the commit 0f2a79300a1471cf92ab43af165ea13555c8b0a5 "USB: xhci: Root hub support." There will be merge conflicts because the check for HC_STATE_SUSPENDED was moved into xhci_suspend in 3.8. Signed-off-by: Sarah Sharp Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 7 +++++++ drivers/usb/host/xhci-ring.c | 9 +++++++++ drivers/usb/host/xhci.c | 10 ++++++++++ 3 files changed, 26 insertions(+) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 0efc857ed1e..8331893c75e 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -940,6 +940,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) int max_ports; __le32 __iomem **port_array; struct xhci_bus_state *bus_state; + bool reset_change = false; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; @@ -971,6 +972,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) buf[(i + 1) / 8] |= 1 << (i + 1) % 8; status = 1; } + if ((temp & PORT_RC)) + reset_change = true; + } + if (!status && !reset_change) { + xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); + clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); } spin_unlock_irqrestore(&xhci->lock, flags); return status ? retval : 0; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index bf8bcc4dd78..01361f929f1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1725,6 +1725,15 @@ static void handle_port_status(struct xhci_hcd *xhci, if (bogus_port_status) return; + /* + * xHCI port-status-change events occur when the "or" of all the + * status-change bits in the portsc register changes from 0 to 1. + * New status changes won't cause an event if any other change + * bits are still set. When an event occurs, switch over to + * polling to avoid losing status changes. + */ + xhci_dbg(xhci, "%s: starting port polling.\n", __func__); + set_bit(HCD_FLAG_POLL_RH, &hcd->flags); spin_unlock(&xhci->lock); /* Pass this up to the core */ usb_hcd_poll_rh_status(hcd); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index b4063fc72b4..b04134aa346 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -880,6 +880,11 @@ int xhci_suspend(struct xhci_hcd *xhci) struct usb_hcd *hcd = xhci_to_hcd(xhci); u32 command; + /* Don't poll the roothubs on bus suspend. */ + xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); + clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); + del_timer_sync(&hcd->rh_timer); + spin_lock_irq(&xhci->lock); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); @@ -1064,6 +1069,11 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) if (xhci->quirks & XHCI_COMP_MODE_QUIRK) compliance_mode_recovery_timer_init(xhci); + /* Re-enable port polling. */ + xhci_dbg(xhci, "%s: starting port polling.\n", __func__); + set_bit(HCD_FLAG_POLL_RH, &hcd->flags); + usb_hcd_poll_rh_status(hcd); + return retval; } #endif /* CONFIG_PM */ From 7dd830b8315230e29f958fd0e039e9eecad28c5d Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 29 Nov 2012 15:05:57 +0100 Subject: [PATCH 1913/2357] USB: hub: handle claim of enabled remote wakeup after reset commit 07e72b95f5038cc82304b9a4a2eb7f9fc391ea68 upstream. Some touchscreens have buggy firmware which claims remote wakeup to be enabled after a reset. They nevertheless crash if the feature is cleared by the host. Add a check for reset resume before checking for an enabled remote wakeup feature. On compliant devices the feature must be cleared after a reset anyway. Signed-off-by: Oliver Neukum Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index dbc4bf75374..ef8f790d617 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2609,7 +2609,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) static int finish_port_resume(struct usb_device *udev) { int status = 0; - u16 devstatus; + u16 devstatus = 0; /* caller owns the udev device lock */ dev_dbg(&udev->dev, "%s\n", @@ -2654,7 +2654,13 @@ static int finish_port_resume(struct usb_device *udev) if (status) { dev_dbg(&udev->dev, "gone after usb resume? status %d\n", status); - } else if (udev->actconfig) { + /* + * There are a few quirky devices which violate the standard + * by claiming to have remote wakeup enabled after a reset, + * which crash if the feature is cleared, hence check for + * udev->reset_resume + */ + } else if (udev->actconfig && !udev->reset_resume) { le16_to_cpus(&devstatus); if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { status = usb_control_msg(udev, From 74abeffd733e53f83e94fc0d90c0a105af7c58ae Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 17 Dec 2012 14:12:35 -0800 Subject: [PATCH 1914/2357] xhci: Handle HS bulk/ctrl endpoints that don't NAK. commit 55c1945edaac94c5338a3647bc2e85ff75d9cf36 upstream. A high speed control or bulk endpoint may have bInterval set to zero, which means it does not NAK. If bInterval is non-zero, it means the endpoint NAKs at a rate of 2^(bInterval - 1). The xHCI code to compute the NAK interval does not handle the special case of zero properly. The current code unconditionally subtracts one from bInterval and uses it as an exponent. This causes a very large bInterval to be used, and warning messages like these will be printed: usb 1-1: ep 0x1 - rounding interval to 32768 microframes, ep desc says 0 microframes This may cause the xHCI host hardware to reject the Configure Endpoint command, which means the HS device will be unusable under xHCI ports. This patch should be backported to kernels as old as 2.6.31, that contain commit dfa49c4ad120a784ef1ff0717168aa79f55a483a "USB: xhci - fix math in xhci_get_endpoint_interval()". Reported-by: Vincent Pelletier Suggested-by: Alan Stern Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 3e16f1c160a..b42a6fb45b2 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1250,6 +1250,8 @@ static unsigned int xhci_microframes_to_exponent(struct usb_device *udev, static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, struct usb_host_endpoint *ep) { + if (ep->desc.bInterval == 0) + return 0; return xhci_microframes_to_exponent(udev, ep, ep->desc.bInterval, 0, 15); } From 8b564a8e7334a2ce7a691ec7fe21195475ae999f Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 7 Nov 2012 00:38:06 -0600 Subject: [PATCH 1915/2357] GFS2: Test bufdata with buffer locked and gfs2_log_lock held commit 96e5d1d3adf56f1c7eeb07258f6a1a0a7ae9c489 upstream. In gfs2_trans_add_bh(), gfs2 was testing if a there was a bd attached to the buffer without having the gfs2_log_lock held. It was then assuming it would stay attached for the rest of the function. However, without either the log lock being held of the buffer locked, __gfs2_ail_flush() could detach bd at any time. This patch moves the locking before the test. If there isn't a bd already attached, gfs2 can safely allocate one and attach it before locking. There is no way that the newly allocated bd could be on the ail list, and thus no way for __gfs2_ail_flush() to detach it. Signed-off-by: Benjamin Marzinski Signed-off-by: Steven Whitehouse [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- fs/gfs2/lops.c | 18 ++++-------------- fs/gfs2/trans.c | 8 ++++++++ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 6b1efb594d9..a392e32af48 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -258,16 +258,14 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct gfs2_meta_header *mh; struct gfs2_trans *tr; - lock_buffer(bd->bd_bh); - gfs2_log_lock(sdp); if (!list_empty(&bd->bd_list_tr)) - goto out; + return; tr = current->journal_info; tr->tr_touched = 1; tr->tr_num_buf++; list_add(&bd->bd_list_tr, &tr->tr_list_buf); if (!list_empty(&le->le_list)) - goto out; + return; set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); gfs2_meta_check(sdp, bd->bd_bh); @@ -278,9 +276,6 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) sdp->sd_log_num_buf++; list_add(&le->le_list, &sdp->sd_log_le_buf); tr->tr_num_buf_new++; -out: - gfs2_log_unlock(sdp); - unlock_buffer(bd->bd_bh); } static void buf_lo_before_commit(struct gfs2_sbd *sdp) @@ -611,11 +606,9 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct address_space *mapping = bd->bd_bh->b_page->mapping; struct gfs2_inode *ip = GFS2_I(mapping->host); - lock_buffer(bd->bd_bh); - gfs2_log_lock(sdp); if (tr) { if (!list_empty(&bd->bd_list_tr)) - goto out; + return; tr->tr_touched = 1; if (gfs2_is_jdata(ip)) { tr->tr_num_buf++; @@ -623,7 +616,7 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) } } if (!list_empty(&le->le_list)) - goto out; + return; set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); @@ -635,9 +628,6 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) } else { list_add_tail(&le->le_list, &sdp->sd_log_le_ordered); } -out: - gfs2_log_unlock(sdp); - unlock_buffer(bd->bd_bh); } static void gfs2_check_magic(struct buffer_head *bh) diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 86ac75d99d3..6ab2a77e772 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -145,14 +145,22 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) struct gfs2_sbd *sdp = gl->gl_sbd; struct gfs2_bufdata *bd; + lock_buffer(bh); + gfs2_log_lock(sdp); bd = bh->b_private; if (bd) gfs2_assert(sdp, bd->bd_gl == gl); else { + gfs2_log_unlock(sdp); + unlock_buffer(bh); gfs2_attach_bufdata(gl, bh, meta); bd = bh->b_private; + lock_buffer(bh); + gfs2_log_lock(sdp); } lops_add(sdp, &bd->bd_le); + gfs2_log_unlock(sdp); + unlock_buffer(bh); } void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) From eb52d3018cd126254c64241e64936a6cfc0a82eb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 8 Dec 2012 12:58:33 +0100 Subject: [PATCH 1916/2357] drm/i915: disable cpt phase pointer fdi rx workaround commit 539526b4137bc0e7a8806c38c8522f226814a0e6 upstream. We've originally added this in commit 291427f5fdadec6e4be2924172e83588880e1539 Author: Jesse Barnes Date: Fri Jul 29 12:42:37 2011 -0700 drm/i915: apply phase pointer override on SNB+ too and then copy-pasted it over to ivb/ppt. The w/a was originally added for ilk/ibx in commit 5b2adf897146edeac6a1e438fb67b5a53dbbdf34 Author: Jesse Barnes Date: Thu Oct 7 16:01:15 2010 -0700 drm/i915: add Ironlake clock gating workaround for FDI link training and fixed up a bit in commit 6f06ce184c765fd8d50669a8d12fdd566c920859 Author: Jesse Barnes Date: Tue Jan 4 15:09:38 2011 -0800 drm/i915: set phase sync pointer override enable before setting phase sync pointer It turns out that this w/a isn't actually required on cpt/ppt and positively harmful on ivb/ppt when using fdi B/C links - it results in a black screen occasionally, with seemingfully everything working as it should. The only failure indication I've found in the hw is that eventually (but not right after the modeset completes) a pipe underrun is signalled. Big thanks to Arthur Runyan for all the ideas for registers to check and changes to test, otherwise I couldn't ever have tracked this down! Reviewed-by: Jesse Barnes Cc: "Runyan, Arthur J" Signed-off-by: Daniel Vetter Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 31 ---------------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fd150a98a62..ec6d1e0c82b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2424,18 +2424,6 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) FDI_FE_ERRC_ENABLE); } -static void cpt_phase_pointer_enable(struct drm_device *dev, int pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 flags = I915_READ(SOUTH_CHICKEN1); - - flags |= FDI_PHASE_SYNC_OVR(pipe); - I915_WRITE(SOUTH_CHICKEN1, flags); /* once to unlock... */ - flags |= FDI_PHASE_SYNC_EN(pipe); - I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to enable */ - POSTING_READ(SOUTH_CHICKEN1); -} - /* The FDI link training functions for ILK/Ibexpeak. */ static void ironlake_fdi_link_train(struct drm_crtc *crtc) { @@ -2586,9 +2574,6 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); - if (HAS_PCH_CPT(dev)) - cpt_phase_pointer_enable(dev, pipe); - for (i = 0; i < 4; i++) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2707,9 +2692,6 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); - if (HAS_PCH_CPT(dev)) - cpt_phase_pointer_enable(dev, pipe); - for (i = 0; i < 4; i++) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2819,17 +2801,6 @@ static void ironlake_fdi_pll_enable(struct drm_crtc *crtc) } } -static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 flags = I915_READ(SOUTH_CHICKEN1); - - flags &= ~(FDI_PHASE_SYNC_EN(pipe)); - I915_WRITE(SOUTH_CHICKEN1, flags); /* once to disable... */ - flags &= ~(FDI_PHASE_SYNC_OVR(pipe)); - I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to lock */ - POSTING_READ(SOUTH_CHICKEN1); -} static void ironlake_fdi_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2859,8 +2830,6 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) I915_WRITE(FDI_RX_CHICKEN(pipe), I915_READ(FDI_RX_CHICKEN(pipe) & ~FDI_RX_PHASE_SYNC_POINTER_EN)); - } else if (HAS_PCH_CPT(dev)) { - cpt_phase_pointer_disable(dev, pipe); } /* still set train pattern 1 */ From 7d609c8d07b74c0a5ef7b903a9ae918d73a9a039 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 6 Oct 2012 03:56:35 +0200 Subject: [PATCH 1917/2357] KVM: PPC: 44x: fix DCR read/write commit e43a028752fed049e4bd94ef895542f96d79fa74 upstream. When remembering the direction of a DCR transaction, we should write to the same variable that we interpret on later when doing vcpu_run again. Signed-off-by: Alexander Graf Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kvm/44x_emulate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kvm/44x_emulate.c b/arch/powerpc/kvm/44x_emulate.c index 549bb2c9a47..ded8a1a0426 100644 --- a/arch/powerpc/kvm/44x_emulate.c +++ b/arch/powerpc/kvm/44x_emulate.c @@ -79,6 +79,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, run->dcr.dcrn = dcrn; run->dcr.data = 0; run->dcr.is_write = 0; + vcpu->arch.dcr_is_write = 0; vcpu->arch.io_gpr = rt; vcpu->arch.dcr_needed = 1; kvmppc_account_exit(vcpu, DCR_EXITS); @@ -100,6 +101,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, run->dcr.dcrn = dcrn; run->dcr.data = kvmppc_get_gpr(vcpu, rs); run->dcr.is_write = 1; + vcpu->arch.dcr_is_write = 1; vcpu->arch.dcr_needed = 1; kvmppc_account_exit(vcpu, DCR_EXITS); emulated = EMULATE_DO_DCR; From fd5f25462460a68f73ff8f90ac08535b01830d9a Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Wed, 23 May 2012 16:26:54 -0400 Subject: [PATCH 1918/2357] drm/edid/quirks: ViewSonic VA2026w commit bc42aabc6a01b92b0f961d65671564e0e1cd7592 upstream. Entirely new class of fail for this one. The detailed timings are for normal CVT but the monitor really wanted CVT-R. Bugzilla: http://bugzilla.redhat/com/516471 Signed-off-by: Adam Jackson Signed-off-by: Dave Airlie Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_edid.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 6e38325d04a..9d9835a4fee 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -66,6 +66,8 @@ #define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) /* use +hsync +vsync for detailed mode */ #define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) +/* Force reduced-blanking timings for detailed modes */ +#define EDID_QUIRK_FORCE_REDUCED_BLANKING (1 << 7) struct detailed_mode_closure { struct drm_connector *connector; @@ -120,6 +122,9 @@ static struct edid_quirk { /* Samsung SyncMaster 22[5-6]BW */ { "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 }, { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 }, + + /* ViewSonic VA2026w */ + { "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING }, }; /*** DDC fetch and block validation ***/ @@ -852,12 +857,19 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, "Wrong Hsync/Vsync pulse width\n"); return NULL; } + + if (quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) { + mode = drm_cvt_mode(dev, hactive, vactive, 60, true, false, false); + if (!mode) + return NULL; + + goto set_size; + } + mode = drm_mode_create(dev); if (!mode) return NULL; - mode->type = DRM_MODE_TYPE_DRIVER; - if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH) timing->pixel_clock = cpu_to_le16(1088); @@ -881,8 +893,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, drm_mode_do_interlace_quirk(mode, pt); - drm_mode_set_name(mode); - if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE; } @@ -892,6 +902,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; +set_size: mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4; mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8; @@ -905,6 +916,9 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->height_mm = edid->height_cm * 10; } + mode->type = DRM_MODE_TYPE_DRIVER; + drm_mode_set_name(mode); + return mode; } From 0ab9c5b5d2ffed9550ca2aae49ef39bfc61d2d0b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 19:35:53 +0100 Subject: [PATCH 1919/2357] drm/i915: Unpin the flip target if we fail to queue the flip commit 83d4092b0381e5dd6f312b2ec57121dcf0fcbade upstream. Signed-off-by: Chris Wilson Cc: Jesse Barnes Signed-off-by: Daniel Vetter Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 50 +++++++++++++++++++--------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ec6d1e0c82b..c19bc62bc4e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7313,14 +7313,14 @@ static int intel_gen2_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); if (ret) - goto out; + goto err; /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8; ret = BEGIN_LP_RING(6); if (ret) - goto out; + goto err_unpin; /* Can't queue multiple flips, so wait for the previous * one to finish before executing the next. @@ -7337,7 +7337,11 @@ static int intel_gen2_queue_flip(struct drm_device *dev, OUT_RING(obj->gtt_offset + offset); OUT_RING(0); /* aux display base address, unused */ ADVANCE_LP_RING(); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7354,14 +7358,14 @@ static int intel_gen3_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); if (ret) - goto out; + goto err; /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8; ret = BEGIN_LP_RING(6); if (ret) - goto out; + goto err_unpin; if (intel_crtc->plane) flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; @@ -7376,7 +7380,11 @@ static int intel_gen3_queue_flip(struct drm_device *dev, OUT_RING(MI_NOOP); ADVANCE_LP_RING(); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7392,11 +7400,11 @@ static int intel_gen4_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); if (ret) - goto out; + goto err; ret = BEGIN_LP_RING(4); if (ret) - goto out; + goto err_unpin; /* i965+ uses the linear or tiled offsets from the * Display Registers (which do not change across a page-flip) @@ -7415,7 +7423,11 @@ static int intel_gen4_queue_flip(struct drm_device *dev, pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; OUT_RING(pf | pipesrc); ADVANCE_LP_RING(); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7431,11 +7443,11 @@ static int intel_gen6_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); if (ret) - goto out; + goto err; ret = BEGIN_LP_RING(4); if (ret) - goto out; + goto err_unpin; OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); @@ -7452,7 +7464,11 @@ static int intel_gen6_queue_flip(struct drm_device *dev, pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; OUT_RING(pf | pipesrc); ADVANCE_LP_RING(); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7474,18 +7490,22 @@ static int intel_gen7_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) - goto out; + goto err; ret = intel_ring_begin(ring, 4); if (ret) - goto out; + goto err_unpin; intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19)); intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); intel_ring_emit(ring, (obj->gtt_offset)); intel_ring_emit(ring, (MI_NOOP)); intel_ring_advance(ring); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } From 6148d57ee89d8ad89cd28a6f5803330c8601dfa6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 23 May 2012 14:02:00 +0200 Subject: [PATCH 1920/2357] drm/i915: fix up ivb plane 3 pageflips commit cb05d8dedefa3066bf5d74ef88c6ca6cf4bd1c87 upstream. Or at least plug another gapping hole. Apparrently hw desingers only moved the bit field, but did not bother ot re-enumerate the planes when adding support for a 3rd pipe. Discovered by i-g-t/flip_test. This may or may not fix the reference bugzilla, because that one smells like we have still larger fish to fry. v2: Fixup the impossible case to catch programming errors, noticed by Chris Wilson. References: https://bugs.freedesktop.org/show_bug.cgi?id=50069 Acked-by: Chris Wilson Tested-by: Eugeni Dodonov Eugeni Dodonov Signed-Off-by: Daniel Vetter Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cd1a85a6880..eaf38060223 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -197,6 +197,14 @@ #define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) #define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1) #define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) +/* IVB has funny definitions for which plane to flip. */ +#define MI_DISPLAY_FLIP_IVB_PLANE_A (0 << 19) +#define MI_DISPLAY_FLIP_IVB_PLANE_B (1 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_A (2 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_B (3 << 19) +#define MI_DISPLAY_FLIP_IVB_PLANE_C (4 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_C (5 << 19) + #define MI_SET_CONTEXT MI_INSTR(0x18, 0) #define MI_MM_SPACE_GTT (1<<8) #define MI_MM_SPACE_PHYSICAL (0<<8) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c19bc62bc4e..216504a6fb4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7486,17 +7486,34 @@ static int intel_gen7_queue_flip(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_ring_buffer *ring = &dev_priv->ring[BCS]; + uint32_t plane_bit = 0; int ret; ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) goto err; + switch(intel_crtc->plane) { + case PLANE_A: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A; + break; + case PLANE_B: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_B; + break; + case PLANE_C: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_C; + break; + default: + WARN_ONCE(1, "unknown plane in flip command\n"); + ret = -ENODEV; + goto err; + } + ret = intel_ring_begin(ring, 4); if (ret) goto err_unpin; - intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19)); + intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit); intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); intel_ring_emit(ring, (obj->gtt_offset)); intel_ring_emit(ring, (MI_NOOP)); From e99e7f74856e4aaf57753b2698d590966fa4022a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 22 Mar 2012 14:38:43 -0700 Subject: [PATCH 1921/2357] drm/i915: move NEEDS_FORCE_WAKE to i915_drv.c commit b7d84096d3c45f4e397e913da4ce24ec9a32022e upstream. It's only used by the main read/write functions, so we can keep it with them. Signed-off-by: Jesse Barnes Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_drv.c | 6 ++++++ drivers/gpu/drm/i915/i915_drv.h | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ae8a64f9f84..01cc14e653c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -993,6 +993,12 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL and additional rights"); +/* We give fast paths for the really cool registers */ +#define NEEDS_FORCE_WAKE(dev_priv, reg) \ + (((dev_priv)->info->gen >= 6) && \ + ((reg) < 0x40000) && \ + ((reg) != FORCEWAKE)) + #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ u##x val = 0; \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5fabc6c31fe..a8edd5379e7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1450,12 +1450,6 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); -/* We give fast paths for the really cool registers */ -#define NEEDS_FORCE_WAKE(dev_priv, reg) \ - (((dev_priv)->info->gen >= 6) && \ - ((reg) < 0x40000) && \ - ((reg) != FORCEWAKE)) - #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); From 2406e63c32cf6bf83f7f188ba0cb96bfa94dc6ec Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 4 Jun 2012 11:18:15 +0200 Subject: [PATCH 1922/2357] drm/i915: hold forcewake around ring hw init commit b7884eb45ec98c0d34c7f49005ae9d4b4b4e38f6 upstream. Empirical evidence suggests that we need to: On at least one ivb machine when running the hangman i-g-t test, the rings don't properly initialize properly - the RING_START registers seems to be stuck at all zeros. Holding forcewake around this register init sequences makes chip reset reliable again. Note that this is not the first such issue: commit f01db988ef6f6c70a6cc36ee71e4a98a68901229 Author: Sean Paul Date: Fri Mar 16 12:43:22 2012 -0400 drm/i915: Add wait_for in init_ring_common added delay loops to make RING_START and RING_CTL initialization reliable on the blt ring at boot-up. So I guess it won't hurt if we do this unconditionally for all force_wake needing gpus. To avoid copy&pasting of the HAS_FORCE_WAKE check I've added a new intel_info bit for that. v2: Fixup missing commas in static struct and properly handling the error case in init_ring_common, both noticed by Jani Nikula. Reported-and-tested-by: Yang Guang Reviewed-by: Eugeni Dodonov Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=50522 Signed-Off-by: Daniel Vetter [bwh: Backported to 3.2: - drop changes to Haswell device information - NEEDS_FORCE_WAKE didn't refer to Valley View anyway] Signed-off-by: Ben Hutchings [jcristau: further context adjustments for 3.4] Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_drv.c | 6 +++++- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/intel_ringbuffer.c | 16 +++++++++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 01cc14e653c..89f3d4aed66 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -224,6 +224,7 @@ static const struct intel_device_info intel_sandybridge_d_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, + .has_force_wake = 1, }; static const struct intel_device_info intel_sandybridge_m_info = { @@ -233,6 +234,7 @@ static const struct intel_device_info intel_sandybridge_m_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, + .has_force_wake = 1, }; static const struct intel_device_info intel_ivybridge_d_info = { @@ -241,6 +243,7 @@ static const struct intel_device_info intel_ivybridge_d_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, + .has_force_wake = 1, }; static const struct intel_device_info intel_ivybridge_m_info = { @@ -250,6 +253,7 @@ static const struct intel_device_info intel_ivybridge_m_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, + .has_force_wake = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ @@ -995,7 +999,7 @@ MODULE_LICENSE("GPL and additional rights"); /* We give fast paths for the really cool registers */ #define NEEDS_FORCE_WAKE(dev_priv, reg) \ - (((dev_priv)->info->gen >= 6) && \ + ((HAS_FORCE_WAKE((dev_priv)->dev)) && \ ((reg) < 0x40000) && \ ((reg) != FORCEWAKE)) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a8edd5379e7..e86f6fd3ed5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -255,6 +255,7 @@ struct intel_device_info { u8 is_broadwater:1; u8 is_crestline:1; u8 is_ivybridge:1; + u8 has_force_wake:1; u8 has_fbc:1; u8 has_pipe_cxsr:1; u8 has_hotplug:1; @@ -1051,6 +1052,8 @@ struct drm_i915_file_private { #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) +#define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) + #include "i915_trace.h" /** diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 302d3d54fb4..60db39df7a0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -249,10 +249,15 @@ u32 intel_ring_get_active_head(struct intel_ring_buffer *ring) static int init_ring_common(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = ring->dev->dev_private; + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj = ring->obj; + int ret = 0; u32 head; + if (HAS_FORCE_WAKE(dev)) + gen6_gt_force_wake_get(dev_priv); + /* Stop the ring if it's running. */ I915_WRITE_CTL(ring, 0); I915_WRITE_HEAD(ring, 0); @@ -300,7 +305,8 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_READ_HEAD(ring), I915_READ_TAIL(ring), I915_READ_START(ring)); - return -EIO; + ret = -EIO; + goto out; } if (!drm_core_check_feature(ring->dev, DRIVER_MODESET)) @@ -312,7 +318,11 @@ static int init_ring_common(struct intel_ring_buffer *ring) ring->last_retired_head = -1; } - return 0; +out: + if (HAS_FORCE_WAKE(dev)) + gen6_gt_force_wake_put(dev_priv); + + return ret; } static int From feef244d1742de63b5a7292883276ee6e11a06c5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Mar 2012 13:07:05 +0100 Subject: [PATCH 1923/2357] drm/i915: Check VBIOS value for determining LVDS dual channel mode, too commit b03543857fd75876b96e10d4320b775e95041bb7 upstream. Currently i915 driver checks [PCH_]LVDS register bits to decide whether to set up the dual-link or the single-link mode. This relies implicitly on that BIOS initializes the register properly at boot. However, BIOS doesn't initialize it always. When the machine is booted with the closed lid, BIOS skips the LVDS reg initialization. This ends up in blank output on a machine with a dual-link LVDS when you open the lid after the boot. This patch adds a workaround for that problem by checking the initial LVDS register value in VBT. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=37742 Tested-By: Paulo Zanoni Reviewed-by: Rodrigo Vivi Reviewed-by: Adam Jackson Signed-off-by: Takashi Iwai Signed-off-by: Daniel Vetter Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_bios.c | 36 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++++++++++----- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e86f6fd3ed5..45c5cf83fae 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -406,6 +406,8 @@ typedef struct drm_i915_private { unsigned int lvds_use_ssc:1; unsigned int display_clock_mode:1; int lvds_ssc_freq; + unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + unsigned int lvds_val; /* used for checking LVDS channel mode */ struct { int rate; int lanes; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 3fe05245d3f..a2c9e56c0c1 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -174,6 +174,28 @@ get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); } +/* get lvds_fp_timing entry + * this function may return NULL if the corresponding entry is invalid + */ +static const struct lvds_fp_timing * +get_lvds_fp_timing(const struct bdb_header *bdb, + const struct bdb_lvds_lfp_data *data, + const struct bdb_lvds_lfp_data_ptrs *ptrs, + int index) +{ + size_t data_ofs = (const u8 *)data - (const u8 *)bdb; + u16 data_size = ((const u16 *)data)[-1]; /* stored in header */ + size_t ofs; + + if (index >= ARRAY_SIZE(ptrs->ptr)) + return NULL; + ofs = ptrs->ptr[index].fp_timing_offset; + if (ofs < data_ofs || + ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size) + return NULL; + return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs); +} + /* Try to find integrated panel data */ static void parse_lfp_panel_data(struct drm_i915_private *dev_priv, @@ -183,6 +205,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, const struct bdb_lvds_lfp_data *lvds_lfp_data; const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; const struct lvds_dvo_timing *panel_dvo_timing; + const struct lvds_fp_timing *fp_timing; struct drm_display_mode *panel_fixed_mode; int i, downclock; @@ -244,6 +267,19 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, "Normal Clock %dKHz, downclock %dKHz\n", panel_fixed_mode->clock, 10*downclock); } + + fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, + lvds_lfp_data_ptrs, + lvds_options->panel_type); + if (fp_timing) { + /* check the resolution, just to be sure */ + if (fp_timing->x_res == panel_fixed_mode->hdisplay && + fp_timing->y_res == panel_fixed_mode->vdisplay) { + dev_priv->bios_lvds_val = fp_timing->lvds_reg_val; + DRM_DEBUG_KMS("VBT initial LVDS value %x\n", + dev_priv->bios_lvds_val); + } + } } /* Try to find sdvo panel data */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 216504a6fb4..7cd342b0180 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -360,6 +360,27 @@ static const intel_limit_t intel_limits_ironlake_display_port = { .find_pll = intel_find_pll_ironlake_dp, }; +static bool is_dual_link_lvds(struct drm_i915_private *dev_priv, + unsigned int reg) +{ + unsigned int val; + + if (dev_priv->lvds_val) + val = dev_priv->lvds_val; + else { + /* BIOS should set the proper LVDS register value at boot, but + * in reality, it doesn't set the value when the lid is closed; + * we need to check "the value to be set" in VBT when LVDS + * register is uninitialized. + */ + val = I915_READ(reg); + if (!(val & ~LVDS_DETECTED)) + val = dev_priv->bios_lvds_val; + dev_priv->lvds_val = val; + } + return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; +} + static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, int refclk) { @@ -368,8 +389,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) { + if (is_dual_link_lvds(dev_priv, PCH_LVDS)) { /* LVDS dual channel */ if (refclk == 100000) limit = &intel_limits_ironlake_dual_lvds_100m; @@ -397,8 +417,7 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + if (is_dual_link_lvds(dev_priv, LVDS)) /* LVDS with dual channel */ limit = &intel_limits_g4x_dual_channel_lvds; else @@ -536,8 +555,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, * reliably set up different single/dual channel state, if we * even can. */ - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + if (is_dual_link_lvds(dev_priv, LVDS)) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow; From 392dcfdce12ee18d511c74132704c8749b149141 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Fri, 16 Mar 2012 12:43:22 -0400 Subject: [PATCH 1924/2357] drm/i915: Add wait_for in init_ring_common commit f01db988ef6f6c70a6cc36ee71e4a98a68901229 upstream. I have seen a number of "blt ring initialization failed" messages where the ctl or start registers are not the correct value. Upon further inspection, if the code just waited a little bit, it would read the correct value. Adding the wait_for to these reads should eliminate the issue. Signed-off-by: Sean Paul Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 60db39df7a0..c17325ce379 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -295,9 +295,9 @@ static int init_ring_common(struct intel_ring_buffer *ring) | RING_VALID); /* If the head is still not zero, the ring is dead */ - if ((I915_READ_CTL(ring) & RING_VALID) == 0 || - I915_READ_START(ring) != obj->gtt_offset || - (I915_READ_HEAD(ring) & HEAD_ADDR) != 0) { + if (wait_for((I915_READ_CTL(ring) & RING_VALID) != 0 && + I915_READ_START(ring) == obj->gtt_offset && + (I915_READ_HEAD(ring) & HEAD_ADDR) == 0, 50)) { DRM_ERROR("%s initialization failed " "ctl %08x head %08x tail %08x start %08x\n", ring->name, From b834417b9134b533c79a12ff134da40b982d6b2f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 10:05:38 +0100 Subject: [PATCH 1925/2357] drm/i915: Wait for all pending operations to the fb before disabling the pipe commit 0f91128d88bbb8b0a8e7bb93df2c40680871d45a upstream. During modeset we have to disable the pipe to reconfigure its timings and maybe its size. Userspace may have queued up command buffers that depend upon the pipe running in a certain configuration and so the commands may become confused across the modeset. At the moment, we use a less than satisfactory kick-scanline-waits should the GPU hang during the modeset. It should be more reliable to wait for the pending operations to complete first, even though we still have a window for userspace to submit a broken command buffer during the modeset. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7cd342b0180..9a29fd67c3a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2897,16 +2897,14 @@ static void intel_clear_scanline_wait(struct drm_device *dev) static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) { - struct drm_i915_gem_object *obj; - struct drm_i915_private *dev_priv; + struct drm_device *dev = crtc->dev; if (crtc->fb == NULL) return; - obj = to_intel_framebuffer(crtc->fb)->obj; - dev_priv = crtc->dev->dev_private; - wait_event(dev_priv->pending_flip_queue, - atomic_read(&obj->pending_flip) == 0); + mutex_lock(&dev->struct_mutex); + intel_finish_fb(crtc->fb); + mutex_unlock(&dev->struct_mutex); } static bool intel_crtc_driving_pch(struct drm_crtc *crtc) @@ -3372,23 +3370,6 @@ static void intel_crtc_disable(struct drm_crtc *crtc) struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; struct drm_device *dev = crtc->dev; - /* Flush any pending WAITs before we disable the pipe. Note that - * we need to drop the struct_mutex in order to acquire it again - * during the lowlevel dpms routines around a couple of the - * operations. It does not look trivial nor desirable to move - * that locking higher. So instead we leave a window for the - * submission of further commands on the fb before we can actually - * disable it. This race with userspace exists anyway, and we can - * only rely on the pipe being disabled by userspace after it - * receives the hotplug notification and has flushed any pending - * batches. - */ - if (crtc->fb) { - mutex_lock(&dev->struct_mutex); - intel_finish_fb(crtc->fb); - mutex_unlock(&dev->struct_mutex); - } - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane); assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe); From 1478f45496fca13f42fb7f940908b5cd3bee105c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 13 Apr 2012 15:51:51 +0200 Subject: [PATCH 1926/2357] drm/i915: don't pwrite tiled objects through the gtt commit c07496fa61f4c5cb2addd1c57f6b22fcaeea2eeb upstream. ... we will botch up the bit17 swizzling. Furthermore tiled pwrite is a (now) unused slowpath, so no one really cares. This fixes the last swizzling issues I have with i-g-t on my bit17 swizzling i915G. No regression, it's been broken since the dawn of gem, but it's nice for regression tracking when really _all_ i-g-t tests work. Actually this is not true, Chris Wilson noticed while reviewing this patch that the commit commit d9e86c0ee60f323e890484628f351bf50fa9a15d Author: Chris Wilson Date: Wed Nov 10 16:40:20 2010 +0000 drm/i915: Pipelined fencing [infrastructure] contained a functional change that broke things. Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter [jcristau: adjust context for 3.4] Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0d1e4b7b4b9..72354455703 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -928,6 +928,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, } if (obj->gtt_space && + obj->tiling_mode == I915_TILING_NONE && obj->base.write_domain != I915_GEM_DOMAIN_CPU) { ret = i915_gem_object_pin(obj, 0, true); if (ret) From 3eafd581892bca5588762bb30d797c74f0441fac Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 17 Jul 2012 14:02:43 -0400 Subject: [PATCH 1927/2357] drm/radeon: fix up pll selection on DCE5/6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 26fe45a0a76f165425f332a5aaa298f149f9db22 upstream. Selecting ATOM_PPLL_INVALID should be equivalent as the DCPLL or PPLL0 are already programmed for the DISPCLK, but the preferred method is to always specify the PLL selected. SetPixelClock will check the parameters and skip the programming if the PLL is already set up. Signed-off-by: Alex Deucher Reviewed-by: Christian König Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_crtc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 19f4082c618..ca2548b2650 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1533,7 +1533,11 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) * crtc virtual pixel clock. */ if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { - if (ASIC_IS_DCE5(rdev) || rdev->clock.dp_extclk) + if (ASIC_IS_DCE5(rdev)) + return ATOM_DCPLL; + else if (ASIC_IS_DCE6(rdev)) + return ATOM_PPLL0; + else if (rdev->clock.dp_extclk) return ATOM_PPLL_INVALID; } } From 64d3c4a1eaca2134821407f7e4c3de9bf3d6aba9 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 28 May 2012 16:43:00 -0300 Subject: [PATCH 1928/2357] drm/i915: add some barriers when changing DIPs commit 9d9740f099f2eaf309c4c9cbc0d732507140db28 upstream. On IVB and older, we basically have two registers: the control and the data register. We write a few consecutitve times to the control register, and we need these writes to arrive exactly in the specified order. Also, when we're changing the data register, we need to guarantee that anything written to the control register already arrived (since changing the control register can change where the data register points to). Also, we need to make sure all the writes to the data register happen exactly in the specified order, and we also *can't* read the data register during this process, since reading and/or writing it will change the place it points to. So invoke the "better safe than sorry" rule and just be careful and put barriers everywhere :) On HSW we still have a control register that we write many times, but we have many data registers. Demanded-by: Chris Wilson Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter [bwh: Backported to 3.2: - There are only two write_infoframe functions to be modified - The other VIDEO_DIP_CTL writes are in entirely different functions] Signed-off-by: Ben Hutchings Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_hdmi.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index fb44e9d116e..c60100d48ce 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -138,14 +138,17 @@ static void i9xx_write_infoframe(struct drm_encoder *encoder, I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); + mmiowb(); for (i = 0; i < len; i += 4) { I915_WRITE(VIDEO_DIP_DATA, *data); data++; } + mmiowb(); flags |= intel_infoframe_flags(frame); I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); + POSTING_READ(VIDEO_DIP_CTL); } static void ironlake_write_infoframe(struct drm_encoder *encoder, @@ -168,14 +171,17 @@ static void ironlake_write_infoframe(struct drm_encoder *encoder, I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); + mmiowb(); for (i = 0; i < len; i += 4) { I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); data++; } + mmiowb(); flags |= intel_infoframe_flags(frame); I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); + POSTING_READ(reg); } static void intel_set_infoframe(struct drm_encoder *encoder, struct dip_infoframe *frame) @@ -549,10 +555,13 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) if (!HAS_PCH_SPLIT(dev)) { intel_hdmi->write_infoframe = i9xx_write_infoframe; I915_WRITE(VIDEO_DIP_CTL, 0); + POSTING_READ(VIDEO_DIP_CTL); } else { intel_hdmi->write_infoframe = ironlake_write_infoframe; - for_each_pipe(i) + for_each_pipe(i) { I915_WRITE(TVIDEO_DIP_CTL(i), 0); + POSTING_READ(TVIDEO_DIP_CTL(i)); + } } drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); From df2a959c0e03e58f4efebbc49b6065014e3798e4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 11 May 2012 18:01:33 +0100 Subject: [PATCH 1929/2357] drm/i915: SDVO hotplug have different interrupt status bits for i915/i965/g4x commit 084b612ecf8e59973576b2f644e6949609c79375 upstream. Note that gen3 is the only platform where we've got the bit definitions right, hence the workaround of disabling sdvo hotplug support on i945g/gm is not due to misdiagnosis of broken hotplug irq handling ... Signed-off-by: Chris Wilson [danvet: add some blurb about sdvo hotplug fail on i945g/gm I've wondered about while reviewing.] Signed-off-by: Daniel Vetter [bwh: Backported to 3.2: - Adjust context - Handle all three cases in i915_driver_irq_postinstall() as there are not separate functions for gen3 and gen4+ - Carry on using IS_SDVOB() in intel_sdvo_init()] Signed-off-by: Ben Hutchings Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_irq.c | 20 ++++++++++++++++---- drivers/gpu/drm/i915/i915_reg.h | 10 ++++++++-- drivers/gpu/drm/i915/intel_sdvo.c | 17 +++++++++++++---- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 26c67a78877..54fcbc15007 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2051,10 +2051,22 @@ static int i915_driver_irq_postinstall(struct drm_device *dev) hotplug_en |= HDMIC_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) hotplug_en |= HDMID_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) - hotplug_en |= SDVOC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS) - hotplug_en |= SDVOB_HOTPLUG_INT_EN; + if (IS_G4X(dev)) { + if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X) + hotplug_en |= SDVOC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X) + hotplug_en |= SDVOB_HOTPLUG_INT_EN; + } else if (IS_GEN4(dev)) { + if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965) + hotplug_en |= SDVOC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965) + hotplug_en |= SDVOB_HOTPLUG_INT_EN; + } else { + if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) + hotplug_en |= SDVOC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) + hotplug_en |= SDVOB_HOTPLUG_INT_EN; + } if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { hotplug_en |= CRT_HOTPLUG_INT_EN; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index eaf38060223..06c0fc3dcd6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1491,14 +1491,20 @@ #define DPC_HOTPLUG_INT_STATUS (1 << 28) #define HDMID_HOTPLUG_INT_STATUS (1 << 27) #define DPD_HOTPLUG_INT_STATUS (1 << 27) +/* CRT/TV common between gen3+ */ #define CRT_HOTPLUG_INT_STATUS (1 << 11) #define TV_HOTPLUG_INT_STATUS (1 << 10) #define CRT_HOTPLUG_MONITOR_MASK (3 << 8) #define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) #define CRT_HOTPLUG_MONITOR_MONO (2 << 8) #define CRT_HOTPLUG_MONITOR_NONE (0 << 8) -#define SDVOC_HOTPLUG_INT_STATUS (1 << 7) -#define SDVOB_HOTPLUG_INT_STATUS (1 << 6) +/* SDVO is different across gen3/4 */ +#define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3) +#define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2) +#define SDVOC_HOTPLUG_INT_STATUS_I965 (3 << 4) +#define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2) +#define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7) +#define SDVOB_HOTPLUG_INT_STATUS_I915 (1 << 6) /* SDVO port control */ #define SDVOB 0x61140 diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index b96e8c835c8..53cbcc3dced 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2528,6 +2528,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; struct intel_sdvo *intel_sdvo; + u32 hotplug_mask; int i; intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); @@ -2558,10 +2559,18 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) } } - if (IS_SDVOB(sdvo_reg)) - dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; - else - dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; + hotplug_mask = 0; + if (IS_G4X(dev)) { + hotplug_mask = IS_SDVOB(sdvo_reg) ? + SDVOB_HOTPLUG_INT_STATUS_G4X : SDVOC_HOTPLUG_INT_STATUS_G4X; + } else if (IS_GEN4(dev)) { + hotplug_mask = IS_SDVOB(sdvo_reg) ? + SDVOB_HOTPLUG_INT_STATUS_I965 : SDVOC_HOTPLUG_INT_STATUS_I965; + } else { + hotplug_mask = IS_SDVOB(sdvo_reg) ? + SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915; + } + dev_priv->hotplug_supported_mask |= hotplug_mask; drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); From 90877b10fb58e3ffa5add2a040d0f10d8ac67535 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 6 Aug 2012 17:06:03 -0400 Subject: [PATCH 1930/2357] drm/radeon: fix ordering in pll picking on dce4+ commit ecd67955fd4c8e66e4df312098989d5fa7da624c upstream. No functional change, but re-order the cases so they evaluate properly due to the way the DCE macros work. Noticed by kallisti5 on IRC. Signed-off-by: Alex Deucher Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_crtc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index ca2548b2650..15594a30ebd 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1533,12 +1533,12 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) * crtc virtual pixel clock. */ if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { - if (ASIC_IS_DCE5(rdev)) - return ATOM_DCPLL; + if (rdev->clock.dp_extclk) + return ATOM_PPLL_INVALID; else if (ASIC_IS_DCE6(rdev)) return ATOM_PPLL0; - else if (rdev->clock.dp_extclk) - return ATOM_PPLL_INVALID; + else if (ASIC_IS_DCE5(rdev)) + return ATOM_DCPLL; } } } From d1879e35935a07a67420fab66a02ae3b4148960f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 29 Aug 2012 14:08:42 +0300 Subject: [PATCH 1931/2357] drm/i915: only enable sdvo hotplug irq if needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit fcbc50da7753b210b4442ca9abc4efbd4e481f6e upstream. Avoid constant wakeups caused by noisy irq lines when we don't even care about the irq. This should be particularly useful for i945g/gm where the hotplug has been disabled: commit 768b107e4b3be0acf6f58e914afe4f337c00932b Author: Daniel Vetter Date: Fri May 4 11:29:56 2012 +0200 drm/i915: disable sdvo hotplug on i945g/gm v2: While at it, remove the bogus hotplug_active read, and do not mask hotplug_active[0] before checking whether the irq is needed, per discussion with Daniel on IRC. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=38442 Tested-by: Dominik Köppl Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_sdvo.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 53cbcc3dced..1b6b1570f4c 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2570,7 +2570,6 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) hotplug_mask = IS_SDVOB(sdvo_reg) ? SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915; } - dev_priv->hotplug_supported_mask |= hotplug_mask; drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); @@ -2578,14 +2577,6 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) goto err; - /* Set up hotplug command - note paranoia about contents of reply. - * We assume that the hardware is in a sane state, and only touch - * the bits we think we understand. - */ - intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, - &intel_sdvo->hotplug_active, 2); - intel_sdvo->hotplug_active[0] &= ~0x3; - if (intel_sdvo_output_setup(intel_sdvo, intel_sdvo->caps.output_flags) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", @@ -2593,6 +2584,12 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) goto err; } + /* Only enable the hotplug irq if we need it, to work around noisy + * hotplug lines. + */ + if (intel_sdvo->hotplug_active[0]) + dev_priv->hotplug_supported_mask |= hotplug_mask; + intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); /* Set the input timing to the screen. Assume always input 0. */ From 755a4897be165bc3b705ee6f83bda2253528b196 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 15 Sep 2012 09:41:57 +0100 Subject: [PATCH 1932/2357] drm/i915: Reduce a pin-leak BUG into a WARN commit 7e81a42e341a4f15d76624b7c02ffb21b085b56f upstream. Pin-leaks persist and we get the perennial bug reports of machine lockups to the BUG_ON(pin_count==MAX). If we instead loudly report that the object cannot be pinned at that time it should prevent the driver from locking up, and hopefully restore a semblance of working whilst still leaving us a OOPS to debug. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 72354455703..a230a93935b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3318,7 +3318,8 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, struct drm_i915_private *dev_priv = dev->dev_private; int ret; - BUG_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); + if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) + return -EBUSY; WARN_ON(i915_verify_lists(dev)); if (obj->gtt_space != NULL) { From 0907a85413bbf79fcdb40c1d984d805f5840cbf9 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Mon, 18 Jun 2012 19:03:38 -0300 Subject: [PATCH 1933/2357] drm/i915: prevent possible pin leak on error path commit ab3951eb74e7c33a2f5b7b64d72e82f1eea61571 upstream. We should not hit this under any sane conditions, but still, this does not looks right. Reported-by: Herton Ronaldo Krzesinski CC: Chris Wilson CC: Daniel Vetter Reviewed-by: Chris Wlison Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9a29fd67c3a..db780cbad99 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7505,7 +7505,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, default: WARN_ONCE(1, "unknown plane in flip command\n"); ret = -ENODEV; - goto err; + goto err_unpin; } ret = intel_ring_begin(ring, 4); From 77f0c3b4713f398e28461c7bfd5fe69126a6edf7 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 3 Oct 2012 19:34:24 -0700 Subject: [PATCH 1934/2357] drm/i915: Fix GT_MODE default value commit f8f2ac9a76b0f80a6763ca316116a7bab8486997 upstream. I can't even find how I figured this might be needed anymore. But sure enough, the value I'm reading back on platforms doesn't match what the docs recommends. It seemed to fix Chris' GT1 in limited testing as well. Tested-by: Chris Wilson Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter [bwh: Backported to 3.2: open-code _MASKED_BIT_{ENABLE,DISABLE}] Signed-off-by: Ben Hutchings Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_display.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 06c0fc3dcd6..27a296a1415 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -445,6 +445,9 @@ # define VS_TIMER_DISPATCH (1 << 6) # define MI_FLUSH_ENABLE (1 << 12) +#define GEN6_GT_MODE 0x20d0 +#define GEN6_GT_MODE_HI (1 << 9) + #define GFX_MODE 0x02520 #define GFX_MODE_GEN7 0x0229c #define RING_MODE_GEN7(ring) ((ring)->mmio_base+0x29c) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index db780cbad99..db2163f2e32 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8620,6 +8620,11 @@ static void gen6_init_clock_gating(struct drm_device *dev) DISPPLANE_TRICKLE_FEED_DISABLE); intel_flush_display_plane(dev_priv, pipe); } + + /* The default value should be 0x200 according to docs, but the two + * platforms I checked have a 0 for this. (Maybe BIOS overrides?) */ + I915_WRITE(GEN6_GT_MODE, 0xffff << 16); + I915_WRITE(GEN6_GT_MODE, GEN6_GT_MODE_HI << 16 | GEN6_GT_MODE_HI); } static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) From 1d35b4e271f56cad111b7150a1de57954e441765 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 2 Oct 2012 17:54:35 +0200 Subject: [PATCH 1935/2357] drm/i915: call drm_handle_vblank before finish_page_flip commit 74d44445afb9f50126eba052adeb89827cee88f3 upstream. ... since finish_page_flip needs the vblank timestamp generated in drm_handle_vblank. Somehow all the gmch platforms get it right, but all the pch platform irq handlers get is wrong. Hooray for copy& pasting! Currently this gets papered over by a gross hack in finish_page_flip. A second patch will remove that. Note that without this, the new timestamp sanity checks in flip_test occasionally get tripped up, hence the cc: stable tag. Reviewed-by: mario.kleiner@tuebingen.mpg.de Tested-by: Imre Deak Signed-off-by: Daniel Vetter [bwh: Backported to 3.2: no loop over pipes in ivybridge_irq_handler(), so make a similar change to that in ironlake_irq_handler()] Signed-off-by: Ben Hutchings Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_irq.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 54fcbc15007..8bca2d2d804 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -530,6 +530,12 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) if (de_iir & DE_GSE_IVB) intel_opregion_gse_intr(dev); + if (de_iir & DE_PIPEA_VBLANK_IVB) + drm_handle_vblank(dev, 0); + + if (de_iir & DE_PIPEB_VBLANK_IVB) + drm_handle_vblank(dev, 1); + if (de_iir & DE_PLANEA_FLIP_DONE_IVB) { intel_prepare_page_flip(dev, 0); intel_finish_page_flip_plane(dev, 0); @@ -540,12 +546,6 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) intel_finish_page_flip_plane(dev, 1); } - if (de_iir & DE_PIPEA_VBLANK_IVB) - drm_handle_vblank(dev, 0); - - if (de_iir & DE_PIPEB_VBLANK_IVB) - drm_handle_vblank(dev, 1); - /* check event from PCH */ if (de_iir & DE_PCH_EVENT_IVB) { if (pch_iir & SDE_HOTPLUG_MASK_CPT) @@ -622,6 +622,12 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) if (de_iir & DE_GSE) intel_opregion_gse_intr(dev); + if (de_iir & DE_PIPEA_VBLANK) + drm_handle_vblank(dev, 0); + + if (de_iir & DE_PIPEB_VBLANK) + drm_handle_vblank(dev, 1); + if (de_iir & DE_PLANEA_FLIP_DONE) { intel_prepare_page_flip(dev, 0); intel_finish_page_flip_plane(dev, 0); @@ -632,12 +638,6 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) intel_finish_page_flip_plane(dev, 1); } - if (de_iir & DE_PIPEA_VBLANK) - drm_handle_vblank(dev, 0); - - if (de_iir & DE_PIPEB_VBLANK) - drm_handle_vblank(dev, 1); - /* check event from PCH */ if (de_iir & DE_PCH_EVENT) { if (pch_iir & hotplug_mask) From 7d17dc4851ad423a848e716354c9499c537fcb5b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 Sep 2012 21:25:58 +0100 Subject: [PATCH 1936/2357] drm/i915: Flush the pending flips on the CRTC before modification commit 5bb61643f6a70d48de9cfe91ad0fee0d618b6816 upstream. This was meant to be the purpose of the intel_crtc_wait_for_pending_flips() function which is called whilst preparing the CRTC for a modeset or before disabling. However, as Ville Syrjala pointed out, we set the pending flip notification on the old framebuffer that is no longer attached to the CRTC by the time we come to flush the pending operations. Instead, we can simply wait on the pending unpin work to be finished on this CRTC, knowning that the hardware has therefore finished modifying the registers, before proceeding with our direct access. Fixes i-g-t/flip_test on non-pch platforms. pch platforms simply schedule the flip immediately when the pipe is disabled, leading to other funny issues. Signed-off-by: Chris Wilson [danvet: Added i-g-t note and cc: stable] Signed-off-by: Daniel Vetter Signed-off-by: Julien Cristau Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index db2163f2e32..8e95c943286 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2895,13 +2895,34 @@ static void intel_clear_scanline_wait(struct drm_device *dev) I915_WRITE_CTL(ring, tmp); } +static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + bool pending; + + if (atomic_read(&dev_priv->mm.wedged)) + return false; + + spin_lock_irqsave(&dev->event_lock, flags); + pending = to_intel_crtc(crtc)->unpin_work != NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + return pending; +} + static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; if (crtc->fb == NULL) return; + wait_event(dev_priv->pending_flip_queue, + !intel_crtc_has_pending_flip(crtc)); + mutex_lock(&dev->struct_mutex); intel_finish_fb(crtc->fb); mutex_unlock(&dev->struct_mutex); @@ -7258,9 +7279,8 @@ static void do_intel_finish_page_flip(struct drm_device *dev, atomic_clear_mask(1 << intel_crtc->plane, &obj->pending_flip.counter); - if (atomic_read(&obj->pending_flip) == 0) - wake_up(&dev_priv->pending_flip_queue); + wake_up(&dev_priv->pending_flip_queue); schedule_work(&work->work); trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); From 627e242990064e050cf09436c46d66ccf0f8a6b9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 7 Jan 2013 10:27:13 +0100 Subject: [PATCH 1937/2357] Revert "drm/i915: no lvds quirk for Zotac ZDBOX SD ID12/ID13" commit 48e858340dae43189a4e55647f6eac736766f828 upstream. This reverts commit 9756fe38d10b2bf90c81dc4d2f17d5632e135364. The bogus lvds output is actually a lvds->hdmi bridge, which we don't really support. But unconditionally disabling it breaks some existing setups. Reported-by: John Tapsell References: http://permalink.gmane.org/gmane.comp.freedesktop.xorg.drivers.intel/17237 Signed-off-by: Daniel Vetter Cc: Luis Henriques Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_lvds.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 802fec20ff8..a8b28c493a8 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -777,14 +777,6 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "MS-7469"), }, }, - { - .callback = intel_no_lvds_dmi_callback, - .ident = "ZOTAC ZBOXSD-ID12/ID13", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ZOTAC"), - DMI_MATCH(DMI_BOARD_NAME, "ZBOXSD-ID12/ID13"), - }, - }, { .callback = intel_no_lvds_dmi_callback, .ident = "Gigabyte GA-D525TUD", From a2d928ffc91d237f178d769943bc785f1a7f7435 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 30 Jul 2012 16:21:17 -0700 Subject: [PATCH 1938/2357] ceph: close old con before reopening on mds reconnect When we detect a mds session reset, close the old ceph_connection before reopening it. This ensures we clean up the old socket properly and keep the ceph_connection state correct. Signed-off-by: Sage Weil Reviewed-by: Alex Elder Reviewed-by: Yehuda Sadeh (cherry picked from commit a53aab645c82f0146e35684b34692c69b5118121) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 7f1682da29a..95708dd092f 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2528,6 +2528,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, session->s_state = CEPH_MDS_SESSION_RECONNECTING; session->s_seq = 0; + ceph_con_close(&session->s_con); ceph_con_open(&session->s_con, CEPH_ENTITY_TYPE_MDS, mds, ceph_mdsmap_get_addr(mdsc->mdsmap, mds)); From 95268c46ace4492b924abf6e82c6974c152bee29 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 21 Nov 2011 18:14:25 -0800 Subject: [PATCH 1939/2357] rbd: return errors for mapped but deleted snapshot When a snapshot is deleted, the OSD will return ENOENT when reading from it. This is normally interpreted as a hole by rbd, which will return zeroes. To minimize the time in which this can happen, stop requests early when we are notified that our snapshot no longer exists. [elder@inktank.com: updated __rbd_init_snaps_header() logic] Signed-off-by: Josh Durgin Reviewed-by: Alex Elder (cherry picked from commit e88a36ec961b8c1899c59c5e4ae35a318c0209d3) Signed-off-by: Greg Kroah-Hartman Conflicts: drivers/block/rbd.c --- drivers/block/rbd.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 7b331366a8a..4f7ed7fa549 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -174,9 +174,13 @@ struct rbd_device { /* protects updating the header */ struct rw_semaphore header_rwsem; + /* name of the snapshot this device reads from */ char snap_name[RBD_MAX_SNAP_NAME_LEN]; + /* id of the snapshot this device reads from */ u64 snap_id; /* current snapshot id */ - int read_only; + /* whether the snap_id this device reads from still exists */ + bool snap_exists; + int read_only; struct list_head node; @@ -590,6 +594,7 @@ static int rbd_header_set_snap(struct rbd_device *dev, u64 *size) else snapc->seq = 0; dev->snap_id = CEPH_NOSNAP; + dev->snap_exists = false; dev->read_only = 0; if (size) *size = header->image_size; @@ -598,6 +603,7 @@ static int rbd_header_set_snap(struct rbd_device *dev, u64 *size) if (ret < 0) goto done; dev->snap_id = snapc->seq; + dev->snap_exists = true; dev->read_only = 1; } @@ -1466,6 +1472,21 @@ static void rbd_rq_fn(struct request_queue *q) spin_unlock_irq(q->queue_lock); + if (rbd_dev->snap_id != CEPH_NOSNAP) { + bool snap_exists; + + down_read(&rbd_dev->header_rwsem); + snap_exists = rbd_dev->snap_exists; + up_read(&rbd_dev->header_rwsem); + + if (!snap_exists) { + dout("request for non-existent snapshot"); + spin_lock_irq(q->queue_lock); + __blk_end_request_all(rq, -ENXIO); + continue; + } + } + dout("%s 0x%x bytes at 0x%llx\n", do_write ? "write" : "read", size, blk_rq_pos(rq) * SECTOR_SIZE); @@ -2069,7 +2090,14 @@ static int __rbd_init_snaps_header(struct rbd_device *rbd_dev) cur_id = rbd_dev->header.snapc->snaps[i - 1]; if (!i || old_snap->id < cur_id) { - /* old_snap->id was skipped, thus was removed */ + /* + * old_snap->id was skipped, thus was + * removed. If this rbd_dev is mapped to + * the removed snapshot, record that it no + * longer exists, to prevent further I/O. + */ + if (rbd_dev->snap_id == old_snap->id) + rbd_dev->snap_exists = false; __rbd_remove_snap_dev(rbd_dev, old_snap); continue; } From 7272b7d3db9160716acce4ae387cf98fd24ff820 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 21 Nov 2011 17:13:54 -0800 Subject: [PATCH 1940/2357] rbd: only reset capacity when pointing to head Snapshots cannot be resized, and the new capacity of head should not be reflected by the snapshot. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder (cherry picked from commit 474ef7ce832d471148f63a9d07f67fc5564834f1) Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 4f7ed7fa549..52a045b11d4 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1721,7 +1721,12 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev) return ret; /* resized? */ - set_capacity(rbd_dev->disk, h.image_size / SECTOR_SIZE); + if (rbd_dev->snap_id == CEPH_NOSNAP) { + sector_t size = (sector_t) h.image_size / SECTOR_SIZE; + + dout("setting size to %llu sectors", (unsigned long long) size); + set_capacity(rbd_dev->disk, size); + } down_write(&rbd_dev->header_rwsem); From 929333aa674e6c1b3026a3b3c8f27907e9a7de5b Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 5 Dec 2011 10:35:04 -0800 Subject: [PATCH 1941/2357] rbd: expose the correct size of the device in sysfs If an image was mapped to a snapshot, the size of the head version would be shown. Protect capacity with header_rwsem, since it may change. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder (cherry picked from commit a51aa0c042fa39946dd017d5f91a073300a71577) Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 52a045b11d4..0ac989cf240 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1720,6 +1720,8 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev) if (ret < 0) return ret; + down_write(&rbd_dev->header_rwsem); + /* resized? */ if (rbd_dev->snap_id == CEPH_NOSNAP) { sector_t size = (sector_t) h.image_size / SECTOR_SIZE; @@ -1728,8 +1730,6 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev) set_capacity(rbd_dev->disk, size); } - down_write(&rbd_dev->header_rwsem); - snap_seq = rbd_dev->header.snapc->seq; if (rbd_dev->header.total_snaps && rbd_dev->header.snapc->snaps[0] == snap_seq) @@ -1844,8 +1844,13 @@ static ssize_t rbd_size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); + sector_t size; + + down_read(&rbd_dev->header_rwsem); + size = get_capacity(rbd_dev->disk); + up_read(&rbd_dev->header_rwsem); - return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size); + return sprintf(buf, "%llu\n", (unsigned long long) size * SECTOR_SIZE); } static ssize_t rbd_major_show(struct device *dev, From 894910deddfe36e66079bea42ae9d728b3f4b5cc Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 5 Dec 2011 10:41:28 -0800 Subject: [PATCH 1942/2357] rbd: set image size when header is updated The image may have been resized. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder (cherry picked from commit 93a24e084d67ba2fcb9a4c289135825b623ec864) Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 0ac989cf240..1dcfd092087 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1741,6 +1741,7 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev) kfree(rbd_dev->header.snap_names); kfree(rbd_dev->header.snap_sizes); + rbd_dev->header.image_size = h.image_size; rbd_dev->header.total_snaps = h.total_snaps; rbd_dev->header.snapc = h.snapc; rbd_dev->header.snap_names = h.snap_names; From fc5eb627a897ac41581692abf60ffea874df2e55 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 5 Dec 2011 14:03:05 -0800 Subject: [PATCH 1943/2357] rbd: use reference counting for the snap context This prevents a race between requests with a given snap context and header updates that free it. The osd client was already expecting the snap context to be reference counted, since it get()s it in ceph_osdc_build_request and put()s it when the request completes. Also remove the second down_read()/up_read() on header_rwsem in rbd_do_request, which wasn't actually preventing this race or protecting any other data. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder (cherry picked from commit d1d25646543134d756a02ffe4e02073faa761f2c) Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 1dcfd092087..dc26c2e48d8 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -615,7 +615,7 @@ static int rbd_header_set_snap(struct rbd_device *dev, u64 *size) static void rbd_header_free(struct rbd_image_header *header) { - kfree(header->snapc); + ceph_put_snap_context(header->snapc); kfree(header->snap_names); kfree(header->snap_sizes); } @@ -893,13 +893,10 @@ static int rbd_do_request(struct request *rq, dout("rbd_do_request obj=%s ofs=%lld len=%lld\n", obj, len, ofs); - down_read(&dev->header_rwsem); - osdc = &dev->rbd_client->client->osdc; req = ceph_osdc_alloc_request(osdc, flags, snapc, ops, false, GFP_NOIO, pages, bio); if (!req) { - up_read(&dev->header_rwsem); ret = -ENOMEM; goto done_pages; } @@ -934,7 +931,6 @@ static int rbd_do_request(struct request *rq, snapc, &mtime, req->r_oid, req->r_oid_len); - up_read(&dev->header_rwsem); if (linger_req) { ceph_osdc_set_request_linger(osdc, req); @@ -1446,6 +1442,7 @@ static void rbd_rq_fn(struct request_queue *q) u64 ofs; int num_segs, cur_seg = 0; struct rbd_req_coll *coll; + struct ceph_snap_context *snapc; /* peek at request from block layer */ if (!rq) @@ -1472,21 +1469,20 @@ static void rbd_rq_fn(struct request_queue *q) spin_unlock_irq(q->queue_lock); - if (rbd_dev->snap_id != CEPH_NOSNAP) { - bool snap_exists; + down_read(&rbd_dev->header_rwsem); - down_read(&rbd_dev->header_rwsem); - snap_exists = rbd_dev->snap_exists; + if (rbd_dev->snap_id != CEPH_NOSNAP && !rbd_dev->snap_exists) { up_read(&rbd_dev->header_rwsem); - - if (!snap_exists) { - dout("request for non-existent snapshot"); - spin_lock_irq(q->queue_lock); - __blk_end_request_all(rq, -ENXIO); - continue; - } + dout("request for non-existent snapshot"); + spin_lock_irq(q->queue_lock); + __blk_end_request_all(rq, -ENXIO); + continue; } + snapc = ceph_get_snap_context(rbd_dev->header.snapc); + + up_read(&rbd_dev->header_rwsem); + dout("%s 0x%x bytes at 0x%llx\n", do_write ? "write" : "read", size, blk_rq_pos(rq) * SECTOR_SIZE); @@ -1496,6 +1492,7 @@ static void rbd_rq_fn(struct request_queue *q) if (!coll) { spin_lock_irq(q->queue_lock); __blk_end_request_all(rq, -ENOMEM); + ceph_put_snap_context(snapc); continue; } @@ -1519,7 +1516,7 @@ static void rbd_rq_fn(struct request_queue *q) /* init OSD command: write or read */ if (do_write) rbd_req_write(rq, rbd_dev, - rbd_dev->header.snapc, + snapc, ofs, op_size, bio, coll, cur_seg); @@ -1542,6 +1539,8 @@ static void rbd_rq_fn(struct request_queue *q) if (bp) bio_pair_release(bp); spin_lock_irq(q->queue_lock); + + ceph_put_snap_context(snapc); } } @@ -1737,7 +1736,7 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev) if head moves */ follow_seq = 1; - kfree(rbd_dev->header.snapc); + ceph_put_snap_context(rbd_dev->header.snapc); kfree(rbd_dev->header.snap_names); kfree(rbd_dev->header.snap_sizes); From ca9a5e33a97a965378a2a0387fd8acf3a0144950 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 5 Dec 2011 18:10:44 -0800 Subject: [PATCH 1944/2357] rbd: send header version when notifying Previously the original header version was sent. Now, we update it when the header changes. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder (cherry picked from commit a71b891bc7d77a070e723c8c53d1dd73cf931555) Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index dc26c2e48d8..52e295defb9 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1195,7 +1195,7 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev, if (ret < 0) return ret; - ops[0].watch.ver = cpu_to_le64(dev->header.obj_version); + ops[0].watch.ver = cpu_to_le64(ver); ops[0].watch.cookie = notify_id; ops[0].watch.flag = 0; @@ -1215,6 +1215,7 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev, static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) { struct rbd_device *dev = (struct rbd_device *)data; + u64 hver; int rc; if (!dev) @@ -1224,12 +1225,13 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) notify_id, (int)opcode); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); rc = __rbd_update_snaps(dev); + hver = dev->header.obj_version; mutex_unlock(&ctl_mutex); if (rc) pr_warning(RBD_DRV_NAME "%d got notification but failed to " " update snaps: %d\n", dev->major, rc); - rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name); + rbd_req_sync_notify_ack(dev, hver, notify_id, dev->obj_md_name); } /* @@ -1740,6 +1742,7 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev) kfree(rbd_dev->header.snap_names); kfree(rbd_dev->header.snap_sizes); + rbd_dev->header.obj_version = h.obj_version; rbd_dev->header.image_size = h.image_size; rbd_dev->header.total_snaps = h.total_snaps; rbd_dev->header.snapc = h.snapc; From 2c130889f540f0bc6bc866d436b2ec3a23ea8f2b Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 21 Aug 2012 15:55:25 -0700 Subject: [PATCH 1945/2357] ceph: tolerate (and warn on) extraneous dentry from mds If the MDS gives us a dentry and we weren't prepared to handle it, WARN_ON_ONCE instead of crashing. Reported-by: Yan, Zheng Signed-off-by: Sage Weil Reviewed-by: Alex Elder (cherry picked from commit 6c5e50fa614fea5325a2973be06f7ec6f1055316) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/inode.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 9fff9f3b17e..4b5762ef7c2 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -992,11 +992,15 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, if (rinfo->head->is_dentry) { struct inode *dir = req->r_locked_dir; - err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag, - session, req->r_request_started, -1, - &req->r_caps_reservation); - if (err < 0) - return err; + if (dir) { + err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag, + session, req->r_request_started, -1, + &req->r_caps_reservation); + if (err < 0) + return err; + } else { + WARN_ON_ONCE(1); + } } /* @@ -1004,6 +1008,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, * will have trouble splicing in the virtual snapdir later */ if (rinfo->head->is_dentry && !req->r_aborted && + req->r_locked_dir && (rinfo->head->is_target || strncmp(req->r_dentry->d_name.name, fsc->mount_options->snapdir_name, req->r_dentry->d_name.len))) { From a871375b5548cbcd28c9b97040da7f6470a96a72 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 10 Aug 2012 13:12:07 -0700 Subject: [PATCH 1946/2357] rbd: drop dev reference on error in rbd_open() If a read-only rbd device is opened for writing in rbd_open(), it returns without dropping the just-acquired device reference. Fix this by moving the read-only check before getting the reference. Signed-off-by: Alex Elder Reviewed-by: Yehuda Sadeh Reviewed-by: Josh Durgin (cherry picked from commit 340c7a2b2c9a2da640af28a8c196356484ac8b50) Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 52e295defb9..c05a4ab47e5 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -250,13 +250,12 @@ static int rbd_open(struct block_device *bdev, fmode_t mode) { struct rbd_device *rbd_dev = bdev->bd_disk->private_data; - rbd_get_dev(rbd_dev); - - set_device_ro(bdev, rbd_dev->read_only); - if ((mode & FMODE_WRITE) && rbd_dev->read_only) return -EROFS; + rbd_get_dev(rbd_dev); + set_device_ro(bdev, rbd_dev->read_only); + return 0; } From b4659d8e7001600f06080f2b3f1922d0f4d96478 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 24 Sep 2012 21:01:02 -0700 Subject: [PATCH 1947/2357] ceph: propagate layout error on osd request creation If we are creating an osd request and get an invalid layout, return an EINVAL to the caller. We switch up the return to have an error code instead of NULL implying -ENOMEM. Signed-off-by: Sage Weil Reviewed-by: Alex Elder (cherry picked from commit 6816282dab3a72efe8c0d182c1bc2960d87f4322) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/addr.c | 8 ++++---- fs/ceph/file.c | 4 ++-- net/ceph/osd_client.c | 15 +++++++++------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 32ee086c259..e009fde39cf 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -308,8 +308,8 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) NULL, 0, ci->i_truncate_seq, ci->i_truncate_size, NULL, false, 1, 0); - if (!req) - return -ENOMEM; + if (IS_ERR(req)) + return PTR_ERR(req); /* build page vector */ nr_pages = len >> PAGE_CACHE_SHIFT; @@ -831,8 +831,8 @@ static int ceph_writepages_start(struct address_space *mapping, ci->i_truncate_size, &inode->i_mtime, true, 1, 0); - if (!req) { - rc = -ENOMEM; + if (IS_ERR(req)) { + rc = PTR_ERR(req); unlock_page(page); break; } diff --git a/fs/ceph/file.c b/fs/ceph/file.c index ed72428d9c7..9ce3a4bd4d1 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -529,8 +529,8 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, do_sync, ci->i_truncate_seq, ci->i_truncate_size, &mtime, false, 2, page_align); - if (!req) - return -ENOMEM; + if (IS_ERR(req)) + return PTR_ERR(req); if (file->f_flags & O_DIRECT) { pages = ceph_get_direct_page_vector(data, num_pages, false); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index a79dbae3ea9..37a9f1e6124 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -461,6 +461,7 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, { struct ceph_osd_req_op ops[3]; struct ceph_osd_request *req; + int r; ops[0].op = opcode; ops[0].extent.truncate_seq = truncate_seq; @@ -479,10 +480,12 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, use_mempool, GFP_NOFS, NULL, NULL); if (!req) - return NULL; + return ERR_PTR(-ENOMEM); /* calculate max write size */ - calc_layout(osdc, vino, layout, off, plen, req, ops); + r = calc_layout(osdc, vino, layout, off, plen, req, ops); + if (r < 0) + return ERR_PTR(r); req->r_file_layout = *layout; /* keep a copy */ /* in case it differs from natural (file) alignment that @@ -1925,8 +1928,8 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc, CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, NULL, 0, truncate_seq, truncate_size, NULL, false, 1, page_align); - if (!req) - return -ENOMEM; + if (IS_ERR(req)) + return PTR_ERR(req); /* it may be a short read due to an object boundary */ req->r_pages = pages; @@ -1968,8 +1971,8 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino, snapc, do_sync, truncate_seq, truncate_size, mtime, nofail, 1, page_align); - if (!req) - return -ENOMEM; + if (IS_ERR(req)) + return PTR_ERR(req); /* it may be a short write due to an object boundary */ req->r_pages = pages; From 1c0bd4af222ba3a54bf3ba489127323079d0816d Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 7 Dec 2012 19:50:07 -0600 Subject: [PATCH 1948/2357] libceph: socket can close in any connection state A connection's socket can close for any reason, independent of the state of the connection (and without irrespective of the connection mutex). As a result, the connectino can be in pretty much any state at the time its socket is closed. Handle those other cases at the top of con_work(). Pull this whole block of code into a separate function to reduce the clutter. Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit 7bb21d68c535ad8be38e14a715632ae398b37ac1) Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 47 ++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index aa71a67450a..429f3bcb56a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2258,6 +2258,35 @@ static void queue_con(struct ceph_connection *con) } } +static bool con_sock_closed(struct ceph_connection *con) +{ + if (!test_and_clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags)) + return false; + +#define CASE(x) \ + case CON_STATE_ ## x: \ + con->error_msg = "socket closed (con state " #x ")"; \ + break; + + switch (con->state) { + CASE(CLOSED); + CASE(PREOPEN); + CASE(CONNECTING); + CASE(NEGOTIATING); + CASE(OPEN); + CASE(STANDBY); + default: + pr_warning("%s con %p unrecognized state %lu\n", + __func__, con, con->state); + con->error_msg = "unrecognized con state"; + BUG(); + break; + } +#undef CASE + + return true; +} + /* * Do some work on a connection. Drop a connection ref when we're done. */ @@ -2269,24 +2298,8 @@ static void con_work(struct work_struct *work) mutex_lock(&con->mutex); restart: - if (test_and_clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags)) { - switch (con->state) { - case CON_STATE_CONNECTING: - con->error_msg = "connection failed"; - break; - case CON_STATE_NEGOTIATING: - con->error_msg = "negotiation failed"; - break; - case CON_STATE_OPEN: - con->error_msg = "socket closed"; - break; - default: - dout("unrecognized con state %d\n", (int)con->state); - con->error_msg = "unrecognized con state"; - BUG(); - } + if (con_sock_closed(con)) goto fault; - } if (test_and_clear_bit(CON_FLAG_BACKOFF, &con->flags)) { dout("con_work %p backing off\n", con); From 6ea5c964ecc4037d4ae56694982be253bd821685 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 14 Dec 2012 16:47:41 -0600 Subject: [PATCH 1949/2357] libceph: report connection fault with warning When a connection's socket disconnects, or if there's a protocol error of some kind on the connection, a fault is signaled and the connection is reset (closed and reopened, basically). We currently get an error message on the log whenever this occurs. A ceph connection will attempt to reestablish a socket connection repeatedly if a fault occurs. This means that these error messages will get repeatedly added to the log, which is undesirable. Change the error message to be a warning, so they don't get logged by default. Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit 28362986f8743124b3a0fda20a8ed3e80309cce1) Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 429f3bcb56a..0ff14e88586 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2365,7 +2365,7 @@ static void con_work(struct work_struct *work) static void ceph_fault(struct ceph_connection *con) __releases(con->mutex) { - pr_err("%s%lld %s %s\n", ENTITY_NAME(con->peer_name), + pr_warning("%s%lld %s %s\n", ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr), con->error_msg); dout("fault %p state %lu to peer %s\n", con, con->state, ceph_pr_addr(&con->peer_addr.in_addr)); From 281c5d9e31a2411055bc750d81dd38d11131648e Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 6 Dec 2012 07:22:04 -0600 Subject: [PATCH 1950/2357] libceph: init osd->o_node in create_osd() The red-black node node in the ceph osd structure is not initialized in create_osd(). Because this node can be the subject of a RB_EMPTY_NODE() call later on, we should ensure the node is initialized properly for that. Add a call to RB_CLEAR_NODE() initialize it. Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit f407731d12214e7686819018f3a1e9d7b6f83a02) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 37a9f1e6124..0b3fbdd7100 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -645,6 +645,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum) atomic_set(&osd->o_ref, 1); osd->o_osdc = osdc; osd->o_osd = onum; + RB_CLEAR_NODE(&osd->o_node); INIT_LIST_HEAD(&osd->o_requests); INIT_LIST_HEAD(&osd->o_linger_requests); INIT_LIST_HEAD(&osd->o_osd_lru); From 76fb865bcfeba57652edf054fd36aeed38ba5ceb Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 17 Dec 2012 12:23:48 -0600 Subject: [PATCH 1951/2357] libceph: init event->node in ceph_osdc_create_event() The red-black node node in the ceph osd event structure is not initialized in create_osdc_create_event(). Because this node can be the subject of a RB_EMPTY_NODE() call later on, we should ensure the node is initialized properly for that. Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit 3ee5234df68d253c415ba4f2db72ad250d9c21a9) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 0b3fbdd7100..6af3d2af31c 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -1598,6 +1598,7 @@ int ceph_osdc_create_event(struct ceph_osd_client *osdc, event->data = data; event->osdc = osdc; INIT_LIST_HEAD(&event->osd_node); + RB_CLEAR_NODE(&event->node); kref_init(&event->kref); /* one ref for us */ kref_get(&event->kref); /* one ref for the caller */ init_completion(&event->completion); From 1d2522a000b6f6a0c836d586bbb39bacaae9b390 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 17 Dec 2012 12:23:48 -0600 Subject: [PATCH 1952/2357] libceph: don't use rb_init_node() in ceph_osdc_alloc_request() The red-black node in the ceph osd request structure is initialized in ceph_osdc_alloc_request() using rbd_init_node(). We do need to initialize this, because in __unregister_request() we call RB_EMPTY_NODE(), which expects the node it's checking to have been initialized. But rb_init_node() is apparently overkill, and may in fact be on its way out. So use RB_CLEAR_NODE() instead. For a little more background, see this commit: 4c199a93 rbtree: empty nodes have no color" Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit a978fa20fb657548561dddbfb605fe43654f0825) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 6af3d2af31c..2c395162887 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -221,6 +221,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, kref_init(&req->r_kref); init_completion(&req->r_completion); init_completion(&req->r_safe_completion); + RB_CLEAR_NODE(&req->r_node); INIT_LIST_HEAD(&req->r_unsafe_item); INIT_LIST_HEAD(&req->r_linger_item); INIT_LIST_HEAD(&req->r_linger_osd); From 0d3b9fff8bc11bc7d745c6b34c098b1c548fec65 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 6 Dec 2012 07:22:04 -0600 Subject: [PATCH 1953/2357] libceph: register request before unregister linger In kick_requests(), we need to register the request before we unregister the linger request. Otherwise the unregister will reset the request's osd pointer to NULL. Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit c89ce05e0c5a01a256100ac6a6019f276bdd1ca6) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 2c395162887..93845f23d3f 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -1364,8 +1364,8 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) dout("kicking lingering %p tid %llu osd%d\n", req, req->r_tid, req->r_osd ? req->r_osd->o_osd : -1); - __unregister_linger_request(osdc, req); __register_request(osdc, req); + __unregister_linger_request(osdc, req); } mutex_unlock(&osdc->request_mutex); From a9ded438f7c08525df2ce19e8aeb112efd3090c9 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 19 Dec 2012 15:52:36 -0600 Subject: [PATCH 1954/2357] libceph: move linger requests sooner in kick_requests() The kick_requests() function is called by ceph_osdc_handle_map() when an osd map change has been indicated. Its purpose is to re-queue any request whose target osd is different from what it was when it was originally sent. It is structured as two loops, one for incomplete but registered requests, and a second for handling completed linger requests. As a special case, in the first loop if a request marked to linger has not yet completed, it is moved from the request list to the linger list. This is as a quick and dirty way to have the second loop handle sending the request along with all the other linger requests. Because of the way it's done now, however, this quick and dirty solution can result in these incomplete linger requests never getting re-sent as desired. The problem lies in the fact that the second loop only arranges for a linger request to be sent if it appears its target osd has changed. This is the proper handling for *completed* linger requests (it avoids issuing the same linger request twice to the same osd). But although the linger requests added to the list in the first loop may have been sent, they have not yet completed, so they need to be re-sent regardless of whether their target osd has changed. The first required fix is we need to avoid calling __map_request() on any incomplete linger request. Otherwise the subsequent __map_request() call in the second loop will find the target osd has not changed and will therefore not re-send the request. Second, we need to be sure that a sent but incomplete linger request gets re-sent. If the target osd is the same with the new osd map as it was when the request was originally sent, this won't happen. This can be fixed through careful handling when we move these requests from the request list to the linger list, by unregistering the request *before* it is registered as a linger request. This works because a side-effect of unregistering the request is to make the request's r_osd pointer be NULL, and *that* will ensure the second loop actually re-sends the linger request. Processing of such a request is done at that point, so continue with the next one once it's been moved. Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit ab60b16d3c31b9bd9fd5b39f97dc42c52a50b67d) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 93845f23d3f..c42ef9f7855 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -1320,6 +1320,24 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) for (p = rb_first(&osdc->requests); p; ) { req = rb_entry(p, struct ceph_osd_request, r_node); p = rb_next(p); + + /* + * For linger requests that have not yet been + * registered, move them to the linger list; they'll + * be sent to the osd in the loop below. Unregister + * the request before re-registering it as a linger + * request to ensure the __map_request() below + * will decide it needs to be sent. + */ + if (req->r_linger && list_empty(&req->r_linger_item)) { + dout("%p tid %llu restart on osd%d\n", + req, req->r_tid, + req->r_osd ? req->r_osd->o_osd : -1); + __unregister_request(osdc, req); + __register_linger_request(osdc, req); + continue; + } + err = __map_request(osdc, req, force_resend); if (err < 0) continue; /* error */ @@ -1334,17 +1352,6 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) req->r_flags |= CEPH_OSD_FLAG_RETRY; } } - if (req->r_linger && list_empty(&req->r_linger_item)) { - /* - * register as a linger so that we will - * re-submit below and get a new tid - */ - dout("%p tid %llu restart on osd%d\n", - req, req->r_tid, - req->r_osd ? req->r_osd->o_osd : -1); - __register_linger_request(osdc, req); - __unregister_request(osdc, req); - } } list_for_each_entry_safe(req, nreq, &osdc->req_linger, @@ -1352,6 +1359,7 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) dout("linger req=%p req->r_osd=%p\n", req, req->r_osd); err = __map_request(osdc, req, force_resend); + dout("__map_request returned %d\n", err); if (err == 0) continue; /* no change and no osd was specified */ if (err < 0) From 1cc023b2653ad66b58970460165d0859943f41e7 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 26 Dec 2012 14:31:40 -0600 Subject: [PATCH 1955/2357] libceph: always reset osds when kicking When ceph_osdc_handle_map() is called to process a new osd map, kick_requests() is called to ensure all affected requests are updated if necessary to reflect changes in the osd map. This happens in two cases: whenever an incremental map update is processed; and when a full map update (or the last one if there is more than one) gets processed. In the former case, the kick_requests() call is followed immediately by a call to reset_changed_osds() to ensure any connections to osds affected by the map change are reset. But for full map updates this isn't done. Both cases should be doing this osd reset. Rather than duplicating the reset_changed_osds() call, move it into the end of kick_requests(). Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit e6d50f67a6b1a6252a616e6e629473b5c4277218) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index c42ef9f7855..e03202bdc27 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -1306,7 +1306,7 @@ static void reset_changed_osds(struct ceph_osd_client *osdc) * Requeue requests whose mapping to an OSD has changed. If requests map to * no osd, request a new map. * - * Caller should hold map_sem for read and request_mutex. + * Caller should hold map_sem for read. */ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) { @@ -1381,6 +1381,7 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) dout("%d requests for down osds, need new map\n", needmap); ceph_monc_request_next_osdmap(&osdc->client->monc); } + reset_changed_osds(osdc); } @@ -1437,7 +1438,6 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) osdc->osdmap = newmap; } kick_requests(osdc, 0); - reset_changed_osds(osdc); } else { dout("ignoring incremental map %u len %d\n", epoch, maplen); From 5bd9eb5a0891df0a806f265db504661fd558529c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 26 Dec 2012 10:43:57 -0600 Subject: [PATCH 1956/2357] libceph: WARN, don't BUG on unexpected connection states A number of assertions in the ceph messenger are implemented with BUG_ON(), killing the system if connection's state doesn't match what's expected. At this point our state model is (evidently) not well understood enough for these assertions to trigger a BUG(). Convert all BUG_ON(con->state...) calls to be WARN_ON(con->state...) so we learn about these issues without killing the machine. We now recognize that a connection fault can occur due to a socket closure at any time, regardless of the state of the connection. So there is really nothing we can assert about the state of the connection at that point so eliminate that assertion. Reported-by: Ugis Tested-by: Ugis Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit 122070a2ffc91f87fe8e8493eb0ac61986c5557c) Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 0ff14e88586..5ff743ee806 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -561,7 +561,7 @@ void ceph_con_open(struct ceph_connection *con, mutex_lock(&con->mutex); dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr)); - BUG_ON(con->state != CON_STATE_CLOSED); + WARN_ON(con->state != CON_STATE_CLOSED); con->state = CON_STATE_PREOPEN; con->peer_name.type = (__u8) entity_type; @@ -1505,7 +1505,7 @@ static int process_banner(struct ceph_connection *con) static void fail_protocol(struct ceph_connection *con) { reset_connection(con); - BUG_ON(con->state != CON_STATE_NEGOTIATING); + WARN_ON(con->state != CON_STATE_NEGOTIATING); con->state = CON_STATE_CLOSED; } @@ -1631,7 +1631,7 @@ static int process_connect(struct ceph_connection *con) return -1; } - BUG_ON(con->state != CON_STATE_NEGOTIATING); + WARN_ON(con->state != CON_STATE_NEGOTIATING); con->state = CON_STATE_OPEN; con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq); @@ -2128,7 +2128,6 @@ static int try_read(struct ceph_connection *con) if (ret < 0) goto out; - BUG_ON(con->state != CON_STATE_CONNECTING); con->state = CON_STATE_NEGOTIATING; /* @@ -2156,7 +2155,7 @@ static int try_read(struct ceph_connection *con) goto more; } - BUG_ON(con->state != CON_STATE_OPEN); + WARN_ON(con->state != CON_STATE_OPEN); if (con->in_base_pos < 0) { /* @@ -2370,7 +2369,7 @@ static void ceph_fault(struct ceph_connection *con) dout("fault %p state %lu to peer %s\n", con, con->state, ceph_pr_addr(&con->peer_addr.in_addr)); - BUG_ON(con->state != CON_STATE_CONNECTING && + WARN_ON(con->state != CON_STATE_CONNECTING && con->state != CON_STATE_NEGOTIATING && con->state != CON_STATE_OPEN); From 7f5b160daddeaa55e441aca16010fab8299dfe9e Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 27 Dec 2012 20:27:04 -0600 Subject: [PATCH 1957/2357] libceph: fix protocol feature mismatch failure path We should not set con->state to CLOSED here; that happens in ceph_fault() in the caller, where it first asserts that the state is not yet CLOSED. Avoids a BUG when the features don't match. Since the fail_protocol() has become a trivial wrapper, replace calls to it with direct calls to reset_connection(). Signed-off-by: Sage Weil Reviewed-by: Alex Elder (cherry picked from commit 0fa6ebc600bc8e830551aee47a0e929e818a1868) Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 5ff743ee806..ba1037ceb49 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -506,6 +506,7 @@ static void reset_connection(struct ceph_connection *con) { /* reset connection, out_queue, msg_ and connect_seq */ /* discard existing out_queue and msg_seq */ + dout("reset_connection %p\n", con); ceph_msg_remove_list(&con->out_queue); ceph_msg_remove_list(&con->out_sent); @@ -1502,13 +1503,6 @@ static int process_banner(struct ceph_connection *con) return 0; } -static void fail_protocol(struct ceph_connection *con) -{ - reset_connection(con); - WARN_ON(con->state != CON_STATE_NEGOTIATING); - con->state = CON_STATE_CLOSED; -} - static int process_connect(struct ceph_connection *con) { u64 sup_feat = con->msgr->supported_features; @@ -1526,7 +1520,7 @@ static int process_connect(struct ceph_connection *con) ceph_pr_addr(&con->peer_addr.in_addr), sup_feat, server_feat, server_feat & ~sup_feat); con->error_msg = "missing required protocol features"; - fail_protocol(con); + reset_connection(con); return -1; case CEPH_MSGR_TAG_BADPROTOVER: @@ -1537,7 +1531,7 @@ static int process_connect(struct ceph_connection *con) le32_to_cpu(con->out_connect.protocol_version), le32_to_cpu(con->in_reply.protocol_version)); con->error_msg = "protocol version mismatch"; - fail_protocol(con); + reset_connection(con); return -1; case CEPH_MSGR_TAG_BADAUTHORIZER: @@ -1627,7 +1621,7 @@ static int process_connect(struct ceph_connection *con) ceph_pr_addr(&con->peer_addr.in_addr), req_feat, server_feat, req_feat & ~server_feat); con->error_msg = "missing required protocol features"; - fail_protocol(con); + reset_connection(con); return -1; } From 9aaab33ec9b7b9cb745fc47dfe20b991ff468d72 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 29 Oct 2012 11:01:42 -0700 Subject: [PATCH 1958/2357] libceph: fix osdmap decode error paths Ensure that we set the err value correctly so that we do not pass a 0 value to ERR_PTR and confuse the calling code. (In particular, osd_client.c handle_map() will BUG(!newmap)). Signed-off-by: Sage Weil Reviewed-by: Alex Elder (cherry picked from commit 0ed7285e0001b960c888e5455ae982025210ed3d) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osdmap.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 430076ee938..7fbe21030f5 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -613,10 +613,12 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) ceph_decode_32_safe(p, end, max, bad); while (max--) { ceph_decode_need(p, end, 4 + 1 + sizeof(pi->v), bad); + err = -ENOMEM; pi = kzalloc(sizeof(*pi), GFP_NOFS); if (!pi) goto bad; pi->id = ceph_decode_32(p); + err = -EINVAL; ev = ceph_decode_8(p); /* encoding version */ if (ev > CEPH_PG_POOL_VERSION) { pr_warning("got unknown v %d > %d of ceph_pg_pool\n", @@ -632,8 +634,13 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) __insert_pg_pool(&map->pg_pools, pi); } - if (version >= 5 && __decode_pool_names(p, end, map) < 0) - goto bad; + if (version >= 5) { + err = __decode_pool_names(p, end, map); + if (err < 0) { + dout("fail to decode pool names"); + goto bad; + } + } ceph_decode_32_safe(p, end, map->pool_max, bad); @@ -713,7 +720,7 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) return map; bad: - dout("osdmap_decode fail\n"); + dout("osdmap_decode fail err %d\n", err); ceph_osdmap_destroy(map); return ERR_PTR(err); } @@ -807,6 +814,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, if (ev > CEPH_PG_POOL_VERSION) { pr_warning("got unknown v %d > %d of ceph_pg_pool\n", ev, CEPH_PG_POOL_VERSION); + err = -EINVAL; goto bad; } pi = __lookup_pg_pool(&map->pg_pools, pool); @@ -823,8 +831,11 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, if (err < 0) goto bad; } - if (version >= 5 && __decode_pool_names(p, end, map) < 0) - goto bad; + if (version >= 5) { + err = __decode_pool_names(p, end, map); + if (err < 0) + goto bad; + } /* old_pool */ ceph_decode_32_safe(p, end, len, bad); @@ -900,15 +911,13 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, (void) __remove_pg_mapping(&map->pg_temp, pgid); /* insert */ - if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) { - err = -EINVAL; + err = -EINVAL; + if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) goto bad; - } + err = -ENOMEM; pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS); - if (!pg) { - err = -ENOMEM; + if (!pg) goto bad; - } pg->pgid = pgid; pg->len = pglen; for (j = 0; j < pglen; j++) From 3aa540b869b9bd734ec60246ae1dfe35ab3530e0 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 7 Dec 2012 09:57:58 -0600 Subject: [PATCH 1959/2357] libceph: avoid using freed osd in __kick_osd_requests() If an osd has no requests and no linger requests, __reset_osd() will just remove it with a call to __remove_osd(). That drops a reference to the osd, and therefore the osd may have been free by the time __reset_osd() returns. That function offers no indication this may have occurred, and as a result the osd will continue to be used even when it's no longer valid. Change__reset_osd() so it returns an error (ENODEV) when it deletes the osd being reset. And change __kick_osd_requests() so it returns immediately (before referencing osd again) if __reset_osd() returns *any* error. Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit 685a7555ca69030739ddb57a47f0ea8ea80196a4) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index e03202bdc27..a5735f7c366 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -579,7 +579,7 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc, dout("__kick_osd_requests osd%d\n", osd->o_osd); err = __reset_osd(osdc, osd); - if (err == -EAGAIN) + if (err) return; list_for_each_entry(req, &osd->o_requests, r_osd_item) { @@ -750,6 +750,7 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) if (list_empty(&osd->o_requests) && list_empty(&osd->o_linger_requests)) { __remove_osd(osdc, osd); + ret = -ENODEV; } else if (memcmp(&osdc->osdmap->osd_addr[osd->o_osd], &osd->o_con.peer_addr, sizeof(osd->o_con.peer_addr)) == 0 && From e4a4a559d2ba0d50059a85967b4c4c707863a65b Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 10 Aug 2012 13:12:10 -0700 Subject: [PATCH 1960/2357] rbd: kill create_snap sysfs entry Josh proposed the following change, and I don't think I could explain it any better than he did: From: Josh Durgin Date: Tue, 24 Jul 2012 14:22:11 -0700 To: ceph-devel Message-ID: <500F1203.9050605@inktank.com> From: Josh Durgin Right now the kernel still has one piece of rbd management duplicated from the rbd command line tool: snapshot creation. There's nothing special about snapshot creation that makes it advantageous to do from the kernel, so I'd like to remove the create_snap sysfs interface. That is, /sys/bus/rbd/devices//create_snap would be removed. Does anyone rely on the sysfs interface for creating rbd snapshots? If so, how hard would it be to replace with: rbd snap create pool/image@snap Is there any benefit to the sysfs interface that I'm missing? Josh This patch implements this proposal, removing the code that implements the "snap_create" sysfs interface for rbd images. As a result, quite a lot of other supporting code goes away. [elder@inktank.com: commented out rbd_req_sync_exec() to avoid warning] Suggested-by: Josh Durgin Signed-off-by: Alex Elder Reviewed-by: Josh Durgin (based on commit 02cdb02ceab1f3dd9ac2bc899fc51f0e0e744782) --- Documentation/ABI/testing/sysfs-bus-rbd | 6 - drivers/block/rbd.c | 165 +----------------------- 2 files changed, 2 insertions(+), 169 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-rbd b/Documentation/ABI/testing/sysfs-bus-rbd index dbedafb095e..eb781c624a7 100644 --- a/Documentation/ABI/testing/sysfs-bus-rbd +++ b/Documentation/ABI/testing/sysfs-bus-rbd @@ -51,12 +51,6 @@ current_snap The current snapshot for which the device is mapped. -create_snap - - Create a snapshot: - - $ echo > /sys/bus/rbd/devices//snap_create - snap_* A directory per each snapshot diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index c05a4ab47e5..cce3e5f8a03 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -201,10 +201,6 @@ static DEFINE_SPINLOCK(rbd_client_list_lock); static int __rbd_init_snaps_header(struct rbd_device *rbd_dev); static void rbd_dev_release(struct device *dev); -static ssize_t rbd_snap_add(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count); static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev, struct rbd_snap *snap); @@ -1307,71 +1303,7 @@ static int rbd_req_sync_unwatch(struct rbd_device *dev, return ret; } -struct rbd_notify_info { - struct rbd_device *dev; -}; - -static void rbd_notify_cb(u64 ver, u64 notify_id, u8 opcode, void *data) -{ - struct rbd_device *dev = (struct rbd_device *)data; - if (!dev) - return; - - dout("rbd_notify_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name, - notify_id, (int)opcode); -} - -/* - * Request sync osd notify - */ -static int rbd_req_sync_notify(struct rbd_device *dev, - const char *obj) -{ - struct ceph_osd_req_op *ops; - struct ceph_osd_client *osdc = &dev->rbd_client->client->osdc; - struct ceph_osd_event *event; - struct rbd_notify_info info; - int payload_len = sizeof(u32) + sizeof(u32); - int ret; - - ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY, payload_len); - if (ret < 0) - return ret; - - info.dev = dev; - - ret = ceph_osdc_create_event(osdc, rbd_notify_cb, 1, - (void *)&info, &event); - if (ret < 0) - goto fail; - - ops[0].watch.ver = 1; - ops[0].watch.flag = 1; - ops[0].watch.cookie = event->cookie; - ops[0].watch.prot_ver = RADOS_NOTIFY_VER; - ops[0].watch.timeout = 12; - - ret = rbd_req_sync_op(dev, NULL, - CEPH_NOSNAP, - 0, - CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, - ops, - 1, obj, 0, 0, NULL, NULL, NULL); - if (ret < 0) - goto fail_event; - - ret = ceph_osdc_wait_event(event, CEPH_OSD_TIMEOUT_DEFAULT); - dout("ceph_osdc_wait_event returned %d\n", ret); - rbd_destroy_ops(ops); - return 0; - -fail_event: - ceph_osdc_cancel_event(event); -fail: - rbd_destroy_ops(ops); - return ret; -} - +#if 0 /* * Request sync osd read */ @@ -1411,6 +1343,7 @@ static int rbd_req_sync_exec(struct rbd_device *dev, dout("cls_exec returned %d\n", ret); return ret; } +#endif static struct rbd_req_coll *rbd_alloc_coll(int num_reqs) { @@ -1645,57 +1578,6 @@ static int rbd_read_header(struct rbd_device *rbd_dev, return rc; } -/* - * create a snapshot - */ -static int rbd_header_add_snap(struct rbd_device *dev, - const char *snap_name, - gfp_t gfp_flags) -{ - int name_len = strlen(snap_name); - u64 new_snapid; - int ret; - void *data, *p, *e; - u64 ver; - struct ceph_mon_client *monc; - - /* we should create a snapshot only if we're pointing at the head */ - if (dev->snap_id != CEPH_NOSNAP) - return -EINVAL; - - monc = &dev->rbd_client->client->monc; - ret = ceph_monc_create_snapid(monc, dev->poolid, &new_snapid); - dout("created snapid=%lld\n", new_snapid); - if (ret < 0) - return ret; - - data = kmalloc(name_len + 16, gfp_flags); - if (!data) - return -ENOMEM; - - p = data; - e = data + name_len + 16; - - ceph_encode_string_safe(&p, e, snap_name, name_len, bad); - ceph_encode_64_safe(&p, e, new_snapid, bad); - - ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add", - data, p - data, &ver); - - kfree(data); - - if (ret < 0) - return ret; - - down_write(&dev->header_rwsem); - dev->header.snapc->seq = new_snapid; - up_write(&dev->header_rwsem); - - return 0; -bad: - return -ERANGE; -} - static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev) { struct rbd_snap *snap; @@ -1923,7 +1805,6 @@ static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL); static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL); static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh); static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL); -static DEVICE_ATTR(create_snap, S_IWUSR, NULL, rbd_snap_add); static struct attribute *rbd_attrs[] = { &dev_attr_size.attr, @@ -1933,7 +1814,6 @@ static struct attribute *rbd_attrs[] = { &dev_attr_name.attr, &dev_attr_current_snap.attr, &dev_attr_refresh.attr, - &dev_attr_create_snap.attr, NULL }; @@ -2563,47 +2443,6 @@ static ssize_t rbd_remove(struct bus_type *bus, return ret; } -static ssize_t rbd_snap_add(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - int ret; - char *name = kmalloc(count + 1, GFP_KERNEL); - if (!name) - return -ENOMEM; - - snprintf(name, count, "%s", buf); - - mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - - ret = rbd_header_add_snap(rbd_dev, - name, GFP_KERNEL); - if (ret < 0) - goto err_unlock; - - ret = __rbd_update_snaps(rbd_dev); - if (ret < 0) - goto err_unlock; - - /* shouldn't hold ctl_mutex when notifying.. notify might - trigger a watch callback that would need to get that mutex */ - mutex_unlock(&ctl_mutex); - - /* make a best effort, don't error if failed */ - rbd_req_sync_notify(rbd_dev, rbd_dev->obj_md_name); - - ret = count; - kfree(name); - return ret; - -err_unlock: - mutex_unlock(&ctl_mutex); - kfree(name); - return ret; -} - /* * create control files in sysfs * /sys/bus/rbd/... From 5833a9132795681510a7dbd952696960763dc736 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 10 Aug 2012 13:12:07 -0700 Subject: [PATCH 1961/2357] rbd: add read_only rbd map option Add the ability to map an rbd image read-only, by specifying either "read_only" or "ro" as an option on the rbd "command line." Also allow the inverse to be explicitly specified using "read_write" or "rw". Signed-off-by: Alex Elder Reviewed-by: Yehuda Sadeh (based on commit cc0538b62c839c2df7b9f8378bb37e3b35faa608) --- drivers/block/rbd.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index cce3e5f8a03..78996d0e149 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -71,7 +71,8 @@ #define DEV_NAME_LEN 32 #define MAX_INT_FORMAT_WIDTH ((5 * sizeof (int)) / 2 + 1) -#define RBD_NOTIFY_TIMEOUT_DEFAULT 10 +#define RBD_NOTIFY_TIMEOUT_DEFAULT 10 +#define RBD_READ_ONLY_DEFAULT false /* * block device image metadata (in-memory version) @@ -95,6 +96,7 @@ struct rbd_image_header { struct rbd_options { int notify_timeout; + bool read_only; }; /* @@ -180,7 +182,7 @@ struct rbd_device { u64 snap_id; /* current snapshot id */ /* whether the snap_id this device reads from still exists */ bool snap_exists; - int read_only; + bool read_only; struct list_head node; @@ -346,12 +348,21 @@ enum { /* int args above */ Opt_last_string, /* string args above */ + Opt_read_only, + Opt_read_write, + /* Boolean args above */ + Opt_last_bool, }; static match_table_t rbdopt_tokens = { {Opt_notify_timeout, "notify_timeout=%d"}, /* int args above */ /* string args above */ + {Opt_read_only, "read_only"}, + {Opt_read_only, "ro"}, /* Alternate spelling */ + {Opt_read_write, "read_write"}, + {Opt_read_write, "rw"}, /* Alternate spelling */ + /* Boolean args above */ {-1, NULL} }; @@ -376,6 +387,8 @@ static int parse_rbd_opts_token(char *c, void *private) } else if (token > Opt_last_int && token < Opt_last_string) { dout("got string token %d val %s\n", token, argstr[0].from); + } else if (token > Opt_last_string && token < Opt_last_bool) { + dout("got Boolean token %d\n", token); } else { dout("got token %d\n", token); } @@ -384,6 +397,12 @@ static int parse_rbd_opts_token(char *c, void *private) case Opt_notify_timeout: rbdopt->notify_timeout = intval; break; + case Opt_read_only: + rbdopt->read_only = true; + break; + case Opt_read_write: + rbdopt->read_only = false; + break; default: BUG_ON(token); } @@ -407,6 +426,7 @@ static struct rbd_client *rbd_get_client(const char *mon_addr, return ERR_PTR(-ENOMEM); rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT; + rbd_opts->read_only = RBD_READ_ONLY_DEFAULT; opt = ceph_parse_options(options, mon_addr, mon_addr + mon_addr_len, @@ -590,7 +610,7 @@ static int rbd_header_set_snap(struct rbd_device *dev, u64 *size) snapc->seq = 0; dev->snap_id = CEPH_NOSNAP; dev->snap_exists = false; - dev->read_only = 0; + dev->read_only = dev->rbd_client->rbd_opts->read_only; if (size) *size = header->image_size; } else { @@ -599,7 +619,7 @@ static int rbd_header_set_snap(struct rbd_device *dev, u64 *size) goto done; dev->snap_id = snapc->seq; dev->snap_exists = true; - dev->read_only = 1; + dev->read_only = true; /* No choice for snapshots */ } ret = 0; From 87c7f759d1546a27d46d8cc2778ffecaa5f542c6 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 10 Aug 2012 13:12:07 -0700 Subject: [PATCH 1962/2357] rbd: kill notify_timeout option The "notify_timeout" rbd device option is never used, so get rid of it. Signed-off-by: Alex Elder Reviewed-by: Yehuda Sadeh (cherry picked from commit 84d34dcc116e117a41c6fc8be13430529fc2d9e7) Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 78996d0e149..cf3ce697c0b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -71,7 +71,6 @@ #define DEV_NAME_LEN 32 #define MAX_INT_FORMAT_WIDTH ((5 * sizeof (int)) / 2 + 1) -#define RBD_NOTIFY_TIMEOUT_DEFAULT 10 #define RBD_READ_ONLY_DEFAULT false /* @@ -95,7 +94,6 @@ struct rbd_image_header { }; struct rbd_options { - int notify_timeout; bool read_only; }; @@ -343,7 +341,6 @@ static struct rbd_client *__rbd_client_find(struct ceph_options *opt) * mount options */ enum { - Opt_notify_timeout, Opt_last_int, /* int args above */ Opt_last_string, @@ -355,7 +352,6 @@ enum { }; static match_table_t rbdopt_tokens = { - {Opt_notify_timeout, "notify_timeout=%d"}, /* int args above */ /* string args above */ {Opt_read_only, "read_only"}, @@ -394,9 +390,6 @@ static int parse_rbd_opts_token(char *c, void *private) } switch (token) { - case Opt_notify_timeout: - rbdopt->notify_timeout = intval; - break; case Opt_read_only: rbdopt->read_only = true; break; @@ -425,7 +418,6 @@ static struct rbd_client *rbd_get_client(const char *mon_addr, if (!rbd_opts) return ERR_PTR(-ENOMEM); - rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT; rbd_opts->read_only = RBD_READ_ONLY_DEFAULT; opt = ceph_parse_options(options, mon_addr, From 31c46473d6a31ac1948c189624b472f26a6365e9 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 28 Nov 2012 12:28:24 -0800 Subject: [PATCH 1963/2357] libceph: remove 'osdtimeout' option This would reset a connection with any OSD that had an outstanding request that was taking more than N seconds. The idea was that if the OSD was buggy, the client could compensate by resending the request. In reality, this only served to hide server bugs, and we haven't actually seen such a bug in quite a while. Moreover, the userspace client code never did this. More importantly, often the request is taking a long time because the OSD is trying to recover, or overloaded, and killing the connection and retrying would only make the situation worse by giving the OSD more work to do. Signed-off-by: Sage Weil Reviewed-by: Alex Elder (cherry picked from commit 83aff95eb9d60aff5497e9f44a2ae906b86d8e88) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/super.c | 2 -- include/linux/ceph/libceph.h | 2 -- net/ceph/ceph_common.c | 3 +-- net/ceph/osd_client.c | 47 +++--------------------------------- 4 files changed, 5 insertions(+), 49 deletions(-) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 1e67dd7305a..f3639181546 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -387,8 +387,6 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) seq_printf(m, ",mount_timeout=%d", opt->mount_timeout); if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl); - if (opt->osd_timeout != CEPH_OSD_TIMEOUT_DEFAULT) - seq_printf(m, ",osdtimeout=%d", opt->osd_timeout); if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) seq_printf(m, ",osdkeepalivetimeout=%d", opt->osd_keepalive_timeout); diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 98ec36ae8a3..893420b78d0 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -49,7 +49,6 @@ struct ceph_options { struct ceph_entity_addr my_addr; int mount_timeout; int osd_idle_ttl; - int osd_timeout; int osd_keepalive_timeout; /* @@ -69,7 +68,6 @@ struct ceph_options { * defaults */ #define CEPH_MOUNT_TIMEOUT_DEFAULT 60 -#define CEPH_OSD_TIMEOUT_DEFAULT 60 /* seconds */ #define CEPH_OSD_KEEPALIVE_DEFAULT 5 #define CEPH_OSD_IDLE_TTL_DEFAULT 60 diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 8e74e8c5a77..b11448f052f 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -304,7 +304,6 @@ ceph_parse_options(char *options, const char *dev_name, /* start with defaults */ opt->flags = CEPH_OPT_DEFAULT; - opt->osd_timeout = CEPH_OSD_TIMEOUT_DEFAULT; opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT; opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */ opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; /* seconds */ @@ -390,7 +389,7 @@ ceph_parse_options(char *options, const char *dev_name, /* misc */ case Opt_osdtimeout: - opt->osd_timeout = intval; + pr_warning("ignoring deprecated osdtimeout option\n"); break; case Opt_osdkeepalivetimeout: opt->osd_keepalive_timeout = intval; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index a5735f7c366..254f530b98f 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -606,14 +606,6 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc, } } -static void kick_osd_requests(struct ceph_osd_client *osdc, - struct ceph_osd *kickosd) -{ - mutex_lock(&osdc->request_mutex); - __kick_osd_requests(osdc, kickosd); - mutex_unlock(&osdc->request_mutex); -} - /* * If the osd connection drops, we need to resubmit all requests. */ @@ -627,7 +619,9 @@ static void osd_reset(struct ceph_connection *con) dout("osd_reset osd%d\n", osd->o_osd); osdc = osd->o_osdc; down_read(&osdc->map_sem); - kick_osd_requests(osdc, osd); + mutex_lock(&osdc->request_mutex); + __kick_osd_requests(osdc, osd); + mutex_unlock(&osdc->request_mutex); send_queued(osdc); up_read(&osdc->map_sem); } @@ -1091,12 +1085,10 @@ static void handle_timeout(struct work_struct *work) { struct ceph_osd_client *osdc = container_of(work, struct ceph_osd_client, timeout_work.work); - struct ceph_osd_request *req, *last_req = NULL; + struct ceph_osd_request *req; struct ceph_osd *osd; - unsigned long timeout = osdc->client->options->osd_timeout * HZ; unsigned long keepalive = osdc->client->options->osd_keepalive_timeout * HZ; - unsigned long last_stamp = 0; struct list_head slow_osds; dout("timeout\n"); down_read(&osdc->map_sem); @@ -1105,37 +1097,6 @@ static void handle_timeout(struct work_struct *work) mutex_lock(&osdc->request_mutex); - /* - * reset osds that appear to be _really_ unresponsive. this - * is a failsafe measure.. we really shouldn't be getting to - * this point if the system is working properly. the monitors - * should mark the osd as failed and we should find out about - * it from an updated osd map. - */ - while (timeout && !list_empty(&osdc->req_lru)) { - req = list_entry(osdc->req_lru.next, struct ceph_osd_request, - r_req_lru_item); - - /* hasn't been long enough since we sent it? */ - if (time_before(jiffies, req->r_stamp + timeout)) - break; - - /* hasn't been long enough since it was acked? */ - if (req->r_request->ack_stamp == 0 || - time_before(jiffies, req->r_request->ack_stamp + timeout)) - break; - - BUG_ON(req == last_req && req->r_stamp == last_stamp); - last_req = req; - last_stamp = req->r_stamp; - - osd = req->r_osd; - BUG_ON(!osd); - pr_warning(" tid %llu timed out on osd%d, will reset osd\n", - req->r_tid, osd->o_osd); - __kick_osd_requests(osdc, osd); - } - /* * ping osds that are a bit slow. this ensures that if there * is a break in the TCP connection we will notice, and reopen From 02585b8bdc988de82b45088a3f2092af2e6b2816 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 29 Nov 2012 08:37:03 -0600 Subject: [PATCH 1964/2357] ceph: don't reference req after put In __unregister_request(), there is a call to list_del_init() referencing a request that was the subject of a call to ceph_osdc_put_request() on the previous line. This is not safe, because the request structure could have been freed by the time we reach the list_del_init(). Fix this by reversing the order of these lines. Signed-off-by: Alex Elder Reviewed-off-by: Sage Weil (cherry picked from commit 7d5f24812bd182a2471cb69c1c2baf0648332e1f) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 254f530b98f..925649c522f 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -871,9 +871,9 @@ static void __unregister_request(struct ceph_osd_client *osdc, req->r_osd = NULL; } + list_del_init(&req->r_req_lru_item); ceph_osdc_put_request(req); - list_del_init(&req->r_req_lru_item); if (osdc->num_requests == 0) { dout(" no requests, canceling timeout\n"); __cancel_osd_timeout(osdc); From 50cda8f4439d715e080ced70d1e6d9ec07f95e6c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 6 Dec 2012 09:37:23 -0600 Subject: [PATCH 1965/2357] rbd: remove linger unconditionally In __unregister_linger_request(), the request is being removed from the osd client's req_linger list only when the request has a non-null osd pointer. It should be done whether or not the request currently has an osd. This is most likely a non-issue because I believe the request will always have an osd when this function is called. Signed-off-by: Alex Elder Reviewed-by: Sage Weil (cherry picked from commit 61c74035626beb25a39b0273ccf7d75510bc36a1) Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 925649c522f..b16dfa25e75 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -905,8 +905,8 @@ static void __unregister_linger_request(struct ceph_osd_client *osdc, struct ceph_osd_request *req) { dout("__unregister_linger_request %p\n", req); + list_del_init(&req->r_linger_item); if (req->r_osd) { - list_del_init(&req->r_linger_item); list_del_init(&req->r_linger_osd); if (list_empty(&req->r_osd->o_requests) && From f2ac87daff2e4a8c9fb8119a8e4badaac684a284 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 24 Sep 2012 21:02:47 -0700 Subject: [PATCH 1966/2357] rbd: BUG on invalid layout This shouldn't actually be possible because the layout struct is constructed from the RBD header and validated then. [elder@inktank.com: converted BUG() call to equivalent rbd_assert()] Signed-off-by: Sage Weil Reviewed-by: Alex Elder (based on commit 6cae3717cddaf8e5e96e304733dca66e40d56f89) --- drivers/block/rbd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index cf3ce697c0b..f1375d98f6e 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -930,8 +930,9 @@ static int rbd_do_request(struct request *rq, layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); layout->fl_pg_preferred = cpu_to_le32(-1); layout->fl_pg_pool = cpu_to_le32(dev->poolid); - ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno, - req, ops); + ret = ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno, + req, ops); + BUG_ON(ret != 0); ceph_osdc_build_request(req, ofs, &len, ops, From 1e411c66732294f5fb983323dafa7559796481f5 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 10 Oct 2012 21:19:13 -0700 Subject: [PATCH 1967/2357] rbd: fix bug in rbd_dev_id_put() In rbd_dev_id_put(), there's a loop that's intended to determine the maximum device id in use. But it isn't doing that at all, the effect of how it's written is to simply use the just-put id number, which ignores whole purpose of this function. Fix the bug. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin (cherry picked from commit b213e0b1a62637b2a9395a34349b13d73ca2b90a) Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index f1375d98f6e..d9ebe6844da 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2150,8 +2150,8 @@ static void rbd_id_put(struct rbd_device *rbd_dev) struct rbd_device *rbd_dev; rbd_dev = list_entry(tmp, struct rbd_device, node); - if (rbd_id > max_id) - max_id = rbd_id; + if (rbd_dev->id > max_id) + max_id = rbd_dev->id; } spin_unlock(&rbd_dev_list_lock); From 3317122449a2ce5c0bba77e1f05b1df2ff716447 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 16 Nov 2012 09:29:16 -0600 Subject: [PATCH 1968/2357] rbd: do not allow remove of mounted-on image There is no check in rbd_remove() to see if anybody holds open the image being removed. That's not cool. Add a simple open count that goes up and down with opens and closes (releases) of the device, and don't allow an rbd image to be removed if the count is non-zero. Protect the updates of the open count value with ctl_mutex to ensure the underlying rbd device doesn't get removed while concurrently being opened. Signed-off-by: Alex Elder Reviewed-by: Sage Weil (based on commit 42382b709bd1d143b9f0fa93e0a3a1f2f4210707) --- drivers/block/rbd.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index d9ebe6844da..cba3d0278b8 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -189,6 +189,7 @@ struct rbd_device { /* sysfs related */ struct device dev; + unsigned long open_count; }; static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */ @@ -249,8 +250,11 @@ static int rbd_open(struct block_device *bdev, fmode_t mode) if ((mode & FMODE_WRITE) && rbd_dev->read_only) return -EROFS; + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); rbd_get_dev(rbd_dev); set_device_ro(bdev, rbd_dev->read_only); + rbd_dev->open_count++; + mutex_unlock(&ctl_mutex); return 0; } @@ -259,7 +263,11 @@ static int rbd_release(struct gendisk *disk, fmode_t mode) { struct rbd_device *rbd_dev = disk->private_data; + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + BUG_ON(!rbd_dev->open_count); + rbd_dev->open_count--; rbd_put_dev(rbd_dev); + mutex_unlock(&ctl_mutex); return 0; } @@ -2448,6 +2456,11 @@ static ssize_t rbd_remove(struct bus_type *bus, goto done; } + if (rbd_dev->open_count) { + ret = -EBUSY; + goto done; + } + __rbd_remove_all_snaps(rbd_dev); rbd_bus_del_dev(rbd_dev); From 7ae7b557aaaf1d50f04706b775341957f12bab10 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:04 +0800 Subject: [PATCH 1969/2357] ceph: Don't update i_max_size when handling non-auth cap The cap from non-auth mds doesn't have a meaningful max_size value. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil (cherry picked from commit 5e62ad30157d0da04cf40c6d1a2f4bc840948b9c) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/caps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 620daad201d..d7149c0dda1 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2388,7 +2388,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, &atime); /* max size increase? */ - if (max_size != ci->i_max_size) { + if (ci->i_auth_cap == cap && max_size != ci->i_max_size) { dout("max_size %lld -> %llu\n", ci->i_max_size, max_size); ci->i_max_size = max_size; if (max_size >= ci->i_wanted_max_size) { From 42d519d12ef2d43a83b86cd2931c539045d07059 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:06 +0800 Subject: [PATCH 1970/2357] ceph: Fix infinite loop in __wake_requests __wake_requests() will enter infinite loop if we use it to wake requests in the session->s_waiting list. __wake_requests() deletes requests from the list and __do_request() adds requests back to the list. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil (cherry picked from commit ed75ec2cd19b47efcd292b6e23f58e56f4c5bc34) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/mds_client.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 95708dd092f..3fd08ad5c47 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1886,9 +1886,14 @@ static int __do_request(struct ceph_mds_client *mdsc, static void __wake_requests(struct ceph_mds_client *mdsc, struct list_head *head) { - struct ceph_mds_request *req, *nreq; + struct ceph_mds_request *req; + LIST_HEAD(tmp_list); + + list_splice_init(head, &tmp_list); - list_for_each_entry_safe(req, nreq, head, r_wait) { + while (!list_empty(&tmp_list)) { + req = list_entry(tmp_list.next, + struct ceph_mds_request, r_wait); list_del_init(&req->r_wait); __do_request(mdsc, req); } From ba647fd5c7ffc1a6433c8c90eedadf76a3df82fa Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:07 +0800 Subject: [PATCH 1971/2357] ceph: Don't add dirty inode to dirty list if caps is in migration Add dirty inode to cap_dirty_migrating list instead, this can avoid ceph_flush_dirty_caps() entering infinite loop. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil (cherry picked from commit 0685235ffd9dbdb9ccbda587f8a3c83ad1d5a921) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/caps.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index d7149c0dda1..e4eb282da10 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1349,11 +1349,15 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) if (!ci->i_head_snapc) ci->i_head_snapc = ceph_get_snap_context( ci->i_snap_realm->cached_context); - dout(" inode %p now dirty snapc %p\n", &ci->vfs_inode, - ci->i_head_snapc); + dout(" inode %p now dirty snapc %p auth cap %p\n", + &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap); BUG_ON(!list_empty(&ci->i_dirty_item)); spin_lock(&mdsc->cap_dirty_lock); - list_add(&ci->i_dirty_item, &mdsc->cap_dirty); + if (ci->i_auth_cap) + list_add(&ci->i_dirty_item, &mdsc->cap_dirty); + else + list_add(&ci->i_dirty_item, + &mdsc->cap_dirty_migrating); spin_unlock(&mdsc->cap_dirty_lock); if (ci->i_flushing_caps == 0) { ihold(inode); From fbc8158351e8d34c499b61c422f3614dad6dc910 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:08 +0800 Subject: [PATCH 1972/2357] ceph: Fix __ceph_do_pending_vmtruncate we should set i_truncate_pending to 0 after page cache is truncated to i_truncate_size Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil (cherry picked from commit a85f50b6ef93fbbb2ae932ce9b2376509d172796) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/inode.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 4b5762ef7c2..81613bced19 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1466,7 +1466,7 @@ void __ceph_do_pending_vmtruncate(struct inode *inode) { struct ceph_inode_info *ci = ceph_inode(inode); u64 to; - int wrbuffer_refs, wake = 0; + int wrbuffer_refs, finish = 0; retry: spin_lock(&ci->i_ceph_lock); @@ -1498,15 +1498,18 @@ void __ceph_do_pending_vmtruncate(struct inode *inode) truncate_inode_pages(inode->i_mapping, to); spin_lock(&ci->i_ceph_lock); - ci->i_truncate_pending--; - if (ci->i_truncate_pending == 0) - wake = 1; + if (to == ci->i_truncate_size) { + ci->i_truncate_pending = 0; + finish = 1; + } spin_unlock(&ci->i_ceph_lock); + if (!finish) + goto retry; if (wrbuffer_refs == 0) ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); - if (wake) - wake_up_all(&ci->i_cap_wq); + + wake_up_all(&ci->i_cap_wq); } From 57d93df8f18dbe66c0e2e1089ed2c120a9b980af Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:09 +0800 Subject: [PATCH 1973/2357] ceph: call handle_cap_grant() for cap import message If client sends cap message that requests new max size during exporting caps, the exporting MDS will drop the message quietly. So the client may wait for the reply that updates the max size forever. call handle_cap_grant() for cap import message can avoid this issue. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil (cherry picked from commit 0e5e1774a92e6fe9c511585de8f078b4c4c68dbb) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/caps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index e4eb282da10..e7d40776f58 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2749,6 +2749,7 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, /* make sure we re-request max_size, if necessary */ spin_lock(&ci->i_ceph_lock); + ci->i_wanted_max_size = 0; /* reset */ ci->i_requested_max_size = 0; spin_unlock(&ci->i_ceph_lock); } @@ -2844,8 +2845,6 @@ void ceph_handle_caps(struct ceph_mds_session *session, case CEPH_CAP_OP_IMPORT: handle_cap_import(mdsc, inode, h, session, snaptrace, snaptrace_len); - ceph_check_caps(ceph_inode(inode), 0, session); - goto done_unlocked; } /* the rest require a cap */ @@ -2862,6 +2861,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, switch (op) { case CEPH_CAP_OP_REVOKE: case CEPH_CAP_OP_GRANT: + case CEPH_CAP_OP_IMPORT: handle_cap_grant(inode, h, session, cap, msg->middle); goto done_unlocked; From 359c4ea7baf79484cc3561f0040f9d5e367155fe Mon Sep 17 00:00:00 2001 From: David Zafman Date: Mon, 3 Dec 2012 19:14:05 -0800 Subject: [PATCH 1974/2357] libceph: Unlock unprocessed pages in start_read() error path Function start_read() can get an error before processing all pages. It must not only release the remaining pages, but unlock them too. This fixes http://tracker.newdream.net/issues/3370 Signed-off-by: David Zafman Reviewed-by: Alex Elder (cherry picked from commit 8884d53dd63b1d9315b343564fcbe1ede004a99e) Signed-off-by: Greg Kroah-Hartman --- fs/ceph/addr.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index e009fde39cf..bb01881cb1f 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -267,6 +267,14 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg) kfree(req->r_pages); } +static void ceph_unlock_page_vector(struct page **pages, int num_pages) +{ + int i; + + for (i = 0; i < num_pages; i++) + unlock_page(pages[i]); +} + /* * start an async read(ahead) operation. return nr_pages we submitted * a read for on success, or negative error code. @@ -347,6 +355,7 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) return nr_pages; out_pages: + ceph_unlock_page_vector(pages, nr_pages); ceph_release_page_vector(pages, nr_pages); out: ceph_osdc_put_request(req); From c390e5a48ae714a6da89f16a8239e1751a285376 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 30 Mar 2012 17:14:58 +0100 Subject: [PATCH 1975/2357] staging: comedi: don't hijack hardware device private data commit c43435d7722134ed1fda58ce1025f41029bd58ad upstream. comedi_auto_config() associates a Comedi minor device number with an auto-configured hardware device and comedi_auto_unconfig() disassociates it. Currently, these use the hardware device's private data pointer to point to some allocated storage holding the minor device number. This is a bit of a waste of the hardware device's private data pointer, preventing it from being used for something more useful by the low-level comedi device drivers. For example, it would make more sense if comedi_usb_auto_config() was passed a pointer to the struct usb_interface instead of the struct usb_device, but this cannot be done currently because the low-level comedi drivers already use the private data pointer in the struct usb_interface for something more useful. This patch stops the comedi core hijacking the hardware device's private data pointer. Instead, comedi_auto_config() stores a pointer to the hardware device's struct device in the struct comedi_device_file_info associated with the minor device number, and comedi_auto_unconfig() calls new function comedi_find_board_minor() to recover the minor device number associated with the hardware device. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 18 +++++++++++++++ drivers/staging/comedi/comedidev.h | 1 + drivers/staging/comedi/drivers.c | 34 ++++++++-------------------- drivers/staging/comedi/internal.h | 1 + 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 3fd9772d7a7..b67c1070df7 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -2210,6 +2210,7 @@ int comedi_alloc_board_minor(struct device *hardware_device) kfree(info); return -ENOMEM; } + info->hardware_device = hardware_device; comedi_device_init(info->device); spin_lock_irqsave(&comedi_file_info_table_lock, flags); for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { @@ -2298,6 +2299,23 @@ void comedi_free_board_minor(unsigned minor) } } +int comedi_find_board_minor(struct device *hardware_device) +{ + int minor; + struct comedi_device_file_info *info; + + for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) { + spin_lock(&comedi_file_info_table_lock); + info = comedi_file_info_table[minor]; + if (info && info->hardware_device == hardware_device) { + spin_unlock(&comedi_file_info_table_lock); + return minor; + } + spin_unlock(&comedi_file_info_table_lock); + } + return -ENODEV; +} + int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdevice *s) { diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index 7a0d4bcbc35..00d3c65589b 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -234,6 +234,7 @@ struct comedi_device_file_info { struct comedi_device *device; struct comedi_subdevice *read_subdevice; struct comedi_subdevice *write_subdevice; + struct device *hardware_device; }; #ifdef CONFIG_COMEDI_DEBUG diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index bf185e2807d..0fc1b9939d9 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -822,25 +822,14 @@ static int comedi_auto_config(struct device *hardware_device, int minor; struct comedi_device_file_info *dev_file_info; int retval; - unsigned *private_data = NULL; - if (!comedi_autoconfig) { - dev_set_drvdata(hardware_device, NULL); + if (!comedi_autoconfig) return 0; - } minor = comedi_alloc_board_minor(hardware_device); if (minor < 0) return minor; - private_data = kmalloc(sizeof(unsigned), GFP_KERNEL); - if (private_data == NULL) { - retval = -ENOMEM; - goto cleanup; - } - *private_data = minor; - dev_set_drvdata(hardware_device, private_data); - dev_file_info = comedi_get_device_file_info(minor); memset(&it, 0, sizeof(it)); @@ -853,25 +842,22 @@ static int comedi_auto_config(struct device *hardware_device, retval = comedi_device_attach(dev_file_info->device, &it); mutex_unlock(&dev_file_info->device->mutex); -cleanup: - if (retval < 0) { - kfree(private_data); + if (retval < 0) comedi_free_board_minor(minor); - } return retval; } static void comedi_auto_unconfig(struct device *hardware_device) { - unsigned *minor = (unsigned *)dev_get_drvdata(hardware_device); - if (minor == NULL) - return; - - BUG_ON(*minor >= COMEDI_NUM_BOARD_MINORS); + int minor; - comedi_free_board_minor(*minor); - dev_set_drvdata(hardware_device, NULL); - kfree(minor); + if (hardware_device == NULL) + return; + minor = comedi_find_board_minor(hardware_device); + if (minor < 0) + return; + BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); + comedi_free_board_minor(minor); } int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name) diff --git a/drivers/staging/comedi/internal.h b/drivers/staging/comedi/internal.h index 434ce343336..4208fb4cf0f 100644 --- a/drivers/staging/comedi/internal.h +++ b/drivers/staging/comedi/internal.h @@ -7,6 +7,7 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int comedi_alloc_board_minor(struct device *hardware_device); void comedi_free_board_minor(unsigned minor); +int comedi_find_board_minor(struct device *hardware_device); void comedi_reset_async_buf(struct comedi_async *async); int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); From ede3e03c6d28bc3aca30206995fec585031698af Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 3 Jan 2013 12:15:26 +0000 Subject: [PATCH 1976/2357] staging: comedi: Kconfig: COMEDI_NI_AT_A2150 should select COMEDI_FC commit 34ffb33e09132401872fe79e95c30824ce194d23 upstream. The 'ni_at_a2150' module links to `cfc_write_to_buffer` in the 'comedi_fc' module, so selecting 'COMEDI_NI_AT_A2150' in the kernel config needs to also select 'COMEDI_FC'. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 12c691d9090..f11cfc87012 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -424,6 +424,7 @@ config COMEDI_ADQ12B config COMEDI_NI_AT_A2150 tristate "NI AT-A2150 ISA card support" + select COMEDI_FC depends on COMEDI_NI_COMMON depends on VIRT_TO_BUS default N From 828b18866ce0907fdb67afe143d5d851deb9fec6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 7 Nov 2012 10:31:30 -0500 Subject: [PATCH 1977/2357] USB: fix endpoint-disabling for failed config changes commit 36caff5d795429c572443894e8789c2150dd796b upstream. This patch (as1631) fixes a bug that shows up when a config change fails for a device under an xHCI controller. The controller needs to be told to disable the endpoints that have been enabled for the new config. The existing code does this, but before storing the information about which endpoints were enabled! As a result, any second attempt to install the new config is doomed to fail because xhci-hcd will refuse to enable an endpoint that is already enabled. The patch optimistically initializes the new endpoints' device structures before asking the device to switch to the new config. If the request fails then the endpoint information is already stored, so we can use usb_hcd_alloc_bandwidth() to disable the endpoints with no trouble. The rest of the error path is slightly more complex now; we have to disable the new interfaces and call put_device() rather than simply deallocating them. Signed-off-by: Alan Stern Reported-and-tested-by: Matthias Schniedermeyer CC: Sarah Sharp Signed-off-by: Greg Kroah-Hartman [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 53 ++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index ef116a55afa..ab11ca3c79a 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1770,28 +1770,8 @@ int usb_set_configuration(struct usb_device *dev, int configuration) goto free_interfaces; } - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, configuration, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); - if (ret < 0) { - /* All the old state is gone, so what else can we do? - * The device is probably useless now anyway. - */ - cp = NULL; - } - - dev->actconfig = cp; - if (!cp) { - usb_set_device_state(dev, USB_STATE_ADDRESS); - usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); - mutex_unlock(hcd->bandwidth_mutex); - usb_autosuspend_device(dev); - goto free_interfaces; - } - mutex_unlock(hcd->bandwidth_mutex); - usb_set_device_state(dev, USB_STATE_CONFIGURED); - - /* Initialize the new interface structures and the + /* + * Initialize the new interface structures and the * hc/hcd/usbcore interface/endpoint state. */ for (i = 0; i < nintf; ++i) { @@ -1835,6 +1815,35 @@ int usb_set_configuration(struct usb_device *dev, int configuration) } kfree(new_interfaces); + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (ret < 0 && cp) { + /* + * All the old state is gone, so what else can we do? + * The device is probably useless now anyway. + */ + usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); + for (i = 0; i < nintf; ++i) { + usb_disable_interface(dev, cp->interface[i], true); + put_device(&cp->interface[i]->dev); + cp->interface[i] = NULL; + } + cp = NULL; + } + + dev->actconfig = cp; + mutex_unlock(hcd->bandwidth_mutex); + + if (!cp) { + usb_set_device_state(dev, USB_STATE_ADDRESS); + + /* Leave LPM disabled while the device is unconfigured. */ + usb_autosuspend_device(dev); + return ret; + } + usb_set_device_state(dev, USB_STATE_CONFIGURED); + if (cp->string == NULL && !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); From 6723972ab0cedb96477d47fb197091b487921322 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 17 Jan 2013 08:51:56 -0800 Subject: [PATCH 1978/2357] Linux 3.4.26 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0913881e456..2d84a1d4d26 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 25 +SUBLEVEL = 26 EXTRAVERSION = NAME = Saber-toothed Squirrel From 8630dda5a013d1b39280ec9bda2ee9b7e99b68c1 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Fri, 16 Nov 2012 10:46:20 +0100 Subject: [PATCH 1979/2357] sh: Fix FDPIC binary loader commit 4a71997a3279a339e7336ea5d0cd27282e2dea44 upstream. Ensure that the aux table is properly initialized, even when optional features are missing. Without this, the FDPIC loader did not work. This was meant to be included in commit d5ab780305bb6d60a7b5a74f18cf84eb6ad153b1. Signed-off-by: Thomas Schwinge Signed-off-by: Paul Mundt Signed-off-by: Greg Kroah-Hartman --- arch/sh/include/asm/elf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h index f38112be67d..978b7fd6d47 100644 --- a/arch/sh/include/asm/elf.h +++ b/arch/sh/include/asm/elf.h @@ -202,9 +202,9 @@ extern void __kernel_vsyscall; if (vdso_enabled) \ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \ else \ - NEW_AUX_ENT(AT_IGNORE, 0); + NEW_AUX_ENT(AT_IGNORE, 0) #else -#define VSYSCALL_AUX_ENT +#define VSYSCALL_AUX_ENT NEW_AUX_ENT(AT_IGNORE, 0) #endif /* CONFIG_VSYSCALL */ #ifdef CONFIG_SH_FPU From e86f92f7eaeb01b071d2ca2a473c1efff6e9db68 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Fri, 21 Dec 2012 10:58:14 -0800 Subject: [PATCH 1980/2357] tcm_fc: Do not indicate retry capability to initiators commit f2eeba214bcd0215b7f558cab6420e5fd153042b upstream. When generating a PRLI response to an initiator, clear the FCP_SPPF_RETRY bit in the response. Signed-off-by: Mark Rustad Reviewed-by: Bhanu Prakash Gollapudi Acked by Robert Love Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/tcm_fc/tfc_sess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index a426c4020be..34d7b251986 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -397,10 +397,10 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, /* * OR in our service parameters with other provider (initiator), if any. - * TBD XXX - indicate RETRY capability? */ fill: fcp_parm = ntohl(spp->spp_params); + fcp_parm &= ~FCP_SPPF_RETRY; spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); return FC_SPP_RESP_ACK; } From 4b77fd473bf78ec6ddd7c6f4d1f03582a4ec34b9 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Fri, 21 Dec 2012 10:58:19 -0800 Subject: [PATCH 1981/2357] tcm_fc: Do not report target role when target is not defined commit edec8dfefa1f372b2dd8197da555352e76a10c03 upstream. Clear the target role when no target is provided for the node performing a PRLI. Signed-off-by: Mark Rustad Reviewed-by: Bhanu Prakash Gollapudi Acked by Robert Love Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/tcm_fc/tfc_sess.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 34d7b251986..9249998a837 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -356,11 +356,11 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, tport = ft_tport_create(rdata->local_port); if (!tport) - return 0; /* not a target for this local port */ + goto not_target; /* not a target for this local port */ acl = ft_acl_get(tport->tpg, rdata); if (!acl) - return 0; + goto not_target; /* no target for this remote */ if (!rspp) goto fill; @@ -403,6 +403,12 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, fcp_parm &= ~FCP_SPPF_RETRY; spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); return FC_SPP_RESP_ACK; + +not_target: + fcp_parm = ntohl(spp->spp_params); + fcp_parm &= ~FCP_SPPF_TARG_FCN; + spp->spp_params = htonl(fcp_parm); + return 0; } /** From aa16959322c2c096ac050d8a970e1cf2d2b1cc35 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 2 Jan 2013 12:47:59 -0800 Subject: [PATCH 1982/2357] target: Release se_cmd when LUN lookup fails for TMR commit 5a3b6fc0092c5f8dee7820064ee54d2631d48573 upstream. When transport_lookup_tmr_lun() fails and we return a task management response from target_complete_tmr_failure(), we need to call transport_cmd_check_stop_to_fabric() to release the last ref to the cmd after calling se_tfo->queue_tm_rsp(), or else we will never remove the failed TMR from the session command list (and we'll end up waiting forever when trying to tear down the session). (nab: Fix minor compile breakage) Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_transport.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 69f3f7d53a0..f52e5a0041b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1748,6 +1748,8 @@ static void target_complete_tmr_failure(struct work_struct *work) se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; se_cmd->se_tfo->queue_tm_rsp(se_cmd); + + transport_cmd_check_stop_to_fabric(se_cmd); } /** From 2017a7c8ee63e678c20479e24416aac20a8899dc Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jan 2013 16:55:55 +0100 Subject: [PATCH 1983/2357] s390/time: fix sched_clock() overflow commit ed4f20943cd4c7b55105c04daedf8d63ab6d499c upstream. Converting a 64 Bit TOD format value to nanoseconds means that the value must be divided by 4.096. In order to achieve that we multiply with 125 and divide by 512. When used within sched_clock() this triggers an overflow after appr. 417 days. Resulting in a sched_clock() return value that is much smaller than previously and therefore may cause all sort of weird things in subsystems that rely on a monotonic sched_clock() behaviour. To fix this implement a tod_to_ns() helper function which converts TOD values without overflow and call this function from both places that open coded the conversion: sched_clock() and kvm_s390_handle_wait(). Reviewed-by: Martin Schwidefsky Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/timex.h | 28 ++++++++++++++++++++++++++++ arch/s390/kernel/time.c | 2 +- arch/s390/kvm/interrupt.c | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index c447a27a7fd..945b7cdf493 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -137,4 +137,32 @@ static inline unsigned long long get_clock_monotonic(void) return get_clock_xt() - sched_clock_base_cc; } +/** + * tod_to_ns - convert a TOD format value to nanoseconds + * @todval: to be converted TOD format value + * Returns: number of nanoseconds that correspond to the TOD format value + * + * Converting a 64 Bit TOD format value to nanoseconds means that the value + * must be divided by 4.096. In order to achieve that we multiply with 125 + * and divide by 512: + * + * ns = (todval * 125) >> 9; + * + * In order to avoid an overflow with the multiplication we can rewrite this. + * With a split todval == 2^32 * th + tl (th upper 32 bits, tl lower 32 bits) + * we end up with + * + * ns = ((2^32 * th + tl) * 125 ) >> 9; + * -> ns = (2^23 * th * 125) + ((tl * 125) >> 9); + * + */ +static inline unsigned long long tod_to_ns(unsigned long long todval) +{ + unsigned long long ns; + + ns = ((todval >> 32) << 23) * 125; + ns += ((todval & 0xffffffff) * 125) >> 9; + return ns; +} + #endif diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index d4e1cb1dbcd..c5531dbc8b2 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -64,7 +64,7 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators); */ unsigned long long notrace __kprobes sched_clock(void) { - return (get_clock_monotonic() * 125) >> 9; + return tod_to_ns(get_clock_monotonic()); } /* diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 2d9f9a72bb8..10e13b331d3 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -390,7 +390,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) return 0; } - sltime = ((vcpu->arch.sie_block->ckc - now)*125)>>9; + sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now); hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL); VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime); From d2e42ef98559ce48a516d40b64a7a489676d69f0 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 14 Nov 2012 20:43:31 +0000 Subject: [PATCH 1984/2357] x86/Sandy Bridge: reserve pages when integrated graphics is present commit a9acc5365dbda29f7be2884efb63771dc24bd815 upstream. SNB graphics devices have a bug that prevent them from accessing certain memory ranges, namely anything below 1M and in the pages listed in the table. So reserve those at boot if set detect a SNB gfx device on the CPU to avoid GPU hangs. Stephane Marchesin had a similar patch to the page allocator awhile back, but rather than reserving pages up front, it leaked them at allocation time. [ hpa: made a number of stylistic changes, marked arrays as static const, and made less verbose; use "memblock=debug" for full verbosity. ] Signed-off-by: Jesse Barnes Signed-off-by: H. Peter Anvin Cc: CAI Qian Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/setup.c | 78 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index ae98dbb5b8c..d289ee73a24 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -620,6 +620,81 @@ static __init void reserve_ibft_region(void) static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10; +static bool __init snb_gfx_workaround_needed(void) +{ + int i; + u16 vendor, devid; + static const u16 snb_ids[] = { + 0x0102, + 0x0112, + 0x0122, + 0x0106, + 0x0116, + 0x0126, + 0x010a, + }; + + /* Assume no if something weird is going on with PCI */ + if (!early_pci_allowed()) + return false; + + vendor = read_pci_config_16(0, 2, 0, PCI_VENDOR_ID); + if (vendor != 0x8086) + return false; + + devid = read_pci_config_16(0, 2, 0, PCI_DEVICE_ID); + for (i = 0; i < ARRAY_SIZE(snb_ids); i++) + if (devid == snb_ids[i]) + return true; + + return false; +} + +/* + * Sandy Bridge graphics has trouble with certain ranges, exclude + * them from allocation. + */ +static void __init trim_snb_memory(void) +{ + static const unsigned long bad_pages[] = { + 0x20050000, + 0x20110000, + 0x20130000, + 0x20138000, + 0x40004000, + }; + int i; + + if (!snb_gfx_workaround_needed()) + return; + + printk(KERN_DEBUG "reserving inaccessible SNB gfx pages\n"); + + /* + * Reserve all memory below the 1 MB mark that has not + * already been reserved. + */ + memblock_reserve(0, 1<<20); + + for (i = 0; i < ARRAY_SIZE(bad_pages); i++) { + if (memblock_reserve(bad_pages[i], PAGE_SIZE)) + printk(KERN_WARNING "failed to reserve 0x%08lx\n", + bad_pages[i]); + } +} + +/* + * Here we put platform-specific memory range workarounds, i.e. + * memory known to be corrupt or otherwise in need to be reserved on + * specific platforms. + * + * If this gets used more widely it could use a real dispatch mechanism. + */ +static void __init trim_platform_memory_ranges(void) +{ + trim_snb_memory(); +} + static void __init trim_bios_range(void) { /* @@ -640,6 +715,7 @@ static void __init trim_bios_range(void) * take them out. */ e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1); + sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); } @@ -919,6 +995,8 @@ void __init setup_arch(char **cmdline_p) setup_trampolines(); + trim_platform_memory_ranges(); + init_gbpages(); /* max_pfn_mapped is updated here */ From ee415da5538413edc5d63c07899abc0b2b36bc54 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Fri, 4 Jan 2013 17:02:18 +0100 Subject: [PATCH 1985/2357] ALSA: usb - fix race in creation of M-Audio Fast track pro driver commit b98ae2729dea161edc96c9d177459b6c28bcbba5 upstream. A patch in the 3.2 kernel caused regression with hotplugging the M-Audio Fast track pro, or sound after suspend. I don't have the device so I haven't done a full analysis, but it seems userspace (both udev and pulseaudio) got confused when a card was created, immediately destroyed, and then created again. However, at least one person in the bug report (martin djfun) reports that this patch resolves the issue for him. It also leaves a message in the log: "snd-usb-audio: probe of 1-1.1:1.1 failed with error -5" which is a bit misleading. It is better than non-working audio, but maybe there's a more elegant solution? BugLink: https://bugs.launchpad.net/bugs/1095315 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Cc: CAI Qian Signed-off-by: Greg Kroah-Hartman --- sound/usb/quirks.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 27817266867..c46171a2bf2 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -387,11 +387,13 @@ static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev) * rules */ err = usb_driver_set_configuration(dev, 2); - if (err < 0) { + if (err < 0) snd_printdd("error usb_driver_set_configuration: %d\n", err); - return -ENODEV; - } + /* Always return an error, so that we stop creating a device + that will just be destroyed and recreated with a new + configuration */ + return -ENODEV; } else snd_printk(KERN_INFO "usb-audio: Fast Track Pro config OK\n"); From 5c9611090f9d110a245cc54ddb9bb31b2cc2965f Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Wed, 14 Nov 2012 22:22:05 -0500 Subject: [PATCH 1986/2357] ext4: init pagevec in ext4_da_block_invalidatepages commit 66bea92c69477a75a5d37b9bfed5773c92a3c4b4 upstream. ext4_da_block_invalidatepages is missing a pagevec_init(), which means that pvec->cold contains random garbage. This affects whether the page goes to the front or back of the LRU when ->cold makes it to free_hot_cold_page() Reviewed-by: Lukas Czerner Reviewed-by: Carlos Maiolino Signed-off-by: Eric Sandeen Signed-off-by: "Theodore Ts'o" Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index dcd08e48576..a0d7e2617fd 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1424,6 +1424,8 @@ static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd) index = mpd->first_page; end = mpd->next_page - 1; + + pagevec_init(&pvec, 0); while (index <= end) { nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE); if (nr_pages == 0) From ced8dfbc6b44c7b14204a13ff95f22bdee52578f Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sat, 9 Jun 2012 10:53:16 +0000 Subject: [PATCH 1987/2357] r8169: avoid NAPI scheduling delay. commit 7dbb491878a2c51d372a8890fa45a8ff80358af1 upstream. While reworking the r8169 driver a few months ago to perform the smallest amount of work in the irq handler, I took care of avoiding any irq mask register operation in the slow work dedicated user context thread. The slow work thread scheduled an extra round of NAPI work which would ultimately set the irq mask register as required, thus keeping such irq mask operations in the NAPI handler. It would eventually race with the irq handler and delay NAPI execution for - assuming no further irq - a whole ksoftirqd period. Mildly a problem for rare link changes or corner case PCI events. The race was always lost after the last bh disabling lock had been removed from the work thread and people started wondering where those pesky "NOHZ: local_softirq_pending 08" messages came from. Actually the irq mask register _can_ be set up directly in the slow work thread. Signed-off-by: Francois Romieu Reported-by: Dave Jones Tested-by: Marc Dionne Cc: Thomas Gleixner Cc: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 0dc70c21767..06ee243d41a 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5516,11 +5516,7 @@ static void rtl_slow_event_work(struct rtl8169_private *tp) if (status & LinkChg) __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true); - napi_disable(&tp->napi); - rtl_irq_disable(tp); - - napi_enable(&tp->napi); - napi_schedule(&tp->napi); + rtl_irq_enable_all(tp); } static void rtl_task(struct work_struct *work) From 92a7389317838f3338466df0c0e3d23ad33cb1f4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 4 Dec 2012 23:43:57 -0800 Subject: [PATCH 1988/2357] target: Add link_magic for fabric allow_link destination target_items commit 0ff8754981261a80f4b77db2536dfea92c2d4539 upstream. This patch adds [dev,lun]_link_magic value assignment + checks within generic target_fabric_port_link() and target_fabric_mappedlun_link() code to ensure destination config_item *target_item sent from configfs_symlink() -> config_item_operations->allow_link() is the underlying se_device->dev_group and se_lun->lun_group that we expect to symlink. Reported-by: Sebastian Andrzej Siewior Cc: Sebastian Andrzej Siewior Signed-off-by: Nicholas Bellinger Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_device.c | 1 + drivers/target/target_core_fabric_configfs.c | 12 ++++++++++++ drivers/target/target_core_tpg.c | 1 + drivers/target/target_core_transport.c | 1 + include/target/target_core_base.h | 4 ++++ 5 files changed, 19 insertions(+) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 4df8022fe3c..26c62f05975 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1665,6 +1665,7 @@ int core_dev_setup_virtual_lun0(void) ret = PTR_ERR(dev); goto out; } + dev->dev_link_magic = SE_DEV_LINK_MAGIC; se_dev->se_dev_ptr = dev; g_lun0_dev = dev; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 405cc98eaed..b009b89d2fb 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -72,6 +72,12 @@ static int target_fabric_mappedlun_link( struct se_portal_group *se_tpg; struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s; int ret = 0, lun_access; + + if (lun->lun_link_magic != SE_LUN_LINK_MAGIC) { + pr_err("Bad lun->lun_link_magic, not a valid lun_ci pointer:" + " %p to struct lun: %p\n", lun_ci, lun); + return -EFAULT; + } /* * Ensure that the source port exists */ @@ -746,6 +752,12 @@ static int target_fabric_port_link( struct target_fabric_configfs *tf; int ret; + if (dev->dev_link_magic != SE_DEV_LINK_MAGIC) { + pr_err("Bad dev->dev_link_magic, not a valid se_dev_ci pointer:" + " %p to struct se_device: %p\n", se_dev_ci, dev); + return -EFAULT; + } + tpg_ci = &lun_ci->ci_parent->ci_group->cg_item; se_tpg = container_of(to_config_group(tpg_ci), struct se_portal_group, tpg_group); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index e320ec24aa1..ba537b6fd85 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -677,6 +677,7 @@ int core_tpg_register( for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { lun = se_tpg->tpg_lun_list[i]; lun->unpacked_lun = i; + lun->lun_link_magic = SE_LUN_LINK_MAGIC; lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f52e5a0041b..f687892b00b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1341,6 +1341,7 @@ struct se_device *transport_add_device_to_core_hba( dev->se_hba = hba; dev->se_sub_dev = se_dev; dev->transport = transport; + dev->dev_link_magic = SE_DEV_LINK_MAGIC; INIT_LIST_HEAD(&dev->dev_list); INIT_LIST_HEAD(&dev->dev_sep_list); INIT_LIST_HEAD(&dev->dev_tmr_list); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 3ad5b33ee32..569c28236b0 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -779,6 +779,8 @@ struct se_subsystem_dev { }; struct se_device { +#define SE_DEV_LINK_MAGIC 0xfeeddeef + u32 dev_link_magic; /* RELATIVE TARGET PORT IDENTIFER Counter */ u16 dev_rpti_counter; /* Used for SAM Task Attribute ordering */ @@ -869,6 +871,8 @@ struct se_port_stat_grps { }; struct se_lun { +#define SE_LUN_LINK_MAGIC 0xffff7771 + u32 lun_link_magic; /* See transport_lun_status_table */ enum transport_lun_status_table lun_status; u32 lun_access; From 5ad7813d5a6ca36e36d41ebfb27ffaf3f3006b45 Mon Sep 17 00:00:00 2001 From: Tom Mingarelli Date: Tue, 20 Nov 2012 19:43:17 +0000 Subject: [PATCH 1989/2357] intel-iommu: Prevent devices with RMRRs from being placed into SI Domain commit ea2447f700cab264019b52e2b417d689e052dcfd upstream. This patch is to prevent non-USB devices that have RMRRs associated with them from being placed into the SI Domain during init. This fixes the issue where the RMRR info for devices being placed in and out of the SI Domain gets lost. Signed-off-by: Thomas Mingarelli Tested-by: Shuah Khan Reviewed-by: Donald Dutile Reviewed-by: Alex Williamson Signed-off-by: Joerg Roedel Cc: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-iommu.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 9c34db8e729..be6660696c9 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2321,8 +2321,39 @@ static int domain_add_dev_info(struct dmar_domain *domain, return 0; } +static bool device_has_rmrr(struct pci_dev *dev) +{ + struct dmar_rmrr_unit *rmrr; + int i; + + for_each_rmrr_units(rmrr) { + for (i = 0; i < rmrr->devices_cnt; i++) { + /* + * Return TRUE if this RMRR contains the device that + * is passed in. + */ + if (rmrr->devices[i] == dev) + return true; + } + } + return false; +} + static int iommu_should_identity_map(struct pci_dev *pdev, int startup) { + + /* + * We want to prevent any device associated with an RMRR from + * getting placed into the SI Domain. This is done because + * problems exist when devices are moved in and out of domains + * and their respective RMRR info is lost. We exempt USB devices + * from this process due to their usage of RMRRs that are known + * to not be needed after BIOS hand-off to OS. + */ + if (device_has_rmrr(pdev) && + (pdev->class >> 8) != PCI_CLASS_SERIAL_USB) + return 0; + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return 1; From 6365d1039ebcdd214a891df7406e709db4d3fc30 Mon Sep 17 00:00:00 2001 From: Stefan Assmann Date: Tue, 4 Dec 2012 06:00:17 +0000 Subject: [PATCH 1990/2357] igb: release already assigned MSI-X interrupts if setup fails commit 52285b762b3681669215bf1d17ca6143448ab7d3 upstream. During MSI-X setup the system might run out of vectors. If this happens the already assigned vectors for this NIC should be freed before trying the disable MSI-X. Failing to do so results in the following oops. kernel BUG at drivers/pci/msi.c:341! [...] Call Trace: [] pci_disable_msix+0x3d/0x60 [] igb_reset_interrupt_capability+0x27/0x5c [igb] [] igb_clear_interrupt_scheme+0x26/0x2d [igb] [] igb_request_irq+0x73/0x297 [igb] [] __igb_open+0xc8/0x223 [igb] [] igb_open+0x13/0x15 [igb] [] __dev_open+0xbf/0x120 [] __dev_change_flags+0xa1/0x180 [] dev_change_flags+0x28/0x70 [] devinet_ioctl+0x5b7/0x620 [] inet_ioctl+0x88/0xa0 [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x72/0x270 [] do_vfs_ioctl+0x8c/0x340 [] sys_ioctl+0xa1/0xb0 [] system_call_fastpath+0x16/0x1b Code: 48 89 df e8 1f 40 ed ff 4d 39 e6 49 8b 45 10 75 b6 48 83 c4 18 5b 41 5c 41 5d 41 5e 41 5f c9 c3 48 8b 7b 20 e8 3e 91 db ff eb ae <0f> 0b eb fe 0f 1f 84 00 00 00 00 00 55 48 89 e5 0f 1f 44 00 00 RIP [] free_msi_irqs+0x124/0x130 RSP Signed-off-by: Stefan Assmann Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Abdallah Chatila --- drivers/net/ethernet/intel/igb/igb_main.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 8683ca4748c..6b4f0148ee6 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -951,17 +951,18 @@ static int igb_request_msix(struct igb_adapter *adapter) { struct net_device *netdev = adapter->netdev; struct e1000_hw *hw = &adapter->hw; - int i, err = 0, vector = 0; + int i, err = 0, vector = 0, free_vector = 0; err = request_irq(adapter->msix_entries[vector].vector, igb_msix_other, 0, netdev->name, adapter); if (err) - goto out; - vector++; + goto err_out; for (i = 0; i < adapter->num_q_vectors; i++) { struct igb_q_vector *q_vector = adapter->q_vector[i]; + vector++; + q_vector->itr_register = hw->hw_addr + E1000_EITR(vector); if (q_vector->rx.ring && q_vector->tx.ring) @@ -980,13 +981,22 @@ static int igb_request_msix(struct igb_adapter *adapter) igb_msix_ring, 0, q_vector->name, q_vector); if (err) - goto out; - vector++; + goto err_free; } igb_configure_msix(adapter); return 0; -out: + +err_free: + /* free already assigned IRQs */ + free_irq(adapter->msix_entries[free_vector++].vector, adapter); + + vector--; + for (i = 0; i < vector; i++) { + free_irq(adapter->msix_entries[free_vector++].vector, + adapter->q_vector[i]); + } +err_out: return err; } From d239fdb0d4d3088b5161f0c92ed929143b45d830 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 23 Feb 2012 12:56:26 +0100 Subject: [PATCH 1991/2357] drbd: add missing part_round_stats to _drbd_start_io_acct commit 72585d2428fa3a0daab02ebad1f41e5ef517dbaa upstream. Without this, iostat frequently sees bogus svctime and >= 100% "utilization". Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Cc: Raoul Bhatia Signed-off-by: Greg Kroah-Hartman --- drivers/block/drbd/drbd_req.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 4a0f314086e..be984e07366 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -37,6 +37,7 @@ static void _drbd_start_io_acct(struct drbd_conf *mdev, struct drbd_request *req const int rw = bio_data_dir(bio); int cpu; cpu = part_stat_lock(); + part_round_stats(cpu, &mdev->vdisk->part0); part_stat_inc(cpu, &mdev->vdisk->part0, ios[rw]); part_stat_add(cpu, &mdev->vdisk->part0, sectors[rw], bio_sectors(bio)); part_inc_in_flight(&mdev->vdisk->part0, rw); From ffe288276822348a3717e11cee6646d856a409c4 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Tue, 15 Jan 2013 13:21:27 +0000 Subject: [PATCH 1992/2357] xen/grant-table: correctly initialize grant table version 1 commit d0b4d64aadb9f4a90669848de9ef3819050a98cd upstream. Commit 85ff6acb075a484780b3d763fdf41596d8fc0970 (xen/granttable: Grant tables V2 implementation) changed the GREFS_PER_GRANT_FRAME macro from a constant to a conditional expression. The expression depends on grant_table_version being appropriately set. Unfortunately, at init time grant_table_version will be 0. The GREFS_PER_GRANT_FRAME conditional expression checks for "grant_table_version == 1", and therefore returns the number of grant references per frame for v2. This causes gnttab_init() to allocate fewer pages for gnttab_list, as a frame can old half the number of v2 entries than v1 entries. After gnttab_resume() is called, grant_table_version is appropriately set. nr_init_grefs will then be miscalculated and gnttab_free_count will hold a value larger than the actual number of free gref entries. If a guest is heavily utilizing improperly initialized v1 grant tables, memory corruption can occur. One common manifestation is corruption of the vmalloc list, resulting in a poisoned pointer derefrence when accessing /proc/meminfo or /proc/vmallocinfo: [ 40.770064] BUG: unable to handle kernel paging request at 0000200200001407 [ 40.770083] IP: [] get_vmalloc_info+0x70/0x110 [ 40.770102] PGD 0 [ 40.770107] Oops: 0000 [#1] SMP [ 40.770114] CPU 10 This patch introduces a static variable, grefs_per_grant_frame, to cache the calculated value. gnttab_init() now calls gnttab_request_version() early so that grant_table_version and grefs_per_grant_frame can be appropriately set. A few BUG_ON()s have been added to prevent this type of bug from reoccurring in the future. Signed-off-by: Matt Wilson Reviewed-and-Tested-by: Steven Noonan Acked-by: Ian Campbell Cc: Konrad Rzeszutek Wilk Cc: Annie Li Cc: xen-devel@lists.xen.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/grant-table.c | 48 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index fda491cd53c..7e34beed9ea 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -53,10 +53,6 @@ /* External tools reserve first few grant table entries. */ #define NR_RESERVED_ENTRIES 8 #define GNTTAB_LIST_END 0xffffffff -#define GREFS_PER_GRANT_FRAME \ -(grant_table_version == 1 ? \ -(PAGE_SIZE / sizeof(struct grant_entry_v1)) : \ -(PAGE_SIZE / sizeof(union grant_entry_v2))) static grant_ref_t **gnttab_list; static unsigned int nr_grant_frames; @@ -151,6 +147,7 @@ static struct gnttab_ops *gnttab_interface; static grant_status_t *grstatus; static int grant_table_version; +static int grefs_per_grant_frame; static struct gnttab_free_callback *gnttab_free_callback_list; @@ -679,12 +676,14 @@ static int grow_gnttab_list(unsigned int more_frames) unsigned int new_nr_grant_frames, extra_entries, i; unsigned int nr_glist_frames, new_nr_glist_frames; + BUG_ON(grefs_per_grant_frame == 0); + new_nr_grant_frames = nr_grant_frames + more_frames; - extra_entries = more_frames * GREFS_PER_GRANT_FRAME; + extra_entries = more_frames * grefs_per_grant_frame; - nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP; + nr_glist_frames = (nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP; new_nr_glist_frames = - (new_nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP; + (new_nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP; for (i = nr_glist_frames; i < new_nr_glist_frames; i++) { gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC); if (!gnttab_list[i]) @@ -692,12 +691,12 @@ static int grow_gnttab_list(unsigned int more_frames) } - for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames; - i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++) + for (i = grefs_per_grant_frame * nr_grant_frames; + i < grefs_per_grant_frame * new_nr_grant_frames - 1; i++) gnttab_entry(i) = i + 1; gnttab_entry(i) = gnttab_free_head; - gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames; + gnttab_free_head = grefs_per_grant_frame * nr_grant_frames; gnttab_free_count += extra_entries; nr_grant_frames = new_nr_grant_frames; @@ -799,7 +798,8 @@ EXPORT_SYMBOL_GPL(gnttab_unmap_refs); static unsigned nr_status_frames(unsigned nr_grant_frames) { - return (nr_grant_frames * GREFS_PER_GRANT_FRAME + SPP - 1) / SPP; + BUG_ON(grefs_per_grant_frame == 0); + return (nr_grant_frames * grefs_per_grant_frame + SPP - 1) / SPP; } static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes) @@ -957,6 +957,7 @@ static void gnttab_request_version(void) rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1); if (rc == 0 && gsv.version == 2) { grant_table_version = 2; + grefs_per_grant_frame = PAGE_SIZE / sizeof(union grant_entry_v2); gnttab_interface = &gnttab_v2_ops; } else if (grant_table_version == 2) { /* @@ -969,17 +970,17 @@ static void gnttab_request_version(void) panic("we need grant tables version 2, but only version 1 is available"); } else { grant_table_version = 1; + grefs_per_grant_frame = PAGE_SIZE / sizeof(struct grant_entry_v1); gnttab_interface = &gnttab_v1_ops; } printk(KERN_INFO "Grant tables using version %d layout.\n", grant_table_version); } -int gnttab_resume(void) +static int gnttab_setup(void) { unsigned int max_nr_gframes; - gnttab_request_version(); max_nr_gframes = gnttab_max_grant_frames(); if (max_nr_gframes < nr_grant_frames) return -ENOSYS; @@ -1002,6 +1003,12 @@ int gnttab_resume(void) return 0; } +int gnttab_resume(void) +{ + gnttab_request_version(); + return gnttab_setup(); +} + int gnttab_suspend(void) { gnttab_interface->unmap_frames(); @@ -1013,9 +1020,10 @@ static int gnttab_expand(unsigned int req_entries) int rc; unsigned int cur, extra; + BUG_ON(grefs_per_grant_frame == 0); cur = nr_grant_frames; - extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / - GREFS_PER_GRANT_FRAME); + extra = ((req_entries + (grefs_per_grant_frame-1)) / + grefs_per_grant_frame); if (cur + extra > gnttab_max_grant_frames()) return -ENOSPC; @@ -1033,21 +1041,23 @@ int gnttab_init(void) unsigned int nr_init_grefs; int ret; + gnttab_request_version(); nr_grant_frames = 1; boot_max_nr_grant_frames = __max_nr_grant_frames(); /* Determine the maximum number of frames required for the * grant reference free list on the current hypervisor. */ + BUG_ON(grefs_per_grant_frame == 0); max_nr_glist_frames = (boot_max_nr_grant_frames * - GREFS_PER_GRANT_FRAME / RPP); + grefs_per_grant_frame / RPP); gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *), GFP_KERNEL); if (gnttab_list == NULL) return -ENOMEM; - nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP; + nr_glist_frames = (nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP; for (i = 0; i < nr_glist_frames; i++) { gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL); if (gnttab_list[i] == NULL) { @@ -1056,12 +1066,12 @@ int gnttab_init(void) } } - if (gnttab_resume() < 0) { + if (gnttab_setup() < 0) { ret = -ENODEV; goto ini_nomem; } - nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; + nr_init_grefs = nr_grant_frames * grefs_per_grant_frame; for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) gnttab_entry(i) = i + 1; From df1ffc8ee5cefbadd7477dda7ba0facafa3853a7 Mon Sep 17 00:00:00 2001 From: Frediano Ziglio Date: Wed, 16 Jan 2013 12:00:55 +0000 Subject: [PATCH 1993/2357] xen: Fix stack corruption in xen_failsafe_callback for 32bit PVOPS guests. commit 9174adbee4a9a49d0139f5d71969852b36720809 upstream. This fixes CVE-2013-0190 / XSA-40 There has been an error on the xen_failsafe_callback path for failed iret, which causes the stack pointer to be wrong when entering the iret_exc error path. This can result in the kernel crashing. In the classic kernel case, the relevant code looked a little like: popl %eax # Error code from hypervisor jz 5f addl $16,%esp jmp iret_exc # Hypervisor said iret fault 5: addl $16,%esp # Hypervisor said segment selector fault Here, there are two identical addls on either option of a branch which appears to have been optimised by hoisting it above the jz, and converting it to an lea, which leaves the flags register unaffected. In the PVOPS case, the code looks like: popl_cfi %eax # Error from the hypervisor lea 16(%esp),%esp # Add $16 before choosing fault path CFI_ADJUST_CFA_OFFSET -16 jz 5f addl $16,%esp # Incorrectly adjust %esp again jmp iret_exc It is possible unprivileged userspace applications to cause this behaviour, for example by loading an LDT code selector, then changing the code selector to be not-present. At this point, there is a race condition where it is possible for the hypervisor to return back to userspace from an interrupt, fault on its own iret, and inject a failsafe_callback into the kernel. This bug has been present since the introduction of Xen PVOPS support in commit 5ead97c84 (xen: Core Xen implementation), in 2.6.23. Signed-off-by: Frediano Ziglio Signed-off-by: Andrew Cooper Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/entry_32.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 6d4f7ba227f..2af4ccd88d1 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -1074,7 +1074,6 @@ ENTRY(xen_failsafe_callback) lea 16(%esp),%esp CFI_ADJUST_CFA_OFFSET -16 jz 5f - addl $16,%esp jmp iret_exc 5: pushl_cfi $-1 /* orig_ax = -1 => not a system call */ SAVE_ALL From a4ee70a6e231c775460a7e1143cde6fc5ec7c03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Tue, 15 Jan 2013 10:29:49 +0100 Subject: [PATCH 1994/2357] USB: option: add TP-LINK HSUPA Modem MA180 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 99beb2e9687ffd61c92a9875141eabe6f57a71b9 upstream. The driver description files gives these names to the vendor specific functions on this modem: Diagnostics VID_2357&PID_0201&MI_00 NMEA VID_2357&PID_0201&MI_01 Modem VID_2357&PID_0201&MI_03 Networkcard VID_2357&PID_0201&MI_04 Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ba23ad55f41..4ea00fa39c4 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -449,6 +449,10 @@ static void option_instat_callback(struct urb *urb); #define PETATEL_VENDOR_ID 0x1ff4 #define PETATEL_PRODUCT_NP10T 0x600e +/* TP-LINK Incorporated products */ +#define TPLINK_VENDOR_ID 0x2357 +#define TPLINK_PRODUCT_MA180 0x0201 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -1311,6 +1315,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) }, { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) }, + { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); From fd426d3b60d656d3b0df7c5ee2cdcb0a4e6f8850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 17 Jan 2013 15:14:22 +0100 Subject: [PATCH 1995/2357] USB: option: blacklist network interface on ONDA MT8205 4G LTE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork commit 2291dff02e5f8c708a46a7c4c888f2c467e26642 upstream. The driver description files gives these names to the vendor specific functions on this modem: Diag VID_19D2&PID_0265&MI_00 NMEA VID_19D2&PID_0265&MI_01 AT cmd VID_19D2&PID_0265&MI_02 Modem VID_19D2&PID_0265&MI_03 Net VID_19D2&PID_0265&MI_04 Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 4ea00fa39c4..0778cd09852 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -934,7 +934,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0254, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff), /* ONDA MT8205 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff), /* ZTE MF880 */ .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) }, From 51478116612441b178bc747b445e592586e1f817 Mon Sep 17 00:00:00 2001 From: chao bi Date: Wed, 12 Dec 2012 11:40:56 +0800 Subject: [PATCH 1996/2357] serial:ifx6x60:Delete SPI timer when shut down port commit 014b9b4ce84281ccb3d723c792bed19815f3571a upstream. When shut down SPI port, it's possible that MRDY has been asserted and a SPI timer was activated waiting for SRDY assert, in the case, it needs to delete this timer. Signed-off-by: Chen Jun Signed-off-by: channing Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ifx6x60.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 144cd3987d4..17f587c5dba 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -552,6 +552,7 @@ static void ifx_port_shutdown(struct tty_port *port) container_of(port, struct ifx_spi_device, tty_port); mrdy_set_low(ifx_dev); + del_timer(&ifx_dev->spi_timer); clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); tasklet_kill(&ifx_dev->io_work_tasklet); } From f6ffcce2ef152bebaeeed0cd9fd117e23a3c46ff Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 14 Jan 2013 20:09:26 +0100 Subject: [PATCH 1997/2357] tty: 8250_dw: Fix inverted arguments to serial_out in IRQ handler commit 68e56cb3a068f9c30971c6117fbbd1e32918e49e upstream. Signed-off-by: Maxime Ripard Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index f574eef3075..b6dc908a24c 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -79,7 +79,7 @@ static int dw8250_handle_irq(struct uart_port *p) } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { /* Clear the USR and write the LCR again. */ (void)p->serial_in(p, UART_USR); - p->serial_out(p, d->last_lcr, UART_LCR); + p->serial_out(p, UART_LCR, d->last_lcr); return 1; } From d7ddb69a53cd7c03c4c0660d13534214d2782c21 Mon Sep 17 00:00:00 2001 From: Tormod Volden Date: Wed, 9 Jan 2013 22:23:32 +0100 Subject: [PATCH 1998/2357] staging: wlan-ng: Fix clamping of returned SSID length commit 811a37effdb11e54e1ff1ddaa944286c88f58487 upstream. Commit 2e254212 broke listing of available network names, since it clamped the length of the returned SSID to WLAN_BSSID_LEN (6) instead of WLAN_SSID_MAXLEN (32). https://bugzilla.kernel.org/show_bug.cgi?id=52501 Signed-off-by: Tormod Volden Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/prism2mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c index c3bb05dd744..4110a2f9425 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ b/drivers/staging/wlan-ng/prism2mgmt.c @@ -406,7 +406,7 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) /* SSID */ req->ssid.status = P80211ENUM_msgitem_status_data_ok; req->ssid.data.len = le16_to_cpu(item->ssid.len); - req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_BSSID_LEN); + req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_SSID_MAXLEN); memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len); /* supported rates */ From 111be1d7aaa33a36bc3e426d882454ca9b966721 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 14 Jan 2013 01:29:17 +0000 Subject: [PATCH 1999/2357] staging: vt6656: Fix inconsistent structure packing commit 1ee4c55fc9620451b2a825d793042a7e0775391b upstream. vt6656 has several headers that use the #pragma pack(1) directive to enable structure packing, but never disable it. The layout of structures defined in other headers can then depend on which order the various headers are included in, breaking the One Definition Rule. In practice this resulted in crashes on x86_64 until the order of header inclusion was changed for some files in commit 11d404cb56ecd ('staging: vt6656: fix headers and add cfg80211.'). But we need a proper fix that won't be affected by future changes to the order of inclusion. This removes the #pragma pack(1) directives and adds __packed to the structure definitions for which packing appears to have been intended. Reported-and-tested-by: Malcolm Priestley Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/bssdb.h | 1 - drivers/staging/vt6656/int.h | 1 - drivers/staging/vt6656/iocmd.h | 33 ++++++++++++++++----------------- drivers/staging/vt6656/iowpa.h | 8 +++----- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/drivers/staging/vt6656/bssdb.h b/drivers/staging/vt6656/bssdb.h index a8f97ebb659..991ce3eecd8 100644 --- a/drivers/staging/vt6656/bssdb.h +++ b/drivers/staging/vt6656/bssdb.h @@ -92,7 +92,6 @@ typedef struct tagSRSNCapObject { } SRSNCapObject, *PSRSNCapObject; // BSS info(AP) -#pragma pack(1) typedef struct tagKnownBSS { // BSS info BOOL bActive; diff --git a/drivers/staging/vt6656/int.h b/drivers/staging/vt6656/int.h index a5d96b96817..27bc7f548ab 100644 --- a/drivers/staging/vt6656/int.h +++ b/drivers/staging/vt6656/int.h @@ -34,7 +34,6 @@ #include "device.h" /*--------------------- Export Definitions -------------------------*/ -#pragma pack(1) typedef struct tagSINTData { BYTE byTSR0; BYTE byPkt0; diff --git a/drivers/staging/vt6656/iocmd.h b/drivers/staging/vt6656/iocmd.h index 22710cef751..ae6e2d237b2 100644 --- a/drivers/staging/vt6656/iocmd.h +++ b/drivers/staging/vt6656/iocmd.h @@ -95,13 +95,12 @@ typedef enum tagWZONETYPE { // Ioctl interface structure // Command structure // -#pragma pack(1) typedef struct tagSCmdRequest { u8 name[16]; void *data; u16 wResult; u16 wCmdCode; -} SCmdRequest, *PSCmdRequest; +} __packed SCmdRequest, *PSCmdRequest; // // Scan @@ -111,7 +110,7 @@ typedef struct tagSCmdScan { u8 ssid[SSID_MAXLEN + 2]; -} SCmdScan, *PSCmdScan; +} __packed SCmdScan, *PSCmdScan; // // BSS Join @@ -126,7 +125,7 @@ typedef struct tagSCmdBSSJoin { BOOL bPSEnable; BOOL bShareKeyAuth; -} SCmdBSSJoin, *PSCmdBSSJoin; +} __packed SCmdBSSJoin, *PSCmdBSSJoin; // // Zonetype Setting @@ -137,7 +136,7 @@ typedef struct tagSCmdZoneTypeSet { BOOL bWrite; WZONETYPE ZoneType; -} SCmdZoneTypeSet, *PSCmdZoneTypeSet; +} __packed SCmdZoneTypeSet, *PSCmdZoneTypeSet; typedef struct tagSWPAResult { char ifname[100]; @@ -145,7 +144,7 @@ typedef struct tagSWPAResult { u8 key_mgmt; u8 eap_type; BOOL authenticated; -} SWPAResult, *PSWPAResult; +} __packed SWPAResult, *PSWPAResult; typedef struct tagSCmdStartAP { @@ -157,7 +156,7 @@ typedef struct tagSCmdStartAP { BOOL bShareKeyAuth; u8 byBasicRate; -} SCmdStartAP, *PSCmdStartAP; +} __packed SCmdStartAP, *PSCmdStartAP; typedef struct tagSCmdSetWEP { @@ -167,7 +166,7 @@ typedef struct tagSCmdSetWEP { BOOL bWepKeyAvailable[WEP_NKEYS]; u32 auWepKeyLength[WEP_NKEYS]; -} SCmdSetWEP, *PSCmdSetWEP; +} __packed SCmdSetWEP, *PSCmdSetWEP; typedef struct tagSBSSIDItem { @@ -180,14 +179,14 @@ typedef struct tagSBSSIDItem { BOOL bWEPOn; u32 uRSSI; -} SBSSIDItem; +} __packed SBSSIDItem; typedef struct tagSBSSIDList { u32 uItem; SBSSIDItem sBSSIDList[0]; -} SBSSIDList, *PSBSSIDList; +} __packed SBSSIDList, *PSBSSIDList; typedef struct tagSNodeItem { @@ -208,7 +207,7 @@ typedef struct tagSNodeItem { u32 uTxAttempts; u16 wFailureRatio; -} SNodeItem; +} __packed SNodeItem; typedef struct tagSNodeList { @@ -216,7 +215,7 @@ typedef struct tagSNodeList { u32 uItem; SNodeItem sNodeList[0]; -} SNodeList, *PSNodeList; +} __packed SNodeList, *PSNodeList; typedef struct tagSCmdLinkStatus { @@ -229,7 +228,7 @@ typedef struct tagSCmdLinkStatus { u32 uChannel; u32 uLinkRate; -} SCmdLinkStatus, *PSCmdLinkStatus; +} __packed SCmdLinkStatus, *PSCmdLinkStatus; // // 802.11 counter @@ -247,7 +246,7 @@ typedef struct tagSDot11MIBCount { u32 ReceivedFragmentCount; u32 MulticastReceivedFrameCount; u32 FCSErrorCount; -} SDot11MIBCount, *PSDot11MIBCount; +} __packed SDot11MIBCount, *PSDot11MIBCount; @@ -355,13 +354,13 @@ typedef struct tagSStatMIBCount { u32 ullTxBroadcastBytes[2]; u32 ullTxMulticastBytes[2]; u32 ullTxDirectedBytes[2]; -} SStatMIBCount, *PSStatMIBCount; +} __packed SStatMIBCount, *PSStatMIBCount; typedef struct tagSCmdValue { u32 dwValue; -} SCmdValue, *PSCmdValue; +} __packed SCmdValue, *PSCmdValue; // // hostapd & viawget ioctl related @@ -431,7 +430,7 @@ struct viawget_hostapd_param { u8 ssid[32]; } scan_req; } u; -}; +} __packed; /*--------------------- Export Classes ----------------------------*/ diff --git a/drivers/staging/vt6656/iowpa.h b/drivers/staging/vt6656/iowpa.h index 959c8868f6e..2522ddec718 100644 --- a/drivers/staging/vt6656/iowpa.h +++ b/drivers/staging/vt6656/iowpa.h @@ -67,12 +67,11 @@ enum { -#pragma pack(1) typedef struct viawget_wpa_header { u8 type; u16 req_ie_len; u16 resp_ie_len; -} viawget_wpa_header; +} __packed viawget_wpa_header; struct viawget_wpa_param { u32 cmd; @@ -113,9 +112,8 @@ struct viawget_wpa_param { u8 *buf; } scan_results; } u; -}; +} __packed; -#pragma pack(1) struct viawget_scan_result { u8 bssid[6]; u8 ssid[32]; @@ -130,7 +128,7 @@ struct viawget_scan_result { int noise; int level; int maxrate; -}; +} __packed; /*--------------------- Export Classes ----------------------------*/ From 02f3169eee620366301c23d29622eb0f69046607 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 21 Jan 2013 11:47:35 -0800 Subject: [PATCH 2000/2357] Linux 3.4.27 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2d84a1d4d26..f139ce7b942 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 26 +SUBLEVEL = 27 EXTRAVERSION = NAME = Saber-toothed Squirrel From aa824d5b726d7d7d90331bcacc7807b83f02fa54 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 15 Jan 2013 16:17:54 +0000 Subject: [PATCH 2001/2357] drm/i915: Invalidate the relocation presumed_offsets along the slow path commit 262b6d363fcff16359c93bd58c297f961f6e6273 upstream. In the slow path, we are forced to copy the relocations prior to acquiring the struct mutex in order to handle pagefaults. We forgo copying the new offsets back into the relocation entries in order to prevent a recursive locking bug should we trigger a pagefault whilst holding the mutex for the reservations of the execbuffer. Therefore, we need to reset the presumed_offsets just in case the objects are rebound back into their old locations after relocating for this exexbuffer - if that were to happen we would assume the relocations were valid and leave the actual pointers to the kernels dangling, instant hang. Fixes regression from commit bcf50e2775bbc3101932d8e4ab8c7902aa4163b4 Author: Chris Wilson Date: Sun Nov 21 22:07:12 2010 +0000 drm/i915: Handle pagefaults in execbuffer user relocations Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55984 Signed-off-by: Chris Wilson Cc: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index de431942ded..d4417e3cc3d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -707,6 +707,8 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, total = 0; for (i = 0; i < count; i++) { struct drm_i915_gem_relocation_entry __user *user_relocs; + u64 invalid_offset = (u64)-1; + int j; user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr; @@ -717,6 +719,25 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, goto err; } + /* As we do not update the known relocation offsets after + * relocating (due to the complexities in lock handling), + * we need to mark them as invalid now so that we force the + * relocation processing next time. Just in case the target + * object is evicted and then rebound into its old + * presumed_offset before the next execbuffer - if that + * happened we would make the mistake of assuming that the + * relocations were valid. + */ + for (j = 0; j < exec[i].relocation_count; j++) { + if (copy_to_user(&user_relocs[j].presumed_offset, + &invalid_offset, + sizeof(invalid_offset))) { + ret = -EFAULT; + mutex_lock(&dev->struct_mutex); + goto err; + } + } + reloc_offset[i] = total; total += exec[i].relocation_count; } From d027bb39240aa55b86738508fb5612b9125a886f Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Fri, 4 Jan 2013 14:39:09 -0800 Subject: [PATCH 2002/2357] libata: ahci: Add support for Enmotus Bobcat device. commit 7f9c9f8e24590e7dcd26ca408458c43df5b83e61 upstream. Silicon does not support standard AHCI BAR assignment. Add vendor/device exception to force BAR 2. Signed-off-by: Hugh Daschbach Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ahci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 93cbc4484cc..5d0fb6b5188 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -53,6 +53,7 @@ enum { AHCI_PCI_BAR_STA2X11 = 0, + AHCI_PCI_BAR_ENMOTUS = 2, AHCI_PCI_BAR_STANDARD = 5, }; @@ -407,6 +408,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* Asmedia */ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1061 */ + /* Enmotus */ + { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, + /* Generic, PCI class code for AHCI */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, @@ -1079,9 +1083,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "PDC42819 can only drive SATA devices with this driver\n"); - /* The Connext uses non-standard BAR */ + /* Both Connext and Enmotus devices use non-standard BARs */ if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06) ahci_pci_bar = AHCI_PCI_BAR_STA2X11; + else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000) + ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS; /* acquire resources */ rc = pcim_enable_device(pdev); From f2a010040e2c368a76f7ea0ed6533f5779cb6b4b Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 14 Dec 2012 09:48:15 -0500 Subject: [PATCH 2003/2357] ftrace: Be first to run code modification on modules commit c1bf08ac26e92122faab9f6c32ea8aba94612dae upstream. If some other kernel subsystem has a module notifier, and adds a kprobe to a ftrace mcount point (now that kprobes work on ftrace points), when the ftrace notifier runs it will fail and disable ftrace, as well as kprobes that are attached to ftrace points. Here's the error: WARNING: at kernel/trace/ftrace.c:1618 ftrace_bug+0x239/0x280() Hardware name: Bochs Modules linked in: fat(+) stap_56d28a51b3fe546293ca0700b10bcb29__8059(F) nfsv4 auth_rpcgss nfs dns_resolver fscache xt_nat iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack lockd sunrpc ppdev parport_pc parport microcode virtio_net i2c_piix4 drm_kms_helper ttm drm i2c_core [last unloaded: bid_shared] Pid: 8068, comm: modprobe Tainted: GF 3.7.0-0.rc8.git0.1.fc19.x86_64 #1 Call Trace: [] warn_slowpath_common+0x7f/0xc0 [] ? __probe_kernel_read+0x46/0x70 [] ? 0xffffffffa017ffff [] ? 0xffffffffa017ffff [] warn_slowpath_null+0x1a/0x20 [] ftrace_bug+0x239/0x280 [] ftrace_process_locs+0x376/0x520 [] ftrace_module_notify+0x47/0x50 [] notifier_call_chain+0x4d/0x70 [] __blocking_notifier_call_chain+0x58/0x80 [] blocking_notifier_call_chain+0x16/0x20 [] sys_init_module+0x73/0x220 [] system_call_fastpath+0x16/0x1b ---[ end trace 9ef46351e53bbf80 ]--- ftrace failed to modify [] init_once+0x0/0x20 [fat] actual: cc:bb:d2:4b:e1 A kprobe was added to the init_once() function in the fat module on load. But this happened before ftrace could have touched the code. As ftrace didn't run yet, the kprobe system had no idea it was a ftrace point and simply added a breakpoint to the code (0xcc in the cc:bb:d2:4b:e1). Then when ftrace went to modify the location from a call to mcount/fentry into a nop, it didn't see a call op, but instead it saw the breakpoint op and not knowing what to do with it, ftrace shut itself down. The solution is to simply give the ftrace module notifier the max priority. This should have been done regardless, as the core code ftrace modification also happens very early on in boot up. This makes the module modification closer to core modification. Link: http://lkml.kernel.org/r/20130107140333.593683061@goodmis.org Acked-by: Masami Hiramatsu Reported-by: Frank Ch. Eigler Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 100b7fd1a64..6b194d842b1 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -3869,7 +3869,7 @@ static int ftrace_module_notify(struct notifier_block *self, struct notifier_block ftrace_module_nb = { .notifier_call = ftrace_module_notify, - .priority = 0, + .priority = INT_MAX, /* Run before anything that can use kprobes */ }; extern unsigned long __start_mcount_loc[]; From 9c5f1b49341154b579851425dabb32cb3aa9b5db Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 18 Jan 2013 23:56:39 +0200 Subject: [PATCH 2004/2357] evm: checking if removexattr is not a NULL commit a67adb997419fb53540d4a4f79c6471c60bc69b6 upstream. The following lines of code produce a kernel oops. fd = socket(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); fchmod(fd, 0666); [ 139.922364] BUG: unable to handle kernel NULL pointer dereference at (null) [ 139.924982] IP: [< (null)>] (null) [ 139.924982] *pde = 00000000 [ 139.924982] Oops: 0000 [#5] SMP [ 139.924982] Modules linked in: fuse dm_crypt dm_mod i2c_piix4 serio_raw evdev binfmt_misc button [ 139.924982] Pid: 3070, comm: acpid Tainted: G D 3.8.0-rc2-kds+ #465 Bochs Bochs [ 139.924982] EIP: 0060:[<00000000>] EFLAGS: 00010246 CPU: 0 [ 139.924982] EIP is at 0x0 [ 139.924982] EAX: cf5ef000 EBX: cf5ef000 ECX: c143d600 EDX: c15225f2 [ 139.924982] ESI: cf4d2a1c EDI: cf4d2a1c EBP: cc02df10 ESP: cc02dee4 [ 139.924982] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [ 139.924982] CR0: 80050033 CR2: 00000000 CR3: 0c059000 CR4: 000006d0 [ 139.924982] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [ 139.924982] DR6: ffff0ff0 DR7: 00000400 [ 139.924982] Process acpid (pid: 3070, ti=cc02c000 task=d7705340 task.ti=cc02c000) [ 139.924982] Stack: [ 139.924982] c1203c88 00000000 cc02def4 cf4d2a1c ae21eefa 471b60d5 1083c1ba c26a5940 [ 139.924982] e891fb5e 00000041 00000004 cc02df1c c1203964 00000000 cc02df4c c10e20c3 [ 139.924982] 00000002 00000000 00000000 22222222 c1ff2222 cf5ef000 00000000 d76efb08 [ 139.924982] Call Trace: [ 139.924982] [] ? evm_update_evmxattr+0x5b/0x62 [ 139.924982] [] evm_inode_post_setattr+0x22/0x26 [ 139.924982] [] notify_change+0x25f/0x281 [ 139.924982] [] chmod_common+0x59/0x76 [ 139.924982] [] ? put_unused_fd+0x33/0x33 [ 139.924982] [] sys_fchmod+0x39/0x5c [ 139.924982] [] syscall_call+0x7/0xb [ 139.924982] Code: Bad EIP value. This happens because sockets do not define the removexattr operation. Before removing the xattr, verify the removexattr function pointer is not NULL. Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- security/integrity/evm/evm_crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 49a464f5595..62fa2c57498 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -205,9 +205,9 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM, &xattr_data, sizeof(xattr_data), 0); - } - else if (rc == -ENODATA) + } else if (rc == -ENODATA && inode->i_op->removexattr) { rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM); + } return rc; } From b08d81801e151fbcefa81a551eadf2beff554752 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 21 Jan 2013 20:47:41 +0100 Subject: [PATCH 2005/2357] ptrace: introduce signal_wake_up_state() and ptrace_signal_wake_up() commit 910ffdb18a6408e14febbb6e4b6840fd2c928c82 upstream. Cleanup and preparation for the next change. signal_wake_up(resume => true) is overused. None of ptrace/jctl callers actually want to wakeup a TASK_WAKEKILL task, but they can't specify the necessary mask. Turn signal_wake_up() into signal_wake_up_state(state), reintroduce signal_wake_up() as a trivial helper, and add ptrace_signal_wake_up() which adds __TASK_TRACED. This way ptrace_signal_wake_up() can work "inside" ptrace_request() even if the tracee doesn't have the TASK_WAKEKILL bit set. Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/sched.h | 11 ++++++++++- kernel/ptrace.c | 8 ++++---- kernel/signal.c | 14 ++++---------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 48241aa976c..3dd0efbb70f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2695,7 +2695,16 @@ static inline void thread_group_cputime_init(struct signal_struct *sig) extern void recalc_sigpending_and_wake(struct task_struct *t); extern void recalc_sigpending(void); -extern void signal_wake_up(struct task_struct *t, int resume_stopped); +extern void signal_wake_up_state(struct task_struct *t, unsigned int state); + +static inline void signal_wake_up(struct task_struct *t, bool resume) +{ + signal_wake_up_state(t, resume ? TASK_WAKEKILL : 0); +} +static inline void ptrace_signal_wake_up(struct task_struct *t, bool resume) +{ + signal_wake_up_state(t, resume ? __TASK_TRACED : 0); +} /* * Wrappers for p->thread_info->cpu access. No-op on UP. diff --git a/kernel/ptrace.c b/kernel/ptrace.c index ee8d49b9c30..c4443846214 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -117,7 +117,7 @@ void __ptrace_unlink(struct task_struct *child) * TASK_KILLABLE sleeps. */ if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child)) - signal_wake_up(child, task_is_traced(child)); + ptrace_signal_wake_up(child, true); spin_unlock(&child->sighand->siglock); } @@ -311,7 +311,7 @@ static int ptrace_attach(struct task_struct *task, long request, */ if (task_is_stopped(task) && task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING)) - signal_wake_up(task, 1); + signal_wake_up_state(task, __TASK_STOPPED); spin_unlock(&task->sighand->siglock); @@ -728,7 +728,7 @@ int ptrace_request(struct task_struct *child, long request, * tracee into STOP. */ if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) - signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); + ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); unlock_task_sighand(child, &flags); ret = 0; @@ -754,7 +754,7 @@ int ptrace_request(struct task_struct *child, long request, * start of this trap and now. Trigger re-trap. */ if (child->jobctl & JOBCTL_TRAP_NOTIFY) - signal_wake_up(child, true); + ptrace_signal_wake_up(child, true); ret = 0; } unlock_task_sighand(child, &flags); diff --git a/kernel/signal.c b/kernel/signal.c index 17afcaf582d..fbeca4a2b2b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -677,23 +677,17 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) * No need to set need_resched since signal event passing * goes through ->blocked */ -void signal_wake_up(struct task_struct *t, int resume) +void signal_wake_up_state(struct task_struct *t, unsigned int state) { - unsigned int mask; - set_tsk_thread_flag(t, TIF_SIGPENDING); - /* - * For SIGKILL, we want to wake it up in the stopped/traced/killable + * TASK_WAKEKILL also means wake it up in the stopped/traced/killable * case. We don't check t->state here because there is a race with it * executing another processor and just now entering stopped state. * By using wake_up_state, we ensure the process will wake up and * handle its death signal. */ - mask = TASK_INTERRUPTIBLE; - if (resume) - mask |= TASK_WAKEKILL; - if (!wake_up_state(t, mask)) + if (!wake_up_state(t, state | TASK_INTERRUPTIBLE)) kick_process(t); } @@ -842,7 +836,7 @@ static void ptrace_trap_notify(struct task_struct *t) assert_spin_locked(&t->sighand->siglock); task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY); - signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); + ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); } /* From 9b6d794e7e56f3a413c57a15d4e07fb7efe6530a Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 21 Jan 2013 20:48:00 +0100 Subject: [PATCH 2006/2357] ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL commit 9899d11f654474d2d54ea52ceaa2a1f4db3abd68 upstream. putreg() assumes that the tracee is not running and pt_regs_access() can safely play with its stack. However a killed tracee can return from ptrace_stop() to the low-level asm code and do RESTORE_REST, this means that debugger can actually read/modify the kernel stack until the tracee does SAVE_REST again. set_task_blockstep() can race with SIGKILL too and in some sense this race is even worse, the very fact the tracee can be woken up breaks the logic. As Linus suggested we can clear TASK_WAKEKILL around the arch_ptrace() call, this ensures that nobody can ever wakeup the tracee while the debugger looks at it. Not only this fixes the mentioned problems, we can do some cleanups/simplifications in arch_ptrace() paths. Probably ptrace_unfreeze_traced() needs more callers, for example it makes sense to make the tracee killable for oom-killer before access_process_vm(). While at it, add the comment into may_ptrace_stop() to explain why ptrace_stop() still can't rely on SIGKILL and signal_pending_state(). Reported-by: Salman Qazi Reported-by: Suleiman Souhlal Suggested-by: Linus Torvalds Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/ptrace.c | 64 +++++++++++++++++++++++++++++++++++++++++-------- kernel/signal.c | 5 ++++ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index c4443846214..daf4394d1ab 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -122,6 +122,40 @@ void __ptrace_unlink(struct task_struct *child) spin_unlock(&child->sighand->siglock); } +/* Ensure that nothing can wake it up, even SIGKILL */ +static bool ptrace_freeze_traced(struct task_struct *task) +{ + bool ret = false; + + /* Lockless, nobody but us can set this flag */ + if (task->jobctl & JOBCTL_LISTENING) + return ret; + + spin_lock_irq(&task->sighand->siglock); + if (task_is_traced(task) && !__fatal_signal_pending(task)) { + task->state = __TASK_TRACED; + ret = true; + } + spin_unlock_irq(&task->sighand->siglock); + + return ret; +} + +static void ptrace_unfreeze_traced(struct task_struct *task) +{ + if (task->state != __TASK_TRACED) + return; + + WARN_ON(!task->ptrace || task->parent != current); + + spin_lock_irq(&task->sighand->siglock); + if (__fatal_signal_pending(task)) + wake_up_state(task, __TASK_TRACED); + else + task->state = TASK_TRACED; + spin_unlock_irq(&task->sighand->siglock); +} + /** * ptrace_check_attach - check whether ptracee is ready for ptrace operation * @child: ptracee to check for @@ -151,24 +185,29 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state) * be changed by us so it's not changing right after this. */ read_lock(&tasklist_lock); - if ((child->ptrace & PT_PTRACED) && child->parent == current) { + if (child->ptrace && child->parent == current) { + WARN_ON(child->state == __TASK_TRACED); /* * child->sighand can't be NULL, release_task() * does ptrace_unlink() before __exit_signal(). */ - spin_lock_irq(&child->sighand->siglock); - WARN_ON_ONCE(task_is_stopped(child)); - if (ignore_state || (task_is_traced(child) && - !(child->jobctl & JOBCTL_LISTENING))) + if (ignore_state || ptrace_freeze_traced(child)) ret = 0; - spin_unlock_irq(&child->sighand->siglock); } read_unlock(&tasklist_lock); - if (!ret && !ignore_state) - ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH; + if (!ret && !ignore_state) { + if (!wait_task_inactive(child, __TASK_TRACED)) { + /* + * This can only happen if may_ptrace_stop() fails and + * ptrace_stop() changes ->state back to TASK_RUNNING, + * so we should not worry about leaking __TASK_TRACED. + */ + WARN_ON(child->state == __TASK_TRACED); + ret = -ESRCH; + } + } - /* All systems go.. */ return ret; } @@ -891,6 +930,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, goto out_put_task_struct; ret = arch_ptrace(child, request, addr, data); + if (ret || request != PTRACE_DETACH) + ptrace_unfreeze_traced(child); out_put_task_struct: put_task_struct(child); @@ -1030,8 +1071,11 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, ret = ptrace_check_attach(child, request == PTRACE_KILL || request == PTRACE_INTERRUPT); - if (!ret) + if (!ret) { ret = compat_arch_ptrace(child, request, addr, data); + if (ret || request != PTRACE_DETACH) + ptrace_unfreeze_traced(child); + } out_put_task_struct: put_task_struct(child); diff --git a/kernel/signal.c b/kernel/signal.c index fbeca4a2b2b..a4363a982b0 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1802,6 +1802,10 @@ static inline int may_ptrace_stop(void) * If SIGKILL was already sent before the caller unlocked * ->siglock we must see ->core_state != NULL. Otherwise it * is safe to enter schedule(). + * + * This is almost outdated, a task with the pending SIGKILL can't + * block in TASK_TRACED. But PTRACE_EVENT_EXIT can be reported + * after SIGKILL was already dequeued. */ if (unlikely(current->mm->core_state) && unlikely(current->mm == current->parent->mm)) @@ -1927,6 +1931,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) if (gstop_done) do_notify_parent_cldstop(current, false, why); + /* tasklist protects us from ptrace_freeze_traced() */ __set_current_state(TASK_RUNNING); if (clear_code) current->exit_code = 0; From 465760c68a4e5037f10a7eab1df3fb2aff1e03a4 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 21 Jan 2013 20:48:17 +0100 Subject: [PATCH 2007/2357] wake_up_process() should be never used to wakeup a TASK_STOPPED/TRACED task commit 9067ac85d533651b98c2ff903182a20cbb361fcb upstream. wake_up_process() should never wakeup a TASK_STOPPED/TRACED task. Change it to use TASK_NORMAL and add the WARN_ON(). TASK_ALL has no other users, probably can be killed. Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/sched/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1d22981cd43..e1718bc35e1 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1688,7 +1688,8 @@ static void try_to_wake_up_local(struct task_struct *p) */ int wake_up_process(struct task_struct *p) { - return try_to_wake_up(p, TASK_ALL, 0); + WARN_ON(task_is_stopped_or_traced(p)); + return try_to_wake_up(p, TASK_NORMAL, 0); } EXPORT_SYMBOL(wake_up_process); From 7145808ebc1f0188cf9decbfd23279b0c10022f1 Mon Sep 17 00:00:00 2001 From: Betty Dall Date: Sun, 13 Jan 2013 15:46:18 -0700 Subject: [PATCH 2008/2357] PCI/AER: pci_get_domain_bus_and_slot() call missing required pci_dev_put() commit a82b6af37d20bfe6e99a4d890f1cf1d89059929f upstream. The function aer_recover_queue() calls pci_get_domain_bus_and_slot(), which requires that the caller decrement the reference count with pci_dev_put(). This patch adds the missing call to pci_dev_put(). Signed-off-by: Betty Dall Signed-off-by: Bjorn Helgaas Reviewed-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/aer/aerdrv_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 0ca05353814..a56105b66f1 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -637,6 +637,7 @@ static void aer_recover_work_func(struct work_struct *work) continue; } do_recovery(pdev, entry.severity); + pci_dev_put(pdev); } } #endif From 11cfb2b163f483a4c97e5a229635d0f6b23bd5ac Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Nov 2012 14:09:40 +0000 Subject: [PATCH 2009/2357] PCI: Allow pcie_aspm=force even when FADT indicates it is unsupported commit 9e16721498b0c3d3ebfa0b503c63d35c0a4c0642 upstream. Right now using pcie_aspm=force will not enable ASPM if the FADT indicates ASPM is unsupported. However, the semantics of force should probably allow for this, especially as they did before 3c076351c4 ("PCI: Rework ASPM disable code") This patch just skips the clearing of any ASPM setup that the firmware has carried out on this bus if pcie_aspm=force is being used. Reference: http://bugs.launchpad.net/bugs/962038 Signed-off-by: Colin Ian King Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/aspm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index b500840a143..474f22f304e 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -798,6 +798,9 @@ void pcie_clear_aspm(struct pci_bus *bus) { struct pci_dev *child; + if (aspm_force) + return; + /* * Clear any ASPM setup that the firmware has carried out on this bus */ From 5f3e5a32d083008c1ad850375d24fc85a27803e4 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Fri, 11 Jan 2013 10:15:54 +0800 Subject: [PATCH 2010/2357] PCI: pciehp: Use per-slot workqueues to avoid deadlock commit c2be6f93b383c873a4f9d521afa49b1b67d06085 upstream. When we have a hotplug-capable PCIe port with a second hotplug-capable PCIe port below it, removing the device below the upstream port causes a deadlock. The deadlock happens because we use the pciehp_wq workqueue to run pciehp_power_thread(), which uses pciehp_disable_slot() to remove devices below the upstream port. When we remove the downstream PCIe port, we call pciehp_remove(), the pciehp driver's .remove() method. That calls flush_workqueue(pciehp_wq), which deadlocks because the pciehp_power_thread() work item is still running. This patch avoids the deadlock by creating a workqueue for every PCIe port and removing the single shared workqueue. Here's the call path that leads to the deadlock: pciehp_queue_pushbutton_work queue_work(pciehp_wq) # queue pciehp_power_thread ... pciehp_power_thread pciehp_disable_slot remove_board pciehp_unconfigure_device pci_stop_and_remove_bus_device ... pciehp_remove # pciehp driver .remove method pciehp_release_ctrl pcie_cleanup_slot flush_workqueue(pciehp_wq) This is fairly urgent because it can be caused by simply unplugging a Thunderbolt adapter, as reported by Daniel below. [bhelgaas: changelog] Reference: http://lkml.kernel.org/r/CAMVG2ssiRgcTD1bej2tkUUfsWmpL5eNtPcNif9va2-Gzb2u8nQ@mail.gmail.com Reported-and-tested-by: Daniel J Blueman Reviewed-by: Kenji Kaneshige Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp.h | 2 +- drivers/pci/hotplug/pciehp_core.c | 11 ++--------- drivers/pci/hotplug/pciehp_ctrl.c | 8 ++++---- drivers/pci/hotplug/pciehp_hpc.c | 11 ++++++++++- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 4b7cce1de6e..a321b77a5e8 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -44,7 +44,6 @@ extern bool pciehp_poll_mode; extern int pciehp_poll_time; extern bool pciehp_debug; extern bool pciehp_force; -extern struct workqueue_struct *pciehp_wq; #define dbg(format, arg...) \ do { \ @@ -78,6 +77,7 @@ struct slot { struct hotplug_slot *hotplug_slot; struct delayed_work work; /* work for button event */ struct mutex lock; + struct workqueue_struct *wq; }; struct event_info { diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 365c6b96c64..9e39df96956 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -42,7 +42,6 @@ bool pciehp_debug; bool pciehp_poll_mode; int pciehp_poll_time; bool pciehp_force; -struct workqueue_struct *pciehp_wq; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman , Dely Sy " @@ -340,18 +339,13 @@ static int __init pcied_init(void) { int retval = 0; - pciehp_wq = alloc_workqueue("pciehp", 0, 0); - if (!pciehp_wq) - return -ENOMEM; - pciehp_firmware_init(); retval = pcie_port_service_register(&hpdriver_portdrv); dbg("pcie_port_service_register = %d\n", retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - if (retval) { - destroy_workqueue(pciehp_wq); + if (retval) dbg("Failure to register service\n"); - } + return retval; } @@ -359,7 +353,6 @@ static void __exit pcied_cleanup(void) { dbg("unload_pciehpd()\n"); pcie_port_service_unregister(&hpdriver_portdrv); - destroy_workqueue(pciehp_wq); info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); } diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 27f44295a65..38f01867917 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -49,7 +49,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) info->p_slot = p_slot; INIT_WORK(&info->work, interrupt_event_handler); - queue_work(pciehp_wq, &info->work); + queue_work(p_slot->wq, &info->work); return 0; } @@ -344,7 +344,7 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) kfree(info); goto out; } - queue_work(pciehp_wq, &info->work); + queue_work(p_slot->wq, &info->work); out: mutex_unlock(&p_slot->lock); } @@ -377,7 +377,7 @@ static void handle_button_press_event(struct slot *p_slot) if (ATTN_LED(ctrl)) pciehp_set_attention_status(p_slot, 0); - queue_delayed_work(pciehp_wq, &p_slot->work, 5*HZ); + queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ); break; case BLINKINGOFF_STATE: case BLINKINGON_STATE: @@ -439,7 +439,7 @@ static void handle_surprise_event(struct slot *p_slot) else p_slot->state = POWERON_STATE; - queue_work(pciehp_wq, &info->work); + queue_work(p_slot->wq, &info->work); } static void interrupt_event_handler(struct work_struct *work) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index a960faec102..9dd2c01a2e1 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -874,23 +874,32 @@ static void pcie_shutdown_notification(struct controller *ctrl) static int pcie_init_slot(struct controller *ctrl) { struct slot *slot; + char name[32]; slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) return -ENOMEM; + snprintf(name, sizeof(name), "pciehp-%u", PSN(ctrl)); + slot->wq = alloc_workqueue(name, 0, 0); + if (!slot->wq) + goto abort; + slot->ctrl = ctrl; mutex_init(&slot->lock); INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); ctrl->slot = slot; return 0; +abort: + kfree(slot); + return -ENOMEM; } static void pcie_cleanup_slot(struct controller *ctrl) { struct slot *slot = ctrl->slot; cancel_delayed_work(&slot->work); - flush_workqueue(pciehp_wq); + destroy_workqueue(slot->wq); kfree(slot); } From 1dbcda3ab27031e2b744b1f8ba48370304340519 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 11 Jan 2013 12:07:22 -0700 Subject: [PATCH 2011/2357] PCI: shpchp: Handle push button event asynchronously commit d347e75847c1fb299c97736638f45e6ea39702d4 upstream. Use non-ordered workqueue for attention button events. Attention button events on each slot can be handled asynchronously. So we should use non-ordered workqueue. This patch also removes ordered workqueue in shpchp as a result. 486b10b9f4 ("PCI: pciehp: Handle push button event asynchronously") made the same change to pciehp. I split this out from a patch by Yijing Wang so we fix one thing at a time and to make the shpchp history correspond more closely with the pciehp history. Signed-off-by: Bjorn Helgaas CC: Kenji Kaneshige Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 1 - drivers/pci/hotplug/shpchp_core.c | 10 ---------- drivers/pci/hotplug/shpchp_ctrl.c | 2 +- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index ca64932e658..1b69d955a31 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -47,7 +47,6 @@ extern bool shpchp_poll_mode; extern int shpchp_poll_time; extern bool shpchp_debug; extern struct workqueue_struct *shpchp_wq; -extern struct workqueue_struct *shpchp_ordered_wq; #define dbg(format, arg...) \ do { \ diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 7414fd9ad1d..5f1f0d93dc1 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -40,7 +40,6 @@ bool shpchp_debug; bool shpchp_poll_mode; int shpchp_poll_time; struct workqueue_struct *shpchp_wq; -struct workqueue_struct *shpchp_ordered_wq; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman , Dely Sy " @@ -175,7 +174,6 @@ void cleanup_slots(struct controller *ctrl) list_del(&slot->slot_list); cancel_delayed_work(&slot->work); flush_workqueue(shpchp_wq); - flush_workqueue(shpchp_ordered_wq); pci_hp_deregister(slot->hotplug_slot); } } @@ -364,17 +362,10 @@ static int __init shpcd_init(void) if (!shpchp_wq) return -ENOMEM; - shpchp_ordered_wq = alloc_ordered_workqueue("shpchp_ordered", 0); - if (!shpchp_ordered_wq) { - destroy_workqueue(shpchp_wq); - return -ENOMEM; - } - retval = pci_register_driver(&shpc_driver); dbg("%s: pci_register_driver = %d\n", __func__, retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); if (retval) { - destroy_workqueue(shpchp_ordered_wq); destroy_workqueue(shpchp_wq); } return retval; @@ -384,7 +375,6 @@ static void __exit shpcd_cleanup(void) { dbg("unload_shpchpd()\n"); pci_unregister_driver(&shpc_driver); - destroy_workqueue(shpchp_ordered_wq); destroy_workqueue(shpchp_wq); info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); } diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index b00b09bdd38..bba5b3e0bf8 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -456,7 +456,7 @@ void shpchp_queue_pushbutton_work(struct work_struct *work) kfree(info); goto out; } - queue_work(shpchp_ordered_wq, &info->work); + queue_work(shpchp_wq, &info->work); out: mutex_unlock(&p_slot->lock); } From a94af21f3f1e333efd205a8bfd9a51aaec505d0e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 22 Jan 2013 11:37:35 -0500 Subject: [PATCH 2012/2357] USB: UHCI: fix IRQ race during initialization commit 0f815a0a700bc10547449bde6c106051a035a1b9 upstream. This patch (as1644) fixes a race that occurs during startup in uhci-hcd. If the IRQ line is shared with other devices, it's possible for the handler routine to be called before the data structures are fully initialized. The problem is fixed by adding a check to the IRQ handler routine. If the initialization hasn't finished yet, the routine will return immediately. Signed-off-by: Alan Stern Reported-by: Don Zickus Tested-by: "Huang, Adrian (ISS Linux TW)" Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e4db350602b..3fe069f536b 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -447,6 +447,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd) return IRQ_NONE; uhci_writew(uhci, status, USBSTS); /* Clear it */ + spin_lock(&uhci->lock); + if (unlikely(!uhci->is_initialized)) /* not yet configured */ + goto done; + if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & USBSTS_HSE) dev_err(uhci_dev(uhci), "host system error, " @@ -455,7 +459,6 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd) dev_err(uhci_dev(uhci), "host controller process " "error, something bad happened!\n"); if (status & USBSTS_HCH) { - spin_lock(&uhci->lock); if (uhci->rh_state >= UHCI_RH_RUNNING) { dev_err(uhci_dev(uhci), "host controller halted, " @@ -473,15 +476,15 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd) * pending unlinks */ mod_timer(&hcd->rh_timer, jiffies); } - spin_unlock(&uhci->lock); } } - if (status & USBSTS_RD) + if (status & USBSTS_RD) { + spin_unlock(&uhci->lock); usb_hcd_poll_rh_status(hcd); - else { - spin_lock(&uhci->lock); + } else { uhci_scan_schedule(uhci); + done: spin_unlock(&uhci->lock); } @@ -662,9 +665,9 @@ static int uhci_start(struct usb_hcd *hcd) */ mb(); + spin_lock_irq(&uhci->lock); configure_hc(uhci); uhci->is_initialized = 1; - spin_lock_irq(&uhci->lock); start_rh(uhci); spin_unlock_irq(&uhci->lock); return 0; From 462434eff40df54e9d5d1b5f8f21383fb382805c Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 18 Jan 2013 16:53:56 +0530 Subject: [PATCH 2013/2357] usb: dwc3: gadget: fix ep->maxburst for ep0 commit 6048e4c69d80600baba35856651056860d5d8f5a upstream. dwc3_gadget_set_ep_config expects maxburst as incremented by 1. So, by default initialize ep->maxburst to 1 for ep0. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index cee0c3e8ab3..f62629b029f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1453,6 +1453,7 @@ static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc) if (epnum == 0 || epnum == 1) { dep->endpoint.maxpacket = 512; + dep->endpoint.maxburst = 1; dep->endpoint.ops = &dwc3_gadget_ep0_ops; if (!epnum) dwc->gadget.ep0 = &dep->endpoint; From af22aff300fc5d70db97e1d551a0f2d1408027be Mon Sep 17 00:00:00 2001 From: "Joel D. Diaz" Date: Wed, 10 Oct 2012 10:36:11 +0200 Subject: [PATCH 2014/2357] SCSI: sd: Reshuffle init_sd to avoid crash commit afd5e34b2bb34881d3a789e62486814a49b47faa upstream. scsi_register_driver will register a prep_fn() function, which in turn migh need to use the sd_cdp_pool for DIF. Which hasn't been initialised at this point, leading to a crash. So reshuffle the init_sd() and exit_sd() paths to have the driver registered last. Signed-off-by: Joel D. Diaz Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley Cc: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sd.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a239382b2bd..5b3cadbffcf 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2919,10 +2919,6 @@ static int __init init_sd(void) if (err) goto err_out; - err = scsi_register_driver(&sd_template.gendrv); - if (err) - goto err_out_class; - sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE, 0, 0, NULL); if (!sd_cdb_cache) { @@ -2936,8 +2932,15 @@ static int __init init_sd(void) goto err_out_cache; } + err = scsi_register_driver(&sd_template.gendrv); + if (err) + goto err_out_driver; + return 0; +err_out_driver: + mempool_destroy(sd_cdb_pool); + err_out_cache: kmem_cache_destroy(sd_cdb_cache); @@ -2960,10 +2963,10 @@ static void __exit exit_sd(void) SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); + scsi_unregister_driver(&sd_template.gendrv); mempool_destroy(sd_cdb_pool); kmem_cache_destroy(sd_cdb_cache); - scsi_unregister_driver(&sd_template.gendrv); class_unregister(&sd_disk_class); for (i = 0; i < SD_MAJORS; i++) From 220a0bc2df2b7385d278864fa1f8b47f9c78c8a2 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Thu, 20 Dec 2012 15:05:13 -0800 Subject: [PATCH 2015/2357] drivers/firmware/dmi_scan.c: check dmi version when get system uuid commit f1d8e614d74b09531b9a85e812485340f3df7b1c upstream. As of version 2.6 of the SMBIOS specification, the first 3 fields of the UUID are supposed to be little-endian encoded. Also a minor fix to match variable meaning and mute checkpatch.pl [akpm@linux-foundation.org: tweak code comment] Signed-off-by: Zhenzhong Duan Cc: Feng Jin Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Abdallah Chatila Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/dmi_scan.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index b298158cb92..3714e3c03df 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -16,6 +16,7 @@ */ static char dmi_empty_string[] = " "; +static u16 __initdata dmi_ver; /* * Catch too early calls to dmi_check_system(): */ @@ -161,8 +162,10 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde return; for (i = 0; i < 16 && (is_ff || is_00); i++) { - if(d[i] != 0x00) is_ff = 0; - if(d[i] != 0xFF) is_00 = 0; + if (d[i] != 0x00) + is_00 = 0; + if (d[i] != 0xFF) + is_ff = 0; } if (is_ff || is_00) @@ -172,7 +175,15 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde if (!s) return; - sprintf(s, "%pUB", d); + /* + * As of version 2.6 of the SMBIOS specification, the first 3 fields of + * the UUID are supposed to be little-endian encoded. The specification + * says that this is the defacto standard. + */ + if (dmi_ver >= 0x0206) + sprintf(s, "%pUL", d); + else + sprintf(s, "%pUB", d); dmi_ident[slot] = s; } @@ -414,6 +425,7 @@ static int __init dmi_present(const char __iomem *p) * DMI version 0.0 means that the real version is taken from * the SMBIOS version, which we don't know at this point. */ + dmi_ver = (buf[14] & 0xf0) << 4 | (buf[14] & 0x0f); if (buf[14] != 0) printk(KERN_INFO "DMI %d.%d present.\n", buf[14] >> 4, buf[14] & 0xF); From b88532f7efaff806193edbbe826ef0d0f8ac1063 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Thu, 20 Dec 2012 15:05:14 -0800 Subject: [PATCH 2016/2357] drivers/firmware/dmi_scan.c: fetch dmi version from SMBIOS if it exists commit 9f9c9cbb60576a1518d0bf93fb8e499cffccf377 upstream. The right dmi version is in SMBIOS if it's zero in DMI region This issue was originally found from an oracle bug. One customer noticed system UUID doesn't match between dmidecode & uek2. - HP ProLiant BL460c G6 : # cat /sys/devices/virtual/dmi/id/product_uuid 00000000-0000-4C48-3031-4D5030333531 # dmidecode | grep -i uuid UUID: 00000000-0000-484C-3031-4D5030333531 From SMBIOS 2.6 on, spec use little-endian encoding for UUID other than network byte order. So we need to get dmi version to distinguish. If version is 0.0, the real version is taken from the SMBIOS version. This is part of original kernel comment in code. [akpm@linux-foundation.org: checkpatch fixes] Signed-off-by: Zhenzhong Duan Cc: Feng Jin Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Abdallah Chatila Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/dmi_scan.c | 62 ++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 3714e3c03df..fd3ae6290d7 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -119,12 +119,12 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *, return 0; } -static int __init dmi_checksum(const u8 *buf) +static int __init dmi_checksum(const u8 *buf, u8 len) { u8 sum = 0; int a; - for (a = 0; a < 15; a++) + for (a = 0; a < len; a++) sum += buf[a]; return sum == 0; @@ -415,30 +415,57 @@ static int __init dmi_present(const char __iomem *p) u8 buf[15]; memcpy_fromio(buf, p, 15); - if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { + if (dmi_checksum(buf, 15)) { dmi_num = (buf[13] << 8) | buf[12]; dmi_len = (buf[7] << 8) | buf[6]; dmi_base = (buf[11] << 24) | (buf[10] << 16) | (buf[9] << 8) | buf[8]; - /* - * DMI version 0.0 means that the real version is taken from - * the SMBIOS version, which we don't know at this point. - */ - dmi_ver = (buf[14] & 0xf0) << 4 | (buf[14] & 0x0f); - if (buf[14] != 0) - printk(KERN_INFO "DMI %d.%d present.\n", - buf[14] >> 4, buf[14] & 0xF); - else - printk(KERN_INFO "DMI present.\n"); if (dmi_walk_early(dmi_decode) == 0) { + if (dmi_ver) + pr_info("SMBIOS %d.%d present.\n", + dmi_ver >> 8, dmi_ver & 0xFF); + else { + dmi_ver = (buf[14] & 0xF0) << 4 | + (buf[14] & 0x0F); + pr_info("Legacy DMI %d.%d present.\n", + dmi_ver >> 8, dmi_ver & 0xFF); + } dmi_dump_ids(); return 0; } } + dmi_ver = 0; return 1; } +static int __init smbios_present(const char __iomem *p) +{ + u8 buf[32]; + int offset = 0; + + memcpy_fromio(buf, p, 32); + if ((buf[5] < 32) && dmi_checksum(buf, buf[5])) { + dmi_ver = (buf[6] << 8) + buf[7]; + + /* Some BIOS report weird SMBIOS version, fix that up */ + switch (dmi_ver) { + case 0x021F: + case 0x0221: + pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", + dmi_ver & 0xFF, 3); + dmi_ver = 0x0203; + break; + case 0x0233: + pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6); + dmi_ver = 0x0206; + break; + } + offset = 16; + } + return dmi_present(buf + offset); +} + void __init dmi_scan_machine(void) { char __iomem *p, *q; @@ -456,7 +483,7 @@ void __init dmi_scan_machine(void) if (p == NULL) goto error; - rc = dmi_present(p + 0x10); /* offset of _DMI_ string */ + rc = smbios_present(p); dmi_iounmap(p, 32); if (!rc) { dmi_available = 1; @@ -474,7 +501,12 @@ void __init dmi_scan_machine(void) goto error; for (q = p; q < p + 0x10000; q += 16) { - rc = dmi_present(q); + if (memcmp(q, "_SM_", 4) == 0 && q - p <= 0xFFE0) + rc = smbios_present(q); + else if (memcmp(q, "_DMI_", 5) == 0) + rc = dmi_present(q); + else + continue; if (!rc) { dmi_available = 1; dmi_iounmap(p, 0x10000); From b7cd50fb1dd6527706415bb61461d6f283a23dd4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 4 Sep 2012 16:25:25 +0100 Subject: [PATCH 2017/2357] ahci: Add identifiers for ASM106x devices commit 7b4f6ecacb14f384adc1a5a67ad95eb082c02bd1 upstream. They don't always appear as AHCI class devices but instead as IDE class. Based on an initial patch by Hiroaki Nito Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=42804 Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik Signed-off-by: Abdallah Chatila Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ahci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 5d0fb6b5188..71a4d040f14 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -406,7 +406,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ /* Asmedia */ - { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1061 */ + { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */ + { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */ + { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ + { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ /* Enmotus */ { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, From 115b96e58609cff057d22d0e6118dae093763461 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Jan 2013 17:43:40 +0100 Subject: [PATCH 2018/2357] ALSA: usb-audio: Fix regression by disconnection-race-fix patch [NOTE: the regression below is found only in 3.2-3.4 stable trees, so there is no upstream commit corresponding to this patch] The recent fix for the race at disconnection of usb-audio devices (upstream commit 978520b7) triggers Oops when a device is unplugged while playing on 3.2 and 3.4 kernels. The culprit is that the shutdown flag check was wrongly added around the urb deactivation code snippet. The urb deactivation code has to be performed even after the device disconnected. Otherwise it remains undead and pokes the wild access in the end. The regression fix is simply reverting the shutdown flag check in that code. Reported-and-tested-by: Chris J Arges Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/endpoint.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 24c511491b4..9ab2b3e2222 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -148,10 +148,8 @@ void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force) int i; /* stop urbs (to be sure) */ - if (!subs->stream->chip->shutdown) { - deactivate_urbs(subs, force, 1); - wait_clear_urbs(subs); - } + deactivate_urbs(subs, force, 1); + wait_clear_urbs(subs); for (i = 0; i < MAX_URBS; i++) release_urb_ctx(&subs->dataurb[i]); From 35d620d4a06a739c97f9e4ea53374df8c2c95281 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 14 Dec 2012 23:38:28 +0100 Subject: [PATCH 2019/2357] drm/i915: Implement WaDisableHiZPlanesWhenMSAAEnabled commit 4283908ef7f11a72c3b80dd4cf026f1a86429f82 upstream. Quoting from Bspec, 3D_CHICKEN1, bit 10 This bit needs to be set always to "1", Project: DevSNB " Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter Signed-off-by: Abdallah Chatila Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_display.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 27a296a1415..dde62bf3b1c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -27,6 +27,8 @@ #define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) +#define _MASKED_BIT_ENABLE(a) (((a) << 16) | (a)) + /* * The Bridge device's PCI config space has information about the * fb aperture size and the amount of pre-reserved memory. @@ -433,6 +435,7 @@ * the enables for writing to the corresponding low bit. */ #define _3D_CHICKEN 0x02084 +#define _3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB (1 << 10) #define _3D_CHICKEN2 0x0208c /* Disables pipelining of read flushes past the SF-WIZ interface. * Required on all Ironlake steppings according to the B-Spec, but the diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8e95c943286..3c9b9c57040 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8592,6 +8592,10 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_READ(ILK_DISPLAY_CHICKEN2) | ILK_ELPIN_409_SELECT); + /* WaDisableHiZPlanesWhenMSAAEnabled */ + I915_WRITE(_3D_CHICKEN, + _MASKED_BIT_ENABLE(_3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB)); + I915_WRITE(WM3_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); From b8b02d1a89f6f0598d815476acce249a4b891020 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 16 Jan 2013 23:40:07 +0100 Subject: [PATCH 2020/2357] ACPI / cpuidle: Fix NULL pointer issues when cpuidle is disabled commit b88a634a903d9670aa5f2f785aa890628ce0dece upstream. If cpuidle is disabled, that means that: per_cpu(acpi_cpuidle_device, pr->id) is set to NULL as the acpi_processor_power_init ends up failing at retval = cpuidle_register_driver(&acpi_idle_driver) (in acpi_processor_power_init) and never sets the per_cpu idle device. So when acpi_processor_hotplug on CPU online notification tries to reference said device it crashes: cpu 3 spinlock event irq 62 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: [] acpi_processor_setup_cpuidle_cx+0x3f/0x105 PGD a259b067 PUD ab38b067 PMD 0 Oops: 0002 [#1] SMP odules linked in: dm_multipath dm_mod xen_evtchn iscsi_boot_sysfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi libcrc32c crc32c nouveau mxm_wmi wmi radeon ttm sg sr_mod sd_mod cdrom ata_generic ata_piix libata crc32c_intel scsi_mod atl1c i915 fbcon tileblit font bitblit softcursor drm_kms_helper video xen_blkfront xen_netfront fb_sys_fops sysimgblt sysfillrect syscopyarea xenfs xen_privcmd mperf CPU 1 Pid: 3047, comm: bash Not tainted 3.8.0-rc3upstream-00250-g165c029 #1 MSI MS-7680/H61M-P23 (MS-7680) RIP: e030:[] [] acpi_processor_setup_cpuidle_cx+0x3f/0x105 RSP: e02b:ffff88001742dca8 EFLAGS: 00010202 RAX: 0000000000010be9 RBX: ffff8800a0a61800 RCX: ffff880105380000 RDX: 0000000000000003 RSI: 0000000000000200 RDI: ffff8800a0a61800 RBP: ffff88001742dce8 R08: ffffffff81812360 R09: 0000000000000200 R10: aaaaaaaaaaaaaaaa R11: 0000000000000001 R12: ffff8800a0a61800 R13: 00000000ffffff01 R14: 0000000000000000 R15: ffffffff81a907a0 FS: 00007fd6942f7700(0000) GS:ffff880105280000(0000) knlGS:0000000000000000 CS: e033 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000004 CR3: 00000000a6773000 CR4: 0000000000042660 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process bash (pid: 3047, threadinfo ffff88001742c000, task ffff880017944000) Stack: 0000000000000150 ffff880100f59e00 ffff88001742dcd8 ffff8800a0a61800 0000000000000000 00000000ffffff01 0000000000000000 ffffffff81a907a0 ffff88001742dd18 ffffffff813815b1 ffff88001742dd08 ffffffff810ae336 Call Trace: [] acpi_processor_hotplug+0x7c/0x9f [] ? schedule_delayed_work_on+0x16/0x20 [] acpi_cpu_soft_notify+0x90/0xca [] notifier_call_chain+0x4d/0x70 [] __raw_notifier_call_chain+0x9/0x10 [] __cpu_notify+0x1b/0x30 [] _cpu_up+0x103/0x14b [] cpu_up+0xd9/0xec [] store_online+0x94/0xd0 [] dev_attr_store+0x1b/0x20 [] sysfs_write_file+0xf4/0x170 This patch fixes it. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_idle.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f3decb30223..9d21cc7d440 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1018,6 +1018,9 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr) return -EINVAL; } + if (!dev) + return -EINVAL; + dev->cpu = pr->id; if (max_cstate == 0) From 54980d10c77318729ce2549635e3950fe338ba53 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Sat, 19 Jan 2013 00:28:22 +0100 Subject: [PATCH 2021/2357] ACPI / processor: Get power info before updating the C-states commit f427e5f1cf75bba84cccdac1d8a90552d9ae1065 upstream. acpi_processor_get_power_info() has to be called before acpi_processor_setup_cpuidle_states() to have the latest information available. This fixes the missing C-state information after AC-->DC transition. Signed-off-by: Thomas Schlichter Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_idle.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 9d21cc7d440..6cba4282588 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1208,6 +1208,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) } /* Populate Updated C-state information */ + acpi_processor_get_power_info(pr); acpi_processor_setup_cpuidle_states(pr); /* Enable all cpuidle devices */ From 8f3933a1e549a54b4c1b743b40cfd196c8bf0035 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 25 Oct 2012 10:22:32 -0600 Subject: [PATCH 2022/2357] ioat: Fix DMA memory sync direction correct flag commit ac4989874af56435c308bdde9ad9c837a26f8b23 upstream. ioat does DMA memory sync with DMA_TO_DEVICE direction on a buffer allocated for DMA_FROM_DEVICE dma, resulting in the following warning from dma debug. Fixed the dma_sync_single_for_device() call to use the correct direction. [ 226.288947] WARNING: at lib/dma-debug.c:990 check_sync+0x132/0x550() [ 226.288948] Hardware name: ProLiant DL380p Gen8 [ 226.288951] ioatdma 0000:00:04.0: DMA-API: device driver syncs DMA memory with different direction [device address=0x00000000ffff7000] [size=4096 bytes] [mapped with DMA_FROM_DEVICE] [synced with DMA_TO_DEVICE] [ 226.288953] Modules linked in: iTCO_wdt(+) sb_edac(+) ioatdma(+) microcode serio_raw pcspkr edac_core hpwdt(+) iTCO_vendor_support hpilo(+) dca acpi_power_meter ata_generic pata_acpi sd_mod crc_t10dif ata_piix libata hpsa tg3 netxen_nic(+) sunrpc dm_mirror dm_region_hash dm_log dm_mod [ 226.288967] Pid: 1055, comm: work_for_cpu Tainted: G W 3.3.0-0.20.el7.x86_64 #1 [ 226.288968] Call Trace: [ 226.288974] [] warn_slowpath_common+0x7f/0xc0 [ 226.288977] [] warn_slowpath_fmt+0x46/0x50 [ 226.288980] [] check_sync+0x132/0x550 [ 226.288983] [] debug_dma_sync_single_for_device+0x3f/0x50 [ 226.288988] [] ? wait_for_common+0x72/0x180 [ 226.288995] [] ioat_xor_val_self_test+0x3e5/0x832 [ioatdma] [ 226.288999] [] ? kfree+0x259/0x270 [ 226.289004] [] ioat3_dma_self_test+0x1b/0x20 [ioatdma] [ 226.289008] [] ioat_probe+0x2f8/0x348 [ioatdma] [ 226.289011] [] ioat3_dma_probe+0x1d5/0x2aa [ioatdma] [ 226.289016] [] ioat_pci_probe+0x139/0x17c [ioatdma] [ 226.289020] [] local_pci_probe+0x5c/0xd0 [ 226.289023] [] ? destroy_work_on_stack+0x20/0x20 [ 226.289025] [] do_work_for_cpu+0x18/0x30 [ 226.289029] [] kthread+0xb7/0xc0 [ 226.289033] [] kernel_thread_helper+0x4/0x10 [ 226.289036] [] ? _raw_spin_unlock_irq+0x30/0x50 [ 226.289038] [] ? retint_restore_args+0x13/0x13 [ 226.289041] [] ? kthread_worker_fn+0x1a0/0x1a0 [ 226.289044] [] ? gs_change+0x13/0x13 [ 226.289045] ---[ end trace e1618afc7a606089 ]--- [ 226.289047] Mapped at: [ 226.289048] [] debug_dma_map_page+0x87/0x150 [ 226.289050] [] dma_map_page.constprop.18+0x70/0xb34 [ioatdma] [ 226.289054] [] ioat_xor_val_self_test+0x1d8/0x832 [ioatdma] [ 226.289058] [] ioat3_dma_self_test+0x1b/0x20 [ioatdma] [ 226.289061] [] ioat_probe+0x2f8/0x348 [ioatdma] Signed-off-by: Shuah Khan Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/ioat/dma_v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index f7f1dc62c15..ed0e8b796a9 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -951,7 +951,7 @@ static int __devinit ioat_xor_val_self_test(struct ioatdma_device *device) goto free_resources; } } - dma_sync_single_for_device(dev, dest_dma, PAGE_SIZE, DMA_TO_DEVICE); + dma_sync_single_for_device(dev, dest_dma, PAGE_SIZE, DMA_FROM_DEVICE); /* skip validate if the capability is not present */ if (!dma_has_cap(DMA_XOR_VAL, dma_chan->device->cap_mask)) From 4ab913dd103e474d4ea6b7e88307a738728c4592 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 27 Jan 2013 20:51:45 -0800 Subject: [PATCH 2023/2357] Linux 3.4.28 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f139ce7b942..8ccebbadf36 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 27 +SUBLEVEL = 28 EXTRAVERSION = NAME = Saber-toothed Squirrel From e3b308abd9a496f300b1552d8d09eb7c6b934478 Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 18 Jan 2013 09:32:39 +0100 Subject: [PATCH 2024/2357] can: c_can: fix invalid error codes commit 6ea45886865c1abb01bb861f7f6bdd5d0f398cb3 upstream. Errors in CAN protocol (location) are reported in data[3] of the can frame instead of data[2]. Signed-off-by: Olivier Sobrie Cc: Bhupesh Sharma Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/c_can/c_can.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 86cd532c78f..21a3d77ea7e 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -914,7 +914,7 @@ static int c_can_handle_bus_err(struct net_device *dev, break; case LEC_ACK_ERROR: netdev_dbg(dev, "ack error\n"); - cf->data[2] |= (CAN_ERR_PROT_LOC_ACK | + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK | CAN_ERR_PROT_LOC_ACK_DEL); break; case LEC_BIT1_ERROR: @@ -927,7 +927,7 @@ static int c_can_handle_bus_err(struct net_device *dev, break; case LEC_CRC_ERROR: netdev_dbg(dev, "CRC error\n"); - cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ | + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | CAN_ERR_PROT_LOC_CRC_DEL); break; default: From 1c539392d87f6e89bfbdab14438710826373a31b Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 18 Jan 2013 09:32:40 +0100 Subject: [PATCH 2025/2357] can: ti_hecc: fix invalid error codes commit 71088c4bd9b8f8cbffb0e66f2abc14297e4b2ca8 upstream. Errors in CAN protocol (location) are reported in data[3] of the can frame instead of data[2]. Signed-off-by: Olivier Sobrie Cc: Anant Gole Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/ti_hecc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 5ec27008ab4..19000aa8680 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -746,12 +746,12 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, } if (err_status & HECC_CANES_CRCE) { hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE); - cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ | + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | CAN_ERR_PROT_LOC_CRC_DEL; } if (err_status & HECC_CANES_ACKE) { hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE); - cf->data[2] |= CAN_ERR_PROT_LOC_ACK | + cf->data[3] |= CAN_ERR_PROT_LOC_ACK | CAN_ERR_PROT_LOC_ACK_DEL; } } From 83829ab554f01ee5fcef4880b0a90cc14350b936 Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 18 Jan 2013 09:32:41 +0100 Subject: [PATCH 2026/2357] can: pch_can: fix invalid error codes commit ee50e135aeb048b90fab662e661c58b67341830b upstream. Errors in CAN protocol (location) are reported in data[3] of the can frame instead of data[2]. Signed-off-by: Olivier Sobrie Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/pch_can.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index 2bb215e00eb..ab13a57ae3b 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c @@ -560,7 +560,7 @@ static void pch_can_error(struct net_device *ndev, u32 status) stats->rx_errors++; break; case PCH_CRC_ERR: - cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ | + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | CAN_ERR_PROT_LOC_CRC_DEL; priv->can.can_stats.bus_error++; stats->rx_errors++; From bad73b66c3862db14a5362113df7680f4ef84200 Mon Sep 17 00:00:00 2001 From: Cong Ding Date: Tue, 22 Jan 2013 19:20:58 -0500 Subject: [PATCH 2027/2357] fs/cifs/cifs_dfs_ref.c: fix potential memory leakage commit 10b8c7dff5d3633b69e77f57d404dab54ead3787 upstream. When it goes to error through line 144, the memory allocated to *devname is not freed, and the caller doesn't free it either in line 250. So we free the memroy of *devname in function cifs_compose_mount_options() when it goes to error. Signed-off-by: Cong Ding Reviewed-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifs_dfs_ref.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 6873bb634a9..22631445a4a 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -226,6 +226,8 @@ char *cifs_compose_mount_options(const char *sb_mountdata, compose_mount_options_err: kfree(mountdata); mountdata = ERR_PTR(rc); + kfree(*devname); + *devname = NULL; goto compose_mount_options_out; } From 96b3ce5cd4186b58085c03412416e9d540e90183 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 19 Jan 2013 11:05:57 +0000 Subject: [PATCH 2028/2357] ARM: DMA: Fix struct page iterator in dma_cache_maint() to work with sparsemem commit 15653371c67c3fbe359ae37b720639dd4c7b42c5 upstream. Subhash Jadavani reported this partial backtrace: Now consider this call stack from MMC block driver (this is on the ARMv7 based board): [] (v7_dma_inv_range+0x30/0x48) from [] (dma_cache_maint_page+0x1c4/0x24c) [] (dma_cache_maint_page+0x1c4/0x24c) from [] (___dma_page_cpu_to_dev+0x14/0x1c) [] (___dma_page_cpu_to_dev+0x14/0x1c) from [] (dma_map_sg+0x3c/0x114) This is caused by incrementing the struct page pointer, and running off the end of the sparsemem page array. Fix this by incrementing by pfn instead, and convert the pfn to a struct page. Suggested-by: James Bottomley Tested-by: Subhash Jadavani Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/mm/dma-mapping.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index db23ae4aaaa..a3e4adf2c28 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -503,25 +503,27 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir, void (*op)(const void *, size_t, int)) { + unsigned long pfn; + size_t left = size; + + pfn = page_to_pfn(page) + offset / PAGE_SIZE; + offset %= PAGE_SIZE; + /* * A single sg entry may refer to multiple physically contiguous * pages. But we still need to process highmem pages individually. * If highmem is not configured then the bulk of this loop gets * optimized out. */ - size_t left = size; do { size_t len = left; void *vaddr; + page = pfn_to_page(pfn); + if (PageHighMem(page)) { - if (len + offset > PAGE_SIZE) { - if (offset >= PAGE_SIZE) { - page += offset / PAGE_SIZE; - offset %= PAGE_SIZE; - } + if (len + offset > PAGE_SIZE) len = PAGE_SIZE - offset; - } vaddr = kmap_high_get(page); if (vaddr) { vaddr += offset; @@ -538,7 +540,7 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, op(vaddr, len, dir); } offset = 0; - page++; + pfn++; left -= len; } while (left); } From 399f41521ecb4dfb55bf86210864ce7c60157d8a Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Sun, 23 Dec 2012 18:07:49 +0000 Subject: [PATCH 2029/2357] ARM: at91: rm9200: remake the BGA as default version commit 36224d0fe0f34cdde66a381708853ebadeac799c upstream. Make BGA as the default version as we are supposed to just have to specify when we use the PQFP version. Issue was existing since commit: 3e90772 (ARM: at91: fix at91rm9200 soc subtype handling). Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-at91/setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index 582142e049a..55293a78cfa 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -104,6 +104,8 @@ static void __init soc_detect(u32 dbgu_base) switch (socid) { case ARCH_ID_AT91RM9200: at91_soc_initdata.type = AT91_SOC_RM9200; + if (at91_soc_initdata.subtype == AT91_SOC_SUBTYPE_NONE) + at91_soc_initdata.subtype = AT91_SOC_RM9200_BGA; at91_boot_soc = at91rm9200_soc; break; From 112ae50d212e65816b9de8ea0010a430569d2fc6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 14 Jan 2013 19:50:42 +0100 Subject: [PATCH 2030/2357] ARM: 7627/1: Predicate preempt logic on PREEMP_COUNT not PREEMPT alone commit 568dca15aa2a0f4ddee255894ec393a159f13147 upstream. Patrik Kluba reports that the preempt count becomes invalid due to the preempt_enable() call being unbalanced with a preempt_disable() call in the vfp assembly routines. This happens because preempt_enable() and preempt_disable() update preempt counts under PREEMPT_COUNT=y but the vfp assembly routines do so under PREEMPT=y. In a configuration where PREEMPT=n and DEBUG_ATOMIC_SLEEP=y, PREEMPT_COUNT=y and so the preempt_enable() call in VFP_bounce() keeps subtracting from the preempt count until it goes negative. Fix this by always using PREEMPT_COUNT to decided when to update preempt counts in the ARM assembly code. Signed-off-by: Stephen Boyd Reported-by: Patrik Kluba Tested-by: Patrik Kluba Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/vfp/entry.S | 6 +++--- arch/arm/vfp/vfphw.S | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index cc926c98598..323ce1a62bb 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -22,7 +22,7 @@ @ IRQs disabled. @ ENTRY(do_vfp) -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT_COUNT ldr r4, [r10, #TI_PREEMPT] @ get preempt count add r11, r4, #1 @ increment it str r11, [r10, #TI_PREEMPT] @@ -35,7 +35,7 @@ ENTRY(do_vfp) ENDPROC(do_vfp) ENTRY(vfp_null_entry) -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT_COUNT get_thread_info r10 ldr r4, [r10, #TI_PREEMPT] @ get preempt count sub r11, r4, #1 @ decrement it @@ -53,7 +53,7 @@ ENDPROC(vfp_null_entry) __INIT ENTRY(vfp_testing_entry) -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT_COUNT get_thread_info r10 ldr r4, [r10, #TI_PREEMPT] @ get preempt count sub r11, r4, #1 @ decrement it diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 3a0efaad609..6ff903e5019 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -167,7 +167,7 @@ vfp_hw_state_valid: @ else it's one 32-bit instruction, so @ always subtract 4 from the following @ instruction address. -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT_COUNT get_thread_info r10 ldr r4, [r10, #TI_PREEMPT] @ get preempt count sub r11, r4, #1 @ decrement it @@ -191,7 +191,7 @@ look_for_VFP_exceptions: @ not recognised by VFP DBGSTR "not VFP" -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT_COUNT get_thread_info r10 ldr r4, [r10, #TI_PREEMPT] @ get preempt count sub r11, r4, #1 @ decrement it From dec3b6a0b8a4b1503617c45b351aedbd63adab58 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 11 Dec 2012 08:51:19 +0100 Subject: [PATCH 2031/2357] Bluetooth: Fix sending HCI commands after reset commit dbccd791a3fbbdac12c33834b73beff3984988e9 upstream. After sending reset command wait for its command complete event before sending next command. Some chips sends CC event for command received before reset if reset was send before chip replied with CC. This is also required by specification that host shall not send additional HCI commands before receiving CC for reset. < HCI Command: Reset (0x03|0x0003) plen 0 [hci0] 18.404612 > HCI Event: Command Complete (0x0e) plen 4 [hci0] 18.405850 Write Extended Inquiry Response (0x03|0x0052) ncmd 1 Status: Success (0x00) < HCI Command: Read Local Supported Features (0x04|0x0003) plen 0 [hci0] 18.406079 > HCI Event: Command Complete (0x0e) plen 4 [hci0] 18.407864 Reset (0x03|0x0003) ncmd 1 Status: Success (0x00) < HCI Command: Read Local Supported Features (0x04|0x0003) plen 0 [hci0] 18.408062 > HCI Event: Command Complete (0x0e) plen 12 [hci0] 18.408835 Signed-off-by: Szymon Janc Acked-by: Johan Hedberg Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 25edda03645..ef45e10c44f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2366,7 +2366,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk if (ev->opcode != HCI_OP_NOP) del_timer(&hdev->cmd_timer); - if (ev->ncmd) { + if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) queue_work(hdev->workqueue, &hdev->cmd_work); From d4ffc500fcf28db4bc6e358e318b37bb884e421b Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 21 Jan 2013 15:50:03 -0500 Subject: [PATCH 2032/2357] drm/radeon: fix cursor corruption on DCE6 and newer commit e521a29014794d139cca46396d1af8faf1295a26 upstream. Aruba and newer gpu does not need the avivo cursor work around, quite the opposite this work around lead to corruption. agd5f: check DCE6 rather than ARUBA since the issue is DCE version specific rather than family specific. Signed-off-by: Jerome Glisse Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_cursor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 711e95ad39b..8fb6f41bd1f 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -238,7 +238,8 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, y = 0; } - if (ASIC_IS_AVIVO(rdev)) { + /* fixed on DCE6 and newer */ + if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) { int i = 0; struct drm_crtc *crtc_p; From 592306fd6bde5d73b2586ab163b4c78953d182ac Mon Sep 17 00:00:00 2001 From: xueminsu Date: Tue, 22 Jan 2013 22:16:53 +0800 Subject: [PATCH 2033/2357] radeon_display: Use pointer return error codes commit b2f4b03f8a378cd626d2ea67d19e7470c050a098 upstream. drm_mode_addfb() expects fb_create return error code instead of NULL. Signed-off-by: xueminsu Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 173b97b2819..1f50727d210 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1136,7 +1136,7 @@ radeon_user_framebuffer_create(struct drm_device *dev, if (ret) { kfree(radeon_fb); drm_gem_object_unreference_unlocked(obj); - return NULL; + return ERR_PTR(ret); } return &radeon_fb->base; From 6f92e64724f5ffbfd114b33ece087b00c7400ce5 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 24 Jan 2013 13:17:53 -0600 Subject: [PATCH 2034/2357] IOMMU, AMD Family15h Model10-1Fh erratum 746 Workaround commit 318fe782539c4150d1b8e4e6c9dc3a896512cb8a upstream. The IOMMU may stop processing page translations due to a perceived lack of credits for writing upstream peripheral page service request (PPR) or event logs. If the L2B miscellaneous clock gating feature is enabled the IOMMU does not properly register credits after the log request has completed, leading to a potential system hang. BIOSes are supposed to disable L2B micellaneous clock gating by setting L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b. This patch corrects that for those which do not enable this workaround. Signed-off-by: Suravee Suthikulpanit Acked-by: Borislav Petkov Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu_init.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index c04ddca7f12..ef0ae93500f 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1001,6 +1001,38 @@ static void __init free_iommu_all(void) } } +/* + * Family15h Model 10h-1fh erratum 746 (IOMMU Logging May Stall Translations) + * Workaround: + * BIOS should disable L2B micellaneous clock gating by setting + * L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b + */ +static void __init amd_iommu_erratum_746_workaround(struct amd_iommu *iommu) +{ + u32 value; + + if ((boot_cpu_data.x86 != 0x15) || + (boot_cpu_data.x86_model < 0x10) || + (boot_cpu_data.x86_model > 0x1f)) + return; + + pci_write_config_dword(iommu->dev, 0xf0, 0x90); + pci_read_config_dword(iommu->dev, 0xf4, &value); + + if (value & BIT(2)) + return; + + /* Select NB indirect register 0x90 and enable writing */ + pci_write_config_dword(iommu->dev, 0xf0, 0x90 | (1 << 8)); + + pci_write_config_dword(iommu->dev, 0xf4, value | 0x4); + pr_info("AMD-Vi: Applying erratum 746 workaround for IOMMU at %s\n", + dev_name(&iommu->dev->dev)); + + /* Clear the enable writing bit */ + pci_write_config_dword(iommu->dev, 0xf0, 0x90); +} + /* * This function clues the initialization function for one IOMMU * together and also allocates the command buffer and programs the @@ -1062,6 +1094,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) amd_iommu_np_cache = true; + amd_iommu_erratum_746_workaround(iommu); + return pci_enable_device(iommu->dev); } From dc28035ca92964adadd7cc1ea286a32b4f194257 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 23 Jan 2013 13:56:18 +0100 Subject: [PATCH 2035/2357] xfs: Fix possible use-after-free with AIO commit 4b05d09c18d9aa62d2e7fb4b057f54e5a38963f5 upstream. Running AIO is pinning inode in memory using file reference. Once AIO is completed using aio_complete(), file reference is put and inode can be freed from memory. So we have to be sure that calling aio_complete() is the last thing we do with the inode. Signed-off-by: Jan Kara CC: xfs@oss.sgi.com CC: Ben Myers Reviewed-by: Ben Myers Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_aops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 0dbb9e70fe2..7a978c7be84 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -89,11 +89,11 @@ xfs_destroy_ioend( } if (ioend->io_iocb) { + inode_dio_done(ioend->io_inode); if (ioend->io_isasync) { aio_complete(ioend->io_iocb, ioend->io_error ? ioend->io_error : ioend->io_result, 0); } - inode_dio_done(ioend->io_inode); } mempool_free(ioend, xfs_ioend_pool); From 68171ce1042bad67397b0408ea04c8f386adee73 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 21 Jan 2013 21:04:10 -0800 Subject: [PATCH 2036/2357] mwifiex: fix typo in PCIe adapter NULL check commit 83f0c6d1f502bd75bb4a9e31e8d64e59c6894ad1 upstream. Add missing "!" as we are supposed to check "!card->adapter" in PCIe suspend handler. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Reviewed-by: Sergey V. Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mwifiex/pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 5867facd415..6ca3d8a3e0e 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -158,7 +158,7 @@ static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state) if (pdev) { card = (struct pcie_service_card *) pci_get_drvdata(pdev); - if (!card || card->adapter) { + if (!card || !card->adapter) { pr_err("Card or adapter structure is not valid\n"); return 0; } From 8c69e052e2330794fce15b7f299c6c797aed8b7d Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 16 Jan 2013 11:45:15 +0100 Subject: [PATCH 2037/2357] iwlegacy: fix IBSS cleanup commit fa4cffcba9e13798ed7c6b8526b91b1631ecb53e upstream. We do not correctly change interface type when switching from IBSS mode to STA mode, that results in microcode errors. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=886946 Reported-by: Jaroslav Skarvada Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlegacy/common.c | 35 +++++++++++--------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 4bc27112cbe..2ab6b968c5f 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -3957,17 +3957,21 @@ il_connection_init_rx_config(struct il_priv *il) memset(&il->staging, 0, sizeof(il->staging)); - if (!il->vif) { + switch (il->iw_mode) { + case NL80211_IFTYPE_UNSPECIFIED: il->staging.dev_type = RXON_DEV_TYPE_ESS; - } else if (il->vif->type == NL80211_IFTYPE_STATION) { + break; + case NL80211_IFTYPE_STATION: il->staging.dev_type = RXON_DEV_TYPE_ESS; il->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; - } else if (il->vif->type == NL80211_IFTYPE_ADHOC) { + break; + case NL80211_IFTYPE_ADHOC: il->staging.dev_type = RXON_DEV_TYPE_IBSS; il->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; il->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; - } else { + break; + default: IL_ERR("Unsupported interface type %d\n", il->vif->type); return; } @@ -4550,8 +4554,7 @@ il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) EXPORT_SYMBOL(il_mac_add_interface); static void -il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif, - bool mode_change) +il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif) { lockdep_assert_held(&il->mutex); @@ -4560,9 +4563,7 @@ il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif, il_force_scan_end(il); } - if (!mode_change) - il_set_mode(il); - + il_set_mode(il); } void @@ -4575,8 +4576,8 @@ il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) WARN_ON(il->vif != vif); il->vif = NULL; - - il_teardown_interface(il, vif, false); + il->iw_mode = NL80211_IFTYPE_UNSPECIFIED; + il_teardown_interface(il, vif); memset(il->bssid, 0, ETH_ALEN); D_MAC80211("leave\n"); @@ -4685,18 +4686,10 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } /* success */ - il_teardown_interface(il, vif, true); vif->type = newtype; vif->p2p = false; - err = il_set_mode(il); - WARN_ON(err); - /* - * We've switched internally, but submitting to the - * device may have failed for some reason. Mask this - * error, because otherwise mac80211 will not switch - * (and set the interface type back) and we'll be - * out of sync with it. - */ + il->iw_mode = newtype; + il_teardown_interface(il, vif); err = 0; out: From df2f07099760702c9f3664230263b6be3142b7d7 Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Thu, 10 Jan 2013 11:20:48 +0100 Subject: [PATCH 2038/2357] brcmsmac: increase timer reference count for new timers only commit a1fe52801a992e590cdaee2fb47a94bac9b5da90 upstream. On hardware reintialization reference count of already existing timers would be increased again. This leads to problems on module unloading. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Reviewed-by: Arend van Spriel Signed-off-by: Piotr Haber Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 569ab8abd2a..27f37c7379d 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1400,9 +1400,10 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic) #endif t->ms = ms; t->periodic = (bool) periodic; - t->set = true; - - atomic_inc(&t->wl->callbacks); + if (!t->set) { + t->set = true; + atomic_inc(&t->wl->callbacks); + } ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms)); } From e4fcbe5297a8c6e512c68a77c660a8cdd7d315e4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Jan 2013 14:34:25 +0100 Subject: [PATCH 2039/2357] mac80211: fix FT roaming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1626e0fa740dec8665a973cf2349405cdfeb46dc upstream. During FT roaming, wpa_supplicant attempts to set the key before association. This used to be rejected, but as a side effect of my commit 66e67e418908442389d3a9e ("mac80211: redesign auth/assoc") the key was accepted causing hardware crypto to not be used for it as the station isn't added to the driver yet. It would be possible to accept the key and then add it to the driver when the station has been added. However, this may run into issues with drivers using the state- based station adding if they accept the key only after association like it used to be. For now, revert to the behaviour from before the auth and assoc change. Reported-by: Cédric Debarge Tested-by: Cédric Debarge Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/cfg.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 677d6592978..94433486959 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -151,7 +151,17 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, sta = sta_info_get(sdata, mac_addr); else sta = sta_info_get_bss(sdata, mac_addr); - if (!sta) { + /* + * The ASSOC test makes sure the driver is ready to + * receive the key. When wpa_supplicant has roamed + * using FT, it attempts to set the key before + * association has completed, this rejects that attempt + * so it will set the key again after assocation. + * + * TODO: accept the key if we have a station entry and + * add it to the device after the station. + */ + if (!sta || !test_sta_flag(sta, WLAN_STA_ASSOC)) { ieee80211_key_free(sdata->local, key); err = -ENOENT; goto out_unlock; From 657273897cd2f9b7964ac704c6e58fbe8295c64d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 9 Jan 2013 16:07:48 +0530 Subject: [PATCH 2040/2357] ath9k_htc: Fix memory leak commit 0981c3b24ef664f5611008a6e6d0622fac6d892b upstream. SKBs that are allocated in the HTC layer do not have callbacks registered and hence ended up not being freed, Fix this by freeing them properly in the TX completion routine. Reported-by: Larry Finger Signed-off-by: Sujith Manoharan Tested-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/htc_hst.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index c25226a32dd..ec86d981abc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -342,6 +342,8 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv, skb, htc_hdr->endpoint_id, txok); + } else { + kfree_skb(skb); } } From fb259496950eaa9fa104ec6e570595ed21d66b07 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 9 Jan 2013 16:16:52 +0100 Subject: [PATCH 2041/2357] ath9k: do not link receive buffers during flush commit a3dc48e82bb146ef11cf75676c8410c1df29b0c4 upstream. On AR9300 the rx FIFO needs to be empty during reset to ensure that no further DMA activity is generated, otherwise it might lead to memory corruption issues. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/recv.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 90b8527154e..039bac7e0c6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -778,6 +778,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, return NULL; } + list_del(&bf->list); if (!bf->bf_mpdu) return bf; @@ -1966,14 +1967,15 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) sc->rx.frag = NULL; } requeue: + list_add_tail(&bf->list, &sc->rx.rxbuf); + if (flush) + continue; + if (edma) { - list_add_tail(&bf->list, &sc->rx.rxbuf); ath_rx_edma_buf_link(sc, qtype); } else { - list_move_tail(&bf->list, &sc->rx.rxbuf); ath_rx_buf_link(sc, bf); - if (!flush) - ath9k_hw_rxena(ah); + ath9k_hw_rxena(ah); } } while (1); From 82f9455a53ee8c02320c6a3b3c74975b804b9df0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 9 Jan 2013 16:16:53 +0100 Subject: [PATCH 2042/2357] ath9k: fix double-free bug on beacon generate failure commit 1adb2e2b5f85023d17eb4f95386a57029df27c88 upstream. When the next beacon is sent, the ath_buf from the previous run is reused. If getting a new beacon from mac80211 fails, bf->bf_mpdu is not reset, yet the skb is freed, leading to a double-free on the next beacon tx attempt, resulting in a system crash. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/beacon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 5eb53c98d75..2e4243fcadc 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -154,6 +154,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); bf->bf_buf_addr = 0; + bf->bf_mpdu = NULL; } /* Get a new beacon from mac80211 */ From d065f12437292348564406a267c35857fe65bafc Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 29 Nov 2012 17:04:23 +0100 Subject: [PATCH 2043/2357] ALSA: usb-audio: fix invalid length check for RME and other UAC 2 devices commit d56268fb108c7c21e19933588ca4d94652585183 upstream. Commit 23caaf19b11e (ALSA: usb-mixer: Add support for Audio Class v2.0) forgot to adjust the length check for UAC 2.0 feature unit descriptors. This would make the code abort on encountering a feature unit without per-channel controls, and thus prevented the driver to work with any device having such a unit, such as the RME Babyface or Fireface UCX. Reported-by: Florian Hanisch Tested-by: Matthew Robbetts Tested-by: Michael Beer Cc: Daniel Mack Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/mixer.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 29ae209344d..15b0712b9ad 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1239,16 +1239,23 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void } channels = (hdr->bLength - 7) / csize - 1; bmaControls = hdr->bmaControls; + if (hdr->bLength < 7 + csize) { + snd_printk(KERN_ERR "usbaudio: unit %u: " + "invalid UAC_FEATURE_UNIT descriptor\n", + unitid); + return -EINVAL; + } } else { struct uac2_feature_unit_descriptor *ftr = _ftr; csize = 4; channels = (hdr->bLength - 6) / 4 - 1; bmaControls = ftr->bmaControls; - } - - if (hdr->bLength < 7 || !csize || hdr->bLength < 7 + csize) { - snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid); - return -EINVAL; + if (hdr->bLength < 6 + csize) { + snd_printk(KERN_ERR "usbaudio: unit %u: " + "invalid UAC_FEATURE_UNIT descriptor\n", + unitid); + return -EINVAL; + } } /* parse the source unit */ From 4184c93021628f144a422ce1c280b3dc69b6ed12 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 23 Jan 2013 18:16:24 +0100 Subject: [PATCH 2044/2357] ALSA: hda - Add a fixup for Packard-Bell desktop with ALC880 commit 0712eea349d8e2b6d0e44b94a752d999319027fb upstream. A Packard-Bell desktop machine gives no proper pin configuration from BIOS. It's almost equivalent with the 6stack+fp standard config, just take the existing fixup. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=901846 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7f2a10901ae..f7f877626d8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4741,6 +4741,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB), SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), + SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), From ecf7defcc50e33fd80e8ba34f140360606530d6b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 26 Jan 2013 10:49:24 +0300 Subject: [PATCH 2045/2357] EDAC: Test correct variable in ->store function commit 8024c4c0b1057d1cd811fc9c3f88f81de9729fcd upstream. We're testing for ->show but calling ->store(). Signed-off-by: Dan Carpenter Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman --- drivers/edac/edac_pci_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 97f5064e399..686ac03de13 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -257,7 +257,7 @@ static ssize_t edac_pci_dev_store(struct kobject *kobj, struct edac_pci_dev_attribute *edac_pci_dev; edac_pci_dev = (struct edac_pci_dev_attribute *)attr; - if (edac_pci_dev->show) + if (edac_pci_dev->store) return edac_pci_dev->store(edac_pci_dev->value, buffer, count); return -EIO; } From 99141c253f45822edfab14fa34bfa47f56d803ad Mon Sep 17 00:00:00 2001 From: Chris Rattray Date: Tue, 15 Jan 2013 13:22:36 +0000 Subject: [PATCH 2046/2357] ASoC: wm2200: correct mixer values and text commit a80cc734282805e15b5e023751a4d02f7ffbcc91 upstream. Signed-off-by: Chris Rattray Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm2200.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 86b84a18ba2..8e0cf146a68 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -897,8 +897,6 @@ static const char *wm2200_mixer_texts[] = { "EQR", "LHPF1", "LHPF2", - "LHPF3", - "LHPF4", "DSP1.1", "DSP1.2", "DSP1.3", @@ -931,7 +929,6 @@ static int wm2200_mixer_values[] = { 0x25, 0x50, /* EQ */ 0x51, - 0x52, 0x60, /* LHPF1 */ 0x61, /* LHPF2 */ 0x68, /* DSP1 */ From 5a6d60801c24f6966cf73894258134778ddccde5 Mon Sep 17 00:00:00 2001 From: Anderson Lizardo Date: Sun, 6 Jan 2013 18:28:53 -0400 Subject: [PATCH 2047/2357] Bluetooth: Fix incorrect strncpy() in hidp_setup_hid() commit 0a9ab9bdb3e891762553f667066190c1d22ad62b upstream. The length parameter should be sizeof(req->name) - 1 because there is no guarantee that string provided by userspace will contain the trailing '\0'. Can be easily reproduced by manually setting req->name to 128 non-zero bytes prior to ioctl(HIDPCONNADD) and checking the device name setup on input subsystem: $ cat /sys/devices/pnp0/00\:04/tty/ttyS0/hci0/hci0\:1/input8/name AAAAAA[...]AAAAAAAAf0:af:f0:af:f0:af ("f0:af:f0:af:f0:af" is the device bluetooth address, taken from "phys" field in struct hid_device due to overflow.) Signed-off-by: Anderson Lizardo Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hidp/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index d478be11d56..7a0d9840866 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -949,7 +949,7 @@ static int hidp_setup_hid(struct hidp_session *session, hid->version = req->version; hid->country = req->country; - strncpy(hid->name, req->name, 128); + strncpy(hid->name, req->name, sizeof(req->name) - 1); strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64); strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64); From 4b56ffb0c322d955c7fe6bae60711479b7ef6519 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 20 Jan 2013 23:50:13 +0100 Subject: [PATCH 2048/2357] iommu/intel: disable DMAR for g4x integrated gfx commit 9452618e7462181ed9755236803b6719298a13ce upstream. DMAR support on g4x/gm45 integrated gpus seems to be totally busted. So don't bother, but instead disable it by default to allow distros to unconditionally enable DMAR support. v2: Actually wire up the right quirk entry, spotted by Adam Jackson. Note that according to intel marketing materials only g45 and gm45 support DMAR/VT-d. So we have reports for all relevant gen4 pci ids by now. Still, keep all the other gen4 ids in the quirk table in case the marketing stuff confused me again, which would not be the first time. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=51921 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=538163 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=538163 Cc: Adam Jackson Cc: David Woodhouse Cc: stable@vger.kernel.org Acked-By: David Woodhouse Tested-by: stathis Tested-by: Mihai Moldovan Signed-off-by: Daniel Vetter Signed-off-by: Mihai Moldovan Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-iommu.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index be6660696c9..5d71873c6f6 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4193,6 +4193,21 @@ static struct iommu_ops intel_iommu_ops = { .pgsize_bitmap = INTEL_IOMMU_PGSIZES, }; +static void __devinit quirk_iommu_g4x_gfx(struct pci_dev *dev) +{ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n"); + dmar_map_gfx = 0; +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx); + static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) { /* @@ -4201,12 +4216,6 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) */ printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n"); rwbf_quirk = 1; - - /* https://bugzilla.redhat.com/show_bug.cgi?id=538163 */ - if (dev->revision == 0x07) { - printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n"); - dmar_map_gfx = 0; - } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf); From 5a099d740ffdff7b217f23d7d871c4fb0c24a24b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 20 Dec 2012 14:41:18 +0100 Subject: [PATCH 2049/2357] mac80211: synchronize scan off/on-channel and PS states commit aacde9ee45225f7e0b90960f479aef83c66bfdc0 upstream. Since: commit b23b025fe246f3acc2988eb6d400df34c27cb8ae Author: Ben Greear Date: Fri Feb 4 11:54:17 2011 -0800 mac80211: Optimize scans on current operating channel. we do not disable PS while going back to operational channel (on ieee80211_scan_state_suspend) and deffer that until scan finish. But since we are allowed to send frames, we can send a frame to AP without PM bit set, so disable PS on AP side. Then when we switch to off-channel (in ieee80211_scan_state_resume) we do not enable PS. Hence we are off-channel with PS disabled, frames are not buffered by AP. To fix remove offchannel_ps_disable argument and always enable PS when going off-channel and disable it when going on-channel, like it was before. Cc: stable@vger.kernel.org # 2.6.39+ Signed-off-by: Stanislaw Gruszka Tested-by: Seth Forshee Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ieee80211_i.h | 6 ++---- net/mac80211/offchannel.c | 17 ++++++----------- net/mac80211/scan.c | 15 +++++---------- net/mac80211/work.c | 4 ++-- 4 files changed, 15 insertions(+), 27 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f8b5e75be8c..05160dbeaf4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1264,10 +1264,8 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); void ieee80211_sched_scan_stopped_work(struct work_struct *work); /* off-channel helpers */ -void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, - bool offchannel_ps_enable); -void ieee80211_offchannel_return(struct ieee80211_local *local, - bool offchannel_ps_disable); +void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local); +void ieee80211_offchannel_return(struct ieee80211_local *local); void ieee80211_hw_roc_setup(struct ieee80211_local *local); /* interface handling */ diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 935aa4b6dee..c22f0748f4f 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -103,8 +103,7 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) ieee80211_sta_reset_conn_monitor(sdata); } -void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, - bool offchannel_ps_enable) +void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; @@ -129,8 +128,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { netif_tx_stop_all_queues(sdata->dev); - if (offchannel_ps_enable && - (sdata->vif.type == NL80211_IFTYPE_STATION) && + if (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.associated) ieee80211_offchannel_ps_enable(sdata, true); } @@ -138,8 +136,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, mutex_unlock(&local->iflist_mtx); } -void ieee80211_offchannel_return(struct ieee80211_local *local, - bool offchannel_ps_disable) +void ieee80211_offchannel_return(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; @@ -152,11 +149,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, continue; /* Tell AP we're back */ - if (offchannel_ps_disable && - sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.associated) - ieee80211_offchannel_ps_disable(sdata); - } + if (sdata->vif.type == NL80211_IFTYPE_STATION && + sdata->u.mgd.associated) + ieee80211_offchannel_ps_disable(sdata); if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { /* diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e95d494f36e..bcc57f93adc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -329,7 +329,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, if (!was_hw_scan) { ieee80211_configure_filter(local); drv_sw_scan_complete(local); - ieee80211_offchannel_return(local, true); + ieee80211_offchannel_return(local); } ieee80211_recalc_idle(local); @@ -374,7 +374,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; - ieee80211_offchannel_stop_vifs(local, true); + ieee80211_offchannel_stop_vifs(local); ieee80211_configure_filter(local); @@ -629,12 +629,8 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local, local->scan_channel = NULL; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - /* - * Re-enable vifs and beaconing. Leave PS - * in off-channel state..will put that back - * on-channel at the end of scanning. - */ - ieee80211_offchannel_return(local, false); + /* disable PS */ + ieee80211_offchannel_return(local); *next_delay = HZ / 5; /* afterwards, resume scan & go to next channel */ @@ -644,8 +640,7 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local, static void ieee80211_scan_state_resume(struct ieee80211_local *local, unsigned long *next_delay) { - /* PS already is in off-channel mode */ - ieee80211_offchannel_stop_vifs(local, false); + ieee80211_offchannel_stop_vifs(local); if (local->ops->flush) { drv_flush(local, false); diff --git a/net/mac80211/work.c b/net/mac80211/work.c index c6e230efa04..a74f53894d6 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -148,7 +148,7 @@ static void ieee80211_work_work(struct work_struct *work) } if (!started && !local->tmp_channel) { - ieee80211_offchannel_stop_vifs(local, true); + ieee80211_offchannel_stop_vifs(local); local->tmp_channel = wk->chan; local->tmp_channel_type = wk->chan_type; @@ -220,7 +220,7 @@ static void ieee80211_work_work(struct work_struct *work) local->tmp_channel = NULL; ieee80211_hw_config(local, 0); - ieee80211_offchannel_return(local, true); + ieee80211_offchannel_return(local); /* give connection some time to breathe */ run_again(local, jiffies + HZ/2); From 64fdede97a7c38889dd9b9016aac3e2afc23412b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 22 Jan 2013 00:17:06 -0500 Subject: [PATCH 2050/2357] NFS: Don't silently fail setattr() requests on mountpoints commit ab225417825963b6dc66be7ea80f94ac1378dfdf upstream. Ensure that any setattr and getattr requests for junctions and/or mountpoints are sent to the server. Ever since commit 0ec26fd0698 (vfs: automount should ignore LOOKUP_FOLLOW), we have silently dropped any setattr requests to a server-side mountpoint. For referrals, we have silently dropped both getattr and setattr requests. This patch restores the original behaviour for setattr on mountpoints, and tries to do the same for referrals, provided that we have a filehandle... Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/namespace.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 2257d1f33e3..43275167649 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -253,11 +253,31 @@ struct vfsmount *nfs_d_automount(struct path *path) return mnt; } +static int +nfs_namespace_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + if (NFS_FH(dentry->d_inode)->size != 0) + return nfs_getattr(mnt, dentry, stat); + generic_fillattr(dentry->d_inode, stat); + return 0; +} + +static int +nfs_namespace_setattr(struct dentry *dentry, struct iattr *attr) +{ + if (NFS_FH(dentry->d_inode)->size != 0) + return nfs_setattr(dentry, attr); + return -EACCES; +} + const struct inode_operations nfs_mountpoint_inode_operations = { .getattr = nfs_getattr, + .setattr = nfs_setattr, }; const struct inode_operations nfs_referral_inode_operations = { + .getattr = nfs_namespace_getattr, + .setattr = nfs_namespace_setattr, }; static void nfs_expire_automounts(struct work_struct *work) From 846c314fd6124b5bd3a3db2624818f29616874a1 Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Sat, 26 Jan 2013 15:53:57 +0800 Subject: [PATCH 2051/2357] smp: Fix SMP function call empty cpu mask race commit f44310b98ddb7f0d06550d73ed67df5865e3eda5 upstream. I get the following warning every day with v3.7, once or twice a day: [ 2235.186027] WARNING: at /mnt/sda7/kernel/linux/arch/x86/kernel/apic/ipi.c:109 default_send_IPI_mask_logical+0x2f/0xb8() As explained by Linus as well: | | Once we've done the "list_add_rcu()" to add it to the | queue, we can have (another) IPI to the target CPU that can | now see it and clear the mask. | | So by the time we get to actually send the IPI, the mask might | have been cleared by another IPI. | This patch also fixes a system hang problem, if the data->cpumask gets cleared after passing this point: if (WARN_ONCE(!mask, "empty IPI mask")) return; then the problem in commit 83d349f35e1a ("x86: don't send an IPI to the empty set of CPU's") will happen again. Signed-off-by: Wang YanQing Acked-by: Linus Torvalds Acked-by: Jan Beulich Cc: Paul E. McKenney Cc: Andrew Morton Cc: peterz@infradead.org Cc: mina86@mina86.org Cc: srivatsa.bhat@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/20130126075357.GA3205@udknight [ Tidied up the changelog and the comment in the code. ] Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/smp.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/kernel/smp.c b/kernel/smp.c index 2f8b10ecf75..d5f3238ec45 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -31,6 +31,7 @@ struct call_function_data { struct call_single_data csd; atomic_t refs; cpumask_var_t cpumask; + cpumask_var_t cpumask_ipi; }; static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_function_data, cfd_data); @@ -54,6 +55,9 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL, cpu_to_node(cpu))) return notifier_from_errno(-ENOMEM); + if (!zalloc_cpumask_var_node(&cfd->cpumask_ipi, GFP_KERNEL, + cpu_to_node(cpu))) + return notifier_from_errno(-ENOMEM); break; #ifdef CONFIG_HOTPLUG_CPU @@ -63,6 +67,7 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) case CPU_DEAD: case CPU_DEAD_FROZEN: free_cpumask_var(cfd->cpumask); + free_cpumask_var(cfd->cpumask_ipi); break; #endif }; @@ -524,6 +529,12 @@ void smp_call_function_many(const struct cpumask *mask, return; } + /* + * After we put an entry into the list, data->cpumask + * may be cleared again when another CPU sends another IPI for + * a SMP function call, so data->cpumask will be zero. + */ + cpumask_copy(data->cpumask_ipi, data->cpumask); raw_spin_lock_irqsave(&call_function.lock, flags); /* * Place entry at the _HEAD_ of the list, so that any cpu still @@ -547,7 +558,7 @@ void smp_call_function_many(const struct cpumask *mask, smp_mb(); /* Send a message to all CPUs in the map */ - arch_send_call_function_ipi_mask(data->cpumask); + arch_send_call_function_ipi_mask(data->cpumask_ipi); /* Optionally wait for the CPUs to complete */ if (wait) From 4031dfce34e8e8355c649f950a9ec7ccad20beee Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 15 Nov 2012 13:06:22 +0000 Subject: [PATCH 2052/2357] x86/msr: Add capabilities check commit c903f0456bc69176912dee6dd25c6a66ee1aed00 upstream. At the moment the MSR driver only relies upon file system checks. This means that anything as root with any capability set can write to MSRs. Historically that wasn't very interesting but on modern processors the MSRs are such that writing to them provides several ways to execute arbitary code in kernel space. Sample code and documentation on doing this is circulating and MSR attacks are used on Windows 64bit rootkits already. In the Linux case you still need to be able to open the device file so the impact is fairly limited and reduces the security of some capability and security model based systems down towards that of a generic "root owns the box" setup. Therefore they should require CAP_SYS_RAWIO to prevent an elevation of capabilities. The impact of this is fairly minimal on most setups because they don't have heavy use of capabilities. Those using SELinux, SMACK or AppArmor rules might want to consider if their rulesets on the MSR driver could be tighter. Signed-off-by: Alan Cox Cc: Linus Torvalds Cc: Andrew Morton Cc: Peter Zijlstra Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/msr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index eb113693f04..8563b64e18c 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -174,6 +174,9 @@ static int msr_open(struct inode *inode, struct file *file) unsigned int cpu; struct cpuinfo_x86 *c; + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + cpu = iminor(file->f_path.dentry->d_inode); if (cpu >= nr_cpu_ids || !cpu_online(cpu)) return -ENXIO; /* No such CPU */ From 956b0310a4f4cb0777d1e8a11a23950ec111a13b Mon Sep 17 00:00:00 2001 From: Nathan Zimmer Date: Tue, 8 Jan 2013 09:02:43 -0600 Subject: [PATCH 2053/2357] efi, x86: Pass a proper identity mapping in efi_call_phys_prelog commit b8f2c21db390273c3eaf0e5308faeaeb1e233840 upstream. Update efi_call_phys_prelog to install an identity mapping of all available memory. This corrects a bug on very large systems with more then 512 GB in which bios would not be able to access addresses above not in the mapping. The result is a crash that looks much like this. BUG: unable to handle kernel paging request at 000000effd870020 IP: [<0000000078bce331>] 0x78bce330 PGD 0 Oops: 0000 [#1] SMP Modules linked in: CPU 0 Pid: 0, comm: swapper/0 Tainted: G W 3.8.0-rc1-next-20121224-medusa_ntz+ #2 Intel Corp. Stoutland Platform RIP: 0010:[<0000000078bce331>] [<0000000078bce331>] 0x78bce330 RSP: 0000:ffffffff81601d28 EFLAGS: 00010006 RAX: 0000000078b80e18 RBX: 0000000000000004 RCX: 0000000000000004 RDX: 0000000078bcf958 RSI: 0000000000002400 RDI: 8000000000000000 RBP: 0000000078bcf760 R08: 000000effd870000 R09: 0000000000000000 R10: 0000000000000000 R11: 00000000000000c3 R12: 0000000000000030 R13: 000000effd870000 R14: 0000000000000000 R15: ffff88effd870000 FS: 0000000000000000(0000) GS:ffff88effe400000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000effd870020 CR3: 000000000160c000 CR4: 00000000000006b0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper/0 (pid: 0, threadinfo ffffffff81600000, task ffffffff81614400) Stack: 0000000078b80d18 0000000000000004 0000000078bced7b ffff880078b81fff 0000000000000000 0000000000000082 0000000078bce3a8 0000000000002400 0000000060000202 0000000078b80da0 0000000078bce45d ffffffff8107cb5a Call Trace: [] ? on_each_cpu+0x77/0x83 [] ? change_page_attr_set_clr+0x32f/0x3ed [] ? efi_call4+0x46/0x80 [] ? efi_enter_virtual_mode+0x1f5/0x305 [] ? start_kernel+0x34a/0x3d2 [] ? repair_env_string+0x60/0x60 [] ? x86_64_start_reservations+0xba/0xc1 [] ? early_idt_handlers+0x120/0x120 [] ? x86_64_start_kernel+0x154/0x163 Code: Bad RIP value. RIP [<0000000078bce331>] 0x78bce330 RSP CR2: 000000effd870020 ---[ end trace ead828934fef5eab ]--- Signed-off-by: Nathan Zimmer Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Signed-off-by: Robin Holt Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/efi/efi_64.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index ac3aa54e265..0fba86da589 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -38,7 +38,7 @@ #include #include -static pgd_t save_pgd __initdata; +static pgd_t *save_pgd __initdata; static unsigned long efi_flags __initdata; static void __init early_code_mapping_set_exec(int executable) @@ -61,12 +61,20 @@ static void __init early_code_mapping_set_exec(int executable) void __init efi_call_phys_prelog(void) { unsigned long vaddress; + int pgd; + int n_pgds; early_code_mapping_set_exec(1); local_irq_save(efi_flags); - vaddress = (unsigned long)__va(0x0UL); - save_pgd = *pgd_offset_k(0x0UL); - set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress)); + + n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE); + save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL); + + for (pgd = 0; pgd < n_pgds; pgd++) { + save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE); + vaddress = (unsigned long)__va(pgd * PGDIR_SIZE); + set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), *pgd_offset_k(vaddress)); + } __flush_tlb_all(); } @@ -75,7 +83,11 @@ void __init efi_call_phys_epilog(void) /* * After the lock is released, the original page table is restored. */ - set_pgd(pgd_offset_k(0x0UL), save_pgd); + int pgd; + int n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE); + for (pgd = 0; pgd < n_pgds; pgd++) + set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), save_pgd[pgd]); + kfree(save_pgd); __flush_tlb_all(); local_irq_restore(efi_flags); early_code_mapping_set_exec(0); From 40913e0adeb733053017293b0a5d6e096e47e4a1 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 25 Jan 2013 10:07:25 +0000 Subject: [PATCH 2054/2357] x86, efi: Set runtime_version to the EFI spec revision commit 712ba9e9afc4b3d3d6fa81565ca36fe518915c01 upstream. efi.runtime_version is erroneously being set to the value of the vendor's firmware revision instead of that of the implemented EFI specification. We can't deduce which EFI functions are available based on the revision of the vendor's firmware since the version scheme is likely to be unique to each vendor. What we really need to know is the revision of the implemented EFI specification, which is available in the EFI System Table header. Signed-off-by: Matt Fleming Cc: Seiji Aguchi Cc: Matthew Garrett Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/efi/efi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 72d88992f38..6825327d00a 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -900,7 +900,7 @@ void __init efi_enter_virtual_mode(void) * * Call EFI services through wrapper functions. */ - efi.runtime_version = efi_systab.fw_revision; + efi.runtime_version = efi_systab.hdr.revision; efi.get_time = virt_efi_get_time; efi.set_time = virt_efi_set_time; efi.get_wakeup_time = virt_efi_get_wakeup_time; From ae2bac5c25d3f073d307338d9a84a1fe454c283b Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sun, 13 Jan 2013 20:56:41 -0800 Subject: [PATCH 2055/2357] x86/Sandy Bridge: Sandy Bridge workaround depends on CONFIG_PCI commit e43b3cec711a61edf047adf6204d542f3a659ef8 upstream. early_pci_allowed() and read_pci_config_16() are only available if CONFIG_PCI is defined. Signed-off-by: H. Peter Anvin Cc: Jesse Barnes Signed-off-by: Abdallah Chatila --- arch/x86/kernel/setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index d289ee73a24..b71e4a533cc 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -622,6 +622,7 @@ static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10; static bool __init snb_gfx_workaround_needed(void) { +#ifdef CONFIG_PCI int i; u16 vendor, devid; static const u16 snb_ids[] = { @@ -646,6 +647,7 @@ static bool __init snb_gfx_workaround_needed(void) for (i = 0; i < ARRAY_SIZE(snb_ids); i++) if (devid == snb_ids[i]) return true; +#endif return false; } From 9767a2421ad0f125bda9a8a1bed0c76bece8125c Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 24 Jan 2013 21:57:14 -0500 Subject: [PATCH 2056/2357] target: fix regression with dev_link_magic in target_fabric_port_link This is to fix a regression that only affect the stable (not for the mainline) that the stable commit fdf9d86 was incorrectly placed dev->dev_link_magic check before the *dev assignment in target_fabric_port_link() due to fuzzy automatically context adjustment during the back-porting. Reported-by: Chris Boot Signed-off-by: Nicholas Bellinger Signed-off-by: CAI Qian Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_fabric_configfs.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index b009b89d2fb..817ba7c849e 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -752,12 +752,6 @@ static int target_fabric_port_link( struct target_fabric_configfs *tf; int ret; - if (dev->dev_link_magic != SE_DEV_LINK_MAGIC) { - pr_err("Bad dev->dev_link_magic, not a valid se_dev_ci pointer:" - " %p to struct se_device: %p\n", se_dev_ci, dev); - return -EFAULT; - } - tpg_ci = &lun_ci->ci_parent->ci_group->cg_item; se_tpg = container_of(to_config_group(tpg_ci), struct se_portal_group, tpg_group); @@ -775,6 +769,11 @@ static int target_fabric_port_link( ret = -ENODEV; goto out; } + if (dev->dev_link_magic != SE_DEV_LINK_MAGIC) { + pr_err("Bad dev->dev_link_magic, not a valid se_dev_ci pointer:" + " %p to struct se_device: %p\n", se_dev_ci, dev); + return -EFAULT; + } lun_p = core_dev_add_lun(se_tpg, dev->se_hba, dev, lun->unpacked_lun); From 398cc33fbceda864a91433b2a76bb510a640021a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 3 Feb 2013 18:24:52 -0600 Subject: [PATCH 2057/2357] Linux 3.4.29 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8ccebbadf36..23bcb1a6604 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 28 +SUBLEVEL = 29 EXTRAVERSION = NAME = Saber-toothed Squirrel From 5343d0c41c2b18eb482f9aa074a67286f3509710 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Thu, 6 Sep 2012 17:49:31 -0400 Subject: [PATCH 2058/2357] Perf: Restore correct CPU's PMU counters after power collpase Since the L1CC PMU's are per CPU, the variable to detect if a CPU came out of powercollapse also needs to be a per CPU variable. This ensures that we reset and restore the correct CPU's PMU counters. Change-Id: I02273df2eff9f6d88d68f46a7752c107b290a8ef Signed-off-by: Ashwin Chaugule --- arch/arm/include/asm/pmu.h | 1 - arch/arm/kernel/perf_event.c | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 0d0103a4aec..88d0872451b 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -113,7 +113,6 @@ struct arm_pmu { struct mutex reserve_mutex; u64 max_period; struct platform_device *plat_device; - u32 from_idle; irqreturn_t (*handle_irq)(int irq_num, void *dev); int (*request_pmu_irq)(int irq, irq_handler_t *irq_h); void (*free_pmu_irq)(int irq); diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index e97aef2b4ca..3f6a6d3fc5c 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -41,6 +41,7 @@ */ #define ARMPMU_MAX_HWEVENTS 32 +static DEFINE_PER_CPU(u32, from_idle); static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events); static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask); static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); @@ -602,7 +603,7 @@ static void armpmu_enable(struct pmu *pmu) int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); int idx; - if (armpmu->from_idle) { + if (__get_cpu_var(from_idle)) { for (idx = 0; idx <= cpu_pmu->num_events; ++idx) { struct perf_event *event = hw_events->events[idx]; @@ -613,9 +614,12 @@ static void armpmu_enable(struct pmu *pmu) } /* Reset bit so we don't needlessly re-enable counters.*/ - armpmu->from_idle = 0; + __get_cpu_var(from_idle) = 0; } + /* So we don't start the PMU before enabling counters after idle. */ + barrier(); + if (enabled) armpmu->start(); } @@ -731,7 +735,6 @@ static void __init cpu_pmu_init(struct arm_pmu *armpmu) * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading * junk values out of them. */ - static int __cpuinit pmu_cpu_notify(struct notifier_block *b, unsigned long action, void *hcpu) { @@ -805,7 +808,7 @@ static int perf_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd, * Flip this bit so armpmu_enable knows it needs * to re-enable active counters. */ - cpu_pmu->from_idle = 1; + __get_cpu_var(from_idle) = 1; cpu_pmu->reset(NULL); perf_pmu_enable(&cpu_pmu->pmu); } From 9c91478a9a3ad7656cc875ffa079002b54815ecc Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Tue, 9 Oct 2012 13:35:16 -0400 Subject: [PATCH 2059/2357] Perf: Make L1 PMU IRQ name target independent Remove target name from IRQ string, since the percpu IRQ API is shared with all Qcomm targets. Change-Id: Id0e7d9267654b373e9360806900259e00bf5a0ab Signed-off-by: Ashwin Chaugule --- arch/arm/kernel/perf_event_msm_krait.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c index 8d8f47a0108..eec614b481c 100644 --- a/arch/arm/kernel/perf_event_msm_krait.c +++ b/arch/arm/kernel/perf_event_msm_krait.c @@ -540,8 +540,8 @@ msm_request_irq(int irq, irq_handler_t *handle_irq) int err = 0; int cpu; - err = request_percpu_irq(irq, *handle_irq, "krait-l1-armpmu", - &cpu_hw_events); + err = request_percpu_irq(irq, *handle_irq, "l1-armpmu", + &cpu_hw_events); if (!err) { for_each_cpu(cpu, cpu_online_mask) { From 22ec8e2a0e8b84be470d2f77c243eb4a4ad25044 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Tue, 9 Oct 2012 13:29:37 -0400 Subject: [PATCH 2060/2357] Perf: Change IRQ functions for CPU variants Unicore targets can't use the percpu IRQ API, so fallback to the generic versions of the functions at init. Change-Id: Id3db611fe4a7e0dcfbeb2f3ae08a5f7189132034 Signed-off-by: Ashwin Chaugule --- arch/arm/kernel/perf_event_msm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c index 90c9c9ec0f9..8f58adffb27 100644 --- a/arch/arm/kernel/perf_event_msm.c +++ b/arch/arm/kernel/perf_event_msm.c @@ -709,8 +709,6 @@ static void scorpion_pmu_reset(void *info) static struct arm_pmu scorpion_pmu = { .handle_irq = armv7pmu_handle_irq, - .request_pmu_irq = msm_request_irq, - .free_pmu_irq = msm_free_irq, .enable = scorpion_pmu_enable_event, .disable = scorpion_pmu_disable_event, .read_counter = armv7pmu_read_counter, @@ -731,6 +729,9 @@ static struct arm_pmu *__init armv7_scorpion_pmu_init(void) scorpion_pmu.name = "ARMv7 Scorpion"; scorpion_pmu.num_events = armv7_read_num_pmnc_events(); scorpion_pmu.pmu.attr_groups = msm_l1_pmu_attr_grps; + /* Unicore can't use the percpu IRQ API. */ + scorpion_pmu.request_pmu_irq = armpmu_generic_request_irq; + scorpion_pmu.free_pmu_irq = armpmu_generic_free_irq; scorpion_clear_pmuregs(); return &scorpion_pmu; } @@ -741,6 +742,8 @@ static struct arm_pmu *__init armv7_scorpionmp_pmu_init(void) scorpion_pmu.name = "ARMv7 Scorpion-MP"; scorpion_pmu.num_events = armv7_read_num_pmnc_events(); scorpion_pmu.pmu.attr_groups = msm_l1_pmu_attr_grps; + scorpion_pmu.request_pmu_irq = msm_request_irq; + scorpion_pmu.free_pmu_irq = msm_free_irq; scorpion_clear_pmuregs(); return &scorpion_pmu; } From d8424b429076ddafe4a3cba45b029d0fdd1a3f43 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Wed, 10 Oct 2012 11:07:22 -0400 Subject: [PATCH 2061/2357] Perf: Add generic IRQ handlers for ARMv7 PMU's For ARMV7 based PMU's implemented outside Qcomm, default to the generic IRQ handlers to maintain original behavior. Change-Id: Ic65379104cc708460f2f84c00ea86c1e284bbd29 Signed-off-by: Ashwin Chaugule --- arch/arm/kernel/perf_event_v7.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 678c55de53d..3163b2ab84a 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -1235,6 +1235,8 @@ static int armv7_a7_map_event(struct perf_event *event) } static struct arm_pmu armv7pmu = { + .request_pmu_irq = armpmu_generic_request_irq, + .free_pmu_irq = armpmu_generic_free_irq, .handle_irq = armv7pmu_handle_irq, .enable = armv7pmu_enable_event, .disable = armv7pmu_disable_event, From 6c755b2ff86d0b75d33adc4f6825a0879b9bae8d Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Mon, 29 Oct 2012 16:30:05 -0400 Subject: [PATCH 2062/2357] Perf: Let platforms decide IRQ request methods. This is in preparation for adding support for the unicore A5 and dualcore A5, both of which have the same MIDR value. Instead of adding extra parsing to the ARM generic perf_event file, this patch moves it to the 'mach' directory where targets types can be detected in an implementation specific manner. The default behavior is maintained for all other ARM targets. Change-Id: I041937273dbbd0fa4c602cf89a2e0fee7f73342b Signed-off-by: Ashwin Chaugule --- arch/arm/include/asm/pmu.h | 10 +++- arch/arm/kernel/perf_event.c | 10 ++++ arch/arm/kernel/perf_event_msm.c | 7 +-- arch/arm/kernel/perf_event_msm_krait.c | 51 +------------------ arch/arm/kernel/perf_event_v7.c | 2 - arch/arm/mach-msm/pmu.c | 69 +++++++++++++++++++++++++- 6 files changed, 88 insertions(+), 61 deletions(-) diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 88d0872451b..5188dbf42c0 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -32,6 +32,10 @@ enum arm_pmu_type { * interrupt and passed the address of the low level handler, * and can be used to implement any platform specific handling * before or after calling it. + * @request_pmu_irq: an optional handler in case the platform wants + * to use a percpu IRQ API call. e.g. request_percpu_irq + * @free_pmu_irq: an optional handler in case the platform wants + * to use a percpu IRQ API call. e.g. free_percpu_irq * @enable_irq: an optional handler which will be called after * request_irq and be used to handle some platform specific * irq enablement @@ -42,6 +46,8 @@ enum arm_pmu_type { struct arm_pmu_platdata { irqreturn_t (*handle_irq)(int irq, void *dev, irq_handler_t pmu_handler); + int (*request_pmu_irq)(int irq, irq_handler_t *irq_h); + void (*free_pmu_irq)(int irq); void (*enable_irq)(int irq); void (*disable_irq)(int irq); }; @@ -114,8 +120,8 @@ struct arm_pmu { u64 max_period; struct platform_device *plat_device; irqreturn_t (*handle_irq)(int irq_num, void *dev); - int (*request_pmu_irq)(int irq, irq_handler_t *irq_h); - void (*free_pmu_irq)(int irq); + int (*request_pmu_irq)(int irq, irq_handler_t *irq_h); + void (*free_pmu_irq)(int irq); void (*enable)(struct hw_perf_event *evt, int idx, int cpu); void (*disable)(struct hw_perf_event *evt, int idx); int (*get_event_idx)(struct pmu_hw_events *hw_events, diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 3f6a6d3fc5c..2464140298c 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -437,6 +437,16 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) else handle_irq = armpmu->handle_irq; + if (plat && plat->request_pmu_irq) + armpmu->request_pmu_irq = plat->request_pmu_irq; + else + armpmu->request_pmu_irq = armpmu_generic_request_irq; + + if (plat && plat->free_pmu_irq) + armpmu->free_pmu_irq = plat->free_pmu_irq; + else + armpmu->free_pmu_irq = armpmu_generic_free_irq; + irqs = min(pmu_device->num_resources, num_possible_cpus()); if (irqs < 1) { pr_err("no irqs for PMUs defined\n"); diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c index 8f58adffb27..92dc7c733a1 100644 --- a/arch/arm/kernel/perf_event_msm.c +++ b/arch/arm/kernel/perf_event_msm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -729,9 +729,6 @@ static struct arm_pmu *__init armv7_scorpion_pmu_init(void) scorpion_pmu.name = "ARMv7 Scorpion"; scorpion_pmu.num_events = armv7_read_num_pmnc_events(); scorpion_pmu.pmu.attr_groups = msm_l1_pmu_attr_grps; - /* Unicore can't use the percpu IRQ API. */ - scorpion_pmu.request_pmu_irq = armpmu_generic_request_irq; - scorpion_pmu.free_pmu_irq = armpmu_generic_free_irq; scorpion_clear_pmuregs(); return &scorpion_pmu; } @@ -742,8 +739,6 @@ static struct arm_pmu *__init armv7_scorpionmp_pmu_init(void) scorpion_pmu.name = "ARMv7 Scorpion-MP"; scorpion_pmu.num_events = armv7_read_num_pmnc_events(); scorpion_pmu.pmu.attr_groups = msm_l1_pmu_attr_grps; - scorpion_pmu.request_pmu_irq = msm_request_irq; - scorpion_pmu.free_pmu_irq = msm_free_irq; scorpion_clear_pmuregs(); return &scorpion_pmu; } diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c index eec614b481c..5708d7465ee 100644 --- a/arch/arm/kernel/perf_event_msm_krait.c +++ b/arch/arm/kernel/perf_event_msm_krait.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -520,53 +520,6 @@ static void krait_pmu_reset(void *info) armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C); } -static void enable_irq_callback(void *info) -{ - int irq = *(unsigned int *)info; - - enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING); -} - -static void disable_irq_callback(void *info) -{ - int irq = *(unsigned int *)info; - - disable_percpu_irq(irq); -} - -static int -msm_request_irq(int irq, irq_handler_t *handle_irq) -{ - int err = 0; - int cpu; - - err = request_percpu_irq(irq, *handle_irq, "l1-armpmu", - &cpu_hw_events); - - if (!err) { - for_each_cpu(cpu, cpu_online_mask) { - smp_call_function_single(cpu, - enable_irq_callback, &irq, 1); - } - } - - return err; -} - -static void -msm_free_irq(int irq) -{ - int cpu; - - if (irq >= 0) { - for_each_cpu(cpu, cpu_online_mask) { - smp_call_function_single(cpu, - disable_irq_callback, &irq, 1); - } - free_percpu_irq(irq, &cpu_hw_events); - } -} - /* * We check for column exclusion constraints here. * Two events cant have same reg and same group. @@ -621,8 +574,6 @@ static int msm_clear_ev_constraint(struct perf_event *event) static struct arm_pmu krait_pmu = { .handle_irq = armv7pmu_handle_irq, - .request_pmu_irq = msm_request_irq, - .free_pmu_irq = msm_free_irq, .enable = krait_pmu_enable_event, .disable = krait_pmu_disable_event, .read_counter = armv7pmu_read_counter, diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 3163b2ab84a..678c55de53d 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -1235,8 +1235,6 @@ static int armv7_a7_map_event(struct perf_event *event) } static struct arm_pmu armv7pmu = { - .request_pmu_irq = armpmu_generic_request_irq, - .free_pmu_irq = armpmu_generic_free_irq, .handle_irq = armv7pmu_handle_irq, .enable = armv7pmu_enable_event, .disable = armv7pmu_disable_event, diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c index 5e339da6d15..5e87bc01202 100644 --- a/arch/arm/mach-msm/pmu.c +++ b/arch/arm/mach-msm/pmu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -11,8 +11,64 @@ */ #include +#include #include #include +#include + +#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) +static DEFINE_PER_CPU(u32, pmu_irq_cookie); + +static void enable_irq_callback(void *info) +{ + int irq = *(unsigned int *)info; + enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING); +} + +static void disable_irq_callback(void *info) +{ + int irq = *(unsigned int *)info; + disable_percpu_irq(irq); +} + +static int +multicore_request_irq(int irq, irq_handler_t *handle_irq) +{ + int err = 0; + int cpu; + + err = request_percpu_irq(irq, *handle_irq, "l1-armpmu", + &pmu_irq_cookie); + + if (!err) { + for_each_cpu(cpu, cpu_online_mask) { + smp_call_function_single(cpu, + enable_irq_callback, &irq, 1); + } + } + + return err; +} + +static void +multicore_free_irq(int irq) +{ + int cpu; + + if (irq >= 0) { + for_each_cpu(cpu, cpu_online_mask) { + smp_call_function_single(cpu, + disable_irq_callback, &irq, 1); + } + free_percpu_irq(irq, &pmu_irq_cookie); + } +} + +static struct arm_pmu_platdata multicore_data = { + .request_pmu_irq = multicore_request_irq, + .free_pmu_irq = multicore_free_irq, +}; +#endif static struct resource cpu_pmu_resource[] = { { @@ -47,6 +103,7 @@ static struct platform_device cpu_pmu_device = { .num_resources = ARRAY_SIZE(cpu_pmu_resource), }; + static struct platform_device *pmu_devices[] = { &cpu_pmu_device, #ifdef CONFIG_CPU_HAS_L2_PMU @@ -56,6 +113,16 @@ static struct platform_device *pmu_devices[] = { static int __init msm_pmu_init(void) { + /* + * For the targets we know are multicore's set the request/free IRQ + * handlers to call the percpu API. + * Defaults to unicore API {request,free}_irq(). + * See arch/arm/kernel/perf_event.c + */ +#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) + cpu_pmu_device.dev.platform_data = &multicore_data; +#endif + return platform_add_devices(pmu_devices, ARRAY_SIZE(pmu_devices)); } From 1f7e7baa27aeb6820f16ac8540d4731e6dae5cff Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Tue, 27 Nov 2012 14:49:58 -0500 Subject: [PATCH 2063/2357] msm: Perf: Differentiate between L1 and L2 PMU IRQs The L2 perf code shares some resource reservation functions with the L1 perf code. In these functions, use defaults only if they're not defined for the L1 and L2. Change-Id: I5a390aa0085694466800db78b51837556aa12cdd Signed-off-by: Ashwin Chaugule --- arch/arm/kernel/perf_event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 2464140298c..3a52ddce848 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -439,12 +439,12 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) if (plat && plat->request_pmu_irq) armpmu->request_pmu_irq = plat->request_pmu_irq; - else + else if (!armpmu->request_pmu_irq) armpmu->request_pmu_irq = armpmu_generic_request_irq; if (plat && plat->free_pmu_irq) armpmu->free_pmu_irq = plat->free_pmu_irq; - else + else if (!armpmu->request_pmu_irq) armpmu->free_pmu_irq = armpmu_generic_free_irq; irqs = min(pmu_device->num_resources, num_possible_cpus()); From 2f71d2b749087057002abbdd5074a804abe757f3 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Thu, 6 Dec 2012 09:56:15 -0500 Subject: [PATCH 2064/2357] Perf: Assign proper routine to free IRQ If the platform descriptor does not provide its own free_irq function, default to the fallback version. Change-Id: I185186bf68b79e2dbfba77b0de66eb4daaf32fb8 Signed-off-by: Ashwin Chaugule --- arch/arm/kernel/perf_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 3a52ddce848..d2e2e445831 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -444,7 +444,7 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) if (plat && plat->free_pmu_irq) armpmu->free_pmu_irq = plat->free_pmu_irq; - else if (!armpmu->request_pmu_irq) + else if (!armpmu->free_pmu_irq) armpmu->free_pmu_irq = armpmu_generic_free_irq; irqs = min(pmu_device->num_resources, num_possible_cpus()); From f9bf3d8c2f5adce71123e42c9cca936f84d3e531 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Tue, 4 Dec 2012 17:40:05 -0500 Subject: [PATCH 2065/2357] msm: perf: Relax Column exclusion checks for L2CC events Identical L2CC events with the same register, code and group can be set up with individual origin filters. The hardware restricts counting only for identical register and group settings but a different value for the event code. Detect such identical events and let them pass the constraint checks. Change-Id: I609defb5c5b070b1007b2e7db9e2d8315d2ba1d7 Signed-off-by: Ashwin Chaugule --- arch/arm/mach-msm/perf_event_msm_krait_l2.c | 52 +++++++++++++++++---- arch/arm/mach-msm/perf_event_msm_l2.c | 46 +++++++++++++++--- 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c index 103eef0202b..26c5e589dfb 100644 --- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c +++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c @@ -72,9 +72,11 @@ */ struct pmu_constraints { u64 pmu_bitmap; + u8 codes[64]; raw_spinlock_t lock; } l2_pmu_constraints = { .pmu_bitmap = 0, + .codes = {-1}, .lock = __RAW_SPIN_LOCK_UNLOCKED(l2_pmu_constraints.lock), }; @@ -335,8 +337,10 @@ static int krait_l2_get_event_idx(struct pmu_hw_events *cpuc, int ctr = 0; if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) { - if (!test_and_set_bit(l2_cycle_ctr_idx, cpuc->used_mask)) - return l2_cycle_ctr_idx; + if (test_and_set_bit(l2_cycle_ctr_idx, cpuc->used_mask)) + return -EAGAIN; + + return l2_cycle_ctr_idx; } for (ctr = 0; ctr < total_l2_ctrs - 1; ctr++) { @@ -453,22 +457,48 @@ static int msm_l2_test_set_ev_constraint(struct perf_event *event) { u32 evt_type = event->attr.config & L2_EVT_MASK; u8 reg = (evt_type & 0x0F000) >> 12; - u8 group = evt_type & 0x0000F; + u8 group = evt_type & 0x0000F; + u8 code = (evt_type & 0x00FF0) >> 4; unsigned long flags; u32 err = 0; u64 bitmap_t; + u32 shift_idx; + + /* + * Cycle counter collision is detected in + * get_event_idx(). + */ + if (evt_type == L2CYCLE_CTR_RAW_CODE) + return err; raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags); - bitmap_t = 1 << ((reg * 4) + group); + shift_idx = ((reg * 4) + group); + + bitmap_t = 1 << shift_idx; if (!(l2_pmu_constraints.pmu_bitmap & bitmap_t)) { l2_pmu_constraints.pmu_bitmap |= bitmap_t; + l2_pmu_constraints.codes[shift_idx] = code; goto out; + } else { + /* + * If NRCCG's are identical, + * its not column exclusion. + */ + if (l2_pmu_constraints.codes[shift_idx] != code) + err = -EPERM; + else + /* + * If the event is counted in syswide mode + * then we want to count only on one CPU + * and set its filter to count from all. + * This sets the event OFF on all but one + * CPU. + */ + if (!(event->cpu < 0)) + event->state = PERF_EVENT_STATE_OFF; } - - /* Bit is already set. Constraint failed. */ - err = -EPERM; out: raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags); return err; @@ -481,14 +511,20 @@ static int msm_l2_clear_ev_constraint(struct perf_event *event) u8 group = evt_type & 0x0000F; unsigned long flags; u64 bitmap_t; + u32 shift_idx; raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags); - bitmap_t = 1 << ((reg * 4) + group); + shift_idx = ((reg * 4) + group); + + bitmap_t = 1 << shift_idx; /* Clear constraint bit. */ l2_pmu_constraints.pmu_bitmap &= ~bitmap_t; + /* Clear code. */ + l2_pmu_constraints.codes[shift_idx] = -1; + raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags); return 1; } diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c index 2ad36df9216..c1b7d23750b 100644 --- a/arch/arm/mach-msm/perf_event_msm_l2.c +++ b/arch/arm/mach-msm/perf_event_msm_l2.c @@ -38,9 +38,11 @@ */ struct pmu_constraints { u64 pmu_bitmap; + u8 codes[64]; raw_spinlock_t lock; } l2_pmu_constraints = { .pmu_bitmap = 0, + .codes = {-1}, .lock = __RAW_SPIN_LOCK_UNLOCKED(l2_pmu_constraints.lock), }; @@ -667,9 +669,11 @@ static int scorpion_l2_get_event_idx(struct pmu_hw_events *cpuc, int ctr = 0; if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE) { - if (!test_and_set_bit(l2_cycle_ctr_idx, + if (test_and_set_bit(l2_cycle_ctr_idx, cpuc->used_mask)) - return l2_cycle_ctr_idx; + return -EAGAIN; + + return l2_cycle_ctr_idx; } for (ctr = 0; ctr < total_l2_ctrs - 1; ctr++) { @@ -792,25 +796,50 @@ static int msm_l2_test_set_ev_constraint(struct perf_event *event) u8 prefix = (evt_type & 0xF0000) >> 16; u8 reg = (evt_type & 0x0F000) >> 12; u8 group = evt_type & 0x0000F; + u8 code = (evt_type & 0x00FF0) >> 4; unsigned long flags; u32 err = 0; u64 bitmap_t; + u32 shift_idx; if (!prefix) return 0; + /* + * Cycle counter collision is detected in + * get_event_idx(). + */ + if (evt_type == SCORPION_L2CYCLE_CTR_RAW_CODE) + return err; raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags); - bitmap_t = 1 << ((reg * 4) + group); + shift_idx = ((reg * 4) + group); + + bitmap_t = 1 << shift_idx; if (!(l2_pmu_constraints.pmu_bitmap & bitmap_t)) { l2_pmu_constraints.pmu_bitmap |= bitmap_t; + l2_pmu_constraints.codes[shift_idx] = code; goto out; + } else { + /* + * If NRCCG's are identical, + * its not column exclusion. + */ + if (l2_pmu_constraints.codes[shift_idx] != code) + err = -EPERM; + else + /* + * If the event is counted in syswide mode + * then we want to count only on one CPU + * and set its filter to count from all. + * This sets the event OFF on all but one + * CPU. + */ + if (!(event->cpu < 0)) + event->state = PERF_EVENT_STATE_OFF; } - /* Bit is already set. Constraint failed. */ - err = -EPERM; - out: raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags); return err; @@ -824,13 +853,16 @@ static int msm_l2_clear_ev_constraint(struct perf_event *event) u8 group = evt_type & 0x0000F; unsigned long flags; u64 bitmap_t; + u32 shift_idx; if (!prefix) return 0; raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags); - bitmap_t = 1 << ((reg * 4) + group); + shift_idx = ((reg * 4) + group); + + bitmap_t = 1 << shift_idx; /* Clear constraint bit. */ l2_pmu_constraints.pmu_bitmap &= ~bitmap_t; From a320a280b2d720198c5778969e1d294ad6826a9b Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Mon, 7 Jan 2013 15:12:45 -0500 Subject: [PATCH 2066/2357] msm: perf: add debug patch logging framework Provide a mechanism to track which msm perf patches are present in a kernel. Some kernel branches do not include all patches which causes problems trying to debug perf issues. This framework provides a way to keep track of which patches have been included in a build. Change-Id: Ib8ef311454564c4609d94decd93e039c80104275 Signed-off-by: Neil Leeder --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/perf_debug.c | 64 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 arch/arm/mach-msm/perf_debug.c diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 44185951006..01de1639091 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o obj-$(CONFIG_ARCH_MSM_KRAIT) += krait-scm.o obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o +obj-$(CONFIG_DEBUG_FS) += perf_debug.o ifndef CONFIG_MSM_SMP obj-$(CONFIG_ARCH_MSM_SCORPION) += msm_fault_handlers.o diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c new file mode 100644 index 00000000000..52e58a20e09 --- /dev/null +++ b/arch/arm/mach-msm/perf_debug.c @@ -0,0 +1,64 @@ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include + +/* + * Subsequent patches should add an entry to end of this string. + * Format is incrementing sequence number followed by text of + * patch commit title with newline. + * Note trailing ';' is on its own line to simplify addition of + * future strings. + */ +static char *descriptions = + "0 msm: perf: add debug patch logging framework\n" +; + +static ssize_t desc_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + return simple_read_from_buffer(buf, count, pos, descriptions, + strlen(descriptions)); +} + +static const struct file_operations perf_debug_desc_fops = { + .read = desc_read, +}; + +static int msm_perf_debugfs_init(void) +{ + int ret = 0; + struct dentry *dir; + struct dentry *file; + + dir = debugfs_create_dir("msm-perf-patches", NULL); + if (IS_ERR_OR_NULL(dir)) { + pr_err("failed to create msm-perf-patches dir in debugfs\n"); + ret = PTR_ERR(dir); + goto init_exit; + } + + file = debugfs_create_file("descriptions", 0444, dir, NULL, + &perf_debug_desc_fops); + if (IS_ERR_OR_NULL(file)) { + debugfs_remove(dir); + pr_err("failed to create descriptions file for msm-perf-patches\n"); + ret = PTR_ERR(file); + goto init_exit; + } + +init_exit: + return ret; +} +late_initcall(msm_perf_debugfs_init); From c4c5fc17aedf009cd5587700019c2cead89e19c1 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Tue, 8 Jan 2013 15:55:06 -0500 Subject: [PATCH 2067/2357] Perf: Restore counter after powercollapse for generic ARM PMU's The MSM SoC's which have ARM's CPU's can power collapse. Ensure the CPU side PMU's correctly restore the counters after coming out of power collapse. Change-Id: I544a1dd8ced26f726ba115d14867d9e34c2a7944 Signed-off-by: Ashwin Chaugule --- arch/arm/kernel/perf_event_v7.c | 4 ++++ arch/arm/mach-msm/perf_debug.c | 1 + 2 files changed, 5 insertions(+) diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 678c55de53d..58e9068cc84 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -997,6 +997,7 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx, int cpu) { unsigned long flags; struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + unsigned long long prev_count = local64_read(&hwc->prev_count); /* * Enable counter and interrupt, and set the counter to count @@ -1022,6 +1023,9 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx, int cpu) */ armv7_pmnc_enable_intens(idx); + /* Restore prev val */ + armv7pmu_write_counter(idx, prev_count & 0xffffffff); + /* * Enable counter */ diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c index 52e58a20e09..eefe32686f9 100644 --- a/arch/arm/mach-msm/perf_debug.c +++ b/arch/arm/mach-msm/perf_debug.c @@ -23,6 +23,7 @@ */ static char *descriptions = "0 msm: perf: add debug patch logging framework\n" + "1 Perf: Restore counter after powercollapse for generic ARM PMU's\n" ; static ssize_t desc_read(struct file *fp, char __user *buf, From b0cc9fb10c1b7240b229b40391f8da2a987995bd Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 25 Jan 2013 16:54:20 +0200 Subject: [PATCH 2068/2357] digsig: Fix memory leakage in digsig_verify_rsa() commit 7810cc1e7721220f1ed2a23ca95113d6434f6dcd upstream. digsig_verify_rsa() does not free kmalloc'ed buffer returned by mpi_get_buffer(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: Dmitry Kasatkin Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- lib/digsig.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/digsig.c b/lib/digsig.c index 8c0e62975c8..dc2be7ed176 100644 --- a/lib/digsig.c +++ b/lib/digsig.c @@ -162,6 +162,8 @@ static int digsig_verify_rsa(struct key *key, memset(out1, 0, head); memcpy(out1 + head, p, l); + kfree(p); + err = pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len); if (err) goto err; From 36509fceeabafd1a6e95e48ae75efe020fa59937 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 31 Jan 2013 09:00:52 -0500 Subject: [PATCH 2069/2357] drm/radeon/evergreen+: wait for the MC to settle after MC blackout commit ed39fadd6df01095378e499fac3674883f16b853 upstream. Some chips seem to need a little delay after blacking out the MC before the requests actually stop. May fix: https://bugs.freedesktop.org/show_bug.cgi?id=56139 https://bugs.freedesktop.org/show_bug.cgi?id=57567 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 4a1d8f3457c..e664e0414c6 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1179,6 +1179,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav blackout &= ~BLACKOUT_MODE_MASK; WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1); } + /* wait for the MC to settle */ + udelay(100); } void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save) From b5d3ef25ca19150e30b0d3c0969349951134684b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 27 Jan 2013 21:57:51 -0500 Subject: [PATCH 2070/2357] drm/radeon: add WAIT_UNTIL to the non-VM safe regs list for cayman/TN commit 674a16f2b4724880d07389abbb95abf320b924aa upstream. Newer versions of mesa emit this. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/reg_srcs/cayman | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/reg_srcs/cayman b/drivers/gpu/drm/radeon/reg_srcs/cayman index 0f656b111c1..a072fa8c46b 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/cayman +++ b/drivers/gpu/drm/radeon/reg_srcs/cayman @@ -1,5 +1,6 @@ cayman 0x9400 0x0000802C GRBM_GFX_INDEX +0x00008040 WAIT_UNTIL 0x000084FC CP_STRMOUT_CNTL 0x000085F0 CP_COHER_CNTL 0x000085F4 CP_COHER_SIZE From b5dc90fe1300df803e7c5b1922c759e135116251 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 29 Jan 2013 16:36:47 -0500 Subject: [PATCH 2071/2357] drm/radeon: add quirk for RV100 board commit 9200ee4941a6e5d1ec5df88982243686882dff3f upstream. vbios says external TMDS while the board is actually internal TMDS. fixes: https://bugs.freedesktop.org/show_bug.cgi?id=60037 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_combios.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 2cad9fde92f..a2470d96deb 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2338,6 +2338,14 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) 1), ATOM_DEVICE_CRT1_SUPPORT); } + /* RV100 board with external TDMS bit mis-set. + * Actually uses internal TMDS, clear the bit. + */ + if (dev->pdev->device == 0x5159 && + dev->pdev->subsystem_vendor == 0x1014 && + dev->pdev->subsystem_device == 0x029A) { + tmp &= ~(1 << 4); + } if ((tmp >> 4) & 0x1) { devices |= ATOM_DEVICE_DFP2_SUPPORT; radeon_add_legacy_encoder(dev, From c7d3c1787d491f55849d587e519a0bfe14d5f716 Mon Sep 17 00:00:00 2001 From: Christopher Staite Date: Sat, 26 Jan 2013 11:10:58 -0500 Subject: [PATCH 2072/2357] drm/radeon: fix MC blackout on evergreen+ commit bb588820ef421c6098dca1fec29c3b347f1c8c19 upstream. Force the crtc mem requests on/off immediately rather than waiting for the double buffered updates to kick in. Seems we miss the update in certain conditions. Also handle the DCE6 case. Signed-off-by: Christopher Staite Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e664e0414c6..c62132cecaf 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1147,14 +1147,18 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) { radeon_wait_for_vblank(rdev, i); tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } } else { tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) { radeon_wait_for_vblank(rdev, i); tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } } /* wait for the next frame */ @@ -1214,11 +1218,15 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s if (ASIC_IS_DCE6(rdev)) { tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } else { tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } /* wait for the next frame */ frame_count = radeon_get_vblank_counter(rdev, i); From dcf73edd833be6d4999a7d8f6cc6941c9e475ce4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 30 Jan 2013 14:24:09 -0500 Subject: [PATCH 2073/2357] drm/radeon: prevent crash in the ring space allocation commit fd5d93a0015ce1a7db881382022b2fcdfdc61760 upstream. If the requested number of DWs on the ring is larger than the size of the ring itself, return an error. In testing with large VM updates, we've seen crashes when we try and allocate more space on the ring than the total size of the ring without checking. This prevents the crash but for large VM updates or bo moves of very large buffers, we will need to break the transaction down into multiple batches. I have patches to use IBs for the next kernel. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_ring.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index cc33b3d7c33..33eff8bcabe 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -311,6 +311,9 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi { int r; + /* make sure we aren't trying to allocate more space than there is on the ring */ + if (ndw > (ring->ring_size / 4)) + return -ENOMEM; /* Align requested size with padding so unlock_commit can * pad safely */ ndw = (ndw + ring->align_mask) & ~ring->align_mask; From 8f69eeaecbb7d741e943f7972627bbd1ca294ab6 Mon Sep 17 00:00:00 2001 From: liu chuansheng Date: Thu, 31 Jan 2013 22:13:00 +0800 Subject: [PATCH 2074/2357] drm/radeon: Calling object_unrefer() when creating fb failure commit f2d68cf4daa4de97d400d94836b907e35228e54f upstream. When kzalloc() failed in radeon_user_framebuffer_create(), need to call object_unreference() to match the object_reference(). Signed-off-by: liu chuansheng Signed-off-by: xueminsu Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1f50727d210..00d9cac69f9 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1129,8 +1129,10 @@ radeon_user_framebuffer_create(struct drm_device *dev, } radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); - if (radeon_fb == NULL) + if (radeon_fb == NULL) { + drm_gem_object_unreference_unlocked(obj); return ERR_PTR(-ENOMEM); + } ret = radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj); if (ret) { From 11151f33ae2b29f8346f5ac1250c1879e3348cbc Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 30 Jan 2013 07:55:53 +0000 Subject: [PATCH 2075/2357] x86-64: Replace left over sti/cli in ia32 audit exit code commit 40a1ef95da85843696fc3ebe5fce39b0db32669f upstream. For some reason they didn't get replaced so far by their paravirt equivalents, resulting in code to be run with interrupts disabled that doesn't expect so (causing, in the observed case, a BUG_ON() to trigger) when syscall auditing is enabled. David (Cc-ed) came up with an identical fix, so likely this can be taken to count as an ack from him. Reported-by: Peter Moody Signed-off-by: Jan Beulich Cc: David Vrabel Cc: Konrad Rzeszutek Wilk Link: http://lkml.kernel.org/r/5108E01902000078000BA9C5@nat28.tlf.novell.com Signed-off-by: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: David Vrabel Tested-by: Peter Moody Signed-off-by: Greg Kroah-Hartman --- arch/x86/ia32/ia32entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index e3e734005e1..66c4cae439c 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -205,7 +205,7 @@ sysexit_from_sys_call: testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) jnz ia32_ret_from_sys_call TRACE_IRQS_ON - sti + ENABLE_INTERRUPTS(CLBR_NONE) movl %eax,%esi /* second arg, syscall return value */ cmpl $-MAX_ERRNO,%eax /* is it an error ? */ jbe 1f @@ -215,7 +215,7 @@ sysexit_from_sys_call: call __audit_syscall_exit movq RAX-ARGOFFSET(%rsp),%rax /* reload syscall return value */ movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi - cli + DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF testl %edi,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) jz \exit From 89960feebaf4f9a53f93a0ce6888207e4a808799 Mon Sep 17 00:00:00 2001 From: Shawn Bohrer Date: Mon, 14 Jan 2013 11:55:31 -0600 Subject: [PATCH 2076/2357] sched/rt: Use root_domain of rt_rq not current processor commit aa7f67304d1a03180f463258aa6f15a8b434e77d upstream. When the system has multiple domains do_sched_rt_period_timer() can run on any CPU and may iterate over all rt_rq in cpu_online_mask. This means when balance_runtime() is run for a given rt_rq that rt_rq may be in a different rd than the current processor. Thus if we use smp_processor_id() to get rd in do_balance_runtime() we may borrow runtime from a rt_rq that is not part of our rd. This changes do_balance_runtime to get the rd from the passed in rt_rq ensuring that we borrow runtime only from the correct rd for the given rt_rq. This fixes a BUG at kernel/sched/rt.c:687! in __disable_runtime when we try reclaim runtime lent to other rt_rq but runtime has been lent to a rt_rq in another rd. Signed-off-by: Shawn Bohrer Acked-by: Steven Rostedt Acked-by: Mike Galbraith Cc: peterz@infradead.org Link: http://lkml.kernel.org/r/1358186131-29494-1-git-send-email-sbohrer@rgmadvisors.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/sched/rt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 44af55e6d5d..ead0336007b 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -560,7 +560,7 @@ static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq) static int do_balance_runtime(struct rt_rq *rt_rq) { struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); - struct root_domain *rd = cpu_rq(smp_processor_id())->rd; + struct root_domain *rd = rq_of_rt_rq(rt_rq)->rd; int i, weight, more = 0; u64 rt_period; From 0b0a57362b8d1585f6909333fc667c73bae8205c Mon Sep 17 00:00:00 2001 From: Vyacheslav Dubeyko Date: Mon, 4 Feb 2013 14:28:41 -0800 Subject: [PATCH 2077/2357] nilfs2: fix fix very long mount time issue commit a9bae189542e71f91e61a4428adf6e5a7dfe8063 upstream. There exists a situation when GC can work in background alone without any other filesystem activity during significant time. The nilfs_clean_segments() method calls nilfs_segctor_construct() that updates superblocks in the case of NILFS_SC_SUPER_ROOT and THE_NILFS_DISCONTINUED flags are set. But when GC is working alone the nilfs_clean_segments() is called with unset THE_NILFS_DISCONTINUED flag. As a result, the update of superblocks doesn't occurred all this time and in the case of SPOR superblocks keep very old values of last super root placement. SYMPTOMS: Trying to mount a NILFS2 volume after SPOR in such environment ends with very long mounting time (it can achieve about several hours in some cases). REPRODUCING PATH: 1. It needs to use external USB HDD, disable automount and doesn't make any additional filesystem activity on the NILFS2 volume. 2. Generate temporary file with size about 100 - 500 GB (for example, dd if=/dev/zero of= bs=1073741824 count=200). The size of file defines duration of GC working. 3. Then it needs to delete file. 4. Start GC manually by means of command "nilfs-clean -p 0". When you start GC by means of such way then, at the end, superblocks is updated by once. So, for simulation of SPOR, it needs to wait sometime (15 - 40 minutes) and simply switch off USB HDD manually. 5. Switch on USB HDD again and try to mount NILFS2 volume. As a result, NILFS2 volume will mount during very long time. REPRODUCIBILITY: 100% FIX: This patch adds checking that superblocks need to update and set THE_NILFS_DISCONTINUED flag before nilfs_clean_segments() call. Reported-by: Sergey Alexandrov Signed-off-by: Vyacheslav Dubeyko Tested-by: Vyacheslav Dubeyko Acked-by: Ryusuke Konishi Tested-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/nilfs2/ioctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 6fe98ed5854..37294933891 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -666,8 +666,11 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, if (ret < 0) printk(KERN_ERR "NILFS: GC failed during preparation: " "cannot read source blocks: err=%d\n", ret); - else + else { + if (nilfs_sb_need_update(nilfs)) + set_nilfs_discontinued(nilfs); ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); + } nilfs_remove_all_gcinodes(nilfs); clear_nilfs_gc_running(nilfs); From 1a9277bba9cfcfac12b204dcf72b0cb019b3b65d Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Mon, 4 Feb 2013 14:28:53 -0800 Subject: [PATCH 2078/2357] drivers/rtc/rtc-isl1208.c: call rtc_update_irq() from the alarm irq handler commit 72fca4a4b32dc778b5b885c3498700e42b610d49 upstream. Previously the alarm event was not propagated into the RTC subsystem. By adding a call to rtc_update_irq, this fixes a timeout problem with the hwclock utility. Signed-off-by: Jan Luebbe Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-isl1208.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index dd2aeee6c66..8f8c8ae3523 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -494,6 +494,7 @@ isl1208_rtc_interrupt(int irq, void *data) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); struct i2c_client *client = data; + struct rtc_device *rtc = i2c_get_clientdata(client); int handled = 0, sr, err; /* @@ -516,6 +517,8 @@ isl1208_rtc_interrupt(int irq, void *data) if (sr & ISL1208_REG_SR_ALM) { dev_dbg(&client->dev, "alarm!\n"); + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); + /* Clear the alarm */ sr &= ~ISL1208_REG_SR_ALM; sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr); From 649d7a793033f428bc85430109069dab35fe8782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Kub=C3=A1nek?= Date: Fri, 1 Feb 2013 17:24:04 +0100 Subject: [PATCH 2079/2357] USB: ftdi_sio: add Zolix FTDI PID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0ba3b2ccc72b3df5c305d61f59d93ab0f0e87991 upstream. Add support for Zolix Omni 1509 monochromator custom USB-RS232 converter. Signed-off-by: Petr Kubánek Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3fbf39d66a7..47a9ebc3ff2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -676,6 +676,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) }, { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index fa5d5603827..a8915f3da73 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -147,6 +147,11 @@ #define XSENS_CONVERTER_6_PID 0xD38E #define XSENS_CONVERTER_7_PID 0xD38F +/** + * Zolix (www.zolix.com.cb) product ids + */ +#define FTDI_OMNI1509 0xD491 /* Omni1509 embedded USB-serial */ + /* * NDI (www.ndigital.com) product ids */ From 66a76eb58058527e579bf82aad0a926bac7fcb09 Mon Sep 17 00:00:00 2001 From: Sven Killig Date: Fri, 1 Feb 2013 23:43:06 +0100 Subject: [PATCH 2080/2357] USB: ftdi_sio: add PID/VID entries for ELV WS 300 PC II commit c249f911406efcc7456cb4af79396726bf7b8c57 upstream. Add PID/VID entries for ELV WS 300 PC II weather station Signed-off-by: Sven Killig Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 47a9ebc3ff2..77469442b3f 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -590,6 +590,7 @@ static struct usb_device_id id_table_combined [] = { /* * ELV devices: */ + { USB_DEVICE(FTDI_ELV_VID, FTDI_ELV_WS300_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index a8915f3da73..9d359e189a6 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -209,7 +209,7 @@ /* * ELV USB devices submitted by Christian Abt of ELV (www.elv.de). - * All of these devices use FTDI's vendor ID (0x0403). + * Almost all of these devices use FTDI's vendor ID (0x0403). * Further IDs taken from ELV Windows .inf file. * * The previously included PID for the UO 100 module was incorrect. @@ -217,6 +217,8 @@ * * Armin Laeuger originally sent the PID for the UM 100 module. */ +#define FTDI_ELV_VID 0x1B1F /* ELV AG */ +#define FTDI_ELV_WS300_PID 0xC006 /* eQ3 WS 300 PC II */ #define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */ #define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */ #define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */ From de4399132e911ca24bd642c7a0f659a0d6a35169 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Mon, 28 Jan 2013 16:47:10 +0100 Subject: [PATCH 2081/2357] USB: option: add support for Telit LE920 commit 03eb466f276ceef9dcf023dc5474db02af68aad9 upstream. Add PID and special handling for Telit LE920 Signed-off-by: Daniele Palmas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0778cd09852..d7d8792d8be 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -242,6 +242,7 @@ static void option_instat_callback(struct urb *urb); #define TELIT_PRODUCT_CC864_DUAL 0x1005 #define TELIT_PRODUCT_CC864_SINGLE 0x1006 #define TELIT_PRODUCT_DE910_DUAL 0x1010 +#define TELIT_PRODUCT_LE920 0x1200 /* ZTE PRODUCTS */ #define ZTE_VENDOR_ID 0x19d2 @@ -534,6 +535,11 @@ static const struct option_blacklist_info zte_1255_blacklist = { .reserved = BIT(3) | BIT(4), }; +static const struct option_blacklist_info telit_le920_blacklist = { + .sendsetup = BIT(0), + .reserved = BIT(1) | BIT(5), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -784,6 +790,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), + .driver_info = (kernel_ulong_t)&telit_le920_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, From fdc3c54a639e9acdd5b391283b1e613d1c99de16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Fri, 1 Feb 2013 12:06:51 +0100 Subject: [PATCH 2082/2357] USB: option: add Changhong CH690 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d4fa681541aa7bf8570d03426dd7ba663a71c467 upstream. New device with 3 serial interfaces: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend) Sub=ff Prot=ff If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend) Sub=ff Prot=ff If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend) Sub=ff Prot=ff If#= 3 Alt= 0 #EPs= 2 Cls=08(stor) Sub=06 Prot=50 Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d7d8792d8be..6c077a174bf 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -454,6 +454,10 @@ static void option_instat_callback(struct urb *urb); #define TPLINK_VENDOR_ID 0x2357 #define TPLINK_PRODUCT_MA180 0x0201 +/* Changhong products */ +#define CHANGHONG_VENDOR_ID 0x2077 +#define CHANGHONG_PRODUCT_CH690 0x7001 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -1326,6 +1330,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) }, { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); From 18591ae05a4bc4f505ae5a7d6e58962900226443 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Mon, 28 Jan 2013 16:48:54 +0100 Subject: [PATCH 2083/2357] USB: qcserial: add Telit Gobi QDL device commit 78796ae17eacedcdcaaeb03ba73d2e532a4c8f83 upstream. Add VID and PID for Telit Gobi QDL device Signed-off-by: Daniele Palmas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 50b5371719f..d46277d3307 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -55,6 +55,7 @@ static const struct usb_device_id id_table[] = { {DEVICE_G1K(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ {DEVICE_G1K(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ {DEVICE_G1K(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ + {DEVICE_G1K(0x1bc7, 0x900e)}, /* Telit Gobi QDL device */ /* Gobi 2000 devices */ {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi 2000 QDL device */ From f4cc7a1602ed1bb673cf86b6ccc10f72e1cfaae4 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 25 Jan 2013 17:17:43 -0500 Subject: [PATCH 2084/2357] USB: EHCI: fix timer bug affecting port resume commit ee74290b7853db9d5fd64db70e5c175241c59fba upstream. This patch (as1652) fixes a long-standing bug in ehci-hcd. The driver relies on status polls to know when to stop port-resume signalling. It uses the root-hub status timer to schedule these status polls. But when the driver for the root hub is resumed, the timer is rescheduled to go off immediately -- before the port is ready. When this happens the timer does not get re-enabled, which prevents the port resume from finishing until some other event occurs. The symptom is that when a new device is plugged in, it doesn't get recognized or enumerated until lsusb is run or something else happens. The solution is to re-enable the root-hub status timer after every status poll while a port resume is in progress. This bug hasn't surfaced before now because we never used to try to suspend the root hub in the middle of a port resume (except by coincidence). Signed-off-by: Alan Stern Reported-and-tested-by: Norbert Preining Tested-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hub.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 38fe0762315..3cb52a93803 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -612,7 +612,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) status = STS_PCD; } } - /* FIXME autosuspend idle root hubs */ + + /* If a resume is in progress, make sure it can finish */ + if (ehci->resuming_ports) + mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(25)); + spin_unlock_irqrestore (&ehci->lock, flags); return status ? retval : 0; } From 5b70af1c0b0088151a1e7a8917527e190ddd76d7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Jan 2013 16:36:40 -0500 Subject: [PATCH 2085/2357] USB: EHCI: fix bug in scheduling periodic split transfers commit 3e619d04159be54b3daa0b7036b0ce9e067f4b5d upstream. This patch (as1654) fixes a very old bug in ehci-hcd, connected with scheduling of periodic split transfers. The calculations for full/low-speed bus usage are all carried out after the correction for bit-stuffing has been applied, but the values in the max_tt_usecs array assume it hasn't been. The array should allow for allocation of up to 90% of the bus capacity, which is 900 us, not 780 us. The symptom caused by this bug is that any isochronous transfer to a full-speed device with a maxpacket size larger than about 980 bytes is always rejected with a -ENOSPC error. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a60679cbbf8..14d2d71163f 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -236,7 +236,7 @@ static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask) } static const unsigned char -max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; +max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 125, 25 }; /* carryover low/fullspeed bandwidth that crosses uframe boundries */ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) From 7ad8ac9444d54af92c61c2fa7d02cbf96c990bc5 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 24 Jan 2013 10:31:28 +0800 Subject: [PATCH 2086/2357] usb: Using correct way to clear usb3.0 device's remote wakeup feature. commit 54a3ac0c9e5b7213daa358ce74d154352657353a upstream. Usb3.0 device defines function remote wakeup which is only for interface recipient rather than device recipient. This is different with usb2.0 device's remote wakeup feature which is defined for device recipient. According usb3.0 spec 9.4.5, the function remote wakeup can be modified by the SetFeature() requests using the FUNCTION_SUSPEND feature selector. This patch is to use correct way to disable usb3.0 device's function remote wakeup after suspend error and resuming. This should be backported to kernels as old as 3.4, that contain the commit 623bef9e03a60adc623b09673297ca7a1cdfb367 "USB/xhci: Enable remote wakeup for USB3 devices." Signed-off-by: Lan Tianyu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 70 ++++++++++++++++++++++++++++++----------- include/linux/usb/ch9.h | 6 ++++ 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ef8f790d617..67dda0dbf81 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2463,6 +2463,23 @@ static int check_port_resume_type(struct usb_device *udev, } #ifdef CONFIG_USB_SUSPEND +/* + * usb_disable_function_remotewakeup - disable usb3.0 + * device's function remote wakeup + * @udev: target device + * + * Assume there's only one function on the USB 3.0 + * device and disable remote wake for the first + * interface. FIXME if the interface association + * descriptor shows there's more than one function. + */ +static int usb_disable_function_remotewakeup(struct usb_device *udev) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE, + USB_INTRF_FUNC_SUSPEND, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); +} /* * usb_port_suspend - suspend a usb device's upstream port @@ -2569,12 +2586,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", port1, status); /* paranoia: "should not happen" */ - if (udev->do_remote_wakeup) - (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); + if (udev->do_remote_wakeup) { + if (!hub_is_superspeed(hub->hdev)) { + (void) usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, + USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else + (void) usb_disable_function_remotewakeup(udev); + + } /* Try to enable USB2 hardware LPM again */ if (udev->usb2_hw_lpm_capable == 1) @@ -2661,20 +2685,30 @@ static int finish_port_resume(struct usb_device *udev) * udev->reset_resume */ } else if (udev->actconfig && !udev->reset_resume) { - le16_to_cpus(&devstatus); - if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { - status = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, + if (!hub_is_superspeed(udev->parent)) { + le16_to_cpus(&devstatus); + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) + status = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); - if (status) - dev_dbg(&udev->dev, - "disable remote wakeup, status %d\n", - status); + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else { + status = usb_get_status(udev, USB_RECIP_INTERFACE, 0, + &devstatus); + le16_to_cpus(&devstatus); + if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP + | USB_INTRF_STAT_FUNC_RW)) + status = + usb_disable_function_remotewakeup(udev); } + + if (status) + dev_dbg(&udev->dev, + "disable remote wakeup, status %d\n", + status); status = 0; } return status; diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index af21f311591..091fdb7b9d5 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -150,6 +150,12 @@ #define USB_INTRF_FUNC_SUSPEND_LP (1 << (8 + 0)) #define USB_INTRF_FUNC_SUSPEND_RW (1 << (8 + 1)) +/* + * Interface status, Figure 9-5 USB 3.0 spec + */ +#define USB_INTRF_STAT_FUNC_RW_CAP 1 +#define USB_INTRF_STAT_FUNC_RW 2 + #define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ /* Bit array elements as returned by the USB_REQ_GET_STATUS request. */ From fae3bb5e23fef7eee49545341601a407c090cf88 Mon Sep 17 00:00:00 2001 From: fangxiaozhi Date: Mon, 4 Feb 2013 15:14:46 +0800 Subject: [PATCH 2087/2357] USB: storage: Define a new macro for USB storage match rules commit 07c7be3d87e5cdaf5f94c271c516456364ef286c upstream. 1. Define a new macro for USB storage match rules: matching with Vendor ID and interface descriptors. Signed-off-by: fangxiaozhi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 12 ++++++++++++ drivers/usb/storage/usual-tables.c | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 2653e73db62..e73cf5630f8 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -120,6 +120,17 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); .useTransport = use_transport, \ } +#define UNUSUAL_VENDOR_INTF(idVendor, cl, sc, pr, \ + vendor_name, product_name, use_protocol, use_transport, \ + init_function, Flags) \ +{ \ + .vendorName = vendor_name, \ + .productName = product_name, \ + .useProtocol = use_protocol, \ + .useTransport = use_transport, \ + .initFunction = init_function, \ +} + static struct us_unusual_dev us_unusual_dev_list[] = { # include "unusual_devs.h" { } /* Terminating entry */ @@ -131,6 +142,7 @@ static struct us_unusual_dev for_dynamic_ids = #undef UNUSUAL_DEV #undef COMPLIANT_DEV #undef USUAL_DEV +#undef UNUSUAL_VENDOR_INTF #ifdef CONFIG_LOCKDEP diff --git a/drivers/usb/storage/usual-tables.c b/drivers/usb/storage/usual-tables.c index b96927914f8..a9b5f2e2918 100644 --- a/drivers/usb/storage/usual-tables.c +++ b/drivers/usb/storage/usual-tables.c @@ -46,6 +46,20 @@ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \ .driver_info = ((useType)<<24) } +/* Define the device is matched with Vendor ID and interface descriptors */ +#define UNUSUAL_VENDOR_INTF(id_vendor, cl, sc, pr, \ + vendorName, productName, useProtocol, useTransport, \ + initFunction, flags) \ +{ \ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ + | USB_DEVICE_ID_MATCH_VENDOR, \ + .idVendor = (id_vendor), \ + .bInterfaceClass = (cl), \ + .bInterfaceSubClass = (sc), \ + .bInterfaceProtocol = (pr), \ + .driver_info = (flags) \ +} + struct usb_device_id usb_storage_usb_ids[] = { # include "unusual_devs.h" { } /* Terminating entry */ @@ -57,6 +71,7 @@ MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids); #undef UNUSUAL_DEV #undef COMPLIANT_DEV #undef USUAL_DEV +#undef UNUSUAL_VENDOR_INTF /* From c42fc5a5c545964d97b3c0910ab7c30672155d04 Mon Sep 17 00:00:00 2001 From: fangxiaozhi Date: Mon, 4 Feb 2013 15:16:34 +0800 Subject: [PATCH 2088/2357] USB: storage: optimize to match the Huawei USB storage devices and support new switch command commit 200e0d994d9d1919b28c87f1a5fb99a8e13b8a0f upstream. 1. Optimize the match rules with new macro for Huawei USB storage devices, to avoid to load USB storage driver for the modem interface with Huawei devices. 2. Add to support new switch command for new Huawei USB dongles. Signed-off-by: fangxiaozhi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/initializers.c | 76 ++++++- drivers/usb/storage/initializers.h | 4 +- drivers/usb/storage/unusual_devs.h | 329 +---------------------------- 3 files changed, 78 insertions(+), 331 deletions(-) diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 105d900150c..16b0bf055ee 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -92,8 +92,8 @@ int usb_stor_ucr61s2b_init(struct us_data *us) return 0; } -/* This places the HUAWEI E220 devices in multi-port mode */ -int usb_stor_huawei_e220_init(struct us_data *us) +/* This places the HUAWEI usb dongles in multi-port mode */ +static int usb_stor_huawei_feature_init(struct us_data *us) { int result; @@ -104,3 +104,75 @@ int usb_stor_huawei_e220_init(struct us_data *us) US_DEBUGP("Huawei mode set result is %d\n", result); return 0; } + +/* + * It will send a scsi switch command called rewind' to huawei dongle. + * When the dongle receives this command at the first time, + * it will reboot immediately. After rebooted, it will ignore this command. + * So it is unnecessary to read its response. + */ +static int usb_stor_huawei_scsi_init(struct us_data *us) +{ + int result = 0; + int act_len = 0; + struct bulk_cb_wrap *bcbw = (struct bulk_cb_wrap *) us->iobuf; + char rewind_cmd[] = {0x11, 0x06, 0x20, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + bcbw->Signature = cpu_to_le32(US_BULK_CB_SIGN); + bcbw->Tag = 0; + bcbw->DataTransferLength = 0; + bcbw->Flags = bcbw->Lun = 0; + bcbw->Length = sizeof(rewind_cmd); + memset(bcbw->CDB, 0, sizeof(bcbw->CDB)); + memcpy(bcbw->CDB, rewind_cmd, sizeof(rewind_cmd)); + + result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcbw, + US_BULK_CB_WRAP_LEN, &act_len); + US_DEBUGP("transfer actual length=%d, result=%d\n", act_len, result); + return result; +} + +/* + * It tries to find the supported Huawei USB dongles. + * In Huawei, they assign the following product IDs + * for all of their mobile broadband dongles, + * including the new dongles in the future. + * So if the product ID is not included in this list, + * it means it is not Huawei's mobile broadband dongles. + */ +static int usb_stor_huawei_dongles_pid(struct us_data *us) +{ + struct usb_interface_descriptor *idesc; + int idProduct; + + idesc = &us->pusb_intf->cur_altsetting->desc; + idProduct = us->pusb_dev->descriptor.idProduct; + /* The first port is CDROM, + * means the dongle in the single port mode, + * and a switch command is required to be sent. */ + if (idesc && idesc->bInterfaceNumber == 0) { + if ((idProduct == 0x1001) + || (idProduct == 0x1003) + || (idProduct == 0x1004) + || (idProduct >= 0x1401 && idProduct <= 0x1500) + || (idProduct >= 0x1505 && idProduct <= 0x1600) + || (idProduct >= 0x1c02 && idProduct <= 0x2202)) { + return 1; + } + } + return 0; +} + +int usb_stor_huawei_init(struct us_data *us) +{ + int result = 0; + + if (usb_stor_huawei_dongles_pid(us)) { + if (us->pusb_dev->descriptor.idProduct >= 0x1446) + result = usb_stor_huawei_scsi_init(us); + else + result = usb_stor_huawei_feature_init(us); + } + return result; +} diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index 529327fbb06..5376d4fc76f 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -46,5 +46,5 @@ int usb_stor_euscsi_init(struct us_data *us); * flash reader */ int usb_stor_ucr61s2b_init(struct us_data *us); -/* This places the HUAWEI E220 devices in multi-port mode */ -int usb_stor_huawei_e220_init(struct us_data *us); +/* This places the HUAWEI usb dongles in multi-port mode */ +int usb_stor_huawei_init(struct us_data *us); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 5ffa11640de..27858f9a20e 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1515,335 +1515,10 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, /* Reported by fangxiaozhi * This brings the HUAWEI data card devices into multi-port mode */ -UNUSUAL_DEV( 0x12d1, 0x1001, 0x0000, 0x0000, +UNUSUAL_VENDOR_INTF(0x12d1, 0x08, 0x06, 0x50, "HUAWEI MOBILE", "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1004, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1401, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1402, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1403, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1404, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1405, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1406, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1407, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1408, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1409, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1410, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1411, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1412, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1413, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1414, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1415, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1416, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1417, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1418, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1419, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1420, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1421, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1422, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1423, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1424, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1425, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1426, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1427, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1428, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1429, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1430, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1431, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1432, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1433, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1434, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1435, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1436, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1437, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1438, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1439, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, + USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_init, 0), /* Reported by Vilius Bilinkevicius Date: Mon, 7 Jan 2013 22:39:31 -0500 Subject: [PATCH 2089/2357] drivers: xhci: fix incorrect bit test commit ba7b5c22d33136a5612ca5ef8d31564dcc501126 upstream. Fix incorrect bit test that originally showed up in 4ee823b83bc9851743fab756c76b27d6a1e2472b "USB/xHCI: Support device-initiated USB 3.0 resume." Use '&' instead of '&&'. This should be backported to kernels as old as 3.4. Signed-off-by: Nickolai Zeldovich Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 01361f929f1..59cdde9d604 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1698,7 +1698,7 @@ static void handle_port_status(struct xhci_hcd *xhci, faked_port_index + 1); if (slot_id && xhci->devs[slot_id]) xhci_ring_device(xhci, slot_id); - if (bus_state->port_remote_wakeup && (1 << faked_port_index)) { + if (bus_state->port_remote_wakeup & (1 << faked_port_index)) { bus_state->port_remote_wakeup &= ~(1 << faked_port_index); xhci_test_and_clear_bit(xhci, port_array, From 1757e241ae2c9758bd983250b94328bddeff8760 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 11 Jan 2013 11:19:07 -0800 Subject: [PATCH 2090/2357] xhci: Fix isoc TD encoding. commit 760973d2a74b93eb1697981f7448f0e62767cfc4 upstream. An isochronous TD is comprised of one isochronous TRB chained to zero or more normal TRBs. Only the isoc TRB has the TBC and TLBPC fields. The normal TRBs must set those fields to zeroes. The code was setting the TBC and TLBPC fields for both isoc and normal TRBs. Fix this. This should be backported to stable kernels as old as 3.0, that contain the commit b61d378f2da41c748aba6ca19d77e1e1c02bcea5 " xhci 1.0: Set transfer burst last packet count field." Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 59cdde9d604..834929f6405 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3662,9 +3662,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, td = urb_priv->td[i]; for (j = 0; j < trbs_per_td; j++) { u32 remainder = 0; - field = TRB_TBC(burst_count) | TRB_TLBPC(residue); + field = 0; if (first_trb) { + field = TRB_TBC(burst_count) | + TRB_TLBPC(residue); /* Queue the isoc TRB */ field |= TRB_TYPE(TRB_ISOC); /* Assume URB_ISO_ASAP is set */ From d018dbbf6e7e3d588b09273c38ea57bc666d474c Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 11 Jan 2013 13:36:35 -0800 Subject: [PATCH 2091/2357] xhci: Fix TD size for isochronous URBs. commit f18f8ed2a9adc41c2d9294b85b6af115829d2af1 upstream. To calculate the TD size for a particular TRB in an isoc TD, we need know the endpoint's max packet size. Isochronous endpoints also encode the number of additional service opportunities in their wMaxPacketSize field. The TD size calculation did not mask off those bits before using the field. This resulted in incorrect TD size information for isochronous TRBs when an URB frame buffer crossed a 64KB boundary. For example: - an isoc endpoint has 2 additional service opportunites and a max packet size of 1020 bytes - a frame transfer buffer contains 3060 bytes - one frame buffer crosses a 64KB boundary, and must be split into one 1276 byte TRB, and one 1784 byte TRB. The TD size is is the number of packets that remain to be transferred for a TD after processing all the max packet sized packets in the current TRB and all previous TRBs. For this TD, the number of packets to be transferred is (3060 / 1020), or 3. The first TRB contains 1276 bytes, which means it contains one full packet, and a 256 byte remainder. After processing all the max packet-sized packets in the first TRB, the host will have 2 packets left to transfer. The old code would calculate the TD size for the first TRB as: total packet count = DIV_ROUND_UP (TD length / endpoint wMaxPacketSize) total packet count - (first TRB length / endpoint wMaxPacketSize) The math should have been: total packet count = DIV_ROUND_UP (3060 / 1020) = 3 3 - (1276 / 1020) = 2 Since the old code didn't mask off the additional service interval bits from the wMaxPacketSize field, the math ended up as total packet count = DIV_ROUND_UP (3060 / 5116) = 1 1 - (1276 / 5116) = 1 Fix this by masking off the number of additional service opportunities in the wMaxPacketSize field. This patch should be backported to stable kernels as old as 3.0, that contain the commit 4da6e6f247a2601ab9f1e63424e4d944ed4124f3 "xhci 1.0: Update TD size field format." It may not apply well to kernels older than 3.2 because of commit 29cc88979a8818cd8c5019426e945aed118b400e "USB: use usb_endpoint_maxp() instead of le16_to_cpu()". Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 834929f6405..8e2169496a9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3106,7 +3106,7 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len, * running_total. */ packets_transferred = (running_total + trb_buff_len) / - usb_endpoint_maxp(&urb->ep->desc); + GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc)); if ((total_packet_count - packets_transferred) > 31) return 31 << 17; @@ -3640,7 +3640,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, td_len = urb->iso_frame_desc[i].length; td_remain_len = td_len; total_packet_count = DIV_ROUND_UP(td_len, - usb_endpoint_maxp(&urb->ep->desc)); + GET_MAX_PACKET( + usb_endpoint_maxp(&urb->ep->desc))); /* A zero-length transfer still involves at least one packet. */ if (total_packet_count == 0) total_packet_count++; From 235b62026c1f73decda124912930e322dc8ec57d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Jan 2013 10:32:16 -0500 Subject: [PATCH 2092/2357] USB: XHCI: fix memory leak of URB-private data commit 48c3375c5f69b1c2ef3d1051a0009cb9bce0ce24 upstream. This patch (as1640) fixes a memory leak in xhci-hcd. The urb_priv data structure isn't always deallocated in the handle_tx_event() routine for non-control transfers. The patch adds a kfree() call so that all paths end up freeing the memory properly. This patch should be backported to kernels as old as 2.6.36, that contain the commit 8e51adccd4c4b9ffcd509d7f2afce0a906139f75 "USB: xHCI: Introduce urb_priv structure" Signed-off-by: Alan Stern Signed-off-by: Sarah Sharp Reported-and-tested-by: Martin Mokrejs Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 8e2169496a9..87ee86d6fbf 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2587,6 +2587,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, (trb_comp_code != COMP_STALL && trb_comp_code != COMP_BABBLE)) xhci_urb_free_priv(xhci, urb_priv); + else + kfree(urb_priv); usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); if ((urb->actual_length != urb->transfer_buffer_length && From b4e8be42e038f1b931a44bc93050f8a261b495a1 Mon Sep 17 00:00:00 2001 From: David Moore Date: Wed, 23 Jan 2013 22:19:49 -0800 Subject: [PATCH 2093/2357] usb: Prevent dead ports when xhci is not enabled commit 58b2939b4d5a030eaec469d29812ab8477ee7e76 upstream. When the xHCI driver is not available, actively switch the ports to EHCI mode since some BIOSes leave them in xHCI mode where they would otherwise appear dead. This was discovered on a Dell Optiplex 7010, but it's possible other systems could be affected. This should be backported to kernels as old as 3.0, that contain the commit 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support EHCI/xHCI port switching." Signed-off-by: David Moore Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index eb5563ac58b..78933512c18 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -780,6 +780,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) "defaulting to EHCI.\n"); dev_warn(&xhci_pdev->dev, "USB 3.0 devices will work at USB 2.0 speeds.\n"); + usb_disable_xhci_ports(xhci_pdev); return; } From c74d85ba3bdb907d23419c77e43a5d6800bafa84 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 11 Feb 2013 08:47:55 -0800 Subject: [PATCH 2094/2357] Linux 3.4.30 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 23bcb1a6604..4941fd9876e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 29 +SUBLEVEL = 30 EXTRAVERSION = NAME = Saber-toothed Squirrel From 5f2ffd29fe0438dfb683a8f0ca0e451408e36970 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 27 Jan 2013 16:24:25 -0600 Subject: [PATCH 2095/2357] rtlwifi: Fix the usage of the wrong variable in usb.c commit 0a06ad8e3a1cb5311b7dbafde45410aa1bce9d40 upstream. In routine _rtl_rx_pre_process(), skb_dequeue() is called to get an skb; however, the wrong variable name is used in subsequent calls. Reported-by: Guenter Roeck Signed-off-by: Larry Finger Cc: Guenter Roeck Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 8fa144fa0c9..17cd028d235 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -542,8 +542,8 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) WARN_ON(skb_queue_empty(&rx_queue)); while (!skb_queue_empty(&rx_queue)) { _skb = skb_dequeue(&rx_queue); - _rtl_usb_rx_process_agg(hw, skb); - ieee80211_rx_irqsafe(hw, skb); + _rtl_usb_rx_process_agg(hw, _skb); + ieee80211_rx_irqsafe(hw, _skb); } } From 5327297d3596654ca58e8a79ec38fa48c8f83fc0 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 2 Feb 2013 15:55:00 -0600 Subject: [PATCH 2096/2357] rtlwifi: Fix scheduling while atomic bug commit a5ffbe0a1993a27072742ef7db6cf9839956fce9 upstream. Kernel commits 41affd5 and 6539306 changed the locking in rtl_lps_leave() from a spinlock to a mutex by doing the calls indirectly from a work queue to reduce the time that interrupts were disabled. This change was fine for most systems; however a scheduling while atomic bug was reported in https://bugzilla.redhat.com/show_bug.cgi?id=903881. The backtrace indicates that routine rtl_is_special(), which calls rtl_lps_leave() in three places was entered in atomic context. These direct calls are replaced by putting a request on the appropriate work queue. Signed-off-by: Larry Finger Reported-and-tested-by: Nathaniel Doherty Cc: Nathaniel Doherty Cc: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/base.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index e54488db0e1..18d9eb3ad7a 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -980,7 +980,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) is_tx ? "Tx" : "Rx"); if (is_tx) { - rtl_lps_leave(hw); + schedule_work(&rtlpriv-> + works.lps_leave_work); ppsc->last_delaylps_stamp_jiffies = jiffies; } @@ -990,7 +991,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) } } else if (ETH_P_ARP == ether_type) { if (is_tx) { - rtl_lps_leave(hw); + schedule_work(&rtlpriv->works.lps_leave_work); ppsc->last_delaylps_stamp_jiffies = jiffies; } @@ -1000,7 +1001,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx"); if (is_tx) { - rtl_lps_leave(hw); + schedule_work(&rtlpriv->works.lps_leave_work); ppsc->last_delaylps_stamp_jiffies = jiffies; } From 0b2d4e113bf714732b041aa879945c4c5ae4b139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Date: Tue, 22 Jan 2013 09:50:26 +1030 Subject: [PATCH 2097/2357] virtio_console: Don't access uninitialized data. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit aded024a12b32fc1ed9a80639681daae2d07ec25 upstream. Don't access uninitialized work-queue when removing device. The work queue is initialized only if the device multi-queue. So don't call cancel_work unless this is a multi-queue device. This fixes the following panic: Kernel panic - not syncing: BUG! Call Trace: 62031b28: [<6026085d>] panic+0x16b/0x2d3 62031b30: [<6004ef5e>] flush_work+0x0/0x1d7 62031b60: [<602606f2>] panic+0x0/0x2d3 62031b68: [<600333b0>] memcpy+0x0/0x140 62031b80: [<6002d58a>] unblock_signals+0x0/0x84 62031ba0: [<602609c5>] printk+0x0/0xa0 62031bd8: [<60264e51>] __mutex_unlock_slowpath+0x13d/0x148 62031c10: [<6004ef5e>] flush_work+0x0/0x1d7 62031c18: [<60050234>] try_to_grab_pending+0x0/0x17e 62031c38: [<6004e984>] get_work_gcwq+0x71/0x8f 62031c48: [<60050539>] __cancel_work_timer+0x5b/0x115 62031c78: [<628acc85>] unplug_port+0x0/0x191 [virtio_console] 62031c98: [<6005061c>] cancel_work_sync+0x12/0x14 62031ca8: [<628ace96>] virtcons_remove+0x80/0x15c [virtio_console] 62031ce8: [<628191de>] virtio_dev_remove+0x1e/0x7e [virtio] 62031d08: [<601cf242>] __device_release_driver+0x75/0xe4 62031d28: [<601cf2dd>] device_release_driver+0x2c/0x40 62031d48: [<601ce0dd>] driver_unbind+0x7d/0xc6 62031d88: [<601cd5d9>] drv_attr_store+0x27/0x29 62031d98: [<60115f61>] sysfs_write_file+0x100/0x14d 62031df8: [<600b737d>] vfs_write+0xcb/0x184 62031e08: [<600b58b8>] filp_close+0x88/0x94 62031e38: [<600b7686>] sys_write+0x59/0x88 62031e88: [<6001ced1>] handle_syscall+0x5d/0x80 62031ea8: [<60030a74>] userspace+0x405/0x531 62031f08: [<600d32cc>] sys_dup+0x0/0x5e 62031f28: [<601b11d6>] strcpy+0x0/0x18 62031f38: [<600be46c>] do_execve+0x10/0x12 62031f48: [<600184c7>] run_init_process+0x43/0x45 62031fd8: [<60019a91>] new_thread_handler+0xba/0xbc Signed-off-by: Sjur Brændeland Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f5451c7..f77e341631d 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1808,7 +1808,8 @@ static void virtcons_remove(struct virtio_device *vdev) /* Disable interrupts for vqs */ vdev->config->reset(vdev); /* Finish up work that's lined up */ - cancel_work_sync(&portdev->control_work); + if (use_multiport(portdev)) + cancel_work_sync(&portdev->control_work); list_for_each_entry_safe(port, port2, &portdev->ports, list) unplug_port(port); From 7308f843f36c30dd1247989a45611760567ea44f Mon Sep 17 00:00:00 2001 From: T Makphaibulchoke Date: Thu, 4 Oct 2012 17:16:55 -0700 Subject: [PATCH 2098/2357] kernel/resource.c: fix stack overflow in __reserve_region_with_split() commit 4965f5667f36a95b41cda6638875bc992bd7d18b upstream. Using a recursive call add a non-conflicting region in __reserve_region_with_split() could result in a stack overflow in the case that the recursive calls are too deep. Convert the recursive calls to an iterative loop to avoid the problem. Tested on a machine containing 135 regions. The kernel no longer panicked with stack overflow. Also tested with code arbitrarily adding regions with no conflict, embedding two consecutive conflicts and embedding two non-consecutive conflicts. Signed-off-by: T Makphaibulchoke Reviewed-by: Ram Pai Cc: Paul Gortmaker Cc: Wei Yang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- kernel/resource.c | 50 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/kernel/resource.c b/kernel/resource.c index 7e8ea66a8c0..bfe96b83497 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -758,6 +758,7 @@ static void __init __reserve_region_with_split(struct resource *root, struct resource *parent = root; struct resource *conflict; struct resource *res = kzalloc(sizeof(*res), GFP_ATOMIC); + struct resource *next_res = NULL; if (!res) return; @@ -767,21 +768,46 @@ static void __init __reserve_region_with_split(struct resource *root, res->end = end; res->flags = IORESOURCE_BUSY; - conflict = __request_resource(parent, res); - if (!conflict) - return; + while (1) { - /* failed, split and try again */ - kfree(res); + conflict = __request_resource(parent, res); + if (!conflict) { + if (!next_res) + break; + res = next_res; + next_res = NULL; + continue; + } - /* conflict covered whole area */ - if (conflict->start <= start && conflict->end >= end) - return; + /* conflict covered whole area */ + if (conflict->start <= res->start && + conflict->end >= res->end) { + kfree(res); + WARN_ON(next_res); + break; + } + + /* failed, split and try again */ + if (conflict->start > res->start) { + end = res->end; + res->end = conflict->start - 1; + if (conflict->end < end) { + next_res = kzalloc(sizeof(*next_res), + GFP_ATOMIC); + if (!next_res) { + kfree(res); + break; + } + next_res->name = name; + next_res->start = conflict->end + 1; + next_res->end = end; + next_res->flags = IORESOURCE_BUSY; + } + } else { + res->start = conflict->end + 1; + } + } - if (conflict->start > start) - __reserve_region_with_split(root, start, conflict->start-1, name); - if (conflict->end < end) - __reserve_region_with_split(root, conflict->end+1, end, name); } void __init reserve_region_with_split(struct resource *root, From a256a4c2001293548f0851b66ea8f39b704bac72 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 29 Jan 2013 10:44:23 -0600 Subject: [PATCH 2099/2357] Bluetooth: Fix handling of unexpected SMP PDUs commit 8cf9fa1240229cbdd888236c0c43fcbad680cf00 upstream. The conn->smp_chan pointer can be NULL if SMP PDUs arrive at unexpected moments. To avoid NULL pointer dereferences the code should be checking for this and disconnect if an unexpected SMP PDU arrives. This patch fixes the issue by adding a check for conn->smp_chan for all other PDUs except pairing request and security request (which are are the first PDUs to come to initialize the SMP context). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/smp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 208edc0cc60..605156f1389 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -852,6 +852,19 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) skb_pull(skb, sizeof(code)); + /* + * The SMP context must be initialized for all other PDUs except + * pairing and security requests. If we get any other PDU when + * not initialized simply disconnect (done if this function + * returns an error). + */ + if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && + !conn->smp_chan) { + BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); + kfree_skb(skb); + return -ENOTSUPP; + } + switch (code) { case SMP_CMD_PAIRING_REQ: reason = smp_cmd_pairing_req(conn, skb); From 739230186fa9d6999f88c53f0cb6d07ed4234fb0 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Wed, 14 Nov 2012 09:42:35 +0000 Subject: [PATCH 2100/2357] efi: Make 'efi_enabled' a function to query EFI facilities commit 83e68189745ad931c2afd45d8ee3303929233e7f upstream. Originally 'efi_enabled' indicated whether a kernel was booted from EFI firmware. Over time its semantics have changed, and it now indicates whether or not we are booted on an EFI machine with bit-native firmware, e.g. 64-bit kernel with 64-bit firmware. The immediate motivation for this patch is the bug report at, https://bugs.launchpad.net/ubuntu-cdimage/+bug/1040557 which details how running a platform driver on an EFI machine that is designed to run under BIOS can cause the machine to become bricked. Also, the following report, https://bugzilla.kernel.org/show_bug.cgi?id=47121 details how running said driver can also cause Machine Check Exceptions. Drivers need a new means of detecting whether they're running on an EFI machine, as sadly the expression, if (!efi_enabled) hasn't been a sufficient condition for quite some time. Users actually want to query 'efi_enabled' for different reasons - what they really want access to is the list of available EFI facilities. For instance, the x86 reboot code needs to know whether it can invoke the ResetSystem() function provided by the EFI runtime services, while the ACPI OSL code wants to know whether the EFI config tables were mapped successfully. There are also checks in some of the platform driver code to simply see if they're running on an EFI machine (which would make it a bad idea to do BIOS-y things). This patch is a prereq for the samsung-laptop fix patch. Signed-off-by: Matt Fleming Cc: David Airlie Cc: Corentin Chary Cc: Matthew Garrett Cc: Dave Jiang Cc: Olof Johansson Cc: Peter Jones Cc: Colin Ian King Cc: Steve Langasek Cc: Tony Luck Cc: Konrad Rzeszutek Wilk Cc: Rafael J. Wysocki Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/efi.h | 1 + arch/x86/kernel/reboot.c | 2 +- arch/x86/kernel/setup.c | 28 ++++++------- arch/x86/platform/efi/efi.c | 57 +++++++++++++++----------- drivers/acpi/osl.c | 2 +- drivers/firmware/dmi_scan.c | 2 +- drivers/firmware/efivars.c | 4 +- drivers/firmware/iscsi_ibft_find.c | 2 +- drivers/gpu/drm/radeon/radeon_device.c | 3 +- drivers/platform/x86/ibm_rtl.c | 2 +- drivers/scsi/isci/init.c | 2 +- include/linux/efi.h | 24 ++++++++--- init/main.c | 4 +- 13 files changed, 79 insertions(+), 54 deletions(-) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 029189db84d..da37433e362 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -94,6 +94,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, #endif /* CONFIG_X86_32 */ extern int add_efi_memmap; +extern unsigned long x86_efi_facility; extern void efi_set_executable(efi_memory_desc_t *md, bool executable); extern int efi_memblock_x86_reserve_range(void); extern void efi_call_phys_prelog(void); diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 3034ee5afb0..df1b604c0c1 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -619,7 +619,7 @@ static void native_machine_emergency_restart(void) break; case BOOT_EFI: - if (efi_enabled) + if (efi_enabled(EFI_RUNTIME_SERVICES)) efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD, diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index b71e4a533cc..537dc033868 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -818,15 +818,15 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_EFI if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, "EL32", 4)) { - efi_enabled = 1; - efi_64bit = false; + set_bit(EFI_BOOT, &x86_efi_facility); } else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, "EL64", 4)) { - efi_enabled = 1; - efi_64bit = true; + set_bit(EFI_BOOT, &x86_efi_facility); + set_bit(EFI_64BIT, &x86_efi_facility); } - if (efi_enabled && efi_memblock_x86_reserve_range()) - efi_enabled = 0; + + if (efi_enabled(EFI_BOOT)) + efi_memblock_x86_reserve_range(); #endif x86_init.oem.arch_setup(); @@ -899,7 +899,7 @@ void __init setup_arch(char **cmdline_p) finish_e820_parsing(); - if (efi_enabled) + if (efi_enabled(EFI_BOOT)) efi_init(); dmi_scan_machine(); @@ -982,7 +982,7 @@ void __init setup_arch(char **cmdline_p) * The EFI specification says that boot service code won't be called * after ExitBootServices(). This is, in fact, a lie. */ - if (efi_enabled) + if (efi_enabled(EFI_MEMMAP)) efi_reserve_boot_services(); /* preallocate 4k for mptable mpc */ @@ -1119,7 +1119,7 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) - if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY)) + if (!efi_enabled(EFI_BOOT) || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY)) conswitchp = &vga_con; #elif defined(CONFIG_DUMMY_CONSOLE) conswitchp = &dummy_con; @@ -1136,14 +1136,14 @@ void __init setup_arch(char **cmdline_p) arch_init_ideal_nops(); #ifdef CONFIG_EFI - /* Once setup is done above, disable efi_enabled on mismatched - * firmware/kernel archtectures since there is no support for - * runtime services. + /* Once setup is done above, unmap the EFI memory map on + * mismatched firmware/kernel archtectures since there is no + * support for runtime services. */ - if (efi_enabled && IS_ENABLED(CONFIG_X86_64) != efi_64bit) { + if (efi_enabled(EFI_BOOT) && + IS_ENABLED(CONFIG_X86_64) != efi_enabled(EFI_64BIT)) { pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n"); efi_unmap_memmap(); - efi_enabled = 0; } #endif } diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 6825327d00a..6fcd4ad9bb6 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -50,9 +50,6 @@ #define EFI_DEBUG 1 -int efi_enabled; -EXPORT_SYMBOL(efi_enabled); - struct efi __read_mostly efi = { .mps = EFI_INVALID_TABLE_ADDR, .acpi = EFI_INVALID_TABLE_ADDR, @@ -68,19 +65,28 @@ EXPORT_SYMBOL(efi); struct efi_memory_map memmap; -bool efi_64bit; - static struct efi efi_phys __initdata; static efi_system_table_t efi_systab __initdata; static inline bool efi_is_native(void) { - return IS_ENABLED(CONFIG_X86_64) == efi_64bit; + return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT); +} + +unsigned long x86_efi_facility; + +/* + * Returns 1 if 'facility' is enabled, 0 otherwise. + */ +int efi_enabled(int facility) +{ + return test_bit(facility, &x86_efi_facility) != 0; } +EXPORT_SYMBOL(efi_enabled); static int __init setup_noefi(char *arg) { - efi_enabled = 0; + clear_bit(EFI_BOOT, &x86_efi_facility); return 0; } early_param("noefi", setup_noefi); @@ -425,6 +431,7 @@ void __init efi_reserve_boot_services(void) void __init efi_unmap_memmap(void) { + clear_bit(EFI_MEMMAP, &x86_efi_facility); if (memmap.map) { early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); memmap.map = NULL; @@ -459,7 +466,7 @@ void __init efi_free_boot_services(void) static int __init efi_systab_init(void *phys) { - if (efi_64bit) { + if (efi_enabled(EFI_64BIT)) { efi_system_table_64_t *systab64; u64 tmp = 0; @@ -551,7 +558,7 @@ static int __init efi_config_init(u64 tables, int nr_tables) void *config_tables, *tablep; int i, sz; - if (efi_64bit) + if (efi_enabled(EFI_64BIT)) sz = sizeof(efi_config_table_64_t); else sz = sizeof(efi_config_table_32_t); @@ -571,7 +578,7 @@ static int __init efi_config_init(u64 tables, int nr_tables) efi_guid_t guid; unsigned long table; - if (efi_64bit) { + if (efi_enabled(EFI_64BIT)) { u64 table64; guid = ((efi_config_table_64_t *)tablep)->guid; table64 = ((efi_config_table_64_t *)tablep)->table; @@ -683,7 +690,6 @@ void __init efi_init(void) if (boot_params.efi_info.efi_systab_hi || boot_params.efi_info.efi_memmap_hi) { pr_info("Table located above 4GB, disabling EFI.\n"); - efi_enabled = 0; return; } efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; @@ -693,10 +699,10 @@ void __init efi_init(void) ((__u64)boot_params.efi_info.efi_systab_hi<<32)); #endif - if (efi_systab_init(efi_phys.systab)) { - efi_enabled = 0; + if (efi_systab_init(efi_phys.systab)) return; - } + + set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility); /* * Show what we know for posterity @@ -714,10 +720,10 @@ void __init efi_init(void) efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor); - if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) { - efi_enabled = 0; + if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) return; - } + + set_bit(EFI_CONFIG_TABLES, &x86_efi_facility); /* * Note: We currently don't support runtime services on an EFI @@ -726,15 +732,17 @@ void __init efi_init(void) if (!efi_is_native()) pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); - else if (efi_runtime_init()) { - efi_enabled = 0; - return; + else { + if (efi_runtime_init()) + return; + set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility); } - if (efi_memmap_init()) { - efi_enabled = 0; + if (efi_memmap_init()) return; - } + + set_bit(EFI_MEMMAP, &x86_efi_facility); + #ifdef CONFIG_X86_32 if (efi_is_native()) { x86_platform.get_wallclock = efi_get_time; @@ -943,6 +951,9 @@ u64 efi_mem_attributes(unsigned long phys_addr) efi_memory_desc_t *md; void *p; + if (!efi_enabled(EFI_MEMMAP)) + return 0; + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { md = p; if ((md->phys_addr <= phys_addr) && diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c3881b2eb8b..f48720cf96f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -250,7 +250,7 @@ acpi_physical_address __init acpi_os_get_root_pointer(void) return acpi_rsdp; #endif - if (efi_enabled) { + if (efi_enabled(EFI_CONFIG_TABLES)) { if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) return efi.acpi20; else if (efi.acpi != EFI_INVALID_TABLE_ADDR) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index fd3ae6290d7..982f1f5f574 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -471,7 +471,7 @@ void __init dmi_scan_machine(void) char __iomem *p, *q; int rc; - if (efi_enabled) { + if (efi_enabled(EFI_CONFIG_TABLES)) { if (efi.smbios == EFI_INVALID_TABLE_ADDR) goto error; diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index d10c9873dd9..bfd8f439249 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -1224,7 +1224,7 @@ efivars_init(void) printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, EFIVARS_DATE); - if (!efi_enabled) + if (!efi_enabled(EFI_RUNTIME_SERVICES)) return 0; /* For now we'll register the efi directory at /sys/firmware/efi */ @@ -1262,7 +1262,7 @@ efivars_init(void) static void __exit efivars_exit(void) { - if (efi_enabled) { + if (efi_enabled(EFI_RUNTIME_SERVICES)) { unregister_efivars(&__efivars); kobject_put(efi_kobj); } diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index 4da4eb9ae92..2224f1dc074 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -99,7 +99,7 @@ unsigned long __init find_ibft_region(unsigned long *sizep) /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will * only use ACPI for this */ - if (!efi_enabled) + if (!efi_enabled(EFI_BOOT)) find_ibft_in_mem(); if (ibft_addr) { diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index de5e0b51dc6..68c89dbfd97 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -358,7 +358,8 @@ bool radeon_card_posted(struct radeon_device *rdev) { uint32_t reg; - if (efi_enabled && rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) + if (efi_enabled(EFI_BOOT) && + rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) return false; /* first check CRTCs */ diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 7481146a5b4..97c2be195ef 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c @@ -244,7 +244,7 @@ static int __init ibm_rtl_init(void) { if (force) pr_warn("module loaded by force\n"); /* first ensure that we are running on IBM HW */ - else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table)) + else if (efi_enabled(EFI_BOOT) || !dmi_check_system(ibm_rtl_dmi_table)) return -ENODEV; /* Get the address for the Extended BIOS Data Area */ diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 4c150dffb1a..5a1bd0ca2bb 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -470,7 +470,7 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic return -ENOMEM; pci_set_drvdata(pdev, pci_info); - if (efi_enabled) + if (efi_enabled(EFI_RUNTIME_SERVICES)) orom = isci_get_efi_var(pdev); if (!orom) diff --git a/include/linux/efi.h b/include/linux/efi.h index 5782114f483..eee8b0b190e 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -539,18 +539,30 @@ extern int __init efi_setup_pcdp_console(char *); #endif /* - * We play games with efi_enabled so that the compiler will, if possible, remove - * EFI-related code altogether. + * We play games with efi_enabled so that the compiler will, if + * possible, remove EFI-related code altogether. */ +#define EFI_BOOT 0 /* Were we booted from EFI? */ +#define EFI_SYSTEM_TABLES 1 /* Can we use EFI system tables? */ +#define EFI_CONFIG_TABLES 2 /* Can we use EFI config tables? */ +#define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */ +#define EFI_MEMMAP 4 /* Can we use EFI memory map? */ +#define EFI_64BIT 5 /* Is the firmware 64-bit? */ + #ifdef CONFIG_EFI # ifdef CONFIG_X86 - extern int efi_enabled; - extern bool efi_64bit; +extern int efi_enabled(int facility); # else -# define efi_enabled 1 +static inline int efi_enabled(int facility) +{ + return 1; +} # endif #else -# define efi_enabled 0 +static inline int efi_enabled(int facility) +{ + return 0; +} #endif /* diff --git a/init/main.c b/init/main.c index c2178d267c1..02c13846578 100644 --- a/init/main.c +++ b/init/main.c @@ -602,7 +602,7 @@ asmlinkage void __init start_kernel(void) pidmap_init(); anon_vma_init(); #ifdef CONFIG_X86 - if (efi_enabled) + if (efi_enabled(EFI_RUNTIME_SERVICES)) efi_enter_virtual_mode(); #endif thread_info_cache_init(); @@ -630,7 +630,7 @@ asmlinkage void __init start_kernel(void) acpi_early_init(); /* before LAPIC and SMP init */ sfi_init_late(); - if (efi_enabled) + if (efi_enabled(EFI_RUNTIME_SERVICES)) efi_free_boot_services(); ftrace_init(); From 7f8d73f9e71d58187f42d26088578be5d2d70859 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 3 Jan 2013 09:02:37 +0000 Subject: [PATCH 2101/2357] samsung-laptop: Disable on EFI hardware commit e0094244e41c4d0c7ad69920681972fc45d8ce34 upstream. It has been reported that running this driver on some Samsung laptops with EFI can cause those machines to become bricked as detailed in the following report, https://bugs.launchpad.net/ubuntu-cdimage/+bug/1040557 There have also been reports of this driver causing Machine Check Exceptions on recent EFI-enabled Samsung laptops, https://bugzilla.kernel.org/show_bug.cgi?id=47121 So disable it if booting from EFI since this driver relies on grovelling around in the BIOS memory map which isn't going to work. Signed-off-by: Matt Fleming Cc: Corentin Chary Cc: Matthew Garrett Cc: Colin Ian King Cc: Steve Langasek Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/samsung-laptop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 1afbe5e0a34..de9f432cf22 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -26,6 +26,7 @@ #include #include #include +#include #if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE) #include #endif @@ -1527,6 +1528,9 @@ static int __init samsung_init(void) struct samsung_laptop *samsung; int ret; + if (efi_enabled(EFI_BOOT)) + return -ENODEV; + quirks = &samsung_unknown; if (!force && !dmi_check_system(samsung_dmi_table)) return -ENODEV; From 0ad715758022062a34bccede6200803e26480c97 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Mon, 7 Jan 2013 21:17:00 +0000 Subject: [PATCH 2102/2357] net: prevent setting ttl=0 via IP_TTL [ Upstream commit c9be4a5c49cf51cc70a993f004c5bb30067a65ce ] A regression is introduced by the following commit: commit 4d52cfbef6266092d535237ba5a4b981458ab171 Author: Eric Dumazet Date: Tue Jun 2 00:42:16 2009 -0700 net: ipv4/ip_sockglue.c cleanups Pure cleanups but it is not a pure cleanup... - if (val != -1 && (val < 1 || val>255)) + if (val != -1 && (val < 0 || val > 255)) Since there is no reason provided to allow ttl=0, change it back. Reported-by: nitin padalia Cc: nitin padalia Cc: Eric Dumazet Cc: David S. Miller Signed-off-by: Cong Wang Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_sockglue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 59ef40abf50..37482848700 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -589,7 +589,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, case IP_TTL: if (optlen < 1) goto e_inval; - if (val != -1 && (val < 0 || val > 255)) + if (val != -1 && (val < 1 || val > 255)) goto e_inval; inet->uc_ttl = val; break; From 3b69055b43c57783a8bf99a8e40f773580e451a1 Mon Sep 17 00:00:00 2001 From: Romain Kuntz Date: Wed, 9 Jan 2013 15:02:26 +0100 Subject: [PATCH 2103/2357] ipv6: fix the noflags test in addrconf_get_prefix_route [ Upstream commit 85da53bf1c336bb07ac038fb951403ab0478d2c5 ] The tests on the flags in addrconf_get_prefix_route() does no make much sense: the 'noflags' parameter contains the set of flags that must not match with the route flags, so the test must be done against 'noflags', and not against 'flags'. Signed-off-by: Romain Kuntz Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/addrconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 468a5ce6e9d..81e0ad2442c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1736,7 +1736,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, continue; if ((rt->rt6i_flags & flags) != flags) continue; - if ((noflags != 0) && ((rt->rt6i_flags & flags) != 0)) + if ((rt->rt6i_flags & noflags) != 0) continue; dst_hold(&rt->dst); break; From 6320f430b95a00ef958d7e98655823bfb3c1b918 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 16 Jan 2013 09:55:57 -0800 Subject: [PATCH 2104/2357] MAINTAINERS: Stephen Hemminger email change [ Upstream commit adbbf69d1a54abf424e91875746a610dcc80017d ] I changed my email because the vyatta.com mail server is now redirected to brocade.com; and the Brocade mail system is not friendly to Linux desktop users. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a60009da728..c744d9c6e28 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2627,7 +2627,7 @@ S: Maintained F: drivers/net/ethernet/i825xx/eexpress.* ETHERNET BRIDGE -M: Stephen Hemminger +M: Stephen Hemminger L: bridge@lists.linux-foundation.org L: netdev@vger.kernel.org W: http://www.linuxfoundation.org/en/Net:Bridge @@ -4312,7 +4312,7 @@ S: Maintained MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2) M: Mirko Lindner -M: Stephen Hemminger +M: Stephen Hemminger L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/marvell/sk* @@ -4563,7 +4563,7 @@ S: Supported F: drivers/infiniband/hw/nes/ NETEM NETWORK EMULATOR -M: Stephen Hemminger +M: Stephen Hemminger L: netem@lists.linux-foundation.org S: Maintained F: net/sched/sch_netem.c From 07da6b22a219ba7907ad41118f0e77f4b8fae9a9 Mon Sep 17 00:00:00 2001 From: Romain KUNTZ Date: Wed, 16 Jan 2013 12:47:40 +0000 Subject: [PATCH 2105/2357] ipv6: fix header length calculation in ip6_append_data() [ Upstream commit 7efdba5bd9a2f3e2059beeb45c9fa55eefe1bced ] Commit 299b0767 (ipv6: Fix IPsec slowpath fragmentation problem) has introduced a error in the header length calculation that provokes corrupted packets when non-fragmentable extensions headers (Destination Option or Routing Header Type 2) are used. rt->rt6i_nfheader_len is the length of the non-fragmentable extension header, and it should be substracted to rt->dst.header_len, and not to exthdrlen, as it was done before commit 299b0767. This patch reverts to the original and correct behavior. It has been successfully tested with and without IPsec on packets that include non-fragmentable extensions headers. Signed-off-by: Romain Kuntz Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_output.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 13e5399b1cd..ce661baa60c 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1287,10 +1287,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, cork->length = 0; sk->sk_sndmsg_page = NULL; sk->sk_sndmsg_off = 0; - exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len; + exthdrlen = (opt ? opt->opt_flen : 0); length += exthdrlen; transhdrlen += exthdrlen; - dst_exthdrlen = rt->dst.header_len; + dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; } else { rt = (struct rt6_info *)cork->dst; fl6 = &inet->cork.fl.u.ip6; From f0adabb18a751ecff5da1e03d47b13dd9628b89b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 16 Jan 2013 13:36:37 +0000 Subject: [PATCH 2106/2357] net: calxedaxgmac: throw away overrun frames [ Upstream commit d6fb3be544b46a7611a3373fcaa62b5b0be01888 ] The xgmac driver assumes 1 frame per descriptor. If a frame larger than the descriptor's buffer size is received, the frame will spill over into the next descriptor. So check for received frames that span more than one descriptor and discard them. This prevents a crash if we receive erroneous large packets. Signed-off-by: Rob Herring Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/calxeda/xgmac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index 11f667f6131..4ebbe6f609d 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -547,6 +547,10 @@ static int desc_get_rx_status(struct xgmac_priv *priv, struct xgmac_dma_desc *p) return -1; } + /* All frames should fit into a single buffer */ + if (!(status & RXDESC_FIRST_SEG) || !(status & RXDESC_LAST_SEG)) + return -1; + /* Check if packet has checksum already */ if ((status & RXDESC_FRAME_TYPE) && (status & RXDESC_EXT_STATUS) && !(ext_status & RXDESC_IP_PAYLOAD_MASK)) From 70f85892c8a0e0eee5f4eeb5371b72e9b46744ab Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Thu, 17 Jan 2013 05:30:42 +0000 Subject: [PATCH 2107/2357] net/mlx4_en: Fix bridged vSwitch configuration for non SRIOV mode [ Upstream commit 213815a1e6ae70b9648483b110bc5081795f99e8 ] Commit 5b4c4d36860e "mlx4_en: Allow communication between functions on same host" introduced a regression under which a bridge acting as vSwitch whose uplink is an mlx4 Ethernet device become non-operative in native (non sriov) mode. This happens since broadcast ARP requests sent by VMs were loopback-ed by the HW and hence the bridge learned VM source MACs on both the VM and the uplink ports. The fix is to place the DMAC in the send WQE only under SRIOV/eSwitch configuration or when the device is in selftest. Reviewed-by: Or Gerlitz Signed-off-by: Yan Burman Signed-off-by: Amir Vadai Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 17968244c39..efa3a13f8b1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -683,10 +683,15 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ring->tx_csum++; } - /* Copy dst mac address to wqe */ - ethh = (struct ethhdr *)skb->data; - tx_desc->ctrl.srcrb_flags16[0] = get_unaligned((__be16 *)ethh->h_dest); - tx_desc->ctrl.imm = get_unaligned((__be32 *)(ethh->h_dest + 2)); + if (mlx4_is_mfunc(mdev->dev) || priv->validate_loopback) { + /* Copy dst mac address to wqe. This allows loopback in eSwitch, + * so that VFs and PF can communicate with each other + */ + ethh = (struct ethhdr *)skb->data; + tx_desc->ctrl.srcrb_flags16[0] = get_unaligned((__be16 *)ethh->h_dest); + tx_desc->ctrl.imm = get_unaligned((__be32 *)(ethh->h_dest + 2)); + } + /* Handle LSO (TSO) packets */ if (lso_header_size) { /* Mark opcode as LSO */ From 37c1a8504945755e6e0f39449023e250eb2c2618 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 17 Jan 2013 05:30:43 +0000 Subject: [PATCH 2108/2357] net/mlx4_core: Set number of msix vectors under SRIOV mode to firmware defaults [ Upstream commit ca4c7b35f75492de7fbf5ee95be07481c348caee ] The lines if (mlx4_is_mfunc(dev)) { nreq = 2; } else { which hard code the number of requested msi-x vectors under multi-function mode to two can be removed completely, since the firmware sets num_eqs and reserved_eqs appropriately Thus, the code line: nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, nreq); is by itself sufficient and correct for all cases. Currently, for mfunc mode num_eqs = 32 and reserved_eqs = 28, hence four vectors will be enabled. This triples (one vector is used for the async events and commands EQ) the horse power provided for processing of incoming packets on netdev RSS scheme, IO initiators/targets commands processing flows, etc. Reviewed-by: Jack Morgenstein Signed-off-by: Amir Vadai Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/main.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 8bb05b46db8..1995cb05acf 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1526,15 +1526,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) int i; if (msi_x) { - /* In multifunction mode each function gets 2 msi-X vectors - * one for data path completions anf the other for asynch events - * or command completions */ - if (mlx4_is_mfunc(dev)) { - nreq = 2; - } else { - nreq = min_t(int, dev->caps.num_eqs - - dev->caps.reserved_eqs, nreq); - } + nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, + nreq); entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); if (!entries) From 3a2593d54499ec5d2ac5682503ae1973bfcd3bcb Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Mon, 21 Jan 2013 11:57:21 +0000 Subject: [PATCH 2109/2357] isdn/gigaset: fix zero size border case in debug dump [ Upstream commit d721a1752ba544df8d7d36959038b26bc92bdf80 ] If subtracting 12 from l leaves zero we'd do a zero size allocation, leading to an oops later when we try to set the NUL terminator. Reported-by: Dan Carpenter Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/gigaset/capi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 579aa021a65..be22d5ee8e0 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -264,6 +264,8 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag, CAPIMSG_APPID(data), CAPIMSG_MSGID(data), l, CAPIMSG_CONTROL(data)); l -= 12; + if (l <= 0) + return; dbgline = kmalloc(3 * l, GFP_ATOMIC); if (!dbgline) return; From 30a66dd405e36be6f470f4c383c16583b44812e1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 22 Jan 2013 06:33:05 +0000 Subject: [PATCH 2110/2357] netxen: fix off by one bug in netxen_release_tx_buffer() [ Upstream commit a05948f296ce103989b28a2606e47d2e287c3c89 ] Christoph Paasch found netxen could trigger a BUG in its dismantle phase, in netxen_release_tx_buffer(), using full size TSO packets. cmd_buf->frag_count includes the skb->data part, so the loop must start at index 1 instead of 0, or else we can make an out of bound access to cmd_buff->frag_array[MAX_SKB_FRAGS + 2] Christoph provided the fixes in netxen_map_tx_skb() function. In case of a dma mapping error, its better to clear the dma fields so that we don't try to unmap them again in netxen_release_tx_buffer() Reported-by: Christoph Paasch Signed-off-by: Eric Dumazet Tested-by: Christoph Paasch Cc: Sony Chacko Cc: Rajesh Borundia Signed-off-by: Christoph Paasch Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c | 2 +- drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index 718b2744035..83538ccddeb 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c @@ -144,7 +144,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter) buffrag->length, PCI_DMA_TODEVICE); buffrag->dma = 0ULL; } - for (j = 0; j < cmd_buf->frag_count; j++) { + for (j = 1; j < cmd_buf->frag_count; j++) { buffrag++; if (buffrag->dma) { pci_unmap_page(adapter->pdev, buffrag->dma, diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 22b399a9db9..7ee9c740085 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -1956,10 +1956,12 @@ netxen_map_tx_skb(struct pci_dev *pdev, while (--i >= 0) { nf = &pbuf->frag_array[i+1]; pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); + nf->dma = 0ULL; } nf = &pbuf->frag_array[0]; pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); + nf->dma = 0ULL; out_err: return -ENOMEM; From 646e28ceca9036d5b2e76f4b116bba0bc60081c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Mon, 21 Jan 2013 22:30:35 +0000 Subject: [PATCH 2111/2357] r8169: remove the obsolete and incorrect AMD workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5d0feaff230c0abfe4a112e6f09f096ed99e0b2d ] This was introduced in commit 6dccd16 "r8169: merge with version 6.001.00 of Realtek's r8169 driver". I did not find the version 6.001.00 online, but in 6.002.00 or any later r8169 from Realtek this hunk is no longer present. Also commit 05af214 "r8169: fix Ethernet Hangup for RTL8110SC rev d" claims to have fixed this issue otherwise. The magic compare mask of 0xfffe000 is dubious as it masks parts of the Reserved part, and parts of the VLAN tag. But this does not make much sense as the VLAN tag parts are perfectly valid there. In matter of fact this seems to be triggered with any VLAN tagged packet as RxVlanTag bit is matched. I would suspect 0xfffe0000 was intended to test reserved part only. Finally, this hunk is evil as it can cause more packets to be handled than what was NAPI quota causing net/core/dev.c: net_rx_action(): WARN_ON_ONCE(work > weight) to trigger, and mess up the NAPI state causing device to hang. As result, any system using VLANs and having high receive traffic (so that NAPI poll budget limits rtl_rx) would result in device hang. Signed-off-by: Timo Teräs Acked-by: Francois Romieu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 06ee243d41a..df49ce26c3e 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5450,13 +5450,6 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget tp->rx_stats.bytes += pkt_size; u64_stats_update_end(&tp->rx_stats.syncp); } - - /* Work around for AMD plateform. */ - if ((desc->opts2 & cpu_to_le32(0xfffe000)) && - (tp->mac_version == RTL_GIGA_MAC_VER_05)) { - desc->opts2 = 0; - cur_rx++; - } } count = cur_rx - tp->cur_rx; From e38660420e8e12d7fd6b58069d985b6298aad176 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 25 Jan 2013 07:44:41 +0000 Subject: [PATCH 2112/2357] net: loopback: fix a dst refcounting issue [ Upstream commit 794ed393b707f01858f5ebe2ae5eabaf89d00022 ] Ben Greear reported crashes in ip_rcv_finish() on a stress test involving many macvlans. We tracked the bug to a dst use after free. ip_rcv_finish() was calling dst->input() and got garbage for dst->input value. It appears the bug is in loopback driver, lacking a skb_dst_force() before calling netif_rx(). As a result, a non refcounted dst, normally protected by a RCU read_lock section, was escaping this section and could be freed before the packet being processed. [] loopback_xmit+0x64/0x83 [] dev_hard_start_xmit+0x26c/0x35e [] dev_queue_xmit+0x2c4/0x37c [] ? dev_hard_start_xmit+0x35e/0x35e [] ? eth_header+0x28/0xb6 [] neigh_resolve_output+0x176/0x1a7 [] ip_finish_output2+0x297/0x30d [] ? ip_finish_output2+0x137/0x30d [] ip_finish_output+0x63/0x68 [] ip_output+0x61/0x67 [] dst_output+0x17/0x1b [] ip_local_out+0x1e/0x23 [] ip_queue_xmit+0x315/0x353 [] ? ip_send_unicast_reply+0x2cc/0x2cc [] tcp_transmit_skb+0x7ca/0x80b [] tcp_connect+0x53c/0x587 [] ? getnstimeofday+0x44/0x7d [] ? ktime_get_real+0x11/0x3e [] tcp_v4_connect+0x3c2/0x431 [] __inet_stream_connect+0x84/0x287 [] ? inet_stream_connect+0x22/0x49 [] ? _local_bh_enable_ip+0x84/0x9f [] ? local_bh_enable+0xd/0x11 [] ? lock_sock_nested+0x6e/0x79 [] ? inet_stream_connect+0x22/0x49 [] inet_stream_connect+0x33/0x49 [] sys_connect+0x75/0x98 This bug was introduced in linux-2.6.35, in commit 7fee226ad2397b (net: add a noref bit on skb dst) skb_dst_force() is enforced in dev_queue_xmit() for devices having a qdisc. Reported-by: Ben Greear Signed-off-by: Eric Dumazet Tested-by: Ben Greear Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/loopback.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 32eb94ece6c..a3d4707505a 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -77,6 +77,11 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, skb_orphan(skb); + /* Before queueing this packet to netif_rx(), + * make sure dst is refcounted. + */ + skb_dst_force(skb); + skb->protocol = eth_type_trans(skb, dev); /* it's OK to use per_cpu_ptr() because BHs are off */ From 6c1128b87d5814de27f8ddc445783a81914b194f Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Sun, 27 Jan 2013 21:14:08 +0000 Subject: [PATCH 2113/2357] pktgen: correctly handle failures when adding a device [ Upstream commit 604dfd6efc9b79bce432f2394791708d8e8f6efc ] The return value of pktgen_add_device() is not checked, so even if we fail to add some device, for example, non-exist one, we still see "OK:...". This patch fixes it. After this patch, I got: # echo "add_device non-exist" > /proc/net/pktgen/kpktgend_0 -bash: echo: write error: No such device # cat /proc/net/pktgen/kpktgend_0 Running: Stopped: Result: ERROR: can not add device non-exist # echo "add_device eth0" > /proc/net/pktgen/kpktgend_0 # cat /proc/net/pktgen/kpktgend_0 Running: Stopped: eth0 Result: OK: add_device=eth0 (Candidate for -stable) Cc: David S. Miller Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/pktgen.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 8dae76f481e..114d8a9e857 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1802,10 +1802,13 @@ static ssize_t pktgen_thread_write(struct file *file, return -EFAULT; i += len; mutex_lock(&pktgen_thread_lock); - pktgen_add_device(t, f); + ret = pktgen_add_device(t, f); mutex_unlock(&pktgen_thread_lock); - ret = count; - sprintf(pg_result, "OK: add_device=%s", f); + if (!ret) { + ret = count; + sprintf(pg_result, "OK: add_device=%s", f); + } else + sprintf(pg_result, "ERROR: can not add device %s", f); goto out; } From 909978d73590b07c3a050a569cc3bd44b1f9355c Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Tue, 29 Jan 2013 22:26:08 +0000 Subject: [PATCH 2114/2357] ipv6: do not create neighbor entries for local delivery [ Upstream commit bd30e947207e2ea0ff2c08f5b4a03025ddce48d3 ] They will be created at output, if ever needed. This avoids creating empty neighbor entries when TPROXYing/Forwarding packets for addresses that are not even directly reachable. Note that IPv4 already handles it this way. No neighbor entries are created for local input. Tested by myself and customer. Signed-off-by: Jiri Pirko Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b84cba19550..493490f052a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -846,7 +846,8 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, dst_hold(&rt->dst); read_unlock_bh(&table->tb6_lock); - if (!dst_get_neighbour_noref_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) + if (!dst_get_neighbour_noref_raw(&rt->dst) && + !(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_LOCAL))) nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); else if (!(rt->dst.flags & DST_HOST)) nrt = rt6_alloc_clone(rt, &fl6->daddr); From d78378096e74b2fd0b42b74156ba0ae0567ea226 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 29 Jan 2013 22:58:04 -0500 Subject: [PATCH 2115/2357] via-rhine: Fix bugs in NAPI support. [ Upstream commit 559bcac35facfed49ab4f408e162971612dcfdf3 ] 1) rhine_tx() should use dev_kfree_skb() not dev_kfree_skb_irq() 2) rhine_slow_event_task's NAPI triggering logic is racey, it should just hit the interrupt mask register. This is the same as commit 7dbb491878a2c51d372a8890fa45a8ff80358af1 ("r8169: avoid NAPI scheduling delay.") made to fix the same problem in the r8169 driver. From Francois Romieu. Reported-by: Jamie Gloudon Tested-by: Jamie Gloudon Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/via/via-rhine.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index fcfa01f7ceb..4c76db4f058 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -1802,7 +1802,7 @@ static void rhine_tx(struct net_device *dev) rp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); } - dev_kfree_skb_irq(rp->tx_skbuff[entry]); + dev_kfree_skb(rp->tx_skbuff[entry]); rp->tx_skbuff[entry] = NULL; entry = (++rp->dirty_tx) % TX_RING_SIZE; } @@ -2011,11 +2011,7 @@ static void rhine_slow_event_task(struct work_struct *work) if (intr_status & IntrPCIErr) netif_warn(rp, hw, dev, "PCI error\n"); - napi_disable(&rp->napi); - rhine_irq_disable(rp); - /* Slow and safe. Consider __napi_schedule as a replacement ? */ - napi_enable(&rp->napi); - napi_schedule(&rp->napi); + iowrite16(RHINE_EVENT & 0xffff, rp->base + IntrEnable); out_unlock: mutex_unlock(&rp->task_lock); From f60f85403b3a5b566ba0eaf174930f6a626d33ad Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 1 Feb 2013 07:21:41 +0000 Subject: [PATCH 2116/2357] packet: fix leakage of tx_ring memory [ Upstream commit 9665d5d62487e8e7b1f546c00e11107155384b9a ] When releasing a packet socket, the routine packet_set_ring() is reused to free rings instead of allocating them. But when calling it for the first time, it fills req->tp_block_nr with the value of rb->pg_vec_len which in the second invocation makes it bail out since req->tp_block_nr is greater zero but req->tp_block_size is zero. This patch solves the problem by passing a zeroed auto-variable to packet_set_ring() upon each invocation from packet_release(). As far as I can tell, this issue exists even since 69e3c75 (net: TX_RING and packet mmap), i.e. the original inclusion of TX ring support into af_packet, but applies only to sockets with both RX and TX ring allocated, which is probably why this was unnoticed all the time. Signed-off-by: Phil Sutter Cc: Johann Baudy Cc: Daniel Borkmann Acked-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 078fdffcd55..38ca5e07d52 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2450,13 +2450,15 @@ static int packet_release(struct socket *sock) packet_flush_mclist(sk); - memset(&req_u, 0, sizeof(req_u)); - - if (po->rx_ring.pg_vec) + if (po->rx_ring.pg_vec) { + memset(&req_u, 0, sizeof(req_u)); packet_set_ring(sk, &req_u, 1, 0); + } - if (po->tx_ring.pg_vec) + if (po->tx_ring.pg_vec) { + memset(&req_u, 0, sizeof(req_u)); packet_set_ring(sk, &req_u, 1, 1); + } fanout_release(sk); From b4129dae20d6e106cb197008d9adf617e1affa89 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 8 Feb 2013 00:19:11 +0000 Subject: [PATCH 2117/2357] atm/iphase: rename fregt_t -> ffreg_t [ Upstream commit ab54ee80aa7585f9666ff4dd665441d7ce41f1e8 ] We have conflicting type qualifiers for "freg_t" in s390's ptrace.h and the iphase atm device driver, which causes the compile error below. Unfortunately the s390 typedef can't be renamed, since it's a user visible api, nor can I change the include order in s390 code to avoid the conflict. So simply rename the iphase typedef to a new name. Fixes this compile error: In file included from drivers/atm/iphase.c:66:0: drivers/atm/iphase.h:639:25: error: conflicting type qualifiers for 'freg_t' In file included from next/arch/s390/include/asm/ptrace.h:9:0, from next/arch/s390/include/asm/lowcore.h:12, from next/arch/s390/include/asm/thread_info.h:30, from include/linux/thread_info.h:54, from include/linux/preempt.h:9, from include/linux/spinlock.h:50, from include/linux/seqlock.h:29, from include/linux/time.h:5, from include/linux/stat.h:18, from include/linux/module.h:10, from drivers/atm/iphase.c:43: next/arch/s390/include/uapi/asm/ptrace.h:197:3: note: previous declaration of 'freg_t' was here Signed-off-by: Heiko Carstens Acked-by: chas williams - CONTRACTOR Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/atm/iphase.h | 146 +++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h index 6a0955e6d4f..53ecac5a216 100644 --- a/drivers/atm/iphase.h +++ b/drivers/atm/iphase.h @@ -636,82 +636,82 @@ struct rx_buf_desc { #define SEG_BASE IPHASE5575_FRAG_CONTROL_REG_BASE #define REASS_BASE IPHASE5575_REASS_CONTROL_REG_BASE -typedef volatile u_int freg_t; +typedef volatile u_int ffreg_t; typedef u_int rreg_t; typedef struct _ffredn_t { - freg_t idlehead_high; /* Idle cell header (high) */ - freg_t idlehead_low; /* Idle cell header (low) */ - freg_t maxrate; /* Maximum rate */ - freg_t stparms; /* Traffic Management Parameters */ - freg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */ - freg_t rm_type; /* */ - u_int filler5[0x17 - 0x06]; - freg_t cmd_reg; /* Command register */ - u_int filler18[0x20 - 0x18]; - freg_t cbr_base; /* CBR Pointer Base */ - freg_t vbr_base; /* VBR Pointer Base */ - freg_t abr_base; /* ABR Pointer Base */ - freg_t ubr_base; /* UBR Pointer Base */ - u_int filler24; - freg_t vbrwq_base; /* VBR Wait Queue Base */ - freg_t abrwq_base; /* ABR Wait Queue Base */ - freg_t ubrwq_base; /* UBR Wait Queue Base */ - freg_t vct_base; /* Main VC Table Base */ - freg_t vcte_base; /* Extended Main VC Table Base */ - u_int filler2a[0x2C - 0x2A]; - freg_t cbr_tab_beg; /* CBR Table Begin */ - freg_t cbr_tab_end; /* CBR Table End */ - freg_t cbr_pointer; /* CBR Pointer */ - u_int filler2f[0x30 - 0x2F]; - freg_t prq_st_adr; /* Packet Ready Queue Start Address */ - freg_t prq_ed_adr; /* Packet Ready Queue End Address */ - freg_t prq_rd_ptr; /* Packet Ready Queue read pointer */ - freg_t prq_wr_ptr; /* Packet Ready Queue write pointer */ - freg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/ - freg_t tcq_ed_adr; /* Transmit Complete Queue End Address */ - freg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */ - freg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/ - u_int filler38[0x40 - 0x38]; - freg_t queue_base; /* Base address for PRQ and TCQ */ - freg_t desc_base; /* Base address of descriptor table */ - u_int filler42[0x45 - 0x42]; - freg_t mode_reg_0; /* Mode register 0 */ - freg_t mode_reg_1; /* Mode register 1 */ - freg_t intr_status_reg;/* Interrupt Status register */ - freg_t mask_reg; /* Mask Register */ - freg_t cell_ctr_high1; /* Total cell transfer count (high) */ - freg_t cell_ctr_lo1; /* Total cell transfer count (low) */ - freg_t state_reg; /* Status register */ - u_int filler4c[0x58 - 0x4c]; - freg_t curr_desc_num; /* Contains the current descriptor num */ - freg_t next_desc; /* Next descriptor */ - freg_t next_vc; /* Next VC */ - u_int filler5b[0x5d - 0x5b]; - freg_t present_slot_cnt;/* Present slot count */ - u_int filler5e[0x6a - 0x5e]; - freg_t new_desc_num; /* New descriptor number */ - freg_t new_vc; /* New VC */ - freg_t sched_tbl_ptr; /* Schedule table pointer */ - freg_t vbrwq_wptr; /* VBR wait queue write pointer */ - freg_t vbrwq_rptr; /* VBR wait queue read pointer */ - freg_t abrwq_wptr; /* ABR wait queue write pointer */ - freg_t abrwq_rptr; /* ABR wait queue read pointer */ - freg_t ubrwq_wptr; /* UBR wait queue write pointer */ - freg_t ubrwq_rptr; /* UBR wait queue read pointer */ - freg_t cbr_vc; /* CBR VC */ - freg_t vbr_sb_vc; /* VBR SB VC */ - freg_t abr_sb_vc; /* ABR SB VC */ - freg_t ubr_sb_vc; /* UBR SB VC */ - freg_t vbr_next_link; /* VBR next link */ - freg_t abr_next_link; /* ABR next link */ - freg_t ubr_next_link; /* UBR next link */ - u_int filler7a[0x7c-0x7a]; - freg_t out_rate_head; /* Out of rate head */ - u_int filler7d[0xca-0x7d]; /* pad out to full address space */ - freg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */ - freg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */ - u_int fillercc[0x100-0xcc]; /* pad out to full address space */ + ffreg_t idlehead_high; /* Idle cell header (high) */ + ffreg_t idlehead_low; /* Idle cell header (low) */ + ffreg_t maxrate; /* Maximum rate */ + ffreg_t stparms; /* Traffic Management Parameters */ + ffreg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */ + ffreg_t rm_type; /* */ + u_int filler5[0x17 - 0x06]; + ffreg_t cmd_reg; /* Command register */ + u_int filler18[0x20 - 0x18]; + ffreg_t cbr_base; /* CBR Pointer Base */ + ffreg_t vbr_base; /* VBR Pointer Base */ + ffreg_t abr_base; /* ABR Pointer Base */ + ffreg_t ubr_base; /* UBR Pointer Base */ + u_int filler24; + ffreg_t vbrwq_base; /* VBR Wait Queue Base */ + ffreg_t abrwq_base; /* ABR Wait Queue Base */ + ffreg_t ubrwq_base; /* UBR Wait Queue Base */ + ffreg_t vct_base; /* Main VC Table Base */ + ffreg_t vcte_base; /* Extended Main VC Table Base */ + u_int filler2a[0x2C - 0x2A]; + ffreg_t cbr_tab_beg; /* CBR Table Begin */ + ffreg_t cbr_tab_end; /* CBR Table End */ + ffreg_t cbr_pointer; /* CBR Pointer */ + u_int filler2f[0x30 - 0x2F]; + ffreg_t prq_st_adr; /* Packet Ready Queue Start Address */ + ffreg_t prq_ed_adr; /* Packet Ready Queue End Address */ + ffreg_t prq_rd_ptr; /* Packet Ready Queue read pointer */ + ffreg_t prq_wr_ptr; /* Packet Ready Queue write pointer */ + ffreg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/ + ffreg_t tcq_ed_adr; /* Transmit Complete Queue End Address */ + ffreg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */ + ffreg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/ + u_int filler38[0x40 - 0x38]; + ffreg_t queue_base; /* Base address for PRQ and TCQ */ + ffreg_t desc_base; /* Base address of descriptor table */ + u_int filler42[0x45 - 0x42]; + ffreg_t mode_reg_0; /* Mode register 0 */ + ffreg_t mode_reg_1; /* Mode register 1 */ + ffreg_t intr_status_reg;/* Interrupt Status register */ + ffreg_t mask_reg; /* Mask Register */ + ffreg_t cell_ctr_high1; /* Total cell transfer count (high) */ + ffreg_t cell_ctr_lo1; /* Total cell transfer count (low) */ + ffreg_t state_reg; /* Status register */ + u_int filler4c[0x58 - 0x4c]; + ffreg_t curr_desc_num; /* Contains the current descriptor num */ + ffreg_t next_desc; /* Next descriptor */ + ffreg_t next_vc; /* Next VC */ + u_int filler5b[0x5d - 0x5b]; + ffreg_t present_slot_cnt;/* Present slot count */ + u_int filler5e[0x6a - 0x5e]; + ffreg_t new_desc_num; /* New descriptor number */ + ffreg_t new_vc; /* New VC */ + ffreg_t sched_tbl_ptr; /* Schedule table pointer */ + ffreg_t vbrwq_wptr; /* VBR wait queue write pointer */ + ffreg_t vbrwq_rptr; /* VBR wait queue read pointer */ + ffreg_t abrwq_wptr; /* ABR wait queue write pointer */ + ffreg_t abrwq_rptr; /* ABR wait queue read pointer */ + ffreg_t ubrwq_wptr; /* UBR wait queue write pointer */ + ffreg_t ubrwq_rptr; /* UBR wait queue read pointer */ + ffreg_t cbr_vc; /* CBR VC */ + ffreg_t vbr_sb_vc; /* VBR SB VC */ + ffreg_t abr_sb_vc; /* ABR SB VC */ + ffreg_t ubr_sb_vc; /* UBR SB VC */ + ffreg_t vbr_next_link; /* VBR next link */ + ffreg_t abr_next_link; /* ABR next link */ + ffreg_t ubr_next_link; /* UBR next link */ + u_int filler7a[0x7c-0x7a]; + ffreg_t out_rate_head; /* Out of rate head */ + u_int filler7d[0xca-0x7d]; /* pad out to full address space */ + ffreg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */ + ffreg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */ + u_int fillercc[0x100-0xcc]; /* pad out to full address space */ } ffredn_t; typedef struct _rfredn_t { From 4c921d0ed5d49a93613530f4dd405fc2db3ccb84 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 17 Jan 2013 11:15:08 +0000 Subject: [PATCH 2118/2357] sctp: refactor sctp_outq_teardown to insure proper re-initalization [ Upstream commit 2f94aabd9f6c925d77aecb3ff020f1cc12ed8f86 ] Jamie Parsons reported a problem recently, in which the re-initalization of an association (The duplicate init case), resulted in a loss of receive window space. He tracked down the root cause to sctp_outq_teardown, which discarded all the data on an outq during a re-initalization of the corresponding association, but never reset the outq->outstanding_data field to zero. I wrote, and he tested this fix, which does a proper full re-initalization of the outq, fixing this problem, and hopefully future proofing us from simmilar issues down the road. Signed-off-by: Neil Horman Reported-by: Jamie Parsons Tested-by: Jamie Parsons CC: Jamie Parsons CC: Vlad Yasevich CC: "David S. Miller" CC: netdev@vger.kernel.org Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/outqueue.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index cfeb1d4a1ee..96eb168a1f4 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -223,7 +223,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) /* Free the outqueue structure and any related pending chunks. */ -void sctp_outq_teardown(struct sctp_outq *q) +static void __sctp_outq_teardown(struct sctp_outq *q) { struct sctp_transport *transport; struct list_head *lchunk, *temp; @@ -276,8 +276,6 @@ void sctp_outq_teardown(struct sctp_outq *q) sctp_chunk_free(chunk); } - q->error = 0; - /* Throw away any leftover control chunks. */ list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) { list_del_init(&chunk->list); @@ -285,11 +283,17 @@ void sctp_outq_teardown(struct sctp_outq *q) } } +void sctp_outq_teardown(struct sctp_outq *q) +{ + __sctp_outq_teardown(q); + sctp_outq_init(q->asoc, q); +} + /* Free the outqueue structure and any related pending chunks. */ void sctp_outq_free(struct sctp_outq *q) { /* Throw away leftover chunks. */ - sctp_outq_teardown(q); + __sctp_outq_teardown(q); /* If we were kmalloc()'d, free the memory. */ if (q->malloced) From 8a501d87edf7190e8fe1741d9312dfcb6361c538 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 8 Feb 2013 03:04:34 +0000 Subject: [PATCH 2119/2357] net: sctp: sctp_setsockopt_auth_key: use kzfree instead of kfree [ Upstream commit 6ba542a291a5e558603ac51cda9bded347ce7627 ] In sctp_setsockopt_auth_key, we create a temporary copy of the user passed shared auth key for the endpoint or association and after internal setup, we free it right away. Since it's sensitive data, we should zero out the key before returning the memory back to the allocator. Thus, use kzfree instead of kfree, just as we do in sctp_auth_key_put(). Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 74053554a85..9fd05edef19 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3375,7 +3375,7 @@ static int sctp_setsockopt_auth_key(struct sock *sk, ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey); out: - kfree(authkey); + kzfree(authkey); return ret; } From d6f5498856f31246818bbe4ebfa710ce92730a37 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 8 Feb 2013 03:04:35 +0000 Subject: [PATCH 2120/2357] net: sctp: sctp_endpoint_free: zero out secret key data [ Upstream commit b5c37fe6e24eec194bb29d22fdd55d73bcc709bf ] On sctp_endpoint_destroy, previously used sensitive keying material should be zeroed out before the memory is returned, as we already do with e.g. auth keys when released. Signed-off-by: Daniel Borkmann Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/endpointola.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 68a385d7c3b..58cd035dcd2 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -248,6 +248,8 @@ void sctp_endpoint_free(struct sctp_endpoint *ep) /* Final destructor for endpoint. */ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) { + int i; + SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); /* Free up the HMAC transform. */ @@ -270,6 +272,9 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) sctp_inq_free(&ep->base.inqueue); sctp_bind_addr_free(&ep->base.bind_addr); + for (i = 0; i < SCTP_HOW_MANY_SECRETS; ++i) + memset(&ep->secret_key[i], 0, SCTP_SECRET_SIZE); + /* Remove and free the port */ if (sctp_sk(ep->base.sk)->bind_hash) sctp_put_port(ep->base.sk); From be7254fc6c92c016a6768cc30596198c61043ff5 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 6 Feb 2013 23:41:35 +0000 Subject: [PATCH 2121/2357] xen/netback: shutdown the ring if it contains garbage. [ Upstream commit 48856286b64e4b66ec62b94e504d0b29c1ade664 ] A buggy or malicious frontend should not be able to confuse netback. If we spot anything which is not as it should be then shutdown the device and don't try to continue with the ring in a potentially hostile state. Well behaved and non-hostile frontends will not be penalised. As well as making the existing checks for such errors fatal also add a new check that ensures that there isn't an insane number of requests on the ring (i.e. more than would fit in the ring). If the ring contains garbage then previously is was possible to loop over this insane number, getting an error each time and therefore not generating any more pending requests and therefore not exiting the loop in xen_netbk_tx_build_gops for an externded period. Also turn various netdev_dbg calls which no precipitate a fatal error into netdev_err, they are rate limited because the device is shutdown afterwards. This fixes at least one known DoS/softlockup of the backend domain. Signed-off-by: Ian Campbell Reviewed-by: Konrad Rzeszutek Wilk Acked-by: Jan Beulich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netback/common.h | 3 ++ drivers/net/xen-netback/interface.c | 23 ++++++----- drivers/net/xen-netback/netback.c | 62 +++++++++++++++++++++-------- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 94b79c3338c..9d7f1723dd8 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -151,6 +151,9 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb); /* Notify xenvif that ring now has space to send an skb to the frontend */ void xenvif_notify_tx_completion(struct xenvif *vif); +/* Prevent the device from generating any further traffic. */ +void xenvif_carrier_off(struct xenvif *vif); + /* Returns number of ring slots required to send an skb to the frontend */ unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb); diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index b7d41f8c338..b8c5193bd42 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -343,17 +343,22 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, return err; } -void xenvif_disconnect(struct xenvif *vif) +void xenvif_carrier_off(struct xenvif *vif) { struct net_device *dev = vif->dev; - if (netif_carrier_ok(dev)) { - rtnl_lock(); - netif_carrier_off(dev); /* discard queued packets */ - if (netif_running(dev)) - xenvif_down(vif); - rtnl_unlock(); - xenvif_put(vif); - } + + rtnl_lock(); + netif_carrier_off(dev); /* discard queued packets */ + if (netif_running(dev)) + xenvif_down(vif); + rtnl_unlock(); + xenvif_put(vif); +} + +void xenvif_disconnect(struct xenvif *vif) +{ + if (netif_carrier_ok(vif->dev)) + xenvif_carrier_off(vif); atomic_dec(&vif->refcnt); wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 2596401308a..770c7e1beba 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -860,6 +860,13 @@ static void netbk_tx_err(struct xenvif *vif, xenvif_put(vif); } +static void netbk_fatal_tx_err(struct xenvif *vif) +{ + netdev_err(vif->dev, "fatal error; disabling device\n"); + xenvif_carrier_off(vif); + xenvif_put(vif); +} + static int netbk_count_requests(struct xenvif *vif, struct xen_netif_tx_request *first, struct xen_netif_tx_request *txp, @@ -873,19 +880,22 @@ static int netbk_count_requests(struct xenvif *vif, do { if (frags >= work_to_do) { - netdev_dbg(vif->dev, "Need more frags\n"); + netdev_err(vif->dev, "Need more frags\n"); + netbk_fatal_tx_err(vif); return -frags; } if (unlikely(frags >= MAX_SKB_FRAGS)) { - netdev_dbg(vif->dev, "Too many frags\n"); + netdev_err(vif->dev, "Too many frags\n"); + netbk_fatal_tx_err(vif); return -frags; } memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags), sizeof(*txp)); if (txp->size > first->size) { - netdev_dbg(vif->dev, "Frags galore\n"); + netdev_err(vif->dev, "Frag is bigger than frame.\n"); + netbk_fatal_tx_err(vif); return -frags; } @@ -893,8 +903,9 @@ static int netbk_count_requests(struct xenvif *vif, frags++; if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) { - netdev_dbg(vif->dev, "txp->offset: %x, size: %u\n", + netdev_err(vif->dev, "txp->offset: %x, size: %u\n", txp->offset, txp->size); + netbk_fatal_tx_err(vif); return -frags; } } while ((txp++)->flags & XEN_NETTXF_more_data); @@ -1067,7 +1078,8 @@ static int xen_netbk_get_extras(struct xenvif *vif, do { if (unlikely(work_to_do-- <= 0)) { - netdev_dbg(vif->dev, "Missing extra info\n"); + netdev_err(vif->dev, "Missing extra info\n"); + netbk_fatal_tx_err(vif); return -EBADR; } @@ -1076,8 +1088,9 @@ static int xen_netbk_get_extras(struct xenvif *vif, if (unlikely(!extra.type || extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) { vif->tx.req_cons = ++cons; - netdev_dbg(vif->dev, + netdev_err(vif->dev, "Invalid extra type: %d\n", extra.type); + netbk_fatal_tx_err(vif); return -EINVAL; } @@ -1093,13 +1106,15 @@ static int netbk_set_skb_gso(struct xenvif *vif, struct xen_netif_extra_info *gso) { if (!gso->u.gso.size) { - netdev_dbg(vif->dev, "GSO size must not be zero.\n"); + netdev_err(vif->dev, "GSO size must not be zero.\n"); + netbk_fatal_tx_err(vif); return -EINVAL; } /* Currently only TCPv4 S.O. is supported. */ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) { - netdev_dbg(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type); + netdev_err(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type); + netbk_fatal_tx_err(vif); return -EINVAL; } @@ -1236,9 +1251,25 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) /* Get a netif from the list with work to do. */ vif = poll_net_schedule_list(netbk); + /* This can sometimes happen because the test of + * list_empty(net_schedule_list) at the top of the + * loop is unlocked. Just go back and have another + * look. + */ if (!vif) continue; + if (vif->tx.sring->req_prod - vif->tx.req_cons > + XEN_NETIF_TX_RING_SIZE) { + netdev_err(vif->dev, + "Impossible number of requests. " + "req_prod %d, req_cons %d, size %ld\n", + vif->tx.sring->req_prod, vif->tx.req_cons, + XEN_NETIF_TX_RING_SIZE); + netbk_fatal_tx_err(vif); + continue; + } + RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do); if (!work_to_do) { xenvif_put(vif); @@ -1266,17 +1297,14 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) work_to_do = xen_netbk_get_extras(vif, extras, work_to_do); idx = vif->tx.req_cons; - if (unlikely(work_to_do < 0)) { - netbk_tx_err(vif, &txreq, idx); + if (unlikely(work_to_do < 0)) continue; - } } ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do); - if (unlikely(ret < 0)) { - netbk_tx_err(vif, &txreq, idx - ret); + if (unlikely(ret < 0)) continue; - } + idx += ret; if (unlikely(txreq.size < ETH_HLEN)) { @@ -1288,11 +1316,11 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) /* No crossing a page as the payload mustn't fragment. */ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) { - netdev_dbg(vif->dev, + netdev_err(vif->dev, "txreq.offset: %x, size: %u, end: %lu\n", txreq.offset, txreq.size, (txreq.offset&~PAGE_MASK) + txreq.size); - netbk_tx_err(vif, &txreq, idx); + netbk_fatal_tx_err(vif); continue; } @@ -1320,8 +1348,8 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; if (netbk_set_skb_gso(vif, skb, gso)) { + /* Failure in netbk_set_skb_gso is fatal. */ kfree_skb(skb); - netbk_tx_err(vif, &txreq, idx); continue; } } From 33eb2607ebfcb68bc9ae8ab029f916f1f4ee5097 Mon Sep 17 00:00:00 2001 From: Matthew Daley Date: Wed, 6 Feb 2013 23:41:36 +0000 Subject: [PATCH 2122/2357] xen/netback: don't leak pages on failure in xen_netbk_tx_check_gop. [ Upstream commit 7d5145d8eb2b9791533ffe4dc003b129b9696c48 ] Signed-off-by: Matthew Daley Reviewed-by: Konrad Rzeszutek Wilk Acked-by: Ian Campbell Acked-by: Jan Beulich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netback/netback.c | 38 +++++++++++-------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 770c7e1beba..c71a73198b0 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -146,7 +146,8 @@ void xen_netbk_remove_xenvif(struct xenvif *vif) atomic_dec(&netbk->netfront_count); } -static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx); +static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx, + u8 status); static void make_tx_response(struct xenvif *vif, struct xen_netif_tx_request *txp, s8 st); @@ -979,30 +980,20 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk, { struct gnttab_copy *gop = *gopp; u16 pending_idx = *((u16 *)skb->data); - struct pending_tx_info *pending_tx_info = netbk->pending_tx_info; - struct xenvif *vif = pending_tx_info[pending_idx].vif; - struct xen_netif_tx_request *txp; struct skb_shared_info *shinfo = skb_shinfo(skb); int nr_frags = shinfo->nr_frags; int i, err, start; /* Check status of header. */ err = gop->status; - if (unlikely(err)) { - pending_ring_idx_t index; - index = pending_index(netbk->pending_prod++); - txp = &pending_tx_info[pending_idx].req; - make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR); - netbk->pending_ring[index] = pending_idx; - xenvif_put(vif); - } + if (unlikely(err)) + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR); /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); for (i = start; i < nr_frags; i++) { int j, newerr; - pending_ring_idx_t index; pending_idx = frag_get_pending_idx(&shinfo->frags[i]); @@ -1011,16 +1002,12 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk, if (likely(!newerr)) { /* Had a previous error? Invalidate this fragment. */ if (unlikely(err)) - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); continue; } /* Error on this fragment: respond to client with an error. */ - txp = &netbk->pending_tx_info[pending_idx].req; - make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR); - index = pending_index(netbk->pending_prod++); - netbk->pending_ring[index] = pending_idx; - xenvif_put(vif); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR); /* Not the first error? Preceding frags already invalidated. */ if (err) @@ -1028,10 +1015,10 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk, /* First error: invalidate header and preceding fragments. */ pending_idx = *((u16 *)skb->data); - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); for (j = start; j < i; j++) { pending_idx = frag_get_pending_idx(&shinfo->frags[j]); - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); } /* Remember the error: invalidate all subsequent fragments. */ @@ -1065,7 +1052,7 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb) /* Take an extra reference to offset xen_netbk_idx_release */ get_page(netbk->mmap_pages[pending_idx]); - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); } } @@ -1448,7 +1435,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk) txp->size -= data_len; } else { /* Schedule a response immediately. */ - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); } if (txp->flags & XEN_NETTXF_csum_blank) @@ -1503,7 +1490,8 @@ static void xen_netbk_tx_action(struct xen_netbk *netbk) } -static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx) +static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx, + u8 status) { struct xenvif *vif; struct pending_tx_info *pending_tx_info; @@ -1517,7 +1505,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx) vif = pending_tx_info->vif; - make_tx_response(vif, &pending_tx_info->req, XEN_NETIF_RSP_OKAY); + make_tx_response(vif, &pending_tx_info->req, status); index = pending_index(netbk->pending_prod++); netbk->pending_ring[index] = pending_idx; From 90ffc8f3315b0d296fea07fbc6fef87155f81f45 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 6 Feb 2013 23:41:37 +0000 Subject: [PATCH 2123/2357] xen/netback: free already allocated memory on failure in xen_netbk_get_requests [ Upstream commit 4cc7c1cb7b11b6f3515bd9075527576a1eecc4aa ] Signed-off-by: Ian Campbell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netback/netback.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index c71a73198b0..4c41f5ea400 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -950,7 +950,7 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk, pending_idx = netbk->pending_ring[index]; page = xen_netbk_alloc_page(netbk, skb, pending_idx); if (!page) - return NULL; + goto err; gop->source.u.ref = txp->gref; gop->source.domid = vif->domid; @@ -972,6 +972,17 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk, } return gop; +err: + /* Unwind, freeing all pages and sending error responses. */ + while (i-- > start) { + xen_netbk_idx_release(netbk, frag_get_pending_idx(&frags[i]), + XEN_NETIF_RSP_ERROR); + } + /* The head too, if necessary. */ + if (start) + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR); + + return NULL; } static int xen_netbk_tx_check_gop(struct xen_netbk *netbk, From 42671f1e6fd8922b071bd3fd3e0cfad7226c654d Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 6 Feb 2013 23:41:38 +0000 Subject: [PATCH 2124/2357] netback: correct netbk_tx_err to handle wrap around. [ Upstream commit b9149729ebdcfce63f853aa54a404c6a8f6ebbf3 ] Signed-off-by: Ian Campbell Acked-by: Jan Beulich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netback/netback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 4c41f5ea400..e2793d06e5d 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -852,7 +852,7 @@ static void netbk_tx_err(struct xenvif *vif, do { make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR); - if (cons >= end) + if (cons == end) break; txp = RING_GET_REQUEST(&vif->tx, cons++); } while (1); From 2813296332187d222b96363fe29f10929f7a5228 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 3 Feb 2013 09:13:05 +0000 Subject: [PATCH 2125/2357] tcp: frto should not set snd_cwnd to 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 2e5f421211ff76c17130b4597bc06df4eeead24f ] Commit 9dc274151a548 (tcp: fix ABC in tcp_slow_start()) uncovered a bug in FRTO code : tcp_process_frto() is setting snd_cwnd to 0 if the number of in flight packets is 0. As Neal pointed out, if no packet is in flight we lost our chance to disambiguate whether a loss timeout was spurious. We should assume it was a proper loss. Reported-by: Pasi Kärkkäinen Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Cc: Ilpo Järvinen Cc: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0e0b6d0e9a6..d8c308f74d5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3619,7 +3619,8 @@ static int tcp_process_frto(struct sock *sk, int flag) ((tp->frto_counter >= 2) && (flag & FLAG_RETRANS_DATA_ACKED))) tp->undo_marker = 0; - if (!before(tp->snd_una, tp->frto_highmark)) { + if (!before(tp->snd_una, tp->frto_highmark) || + !tcp_packets_in_flight(tp)) { tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag); return 1; } From f641de91169472dc398fbd971cef380ad8d0f787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 4 Feb 2013 02:14:25 +0000 Subject: [PATCH 2126/2357] tcp: fix for zero packets_in_flight was too broad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 6731d2095bd4aef18027c72ef845ab1087c3ba63 ] There are transients during normal FRTO procedure during which the packets_in_flight can go to zero between write_queue state updates and firing the resulting segments out. As FRTO processing occurs during that window the check must be more precise to not match "spuriously" :-). More specificly, e.g., when packets_in_flight is zero but FLAG_DATA_ACKED is true the problematic branch that set cwnd into zero would not be taken and new segments might be sent out later. Signed-off-by: Ilpo Järvinen Tested-by: Eric Dumazet Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d8c308f74d5..57b20b9dc11 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3619,8 +3619,7 @@ static int tcp_process_frto(struct sock *sk, int flag) ((tp->frto_counter >= 2) && (flag & FLAG_RETRANS_DATA_ACKED))) tp->undo_marker = 0; - if (!before(tp->snd_una, tp->frto_highmark) || - !tcp_packets_in_flight(tp)) { + if (!before(tp->snd_una, tp->frto_highmark)) { tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag); return 1; } @@ -3640,6 +3639,11 @@ static int tcp_process_frto(struct sock *sk, int flag) } } else { if (!(flag & FLAG_DATA_ACKED) && (tp->frto_counter == 1)) { + if (!tcp_packets_in_flight(tp)) { + tcp_enter_frto_loss(sk, 2, flag); + return true; + } + /* Prevent sending of new data. */ tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)); From 94fab0a18e9cbec420c58c7b12b93acf1663c3fd Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Wed, 10 Oct 2012 01:15:01 +0000 Subject: [PATCH 2127/2357] bridge: Pull ip header into skb->data before looking into ip header. [ Upstream commit 6caab7b0544e83e6c160b5e80f5a4a7dd69545c7 ] If lower layer driver leaves the ip header in the skb fragment, it needs to be first pulled into skb->data before inspecting ip header length or ip version number. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bridge/br_netfilter.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index d7f49b63ab0..e54ef82fdad 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -254,6 +254,9 @@ static int br_parse_ip_options(struct sk_buff *skb) struct net_device *dev = skb->dev; u32 len; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto inhdr_error; + iph = ip_hdr(skb); opt = &(IPCB(skb)->opt); From a10a3daa591e6ea2619da1e0418af2a30aa77ac5 Mon Sep 17 00:00:00 2001 From: Nithin Nayak Sujir Date: Mon, 14 Jan 2013 17:10:59 +0000 Subject: [PATCH 2128/2357] tg3: Avoid null pointer dereference in tg3_interrupt in netconsole mode [ Upstream commit 9c13cb8bb477a83b9a3c9e5a5478a4e21294a760 ] When netconsole is enabled, logging messages generated during tg3_open can result in a null pointer dereference for the uninitialized tg3 status block. Use the irq_sync flag to disable polling in the early stages. irq_sync is cleared when the driver is enabling interrupts after all initialization is completed. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/tg3.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 689d2a1935b..42e621a2d24 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6574,6 +6574,9 @@ static void tg3_poll_controller(struct net_device *dev) int i; struct tg3 *tp = netdev_priv(dev); + if (tg3_irq_sync(tp)) + return; + for (i = 0; i < tp->irq_cnt; i++) tg3_interrupt(tp->napi[i].irq_vec, &tp->napi[i]); } @@ -15529,6 +15532,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->pm_cap = pm_cap; tp->rx_mode = TG3_DEF_RX_MODE; tp->tx_mode = TG3_DEF_TX_MODE; + tp->irq_sync = 1; if (tg3_debug > 0) tp->msg_enable = tg3_debug; From eac7b44eb80d3e1fa3310ad2dc57e10c2fc970fd Mon Sep 17 00:00:00 2001 From: Nithin Nayak Sujir Date: Mon, 14 Jan 2013 17:11:00 +0000 Subject: [PATCH 2129/2357] tg3: Fix crc errors on jumbo frame receive [ Upstream commit daf3ec688e057f6060fb9bb0819feac7a8bbf45c ] TG3_PHY_AUXCTL_SMDSP_ENABLE/DISABLE macros do a blind write to the phy auxiliary control register and overwrite the EXT_PKT_LEN (bit 14) resulting in intermittent crc errors on jumbo frames with some link partners. Change the code to do a read/modify/write. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/tg3.c | 58 +++++++++++++++++------------ 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 42e621a2d24..e143d8c0be5 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -1136,14 +1136,26 @@ static int tg3_phy_auxctl_write(struct tg3 *tp, int reg, u32 set) return tg3_writephy(tp, MII_TG3_AUX_CTRL, set | reg); } -#define TG3_PHY_AUXCTL_SMDSP_ENABLE(tp) \ - tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \ - MII_TG3_AUXCTL_ACTL_SMDSP_ENA | \ - MII_TG3_AUXCTL_ACTL_TX_6DB) +static int tg3_phy_toggle_auxctl_smdsp(struct tg3 *tp, bool enable) +{ + u32 val; + int err; + + err = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val); -#define TG3_PHY_AUXCTL_SMDSP_DISABLE(tp) \ - tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \ - MII_TG3_AUXCTL_ACTL_TX_6DB); + if (err) + return err; + if (enable) + + val |= MII_TG3_AUXCTL_ACTL_SMDSP_ENA; + else + val &= ~MII_TG3_AUXCTL_ACTL_SMDSP_ENA; + + err = tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, + val | MII_TG3_AUXCTL_ACTL_TX_6DB); + + return err; +} static int tg3_bmcr_reset(struct tg3 *tp) { @@ -2076,7 +2088,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp) otp = tp->phy_otp; - if (TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) + if (tg3_phy_toggle_auxctl_smdsp(tp, true)) return; phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT); @@ -2101,7 +2113,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp) ((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT); tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy); - TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + tg3_phy_toggle_auxctl_smdsp(tp, false); } static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) @@ -2137,9 +2149,9 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) if (!tp->setlpicnt) { if (current_link_up == 1 && - !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + !tg3_phy_toggle_auxctl_smdsp(tp, true)) { tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000); - TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + tg3_phy_toggle_auxctl_smdsp(tp, false); } val = tr32(TG3_CPMU_EEE_MODE); @@ -2155,11 +2167,11 @@ static void tg3_phy_eee_enable(struct tg3 *tp) (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || tg3_flag(tp, 57765_CLASS)) && - !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + !tg3_phy_toggle_auxctl_smdsp(tp, true)) { val = MII_TG3_DSP_TAP26_ALNOKO | MII_TG3_DSP_TAP26_RMRXSTO; tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val); - TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + tg3_phy_toggle_auxctl_smdsp(tp, false); } val = tr32(TG3_CPMU_EEE_MODE); @@ -2303,7 +2315,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) tg3_writephy(tp, MII_CTRL1000, CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER); - err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); + err = tg3_phy_toggle_auxctl_smdsp(tp, true); if (err) return err; @@ -2324,7 +2336,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200); tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000); - TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + tg3_phy_toggle_auxctl_smdsp(tp, false); tg3_writephy(tp, MII_CTRL1000, phy9_orig); @@ -2413,10 +2425,10 @@ static int tg3_phy_reset(struct tg3 *tp) out: if ((tp->phy_flags & TG3_PHYFLG_ADC_BUG) && - !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + !tg3_phy_toggle_auxctl_smdsp(tp, true)) { tg3_phydsp_write(tp, 0x201f, 0x2aaa); tg3_phydsp_write(tp, 0x000a, 0x0323); - TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + tg3_phy_toggle_auxctl_smdsp(tp, false); } if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) { @@ -2425,14 +2437,14 @@ static int tg3_phy_reset(struct tg3 *tp) } if (tp->phy_flags & TG3_PHYFLG_BER_BUG) { - if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + if (!tg3_phy_toggle_auxctl_smdsp(tp, true)) { tg3_phydsp_write(tp, 0x000a, 0x310b); tg3_phydsp_write(tp, 0x201f, 0x9506); tg3_phydsp_write(tp, 0x401f, 0x14e2); - TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + tg3_phy_toggle_auxctl_smdsp(tp, false); } } else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) { - if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + if (!tg3_phy_toggle_auxctl_smdsp(tp, true)) { tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) { tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b); @@ -2441,7 +2453,7 @@ static int tg3_phy_reset(struct tg3 *tp) } else tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); - TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + tg3_phy_toggle_auxctl_smdsp(tp, false); } } @@ -3858,7 +3870,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) tw32(TG3_CPMU_EEE_MODE, tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE); - err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); + err = tg3_phy_toggle_auxctl_smdsp(tp, true); if (!err) { u32 err2; @@ -3891,7 +3903,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) MII_TG3_DSP_CH34TP2_HIBW01); } - err2 = TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + err2 = tg3_phy_toggle_auxctl_smdsp(tp, false); if (!err) err = err2; } From 495f02922e05a6858005dc6b9e07eeed026cf9a0 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Tue, 26 Jun 2012 22:32:10 +0000 Subject: [PATCH 2130/2357] be2net: Fix to trim skb for padded vlan packets to workaround an ASIC Bug commit 93040ae5cc8dcc893eca4a4366dc8415af278edf upstream. Fixed spelling error in a comment as pointed out by DaveM. Also refactored existing code a bit to provide placeholders for another ASIC Bug workaround that will be checked-in soon after this. Signed-off-by: Somnath Kotur Signed-off-by: David S. Miller Cc: Jacek Luczak Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/emulex/benet/be.h | 5 ++ drivers/net/ethernet/emulex/benet/be_main.c | 56 +++++++++++++++------ 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 9576ac002c2..dcb02c219dd 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -536,6 +536,11 @@ static inline void be_check_sriov_fn_type(struct be_adapter *adapter) adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; } +static inline bool is_ipv4_pkt(struct sk_buff *skb) +{ + return skb->protocol == ntohs(ETH_P_IP) && ip_hdr(skb)->version == 4; +} + static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) { u32 addr; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 1bbf6b3eca9..ef1f9400b96 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -571,6 +571,11 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, return vlan_tag; } +static int be_vlan_tag_chk(struct be_adapter *adapter, struct sk_buff *skb) +{ + return vlan_tx_tag_present(skb) || adapter->pvid; +} + static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, u32 wrb_cnt, u32 len) { @@ -698,33 +703,56 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, return 0; } +static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, + struct sk_buff *skb) +{ + u16 vlan_tag = 0; + + skb = skb_share_check(skb, GFP_ATOMIC); + if (unlikely(!skb)) + return skb; + + if (vlan_tx_tag_present(skb)) { + vlan_tag = be_get_tx_vlan_tag(adapter, skb); + __vlan_put_tag(skb, vlan_tag); + skb->vlan_tci = 0; + } + + return skb; +} + static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)]; struct be_queue_info *txq = &txo->q; + struct iphdr *ip = NULL; u32 wrb_cnt = 0, copied = 0; - u32 start = txq->head; + u32 start = txq->head, eth_hdr_len; bool dummy_wrb, stopped = false; - /* For vlan tagged pkts, BE - * 1) calculates checksum even when CSO is not requested - * 2) calculates checksum wrongly for padded pkt less than - * 60 bytes long. - * As a workaround disable TX vlan offloading in such cases. + eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? + VLAN_ETH_HLEN : ETH_HLEN; + + /* HW has a bug which considers padding bytes as legal + * and modifies the IPv4 hdr's 'tot_len' field */ - if (unlikely(vlan_tx_tag_present(skb) && - (skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60))) { - skb = skb_share_check(skb, GFP_ATOMIC); - if (unlikely(!skb)) - goto tx_drop; + if (skb->len <= 60 && be_vlan_tag_chk(adapter, skb) && + is_ipv4_pkt(skb)) { + ip = (struct iphdr *)ip_hdr(skb); + pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len)); + } - skb = __vlan_put_tag(skb, be_get_tx_vlan_tag(adapter, skb)); + /* HW has a bug wherein it will calculate CSUM for VLAN + * pkts even though it is disabled. + * Manually insert VLAN in pkt. + */ + if (skb->ip_summed != CHECKSUM_PARTIAL && + be_vlan_tag_chk(adapter, skb)) { + skb = be_insert_vlan_in_pkt(adapter, skb); if (unlikely(!skb)) goto tx_drop; - - skb->vlan_tci = 0; } wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); From 72a274602416d7c5dc04641832af8d0710a548dd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 14 Feb 2013 10:52:45 -0800 Subject: [PATCH 2131/2357] Linux 3.4.31 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4941fd9876e..930db766a3f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 30 +SUBLEVEL = 31 EXTRAVERSION = NAME = Saber-toothed Squirrel From 18051b4221f2d593d8f98913cf7095dfec269706 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 29 Jan 2013 09:16:28 +0100 Subject: [PATCH 2132/2357] s390/timer: avoid overflow when programming clock comparator commit d911e03d097bdc01363df5d81c43f69432eb785c upstream. Since ed4f209 "s390/time: fix sched_clock() overflow" a new helper function is used to avoid overflows when converting TOD format values to nanosecond values. The kvm interrupt code formerly however only worked by accident because of an overflow. It tried to program a timer that would expire in more than ~29 years. Because of the old TOD-to-nanoseconds overflow bug the real expiry value however was much smaller, but now it isn't anymore. This however triggers yet another bug in the function that programs the clock comparator s390_next_ktime(): if the absolute "expires" value is after 2042 this will result in an overflow and the programmed value is lower than the current TOD value which immediatly triggers a clock comparator (= timer) interrupt. Since the timer isn't expired it will be programmed immediately again and so on... the result is a dead system. To fix this simply program the maximum possible value if an overflow is detected. Reported-by: Christian Borntraeger Tested-by: Christian Borntraeger Signed-off-by: Heiko Carstens Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/time.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index c5531dbc8b2..747ab28d0e6 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -121,6 +121,9 @@ static int s390_next_ktime(ktime_t expires, nsecs = ktime_to_ns(ktime_add(timespec_to_ktime(ts), expires)); do_div(nsecs, 125); S390_lowcore.clock_comparator = sched_clock_base_cc + (nsecs << 9); + /* Program the maximum value if we have an overflow (== year 2042) */ + if (unlikely(S390_lowcore.clock_comparator < sched_clock_base_cc)) + S390_lowcore.clock_comparator = -1ULL; set_clock_comparator(S390_lowcore.clock_comparator); return 0; } From e2ef6aad8a81c730bba92b2a44d758cabd7d9053 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 7 Feb 2013 09:44:13 -0800 Subject: [PATCH 2133/2357] x86: Do not leak kernel page mapping locations commit e575a86fdc50d013bf3ad3aa81d9100e8e6cc60d upstream. Without this patch, it is trivial to determine kernel page mappings by examining the error code reported to dmesg[1]. Instead, declare the entire kernel memory space as a violation of a present page. Additionally, since show_unhandled_signals is enabled by default, switch branch hinting to the more realistic expectation, and unobfuscate the setting of the PF_PROT bit to improve readability. [1] http://vulnfactory.org/blog/2013/02/06/a-linux-memory-trick/ Reported-by: Dan Rosenberg Suggested-by: Brad Spengler Signed-off-by: Kees Cook Acked-by: H. Peter Anvin Cc: Paul E. McKenney Cc: Frederic Weisbecker Cc: Eric W. Biederman Cc: Linus Torvalds Cc: Andrew Morton Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20130207174413.GA12485@www.outflux.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/fault.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 3ecfd1aaf21..e922e01868f 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -747,13 +747,15 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, return; } #endif + /* Kernel addresses are always protection faults: */ + if (address >= TASK_SIZE) + error_code |= PF_PROT; - if (unlikely(show_unhandled_signals)) + if (likely(show_unhandled_signals)) show_signal_msg(regs, error_code, address, tsk); - /* Kernel addresses are always protection faults: */ tsk->thread.cr2 = address; - tsk->thread.error_code = error_code | (address >= TASK_SIZE); + tsk->thread.error_code = error_code; tsk->thread.trap_nr = X86_TRAP_PF; force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0); From 65f55391cf03b2e4bcfec63b08b8db032b4d6f3a Mon Sep 17 00:00:00 2001 From: Stoney Wang Date: Thu, 7 Feb 2013 10:53:02 -0800 Subject: [PATCH 2134/2357] x86/apic: Work around boot failure on HP ProLiant DL980 G7 Server systems commit cb214ede7657db458fd0b2a25ea0b28dbf900ebc upstream. When a HP ProLiant DL980 G7 Server boots a regular kernel, there will be intermittent lost interrupts which could result in a hang or (in extreme cases) data loss. The reason is that this system only supports x2apic physical mode, while the kernel boots with a logical-cluster default setting. This bug can be worked around by specifying the "x2apic_phys" or "nox2apic" boot option, but we want to handle this system without requiring manual workarounds. The BIOS sets ACPI_FADT_APIC_PHYSICAL in FADT table. As all apicids are smaller than 255, BIOS need to pass the control to the OS with xapic mode, according to x2apic-spec, chapter 2.9. Current code handle x2apic when BIOS pass with xapic mode enabled: When user specifies x2apic_phys, or FADT indicates PHYSICAL: 1. During madt oem check, apic driver is set with xapic logical or xapic phys driver at first. 2. enable_IR_x2apic() will enable x2apic_mode. 3. if user specifies x2apic_phys on the boot line, x2apic_phys_probe() will install the correct x2apic phys driver and use x2apic phys mode. Otherwise it will skip the driver will let x2apic_cluster_probe to take over to install x2apic cluster driver (wrong one) even though FADT indicates PHYSICAL, because x2apic_phys_probe does not check FADT PHYSICAL. Add checking x2apic_fadt_phys in x2apic_phys_probe() to fix the problem. Signed-off-by: Stoney Wang [ updated the changelog and simplified the code ] Signed-off-by: Yinghai Lu Link: http://lkml.kernel.org/r/1360263182-16226-1-git-send-email-yinghai@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/apic/x2apic_phys.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c index 991e315f422..db31a2cfc9a 100644 --- a/arch/x86/kernel/apic/x2apic_phys.c +++ b/arch/x86/kernel/apic/x2apic_phys.c @@ -20,18 +20,19 @@ static int set_x2apic_phys_mode(char *arg) } early_param("x2apic_phys", set_x2apic_phys_mode); -static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) +static bool x2apic_fadt_phys(void) { - if (x2apic_phys) - return x2apic_enabled(); - else if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) && - (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) && - x2apic_enabled()) { + if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) && + (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) { printk(KERN_DEBUG "System requires x2apic physical mode\n"); - return 1; + return true; } - else - return 0; + return false; +} + +static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) +{ + return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys()); } static void @@ -114,7 +115,7 @@ static void init_x2apic_ldr(void) static int x2apic_phys_probe(void) { - if (x2apic_mode && x2apic_phys) + if (x2apic_mode && (x2apic_phys || x2apic_fadt_phys())) return 1; return apic == &apic_x2apic_phys; From 44f80d63b26469593b633bc40049538683e70311 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Mon, 11 Feb 2013 14:52:36 +0000 Subject: [PATCH 2135/2357] x86/mm: Check if PUD is large when validating a kernel address commit 0ee364eb316348ddf3e0dfcd986f5f13f528f821 upstream. A user reported the following oops when a backup process reads /proc/kcore: BUG: unable to handle kernel paging request at ffffbb00ff33b000 IP: [] kern_addr_valid+0xbe/0x110 [...] Call Trace: [] read_kcore+0x17a/0x370 [] proc_reg_read+0x77/0xc0 [] vfs_read+0xc7/0x130 [] sys_read+0x53/0xa0 [] system_call_fastpath+0x16/0x1b Investigation determined that the bug triggered when reading system RAM at the 4G mark. On this system, that was the first address using 1G pages for the virt->phys direct mapping so the PUD is pointing to a physical address, not a PMD page. The problem is that the page table walker in kern_addr_valid() is not checking pud_large() and treats the physical address as if it was a PMD. If it happens to look like pmd_none then it'll silently fail, probably returning zeros instead of real data. If the data happens to look like a present PMD though, it will be walked resulting in the oops above. This patch adds the necessary pud_large() check. Unfortunately the problem was not readily reproducible and now they are running the backup program without accessing /proc/kcore so the patch has not been validated but I think it makes sense. Signed-off-by: Mel Gorman Reviewed-by: Rik van Riel Reviewed-by: Michal Hocko Acked-by: Johannes Weiner Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20130211145236.GX21389@suse.de Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/pgtable.h | 5 +++++ arch/x86/mm/init_64.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index c3520d76820..3f3dd526b3b 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -142,6 +142,11 @@ static inline unsigned long pmd_pfn(pmd_t pmd) return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT; } +static inline unsigned long pud_pfn(pud_t pud) +{ + return (pud_val(pud) & PTE_PFN_MASK) >> PAGE_SHIFT; +} + #define pte_page(pte) pfn_to_page(pte_pfn(pte)) static inline int pmd_large(pmd_t pte) diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index fc18be0f6f2..faf7a6830c0 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -821,6 +821,9 @@ int kern_addr_valid(unsigned long addr) if (pud_none(*pud)) return 0; + if (pud_large(*pud)) + return pfn_valid(pud_pfn(*pud)); + pmd = pmd_offset(pud, addr); if (pmd_none(*pmd)) return 0; From dc66ff14a9489f8c239ecc43a20ca946cce8d217 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 24 Jan 2013 13:11:10 +0000 Subject: [PATCH 2136/2357] x86/xen: don't assume %ds is usable in xen_iret for 32-bit PVOPS. commit 13d2b4d11d69a92574a55bfd985cfb0ca77aebdc upstream. This fixes CVE-2013-0228 / XSA-42 Drew Jones while working on CVE-2013-0190 found that that unprivileged guest user in 32bit PV guest can use to crash the > guest with the panic like this: ------------- general protection fault: 0000 [#1] SMP last sysfs file: /sys/devices/vbd-51712/block/xvda/dev Modules linked in: sunrpc ipt_REJECT nf_conntrack_ipv4 nf_defrag_ipv4 iptable_filter ip_tables ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables ipv6 xen_netfront ext4 mbcache jbd2 xen_blkfront dm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan] Pid: 1250, comm: r Not tainted 2.6.32-356.el6.i686 #1 EIP: 0061:[] EFLAGS: 00010086 CPU: 0 EIP is at xen_iret+0x12/0x2b EAX: eb8d0000 EBX: 00000001 ECX: 08049860 EDX: 00000010 ESI: 00000000 EDI: 003d0f00 EBP: b77f8388 ESP: eb8d1fe0 DS: 0000 ES: 007b FS: 0000 GS: 00e0 SS: 0069 Process r (pid: 1250, ti=eb8d0000 task=c2953550 task.ti=eb8d0000) Stack: 00000000 0027f416 00000073 00000206 b77f8364 0000007b 00000000 00000000 Call Trace: Code: c3 8b 44 24 18 81 4c 24 38 00 02 00 00 8d 64 24 30 e9 03 00 00 00 8d 76 00 f7 44 24 08 00 00 02 80 75 33 50 b8 00 e0 ff ff 21 e0 <8b> 40 10 8b 04 85 a0 f6 ab c0 8b 80 0c b0 b3 c0 f6 44 24 0d 02 EIP: [] xen_iret+0x12/0x2b SS:ESP 0069:eb8d1fe0 general protection fault: 0000 [#2] ---[ end trace ab0d29a492dcd330 ]--- Kernel panic - not syncing: Fatal exception Pid: 1250, comm: r Tainted: G D --------------- 2.6.32-356.el6.i686 #1 Call Trace: [] ? panic+0x6e/0x122 [] ? oops_end+0xbc/0xd0 [] ? do_general_protection+0x0/0x210 [] ? error_code+0x73/ ------------- Petr says: " I've analysed the bug and I think that xen_iret() cannot cope with mangled DS, in this case zeroed out (null selector/descriptor) by either xen_failsafe_callback() or RESTORE_REGS because the corresponding LDT entry was invalidated by the reproducer. " Jan took a look at the preliminary patch and came up a fix that solves this problem: "This code gets called after all registers other than those handled by IRET got already restored, hence a null selector in %ds or a non-null one that got loaded from a code or read-only data descriptor would cause a kernel mode fault (with the potential of crashing the kernel as a whole, if panic_on_oops is set)." The way to fix this is to realize that the we can only relay on the registers that IRET restores. The two that are guaranteed are the %cs and %ss as they are always fixed GDT selectors. Also they are inaccessible from user mode - so they cannot be altered. This is the approach taken in this patch. Another alternative option suggested by Jan would be to relay on the subtle realization that using the %ebp or %esp relative references uses the %ss segment. In which case we could switch from using %eax to %ebp and would not need the %ss over-rides. That would also require one extra instruction to compensate for the one place where the register is used as scaled index. However Andrew pointed out that is too subtle and if further work was to be done in this code-path it could escape folks attention and lead to accidents. Reviewed-by: Petr Matousek Reported-by: Petr Matousek Reviewed-by: Andrew Cooper Signed-off-by: Jan Beulich Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/xen-asm_32.S | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S index b040b0e518c..7328f71651e 100644 --- a/arch/x86/xen/xen-asm_32.S +++ b/arch/x86/xen/xen-asm_32.S @@ -88,11 +88,11 @@ ENTRY(xen_iret) */ #ifdef CONFIG_SMP GET_THREAD_INFO(%eax) - movl TI_cpu(%eax), %eax - movl __per_cpu_offset(,%eax,4), %eax - mov xen_vcpu(%eax), %eax + movl %ss:TI_cpu(%eax), %eax + movl %ss:__per_cpu_offset(,%eax,4), %eax + mov %ss:xen_vcpu(%eax), %eax #else - movl xen_vcpu, %eax + movl %ss:xen_vcpu, %eax #endif /* check IF state we're restoring */ @@ -105,11 +105,11 @@ ENTRY(xen_iret) * resuming the code, so we don't have to be worried about * being preempted to another CPU. */ - setz XEN_vcpu_info_mask(%eax) + setz %ss:XEN_vcpu_info_mask(%eax) xen_iret_start_crit: /* check for unmasked and pending */ - cmpw $0x0001, XEN_vcpu_info_pending(%eax) + cmpw $0x0001, %ss:XEN_vcpu_info_pending(%eax) /* * If there's something pending, mask events again so we can @@ -117,7 +117,7 @@ xen_iret_start_crit: * touch XEN_vcpu_info_mask. */ jne 1f - movb $1, XEN_vcpu_info_mask(%eax) + movb $1, %ss:XEN_vcpu_info_mask(%eax) 1: popl %eax From 15295d7dc33491a0a015a0f48d04bbaa696b802d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 11 Feb 2013 20:49:49 +0100 Subject: [PATCH 2137/2357] PCI/PM: Clean up PME state when removing a device commit 249bfb83cf8ba658955f0245ac3981d941f746ee upstream. Devices are added to pci_pme_list when drivers use pci_enable_wake() or pci_wake_from_d3(), but they aren't removed from the list unless the driver explicitly disables wakeup. Many drivers never disable wakeup, so their devices remain on the list even after they are removed, e.g., via hotplug. A subsequent PME poll will oops when it tries to touch the device. This patch disables PME# on a device before removing it, which removes the device from pci_pme_list. This is safe even if the device never had PME# enabled. This oops can be triggered by unplugging a Thunderbolt ethernet adapter on a Macbook Pro, as reported by Daniel below. [bhelgaas: changelog] Reference: http://lkml.kernel.org/r/CAMVG2svG21yiM1wkH4_2pen2n+cr2-Zv7TbH3Gj+8MwevZjDbw@mail.gmail.com Reported-and-tested-by: Daniel J Blueman Signed-off-by: Rafael J. Wysocki Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman --- drivers/pci/remove.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index fd77e2bde2e..eae55c7b647 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -19,6 +19,8 @@ static void pci_free_resources(struct pci_dev *dev) static void pci_stop_dev(struct pci_dev *dev) { + pci_pme_active(dev, false); + if (dev->is_added) { pci_proc_detach_device(dev); pci_remove_sysfs_dev_files(dev); From 266c43c175a51002b04c18a453a39708d1775ced Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Thu, 14 Feb 2013 09:12:52 +0900 Subject: [PATCH 2138/2357] efi: Clear EFI_RUNTIME_SERVICES rather than EFI_BOOT by "noefi" boot parameter commit 1de63d60cd5b0d33a812efa455d5933bf1564a51 upstream. There was a serious problem in samsung-laptop that its platform driver is designed to run under BIOS and running under EFI can cause the machine to become bricked or can cause Machine Check Exceptions. Discussion about this problem: https://bugs.launchpad.net/ubuntu-cdimage/+bug/1040557 https://bugzilla.kernel.org/show_bug.cgi?id=47121 The patches to fix this problem: efi: Make 'efi_enabled' a function to query EFI facilities 83e68189745ad931c2afd45d8ee3303929233e7f samsung-laptop: Disable on EFI hardware e0094244e41c4d0c7ad69920681972fc45d8ce34 Unfortunately this problem comes back again if users specify "noefi" option. This parameter clears EFI_BOOT and that driver continues to run even if running under EFI. Refer to the document, this parameter should clear EFI_RUNTIME_SERVICES instead. Documentation/kernel-parameters.txt: =============================================================================== ... noefi [X86] Disable EFI runtime services support. ... =============================================================================== Documentation/x86/x86_64/uefi.txt: =============================================================================== ... - If some or all EFI runtime services don't work, you can try following kernel command line parameters to turn off some or all EFI runtime services. noefi turn off all EFI runtime services ... =============================================================================== Signed-off-by: Satoru Takeuchi Link: http://lkml.kernel.org/r/511C2C04.2070108@jp.fujitsu.com Cc: Matt Fleming Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/efi/efi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 6fcd4ad9bb6..3705bb049e5 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -86,7 +86,7 @@ EXPORT_SYMBOL(efi_enabled); static int __init setup_noefi(char *arg) { - clear_bit(EFI_BOOT, &x86_efi_facility); + clear_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility); return 0; } early_param("noefi", setup_noefi); From 248924caf7d1e452e3cad8433ae7b4942654ea8b Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 8 Aug 2012 05:23:22 +0000 Subject: [PATCH 2139/2357] igb: Remove artificial restriction on RQDPC stat reading commit ae1c07a6b7ced6c0c94c99e3b53f4e7856fa8bff upstream. For some reason the reading of the RQDPC register was being artificially limited to 4K. Instead of limiting the value we should read the value and add the full amount. Otherwise this can lead to a misleading number of dropped packets when the actual value is in fact much higher. Signed-off-by: Alexander Duyck Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher Cc: Vinson Lee Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/igb/igb_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6b4f0148ee6..1fb180dbc7b 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -4649,11 +4649,13 @@ void igb_update_stats(struct igb_adapter *adapter, bytes = 0; packets = 0; for (i = 0; i < adapter->num_rx_queues; i++) { - u32 rqdpc_tmp = rd32(E1000_RQDPC(i)) & 0x0FFF; + u32 rqdpc = rd32(E1000_RQDPC(i)); struct igb_ring *ring = adapter->rx_ring[i]; - ring->rx_stats.drops += rqdpc_tmp; - net_stats->rx_fifo_errors += rqdpc_tmp; + if (rqdpc) { + ring->rx_stats.drops += rqdpc; + net_stats->rx_fifo_errors += rqdpc; + } do { start = u64_stats_fetch_begin_bh(&ring->rx_syncp); From 9ad3bfb9e26197c378d6c239180ed7bcf7c29fd8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 17 Feb 2013 10:49:37 -0800 Subject: [PATCH 2140/2357] Linux 3.4.32 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 930db766a3f..ece89702c5c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 31 +SUBLEVEL = 32 EXTRAVERSION = NAME = Saber-toothed Squirrel From 8ff19d42a104535a8a67a3fa8df39f72f23b2743 Mon Sep 17 00:00:00 2001 From: Mahesh Palivela Date: Fri, 22 Jun 2012 07:27:46 +0000 Subject: [PATCH 2141/2357] wireless: add VHT (802.11ac) definitions Add the VHT definitions to be used by drivers supporting it. Change-Id: Ia301cf72940cef19767f4f485a09c9afc12ae514 CRs-fixed: 452921 Signed-off-by: Mahesh Palivela Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 70 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index a2b59d795ae..b767ec80e88 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1074,6 +1074,73 @@ struct ieee80211_ht_info { #define WLAN_HT_SMPS_CONTROL_STATIC 1 #define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 +#define VHT_MCS_SUPPORTED_SET_SIZE 8 + +struct ieee80211_vht_capabilities { + __le32 vht_capabilities_info; + u8 vht_supported_mcs_set[VHT_MCS_SUPPORTED_SET_SIZE]; +} __packed; + +struct ieee80211_vht_operation { + u8 vht_op_info_chwidth; + u8 vht_op_info_chan_center_freq_seg1_idx; + u8 vht_op_info_chan_center_freq_seg2_idx; + __le16 vht_basic_mcs_set; +} __packed; + +/** + * struct ieee80211_vht_mcs_info - VHT MCS information + * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams + * @rx_highest: Indicates highest long GI VHT PPDU data rate + * STA can receive. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest RX data rate supported. + * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams + * @tx_highest: Indicates highest long GI VHT PPDU data rate + * STA can transmit. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest TX data rate supported. + */ +struct ieee80211_vht_mcs_info { + __le16 rx_mcs_map; + __le16 rx_highest; + __le16 tx_mcs_map; + __le16 tx_highest; +} __packed; + +#define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0 +#define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1 +#define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT 2 +#define IEEE80211_VHT_MCS_NOT_SUPPORTED 3 + +/* 802.11ac VHT Capabilities */ +#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 +#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001 +#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 +#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 +#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 +#define IEEE80211_VHT_CAP_RXLDPC 0x00000010 +#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 +#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 +#define IEEE80211_VHT_CAP_TXSTBC 0x00000080 +#define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100 +#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200 +#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 +#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 +#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 +#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 +#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000 +#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000 +#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 +#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 +#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 +#define IEEE80211_VHT_CAP_HTC_VHT 0x00400000 +#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT 0x00800000 +#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000 +#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 +#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 +#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 + /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 @@ -1334,6 +1401,9 @@ enum ieee80211_eid { WLAN_EID_DSE_REGISTERED_LOCATION = 58, WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, WLAN_EID_EXT_CHANSWITCH_ANN = 60, + + WLAN_EID_VHT_CAPABILITY = 191, + WLAN_EID_VHT_OPERATION = 192, }; /* Action category code */ From 3254baddc0c398ccadb2d0e638b9b7e7819c848a Mon Sep 17 00:00:00 2001 From: Mahesh Palivela Date: Thu, 21 Feb 2013 05:28:31 +0530 Subject: [PATCH 2142/2357] cfg80211: allow advertising VHT capabilities Allow drivers to advertise their VHT capabilities and export them to userspace via nl80211. Change-Id: I2d2825a09dfddccca1bd3edacd7fc382d765bea5 CRs-fixed: 452921 Signed-off-by: Mahesh Palivela Signed-off-by: Johannes Berg --- include/linux/nl80211.h | 6 ++++++ include/net/cfg80211.h | 17 +++++++++++++++++ net/wireless/nl80211.c | 9 +++++++++ 3 files changed, 32 insertions(+) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index d5ed1035c79..1f4c164d6b9 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1832,6 +1832,9 @@ enum nl80211_mpath_info { * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n + * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as + * defined in 802.11ac + * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined * @__NL80211_BAND_ATTR_AFTER_LAST: internal use */ @@ -1845,6 +1848,9 @@ enum nl80211_band_attr { NL80211_BAND_ATTR_HT_AMPDU_FACTOR, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, + NL80211_BAND_ATTR_VHT_MCS_SET, + NL80211_BAND_ATTR_VHT_CAPA, + /* keep last */ __NL80211_BAND_ATTR_AFTER_LAST, NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a166ee3fe52..10b8288be50 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -210,6 +210,22 @@ struct ieee80211_sta_ht_cap { struct ieee80211_mcs_info mcs; }; +/** + * struct ieee80211_sta_vht_cap - STA's VHT capabilities + * + * This structure describes most essential parameters needed + * to describe 802.11ac VHT capabilities for an STA. + * + * @vht_supported: is VHT supported by the STA + * @cap: VHT capabilities map as described in 802.11ac spec + * @vht_mcs: Supported VHT MCS rates + */ +struct ieee80211_sta_vht_cap { + bool vht_supported; + u32 cap; /* use IEEE80211_VHT_CAP_ */ + struct ieee80211_vht_mcs_info vht_mcs; +}; + /** * struct ieee80211_supported_band - frequency band definition * @@ -233,6 +249,7 @@ struct ieee80211_supported_band { int n_channels; int n_bitrates; struct ieee80211_sta_ht_cap ht_cap; + struct ieee80211_sta_vht_cap vht_cap; }; /* diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e73504e3b6c..8303690284a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -811,6 +811,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, dev->wiphy.bands[band]->ht_cap.ampdu_density); } + /* add VHT info */ + if (dev->wiphy.bands[band]->vht_cap.vht_supported && + (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, + sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), + &dev->wiphy.bands[band]->vht_cap.vht_mcs) || + nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, + dev->wiphy.bands[band]->vht_cap.cap))) + goto nla_put_failure; + /* add frequencies */ nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); if (!nl_freqs) From fcc24975ebe2a58f0c3b121b1c1cd4b24d86c407 Mon Sep 17 00:00:00 2001 From: Mahesh Palivela Date: Thu, 21 Feb 2013 06:22:19 +0530 Subject: [PATCH 2143/2357] mac80211: include VHT capability IE in probe requests Insert the VHT capability IE into probe requests. Change-Id: I75620090969b46701f1c760baf9c6559a4a1ac2c CRs-fixed: 452921 Signed-off-by: Mahesh Palivela Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/main.c | 8 +++++++- net/mac80211/util.c | 24 ++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index db8fae51714..1f13892196f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1475,6 +1475,8 @@ u8 *ieee80211_ie_build_ht_info(u8 *pos, struct ieee80211_channel *channel, enum nl80211_channel_type channel_type); +u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, + u32 cap); /* internal work items */ void ieee80211_work_init(struct ieee80211_local *local); void ieee80211_add_work(struct ieee80211_work *wk); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 16336480c63..c80361f5a01 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -673,7 +673,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) int result, i; enum ieee80211_band band; int channels, max_bitrates; - bool supp_ht; + bool supp_ht, supp_vht; static const u32 cipher_suites[] = { /* keep WEP first, it may be removed below */ WLAN_CIPHER_SUITE_WEP40, @@ -706,6 +706,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) channels = 0; max_bitrates = 0; supp_ht = false; + supp_vht = false; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; @@ -723,6 +724,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; + supp_vht = supp_vht || sband->vht_cap.vht_supported; } local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + @@ -798,6 +800,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (supp_ht) local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); + if (supp_vht) + local->scan_ies_len += + 2 + sizeof(struct ieee80211_vht_capabilities); + if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ local->hw.wiphy->max_scan_ssids = 4; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 32f7a3b3d43..128ac2af1a4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1031,6 +1031,9 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, pos += noffset - offset; } + if (sband->vht_cap.vht_supported) + pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, + sband->vht_cap.cap); return pos - buffer; } @@ -1611,6 +1614,27 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, return pos; } +u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, + u32 cap) +{ + __le32 tmp; + + *pos++ = WLAN_EID_VHT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_vht_capabilities); + memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); + + /* capability flags */ + tmp = cpu_to_le32(cap); + memcpy(pos, &tmp, sizeof(u32)); + pos += sizeof(u32); + + /* VHT MCS set */ + memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs)); + pos += sizeof(vht_cap->vht_mcs); + + return pos; +} + u8 *ieee80211_ie_build_ht_info(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, struct ieee80211_channel *channel, From 4cdf85ae77f066e29d518f056201095943028e9d Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Wed, 16 Jan 2013 11:22:08 -0500 Subject: [PATCH 2144/2357] Perf: Toggle PMU IRQ when CPU's are hotplugged When a CPU is hotplugged out while a perf session is active, disarm the IRQ when the CPU is preparing to die. This ensures that perf doesn't lock up when it tries to free the irq of a hotplugged CPU. Similarly, when a CPU comes online during a perf session enable the IRQ so that perf doesn't try to disable an unarmed IRQ when it finishes. Change-Id: Ic4e412e5f1effae0db34a3e4b5e7e5c65faed2a0 Signed-off-by: Ashwin Chaugule --- arch/arm/include/asm/pmu.h | 3 ++ arch/arm/kernel/perf_event.c | 92 ++++++++++++++++++++++++++-------- arch/arm/mach-msm/perf_debug.c | 1 + arch/arm/mach-msm/pmu.c | 13 ----- 4 files changed, 75 insertions(+), 34 deletions(-) diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 5188dbf42c0..d1a3e619481 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -151,6 +151,9 @@ int armpmu_event_set_period(struct perf_event *event, struct hw_perf_event *hwc, int idx); +extern void enable_irq_callback(void *); +extern void disable_irq_callback(void *); + #endif /* CONFIG_HW_PERF_EVENTS */ #endif /* __ARM_PMU_H__ */ diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index d2e2e445831..85b1bb373ae 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -739,6 +739,36 @@ static void __init cpu_pmu_init(struct arm_pmu *armpmu) armpmu->type = ARM_PMU_DEVICE_CPU; } +static int cpu_has_active_perf(void) +{ + struct pmu_hw_events *hw_events; + int enabled; + + if (!cpu_pmu) + return 0; + + hw_events = cpu_pmu->get_hw_events(); + enabled = bitmap_weight(hw_events->used_mask, cpu_pmu->num_events); + + if (enabled) + /*Even one event's existence is good enough.*/ + return 1; + + return 0; +} + +void enable_irq_callback(void *info) +{ + int irq = *(unsigned int *)info; + enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING); +} + +void disable_irq_callback(void *info) +{ + int irq = *(unsigned int *)info; + disable_percpu_irq(irq); +} + /* * PMU hardware loses all context when a CPU goes offline. * When a CPU is hotplugged back in, since some hardware registers are @@ -748,12 +778,50 @@ static void __init cpu_pmu_init(struct arm_pmu *armpmu) static int __cpuinit pmu_cpu_notify(struct notifier_block *b, unsigned long action, void *hcpu) { + int irq; + + if (cpu_has_active_perf()) { + switch ((action & ~CPU_TASKS_FROZEN)) { + + case CPU_DOWN_PREPARE: + /* + * If this is on a multicore CPU, we need + * to disarm the PMU IRQ before disappearing. + */ + if (cpu_pmu && + cpu_pmu->plat_device->dev.platform_data) { + irq = platform_get_irq(cpu_pmu->plat_device, 1); + smp_call_function_single((int)hcpu, + disable_irq_callback, &irq, 1); + } + return NOTIFY_DONE; + + case CPU_UP_PREPARE: + /* + * If this is on a multicore CPU, we need + * to arm the PMU IRQ before appearing. + */ + if (cpu_pmu && + cpu_pmu->plat_device->dev.platform_data) { + irq = platform_get_irq(cpu_pmu->plat_device, 1); + smp_call_function_single((int)hcpu, + enable_irq_callback, &irq, 1); + } + return NOTIFY_DONE; + + case CPU_STARTING: + if (cpu_pmu && cpu_pmu->reset) { + cpu_pmu->reset(NULL); + return NOTIFY_OK; + } + default: + return NOTIFY_DONE; + } + } + if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) return NOTIFY_DONE; - if (cpu_pmu && cpu_pmu->reset) - cpu_pmu->reset(NULL); - return NOTIFY_OK; } @@ -777,24 +845,6 @@ static void armpmu_update_counters(void) } } -static int cpu_has_active_perf(void) -{ - struct pmu_hw_events *hw_events; - int enabled; - - if (!cpu_pmu) - return 0; - - hw_events = cpu_pmu->get_hw_events(); - enabled = bitmap_weight(hw_events->used_mask, cpu_pmu->num_events); - - if (enabled) - /*Even one event's existence is good enough.*/ - return 1; - - return 0; -} - static struct notifier_block __cpuinitdata pmu_cpu_notifier = { .notifier_call = pmu_cpu_notify, }; diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c index eefe32686f9..8c942ad51b6 100644 --- a/arch/arm/mach-msm/perf_debug.c +++ b/arch/arm/mach-msm/perf_debug.c @@ -24,6 +24,7 @@ static char *descriptions = "0 msm: perf: add debug patch logging framework\n" "1 Perf: Restore counter after powercollapse for generic ARM PMU's\n" + "2 Perf: Toggle PMU IRQ when CPU's are hotplugged\n" ; static ssize_t desc_read(struct file *fp, char __user *buf, diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c index 5e87bc01202..8d65eea345e 100644 --- a/arch/arm/mach-msm/pmu.c +++ b/arch/arm/mach-msm/pmu.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include @@ -19,18 +18,6 @@ #if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) static DEFINE_PER_CPU(u32, pmu_irq_cookie); -static void enable_irq_callback(void *info) -{ - int irq = *(unsigned int *)info; - enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING); -} - -static void disable_irq_callback(void *info) -{ - int irq = *(unsigned int *)info; - disable_percpu_irq(irq); -} - static int multicore_request_irq(int irq, irq_handler_t *handle_irq) { From 05cfbed68ddd97a1440837f572f3b85a36e9c554 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Tue, 19 Feb 2013 16:10:10 -0500 Subject: [PATCH 2145/2357] Perf: Correct irq for CPU hotplug detection The platform data was requesting the wrong number, it should request the first perf irq item. Change-Id: I4a25b4704ed9e76172c6b0d4ca4b28a3286ab2ad Signed-off-by: Neil Leeder --- arch/arm/kernel/perf_event.c | 4 ++-- arch/arm/mach-msm/perf_debug.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 85b1bb373ae..8fb93d07de0 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -790,7 +790,7 @@ static int __cpuinit pmu_cpu_notify(struct notifier_block *b, */ if (cpu_pmu && cpu_pmu->plat_device->dev.platform_data) { - irq = platform_get_irq(cpu_pmu->plat_device, 1); + irq = platform_get_irq(cpu_pmu->plat_device, 0); smp_call_function_single((int)hcpu, disable_irq_callback, &irq, 1); } @@ -803,7 +803,7 @@ static int __cpuinit pmu_cpu_notify(struct notifier_block *b, */ if (cpu_pmu && cpu_pmu->plat_device->dev.platform_data) { - irq = platform_get_irq(cpu_pmu->plat_device, 1); + irq = platform_get_irq(cpu_pmu->plat_device, 0); smp_call_function_single((int)hcpu, enable_irq_callback, &irq, 1); } diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c index 8c942ad51b6..bbd08523bd8 100644 --- a/arch/arm/mach-msm/perf_debug.c +++ b/arch/arm/mach-msm/perf_debug.c @@ -25,6 +25,7 @@ static char *descriptions = "0 msm: perf: add debug patch logging framework\n" "1 Perf: Restore counter after powercollapse for generic ARM PMU's\n" "2 Perf: Toggle PMU IRQ when CPU's are hotplugged\n" + "3 Perf: Correct irq for CPU hotplug detection\n" ; static ssize_t desc_read(struct file *fp, char __user *buf, From ce0030c00f95cf9110d9cdcd41e901e1fb814417 Mon Sep 17 00:00:00 2001 From: Alexandre SIMON Date: Fri, 1 Feb 2013 15:31:54 +0100 Subject: [PATCH 2146/2357] printk: fix buffer overflow when calling log_prefix function from call_console_drivers This patch corrects a buffer overflow in kernels from 3.0 to 3.4 when calling log_prefix() function from call_console_drivers(). This bug existed in previous releases but has been revealed with commit 162a7e7500f9664636e649ba59defe541b7c2c60 (2.6.39 => 3.0) that made changes about how to allocate memory for early printk buffer (use of memblock_alloc). It disappears with commit 7ff9554bb578ba02166071d2d487b7fc7d860d62 (3.4 => 3.5) that does a refactoring of printk buffer management. In log_prefix(), the access to "p[0]", "p[1]", "p[2]" or "simple_strtoul(&p[1], &endp, 10)" may cause a buffer overflow as this function is called from call_console_drivers by passing "&LOG_BUF(cur_index)" where the index must be masked to do not exceed the buffer's boundary. The trick is to prepare in call_console_drivers() a buffer with the necessary data (PRI field of syslog message) to be safely evaluated in log_prefix(). This patch can be applied to stable kernel branches 3.0.y, 3.2.y and 3.4.y. Without this patch, one can freeze a server running this loop from shell : $ export DUMMY=`cat /dev/urandom | tr -dc '12345AZERTYUIOPQSDFGHJKLMWXCVBNazertyuiopqsdfghjklmwxcvbn' | head -c255` $ while true do ; echo $DUMMY > /dev/kmsg ; done The "server freeze" depends on where memblock_alloc does allocate printk buffer : if the buffer overflow is inside another kernel allocation the problem may not be revealed, else the server may hangs up. Signed-off-by: Alexandre SIMON Signed-off-by: Greg Kroah-Hartman --- include/linux/syslog.h | 6 ++++++ kernel/printk.c | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/linux/syslog.h b/include/linux/syslog.h index 38911391a13..ce4c6655605 100644 --- a/include/linux/syslog.h +++ b/include/linux/syslog.h @@ -47,6 +47,12 @@ #define SYSLOG_FROM_CALL 0 #define SYSLOG_FROM_FILE 1 +/* + * Syslog priority (PRI) maximum length in char : '<[0-9]{1,3}>' + * See RFC5424 for details +*/ +#define SYSLOG_PRI_MAX_LENGTH 5 + int do_syslog(int type, char __user *buf, int count, bool from_file); #endif /* _LINUX_SYSLOG_H */ diff --git a/kernel/printk.c b/kernel/printk.c index b663c2c95d3..e95c66223d3 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -638,8 +638,19 @@ static void call_console_drivers(unsigned start, unsigned end) start_print = start; while (cur_index != end) { if (msg_level < 0 && ((end - cur_index) > 2)) { + /* + * prepare buf_prefix, as a contiguous array, + * to be processed by log_prefix function + */ + char buf_prefix[SYSLOG_PRI_MAX_LENGTH+1]; + unsigned i; + for (i = 0; i < ((end - cur_index)) && (i < SYSLOG_PRI_MAX_LENGTH); i++) { + buf_prefix[i] = LOG_BUF(cur_index + i); + } + buf_prefix[i] = '\0'; /* force '\0' as last string character */ + /* strip log prefix */ - cur_index += log_prefix(&LOG_BUF(cur_index), &msg_level, NULL); + cur_index += log_prefix((const char *)&buf_prefix, &msg_level, NULL); start_print = cur_index; } while (cur_index != end) { From 1c3000a67a350c7ac31897cf22ec8e4ddd47d3aa Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 21 Feb 2013 10:05:05 -0800 Subject: [PATCH 2147/2357] 3.4.33 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ece89702c5c..a26d19a31d9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 32 +SUBLEVEL = 33 EXTRAVERSION = NAME = Saber-toothed Squirrel From 55cf35b49777586b86d1b1ab476e6b7e2009b0a7 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Wed, 20 Feb 2013 18:40:59 -0800 Subject: [PATCH 2148/2357] power: pm8921-charger: don't reject all the chg current requests The driver currently rejects any changes to the USB charge current if no other source of power is present. This causes issues because if a pc usb cable which supplies 500mA is connected while the PMIC was drawing 1500mA, it will continue to draw 1500mA from it causing charger collapse. The reason why the rejects were put in place were because if we are running from USB as the source, vbus_draw() could be called with 0mA. This would cause brownouts. So only reject setting the current to 0mA in case another source is not present. Change-Id: I55a829db369bf60de2ba86a522480dacddc02186 Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/pm8921-charger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c index b3fd5bc0732..ba1a5681af3 100644 --- a/drivers/power/pm8921-charger.c +++ b/drivers/power/pm8921-charger.c @@ -2098,10 +2098,10 @@ void pm8921_charger_vbus_draw(unsigned int mA) * This would also apply when the battery has been * removed from the running system. */ - if (the_chip && !get_prop_batt_present(the_chip) + if (mA == 0 && the_chip && !get_prop_batt_present(the_chip) && !is_dc_chg_plugged_in(the_chip)) { if (!the_chip->has_dc_supply) { - pr_err("rejected: no other power source connected\n"); + pr_err("rejected: no other power source mA = %d\n", mA); return; } } From c2392df88afbb985d9396aa75c202830b471245d Mon Sep 17 00:00:00 2001 From: Liron Kuch Date: Thu, 14 Feb 2013 16:26:38 +0200 Subject: [PATCH 2149/2357] tspp: improve tspp_open_stream/tspp_close_stream behavior The TSPP driver's kernel API supports opening and closing a TSPP stream using the tspp_open_stream/tspp_close_stream API functions. This commit fixes a few minor issues with the behavior and usage of this API. tspp_open_stream and tspp_close_stream were fixed to connect/disconnect the appropriate TSIF source based on the TSIF reference count. The call to tspp_close_stream from within tspp_close_channel was removed, since a kernel driver that uses the TSPP driver API is expected to call tspp_close_stream explicitly, and not rely on the TSPP driver to close the stream implicitly when the channel is closed. An ioctl was added to allow user-space application to close the stream. Change-Id: If49b440d9d83c8bba54aeabc18e8f06b3cc11b3e Signed-off-by: Liron Kuch --- .../dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c | 2 +- drivers/misc/tspp.c | 50 ++++++++++++------- include/linux/tspp.h | 2 + 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c index 49f87bad9a6..632e864ee8c 100644 --- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c +++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c @@ -1433,8 +1433,8 @@ static int mpq_tspp_dmx_remove_channel(struct dvb_demux_feed *feed) if (*channel_ref_count == 0) { /* channel is not used any more, release it */ tspp_unregister_notification(0, channel_id); - tspp_close_channel(0, channel_id); tspp_close_stream(0, channel_id); + tspp_close_channel(0, channel_id); atomic_set(data_cnt, 0); if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c index ef238718611..9a538174fe4 100644 --- a/drivers/misc/tspp.c +++ b/drivers/misc/tspp.c @@ -1319,10 +1319,12 @@ int tspp_open_stream(u32 dev, u32 channel_id, pr_err("tspp: error starting tsif0"); return -EBUSY; } - val = readl_relaxed(pdev->base + TSPP_CONTROL); - writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS, - pdev->base + TSPP_CONTROL); - wmb(); + if (pdev->tsif[0].ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS, + pdev->base + TSPP_CONTROL); + wmb(); + } break; case TSPP_SOURCE_TSIF1: if (tspp_config_gpios(pdev, channel->src, 1) != 0) { @@ -1334,10 +1336,12 @@ int tspp_open_stream(u32 dev, u32 channel_id, pr_err("tspp: error starting tsif1"); return -EBUSY; } - val = readl_relaxed(pdev->base + TSPP_CONTROL); - writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS, - pdev->base + TSPP_CONTROL); - wmb(); + if (pdev->tsif[1].ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS, + pdev->base + TSPP_CONTROL); + wmb(); + } break; case TSPP_SOURCE_MEM: break; @@ -1363,6 +1367,7 @@ EXPORT_SYMBOL(tspp_open_stream); int tspp_close_stream(u32 dev, u32 channel_id) { u32 val; + u32 prev_ref_count; struct tspp_device *pdev; struct tspp_channel *channel; @@ -1379,23 +1384,30 @@ int tspp_close_stream(u32 dev, u32 channel_id) switch (channel->src) { case TSPP_SOURCE_TSIF0: + prev_ref_count = pdev->tsif[0].ref_count; tspp_stop_tsif(&pdev->tsif[0]); if (tspp_config_gpios(pdev, channel->src, 0) != 0) pr_err("tspp: error disabling tsif0 GPIOs\n"); - val = readl_relaxed(pdev->base + TSPP_CONTROL); - writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS, - pdev->base + TSPP_CONTROL); - wmb(); + if (prev_ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS, + pdev->base + TSPP_CONTROL); + wmb(); + } break; case TSPP_SOURCE_TSIF1: + prev_ref_count = pdev->tsif[1].ref_count; tspp_stop_tsif(&pdev->tsif[1]); if (tspp_config_gpios(pdev, channel->src, 0) != 0) pr_err("tspp: error disabling tsif0 GPIOs\n"); - val = readl_relaxed(pdev->base + TSPP_CONTROL); - writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS, - pdev->base + TSPP_CONTROL); + if (prev_ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS, + pdev->base + TSPP_CONTROL); + wmb(); + } break; case TSPP_SOURCE_MEM: break; @@ -1595,9 +1607,6 @@ int tspp_close_channel(u32 dev, u32 channel_id) } channel->filter_count = 0; - /* stop the stream */ - tspp_close_stream(dev, channel->id); - /* disconnect the bam */ if (sps_disconnect(channel->pipe) != 0) pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id); @@ -2435,7 +2444,7 @@ static long tspp_ioctl(struct file *filp, channel = filp->private_data; dev = channel->pdev->pdev->id; - if (!param1) + if ((param0 != TSPP_IOCTL_CLOSE_STREAM) && !param1) return -EINVAL; switch (param0) { @@ -2502,6 +2511,9 @@ static long tspp_ioctl(struct file *filp, sizeof(struct tspp_buffer)) == 0) rc = tspp_set_buffer_size(channel, &b); break; + case TSPP_IOCTL_CLOSE_STREAM: + rc = tspp_close_stream(dev, channel->id); + break; default: pr_err("tspp: Unknown ioctl %i", param0); } diff --git a/include/linux/tspp.h b/include/linux/tspp.h index 551fbb090aa..c790c28dae7 100644 --- a/include/linux/tspp.h +++ b/include/linux/tspp.h @@ -88,5 +88,7 @@ struct tspp_buffer { _IOW(TSPP_IOCTL_BASE, 5, struct tspp_system_keys) #define TSPP_IOCTL_BUFFER_SIZE \ _IOW(TSPP_IOCTL_BASE, 6, struct tspp_buffer) +#define TSPP_IOCTL_CLOSE_STREAM \ + _IO(TSPP_IOCTL_BASE, 7) #endif /* _TSPP_H_ */ From 4257a94dd136b147c7590b363879d1a486fb2fcd Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Tue, 19 Feb 2013 09:02:37 -0800 Subject: [PATCH 2150/2357] msm_fb: display: add mutex to video_off It is possible that pipe_commit still be issued by frame work after suspend had been started. Therefore mutex lock within video_off is necessary to prevent race condition from happening between these two threads. Change-Id: I57f51744c1654d6def8664c492035631a5b7081e Signed-off-by: Kuogee Hsieh --- drivers/video/msm/mdp4_overlay_dsi_cmd.c | 15 +++++++++++++++ drivers/video/msm/mdp4_overlay_dsi_video.c | 14 ++++++++++++++ drivers/video/msm/mdp4_overlay_dtv.c | 14 ++++++++++++++ drivers/video/msm/mdp4_overlay_lcdc.c | 12 ++++++++++++ 4 files changed, 55 insertions(+) diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c index 38c7baf8baa..3c089bb19ac 100644 --- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c +++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c @@ -287,6 +287,12 @@ int mdp4_dsi_cmd_pipe_commit(int cndx, int wait) undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; + if (pipe == NULL) { + pr_err("%s: NO base pipe\n", __func__); + mutex_unlock(&vctrl->update_lock); + return 0; + } + mixer = pipe->mixer_num; mdp_update_pm(vctrl->mfd, vctrl->vsync_time); @@ -1023,6 +1029,8 @@ int mdp4_dsi_cmd_on(struct platform_device *pdev) mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); mfd->cont_splash_done = 1; + mutex_lock(&mfd->dma->ov_mutex); + vctrl = &vsync_ctrl_db[cndx]; vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; @@ -1035,6 +1043,8 @@ int mdp4_dsi_cmd_on(struct platform_device *pdev) atomic_set(&vctrl->suspend, 0); + mutex_unlock(&mfd->dma->ov_mutex); + pr_debug("%s-:\n", __func__); return ret; @@ -1056,10 +1066,13 @@ int mdp4_dsi_cmd_off(struct platform_device *pdev) mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + mutex_lock(&mfd->dma->ov_mutex); + vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; if (pipe == NULL) { pr_err("%s: NO base pipe\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); return ret; } @@ -1120,6 +1133,8 @@ int mdp4_dsi_cmd_off(struct platform_device *pdev) mdp4_dsi_cmd_pipe_clean(vp); } + mutex_unlock(&mfd->dma->ov_mutex); + pr_debug("%s-:\n", __func__); return ret; } diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c index c8102e20b27..c2edef20295 100644 --- a/drivers/video/msm/mdp4_overlay_dsi_video.c +++ b/drivers/video/msm/mdp4_overlay_dsi_video.c @@ -181,6 +181,12 @@ int mdp4_dsi_video_pipe_commit(int cndx, int wait) undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; + if (pipe == NULL) { + pr_err("%s: NO base pipe\n", __func__); + mutex_unlock(&vctrl->update_lock); + return 0; + } + mixer = pipe->mixer_num; mdp_update_pm(vctrl->mfd, vctrl->vsync_time); @@ -554,6 +560,8 @@ int mdp4_dsi_video_on(struct platform_device *pdev) if (mfd->key != MFD_KEY) return -EINVAL; + mutex_lock(&mfd->dma->ov_mutex); + vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; vctrl->blt_ctrl = pinfo->lcd.blt_ctrl; @@ -575,6 +583,7 @@ int mdp4_dsi_video_on(struct platform_device *pdev) pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); if (pipe == NULL) { printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); return -EBUSY; } pipe->pipe_used++; @@ -716,6 +725,7 @@ int mdp4_dsi_video_on(struct platform_device *pdev) mdp_histogram_ctrl_all(TRUE); mdp4_overlay_dsi_video_start(); + mutex_unlock(&mfd->dma->ov_mutex); return ret; } @@ -732,6 +742,8 @@ int mdp4_dsi_video_off(struct platform_device *pdev) int undx, need_wait = 0; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + mutex_lock(&mfd->dma->ov_mutex); vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; @@ -799,6 +811,8 @@ int mdp4_dsi_video_off(struct platform_device *pdev) mdp_clk_ctrl(0); mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mutex_unlock(&mfd->dma->ov_mutex); + return ret; } diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c index 0aec1471d27..d6358abfc95 100644 --- a/drivers/video/msm/mdp4_overlay_dtv.c +++ b/drivers/video/msm/mdp4_overlay_dtv.c @@ -198,6 +198,11 @@ int mdp4_dtv_pipe_commit(int cndx, int wait) undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; + if (pipe == NULL) { + pr_err("%s: NO base pipe\n", __func__); + mutex_unlock(&vctrl->update_lock); + return 0; + } mixer = pipe->mixer_num; mdp4_overlay_iommu_unmap_freelist(mixer); @@ -587,6 +592,8 @@ int mdp4_dtv_on(struct platform_device *pdev) if (mfd->key != MFD_KEY) return -EINVAL; + mutex_lock(&mfd->dma->ov_mutex); + vctrl->dev = mfd->fbi->dev; mdp_footswitch_ctrl(TRUE); @@ -600,6 +607,7 @@ int mdp4_dtv_on(struct platform_device *pdev) if (mdp4_overlay_dtv_set(mfd, NULL)) { pr_warn("%s: dtv_pipe is NULL, dtv_set failed\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); return -EINVAL; } } @@ -610,6 +618,8 @@ int mdp4_dtv_on(struct platform_device *pdev) atomic_set(&vctrl->suspend, 0); + mutex_unlock(&mfd->dma->ov_mutex); + pr_info("%s:\n", __func__); return ret; @@ -641,6 +651,8 @@ int mdp4_dtv_off(struct platform_device *pdev) mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + mutex_lock(&mfd->dma->ov_mutex); + vctrl = &vsync_ctrl_db[cndx]; mdp4_dtv_wait4vsync(cndx); @@ -690,6 +702,8 @@ int mdp4_dtv_off(struct platform_device *pdev) /* Mdp clock disable */ mdp_clk_ctrl(0); + mutex_unlock(&mfd->dma->ov_mutex); + pr_info("%s:\n", __func__); return ret; } diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c index 629e51e5d81..c55fbd26679 100644 --- a/drivers/video/msm/mdp4_overlay_lcdc.c +++ b/drivers/video/msm/mdp4_overlay_lcdc.c @@ -185,6 +185,11 @@ int mdp4_lcdc_pipe_commit(int cndx, int wait) undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; + if (pipe == NULL) { + pr_err("%s: NO base pipe\n", __func__); + mutex_unlock(&vctrl->update_lock); + return 0; + } mixer = pipe->mixer_num; mdp_update_pm(vctrl->mfd, vctrl->vsync_time); @@ -523,6 +528,8 @@ int mdp4_lcdc_on(struct platform_device *pdev) if (mfd->key != MFD_KEY) return -EINVAL; + mutex_lock(&mfd->dma->ov_mutex); + vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; @@ -686,6 +693,7 @@ int mdp4_lcdc_on(struct platform_device *pdev) mdp_histogram_ctrl_all(TRUE); mdp4_overlay_lcdc_start(); + mutex_unlock(&mfd->dma->ov_mutex); return ret; } @@ -715,6 +723,8 @@ int mdp4_lcdc_off(struct platform_device *pdev) int undx, need_wait = 0; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + mutex_lock(&mfd->dma->ov_mutex); vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; @@ -777,6 +787,8 @@ int mdp4_lcdc_off(struct platform_device *pdev) mdp_clk_ctrl(0); mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mutex_unlock(&mfd->dma->ov_mutex); + return ret; } From 12387de738ac779372699a6f2d11099ab8ea9754 Mon Sep 17 00:00:00 2001 From: Tianyi Gou Date: Mon, 25 Feb 2013 19:32:11 -0800 Subject: [PATCH 2151/2357] msm: acpuclock-8064: Lower max L2 speed to 1134MHz There are some testing showing that L2 at 1188MHz may cause some stability issue. Lower the max speed to 1134Mhz until the root cause is found. Change-Id: I327c33c72ea0327e269d7839fadfb25ac715408b Signed-off-by: Tianyi Gou --- arch/arm/mach-msm/acpuclock-8064.c | 353 ++++++++++++++--------------- 1 file changed, 176 insertions(+), 177 deletions(-) diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c index 359a156d831..0fe1793d5df 100644 --- a/arch/arm/mach-msm/acpuclock-8064.c +++ b/arch/arm/mach-msm/acpuclock-8064.c @@ -131,7 +131,6 @@ static struct l2_level l2_freq_tbl[] __initdata = { [12] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 5 }, [13] = { { 1080000, HFPLL, 1, 0x28 }, 1150000, 1150000, 5 }, [14] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 5 }, - [15] = { { 1188000, HFPLL, 1, 0x2C }, 1150000, 1150000, 5 }, { } }; @@ -149,15 +148,15 @@ static struct acpu_level tbl_slow[] __initdata = { { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1100000 }, { 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1125000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1125000 }, - { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 }, - { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 }, - { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 }, - { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 }, + { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1175000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1175000 }, + { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1200000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1200000 }, + { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1225000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1225000 }, + { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1237500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1237500 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1250000 }, { 0, { 0 } } }; @@ -175,15 +174,15 @@ static struct acpu_level tbl_nom[] __initdata = { { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1050000 }, { 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1075000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1075000 }, - { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1125000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1125000 }, - { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1150000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1150000 }, - { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1175000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1175000 }, - { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1187500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1187500 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1200000 }, + { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1125000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1125000 }, + { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1150000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1150000 }, + { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1175000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1175000 }, + { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1187500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1187500 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1200000 }, { 0, { 0 } } }; @@ -201,15 +200,15 @@ static struct acpu_level tbl_fast[] __initdata = { { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 }, { 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1025000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1025000 }, - { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1075000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 }, - { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1100000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1100000 }, - { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1125000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 }, - { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1137500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1137500 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1150000 }, + { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1075000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 }, + { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1100000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1100000 }, + { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1125000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 }, + { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1137500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1137500 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1150000 }, { 0, { 0 } } }; @@ -227,15 +226,15 @@ static struct acpu_level tbl_faster[] __initdata = { { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 975000 }, { 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1000000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1000000 }, - { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1050000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1050000 }, - { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1075000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1075000 }, - { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1100000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1100000 }, - { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1112500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1125000 }, + { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1050000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1050000 }, + { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1075000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1075000 }, + { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1100000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1100000 }, + { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1112500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1125000 }, { 0, { 0 } } }; @@ -247,11 +246,11 @@ static struct acpu_level tbl_PVS0_1512MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 1000000 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1025000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1037500 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1087500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1162500 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1087500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1150000 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1162500 }, { 0, { 0 } } }; @@ -263,11 +262,11 @@ static struct acpu_level tbl_PVS1_1512MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 975000 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1012500 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1037500 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1087500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1125000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1037500 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1050000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1087500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1125000 }, { 0, { 0 } } }; @@ -279,11 +278,11 @@ static struct acpu_level tbl_PVS2_1512MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1087500 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1087500 }, { 0, { 0 } } }; @@ -295,11 +294,11 @@ static struct acpu_level tbl_PVS3_1512MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 975000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 987500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1050000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 975000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 987500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1037500 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1050000 }, { 0, { 0 } } }; @@ -311,11 +310,11 @@ static struct acpu_level tbl_PVS4_1512MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 950000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 962500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 975000 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1012500 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 950000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 962500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 975000 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1012500 }, { 0, { 0 } } }; @@ -327,11 +326,11 @@ static struct acpu_level tbl_PVS5_1512MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 987500 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1000000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 987500 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1000000 }, { 0, { 0 } } }; @@ -343,11 +342,11 @@ static struct acpu_level tbl_PVS6_1512MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 975000 }, - { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 987500 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 975000 }, + { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 987500 }, { 0, { 0 } } }; @@ -359,13 +358,13 @@ static struct acpu_level tbl_PVS0_1700MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 1000000 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1025000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1037500 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1087500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1175000 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1225000 }, - { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1250000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1087500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1150000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1175000 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1225000 }, + { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1250000 }, { 0, { 0 } } }; @@ -377,13 +376,13 @@ static struct acpu_level tbl_PVS1_1700MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 975000 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1012500 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1037500 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1087500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1150000 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1187500 }, - { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1200000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1037500 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1050000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1087500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1150000 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1187500 }, + { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1200000 }, { 0, { 0 } } }; @@ -395,13 +394,13 @@ static struct acpu_level tbl_PVS2_1700MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 }, - { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1162500 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1100000 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1137500 }, + { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1162500 }, { 0, { 0 } } }; @@ -413,13 +412,13 @@ static struct acpu_level tbl_PVS3_1700MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 975000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 987500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1062500 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1100000 }, - { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1125000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 975000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 987500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1037500 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1062500 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1100000 }, + { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1125000 }, { 0, { 0 } } }; @@ -431,13 +430,13 @@ static struct acpu_level tbl_PVS4_1700MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 950000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 962500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 975000 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 }, - { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1100000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 950000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 962500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 975000 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1037500 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1075000 }, + { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1100000 }, { 0, { 0 } } }; @@ -449,13 +448,13 @@ static struct acpu_level tbl_PVS5_1700MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 987500 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 }, - { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1075000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 987500 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1012500 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1050000 }, + { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1075000 }, { 0, { 0 } } }; @@ -467,13 +466,13 @@ static struct acpu_level tbl_PVS6_1700MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 975000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1000000 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 }, - { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1050000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 975000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1000000 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1025000 }, + { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1050000 }, { 0, { 0 } } }; @@ -485,14 +484,14 @@ static struct acpu_level tbl_PVS0_2000MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 962500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 975000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1000000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1025000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1037500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1062500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1100000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1125000 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1175000 }, - { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1225000 }, - { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1287500 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1025000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1037500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1062500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1100000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1125000 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1175000 }, + { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1225000 }, + { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1287500 }, { 0, { 0 } } }; @@ -504,14 +503,14 @@ static struct acpu_level tbl_PVS1_2000MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 }, - { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1187500 }, - { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1250000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1100000 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1137500 }, + { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1187500 }, + { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1250000 }, { 0, { 0 } } }; @@ -523,14 +522,14 @@ static struct acpu_level tbl_PVS2_2000MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 912500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 975000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 987500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1012500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1050000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1075000 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1112500 }, - { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1162500 }, - { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1212500 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 975000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 987500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1012500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1050000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1075000 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1112500 }, + { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1162500 }, + { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1212500 }, { 0, { 0 } } }; @@ -542,14 +541,14 @@ static struct acpu_level tbl_PVS3_2000MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 912500 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 937500 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 962500 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 975000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1025000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1050000 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1087500 }, - { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1137500 }, - { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1175000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 962500 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 975000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1025000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1050000 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1087500 }, + { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1137500 }, + { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1175000 }, { 0, { 0 } } }; @@ -561,14 +560,14 @@ static struct acpu_level tbl_PVS4_2000MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 950000 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 962500 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 975000 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 }, - { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1112500 }, - { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1150000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 950000 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 962500 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 975000 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1037500 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1075000 }, + { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1112500 }, + { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1150000 }, { 0, { 0 } } }; @@ -580,14 +579,14 @@ static struct acpu_level tbl_PVS5_2000MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 987500 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 }, - { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1087500 }, - { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1125000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 987500 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1012500 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1050000 }, + { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1087500 }, + { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1125000 }, { 0, { 0 } } }; @@ -599,14 +598,14 @@ static struct acpu_level tbl_PVS6_2000MHz[] __initdata = { { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 }, { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 }, { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 }, - { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 }, - { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 }, - { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 }, - { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 975000 }, - { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1000000 }, - { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 }, - { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1062500 }, - { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1100000 }, + { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 }, + { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 }, + { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 }, + { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 975000 }, + { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1000000 }, + { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1025000 }, + { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1062500 }, + { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1100000 }, { 0, { 0 } } }; From 2ffb3eb14f208a7aa41ee498247c28bc1b267a7a Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Tue, 26 Feb 2013 10:31:47 +0530 Subject: [PATCH 2152/2357] msm: camera: Update debug data in vfe driver there is a mismatch between actual VFE command and the debug data.Update debug data in vfe driver to fix this issue. Change-Id: I3727cd8e5c7095d462b5532cd45f118ad7a6504c CRs-Fixed: 452004 Signed-off-by: Suresh Vankadara --- drivers/media/video/msm/vfe/msm_vfe32.c | 29 ++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c index a8db6dd26ec..581a74b41bb 100644 --- a/drivers/media/video/msm/vfe/msm_vfe32.c +++ b/drivers/media/video/msm/vfe/msm_vfe32.c @@ -232,12 +232,12 @@ static struct vfe32_cmd_type vfe32_cmd[] = { {VFE_CMD_STATS_UNREGBUF}, {VFE_CMD_STATS_BG_START, V32_STATS_BG_LEN, V32_STATS_BG_OFF}, {VFE_CMD_STATS_BG_STOP}, - {VFE_CMD_STATS_BF_START, V32_STATS_BF_LEN, V32_STATS_BF_OFF}, -/*145*/ {VFE_CMD_STATS_BF_STOP}, +/*145*/ {VFE_CMD_STATS_BF_START, V32_STATS_BF_LEN, V32_STATS_BF_OFF}, + {VFE_CMD_STATS_BF_STOP}, {VFE_CMD_STATS_BHIST_START, V32_STATS_BHIST_LEN, V32_STATS_BHIST_OFF}, {VFE_CMD_STATS_BHIST_STOP}, -/*148*/ {VFE_CMD_SELECT_RDI}, +/*149*/ {VFE_CMD_SELECT_RDI}, }; uint32_t vfe32_AXI_WM_CFG[] = { @@ -364,7 +364,7 @@ static const char * const vfe32_general_cmd[] = { "DEMOSAICV3_DBCC_UPDATE", /* 110 */ "DEMOSAICV3_DBPC_UPDATE", "XBAR_CFG", - "EZTUNE_CFG", + "MODULE_CFG", "V32_ZSL", "LINEARIZATION_UPDATE", /*115*/ "DEMOSAICV3_ABF_UPDATE", @@ -380,16 +380,16 @@ static const char * const vfe32_general_cmd[] = { "GET_RGB_G_TABLE", "GET_LA_TABLE", "DEMOSAICV3_UPDATE", - "DUMMY_11", - "DUMMY_12", /*130*/ - "DUMMY_13", - "DUMMY_14", - "DUMMY_15", - "DUMMY_16", - "DUMMY_17", /*135*/ - "DUMMY_18", - "DUMMY_19", - "DUMMY_20", + "VFE_CMD_ACTIVE_REGION_CFG", + "VFE_CMD_COLOR_PROCESSING_CONFIG", /*130*/ + "VFE_CMD_STATS_WB_AEC_CONFIG", + "VFE_CMD_STATS_WB_AEC_UPDATE", + "VFE_CMD_Y_GAMMA_CONFIG", + "VFE_CMD_SCALE_OUTPUT1_CONFIG", + "VFE_CMD_SCALE_OUTPUT2_CONFIG", /*135*/ + "VFE_CMD_CAPTURE_RAW", + "VFE_CMD_STOP_LIVESHOT", + "VFE_CMD_RECONFIG_VFE", "STATS_REQBUF", "STATS_ENQUEUEBUF", /*140*/ "STATS_FLUSH_BUFQ", @@ -400,7 +400,6 @@ static const char * const vfe32_general_cmd[] = { "STATS_BF_STOP", "STATS_BHIST_START", "STATS_BHIST_STOP", - "RESET_2", "RDI_SEL" /*150*/ }; From fdd415b77837edfc0c11eab4b64205c28c896ad0 Mon Sep 17 00:00:00 2001 From: Amy Maloche Date: Mon, 24 Sep 2012 14:06:22 -0700 Subject: [PATCH 2153/2357] board: 8960-pmic: Swap mapping of camera snapshot and focus keys Functionality is swapped on 8960 devices. Change-Id: I2a458c40b60be583dee982bb12927a9b018fb94f Signed-off-by: Amy Maloche --- arch/arm/mach-msm/board-8960-pmic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c index 01948aef390..f011629b380 100644 --- a/arch/arm/mach-msm/board-8960-pmic.c +++ b/arch/arm/mach-msm/board-8960-pmic.c @@ -249,8 +249,8 @@ static struct pm8xxx_keypad_platform_data keypad_data_liquid = { static const unsigned int keymap[] = { KEY(0, 0, KEY_VOLUMEUP), KEY(0, 1, KEY_VOLUMEDOWN), - KEY(0, 2, KEY_CAMERA_SNAPSHOT), - KEY(0, 3, KEY_CAMERA_FOCUS), + KEY(0, 2, KEY_CAMERA_FOCUS), + KEY(0, 3, KEY_CAMERA_SNAPSHOT), }; static struct matrix_keymap_data keymap_data = { From de8cbf9610ce298ce128f2b73b5b0a41c27a8f1f Mon Sep 17 00:00:00 2001 From: Liron Kuch Date: Thu, 21 Feb 2013 14:25:57 +0200 Subject: [PATCH 2154/2357] tspp: Fix incorrect usage of clk_disable to support PM The TSPP driver uses clk_prepare_enable() API to use the appropriate clocks. When the device is not used, clk_disable_unprepare() should be called. However, clk_disable() was used by mistake instead. Change-Id: I70f8e9e8a7d2aef3a781be160b72096252e964de Signed-off-by: Liron Kuch --- drivers/misc/tspp.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c index ef238718611..75b10208e10 100644 --- a/drivers/misc/tspp.c +++ b/drivers/misc/tspp.c @@ -763,6 +763,11 @@ static int tspp_config_gpios(struct tspp_device *device, /*** Clock functions ***/ static int tspp_clock_start(struct tspp_device *device) { + if (device == NULL) { + pr_err("tspp: Can't start clocks, invalid device\n"); + return -EINVAL; + } + if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) { pr_err("tspp: Can't start pclk"); return -EBUSY; @@ -780,11 +785,16 @@ static int tspp_clock_start(struct tspp_device *device) static void tspp_clock_stop(struct tspp_device *device) { + if (device == NULL) { + pr_err("tspp: Can't stop clocks, invalid device\n"); + return; + } + if (device->tsif_pclk) - clk_disable(device->tsif_pclk); + clk_disable_unprepare(device->tsif_pclk); if (device->tsif_ref_clk) - clk_disable(device->tsif_ref_clk); + clk_disable_unprepare(device->tsif_ref_clk); } /*** TSIF functions ***/ @@ -1446,7 +1456,10 @@ int tspp_open_channel(u32 dev, u32 channel_id) /* start the clocks if needed */ if (tspp_channels_in_use(pdev) == 0) { - tspp_clock_start(pdev); + rc = tspp_clock_start(pdev); + if (rc) + return rc; + wake_lock(&pdev->wake_lock); } @@ -1628,6 +1641,8 @@ int tspp_close_channel(u32 dev, u32 channel_id) tspp_clock_stop(pdev); } + pm_runtime_put(&pdev->pdev->dev); + return 0; } EXPORT_SYMBOL(tspp_close_channel); @@ -3009,6 +3024,7 @@ static int __devexit msm_tspp_remove(struct platform_device *pdev) { struct tspp_channel *channel; u32 i; + int rc; struct tspp_device *device = platform_get_drvdata(pdev); @@ -3021,9 +3037,11 @@ static int __devexit msm_tspp_remove(struct platform_device *pdev) } /* de-registering BAM device requires clocks */ - tspp_clock_start(device); - sps_deregister_bam_device(device->bam_handle); - tspp_clock_stop(device); + rc = tspp_clock_start(device); + if (rc == 0) { + sps_deregister_bam_device(device->bam_handle); + tspp_clock_stop(device); + } for (i = 0; i < TSPP_TSIF_INSTANCES; i++) { tsif_debugfs_exit(&device->tsif[i]); @@ -3046,7 +3064,7 @@ static int __devexit msm_tspp_remove(struct platform_device *pdev) clk_put(device->tsif_pclk); pm_runtime_disable(&pdev->dev); - pm_runtime_put(&pdev->dev); + kfree(device); return 0; From ef3e9fa6cce8f76670c6990b693c8c3063014250 Mon Sep 17 00:00:00 2001 From: Aviral Gupta Date: Tue, 16 Oct 2012 14:19:05 +0530 Subject: [PATCH 2155/2357] ASoC: msm: Mixer control to update the sample rate of HDMI interface Updating the sample rate for the compressed stream playback of the HDMI interface through the mixer control. Change-Id: Ib7b01f490f5e209512433a82faf96af0a3a810bd Signed-off-by: Aviral Gupta --- sound/soc/msm/mpq8064.c | 27 ++++++++++++++++++++++++--- sound/soc/msm/msm-dai-q6-hdmi.c | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c index 0f7203f523b..0dcb958bae6 100644 --- a/sound/soc/msm/mpq8064.c +++ b/sound/soc/msm/mpq8064.c @@ -134,7 +134,7 @@ static int msm_ext_top_spk_pamp; static int msm_slim_0_rx_ch = 1; static int msm_slim_0_tx_ch = 1; static int msm_hdmi_rx_ch = 8; - +static int hdmi_rate_variable; static struct clk *codec_clk; static int clk_users; @@ -517,6 +517,7 @@ static const char *slim0_rx_ch_text[] = {"One", "Two"}; static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"}; static const char * const hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; +static const char * const hdmi_rate[] = {"Default", "Variable"}; static const struct soc_enum msm_enum[] = { @@ -524,6 +525,7 @@ static const struct soc_enum msm_enum[] = { SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text), SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text), SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text), + SOC_ENUM_SINGLE_EXT(2, hdmi_rate), }; @@ -585,6 +587,21 @@ static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol, } +static int msm_hdmi_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + hdmi_rate_variable = ucontrol->value.integer.value[0]; + pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable); + return 0; +} + +static int msm_hdmi_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = hdmi_rate_variable; + return 0; +} + static const struct snd_kcontrol_new tabla_msm_controls[] = { SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk, msm_set_spk), @@ -594,7 +611,9 @@ static const struct snd_kcontrol_new tabla_msm_controls[] = { msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put), SOC_ENUM_EXT("HDMI_RX Channels", msm_enum[3], msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put), - + SOC_ENUM_EXT("HDMI RX Rate", msm_enum[4], + msm_hdmi_rate_get, + msm_hdmi_rate_put), }; static void *def_tabla_mbhc_cal(void) @@ -850,7 +869,9 @@ static int msm_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, pr_debug("%s channels->min %u channels->max %u ()\n", __func__, channels->min, channels->max); - rate->min = rate->max = 48000; + /*Configure the sample rate as 48000 KHz for the LPCM playback*/ + if (!hdmi_rate_variable) + rate->min = rate->max = 48000; channels->min = channels->max = msm_hdmi_rx_ch; return 0; diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c index ab5265e2198..99290a19a58 100644 --- a/sound/soc/msm/msm-dai-q6-hdmi.c +++ b/sound/soc/msm/msm-dai-q6-hdmi.c @@ -91,11 +91,25 @@ static int msm_dai_q6_hdmi_hw_params(struct snd_pcm_substream *substream, u32 channel_allocation = 0; u32 level_shift = 0; /* 0dB */ bool down_mix = FALSE; + int sample_rate = 48000; dai_data->channels = params_channels(params); dai_data->rate = params_rate(params); dai_data->port_config.hdmi_multi_ch.reserved = 0; + switch (dai_data->rate) { + case 48000: + sample_rate = HDMI_SAMPLE_RATE_48KHZ; + break; + case 44100: + sample_rate = HDMI_SAMPLE_RATE_44_1KHZ; + break; + case 32000: + sample_rate = HDMI_SAMPLE_RATE_32KHZ; + break; + } + hdmi_msm_audio_sample_rate_reset(sample_rate); + switch (dai_data->channels) { case 2: channel_allocation = 0; From 798299147ba7eef47f0cb85ff0e9c61f61b2a1e8 Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Wed, 27 Feb 2013 15:41:49 -0800 Subject: [PATCH 2156/2357] msm_fb: display: fix fence fd list be put twice msm_fb_wait_for_fence() will put fence fd list if sync_fence_wait() failed. After that same fd list wil be put one more time. This cause a fd put twice and cause system crash at the time fd was closed. Change-Id: If6a358e051c98841e34c23d81098243003ef0836 Signed-off-by: Kuogee Hsieh --- drivers/video/msm/msm_fb.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index 04304a295af..e45b02a5b46 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -3637,7 +3637,7 @@ static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd, static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd, struct mdp_buf_sync *buf_sync) { - int i, fence_cnt = 0, ret = 0; + int i, ret = 0; u32 threshold; int acq_fen_fd[MDP_MAX_FENCE_FD]; struct sync_fence *fence; @@ -3667,10 +3667,9 @@ static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd, } mfd->acq_fen[i] = fence; } - fence_cnt = i; + mfd->acq_fen_cnt = i; if (ret) goto buf_sync_err_1; - mfd->acq_fen_cnt = fence_cnt; if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT) { msm_fb_wait_for_fence(mfd); } @@ -3719,7 +3718,7 @@ static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd, mfd->cur_rel_fence = NULL; mfd->cur_rel_fen_fd = 0; buf_sync_err_1: - for (i = 0; i < fence_cnt; i++) + for (i = 0; i < mfd->acq_fen_cnt; i++) sync_fence_put(mfd->acq_fen[i]); mfd->acq_fen_cnt = 0; mutex_unlock(&mfd->sync_mutex); From 6e0f798c395c7e71a8392124f0663a5751802158 Mon Sep 17 00:00:00 2001 From: Amal Paul Date: Thu, 21 Feb 2013 19:36:35 -0800 Subject: [PATCH 2157/2357] ASoC: msm: qdsp6: Add support to configure ISO and ARIB coefficients Add support for configuring ISO or ARIB stereo mixing coefficients. This change introduces a function with whichi, AAC multi-channel driver can configure ISO or ARIB coefficients according to configuration done by the client. Change-Id: I72b74033532a276fa3bc1d305a04720ff6767409 Signed-off-by: Amal Paul --- include/sound/apr_audio.h | 13 ++++++++++++- include/sound/q6asm-v2.h | 4 +++- include/sound/q6asm.h | 2 ++ sound/soc/msm/qdsp6/q6asm.c | 33 +++++++++++++++++++++++++++++++++ sound/soc/msm/qdsp6v2/q6asm.c | 9 ++++++++- 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h index 000eac9332e..51bb21648db 100644 --- a/include/sound/apr_audio.h +++ b/include/sound/apr_audio.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1278,6 +1278,17 @@ struct asm_stream_cmd_encdec_dualmono { struct asm_dual_mono channel_map; } __packed; +#define ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG 0x00010DD8 + +/* Structure for AAC decoder stereo coefficient setting. */ + +struct asm_aac_stereo_mix_coeff_selection_param { + struct apr_hdr hdr; + u32 param_id; + u32 param_size; + u32 aac_stereo_mix_coeff_flag; +} __packed; + #define ASM_ENCDEC_DEC_CHAN_MAP 0x00010D82 struct asm_stream_cmd_encdec_channelmap { struct apr_hdr hdr; diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index cf0c4d43b07..f547dcc68f2 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -242,6 +242,8 @@ int q6asm_enable_sbrps(struct audio_client *ac, int q6asm_cfg_dual_mono_aac(struct audio_client *ac, uint16_t sce_left, uint16_t sce_right); +int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff); + int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf, uint16_t min_rate, uint16_t max_rate, uint16_t reduced_rate_level, uint16_t rate_modulation_cmd); diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h index 579f5e188e9..ddbce4c5e50 100644 --- a/include/sound/q6asm.h +++ b/include/sound/q6asm.h @@ -262,6 +262,8 @@ int q6asm_enable_sbrps(struct audio_client *ac, int q6asm_cfg_dual_mono_aac(struct audio_client *ac, uint16_t sce_left, uint16_t sce_right); +int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff); + int q6asm_set_encdec_chan_map(struct audio_client *ac, uint32_t num_channels); diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c index a0530632fc3..1455dfd7424 100644 --- a/sound/soc/msm/qdsp6/q6asm.c +++ b/sound/soc/msm/qdsp6/q6asm.c @@ -2045,6 +2045,39 @@ int q6asm_cfg_dual_mono_aac(struct audio_client *ac, return -EINVAL; } +int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff) +{ + struct asm_aac_stereo_mix_coeff_selection_param aac_mix_coeff; + int rc = 0; + q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE); + aac_mix_coeff.hdr.opcode = + ASM_STREAM_CMD_SET_ENCDEC_PARAM; + aac_mix_coeff.param_id = + ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG; + aac_mix_coeff.param_size = + sizeof(struct asm_aac_stereo_mix_coeff_selection_param); + aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff; + pr_debug("%s, mix_coeff = %u", __func__, mix_coeff); + rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff); + if (rc < 0) { + pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n", + __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, + ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG); + rc = -EINVAL; + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) == 0), 5*HZ); + if (!rc) { + pr_err("%s:timeout opcode[0x%x]\n", __func__, + aac_mix_coeff.hdr.opcode); + goto fail_cmd; + } + return 0; +fail_cmd: + return -EINVAL; +} + int q6asm_set_encdec_chan_map(struct audio_client *ac, uint32_t num_channels) { diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 6d7649063ed..af615c5a630 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -1887,6 +1887,13 @@ int q6asm_cfg_dual_mono_aac(struct audio_client *ac, return -EINVAL; } +/* Support for selecting stereo mixing coefficients for B family not done */ +int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff) +{ + /* To Be Done */ + return 0; +} + int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf, uint16_t min_rate, uint16_t max_rate, uint16_t reduced_rate_level, uint16_t rate_modulation_cmd) From da995f211ace52fc7e0f5cbda1c97ac9065dd6ce Mon Sep 17 00:00:00 2001 From: Amal Paul Date: Tue, 19 Feb 2013 20:27:49 -0800 Subject: [PATCH 2158/2357] msm: audio: qdsp6v2: Add support to configure ISO and ARIB coefficients Add support for configuring ISO or ARIB stereo mixing coefficients. This change introduces an IOCTL through which the user space can configure ISO or ARIB coefficients. Change-Id: Id08c859ce8bc18d7d0e41ce1ecb6a08f0794e067 Signed-off-by: Amal Paul --- arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c | 21 ++++++++++++++++++++- include/linux/msm_audio_aac.h | 3 +++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c index 6e1bdc0653b..6ee35f4c80b 100644 --- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c +++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c @@ -2,7 +2,7 @@ * * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -182,6 +182,25 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; } + case AUDIO_SET_AAC_MIX_CONFIG: { + pr_debug("%s, AUDIO_SET_AAC_MIX_CONFIG", __func__); + if (copy_from_user(audio->codec_cfg, (void *)arg, + sizeof(unsigned long))) { + rc = -EFAULT; + break; + } else { + unsigned long *mix_coeff = + (unsigned long *)audio->codec_cfg; + pr_debug("%s, value of coeff = %lu", + __func__, *mix_coeff); + rc = q6asm_cfg_aac_sel_mix_coef(audio->ac, *mix_coeff); + if (rc < 0) + pr_err("%s asm aac_sel_mix_coef failed rc=%d\n", + __func__, rc); + break; + } + break; + } default: pr_debug("Calling utils ioctl\n"); rc = audio->codec_ioctl(file, cmd, arg); diff --git a/include/linux/msm_audio_aac.h b/include/linux/msm_audio_aac.h index 620e5abfc8d..e03c4f892b9 100644 --- a/include/linux/msm_audio_aac.h +++ b/include/linux/msm_audio_aac.h @@ -14,6 +14,9 @@ #define AUDIO_GET_AAC_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \ (AUDIO_MAX_COMMON_IOCTL_NUM+4), struct msm_audio_aac_enc_config) +#define AUDIO_SET_AAC_MIX_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+5), unsigned) + #define AUDIO_AAC_FORMAT_ADTS -1 #define AUDIO_AAC_FORMAT_RAW 0x0000 #define AUDIO_AAC_FORMAT_PSUEDO_RAW 0x0001 From 8c8778cb99adcf82d36a156761478462110d1714 Mon Sep 17 00:00:00 2001 From: Sameer Thalappil Date: Wed, 20 Feb 2013 13:54:17 -0800 Subject: [PATCH 2159/2357] wcnss: Add support for nv bin download at coldboot NV bin is downloaded when wlan driver is loaded. This change adds support for NV bin download during coldboot of WCNSS and thus much before wlan driver is loaded. NV bin id not downloaded by platform driver during SSR. Change-Id: I070aae4270c54a3af4d4c0a24897e8c0c9cbfaa5 Acked-by: Rajesh Chauhan Signed-off-by: Sameer Thalappil --- drivers/net/wireless/wcnss/wcnss_riva.c | 33 +++- drivers/net/wireless/wcnss/wcnss_wlan.c | 212 +++++++++++++++++++++++- include/linux/wcnss_wlan.h | 1 + 3 files changed, 229 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c index 25d9b5d3937..c4cc8e9bc56 100644 --- a/drivers/net/wireless/wcnss/wcnss_riva.c +++ b/drivers/net/wireless/wcnss/wcnss_riva.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,6 +44,9 @@ static DEFINE_SEMAPHORE(riva_power_on_lock); #define RIVA_PMU_CFG_IRIS_XO_MODE 0x6 #define RIVA_PMU_CFG_IRIS_XO_MODE_48 (3 << 1) +#define RIVA_SPARE_OUT (msm_riva_base + 0x0b4) +#define NVBIN_DLND_BIT BIT(25) + #define VREG_NULL_CONFIG 0x0000 #define VREG_GET_REGULATOR_MASK 0x0001 #define VREG_SET_VOLTAGE_MASK 0x0002 @@ -96,6 +99,16 @@ static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on) goto fail; } + /* power on thru SSR should not set NV bit, + * during SSR, NV bin is downloaded by WLAN driver + */ + if (!wcnss_cold_boot_done()) { + pr_debug("wcnss: Indicate NV bin download\n"); + reg = readl_relaxed(RIVA_SPARE_OUT); + reg |= NVBIN_DLND_BIT; + writel_relaxed(reg, RIVA_SPARE_OUT); + } + /* Enable IRIS XO */ rc = clk_prepare_enable(cxo); if (rc) { @@ -135,15 +148,15 @@ static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on) wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id); if (IS_ERR(wlan_clock)) { rc = PTR_ERR(wlan_clock); - pr_err("Failed to get MSM_XO_TCXO_A2 voter" - " (%d)\n", rc); + pr_err("Failed to get MSM_XO_TCXO_A2 voter (%d)\n", + rc); goto fail; } rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON); if (rc < 0) { - pr_err("Configuring MSM_XO_MODE_ON failed" - " (%d)\n", rc); + pr_err("Configuring MSM_XO_MODE_ON failed (%d)\n", + rc); goto msm_xo_vote_fail; } } @@ -151,8 +164,8 @@ static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on) if (wlan_clock != NULL && !use_48mhz_xo) { rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF); if (rc < 0) - pr_err("Configuring MSM_XO_MODE_OFF failed" - " (%d)\n", rc); + pr_err("Configuring MSM_XO_MODE_OFF failed (%d)\n", + rc); } } @@ -359,7 +372,11 @@ int req_riva_power_on_lock(char *driver_name) node = kmalloc(sizeof(struct host_driver), GFP_KERNEL); if (!node) goto err; - strncpy(node->name, driver_name, sizeof(node->name)); + if (strlcpy(node->name, driver_name, sizeof(node->name)) + >= sizeof(node->name)) { + kfree(node); + goto err; + } mutex_lock(&list_lock); /* Lock when the first request is added */ diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index b30ed4567bf..3bc8d89a580 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -34,6 +35,7 @@ /* module params */ #define WCNSS_CONFIG_UNSPECIFIED (-1) + static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED; module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present"); @@ -54,13 +56,16 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_CTRL_MSG_START 0x01000000 #define WCNSS_VERSION_REQ (WCNSS_CTRL_MSG_START + 0) #define WCNSS_VERSION_RSP (WCNSS_CTRL_MSG_START + 1) +#define WCNSS_NVBIN_DNLD_REQ (WCNSS_CTRL_MSG_START + 2) +#define WCNSS_NVBIN_DNLD_RSP (WCNSS_CTRL_MSG_START + 3) + #define VALID_VERSION(version) \ ((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0) struct smd_msg_hdr { - unsigned int type; - unsigned int len; + unsigned int msg_type; + unsigned int msg_len; }; struct wcnss_version { @@ -71,6 +76,57 @@ struct wcnss_version { unsigned char revision; }; +#define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" + +/* + * On SMD channel 4K of maximum data can be transferred, including message + * header, so NV fragment size as next multiple of 1Kb is 3Kb. + */ +#define NV_FRAGMENT_SIZE 3072 + +/* Macro to find the total number fragments of the NV bin Image */ +#define TOTALFRAGMENTS(x) (((x % NV_FRAGMENT_SIZE) == 0) ? \ + (x / NV_FRAGMENT_SIZE) : ((x / NV_FRAGMENT_SIZE) + 1)) + +struct nvbin_dnld_req_params { + /* + * Fragment sequence number of the NV bin Image. NV Bin Image + * might not fit into one message due to size limitation of + * the SMD channel FIFO so entire NV blob is chopped into + * multiple fragments starting with seqeunce number 0. The + * last fragment is indicated by marking is_last_fragment field + * to 1. At receiving side, NV blobs would be concatenated + * together without any padding bytes in between. + */ + unsigned short frag_number; + + /* + * When set to 1 it indicates that no more fragments will + * be sent. Receiver shall send back response message after + * last fragment. + */ + unsigned short is_last_fragment; + + /* NV Image size (number of bytes) */ + unsigned int nvbin_buffer_size; + + /* + * Following the 'nvbin_buffer_size', there should be + * nvbin_buffer_size bytes of NV bin Image i.e. + * uint8[nvbin_buffer_size]. + */ +}; + +struct nvbin_dnld_req_msg { + /* + * Note: The length specified in nvbin_dnld_req_msg messages + * should be hdr.msg_len = sizeof(nvbin_dnld_req_msg) + + * nvbin_buffer_size. + */ + struct smd_msg_hdr hdr; + struct nvbin_dnld_req_params dnld_req_params; +}; + static struct { struct platform_device *pdev; void *pil; @@ -81,6 +137,7 @@ static struct { const struct dev_pm_ops *pm_ops; int triggered; int smd_channel_ready; + int cold_boot_done; smd_channel_t *smd_ch; unsigned char wcnss_version[WCNSS_VERSION_LEN]; unsigned int serial_number; @@ -89,6 +146,7 @@ static struct { struct wcnss_wlan_config wlan_config; struct delayed_work wcnss_work; struct work_struct wcnssctrl_version_work; + struct work_struct wcnssctrl_nvbin_dnld_work; struct work_struct wcnssctrl_rx_work; struct wake_lock wcnss_wake_lock; void __iomem *msm_wcnss_base; @@ -564,6 +622,16 @@ void wcnss_allow_suspend() } EXPORT_SYMBOL(wcnss_allow_suspend); +int wcnss_cold_boot_done(void) +{ + if (penv) + return penv->cold_boot_done; + else + return -ENODEV; +} +EXPORT_SYMBOL(wcnss_cold_boot_done); + + static int wcnss_smd_tx(void *data, int len) { int ret = 0; @@ -571,7 +639,7 @@ static int wcnss_smd_tx(void *data, int len) ret = smd_write_avail(penv->smd_ch); if (ret < len) { pr_err("wcnss: no space available for smd frame\n"); - ret = -ENOSPC; + return -ENOSPC; } ret = smd_write(penv->smd_ch, data, len); if (ret < len) { @@ -606,7 +674,7 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) phdr = (struct smd_msg_hdr *)buf; - switch (phdr->type) { + switch (phdr->msg_type) { case WCNSS_VERSION_RSP: pversion = (struct wcnss_version *)buf; @@ -619,10 +687,22 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) "%02x%02x%02x%02x", pversion->major, pversion->minor, pversion->version, pversion->revision); pr_info("wcnss: version %s\n", penv->wcnss_version); + /* + * schedule work to download nvbin to riva ccpu, + * only if riva major >= 1 and minor >= 4. + */ + if ((pversion->major >= 1) && (pversion->minor >= 4)) { + pr_info("wcnss: schedule dnld work for riva\n"); + schedule_work(&penv->wcnssctrl_nvbin_dnld_work); + } + break; + + case WCNSS_NVBIN_DNLD_RSP: + pr_info("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu\n"); break; default: - pr_err("wcnss: invalid message type %d\n", phdr->type); + pr_err("wcnss: invalid message type %d\n", phdr->msg_type); } return; } @@ -632,15 +712,126 @@ static void wcnss_send_version_req(struct work_struct *worker) struct smd_msg_hdr smd_msg; int ret = 0; - smd_msg.type = WCNSS_VERSION_REQ; - smd_msg.len = sizeof(smd_msg); - ret = wcnss_smd_tx(&smd_msg, smd_msg.len); + smd_msg.msg_type = WCNSS_VERSION_REQ; + smd_msg.msg_len = sizeof(smd_msg); + ret = wcnss_smd_tx(&smd_msg, smd_msg.msg_len); if (ret < 0) pr_err("wcnss: smd tx failed\n"); return; } +static void wcnss_nvbin_dnld_req(struct work_struct *worker) +{ + int ret = 0; + struct nvbin_dnld_req_msg *dnld_req_msg; + unsigned short total_fragments = 0; + unsigned short count = 0; + unsigned short retry_count = 0; + unsigned short cur_frag_size = 0; + unsigned char *outbuffer = NULL; + const void *nv_blob_addr = NULL; + unsigned int nv_blob_size = 0; + const struct firmware *nv = NULL; + struct device *dev = NULL; + + dev = wcnss_wlan_get_device(); + + ret = request_firmware(&nv, NVBIN_FILE, dev); + + if (ret || !nv || !nv->data || !nv->size) { + pr_err("wcnss: wcnss_nvbin_dnld_req: request_firmware failed for %s\n", + NVBIN_FILE); + return; + } + + /* + * First 4 bytes in nv blob is validity bitmap. + * We cannot validate nv, so skip those 4 bytes. + */ + nv_blob_addr = nv->data + 4; + nv_blob_size = nv->size - 4; + + total_fragments = TOTALFRAGMENTS(nv_blob_size); + + pr_info("wcnss: NV bin size: %d, total_fragments: %d\n", + nv_blob_size, total_fragments); + + /* get buffer for nv bin dnld req message */ + outbuffer = kmalloc((sizeof(struct nvbin_dnld_req_msg) + + NV_FRAGMENT_SIZE), GFP_KERNEL); + + if (NULL == outbuffer) { + pr_err("wcnss: wcnss_nvbin_dnld_req: failed to get buffer\n"); + goto err_free_nv; + } + + dnld_req_msg = (struct nvbin_dnld_req_msg *)outbuffer; + + dnld_req_msg->hdr.msg_type = WCNSS_NVBIN_DNLD_REQ; + + for (count = 0; count < total_fragments; count++) { + dnld_req_msg->dnld_req_params.frag_number = count; + + if (count == (total_fragments - 1)) { + /* last fragment, take care of boundry condition */ + cur_frag_size = nv_blob_size % NV_FRAGMENT_SIZE; + if (!cur_frag_size) + cur_frag_size = NV_FRAGMENT_SIZE; + + dnld_req_msg->dnld_req_params.is_last_fragment = 1; + } else { + cur_frag_size = NV_FRAGMENT_SIZE; + dnld_req_msg->dnld_req_params.is_last_fragment = 0; + } + + dnld_req_msg->dnld_req_params.nvbin_buffer_size = + cur_frag_size; + + dnld_req_msg->hdr.msg_len = + sizeof(struct nvbin_dnld_req_msg) + cur_frag_size; + + /* copy NV fragment */ + memcpy((outbuffer + sizeof(struct nvbin_dnld_req_msg)), + (nv_blob_addr + count * NV_FRAGMENT_SIZE), + cur_frag_size); + + ret = wcnss_smd_tx(outbuffer, dnld_req_msg->hdr.msg_len); + + retry_count = 0; + while ((ret == -ENOSPC) && (retry_count <= 3)) { + pr_debug("wcnss: wcnss_nvbin_dnld_req: smd tx failed, ENOSPC\n"); + pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n", + count, dnld_req_msg->hdr.msg_len, + total_fragments, retry_count); + + /* wait and try again */ + msleep(20); + retry_count++; + ret = wcnss_smd_tx(outbuffer, + dnld_req_msg->hdr.msg_len); + } + + if (ret < 0) { + pr_err("wcnss: wcnss_nvbin_dnld_req: smd tx failed\n"); + pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n", + count, dnld_req_msg->hdr.msg_len, + total_fragments, retry_count); + goto err_dnld; + } + } + +err_dnld: + /* free buffer */ + kfree(outbuffer); + +err_free_nv: + /* release firmware */ + release_firmware(nv); + + return; +} + static int wcnss_trigger_config(struct platform_device *pdev) { @@ -711,6 +902,7 @@ wcnss_trigger_config(struct platform_device *pdev) INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler); INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req); + INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_req); wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss"); @@ -720,6 +912,8 @@ wcnss_trigger_config(struct platform_device *pdev) goto fail_wake; } + penv->cold_boot_done = 1; + return 0; fail_wake: diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 44ad73e4217..eaf7ed383dc 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -53,6 +53,7 @@ void wcnss_allow_suspend(void); void wcnss_prevent_suspend(void); void wcnss_ssr_boot_notify(void); void wcnss_reset_intr(void); +int wcnss_cold_boot_done(void); #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev) #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data)) From e28b135193b1eb8449c7115748483228ffc1ce66 Mon Sep 17 00:00:00 2001 From: Gilad Broner Date: Wed, 27 Feb 2013 11:51:15 +0200 Subject: [PATCH 2160/2357] media: dvb: Fix secure demux application load check To deduce whether secure demux is available, an attempt is made to load the secure demux appliction during module initialization. The loading process retrieves the application from filesystem. When kernel configuration is set so that the module is built-in as part of the kernel image, filesystem is not yet available and loading fails. This change moves the loading attempt from initialization to first usage of status query, which occurs after device is opened by user-space and filesystem is sure to be available. Change-Id: I22d24054196f6068bf28e2ba6f2a4da6a9340730 Signed-off-by: Gilad Broner --- .../media/dvb/mpq/demux/mpq_dmx_plugin_common.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c index de70792d5bc..75b70283c1a 100644 --- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c +++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c @@ -819,7 +819,7 @@ int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func) mpq_dmx_info.devices = NULL; mpq_dmx_info.ion_client = NULL; - mpq_sdmx_check_app_loaded(); + mpq_dmx_info.secure_demux_app_loaded = 0; /* * TODO: the following should be set based on the decoder: @@ -4547,6 +4547,16 @@ EXPORT_SYMBOL(mpq_dmx_write); int mpq_sdmx_is_loaded(void) { - return mpq_bypass_sdmx ? 0 : mpq_dmx_info.secure_demux_app_loaded; + static int sdmx_load_checked; + + if (mpq_bypass_sdmx) + return 0; + + if (!sdmx_load_checked) { + mpq_sdmx_check_app_loaded(); + sdmx_load_checked = 1; + } + + return mpq_dmx_info.secure_demux_app_loaded; } EXPORT_SYMBOL(mpq_sdmx_is_loaded); From 9d41b6ae75959b5c9480fc99b9aede641abff9cd Mon Sep 17 00:00:00 2001 From: Amy Maloche Date: Fri, 7 Dec 2012 18:40:04 -0800 Subject: [PATCH 2161/2357] misc: isa1200: add device tree support Add device tree (DT) support for isa1200. Extract device properties from DT and store it in platform data structure. Change-Id: I9ed9cc36cb07db00634b9e73a8052e62d313d484 Signed-off-by: Amy Maloche --- .../devicetree/bindings/misc/isa1200.txt | 65 +++++++ drivers/misc/isa1200.c | 165 +++++++++++++++++- 2 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/misc/isa1200.txt diff --git a/Documentation/devicetree/bindings/misc/isa1200.txt b/Documentation/devicetree/bindings/misc/isa1200.txt new file mode 100644 index 00000000000..b30782d157c --- /dev/null +++ b/Documentation/devicetree/bindings/misc/isa1200.txt @@ -0,0 +1,65 @@ +Imagis ISA1200 Haptics Vibrator + +Required properties: + - reg: slave address of bus + - compatible: should be "imagis,isa1200" + - label: name for vibrator directory + - imagis,hap-en-gpio: haptic enable gpio + - imagis,mode-ctrl: mode of the controller, 0 = POWER_DOWN_MODE, + 1 = PWM_INPUT_MODE, 2 = PWM_GEN_MODE, 3 = WAVE_GEN_MODE + - imagis,max-timeout: maximum timeout for vibration + - imagis,chip-en: chip enable + - vcc_i2c-supply: regulator supplying i2c bus + +Regulator described as a child of the main device: + - regulator-name: A string used as a descriptive name for regulator outputs, + should match vcc_i2c above + - regulator-min-microvolt: smallest voltage consumers may set + - regulator-max-microvolt: largest voltage consumers may set + - regulator-max-microamp: largest current consumers may set + +Optional properties: + - imagis,smart-en: automatically control haptic power based on pwm/clk signal + - imagis,is-erm: controlled by dc motor, use ERM driving method + - imagis,overdrive-high: overdrive high + - imagis,overdrive-en: enable overdrive + - imagis,pwm-freq: pwm frequency (hZ) + - imagis,pwm-ch-id: pwm channel id + - imagis,pwm-div: pwm division to be used for vibration + - imagis,need-pwm-clk: use "pwm_clk" + - imagis,hap-len-gpio: haptic ldo enable gpio + - imagis,etc-clk-en: use external clock + - xyz-supply: to be used if additional regulators are require beyond + "imagis,regulator" above + +Any additional regulators are described as child nodes of main device: + - regulator-name: A string used as a descriptive name for regulator outputs, + should match supply "xyz" + - regulator-min-microvolt: smallest voltage consumers may set + - regulator-max-microvolt: largest voltage consumers may set + - regulator-max-microamp: largest current consumers may set + +Example: + i2c@f9967000 { + isa1200@48 { + status = "okay"; + reg = <0x48>; + vcc_i2c-supply = <&pm8941_s3>; + compatible = "imagis,isa1200"; + label = "vibrator"; + imagis,chip-en; + imagis,smart-en; + imagis,need-pwm-clk; + imagis,ext-clk-en; + imagis,hap-en-gpio = <&msmgpio 86 0x00>; + imagis,max-timeout = <15000>; + imagis,pwm-div = <256>; + imagis,mode-ctrl = <2>; + imagis,regulator { + regulator-name = "vcc_i2c"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-max-microamp = <9360>; + }; + }; + }; diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c index 647799f15a3..1a7a0af3a23 100644 --- a/drivers/misc/isa1200.c +++ b/drivers/misc/isa1200.c @@ -23,6 +23,7 @@ #include #include #include "../staging/android/timed_output.h" +#include #define ISA1200_HCTRL0 0x30 #define ISA1200_HCTRL1 0x31 @@ -121,7 +122,7 @@ static void isa1200_vib_set(struct isa1200_chip *haptic, int enable) /* vote for clock */ if (haptic->pdata->need_pwm_clk && !haptic->clk_on) { - rc = clk_enable(haptic->pwm_clk); + rc = clk_prepare_enable(haptic->pwm_clk); if (rc < 0) { pr_err("%s: clk enable failed\n", __func__); @@ -406,10 +407,10 @@ static int isa1200_reg_setup(struct isa1200_chip *haptic, bool on) for (i = 0; i < num_reg; i++) { haptic->regs[i] = regulator_get(&haptic->client->dev, - reg_info[i].name); + reg_info[i].name); if (IS_ERR(haptic->regs[i])) { rc = PTR_ERR(haptic->regs[i]); - pr_err("%s:regulator get failed(%d)\n", __func__, rc); + pr_err("%s:regulator get failed(%d)\n", __func__, rc); goto put_regs; } @@ -438,6 +439,138 @@ static int isa1200_reg_setup(struct isa1200_chip *haptic, bool on) return rc; } +#ifdef CONFIG_OF +static int isa1200_parse_dt(struct device *dev, + struct isa1200_platform_data *pdata) +{ + struct device_node *temp, *np = dev->of_node; + struct isa1200_regulator *reg_info; + enum of_gpio_flags hap_en_flags = OF_GPIO_ACTIVE_LOW; + enum of_gpio_flags hap_len_flags = OF_GPIO_ACTIVE_LOW; + int rc = 0; + u32 temp_val; + const char *temp_string; + + rc = of_property_read_string(np, "label", &pdata->name); + if (rc) { + dev_err(dev, "Unable to read device name\n"); + return rc; + } + + pdata->chip_en = of_property_read_bool(np, "imagis,chip-en"); + pdata->ext_clk_en = of_property_read_bool(np, "imagis,ext-clk-en"); + pdata->is_erm = of_property_read_bool(np, "imagis,is-erm"); + pdata->overdrive_high = + of_property_read_bool(np, "imagis,overdrive-high"); + pdata->overdrive_en = of_property_read_bool(np, "imagis,overdrive-en"); + pdata->smart_en = of_property_read_bool(np, "imagis,smart-en"); + pdata->need_pwm_clk = of_property_read_bool(np, "imagis,need-pwm-clk"); + + pdata->hap_en_gpio = of_get_named_gpio_flags(np, + "imagis,hap-en-gpio", 0, &hap_en_flags); + pdata->hap_len_gpio = of_get_named_gpio_flags(np, + "imagis,hap-len-gpio", 0, &hap_len_flags); + + rc = of_property_read_u32(np, "imagis,max-timeout", + &pdata->max_timeout); + if (rc) { + dev_err(dev, "Unable to read max timeout\n"); + return rc; + } + + rc = of_property_read_u32(np, "imagis,pwm-div", &pdata->pwm_fd.pwm_div); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read pwm division\n"); + return rc; + } + + rc = of_property_read_u32(np, "imagis,pwm-freq", + &pdata->pwm_fd.pwm_freq); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read pwm frequency\n"); + return rc; + } + + rc = of_property_read_u32(np, "imagis,pwm-ch-id", &pdata->pwm_ch_id); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read pwm channel id\n"); + return rc; + } + + rc = of_property_read_u32(np, "imagis,mode-ctrl", &pdata->mode_ctrl); + if (rc) { + dev_err(dev, "Unable to read control mode\n"); + return rc; + } + + rc = of_property_read_u32(np, "imagis,duty", &pdata->duty); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read duty cycle\n"); + return rc; + } + + pdata->num_regulators = 0; + temp = NULL; + while ((temp = of_get_next_child(np, temp))) + pdata->num_regulators++; + + if (!pdata->num_regulators) + return 0; + + reg_info = devm_kzalloc(dev, pdata->num_regulators * + sizeof(struct isa1200_regulator), GFP_KERNEL); + if (!reg_info) + return -ENOMEM; + + pdata->regulator_info = reg_info; + + for_each_child_of_node(np, temp) { + rc = of_property_read_string(temp, + "regulator-name", &temp_string); + if (rc) { + dev_err(dev, "Unable to read regulator name\n"); + return rc; + } else + reg_info->name = temp_string; + + rc = of_property_read_u32(temp, "regulator-max-microvolt", + &temp_val); + if (rc) { + dev_err(dev, "Unable to read max uV\n"); + return rc; + } else + reg_info->max_uV = temp_val; + + rc = of_property_read_u32(temp, "regulator-min-microvolt", + &temp_val); + if (rc) { + dev_err(dev, "Unable to read min uV\n"); + return rc; + } else + reg_info->min_uV = temp_val; + + rc = of_property_read_u32(temp, "regulator-max-microamp", + &temp_val); + if (rc) { + dev_err(dev, "Unable to read load uA\n"); + return rc; + } else + reg_info->load_uA = temp_val; + + reg_info++; + } + + return 0; +} +#else +static int isa1200_parse_dt(struct device *dev, + struct isa1200_platform_data *pdata) +{ + return -ENODEV; +} +#endif + + static int __devinit isa1200_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -452,7 +585,22 @@ static int __devinit isa1200_probe(struct i2c_client *client, return -EIO; } - pdata = client->dev.platform_data; + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct isa1200_platform_data), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + ret = isa1200_parse_dt(&client->dev, pdata); + if (ret) { + dev_err(&client->dev, "Parsing DT failed(%d)", ret); + return ret; + } + } else + pdata = client->dev.platform_data; + if (!pdata) { dev_err(&client->dev, "%s: no platform data\n", __func__); return -EINVAL; @@ -714,10 +862,19 @@ static const struct i2c_device_id isa1200_id[] = { { }, }; MODULE_DEVICE_TABLE(i2c, isa1200_id); +#ifdef CONFIG_OF +static struct of_device_id isa1200_match_table[] = { + { .compatible = "imagis,isa1200",}, + { }, +}; +#else +#define isa1200_match_table NULL +#endif static struct i2c_driver isa1200_driver = { .driver = { .name = "isa1200", + .of_match_table = isa1200_match_table, }, .probe = isa1200_probe, .remove = __devexit_p(isa1200_remove), From 33f8150487904727cc8c491e3f1bdb2fba3d8860 Mon Sep 17 00:00:00 2001 From: Amy Maloche Date: Fri, 7 Dec 2012 18:40:04 -0800 Subject: [PATCH 2162/2357] misc: isa1200: properly disable clocks Since clk_prepare_enable is being used when enabling clocks, clk_disable_prepare should be used to disable them. CRs-fixed: 453579 Change-Id: Ic15c99e1fa82e45a3b9165af60c104a6bb736f92 Signed-off-by: Amy Maloche --- drivers/misc/isa1200.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c index 1a7a0af3a23..c6d08d126e2 100644 --- a/drivers/misc/isa1200.c +++ b/drivers/misc/isa1200.c @@ -3,7 +3,7 @@ * * Copyright (C) 2009 Samsung Electronics * Kyungmin Park - * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -164,7 +164,7 @@ static void isa1200_vib_set(struct isa1200_chip *haptic, int enable) /* de-vote clock */ if (haptic->pdata->need_pwm_clk && haptic->clk_on) { - clk_disable(haptic->pwm_clk); + clk_disable_unprepare(haptic->pwm_clk); haptic->clk_on = false; } /* check for board specific clk callback */ @@ -181,7 +181,7 @@ static void isa1200_vib_set(struct isa1200_chip *haptic, int enable) dis_clk: if (haptic->pdata->need_pwm_clk && haptic->clk_on) { - clk_disable(haptic->pwm_clk); + clk_disable_unprepare(haptic->pwm_clk); haptic->clk_on = false; } From 025cee7f8fef02af09b03c8e1cd9843cb32adf9b Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 30 Jan 2013 16:56:16 -0800 Subject: [PATCH 2163/2357] x86-32, mm: Rip out x86_32 NUMA remapping code commit f03574f2d5b2d6229dcdf2d322848065f72953c7 upstream. This code was an optimization for 32-bit NUMA systems. It has probably been the cause of a number of subtle bugs over the years, although the conditions to excite them would have been hard to trigger. Essentially, we remap part of the kernel linear mapping area, and then sometimes part of that area gets freed back in to the bootmem allocator. If those pages get used by kernel data structures (say mem_map[] or a dentry), there's no big deal. But, if anyone ever tried to use the linear mapping for these pages _and_ cared about their physical address, bad things happen. For instance, say you passed __GFP_ZERO to the page allocator and then happened to get handed one of these pages, it zero the remapped page, but it would make a pte to the _old_ page. There are probably a hundred other ways that it could screw with things. We don't need to hang on to performance optimizations for these old boxes any more. All my 32-bit NUMA systems are long dead and buried, and I probably had access to more than most people. This code is causing real things to break today: https://lkml.org/lkml/2013/1/9/376 I looked in to actually fixing this, but it requires surgery to way too much brittle code, as well as stuff like per_cpu_ptr_to_phys(). [ hpa: Cc: this for -stable, since it is a memory corruption issue. However, an alternative is to simply mark NUMA as depends BROKEN rather than EXPERIMENTAL in the X86_32 subclause... ] Link: http://lkml.kernel.org/r/20130131005616.1C79F411@kernel.stglabs.ibm.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/Kconfig | 4 - arch/x86/mm/numa.c | 3 - arch/x86/mm/numa_32.c | 161 ------------------------------------ arch/x86/mm/numa_internal.h | 6 -- 4 files changed, 174 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index c9866b0b77d..b1478f40723 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1243,10 +1243,6 @@ config HAVE_ARCH_BOOTMEM def_bool y depends on X86_32 && NUMA -config HAVE_ARCH_ALLOC_REMAP - def_bool y - depends on X86_32 && NUMA - config ARCH_HAVE_MEMORY_PRESENT def_bool y depends on X86_32 && DISCONTIGMEM diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 19d3fa08b11..dae8397e361 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -205,9 +205,6 @@ static void __init setup_node_data(int nid, u64 start, u64 end) if (end && (end - start) < NODE_MIN_SIZE) return; - /* initialize remap allocator before aligning to ZONE_ALIGN */ - init_alloc_remap(nid, start, end); - start = roundup(start, ZONE_ALIGN); printk(KERN_INFO "Initmem setup node %d %016Lx-%016Lx\n", diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 534255a36b6..73a6d7395bd 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -73,167 +73,6 @@ unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn, extern unsigned long highend_pfn, highstart_pfn; -#define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE) - -static void *node_remap_start_vaddr[MAX_NUMNODES]; -void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); - -/* - * Remap memory allocator - */ -static unsigned long node_remap_start_pfn[MAX_NUMNODES]; -static void *node_remap_end_vaddr[MAX_NUMNODES]; -static void *node_remap_alloc_vaddr[MAX_NUMNODES]; - -/** - * alloc_remap - Allocate remapped memory - * @nid: NUMA node to allocate memory from - * @size: The size of allocation - * - * Allocate @size bytes from the remap area of NUMA node @nid. The - * size of the remap area is predetermined by init_alloc_remap() and - * only the callers considered there should call this function. For - * more info, please read the comment on top of init_alloc_remap(). - * - * The caller must be ready to handle allocation failure from this - * function and fall back to regular memory allocator in such cases. - * - * CONTEXT: - * Single CPU early boot context. - * - * RETURNS: - * Pointer to the allocated memory on success, %NULL on failure. - */ -void *alloc_remap(int nid, unsigned long size) -{ - void *allocation = node_remap_alloc_vaddr[nid]; - - size = ALIGN(size, L1_CACHE_BYTES); - - if (!allocation || (allocation + size) > node_remap_end_vaddr[nid]) - return NULL; - - node_remap_alloc_vaddr[nid] += size; - memset(allocation, 0, size); - - return allocation; -} - -#ifdef CONFIG_HIBERNATION -/** - * resume_map_numa_kva - add KVA mapping to the temporary page tables created - * during resume from hibernation - * @pgd_base - temporary resume page directory - */ -void resume_map_numa_kva(pgd_t *pgd_base) -{ - int node; - - for_each_online_node(node) { - unsigned long start_va, start_pfn, nr_pages, pfn; - - start_va = (unsigned long)node_remap_start_vaddr[node]; - start_pfn = node_remap_start_pfn[node]; - nr_pages = (node_remap_end_vaddr[node] - - node_remap_start_vaddr[node]) >> PAGE_SHIFT; - - printk(KERN_DEBUG "%s: node %d\n", __func__, node); - - for (pfn = 0; pfn < nr_pages; pfn += PTRS_PER_PTE) { - unsigned long vaddr = start_va + (pfn << PAGE_SHIFT); - pgd_t *pgd = pgd_base + pgd_index(vaddr); - pud_t *pud = pud_offset(pgd, vaddr); - pmd_t *pmd = pmd_offset(pud, vaddr); - - set_pmd(pmd, pfn_pmd(start_pfn + pfn, - PAGE_KERNEL_LARGE_EXEC)); - - printk(KERN_DEBUG "%s: %08lx -> pfn %08lx\n", - __func__, vaddr, start_pfn + pfn); - } - } -} -#endif - -/** - * init_alloc_remap - Initialize remap allocator for a NUMA node - * @nid: NUMA node to initizlie remap allocator for - * - * NUMA nodes may end up without any lowmem. As allocating pgdat and - * memmap on a different node with lowmem is inefficient, a special - * remap allocator is implemented which can be used by alloc_remap(). - * - * For each node, the amount of memory which will be necessary for - * pgdat and memmap is calculated and two memory areas of the size are - * allocated - one in the node and the other in lowmem; then, the area - * in the node is remapped to the lowmem area. - * - * As pgdat and memmap must be allocated in lowmem anyway, this - * doesn't waste lowmem address space; however, the actual lowmem - * which gets remapped over is wasted. The amount shouldn't be - * problematic on machines this feature will be used. - * - * Initialization failure isn't fatal. alloc_remap() is used - * opportunistically and the callers will fall back to other memory - * allocation mechanisms on failure. - */ -void __init init_alloc_remap(int nid, u64 start, u64 end) -{ - unsigned long start_pfn = start >> PAGE_SHIFT; - unsigned long end_pfn = end >> PAGE_SHIFT; - unsigned long size, pfn; - u64 node_pa, remap_pa; - void *remap_va; - - /* - * The acpi/srat node info can show hot-add memroy zones where - * memory could be added but not currently present. - */ - printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n", - nid, start_pfn, end_pfn); - - /* calculate the necessary space aligned to large page size */ - size = node_memmap_size_bytes(nid, start_pfn, end_pfn); - size += ALIGN(sizeof(pg_data_t), PAGE_SIZE); - size = ALIGN(size, LARGE_PAGE_BYTES); - - /* allocate node memory and the lowmem remap area */ - node_pa = memblock_find_in_range(start, end, size, LARGE_PAGE_BYTES); - if (!node_pa) { - pr_warning("remap_alloc: failed to allocate %lu bytes for node %d\n", - size, nid); - return; - } - memblock_reserve(node_pa, size); - - remap_pa = memblock_find_in_range(min_low_pfn << PAGE_SHIFT, - max_low_pfn << PAGE_SHIFT, - size, LARGE_PAGE_BYTES); - if (!remap_pa) { - pr_warning("remap_alloc: failed to allocate %lu bytes remap area for node %d\n", - size, nid); - memblock_free(node_pa, size); - return; - } - memblock_reserve(remap_pa, size); - remap_va = phys_to_virt(remap_pa); - - /* perform actual remap */ - for (pfn = 0; pfn < size >> PAGE_SHIFT; pfn += PTRS_PER_PTE) - set_pmd_pfn((unsigned long)remap_va + (pfn << PAGE_SHIFT), - (node_pa >> PAGE_SHIFT) + pfn, - PAGE_KERNEL_LARGE); - - /* initialize remap allocator parameters */ - node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT; - node_remap_start_vaddr[nid] = remap_va; - node_remap_end_vaddr[nid] = remap_va + size; - node_remap_alloc_vaddr[nid] = remap_va; - - printk(KERN_DEBUG "remap_alloc: node %d [%08llx-%08llx) -> [%p-%p)\n", - nid, node_pa, node_pa + size, remap_va, remap_va + size); -} - void __init initmem_init(void) { x86_numa_init(); diff --git a/arch/x86/mm/numa_internal.h b/arch/x86/mm/numa_internal.h index 7178c3afe05..ad86ec91e64 100644 --- a/arch/x86/mm/numa_internal.h +++ b/arch/x86/mm/numa_internal.h @@ -21,12 +21,6 @@ void __init numa_reset_distance(void); void __init x86_numa_init(void); -#ifdef CONFIG_X86_64 -static inline void init_alloc_remap(int nid, u64 start, u64 end) { } -#else -void __init init_alloc_remap(int nid, u64 start, u64 end); -#endif - #ifdef CONFIG_NUMA_EMU void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt); From 99867c9603b88d11ef8c7223b978d389fcb8e4c6 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 31 Jan 2013 13:53:10 -0800 Subject: [PATCH 2164/2357] x86-32, mm: Remove reference to resume_map_numa_kva() commit bb112aec5ee41427e9b9726e3d57b896709598ed upstream. Remove reference to removed function resume_map_numa_kva(). Signed-off-by: H. Peter Anvin Cc: Dave Hansen Link: http://lkml.kernel.org/r/20130131005616.1C79F411@kernel.stglabs.ibm.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mmzone_32.h | 6 ------ arch/x86/power/hibernate_32.c | 2 -- 2 files changed, 8 deletions(-) diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h index 55728e12147..5e0286f8081 100644 --- a/arch/x86/include/asm/mmzone_32.h +++ b/arch/x86/include/asm/mmzone_32.h @@ -14,12 +14,6 @@ extern struct pglist_data *node_data[]; #include -extern void resume_map_numa_kva(pgd_t *pgd); - -#else /* !CONFIG_NUMA */ - -static inline void resume_map_numa_kva(pgd_t *pgd) {} - #endif /* CONFIG_NUMA */ #ifdef CONFIG_DISCONTIGMEM diff --git a/arch/x86/power/hibernate_32.c b/arch/x86/power/hibernate_32.c index 74202c1910c..7d28c885d23 100644 --- a/arch/x86/power/hibernate_32.c +++ b/arch/x86/power/hibernate_32.c @@ -129,8 +129,6 @@ static int resume_physical_mapping_init(pgd_t *pgd_base) } } - resume_map_numa_kva(pgd_base); - return 0; } From 5c444ede11d516377ec6a3230d450441f46cfb4f Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 31 Jan 2013 14:00:48 -0800 Subject: [PATCH 2165/2357] x86-32, mm: Remove reference to alloc_remap() commit 07f4207a305c834f528d08428df4531744e25678 upstream. We have removed the remap allocator for x86-32, and x86-64 never had it (and doesn't need it). Remove residual reference to it. Reported-by: Yinghai Lu Signed-off-by: H. Peter Anvin Cc: Dave Hansen Link: http://lkml.kernel.org/r/CAE9FiQVn6_QZi3fNQ-JHYiR-7jeDJ5hT0SyT_%2BzVvfOj=PzF3w@mail.gmail.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/numa.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index dae8397e361..c1e83944abf 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -193,7 +193,6 @@ int __init numa_add_memblk(int nid, u64 start, u64 end) static void __init setup_node_data(int nid, u64 start, u64 end) { const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); - bool remapped = false; u64 nd_pa; void *nd; int tnid; @@ -211,28 +210,22 @@ static void __init setup_node_data(int nid, u64 start, u64 end) nid, start, end); /* - * Allocate node data. Try remap allocator first, node-local - * memory and then any node. Never allocate in DMA zone. + * Allocate node data. Try node-local memory and then any node. + * Never allocate in DMA zone. */ - nd = alloc_remap(nid, nd_size); - if (nd) { - nd_pa = __pa(nd); - remapped = true; - } else { - nd_pa = memblock_alloc_nid(nd_size, SMP_CACHE_BYTES, nid); - if (!nd_pa) { - pr_err("Cannot find %zu bytes in node %d\n", - nd_size, nid); - return; - } - nd = __va(nd_pa); + nd_pa = memblock_alloc_nid(nd_size, SMP_CACHE_BYTES, nid); + if (!nd_pa) { + pr_err("Cannot find %zu bytes in node %d\n", + nd_size, nid); + return; } + nd = __va(nd_pa); /* report and initialize */ - printk(KERN_INFO " NODE_DATA [%016Lx - %016Lx]%s\n", - nd_pa, nd_pa + nd_size - 1, remapped ? " (remapped)" : ""); + printk(KERN_INFO " NODE_DATA [mem %#010Lx-%#010Lx]\n", + nd_pa, nd_pa + nd_size - 1); tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT); - if (!remapped && tnid != nid) + if (tnid != nid) printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nid, tnid); node_data[nid] = nd; From 17c2f96bd1de5999900303b3eb923b8cdf6ee2ba Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 18 Feb 2013 09:58:02 -0800 Subject: [PATCH 2166/2357] mm: fix pageblock bitmap allocation commit 7c45512df987c5619db041b5c9b80d281e26d3db upstream. Commit c060f943d092 ("mm: use aligned zone start for pfn_to_bitidx calculation") fixed out calculation of the index into the pageblock bitmap when a !SPARSEMEM zome was not aligned to pageblock_nr_pages. However, the _allocation_ of that bitmap had never taken this alignment requirement into accout, so depending on the exact size and alignment of the zone, the use of that index could then access past the allocation, resulting in some very subtle memory corruption. This was reported (and bisected) by Ingo Molnar: one of his random config builds would hang with certain very specific kernel command line options. In the meantime, commit c060f943d092 has been marked for stable, so this fix needs to be back-ported to the stable kernels that backported the commit to use the right alignment. Bisected-and-tested-by: Ingo Molnar Acked-by: Mel Gorman Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 691b8ecdaa6..533ea80f856 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4216,10 +4216,11 @@ static void __meminit calculate_node_totalpages(struct pglist_data *pgdat, * round what is now in bits to nearest long in bits, then return it in * bytes. */ -static unsigned long __init usemap_size(unsigned long zonesize) +static unsigned long __init usemap_size(unsigned long zone_start_pfn, unsigned long zonesize) { unsigned long usemapsize; + zonesize += zone_start_pfn & (pageblock_nr_pages-1); usemapsize = roundup(zonesize, pageblock_nr_pages); usemapsize = usemapsize >> pageblock_order; usemapsize *= NR_PAGEBLOCK_BITS; @@ -4229,17 +4230,19 @@ static unsigned long __init usemap_size(unsigned long zonesize) } static void __init setup_usemap(struct pglist_data *pgdat, - struct zone *zone, unsigned long zonesize) + struct zone *zone, + unsigned long zone_start_pfn, + unsigned long zonesize) { - unsigned long usemapsize = usemap_size(zonesize); + unsigned long usemapsize = usemap_size(zone_start_pfn, zonesize); zone->pageblock_flags = NULL; if (usemapsize) zone->pageblock_flags = alloc_bootmem_node_nopanic(pgdat, usemapsize); } #else -static inline void setup_usemap(struct pglist_data *pgdat, - struct zone *zone, unsigned long zonesize) {} +static inline void setup_usemap(struct pglist_data *pgdat, struct zone *zone, + unsigned long zone_start_pfn, unsigned long zonesize) {} #endif /* CONFIG_SPARSEMEM */ #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE @@ -4367,7 +4370,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat, continue; set_pageblock_order(pageblock_default_order()); - setup_usemap(pgdat, zone, size); + setup_usemap(pgdat, zone, zone_start_pfn, size); ret = init_currently_empty_zone(zone, zone_start_pfn, size, MEMMAP_EARLY); BUG_ON(ret); From 526a26556b9069238ea7eecb9095cc672daef0e5 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 7 Feb 2013 17:14:08 -0800 Subject: [PATCH 2167/2357] timeconst.pl: Eliminate Perl warning commit 63a3f603413ffe82ad775f2d62a5afff87fd94a0 upstream. defined(@array) is deprecated in Perl and gives off a warning. Restructure the code to remove that warning. [ hpa: it would be interesting to revert to the timeconst.bc script. It appears that the failures reported by akpm during testing of that script was due to a known broken version of make, not a problem with bc. The Makefile rules could probably be restructured to avoid the make bug, or it is probably old enough that it doesn't matter. ] Reported-by: Andi Kleen Signed-off-by: H. Peter Anvin Cc: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- kernel/timeconst.pl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/timeconst.pl b/kernel/timeconst.pl index eb51d76e058..3f42652a6a3 100644 --- a/kernel/timeconst.pl +++ b/kernel/timeconst.pl @@ -369,10 +369,8 @@ (@) die "Usage: $0 HZ\n"; } - @val = @{$canned_values{$hz}}; - if (!defined(@val)) { - @val = compute_values($hz); - } + $cv = $canned_values{$hz}; + @val = defined($cv) ? @$cv : compute_values($hz); output($hz, @val); } exit 0; From b3c57f009cfd9ed81737169c4026bfd03191d993 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 23 Nov 2012 10:08:44 +0100 Subject: [PATCH 2168/2357] genirq: Avoid deadlock in spurious handling commit e716efde75267eab919cdb2bef5b2cb77f305326 upstream. commit 52553ddf(genirq: fix regression in irqfixup, irqpoll) introduced a potential deadlock by calling the action handler with the irq descriptor lock held. Remove the call and let the handling code run even for an interrupt where only a single action is registered. That matches the goal of the above commit and avoids the deadlock. Document the confusing action = desc->action reload in the handling loop while at it. Reported-and-tested-by: "Wang, Warner" Tested-by: Edward Donovan Cc: "Wang, Song-Bo (Stoney)" Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/irq/spurious.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index 611cd6003c4..7b5f012bde9 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -80,13 +80,11 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force) /* * All handlers must agree on IRQF_SHARED, so we test just the - * first. Check for action->next as well. + * first. */ action = desc->action; if (!action || !(action->flags & IRQF_SHARED) || - (action->flags & __IRQF_TIMER) || - (action->handler(irq, action->dev_id) == IRQ_HANDLED) || - !action->next) + (action->flags & __IRQF_TIMER)) goto out; /* Already running on another processor */ @@ -104,6 +102,7 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force) do { if (handle_irq_event(desc) == IRQ_HANDLED) ret = IRQ_HANDLED; + /* Make sure that there is still a valid action */ action = desc->action; } while ((desc->istate & IRQS_PENDING) && action); desc->istate &= ~IRQS_POLL_INPROGRESS; From 7c3e516d99265e4aa915f3c05611b0f426bf8ce3 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 15 Feb 2013 11:08:11 +0100 Subject: [PATCH 2169/2357] posix-cpu-timers: Fix nanosleep task_struct leak commit e6c42c295e071dd74a66b5a9fcf4f44049888ed8 upstream. The trinity fuzzer triggered a task_struct reference leak via clock_nanosleep with CPU_TIMERs. do_cpu_nanosleep() calls posic_cpu_timer_create(), but misses a corresponding posix_cpu_timer_del() which leads to the task_struct reference leak. Reported-and-tested-by: Tommi Rantala Signed-off-by: Stanislaw Gruszka Cc: Dave Jones Cc: John Stultz Cc: Oleg Nesterov Link: http://lkml.kernel.org/r/20130215100810.GF4392@redhat.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/posix-cpu-timers.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 125cb67daa2..acbb79c9092 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -1422,8 +1422,10 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, while (!signal_pending(current)) { if (timer.it.cpu.expires.sched == 0) { /* - * Our timer fired and was reset. + * Our timer fired and was reset, below + * deletion can not fail. */ + posix_cpu_timer_del(&timer); spin_unlock_irq(&timer.it_lock); return 0; } @@ -1441,9 +1443,26 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, * We were interrupted by a signal. */ sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp); - posix_cpu_timer_set(&timer, 0, &zero_it, it); + error = posix_cpu_timer_set(&timer, 0, &zero_it, it); + if (!error) { + /* + * Timer is now unarmed, deletion can not fail. + */ + posix_cpu_timer_del(&timer); + } spin_unlock_irq(&timer.it_lock); + while (error == TIMER_RETRY) { + /* + * We need to handle case when timer was or is in the + * middle of firing. In other cases we already freed + * resources. + */ + spin_lock_irq(&timer.it_lock); + error = posix_cpu_timer_del(&timer); + spin_unlock_irq(&timer.it_lock); + } + if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) { /* * It actually did fire already. From dd9c58a90c955ae794c1080156db8d8f64a52a21 Mon Sep 17 00:00:00 2001 From: Leonid Shatz Date: Mon, 4 Feb 2013 14:33:37 +0200 Subject: [PATCH 2170/2357] hrtimer: Prevent hrtimer_enqueue_reprogram race commit b22affe0aef429d657bc6505aacb1c569340ddd2 upstream. hrtimer_enqueue_reprogram contains a race which could result in timer.base switch during unlock/lock sequence. hrtimer_enqueue_reprogram is releasing the lock protecting the timer base for calling raise_softirq_irqsoff() due to a lock ordering issue versus rq->lock. If during that time another CPU calls __hrtimer_start_range_ns() on the same hrtimer, the timer base might switch, before the current CPU can lock base->lock again and therefor the unlock_timer_base() call will unlock the wrong lock. [ tglx: Added comment and massaged changelog ] Signed-off-by: Leonid Shatz Signed-off-by: Izik Eidus Cc: Andrea Arcangeli Link: http://lkml.kernel.org/r/1359981217-389-1-git-send-email-izik.eidus@ravellosystems.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/hrtimer.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 6db7a5ed52b..cdd5607c0ce 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -640,21 +640,9 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) * and expiry check is done in the hrtimer_interrupt or in the softirq. */ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base, - int wakeup) + struct hrtimer_clock_base *base) { - if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) { - if (wakeup) { - raw_spin_unlock(&base->cpu_base->lock); - raise_softirq_irqoff(HRTIMER_SOFTIRQ); - raw_spin_lock(&base->cpu_base->lock); - } else - __raise_softirq_irqoff(HRTIMER_SOFTIRQ); - - return 1; - } - - return 0; + return base->cpu_base->hres_active && hrtimer_reprogram(timer, base); } static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) @@ -735,8 +723,7 @@ static inline int hrtimer_switch_to_hres(void) { return 0; } static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { } static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base, - int wakeup) + struct hrtimer_clock_base *base) { return 0; } @@ -995,8 +982,21 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, * * XXX send_remote_softirq() ? */ - if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)) - hrtimer_enqueue_reprogram(timer, new_base, wakeup); + if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases) + && hrtimer_enqueue_reprogram(timer, new_base)) { + if (wakeup) { + /* + * We need to drop cpu_base->lock to avoid a + * lock ordering issue vs. rq->lock. + */ + raw_spin_unlock(&new_base->cpu_base->lock); + raise_softirq_irqoff(HRTIMER_SOFTIRQ); + local_irq_restore(flags); + return ret; + } else { + __raise_softirq_irqoff(HRTIMER_SOFTIRQ); + } + } unlock_hrtimer_base(timer, &flags); From 507d34bf74e3cef390d74b180ed9695e6bf3dcbb Mon Sep 17 00:00:00 2001 From: Olaf Hering <[mailto:olaf@aepfle.de]> Date: Sun, 3 Feb 2013 17:22:37 -0800 Subject: [PATCH 2171/2357] x86: Hyper-V: register clocksource only if its advertised commit 32068f6527b8f1822a30671dedaf59c567325026 upstream. Enable hyperv_clocksource only if its advertised as a feature. XenServer 6 returns the signature which is checked in ms_hyperv_platform(), but it does not offer all features. Currently the clocksource is enabled unconditionally in ms_hyperv_init_platform(), and the result is a hanging guest. Hyper-V spec Bit 1 indicates the availability of Partition Reference Counter. Register the clocksource only if this bit is set. The guest in question prints this in dmesg: [ 0.000000] Hypervisor detected: Microsoft HyperV [ 0.000000] HyperV: features 0x70, hints 0x0 This bug can be reproduced easily be setting 'viridian=1' in a HVM domU .cfg file. A workaround without this patch is to boot the HVM guest with 'clocksource=jiffies'. Signed-off-by: Olaf Hering Link: http://lkml.kernel.org/r/1359940959-32168-1-git-send-email-kys@microsoft.com Signed-off-by: K. Y. Srinivasan Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mshyperv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 0a630dd4b62..646d192b18a 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -68,7 +68,8 @@ static void __init ms_hyperv_init_platform(void) printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n", ms_hyperv.features, ms_hyperv.hints); - clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); + if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) + clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); } const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { From 7fb3e95821e901ed594c88747e5729a39723d2ff Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Mon, 11 Feb 2013 19:49:48 +0400 Subject: [PATCH 2172/2357] ALSA: ali5451: remove irq enabling in pointer callback commit dacae5a19b4cbe1b5e3a86de23ea74cbe9ec9652 upstream. snd_ali_pointer function is called with local interrupts disabled. However it seems very strange to reenable them in such way. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Denis Efremov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/ali5451/ali5451.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index bdd6164e9c7..131fd1f5db0 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1435,7 +1435,7 @@ static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream) spin_lock(&codec->reg_lock); if (!pvoice->running) { - spin_unlock_irq(&codec->reg_lock); + spin_unlock(&codec->reg_lock); return 0; } outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR)); From ceb0446b6dff34bfe41c9fa54796e7b21a17bd56 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Mon, 11 Feb 2013 19:04:06 +0400 Subject: [PATCH 2173/2357] ALSA: rme32.c irq enabling after spin_lock_irq commit f49a59c4471d81a233e09dda45187cc44fda009d upstream. According to the other code in this driver and similar code in rme96 it seems, that spin_lock_irq in snd_rme32_capture_close function should be paired with spin_unlock_irq. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Denis Efremov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/rme32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index b4819d5e41d..64da910ac34 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1017,7 +1017,7 @@ static int snd_rme32_capture_close(struct snd_pcm_substream *substream) spin_lock_irq(&rme32->lock); rme32->capture_substream = NULL; rme32->capture_periodsize = 0; - spin_unlock(&rme32->lock); + spin_unlock_irq(&rme32->lock); return 0; } From 0c10d7fd0d53e3e44cc04edc37120bce6d74e2ca Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Wed, 30 Jan 2013 11:44:50 +0100 Subject: [PATCH 2174/2357] tty: Prevent deadlock in n_gsm driver commit 4d9b109060f690f5c835130ff54165ae157b3087 upstream. This change fixes a deadlock when the multiplexer is closed while there are still client side ports open. When the multiplexer is closed and there are active tty's it tries to close them with tty_vhangup. This has a problem though, because tty_vhangup needs the tty_lock. This patch changes it to unlock the tty_lock before attempting the hangup and relocks afterwards. The additional call to tty_port_tty_set is needed because otherwise the port stays active because of the reference counter. This change also exposed another problem that other code paths don't expect that the multiplexer could have been closed. This patch also adds checks for these cases in the gsmtty_ class of function that could be called. The documentation explicitly states that "first close all virtual ports before closing the physical port" but we've found this to not always reality in our field situations. The GPRS / UTMS modem sometimes crashes and needs a power cycle in that case which means cleanly shutting down everything is not always possible. This change makes it much more robust for our situation where at least the system is recoverable with this patch and doesn't hang in a deadlock situation inside the kernel. The patch is against the long term support kernel (3.4.27) and should apply cleanly to more recent branches. Tested with a Telit GE864-QUADV2 and Telit HE910 modem. Signed-off-by: Dirkjan Bussink Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 90dff8233ef..4a418e44d56 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1692,6 +1692,8 @@ static inline void dlci_put(struct gsm_dlci *dlci) kref_put(&dlci->ref, gsm_dlci_free); } +static void gsm_destroy_network(struct gsm_dlci *dlci); + /** * gsm_dlci_release - release DLCI * @dlci: DLCI to destroy @@ -1705,9 +1707,19 @@ static void gsm_dlci_release(struct gsm_dlci *dlci) { struct tty_struct *tty = tty_port_tty_get(&dlci->port); if (tty) { + mutex_lock(&dlci->mutex); + gsm_destroy_network(dlci); + mutex_unlock(&dlci->mutex); + + /* tty_vhangup needs the tty_lock, so unlock and + relock after doing the hangup. */ + tty_unlock(); tty_vhangup(tty); + tty_lock(); + tty_port_tty_set(&dlci->port, NULL); tty_kref_put(tty); } + dlci->state = DLCI_CLOSED; dlci_put(dlci); } @@ -2933,6 +2945,8 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp) if (dlci == NULL) return; + if (dlci->state == DLCI_CLOSED) + return; mutex_lock(&dlci->mutex); gsm_destroy_network(dlci); mutex_unlock(&dlci->mutex); @@ -2951,6 +2965,8 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp) static void gsmtty_hangup(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return; tty_port_hangup(&dlci->port); gsm_dlci_begin_close(dlci); } @@ -2958,9 +2974,12 @@ static void gsmtty_hangup(struct tty_struct *tty) static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf, int len) { + int sent; struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return -EINVAL; /* Stuff the bytes into the fifo queue */ - int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock); + sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock); /* Need to kick the channel */ gsm_dlci_data_kick(dlci); return sent; @@ -2969,18 +2988,24 @@ static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf, static int gsmtty_write_room(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return -EINVAL; return TX_SIZE - kfifo_len(dlci->fifo); } static int gsmtty_chars_in_buffer(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return -EINVAL; return kfifo_len(dlci->fifo); } static void gsmtty_flush_buffer(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return; /* Caution needed: If we implement reliable transport classes then the data being transmitted can't simply be junked once it has first hit the stack. Until then we can just blow it @@ -2999,6 +3024,8 @@ static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout) static int gsmtty_tiocmget(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return -EINVAL; return dlci->modem_rx; } @@ -3008,6 +3035,8 @@ static int gsmtty_tiocmset(struct tty_struct *tty, struct gsm_dlci *dlci = tty->driver_data; unsigned int modem_tx = dlci->modem_tx; + if (dlci->state == DLCI_CLOSED) + return -EINVAL; modem_tx &= ~clear; modem_tx |= set; @@ -3026,6 +3055,8 @@ static int gsmtty_ioctl(struct tty_struct *tty, struct gsm_netconfig nc; int index; + if (dlci->state == DLCI_CLOSED) + return -EINVAL; switch (cmd) { case GSMIOC_ENABLE_NET: if (copy_from_user(&nc, (void __user *)arg, sizeof(nc))) @@ -3052,6 +3083,9 @@ static int gsmtty_ioctl(struct tty_struct *tty, static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old) { + struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return; /* For the moment its fixed. In actual fact the speed information for the virtual channel can be propogated in both directions by the RPN control message. This however rapidly gets nasty as we @@ -3063,6 +3097,8 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old) static void gsmtty_throttle(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return; if (tty->termios->c_cflag & CRTSCTS) dlci->modem_tx &= ~TIOCM_DTR; dlci->throttled = 1; @@ -3073,6 +3109,8 @@ static void gsmtty_throttle(struct tty_struct *tty) static void gsmtty_unthrottle(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return; if (tty->termios->c_cflag & CRTSCTS) dlci->modem_tx |= TIOCM_DTR; dlci->throttled = 0; @@ -3084,6 +3122,8 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) { struct gsm_dlci *dlci = tty->driver_data; int encode = 0; /* Off */ + if (dlci->state == DLCI_CLOSED) + return -EINVAL; if (state == -1) /* "On indefinitely" - we can't encode this properly */ From 46605dae03a55a70d7fd9886f466b435afc7738b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 29 Jan 2013 20:07:41 +0100 Subject: [PATCH 2175/2357] tty: set_termios/set_termiox should not return -EINTR commit 183d95cdd834381c594d3aa801c1f9f9c0c54fa9 upstream. See https://bugzilla.redhat.com/show_bug.cgi?id=904907 read command causes bash to abort with double free or corruption (out). A simple test-case from Roman: // Compile the reproducer and send sigchld ti that process. // EINTR occurs even if SA_RESTART flag is set. void handler(int sig) { } main() { struct sigaction act; act.sa_handler = handler; act.sa_flags = SA_RESTART; sigaction (SIGCHLD, &act, 0); struct termio ttp; ioctl(0, TCGETA, &ttp); while(1) { if (ioctl(0, TCSETAW, ttp) < 0) { if (errno == EINTR) { fprintf(stderr, "BUG!"); return(1); } } } } Change set_termios/set_termiox to return -ERESTARTSYS to fix this particular problem. I didn't dare to change other EINTR's in drivers/tty/, but they look equally wrong. Reported-by: Roman Rakus Reported-by: Lingzhu Xiang Signed-off-by: Oleg Nesterov Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ioctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index a1b9a2f6856..f8d03da536d 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -617,7 +617,7 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) if (opt & TERMIOS_WAIT) { tty_wait_until_sent(tty, 0); if (signal_pending(current)) - return -EINTR; + return -ERESTARTSYS; } tty_set_termios(tty, &tmp_termios); @@ -684,7 +684,7 @@ static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) if (opt & TERMIOS_WAIT) { tty_wait_until_sent(tty, 0); if (signal_pending(current)) - return -EINTR; + return -ERESTARTSYS; } mutex_lock(&tty->termios_mutex); From 906c9c42101742d1ec86ab22eb55d24d496830a7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 13 Feb 2013 17:53:28 +0100 Subject: [PATCH 2176/2357] USB: serial: fix null-pointer dereferences on disconnect commit b2ca699076573c94fee9a73cb0d8645383b602a0 upstream. Make sure serial-driver dtr_rts is called with disc_mutex held after checking the disconnected flag. Due to a bug in the tty layer, dtr_rts may get called after a device has been disconnected and the tty-device unregistered. Some drivers have had individual checks for disconnect to make sure the disconnected interface was not accessed, but this should really be handled in usb-serial core (at least until the long-standing tty-bug has been fixed). Note that the problem has been made more acute with commit 0998d0631001 ("device-core: Ensure drvdata = NULL when no driver is bound") as the port data is now also NULL when dtr_rts is called resulting in further oopses. Reported-by: Chris Ruehl Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 20 +++++++++----------- drivers/usb/serial/mct_u232.c | 22 +++++++++------------- drivers/usb/serial/sierra.c | 8 +------- drivers/usb/serial/ssu100.c | 19 ++++++++----------- drivers/usb/serial/usb-serial.c | 14 ++++++++++++-- drivers/usb/serial/usb_wwan.c | 8 +++----- 6 files changed, 42 insertions(+), 49 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 77469442b3f..87ef1503552 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1919,24 +1919,22 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on) { struct ftdi_private *priv = usb_get_serial_port_data(port); - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* Disable flow control */ - if (!on && usb_control_msg(port->serial->dev, + /* Disable flow control */ + if (!on) { + if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "error from flowcontrol urb\n"); + dev_err(&port->dev, "error from flowcontrol urb\n"); } - /* drop RTS and DTR */ - if (on) - set_mctrl(port, TIOCM_DTR | TIOCM_RTS); - else - clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } - mutex_unlock(&port->serial->disc_mutex); + /* drop RTS and DTR */ + if (on) + set_mctrl(port, TIOCM_DTR | TIOCM_RTS); + else + clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index d0bf56dba07..933dd07aa08 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -514,19 +514,15 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on) unsigned int control_state; struct mct_u232_private *priv = usb_get_serial_port_data(port); - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* drop DTR and RTS */ - spin_lock_irq(&priv->lock); - if (on) - priv->control_state |= TIOCM_DTR | TIOCM_RTS; - else - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - control_state = priv->control_state; - spin_unlock_irq(&priv->lock); - mct_u232_set_modem_ctrl(port->serial, control_state); - } - mutex_unlock(&port->serial->disc_mutex); + spin_lock_irq(&priv->lock); + if (on) + priv->control_state |= TIOCM_DTR | TIOCM_RTS; + else + priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); + control_state = priv->control_state; + spin_unlock_irq(&priv->lock); + + mct_u232_set_modem_ctrl(port->serial, control_state); } static void mct_u232_close(struct usb_serial_port *port) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index b622d695fdb..8ec15c2540b 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -890,19 +890,13 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) static void sierra_dtr_rts(struct usb_serial_port *port, int on) { - struct usb_serial *serial = port->serial; struct sierra_port_private *portdata; portdata = usb_get_serial_port_data(port); portdata->rts_state = on; portdata->dtr_state = on; - if (serial->dev) { - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - sierra_send_setup(port); - mutex_unlock(&serial->disc_mutex); - } + sierra_send_setup(port); } static int sierra_startup(struct usb_serial *serial) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 3cdc8a52de4..b8db69d96df 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -532,19 +532,16 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) dbg("%s\n", __func__); - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* Disable flow control */ - if (!on && - ssu100_setregister(dev, 0, UART_MCR, 0) < 0) + /* Disable flow control */ + if (!on) { + if (ssu100_setregister(dev, 0, UART_MCR, 0) < 0) dev_err(&port->dev, "error from flowcontrol urb\n"); - /* drop RTS and DTR */ - if (on) - set_mctrl(dev, TIOCM_DTR | TIOCM_RTS); - else - clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS); } - mutex_unlock(&port->serial->disc_mutex); + /* drop RTS and DTR */ + if (on) + set_mctrl(dev, TIOCM_DTR | TIOCM_RTS); + else + clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS); } static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index c627ba21b1e..e4b199cbc97 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -699,10 +699,20 @@ static int serial_carrier_raised(struct tty_port *port) static void serial_dtr_rts(struct tty_port *port, int on) { struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); - struct usb_serial_driver *drv = p->serial->type; + struct usb_serial *serial = p->serial; + struct usb_serial_driver *drv = serial->type; - if (drv->dtr_rts) + if (!drv->dtr_rts) + return; + /* + * Work-around bug in the tty-layer which can result in dtr_rts + * being called after a disconnect (and tty_unregister_device + * has returned). Remove once bug has been squashed. + */ + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) drv->dtr_rts(p, on); + mutex_unlock(&serial->disc_mutex); } static const struct tty_port_operations serial_port_ops = { diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index c88657dd31c..820436ec60e 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -41,7 +41,6 @@ static bool debug; void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) { - struct usb_serial *serial = port->serial; struct usb_wwan_port_private *portdata; struct usb_wwan_intf_private *intfdata; @@ -54,12 +53,11 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) return; portdata = usb_get_serial_port_data(port); - mutex_lock(&serial->disc_mutex); + /* FIXME: locking */ portdata->rts_state = on; portdata->dtr_state = on; - if (serial->dev) - intfdata->send_setup(port); - mutex_unlock(&serial->disc_mutex); + + intfdata->send_setup(port); } EXPORT_SYMBOL(usb_wwan_dtr_rts); From 1946c763f335fcc7482936c039fddeb179c7f384 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 17 Feb 2013 17:01:20 +0000 Subject: [PATCH 2177/2357] b43: Increase number of RX DMA slots commit ccae0e50c16a7f7adb029c169147400d1ce9f703 upstream. Bastian Bittorf reported that some of the silent freezes on a Linksys WRT54G were due to overflow of the RX DMA ring buffer, which was created with 64 slots. That finding reminded me that I was seeing similar crashed on a netbook, which also has a relatively slow processor. After increasing the number of slots to 128, runs on the netbook that previously failed now worked; however, I found that 109 slots had been used in one test. For that reason, the number of slots is being increased to 256. Signed-off-by: Larry Finger Cc: Bastian Bittorf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/b43/dma.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 315b96ed1d9..9fdd1983079 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -169,7 +169,7 @@ struct b43_dmadesc_generic { /* DMA engine tuning knobs */ #define B43_TXRING_SLOTS 256 -#define B43_RXRING_SLOTS 64 +#define B43_RXRING_SLOTS 256 #define B43_DMA0_RX_FW598_BUFSIZE (B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN) #define B43_DMA0_RX_FW351_BUFSIZE (B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN) From d1179077b018d6c5488eaaa5c71349094d5104f3 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 8 Feb 2013 12:28:18 -0600 Subject: [PATCH 2178/2357] rtlwifi: rtl8192cu: Add new USB ID commit 8708aac79e4572ba673d7a21e94ddca9f3abb7fc upstream. A new model of the RTL8188CUS has appeared. Reported-and-tested-by: Thomas Rosenkrantz Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 61e57689a05..8cf41bb9883 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -285,6 +285,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)}, /* RTL8188CUS-VL */ {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)}, + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x819a, rtl92cu_hal_cfg)}, /* 8188 Combo for BC4 */ {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)}, From 6a171676006047cd613093b74a6cfdcba8686065 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Mon, 18 Feb 2013 10:29:30 +0200 Subject: [PATCH 2179/2357] rtlwifi: usb: allocate URB control message setup_packet and data buffer separately commit bc6b89237acb3dee6af6e64e51a18255fef89cc2 upstream. rtlwifi allocates both setup_packet and data buffer of control message urb, using shared kmalloc in _usbctrl_vendorreq_async_write. Structure used for allocating is: struct { u8 data[254]; struct usb_ctrlrequest dr; }; Because 'struct usb_ctrlrequest' is __packed, setup packet is unaligned and DMA mapping of both 'data' and 'dr' confuses ARM/sunxi, leading to memory corruptions and freezes. Patch changes setup packet to be allocated separately. [v2]: - Use WARN_ON_ONCE instead of WARN_ON Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/usb.c | 44 +++++++++++++++++++----------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 17cd028d235..6ce848457d1 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -42,8 +42,12 @@ static void usbctrl_async_callback(struct urb *urb) { - if (urb) - kfree(urb->context); + if (urb) { + /* free dr */ + kfree(urb->setup_packet); + /* free databuf */ + kfree(urb->transfer_buffer); + } } static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, @@ -55,39 +59,47 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, u8 reqtype; struct usb_ctrlrequest *dr; struct urb *urb; - struct rtl819x_async_write_data { - u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE]; - struct usb_ctrlrequest dr; - } *buf; + const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE; + u8 *databuf; + + if (WARN_ON_ONCE(len > databuf_maxlen)) + len = databuf_maxlen; pipe = usb_sndctrlpipe(udev, 0); /* write_out */ reqtype = REALTEK_USB_VENQT_WRITE; - buf = kmalloc(sizeof(*buf), GFP_ATOMIC); - if (!buf) + dr = kmalloc(sizeof(*dr), GFP_ATOMIC); + if (!dr) return -ENOMEM; + databuf = kmalloc(databuf_maxlen, GFP_ATOMIC); + if (!databuf) { + kfree(dr); + return -ENOMEM; + } + urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { - kfree(buf); + kfree(databuf); + kfree(dr); return -ENOMEM; } - dr = &buf->dr; - dr->bRequestType = reqtype; dr->bRequest = request; dr->wValue = cpu_to_le16(value); dr->wIndex = cpu_to_le16(index); dr->wLength = cpu_to_le16(len); /* data are already in little-endian order */ - memcpy(buf, pdata, len); + memcpy(databuf, pdata, len); usb_fill_control_urb(urb, udev, pipe, - (unsigned char *)dr, buf, len, - usbctrl_async_callback, buf); + (unsigned char *)dr, databuf, len, + usbctrl_async_callback, NULL); rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc < 0) - kfree(buf); + if (rc < 0) { + kfree(databuf); + kfree(dr); + } usb_free_urb(urb); return rc; } From 4f4eb62481b02ffec9edee9f109d22d6debe0281 Mon Sep 17 00:00:00 2001 From: Stefan Bader Date: Fri, 15 Feb 2013 09:48:52 +0100 Subject: [PATCH 2180/2357] xen: Send spinlock IPI to all waiters commit 76eaca031f0af2bb303e405986f637811956a422 upstream. There is a loophole between Xen's current implementation of pv-spinlocks and the scheduler. This was triggerable through a testcase until v3.6 changed the TLB flushing code. The problem potentially is still there just not observable in the same way. What could happen was (is): 1. CPU n tries to schedule task x away and goes into a slow wait for the runq lock of CPU n-# (must be one with a lower number). 2. CPU n-#, while processing softirqs, tries to balance domains and goes into a slow wait for its own runq lock (for updating some records). Since this is a spin_lock_irqsave in softirq context, interrupts will be re-enabled for the duration of the poll_irq hypercall used by Xen. 3. Before the runq lock of CPU n-# is unlocked, CPU n-1 receives an interrupt (e.g. endio) and when processing the interrupt, tries to wake up task x. But that is in schedule and still on_cpu, so try_to_wake_up goes into a tight loop. 4. The runq lock of CPU n-# gets unlocked, but the message only gets sent to the first waiter, which is CPU n-# and that is busily stuck. 5. CPU n-# never returns from the nested interruption to take and release the lock because the scheduler uses a busy wait. And CPU n never finishes the task migration because the unlock notification only went to CPU n-#. To avoid this and since the unlocking code has no real sense of which waiter is best suited to grab the lock, just send the IPI to all of them. This causes the waiters to return from the hyper- call (those not interrupted at least) and do active spinlocking. BugLink: http://bugs.launchpad.net/bugs/1011792 Acked-by: Jan Beulich Signed-off-by: Stefan Bader Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/spinlock.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c index d69cc6c3f80..67bc7bae746 100644 --- a/arch/x86/xen/spinlock.c +++ b/arch/x86/xen/spinlock.c @@ -328,7 +328,6 @@ static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl) if (per_cpu(lock_spinners, cpu) == xl) { ADD_STATS(released_slow_kicked, 1); xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR); - break; } } } From 2199a6528ce9b299f3a3e2a6b50cfd197cbc135e Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Mon, 18 Feb 2013 14:57:58 +0000 Subject: [PATCH 2181/2357] xen: close evtchn port if binding to irq fails commit e7e44e444876478d50630f57b0c31d29f6725020 upstream. Signed-off-by: Wei Liu Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/evtchn.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index b1f60a0c0be..b2db77e5a59 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -269,6 +269,14 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port) u->name, (void *)(unsigned long)port); if (rc >= 0) rc = evtchn_make_refcounted(port); + else { + /* bind failed, should close the port now */ + struct evtchn_close close; + close.port = port; + if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) + BUG(); + set_port_user(port, NULL); + } return rc; } @@ -277,6 +285,8 @@ static void evtchn_unbind_from_user(struct per_user_data *u, int port) { int irq = irq_from_evtchn(port); + BUG_ON(irq < 0); + unbind_from_irqhandler(irq, (void *)(unsigned long)port); set_port_user(port, NULL); From 362efcc9b0ba020f9124c70c56381ed64491aeca Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 29 Jan 2013 16:44:27 -0700 Subject: [PATCH 2182/2357] Driver core: treat unregistered bus_types as having no devices commit 4fa3e78be7e985ca814ce2aa0c09cbee404efcf7 upstream. A bus_type has a list of devices (klist_devices), but the list and the subsys_private structure that contains it are not initialized until the bus_type is registered with bus_register(). The panic/reboot path has fixups that look up devices in pci_bus_type. If we panic before registering pci_bus_type, the bus_type exists but the list does not, so mach_reboot_fixups() trips over a null pointer and panics again: mach_reboot_fixups pci_get_device .. bus_find_device(&pci_bus_type, ...) bus->p is NULL Joonsoo reported a problem when panicking before PCI was initialized. I think this patch should be sufficient to replace the patch he posted here: https://lkml.org/lkml/2012/12/28/75 ("[PATCH] x86, reboot: skip reboot_fixups in early boot phase") Reported-by: Joonsoo Kim Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 26a06b801b5..b850cecb147 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -294,7 +294,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start, struct device *dev; int error = 0; - if (!bus) + if (!bus || !bus->p) return -EINVAL; klist_iter_init_node(&bus->p->klist_devices, &i, @@ -328,7 +328,7 @@ struct device *bus_find_device(struct bus_type *bus, struct klist_iter i; struct device *dev; - if (!bus) + if (!bus || !bus->p) return NULL; klist_iter_init_node(&bus->p->klist_devices, &i, From 4209ee0d3f7992af3903b5f9a3359f6d2f597c4b Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 8 Oct 2012 16:29:24 -0700 Subject: [PATCH 2183/2357] mm: mmu_notifier: have mmu_notifiers use a global SRCU so they may safely schedule commit 21a92735f660eaecf69a6f2e777f18463760ec32 upstream. With an RCU based mmu_notifier implementation, any callout to mmu_notifier_invalidate_range_{start,end}() or mmu_notifier_invalidate_page() would not be allowed to call schedule() as that could potentially allow a modification to the mmu_notifier structure while it is currently being used. Since srcu allocs 4 machine words per instance per cpu, we may end up with memory exhaustion if we use srcu per mm. So all mms share a global srcu. Note that during large mmu_notifier activity exit & unregister paths might hang for longer periods, but it is tolerable for current mmu_notifier clients. Signed-off-by: Sagi Grimberg Signed-off-by: Andrea Arcangeli Cc: Peter Zijlstra Cc: Haggai Eran Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/mmu_notifier.h | 1 + mm/mmu_notifier.c | 73 ++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h index 1d1b1e13f79..ee2baf034fc 100644 --- a/include/linux/mmu_notifier.h +++ b/include/linux/mmu_notifier.h @@ -4,6 +4,7 @@ #include #include #include +#include struct mmu_notifier; struct mmu_notifier_ops; diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c index 862b60822d9..35ff447d8d1 100644 --- a/mm/mmu_notifier.c +++ b/mm/mmu_notifier.c @@ -14,10 +14,14 @@ #include #include #include +#include #include #include #include +/* global SRCU for all MMs */ +struct srcu_struct srcu; + /* * This function can't run concurrently against mmu_notifier_register * because mm->mm_users > 0 during mmu_notifier_register and exit_mmap @@ -25,8 +29,8 @@ * in parallel despite there being no task using this mm any more, * through the vmas outside of the exit_mmap context, such as with * vmtruncate. This serializes against mmu_notifier_unregister with - * the mmu_notifier_mm->lock in addition to RCU and it serializes - * against the other mmu notifiers with RCU. struct mmu_notifier_mm + * the mmu_notifier_mm->lock in addition to SRCU and it serializes + * against the other mmu notifiers with SRCU. struct mmu_notifier_mm * can't go away from under us as exit_mmap holds an mm_count pin * itself. */ @@ -34,12 +38,13 @@ void __mmu_notifier_release(struct mm_struct *mm) { struct mmu_notifier *mn; struct hlist_node *n; + int id; /* * RCU here will block mmu_notifier_unregister until * ->release returns. */ - rcu_read_lock(); + id = srcu_read_lock(&srcu); hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) /* * if ->release runs before mmu_notifier_unregister it @@ -50,7 +55,7 @@ void __mmu_notifier_release(struct mm_struct *mm) */ if (mn->ops->release) mn->ops->release(mn, mm); - rcu_read_unlock(); + srcu_read_unlock(&srcu, id); spin_lock(&mm->mmu_notifier_mm->lock); while (unlikely(!hlist_empty(&mm->mmu_notifier_mm->list))) { @@ -68,7 +73,7 @@ void __mmu_notifier_release(struct mm_struct *mm) spin_unlock(&mm->mmu_notifier_mm->lock); /* - * synchronize_rcu here prevents mmu_notifier_release to + * synchronize_srcu here prevents mmu_notifier_release to * return to exit_mmap (which would proceed freeing all pages * in the mm) until the ->release method returns, if it was * invoked by mmu_notifier_unregister. @@ -76,7 +81,7 @@ void __mmu_notifier_release(struct mm_struct *mm) * The mmu_notifier_mm can't go away from under us because one * mm_count is hold by exit_mmap. */ - synchronize_rcu(); + synchronize_srcu(&srcu); } /* @@ -89,14 +94,14 @@ int __mmu_notifier_clear_flush_young(struct mm_struct *mm, { struct mmu_notifier *mn; struct hlist_node *n; - int young = 0; + int young = 0, id; - rcu_read_lock(); + id = srcu_read_lock(&srcu); hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { if (mn->ops->clear_flush_young) young |= mn->ops->clear_flush_young(mn, mm, address); } - rcu_read_unlock(); + srcu_read_unlock(&srcu, id); return young; } @@ -106,9 +111,9 @@ int __mmu_notifier_test_young(struct mm_struct *mm, { struct mmu_notifier *mn; struct hlist_node *n; - int young = 0; + int young = 0, id; - rcu_read_lock(); + id = srcu_read_lock(&srcu); hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { if (mn->ops->test_young) { young = mn->ops->test_young(mn, mm, address); @@ -116,7 +121,7 @@ int __mmu_notifier_test_young(struct mm_struct *mm, break; } } - rcu_read_unlock(); + srcu_read_unlock(&srcu, id); return young; } @@ -126,8 +131,9 @@ void __mmu_notifier_change_pte(struct mm_struct *mm, unsigned long address, { struct mmu_notifier *mn; struct hlist_node *n; + int id; - rcu_read_lock(); + id = srcu_read_lock(&srcu); hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { if (mn->ops->change_pte) mn->ops->change_pte(mn, mm, address, pte); @@ -138,7 +144,7 @@ void __mmu_notifier_change_pte(struct mm_struct *mm, unsigned long address, else if (mn->ops->invalidate_page) mn->ops->invalidate_page(mn, mm, address); } - rcu_read_unlock(); + srcu_read_unlock(&srcu, id); } void __mmu_notifier_invalidate_page(struct mm_struct *mm, @@ -146,13 +152,14 @@ void __mmu_notifier_invalidate_page(struct mm_struct *mm, { struct mmu_notifier *mn; struct hlist_node *n; + int id; - rcu_read_lock(); + id = srcu_read_lock(&srcu); hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { if (mn->ops->invalidate_page) mn->ops->invalidate_page(mn, mm, address); } - rcu_read_unlock(); + srcu_read_unlock(&srcu, id); } void __mmu_notifier_invalidate_range_start(struct mm_struct *mm, @@ -160,13 +167,14 @@ void __mmu_notifier_invalidate_range_start(struct mm_struct *mm, { struct mmu_notifier *mn; struct hlist_node *n; + int id; - rcu_read_lock(); + id = srcu_read_lock(&srcu); hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { if (mn->ops->invalidate_range_start) mn->ops->invalidate_range_start(mn, mm, start, end); } - rcu_read_unlock(); + srcu_read_unlock(&srcu, id); } void __mmu_notifier_invalidate_range_end(struct mm_struct *mm, @@ -174,13 +182,14 @@ void __mmu_notifier_invalidate_range_end(struct mm_struct *mm, { struct mmu_notifier *mn; struct hlist_node *n; + int id; - rcu_read_lock(); + id = srcu_read_lock(&srcu); hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { if (mn->ops->invalidate_range_end) mn->ops->invalidate_range_end(mn, mm, start, end); } - rcu_read_unlock(); + srcu_read_unlock(&srcu, id); } static int do_mmu_notifier_register(struct mmu_notifier *mn, @@ -192,6 +201,12 @@ static int do_mmu_notifier_register(struct mmu_notifier *mn, BUG_ON(atomic_read(&mm->mm_users) <= 0); + /* + * Verify that mmu_notifier_init() already run and the global srcu is + * initialized. + */ + BUG_ON(!srcu.per_cpu_ref); + ret = -ENOMEM; mmu_notifier_mm = kmalloc(sizeof(struct mmu_notifier_mm), GFP_KERNEL); if (unlikely(!mmu_notifier_mm)) @@ -274,8 +289,8 @@ void __mmu_notifier_mm_destroy(struct mm_struct *mm) /* * This releases the mm_count pin automatically and frees the mm * structure if it was the last user of it. It serializes against - * running mmu notifiers with RCU and against mmu_notifier_unregister - * with the unregister lock + RCU. All sptes must be dropped before + * running mmu notifiers with SRCU and against mmu_notifier_unregister + * with the unregister lock + SRCU. All sptes must be dropped before * calling mmu_notifier_unregister. ->release or any other notifier * method may be invoked concurrently with mmu_notifier_unregister, * and only after mmu_notifier_unregister returned we're guaranteed @@ -290,8 +305,9 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm) * RCU here will force exit_mmap to wait ->release to finish * before freeing the pages. */ - rcu_read_lock(); + int id; + id = srcu_read_lock(&srcu); /* * exit_mmap will block in mmu_notifier_release to * guarantee ->release is called before freeing the @@ -299,7 +315,7 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm) */ if (mn->ops->release) mn->ops->release(mn, mm); - rcu_read_unlock(); + srcu_read_unlock(&srcu, id); spin_lock(&mm->mmu_notifier_mm->lock); hlist_del_rcu(&mn->hlist); @@ -310,10 +326,17 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm) * Wait any running method to finish, of course including * ->release if it was run by mmu_notifier_relase instead of us. */ - synchronize_rcu(); + synchronize_srcu(&srcu); BUG_ON(atomic_read(&mm->mm_count) <= 0); mmdrop(mm); } EXPORT_SYMBOL_GPL(mmu_notifier_unregister); + +static int __init mmu_notifier_init(void) +{ + return init_srcu_struct(&srcu); +} + +module_init(mmu_notifier_init); From d0730c2bf33c1cdab392f88013be6b5ebacf0f29 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Mon, 8 Oct 2012 16:31:52 -0700 Subject: [PATCH 2184/2357] mm: mmu_notifier: make the mmu_notifier srcu static commit 70400303ce0c4ced3139499c676d5c79636b0c72 upstream. The variable must be static especially given the variable name. s/RCU/SRCU/ over a few comments. Signed-off-by: Andrea Arcangeli Cc: Xiao Guangrong Cc: Sagi Grimberg Cc: Peter Zijlstra Cc: Haggai Eran Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mmu_notifier.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c index 35ff447d8d1..3775c9076e4 100644 --- a/mm/mmu_notifier.c +++ b/mm/mmu_notifier.c @@ -20,7 +20,7 @@ #include /* global SRCU for all MMs */ -struct srcu_struct srcu; +static struct srcu_struct srcu; /* * This function can't run concurrently against mmu_notifier_register @@ -41,7 +41,7 @@ void __mmu_notifier_release(struct mm_struct *mm) int id; /* - * RCU here will block mmu_notifier_unregister until + * SRCU here will block mmu_notifier_unregister until * ->release returns. */ id = srcu_read_lock(&srcu); @@ -302,7 +302,7 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm) if (!hlist_unhashed(&mn->hlist)) { /* - * RCU here will force exit_mmap to wait ->release to finish + * SRCU here will force exit_mmap to wait ->release to finish * before freeing the pages. */ int id; From 7fecb64cca9a98f60ff4bc794bb353512bd5c665 Mon Sep 17 00:00:00 2001 From: Robin Holt Date: Fri, 22 Feb 2013 16:35:34 -0800 Subject: [PATCH 2185/2357] mmu_notifier_unregister NULL Pointer deref and multiple ->release() callouts commit 751efd8610d3d7d67b7bdf7f62646edea7365dd7 upstream. There is a race condition between mmu_notifier_unregister() and __mmu_notifier_release(). Assume two tasks, one calling mmu_notifier_unregister() as a result of a filp_close() ->flush() callout (task A), and the other calling mmu_notifier_release() from an mmput() (task B). A B t1 srcu_read_lock() t2 if (!hlist_unhashed()) t3 srcu_read_unlock() t4 srcu_read_lock() t5 hlist_del_init_rcu() t6 synchronize_srcu() t7 srcu_read_unlock() t8 hlist_del_rcu() <--- NULL pointer deref. Additionally, the list traversal in __mmu_notifier_release() is not protected by the by the mmu_notifier_mm->hlist_lock which can result in callouts to the ->release() notifier from both mmu_notifier_unregister() and __mmu_notifier_release(). -stable suggestions: The stable trees prior to 3.7.y need commits 21a92735f660 and 70400303ce0c cherry-picked in that order prior to cherry-picking this commit. The 3.7.y tree already has those two commits. Signed-off-by: Robin Holt Cc: Andrea Arcangeli Cc: Wanpeng Li Cc: Xiao Guangrong Cc: Avi Kivity Cc: Hugh Dickins Cc: Marcelo Tosatti Cc: Sagi Grimberg Cc: Haggai Eran Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mmu_notifier.c | 82 ++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c index 3775c9076e4..8d1ca2de408 100644 --- a/mm/mmu_notifier.c +++ b/mm/mmu_notifier.c @@ -37,49 +37,51 @@ static struct srcu_struct srcu; void __mmu_notifier_release(struct mm_struct *mm) { struct mmu_notifier *mn; - struct hlist_node *n; int id; /* - * SRCU here will block mmu_notifier_unregister until - * ->release returns. + * srcu_read_lock() here will block synchronize_srcu() in + * mmu_notifier_unregister() until all registered + * ->release() callouts this function makes have + * returned. */ id = srcu_read_lock(&srcu); - hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) - /* - * if ->release runs before mmu_notifier_unregister it - * must be handled as it's the only way for the driver - * to flush all existing sptes and stop the driver - * from establishing any more sptes before all the - * pages in the mm are freed. - */ - if (mn->ops->release) - mn->ops->release(mn, mm); - srcu_read_unlock(&srcu, id); - spin_lock(&mm->mmu_notifier_mm->lock); while (unlikely(!hlist_empty(&mm->mmu_notifier_mm->list))) { mn = hlist_entry(mm->mmu_notifier_mm->list.first, struct mmu_notifier, hlist); + /* - * We arrived before mmu_notifier_unregister so - * mmu_notifier_unregister will do nothing other than - * to wait ->release to finish and - * mmu_notifier_unregister to return. + * Unlink. This will prevent mmu_notifier_unregister() + * from also making the ->release() callout. */ hlist_del_init_rcu(&mn->hlist); + spin_unlock(&mm->mmu_notifier_mm->lock); + + /* + * Clear sptes. (see 'release' description in mmu_notifier.h) + */ + if (mn->ops->release) + mn->ops->release(mn, mm); + + spin_lock(&mm->mmu_notifier_mm->lock); } spin_unlock(&mm->mmu_notifier_mm->lock); /* - * synchronize_srcu here prevents mmu_notifier_release to - * return to exit_mmap (which would proceed freeing all pages - * in the mm) until the ->release method returns, if it was - * invoked by mmu_notifier_unregister. - * - * The mmu_notifier_mm can't go away from under us because one - * mm_count is hold by exit_mmap. + * All callouts to ->release() which we have done are complete. + * Allow synchronize_srcu() in mmu_notifier_unregister() to complete + */ + srcu_read_unlock(&srcu, id); + + /* + * mmu_notifier_unregister() may have unlinked a notifier and may + * still be calling out to it. Additionally, other notifiers + * may have been active via vmtruncate() et. al. Block here + * to ensure that all notifier callouts for this mm have been + * completed and the sptes are really cleaned up before returning + * to exit_mmap(). */ synchronize_srcu(&srcu); } @@ -300,31 +302,31 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm) { BUG_ON(atomic_read(&mm->mm_count) <= 0); + spin_lock(&mm->mmu_notifier_mm->lock); if (!hlist_unhashed(&mn->hlist)) { - /* - * SRCU here will force exit_mmap to wait ->release to finish - * before freeing the pages. - */ int id; - id = srcu_read_lock(&srcu); /* - * exit_mmap will block in mmu_notifier_release to - * guarantee ->release is called before freeing the - * pages. + * Ensure we synchronize up with __mmu_notifier_release(). */ + id = srcu_read_lock(&srcu); + + hlist_del_rcu(&mn->hlist); + spin_unlock(&mm->mmu_notifier_mm->lock); + if (mn->ops->release) mn->ops->release(mn, mm); - srcu_read_unlock(&srcu, id); - spin_lock(&mm->mmu_notifier_mm->lock); - hlist_del_rcu(&mn->hlist); + /* + * Allow __mmu_notifier_release() to complete. + */ + srcu_read_unlock(&srcu, id); + } else spin_unlock(&mm->mmu_notifier_mm->lock); - } /* - * Wait any running method to finish, of course including - * ->release if it was run by mmu_notifier_relase instead of us. + * Wait for any running method to finish, including ->release() if it + * was run by __mmu_notifier_release() instead of us. */ synchronize_srcu(&srcu); From 2030511afec79a7f65b967c3d8a22e4a1edd9532 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 14 Dec 2012 17:02:16 +0100 Subject: [PATCH 2186/2357] KVM: s390: Handle hosts not supporting s390-virtio. commit 55c171a6d90dc0574021f9c836127cfd1a7d2e30 upstream. Running under a kvm host does not necessarily imply the presence of a page mapped above the main memory with the virtio information; however, the code includes a hard coded access to that page. Instead, check for the presence of the page and exit gracefully before we hit an addressing exception if it does not exist. Reviewed-by: Marcelo Tosatti Reviewed-by: Alexander Graf Signed-off-by: Cornelia Huck Signed-off-by: Gleb Natapov Signed-off-by: Greg Kroah-Hartman --- drivers/s390/kvm/kvm_virtio.c | 38 +++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index d74e9ae6dfb..f97b2aa65f4 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -417,6 +417,26 @@ static void kvm_extint_handler(struct ext_code ext_code, } } +/* + * For s390-virtio, we expect a page above main storage containing + * the virtio configuration. Try to actually load from this area + * in order to figure out if the host provides this page. + */ +static int __init test_devices_support(unsigned long addr) +{ + int ret = -EIO; + + asm volatile( + "0: lura 0,%1\n" + "1: xgr %0,%0\n" + "2:\n" + EX_TABLE(0b,2b) + EX_TABLE(1b,2b) + : "+d" (ret) + : "a" (addr) + : "0", "cc"); + return ret; +} /* * Init function for virtio * devices are in a single page above top of "normal" mem @@ -428,21 +448,23 @@ static int __init kvm_devices_init(void) if (!MACHINE_IS_KVM) return -ENODEV; + if (test_devices_support(real_memory_size) < 0) + return -ENODEV; + + rc = vmem_add_mapping(real_memory_size, PAGE_SIZE); + if (rc) + return rc; + + kvm_devices = (void *) real_memory_size; + kvm_root = root_device_register("kvm_s390"); if (IS_ERR(kvm_root)) { rc = PTR_ERR(kvm_root); printk(KERN_ERR "Could not register kvm_s390 root device"); + vmem_remove_mapping(real_memory_size, PAGE_SIZE); return rc; } - rc = vmem_add_mapping(real_memory_size, PAGE_SIZE); - if (rc) { - root_device_unregister(kvm_root); - return rc; - } - - kvm_devices = (void *) real_memory_size; - INIT_WORK(&hotplug_work, hotplug_devices); service_subclass_irq_register(); From e3aa5ed471454f36e99b8d3a960746eb58c07180 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 25 Jan 2013 15:34:15 +0100 Subject: [PATCH 2187/2357] s390/kvm: Fix store status for ACRS/FPRS commit 15bc8d8457875f495c59d933b05770ba88d1eacb upstream. On store status we need to copy the current state of registers into a save area. Currently we might save stale versions: The sie state descriptor doesnt have fields for guest ACRS,FPRS, those registers are simply stored in the host registers. The host program must copy these away if needed. We do that in vcpu_put/load. If we now do a store status in KVM code between vcpu_put/load, the saved values are not up-to-date. Lets collect the ACRS/FPRS before saving them. This also fixes some strange problems with hotplug and virtio-ccw, since the low level machine check handler (on hotplug a machine check will happen) will revalidate all registers with the content of the save area. Signed-off-by: Christian Borntraeger Signed-off-by: Gleb Natapov Signed-off-by: Greg Kroah-Hartman --- arch/s390/kvm/kvm-s390.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 217ce44395a..e00accf9523 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -677,6 +677,14 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) } else prefix = 0; + /* + * The guest FPRS and ACRS are in the host FPRS/ACRS due to the lazy + * copying in vcpu load/put. Lets update our copies before we save + * it into the save area + */ + save_fp_regs(&vcpu->arch.guest_fpregs); + save_access_regs(vcpu->run->s.regs.acrs); + if (__guestcopy(vcpu, addr + offsetof(struct save_area, fp_regs), vcpu->arch.guest_fpregs.fprs, 128, prefix)) return -EFAULT; From 803437207a3e6fef7791adeb7a0c2adb4b012459 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 18 Feb 2013 09:52:08 +0100 Subject: [PATCH 2188/2357] futex: Revert "futex: Mark get_robust_list as deprecated" commit fe2b05f7ca9f906be61dced5489f63b8b4d7c770 upstream. This reverts commit ec0c4274e33c0373e476b73e01995c53128f1257. get_robust_list() is in use and a removal would break existing user space. With the permission checks in place it's not longer a security hole. Remove the deprecation warnings. Signed-off-by: Thomas Gleixner Cc: Cyrill Gorcunov Cc: Richard Weinberger Cc: akpm@linux-foundation.org Cc: paul.gortmaker@windriver.com Cc: davej@redhat.com Cc: keescook@chromium.org Cc: ebiederm@xmission.com Signed-off-by: Greg Kroah-Hartman --- kernel/futex.c | 2 -- kernel/futex_compat.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 19eb089ca00..887943044d4 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2471,8 +2471,6 @@ SYSCALL_DEFINE3(get_robust_list, int, pid, if (!futex_cmpxchg_enabled) return -ENOSYS; - WARN_ONCE(1, "deprecated: get_robust_list will be deleted in 2013.\n"); - rcu_read_lock(); ret = -ESRCH; diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index 83e368b005f..a9642d52863 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -142,8 +142,6 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, if (!futex_cmpxchg_enabled) return -ENOSYS; - WARN_ONCE(1, "deprecated: get_robust_list will be deleted in 2013.\n"); - rcu_read_lock(); ret = -ESRCH; From 0b7fba4034da2a6dd6ebb994ad9f592939a752cf Mon Sep 17 00:00:00 2001 From: Jim Somerville Date: Thu, 21 Feb 2013 16:41:59 -0800 Subject: [PATCH 2189/2357] inotify: remove broken mask checks causing unmount to be EINVAL commit 676a0675cf9200ac047fb50825f80867b3bb733b upstream. Running the command: inotifywait -e unmount /mnt/disk immediately aborts with a -EINVAL return code. This is however a valid parameter. This abort occurs only if unmount is the sole event parameter. If other event parameters are supplied, then the unmount event wait will work. The problem was introduced by commit 44b350fc23e ("inotify: Fix mask checks"). In that commit, it states: The mask checks in inotify_update_existing_watch() and inotify_new_watch() are useless because inotify_arg_to_mask() sets FS_IN_IGNORED and FS_EVENT_ON_CHILD bits anyway. But instead of removing the useless checks, it did this: mask = inotify_arg_to_mask(arg); - if (unlikely(!mask)) + if (unlikely(!(mask & IN_ALL_EVENTS))) return -EINVAL; The problem is that IN_ALL_EVENTS doesn't include IN_UNMOUNT, and other parts of the code keep IN_UNMOUNT separate from IN_ALL_EVENTS. So the check should be: if (unlikely(!(mask & (IN_ALL_EVENTS | IN_UNMOUNT)))) But inotify_arg_to_mask(arg) always sets the IN_UNMOUNT bit in the mask anyway, so the check is always going to pass and thus should simply be removed. Also note that inotify_arg_to_mask completely controls what mask bits get set from arg, there's no way for invalid bits to get enabled there. Lets fix it by simply removing the useless broken checks. Signed-off-by: Jim Somerville Signed-off-by: Paul Gortmaker Cc: Jerome Marchand Cc: John McCutchan Cc: Robert Love Cc: Eric Paris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/notify/inotify/inotify_user.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 8445fbc8985..6f292dd53c6 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -579,8 +579,6 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, /* don't allow invalid bits: we don't want flags set */ mask = inotify_arg_to_mask(arg); - if (unlikely(!(mask & IN_ALL_EVENTS))) - return -EINVAL; fsn_mark = fsnotify_find_inode_mark(group, inode); if (!fsn_mark) @@ -632,8 +630,6 @@ static int inotify_new_watch(struct fsnotify_group *group, /* don't allow invalid bits: we don't want flags set */ mask = inotify_arg_to_mask(arg); - if (unlikely(!(mask & IN_ALL_EVENTS))) - return -EINVAL; tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL); if (unlikely(!tmp_i_mark)) From 9fd4e539ed0737be165fc633063885a477ac556a Mon Sep 17 00:00:00 2001 From: MITSUNARI Shigeo Date: Thu, 21 Feb 2013 16:42:01 -0800 Subject: [PATCH 2190/2357] fs/block_dev.c: page cache wrongly left invalidated after revalidate_disk() commit 7630b661da330b35dd57b6f5d6d62b386f2dd751 upstream. We found that bdev->bd_invalidated was left set once revalidate_disk() is called, which results in page cache flush every time that device is open. Specifically, we found this problem in MD block device. Once we resize a MD device, mdadm --monitor periodically flush all page cache for that device every 60 or 1000 seconds when it opens the device. This bug lies since at least 3.2.0 till the latest kernel(3.6.2). Patch is attached. The following steps will reproduce the problem. 1. prepair a block device (eg /dev/sdb). 2. create two partitions: sudo parted /dev/sdb mklabel gpt mkpart primary 0% 50% mkpart primary 50% 100% 3. create a md device. sudo mdadm -C /dev/md/hoge -l 1 -n 2 -e 1.2 --assume-clean --auto=md --symlink=no /dev/sdb1 /dev/sdb2 4. create file system and mount it sudo mkfs.ext3 /dev/md/hoge sudo mkdir /mnt/test sudo mount /dev/md/hoge /mnt/test 5. try to resize the device sudo mdadm -G /dev/md/hoge --size=max 6. create a file to fill file cache. sudo dd if=/dev/urandom of=/mnt/test/data bs=1M count=10 and verify the current status of file by free command. 7. mdadm monitor will open the md device every 1000 seconds and you will find all file cache on the device are cleared. The timing can be reduced by the following steps. a) kill mdadm and restart it with --delay option /sbin/mdadm --monitor --delay=30 --pid-file /var/run/mdadm/monitor.pid --daemonise --scan --syslog or open the md device directly. sudo dd if=/dev/md/hoge of=/dev/null bs=4096 count=1 Signed-off-by: MITSUNARI Shigeo Cc: Al Viro Cc: Jeff Moyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/block_dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/block_dev.c b/fs/block_dev.c index ba11c30f302..b3be92c980e 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1047,6 +1047,7 @@ int revalidate_disk(struct gendisk *disk) mutex_lock(&bdev->bd_mutex); check_disk_size_change(disk, bdev); + bdev->bd_invalidated = 0; mutex_unlock(&bdev->bd_mutex); bdput(bdev); return ret; From cd336937712589aff73931ed84c2bc56d0574a3c Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Thu, 21 Feb 2013 16:42:45 -0800 Subject: [PATCH 2191/2357] ocfs2: unlock super lock if lockres refresh failed commit 3278bb748d2437eb1464765f36429e5d6aa91c38 upstream. If lockres refresh failed, the super lock will never be released which will cause some processes on other cluster nodes hung forever. Signed-off-by: Junxiao Bi Cc: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/dlmglue.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 81a4cd22f80..231eab2b2d0 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -2545,6 +2545,7 @@ int ocfs2_super_lock(struct ocfs2_super *osb, * everything is up to the caller :) */ status = ocfs2_should_refresh_lock_res(lockres); if (status < 0) { + ocfs2_cluster_unlock(osb, lockres, level); mlog_errno(status); goto bail; } @@ -2553,8 +2554,10 @@ int ocfs2_super_lock(struct ocfs2_super *osb, ocfs2_complete_lock_res_refresh(lockres, status); - if (status < 0) + if (status < 0) { + ocfs2_cluster_unlock(osb, lockres, level); mlog_errno(status); + } ocfs2_track_lock_refresh(lockres); } bail: From 3b6e03c9ac4d57ccb03737a997069dc7ab65601c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 21 Feb 2013 16:44:04 -0800 Subject: [PATCH 2192/2357] drivers/video/backlight/adp88?0_bl.c: fix resume commit 5eb02c01bd1f3ef195989ab05e835e2b0711b5a9 upstream. Clearing the NSTBY bit in the control register also automatically clears the BLEN bit. So we need to make sure to set it again during resume, otherwise the backlight will stay off. Signed-off-by: Lars-Peter Clausen Acked-by: Michael Hennerich Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/video/backlight/adp8860_bl.c | 2 +- drivers/video/backlight/adp8870_bl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 550dbf0bb89..feda482d4af 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -791,7 +791,7 @@ static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message) static int adp8860_i2c_resume(struct i2c_client *client) { - adp8860_set_bits(client, ADP8860_MDCR, NSTBY); + adp8860_set_bits(client, ADP8860_MDCR, NSTBY | BLEN); return 0; } diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 9be58c6f18f..c7a2c35abdd 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -965,7 +965,7 @@ static int adp8870_i2c_suspend(struct i2c_client *client, pm_message_t message) static int adp8870_i2c_resume(struct i2c_client *client) { - adp8870_set_bits(client, ADP8870_MDCR, NSTBY); + adp8870_set_bits(client, ADP8870_MDCR, NSTBY | BLEN); return 0; } From 06c7976c91566d676766ad57b574757f6d0abd02 Mon Sep 17 00:00:00 2001 From: Greg Thelen Date: Fri, 22 Feb 2013 16:36:01 -0800 Subject: [PATCH 2193/2357] tmpfs: fix use-after-free of mempolicy object commit 5f00110f7273f9ff04ac69a5f85bb535a4fd0987 upstream. The tmpfs remount logic preserves filesystem mempolicy if the mpol=M option is not specified in the remount request. A new policy can be specified if mpol=M is given. Before this patch remounting an mpol bound tmpfs without specifying mpol= mount option in the remount request would set the filesystem's mempolicy object to a freed mempolicy object. To reproduce the problem boot a DEBUG_PAGEALLOC kernel and run: # mkdir /tmp/x # mount -t tmpfs -o size=100M,mpol=interleave nodev /tmp/x # grep /tmp/x /proc/mounts nodev /tmp/x tmpfs rw,relatime,size=102400k,mpol=interleave:0-3 0 0 # mount -o remount,size=200M nodev /tmp/x # grep /tmp/x /proc/mounts nodev /tmp/x tmpfs rw,relatime,size=204800k,mpol=??? 0 0 # note ? garbage in mpol=... output above # dd if=/dev/zero of=/tmp/x/f count=1 # panic here Panic: BUG: unable to handle kernel NULL pointer dereference at (null) IP: [< (null)>] (null) [...] Oops: 0010 [#1] SMP DEBUG_PAGEALLOC Call Trace: mpol_shared_policy_init+0xa5/0x160 shmem_get_inode+0x209/0x270 shmem_mknod+0x3e/0xf0 shmem_create+0x18/0x20 vfs_create+0xb5/0x130 do_last+0x9a1/0xea0 path_openat+0xb3/0x4d0 do_filp_open+0x42/0xa0 do_sys_open+0xfe/0x1e0 compat_sys_open+0x1b/0x20 cstar_dispatch+0x7/0x1f Non-debug kernels will not crash immediately because referencing the dangling mpol will not cause a fault. Instead the filesystem will reference a freed mempolicy object, which will cause unpredictable behavior. The problem boils down to a dropped mpol reference below if shmem_parse_options() does not allocate a new mpol: config = *sbinfo shmem_parse_options(data, &config, true) mpol_put(sbinfo->mpol) sbinfo->mpol = config.mpol /* BUG: saves unreferenced mpol */ This patch avoids the crash by not releasing the mempolicy if shmem_parse_options() doesn't create a new mpol. How far back does this issue go? I see it in both 2.6.36 and 3.3. I did not look back further. Signed-off-by: Greg Thelen Acked-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/shmem.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index a409bd81781..58c4a477be6 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2177,6 +2177,7 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) unsigned long inodes; int error = -EINVAL; + config.mpol = NULL; if (shmem_parse_options(data, &config, true)) return error; @@ -2201,8 +2202,13 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) sbinfo->max_inodes = config.max_inodes; sbinfo->free_inodes = config.max_inodes - inodes; - mpol_put(sbinfo->mpol); - sbinfo->mpol = config.mpol; /* transfers initial ref */ + /* + * Preserve previous mempolicy unless mpol remount option was specified. + */ + if (config.mpol) { + mpol_put(sbinfo->mpol); + sbinfo->mpol = config.mpol; /* transfers initial ref */ + } out: spin_unlock(&sbinfo->stat_lock); return error; From f4ce5b3f263c05e7af66fa4eba7c4eb8e1b006bf Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Fri, 22 Feb 2013 16:35:59 -0800 Subject: [PATCH 2194/2357] mm/fadvise.c: drain all pagevecs if POSIX_FADV_DONTNEED fails to discard all pages commit 67d46b296a1ba1477c0df8ff3bc5e0167a0b0732 upstream. Rob van der Heij reported the following (paraphrased) on private mail. The scenario is that I want to avoid backups to fill up the page cache and purge stuff that is more likely to be used again (this is with s390x Linux on z/VM, so I don't give it as much memory that we don't care anymore). So I have something with LD_PRELOAD that intercepts the close() call (from tar, in this case) and issues a posix_fadvise() just before closing the file. This mostly works, except for small files (less than 14 pages) that remains in page cache after the face. Unfortunately Rob has not had a chance to test this exact patch but the test program below should be reproducing the problem he described. The issue is the per-cpu pagevecs for LRU additions. If the pages are added by one CPU but fadvise() is called on another then the pages remain resident as the invalidate_mapping_pages() only drains the local pagevecs via its call to pagevec_release(). The user-visible effect is that a program that uses fadvise() properly is not obeyed. A possible fix for this is to put the necessary smarts into invalidate_mapping_pages() to globally drain the LRU pagevecs if a pagevec page could not be discarded. The downside with this is that an inode cache shrink would send a global IPI and memory pressure potentially causing global IPI storms is very undesirable. Instead, this patch adds a check during fadvise(POSIX_FADV_DONTNEED) to check if invalidate_mapping_pages() discarded all the requested pages. If a subset of pages are discarded it drains the LRU pagevecs and tries again. If the second attempt fails, it assumes it is due to the pages being mapped, locked or dirty and does not care. With this patch, an application using fadvise() correctly will be obeyed but there is a downside that a malicious application can force the kernel to send global IPIs and increase overhead. If accepted, I would like this to be considered as a -stable candidate. It's not an urgent issue but it's a system call that is not working as advertised which is weak. The following test program demonstrates the problem. It should never report that pages are still resident but will without this patch. It assumes that CPU 0 and 1 exist. int main() { int fd; int pagesize = getpagesize(); ssize_t written = 0, expected; char *buf; unsigned char *vec; int resident, i; cpu_set_t set; /* Prepare a buffer for writing */ expected = FILESIZE_PAGES * pagesize; buf = malloc(expected + 1); if (buf == NULL) { printf("ENOMEM\n"); exit(EXIT_FAILURE); } buf[expected] = 0; memset(buf, 'a', expected); /* Prepare the mincore vec */ vec = malloc(FILESIZE_PAGES); if (vec == NULL) { printf("ENOMEM\n"); exit(EXIT_FAILURE); } /* Bind ourselves to CPU 0 */ CPU_ZERO(&set); CPU_SET(0, &set); if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) { perror("sched_setaffinity"); exit(EXIT_FAILURE); } /* open file, unlink and write buffer */ fd = open("fadvise-test-file", O_CREAT|O_EXCL|O_RDWR); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } unlink("fadvise-test-file"); while (written < expected) { ssize_t this_write; this_write = write(fd, buf + written, expected - written); if (this_write == -1) { perror("write"); exit(EXIT_FAILURE); } written += this_write; } free(buf); /* * Force ourselves to another CPU. If fadvise only flushes the local * CPUs pagevecs then the fadvise will fail to discard all file pages */ CPU_ZERO(&set); CPU_SET(1, &set); if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) { perror("sched_setaffinity"); exit(EXIT_FAILURE); } /* sync and fadvise to discard the page cache */ fsync(fd); if (posix_fadvise(fd, 0, expected, POSIX_FADV_DONTNEED) == -1) { perror("posix_fadvise"); exit(EXIT_FAILURE); } /* map the file and use mincore to see which parts of it are resident */ buf = mmap(NULL, expected, PROT_READ, MAP_SHARED, fd, 0); if (buf == NULL) { perror("mmap"); exit(EXIT_FAILURE); } if (mincore(buf, expected, vec) == -1) { perror("mincore"); exit(EXIT_FAILURE); } /* Check residency */ for (i = 0, resident = 0; i < FILESIZE_PAGES; i++) { if (vec[i]) resident++; } if (resident != 0) { printf("Nr unexpected pages resident: %d\n", resident); exit(EXIT_FAILURE); } munmap(buf, expected); close(fd); free(vec); exit(EXIT_SUCCESS); } Signed-off-by: Mel Gorman Reported-by: Rob van der Heij Tested-by: Rob van der Heij Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/fadvise.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/mm/fadvise.c b/mm/fadvise.c index 469491e0af7..dcb98722a22 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -124,9 +125,22 @@ SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice) start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT; end_index = (endbyte >> PAGE_CACHE_SHIFT); - if (end_index >= start_index) - invalidate_mapping_pages(mapping, start_index, + if (end_index >= start_index) { + unsigned long count = invalidate_mapping_pages(mapping, + start_index, end_index); + + /* + * If fewer pages were invalidated than expected then + * it is possible that some of the pages were on + * a per-cpu pagevec for a remote CPU. Drain all + * pagevecs and try again. + */ + if (count < (end_index - start_index + 1)) { + lru_add_drain_all(); + invalidate_mapping_pages(mapping, start_index, end_index); + } + } break; default: ret = -EINVAL; From 38bc0fe99edd35ef738800167c67055f8ca7e476 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 14 Feb 2013 18:14:27 +0000 Subject: [PATCH 2195/2357] drivercore: Fix ordering between deferred_probe and exiting initcalls commit d72cca1eee5b26e313da2a380d4862924e271031 upstream. One of the side effects of deferred probe is that some drivers which used to be probed before initcalls completed are now happening slightly later. This causes two problems. - If a console driver gets deferred, then it may not be ready when userspace starts. For example, if a uart depends on pinctrl, then the uart will get deferred and /dev/console will not be available - __init sections will be discarded before built-in drivers are probed. Strictly speaking, __init functions should not be called in a drivers __probe path, but there are a lot of drivers (console stuff again) that do anyway. In the past it was perfectly safe to do so because all built-in drivers got probed before the end of initcalls. This patch fixes the problem by forcing the first pass of the deferred list to complete at late_initcall time. This is late enough to catch the drivers that are known to have the above issues. Signed-off-by: Grant Likely Tested-by: Haojian Zhuang Cc: Arnd Bergmann Cc: Russell King Cc: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 1b1cbb571d3..97fc774e6bc 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -160,6 +160,8 @@ static int deferred_probe_initcall(void) driver_deferred_probe_enable = true; driver_deferred_probe_trigger(); + /* Sort as many dependencies as possible before exiting initcalls */ + flush_workqueue(deferred_wq); return 0; } late_initcall(deferred_probe_initcall); From 8e0ed8259d2016543b07a43896bc6f4b7f541e42 Mon Sep 17 00:00:00 2001 From: fanchaoting Date: Mon, 4 Feb 2013 21:15:02 +0800 Subject: [PATCH 2196/2357] umount oops when remove blocklayoutdriver first commit 5a12cca697aca5dfba42a7d4c3356acc0445a2b0 upstream. now pnfs client uses block layout, maybe we can remove blocklayoutdriver first. if we umount later, it can cause oops in unset_pnfs_layoutdriver. because nfss->pnfs_curr_ld->clear_layoutdriver is invalid. reproduce it: modprobe blocklayoutdriver mount -t nfs4 -o minorversion=1 pnfsip:/ /mnt/ rmmod blocklayoutdriver umount /mnt then you can see following CPU 0 Pid: 17023, comm: umount.nfs4 Tainted: GF O 3.7.0-rc6-pnfs #1 VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform RIP: 0010:[] [] unset_pnfs_layoutdriver+0x1d/0x70 [nfsv4] RSP: 0018:ffff8800022d9e48 EFLAGS: 00010286 RAX: ffffffffa04a1b00 RBX: ffff88000b013800 RCX: 0000000000000001 RDX: ffffffff81ae8ee0 RSI: ffff880001ee94b8 RDI: ffff88000b013800 RBP: ffff8800022d9e58 R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: ffff880001ee9400 R13: ffff8800105978c0 R14: 00007fff25846c08 R15: 0000000001bba550 FS: 00007f45ae7f0700(0000) GS:ffff880012c00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: ffffffffa04a1b38 CR3: 0000000002c0c000 CR4: 00000000000006f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process umount.nfs4 (pid: 17023, threadinfo ffff8800022d8000, task ffff880006e48aa0) Stack: ffff8800105978c0 ffff88000b013800 ffff8800022d9e78 ffffffffa04cd0ce ffff8800022d9e78 ffff88000b013800 ffff8800022d9ea8 ffffffffa04755a7 ffff8800022d9ea8 ffff880002f96400 ffff88000b013800 ffff880002f96400 Call Trace: [] nfs4_destroy_server+0x1e/0x30 [nfsv4] [] nfs_free_server+0xb7/0x150 [nfs] [] nfs_kill_super+0x35/0x40 [nfs] [] deactivate_locked_super+0x45/0x70 [] deactivate_super+0x4a/0x70 [] mntput_no_expire+0xd2/0x130 [] sys_umount+0x72/0xe0 [] system_call_fastpath+0x16/0x1b Code: 06 e1 b8 ea ff ff ff eb 9e 0f 1f 44 00 00 55 48 89 e5 53 48 83 ec 08 66 66 66 66 90 48 8b 87 80 03 00 00 48 89 fb 48 85 c0 74 29 <48> 8b 40 38 48 85 c0 74 02 ff d0 48 8b 03 3e ff 48 04 0f 94 c2 RIP [] unset_pnfs_layoutdriver+0x1d/0x70 [nfsv4] RSP CR2: ffffffffa04a1b38 ---[ end trace 29f75aaedda058bf ]--- Signed-off-by: fanchaoting Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/blocklayout/blocklayout.c | 1 + fs/nfs/objlayout/objio_osd.c | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index d16dae2a9b2..3a9c2470e4f 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -1155,6 +1155,7 @@ static const struct nfs_pageio_ops bl_pg_write_ops = { static struct pnfs_layoutdriver_type blocklayout_type = { .id = LAYOUT_BLOCK_VOLUME, .name = "LAYOUT_BLOCK_VOLUME", + .owner = THIS_MODULE, .read_pagelist = bl_read_pagelist, .write_pagelist = bl_write_pagelist, .alloc_layout_hdr = bl_alloc_layout_hdr, diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index 1afe74c42c8..65538f569f4 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c @@ -589,6 +589,7 @@ static struct pnfs_layoutdriver_type objlayout_type = { .flags = PNFS_LAYOUTRET_ON_SETATTR | PNFS_LAYOUTRET_ON_ERROR, + .owner = THIS_MODULE, .alloc_layout_hdr = objlayout_alloc_layout_hdr, .free_layout_hdr = objlayout_free_layout_hdr, From 92a5267ac37e74cf44675f5992fc6fa4ad694a04 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 19 Feb 2013 12:04:42 -0500 Subject: [PATCH 2197/2357] NLM: Ensure that we resend all pending blocking locks after a reclaim commit 666b3d803a511fbc9bc5e5ea8ce66010cf03ea13 upstream. Currently, nlmclnt_lock will break out of the for(;;) loop when the reclaimer wakes up the blocking lock thread by setting nlm_lck_denied_grace_period. This causes the lock request to fail with an ENOLCK error. The intention was always to ensure that we resend the lock request after the grace period has expired. Reported-by: Wangyuan Zhang Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/lockd/clntproc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 8392cb85bd5..a3a09877ea6 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -551,6 +551,9 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); if (status < 0) break; + /* Resend the blocking lock request after a server reboot */ + if (resp->status == nlm_lck_denied_grace_period) + continue; if (resp->status != nlm_lck_blocked) break; } From a8fb02fe99203fea52046151817672102124d389 Mon Sep 17 00:00:00 2001 From: Tomasz Guszkowski Date: Tue, 5 Feb 2013 22:10:31 +0100 Subject: [PATCH 2198/2357] p54usb: corrected USB ID for T-Com Sinus 154 data II commit 008e33f733ca51acb2dd9d88ea878693b04d1d2a upstream. Corrected USB ID for T-Com Sinus 154 data II. ISL3887-based. The device was tested in managed mode with no security, WEP 128 bit and WPA-PSK (TKIP) with firmware 2.13.1.0.lm87.arm (md5sum: 7d676323ac60d6e1a3b6d61e8c528248). It works. Signed-off-by: Tomasz Guszkowski Acked-By: Christian Lamparter Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/p54/p54usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index be20cf765bc..af30777ce31 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -84,8 +84,8 @@ static struct usb_device_id p54u_table[] = { {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */ - {USB_DEVICE(0x083a, 0x4503)}, /* T-Com Sinus 154 data II */ {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ + {USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */ {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */ {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */ {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ From e3fc3cb2a03623b48250dd3a12378a42d276f20e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 31 Jan 2013 21:14:33 +0100 Subject: [PATCH 2199/2357] ALSA: usb-audio: fix Roland A-PRO support commit 7da58046482fceb17c4a0d4afefd9507ec56de7f upstream. The quirk for the Roland/Cakewalk A-PRO keyboards accidentally used the wrong interface number, which prevented the driver from attaching to the device. Signed-off-by: Clemens Ladisch Signed-off-by: Greg Kroah-Hartman --- sound/usb/quirks-table.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 63128cd6254..fa4c2f7e6ab 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1658,7 +1658,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "Roland", */ /* .product_name = "A-PRO", */ - .ifnum = 1, + .ifnum = 0, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = & (const struct snd_usb_midi_endpoint_info) { .out_cables = 0x0003, From e32afc122e3a808944a9f7af5612bf2a3cbea89a Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Thu, 21 Feb 2013 01:55:50 +0000 Subject: [PATCH 2200/2357] ALSA: usb: Fix Processing Unit Descriptor parsers commit b531f81b0d70ffbe8d70500512483227cc532608 upstream. Commit 99fc86450c439039d2ef88d06b222fd51a779176 "ALSA: usb-mixer: parse descriptors with structs" introduced a set of useful parsers for descriptors. Unfortunately the parses for the Processing Unit Descriptor came with a very subtle bug... Functions uac_processing_unit_iProcessing() and uac_processing_unit_specific() were indexing the baSourceID array forgetting the fields before the iProcessing and process-specific descriptors. The problem was observed with Sound Blaster Extigy mixer, where nNrModes in Up/Down-mix Processing Unit Descriptor was accessed at offset 10 of the descriptor (value 0) instead of offset 15 (value 7). In result the resulting control had interesting limit values: Simple mixer control 'Channel Routing Mode Select',0 Capabilities: volume volume-joined penum Playback channels: Mono Capture channels: Mono Limits: 0 - -1 Mono: -1 [100%] Fixed by starting from the bmControls, which was calculated correctly, instead of baSourceID. Now the mentioned control is fine: Simple mixer control 'Channel Routing Mode Select',0 Capabilities: volume volume-joined penum Playback channels: Mono Capture channels: Mono Limits: 0 - 6 Mono: 0 [0%] Signed-off-by: Pawel Moll Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/audio.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index a54b8255d75..6f8b026b339 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h @@ -384,14 +384,16 @@ static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_de int protocol) { __u8 control_size = uac_processing_unit_bControlSize(desc, protocol); - return desc->baSourceID[desc->bNrInPins + control_size]; + return *(uac_processing_unit_bmControls(desc, protocol) + + control_size); } static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc, int protocol) { __u8 control_size = uac_processing_unit_bControlSize(desc, protocol); - return &desc->baSourceID[desc->bNrInPins + control_size + 1]; + return uac_processing_unit_bmControls(desc, protocol) + + control_size + 1; } /* 4.5.2 Class-Specific AS Interface Descriptor */ From 63b2afe91cef7d844ea07a1ad17be63ded94e8ca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 1 Feb 2013 14:01:27 +0100 Subject: [PATCH 2201/2357] ALSA: hda - Release assigned pin/cvt at error path of hdmi_pcm_open() commit 2ad779b7329d6894a80df94e693e72eaa0d56790 upstream. If the driver detects and invalid ELD, it gives an open error. But it forgot to release the assigned pin, converter and spdif ctls before returning. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_hdmi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d1b805aefa5..f694dd77ad4 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -924,8 +924,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, if (!static_hdmi_pcm && eld->eld_valid) { snd_hdmi_eld_update_pcm_info(eld, hinfo); if (hinfo->channels_min > hinfo->channels_max || - !hinfo->rates || !hinfo->formats) + !hinfo->rates || !hinfo->formats) { + per_cvt->assigned = 0; + hinfo->nid = 0; + snd_hda_spdif_ctls_unassign(codec, pin_idx); return -ENODEV; + } } /* Store the updated parameters */ From 7e8b41d605b06c68a7df890e34cb560d837e87ac Mon Sep 17 00:00:00 2001 From: Fernando Luis Vazquez Cao Date: Tue, 12 Feb 2013 16:47:44 +0900 Subject: [PATCH 2202/2357] ALSA: hda - Workaround for silent output on Sony Vaio VGC-LN51JGB with ALC889 commit 12e31a78c70dc12897fda2489113f445c0e94a18 upstream. Some Vaio all-in-one desktop PCs (for example VGC-LN51JGB) are affected by the same issue that caused Vaio Z laptops to become silent: the speaker pin must be connected to the first DAC even though the codec itself advertises flexible routing through any of the DACs. Use the no-primary-hp fixup for choosing the speaker pin as the primary so that the right DAC is assigned on this device. Signed-off-by: Fernando Luis Vazquez Cao Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f7f877626d8..adb97d6c504 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5440,6 +5440,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), /* All Apple entries are in codec SSIDs */ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), From 652328944e2514cd8306a71a2bbac4896efa49ed Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 19 Feb 2013 16:11:22 +0100 Subject: [PATCH 2203/2357] ALSA: hda - hdmi: ELD shouldn't be valid after unplug commit bbfd8a19b6913f50a362457c34d49bfafe5e456e upstream. Currently, eld_valid is never set to false, except at kernel module load time. This patch makes sure that eld is no longer valid when the cable is (hot-)unplugged. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_hdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index f694dd77ad4..02a6e3f481e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -993,6 +993,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", codec->addr, pin_nid, eld->monitor_present, eld_valid); + eld->eld_valid = false; if (eld_valid) { if (!snd_hdmi_get_eld(eld, codec, pin_nid)) snd_hdmi_show_eld(eld); From 5cf5b734496e73c30f43833138078ee7884ec725 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 14 Feb 2013 11:49:01 -0800 Subject: [PATCH 2204/2357] sunvdc: Fix off-by-one in generic_request(). [ Upstream commit f4d9605434c0fd4cc8639bf25cfc043418c52362 ] The 'operations' bitmap corresponds one-for-one with the operation codes, no adjustment is necessary. Reported-by: Mark Kettenis Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/block/sunvdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 9dcf76a10bb..31dd45177a7 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -461,7 +461,7 @@ static int generic_request(struct vdc_port *port, u8 op, void *buf, int len) int op_len, err; void *req_buf; - if (!(((u64)1 << ((u64)op - 1)) & port->operations)) + if (!(((u64)1 << (u64)op) & port->operations)) return -EOPNOTSUPP; switch (op) { From 746042cf26dbcf5a8feb4f8938a3531a6169c96e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 5 Feb 2013 11:47:09 -0500 Subject: [PATCH 2205/2357] drm/radeon/dce6: fix display powergating commit 0e3d50bfcbd338254795a700dcff429a96cba1a6 upstream. Only enable it when we disable the display rather than at DPMS time since enabling it requires a full modeset to restore the display state. Fixes blank screens in certain cases. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_crtc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 15594a30ebd..ebbfbd20173 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -258,8 +258,6 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) radeon_crtc->enabled = true; /* adjust pm to dpms changes BEFORE enabling crtcs */ radeon_pm_compute_clocks(rdev); - if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) - atombios_powergate_crtc(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); @@ -277,8 +275,6 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); radeon_crtc->enabled = false; - if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) - atombios_powergate_crtc(crtc, ATOM_ENABLE); /* adjust pm to dpms changes AFTER disabling crtcs */ radeon_pm_compute_clocks(rdev); break; @@ -1670,6 +1666,8 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) int i; atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + if (ASIC_IS_DCE6(rdev)) + atombios_powergate_crtc(crtc, ATOM_ENABLE); for (i = 0; i < rdev->num_crtc; i++) { if (rdev->mode_info.crtcs[i] && From b701cf407f9508fb899b482d9224daba2cedec75 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Feb 2013 11:19:15 +1000 Subject: [PATCH 2206/2357] drm/udl: make usage as a console safer commit bcb39af4486be07e896fc374a2336bad3104ae0a upstream. Okay you don't really want to use udl devices as your console, but if you are unlucky enough to do so, you run into a lot of schedule while atomic due to printk being called from all sorts of funky places. So check if we are in an atomic context, and queue the damage for later, the next printk should cause it to appear. This isn't ideal, but it is simple, and seems to work okay in my testing here. (dirty area idea came from xenfb) fixes a bunch of sleeping while atomic issues running fbcon on udl devices. Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_drv.h | 2 ++ drivers/gpu/drm/udl/udl_fb.c | 44 +++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index e7605758661..2b8c4fdda97 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -74,6 +74,8 @@ struct udl_framebuffer { struct drm_framebuffer base; struct udl_gem_object *obj; bool active_16; /* active on the 16-bit channel */ + int x1, y1, x2, y2; /* dirty rect */ + spinlock_t dirty_lock; }; #define to_udl_fb(x) container_of(x, struct udl_framebuffer, base) diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index b9282cf7aea..9fbb2778716 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -153,6 +153,9 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, struct urb *urb; int aligned_x; int bpp = (fb->base.bits_per_pixel / 8); + int x2, y2; + bool store_for_later = false; + unsigned long flags; if (!fb->active_16) return 0; @@ -160,8 +163,6 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, if (!fb->obj->vmapping) udl_gem_vmap(fb->obj); - start_cycles = get_cycles(); - aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long)); width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long)); x = aligned_x; @@ -171,19 +172,53 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, (y + height > fb->base.height)) return -EINVAL; + /* if we are in atomic just store the info + can't test inside spin lock */ + if (in_atomic()) + store_for_later = true; + + x2 = x + width - 1; + y2 = y + height - 1; + + spin_lock_irqsave(&fb->dirty_lock, flags); + + if (fb->y1 < y) + y = fb->y1; + if (fb->y2 > y2) + y2 = fb->y2; + if (fb->x1 < x) + x = fb->x1; + if (fb->x2 > x2) + x2 = fb->x2; + + if (store_for_later) { + fb->x1 = x; + fb->x2 = x2; + fb->y1 = y; + fb->y2 = y2; + spin_unlock_irqrestore(&fb->dirty_lock, flags); + return 0; + } + + fb->x1 = fb->y1 = INT_MAX; + fb->x2 = fb->y2 = 0; + + spin_unlock_irqrestore(&fb->dirty_lock, flags); + start_cycles = get_cycles(); + urb = udl_get_urb(dev); if (!urb) return 0; cmd = urb->transfer_buffer; - for (i = y; i < y + height ; i++) { + for (i = y; i <= y2 ; i++) { const int line_offset = fb->base.pitches[0] * i; const int byte_offset = line_offset + (x * bpp); const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp); if (udl_render_hline(dev, bpp, &urb, (char *) fb->obj->vmapping, &cmd, byte_offset, dev_byte_offset, - width * bpp, + (x2 - x + 1) * bpp, &bytes_identical, &bytes_sent)) goto error; } @@ -408,6 +443,7 @@ udl_framebuffer_init(struct drm_device *dev, { int ret; + spin_lock_init(&ufb->dirty_lock); ufb->obj = obj; ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs); drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd); From ae4c05e0232e869cf2418ac6c0c862bb5287d672 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Feb 2013 12:30:25 +1000 Subject: [PATCH 2207/2357] drm/udl: disable fb_defio by default commit 677d23b70bf949f75746c80cbae92c233c6b5e2a upstream. There seems to be a bad interaction between gem/shmem and defio on top, I get list corruption on the page lru in the shmem code. Turn it off for now until we get some more digging done. Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 9fbb2778716..f02d223d394 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -22,9 +22,9 @@ #include "drm_fb_helper.h" -#define DL_DEFIO_WRITE_DELAY 5 /* fb_deferred_io.delay in jiffies */ +#define DL_DEFIO_WRITE_DELAY (HZ/20) /* fb_deferred_io.delay in jiffies */ -static int fb_defio = 1; /* Optionally enable experimental fb_defio mmap support */ +static int fb_defio = 0; /* Optionally enable experimental fb_defio mmap support */ static int fb_bpp = 16; module_param(fb_bpp, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); From df28f4890263a0540b395402b43b57f047ccf7d5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 24 Jan 2013 14:14:19 +1000 Subject: [PATCH 2208/2357] vgacon/vt: clear buffer attributes when we load a 512 character font (v2) commit 2a2483072393b27f4336ab068a1f48ca19ff1c1e upstream. When we switch from 256->512 byte font rendering mode, it means the current contents of the screen is being reinterpreted. The bit that holds the high bit of the 9-bit font, may have been previously set, and thus the new font misrenders. The problem case we see is grub2 writes spaces with the bit set, so it ends up with data like 0x820, which gets reinterpreted into 0x120 char which the font translates into G with a circumflex. This flashes up on screen at boot and is quite ugly. A current side effect of this patch though is that any rendering on the screen changes color to a slightly darker color, but at least the screen no longer corrupts. v2: as suggested by hpa, always clear the attribute space, whether we are are going to or from 512 chars. Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/video/console/vgacon.c | 22 +++++++++++++++------- include/linux/vt_kern.h | 1 + 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 18d06be8c9b..068abe1524a 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -656,7 +656,7 @@ static inline void save_screen(struct vc_data *vc) * Redrawing of screen */ -static void clear_buffer_attributes(struct vc_data *vc) +void clear_buffer_attributes(struct vc_data *vc) { unsigned short *p = (unsigned short *)vc->vc_origin; int count = vc->vc_screenbuf_size / 2; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d449a74d4a3..5855d17d19a 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1064,7 +1064,7 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) unsigned short video_port_status = vga_video_port_reg + 6; int font_select = 0x00, beg, i; char *charmap; - + bool clear_attribs = false; if (vga_video_type != VIDEO_TYPE_EGAM) { charmap = (char *) VGA_MAP_MEM(colourmap, 0); beg = 0x0e; @@ -1169,12 +1169,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) /* if 512 char mode is already enabled don't re-enable it. */ if ((set) && (ch512 != vga_512_chars)) { - /* attribute controller */ - for (i = 0; i < MAX_NR_CONSOLES; i++) { - struct vc_data *c = vc_cons[i].d; - if (c && c->vc_sw == &vga_con) - c->vc_hi_font_mask = ch512 ? 0x0800 : 0; - } vga_512_chars = ch512; /* 256-char: enable intensity bit 512-char: disable intensity bit */ @@ -1185,8 +1179,22 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) it means, but it works, and it appears necessary */ inb_p(video_port_status); vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0); + clear_attribs = true; } raw_spin_unlock_irq(&vga_lock); + + if (clear_attribs) { + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *c = vc_cons[i].d; + if (c && c->vc_sw == &vga_con) { + /* force hi font mask to 0, so we always clear + the bit on either transition */ + c->vc_hi_font_mask = 0x00; + clear_buffer_attributes(c); + c->vc_hi_font_mask = ch512 ? 0x0800 : 0; + } + } + } return 0; } diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index e33d77f15bd..49e39d4396d 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -47,6 +47,7 @@ int con_set_cmap(unsigned char __user *cmap); int con_get_cmap(unsigned char __user *cmap); void scrollback(struct vc_data *vc, int lines); void scrollfront(struct vc_data *vc, int lines); +void clear_buffer_attributes(struct vc_data *vc); void update_region(struct vc_data *vc, unsigned long start, int count); void redraw_screen(struct vc_data *vc, int is_switch); #define update_screen(x) redraw_screen(x, 0) From 7b480b03691358af771e6104087e05ffecc7d16a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 15 Feb 2013 13:36:27 -0200 Subject: [PATCH 2209/2357] drm: don't add inferred modes for monitors that don't support them commit 196e077dc165a307efbd9e7569f81bbdbcf18f65 upstream. If bit 0 of the features byte (0x18) is set to 0, then, according to the EDID spec, "the display is non-continuous frequency (multi-mode) and is only specified to accept the video timing formats that are listed in Base EDID and certain Extension Blocks". For more information, please see the EDID spec, check the notes of the table that explains the "Feature Support" byte (18h) and also the notes on the tables of the section that explains "Display Range Limits & Additional Timing Description Definition (tag #FDh)". Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=45729 Reviewed-by: Alex Deucher Reviewed-by: Adam Jackson Signed-off-by: Paulo Zanoni Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_edid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9d9835a4fee..384edc67762 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1769,7 +1769,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) num_modes += add_cvt_modes(connector, edid); num_modes += add_standard_modes(connector, edid); num_modes += add_established_modes(connector, edid); - num_modes += add_inferred_modes(connector, edid); + if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) + num_modes += add_inferred_modes(connector, edid); num_modes += add_cea_modes(connector, edid); if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) From d8fe02dde5c0aa474a32fe13d0743be515bb41dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 31 Jan 2013 19:43:37 +0200 Subject: [PATCH 2210/2357] drm: Fill depth/bits_per_pixel for C8 format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c51a6bc5f6d328926a9a4a1247c5030faf190a80 upstream. Set depth/bits_per_pixel to 8 for C8 format. Signed-off-by: Ville Syrjälä Acked-by: Dave Airlie Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_crtc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 4fd363f1656..8320c6bb48d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3409,6 +3409,7 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp) { switch (format) { + case DRM_FORMAT_C8: case DRM_FORMAT_RGB332: case DRM_FORMAT_BGR233: *depth = 8; From d8a5f7fe8d632290ecbb6f692b98136957abe21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 31 Jan 2013 19:43:38 +0200 Subject: [PATCH 2211/2357] drm: Use C8 instead of RGB332 when determining the format from depth/bpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d84f031bd230fdf9c3b7734940c859bf28b90219 upstream. Support for real RGB332 is a rarity, most hardware only really support C8. So use C8 instead of RGB332 when determining the format based on depth/bpp. This fixes 8bpp fbcon on i915, since i915 will only accept C8 and not RGB332. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=59572 Signed-off-by: Ville Syrjälä Acked-by: Dave Airlie Tested-by: mlsemon35@gmail.com Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 8320c6bb48d..c61e6722216 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2023,7 +2023,7 @@ uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) switch (bpp) { case 8: - fmt = DRM_FORMAT_RGB332; + fmt = DRM_FORMAT_C8; break; case 16: if (depth == 15) From 61d40262e55fe00b817fe7e28f0f4dfad6e31fca Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Feb 2013 10:10:04 +1000 Subject: [PATCH 2212/2357] drm/usb: bind driver to correct device commit 9f23de52b64f7fb801fd76f3dd8651a0dc89187b upstream. While looking at plymouth on udl I noticed that plymouth was trying to use its fb plugin not its drm one, it was trying to drmOpen a driver called usb not udl, noticed that we actually had out driver pointing at the wrong device. Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c index 37c9a523dd1..767782a96c3 100644 --- a/drivers/gpu/drm/drm_usb.c +++ b/drivers/gpu/drm/drm_usb.c @@ -18,7 +18,7 @@ int drm_get_usb_dev(struct usb_interface *interface, usbdev = interface_to_usbdev(interface); dev->usbdev = usbdev; - dev->dev = &usbdev->dev; + dev->dev = &interface->dev; mutex_lock(&drm_global_mutex); From bdfb3335569583fd195a3a1a89380d7648a9a85f Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 19 Feb 2013 03:15:14 +0000 Subject: [PATCH 2213/2357] target: Fix divide by zero bug in fabric_max_sectors for unconfigured devices commit 7a3cf6ca1ab2a2f7161c6dec5a787fc7a5de864e upstream This patch fixes a possible divide by zero bug when the fabric_max_sectors device attribute is written and backend se_device failed to be successfully configured -> enabled. Go ahead and use block_size=512 within se_dev_set_fabric_max_sectors() in the event of a target_configure_device() failure case, as no valid dev->dev_attrib.block_size value will have been setup yet. Signed-off-by: Nicholas Bellinger Cc: Herton Ronaldo Krzesinski Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_device.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 26c62f05975..4ecf9d61c22 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1230,6 +1230,8 @@ int se_dev_set_max_sectors(struct se_device *dev, u32 max_sectors) int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors) { + int block_size = dev->se_sub_dev->se_dev_attrib.block_size; + if (atomic_read(&dev->dev_export_obj.obj_access_count)) { pr_err("dev[%p]: Unable to change SE Device" " fabric_max_sectors while dev_export_obj: %d count exists\n", @@ -1267,8 +1269,12 @@ int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors) /* * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks() */ + if (!block_size) { + block_size = 512; + pr_warn("Defaulting to 512 for zero block_size\n"); + } fabric_max_sectors = se_dev_align_max_sectors(fabric_max_sectors, - dev->se_sub_dev->se_dev_attrib.block_size); + block_size); dev->se_sub_dev->se_dev_attrib.fabric_max_sectors = fabric_max_sectors; pr_debug("dev[%p]: SE Device max_sectors changed to %u\n", From df87bd32f94547ecaa586052a6edeb653294a5b4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 21 Jan 2013 19:48:59 +0100 Subject: [PATCH 2214/2357] intel/iommu: force writebuffer-flush quirk on Gen 4 Chipsets commit 210561ffd72d00eccf12c0131b8024d5436bae95 upstream. We already have the quirk entry for the mobile platform, but also reports on some desktop versions. So be paranoid and set it everywhere. References: http://www.mail-archive.com/dri-devel@lists.freedesktop.org/msg33138.html Reported-and-tested-by: Mihai Moldovan Cc: David Woodhouse Cc: "Sankaran, Rajesh" Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-iommu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 5d71873c6f6..17119247ac4 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4212,13 +4212,19 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) { /* * Mobile 4 Series Chipset neglects to set RWBF capability, - * but needs it: + * but needs it. Same seems to hold for the desktop versions. */ printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n"); rwbf_quirk = 1; } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf); #define GGC 0x52 #define GGC_MEMORY_SIZE_MASK (0xf << 8) From 6bdf87562cb048e3e9a76d18e440794830647657 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 8 Feb 2013 16:35:37 +0200 Subject: [PATCH 2215/2357] drm/i915: disable shared panel fitter for pipe commit 24a1f16de97c4cf0029d9acd04be06db32208726 upstream. If encoder is switched off by BIOS, but the panel fitter is left on, we never try to turn off the panel fitter and leave it still attached to the pipe - which can cause blurry output elsewhere. Based on work by Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=58867 Signed-off-by: Mika Kuoppala Tested-by: Andreas Sturmlechner [danvet: Remove the redundant HAS_PCH_SPLIT check and add a tiny comment.] Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3c9b9c57040..6e8d7a75727 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3303,6 +3303,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; + u32 pctl; if (!intel_crtc->active) return; @@ -3318,6 +3319,13 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_disable_plane(dev_priv, plane, pipe); intel_disable_pipe(dev_priv, pipe); + + /* Disable pannel fitter if it is on this pipe. */ + pctl = I915_READ(PFIT_CONTROL); + if ((pctl & PFIT_ENABLE) && + ((pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT) == pipe) + I915_WRITE(PFIT_CONTROL, 0); + intel_disable_pll(dev_priv, pipe); intel_crtc->active = false; From a143ae690fbf24c2473d5c7c42875c29e150bd13 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 13 Feb 2013 22:20:22 +0100 Subject: [PATCH 2216/2357] drm/i915: Set i9xx sdvo clock limits according to specifications commit 4f7dfb6788dd022446847fbbfbe45e13bedb5be2 upstream. The Intel PRM says the M1 and M2 divisors must be in the range of 10-20 and 5-9. Since we do all calculations based on them being register values (which are subtracted by 2) we need to specify them accordingly. Signed-off-by: Patrik Jakobsson Reviewed-by: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=56359 Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6e8d7a75727..67f6db53409 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -142,8 +142,8 @@ static const intel_limit_t intel_limits_i9xx_sdvo = { .vco = { .min = 1400000, .max = 2800000 }, .n = { .min = 1, .max = 6 }, .m = { .min = 70, .max = 120 }, - .m1 = { .min = 10, .max = 22 }, - .m2 = { .min = 5, .max = 9 }, + .m1 = { .min = 8, .max = 18 }, + .m2 = { .min = 3, .max = 7 }, .p = { .min = 5, .max = 80 }, .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 200000, From 59959c9505e28cc7b9ead416cb064b4e56ba7dd5 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 28 Jan 2013 16:14:31 +0000 Subject: [PATCH 2217/2357] staging: comedi: disallow COMEDI_DEVCONFIG on non-board minors commit 754ab5c0e55dd118273ca2c217c4d95e9fbc8259 upstream. Comedi has two sorts of minor devices: (a) normal board minor devices in the range 0 to COMEDI_NUM_BOARD_MINORS-1 inclusive; and (b) special subdevice minor devices in the range COMEDI_NUM_BOARD_MINORS upwards that are used to open the same underlying comedi device as the normal board minor devices, but with non-default read and write subdevices for asynchronous commands. The special subdevice minor devices get created when a board supporting asynchronous commands is attached to a normal board minor device, and destroyed when the board is detached from the normal board minor device. One way to attach or detach a board is by using the COMEDI_DEVCONFIG ioctl. This should only be used on normal board minors as the special subdevice minors are too ephemeral. In particular, the change introduced in commit 7d3135af399e92cf4c9bbc5f86b6c140aab3b88c ("staging: comedi: prevent auto-unconfig of manually configured devices") breaks horribly for special subdevice minor devices. Since there's no legitimate use for the COMEDI_DEVCONFIG ioctl on a special subdevice minor device node, disallow it and return -ENOTTY. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index b67c1070df7..cf67ce54f46 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -136,6 +136,11 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, /* Device config is special, because it must work on * an unconfigured device. */ if (cmd == COMEDI_DEVCONFIG) { + if (minor >= COMEDI_NUM_BOARD_MINORS) { + /* Device config not appropriate on non-board minors. */ + rc = -ENOTTY; + goto done; + } rc = do_devconfig_ioctl(dev, (struct comedi_devconfig __user *)arg); if (rc == 0) From 4aee4099c7309d0610cf857d9d02d27ebfeb1b95 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 30 Jan 2013 20:07:29 +0000 Subject: [PATCH 2218/2357] staging: vt6656: Fix URB submitted while active warning. commit ae5943de8c8c4438cbac5cda599ff0b88c224468 upstream. This error happens because PIPEnsControlOut and PIPEnsControlIn unlock the spin lock for delay, letting in another thread. The patch moves the current MP_SET_FLAG to before filling of sUsbCtlRequest for pControlURB and clears it in event of failing. Any thread calling either function while fMP_CONTROL_READS or fMP_CONTROL_WRITES flags set will return STATUS_FAILURE. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/usbpipe.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c index c612ab58f38..f759352a268 100644 --- a/drivers/staging/vt6656/usbpipe.c +++ b/drivers/staging/vt6656/usbpipe.c @@ -168,6 +168,11 @@ int PIPEnsControlOut( if (pDevice->Flags & fMP_CONTROL_WRITES) return STATUS_FAILURE; + if (pDevice->Flags & fMP_CONTROL_READS) + return STATUS_FAILURE; + + MP_SET_FLAG(pDevice, fMP_CONTROL_WRITES); + pDevice->sUsbCtlRequest.bRequestType = 0x40; pDevice->sUsbCtlRequest.bRequest = byRequest; pDevice->sUsbCtlRequest.wValue = cpu_to_le16p(&wValue); @@ -182,12 +187,13 @@ int PIPEnsControlOut( ntStatus = usb_submit_urb(pDevice->pControlURB, GFP_ATOMIC); if (ntStatus != 0) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"control send request submission failed: %d\n", ntStatus); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "control send request submission failed: %d\n", + ntStatus); + MP_CLEAR_FLAG(pDevice, fMP_CONTROL_WRITES); return STATUS_FAILURE; } - else { - MP_SET_FLAG(pDevice, fMP_CONTROL_WRITES); - } + spin_unlock_irq(&pDevice->lock); for (ii = 0; ii <= USB_CTL_WAIT; ii ++) { @@ -227,6 +233,11 @@ int PIPEnsControlIn( if (pDevice->Flags & fMP_CONTROL_READS) return STATUS_FAILURE; + if (pDevice->Flags & fMP_CONTROL_WRITES) + return STATUS_FAILURE; + + MP_SET_FLAG(pDevice, fMP_CONTROL_READS); + pDevice->sUsbCtlRequest.bRequestType = 0xC0; pDevice->sUsbCtlRequest.bRequest = byRequest; pDevice->sUsbCtlRequest.wValue = cpu_to_le16p(&wValue); @@ -240,10 +251,11 @@ int PIPEnsControlIn( ntStatus = usb_submit_urb(pDevice->pControlURB, GFP_ATOMIC); if (ntStatus != 0) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"control request submission failed: %d\n", ntStatus); - }else { - MP_SET_FLAG(pDevice, fMP_CONTROL_READS); - } + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "control request submission failed: %d\n", ntStatus); + MP_CLEAR_FLAG(pDevice, fMP_CONTROL_READS); + return STATUS_FAILURE; + } spin_unlock_irq(&pDevice->lock); for (ii = 0; ii <= USB_CTL_WAIT; ii ++) { From 03e578b9213094935c692d5728229cc8c0df0fd6 Mon Sep 17 00:00:00 2001 From: Chris Rattray Date: Fri, 1 Feb 2013 15:51:41 +0000 Subject: [PATCH 2219/2357] ASoC: wm2200: correct IN2L and IN3L digital mute commit 0d2b6422529a26ac4dee06196524ba9da70cf735 upstream. Signed-off-by: Chris Rattray Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm2200.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 8e0cf146a68..9932aacaa5b 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -990,9 +990,9 @@ SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL, SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L, WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1), -SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L, +SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_2L, WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1), -SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L, +SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_3L, WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1), SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L, From 76753d39bf46abf7e37df89e2258bef933bb2207 Mon Sep 17 00:00:00 2001 From: Igor Grinberg Date: Sun, 13 Jan 2013 13:49:47 +0200 Subject: [PATCH 2220/2357] ARM: PXA3xx: program the CSMSADRCFG register commit d107a204154ddd79339203c2deeb7433f0cf6777 upstream. The Chip Select Configuration Register must be programmed to 0x2 in order to achieve the correct behavior of the Static Memory Controller. Without this patch devices wired to DFI and accessed through SMC cannot be accessed after resume from S2. Do not rely on the boot loader to program the CSMSADRCFG register by programming it in the kernel smemc module. Signed-off-by: Igor Grinberg Acked-by: Eric Miao Signed-off-by: Haojian Zhuang Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-pxa/include/mach/smemc.h | 1 + arch/arm/mach-pxa/smemc.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-pxa/include/mach/smemc.h b/arch/arm/mach-pxa/include/mach/smemc.h index b7de471b273..b802f285fe0 100644 --- a/arch/arm/mach-pxa/include/mach/smemc.h +++ b/arch/arm/mach-pxa/include/mach/smemc.h @@ -37,6 +37,7 @@ #define CSADRCFG1 (SMEMC_VIRT + 0x84) /* Address Configuration Register for CS1 */ #define CSADRCFG2 (SMEMC_VIRT + 0x88) /* Address Configuration Register for CS2 */ #define CSADRCFG3 (SMEMC_VIRT + 0x8C) /* Address Configuration Register for CS3 */ +#define CSMSADRCFG (SMEMC_VIRT + 0xA0) /* Chip Select Configuration Register */ /* * More handy macros for PCMCIA diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c index 79923058d10..f38aa890b2c 100644 --- a/arch/arm/mach-pxa/smemc.c +++ b/arch/arm/mach-pxa/smemc.c @@ -40,6 +40,8 @@ static void pxa3xx_smemc_resume(void) __raw_writel(csadrcfg[1], CSADRCFG1); __raw_writel(csadrcfg[2], CSADRCFG2); __raw_writel(csadrcfg[3], CSADRCFG3); + /* CSMSADRCFG wakes up in its default state (0), so we need to set it */ + __raw_writel(0x2, CSMSADRCFG); } static struct syscore_ops smemc_syscore_ops = { @@ -49,8 +51,19 @@ static struct syscore_ops smemc_syscore_ops = { static int __init smemc_init(void) { - if (cpu_is_pxa3xx()) + if (cpu_is_pxa3xx()) { + /* + * The only documentation we have on the + * Chip Select Configuration Register (CSMSADRCFG) is that + * it must be programmed to 0x2. + * Moreover, in the bit definitions, the second bit + * (CSMSADRCFG[1]) is called "SETALWAYS". + * Other bits are reserved in this register. + */ + __raw_writel(0x2, CSMSADRCFG); + register_syscore_ops(&smemc_syscore_ops); + } return 0; } From cae53e2a9a03e53152fdd331067923f7d65fc72e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Jan 2013 21:58:31 +0000 Subject: [PATCH 2221/2357] ARM: samsung: fix assembly syntax for new gas commit 2815774bb38445006074e16251b9ef5123bdc616 upstream. Recent assembler versions complain about extraneous whitespace inside [] brackets. This fixes all of these instances for the samsung platforms. We should backport this to all kernels that might need to be built with new binutils. arch/arm/kernel/entry-armv.S: Assembler messages: arch/arm/kernel/entry-armv.S:214: Error: ARM register expected -- `ldr r2,[ r6,#(0x10)]' arch/arm/kernel/entry-armv.S:214: Error: ARM register expected -- `ldr r0,[ r6,#(0x14)]' arch/arm/kernel/entry-armv.S:430: Error: ARM register expected -- `ldr r2,[ r6,#(0x10)]' arch/arm/kernel/entry-armv.S:430: Error: ARM register expected -- `ldr r0,[ r6,#(0x14)]' arch/arm/mach-s3c24xx/sleep-s3c2410.S: Assembler messages: arch/arm/mach-s3c24xx/sleep-s3c2410.S:48: Error: ARM register expected -- `ldr r7,[ r4 ]' arch/arm/mach-s3c24xx/sleep-s3c2410.S:49: Error: ARM register expected -- `ldr r8,[ r5 ]' arch/arm/mach-s3c24xx/sleep-s3c2410.S:50: Error: ARM register expected -- `ldr r9,[ r6 ]' arch/arm/mach-s3c24xx/sleep-s3c2410.S:64: Error: ARM register expected -- `streq r7,[ r4 ]' arch/arm/mach-s3c24xx/sleep-s3c2410.S:65: Error: ARM register expected -- `streq r8,[ r5 ]' arch/arm/mach-s3c24xx/sleep-s3c2410.S:66: Error: ARM register expected -- `streq r9,[ r6 ]' arch/arm/kernel/debug.S: Assembler messages: arch/arm/kernel/debug.S:83: Error: ARM register expected -- `ldr r2,[ r2,#((0x0B0)+(((0x56000000)-(0x50000000))+(0xF6000000+(0x01000000))))-((0)+(((0x56000000)-(0x50000000))+(0xF6000000+(0x01000000))))]' arch/arm/kernel/debug.S:83: Error: ARM register expected -- `ldr r2,[ r3,#(0x18)]' arch/arm/kernel/debug.S:85: Error: ARM register expected -- `ldr r2,[ r2,#((0x0B0)+(((0x56000000)-(0x50000000))+(0xF6000000+(0x01000000))))-((0)+(((0x56000000)-(0x50000000))+(0xF6000000+(0x01000000))))]' arch/arm/kernel/debug.S:85: Error: ARM register expected -- `ldr r2,[ r3,#(0x18)]' arch/arm/mach-s3c24xx/pm-h1940.S: Assembler messages: arch/arm/mach-s3c24xx/pm-h1940.S:33: Error: ARM register expected -- `ldr pc,[ r0,#((0x0B8)+(((0x56000000)-(0x50000000))+(0xF6000000+(0x01000000))))-(((0x56000000)-(0x50000000))+(0xF6000000+(0x01000000)))]' arch/arm/mach-s3c24xx/sleep-s3c2412.S: Assembler messages: arch/arm/mach-s3c24xx/sleep-s3c2412.S:60: Error: ARM register expected -- `ldrne r9,[ r1 ]' arch/arm/mach-s3c24xx/sleep-s3c2412.S:61: Error: ARM register expected -- `strne r9,[ r1 ]' arch/arm/mach-s3c24xx/sleep-s3c2412.S:62: Error: ARM register expected -- `ldrne r9,[ r2 ]' arch/arm/mach-s3c24xx/sleep-s3c2412.S:63: Error: ARM register expected -- `strne r9,[ r2 ]' arch/arm/mach-s3c24xx/sleep-s3c2412.S:64: Error: ARM register expected -- `ldrne r9,[ r3 ]' arch/arm/mach-s3c24xx/sleep-s3c2412.S:65: Error: ARM register expected -- `strne r9,[ r3 ]' arch/arm/kernel/debug.S:83: Error: ARM register expected -- `ldr r2,[ r3,#(0x08)]' arch/arm/kernel/debug.S:83: Error: ARM register expected -- `ldr r2,[ r3,#(0x18)]' arch/arm/kernel/debug.S:83: Error: ARM register expected -- `ldr r2,[ r3,#(0x10)]' arch/arm/kernel/debug.S:85: Error: ARM register expected -- `ldr r2,[ r3,#(0x08)]' arch/arm/kernel/debug.S:85: Error: ARM register expected -- `ldr r2,[ r3,#(0x18)]' arch/arm/kernel/debug.S:85: Error: ARM register expected -- `ldr r2,[ r3,#(0x10)]' Signed-off-by: Arnd Bergmann Acked-by: Kukjin Kim Cc: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- .../mach-s3c24xx/include/mach/debug-macro.S | 12 ++++++------ .../mach-s3c24xx/include/mach/entry-macro.S | 4 ++-- arch/arm/mach-s3c24xx/pm-h1940.S | 2 +- arch/arm/mach-s3c24xx/sleep-s3c2410.S | 12 ++++++------ arch/arm/mach-s3c24xx/sleep-s3c2412.S | 12 ++++++------ .../plat-samsung/include/plat/debug-macro.S | 18 +++++++++--------- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-s3c24xx/include/mach/debug-macro.S b/arch/arm/mach-s3c24xx/include/mach/debug-macro.S index 4135de87d1f..13ed33c6911 100644 --- a/arch/arm/mach-s3c24xx/include/mach/debug-macro.S +++ b/arch/arm/mach-s3c24xx/include/mach/debug-macro.S @@ -40,17 +40,17 @@ addeq \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART) addne \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART) bic \rd, \rd, #0xff000 - ldr \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ] + ldr \rd, [\rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0)] and \rd, \rd, #0x00ff0000 teq \rd, #0x00440000 @ is it 2440? 1004: - ldr \rd, [ \rx, # S3C2410_UFSTAT ] + ldr \rd, [\rx, # S3C2410_UFSTAT] moveq \rd, \rd, lsr #SHIFT_2440TXF tst \rd, #S3C2410_UFSTAT_TXFULL .endm .macro fifo_full_s3c2410 rd, rx - ldr \rd, [ \rx, # S3C2410_UFSTAT ] + ldr \rd, [\rx, # S3C2410_UFSTAT] tst \rd, #S3C2410_UFSTAT_TXFULL .endm @@ -68,18 +68,18 @@ addeq \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART) addne \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART) bic \rd, \rd, #0xff000 - ldr \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ] + ldr \rd, [\rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0)] and \rd, \rd, #0x00ff0000 teq \rd, #0x00440000 @ is it 2440? 10000: - ldr \rd, [ \rx, # S3C2410_UFSTAT ] + ldr \rd, [\rx, # S3C2410_UFSTAT] andne \rd, \rd, #S3C2410_UFSTAT_TXMASK andeq \rd, \rd, #S3C2440_UFSTAT_TXMASK .endm .macro fifo_level_s3c2410 rd, rx - ldr \rd, [ \rx, # S3C2410_UFSTAT ] + ldr \rd, [\rx, # S3C2410_UFSTAT] and \rd, \rd, #S3C2410_UFSTAT_TXMASK .endm diff --git a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S index 7615a14773f..6a21beeba1d 100644 --- a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S +++ b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S @@ -31,10 +31,10 @@ @@ try the interrupt offset register, since it is there - ldr \irqstat, [ \base, #INTPND ] + ldr \irqstat, [\base, #INTPND ] teq \irqstat, #0 beq 1002f - ldr \irqnr, [ \base, #INTOFFSET ] + ldr \irqnr, [\base, #INTOFFSET ] mov \tmp, #1 tst \irqstat, \tmp, lsl \irqnr bne 1001f diff --git a/arch/arm/mach-s3c24xx/pm-h1940.S b/arch/arm/mach-s3c24xx/pm-h1940.S index c93bf2db9f4..6183a688012 100644 --- a/arch/arm/mach-s3c24xx/pm-h1940.S +++ b/arch/arm/mach-s3c24xx/pm-h1940.S @@ -30,4 +30,4 @@ h1940_pm_return: mov r0, #S3C2410_PA_GPIO - ldr pc, [ r0, #S3C2410_GSTATUS3 - S3C24XX_VA_GPIO ] + ldr pc, [r0, #S3C2410_GSTATUS3 - S3C24XX_VA_GPIO] diff --git a/arch/arm/mach-s3c24xx/sleep-s3c2410.S b/arch/arm/mach-s3c24xx/sleep-s3c2410.S index dd5b6388a5a..65200ae72c9 100644 --- a/arch/arm/mach-s3c24xx/sleep-s3c2410.S +++ b/arch/arm/mach-s3c24xx/sleep-s3c2410.S @@ -45,9 +45,9 @@ ENTRY(s3c2410_cpu_suspend) ldr r4, =S3C2410_REFRESH ldr r5, =S3C24XX_MISCCR ldr r6, =S3C2410_CLKCON - ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB) - ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB) - ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB) + ldr r7, [r4] @ get REFRESH (and ensure in TLB) + ldr r8, [r5] @ get MISCCR (and ensure in TLB) + ldr r9, [r6] @ get CLKCON (and ensure in TLB) orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals @@ -61,8 +61,8 @@ ENTRY(s3c2410_cpu_suspend) @@ align next bit of code to cache line .align 5 s3c2410_do_sleep: - streq r7, [ r4 ] @ SDRAM sleep command - streq r8, [ r5 ] @ SDRAM power-down config - streq r9, [ r6 ] @ CPU sleep + streq r7, [r4] @ SDRAM sleep command + streq r8, [r5] @ SDRAM power-down config + streq r9, [r6] @ CPU sleep 1: beq 1b mov pc, r14 diff --git a/arch/arm/mach-s3c24xx/sleep-s3c2412.S b/arch/arm/mach-s3c24xx/sleep-s3c2412.S index c82418ed714..5adaceb7da1 100644 --- a/arch/arm/mach-s3c24xx/sleep-s3c2412.S +++ b/arch/arm/mach-s3c24xx/sleep-s3c2412.S @@ -57,12 +57,12 @@ s3c2412_sleep_enter1: * retry, as simply returning causes the system to lock. */ - ldrne r9, [ r1 ] - strne r9, [ r1 ] - ldrne r9, [ r2 ] - strne r9, [ r2 ] - ldrne r9, [ r3 ] - strne r9, [ r3 ] + ldrne r9, [r1] + strne r9, [r1] + ldrne r9, [r2] + strne r9, [r2] + ldrne r9, [r3] + strne r9, [r3] bne s3c2412_sleep_enter1 mov pc, r14 diff --git a/arch/arm/plat-samsung/include/plat/debug-macro.S b/arch/arm/plat-samsung/include/plat/debug-macro.S index 207e275362a..f3a9cff6d5d 100644 --- a/arch/arm/plat-samsung/include/plat/debug-macro.S +++ b/arch/arm/plat-samsung/include/plat/debug-macro.S @@ -14,12 +14,12 @@ /* The S5PV210/S5PC110 implementations are as belows. */ .macro fifo_level_s5pv210 rd, rx - ldr \rd, [ \rx, # S3C2410_UFSTAT ] + ldr \rd, [\rx, # S3C2410_UFSTAT] and \rd, \rd, #S5PV210_UFSTAT_TXMASK .endm .macro fifo_full_s5pv210 rd, rx - ldr \rd, [ \rx, # S3C2410_UFSTAT ] + ldr \rd, [\rx, # S3C2410_UFSTAT] tst \rd, #S5PV210_UFSTAT_TXFULL .endm @@ -27,7 +27,7 @@ * most widely re-used */ .macro fifo_level_s3c2440 rd, rx - ldr \rd, [ \rx, # S3C2410_UFSTAT ] + ldr \rd, [\rx, # S3C2410_UFSTAT] and \rd, \rd, #S3C2440_UFSTAT_TXMASK .endm @@ -36,7 +36,7 @@ #endif .macro fifo_full_s3c2440 rd, rx - ldr \rd, [ \rx, # S3C2410_UFSTAT ] + ldr \rd, [\rx, # S3C2410_UFSTAT] tst \rd, #S3C2440_UFSTAT_TXFULL .endm @@ -45,11 +45,11 @@ #endif .macro senduart,rd,rx - strb \rd, [\rx, # S3C2410_UTXH ] + strb \rd, [\rx, # S3C2410_UTXH] .endm .macro busyuart, rd, rx - ldr \rd, [ \rx, # S3C2410_UFCON ] + ldr \rd, [\rx, # S3C2410_UFCON] tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled? beq 1001f @ @ FIFO enabled... @@ -60,7 +60,7 @@ 1001: @ busy waiting for non fifo - ldr \rd, [ \rx, # S3C2410_UTRSTAT ] + ldr \rd, [\rx, # S3C2410_UTRSTAT] tst \rd, #S3C2410_UTRSTAT_TXFE beq 1001b @@ -68,7 +68,7 @@ .endm .macro waituart,rd,rx - ldr \rd, [ \rx, # S3C2410_UFCON ] + ldr \rd, [\rx, # S3C2410_UFCON] tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled? beq 1001f @ @ FIFO enabled... @@ -79,7 +79,7 @@ b 1002f 1001: @ idle waiting for non fifo - ldr \rd, [ \rx, # S3C2410_UTRSTAT ] + ldr \rd, [\rx, # S3C2410_UTRSTAT] tst \rd, #S3C2410_UTRSTAT_TXFE beq 1001b From 27c303244ef8049be6fd8088230c7f5e02a522b3 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Sat, 9 Feb 2013 05:52:45 +0100 Subject: [PATCH 2222/2357] ARM: 7643/1: sched: correct update_sched_clock() commit 7c4e9ced424be4d36df6a3e3825763e97ee97607 upstream. If we want load epoch_cyc and epoch_ns atomically, we should update epoch_cyc_copy first of all. This notify reader that updating is in progress. If we update epoch_cyc first like as current implementation, there is subtle error case. Look at the below example. cyc = 9 ns = 900 cyc_copy = 9 == CASE 1 == write cyc = 10 read cyc = 10 read ns = 900 write ns = 1000 write cyc_copy = 10 read cyc_copy = 10 output = (10, 900) == CASE 2 == read cyc = 9 write cyc = 10 write ns = 1000 read ns = 1000 read cyc_copy = 9 write cyc_copy = 10 output = (9, 1000) If atomic read is ensured, output should be (9, 900) or (10, 1000). But, output in example case are not. So, change updating sequence in order to correct this problem. Signed-off-by: Joonsoo Kim Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/sched_clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c index 27d186abbc0..6bbf936b835 100644 --- a/arch/arm/kernel/sched_clock.c +++ b/arch/arm/kernel/sched_clock.c @@ -84,11 +84,11 @@ static void notrace update_sched_clock(void) * detectable in cyc_to_fixed_sched_clock(). */ raw_local_irq_save(flags); - cd.epoch_cyc = cyc; + cd.epoch_cyc_copy = cyc; smp_wmb(); cd.epoch_ns = ns; smp_wmb(); - cd.epoch_cyc_copy = cyc; + cd.epoch_cyc = cyc; raw_local_irq_restore(flags); } From 25c3a0840c99270041487907b6365cb5bfc8a03f Mon Sep 17 00:00:00 2001 From: Phileas Fogg Date: Sat, 23 Feb 2013 00:32:19 +0100 Subject: [PATCH 2223/2357] powerpc/kexec: Disable hard IRQ before kexec commit 8520e443aa56cc157b015205ea53e7b9fc831291 upstream. Disable hard IRQ before kexec a new kernel image. Not doing it can result in corrupted data in the memory segments reserved for the new kernel. Signed-off-by: Phileas Fogg Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/machine_kexec_64.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index d7f609086a9..39833e0b282 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -162,6 +162,8 @@ static int kexec_all_irq_disabled = 0; static void kexec_smp_down(void *arg) { local_irq_disable(); + hard_irq_disable(); + mb(); /* make sure our irqs are disabled before we say they are */ get_paca()->kexec_state = KEXEC_STATE_IRQS_OFF; while(kexec_all_irq_disabled == 0) @@ -244,6 +246,8 @@ static void kexec_prepare_cpus(void) wake_offline_cpus(); smp_call_function(kexec_smp_down, NULL, /* wait */0); local_irq_disable(); + hard_irq_disable(); + mb(); /* make sure IRQs are disabled before we say they are */ get_paca()->kexec_state = KEXEC_STATE_IRQS_OFF; @@ -281,6 +285,7 @@ static void kexec_prepare_cpus(void) if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(0, 0); local_irq_disable(); + hard_irq_disable(); } #endif /* SMP */ From 49e8ae95b16fbc66b630b50ad3a18273b9342a06 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Mon, 14 Jan 2013 19:45:00 -0500 Subject: [PATCH 2224/2357] Purge existing TLB entries in set_pte_at and ptep_set_wrprotect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7139bc1579901b53db7e898789e916ee2fb52d78 upstream. This patch goes a long way toward fixing the minifail bug, and it  significantly improves the stability of SMP machines such as the rp3440.  When write  protecting a page for COW, we need to purge the existing translation.  Otherwise, the COW break doesn't occur as expected because the TLB may still have a stale entry which allows writes. [jejb: fix up checkpatch errors] Signed-off-by: John David Anglin Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- arch/parisc/include/asm/pgtable.h | 13 ++++++++++--- arch/parisc/kernel/cache.c | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index ee99f233935..7df49fad29f 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -12,11 +12,10 @@ #include #include +#include #include #include -struct vm_area_struct; - /* * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel * memory. For the return value to be meaningful, ADDR must be >= @@ -40,7 +39,14 @@ struct vm_area_struct; do{ \ *(pteptr) = (pteval); \ } while(0) -#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) + +extern void purge_tlb_entries(struct mm_struct *, unsigned long); + +#define set_pte_at(mm, addr, ptep, pteval) \ + do { \ + set_pte(ptep, pteval); \ + purge_tlb_entries(mm, addr); \ + } while (0) #endif /* !__ASSEMBLY__ */ @@ -466,6 +472,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, old = pte_val(*ptep); new = pte_val(pte_wrprotect(__pte (old))); } while (cmpxchg((unsigned long *) ptep, old, new) != old); + purge_tlb_entries(mm, addr); #else pte_t old_pte = *ptep; set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte)); diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 9d181890a7e..fa2146341da 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -420,6 +420,24 @@ void kunmap_parisc(void *addr) EXPORT_SYMBOL(kunmap_parisc); #endif +void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) +{ + unsigned long flags; + + /* Note: purge_tlb_entries can be called at startup with + no context. */ + + /* Disable preemption while we play with %sr1. */ + preempt_disable(); + mtsp(mm->context, 1); + purge_tlb_start(flags); + pdtlb(addr); + pitlb(addr); + purge_tlb_end(flags); + preempt_enable(); +} +EXPORT_SYMBOL(purge_tlb_entries); + void __flush_tlb_range(unsigned long sid, unsigned long start, unsigned long end) { From aa3fc3566478493f635d265731d81a3defcef98d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 16 Dec 2012 22:00:50 +0100 Subject: [PATCH 2225/2357] pcmcia/vrc4171: Add missing spinlock init commit 811af9723859884f2f771f3174f3ddedab7c53b5 upstream. It doesn't seem this spinlock was properly initialized. This bug was introduced by commit 7a410e8d4d97457c8c381e2de9cdc7bd3306badc. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/vrc4171_card.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 86e4a1a3c64..6bb02ab5dd9 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -246,6 +246,7 @@ static int pccard_init(struct pcmcia_socket *sock) socket = &vrc4171_sockets[slot]; socket->csc_irq = search_nonuse_irq(); socket->io_irq = search_nonuse_irq(); + spin_lock_init(&socket->lock); return 0; } From 0bbdba111a75875890290150333c07f2d79b160a Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 17 Jan 2013 21:28:37 +0100 Subject: [PATCH 2226/2357] drivers/video: fsl-diu-fb: fix pixel formats for 24 and 16 bpp commit 5d3cc311a76073f6e0a27c0752f7e41f69e95ea7 upstream. Framebuffer colors for 24 and 16 bpp are currently wrong. The order of the color component arguments in the MAKE_PF() is not natural and causes some confusion. The generated pixel format values for 24 and 16 bpp depths do not much the values in the comments. Fix the macro arguments to be in the natural RGB order and adjust the arguments for all depths to generate correct pixel format values (equal to the values mentioned in the comments). Signed-off-by: Anatolij Gustschin Cc: Timur Tabi Acked-by: Timur Tabi Signed-off-by: Greg Kroah-Hartman --- drivers/video/fsl-diu-fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 6af3f16754f..d02a538518c 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -923,7 +923,7 @@ static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel) #define PF_COMP_0_MASK 0x0000000F #define PF_COMP_0_SHIFT 0 -#define MAKE_PF(alpha, red, blue, green, size, c0, c1, c2, c3) \ +#define MAKE_PF(alpha, red, green, blue, size, c0, c1, c2, c3) \ cpu_to_le32(PF_BYTE_F | (alpha << PF_ALPHA_C_SHIFT) | \ (blue << PF_BLUE_C_SHIFT) | (green << PF_GREEN_C_SHIFT) | \ (red << PF_RED_C_SHIFT) | (c3 << PF_COMP_3_SHIFT) | \ @@ -933,10 +933,10 @@ static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel) switch (bits_per_pixel) { case 32: /* 0x88883316 */ - return MAKE_PF(3, 2, 0, 1, 3, 8, 8, 8, 8); + return MAKE_PF(3, 2, 1, 0, 3, 8, 8, 8, 8); case 24: /* 0x88082219 */ - return MAKE_PF(4, 0, 1, 2, 2, 0, 8, 8, 8); + return MAKE_PF(4, 0, 1, 2, 2, 8, 8, 8, 0); case 16: /* 0x65053118 */ return MAKE_PF(4, 2, 1, 0, 1, 5, 6, 5, 0); From 62a3dcc78d04dcd84276eaa7a40dec1066054532 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 24 Jan 2013 16:12:41 +1000 Subject: [PATCH 2227/2357] fbcon: don't lose the console font across generic->chip driver switch commit ae1287865f5361fa138d4d3b1b6277908b54eac9 upstream. If grub2 loads efifb/vesafb, then when systemd starts it can set the console font on that framebuffer device, however when we then load the native KMS driver, the first thing it does is tear down the generic framebuffer driver. The thing is the generic code is doing the right thing, it frees the font because otherwise it would leak memory. However we can assume that if you are removing the generic firmware driver (vesa/efi/offb), that a new driver *should* be loading soon after, so we effectively leak the font. However the old code left a dangling pointer in vc->vc_font.data and we can now reuse that dangling pointer to load the font into the new driver, now that we aren't freeing it. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=892340 Signed-off-by: Dave Airlie Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/fbcon.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 88e92041d8f..bdcd34d842d 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -990,7 +990,7 @@ static const char *fbcon_startup(void) } /* Setup default font */ - if (!p->fontdata) { + if (!p->fontdata && !vc->vc_font.data) { if (!fontname[0] || !(font = find_font(fontname))) font = get_default_font(info->var.xres, info->var.yres, @@ -1000,6 +1000,8 @@ static const char *fbcon_startup(void) vc->vc_font.height = font->height; vc->vc_font.data = (void *)(p->fontdata = font->data); vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ + } else { + p->fontdata = vc->vc_font.data; } cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); @@ -1159,9 +1161,9 @@ static void fbcon_init(struct vc_data *vc, int init) ops->p = &fb_display[fg_console]; } -static void fbcon_free_font(struct display *p) +static void fbcon_free_font(struct display *p, bool freefont) { - if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) + if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); p->fontdata = NULL; p->userfont = 0; @@ -1173,8 +1175,8 @@ static void fbcon_deinit(struct vc_data *vc) struct fb_info *info; struct fbcon_ops *ops; int idx; + bool free_font = true; - fbcon_free_font(p); idx = con2fb_map[vc->vc_num]; if (idx == -1) @@ -1185,6 +1187,8 @@ static void fbcon_deinit(struct vc_data *vc) if (!info) goto finished; + if (info->flags & FBINFO_MISC_FIRMWARE) + free_font = false; ops = info->fbcon_par; if (!ops) @@ -1196,6 +1200,8 @@ static void fbcon_deinit(struct vc_data *vc) ops->flags &= ~FBCON_FLAGS_INIT; finished: + fbcon_free_font(p, free_font); + if (!con_is_bound(&fb_con)) fbcon_exit(); From c30b55c385288be48f7accd16a6929ad4d983311 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 25 Jan 2013 10:28:15 +1000 Subject: [PATCH 2228/2357] fb: rework locking to fix lock ordering on takeover commit 50e244cc793d511b86adea24972f3a7264cae114 upstream. Adjust the console layer to allow a take over call where the caller already holds the locks. Make the fb layer lock in order. This is partly a band aid, the fb layer is terminally confused about the locking rules it uses for its notifiers it seems. [akpm@linux-foundation.org: remove stray non-ascii char, tidy comment] [akpm@linux-foundation.org: export do_take_over_console()] [airlied: cleanup another non-ascii char] Signed-off-by: Alan Cox Cc: Florian Tobias Schandinat Cc: Stephen Rothwell Cc: Jiri Kosina Tested-by: Sedat Dilek Reviewed-by: Daniel Vetter Signed-off-by: Andrew Morton Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 93 ++++++++++++++++++++++++++--------- drivers/video/console/fbcon.c | 29 ++++++++++- drivers/video/fbmem.c | 5 +- drivers/video/fbsysfs.c | 3 ++ include/linux/console.h | 1 + 5 files changed, 104 insertions(+), 27 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 068abe1524a..e948f5baa5c 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3017,7 +3017,7 @@ int __init vty_init(const struct file_operations *console_fops) static struct class *vtconsole_class; -static int bind_con_driver(const struct consw *csw, int first, int last, +static int do_bind_con_driver(const struct consw *csw, int first, int last, int deflt) { struct module *owner = csw->owner; @@ -3028,7 +3028,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last, if (!try_module_get(owner)) return -ENODEV; - console_lock(); + WARN_CONSOLE_UNLOCKED(); /* check if driver is registered */ for (i = 0; i < MAX_NR_CON_DRIVER; i++) { @@ -3113,11 +3113,22 @@ static int bind_con_driver(const struct consw *csw, int first, int last, retval = 0; err: - console_unlock(); module_put(owner); return retval; }; + +static int bind_con_driver(const struct consw *csw, int first, int last, + int deflt) +{ + int ret; + + console_lock(); + ret = do_bind_con_driver(csw, first, last, deflt); + console_unlock(); + return ret; +} + #ifdef CONFIG_VT_HW_CONSOLE_BINDING static int con_is_graphics(const struct consw *csw, int first, int last) { @@ -3229,9 +3240,9 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) if (!con_is_bound(csw)) con_driver->flag &= ~CON_DRIVER_FLAG_INIT; - console_unlock(); /* ignore return value, binding should not fail */ - bind_con_driver(defcsw, first, last, deflt); + do_bind_con_driver(defcsw, first, last, deflt); + console_unlock(); err: module_put(owner); return retval; @@ -3522,28 +3533,18 @@ int con_debug_leave(void) } EXPORT_SYMBOL_GPL(con_debug_leave); -/** - * register_con_driver - register console driver to console layer - * @csw: console driver - * @first: the first console to take over, minimum value is 0 - * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1 - * - * DESCRIPTION: This function registers a console driver which can later - * bind to a range of consoles specified by @first and @last. It will - * also initialize the console driver by calling con_startup(). - */ -int register_con_driver(const struct consw *csw, int first, int last) +static int do_register_con_driver(const struct consw *csw, int first, int last) { struct module *owner = csw->owner; struct con_driver *con_driver; const char *desc; int i, retval = 0; + WARN_CONSOLE_UNLOCKED(); + if (!try_module_get(owner)) return -ENODEV; - console_lock(); - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { con_driver = ®istered_con_driver[i]; @@ -3596,10 +3597,29 @@ int register_con_driver(const struct consw *csw, int first, int last) } err: - console_unlock(); module_put(owner); return retval; } + +/** + * register_con_driver - register console driver to console layer + * @csw: console driver + * @first: the first console to take over, minimum value is 0 + * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1 + * + * DESCRIPTION: This function registers a console driver which can later + * bind to a range of consoles specified by @first and @last. It will + * also initialize the console driver by calling con_startup(). + */ +int register_con_driver(const struct consw *csw, int first, int last) +{ + int retval; + + console_lock(); + retval = do_register_con_driver(csw, first, last); + console_unlock(); + return retval; +} EXPORT_SYMBOL(register_con_driver); /** @@ -3653,17 +3673,44 @@ EXPORT_SYMBOL(unregister_con_driver); * when a driver wants to take over some existing consoles * and become default driver for newly opened ones. * - * take_over_console is basically a register followed by unbind + * take_over_console is basically a register followed by unbind + */ +int do_take_over_console(const struct consw *csw, int first, int last, int deflt) +{ + int err; + + err = do_register_con_driver(csw, first, last); + /* + * If we get an busy error we still want to bind the console driver + * and return success, as we may have unbound the console driver + * but not unregistered it. + */ + if (err == -EBUSY) + err = 0; + if (!err) + do_bind_con_driver(csw, first, last, deflt); + + return err; +} +EXPORT_SYMBOL_GPL(do_take_over_console); + +/* + * If we support more console drivers, this function is used + * when a driver wants to take over some existing consoles + * and become default driver for newly opened ones. + * + * take_over_console is basically a register followed by unbind */ int take_over_console(const struct consw *csw, int first, int last, int deflt) { int err; err = register_con_driver(csw, first, last); - /* if we get an busy error we still want to bind the console driver + /* + * If we get an busy error we still want to bind the console driver * and return success, as we may have unbound the console driver -  * but not unregistered it. - */ + * but not unregistered it. + */ if (err == -EBUSY) err = 0; if (!err) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index bdcd34d842d..7ccec556373 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -529,6 +529,33 @@ static int search_for_mapped_con(void) return retval; } +static int do_fbcon_takeover(int show_logo) +{ + int err, i; + + if (!num_registered_fb) + return -ENODEV; + + if (!show_logo) + logo_shown = FBCON_LOGO_DONTSHOW; + + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map[i] = info_idx; + + err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc, + fbcon_is_default); + + if (err) { + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map[i] = -1; + info_idx = -1; + } else { + fbcon_has_console_bind = 1; + } + + return err; +} + static int fbcon_takeover(int show_logo) { int err, i; @@ -3121,7 +3148,7 @@ static int fbcon_fb_registered(struct fb_info *info) } if (info_idx != -1) - ret = fbcon_takeover(1); + ret = do_fbcon_takeover(1); } else { for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map_boot[i] == idx) diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index c6ce416ab58..f04ccf7d86e 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1642,7 +1642,9 @@ static int do_register_framebuffer(struct fb_info *fb_info) event.info = fb_info; if (!lock_fb_info(fb_info)) return -ENODEV; + console_lock(); fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); + console_unlock(); unlock_fb_info(fb_info); return 0; } @@ -1845,11 +1847,8 @@ int fb_new_modelist(struct fb_info *info) err = 1; if (!list_empty(&info->modelist)) { - if (!lock_fb_info(info)) - return -ENODEV; event.info = info; err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); - unlock_fb_info(info); } return err; diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 67afa9c2289..303fb9f35b2 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -175,6 +175,8 @@ static ssize_t store_modes(struct device *device, if (i * sizeof(struct fb_videomode) != count) return -EINVAL; + if (!lock_fb_info(fb_info)) + return -ENODEV; console_lock(); list_splice(&fb_info->modelist, &old_list); fb_videomode_to_modelist((const struct fb_videomode *)buf, i, @@ -186,6 +188,7 @@ static ssize_t store_modes(struct device *device, fb_destroy_modelist(&old_list); console_unlock(); + unlock_fb_info(fb_info); return 0; } diff --git a/include/linux/console.h b/include/linux/console.h index 7201ce4280c..e8ea7d7371b 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -78,6 +78,7 @@ int con_is_bound(const struct consw *csw); int register_con_driver(const struct consw *csw, int first, int last); int unregister_con_driver(const struct consw *csw); int take_over_console(const struct consw *sw, int first, int last, int deflt); +int do_take_over_console(const struct consw *sw, int first, int last, int deflt); void give_up_console(const struct consw *sw); #ifdef CONFIG_HW_CONSOLE int con_debug_enter(struct vc_data *vc); From f515e1d59602f8eafaad39b6842bd823ad34654e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Jan 2013 10:28:18 +1000 Subject: [PATCH 2229/2357] fb: Yet another band-aid for fixing lockdep mess commit e93a9a868792ad71cdd09d75e5a02d8067473c4e upstream. I've still got lockdep warnings even after Alan's patch, and it seems that yet more band aids are required to paper over similar paths for unbind_con_driver() and unregister_con_driver(). After this hack, lockdep warnings are finally gone. Signed-off-by: Takashi Iwai Cc: Alan Cox Cc: Florian Tobias Schandinat Cc: Jiri Kosina Tested-by: Sedat Dilek Signed-off-by: Andrew Morton Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 43 +++++++++++++++++++++++------------ drivers/video/console/fbcon.c | 4 ++-- drivers/video/fbmem.c | 4 ++++ include/linux/console.h | 1 + include/linux/vt_kern.h | 2 ++ 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e948f5baa5c..268294c71c1 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3164,6 +3164,18 @@ static int con_is_graphics(const struct consw *csw, int first, int last) * or 0 on success. */ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) +{ + int retval; + + console_lock(); + retval = do_unbind_con_driver(csw, first, last, deflt); + console_unlock(); + return retval; +} +EXPORT_SYMBOL(unbind_con_driver); + +/* unlocked version of unbind_con_driver() */ +int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt) { struct module *owner = csw->owner; const struct consw *defcsw = NULL; @@ -3173,7 +3185,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) if (!try_module_get(owner)) return -ENODEV; - console_lock(); + WARN_CONSOLE_UNLOCKED(); /* check if driver is registered and if it is unbindable */ for (i = 0; i < MAX_NR_CON_DRIVER; i++) { @@ -3186,10 +3198,8 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) } } - if (retval) { - console_unlock(); + if (retval) goto err; - } retval = -ENODEV; @@ -3205,15 +3215,11 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) } } - if (retval) { - console_unlock(); + if (retval) goto err; - } - if (!con_is_bound(csw)) { - console_unlock(); + if (!con_is_bound(csw)) goto err; - } first = max(first, con_driver->first); last = min(last, con_driver->last); @@ -3242,13 +3248,12 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) /* ignore return value, binding should not fail */ do_bind_con_driver(defcsw, first, last, deflt); - console_unlock(); err: module_put(owner); return retval; } -EXPORT_SYMBOL(unbind_con_driver); +EXPORT_SYMBOL_GPL(do_unbind_con_driver); static int vt_bind(struct con_driver *con) { @@ -3635,9 +3640,18 @@ EXPORT_SYMBOL(register_con_driver); */ int unregister_con_driver(const struct consw *csw) { - int i, retval = -ENODEV; + int retval; console_lock(); + retval = do_unregister_con_driver(csw); + console_unlock(); + return retval; +} +EXPORT_SYMBOL(unregister_con_driver); + +int do_unregister_con_driver(const struct consw *csw) +{ + int i, retval = -ENODEV; /* cannot unregister a bound driver */ if (con_is_bound(csw)) @@ -3663,10 +3677,9 @@ int unregister_con_driver(const struct consw *csw) } } err: - console_unlock(); return retval; } -EXPORT_SYMBOL(unregister_con_driver); +EXPORT_SYMBOL_GPL(do_unregister_con_driver); /* * If we support more console drivers, this function is used diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 7ccec556373..5bf163e0384 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -3010,7 +3010,7 @@ static int fbcon_unbind(void) { int ret; - ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc, + ret = do_unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); if (!ret) @@ -3083,7 +3083,7 @@ static int fbcon_fb_unregistered(struct fb_info *info) primary_device = -1; if (!num_registered_fb) - unregister_con_driver(&fb_con); + do_unregister_con_driver(&fb_con); return 0; } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index f04ccf7d86e..90f13152d21 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1660,8 +1660,10 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) if (!lock_fb_info(fb_info)) return -ENODEV; + console_lock(); event.info = fb_info; ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); + console_unlock(); unlock_fb_info(fb_info); if (ret) @@ -1676,7 +1678,9 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) num_registered_fb--; fb_cleanup_device(fb_info); event.info = fb_info; + console_lock(); fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); + console_unlock(); /* this may free fb info */ put_fb_info(fb_info); diff --git a/include/linux/console.h b/include/linux/console.h index e8ea7d7371b..f59e9428d06 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -77,6 +77,7 @@ extern const struct consw prom_con; /* SPARC PROM console */ int con_is_bound(const struct consw *csw); int register_con_driver(const struct consw *csw, int first, int last); int unregister_con_driver(const struct consw *csw); +int do_unregister_con_driver(const struct consw *csw); int take_over_console(const struct consw *sw, int first, int last, int deflt); int do_take_over_console(const struct consw *sw, int first, int last, int deflt); void give_up_console(const struct consw *sw); diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 49e39d4396d..57eeb145455 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -132,6 +132,8 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new); int vt_waitactive(int n); void change_console(struct vc_data *new_vc); void reset_vc(struct vc_data *vc); +extern int do_unbind_con_driver(const struct consw *csw, int first, int last, + int deflt); extern int unbind_con_driver(const struct consw *csw, int first, int last, int deflt); int vty_init(const struct file_operations *console_fops); From 6a924a76039689fd260ee311b85fb2202bcd4910 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 15 Jan 2013 23:30:27 +0800 Subject: [PATCH 2230/2357] mmc: sdhci-esdhc-imx: fix host version read commit ef4d0888bb7e1b963880f086575081c3d39cad2d upstream. When commit 95a2482 (mmc: sdhci-esdhc-imx: add basic imx6q usdhc support) works around host version issue on imx6q, it gets the register address fixup "reg ^= 2" lost for imx25/35/51/53 esdhc. Thus, the controller version on these SoCs is wrongly identified as v1 while it's actually v2. Add the address fixup back and take a different approach to correct imx6q host version, so that the host version read gets back to work for all SoCs. Signed-off-by: Shawn Guo Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-esdhc-imx.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 8abdaf6697a..be46052228b 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -232,15 +232,18 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) static u16 esdhc_readw_le(struct sdhci_host *host, int reg) { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = pltfm_host->priv; + if (unlikely(reg == SDHCI_HOST_VERSION)) { - u16 val = readw(host->ioaddr + (reg ^ 2)); - /* - * uSDHC supports SDHCI v3.0, but it's encoded as value - * 0x3 in host controller version register, which violates - * SDHCI_SPEC_300 definition. Work it around here. - */ - if ((val & SDHCI_SPEC_VER_MASK) == 3) - return --val; + reg ^= 2; + if (is_imx6q_usdhc(imx_data)) { + /* + * The usdhc register returns a wrong host version. + * Correct it here. + */ + return SDHCI_SPEC_300; + } } return readw(host->ioaddr + reg); From a9115fba99247ad51211beb3ffd23b6553c80ee9 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 18 Feb 2013 01:47:15 +0100 Subject: [PATCH 2231/2357] HID: wiimote: fix nunchuck button parser commit 89bdd0c6f38ccf0de43d5a36ede384a730f3394e upstream. The buttons of the Wii Remote Nunchuck extension are actually active low. Fix the parser to forward the inverted values. The comment in the function always said "0 == pressed" but the implementation was wrong from the beginning. Reported-by: Victor Quicksilver Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-wiimote-ext.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c index aa958706c0e..9e572850201 100644 --- a/drivers/hid/hid-wiimote-ext.c +++ b/drivers/hid/hid-wiimote-ext.c @@ -378,14 +378,14 @@ static void handler_nunchuck(struct wiimote_ext *ext, const __u8 *payload) if (ext->motionp) { input_report_key(ext->input, - wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x04)); + wiiext_keymap[WIIEXT_KEY_Z], !(payload[5] & 0x04)); input_report_key(ext->input, - wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x08)); + wiiext_keymap[WIIEXT_KEY_C], !(payload[5] & 0x08)); } else { input_report_key(ext->input, - wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x01)); + wiiext_keymap[WIIEXT_KEY_Z], !(payload[5] & 0x01)); input_report_key(ext->input, - wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x02)); + wiiext_keymap[WIIEXT_KEY_C], !(payload[5] & 0x02)); } input_sync(ext->input); From 6e95f970d1cb6801b5f26d2c167fb1e0ad6c5dba Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Feb 2013 08:22:22 +0000 Subject: [PATCH 2232/2357] bridge: set priority of STP packets [ Upstream commit 547b4e718115eea74087e28d7fa70aec619200db ] Spanning Tree Protocol packets should have always been marked as control packets, this causes them to get queued in the high prirority FIFO. As Radia Perlman mentioned in her LCA talk, STP dies if bridge gets overloaded and can't communicate. This is a long-standing bug back to the first versions of Linux bridge. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bridge/br_stp_bpdu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index e16aade51ae..718cbe8ad42 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ static void br_send_bpdu(struct net_bridge_port *p, skb->dev = p->dev; skb->protocol = htons(ETH_P_802_2); + skb->priority = TC_PRIO_CONTROL; skb_reserve(skb, LLC_RESERVE); memcpy(__skb_put(skb, length), data, length); From b5428e471b91192a2438d04c1d2ff2b3d4708366 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 Feb 2013 06:16:53 +0000 Subject: [PATCH 2233/2357] net: fix infinite loop in __skb_recv_datagram() [ Upstream commit 77c1090f94d1b0b5186fb13a1b71b47b1343f87f ] Tommi was fuzzing with trinity and reported the following problem : commit 3f518bf745 (datagram: Add offset argument to __skb_recv_datagram) missed that a raw socket receive queue can contain skbs with no payload. We can loop in __skb_recv_datagram() with MSG_PEEK mode, because wait_for_packet() is not prepared to skip these skbs. [ 83.541011] INFO: rcu_sched detected stalls on CPUs/tasks: {} (detected by 0, t=26002 jiffies, g=27673, c=27672, q=75) [ 83.541011] INFO: Stall ended before state dump start [ 108.067010] BUG: soft lockup - CPU#0 stuck for 22s! [trinity-child31:2847] ... [ 108.067010] Call Trace: [ 108.067010] [] __skb_recv_datagram+0x1a3/0x3b0 [ 108.067010] [] skb_recv_datagram+0x2d/0x30 [ 108.067010] [] rawv6_recvmsg+0xad/0x240 [ 108.067010] [] sock_common_recvmsg+0x34/0x50 [ 108.067010] [] sock_recvmsg+0xbc/0xf0 [ 108.067010] [] sys_recvfrom+0xde/0x150 [ 108.067010] [] system_call_fastpath+0x16/0x1b Reported-by: Tommi Rantala Tested-by: Tommi Rantala Signed-off-by: Eric Dumazet Cc: Pavel Emelyanov Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/datagram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/datagram.c b/net/core/datagram.c index e4fbfd6e2bd..da7e0c867cc 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -187,7 +187,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, skb_queue_walk(queue, skb) { *peeked = skb->peeked; if (flags & MSG_PEEK) { - if (*off >= skb->len) { + if (*off >= skb->len && skb->len) { *off -= skb->len; continue; } From 320c1509197bce83d2ebb45d4cc5f9b4d91c05dc Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 14 Feb 2013 03:18:57 +0000 Subject: [PATCH 2234/2357] xen-netback: correctly return errors from netbk_count_requests() [ Upstream commit 35876b5ffc154c357476b2c3bdab10feaf4bd8f0 ] netbk_count_requests() could detect an error, call netbk_fatal_tx_error() but return 0. The vif may then be used afterwards (e.g., in a call to netbk_tx_error(). Since netbk_fatal_tx_error() could set vif->refcnt to 1, the vif may be freed immediately after the call to netbk_fatal_tx_error() (e.g., if the vif is also removed). Netback thread Xenwatch thread ------------------------------------------- netbk_fatal_tx_err() netback_remove() xenvif_disconnect() ... free_netdev() netbk_tx_err() Oops! Signed-off-by: Wei Liu Signed-off-by: Jan Beulich Signed-off-by: David Vrabel Reported-by: Christopher S. Aker Acked-by: Ian Campbell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netback/netback.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index e2793d06e5d..2bdf798b3d9 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -883,13 +883,13 @@ static int netbk_count_requests(struct xenvif *vif, if (frags >= work_to_do) { netdev_err(vif->dev, "Need more frags\n"); netbk_fatal_tx_err(vif); - return -frags; + return -ENODATA; } if (unlikely(frags >= MAX_SKB_FRAGS)) { netdev_err(vif->dev, "Too many frags\n"); netbk_fatal_tx_err(vif); - return -frags; + return -E2BIG; } memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags), @@ -897,7 +897,7 @@ static int netbk_count_requests(struct xenvif *vif, if (txp->size > first->size) { netdev_err(vif->dev, "Frag is bigger than frame.\n"); netbk_fatal_tx_err(vif); - return -frags; + return -EIO; } first->size -= txp->size; @@ -907,7 +907,7 @@ static int netbk_count_requests(struct xenvif *vif, netdev_err(vif->dev, "txp->offset: %x, size: %u\n", txp->offset, txp->size); netbk_fatal_tx_err(vif); - return -frags; + return -EINVAL; } } while ((txp++)->flags & XEN_NETTXF_more_data); return frags; From 29b3bb0be43fea0a49e5235894e1dcbc0ac299dc Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 14 Feb 2013 03:18:58 +0000 Subject: [PATCH 2235/2357] xen-netback: cancel the credit timer when taking the vif down [ Upstream commit 3e55f8b306cf305832a4ac78aa82e1b40e818ece ] If the credit timer is left armed after calling xen_netbk_remove_xenvif(), then it may fire and attempt to schedule the vif which will then oops as vif->netbk == NULL. This may happen both in the fatal error path and during normal disconnection from the front end. The sequencing during shutdown is critical to ensure that: a) vif->netbk doesn't become unexpectedly NULL; and b) the net device/vif is not freed. 1. Mark as unschedulable (netif_carrier_off()). 2. Synchronously cancel the timer. 3. Remove the vif from the schedule list. 4. Remove it from it netback thread group. 5. Wait for vif->refcnt to become 0. Signed-off-by: David Vrabel Acked-by: Ian Campbell Reported-by: Christopher S. Aker Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netback/interface.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index b8c5193bd42..221f4265f7d 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -132,6 +132,7 @@ static void xenvif_up(struct xenvif *vif) static void xenvif_down(struct xenvif *vif) { disable_irq(vif->irq); + del_timer_sync(&vif->credit_timeout); xen_netbk_deschedule_xenvif(vif); xen_netbk_remove_xenvif(vif); } @@ -363,8 +364,6 @@ void xenvif_disconnect(struct xenvif *vif) atomic_dec(&vif->refcnt); wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0); - del_timer_sync(&vif->credit_timeout); - if (vif->irq) unbind_from_irqhandler(vif->irq, vif); From 1e6b5fb5ce92028f6c87864712ed7290446a4c11 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Fri, 15 Feb 2013 22:28:25 +0000 Subject: [PATCH 2236/2357] net: fix a compile error when SOCK_REFCNT_DEBUG is enabled [ Upstream commit dec34fb0f5b7873de45132a84a3af29e61084a6b ] When SOCK_REFCNT_DEBUG is enabled, below build error is met: kernel/sysctl_binary.o: In function `sk_refcnt_debug_release': include/net/sock.h:1025: multiple definition of `sk_refcnt_debug_release' kernel/sysctl.o:include/net/sock.h:1025: first defined here kernel/audit.o: In function `sk_refcnt_debug_release': include/net/sock.h:1025: multiple definition of `sk_refcnt_debug_release' kernel/sysctl.o:include/net/sock.h:1025: first defined here make[1]: *** [kernel/built-in.o] Error 1 make: *** [kernel] Error 2 So we decide to make sk_refcnt_debug_release static to eliminate the error. Signed-off-by: Ying Xue Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/sock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/sock.h b/include/net/sock.h index 5878118e3ce..59a8947a194 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -944,7 +944,7 @@ static inline void sk_refcnt_debug_dec(struct sock *sk) sk->sk_prot->name, sk, atomic_read(&sk->sk_prot->socks)); } -inline void sk_refcnt_debug_release(const struct sock *sk) +static inline void sk_refcnt_debug_release(const struct sock *sk) { if (atomic_read(&sk->sk_refcnt) != 1) printk(KERN_DEBUG "Destruction of the %s socket %p delayed, refcnt=%d\n", From 785e5dce256ea5bdf4871af13f9908b74264b515 Mon Sep 17 00:00:00 2001 From: Li Wei Date: Thu, 21 Feb 2013 00:09:54 +0000 Subject: [PATCH 2237/2357] ipv4: fix a bug in ping_err(). [ Upstream commit b531ed61a2a2a77eeb2f7c88b49aa5ec7d9880d8 ] We should get 'type' and 'code' from the outer ICMP header. Signed-off-by: Li Wei Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 50009c787bc..c234bda5b80 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -321,8 +321,8 @@ void ping_err(struct sk_buff *skb, u32 info) struct iphdr *iph = (struct iphdr *)skb->data; struct icmphdr *icmph = (struct icmphdr *)(skb->data+(iph->ihl<<2)); struct inet_sock *inet_sock; - int type = icmph->type; - int code = icmph->code; + int type = icmp_hdr(skb)->type; + int code = icmp_hdr(skb)->code; struct net *net = dev_net(skb->dev); struct sock *sk; int harderr; From e5a096aa0aeb1fc8ad8b3d6bd70d322a0d65edc4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 21 Feb 2013 12:18:52 +0000 Subject: [PATCH 2238/2357] ipv6: use a stronger hash for tcp [ Upstream commit 08dcdbf6a7b9d14c2302c5bd0c5390ddf122f664 ] It looks like its possible to open thousands of TCP IPv6 sessions on a server, all landing in a single slot of TCP hash table. Incoming packets have to lookup sockets in a very long list. We should hash all bits from foreign IPv6 addresses, using a salt and hash mix, not a simple XOR. inet6_ehashfn() can also separately use the ports, instead of xoring them. Reported-by: Neal Cardwell Signed-off-by: Eric Dumazet Cc: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/inet6_hashtables.h | 8 ++++---- include/net/inet_sock.h | 1 + include/net/ipv6.h | 12 ++++++++++++ net/ipv4/af_inet.c | 9 +++++++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index 00cbb4384c7..2da45ce8acb 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h @@ -28,16 +28,16 @@ struct inet_hashinfo; -/* I have no idea if this is a good hash for v6 or not. -DaveM */ static inline unsigned int inet6_ehashfn(struct net *net, const struct in6_addr *laddr, const u16 lport, const struct in6_addr *faddr, const __be16 fport) { - u32 ports = (lport ^ (__force u16)fport); + u32 ports = (((u32)lport) << 16) | (__force u32)fport; return jhash_3words((__force u32)laddr->s6_addr32[3], - (__force u32)faddr->s6_addr32[3], - ports, inet_ehash_secret + net_hash_mix(net)); + ipv6_addr_jhash(faddr), + ports, + inet_ehash_secret + net_hash_mix(net)); } static inline int inet6_sk_ehashfn(const struct sock *sk) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index ae17e1352d7..8cd2e1d0ec3 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -202,6 +202,7 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to, extern int inet_sk_rebuild_header(struct sock *sk); extern u32 inet_ehash_secret; +extern u32 ipv6_hash_secret; extern void build_ehash_secret(void); static inline unsigned int inet_ehashfn(struct net *net, diff --git a/include/net/ipv6.h b/include/net/ipv6.h index e4170a22fc6..12a1bd2e987 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -390,6 +391,17 @@ struct ip6_create_arg { void ip6_frag_init(struct inet_frag_queue *q, void *a); int ip6_frag_match(struct inet_frag_queue *q, void *a); +/* more secured version of ipv6_addr_hash() */ +static inline u32 ipv6_addr_jhash(const struct in6_addr *a) +{ + u32 v = (__force u32)a->s6_addr32[0] ^ (__force u32)a->s6_addr32[1]; + + return jhash_3words(v, + (__force u32)a->s6_addr32[2], + (__force u32)a->s6_addr32[3], + ipv6_hash_secret); +} + static inline int ipv6_addr_any(const struct in6_addr *a) { return (a->s6_addr32[0] | a->s6_addr32[1] | diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 10e3751466b..78ec298001c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -227,8 +227,12 @@ EXPORT_SYMBOL(inet_listen); u32 inet_ehash_secret __read_mostly; EXPORT_SYMBOL(inet_ehash_secret); +u32 ipv6_hash_secret __read_mostly; +EXPORT_SYMBOL(ipv6_hash_secret); + /* - * inet_ehash_secret must be set exactly once + * inet_ehash_secret must be set exactly once, and to a non nul value + * ipv6_hash_secret must be set exactly once. */ void build_ehash_secret(void) { @@ -238,7 +242,8 @@ void build_ehash_secret(void) get_random_bytes(&rnd, sizeof(rnd)); } while (rnd == 0); - cmpxchg(&inet_ehash_secret, 0, rnd); + if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0) + get_random_bytes(&ipv6_hash_secret, sizeof(ipv6_hash_secret)); } EXPORT_SYMBOL(build_ehash_secret); From 8c2223fc19032e7b8761e46c15e1ed167a252285 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sat, 23 Feb 2013 01:13:47 +0000 Subject: [PATCH 2239/2357] sock_diag: Fix out-of-bounds access to sock_diag_handlers[] [ Upstream commit 6e601a53566d84e1ffd25e7b6fe0b6894ffd79c0 ] Userland can send a netlink message requesting SOCK_DIAG_BY_FAMILY with a family greater or equal then AF_MAX -- the array size of sock_diag_handlers[]. The current code does not test for this condition therefore is vulnerable to an out-of-bound access opening doors for a privilege escalation. Signed-off-by: Mathias Krause Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/sock_diag.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index b9868e1fd62..aa74be442df 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -126,6 +126,9 @@ static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (nlmsg_len(nlh) < sizeof(*req)) return -EINVAL; + if (req->sdiag_family >= AF_MAX) + return -EINVAL; + hndl = sock_diag_lock_handler(req->sdiag_family); if (hndl == NULL) err = -ENOENT; From b9bf60ac3e3779d4ffa03daceebf59df7b46c224 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 21 Feb 2013 23:32:27 +0000 Subject: [PATCH 2240/2357] vlan: adjust vlan_set_encap_proto() for its callers [ Upstream commit da8c87241c26aac81a64c7e4d21d438a33018f4e ] There are two places to call vlan_set_encap_proto(): vlan_untag() and __pop_vlan_tci(). vlan_untag() assumes skb->data points after mac addr, otherwise the following code vhdr = (struct vlan_hdr *) skb->data; vlan_tci = ntohs(vhdr->h_vlan_TCI); __vlan_hwaccel_put_tag(skb, vlan_tci); skb_pull_rcsum(skb, VLAN_HLEN); won't be correct. But __pop_vlan_tci() assumes points _before_ mac addr. In vlan_set_encap_proto(), it looks for some magic L2 value after mac addr: rawp = skb->data; if (*(unsigned short *) rawp == 0xFFFF) ... Therefore __pop_vlan_tci() is obviously wrong. A quick fix is avoiding using skb->data in vlan_set_encap_proto(), use 'vhdr+1' is always correct in both cases. Signed-off-by: Cong Wang Cc: David S. Miller Cc: Jesse Gross Acked-by: Jesse Gross Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/if_vlan.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 561e130df0b..9b0c6142eae 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -327,7 +327,7 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr) { __be16 proto; - unsigned char *rawp; + unsigned short *rawp; /* * Was a VLAN packet, grab the encapsulated protocol, which the layer @@ -340,8 +340,8 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb, return; } - rawp = skb->data; - if (*(unsigned short *) rawp == 0xFFFF) + rawp = (unsigned short *)(vhdr + 1); + if (*rawp == 0xFFFF) /* * This is a magic hack to spot IPX packets. Older Novell * breaks the protocol design and runs IPX over 802.3 without From 62fb8fe993f3a9060d75bc3d8b6eb9d153d8238c Mon Sep 17 00:00:00 2001 From: Maciej Sosnowski Date: Wed, 23 May 2012 17:27:07 +0200 Subject: [PATCH 2241/2357] dca: check against empty dca_domains list before unregister provider commit c419fcfd071cf34ba00f9f65282583772d2655e7 upstream. When providers get blocked unregister_dca_providers() is called ending up with dca_providers and dca_domain lists emptied. Dca should be prevented from trying to unregister any provider if dca_domain list is found empty. Reported-by: Jiang Liu Tested-by: Gaohuai Han Signed-off-by: Maciej Sosnowski Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/dca/dca-core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index bc6f5faa1e9..819dfda8823 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -420,6 +420,11 @@ void unregister_dca_provider(struct dca_provider *dca, struct device *dev) raw_spin_lock_irqsave(&dca_lock, flags); + if (list_empty(&dca_domains)) { + raw_spin_unlock_irqrestore(&dca_lock, flags); + return; + } + list_del(&dca->node); pci_rc = dca_pci_rc_from_dev(dev); From 78b42978accff2b4ccc45f399c47841d697e166f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 23 Jan 2013 10:44:36 +0100 Subject: [PATCH 2242/2357] USB: option: add and update Alcatel modems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f8f0302bbcbd1b14655bef29f6996a2152be559d upstream. Adding three currently unsupported modems based on information from .inf driver files: Diag VID_1BBB&PID_0052&MI_00 AGPS VID_1BBB&PID_0052&MI_01 VOICE VID_1BBB&PID_0052&MI_02 AT VID_1BBB&PID_0052&MI_03 Modem VID_1BBB&PID_0052&MI_05 wwan VID_1BBB&PID_0052&MI_06 Diag VID_1BBB&PID_00B6&MI_00 AT VID_1BBB&PID_00B6&MI_01 Modem VID_1BBB&PID_00B6&MI_02 wwan VID_1BBB&PID_00B6&MI_03 Diag VID_1BBB&PID_00B7&MI_00 AGPS VID_1BBB&PID_00B7&MI_01 VOICE VID_1BBB&PID_00B7&MI_02 AT VID_1BBB&PID_00B7&MI_03 Modem VID_1BBB&PID_00B7&MI_04 wwan VID_1BBB&PID_00B7&MI_05 Updating the blacklist info for the X060S_X200 and X220_X500D, reserving interfaces for a wwan driver, based on wwan VID_1BBB&PID_0000&MI_04 wwan VID_1BBB&PID_0017&MI_06 Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 6c077a174bf..db976033b02 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -479,6 +479,7 @@ static const struct option_blacklist_info four_g_w14_blacklist = { static const struct option_blacklist_info alcatel_x200_blacklist = { .sendsetup = BIT(0) | BIT(1), + .reserved = BIT(4), }; static const struct option_blacklist_info zte_0037_blacklist = { @@ -1215,7 +1216,14 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist }, - { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, 0x0052), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b6), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b7), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, From 0457c05d7f770e5b1581ecc1357b4c2b7b336808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Tue, 12 Feb 2013 13:42:24 +0100 Subject: [PATCH 2243/2357] USB: option: add Yota / Megafon M100-1 4g modem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit cd565279e51bedee1b2988e84f9b3bef485adeb6 upstream. Interface layout: 00 CD-ROM 01 debug COM port 02 AP control port 03 modem 04 usb-ethernet Bus=01 Lev=02 Prnt=02 Port=01 Cnt=02 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=0408 ProdID=ea42 Rev= 0.00 S: Manufacturer=Qualcomm, Incorporated S: Product=Qualcomm CDMA Technologies MSM S: SerialNumber=353568051xxxxxx C:* #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=84(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=86(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index db976033b02..5e7f5524cea 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -576,6 +576,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, + { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), From 9c5879c55ecc7c5b0e54809e011561bde4926d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 13 Feb 2013 23:41:34 +0100 Subject: [PATCH 2244/2357] USB: option: add Huawei "ACM" devices using protocol = vendor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1f3f687722fd9b29a0c2a85b4844e3b2a3585c63 upstream. The USB device descriptor of one identity presented by a few Huawei morphing devices have serial functions with class codes 02/02/ff, indicating CDC ACM with a vendor specific protocol. This combination is often used for MSFT RNDIS functions, and the CDC ACM class driver will therefore ignore such functions. The CDC ACM class driver cannot support functions with only 2 endpoints. The underlying serial functions of these modems are also believed to be the same as for alternate device identities already supported by the option driver. Letting the same driver handle these functions independently of the current identity ensures consistent handling and user experience. There is no need to blacklist these devices in the rndis_host driver. Huawei serial functions will either have only 2 endpoints or a CDC ACM functional descriptor with bmCapabilities != 0, making them correctly ignored as "non RNDIS" by that driver. Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5e7f5524cea..539247b934a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -578,8 +578,12 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1442, USB_CLASS_COMM, 0x02, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), From 30361160bc12da86b9ce4c7c60bd68ff930eda76 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 14 Feb 2013 17:08:09 +0200 Subject: [PATCH 2245/2357] USB: ehci-omap: Fix autoloading of module commit 04753523266629b1cd0518091da1658755787198 upstream. The module alias should be "ehci-omap" and not "omap-ehci" to match the platform device name. The omap-ehci module should now autoload correctly. Signed-off-by: Roger Quadros Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index e669c6a7e91..12d3f284998 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -371,7 +371,7 @@ static const struct hc_driver ehci_omap_hc_driver = { .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; -MODULE_ALIAS("platform:omap-ehci"); +MODULE_ALIAS("platform:ehci-omap"); MODULE_AUTHOR("Texas Instruments, Inc."); MODULE_AUTHOR("Felipe Balbi "); From 12b64a247ef45dcd865a98d63bbae7355e51633b Mon Sep 17 00:00:00 2001 From: fangxiaozhi Date: Thu, 7 Feb 2013 15:32:07 +0800 Subject: [PATCH 2246/2357] USB: storage: properly handle the endian issues of idProduct commit cd060956c5e97931c3909e4a808508469c0bb9f6 upstream. 1. The idProduct is little endian, so make sure its value to be compatible with the current CPU. Make no break on big endian processors. Signed-off-by: fangxiaozhi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/initializers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 16b0bf055ee..7ab9046ae0e 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -147,7 +147,7 @@ static int usb_stor_huawei_dongles_pid(struct us_data *us) int idProduct; idesc = &us->pusb_intf->cur_altsetting->desc; - idProduct = us->pusb_dev->descriptor.idProduct; + idProduct = le16_to_cpu(us->pusb_dev->descriptor.idProduct); /* The first port is CDROM, * means the dongle in the single port mode, * and a switch command is required to be sent. */ @@ -169,7 +169,7 @@ int usb_stor_huawei_init(struct us_data *us) int result = 0; if (usb_stor_huawei_dongles_pid(us)) { - if (us->pusb_dev->descriptor.idProduct >= 0x1446) + if (le16_to_cpu(us->pusb_dev->descriptor.idProduct) >= 0x1446) result = usb_stor_huawei_scsi_init(us); else result = usb_stor_huawei_feature_init(us); From 616dd23b2e475e61a2974eb112cc88d3cb94d47f Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Thu, 14 Feb 2013 09:39:09 -0500 Subject: [PATCH 2247/2357] USB: usb-storage: unusual_devs update for Super TOP SATA bridge commit 18e03310b5caa6d11c1a8c61b982c37047693fba upstream. The current entry in unusual_cypress.h for the Super TOP SATA bridge devices seems to be causing corruption on newer revisions of this device. This has been reported in Arch Linux and Fedora. The original patch was tested on devices with bcdDevice of 1.60, whereas the newer devices report bcdDevice as 2.20. Limit the UNUSUAL_DEV entry to devices less than 2.20. This fixes https://bugzilla.redhat.com/show_bug.cgi?id=909591 The Arch Forum post on this is here: https://bbs.archlinux.org/viewtopic.php?id=152011 Reported-by: Carsten S. Tested-by: Carsten S. Signed-off-by: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_cypress.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/unusual_cypress.h b/drivers/usb/storage/unusual_cypress.h index 2c855302622..65a6a75066a 100644 --- a/drivers/usb/storage/unusual_cypress.h +++ b/drivers/usb/storage/unusual_cypress.h @@ -31,7 +31,7 @@ UNUSUAL_DEV( 0x04b4, 0x6831, 0x0000, 0x9999, "Cypress ISD-300LP", USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), -UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x9999, +UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x0219, "Super Top", "USB 2.0 SATA BRIDGE", USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), From 048b6fe6dccb105512147eb47accbb1431b4e54b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 28 Feb 2013 07:01:22 -0800 Subject: [PATCH 2248/2357] Linux 3.4.34 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a26d19a31d9..250be36a818 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 33 +SUBLEVEL = 34 EXTRAVERSION = NAME = Saber-toothed Squirrel From 4201af673b5f07ffbb128bc79d8139fd7db3260f Mon Sep 17 00:00:00 2001 From: Shobhit Pandey Date: Mon, 25 Feb 2013 10:30:40 +0530 Subject: [PATCH 2249/2357] msm: wfd: Correct logic to unmap mdp buffers Currently unmapping of the mdp buffers from iommu is not happening for non-secure mode. Initial value of the flag that decides unmapping is changed to fix the issue. Change-Id: I34201780f3b454f368e401792a050247e58eb185 Signed-off-by: Rajeshwar Kurapaty --- drivers/media/video/msm_wfd/mdp-4-subdev.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/msm_wfd/mdp-4-subdev.c b/drivers/media/video/msm_wfd/mdp-4-subdev.c index 3708c14fc5c..d1b39f662a8 100644 --- a/drivers/media/video/msm_wfd/mdp-4-subdev.c +++ b/drivers/media/video/msm_wfd/mdp-4-subdev.c @@ -202,9 +202,12 @@ int mdp_mmap(struct v4l2_subdev *sd, void *arg) if (inst->uses_iommu_split_domain) { if (inst->secure) use_iommu = false; - else + else { + use_iommu = true; domain = DISPLAY_WRITE_DOMAIN; + } } else { + use_iommu = true; domain = DISPLAY_READ_DOMAIN; } @@ -227,7 +230,7 @@ int mdp_munmap(struct v4l2_subdev *sd, void *arg) { struct mem_region_map *mmap = arg; struct mem_region *mregion; - bool use_iommu = false; + bool use_iommu = true; int domain = -1; struct mdp_instance *inst = NULL; @@ -242,9 +245,12 @@ int mdp_munmap(struct v4l2_subdev *sd, void *arg) if (inst->uses_iommu_split_domain) { if (inst->secure) use_iommu = false; - else + else { + use_iommu = true; domain = DISPLAY_WRITE_DOMAIN; + } } else { + use_iommu = true; domain = DISPLAY_READ_DOMAIN; } From fc0cf27d144867c0bd963582ab41f74a19acaf98 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Tue, 6 Nov 2012 20:03:53 -0800 Subject: [PATCH 2250/2357] Revert "USB: ensure parent device is resumed for child's system-resume" This reverts commit de86e6482897db0006151ae9154f181e75f5ab2c. Commit 7c8527ce ("PM: Prevent runtime suspend during system resume") fixes the general issue of a parent device being prematurely runtime suspended before a child device is resumed. It does so by moving the pm_runtime_put_sync() call from the device_resume() stage to device_complete(), which happens to act on the devices in reverse (children before parent) order. Thus when usb_resume() is called by device_resume(), we know its parent will be runtime PM enabled and its usage counter is still non-zero. This obviates the need to do an additional pm_runtime_get_sync() before calling usb_resume_both() as the device and its interfaces now have the opportunity to increment the parent's power.child_count if necessary without fear of having a runtime suspended parent. (cherry picked from commit d48e904824ec38f9db01fcaccb527063b4c5d894) Change-Id: I6d092c649889daf9483ed27aebe67df50d38ae91 CRs-fixed: 396041 Signed-off-by: Jack Pham --- drivers/usb/core/driver.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 9e3a49957cf..23826403b54 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1416,7 +1416,6 @@ int usb_resume(struct device *dev, pm_message_t msg) * (This can't be done in usb_resume_interface() * above because it doesn't own the right set of locks.) */ - pm_runtime_get_sync(dev->parent); status = usb_resume_both(udev, msg); if (status == 0) { pm_runtime_disable(dev); @@ -1424,7 +1423,6 @@ int usb_resume(struct device *dev, pm_message_t msg) pm_runtime_enable(dev); unbind_no_reset_resume_drivers_interfaces(udev); } - pm_runtime_put_sync(dev->parent); /* Avoid PM error messages for devices disconnected while suspended * as we'll display regular disconnect messages just a bit later. From c03cdb744746297d370d6b5c42e8ce82b6eebc08 Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Mon, 4 Feb 2013 19:19:01 -0500 Subject: [PATCH 2251/2357] msm_fb: Update MDP fence wait behaviour The current fence wait times out too early in cases where the GPU is under a heavy workload. Change this behaviour to warn and wait for a longer time for GPU to complete it's work. Change-Id: I8b20c22733a77c1aaea4a1fd1e4daaa14b5ec2fd Signed-off-by: Naseer Ahmed --- drivers/video/msm/msm_fb.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index 04304a295af..1861cb512a6 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -122,10 +122,11 @@ static int msm_fb_pan_idle(struct msm_fb_data_type *mfd); #define MSM_FB_MAX_DBGFS 1024 #define MAX_BACKLIGHT_BRIGHTNESS 255 -/* 900 ms for fence time out */ -#define WAIT_FENCE_TIMEOUT 900 -/* 950 ms for display operation time out */ -#define WAIT_DISP_OP_TIMEOUT 950 +#define WAIT_FENCE_FIRST_TIMEOUT MSEC_PER_SEC +#define WAIT_FENCE_FINAL_TIMEOUT 10 * MSEC_PER_SEC +/* Display op timeout should be greater than total timeout */ +#define WAIT_DISP_OP_TIMEOUT (WAIT_FENCE_FIRST_TIMEOUT +\ + WAIT_FENCE_FINAL_TIMEOUT) * MDP_MAX_FENCE_FD #define MAX_TIMELINE_NAME_LEN 16 int msm_fb_debugfs_file_index; @@ -1792,7 +1793,15 @@ void msm_fb_wait_for_fence(struct msm_fb_data_type *mfd) int i, ret = 0; /* buf sync */ for (i = 0; i < mfd->acq_fen_cnt; i++) { - ret = sync_fence_wait(mfd->acq_fen[i], WAIT_FENCE_TIMEOUT); + ret = sync_fence_wait(mfd->acq_fen[i], + WAIT_FENCE_FIRST_TIMEOUT); + if (ret == -ETIME) { + pr_warn("%s: sync_fence_wait timed out!" + "Waiting %ld more seconds\n", + __func__,WAIT_FENCE_FINAL_TIMEOUT/MSEC_PER_SEC); + ret = sync_fence_wait(mfd->acq_fen[i], + WAIT_FENCE_FINAL_TIMEOUT); + } if (ret < 0) { pr_err("%s: sync_fence_wait failed! ret = %x\n", __func__, ret); From baa25cc36d42e1bae3e091685b5dba6ad759e31b Mon Sep 17 00:00:00 2001 From: Hariram Purushothaman Date: Tue, 4 Dec 2012 16:55:39 -0800 Subject: [PATCH 2252/2357] msm:camera: Add new vfe32 commands Add new vfe32 commands for independent gamma R, G, B values update and config. Change-Id: If81b3c1257a64c5c26f8baf7264cae79cd682675 Signed-off-by: Hariram Purushothaman --- drivers/media/video/msm/vfe/msm_vfe32.c | 61 +++++++++++++++++++++++++ drivers/media/video/msm/vfe/msm_vfe32.h | 6 +++ include/media/msm_camera.h | 14 ------ include/media/msm_isp.h | 2 + 4 files changed, 69 insertions(+), 14 deletions(-) diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c index f537a2d3054..da8f00f44d9 100644 --- a/drivers/media/video/msm/vfe/msm_vfe32.c +++ b/drivers/media/video/msm/vfe/msm_vfe32.c @@ -2951,6 +2951,67 @@ static int vfe32_proc_general( cmdp -= 1; break; + case VFE_CMD_RGB_ALL_CFG: { + cmdp = kmalloc((cmd->length), GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_camera_io_memcpy( + vfe32_ctrl->share_ctrl->vfebase + V32_RGB_G_OFF, + cmdp, 4); + cmdp += 1; + + vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, + cmdp + VFE32_GAMMA_CH0_G_POS, vfe32_ctrl); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, + cmdp + VFE32_GAMMA_CH1_B_POS, vfe32_ctrl); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, + cmdp + VFE32_GAMMA_CH2_R_POS, vfe32_ctrl); + } + cmdp -= 1; + break; + + case VFE_CMD_RGB_ALL_UPDATE: { + cmdp = kmalloc((cmd->length), GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_camera_io_r( + vfe32_ctrl->share_ctrl->vfebase + V32_RGB_G_OFF); + cmdp += 1; + if (old_val != 0x0) { + vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, + cmdp + VFE32_GAMMA_CH0_G_POS, vfe32_ctrl); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, + cmdp + VFE32_GAMMA_CH1_B_POS, vfe32_ctrl); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, + cmdp + VFE32_GAMMA_CH2_R_POS, vfe32_ctrl); + } else { + vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK1, + cmdp + VFE32_GAMMA_CH0_G_POS, vfe32_ctrl); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK1, + cmdp + VFE32_GAMMA_CH1_B_POS, vfe32_ctrl); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK1, + cmdp + VFE32_GAMMA_CH2_R_POS, vfe32_ctrl); + } + } + vfe32_ctrl->update_gamma = TRUE; + cmdp -= 1; + break; + case VFE_CMD_RGB_G_UPDATE: { cmdp = kmalloc(cmd->length, GFP_ATOMIC); if (!cmdp) { diff --git a/drivers/media/video/msm/vfe/msm_vfe32.h b/drivers/media/video/msm/vfe/msm_vfe32.h index 322684cbbea..65257524bf7 100644 --- a/drivers/media/video/msm/vfe/msm_vfe32.h +++ b/drivers/media/video/msm/vfe/msm_vfe32.h @@ -543,6 +543,12 @@ enum VFE_YUV_INPUT_COSITING_MODE { #define VFE32_GAMMA_NUM_ENTRIES 64 +#define VFE32_GAMMA_CH0_G_POS 0 + +#define VFE32_GAMMA_CH1_B_POS 32 + +#define VFE32_GAMMA_CH2_R_POS 64 + #define VFE32_LA_TABLE_LENGTH 64 #define VFE32_LINEARIZATON_TABLE_LENGTH 36 diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h index 28314f72eda..d526cf7e87d 100644 --- a/include/media/msm_camera.h +++ b/include/media/msm_camera.h @@ -1034,20 +1034,6 @@ struct msm_snapshot_pp_status { #define SENSOR_QVGA_SIZE 2 #define SENSOR_INVALID_SIZE 3 -#define CAMERA_EFFECT_OFF 0 -#define CAMERA_EFFECT_MONO 1 -#define CAMERA_EFFECT_NEGATIVE 2 -#define CAMERA_EFFECT_SOLARIZE 3 -#define CAMERA_EFFECT_SEPIA 4 -#define CAMERA_EFFECT_POSTERIZE 5 -#define CAMERA_EFFECT_WHITEBOARD 6 -#define CAMERA_EFFECT_BLACKBOARD 7 -#define CAMERA_EFFECT_AQUA 8 -#define CAMERA_EFFECT_EMBOSS 9 -#define CAMERA_EFFECT_SKETCH 10 -#define CAMERA_EFFECT_NEON 11 -#define CAMERA_EFFECT_MAX 12 - /* QRD */ #define CAMERA_EFFECT_BW 10 #define CAMERA_EFFECT_BLUISH 12 diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h index 8811104f305..19953ac695d 100644 --- a/include/media/msm_isp.h +++ b/include/media/msm_isp.h @@ -239,6 +239,8 @@ #define VFE_CMD_TEST_GEN_CFG 162 #define VFE_CMD_SELECT_RDI 163 #define VFE_CMD_SET_STATS_VER 164 +#define VFE_CMD_RGB_ALL_CFG 165 +#define VFE_CMD_RGB_ALL_UPDATE 166 struct msm_isp_cmd { int32_t id; From 96134ff667407ae52a91e43066d6b6cdcc1a4f92 Mon Sep 17 00:00:00 2001 From: Huaibin Yang Date: Tue, 26 Feb 2013 15:27:49 -0800 Subject: [PATCH 2253/2357] msm_fb: display: balance secure map and unmap in each mfd Make sure secure map and unmap get called in each mfd and balanced. Otherwise, secure contents can not be played for both primary and hdmi. CRs-fixed: 450427 Change-Id: I5399be64fbb104dc3cbe2c5c65b3f4406f47473c Signed-off-by: Huaibin Yang --- drivers/video/msm/mdp4.h | 4 +-- drivers/video/msm/mdp4_overlay.c | 48 ++++++++++++++++++++++---------- drivers/video/msm/msm_fb.c | 2 +- drivers/video/msm/msm_fb.h | 2 ++ 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h index c303c8f44ef..7a2efc53c9b 100644 --- a/drivers/video/msm/mdp4.h +++ b/drivers/video/msm/mdp4.h @@ -974,9 +974,9 @@ void mdp4_wfd_init(int cndx); int mdp4_wfd_pipe_commit(struct msm_fb_data_type *mfd, int cndx, int wait); #endif #ifdef CONFIG_FB_MSM_OVERLAY -int mdp4_unmap_sec_resource(void); +int mdp4_unmap_sec_resource(struct msm_fb_data_type *mfd); #else -static inline void mdp4_unmap_sec_resource(void); +static inline void mdp4_unmap_sec_resource(struct msm_fb_data_type *mfd); { /* empty */ return 0; diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c index 942784219c6..51944e856fd 100644 --- a/drivers/video/msm/mdp4_overlay.c +++ b/drivers/video/msm/mdp4_overlay.c @@ -59,9 +59,6 @@ struct mdp4_overlay_ctrl { uint32 mixer0_played; uint32 mixer1_played; uint32 mixer2_played; - uint32 sec_mapped; - uint32 mmu_clk_on; - uint32 sec_active; } mdp4_overlay_db = { .cs_controller = CS_CONTROLLER_0, .plist = { @@ -123,10 +120,20 @@ struct mdp4_overlay_perf perf_current; static struct ion_client *display_iclient; -static int mdp4_map_sec_resource(void) +static int mdp4_map_sec_resource(struct msm_fb_data_type *mfd) { int ret = 0; - if (ctrl->sec_mapped) + + if (!mfd) { + pr_err("%s: mfd is invalid\n", __func__); + return -ENODEV; + } + + pr_debug("%s %d mfd->index=%d,mapped=%d,active=%d\n", + __func__, __LINE__, + mfd->index, mfd->sec_mapped, mfd->sec_active); + + if (mfd->sec_mapped) return 0; ret = mdp_enable_iommu_clocks(); @@ -139,24 +146,34 @@ static int mdp4_map_sec_resource(void) pr_err("ION heap secure failed heap id %d ret %d\n", ION_CP_MM_HEAP_ID, ret); else - ctrl->sec_mapped = 1; + mfd->sec_mapped = 1; mdp_disable_iommu_clocks(); return ret; } -int mdp4_unmap_sec_resource(void) +int mdp4_unmap_sec_resource(struct msm_fb_data_type *mfd) { int ret = 0; - if ((ctrl->sec_mapped == 0) || (ctrl->sec_active)) + + if (!mfd) { + pr_err("%s: mfd is invalid\n", __func__); + return -ENODEV; + } + + if ((mfd->sec_mapped == 0) || (mfd->sec_active)) return 0; + pr_debug("%s %d mfd->index=%d,mapped=%d,active=%d\n", + __func__, __LINE__, + mfd->index, mfd->sec_mapped, mfd->sec_active); + ret = mdp_enable_iommu_clocks(); if (ret) { pr_err("IOMMU clock enabled failed while close\n"); return ret; } msm_ion_unsecure_heap(ION_HEAP(ION_CP_MM_HEAP_ID)); - ctrl->sec_mapped = 0; + mfd->sec_mapped = 0; mdp_disable_iommu_clocks(); return ret; } @@ -3200,6 +3217,11 @@ int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req) return ret; } + if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) { + mdp4_map_sec_resource(mfd); + mfd->sec_active = TRUE; + } + /* return id back to user */ req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */ pipe->req_data = *req; /* keep original req */ @@ -3215,10 +3237,6 @@ int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req) } } - if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) { - mdp4_map_sec_resource(); - ctrl->sec_active = TRUE; - } mdp4_stat.overlay_set[pipe->mixer_num]++; if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) { @@ -3318,7 +3336,7 @@ int mdp4_overlay_unset(struct fb_info *info, int ndx) mdp4_stat.overlay_unset[pipe->mixer_num]++; if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) - ctrl->sec_active = FALSE; + mfd->sec_active = FALSE; mdp4_overlay_pipe_free(pipe); mutex_unlock(&mfd->dma->ov_mutex); @@ -3645,7 +3663,7 @@ int mdp4_overlay_commit(struct fb_info *info) msm_fb_signal_timeline(mfd); mdp4_overlay_mdp_perf_upd(mfd, 0); - mdp4_unmap_sec_resource(); + mdp4_unmap_sec_resource(mfd); mutex_unlock(&mfd->dma->ov_mutex); return ret; diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index 04304a295af..0209173b29f 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -2028,7 +2028,7 @@ static int msm_fb_pan_display_sub(struct fb_var_screeninfo *var, mdp_dma_pan_update(info); msm_fb_signal_timeline(mfd); - if (mdp4_unmap_sec_resource()) + if (mdp4_unmap_sec_resource(mfd)) pr_err("%s: unmap secure res failed\n", __func__); up(&msm_fb_pan_sem); diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h index 3eba41a9682..4b6f41f76c0 100644 --- a/drivers/video/msm/msm_fb.h +++ b/drivers/video/msm/msm_fb.h @@ -215,6 +215,8 @@ struct msm_fb_data_type { int vsync_sysfs_created; void *copy_splash_buf; unsigned char *copy_splash_phys; + uint32 sec_mapped; + uint32 sec_active; }; struct msm_fb_backup_type { struct fb_info info; From 9c706fb1ae094a92593223a741d6bd0e9ae512fd Mon Sep 17 00:00:00 2001 From: Sagar Dharia Date: Mon, 23 Jul 2012 19:38:57 -0600 Subject: [PATCH 2254/2357] slimbus: Callback to indicate device report present message Clients can register a callback (just like probe) and that callback will be called when the client's device reports present per slimbus specification. The callback is hosted in a workqueue to avoid doing it in same context from which probe is called (and/or in the context receiving report present message). Callback is called when the device reports present for the first time after the bus is initialized. Change-Id: I8396b87121950f99a09764d497bf2d4b1535565d Signed-off-by: Sagar Dharia (cherry picked from commit 0e7a1ef6292642d2c7c22fcaf8d5da1e7610f26d) --- drivers/slimbus/slimbus.c | 81 +++++++++++++++++++++++++++------ include/linux/slimbus/slimbus.h | 13 ++++++ 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c index 4ab803b67f6..4fcb1cdc8b7 100644 --- a/drivers/slimbus/slimbus.c +++ b/drivers/slimbus/slimbus.c @@ -176,16 +176,27 @@ module_exit(slimbus_exit); static int slim_drv_probe(struct device *dev) { const struct slim_driver *sdrv = to_slim_driver(dev->driver); + struct slim_device *sbdev = to_slim_device(dev); + struct slim_controller *ctrl = sbdev->ctrl; - if (sdrv->probe) - return sdrv->probe(to_slim_device(dev)); + if (sdrv->probe) { + int ret; + ret = sdrv->probe(sbdev); + if (ret) + return ret; + if (sdrv->device_up) + queue_work(ctrl->wq, &sbdev->wd); + return 0; + } return -ENODEV; } static int slim_drv_remove(struct device *dev) { const struct slim_driver *sdrv = to_slim_driver(dev->driver); + struct slim_device *sbdev = to_slim_device(dev); + sbdev->notified = false; if (sdrv->remove) return sdrv->remove(to_slim_device(dev)); return -ENODEV; @@ -263,6 +274,23 @@ static struct device_type slim_dev_type = { .release = slim_dev_release, }; +static void slim_report_present(struct work_struct *work) +{ + u8 laddr; + int ret; + struct slim_driver *sbdrv; + struct slim_device *sbdev = + container_of(work, struct slim_device, wd); + if (sbdev->notified || !sbdev->dev.driver) + return; + ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr); + sbdrv = to_slim_driver(sbdev->dev.driver); + if (!ret && sbdrv->device_up) { + sbdev->notified = true; + sbdrv->device_up(sbdev); + } +} + /* * slim_add_device: Add a new device without register board info. * @ctrl: Controller to which this device is to be added to. @@ -271,25 +299,23 @@ static struct device_type slim_dev_type = { */ int slim_add_device(struct slim_controller *ctrl, struct slim_device *sbdev) { - int ret = 0; - sbdev->dev.bus = &slimbus_type; sbdev->dev.parent = ctrl->dev.parent; sbdev->dev.type = &slim_dev_type; + sbdev->dev.driver = NULL; sbdev->ctrl = ctrl; slim_ctrl_get(ctrl); dev_set_name(&sbdev->dev, "%s", sbdev->name); - /* probe slave on this controller */ - ret = device_register(&sbdev->dev); - - if (ret) - return ret; - mutex_init(&sbdev->sldev_reconf); INIT_LIST_HEAD(&sbdev->mark_define); INIT_LIST_HEAD(&sbdev->mark_suspend); INIT_LIST_HEAD(&sbdev->mark_removal); - return 0; + INIT_WORK(&sbdev->wd, slim_report_present); + mutex_lock(&ctrl->m_ctrl); + list_add_tail(&sbdev->dev_list, &ctrl->devs); + mutex_unlock(&ctrl->m_ctrl); + /* probe slave on this controller */ + return device_register(&sbdev->dev); } EXPORT_SYMBOL_GPL(slim_add_device); @@ -431,6 +457,11 @@ static int slim_register_controller(struct slim_controller *ctrl) ctrl->sched.slots = kzalloc(SLIM_SL_PER_SUPERFRAME, GFP_KERNEL); #endif init_completion(&ctrl->pause_comp); + + INIT_LIST_HEAD(&ctrl->devs); + ctrl->wq = create_singlethread_workqueue(dev_name(&ctrl->dev)); + if (!ctrl->wq) + goto err_workq_failed; /* * If devices on a controller were registered before controller, * this will make sure that they get probed now that controller is up @@ -443,6 +474,10 @@ static int slim_register_controller(struct slim_controller *ctrl) return 0; +err_workq_failed: + kfree(ctrl->sched.chc3); + kfree(ctrl->sched.chc1); + kfree(ctrl->chans); err_chan_failed: kfree(ctrl->ports); err_port_failed: @@ -495,6 +530,7 @@ int slim_del_controller(struct slim_controller *ctrl) wait_for_completion(&ctrl->dev_released); list_del(&ctrl->list); + destroy_workqueue(ctrl->wq); /* free bus id */ mutex_lock(&slim_lock); idr_remove(&ctrl_idr, ctrl->nr); @@ -665,7 +701,8 @@ int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr, u8 e_len, u8 *laddr) { int ret; - u8 i; + u8 i = 0; + struct slim_device *sbdev; mutex_lock(&ctrl->m_ctrl); /* already assigned */ if (ctrl_getlogical_addr(ctrl, e_addr, e_len, laddr) == 0) @@ -704,7 +741,25 @@ int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr, dev_dbg(&ctrl->dev, "setting slimbus l-addr:%x\n", i); ret_assigned_laddr: mutex_unlock(&ctrl->m_ctrl); - return ret; + if (ret) + return ret; + + pr_info("slimbus laddr:0x%x, EAPC:0x%x:0x%x", i, + e_addr[1], e_addr[2]); + mutex_lock(&ctrl->m_ctrl); + list_for_each_entry(sbdev, &ctrl->devs, dev_list) { + if (memcmp(sbdev->e_addr, e_addr, 6) == 0) { + struct slim_driver *sbdrv; + if (sbdev->dev.driver) { + sbdrv = to_slim_driver(sbdev->dev.driver); + if (sbdrv->device_up) + queue_work(ctrl->wq, &sbdev->wd); + } + break; + } + } + mutex_unlock(&ctrl->m_ctrl); + return 0; } EXPORT_SYMBOL_GPL(slim_assign_laddr); diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h index a12bc447eb5..461a2bf66ab 100644 --- a/include/linux/slimbus/slimbus.h +++ b/include/linux/slimbus/slimbus.h @@ -479,6 +479,8 @@ enum slim_clk_state { * @m_ctrl: Mutex protecting controller data structures (ports, channels etc) * @addrt: Logical address table * @num_dev: Number of active slimbus slaves on this bus + * @devs: List of devices on this controller + * @wq: Workqueue per controller used to notify devices when they report present * @txnt: Table of transactions having transaction ID * @last_tid: size of the table txnt (can't grow beyond 256 since TID is 8-bits) * @ports: Ports associated with this controller @@ -525,6 +527,8 @@ struct slim_controller { struct mutex m_ctrl; struct slim_addrt *addrt; u8 num_dev; + struct list_head devs; + struct workqueue_struct *wq; struct slim_msg_txn **txnt; u8 last_tid; struct slim_port *ports; @@ -569,6 +573,7 @@ struct slim_driver { int (*suspend)(struct slim_device *sldev, pm_message_t pmesg); int (*resume)(struct slim_device *sldev); + int (*device_up)(struct slim_device *sldev); struct device_driver driver; const struct slim_device_id *id_table; @@ -601,6 +606,11 @@ struct slim_pending_ch { * @mark_define: List of channels pending definition/activation. * @mark_suspend: List of channels pending suspend. * @mark_removal: List of channels pending removal. + * @notified: Flag to indicate whether this device has been notified. The + * device may report present multiple times, but should be notified only + * first time it has reported present. + * @dev_list: List of devices on a controller + * @wd: Work structure associated with workqueue for presence notification * @sldev_reconf: Mutex to protect the pending data-channel lists. * @pending_msgsl: Message bandwidth reservation request by this client in * slots that's pending reconfiguration. @@ -619,6 +629,9 @@ struct slim_device { struct list_head mark_define; struct list_head mark_suspend; struct list_head mark_removal; + bool notified; + struct list_head dev_list; + struct work_struct wd; struct mutex sldev_reconf; u32 pending_msgsl; u32 cur_msgsl; From 36097c4a7d5fbf7d2a7155637cacda20bf799b20 Mon Sep 17 00:00:00 2001 From: Sagar Dharia Date: Tue, 24 Jul 2012 23:44:26 -0600 Subject: [PATCH 2255/2357] slimbus: Allow controller to override default scheduling algorithm Framework provides a slimbus scheduling algorithm and controller may choose to override it. e.g. controller will override this if it supports fixed set of channels at a fixed clock gear. In that case, it is controller's responsibility to act on client requests and update channel scheduling, subframe coding information. Change-Id: I31fe72ef85f931900467b737652da7516d173dc5 Signed-off-by: Sagar Dharia (cherry picked from commit 4aec9230916f844d89b2565d09a7b874f181d5e0) --- drivers/slimbus/slimbus.c | 10 +++++++++- include/linux/slimbus/slimbus.h | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c index 4fcb1cdc8b7..8d2f7d905ef 100644 --- a/drivers/slimbus/slimbus.c +++ b/drivers/slimbus/slimbus.c @@ -2633,7 +2633,15 @@ int slim_reconfigure_now(struct slim_device *sb) slc->state = SLIM_CH_SUSPENDED; } - ret = slim_allocbw(sb, &subframe, &clkgear); + /* + * Controller can override default channel scheduling algorithm. + * (e.g. if controller needs to use fixed channel scheduling based + * on number of channels) + */ + if (ctrl->allocbw) + ret = ctrl->allocbw(sb, &subframe, &clkgear); + else + ret = slim_allocbw(sb, &subframe, &clkgear); if (!ret) { ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST, diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h index 461a2bf66ab..c5031c10d5d 100644 --- a/include/linux/slimbus/slimbus.h +++ b/include/linux/slimbus/slimbus.h @@ -498,6 +498,8 @@ enum slim_clk_state { * @set_laddr: Setup logical address at laddr for the slave with elemental * address e_addr. Drivers implementing controller will be expected to * send unicast message to this device with its logical address. + * @allocbw: Controller can override default reconfiguration and channel + * scheduling algorithm. * @wakeup: This function pointer implements controller-specific procedure * to wake it up from clock-pause. Framework will call this to bring * the controller out of clock pause. @@ -542,6 +544,8 @@ struct slim_controller { struct slim_msg_txn *txn); int (*set_laddr)(struct slim_controller *ctrl, const u8 *ea, u8 elen, u8 laddr); + int (*allocbw)(struct slim_device *sb, + int *subfrmc, int *clkgear); int (*wakeup)(struct slim_controller *ctrl); int (*config_port)(struct slim_controller *ctrl, u8 port); From 6d43009e09a3d99630b9198e7a64a93b2e12d00f Mon Sep 17 00:00:00 2001 From: Sagar Dharia Date: Sun, 9 Sep 2012 17:32:46 -0600 Subject: [PATCH 2256/2357] slimbus: Allow controller to specify logical addresses It is possible that the controller has fixed addressing table for enumeration devices. In that case, logical address will be set by controller and not by framework. get_laddr allows a controller to assign logical address. Make sure framework allows such addressing by not assuming that index into address table will represent logical address. Change-Id: I0e3873980c2ee2ece01237f450ecefff4e99aedc Signed-off-by: Sagar Dharia (cherry picked from commit f0b9c75110471242b8c832457ef7b8b9444e42f3) --- drivers/slimbus/slim-msm-ctrl.c | 3 ++- drivers/slimbus/slimbus.c | 46 ++++++++++++++++++++++----------- include/linux/slimbus/slimbus.h | 17 ++++++++++-- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c index b7081333e07..c1ba63857dc 100644 --- a/drivers/slimbus/slim-msm-ctrl.c +++ b/drivers/slimbus/slim-msm-ctrl.c @@ -1194,7 +1194,8 @@ static void msm_slim_rxwq(struct msm_slim_ctrl *dev) for (i = 0; i < 6; i++) e_addr[i] = buf[7-i]; - ret = slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr); + ret = slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr, + false); /* Is this Qualcomm ported generic device? */ if (!ret && e_addr[5] == QC_MFGID_LSB && e_addr[4] == QC_MFGID_MSB && diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c index 8d2f7d905ef..1819e2c0592 100644 --- a/drivers/slimbus/slimbus.c +++ b/drivers/slimbus/slimbus.c @@ -673,13 +673,13 @@ static int slim_processtxn(struct slim_controller *ctrl, u8 dt, u16 mc, u16 ec, } static int ctrl_getlogical_addr(struct slim_controller *ctrl, const u8 *eaddr, - u8 e_len, u8 *laddr) + u8 e_len, u8 *entry) { u8 i; for (i = 0; i < ctrl->num_dev; i++) { if (ctrl->addrt[i].valid && memcmp(ctrl->addrt[i].eaddr, eaddr, e_len) == 0) { - *laddr = i; + *entry = i; return 0; } } @@ -691,23 +691,28 @@ static int ctrl_getlogical_addr(struct slim_controller *ctrl, const u8 *eaddr, * @ctrl: Controller with which device is enumerated. * @e_addr: 6-byte elemental address of the device. * @e_len: buffer length for e_addr - * @laddr: Return logical address. + * @laddr: Return logical address (if valid flag is false) + * @valid: true if laddr holds a valid address that controller wants to + * set for this enumeration address. Otherwise framework sets index into + * address table as logical address. * Called by controller in response to REPORT_PRESENT. Framework will assign * a logical address to this enumeration address. * Function returns -EXFULL to indicate that all logical addresses are already * taken. */ int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr, - u8 e_len, u8 *laddr) + u8 e_len, u8 *laddr, bool valid) { int ret; u8 i = 0; + bool exists = false; struct slim_device *sbdev; mutex_lock(&ctrl->m_ctrl); /* already assigned */ - if (ctrl_getlogical_addr(ctrl, e_addr, e_len, laddr) == 0) - i = *laddr; - else { + if (ctrl_getlogical_addr(ctrl, e_addr, e_len, &i) == 0) { + *laddr = ctrl->addrt[i].laddr; + exists = true; + } else { if (ctrl->num_dev >= 254) { ret = -EXFULL; goto ret_assigned_laddr; @@ -729,22 +734,26 @@ int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr, } memcpy(ctrl->addrt[i].eaddr, e_addr, e_len); ctrl->addrt[i].valid = true; + /* Preferred address is index into table */ + if (!valid) + *laddr = i; } - ret = ctrl->set_laddr(ctrl, ctrl->addrt[i].eaddr, 6, i); + ret = ctrl->set_laddr(ctrl, (const u8 *)&ctrl->addrt[i].eaddr, 6, + *laddr); if (ret) { ctrl->addrt[i].valid = false; goto ret_assigned_laddr; } - *laddr = i; + ctrl->addrt[i].laddr = *laddr; - dev_dbg(&ctrl->dev, "setting slimbus l-addr:%x\n", i); + dev_dbg(&ctrl->dev, "setting slimbus l-addr:%x\n", *laddr); ret_assigned_laddr: mutex_unlock(&ctrl->m_ctrl); - if (ret) + if (exists || ret) return ret; - pr_info("slimbus laddr:0x%x, EAPC:0x%x:0x%x", i, + pr_info("slimbus:%d laddr:0x%x, EAPC:0x%x:0x%x", ctrl->nr, *laddr, e_addr[1], e_addr[2]); mutex_lock(&ctrl->m_ctrl); list_for_each_entry(sbdev, &ctrl->devs, dev_list) { @@ -777,12 +786,21 @@ int slim_get_logical_addr(struct slim_device *sb, const u8 *e_addr, u8 e_len, u8 *laddr) { int ret = 0; + u8 entry; struct slim_controller *ctrl = sb->ctrl; if (!ctrl || !laddr || !e_addr || e_len != 6) return -EINVAL; mutex_lock(&ctrl->m_ctrl); - ret = ctrl_getlogical_addr(ctrl, e_addr, e_len, laddr); + ret = ctrl_getlogical_addr(ctrl, e_addr, e_len, &entry); + if (!ret) + *laddr = ctrl->addrt[entry].laddr; mutex_unlock(&ctrl->m_ctrl); + if (ret == -ENXIO && ctrl->get_laddr) { + ret = ctrl->get_laddr(ctrl, e_addr, e_len, laddr); + if (!ret) + ret = slim_assign_laddr(ctrl, e_addr, e_len, laddr, + true); + } return ret; } EXPORT_SYMBOL_GPL(slim_get_logical_addr); @@ -935,8 +953,6 @@ int slim_xfer_msg(struct slim_controller *ctrl, struct slim_device *sbdev, u16 ec; u8 tid, mlen = 6; - if (sbdev->laddr != SLIM_LA_MANAGER && sbdev->laddr >= ctrl->num_dev) - return -ENXIO; ret = slim_ele_access_sanity(msg, mc, rbuf, wbuf, len); if (ret) goto xfer_err; diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h index c5031c10d5d..f06f6326323 100644 --- a/include/linux/slimbus/slimbus.h +++ b/include/linux/slimbus/slimbus.h @@ -143,10 +143,15 @@ struct slim_framer { * struct slim_addrt: slimbus address used internally by the slimbus framework. * @valid: If the device is still there or if the address can be reused. * @eaddr: 6-bytes-long elemental address + * @laddr: It is possible that controller will set a predefined logical address + * rather than the one assigned by framework. (i.e. logical address may + * not be same as index into this table). This entry will store the + * logical address value for this enumeration address. */ struct slim_addrt { bool valid; u8 eaddr[6]; + u8 laddr; }; /* @@ -500,6 +505,9 @@ enum slim_clk_state { * send unicast message to this device with its logical address. * @allocbw: Controller can override default reconfiguration and channel * scheduling algorithm. + * @get_laddr: It is possible that controller needs to set fixed logical + * address table and get_laddr can be used in that case so that controller + * can do this assignment. * @wakeup: This function pointer implements controller-specific procedure * to wake it up from clock-pause. Framework will call this to bring * the controller out of clock pause. @@ -546,6 +554,8 @@ struct slim_controller { const u8 *ea, u8 elen, u8 laddr); int (*allocbw)(struct slim_device *sb, int *subfrmc, int *clkgear); + int (*get_laddr)(struct slim_controller *ctrl, + const u8 *ea, u8 elen, u8 *laddr); int (*wakeup)(struct slim_controller *ctrl); int (*config_port)(struct slim_controller *ctrl, u8 port); @@ -983,14 +993,17 @@ extern void slim_remove_device(struct slim_device *sbdev); * @ctrl: Controller with which device is enumerated. * @e_addr: 6-byte elemental address of the device. * @e_len: buffer length for e_addr - * @laddr: Return logical address. + * @laddr: Return logical address (if valid flag is false) + * @valid: true if laddr holds a valid address that controller wants to + * set for this enumeration address. Otherwise framework sets index into + * address table as logical address. * Called by controller in response to REPORT_PRESENT. Framework will assign * a logical address to this enumeration address. * Function returns -EXFULL to indicate that all logical addresses are already * taken. */ extern int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr, - u8 e_len, u8 *laddr); + u8 e_len, u8 *laddr, bool valid); /* * slim_msg_response: Deliver Message response received from a device to the From 6cf304e04a5d602b2137b5bd960042619253b1c2 Mon Sep 17 00:00:00 2001 From: Sagar Dharia Date: Tue, 30 Oct 2012 21:12:09 -0600 Subject: [PATCH 2257/2357] slimbus: Populate slimbus device's logical address during assignment Slimbus device is assigned logical address when it reports present. Make sure to populate the device's logical address (laddr) during this assignment. CRs-Fixed: 412148 Change-Id: Icb8d74f6ea71aff8f6cb30523002f7839e2cb028 Signed-off-by: Sagar Dharia (cherry picked from commit 33c84e6255c03f15f6c6a46ec9e428e27fb35639) --- drivers/slimbus/slimbus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c index 1819e2c0592..977e6f3d100 100644 --- a/drivers/slimbus/slimbus.c +++ b/drivers/slimbus/slimbus.c @@ -759,6 +759,7 @@ int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr, list_for_each_entry(sbdev, &ctrl->devs, dev_list) { if (memcmp(sbdev->e_addr, e_addr, 6) == 0) { struct slim_driver *sbdrv; + sbdev->laddr = *laddr; if (sbdev->dev.driver) { sbdrv = to_slim_driver(sbdev->dev.driver); if (sbdrv->device_up) From a3720ae08c443c15e667ab71121139f1bf948298 Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Fri, 18 Jan 2013 15:58:29 -0800 Subject: [PATCH 2258/2357] SoC: msm: Set soft step values to 0 to avoid noise The abrupt steps in the curve are causing the noise. To avoid noise smaller step size are recommended. CRs-fixed: 439933 Change-Id: I34681af412e4f7ba8a99ce0f08f5ee1fa69186ff Signed-off-by: Fred Oh --- include/sound/q6asm.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h index 257026e1001..31bfa24d19a 100644 --- a/include/sound/q6asm.h +++ b/include/sound/q6asm.h @@ -81,18 +81,18 @@ #define SESSION_MAX 0x08 -#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */ +#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */ #define SOFT_PAUSE_STEP_LINEAR 0 /* Step value 0ms or 0us */ -#define SOFT_PAUSE_STEP 2000 /* Step value 2000ms or 2000us */ +#define SOFT_PAUSE_STEP 0 /* Step value 0ms or 0us */ enum { SOFT_PAUSE_CURVE_LINEAR = 0, SOFT_PAUSE_CURVE_EXP, SOFT_PAUSE_CURVE_LOG, }; -#define SOFT_VOLUME_PERIOD 30 /* ramp up/down for 30ms */ +#define SOFT_VOLUME_PERIOD 30 /* ramp up/down for 30ms */ #define SOFT_VOLUME_STEP_LINEAR 0 /* Step value 0ms or 0us */ -#define SOFT_VOLUME_STEP 2000 /* Step value 2000ms or 2000us */ +#define SOFT_VOLUME_STEP 0 /* Step value 0ms or 0us */ enum { SOFT_VOLUME_CURVE_LINEAR = 0, SOFT_VOLUME_CURVE_EXP, From 4c69856ae0cb138740c0178786f3f3193dcb3843 Mon Sep 17 00:00:00 2001 From: Satish Babu Patakokila Date: Mon, 3 Sep 2012 17:09:07 +0530 Subject: [PATCH 2259/2357] ASoC:msm:Add support for Voice Features on SGLTE Call - For every put command from userspace, flags related to Voice Features (TTY,WV etc) are updated for both Voice and SGLTE Sessions. - Since either SGLTE or Voice Call will be active at any given point of time, flags for both the sessions should be upated. Change-Id: Iab9f3aa4938eabce7e81d59938a8ebd7a4119857 Signed-off-by: VidyaKumar Athota --- sound/soc/msm/msm-pcm-voice.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c index 80dbaecfb5c..a545564f3b4 100644 --- a/sound/soc/msm/msm-pcm-voice.c +++ b/sound/soc/msm/msm-pcm-voice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -464,6 +464,7 @@ static int msm_voice_tty_mode_put(struct snd_kcontrol *kcontrol, voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode); + voc_set_tty_mode(voc_get_session_id(SGLTE_SESSION_NAME), tty_mode); return 0; } static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol, @@ -475,7 +476,8 @@ static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol, voc_set_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME), wv_enable); - + voc_set_widevoice_enable(voc_get_session_id(SGLTE_SESSION_NAME), + wv_enable); return 0; } @@ -497,6 +499,8 @@ static int msm_voice_slowtalk_put(struct snd_kcontrol *kcontrol, voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME), MODULE_ID_VOICE_MODULE_ST, st_enable); + voc_set_pp_enable(voc_get_session_id(SGLTE_SESSION_NAME), + MODULE_ID_VOICE_MODULE_ST, st_enable); return 0; } @@ -519,6 +523,8 @@ static int msm_voice_fens_put(struct snd_kcontrol *kcontrol, voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME), MODULE_ID_VOICE_MODULE_FENS, fens_enable); + voc_set_pp_enable(voc_get_session_id(SGLTE_SESSION_NAME), + MODULE_ID_VOICE_MODULE_FENS, fens_enable); return 0; } From 6d9fdc8c2282f2e4eac14a317b1dad6329d8c4bc Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Mon, 25 Feb 2013 21:42:18 +0530 Subject: [PATCH 2260/2357] USB: mdm_bridge: Simplify data bridge suspend/resume path Synchronous runtime PM API is used to increment the PM usage counter in Tx path. It means Tx data path will not race with interface suspend. Remove "delayed" anchor which is meant for Tx requests, that are arrived during suspend. There is no point in distinguishing auto suspend and system wide suspend. Abort suspend when we have pending Tx URBs. CRs-Fixed: 451414 Change-Id: I302b120ccecfe30db1ebd2b1fcd9945a3675cf83 Signed-off-by: Pavankumar Kondeti --- drivers/usb/misc/mdm_data_bridge.c | 81 ++++++------------------------ 1 file changed, 14 insertions(+), 67 deletions(-) diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c index 59dac50a49d..0c82b8a96ba 100644 --- a/drivers/usb/misc/mdm_data_bridge.c +++ b/drivers/usb/misc/mdm_data_bridge.c @@ -99,9 +99,6 @@ struct data_bridge { struct usb_anchor tx_active; struct usb_anchor rx_active; - /* keep track of outgoing URBs during suspend */ - struct usb_anchor delayed; - struct list_head rx_idle; struct sk_buff_head rx_done; @@ -437,7 +434,6 @@ void data_bridge_close(unsigned int id) usb_kill_anchored_urbs(&dev->tx_active); usb_kill_anchored_urbs(&dev->rx_active); - usb_kill_anchored_urbs(&dev->delayed); spin_lock_irqsave(&dev->rx_done.lock, flags); while ((skb = __skb_dequeue(&dev->rx_done))) @@ -596,11 +592,6 @@ int data_bridge_write(unsigned int id, struct sk_buff *skb) txurb->transfer_flags |= URB_ZERO_PACKET; - if (test_bit(SUSPENDED, &dev->flags)) { - usb_anchor_urb(txurb, &dev->delayed); - goto free_urb; - } - pending = atomic_inc_return(&dev->pending_txurbs); usb_anchor_urb(txurb, &dev->tx_active); @@ -640,82 +631,39 @@ int data_bridge_write(unsigned int id, struct sk_buff *skb) } EXPORT_SYMBOL(data_bridge_write); -static int data_bridge_resume(struct data_bridge *dev) -{ - struct urb *urb; - int retval; - - if (!test_and_clear_bit(SUSPENDED, &dev->flags)) - return 0; - - while ((urb = usb_get_from_anchor(&dev->delayed))) { - usb_anchor_urb(urb, &dev->tx_active); - atomic_inc(&dev->pending_txurbs); - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval < 0) { - atomic_dec(&dev->pending_txurbs); - usb_unanchor_urb(urb); - - /* TODO: need to free urb data */ - usb_scuttle_anchored_urbs(&dev->delayed); - break; - } - dev->to_modem++; - dev->txurb_drp_cnt--; - } - - if (dev->brdg) - queue_work(dev->wq, &dev->process_rx_w); - - return 0; -} - static int bridge_resume(struct usb_interface *iface) { int retval = 0; - int oldstate; struct data_bridge *dev = usb_get_intfdata(iface); - oldstate = iface->dev.power.power_state.event; - iface->dev.power.power_state.event = PM_EVENT_ON; + clear_bit(SUSPENDED, &dev->flags); - if (oldstate & PM_EVENT_SUSPEND) { - retval = data_bridge_resume(dev); - if (!retval) - retval = ctrl_bridge_resume(dev->id); - } + if (dev->brdg) + queue_work(dev->wq, &dev->process_rx_w); + + retval = ctrl_bridge_resume(dev->id); return retval; } -static int data_bridge_suspend(struct data_bridge *dev, pm_message_t message) +static int bridge_suspend(struct usb_interface *intf, pm_message_t message) { - if (atomic_read(&dev->pending_txurbs) && - (message.event & PM_EVENT_AUTO)) + int retval; + struct data_bridge *dev = usb_get_intfdata(intf); + + if (atomic_read(&dev->pending_txurbs)) return -EBUSY; - set_bit(SUSPENDED, &dev->flags); + retval = ctrl_bridge_suspend(dev->id); + if (retval) + return retval; - usb_kill_anchored_urbs(&dev->tx_active); + set_bit(SUSPENDED, &dev->flags); usb_kill_anchored_urbs(&dev->rx_active); return 0; } -static int bridge_suspend(struct usb_interface *intf, pm_message_t message) -{ - int retval; - struct data_bridge *dev = usb_get_intfdata(intf); - - retval = data_bridge_suspend(dev, message); - if (!retval) { - retval = ctrl_bridge_suspend(dev->id); - intf->dev.power.power_state.event = message.event; - } - - return retval; -} - static int data_bridge_probe(struct usb_interface *iface, struct usb_host_endpoint *bulk_in, struct usb_host_endpoint *bulk_out, char *name, int id) @@ -1178,7 +1126,6 @@ static int __init bridge_init(void) init_usb_anchor(&dev->tx_active); init_usb_anchor(&dev->rx_active); - init_usb_anchor(&dev->delayed); INIT_LIST_HEAD(&dev->rx_idle); From 6252c3682957f9bc3f48c660904d79f1d2e24b16 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Mon, 25 Feb 2013 21:57:54 +0530 Subject: [PATCH 2261/2357] USB: mdm_bridge: Fix control bridge suspend The current code does not abort suspend when there are pending URBs. They are simply killed during suspend. This may lead to QMI stall. Add proper checks to ensure that there is no pending Tx/Rx data during suspend. Clear the "SUSPENDED" flag in resume only after taking out all the URBs from "tx_deferred" anchor. CRs-Fixed: 451414 Change-Id: Icc48afc5eeedcc126d0ab1bec951bde4a53ac165 Signed-off-by: Pavankumar Kondeti --- drivers/usb/misc/mdm_ctrl_bridge.c | 133 +++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 35 deletions(-) diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c index 69e28e4ce1e..dab90229fb8 100644 --- a/drivers/usb/misc/mdm_ctrl_bridge.c +++ b/drivers/usb/misc/mdm_ctrl_bridge.c @@ -35,6 +35,12 @@ #define SUSPENDED BIT(0) +enum ctrl_bridge_rx_state { + RX_IDLE, /* inturb is not queued */ + RX_WAIT, /* inturb is queued and waiting for data */ + RX_BUSY, /* inturb is completed. processing RX */ +}; + struct ctrl_bridge { struct usb_device *udev; struct usb_interface *intf; @@ -63,6 +69,9 @@ struct ctrl_bridge { /* output control lines (DTR, RTS) */ unsigned int cbits_tomdm; + spinlock_t lock; + enum ctrl_bridge_rx_state rx_state; + /* counters */ unsigned int snd_encap_cmd; unsigned int get_encap_res; @@ -133,12 +142,39 @@ int ctrl_bridge_set_cbits(unsigned int id, unsigned int cbits) } EXPORT_SYMBOL(ctrl_bridge_set_cbits); +static int ctrl_bridge_start_read(struct ctrl_bridge *dev, gfp_t gfp_flags) +{ + int retval = 0; + unsigned long flags; + + if (!dev->inturb) { + dev_err(&dev->intf->dev, "%s: inturb is NULL\n", __func__); + return -ENODEV; + } + + retval = usb_submit_urb(dev->inturb, gfp_flags); + if (retval < 0 && retval != -EPERM) { + dev_err(&dev->intf->dev, + "%s error submitting int urb %d\n", + __func__, retval); + } + + spin_lock_irqsave(&dev->lock, flags); + if (retval) + dev->rx_state = RX_IDLE; + else + dev->rx_state = RX_WAIT; + spin_unlock_irqrestore(&dev->lock, flags); + + return retval; +} + static void resp_avail_cb(struct urb *urb) { struct ctrl_bridge *dev = urb->context; - int status = 0; int resubmit_urb = 1; struct bridge *brdg = dev->brdg; + unsigned long flags; /*usb device disconnect*/ if (urb->dev->state == USB_STATE_NOTATTACHED) @@ -170,12 +206,14 @@ static void resp_avail_cb(struct urb *urb) if (resubmit_urb) { /*re- submit int urb to check response available*/ - status = usb_submit_urb(dev->inturb, GFP_ATOMIC); - if (status) - dev_err(&dev->intf->dev, - "%s: Error re-submitting Int URB %d\n", - __func__, status); + ctrl_bridge_start_read(dev, GFP_ATOMIC); + } else { + spin_lock_irqsave(&dev->lock, flags); + dev->rx_state = RX_IDLE; + spin_unlock_irqrestore(&dev->lock, flags); } + + usb_autopm_put_interface_async(dev->intf); } static void notification_available_cb(struct urb *urb) @@ -186,11 +224,16 @@ static void notification_available_cb(struct urb *urb) struct bridge *brdg = dev->brdg; unsigned int ctrl_bits; unsigned char *data; + unsigned long flags; /*usb device disconnect*/ if (urb->dev->state == USB_STATE_NOTATTACHED) return; + spin_lock_irqsave(&dev->lock, flags); + dev->rx_state = RX_IDLE; + spin_unlock_irqrestore(&dev->lock, flags); + switch (urb->status) { case 0: /*success*/ @@ -217,7 +260,11 @@ static void notification_available_cb(struct urb *urb) switch (ctrl->bNotificationType) { case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: + spin_lock_irqsave(&dev->lock, flags); + dev->rx_state = RX_BUSY; + spin_unlock_irqrestore(&dev->lock, flags); dev->resp_avail++; + usb_autopm_get_interface_no_resume(dev->intf); usb_fill_control_urb(dev->readurb, dev->udev, usb_rcvctrlpipe(dev->udev, 0), (unsigned char *)dev->in_ctlreq, @@ -230,6 +277,7 @@ static void notification_available_cb(struct urb *urb) dev_err(&dev->intf->dev, "%s: Error submitting Read URB %d\n", __func__, status); + usb_autopm_put_interface_async(dev->intf); goto resubmit_int_urb; } return; @@ -253,28 +301,7 @@ static void notification_available_cb(struct urb *urb) } resubmit_int_urb: - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) - dev_err(&dev->intf->dev, "%s: Error re-submitting Int URB %d\n", - __func__, status); -} - -static int ctrl_bridge_start_read(struct ctrl_bridge *dev) -{ - int retval = 0; - - if (!dev->inturb) { - dev_err(&dev->intf->dev, "%s: inturb is NULL\n", __func__); - return -ENODEV; - } - - retval = usb_submit_urb(dev->inturb, GFP_KERNEL); - if (retval < 0) - dev_err(&dev->intf->dev, - "%s error submitting int urb %d\n", - __func__, retval); - - return retval; + ctrl_bridge_start_read(dev, GFP_ATOMIC); } int ctrl_bridge_open(struct bridge *brdg) @@ -356,6 +383,7 @@ int ctrl_bridge_write(unsigned int id, char *data, size_t size) struct urb *writeurb; struct usb_ctrlrequest *out_ctlreq; struct ctrl_bridge *dev; + unsigned long flags; if (id >= MAX_BRIDGE_DEVICES) { result = -EINVAL; @@ -424,12 +452,15 @@ int ctrl_bridge_write(unsigned int id, char *data, size_t size) goto free_ctrlreq; } + spin_lock_irqsave(&dev->lock, flags); if (test_bit(SUSPENDED, &dev->flags)) { usb_anchor_urb(writeurb, &dev->tx_deferred); + spin_unlock_irqrestore(&dev->lock, flags); goto deferred; } usb_anchor_urb(writeurb, &dev->tx_submitted); + spin_unlock_irqrestore(&dev->lock, flags); result = usb_submit_urb(writeurb, GFP_ATOMIC); if (result < 0) { dev_err(&dev->intf->dev, "%s: submit URB error %d\n", @@ -456,6 +487,7 @@ EXPORT_SYMBOL(ctrl_bridge_write); int ctrl_bridge_suspend(unsigned int id) { struct ctrl_bridge *dev; + unsigned long flags; if (id >= MAX_BRIDGE_DEVICES) return -EINVAL; @@ -464,10 +496,27 @@ int ctrl_bridge_suspend(unsigned int id) if (!dev) return -ENODEV; - set_bit(SUSPENDED, &dev->flags); + spin_lock_irqsave(&dev->lock, flags); + if (!usb_anchor_empty(&dev->tx_submitted) || dev->rx_state == RX_BUSY) { + spin_unlock_irqrestore(&dev->lock, flags); + return -EBUSY; + } + spin_unlock_irqrestore(&dev->lock, flags); + usb_kill_urb(dev->inturb); - usb_kill_urb(dev->readurb); - usb_kill_anchored_urbs(&dev->tx_submitted); + + spin_lock_irqsave(&dev->lock, flags); + if (dev->rx_state != RX_IDLE) { + spin_unlock_irqrestore(&dev->lock, flags); + return -EBUSY; + } + if (!usb_anchor_empty(&dev->tx_submitted)) { + spin_unlock_irqrestore(&dev->lock, flags); + ctrl_bridge_start_read(dev, GFP_KERNEL); + return -EBUSY; + } + set_bit(SUSPENDED, &dev->flags); + spin_unlock_irqrestore(&dev->lock, flags); return 0; } @@ -476,6 +525,8 @@ int ctrl_bridge_resume(unsigned int id) { struct ctrl_bridge *dev; struct urb *urb; + unsigned long flags; + int ret; if (id >= MAX_BRIDGE_DEVICES) return -EINVAL; @@ -484,12 +535,19 @@ int ctrl_bridge_resume(unsigned int id) if (!dev) return -ENODEV; - if (!test_and_clear_bit(SUSPENDED, &dev->flags)) + if (!test_bit(SUSPENDED, &dev->flags)) return 0; + spin_lock_irqsave(&dev->lock, flags); /* submit pending write requests */ while ((urb = usb_get_from_anchor(&dev->tx_deferred))) { - int ret; + spin_unlock_irqrestore(&dev->lock, flags); + /* + * usb_get_from_anchor() does not drop the + * ref count incremented by the usb_anchro_urb() + * called in Tx submission path. Let us do it. + */ + usb_put_urb(urb); usb_anchor_urb(urb, &dev->tx_submitted); ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { @@ -499,9 +557,12 @@ int ctrl_bridge_resume(unsigned int id) usb_free_urb(urb); usb_autopm_put_interface_async(dev->intf); } + spin_lock_irqsave(&dev->lock, flags); } + clear_bit(SUSPENDED, &dev->flags); + spin_unlock_irqrestore(&dev->lock, flags); - return ctrl_bridge_start_read(dev); + return ctrl_bridge_start_read(dev, GFP_KERNEL); } #if defined(CONFIG_DEBUG_FS) @@ -698,7 +759,7 @@ ctrl_bridge_probe(struct usb_interface *ifc, struct usb_host_endpoint *int_in, platform_device_add(dev->pdev); - return ctrl_bridge_start_read(dev); + return ctrl_bridge_start_read(dev, GFP_KERNEL); free_rbuf: kfree(dev->readbuf); @@ -727,6 +788,7 @@ void ctrl_bridge_disconnect(unsigned int id) platform_device_unregister(dev->pdev); + usb_scuttle_anchored_urbs(&dev->tx_deferred); usb_kill_anchored_urbs(&dev->tx_submitted); usb_kill_urb(dev->inturb); @@ -758,6 +820,7 @@ int ctrl_bridge_init(void) /*transport name will be set during probe*/ dev->name = "none"; + spin_lock_init(&dev->lock); init_usb_anchor(&dev->tx_submitted); init_usb_anchor(&dev->tx_deferred); From 9f3b2eef929f6878c83d90a64f1f8296d8641932 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Thu, 28 Feb 2013 10:11:37 +0530 Subject: [PATCH 2262/2357] USB: Rate limit adb open and release messages The print messages are helpful in debugging adb stability issues. However they get flooded if adb daemon is restarted continuously. If serial console is enabled this is leading to watchdog bark. CRs-Fixed: 456662 Change-Id: I1381d44b7a5081ee04053c739b9c83111b191125 Signed-off-by: Pavankumar Kondeti --- drivers/usb/gadget/f_adb.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c index dabb6735ccb..4445dc28831 100644 --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -420,7 +420,10 @@ static ssize_t adb_write(struct file *fp, const char __user *buf, static int adb_open(struct inode *ip, struct file *fp) { - pr_info("adb_open\n"); + static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1); + + if (__ratelimit(&rl)) + pr_info("adb_open\n"); if (!_adb_dev) return -ENODEV; @@ -443,7 +446,10 @@ static int adb_open(struct inode *ip, struct file *fp) static int adb_release(struct inode *ip, struct file *fp) { - pr_info("adb_release\n"); + static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1); + + if (__ratelimit(&rl)) + pr_info("adb_release\n"); /* * ADB daemon closes the device file after I/O error. The From a7bb2928f1c536b29fecd6f0940fa30099b319c9 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Thu, 28 Feb 2013 10:19:40 +0530 Subject: [PATCH 2263/2357] USB: android: Rate limit android enable warning An error message is printed when user space tries to enable/disable android configuration when it is already enabled/disabled. This message is helpful in debugging USB composition issues. However this message is getting flooded in an error condition. If serial console is enabled, it is leading to watchdog bark. CRs-Fixed: 457725 Change-Id: I2d61ac46ba3c8464bada23a64ad0d8027a4adfe9 Signed-off-by: Pavankumar Kondeti --- drivers/usb/gadget/android.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 5b83cb4d59f..52ea9e15a7c 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -2105,6 +2105,7 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, struct android_usb_function *f; struct android_configuration *conf; int enabled = 0; + static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1); if (!cdev) return -ENODEV; @@ -2140,7 +2141,7 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, f->disable(f); } dev->enabled = false; - } else { + } else if (__ratelimit(&rl)) { pr_err("android_usb: already %s\n", dev->enabled ? "enabled" : "disabled"); } From 92406e6d8bd5538e58c53bc9bc4a8f48de6d1627 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Tue, 26 Feb 2013 10:04:31 -0700 Subject: [PATCH 2264/2357] msm: kgsl: Always send fence sync the timestamp it expects Fence sync seems to react badly when it gets a unexpected timestamp on a timeline. When a event expires always send the expected timestamp even if the event expired because the context was destroyed. Change-Id: Ic0dedbad770363a00257d62c4940f7743bc33060 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/kgsl_sync.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c index 9325124f812..d9ab081fc2f 100644 --- a/drivers/gpu/msm/kgsl_sync.c +++ b/drivers/gpu/msm/kgsl_sync.c @@ -69,6 +69,7 @@ static int kgsl_sync_pt_compare(struct sync_pt *a, struct sync_pt *b) struct kgsl_fence_event_priv { struct kgsl_context *context; + unsigned int timestamp; }; /** @@ -85,7 +86,7 @@ static inline void kgsl_fence_event_cb(struct kgsl_device *device, void *priv, u32 context_id, u32 timestamp) { struct kgsl_fence_event_priv *ev = priv; - kgsl_sync_timeline_signal(ev->context->timeline, timestamp); + kgsl_sync_timeline_signal(ev->context->timeline, ev->timestamp); kgsl_context_put(ev->context); kfree(ev); } @@ -125,6 +126,7 @@ int kgsl_add_fence_event(struct kgsl_device *device, if (event == NULL) return -ENOMEM; event->context = context; + event->timestamp = timestamp; kgsl_context_get(context); pt = kgsl_sync_pt_create(context->timeline, timestamp); From fb4e77edf9ce62aa836e8406aa9dfc1bf9aecab5 Mon Sep 17 00:00:00 2001 From: Ravishangar Kalyanam Date: Mon, 23 Jul 2012 18:26:09 -0700 Subject: [PATCH 2265/2357] msm: display: Add DSI clock control for MDP GDHS power collapse Enable DSI clock and regulator before enabling/disabling power collapse for MDP GDHS. (cherry picked from commit ad3200279e62eff01fd1bb9136cc9c0d11e10380) (cherry picked from commit 58c5992c710df379e26bb210e00c74da501db9d2) Change-Id: I76b91260c61abf214e688c0dea6989ed2cfa3801 Signed-off-by: Ravishangar Kalyanam Signed-off-by: Siddhartha Agrawal Signed-off-by: Ram Kumar Chakravarthy Chebathini Conflicts: arch/arm/mach-msm/board-8064-regulator.c Signed-off-by: Dhivya Subramanian --- arch/arm/mach-msm/board-8064-regulator.c | 2 + .../mach-msm/board-8930-regulator-pm8038.c | 2 + arch/arm/mach-msm/board-8960-regulator.c | 2 + drivers/video/msm/mdp.c | 73 ++++++++++++++++--- drivers/video/msm/mipi_dsi.h | 35 ++++++++- 5 files changed, 102 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c index 88d00eb89e1..83ff1dd4ca6 100644 --- a/arch/arm/mach-msm/board-8064-regulator.c +++ b/arch/arm/mach-msm/board-8064-regulator.c @@ -33,6 +33,7 @@ VREG_CONSUMERS(L2) = { REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.2"), REGULATOR_SUPPLY("lvds_pll_vdda", "lvds.0"), REGULATOR_SUPPLY("dsi1_pll_vdda", "mipi_dsi.1"), + REGULATOR_SUPPLY("dsi_pll_vdda", "mdp.0"), }; VREG_CONSUMERS(L3) = { REGULATOR_SUPPLY("8921_l3", NULL), @@ -220,6 +221,7 @@ VREG_CONSUMERS(LVS7) = { REGULATOR_SUPPLY("pll_vdd", "pil_riva"), REGULATOR_SUPPLY("lvds_vdda", "lvds.0"), REGULATOR_SUPPLY("dsi1_vddio", "mipi_dsi.1"), + REGULATOR_SUPPLY("dsi_pll_vddio", "mdp.0"), REGULATOR_SUPPLY("hdmi_vdda", "hdmi_msm.0"), }; VREG_CONSUMERS(USB_OTG) = { diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c index 770abf098d6..0203db4e8b3 100644 --- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c +++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c @@ -35,6 +35,7 @@ VREG_CONSUMERS(L2) = { REGULATOR_SUPPLY("8038_l2", NULL), REGULATOR_SUPPLY("iris_vdddig", "wcnss_wlan.0"), REGULATOR_SUPPLY("dsi_vdda", "mipi_dsi.1"), + REGULATOR_SUPPLY("dsi_pll_vdda", "mdp.0"), REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.0"), REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.1"), REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.2"), @@ -146,6 +147,7 @@ VREG_CONSUMERS(L22) = { VREG_CONSUMERS(L23) = { REGULATOR_SUPPLY("8038_l23", NULL), REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"), + REGULATOR_SUPPLY("dsi_pll_vddio", "mdp.0"), REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"), REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"), REGULATOR_SUPPLY("pll_vdd", "pil_riva"), diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c index 44cd4c98111..b731d9eafd4 100644 --- a/arch/arm/mach-msm/board-8960-regulator.c +++ b/arch/arm/mach-msm/board-8960-regulator.c @@ -31,6 +31,7 @@ VREG_CONSUMERS(L1) = { VREG_CONSUMERS(L2) = { REGULATOR_SUPPLY("8921_l2", NULL), REGULATOR_SUPPLY("dsi_vdda", "mipi_dsi.1"), + REGULATOR_SUPPLY("dsi_pll_vdda", "mdp.0"), REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.0"), REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.1"), REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.2"), @@ -117,6 +118,7 @@ VREG_CONSUMERS(L22) = { VREG_CONSUMERS(L23) = { REGULATOR_SUPPLY("8921_l23", NULL), REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"), + REGULATOR_SUPPLY("dsi_pll_vddio", "mdp.0"), REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"), REGULATOR_SUPPLY("pll_vdd", "pil_riva"), REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"), diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 30e0ea8b049..566fb439066 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -67,7 +67,7 @@ u32 mdp_max_clk = 266667000; u64 mdp_max_bw = 2000000000; static struct platform_device *mdp_init_pdev; -static struct regulator *footswitch; +static struct regulator *footswitch, *dsi_pll_vdda, *dsi_pll_vddio; static unsigned int mdp_footswitch_on; struct completion mdp_ppp_comp; @@ -2615,18 +2615,40 @@ static int mdp_irq_clk_setup(struct platform_device *pdev, } disable_irq(mdp_irq); + dsi_pll_vdda = regulator_get(&pdev->dev, "dsi_pll_vdda"); + if (IS_ERR(dsi_pll_vdda)) { + dsi_pll_vdda = NULL; + } else { + if (mdp_rev == MDP_REV_42 || mdp_rev == MDP_REV_44) { + ret = regulator_set_voltage(dsi_pll_vdda, 1200000, + 1200000); + if (ret) { + pr_err("set_voltage failed for dsi_pll_vdda, ret=%d\n", + ret); + } + } + } + + dsi_pll_vddio = regulator_get(&pdev->dev, "dsi_pll_vddio"); + if (IS_ERR(dsi_pll_vddio)) { + dsi_pll_vddio = NULL; + } else { + if (mdp_rev == MDP_REV_42) { + ret = regulator_set_voltage(dsi_pll_vddio, 1800000, + 1800000); + if (ret) { + pr_err("set_voltage failed for dsi_pll_vddio, ret=%d\n", + ret); + } + } + } + footswitch = regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(footswitch)) + if (IS_ERR(footswitch)) { footswitch = NULL; - else { + } else { regulator_enable(footswitch); mdp_footswitch_on = 1; - - if (mdp_rev == MDP_REV_42 && !cont_splashScreen) { - regulator_disable(footswitch); - msleep(20); - regulator_enable(footswitch); - } } mdp_clk = clk_get(&pdev->dev, "core_clk"); @@ -2677,6 +2699,17 @@ static int mdp_irq_clk_setup(struct platform_device *pdev, MSM_FB_DEBUG("mdp_clk: mdp_clk=%d\n", (int)clk_get_rate(mdp_clk)); #endif + + if (mdp_rev == MDP_REV_42 && !cont_splashScreen) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* DSI Video Timing generator disable */ + outpdw(MDP_BASE + 0xE0000, 0x0); + /* Clear MDP Interrupt Enable register */ + outpdw(MDP_BASE + 0x50, 0x0); + /* Set Overlay Proc 0 to reset state */ + outpdw(MDP_BASE + 0x10004, 0x3); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } return 0; } @@ -3203,6 +3236,17 @@ void mdp_footswitch_ctrl(boolean on) return; } + if (dsi_pll_vddio) + regulator_enable(dsi_pll_vddio); + + if (dsi_pll_vdda) + regulator_enable(dsi_pll_vdda); + + mipi_dsi_prepare_clocks(); + mipi_dsi_ahb_ctrl(1); + mipi_dsi_phy_ctrl(1); + mipi_dsi_clk_enable(); + if (on && !mdp_footswitch_on) { pr_debug("Enable MDP FS\n"); regulator_enable(footswitch); @@ -3213,6 +3257,17 @@ void mdp_footswitch_ctrl(boolean on) mdp_footswitch_on = 0; } + mipi_dsi_clk_disable(); + mipi_dsi_phy_ctrl(0); + mipi_dsi_ahb_ctrl(0); + mipi_dsi_unprepare_clocks(); + + if (dsi_pll_vdda) + regulator_disable(dsi_pll_vdda); + + if (dsi_pll_vddio) + regulator_disable(dsi_pll_vddio); + mutex_unlock(&mdp_suspend_mutex); } diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h index 818caa8cb8b..223ec58f89b 100644 --- a/drivers/video/msm/mipi_dsi.h +++ b/drivers/video/msm/mipi_dsi.h @@ -313,8 +313,6 @@ void mipi_dsi_set_tear_on(struct msm_fb_data_type *mfd); void mipi_dsi_set_tear_off(struct msm_fb_data_type *mfd); void mipi_dsi_set_backlight(struct msm_fb_data_type *mfd, int level); void mipi_dsi_cmd_backlight_tx(struct dsi_buf *dp); -void mipi_dsi_clk_enable(void); -void mipi_dsi_clk_disable(void); void mipi_dsi_pre_kickoff_action(void); void mipi_dsi_post_kickoff_action(void); void mipi_dsi_pre_kickoff_add(struct dsi_kickoff_action *act); @@ -328,16 +326,47 @@ void mipi_dsi_mdp_busy_wait(void); irqreturn_t mipi_dsi_isr(int irq, void *ptr); void mipi_set_tx_power_mode(int mode); -void mipi_dsi_phy_ctrl(int on); void mipi_dsi_phy_init(int panel_ndx, struct msm_panel_info const *panel_info, int target_type); int mipi_dsi_clk_div_config(uint8 bpp, uint8 lanes, uint32 *expected_dsi_pclk); int mipi_dsi_clk_init(struct platform_device *pdev); void mipi_dsi_clk_deinit(struct device *dev); + +#ifdef CONFIG_FB_MSM_MIPI_DSI +void mipi_dsi_clk_enable(void); +void mipi_dsi_clk_disable(void); void mipi_dsi_prepare_clocks(void); void mipi_dsi_unprepare_clocks(void); void mipi_dsi_ahb_ctrl(u32 enable); +void mipi_dsi_phy_ctrl(int on); +#else +static inline void mipi_dsi_clk_enable(void) +{ + /* empty */ +} +void mipi_dsi_clk_disable(void) +{ + /* empty */ +} +void mipi_dsi_prepare_clocks(void) +{ + /* empty */ +} +void mipi_dsi_unprepare_clocks(void) +{ + /* empty */ +} +void mipi_dsi_ahb_ctrl(u32 enable) +{ + /* empty */ +} +void mipi_dsi_phy_ctrl(int on) +{ + /* empty */ +} +#endif + void cont_splash_clk_ctrl(int enable); void mipi_dsi_turn_on_clks(void); void mipi_dsi_turn_off_clks(void); From 618de442d418c2c454e91abdcbd448a4023813ec Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Fri, 11 Jan 2013 09:56:08 -0800 Subject: [PATCH 2266/2357] ASoC: wcd9310: Reset OTHR_RESET_CTR before power down There is a missing step to clear OTHR_RESET_CTR before power down. It could cause a glitch and power hit without it. It has to be reset. original gerrit is https://review-android.quicinc.com/#/c/191312/ This is cherry-pick gerrit by developer to jb_2.5 Change-Id: Id96070352480be6ea412844d4f71765e2df76afe CRs-fixed: 420142 Signed-off-by: Fred Oh --- sound/soc/codecs/wcd9310.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c index 00c2e1e170e..cb403711c64 100644 --- a/sound/soc/codecs/wcd9310.c +++ b/sound/soc/codecs/wcd9310.c @@ -468,6 +468,8 @@ static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00); snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01, 0x00); + snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10, + 0x00); snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00); break; } From a7f44e6ca0ad8edcd95ee3e663bd195c02d1dd48 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 1 Oct 2012 18:56:41 -0700 Subject: [PATCH 2267/2357] msm: clock-8960: Correctly measure KPSS pass3 debug clocks All debugging outputs from KPSS pass 3 are divided by four in hardware. Multiply the measured clock rate to compensate. Change-Id: Id0e0e0116bb469b690b4d1b2a46e8a2b3b164a86 Signed-off-by: Patrick Daly (cherry picked from commit 73db3ad247a9ab74c8edeca59b961594d1cdb13d) --- arch/arm/mach-msm/clock-8960.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c index 7be143c5834..378952901c1 100644 --- a/arch/arm/mach-msm/clock-8960.c +++ b/arch/arm/mach-msm/clock-8960.c @@ -5111,6 +5111,8 @@ static int measure_clk_set_parent(struct clk *c, struct clk *parent) writel_relaxed(0x80|BVAL(5, 3, clk_sel), GCC_APCS_CLK_DIAG); measure->sample_ticks = 0x4000; measure->multiplier = 2; + if (cpu_is_krait_v3()) + measure->multiplier = 8; break; default: ret = -EPERM; From a3a99230075616d4504393b9120ce578caaf5a2c Mon Sep 17 00:00:00 2001 From: Subhash Chandra Bose Naripeddy Date: Fri, 11 Jan 2013 14:05:21 -0800 Subject: [PATCH 2268/2357] ASoC: msm: Add support to fix up the channels for HDMI For the use case of Playback over HDMI device, the number of channels supported varies with the sink capabilities. Add support to fix the channels based on the sink capabilites configured by userspace for msm8960 Change-Id: Iba4f1fead17832d7832fabdcba02da671e5fd005 Signed-off-by: Subhash Chandra Bose Naripeddy --- sound/soc/msm/apq8064.c | 6 +++--- sound/soc/msm/msm8930.c | 30 ++++++++++++++++++++++++++++-- sound/soc/msm/msm8960.c | 30 ++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c index 2de797acfd5..b29cde7eb9b 100644 --- a/sound/soc/msm/apq8064.c +++ b/sound/soc/msm/apq8064.c @@ -846,7 +846,7 @@ static const struct snd_kcontrol_new tabla_msm_controls[] = { msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put), SOC_ENUM_EXT("HDMI_RX Channels", msm_enum[3], msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put), - SOC_ENUM_EXT("HDMI RX Rate", msm_enum[1], + SOC_ENUM_EXT("HDMI RX Rate", msm_enum[4], msm_hdmi_rate_get, msm_hdmi_rate_put), }; @@ -1426,11 +1426,11 @@ static int msm_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, pr_debug("%s channels->min %u channels->max %u ()\n", __func__, channels->min, channels->max); - if (channels->max < 2) - channels->min = channels->max = 2; if (!hdmi_rate_variable) rate->min = rate->max = 48000; channels->min = channels->max = msm_hdmi_rx_ch; + if (channels->max < 2) + channels->min = channels->max = 2; return 0; } diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c index a0295eae385..18b871619e3 100644 --- a/sound/soc/msm/msm8930.c +++ b/sound/soc/msm/msm8930.c @@ -59,6 +59,7 @@ static int msm8930_ext_spk_pamp; static int msm8930_btsco_rate = BTSCO_RATE_8KHZ; static int msm8930_btsco_ch = 1; static int hdmi_rate_variable; +static int msm_hdmi_rx_ch = 2; static struct clk *codec_clk; static int clk_users; @@ -394,7 +395,8 @@ static const struct snd_soc_dapm_route common_audio_map[] = { static const char *spk_function[] = {"Off", "On"}; static const char *slim0_rx_ch_text[] = {"One", "Two"}; static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"}; - +static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", + "Six", "Seven", "Eight"}; static const char * const hdmi_rate[] = {"Default", "Variable"}; static const struct soc_enum msm8930_enum[] = { @@ -402,6 +404,7 @@ static const struct soc_enum msm8930_enum[] = { SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text), SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text), SOC_ENUM_SINGLE_EXT(2, hdmi_rate), + SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text), }; static const char *btsco_rate_text[] = {"8000", "16000"}; @@ -508,6 +511,25 @@ static int msm8930_pmic_gain_put(struct snd_kcontrol *kcontrol, return ret; } +static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, + msm_hdmi_rx_ch); + ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2; + return 0; +} + +static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2; + + pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, + msm_hdmi_rx_ch); + return 1; +} + static int msm8930_hdmi_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -537,6 +559,8 @@ static const struct snd_kcontrol_new sitar_msm8930_controls[] = { SOC_ENUM_EXT("HDMI RX Rate", msm8930_enum[3], msm8930_hdmi_rate_get, msm8930_hdmi_rate_put), + SOC_ENUM_EXT("HDMI_RX Channels", msm8930_enum[4], + msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put), }; static void *def_sitar_mbhc_cal(void) @@ -778,7 +802,9 @@ static int msm8930_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, if (!hdmi_rate_variable) rate->min = rate->max = 48000; - channels->min = channels->max = 2; + channels->min = channels->max = msm_hdmi_rx_ch; + if (channels->max < 2) + channels->min = channels->max = 2; return 0; } diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c index 9bf404dc4cf..b1515523669 100644 --- a/sound/soc/msm/msm8960.c +++ b/sound/soc/msm/msm8960.c @@ -74,6 +74,7 @@ static int msm8960_slim_0_tx_ch = 1; static int msm8960_btsco_rate = SAMPLE_RATE_8KHZ; static int msm8960_btsco_ch = 1; static int hdmi_rate_variable; +static int msm_hdmi_rx_ch = 2; static int msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ; static struct clk *codec_clk; @@ -549,6 +550,8 @@ static const struct snd_soc_dapm_route common_audio_map[] = { static const char *spk_function[] = {"Off", "On"}; static const char *slim0_rx_ch_text[] = {"One", "Two"}; static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"}; +static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", + "Six", "Seven", "Eight"}; static const char * const hdmi_rate[] = {"Default", "Variable"}; static const struct soc_enum msm8960_enum[] = { @@ -556,6 +559,7 @@ static const struct soc_enum msm8960_enum[] = { SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text), SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text), SOC_ENUM_SINGLE_EXT(2, hdmi_rate), + SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text), }; static const char *btsco_rate_text[] = {"8000", "16000"}; @@ -662,6 +666,25 @@ static int msm8960_auxpcm_rate_put(struct snd_kcontrol *kcontrol, return 0; } +static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, + msm_hdmi_rx_ch); + ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2; + return 0; +} + +static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2; + + pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, + msm_hdmi_rx_ch); + return 1; +} + static int msm8960_hdmi_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -691,6 +714,8 @@ static const struct snd_kcontrol_new tabla_msm8960_controls[] = { SOC_ENUM_EXT("HDMI RX Rate", msm8960_enum[3], msm8960_hdmi_rate_get, msm8960_hdmi_rate_put), + SOC_ENUM_EXT("HDMI_RX Channels", msm8960_enum[4], + msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put), }; static void *def_tabla_mbhc_cal(void) @@ -1038,10 +1063,11 @@ static int msm8960_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, pr_debug("%s channels->min %u channels->max %u ()\n", __func__, channels->min, channels->max); - if (channels->max < 2) - channels->min = channels->max = 2; if (!hdmi_rate_variable) rate->min = rate->max = 48000; + channels->min = channels->max = msm_hdmi_rx_ch; + if (channels->max < 2) + channels->min = channels->max = 2; return 0; } From cc625fbb3b3c6c7457e3976808081ae857de5860 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Wed, 26 Dec 2012 21:28:43 -0800 Subject: [PATCH 2269/2357] power: pm8921-bms: implement BMS reset Sometimes during testing it is convenient to force the BMS to take a new OCV, essentially restarting the BMS soc calculation in order to test short portions of the battery profile. Implement a BMS_reset module parameter, which sets OCV to the instantaneous VBAT and resets the coulomb counter whenever a 'Y' is written to it. Furthermore, in the bms reset mode, keep UUC constant at 3%, and do not run adjusting algorithms until a 'N' is written to the module parameter. Note that this feature should only be used with a fake battery, as it maintains a constant voltage and gives us near true OCV estimates. Also, the adjusting algorithm is disabled due to this reason. If adjustments to the OCV were allowed, we will end up adjusting the SOC higher, because the OCV est will never go low as the battery discharges. It will fail the test cases for which this feature is designed. Change-Id: Idfe7f0edf9c25f018f6e6d0a9df20a1a04d5277a Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/pm8921-bms.c | 123 +++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 25 deletions(-) diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index 3662ac5714b..981fde667df 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -724,6 +724,90 @@ static bool is_warm_restart(struct pm8921_bms_chip *chip) } return reg & WD_BIT; } + +#define IBAT_TOL_MASK 0x0F +#define OCV_TOL_MASK 0xF0 +#define IBAT_TOL_DEFAULT 0x03 +#define IBAT_TOL_NOCHG 0x0F +#define OCV_TOL_DEFAULT 0x20 +#define OCV_TOL_NO_OCV 0x00 +static int pm8921_bms_stop_ocv_updates(void) +{ + if (!the_chip) { + pr_err("BMS driver has not been initialized yet!\n"); + return -EINVAL; + } + pr_debug("stopping ocv updates\n"); + return pm_bms_masked_write(the_chip, BMS_TOLERANCES, + OCV_TOL_MASK, OCV_TOL_NO_OCV); +} + +static int pm8921_bms_start_ocv_updates(void) +{ + if (!the_chip) { + pr_err("BMS driver has not been initialized yet!\n"); + return -EINVAL; + } + pr_debug("stopping ocv updates\n"); + return pm_bms_masked_write(the_chip, BMS_TOLERANCES, + OCV_TOL_MASK, OCV_TOL_DEFAULT); +} + +static int reset_bms_for_test(void) +{ + int ibat_ua, vbat_uv, rc; + int ocv_est_uv; + + if (!the_chip) { + pr_err("BMS driver has not been initialized yet!\n"); + return -EINVAL; + } + + rc = pm8921_bms_get_simultaneous_battery_voltage_and_current( + &ibat_ua, + &vbat_uv); + + ocv_est_uv = vbat_uv + (ibat_ua * the_chip->rconn_mohm) / 1000; + pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv); + the_chip->last_ocv_uv = ocv_est_uv; + last_soc = -EINVAL; + reset_cc(the_chip); + the_chip->last_cc_uah = 0; + pm8921_bms_stop_ocv_updates(); + + pr_debug("bms reset to ocv = %duv vbat_ua = %d ibat_ua = %d\n", + the_chip->last_ocv_uv, vbat_uv, ibat_ua); + + return rc; +} + +static int bms_reset_set(const char *val, const struct kernel_param *kp) +{ + int rc; + + rc = param_set_bool(val, kp); + if (rc) { + pr_err("Unable to set bms_reset: %d\n", rc); + return rc; + } + + if (*val == 'Y') { + rc = reset_bms_for_test(); + if (rc) { + pr_err("Unable to modify bms_reset: %d\n", rc); + return rc; + } + } + return 0; +} + +static struct kernel_param_ops bms_reset_ops = { + .set = bms_reset_set, + .get = param_get_bool, +}; + +static bool bms_reset; +module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644); /* * This reflects what should the CC readings should be for * a 5mAh discharge. This value is dependent on @@ -1209,6 +1293,12 @@ static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip, iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, iavg_num_samples); } + /* + * if we're in bms reset mode, force uuc to be 3% of fcc + */ + if (bms_reset) + return (fcc_uah * 3) / 100; + uuc_uah_iavg = calculate_termination_uuc(chip, batt_temp, chargecycles, fcc_uah, iavg_ma, @@ -1560,6 +1650,12 @@ static int adjust_soc(struct pm8921_bms_chip *chip, int soc, (s64)fcc_uah - uuc_uah); soc_est = bound_soc(soc_est); + /* never adjust during bms reset mode */ + if (bms_reset) { + pr_debug("bms reset mode, SOC adjustment skipped\n"); + goto out; + } + if (ibat_ua < 0 && pm8921_is_batfet_closed()) { soc = charging_adjustments(chip, soc, vbat_uv, ibat_ua, batt_temp, chargecycles, @@ -2287,13 +2383,6 @@ int pm8921_bms_get_fcc(void) return calculate_fcc_uah(the_chip, batt_temp, last_chargecycles); } EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc); - -#define IBAT_TOL_MASK 0x0F -#define OCV_TOL_MASK 0xF0 -#define IBAT_TOL_DEFAULT 0x03 -#define IBAT_TOL_NOCHG 0x0F -#define OCV_TOL_DEFAULT 0x20 -#define OCV_TOL_NO_OCV 0x00 void pm8921_bms_charging_began(void) { struct pm8921_soc_params raw; @@ -2420,22 +2509,6 @@ void pm8921_bms_charging_end(int is_battery_full) } EXPORT_SYMBOL_GPL(pm8921_bms_charging_end); -int pm8921_bms_stop_ocv_updates(struct pm8921_bms_chip *chip) -{ - pr_debug("stopping ocv updates\n"); - return pm_bms_masked_write(chip, BMS_TOLERANCES, - OCV_TOL_MASK, OCV_TOL_NO_OCV); -} -EXPORT_SYMBOL_GPL(pm8921_bms_stop_ocv_updates); - -int pm8921_bms_start_ocv_updates(struct pm8921_bms_chip *chip) -{ - pr_debug("stopping ocv updates\n"); - return pm_bms_masked_write(chip, BMS_TOLERANCES, - OCV_TOL_MASK, OCV_TOL_DEFAULT); -} -EXPORT_SYMBOL_GPL(pm8921_bms_start_ocv_updates); - static irqreturn_t pm8921_bms_sbi_write_ok_handler(int irq, void *data) { pr_debug("irq = %d triggered", irq); @@ -2775,10 +2848,10 @@ static int set_calc(void *data, u64 val) switch (param) { case STOP_OCV: - pm8921_bms_stop_ocv_updates(the_chip); + pm8921_bms_stop_ocv_updates(); break; case START_OCV: - pm8921_bms_start_ocv_updates(the_chip); + pm8921_bms_start_ocv_updates(); break; default: ret = -EINVAL; From 12139a34d7301216fcdb9f12573a43ad2bf23c82 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Thu, 10 Jan 2013 15:59:33 -0800 Subject: [PATCH 2270/2357] power: pm8921-bms: disable ocv updates for flat portion of the curve An issue is observed when an OCV is updated while the device is sleeping. When it wakes up the SOC calculations are run on the new OCV which result in a drastically different SOC than previously reported. The root cause of this issue is PON OCV likely was unsettled. Provide a feature where OCV updates can be disabled between certain SOC range. Change-Id: I54a75a7e9d05ff2c8ccd484850f02a0190d6a3b7 Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/pm8921-bms.c | 18 +++++++++++++++++- include/linux/mfd/pm8xxx/pm8921-bms.h | 6 ++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index 981fde667df..de656fc7e75 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -162,6 +162,9 @@ struct pm8921_bms_chip { int low_voltage_calc_ms; int imax_ua; struct wake_lock soc_wake_lock; + int disable_flat_portion_ocv; + int ocv_dis_high_soc; + int ocv_dis_low_soc; }; /* @@ -748,7 +751,7 @@ static int pm8921_bms_start_ocv_updates(void) pr_err("BMS driver has not been initialized yet!\n"); return -EINVAL; } - pr_debug("stopping ocv updates\n"); + pr_debug("starting ocv updates\n"); return pm_bms_masked_write(the_chip, BMS_TOLERANCES, OCV_TOL_MASK, OCV_TOL_DEFAULT); } @@ -2154,6 +2157,15 @@ static int calculate_state_of_charge(struct pm8921_bms_chip *chip, calculated_soc = new_calculated_soc; firsttime = 0; get_current_time(&chip->last_recalc_time); + + if (chip->disable_flat_portion_ocv) { + if (is_between(chip->ocv_dis_high_soc, chip->ocv_dis_low_soc, + calculated_soc)) { + pm8921_bms_stop_ocv_updates(); + } else { + pm8921_bms_start_ocv_updates(); + } + } return calculated_soc; } @@ -3130,6 +3142,10 @@ static int __devinit pm8921_bms_probe(struct platform_device *pdev) chip->revision = pm8xxx_get_revision(chip->dev->parent); chip->enable_fcc_learning = pdata->enable_fcc_learning; + chip->disable_flat_portion_ocv = pdata->disable_flat_portion_ocv; + chip->ocv_dis_high_soc = pdata->ocv_dis_high_soc; + chip->ocv_dis_low_soc = pdata->ocv_dis_low_soc; + mutex_init(&chip->calib_mutex); INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work); diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h index 12214d9caa3..d670732560a 100644 --- a/include/linux/mfd/pm8xxx/pm8921-bms.h +++ b/include/linux/mfd/pm8xxx/pm8921-bms.h @@ -41,6 +41,9 @@ struct pm8xxx_bms_core_data { * voltage higher than cutoff voltage * @low_voltage_calc_ms: The period of soc calculation in ms when battery * voltage is near cutoff voltage + * @disable_flat_portion_ocv: feature to disable ocv updates while in sleep + * @ocv_dis_high_soc: the high soc percent when ocv should be disabled + * @ocv_dis_low_soc: the low soc percent when ocv should be enabled */ struct pm8921_bms_platform_data { struct pm8xxx_bms_core_data bms_cdata; @@ -57,6 +60,9 @@ struct pm8921_bms_platform_data { int chg_term_ua; int normal_voltage_calc_ms; int low_voltage_calc_ms; + int disable_flat_portion_ocv; + int ocv_dis_high_soc; + int ocv_dis_low_soc; }; #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE) From 165f1aee804e5224b440e13c4de6bebe90e91c23 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Mon, 14 Jan 2013 18:19:18 -0800 Subject: [PATCH 2271/2357] power: pm8921-bms: fix override mode causes sleep current increase The override mode is used to measure battery voltage and current simultaneously. We observed that the XOADC and the AMUX were left enabled even after the override mode is exited. This causes the current consumption to increase by 500uA. Execute a dummy XOADC read after override mode is exited. This will ensure that the XOADC and the AMUX get turned off after the dummy transaction is completed. CRs-Fixed: 440864 Change-Id: I53b8b67d55bbab1de588a36b7d2eca26ba6e6bfd Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/pm8921-bms.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index de656fc7e75..1f54574b4a1 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -599,6 +599,23 @@ static int read_vsense_avg(struct pm8921_bms_chip *chip, int *result) return 0; } +static int get_batt_temp(struct pm8921_bms_chip *chip, int *batt_temp) +{ + int rc; + struct pm8xxx_adc_chan_result result; + + rc = pm8xxx_adc_read(chip->batt_temp_channel, &result); + if (rc) { + pr_err("error reading batt_temp_channel = %d, rc = %d\n", + chip->batt_temp_channel, rc); + return rc; + } + *batt_temp = result.physical; + pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical, + result.measurement); + return 0; +} + #define BMS_MODE_BIT BIT(6) #define EN_VBAT_BIT BIT(5) #define OVERRIDE_MODE_DELAY_MS 20 @@ -609,6 +626,7 @@ int override_mode_simultaneous_battery_voltage_and_current(int *ibat_ua, int16_t vbat_raw; int vsense_uv; int usb_chg; + int batt_temp; mutex_lock(&the_chip->bms_output_lock); @@ -623,12 +641,13 @@ int override_mode_simultaneous_battery_voltage_and_current(int *ibat_ua, pm_bms_read_output_data(the_chip, VBATT_AVG, &vbat_raw); pm_bms_unlock_output_data(the_chip); pm_bms_masked_write(the_chip, BMS_CONTROL, - BMS_MODE_BIT | EN_VBAT_BIT, 0); + BMS_MODE_BIT | EN_VBAT_BIT, 0); pm8xxx_writeb(the_chip->dev->parent, BMS_S1_DELAY, 0x0B); mutex_unlock(&the_chip->bms_output_lock); + get_batt_temp(the_chip, &batt_temp); usb_chg = usb_chg_plugged_in(the_chip); convert_vbatt_raw_to_uv(the_chip, usb_chg, vbat_raw, vbat_uv); @@ -1909,23 +1928,6 @@ static void update_power_supply(struct pm8921_bms_chip *chip) power_supply_changed(chip->batt_psy); } -static int get_batt_temp(struct pm8921_bms_chip *chip, int *batt_temp) -{ - int rc; - struct pm8xxx_adc_chan_result result; - - rc = pm8xxx_adc_read(chip->batt_temp_channel, &result); - if (rc) { - pr_err("error reading batt_temp_channel = %d, rc = %d\n", - chip->batt_temp_channel, rc); - return rc; - } - *batt_temp = result.physical; - pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical, - result.measurement); - return 0; -} - #define MIN_DELTA_625_UV 1000 static void calib_hkadc(struct pm8921_bms_chip *chip) { From aa725063798f511abac903d2d02a9954ea818f05 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 1 Feb 2013 11:44:33 +0530 Subject: [PATCH 2272/2357] power: pm8921-bms: Enable batt alarm Set the batt alarm to wake up the system if the battery voltage falls below a threshold. This is to make sure that the device does not shutdown abruptly without any notification. Hold the low voltage wakelock to prevent the device from going to sleep immediately after the low voltage notification. Change-Id: Ifaeeeb27bd85f9c95f026ac3565681432e247b02 Signed-off-by: Anirudh Ghayal --- arch/arm/mach-msm/board-8064-pmic.c | 2 + arch/arm/mach-msm/board-8930-pmic.c | 2 + arch/arm/mach-msm/board-8960-pmic.c | 4 +- drivers/power/pm8921-bms.c | 148 ++++++++++++++++++++++++++ include/linux/mfd/pm8xxx/pm8921-bms.h | 2 + 5 files changed, 157 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c index 2224b22d07b..6269abbaf64 100644 --- a/arch/arm/mach-msm/board-8064-pmic.c +++ b/arch/arm/mach-msm/board-8064-pmic.c @@ -423,6 +423,8 @@ apq8064_pm8921_bms_pdata __devinitdata = { .chg_term_ua = CHG_TERM_MA * 1000, .normal_voltage_calc_ms = 20000, .low_voltage_calc_ms = 1000, + .alarm_low_mv = 3400, + .alarm_high_mv = 4000, }; static struct pm8921_platform_data diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c index f3436ac7853..d480a51d670 100644 --- a/arch/arm/mach-msm/board-8930-pmic.c +++ b/arch/arm/mach-msm/board-8930-pmic.c @@ -476,6 +476,8 @@ static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = { .rconn_mohm = 18, .normal_voltage_calc_ms = 20000, .low_voltage_calc_ms = 1000, + .alarm_low_mv = 3400, + .alarm_high_mv = 4000, }; static struct pm8038_platform_data pm8038_platform_data __devinitdata = { diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c index 01948aef390..d01590bf8c0 100644 --- a/arch/arm/mach-msm/board-8960-pmic.c +++ b/arch/arm/mach-msm/board-8960-pmic.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -433,6 +433,8 @@ static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = { .chg_term_ua = CHG_TERM_MA * 1000, .normal_voltage_calc_ms = 20000, .low_voltage_calc_ms = 1000, + .alarm_low_mv = 3400, + .alarm_high_mv = 4000, }; #define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */ diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index 1f54574b4a1..417e5559586 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,9 @@ struct pm8921_bms_chip { unsigned int charging_began; unsigned int start_percent; unsigned int end_percent; + unsigned int alarm_low_mv; + unsigned int alarm_high_mv; + int charge_time_us; int catch_up_time_us; enum battery_type batt_type; @@ -192,6 +196,13 @@ static int last_soc = -EINVAL; static int last_real_fcc_mah = -EINVAL; static int last_real_fcc_batt_temp = -EINVAL; +static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb, + unsigned long status, void *unused); + +static struct notifier_block alarm_notifier = { + .notifier_call = pm8921_battery_gauge_alarm_notify, +}; + static int bms_ops_set(const char *val, const struct kernel_param *kp) { if (*(int *)kp->arg == -EINVAL) @@ -379,6 +390,124 @@ static int usb_chg_plugged_in(struct pm8921_bms_chip *chip) return val; } +static int pm8921_bms_enable_batt_alarm(struct pm8921_bms_chip *chip) +{ + int rc = 0; + + rc = pm8xxx_batt_alarm_enable(PM8XXX_BATT_ALARM_LOWER_COMPARATOR); + if (!rc) + rc = pm8xxx_batt_alarm_disable( + PM8XXX_BATT_ALARM_UPPER_COMPARATOR); + if (rc) { + pr_err("unable to set batt alarm state rc=%d\n", rc); + return rc; + } + + return rc; +} + +static int pm8921_bms_configure_batt_alarm(struct pm8921_bms_chip *chip) +{ + int rc = 0; + + rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR); + if (!rc) + rc = pm8xxx_batt_alarm_disable( + PM8XXX_BATT_ALARM_LOWER_COMPARATOR); + if (rc) { + pr_err("unable to set batt alarm state rc=%d\n", rc); + return rc; + } + + /* + * The batt-alarm driver requires sane values for both min / max, + * regardless of whether they're both activated. + */ + rc = pm8xxx_batt_alarm_threshold_set( + PM8XXX_BATT_ALARM_LOWER_COMPARATOR, + chip->alarm_low_mv); + if (!rc) + rc = pm8xxx_batt_alarm_threshold_set( + PM8XXX_BATT_ALARM_UPPER_COMPARATOR, + chip->alarm_high_mv); + if (rc) { + pr_err("unable to set batt alarm threshold rc=%d\n", rc); + return rc; + } + + rc = pm8xxx_batt_alarm_hold_time_set( + PM8XXX_BATT_ALARM_HOLD_TIME_16_MS); + if (rc) { + pr_err("unable to set batt alarm hold time rc=%d\n", rc); + return rc; + } + + /* PWM enabled at 2Hz */ + rc = pm8xxx_batt_alarm_pwm_rate_set(1, 7, 4); + if (rc) { + pr_err("unable to set batt alarm pwm rate rc=%d\n", rc); + return rc; + } + + rc = pm8xxx_batt_alarm_register_notifier(&alarm_notifier); + if (rc) { + pr_err("unable to register alarm notifier rc=%d\n", rc); + return rc; + } + + return rc; +} + +static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb, + unsigned long status, void *unused) +{ + int rc; + + if (!the_chip) { + pr_err("not initialized\n"); + return -EINVAL; + } + + switch (status) { + case 0: + pr_debug("spurious interrupt\n"); + break; + case 1: + pr_debug("Low voltage alarm triggered\n"); + /* + * hold the low voltage wakelock until the soc + * work finds it appropriate to release it. + */ + wake_lock(&the_chip->low_voltage_wake_lock); + the_chip->low_voltage_wake_lock_held = 1; + + rc = pm8xxx_batt_alarm_disable( + PM8XXX_BATT_ALARM_LOWER_COMPARATOR); + if (!rc) + rc = pm8xxx_batt_alarm_enable( + PM8XXX_BATT_ALARM_UPPER_COMPARATOR); + if (rc) + pr_err("unable to set alarm state rc=%d\n", rc); + break; + case 2: + rc = pm8xxx_batt_alarm_disable( + PM8XXX_BATT_ALARM_UPPER_COMPARATOR); + if (!rc) + rc = pm8xxx_batt_alarm_enable( + PM8XXX_BATT_ALARM_LOWER_COMPARATOR); + if (rc) + pr_err("unable to set alarm state rc=%d\n", rc); + + break; + default: + pr_err("error received\n"); + break; + } + + return 0; +}; + + #define HOLD_OREG_DATA BIT(1) static int pm_bms_lock_output_data(struct pm8921_bms_chip *chip) { @@ -1616,6 +1745,7 @@ static int charging_adjustments(struct pm8921_bms_chip *chip, static void very_low_voltage_check(struct pm8921_bms_chip *chip, int ibat_ua, int vbat_uv) { + int rc; /* * if battery is very low (v_cutoff voltage + 20mv) hold * a wakelock untill soc = 0% @@ -1634,6 +1764,9 @@ static void very_low_voltage_check(struct pm8921_bms_chip *chip, chip->low_voltage_wake_lock_held = 0; wake_unlock(&chip->low_voltage_wake_lock); chip->soc_calc_period = chip->normal_voltage_calc_ms; + rc = pm8921_bms_enable_batt_alarm(chip); + if (rc) + pr_err("Unable to enable batt alarm\n"); } } @@ -3148,6 +3281,9 @@ static int __devinit pm8921_bms_probe(struct platform_device *pdev) chip->ocv_dis_high_soc = pdata->ocv_dis_high_soc; chip->ocv_dis_low_soc = pdata->ocv_dis_low_soc; + chip->alarm_low_mv = pdata->alarm_low_mv; + chip->alarm_high_mv = pdata->alarm_high_mv; + mutex_init(&chip->calib_mutex); INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work); @@ -3188,6 +3324,18 @@ static int __devinit pm8921_bms_probe(struct platform_device *pdev) pm8921_bms_enable_irq(chip, PM8921_BMS_GOOD_OCV); pm8921_bms_enable_irq(chip, PM8921_BMS_OCV_FOR_R); + rc = pm8921_bms_configure_batt_alarm(chip); + if (rc) { + pr_err("Couldn't configure battery alarm! rc=%d\n", rc); + goto free_irqs; + } + + rc = pm8921_bms_enable_batt_alarm(chip); + if (rc) { + pr_err("Couldn't enable battery alarm! rc=%d\n", rc); + goto free_irqs; + } + calculate_soc_work(&(chip->calculate_soc_delayed_work.work)); rc = get_battery_uvolts(chip, &vbatt); diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h index d670732560a..0806d31e6b6 100644 --- a/include/linux/mfd/pm8xxx/pm8921-bms.h +++ b/include/linux/mfd/pm8xxx/pm8921-bms.h @@ -53,6 +53,8 @@ struct pm8921_bms_platform_data { unsigned int v_cutoff; unsigned int max_voltage_uv; unsigned int rconn_mohm; + unsigned int alarm_low_mv; + unsigned int alarm_high_mv; int enable_fcc_learning; int shutdown_soc_valid_limit; int ignore_shutdown_soc; From 90514c3b2859d83ac19604757513a08820ddcfb5 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Fri, 25 Jan 2013 13:10:07 -0800 Subject: [PATCH 2273/2357] power: pm8921-bms: correct even after faking 100% The current driver restores the OCV to the max voltage when the BMS is in a mode where it fakes 100%. This erases any corrections done to the OCV. Fix it by forcing the OCV to max voltage just once right after charging is done with a full battery. Change-Id: Ibcbc20386e7932fe25d8152943be409397353988 Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/pm8921-bms.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index 417e5559586..454727f1b9f 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -1037,18 +1037,10 @@ static int read_soc_params_raw(struct pm8921_bms_chip *chip, raw->last_good_ocv_uv = chip->last_ocv_uv; } - /* fake a high OCV if we are just done charging */ + /* stop faking 100% after an OCV event */ if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) { chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED; chip->cc_reading_at_100 = 0; - } else { - /* - * force 100% ocv by selecting the highest voltage the - * battery could ever reach - */ - raw->last_good_ocv_uv = chip->max_voltage_uv; - chip->last_ocv_uv = chip->max_voltage_uv; - chip->last_ocv_temp_decidegc = batt_temp_decidegc; } pr_debug("0p625 = %duV\n", chip->xoadc_v0625); pr_debug("1p25 = %duV\n", chip->xoadc_v125); @@ -2616,6 +2608,7 @@ void pm8921_bms_charging_end(int is_battery_full) the_chip->last_ocv_uv = the_chip->max_voltage_uv; raw.last_good_ocv_uv = the_chip->max_voltage_uv; + the_chip->last_ocv_temp_decidegc = batt_temp; /* * since we are treating this as an ocv event * forget the old cc value From 67021bffcb3f76f5eec6ed49b1c09f3cfb74c350 Mon Sep 17 00:00:00 2001 From: Xiaozhe Shi Date: Tue, 12 Feb 2013 23:17:54 -0800 Subject: [PATCH 2274/2357] power: pm8921-bms: Fix CC conversion precision In a previous patch, the precision of the coulomb counter conversion was reduced. Fix this by converting the CC value to picovolt-hours before dividing by r_sense uohm to convert back to microvolt-hours. Change-Id: I2cb4f99ea3636159dfefd2747b24e6ac3bbb7a04 Signed-off-by: Xiaozhe Shi --- drivers/power/pm8921-bms.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index 454727f1b9f..5f52ee848ee 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -643,15 +643,15 @@ static s64 cc_to_microvolt(struct pm8921_bms_chip *chip, s64 cc) #define SLEEP_CLK_HZ 32764 #define SECONDS_PER_HOUR 3600 /** - * ccmicrovolt_to_uvh - + * ccmicrovolt_to_pvh - * @cc_uv: coulumb counter converted to uV * - * RETURNS: coulumb counter based charge in uVh - * (micro Volt Hour) + * RETURNS: coulumb counter based charge in pVh + * (pico Volt Hour) */ -static s64 ccmicrovolt_to_uvh(s64 cc_uv) +static s64 ccmicrovolt_to_pvh(s64 cc_uv) { - return div_s64(cc_uv * CC_READING_TICKS, + return div_s64(cc_uv * CC_READING_TICKS * 1000000L, SLEEP_CLK_HZ * SECONDS_PER_HOUR); } @@ -1174,7 +1174,7 @@ static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv, */ static void calculate_cc_uah(struct pm8921_bms_chip *chip, int cc, int *val) { - int64_t cc_voltage_uv, cc_uvh, cc_uah; + int64_t cc_voltage_uv, cc_pvh, cc_uah; cc_voltage_uv = cc; cc_voltage_uv -= chip->cc_reading_at_100; @@ -1184,9 +1184,9 @@ static void calculate_cc_uah(struct pm8921_bms_chip *chip, int cc, int *val) cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv); cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv); pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv); - cc_uvh = ccmicrovolt_to_uvh(cc_voltage_uv); - pr_debug("cc_uvh = %lld micro_volt_hour\n", cc_uvh); - cc_uah = div_s64(cc_uvh * 1000000LL, chip->r_sense_uohm); + cc_pvh = ccmicrovolt_to_pvh(cc_voltage_uv); + pr_debug("cc_pvh = %lld pico_volt_hour\n", cc_pvh); + cc_uah = div_s64(cc_pvh, chip->r_sense_uohm); *val = cc_uah; } From 4dc49a5251b0caa0fff8985ce90639714daf889f Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Wed, 13 Feb 2013 17:57:40 -0800 Subject: [PATCH 2275/2357] power: pm8921-bms: add capacitive resistance The current code only accounts for the series resistance via a lookup table. Add a configurable parameter to account for capacitive resistance. Change-Id: I6a844b51970a6bdf40cfc1340fa31f580efc1c9e Signed-off-by: Abhijeet Dharmapurikar --- arch/arm/mach-msm/bms-batterydata-desay.c | 3 ++- arch/arm/mach-msm/bms-batterydata.c | 3 ++- drivers/power/pm8921-bms.c | 18 +++++++++++++++--- include/linux/mfd/pm8xxx/batterydata-lib.h | 3 +++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c index 5b72a3f00d5..dd3f346214c 100644 --- a/arch/arm/mach-msm/bms-batterydata-desay.c +++ b/arch/arm/mach-msm/bms-batterydata-desay.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -83,4 +83,5 @@ struct bms_battery_data desay_5200_data = { .pc_temp_ocv_lut = &desay_5200_pc_temp_ocv, .pc_sf_lut = &desay_5200_pc_sf, .default_rbatt_mohm = 156, + .rbatt_capacitive_mohm = 50, }; diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c index 824cf6b7268..0c39df67fc7 100644 --- a/arch/arm/mach-msm/bms-batterydata.c +++ b/arch/arm/mach-msm/bms-batterydata.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -105,4 +105,5 @@ struct bms_battery_data palladium_1500_data = { .pc_temp_ocv_lut = &pc_temp_ocv, .rbatt_sf_lut = &rbatt_sf, .default_rbatt_mohm = 236, + .rbatt_capacitive_mohm = 50, }; diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index 5f52ee848ee..a03c980e400 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -136,6 +136,7 @@ struct pm8921_bms_chip { int amux_2_trim_delta; uint16_t prev_last_good_ocv_raw; int rconn_mohm; + int rbatt_capacitive_mohm; struct mutex last_ocv_uv_mutex; int last_ocv_uv; int last_ocv_temp_decidegc; @@ -847,8 +848,8 @@ static int estimate_ocv(struct pm8921_bms_chip *chip) { int ibat_ua, vbat_uv, ocv_est_uv; int rc; - - int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm; + int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm + + chip->rbatt_capacitive_mohm; rc = pm8921_bms_get_simultaneous_battery_voltage_and_current( &ibat_ua, @@ -917,7 +918,10 @@ static int reset_bms_for_test(void) rc = pm8921_bms_get_simultaneous_battery_voltage_and_current( &ibat_ua, &vbat_uv); - + /* + * don't include rbatt and rbatt_capacitve since we expect this to + * be used with a fake battery which does not have internal resistnaces + */ ocv_est_uv = vbat_uv + (ibat_ua * the_chip->rconn_mohm) / 1000; pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv); the_chip->last_ocv_uv = ocv_est_uv; @@ -1072,6 +1076,10 @@ static int get_rbatt(struct pm8921_bms_chip *chip, int soc_rbatt, int batt_temp) pr_debug("adding rconn_mohm = %d rbatt = %d\n", the_chip->rconn_mohm, rbatt); + rbatt += the_chip->rbatt_capacitive_mohm; + pr_debug("adding rbatt_capacitive_mohm = %d rbatt = %d\n", + the_chip->rbatt_capacitive_mohm, rbatt); + if (is_between(20, 10, soc_rbatt)) rbatt = rbatt + ((20 - soc_rbatt) * chip->delta_rbatt_mohm) / 10; @@ -2867,6 +2875,8 @@ static int set_battery_data(struct pm8921_bms_chip *chip) chip->default_rbatt_mohm = palladium_1500_data.default_rbatt_mohm; chip->delta_rbatt_mohm = palladium_1500_data.delta_rbatt_mohm; + chip->rbatt_capacitive_mohm + = palladium_1500_data.rbatt_capacitive_mohm; return 0; desay: chip->fcc = desay_5200_data.fcc; @@ -2876,6 +2886,8 @@ static int set_battery_data(struct pm8921_bms_chip *chip) chip->rbatt_sf_lut = desay_5200_data.rbatt_sf_lut; chip->default_rbatt_mohm = desay_5200_data.default_rbatt_mohm; chip->delta_rbatt_mohm = desay_5200_data.delta_rbatt_mohm; + chip->rbatt_capacitive_mohm + = desay_5200_data.rbatt_capacitive_mohm; return 0; } diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h index c55e47e0ce9..62326ef26e3 100644 --- a/include/linux/mfd/pm8xxx/batterydata-lib.h +++ b/include/linux/mfd/pm8xxx/batterydata-lib.h @@ -88,6 +88,8 @@ enum battery_type { * readings from bms are not available. * @delta_rbatt_mohm: the resistance to be added towards lower soc to * compensate for battery capacitance. + * @rbatt_capacitve_mohm: the resistance to be added to compensate for + * battery capacitance */ struct bms_battery_data { @@ -99,6 +101,7 @@ struct bms_battery_data { struct sf_lut *rbatt_sf_lut; int default_rbatt_mohm; int delta_rbatt_mohm; + int rbatt_capacitive_mohm; }; #if defined(CONFIG_PM8921_BMS) || \ From c716e1a0251131447eaff9d635b2007c791e3f2e Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Wed, 13 Feb 2013 19:51:56 -0800 Subject: [PATCH 2276/2357] power: pm8921-bms: fix the mutex usage get_reading() should be protected by the ocv mutex not the bms output mutex. Change-Id: I24eea963611a8df87ce350120d318319cd1a6c3a Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/pm8921-bms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index a03c980e400..3da777eaea5 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -3018,9 +3018,9 @@ static int get_reading(void *data, u64 * val) int ret = 0; struct pm8921_soc_params raw; - mutex_lock(&the_chip->bms_output_lock); + mutex_lock(&the_chip->last_ocv_uv_mutex); read_soc_params_raw(the_chip, &raw, 300); - mutex_unlock(&the_chip->bms_output_lock); + mutex_lock(&the_chip->last_ocv_uv_mutex); *val = 0; From 64b37c2197d4680271529ee3f82e4a25740a49c5 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Wed, 13 Feb 2013 16:47:14 -0800 Subject: [PATCH 2277/2357] power: pm8921-bms: optimize finding ocv The current code returns if the OCV is within 1% of the expected percent charge. This is suboptimal and instead it should try to be find an OCV that results exactly in the desired percent charge. Change-Id: If0918d0fb386719487c2e0dfa24c255b3c32c5dc Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/pm8921-bms.c | 59 ++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index 3da777eaea5..9fa952e82cb 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -1591,6 +1591,8 @@ int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua, } EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current); +#define SIGN(x) ((x) < 0 ? -1 : 1) + static void find_ocv_for_soc(struct pm8921_bms_chip *chip, int batt_temp, int chargecycles, @@ -1618,16 +1620,55 @@ static void find_ocv_for_soc(struct pm8921_bms_chip *chip, new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv); pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv); - while (abs(new_pc - pc) > 1) { + if (abs(new_pc - pc) > 0) { + /* Maximum spins to make in while-loop when searching in + * full resolution. + */ + const unsigned int max_spin_count = + chip->max_voltage_uv / 1000 - chip->v_cutoff + 1; + unsigned int count = 0; int delta_mv = 5; - - if (new_pc > pc) - delta_mv = -1 * delta_mv; - - ocv = ocv + delta_mv; - new_pc = interpolate_pc(chip->pc_temp_ocv_lut, - batt_temp_degc, ocv); - pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv); + int diff = abs(new_pc - pc); + char sign = SIGN(new_pc - pc); + char old_sign; + int old_diff; + int old_ocv; + + do { + count++; + old_ocv = ocv; + old_diff = diff; + old_sign = sign; + + if (new_pc > pc) + ocv -= delta_mv; + else + ocv += delta_mv; + + new_pc = interpolate_pc(chip->pc_temp_ocv_lut, + batt_temp_degc, ocv); + pr_debug("test revlookup pc = %d for ocv = %d\n", + new_pc, ocv); + diff = abs(new_pc - pc); + sign = SIGN(new_pc - pc); + + if (sign != old_sign) { + if (delta_mv == 5) { + /* + * we crossed our desired PC probably + * becuase we were overcorrecting + */ + delta_mv = 1; + } else { + /* we crossed our desired PC even with + * 1mV steps, choose the best of two */ + if (diff > old_diff) + ocv = old_ocv; + + break; + } + } + } while (count <= max_spin_count && diff > 0); } *ocv_uv = ocv * 1000; From 2f8088b60a262c47033bcfad49502dd51713b7c6 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Wed, 27 Feb 2013 19:16:22 -0800 Subject: [PATCH 2278/2357] power: pm8921-bms: reset coulomb counter when faking high ocv When charging is complete, BMS will fake a high OCV in order to appear at 100%. Instead of tracking the cc value at EOC and using that to offset further CC reads reset the coulomb counter in the h/w itself. Change-Id: I7e4cb7a057d19c43aa0f949411b272a9e02d7cfd Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/pm8921-bms.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index 9fa952e82cb..a189a852d3d 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -128,7 +128,6 @@ struct pm8921_bms_chip { int catch_up_time_us; enum battery_type batt_type; uint16_t ocv_reading_at_100; - int cc_reading_at_100; int max_voltage_uv; int chg_term_ua; @@ -1042,10 +1041,8 @@ static int read_soc_params_raw(struct pm8921_bms_chip *chip, } /* stop faking 100% after an OCV event */ - if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) { + if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED; - chip->cc_reading_at_100 = 0; - } pr_debug("0p625 = %duV\n", chip->xoadc_v0625); pr_debug("1p25 = %duV\n", chip->xoadc_v125); pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n", @@ -1185,10 +1182,7 @@ static void calculate_cc_uah(struct pm8921_bms_chip *chip, int cc, int *val) int64_t cc_voltage_uv, cc_pvh, cc_uah; cc_voltage_uv = cc; - cc_voltage_uv -= chip->cc_reading_at_100; - pr_debug("cc = %d. after subtracting 0x%x cc = %lld\n", - cc, chip->cc_reading_at_100, - cc_voltage_uv); + pr_debug("cc = %d\n", cc); cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv); cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv); pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv); @@ -1513,10 +1507,7 @@ static void calculate_soc_params(struct pm8921_bms_chip *chip, /* calculate cc micro_volt_hour */ calculate_cc_uah(chip, raw->cc, cc_uah); - pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n", - *cc_uah, raw->cc, - (int64_t)raw->cc - chip->cc_reading_at_100, - chip->cc_reading_at_100); + pr_debug("cc_uah = %duAh raw->cc = %x\n", *cc_uah, raw->cc); soc_rbatt = ((*remaining_charge_uah - *cc_uah) * 100) / *fcc_uah; if (soc_rbatt < 0) @@ -2653,19 +2644,20 @@ void pm8921_bms_charging_end(int is_battery_full) if (is_battery_full) { the_chip->ocv_reading_at_100 = raw.last_good_ocv_raw; - the_chip->cc_reading_at_100 = raw.cc; the_chip->last_ocv_uv = the_chip->max_voltage_uv; raw.last_good_ocv_uv = the_chip->max_voltage_uv; + raw.cc = 0; + /* reset the cc in h/w */ + reset_cc(the_chip); the_chip->last_ocv_temp_decidegc = batt_temp; /* * since we are treating this as an ocv event * forget the old cc value */ the_chip->last_cc_uah = 0; - pr_debug("EOC BATT_FULL ocv_reading = 0x%x cc = 0x%x\n", - the_chip->ocv_reading_at_100, - the_chip->cc_reading_at_100); + pr_debug("EOC BATT_FULL ocv_reading = 0x%x\n", + the_chip->ocv_reading_at_100); } the_chip->end_percent = calculate_state_of_charge(the_chip, &raw, From dd54ec4067a23236736afecbda120030d7ce8fe9 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Fri, 22 Feb 2013 10:16:28 +0100 Subject: [PATCH 2279/2357] ALSA: hda - hdmi: Make jacks phantom, if they're not detectable commit 30efd8debd1ef30be342d374f01e993509f5b76b upstream. Just as for analog codecs, a jack that isn't suitable for detection (in this case, NO_PRESENCE was set) should be a phantom Jack instead of a normal one. Thanks to Raymond Yau for spotting. BugLink: https://bugs.launchpad.net/bugs/961286 BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=903869 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_hdmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 02a6e3f481e..fa2ce0cf47d 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1244,6 +1244,9 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) if (pcmdev > 0) sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); + if (!is_jack_detectable(codec, per_pin->pin_nid)) + strncat(hdmi_str, " Phantom", + sizeof(hdmi_str) - strlen(hdmi_str) - 1); return snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, 0); } From db6154ead40e0a568982ec4885cfa3fa89e67324 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 24 Jan 2013 23:24:56 -0500 Subject: [PATCH 2280/2357] quota: autoload the quota_v2 module for QFMT_VFS_V1 quota format commit c3ad83d9efdfe6a86efd44945a781f00c879b7b4 upstream. Otherwise, ext4 file systems with the quota featured enable will get a very confusing "No such process" error message if the quota code is built as a module and the quota_v2 module has not been loaded. Signed-off-by: "Theodore Ts'o" Reviewed-by: Carlos Maiolino Acked-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- include/linux/quota.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/quota.h b/include/linux/quota.h index c09fa042b5e..ffd8607ca4b 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -417,6 +417,7 @@ struct quota_module_name { #define INIT_QUOTA_MODULE_NAMES {\ {QFMT_VFS_OLD, "quota_v1"},\ {QFMT_VFS_V0, "quota_v2"},\ + {QFMT_VFS_V1, "quota_v2"},\ {0, NULL}} #endif /* __KERNEL__ */ From 0c8581863389e969dcbf6d9e79971435a1ecf554 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 6 Feb 2013 12:55:23 +0100 Subject: [PATCH 2281/2357] iommu/amd: Initialize device table after dma_ops commit f528d980c17b8714aedc918ba86e058af914d66b upstream. When dma_ops are initialized the unity mappings are created. The init_device_table_dma() function makes sure DMA from all devices is blocked by default. This opens a short window in time where DMA to unity mapped regions is blocked by the IOMMU. Make sure this does not happen by initializing the device table after dma_ops. Signed-off-by: Joerg Roedel Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd_iommu_init.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index ef0ae93500f..b573f803d84 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1572,8 +1572,6 @@ int __init amd_iommu_init_hardware(void) if (amd_iommu_pd_alloc_bitmap == NULL) goto free; - /* init the device table */ - init_device_table(); /* * let all alias entries point to itself @@ -1655,6 +1653,7 @@ static int amd_iommu_enable_interrupts(void) */ static int __init amd_iommu_init(void) { + struct amd_iommu *iommu; int ret = 0; ret = amd_iommu_init_hardware(); @@ -1673,6 +1672,12 @@ static int __init amd_iommu_init(void) if (ret) goto free; + /* init the device table */ + init_device_table(); + + for_each_iommu(iommu) + iommu_flush_all_caches(iommu); + amd_iommu_init_api(); x86_platform.iommu_shutdown = disable_iommus; From db3d76a623b8ce429318cc2491881c02b790dab4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 20 Feb 2013 15:24:12 -0800 Subject: [PATCH 2282/2357] posix-timer: Don't call idr_find() with out-of-range ID commit e182bb38d7db7494fa5dcd82da17fe0dedf60ecf upstream. When idr_find() was fed a negative ID, it used to look up the ID ignoring the sign bit before recent ("idr: remove MAX_IDR_MASK and move left MAX_IDR_* into idr.c") patch. Now a negative ID triggers a WARN_ON_ONCE(). __lock_timer() feeds timer_id from userland directly to idr_find() without sanitizing it which can trigger the above malfunctions. Add a range check on @timer_id before invoking idr_find() in __lock_timer(). While timer_t is defined as int by all archs at the moment, Andrew worries that it may be defined as a larger type later on. Make the test cover larger integers too so that it at least is guaranteed to not return the wrong timer. Note that WARN_ON_ONCE() in idr_find() on id < 0 is transitional precaution while moving away from ignoring MSB. Once it's gone we can remove the guard as long as timer_t isn't larger than int. Signed-off-by: Tejun Heo Reported-by: Sasha Levin Cc: Andrew Morton Link: http://lkml.kernel.org/r/20130220232412.GL3570@htj.dyndns.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/posix-timers.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index 69185ae6b70..e885be1e8a1 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -639,6 +639,13 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags) { struct k_itimer *timr; + /* + * timer_t could be any type >= int and we want to make sure any + * @timer_id outside positive int range fails lookup. + */ + if ((unsigned long long)timer_id > INT_MAX) + return NULL; + rcu_read_lock(); timr = idr_find(&posix_timers_id, (int)timer_id); if (timr) { From e6842472eb7f8091c27eb43ad934097ce04d3fbb Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 13 Feb 2013 15:18:38 -0500 Subject: [PATCH 2283/2357] ftrace: Call ftrace cleanup module notifier after all other notifiers commit 8c189ea64eea01ca20d102ddb74d6936dd16c579 upstream. Commit: c1bf08ac "ftrace: Be first to run code modification on modules" changed ftrace module notifier's priority to INT_MAX in order to process the ftrace nops before anything else could touch them (namely kprobes). This was the correct thing to do. Unfortunately, the ftrace module notifier also contains the ftrace clean up code. As opposed to the set up code, this code should be run *after* all the module notifiers have run in case a module is doing correct clean-up and unregisters its ftrace hooks. Basically, ftrace needs to do clean up on module removal, as it needs to know about code being removed so that it doesn't try to modify that code. But after it removes the module from its records, if a ftrace user tries to remove a probe, that removal will fail due as the record of that code segment no longer exists. Nothing really bad happens if the probe removal is called after ftrace did the clean up, but the ftrace removal function will return an error. Correct code (such as kprobes) will produce a WARN_ON() if it fails to remove the probe. As people get annoyed by frivolous warnings, it's best to do the ftrace clean up after everything else. By splitting the ftrace_module_notifier into two notifiers, one that does the module load setup that is run at high priority, and the other that is called for module clean up that is run at low priority, the problem is solved. Reported-by: Frank Ch. Eigler Acked-by: Masami Hiramatsu Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/ftrace.c | 46 ++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6b194d842b1..4a86e640408 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -3841,37 +3841,51 @@ static void ftrace_init_module(struct module *mod, ftrace_process_locs(mod, start, end); } -static int ftrace_module_notify(struct notifier_block *self, - unsigned long val, void *data) +static int ftrace_module_notify_enter(struct notifier_block *self, + unsigned long val, void *data) { struct module *mod = data; - switch (val) { - case MODULE_STATE_COMING: + if (val == MODULE_STATE_COMING) ftrace_init_module(mod, mod->ftrace_callsites, mod->ftrace_callsites + mod->num_ftrace_callsites); - break; - case MODULE_STATE_GOING: + return 0; +} + +static int ftrace_module_notify_exit(struct notifier_block *self, + unsigned long val, void *data) +{ + struct module *mod = data; + + if (val == MODULE_STATE_GOING) ftrace_release_mod(mod); - break; - } return 0; } #else -static int ftrace_module_notify(struct notifier_block *self, - unsigned long val, void *data) +static int ftrace_module_notify_enter(struct notifier_block *self, + unsigned long val, void *data) +{ + return 0; +} +static int ftrace_module_notify_exit(struct notifier_block *self, + unsigned long val, void *data) { return 0; } #endif /* CONFIG_MODULES */ -struct notifier_block ftrace_module_nb = { - .notifier_call = ftrace_module_notify, +struct notifier_block ftrace_module_enter_nb = { + .notifier_call = ftrace_module_notify_enter, .priority = INT_MAX, /* Run before anything that can use kprobes */ }; +struct notifier_block ftrace_module_exit_nb = { + .notifier_call = ftrace_module_notify_exit, + .priority = INT_MIN, /* Run after anything that can remove kprobes */ +}; + extern unsigned long __start_mcount_loc[]; extern unsigned long __stop_mcount_loc[]; @@ -3903,9 +3917,13 @@ void __init ftrace_init(void) __start_mcount_loc, __stop_mcount_loc); - ret = register_module_notifier(&ftrace_module_nb); + ret = register_module_notifier(&ftrace_module_enter_nb); + if (ret) + pr_warning("Failed to register trace ftrace module enter notifier\n"); + + ret = register_module_notifier(&ftrace_module_exit_nb); if (ret) - pr_warning("Failed to register trace ftrace module notifier\n"); + pr_warning("Failed to register trace ftrace module exit notifier\n"); set_ftrace_early_filters(); From 92916fb21cc71f7877c06ab998728f118e2d72cb Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Wed, 20 Feb 2013 20:36:12 +0000 Subject: [PATCH 2284/2357] x86, efi: Make "noefi" really disable EFI runtime serivces commit fb834c7acc5e140cf4f9e86da93a66de8c0514da upstream. commit 1de63d60cd5b ("efi: Clear EFI_RUNTIME_SERVICES rather than EFI_BOOT by "noefi" boot parameter") attempted to make "noefi" true to its documentation and disable EFI runtime services to prevent the bricking bug described in commit e0094244e41c ("samsung-laptop: Disable on EFI hardware"). However, it's not possible to clear EFI_RUNTIME_SERVICES from an early param function because EFI_RUNTIME_SERVICES is set in efi_init() *after* parse_early_param(). This resulted in "noefi" effectively becoming a no-op and no longer providing users with a way to disable EFI, which is bad for those users that have buggy machines. Reported-by: Walt Nelson Jr Cc: Satoru Takeuchi Signed-off-by: Matt Fleming Link: http://lkml.kernel.org/r/1361392572-25657-1-git-send-email-matt@console-pimps.org Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/efi/efi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 3705bb049e5..1e406371a68 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -84,9 +84,10 @@ int efi_enabled(int facility) } EXPORT_SYMBOL(efi_enabled); +static bool disable_runtime = false; static int __init setup_noefi(char *arg) { - clear_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility); + disable_runtime = true; return 0; } early_param("noefi", setup_noefi); @@ -733,7 +734,7 @@ void __init efi_init(void) if (!efi_is_native()) pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); else { - if (efi_runtime_init()) + if (disable_runtime || efi_runtime_init()) return; set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility); } From 938987dc41c19b1683934e0d4e75ae9b04456b80 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 25 Feb 2013 15:54:08 -0500 Subject: [PATCH 2285/2357] doc, xen: Mention 'earlyprintk=xen' in the documentation. commit 2482a92e7d17187301d7313cfe5021b13393a0b4 upstream. The earlyprintk for Xen PV guests utilizes a simple hypercall (console_io) to provide output to Xen emergency console. Note that the Xen hypervisor should be booted with 'loglevel=all' to output said information. Reported-by: H. Peter Anvin Signed-off-by: Konrad Rzeszutek Wilk Link: http://lkml.kernel.org/r/1361825650-14031-2-git-send-email-konrad.wilk@oracle.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index c1601e5a8b7..f2e1645a2bd 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -742,6 +742,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. earlyprintk= [X86,SH,BLACKFIN] earlyprintk=vga + earlyprintk=xen earlyprintk=serial[,ttySn[,baudrate]] earlyprintk=ttySn[,baudrate] earlyprintk=dbgp[debugController#] @@ -759,6 +760,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. The VGA output is eventually overwritten by the real console. + The xen output can only be used by Xen PV guests. + ekgdboc= [X86,KGDB] Allow early kernel console debugging ekgdboc=kbd From 2a0887caaf540517017d994d8d1940416a3365da Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 25 Feb 2013 15:54:09 -0500 Subject: [PATCH 2286/2357] doc, kernel-parameters: Document 'console=hvc' commit a2fd6419174470f5ae6383f5037d0ee21ed9833f upstream. Both the PowerPC hypervisor and Xen hypervisor can utilize the hvc driver. Signed-off-by: Konrad Rzeszutek Wilk Link: http://lkml.kernel.org/r/1361825650-14031-3-git-send-email-konrad.wilk@oracle.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index f2e1645a2bd..753d18ae010 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -557,6 +557,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. UART at the specified I/O port or MMIO address, switching to the matching ttyS device later. The options are the same as for ttyS, above. + hvc Use the hypervisor console device . This is for + both Xen and PowerPC hypervisors. If the device connected to the port is not a TTY but a braille device, prepend "brl," before the device type, for instance From 58d7422c654e7720a3920e63dcd6c64052aeec2d Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 27 Feb 2013 12:46:40 -0800 Subject: [PATCH 2287/2357] x86: Make sure we can boot in the case the BDA contains pure garbage commit 7c10093692ed2e6f318387d96b829320aa0ca64c upstream. On non-BIOS platforms it is possible that the BIOS data area contains garbage instead of being zeroed or something equivalent (firmware people: we are talking of 1.5K here, so please do the sane thing.) We need on the order of 20-30K of low memory in order to boot, which may grow up to < 64K in the future. We probably want to avoid the lowest of the low memory. At the same time, it seems extremely unlikely that a legitimate EBDA would ever reach down to the 128K (which would require it to be over half a megabyte in size.) Thus, pick 128K as the cutoff for "this is insane, ignore." We may still end up reserving a bunch of extra memory on the low megabyte, but that is not really a major issue these days. In the worst case we lose 512K of RAM. This code really should be merged with trim_bios_range() in arch/x86/kernel/setup.c, but that is a bigger patch for a later merge window. Reported-by: Darren Hart Signed-off-by: H. Peter Anvin Cc: Matt Fleming Link: http://lkml.kernel.org/n/tip-oebml055yyfm8yxmria09rja@git.kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/head.c | 53 +++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c index 48d9d4ea102..992f442ca15 100644 --- a/arch/x86/kernel/head.c +++ b/arch/x86/kernel/head.c @@ -5,8 +5,6 @@ #include #include -#define BIOS_LOWMEM_KILOBYTES 0x413 - /* * The BIOS places the EBDA/XBDA at the top of conventional * memory, and usually decreases the reported amount of @@ -16,17 +14,30 @@ * chipset: reserve a page before VGA to prevent PCI prefetch * into it (errata #56). Usually the page is reserved anyways, * unless you have no PS/2 mouse plugged in. + * + * This functions is deliberately very conservative. Losing + * memory in the bottom megabyte is rarely a problem, as long + * as we have enough memory to install the trampoline. Using + * memory that is in use by the BIOS or by some DMA device + * the BIOS didn't shut down *is* a big problem. */ + +#define BIOS_LOWMEM_KILOBYTES 0x413 +#define LOWMEM_CAP 0x9f000U /* Absolute maximum */ +#define INSANE_CUTOFF 0x20000U /* Less than this = insane */ + void __init reserve_ebda_region(void) { unsigned int lowmem, ebda_addr; - /* To determine the position of the EBDA and the */ - /* end of conventional memory, we need to look at */ - /* the BIOS data area. In a paravirtual environment */ - /* that area is absent. We'll just have to assume */ - /* that the paravirt case can handle memory setup */ - /* correctly, without our help. */ + /* + * To determine the position of the EBDA and the + * end of conventional memory, we need to look at + * the BIOS data area. In a paravirtual environment + * that area is absent. We'll just have to assume + * that the paravirt case can handle memory setup + * correctly, without our help. + */ if (paravirt_enabled()) return; @@ -37,19 +48,23 @@ void __init reserve_ebda_region(void) /* start of EBDA area */ ebda_addr = get_bios_ebda(); - /* Fixup: bios puts an EBDA in the top 64K segment */ - /* of conventional memory, but does not adjust lowmem. */ - if ((lowmem - ebda_addr) <= 0x10000) - lowmem = ebda_addr; + /* + * Note: some old Dells seem to need 4k EBDA without + * reporting so, so just consider the memory above 0x9f000 + * to be off limits (bugzilla 2990). + */ + + /* If the EBDA address is below 128K, assume it is bogus */ + if (ebda_addr < INSANE_CUTOFF) + ebda_addr = LOWMEM_CAP; - /* Fixup: bios does not report an EBDA at all. */ - /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */ - if ((ebda_addr == 0) && (lowmem >= 0x9f000)) - lowmem = 0x9f000; + /* If lowmem is less than 128K, assume it is bogus */ + if (lowmem < INSANE_CUTOFF) + lowmem = LOWMEM_CAP; - /* Paranoia: should never happen, but... */ - if ((lowmem == 0) || (lowmem >= 0x100000)) - lowmem = 0x9f000; + /* Use the lower of the lowmem and EBDA markers as the cutoff */ + lowmem = min(lowmem, ebda_addr); + lowmem = min(lowmem, LOWMEM_CAP); /* Absolute cap */ /* reserve all memory between lowmem and the 1MB mark */ memblock_reserve(lowmem, 0x100000 - lowmem); From 3fa4f7261d75cb6b35fdf8d329f5fd64e7354c58 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 18 Feb 2013 18:00:33 -0800 Subject: [PATCH 2288/2357] target: Fix lookup of dynamic NodeACLs during cached demo-mode operation commit fcf29481fb8e106daad6688f2e898226ee928992 upstream. This patch fixes a bug in core_tpg_check_initiator_node_acl() -> core_tpg_get_initiator_node_acl() where a dynamically created se_node_acl generated during session login would be skipped during subsequent lookup due to the '!acl->dynamic_node_acl' check, causing a new se_node_acl to be created with a duplicate ->initiatorname. This would occur when a fabric endpoint was configured with TFO->tpg_check_demo_mode()=1 + TPF->tpg_check_demo_mode_cache()=1 preventing the release of an existing se_node_acl during se_session shutdown. Also, drop the unnecessary usage of core_tpg_get_initiator_node_acl() within core_dev_init_initiator_node_lun_acl() that originally required the extra '!acl->dynamic_node_acl' check, and just pass the configfs provided se_node_acl pointer instead. Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_device.c | 13 ++++--------- drivers/target/target_core_fabric_configfs.c | 4 ++-- drivers/target/target_core_internal.h | 2 +- drivers/target/target_core_tpg.c | 10 ++-------- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 4ecf9d61c22..79d9865a127 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1483,24 +1483,18 @@ static struct se_lun *core_dev_get_lun(struct se_portal_group *tpg, u32 unpacked struct se_lun_acl *core_dev_init_initiator_node_lun_acl( struct se_portal_group *tpg, + struct se_node_acl *nacl, u32 mapped_lun, - char *initiatorname, int *ret) { struct se_lun_acl *lacl; - struct se_node_acl *nacl; - if (strlen(initiatorname) >= TRANSPORT_IQN_LEN) { + if (strlen(nacl->initiatorname) >= TRANSPORT_IQN_LEN) { pr_err("%s InitiatorName exceeds maximum size.\n", tpg->se_tpg_tfo->get_fabric_name()); *ret = -EOVERFLOW; return NULL; } - nacl = core_tpg_get_initiator_node_acl(tpg, initiatorname); - if (!nacl) { - *ret = -EINVAL; - return NULL; - } lacl = kzalloc(sizeof(struct se_lun_acl), GFP_KERNEL); if (!lacl) { pr_err("Unable to allocate memory for struct se_lun_acl.\n"); @@ -1511,7 +1505,8 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl( INIT_LIST_HEAD(&lacl->lacl_list); lacl->mapped_lun = mapped_lun; lacl->se_lun_nacl = nacl; - snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); + snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", + nacl->initiatorname); return lacl; } diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 817ba7c849e..1516bda3f75 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -357,8 +357,8 @@ static struct config_group *target_fabric_make_mappedlun( goto out; } - lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun, - config_item_name(acl_ci), &ret); + lacl = core_dev_init_initiator_node_lun_acl(se_tpg, se_nacl, + mapped_lun, &ret); if (!lacl) { ret = -EINVAL; goto out; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 21c05638f15..17179b1af54 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -61,7 +61,7 @@ struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *, int core_dev_del_lun(struct se_portal_group *, u32); struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, - u32, char *, int *); + struct se_node_acl *, u32, int *); int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, struct se_lun_acl *, u32, u32); int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index ba537b6fd85..0e17fa3da01 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -114,16 +114,10 @@ struct se_node_acl *core_tpg_get_initiator_node_acl( struct se_node_acl *acl; spin_lock_irq(&tpg->acl_node_lock); - list_for_each_entry(acl, &tpg->acl_node_list, acl_list) { - if (!strcmp(acl->initiatorname, initiatorname) && - !acl->dynamic_node_acl) { - spin_unlock_irq(&tpg->acl_node_lock); - return acl; - } - } + acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); spin_unlock_irq(&tpg->acl_node_lock); - return NULL; + return acl; } /* core_tpg_add_node_to_devs(): From 316857e5fe5391057d5a05f215e01d0deff7c473 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 18 Feb 2013 18:31:37 -0800 Subject: [PATCH 2289/2357] target: Add missing mapped_lun bounds checking during make_mappedlun setup commit fbbf8555a986ed31e54f006b6cc637ea4ff1425b upstream. This patch adds missing bounds checking for the configfs provided mapped_lun value during target_fabric_make_mappedlun() setup ahead of se_lun_acl initialization. This addresses a potential OOPs when using a mapped_lun value that exceeds the hardcoded TRANSPORT_MAX_LUNS_PER_TPG-1 value within se_node_acl->device_list[]. Reported-by: Jan Engelhardt Cc: Jan Engelhardt Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_fabric_configfs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 1516bda3f75..6b79ee71152 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -356,6 +356,14 @@ static struct config_group *target_fabric_make_mappedlun( ret = -EINVAL; goto out; } + if (mapped_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { + pr_err("Mapped LUN: %lu exceeds TRANSPORT_MAX_LUNS_PER_TPG" + "-1: %u for Target Portal Group: %u\n", mapped_lun, + TRANSPORT_MAX_LUNS_PER_TPG-1, + se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); + ret = -EINVAL; + goto out; + } lacl = core_dev_init_initiator_node_lun_acl(se_tpg, se_nacl, mapped_lun, &ret); From fa1c19bbbd6cb82086da10ae3817f8d5d8c6a7ae Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Feb 2013 13:16:39 +1100 Subject: [PATCH 2290/2357] ocfs2: fix possible use-after-free with AIO commit 9b171e0c74ca0549d0610990a862dd895870f04a upstream. Running AIO is pinning inode in memory using file reference. Once AIO is completed using aio_complete(), file reference is put and inode can be freed from memory. So we have to be sure that calling aio_complete() is the last thing we do with the inode. Signed-off-by: Jan Kara Acked-by: Jeff Moyer Acked-by: Joel Becker Cc: Mark Fasheh Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/aops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 657743254eb..340bd02839b 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -593,9 +593,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, level = ocfs2_iocb_rw_locked_level(iocb); ocfs2_rw_unlock(inode, level); + inode_dio_done(inode); if (is_async) aio_complete(iocb, ret, 0); - inode_dio_done(inode); } /* From 0d5b0fcbebada4d74130ea9911c38dad1faacb8c Mon Sep 17 00:00:00 2001 From: Jeff Liu Date: Wed, 27 Feb 2013 17:02:48 -0800 Subject: [PATCH 2291/2357] ocfs2: fix ocfs2_init_security_and_acl() to initialize acl correctly commit 32918dd9f19e5960af4cdfa41190bb843fb2247b upstream. We need to re-initialize the security for a new reflinked inode with its parent dirs if it isn't specified to be preserved for ocfs2_reflink(). However, the code logic is broken at ocfs2_init_security_and_acl() although ocfs2_init_security_get() succeed. As a result, ocfs2_acl_init() does not involked and therefore the default ACL of parent dir was missing on the new inode. Note this was introduced by 9d8f13ba3 ("security: new security_inode_init_security API adds function callback") To reproduce: set default ACL for the parent dir(ocfs2 in this case): $ setfacl -m default:user:jeff:rwx ../ocfs2/ $ getfacl ../ocfs2/ # file: ../ocfs2/ # owner: jeff # group: jeff user::rwx group::r-x other::r-x default:user::rwx default:user:jeff:rwx default:group::r-x default:mask::rwx default:other::r-x $ touch a $ getfacl a # file: a # owner: jeff # group: jeff user::rw- group::rw- other::r-- Before patching, create reflink file b from a, the user default ACL entry(user:jeff:rwx)was missing: $ ./ocfs2_reflink a b $ getfacl b # file: b # owner: jeff # group: jeff user::rw- group::rw- other::r-- In this case, the end user can also observed an error message at syslog: (ocfs2_reflink,3229,2):ocfs2_init_security_and_acl:7193 ERROR: status = 0 After applying this patch, create reflink file c from a: $ ./ocfs2_reflink a c $ getfacl c # file: c # owner: jeff # group: jeff user::rw- user:jeff:rwx #effective:rw- group::r-x #effective:r-- mask::rw- other::r-- Test program: /* Usage: reflink */ #include #include #include #include #include #include #include #include #include static int reflink_file(char const *src_name, char const *dst_name, bool preserve_attrs) { int fd; #ifndef REFLINK_ATTR_NONE # define REFLINK_ATTR_NONE 0 #endif #ifndef REFLINK_ATTR_PRESERVE # define REFLINK_ATTR_PRESERVE 1 #endif #ifndef OCFS2_IOC_REFLINK struct reflink_arguments { uint64_t old_path; uint64_t new_path; uint64_t preserve; }; # define OCFS2_IOC_REFLINK _IOW ('o', 4, struct reflink_arguments) #endif struct reflink_arguments args = { .old_path = (unsigned long) src_name, .new_path = (unsigned long) dst_name, .preserve = preserve_attrs ? REFLINK_ATTR_PRESERVE : REFLINK_ATTR_NONE, }; fd = open(src_name, O_RDONLY); if (fd < 0) { fprintf(stderr, "Failed to open %s: %s\n", src_name, strerror(errno)); return -1; } if (ioctl(fd, OCFS2_IOC_REFLINK, &args) < 0) { fprintf(stderr, "Failed to reflink %s to %s: %s\n", src_name, dst_name, strerror(errno)); return -1; } } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stdout, "Usage: %s source dest\n", argv[0]); return 1; } return reflink_file(argv[1], argv[2], 0); } Signed-off-by: Jie Liu Reviewed-by: Tao Ma Cc: Mimi Zohar Cc: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 0ba9ea1e796..2e3ea308c14 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -7189,7 +7189,7 @@ int ocfs2_init_security_and_acl(struct inode *dir, struct buffer_head *dir_bh = NULL; ret = ocfs2_init_security_get(inode, dir, qstr, NULL); - if (!ret) { + if (ret) { mlog_errno(ret); goto leave; } From 5978ac7c68e30bd9a322aa62efc411581263f881 Mon Sep 17 00:00:00 2001 From: "Xiaowei.Hu" Date: Wed, 27 Feb 2013 17:02:49 -0800 Subject: [PATCH 2292/2357] ocfs2: ac->ac_allow_chain_relink=0 won't disable group relink commit 309a85b6861fedbb48a22d45e0e079d1be993b3a upstream. ocfs2_block_group_alloc_discontig() disables chain relink by setting ac->ac_allow_chain_relink = 0 because it grabs clusters from multiple cluster groups. It doesn't keep the credits for all chain relink,but ocfs2_claim_suballoc_bits overrides this in this call trace: ocfs2_block_group_claim_bits()->ocfs2_claim_clusters()-> __ocfs2_claim_clusters()->ocfs2_claim_suballoc_bits() ocfs2_claim_suballoc_bits set ac->ac_allow_chain_relink = 1; then call ocfs2_search_chain() one time and disable it again, and then we run out of credits. Fix is to allow relink by default and disable it in ocfs2_block_group_alloc_discontig. Without this patch, End-users will run into a crash due to run out of credits, backtrace like this: RIP: 0010:[] [] jbd2_journal_dirty_metadata+0x164/0x170 [jbd2] RSP: 0018:ffff8801b919b5b8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff88022139ddc0 RCX: ffff880159f652d0 RDX: ffff880178aa3000 RSI: ffff880159f652d0 RDI: ffff880087f09bf8 RBP: ffff8801b919b5e8 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000001e00 R11: 00000000000150b0 R12: ffff880159f652d0 R13: ffff8801a0cae908 R14: ffff880087f09bf8 R15: ffff88018d177800 FS: 00007fc9b0b6b6e0(0000) GS:ffff88022fd40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 000000000040819c CR3: 0000000184017000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process dd (pid: 9945, threadinfo ffff8801b919a000, task ffff880149a264c0) Call Trace: ocfs2_journal_dirty+0x2f/0x70 [ocfs2] ocfs2_relink_block_group+0x111/0x480 [ocfs2] ocfs2_search_chain+0x455/0x9a0 [ocfs2] ... Signed-off-by: Xiaowei.Hu Reviewed-by: Srinivas Eeda Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/suballoc.c | 7 +++---- fs/ocfs2/suballoc.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index f169da4624f..b7e74b580c0 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -642,7 +642,7 @@ ocfs2_block_group_alloc_discontig(handle_t *handle, * cluster groups will be staying in cache for the duration of * this operation. */ - ac->ac_allow_chain_relink = 0; + ac->ac_disable_chain_relink = 1; /* Claim the first region */ status = ocfs2_block_group_claim_bits(osb, handle, ac, min_bits, @@ -1823,7 +1823,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, * Do this *after* figuring out how many bits we're taking out * of our target group. */ - if (ac->ac_allow_chain_relink && + if (!ac->ac_disable_chain_relink && (prev_group_bh) && (ocfs2_block_group_reasonably_empty(bg, res->sr_bits))) { status = ocfs2_relink_block_group(handle, alloc_inode, @@ -1928,7 +1928,6 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, victim = ocfs2_find_victim_chain(cl); ac->ac_chain = victim; - ac->ac_allow_chain_relink = 1; status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, res, &bits_left); @@ -1947,7 +1946,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, * searching each chain in order. Don't allow chain relinking * because we only calculate enough journal credits for one * relink per alloc. */ - ac->ac_allow_chain_relink = 0; + ac->ac_disable_chain_relink = 1; for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i ++) { if (i == victim) continue; diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index b8afabfeede..a36d0aa5091 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h @@ -49,7 +49,7 @@ struct ocfs2_alloc_context { /* these are used by the chain search */ u16 ac_chain; - int ac_allow_chain_relink; + int ac_disable_chain_relink; group_search_t *ac_group_search; u64 ac_last_group; From 6ee1df3bff435d169d0ab93420bd02b4f9392e66 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Wed, 27 Feb 2013 17:03:32 -0800 Subject: [PATCH 2293/2357] block: fix ext_devt_idr handling commit 7b74e912785a11572da43292786ed07ada7e3e0c upstream. While adding and removing a lot of disks disks and partitions this sometimes shows up: WARNING: at fs/sysfs/dir.c:512 sysfs_add_one+0xc9/0x130() (Not tainted) Hardware name: sysfs: cannot create duplicate filename '/dev/block/259:751' Modules linked in: raid1 autofs4 bnx2fc cnic uio fcoe libfcoe libfc 8021q scsi_transport_fc scsi_tgt garp stp llc sunrpc cpufreq_ondemand powernow_k8 freq_table mperf ipv6 dm_mirror dm_region_hash dm_log power_meter microcode dcdbas serio_raw amd64_edac_mod edac_core edac_mce_amd i2c_piix4 i2c_core k10temp bnx2 sg ixgbe dca mdio ext4 mbcache jbd2 dm_round_robin sr_mod cdrom sd_mod crc_t10dif ata_generic pata_acpi pata_atiixp ahci mptsas mptscsih mptbase scsi_transport_sas dm_multipath dm_mod [last unloaded: scsi_wait_scan] Pid: 44103, comm: async/16 Not tainted 2.6.32-195.el6.x86_64 #1 Call Trace: warn_slowpath_common+0x87/0xc0 warn_slowpath_fmt+0x46/0x50 sysfs_add_one+0xc9/0x130 sysfs_do_create_link+0x12b/0x170 sysfs_create_link+0x13/0x20 device_add+0x317/0x650 idr_get_new+0x13/0x50 add_partition+0x21c/0x390 rescan_partitions+0x32b/0x470 sd_open+0x81/0x1f0 [sd_mod] __blkdev_get+0x1b6/0x3c0 blkdev_get+0x10/0x20 register_disk+0x155/0x170 add_disk+0xa6/0x160 sd_probe_async+0x13b/0x210 [sd_mod] add_wait_queue+0x46/0x60 async_thread+0x102/0x250 default_wake_function+0x0/0x20 async_thread+0x0/0x250 kthread+0x96/0xa0 child_rip+0xa/0x20 kthread+0x0/0xa0 child_rip+0x0/0x20 This most likely happens because dev_t is freed while the number is still used and idr_get_new() is not protected on every use. The fix adds a mutex where it wasn't before and moves the dev_t free function so it is called after device del. Signed-off-by: Tomas Henzl Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 6 +++++- block/partition-generic.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 9cf5583c90f..9433636b88b 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -420,14 +420,18 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt) do { if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL)) return -ENOMEM; + mutex_lock(&ext_devt_mutex); rc = idr_get_new(&ext_devt_idr, part, &idx); + mutex_unlock(&ext_devt_mutex); } while (rc == -EAGAIN); if (rc) return rc; if (idx > MAX_EXT_DEVT) { + mutex_lock(&ext_devt_mutex); idr_remove(&ext_devt_idr, idx); + mutex_unlock(&ext_devt_mutex); return -EBUSY; } @@ -644,7 +648,6 @@ void del_gendisk(struct gendisk *disk) disk_part_iter_exit(&piter); invalidate_partition(disk, 0); - blk_free_devt(disk_to_dev(disk)->devt); set_capacity(disk, 0); disk->flags &= ~GENHD_FL_UP; @@ -662,6 +665,7 @@ void del_gendisk(struct gendisk *disk) if (!sysfs_deprecated) sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); device_del(disk_to_dev(disk)); + blk_free_devt(disk_to_dev(disk)->devt); } EXPORT_SYMBOL(del_gendisk); diff --git a/block/partition-generic.c b/block/partition-generic.c index 6df5d6928a4..7b8b8d17764 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -249,11 +249,11 @@ void delete_partition(struct gendisk *disk, int partno) if (!part) return; - blk_free_devt(part_devt(part)); rcu_assign_pointer(ptbl->part[partno], NULL); rcu_assign_pointer(ptbl->last_lookup, NULL); kobject_put(part->holder_dir); device_del(part_to_dev(part)); + blk_free_devt(part_devt(part)); hd_struct_put(part); } From f8cf1124a8f6cdd4ebc834ec3d848508e229e1d4 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 20 Dec 2012 10:31:11 +0000 Subject: [PATCH 2294/2357] xen-blkback: do not leak mode property commit 9d092603cc306ee6edfe917bf9ab8beb5f32d7bc upstream. "be->mode" is obtained from xenbus_read(), which does a kmalloc() for the message body. The short string is never released, so do it along with freeing "be" itself, and make sure the string isn't kept when backend_changed() doesn't complete successfully (which made it desirable to slightly re-structure that function, so that the error cleanup can be done in one place). Reported-by: Olaf Hering Signed-off-by: Jan Beulich Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/block/xen-blkback/xenbus.c | 49 +++++++++++++++--------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 4f66171c668..a155254f133 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -367,6 +367,7 @@ static int xen_blkbk_remove(struct xenbus_device *dev) be->blkif = NULL; } + kfree(be->mode); kfree(be); dev_set_drvdata(&dev->dev, NULL); return 0; @@ -502,6 +503,7 @@ static void backend_changed(struct xenbus_watch *watch, = container_of(watch, struct backend_info, backend_watch); struct xenbus_device *dev = be->dev; int cdrom = 0; + unsigned long handle; char *device_type; DPRINTK(""); @@ -521,10 +523,10 @@ static void backend_changed(struct xenbus_watch *watch, return; } - if ((be->major || be->minor) && - ((be->major != major) || (be->minor != minor))) { - pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n", - be->major, be->minor, major, minor); + if (be->major | be->minor) { + if (be->major != major || be->minor != minor) + pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n", + be->major, be->minor, major, minor); return; } @@ -542,36 +544,33 @@ static void backend_changed(struct xenbus_watch *watch, kfree(device_type); } - if (be->major == 0 && be->minor == 0) { - /* Front end dir is a number, which is used as the handle. */ - - char *p = strrchr(dev->otherend, '/') + 1; - long handle; - err = strict_strtoul(p, 0, &handle); - if (err) - return; + /* Front end dir is a number, which is used as the handle. */ + err = strict_strtoul(strrchr(dev->otherend, '/') + 1, 0, &handle); + if (err) + return; - be->major = major; - be->minor = minor; + be->major = major; + be->minor = minor; - err = xen_vbd_create(be->blkif, handle, major, minor, - (NULL == strchr(be->mode, 'w')), cdrom); - if (err) { - be->major = 0; - be->minor = 0; - xenbus_dev_fatal(dev, err, "creating vbd structure"); - return; - } + err = xen_vbd_create(be->blkif, handle, major, minor, + !strchr(be->mode, 'w'), cdrom); + if (err) + xenbus_dev_fatal(dev, err, "creating vbd structure"); + else { err = xenvbd_sysfs_addif(dev); if (err) { xen_vbd_free(&be->blkif->vbd); - be->major = 0; - be->minor = 0; xenbus_dev_fatal(dev, err, "creating sysfs entries"); - return; } + } + if (err) { + kfree(be->mode); + be->mode = NULL; + be->major = 0; + be->minor = 0; + } else { /* We're potentially connected now */ xen_update_blkif_status(be->blkif); } From c93c85196e2c7001daa8a04b83a9d6dd4febfb59 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 16 Jan 2013 11:36:23 -0500 Subject: [PATCH 2295/2357] xen/blkback: Don't trust the handle from the frontend. commit 01c681d4c70d64cb72142a2823f27c4146a02e63 upstream. The 'handle' is the device that the request is from. For the life-time of the ring we copy it from a request to a response so that the frontend is not surprised by it. But we do not need it - when we start processing I/Os we have our own 'struct phys_req' which has only most essential information about the request. In fact the 'vbd_translate' ends up over-writing the preq.dev with a value from the backend. This assignment of preq.dev with the 'handle' value is superfluous so lets not do it. Acked-by: Jan Beulich Acked-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/block/xen-blkback/blkback.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index c6decb901e5..73d8c9276b9 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -623,7 +623,6 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, goto fail_response; } - preq.dev = req->u.rw.handle; preq.sector_number = req->u.rw.sector_number; preq.nr_sects = 0; From a8aa6d32035120fdfef09ccb88c694047013eb7b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 27 Feb 2013 17:03:34 -0800 Subject: [PATCH 2296/2357] idr: fix a subtle bug in idr_get_next() commit 6cdae7416a1c45c2ce105a78187d9b7e8feb9e24 upstream. The iteration logic of idr_get_next() is borrowed mostly verbatim from idr_for_each(). It walks down the tree looking for the slot matching the current ID. If the matching slot is not found, the ID is incremented by the distance of single slot at the given level and repeats. The implementation assumes that during the whole iteration id is aligned to the layer boundaries of the level closest to the leaf, which is true for all iterations starting from zero or an existing element and thus is fine for idr_for_each(). However, idr_get_next() may be given any point and if the starting id hits in the middle of a non-existent layer, increment to the next layer will end up skipping the same offset into it. For example, an IDR with IDs filled between [64, 127] would look like the following. [ 0 64 ... ] /----/ | | | NULL [ 64 ... 127 ] If idr_get_next() is called with 63 as the starting point, it will try to follow down the pointer from 0. As it is NULL, it will then try to proceed to the next slot in the same level by adding the slot distance at that level which is 64 - making the next try 127. It goes around the loop and finds and returns 127 skipping [64, 126]. Note that this bug also triggers in idr_for_each_entry() loop which deletes during iteration as deletions can make layers go away leaving the iteration with unaligned ID into missing layers. Fix it by ensuring proceeding to the next slot doesn't carry over the unaligned offset - ie. use round_up(id + 1, slot_distance) instead of id += slot_distance. Signed-off-by: Tejun Heo Reported-by: David Teigland Cc: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- lib/idr.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/idr.c b/lib/idr.c index 4046e29c0a9..e90d2d05d78 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -625,7 +625,14 @@ void *idr_get_next(struct idr *idp, int *nextidp) return p; } - id += 1 << n; + /* + * Proceed to the next layer at the current level. Unlike + * idr_for_each(), @id isn't guaranteed to be aligned to + * layer boundary at this point and adding 1 << n may + * incorrectly skip IDs. Make sure we jump to the + * beginning of the next layer using round_up(). + */ + id = round_up(id + 1, 1 << n); while (n < fls(id)) { n += IDR_BITS; p = *--paa; From 303ee54c72f488b90c2355977c1619a08db6ed9c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 27 Feb 2013 17:03:56 -0800 Subject: [PATCH 2297/2357] block: fix synchronization and limit check in blk_alloc_devt() commit ce23bba842aee98092225d9576dba47c82352521 upstream. idr allocation in blk_alloc_devt() wasn't synchronized against lookup and removal, and its limit check was off by one - 1 << MINORBITS is the number of minors allowed, not the maximum allowed minor. Add locking and rename MAX_EXT_DEVT to NR_EXT_DEVT and fix limit checking. Signed-off-by: Tejun Heo Acked-by: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 9433636b88b..60108d9fa04 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -25,7 +25,7 @@ static DEFINE_MUTEX(block_class_lock); struct kobject *block_depr; /* for extended dynamic devt allocation, currently only one major is used */ -#define MAX_EXT_DEVT (1 << MINORBITS) +#define NR_EXT_DEVT (1 << MINORBITS) /* For extended devt allocation. ext_devt_mutex prevents look up * results from going away underneath its user. @@ -422,19 +422,16 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt) return -ENOMEM; mutex_lock(&ext_devt_mutex); rc = idr_get_new(&ext_devt_idr, part, &idx); + if (!rc && idx >= NR_EXT_DEVT) { + idr_remove(&ext_devt_idr, idx); + rc = -EBUSY; + } mutex_unlock(&ext_devt_mutex); } while (rc == -EAGAIN); if (rc) return rc; - if (idx > MAX_EXT_DEVT) { - mutex_lock(&ext_devt_mutex); - idr_remove(&ext_devt_idr, idx); - mutex_unlock(&ext_devt_mutex); - return -EBUSY; - } - *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx)); return 0; } From ef7a6c344031cd99e16a116a7984d9428dce8401 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 27 Feb 2013 17:04:04 -0800 Subject: [PATCH 2298/2357] firewire: add minor number range check to fw_device_init() commit 3bec60d511179853138836ae6e1b61fe34d9235f upstream. fw_device_init() didn't check whether the allocated minor number isn't too large. Fail if it goes overflows MINORBITS. Signed-off-by: Tejun Heo Suggested-by: Stefan Richter Acked-by: Stefan Richter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/firewire/core-device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 68109e9bb04..04ebeaf8cff 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -999,6 +999,10 @@ static void fw_device_init(struct work_struct *work) ret = idr_pre_get(&fw_device_idr, GFP_KERNEL) ? idr_get_new(&fw_device_idr, device, &minor) : -ENOMEM; + if (minor >= 1 << MINORBITS) { + idr_remove(&fw_device_idr, minor); + minor = -ENOSPC; + } up_write(&fw_device_rwsem); if (ret < 0) From d48e3a8dc45d9eac3e2be330ef4df663a6f54dfc Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Wed, 27 Feb 2013 17:05:21 -0800 Subject: [PATCH 2299/2357] sysctl: fix null checking in bin_dn_node_address() commit df1778be1a33edffa51d094eeda87c858ded6560 upstream. The null check of `strchr() + 1' is broken, which is always non-null, leading to OOB read. Instead, check the result of strchr(). Signed-off-by: Xi Wang Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/sysctl_binary.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c index a650694883a..9f9aa320597 100644 --- a/kernel/sysctl_binary.c +++ b/kernel/sysctl_binary.c @@ -1194,9 +1194,10 @@ static ssize_t bin_dn_node_address(struct file *file, /* Convert the decnet address to binary */ result = -EIO; - nodep = strchr(buf, '.') + 1; + nodep = strchr(buf, '.'); if (!nodep) goto out; + ++nodep; area = simple_strtoul(buf, NULL, 10); node = simple_strtoul(nodep, NULL, 10); From 0f600ee1431404eb87d36b84a66ccc004c5ace9b Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 30 Jan 2013 00:28:01 +0100 Subject: [PATCH 2300/2357] fs: Fix possible use-after-free with AIO commit 54c807e71d5ac59dee56c685f2b66e27cd54c475 upstream. Running AIO is pinning inode in memory using file reference. Once AIO is completed using aio_complete(), file reference is put and inode can be freed from memory. So we have to be sure that calling aio_complete() is the last thing we do with the inode. Acked-by: Jeff Moyer CC: Christoph Hellwig CC: Jens Axboe CC: Jeff Moyer Signed-off-by: Jan Kara Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/direct-io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/direct-io.c b/fs/direct-io.c index f4aadd15b61..29c4fdab29d 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -305,9 +305,9 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, bool is dio->end_io(dio->iocb, offset, transferred, dio->private, ret, is_async); } else { + inode_dio_done(dio->inode); if (is_async) aio_complete(dio->iocb, ret, 0); - inode_dio_done(dio->inode); } return ret; From f74e995c9ba5963cd8d6ef91abe8f49d9614b423 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 27 Nov 2012 13:35:09 -0300 Subject: [PATCH 2301/2357] media: rc: unlock on error in show_protocols() commit 30ebc5e44d057a1619ad63fe32c8c1670c37c4b8 upstream. We recently introduced a new return -ENODEV in this function but we need to unlock before returning. [mchehab@redhat.com: found two patches with the same fix. Merged SOB's/acks into one patch] Acked-by: Herton R. Krzesinski Signed-off-by: Dan Carpenter Signed-off-by: Douglas Bagnall Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/rc-main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index cabc19c1051..cec1f8c05e6 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -778,8 +778,10 @@ static ssize_t show_protocols(struct device *device, } else if (dev->raw) { enabled = dev->raw->enabled_protocols; allowed = ir_raw_get_allowed_protocols(); - } else + } else { + mutex_unlock(&dev->lock); return -ENODEV; + } IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", (long long)allowed, From ced2decfe31ba7b7b97cce2de010f75e8a90b412 Mon Sep 17 00:00:00 2001 From: Eryu Guan Date: Sat, 12 Jan 2013 16:33:25 -0500 Subject: [PATCH 2302/2357] ext4: check bh in ext4_read_block_bitmap() commit 15b49132fc972c63894592f218ea5a9a61b1a18f upstream. Validate the bh pointer before using it, since ext4_read_block_bitmap_nowait() might return NULL. I've seen this in fsfuzz testing. EXT4-fs error (device loop0): ext4_read_block_bitmap_nowait:385: comm touch: Cannot get buffer for block bitmap - block_group = 0, block_bitmap = 3925999616 BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] ext4_wait_block_bitmap+0x25/0xe0 ... Call Trace: [] ext4_read_block_bitmap+0x35/0x60 [] ext4_free_blocks+0x236/0xb80 [] ? __getblk+0x36/0x70 [] ? __find_get_block+0x8f/0x210 [] ? kmem_cache_free+0x33/0x140 [] ext4_xattr_release_block+0x1b5/0x1d0 [] ext4_xattr_delete_inode+0xbe/0x100 [] ext4_free_inode+0x7c/0x4d0 [] ? ext4_mark_inode_dirty+0x88/0x230 [] ext4_evict_inode+0x32c/0x490 [] evict+0xa7/0x1c0 [] iput_final+0xe3/0x170 [] iput+0x3e/0x50 [] ext4_add_nondir+0x4d/0x90 [] ext4_create+0xeb/0x170 [] vfs_create+0xac/0xd0 [] lookup_open+0x185/0x1c0 [] ? selinux_inode_permission+0xa9/0x170 [] do_last+0x2d4/0x7a0 [] path_openat+0xb3/0x480 [] ? handle_mm_fault+0x251/0x3b0 [] do_filp_open+0x49/0xa0 [] ? __alloc_fd+0xdd/0x150 [] do_sys_open+0x108/0x1f0 [] sys_open+0x21/0x30 [] system_call_fastpath+0x16/0x1b Also fix comment for ext4_read_block_bitmap_nowait() Signed-off-by: Eryu Guan Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index df76291d692..bb74d7f0f35 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -326,7 +326,7 @@ static int ext4_valid_block_bitmap(struct super_block *sb, return 0; } /** - * ext4_read_block_bitmap() + * ext4_read_block_bitmap_nowait() * @sb: super block * @block_group: given block group * @@ -422,6 +422,8 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group) struct buffer_head *bh; bh = ext4_read_block_bitmap_nowait(sb, block_group); + if (!bh) + return NULL; if (ext4_wait_block_bitmap(sb, block_group, bh)) { put_bh(bh); return NULL; From 51e26006d1c9d5a2609d1bb6b7899cd86f92eed9 Mon Sep 17 00:00:00 2001 From: Niu Yawei Date: Fri, 1 Feb 2013 21:31:27 -0500 Subject: [PATCH 2303/2357] ext4: fix race in ext4_mb_add_n_trim() commit f1167009711032b0d747ec89a632a626c901a1ad upstream. In ext4_mb_add_n_trim(), lg_prealloc_lock should be taken when changing the lg_prealloc_list. Signed-off-by: Niu Yawei Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/mballoc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index e77c4fe665a..3122ece1514 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -4126,7 +4126,7 @@ static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac) /* The max size of hash table is PREALLOC_TB_SIZE */ order = PREALLOC_TB_SIZE - 1; /* Add the prealloc space to lg */ - rcu_read_lock(); + spin_lock(&lg->lg_prealloc_lock); list_for_each_entry_rcu(tmp_pa, &lg->lg_prealloc_list[order], pa_inode_list) { spin_lock(&tmp_pa->pa_lock); @@ -4150,12 +4150,12 @@ static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac) if (!added) list_add_tail_rcu(&pa->pa_inode_list, &lg->lg_prealloc_list[order]); - rcu_read_unlock(); + spin_unlock(&lg->lg_prealloc_lock); /* Now trim the list to be not more than 8 elements */ if (lg_prealloc_count > 8) { ext4_mb_discard_lg_preallocations(sb, lg, - order, lg_prealloc_count); + order, lg_prealloc_count); return; } return ; From 19c9740ba7362357bde91267a0aa5109a809cd3e Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Mon, 18 Feb 2013 12:12:07 -0500 Subject: [PATCH 2304/2357] ext4: fix xattr block allocation/release with bigalloc commit 1231b3a1eb5740192aeebf5344dd6d6da000febf upstream. Currently when new xattr block is created or released we we would call dquot_free_block() or dquot_alloc_block() respectively, among the else decrementing or incrementing the number of blocks assigned to the inode by one block. This however does not work for bigalloc file system because we always allocate/free the whole cluster so we have to count with that in dquot_free_block() and dquot_alloc_block() as well. Use the clusters-to-blocks conversion EXT4_C2B() when passing number of blocks to the dquot_alloc/free functions to fix the problem. The problem has been revealed by xfstests #117 (and possibly others). Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" Reviewed-by: Eric Sandeen Signed-off-by: Greg Kroah-Hartman --- fs/ext4/xattr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index e88748e55c0..e712a8cb165 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -495,7 +495,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, error = ext4_handle_dirty_metadata(handle, inode, bh); if (IS_SYNC(inode)) ext4_handle_sync(handle); - dquot_free_block(inode, 1); + dquot_free_block(inode, EXT4_C2B(EXT4_SB(inode->i_sb), 1)); ea_bdebug(bh, "refcount now=%d; releasing", le32_to_cpu(BHDR(bh)->h_refcount)); } @@ -784,7 +784,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, else { /* The old block is released after updating the inode. */ - error = dquot_alloc_block(inode, 1); + error = dquot_alloc_block(inode, + EXT4_C2B(EXT4_SB(sb), 1)); if (error) goto cleanup; error = ext4_journal_get_write_access(handle, @@ -880,7 +881,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, return error; cleanup_dquot: - dquot_free_block(inode, 1); + dquot_free_block(inode, EXT4_C2B(EXT4_SB(sb), 1)); goto cleanup; bad_block: From 4234fb29a8c0a5c5eaee6de38fe3cba674daecd0 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Fri, 22 Feb 2013 15:27:52 -0500 Subject: [PATCH 2305/2357] ext4: fix free clusters calculation in bigalloc filesystem commit 304e220f0879198b1f5309ad6f0be862b4009491 upstream. ext4_has_free_clusters() should tell us whether there is enough free clusters to allocate, however number of free clusters in the file system is converted to blocks using EXT4_C2B() which is not only wrong use of the macro (we should have used EXT4_NUM_B2C) but it's also completely wrong concept since everything else is in cluster units. Moreover when calculating number of root clusters we should be using macro EXT4_NUM_B2C() instead of EXT4_B2C() otherwise the result might be off by one. However r_blocks_count should always be a multiple of the cluster ratio so doing a plain bit shift should be enough here. We avoid using EXT4_B2C() because it's confusing. As a result of the first problem number of free clusters is much bigger than it should have been and ext4_has_free_clusters() would return 1 even if there is really not enough free clusters available. Fix this by removing the EXT4_C2B() conversion of free clusters and using bit shift when calculating number of root clusters. This bug affects number of xfstests tests covering file system ENOSPC situation handling. With this patch most of the ENOSPC problems with bigalloc file system disappear, especially the errors caused by delayed allocation not having enough space when the actual allocation is finally requested. Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index bb74d7f0f35..3e1018ace70 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -449,11 +449,16 @@ static int ext4_has_free_clusters(struct ext4_sb_info *sbi, free_clusters = percpu_counter_read_positive(fcc); dirty_clusters = percpu_counter_read_positive(dcc); - root_clusters = EXT4_B2C(sbi, ext4_r_blocks_count(sbi->s_es)); + + /* + * r_blocks_count should always be multiple of the cluster ratio so + * we are safe to do a plane bit shift only. + */ + root_clusters = ext4_r_blocks_count(sbi->s_es) >> sbi->s_cluster_bits; if (free_clusters - (nclusters + root_clusters + dirty_clusters) < EXT4_FREECLUSTERS_WATERMARK) { - free_clusters = EXT4_C2B(sbi, percpu_counter_sum_positive(fcc)); + free_clusters = percpu_counter_sum_positive(fcc); dirty_clusters = percpu_counter_sum_positive(dcc); } /* Check whether we have space after accounting for current From 5623a7cc4e3f0f461586b10b78967bb5f53fa096 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Tue, 29 Jan 2013 13:16:06 +0800 Subject: [PATCH 2306/2357] nfsd: Fix memleak commit 2d32b29a1c2830f7c42caa8258c714acd983961f upstream. When free nfs-client, it must free the ->cl_stateids. Signed-off-by: Jianpeng Ma Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 537731e4c16..abd785e5fd2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1053,6 +1053,8 @@ free_client(struct nfs4_client *clp) put_group_info(clp->cl_cred.cr_group_info); kfree(clp->cl_principal); kfree(clp->cl_name.data); + idr_remove_all(&clp->cl_stateids); + idr_destroy(&clp->cl_stateids); kfree(clp); } From 7e5e167c5c1b44f408fa8f8a8f062f234cd0f0d6 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 10 Feb 2013 11:33:48 -0500 Subject: [PATCH 2307/2357] svcrpc: make svc_age_temp_xprts enqueue under sv_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e75bafbff2270993926abcc31358361db74a9bc2 upstream. svc_age_temp_xprts expires xprts in a two-step process: first it takes the sv_lock and moves the xprts to expire off their server-wide list (sv_tempsocks or sv_permsocks) to a local list. Then it drops the sv_lock and enqueues and puts each one. I see no reason for this: svc_xprt_enqueue() will take sp_lock, but the sv_lock and sp_lock are not otherwise nested anywhere (and documentation at the top of this file claims it's correct to nest these with sp_lock inside.) Tested-by: Jason Tibbitts Tested-by: Paweł Sikora Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/svc_xprt.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index fd9b2889aa9..aec7dbb9d3d 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -817,7 +817,6 @@ static void svc_age_temp_xprts(unsigned long closure) struct svc_serv *serv = (struct svc_serv *)closure; struct svc_xprt *xprt; struct list_head *le, *next; - LIST_HEAD(to_be_aged); dprintk("svc_age_temp_xprts\n"); @@ -838,25 +837,15 @@ static void svc_age_temp_xprts(unsigned long closure) if (atomic_read(&xprt->xpt_ref.refcount) > 1 || test_bit(XPT_BUSY, &xprt->xpt_flags)) continue; - svc_xprt_get(xprt); - list_move(le, &to_be_aged); + list_del_init(le); set_bit(XPT_CLOSE, &xprt->xpt_flags); set_bit(XPT_DETACHED, &xprt->xpt_flags); - } - spin_unlock_bh(&serv->sv_lock); - - while (!list_empty(&to_be_aged)) { - le = to_be_aged.next; - /* fiddling the xpt_list node is safe 'cos we're XPT_DETACHED */ - list_del_init(le); - xprt = list_entry(le, struct svc_xprt, xpt_list); - dprintk("queuing xprt %p for closing\n", xprt); /* a thread will dequeue and close it soon */ svc_xprt_enqueue(xprt); - svc_xprt_put(xprt); } + spin_unlock_bh(&serv->sv_lock); mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); } From 94dcb26bbbed1851e0a7fb16165207c2c61e545f Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 26 Nov 2012 05:57:27 +0000 Subject: [PATCH 2308/2357] vhost: fix length for cross region descriptor commit bd97120fc3d1a11f3124c7c9ba1d91f51829eb85 upstream. If a single descriptor crosses a region, the second chunk length should be decremented by size translated so far, instead it includes the full descriptor length. Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 51e4c1eeec4..1a9e2a9b856 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1074,7 +1074,7 @@ static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len, } _iov = iov + ret; size = reg->memory_size - addr + reg->guest_phys_addr; - _iov->iov_len = min((u64)len, size); + _iov->iov_len = min((u64)len - s, size); _iov->iov_base = (void __user *)(unsigned long) (reg->userspace_addr + addr - reg->guest_phys_addr); s += size; From 146207bbadeb4578334d6e26b9b690df8aeb1a3d Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 4 Feb 2013 15:57:42 +0100 Subject: [PATCH 2309/2357] fuse: don't WARN when nlink is zero commit dfca7cebc2679f3d129f8e680a8f199a7ad16e38 upstream. drop_nlink() warns if nlink is already zero. This is triggerable by a buggy userspace filesystem. The cure, I think, is worse than the disease so disable the warning. Reported-by: Tero Roponen Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/dir.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index bc438320cac..d48478a864b 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -645,7 +645,14 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) spin_lock(&fc->lock); fi->attr_version = ++fc->attr_version; - drop_nlink(inode); + /* + * If i_nlink == 0 then unlink doesn't make sense, yet this can + * happen if userspace filesystem is careless. It would be + * difficult to enforce correct nlink usage so just ignore this + * condition here + */ + if (inode->i_nlink > 0) + drop_nlink(inode); spin_unlock(&fc->lock); fuse_invalidate_attr(inode); fuse_invalidate_attr(dir); From 57ef0d83d393b0f1f378a6b18a7394c62caadafa Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 4 Feb 2013 19:39:52 +0000 Subject: [PATCH 2310/2357] unbreak automounter support on 64-bit kernel with 32-bit userspace (v2) commit 4f4ffc3a5398ef9bdbb32db04756d7d34e356fcf upstream. automount-support is broken on the parisc architecture, because the existing #if list does not include a check for defined(__hppa__). The HPPA (parisc) architecture is similiar to other 64bit Linux targets where we have to define autofs_wqt_t (which is passed back and forth to user space) as int type which has a size of 32bit across 32 and 64bit kernels. During the discussion on the mailing list, H. Peter Anvin suggested to invert the #if list since only specific platforms (specifically those who do not have a 32bit userspace, like IA64 and Alpha) should have autofs_wqt_t as unsigned long type. This suggestion is probably the best way to go, since Arm64 (and maybe others?) seems to have a non-working automounter. So in the long run even for other new upcoming architectures this inverted check seem to be the best solution, since it will not require them to change this #if again (unless they are 64bit only). Signed-off-by: Helge Deller Acked-by: H. Peter Anvin Acked-by: Ian Kent Acked-by: Catalin Marinas CC: James Bottomley CC: Rolf Eike Beer Signed-off-by: Greg Kroah-Hartman --- include/linux/auto_fs.h | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/include/linux/auto_fs.h b/include/linux/auto_fs.h index da64e15004b..6cdabb422de 100644 --- a/include/linux/auto_fs.h +++ b/include/linux/auto_fs.h @@ -31,25 +31,16 @@ #define AUTOFS_MIN_PROTO_VERSION AUTOFS_PROTO_VERSION /* - * Architectures where both 32- and 64-bit binaries can be executed - * on 64-bit kernels need this. This keeps the structure format - * uniform, and makes sure the wait_queue_token isn't too big to be - * passed back down to the kernel. - * - * This assumes that on these architectures: - * mode 32 bit 64 bit - * ------------------------- - * int 32 bit 32 bit - * long 32 bit 64 bit - * - * If so, 32-bit user-space code should be backwards compatible. + * The wait_queue_token (autofs_wqt_t) is part of a structure which is passed + * back to the kernel via ioctl from userspace. On architectures where 32- and + * 64-bit userspace binaries can be executed it's important that the size of + * autofs_wqt_t stays constant between 32- and 64-bit Linux kernels so that we + * do not break the binary ABI interface by changing the structure size. */ - -#if defined(__sparc__) || defined(__mips__) || defined(__x86_64__) \ - || defined(__powerpc__) || defined(__s390__) -typedef unsigned int autofs_wqt_t; -#else +#if defined(__ia64__) || defined(__alpha__) /* pure 64bit architectures */ typedef unsigned long autofs_wqt_t; +#else +typedef unsigned int autofs_wqt_t; #endif /* Packet types */ From 06f924f163e4426ce6a8d4cf61b45f2fc8eaeecc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 20 Jan 2013 21:55:20 +0100 Subject: [PATCH 2311/2357] ath9k_hw: fix calibration issues on chainmask that don't include chain 0 commit 4a8f199508d79ff8a7d1e22f47b912baaf225336 upstream. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: CAI Qian Reviewed-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 2 ++ drivers/net/wireless/ath/ath9k/ar9003_phy.c | 2 +- drivers/net/wireless/ath/ath9k/hw.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 63089cc1faf..9284bca6e16 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -938,6 +938,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, AR_PHY_CL_TAB_1, AR_PHY_CL_TAB_2 }; + ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); + if (rtt) { if (!ar9003_hw_rtt_restore(ah, chan)) run_rtt_cal = true; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 600aca9fe6b..f86ee0c7f31 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -543,7 +543,7 @@ static void ar9003_hw_init_bb(struct ath_hw *ah, udelay(synthDelay + BASE_ACTIVATE_DELAY); } -static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) +void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) { switch (rx) { case 0x5: diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f8e1fbbbfc5..d5c5dca3d36 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1014,6 +1014,7 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain); int ar9003_paprd_init_table(struct ath_hw *ah); bool ar9003_paprd_is_done(struct ath_hw *ah); void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains); +void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); /* Hardware family op attach helpers */ void ar5008_hw_attach_phy_ops(struct ath_hw *ah); From 68412b1718c488e58783d1c576d0aeb34012092d Mon Sep 17 00:00:00 2001 From: Seiji Aguchi Date: Fri, 11 Jan 2013 18:09:41 +0000 Subject: [PATCH 2312/2357] pstore: Avoid deadlock in panic and emergency-restart path commit 9f244e9cfd70c7c0f82d3c92ce772ab2a92d9f64 upstream. [Issue] When pstore is in panic and emergency-restart paths, it may be blocked in those paths because it simply takes spin_lock. This is an example scenario which pstore may hang up in a panic path: - cpuA grabs psinfo->buf_lock - cpuB panics and calls smp_send_stop - smp_send_stop sends IRQ to cpuA - after 1 second, cpuB gives up on cpuA and sends an NMI instead - cpuA is now in an NMI handler while still holding buf_lock - cpuB is deadlocked This case may happen if a firmware has a bug and cpuA is stuck talking with it more than one second. Also, this is a similar scenario in an emergency-restart path: - cpuA grabs psinfo->buf_lock and stucks in a firmware - cpuB kicks emergency-restart via either sysrq-b or hangcheck timer. And then, cpuB is deadlocked by taking psinfo->buf_lock again. [Solution] This patch avoids the deadlocking issues in both panic and emergency_restart paths by introducing a function, is_non_blocking_path(), to check if a cpu can be blocked in current path. With this patch, pstore is not blocked even if another cpu has taken a spin_lock, in those paths by changing from spin_lock_irqsave to spin_trylock_irqsave. In addition, according to a comment of emergency_restart() in kernel/sys.c, spin_lock shouldn't be taken in an emergency_restart path to avoid deadlock. This patch fits the comment below. /** * emergency_restart - reboot the system * * Without shutting down any hardware or taking any locks * reboot the system. This is called when we know we are in * trouble so this is our best effort to reboot. This is * safe to call in interrupt context. */ void emergency_restart(void) Signed-off-by: Seiji Aguchi Acked-by: Don Zickus Signed-off-by: Tony Luck Cc: CAI Qian Signed-off-by: Greg Kroah-Hartman --- fs/pstore/platform.c | 35 +++++++++++++++++++++++++++++------ include/linux/pstore.h | 6 ++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 82c585f715e..4a66a5c4a63 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -88,6 +88,27 @@ static const char *get_reason_str(enum kmsg_dump_reason reason) } } +bool pstore_cannot_block_path(enum kmsg_dump_reason reason) +{ + /* + * In case of NMI path, pstore shouldn't be blocked + * regardless of reason. + */ + if (in_nmi()) + return true; + + switch (reason) { + /* In panic case, other cpus are stopped by smp_send_stop(). */ + case KMSG_DUMP_PANIC: + /* Emergency restart shouldn't be blocked by spin lock. */ + case KMSG_DUMP_EMERG: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_GPL(pstore_cannot_block_path); + /* * callback from kmsg_dump. (s2,l2) has the most recently * written bytes, older bytes are in (s1,l1). Save as much @@ -111,10 +132,12 @@ static void pstore_dump(struct kmsg_dumper *dumper, why = get_reason_str(reason); - if (in_nmi()) { - is_locked = spin_trylock(&psinfo->buf_lock); - if (!is_locked) - pr_err("pstore dump routine blocked in NMI, may corrupt error record\n"); + if (pstore_cannot_block_path(reason)) { + is_locked = spin_trylock_irqsave(&psinfo->buf_lock, flags); + if (!is_locked) { + pr_err("pstore dump routine blocked in %s path, may corrupt error record\n" + , in_nmi() ? "NMI" : why); + } } else spin_lock_irqsave(&psinfo->buf_lock, flags); oopscount++; @@ -145,9 +168,9 @@ static void pstore_dump(struct kmsg_dumper *dumper, total += l1_cpy + l2_cpy; part++; } - if (in_nmi()) { + if (pstore_cannot_block_path(reason)) { if (is_locked) - spin_unlock(&psinfo->buf_lock); + spin_unlock_irqrestore(&psinfo->buf_lock, flags); } else spin_unlock_irqrestore(&psinfo->buf_lock, flags); } diff --git a/include/linux/pstore.h b/include/linux/pstore.h index e1461e143be..318cca1dee9 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -54,12 +54,18 @@ struct pstore_info { #ifdef CONFIG_PSTORE extern int pstore_register(struct pstore_info *); +extern bool pstore_cannot_block_path(enum kmsg_dump_reason reason); #else static inline int pstore_register(struct pstore_info *psi) { return -ENODEV; } +static inline bool +pstore_cannot_block_path(enum kmsg_dump_reason reason) +{ + return false; +} #endif #endif /*_LINUX_PSTORE_H*/ From a74e9a386f6e775f88061f7958b8b34c6742f926 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 25 Jan 2013 16:08:01 +0800 Subject: [PATCH 2313/2357] cpuset: fix cpuset_print_task_mems_allowed() vs rename() race commit 63f43f55c9bbc14f76b582644019b8a07dc8219a upstream. rename() will change dentry->d_name. The result of this race can be worse than seeing partially rewritten name, but we might access a stale pointer because rename() will re-allocate memory to hold a longer name. It's safe in the protection of dentry->d_lock. v2: check NULL dentry before acquiring dentry lock. Signed-off-by: Li Zefan Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/cpuset.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 5fc1570e64c..8fe6f6b6500 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -2479,8 +2479,16 @@ void cpuset_print_task_mems_allowed(struct task_struct *tsk) dentry = task_cs(tsk)->css.cgroup->dentry; spin_lock(&cpuset_buffer_lock); - snprintf(cpuset_name, CPUSET_NAME_LEN, - dentry ? (const char *)dentry->d_name.name : "/"); + + if (!dentry) { + strcpy(cpuset_name, "/"); + } else { + spin_lock(&dentry->d_lock); + strlcpy(cpuset_name, (const char *)dentry->d_name.name, + CPUSET_NAME_LEN); + spin_unlock(&dentry->d_lock); + } + nodelist_scnprintf(cpuset_nodelist, CPUSET_NODELIST_LEN, tsk->mems_allowed); printk(KERN_INFO "%s cpuset=%s mems_allowed=%s\n", From 916b6c67cd471fafa3e5e53ce8389c36749ed6f1 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Thu, 24 Jan 2013 14:43:28 +0800 Subject: [PATCH 2314/2357] cgroup: fix exit() vs rmdir() race commit 71b5707e119653039e6e95213f00479668c79b75 upstream. In cgroup_exit() put_css_set_taskexit() is called without any lock, which might lead to accessing a freed cgroup: thread1 thread2 --------------------------------------------- exit() cgroup_exit() put_css_set_taskexit() atomic_dec(cgrp->count); rmdir(); /* not safe !! */ check_for_release(cgrp); rcu_read_lock() can be used to make sure the cgroup is alive. Signed-off-by: Li Zefan Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index a5dccd4c236..a4c47d1b3ce 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -378,12 +378,20 @@ static void __put_css_set(struct css_set *cg, int taskexit) struct cgroup *cgrp = link->cgrp; list_del(&link->cg_link_list); list_del(&link->cgrp_link_list); + + /* + * We may not be holding cgroup_mutex, and if cgrp->count is + * dropped to 0 the cgroup can be destroyed at any time, hence + * rcu_read_lock is used to keep it alive. + */ + rcu_read_lock(); if (atomic_dec_and_test(&cgrp->count) && notify_on_release(cgrp)) { if (taskexit) set_bit(CGRP_RELEASABLE, &cgrp->flags); check_for_release(cgrp); } + rcu_read_unlock(); kfree(link); } From f9a8884a35a74f1fb9f12a17f62331bdc6eac2af Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 17 Jan 2013 14:21:53 +0000 Subject: [PATCH 2315/2357] ab8500-chargalg: Only root should have write permission on sysfs file commit e3455002d04276c256a531f7175dce0f7d1cb78a upstream. Only root should have write permission on sysfs file ab8500_chargalg/chargalg. Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/power/abx500_chargalg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 804b88c760d..d8cd1517c84 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -1698,7 +1698,7 @@ static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj, static struct attribute abx500_chargalg_en_charger = \ { .name = "chargalg", - .mode = S_IWUGO, + .mode = S_IWUSR, }; static struct attribute *abx500_chargalg_chg[] = { From 7eb0fad53ef76201d81a2e9e1bad5b68a457e4e3 Mon Sep 17 00:00:00 2001 From: "Rajanikanth H.V" Date: Wed, 23 Jan 2013 09:56:45 +0530 Subject: [PATCH 2316/2357] ab8500_btemp: Demote initcall sequence commit eeb0751c99522a4d1bbcc7b6bc1460cd07d07488 upstream. Power supply subsystem creates thermal zone device for the property 'POWER_SUPPLY_PROP_TEMP' which requires thermal subsystem to be ready before 'ab8500 battery temperature monitor' driver is initialized. ab8500 btemp driver is initialized with subsys_initcall whereas thermal subsystem is initialized with fs_initcall which causes thermal_zone_device_register(...) to crash since the required structure 'thermal_class' is not initialized yet: Unable to handle kernel NULL pointer dereference at virtual address 000000a4 pgd = c0004000 [000000a4] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 Tainted: G W (3.8.0-rc4-00001-g632fda8-dirty #1) PC is at _raw_spin_lock+0x18/0x54 LR is at get_device_parent+0x50/0x1b8 pc : [] lr : [] psr: 60000013 sp : ef04bdc8 ip : 00000000 fp : c0446180 r10: ef216e38 r9 : c03af5d0 r8 : ef275c18 r7 : 00000000 r6 : c0476c14 r5 : ef275c18 r4 : ef095840 r3 : ef04a000 r2 : 00000001 r1 : 00000000 r0 : 000000a4 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5787d Table: 0000404a DAC: 00000015 Process swapper/0 (pid: 1, stack limit = 0xef04a238) Stack: (0xef04bdc8 to 0xef04c000) [...] [] (_raw_spin_lock+0x18/0x54) from [] (get_device_parent+0x50/0x1b8) [] (get_device_parent+0x50/0x1b8) from [] (device_add+0xa4/0x574) [] (device_add+0xa4/0x574) from [] (thermal_zone_device_register+0x118/0x938) [] (thermal_zone_device_register+0x118/0x938) from [] (power_supply_register+0x170/0x1f8) [] (power_supply_register+0x170/0x1f8) from [] (ab8500_btemp_probe+0x208/0x47c) [] (ab8500_btemp_probe+0x208/0x47c) from [] (platform_drv_probe+0x14/0x18) [] (platform_drv_probe+0x14/0x18) from [] (driver_probe_device+0x74/0x20c) [] (driver_probe_device+0x74/0x20c) from [] (__driver_attach+0x8c/0x90) [] (__driver_attach+0x8c/0x90) from [] (bus_for_each_dev+0x4c/0x80) [] (bus_for_each_dev+0x4c/0x80) from [] (bus_add_driver+0x16c/0x23c) [] (bus_add_driver+0x16c/0x23c) from [] (driver_register+0x78/0x14c) [] (driver_register+0x78/0x14c) from [] (do_one_initcall+0xfc/0x164) [] (do_one_initcall+0xfc/0x164) from [] (kernel_init+0x120/0x2b8) [] (kernel_init+0x120/0x2b8) from [] (ret_from_fork+0x14/0x3c) Code: e3c3303f e5932004 e2822001 e5832004 (e1903f9f) ---[ end trace ed9df72941b5bada ]--- Signed-off-by: Rajanikanth H.V Signed-off-by: Anton Vorontsov Signed-off-by: Greg Kroah-Hartman --- drivers/power/ab8500_btemp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index d8bb99394ac..2a6bf76baac 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -1115,7 +1115,7 @@ static void __exit ab8500_btemp_exit(void) platform_driver_unregister(&ab8500_btemp_driver); } -subsys_initcall_sync(ab8500_btemp_init); +device_initcall(ab8500_btemp_init); module_exit(ab8500_btemp_exit); MODULE_LICENSE("GPL v2"); From 427e85ba0d2e3811c130714eea3fec0800ef2fcd Mon Sep 17 00:00:00 2001 From: Joseph Salisbury Date: Tue, 5 Feb 2013 00:16:29 +0000 Subject: [PATCH 2317/2357] ACPI: Add DMI entry for Sony VGN-FW41E_H commit 66f2fda93b67fa744d406e6dcf443f67bac204b6 upstream. This patch adds a quirk to allow the Sony VGN-FW41E_H to suspend/resume properly. References: http://bugs.launchpad.net/bugs/1113547 Signed-off-by: Joseph Salisbury Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/sleep.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index aa0a904e563..189c704a950 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -186,6 +186,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { }, { .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-FW41E_H", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW41E_H"), + }, + }, + { + .callback = init_nvs_nosave, .ident = "Sony Vaio VGN-FW21E", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), From 1e05b9964644382e9994e62dc5c8eb815e5225fa Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 27 Feb 2013 12:52:45 +0000 Subject: [PATCH 2318/2357] staging: comedi: ni_labpc: correct differential channel sequence for AI commands Commit 4c4bc25d0fa6beaf054c0b4c3b324487f266c820 upstream. Tuomas reported problems getting meaningful output from a Lab-PC+ in differential mode for AI cmds, but AI insn reads gave correct readings. He tracked it down to two problems, one of which is addressed by this patch. It seems the setting of the channel bits for particular scanning modes was incorrect for differential mode. (Only half the number of channels are available in differential mode; comedi refers to them as channels 0, 1, 2 and 3, but the hardware documentation refers to them as channels 0, 2, 4 and 6.) In differential mode, the setting of the channel enable bits in the command1 register should depend on whether the scan enable bit is set. Effectively, we need to double the comedi channel number when the scan enable bit is not set in differential mode. The scan enable bit gets set when the AI scan mode is `MODE_MULT_CHAN_UP` or `MODE_MULT_CHAN_DOWN`, and gets cleared when the AI scan mode is `MODE_SINGLE_CHAN` or `MODE_SINGLE_CHAN_INTERVAL`. The existing test for whether the comedi channel number needs to be doubled in differential mode is incorrect in `labpc_ai_cmd()`. This patch corrects the test. Thanks to Tuomas for suggesting the fix. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ni_labpc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 721b2be2250..9b876e0ab24 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -1264,7 +1264,9 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) else channel = CR_CHAN(cmd->chanlist[0]); /* munge channel bits for differential / scan disabled mode */ - if (labpc_ai_scan_mode(cmd) != MODE_SINGLE_CHAN && aref == AREF_DIFF) + if ((labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN || + labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN_INTERVAL) && + aref == AREF_DIFF) channel *= 2; devpriv->command1_bits |= ADC_CHAN_BITS(channel); devpriv->command1_bits |= thisboard->ai_range_code[range]; From e4cd1e4dba29c756272c2ee9d06b094b4319b90a Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 27 Feb 2013 12:52:46 +0000 Subject: [PATCH 2319/2357] staging: comedi: ni_labpc: set up command4 register *after* command3 Commit 22056e2b46246d97ff0f7c6e21a77b8daa07f02c upstream. Tuomas reported problems getting meaningful output from a Lab-PC+ in differential mode for AI cmds, but AI insn reads gave correct readings. He tracked it down to two problems, one of which is addressed by this patch. It seems that writing to the command3 register after writing to the command4 register in `labpc_ai_cmd()` messes up the differential reference bit setting in the command4 register. Set up the command4 register after the command3 register (as in `labpc_ai_rinsn()`) to avoid the problem. Thanks to Tuomas for suggesting the fix. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ni_labpc.c | 31 ++++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 9b876e0ab24..0517a2315ef 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -1282,21 +1282,6 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); } - /* setup any external triggering/pacing (command4 register) */ - devpriv->command4_bits = 0; - if (cmd->convert_src != TRIG_EXT) - devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; - /* XXX should discard first scan when using interval scanning - * since manual says it is not synced with scan clock */ - if (labpc_use_continuous_mode(cmd) == 0) { - devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT; - if (cmd->scan_begin_src == TRIG_EXT) - devpriv->command4_bits |= EXT_SCAN_EN_BIT; - } - /* single-ended/differential */ - if (aref == AREF_DIFF) - devpriv->command4_bits |= ADC_DIFF_BIT; - devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); devpriv->write_byte(cmd->chanlist_len, dev->iobase + INTERVAL_COUNT_REG); @@ -1376,6 +1361,22 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT; devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); + /* setup any external triggering/pacing (command4 register) */ + devpriv->command4_bits = 0; + if (cmd->convert_src != TRIG_EXT) + devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; + /* XXX should discard first scan when using interval scanning + * since manual says it is not synced with scan clock */ + if (labpc_use_continuous_mode(cmd) == 0) { + devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT; + if (cmd->scan_begin_src == TRIG_EXT) + devpriv->command4_bits |= EXT_SCAN_EN_BIT; + } + /* single-ended/differential */ + if (aref == AREF_DIFF) + devpriv->command4_bits |= ADC_DIFF_BIT; + devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); + /* startup acquisition */ /* command2 reg */ From 0685b5924819447dad0413312b508e68168a1ee2 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 27 Feb 2013 10:56:19 +0000 Subject: [PATCH 2320/2357] staging: comedi: check s->async for poll(), read() and write() commit cc400e185c07c15a42d2635995f422de5b94b696 upstream. Some low-level comedi drivers (incorrectly) point `dev->read_subdev` or `dev->write_subdev` to a subdevice that does not support asynchronous commands. Comedi's poll(), read() and write() file operation handlers assume these subdevices do support asynchronous commands. In particular, they assume `s->async` is valid (where `s` points to the read or write subdevice), which it won't be if it has been set incorrectly. This can lead to a NULL pointer dereference. Check `s->async` is non-NULL in `comedi_poll()`, `comedi_read()` and `comedi_write()` to avoid the bug. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index cf67ce54f46..3799cf1c2b6 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1577,7 +1577,7 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) mask = 0; read_subdev = comedi_get_read_subdevice(dev_file_info); - if (read_subdev) { + if (read_subdev && read_subdev->async) { poll_wait(file, &read_subdev->async->wait_head, wait); if (!read_subdev->busy || comedi_buf_read_n_available(read_subdev->async) > 0 @@ -1587,7 +1587,7 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) } } write_subdev = comedi_get_write_subdevice(dev_file_info); - if (write_subdev) { + if (write_subdev && write_subdev->async) { poll_wait(file, &write_subdev->async->wait_head, wait); comedi_buf_write_alloc(write_subdev->async, write_subdev->async->prealloc_bufsz); @@ -1629,7 +1629,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, } s = comedi_get_write_subdevice(dev_file_info); - if (s == NULL) { + if (s == NULL || s->async == NULL) { retval = -EIO; goto done; } @@ -1740,7 +1740,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, } s = comedi_get_read_subdevice(dev_file_info); - if (s == NULL) { + if (s == NULL || s->async == NULL) { retval = -EIO; goto done; } From 3f14f68ff0121c770930b061fe23008af45006a2 Mon Sep 17 00:00:00 2001 From: Vinson Lee Date: Tue, 26 Feb 2013 18:30:30 -0800 Subject: [PATCH 2321/2357] perf tools: Fix build with bison 2.3 and older. commit 85df3b3769222894e9692b383c7af124b7721086 upstream. The %name-prefix "prefix" syntax is not available on bison 2.3 and older. Substitute with the -p "prefix" command-line option for compatibility with older versions of bison. This patch fixes this build error with older versions of bison. CC util/sysfs.o BISON util/pmu-bison.c util/pmu.y:2.14-24: syntax error, unexpected string, expecting = make: *** [util/pmu-bison.c] Error 1 Signed-off-by: Vinson Lee Tested-by: Li Zefan Cc: Ingo Molnar Cc: Jiri Olsa Cc: Li Zefan Cc: Namhyung Kim Cc: Paul Mackerras Cc: Pekka Enberg Link: http://lkml.kernel.org/r/1360792138-29186-1-git-send-email-vlee@twitter.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/Makefile | 4 ++-- tools/perf/util/parse-events.y | 1 - tools/perf/util/pmu.y | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index c3dd3d4424f..2db7ba001c6 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -241,13 +241,13 @@ $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c: util/parse-events.y - $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c + $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c -p parse_events_ $(OUTPUT)util/pmu-flex.c: util/pmu.l $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c: util/pmu.y - $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c + $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_ $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index d9637da7333..3f35ea3f504 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -1,5 +1,4 @@ -%name-prefix "parse_events_" %parse-param {struct list_head *list_all} %parse-param {struct list_head *list_event} %parse-param {int *idx} diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y index 20ea77e9316..522943f7bfd 100644 --- a/tools/perf/util/pmu.y +++ b/tools/perf/util/pmu.y @@ -1,5 +1,4 @@ -%name-prefix "perf_pmu_" %parse-param {struct list_head *format} %parse-param {char *name} From 78b6767929e77f40b455b115d1643b82678b6a26 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Fri, 25 Jan 2013 11:57:05 -0800 Subject: [PATCH 2322/2357] ata_piix: IDE-mode SATA patch for Intel Avoton DeviceIDs commit aaa515277db9585eeb4fdeb4637b9f9df50a1dd9 upstream. This patch adds the IDE-mode SATA DeviceIDs for the Intel Avoton SOC. Signed-off-by: Seth Heasley Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ata_piix.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 3c809bfbccf..00a01be1e50 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -331,6 +331,14 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (DH89xxCC) */ { 0x8086, 0x2326, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Avoton) */ + { 0x8086, 0x1f20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Avoton) */ + { 0x8086, 0x1f21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Avoton) */ + { 0x8086, 0x1f30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Avoton) */ + { 0x8086, 0x1f31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ }; From a059654e30e7f0d0aaba17a44165332443d3f48e Mon Sep 17 00:00:00 2001 From: James Ralston Date: Fri, 8 Feb 2013 17:24:12 -0800 Subject: [PATCH 2323/2357] ata_piix: Add Device IDs for Intel Wellsburg PCH commit 3aee8bc52c415aba8148f144e5e5359b0fd75dd1 upstream. This patch adds the IDE-mode SATA Device IDs for the Intel Wellsburg PCH Signed-off-by: James Ralston Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ata_piix.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 00a01be1e50..88f6908c31f 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -339,6 +339,15 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x1f30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (Avoton) */ { 0x8086, 0x1f31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Wellsburg) */ + { 0x8086, 0x8d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Wellsburg) */ + { 0x8086, 0x8d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Wellsburg) */ + { 0x8086, 0x8d60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Wellsburg) */ + { 0x8086, 0x8d68, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + { } /* terminate list */ }; From e7e24f96cacd091ecd6ed0a4c10c83daae28f3c4 Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Mon, 12 Nov 2012 02:57:03 -0300 Subject: [PATCH 2324/2357] usb hid quirks for Masterkit MA901 usb radio commit 0322bd3980b3ebf7dde8474e22614cb443d6479a upstream. Don't let Masterkit MA901 USB radio be handled by usb hid drivers. This device will be handled by radio-ma901.c driver. Signed-off-by: Alexey Klimov Acked-by: Hans Verkuil Acked-by: Jiri Kosina Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 1a92a271adb..ff73d60cfc7 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1922,6 +1922,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) }, { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MASTERKIT, USB_DEVICE_ID_MASTERKIT_MA901RADIO) }, { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) }, { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 55838995eca..02f4664478b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -520,6 +520,9 @@ #define USB_VENDOR_ID_MADCATZ 0x0738 #define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540 +#define USB_VENDOR_ID_MASTERKIT 0x16c0 +#define USB_DEVICE_ID_MASTERKIT_MA901RADIO 0x05df + #define USB_VENDOR_ID_MCC 0x09db #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 #define USB_DEVICE_ID_MCC_PMD1208LS 0x007a From 2713e2797a78a0fdda765bc5ad7fed41e94818ba Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 4 Mar 2013 06:07:21 +0800 Subject: [PATCH 2325/2357] Linux 3.4.35 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 250be36a818..282e8da323d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 4 -SUBLEVEL = 34 +SUBLEVEL = 35 EXTRAVERSION = NAME = Saber-toothed Squirrel From 6f2cc2f541ea696aa6ba81520eec2ede461c03b9 Mon Sep 17 00:00:00 2001 From: Evan McClain Date: Sun, 3 Mar 2013 17:32:32 -0500 Subject: [PATCH 2326/2357] Fix warnings. Lots of uninitialized, unused variable warnings. Signed-off-by: Evan McClain --- arch/arm/mach-msm/board-mms-tsp.c | 2 +- drivers/input/misc/bmp180.c | 4 ++-- drivers/media/common/tuners/xc4000.c | 2 +- drivers/misc/a2220.c | 2 +- drivers/power/pm8xxx-ccadc.c | 2 +- fs/cifs/transport.c | 2 +- fs/ecryptfs/keystore.c | 2 +- include/linux/charging_temperature_data.h | 12 ++++++------ net/netfilter/xt_socket.c | 10 +++++----- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-msm/board-mms-tsp.c b/arch/arm/mach-msm/board-mms-tsp.c index 6ce42674a4f..543d38f1374 100644 --- a/arch/arm/mach-msm/board-mms-tsp.c +++ b/arch/arm/mach-msm/board-mms-tsp.c @@ -74,7 +74,6 @@ void melfas_vdd_on(bool onoff) static struct regulator *reg_l17; /* 1.8V */ #ifdef CONFIG_MACH_M2_VZW - static struct regulator *reg_l11; if (system_rev < BOARD_REV02) { if (onoff) gpio_direction_output(10, 1); @@ -150,6 +149,7 @@ void melfas_vdd_on(bool onoff) } #else /* 2.8V */ + static struct regulator *reg_l11; if (machine_is_ESPRESSO_VZW() && system_rev < BOARD_REV03) { if (!reg_l17) { reg_l17 = regulator_get(NULL, "8921_l17"); diff --git a/drivers/input/misc/bmp180.c b/drivers/input/misc/bmp180.c index adf025da18a..8eff6535069 100644 --- a/drivers/input/misc/bmp180.c +++ b/drivers/input/misc/bmp180.c @@ -189,8 +189,8 @@ static int bmp180_get_raw_pressure(struct bmp180_data *barom, static int bmp180_get_pressure_data_body(struct bmp180_data *barom) { - u16 raw_temperature; - u32 raw_pressure; + u16 raw_temperature = 0; + u32 raw_pressure = 0; long x1, x2, x3, b3, b5, b6; unsigned long b4, b7; long p; diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c index 68397110b7d..6d157c34a64 100644 --- a/drivers/media/common/tuners/xc4000.c +++ b/drivers/media/common/tuners/xc4000.c @@ -935,7 +935,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, int rc = 0, is_retry = 0; u16 hwmodel; v4l2_std_id std0; - u8 hw_major, hw_minor, fw_major, fw_minor; + u8 hw_major = 0, hw_minor = 0, fw_major = 0, fw_minor = 0; dprintk(1, "%s called\n", __func__); diff --git a/drivers/misc/a2220.c b/drivers/misc/a2220.c index 8e396dec544..46383708a36 100644 --- a/drivers/misc/a2220.c +++ b/drivers/misc/a2220.c @@ -176,7 +176,7 @@ static void a2220_i2c_sw_reset(struct a2220_data *a2220, unsigned int reset_cmd) a2220_hw_reset(struct a2220_data *a2220, struct a2220img *img) { struct a2220img *vp = img; - int rc, i, pass = 0; + int rc = 0, i, pass = 0; int remaining; int retry = RETRY_CNT; unsigned char *index; diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c index 7e37daa4ed1..b453caa6aa5 100644 --- a/drivers/power/pm8xxx-ccadc.c +++ b/drivers/power/pm8xxx-ccadc.c @@ -779,7 +779,7 @@ static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev) #define CCADC_CALIB_TEMP_THRESH 20 static int pm8xxx_ccadc_resume(struct device *dev) { - int rc, batt_temp, delta_temp; + int rc, batt_temp = 0, delta_temp; unsigned long current_time_sec; unsigned long time_since_last_calib; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0961336513d..1607615186c 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -569,7 +569,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, { int rc = 0; int long_op; - struct mid_q_entry *midQ; + struct mid_q_entry *midQ = NULL; char *buf = iov[0].iov_base; long_op = flags & CIFS_TIMEOUT_MASK; diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index 2333203a120..6154cde3a05 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -1150,7 +1150,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_message *msg = NULL; char *auth_tok_sig; char *payload; - size_t payload_len; + size_t payload_len = 0; int rc; rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok); diff --git a/include/linux/charging_temperature_data.h b/include/linux/charging_temperature_data.h index db31292a400..0f4262220a5 100644 --- a/include/linux/charging_temperature_data.h +++ b/include/linux/charging_temperature_data.h @@ -29,7 +29,7 @@ #define DEFAULT_LOW_RECOVER_TEMP 0 #if defined(CONFIG_MACH_JAGUAR) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26250, 800}, {26583, 750}, {26979, 700}, @@ -54,7 +54,7 @@ static const int temp_table[][2] = { }; #elif defined(CONFIG_MACH_M2_ATT) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26465, 800}, {26749, 750}, {27017, 700}, @@ -104,7 +104,7 @@ static const struct pm8xxx_adc_map_pt temp_table[] = { }; #elif defined(CONFIG_MACH_M2_VZW) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26537, 800}, {26849, 750}, {27211, 700}, @@ -129,7 +129,7 @@ static const int temp_table[][2] = { }; #elif defined(CONFIG_MACH_GOGH) || defined(CONFIG_MACH_INFINITE) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26478, 800}, {27123, 700}, {27985, 600}, @@ -144,7 +144,7 @@ static const int temp_table[][2] = { }; #elif defined(CONFIG_MACH_AEGIS2) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {27401, 650}, {27790, 600}, {28378, 550}, @@ -167,7 +167,7 @@ static const int temp_table[][2] = { }; #else -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26250, 800}, {26583, 750}, {26979, 700}, diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 1e48fcf2920..3163becc172 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -108,9 +108,9 @@ xt_socket_get4_sk(const struct sk_buff *skb, struct xt_action_param *par) const struct iphdr *iph = ip_hdr(skb); struct udphdr _hdr, *hp = NULL; struct sock *sk; - __be32 daddr, saddr; - __be16 dport, sport; - u8 protocol; + __be32 daddr = 0, saddr = 0; + __be16 dport = 0, sport = 0; + u8 protocol = 0; #ifdef XT_SOCKET_HAVE_CONNTRACK struct nf_conn const *ct; enum ip_conntrack_info ctinfo; @@ -273,8 +273,8 @@ xt_socket_get6_sk(const struct sk_buff *skb, struct xt_action_param *par) struct ipv6hdr *iph = ipv6_hdr(skb); struct udphdr _hdr, *hp = NULL; struct sock *sk; - struct in6_addr *daddr, *saddr; - __be16 dport, sport; + struct in6_addr *daddr = NULL, *saddr = NULL; + __be16 dport = 0, sport = 0; int thoff, tproto; tproto = ipv6_find_hdr(skb, &thoff, -1, NULL); From 9ced45c42724e2889fbd88b13f6b61b3c08bda10 Mon Sep 17 00:00:00 2001 From: detule Date: Fri, 21 Dec 2012 15:36:51 -0500 Subject: [PATCH 2327/2357] M2: Port M2-kernel on top of jb_2.5 AU_LINUX_ANDROID_JB_2.5.04.02.02.40.171 Squash the following: Initial board files and mach-type going through board file - doesnt compile HACK:remove otg calls from board file - need to bring them back later add i2c defines update samsung max17040 battery driver from cyano msm/Kconfig: add another select for M2; will remove these in time and adjust d2spr_defconfig appropriately Add bmp180 pressure driver power_supply.h: more defines board*m2: otg: HACK: return a sane value/remove non-existing field m2_spr:pn544 fix return type; err_ldo_gpio_set_dir remove unused label m2spr: HACK remove irrelevant touch device causing compilation problems M2_SPR: rpm: use 8960 pdata M2_SPR: no more sleep stats in 3.4 M2_SPR: int = null doesnt really make sense does it M2_SPR: no QDSS devices for now M2_SPR: no msm governor; if needed the commit is a4d6f11f348d2303f79049404b2101d1f62f40f4 M2_SPR: bring in msm governor after all no idea whats done on probe here M2_SPR: q6 modem subsystem, new device registration per board-8960 M2_SPR: clock fixup - MAJOR DERPING opportunity M2_SPR: gfx_init from board-8960; remove cpu_idle device per c1ed66c9035b4fbf240e46837d86a9a6442531f1 pm8xxx: Samsung defines M2_SPR: rpmrs_levels init as in board-8960 Missing defines and drivers M2_SPR: new acpuclk init; TOUCHSCREEN additions; swfi_latency for android_usb rathern than otg M2_SPR: Makefile derp - more things to compile M2_SPR: cpuidle set_states has been moved into driver per 42da9d2634a6e0d335e81a72d77dc606669ae022 M2_SPR: if 0 unused items in m2_sprc.c; add missing define in 8960.h M2_SPR: msising defines + gpiomux if 0 unneeded M2_SPR: out of board files; compilation fixes benign M2_SPR: drivers: adding files + cleanup M2_SPR: battery: derping-opportunity in i2c_write M2_SPR: drivers/power: fixups benign M2_SPR: drivers/video/msm compilation fixes mostly benign M2_SPR: video/msm: no more idle wake locks; change to pm_qos requests as in 2fcabf92eea31cad2ec4852dcab563f2c93e4294 M2_SPR: switch to board-m2_spr-display (copy from 8960-display). Too much samsung crap in there to port it statement by statement. M2_SPR: drivers/video: compilation fixes; minor derping poss (where else do we need pinfo->width pinfo->height?) M2_SPR: mostly benign video compilation fixes; (new) camera (requirements) added to defconfig) M2_SPR: board-m2spr: set_rpm_wakup_irq: this is no handled in devices-8960 via irq_wakeup= M2_SPR: board-m2: footswitch device name change M2_SPR: devices-8960: add msm_i2s_cpudai0 and *1 devices; DERP-ing possibility: how does this compare with cpudai_slimbus_2_rx(tx) see board-8960 M2_SPR mdp4_util missing stuff; benign M2_SPR: hdmi DERP-ing opportunity; samsung mhl_v2 doesnt really conform to current hdmi code M2_SPR: add drivers/battery and drivers/sensors M2_SPR: init/main add poweroff_charging; Do we need it in msm_fb.c as well? M2_SPR: pm8xxx compilation fixes; benign M2_SPR: sec_misc: comment out sec_debug functions DERP-ing opportunity sound/soc: wcd missing defines - need more? DERP-ing opportunity M2_SPR: defconfig: missing options - it compiles! M2_SPR: re-implement ram-console to use persistent ram M2_SPR: 8960-display revert any changes we made (we have a new display file for m2_spr) M2_SPR: benign ifdef/compilation changes (make sure we can compile other boardfiles too) M2_SPR: drivers/hwmon: properly ifdef our changes M2_SPR: devices-8960: benign ifdef our changes M2_SPR: low level debugging M2_SPR: remove CMA/MSM_IOMMU/GPU_SYNC(dirty); bring back original reserve_ion M2_SPR: add more low level debugging prints current failure local_flush_tlb_all M2_SPR: defconfig: disable memory strict RWX while debugging M2_SPR: defconfig: Add MEMBLOCK_NODE_MAP (substitute for ARCH_POPULATES_NODE*); Add SPARSEMEM, HOLES_IN_ZONE M2_SPR: move debugging console to bb705*; HACK: mmu: disable clearing pmd under MODULES_VADDR - otherwise we lose our debugging console - this WILL break things M2_SPR: board-m2*: fix init irq; remove debugging checks (we are past those) M2_SPR: change ram_console address; register early (IT WORKS!) remove duplicated socinfo_init M2_SPR: add/remove various debugging prints M2_SPR: bring in m2_spr-regulator M2_SPR: 8960-pmic: sec additions M2_SPR: board: gic ppi manual trigger no longer needed (see 1e52e43443009e7ee0c0afab603e71f5d532d7c4 in msm-3.0) Also bring adjust_ion_secure from board-8960 Also bring in spm data from board-8960 Also bring in tz_retention_flag adjustment from board-8960 M2_SPR: remove ALL low-level debugging prints/ram_console is functional M2_SPR: board: add qseecom device M2_SPR: Kconfig: select LPASS/MODEM_QDSPSV4 M2_SPR: ram_console: console_verbose() M2_SPR: msm_bus: add debugging print M2_SPR: drivers: hush some warnings M2_SPR: board: kgsl devices now registered in gfx_init M2_SPR: spr-regulator.c: add consumer mapping; need to reconsider switching back to 8960-regulator M2_SPR: regulator: more changes M2_SPR: register msmgpio device (new format for this in 3.4) M2_SPR: board*: no gov_device afterall M2_SPR: board: tabl_i2c_*_data needs explicit regulators (not hardcoded anymore); use proper structs if we are to couple with wcd9xxx driver M2_SPR: add drivers/cypress_236 M2_SPR: Kconfig: select REGULATOR_MSM_GPIO M2_SPR: back to original 8960-regulator; mod with m2 additions; DERP-ing opportunity M2_SPR: m2_spr-pmic; bring in leds-pm8xxx-m2; samsung really did a number here M2_SPR: otg additions; not done here, more might be needed M2_SPR: usb: BUGFIX: oh google M2_SPR: gadget/android: BUGFIX ctd M2_SPR: video: add debugging M2_SPR: arm/mm/fault: bionic cant dabrt M2_SPR: leds fixup (compiile new pm8xxx-m2) M2_SPR: cleanup from msm-3.4-dev; DERP-ing opportunity(esp in msm_otg); vsync fires though! M2_SPR: video: no footswitch (as in 3.0) <- possibly unncessary M2_SPR: WIP: camera sensor M2_SPR: add m2_spr-camera.c: was 8960-camera in 3.0 M2_SPR: m2_spr-camera: delete ifdefs for non d2 devices M2_SPR: board* more cleanup M2_SPR: media/video/msm_zsl from 3.0 M2_SPR: legacy camera fixups: bunch of hacks; compiles but hard reboot upon starting camera service M2_SPR: fix thermal - new init sequence in 3.4 M2_SPR: video/msm: quiet down debugging M2_SPR: sound: Add d2 files M2_SPR: msm/msm8960-d2 3.4 fixups; DERP-ing opportunity: register only i2c dais (no slim) Looking at 3.0, slim codecs aren't even getting probed M2_SPR: Disable pmem_audio devices M2_SPR: regulator: make audio regulators accessible M2_SPR: audio: make audio related clocks accessible M2_SPR: sound/msm8960-d2: clock fixup - benign M2_SPR: board*: remove audio slimbus devices; irrelevant Revert "ASoc: msm: Increase default buffersize to 4k for audio playback" This reverts commit 3449f7b315ae563569f41ef2d1a0edc9b7c999e8. M2: add d2vzw support M2_SPR: gpio_keys: compile gpio_keys_sec; Home/Vol Up/Down rocker should work M2: add vibrator M2: sound/*/codecs/wcd*: some fixups to match msm8960-d2 M2: sound: regulator: make more regulators easily accessible; board_m2*: increase audio ion heap M2: sound: add debugging prints M2: Audience a2220 (Nothing newer than (c) 2009 HTC?) M2: board: add restart function in machine description M2: configs: unset WCNSS_CORE; remove PRE_ALLOC carryover from msm-3.4 Almost ready to re-generate defconfigs. M2: fwd-port our old bcmdhd drivers and fixup board files to make them work. M2: @bluetooth - ohai! M2: ipc_socket: gps fix: Too much paranoia never a good thing - gps is functional M2: video: clocks: make sure set_rate is called before enable (benign, should get rid of some warning stacks on boot) Also use correct rate for esc_clk (incorrect value fro msm-3.4 branch) M2: wakelock: enable suspend debugging prints Looking for active wakelocks here. M2: otg: fixup suspend/resume The change in init_sm is needed because wait_for_completion(&pmic_vbus_init); blocks the init thread (and the otg wakelock taken out on probe is never released). Also make sure FSA9* toggles msm_otg_set_vbus_state both on plug-in as well as plug-out. Should be actually suspending now. M2: audio: fix some things I broke when porting (BT related) M2: max8952: from 3.0 (camera related regulator control) M2: camera: un/prepare clocks before enable/disable (get rid of warning stacks) M2: clocks: make camera related clocks accessible M2: bugfix: Fix a kernel bug causing ioctl mismatches in the media layer. Thanks to jonpry for finding the root of the problem. M2: header file fixup: bring in MSM camera headers in include/media from 3.0 Otherwise, there would be no end to ifdefs. Adjust headers elsewhere, as needed. M2: force evt->id=subscription->id=0; Our userland blob doesnt know about ids yet M2: HACK: media: Comment out a failing check during QBUF This check is not present in 3.0 -> if it were, it would fail there as well (I tried this). Need to figure out why it fails. M2: msm_wfd: compile This is compiled in 3.0. No idea why we would need it. M2: Makefile: bring back "treat warnings as errors" M2: compilation warning fixes; benign M2: vidc firmware download address to a sane value Compare to PIL_FW_BASE_ADDR in drivers/video/msm/vidc in 3.0. M2: camera: mach/camera.h from 3.0 as well; adjust headers elsewhere M2: camera: s5c73m3: fix my derp in antibanding settings (50/60HZ mismatch) M2: camera/vfe: request footswitch regulator using consumer supply name (benign) No functional change M2: add debug: print the footswitch on enable/disable M2: clocks: access to correct clock for front camera driver M2: mmc: Fix sdcc.4 suspend/resume handling Was causing bus failures on resume, resulting in hard resets when coming out of suspend with WiFi on. This is present in older msm kernels before they went with their built-in wifi solution (and used broadcom cards). M2: Squashed set of commits from invisiblek M2_VZW: fix rotation I must have been sleeping when I derped this M2: General cleanup and commonize common board files Cleaned up the board files to be more similar (easier to diff) Commonized the the common board files and created CONFIG_MACH_M2 to enable them. M2: add d2att/d2tmo, d2-r530 variantes and d2cri M2: defconfig: finally, new defconfigs M2: otg: Make sure the otg state machine workqueue is scheduled on first un/plug Fixes having to re-plug initially to get gadget started. msm: rotator: sync point support Wait for fence before do rotate Put the fence and fd after fence is signaled (cherry picked from commit 78c7b6971a12a541c7bd55cb4998bf1bf285609e) *detule: Rotator rendering support was failing (in particular when playing HD videos without HW support) because of the ioctl mismatch (see struct msm_rotator_data_info in MSM_ROTATOR_IOCTL_ROTATE). Even though I dislike the way this sync pt framework is implemented in the video layer, commit the entire patch rather than just changing the size of the data structure so that the IOCTL's match. Change-Id: Ia9092a9d19e5c8390a05cef7bdf908732bbbf8d6 Signed-off-by: Ken Zhang Signed-off-by: Siddhartha Agrawal M2: HACK: better camera hack M2: ion: ioctl compatibility with userland using old api As far as I can tell, flags passed by userland are now used to determine buffer caching. Note in ION_IOC_ALLOC_COMPAT we are currently forcing uncached buffer allocations (needed to make a choice here). This may need to change. M2: hardboot: Squash set of commits by mkasick M2: rebase fixups Conflicts: include/media/msm_camera.h include/media/msm_isp.h M2: defconfig: update non-spr defconfigs. --- Makefile | 4 +- arch/arm/Kconfig | 30 + arch/arm/boot/compressed/Makefile | 3 + arch/arm/boot/compressed/head.S | 77 +- arch/arm/boot/compressed/misc.c | 24 + arch/arm/configs/cyanogen_d2-r530_defconfig | 3699 +++++++ arch/arm/configs/cyanogen_d2att_defconfig | 3699 +++++++ arch/arm/configs/cyanogen_d2cri_defconfig | 3699 +++++++ arch/arm/configs/cyanogen_d2spr_defconfig | 3699 +++++++ arch/arm/configs/cyanogen_d2vzw_defconfig | 3699 +++++++ arch/arm/include/asm/kexec.h | 9 + arch/arm/include/asm/mach/mmc.h | 2 + arch/arm/kernel/machine_kexec.c | 24 +- arch/arm/kernel/relocate_kernel.S | 48 + arch/arm/kernel/setup.c | 3 +- arch/arm/mach-msm/Kconfig | 56 +- arch/arm/mach-msm/Makefile | 5 + arch/arm/mach-msm/Makefile.boot | 1 + arch/arm/mach-msm/board-8960-regulator.c | 64 +- arch/arm/mach-msm/board-8960-wifi.c | 357 + arch/arm/mach-msm/board-8960.h | 27 +- arch/arm/mach-msm/board-bluetooth-bcm4334.c | 240 + arch/arm/mach-msm/board-m2-camera.c | 1492 +++ arch/arm/mach-msm/board-m2-display.c | 2074 ++++ arch/arm/mach-msm/board-m2-pmic.c | 1068 ++ arch/arm/mach-msm/board-m2-regulator.c | 754 ++ arch/arm/mach-msm/board-m2-storage.c | 412 + arch/arm/mach-msm/board-m2_att-gpiomux.c | 1081 ++ arch/arm/mach-msm/board-m2_att.c | 5523 ++++++++++ arch/arm/mach-msm/board-m2_spr-gpiomux.c | 1099 ++ arch/arm/mach-msm/board-m2_spr.c | 5542 ++++++++++ arch/arm/mach-msm/board-m2_vzw-gpiomux.c | 1103 ++ arch/arm/mach-msm/board-m2_vzw.c | 5546 ++++++++++ arch/arm/mach-msm/board-mms-tsp.c | 425 + arch/arm/mach-msm/clock-8960.c | 77 +- arch/arm/mach-msm/devices-8960.c | 194 +- arch/arm/mach-msm/devices-msm8x60.h | 18 + arch/arm/mach-msm/devices.h | 9 + arch/arm/mach-msm/footswitch-8x60.c | 4 +- .../include/mach/board-msm8960-camera.h | 41 + arch/arm/mach-msm/include/mach/board.h | 86 +- arch/arm/mach-msm/include/mach/camera.h | 277 +- arch/arm/mach-msm/include/mach/m2_att-gpio.h | 205 + arch/arm/mach-msm/include/mach/m2_spr-gpio.h | 205 + arch/arm/mach-msm/include/mach/m2_vzw-gpio.h | 208 + arch/arm/mach-msm/include/mach/memory.h | 3 + arch/arm/mach-msm/include/mach/msm8960-gpio.h | 71 + arch/arm/mach-msm/include/mach/sec_debug.h | 530 + arch/arm/mach-msm/ipc_socket.c | 2 + arch/arm/mach-msm/mpm.h | 77 + arch/arm/mach-msm/msm_bus/msm_bus_arb.c | 1 + arch/arm/mach-msm/msm_watchdog.c | 1 + arch/arm/mach-msm/restart.c | 19 + arch/arm/mm/fault.c | 2 +- arch/arm/tools/mach-types | 23 + drivers/Kconfig | 8 + drivers/Makefile | 5 +- drivers/accessory/Kconfig | 26 + drivers/accessory/Makefile | 7 + drivers/accessory/mhl_tab_v2/Kconfig | 23 + drivers/accessory/mhl_tab_v2/Makefile | 10 + drivers/accessory/mhl_tab_v2/sii9234.c | 872 ++ drivers/accessory/mhl_tab_v2/sii9234_driver.h | 504 + drivers/accessory/sec_keyboard.c | 527 + drivers/accessory/sec_keyboard.h | 231 + drivers/accessory/sec_tablet_conn.c | 615 ++ drivers/base/core.c | 5 +- drivers/battery/Kconfig | 166 + drivers/battery/Makefile | 15 + drivers/battery/bq24157_charger.c | 482 + drivers/battery/max17042_fuelgauge.c | 2436 +++++ drivers/battery/max17048_fuelgauge.c | 422 + drivers/battery/max17050_fuelgauge.c | 2315 ++++ drivers/battery/sec_battery.c | 2540 +++++ drivers/battery/sec_charger.c | 396 + drivers/battery/sec_fuelgauge.c | 473 + drivers/battery/smb347_charger.c | 685 ++ drivers/bluetooth/Makefile | 2 + drivers/bluetooth/bluesleep_bcm.c | 961 ++ drivers/char/msm_rotator.c | 58 + drivers/gpu/ion/ion.c | 23 + drivers/hwmon/pm8xxx-adc-scale.c | 20 + drivers/hwmon/pm8xxx-adc.c | 46 + drivers/input/keyboard/Kconfig | 2 +- drivers/input/keyboard/Makefile | 2 + .../keyboard/cypress_touchkey_236/Kconfig | 12 + .../keyboard/cypress_touchkey_236/Makefile | 5 + .../cypress_touchkey_236/apexq_tkey_fw.h | 704 ++ .../cypress-touchkey-236.c | 1265 +++ .../cypress_touchkey_236/cypress_tkey_fw.h | 43 + .../cypress_touchkey_236/d2_tkey_fw.h | 1047 ++ .../cypress_touchkey_236/gogh_tkey_fw.h | 707 ++ .../keyboard/cypress_touchkey_236/issp_defs.h | 61 + .../cypress_touchkey_236/issp_delays.h | 82 + .../cypress_touchkey_236/issp_directives.h | 194 + .../issp_driver_routines.c | 530 + .../cypress_touchkey_236/issp_errors.h | 66 + .../cypress_touchkey_236/issp_extern.h | 102 + .../keyboard/cypress_touchkey_236/issp_main.c | 462 + .../cypress_touchkey_236/issp_revision.h | 33 + .../cypress_touchkey_236/issp_routines.c | 1031 ++ .../cypress_touchkey_236/issp_vectors.h | 1089 ++ .../cypress_touchkey_236/jaguar_tkey_fw.h | 1045 ++ drivers/input/keyboard/gpio_keys_sec.c | 810 ++ drivers/input/misc/Kconfig | 10 + drivers/input/misc/Makefile | 1 + drivers/input/misc/bmp180.c | 841 ++ drivers/input/touchscreen/Kconfig | 36 + drivers/input/touchscreen/Makefile | 4 + drivers/input/touchscreen/d2_465_fw.h | 2652 +++++ drivers/input/touchscreen/d2_fw.h | 2664 +++++ drivers/input/touchscreen/mms_ts_136.c | 2776 +++++ drivers/input/touchscreen/mms_ts_136_tablet.c | 2481 +++++ drivers/input/touchscreen/mms_ts_144.c | 3199 ++++++ drivers/input/touchscreen/mms_ts_fw.h | 65 + drivers/leds/Makefile | 2 +- drivers/leds/leds-pm8xxx-m2.c | 1287 +++ drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 5 +- drivers/media/video/msm/Kconfig | 15 + drivers/media/video/msm/sensors/Makefile | 2 + drivers/media/video/msm/sensors/s5c73m3.c | 3901 +++++++ drivers/media/video/msm/sensors/s5c73m3.h | 1066 ++ drivers/media/video/msm/sensors/s5c73m3_spi.c | 234 + drivers/media/video/msm/sensors/s5k6a3yx.c | 558 + drivers/media/video/msm_zsl/Kconfig | 242 + drivers/media/video/msm_zsl/Makefile | 50 + .../media/video/msm_zsl/actuators/Makefile | 5 + .../video/msm_zsl/actuators/imx074_act.c | 259 + .../video/msm_zsl/actuators/msm_actuator.c | 340 + .../video/msm_zsl/actuators/msm_actuator.h | 127 + drivers/media/video/msm_zsl/cam_pmic_s5k6aa.c | 135 + drivers/media/video/msm_zsl/cam_pmic_s5k6aa.h | 35 + drivers/media/video/msm_zsl/csi/Makefile | 3 + drivers/media/video/msm_zsl/csi/msm_csid.c | 355 + drivers/media/video/msm_zsl/csi/msm_csid.h | 48 + drivers/media/video/msm_zsl/csi/msm_csiphy.c | 325 + drivers/media/video/msm_zsl/csi/msm_csiphy.h | 46 + drivers/media/video/msm_zsl/csi/msm_ispif.c | 968 ++ drivers/media/video/msm_zsl/csi/msm_ispif.h | 62 + drivers/media/video/msm_zsl/flash.c | 622 ++ drivers/media/video/msm_zsl/gemini/Makefile | 2 + .../video/msm_zsl/gemini/msm_gemini_common.h | 39 + .../video/msm_zsl/gemini/msm_gemini_core.c | 253 + .../video/msm_zsl/gemini/msm_gemini_core.h | 35 + .../video/msm_zsl/gemini/msm_gemini_dev.c | 207 + .../video/msm_zsl/gemini/msm_gemini_hw.c | 524 + .../video/msm_zsl/gemini/msm_gemini_hw.h | 108 + .../video/msm_zsl/gemini/msm_gemini_hw_reg.h | 176 + .../msm_zsl/gemini/msm_gemini_platform.c | 228 + .../msm_zsl/gemini/msm_gemini_platform.h | 44 + .../video/msm_zsl/gemini/msm_gemini_sync.c | 887 ++ .../video/msm_zsl/gemini/msm_gemini_sync.h | 77 + drivers/media/video/msm_zsl/imx072.c | 1184 ++ drivers/media/video/msm_zsl/imx072.h | 79 + drivers/media/video/msm_zsl/imx072_reg.c | 153 + drivers/media/video/msm_zsl/imx074.c | 1413 +++ drivers/media/video/msm_zsl/imx074.h | 118 + drivers/media/video/msm_zsl/imx074_reg.c | 111 + drivers/media/video/msm_zsl/io/Makefile | 3 + .../video/msm_zsl/io/msm_camera_eeprom.c | 95 + .../video/msm_zsl/io/msm_camera_eeprom.h | 63 + .../media/video/msm_zsl/io/msm_camera_i2c.c | 427 + .../media/video/msm_zsl/io/msm_camera_i2c.h | 118 + drivers/media/video/msm_zsl/io/msm_io_util.c | 182 + drivers/media/video/msm_zsl/isx012.c | 623 ++ drivers/media/video/msm_zsl/isx012.h | 201 + drivers/media/video/msm_zsl/isx012_regs.h | 8979 +++++++++++++++ drivers/media/video/msm_zsl/isx012_regs_old.h | 4630 ++++++++ drivers/media/video/msm_zsl/isx012_v4l2.c | 1687 +++ drivers/media/video/msm_zsl/msm.c | 2855 +++++ drivers/media/video/msm_zsl/msm.h | 502 + drivers/media/video/msm_zsl/msm_axi_qos.c | 47 + drivers/media/video/msm_zsl/msm_camera.c | 4104 +++++++ drivers/media/video/msm_zsl/msm_io7x.c | 318 + drivers/media/video/msm_zsl/msm_io8x.c | 331 + drivers/media/video/msm_zsl/msm_io_7x27a.c | 609 ++ drivers/media/video/msm_zsl/msm_io_8960.c | 871 ++ drivers/media/video/msm_zsl/msm_io_8x60.c | 891 ++ drivers/media/video/msm_zsl/msm_io_vfe31.c | 840 ++ drivers/media/video/msm_zsl/msm_isp.c | 783 ++ drivers/media/video/msm_zsl/msm_ispif.c | 959 ++ drivers/media/video/msm_zsl/msm_mctl.c | 772 ++ drivers/media/video/msm_zsl/msm_mctl_buf.c | 764 ++ drivers/media/video/msm_zsl/msm_mctl_pp.c | 925 ++ drivers/media/video/msm_zsl/msm_mem.c | 414 + drivers/media/video/msm_zsl/msm_vfe31.c | 3736 +++++++ drivers/media/video/msm_zsl/msm_vfe31.h | 1115 ++ drivers/media/video/msm_zsl/msm_vfe32.c | 4277 ++++++++ drivers/media/video/msm_zsl/msm_vfe32.h | 995 ++ drivers/media/video/msm_zsl/msm_vfe7x.c | 783 ++ drivers/media/video/msm_zsl/msm_vfe7x.h | 265 + drivers/media/video/msm_zsl/msm_vfe7x27a.c | 741 ++ drivers/media/video/msm_zsl/msm_vfe7x27a.h | 300 + drivers/media/video/msm_zsl/msm_vfe8x.c | 842 ++ drivers/media/video/msm_zsl/msm_vfe8x.h | 909 ++ drivers/media/video/msm_zsl/msm_vfe8x_proc.c | 3888 +++++++ drivers/media/video/msm_zsl/msm_vfe8x_proc.h | 1563 +++ drivers/media/video/msm_zsl/msm_vpe.c | 793 ++ drivers/media/video/msm_zsl/msm_vpe.h | 192 + drivers/media/video/msm_zsl/msm_vpe1.c | 1446 +++ drivers/media/video/msm_zsl/msm_vpe1.h | 252 + drivers/media/video/msm_zsl/mt9d112.c | 845 ++ drivers/media/video/msm_zsl/mt9d112.h | 47 + drivers/media/video/msm_zsl/mt9d112_reg.c | 316 + drivers/media/video/msm_zsl/mt9d113.c | 656 ++ drivers/media/video/msm_zsl/mt9d113.h | 66 + drivers/media/video/msm_zsl/mt9d113_reg.c | 452 + drivers/media/video/msm_zsl/mt9e013.c | 1137 ++ drivers/media/video/msm_zsl/mt9e013.h | 174 + drivers/media/video/msm_zsl/mt9e013_reg.c | 234 + drivers/media/video/msm_zsl/mt9p012.h | 59 + drivers/media/video/msm_zsl/mt9p012_bam.c | 1426 +++ drivers/media/video/msm_zsl/mt9p012_fox.c | 1345 +++ drivers/media/video/msm_zsl/mt9p012_km.c | 1295 +++ drivers/media/video/msm_zsl/mt9p012_km.h | 61 + drivers/media/video/msm_zsl/mt9p012_km_reg.c | 373 + drivers/media/video/msm_zsl/mt9p012_reg.c | 261 + drivers/media/video/msm_zsl/mt9t013.c | 1503 +++ drivers/media/video/msm_zsl/mt9t013.h | 59 + drivers/media/video/msm_zsl/mt9t013_reg.c | 273 + drivers/media/video/msm_zsl/ov5640.c | 1477 +++ drivers/media/video/msm_zsl/ov5640.h | 2993 +++++ drivers/media/video/msm_zsl/ov7692.c | 595 + drivers/media/video/msm_zsl/ov7692.h | 49 + drivers/media/video/msm_zsl/ov7692_qrd.c | 679 ++ drivers/media/video/msm_zsl/ov9726.c | 793 ++ drivers/media/video/msm_zsl/ov9726.h | 38 + drivers/media/video/msm_zsl/ov9726_reg.c | 100 + drivers/media/video/msm_zsl/pm_qos_params.h | 38 + drivers/media/video/msm_zsl/qs_s5k4e1.c | 1822 ++++ drivers/media/video/msm_zsl/qs_s5k4e1.h | 89 + drivers/media/video/msm_zsl/qs_s5k4e1_reg.c | 804 ++ drivers/media/video/msm_zsl/s5k3e2fx.c | 1385 +++ drivers/media/video/msm_zsl/s5k3e2fx.h | 18 + drivers/media/video/msm_zsl/s5k4e1.c | 1103 ++ drivers/media/video/msm_zsl/s5k4e1.h | 94 + drivers/media/video/msm_zsl/s5k4e1_reg.c | 169 + drivers/media/video/msm_zsl/s5k6aa.h | 196 + drivers/media/video/msm_zsl/s5k6aa_regs.h | 2840 +++++ drivers/media/video/msm_zsl/s5k6aa_v4l2.c | 818 ++ drivers/media/video/msm_zsl/s5k8aay.h | 181 + drivers/media/video/msm_zsl/s5k8aay_regs.h | 3537 ++++++ drivers/media/video/msm_zsl/s5k8aay_regs_v2.h | 9631 +++++++++++++++++ drivers/media/video/msm_zsl/s5k8aay_v4l2.c | 1058 ++ drivers/media/video/msm_zsl/sensors/Makefile | 10 + .../media/video/msm_zsl/sensors/imx074_v4l2.c | 371 + .../media/video/msm_zsl/sensors/msm_sensor.c | 760 ++ .../media/video/msm_zsl/sensors/msm_sensor.h | 233 + .../video/msm_zsl/sensors/mt9m114_v4l2.c | 1340 +++ drivers/media/video/msm_zsl/sensors/ov2720.c | 532 + drivers/media/video/msm_zsl/sensors/ov2720.h | 15 + drivers/media/video/msm_zsl/sensors/s5c73m3.c | 3888 +++++++ drivers/media/video/msm_zsl/sensors/s5c73m3.h | 1067 ++ .../media/video/msm_zsl/sensors/s5c73m3_spi.c | 234 + .../media/video/msm_zsl/sensors/s5k6a3yx.c | 559 + drivers/media/video/msm_zsl/sn12m0pz.c | 1850 ++++ drivers/media/video/msm_zsl/sn12m0pz.h | 138 + drivers/media/video/msm_zsl/sn12m0pz_reg.c | 212 + drivers/media/video/msm_zsl/vb6801.c | 1616 +++ drivers/media/video/msm_zsl/vb6801.h | 66 + drivers/media/video/msm_zsl/vx6953.c | 3664 +++++++ drivers/media/video/msm_zsl/vx6953.h | 136 + drivers/media/video/msm_zsl/vx6953_reg.c | 135 + drivers/media/video/msm_zsl/vx6953_reg_v4l2.c | 135 + drivers/media/video/msm_zsl/vx6953_v4l2.c | 4147 +++++++ drivers/media/video/msm_zsl/vx6953_v4l2.h | 136 + drivers/media/video/v4l2-ioctl.c | 7 +- drivers/media/video/videobuf2-core.c | 17 +- drivers/misc/Kconfig | 106 + drivers/misc/Makefile | 10 + drivers/misc/a2220.c | 1274 +++ drivers/misc/a2220_firmware.h | 31 + drivers/misc/a2220_firmware_i747.h | 4867 +++++++++ drivers/misc/a2220_firmware_t999.h | 5379 +++++++++ drivers/misc/bh1721.c | 700 ++ drivers/misc/cm36651.c | 1341 +++ drivers/misc/fsa9485.c | 1362 +++ drivers/misc/inv_mpu/Kconfig | 78 + drivers/misc/inv_mpu/Makefile | 51 + drivers/misc/inv_mpu/README | 104 + drivers/misc/inv_mpu/accel/Kconfig | 133 + drivers/misc/inv_mpu/accel/Makefile | 38 + drivers/misc/inv_mpu/accel/mpu6050.c | 700 ++ drivers/misc/inv_mpu/accel/mpu6050.h | 39 + drivers/misc/inv_mpu/compass/Kconfig | 121 + drivers/misc/inv_mpu/compass/Makefile | 38 + drivers/misc/inv_mpu/compass/ak8975.c | 504 + drivers/misc/inv_mpu/compass/yas530_ext.c | 273 + drivers/misc/inv_mpu/compass/yas530_ext.h | 31 + drivers/misc/inv_mpu/log.h | 287 + drivers/misc/inv_mpu/mldl_cfg.c | 2054 ++++ drivers/misc/inv_mpu/mldl_cfg.h | 384 + drivers/misc/inv_mpu/mldl_print_cfg.c | 138 + drivers/misc/inv_mpu/mldl_print_cfg.h | 38 + drivers/misc/inv_mpu/mlsl-kernel.c | 421 + drivers/misc/inv_mpu/mlsl.h | 193 + drivers/misc/inv_mpu/mltypes.h | 234 + drivers/misc/inv_mpu/mpu-dev.c | 2581 +++++ drivers/misc/inv_mpu/mpu-dev.h | 43 + drivers/misc/inv_mpu/mpu6050b1.h | 437 + drivers/misc/inv_mpu/mpuirq.c | 317 + drivers/misc/inv_mpu/mpuirq.h | 36 + drivers/misc/inv_mpu/slaveirq.c | 266 + drivers/misc/inv_mpu/slaveirq.h | 36 + drivers/misc/inv_mpu/timerirq.c | 298 + drivers/misc/inv_mpu/timerirq.h | 30 + drivers/misc/pn544.c | 458 + drivers/misc/sec_jack.c | 670 ++ drivers/misc/sec_misc.c | 287 + drivers/misc/sec_param.c | 256 + drivers/misc/stmpe811.c | 300 + drivers/mmc/core/core.c | 14 +- drivers/mmc/host/msm_sdcc.c | 12 +- drivers/motor/Kconfig | 13 + drivers/motor/Makefile | 8 + drivers/motor/VibeOSKernelLinuxHRTime.c | 254 + drivers/motor/immvibespi.c | 344 + drivers/motor/max77693_haptic.c | 166 + drivers/motor/tspdrv.c | 746 ++ drivers/motor/tspdrv.h | 224 + drivers/net/wireless/Makefile | 3 + drivers/net/wireless/bcmdhd/Kconfig | 55 +- drivers/net/wireless/bcmdhd/Makefile | 250 +- drivers/net/wireless/bcmdhd/aiutils.c | 18 +- drivers/net/wireless/bcmdhd/bcmevent.c | 2 +- drivers/net/wireless/bcmdhd/bcmsdh.c | 72 +- drivers/net/wireless/bcmdhd/bcmsdh_linux.c | 97 +- drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c | 184 +- .../net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c | 116 +- drivers/net/wireless/bcmdhd/bcmsdspi_linux.c | 420 + drivers/net/wireless/bcmdhd/bcmspibrcm.c | 1853 ++++ drivers/net/wireless/bcmdhd/bcmutils.c | 7 + drivers/net/wireless/bcmdhd/bcmwifi.c | 668 +- drivers/net/wireless/bcmdhd/dhd.h | 175 +- drivers/net/wireless/bcmdhd/dhd_bus.h | 4 +- drivers/net/wireless/bcmdhd/dhd_cdc.c | 314 +- drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 37 +- drivers/net/wireless/bcmdhd/dhd_common.c | 120 +- drivers/net/wireless/bcmdhd/dhd_custom_gpio.c | 22 +- drivers/net/wireless/bcmdhd/dhd_custom_sec.c | 1197 ++ drivers/net/wireless/bcmdhd/dhd_dbg.h | 24 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 1724 ++- drivers/net/wireless/bcmdhd/dhd_proto.h | 8 +- drivers/net/wireless/bcmdhd/dhd_sdio.c | 1392 ++- drivers/net/wireless/bcmdhd/dhd_sec_feature.h | 123 + drivers/net/wireless/bcmdhd/dhd_wlfc.h | 22 +- drivers/net/wireless/bcmdhd/hndpmu.c | 16 +- drivers/net/wireless/bcmdhd/include/Makefile | 2 +- .../bcmdhd/include/bcm_android_types.h | 44 - drivers/net/wireless/bcmdhd/include/bcmdevs.h | 10 +- .../net/wireless/bcmdhd/include/bcmsdbus.h | 31 +- drivers/net/wireless/bcmdhd/include/bcmsdh.h | 13 +- .../wireless/bcmdhd/include/bcmsdh_sdmmc.h | 6 +- .../net/wireless/bcmdhd/include/bcmsdstd.h | 18 +- .../net/wireless/bcmdhd/include/bcmspibrcm.h | 59 +- .../net/wireless/bcmdhd/include/bcmutils.h | 10 +- drivers/net/wireless/bcmdhd/include/bcmwifi.h | 210 +- .../net/wireless/bcmdhd/include/dhdioctl.h | 3 +- drivers/net/wireless/bcmdhd/include/epivers.h | 28 +- .../net/wireless/bcmdhd/include/linux_osl.h | 4 +- .../net/wireless/bcmdhd/include/linuxver.h | 30 +- .../wireless/bcmdhd/include/proto/802.11.h | 13 +- .../wireless/bcmdhd/include/proto/802.11e.h | 6 + .../wireless/bcmdhd/include/proto/bcmevent.h | 13 + .../net/wireless/bcmdhd/include/proto/p2p.h | 4 +- .../net/wireless/bcmdhd/include/proto/wpa.h | 11 +- .../net/wireless/bcmdhd/include/rwl_wifi.h | 96 - drivers/net/wireless/bcmdhd/include/sbchipc.h | 151 +- drivers/net/wireless/bcmdhd/include/sbsdio.h | 5 + .../net/wireless/bcmdhd/include/sbsdpcmdev.h | 4 +- drivers/net/wireless/bcmdhd/include/sdioh.h | 6 +- drivers/net/wireless/bcmdhd/include/sdiovar.h | 23 + drivers/net/wireless/bcmdhd/include/siutils.h | 21 +- drivers/net/wireless/bcmdhd/include/spid.h | 26 +- drivers/net/wireless/bcmdhd/include/usbrdl.h | 203 - .../wireless/bcmdhd/include/wlc_clm_rates.h | 255 - .../bcmdhd/include/wlc_extlog_idstr.h | 117 - .../net/wireless/bcmdhd/include/wlfc_proto.h | 5 +- drivers/net/wireless/bcmdhd/include/wlioctl.h | 90 +- drivers/net/wireless/bcmdhd/linux_osl.c | 121 +- drivers/net/wireless/bcmdhd/siutils.c | 135 +- drivers/net/wireless/bcmdhd/wl_android.c | 1367 ++- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 4581 ++++++-- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 239 +- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 779 +- drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 88 +- drivers/net/wireless/bcmdhd/wl_iw.c | 18 +- drivers/net/wireless/bcmdhd/wl_roam.c | 288 + drivers/net/wireless/bcmdhd/wldev_common.c | 44 +- drivers/net/wireless/bcmdhd/wldev_common.h | 7 +- drivers/net/wireless/btlock/Kconfig | 5 + drivers/net/wireless/btlock/Makefile | 1 + drivers/net/wireless/btlock/btlock.c | 140 + drivers/power/Kconfig | 49 + drivers/power/Makefile | 11 +- drivers/power/max17040_battery.c | 868 +- drivers/power/pm8921-sec-charger.c | 4214 ++++++++ drivers/power/sec_battery.c | 2932 +++++ drivers/power/smb347_charger.c | 1840 ++++ drivers/regulator/max8952.c | 119 +- drivers/sensors/Kconfig | 13 + drivers/sensors/Makefile | 7 + drivers/sensors/core/Kconfig | 10 + drivers/sensors/core/Makefile | 5 + drivers/sensors/core/sensors_core.c | 105 + drivers/staging/android/ram_console.c | 2 +- drivers/usb/gadget/android.c | 4 +- drivers/usb/otg/msm_otg.c | 103 +- drivers/video/msm/Kconfig | 47 +- drivers/video/msm/Makefile | 17 +- drivers/video/msm/cmc624.h | 102 + drivers/video/msm/cmc624_sysfs.c | 514 + drivers/video/msm/hdmi_msm.c | 39 +- drivers/video/msm/hdmi_msm.h | 5 +- drivers/video/msm/mdp.c | 7 +- drivers/video/msm/mdp.h | 4 + drivers/video/msm/mdp4.h | 32 + drivers/video/msm/mdp4_util.c | 627 ++ drivers/video/msm/mdp4_video_enhance.c | 880 ++ drivers/video/msm/mdp4_video_enhance.h | 61 + drivers/video/msm/mdp4_video_tuning.h | 2124 ++++ drivers/video/msm/mdp4_wfd_writeback_util.h | 4 +- drivers/video/msm/mhl/mhl_8334.c | 2 +- drivers/video/msm/mhl_v2/Kconfig | 21 + drivers/video/msm/mhl_v2/Makefile | 10 + drivers/video/msm/mhl_v2/sii9234.c | 3202 ++++++ drivers/video/msm/mhl_v2/sii9234_driver.h | 517 + drivers/video/msm/mipi_dsi.h | 2 + drivers/video/msm/mipi_samsung_esd_refresh.c | 406 + drivers/video/msm/mipi_samsung_esd_refresh.h | 88 + drivers/video/msm/mipi_samsung_oled.c | 1653 +++ drivers/video/msm/mipi_samsung_oled.h | 250 + .../video/msm/mipi_samsung_oled_cmd_qhd_pt.c | 1115 ++ .../video/msm/mipi_samsung_oled_video_hd_pt.c | 1696 +++ .../msm/mipi_samsung_oled_video_wvga_pt.c | 1113 ++ .../msm/mipi_samsung_tft_video_wxga_pt.c | 165 + drivers/video/msm/msm_dss_io_8960.c | 12 + drivers/video/msm/msm_fb.c | 6 +- drivers/video/msm/msm_fb.h | 2 + drivers/video/msm/msm_fb_panel.h | 4 + drivers/video/msm/samsung_cmc624.c | 1790 +++ drivers/video/msm/samsung_cmc624.h | 94 + drivers/video/msm/samsung_cmc624_tune.h | 1342 +++ drivers/video/msm/smart_dimming.h | 112 + drivers/video/msm/smart_mtp_2p2_gamma.h | 2138 ++++ drivers/video/msm/smart_mtp_s6e8aa0x01.c | 1592 +++ drivers/video/msm/smart_mtp_s6e8aa0x01.h | 321 + include/linux/charging_temperature_data.h | 195 + include/linux/gpio_keys.h | 3 +- include/linux/i2c/cm36651.h | 32 + include/linux/i2c/cypress_touchkey.h | 54 + include/linux/i2c/fsa9485.h | 70 + include/linux/input.h | 3 + include/linux/input/bmp180.h | 95 + include/linux/ion.h | 32 + include/linux/kexec.h | 16 +- include/linux/leds-pm8xxx.h | 26 + include/linux/max17040_battery.h | 45 + include/linux/mfd/pm8xxx/pm8921-charger.h | 5 + include/linux/mfd/pm8xxx/pm8921-sec-charger.h | 116 + include/linux/mfd/pm8xxx/pm8xxx-adc.h | 28 +- include/linux/mfd/wcd9310/Kbuild | 1 + include/linux/mfd/wcd9310/core.h | 149 + include/linux/mfd/wcd9310/pdata.h | 132 + include/linux/mfd/wcd9310/registers.h | 1073 ++ include/linux/mpu.h | 483 + include/linux/mpu_411.h | 380 + include/linux/msm_ion.h | 19 +- include/linux/msm_mdp.h | 4 +- include/linux/msm_rotator.h | 1 + include/linux/platform_data/mms_ts.h | 47 + include/linux/pn544.h | 34 + include/linux/power_supply.h | 27 + include/linux/regulator/gpio-regulator.h | 2 +- include/linux/regulator/max8952.h | 3 + include/linux/sec_battery.h | 89 + include/linux/sec_jack.h | 67 + include/linux/sec_param.h | 41 + include/linux/sii9234.h | 51 + include/linux/sii9234_rcp.h | 177 + include/linux/smb347_charger.h | 29 + include/linux/usb/msm_hsusb.h | 1 + include/linux/vibrator.h | 43 + include/linux/videodev2.h | 2 +- include/media/msm_camera.h | 1434 +-- include/media/msm_isp.h | 114 +- include/sound/a2220.h | 237 + include/sound/soc-dsp.h | 124 + include/trace/trace_msm_low_power.h | 154 + init/main.c | 13 + kernel/kexec.c | 4 + kernel/power/wakelock.c | 2 +- scripts/gcc-wrapper.py | 5 + sound/soc/codecs/wcd9310.c | 46 +- sound/soc/msm/Makefile | 36 +- sound/soc/msm/msm-pcm-routing.c | 3 +- sound/soc/msm/msm8960-d2.c | 2339 ++++ sound/soc/msm/qdsp6/q6afe.c | 14 +- sound/soc/msm/qdsp6v2/q6afe.c | 2 +- 500 files changed, 301381 insertions(+), 5411 deletions(-) create mode 100644 arch/arm/configs/cyanogen_d2-r530_defconfig create mode 100644 arch/arm/configs/cyanogen_d2att_defconfig create mode 100644 arch/arm/configs/cyanogen_d2cri_defconfig create mode 100644 arch/arm/configs/cyanogen_d2spr_defconfig create mode 100644 arch/arm/configs/cyanogen_d2vzw_defconfig create mode 100644 arch/arm/mach-msm/board-8960-wifi.c create mode 100644 arch/arm/mach-msm/board-bluetooth-bcm4334.c create mode 100644 arch/arm/mach-msm/board-m2-camera.c create mode 100644 arch/arm/mach-msm/board-m2-display.c create mode 100644 arch/arm/mach-msm/board-m2-pmic.c create mode 100644 arch/arm/mach-msm/board-m2-regulator.c create mode 100644 arch/arm/mach-msm/board-m2-storage.c create mode 100644 arch/arm/mach-msm/board-m2_att-gpiomux.c create mode 100644 arch/arm/mach-msm/board-m2_att.c create mode 100644 arch/arm/mach-msm/board-m2_spr-gpiomux.c create mode 100644 arch/arm/mach-msm/board-m2_spr.c create mode 100644 arch/arm/mach-msm/board-m2_vzw-gpiomux.c create mode 100644 arch/arm/mach-msm/board-m2_vzw.c create mode 100644 arch/arm/mach-msm/board-mms-tsp.c create mode 100644 arch/arm/mach-msm/include/mach/board-msm8960-camera.h create mode 100644 arch/arm/mach-msm/include/mach/m2_att-gpio.h create mode 100644 arch/arm/mach-msm/include/mach/m2_spr-gpio.h create mode 100644 arch/arm/mach-msm/include/mach/m2_vzw-gpio.h create mode 100644 arch/arm/mach-msm/include/mach/msm8960-gpio.h create mode 100644 arch/arm/mach-msm/include/mach/sec_debug.h create mode 100644 arch/arm/mach-msm/mpm.h create mode 100644 drivers/accessory/Kconfig create mode 100644 drivers/accessory/Makefile create mode 100644 drivers/accessory/mhl_tab_v2/Kconfig create mode 100644 drivers/accessory/mhl_tab_v2/Makefile create mode 100644 drivers/accessory/mhl_tab_v2/sii9234.c create mode 100644 drivers/accessory/mhl_tab_v2/sii9234_driver.h create mode 100644 drivers/accessory/sec_keyboard.c create mode 100644 drivers/accessory/sec_keyboard.h create mode 100644 drivers/accessory/sec_tablet_conn.c create mode 100644 drivers/battery/Kconfig create mode 100644 drivers/battery/Makefile create mode 100644 drivers/battery/bq24157_charger.c create mode 100644 drivers/battery/max17042_fuelgauge.c create mode 100644 drivers/battery/max17048_fuelgauge.c create mode 100644 drivers/battery/max17050_fuelgauge.c create mode 100644 drivers/battery/sec_battery.c create mode 100644 drivers/battery/sec_charger.c create mode 100644 drivers/battery/sec_fuelgauge.c create mode 100644 drivers/battery/smb347_charger.c create mode 100644 drivers/bluetooth/bluesleep_bcm.c create mode 100644 drivers/input/keyboard/cypress_touchkey_236/Kconfig create mode 100644 drivers/input/keyboard/cypress_touchkey_236/Makefile create mode 100644 drivers/input/keyboard/cypress_touchkey_236/apexq_tkey_fw.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/cypress-touchkey-236.c create mode 100644 drivers/input/keyboard/cypress_touchkey_236/cypress_tkey_fw.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/d2_tkey_fw.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/gogh_tkey_fw.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_defs.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_delays.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_directives.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_driver_routines.c create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_errors.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_extern.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_main.c create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_revision.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_routines.c create mode 100644 drivers/input/keyboard/cypress_touchkey_236/issp_vectors.h create mode 100644 drivers/input/keyboard/cypress_touchkey_236/jaguar_tkey_fw.h create mode 100644 drivers/input/keyboard/gpio_keys_sec.c create mode 100644 drivers/input/misc/bmp180.c create mode 100644 drivers/input/touchscreen/d2_465_fw.h create mode 100644 drivers/input/touchscreen/d2_fw.h create mode 100644 drivers/input/touchscreen/mms_ts_136.c create mode 100644 drivers/input/touchscreen/mms_ts_136_tablet.c create mode 100644 drivers/input/touchscreen/mms_ts_144.c create mode 100644 drivers/input/touchscreen/mms_ts_fw.h create mode 100644 drivers/leds/leds-pm8xxx-m2.c create mode 100644 drivers/media/video/msm/sensors/s5c73m3.c create mode 100644 drivers/media/video/msm/sensors/s5c73m3.h create mode 100644 drivers/media/video/msm/sensors/s5c73m3_spi.c create mode 100644 drivers/media/video/msm/sensors/s5k6a3yx.c create mode 100644 drivers/media/video/msm_zsl/Kconfig create mode 100644 drivers/media/video/msm_zsl/Makefile create mode 100644 drivers/media/video/msm_zsl/actuators/Makefile create mode 100644 drivers/media/video/msm_zsl/actuators/imx074_act.c create mode 100755 drivers/media/video/msm_zsl/actuators/msm_actuator.c create mode 100644 drivers/media/video/msm_zsl/actuators/msm_actuator.h create mode 100644 drivers/media/video/msm_zsl/cam_pmic_s5k6aa.c create mode 100644 drivers/media/video/msm_zsl/cam_pmic_s5k6aa.h create mode 100644 drivers/media/video/msm_zsl/csi/Makefile create mode 100644 drivers/media/video/msm_zsl/csi/msm_csid.c create mode 100644 drivers/media/video/msm_zsl/csi/msm_csid.h create mode 100644 drivers/media/video/msm_zsl/csi/msm_csiphy.c create mode 100644 drivers/media/video/msm_zsl/csi/msm_csiphy.h create mode 100644 drivers/media/video/msm_zsl/csi/msm_ispif.c create mode 100644 drivers/media/video/msm_zsl/csi/msm_ispif.h create mode 100644 drivers/media/video/msm_zsl/flash.c create mode 100644 drivers/media/video/msm_zsl/gemini/Makefile create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_common.h create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_core.c create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_core.h create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_dev.c create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_hw.c create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_hw.h create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_hw_reg.h create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_platform.c create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_platform.h create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_sync.c create mode 100644 drivers/media/video/msm_zsl/gemini/msm_gemini_sync.h create mode 100644 drivers/media/video/msm_zsl/imx072.c create mode 100644 drivers/media/video/msm_zsl/imx072.h create mode 100644 drivers/media/video/msm_zsl/imx072_reg.c create mode 100644 drivers/media/video/msm_zsl/imx074.c create mode 100644 drivers/media/video/msm_zsl/imx074.h create mode 100644 drivers/media/video/msm_zsl/imx074_reg.c create mode 100644 drivers/media/video/msm_zsl/io/Makefile create mode 100644 drivers/media/video/msm_zsl/io/msm_camera_eeprom.c create mode 100644 drivers/media/video/msm_zsl/io/msm_camera_eeprom.h create mode 100644 drivers/media/video/msm_zsl/io/msm_camera_i2c.c create mode 100644 drivers/media/video/msm_zsl/io/msm_camera_i2c.h create mode 100644 drivers/media/video/msm_zsl/io/msm_io_util.c create mode 100644 drivers/media/video/msm_zsl/isx012.c create mode 100644 drivers/media/video/msm_zsl/isx012.h create mode 100644 drivers/media/video/msm_zsl/isx012_regs.h create mode 100644 drivers/media/video/msm_zsl/isx012_regs_old.h create mode 100644 drivers/media/video/msm_zsl/isx012_v4l2.c create mode 100755 drivers/media/video/msm_zsl/msm.c create mode 100755 drivers/media/video/msm_zsl/msm.h create mode 100644 drivers/media/video/msm_zsl/msm_axi_qos.c create mode 100644 drivers/media/video/msm_zsl/msm_camera.c create mode 100644 drivers/media/video/msm_zsl/msm_io7x.c create mode 100644 drivers/media/video/msm_zsl/msm_io8x.c create mode 100644 drivers/media/video/msm_zsl/msm_io_7x27a.c create mode 100644 drivers/media/video/msm_zsl/msm_io_8960.c create mode 100644 drivers/media/video/msm_zsl/msm_io_8x60.c create mode 100644 drivers/media/video/msm_zsl/msm_io_vfe31.c create mode 100644 drivers/media/video/msm_zsl/msm_isp.c create mode 100644 drivers/media/video/msm_zsl/msm_ispif.c create mode 100644 drivers/media/video/msm_zsl/msm_mctl.c create mode 100644 drivers/media/video/msm_zsl/msm_mctl_buf.c create mode 100644 drivers/media/video/msm_zsl/msm_mctl_pp.c create mode 100644 drivers/media/video/msm_zsl/msm_mem.c create mode 100644 drivers/media/video/msm_zsl/msm_vfe31.c create mode 100644 drivers/media/video/msm_zsl/msm_vfe31.h create mode 100755 drivers/media/video/msm_zsl/msm_vfe32.c create mode 100644 drivers/media/video/msm_zsl/msm_vfe32.h create mode 100644 drivers/media/video/msm_zsl/msm_vfe7x.c create mode 100644 drivers/media/video/msm_zsl/msm_vfe7x.h create mode 100644 drivers/media/video/msm_zsl/msm_vfe7x27a.c create mode 100644 drivers/media/video/msm_zsl/msm_vfe7x27a.h create mode 100644 drivers/media/video/msm_zsl/msm_vfe8x.c create mode 100644 drivers/media/video/msm_zsl/msm_vfe8x.h create mode 100644 drivers/media/video/msm_zsl/msm_vfe8x_proc.c create mode 100644 drivers/media/video/msm_zsl/msm_vfe8x_proc.h create mode 100644 drivers/media/video/msm_zsl/msm_vpe.c create mode 100644 drivers/media/video/msm_zsl/msm_vpe.h create mode 100644 drivers/media/video/msm_zsl/msm_vpe1.c create mode 100644 drivers/media/video/msm_zsl/msm_vpe1.h create mode 100644 drivers/media/video/msm_zsl/mt9d112.c create mode 100644 drivers/media/video/msm_zsl/mt9d112.h create mode 100644 drivers/media/video/msm_zsl/mt9d112_reg.c create mode 100644 drivers/media/video/msm_zsl/mt9d113.c create mode 100644 drivers/media/video/msm_zsl/mt9d113.h create mode 100644 drivers/media/video/msm_zsl/mt9d113_reg.c create mode 100644 drivers/media/video/msm_zsl/mt9e013.c create mode 100644 drivers/media/video/msm_zsl/mt9e013.h create mode 100644 drivers/media/video/msm_zsl/mt9e013_reg.c create mode 100644 drivers/media/video/msm_zsl/mt9p012.h create mode 100644 drivers/media/video/msm_zsl/mt9p012_bam.c create mode 100644 drivers/media/video/msm_zsl/mt9p012_fox.c create mode 100644 drivers/media/video/msm_zsl/mt9p012_km.c create mode 100644 drivers/media/video/msm_zsl/mt9p012_km.h create mode 100644 drivers/media/video/msm_zsl/mt9p012_km_reg.c create mode 100644 drivers/media/video/msm_zsl/mt9p012_reg.c create mode 100644 drivers/media/video/msm_zsl/mt9t013.c create mode 100644 drivers/media/video/msm_zsl/mt9t013.h create mode 100644 drivers/media/video/msm_zsl/mt9t013_reg.c create mode 100644 drivers/media/video/msm_zsl/ov5640.c create mode 100644 drivers/media/video/msm_zsl/ov5640.h create mode 100644 drivers/media/video/msm_zsl/ov7692.c create mode 100644 drivers/media/video/msm_zsl/ov7692.h create mode 100644 drivers/media/video/msm_zsl/ov7692_qrd.c create mode 100644 drivers/media/video/msm_zsl/ov9726.c create mode 100644 drivers/media/video/msm_zsl/ov9726.h create mode 100644 drivers/media/video/msm_zsl/ov9726_reg.c create mode 100644 drivers/media/video/msm_zsl/pm_qos_params.h create mode 100644 drivers/media/video/msm_zsl/qs_s5k4e1.c create mode 100644 drivers/media/video/msm_zsl/qs_s5k4e1.h create mode 100644 drivers/media/video/msm_zsl/qs_s5k4e1_reg.c create mode 100644 drivers/media/video/msm_zsl/s5k3e2fx.c create mode 100644 drivers/media/video/msm_zsl/s5k3e2fx.h create mode 100644 drivers/media/video/msm_zsl/s5k4e1.c create mode 100644 drivers/media/video/msm_zsl/s5k4e1.h create mode 100644 drivers/media/video/msm_zsl/s5k4e1_reg.c create mode 100644 drivers/media/video/msm_zsl/s5k6aa.h create mode 100644 drivers/media/video/msm_zsl/s5k6aa_regs.h create mode 100644 drivers/media/video/msm_zsl/s5k6aa_v4l2.c create mode 100644 drivers/media/video/msm_zsl/s5k8aay.h create mode 100644 drivers/media/video/msm_zsl/s5k8aay_regs.h create mode 100644 drivers/media/video/msm_zsl/s5k8aay_regs_v2.h create mode 100644 drivers/media/video/msm_zsl/s5k8aay_v4l2.c create mode 100644 drivers/media/video/msm_zsl/sensors/Makefile create mode 100644 drivers/media/video/msm_zsl/sensors/imx074_v4l2.c create mode 100644 drivers/media/video/msm_zsl/sensors/msm_sensor.c create mode 100644 drivers/media/video/msm_zsl/sensors/msm_sensor.h create mode 100644 drivers/media/video/msm_zsl/sensors/mt9m114_v4l2.c create mode 100644 drivers/media/video/msm_zsl/sensors/ov2720.c create mode 100644 drivers/media/video/msm_zsl/sensors/ov2720.h create mode 100644 drivers/media/video/msm_zsl/sensors/s5c73m3.c create mode 100644 drivers/media/video/msm_zsl/sensors/s5c73m3.h create mode 100644 drivers/media/video/msm_zsl/sensors/s5c73m3_spi.c create mode 100644 drivers/media/video/msm_zsl/sensors/s5k6a3yx.c create mode 100644 drivers/media/video/msm_zsl/sn12m0pz.c create mode 100644 drivers/media/video/msm_zsl/sn12m0pz.h create mode 100644 drivers/media/video/msm_zsl/sn12m0pz_reg.c create mode 100644 drivers/media/video/msm_zsl/vb6801.c create mode 100644 drivers/media/video/msm_zsl/vb6801.h create mode 100644 drivers/media/video/msm_zsl/vx6953.c create mode 100644 drivers/media/video/msm_zsl/vx6953.h create mode 100644 drivers/media/video/msm_zsl/vx6953_reg.c create mode 100644 drivers/media/video/msm_zsl/vx6953_reg_v4l2.c create mode 100644 drivers/media/video/msm_zsl/vx6953_v4l2.c create mode 100644 drivers/media/video/msm_zsl/vx6953_v4l2.h create mode 100644 drivers/misc/a2220.c create mode 100755 drivers/misc/a2220_firmware.h create mode 100644 drivers/misc/a2220_firmware_i747.h create mode 100644 drivers/misc/a2220_firmware_t999.h create mode 100644 drivers/misc/bh1721.c create mode 100644 drivers/misc/cm36651.c create mode 100644 drivers/misc/fsa9485.c create mode 100644 drivers/misc/inv_mpu/Kconfig create mode 100644 drivers/misc/inv_mpu/Makefile create mode 100755 drivers/misc/inv_mpu/README create mode 100644 drivers/misc/inv_mpu/accel/Kconfig create mode 100644 drivers/misc/inv_mpu/accel/Makefile create mode 100644 drivers/misc/inv_mpu/accel/mpu6050.c create mode 100644 drivers/misc/inv_mpu/accel/mpu6050.h create mode 100644 drivers/misc/inv_mpu/compass/Kconfig create mode 100644 drivers/misc/inv_mpu/compass/Makefile create mode 100644 drivers/misc/inv_mpu/compass/ak8975.c create mode 100644 drivers/misc/inv_mpu/compass/yas530_ext.c create mode 100644 drivers/misc/inv_mpu/compass/yas530_ext.h create mode 100644 drivers/misc/inv_mpu/log.h create mode 100644 drivers/misc/inv_mpu/mldl_cfg.c create mode 100644 drivers/misc/inv_mpu/mldl_cfg.h create mode 100644 drivers/misc/inv_mpu/mldl_print_cfg.c create mode 100644 drivers/misc/inv_mpu/mldl_print_cfg.h create mode 100644 drivers/misc/inv_mpu/mlsl-kernel.c create mode 100644 drivers/misc/inv_mpu/mlsl.h create mode 100644 drivers/misc/inv_mpu/mltypes.h create mode 100644 drivers/misc/inv_mpu/mpu-dev.c create mode 100644 drivers/misc/inv_mpu/mpu-dev.h create mode 100644 drivers/misc/inv_mpu/mpu6050b1.h create mode 100644 drivers/misc/inv_mpu/mpuirq.c create mode 100644 drivers/misc/inv_mpu/mpuirq.h create mode 100644 drivers/misc/inv_mpu/slaveirq.c create mode 100644 drivers/misc/inv_mpu/slaveirq.h create mode 100644 drivers/misc/inv_mpu/timerirq.c create mode 100644 drivers/misc/inv_mpu/timerirq.h create mode 100644 drivers/misc/pn544.c create mode 100644 drivers/misc/sec_jack.c create mode 100644 drivers/misc/sec_misc.c create mode 100644 drivers/misc/sec_param.c create mode 100644 drivers/misc/stmpe811.c create mode 100644 drivers/motor/Kconfig create mode 100644 drivers/motor/Makefile create mode 100644 drivers/motor/VibeOSKernelLinuxHRTime.c create mode 100644 drivers/motor/immvibespi.c create mode 100644 drivers/motor/max77693_haptic.c create mode 100644 drivers/motor/tspdrv.c create mode 100644 drivers/motor/tspdrv.h create mode 100755 drivers/net/wireless/bcmdhd/bcmsdspi_linux.c create mode 100755 drivers/net/wireless/bcmdhd/bcmspibrcm.c create mode 100644 drivers/net/wireless/bcmdhd/dhd_custom_sec.c create mode 100755 drivers/net/wireless/bcmdhd/dhd_sec_feature.h mode change 100644 => 100755 drivers/net/wireless/bcmdhd/include/Makefile delete mode 100644 drivers/net/wireless/bcmdhd/include/bcm_android_types.h delete mode 100644 drivers/net/wireless/bcmdhd/include/rwl_wifi.h delete mode 100644 drivers/net/wireless/bcmdhd/include/usbrdl.h delete mode 100644 drivers/net/wireless/bcmdhd/include/wlc_clm_rates.h delete mode 100644 drivers/net/wireless/bcmdhd/include/wlc_extlog_idstr.h create mode 100644 drivers/net/wireless/bcmdhd/wl_roam.c create mode 100644 drivers/net/wireless/btlock/Kconfig create mode 100644 drivers/net/wireless/btlock/Makefile create mode 100644 drivers/net/wireless/btlock/btlock.c create mode 100644 drivers/power/pm8921-sec-charger.c create mode 100644 drivers/power/sec_battery.c create mode 100644 drivers/power/smb347_charger.c create mode 100644 drivers/sensors/Kconfig create mode 100644 drivers/sensors/Makefile create mode 100644 drivers/sensors/core/Kconfig create mode 100644 drivers/sensors/core/Makefile create mode 100644 drivers/sensors/core/sensors_core.c create mode 100644 drivers/video/msm/cmc624.h create mode 100644 drivers/video/msm/cmc624_sysfs.c create mode 100644 drivers/video/msm/mdp4_video_enhance.c create mode 100644 drivers/video/msm/mdp4_video_enhance.h create mode 100644 drivers/video/msm/mdp4_video_tuning.h create mode 100644 drivers/video/msm/mhl_v2/Kconfig create mode 100644 drivers/video/msm/mhl_v2/Makefile create mode 100644 drivers/video/msm/mhl_v2/sii9234.c create mode 100644 drivers/video/msm/mhl_v2/sii9234_driver.h create mode 100644 drivers/video/msm/mipi_samsung_esd_refresh.c create mode 100644 drivers/video/msm/mipi_samsung_esd_refresh.h create mode 100644 drivers/video/msm/mipi_samsung_oled.c create mode 100644 drivers/video/msm/mipi_samsung_oled.h create mode 100644 drivers/video/msm/mipi_samsung_oled_cmd_qhd_pt.c create mode 100644 drivers/video/msm/mipi_samsung_oled_video_hd_pt.c create mode 100644 drivers/video/msm/mipi_samsung_oled_video_wvga_pt.c create mode 100644 drivers/video/msm/mipi_samsung_tft_video_wxga_pt.c create mode 100644 drivers/video/msm/samsung_cmc624.c create mode 100644 drivers/video/msm/samsung_cmc624.h create mode 100644 drivers/video/msm/samsung_cmc624_tune.h create mode 100644 drivers/video/msm/smart_dimming.h create mode 100644 drivers/video/msm/smart_mtp_2p2_gamma.h create mode 100644 drivers/video/msm/smart_mtp_s6e8aa0x01.c create mode 100644 drivers/video/msm/smart_mtp_s6e8aa0x01.h create mode 100644 include/linux/charging_temperature_data.h create mode 100644 include/linux/i2c/cm36651.h create mode 100644 include/linux/i2c/cypress_touchkey.h create mode 100644 include/linux/i2c/fsa9485.h create mode 100644 include/linux/input/bmp180.h create mode 100644 include/linux/mfd/pm8xxx/pm8921-sec-charger.h create mode 100644 include/linux/mfd/wcd9310/Kbuild create mode 100644 include/linux/mfd/wcd9310/core.h create mode 100644 include/linux/mfd/wcd9310/pdata.h create mode 100644 include/linux/mfd/wcd9310/registers.h create mode 100644 include/linux/mpu.h create mode 100644 include/linux/mpu_411.h create mode 100644 include/linux/platform_data/mms_ts.h create mode 100644 include/linux/pn544.h create mode 100644 include/linux/sec_battery.h create mode 100644 include/linux/sec_jack.h create mode 100644 include/linux/sec_param.h create mode 100644 include/linux/sii9234.h create mode 100644 include/linux/sii9234_rcp.h create mode 100644 include/linux/smb347_charger.h create mode 100644 include/linux/vibrator.h create mode 100644 include/sound/a2220.h create mode 100644 include/sound/soc-dsp.h create mode 100644 include/trace/trace_msm_low_power.h create mode 100644 sound/soc/msm/msm8960-d2.c diff --git a/Makefile b/Makefile index 75b36ae3c7d..5b4a18f824b 100644 --- a/Makefile +++ b/Makefile @@ -192,8 +192,8 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ # Default value for CROSS_COMPILE is not to prefix executables # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile export KBUILD_BUILDHOST := $(SUBARCH) -ARCH ?= $(SUBARCH) -CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) +ARCH ?= arm +CROSS_COMPILE ?= /opt/toolchains/arm-eabi-4.4.3/bin/arm-eabi- # Architecture as present in compile.h UTS_MACHINE := $(ARCH) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d7ebcfeca2c..cafc58945fa 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2224,6 +2224,36 @@ config ATAGS_PROC Should the atags used to boot the kernel be exported in an "atags" file in procfs. Useful with kexec. +config KEXEC_HARDBOOT + bool "Support hard booting to a kexec kernel" + depends on KEXEC + help + Allows hard booting (i.e., with a full hardware reboot) to a kernel + previously loaded in memory by kexec. This works around the problem of + soft-booted kernel hangs due to improper device shutdown and/or + reinitialization. Support is comprised of two components: + + First, a "hardboot" flag is added to the kexec syscall to force a hard + reboot in relocate_new_kernel() (which requires machine-specific assembly + code). This also requires the kexec userspace tool to load the kexec'd + kernel in memory region left untouched by the bootloader (i.e., not + explicitly cleared and not overwritten by the boot kernel). Just prior + to reboot, the kexec kernel arguments are stashed in a machine-specific + memory page that must also be preserved. Note that this hardboot page + need not be reserved during regular kernel execution. + + Second, the zImage decompresor of the boot (bootloader-loaded) kernel is + modified to check the hardboot page for fresh kexec arguments, and if + present, attempts to jump to the kexec'd kernel preserved in memory. + + Note that hardboot support is only required in the boot kernel and any + kernel capable of performing a hardboot kexec. It is _not_ required by a + kexec'd kernel. + +config KEXEC_HB_PAGE_ADDR + hex "Kexec hardboot page address" + depends on KEXEC_HARDBOOT + config CRASH_DUMP bool "Build kdump crash kernel (EXPERIMENTAL)" depends on EXPERIMENTAL diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index bb267562e7e..b3f5924644c 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -139,6 +139,9 @@ endif ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) LDFLAGS_vmlinux += --be8 endif +ifneq ($(PARAMS_PHYS),) +LDFLAGS_vmlinux += --defsym params_phys=$(PARAMS_PHYS) +endif # ? LDFLAGS_vmlinux += -p # Report unresolved symbol references diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 64a6d6f8d29..997a9f64119 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -9,6 +9,11 @@ * published by the Free Software Foundation. */ #include +#include + +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#endif /* * Debugging stuff @@ -133,7 +138,31 @@ start: .word _edata @ zImage end address THUMB( .thumb ) 1: mov r7, r1 @ save architecture ID - mov r8, r2 @ save atags pointer + teq r0, #0 @ Check for kexec_boot_atags. + movne r8, r0 @ Save kexec_boot_tags. + moveq r8, r2 @ save atags pointer + +#ifdef CONFIG_KEXEC_HARDBOOT + /* Check hardboot page for a kexec kernel. */ + ldr r3, =KEXEC_HB_PAGE_ADDR + ldr r0, [r3] + ldr r1, =KEXEC_HB_PAGE_MAGIC + teq r0, r1 + bne not_booting_other + + /* Clear hardboot page magic to avoid boot loop. */ + mov r0, #0 + str r0, [r3] + + /* Load boot arguments and jump to kexec kernel. */ + ldr r0, [r3, #12] @ kexec_boot_atags (r2: boot_atags) + ldr r1, [r3, #8] @ kexec_mach_type + ldr pc, [r3, #4] @ kexec_start_address + + .ltorg + +not_booting_other: +#endif #ifndef __ARM_ARCH_2__ /* @@ -456,6 +485,41 @@ not_relocated: mov r0, #0 add r2, sp, #0x10000 @ 64k max mov r3, r7 bl decompress_kernel + +/* Copy the kernel tagged list (atags): + * + * The kernel requires atags to be located in a direct-mapped region, + * usually below the kernel in the first 16 kB of RAM. If they're above + * (the start of) the kernel, they need to be copied to a suitable + * location, e.g., the machine-defined params_phys. + * + * Still need to make sure that the copied tags don't overwrite either the + * kernel or decompressor code (or rather, the remainder of it since + * everything up to here has already been executed). + * + * r4: zreladdr (kernel start) + * r8: atags */ + + /* Don't need to copy atags if they're already below the kernel. */ + cmp r8, r4 + blo call_kernel + + /* r1: min(zreladdr, pc) */ + mov r1, pc + cmp r4, r1 + movlo r1, r4 + + /* Compute max space for atags, if max <= 0 don't copy. */ + ldr r0, =params_phys @ dest + subs r2, r1, r0 @ max = min(zreladdr, pc) - dest + bls call_kernel + + /* Copy atags to params_phys. */ + mov r1, r8 @ src + bl copy_atags + mov r8, r0 + +call_kernel: bl cache_clean_flush bl cache_off mov r0, #0 @ must be zero @@ -464,6 +528,8 @@ not_relocated: mov r0, #0 ARM( mov pc, r4 ) @ call kernel THUMB( bx r4 ) @ entry point is always ARM + .ltorg + .align 2 .type LC0, #object LC0: .word LC0 @ r1 @@ -581,11 +647,16 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size * bits for the RAM area only. */ mov r0, r3 +#if defined(PLAT_PHYS_OFFSET) && defined(END_MEM) + ldr r9, =PLAT_PHYS_OFFSET @ start of RAM + ldr r10, =END_MEM @ end of RAM +#else mov r9, r0, lsr #18 mov r9, r9, lsl #18 @ start of RAM add r10, r9, #0x10000000 @ a reasonable RAM size - mov r1, #0x12 @ XN|U + section mapping - orr r1, r1, #3 << 10 @ AP=11 +#endif + mov r1, #0x12 + orr r1, r1, #3 << 10 add r2, r3, #16384 1: cmp r1, r9 @ if virt > start of RAM cmphs r10, r1 @ && end of RAM > virt diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index 8e2a8fca5ed..112edaedf35 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -21,6 +21,8 @@ unsigned int __machine_arch_type; #include /* for inline */ #include #include +#include +#include static void putstr(const char *ptr); extern void error(char *x); @@ -152,3 +154,25 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, else putstr(" done, booting the kernel.\n"); } + +const struct tag *copy_atags(struct tag *dest, const struct tag *src, + size_t max) +{ + struct tag *tag; + size_t size; + + /* Find the last tag (ATAG_NONE). */ + for_each_tag(tag, (struct tag *)src) + continue; + + /* Include the last tag in copy. */ + size = (char *)tag - (char *)src + sizeof(struct tag_header); + + /* If there's not enough room, just use original and hope it works. */ + if (size > max) + return src; + + memcpy(dest, src, size); + + return dest; +} diff --git a/arch/arm/configs/cyanogen_d2-r530_defconfig b/arch/arm/configs/cyanogen_d2-r530_defconfig new file mode 100644 index 00000000000..db712bd9c2b --- /dev/null +++ b/arch/arm/configs/cyanogen_d2-r530_defconfig @@ -0,0 +1,3699 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARM_TICKET_LOCKS=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x80200000 +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-cyanogenmod" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_CGROUP_MEM_RES_CTLR is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +CONFIG_PERF_COUNTERS=y +CONFIG_DEBUG_PERF_USE_VMALLOC=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_TEST=m +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM7X01A is not set +# CONFIG_ARCH_MSM7X25 is not set +# CONFIG_ARCH_MSM7X27 is not set +# CONFIG_ARCH_MSM7X30 is not set +# CONFIG_ARCH_QSD8X50 is not set +# CONFIG_ARCH_MSM8X60 is not set +CONFIG_ARCH_MSM8960=y +# CONFIG_ARCH_MSM8930 is not set +CONFIG_ARCH_APQ8064=y +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_MPQ8092 is not set +# CONFIG_ARCH_MSM8226 is not set +# CONFIG_ARCH_FSM9XXX is not set +# CONFIG_ARCH_MSM9615 is not set +# CONFIG_ARCH_MSM8625 is not set +# CONFIG_ARCH_MSM9625 is not set +CONFIG_MSM_SOC_REV_NONE=y +# CONFIG_MSM_SOC_REV_A is not set +CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y +CONFIG_ARCH_MSM_KRAIT=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_KRAITMP=y +CONFIG_MSM_KRAIT_WFE_FIXUP=y +CONFIG_MSM_RPM=y +# CONFIG_MSM_RPM_SMD is not set +CONFIG_MSM_MPM=y +CONFIG_MSM_XO=y +CONFIG_MSM_REMOTE_SPINLOCK_SFPB=y + +# +# MSM Board Selection +# +# CONFIG_MACH_MSM8960_CDP is not set +# CONFIG_MACH_MSM8960_MTP is not set +# CONFIG_MACH_MSM8960_FLUID is not set +# CONFIG_MACH_MSM8960_LIQUID is not set +# CONFIG_MACH_APQ8064_CDP is not set +# CONFIG_MACH_APQ8064_MTP is not set +# CONFIG_MACH_APQ8064_LIQUID is not set +# CONFIG_MACH_MPQ8064_CDP is not set +# CONFIG_MACH_MPQ8064_HRD is not set +# CONFIG_MACH_MPQ8064_DTV is not set +# CONFIG_MACH_MSM_DUMMY is not set +CONFIG_MACH_M2=y +# CONFIG_MACH_M2_ATT is not set +# CONFIG_MACH_M2_SPR is not set +CONFIG_MACH_M2_VZW=y + +# +# LGE Board Selection +# +CONFIG_BOARD_HEADER_FILE="" +# CONFIG_MACH_APQ8064_MAKO is not set +# CONFIG_MACH_LGE_DUMMY is not set + +# +# LGE Specific Patches +# +# CONFIG_LGE_CRASH_HANDLER is not set +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_HAVE_END_MEM=y +CONFIG_END_MEM=0xffffffff +# CONFIG_KERNEL_MSM_CONTIG_MEM_REGION is not set +CONFIG_KERNEL_PMEM_EBI_REGION=y +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +CONFIG_MSM_HAS_DEBUG_UART_HS=y +CONFIG_DEBUG_MSM8960_UART=y +# CONFIG_DEBUG_APQ8064_UART is not set +CONFIG_MSM7X00A_USE_GP_TIMER=y +# CONFIG_MSM7X00A_USE_DG_TIMER is not set +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_HTC_HEADSET is not set +# CONFIG_HTC_PWRSINK is not set +# CONFIG_MSM_FIQ_SUPPORT is not set +# CONFIG_MSM_SERIAL_DEBUGGER is not set +# CONFIG_MSM_PROC_COMM is not set +CONFIG_MSM_SMD=y +# CONFIG_MSM_SMD_PKG3 is not set +CONFIG_MSM_SMD_PKG4=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_N_WAY_SMD=y +CONFIG_MSM_N_WAY_SMSM=y +CONFIG_MSM_RESET_MODEM=m +CONFIG_MSM_SMD_LOGGING=y +# CONFIG_MSM_IPC_LOGGING is not set +CONFIG_MSM_SMD_NMEA=y +# CONFIG_MSM_HSIC_TTY is not set +CONFIG_MSM_SMD_TTY=y +CONFIG_MSM_SMD_QMI=y +CONFIG_MSM_SMD_PKT=y +# CONFIG_MSM_DSPS is not set +# CONFIG_MSM_ONCRPCROUTER is not set +CONFIG_MSM_IPC_ROUTER=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +# CONFIG_MSM_DALRPC is not set +# CONFIG_MSM_CPU_FREQ_SET_MIN_MAX is not set +# CONFIG_MSM_AVS_HW is not set +# CONFIG_MSM_HW3D is not set +CONFIG_AMSS_7X25_VERSION_2009=y +# CONFIG_AMSS_7X25_VERSION_2008 is not set +CONFIG_RTAC=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +CONFIG_MSM_DMA_TEST=m +CONFIG_WIFI_CONTROL_FUNC=y +# CONFIG_WIFI_MEM_PREALLOC is not set +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +CONFIG_MSM_RPM_REGULATOR=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +# CONFIG_MSM_PIL_MODEM is not set +# CONFIG_MSM_PIL_QDSP6V3 is not set +CONFIG_MSM_PIL_QDSP6V4=y +# CONFIG_MSM_PIL_LPASS_QDSP6V5 is not set +# CONFIG_MSM_PIL_MSS_QDSP6V5 is not set +CONFIG_MSM_PIL_RIVA=y +CONFIG_MSM_PIL_TZAPPS=y +# CONFIG_MSM_PIL_DSPS is not set +CONFIG_MSM_PIL_VIDC=y +# CONFIG_MSM_PIL_VENUS is not set +# CONFIG_MSM_PIL_GSS is not set +# CONFIG_MSM_PIL_PRONTO is not set +CONFIG_MSM_SCM=y +CONFIG_MSM_MODEM_8960=y +CONFIG_MSM_LPASS_8960=y +# CONFIG_MSM_GSS_SSR_8064 is not set +CONFIG_MSM_BUSPM_DEV=m +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +# CONFIG_MSM_RPM_RBCPR_STATS_LOG is not set +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_MSM_GPIOMUX=y +CONFIG_MSM_NATIVE_RESTART=y +CONFIG_MSM_PM8X60=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y +CONFIG_MSM_WATCHDOG=y +# CONFIG_MSM_WATCHDOG_V2 is not set +# CONFIG_MSM_MEMORY_DUMP is not set +CONFIG_MSM_DLOAD_MODE=y +CONFIG_MSM_JTAG=y +# CONFIG_MSM_SLEEP_STATS_DEVICE is not set +CONFIG_MSM_RUN_QUEUE_STATS=y +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_BT_BCM4334=y +# CONFIG_MSM_FAKE_BATTERY is not set +CONFIG_MSM_QDSP6_APR=y +# CONFIG_MSM_QDSP6_APRV2 is not set +CONFIG_MSM_QDSP6_CODECS=y +# CONFIG_MSM_QDSP6V2_CODECS is not set +CONFIG_MSM_AUDIO_QDSP6=y +# CONFIG_MSM_AUDIO_QDSP6V2 is not set +# CONFIG_MSM_ULTRASOUND is not set +# CONFIG_MSM_SPM_V1 is not set +CONFIG_MSM_SPM_V2=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MULTIMEDIA_USE_ION=y +# CONFIG_MSM_OCMEM is not set +# CONFIG_MSM_RTB is not set +# CONFIG_MSM_EBI_ERP is not set +CONFIG_MSM_CACHE_ERP=y +CONFIG_MSM_L1_ERR_PANIC=y +# CONFIG_MSM_L1_ERR_LOG is not set +# CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS is not set +# CONFIG_MSM_L2_ERP_1BIT_PANIC is not set +CONFIG_MSM_L2_ERP_2BIT_PANIC=y +CONFIG_MSM_DCVS=y +# CONFIG_MSM_CPR is not set +CONFIG_HAVE_ARCH_HAS_CURRENT_TIMER=y +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_HSIC_SYSMON is not set +CONFIG_MSM_CPU_PWRCTL=y + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_VCM is not set +# CONFIG_STRICT_MEMORY_RWX is not set +CONFIG_ARM_NR_BANKS=8 +# CONFIG_RESERVE_FIRST_PAGE is not set +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_KSAPI is not set +CONFIG_ARM_GIC=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI is not set +# CONFIG_PCI_SYSCALL is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_ARM_ARCH_TIMER is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_VMALLOC_RESERVE=0x19000000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CLEANCACHE=y +# CONFIG_ARCH_MEMORY_PROBE is not set +# CONFIG_ARCH_MEMORY_REMOVE is not set +# CONFIG_ENABLE_DMM is not set +# CONFIG_FIX_MOVABLE_ZONE is not set +CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0=y +# CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG is not set +# CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE is not set +CONFIG_HOLES_IN_ZONE=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_SECCOMP is not set +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set +CONFIG_CP_ACCESS=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y +CONFIG_KEXEC_HARDBOOT=y +CONFIG_KEXEC_HB_PAGE_ADDR=0xfffff000 +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_FREQ_MSM=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +# CONFIG_CONSOLE_EARLYSUSPEND is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +CONFIG_NET_SCH_INGRESS=y +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +CONFIG_BT_HCISMD=y +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_IBS is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_MSM_SLEEP is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_MSM_BT_POWER is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_CFG80211=y +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +CONFIG_RFKILL_LEDS=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_BCM2079X is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_GENLOCK=y +CONFIG_GENLOCK_MISCDEVICE=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +# CONFIG_CMA is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +CONFIG_ANDROID_PMEM=y +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +# CONFIG_TSIF is not set +# CONFIG_TSPP is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_PMIC8XXX_VIBRATOR is not set +# CONFIG_ANDROID_VIBRATOR is not set +# CONFIG_TOUCHSENSE_VIBRATOR is not set +# CONFIG_PMIC8XXX_NFC is not set +# CONFIG_PMIC8XXX_UPL is not set +CONFIG_QSEECOM=y +# CONFIG_QFP_FUSE is not set +# CONFIG_BU52031NVX is not set +CONFIG_NFC_PN544=y +CONFIG_SEC_MISC=y +CONFIG_USB_SWITCH_FSA9485=y +CONFIG_MPU_411_ENABLE=y +# CONFIG_YAS_532_ENABLE is not set +# CONFIG_OPTICAL_GP2A is not set +# CONFIG_OPTICAL_GP2AP020A00F is not set +# CONFIG_OPTICAL_TAOS_TRITON is not set +# CONFIG_OPTICAL_TAOS_TMD2672X is not set +# CONFIG_SENSORS_AL3201 is not set +CONFIG_SENSORS_CM36651=y +CONFIG_VP_A2220=y +# CONFIG_ADC_STMPE811 is not set +CONFIG_SAMSUNG_JACK=y +# CONFIG_SAMSUNG_JACK_GNDLDET is not set +# CONFIG_OPTICAL_BH1721 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +CONFIG_MPU_SENSORS_TIMERIRQ_411=y +CONFIG_INV_SENSORS_411=y +# CONFIG_MPU_SENSORS_MPU3050_411 is not set +# CONFIG_MPU_SENSORS_MPU6050A2_411 is not set +CONFIG_MPU_SENSORS_MPU6050B1_411=y +CONFIG_INV_SENSORS_ACCELEROMETERS=y +CONFIG_MPU_SENSORS_MPU6050_ACCEL_411=y +CONFIG_INV_SENSORS_COMPASS=y +CONFIG_MPU_SENSORS_AK8975_411=y +# CONFIG_MPU_SENSORS_AK8972_411 is not set +# CONFIG_MPU_SENSORS_MMC314X_411 is not set +# CONFIG_MPU_SENSORS_AMI30X_411 is not set +# CONFIG_MPU_SENSORS_AMI306_411 is not set +# CONFIG_MPU_SENSORS_HMC5883_411 is not set +# CONFIG_MPU_SENSORS_LSM303DLX_M_411 is not set +# CONFIG_MPU_SENSORS_MMC314XMS_411 is not set +# CONFIG_MPU_SENSORS_YAS530_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD002B_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD004A_411 is not set +# CONFIG_MPU_USERSPACE_DEBUG is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +# CONFIG_SLIMPORT_ANX7808 is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=y +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_ENC28J60 is not set +# CONFIG_MSM_RMNET is not set +CONFIG_MSM_RMNET_BAM=y +# CONFIG_QFEC is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_SLIP=y +CONFIG_SLHC=y +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_SMART is not set +CONFIG_SLIP_MODE_SLIP6=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_LIBRA_SDIOIF is not set +# CONFIG_ATH6K_LEGACY_EXT is not set +# CONFIG_WCNSS_CORE is not set +# CONFIG_ATH_COMMON is not set +CONFIG_BCMDHD=m +# CONFIG_BCM4330 is not set +CONFIG_BCM4334=y +# CONFIG_BCM43241 is not set +CONFIG_BCMDHD_FW_PATH="/system/etc/wifi/bcmdhd_sta.bin_b2" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/nvram_net.txt" +# CONFIG_DHD_USE_STATIC_BUF is not set +# CONFIG_DHD_USE_SCHED_SCAN is not set +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_WLAN_REGION_CODE=100 +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PMIC8XXX is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_QCIKBD is not set +CONFIG_KEYBOARD_CYPRESS_TOUCH_236=y +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_QCITP is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +# CONFIG_JOYSTICK_XPAD_FF is not set +# CONFIG_JOYSTICK_XPAD_LEDS is not set +# CONFIG_TOUCHDISC_VTD518_SHINETSU is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +CONFIG_TOUCHSCREEN_MMS144=y +# CONFIG_TOUCHSCREEN_MMS136 is not set +# CONFIG_TOUCHSCREEN_MMS136_TABLET is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_MSM_LEGACY is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8C_TS is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC is not set +# CONFIG_TOUCHSCREEN_FT5X06 is not set +# CONFIG_TOUCHSCREEN_LGE_COMMON is not set +# CONFIG_TOUCHSCREEN_LGE_SYNAPTICS is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +CONFIG_INPUT_BMP180=y +# CONFIG_INPUT_PM8XXX_VIBRATOR is not set +CONFIG_INPUT_PMIC8XXX_PWRKEY=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BOSCH_BMA150 is not set +# CONFIG_STM_LIS3DH is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_VT_CONSOLE is not set +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_N_SMUX is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MSM=y +# CONFIG_SERIAL_MSM_CONSOLE is not set +CONFIG_SERIAL_MSM_HS=y +# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_MSM_SMD is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# SDIO support for DIAG +# + +# +# HSIC support for DIAG +# +CONFIG_DIAG_BRIDGE_CODE=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_MSM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +CONFIG_MSM_ROTATOR=y +# CONFIG_MMC_GENERIC_CSDIO is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_MSM is not set +CONFIG_I2C_QUP=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_QUP=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=m +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPMI is not set +CONFIG_SLIMBUS=y +# CONFIG_SLIMBUS_MSM_CTRL is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_MSM_V1 is not set +CONFIG_GPIO_MSM_V2=y +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_FSM9XXX is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_SX150X=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_GPIO_PM8XXX=y +CONFIG_GPIO_PM8XXX_MPP=y +# CONFIG_GPIO_PM8XXX_RPC is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +CONFIG_BATTERY_MAX17040=y +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_BATTERY_MSM is not set +# CONFIG_BATTERY_MSM8X60 is not set +# CONFIG_ISL9519_CHARGER is not set +# CONFIG_SMB137B_CHARGER is not set +# CONFIG_SMB349_CHARGER is not set +# CONFIG_BATTERY_BQ27520 is not set +# CONFIG_BATTERY_BQ27541 is not set +CONFIG_PM8921_CHARGER=y +CONFIG_PM8XXX_CCADC=y +# CONFIG_LTC4088_CHARGER is not set +# CONFIG_PM8921_BMS is not set +CONFIG_PM8921_SEC_CHARGER=y +CONFIG_BATTERY_CTIA=y +CONFIG_BATTERY_SEC=y +CONFIG_SAMSUNG_LPM_MODE=y +CONFIG_WIRELESS_CHARGING=y +# CONFIG_BATTERY_SAMSUNG_STRETTO is not set +# CONFIG_BATTERY_BCL is not set +CONFIG_CHARGER_SMB347=y +# CONFIG_WIRELESS_CHARGER is not set +# CONFIG_BATTERY_TEMP_CONTROL is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +CONFIG_SENSORS_PM8XXX_ADC=y +# CONFIG_SENSORS_EPM_ADC is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_MSM_POPMEM is not set +# CONFIG_THERMAL_TSENS is not set +CONFIG_THERMAL_TSENS8960=y +# CONFIG_THERMAL_TSENS8974 is not set +CONFIG_THERMAL_PM8XXX=y +CONFIG_THERMAL_MONITOR=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_PMIC8058 is not set +# CONFIG_PMIC8901 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +CONFIG_MFD_PM8XXX=y +CONFIG_MFD_PM8921_CORE=y +# CONFIG_MFD_PM8821_CORE is not set +# CONFIG_MFD_PM8018_CORE is not set +CONFIG_MFD_PM8038_CORE=y +CONFIG_MFD_PM8XXX_IRQ=y +# CONFIG_MFD_PM8821_IRQ is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +CONFIG_MFD_PM8XXX_DEBUG=y +CONFIG_MFD_PM8XXX_PWM=y +CONFIG_MFD_PM8XXX_MISC=y +CONFIG_MFD_PM8XXX_SPK=y +CONFIG_MFD_PM8XXX_BATT_ALARM=y +# CONFIG_WCD9304_CODEC is not set +CONFIG_WCD9310_CODEC=y +# CONFIG_WCD9320_CODEC is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_GPIO=y +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +CONFIG_REGULATOR_MAX8952=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_PM8XXX=y +CONFIG_REGULATOR_MSM_GPIO=y +# CONFIG_REGULATOR_STUB is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +# CONFIG_VIDEO_V4L2_SUBDEV_API is not set +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +CONFIG_RC_CORE=y +CONFIG_LIRC=y +# CONFIG_USER_RC_INPUT is not set +CONFIG_RC_MAP=y +CONFIG_IR_NEC_DECODER=y +CONFIG_IR_RC5_DECODER=y +CONFIG_IR_RC6_DECODER=y +CONFIG_IR_JVC_DECODER=y +CONFIG_IR_SONY_DECODER=y +CONFIG_IR_RC5_SZ_DECODER=y +CONFIG_IR_SANYO_DECODER=y +CONFIG_IR_MCE_KBD_DECODER=y +CONFIG_IR_LIRC_CODEC=y +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MC44S803=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_IR_I2C=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# MPEG video encoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# +CONFIG_MSM_VCAP=y +CONFIG_V4L_USB_DRIVERS=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set + +# +# Qualcomm MSM Camera And Video +# +CONFIG_MSM_CAMERA=y +# CONFIG_MSM_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_V4L2=y + +# +# Camera Sensor Selection +# +# CONFIG_ISX012 is not set +CONFIG_S5C73M3=y +CONFIG_S5K6A3YX=y +# CONFIG_S5K8AAY is not set +# CONFIG_MT9M114 is not set +# CONFIG_IMX074_ACT is not set +# CONFIG_S5K4E1 is not set +CONFIG_MSM_CAMERA_FLASH_SC628A=y +# CONFIG_IMX072 is not set +CONFIG_MSM_CAMERA_FLASH=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_ACTUATOR=y +CONFIG_MSM_GEMINI=y +CONFIG_QUP_EXCLUSIVE_TO_CAMERA=y + +# +# Camera Sensor Selection +# +# CONFIG_IMX074 is not set +# CONFIG_OV5647 is not set +# CONFIG_MSM_CAMERA_FLASH_TPS61310 is not set +# CONFIG_OV2720 is not set +# CONFIG_OV8825 is not set +# CONFIG_MSM_EEPROM is not set +# CONFIG_IMX074_EEPROM is not set +# CONFIG_IMX091_EEPROM is not set +CONFIG_MSM_MERCURY=y +# CONFIG_MSM_CAM_IRQ_ROUTER is not set +# CONFIG_MSM_CPP is not set +# CONFIG_MSM_CCI is not set +CONFIG_MSM_CSI20_HEADER=y +# CONFIG_MSM_CSI30_HEADER is not set +# CONFIG_MSM_CSIPHY is not set +# CONFIG_MSM_CSID is not set +# CONFIG_MSM_CSI2_REGISTER is not set +# CONFIG_MSM_ISPIF is not set +# CONFIG_S5K3L1YX is not set +# CONFIG_IMX091 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +# CONFIG_OV7692 is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_MSM_WFD=y +# CONFIG_RADIO_ADAPTERS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set +CONFIG_MSM_KGSL_2D=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 +CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24 +CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y +# CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +CONFIG_FB_VIRTUAL=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_VIDEO_MHL_V2=y +CONFIG_MHL_D3_SUPPORT=y +CONFIG_MHL_NEW_CBUS_MSC_CMD=y +CONFIG_MSM_VIDC=y +CONFIG_MSM_VIDC_1080P=y +CONFIG_MSM_VIDC_VENC=y +CONFIG_MSM_VIDC_VDEC=y +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_LCDC_HW=y +CONFIG_FB_MSM_TRIPLE_BUFFER=y +CONFIG_FB_MSM_MDP_HW=y +# CONFIG_FB_MSM_MDP22 is not set +# CONFIG_FB_MSM_MDP30 is not set +# CONFIG_FB_MSM_MDP31 is not set +CONFIG_FB_MSM_MDP40=y +# CONFIG_FB_MSM_MDSS is not set +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_EBI2 is not set +# CONFIG_FB_MSM_MDDI is not set +CONFIG_FB_MSM_MIPI_DSI=y +# CONFIG_FB_MSM_LCDC is not set +# CONFIG_FB_MSM_LVDS is not set +CONFIG_FB_MSM_OVERLAY=y +CONFIG_FB_MSM_DTV=y +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_TVOUT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA is not set +# CONFIG_FB_MSM_MDDI_ORISE is not set +# CONFIG_FB_MSM_MDDI_QUICKVX is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL is not set +# CONFIG_FB_MSM_MIPI_DSI_TOSHIBA is not set +# CONFIG_FB_MSM_MIPI_DSI_LGIT is not set +# CONFIG_FB_MSM_MIPI_DSI_RENESAS is not set +# CONFIG_FB_MSM_MIPI_DSI_SIMULATOR is not set +# CONFIG_FB_MSM_MIPI_DSI_NOVATEK is not set +# CONFIG_FB_MSM_MIPI_DSI_ORISE is not set +CONFIG_FB_MSM_MIPI_DSI_SAMSUNG_OLED=y +CONFIG_SAMSUNG_CMC624=y +# CONFIG_FB_MSM_LCDC_ST15_WXGA is not set +# CONFIG_FB_MSM_LCDC_ST15_PANEL is not set +# CONFIG_FB_MSM_LCDC_PRISM_WVGA is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335 is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT is not set +# CONFIG_FB_MSM_LCDC_NT35582_WVGA is not set +# CONFIG_FB_MSM_LCDC_WXGA is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO is not set +CONFIG_FB_MSM_NO_MDP_PIPE_CTRL=y +CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y +CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y +CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y +# CONFIG_FB_MSM_LCDC_PRISM_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_NT35582_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM is not set +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PRISM_WVGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA is not set +# CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128 is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF is not set +# CONFIG_FB_MSM_HDMI_AS_PRIMARY is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +CONFIG_MIPI_SAMSUNG_ESD_REFRESH=y +CONFIG_FB_MSM_EXT_INTERFACE_COMMON=y +CONFIG_FB_MSM_HDMI_COMMON=y +CONFIG_FB_MSM_HDMI_3D=y +# CONFIG_FB_MSM_HDMI_ADV7520_PANEL is not set +CONFIG_FB_MSM_HDMI_MSM_PANEL=y +CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT=y +# CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT is not set +# CONFIG_FB_MSM_HDMI_MHL_9244 is not set +# CONFIG_FB_MSM_HDMI_MHL_8334 is not set +# CONFIG_FB_MSM_TVOUT_NTSC_M is not set +# CONFIG_FB_MSM_TVOUT_NTSC_J is not set +# CONFIG_FB_MSM_TVOUT_PAL_BDGHIN is not set +# CONFIG_FB_MSM_TVOUT_PAL_M is not set +# CONFIG_FB_MSM_TVOUT_PAL_N is not set +CONFIG_FB_MSM_TVOUT_NONE=y +# CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565 is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888 is not set +CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888=y +# CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_AMS369FG06 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LM3530 is not set +# CONFIG_BACKLIGHT_LM3533 is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y + +# +# MSM SoC Audio support +# +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO=y +CONFIG_SND_SOC_MSM_QDSP6_INTF=y +# CONFIG_SND_SOC_MSM_QDSP6V2_INTF is not set +CONFIG_SND_SOC_VOICE=y +CONFIG_SND_SOC_QDSP6=y +# CONFIG_SND_SOC_QDSP6V2 is not set +CONFIG_SND_SOC_MSM8960=y +# CONFIG_SND_SOC_DUAL_AMIC is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WCD9304=y +CONFIG_SND_SOC_WCD9310=y +CONFIG_SND_SOC_CS8427=y +CONFIG_SND_SOC_MSM_STUB=y +# CONFIG_SND_SOC_TPA2028D is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +CONFIG_UHID=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +# CONFIG_HID_ACRUX is not set +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +# CONFIG_HID_PRODIKEYS is not set +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_HID_EMS_FF is not set +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_KEYTOUCH is not set +CONFIG_HID_KYE=y +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +# CONFIG_HID_LCPOWER is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=m +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +# CONFIG_HID_MULTITOUCH is not set +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LCD is not set +# CONFIG_HID_PICOLCD_LEDS is not set +# CONFIG_HID_PRIMAX is not set +CONFIG_HID_ROCCAT=y +# CONFIG_HID_SAITEK is not set +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +# CONFIG_GREENASIA_FF is not set +CONFIG_HID_SMARTJOYPLUS=y +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_HID_TIVO is not set +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WACOM_POWER_SUPPLY is not set +# CONFIG_HID_WIIMOTE is not set +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_MSM=y +# CONFIG_USB_EHCI_MSM_HSIC is not set +# CONFIG_USB_EHCI_MSM_HOST4 is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_PEHCI_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +CONFIG_USB_PRINTER=y +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=y +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +CONFIG_USB_SERIAL_QUALCOMM=y +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +CONFIG_USB_SERIAL_WWAN=y +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_CSVT is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_QCOM_DIAG_BRIDGE=y +# CONFIG_USB_QCOM_DIAG_BRIDGE_TEST is not set +CONFIG_USB_QCOM_MDM_BRIDGE=y +# CONFIG_USB_QCOM_KS_BRIDGE is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +CONFIG_USB_CI13XXX_MSM=y +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +# CONFIG_USB_MSM_72K is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_SUPERSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="" +CONFIG_RMNET_SMD_DATA_CHANNEL="" +CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y +# CONFIG_USB_ANDROID_CDC_ECM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_OTG_WAKELOCK is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_MSM_OTG_72K is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_USB_MSM_OTG=y +# CONFIG_USB_MSM_ACA is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_PERF_PROFILING is not set +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +# CONFIG_MMC_EMBEDDED_SDIO is not set +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +# CONFIG_MMC_BLOCK_BOUNCE is not set +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_BLOCK_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_MSM=y +CONFIG_MMC_MSM_SDC1_SUPPORT=y +CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y +# CONFIG_MMC_MSM_SDC2_SUPPORT is not set +CONFIG_MMC_MSM_SDC3_SUPPORT=y +# CONFIG_MMC_MSM_SDC3_POLLING is not set +# CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC3_WP_SUPPORT is not set +CONFIG_MMC_MSM_SDC4_SUPPORT=y +# CONFIG_MMC_MSM_SDC4_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC5_SUPPORT is not set +CONFIG_MMC_MSM_SPS_SUPPORT=y +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_MSM_PDM is not set +# CONFIG_LEDS_PMIC_MPP is not set +# CONFIG_LEDS_MSM_TRICOLOR is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_CPLD is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +CONFIG_LEDS_PM8XXX=y +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_MSM_PMIC is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set +# CONFIG_LEDS_TRIGGER_SLEEP is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_SWITCH_FSA8008 is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_VIDEO_MHL_TAB_V2 is not set +# CONFIG_MHL_SWING_LEVEL is not set +# CONFIG_ACCESSORY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_MSM is not set +# CONFIG_RTC_DRV_MSM7X00A is not set +CONFIG_RTC_DRV_PM8XXX=y +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +CONFIG_QCACHE=y +# CONFIG_FB_SM7XX is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_PERSISTENT_RAM=y +CONFIG_ANDROID_RAM_CONSOLE=y +# CONFIG_PERSISTENT_TRACER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +# CONFIG_ANDROID_SWITCH is not set +# CONFIG_ANDROID_INTF_ALARM_DEV is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set + +# +# Qualcomm Atheros Prima WLAN module +# +# CONFIG_PRIMA_WLAN is not set + +# +# Qualcomm MSM specific device drivers +# +CONFIG_MSM_SSBI=y +CONFIG_SPS=y +# CONFIG_USB_BAM is not set +CONFIG_SPS_SUPPORT_BAMDMA=y +# CONFIG_SPS_SUPPORT_NDP_BAM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_NEW_SENSORS=y +CONFIG_SENSORS_CORE=y +# CONFIG_BATTERY_SAMSUNG is not set +CONFIG_VIBETONZ=y + +# +# Hardware Spinlock drivers +# +CONFIG_IOMMU_SUPPORT=y +# CONFIG_MSM_IOMMU is not set + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MOBICORE_SUPPORT is not set +CONFIG_MSM_QDSS=y +# CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE is not set +CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_DEBUG_LIST=y +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +CONFIG_SCHED_TRACER=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_DYNAMIC_FTRACE=y +# CONFIG_FUNCTION_PROFILER is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_OLD_MCOUNT=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_RODATA is not set +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_NONE=y +# CONFIG_DEBUG_LL_UART is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_EARLY_PRINTK is not set +CONFIG_PID_IN_CONTEXTIDR=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +CONFIG_KEYS_DEBUG_PROC_KEYS=y +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_QCE40=y +CONFIG_CRYPTO_DEV_QCRYPTO=m +CONFIG_CRYPTO_DEV_QCE=m +CONFIG_CRYPTO_DEV_QCEDEV=m +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set diff --git a/arch/arm/configs/cyanogen_d2att_defconfig b/arch/arm/configs/cyanogen_d2att_defconfig new file mode 100644 index 00000000000..9f456cb87a8 --- /dev/null +++ b/arch/arm/configs/cyanogen_d2att_defconfig @@ -0,0 +1,3699 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARM_TICKET_LOCKS=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x80200000 +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-cyanogenmod" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_CGROUP_MEM_RES_CTLR is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +CONFIG_PERF_COUNTERS=y +CONFIG_DEBUG_PERF_USE_VMALLOC=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_TEST=m +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM7X01A is not set +# CONFIG_ARCH_MSM7X25 is not set +# CONFIG_ARCH_MSM7X27 is not set +# CONFIG_ARCH_MSM7X30 is not set +# CONFIG_ARCH_QSD8X50 is not set +# CONFIG_ARCH_MSM8X60 is not set +CONFIG_ARCH_MSM8960=y +# CONFIG_ARCH_MSM8930 is not set +CONFIG_ARCH_APQ8064=y +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_MPQ8092 is not set +# CONFIG_ARCH_MSM8226 is not set +# CONFIG_ARCH_FSM9XXX is not set +# CONFIG_ARCH_MSM9615 is not set +# CONFIG_ARCH_MSM8625 is not set +# CONFIG_ARCH_MSM9625 is not set +CONFIG_MSM_SOC_REV_NONE=y +# CONFIG_MSM_SOC_REV_A is not set +CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y +CONFIG_ARCH_MSM_KRAIT=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_KRAITMP=y +CONFIG_MSM_KRAIT_WFE_FIXUP=y +CONFIG_MSM_RPM=y +# CONFIG_MSM_RPM_SMD is not set +CONFIG_MSM_MPM=y +CONFIG_MSM_XO=y +CONFIG_MSM_REMOTE_SPINLOCK_SFPB=y + +# +# MSM Board Selection +# +# CONFIG_MACH_MSM8960_CDP is not set +# CONFIG_MACH_MSM8960_MTP is not set +# CONFIG_MACH_MSM8960_FLUID is not set +# CONFIG_MACH_MSM8960_LIQUID is not set +# CONFIG_MACH_APQ8064_CDP is not set +# CONFIG_MACH_APQ8064_MTP is not set +# CONFIG_MACH_APQ8064_LIQUID is not set +# CONFIG_MACH_MPQ8064_CDP is not set +# CONFIG_MACH_MPQ8064_HRD is not set +# CONFIG_MACH_MPQ8064_DTV is not set +# CONFIG_MACH_MSM_DUMMY is not set +CONFIG_MACH_M2=y +CONFIG_MACH_M2_ATT=y +# CONFIG_MACH_M2_SPR is not set +# CONFIG_MACH_M2_VZW is not set + +# +# LGE Board Selection +# +CONFIG_BOARD_HEADER_FILE="" +# CONFIG_MACH_APQ8064_MAKO is not set +# CONFIG_MACH_LGE_DUMMY is not set + +# +# LGE Specific Patches +# +# CONFIG_LGE_CRASH_HANDLER is not set +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_HAVE_END_MEM=y +CONFIG_END_MEM=0xffffffff +# CONFIG_KERNEL_MSM_CONTIG_MEM_REGION is not set +CONFIG_KERNEL_PMEM_EBI_REGION=y +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +CONFIG_MSM_HAS_DEBUG_UART_HS=y +CONFIG_DEBUG_MSM8960_UART=y +# CONFIG_DEBUG_APQ8064_UART is not set +CONFIG_MSM7X00A_USE_GP_TIMER=y +# CONFIG_MSM7X00A_USE_DG_TIMER is not set +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_HTC_HEADSET is not set +# CONFIG_HTC_PWRSINK is not set +# CONFIG_MSM_FIQ_SUPPORT is not set +# CONFIG_MSM_SERIAL_DEBUGGER is not set +# CONFIG_MSM_PROC_COMM is not set +CONFIG_MSM_SMD=y +# CONFIG_MSM_SMD_PKG3 is not set +CONFIG_MSM_SMD_PKG4=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_N_WAY_SMD=y +CONFIG_MSM_N_WAY_SMSM=y +CONFIG_MSM_RESET_MODEM=m +CONFIG_MSM_SMD_LOGGING=y +# CONFIG_MSM_IPC_LOGGING is not set +CONFIG_MSM_SMD_NMEA=y +# CONFIG_MSM_HSIC_TTY is not set +CONFIG_MSM_SMD_TTY=y +CONFIG_MSM_SMD_QMI=y +CONFIG_MSM_SMD_PKT=y +# CONFIG_MSM_DSPS is not set +# CONFIG_MSM_ONCRPCROUTER is not set +CONFIG_MSM_IPC_ROUTER=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +# CONFIG_MSM_DALRPC is not set +# CONFIG_MSM_CPU_FREQ_SET_MIN_MAX is not set +# CONFIG_MSM_AVS_HW is not set +# CONFIG_MSM_HW3D is not set +CONFIG_AMSS_7X25_VERSION_2009=y +# CONFIG_AMSS_7X25_VERSION_2008 is not set +CONFIG_RTAC=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +CONFIG_MSM_DMA_TEST=m +CONFIG_WIFI_CONTROL_FUNC=y +# CONFIG_WIFI_MEM_PREALLOC is not set +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +CONFIG_MSM_RPM_REGULATOR=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +# CONFIG_MSM_PIL_MODEM is not set +# CONFIG_MSM_PIL_QDSP6V3 is not set +CONFIG_MSM_PIL_QDSP6V4=y +# CONFIG_MSM_PIL_LPASS_QDSP6V5 is not set +# CONFIG_MSM_PIL_MSS_QDSP6V5 is not set +CONFIG_MSM_PIL_RIVA=y +CONFIG_MSM_PIL_TZAPPS=y +# CONFIG_MSM_PIL_DSPS is not set +CONFIG_MSM_PIL_VIDC=y +# CONFIG_MSM_PIL_VENUS is not set +# CONFIG_MSM_PIL_GSS is not set +# CONFIG_MSM_PIL_PRONTO is not set +CONFIG_MSM_SCM=y +CONFIG_MSM_MODEM_8960=y +CONFIG_MSM_LPASS_8960=y +# CONFIG_MSM_GSS_SSR_8064 is not set +CONFIG_MSM_BUSPM_DEV=m +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +# CONFIG_MSM_RPM_RBCPR_STATS_LOG is not set +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_MSM_GPIOMUX=y +CONFIG_MSM_NATIVE_RESTART=y +CONFIG_MSM_PM8X60=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y +CONFIG_MSM_WATCHDOG=y +# CONFIG_MSM_WATCHDOG_V2 is not set +# CONFIG_MSM_MEMORY_DUMP is not set +CONFIG_MSM_DLOAD_MODE=y +CONFIG_MSM_JTAG=y +# CONFIG_MSM_SLEEP_STATS_DEVICE is not set +CONFIG_MSM_RUN_QUEUE_STATS=y +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_BT_BCM4334=y +# CONFIG_MSM_FAKE_BATTERY is not set +CONFIG_MSM_QDSP6_APR=y +# CONFIG_MSM_QDSP6_APRV2 is not set +CONFIG_MSM_QDSP6_CODECS=y +# CONFIG_MSM_QDSP6V2_CODECS is not set +CONFIG_MSM_AUDIO_QDSP6=y +# CONFIG_MSM_AUDIO_QDSP6V2 is not set +# CONFIG_MSM_ULTRASOUND is not set +# CONFIG_MSM_SPM_V1 is not set +CONFIG_MSM_SPM_V2=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MULTIMEDIA_USE_ION=y +# CONFIG_MSM_OCMEM is not set +# CONFIG_MSM_RTB is not set +# CONFIG_MSM_EBI_ERP is not set +CONFIG_MSM_CACHE_ERP=y +CONFIG_MSM_L1_ERR_PANIC=y +# CONFIG_MSM_L1_ERR_LOG is not set +# CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS is not set +# CONFIG_MSM_L2_ERP_1BIT_PANIC is not set +CONFIG_MSM_L2_ERP_2BIT_PANIC=y +CONFIG_MSM_DCVS=y +# CONFIG_MSM_CPR is not set +CONFIG_HAVE_ARCH_HAS_CURRENT_TIMER=y +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_HSIC_SYSMON is not set +CONFIG_MSM_CPU_PWRCTL=y + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_VCM is not set +# CONFIG_STRICT_MEMORY_RWX is not set +CONFIG_ARM_NR_BANKS=8 +# CONFIG_RESERVE_FIRST_PAGE is not set +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_KSAPI is not set +CONFIG_ARM_GIC=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI is not set +# CONFIG_PCI_SYSCALL is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_ARM_ARCH_TIMER is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_VMALLOC_RESERVE=0x19000000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CLEANCACHE=y +# CONFIG_ARCH_MEMORY_PROBE is not set +# CONFIG_ARCH_MEMORY_REMOVE is not set +# CONFIG_ENABLE_DMM is not set +# CONFIG_FIX_MOVABLE_ZONE is not set +CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0=y +# CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG is not set +# CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE is not set +CONFIG_HOLES_IN_ZONE=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_SECCOMP is not set +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set +CONFIG_CP_ACCESS=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y +CONFIG_KEXEC_HARDBOOT=y +CONFIG_KEXEC_HB_PAGE_ADDR=0xfffff000 +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_FREQ_MSM=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +# CONFIG_CONSOLE_EARLYSUSPEND is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +CONFIG_NET_SCH_INGRESS=y +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +CONFIG_BT_HCISMD=y +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_IBS is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_MSM_SLEEP is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_MSM_BT_POWER is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_CFG80211=y +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +CONFIG_RFKILL_LEDS=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_BCM2079X is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_GENLOCK=y +CONFIG_GENLOCK_MISCDEVICE=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +# CONFIG_CMA is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +CONFIG_ANDROID_PMEM=y +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +# CONFIG_TSIF is not set +# CONFIG_TSPP is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_PMIC8XXX_VIBRATOR is not set +# CONFIG_ANDROID_VIBRATOR is not set +# CONFIG_TOUCHSENSE_VIBRATOR is not set +# CONFIG_PMIC8XXX_NFC is not set +# CONFIG_PMIC8XXX_UPL is not set +CONFIG_QSEECOM=y +# CONFIG_QFP_FUSE is not set +# CONFIG_BU52031NVX is not set +CONFIG_NFC_PN544=y +CONFIG_SEC_MISC=y +CONFIG_USB_SWITCH_FSA9485=y +CONFIG_MPU_411_ENABLE=y +# CONFIG_YAS_532_ENABLE is not set +# CONFIG_OPTICAL_GP2A is not set +# CONFIG_OPTICAL_GP2AP020A00F is not set +# CONFIG_OPTICAL_TAOS_TRITON is not set +# CONFIG_OPTICAL_TAOS_TMD2672X is not set +# CONFIG_SENSORS_AL3201 is not set +CONFIG_SENSORS_CM36651=y +CONFIG_VP_A2220=y +# CONFIG_ADC_STMPE811 is not set +CONFIG_SAMSUNG_JACK=y +# CONFIG_SAMSUNG_JACK_GNDLDET is not set +# CONFIG_OPTICAL_BH1721 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +CONFIG_MPU_SENSORS_TIMERIRQ_411=y +CONFIG_INV_SENSORS_411=y +# CONFIG_MPU_SENSORS_MPU3050_411 is not set +# CONFIG_MPU_SENSORS_MPU6050A2_411 is not set +CONFIG_MPU_SENSORS_MPU6050B1_411=y +CONFIG_INV_SENSORS_ACCELEROMETERS=y +CONFIG_MPU_SENSORS_MPU6050_ACCEL_411=y +CONFIG_INV_SENSORS_COMPASS=y +CONFIG_MPU_SENSORS_AK8975_411=y +# CONFIG_MPU_SENSORS_AK8972_411 is not set +# CONFIG_MPU_SENSORS_MMC314X_411 is not set +# CONFIG_MPU_SENSORS_AMI30X_411 is not set +# CONFIG_MPU_SENSORS_AMI306_411 is not set +# CONFIG_MPU_SENSORS_HMC5883_411 is not set +# CONFIG_MPU_SENSORS_LSM303DLX_M_411 is not set +# CONFIG_MPU_SENSORS_MMC314XMS_411 is not set +# CONFIG_MPU_SENSORS_YAS530_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD002B_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD004A_411 is not set +# CONFIG_MPU_USERSPACE_DEBUG is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +# CONFIG_SLIMPORT_ANX7808 is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=y +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_ENC28J60 is not set +# CONFIG_MSM_RMNET is not set +CONFIG_MSM_RMNET_BAM=y +# CONFIG_QFEC is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_SLIP=y +CONFIG_SLHC=y +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_SMART is not set +CONFIG_SLIP_MODE_SLIP6=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_LIBRA_SDIOIF is not set +# CONFIG_ATH6K_LEGACY_EXT is not set +# CONFIG_WCNSS_CORE is not set +# CONFIG_ATH_COMMON is not set +CONFIG_BCMDHD=m +# CONFIG_BCM4330 is not set +CONFIG_BCM4334=y +# CONFIG_BCM43241 is not set +CONFIG_BCMDHD_FW_PATH="/system/etc/wifi/bcmdhd_sta.bin_b2" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/nvram_net.txt" +# CONFIG_DHD_USE_STATIC_BUF is not set +# CONFIG_DHD_USE_SCHED_SCAN is not set +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_WLAN_REGION_CODE=100 +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PMIC8XXX is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_QCIKBD is not set +CONFIG_KEYBOARD_CYPRESS_TOUCH_236=y +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_QCITP is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +# CONFIG_JOYSTICK_XPAD_FF is not set +# CONFIG_JOYSTICK_XPAD_LEDS is not set +# CONFIG_TOUCHDISC_VTD518_SHINETSU is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +CONFIG_TOUCHSCREEN_MMS144=y +# CONFIG_TOUCHSCREEN_MMS136 is not set +# CONFIG_TOUCHSCREEN_MMS136_TABLET is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_MSM_LEGACY is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8C_TS is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC is not set +# CONFIG_TOUCHSCREEN_FT5X06 is not set +# CONFIG_TOUCHSCREEN_LGE_COMMON is not set +# CONFIG_TOUCHSCREEN_LGE_SYNAPTICS is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +CONFIG_INPUT_BMP180=y +# CONFIG_INPUT_PM8XXX_VIBRATOR is not set +CONFIG_INPUT_PMIC8XXX_PWRKEY=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BOSCH_BMA150 is not set +# CONFIG_STM_LIS3DH is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_VT_CONSOLE is not set +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_N_SMUX is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MSM=y +# CONFIG_SERIAL_MSM_CONSOLE is not set +CONFIG_SERIAL_MSM_HS=y +# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_MSM_SMD is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# SDIO support for DIAG +# + +# +# HSIC support for DIAG +# +CONFIG_DIAG_BRIDGE_CODE=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_MSM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +CONFIG_MSM_ROTATOR=y +# CONFIG_MMC_GENERIC_CSDIO is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_MSM is not set +CONFIG_I2C_QUP=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_QUP=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=m +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPMI is not set +CONFIG_SLIMBUS=y +# CONFIG_SLIMBUS_MSM_CTRL is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_MSM_V1 is not set +CONFIG_GPIO_MSM_V2=y +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_FSM9XXX is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_SX150X=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_GPIO_PM8XXX=y +CONFIG_GPIO_PM8XXX_MPP=y +# CONFIG_GPIO_PM8XXX_RPC is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +CONFIG_BATTERY_MAX17040=y +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_BATTERY_MSM is not set +# CONFIG_BATTERY_MSM8X60 is not set +# CONFIG_ISL9519_CHARGER is not set +# CONFIG_SMB137B_CHARGER is not set +# CONFIG_SMB349_CHARGER is not set +# CONFIG_BATTERY_BQ27520 is not set +# CONFIG_BATTERY_BQ27541 is not set +CONFIG_PM8921_CHARGER=y +CONFIG_PM8XXX_CCADC=y +# CONFIG_LTC4088_CHARGER is not set +# CONFIG_PM8921_BMS is not set +CONFIG_PM8921_SEC_CHARGER=y +CONFIG_BATTERY_CTIA=y +CONFIG_BATTERY_SEC=y +CONFIG_SAMSUNG_LPM_MODE=y +CONFIG_WIRELESS_CHARGING=y +# CONFIG_BATTERY_SAMSUNG_STRETTO is not set +# CONFIG_BATTERY_BCL is not set +CONFIG_CHARGER_SMB347=y +# CONFIG_WIRELESS_CHARGER is not set +# CONFIG_BATTERY_TEMP_CONTROL is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +CONFIG_SENSORS_PM8XXX_ADC=y +# CONFIG_SENSORS_EPM_ADC is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_MSM_POPMEM is not set +# CONFIG_THERMAL_TSENS is not set +CONFIG_THERMAL_TSENS8960=y +# CONFIG_THERMAL_TSENS8974 is not set +CONFIG_THERMAL_PM8XXX=y +CONFIG_THERMAL_MONITOR=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_PMIC8058 is not set +# CONFIG_PMIC8901 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +CONFIG_MFD_PM8XXX=y +CONFIG_MFD_PM8921_CORE=y +# CONFIG_MFD_PM8821_CORE is not set +# CONFIG_MFD_PM8018_CORE is not set +CONFIG_MFD_PM8038_CORE=y +CONFIG_MFD_PM8XXX_IRQ=y +# CONFIG_MFD_PM8821_IRQ is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +CONFIG_MFD_PM8XXX_DEBUG=y +CONFIG_MFD_PM8XXX_PWM=y +CONFIG_MFD_PM8XXX_MISC=y +CONFIG_MFD_PM8XXX_SPK=y +CONFIG_MFD_PM8XXX_BATT_ALARM=y +# CONFIG_WCD9304_CODEC is not set +CONFIG_WCD9310_CODEC=y +# CONFIG_WCD9320_CODEC is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_GPIO=y +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +CONFIG_REGULATOR_MAX8952=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_PM8XXX=y +CONFIG_REGULATOR_MSM_GPIO=y +# CONFIG_REGULATOR_STUB is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +# CONFIG_VIDEO_V4L2_SUBDEV_API is not set +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +CONFIG_RC_CORE=y +CONFIG_LIRC=y +# CONFIG_USER_RC_INPUT is not set +CONFIG_RC_MAP=y +CONFIG_IR_NEC_DECODER=y +CONFIG_IR_RC5_DECODER=y +CONFIG_IR_RC6_DECODER=y +CONFIG_IR_JVC_DECODER=y +CONFIG_IR_SONY_DECODER=y +CONFIG_IR_RC5_SZ_DECODER=y +CONFIG_IR_SANYO_DECODER=y +CONFIG_IR_MCE_KBD_DECODER=y +CONFIG_IR_LIRC_CODEC=y +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MC44S803=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_IR_I2C=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# MPEG video encoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# +CONFIG_MSM_VCAP=y +CONFIG_V4L_USB_DRIVERS=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set + +# +# Qualcomm MSM Camera And Video +# +CONFIG_MSM_CAMERA=y +# CONFIG_MSM_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_V4L2=y + +# +# Camera Sensor Selection +# +# CONFIG_ISX012 is not set +CONFIG_S5C73M3=y +CONFIG_S5K6A3YX=y +# CONFIG_S5K8AAY is not set +# CONFIG_MT9M114 is not set +# CONFIG_IMX074_ACT is not set +# CONFIG_S5K4E1 is not set +CONFIG_MSM_CAMERA_FLASH_SC628A=y +# CONFIG_IMX072 is not set +CONFIG_MSM_CAMERA_FLASH=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_ACTUATOR=y +CONFIG_MSM_GEMINI=y +CONFIG_QUP_EXCLUSIVE_TO_CAMERA=y + +# +# Camera Sensor Selection +# +# CONFIG_IMX074 is not set +# CONFIG_OV5647 is not set +# CONFIG_MSM_CAMERA_FLASH_TPS61310 is not set +# CONFIG_OV2720 is not set +# CONFIG_OV8825 is not set +# CONFIG_MSM_EEPROM is not set +# CONFIG_IMX074_EEPROM is not set +# CONFIG_IMX091_EEPROM is not set +CONFIG_MSM_MERCURY=y +# CONFIG_MSM_CAM_IRQ_ROUTER is not set +# CONFIG_MSM_CPP is not set +# CONFIG_MSM_CCI is not set +CONFIG_MSM_CSI20_HEADER=y +# CONFIG_MSM_CSI30_HEADER is not set +# CONFIG_MSM_CSIPHY is not set +# CONFIG_MSM_CSID is not set +# CONFIG_MSM_CSI2_REGISTER is not set +# CONFIG_MSM_ISPIF is not set +# CONFIG_S5K3L1YX is not set +# CONFIG_IMX091 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +# CONFIG_OV7692 is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_MSM_WFD=y +# CONFIG_RADIO_ADAPTERS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set +CONFIG_MSM_KGSL_2D=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 +CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24 +CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y +# CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +CONFIG_FB_VIRTUAL=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_VIDEO_MHL_V2=y +CONFIG_MHL_D3_SUPPORT=y +CONFIG_MHL_NEW_CBUS_MSC_CMD=y +CONFIG_MSM_VIDC=y +CONFIG_MSM_VIDC_1080P=y +CONFIG_MSM_VIDC_VENC=y +CONFIG_MSM_VIDC_VDEC=y +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_LCDC_HW=y +CONFIG_FB_MSM_TRIPLE_BUFFER=y +CONFIG_FB_MSM_MDP_HW=y +# CONFIG_FB_MSM_MDP22 is not set +# CONFIG_FB_MSM_MDP30 is not set +# CONFIG_FB_MSM_MDP31 is not set +CONFIG_FB_MSM_MDP40=y +# CONFIG_FB_MSM_MDSS is not set +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_EBI2 is not set +# CONFIG_FB_MSM_MDDI is not set +CONFIG_FB_MSM_MIPI_DSI=y +# CONFIG_FB_MSM_LCDC is not set +# CONFIG_FB_MSM_LVDS is not set +CONFIG_FB_MSM_OVERLAY=y +CONFIG_FB_MSM_DTV=y +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_TVOUT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA is not set +# CONFIG_FB_MSM_MDDI_ORISE is not set +# CONFIG_FB_MSM_MDDI_QUICKVX is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL is not set +# CONFIG_FB_MSM_MIPI_DSI_TOSHIBA is not set +# CONFIG_FB_MSM_MIPI_DSI_LGIT is not set +# CONFIG_FB_MSM_MIPI_DSI_RENESAS is not set +# CONFIG_FB_MSM_MIPI_DSI_SIMULATOR is not set +# CONFIG_FB_MSM_MIPI_DSI_NOVATEK is not set +# CONFIG_FB_MSM_MIPI_DSI_ORISE is not set +CONFIG_FB_MSM_MIPI_DSI_SAMSUNG_OLED=y +CONFIG_SAMSUNG_CMC624=y +# CONFIG_FB_MSM_LCDC_ST15_WXGA is not set +# CONFIG_FB_MSM_LCDC_ST15_PANEL is not set +# CONFIG_FB_MSM_LCDC_PRISM_WVGA is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335 is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT is not set +# CONFIG_FB_MSM_LCDC_NT35582_WVGA is not set +# CONFIG_FB_MSM_LCDC_WXGA is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO is not set +CONFIG_FB_MSM_NO_MDP_PIPE_CTRL=y +CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y +CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y +CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y +# CONFIG_FB_MSM_LCDC_PRISM_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_NT35582_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM is not set +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PRISM_WVGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA is not set +# CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128 is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF is not set +# CONFIG_FB_MSM_HDMI_AS_PRIMARY is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +CONFIG_MIPI_SAMSUNG_ESD_REFRESH=y +CONFIG_FB_MSM_EXT_INTERFACE_COMMON=y +CONFIG_FB_MSM_HDMI_COMMON=y +CONFIG_FB_MSM_HDMI_3D=y +# CONFIG_FB_MSM_HDMI_ADV7520_PANEL is not set +CONFIG_FB_MSM_HDMI_MSM_PANEL=y +CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT=y +# CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT is not set +# CONFIG_FB_MSM_HDMI_MHL_9244 is not set +# CONFIG_FB_MSM_HDMI_MHL_8334 is not set +# CONFIG_FB_MSM_TVOUT_NTSC_M is not set +# CONFIG_FB_MSM_TVOUT_NTSC_J is not set +# CONFIG_FB_MSM_TVOUT_PAL_BDGHIN is not set +# CONFIG_FB_MSM_TVOUT_PAL_M is not set +# CONFIG_FB_MSM_TVOUT_PAL_N is not set +CONFIG_FB_MSM_TVOUT_NONE=y +# CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565 is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888 is not set +CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888=y +# CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_AMS369FG06 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LM3530 is not set +# CONFIG_BACKLIGHT_LM3533 is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y + +# +# MSM SoC Audio support +# +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO=y +CONFIG_SND_SOC_MSM_QDSP6_INTF=y +# CONFIG_SND_SOC_MSM_QDSP6V2_INTF is not set +CONFIG_SND_SOC_VOICE=y +CONFIG_SND_SOC_QDSP6=y +# CONFIG_SND_SOC_QDSP6V2 is not set +CONFIG_SND_SOC_MSM8960=y +# CONFIG_SND_SOC_DUAL_AMIC is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WCD9304=y +CONFIG_SND_SOC_WCD9310=y +CONFIG_SND_SOC_CS8427=y +CONFIG_SND_SOC_MSM_STUB=y +# CONFIG_SND_SOC_TPA2028D is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +CONFIG_UHID=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +# CONFIG_HID_ACRUX is not set +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +# CONFIG_HID_PRODIKEYS is not set +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_HID_EMS_FF is not set +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_KEYTOUCH is not set +CONFIG_HID_KYE=y +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +# CONFIG_HID_LCPOWER is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=m +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +# CONFIG_HID_MULTITOUCH is not set +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LCD is not set +# CONFIG_HID_PICOLCD_LEDS is not set +# CONFIG_HID_PRIMAX is not set +CONFIG_HID_ROCCAT=y +# CONFIG_HID_SAITEK is not set +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +# CONFIG_GREENASIA_FF is not set +CONFIG_HID_SMARTJOYPLUS=y +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_HID_TIVO is not set +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WACOM_POWER_SUPPLY is not set +# CONFIG_HID_WIIMOTE is not set +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_MSM=y +# CONFIG_USB_EHCI_MSM_HSIC is not set +# CONFIG_USB_EHCI_MSM_HOST4 is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_PEHCI_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +CONFIG_USB_PRINTER=y +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=y +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +CONFIG_USB_SERIAL_QUALCOMM=y +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +CONFIG_USB_SERIAL_WWAN=y +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_CSVT is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_QCOM_DIAG_BRIDGE=y +# CONFIG_USB_QCOM_DIAG_BRIDGE_TEST is not set +CONFIG_USB_QCOM_MDM_BRIDGE=y +# CONFIG_USB_QCOM_KS_BRIDGE is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +CONFIG_USB_CI13XXX_MSM=y +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +# CONFIG_USB_MSM_72K is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_SUPERSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="" +CONFIG_RMNET_SMD_DATA_CHANNEL="" +CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y +# CONFIG_USB_ANDROID_CDC_ECM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_OTG_WAKELOCK is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_MSM_OTG_72K is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_USB_MSM_OTG=y +# CONFIG_USB_MSM_ACA is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_PERF_PROFILING is not set +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +# CONFIG_MMC_EMBEDDED_SDIO is not set +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +# CONFIG_MMC_BLOCK_BOUNCE is not set +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_BLOCK_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_MSM=y +CONFIG_MMC_MSM_SDC1_SUPPORT=y +CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y +# CONFIG_MMC_MSM_SDC2_SUPPORT is not set +CONFIG_MMC_MSM_SDC3_SUPPORT=y +# CONFIG_MMC_MSM_SDC3_POLLING is not set +# CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC3_WP_SUPPORT is not set +CONFIG_MMC_MSM_SDC4_SUPPORT=y +# CONFIG_MMC_MSM_SDC4_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC5_SUPPORT is not set +CONFIG_MMC_MSM_SPS_SUPPORT=y +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_MSM_PDM is not set +# CONFIG_LEDS_PMIC_MPP is not set +# CONFIG_LEDS_MSM_TRICOLOR is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_CPLD is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +CONFIG_LEDS_PM8XXX=y +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_MSM_PMIC is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set +# CONFIG_LEDS_TRIGGER_SLEEP is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_SWITCH_FSA8008 is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_VIDEO_MHL_TAB_V2 is not set +# CONFIG_MHL_SWING_LEVEL is not set +# CONFIG_ACCESSORY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_MSM is not set +# CONFIG_RTC_DRV_MSM7X00A is not set +CONFIG_RTC_DRV_PM8XXX=y +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +CONFIG_QCACHE=y +# CONFIG_FB_SM7XX is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_PERSISTENT_RAM=y +CONFIG_ANDROID_RAM_CONSOLE=y +# CONFIG_PERSISTENT_TRACER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +# CONFIG_ANDROID_SWITCH is not set +# CONFIG_ANDROID_INTF_ALARM_DEV is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set + +# +# Qualcomm Atheros Prima WLAN module +# +# CONFIG_PRIMA_WLAN is not set + +# +# Qualcomm MSM specific device drivers +# +CONFIG_MSM_SSBI=y +CONFIG_SPS=y +# CONFIG_USB_BAM is not set +CONFIG_SPS_SUPPORT_BAMDMA=y +# CONFIG_SPS_SUPPORT_NDP_BAM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_NEW_SENSORS=y +CONFIG_SENSORS_CORE=y +# CONFIG_BATTERY_SAMSUNG is not set +CONFIG_VIBETONZ=y + +# +# Hardware Spinlock drivers +# +CONFIG_IOMMU_SUPPORT=y +# CONFIG_MSM_IOMMU is not set + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MOBICORE_SUPPORT is not set +CONFIG_MSM_QDSS=y +# CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE is not set +CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_DEBUG_LIST=y +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +CONFIG_SCHED_TRACER=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_DYNAMIC_FTRACE=y +# CONFIG_FUNCTION_PROFILER is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_OLD_MCOUNT=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_RODATA is not set +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_NONE=y +# CONFIG_DEBUG_LL_UART is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_EARLY_PRINTK is not set +CONFIG_PID_IN_CONTEXTIDR=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +CONFIG_KEYS_DEBUG_PROC_KEYS=y +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_QCE40=y +CONFIG_CRYPTO_DEV_QCRYPTO=m +CONFIG_CRYPTO_DEV_QCE=m +CONFIG_CRYPTO_DEV_QCEDEV=m +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set diff --git a/arch/arm/configs/cyanogen_d2cri_defconfig b/arch/arm/configs/cyanogen_d2cri_defconfig new file mode 100644 index 00000000000..db712bd9c2b --- /dev/null +++ b/arch/arm/configs/cyanogen_d2cri_defconfig @@ -0,0 +1,3699 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARM_TICKET_LOCKS=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x80200000 +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-cyanogenmod" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_CGROUP_MEM_RES_CTLR is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +CONFIG_PERF_COUNTERS=y +CONFIG_DEBUG_PERF_USE_VMALLOC=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_TEST=m +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM7X01A is not set +# CONFIG_ARCH_MSM7X25 is not set +# CONFIG_ARCH_MSM7X27 is not set +# CONFIG_ARCH_MSM7X30 is not set +# CONFIG_ARCH_QSD8X50 is not set +# CONFIG_ARCH_MSM8X60 is not set +CONFIG_ARCH_MSM8960=y +# CONFIG_ARCH_MSM8930 is not set +CONFIG_ARCH_APQ8064=y +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_MPQ8092 is not set +# CONFIG_ARCH_MSM8226 is not set +# CONFIG_ARCH_FSM9XXX is not set +# CONFIG_ARCH_MSM9615 is not set +# CONFIG_ARCH_MSM8625 is not set +# CONFIG_ARCH_MSM9625 is not set +CONFIG_MSM_SOC_REV_NONE=y +# CONFIG_MSM_SOC_REV_A is not set +CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y +CONFIG_ARCH_MSM_KRAIT=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_KRAITMP=y +CONFIG_MSM_KRAIT_WFE_FIXUP=y +CONFIG_MSM_RPM=y +# CONFIG_MSM_RPM_SMD is not set +CONFIG_MSM_MPM=y +CONFIG_MSM_XO=y +CONFIG_MSM_REMOTE_SPINLOCK_SFPB=y + +# +# MSM Board Selection +# +# CONFIG_MACH_MSM8960_CDP is not set +# CONFIG_MACH_MSM8960_MTP is not set +# CONFIG_MACH_MSM8960_FLUID is not set +# CONFIG_MACH_MSM8960_LIQUID is not set +# CONFIG_MACH_APQ8064_CDP is not set +# CONFIG_MACH_APQ8064_MTP is not set +# CONFIG_MACH_APQ8064_LIQUID is not set +# CONFIG_MACH_MPQ8064_CDP is not set +# CONFIG_MACH_MPQ8064_HRD is not set +# CONFIG_MACH_MPQ8064_DTV is not set +# CONFIG_MACH_MSM_DUMMY is not set +CONFIG_MACH_M2=y +# CONFIG_MACH_M2_ATT is not set +# CONFIG_MACH_M2_SPR is not set +CONFIG_MACH_M2_VZW=y + +# +# LGE Board Selection +# +CONFIG_BOARD_HEADER_FILE="" +# CONFIG_MACH_APQ8064_MAKO is not set +# CONFIG_MACH_LGE_DUMMY is not set + +# +# LGE Specific Patches +# +# CONFIG_LGE_CRASH_HANDLER is not set +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_HAVE_END_MEM=y +CONFIG_END_MEM=0xffffffff +# CONFIG_KERNEL_MSM_CONTIG_MEM_REGION is not set +CONFIG_KERNEL_PMEM_EBI_REGION=y +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +CONFIG_MSM_HAS_DEBUG_UART_HS=y +CONFIG_DEBUG_MSM8960_UART=y +# CONFIG_DEBUG_APQ8064_UART is not set +CONFIG_MSM7X00A_USE_GP_TIMER=y +# CONFIG_MSM7X00A_USE_DG_TIMER is not set +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_HTC_HEADSET is not set +# CONFIG_HTC_PWRSINK is not set +# CONFIG_MSM_FIQ_SUPPORT is not set +# CONFIG_MSM_SERIAL_DEBUGGER is not set +# CONFIG_MSM_PROC_COMM is not set +CONFIG_MSM_SMD=y +# CONFIG_MSM_SMD_PKG3 is not set +CONFIG_MSM_SMD_PKG4=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_N_WAY_SMD=y +CONFIG_MSM_N_WAY_SMSM=y +CONFIG_MSM_RESET_MODEM=m +CONFIG_MSM_SMD_LOGGING=y +# CONFIG_MSM_IPC_LOGGING is not set +CONFIG_MSM_SMD_NMEA=y +# CONFIG_MSM_HSIC_TTY is not set +CONFIG_MSM_SMD_TTY=y +CONFIG_MSM_SMD_QMI=y +CONFIG_MSM_SMD_PKT=y +# CONFIG_MSM_DSPS is not set +# CONFIG_MSM_ONCRPCROUTER is not set +CONFIG_MSM_IPC_ROUTER=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +# CONFIG_MSM_DALRPC is not set +# CONFIG_MSM_CPU_FREQ_SET_MIN_MAX is not set +# CONFIG_MSM_AVS_HW is not set +# CONFIG_MSM_HW3D is not set +CONFIG_AMSS_7X25_VERSION_2009=y +# CONFIG_AMSS_7X25_VERSION_2008 is not set +CONFIG_RTAC=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +CONFIG_MSM_DMA_TEST=m +CONFIG_WIFI_CONTROL_FUNC=y +# CONFIG_WIFI_MEM_PREALLOC is not set +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +CONFIG_MSM_RPM_REGULATOR=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +# CONFIG_MSM_PIL_MODEM is not set +# CONFIG_MSM_PIL_QDSP6V3 is not set +CONFIG_MSM_PIL_QDSP6V4=y +# CONFIG_MSM_PIL_LPASS_QDSP6V5 is not set +# CONFIG_MSM_PIL_MSS_QDSP6V5 is not set +CONFIG_MSM_PIL_RIVA=y +CONFIG_MSM_PIL_TZAPPS=y +# CONFIG_MSM_PIL_DSPS is not set +CONFIG_MSM_PIL_VIDC=y +# CONFIG_MSM_PIL_VENUS is not set +# CONFIG_MSM_PIL_GSS is not set +# CONFIG_MSM_PIL_PRONTO is not set +CONFIG_MSM_SCM=y +CONFIG_MSM_MODEM_8960=y +CONFIG_MSM_LPASS_8960=y +# CONFIG_MSM_GSS_SSR_8064 is not set +CONFIG_MSM_BUSPM_DEV=m +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +# CONFIG_MSM_RPM_RBCPR_STATS_LOG is not set +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_MSM_GPIOMUX=y +CONFIG_MSM_NATIVE_RESTART=y +CONFIG_MSM_PM8X60=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y +CONFIG_MSM_WATCHDOG=y +# CONFIG_MSM_WATCHDOG_V2 is not set +# CONFIG_MSM_MEMORY_DUMP is not set +CONFIG_MSM_DLOAD_MODE=y +CONFIG_MSM_JTAG=y +# CONFIG_MSM_SLEEP_STATS_DEVICE is not set +CONFIG_MSM_RUN_QUEUE_STATS=y +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_BT_BCM4334=y +# CONFIG_MSM_FAKE_BATTERY is not set +CONFIG_MSM_QDSP6_APR=y +# CONFIG_MSM_QDSP6_APRV2 is not set +CONFIG_MSM_QDSP6_CODECS=y +# CONFIG_MSM_QDSP6V2_CODECS is not set +CONFIG_MSM_AUDIO_QDSP6=y +# CONFIG_MSM_AUDIO_QDSP6V2 is not set +# CONFIG_MSM_ULTRASOUND is not set +# CONFIG_MSM_SPM_V1 is not set +CONFIG_MSM_SPM_V2=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MULTIMEDIA_USE_ION=y +# CONFIG_MSM_OCMEM is not set +# CONFIG_MSM_RTB is not set +# CONFIG_MSM_EBI_ERP is not set +CONFIG_MSM_CACHE_ERP=y +CONFIG_MSM_L1_ERR_PANIC=y +# CONFIG_MSM_L1_ERR_LOG is not set +# CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS is not set +# CONFIG_MSM_L2_ERP_1BIT_PANIC is not set +CONFIG_MSM_L2_ERP_2BIT_PANIC=y +CONFIG_MSM_DCVS=y +# CONFIG_MSM_CPR is not set +CONFIG_HAVE_ARCH_HAS_CURRENT_TIMER=y +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_HSIC_SYSMON is not set +CONFIG_MSM_CPU_PWRCTL=y + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_VCM is not set +# CONFIG_STRICT_MEMORY_RWX is not set +CONFIG_ARM_NR_BANKS=8 +# CONFIG_RESERVE_FIRST_PAGE is not set +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_KSAPI is not set +CONFIG_ARM_GIC=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI is not set +# CONFIG_PCI_SYSCALL is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_ARM_ARCH_TIMER is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_VMALLOC_RESERVE=0x19000000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CLEANCACHE=y +# CONFIG_ARCH_MEMORY_PROBE is not set +# CONFIG_ARCH_MEMORY_REMOVE is not set +# CONFIG_ENABLE_DMM is not set +# CONFIG_FIX_MOVABLE_ZONE is not set +CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0=y +# CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG is not set +# CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE is not set +CONFIG_HOLES_IN_ZONE=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_SECCOMP is not set +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set +CONFIG_CP_ACCESS=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y +CONFIG_KEXEC_HARDBOOT=y +CONFIG_KEXEC_HB_PAGE_ADDR=0xfffff000 +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_FREQ_MSM=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +# CONFIG_CONSOLE_EARLYSUSPEND is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +CONFIG_NET_SCH_INGRESS=y +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +CONFIG_BT_HCISMD=y +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_IBS is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_MSM_SLEEP is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_MSM_BT_POWER is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_CFG80211=y +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +CONFIG_RFKILL_LEDS=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_BCM2079X is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_GENLOCK=y +CONFIG_GENLOCK_MISCDEVICE=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +# CONFIG_CMA is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +CONFIG_ANDROID_PMEM=y +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +# CONFIG_TSIF is not set +# CONFIG_TSPP is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_PMIC8XXX_VIBRATOR is not set +# CONFIG_ANDROID_VIBRATOR is not set +# CONFIG_TOUCHSENSE_VIBRATOR is not set +# CONFIG_PMIC8XXX_NFC is not set +# CONFIG_PMIC8XXX_UPL is not set +CONFIG_QSEECOM=y +# CONFIG_QFP_FUSE is not set +# CONFIG_BU52031NVX is not set +CONFIG_NFC_PN544=y +CONFIG_SEC_MISC=y +CONFIG_USB_SWITCH_FSA9485=y +CONFIG_MPU_411_ENABLE=y +# CONFIG_YAS_532_ENABLE is not set +# CONFIG_OPTICAL_GP2A is not set +# CONFIG_OPTICAL_GP2AP020A00F is not set +# CONFIG_OPTICAL_TAOS_TRITON is not set +# CONFIG_OPTICAL_TAOS_TMD2672X is not set +# CONFIG_SENSORS_AL3201 is not set +CONFIG_SENSORS_CM36651=y +CONFIG_VP_A2220=y +# CONFIG_ADC_STMPE811 is not set +CONFIG_SAMSUNG_JACK=y +# CONFIG_SAMSUNG_JACK_GNDLDET is not set +# CONFIG_OPTICAL_BH1721 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +CONFIG_MPU_SENSORS_TIMERIRQ_411=y +CONFIG_INV_SENSORS_411=y +# CONFIG_MPU_SENSORS_MPU3050_411 is not set +# CONFIG_MPU_SENSORS_MPU6050A2_411 is not set +CONFIG_MPU_SENSORS_MPU6050B1_411=y +CONFIG_INV_SENSORS_ACCELEROMETERS=y +CONFIG_MPU_SENSORS_MPU6050_ACCEL_411=y +CONFIG_INV_SENSORS_COMPASS=y +CONFIG_MPU_SENSORS_AK8975_411=y +# CONFIG_MPU_SENSORS_AK8972_411 is not set +# CONFIG_MPU_SENSORS_MMC314X_411 is not set +# CONFIG_MPU_SENSORS_AMI30X_411 is not set +# CONFIG_MPU_SENSORS_AMI306_411 is not set +# CONFIG_MPU_SENSORS_HMC5883_411 is not set +# CONFIG_MPU_SENSORS_LSM303DLX_M_411 is not set +# CONFIG_MPU_SENSORS_MMC314XMS_411 is not set +# CONFIG_MPU_SENSORS_YAS530_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD002B_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD004A_411 is not set +# CONFIG_MPU_USERSPACE_DEBUG is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +# CONFIG_SLIMPORT_ANX7808 is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=y +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_ENC28J60 is not set +# CONFIG_MSM_RMNET is not set +CONFIG_MSM_RMNET_BAM=y +# CONFIG_QFEC is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_SLIP=y +CONFIG_SLHC=y +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_SMART is not set +CONFIG_SLIP_MODE_SLIP6=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_LIBRA_SDIOIF is not set +# CONFIG_ATH6K_LEGACY_EXT is not set +# CONFIG_WCNSS_CORE is not set +# CONFIG_ATH_COMMON is not set +CONFIG_BCMDHD=m +# CONFIG_BCM4330 is not set +CONFIG_BCM4334=y +# CONFIG_BCM43241 is not set +CONFIG_BCMDHD_FW_PATH="/system/etc/wifi/bcmdhd_sta.bin_b2" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/nvram_net.txt" +# CONFIG_DHD_USE_STATIC_BUF is not set +# CONFIG_DHD_USE_SCHED_SCAN is not set +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_WLAN_REGION_CODE=100 +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PMIC8XXX is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_QCIKBD is not set +CONFIG_KEYBOARD_CYPRESS_TOUCH_236=y +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_QCITP is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +# CONFIG_JOYSTICK_XPAD_FF is not set +# CONFIG_JOYSTICK_XPAD_LEDS is not set +# CONFIG_TOUCHDISC_VTD518_SHINETSU is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +CONFIG_TOUCHSCREEN_MMS144=y +# CONFIG_TOUCHSCREEN_MMS136 is not set +# CONFIG_TOUCHSCREEN_MMS136_TABLET is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_MSM_LEGACY is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8C_TS is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC is not set +# CONFIG_TOUCHSCREEN_FT5X06 is not set +# CONFIG_TOUCHSCREEN_LGE_COMMON is not set +# CONFIG_TOUCHSCREEN_LGE_SYNAPTICS is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +CONFIG_INPUT_BMP180=y +# CONFIG_INPUT_PM8XXX_VIBRATOR is not set +CONFIG_INPUT_PMIC8XXX_PWRKEY=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BOSCH_BMA150 is not set +# CONFIG_STM_LIS3DH is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_VT_CONSOLE is not set +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_N_SMUX is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MSM=y +# CONFIG_SERIAL_MSM_CONSOLE is not set +CONFIG_SERIAL_MSM_HS=y +# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_MSM_SMD is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# SDIO support for DIAG +# + +# +# HSIC support for DIAG +# +CONFIG_DIAG_BRIDGE_CODE=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_MSM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +CONFIG_MSM_ROTATOR=y +# CONFIG_MMC_GENERIC_CSDIO is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_MSM is not set +CONFIG_I2C_QUP=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_QUP=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=m +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPMI is not set +CONFIG_SLIMBUS=y +# CONFIG_SLIMBUS_MSM_CTRL is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_MSM_V1 is not set +CONFIG_GPIO_MSM_V2=y +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_FSM9XXX is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_SX150X=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_GPIO_PM8XXX=y +CONFIG_GPIO_PM8XXX_MPP=y +# CONFIG_GPIO_PM8XXX_RPC is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +CONFIG_BATTERY_MAX17040=y +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_BATTERY_MSM is not set +# CONFIG_BATTERY_MSM8X60 is not set +# CONFIG_ISL9519_CHARGER is not set +# CONFIG_SMB137B_CHARGER is not set +# CONFIG_SMB349_CHARGER is not set +# CONFIG_BATTERY_BQ27520 is not set +# CONFIG_BATTERY_BQ27541 is not set +CONFIG_PM8921_CHARGER=y +CONFIG_PM8XXX_CCADC=y +# CONFIG_LTC4088_CHARGER is not set +# CONFIG_PM8921_BMS is not set +CONFIG_PM8921_SEC_CHARGER=y +CONFIG_BATTERY_CTIA=y +CONFIG_BATTERY_SEC=y +CONFIG_SAMSUNG_LPM_MODE=y +CONFIG_WIRELESS_CHARGING=y +# CONFIG_BATTERY_SAMSUNG_STRETTO is not set +# CONFIG_BATTERY_BCL is not set +CONFIG_CHARGER_SMB347=y +# CONFIG_WIRELESS_CHARGER is not set +# CONFIG_BATTERY_TEMP_CONTROL is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +CONFIG_SENSORS_PM8XXX_ADC=y +# CONFIG_SENSORS_EPM_ADC is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_MSM_POPMEM is not set +# CONFIG_THERMAL_TSENS is not set +CONFIG_THERMAL_TSENS8960=y +# CONFIG_THERMAL_TSENS8974 is not set +CONFIG_THERMAL_PM8XXX=y +CONFIG_THERMAL_MONITOR=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_PMIC8058 is not set +# CONFIG_PMIC8901 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +CONFIG_MFD_PM8XXX=y +CONFIG_MFD_PM8921_CORE=y +# CONFIG_MFD_PM8821_CORE is not set +# CONFIG_MFD_PM8018_CORE is not set +CONFIG_MFD_PM8038_CORE=y +CONFIG_MFD_PM8XXX_IRQ=y +# CONFIG_MFD_PM8821_IRQ is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +CONFIG_MFD_PM8XXX_DEBUG=y +CONFIG_MFD_PM8XXX_PWM=y +CONFIG_MFD_PM8XXX_MISC=y +CONFIG_MFD_PM8XXX_SPK=y +CONFIG_MFD_PM8XXX_BATT_ALARM=y +# CONFIG_WCD9304_CODEC is not set +CONFIG_WCD9310_CODEC=y +# CONFIG_WCD9320_CODEC is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_GPIO=y +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +CONFIG_REGULATOR_MAX8952=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_PM8XXX=y +CONFIG_REGULATOR_MSM_GPIO=y +# CONFIG_REGULATOR_STUB is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +# CONFIG_VIDEO_V4L2_SUBDEV_API is not set +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +CONFIG_RC_CORE=y +CONFIG_LIRC=y +# CONFIG_USER_RC_INPUT is not set +CONFIG_RC_MAP=y +CONFIG_IR_NEC_DECODER=y +CONFIG_IR_RC5_DECODER=y +CONFIG_IR_RC6_DECODER=y +CONFIG_IR_JVC_DECODER=y +CONFIG_IR_SONY_DECODER=y +CONFIG_IR_RC5_SZ_DECODER=y +CONFIG_IR_SANYO_DECODER=y +CONFIG_IR_MCE_KBD_DECODER=y +CONFIG_IR_LIRC_CODEC=y +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MC44S803=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_IR_I2C=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# MPEG video encoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# +CONFIG_MSM_VCAP=y +CONFIG_V4L_USB_DRIVERS=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set + +# +# Qualcomm MSM Camera And Video +# +CONFIG_MSM_CAMERA=y +# CONFIG_MSM_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_V4L2=y + +# +# Camera Sensor Selection +# +# CONFIG_ISX012 is not set +CONFIG_S5C73M3=y +CONFIG_S5K6A3YX=y +# CONFIG_S5K8AAY is not set +# CONFIG_MT9M114 is not set +# CONFIG_IMX074_ACT is not set +# CONFIG_S5K4E1 is not set +CONFIG_MSM_CAMERA_FLASH_SC628A=y +# CONFIG_IMX072 is not set +CONFIG_MSM_CAMERA_FLASH=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_ACTUATOR=y +CONFIG_MSM_GEMINI=y +CONFIG_QUP_EXCLUSIVE_TO_CAMERA=y + +# +# Camera Sensor Selection +# +# CONFIG_IMX074 is not set +# CONFIG_OV5647 is not set +# CONFIG_MSM_CAMERA_FLASH_TPS61310 is not set +# CONFIG_OV2720 is not set +# CONFIG_OV8825 is not set +# CONFIG_MSM_EEPROM is not set +# CONFIG_IMX074_EEPROM is not set +# CONFIG_IMX091_EEPROM is not set +CONFIG_MSM_MERCURY=y +# CONFIG_MSM_CAM_IRQ_ROUTER is not set +# CONFIG_MSM_CPP is not set +# CONFIG_MSM_CCI is not set +CONFIG_MSM_CSI20_HEADER=y +# CONFIG_MSM_CSI30_HEADER is not set +# CONFIG_MSM_CSIPHY is not set +# CONFIG_MSM_CSID is not set +# CONFIG_MSM_CSI2_REGISTER is not set +# CONFIG_MSM_ISPIF is not set +# CONFIG_S5K3L1YX is not set +# CONFIG_IMX091 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +# CONFIG_OV7692 is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_MSM_WFD=y +# CONFIG_RADIO_ADAPTERS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set +CONFIG_MSM_KGSL_2D=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 +CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24 +CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y +# CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +CONFIG_FB_VIRTUAL=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_VIDEO_MHL_V2=y +CONFIG_MHL_D3_SUPPORT=y +CONFIG_MHL_NEW_CBUS_MSC_CMD=y +CONFIG_MSM_VIDC=y +CONFIG_MSM_VIDC_1080P=y +CONFIG_MSM_VIDC_VENC=y +CONFIG_MSM_VIDC_VDEC=y +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_LCDC_HW=y +CONFIG_FB_MSM_TRIPLE_BUFFER=y +CONFIG_FB_MSM_MDP_HW=y +# CONFIG_FB_MSM_MDP22 is not set +# CONFIG_FB_MSM_MDP30 is not set +# CONFIG_FB_MSM_MDP31 is not set +CONFIG_FB_MSM_MDP40=y +# CONFIG_FB_MSM_MDSS is not set +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_EBI2 is not set +# CONFIG_FB_MSM_MDDI is not set +CONFIG_FB_MSM_MIPI_DSI=y +# CONFIG_FB_MSM_LCDC is not set +# CONFIG_FB_MSM_LVDS is not set +CONFIG_FB_MSM_OVERLAY=y +CONFIG_FB_MSM_DTV=y +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_TVOUT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA is not set +# CONFIG_FB_MSM_MDDI_ORISE is not set +# CONFIG_FB_MSM_MDDI_QUICKVX is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL is not set +# CONFIG_FB_MSM_MIPI_DSI_TOSHIBA is not set +# CONFIG_FB_MSM_MIPI_DSI_LGIT is not set +# CONFIG_FB_MSM_MIPI_DSI_RENESAS is not set +# CONFIG_FB_MSM_MIPI_DSI_SIMULATOR is not set +# CONFIG_FB_MSM_MIPI_DSI_NOVATEK is not set +# CONFIG_FB_MSM_MIPI_DSI_ORISE is not set +CONFIG_FB_MSM_MIPI_DSI_SAMSUNG_OLED=y +CONFIG_SAMSUNG_CMC624=y +# CONFIG_FB_MSM_LCDC_ST15_WXGA is not set +# CONFIG_FB_MSM_LCDC_ST15_PANEL is not set +# CONFIG_FB_MSM_LCDC_PRISM_WVGA is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335 is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT is not set +# CONFIG_FB_MSM_LCDC_NT35582_WVGA is not set +# CONFIG_FB_MSM_LCDC_WXGA is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO is not set +CONFIG_FB_MSM_NO_MDP_PIPE_CTRL=y +CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y +CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y +CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y +# CONFIG_FB_MSM_LCDC_PRISM_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_NT35582_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM is not set +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PRISM_WVGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA is not set +# CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128 is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF is not set +# CONFIG_FB_MSM_HDMI_AS_PRIMARY is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +CONFIG_MIPI_SAMSUNG_ESD_REFRESH=y +CONFIG_FB_MSM_EXT_INTERFACE_COMMON=y +CONFIG_FB_MSM_HDMI_COMMON=y +CONFIG_FB_MSM_HDMI_3D=y +# CONFIG_FB_MSM_HDMI_ADV7520_PANEL is not set +CONFIG_FB_MSM_HDMI_MSM_PANEL=y +CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT=y +# CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT is not set +# CONFIG_FB_MSM_HDMI_MHL_9244 is not set +# CONFIG_FB_MSM_HDMI_MHL_8334 is not set +# CONFIG_FB_MSM_TVOUT_NTSC_M is not set +# CONFIG_FB_MSM_TVOUT_NTSC_J is not set +# CONFIG_FB_MSM_TVOUT_PAL_BDGHIN is not set +# CONFIG_FB_MSM_TVOUT_PAL_M is not set +# CONFIG_FB_MSM_TVOUT_PAL_N is not set +CONFIG_FB_MSM_TVOUT_NONE=y +# CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565 is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888 is not set +CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888=y +# CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_AMS369FG06 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LM3530 is not set +# CONFIG_BACKLIGHT_LM3533 is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y + +# +# MSM SoC Audio support +# +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO=y +CONFIG_SND_SOC_MSM_QDSP6_INTF=y +# CONFIG_SND_SOC_MSM_QDSP6V2_INTF is not set +CONFIG_SND_SOC_VOICE=y +CONFIG_SND_SOC_QDSP6=y +# CONFIG_SND_SOC_QDSP6V2 is not set +CONFIG_SND_SOC_MSM8960=y +# CONFIG_SND_SOC_DUAL_AMIC is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WCD9304=y +CONFIG_SND_SOC_WCD9310=y +CONFIG_SND_SOC_CS8427=y +CONFIG_SND_SOC_MSM_STUB=y +# CONFIG_SND_SOC_TPA2028D is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +CONFIG_UHID=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +# CONFIG_HID_ACRUX is not set +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +# CONFIG_HID_PRODIKEYS is not set +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_HID_EMS_FF is not set +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_KEYTOUCH is not set +CONFIG_HID_KYE=y +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +# CONFIG_HID_LCPOWER is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=m +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +# CONFIG_HID_MULTITOUCH is not set +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LCD is not set +# CONFIG_HID_PICOLCD_LEDS is not set +# CONFIG_HID_PRIMAX is not set +CONFIG_HID_ROCCAT=y +# CONFIG_HID_SAITEK is not set +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +# CONFIG_GREENASIA_FF is not set +CONFIG_HID_SMARTJOYPLUS=y +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_HID_TIVO is not set +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WACOM_POWER_SUPPLY is not set +# CONFIG_HID_WIIMOTE is not set +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_MSM=y +# CONFIG_USB_EHCI_MSM_HSIC is not set +# CONFIG_USB_EHCI_MSM_HOST4 is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_PEHCI_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +CONFIG_USB_PRINTER=y +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=y +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +CONFIG_USB_SERIAL_QUALCOMM=y +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +CONFIG_USB_SERIAL_WWAN=y +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_CSVT is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_QCOM_DIAG_BRIDGE=y +# CONFIG_USB_QCOM_DIAG_BRIDGE_TEST is not set +CONFIG_USB_QCOM_MDM_BRIDGE=y +# CONFIG_USB_QCOM_KS_BRIDGE is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +CONFIG_USB_CI13XXX_MSM=y +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +# CONFIG_USB_MSM_72K is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_SUPERSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="" +CONFIG_RMNET_SMD_DATA_CHANNEL="" +CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y +# CONFIG_USB_ANDROID_CDC_ECM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_OTG_WAKELOCK is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_MSM_OTG_72K is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_USB_MSM_OTG=y +# CONFIG_USB_MSM_ACA is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_PERF_PROFILING is not set +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +# CONFIG_MMC_EMBEDDED_SDIO is not set +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +# CONFIG_MMC_BLOCK_BOUNCE is not set +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_BLOCK_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_MSM=y +CONFIG_MMC_MSM_SDC1_SUPPORT=y +CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y +# CONFIG_MMC_MSM_SDC2_SUPPORT is not set +CONFIG_MMC_MSM_SDC3_SUPPORT=y +# CONFIG_MMC_MSM_SDC3_POLLING is not set +# CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC3_WP_SUPPORT is not set +CONFIG_MMC_MSM_SDC4_SUPPORT=y +# CONFIG_MMC_MSM_SDC4_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC5_SUPPORT is not set +CONFIG_MMC_MSM_SPS_SUPPORT=y +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_MSM_PDM is not set +# CONFIG_LEDS_PMIC_MPP is not set +# CONFIG_LEDS_MSM_TRICOLOR is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_CPLD is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +CONFIG_LEDS_PM8XXX=y +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_MSM_PMIC is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set +# CONFIG_LEDS_TRIGGER_SLEEP is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_SWITCH_FSA8008 is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_VIDEO_MHL_TAB_V2 is not set +# CONFIG_MHL_SWING_LEVEL is not set +# CONFIG_ACCESSORY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_MSM is not set +# CONFIG_RTC_DRV_MSM7X00A is not set +CONFIG_RTC_DRV_PM8XXX=y +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +CONFIG_QCACHE=y +# CONFIG_FB_SM7XX is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_PERSISTENT_RAM=y +CONFIG_ANDROID_RAM_CONSOLE=y +# CONFIG_PERSISTENT_TRACER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +# CONFIG_ANDROID_SWITCH is not set +# CONFIG_ANDROID_INTF_ALARM_DEV is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set + +# +# Qualcomm Atheros Prima WLAN module +# +# CONFIG_PRIMA_WLAN is not set + +# +# Qualcomm MSM specific device drivers +# +CONFIG_MSM_SSBI=y +CONFIG_SPS=y +# CONFIG_USB_BAM is not set +CONFIG_SPS_SUPPORT_BAMDMA=y +# CONFIG_SPS_SUPPORT_NDP_BAM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_NEW_SENSORS=y +CONFIG_SENSORS_CORE=y +# CONFIG_BATTERY_SAMSUNG is not set +CONFIG_VIBETONZ=y + +# +# Hardware Spinlock drivers +# +CONFIG_IOMMU_SUPPORT=y +# CONFIG_MSM_IOMMU is not set + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MOBICORE_SUPPORT is not set +CONFIG_MSM_QDSS=y +# CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE is not set +CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_DEBUG_LIST=y +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +CONFIG_SCHED_TRACER=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_DYNAMIC_FTRACE=y +# CONFIG_FUNCTION_PROFILER is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_OLD_MCOUNT=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_RODATA is not set +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_NONE=y +# CONFIG_DEBUG_LL_UART is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_EARLY_PRINTK is not set +CONFIG_PID_IN_CONTEXTIDR=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +CONFIG_KEYS_DEBUG_PROC_KEYS=y +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_QCE40=y +CONFIG_CRYPTO_DEV_QCRYPTO=m +CONFIG_CRYPTO_DEV_QCE=m +CONFIG_CRYPTO_DEV_QCEDEV=m +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set diff --git a/arch/arm/configs/cyanogen_d2spr_defconfig b/arch/arm/configs/cyanogen_d2spr_defconfig new file mode 100644 index 00000000000..98fce33dc55 --- /dev/null +++ b/arch/arm/configs/cyanogen_d2spr_defconfig @@ -0,0 +1,3699 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARM_TICKET_LOCKS=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x80200000 +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-cyanogenmod" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_CGROUP_MEM_RES_CTLR is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +CONFIG_PERF_COUNTERS=y +CONFIG_DEBUG_PERF_USE_VMALLOC=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_TEST=m +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM7X01A is not set +# CONFIG_ARCH_MSM7X25 is not set +# CONFIG_ARCH_MSM7X27 is not set +# CONFIG_ARCH_MSM7X30 is not set +# CONFIG_ARCH_QSD8X50 is not set +# CONFIG_ARCH_MSM8X60 is not set +CONFIG_ARCH_MSM8960=y +# CONFIG_ARCH_MSM8930 is not set +CONFIG_ARCH_APQ8064=y +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_MPQ8092 is not set +# CONFIG_ARCH_MSM8226 is not set +# CONFIG_ARCH_FSM9XXX is not set +# CONFIG_ARCH_MSM9615 is not set +# CONFIG_ARCH_MSM8625 is not set +# CONFIG_ARCH_MSM9625 is not set +CONFIG_MSM_SOC_REV_NONE=y +# CONFIG_MSM_SOC_REV_A is not set +CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y +CONFIG_ARCH_MSM_KRAIT=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_KRAITMP=y +CONFIG_MSM_KRAIT_WFE_FIXUP=y +CONFIG_MSM_RPM=y +# CONFIG_MSM_RPM_SMD is not set +CONFIG_MSM_MPM=y +CONFIG_MSM_XO=y +CONFIG_MSM_REMOTE_SPINLOCK_SFPB=y + +# +# MSM Board Selection +# +# CONFIG_MACH_MSM8960_CDP is not set +# CONFIG_MACH_MSM8960_MTP is not set +# CONFIG_MACH_MSM8960_FLUID is not set +# CONFIG_MACH_MSM8960_LIQUID is not set +# CONFIG_MACH_APQ8064_CDP is not set +# CONFIG_MACH_APQ8064_MTP is not set +# CONFIG_MACH_APQ8064_LIQUID is not set +# CONFIG_MACH_MPQ8064_CDP is not set +# CONFIG_MACH_MPQ8064_HRD is not set +# CONFIG_MACH_MPQ8064_DTV is not set +# CONFIG_MACH_MSM_DUMMY is not set +CONFIG_MACH_M2=y +# CONFIG_MACH_M2_ATT is not set +CONFIG_MACH_M2_SPR=y +# CONFIG_MACH_M2_VZW is not set + +# +# LGE Board Selection +# +CONFIG_BOARD_HEADER_FILE="" +# CONFIG_MACH_APQ8064_MAKO is not set +# CONFIG_MACH_LGE_DUMMY is not set + +# +# LGE Specific Patches +# +# CONFIG_LGE_CRASH_HANDLER is not set +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_HAVE_END_MEM=y +CONFIG_END_MEM=0xffffffff +# CONFIG_KERNEL_MSM_CONTIG_MEM_REGION is not set +CONFIG_KERNEL_PMEM_EBI_REGION=y +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +CONFIG_MSM_HAS_DEBUG_UART_HS=y +CONFIG_DEBUG_MSM8960_UART=y +# CONFIG_DEBUG_APQ8064_UART is not set +CONFIG_MSM7X00A_USE_GP_TIMER=y +# CONFIG_MSM7X00A_USE_DG_TIMER is not set +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_HTC_HEADSET is not set +# CONFIG_HTC_PWRSINK is not set +# CONFIG_MSM_FIQ_SUPPORT is not set +# CONFIG_MSM_SERIAL_DEBUGGER is not set +# CONFIG_MSM_PROC_COMM is not set +CONFIG_MSM_SMD=y +# CONFIG_MSM_SMD_PKG3 is not set +CONFIG_MSM_SMD_PKG4=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_N_WAY_SMD=y +CONFIG_MSM_N_WAY_SMSM=y +CONFIG_MSM_RESET_MODEM=m +CONFIG_MSM_SMD_LOGGING=y +# CONFIG_MSM_IPC_LOGGING is not set +CONFIG_MSM_SMD_NMEA=y +# CONFIG_MSM_HSIC_TTY is not set +CONFIG_MSM_SMD_TTY=y +CONFIG_MSM_SMD_QMI=y +CONFIG_MSM_SMD_PKT=y +# CONFIG_MSM_DSPS is not set +# CONFIG_MSM_ONCRPCROUTER is not set +CONFIG_MSM_IPC_ROUTER=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +# CONFIG_MSM_DALRPC is not set +# CONFIG_MSM_CPU_FREQ_SET_MIN_MAX is not set +# CONFIG_MSM_AVS_HW is not set +# CONFIG_MSM_HW3D is not set +CONFIG_AMSS_7X25_VERSION_2009=y +# CONFIG_AMSS_7X25_VERSION_2008 is not set +CONFIG_RTAC=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +CONFIG_MSM_DMA_TEST=m +CONFIG_WIFI_CONTROL_FUNC=y +# CONFIG_WIFI_MEM_PREALLOC is not set +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +CONFIG_MSM_RPM_REGULATOR=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +# CONFIG_MSM_PIL_MODEM is not set +# CONFIG_MSM_PIL_QDSP6V3 is not set +CONFIG_MSM_PIL_QDSP6V4=y +# CONFIG_MSM_PIL_LPASS_QDSP6V5 is not set +# CONFIG_MSM_PIL_MSS_QDSP6V5 is not set +CONFIG_MSM_PIL_RIVA=y +CONFIG_MSM_PIL_TZAPPS=y +# CONFIG_MSM_PIL_DSPS is not set +CONFIG_MSM_PIL_VIDC=y +# CONFIG_MSM_PIL_VENUS is not set +# CONFIG_MSM_PIL_GSS is not set +# CONFIG_MSM_PIL_PRONTO is not set +CONFIG_MSM_SCM=y +CONFIG_MSM_MODEM_8960=y +CONFIG_MSM_LPASS_8960=y +# CONFIG_MSM_GSS_SSR_8064 is not set +CONFIG_MSM_BUSPM_DEV=m +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +# CONFIG_MSM_RPM_RBCPR_STATS_LOG is not set +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_MSM_GPIOMUX=y +CONFIG_MSM_NATIVE_RESTART=y +CONFIG_MSM_PM8X60=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y +CONFIG_MSM_WATCHDOG=y +# CONFIG_MSM_WATCHDOG_V2 is not set +# CONFIG_MSM_MEMORY_DUMP is not set +CONFIG_MSM_DLOAD_MODE=y +CONFIG_MSM_JTAG=y +# CONFIG_MSM_SLEEP_STATS_DEVICE is not set +CONFIG_MSM_RUN_QUEUE_STATS=y +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_BT_BCM4334=y +# CONFIG_MSM_FAKE_BATTERY is not set +CONFIG_MSM_QDSP6_APR=y +# CONFIG_MSM_QDSP6_APRV2 is not set +CONFIG_MSM_QDSP6_CODECS=y +# CONFIG_MSM_QDSP6V2_CODECS is not set +CONFIG_MSM_AUDIO_QDSP6=y +# CONFIG_MSM_AUDIO_QDSP6V2 is not set +# CONFIG_MSM_ULTRASOUND is not set +# CONFIG_MSM_SPM_V1 is not set +CONFIG_MSM_SPM_V2=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MULTIMEDIA_USE_ION=y +# CONFIG_MSM_OCMEM is not set +# CONFIG_MSM_RTB is not set +# CONFIG_MSM_EBI_ERP is not set +CONFIG_MSM_CACHE_ERP=y +CONFIG_MSM_L1_ERR_PANIC=y +# CONFIG_MSM_L1_ERR_LOG is not set +# CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS is not set +# CONFIG_MSM_L2_ERP_1BIT_PANIC is not set +CONFIG_MSM_L2_ERP_2BIT_PANIC=y +CONFIG_MSM_DCVS=y +# CONFIG_MSM_CPR is not set +CONFIG_HAVE_ARCH_HAS_CURRENT_TIMER=y +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_HSIC_SYSMON is not set +CONFIG_MSM_CPU_PWRCTL=y + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_VCM is not set +# CONFIG_STRICT_MEMORY_RWX is not set +CONFIG_ARM_NR_BANKS=8 +# CONFIG_RESERVE_FIRST_PAGE is not set +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_KSAPI is not set +CONFIG_ARM_GIC=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI is not set +# CONFIG_PCI_SYSCALL is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_ARM_ARCH_TIMER is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_VMALLOC_RESERVE=0x19000000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CLEANCACHE=y +# CONFIG_ARCH_MEMORY_PROBE is not set +# CONFIG_ARCH_MEMORY_REMOVE is not set +# CONFIG_ENABLE_DMM is not set +# CONFIG_FIX_MOVABLE_ZONE is not set +CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0=y +# CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG is not set +# CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE is not set +CONFIG_HOLES_IN_ZONE=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_SECCOMP is not set +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set +CONFIG_CP_ACCESS=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y +CONFIG_KEXEC_HARDBOOT=y +CONFIG_KEXEC_HB_PAGE_ADDR=0xfffff000 +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_FREQ_MSM=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +# CONFIG_CONSOLE_EARLYSUSPEND is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +CONFIG_NET_SCH_INGRESS=y +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +CONFIG_BT_HCISMD=y +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_IBS is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_MSM_SLEEP is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_MSM_BT_POWER is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_CFG80211=y +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +CONFIG_RFKILL_LEDS=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_BCM2079X is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_GENLOCK=y +CONFIG_GENLOCK_MISCDEVICE=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +# CONFIG_CMA is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +CONFIG_ANDROID_PMEM=y +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +# CONFIG_TSIF is not set +# CONFIG_TSPP is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_PMIC8XXX_VIBRATOR is not set +# CONFIG_ANDROID_VIBRATOR is not set +# CONFIG_TOUCHSENSE_VIBRATOR is not set +# CONFIG_PMIC8XXX_NFC is not set +# CONFIG_PMIC8XXX_UPL is not set +CONFIG_QSEECOM=y +# CONFIG_QFP_FUSE is not set +# CONFIG_BU52031NVX is not set +CONFIG_NFC_PN544=y +CONFIG_SEC_MISC=y +CONFIG_USB_SWITCH_FSA9485=y +CONFIG_MPU_411_ENABLE=y +# CONFIG_YAS_532_ENABLE is not set +# CONFIG_OPTICAL_GP2A is not set +# CONFIG_OPTICAL_GP2AP020A00F is not set +# CONFIG_OPTICAL_TAOS_TRITON is not set +# CONFIG_OPTICAL_TAOS_TMD2672X is not set +# CONFIG_SENSORS_AL3201 is not set +CONFIG_SENSORS_CM36651=y +CONFIG_VP_A2220=y +# CONFIG_ADC_STMPE811 is not set +CONFIG_SAMSUNG_JACK=y +# CONFIG_SAMSUNG_JACK_GNDLDET is not set +# CONFIG_OPTICAL_BH1721 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +CONFIG_MPU_SENSORS_TIMERIRQ_411=y +CONFIG_INV_SENSORS_411=y +# CONFIG_MPU_SENSORS_MPU3050_411 is not set +# CONFIG_MPU_SENSORS_MPU6050A2_411 is not set +CONFIG_MPU_SENSORS_MPU6050B1_411=y +CONFIG_INV_SENSORS_ACCELEROMETERS=y +CONFIG_MPU_SENSORS_MPU6050_ACCEL_411=y +CONFIG_INV_SENSORS_COMPASS=y +CONFIG_MPU_SENSORS_AK8975_411=y +# CONFIG_MPU_SENSORS_AK8972_411 is not set +# CONFIG_MPU_SENSORS_MMC314X_411 is not set +# CONFIG_MPU_SENSORS_AMI30X_411 is not set +# CONFIG_MPU_SENSORS_AMI306_411 is not set +# CONFIG_MPU_SENSORS_HMC5883_411 is not set +# CONFIG_MPU_SENSORS_LSM303DLX_M_411 is not set +# CONFIG_MPU_SENSORS_MMC314XMS_411 is not set +# CONFIG_MPU_SENSORS_YAS530_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD002B_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD004A_411 is not set +# CONFIG_MPU_USERSPACE_DEBUG is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +# CONFIG_SLIMPORT_ANX7808 is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=y +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_ENC28J60 is not set +# CONFIG_MSM_RMNET is not set +CONFIG_MSM_RMNET_BAM=y +# CONFIG_QFEC is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_SLIP=y +CONFIG_SLHC=y +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_SMART is not set +CONFIG_SLIP_MODE_SLIP6=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_LIBRA_SDIOIF is not set +# CONFIG_ATH6K_LEGACY_EXT is not set +# CONFIG_WCNSS_CORE is not set +# CONFIG_ATH_COMMON is not set +CONFIG_BCMDHD=m +# CONFIG_BCM4330 is not set +CONFIG_BCM4334=y +# CONFIG_BCM43241 is not set +CONFIG_BCMDHD_FW_PATH="/system/etc/wifi/bcmdhd_sta.bin_b2" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/nvram_net.txt" +# CONFIG_DHD_USE_STATIC_BUF is not set +# CONFIG_DHD_USE_SCHED_SCAN is not set +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_WLAN_REGION_CODE=100 +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PMIC8XXX is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_QCIKBD is not set +CONFIG_KEYBOARD_CYPRESS_TOUCH_236=y +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_QCITP is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +# CONFIG_JOYSTICK_XPAD_FF is not set +# CONFIG_JOYSTICK_XPAD_LEDS is not set +# CONFIG_TOUCHDISC_VTD518_SHINETSU is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +CONFIG_TOUCHSCREEN_MMS144=y +# CONFIG_TOUCHSCREEN_MMS136 is not set +# CONFIG_TOUCHSCREEN_MMS136_TABLET is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_MSM_LEGACY is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8C_TS is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC is not set +# CONFIG_TOUCHSCREEN_FT5X06 is not set +# CONFIG_TOUCHSCREEN_LGE_COMMON is not set +# CONFIG_TOUCHSCREEN_LGE_SYNAPTICS is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +CONFIG_INPUT_BMP180=y +# CONFIG_INPUT_PM8XXX_VIBRATOR is not set +CONFIG_INPUT_PMIC8XXX_PWRKEY=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BOSCH_BMA150 is not set +# CONFIG_STM_LIS3DH is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_VT_CONSOLE is not set +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_N_SMUX is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MSM=y +# CONFIG_SERIAL_MSM_CONSOLE is not set +CONFIG_SERIAL_MSM_HS=y +# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_MSM_SMD is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# SDIO support for DIAG +# + +# +# HSIC support for DIAG +# +CONFIG_DIAG_BRIDGE_CODE=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_MSM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +CONFIG_MSM_ROTATOR=y +# CONFIG_MMC_GENERIC_CSDIO is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_MSM is not set +CONFIG_I2C_QUP=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_QUP=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=m +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPMI is not set +CONFIG_SLIMBUS=y +# CONFIG_SLIMBUS_MSM_CTRL is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_MSM_V1 is not set +CONFIG_GPIO_MSM_V2=y +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_FSM9XXX is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_SX150X=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_GPIO_PM8XXX=y +CONFIG_GPIO_PM8XXX_MPP=y +# CONFIG_GPIO_PM8XXX_RPC is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +CONFIG_BATTERY_MAX17040=y +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_BATTERY_MSM is not set +# CONFIG_BATTERY_MSM8X60 is not set +# CONFIG_ISL9519_CHARGER is not set +# CONFIG_SMB137B_CHARGER is not set +# CONFIG_SMB349_CHARGER is not set +# CONFIG_BATTERY_BQ27520 is not set +# CONFIG_BATTERY_BQ27541 is not set +CONFIG_PM8921_CHARGER=y +CONFIG_PM8XXX_CCADC=y +# CONFIG_LTC4088_CHARGER is not set +# CONFIG_PM8921_BMS is not set +CONFIG_PM8921_SEC_CHARGER=y +CONFIG_BATTERY_CTIA=y +CONFIG_BATTERY_SEC=y +CONFIG_SAMSUNG_LPM_MODE=y +CONFIG_WIRELESS_CHARGING=y +# CONFIG_BATTERY_SAMSUNG_STRETTO is not set +# CONFIG_BATTERY_BCL is not set +CONFIG_CHARGER_SMB347=y +# CONFIG_WIRELESS_CHARGER is not set +# CONFIG_BATTERY_TEMP_CONTROL is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +CONFIG_SENSORS_PM8XXX_ADC=y +# CONFIG_SENSORS_EPM_ADC is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_MSM_POPMEM is not set +# CONFIG_THERMAL_TSENS is not set +CONFIG_THERMAL_TSENS8960=y +# CONFIG_THERMAL_TSENS8974 is not set +CONFIG_THERMAL_PM8XXX=y +CONFIG_THERMAL_MONITOR=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_PMIC8058 is not set +# CONFIG_PMIC8901 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +CONFIG_MFD_PM8XXX=y +CONFIG_MFD_PM8921_CORE=y +# CONFIG_MFD_PM8821_CORE is not set +# CONFIG_MFD_PM8018_CORE is not set +CONFIG_MFD_PM8038_CORE=y +CONFIG_MFD_PM8XXX_IRQ=y +# CONFIG_MFD_PM8821_IRQ is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +CONFIG_MFD_PM8XXX_DEBUG=y +CONFIG_MFD_PM8XXX_PWM=y +CONFIG_MFD_PM8XXX_MISC=y +CONFIG_MFD_PM8XXX_SPK=y +CONFIG_MFD_PM8XXX_BATT_ALARM=y +# CONFIG_WCD9304_CODEC is not set +CONFIG_WCD9310_CODEC=y +# CONFIG_WCD9320_CODEC is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_GPIO=y +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +CONFIG_REGULATOR_MAX8952=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_PM8XXX=y +CONFIG_REGULATOR_MSM_GPIO=y +# CONFIG_REGULATOR_STUB is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +# CONFIG_VIDEO_V4L2_SUBDEV_API is not set +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +CONFIG_RC_CORE=y +CONFIG_LIRC=y +# CONFIG_USER_RC_INPUT is not set +CONFIG_RC_MAP=y +CONFIG_IR_NEC_DECODER=y +CONFIG_IR_RC5_DECODER=y +CONFIG_IR_RC6_DECODER=y +CONFIG_IR_JVC_DECODER=y +CONFIG_IR_SONY_DECODER=y +CONFIG_IR_RC5_SZ_DECODER=y +CONFIG_IR_SANYO_DECODER=y +CONFIG_IR_MCE_KBD_DECODER=y +CONFIG_IR_LIRC_CODEC=y +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MC44S803=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_IR_I2C=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# MPEG video encoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# +CONFIG_MSM_VCAP=y +CONFIG_V4L_USB_DRIVERS=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set + +# +# Qualcomm MSM Camera And Video +# +CONFIG_MSM_CAMERA=y +# CONFIG_MSM_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_V4L2=y + +# +# Camera Sensor Selection +# +# CONFIG_ISX012 is not set +CONFIG_S5C73M3=y +CONFIG_S5K6A3YX=y +# CONFIG_S5K8AAY is not set +# CONFIG_MT9M114 is not set +# CONFIG_IMX074_ACT is not set +# CONFIG_S5K4E1 is not set +CONFIG_MSM_CAMERA_FLASH_SC628A=y +# CONFIG_IMX072 is not set +CONFIG_MSM_CAMERA_FLASH=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_ACTUATOR=y +CONFIG_MSM_GEMINI=y +CONFIG_QUP_EXCLUSIVE_TO_CAMERA=y + +# +# Camera Sensor Selection +# +# CONFIG_IMX074 is not set +# CONFIG_OV5647 is not set +# CONFIG_MSM_CAMERA_FLASH_TPS61310 is not set +# CONFIG_OV2720 is not set +# CONFIG_OV8825 is not set +# CONFIG_MSM_EEPROM is not set +# CONFIG_IMX074_EEPROM is not set +# CONFIG_IMX091_EEPROM is not set +CONFIG_MSM_MERCURY=y +# CONFIG_MSM_CAM_IRQ_ROUTER is not set +# CONFIG_MSM_CPP is not set +# CONFIG_MSM_CCI is not set +CONFIG_MSM_CSI20_HEADER=y +# CONFIG_MSM_CSI30_HEADER is not set +# CONFIG_MSM_CSIPHY is not set +# CONFIG_MSM_CSID is not set +# CONFIG_MSM_CSI2_REGISTER is not set +# CONFIG_MSM_ISPIF is not set +# CONFIG_S5K3L1YX is not set +# CONFIG_IMX091 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +# CONFIG_OV7692 is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_MSM_WFD=y +# CONFIG_RADIO_ADAPTERS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set +CONFIG_MSM_KGSL_2D=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 +CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24 +CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y +# CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +CONFIG_FB_VIRTUAL=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_VIDEO_MHL_V2=y +CONFIG_MHL_D3_SUPPORT=y +CONFIG_MHL_NEW_CBUS_MSC_CMD=y +CONFIG_MSM_VIDC=y +CONFIG_MSM_VIDC_1080P=y +CONFIG_MSM_VIDC_VENC=y +CONFIG_MSM_VIDC_VDEC=y +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_LCDC_HW=y +CONFIG_FB_MSM_TRIPLE_BUFFER=y +CONFIG_FB_MSM_MDP_HW=y +# CONFIG_FB_MSM_MDP22 is not set +# CONFIG_FB_MSM_MDP30 is not set +# CONFIG_FB_MSM_MDP31 is not set +CONFIG_FB_MSM_MDP40=y +# CONFIG_FB_MSM_MDSS is not set +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_EBI2 is not set +# CONFIG_FB_MSM_MDDI is not set +CONFIG_FB_MSM_MIPI_DSI=y +# CONFIG_FB_MSM_LCDC is not set +# CONFIG_FB_MSM_LVDS is not set +CONFIG_FB_MSM_OVERLAY=y +CONFIG_FB_MSM_DTV=y +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_TVOUT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA is not set +# CONFIG_FB_MSM_MDDI_ORISE is not set +# CONFIG_FB_MSM_MDDI_QUICKVX is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL is not set +# CONFIG_FB_MSM_MIPI_DSI_TOSHIBA is not set +# CONFIG_FB_MSM_MIPI_DSI_LGIT is not set +# CONFIG_FB_MSM_MIPI_DSI_RENESAS is not set +# CONFIG_FB_MSM_MIPI_DSI_SIMULATOR is not set +# CONFIG_FB_MSM_MIPI_DSI_NOVATEK is not set +# CONFIG_FB_MSM_MIPI_DSI_ORISE is not set +CONFIG_FB_MSM_MIPI_DSI_SAMSUNG_OLED=y +CONFIG_SAMSUNG_CMC624=y +# CONFIG_FB_MSM_LCDC_ST15_WXGA is not set +# CONFIG_FB_MSM_LCDC_ST15_PANEL is not set +# CONFIG_FB_MSM_LCDC_PRISM_WVGA is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335 is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT is not set +# CONFIG_FB_MSM_LCDC_NT35582_WVGA is not set +# CONFIG_FB_MSM_LCDC_WXGA is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO is not set +CONFIG_FB_MSM_NO_MDP_PIPE_CTRL=y +CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y +CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y +CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y +# CONFIG_FB_MSM_LCDC_PRISM_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_NT35582_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM is not set +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PRISM_WVGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA is not set +# CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128 is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF is not set +# CONFIG_FB_MSM_HDMI_AS_PRIMARY is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +CONFIG_MIPI_SAMSUNG_ESD_REFRESH=y +CONFIG_FB_MSM_EXT_INTERFACE_COMMON=y +CONFIG_FB_MSM_HDMI_COMMON=y +CONFIG_FB_MSM_HDMI_3D=y +# CONFIG_FB_MSM_HDMI_ADV7520_PANEL is not set +CONFIG_FB_MSM_HDMI_MSM_PANEL=y +CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT=y +# CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT is not set +# CONFIG_FB_MSM_HDMI_MHL_9244 is not set +# CONFIG_FB_MSM_HDMI_MHL_8334 is not set +# CONFIG_FB_MSM_TVOUT_NTSC_M is not set +# CONFIG_FB_MSM_TVOUT_NTSC_J is not set +# CONFIG_FB_MSM_TVOUT_PAL_BDGHIN is not set +# CONFIG_FB_MSM_TVOUT_PAL_M is not set +# CONFIG_FB_MSM_TVOUT_PAL_N is not set +CONFIG_FB_MSM_TVOUT_NONE=y +# CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565 is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888 is not set +CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888=y +# CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_AMS369FG06 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LM3530 is not set +# CONFIG_BACKLIGHT_LM3533 is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y + +# +# MSM SoC Audio support +# +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO=y +CONFIG_SND_SOC_MSM_QDSP6_INTF=y +# CONFIG_SND_SOC_MSM_QDSP6V2_INTF is not set +CONFIG_SND_SOC_VOICE=y +CONFIG_SND_SOC_QDSP6=y +# CONFIG_SND_SOC_QDSP6V2 is not set +CONFIG_SND_SOC_MSM8960=y +# CONFIG_SND_SOC_DUAL_AMIC is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WCD9304=y +CONFIG_SND_SOC_WCD9310=y +CONFIG_SND_SOC_CS8427=y +CONFIG_SND_SOC_MSM_STUB=y +# CONFIG_SND_SOC_TPA2028D is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +CONFIG_UHID=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +# CONFIG_HID_ACRUX is not set +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +# CONFIG_HID_PRODIKEYS is not set +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_HID_EMS_FF is not set +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_KEYTOUCH is not set +CONFIG_HID_KYE=y +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +# CONFIG_HID_LCPOWER is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=m +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +# CONFIG_HID_MULTITOUCH is not set +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LCD is not set +# CONFIG_HID_PICOLCD_LEDS is not set +# CONFIG_HID_PRIMAX is not set +CONFIG_HID_ROCCAT=y +# CONFIG_HID_SAITEK is not set +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +# CONFIG_GREENASIA_FF is not set +CONFIG_HID_SMARTJOYPLUS=y +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_HID_TIVO is not set +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WACOM_POWER_SUPPLY is not set +# CONFIG_HID_WIIMOTE is not set +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_MSM=y +# CONFIG_USB_EHCI_MSM_HSIC is not set +# CONFIG_USB_EHCI_MSM_HOST4 is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_PEHCI_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +CONFIG_USB_PRINTER=y +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=y +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +CONFIG_USB_SERIAL_QUALCOMM=y +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +CONFIG_USB_SERIAL_WWAN=y +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_CSVT is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_QCOM_DIAG_BRIDGE=y +# CONFIG_USB_QCOM_DIAG_BRIDGE_TEST is not set +CONFIG_USB_QCOM_MDM_BRIDGE=y +# CONFIG_USB_QCOM_KS_BRIDGE is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +CONFIG_USB_CI13XXX_MSM=y +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +# CONFIG_USB_MSM_72K is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_SUPERSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="" +CONFIG_RMNET_SMD_DATA_CHANNEL="" +CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y +# CONFIG_USB_ANDROID_CDC_ECM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_OTG_WAKELOCK is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_MSM_OTG_72K is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_USB_MSM_OTG=y +# CONFIG_USB_MSM_ACA is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_PERF_PROFILING is not set +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +# CONFIG_MMC_EMBEDDED_SDIO is not set +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +# CONFIG_MMC_BLOCK_BOUNCE is not set +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_BLOCK_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_MSM=y +CONFIG_MMC_MSM_SDC1_SUPPORT=y +CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y +# CONFIG_MMC_MSM_SDC2_SUPPORT is not set +CONFIG_MMC_MSM_SDC3_SUPPORT=y +# CONFIG_MMC_MSM_SDC3_POLLING is not set +# CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC3_WP_SUPPORT is not set +CONFIG_MMC_MSM_SDC4_SUPPORT=y +# CONFIG_MMC_MSM_SDC4_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC5_SUPPORT is not set +CONFIG_MMC_MSM_SPS_SUPPORT=y +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_MSM_PDM is not set +# CONFIG_LEDS_PMIC_MPP is not set +# CONFIG_LEDS_MSM_TRICOLOR is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_CPLD is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +CONFIG_LEDS_PM8XXX=y +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_MSM_PMIC is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set +# CONFIG_LEDS_TRIGGER_SLEEP is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_SWITCH_FSA8008 is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_VIDEO_MHL_TAB_V2 is not set +# CONFIG_MHL_SWING_LEVEL is not set +# CONFIG_ACCESSORY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_MSM is not set +# CONFIG_RTC_DRV_MSM7X00A is not set +CONFIG_RTC_DRV_PM8XXX=y +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +CONFIG_QCACHE=y +# CONFIG_FB_SM7XX is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_PERSISTENT_RAM=y +CONFIG_ANDROID_RAM_CONSOLE=y +# CONFIG_PERSISTENT_TRACER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +# CONFIG_ANDROID_SWITCH is not set +# CONFIG_ANDROID_INTF_ALARM_DEV is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set + +# +# Qualcomm Atheros Prima WLAN module +# +# CONFIG_PRIMA_WLAN is not set + +# +# Qualcomm MSM specific device drivers +# +CONFIG_MSM_SSBI=y +CONFIG_SPS=y +# CONFIG_USB_BAM is not set +CONFIG_SPS_SUPPORT_BAMDMA=y +# CONFIG_SPS_SUPPORT_NDP_BAM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_NEW_SENSORS=y +CONFIG_SENSORS_CORE=y +# CONFIG_BATTERY_SAMSUNG is not set +CONFIG_VIBETONZ=y + +# +# Hardware Spinlock drivers +# +CONFIG_IOMMU_SUPPORT=y +# CONFIG_MSM_IOMMU is not set + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MOBICORE_SUPPORT is not set +CONFIG_MSM_QDSS=y +# CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE is not set +CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_DEBUG_LIST=y +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +CONFIG_SCHED_TRACER=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_DYNAMIC_FTRACE=y +# CONFIG_FUNCTION_PROFILER is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_OLD_MCOUNT=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_RODATA is not set +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_NONE=y +# CONFIG_DEBUG_LL_UART is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_EARLY_PRINTK is not set +CONFIG_PID_IN_CONTEXTIDR=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +CONFIG_KEYS_DEBUG_PROC_KEYS=y +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_QCE40=y +CONFIG_CRYPTO_DEV_QCRYPTO=m +CONFIG_CRYPTO_DEV_QCE=m +CONFIG_CRYPTO_DEV_QCEDEV=m +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set diff --git a/arch/arm/configs/cyanogen_d2vzw_defconfig b/arch/arm/configs/cyanogen_d2vzw_defconfig new file mode 100644 index 00000000000..db712bd9c2b --- /dev/null +++ b/arch/arm/configs/cyanogen_d2vzw_defconfig @@ -0,0 +1,3699 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARM_TICKET_LOCKS=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x80200000 +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-cyanogenmod" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_CGROUP_MEM_RES_CTLR is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +CONFIG_PERF_COUNTERS=y +CONFIG_DEBUG_PERF_USE_VMALLOC=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_TEST=m +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM7X01A is not set +# CONFIG_ARCH_MSM7X25 is not set +# CONFIG_ARCH_MSM7X27 is not set +# CONFIG_ARCH_MSM7X30 is not set +# CONFIG_ARCH_QSD8X50 is not set +# CONFIG_ARCH_MSM8X60 is not set +CONFIG_ARCH_MSM8960=y +# CONFIG_ARCH_MSM8930 is not set +CONFIG_ARCH_APQ8064=y +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_MPQ8092 is not set +# CONFIG_ARCH_MSM8226 is not set +# CONFIG_ARCH_FSM9XXX is not set +# CONFIG_ARCH_MSM9615 is not set +# CONFIG_ARCH_MSM8625 is not set +# CONFIG_ARCH_MSM9625 is not set +CONFIG_MSM_SOC_REV_NONE=y +# CONFIG_MSM_SOC_REV_A is not set +CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y +CONFIG_ARCH_MSM_KRAIT=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_KRAITMP=y +CONFIG_MSM_KRAIT_WFE_FIXUP=y +CONFIG_MSM_RPM=y +# CONFIG_MSM_RPM_SMD is not set +CONFIG_MSM_MPM=y +CONFIG_MSM_XO=y +CONFIG_MSM_REMOTE_SPINLOCK_SFPB=y + +# +# MSM Board Selection +# +# CONFIG_MACH_MSM8960_CDP is not set +# CONFIG_MACH_MSM8960_MTP is not set +# CONFIG_MACH_MSM8960_FLUID is not set +# CONFIG_MACH_MSM8960_LIQUID is not set +# CONFIG_MACH_APQ8064_CDP is not set +# CONFIG_MACH_APQ8064_MTP is not set +# CONFIG_MACH_APQ8064_LIQUID is not set +# CONFIG_MACH_MPQ8064_CDP is not set +# CONFIG_MACH_MPQ8064_HRD is not set +# CONFIG_MACH_MPQ8064_DTV is not set +# CONFIG_MACH_MSM_DUMMY is not set +CONFIG_MACH_M2=y +# CONFIG_MACH_M2_ATT is not set +# CONFIG_MACH_M2_SPR is not set +CONFIG_MACH_M2_VZW=y + +# +# LGE Board Selection +# +CONFIG_BOARD_HEADER_FILE="" +# CONFIG_MACH_APQ8064_MAKO is not set +# CONFIG_MACH_LGE_DUMMY is not set + +# +# LGE Specific Patches +# +# CONFIG_LGE_CRASH_HANDLER is not set +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_HAVE_END_MEM=y +CONFIG_END_MEM=0xffffffff +# CONFIG_KERNEL_MSM_CONTIG_MEM_REGION is not set +CONFIG_KERNEL_PMEM_EBI_REGION=y +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +CONFIG_MSM_HAS_DEBUG_UART_HS=y +CONFIG_DEBUG_MSM8960_UART=y +# CONFIG_DEBUG_APQ8064_UART is not set +CONFIG_MSM7X00A_USE_GP_TIMER=y +# CONFIG_MSM7X00A_USE_DG_TIMER is not set +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_HTC_HEADSET is not set +# CONFIG_HTC_PWRSINK is not set +# CONFIG_MSM_FIQ_SUPPORT is not set +# CONFIG_MSM_SERIAL_DEBUGGER is not set +# CONFIG_MSM_PROC_COMM is not set +CONFIG_MSM_SMD=y +# CONFIG_MSM_SMD_PKG3 is not set +CONFIG_MSM_SMD_PKG4=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_N_WAY_SMD=y +CONFIG_MSM_N_WAY_SMSM=y +CONFIG_MSM_RESET_MODEM=m +CONFIG_MSM_SMD_LOGGING=y +# CONFIG_MSM_IPC_LOGGING is not set +CONFIG_MSM_SMD_NMEA=y +# CONFIG_MSM_HSIC_TTY is not set +CONFIG_MSM_SMD_TTY=y +CONFIG_MSM_SMD_QMI=y +CONFIG_MSM_SMD_PKT=y +# CONFIG_MSM_DSPS is not set +# CONFIG_MSM_ONCRPCROUTER is not set +CONFIG_MSM_IPC_ROUTER=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +# CONFIG_MSM_DALRPC is not set +# CONFIG_MSM_CPU_FREQ_SET_MIN_MAX is not set +# CONFIG_MSM_AVS_HW is not set +# CONFIG_MSM_HW3D is not set +CONFIG_AMSS_7X25_VERSION_2009=y +# CONFIG_AMSS_7X25_VERSION_2008 is not set +CONFIG_RTAC=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +CONFIG_MSM_DMA_TEST=m +CONFIG_WIFI_CONTROL_FUNC=y +# CONFIG_WIFI_MEM_PREALLOC is not set +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +CONFIG_MSM_RPM_REGULATOR=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +# CONFIG_MSM_PIL_MODEM is not set +# CONFIG_MSM_PIL_QDSP6V3 is not set +CONFIG_MSM_PIL_QDSP6V4=y +# CONFIG_MSM_PIL_LPASS_QDSP6V5 is not set +# CONFIG_MSM_PIL_MSS_QDSP6V5 is not set +CONFIG_MSM_PIL_RIVA=y +CONFIG_MSM_PIL_TZAPPS=y +# CONFIG_MSM_PIL_DSPS is not set +CONFIG_MSM_PIL_VIDC=y +# CONFIG_MSM_PIL_VENUS is not set +# CONFIG_MSM_PIL_GSS is not set +# CONFIG_MSM_PIL_PRONTO is not set +CONFIG_MSM_SCM=y +CONFIG_MSM_MODEM_8960=y +CONFIG_MSM_LPASS_8960=y +# CONFIG_MSM_GSS_SSR_8064 is not set +CONFIG_MSM_BUSPM_DEV=m +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +# CONFIG_MSM_RPM_RBCPR_STATS_LOG is not set +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_MSM_GPIOMUX=y +CONFIG_MSM_NATIVE_RESTART=y +CONFIG_MSM_PM8X60=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y +CONFIG_MSM_WATCHDOG=y +# CONFIG_MSM_WATCHDOG_V2 is not set +# CONFIG_MSM_MEMORY_DUMP is not set +CONFIG_MSM_DLOAD_MODE=y +CONFIG_MSM_JTAG=y +# CONFIG_MSM_SLEEP_STATS_DEVICE is not set +CONFIG_MSM_RUN_QUEUE_STATS=y +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_BT_BCM4334=y +# CONFIG_MSM_FAKE_BATTERY is not set +CONFIG_MSM_QDSP6_APR=y +# CONFIG_MSM_QDSP6_APRV2 is not set +CONFIG_MSM_QDSP6_CODECS=y +# CONFIG_MSM_QDSP6V2_CODECS is not set +CONFIG_MSM_AUDIO_QDSP6=y +# CONFIG_MSM_AUDIO_QDSP6V2 is not set +# CONFIG_MSM_ULTRASOUND is not set +# CONFIG_MSM_SPM_V1 is not set +CONFIG_MSM_SPM_V2=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MULTIMEDIA_USE_ION=y +# CONFIG_MSM_OCMEM is not set +# CONFIG_MSM_RTB is not set +# CONFIG_MSM_EBI_ERP is not set +CONFIG_MSM_CACHE_ERP=y +CONFIG_MSM_L1_ERR_PANIC=y +# CONFIG_MSM_L1_ERR_LOG is not set +# CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS is not set +# CONFIG_MSM_L2_ERP_1BIT_PANIC is not set +CONFIG_MSM_L2_ERP_2BIT_PANIC=y +CONFIG_MSM_DCVS=y +# CONFIG_MSM_CPR is not set +CONFIG_HAVE_ARCH_HAS_CURRENT_TIMER=y +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_HSIC_SYSMON is not set +CONFIG_MSM_CPU_PWRCTL=y + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_VCM is not set +# CONFIG_STRICT_MEMORY_RWX is not set +CONFIG_ARM_NR_BANKS=8 +# CONFIG_RESERVE_FIRST_PAGE is not set +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_KSAPI is not set +CONFIG_ARM_GIC=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI is not set +# CONFIG_PCI_SYSCALL is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_ARM_ARCH_TIMER is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_VMALLOC_RESERVE=0x19000000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CLEANCACHE=y +# CONFIG_ARCH_MEMORY_PROBE is not set +# CONFIG_ARCH_MEMORY_REMOVE is not set +# CONFIG_ENABLE_DMM is not set +# CONFIG_FIX_MOVABLE_ZONE is not set +CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0=y +# CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG is not set +# CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE is not set +CONFIG_HOLES_IN_ZONE=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_SECCOMP is not set +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set +CONFIG_CP_ACCESS=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y +CONFIG_KEXEC_HARDBOOT=y +CONFIG_KEXEC_HB_PAGE_ADDR=0xfffff000 +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_FREQ_MSM=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +# CONFIG_CONSOLE_EARLYSUSPEND is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +CONFIG_NET_SCH_INGRESS=y +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +CONFIG_BT_HCISMD=y +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_IBS is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_MSM_SLEEP is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_MSM_BT_POWER is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_CFG80211=y +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +CONFIG_RFKILL_LEDS=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_BCM2079X is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_GENLOCK=y +CONFIG_GENLOCK_MISCDEVICE=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +# CONFIG_CMA is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +CONFIG_ANDROID_PMEM=y +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +# CONFIG_TSIF is not set +# CONFIG_TSPP is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_PMIC8XXX_VIBRATOR is not set +# CONFIG_ANDROID_VIBRATOR is not set +# CONFIG_TOUCHSENSE_VIBRATOR is not set +# CONFIG_PMIC8XXX_NFC is not set +# CONFIG_PMIC8XXX_UPL is not set +CONFIG_QSEECOM=y +# CONFIG_QFP_FUSE is not set +# CONFIG_BU52031NVX is not set +CONFIG_NFC_PN544=y +CONFIG_SEC_MISC=y +CONFIG_USB_SWITCH_FSA9485=y +CONFIG_MPU_411_ENABLE=y +# CONFIG_YAS_532_ENABLE is not set +# CONFIG_OPTICAL_GP2A is not set +# CONFIG_OPTICAL_GP2AP020A00F is not set +# CONFIG_OPTICAL_TAOS_TRITON is not set +# CONFIG_OPTICAL_TAOS_TMD2672X is not set +# CONFIG_SENSORS_AL3201 is not set +CONFIG_SENSORS_CM36651=y +CONFIG_VP_A2220=y +# CONFIG_ADC_STMPE811 is not set +CONFIG_SAMSUNG_JACK=y +# CONFIG_SAMSUNG_JACK_GNDLDET is not set +# CONFIG_OPTICAL_BH1721 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +CONFIG_MPU_SENSORS_TIMERIRQ_411=y +CONFIG_INV_SENSORS_411=y +# CONFIG_MPU_SENSORS_MPU3050_411 is not set +# CONFIG_MPU_SENSORS_MPU6050A2_411 is not set +CONFIG_MPU_SENSORS_MPU6050B1_411=y +CONFIG_INV_SENSORS_ACCELEROMETERS=y +CONFIG_MPU_SENSORS_MPU6050_ACCEL_411=y +CONFIG_INV_SENSORS_COMPASS=y +CONFIG_MPU_SENSORS_AK8975_411=y +# CONFIG_MPU_SENSORS_AK8972_411 is not set +# CONFIG_MPU_SENSORS_MMC314X_411 is not set +# CONFIG_MPU_SENSORS_AMI30X_411 is not set +# CONFIG_MPU_SENSORS_AMI306_411 is not set +# CONFIG_MPU_SENSORS_HMC5883_411 is not set +# CONFIG_MPU_SENSORS_LSM303DLX_M_411 is not set +# CONFIG_MPU_SENSORS_MMC314XMS_411 is not set +# CONFIG_MPU_SENSORS_YAS530_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD002B_411 is not set +# CONFIG_MPU_SENSORS_HSCDTD004A_411 is not set +# CONFIG_MPU_USERSPACE_DEBUG is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +# CONFIG_SLIMPORT_ANX7808 is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=y +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_ENC28J60 is not set +# CONFIG_MSM_RMNET is not set +CONFIG_MSM_RMNET_BAM=y +# CONFIG_QFEC is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_SLIP=y +CONFIG_SLHC=y +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_SMART is not set +CONFIG_SLIP_MODE_SLIP6=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_LIBRA_SDIOIF is not set +# CONFIG_ATH6K_LEGACY_EXT is not set +# CONFIG_WCNSS_CORE is not set +# CONFIG_ATH_COMMON is not set +CONFIG_BCMDHD=m +# CONFIG_BCM4330 is not set +CONFIG_BCM4334=y +# CONFIG_BCM43241 is not set +CONFIG_BCMDHD_FW_PATH="/system/etc/wifi/bcmdhd_sta.bin_b2" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/nvram_net.txt" +# CONFIG_DHD_USE_STATIC_BUF is not set +# CONFIG_DHD_USE_SCHED_SCAN is not set +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_WLAN_REGION_CODE=100 +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PMIC8XXX is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_QCIKBD is not set +CONFIG_KEYBOARD_CYPRESS_TOUCH_236=y +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_QCITP is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +# CONFIG_JOYSTICK_XPAD_FF is not set +# CONFIG_JOYSTICK_XPAD_LEDS is not set +# CONFIG_TOUCHDISC_VTD518_SHINETSU is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +CONFIG_TOUCHSCREEN_MMS144=y +# CONFIG_TOUCHSCREEN_MMS136 is not set +# CONFIG_TOUCHSCREEN_MMS136_TABLET is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_MSM_LEGACY is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8C_TS is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC is not set +# CONFIG_TOUCHSCREEN_FT5X06 is not set +# CONFIG_TOUCHSCREEN_LGE_COMMON is not set +# CONFIG_TOUCHSCREEN_LGE_SYNAPTICS is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +CONFIG_INPUT_BMP180=y +# CONFIG_INPUT_PM8XXX_VIBRATOR is not set +CONFIG_INPUT_PMIC8XXX_PWRKEY=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BOSCH_BMA150 is not set +# CONFIG_STM_LIS3DH is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_VT_CONSOLE is not set +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_N_SMUX is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MSM=y +# CONFIG_SERIAL_MSM_CONSOLE is not set +CONFIG_SERIAL_MSM_HS=y +# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_MSM_SMD is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# SDIO support for DIAG +# + +# +# HSIC support for DIAG +# +CONFIG_DIAG_BRIDGE_CODE=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_MSM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +CONFIG_MSM_ROTATOR=y +# CONFIG_MMC_GENERIC_CSDIO is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_MSM is not set +CONFIG_I2C_QUP=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_QUP=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=m +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPMI is not set +CONFIG_SLIMBUS=y +# CONFIG_SLIMBUS_MSM_CTRL is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_MSM_V1 is not set +CONFIG_GPIO_MSM_V2=y +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_FSM9XXX is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_SX150X=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_GPIO_PM8XXX=y +CONFIG_GPIO_PM8XXX_MPP=y +# CONFIG_GPIO_PM8XXX_RPC is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +CONFIG_BATTERY_MAX17040=y +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_BATTERY_MSM is not set +# CONFIG_BATTERY_MSM8X60 is not set +# CONFIG_ISL9519_CHARGER is not set +# CONFIG_SMB137B_CHARGER is not set +# CONFIG_SMB349_CHARGER is not set +# CONFIG_BATTERY_BQ27520 is not set +# CONFIG_BATTERY_BQ27541 is not set +CONFIG_PM8921_CHARGER=y +CONFIG_PM8XXX_CCADC=y +# CONFIG_LTC4088_CHARGER is not set +# CONFIG_PM8921_BMS is not set +CONFIG_PM8921_SEC_CHARGER=y +CONFIG_BATTERY_CTIA=y +CONFIG_BATTERY_SEC=y +CONFIG_SAMSUNG_LPM_MODE=y +CONFIG_WIRELESS_CHARGING=y +# CONFIG_BATTERY_SAMSUNG_STRETTO is not set +# CONFIG_BATTERY_BCL is not set +CONFIG_CHARGER_SMB347=y +# CONFIG_WIRELESS_CHARGER is not set +# CONFIG_BATTERY_TEMP_CONTROL is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +CONFIG_SENSORS_PM8XXX_ADC=y +# CONFIG_SENSORS_EPM_ADC is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_MSM_POPMEM is not set +# CONFIG_THERMAL_TSENS is not set +CONFIG_THERMAL_TSENS8960=y +# CONFIG_THERMAL_TSENS8974 is not set +CONFIG_THERMAL_PM8XXX=y +CONFIG_THERMAL_MONITOR=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_PMIC8058 is not set +# CONFIG_PMIC8901 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +CONFIG_MFD_PM8XXX=y +CONFIG_MFD_PM8921_CORE=y +# CONFIG_MFD_PM8821_CORE is not set +# CONFIG_MFD_PM8018_CORE is not set +CONFIG_MFD_PM8038_CORE=y +CONFIG_MFD_PM8XXX_IRQ=y +# CONFIG_MFD_PM8821_IRQ is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +CONFIG_MFD_PM8XXX_DEBUG=y +CONFIG_MFD_PM8XXX_PWM=y +CONFIG_MFD_PM8XXX_MISC=y +CONFIG_MFD_PM8XXX_SPK=y +CONFIG_MFD_PM8XXX_BATT_ALARM=y +# CONFIG_WCD9304_CODEC is not set +CONFIG_WCD9310_CODEC=y +# CONFIG_WCD9320_CODEC is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_GPIO=y +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +CONFIG_REGULATOR_MAX8952=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_PM8XXX=y +CONFIG_REGULATOR_MSM_GPIO=y +# CONFIG_REGULATOR_STUB is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +# CONFIG_VIDEO_V4L2_SUBDEV_API is not set +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +CONFIG_RC_CORE=y +CONFIG_LIRC=y +# CONFIG_USER_RC_INPUT is not set +CONFIG_RC_MAP=y +CONFIG_IR_NEC_DECODER=y +CONFIG_IR_RC5_DECODER=y +CONFIG_IR_RC6_DECODER=y +CONFIG_IR_JVC_DECODER=y +CONFIG_IR_SONY_DECODER=y +CONFIG_IR_RC5_SZ_DECODER=y +CONFIG_IR_SANYO_DECODER=y +CONFIG_IR_MCE_KBD_DECODER=y +CONFIG_IR_LIRC_CODEC=y +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MC44S803=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_IR_I2C=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# MPEG video encoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# +CONFIG_MSM_VCAP=y +CONFIG_V4L_USB_DRIVERS=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set + +# +# Qualcomm MSM Camera And Video +# +CONFIG_MSM_CAMERA=y +# CONFIG_MSM_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_V4L2=y + +# +# Camera Sensor Selection +# +# CONFIG_ISX012 is not set +CONFIG_S5C73M3=y +CONFIG_S5K6A3YX=y +# CONFIG_S5K8AAY is not set +# CONFIG_MT9M114 is not set +# CONFIG_IMX074_ACT is not set +# CONFIG_S5K4E1 is not set +CONFIG_MSM_CAMERA_FLASH_SC628A=y +# CONFIG_IMX072 is not set +CONFIG_MSM_CAMERA_FLASH=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_ACTUATOR=y +CONFIG_MSM_GEMINI=y +CONFIG_QUP_EXCLUSIVE_TO_CAMERA=y + +# +# Camera Sensor Selection +# +# CONFIG_IMX074 is not set +# CONFIG_OV5647 is not set +# CONFIG_MSM_CAMERA_FLASH_TPS61310 is not set +# CONFIG_OV2720 is not set +# CONFIG_OV8825 is not set +# CONFIG_MSM_EEPROM is not set +# CONFIG_IMX074_EEPROM is not set +# CONFIG_IMX091_EEPROM is not set +CONFIG_MSM_MERCURY=y +# CONFIG_MSM_CAM_IRQ_ROUTER is not set +# CONFIG_MSM_CPP is not set +# CONFIG_MSM_CCI is not set +CONFIG_MSM_CSI20_HEADER=y +# CONFIG_MSM_CSI30_HEADER is not set +# CONFIG_MSM_CSIPHY is not set +# CONFIG_MSM_CSID is not set +# CONFIG_MSM_CSI2_REGISTER is not set +# CONFIG_MSM_ISPIF is not set +# CONFIG_S5K3L1YX is not set +# CONFIG_IMX091 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +# CONFIG_OV7692 is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_MSM_WFD=y +# CONFIG_RADIO_ADAPTERS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set +CONFIG_MSM_KGSL_2D=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 +CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24 +CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y +# CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +CONFIG_FB_VIRTUAL=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_VIDEO_MHL_V2=y +CONFIG_MHL_D3_SUPPORT=y +CONFIG_MHL_NEW_CBUS_MSC_CMD=y +CONFIG_MSM_VIDC=y +CONFIG_MSM_VIDC_1080P=y +CONFIG_MSM_VIDC_VENC=y +CONFIG_MSM_VIDC_VDEC=y +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_LCDC_HW=y +CONFIG_FB_MSM_TRIPLE_BUFFER=y +CONFIG_FB_MSM_MDP_HW=y +# CONFIG_FB_MSM_MDP22 is not set +# CONFIG_FB_MSM_MDP30 is not set +# CONFIG_FB_MSM_MDP31 is not set +CONFIG_FB_MSM_MDP40=y +# CONFIG_FB_MSM_MDSS is not set +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_EBI2 is not set +# CONFIG_FB_MSM_MDDI is not set +CONFIG_FB_MSM_MIPI_DSI=y +# CONFIG_FB_MSM_LCDC is not set +# CONFIG_FB_MSM_LVDS is not set +CONFIG_FB_MSM_OVERLAY=y +CONFIG_FB_MSM_DTV=y +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_TVOUT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA is not set +# CONFIG_FB_MSM_MDDI_ORISE is not set +# CONFIG_FB_MSM_MDDI_QUICKVX is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL is not set +# CONFIG_FB_MSM_MIPI_DSI_TOSHIBA is not set +# CONFIG_FB_MSM_MIPI_DSI_LGIT is not set +# CONFIG_FB_MSM_MIPI_DSI_RENESAS is not set +# CONFIG_FB_MSM_MIPI_DSI_SIMULATOR is not set +# CONFIG_FB_MSM_MIPI_DSI_NOVATEK is not set +# CONFIG_FB_MSM_MIPI_DSI_ORISE is not set +CONFIG_FB_MSM_MIPI_DSI_SAMSUNG_OLED=y +CONFIG_SAMSUNG_CMC624=y +# CONFIG_FB_MSM_LCDC_ST15_WXGA is not set +# CONFIG_FB_MSM_LCDC_ST15_PANEL is not set +# CONFIG_FB_MSM_LCDC_PRISM_WVGA is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335 is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT is not set +# CONFIG_FB_MSM_LCDC_NT35582_WVGA is not set +# CONFIG_FB_MSM_LCDC_WXGA is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO is not set +CONFIG_FB_MSM_NO_MDP_PIPE_CTRL=y +CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y +CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y +CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y +# CONFIG_FB_MSM_LCDC_PRISM_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_NT35582_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM is not set +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PRISM_WVGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA is not set +# CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128 is not set +# CONFIG_FB_MSM_MIPI_LGIT_VIDEO_WXGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL is not set +CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL=y +# CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF is not set +# CONFIG_FB_MSM_HDMI_AS_PRIMARY is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +CONFIG_MIPI_SAMSUNG_ESD_REFRESH=y +CONFIG_FB_MSM_EXT_INTERFACE_COMMON=y +CONFIG_FB_MSM_HDMI_COMMON=y +CONFIG_FB_MSM_HDMI_3D=y +# CONFIG_FB_MSM_HDMI_ADV7520_PANEL is not set +CONFIG_FB_MSM_HDMI_MSM_PANEL=y +CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT=y +# CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT is not set +# CONFIG_FB_MSM_HDMI_MHL_9244 is not set +# CONFIG_FB_MSM_HDMI_MHL_8334 is not set +# CONFIG_FB_MSM_TVOUT_NTSC_M is not set +# CONFIG_FB_MSM_TVOUT_NTSC_J is not set +# CONFIG_FB_MSM_TVOUT_PAL_BDGHIN is not set +# CONFIG_FB_MSM_TVOUT_PAL_M is not set +# CONFIG_FB_MSM_TVOUT_PAL_N is not set +CONFIG_FB_MSM_TVOUT_NONE=y +# CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565 is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888 is not set +CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888=y +# CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_AMS369FG06 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LM3530 is not set +# CONFIG_BACKLIGHT_LM3533 is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y + +# +# MSM SoC Audio support +# +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO=y +CONFIG_SND_SOC_MSM_QDSP6_INTF=y +# CONFIG_SND_SOC_MSM_QDSP6V2_INTF is not set +CONFIG_SND_SOC_VOICE=y +CONFIG_SND_SOC_QDSP6=y +# CONFIG_SND_SOC_QDSP6V2 is not set +CONFIG_SND_SOC_MSM8960=y +# CONFIG_SND_SOC_DUAL_AMIC is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WCD9304=y +CONFIG_SND_SOC_WCD9310=y +CONFIG_SND_SOC_CS8427=y +CONFIG_SND_SOC_MSM_STUB=y +# CONFIG_SND_SOC_TPA2028D is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +CONFIG_UHID=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +# CONFIG_HID_ACRUX is not set +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +# CONFIG_HID_PRODIKEYS is not set +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_HID_EMS_FF is not set +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_KEYTOUCH is not set +CONFIG_HID_KYE=y +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +# CONFIG_HID_LCPOWER is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=m +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +# CONFIG_HID_MULTITOUCH is not set +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LCD is not set +# CONFIG_HID_PICOLCD_LEDS is not set +# CONFIG_HID_PRIMAX is not set +CONFIG_HID_ROCCAT=y +# CONFIG_HID_SAITEK is not set +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +# CONFIG_GREENASIA_FF is not set +CONFIG_HID_SMARTJOYPLUS=y +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_HID_TIVO is not set +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WACOM_POWER_SUPPLY is not set +# CONFIG_HID_WIIMOTE is not set +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_MSM=y +# CONFIG_USB_EHCI_MSM_HSIC is not set +# CONFIG_USB_EHCI_MSM_HOST4 is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_PEHCI_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +CONFIG_USB_PRINTER=y +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=y +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +CONFIG_USB_SERIAL_QUALCOMM=y +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +CONFIG_USB_SERIAL_WWAN=y +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_CSVT is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_QCOM_DIAG_BRIDGE=y +# CONFIG_USB_QCOM_DIAG_BRIDGE_TEST is not set +CONFIG_USB_QCOM_MDM_BRIDGE=y +# CONFIG_USB_QCOM_KS_BRIDGE is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +CONFIG_USB_CI13XXX_MSM=y +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +# CONFIG_USB_MSM_72K is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_SUPERSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="" +CONFIG_RMNET_SMD_DATA_CHANNEL="" +CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y +# CONFIG_USB_ANDROID_CDC_ECM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_OTG_WAKELOCK is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_MSM_OTG_72K is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_USB_MSM_OTG=y +# CONFIG_USB_MSM_ACA is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_PERF_PROFILING is not set +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +# CONFIG_MMC_EMBEDDED_SDIO is not set +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +# CONFIG_MMC_BLOCK_BOUNCE is not set +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_BLOCK_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_MSM=y +CONFIG_MMC_MSM_SDC1_SUPPORT=y +CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y +# CONFIG_MMC_MSM_SDC2_SUPPORT is not set +CONFIG_MMC_MSM_SDC3_SUPPORT=y +# CONFIG_MMC_MSM_SDC3_POLLING is not set +# CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC3_WP_SUPPORT is not set +CONFIG_MMC_MSM_SDC4_SUPPORT=y +# CONFIG_MMC_MSM_SDC4_8_BIT_SUPPORT is not set +# CONFIG_MMC_MSM_SDC5_SUPPORT is not set +CONFIG_MMC_MSM_SPS_SUPPORT=y +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_MSM_PDM is not set +# CONFIG_LEDS_PMIC_MPP is not set +# CONFIG_LEDS_MSM_TRICOLOR is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_CPLD is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +CONFIG_LEDS_PM8XXX=y +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_MSM_PMIC is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set +# CONFIG_LEDS_TRIGGER_SLEEP is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_SWITCH_FSA8008 is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_VIDEO_MHL_TAB_V2 is not set +# CONFIG_MHL_SWING_LEVEL is not set +# CONFIG_ACCESSORY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_MSM is not set +# CONFIG_RTC_DRV_MSM7X00A is not set +CONFIG_RTC_DRV_PM8XXX=y +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +CONFIG_QCACHE=y +# CONFIG_FB_SM7XX is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_PERSISTENT_RAM=y +CONFIG_ANDROID_RAM_CONSOLE=y +# CONFIG_PERSISTENT_TRACER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +# CONFIG_ANDROID_SWITCH is not set +# CONFIG_ANDROID_INTF_ALARM_DEV is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set + +# +# Qualcomm Atheros Prima WLAN module +# +# CONFIG_PRIMA_WLAN is not set + +# +# Qualcomm MSM specific device drivers +# +CONFIG_MSM_SSBI=y +CONFIG_SPS=y +# CONFIG_USB_BAM is not set +CONFIG_SPS_SUPPORT_BAMDMA=y +# CONFIG_SPS_SUPPORT_NDP_BAM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_NEW_SENSORS=y +CONFIG_SENSORS_CORE=y +# CONFIG_BATTERY_SAMSUNG is not set +CONFIG_VIBETONZ=y + +# +# Hardware Spinlock drivers +# +CONFIG_IOMMU_SUPPORT=y +# CONFIG_MSM_IOMMU is not set + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MOBICORE_SUPPORT is not set +CONFIG_MSM_QDSS=y +# CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE is not set +CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_DEBUG_LIST=y +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +CONFIG_SCHED_TRACER=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_DYNAMIC_FTRACE=y +# CONFIG_FUNCTION_PROFILER is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_OLD_MCOUNT=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_RODATA is not set +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_NONE=y +# CONFIG_DEBUG_LL_UART is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_EARLY_PRINTK is not set +CONFIG_PID_IN_CONTEXTIDR=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +CONFIG_KEYS_DEBUG_PROC_KEYS=y +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_QCE40=y +CONFIG_CRYPTO_DEV_QCRYPTO=m +CONFIG_CRYPTO_DEV_QCE=m +CONFIG_CRYPTO_DEV_QCEDEV=m +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h index c2b9b4bdec0..632bc1504dd 100644 --- a/arch/arm/include/asm/kexec.h +++ b/arch/arm/include/asm/kexec.h @@ -17,6 +17,11 @@ #define KEXEC_ARM_ATAGS_OFFSET 0x1000 #define KEXEC_ARM_ZIMAGE_OFFSET 0x8000 +#ifdef CONFIG_KEXEC_HARDBOOT +#define KEXEC_HB_PAGE_ADDR UL(CONFIG_KEXEC_HB_PAGE_ADDR) +#define KEXEC_HB_PAGE_MAGIC 0x4a5db007 +#endif + #ifndef __ASSEMBLY__ /** @@ -53,6 +58,10 @@ static inline void crash_setup_regs(struct pt_regs *newregs, /* Function pointer to optional machine-specific reinitialization */ extern void (*kexec_reinit)(void); +#ifdef CONFIG_KEXEC_HARDBOOT +extern void (*kexec_hardboot_hook)(void); +#endif + #endif /* __ASSEMBLY__ */ #endif /* CONFIG_KEXEC */ diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h index f1068f8c7f6..9c04ee15b4c 100644 --- a/arch/arm/include/asm/mach/mmc.h +++ b/arch/arm/include/asm/mach/mmc.h @@ -154,6 +154,7 @@ struct mmc_platform_data { unsigned int sdiowakeup_irq; unsigned long irq_flags; unsigned long mmc_bus_width; + unsigned long mmc_erase_caps; int (*wpswitch) (struct device *); unsigned int msmsdcc_fmin; unsigned int msmsdcc_fmid; @@ -172,6 +173,7 @@ struct mmc_platform_data { bool disable_cmd23; u32 cpu_dma_latency; struct msm_mmc_bus_voting_data *msm_bus_voting_data; + struct msm_bus_scale_pdata *msm_bus_scale_data; }; #endif diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index dfcdb9f7c12..72ae6dd0b72 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -14,6 +14,7 @@ #include #include #include +#include extern const unsigned char relocate_new_kernel[]; extern const unsigned int relocate_new_kernel_size; @@ -23,6 +24,11 @@ extern unsigned long kexec_indirection_page; extern unsigned long kexec_mach_type; extern unsigned long kexec_boot_atags; +#ifdef CONFIG_KEXEC_HARDBOOT +extern unsigned long kexec_hardboot; +void (*kexec_hardboot_hook)(void); +#endif + static atomic_t waiting_for_crash_ipi; /* @@ -119,10 +125,13 @@ void machine_kexec(struct kimage *image) reboot_code_buffer = page_address(image->control_code_page); /* Prepare parameters for reboot_code_buffer*/ - kexec_start_address = image->start; - kexec_indirection_page = page_list; - kexec_mach_type = machine_arch_type; - kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET; + mem_text_write_kernel_word(&kexec_start_address, image->start); + mem_text_write_kernel_word(&kexec_indirection_page, page_list); + mem_text_write_kernel_word(&kexec_mach_type, machine_arch_type); + mem_text_write_kernel_word(&kexec_boot_atags, image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET); +#ifdef CONFIG_KEXEC_HARDBOOT + mem_text_write_kernel_word(&kexec_hardboot, image->hardboot); +#endif /* copy our kernel relocation code to the control code page */ memcpy(reboot_code_buffer, @@ -136,5 +145,12 @@ void machine_kexec(struct kimage *image) if (kexec_reinit) kexec_reinit(); +#ifdef CONFIG_KEXEC_HARDBOOT + if (image->hardboot && kexec_hardboot_hook) + /* Run any final machine-specific shutdown code. */ + kexec_hardboot_hook(); +#endif + soft_restart(reboot_code_buffer_phys); + } diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S index d0cdedf4864..d04427c3fb4 100644 --- a/arch/arm/kernel/relocate_kernel.S +++ b/arch/arm/kernel/relocate_kernel.S @@ -4,6 +4,13 @@ #include +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#ifdef CONFIG_ARCH_MSM8960 +#include +#endif +#endif + .globl relocate_new_kernel relocate_new_kernel: @@ -52,6 +59,12 @@ relocate_new_kernel: b 0b 2: +#ifdef CONFIG_KEXEC_HARDBOOT + ldr r0, kexec_hardboot + teq r0, #0 + bne hardboot +#endif + /* Jump to relocated kernel */ mov lr,r1 mov r0,#0 @@ -60,6 +73,35 @@ relocate_new_kernel: ARM( mov pc, lr ) THUMB( bx lr ) +#ifdef CONFIG_KEXEC_HARDBOOT +hardboot: + /* Stash boot arguments in hardboot page: + * 0: KEXEC_HB_PAGE_MAGIC + * 4: kexec_start_address + * 8: kexec_mach_type + * 12: kexec_boot_atags */ + ldr r0, =KEXEC_HB_PAGE_ADDR + str r1, [r0, #4] + ldr r1, kexec_mach_type + str r1, [r0, #8] + ldr r1, kexec_boot_atags + str r1, [r0, #12] + ldr r1, =KEXEC_HB_PAGE_MAGIC + str r1, [r0] + +#ifdef CONFIG_ARCH_MSM8960 + /* Hard reset via PMIC, decompressor jumps to kernel. */ + ldr r0, =MSM8960_TLMM_PHYS + mov r1, #0 + str r1, [r0, #0x820] @ PSHOLD_CTL_SU +loop: b loop +#else +#error "No reboot method defined for hardboot." +#endif + + .ltorg +#endif + .align .globl kexec_start_address @@ -79,6 +121,12 @@ kexec_mach_type: kexec_boot_atags: .long 0x0 +#ifdef CONFIG_KEXEC_HARDBOOT + .globl kexec_hardboot +kexec_hardboot: + .long 0x0 +#endif + relocate_new_kernel_end: .globl relocate_new_kernel_size diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index b012f0f4544..58eeaf70d61 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -957,7 +957,6 @@ void __init setup_arch(char **cmdline_p) *cmdline_p = cmd_line; parse_early_param(); - if (mdesc->init_very_early) mdesc->init_very_early(); @@ -966,8 +965,10 @@ void __init setup_arch(char **cmdline_p) arm_memblock_init(&meminfo, mdesc); paging_init(mdesc); + request_standard_resources(mdesc); + if (mdesc->restart) arm_pm_restart = mdesc->restart; diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 120a4e98b77..30fb221c0a7 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -176,7 +176,6 @@ config ARCH_MSM8960 select MSM_RUN_QUEUE_STATS select ARM_HAS_SG_CHAIN select MSM_KRAIT_WFE_FIXUP - select MSM_IOMMU_GPU_SYNC select MSM_CPU_PWRCTL config ARCH_MSM8930 @@ -210,7 +209,6 @@ config ARCH_MSM8930 select HOLES_IN_ZONE if SPARSEMEM select ARM_HAS_SG_CHAIN select MSM_KRAIT_WFE_FIXUP - select MSM_IOMMU_GPU_SYNC select MSM_CPU_PWRCTL config ARCH_APQ8064 @@ -239,7 +237,6 @@ config ARCH_APQ8064 select ARCH_SUPPORTS_MSI select ARM_HAS_SG_CHAIN select MSM_KRAIT_WFE_FIXUP - select MSM_IOMMU_GPU_SYNC select MSM_CPU_PWRCTL config ARCH_MSM8974 @@ -911,6 +908,38 @@ config MACH_FSM9XXX_SURF config MACH_MSM_DUMMY bool "NONE (No device)" +config MACH_M2 + depends on ARCH_MSM8960 + default n + select REGULATOR_MSM_GPIO + select HAVE_MEMBLOCK_NODE_MAP + select ARCH_SPARSEMEM_ENABLE + select HOLES_IN_ZONE if SPARSEMEMP + select MSM_MERCURY + bool "MSM8960 Samsung M2" + help + Support for Samsung M2 devices. + +config MACH_M2_ATT + depends on MACH_M2 + default n + bool "MSM8960 Samsung M2_ATT" + help + Support for the Samsung M2 AT&T device. + +config MACH_M2_SPR + depends on MACH_M2 + default n + bool "MSM8960 Samsung M2_SPR" + help + Support for the Samsung M2 Sprint device. + +config MACH_M2_VZW + depends on MACH_M2 + default n + bool "MSM8960 Samsung M2_VZW" + help + Support for the Samsung M2 Verizon device. endmenu source "arch/arm/mach-msm/lge/Kconfig" @@ -940,6 +969,13 @@ config PHYS_OFFSET default "0x40200000" if ARCH_MSM8X60 default "0x10000000" +config HAVE_END_MEM + bool "Specify highest physical RAM address at compile time" + +config END_MEM + hex "Highest physical address where system RAM resides" + depends on HAVE_END_MEM + config KERNEL_MSM_CONTIG_MEM_REGION bool "Enable in-kernel contiguous memory region" default y if ARCH_MSM8X60 @@ -957,6 +993,14 @@ config KERNEL_PMEM_SMI_REGION help Enable the in-kernel PMEM allocator to use SMI memory. +config KERNEL_PMEM_EBI_REGION + bool "Enable in-kernel PMEM region for EBI" + default y if ARCH_MSM8X60 + depends on ANDROID_PMEM && (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSMCOPPER) + help + Enable the in-kernel PMEM allocator to use EBI memory. + + config PMEM_GPU0 bool "Enable PMEM GPU0 region" default y @@ -2257,6 +2301,12 @@ config BT_MSM_PINTEST This driver provides support for verifying the MSM to BT pin connectivity. +config BT_BCM4334 + bool "Enable BCM4334 driver" + default n + help + Adds BCM4334 RFKILL driver for Broadcom BCM4334 chipset + config MSM_FAKE_BATTERY depends on POWER_SUPPLY default n diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 01de1639091..17099f7d8f9 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -302,6 +302,11 @@ obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-rfkill.o msm_vibrator.o +obj-$(CONFIG_MACH_M2) += board-mms-tsp.o board-bluetooth-bcm4334.o board-8960-wifi.o board-8960-regulator.o +obj-$(CONFIG_MACH_M2) += board-m2-camera.o board-m2-display.o board-m2-pmic.o board-m2-storage.o +obj-$(CONFIG_MACH_M2_ATT) += board-m2_att.o board-m2_att-gpiomux.o +obj-$(CONFIG_MACH_M2_SPR) += board-m2_spr.o board-m2_spr-gpiomux.o +obj-$(CONFIG_MACH_M2_VZW) += board-m2_vzw.o board-m2_vzw-gpiomux.o obj-$(CONFIG_MACH_LGE) += lge/ diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot index b57d4e1a735..6b9376a6dcf 100644 --- a/arch/arm/mach-msm/Makefile.boot +++ b/arch/arm/mach-msm/Makefile.boot @@ -38,6 +38,7 @@ endif # MSM8960 zreladdr-$(CONFIG_ARCH_MSM8960) := 0x80208000 +params_phys-$(CONFIG_ARCH_MSM8960) := 0x80200100 # MSM8930 zreladdr-$(CONFIG_ARCH_MSM8930) := 0x80208000 diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c index 44cd4c98111..756cbfd0bc6 100644 --- a/arch/arm/mach-msm/board-8960-regulator.c +++ b/arch/arm/mach-msm/board-8960-regulator.c @@ -34,6 +34,9 @@ VREG_CONSUMERS(L2) = { REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.0"), REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.1"), REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.2"), + REGULATOR_SUPPLY("mipi_csi_vdd", "4-003d"), + REGULATOR_SUPPLY("mipi_csi_vdd", "4-002d"), + REGULATOR_SUPPLY("mipi_csi_vdd", "4-0045"), }; VREG_CONSUMERS(L3) = { REGULATOR_SUPPLY("8921_l3", NULL), @@ -43,6 +46,10 @@ VREG_CONSUMERS(L4) = { REGULATOR_SUPPLY("8921_l4", NULL), REGULATOR_SUPPLY("HSUSB_1p8", "msm_otg"), REGULATOR_SUPPLY("iris_vddxo", "wcnss_wlan.0"), +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) + REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.4"), +#endif + REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.4"), }; VREG_CONSUMERS(L5) = { REGULATOR_SUPPLY("8921_l5", NULL), @@ -77,6 +84,10 @@ VREG_CONSUMERS(L11) = { REGULATOR_SUPPLY("cam_vana", "4-0048"), REGULATOR_SUPPLY("cam_vana", "4-0020"), REGULATOR_SUPPLY("cam_vana", "4-0034"), + REGULATOR_SUPPLY("cam_vana", "4-0010"), + REGULATOR_SUPPLY("cam_vana", "4-003d"), + REGULATOR_SUPPLY("cam_vana", "4-002d"), + REGULATOR_SUPPLY("cam_vana", "4-0045"), }; VREG_CONSUMERS(L12) = { REGULATOR_SUPPLY("8921_l12", NULL), @@ -85,6 +96,10 @@ VREG_CONSUMERS(L12) = { REGULATOR_SUPPLY("cam_vdig", "4-0048"), REGULATOR_SUPPLY("cam_vdig", "4-0020"), REGULATOR_SUPPLY("cam_vdig", "4-0034"), + REGULATOR_SUPPLY("cam_vdig", "4-0010"), + REGULATOR_SUPPLY("cam_vdig", "4-003d"), + REGULATOR_SUPPLY("cam_vdig", "4-002d"), + REGULATOR_SUPPLY("cam_vdig", "4-0045"), }; VREG_CONSUMERS(L14) = { REGULATOR_SUPPLY("8921_l14", NULL), @@ -101,12 +116,17 @@ VREG_CONSUMERS(L16) = { REGULATOR_SUPPLY("cam_vaf", "4-0048"), REGULATOR_SUPPLY("cam_vaf", "4-0020"), REGULATOR_SUPPLY("cam_vaf", "4-0034"), + REGULATOR_SUPPLY("cam_vaf", "4-0010"), + REGULATOR_SUPPLY("cam_vaf", "4-003d"), + REGULATOR_SUPPLY("cam_vaf", "4-002d"), + REGULATOR_SUPPLY("cam_vaf", "4-0045"), }; VREG_CONSUMERS(L17) = { REGULATOR_SUPPLY("8921_l17", NULL), }; VREG_CONSUMERS(L18) = { REGULATOR_SUPPLY("8921_l18", NULL), + REGULATOR_SUPPLY("camDVDD", "4-0045"), }; VREG_CONSUMERS(L21) = { REGULATOR_SUPPLY("8921_l21", NULL), @@ -117,6 +137,8 @@ VREG_CONSUMERS(L22) = { VREG_CONSUMERS(L23) = { REGULATOR_SUPPLY("8921_l23", NULL), REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"), + REGULATOR_SUPPLY("dsi_pll_vddio", "mdp.0"), + REGULATOR_SUPPLY("hdmi_pll_fs", "mdp.0"), REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"), REGULATOR_SUPPLY("pll_vdd", "pil_riva"), REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"), @@ -132,6 +154,8 @@ VREG_CONSUMERS(L25) = { REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "tabla-slim"), REGULATOR_SUPPLY("VDDD_CDC_D", "tabla2x-slim"), REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "tabla2x-slim"), + REGULATOR_SUPPLY("VDDD_CDC_D", NULL), + REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", NULL), }; VREG_CONSUMERS(L26) = { REGULATOR_SUPPLY("8921_l26", NULL), @@ -147,6 +171,7 @@ VREG_CONSUMERS(L28) = { }; VREG_CONSUMERS(L29) = { REGULATOR_SUPPLY("8921_l29", NULL), + REGULATOR_SUPPLY("cam_vio", NULL), }; VREG_CONSUMERS(S1) = { REGULATOR_SUPPLY("8921_s1", NULL), @@ -166,7 +191,8 @@ VREG_CONSUMERS(S4) = { REGULATOR_SUPPLY("8921_s4", NULL), REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.1"), REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.2"), - REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.4"), + /* Changed to L4 + REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.4"),*/ REGULATOR_SUPPLY("riva_vddpx", "wcnss_wlan.0"), REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"), REGULATOR_SUPPLY("VDDIO_CDC", "tabla-slim"), @@ -177,6 +203,10 @@ VREG_CONSUMERS(S4) = { REGULATOR_SUPPLY("CDC_VDD_CP", "tabla2x-slim"), REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla2x-slim"), REGULATOR_SUPPLY("CDC_VDDA_RX", "tabla2x-slim"), + REGULATOR_SUPPLY("VDDIO_CDC", NULL), + REGULATOR_SUPPLY("CDC_VDD_CP", NULL), + REGULATOR_SUPPLY("CDC_VDDA_TX", NULL), + REGULATOR_SUPPLY("CDC_VDDA_RX", NULL), REGULATOR_SUPPLY("vcc_i2c", "3-005b"), REGULATOR_SUPPLY("EXT_HUB_VDDIO", "msm_smsc_hub"), REGULATOR_SUPPLY("vcc_i2c", "10-0048"), @@ -220,6 +250,10 @@ VREG_CONSUMERS(LVS5) = { REGULATOR_SUPPLY("cam_vio", "4-0048"), REGULATOR_SUPPLY("cam_vio", "4-0020"), REGULATOR_SUPPLY("cam_vio", "4-0034"), + REGULATOR_SUPPLY("cam_vio", "4-0010"), + REGULATOR_SUPPLY("cam_vio", "4-003d"), + REGULATOR_SUPPLY("cam_vio", "4-002d"), + REGULATOR_SUPPLY("cam_vio", "4-0045"), }; /* This mapping is used for CDP only. */ VREG_CONSUMERS(CDP_LVS6) = { @@ -514,9 +548,13 @@ msm_pm8921_regulator_pdata[] __devinitdata = { 0, 2), PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 375000, 1050000, 200, "8921_s7", 0, 3), +#if defined(CONFIG_MACH_M2_SPR) || defined(CONFIG_MACH_M2_VZW) || defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_M2_DCM) + PM8XXX_LDO(L29, "8921_l29", 0, 1, 1800000, 1800000, 200, "8921_s8", + 0, 4), +#else PM8XXX_LDO(L29, "8921_l29", 0, 1, 2050000, 2100000, 200, "8921_s8", 0, 4), - +#endif /* ID name always_on pd en_t supply reg_ID */ PM8XXX_VS300(USB_OTG, "8921_usb_otg", 0, 1, 0, "ext_5v", 5), PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0, "ext_5v", 6), @@ -540,22 +578,40 @@ msm_rpm_regulator_init_data[] __devinitdata = { RPM_LDO(L5, 0, 1, 0, 2950000, 2950000, NULL, 0, 0), RPM_LDO(L6, 0, 1, 0, 2950000, 2950000, NULL, 0, 0), RPM_LDO(L7, 1, 1, 0, 1850000, 2950000, NULL, 10000, 10000), +#if defined(CONFIG_MACH_M2_SPR) || defined(CONFIG_MACH_M2_VZW) || defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_M2_DCM) + RPM_LDO(L8, 0, 1, 0, 3000000, 3100000, NULL, 0, 0), + RPM_LDO(L9, 0, 1, 0, 2850000, 2850000, NULL, 0, 0), +#else RPM_LDO(L8, 0, 1, 0, 2800000, 3000000, NULL, 0, 0), RPM_LDO(L9, 0, 1, 0, 3000000, 3000000, NULL, 0, 0), +#endif RPM_LDO(L10, 0, 1, 0, 3000000, 3000000, NULL, 0, 0), +#if defined(CONFIG_MACH_M2_SPR) || defined(CONFIG_MACH_M2_VZW) || defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_M2_DCM) + RPM_LDO(L11, 0, 1, 0, 2800000, 3300000, NULL, 0, 0), +#else RPM_LDO(L11, 0, 1, 0, 2850000, 2850000, NULL, 0, 0), +#endif RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0), RPM_LDO(L14, 0, 1, 0, 1800000, 1800000, NULL, 0, 0), RPM_LDO(L15, 0, 1, 0, 1800000, 2950000, NULL, 0, 0), +#if defined(CONFIG_MACH_M2_SPR) || defined(CONFIG_MACH_M2_VZW) || defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_M2_DCM) + RPM_LDO(L16, 0, 1, 0, 2800000, 3000000, NULL, 0, 0), + RPM_LDO(L17, 0, 1, 0, 1800000, 3300000, NULL, 0, 0), + RPM_LDO(L18, 0, 1, 0, 1300000, 1300000, "8921_s4", 0, 0), +#else RPM_LDO(L16, 0, 1, 0, 2800000, 2800000, NULL, 0, 0), RPM_LDO(L17, 0, 1, 0, 1800000, 2950000, NULL, 0, 0), - RPM_LDO(L18, 0, 1, 0, 1300000, 1300000, "8921_s4", 0, 0), + RPM_LDO(L18, 0, 1, 0, 1200000, 1500000, "8921_s4", 0, 0), +#endif RPM_LDO(L21, 0, 1, 0, 1900000, 1900000, "8921_s8", 0, 0), RPM_LDO(L22, 0, 1, 0, 2750000, 2750000, NULL, 0, 0), RPM_LDO(L23, 1, 1, 1, 1800000, 1800000, "8921_s8", 10000, 10000), RPM_LDO(L24, 0, 1, 1, 750000, 1150000, "8921_s1", 10000, 10000), +#if defined(CONFIG_MACH_M2_SPR) || defined(CONFIG_MACH_M2_VZW) || defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_M2_DCM) + RPM_LDO(L25, 1, 1, 0, 1225000, 1225000, "8921_s1", 10000, 10000), +#else RPM_LDO(L25, 1, 1, 0, 1250000, 1250000, "8921_s1", 10000, 10000), - +#endif /* ID a_on pd ss supply */ RPM_VS(LVS1, 0, 1, 0, "8921_s4"), RPM_VS(LVS2, 0, 1, 0, "8921_s1"), diff --git a/arch/arm/mach-msm/board-8960-wifi.c b/arch/arm/mach-msm/board-8960-wifi.c new file mode 100644 index 00000000000..9f20baeedc3 --- /dev/null +++ b/arch/arm/mach-msm/board-8960-wifi.c @@ -0,0 +1,357 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + +#define WLAN_STATIC_SCAN_BUF0 5 +#define WLAN_STATIC_SCAN_BUF1 6 +#define PREALLOC_WLAN_SEC_NUM 4 +#define PREALLOC_WLAN_BUF_NUM 160 +#define PREALLOC_WLAN_SECTION_HEADER 24 + +#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512) +#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) + +#define DHD_SKB_HDRSIZE 336 +#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) +#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) +#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) + +#define WLAN_SKB_BUF_NUM 17 + +static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM]; + +struct wlan_mem_prealloc { + void *mem_ptr; + unsigned long size; +}; + +static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = { + {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)} +}; + +void *wlan_static_scan_buf0; +void *wlan_static_scan_buf1; +static void *brcm_wlan_mem_prealloc(int section, unsigned long size) +{ + if (section == PREALLOC_WLAN_SEC_NUM) + return wlan_static_skb; + if (section == WLAN_STATIC_SCAN_BUF0) + return wlan_static_scan_buf0; + if (section == WLAN_STATIC_SCAN_BUF1) + return wlan_static_scan_buf1; + if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM)) + return NULL; + + if (wlan_mem_array[section].size < size) + return NULL; + + return wlan_mem_array[section].mem_ptr; +} + +static int brcm_init_wlan_mem(void) +{ + int i; + int j; + + for (i = 0; i < 8; i++) { + wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE); + if (!wlan_static_skb[i]) + goto err_skb_alloc; + } + + for (; i < 16; i++) { + wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE); + if (!wlan_static_skb[i]) + goto err_skb_alloc; + } + + wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE); + if (!wlan_static_skb[i]) + goto err_skb_alloc; + + for (i = 0 ; i < PREALLOC_WLAN_SEC_NUM ; i++) { + wlan_mem_array[i].mem_ptr = + kmalloc(wlan_mem_array[i].size, GFP_KERNEL); + + if (!wlan_mem_array[i].mem_ptr) + goto err_mem_alloc; + } + wlan_static_scan_buf0 = kmalloc(65536, GFP_KERNEL); + if (!wlan_static_scan_buf0) + goto err_mem_alloc; + wlan_static_scan_buf1 = kmalloc(65536, GFP_KERNEL); + if (!wlan_static_scan_buf1) + goto err_mem_alloc; + + printk(KERN_INFO"%s: WIFI MEM Allocated\n", __func__); + return 0; + + err_mem_alloc: + pr_err("Failed to mem_alloc for WLAN\n"); + for (j = 0 ; j < i ; j++) + kfree(wlan_mem_array[j].mem_ptr); + + i = WLAN_SKB_BUF_NUM; + + err_skb_alloc: + pr_err("Failed to skb_alloc for WLAN\n"); + for (j = 0 ; j < i ; j++) + dev_kfree_skb(wlan_static_skb[j]); + + return -ENOMEM; +} +#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ + + +static unsigned config_gpio_wl_reg_on[] = { + GPIO_CFG(GPIO_WL_REG_ON, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA) }; + +static unsigned config_gpio_wl_host_wake[] = { + GPIO_CFG(GPIO_WL_HOST_WAKE, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA) }; + + +int __init brcm_wifi_init_gpio(void) +{ + if (gpio_tlmm_config(config_gpio_wl_reg_on[0], GPIO_CFG_ENABLE)) + printk(KERN_ERR "%s: Failed to configure GPIO" + " - WL_REG_ON\n", __func__); + + if (gpio_request(GPIO_WL_REG_ON, "WL_REG_ON")) + printk(KERN_ERR "Failed to request gpio %d for WL_REG_ON\n", + GPIO_WL_REG_ON); + + if (gpio_direction_output(GPIO_WL_REG_ON, 0)) + printk(KERN_ERR "%s: WL_REG_ON " + "failed to pull down\n", __func__); + + + if (gpio_tlmm_config(config_gpio_wl_host_wake[0], GPIO_CFG_ENABLE)) + printk(KERN_ERR "%s: Failed to configure GPIO" + " - WL_HOST_WAKE\n", __func__); + + if (gpio_request(GPIO_WL_HOST_WAKE, "WL_HOST_WAKE")) + printk(KERN_ERR "Failed to request gpio for WL_HOST_WAKE\n"); + + if (gpio_direction_input(GPIO_WL_HOST_WAKE)) + printk(KERN_ERR "%s: WL_HOST_WAKE " + "failed to pull down\n", __func__); + + + return 0; +} + +static int brcm_wlan_power(int onoff) +{ + printk(KERN_INFO"------------------------------------------------"); + printk(KERN_INFO"------------------------------------------------\n"); + printk(KERN_INFO"%s Enter: power %s\n", __func__, onoff ? "on" : "off"); + if (onoff) { + /* + if (gpio_request(GPIO_WL_REG_ON, "WL_REG_ON")) + { + printk("Failed to request for WL_REG_ON\n"); + }*/ + if (gpio_direction_output(GPIO_WL_REG_ON, 1)) { + printk(KERN_ERR "%s: WL_REG_ON failed to pull up\n", + __func__); + return -EIO; + } + } else { + /* + if (gpio_request(GPIO_WL_REG_ON, "WL_REG_ON")) + { + printk("Failed to request for WL_REG_ON\n"); + } + */ + if (gpio_direction_output(GPIO_WL_REG_ON, 0)) { + printk(KERN_ERR "%s: WL_REG_ON failed to pull down\n", + __func__); + return -EIO; + } + } + return 0; +} + +static int brcm_wlan_reset(int onoff) +{ + /* + gpio_set_value(GPIO_WLAN_ENABLE, + onoff ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW); + */ + return 0; +} + + +static int brcm_wifi_cd; /* WIFI virtual 'card detect' status */ +static void (*wifi_status_cb)(int card_present, void *dev_id); +static void *wifi_status_cb_devid; + +int brcm_wifi_status_register( + void (*callback)(int card_present, void *dev_id), + void *dev_id) +{ + if (wifi_status_cb) + return -EAGAIN; + wifi_status_cb = callback; + wifi_status_cb_devid = dev_id; + printk(KERN_INFO "%s: callback is %p, devid is %p\n", + __func__, wifi_status_cb, dev_id); + return 0; +} + +#if 0 +static unsigned int brcm_wifi_status(struct device *dev) +{ + return brcm_wifi_cd; +} +#endif + +static int brcm_wlan_set_carddetect(int val) +{ + pr_debug("%s: wifi_status_cb : %p, devid : %p, val : %d\n", + __func__, wifi_status_cb, wifi_status_cb_devid, val); + brcm_wifi_cd = val; + if (wifi_status_cb) + wifi_status_cb(val, wifi_status_cb_devid); + else + pr_warning("%s: Nobody to notify\n", __func__); + + /* msleep(200); wait for carddetect */ + return 0; +} + +/* Customized Locale table : OPTIONAL feature */ +#define WLC_CNTRY_BUF_SZ 4 + +struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; + char custom_locale[WLC_CNTRY_BUF_SZ]; + int custom_locale_rev; +}; + +static struct cntry_locales_custom brcm_wlan_translate_custom_table[] = { + /* Table should be filled out based + on custom platform regulatory requirement */ + {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ + {"AE", "AE", 1}, + {"AR", "AR", 1}, + {"AT", "AT", 1}, + {"AU", "AU", 2}, + {"BE", "BE", 1}, + {"BG", "BG", 1}, + {"BN", "BN", 1}, + {"CA", "CA", 2}, + {"CH", "CH", 1}, + {"CY", "CY", 1}, + {"CZ", "CZ", 1}, + {"DE", "DE", 3}, + {"DK", "DK", 1}, + {"EE", "EE", 1}, + {"ES", "ES", 1}, + {"FI", "FI", 1}, + {"FR", "FR", 1}, + {"GB", "GB", 1}, + {"GR", "GR", 1}, + {"HR", "HR", 1}, + {"HU", "HU", 1}, + {"IE", "IE", 1}, + {"IS", "IS", 1}, + {"IT", "IT", 1}, + {"JP", "JP", 5}, + {"KR", "KR", 24}, + {"KW", "KW", 1}, + {"LI", "LI", 1}, + {"LT", "LT", 1}, + {"LU", "LU", 1}, + {"LV", "LV", 1}, + {"MA", "MA", 1}, + {"MT", "MT", 1}, + {"MX", "MX", 1}, + {"NL", "NL", 1}, + {"NO", "NO", 1}, + {"PL", "PL", 1}, + {"PT", "PT", 1}, + {"PY", "PY", 1}, + {"RO", "RO", 1}, + {"RU", "RU", 5}, + {"SE", "SE", 1}, + {"SG", "SG", 4}, + {"SI", "SI", 1}, + {"SK", "SK", 1}, + {"TR", "TR", 7}, + {"TW", "TW", 2}, + {"US", "US", 46} +}; + + +static void *brcm_wlan_get_country_code(char *ccode) +{ + int size = ARRAY_SIZE(brcm_wlan_translate_custom_table); + int i; + + if (!ccode) + return NULL; + + for (i = 0; i < size; i++) + if (strcmp(ccode, + brcm_wlan_translate_custom_table[i].iso_abbrev) == 0) + return &brcm_wlan_translate_custom_table[i]; + return &brcm_wlan_translate_custom_table[0]; +} + + +static struct resource brcm_wlan_resources[] = { + [0] = { + .name = "bcmdhd_wlan_irq", + .start = MSM_GPIO_TO_INT(GPIO_WL_HOST_WAKE), + .end = MSM_GPIO_TO_INT(GPIO_WL_HOST_WAKE), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE + | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct wifi_platform_data brcm_wlan_control = { + .set_power = brcm_wlan_power, + .set_reset = brcm_wlan_reset, + .set_carddetect = brcm_wlan_set_carddetect, +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + .mem_prealloc = brcm_wlan_mem_prealloc, +#endif + .get_country_code = brcm_wlan_get_country_code, +}; + +static struct platform_device brcm_device_wlan = { + .name = "bcmdhd_wlan", + .id = 1, + .num_resources = ARRAY_SIZE(brcm_wlan_resources), + .resource = brcm_wlan_resources, + .dev = { + .platform_data = &brcm_wlan_control, + }, +}; + +int __init brcm_wlan_init(void) +{ + printk(KERN_INFO"%s: start\n", __func__); + + brcm_wifi_init_gpio(); +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + brcm_init_wlan_mem(); +#endif + return platform_device_register(&brcm_device_wlan); +} diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h index ee0f25d1d1d..cb2a4fecaf6 100644 --- a/arch/arm/mach-msm/board-8960.h +++ b/arch/arm/mach-msm/board-8960.h @@ -49,6 +49,20 @@ extern struct regulator_init_data msm_saw_regulator_pdata_s6; extern struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata; /* GPIO SX150X */ +#if defined(CONFIG_TOUCHSCREEN_MMS144) || \ + defined(CONFIG_TOUCHSCREEN_MMS136) || \ + defined(CONFIG_TOUCHSCREEN_MMS136_TABLET) +extern void __init mms_tsp_input_init(void); +#endif + +#define PLATFORM_IS_CHARM25() \ + (machine_is_msm8960_cdp() && \ + (socinfo_get_platform_subtype() == 1) \ + ) +extern int gpio_rev(unsigned int); +extern int samsung_cmc624_on(int enable); +extern int samsung_has_cmc624(void); +#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE) enum { GPIO_EXPANDER_IRQ_BASE = (PM8921_IRQ_BASE + PM8921_NR_IRQS), GPIO_EXPANDER_GPIO_BASE = (PM8921_MPP_BASE + PM8921_NR_MPPS), @@ -64,7 +78,7 @@ enum { GPIO_CAM_GP_LED_EN2, GPIO_LIQUID_EXPANDER_BASE = GPIO_CAM_EXPANDER_BASE + 8, }; - +#endif enum { SX150X_CAM, SX150X_LIQUID, @@ -75,6 +89,7 @@ enum { extern struct sx150x_platform_data msm8960_sx150x_data[]; extern struct msm_camera_board_info msm8960_camera_board_info; +int msm8960_get_cable_type(void); void msm8960_init_cam(void); void msm8960_init_fb(void); void msm8960_init_pmic(void); @@ -88,9 +103,19 @@ void msm8960_pm8921_gpio_mpp_init(void); void msm8960_mdp_writeback(struct memtype_reserve *reserve_table); #define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4 #define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3 +#define MSM_8960_GSBI8_QUP_I2C_BUS_ID 8 #define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10 extern struct msm_rtb_platform_data msm8960_rtb_pdata; extern struct msm_cache_dump_platform_data msm8960_cache_dump_pdata; extern void msm8960_add_vidc_device(void); +extern void msm_otg_set_vbus_state(int); +extern void msm_otg_set_charging_state(bool); +extern void msm_otg_set_id_state(bool); + +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) +int brcm_wlan_init(void); +int brcm_wifi_status_register( + void (*callback)(int card_present, void *dev_id), void *dev_id); +#endif #endif diff --git a/arch/arm/mach-msm/board-bluetooth-bcm4334.c b/arch/arm/mach-msm/board-bluetooth-bcm4334.c new file mode 100644 index 00000000000..98c0bcee0a4 --- /dev/null +++ b/arch/arm/mach-msm/board-bluetooth-bcm4334.c @@ -0,0 +1,240 @@ +/* + * Bluetooth Broadcom GPIO and Low Power Mode control + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Copyright (C) 2011 Google, Inc. + * + * 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 "board-8960.h" +#include "devices.h" + +#define BT_UART_CFG +#define BT_LPM_ENABLE + +static struct rfkill *bt_rfkill; + +#ifdef BT_UART_CFG +static unsigned bt_uart_on_table[] = { + GPIO_CFG(GPIO_BT_UART_RTS, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, + GPIO_CFG_2MA), + GPIO_CFG(GPIO_BT_UART_CTS, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, + GPIO_CFG_2MA), + GPIO_CFG(GPIO_BT_UART_RXD, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, + GPIO_CFG_2MA), + GPIO_CFG(GPIO_BT_UART_TXD, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, + GPIO_CFG_2MA), +}; + +static unsigned bt_uart_off_table[] = { + GPIO_CFG(GPIO_BT_UART_RTS, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, + GPIO_CFG_2MA), + GPIO_CFG(GPIO_BT_UART_CTS, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, + GPIO_CFG_2MA), + GPIO_CFG(GPIO_BT_UART_RXD, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, + GPIO_CFG_2MA), + GPIO_CFG(GPIO_BT_UART_TXD, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, + GPIO_CFG_2MA), +}; +#endif + +static int bcm4334_bt_rfkill_set_power(void *data, bool blocked) +{ + /* rfkill_ops callback. Turn transmitter on when blocked is false */ + int pin, rc = 0; + + if (!blocked) { + pr_info("[BT] Bluetooth Power On.\n"); +#ifdef BT_UART_CFG + for (pin = 0; pin < ARRAY_SIZE(bt_uart_on_table); pin++) { + rc = gpio_tlmm_config(bt_uart_on_table[pin], + GPIO_CFG_ENABLE); + if (rc < 0) + pr_err("%s: gpio_tlmm_config(%#x)=%d\n", + __func__, bt_uart_on_table[pin], rc); + } +#endif + gpio_set_value(gpio_rev(BT_EN), 1); + msleep(50); + } else { +#ifdef BT_UART_CFG + for (pin = 0; pin < ARRAY_SIZE(bt_uart_off_table); pin++) { + rc = gpio_tlmm_config(bt_uart_off_table[pin], + GPIO_CFG_ENABLE); + if (rc < 0) + pr_err("%s: gpio_tlmm_config(%#x)=%d\n", + __func__, bt_uart_off_table[pin], rc); + } +#endif + pr_info("[BT] Bluetooth Power Off.\n"); + gpio_set_value(gpio_rev(BT_EN), 0); + } + return 0; +} + +static const struct rfkill_ops bcm4334_bt_rfkill_ops = { + .set_block = bcm4334_bt_rfkill_set_power, +}; + +static int bcm4334_bluetooth_probe(struct platform_device *pdev) +{ + int rc = 0; + + rc = gpio_request(gpio_rev(BT_EN), "bcm4334_bten_gpio"); + if (unlikely(rc)) { + pr_err("[BT] GPIO_BT_EN request failed.\n"); + return rc; + } + + gpio_tlmm_config(GPIO_CFG(GPIO_BT_UART_RTS, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(GPIO_BT_UART_CTS, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(GPIO_BT_UART_RXD, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(GPIO_BT_UART_TXD, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), GPIO_CFG_ENABLE); + + gpio_tlmm_config(GPIO_CFG(gpio_rev(BT_EN), 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + + gpio_direction_output(gpio_rev(BT_EN), 0); + + bt_rfkill = rfkill_alloc("bcm4334 Bluetooth", &pdev->dev, + RFKILL_TYPE_BLUETOOTH, &bcm4334_bt_rfkill_ops, + NULL); + + if (unlikely(!bt_rfkill)) { + pr_err("[BT] bt_rfkill alloc failed.\n"); + gpio_free(gpio_rev(BT_EN)); + return -ENOMEM; + } + + rfkill_init_sw_state(bt_rfkill, 0); + + rc = rfkill_register(bt_rfkill); + + if (unlikely(rc)) { + pr_err("[BT] bt_rfkill register failed.\n"); + rfkill_destroy(bt_rfkill); + gpio_free(gpio_rev(BT_EN)); + return -1; + } + + rfkill_set_sw_state(bt_rfkill, true); + + return rc; +} + +static int bcm4334_bluetooth_remove(struct platform_device *pdev) +{ + rfkill_unregister(bt_rfkill); + rfkill_destroy(bt_rfkill); + + gpio_free(gpio_rev(BT_EN)); + + return 0; +} + +static struct platform_driver bcm4334_bluetooth_platform_driver = { + .probe = bcm4334_bluetooth_probe, + .remove = bcm4334_bluetooth_remove, + .driver = { + .name = "bcm4334_bluetooth", + .owner = THIS_MODULE, + }, +}; + +#ifdef BT_LPM_ENABLE +static struct resource bluesleep_resources[] = { + { + .name = "gpio_host_wake", + .start = -1, + .end = -1, + .flags = IORESOURCE_IO, + }, + { + .name = "gpio_ext_wake", + .start = -1, + .end = -1, + .flags = IORESOURCE_IO, + }, + { + .name = "host_wake", + .start = -1, + .end = -1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device msm_bluesleep_device = { + .name = "bluesleep_bcm", + .id = -1, + .num_resources = ARRAY_SIZE(bluesleep_resources), + .resource = bluesleep_resources, +}; + +static void gpio_rev_init(void) +{ + bluesleep_resources[0].start = gpio_rev(BT_HOST_WAKE); + bluesleep_resources[0].end = gpio_rev(BT_HOST_WAKE); + bluesleep_resources[1].start = gpio_rev(BT_WAKE); + bluesleep_resources[1].end = gpio_rev(BT_WAKE); + bluesleep_resources[2].start = MSM_GPIO_TO_INT(gpio_rev(BT_HOST_WAKE)); + bluesleep_resources[2].end = MSM_GPIO_TO_INT(gpio_rev(BT_HOST_WAKE)); +} +#endif + +extern void bluesleep_setup_uart_port(struct platform_device *uart_dev); +static int __init bcm4334_bluetooth_init(void) +{ +#ifdef BT_LPM_ENABLE + gpio_rev_init(); + platform_device_register(&msm_bluesleep_device); + bluesleep_setup_uart_port(&msm_device_uart_dm6); +#endif + return platform_driver_register(&bcm4334_bluetooth_platform_driver); +} + +static void __exit bcm4334_bluetooth_exit(void) +{ +#ifdef BT_LPM_ENABLE + platform_device_unregister(&msm_bluesleep_device); +#endif + platform_driver_unregister(&bcm4334_bluetooth_platform_driver); +} + +module_init(bcm4334_bluetooth_init); +module_exit(bcm4334_bluetooth_exit); + +MODULE_ALIAS("platform:bcm4334"); +MODULE_DESCRIPTION("bcm4334_bluetooth"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/board-m2-camera.c b/arch/arm/mach-msm/board-m2-camera.c new file mode 100644 index 00000000000..256172261c1 --- /dev/null +++ b/arch/arm/mach-msm/board-m2-camera.c @@ -0,0 +1,1492 @@ +/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include "devices.h" +#include "board-8960.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_LEDS_AAT1290A +#include +#endif + +extern int system_rev; +#if (defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)) && \ + defined(CONFIG_I2C) + +#if 0 +static struct i2c_board_info cam_expander_i2c_info[] = { + { + I2C_BOARD_INFO("sx1508q", 0x22), + .platform_data = &msm8960_sx150x_data[SX150X_CAM] + }, +}; +static struct msm_cam_expander_info cam_expander_info[] = { + { + cam_expander_i2c_info, + MSM_8960_GSBI4_QUP_I2C_BUS_ID, + }, +}; +#endif +#endif + +static struct gpiomux_setting cam_settings[] = { + { + .func = GPIOMUX_FUNC_GPIO, /*suspend*/ + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + }, + + { + .func = GPIOMUX_FUNC_1, /*active 1*/ + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, + }, + + { + .func = GPIOMUX_FUNC_GPIO, /*active 2*/ + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, + }, + + { + .func = GPIOMUX_FUNC_1, /*active 3*/ + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, + }, + + { + .func = GPIOMUX_FUNC_5, /*active 4*/ + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, + }, + + { + .func = GPIOMUX_FUNC_6, /*active 5*/ + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, + }, + + { + .func = GPIOMUX_FUNC_2, /*active 6*/ + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, + }, + + { + .func = GPIOMUX_FUNC_3, /*active 7*/ + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, + }, + + { + .func = GPIOMUX_FUNC_GPIO, /*i2c suspend*/ + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_KEEPER, + }, + { + .func = GPIOMUX_FUNC_1, /* drive strength for D2*/ +#if defined(CONFIG_MACH_M2_VZW) + .drv = GPIOMUX_DRV_2MA, +#else + .drv = GPIOMUX_DRV_4MA, +#endif + .pull = GPIOMUX_PULL_NONE, + }, + { + .func = GPIOMUX_FUNC_4, /* sub camera of D2 */ + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, + }, + { + .func = GPIOMUX_FUNC_4, /*active 11 : sub camera of ApexQ*/ + .drv = GPIOMUX_DRV_4MA, + .pull = GPIOMUX_PULL_NONE, + }, +}; + +static struct msm_gpiomux_config msm8960_cam_common_configs[] = { +#ifdef CONFIG_S5C73M3 + { + .gpio = GPIO_MSM_FLASH_NOW, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[1], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, + { + .gpio = GPIO_CAM_MCLK0, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[9], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +#if !defined(CONFIG_MACH_M2_DCM) && !defined(CONFIG_MACH_K2_KDI) + { + .gpio = CAM2_RST_N, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[2], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +#endif + { + .gpio = ISP_RESET, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[2], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +#else +#if !defined(CONFIG_MACH_STRETTO) + { + .gpio = GPIO_MSM_FLASH_CNTL_EN, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[2], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +#endif + { + .gpio = GPIO_MSM_FLASH_NOW, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[2], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +#if !(defined(CONFIG_MACH_AEGIS2) || defined(CONFIG_MACH_JASPER)) + { + .gpio = GPIO_MAIN_CAM_STBY, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[2], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +#endif + { + .gpio = GPIO_CAM_MCLK, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[1], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +#if !defined(CONFIG_MACH_STRETTO) + { + .gpio = GPIO_VT_STBY, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[2], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +#endif + { + .gpio = GPIO_CAM2_RST_N, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[2], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, + { + .gpio = GPIO_CAM1_RST_N, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[2], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +#endif +}; + +#ifdef CONFIG_MSM_CAMERA + +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) +static struct msm_gpiomux_config msm8960_cam_2d_configs[] = { + { + .gpio = 2, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[2], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, + { + .gpio = 20, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[3], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, + { + .gpio = 21, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[3], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +}; + +static struct msm_gpiomux_config msm8960_cam_2d_configs_v2[] = { + { + .gpio = 2, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[10], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, + { + .gpio = 20, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[3], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, + { + .gpio = 21, + .settings = { + [GPIOMUX_ACTIVE] = &cam_settings[3], + [GPIOMUX_SUSPENDED] = &cam_settings[0], + }, + }, +}; + +static uint16_t msm_cam_gpio_2d_tbl[] = { + 5, /*CAMIF_MCLK*/ + 20, /*CAMIF_I2C_DATA*/ + 21, /*CAMIF_I2C_CLK*/ +}; + +static uint16_t msm_cam_gpio_2d_tbl_v2[] = { + 2, /*CAMIF_MCLK*/ + 20, /*CAMIF_I2C_DATA*/ + 21, /*CAMIF_I2C_CLK*/ +}; + +static struct msm_camera_gpio_conf rear_gpio_conf = { + .cam_gpiomux_conf_tbl = msm8960_cam_2d_configs, + .cam_gpiomux_conf_tbl_size = ARRAY_SIZE(msm8960_cam_2d_configs), + .cam_gpio_tbl = msm_cam_gpio_2d_tbl, + .cam_gpio_tbl_size = ARRAY_SIZE(msm_cam_gpio_2d_tbl), +}; + +static struct msm_camera_gpio_conf front_gpio_conf = { + .cam_gpiomux_conf_tbl = msm8960_cam_2d_configs, + .cam_gpiomux_conf_tbl_size = ARRAY_SIZE(msm8960_cam_2d_configs), + .cam_gpio_tbl = msm_cam_gpio_2d_tbl, + .cam_gpio_tbl_size = ARRAY_SIZE(msm_cam_gpio_2d_tbl), +}; + +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) +struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = { + .flash_trigger = GPIO_MSM_FLASH_NOW, + .flash_charge = GPIO_MSM_FLASH_CNTL_EN, + .flash_charge_done = GPIO_VFE_CAMIF_TIMER3_INT, + .flash_recharge_duration = 50000, + .irq = MSM_GPIO_TO_INT(GPIO_VFE_CAMIF_TIMER3_INT), +}; +#ifdef CONFIG_MSM_CAMERA_FLASH +#if 0 +static struct msm_camera_sensor_flash_src msm_flash_src = { + .flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT, + ._fsrc.ext_driver_src.led_en = GPIO_MSM_FLASH_CNTL_EN, + ._fsrc.ext_driver_src.led_flash_en = GPIO_MSM_FLASH_NOW, +}; +#endif +#endif +#endif + +static struct msm_bus_vectors cam_init_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, + { + .src = MSM_BUS_MASTER_VPE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, + { + .src = MSM_BUS_MASTER_JPEG_ENC, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors cam_preview_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 27648000, + .ib = 110592000, + }, + { + .src = MSM_BUS_MASTER_VPE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, + { + .src = MSM_BUS_MASTER_JPEG_ENC, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors cam_video_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 154275840, + .ib = 617103360, + }, + { + .src = MSM_BUS_MASTER_VPE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 206807040, + .ib = 488816640, + }, + { + .src = MSM_BUS_MASTER_JPEG_ENC, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors cam_snapshot_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 274423680, + .ib = 1097694720, + }, + { + .src = MSM_BUS_MASTER_VPE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, + { + .src = MSM_BUS_MASTER_JPEG_ENC, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 540000000, + .ib = 1350000000, + }, +}; + +static struct msm_bus_vectors cam_zsl_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 689376000, + .ib = 1208286720, + }, + { + .src = MSM_BUS_MASTER_VPE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, + { + .src = MSM_BUS_MASTER_JPEG_ENC, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 540000000, + .ib = 1350000000, + }, +}; + +static struct msm_bus_paths cam_bus_client_config[] = { + { + ARRAY_SIZE(cam_init_vectors), + cam_init_vectors, + }, + { + ARRAY_SIZE(cam_preview_vectors), + cam_preview_vectors, + }, + { + ARRAY_SIZE(cam_video_vectors), + cam_video_vectors, + }, + { + ARRAY_SIZE(cam_snapshot_vectors), + cam_snapshot_vectors, + }, + { + ARRAY_SIZE(cam_zsl_vectors), + cam_zsl_vectors, + }, +}; + +static struct msm_bus_scale_pdata cam_bus_client_pdata = { + cam_bus_client_config, + ARRAY_SIZE(cam_bus_client_config), + .name = "msm_camera", +}; + +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) +static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = { + { + .ioclk.mclk_clk_rate = 24000000, + .ioclk.vfe_clk_rate = 228570000, + .csid_core = 0, + .cam_bus_scale_table = &cam_bus_client_pdata, + }, + { + .ioclk.mclk_clk_rate = 24000000, + .ioclk.vfe_clk_rate = 228570000, + .csid_core = 1, + .cam_bus_scale_table = &cam_bus_client_pdata, + }, +}; +#endif + +static struct regulator *l29, *l28, *isp_core; +/* CAM power + CAM_SENSOR_A_2.8 : GPIO_CAM_A_EN(GPIO 46) + CAM_SENSOR_IO_1.8 : VREG_L29 : l29 + CAM_AF_2.8 : VREG_L11 : l11 + CAM_SENSOR_CORE1.2 : VREG_L12 : l12 + CAM_ISP_CORE_1.2 : CAM_CORE_EN(GPIO 6) + + CAM_DVDD_1.5 : VREG_L18 : l18 +*/ + +static int vddCore = 1150000; +static bool isVddCoreSet; +static u8 gpio_cam_flash_sw; +static u8 pmic_gpio_msm_flash_cntl_en; +static bool isFlashCntlEn; + +static void cam_set_isp_core(int level) +{ + if (level == 1050000) { + pr_err("Change core voltage\n"); + vddCore = 1100000; + } else + vddCore = level; + + isVddCoreSet = true; + pr_err("ISP CORE = %d\n", vddCore); +} + +static bool cam_is_vdd_core_set(void) +{ + return isVddCoreSet; +} + +static void cam_ldo_power_on(int mode, int num) +{ + int ret = 0; + int temp = 0; + + printk(KERN_DEBUG "[%s : %d] %s CAMERA POWER ON!!\n", + __func__, __LINE__, mode ? "FRONT" : "REAR"); + + if (mode) { /* front camera */ + if (num == 0) { + /* ISP CORE 1.2V */ + /* delete for unnecessary power */ + /* 8M AVDD 2.8V */ + gpio_set_value_cansleep(GPIO_CAM_A_EN, 1); + temp = gpio_get_value(GPIO_CAM_A_EN); + printk(KERN_DEBUG "[s5k6a3yx] check GPIO_CAM_A_EN : %d\n", + temp); + usleep(1*1000); + } else { + /* VT_RESET */ + #if defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + gpio_set_value_cansleep(gpio_rev(CAM2_RST_N), 1); + temp = gpio_get_value(gpio_rev(CAM2_RST_N)); + #else + gpio_set_value_cansleep(CAM2_RST_N, 1); + temp = gpio_get_value(CAM2_RST_N); + #endif + printk(KERN_DEBUG "[s5k6a3yx] check CAM2_RST_N : %d\n", + temp); + usleep(1*1000); + + /* ISP 8M HOST 1.8V */ + l29 = regulator_get(NULL, "8921_lvs5"); + ret = regulator_enable(l29); + if (ret) + cam_err("error enabling regulator\n"); + usleep(1*1000); + + /* ISP 8M MIPI 1.2V */ + /* delete for unnecessary power */ + } + } else { /* rear camera */ + if (num == 0) { + printk(KERN_DEBUG "[s5c73m3] rear camera on 1\n"); + + temp = gpio_get_value(GPIO_MSM_FLASH_NOW); + + if (isFlashCntlEn == 0 && temp == 0) { + /* FLASH_LED_UNLOCK*/ + gpio_set_value_cansleep(PM8921_MPP_PM_TO_SYS + (PMIC_MPP_FLASH_LED_UNLOCK), 1); + /* GPIO_CAM_FLASH_SW : tourch */ + gpio_set_value_cansleep(gpio_cam_flash_sw, 1); + temp = gpio_get_value(gpio_cam_flash_sw); + printk(KERN_DEBUG "[s5c73m3] check" + " GPIO_CAM_FLASH_SW : %d\n", temp); + usleep(1*1000); + } + + /* flash power 1.8V */ + l28 = regulator_get(NULL, "8921_lvs4"); + ret = regulator_enable(l28); + if (ret) + cam_err("error enabling regulator\n"); + usleep(1*1000); + + /* ISP CORE 1.2V */ +#ifdef CONFIG_MACH_M2_ATT + if (system_rev >= BOARD_REV03) { + printk(KERN_DEBUG "[s5c73m3] check vddCore : %d\n", + vddCore); + + isp_core = regulator_get(NULL, "cam_isp_core"); + ret = regulator_set_voltage(isp_core, + vddCore, vddCore); + if (ret) + cam_err("error setting voltage\n"); + + ret = regulator_enable(isp_core); + if (ret) + cam_err("error enabling regulator."); + } +#elif defined(CONFIG_MACH_M2_VZW) + if (system_rev >= BOARD_REV08) { + printk(KERN_DEBUG "[s5c73m3] vzw check vddCore : %d\n", + vddCore); + + isp_core = regulator_get(NULL, "cam_isp_core"); + ret = regulator_set_voltage(isp_core, + vddCore, vddCore); + if (ret) + cam_err("error setting voltage\n"); + + ret = regulator_enable(isp_core); + if (ret) + cam_err("error enabling regulator."); + } else + gpio_set_value_cansleep(CAM_CORE_EN, 1); +#elif defined(CONFIG_MACH_M2_SPR) + if (system_rev >= BOARD_REV03) { + printk(KERN_DEBUG "[s5c73m3] spr check vddCore : %d\n", + vddCore); + + isp_core = regulator_get(NULL, "cam_isp_core"); + ret = regulator_set_voltage(isp_core, + vddCore, vddCore); + if (ret) + cam_err("error setting voltage\n"); + + ret = regulator_enable(isp_core); + if (ret) + cam_err("error enabling regulator."); + } else + gpio_set_value_cansleep(CAM_CORE_EN, 1); +#elif defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + gpio_set_value_cansleep(gpio_rev(CAM_CORE_EN), 1); +#else + gpio_set_value_cansleep(CAM_CORE_EN, 1); +#endif + usleep(1200); + + /* 8M AVDD 2.8V */ + gpio_set_value_cansleep(GPIO_CAM_A_EN, 1); + temp = gpio_get_value(GPIO_CAM_A_EN); + printk(KERN_DEBUG "[s5c73m3] check GPIO_CAM_A_EN : %d\n", + temp); + usleep(1*1000); + + /* 8M DVDD 1.2V */ + gpio_set_value_cansleep(GPIO_CAM_SENSOR_EN, 1); + temp = gpio_get_value(GPIO_CAM_SENSOR_EN); + printk(KERN_DEBUG "[s5c73m3] check GPIO_CAM_SENSOR_EN : %d\n", + temp); + usleep(1*1000); + } else { + printk(KERN_DEBUG "[s5c73m3] rear camera on 2\n"); + /* AF 2.8V */ + gpio_set_value_cansleep(gpio_rev(CAM_AF_EN), 1); + temp = gpio_get_value(gpio_rev(CAM_AF_EN)); + printk(KERN_DEBUG "[s5c73m3] check CAM_AF_EN : %d\n", + temp); + usleep(3*1000); + + /* ISP 8M HOST 1.8V */ + l29 = regulator_get(NULL, "8921_lvs5"); + ret = regulator_enable(l29); + if (ret) + cam_err("error enabling regulator\n"); + + /* ISP 8M MIPI 1.2V */ + gpio_set_value_cansleep(CAM_MIPI_EN, 1); + temp = gpio_get_value(CAM_MIPI_EN); + printk(KERN_DEBUG "[s5c73m3] check CAM_MIPI_EN : %d\n", + temp); + usleep(1*1000); + + /* ISP_STANDBY */ + gpio_set_value_cansleep(PM8921_GPIO_PM_TO_SYS(24), 1); + usleep(1*1000); + + /* ISP_RESET */ + gpio_set_value_cansleep(ISP_RESET, 1); + temp = gpio_get_value(ISP_RESET); + printk(KERN_DEBUG "[s5c73m3] check ISP_RESET : %d\n", + temp); + usleep(1*1000); + } + } + +} + +static void cam_ldo_power_off(int mode) +{ + int ret = 0; + int temp = 0; + + printk(KERN_DEBUG "[%s : %d] %s CAMERA POWER OFF!!\n", + __func__, __LINE__, mode ? "FRONT" : "REAR"); + + if (mode) { /* front camera */ + /* VT_RESET */ +#if defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + gpio_set_value_cansleep(gpio_rev(CAM2_RST_N), 0); + usleep(1*1000); +#else + gpio_set_value_cansleep(CAM2_RST_N, 0); + usleep(1*1000); +#endif + /* ISP 8M MIPI 1.2V */ + /* delete for unnecessary power */ + + + /* ISP 8M HOST 1.8V */ + if (l29) { + ret = regulator_disable(l29); + if (ret) + cam_err("error disabling regulator\n"); + } + usleep(1*1000); + + /* MCLK 24MHz*/ + + /* 8M AVDD 2.8V */ + gpio_set_value_cansleep(GPIO_CAM_A_EN, 0); + usleep(1*1000); + /* ISP CORE 1.2V */ + /* delete for unnecessary power */ + } else { /* rear camera */ + /* ISP_STANDBY */ + gpio_set_value_cansleep(PM8921_GPIO_PM_TO_SYS(24), 0); + usleep(1*1000); + + /* ISP_RESET */ + gpio_set_value_cansleep(ISP_RESET, 0); + usleep(1*1000); + + /* AF 2.8V */ + gpio_set_value_cansleep(gpio_rev(CAM_AF_EN), 0); + usleep(1*1000); + + /* ISP 8M MIPI 1.2V */ + gpio_set_value_cansleep(CAM_MIPI_EN, 0); + usleep(1*1000); + + /* ISP 8M HOST 1.8V */ + if (l29) { + ret = regulator_disable(l29); + if (ret) + cam_err("error disabling regulator\n"); + } + usleep(1*1000); + + /* 8M DVDD 1.2V */ + gpio_set_value_cansleep(GPIO_CAM_SENSOR_EN, 0); + usleep(1*1000); + + /* 8M AVDD 2.8V */ + gpio_set_value_cansleep(GPIO_CAM_A_EN, 0); + usleep(1*1000); + + /* ISP CORE 1.2V */ +#ifdef CONFIG_MACH_M2_ATT + if (system_rev >= BOARD_REV03) + ret = regulator_disable(isp_core); + if (ret) + cam_err("error disabling regulator"); + regulator_put(isp_core); +#elif defined(CONFIG_MACH_M2_VZW) + if (system_rev >= BOARD_REV08) + ret = regulator_disable(isp_core); + if (ret) + cam_err("error disabling regulator"); + regulator_put(isp_core); +#elif defined(CONFIG_MACH_M2_SPR) + if (system_rev >= BOARD_REV03) + ret = regulator_disable(isp_core); + if (ret) + cam_err("error disabling regulator"); + regulator_put(isp_core); +#elif defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + gpio_set_value_cansleep(gpio_rev(CAM_CORE_EN), 0); +#else + gpio_set_value_cansleep(CAM_CORE_EN, 0); +#endif + usleep(1*1000); + + /* flash power 1.8V */ + if (l28) { + ret = regulator_disable(l28); + if (ret) + cam_err("error disabling regulator\n"); + } + usleep(1*1000); + + /* GPIO_CAM_FLASH_SW : tourch */ + temp = gpio_get_value(GPIO_MSM_FLASH_NOW); + + if (isFlashCntlEn == 0 && temp == 0) { + /* GPIO_CAM_FLASH_SW : tourch */ + gpio_set_value_cansleep(gpio_cam_flash_sw, 0); + temp = gpio_get_value(gpio_cam_flash_sw); + printk(KERN_DEBUG "[s5c73m3] check" + " GPIO_CAM_FLASH_SW : %d\n", temp); + /* FLASH_LED_LOCK*/ + gpio_set_value_cansleep(PM8921_MPP_PM_TO_SYS + (PMIC_MPP_FLASH_LED_UNLOCK), 0); + usleep(1*1000); + } + } +} + +static void cam_isp_reset(void) +{ + int temp = 0; + + /* ISP_RESET */ + gpio_set_value_cansleep(ISP_RESET, 0); + temp = gpio_get_value(ISP_RESET); + printk(KERN_DEBUG "[s5c73m3] check ISP_RESET : %d\n", temp); + usleep(1*1000); + /* ISP_RESET */ + gpio_set_value_cansleep(ISP_RESET, 1); + temp = gpio_get_value(ISP_RESET); + printk(KERN_DEBUG "[s5c73m3] check ISP_RESET : %d\n", temp); + usleep(1*1000); +} + +static u8 *rear_sensor_fw; +static u8 *rear_phone_fw; +static void cam_get_fw(u8 *isp_fw, u8 *phone_fw) +{ + rear_sensor_fw = isp_fw; + rear_phone_fw = phone_fw; + pr_debug("sensor_fw = %s\n", rear_sensor_fw); + pr_debug("phone_fw = %s\n", rear_phone_fw); +} + +/* test: Qualcomm */ +void print_ldos(void) +{ + int temp = 0; +#if defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + temp = gpio_get_value(gpio_rev(CAM_CORE_EN)); +#else + temp = gpio_get_value(CAM_CORE_EN); +#endif + printk(KERN_DEBUG "[s5c73m3] check CAM_CORE_EN : %d\n", temp); + + temp = gpio_get_value(GPIO_CAM_A_EN); + printk(KERN_DEBUG "[s5c73m3] check GPIO_CAM_A_EN : %d\n", temp); + + temp = gpio_get_value(GPIO_CAM_SENSOR_EN); + printk(KERN_DEBUG "[s5c73m3] check GPIO_CAM_SENSOR_EN : %d\n", temp); + + temp = gpio_get_value(CAM_MIPI_EN); + printk(KERN_DEBUG "[s5c73m3] check CAM_MIPI_EN : %d\n", temp); + + temp = gpio_get_value(PM8921_GPIO_PM_TO_SYS(24));/*SPI_TEMP*/ + printk(KERN_DEBUG "[s5c73m3] check ISP_STANDBY : %d\n", temp); + + temp = gpio_get_value(ISP_RESET); + printk(KERN_DEBUG "[s5c73m3] check ISP_RESET : %d\n", temp); + +} + +#ifdef CONFIG_S5C73M3 +static struct msm_camera_sensor_flash_data flash_s5c73m3 = { + .flash_type = MSM_CAMERA_FLASH_LED, +}; + +static struct msm_camera_sensor_platform_info sensor_board_info_s5c73m3 = { + .mount_angle = 90, + .sensor_reset = ISP_RESET, + .flash_en = GPIO_MSM_FLASH_NOW, + .flash_set = GPIO_MSM_FLASH_CNTL_EN, + .mclk = GPIO_CAM_MCLK0, + .sensor_pwd = CAM_CORE_EN, + .vcm_pwd = 0, + .vcm_enable = 1, + .sensor_power_on = cam_ldo_power_on, + .sensor_power_off = cam_ldo_power_off, + .sensor_isp_reset = cam_isp_reset, + .sensor_get_fw = cam_get_fw, + .sensor_set_isp_core = cam_set_isp_core, + .sensor_is_vdd_core_set = cam_is_vdd_core_set, +}; + +static struct msm_camera_sensor_info msm_camera_sensor_s5c73m3_data = { + .sensor_name = "s5c73m3", + .pdata = &msm_camera_csi_device_data[0], + .flash_data = &flash_s5c73m3, + .sensor_platform_info = &sensor_board_info_s5c73m3, + .gpio_conf = &rear_gpio_conf, + .csi_if = 1, + .camera_type = BACK_CAMERA_2D, +}; + +struct platform_device msm8960_camera_sensor_s5c73m3 = { + .name = "msm_camera_s5c73m3", + .dev = { + .platform_data = &msm_camera_sensor_s5c73m3_data, + }, +}; +#endif + +#ifdef CONFIG_S5K6A3YX +static struct msm_camera_sensor_flash_data flash_s5k6a3yx = { + .flash_type = MSM_CAMERA_FLASH_NONE, +}; + +static struct msm_camera_sensor_platform_info sensor_board_info_s5k6a3yx = { + .mount_angle = 270, + .mclk = GPIO_CAM_MCLK0, + .sensor_pwd = CAM_CORE_EN, + .vcm_pwd = 0, + .vcm_enable = 1, + .sensor_power_on = cam_ldo_power_on, + .sensor_power_off = cam_ldo_power_off, +}; + +static struct msm_camera_sensor_info msm_camera_sensor_s5k6a3yx_data = { + .sensor_name = "s5k6a3yx", + .pdata = &msm_camera_csi_device_data[1], + .flash_data = &flash_s5k6a3yx, + .sensor_platform_info = &sensor_board_info_s5k6a3yx, + .gpio_conf = &front_gpio_conf, + .csi_if = 1, + .camera_type = FRONT_CAMERA_2D, +}; + +struct platform_device msm8960_camera_sensor_s5k6a3yx = { + .name = "msm_camera_s5k6a3yx", + .dev = { + .platform_data = &msm_camera_sensor_s5k6a3yx_data, + }, +}; +#endif + +#ifdef CONFIG_LEDS_AAT1290A +static int aat1290a_setGpio(void) +{ + int ret; + int temp = 0; + + printk(KERN_DEBUG "[%s : %d]!!\n", __func__, __LINE__); + +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) /* D2 */ + /* FLASH_LED_UNLOCK*/ + gpio_set_value_cansleep(PM8921_MPP_PM_TO_SYS + (PMIC_MPP_FLASH_LED_UNLOCK), 1); +#endif + + /* GPIO_CAM_FLASH_SW : tourch */ + gpio_set_value_cansleep(gpio_cam_flash_sw, 0); + temp = gpio_get_value(gpio_cam_flash_sw); + printk(KERN_DEBUG "[s5c73m3] check GPIO_CAM_FLASH_SW : %d\n", temp); + usleep(1*1000); + + /* flash power 1.8V */ + l28 = regulator_get(NULL, "8921_lvs4"); + ret = regulator_enable(l28); + if (ret) + cam_err("error enabling regulator\n"); + usleep(1*1000); + + if (pmic_gpio_msm_flash_cntl_en) { + gpio_set_value_cansleep(pmic_gpio_msm_flash_cntl_en, 1); + } else { + gpio_set_value_cansleep(GPIO_MSM_FLASH_CNTL_EN, 1); + temp = gpio_get_value(GPIO_MSM_FLASH_CNTL_EN); + printk(KERN_DEBUG "[s5c73m3] check Flash set GPIO : %d\n", + temp); + } + isFlashCntlEn = true; + usleep(1*1000); + + gpio_set_value_cansleep(GPIO_MSM_FLASH_NOW, 1); + temp = gpio_get_value(GPIO_MSM_FLASH_NOW); + printk(KERN_DEBUG "[s5c73m3] check Flash enable GPIO : %d\n", temp); + usleep(1*1000); + + return 0; +} + +static int aat1290a_freeGpio(void) +{ + int ret; + + printk(KERN_DEBUG "[%s : %d]!!\n", __func__, __LINE__); + + if (pmic_gpio_msm_flash_cntl_en) + gpio_set_value_cansleep(pmic_gpio_msm_flash_cntl_en, 0); + else + gpio_set_value_cansleep(GPIO_MSM_FLASH_CNTL_EN, 0); + isFlashCntlEn = false; + usleep(1*1000); + gpio_set_value_cansleep(GPIO_MSM_FLASH_NOW, 0); + usleep(1*1000); + + /* flash power 1.8V */ + if (l28) { + ret = regulator_disable(l28); + if (ret) + cam_err("error disabling regulator\n"); + } + usleep(1*1000); + + /* GPIO_CAM_FLASH_SW : tourch */ + gpio_set_value_cansleep(gpio_cam_flash_sw, 0); + usleep(1*1000); + +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) /* D2 */ + /* FLASH_LED_LOCK*/ + gpio_set_value_cansleep(PM8921_MPP_PM_TO_SYS + (PMIC_MPP_FLASH_LED_UNLOCK), 0); +#endif + return 0; +} + +static void aat1290a_torch_en(int onoff) +{ + int ret; + int temp = 0; + + printk(KERN_DEBUG "[%s : %d] %s!!\n", + __func__, __LINE__, onoff ? "enabled" : "disabled"); + + gpio_set_value_cansleep(GPIO_MSM_FLASH_NOW, onoff); + temp = gpio_get_value(GPIO_MSM_FLASH_NOW); + printk(KERN_DEBUG "[s5c73m3] check Flash enable GPIO : %d\n", temp); + usleep(1*1000); +} + +static void aat1290a_torch_set(int onoff) +{ + int ret; + int temp = 0; + + printk(KERN_DEBUG "[%s : %d] %s!!\n", + __func__, __LINE__, onoff ? "enabled" : "disabled"); + + if (pmic_gpio_msm_flash_cntl_en) { + gpio_set_value_cansleep(pmic_gpio_msm_flash_cntl_en, onoff); + } else { + gpio_set_value_cansleep(GPIO_MSM_FLASH_CNTL_EN, onoff); + temp = gpio_get_value(GPIO_MSM_FLASH_CNTL_EN); + printk(KERN_DEBUG "[s5c73m3] check Flash set GPIO : %d\n", + temp); + } + usleep(1*1000); +} + +static struct aat1290a_led_platform_data aat1290a_led_data = { + .brightness = TORCH_BRIGHTNESS_50, + .status = STATUS_UNAVAILABLE, + .setGpio = aat1290a_setGpio, + .freeGpio = aat1290a_freeGpio, + .torch_en = aat1290a_torch_en, + .torch_set = aat1290a_torch_set, +}; + +static struct platform_device s3c_device_aat1290a_led = { + .name = "aat1290a-led", + .id = -1, + .dev = { + .platform_data = &aat1290a_led_data, + }, +}; +#endif + +static struct platform_device *cam_dev[] = { +#ifdef CONFIG_S5C73M3 + &msm8960_camera_sensor_s5c73m3, +#endif +#ifdef CONFIG_S5K6A3YX + &msm8960_camera_sensor_s5k6a3yx, +#endif +}; + +static ssize_t back_camera_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#if defined(CONFIG_ISX012) + char cam_type[] = "SONY_ISX012\n"; +#elif defined(CONFIG_S5C73M3) + char cam_type[] = "S5C73M3\n"; +#elif defined(CONFIG_S5K5CCGX) + char cam_type[] = "SLSI_S5K5CCGX\n"; +#else + char cam_type[] = "Rear default camera\n"; +#endif + + return snprintf(buf, sizeof(cam_type), "%s", cam_type); +} + +static ssize_t front_camera_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#if defined(CONFIG_S5K8AAY) + char cam_type[] = "SLSI_S5K8AA\n"; +#elif defined(CONFIG_S5K6A3YX) + char cam_type[] = "SLSI_S5K6A3YX\n"; +#elif defined(CONFIG_DB8131M) + char cam_type[] = "DUB_DB8131M\n"; +#elif defined(CONFIG_SR030PC50) + char cam_type[] = "SILICON_SR030PC50\n"; +#else + char cam_type[] = "Front default camera\n"; +#endif + + return snprintf(buf, sizeof(cam_type), "%s", cam_type); +} + +static DEVICE_ATTR(rear_camtype, S_IRUGO, back_camera_type_show, NULL); +static DEVICE_ATTR(front_camtype, S_IRUGO, front_camera_type_show, NULL); + +static ssize_t back_camera_firmware_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#if defined(CONFIG_ISX012) + char cam_fw[] = "ISX012\n"; +#elif defined(CONFIG_S5K5CCGX) + char cam_fw[] = "S5K5CCGX\n"; +#endif + +#if defined(CONFIG_S5C73M3) + return sprintf(buf, "%s %s", rear_sensor_fw, rear_phone_fw); +#else + char cam_fw[] = "Rear default camera\n"; + return snprintf(buf, sizeof(cam_fw), "%s", cam_fw); +#endif +} + +static ssize_t front_camera_firmware_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#if defined(CONFIG_S5K8AAY) + char cam_fw[] = "S5K8AAY\n"; +#elif defined(CONFIG_S5K6A3YX) + char *cam_fw[] = {"S5K6A3", "S5K6A3"}; /*char cam_fw[] = "S5K6A3YX\n";*/ +#elif defined(CONFIG_DB8131M) + char cam_fw[] = "DB8131M\n"; +#elif defined(CONFIG_SR030PC50) + char cam_fw[] = "SR030PC50\n"; +#else + char cam_fw[] = "Front default camera\n"; +#endif + +#if defined(CONFIG_S5K6A3YX) + return sprintf(buf, "%s %s", cam_fw[0], cam_fw[1]); +#else + return snprintf(buf, sizeof(cam_fw), "%s", cam_fw); +#endif +} + +static DEVICE_ATTR(rear_camfw, 0664, back_camera_firmware_show, NULL); +static DEVICE_ATTR(front_camfw, 0664, front_camera_firmware_show, NULL); + + +static ssize_t cameraflash_file_cmd_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int value; + int err = 1; + int flash_rev = 0; + + flash_rev = 0; + + if (strlen(buf) > 2) + return -err; + + if (isdigit(*buf)) { + err = kstrtoint(buf, 10, &value); + if (err < 0) + pr_err("%s, kstrtoint failed.", __func__); + } else + return -err; + +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) /* D2 */ +#ifdef CONFIG_LEDS_AAT1290A + err = aat1290a_flash_power(value); + if (err < 0) + printk(KERN_DEBUG "[%s : %d]aat1290a_flash_power" + " contorl fail!!\n", __func__, __LINE__); +#endif +#endif + return size; +} + +static DEVICE_ATTR(rear_flash, S_IRUGO | S_IWUSR | S_IWGRP, + NULL, cameraflash_file_cmd_store); + +void msm8960_cam_create_node(void) +{ + struct device *cam_dev_back; + struct device *cam_dev_front; + struct class *camera_class; + + camera_class = class_create(THIS_MODULE, "camera"); + + if (IS_ERR(camera_class)) { + pr_err("Failed to create class(camera)!\n"); + return; + } + cam_dev_back = device_create(camera_class, NULL, + 0, NULL, "rear"); + + if (IS_ERR(cam_dev_back)) { + pr_err("Failed to create cam_dev_back device!\n"); + goto OUT7; + } + + if (device_create_file(cam_dev_back, &dev_attr_rear_flash) < 0) { + pr_err("Failed to create device file!(%s)!\n", + dev_attr_rear_flash.attr.name); + goto OUT6; + } + + if (device_create_file(cam_dev_back, &dev_attr_rear_camtype) < 0) { + pr_err("Failed to create device file!(%s)!\n", + dev_attr_rear_camtype.attr.name); + goto OUT5; + } + + if (device_create_file(cam_dev_back, &dev_attr_rear_camfw) < 0) { + pr_err("Failed to create device file!(%s)!\n", + dev_attr_rear_camfw.attr.name); + goto OUT4; + } + + cam_dev_front = device_create(camera_class, NULL, + 1, NULL, "front"); + + if (IS_ERR(cam_dev_front)) { + pr_err("Failed to create cam_dev_front device!"); + goto OUT3; + } + + if (device_create_file(cam_dev_front, &dev_attr_front_camtype) < 0) { + pr_err("Failed to create device file!(%s)!\n", + dev_attr_front_camtype.attr.name); + goto OUT2; + } + + if (device_create_file(cam_dev_front, &dev_attr_front_camfw) < 0) { + pr_err("Failed to create device file!(%s)!\n", + dev_attr_front_camfw.attr.name); + goto OUT1; + } + + return; + +OUT1: + device_remove_file(cam_dev_back, &dev_attr_front_camtype); +OUT2: + device_destroy(camera_class, 1); +OUT3: + device_remove_file(cam_dev_back, &dev_attr_rear_camfw); +OUT4: + device_remove_file(cam_dev_back, &dev_attr_rear_camtype); +OUT5: + device_remove_file(cam_dev_back, &dev_attr_rear_flash); +OUT6: + device_destroy(camera_class, 0); +OUT7: + return; +} +#ifdef CONFIG_S5C73M3 +static struct spi_board_info s5c73m3_spi_info[] __initdata = { + { + .modalias = "s5c73m3_spi", + .mode = SPI_MODE_0, + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 48000000, + } +}; +#endif +#if 0 +static struct pm8xxx_mpp_config_data privacy_light_on_config = { + .type = PM8XXX_MPP_TYPE_SINK, + .level = PM8XXX_MPP_CS_OUT_5MA, + .control = PM8XXX_MPP_CS_CTRL_MPP_LOW_EN, +}; +static struct pm8xxx_mpp_config_data privacy_light_off_config = { + .type = PM8XXX_MPP_TYPE_SINK, + .level = PM8XXX_MPP_CS_OUT_5MA, + .control = PM8XXX_MPP_CS_CTRL_DISABLE, +}; +static int32_t msm_camera_8960_ext_power_ctrl(int enable) +{ + int rc = 0; + if (enable) { + rc = pm8xxx_mpp_config(PM8921_MPP_PM_TO_SYS(12), + &privacy_light_on_config); + } else { + rc = pm8xxx_mpp_config(PM8921_MPP_PM_TO_SYS(12), + &privacy_light_off_config); + } + return rc; +} +#endif +static int get_mclk_rev(void) +{ +#if defined(CONFIG_MACH_M2_ATT) + return ((system_rev >= BOARD_REV10) ? 1 : 0); +#elif defined(CONFIG_MACH_M2_VZW) + return ((system_rev >= BOARD_REV13) ? 1 : 0); +#elif defined(CONFIG_MACH_M2_SPR) + return ((system_rev >= BOARD_REV08) ? 1 : 0); +#elif defined(CONFIG_MACH_M2_SKT) + return ((system_rev >= BOARD_REV09) ? 1 : 0); +#elif defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + return ((system_rev >= BOARD_REV03) ? 1 : 0); +#elif defined(CONFIG_MACH_APEXQ) + return ((system_rev >= BOARD_REV04) ? 1 : 0); +#elif defined(CONFIG_MACH_COMANCHE) + return ((system_rev >= BOARD_REV03) ? 1 : 0); +#elif defined(CONFIG_MACH_EXPRESS) + return ((system_rev >= BOARD_REV03) ? 1 : 0); +#elif defined(CONFIG_MACH_AEGIS2) + return ((system_rev >= BOARD_REV07) ? 1 : 0); +#elif defined(CONFIG_MACH_JASPER) + return ((system_rev >= BOARD_REV08) ? 1 : 0); +#elif defined(CONFIG_MACH_STRETTO) + return 1; +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) + return 1; +#else + return 0; +#endif +} + +void __init msm8960_init_cam(void) +{ + int rev = 0; + struct msm_camera_sensor_info *s_info; + + rev = get_mclk_rev(); + +#if !defined(CONFIG_MACH_STRETTO) +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX)\ + || defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_COMANCHE) \ + || defined(CONFIG_MACH_EXPRESS) || defined(CONFIG_MACH_GOGH) \ + || defined(CONFIG_MACH_INFINITE) + /*|| ((defined(CONFIG_ISX012) || defined(CONFIG_DB8131M))\temp */ + + if (rev) { + int rc; + + struct pm_gpio param_flash = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + }; + + rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS + (PMIC_MSM_FLASH_CNTL_EN), ¶m_flash); + + if (rc) { + pr_err("%s pmic gpio config failed\n", __func__); + return; + } + pmic_gpio_msm_flash_cntl_en = + PM8921_GPIO_PM_TO_SYS(PMIC_MSM_FLASH_CNTL_EN); + } else { + pmic_gpio_msm_flash_cntl_en = 0; + } + isFlashCntlEn = false; +#endif +#endif + + msm8960_cam_create_node(); + + msm_gpiomux_install(msm8960_cam_common_configs, + ARRAY_SIZE(msm8960_cam_common_configs)); + +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) +#if defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + gpio_tlmm_config(GPIO_CFG(gpio_rev(CAM_CORE_EN), 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); +#else + gpio_tlmm_config(GPIO_CFG(CAM_CORE_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); +#endif + gpio_tlmm_config(GPIO_CFG(CAM_MIPI_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(GPIO_CAM_A_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(GPIO_CAM_SENSOR_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(ISP_RESET, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); +#if defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + gpio_tlmm_config(GPIO_CFG(gpio_rev(CAM2_RST_N), 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); +#else + gpio_tlmm_config(GPIO_CFG(CAM2_RST_N, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); +#endif + + gpio_cam_flash_sw = gpio_rev(CAM_FLASH_SW); + gpio_tlmm_config(GPIO_CFG(gpio_cam_flash_sw, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(gpio_rev(CAM_AF_EN), 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + + if (!pmic_gpio_msm_flash_cntl_en) { + gpio_tlmm_config(GPIO_CFG(GPIO_MSM_FLASH_CNTL_EN, 0, + GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + } + gpio_tlmm_config(GPIO_CFG(GPIO_MSM_FLASH_NOW, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(GPIO_VT_CAM_SEN_DET, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); +#endif + +#if defined(CONFIG_S5C73M3) + s_info = &msm_camera_sensor_s5c73m3_data; +#if defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + s_info->sensor_platform_info->sensor_pwd = + gpio_rev(CAM_CORE_EN); +#endif + msm_get_cam_resources(s_info); + platform_device_register(cam_dev[0]); +#endif +#if defined(CONFIG_S5K6A3YX) + s_info = &msm_camera_sensor_s5k6a3yx_data; +#if defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + s_info->sensor_platform_info->sensor_pwd = + gpio_rev(CAM_CORE_EN); +#endif + if (rev) { + s_info->sensor_platform_info->mclk = + GPIO_CAM_MCLK2; + s_info->gpio_conf->cam_gpiomux_conf_tbl = + msm8960_cam_2d_configs_v2; + s_info->gpio_conf->cam_gpio_tbl = + msm_cam_gpio_2d_tbl_v2; + } + + msm_get_cam_resources(s_info); + platform_device_register(cam_dev[1]); +#endif + if (spi_register_board_info( + s5c73m3_spi_info, + ARRAY_SIZE(s5c73m3_spi_info)) != 0) + pr_err("%s: spi_register_board_info returned error\n", + __func__); + + pr_err("[%s:%d]setting done!!\n", __func__, __LINE__); + + platform_device_register(&msm8960_device_csiphy0); + platform_device_register(&msm8960_device_csiphy1); + platform_device_register(&msm8960_device_csid0); + platform_device_register(&msm8960_device_csid1); + platform_device_register(&msm8960_device_ispif); + platform_device_register(&msm8960_device_vfe); + platform_device_register(&msm8960_device_vpe); +#ifdef CONFIG_LEDS_AAT1290A + platform_device_register(&s3c_device_aat1290a_led); +#endif +} + +#ifdef CONFIG_I2C +static struct i2c_board_info msm8960_camera_i2c_boardinfo[] = { +#ifdef CONFIG_S5K6A3YX + { + I2C_BOARD_INFO("s5k6a3yx", 0x20), + .platform_data = &msm_camera_sensor_s5k6a3yx_data, + }, +#endif +}; + +struct msm_camera_board_info msm8960_camera_board_info = { + .board_info = msm8960_camera_i2c_boardinfo, + .num_i2c_board_info = ARRAY_SIZE(msm8960_camera_i2c_boardinfo), +}; + +struct resource msm_camera_resources[] = { + { + .name = "s3d_rw", + .start = 0x008003E0, + .end = 0x008003E0 + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "s3d_ctl", + .start = 0x008020B8, + .end = 0x008020B8 + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +int __init msm_get_cam_resources(struct msm_camera_sensor_info *s_info) +{ + s_info->resource = msm_camera_resources; + s_info->num_resources = ARRAY_SIZE(msm_camera_resources); + return 0; +} + +#endif +#endif +#endif diff --git a/arch/arm/mach-msm/board-m2-display.c b/arch/arm/mach-msm/board-m2-display.c new file mode 100644 index 00000000000..d4e1b216ab4 --- /dev/null +++ b/arch/arm/mach-msm/board-m2-display.c @@ -0,0 +1,2074 @@ +/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "devices.h" +#include "board-8960.h" +#include +#include +#include "devices-msm8x60.h" + +#ifdef CONFIG_SAMSUNG_CMC624 +/*1.8V*/ +#define MLCD_ON PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_MLCD_ON) +/*CMC_DCDC_EN (1.1V)*/ +#define IMA_PWR_EN PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_IMA_PWR_EN) +/*FAIL_SAFEB*/ +#define IMA_CMC_EN PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_IMA_CMC_EN) +#define IMA_nRST PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_IMA_nRST) /*RESETB */ +#define IMA_SLEEP PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_IMA_SLEEP) /*SLEEPB*/ +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +#if defined(CONFIG_SAMSUNG_CMC624) +#define CMC_ESD PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_CMC_ESD_DET) +#define OLED_ESD PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_VGH_ESD_DET) +#endif +#endif +static struct gpiomux_setting cmc624_active_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, + .dir = GPIOMUX_OUT_LOW, +}; +static struct gpiomux_setting cmc624_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_IN, +}; + +static struct msm_gpiomux_config msm8x60_cmc624_configs[] __initdata = { + { + .gpio = 71, + .settings = { + [GPIOMUX_ACTIVE] = &cmc624_active_cfg, + [GPIOMUX_SUSPENDED] = &cmc624_suspend_cfg, + }, + }, + { + .gpio = 72, + .settings = { + [GPIOMUX_ACTIVE] = &cmc624_active_cfg, + [GPIOMUX_SUSPENDED] = &cmc624_suspend_cfg, + }, + }, + + { + .gpio = 10, + .settings = { + [GPIOMUX_ACTIVE] = &cmc624_active_cfg, + [GPIOMUX_SUSPENDED] = &cmc624_suspend_cfg, + }, + }, +}; + +static struct i2c_gpio_platform_data cmc624_i2c_gpio_data = { + .sda_pin = GPIO_IMA_I2C_SDA, + .scl_pin = GPIO_IMA_I2C_SCL, + .udelay = 5, +}; + +static struct platform_device cmc624_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_CMC624_I2C_BUS_ID, + .dev = { + .platform_data = &cmc624_i2c_gpio_data, + }, +}; +#else +#define OLED_ESD PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_VGH_ESD_DET) +#endif + + +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +static struct sec_esd_platform_data esd_pdata; +static struct platform_device samsung_mipi_esd_refresh_device = { + .name = "samsung_mipi_esd_refresh", + .id = -1, + .dev = { + .platform_data = &esd_pdata, + }, +}; +#endif +#if defined(CONFIG_FB_MSM_TRIPLE_BUFFER) +/* prim = 540 x 960 x 4(bpp) x 3(pages) */ +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (480 * 800 * 4 * 3) +#elif defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (1024 * 600 * 4 * 3) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (1280 * 800 * 4 * 3) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (544 * 960 * 4 * 3) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (1280 * 736 * 4 * 3) +#else +#define MSM_FB_PRIM_BUF_SIZE (480 * 800 * 4 * 3) +#endif +#else +/* prim = 540 x 960 x 4(bpp) x 2(pages) */ +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (480 * 800 * 4 * 2) +#elif defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (1024 * 600 * 4 * 2) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (1280 * 800 * 4 * 2) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (544 * 960 * 4 * 2) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL) +#define MSM_FB_PRIM_BUF_SIZE (1280 * 736 * 4 * 2) +#else +#define MSM_FB_PRIM_BUF_SIZE (480 * 800 * 4 * 2) +#endif +#endif + +#if defined(CONFIG_FB_MSM_MIPI_DSI) +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) +/* 480 x 800 x 3 x 2 */ +#define MIPI_DSI_WRITEBACK_SIZE (480 * 800 * 3 * 2) +#elif defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) +/* 1024 x 600 x 3 x 2 */ +#define MIPI_DSI_WRITEBACK_SIZE (1024 * 600 * 3 * 2) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) +/* 1280 x 800 x 3 x 2 */ +#define MIPI_DSI_WRITEBACK_SIZE (1280 * 800 * 3 * 2) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL) +/* 540 x 960 x 3 x 2 */ +#define MIPI_DSI_WRITEBACK_SIZE (544 * 960 * 3 * 2) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL) +/*1280 x732 x 3 x 2 */ +#define MIPI_DSI_WRITEBACK_SIZE (1280 * 736 * 3 * 2) +#endif +#else +#define MIPI_DSI_WRITEBACK_SIZE 0 +#endif + +/* Note: must be multiple of 4096 */ +#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096) + +#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) +#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((480 * 800 * 3 * 2), 4096) +#elif defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) +#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1024 * 608 * 3 * 2), 4096) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) +#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1280 * 800 * 3 * 2), 4096) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL) +#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((544 * 960 * 3 * 2), 4096) +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL) +#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1280 * 736 * 3 * 2), 4096) +#else +#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1920 * 1200 * 3 * 2), 4096) +#endif +#else +#define MSM_FB_OVERLAY0_WRITEBACK_SIZE (0) +#endif /* CONFIG_FB_MSM_OVERLAY0_WRITEBACK */ + +#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK +#define MSM_FB_OVERLAY1_WRITEBACK_SIZE roundup((1920 * 1088 * 3 * 2), 4096) +#else +#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0) +#endif /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */ + +#define MDP_VSYNC_GPIO 0 + +#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME "mipi_cmd_novatek_qhd" +#define MIPI_CMD_NOVATEK_WVGA_PANEL_NAME "mipi_cmd_novatek_wvga" +#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME "mipi_video_novatek_qhd" +#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga" +#define MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME "mipi_video_toshiba_wuxga" +#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga" +#define MIPI_VIDEO_CHIMEI_WUXGA_PANEL_NAME "mipi_video_chimei_wuxga" +#define MIPI_VIDEO_BOEOT_WSVGA_PANEL_NAME "mipi_video_boeot_tft_wsvga" +#define MIPI_VIDEO_SAMSUNG_WXGA_PANEL_NAME "mipi_video_samsung_tft_wxga" +#define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME "mipi_video_simulator_vga" +#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME "mipi_cmd_renesas_fwvga" +#define MIPI_VIDEO_ORISE_720P_PANEL_NAME "mipi_video_orise_720p" +#define MIPI_CMD_ORISE_720P_PANEL_NAME "mipi_cmd_orise_720p" +#define HDMI_PANEL_NAME "hdmi_msm" +#define TVOUT_PANEL_NAME "tvout_msm" + +#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY + unsigned char hdmi_is_primary = 1; +#else + unsigned char hdmi_is_primary; +#endif + +unsigned char msm8960_hdmi_as_primary_selected(void) +{ + return hdmi_is_primary; +} + +static struct resource msm_fb_resources[] = { + { + .flags = IORESOURCE_DMA, + } +}; + +static void set_mdp_clocks_for_wuxga(void); + +static int msm_fb_detect_panel(const char *name) +{ + if (machine_is_msm8960_liquid()) { + if (!strncmp(name, MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME, + strnlen(MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + + if (!strncmp(name, MIPI_VIDEO_BOEOT_WSVGA_PANEL_NAME, + strnlen(MIPI_VIDEO_BOEOT_WSVGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + if (!strncmp(name, MIPI_VIDEO_SAMSUNG_WXGA_PANEL_NAME, + strnlen(MIPI_VIDEO_SAMSUNG_WXGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + + } else { + if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME, + strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + +#ifndef CONFIG_FB_MSM_MIPI_PANEL_DETECT + if (!strncmp(name, MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME, + strnlen(MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + + if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME, + strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + + if (!strncmp(name, MIPI_CMD_NOVATEK_WVGA_PANEL_NAME, + strnlen(MIPI_CMD_NOVATEK_WVGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + + if (!strncmp(name, MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME, + strnlen(MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + + if (!strncmp(name, MIPI_CMD_RENESAS_FWVGA_PANEL_NAME, + strnlen(MIPI_CMD_RENESAS_FWVGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + + if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME, + strnlen(MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) { + set_mdp_clocks_for_wuxga(); + return 0; + } + + if (!strncmp(name, MIPI_VIDEO_ORISE_720P_PANEL_NAME, + strnlen(MIPI_VIDEO_ORISE_720P_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + + if (!strncmp(name, MIPI_CMD_ORISE_720P_PANEL_NAME, + strnlen(MIPI_CMD_ORISE_720P_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; +#endif + } + + if (!strncmp(name, HDMI_PANEL_NAME, + strnlen(HDMI_PANEL_NAME, + PANEL_NAME_MAX_LEN))) { + if (hdmi_is_primary) + set_mdp_clocks_for_wuxga(); + return 0; + } + + if (!strncmp(name, TVOUT_PANEL_NAME, + strnlen(TVOUT_PANEL_NAME, + PANEL_NAME_MAX_LEN))) + return 0; + + pr_warning("%s: not supported '%s'", __func__, name); + return -ENODEV; +} + +static struct msm_fb_platform_data msm_fb_pdata = { + .detect_client = msm_fb_detect_panel, +}; + +static struct platform_device msm_fb_device = { + .name = "msm_fb", + .id = 0, + .num_resources = ARRAY_SIZE(msm_fb_resources), + .resource = msm_fb_resources, + .dev.platform_data = &msm_fb_pdata, +}; + +static void mipi_dsi_panel_pwm_cfg(void) +{ + int rc; + static int mipi_dsi_panel_gpio_configured; + static struct pm_gpio pwm_enable = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 1, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_VPH, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .disable_pin = 0, + }; + static struct pm_gpio pwm_mode = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_2, + .inv_int_pol = 0, + .disable_pin = 0, + }; + + if (mipi_dsi_panel_gpio_configured == 0) { + /* pm8xxx: gpio-21, Backlight Enable */ + rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(21), + &pwm_enable); + if (rc != 0) + pr_err("%s: pwm_enabled failed\n", __func__); + + /* pm8xxx: gpio-24, Bl: Off, PWM mode */ + rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(24), + &pwm_mode); + if (rc != 0) + pr_err("%s: pwm_mode failed\n", __func__); + + mipi_dsi_panel_gpio_configured++; + } +} + +static bool dsi_power_on; + +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) +/* + * Macros to be used in espresso panel power function for + * controlling regulators. + */ +#define LVDS_REGULATOR_TUNE(regvar, conmdev, supply_name, optmodcurr) \ + do { \ + regvar = regulator_get(conmdev, #supply_name); \ + if (IS_ERR(regvar)) { \ + pr_err("[%s] could not get " \ + #supply_name", rc = %ld\n", __func__,\ + PTR_ERR(regvar)); \ + return -ENODEV; \ + } \ + rc = regulator_set_optimum_mode(regvar, optmodcurr); \ + if (rc < 0) { \ + pr_err("[%s] set_optimum_mode high " \ + #regvar" failed, rc=%d\n", __func__, rc); \ + return -EINVAL; \ + } \ + } while (0); + + +#define LVDS_REGULATOR_ENABLE(rpm_name, minvolt, maxvolt) \ + do { \ + rpm_vreg_set_voltage(rpm_name, RPM_VREG_VOTER3, \ + minvolt, maxvolt, 1);\ + } while (0); + +#define LVDS_REGULATOR_DISABLE(rpm_name) \ + do { \ + rpm_vreg_set_voltage(rpm_name, RPM_VREG_VOTER3, 0, 0, 1);\ + } while (0); + +/** + * Espresso Board DSI power on/off + * + * @param on + * + * @return int + */ +static int mipi_dsi_espresso_dsi_power(int on) +{ + static struct regulator *vreg_l2_1p2; + int rc; + + if (!dsi_power_on) { + /* VDD_MIPI */ + LVDS_REGULATOR_TUNE(vreg_l2_1p2, + &msm_mipi_dsi1_device.dev, dsi_vdda, 100000) + + dsi_power_on = true; + } + if (on) { + pr_info("%s: power on sequence\n", __func__); + + /* Enable power - DSI */ + LVDS_REGULATOR_ENABLE(RPM_VREG_ID_PM8921_L2, 1200000, 1200000) + + } else { + pr_info("%s: power off sequence\n", __func__); + /* Disable power - DSI */ + LVDS_REGULATOR_DISABLE(RPM_VREG_ID_PM8921_L2) + } + return 0; +} + +static int mipi_dsi_tc35reset_release(void) +{ + /* Perform LVDS_RST */ + gpio_set_value_cansleep(GPIO_LVDS_RST, 1); /* disp enable */ + return 0; +} + +static bool espresso_panel_power_on; +/** + * Espresso Board panel on/off + * + * @param on + * + * @return int + */ +static int mipi_dsi_espresso_panel_power(int on) +{ + static struct regulator *vreg_l18_lvds_1p2_vddc, *vreg_l16_lvds_3p3v; + static int led_backlight_reset, check_bootup_for_vreg_l16; + int rc; + + pr_info("%s: on=%d\n", __func__, on); + + if (!espresso_panel_power_on) { + + /* Configure and Get GPIO LVDS_RST*/ + gpio_tlmm_config(GPIO_CFG(GPIO_LVDS_RST, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), + GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(GPIO_USB_I2C_SDA, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + GPIO_CFG_DISABLE); + + gpio_tlmm_config(GPIO_CFG(GPIO_USB_I2C_SCL, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + GPIO_CFG_DISABLE); + led_backlight_reset = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_LCD_RST); + rc = gpio_request(led_backlight_reset, "led_backlight_reset"); + if (rc) { + pr_err("request gpio 43 failed, rc=%d\n", rc); + return -ENODEV; + } + + gpio_set_value_cansleep(GPIO_LVDS_RST, 0); + gpio_set_value_cansleep(led_backlight_reset, 0); + + /* + * Enabling and tuning Supplies related to processor + * DSI. + */ + /* + * Get the regulator reference for rest of the LVDS related + * supplies and setting voltage requirement. + */ + /* VDD_MIPI + VDDC */ + LVDS_REGULATOR_TUNE(vreg_l18_lvds_1p2_vddc, + &msm_mipi_dsi1_device.dev, lvds_1p2, 100000) + /* VDD_LVDS1_3 */ + LVDS_REGULATOR_TUNE(vreg_l16_lvds_3p3v, + &msm_mipi_dsi1_device.dev, lvds_3p3, 100000) + + espresso_panel_power_on = true; + } + if (on) { + gpio_set_value_cansleep(GPIO_LVDS_RST, 0); + pr_info("%s: power on sequence\n", __func__); + + /* + * Enable power - Toshiba D2L + */ + /* VDD */ + LVDS_REGULATOR_ENABLE(RPM_VREG_ID_PM8921_L18, + 1200000, 1200000) + /* VCC_IO */ + if (((machine_is_ESPRESSO_VZW() && (system_rev >= BOARD_REV04))) + || machine_is_ESPRESSO10_VZW() + || machine_is_ESPRESSO10_SPR() + || machine_is_ESPRESSO10_ATT() + || machine_is_ESPRESSO_SPR()) + LVDS_REGULATOR_ENABLE(RPM_VREG_ID_PM8921_LVS6, 1, 1) + else + LVDS_REGULATOR_ENABLE(RPM_VREG_ID_PM8921_LVS5, 1, 1) + /* VDD_LVDS */ + if (check_bootup_for_vreg_l16) { + LVDS_REGULATOR_ENABLE(RPM_VREG_ID_PM8921_L16, + 3300000, 3300000) + } + check_bootup_for_vreg_l16 = 1; + + /* Perform LVDS_RST */ + gpio_set_value_cansleep(led_backlight_reset, 1); + + } else { + pr_info("%s: power off sequence\n", __func__); + + /* Assert reset */ + gpio_set_value_cansleep(GPIO_LVDS_RST, 0); + mdelay(20); + + /* Disable power - D2L */ + LVDS_REGULATOR_DISABLE(RPM_VREG_ID_PM8921_L18) + /* Disable LCD Power */ + LVDS_REGULATOR_DISABLE(RPM_VREG_ID_PM8921_L16) + if (((machine_is_ESPRESSO_VZW() && (system_rev >= BOARD_REV04))) + || machine_is_ESPRESSO10_SPR() + || machine_is_ESPRESSO10_VZW() + || machine_is_ESPRESSO10_ATT() + || machine_is_ESPRESSO_SPR()) + LVDS_REGULATOR_DISABLE(RPM_VREG_ID_PM8921_LVS6) + else + LVDS_REGULATOR_DISABLE(RPM_VREG_ID_PM8921_LVS5) + + gpio_set_value_cansleep(led_backlight_reset, 0); + } + return 0; +} + +#undef LVDS_REGULATOR_TUNE +#undef LVDS_REGULATOR_ENABLE +#undef LVDS_REGULATOR_DISABLE +#endif /* CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL */ + +/** + * LiQUID panel on/off + * + * @param on + * + * @return int + */ +static int mipi_dsi_liquid_panel_power(int on) +{ + static struct regulator *reg_l2, *reg_ext_3p3v; + static int gpio21, gpio24, gpio43; + int rc; + + mipi_dsi_panel_pwm_cfg(); + pr_debug("%s: on=%d\n", __func__, on); + + gpio21 = PM8921_GPIO_PM_TO_SYS(21); /* disp power enable_n */ + /*Display Enable (rst_n)*/ + gpio43 = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_LCD_RST); + gpio24 = PM8921_GPIO_PM_TO_SYS(24); /* Backlight PWM */ + + if (!dsi_power_on) { + + reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev, + "dsi_vdda"); + if (IS_ERR(reg_l2)) { + pr_err("could not get 8921_l2, rc = %ld\n", + PTR_ERR(reg_l2)); + return -ENODEV; + } + + rc = regulator_set_voltage(reg_l2, 1200000, 1200000); + if (rc) { + pr_err("set_voltage l2 failed, rc=%d\n", rc); + return -EINVAL; + } + + reg_ext_3p3v = regulator_get(&msm_mipi_dsi1_device.dev, + "vdd_lvds_3p3v"); + if (IS_ERR(reg_ext_3p3v)) { + pr_err("could not get reg_ext_3p3v, rc = %ld\n", + PTR_ERR(reg_ext_3p3v)); + return -ENODEV; + } + + rc = gpio_request(gpio21, "disp_pwr_en_n"); + if (rc) { + pr_err("request gpio 21 failed, rc=%d\n", rc); + return -ENODEV; + } + + rc = gpio_request(gpio43, "disp_rst_n"); + if (rc) { + pr_err("request gpio 43 failed, rc=%d\n", rc); + return -ENODEV; + } + + rc = gpio_request(gpio24, "disp_backlight_pwm"); + if (rc) { + pr_err("request gpio 24 failed, rc=%d\n", rc); + return -ENODEV; + } + + dsi_power_on = true; + } + + if (on) { + rc = regulator_set_optimum_mode(reg_l2, 100000); + if (rc < 0) { + pr_err("set_optimum_mode l2 failed, rc=%d\n", rc); + return -EINVAL; + } + rc = regulator_enable(reg_l2); + if (rc) { + pr_err("enable l2 failed, rc=%d\n", rc); + return -ENODEV; + } + + rc = regulator_enable(reg_ext_3p3v); + if (rc) { + pr_err("enable reg_ext_3p3v failed, rc=%d\n", rc); + return -ENODEV; + } + + /* set reset pin before power enable */ + gpio_set_value_cansleep(gpio43, 0); /* disp disable (resx=0) */ + + gpio_set_value_cansleep(gpio21, 0); /* disp power enable_n */ + msleep(20); + gpio_set_value_cansleep(gpio43, 1); /* disp enable */ + msleep(20); + gpio_set_value_cansleep(gpio43, 0); /* disp enable */ + msleep(20); + gpio_set_value_cansleep(gpio43, 1); /* disp enable */ + msleep(20); + } else { + gpio_set_value_cansleep(gpio43, 0); + gpio_set_value_cansleep(gpio21, 1); + + rc = regulator_disable(reg_l2); + if (rc) { + pr_err("disable reg_l2 failed, rc=%d\n", rc); + return -ENODEV; + } + rc = regulator_disable(reg_ext_3p3v); + if (rc) { + pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc); + return -ENODEV; + } + rc = regulator_set_optimum_mode(reg_l2, 100); + if (rc < 0) { + pr_err("set_optimum_mode l2 failed, rc=%d\n", rc); + return -EINVAL; + } + } + + return 0; +} + +static void active_reset_ldi(void) +{ + + int gpio43 = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_LCD_RST); + pr_info("Active Reset: Resettig LCD 1...0..1\n"); + gpio_direction_output(gpio43, 1); +#if defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL)\ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL)\ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) + gpio_direction_output(gpio43, 0); + msleep(20); + gpio_direction_output(gpio43, 1); + msleep(20); +#else + mdelay(10); + gpio_direction_output(gpio43, 0); + mdelay(30); + gpio_direction_output(gpio43, 1); + mdelay(100); +#endif +#else + udelay(500); + gpio_direction_output(gpio43, 0); + mdelay(5); + gpio_direction_output(gpio43, 1); + udelay(500); +#endif /* CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL */ +} + +void pull_ldi_reset_down(void) +{ + int gpio43 = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_LCD_RST); + gpio_direction_output(gpio43, 0); /*RESETB*/ +} + +void pull_ldi_reset_up(void) +{ + int gpio43 = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_LCD_RST); + gpio_direction_output(gpio43, 1); /*RESETB*/ +} +#ifdef CONFIG_SAMSUNG_CMC624 +void cmc_power(int on) +{ + if (on) { + /*RESETB->hi, FAILSAFE->lo, SLEEPB->hi */ + pr_info("Performing CMC624 Power On Init\n"); + gpio_direction_output(IMA_nRST, 1); /*RESETB*/ + gpio_direction_output(IMA_SLEEP, 1); /*SLEEPB*/ + udelay(50); /*Wait 50us*/ + /* V_IMA_1.1V on*/ + gpio_direction_output(IMA_PWR_EN, 1); + udelay(50); + /*V_IMA_1.8V on*/ + gpio_direction_output(MLCD_ON, 1); + udelay(50); + gpio_direction_output(IMA_CMC_EN, 1); /*FAIL_SAFEB*/ + udelay(50); + gpio_direction_output(IMA_nRST, 0); /*RESETB*/ + mdelay(4); + gpio_direction_output(IMA_nRST, 1); /*RESETB*/ + return; + } else { + pr_info("CMC Power off ................\n"); + /*FAILSAFE->lo*/ + gpio_direction_output(IMA_CMC_EN, 0); + /*V_IMA_1.8V off*/ + gpio_direction_output(MLCD_ON, 0); + /* V_IMA_1.1V off*/ + gpio_direction_output(IMA_PWR_EN, 0); + /* RESETB->lo, FAILSAFE->lo, SLEEPB->lo */ + gpio_direction_output(IMA_nRST, 0); + gpio_direction_output(IMA_SLEEP, 0); + gpio_tlmm_config(GPIO_CFG(GPIO_IMA_I2C_SDA, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + GPIO_CFG_DISABLE); + gpio_tlmm_config(GPIO_CFG(GPIO_IMA_I2C_SCL, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + GPIO_CFG_DISABLE); + } +} +#endif +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +#if defined(CONFIG_SAMSUNG_CMC624) +void set_esd_gpio_config(void) +{ + int rc; + struct pm_gpio sec_mipi_vgh_esd_det_gpio_cfg = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_L17, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + }; + struct pm_gpio sec_mipi_cmc_esd_det_gpio_cfg = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_DN, + .vin_sel = PM_GPIO_VIN_L17, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + }; + pm8xxx_gpio_config(OLED_ESD, &sec_mipi_vgh_esd_det_gpio_cfg); + rc = gpio_request(OLED_ESD, "IMA_ESD_DET"); + if (rc) + pr_err("request OLED_ESD failed, rc=%d\n", rc); + + pm8xxx_gpio_config(CMC_ESD, &sec_mipi_cmc_esd_det_gpio_cfg); + rc = gpio_request(CMC_ESD, "IMA_ESD_DET"); + if (rc) + pr_err("request CMC_ESD failed, rc=%d\n", rc); +} +#elif defined(CONFIG_MACH_JAGUAR) || \ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) +void set_esd_gpio_config(void) +{ + int rc; + struct pm_gpio sec_mipi_vgh_esd_det_gpio_cfg = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_UP_30, + .vin_sel = PM_GPIO_VIN_L17, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + }; + pm8xxx_gpio_config(OLED_ESD, &sec_mipi_vgh_esd_det_gpio_cfg); + rc = gpio_request(OLED_ESD, "IMA_ESD_DET"); + if (rc) + pr_err("request OLED_ESD failed, rc=%d\n", rc); +} +#elif defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) +void set_esd_gpio_config(void) +{ + int rc; + int esd_gpio = gpio_rev(ESD_DET); + + struct pm_gpio sec_mipi_esd_det_gpio_cfg = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_L17, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + }; + + if (system_rev >= BOARD_REV02) { + + esd_gpio = PM8921_GPIO_PM_TO_SYS(esd_gpio); + pm8xxx_gpio_config(esd_gpio, &sec_mipi_esd_det_gpio_cfg); + esd_pdata.esd_gpio_irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, + esd_gpio); + } else { + gpio_tlmm_config(GPIO_CFG(esd_gpio, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + esd_pdata.esd_gpio_irq = MSM_GPIO_TO_INT(esd_gpio); + } + rc = gpio_request(esd_gpio, "ESD_DET"); + if (rc) { + pr_err("request ESD gpio failed, rc=%d\n", rc); + return; + } +} +#endif +#endif + +#ifdef CONFIG_SAMSUNG_CMC624 /*change CMC gpio cfg*/ +static int mipi_pmic_gpios_pmconfig(int state) +{ + int ret; + + struct pm_gpio param = { + .disable_pin = state, + }; + + ret = pm8xxx_gpio_config(MLCD_ON, ¶m); + if (ret) { + pr_err("%s: Failed to configure gpio %d\n", __func__, + MLCD_ON); + return ret; + } + ret = pm8xxx_gpio_config(IMA_PWR_EN, ¶m); + if (ret) { + pr_err("%s: Failed to configure gpio %d\n", __func__, + IMA_PWR_EN); + return ret; + } + ret = pm8xxx_gpio_config(IMA_nRST, ¶m); + if (ret) { + pr_err("%s: Failed to configure gpio %d\n", __func__, + IMA_nRST); + return ret; + } + ret = pm8xxx_gpio_config(IMA_SLEEP, ¶m); + if (ret) { + pr_err("%s: Failed to configure gpio %d\n", __func__, + IMA_SLEEP); + return ret; + } + ret = pm8xxx_gpio_config(IMA_CMC_EN, ¶m); + if (ret) { + pr_err("%s: Failed to configure gpio %d\n", __func__, + IMA_CMC_EN); + return ret; + } + return 0; +} +#endif + +static int mipi_dsi_cdp_panel_power(int on) +{ + static struct regulator *reg_l8, *reg_l2; +#if defined(CONFIG_MACH_JAGUAR) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_MACH_EXPRESS) + static struct regulator *reg_l23; +#endif + static int gpio43; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + static int gpio_lcd_22v_en; +#endif + int rc = 0; + + struct pm_gpio gpio43_param = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) ||\ + defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) ||\ + defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + .output_value = 1, +#else + .output_value = 0, +#endif + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .disable_pin = 0, + }; + pr_debug("%s: state : %d\n", __func__, on); + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + gpio_lcd_22v_en = gpio_rev(LCD_22V_EN); +#endif + gpio43 = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_LCD_RST); + if (!dsi_power_on) { + + reg_l8 = regulator_get(&msm_mipi_dsi1_device.dev, + "dsi_vdc"); + if (IS_ERR(reg_l8)) { + pr_err("could not get 8921_l8, rc = %ld\n", + PTR_ERR(reg_l8)); + return -ENODEV; + } +#if defined(CONFIG_MACH_JAGUAR) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_MACH_EXPRESS) + reg_l23 = regulator_get(&msm_mipi_dsi1_device.dev, + "dsi_vddio"); + if (IS_ERR(reg_l23)) { + pr_err("could not get 8921_l23, rc = %ld\n", + PTR_ERR(reg_l23)); + return -ENODEV; + } +#else +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + rc = gpio_request(gpio_lcd_22v_en, "lcd_22v_en"); +#elif !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + && !defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + && !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + + rc = gpio_request(GPIO_LCD_22V_EN, "lcd_22v_en"); +#endif + if (rc) { + pr_err("request lcd_22v_en failed, rc=%d\n", rc); + return -ENODEV; + } +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + gpio_tlmm_config(GPIO_CFG(gpio_lcd_22v_en, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + GPIO_CFG_ENABLE); +#elif !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT)\ + && !defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL)\ + && !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + gpio_tlmm_config(GPIO_CFG(GPIO_LCD_22V_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + GPIO_CFG_ENABLE); +#endif +#endif + reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev, + "dsi_vdda"); + if (IS_ERR(reg_l2)) { + pr_err("could not get 8921_l2, rc = %ld\n", + PTR_ERR(reg_l2)); + return -ENODEV; + } +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + rc = regulator_set_voltage(reg_l8, 3100000, 3100000); + if (rc) { + pr_err("set_voltage l8 failed, rc=%d\n", rc); + return -EINVAL; + } +#else + rc = regulator_set_voltage(reg_l8, 3000000, 3100000); + if (rc) { + pr_err("set_voltage l8 failed, rc=%d\n", rc); + return -EINVAL; + } +#endif +#if defined(CONFIG_MACH_JAGUAR) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_MACH_EXPRESS) + rc = regulator_set_voltage(reg_l23, 1800000, 1800000); + if (rc) { + pr_err("set_voltage l23 failed, rc=%d\n", rc); + return -EINVAL; + } +#endif + + rc = regulator_set_voltage(reg_l2, 1200000, 1200000); + if (rc) { + pr_err("set_voltage l2 failed, rc=%d\n", rc); + return -EINVAL; + } + + /* + * turn VDD3.0, VDD1.8 on + */ + rc = regulator_set_optimum_mode(reg_l8, 100000); + if (rc < 0) { + pr_err("set_optimum_mode l8 failed, rc=%d\n", rc); + return -EINVAL; + } +#if defined(CONFIG_MACH_JAGUAR) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_MACH_EXPRESS) + rc = regulator_set_optimum_mode(reg_l23, 100000); + if (rc < 0) { + pr_err("set_optimum_mode l23 failed, rc=%d\n", rc); + return -EINVAL; + } +#endif + rc = regulator_set_optimum_mode(reg_l2, 100000); + if (rc < 0) { + pr_err("set_optimum_mode l2 failed, rc=%d\n", rc); + return -EINVAL; + } + + rc = regulator_enable(reg_l2); + if (rc) { + pr_err("enable l2 failed, rc=%d\n", rc); + return -ENODEV; + } + rc = gpio_request(gpio43, "disp_rst_n"); + if (rc) { + pr_err("request gpio 43 failed, rc=%d\n", rc); + return -ENODEV; + } + + rc = pm8xxx_gpio_config(gpio43, &gpio43_param); + if (rc) { + pr_err("gpio_config 43 failed (3), rc=%d\n", rc); + return -EINVAL; + } + +#if defined(CONFIG_MACH_JAGUAR) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_MACH_EXPRESS) + rc = regulator_enable(reg_l23); + if (rc) { + pr_err("enable l23 failed, rc=%d\n", rc); + return -ENODEV; + } +#else +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + gpio_direction_output(gpio_lcd_22v_en, 1); +#elif !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT)\ + && !defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + && !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + gpio_direction_output(GPIO_LCD_22V_EN, 1); +#endif +#endif + msleep(20); + rc = regulator_enable(reg_l8); + if (rc) { + pr_err("enable l8 failed, rc=%d\n", rc); + return -ENODEV; + } +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT)\ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT)\ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + udelay(100); +#endif + +#if defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT) + mdelay(150); +#endif +#if defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + + udelay(10); + active_reset_ldi(); +#endif +#if defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT) + mdelay(50); +#endif +#ifdef CONFIG_SAMSUNG_CMC624 + if (samsung_has_cmc624()) { + struct pm_gpio cmc_gpio_param = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .disable_pin = 0, + }; + gpio_tlmm_config(GPIO_CFG(GPIO_IMA_I2C_SDA, 0, + GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), GPIO_CFG_DISABLE); + gpio_tlmm_config(GPIO_CFG(GPIO_IMA_I2C_SCL, 0, + GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), GPIO_CFG_DISABLE); + + pm8xxx_gpio_config(MLCD_ON, &cmc_gpio_param); + pm8xxx_gpio_config(IMA_PWR_EN, &cmc_gpio_param); + pm8xxx_gpio_config(IMA_nRST, &cmc_gpio_param); + pm8xxx_gpio_config(IMA_SLEEP, &cmc_gpio_param); + pm8xxx_gpio_config(IMA_CMC_EN, &cmc_gpio_param); + rc = gpio_request(IMA_PWR_EN, "IMA_PWR_EN"); + if (rc) { + pr_err("request IMA_PWR_EN failed, rc=%d\n", + rc); + return -ENODEV; + } + rc = gpio_request(IMA_nRST, "IMA_nRST"); + if (rc) { + pr_err("request IMA_nRST failed, rc=%d\n", + rc); + return -ENODEV; + } + rc = gpio_request(IMA_SLEEP, "IMA_SLEEP"); + if (rc) { + pr_err("request IMA_SLEEP failed, rc=%d\n", rc); + return -ENODEV; + } + rc = gpio_request(IMA_CMC_EN, "IMA_CMC_EN"); + if (rc) { + pr_err("request IMA_CMC_EN failed, rc=%d\n", + rc); + return -ENODEV; + } + rc = gpio_request(MLCD_ON, "IMA_CMC_EN"); + if (rc) { + pr_err("request MLCD_ON failed, rc=%d\n", rc); + return -ENODEV; + } + pr_info("All CMC GPIOs configured\n"); + cmc_power(on); + mdelay(25); + active_reset_ldi(); + mdelay(5); + samsung_cmc624_on(1); + } else { + gpio_direction_output(gpio43, 1); + } +#else + gpio_direction_output(gpio43, 1); +#endif + dsi_power_on = true; + + return 0; + } + + if (on) { + + /* + * turn VDD3.0, VDD1.8 on + */ +#ifdef CONFIG_SAMSUNG_CMC624/*change CMC gpio cfg*/ + mipi_pmic_gpios_pmconfig(0); +#endif + rc = regulator_set_optimum_mode(reg_l8, 100000); + if (rc < 0) { + pr_err("set_optimum_mode l8 failed, rc=%d\n", rc); + return -EINVAL; + } +#if defined(CONFIG_MACH_JAGUAR) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_MACH_EXPRESS) + rc = regulator_set_optimum_mode(reg_l23, 100000); + if (rc < 0) { + pr_err("set_optimum_mode l23 failed, rc=%d\n", rc); + return -EINVAL; + } +#endif + rc = regulator_set_optimum_mode(reg_l2, 100000); + if (rc < 0) { + pr_err("set_optimum_mode l2 failed, rc=%d\n", rc); + return -EINVAL; + } + + rc = regulator_enable(reg_l2); + if (rc) { + pr_err("enable l2 failed, rc=%d\n", rc); + return -ENODEV; + } +#if defined(CONFIG_MACH_JAGUAR) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_MACH_EXPRESS) + rc = regulator_enable(reg_l23); + if (rc) { + pr_err("enable l23 failed, rc=%d\n", rc); + return -ENODEV; + } +#else +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + gpio_direction_output(gpio_lcd_22v_en, 1); +#elif !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT)\ + && !defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + && !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + + gpio_direction_output(GPIO_LCD_22V_EN, 1); +#endif +#endif + +#if !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL)\ + && !defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT) + udelay(500); +#endif + rc = regulator_enable(reg_l8); + if (rc) { + pr_err("enable l8 failed, rc=%d\n", rc); + return -ENODEV; + } + #ifdef CONFIG_SAMSUNG_CMC624 + /* Enable CMC Chip */ + if (samsung_has_cmc624()) + cmc_power(on); + #endif + + #if !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) + /* Wait 25ms */ + msleep(25); + #endif + /* Active Reset */ +#ifdef CONFIG_SAMSUNG_CMC624 + if (samsung_has_cmc624()) { + active_reset_ldi(); + mdelay(5); + samsung_cmc624_on(1); + } else { + active_reset_ldi(); + } +#else + active_reset_ldi(); +#endif +#if !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) + udelay(500); +#endif + } else { + +#ifdef CONFIG_SAMSUNG_CMC624 + if (samsung_has_cmc624()) { + samsung_cmc624_on(0); + cmc_power(0); + } + mipi_pmic_gpios_pmconfig(1);/*change CMC gpio cfg*/ +#endif + +#if !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + gpio_set_value_cansleep(gpio43, 0); +#endif + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) + + msleep(120); +#endif + + rc = regulator_disable(reg_l8); + if (rc) { + pr_err("disable l8 failed, rc=%d\n", rc); + return -ENODEV; + } + +#if defined(CONFIG_MACH_JAGUAR) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_MACH_EXPRESS) + + rc = regulator_disable(reg_l23); + if (rc) { + pr_err("disable l23 failed, rc=%d\n", rc); + return -ENODEV; + } +#else +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + gpio_direction_output(gpio_lcd_22v_en, 0); +#elif !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + && !defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + && !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + && !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + + gpio_direction_output(GPIO_LCD_22V_EN, 0); +#endif +#endif + rc = regulator_disable(reg_l2); + if (rc) { + pr_err("disable l2 failed, rc=%d\n", rc); + return -ENODEV; + } + + rc = regulator_set_optimum_mode(reg_l8, 100); + if (rc < 0) { + pr_err("set_optimum_mode l8 failed, rc=%d\n", rc); + return -EINVAL; + } +#if defined(CONFIG_MACH_JAGUAR) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT_PANEL) \ + || defined(CONFIG_MACH_EXPRESS) + rc = regulator_set_optimum_mode(reg_l23, 100); + if (rc < 0) { + pr_err("set_optimum_mode l23 failed, rc=%d\n", rc); + return -EINVAL; + } +#endif + rc = regulator_set_optimum_mode(reg_l2, 100); + if (rc < 0) { + pr_err("set_optimum_mode l2 failed, rc=%d\n", rc); + return -EINVAL; + } + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + gpio_set_value_cansleep(gpio43, 0); +#endif + } + + return 0; +} +#if 0 +static char mipi_dsi_splash_is_enabled(void); +#endif +static int mipi_dsi_panel_power(int on) +{ + int ret; + + pr_debug("%s: on=%d\n", __func__, on); + + if (machine_is_msm8960_liquid()) + ret = mipi_dsi_liquid_panel_power(on); +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + else if (machine_is_ESPRESSO_VZW() + || machine_is_ESPRESSO_SPR() + || machine_is_ESPRESSO_ATT() + || machine_is_ESPRESSO10_SPR() + || machine_is_ESPRESSO10_VZW() + || machine_is_ESPRESSO10_ATT()) + ret = mipi_dsi_espresso_dsi_power(on); +#endif + else + ret = mipi_dsi_cdp_panel_power(on); + + return ret; +} + +static struct mipi_dsi_platform_data mipi_dsi_pdata = { + .vsync_gpio = MDP_VSYNC_GPIO, + .dsi_power_save = mipi_dsi_panel_power, +#ifdef CONFIG_FB_MSM_MIPI_PANEL_POWERON_LP11 + .dsi_client_power_save = mipi_dsi_espresso_panel_power, + .dsi_client_reset = mipi_dsi_tc35reset_release, +#endif /* CONFIG_FB_MSM_MIPI_PANEL_POWERON_LP11 */ + .lcd_rst_up = pull_ldi_reset_up, + .lcd_rst_down = pull_ldi_reset_down, +}; +#ifdef CONFIG_MSM_BUS_SCALING +static struct msm_bus_vectors mdp_init_vectors[] = { + { + .src = MSM_BUS_MASTER_MDP_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors mdp_ui_vectors[] = { + { + .src = MSM_BUS_MASTER_MDP_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 216000000 * 2, + .ib = 270000000 * 2, + }, +}; + +static struct msm_bus_vectors mdp_vga_vectors[] = { + /* VGA and less video */ + { + .src = MSM_BUS_MASTER_MDP_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 216000000 * 2, + .ib = 270000000 * 2, + }, +}; + +static struct msm_bus_vectors mdp_720p_vectors[] = { + /* 720p and less video */ + { + .src = MSM_BUS_MASTER_MDP_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 230400000 * 2, + .ib = 288000000 * 2, + }, +}; + +static struct msm_bus_vectors mdp_1080p_vectors[] = { + /* 1080p and less video */ + { + .src = MSM_BUS_MASTER_MDP_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 334080000 * 2, + .ib = 417600000 * 2, + }, +}; + +static struct msm_bus_paths mdp_bus_scale_usecases[] = { + { + ARRAY_SIZE(mdp_init_vectors), + mdp_init_vectors, + }, + { + ARRAY_SIZE(mdp_ui_vectors), + mdp_ui_vectors, + }, + { + ARRAY_SIZE(mdp_ui_vectors), + mdp_ui_vectors, + }, + { + ARRAY_SIZE(mdp_vga_vectors), + mdp_vga_vectors, + }, + { + ARRAY_SIZE(mdp_720p_vectors), + mdp_720p_vectors, + }, + { + ARRAY_SIZE(mdp_1080p_vectors), + mdp_1080p_vectors, + }, +}; + +static struct msm_bus_scale_pdata mdp_bus_scale_pdata = { + mdp_bus_scale_usecases, + ARRAY_SIZE(mdp_bus_scale_usecases), + .name = "mdp", +}; + +#endif + +static struct msm_panel_common_pdata mdp_pdata = { + .gpio = MDP_VSYNC_GPIO, + .mdp_max_clk = 200000000, +#ifdef CONFIG_MSM_BUS_SCALING + .mdp_bus_scale_table = &mdp_bus_scale_pdata, +#endif + .mdp_rev = MDP_REV_42, +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + .mem_hid = BIT(ION_CP_MM_HEAP_ID), +#else + .mem_hid = MEMTYPE_EBI1, +#endif + .cont_splash_enabled = 0x0, + .mdp_iommu_split_domain = 0, +}; + +void __init msm8960_mdp_writeback(struct memtype_reserve* reserve_table) +{ + mdp_pdata.ov0_wb_size = MSM_FB_OVERLAY0_WRITEBACK_SIZE; + mdp_pdata.ov1_wb_size = MSM_FB_OVERLAY1_WRITEBACK_SIZE; +#if defined(CONFIG_ANDROID_PMEM) && !defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + reserve_table[mdp_pdata.mem_hid].size += + mdp_pdata.ov0_wb_size; + reserve_table[mdp_pdata.mem_hid].size += + mdp_pdata.ov1_wb_size; +#endif +} +#if 0 +static char mipi_dsi_splash_is_enabled(void) +{ + return mdp_pdata.cont_splash_enabled; +} +#endif +static struct platform_device mipi_dsi_renesas_panel_device = { + .name = "mipi_renesas", + .id = 0, +}; + +static struct platform_device mipi_dsi_simulator_panel_device = { + .name = "mipi_simulator", + .id = 0, +}; + +#define LPM_CHANNEL0 0 +#if defined(CONFIG_FB_MSM_MIPI_DSI_TOSHIBA) +static int toshiba_gpio[] = {LPM_CHANNEL0}; + +static struct mipi_dsi_panel_platform_data toshiba_pdata = { + .gpio = toshiba_gpio, + .dsi_pwm_cfg = mipi_dsi_panel_pwm_cfg, +}; + +static struct platform_device mipi_dsi_toshiba_panel_device = { + .name = "mipi_toshiba", + .id = 0, + .dev = { + .platform_data = &toshiba_pdata, + } +}; +#endif + +#define FPGA_3D_GPIO_CONFIG_ADDR 0xB5 +static int dsi2lvds_gpio[2] = { +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + 1,/* Backlight PWM-ID=1 for PMIC-GPIO#25 */ + 0x0000 /* GPIOs not connected in espresso*/ +#else + 0,/* Backlight PWM-ID=0 for PMIC-GPIO#24 */ + 0x1F08 /* DSI2LVDS Bridge GPIO Output, mask=0x1f, out=0x08 */ + +#endif + }; + +static struct msm_panel_common_pdata mipi_dsi2lvds_pdata = { + .gpio_num = dsi2lvds_gpio, + .cont_splash_enabled = 0x0, +}; + +static struct mipi_dsi_phy_ctrl dsi_novatek_cmd_mode_phy_db = { + +/* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */ + {0x0F, 0x0a, 0x04, 0x00, 0x20}, /* regulator */ + /* timing */ + {0xab, 0x8a, 0x18, 0x00, 0x92, 0x97, 0x1b, 0x8c, + 0x0c, 0x03, 0x04, 0xa0}, + {0x5f, 0x00, 0x00, 0x10}, /* phy ctrl */ + {0xff, 0x00, 0x06, 0x00}, /* strength */ + /* pll control */ + {0x40, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62, + 0x40, 0x07, 0x03, + 0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01}, +}; + +static struct mipi_dsi_panel_platform_data novatek_pdata = { + .fpga_3d_config_addr = FPGA_3D_GPIO_CONFIG_ADDR, + .fpga_ctrl_mode = FPGA_SPI_INTF, + .phy_ctrl_settings = &dsi_novatek_cmd_mode_phy_db, +}; + +static struct platform_device mipi_dsi_novatek_panel_device = { + .name = "mipi_novatek", + .id = 0, + .dev = { + .platform_data = &novatek_pdata, + } +}; + +static struct platform_device mipi_dsi2lvds_bridge_device = { + .name = "mipi_tc358764", + .id = 0, + .dev.platform_data = &mipi_dsi2lvds_pdata, +}; +static struct platform_device mipi_dsi_samsung_oled_panel_device = { + .name = "mipi_samsung_oled", + .id = 0, + .dev.platform_data = &mipi_dsi_pdata, +}; + +static struct platform_device mipi_dsi_orise_panel_device = { + .name = "mipi_orise", + .id = 0, +}; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static struct resource hdmi_msm_resources[] = { + { + .name = "hdmi_msm_qfprom_addr", + .start = 0x00700000, + .end = 0x007060FF, + .flags = IORESOURCE_MEM, + }, + { + .name = "hdmi_msm_hdmi_addr", + .start = 0x04A00000, + .end = 0x04A00FFF, + .flags = IORESOURCE_MEM, + }, + { + .name = "hdmi_msm_irq", + .start = HDMI_IRQ, + .end = HDMI_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static int hdmi_enable_5v(int on); +static int hdmi_core_power(int on, int show); +static int hdmi_cec_power(int on); +static int hdmi_gpio_config(int on); +static int hdmi_panel_power(int on); + +static struct msm_hdmi_platform_data hdmi_msm_data = { + .irq = HDMI_IRQ, + .enable_5v = hdmi_enable_5v, + .core_power = hdmi_core_power, + .cec_power = hdmi_cec_power, + .panel_power = hdmi_panel_power, + .gpio_config = hdmi_gpio_config, +}; + +static struct platform_device hdmi_msm_device = { + .name = "hdmi_msm", + .id = 0, + .num_resources = ARRAY_SIZE(hdmi_msm_resources), + .resource = hdmi_msm_resources, + .dev.platform_data = &hdmi_msm_data, +}; +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */ + +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL +static struct platform_device wfd_panel_device = { + .name = "wfd_panel", + .id = 0, + .dev.platform_data = NULL, +}; + +static struct platform_device wfd_device = { + .name = "msm_wfd", + .id = -1, +}; +#endif + +#ifdef CONFIG_MSM_BUS_SCALING +static struct msm_bus_vectors dtv_bus_init_vectors[] = { + { + .src = MSM_BUS_MASTER_MDP_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors dtv_bus_def_vectors[] = { + { + .src = MSM_BUS_MASTER_MDP_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 566092800 * 2, + .ib = 707616000 * 2, + }, +}; + +static struct msm_bus_paths dtv_bus_scale_usecases[] = { + { + ARRAY_SIZE(dtv_bus_init_vectors), + dtv_bus_init_vectors, + }, + { + ARRAY_SIZE(dtv_bus_def_vectors), + dtv_bus_def_vectors, + }, +}; +static struct msm_bus_scale_pdata dtv_bus_scale_pdata = { + dtv_bus_scale_usecases, + ARRAY_SIZE(dtv_bus_scale_usecases), + .name = "dtv", +}; +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static struct lcdc_platform_data dtv_pdata = { + .bus_scale_table = &dtv_bus_scale_pdata, + .lcdc_power_save = hdmi_panel_power, +}; + +static int hdmi_panel_power(int on) +{ + int rc; + + pr_debug("%s: HDMI Core: %s\n", __func__, (on ? "ON" : "OFF")); + rc = hdmi_core_power(on, 1); + if (rc) + rc = hdmi_cec_power(on); + + pr_debug("%s: HDMI Core: %s Success\n", __func__, (on ? "ON" : "OFF")); + return rc; +} +#endif +#endif + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static int hdmi_enable_5v(int on) +{ + /* TBD: PM8921 regulator instead of 8901 */ + static struct regulator *reg_8921_hdmi_mvs; /* HDMI_5V */ + static int prev_on; + int rc; + + if (on == prev_on) + return 0; + + if (!reg_8921_hdmi_mvs) { + reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev, + "hdmi_mvs"); + if (IS_ERR(reg_8921_hdmi_mvs)) { + pr_err("'%s' regulator not found, rc=%ld\n", + "hdmi_mvs", IS_ERR(reg_8921_hdmi_mvs)); + reg_8921_hdmi_mvs = NULL; + return -ENODEV; + } + } + + if (on) { + rc = regulator_enable(reg_8921_hdmi_mvs); + if (rc) { + pr_err("'%s' regulator enable failed, rc=%d\n", + "8921_hdmi_mvs", rc); + return rc; + } + pr_debug("%s(on): success\n", __func__); + } else { + rc = regulator_disable(reg_8921_hdmi_mvs); + if (rc) + pr_warning("'%s' regulator disable failed, rc=%d\n", + "8921_hdmi_mvs", rc); + pr_debug("%s(off): success\n", __func__); + } + + prev_on = on; + + return 0; +} + +static int hdmi_core_power(int on, int show) +{ + static struct regulator *reg_8921_l23, *reg_8921_s4; + static int prev_on; + int rc; + + if (on == prev_on) + return 0; + + /* TBD: PM8921 regulator instead of 8901 */ + if (!reg_8921_l23) { + reg_8921_l23 = regulator_get(&hdmi_msm_device.dev, "hdmi_avdd"); + if (IS_ERR(reg_8921_l23)) { + pr_err("could not get reg_8921_l23, rc = %ld\n", + PTR_ERR(reg_8921_l23)); + return -ENODEV; + } + rc = regulator_set_voltage(reg_8921_l23, 1800000, 1800000); + if (rc) { + pr_err("set_voltage failed for 8921_l23, rc=%d\n", rc); + return -EINVAL; + } + } + if (!reg_8921_s4) { + reg_8921_s4 = regulator_get(&hdmi_msm_device.dev, "hdmi_vcc"); + if (IS_ERR(reg_8921_s4)) { + pr_err("could not get reg_8921_s4, rc = %ld\n", + PTR_ERR(reg_8921_s4)); + return -ENODEV; + } + rc = regulator_set_voltage(reg_8921_s4, 1800000, 1800000); + if (rc) { + pr_err("set_voltage failed for 8921_s4, rc=%d\n", rc); + return -EINVAL; + } + } + + if (on) { + rc = regulator_set_optimum_mode(reg_8921_l23, 100000); + if (rc < 0) { + pr_err("set_optimum_mode l23 failed, rc=%d\n", rc); + return -EINVAL; + } + rc = regulator_enable(reg_8921_l23); + if (rc) { + pr_err("'%s' regulator enable failed, rc=%d\n", + "hdmi_avdd", rc); + return rc; + } + rc = regulator_enable(reg_8921_s4); + if (rc) { + pr_err("'%s' regulator enable failed, rc=%d\n", + "hdmi_vcc", rc); + return rc; + } + pr_debug("%s(on): success\n", __func__); + } else { + rc = regulator_disable(reg_8921_l23); + if (rc) { + pr_err("disable reg_8921_l23 failed, rc=%d\n", rc); + return -ENODEV; + } + rc = regulator_disable(reg_8921_s4); + if (rc) { + pr_err("disable reg_8921_s4 failed, rc=%d\n", rc); + return -ENODEV; + } + rc = regulator_set_optimum_mode(reg_8921_l23, 100); + if (rc < 0) { + pr_err("set_optimum_mode l23 failed, rc=%d\n", rc); + return -EINVAL; + } + pr_debug("%s(off): success\n", __func__); + } + + prev_on = on; + + return 0; +} + +static int hdmi_gpio_config(int on) +{ + int rc = 0; + static int prev_on; + + if (on == prev_on) + return 0; + + if (on) { + rc = gpio_request(100, "HDMI_DDC_CLK"); + if (rc) { + pr_err("'%s'(%d) gpio_request failed, rc=%d\n", + "HDMI_DDC_CLK", 100, rc); + return rc; + } + rc = gpio_request(101, "HDMI_DDC_DATA"); + if (rc) { + pr_err("'%s'(%d) gpio_request failed, rc=%d\n", + "HDMI_DDC_DATA", 101, rc); + goto error1; + } + rc = gpio_request(102, "HDMI_HPD"); + if (rc) { + pr_err("'%s'(%d) gpio_request failed, rc=%d\n", + "HDMI_HPD", 102, rc); + goto error2; + } + pr_debug("%s(on): success\n", __func__); + } else { + gpio_free(100); + gpio_free(101); + gpio_free(102); + pr_debug("%s(off): success\n", __func__); + } + + prev_on = on; + return 0; + +error2: + gpio_free(101); +error1: + gpio_free(100); + return rc; +} + +static int hdmi_cec_power(int on) +{ + static int prev_on; + int rc; + + if (on == prev_on) + return 0; + + if (on) { + rc = gpio_request(99, "HDMI_CEC_VAR"); + if (rc) { + pr_err("'%s'(%d) gpio_request failed, rc=%d\n", + "HDMI_CEC_VAR", 99, rc); + goto error; + } + pr_debug("%s(on): success\n", __func__); + } else { + gpio_free(99); + pr_debug("%s(off): success\n", __func__); + } + + prev_on = on; + + return 0; +error: + return rc; +} +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */ + + + +void __init msm8960_init_fb(void) +{ + uint32_t soc_platform_version = socinfo_get_version(); + +#ifdef CONFIG_SAMSUNG_CMC624 + if (samsung_has_cmc624()) { + msm_gpiomux_install(msm8x60_cmc624_configs, + ARRAY_SIZE(msm8x60_cmc624_configs)); + } +#endif + + if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3) + mdp_pdata.mdp_rev = MDP_REV_43; + + platform_device_register(&msm_fb_device); + +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL + platform_device_register(&wfd_panel_device); + platform_device_register(&wfd_device); +#endif + + if (machine_is_msm8960_sim()) + platform_device_register(&mipi_dsi_simulator_panel_device); + + if (machine_is_msm8960_rumi3()) + platform_device_register(&mipi_dsi_renesas_panel_device); + + if (!machine_is_msm8960_sim() && !machine_is_msm8960_rumi3()) { + platform_device_register(&mipi_dsi_novatek_panel_device); + platform_device_register(&mipi_dsi_orise_panel_device); + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL + platform_device_register(&hdmi_msm_device); +#endif + } + + if (machine_is_msm8960_liquid()) + platform_device_register(&mipi_dsi2lvds_bridge_device); + else + platform_device_register(&mipi_dsi_samsung_oled_panel_device); + +#ifdef CONFIG_SAMSUNG_CMC624 + platform_device_register(&cmc624_i2c_gpio_device); +#endif +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +#if defined(CONFIG_SAMSUNG_CMC624) + set_esd_gpio_config(); + esd_pdata.esd_gpio_irq = + PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_VGH_ESD_DET), + esd_pdata.esd_gpio_cmc_irq = + PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_CMC_ESD_DET), + platform_device_register(&samsung_mipi_esd_refresh_device); +#elif defined(CONFIG_MACH_JAGUAR) || \ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) + set_esd_gpio_config(); + esd_pdata.esd_gpio_irq = + PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_VGH_ESD_DET), + platform_device_register(&samsung_mipi_esd_refresh_device); +#else + if (gpio_rev(ESD_DET) > 0) { + set_esd_gpio_config(); + platform_device_register(&samsung_mipi_esd_refresh_device); + } +#endif +#endif + if (machine_is_msm8x60_rumi3()) { + msm_fb_register_device("mdp", NULL); + mipi_dsi_pdata.target_type = 1; + } else + msm_fb_register_device("mdp", &mdp_pdata); + + /*LCD MDP REV*/ + mipi_dsi_pdata.vsync_gpio = gpio_rev(MDP_VSYNC); + mdp_pdata.gpio = gpio_rev(MDP_VSYNC); + + msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata); +#ifdef CONFIG_MSM_BUS_SCALING +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL + msm_fb_register_device("dtv", &dtv_pdata); +#endif +#endif +} + +void __init msm8960_allocate_fb_region(void) +{ + void *addr; + unsigned long size; + + size = MSM_FB_SIZE; + addr = alloc_bootmem_align(size, 0x1000); + msm_fb_resources[0].start = __pa(addr); + msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; + pr_info("allocating %lu bytes at %p (%lx physical) for fb\n", + size, addr, __pa(addr)); +} + +/** + * Set MDP clocks to high frequency to avoid DSI underflow + * when using high resolution 1200x1920 WUXGA panels + */ +static void set_mdp_clocks_for_wuxga(void) +{ + mdp_ui_vectors[0].ab = 2000000000; + mdp_ui_vectors[0].ib = 2000000000; + mdp_vga_vectors[0].ab = 2000000000; + mdp_vga_vectors[0].ib = 2000000000; + mdp_720p_vectors[0].ab = 2000000000; + mdp_720p_vectors[0].ib = 2000000000; + mdp_1080p_vectors[0].ab = 2000000000; + mdp_1080p_vectors[0].ib = 2000000000; + + if (hdmi_is_primary) { + dtv_bus_def_vectors[0].ab = 2000000000; + dtv_bus_def_vectors[0].ib = 2000000000; + } +} + +void __init msm8960_set_display_params(char *prim_panel, char *ext_panel) +{ + int disable_splash = 0; + if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) { + strlcpy(msm_fb_pdata.prim_panel_name, prim_panel, + PANEL_NAME_MAX_LEN); + pr_debug("msm_fb_pdata.prim_panel_name %s\n", + msm_fb_pdata.prim_panel_name); + + if (strncmp((char *)msm_fb_pdata.prim_panel_name, + MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME, + strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) { + /* Disable splash for panels other than Toshiba WSVGA */ + disable_splash = 1; + } + + if (!strncmp((char *)msm_fb_pdata.prim_panel_name, + HDMI_PANEL_NAME, strnlen(HDMI_PANEL_NAME, + PANEL_NAME_MAX_LEN))) { + pr_debug("HDMI is the primary display by" + " boot parameter\n"); + hdmi_is_primary = 1; + set_mdp_clocks_for_wuxga(); + } + if (!strncmp((char *)msm_fb_pdata.prim_panel_name, + MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME, + strnlen(MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME, + PANEL_NAME_MAX_LEN))) { + set_mdp_clocks_for_wuxga(); + } + } + if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) { + strlcpy(msm_fb_pdata.ext_panel_name, ext_panel, + PANEL_NAME_MAX_LEN); + pr_debug("msm_fb_pdata.ext_panel_name %s\n", + msm_fb_pdata.ext_panel_name); + } + + if (disable_splash) + mdp_pdata.cont_splash_enabled = 0; +} diff --git a/arch/arm/mach-msm/board-m2-pmic.c b/arch/arm/mach-msm/board-m2-pmic.c new file mode 100644 index 00000000000..85a986ef1c1 --- /dev/null +++ b/arch/arm/mach-msm/board-m2-pmic.c @@ -0,0 +1,1068 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devices.h" +#include "board-8960.h" +extern unsigned int system_rev; +struct pm8xxx_gpio_init { + unsigned gpio; + struct pm_gpio config; +}; + +struct pm8xxx_mpp_init { + unsigned mpp; + struct pm8xxx_mpp_config_data config; +}; + +#define PM8XXX_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \ + _func, _inv, _disable) \ +{ \ + .gpio = PM8921_GPIO_PM_TO_SYS(_gpio), \ + .config = { \ + .direction = _dir, \ + .output_buffer = _buf, \ + .output_value = _val, \ + .pull = _pull, \ + .vin_sel = _vin, \ + .out_strength = _out_strength, \ + .function = _func, \ + .inv_int_pol = _inv, \ + .disable_pin = _disable, \ + } \ +} + +#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \ +{ \ + .mpp = PM8921_MPP_PM_TO_SYS(_mpp), \ + .config = { \ + .type = PM8XXX_MPP_TYPE_##_type, \ + .level = _level, \ + .control = PM8XXX_MPP_##_control, \ + } \ +} + +#define PM8XXX_GPIO_DISABLE(_gpio) \ + PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \ + 0, 0, 0, 1) + +#define PM8XXX_GPIO_OUTPUT(_gpio, _val) \ + PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \ + PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \ + PM_GPIO_STRENGTH_HIGH, \ + PM_GPIO_FUNC_NORMAL, 0, 0) + +#define PM8XXX_GPIO_INPUT(_gpio, _pull) \ + PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \ + _pull, PM_GPIO_VIN_S4, \ + PM_GPIO_STRENGTH_NO, \ + PM_GPIO_FUNC_NORMAL, 0, 0) + +#define PM8XXX_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \ + PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \ + PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \ + PM_GPIO_STRENGTH_HIGH, \ + _func, 0, 0) + +#define PM8XXX_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \ + PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \ + PM_GPIO_PULL_NO, _vin, \ + PM_GPIO_STRENGTH_HIGH, \ + PM_GPIO_FUNC_NORMAL, 0, 0) + +/* Initial PM8921 GPIO configurations */ +static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = { +#if !defined(CONFIG_MACH_M2_DCM) && !defined(CONFIG_MACH_K2_KDI) + PM8XXX_GPIO_INPUT(16, PM_GPIO_PULL_UP_30), /* SD_CARD_WP */ + /* External regulator shared by display and touchscreen on LiQUID */ + PM8XXX_GPIO_OUTPUT_VIN(21, 1, PM_GPIO_VIN_VPH), /* Backlight Enable */ + PM8XXX_GPIO_DISABLE(22), /* Disable NFC */ +#endif + PM8XXX_GPIO_OUTPUT_FUNC(24, 0, PM_GPIO_FUNC_2), /* Bl: Off, PWM mode */ +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + PM8XXX_GPIO_OUTPUT_FUNC(25, 0, PM_GPIO_FUNC_2), /* LED_BACKLIGHT_PWM */ +#endif /* CONFIG_MACH_ESPRESSO_VZW/ATT */ + + PM8XXX_GPIO_INPUT(26, PM_GPIO_PULL_NO), /* SD_CARD_DET_N */ +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + PM8XXX_GPIO_OUTPUT(43, 0), /* LED_BACKLIGHT_RESET */ +#else + PM8XXX_GPIO_OUTPUT(43, 1), /* DISP_RESET_N */ +#endif + PM8XXX_GPIO_INPUT(42, PM_GPIO_PULL_NO), /* USB 5V reg enable */ +#if defined(CONFIG_CHARGER_SMB347) + PM8XXX_GPIO_INPUT(17, PM_GPIO_PULL_UP_30), /* CHG_STAT */ +#else + PM8XXX_GPIO_OUTPUT(17, 0), /* DISP 3.3 V Boost */ +#endif +#if defined(CONFIG_MACH_ESPRESSO_VZW) || defined(CONFIG_MACH_ESPRESSO10_VZW) \ + || defined(CONFIG_MACH_ESPRESSO10_ATT) \ + || defined(CONFIG_MACH_ESPRESSO10_SPR) \ + || defined(CONFIG_MACH_ESPRESSO_SPR) + PM8XXX_GPIO_OUTPUT(38, 1), +#endif + +#if defined(CONFIG_MACH_AEGIS2) /* Disable NC GPIOs for AEGIS2*/ + PM8XXX_GPIO_DISABLE(1), + PM8XXX_GPIO_DISABLE(2), + PM8XXX_GPIO_DISABLE(9), + PM8XXX_GPIO_DISABLE(15), + PM8XXX_GPIO_DISABLE(23), + PM8XXX_GPIO_DISABLE(28), + PM8XXX_GPIO_DISABLE(35), + PM8XXX_GPIO_DISABLE(40), + PM8XXX_GPIO_DISABLE(41), +#endif +}; + +/* Initial PM8921 MPP configurations */ +static struct pm8xxx_mpp_init pm8921_mpps[] __initdata = { + /* External 5V regulator enable; shared by HDMI and USB_OTG switches. */ + PM8XXX_MPP_INIT(7, D_INPUT, PM8921_MPP_DIG_LEVEL_VPH, DIN_TO_INT), +#ifdef CONFIG_OPTICAL_GP2A + PM8XXX_MPP_INIT(PM8XXX_AMUX_MPP_4, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH7, + DOUT_CTRL_LOW), +#endif + PM8XXX_MPP_INIT(PM8XXX_AMUX_MPP_8, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH8, + DOUT_CTRL_LOW), +}; + +void __init msm8960_pm8921_gpio_mpp_init(void) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(pm8921_gpios); i++) { + rc = pm8xxx_gpio_config(pm8921_gpios[i].gpio, + &pm8921_gpios[i].config); + if (rc) { + pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc); + break; + } + } + + for (i = 0; i < ARRAY_SIZE(pm8921_mpps); i++) { + rc = pm8xxx_mpp_config(pm8921_mpps[i].mpp, + &pm8921_mpps[i].config); + if (rc) { + pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc); + break; + } + } +} + +static struct pm8xxx_adc_amux pm8xxx_adc_channels_data[] = { + {"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2, + ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM}, + {"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM}, + {"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, + {"pa_therm1", ADC_MPP_1_AMUX8, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM}, + {"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0, + ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM}, + {"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM}, + {"dev_mpp_7", ADC_MPP_1_AMUX6, CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_SEC_BOARD_THERM}, /*main_thm */ +#ifdef CONFIG_SAMSUNG_JACK + {"earjack", ADC_MPP_1_AMUX6_SCALE_DEFAULT, + CHAN_PATH_SCALING1, AMUX_RSV1, + ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT}, +#endif +}; + +static struct pm8xxx_adc_properties pm8xxx_adc_data = { + .adc_vdd_reference = 1800, /* milli-voltage for this adc */ + .bitresolution = 15, + .bipolar = 0, +}; + +static struct pm8xxx_adc_platform_data pm8xxx_adc_pdata = { + .adc_channel = pm8xxx_adc_channels_data, + .adc_num_board_channel = ARRAY_SIZE(pm8xxx_adc_channels_data), + .adc_prop = &pm8xxx_adc_data, + .adc_mpp_base = PM8921_MPP_PM_TO_SYS(1), +}; + +static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata __devinitdata = { + .irq_base = PM8921_IRQ_BASE, + .devirq = MSM_GPIO_TO_INT(104), + .irq_trigger_flag = IRQF_TRIGGER_LOW, +}; + +static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata __devinitdata = { + .gpio_base = PM8921_GPIO_PM_TO_SYS(1), +}; + +static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata __devinitdata = { + .mpp_base = PM8921_MPP_PM_TO_SYS(1), +}; + +static struct pm8xxx_rtc_platform_data pm8xxx_rtc_pdata __devinitdata = { + .rtc_write_enable = false, + .rtc_alarm_powerup = false, +}; + +static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = { + .pull_up = 1, + .kpd_trigger_delay_us = 15625, + .wakeup = 1, +}; + +/* Rotate lock key is not available so use F1 */ +#define KEY_ROTATE_LOCK KEY_F1 + +static const unsigned int keymap_liquid[] = { + KEY(0, 0, KEY_VOLUMEUP), + KEY(0, 1, KEY_VOLUMEDOWN), + KEY(1, 3, KEY_ROTATE_LOCK), + KEY(1, 4, KEY_HOME), +}; + +static struct matrix_keymap_data keymap_data_liquid = { + .keymap_size = ARRAY_SIZE(keymap_liquid), + .keymap = keymap_liquid, +}; + +static struct pm8xxx_keypad_platform_data keypad_data_liquid = { + .input_name = "keypad_8960_liquid", + .input_phys_device = "keypad_8960/input0", + .num_rows = 2, + .num_cols = 5, + .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9), + .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1), + .debounce_ms = 15, + .scan_delay_ms = 32, + .row_hold_ns = 91500, + .wakeup = 1, + .keymap_data = &keymap_data_liquid, +}; + +static const unsigned int keymap[] = { + KEY(0, 0, KEY_SEARCH), + KEY(0, 1, KEY_BACK), + KEY(0, 2, KEY_HOME), + KEY(0, 3, KEY_MENU), +}; + +static struct matrix_keymap_data keymap_data = { + .keymap_size = ARRAY_SIZE(keymap), + .keymap = keymap, +}; + +static struct pm8xxx_keypad_platform_data keypad_data = { + .input_name = "keypad_8960", + .input_phys_device = "keypad_8960/input0", + .num_rows = 1, + .num_cols = 5, + .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9), + .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1), + .debounce_ms = 15, + .scan_delay_ms = 32, + .row_hold_ns = 91500, + .wakeup = 1, + .keymap_data = &keymap_data, +}; + +static const unsigned int keymap_sim[] = { + KEY(0, 0, KEY_7), + KEY(0, 1, KEY_DOWN), + KEY(0, 2, KEY_UP), + KEY(0, 3, KEY_RIGHT), + KEY(0, 4, KEY_ENTER), + KEY(0, 5, KEY_L), + KEY(0, 6, KEY_BACK), + KEY(0, 7, KEY_M), + + KEY(1, 0, KEY_LEFT), + KEY(1, 1, KEY_SEND), + KEY(1, 2, KEY_1), + KEY(1, 3, KEY_4), + KEY(1, 4, KEY_CLEAR), + KEY(1, 5, KEY_MSDOS), + KEY(1, 6, KEY_SPACE), + KEY(1, 7, KEY_COMMA), + + KEY(2, 0, KEY_6), + KEY(2, 1, KEY_5), + KEY(2, 2, KEY_8), + KEY(2, 3, KEY_3), + KEY(2, 4, KEY_NUMERIC_STAR), + KEY(2, 5, KEY_UP), + KEY(2, 6, KEY_DOWN), + KEY(2, 7, KEY_LEFTSHIFT), + + KEY(3, 0, KEY_9), + KEY(3, 1, KEY_NUMERIC_POUND), + KEY(3, 2, KEY_0), + KEY(3, 3, KEY_2), + KEY(3, 4, KEY_SLEEP), + KEY(3, 5, KEY_F1), + KEY(3, 6, KEY_F2), + KEY(3, 7, KEY_F3), + + KEY(4, 0, KEY_BACK), + KEY(4, 1, KEY_HOME), + KEY(4, 2, KEY_MENU), + KEY(4, 3, KEY_VOLUMEUP), + KEY(4, 4, KEY_VOLUMEDOWN), + KEY(4, 5, KEY_F4), + KEY(4, 6, KEY_F5), + KEY(4, 7, KEY_F6), + + KEY(5, 0, KEY_R), + KEY(5, 1, KEY_T), + KEY(5, 2, KEY_Y), + KEY(5, 3, KEY_LEFTALT), + KEY(5, 4, KEY_KPENTER), + KEY(5, 5, KEY_Q), + KEY(5, 6, KEY_W), + KEY(5, 7, KEY_E), + + KEY(6, 0, KEY_F), + KEY(6, 1, KEY_G), + KEY(6, 2, KEY_H), + KEY(6, 3, KEY_CAPSLOCK), + KEY(6, 4, KEY_PAGEUP), + KEY(6, 5, KEY_A), + KEY(6, 6, KEY_S), + KEY(6, 7, KEY_D), + + KEY(7, 0, KEY_V), + KEY(7, 1, KEY_B), + KEY(7, 2, KEY_N), + KEY(7, 3, KEY_MENU), + KEY(7, 4, KEY_PAGEDOWN), + KEY(7, 5, KEY_Z), + KEY(7, 6, KEY_X), + KEY(7, 7, KEY_C), + + KEY(8, 0, KEY_P), + KEY(8, 1, KEY_J), + KEY(8, 2, KEY_K), + KEY(8, 3, KEY_INSERT), + KEY(8, 4, KEY_LINEFEED), + KEY(8, 5, KEY_U), + KEY(8, 6, KEY_I), + KEY(8, 7, KEY_O), + + KEY(9, 0, KEY_4), + KEY(9, 1, KEY_5), + KEY(9, 2, KEY_6), + KEY(9, 3, KEY_7), + KEY(9, 4, KEY_8), + KEY(9, 5, KEY_1), + KEY(9, 6, KEY_2), + KEY(9, 7, KEY_3), + + KEY(10, 0, KEY_F7), + KEY(10, 1, KEY_F8), + KEY(10, 2, KEY_F9), + KEY(10, 3, KEY_F10), + KEY(10, 4, KEY_FN), + KEY(10, 5, KEY_9), + KEY(10, 6, KEY_0), + KEY(10, 7, KEY_DOT), + + KEY(11, 0, KEY_LEFTCTRL), + KEY(11, 1, KEY_F11), + KEY(11, 2, KEY_ENTER), + KEY(11, 3, KEY_SEARCH), + KEY(11, 4, KEY_DELETE), + KEY(11, 5, KEY_RIGHT), + KEY(11, 6, KEY_LEFT), + KEY(11, 7, KEY_RIGHTSHIFT), + KEY(0, 0, KEY_VOLUMEUP), + KEY(0, 1, KEY_VOLUMEDOWN), + KEY(0, 2, KEY_CAMERA_SNAPSHOT), + KEY(0, 3, KEY_CAMERA_FOCUS), +}; + +static struct matrix_keymap_data keymap_data_sim = { + .keymap_size = ARRAY_SIZE(keymap_sim), + .keymap = keymap_sim, +}; + +static struct pm8xxx_keypad_platform_data keypad_data_sim = { + .input_name = "keypad_8960", + .input_phys_device = "keypad_8960/input0", + .num_rows = 12, + .num_cols = 8, + .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9), + .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1), + .debounce_ms = 15, + .scan_delay_ms = 32, + .row_hold_ns = 91500, + .wakeup = 1, + .keymap_data = &keymap_data_sim, +}; + +static int pm8921_therm_mitigation[] = { + 1100, + 700, + 600, + 325, +}; + +#define MAX_VOLTAGE_MV 4200 +static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = { +#ifdef CONFIG_PM8921_SEC_CHARGER + .safety_time = 512, /* max */ + .update_time = 30000, + .cool_temp = 0, + .warm_temp = 0, + .get_cable_type = msm8960_get_cable_type, +#else + .safety_time = 180, + .update_time = 60000, + .cool_temp = 10, + .warm_temp = 40, +#endif /* CONFIG_PM8921_SEC_CHARGER */ + .max_voltage = MAX_VOLTAGE_MV, + .min_voltage = 3200, + .resume_voltage_delta = 100, + .term_current = 100, + .temp_check_period = 1, + .max_bat_chg_current = 1100, + .cool_bat_chg_current = 350, + .warm_bat_chg_current = 350, + .cool_bat_voltage = 4100, + .warm_bat_voltage = 4100, + .thermal_mitigation = pm8921_therm_mitigation, + .thermal_levels = ARRAY_SIZE(pm8921_therm_mitigation), +}; + +static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = { + .priority = 0, +}; + +static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = { + .r_sense_uohm = 10000, + .i_test = 2500, + .v_cutoff = 3000, +// .normal_voltage_calc_ms = 600000, + .max_voltage_uv = MAX_VOLTAGE_MV * 1000, +}; + +#define PM8921_LC_LED_MAX_CURRENT 2 /* I = 4mA */ +#define PM8921_LC_LED_LOW_CURRENT 1 /* I = 1mA */ +#define PM8XXX_LED_PWM_PERIOD 1000 + +#define PM8XXX_LED_PWM_DUTY_MS_PAT1_R 1 +#define PM8XXX_LED_PWM_DUTY_MS_PAT1_G 1 + +#define PM8XXX_LED_PWM_DUTY_MS_PAT2 1 + +#define PM8XXX_LED_PWM_DUTY_MS_PAT3 1 + +#define PM8XXX_LED_PWM_DUTY_MS_PAT4 1 + +#define PM8XXX_LED_PWM_DUTY_MS_PAT5_R 1 +#define PM8XXX_LED_PWM_DUTY_MS_PAT5_G 1 +#define PM8XXX_LED_PWM_DUTY_MS_PAT5_B 1 + +#define PM8XXX_LED_PWM_DUTY_MS_PAT6_G 32 + +#define PM8XXX_LED_PWM_DUTY_MS_PAT6_B 32 + +#define PM8XXX_LED_PWM_DUTY_MS_PAT8 1 + +/** + * PM8XXX_PWM_CHANNEL_NONE shall be used when LED shall not be + * driven using PWM feature. + */ +#define PM8XXX_PWM_CHANNEL_NONE -1 + +static struct led_info pm8921_led_info[] = { + [PM8XXX_LED_PAT1_RED] = { + .name = "led:red_chrg", + .default_trigger = "red-chrg", + }, + [PM8XXX_LED_PAT1_GREEN] = { + .name = "led:green_chrg", + .default_trigger = "green-chrg", + }, + [PM8XXX_LED_PAT2_RED] = { + .name = "led:red_chrg_err", + .default_trigger = "red-chrg-err", + }, + [PM8XXX_LED_PAT2_GREEN] = { + .name = "led:green_chrg_err", + .default_trigger = "green-chrg-err", + }, + [PM8XXX_LED_PAT3_RED] = { + .name = "led:red_miss_noti", + .default_trigger = "red-miss-noti", + }, + [PM8XXX_LED_PAT3_GREEN] = { + .name = "led:green_miss_noti", + .default_trigger = "green-miss-noti", + }, + [PM8XXX_LED_PAT4_RED] = { + .name = "led:red_in_lowbat", + .default_trigger = "red-in-lowbat", + }, + [PM8XXX_LED_PAT4_GREEN] = { + .name = "led:green_in_lowbat", + .default_trigger = "green-in-lowbat", + }, + [PM8XXX_LED_PAT5_RED] = { + .name = "led:red_full_chrg", + .default_trigger = "red-full-chrg", + }, + [PM8XXX_LED_PAT5_GREEN] = { + .name = "led:green_full_chrg", + .default_trigger = "green-full-chrg", + }, + [PM8XXX_LED_PAT5_BLUE] = { + .name = "led:blue_full_chrg", + .default_trigger = "blue-full-chrg", + }, + [PM8XXX_LED_PAT6_GREEN] = { + .name = "led:green_pwr", + .default_trigger = "green-pwr", + }, + [PM8XXX_LED_PAT6_BLUE] = { + .name = "led:blue_pwr", + .default_trigger = "blue-pwr", + }, + [PM8XXX_LED_PAT7_RED] = { + .name = "led:r", + .default_trigger = "r-trig", + }, + [PM8XXX_LED_PAT7_GREEN] = { + .name = "led:g", + .default_trigger = "g-trig", + }, + [PM8XXX_LED_PAT7_BLUE] = { + .name = "led:b", + .default_trigger = "b-trig", + }, + [PM8XXX_LED_PAT8_RED] = { + .name = "led:blink_red", + .default_trigger = "blink-red", + }, + [PM8XXX_LED_PAT8_GREEN] = { + .name = "led:blink_green", + .default_trigger = "blink-green", + }, + [PM8XXX_LED_PAT8_BLUE] = { + .name = "led:blink_blue", + .default_trigger = "blink-blue", + }, + [PM8XXX_LED_KB_LED] = { + .name = "kb:backlight", + .default_trigger = "kb-backlight", + }, +}; + +static struct led_platform_data pm8921_led_core_pdata = { + .num_leds = ARRAY_SIZE(pm8921_led_info), + .leds = pm8921_led_info, +}; + + +int pm8921_led0_pat1_red_pwm_duty_pcts[] = { + 100, 100 +}; +int pm8921_led0_pat1_green_pwm_duty_pcts[] = { + 0, 0 +}; + +int pm8921_led0_pat2_red_pwm_duty_pcts[] = { + 0, 100 +}; +int pm8921_led0_pat2_green_pwm_duty_pcts[] = { + 0, 0 +}; + +int pm8921_led0_pat3_red_pwm_duty_pcts[] = { + 0, 0 +}; + +int pm8921_led0_pat3_green_pwm_duty_pcts[] = { + 0, 0 +}; + +int pm8921_led0_pat3_blue_pwm_duty_pcts[] = { + 0, 100 +}; + +int pm8921_led0_pat4_red_pwm_duty_pcts[] = { + 0, 100 +}; +int pm8921_led0_pat4_green_pwm_duty_pcts[] = { + 0, 0 +}; + +int pm8921_led0_pat5_red_pwm_duty_pcts[] = { + 0, 0 +}; +int pm8921_led0_pat5_green_pwm_duty_pcts[] = { + 100, 100 +}; +int pm8921_led0_pat5_blue_pwm_duty_pcts[] = { + 0, 0 +}; + + +static int pm8921_led0_pat6_green_pwm_duty_pcts[] = { + 8, 10 , 11, 13, 15, 17, 18, 19, 20, 22, 24, 26, 28, 31, 33, 34, 37, 39, + 41, 43, 44, 46, 48, 49, 51, +}; +static int pm8921_led0_pat6_blue_pwm_duty_pcts[] = { + 79, 80, 80, 81, 82, 83, 84, 85, 85, 86, 87, 88, 89, 90, 91, 92, 92, 93, + 94, 95, 96, 97, 98, 99, 100, +}; + +int pm8921_led0_pat8_red_pwm_duty_pcts[] = { + 0, 100 +}; +int pm8921_led0_pat8_green_pwm_duty_pcts[] = { + 0, 100 +}; +int pm8921_led0_pat8_blue_pwm_duty_pcts[] = { + 0, 100 +}; + + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat5_red_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat5_red_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat5_red_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT5_R, + .start_idx = 0, +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat5_green_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat5_green_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat5_green_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT5_G, + .start_idx = ARRAY_SIZE(pm8921_led0_pat5_red_pwm_duty_pcts), +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat5_blue_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat5_blue_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat5_blue_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT5_B, + .start_idx = ARRAY_SIZE(pm8921_led0_pat5_red_pwm_duty_pcts) + + ARRAY_SIZE(pm8921_led0_pat5_green_pwm_duty_pcts), +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat4_red_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat4_red_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat4_red_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT4, + .start_idx = 0, +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat4_green_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat4_green_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat4_green_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT4, + .start_idx = ARRAY_SIZE(pm8921_led0_pat4_red_pwm_duty_pcts), +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat3_red_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat3_red_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat3_red_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT3, + .start_idx = 0, +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat3_green_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat3_green_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat3_green_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT3, + .start_idx = ARRAY_SIZE(pm8921_led0_pat3_red_pwm_duty_pcts), +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat3_blue_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat3_blue_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat3_blue_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT3, + .start_idx = ARRAY_SIZE(pm8921_led0_pat3_red_pwm_duty_pcts) + + ARRAY_SIZE(pm8921_led0_pat3_green_pwm_duty_pcts), +}; + + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat2_red_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat2_red_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat2_red_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT2, + .start_idx = 0, +}; +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat2_green_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat2_green_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat2_green_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT2, + .start_idx = ARRAY_SIZE(pm8921_led0_pat2_red_pwm_duty_pcts), +}; +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat1_red_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat1_red_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat1_red_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT1_R, + .start_idx = 0, +}; +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat1_green_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat1_green_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat1_green_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT1_G, + .start_idx = ARRAY_SIZE(pm8921_led0_pat1_red_pwm_duty_pcts), +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat6_green_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat6_green_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat6_green_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT6_G, + .start_idx = 0, +}; +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat6_blue_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat6_blue_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat6_blue_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT6_B, + .start_idx = ARRAY_SIZE(pm8921_led0_pat6_green_pwm_duty_pcts), +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat8_red_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat8_red_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat8_red_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT8, + .start_idx = 0, +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat8_green_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat8_green_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat8_green_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT8, + .start_idx = ARRAY_SIZE(pm8921_led0_pat8_red_pwm_duty_pcts), +}; + +static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_pat8_blue_duty_cycles = { + .duty_pcts = (int *)&pm8921_led0_pat8_blue_pwm_duty_pcts, + .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pat8_blue_pwm_duty_pcts), + .duty_ms = PM8XXX_LED_PWM_DUTY_MS_PAT8, + .start_idx = ARRAY_SIZE(pm8921_led0_pat8_red_pwm_duty_pcts) + + ARRAY_SIZE(pm8921_led0_pat8_green_pwm_duty_pcts), +}; + + + + +static struct pm8xxx_led_config pm8921_led_configs[] = { + /*pattern 1 Charging*/ + [PM8XXX_LED_PAT1_RED] = { + .id = PM8XXX_ID_LED_0, + .mode = PM8XXX_LED_MODE_PWM2, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 5, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat1_red_duty_cycles, + }, + [PM8XXX_LED_PAT1_GREEN] = { + .id = PM8XXX_ID_LED_1, + .mode = PM8XXX_LED_MODE_PWM1, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 4, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat1_green_duty_cycles + }, + /*pattern 2 Charging Error*/ + + [PM8XXX_LED_PAT2_RED] = { + .id = PM8XXX_ID_LED_0, + .mode = PM8XXX_LED_MODE_PWM2, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 5, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat2_red_duty_cycles + }, + [PM8XXX_LED_PAT2_GREEN] = { + .id = PM8XXX_ID_LED_1, + .mode = PM8XXX_LED_MODE_PWM1, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 4, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat2_green_duty_cycles + }, + /*pattern 3 Missed Noti*/ + + [PM8XXX_LED_PAT3_RED] = { + .id = PM8XXX_ID_LED_0, + .mode = PM8XXX_LED_MODE_PWM2, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 5, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat3_red_duty_cycles + }, + [PM8XXX_LED_PAT3_GREEN] = { + .id = PM8XXX_ID_LED_1, + .mode = PM8XXX_LED_MODE_PWM1, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 4, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat3_green_duty_cycles + }, + [PM8XXX_LED_PAT3_BLUE] = { + .id = PM8XXX_ID_LED_2, + .mode = PM8XXX_LED_MODE_PWM3, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 6, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat3_blue_duty_cycles + }, + /*pattern 4 Low Batt*/ + [PM8XXX_LED_PAT4_RED] = { + .id = PM8XXX_ID_LED_0, + .mode = PM8XXX_LED_MODE_PWM2, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 5, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat4_red_duty_cycles + }, + [PM8XXX_LED_PAT4_GREEN] = { + .id = PM8XXX_ID_LED_1, + .mode = PM8XXX_LED_MODE_PWM1, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 4, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat4_green_duty_cycles + }, + /*pattern 5 Fully Charged*/ + + [PM8XXX_LED_PAT5_RED] = { + .id = PM8XXX_ID_LED_0, + .mode = PM8XXX_LED_MODE_PWM2, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 5, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat5_red_duty_cycles + }, + [PM8XXX_LED_PAT5_GREEN] = { + .id = PM8XXX_ID_LED_1, + .mode = PM8XXX_LED_MODE_PWM1, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 4, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat5_green_duty_cycles + }, + [PM8XXX_LED_PAT5_BLUE] = { + .id = PM8XXX_ID_LED_2, + .mode = PM8XXX_LED_MODE_PWM3, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 6, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat5_blue_duty_cycles + }, + + /*pattern 6 Powering */ + [PM8XXX_LED_PAT6_GREEN] = { + .id = PM8XXX_ID_LED_1, + .mode = PM8XXX_LED_MODE_PWM1, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 4, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat6_green_duty_cycles + }, + [PM8XXX_LED_PAT6_BLUE] = { + .id = PM8XXX_ID_LED_2, + .mode = PM8XXX_LED_MODE_PWM3, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 6, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat6_blue_duty_cycles + }, + /*pattern 7*/ + [PM8XXX_LED_PAT7_RED] = { + .id = PM8XXX_ID_LED_0, + .mode = PM8XXX_LED_MODE_PWM2, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 5, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + }, + [PM8XXX_LED_PAT7_GREEN] = { + .id = PM8XXX_ID_LED_1, + .mode = PM8XXX_LED_MODE_PWM1, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 4, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + }, + [PM8XXX_LED_PAT7_BLUE] = { + .id = PM8XXX_ID_LED_2, + .mode = PM8XXX_LED_MODE_PWM3, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 6, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + }, + + /*pattern 8*/ + [PM8XXX_LED_PAT8_RED] = { + .id = PM8XXX_ID_LED_0, + .mode = PM8XXX_LED_MODE_PWM2, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 5, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat8_red_duty_cycles, + }, + [PM8XXX_LED_PAT8_GREEN] = { + .id = PM8XXX_ID_LED_1, + .mode = PM8XXX_LED_MODE_PWM1, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 4, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat8_green_duty_cycles, + }, + [PM8XXX_LED_PAT8_BLUE] = { + .id = PM8XXX_ID_LED_2, + .mode = PM8XXX_LED_MODE_PWM3, + .max_current = PM8921_LC_LED_MAX_CURRENT, + .pwm_channel = 6, + .pwm_period_us = PM8XXX_LED_PWM_PERIOD, + .pwm_duty_cycles = &pm8921_led0_pwm_pat8_blue_duty_cycles, + }, + + [PM8XXX_LED_KB_LED] = { + .id = PM8XXX_ID_LED_KB_LIGHT, + .mode = PM8XXX_LED_MODE_MANUAL, + .max_current = 30, + .pwm_channel = 7, + }, + +}; + +static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = { + .led_core = &pm8921_led_core_pdata, + .configs = pm8921_led_configs, + .num_configs = ARRAY_SIZE(pm8921_led_configs), + .led_power_on = NULL, +}; + +static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = { + .r_sense_uohm = 10000, +}; + +static struct pm8921_platform_data pm8921_platform_data __devinitdata = { + .irq_pdata = &pm8xxx_irq_pdata, + .gpio_pdata = &pm8xxx_gpio_pdata, + .mpp_pdata = &pm8xxx_mpp_pdata, + .rtc_pdata = &pm8xxx_rtc_pdata, + .pwrkey_pdata = &pm8xxx_pwrkey_pdata, + .keypad_pdata = &keypad_data, + .misc_pdata = &pm8xxx_misc_pdata, + .regulator_pdatas = msm_pm8921_regulator_pdata, + .charger_pdata = &pm8921_chg_pdata, + .bms_pdata = &pm8921_bms_pdata, + .adc_pdata = &pm8xxx_adc_pdata, + .leds_pdata = &pm8xxx_leds_pdata, + .ccadc_pdata = &pm8xxx_ccadc_pdata, +}; + +static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = { + .controller_type = MSM_SBI_CTRL_PMIC_ARBITER, + .slave = { + .name = "pm8921-core", + .platform_data = &pm8921_platform_data, + }, +}; + +static void msm8921_sec_charger_init(void) +{ + /* batt_id */ + if (machine_is_M2_ATT() && system_rev >= 0x02) { + pm8921_chg_pdata.batt_id_min = 860000; + pm8921_chg_pdata.batt_id_max = 960000; + } else if (machine_is_M2_SKT() && system_rev >= 0x02) { + pm8921_chg_pdata.batt_id_min = 860000; + pm8921_chg_pdata.batt_id_max = 960000; + } else if (machine_is_M2_SPR() && system_rev >= 0x01) { + pm8921_chg_pdata.batt_id_min = 860000; + pm8921_chg_pdata.batt_id_max = 960000; + } else if (machine_is_M2_VZW() && system_rev >= 0x04) { + pm8921_chg_pdata.batt_id_min = 810000; + pm8921_chg_pdata.batt_id_max = 960000; + } else if (machine_is_M2_DCM() && system_rev >= 0x00) { + pm8921_chg_pdata.batt_id_min = 860000; + pm8921_chg_pdata.batt_id_max = 960000; + } else if (machine_is_jaguar() && system_rev >= 0x04) { + pm8921_chg_pdata.batt_id_min = 860000; + pm8921_chg_pdata.batt_id_max = 960000; + } else { + /* + * PMIC ES1 has problem for adc reading + * So batt_id min and max should be '0', + * Then charger driver will skip batt_id checking + */ + pm8921_chg_pdata.batt_id_min = 0; + pm8921_chg_pdata.batt_id_max = 0; + } + + /* battery voltage */ + if ((machine_is_M2_ATT() && system_rev >= 0x02) || + (machine_is_M2_SPR() && system_rev >= 0x02) || + (machine_is_M2_VZW() && system_rev >= 0x06) || + (machine_is_jaguar() && system_rev >= 0x0A) || + (machine_is_M2_DCM() && system_rev >= 0x00) || + machine_is_JASPER()) + pm8921_chg_pdata.max_voltage = 4350; +} + +void __init msm8960_init_pmic(void) +{ + msm8921_sec_charger_init(); + +#if !defined(CONFIG_MACH_AEGIS2) && !defined(CONFIG_MACH_JASPER)\ + && !defined(CONFIG_MACH_M2_VZW) + pmic_reset_irq = PM8921_IRQ_BASE + PM8921_RESOUT_IRQ; +#endif + msm8960_device_ssbi_pmic.dev.platform_data = + &msm8960_ssbi_pm8921_pdata; + pm8921_platform_data.num_regulators = msm_pm8921_regulator_pdata_len; + + /* Simulator supports a QWERTY keypad */ + if (machine_is_msm8960_sim()) + pm8921_platform_data.keypad_pdata = &keypad_data_sim; + + if (machine_is_msm8960_liquid()) + pm8921_platform_data.keypad_pdata = &keypad_data_liquid; +} diff --git a/arch/arm/mach-msm/board-m2-regulator.c b/arch/arm/mach-msm/board-m2-regulator.c new file mode 100644 index 00000000000..1aa07cf81a6 --- /dev/null +++ b/arch/arm/mach-msm/board-m2-regulator.c @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include + +#include "board-8960.h" + +#ifdef CONFIG_MFD_MAX77693 +#include +#endif + +#define VREG_CONSUMERS(_id) \ + static struct regulator_consumer_supply vreg_consumers_##_id[] + +/* + * Consumer specific regulator names: + * regulator name consumer dev_name + */ +VREG_CONSUMERS(L1) = { + REGULATOR_SUPPLY("8921_l1", NULL), +}; +VREG_CONSUMERS(L2) = { + REGULATOR_SUPPLY("8921_l2", NULL), + REGULATOR_SUPPLY("dsi_vdda", "mipi_dsi.1"), + REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.0"), + REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.1"), + REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.2"), + REGULATOR_SUPPLY("mipi_csi_vdd", "4-003d"), + REGULATOR_SUPPLY("mipi_csi_vdd", "4-002d"), + REGULATOR_SUPPLY("mipi_csi_vdd", "4-0045"), +}; +VREG_CONSUMERS(L3) = { + REGULATOR_SUPPLY("8921_l3", NULL), + REGULATOR_SUPPLY("HSUSB_3p3", "msm_otg"), +}; +VREG_CONSUMERS(L4) = { + REGULATOR_SUPPLY("8921_l4", NULL), + REGULATOR_SUPPLY("HSUSB_1p8", "msm_otg"), +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) + REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.4"), +#endif +#ifdef CONFIG_WCNSS_CORE + REGULATOR_SUPPLY("iris_vddxo", "wcnss_wlan.0"), +#endif +}; +VREG_CONSUMERS(L5) = { + REGULATOR_SUPPLY("8921_l5", NULL), + REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.1"), +}; +VREG_CONSUMERS(L6) = { + REGULATOR_SUPPLY("8921_l6", NULL), + REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.3"), +}; +VREG_CONSUMERS(L7) = { + REGULATOR_SUPPLY("8921_l7", NULL), + REGULATOR_SUPPLY("sdc_vddp", "msm_sdcc.3"), +}; +VREG_CONSUMERS(L8) = { + REGULATOR_SUPPLY("8921_l8", NULL), + REGULATOR_SUPPLY("dsi_vdc", "mipi_dsi.1"), +}; +VREG_CONSUMERS(L9) = { + REGULATOR_SUPPLY("8921_l9", NULL), + REGULATOR_SUPPLY("vdd", "3-0024"), + REGULATOR_SUPPLY("vdd_ana", "3-004a"), +}; +VREG_CONSUMERS(L10) = { + REGULATOR_SUPPLY("8921_l10", NULL), +#ifdef CONFIG_WCNSS_CORE + REGULATOR_SUPPLY("iris_vddpa", "wcnss_wlan.0"), +#endif +}; +VREG_CONSUMERS(L11) = { + REGULATOR_SUPPLY("8921_l11", NULL), + REGULATOR_SUPPLY("cam_vana", "4-001a"), + REGULATOR_SUPPLY("cam_vana", "4-006c"), + REGULATOR_SUPPLY("cam_vana", "4-0048"), + REGULATOR_SUPPLY("cam_vana", "4-003d"), + REGULATOR_SUPPLY("cam_vana", "4-002d"), + REGULATOR_SUPPLY("cam_vana", "4-0045"), + REGULATOR_SUPPLY("cam_vana", "4-0020"), +}; +VREG_CONSUMERS(L12) = { + REGULATOR_SUPPLY("8921_l12", NULL), + REGULATOR_SUPPLY("cam_vdig", "4-001a"), + REGULATOR_SUPPLY("cam_vdig", "4-006c"), + REGULATOR_SUPPLY("cam_vdig", "4-0048"), + REGULATOR_SUPPLY("cam_vdig", "4-003d"), + REGULATOR_SUPPLY("cam_vdig", "4-002d"), + REGULATOR_SUPPLY("cam_vdig", "4-0045"), + REGULATOR_SUPPLY("cam_vdig", "4-0020"), +}; +VREG_CONSUMERS(L14) = { + REGULATOR_SUPPLY("8921_l14", NULL), + REGULATOR_SUPPLY("pa_therm", "pm8xxx-adc"), +}; +VREG_CONSUMERS(L15) = { + REGULATOR_SUPPLY("8921_l15", NULL), +}; +VREG_CONSUMERS(L16) = { + REGULATOR_SUPPLY("8921_l16", NULL), + REGULATOR_SUPPLY("cam_vaf", "4-001a"), + REGULATOR_SUPPLY("cam_vaf", "4-006c"), + REGULATOR_SUPPLY("cam_vaf", "4-0048"), + REGULATOR_SUPPLY("cam_vaf", "4-003d"), + REGULATOR_SUPPLY("cam_vaf", "4-002d"), + REGULATOR_SUPPLY("cam_vaf", "4-0045"), +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + REGULATOR_SUPPLY("lvds_3p3", "mipi_dsi.1"), +#endif + REGULATOR_SUPPLY("cam_vaf", "4-0020"), +}; +VREG_CONSUMERS(L17) = { + REGULATOR_SUPPLY("8921_l17", NULL), +}; +VREG_CONSUMERS(L18) = { + REGULATOR_SUPPLY("8921_l18", NULL), + REGULATOR_SUPPLY("camDVDD", "4-0045"), +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + REGULATOR_SUPPLY("lvds_1p2", "mipi_dsi.1"), +#endif /* CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL */ +}; +VREG_CONSUMERS(L21) = { + REGULATOR_SUPPLY("8921_l21", NULL), +}; +VREG_CONSUMERS(L22) = { + REGULATOR_SUPPLY("8921_l22", NULL), +}; +VREG_CONSUMERS(L23) = { + REGULATOR_SUPPLY("8921_l23", NULL), + REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"), + REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"), + REGULATOR_SUPPLY("hdmi_pll_fs", "mdp.0"), + REGULATOR_SUPPLY("pll_vdd", "pil_riva"), + REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"), + REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"), +}; +VREG_CONSUMERS(L24) = { + REGULATOR_SUPPLY("8921_l24", NULL), +#ifdef CONFIG_WCNSS_CORE + REGULATOR_SUPPLY("riva_vddmx", "wcnss_wlan.0"), +#endif +}; +VREG_CONSUMERS(L25) = { + REGULATOR_SUPPLY("8921_l25", NULL), + REGULATOR_SUPPLY("VDDD_CDC_D", "tabla-slim"), + REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "tabla-slim"), + REGULATOR_SUPPLY("VDDD_CDC_D", "tabla2x-slim"), + REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "tabla2x-slim"), + REGULATOR_SUPPLY("VDDD_CDC_D", "1-000d"), + REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "1-000d"), +}; +VREG_CONSUMERS(L26) = { + REGULATOR_SUPPLY("8921_l26", NULL), + REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"), +}; +VREG_CONSUMERS(L27) = { + REGULATOR_SUPPLY("8921_l27", NULL), + REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"), +}; +VREG_CONSUMERS(L28) = { + REGULATOR_SUPPLY("8921_l28", NULL), + REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"), +}; +VREG_CONSUMERS(L29) = { + REGULATOR_SUPPLY("8921_l29", NULL), + REGULATOR_SUPPLY("cam_vio", NULL), +}; +VREG_CONSUMERS(S1) = { + REGULATOR_SUPPLY("8921_s1", NULL), +}; +VREG_CONSUMERS(S2) = { + REGULATOR_SUPPLY("8921_s2", NULL), +#ifdef CONFIG_WCNSS_CORE + REGULATOR_SUPPLY("iris_vddrfa", "wcnss_wlan.0"), +#endif +}; +VREG_CONSUMERS(S3) = { + REGULATOR_SUPPLY("8921_s3", NULL), + REGULATOR_SUPPLY("HSUSB_VDDCX", "msm_otg"), +#ifdef CONFIG_WCNSS_CORE + REGULATOR_SUPPLY("riva_vddcx", "wcnss_wlan.0"), +#endif + REGULATOR_SUPPLY("HSIC_VDDCX", "msm_hsic_host"), +}; +VREG_CONSUMERS(S4) = { + REGULATOR_SUPPLY("8921_s4", NULL), + REGULATOR_SUPPLY("sdc_vccq", "msm_sdcc.1"), +#ifdef CONFIG_WCNSS_CORE + REGULATOR_SUPPLY("riva_vddpx", "wcnss_wlan.0"), +#endif + REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"), + REGULATOR_SUPPLY("VDDIO_CDC", "tabla-slim"), + REGULATOR_SUPPLY("CDC_VDD_CP", "tabla-slim"), + REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla-slim"), + REGULATOR_SUPPLY("CDC_VDDA_RX", "tabla-slim"), + REGULATOR_SUPPLY("VDDIO_CDC", "tabla2x-slim"), + REGULATOR_SUPPLY("CDC_VDD_CP", "tabla2x-slim"), + REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla2x-slim"), + REGULATOR_SUPPLY("CDC_VDDA_RX", "tabla2x-slim"), + REGULATOR_SUPPLY("VDDIO_CDC", "1-000d"), + REGULATOR_SUPPLY("CDC_VDD_CP", "1-000d"), + REGULATOR_SUPPLY("CDC_VDDA_TX", "1-000d"), + REGULATOR_SUPPLY("CDC_VDDA_RX", "1-000d"), + REGULATOR_SUPPLY("vcc_i2c", "3-005b"), + REGULATOR_SUPPLY("EXT_HUB_VDDIO", "msm_hsic_host"), + REGULATOR_SUPPLY("vcc_i2c", "10-0048"), +}; +VREG_CONSUMERS(S5) = { + REGULATOR_SUPPLY("8921_s5", NULL), + REGULATOR_SUPPLY("krait0", "acpuclk-8960"), +}; +VREG_CONSUMERS(S6) = { + REGULATOR_SUPPLY("8921_s6", NULL), + REGULATOR_SUPPLY("krait1", "acpuclk-8960"), +}; +VREG_CONSUMERS(S7) = { + REGULATOR_SUPPLY("8921_s7", NULL), +}; +VREG_CONSUMERS(S8) = { + REGULATOR_SUPPLY("8921_s8", NULL), +}; +VREG_CONSUMERS(LVS1) = { + REGULATOR_SUPPLY("8921_lvs1", NULL), + /* Changed to L4 */ + /*REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.4"), */ +#ifdef CONFIG_WCNSS_CORE + REGULATOR_SUPPLY("iris_vddio", "wcnss_wlan.0"), +#endif +}; +VREG_CONSUMERS(LVS2) = { + REGULATOR_SUPPLY("8921_lvs2", NULL), +#ifdef CONFIG_WCNSS_CORE + REGULATOR_SUPPLY("iris_vdddig", "wcnss_wlan.0"), +#endif +}; +VREG_CONSUMERS(LVS3) = { + REGULATOR_SUPPLY("8921_lvs3", NULL), +}; +VREG_CONSUMERS(LVS4) = { + REGULATOR_SUPPLY("8921_lvs4", NULL), + REGULATOR_SUPPLY("vcc_i2c", "3-0024"), + REGULATOR_SUPPLY("vcc_i2c", "3-004a"), +}; +VREG_CONSUMERS(LVS5) = { + REGULATOR_SUPPLY("8921_lvs5", NULL), + REGULATOR_SUPPLY("cam_vio", "4-001a"), + REGULATOR_SUPPLY("cam_vio", "4-006c"), + REGULATOR_SUPPLY("cam_vio", "4-0048"), + REGULATOR_SUPPLY("cam_vio", "4-003d"), + REGULATOR_SUPPLY("cam_vio", "4-002d"), + REGULATOR_SUPPLY("cam_vio", "4-0045"), + REGULATOR_SUPPLY("cam_vio", "4-0020"), +}; +VREG_CONSUMERS(LVS6) = { + REGULATOR_SUPPLY("8921_lvs6", NULL), + REGULATOR_SUPPLY("vdd_io", "spi0.0"), +}; +VREG_CONSUMERS(LVS7) = { + REGULATOR_SUPPLY("8921_lvs7", NULL), +}; +VREG_CONSUMERS(USB_OTG) = { + REGULATOR_SUPPLY("8921_usb_otg", NULL), +}; +VREG_CONSUMERS(HDMI_MVS) = { + REGULATOR_SUPPLY("8921_hdmi_mvs", NULL), + REGULATOR_SUPPLY("hdmi_mvs", "hdmi_msm.0"), +}; +VREG_CONSUMERS(NCP) = { + REGULATOR_SUPPLY("8921_ncp", NULL), +}; +VREG_CONSUMERS(EXT_5V) = { + REGULATOR_SUPPLY("ext_5v", NULL), +}; +VREG_CONSUMERS(EXT_L2) = { + REGULATOR_SUPPLY("ext_l2", NULL), + REGULATOR_SUPPLY("vdd_phy", "spi0.0"), +}; +VREG_CONSUMERS(EXT_3P3V) = { + REGULATOR_SUPPLY("ext_3p3v", NULL), + REGULATOR_SUPPLY("vdd_ana", "3-005b"), + REGULATOR_SUPPLY("vdd_lvds_3p3v", "mipi_dsi.1"), + REGULATOR_SUPPLY("mhl_ext_3p3v", "msm_otg"), +}; +VREG_CONSUMERS(EXT_OTG_SW) = { + REGULATOR_SUPPLY("ext_otg_sw", NULL), + REGULATOR_SUPPLY("vbus_otg", "msm_otg"), +}; + +#ifdef CONFIG_MFD_MAX77693 +static struct regulator_consumer_supply safeout1_supply[] = { + REGULATOR_SUPPLY("safeout1", NULL), +}; + +static struct regulator_consumer_supply safeout2_supply[] = { + REGULATOR_SUPPLY("safeout2", NULL), +}; + +static struct regulator_consumer_supply charger_supply[] = { + REGULATOR_SUPPLY("vinchg1", "charger-manager.0"), + REGULATOR_SUPPLY("vinchg1", NULL), +}; + +static struct regulator_init_data safeout1_init_data = { + .constraints = { + .name = "safeout1 range", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .always_on = 0, + .boot_on = 1, + .state_mem = { + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(safeout1_supply), + .consumer_supplies = safeout1_supply, +}; + +static struct regulator_init_data safeout2_init_data = { + .constraints = { + .name = "safeout2 range", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .always_on = 0, + .boot_on = 0, + .state_mem = { + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(safeout2_supply), + .consumer_supplies = safeout2_supply, +}; + +static struct regulator_init_data charger_init_data = { + .constraints = { + .name = "CHARGER", + .valid_ops_mask = REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_CURRENT, + .boot_on = 1, + .min_uA = 60000, + .max_uA = 2580000, + }, + .num_consumer_supplies = ARRAY_SIZE(charger_supply), + .consumer_supplies = charger_supply, +}; + +struct max77693_regulator_data max77693_regulators[] = { + {MAX77693_ESAFEOUT1, &safeout1_init_data,}, + {MAX77693_ESAFEOUT2, &safeout2_init_data,}, + {MAX77693_CHARGER, &charger_init_data,}, +}; +#endif /* CONFIG_MFD_MAX77693 */ + + + +#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \ + _apply_uV, _pull_down, _always_on, _supply_regulator, \ + _system_uA, _enable_time, _reg_id) \ + { \ + .init_data = { \ + .constraints = { \ + .valid_modes_mask = _modes, \ + .valid_ops_mask = _ops, \ + .min_uV = _min_uV, \ + .max_uV = _max_uV, \ + .input_uV = _max_uV, \ + .apply_uV = _apply_uV, \ + .always_on = _always_on, \ + .name = _name, \ + }, \ + .num_consumer_supplies = \ + ARRAY_SIZE(vreg_consumers_##_id), \ + .consumer_supplies = vreg_consumers_##_id, \ + .supply_regulator = _supply_regulator, \ + }, \ + .id = _reg_id, \ + .pull_down_enable = _pull_down, \ + .system_uA = _system_uA, \ + .enable_time = _enable_time, \ + } + +#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \ + _enable_time, _supply_regulator, _system_uA, _reg_id) \ + PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \ + | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \ + REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \ + _supply_regulator, _system_uA, _enable_time, _reg_id) + +#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \ + _max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \ + PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \ + | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \ + REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \ + _supply_regulator, _system_uA, _enable_time, _reg_id) + +#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \ + _enable_time, _supply_regulator, _system_uA, _reg_id) \ + PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \ + | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \ + REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \ + _supply_regulator, _system_uA, _enable_time, _reg_id) + +#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \ + _enable_time, _supply_regulator, _system_uA, _reg_id) \ + PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \ + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \ + | REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \ + _supply_regulator, _system_uA, _enable_time, _reg_id) + +#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \ + _supply_regulator, _reg_id) \ + PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \ + _pull_down, _always_on, _supply_regulator, 0, _enable_time, \ + _reg_id) + +#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \ + _supply_regulator, _reg_id) \ + PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \ + _pull_down, _always_on, _supply_regulator, 0, _enable_time, \ + _reg_id) + +#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \ + _supply_regulator, _reg_id) \ + PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \ + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \ + _always_on, _supply_regulator, 0, _enable_time, _reg_id) + +/* Pin control initialization */ +#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \ + _supply_regulator, _reg_id) \ + { \ + .init_data = { \ + .constraints = { \ + .valid_ops_mask = REGULATOR_CHANGE_STATUS, \ + .always_on = _always_on, \ + .name = _name, \ + }, \ + .num_consumer_supplies = \ + ARRAY_SIZE(vreg_consumers_##_id##_PC), \ + .consumer_supplies = vreg_consumers_##_id##_PC, \ + .supply_regulator = _supply_regulator, \ + }, \ + .id = _reg_id, \ + .pin_fn = PM8XXX_VREG_PIN_FN_##_pin_fn, \ + .pin_ctrl = _pin_ctrl, \ + } + +#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \ + [GPIO_VREG_ID_##_id] = { \ + .init_data = { \ + .constraints = { \ + .valid_ops_mask = REGULATOR_CHANGE_STATUS, \ + }, \ + .num_consumer_supplies = \ + ARRAY_SIZE(vreg_consumers_##_id), \ + .consumer_supplies = vreg_consumers_##_id, \ + .supply_regulator = _supply_regulator, \ + }, \ + .regulator_name = _reg_name, \ + .gpio_label = _gpio_label, \ + .gpio = _gpio, \ + } + +#define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \ + { \ + .constraints = { \ + .name = _name, \ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, \ + REGULATOR_CHANGE_STATUS, \ + .min_uV = _min_uV, \ + .max_uV = _max_uV, \ + }, \ + .num_consumer_supplies = ARRAY_SIZE(vreg_consumers_##_id), \ + .consumer_supplies = vreg_consumers_##_id, \ + } + +#define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \ + _peak_uA, _avg_uA, _pull_down, _pin_ctrl, _freq, _pin_fn, \ + _force_mode, _power_mode, _state, _sleep_selectable, \ + _always_on, _supply_regulator, _system_uA) \ + { \ + .init_data = { \ + .constraints = { \ + .valid_modes_mask = _modes, \ + .valid_ops_mask = _ops, \ + .min_uV = _min_uV, \ + .max_uV = _max_uV, \ + .input_uV = _min_uV, \ + .apply_uV = _apply_uV, \ + .always_on = _always_on, \ + }, \ + .num_consumer_supplies = \ + ARRAY_SIZE(vreg_consumers_##_id), \ + .consumer_supplies = vreg_consumers_##_id, \ + .supply_regulator = _supply_regulator, \ + }, \ + .id = RPM_VREG_ID_PM8921_##_id, \ + .default_uV = _default_uV, \ + .peak_uA = _peak_uA, \ + .avg_uA = _avg_uA, \ + .pull_down_enable = _pull_down, \ + .pin_ctrl = _pin_ctrl, \ + .freq = RPM_VREG_FREQ_##_freq, \ + .pin_fn = _pin_fn, \ + .force_mode = _force_mode, \ + .power_mode = _power_mode, \ + .state = _state, \ + .sleep_selectable = _sleep_selectable, \ + .system_uA = _system_uA, \ + } + +#define RPM_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \ + _supply_regulator, _system_uA, _init_peak_uA) \ + RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \ + | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \ + | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \ + | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \ + RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \ + RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \ + RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \ + _supply_regulator, _system_uA) + +#define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \ + _supply_regulator, _system_uA, _freq) \ + RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \ + | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \ + | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \ + | REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \ + RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \ + RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \ + RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \ + _supply_regulator, _system_uA) + +#define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \ + RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \ + RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \ + RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \ + RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \ + _supply_regulator, 0) + +#define RPM_NCP(_id, _always_on, _sleep_selectable, _min_uV, _max_uV, \ + _supply_regulator, _freq) \ + RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \ + | REGULATOR_CHANGE_STATUS, 0, _max_uV, 1000, 1000, 0, \ + RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \ + RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \ + RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \ + _supply_regulator, 0) + +/* Pin control initialization */ +#define RPM_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \ + { \ + .init_data = { \ + .constraints = { \ + .valid_ops_mask = REGULATOR_CHANGE_STATUS, \ + .always_on = _always_on, \ + }, \ + .num_consumer_supplies = \ + ARRAY_SIZE(vreg_consumers_##_id##_PC), \ + .consumer_supplies = vreg_consumers_##_id##_PC, \ + .supply_regulator = _supply_regulator, \ + }, \ + .id = RPM_VREG_ID_PM8921_##_id##_PC, \ + .pin_fn = RPM_VREG_PIN_FN_8960_##_pin_fn, \ + .pin_ctrl = _pin_ctrl, \ + } + +/* GPIO regulator constraints */ +struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] __devinitdata = { + /* ID vreg_name gpio_label gpio supply */ + GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", PM8921_MPP_PM_TO_SYS(7), NULL), + GPIO_VREG(EXT_L2, "ext_l2", "ext_l2_en", 91, NULL), + GPIO_VREG(EXT_3P3V, "ext_3p3v", "ext_3p3v_en", + PM8921_GPIO_PM_TO_SYS(17), NULL), + GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", + PM8921_GPIO_PM_TO_SYS(42), "8921_usb_otg"), +}; + +/* SAW regulator constraints */ +struct regulator_init_data msm_saw_regulator_pdata_s5 = + /* ID vreg_name min_uV max_uV */ + SAW_VREG_INIT(S5, "8921_s5", 850000, 1300000); +struct regulator_init_data msm_saw_regulator_pdata_s6 = + SAW_VREG_INIT(S6, "8921_s6", 850000, 1300000); + +/* PM8921 regulator constraints */ +struct pm8xxx_regulator_platform_data +msm_pm8921_regulator_pdata[] __devinitdata = { + /* + * ID name always_on pd min_uV max_uV en_t supply + * system_uA reg_ID + */ + PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7", + 0, 1), + PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1050000, 1050000, 200, "8921_s7", + 0, 2), + PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 1050000, 1050000, 200, "8921_s7", + 0, 3), +#if defined(CONFIG_MACH_ESPRESSO_ATT) || defined(CONFIG_MACH_ESPRESSO_VZW) \ + || defined(CONFIG_MACH_JAGUAR) || defined(CONFIG_MACH_ESPRESSO10_VZW) \ + || defined(CONFIG_MACH_ESPRESSO_SPR) \ + || defined(CONFIG_MACH_ESPRESSO10_SPR) \ + || defined(CONFIG_MACH_ESPRESSO10_ATT) + PM8XXX_LDO(L29, "8921_l29", 0, 1, 1800000, 2050000, 200, "8921_s8", + 0, 4), +#else + PM8XXX_LDO(L29, "8921_l29", 0, 1, 1800000, 1800000, 200, "8921_s8", + 0, 4), +#endif + /* ID name always_on pd en_t supply reg_ID */ + PM8XXX_VS300(USB_OTG, "8921_usb_otg", 0, 1, 0, "ext_5v", 5), + PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0, "ext_5v", 6), +}; + +static struct rpm_regulator_init_data +msm_rpm_regulator_init_data[] __devinitdata = { + /* ID a_on pd ss min_uV max_uV supply sys_uA freq */ + RPM_SMPS(S1, 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20), +#if defined(CONFIG_MACH_M2_ATT) + RPM_SMPS(S2, 0, 1, 1, 1350000, 1350000, NULL, 0, 1p60), + RPM_LDO(L22, 0, 1, 0, 2800000, 2800000, NULL, 0, 0), +#elif defined(CONFIG_MACH_APEXQ) + RPM_SMPS(S2, 0, 1, 1, 1300000, 1300000, NULL, 0, 1p60), + RPM_LDO(L22, 0, 1, 0, 2750000, 2750000, NULL, 0, 0), +#else + RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL, 0, 1p60), + RPM_LDO(L22, 0, 1, 0, 2750000, 2750000, NULL, 0, 0), +#endif + RPM_SMPS(S3, 0, 1, 1, 500000, 1150000, NULL, 100000, 4p80), + RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60), + RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20), + RPM_SMPS(S8, 1, 1, 1, 2050000, 2100000, NULL, 100000, 1p60), + /* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */ + RPM_LDO(L1, 1, 1, 0, 1050000, 1050000, "8921_s4", 0, 10000), +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + RPM_LDO(L2, 0, 1, 1, 1200000, 1200000, "8921_s4", 0, 0), +#else + RPM_LDO(L2, 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0), +#endif + RPM_LDO(L3, 0, 1, 0, 3075000, 3075000, NULL, 0, 0), + RPM_LDO(L4, 1, 1, 0, 1800000, 1800000, NULL, 10000, 10000), + RPM_LDO(L5, 0, 1, 0, 2950000, 2950000, NULL, 0, 0), + RPM_LDO(L6, 0, 1, 0, 2950000, 2950000, NULL, 0, 0), + RPM_LDO(L7, 1, 1, 0, 1850000, 2950000, NULL, 10000, 10000), + RPM_LDO(L8, 0, 1, 0, 3000000, 3100000, NULL, 0, 0), + RPM_LDO(L9, 0, 1, 0, 2850000, 2850000, NULL, 0, 0), +#ifdef CONFIG_MACH_JAGUAR + RPM_LDO(L10, 0, 1, 0, 2900000, 2900000, NULL, 0, 0), +#else + RPM_LDO(L10, 0, 1, 0, 3000000, 3000000, NULL, 0, 0), +#endif + RPM_LDO(L11, 0, 1, 0, 2800000, 3300000, NULL, 0, 0), + RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0), + RPM_LDO(L14, 0, 1, 0, 1800000, 1800000, NULL, 0, 0), + RPM_LDO(L15, 0, 1, 0, 1800000, 2950000, NULL, 0, 0), +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + RPM_LDO(L16, 0, 1, 1, 3300000, 3300000, NULL, 0, 0), +#else + RPM_LDO(L16, 0, 1, 0, 2800000, 3000000, NULL, 0, 0), +#endif /* CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL */ + RPM_LDO(L17, 0, 1, 0, 1800000, 3300000, NULL, 0, 0), +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + RPM_LDO(L18, 0, 1, 1, 1200000, 1500000, "8921_s4", 0, 0), +#else + RPM_LDO(L18, 0, 1, 0, 1200000, 1500000, "8921_s4", 0, 0), +#endif + RPM_LDO(L21, 0, 1, 0, 1900000, 1900000, "8921_s8", 0, 0), + + RPM_LDO(L23, 1, 1, 1, 1800000, 1800000, "8921_s8", 10000, 10000), + RPM_LDO(L24, 0, 1, 1, 750000, 1150000, "8921_s1", 10000, 10000), + RPM_LDO(L25, 1, 1, 0, 1225000, 1225000, "8921_s1", 10000, 10000), + + /* ID a_on pd ss supply */ + RPM_VS(LVS1, 0, 1, 0, "8921_s4"), + RPM_VS(LVS2, 0, 1, 0, "8921_s1"), + RPM_VS(LVS3, 0, 1, 0, "8921_s4"), + RPM_VS(LVS4, 0, 1, 0, "8921_s4"), +#if defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT_PANEL) + RPM_VS(LVS5, 0, 1, 1, NULL), + RPM_VS(LVS6, 0, 1, 1, NULL), +#else + RPM_VS(LVS5, 0, 1, 0, "8921_s4"), + RPM_VS(LVS6, 0, 1, 0, "8921_s4"), +#endif + RPM_VS(LVS7, 0, 1, 0, "8921_s4"), + + /* ID a_on ss min_uV max_uV supply freq */ + RPM_NCP(NCP, 0, 0, 1800000, 1800000, "8921_l6", 1p60), +}; + +int msm_pm8921_regulator_pdata_len __devinitdata = + ARRAY_SIZE(msm_pm8921_regulator_pdata); + +#define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \ + { \ + .vreg_id = RPM_VREG_ID_PM8921_##_id, \ + .sleep_also = _sleep_also, \ + .voter = _voter, \ + .supply = _supply, \ + .dev_name = _dev_name, \ + } +static struct rpm_regulator_consumer_mapping + msm_rpm_regulator_consumer_mapping[] __devinitdata = { + RPM_REG_MAP(L23, 0, 1, "krait0_l23", "acpuclk-8960"), + RPM_REG_MAP(L23, 0, 2, "krait1_l23", "acpuclk-8960"), + RPM_REG_MAP(L23, 0, 6, "l2_l23", "acpuclk-8960"), + RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8960"), + RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8960"), + RPM_REG_MAP(S3, 0, 1, "krait0_dig", "acpuclk-8960"), + RPM_REG_MAP(S3, 0, 2, "krait1_dig", "acpuclk-8960"), + RPM_REG_MAP(S8, 0, 1, "krait0_s8", "acpuclk-8960"), + RPM_REG_MAP(S8, 0, 2, "krait1_s8", "acpuclk-8960"), + RPM_REG_MAP(S8, 0, 6, "l2_s8", "acpuclk-8960"), + + RPM_REG_MAP(L23, 0, 1, "krait0_l23", "acpuclk-8960ab"), + RPM_REG_MAP(L23, 0, 2, "krait1_l23", "acpuclk-8960ab"), + RPM_REG_MAP(L23, 0, 6, "l2_l23", "acpuclk-8960ab"), + RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8960ab"), + RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8960ab"), + RPM_REG_MAP(S3, 0, 1, "krait0_dig", "acpuclk-8960ab"), + RPM_REG_MAP(S3, 0, 2, "krait1_dig", "acpuclk-8960ab"), + RPM_REG_MAP(S8, 0, 1, "krait0_s8", "acpuclk-8960ab"), + RPM_REG_MAP(S8, 0, 2, "krait1_s8", "acpuclk-8960ab"), + RPM_REG_MAP(S8, 0, 6, "l2_s8", "acpuclk-8960ab"), +}; + +struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata = { + .init_data = msm_rpm_regulator_init_data, + .num_regulators = ARRAY_SIZE(msm_rpm_regulator_init_data), + .version = RPM_VREG_VERSION_8960, + .vreg_id_vdd_mem = RPM_VREG_ID_PM8921_L24, + .vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3, + .consumer_map = msm_rpm_regulator_consumer_mapping, + .consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping), +}; diff --git a/arch/arm/mach-msm/board-m2-storage.c b/arch/arm/mach-msm/board-m2-storage.c new file mode 100644 index 00000000000..28499601e95 --- /dev/null +++ b/arch/arm/mach-msm/board-m2-storage.c @@ -0,0 +1,412 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devices.h" +#include "board-8960.h" +#include "board-storage-common-a.h" + +static struct msm_bus_vectors sdcc_init_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors sdcc_perf_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 60000000, + /* + * 960 MB/s bandwidth requirement would ensure that system + * fabric clock running atleast minimum speed of 120MHz + * with 64-bit wide (8-byte) system fabric. + */ + .ib = 960000000, + }, +}; + +static struct msm_bus_paths sdcc_bus_scale_usecases[] = { + { + ARRAY_SIZE(sdcc_init_vectors), + sdcc_init_vectors, + }, + { + ARRAY_SIZE(sdcc_perf_vectors), + sdcc_perf_vectors, + }, +}; + +static struct msm_bus_scale_pdata sdcc_bus_scale_pdata = { + sdcc_bus_scale_usecases, + ARRAY_SIZE(sdcc_bus_scale_usecases), + .name = "sdcc", +}; + +/* MSM8960 has 5 SDCC controllers */ +enum sdcc_controllers { + SDCC1, + SDCC2, + SDCC3, + SDCC4, + SDCC5, + MAX_SDCC_CONTROLLER +}; + +/* All SDCC controllers require VDD/VCC voltage */ +static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = { + /* SDCC1 : eMMC card connected */ + [SDCC1] = { + .name = "sdc_vdd", + .high_vol_level = 2950000, + .low_vol_level = 2950000, + .always_on = 1, + .lpm_sup = 1, + .lpm_uA = 9000, + .hpm_uA = 200000, /* 200mA */ + }, + /* SDCC3 : External card slot connected */ + [SDCC3] = { + .name = "sdc_vdd", + .high_vol_level = 2950000, + .low_vol_level = 2950000, + .hpm_uA = 600000, /* 600mA */ + }, + /* SDCC4 : External card slot connected */ + [SDCC4] = { + .name = "sdc_vdd", + .set_voltage_sup = 1, + .high_vol_level = 1800000, + .low_vol_level = 1800000, + .hpm_uA = 600000, /* 600mA */ + }, + +}; + +/* SDCC controllers may require voting for VDD IO voltage */ +static struct msm_mmc_reg_data mmc_vdd_io_reg_data[MAX_SDCC_CONTROLLER] = { + /* SDCC1 : eMMC card connected */ + [SDCC1] = { + .name = "sdc_vdd_io", + .always_on = 1, + .high_vol_level = 1800000, + .low_vol_level = 1800000, + .hpm_uA = 200000, /* 200mA */ + }, + /* SDCC3 : External card slot connected */ + [SDCC3] = { + .name = "sdc_vdd_io", + .high_vol_level = 2950000, + .low_vol_level = 1850000, + .always_on = 1, + .lpm_sup = 1, + /* Max. Active current required is 16 mA */ + .hpm_uA = 16000, + /* + * Sleep current required is ~300 uA. But min. vote can be + * in terms of mA (min. 1 mA). So let's vote for 2 mA + * during sleep. + */ + .lpm_uA = 2000, + }, + [SDCC4] = { + .name = "sdc_vddp", + .set_voltage_sup = 1, + .high_vol_level = 1800000, + .low_vol_level = 1800000, + .always_on = 1, + .lpm_sup = 1, + /* Max. Active current required is 16 mA */ + .hpm_uA = 600000, /* 600mA, */ + /* + * Sleep current required is ~300 uA. But min. vote can be + * in terms of mA (min. 1 mA). So let's vote for 2 mA + * during sleep. + */ + .lpm_uA = 600000, /* 600mA, */ + }, +}; + +static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = { + /* SDCC1 : eMMC card connected */ + [SDCC1] = { + .vdd_data = &mmc_vdd_reg_data[SDCC1], + .vdd_io_data = &mmc_vdd_io_reg_data[SDCC1], + }, + /* SDCC3 : External card slot connected */ + [SDCC3] = { + .vdd_data = &mmc_vdd_reg_data[SDCC3], + .vdd_io_data = &mmc_vdd_io_reg_data[SDCC3], + }, + /* SDCC4 : External card slot connected */ + [SDCC4] = { + .vdd_data = &mmc_vdd_reg_data[SDCC4], + /* Qcom said no vddp is needed */ + /* .vddp_data = &mmc_vddp_reg_data[SDCC4], */ + } +}; + +/* SDC1 pad data */ +static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = { + {TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA}, + {TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA}, + {TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA} +}; + +static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = { + {TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA}, + {TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA}, + {TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA} +}; + +static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = { + {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL}, + {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP}, + {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP} +}; + +static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = { + {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL}, + {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP}, + {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP} +}; + +/* SDC3 pad data */ +static struct msm_mmc_pad_drv sdc3_pad_drv_on_cfg[] = { + {TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA}, + {TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA}, + {TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA} +}; + +static struct msm_mmc_pad_drv sdc3_pad_drv_off_cfg[] = { + {TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA}, + {TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA}, + {TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA} +}; + +static struct msm_mmc_pad_pull sdc3_pad_pull_on_cfg[] = { + {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL}, + {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP}, + {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP} +}; + +static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = { + {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL}, + /* + * SDC3 CMD line should be PULLed UP otherwise fluid platform will + * see transitions (1 -> 0 and 0 -> 1) on card detection line, + * which would result in false card detection interrupts. + */ + {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP}, + /* + * Keeping DATA lines status to PULL UP will make sure that + * there is no current leak during sleep if external pull up + * is connected to DATA lines. + */ + {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP} +}; + +/* SDC4 pad data */ +static struct msm_mmc_pad_drv sdc4_pad_drv_on_cfg[] = { + {TLMM_HDRV_SDC4_CLK, GPIO_CFG_8MA}, + {TLMM_HDRV_SDC4_CMD, GPIO_CFG_8MA}, + {TLMM_HDRV_SDC4_DATA, GPIO_CFG_8MA} +}; + +static struct msm_mmc_pad_drv sdc4_pad_drv_off_cfg[] = { + {TLMM_HDRV_SDC4_CLK, GPIO_CFG_2MA}, + {TLMM_HDRV_SDC4_CMD, GPIO_CFG_2MA}, + {TLMM_HDRV_SDC4_DATA, GPIO_CFG_2MA} +}; + +static struct msm_mmc_pad_pull sdc4_pad_pull_on_cfg[] = { + {TLMM_PULL_SDC4_CLK, GPIO_CFG_NO_PULL}, + {TLMM_PULL_SDC4_CMD, GPIO_CFG_PULL_UP}, + {TLMM_PULL_SDC4_DATA, GPIO_CFG_PULL_UP} +}; + +static struct msm_mmc_pad_pull sdc4_pad_pull_off_cfg[] = { + {TLMM_PULL_SDC4_CLK, GPIO_CFG_NO_PULL}, + {TLMM_PULL_SDC4_CMD, GPIO_CFG_PULL_UP}, + {TLMM_PULL_SDC4_DATA, GPIO_CFG_PULL_UP} +}; + + +static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = { + [SDCC1] = { + .on = sdc1_pad_pull_on_cfg, + .off = sdc1_pad_pull_off_cfg, + .size = ARRAY_SIZE(sdc1_pad_pull_on_cfg) + }, + [SDCC3] = { + .on = sdc3_pad_pull_on_cfg, + .off = sdc3_pad_pull_off_cfg, + .size = ARRAY_SIZE(sdc3_pad_pull_on_cfg) + }, + [SDCC4] = { + .on = sdc4_pad_pull_on_cfg, + .off = sdc4_pad_pull_off_cfg, + .size = ARRAY_SIZE(sdc4_pad_pull_on_cfg) + }, +}; + +static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = { + [SDCC1] = { + .on = sdc1_pad_drv_on_cfg, + .off = sdc1_pad_drv_off_cfg, + .size = ARRAY_SIZE(sdc1_pad_drv_on_cfg) + }, + [SDCC3] = { + .on = sdc3_pad_drv_on_cfg, + .off = sdc3_pad_drv_off_cfg, + .size = ARRAY_SIZE(sdc3_pad_drv_on_cfg) + }, + [SDCC4] = { + .on = sdc4_pad_drv_on_cfg, + .off = sdc4_pad_drv_off_cfg, + .size = ARRAY_SIZE(sdc4_pad_drv_on_cfg) + }, +}; + +static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = { + [SDCC1] = { + .pull = &mmc_pad_pull_data[SDCC1], + .drv = &mmc_pad_drv_data[SDCC1] + }, + [SDCC3] = { + .pull = &mmc_pad_pull_data[SDCC3], + .drv = &mmc_pad_drv_data[SDCC3] + }, + [SDCC4] = { + .pull = &mmc_pad_pull_data[SDCC4], + .drv = &mmc_pad_drv_data[SDCC4] + }, +}; + +static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = { + [SDCC1] = { + .pad_data = &mmc_pad_data[SDCC1], + }, + [SDCC3] = { + .pad_data = &mmc_pad_data[SDCC3], + }, + [SDCC4] = { + .pad_data = &mmc_pad_data[SDCC4], + }, +}; + +static unsigned int sdc1_sup_clk_rates[] = { + 400000, 24000000, 48000000, 96000000 +}; + +static unsigned int sdc3_sup_clk_rates[] = { + 400000, 24000000, 48000000, 96000000, 192000000 +}; + +static unsigned int sdc4_sup_clk_rates[] = { + 400000, 24000000, 48000000 +}; + +#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT +static struct mmc_platform_data msm8960_sdc1_data = { + .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, +#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT + .mmc_bus_width = MMC_CAP_8_BIT_DATA, +#else + .mmc_bus_width = MMC_CAP_4_BIT_DATA, +#endif + .mmc_erase_caps = MMC_CAP_ERASE, + .sup_clk_table = sdc1_sup_clk_rates, + .sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates), + .nonremovable = 1, + .vreg_data = &mmc_slot_vreg_data[SDCC1], + .uhs_caps = (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50), + .pin_data = &mmc_slot_pin_data[SDCC1], + .msm_bus_voting_data = &sps_to_ddr_bus_voting_data, + .uhs_caps2 = MMC_CAP2_HS200_1_8V_SDR, + .packed_write = MMC_CAP2_PACKED_WR | MMC_CAP2_PACKED_WR_CONTROL, +}; +#endif + +#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT +static struct mmc_platform_data msm8960_sdc3_data = { + .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, + .mmc_bus_width = MMC_CAP_4_BIT_DATA, + .sup_clk_table = sdc3_sup_clk_rates, + .sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates), +#ifdef CONFIG_MMC_MSM_SDC3_WP_SUPPORT + .wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(16), +#endif + .vreg_data = &mmc_slot_vreg_data[SDCC3], + .pin_data = &mmc_slot_pin_data[SDCC3], + .status_gpio = PM8921_GPIO_PM_TO_SYS(26), + .status_irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26), + .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + .is_status_gpio_active_low = true, + .xpc_cap = 1, + .uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 | + MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_600 | MMC_CAP_1_8V_DDR), + .msm_bus_voting_data = &sps_to_ddr_bus_voting_data, +}; +#endif + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT +static struct mmc_platform_data msm8960_sdc4_data = { + .ocr_mask = MMC_VDD_165_195 | MMC_VDD_27_28 | MMC_VDD_28_29, + .mmc_bus_width = MMC_CAP_4_BIT_DATA, + .sup_clk_table = sdc4_sup_clk_rates, + .sup_clk_cnt = ARRAY_SIZE(sdc4_sup_clk_rates), + .vreg_data = &mmc_slot_vreg_data[SDCC4], + .pin_data = &mmc_slot_pin_data[SDCC4], + .xpc_cap = 1, + .uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 | + MMC_CAP_MAX_CURRENT_600), +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) + .register_status_notify = brcm_wifi_status_register, +#endif + .msm_bus_scale_data = &sdcc_bus_scale_pdata, + .msm_bus_voting_data = &sps_to_ddr_bus_voting_data, +}; +#endif + +void __init msm8960_init_mmc(void) +{ +#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT + /* SDC1 : eMMC card connected */ + msm_add_sdcc(1, &msm8960_sdc1_data); +#endif +#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT + /* SDC3: External card slot */ + msm_add_sdcc(3, &msm8960_sdc3_data); +#endif + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + /* SDC4: WIFI BCM4334 */ + msm_add_sdcc(4, &msm8960_sdc4_data); +#endif + +} diff --git a/arch/arm/mach-msm/board-m2_att-gpiomux.c b/arch/arm/mach-msm/board-m2_att-gpiomux.c new file mode 100644 index 00000000000..ba4695a097b --- /dev/null +++ b/arch/arm/mach-msm/board-m2_att-gpiomux.c @@ -0,0 +1,1081 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include "devices.h" +#include "board-8960.h" +#include +#include + +/* The SPI configurations apply to GSBI 1*/ +static struct gpiomux_setting spi_active = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_12MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting spi_suspended_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting spi_active_config2 = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting spi_suspended_config2 = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting gsbi3_suspended_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting gsbi1 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_12MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi3_active_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi5 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi7 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#ifdef CONFIG_VP_A2220 +static struct gpiomux_setting gsbi8 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +static struct gpiomux_setting audience_suspend_gpio_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif +static struct gpiomux_setting gsbi10 = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi12 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_mclk = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#if 0 +static struct gpiomux_setting audio_auxpcm[] = { + /* Suspended state */ + { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + }, + /* Active state */ + { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, + }, +}; +#endif +#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE) +static struct gpiomux_setting gpio_eth_config = { + .pull = GPIOMUX_PULL_NONE, + .drv = GPIOMUX_DRV_8MA, + .func = GPIOMUX_FUNC_GPIO, +}; +#endif +#if 0 +static struct gpiomux_setting slimbus = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_KEEPER, +}; +#endif +static struct gpiomux_setting gpio_key_active_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting gpio_key_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting wcnss_5wire_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting wcnss_5wire_active_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_6MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT +static struct gpiomux_setting sdc4_suspend_cfg = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting sdc4_suspend2_cfg = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting sdc4_active_cfg = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_16MA, + .pull = GPIOMUX_PULL_UP, +}; +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC +static struct gpiomux_setting hsic_act_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_12MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting hsic_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_OUT_LOW, +}; + +static struct gpiomux_setting hsic_hub_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif + +static struct gpiomux_setting hap_lvl_shft_suspended_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting hap_lvl_shft_active_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting ap2mdm_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting mdm2ap_status_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting mdm2ap_errfatal_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_16MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting mdp_vsync_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting mdp_vsync_active_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static struct gpiomux_setting hdmi_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting hdmi_active_1_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting hdmi_active_2_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; +#if 0 +static struct gpiomux_setting hdmi_active_3_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_IN, +}; +static struct gpiomux_setting hdmi_active_4_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, + .dir = GPIOMUX_OUT_HIGH, +}; +#endif +#endif +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +static struct gpiomux_setting mhl_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting mhl_active_1_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_OUT_LOW, +}; +#if 0 +static struct gpiomux_setting mhl_active_2_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif +#endif + +#ifdef CONFIG_USB_SWITCH_FSA9485 +static struct gpiomux_setting fsa9485_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting fsa9485_active_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_fsa9485_configs[] __initdata = { + { + .gpio = 14, + .settings = { + [GPIOMUX_ACTIVE] = &fsa9485_active_cfg, + [GPIOMUX_SUSPENDED] = &fsa9485_suspend_cfg, + }, + }, + + { + .gpio = 73, + .settings = { + [GPIOMUX_ACTIVE] = &fsa9485_active_cfg, + [GPIOMUX_SUSPENDED] = &fsa9485_suspend_cfg, + }, + }, + + { + .gpio = 74, + .settings = { + [GPIOMUX_ACTIVE] = &fsa9485_active_cfg, + [GPIOMUX_SUSPENDED] = &fsa9485_suspend_cfg, + }, + }, +}; +#endif + +#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE) +static struct msm_gpiomux_config msm8960_ethernet_configs[] = { + { + .gpio = 90, + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_eth_config, + } + }, + { + .gpio = 89, + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_eth_config, + } + }, +}; +#endif + +struct msm_gpiomux_config msm8960_gpio_key_configs[] = { + { + .settings = { + [GPIOMUX_ACTIVE] = &gpio_key_active_cfg, + [GPIOMUX_SUSPENDED] = &gpio_key_suspend_cfg, + } + }, + { + .settings = { + [GPIOMUX_ACTIVE] = &gpio_key_active_cfg, + [GPIOMUX_SUSPENDED] = &gpio_key_suspend_cfg, + } + }, + { + .gpio = GPIO_HOME_KEY, + .settings = { + [GPIOMUX_ACTIVE] = &gpio_key_active_cfg, + [GPIOMUX_SUSPENDED] = &gpio_key_suspend_cfg, + } + }, +}; +#ifdef CONFIG_VP_A2220 +static struct msm_gpiomux_config audience_suspend_configs[] __initdata = { + { + .gpio = 35, /* 2MIC PW DN */ + .settings = { + [GPIOMUX_SUSPENDED] = &audience_suspend_gpio_config, + }, + }, + { + .gpio = 75, /* 2MIC RESET */ + .settings = { + [GPIOMUX_SUSPENDED] = &audience_suspend_gpio_config, + }, + }, +}; +#endif + +static struct msm_gpiomux_config msm8960_gsbi_configs[] __initdata = { + { + .gpio = 6, /* GSBI1 QUP SPI_DATA_MOSI */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = 7, /* GSBI1 QUP SPI_DATA_MISO */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = 8, /* GSBI1 QUP SPI_CS_N */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi1, + [GPIOMUX_ACTIVE] = &gsbi1, + }, + }, + { + .gpio = 9, /* GSBI1 QUP SPI_CLK */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi1, + [GPIOMUX_ACTIVE] = &gsbi1, + }, + }, + { + .gpio = 14, /* GSBI1 SPI_CS_1 */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config2, + [GPIOMUX_ACTIVE] = &spi_active_config2, + }, + }, + { + .gpio = 16, /* GSBI3 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg, + [GPIOMUX_ACTIVE] = &gsbi3_active_cfg, + }, + }, + { + .gpio = 17, /* GSBI3 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg, + [GPIOMUX_ACTIVE] = &gsbi3_active_cfg, + }, + }, + { + .gpio = 22, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 23, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 24, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 25, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 32, /* GSBI7 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi7, + }, + }, + { + .gpio = 33, /* GSBI7 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi7, + }, + }, +#ifdef CONFIG_S5C73M3 + { + .gpio = GPIO_CAM_SPI_MOSI, /* GSBI11 QUP SPI_DATA_MOSI */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = GPIO_CAM_SPI_MISO, /* GSBI11 QUP SPI_DATA_MISO */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = GPIO_CAM_SPI_SSN, /* GSBI11 QUP SPI_CS_N */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = GPIO_CAM_SPI_SCLK, /* GSBI11 QUP SPI_CLK */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, +#endif + { + .gpio = 44, /* GSBI12 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi12, + }, + }, + { + .gpio = 45, /* GSBI12 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi12, + }, + }, +#ifdef CONFIG_VP_A2220 + { + .gpio = 36, /* GSBI8 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi8, + }, + }, + { + .gpio = 37, /* GSBI8 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi8, + }, + }, +#endif + { + .gpio = 73, /* GSBI10 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi10, + }, + }, + { + .gpio = 74, /* GSBI10 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi10, + }, + }, +}; +#if 0 +static struct msm_gpiomux_config msm8960_slimbus_config[] __initdata = { + { + .gpio = 60, /* slimbus data */ + .settings = { + [GPIOMUX_SUSPENDED] = &slimbus, + }, + }, + { + .gpio = 61, /* slimbus clk */ + .settings = { + [GPIOMUX_SUSPENDED] = &slimbus, + }, + }, +}; +#endif +static struct msm_gpiomux_config msm8960_audio_codec_configs[] __initdata = { + { + .gpio = 59, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_mclk, + }, + }, +}; + +static struct gpiomux_setting cdc_i2s_mclk = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_rx_sclk = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_rx_dout = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_rx_ws = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_audio_i2s_rx_codec_configs[] = { + { + .gpio = 59, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_mclk, + }, + }, + { + .gpio = 60, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_rx_sclk, + }, + }, + { + .gpio = 61, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_rx_dout, + }, + }, + { + .gpio = 62, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_rx_ws, + }, + }, +}; + +static struct gpiomux_setting cdc_i2s_tx_sclk = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_tx_d0 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#if 0 +static struct gpiomux_setting cdc_i2s_tx_d1 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif +static struct gpiomux_setting cdc_i2s_tx_ws = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_audio_i2s_tx_codec_configs[] = { + { + .gpio = 59, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_mclk, + }, + }, + { + .gpio = 55, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_tx_sclk, + }, + }, + { + .gpio = 56, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_tx_ws, + }, + }, + { + .gpio = 57, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_tx_d0, + }, + }, + +}; + +#if 0 +static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = { + { + .gpio = 63, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, + { + .gpio = 64, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, + { + .gpio = 65, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, + { + .gpio = 66, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, +}; +#endif +static struct msm_gpiomux_config wcnss_5wire_interface[] = { + { + .gpio = 84, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 85, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 86, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 87, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 88, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, +}; + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT +static struct msm_gpiomux_config sdc4_interface[] = { + { + .gpio = 83, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 84, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 85, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 86, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 87, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 88, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend2_cfg, + }, + }, +}; +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC +static struct msm_gpiomux_config msm8960_hsic_configs[] = { + { + .gpio = 150, /*HSIC_STROBE */ + .settings = { + [GPIOMUX_ACTIVE] = &hsic_act_cfg, + [GPIOMUX_SUSPENDED] = &hsic_sus_cfg, + }, + }, + { + .gpio = 151, /* HSIC_DATA */ + .settings = { + [GPIOMUX_ACTIVE] = &hsic_act_cfg, + [GPIOMUX_SUSPENDED] = &hsic_sus_cfg, + }, + }, + { + .gpio = 91, /* HSIC_HUB_RESET */ + .settings = { + [GPIOMUX_ACTIVE] = &hsic_hub_act_cfg, + [GPIOMUX_SUSPENDED] = &hsic_sus_cfg, + }, + }, +}; +#endif + +static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = { + { + .gpio = 47, + .settings = { + [GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config, + [GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config, + }, + }, +}; + +static struct msm_gpiomux_config mdm_configs[] __initdata = { + /* AP2MDM_STATUS */ + { + .gpio = 94, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_cfg, + } + }, + /* MDM2AP_STATUS */ + { + .gpio = 69, + .settings = { + [GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg, + } + }, + /* MDM2AP_ERRFATAL */ + { + .gpio = 70, + .settings = { + [GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg, + } + }, + /* AP2MDM_ERRFATAL */ + { + .gpio = 95, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_cfg, + } + }, +}; + +static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = { + { + .gpio = 0, + .settings = { + [GPIOMUX_ACTIVE] = &mdp_vsync_active_cfg, + [GPIOMUX_SUSPENDED] = &mdp_vsync_suspend_cfg, + }, + } +}; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static struct msm_gpiomux_config msm8960_hdmi_configs[] __initdata = { + { + .gpio = 99, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 100, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 101, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 102, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_2_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, +}; +#endif +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +static struct msm_gpiomux_config msm8960_mhl_configs[] __initdata = { + { + .gpio = GPIO_MHL_EN, + .settings = { + [GPIOMUX_ACTIVE] = &mhl_active_1_cfg, + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_RST, + .settings = { + [GPIOMUX_ACTIVE] = &mhl_active_1_cfg, + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_WAKE_UP, + .settings = { + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_SDA, + .settings = { + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_SCL, + .settings = { + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + + + +}; +#endif + +#ifdef CONFIG_I2C + +#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3 +#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10 + +#endif + +static struct gpiomux_setting sec_ts_int_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting sec_ts_int_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct msm_gpiomux_config msm8960_sec_ts_configs[] = { + { /* TS INTERRUPT */ + .gpio = 11, + .settings = { + [GPIOMUX_ACTIVE] = &sec_ts_int_act_cfg, + [GPIOMUX_SUSPENDED] = &sec_ts_int_sus_cfg, + }, + }, +}; + + +static struct gpiomux_setting sec_prox_int_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting sec_prox_int_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_sec_sensor_configs[] = { + { /* PS INTERRUPT */ + .gpio = 42, + .settings = { + [GPIOMUX_ACTIVE] = &sec_prox_int_act_cfg, + [GPIOMUX_SUSPENDED] = &sec_prox_int_sus_cfg, + }, + }, +}; + +int __init msm8960_init_gpiomux(void) +{ + int rc = msm_gpiomux_init(NR_GPIO_IRQS); + if (rc) { + pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc); + return rc; + } + +#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE) + msm_gpiomux_install(msm8960_ethernet_configs, + ARRAY_SIZE(msm8960_ethernet_configs)); +#endif + + msm_gpiomux_install(msm8960_gsbi_configs, + ARRAY_SIZE(msm8960_gsbi_configs)); + +#ifdef CONFIG_VP_A2220 + msm_gpiomux_install(audience_suspend_configs, + ARRAY_SIZE(audience_suspend_configs)); +#endif + msm8960_gpio_key_configs[0].gpio = gpio_rev(VOLUME_UP); + msm8960_gpio_key_configs[1].gpio = gpio_rev(VOLUME_DOWN); + if (system_rev < BOARD_REV09) + msm_gpiomux_install(msm8960_gpio_key_configs, 2); + else + msm_gpiomux_install(msm8960_gpio_key_configs, + ARRAY_SIZE(msm8960_gpio_key_configs)); + + msm_gpiomux_install(msm8960_sec_ts_configs, + ARRAY_SIZE(msm8960_sec_ts_configs)); + + msm_gpiomux_install(msm8960_sec_sensor_configs, + ARRAY_SIZE(msm8960_sec_sensor_configs)); + + msm_gpiomux_install(msm8960_audio_codec_configs, + ARRAY_SIZE(msm8960_audio_codec_configs)); + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + if (system_rev >= BOARD_REV04) + msm_gpiomux_install(sdc4_interface, ARRAY_SIZE(sdc4_interface)); + else +#endif + msm_gpiomux_install(wcnss_5wire_interface, + ARRAY_SIZE(wcnss_5wire_interface)); + + msm_gpiomux_install(msm8960_audio_i2s_rx_codec_configs, + ARRAY_SIZE(msm8960_audio_i2s_tx_codec_configs)); + + msm_gpiomux_install(msm8960_audio_i2s_tx_codec_configs, + ARRAY_SIZE(msm8960_audio_i2s_tx_codec_configs)); + +#ifdef CONFIG_USB_SWITCH_FSA9485 + msm_gpiomux_install(msm8960_fsa9485_configs, + ARRAY_SIZE(msm8960_fsa9485_configs)); +#endif + + if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() || + machine_is_msm8960_liquid() || machine_is_msm8960_cdp()) + msm_gpiomux_install(hap_lvl_shft_config, + ARRAY_SIZE(hap_lvl_shft_config)); + + if (PLATFORM_IS_CHARM25()) + msm_gpiomux_install(mdm_configs, + ARRAY_SIZE(mdm_configs)); + +#ifdef CONFIG_USB_EHCI_MSM_HSIC + if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) && + (PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid())) + msm_gpiomux_install(msm8960_hsic_configs, + ARRAY_SIZE(msm8960_hsic_configs)); +#endif + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL + msm_gpiomux_install(msm8960_hdmi_configs, + ARRAY_SIZE(msm8960_hdmi_configs)); +#endif + + msm_gpiomux_install(msm8960_mdp_vsync_configs, + ARRAY_SIZE(msm8960_mdp_vsync_configs)); + + return 0; +} diff --git a/arch/arm/mach-msm/board-m2_att.c b/arch/arm/mach-msm/board-m2_att.c new file mode 100644 index 00000000000..9fd4e8415ef --- /dev/null +++ b/arch/arm/mach-msm/board-m2_att.c @@ -0,0 +1,5523 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ANDROID_PMEM +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef CONFIG_USB_MSM_OTG_72K +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SENSORS_AK8975 +#include +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1 +#include +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 +#include +#endif + +#ifdef CONFIG_OPTICAL_GP2A +#include +#endif +#ifdef CONFIG_OPTICAL_GP2AP020A00F +#include +#endif +#ifdef CONFIG_VP_A2220 +#include +#endif +#ifdef CONFIG_INPUT_BMP180 +#include +#endif +#ifdef CONFIG_WCD9310_CODEC +#include +#include +#include +#endif +#ifdef CONFIG_KEYBOARD_GPIO +#include +#endif +#ifdef CONFIG_USB_SWITCH_FSA9485 +#include +#include +#endif + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +#include +#endif + +#include +#ifdef CONFIG_PM8921_CHARGER +#include +#endif +#ifdef CONFIG_PM8921_SEC_CHARGER +#include +#endif +#ifdef CONFIG_BATTERY_SEC +#include +#endif +#ifdef CONFIG_CHARGER_SMB347 +#include +#endif +#ifdef CONFIG_BATTERY_MAX17040 +#include +#endif +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "timer.h" +#include "devices.h" +#include "devices-msm8x60.h" +#include "spm.h" +#include "board-8960.h" +#include "pm.h" +#include +#include "rpm_resources.h" +#include +#include "acpuclock.h" +#include "rpm_log.h" +#include "smd_private.h" +#ifdef CONFIG_NFC_PN544 +#include +#endif /* CONFIG_NFC_PN544 */ +#include "mach/board-msm8960-camera.h" +#include "pm-boot.h" +#include "msm_watchdog.h" +#ifdef CONFIG_SENSORS_CM36651 +#include +#endif +#ifdef CONFIG_REGULATOR_MAX8952 +#include +#include +#endif +#ifdef CONFIG_VIBETONZ +#include +#endif + +#ifdef CONFIG_SAMSUNG_JACK +#include +#endif + +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#endif + +#ifdef CONFIG_ANDROID_RAM_CONSOLE +#include +#endif + +extern int system_rev; +#ifdef CONFIG_TOUCHSCREEN_MMS144 +struct tsp_callbacks *charger_callbacks; +#endif + +static struct platform_device msm_fm_platform_init = { + .name = "iris_fm", + .id = -1, +}; + +#ifdef CONFIG_SEC_DEBUG +#include +#endif +unsigned int gpio_table[][GPIO_REV_MAX] = { +/* GPIO_INDEX Rev {#00,#01,#02,#03,#04,#05,#06,#07,#08, ..., #12 }, */ +/* MDP_VSYNC */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* VOLUME_UP */ { 80, 80, 80, 80, 80, 80, 50, 50, 50, 50, 50, 50, 50 }, +/* VOLUME_DOWN */ { 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81 }, +/* GPIO_MAG_RST */ { 66, 66, 66, 66, 48, 48, 48, 48, 9, 9, 9, 48, 9 }, +/* ALS_INT */ { 42, 42, 42, 42, 42, 42, 42, 42, 6, 6, 6, 42, 6 }, +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) +/* ALS_SDA */ { 63, 63, 63, 63, 12, 12, 12, 12, 12, 12, 12, 12, 12 }, +/* ALS_SCL */ { 64, 64, 64, 64, 13, 13, 13, 13, 13, 13, 13, 13, 13 }, +#endif +/* LCD_22V_EN */ { 10, 10, 10, 10, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, +/* LINEOUT_EN */ { -1, -1, -1, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, +/* A2220_WAKEUP */ { 79, 79, 79, 79, 35, 35, 35, 35, 35, 35, 35, 35, 35 }, +/* A2220_SDA */ { 12, 12, 12, 12, 36, 36, 36, 36, 36, 36, 36, 36, 36 }, +/* A2220_SCL */ { 13, 13, 13, 13, 37, 37, 37, 37, 37, 37, 37, 37, 37 }, +/* CAM_AF_EN */ { 54, 54, 54, 54, 77, 77, 77, 77, 77, 77, 77, 77, 77 }, +/* CAM_FLASH_SW */ { 49, 49, 49, 49, 49, 49, 49, 49, 80, 80, 80, 80, 80 }, +/* BT_HOST_WAKE */ { -1, -1, -1, -1, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, +/* BT_WAKE */ { -1, -1, -1, -1, 79, 79, 79, 79, 79, 79, 79, 79, 79 }, +/* BT_EN */ { -1, -1, -1, -1, 82, 82, 82, 82, 82, 82, 82, 82, 82 }, +}; + +int gpio_rev(unsigned int index) +{ + if (system_rev >= GPIO_REV_MAX) + return -EINVAL; + + if (system_rev < BOARD_REV12) + return gpio_table[index][system_rev]; + else + return gpio_table[index][BOARD_REV12]; +} + +#if defined(CONFIG_OPTICAL_GP2AP020A00F) +static void gp2a_power_on(int onoff); +#endif + +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static void mpu_power_on(int onoff); +#endif + +#ifdef CONFIG_SENSORS_AK8975 +static void akm_power_on(int onoff); +#endif + +#ifdef CONFIG_INPUT_BMP180 +static void bmp180_power_on(int onoff); +#endif + +#ifdef CONFIG_SENSORS_CM36651 +static void cm36651_power_on(int onoff); +#endif + +#if defined(CONFIG_SENSORS_AK8975) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_INPUT_BMP180) || defined(CONFIG_OPTICAL_GP2A) || \ + defined(CONFIG_OPTICAL_GP2AP020A00F) || \ + defined(CONFIG_SENSORS_CM36651) +enum { + SNS_PWR_OFF, + SNS_PWR_ON, + SNS_PWR_KEEP +}; +#endif + + +#if defined(CONFIG_SENSORS_AK8975) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_INPUT_BMP180) || defined(CONFIG_OPTICAL_GP2A) +static void sensor_power_on_vdd(int, int); + +#endif + +#ifndef CONFIG_S5C73M3 +#define KS8851_RST_GPIO 89 +#define KS8851_IRQ_GPIO 90 +#endif + + +#define HAP_SHIFT_LVL_OE_GPIO 47 + +#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE) + +struct sx150x_platform_data msm8960_sx150x_data[] = { + [SX150X_CAM] = { + .gpio_base = GPIO_CAM_EXPANDER_BASE, + .oscio_is_gpo = false, + .io_pullup_ena = 0x0, + .io_pulldn_ena = 0xc0, + .io_open_drain_ena = 0x0, + .irq_summary = -1, + }, +}; + +#endif + +#ifdef CONFIG_I2C + +#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3 +#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10 + +#endif + +#if 0 +static struct gpiomux_setting sec_ts_ldo_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting sec_ts_ldo_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct msm_gpiomux_config msm8960_sec_ts_configs[] = { + { /* TS LDO EN */ + .gpio = 10, + .settings = { + [GPIOMUX_ACTIVE] = &sec_ts_ldo_act_cfg, + [GPIOMUX_SUSPENDED] = &sec_ts_ldo_sus_cfg, + }, + }, +}; +#endif +#define MSM_PMEM_ADSP_SIZE 0x9600000 /* 150 Mbytes */ +#define MSM_PMEM_ADSP_SIZE_FOR_2GB 0xA500000 /* 165 Mbytes */ +#define MSM_PMEM_AUDIO_SIZE 0x4CF000 /* 1.375 Mbytes */ +#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */ +#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */ +#define MSM_HDMI_PRIM_PMEM_SIZE 0x4000000 /* 64 Mbytes */ + +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +#define HOLE_SIZE 0x20000 +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x280000 /* 2.5MB */ +#ifdef CONFIG_MSM_IOMMU +#define MSM_ION_MM_SIZE 0x3800000 +#define MSM_ION_SF_SIZE 0x0 +#define MSM_ION_SF_SIZE_FOR_2GB 0x0 +#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */ +#define MSM_ION_HEAP_NUM 7 +#else +#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE +#define MSM_ION_SF_SIZE 0x5000000 /* 80MB */ +#define MSM_ION_SF_SIZE_FOR_2GB 0x6400000 /* 100MB */ +#define MSM_ION_QSECOM_SIZE 0x1700000 /* (24MB) */ +#define MSM_ION_HEAP_NUM 8 +#endif +#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */ +#define MSM_ION_MFC_SIZE SZ_8K +#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE + +#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000) +#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE +#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE + +#define MSM8960_FIXED_AREA_START 0xb0000000 +#define MAX_FIXED_AREA_SIZE 0x10000000 +#define MSM_MM_FW_SIZE 0x200000 +#define MSM8960_FW_START (MSM8960_FIXED_AREA_START - MSM_MM_FW_SIZE) + +static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE; +#else +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000 +#define MSM_ION_HEAP_NUM 1 +#endif + +#ifdef CONFIG_KERNEL_PMEM_EBI_REGION +static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE; +static int __init pmem_kernel_ebi1_size_setup(char *p) +{ + pmem_kernel_ebi1_size = memparse(p, NULL); + return 0; +} +early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); +#endif + +#ifdef CONFIG_ANDROID_PMEM +static unsigned pmem_size = MSM_PMEM_SIZE; +static unsigned pmem_param_set; +static int __init pmem_size_setup(char *p) +{ + pmem_size = memparse(p, NULL); + pmem_param_set = 1; + return 0; +} +early_param("pmem_size", pmem_size_setup); + +static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE; + +static int __init pmem_adsp_size_setup(char *p) +{ + pmem_adsp_size = memparse(p, NULL); + return 0; +} +early_param("pmem_adsp_size", pmem_adsp_size_setup); + +static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE; + +static int __init pmem_audio_size_setup(char *p) +{ + pmem_audio_size = memparse(p, NULL); + return 0; +} +early_param("pmem_audio_size", pmem_audio_size_setup); +#endif + +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem", + .allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING, + .cached = 1, + .memory_type = MEMTYPE_EBI1, +}; + +static struct platform_device android_pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = {.platform_data = &android_pmem_pdata}, +}; + +static struct android_pmem_platform_data android_pmem_adsp_pdata = { + .name = "pmem_adsp", + .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, + .cached = 0, + .memory_type = MEMTYPE_EBI1, +}; +static struct platform_device android_pmem_adsp_device = { + .name = "android_pmem", + .id = 2, + .dev = { .platform_data = &android_pmem_adsp_pdata }, +}; + +static struct android_pmem_platform_data android_pmem_audio_pdata = { + .name = "pmem_audio", + .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, + .cached = 0, + .memory_type = MEMTYPE_EBI1, +}; + +static struct platform_device android_pmem_audio_device = { + .name = "android_pmem", + .id = 4, + .dev = { .platform_data = &android_pmem_audio_pdata }, +}; +#endif +#endif + +struct fmem_platform_data fmem_pdata = { +}; + +#define DSP_RAM_BASE_8960 0x8da00000 +#define DSP_RAM_SIZE_8960 0x1800000 +static int dspcrashd_pdata_8960 = 0xDEADDEAD; + +static struct resource resources_dspcrashd_8960[] = { + { + .name = "msm_dspcrashd", + .start = DSP_RAM_BASE_8960, + .end = DSP_RAM_BASE_8960 + DSP_RAM_SIZE_8960, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device msm_device_dspcrashd_8960 = { + .name = "msm_dspcrashd", + .num_resources = ARRAY_SIZE(resources_dspcrashd_8960), + .resource = resources_dspcrashd_8960, + .dev = { .platform_data = &dspcrashd_pdata_8960 }, +}; + +static struct memtype_reserve msm8960_reserve_table[] __initdata = { + [MEMTYPE_SMI] = { + }, + [MEMTYPE_EBI0] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, + [MEMTYPE_EBI1] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, +}; + +#if defined(CONFIG_MSM_RTB) +static struct msm_rtb_platform_data msm_rtb_pdata = { + .size = SZ_1M, +}; + +static int __init msm_rtb_set_buffer_size(char *p) +{ + int s; + + s = memparse(p, NULL); + msm_rtb_pdata.size = ALIGN(s, SZ_4K); + return 0; +} +early_param("msm_rtb_size", msm_rtb_set_buffer_size); + +static struct platform_device msm_rtb_device = { + .name = "msm_rtb", + .id = -1, + .dev = { + .platform_data = &msm_rtb_pdata, + }, +}; +#endif + +static void __init reserve_rtb_memory(void) +{ +#if defined(CONFIG_MSM_RTB) + msm8960_reserve_table[MEMTYPE_EBI1].size += msm_rtb_pdata.size; +#endif +} + +static void __init size_pmem_devices(void) +{ +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + android_pmem_adsp_pdata.size = pmem_adsp_size; + + if (!pmem_param_set) { + if (machine_is_msm8960_liquid()) + pmem_size = MSM_LIQUID_PMEM_SIZE; + if (msm8960_hdmi_as_primary_selected()) + pmem_size = MSM_HDMI_PRIM_PMEM_SIZE; + } + + android_pmem_pdata.size = pmem_size; + android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE; +#endif +#endif +} +#if 0 +static void __init reserve_memory_for(struct android_pmem_platform_data *p) +{ + msm8960_reserve_table[p->memory_type].size += p->size; +} +#endif +static void __init reserve_pmem_memory(void) +{ +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + reserve_memory_for(&android_pmem_adsp_pdata); + reserve_memory_for(&android_pmem_pdata); + reserve_memory_for(&android_pmem_audio_pdata); +#endif + msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; +#endif +} + +static int msm8960_paddr_to_memtype(unsigned int paddr) +{ + return MEMTYPE_EBI1; +} + +#define FMEM_ENABLED 0 + +#ifdef CONFIG_ION_MSM +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +static struct ion_cp_heap_pdata cp_mm_ion_pdata = { + .permission_type = IPT_TYPE_MM_CARVEOUT, + .align = SZ_64K, + .reusable = FMEM_ENABLED, + .mem_is_fmem = FMEM_ENABLED, + .fixed_position = FIXED_MIDDLE, + .iommu_map_all = 1, + .iommu_2x_map_domain = VIDEO_DOMAIN, +}; + +static struct ion_cp_heap_pdata cp_mfc_ion_pdata = { + .permission_type = IPT_TYPE_MFC_SHAREDMEM, + .align = PAGE_SIZE, + .reusable = 0, + .mem_is_fmem = FMEM_ENABLED, + .fixed_position = FIXED_HIGH, +}; + +static struct ion_co_heap_pdata co_ion_pdata = { + .adjacent_mem_id = INVALID_HEAP_ID, + .align = PAGE_SIZE, + .mem_is_fmem = 0, +}; + +static struct ion_co_heap_pdata fw_co_ion_pdata = { + .adjacent_mem_id = ION_CP_MM_HEAP_ID, + .align = SZ_128K, + .mem_is_fmem = FMEM_ENABLED, + .fixed_position = FIXED_LOW, +}; +#endif + +struct ion_platform_heap m2_ion_heaps[] = { + { + .id = ION_SYSTEM_HEAP_ID, + .type = ION_HEAP_TYPE_SYSTEM, + .name = ION_VMALLOC_HEAP_NAME, + }, +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + { + .id = ION_CP_MM_HEAP_ID, + .type = ION_HEAP_TYPE_CP, + .name = ION_MM_HEAP_NAME, + .size = MSM_ION_MM_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &cp_mm_ion_pdata, + }, + { + .id = ION_MM_FIRMWARE_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_MM_FIRMWARE_HEAP_NAME, + .size = MSM_ION_MM_FW_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &fw_co_ion_pdata, + }, + { + .id = ION_CP_MFC_HEAP_ID, + .type = ION_HEAP_TYPE_CP, + .name = ION_MFC_HEAP_NAME, + .size = MSM_ION_MFC_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &cp_mfc_ion_pdata, + }, +#ifndef CONFIG_MSM_IOMMU + { + .id = ION_SF_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_SF_HEAP_NAME, + .size = MSM_ION_SF_SIZE_FOR_2GB, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &co_ion_pdata, + }, +#endif + { + .id = ION_IOMMU_HEAP_ID, + .type = ION_HEAP_TYPE_IOMMU, + .name = ION_IOMMU_HEAP_NAME, + }, + { + .id = ION_QSECOM_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_QSECOM_HEAP_NAME, + .size = MSM_ION_QSECOM_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &co_ion_pdata, + }, + { + .id = ION_AUDIO_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_HEAP_NAME, + .size = MSM_ION_AUDIO_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &co_ion_pdata, + }, +#endif +}; + +#if 0 +static u64 msm_dmamask = DMA_BIT_MASK(32); +static struct platform_device ion_mm_heap_device = { + .name = "ion-mm-heap-device", + .id = -1, + .dev = { + .dma_mask = &msm_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif +/** + * These heaps are listed in the order they will be allocated. Due to + * video hardware restrictions and content protection the FW heap has to + * be allocated adjacent (below) the MM heap and the MFC heap has to be + * allocated after the MM heap to ensure MFC heap is not more than 256MB + * away from the base address of the FW heap. + * However, the order of FW heap and MM heap doesn't matter since these + * two heaps are taken care of by separate code to ensure they are adjacent + * to each other. + * Don't swap the order unless you know what you are doing! + */ +static struct ion_platform_data ion_pdata = { + .nr = MSM_ION_HEAP_NUM, + .heaps = m2_ion_heaps, +}; + + +static struct platform_device ion_dev = { + .name = "ion-msm", + .id = 1, + .dev = { .platform_data = &ion_pdata }, +}; +#endif + +struct platform_device fmem_device = { + .name = "fmem", + .id = 1, + .dev = { .platform_data = &fmem_pdata }, +}; + +static void __init adjust_mem_for_liquid(void) +{ + unsigned int i; + + if (!pmem_param_set) { + if (machine_is_msm8960_liquid()) + msm_ion_sf_size = MSM_LIQUID_ION_SF_SIZE; + + if (msm8960_hdmi_as_primary_selected()) + msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE; + + if (machine_is_msm8960_liquid() || + msm8960_hdmi_as_primary_selected()) { + for (i = 0; i < ion_pdata.nr; i++) { + if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) { + ion_pdata.heaps[i].size = + msm_ion_sf_size; + pr_debug("msm_ion_sf_size 0x%x\n", + msm_ion_sf_size); + break; + } + } + } + } +} + +static void __init reserve_mem_for_ion(enum ion_memory_types mem_type, + unsigned long size) +{ + msm8960_reserve_table[mem_type].size += size; +} + +static void __init msm8960_reserve_fixed_area(unsigned long fixed_area_size) +{ +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + int ret; + + if (fixed_area_size > MAX_FIXED_AREA_SIZE) + panic("fixed area size is larger than %dM\n", + MAX_FIXED_AREA_SIZE >> 20); + + reserve_info->fixed_area_size = fixed_area_size; + reserve_info->fixed_area_start = MSM8960_FW_START; + + ret = memblock_remove(reserve_info->fixed_area_start, + reserve_info->fixed_area_size); + BUG_ON(ret); +#endif +} + + +/** + * Reserve memory for ION and calculate amount of reusable memory for fmem. + * We only reserve memory for heaps that are not reusable. However, we only + * support one reusable heap at the moment so we ignore the reusable flag for + * other than the first heap with reusable flag set. Also handle special case + * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be + * at a higher address than FW in addition to not more than 256MB away from the + * base address of the firmware. This means that if MM is reusable the other + * two heaps must be allocated in the same region as FW. This is handled by the + * mem_is_fmem flag in the platform data. In addition the MM heap must be + * adjacent to the FW heap for content protection purposes. + */ +static void __init reserve_ion_memory(void) +{ +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + unsigned int i; + unsigned int reusable_count = 0; + unsigned int fixed_size = 0; + unsigned int fixed_low_size, fixed_middle_size, fixed_high_size; + unsigned long fixed_low_start, fixed_middle_start, fixed_high_start; + struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1]; + + adjust_mem_for_liquid(); + fmem_pdata.size = 0; + fmem_pdata.reserved_size_low = 0; + fmem_pdata.reserved_size_high = 0; + fmem_pdata.align = PAGE_SIZE; + fixed_low_size = 0; + fixed_middle_size = 0; + fixed_high_size = 0; + + /* We only support 1 reusable heap. Check if more than one heap + * is specified as reusable and set as non-reusable if found. + */ + for (i = 0; i < ion_pdata.nr; ++i) { + struct ion_platform_heap *heap = &(ion_pdata.heaps[i]); + + if ((int)heap->type == ION_HEAP_TYPE_CP && heap->extra_data) { + struct ion_cp_heap_pdata *data = heap->extra_data; + + reusable_count += (data->reusable) ? 1 : 0; + + if (data->reusable && reusable_count > 1) { + pr_err("%s: Too many heaps specified as " + "reusable. Heap %s was not configured " + "as reusable.\n", __func__, heap->name); + data->reusable = 0; + } + } + } + + for (i = 0; i < ion_pdata.nr; ++i) { + struct ion_platform_heap *heap = + &(ion_pdata.heaps[i]); + int align = SZ_4K; + int iommu_map_all = 0; + int adjacent_mem_id = INVALID_HEAP_ID; + + if (heap->extra_data) { + int fixed_position = NOT_FIXED; + int mem_is_fmem = 0; + + if (!strcmp(heap->name, "mm") + && (mb->start >= 0xc0000000)) { + printk(KERN_ERR "heap->name %s, mb->start %x\n", + heap->name, mb->start); + heap->size = MSM_PMEM_ADSP_SIZE_FOR_2GB; + } + + switch ((int)heap->type) { + case ION_HEAP_TYPE_CP: + mem_is_fmem = ((struct ion_cp_heap_pdata *) + heap->extra_data)->mem_is_fmem; + fixed_position = ((struct ion_cp_heap_pdata *) + heap->extra_data)->fixed_position; + align = ((struct ion_cp_heap_pdata *) + heap->extra_data)->align; + iommu_map_all = + ((struct ion_cp_heap_pdata *) + heap->extra_data)->iommu_map_all; + break; + case ION_HEAP_TYPE_CARVEOUT: + mem_is_fmem = ((struct ion_co_heap_pdata *) + heap->extra_data)->mem_is_fmem; + fixed_position = ((struct ion_co_heap_pdata *) + heap->extra_data)->fixed_position; + adjacent_mem_id = ((struct ion_co_heap_pdata *) + heap->extra_data)->adjacent_mem_id; + break; + default: + break; + } + + if (iommu_map_all) { + if (heap->size & (SZ_64K-1)) { + heap->size = ALIGN(heap->size, SZ_64K); + pr_info("Heap %s not aligned to 64K. Adjusting size to %x\n", + heap->name, heap->size); + } + } + + if (mem_is_fmem && adjacent_mem_id != INVALID_HEAP_ID) + fmem_pdata.align = align; + + if (fixed_position != NOT_FIXED) + fixed_size += heap->size; + else + reserve_mem_for_ion(MEMTYPE_EBI1, heap->size); + + if (fixed_position == FIXED_LOW) + fixed_low_size += heap->size; + else if (fixed_position == FIXED_MIDDLE) + fixed_middle_size += heap->size; + else if (fixed_position == FIXED_HIGH) + fixed_high_size += heap->size; + + if (mem_is_fmem) + fmem_pdata.size += heap->size; + } + } + + if (!fixed_size) + return; + + if (fmem_pdata.size) { + fmem_pdata.reserved_size_low = fixed_low_size; + fmem_pdata.reserved_size_high = fixed_high_size; + } + + msm8960_reserve_fixed_area(fixed_size + MSM_MM_FW_SIZE); + + fixed_low_start = MSM8960_FIXED_AREA_START; + fixed_middle_start = fixed_low_start + fixed_low_size; + fixed_high_start = fixed_middle_start + fixed_middle_size; + + for (i = 0; i < ion_pdata.nr; ++i) { + struct ion_platform_heap *heap = &(ion_pdata.heaps[i]); + + if (heap->extra_data) { + int fixed_position = NOT_FIXED; + + switch ((int)heap->type) { + case ION_HEAP_TYPE_CP: + fixed_position = ((struct ion_cp_heap_pdata *) + heap->extra_data)->fixed_position; + break; + case ION_HEAP_TYPE_CARVEOUT: + fixed_position = ((struct ion_co_heap_pdata *) + heap->extra_data)->fixed_position; + break; + default: + break; + } + + switch (fixed_position) { + case FIXED_LOW: + heap->base = fixed_low_start; + break; + case FIXED_MIDDLE: + heap->base = fixed_middle_start; + break; + case FIXED_HIGH: + heap->base = fixed_high_start; + break; + default: + break; + } + } + } +#endif +} + +static void ion_adjust_secure_allocation(void) +{ + int i; + + for (i = 0; i < ion_pdata.nr; i++) { + struct ion_platform_heap *heap = + &(ion_pdata.heaps[i]); + + + if (heap->extra_data) { + switch ((int) heap->type) { + case ION_HEAP_TYPE_CP: + if (cpu_is_msm8960()) { + ((struct ion_cp_heap_pdata *) + heap->extra_data)->no_nonsecure_alloc = + 0; + } + + } + } + } +} + +static void __init reserve_mdp_memory(void) +{ + msm8960_mdp_writeback(msm8960_reserve_table); +} + +#if defined(CONFIG_MSM_CACHE_DUMP) +static struct msm_cache_dump_platform_data msm_cache_dump_pdata = { + .l2_size = L2_BUFFER_SIZE, +}; + +static struct platform_device msm_cache_dump_device = { + .name = "msm_cache_dump", + .id = -1, + .dev = { + .platform_data = &msm_cache_dump_pdata, + }, +}; + +#endif + +static void reserve_cache_dump_memory(void) +{ +#ifdef CONFIG_MSM_CACHE_DUMP + unsigned int spare; + unsigned int l1_size; + unsigned int total; + int ret; + + ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_GET_SIZE_COMMAND_ID, &spare, + sizeof(spare), &l1_size, sizeof(l1_size)); + + if (ret) + /* Fall back to something reasonable here */ + l1_size = L1_BUFFER_SIZE; + + total = l1_size + L2_BUFFER_SIZE; + + msm8960_reserve_table[MEMTYPE_EBI1].size += total; + msm_cache_dump_pdata.l1_size = l1_size; +#endif +} + +static void __init msm8960_calculate_reserve_sizes(void) +{ + size_pmem_devices(); + reserve_pmem_memory(); + reserve_ion_memory(); + reserve_mdp_memory(); + reserve_rtb_memory(); + reserve_cache_dump_memory(); +} + +static struct reserve_info msm8960_reserve_info __initdata = { + .memtype_reserve_table = msm8960_reserve_table, + .calculate_reserve_sizes = msm8960_calculate_reserve_sizes, + .reserve_fixed_area = msm8960_reserve_fixed_area, + .paddr_to_memtype = msm8960_paddr_to_memtype, +}; + +static int msm8960_memory_bank_size(void) +{ + return 1<<29; +} + +static void __init locate_unstable_memory(void) +{ + struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1]; + unsigned long bank_size; + unsigned long low, high; + + bank_size = msm8960_memory_bank_size(); + low = meminfo.bank[0].start; + high = mb->start + mb->size; + + /* Check if 32 bit overflow occured */ + if (high < mb->start) { + high = ~0UL; + mb->size-= 1 << 12; + } + + low &= ~(bank_size - 1); + + if (high - low <= bank_size) + return; + + msm8960_reserve_info.bank_size = bank_size; +#ifdef CONFIG_ENABLE_DMM + msm8960_reserve_info.low_unstable_address = mb->start - + MIN_MEMORY_BLOCK_SIZE + mb->size; + msm8960_reserve_info.max_unstable_size = 0 /* MIN_MEMORY_BLOCK_SIZE */; + pr_info("low unstable address %lx max size %lx bank size %lx\n", + msm8960_reserve_info.low_unstable_address, + msm8960_reserve_info.max_unstable_size, + msm8960_reserve_info.bank_size); +#else + msm8960_reserve_info.low_unstable_address = 0; + msm8960_reserve_info.max_unstable_size = 0; +#endif +} + +static void __init place_movable_zone(void) +{ +#ifdef CONFIG_ENABLE_DMM + movable_reserved_start = msm8960_reserve_info.low_unstable_address; + movable_reserved_size = msm8960_reserve_info.max_unstable_size; + pr_info("movable zone start %lx size %lx\n", + movable_reserved_start, movable_reserved_size); +#endif +} + +static void __init msm8960_early_memory(void) +{ + reserve_info = &msm8960_reserve_info; + locate_unstable_memory(); + place_movable_zone(); +} + +static char prim_panel_name[PANEL_NAME_MAX_LEN]; +static char ext_panel_name[PANEL_NAME_MAX_LEN]; +static int __init prim_display_setup(char *param) +{ + if (strnlen(param, PANEL_NAME_MAX_LEN)) + strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN); + return 0; +} +early_param("prim_display", prim_display_setup); + +static int __init ext_display_setup(char *param) +{ + if (strnlen(param, PANEL_NAME_MAX_LEN)) + strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN); + return 0; +} +early_param("ext_display", ext_display_setup); + +/* Exclude the last 4 kB to preserve the kexec hardboot page. */ +#ifdef CONFIG_ANDROID_RAM_CONSOLE +#define RAM_CONSOLE_START 0x9fde0000 +#define RAM_CONSOLE_SIZE 0x20000 + +static struct platform_device ram_console_device = { + .name = "ram_console", + .id = -1, +}; + +struct persistent_ram_descriptor ram_console_desc = { + .name = "ram_console", + .size = RAM_CONSOLE_SIZE, +}; + +struct persistent_ram ram_console_ram = { + .start = RAM_CONSOLE_START, + .size = RAM_CONSOLE_SIZE, + .num_descs = 1, + .descs = &ram_console_desc, +}; +#endif + +unsigned int address = 0xea000000; +unsigned int size = 0x100000; + +static void __init msm8960_reserve(void) +{ + int ret; + msm8960_set_display_params(prim_panel_name, ext_panel_name); + msm_reserve(); + if (fmem_pdata.size) { +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + if (reserve_info->fixed_area_size) { + fmem_pdata.phys = + reserve_info->fixed_area_start + MSM_MM_FW_SIZE; + pr_info("mm fw at %lx (fixed) size %x\n", + reserve_info->fixed_area_start, MSM_MM_FW_SIZE); + pr_info("fmem start %lx (fixed) size %lx\n", + fmem_pdata.phys, + fmem_pdata.size); + } +#endif + } + + if (system_rev >= 16) { + pr_err("Reserving memory at address %x size: %x\n", address, size); + ret = memblock_remove(address, size); + BUG_ON(ret); + } + +#ifdef CONFIG_KEXEC_HARDBOOT + memblock_remove(KEXEC_HB_PAGE_ADDR, SZ_4K); +#endif +} + +static int msm8960_change_memory_power(u64 start, u64 size, + int change_type) +{ + return soc_change_memory_power(start, size, change_type); +} + +static void __init msm8960_allocate_memory_regions(void) +{ + msm8960_allocate_fb_region(); +#ifdef CONFIG_ANDROID_RAM_CONSOLE + persistent_ram_early_init(&ram_console_ram); +#endif + +} +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +static void cypress_power_onoff(int onoff) +{ + int ret, rc; + static struct regulator *reg_l29, *reg_l10; + + pr_debug("power on entry\n"); + + if (!reg_l29) { + reg_l29 = regulator_get(NULL, "8921_l29"); + ret = regulator_set_voltage(reg_l29, 1800000, 1800000); + + if (IS_ERR(reg_l29)) { + pr_err("could not get 8921_l29, rc = %ld\n", + PTR_ERR(reg_l29)); + return; + } + } + + if (!reg_l10) { + reg_l10 = regulator_get(NULL, "8921_l10"); + ret = regulator_set_voltage(reg_l10, 3000000, 3000000); + + if (IS_ERR(reg_l10)) { + pr_err("could not get 8921_l10, rc = %ld\n", + PTR_ERR(reg_l10)); + return; + } + } + + if (onoff) { + ret = regulator_enable(reg_l29); + rc = regulator_enable(reg_l10); + if (ret) { + pr_err("enable l29 failed, rc=%d\n", ret); + return; + } + if (rc) { + pr_err("enable l10 failed, rc=%d\n", ret); + return; + } + pr_info("cypress_power_on is finished.\n"); + } else { + ret = regulator_disable(reg_l29); + rc = regulator_disable(reg_l10); + if (ret) { + pr_err("disable l29 failed, rc=%d\n", ret); + return; + } + if (rc) { + pr_err("enable l29failed, rc=%d\n", ret); + return; + } + pr_info("cypress_power_off is finished.\n"); + } +} + +static u8 touchkey_keycode[] = {KEY_BACK, KEY_MENU}; + +static struct cypress_touchkey_platform_data cypress_touchkey_pdata = { + .gpio_int = GPIO_TOUCH_KEY_INT, + .touchkey_keycode = touchkey_keycode, + .power_onoff = cypress_power_onoff, +}; + +static struct i2c_board_info touchkey_i2c_devices_info[] __initdata = { + { + I2C_BOARD_INFO("cypress_touchkey", 0x20), + .platform_data = &cypress_touchkey_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_TOUCH_KEY_INT), + }, +}; + +static struct i2c_gpio_platform_data cypress_touchkey_i2c_gpio_data = { + .sda_pin = GPIO_TOUCHKEY_SDA, + .scl_pin = GPIO_TOUCHKEY_SCL, + .udelay = 0, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0, +}; + +static struct platform_device touchkey_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_TOUCHKEY_I2C_BUS_ID, + .dev.platform_data = &cypress_touchkey_i2c_gpio_data, +}; + +#endif + +#ifdef CONFIG_USB_SWITCH_FSA9485 +static enum cable_type_t set_cable_status; +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD +static void fsa9485_mhl_cb(bool attached, int mhl_charge) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_mhl_cb attached (%d), mhl_charge(%d)\n", + attached, mhl_charge); + + if (attached) { + switch (mhl_charge) { + case 0: + case 1: + set_cable_status = CABLE_TYPE_USB; + break; + case 2: + set_cable_status = CABLE_TYPE_AC; + break; + } + } else { + set_cable_status = CABLE_TYPE_NONE; + } + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_USB: + value.intval = POWER_SUPPLY_TYPE_USB; + break; + case CABLE_TYPE_AC: + value.intval = POWER_SUPPLY_TYPE_MAINS; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("%s: invalid cable :%d\n", __func__, set_cable_status); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} +#else +static void fsa9485_mhl_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_mhl_cb attached %d\n", attached); + set_cable_status = attached ? CABLE_TYPE_MISC : CABLE_TYPE_NONE; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_MISC: + value.intval = POWER_SUPPLY_TYPE_MISC; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("%s: invalid cable :%d\n", __func__, set_cable_status); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} +#endif +static void fsa9485_otg_cb(bool attached) +{ + pr_info("fsa9485_otg_cb attached %d\n", attached); + + if (attached) { + pr_info("%s set id state\n", __func__); +// msm_otg_set_id_state(attached); + } +} + +static void fsa9485_usb_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_usb_cb attached %d\n", attached); + set_cable_status = attached ? CABLE_TYPE_USB : CABLE_TYPE_NONE; + + if (system_rev >= 0x4) { +// if (attached) { + pr_info("%s set vbus state\n", __func__); + msm_otg_set_vbus_state(attached); +// } + } + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_USB: + value.intval = POWER_SUPPLY_TYPE_USB; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("%s: invalid cable :%d\n", __func__, set_cable_status); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} + +static void fsa9485_charger_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9480_charger_cb attached %d\n", attached); + set_cable_status = attached ? CABLE_TYPE_AC : CABLE_TYPE_NONE; + + msm_otg_set_charging_state(attached); + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + +#ifdef CONFIG_TOUCHSCREEN_MMS144 + if (charger_callbacks && charger_callbacks->inform_charger) + charger_callbacks->inform_charger(charger_callbacks, attached); +#endif + + switch (set_cable_status) { + case CABLE_TYPE_AC: + value.intval = POWER_SUPPLY_TYPE_MAINS; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} + +static void fsa9485_uart_cb(bool attached) +{ + pr_info("fsa9485_uart_cb attached %d\n", attached); + + set_cable_status = attached ? CABLE_TYPE_UARTOFF : CABLE_TYPE_NONE; +} + +static struct switch_dev switch_dock = { + .name = "dock", +}; + +static void fsa9485_jig_cb(bool attached) +{ + pr_info("fsa9485_jig_cb attached %d\n", attached); + + set_cable_status = attached ? CABLE_TYPE_JIG : CABLE_TYPE_NONE; +} + +static void fsa9485_dock_cb(int attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9480_dock_cb attached %d\n", attached); + switch_set_state(&switch_dock, attached); + + set_cable_status = attached ? CABLE_TYPE_CARDOCK : CABLE_TYPE_NONE; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_CARDOCK: + value.intval = POWER_SUPPLY_TYPE_CARDOCK; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} + +static void fsa9485_usb_cdp_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_usb_cdp_cb attached %d\n", attached); + + set_cable_status = + attached ? CABLE_TYPE_CDP : CABLE_TYPE_NONE; + + if (system_rev >= 0x4) { + if (attached) { + pr_info("%s set vbus state\n", __func__); + msm_otg_set_vbus_state(attached); + } + } + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_CDP: + value.intval = POWER_SUPPLY_TYPE_USB_CDP; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } + +} +static void fsa9485_smartdock_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_smartdock_cb attached %d\n", attached); + + set_cable_status = + attached ? CABLE_TYPE_SMART_DOCK : CABLE_TYPE_NONE; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_SMART_DOCK: + value.intval = POWER_SUPPLY_TYPE_USB_CDP; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } + +// msm_otg_set_smartdock_state(attached); +} + +static void fsa9485_audio_dock_cb(bool attached) +{ + pr_info("fsa9485_audio_dock_cb attached %d\n", attached); + +// msm_otg_set_smartdock_state(attached); +} + +static int fsa9485_dock_init(void) +{ + int ret; + + /* for CarDock, DeskDock */ + ret = switch_dev_register(&switch_dock); + if (ret < 0) { + pr_err("Failed to register dock switch. %d\n", ret); + return ret; + } + return 0; +} + +int msm8960_get_cable_type(void) +{ +#ifdef CONFIG_WIRELESS_CHARGING + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return -1; + } +#endif + + pr_info("cable type (%d) -----\n", set_cable_status); + + if (set_cable_status != CABLE_TYPE_NONE) { + switch (set_cable_status) { + case CABLE_TYPE_MISC: +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD + fsa9485_mhl_cb(1 , 0); +#else + fsa9485_mhl_cb(1); +#endif + break; + case CABLE_TYPE_USB: + fsa9485_usb_cb(1); + break; + case CABLE_TYPE_AC: + fsa9485_charger_cb(1); + break; +#ifdef CONFIG_WIRELESS_CHARGING + case CABLE_TYPE_WPC: + value.intval = POWER_SUPPLY_TYPE_WPC; + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + break; +#endif + default: + pr_err("invalid status:%d\n", set_cable_status); + break; + } + } + return set_cable_status; +} + +static struct i2c_gpio_platform_data fsa_i2c_gpio_data = { + .sda_pin = GPIO_USB_I2C_SDA, + .scl_pin = GPIO_USB_I2C_SCL, + .udelay = 2, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0, +}; + +static struct platform_device fsa_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_FSA9485_I2C_BUS_ID, + .dev.platform_data = &fsa_i2c_gpio_data, +}; + +static struct fsa9485_platform_data fsa9485_pdata = { + .otg_cb = fsa9485_otg_cb, + .usb_cb = fsa9485_usb_cb, + .charger_cb = fsa9485_charger_cb, + .uart_cb = fsa9485_uart_cb, + .jig_cb = fsa9485_jig_cb, + .dock_cb = fsa9485_dock_cb, + .dock_init = fsa9485_dock_init, + .usb_cdp_cb = fsa9485_usb_cdp_cb, + .smartdock_cb = fsa9485_smartdock_cb, + .audio_dock_cb = fsa9485_audio_dock_cb, +}; + +static struct i2c_board_info micro_usb_i2c_devices_info[] __initdata = { + { + I2C_BOARD_INFO("fsa9485", 0x4A >> 1), + .platform_data = &fsa9485_pdata, + .irq = MSM_GPIO_TO_INT(14), + }, +}; + +#endif + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + +static void msm8960_mhl_gpio_init(void) +{ + int ret; + + ret = gpio_request(GPIO_MHL_EN, "mhl_en"); + if (ret < 0) { + pr_err("mhl_en gpio_request is failed\n"); + return; + } + + ret = gpio_request(GPIO_MHL_RST, "mhl_rst"); + if (ret < 0) { + pr_err("mhl_rst gpio_request is failed\n"); + return; + } + +} + +static void mhl_gpio_config(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_RST, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); +} + +static struct i2c_gpio_platform_data mhl_i2c_gpio_data = { + .sda_pin = GPIO_MHL_SDA, + .scl_pin = GPIO_MHL_SCL, + .udelay = 3,/*(i2c clk speed: 500khz / udelay)*/ +}; + +static struct platform_device mhl_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_MHL_I2C_BUS_ID, + .dev = { + .platform_data = &mhl_i2c_gpio_data, + }, +}; +/* +gpio_interrupt pin is very changable each different h/w_rev or board. +*/ +int get_mhl_int_irq(void) +{ + return MSM_GPIO_TO_INT(GPIO_MHL_INT); +} + +static struct regulator *mhl_l12; + +static void sii9234_hw_onoff(bool onoff) +{ + int rc; + /*VPH_PWR : mhl_power_source + VMHL_3.3V, VSIL_A_1.2V, VMHL_1.8V + just power control with HDMI_EN pin or control Regulator12*/ + if (onoff) { + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + mhl_l12 = regulator_get(NULL, "8921_l12"); + rc = regulator_set_voltage(mhl_l12, 1200000, 1200000); + if (rc) + pr_err("error setting voltage\n"); + rc = regulator_enable(mhl_l12); + if (rc) + pr_err("error enabling regulator\n"); + usleep(1*1000); + gpio_direction_output(GPIO_MHL_EN, 1); + } else { + gpio_direction_output(GPIO_MHL_EN, 0); + if (mhl_l12) { + rc = regulator_disable(mhl_l12); + if (rc) + pr_err("error disabling regulator\n"); + } + + usleep_range(10000, 20000); + + if (gpio_direction_output(GPIO_MHL_RST, 0)) + pr_err("%s error in making GPIO_MHL_RST Low\n" + , __func__); + + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + } + + return; +} + +static void sii9234_hw_reset(void) +{ + usleep_range(10000, 20000); + if (gpio_direction_output(GPIO_MHL_RST, 1)) + printk(KERN_ERR "%s error in making GPIO_MHL_RST HIGH\n", + __func__); + + usleep_range(5000, 20000); + if (gpio_direction_output(GPIO_MHL_RST, 0)) + printk(KERN_ERR "%s error in making GPIO_MHL_RST Low\n", + __func__); + + usleep_range(10000, 20000); + if (gpio_direction_output(GPIO_MHL_RST, 1)) + printk(KERN_ERR "%s error in making GPIO_MHL_RST HIGH\n", + __func__); + msleep(30); +} + +struct sii9234_platform_data sii9234_pdata = { + .get_irq = get_mhl_int_irq, + .hw_onoff = sii9234_hw_onoff, + .hw_reset = sii9234_hw_reset, + .gpio_cfg = mhl_gpio_config, + .swing_level = 0xEB, +#if defined(CONFIG_VIDEO_MHL_V2) + .vbus_present = fsa9485_mhl_cb, +#endif +}; + +static struct i2c_board_info mhl_i2c_board_info[] = { + { + I2C_BOARD_INFO("sii9234_mhl_tx", 0x72>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_tpi", 0x7A>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_hdmi_rx", 0x92>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_cbus", 0xC8>>1), + .platform_data = &sii9234_pdata, + }, +}; +#endif + +#ifdef CONFIG_BATTERY_SEC +static int is_sec_battery_using(void) +{ + if (system_rev >= 0x4) + return 1; + else + return 0; +} + +int check_battery_type(void) +{ + return BATT_TYPE_D2_ACTIVE; +} + +static struct sec_bat_platform_data sec_bat_pdata = { + .fuel_gauge_name = "fuelgauge", + .charger_name = "sec-charger", + .get_cable_type = msm8960_get_cable_type, + .sec_battery_using = is_sec_battery_using, + .check_batt_type = check_battery_type, + .iterm = 150, + .charge_duration = 6 * 60 * 60, + .wpc_charge_duration = 8 * 60 * 60, + .recharge_duration = 1.5 * 60 * 60, + .max_voltage = 4350 * 1000, + .recharge_voltage = 4280 * 1000, + .event_block = 600, + .high_block = 500, + .high_recovery = 450, + .low_block = -50, + .low_recovery = 0, + .lpm_high_block = 480, + .lpm_high_recovery = 450, + .lpm_low_block = -50, + .lpm_low_recovery = 0, + .wpc_charging_current = 500, +}; + +static struct platform_device sec_device_battery = { + .name = "sec-battery", + .id = -1, + .dev.platform_data = &sec_bat_pdata, +}; + +static void check_highblock_temp(void) +{ + if (system_rev < 0x6) + sec_bat_pdata.high_block = 600; +} + +#endif /* CONFIG_BATTERY_SEC */ + +static int is_smb347_using(void) +{ + if (system_rev >= 0x4) + return 1; + else + return 0; +} + +#ifdef CONFIG_CHARGER_SMB347 +static int is_smb347_inok_using(void) +{ + if (system_rev >= 0x6) + return 1; + + return 0; +} + +#ifdef CONFIG_WIRELESS_CHARGING +static void smb347_wireless_cb(void) +{ + set_cable_status = CABLE_TYPE_WPC; +} +#endif + +void smb347_hw_init(void) +{ + struct pm_gpio batt_int_param = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .function = PM_GPIO_FUNC_NORMAL, + }; + int rc = 0; + + gpio_tlmm_config(GPIO_CFG(GPIO_INOK_INT, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + + rc = gpio_request(GPIO_INOK_INT, "wpc-detect"); + if (rc < 0) { + pr_err("%s: GPIO_INOK_INT gpio_request failed\n", __func__); + return; + } + rc = gpio_direction_input(GPIO_INOK_INT); + if (rc < 0) { + pr_err("%s: GPIO_INOK_INT gpio_direction_input failed\n", + __func__); + return; + } + + if (system_rev >= 0xd) { + sec_bat_pdata.batt_int = + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT); + pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT), + &batt_int_param); + gpio_request( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT), + "batt_int"); + gpio_direction_input(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT)); + } + pr_debug("%s : share gpioi2c with max17048\n", __func__); +} + +static int smb347_intr_trigger(int status) +{ + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + + if (!psy) { + pr_err("%s: fail to get battery ps\n", __func__); + return -ENODEV; + } + pr_info("%s : charging status =%d\n", __func__, status); + + value.intval = status; + + /*if (status) + value.intval = POWER_SUPPLY_STATUS_CHARGING; + else + value.intval = POWER_SUPPLY_STATUS_DISCHARGING;*/ + + return psy->set_property(psy, POWER_SUPPLY_PROP_STATUS, &value); +} + +static struct smb347_platform_data smb347_pdata = { + .hw_init = smb347_hw_init, + .chg_intr_trigger = smb347_intr_trigger, + .enable = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + .stat = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_CHG_STAT), + .smb347_using = is_smb347_using, + .inok = GPIO_INOK_INT, + .smb347_inok_using = is_smb347_inok_using, +#ifdef CONFIG_WIRELESS_CHARGING + .smb347_wpc_cb = smb347_wireless_cb, +#endif + .smb347_get_cable = msm8960_get_cable_type, +}; +#endif /* CONFIG_CHARGER_SMB347 */ + +#ifdef CONFIG_BATTERY_MAX17040 +void max17040_hw_init(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_FUEKGAUGE_I2C_SCL, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_FUELGAUGE_I2C_SDA, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_set_value(GPIO_FUEKGAUGE_I2C_SCL, 1); + gpio_set_value(GPIO_FUELGAUGE_I2C_SDA, 1); + + gpio_tlmm_config(GPIO_CFG(GPIO_FUEL_INT, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); +} + +static int max17040_low_batt_cb(void) +{ +#ifdef CONFIG_BATTERY_SEC + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + pr_err("%s: Low battery alert\n", __func__); + + + if (!psy) { + pr_err("%s: fail to get battery ps\n", __func__); + return -ENODEV; + } + + value.intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + return psy->set_property(psy, POWER_SUPPLY_PROP_CAPACITY_LEVEL, &value); +#else + pr_err("%s: Low battery alert\n", __func__); + + return 0; +#endif +} + +static struct max17040_platform_data max17043_pdata = { + .hw_init = max17040_hw_init, + .low_batt_cb = max17040_low_batt_cb, + .check_batt_type = check_battery_type, + .rcomp_value = 0x6d1c, +}; + +static struct i2c_gpio_platform_data fuelgauge_i2c_gpio_data = { + .sda_pin = GPIO_FUELGAUGE_I2C_SDA, + .scl_pin = GPIO_FUEKGAUGE_I2C_SCL, + .udelay = 2, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0, +}; + +static struct platform_device fuelgauge_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_FUELGAUGE_I2C_BUS_ID, + .dev.platform_data = &fuelgauge_i2c_gpio_data, +}; + +static struct i2c_board_info fg_i2c_board_info[] = { + { + I2C_BOARD_INFO("max17040", (0x6D >> 1)), + .platform_data = &max17043_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_FUEL_INT), + } +}; + +static struct i2c_board_info fg_smb_i2c_board_info[] = { +#ifdef CONFIG_CHARGER_SMB347 + { + I2C_BOARD_INFO("smb347", (0x0C >> 1)), + .platform_data = &smb347_pdata, + .irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_CHG_STAT), + }, +#endif + { + I2C_BOARD_INFO("max17040", (0x6D >> 1)), + .platform_data = &max17043_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_FUEL_INT), + } +}; +#endif /* CONFIG_BATTERY_MAX17040 */ + +#ifdef CONFIG_VIBETONZ +static struct vibrator_platform_data msm_8960_vibrator_pdata = { + .vib_model = HAPTIC_PWM, + .vib_pwm_gpio = GPIO_VIB_PWM, + .haptic_pwr_en_gpio = GPIO_HAPTIC_PWR_EN, + .vib_en_gpio = GPIO_VIB_ON, + .is_pmic_vib_en = 0, + .is_pmic_haptic_pwr_en = 0, +}; +static struct platform_device vibetonz_device = { + .name = "tspdrv", + .id = -1, + .dev = { + .platform_data = &msm_8960_vibrator_pdata , + }, +}; +#endif /* CONFIG_VIBETONZ */ + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) +static struct i2c_gpio_platform_data opt_i2c_gpio_data = { + .sda_pin = GPIO_SENSOR_ALS_SDA, + .scl_pin = GPIO_SENSOR_ALS_SCL, + .udelay = 5, +}; + +static struct platform_device opt_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_OPT_I2C_BUS_ID, + .dev = { + .platform_data = &opt_i2c_gpio_data, + }, +}; +#if defined(CONFIG_SENSORS_CM36651) +static void cm36651_led_onoff(int); + +static struct cm36651_platform_data cm36651_pdata = { + .cm36651_led_on = cm36651_led_onoff, + .cm36651_power_on = cm36651_power_on, + .irq = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_RGB_INT), + .threshold = 15, +}; +#endif +static struct i2c_board_info opt_i2c_borad_info[] = { + { +#if defined(CONFIG_OPTICAL_GP2A) + I2C_BOARD_INFO("gp2a", 0x88>>1), +#elif defined(CONFIG_OPTICAL_GP2AP020A00F) + I2C_BOARD_INFO("gp2a", 0x72>>1), +#endif + }, +#if defined(CONFIG_SENSORS_CM36651) + { + I2C_BOARD_INFO("cm36651", (0x30 >> 1)), + .platform_data = &cm36651_pdata, + }, +#endif +}; +#if 0 +static void gp2a_led_onoff(int); + +#if defined(CONFIG_OPTICAL_GP2A) +static struct opt_gp2a_platform_data opt_gp2a_data = { + .gp2a_led_on = gp2a_led_onoff, + .power_on = sensor_power_on_vdd, + .irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_RGB_INT), + .ps_status = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_RGB_INT), +}; +#elif defined(CONFIG_OPTICAL_GP2AP020A00F) +static struct gp2a_platform_data opt_gp2a_data = { + .gp2a_led_on = gp2a_led_onoff, + .power_on = gp2a_power_on, + .p_out = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_RGB_INT), + .adapt_num = MSM_OPT_I2C_BUS_ID, + .addr = 0x72>>1, + .version = 0, +}; +#endif + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) +static struct platform_device opt_gp2a = { + .name = "gp2a-opt", + .id = -1, + .dev = { + .platform_data = &opt_gp2a_data, + }, +}; +#endif +#endif +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 + struct mpu_platform_data mpu6050_data = { + .int_config = 0x10, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {0, 1, 0, + -1, 0, 0, + 0, 0, 1}, + }; + + static struct ext_slave_platform_data inv_mpu_ak8963_data_03 = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {-1, 0, 0, + 0, 1, 0, + 0, 0, -1}, + }; + + struct mpu_platform_data mpu6050_data_01 = { + .int_config = 0x10, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data_01 = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {0, 1, 0, + -1, 0, 0, + 0, 0, 1}, + }; + struct mpu_platform_data mpu6050_data_00 = { + .int_config = 0x10, + .orientation = {0, -1, 0, + -1, 0, 0, + 0, 0, -1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data_00 = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }; +#endif + +#ifdef CONFIG_MPU_SENSORS_MPU6050B1 +#define SENSOR_MPU_NAME "mpu6050B1" +static struct mpu_platform_data mpu_data = { + .int_config = 0x12, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + /* accel */ + .accel = { + .get_slave_descr = mantis_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x68, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + }, + /* compass */ + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = {0, 1, 0, + -1, 0, 0, + 0, 0, 1}, + }, + .poweron = mpu_power_on, +}; + +static struct mpu_platform_data mpu_data_01 = { + .int_config = 0x12, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + /* accel */ + .accel = { + .get_slave_descr = mantis_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x68, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + }, + /* compass */ + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = {0, 1, 0, + -1, 0, 0, + 0, 0, 1}, + }, + .poweron = mpu_power_on, +}; + +static struct mpu_platform_data mpu_data_00 = { + .int_config = 0x12, + .orientation = {0, -1, 0, + -1, 0, 0, + 0, 0, -1}, + /* accel */ + .accel = { + .get_slave_descr = mantis_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x68, + .orientation = {0, -1, 0, + -1, 0, 0, + 0, 0, -1}, + }, + /* compass */ + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }, + .poweron = mpu_power_on, +}; +#endif /*CONFIG_MPU_SENSORS_MPU6050B1 */ + +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + +#ifdef CONFIG_SENSORS_AK8975 +static struct akm8975_platform_data akm8975_pdata = { + .gpio_data_ready_int = GPIO_MSENSE_RST, + .power_on = akm_power_on, +}; +#endif +#ifdef CONFIG_INPUT_BMP180 +static struct bmp_i2c_platform_data bmp180_pdata = { + .power_on = bmp180_power_on, +}; +#endif + +static struct i2c_board_info sns_i2c_borad_info[] = { +#ifdef CONFIG_MPU_SENSORS_MPU6050B1 + { + I2C_BOARD_INFO(SENSOR_MPU_NAME, 0x68), + .irq = MSM_GPIO_TO_INT(GPIO_MPU3050_INT), + .platform_data = &mpu_data, + }, +#endif +#ifdef CONFIG_SENSORS_AK8975 + { + I2C_BOARD_INFO("ak8975", 0x0C), + .platform_data = &akm8975_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_MSENSE_RST), + }, +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 + { + I2C_BOARD_INFO("mpu6050", 0x68), + .irq = MSM_GPIO_TO_INT(GPIO_MPU3050_INT), + .platform_data = &mpu6050_data, + }, +#endif +#ifdef CONFIG_MPU_SENSORS_AK8975_411 + { + I2C_BOARD_INFO("ak8975_mod", 0x0C), + .platform_data = &inv_mpu_ak8963_data, + .irq = MSM_GPIO_TO_INT(GPIO_MSENSE_RST), + }, +#endif +#ifdef CONFIG_INPUT_BMP180 + { + I2C_BOARD_INFO("bmp180", 0x77), + .platform_data = &bmp180_pdata, + }, +#endif + +}; +#endif + +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static void mpl_init(void) +{ + int ret = 0; + ret = gpio_request(GPIO_MPU3050_INT, "MPUIRQ"); + if (ret) + pr_err("%s gpio request %d err\n", __func__, GPIO_MPU3050_INT); + else + gpio_direction_input(GPIO_MPU3050_INT); + +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) + if (system_rev == BOARD_REV01) + mpu_data = mpu_data_01; + else if (system_rev < BOARD_REV01) + mpu_data = mpu_data_00; + mpu_data.reset = gpio_rev(GPIO_MAG_RST); +#elif defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + if (system_rev == BOARD_REV01) { + mpu6050_data = mpu6050_data_01; + inv_mpu_ak8963_data = inv_mpu_ak8963_data_01; + } else if (system_rev < BOARD_REV01) { + mpu6050_data = mpu6050_data_00; + inv_mpu_ak8963_data = inv_mpu_ak8963_data_00; + } + if (system_rev < BOARD_REV08 || system_rev == BOARD_REV11) + mpu6050_data.reset = gpio_rev(GPIO_MAG_RST); + else + mpu6050_data.reset = + PM8921_GPIO_PM_TO_SYS(gpio_rev(GPIO_MAG_RST)); +#endif +} +#endif + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) +static void opt_init(void) +{ + int ret = 0; + int prox_int = gpio_rev(ALS_INT); + struct pm_gpio prox_cfg = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + }; + + if (system_rev < BOARD_REV08 || system_rev == BOARD_REV11) { + gpio_tlmm_config(GPIO_CFG(prox_int, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + } else { + prox_int = PM8921_GPIO_PM_TO_SYS(prox_int); + pm8xxx_gpio_config(prox_int, &prox_cfg); + } + + gpio_tlmm_config(GPIO_CFG(gpio_rev(ALS_SDA), 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(gpio_rev(ALS_SCL), 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + ret = gpio_request(prox_int, "PSVOUT"); + if (ret) { + pr_err("%s gpio request %d err\n", __func__, prox_int); + } else { + gpio_direction_input(prox_int); + gpio_free(prox_int); + } +} +#endif + +struct class *sec_class; +EXPORT_SYMBOL(sec_class); + +static void samsung_sys_class_init(void) +{ + pr_info("samsung sys class init.\n"); + + sec_class = class_create(THIS_MODULE, "sec"); + + if (IS_ERR(sec_class)) { + pr_err("Failed to create class(sec)!\n"); + return; + } + + pr_info("samsung sys class end.\n"); +}; + +#if defined(CONFIG_NFC_PN544) +static void pn544_conf_gpio(void) +{ + pr_debug("pn544_conf_gpio\n"); + + gpio_tlmm_config(GPIO_CFG(GPIO_NFC_SDA, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_NFC_SCL, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + return; +} + +static int __init pn544_init(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_NFC_IRQ, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + pn544_conf_gpio(); + return 0; +} +#endif + +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) ||\ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + +static int __init sensor_device_init(void) +{ + int ret = 0; + int mag_rst = gpio_rev(GPIO_MAG_RST); + struct pm_gpio mag_rst_cfg = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .disable_pin = 0, + }; + + if (system_rev < BOARD_REV08 || system_rev == BOARD_REV11) { + gpio_tlmm_config(GPIO_CFG(mag_rst, 0, + GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + } else { + mag_rst = PM8921_GPIO_PM_TO_SYS(mag_rst); + pm8xxx_gpio_config(mag_rst, &mag_rst_cfg); + } + sensor_power_on_vdd(SNS_PWR_ON, SNS_PWR_ON); + ret = gpio_request(mag_rst, "MAG_RST"); + if (ret) { + pr_err("%s gpio request %d err\n", __func__, mag_rst); + } else { + gpio_direction_output(mag_rst, 0); + usleep_range(20, 20); + gpio_set_value_cansleep(mag_rst, 1); + } + + return 0; +} +#endif + +#if defined(CONFIG_SENSORS_AK8975) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_INPUT_BMP180) || defined(CONFIG_OPTICAL_GP2A) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static struct regulator *vsensor_2p85, *vsensor_1p8; +static int sensor_power_2p85_cnt, sensor_power_1p8_cnt; + +static void sensor_power_on_vdd(int onoff_l9, int onoff_lvs4) +{ + int ret; + + if (vsensor_2p85 == NULL) { + vsensor_2p85 = regulator_get(NULL, "8921_l9"); + if (IS_ERR(vsensor_2p85)) + return ; + + ret = regulator_set_voltage(vsensor_2p85, 2850000, 2850000); + if (ret) + pr_err("%s: error vsensor_2p85 setting voltage ret=%d\n", + __func__, ret); + } + if (vsensor_1p8 == NULL) { + vsensor_1p8 = regulator_get(NULL, "8921_lvs4"); + if (IS_ERR(vsensor_1p8)) + return ; + } + + if (onoff_l9 == SNS_PWR_ON) { + sensor_power_2p85_cnt++; + ret = regulator_enable(vsensor_2p85); + if (ret) + pr_err("%s: error enabling regulator\n", __func__); + } else if ((onoff_l9 == SNS_PWR_OFF)) { + sensor_power_2p85_cnt--; + if (regulator_is_enabled(vsensor_2p85)) { + ret = regulator_disable(vsensor_2p85); + if (ret) + pr_err("%s: error vsensor_2p85 enabling regulator\n", + __func__); + } + } + if (onoff_lvs4 == SNS_PWR_ON) { + sensor_power_1p8_cnt++; + ret = regulator_enable(vsensor_1p8); + if (ret) + pr_err("%s: error enabling regulator\n", __func__); + } else if ((onoff_lvs4 == SNS_PWR_OFF)) { + sensor_power_1p8_cnt--; + if (regulator_is_enabled(vsensor_1p8)) { + ret = regulator_disable(vsensor_1p8); + if (ret) + pr_err("%s: error vsensor_1p8 enabling regulator\n", + __func__); + } + } +} + +#endif +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static void mpu_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#ifdef CONFIG_SENSORS_AK8975 +static void akm_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#ifdef CONFIG_INPUT_BMP180 +static void bmp180_power_on(int onoff) +{ + sensor_power_on_vdd(SNS_PWR_KEEP, onoff); +} +#endif + +#if defined(CONFIG_OPTICAL_GP2AP020A00F) +static void gp2a_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#if defined(CONFIG_SENSORS_CM36651) +static void cm36651_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) +static void gp2a_led_onoff(int onoff) +{ + static struct regulator *reg_8921_leda; + static int prev_on; + int rc; + + if (onoff == prev_on) + return; + + if (!reg_8921_leda) { + reg_8921_leda = regulator_get(NULL, "8921_l16"); + rc = regulator_set_voltage(reg_8921_leda, + 3000000, 3000000); + if (rc) + pr_err("%s: error reg_8921_leda setting ret=%d\n", + __func__, rc); + } + + if (onoff) { + rc = regulator_enable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator enable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(on): success\n", __func__); + } else { + rc = regulator_disable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator disable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(off): success\n", __func__); + } + prev_on = onoff; +} +#endif + +#if defined(CONFIG_SENSORS_CM36651) + +static void cm36651_led_onoff(int onoff) +{ + static struct regulator *reg_8921_leda; + static int prev_on; + int rc; + + if (onoff == prev_on) + return; + + if (!reg_8921_leda) { + reg_8921_leda = regulator_get(NULL, "8921_l16"); + rc = regulator_set_voltage(reg_8921_leda, + 2800000, 2800000); + if (rc) + pr_err("%s: error reg_8921_leda setting ret=%d\n", + __func__, rc); + return; + } + + if (onoff) { + rc = regulator_enable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator enable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(on): success\n", __func__); + } else { + rc = regulator_disable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator disable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(off): success\n", __func__); + } + prev_on = onoff; +} +#endif + +#ifdef CONFIG_VP_A2220 +static int a2220_hw_init(void) +{ + int rc = 0; + + rc = gpio_request(gpio_rev(A2220_WAKEUP), "a2220_wakeup"); + if (rc < 0) { + pr_err("%s: gpio request wakeup pin failed\n", __func__); + goto err_alloc_data_failed; + } + + rc = gpio_direction_output(gpio_rev(A2220_WAKEUP), 1); + if (rc < 0) { + pr_err("%s: request wakeup gpio direction failed\n", __func__); + goto err_free_gpio; + } + + rc = gpio_request(MSM_AUD_A2220_RESET, "a2220_reset"); + if (rc < 0) { + pr_err("%s: gpio request reset pin failed\n", __func__); + goto err_free_gpio; + } + + rc = gpio_direction_output(MSM_AUD_A2220_RESET, 1); + if (rc < 0) { + pr_err("%s: request reset gpio direction failed\n", __func__); + goto err_free_gpio_all; + } + gpio_set_value(gpio_rev(A2220_WAKEUP), 1); + gpio_set_value(MSM_AUD_A2220_RESET, 1); + return rc; + +err_free_gpio_all: + gpio_free(MSM_AUD_A2220_RESET); +err_free_gpio: + gpio_free(gpio_rev(A2220_WAKEUP)); +err_alloc_data_failed: + pr_err("a2220_probe - failed\n"); + return rc; +} + +static struct a2220_platform_data a2220_data = { + .a2220_hw_init = a2220_hw_init, + .gpio_reset = MSM_AUD_A2220_RESET, +}; + +static struct i2c_board_info a2220_device[] __initdata = { + { + I2C_BOARD_INFO("audience_a2220", 0x3E), + .platform_data = &a2220_data, + }, +}; + +static struct i2c_gpio_platform_data a2220_i2c_gpio_data = { + .udelay = 1, +}; +#if 0 +static struct platform_device a2220_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_A2220_I2C_BUS_ID, + .dev.platform_data = &a2220_i2c_gpio_data, +}; +#endif +static struct gpiomux_setting a2220_gsbi_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_a2220_configs[] = { + { + .settings = { + [GPIOMUX_SUSPENDED] = &a2220_gsbi_config, + }, + }, + { + .settings = { + [GPIOMUX_SUSPENDED] = &a2220_gsbi_config, + }, + }, +}; +#endif +#ifdef CONFIG_WCD9310_CODEC + +#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS) + +/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement + * 4 micbiases are used to power various analog and digital + * microphones operating at 1800 mV. Technically, all micbiases + * can source from single cfilter since all microphones operate + * at the same voltage level. The arrangement below is to make + * sure all cfilters are exercised. LDO_H regulator ouput level + * does not need to be as high as 2.85V. It is choosen for + * microphone sensitivity purpose. + */ +#ifndef CONFIG_SLIMBUS_MSM_CTRL +static struct wcd9xxx_pdata tabla_i2c_platform_data = { + .irq = MSM_GPIO_TO_INT(58), + .irq_base = TABLA_INTERRUPT_BASE, + .num_irqs = NR_TABLA_IRQS, + .reset_gpio = PM8921_GPIO_PM_TO_SYS(38), + .micbias = { + .ldoh_v = TABLA_LDOH_2P85_V, + .cfilt1_mv = 1800, + .cfilt2_mv = 2700, + .cfilt3_mv = 1800, + .bias1_cfilt_sel = TABLA_CFILT1_SEL, + .bias2_cfilt_sel = TABLA_CFILT2_SEL, + .bias3_cfilt_sel = TABLA_CFILT3_SEL, + .bias4_cfilt_sel = TABLA_CFILT3_SEL, + }, + .regulator = { + { + .name = "CDC_VDD_CP", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX, + }, + { + .name = "CDC_VDDA_RX", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX, + }, + { + .name = "CDC_VDDA_TX", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX, + }, + { + .name = "VDDIO_CDC", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX, + }, + { + .name = "VDDD_CDC_D", + .min_uV = 1225000, + .max_uV = 1225000, + .optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX, + }, + { + .name = "CDC_VDDA_A_1P2V", + .min_uV = 1225000, + .max_uV = 1225000, + .optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX, + }, + }, +}; +#endif +#endif +#define MSM_WCNSS_PHYS 0x03000000 +#define MSM_WCNSS_SIZE 0x280000 + +static struct resource resources_wcnss_wlan[] = { + { + .start = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ, + .end = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ, + .name = "wcnss_wlanrx_irq", + .flags = IORESOURCE_IRQ, + }, + { + .start = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ, + .end = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ, + .name = "wcnss_wlantx_irq", + .flags = IORESOURCE_IRQ, + }, + { + .start = MSM_WCNSS_PHYS, + .end = MSM_WCNSS_PHYS + MSM_WCNSS_SIZE - 1, + .name = "wcnss_mmio", + .flags = IORESOURCE_MEM, + }, + { + .start = 84, + .end = 88, + .name = "wcnss_gpios_5wire", + .flags = IORESOURCE_IO, + }, +}; + +static struct qcom_wcnss_opts qcom_wcnss_pdata = { + .has_48mhz_xo = 1, +}; + +static struct platform_device msm_device_wcnss_wlan = { + .name = "wcnss_wlan", + .id = 0, + .num_resources = ARRAY_SIZE(resources_wcnss_wlan), + .resource = resources_wcnss_wlan, + .dev = {.platform_data = &qcom_wcnss_pdata}, +}; + +#ifdef CONFIG_QSEECOM +/* qseecom bus scaling */ +static struct msm_bus_vectors qseecom_clks_init_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = 0, + .ab = 0, + }, +}; + +static struct msm_bus_vectors qseecom_enable_dfab_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = 0, + .ab = 0, + }, +}; + +static struct msm_bus_vectors qseecom_enable_sfpb_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = (64 * 8) * 1000000UL, + .ab = (64 * 8) * 100000UL, + }, +}; + +static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = (64 * 8) * 1000000UL, + .ab = (64 * 8) * 100000UL, + }, +}; + +static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = { + { + ARRAY_SIZE(qseecom_clks_init_vectors), + qseecom_clks_init_vectors, + }, + { + ARRAY_SIZE(qseecom_enable_dfab_vectors), + qseecom_enable_dfab_vectors, + }, + { + ARRAY_SIZE(qseecom_enable_sfpb_vectors), + qseecom_enable_sfpb_vectors, + }, + { + ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors), + qseecom_enable_dfab_sfpb_vectors, + }, +}; + +static struct msm_bus_scale_pdata qseecom_bus_pdata = { + qseecom_hw_bus_scale_usecases, + ARRAY_SIZE(qseecom_hw_bus_scale_usecases), + .name = "qsee", +}; + +static struct platform_device qseecom_device = { + .name = "qseecom", + .id = 0, + .dev = { + .platform_data = &qseecom_bus_pdata, + }, +}; +#endif +#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \ + defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE) + +#define QCE_SIZE 0x10000 +#define QCE_0_BASE 0x18500000 + +#define QCE_HW_KEY_SUPPORT 0 +#define QCE_SHA_HMAC_SUPPORT 1 +#define QCE_SHARE_CE_RESOURCE 1 +#define QCE_CE_SHARED 0 + +/* Begin Bus scaling definitions */ +static struct msm_bus_vectors crypto_hw_init_vectors[] = { + { + .src = MSM_BUS_MASTER_ADM_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, + { + .src = MSM_BUS_MASTER_ADM_PORT1, + .dst = MSM_BUS_SLAVE_GSBI1_UART, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors crypto_hw_active_vectors[] = { + { + .src = MSM_BUS_MASTER_ADM_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 70000000UL, + .ib = 70000000UL, + }, + { + .src = MSM_BUS_MASTER_ADM_PORT1, + .dst = MSM_BUS_SLAVE_GSBI1_UART, + .ab = 2480000000UL, + .ib = 2480000000UL, + }, +}; + +static struct msm_bus_paths crypto_hw_bus_scale_usecases[] = { + { + ARRAY_SIZE(crypto_hw_init_vectors), + crypto_hw_init_vectors, + }, + { + ARRAY_SIZE(crypto_hw_active_vectors), + crypto_hw_active_vectors, + }, +}; + +static struct msm_bus_scale_pdata crypto_hw_bus_scale_pdata = { + crypto_hw_bus_scale_usecases, + ARRAY_SIZE(crypto_hw_bus_scale_usecases), + .name = "cryptohw", +}; +/* End Bus Scaling Definitions*/ + +static struct resource qcrypto_resources[] = { + [0] = { + .start = QCE_0_BASE, + .end = QCE_0_BASE + QCE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "crypto_channels", + .start = DMOV_CE_IN_CHAN, + .end = DMOV_CE_OUT_CHAN, + .flags = IORESOURCE_DMA, + }, + [2] = { + .name = "crypto_crci_in", + .start = DMOV_CE_IN_CRCI, + .end = DMOV_CE_IN_CRCI, + .flags = IORESOURCE_DMA, + }, + [3] = { + .name = "crypto_crci_out", + .start = DMOV_CE_OUT_CRCI, + .end = DMOV_CE_OUT_CRCI, + .flags = IORESOURCE_DMA, + }, +}; + +static struct resource qcedev_resources[] = { + [0] = { + .start = QCE_0_BASE, + .end = QCE_0_BASE + QCE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "crypto_channels", + .start = DMOV_CE_IN_CHAN, + .end = DMOV_CE_OUT_CHAN, + .flags = IORESOURCE_DMA, + }, + [2] = { + .name = "crypto_crci_in", + .start = DMOV_CE_IN_CRCI, + .end = DMOV_CE_IN_CRCI, + .flags = IORESOURCE_DMA, + }, + [3] = { + .name = "crypto_crci_out", + .start = DMOV_CE_OUT_CRCI, + .end = DMOV_CE_OUT_CRCI, + .flags = IORESOURCE_DMA, + }, +}; + +#endif + +#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \ + defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) + +static struct msm_ce_hw_support qcrypto_ce_hw_suppport = { + .ce_shared = QCE_CE_SHARED, + .shared_ce_resource = QCE_SHARE_CE_RESOURCE, + .hw_key_support = QCE_HW_KEY_SUPPORT, + .sha_hmac = QCE_SHA_HMAC_SUPPORT, + .bus_scale_table = &crypto_hw_bus_scale_pdata, +}; + +static struct platform_device qcrypto_device = { + .name = "qcrypto", + .id = 0, + .num_resources = ARRAY_SIZE(qcrypto_resources), + .resource = qcrypto_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &qcrypto_ce_hw_suppport, + }, +}; +#endif + +#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE) + +static struct msm_ce_hw_support qcedev_ce_hw_suppport = { + .ce_shared = QCE_CE_SHARED, + .shared_ce_resource = QCE_SHARE_CE_RESOURCE, + .hw_key_support = QCE_HW_KEY_SUPPORT, + .sha_hmac = QCE_SHA_HMAC_SUPPORT, + .bus_scale_table = &crypto_hw_bus_scale_pdata, +}; + +static struct platform_device qcedev_device = { + .name = "qce", + .id = 0, + .num_resources = ARRAY_SIZE(qcedev_resources), + .resource = qcedev_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &qcedev_ce_hw_suppport, + }, +}; +#endif + +#define MDM2AP_ERRFATAL 70 +#define AP2MDM_ERRFATAL 95 +#define MDM2AP_STATUS 69 +#define AP2MDM_STATUS 94 +#define AP2MDM_PMIC_RESET_N 80 +#define AP2MDM_KPDPWR_N 81 + +static struct resource mdm_resources[] = { + { + .start = MDM2AP_ERRFATAL, + .end = MDM2AP_ERRFATAL, + .name = "MDM2AP_ERRFATAL", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_ERRFATAL, + .end = AP2MDM_ERRFATAL, + .name = "AP2MDM_ERRFATAL", + .flags = IORESOURCE_IO, + }, + { + .start = MDM2AP_STATUS, + .end = MDM2AP_STATUS, + .name = "MDM2AP_STATUS", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_STATUS, + .end = AP2MDM_STATUS, + .name = "AP2MDM_STATUS", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_PMIC_RESET_N, + .end = AP2MDM_PMIC_RESET_N, + .name = "AP2MDM_PMIC_RESET_N", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_KPDPWR_N, + .end = AP2MDM_KPDPWR_N, + .name = "AP2MDM_KPDPWR_N", + .flags = IORESOURCE_IO, + }, +}; + +static struct mdm_platform_data mdm_platform_data = { + .mdm_version = "2.5", +}; + +static struct platform_device mdm_device = { + .name = "mdm2_modem", + .id = -1, + .num_resources = ARRAY_SIZE(mdm_resources), + .resource = mdm_resources, + .dev = { + .platform_data = &mdm_platform_data, + }, +}; + +static struct platform_device *mdm_devices[] __initdata = { + &mdm_device, +}; + +#define MSM_SHARED_RAM_PHYS 0x80000000 + +static void __init msm8960_map_io(void) +{ + msm_shared_ram_phys = MSM_SHARED_RAM_PHYS; + msm_map_msm8960_io(); + + if (socinfo_init() < 0) + pr_err("socinfo_init() failed!\n"); +#ifdef CONFIG_SEC_DEBUG + sec_getlog_supply_meminfo(0x40000000, 0x80000000, 0x00, 0x00); +#endif + +} + +static void __init msm8960_init_irq(void) +{ + struct msm_mpm_device_data *data = NULL; + +#ifdef CONFIG_MSM_MPM + data = &msm8960_mpm_dev_data; +#endif + + msm_mpm_irq_extn_init(data); + gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, + (void *)MSM_QGIC_CPU_BASE); +} + +static void __init msm8960_init_buses(void) +{ +#ifdef CONFIG_MSM_BUS_SCALING + msm_bus_rpm_set_mt_mask(); + msm_bus_8960_apps_fabric_pdata.rpm_enabled = 1; + msm_bus_8960_sys_fabric_pdata.rpm_enabled = 1; + msm_bus_8960_mm_fabric_pdata.rpm_enabled = 1; + msm_bus_apps_fabric.dev.platform_data = + &msm_bus_8960_apps_fabric_pdata; + msm_bus_sys_fabric.dev.platform_data = &msm_bus_8960_sys_fabric_pdata; + msm_bus_mm_fabric.dev.platform_data = &msm_bus_8960_mm_fabric_pdata; + msm_bus_sys_fpb.dev.platform_data = &msm_bus_8960_sys_fpb_pdata; + msm_bus_cpss_fpb.dev.platform_data = &msm_bus_8960_cpss_fpb_pdata; +#endif +} + +#ifdef CONFIG_S5C73M3 +static struct msm_spi_platform_data msm8960_qup_spi_gsbi11_pdata = { + .max_clock_speed = 48000000, /*15060000,*/ +}; +#endif + +#ifdef CONFIG_USB_MSM_OTG_72K +static struct msm_otg_platform_data msm_otg_pdata; +#else +static bool vbus_is_on; +static void msm_hsusb_vbus_power_max8627(bool on) +{ + int rc; + static struct regulator *mvs_otg_switch; + struct pm_gpio param = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 1, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + }; + + pr_info("%s, attached %d, vbus_is_on %d\n", __func__, on, vbus_is_on); + + if (vbus_is_on == on) + return; + + if (on) { + mvs_otg_switch = regulator_get(&msm8960_device_otg.dev, + "vbus_otg"); + if (IS_ERR(mvs_otg_switch)) { + pr_err("Unable to get mvs_otg_switch\n"); + return; + } + + rc = gpio_request(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + "usb_5v_en"); + if (rc < 0) { + pr_err("failed to request usb_5v_en gpio\n"); + goto put_mvs_otg; + } + + if (regulator_enable(mvs_otg_switch)) { + pr_err("unable to enable mvs_otg_switch\n"); + goto free_usb_5v_en; + } + + rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + ¶m); + if (rc < 0) { + pr_err("failed to configure usb_5v_en gpio\n"); + goto disable_mvs_otg; + } + vbus_is_on = true; + return; + } else { + gpio_set_value_cansleep(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + 0); +#ifdef CONFIG_USB_SWITCH_FSA9485 + fsa9485_otg_detach(); +#endif + } + +disable_mvs_otg: + regulator_disable(mvs_otg_switch); +free_usb_5v_en: + gpio_free(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN)); +put_mvs_otg: + regulator_put(mvs_otg_switch); + vbus_is_on = false; +} + +#ifdef CONFIG_CHARGER_SMB347 +static void msm_hsusb_vbus_power_smb347s(bool on) +{ + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + int ret = 0; + + pr_info("%s, attached %d, vbus_is_on %d\n", __func__, on, vbus_is_on); + + /* If VBUS is already on (or off), do nothing. */ + if (vbus_is_on == on) + return; + + if (on) + value.intval = POWER_SUPPLY_CAPACITY_OTG_ENABLE; + else + value.intval = POWER_SUPPLY_CAPACITY_OTG_DISABLE; + + if (psy) { + ret = psy->set_property(psy, POWER_SUPPLY_PROP_OTG, &value); + if (ret) { + pr_err("%s: fail to set power_suppy otg property(%d)\n", + __func__, ret); + } +#ifdef CONFIG_USB_SWITCH_FSA9485 + if (!on) + fsa9485_otg_detach(); +#endif + vbus_is_on = on; + } else { + pr_err("%s : psy is null!\n", __func__); + } +} +#endif + +static int msm_hsusb_vbus_power(bool on) +{ + if (system_rev < BOARD_REV04) + msm_hsusb_vbus_power_max8627(on); +#ifdef CONFIG_CHARGER_SMB347 + else + msm_hsusb_vbus_power_smb347s(on); +#endif + return 0; +} + +static int phy_settings[] = { + 0x44, 0x80, + 0x7F, 0x81, + 0x3C, 0x82, + 0x13, 0x83, + -1, +}; + +static int wr_phy_init_seq[] = { + 0x44, 0x80, /* set VBUS valid threshold + and disconnect valid threshold */ + 0x38, 0x81, /* update DC voltage level */ + 0x14, 0x82, /* set preemphasis and rise/fall time */ + 0x13, 0x83, /* set source impedance adjusment */ + -1}; + +static int liquid_v1_phy_init_seq[] = { + 0x44, 0x80,/* set VBUS valid threshold + and disconnect valid threshold */ + 0x3C, 0x81,/* update DC voltage level */ + 0x18, 0x82,/* set preemphasis and rise/fall time */ + 0x23, 0x83,/* set source impedance sdjusment */ + -1}; + +#ifdef CONFIG_MSM_BUS_SCALING +/* Bandwidth requests (zero) if no vote placed */ +static struct msm_bus_vectors usb_init_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +/* Bus bandwidth requests in Bytes/sec */ +static struct msm_bus_vectors usb_max_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 60000000, /* At least 480Mbps on bus. */ + .ib = 960000000, /* MAX bursts rate */ + }, +}; + +static struct msm_bus_paths usb_bus_scale_usecases[] = { + { + ARRAY_SIZE(usb_init_vectors), + usb_init_vectors, + }, + { + ARRAY_SIZE(usb_max_vectors), + usb_max_vectors, + }, +}; + +static struct msm_bus_scale_pdata usb_bus_scale_pdata = { + usb_bus_scale_usecases, + ARRAY_SIZE(usb_bus_scale_usecases), + .name = "usb", +}; +#endif + +static struct msm_otg_platform_data msm_otg_pdata = { + .mode = USB_OTG, + .otg_control = OTG_PMIC_CONTROL, + .phy_type = SNPS_28NM_INTEGRATED_PHY, + .pmic_id_irq = PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE), + .vbus_power = msm_hsusb_vbus_power, + .power_budget = 750, + .phy_init_seq = phy_settings, + .smb347s = true, +#ifdef CONFIG_MSM_BUS_SCALING + .bus_scale_table = &usb_bus_scale_pdata, +#endif +}; + +#ifdef CONFIG_USB_HOST_NOTIFY +static void __init msm_otg_power_init(void) +{ + if (system_rev >= BOARD_REV02) { + msm_otg_pdata.otg_power_gpio = + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_POWER); + msm_otg_pdata.otg_power_irq = + PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_OTG_POWER); + } + if (system_rev >= BOARD_REV04) + msm_otg_pdata.smb347s = true; + else + msm_otg_pdata.smb347s = false; +} +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC +#define HSIC_HUB_RESET_GPIO 91 +static struct msm_hsic_host_platform_data msm_hsic_pdata = { + .strobe = 150, + .data = 151, +}; +#else +static struct msm_hsic_host_platform_data msm_hsic_pdata; +#endif + +#define PID_MAGIC_ID 0x71432909 +#define SERIAL_NUM_MAGIC_ID 0x61945374 +#define SERIAL_NUMBER_LENGTH 127 +#define DLOAD_USB_BASE_ADD 0x2A03F0C8 + +struct magic_num_struct { + uint32_t pid; + uint32_t serial_num; +}; + +struct dload_struct { + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint16_t reserved4; + uint16_t pid; + char serial_number[SERIAL_NUMBER_LENGTH]; + uint16_t reserved5; + struct magic_num_struct magic_struct; +}; + +static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum) +{ + struct dload_struct __iomem *dload = 0; + + dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload)); + if (!dload) { + pr_err("%s: cannot remap I/O memory region: %08x\n", + __func__, DLOAD_USB_BASE_ADD); + return -ENXIO; + } + + pr_debug("%s: dload:%p pid:%x serial_num:%s\n", + __func__, dload, pid, snum); + /* update pid */ + dload->magic_struct.pid = PID_MAGIC_ID; + dload->pid = pid; + + /* update serial number */ + dload->magic_struct.serial_num = 0; + if (!snum) { + memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH); + goto out; + } + + dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID; + strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH); +out: + iounmap(dload); + return 0; +} + +static struct android_usb_platform_data android_usb_pdata = { + .update_pid_and_serial_num = usb_diag_update_pid_and_serial_num, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; + +static uint8_t spm_wfi_cmd_sequence[] __initdata = { + 0x03, 0x0f, +}; + +static uint8_t spm_retention_cmd_sequence[] __initdata = { + 0x00, 0x05, 0x03, 0x0D, + 0x0B, 0x00, 0x0f, +}; + +static uint8_t spm_power_collapse_without_rpm[] __initdata = { + 0x00, 0x24, 0x54, 0x10, + 0x09, 0x03, 0x01, + 0x10, 0x54, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +static uint8_t spm_power_collapse_with_rpm[] __initdata = { + 0x00, 0x24, 0x54, 0x10, + 0x09, 0x07, 0x01, 0x0B, + 0x10, 0x54, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +/* 8960AB has a different command to assert apc_pdn */ +static uint8_t spm_power_collapse_without_rpm_krait_v3[] __initdata = { + 0x00, 0x24, 0x84, 0x10, + 0x09, 0x03, 0x01, + 0x10, 0x84, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +static uint8_t spm_power_collapse_with_rpm_krait_v3[] __initdata = { + 0x00, 0x24, 0x84, 0x10, + 0x09, 0x07, 0x01, 0x0B, + 0x10, 0x84, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +static struct msm_spm_seq_entry msm_spm_boot_cpu_seq_list[] __initdata = { + [0] = { + .mode = MSM_SPM_MODE_CLOCK_GATING, + .notify_rpm = false, + .cmd = spm_wfi_cmd_sequence, + }, + [1] = { + .mode = MSM_SPM_MODE_POWER_RETENTION, + .notify_rpm = false, + .cmd = spm_retention_cmd_sequence, + }, + [2] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = false, + .cmd = spm_power_collapse_without_rpm, + }, + [3] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = true, + .cmd = spm_power_collapse_with_rpm, + }, +}; + +static struct msm_spm_seq_entry msm_spm_nonboot_cpu_seq_list[] __initdata = { + [0] = { + .mode = MSM_SPM_MODE_CLOCK_GATING, + .notify_rpm = false, + .cmd = spm_wfi_cmd_sequence, + }, + [1] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = false, + .cmd = spm_power_collapse_without_rpm, + }, + [2] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = true, + .cmd = spm_power_collapse_with_rpm, + }, +}; + +static struct msm_spm_platform_data msm_spm_data[] __initdata = { + [0] = { + .reg_base_addr = MSM_SAW0_BASE, + .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F, +#if defined(CONFIG_MSM_AVS_HW) + .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464, + .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000, +#endif + .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0084009C, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A4001C, + .vctl_timeout_us = 50, + .num_modes = ARRAY_SIZE(msm_spm_boot_cpu_seq_list), + .modes = msm_spm_boot_cpu_seq_list, + }, + [1] = { + .reg_base_addr = MSM_SAW1_BASE, + .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F, +#if defined(CONFIG_MSM_AVS_HW) + .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464, + .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000, +#endif + .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C, + .vctl_timeout_us = 50, + .num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list), + .modes = msm_spm_nonboot_cpu_seq_list, + }, +}; + +static uint8_t l2_spm_wfi_cmd_sequence[] __initdata = { + 0x00, 0x20, 0x03, 0x20, + 0x00, 0x0f, +}; + +static uint8_t l2_spm_gdhs_cmd_sequence[] __initdata = { + 0x00, 0x20, 0x34, 0x64, + 0x48, 0x07, 0x48, 0x20, + 0x50, 0x64, 0x04, 0x34, + 0x50, 0x0f, +}; +static uint8_t l2_spm_power_off_cmd_sequence[] __initdata = { + 0x00, 0x10, 0x34, 0x64, + 0x48, 0x07, 0x48, 0x10, + 0x50, 0x64, 0x04, 0x34, + 0x50, 0x0F, +}; + +static struct msm_spm_seq_entry msm_spm_l2_seq_list[] __initdata = { + [0] = { + .mode = MSM_SPM_L2_MODE_RETENTION, + .notify_rpm = false, + .cmd = l2_spm_wfi_cmd_sequence, + }, + [1] = { + .mode = MSM_SPM_L2_MODE_GDHS, + .notify_rpm = true, + .cmd = l2_spm_gdhs_cmd_sequence, + }, + [2] = { + .mode = MSM_SPM_L2_MODE_POWER_COLLAPSE, + .notify_rpm = true, + .cmd = l2_spm_power_off_cmd_sequence, + }, +}; + +static struct msm_spm_platform_data msm_spm_l2_data[] __initdata = { + [0] = { + .reg_base_addr = MSM_SAW_L2_BASE, + .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020, + .modes = msm_spm_l2_seq_list, + .num_modes = ARRAY_SIZE(msm_spm_l2_seq_list), + }, +}; + +#define PM_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33) +#define PM_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20) + +static struct msm_xo_voter *xo_handle_d1; + +static int isa1200_power(int on) +{ + int rc = 0; + + gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on); + + rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) : + msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF); + if (rc < 0) { + pr_err("%s: failed to %svote for TCXO D1 buffer%d\n", + __func__, on ? "" : "de-", rc); + goto err_xo_vote; + } + + return 0; + +err_xo_vote: + gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on); + return rc; +} + +static int isa1200_dev_setup(bool enable) +{ + int rc = 0; + + struct pm_gpio hap_gpio_config = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .vin_sel = 2, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + }; + + if (enable == true) { + rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config); + if (rc) { + pr_err("%s: pm8921 gpio %d config failed(%d)\n", + __func__, PM_HAP_EN_GPIO, rc); + return rc; + } + + rc = pm8xxx_gpio_config(PM_HAP_LEN_GPIO, &hap_gpio_config); + if (rc) { + pr_err("%s: pm8921 gpio %d config failed(%d)\n", + __func__, PM_HAP_LEN_GPIO, rc); + return rc; + } + + rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe"); + if (rc) { + pr_err("%s: unable to request gpio %d (%d)\n", + __func__, HAP_SHIFT_LVL_OE_GPIO, rc); + return rc; + } + + rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0); + if (rc) { + pr_err("%s: Unable to set direction\n", __func__); + goto free_gpio; + } + + xo_handle_d1 = msm_xo_get(MSM_XO_TCXO_D1, "isa1200"); + if (IS_ERR(xo_handle_d1)) { + rc = PTR_ERR(xo_handle_d1); + pr_err("%s: failed to get the handle for D1(%d)\n", + __func__, rc); + goto gpio_set_dir; + } + } else { + gpio_free(HAP_SHIFT_LVL_OE_GPIO); + + msm_xo_put(xo_handle_d1); + } + + return 0; + +gpio_set_dir: + gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0); +free_gpio: + gpio_free(HAP_SHIFT_LVL_OE_GPIO); + return rc; +} + +static struct isa1200_regulator isa1200_reg_data[] = { + { + .name = "vcc_i2c", + .min_uV = ISA_I2C_VTG_MIN_UV, + .max_uV = ISA_I2C_VTG_MAX_UV, + .load_uA = ISA_I2C_CURR_UA, + }, +}; + +static struct isa1200_platform_data isa1200_1_pdata = { + .name = "vibrator", + .dev_setup = isa1200_dev_setup, + .power_on = isa1200_power, + .hap_en_gpio = PM_HAP_EN_GPIO, + .hap_len_gpio = PM_HAP_LEN_GPIO, + .max_timeout = 15000, + .mode_ctrl = PWM_GEN_MODE, + .pwm_fd = { + .pwm_div = 256, + }, + .is_erm = false, + .smart_en = true, + .ext_clk_en = true, + .chip_en = 1, + .regulator_info = isa1200_reg_data, + .num_regulators = ARRAY_SIZE(isa1200_reg_data), +}; + +static struct i2c_board_info msm_isa1200_board_info[] __initdata = { + { + I2C_BOARD_INFO("isa1200_1", 0x90>>1), + .platform_data = &isa1200_1_pdata, + }, +}; + +#ifdef CONFIG_NFC_PN544 +static struct i2c_gpio_platform_data pn544_i2c_gpio_data = { + .sda_pin = GPIO_NFC_SDA, + .scl_pin = GPIO_NFC_SCL, + .udelay = 5, +}; + +static struct platform_device pn544_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_NFC_I2C_BUS_ID, + .dev = { + .platform_data = &pn544_i2c_gpio_data, + }, +}; + +static struct pn544_i2c_platform_data pn544_pdata = { + .conf_gpio = pn544_conf_gpio, + .irq_gpio = GPIO_NFC_IRQ, + .ven_gpio = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_NFC_EN), + .firm_gpio = GPIO_NFC_FIRMWARE, +}; + +static struct i2c_board_info pn544_info[] __initdata = { + { + I2C_BOARD_INFO("pn544", 0x2b), + .irq = MSM_GPIO_TO_INT(GPIO_NFC_IRQ), + .platform_data = &pn544_pdata, + }, +}; +#endif /* CONFIG_NFC_PN544 */ + +/* configuration data */ +static const u8 mxt_config_data[] = { + /* T6 Object */ + 0, 0, 0, 0, 0, 0, + /* T38 Object */ + 11, 2, 0, 11, 11, 11, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + /* T7 Object */ + 100, 16, 50, + /* T8 Object */ + 8, 0, 0, 0, 0, 0, 8, 14, 50, 215, + /* T9 Object */ + 131, 0, 0, 26, 42, 0, 32, 63, 3, 5, + 0, 2, 1, 113, 10, 10, 8, 10, 255, 2, + 85, 5, 0, 0, 20, 20, 75, 25, 202, 29, + 10, 10, 45, 46, + /* T15 Object */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + /* T18 Object */ + 0, 0, + /* T22 Object */ + 5, 0, 0, 0, 0, 0, 0, 0, 30, 0, + 0, 0, 5, 8, 10, 13, 0, + /* T24 Object */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* T25 Object */ + 3, 0, 188, 52, 52, 33, 0, 0, 0, 0, + 0, 0, 0, 0, + /* T27 Object */ + 0, 0, 0, 0, 0, 0, 0, + /* T28 Object */ + 0, 0, 0, 8, 12, 60, + /* T40 Object */ + 0, 0, 0, 0, 0, + /* T41 Object */ + 0, 0, 0, 0, 0, 0, + /* T43 Object */ + 0, 0, 0, 0, 0, 0, +}; + +static void mxt_init_hw_liquid(void) +{ + int rc; + + rc = gpio_request(GPIO_MXT_TS_IRQ, "mxt_ts_irq_gpio"); + if (rc) { + pr_err("%s: unable to request mxt_ts_irq gpio [%d]\n", + __func__, GPIO_MXT_TS_IRQ); + return; + } + + rc = gpio_direction_input(GPIO_MXT_TS_IRQ); + if (rc) { + pr_err("%s: unable to set_direction for mxt_ts_irq gpio [%d]\n", + __func__, GPIO_MXT_TS_IRQ); + goto err_irq_gpio_req; + } + + rc = gpio_request(GPIO_MXT_TS_LDO_EN, "mxt_ldo_en_gpio"); + if (rc) { + pr_err("%s: unable to request mxt_ldo_en gpio [%d]\n", + __func__, GPIO_MXT_TS_LDO_EN); + goto err_irq_gpio_req; + } + + rc = gpio_direction_output(GPIO_MXT_TS_LDO_EN, 1); + if (rc) { + pr_err("%s: unable to set_direction for mxt_ldo_en gpio [%d]\n", + __func__, GPIO_MXT_TS_LDO_EN); + goto err_ldo_gpio_req; + } +#if !defined(CONFIG_WIRELESS_CHARGING) + rc = gpio_request(GPIO_MXT_TS_RESET, "mxt_reset_gpio"); + if (rc) { + pr_err("%s: unable to request mxt_reset gpio [%d]\n", + __func__, GPIO_MXT_TS_RESET); + goto err_ldo_gpio_set_dir; + } + + rc = gpio_direction_output(GPIO_MXT_TS_RESET, 1); + if (rc) { + pr_err("%s: unable to set_direction for mxt_reset gpio [%d]\n", + __func__, GPIO_MXT_TS_RESET); + goto err_reset_gpio_req; + } +#endif + return; + +err_ldo_gpio_req: + gpio_free(GPIO_MXT_TS_LDO_EN); +err_irq_gpio_req: + gpio_free(GPIO_MXT_TS_IRQ); +} +#if 0 +static struct mxt_platform_data mxt_platform_data = { + .config = mxt_config_data, + .config_length = ARRAY_SIZE(mxt_config_data), + .irqflags = IRQF_TRIGGER_FALLING, + .x_size = 1365, + .y_size = 767, + .i2c_pull_up = true, +}; + +static struct i2c_board_info mxt_device_info[] __initdata = { + { + I2C_BOARD_INFO("atmel_mxt_ts", 0x5b), + .platform_data = &mxt_platform_data, + .irq = MSM_GPIO_TO_INT(GPIO_MXT_TS_IRQ), + }, +}; +#endif +#ifndef CONFIG_SLIMBUS_MSM_CTRL +#define TABLA_I2C_SLAVE_ADDR 0x0d +#define TABLA_ANALOG_I2C_SLAVE_ADDR 0x77 +#define TABLA_DIGITAL1_I2C_SLAVE_ADDR 0x66 +#define TABLA_DIGITAL2_I2C_SLAVE_ADDR 0x55 + +static struct i2c_board_info tabla_device_info[] __initdata = { + { + I2C_BOARD_INFO("tabla top level", TABLA_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, + { + I2C_BOARD_INFO("tabla analog", TABLA_ANALOG_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, + { + I2C_BOARD_INFO("tabla digital1", TABLA_DIGITAL1_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, + { + I2C_BOARD_INFO("tabla digital2", TABLA_DIGITAL2_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, +}; +#endif +static struct i2c_board_info sii_device_info[] __initdata = { + { + I2C_BOARD_INFO("Sil-9244", 0x39), + .flags = I2C_CLIENT_WAKE, + .irq = MSM_GPIO_TO_INT(15), + }, +}; + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = { + .clk_freq = 400000, + .src_clk_rate = 24000000, +}; + +#ifndef CONFIG_SLIMBUS_MSM_CTRL +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi1_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; +#endif + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi7_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; +#ifdef CONFIG_VP_A2220 +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi8_pdata = { + .clk_freq = 400000, + .src_clk_rate = 24000000, +}; +#endif +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = { + .clk_freq = 400000, + .src_clk_rate = 24000000, +}; +#if 0 +static struct msm_rpm_platform_data msm_rpm_data = { + .reg_base_addrs = { + [MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE, + [MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400, + [MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600, + [MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00, + }, + + .irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ, + .irq_err = RPM_APCC_CPU0_GP_LOW_IRQ, + .irq_vmpm = RPM_APCC_CPU0_GP_MEDIUM_IRQ, + .msm_apps_ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008, + .msm_apps_ipc_rpm_val = 4, +}; +#endif + +#if 0 +static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = { + .base_addr = MSM_ACC0_BASE + 0x08, + .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE, + .mask = 1UL << 13, +}; +#endif + +#ifndef CONFIG_S5C73M3 +static struct ks8851_pdata spi_eth_pdata = { + .irq_gpio = KS8851_IRQ_GPIO, + .rst_gpio = KS8851_RST_GPIO, +}; + +static struct spi_board_info spi_board_info[] __initdata = { + { + .modalias = "ks8851", + .irq = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO), + .max_speed_hz = 19200000, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_0, + .platform_data = &spi_eth_pdata + }, + { + .modalias = "dsi_novatek_3d_panel_spi", + .max_speed_hz = 10800000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_0, + }, +}; +#endif +static struct platform_device msm_device_saw_core0 = { + .name = "saw-regulator", + .id = 0, + .dev = { + .platform_data = &msm_saw_regulator_pdata_s5, + }, +}; + +static struct platform_device msm_device_saw_core1 = { + .name = "saw-regulator", + .id = 1, + .dev = { + .platform_data = &msm_saw_regulator_pdata_s6, + }, +}; + +static struct tsens_platform_data msm_tsens_pdata = { + .slope = {910, 910, 910, 910, 910}, + .tsens_factor = 1000, + .hw_type = MSM_8960, + .tsens_num_sensor = 5, +}; + +static struct platform_device msm_tsens_device = { + .name = "tsens8960-tm", + .id = -1, +}; + +static struct msm_thermal_data msm_thermal_pdata = { + .sensor_id = 0, + .poll_ms = 250, + .limit_temp_degC = 60, + .temp_hysteresis_degC = 10, + .freq_step = 2, +}; + +/* Bluetooth */ +#ifdef CONFIG_BT_BCM4334 +static struct platform_device bcm4334_bluetooth_device = { + .name = "bcm4334_bluetooth", + .id = -1, +}; +#endif + +#ifdef CONFIG_MSM_FAKE_BATTERY +static struct platform_device fish_battery_device = { + .name = "fish_battery", +}; +#endif + +static struct platform_device msm8960_device_ext_5v_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = PM8921_MPP_PM_TO_SYS(7), + .dev = { + .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V], + }, +}; +#if 0 +static struct platform_device msm8960_device_ext_l2_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = 91, + .dev = { + .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2], + }, +}; +#endif +static struct platform_device msm8960_device_ext_3p3v_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = PM8921_GPIO_PM_TO_SYS(17), + .dev = { + .platform_data = + &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_3P3V], + }, +}; +#ifdef CONFIG_KEYBOARD_GPIO +static struct gpio_keys_button gpio_keys_button[] = { + { + .code = KEY_VOLUMEUP, + .type = EV_KEY, + .gpio = -1, + .active_low = 1, + .wakeup = 0, + .debounce_interval = 5, /* ms */ + .desc = "Vol Up", + }, + { + .code = KEY_VOLUMEDOWN, + .type = EV_KEY, + .gpio = -1, + .active_low = 1, + .wakeup = 0, + .debounce_interval = 5, /* ms */ + .desc = "Vol Down", + }, + { + .code = KEY_HOMEPAGE, + .type = EV_KEY, + .gpio = -1, + .active_low = 1, + .wakeup = 1, + .debounce_interval = 5, /* ms */ + .desc = "Home", + }, +}; +static struct gpio_keys_platform_data gpio_keys_platform_data = { + .buttons = gpio_keys_button, + .nbuttons = ARRAY_SIZE(gpio_keys_button), + .rep = 0, +}; + +static struct platform_device msm8960_gpio_keys_device = { + .name = "sec_keys", + .id = -1, + .dev = { + .platform_data = &gpio_keys_platform_data, + } +}; +#endif + +static struct platform_device msm8960_device_ext_otg_sw_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = PM8921_GPIO_PM_TO_SYS(42), + .dev = { + .platform_data = + &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_OTG_SW], + }, +}; + +static struct platform_device msm8960_device_rpm_regulator __devinitdata = { + .name = "rpm-regulator", + .id = -1, + .dev = { + .platform_data = &msm_rpm_regulator_pdata, + }, +}; + +static struct msm_rpm_log_platform_data msm_rpm_log_pdata = { + .phys_addr_base = 0x0010C000, + .reg_offsets = { + [MSM_RPM_LOG_PAGE_INDICES] = 0x00000080, + [MSM_RPM_LOG_PAGE_BUFFER] = 0x000000A0, + }, + .phys_size = SZ_8K, + .log_len = 4096, /* log's buffer length in bytes */ + .log_len_mask = (4096 >> 2) - 1, /* length mask in units of u32 */ +}; + +static struct platform_device msm_rpm_log_device = { + .name = "msm_rpm_log", + .id = -1, + .dev = { + .platform_data = &msm_rpm_log_pdata, + }, +}; + +#ifdef CONFIG_SAMSUNG_JACK +#define PMIC_GPIO_EAR_DET 36 +#define PMIC_GPIO_SHORT_SENDEND 32 +#define PMIC_GPIO_EAR_MICBIAS_EN 3 + +static struct sec_jack_zone jack_zones[] = { + [0] = { + .adc_high = 3, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_3POLE, + }, + [1] = { + .adc_high = 630, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_3POLE, + }, + [2] = { + .adc_high = 1720, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_4POLE, + }, + [3] = { + .adc_high = 9999, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_4POLE, + }, +}; + +/* To support 3-buttons earjack */ +static struct sec_jack_buttons_zone jack_buttons_zones[] = { + { + .code = KEY_MEDIA, + .adc_low = 0, + .adc_high = 93, + }, + { + .code = KEY_VOLUMEUP, + .adc_low = 94, + .adc_high = 217, + }, + { + .code = KEY_VOLUMEDOWN, + .adc_low = 218, + .adc_high = 450, + }, +}; + +static int get_sec_det_jack_state(void) +{ + return (gpio_get_value_cansleep( + PM8921_GPIO_PM_TO_SYS( + PMIC_GPIO_EAR_DET))) ^ 1; +} + +static int get_sec_send_key_state(void) +{ + struct pm_gpio ear_micbiase = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .vin_sel = PM_GPIO_VIN_S4, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + }; + + if (get_sec_det_jack_state()) { + pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + &ear_micbiase); + gpio_set_value_cansleep( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + 1); + } + return (gpio_get_value_cansleep( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_SHORT_SENDEND))) ^ 1; + + return 0; +} + +static void set_sec_micbias_state(bool state) +{ + pr_info("sec_jack: ear micbias %s\n", state ? "on" : "off"); + gpio_set_value_cansleep( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + state); +} + +static int sec_jack_get_adc_value(void) +{ + int rc = 0; + int retVal = 0; + struct pm8xxx_adc_chan_result result; + + rc = pm8xxx_adc_mpp_config_read( + PM8XXX_AMUX_MPP_3, + ADC_MPP_1_AMUX6_SCALE_DEFAULT, + &result); + if (rc) { + pr_err("%s : error reading mpp %d, rc = %d\n", + __func__, PM8XXX_AMUX_MPP_3, rc); + return rc; + } + retVal = ((int)result.physical)/1000; + return retVal; +} + +static struct sec_jack_platform_data sec_jack_data = { + .get_det_jack_state = get_sec_det_jack_state, + .get_send_key_state = get_sec_send_key_state, + .set_micbias_state = set_sec_micbias_state, + .get_adc_value = sec_jack_get_adc_value, + .zones = jack_zones, + .num_zones = ARRAY_SIZE(jack_zones), + .buttons_zones = jack_buttons_zones, + .num_buttons_zones = ARRAY_SIZE(jack_buttons_zones), + .det_int = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, + PMIC_GPIO_EAR_DET), + .send_int = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, + PMIC_GPIO_SHORT_SENDEND), +}; + +static struct platform_device sec_device_jack = { + .name = "sec_jack", + .id = -1, + .dev = { + .platform_data = &sec_jack_data, + }, +}; +#endif + +static struct platform_device *common_devices[] __initdata = { + &msm8960_device_dmov, + &msm_device_smd, + &msm8960_device_uart_gsbi5, + &msm_device_uart_dm6, + &msm_device_saw_core0, + &msm_device_saw_core1, + &msm8960_device_ext_5v_vreg, + &msm8960_device_ssbi_pmic, + &msm8960_device_ext_otg_sw_vreg, +#ifndef CONFIG_SLIMBUS_MSM_CTRL + &msm8960_device_qup_i2c_gsbi1, +#endif +#ifdef CONFIG_S5C73M3 + &msm8960_device_qup_spi_gsbi11, +#endif + &msm8960_device_qup_i2c_gsbi3, + &msm8960_device_qup_i2c_gsbi4, + &msm8960_device_qup_i2c_gsbi7, + &msm8960_device_qup_i2c_gsbi10, +#ifdef CONFIG_VP_A2220 + &msm8960_device_qup_i2c_gsbi8, +#endif +#ifndef CONFIG_MSM_DSPS + &msm8960_device_qup_i2c_gsbi12, +#endif + &msm_slim_ctrl, + &msm_device_wcnss_wlan, +#if defined(CONFIG_QSEECOM) + &qseecom_device, +#endif +#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \ + defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) + &qcrypto_device, +#endif + +#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE) + &qcedev_device, +#endif +#ifdef CONFIG_MSM_ROTATOR + &msm_rotator_device, +#endif + &msm_device_sps, +#ifdef CONFIG_MSM_FAKE_BATTERY + &fish_battery_device, +#endif + &fmem_device, +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + &android_pmem_device, + &android_pmem_adsp_device, + &android_pmem_audio_device, +#endif +#endif +#ifdef CONFIG_KEYBOARD_GPIO + &msm8960_gpio_keys_device, +#endif + &msm_device_vidc, + &msm_device_bam_dmux, + &msm_fm_platform_init, + +#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) +#ifdef CONFIG_MSM_USE_TSIF1 + &msm_device_tsif[1], +#else + &msm_device_tsif[0], +#endif +#endif + +#ifdef CONFIG_HW_RANDOM_MSM + &msm_device_rng, +#endif + &msm8960_rpm_device, +#ifdef CONFIG_ION_MSM + &ion_dev, +#endif + &msm_rpm_log_device, + &msm8960_rpm_stat_device, + &msm_device_tz_log, +#if 0 +#ifdef CONFIG_MSM_QDSS + &msm_etb_device, + &msm_tpiu_device, + &msm_funnel_device, + &msm_etm_device, +#endif +#endif + &msm_device_dspcrashd_8960, + &msm8960_device_watchdog, +#ifdef CONFIG_MSM_RTB + &msm_rtb_device, +#endif + &msm8960_device_cache_erp, +#ifdef CONFIG_MSM_CACHE_DUMP + &msm_cache_dump_device, +#endif + &msm8960_iommu_domain_device, + &msm_tsens_device, +}; + +static struct platform_device *m2_att_devices[] __initdata = { + &msm_8960_q6_lpass, + &msm_8960_q6_mss_sw, + &msm_8960_q6_mss_fw, + &msm_8960_riva, + &msm_pil_tzapps, + &msm_pil_vidc, + &msm8960_device_otg, + &msm8960_device_gadget_peripheral, + &msm_device_hsusb_host, + &android_usb_device, + &msm_pcm, + &msm_multi_ch_pcm, + &msm_lowlatency_pcm, + &msm_pcm_routing, +#ifdef CONFIG_SLIMBUS_MSM_CTRL + &msm_cpudai0, + &msm_cpudai1, +#else + &msm_i2s_cpudai0, + &msm_i2s_cpudai1, +#endif + &msm_cpudai_hdmi_rx, + &msm_cpudai_bt_rx, + &msm_cpudai_bt_tx, + &msm_cpudai_fm_rx, + &msm_cpudai_fm_tx, + &msm_cpudai_auxpcm_rx, + &msm_cpudai_auxpcm_tx, + &msm_cpu_fe, + &msm_stub_codec, +#ifdef CONFIG_MSM_GEMINI + &msm8960_gemini_device, +#endif + &msm_voice, + &msm_voip, + &msm_lpa_pcm, + &msm_cpudai_afe_01_rx, + &msm_cpudai_afe_01_tx, + &msm_cpudai_afe_02_rx, + &msm_cpudai_afe_02_tx, + &msm_pcm_afe, + &msm_compr_dsp, + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + &mhl_i2c_gpio_device, +#endif +#ifdef CONFIG_USB_SWITCH_FSA9485 + &fsa_i2c_gpio_device, +#endif +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 + &touchkey_i2c_gpio_device, +#endif +#ifdef CONFIG_BATTERY_MAX17040 + &fuelgauge_i2c_gpio_device, +#endif +#ifdef CONFIG_BATTERY_SEC + &sec_device_battery, +#endif +#ifdef CONFIG_SAMSUNG_JACK + &sec_device_jack, +#endif + &msm_cpudai_incall_music_rx, + &msm_cpudai_incall_record_rx, + &msm_cpudai_incall_record_tx, + &msm_pcm_hostless, + &msm_bus_apps_fabric, + &msm_bus_sys_fabric, + &msm_bus_mm_fabric, + &msm_bus_sys_fpb, + &msm_bus_cpss_fpb, + &pn544_i2c_gpio_device, +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + &opt_i2c_gpio_device, +#if 0 +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) + &opt_gp2a, +#endif +#endif +#endif +#ifdef CONFIG_BT_BCM4334 + &bcm4334_bluetooth_device, +#endif +#ifdef CONFIG_VIBETONZ + &vibetonz_device, +#endif /* CONFIG_VIBETONZ */ +}; + +static void __init msm8960_i2c_init(void) +{ + msm8960_device_qup_i2c_gsbi4.dev.platform_data = + &msm8960_i2c_qup_gsbi4_pdata; + +#ifndef CONFIG_SLIMBUS_MSM_CTRL + msm8960_device_qup_i2c_gsbi1.dev.platform_data = + &msm8960_i2c_qup_gsbi1_pdata; +#endif + + msm8960_device_qup_i2c_gsbi7.dev.platform_data = + &msm8960_i2c_qup_gsbi7_pdata; + + msm8960_device_qup_i2c_gsbi3.dev.platform_data = + &msm8960_i2c_qup_gsbi3_pdata; + + msm8960_device_qup_i2c_gsbi10.dev.platform_data = + &msm8960_i2c_qup_gsbi10_pdata; +#ifdef CONFIG_VP_A2220 + msm8960_device_qup_i2c_gsbi8.dev.platform_data = + &msm8960_i2c_qup_gsbi8_pdata; +#endif + msm8960_device_qup_i2c_gsbi12.dev.platform_data = + &msm8960_i2c_qup_gsbi12_pdata; +} + +static void __init msm8960_gfx_init(void) +{ + struct kgsl_device_platform_data *kgsl_3d0_pdata = + msm_kgsl_3d0.dev.platform_data; + uint32_t soc_platform_version = socinfo_get_version(); + + kgsl_3d0_pdata->iommu_count = 1; + + if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) { + kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000; + kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000; + } + if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3) { + /* 8960v3 GPU registers returns 5 for patch release + * but it should be 6, so dummy up the chipid here + * based the platform type + */ + kgsl_3d0_pdata->chipid = ADRENO_CHIPID(2, 2, 0, 6); + } + + /* Register the 3D core */ + platform_device_register(&msm_kgsl_3d0); + + /* Register the 2D cores if we are not 8960PRO */ + if (!cpu_is_msm8960ab()) { + platform_device_register(&msm_kgsl_2d0); + platform_device_register(&msm_kgsl_2d1); + } +} +#if 0 +static struct msm_cpuidle_state msm_cstates[] __initdata = { + {0, 0, "C0", "WFI", + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT}, + + {0, 1, "C2", "POWER_COLLAPSE", + MSM_PM_SLEEP_MODE_POWER_COLLAPSE}, + + {1, 0, "C0", "WFI", + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT}, +}; + +static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = { + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + }, + + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + }, + + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 0, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + }, + + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 0, + .idle_enabled = 1, + .suspend_enabled = 0, + }, +}; +#endif +static struct msm_rpmrs_level msm_rpmrs_levels[] = { + { + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT, + MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE), + true, + 100, 650, 801, 200, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE), + false, + 8500, 51, 1122000, 8500, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE), + false, + 9000, 51, 1130300, 9000, + }, + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH), + false, + 10000, 51, 1130300, 10000, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE), + false, + 12000, 14, 2205900, 12000, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE), + false, + 18000, 12, 2364250, 18000, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH), + false, + 23500, 10, 2667000, 23500, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW), + false, + 29700, 5, 2867000, 30000, + }, +}; + +static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = { + .levels = &msm_rpmrs_levels[0], + .num_levels = ARRAY_SIZE(msm_rpmrs_levels), + .vdd_mem_levels = { + [MSM_RPMRS_VDD_MEM_RET_LOW] = 750000, + [MSM_RPMRS_VDD_MEM_RET_HIGH] = 750000, + [MSM_RPMRS_VDD_MEM_ACTIVE] = 1050000, + [MSM_RPMRS_VDD_MEM_MAX] = 1150000, + }, + .vdd_dig_levels = { + [MSM_RPMRS_VDD_DIG_RET_LOW] = 500000, + [MSM_RPMRS_VDD_DIG_RET_HIGH] = 750000, + [MSM_RPMRS_VDD_DIG_ACTIVE] = 950000, + [MSM_RPMRS_VDD_DIG_MAX] = 1150000, + }, + .vdd_mask = 0x7FFFFF, + .rpmrs_target_id = { + [MSM_RPMRS_ID_PXO_CLK] = MSM_RPM_ID_PXO_CLK, + [MSM_RPMRS_ID_L2_CACHE_CTL] = MSM_RPM_ID_LAST, + [MSM_RPMRS_ID_VDD_DIG_0] = MSM_RPM_ID_PM8921_S3_0, + [MSM_RPMRS_ID_VDD_DIG_1] = MSM_RPM_ID_PM8921_S3_1, + [MSM_RPMRS_ID_VDD_MEM_0] = MSM_RPM_ID_PM8921_L24_0, + [MSM_RPMRS_ID_VDD_MEM_1] = MSM_RPM_ID_PM8921_L24_1, + [MSM_RPMRS_ID_RPM_CTL] = MSM_RPM_ID_RPM_CTL, + }, +}; + +static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = { + .mode = MSM_PM_BOOT_CONFIG_TZ, +}; + +#ifdef CONFIG_I2C +#define I2C_SURF 1 +#define I2C_FFA (1 << 1) +#define I2C_RUMI (1 << 2) +#define I2C_SIM (1 << 3) +#define I2C_FLUID (1 << 4) +#define I2C_LIQUID (1 << 5) + +struct i2c_registry { + u8 machs; + int bus; + struct i2c_board_info *info; + int len; +}; + +#ifdef CONFIG_MSM_CAMERA +static struct i2c_board_info msm_camera_boardinfo[] __initdata = { +#ifdef CONFIG_S5C73M3 + { + I2C_BOARD_INFO("s5c73m3", 0x78>>1), + }, +#endif +#ifdef CONFIG_S5K6A3YX + { + I2C_BOARD_INFO("s5k6a3yx", 0x20), + }, +#endif +#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A + { + I2C_BOARD_INFO("sc628a", 0x6E), + }, +#endif +}; +#endif + +/*add for D2_ATT CAM_ISP_CORE power setting by MAX8952*/ +#ifdef CONFIG_REGULATOR_MAX8952 +static int max8952_is_used(void) +{ + if (system_rev >= 0x3) + return 1; + else + return 0; +} + +static struct regulator_consumer_supply max8952_consumer = + REGULATOR_SUPPLY("cam_isp_core", NULL); + +static struct max8952_platform_data m2_att_max8952_pdata = { + .gpio_vid0 = -1, /* NOT controlled by GPIO, HW default high*/ + .gpio_vid1 = -1, /* NOT controlled by GPIO, HW default high*/ + .gpio_en = CAM_CORE_EN, /* Controlled by GPIO, High enable */ + .default_mode = 3, /* vid0 = 1, vid1 = 1 */ + .dvs_mode = { 33, 33, 33, 43 }, /* 1.1V, 1.1V, 1.1V, 1.2V*/ + .sync_freq = 0, /* default: fastest */ + .ramp_speed = 0, /* default: fastest */ + .reg_data = { + .constraints = { + .name = "CAM_ISP_CORE", + .min_uV = 770000, + .max_uV = 1400000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &max8952_consumer, + }, +}; +#endif /*CONFIG_REGULATOR_MAX8952*/ + +#ifdef CONFIG_SAMSUNG_CMC624 +static struct i2c_board_info cmc624_i2c_borad_info[] = { + { + I2C_BOARD_INFO("cmc624", 0x38), + }, +}; +#endif + +#ifdef CONFIG_REGULATOR_MAX8952 +static struct i2c_board_info cmc624_max8952_i2c_borad_info[] = { + { + I2C_BOARD_INFO("cmc624", 0x38), + }, + + { + I2C_BOARD_INFO("max8952", 0xC0>>1), + .platform_data = &m2_att_max8952_pdata, + }, +}; +#endif /*CONFIG_REGULATOR_MAX8952*/ + +/* Sensors DSPS platform data */ +#ifdef CONFIG_MSM_DSPS +#define DSPS_PIL_GENERIC_NAME "dsps" +#endif /* CONFIG_MSM_DSPS */ + +static void __init msm8960_init_dsps(void) +{ +#ifdef CONFIG_MSM_DSPS + struct msm_dsps_platform_data *pdata = + msm_dsps_device.dev.platform_data; + pdata->pil_name = DSPS_PIL_GENERIC_NAME; + pdata->gpios = NULL; + pdata->gpios_num = 0; + + platform_device_register(&msm_dsps_device); +#endif /* CONFIG_MSM_DSPS */ +} + +static int hsic_peripheral_status = 1; +static DEFINE_MUTEX(hsic_status_lock); + +void peripheral_connect() +{ + mutex_lock(&hsic_status_lock); + if (hsic_peripheral_status) + goto out; + platform_device_add(&msm_device_hsic_host); + hsic_peripheral_status = 1; +out: + mutex_unlock(&hsic_status_lock); +} +EXPORT_SYMBOL(peripheral_connect); + +void peripheral_disconnect() +{ + mutex_lock(&hsic_status_lock); + if (!hsic_peripheral_status) + goto out; + platform_device_del(&msm_device_hsic_host); + hsic_peripheral_status = 0; +out: + mutex_unlock(&hsic_status_lock); +} +EXPORT_SYMBOL(peripheral_disconnect); + +static void __init msm8960_init_hsic(void) +{ +#ifdef CONFIG_USB_EHCI_MSM_HSIC + uint32_t version = socinfo_get_version(); + + if (SOCINFO_VERSION_MAJOR(version) == 1) + return; + + if (PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid()) + platform_device_register(&msm_device_hsic_host); +#endif +} + +#ifdef CONFIG_ISL9519_CHARGER +static struct isl_platform_data isl_data __initdata = { + .valid_n_gpio = 0, /* Not required when notify-by-pmic */ + .chg_detection_config = NULL, /* Not required when notify-by-pmic */ + .max_system_voltage = 4200, + .min_system_voltage = 3200, + .chgcurrent = 1000, /* 1900, */ + .term_current = 400, /* Need fine tuning */ + .input_current = 2048, +}; + +static struct i2c_board_info isl_charger_i2c_info[] __initdata = { + { + I2C_BOARD_INFO("isl9519q", 0x9), + .irq = 0, /* Not required when notify-by-pmic */ + .platform_data = &isl_data, + }, +}; +#endif /* CONFIG_ISL9519_CHARGER */ + +static struct i2c_registry msm8960_i2c_devices[] __initdata = { +#ifdef CONFIG_MSM_CAMERA + { + I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI, + MSM_8960_GSBI4_QUP_I2C_BUS_ID, + msm_camera_boardinfo, + ARRAY_SIZE(msm_camera_boardinfo), + }, +#endif +#ifdef CONFIG_ISL9519_CHARGER + { + I2C_LIQUID, + MSM_8960_GSBI10_QUP_I2C_BUS_ID, + isl_charger_i2c_info, + ARRAY_SIZE(isl_charger_i2c_info), + }, +#endif /* CONFIG_ISL9519_CHARGER */ +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_MHL_I2C_BUS_ID, + mhl_i2c_board_info, + ARRAY_SIZE(mhl_i2c_board_info), + }, +#endif +#ifdef CONFIG_USB_SWITCH_FSA9485 + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_FSA9485_I2C_BUS_ID, + micro_usb_i2c_devices_info, + ARRAY_SIZE(micro_usb_i2c_devices_info), + }, +#endif +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +{ + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_TOUCHKEY_I2C_BUS_ID, + touchkey_i2c_devices_info, + ARRAY_SIZE(touchkey_i2c_devices_info), + }, +#endif +#ifdef CONFIG_VP_A2220 + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_8960_GSBI8_QUP_I2C_BUS_ID, + a2220_device, + ARRAY_SIZE(a2220_device), + }, +#endif +#ifdef CONFIG_NFC_PN544 + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_NFC_I2C_BUS_ID, + pn544_info, + ARRAY_SIZE(pn544_info), + }, +#endif /* CONFIG_NFC_PN544 */ +#if 0 + { + I2C_LIQUID, + MSM_8960_GSBI3_QUP_I2C_BUS_ID, + mxt_device_info, + ARRAY_SIZE(mxt_device_info), + }, +#endif +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_SNS_I2C_BUS_ID, + sns_i2c_borad_info, + ARRAY_SIZE(sns_i2c_borad_info), + }, +#endif +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_OPT_I2C_BUS_ID, + opt_i2c_borad_info, + ARRAY_SIZE(opt_i2c_borad_info), + }, +#endif +#ifdef CONFIG_SAMSUNG_CMC624 + { + I2C_SURF | I2C_FFA | I2C_FLUID , + MSM_CMC624_I2C_BUS_ID, + cmc624_i2c_borad_info, + ARRAY_SIZE(cmc624_i2c_borad_info), + }, +#endif + { + I2C_LIQUID, + MSM_8960_GSBI10_QUP_I2C_BUS_ID, + sii_device_info, + ARRAY_SIZE(sii_device_info), + }, + { + I2C_LIQUID, + MSM_8960_GSBI10_QUP_I2C_BUS_ID, + msm_isa1200_board_info, + ARRAY_SIZE(msm_isa1200_board_info), + }, +#ifndef CONFIG_SLIMBUS_MSM_CTRL + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_8960_GSBI1_QUP_I2C_BUS_ID, + tabla_device_info, + ARRAY_SIZE(tabla_device_info), + }, +#endif +}; +#endif /* CONFIG_I2C */ + +static void __init register_i2c_devices(void) +{ +#ifdef CONFIG_I2C + u8 mach_mask = 0; + int i; + +#ifdef CONFIG_REGULATOR_MAX8952 +struct i2c_registry cmc624_max8952_i2c_devices = { + I2C_SURF | I2C_FFA | I2C_FLUID , + MSM_CMC624_I2C_BUS_ID, + cmc624_max8952_i2c_borad_info, + ARRAY_SIZE(cmc624_max8952_i2c_borad_info), + }; +#endif /*CONFIG_REGULATOR_MAX8952*/ + +#ifdef CONFIG_BATTERY_MAX17040 + struct i2c_registry msm8960_fg_i2c_devices = { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_FUELGAUGE_I2C_BUS_ID, + fg_i2c_board_info, + ARRAY_SIZE(fg_i2c_board_info), + }; +#endif /* CONFIG_BATTERY_MAX17040 */ +#if defined(CONFIG_CHARGER_SMB347) + struct i2c_registry msm8960_fg_smb_i2c_devices = { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_FUELGAUGE_I2C_BUS_ID, + fg_smb_i2c_board_info, + ARRAY_SIZE(fg_smb_i2c_board_info), + }; +#endif + + /* Build the matching 'supported_machs' bitmask */ + if (machine_is_msm8960_cdp()) + mach_mask = I2C_SURF; + else if (machine_is_msm8960_rumi3()) + mach_mask = I2C_RUMI; + else if (machine_is_msm8960_sim()) + mach_mask = I2C_SIM; + else if (machine_is_msm8960_fluid()) + mach_mask = I2C_FLUID; + else if (machine_is_msm8960_liquid()) + mach_mask = I2C_LIQUID; + else if (machine_is_msm8960_mtp()) + mach_mask = I2C_FFA; + else if (machine_is_M2_ATT()) + mach_mask = I2C_FFA; + else + pr_err("unmatched machine ID in register_i2c_devices\n"); + + /* Run the array and install devices as appropriate */ + for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) { + if (msm8960_i2c_devices[i].machs & mach_mask) + i2c_register_board_info(msm8960_i2c_devices[i].bus, + msm8960_i2c_devices[i].info, + msm8960_i2c_devices[i].len); + } + +#ifdef CONFIG_SAMSUNG_CMC624 +#ifdef CONFIG_REGULATOR_MAX8952 + if (max8952_is_used()) { + i2c_register_board_info(cmc624_max8952_i2c_devices.bus, + cmc624_max8952_i2c_devices.info, + cmc624_max8952_i2c_devices.len); + } +#endif /*CONFIG_REGULATOR_MAX8952*/ +#endif /*CONFIG_SAMSUNG_CMC624*/ + +#if defined(CONFIG_BATTERY_MAX17040) + if (!is_smb347_using()) { + i2c_register_board_info(msm8960_fg_i2c_devices.bus, + msm8960_fg_i2c_devices.info, + msm8960_fg_i2c_devices.len); + } +#if defined(CONFIG_CHARGER_SMB347) + else { + i2c_register_board_info(msm8960_fg_smb_i2c_devices.bus, + msm8960_fg_smb_i2c_devices.info, + msm8960_fg_smb_i2c_devices.len); + } +#endif /* CONFIG_CHARGER_SMB347 */ +#endif /* CONFIG_BATTERY_MAX17040 */ +#endif +} + +static void __init gpio_rev_init(void) +{ + /*KEY REV*/ + gpio_keys_button[0].gpio = gpio_rev(VOLUME_UP); + gpio_keys_button[1].gpio = gpio_rev(VOLUME_DOWN); + gpio_keys_platform_data.nbuttons = 2; + if (system_rev >= BOARD_REV08) { + gpio_tlmm_config(GPIO_CFG(GPIO_HOME_KEY, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + gpio_keys_button[2].gpio = GPIO_HOME_KEY; + gpio_keys_platform_data.nbuttons = ARRAY_SIZE(gpio_keys_button); + } +#if defined(CONFIG_SENSORS_CM36651) + if (system_rev < BOARD_REV08 || system_rev == BOARD_REV11) + cm36651_pdata.irq = gpio_rev(ALS_INT); +#endif +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + opt_i2c_gpio_data.sda_pin = gpio_rev(ALS_SDA); + opt_i2c_gpio_data.scl_pin = gpio_rev(ALS_SCL); +#if defined(CONFIG_OPTICAL_GP2A) + if (system_rev < BOARD_REV08 || system_rev == BOARD_REV11) { + opt_gp2a_data.irq = MSM_GPIO_TO_INT(gpio_rev(ALS_INT)); + opt_gp2a_data.ps_status = gpio_rev(ALS_INT); + } +#elif defined(CONFIG_OPTICAL_GP2AP020A00F) + if (system_rev < BOARD_REV08 || system_rev == BOARD_REV11) + opt_gp2a_data.p_out = gpio_rev(ALS_INT); +#endif +#endif + a2220_i2c_gpio_data.sda_pin = gpio_rev(A2220_SDA); + a2220_i2c_gpio_data.scl_pin = gpio_rev(A2220_SCL); + a2220_data.gpio_wakeup = gpio_rev(A2220_WAKEUP); + msm8960_a2220_configs[0].gpio = gpio_rev(A2220_SDA); + msm8960_a2220_configs[1].gpio = gpio_rev(A2220_SCL); +#ifdef CONFIG_VIBETONZ + if (system_rev >= BOARD_REV04) { + msm_8960_vibrator_pdata.vib_en_gpio = PMIC_GPIO_VIB_ON; + msm_8960_vibrator_pdata.is_pmic_vib_en = 1; + } + if (system_rev >= BOARD_REV08) { + msm_8960_vibrator_pdata.haptic_pwr_en_gpio = \ + PMIC_GPIO_HAPTIC_PWR_EN; + msm_8960_vibrator_pdata.is_pmic_haptic_pwr_en = 1; + } +#endif /* CONFIG_VIBETONZ */ +} + +#ifdef CONFIG_SAMSUNG_JACK +static struct pm_gpio ear_det = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, +}; + +static struct pm_gpio short_sendend = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, +}; + +static struct pm_gpio ear_micbiase = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .vin_sel = PM_GPIO_VIN_S4, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, +}; + +static int secjack_gpio_init(void) +{ + int rc; + + rc = pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_DET), + &ear_det); + if (rc) { + pr_err("%s PMIC_GPIO_EAR_DET config failed\n", __func__); + return rc; + } + rc = pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_SHORT_SENDEND), + &short_sendend); + if (rc) { + pr_err("%s PMIC_GPIO_SHORT_SENDEND config failed\n", __func__); + return rc; + } + rc = gpio_request( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + "EAR_MICBIAS"); + if (rc) { + pr_err("failed to request ear micbias gpio\n"); + gpio_free(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN)); + return rc; + } + rc = pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + &ear_micbiase); + if (rc) { + pr_err("%s PMIC_GPIO_EAR_MICBIAS_EN config failed\n", __func__); + return rc; + } else { + gpio_direction_output(PM8921_GPIO_PM_TO_SYS( + PMIC_GPIO_EAR_MICBIAS_EN), 0); + } + + return rc; +} +#endif + +void main_mic_bias_init(void) +{ + int ret; + ret = gpio_request(GPIO_MAIN_MIC_BIAS, "LDO_BIAS"); + if (ret) { + pr_err("%s: ldo bias gpio %d request" + "failed\n", __func__, GPIO_MAIN_MIC_BIAS); + return; + } + gpio_direction_output(GPIO_MAIN_MIC_BIAS, 0); +} + +static int configure_codec_lineout_gpio(void) +{ + int ret; + struct pm_gpio param = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 1, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + }; + + ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS( + gpio_rev(LINEOUT_EN)), ¶m); + if (ret) { + pr_err("%s: Failed to configure Lineout EN" + " gpio %d\n", __func__, + PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN))); + return ret; + } else + gpio_direction_output(PM8921_GPIO_PM_TO_SYS( + gpio_rev(LINEOUT_EN)), 1); + return 0; +} + +static int tabla_codec_ldo_en_init(void) +{ + int ret; + + ret = gpio_request(PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN)), + "LINEOUT_EN"); + if (ret) { + pr_err("%s:External LDO gpio %d request" + "failed\n", __func__, + PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN))); + return ret; + } + gpio_direction_output(PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN)), 0); + return 0; +} + +static void __init msm8960ab_update_krait_spm(void) +{ + int i; + + /* Reset the AVS registers until we have support for AVS */ + for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) { + struct msm_spm_platform_data *pdata = &msm_spm_data[i]; + pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0; + pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0; + } + + /* Update the SPM sequences for SPC and PC */ + for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) { + int j; + struct msm_spm_platform_data *pdata = &msm_spm_data[i]; + for (j = 0; j < pdata->num_modes; j++) { + if (pdata->modes[j].cmd == + spm_power_collapse_without_rpm) + pdata->modes[j].cmd = + spm_power_collapse_without_rpm_krait_v3; + else if (pdata->modes[j].cmd == + spm_power_collapse_with_rpm) + pdata->modes[j].cmd = + spm_power_collapse_with_rpm_krait_v3; + } + } +} + +static void __init msm8960_tsens_init(void) +{ + if (cpu_is_msm8960()) + if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) + return; + + msm_tsens_early_init(&msm_tsens_pdata); +} + +static void __init samsung_m2_att_init(void) +{ +#ifdef CONFIG_ANDROID_RAM_CONSOLE + platform_device_register(&ram_console_device); +#endif +#ifdef CONFIG_SEC_DEBUG + sec_debug_init(); +#endif + + if (meminfo_init(SYS_MEMORY, SZ_256M) < 0) + pr_err("meminfo_init() failed!\n"); + + platform_device_register(&msm_gpio_device); + msm8960_tsens_init(); + msm_thermal_init(&msm_thermal_pdata); + BUG_ON(msm_rpm_init(&msm8960_rpm_data)); + BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data)); + + gpio_rev_init(); + regulator_suppress_info_printing(); + if (msm_xo_init()) + pr_err("Failed to initialize XO votes\n"); + platform_device_register(&msm8960_device_rpm_regulator); + msm_clock_init(&msm8960_clock_init_data); + if (machine_is_msm8960_liquid()) + msm_otg_pdata.mhl_enable = true; + msm8960_device_otg.dev.platform_data = &msm_otg_pdata; + if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() || + machine_is_msm8960_cdp()) { + msm_otg_pdata.phy_init_seq = wr_phy_init_seq; + } else if (machine_is_msm8960_liquid()) { + msm_otg_pdata.phy_init_seq = + liquid_v1_phy_init_seq; + } + android_usb_pdata.swfi_latency = + msm_rpmrs_levels[0].latency_us; + +#ifdef CONFIG_USB_HOST_NOTIFY + msm_otg_power_init(); +#endif +#ifdef CONFIG_VP_A2220 + if (system_rev > BOARD_REV02) + msm_gpiomux_install(msm8960_a2220_configs, + ARRAY_SIZE(msm8960_a2220_configs)); +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC + if (machine_is_msm8960_liquid()) { + if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2) + msm_hsic_pdata.hub_reset = HSIC_HUB_RESET_GPIO; + } +#endif + msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata; + msm8960_init_gpiomux(); + +#ifndef CONFIG_S5C73M3 + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); +#endif +#ifdef CONFIG_S5C73M3 + msm8960_device_qup_spi_gsbi11.dev.platform_data = + &msm8960_qup_spi_gsbi11_pdata; +#endif + +#ifndef CONFIG_S5C73M3 + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); +#endif +#ifdef CONFIG_BATTERY_SEC + check_highblock_temp(); +#endif /*CONFIG_BATTERY_SEC*/ + msm8960_init_pmic(); + msm8960_i2c_init(); + msm8960_gfx_init(); + if (cpu_is_msm8960ab()) + msm8960ab_update_krait_spm(); + msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data)); + msm_spm_l2_init(msm_spm_l2_data); + msm8960_init_buses(); + if (cpu_is_msm8960ab()) { + platform_add_devices(msm8960ab_footswitch, + msm8960ab_num_footswitch); + } else { + platform_add_devices(msm8960_footswitch, + msm8960_num_footswitch); + } + if (machine_is_msm8960_liquid()) + platform_device_register(&msm8960_device_ext_3p3v_vreg); + if (cpu_is_msm8960ab()) + platform_device_register(&msm8960ab_device_acpuclk); + else + platform_device_register(&msm8960_device_acpuclk); + platform_add_devices(common_devices, ARRAY_SIZE(common_devices)); + msm8960_pm8921_gpio_mpp_init(); + platform_add_devices(m2_att_devices, ARRAY_SIZE(m2_att_devices)); + msm8960_init_hsic(); + msm8960_init_cam(); + msm8960_init_mmc(); + if (machine_is_msm8960_liquid()) + mxt_init_hw_liquid(); + samsung_sys_class_init(); + mms_tsp_input_init(); +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + sensor_device_init(); +#endif +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + mpl_init(); +#endif +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + opt_init(); +#endif +#if defined(CONFIG_NFC_PN544) + pn544_init(); +#endif + msm8960_mhl_gpio_init(); + register_i2c_devices(); + msm8960_init_fb(); + main_mic_bias_init(); + /* From REV09 onwards LINEOUT_EN is not used */ + if (system_rev < BOARD_REV09) { + tabla_codec_ldo_en_init(); + configure_codec_lineout_gpio(); + } + +#ifdef CONFIG_SAMSUNG_JACK + if (system_rev < BOARD_REV10) { + pr_info("%s : system rev = %d, MBHC Using\n", + __func__, system_rev); + memset(&sec_jack_data, 0, sizeof(sec_jack_data)); + } else { + pr_info("%s : system rev = %d, Secjack Using\n", + __func__, system_rev); + secjack_gpio_init(); + } +#endif + + msm8960_init_dsps(); +#if 0 + msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ); +#endif + change_memory_power = &msm8960_change_memory_power; + BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata)); +#if 0 + msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data); +#endif +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) + printk(KERN_INFO "[WIFI] system_rev = %d\n", system_rev); + if (system_rev >= 0x3) + brcm_wlan_init(); +#endif + msm_pm_set_tz_retention_flag(1); + + if (PLATFORM_IS_CHARM25()) + platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices)); + ion_adjust_secure_allocation(); +} + +MACHINE_START(M2_ATT, "SAMSUNG M2_ATT") + .map_io = msm8960_map_io, + .reserve = msm8960_reserve, + .init_irq = msm8960_init_irq, + .handle_irq = gic_handle_irq, + .timer = &msm_timer, + .init_machine = samsung_m2_att_init, + .init_early = msm8960_allocate_memory_regions, + .init_very_early = msm8960_early_memory, + .restart = msm_restart, +MACHINE_END +#endif diff --git a/arch/arm/mach-msm/board-m2_spr-gpiomux.c b/arch/arm/mach-msm/board-m2_spr-gpiomux.c new file mode 100644 index 00000000000..57ef16517e1 --- /dev/null +++ b/arch/arm/mach-msm/board-m2_spr-gpiomux.c @@ -0,0 +1,1099 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include "devices.h" +#include "board-8960.h" +#include +#include + +/* The SPI configurations apply to GSBI 1*/ +static struct gpiomux_setting spi_active = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_12MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting spi_suspended_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting spi_active_config2 = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting spi_suspended_config2 = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting gsbi3_suspended_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting gsbi1 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_12MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi3_active_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi5 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi7 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#ifdef CONFIG_VP_A2220 +static struct gpiomux_setting gsbi8 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +static struct gpiomux_setting audience_suspend_gpio_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif +static struct gpiomux_setting gsbi10 = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi12 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_mclk = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#if 0 +static struct gpiomux_setting audio_auxpcm[] = { + /* Suspended state */ + { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + }, + /* Active state */ + { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, + }, +}; +#endif +#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE) +static struct gpiomux_setting gpio_eth_config = { + .pull = GPIOMUX_PULL_NONE, + .drv = GPIOMUX_DRV_8MA, + .func = GPIOMUX_FUNC_GPIO, +}; +#endif +#if 0 +static struct gpiomux_setting slimbus = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_KEEPER, +}; +#endif +static struct gpiomux_setting gpio_key_active_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting gpio_key_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting wcnss_5wire_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting wcnss_5wire_active_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_6MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT +static struct gpiomux_setting sdc4_suspend_cfg = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting sdc4_suspend2_cfg = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting sdc4_active_cfg = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_16MA, + .pull = GPIOMUX_PULL_UP, +}; +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC +static struct gpiomux_setting hsic_act_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_12MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting hsic_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_OUT_LOW, +}; + +static struct gpiomux_setting hsic_hub_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif + +static struct gpiomux_setting hap_lvl_shft_suspended_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting hap_lvl_shft_active_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting ap2mdm_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting mdm2ap_status_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting mdm2ap_errfatal_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_16MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting mdp_vsync_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting mdp_vsync_active_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static struct gpiomux_setting hdmi_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting hdmi_active_1_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting hdmi_active_2_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; +#if 0 +static struct gpiomux_setting hdmi_active_3_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_IN, +}; +static struct gpiomux_setting hdmi_active_4_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, + .dir = GPIOMUX_OUT_HIGH, +}; +#endif +#endif +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +static struct gpiomux_setting mhl_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting mhl_active_1_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_OUT_LOW, +}; +#if 0 +static struct gpiomux_setting mhl_active_2_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif +#endif + +#ifdef CONFIG_USB_SWITCH_FSA9485 +static struct gpiomux_setting fsa9485_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting fsa9485_active_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_fsa9485_configs[] __initdata = { + { + .gpio = 14, + .settings = { + [GPIOMUX_ACTIVE] = &fsa9485_active_cfg, + [GPIOMUX_SUSPENDED] = &fsa9485_suspend_cfg, + }, + }, + + { + .gpio = 73, + .settings = { + [GPIOMUX_ACTIVE] = &fsa9485_active_cfg, + [GPIOMUX_SUSPENDED] = &fsa9485_suspend_cfg, + }, + }, + + { + .gpio = 74, + .settings = { + [GPIOMUX_ACTIVE] = &fsa9485_active_cfg, + [GPIOMUX_SUSPENDED] = &fsa9485_suspend_cfg, + }, + }, +}; +#endif + +#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE) +static struct msm_gpiomux_config msm8960_ethernet_configs[] = { + { + .gpio = 90, + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_eth_config, + } + }, + { + .gpio = 89, + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_eth_config, + } + }, +}; +#endif + +struct msm_gpiomux_config msm8960_gpio_key_configs[] = { + { + .settings = { + [GPIOMUX_ACTIVE] = &gpio_key_active_cfg, + [GPIOMUX_SUSPENDED] = &gpio_key_suspend_cfg, + } + }, + { + .settings = { + [GPIOMUX_ACTIVE] = &gpio_key_active_cfg, + [GPIOMUX_SUSPENDED] = &gpio_key_suspend_cfg, + } + }, + { + .gpio = GPIO_HOME_KEY, + .settings = { + [GPIOMUX_ACTIVE] = &gpio_key_active_cfg, + [GPIOMUX_SUSPENDED] = &gpio_key_suspend_cfg, + } + }, +}; +#ifdef CONFIG_VP_A2220 +static struct msm_gpiomux_config audience_suspend_configs[] __initdata = { + { + .gpio = 35, /* 2MIC PW DN */ + .settings = { + [GPIOMUX_SUSPENDED] = &audience_suspend_gpio_config, + }, + }, + { + .gpio = 75, /* 2MIC RESET */ + .settings = { + [GPIOMUX_SUSPENDED] = &audience_suspend_gpio_config, + }, + }, +}; +#endif + +static struct msm_gpiomux_config msm8960_gsbi_configs[] __initdata = { + { + .gpio = 6, /* GSBI1 QUP SPI_DATA_MOSI */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = 7, /* GSBI1 QUP SPI_DATA_MISO */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = 8, /* GSBI1 QUP SPI_CS_N */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi1, + [GPIOMUX_ACTIVE] = &gsbi1, + }, + }, + { + .gpio = 9, /* GSBI1 QUP SPI_CLK */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi1, + [GPIOMUX_ACTIVE] = &gsbi1, + }, + }, + { + .gpio = 14, /* GSBI1 SPI_CS_1 */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config2, + [GPIOMUX_ACTIVE] = &spi_active_config2, + }, + }, + { + .gpio = 16, /* GSBI3 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg, + [GPIOMUX_ACTIVE] = &gsbi3_active_cfg, + }, + }, + { + .gpio = 17, /* GSBI3 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg, + [GPIOMUX_ACTIVE] = &gsbi3_active_cfg, + }, + }, + { + .gpio = 22, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 23, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 24, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 25, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 32, /* GSBI7 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi7, + }, + }, + { + .gpio = 33, /* GSBI7 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi7, + }, + }, +#ifdef CONFIG_S5C73M3 + { + .gpio = GPIO_CAM_SPI_MOSI, /* GSBI11 QUP SPI_DATA_MOSI */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = GPIO_CAM_SPI_MISO, /* GSBI11 QUP SPI_DATA_MISO */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = GPIO_CAM_SPI_SSN, /* GSBI11 QUP SPI_CS_N */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = GPIO_CAM_SPI_SCLK, /* GSBI11 QUP SPI_CLK */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, +#endif + { + .gpio = 44, /* GSBI12 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi12, + }, + }, + { + .gpio = 45, /* GSBI12 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi12, + }, + }, +#ifdef CONFIG_VP_A2220 + { + .gpio = 36, /* GSBI8 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi8, + }, + }, + { + .gpio = 37, /* GSBI8 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi8, + }, + }, +#endif + { + .gpio = 73, /* GSBI10 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi10, + }, + }, + { + .gpio = 74, /* GSBI10 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi10, + }, + }, +}; +#if 0 +static struct msm_gpiomux_config msm8960_slimbus_config[] __initdata = { + { + .gpio = 60, /* slimbus data */ + .settings = { + [GPIOMUX_SUSPENDED] = &slimbus, + }, + }, + { + .gpio = 61, /* slimbus clk */ + .settings = { + [GPIOMUX_SUSPENDED] = &slimbus, + }, + }, +}; +#endif +static struct msm_gpiomux_config msm8960_audio_codec_configs[] __initdata = { + { + .gpio = 59, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_mclk, + }, + }, +}; + +static struct gpiomux_setting cdc_i2s_mclk = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_rx_sclk = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_rx_dout = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_rx_ws = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_audio_i2s_rx_codec_configs[] = { + { + .gpio = 59, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_mclk, + }, + }, + { + .gpio = 60, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_rx_sclk, + }, + }, + { + .gpio = 61, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_rx_dout, + }, + }, + { + .gpio = 62, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_rx_ws, + }, + }, +}; + +static struct gpiomux_setting cdc_i2s_tx_sclk = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_tx_d0 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#if 0 +static struct gpiomux_setting cdc_i2s_tx_d1 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif +static struct gpiomux_setting cdc_i2s_tx_ws = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_audio_i2s_tx_codec_configs[] = { + { + .gpio = 59, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_mclk, + }, + }, + { + .gpio = 55, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_tx_sclk, + }, + }, + { + .gpio = 56, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_tx_ws, + }, + }, + { + .gpio = 57, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_tx_d0, + }, + }, + +}; + +#if 0 +static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = { + { + .gpio = 63, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, + { + .gpio = 64, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, + { + .gpio = 65, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, + { + .gpio = 66, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, +}; +#endif +static struct msm_gpiomux_config wcnss_5wire_interface[] = { + { + .gpio = 84, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 85, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 86, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 87, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 88, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, +}; + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT +static struct msm_gpiomux_config sdc4_interface[] = { + { + .gpio = 83, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 84, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 85, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 86, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 87, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 88, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend2_cfg, + }, + }, +}; +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC +static struct msm_gpiomux_config msm8960_hsic_configs[] = { + { + .gpio = 150, /*HSIC_STROBE */ + .settings = { + [GPIOMUX_ACTIVE] = &hsic_act_cfg, + [GPIOMUX_SUSPENDED] = &hsic_sus_cfg, + }, + }, + { + .gpio = 151, /* HSIC_DATA */ + .settings = { + [GPIOMUX_ACTIVE] = &hsic_act_cfg, + [GPIOMUX_SUSPENDED] = &hsic_sus_cfg, + }, + }, + { + .gpio = 91, /* HSIC_HUB_RESET */ + .settings = { + [GPIOMUX_ACTIVE] = &hsic_hub_act_cfg, + [GPIOMUX_SUSPENDED] = &hsic_sus_cfg, + }, + }, +}; +#endif + +static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = { + { + .gpio = 47, + .settings = { + [GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config, + [GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config, + }, + }, +}; + +static struct msm_gpiomux_config mdm_configs[] __initdata = { + /* AP2MDM_STATUS */ + { + .gpio = 94, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_cfg, + } + }, + /* MDM2AP_STATUS */ + { + .gpio = 69, + .settings = { + [GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg, + } + }, + /* MDM2AP_ERRFATAL */ + { + .gpio = 70, + .settings = { + [GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg, + } + }, + /* AP2MDM_ERRFATAL */ + { + .gpio = 95, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_cfg, + } + }, + /* AP2MDM_KPDPWR_N */ + { + .gpio = 81, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg, + } + }, + /* AP2MDM_PMIC_RESET_N */ + { + .gpio = 80, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg, + } + } +}; + +static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = { + { + .gpio = 0, + .settings = { + [GPIOMUX_ACTIVE] = &mdp_vsync_active_cfg, + [GPIOMUX_SUSPENDED] = &mdp_vsync_suspend_cfg, + }, + } +}; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static struct msm_gpiomux_config msm8960_hdmi_configs[] __initdata = { + { + .gpio = 99, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 100, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 101, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 102, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_2_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, +}; +#endif +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +static struct msm_gpiomux_config msm8960_mhl_configs[] __initdata = { + { + .gpio = GPIO_MHL_EN, + .settings = { + [GPIOMUX_ACTIVE] = &mhl_active_1_cfg, + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_RST, + .settings = { + [GPIOMUX_ACTIVE] = &mhl_active_1_cfg, + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_WAKE_UP, + .settings = { + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_SDA, + .settings = { + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_SCL, + .settings = { + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + + + +}; +#endif + +#ifdef CONFIG_I2C + +#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3 +#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10 + +#endif + +static struct gpiomux_setting sec_ts_int_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting sec_ts_int_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct msm_gpiomux_config msm8960_sec_ts_configs[] = { + { /* TS INTERRUPT */ + .gpio = 11, + .settings = { + [GPIOMUX_ACTIVE] = &sec_ts_int_act_cfg, + [GPIOMUX_SUSPENDED] = &sec_ts_int_sus_cfg, + }, + }, +}; + + +static struct gpiomux_setting sec_prox_int_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting sec_prox_int_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_sec_sensor_configs[] = { + { /* PS INTERRUPT */ + .gpio = 42, + .settings = { + [GPIOMUX_ACTIVE] = &sec_prox_int_act_cfg, + [GPIOMUX_SUSPENDED] = &sec_prox_int_sus_cfg, + }, + }, +}; + +int __init msm8960_init_gpiomux(void) +{ + int rc = msm_gpiomux_init(NR_GPIO_IRQS); + if (rc) { + pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc); + return rc; + } + +#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE) + msm_gpiomux_install(msm8960_ethernet_configs, + ARRAY_SIZE(msm8960_ethernet_configs)); +#endif + + msm_gpiomux_install(msm8960_gsbi_configs, + ARRAY_SIZE(msm8960_gsbi_configs)); + +#ifdef CONFIG_VP_A2220 + msm_gpiomux_install(audience_suspend_configs, + ARRAY_SIZE(audience_suspend_configs)); +#endif + msm8960_gpio_key_configs[0].gpio = gpio_rev(VOLUME_UP); + msm8960_gpio_key_configs[1].gpio = gpio_rev(VOLUME_DOWN); + if (system_rev < BOARD_REV06) + msm_gpiomux_install(msm8960_gpio_key_configs, 2); + else + msm_gpiomux_install(msm8960_gpio_key_configs, + ARRAY_SIZE(msm8960_gpio_key_configs)); + + msm_gpiomux_install(msm8960_sec_ts_configs, + ARRAY_SIZE(msm8960_sec_ts_configs)); + + msm_gpiomux_install(msm8960_sec_sensor_configs, + ARRAY_SIZE(msm8960_sec_sensor_configs)); + + msm_gpiomux_install(msm8960_audio_codec_configs, + ARRAY_SIZE(msm8960_audio_codec_configs)); + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + if (system_rev >= BOARD_REV03) + msm_gpiomux_install(sdc4_interface, ARRAY_SIZE(sdc4_interface)); + else +#endif + msm_gpiomux_install(wcnss_5wire_interface, + ARRAY_SIZE(wcnss_5wire_interface)); + + msm_gpiomux_install(msm8960_audio_i2s_rx_codec_configs, + ARRAY_SIZE(msm8960_audio_i2s_tx_codec_configs)); + + msm_gpiomux_install(msm8960_audio_i2s_tx_codec_configs, + ARRAY_SIZE(msm8960_audio_i2s_tx_codec_configs)); + +#ifdef CONFIG_USB_SWITCH_FSA9485 + msm_gpiomux_install(msm8960_fsa9485_configs, + ARRAY_SIZE(msm8960_fsa9485_configs)); +#endif + + if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() || + machine_is_msm8960_liquid() || machine_is_msm8960_cdp()) + msm_gpiomux_install(hap_lvl_shft_config, + ARRAY_SIZE(hap_lvl_shft_config)); + + if (PLATFORM_IS_CHARM25()) + msm_gpiomux_install(mdm_configs, + ARRAY_SIZE(mdm_configs)); + +#ifdef CONFIG_USB_EHCI_MSM_HSIC + if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) && + (PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid())) + msm_gpiomux_install(msm8960_hsic_configs, + ARRAY_SIZE(msm8960_hsic_configs)); +#endif + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL + msm_gpiomux_install(msm8960_hdmi_configs, + ARRAY_SIZE(msm8960_hdmi_configs)); +#endif +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + msm_gpiomux_install(msm8960_mhl_configs, + ARRAY_SIZE(msm8960_mhl_configs)); +#endif + + msm_gpiomux_install(msm8960_mdp_vsync_configs, + ARRAY_SIZE(msm8960_mdp_vsync_configs)); + + return 0; +} diff --git a/arch/arm/mach-msm/board-m2_spr.c b/arch/arm/mach-msm/board-m2_spr.c new file mode 100644 index 00000000000..ef61c5ce11c --- /dev/null +++ b/arch/arm/mach-msm/board-m2_spr.c @@ -0,0 +1,5542 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ANDROID_PMEM +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef CONFIG_USB_MSM_OTG_72K +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SENSORS_AK8975 +#include +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1 +#include +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 +#include +#endif + +#ifdef CONFIG_OPTICAL_GP2A +#include +#endif +#ifdef CONFIG_OPTICAL_GP2AP020A00F +#include +#endif +#ifdef CONFIG_VP_A2220 +#include +#endif +#ifdef CONFIG_INPUT_BMP180 +#include +#endif +#ifdef CONFIG_WCD9310_CODEC +#include +#include +#include +#endif +#ifdef CONFIG_KEYBOARD_GPIO +#include +#endif +#ifdef CONFIG_USB_SWITCH_FSA9485 +#include +#include +#endif + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +#include +#endif + +#include +#ifdef CONFIG_PM8921_CHARGER +#include +#endif +#ifdef CONFIG_PM8921_SEC_CHARGER +#include +#endif +#ifdef CONFIG_BATTERY_SEC +#include +#endif +#ifdef CONFIG_CHARGER_SMB347 +#include +#endif +#ifdef CONFIG_BATTERY_MAX17040 +#include +#endif +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "timer.h" +#include "devices.h" +#include "devices-msm8x60.h" +#include "spm.h" +#include "board-8960.h" +#include "pm.h" +#include +#include "rpm_resources.h" +#include +#include "acpuclock.h" +#include "rpm_log.h" +#include "smd_private.h" +#ifdef CONFIG_NFC_PN544 +#include +#endif /* CONFIG_NFC_PN544 */ +#include "mach/board-msm8960-camera.h" +#include "pm-boot.h" +#include "msm_watchdog.h" +#ifdef CONFIG_SENSORS_CM36651 +#include +#endif +#ifdef CONFIG_REGULATOR_MAX8952 +#include +#include +#endif +#ifdef CONFIG_VIBETONZ +#include +#endif + +#ifdef CONFIG_SAMSUNG_JACK +#include +#endif + +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#endif + +#ifdef CONFIG_ANDROID_RAM_CONSOLE +#include +#endif + +extern int system_rev; +#ifdef CONFIG_TOUCHSCREEN_MMS144 +struct tsp_callbacks *charger_callbacks; +#endif + +static struct platform_device msm_fm_platform_init = { + .name = "iris_fm", + .id = -1, +}; + +#ifdef CONFIG_SEC_DEBUG +#include +#endif +unsigned int gpio_table[][GPIO_REV_MAX] = { +/* GPIO_INDEX Rev {#00,#01,#02,#03,#04,#05,#06,#07,#08 } */ +/* MDP_VSYNC */ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* VOLUME_UP */ { 80, 80, 80, 80, 50, 50, 50, 50, 50 }, +/* VOLUME_DOWN */ { 81, 81, 81, 81, 81, 81, 81, 81, 81 }, +/* GPIO_MAG_RST */ { 66, 66, 66, 48, 48, 48, 9, 9, 9 }, +/* ALS_INT */ { 42, 42, 42, 42, 42, 42, 6, 6, 6 }, +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) +/* ALS_SDA */ { 63, 63, 63, 12, 12, 12, 12, 12, 12 }, +/* ALS_SCL */ { 64, 64, 64, 13, 13, 13, 13, 13, 13 }, +#endif +/* LCD_22V_EN */ { 10, 10, 10, 4, 4, 4, 4, 4, 4 }, +/* LINEOUT_EN */ { -1, -1, 17, 5, 5, 5, 5, 5, 5 }, +/* A2220_WAKEUP */ { 79, 79, 79, 35, 35, 35, 35, 35, 35 }, +/* A2220_SDA */ { 12, 12, 12, 36, 36, 36, 36, 36, 36 }, +/* A2220_SCL */ { 13, 13, 13, 37, 37, 37, 37, 37, 37 }, +/* CAM_AF_EN */ { 54, 54, 54, 77, 77, 77, 77, 77, 77 }, +/* CAM_FLASH_SW */ { 49, 49, 49, 49, 49, 49, 80, 80, 80 }, +/* BT_HOST_WAKE */ { -1, -1, -1, 10, 10, 10, 10, 10, 10 }, +/* BT_WAKE */ { -1, -1, -1, 79, 79, 79, 79, 79, 79 }, +/* BT_EN */ { -1, -1, -1, 82, 82, 82, 82, 82, 82 }, +}; + +int gpio_rev(unsigned int index) +{ + if (system_rev >= GPIO_REV_MAX) + return -EINVAL; + + if (system_rev < BOARD_REV08) + return gpio_table[index][system_rev]; + else + return gpio_table[index][BOARD_REV08]; +} + +#if defined(CONFIG_OPTICAL_GP2AP020A00F) +static void gp2a_power_on(int onoff); +#endif + +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static void mpu_power_on(int onoff); +#endif + +#ifdef CONFIG_SENSORS_AK8975 +static void akm_power_on(int onoff); +#endif + +#ifdef CONFIG_INPUT_BMP180 +static void bmp180_power_on(int onoff); +#endif + +#ifdef CONFIG_SENSORS_CM36651 +static void cm36651_power_on(int onoff); +#endif + +#if defined(CONFIG_SENSORS_AK8975) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_INPUT_BMP180) || defined(CONFIG_OPTICAL_GP2A) || \ + defined(CONFIG_OPTICAL_GP2AP020A00F) || \ + defined(CONFIG_SENSORS_CM36651) +enum { + SNS_PWR_OFF, + SNS_PWR_ON, + SNS_PWR_KEEP +}; +#endif + + +#if defined(CONFIG_SENSORS_AK8975) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_INPUT_BMP180) || defined(CONFIG_OPTICAL_GP2A) +static void sensor_power_on_vdd(int, int); + +#endif + +#ifndef CONFIG_S5C73M3 +#define KS8851_RST_GPIO 89 +#define KS8851_IRQ_GPIO 90 +#endif + + +#define HAP_SHIFT_LVL_OE_GPIO 47 + +#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE) + +struct sx150x_platform_data msm8960_sx150x_data[] = { + [SX150X_CAM] = { + .gpio_base = GPIO_CAM_EXPANDER_BASE, + .oscio_is_gpo = false, + .io_pullup_ena = 0x0, + .io_pulldn_ena = 0xc0, + .io_open_drain_ena = 0x0, + .irq_summary = -1, + }, +}; + +#endif + +#ifdef CONFIG_I2C + +#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3 +#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10 + +#endif + +#if 0 +static struct gpiomux_setting sec_ts_ldo_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting sec_ts_ldo_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct msm_gpiomux_config msm8960_sec_ts_configs[] = { + { /* TS LDO EN */ + .gpio = 10, + .settings = { + [GPIOMUX_ACTIVE] = &sec_ts_ldo_act_cfg, + [GPIOMUX_SUSPENDED] = &sec_ts_ldo_sus_cfg, + }, + }, +}; +#endif +#define MSM_PMEM_ADSP_SIZE 0x9600000 /* 150 Mbytes */ +#define MSM_PMEM_ADSP_SIZE_FOR_2GB 0xA500000 /* 165 Mbytes */ +#define MSM_PMEM_AUDIO_SIZE 0x4CF000 /* 1.375 Mbytes */ +#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */ +#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */ +#define MSM_HDMI_PRIM_PMEM_SIZE 0x4000000 /* 64 Mbytes */ + +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +#define HOLE_SIZE 0x20000 +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x280000 /* 2.5MB */ +#ifdef CONFIG_MSM_IOMMU +#define MSM_ION_MM_SIZE 0x3800000 +#define MSM_ION_SF_SIZE 0x0 +#define MSM_ION_SF_SIZE_FOR_2GB 0x0 +#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */ +#define MSM_ION_HEAP_NUM 7 +#else +#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE +#define MSM_ION_SF_SIZE 0x5000000 /* 80MB */ +#define MSM_ION_SF_SIZE_FOR_2GB 0x6400000 /* 100MB */ +#define MSM_ION_QSECOM_SIZE 0x1700000 /* (24MB) */ +#define MSM_ION_HEAP_NUM 8 +#endif +#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */ +#define MSM_ION_MFC_SIZE SZ_8K +#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE + +#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000) +#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE +#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE + +#define MSM8960_FIXED_AREA_START 0xb0000000 +#define MAX_FIXED_AREA_SIZE 0x10000000 +#define MSM_MM_FW_SIZE 0x200000 +#define MSM8960_FW_START (MSM8960_FIXED_AREA_START - MSM_MM_FW_SIZE) + +static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE; +#else +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000 +#define MSM_ION_HEAP_NUM 1 +#endif + +#ifdef CONFIG_KERNEL_PMEM_EBI_REGION +static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE; +static int __init pmem_kernel_ebi1_size_setup(char *p) +{ + pmem_kernel_ebi1_size = memparse(p, NULL); + return 0; +} +early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); +#endif + +#ifdef CONFIG_ANDROID_PMEM +static unsigned pmem_size = MSM_PMEM_SIZE; +static unsigned pmem_param_set; +static int __init pmem_size_setup(char *p) +{ + pmem_size = memparse(p, NULL); + pmem_param_set = 1; + return 0; +} +early_param("pmem_size", pmem_size_setup); + +static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE; + +static int __init pmem_adsp_size_setup(char *p) +{ + pmem_adsp_size = memparse(p, NULL); + return 0; +} +early_param("pmem_adsp_size", pmem_adsp_size_setup); + +static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE; + +static int __init pmem_audio_size_setup(char *p) +{ + pmem_audio_size = memparse(p, NULL); + return 0; +} +early_param("pmem_audio_size", pmem_audio_size_setup); +#endif + +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem", + .allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING, + .cached = 1, + .memory_type = MEMTYPE_EBI1, +}; + +static struct platform_device android_pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = {.platform_data = &android_pmem_pdata}, +}; + +static struct android_pmem_platform_data android_pmem_adsp_pdata = { + .name = "pmem_adsp", + .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, + .cached = 0, + .memory_type = MEMTYPE_EBI1, +}; +static struct platform_device android_pmem_adsp_device = { + .name = "android_pmem", + .id = 2, + .dev = { .platform_data = &android_pmem_adsp_pdata }, +}; + +static struct android_pmem_platform_data android_pmem_audio_pdata = { + .name = "pmem_audio", + .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, + .cached = 0, + .memory_type = MEMTYPE_EBI1, +}; + +static struct platform_device android_pmem_audio_device = { + .name = "android_pmem", + .id = 4, + .dev = { .platform_data = &android_pmem_audio_pdata }, +}; +#endif +#endif + +struct fmem_platform_data fmem_pdata = { +}; + +#define DSP_RAM_BASE_8960 0x8da00000 +#define DSP_RAM_SIZE_8960 0x1800000 +static int dspcrashd_pdata_8960 = 0xDEADDEAD; + +static struct resource resources_dspcrashd_8960[] = { + { + .name = "msm_dspcrashd", + .start = DSP_RAM_BASE_8960, + .end = DSP_RAM_BASE_8960 + DSP_RAM_SIZE_8960, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device msm_device_dspcrashd_8960 = { + .name = "msm_dspcrashd", + .num_resources = ARRAY_SIZE(resources_dspcrashd_8960), + .resource = resources_dspcrashd_8960, + .dev = { .platform_data = &dspcrashd_pdata_8960 }, +}; + +static struct memtype_reserve msm8960_reserve_table[] __initdata = { + [MEMTYPE_SMI] = { + }, + [MEMTYPE_EBI0] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, + [MEMTYPE_EBI1] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, +}; + +#if defined(CONFIG_MSM_RTB) +static struct msm_rtb_platform_data msm_rtb_pdata = { + .size = SZ_1M, +}; + +static int __init msm_rtb_set_buffer_size(char *p) +{ + int s; + + s = memparse(p, NULL); + msm_rtb_pdata.size = ALIGN(s, SZ_4K); + return 0; +} +early_param("msm_rtb_size", msm_rtb_set_buffer_size); + +static struct platform_device msm_rtb_device = { + .name = "msm_rtb", + .id = -1, + .dev = { + .platform_data = &msm_rtb_pdata, + }, +}; +#endif + +static void __init reserve_rtb_memory(void) +{ +#if defined(CONFIG_MSM_RTB) + msm8960_reserve_table[MEMTYPE_EBI1].size += msm_rtb_pdata.size; +#endif +} + +static void __init size_pmem_devices(void) +{ +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + android_pmem_adsp_pdata.size = pmem_adsp_size; + + if (!pmem_param_set) { + if (machine_is_msm8960_liquid()) + pmem_size = MSM_LIQUID_PMEM_SIZE; + if (msm8960_hdmi_as_primary_selected()) + pmem_size = MSM_HDMI_PRIM_PMEM_SIZE; + } + + android_pmem_pdata.size = pmem_size; + android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE; +#endif +#endif +} +#if 0 +static void __init reserve_memory_for(struct android_pmem_platform_data *p) +{ + msm8960_reserve_table[p->memory_type].size += p->size; +} +#endif +static void __init reserve_pmem_memory(void) +{ +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + reserve_memory_for(&android_pmem_adsp_pdata); + reserve_memory_for(&android_pmem_pdata); + reserve_memory_for(&android_pmem_audio_pdata); +#endif + msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; +#endif +} + +static int msm8960_paddr_to_memtype(unsigned int paddr) +{ + return MEMTYPE_EBI1; +} + +#define FMEM_ENABLED 0 + +#ifdef CONFIG_ION_MSM +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +static struct ion_cp_heap_pdata cp_mm_ion_pdata = { + .permission_type = IPT_TYPE_MM_CARVEOUT, + .align = SZ_64K, + .reusable = FMEM_ENABLED, + .mem_is_fmem = FMEM_ENABLED, + .fixed_position = FIXED_MIDDLE, + .iommu_map_all = 1, + .iommu_2x_map_domain = VIDEO_DOMAIN, +}; + +static struct ion_cp_heap_pdata cp_mfc_ion_pdata = { + .permission_type = IPT_TYPE_MFC_SHAREDMEM, + .align = PAGE_SIZE, + .reusable = 0, + .mem_is_fmem = FMEM_ENABLED, + .fixed_position = FIXED_HIGH, +}; + +static struct ion_co_heap_pdata co_ion_pdata = { + .adjacent_mem_id = INVALID_HEAP_ID, + .align = PAGE_SIZE, + .mem_is_fmem = 0, +}; + +static struct ion_co_heap_pdata fw_co_ion_pdata = { + .adjacent_mem_id = ION_CP_MM_HEAP_ID, + .align = SZ_128K, + .mem_is_fmem = FMEM_ENABLED, + .fixed_position = FIXED_LOW, +}; +#endif + +struct ion_platform_heap m2_ion_heaps[] = { + { + .id = ION_SYSTEM_HEAP_ID, + .type = ION_HEAP_TYPE_SYSTEM, + .name = ION_VMALLOC_HEAP_NAME, + }, +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + { + .id = ION_CP_MM_HEAP_ID, + .type = ION_HEAP_TYPE_CP, + .name = ION_MM_HEAP_NAME, + .size = MSM_ION_MM_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &cp_mm_ion_pdata, + }, + { + .id = ION_MM_FIRMWARE_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_MM_FIRMWARE_HEAP_NAME, + .size = MSM_ION_MM_FW_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &fw_co_ion_pdata, + }, + { + .id = ION_CP_MFC_HEAP_ID, + .type = ION_HEAP_TYPE_CP, + .name = ION_MFC_HEAP_NAME, + .size = MSM_ION_MFC_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &cp_mfc_ion_pdata, + }, +#ifndef CONFIG_MSM_IOMMU + { + .id = ION_SF_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_SF_HEAP_NAME, + .size = MSM_ION_SF_SIZE_FOR_2GB, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &co_ion_pdata, + }, +#endif + { + .id = ION_IOMMU_HEAP_ID, + .type = ION_HEAP_TYPE_IOMMU, + .name = ION_IOMMU_HEAP_NAME, + }, + { + .id = ION_QSECOM_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_QSECOM_HEAP_NAME, + .size = MSM_ION_QSECOM_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &co_ion_pdata, + }, + { + .id = ION_AUDIO_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_HEAP_NAME, + .size = MSM_ION_AUDIO_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &co_ion_pdata, + }, +#endif +}; + +#if 0 +static u64 msm_dmamask = DMA_BIT_MASK(32); +static struct platform_device ion_mm_heap_device = { + .name = "ion-mm-heap-device", + .id = -1, + .dev = { + .dma_mask = &msm_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif +/** + * These heaps are listed in the order they will be allocated. Due to + * video hardware restrictions and content protection the FW heap has to + * be allocated adjacent (below) the MM heap and the MFC heap has to be + * allocated after the MM heap to ensure MFC heap is not more than 256MB + * away from the base address of the FW heap. + * However, the order of FW heap and MM heap doesn't matter since these + * two heaps are taken care of by separate code to ensure they are adjacent + * to each other. + * Don't swap the order unless you know what you are doing! + */ +static struct ion_platform_data ion_pdata = { + .nr = MSM_ION_HEAP_NUM, + .heaps = m2_ion_heaps, +}; + + +static struct platform_device ion_dev = { + .name = "ion-msm", + .id = 1, + .dev = { .platform_data = &ion_pdata }, +}; +#endif + +struct platform_device fmem_device = { + .name = "fmem", + .id = 1, + .dev = { .platform_data = &fmem_pdata }, +}; + +static void __init adjust_mem_for_liquid(void) +{ + unsigned int i; + + if (!pmem_param_set) { + if (machine_is_msm8960_liquid()) + msm_ion_sf_size = MSM_LIQUID_ION_SF_SIZE; + + if (msm8960_hdmi_as_primary_selected()) + msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE; + + if (machine_is_msm8960_liquid() || + msm8960_hdmi_as_primary_selected()) { + for (i = 0; i < ion_pdata.nr; i++) { + if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) { + ion_pdata.heaps[i].size = + msm_ion_sf_size; + pr_debug("msm_ion_sf_size 0x%x\n", + msm_ion_sf_size); + break; + } + } + } + } +} + +static void __init reserve_mem_for_ion(enum ion_memory_types mem_type, + unsigned long size) +{ + msm8960_reserve_table[mem_type].size += size; +} + +static void __init msm8960_reserve_fixed_area(unsigned long fixed_area_size) +{ +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + int ret; + + if (fixed_area_size > MAX_FIXED_AREA_SIZE) + panic("fixed area size is larger than %dM\n", + MAX_FIXED_AREA_SIZE >> 20); + + reserve_info->fixed_area_size = fixed_area_size; + reserve_info->fixed_area_start = MSM8960_FW_START; + + ret = memblock_remove(reserve_info->fixed_area_start, + reserve_info->fixed_area_size); + BUG_ON(ret); +#endif +} + + +/** + * Reserve memory for ION and calculate amount of reusable memory for fmem. + * We only reserve memory for heaps that are not reusable. However, we only + * support one reusable heap at the moment so we ignore the reusable flag for + * other than the first heap with reusable flag set. Also handle special case + * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be + * at a higher address than FW in addition to not more than 256MB away from the + * base address of the firmware. This means that if MM is reusable the other + * two heaps must be allocated in the same region as FW. This is handled by the + * mem_is_fmem flag in the platform data. In addition the MM heap must be + * adjacent to the FW heap for content protection purposes. + */ +static void __init reserve_ion_memory(void) +{ +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + unsigned int i; + unsigned int reusable_count = 0; + unsigned int fixed_size = 0; + unsigned int fixed_low_size, fixed_middle_size, fixed_high_size; + unsigned long fixed_low_start, fixed_middle_start, fixed_high_start; + struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1]; + + adjust_mem_for_liquid(); + fmem_pdata.size = 0; + fmem_pdata.reserved_size_low = 0; + fmem_pdata.reserved_size_high = 0; + fmem_pdata.align = PAGE_SIZE; + fixed_low_size = 0; + fixed_middle_size = 0; + fixed_high_size = 0; + + /* We only support 1 reusable heap. Check if more than one heap + * is specified as reusable and set as non-reusable if found. + */ + for (i = 0; i < ion_pdata.nr; ++i) { + struct ion_platform_heap *heap = &(ion_pdata.heaps[i]); + + if ((int)heap->type == ION_HEAP_TYPE_CP && heap->extra_data) { + struct ion_cp_heap_pdata *data = heap->extra_data; + + reusable_count += (data->reusable) ? 1 : 0; + + if (data->reusable && reusable_count > 1) { + pr_err("%s: Too many heaps specified as " + "reusable. Heap %s was not configured " + "as reusable.\n", __func__, heap->name); + data->reusable = 0; + } + } + } + + for (i = 0; i < ion_pdata.nr; ++i) { + struct ion_platform_heap *heap = + &(ion_pdata.heaps[i]); + int align = SZ_4K; + int iommu_map_all = 0; + int adjacent_mem_id = INVALID_HEAP_ID; + + if (heap->extra_data) { + int fixed_position = NOT_FIXED; + int mem_is_fmem = 0; + + if (!strcmp(heap->name, "mm") + && (mb->start >= 0xc0000000)) { + printk(KERN_ERR "heap->name %s, mb->start %x\n", + heap->name, mb->start); + heap->size = MSM_PMEM_ADSP_SIZE_FOR_2GB; + } + + switch ((int)heap->type) { + case ION_HEAP_TYPE_CP: + mem_is_fmem = ((struct ion_cp_heap_pdata *) + heap->extra_data)->mem_is_fmem; + fixed_position = ((struct ion_cp_heap_pdata *) + heap->extra_data)->fixed_position; + align = ((struct ion_cp_heap_pdata *) + heap->extra_data)->align; + iommu_map_all = + ((struct ion_cp_heap_pdata *) + heap->extra_data)->iommu_map_all; + break; + case ION_HEAP_TYPE_CARVEOUT: + mem_is_fmem = ((struct ion_co_heap_pdata *) + heap->extra_data)->mem_is_fmem; + fixed_position = ((struct ion_co_heap_pdata *) + heap->extra_data)->fixed_position; + adjacent_mem_id = ((struct ion_co_heap_pdata *) + heap->extra_data)->adjacent_mem_id; + break; + default: + break; + } + + if (iommu_map_all) { + if (heap->size & (SZ_64K-1)) { + heap->size = ALIGN(heap->size, SZ_64K); + pr_info("Heap %s not aligned to 64K. Adjusting size to %x\n", + heap->name, heap->size); + } + } + + if (mem_is_fmem && adjacent_mem_id != INVALID_HEAP_ID) + fmem_pdata.align = align; + + if (fixed_position != NOT_FIXED) + fixed_size += heap->size; + else + reserve_mem_for_ion(MEMTYPE_EBI1, heap->size); + + if (fixed_position == FIXED_LOW) + fixed_low_size += heap->size; + else if (fixed_position == FIXED_MIDDLE) + fixed_middle_size += heap->size; + else if (fixed_position == FIXED_HIGH) + fixed_high_size += heap->size; + + if (mem_is_fmem) + fmem_pdata.size += heap->size; + } + } + + if (!fixed_size) + return; + + if (fmem_pdata.size) { + fmem_pdata.reserved_size_low = fixed_low_size; + fmem_pdata.reserved_size_high = fixed_high_size; + } + + msm8960_reserve_fixed_area(fixed_size + MSM_MM_FW_SIZE); + + fixed_low_start = MSM8960_FIXED_AREA_START; + fixed_middle_start = fixed_low_start + fixed_low_size; + fixed_high_start = fixed_middle_start + fixed_middle_size; + + for (i = 0; i < ion_pdata.nr; ++i) { + struct ion_platform_heap *heap = &(ion_pdata.heaps[i]); + + if (heap->extra_data) { + int fixed_position = NOT_FIXED; + + switch ((int)heap->type) { + case ION_HEAP_TYPE_CP: + fixed_position = ((struct ion_cp_heap_pdata *) + heap->extra_data)->fixed_position; + break; + case ION_HEAP_TYPE_CARVEOUT: + fixed_position = ((struct ion_co_heap_pdata *) + heap->extra_data)->fixed_position; + break; + default: + break; + } + + switch (fixed_position) { + case FIXED_LOW: + heap->base = fixed_low_start; + break; + case FIXED_MIDDLE: + heap->base = fixed_middle_start; + break; + case FIXED_HIGH: + heap->base = fixed_high_start; + break; + default: + break; + } + } + } +#endif +} + +static void ion_adjust_secure_allocation(void) +{ + int i; + + for (i = 0; i < ion_pdata.nr; i++) { + struct ion_platform_heap *heap = + &(ion_pdata.heaps[i]); + + + if (heap->extra_data) { + switch ((int) heap->type) { + case ION_HEAP_TYPE_CP: + if (cpu_is_msm8960()) { + ((struct ion_cp_heap_pdata *) + heap->extra_data)->no_nonsecure_alloc = + 0; + } + + } + } + } +} + +static void __init reserve_mdp_memory(void) +{ + msm8960_mdp_writeback(msm8960_reserve_table); +} + +#if defined(CONFIG_MSM_CACHE_DUMP) +static struct msm_cache_dump_platform_data msm_cache_dump_pdata = { + .l2_size = L2_BUFFER_SIZE, +}; + +static struct platform_device msm_cache_dump_device = { + .name = "msm_cache_dump", + .id = -1, + .dev = { + .platform_data = &msm_cache_dump_pdata, + }, +}; + +#endif + +static void reserve_cache_dump_memory(void) +{ +#ifdef CONFIG_MSM_CACHE_DUMP + unsigned int spare; + unsigned int l1_size; + unsigned int total; + int ret; + + ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_GET_SIZE_COMMAND_ID, &spare, + sizeof(spare), &l1_size, sizeof(l1_size)); + + if (ret) + /* Fall back to something reasonable here */ + l1_size = L1_BUFFER_SIZE; + + total = l1_size + L2_BUFFER_SIZE; + + msm8960_reserve_table[MEMTYPE_EBI1].size += total; + msm_cache_dump_pdata.l1_size = l1_size; +#endif +} + +static void __init msm8960_calculate_reserve_sizes(void) +{ + size_pmem_devices(); + reserve_pmem_memory(); + reserve_ion_memory(); + reserve_mdp_memory(); + reserve_rtb_memory(); + reserve_cache_dump_memory(); +} + +static struct reserve_info msm8960_reserve_info __initdata = { + .memtype_reserve_table = msm8960_reserve_table, + .calculate_reserve_sizes = msm8960_calculate_reserve_sizes, + .reserve_fixed_area = msm8960_reserve_fixed_area, + .paddr_to_memtype = msm8960_paddr_to_memtype, +}; + +static int msm8960_memory_bank_size(void) +{ + return 1<<29; +} + +static void __init locate_unstable_memory(void) +{ + struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1]; + unsigned long bank_size; + unsigned long low, high; + + bank_size = msm8960_memory_bank_size(); + low = meminfo.bank[0].start; + high = mb->start + mb->size; + + /* Check if 32 bit overflow occured */ + if (high < mb->start) { + high = ~0UL; + mb->size-= 1 << 12; + } + + low &= ~(bank_size - 1); + + if (high - low <= bank_size) + return; + + msm8960_reserve_info.bank_size = bank_size; +#ifdef CONFIG_ENABLE_DMM + msm8960_reserve_info.low_unstable_address = mb->start - + MIN_MEMORY_BLOCK_SIZE + mb->size; + msm8960_reserve_info.max_unstable_size = 0 /* MIN_MEMORY_BLOCK_SIZE */; + pr_info("low unstable address %lx max size %lx bank size %lx\n", + msm8960_reserve_info.low_unstable_address, + msm8960_reserve_info.max_unstable_size, + msm8960_reserve_info.bank_size); +#else + msm8960_reserve_info.low_unstable_address = 0; + msm8960_reserve_info.max_unstable_size = 0; +#endif +} + +static void __init place_movable_zone(void) +{ +#ifdef CONFIG_ENABLE_DMM + movable_reserved_start = msm8960_reserve_info.low_unstable_address; + movable_reserved_size = msm8960_reserve_info.max_unstable_size; + pr_info("movable zone start %lx size %lx\n", + movable_reserved_start, movable_reserved_size); +#endif +} + +static void __init msm8960_early_memory(void) +{ + reserve_info = &msm8960_reserve_info; + locate_unstable_memory(); + place_movable_zone(); +} + +static char prim_panel_name[PANEL_NAME_MAX_LEN]; +static char ext_panel_name[PANEL_NAME_MAX_LEN]; +static int __init prim_display_setup(char *param) +{ + if (strnlen(param, PANEL_NAME_MAX_LEN)) + strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN); + return 0; +} +early_param("prim_display", prim_display_setup); + +static int __init ext_display_setup(char *param) +{ + if (strnlen(param, PANEL_NAME_MAX_LEN)) + strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN); + return 0; +} +early_param("ext_display", ext_display_setup); + +/* Exclude the last 4 kB to preserve the kexec hardboot page. */ +#ifdef CONFIG_ANDROID_RAM_CONSOLE +#define RAM_CONSOLE_START 0x9fde0000 +#define RAM_CONSOLE_SIZE 0x20000 + +static struct platform_device ram_console_device = { + .name = "ram_console", + .id = -1, +}; + +struct persistent_ram_descriptor ram_console_desc = { + .name = "ram_console", + .size = RAM_CONSOLE_SIZE, +}; + +struct persistent_ram ram_console_ram = { + .start = RAM_CONSOLE_START, + .size = RAM_CONSOLE_SIZE, + .num_descs = 1, + .descs = &ram_console_desc, +}; +#endif + +unsigned int address = 0xea000000; +unsigned int size = 0x100000; + +static void __init msm8960_reserve(void) +{ + int ret; + msm8960_set_display_params(prim_panel_name, ext_panel_name); + msm_reserve(); + if (fmem_pdata.size) { +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + if (reserve_info->fixed_area_size) { + fmem_pdata.phys = + reserve_info->fixed_area_start + MSM_MM_FW_SIZE; + pr_info("mm fw at %lx (fixed) size %x\n", + reserve_info->fixed_area_start, MSM_MM_FW_SIZE); + pr_info("fmem start %lx (fixed) size %lx\n", + fmem_pdata.phys, + fmem_pdata.size); + } +#endif + } + + if (system_rev >= 14) { + pr_err("Reserving memory at address %x size: %x\n", address, size); + ret = memblock_remove(address, size); + BUG_ON(ret); + } + +#ifdef CONFIG_KEXEC_HARDBOOT + memblock_remove(KEXEC_HB_PAGE_ADDR, SZ_4K); +#endif +} + +static int msm8960_change_memory_power(u64 start, u64 size, + int change_type) +{ + return soc_change_memory_power(start, size, change_type); +} + +static void __init msm8960_allocate_memory_regions(void) +{ + msm8960_allocate_fb_region(); +#ifdef CONFIG_ANDROID_RAM_CONSOLE + persistent_ram_early_init(&ram_console_ram); +#endif + +} +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +static void cypress_power_onoff(int onoff) +{ + int ret, rc; + static struct regulator *reg_l29, *reg_l10; + + pr_debug("power on entry\n"); + + if (!reg_l29) { + reg_l29 = regulator_get(NULL, "8921_l29"); + ret = regulator_set_voltage(reg_l29, 1800000, 1800000); + + if (IS_ERR(reg_l29)) { + pr_err("could not get 8921_l29, rc = %ld\n", + PTR_ERR(reg_l29)); + return; + } + } + + if (!reg_l10) { + reg_l10 = regulator_get(NULL, "8921_l10"); + ret = regulator_set_voltage(reg_l10, 3000000, 3000000); + + if (IS_ERR(reg_l10)) { + pr_err("could not get 8921_l10, rc = %ld\n", + PTR_ERR(reg_l10)); + return; + } + } + + if (onoff) { + ret = regulator_enable(reg_l29); + rc = regulator_enable(reg_l10); + if (ret) { + pr_err("enable l29 failed, rc=%d\n", ret); + return; + } + if (rc) { + pr_err("enable l10 failed, rc=%d\n", ret); + return; + } + pr_info("cypress_power_on is finished.\n"); + } else { + ret = regulator_disable(reg_l29); + rc = regulator_disable(reg_l10); + if (ret) { + pr_err("disable l29 failed, rc=%d\n", ret); + return; + } + if (rc) { + pr_err("enable l29failed, rc=%d\n", ret); + return; + } + pr_info("cypress_power_off is finished.\n"); + } +} + +static u8 touchkey_keycode[] = {KEY_BACK, KEY_MENU}; + +static struct cypress_touchkey_platform_data cypress_touchkey_pdata = { + .gpio_int = GPIO_TOUCH_KEY_INT, + .touchkey_keycode = touchkey_keycode, + .power_onoff = cypress_power_onoff, +}; + +static struct i2c_board_info touchkey_i2c_devices_info[] __initdata = { + { + I2C_BOARD_INFO("cypress_touchkey", 0x20), + .platform_data = &cypress_touchkey_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_TOUCH_KEY_INT), + }, +}; + +static struct i2c_gpio_platform_data cypress_touchkey_i2c_gpio_data = { + .sda_pin = GPIO_TOUCHKEY_SDA, + .scl_pin = GPIO_TOUCHKEY_SCL, + .udelay = 0, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0, +}; + +static struct platform_device touchkey_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_TOUCHKEY_I2C_BUS_ID, + .dev.platform_data = &cypress_touchkey_i2c_gpio_data, +}; + +#endif + +#ifdef CONFIG_USB_SWITCH_FSA9485 +static enum cable_type_t set_cable_status; +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD +static void fsa9485_mhl_cb(bool attached, int mhl_charge) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_mhl_cb attached (%d), mhl_charge(%d)\n", + attached, mhl_charge); + + if (attached) { + switch (mhl_charge) { + case 0: + case 1: + set_cable_status = CABLE_TYPE_USB; + break; + case 2: + set_cable_status = CABLE_TYPE_AC; + break; + } + } else { + set_cable_status = CABLE_TYPE_NONE; + } + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_USB: + value.intval = POWER_SUPPLY_TYPE_USB; + break; + case CABLE_TYPE_AC: + value.intval = POWER_SUPPLY_TYPE_MAINS; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("%s: invalid cable :%d\n", __func__, set_cable_status); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} +#else +static void fsa9485_mhl_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_mhl_cb attached %d\n", attached); + set_cable_status = attached ? CABLE_TYPE_MISC : CABLE_TYPE_NONE; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_MISC: + value.intval = POWER_SUPPLY_TYPE_MISC; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("%s: invalid cable :%d\n", __func__, set_cable_status); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} +#endif +static void fsa9485_otg_cb(bool attached) +{ + pr_info("fsa9485_otg_cb attached %d\n", attached); + + if (attached) { + pr_info("%s set id state\n", __func__); +// msm_otg_set_id_state(attached); + } +} + +static void fsa9485_usb_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_usb_cb attached %d\n", attached); + set_cable_status = attached ? CABLE_TYPE_USB : CABLE_TYPE_NONE; + + if (system_rev >= 0x3) { +// if (attached) { + pr_info("%s set vbus state\n", __func__); + msm_otg_set_vbus_state(attached); +// } + } + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_USB: + value.intval = POWER_SUPPLY_TYPE_USB; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("%s: invalid cable :%d\n", __func__, set_cable_status); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} + +static void fsa9485_charger_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9480_charger_cb attached %d\n", attached); + set_cable_status = attached ? CABLE_TYPE_AC : CABLE_TYPE_NONE; + + msm_otg_set_charging_state(attached); + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + +#ifdef CONFIG_TOUCHSCREEN_MMS144 + if (charger_callbacks && charger_callbacks->inform_charger) + charger_callbacks->inform_charger(charger_callbacks, attached); +#endif + + switch (set_cable_status) { + case CABLE_TYPE_AC: + value.intval = POWER_SUPPLY_TYPE_MAINS; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} + +static void fsa9485_uart_cb(bool attached) +{ + pr_info("fsa9485_uart_cb attached %d\n", attached); + + set_cable_status = attached ? CABLE_TYPE_UARTOFF : CABLE_TYPE_NONE; +} + +static struct switch_dev switch_dock = { + .name = "dock", +}; + +static void fsa9485_jig_cb(bool attached) +{ + pr_info("fsa9485_jig_cb attached %d\n", attached); + + set_cable_status = attached ? CABLE_TYPE_JIG : CABLE_TYPE_NONE; +} + +static void fsa9485_dock_cb(int attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9480_dock_cb attached %d\n", attached); + switch_set_state(&switch_dock, attached); + + set_cable_status = attached ? CABLE_TYPE_CARDOCK : CABLE_TYPE_NONE; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_CARDOCK: + value.intval = POWER_SUPPLY_TYPE_CARDOCK; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} + +static void fsa9485_usb_cdp_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_usb_cdp_cb attached %d\n", attached); + + set_cable_status = + attached ? CABLE_TYPE_CDP : CABLE_TYPE_NONE; + + if (system_rev >= 0x3) { + if (attached) { + pr_info("%s set vbus state\n", __func__); + msm_otg_set_vbus_state(attached); + } + } + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_CDP: + value.intval = POWER_SUPPLY_TYPE_USB_CDP; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } + +} +static void fsa9485_smartdock_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_smartdock_cb attached %d\n", attached); + + set_cable_status = + attached ? CABLE_TYPE_SMART_DOCK : CABLE_TYPE_NONE; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_SMART_DOCK: + value.intval = POWER_SUPPLY_TYPE_USB_CDP; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } + +// msm_otg_set_smartdock_state(attached); +} + +static void fsa9485_audio_dock_cb(bool attached) +{ + pr_info("fsa9485_audio_dock_cb attached %d\n", attached); + +// msm_otg_set_smartdock_state(attached); +} + +static int fsa9485_dock_init(void) +{ + int ret; + + /* for CarDock, DeskDock */ + ret = switch_dev_register(&switch_dock); + if (ret < 0) { + pr_err("Failed to register dock switch. %d\n", ret); + return ret; + } + return 0; +} + +int msm8960_get_cable_type(void) +{ +#ifdef CONFIG_WIRELESS_CHARGING + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return -1; + } +#endif + + pr_info("cable type (%d) -----\n", set_cable_status); + + if (set_cable_status != CABLE_TYPE_NONE) { + switch (set_cable_status) { + case CABLE_TYPE_MISC: +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD + fsa9485_mhl_cb(1 , 0); +#else + fsa9485_mhl_cb(1); +#endif + break; + case CABLE_TYPE_USB: + fsa9485_usb_cb(1); + break; + case CABLE_TYPE_AC: + fsa9485_charger_cb(1); + break; +#ifdef CONFIG_WIRELESS_CHARGING + case CABLE_TYPE_WPC: + value.intval = POWER_SUPPLY_TYPE_WPC; + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + break; +#endif + default: + pr_err("invalid status:%d\n", set_cable_status); + break; + } + } + return set_cable_status; +} + +static struct i2c_gpio_platform_data fsa_i2c_gpio_data = { + .sda_pin = GPIO_USB_I2C_SDA, + .scl_pin = GPIO_USB_I2C_SCL, + .udelay = 2, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0, +}; + +static struct platform_device fsa_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_FSA9485_I2C_BUS_ID, + .dev.platform_data = &fsa_i2c_gpio_data, +}; + +static struct fsa9485_platform_data fsa9485_pdata = { + .otg_cb = fsa9485_otg_cb, + .usb_cb = fsa9485_usb_cb, + .charger_cb = fsa9485_charger_cb, + .uart_cb = fsa9485_uart_cb, + .jig_cb = fsa9485_jig_cb, + .dock_cb = fsa9485_dock_cb, + .dock_init = fsa9485_dock_init, + .usb_cdp_cb = fsa9485_usb_cdp_cb, + .smartdock_cb = fsa9485_smartdock_cb, + .audio_dock_cb = fsa9485_audio_dock_cb, +}; + +static struct i2c_board_info micro_usb_i2c_devices_info[] __initdata = { + { + I2C_BOARD_INFO("fsa9485", 0x4A >> 1), + .platform_data = &fsa9485_pdata, + .irq = MSM_GPIO_TO_INT(14), + }, +}; + +#endif + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + +static void msm8960_mhl_gpio_init(void) +{ + int ret; + + ret = gpio_request(GPIO_MHL_EN, "mhl_en"); + if (ret < 0) { + pr_err("mhl_en gpio_request is failed\n"); + return; + } + + ret = gpio_request(GPIO_MHL_RST, "mhl_rst"); + if (ret < 0) { + pr_err("mhl_rst gpio_request is failed\n"); + return; + } + +} + +static void mhl_gpio_config(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_RST, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); +} + +static struct i2c_gpio_platform_data mhl_i2c_gpio_data = { + .sda_pin = GPIO_MHL_SDA, + .scl_pin = GPIO_MHL_SCL, + .udelay = 3,/*(i2c clk speed: 500khz / udelay)*/ +}; + +static struct platform_device mhl_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_MHL_I2C_BUS_ID, + .dev = { + .platform_data = &mhl_i2c_gpio_data, + }, +}; +/* +gpio_interrupt pin is very changable each different h/w_rev or board. +*/ +int get_mhl_int_irq(void) +{ + return MSM_GPIO_TO_INT(GPIO_MHL_INT); +} + +static struct regulator *mhl_l12; + +static void sii9234_hw_onoff(bool onoff) +{ + int rc; + /*VPH_PWR : mhl_power_source + VMHL_3.3V, VSIL_A_1.2V, VMHL_1.8V + just power control with HDMI_EN pin or control Regulator12*/ + if (onoff) { + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + mhl_l12 = regulator_get(NULL, "8921_l12"); + rc = regulator_set_voltage(mhl_l12, 1200000, 1200000); + if (rc) + pr_err("error setting voltage\n"); + rc = regulator_enable(mhl_l12); + if (rc) + pr_err("error enabling regulator\n"); + usleep(1*1000); + gpio_direction_output(GPIO_MHL_EN, 1); + } else { + gpio_direction_output(GPIO_MHL_EN, 0); + if (mhl_l12) { + rc = regulator_disable(mhl_l12); + if (rc) + pr_err("error disabling regulator\n"); + } + + usleep_range(10000, 20000); + + if (gpio_direction_output(GPIO_MHL_RST, 0)) + pr_err("%s error in making GPIO_MHL_RST Low\n" + , __func__); + + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + } + + return; +} + +static void sii9234_hw_reset(void) +{ + usleep_range(10000, 20000); + if (gpio_direction_output(GPIO_MHL_RST, 1)) + printk(KERN_ERR "%s error in making GPIO_MHL_RST HIGH\n", + __func__); + + usleep_range(5000, 20000); + if (gpio_direction_output(GPIO_MHL_RST, 0)) + printk(KERN_ERR "%s error in making GPIO_MHL_RST Low\n", + __func__); + + usleep_range(10000, 20000); + if (gpio_direction_output(GPIO_MHL_RST, 1)) + printk(KERN_ERR "%s error in making GPIO_MHL_RST HIGH\n", + __func__); + msleep(30); +} + +struct sii9234_platform_data sii9234_pdata = { + .get_irq = get_mhl_int_irq, + .hw_onoff = sii9234_hw_onoff, + .hw_reset = sii9234_hw_reset, + .gpio_cfg = mhl_gpio_config, + .swing_level = 0xEB, +#if defined(CONFIG_VIDEO_MHL_V2) + .vbus_present = fsa9485_mhl_cb, +#endif +}; + +static struct i2c_board_info mhl_i2c_board_info[] = { + { + I2C_BOARD_INFO("sii9234_mhl_tx", 0x72>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_tpi", 0x7A>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_hdmi_rx", 0x92>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_cbus", 0xC8>>1), + .platform_data = &sii9234_pdata, + }, +}; +#endif + +#ifdef CONFIG_BATTERY_SEC +static int is_sec_battery_using(void) +{ + if (system_rev >= 0x3) + return 1; + else + return 0; +} + +int check_battery_type(void) +{ + return BATT_TYPE_D2_ACTIVE; +} + +static struct sec_bat_platform_data sec_bat_pdata = { + .fuel_gauge_name = "fuelgauge", + .charger_name = "sec-charger", + .get_cable_type = msm8960_get_cable_type, + .sec_battery_using = is_sec_battery_using, + .check_batt_type = check_battery_type, + .iterm = 100, + .charge_duration = 8 * 60 * 60, + .recharge_duration = 2 * 60 * 60, + .max_voltage = 4350 * 1000, + .recharge_voltage = 4280 * 1000, + .event_block = 600, + .high_block = 450, + .high_recovery = 430, + .low_block = -50, + .low_recovery = 0, + .lpm_high_block = 450, + .lpm_high_recovery = 435, + .lpm_low_block = 0, + .lpm_low_recovery = 15, + .wpc_charging_current = 500, +}; + +static struct platform_device sec_device_battery = { + .name = "sec-battery", + .id = -1, + .dev.platform_data = &sec_bat_pdata, +}; + +static void check_highblock_temp(void) +{ + if (system_rev < 0xd) + sec_bat_pdata.high_block = 600; +} + +#endif /* CONFIG_BATTERY_SEC */ + +static int is_smb347_using(void) +{ + if (system_rev >= 0x3) + return 1; + else + return 0; +} + +#ifdef CONFIG_CHARGER_SMB347 +static int is_smb347_inok_using(void) +{ + if (system_rev >= 0x4) + return 1; + + return 0; +} + +#ifdef CONFIG_WIRELESS_CHARGING +static void smb347_wireless_cb(void) +{ + set_cable_status = CABLE_TYPE_WPC; +} +#endif + +void smb347_hw_init(void) +{ + struct pm_gpio batt_int_param = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .function = PM_GPIO_FUNC_NORMAL, + }; + int rc = 0; + + gpio_tlmm_config(GPIO_CFG(GPIO_INOK_INT, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + + rc = gpio_request(GPIO_INOK_INT, "wpc-detect"); + if (rc < 0) { + pr_err("%s: GPIO_INOK_INT gpio_request failed\n", __func__); + return; + } + rc = gpio_direction_input(GPIO_INOK_INT); + if (rc < 0) { + pr_err("%s: GPIO_INOK_INT gpio_direction_input failed\n", + __func__); + return; + } + + if (system_rev >= 0x6) { + sec_bat_pdata.batt_int = + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT); + pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT), + &batt_int_param); + gpio_request( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT), + "batt_int"); + gpio_direction_input(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT)); + } + pr_debug("%s : share gpioi2c with max17048\n", __func__); +} + +static int smb347_intr_trigger(int status) +{ + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + + if (!psy) { + pr_err("%s: fail to get battery ps\n", __func__); + return -ENODEV; + } + pr_info("%s : charging status =%d\n", __func__, status); + + value.intval = status; + + /*if (status) + value.intval = POWER_SUPPLY_STATUS_CHARGING; + else + value.intval = POWER_SUPPLY_STATUS_DISCHARGING;*/ + + return psy->set_property(psy, POWER_SUPPLY_PROP_STATUS, &value); +} + +static struct smb347_platform_data smb347_pdata = { + .hw_init = smb347_hw_init, + .chg_intr_trigger = smb347_intr_trigger, + .enable = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + .stat = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_CHG_STAT), + .smb347_using = is_smb347_using, + .inok = GPIO_INOK_INT, + .smb347_inok_using = is_smb347_inok_using, +#ifdef CONFIG_WIRELESS_CHARGING + .smb347_wpc_cb = smb347_wireless_cb, +#endif + .smb347_get_cable = msm8960_get_cable_type, +}; +#endif /* CONFIG_CHARGER_SMB347 */ + +#ifdef CONFIG_BATTERY_MAX17040 +void max17040_hw_init(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_FUEKGAUGE_I2C_SCL, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_FUELGAUGE_I2C_SDA, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_set_value(GPIO_FUEKGAUGE_I2C_SCL, 1); + gpio_set_value(GPIO_FUELGAUGE_I2C_SDA, 1); + + gpio_tlmm_config(GPIO_CFG(GPIO_FUEL_INT, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); +} + +static int max17040_low_batt_cb(void) +{ +#ifdef CONFIG_BATTERY_SEC + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + pr_err("%s: Low battery alert\n", __func__); + + + if (!psy) { + pr_err("%s: fail to get battery ps\n", __func__); + return -ENODEV; + } + + value.intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + return psy->set_property(psy, POWER_SUPPLY_PROP_CAPACITY_LEVEL, &value); +#else + pr_err("%s: Low battery alert\n", __func__); + + return 0; +#endif +} + +static struct max17040_platform_data max17043_pdata = { + .hw_init = max17040_hw_init, + .low_batt_cb = max17040_low_batt_cb, + .check_batt_type = check_battery_type, + .rcomp_value = 0x6d1c, +}; + +static struct i2c_gpio_platform_data fuelgauge_i2c_gpio_data = { + .sda_pin = GPIO_FUELGAUGE_I2C_SDA, + .scl_pin = GPIO_FUEKGAUGE_I2C_SCL, + .udelay = 2, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0, +}; + +static struct platform_device fuelgauge_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_FUELGAUGE_I2C_BUS_ID, + .dev.platform_data = &fuelgauge_i2c_gpio_data, +}; + +static struct i2c_board_info fg_i2c_board_info[] = { + { + I2C_BOARD_INFO("max17040", (0x6D >> 1)), + .platform_data = &max17043_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_FUEL_INT), + } +}; + +static struct i2c_board_info fg_smb_i2c_board_info[] = { +#ifdef CONFIG_CHARGER_SMB347 + { + I2C_BOARD_INFO("smb347", (0x0C >> 1)), + .platform_data = &smb347_pdata, + .irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_CHG_STAT), + }, +#endif + { + I2C_BOARD_INFO("max17040", (0x6D >> 1)), + .platform_data = &max17043_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_FUEL_INT), + } +}; +#endif /* CONFIG_BATTERY_MAX17040 */ + +#ifdef CONFIG_VIBETONZ +static struct vibrator_platform_data msm_8960_vibrator_pdata = { + .vib_model = HAPTIC_PWM, + .vib_pwm_gpio = GPIO_VIB_PWM, + .haptic_pwr_en_gpio = GPIO_HAPTIC_PWR_EN, + .vib_en_gpio = GPIO_VIB_ON, + .is_pmic_vib_en = 0, + .is_pmic_haptic_pwr_en = 0, +}; +static struct platform_device vibetonz_device = { + .name = "tspdrv", + .id = -1, + .dev = { + .platform_data = &msm_8960_vibrator_pdata , + }, +}; +#endif /* CONFIG_VIBETONZ */ + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) +static struct i2c_gpio_platform_data opt_i2c_gpio_data = { + .sda_pin = GPIO_SENSOR_ALS_SDA, + .scl_pin = GPIO_SENSOR_ALS_SCL, + .udelay = 5, +}; + +static struct platform_device opt_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_OPT_I2C_BUS_ID, + .dev = { + .platform_data = &opt_i2c_gpio_data, + }, +}; +#if defined(CONFIG_SENSORS_CM36651) +static void cm36651_led_onoff(int); + +static struct cm36651_platform_data cm36651_pdata = { + .cm36651_led_on = cm36651_led_onoff, + .cm36651_power_on = cm36651_power_on, + .irq = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_RGB_INT), + .threshold = 15, +}; +#endif +static struct i2c_board_info opt_i2c_borad_info[] = { + { +#if defined(CONFIG_OPTICAL_GP2A) + I2C_BOARD_INFO("gp2a", 0x88>>1), +#elif defined(CONFIG_OPTICAL_GP2AP020A00F) + I2C_BOARD_INFO("gp2a", 0x72>>1), +#endif + }, +#if defined(CONFIG_SENSORS_CM36651) + { + I2C_BOARD_INFO("cm36651", (0x30 >> 1)), + .platform_data = &cm36651_pdata, + }, +#endif +}; +#if 0 +static void gp2a_led_onoff(int); + +#if defined(CONFIG_OPTICAL_GP2A) +static struct opt_gp2a_platform_data opt_gp2a_data = { + .gp2a_led_on = gp2a_led_onoff, + .power_on = sensor_power_on_vdd, + .irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_RGB_INT), + .ps_status = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_RGB_INT), +}; +#elif defined(CONFIG_OPTICAL_GP2AP020A00F) +static struct gp2a_platform_data opt_gp2a_data = { + .gp2a_led_on = gp2a_led_onoff, + .power_on = gp2a_power_on, + .p_out = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_RGB_INT), + .adapt_num = MSM_OPT_I2C_BUS_ID, + .addr = 0x72>>1, + .version = 0, +}; +#endif + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) +static struct platform_device opt_gp2a = { + .name = "gp2a-opt", + .id = -1, + .dev = { + .platform_data = &opt_gp2a_data, + }, +}; +#endif +#endif +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 + struct mpu_platform_data mpu6050_data = { + .int_config = 0x10, + .orientation = {0, 1, 0, + 1, 0, 0, + 0, 0, -1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }; + + static struct ext_slave_platform_data inv_mpu_ak8963_data_03 = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {-1, 0, 0, + 0, 1, 0, + 0, 0, -1}, + }; + + struct mpu_platform_data mpu6050_data_01 = { + .int_config = 0x10, + .orientation = {0, 1, 0, + 1, 0, 0, + 0, 0, -1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data_01 = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {0, -1, 0, + -1, 0, 0, + 0, 0, -1}, + }; + struct mpu_platform_data mpu6050_data_00 = { + .int_config = 0x10, + .orientation = {1, 0, 0, + 0, -1, 0, + 0, 0, -1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data_00 = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }; +#endif + +#ifdef CONFIG_MPU_SENSORS_MPU6050B1 +#define SENSOR_MPU_NAME "mpu6050B1" +static struct mpu_platform_data mpu_data = { + .int_config = 0x12, + .orientation = {1, 0, 0, + 0, -1, 0, + 0, 0, -1}, + /* accel */ + .accel = { + .get_slave_descr = mantis_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x68, + .orientation = {1, 0, 0, + 0, -1, 0, + 0, 0, -1}, + }, + /* compass */ + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + }, + .poweron = mpu_power_on, +}; + +static struct mpu_platform_data mpu_data_01 = { + .int_config = 0x12, + .orientation = {0, 1, 0, + 1, 0, 0, + 0, 0, -1}, + /* accel */ + .accel = { + .get_slave_descr = mantis_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x68, + .orientation = {0, 1, 0, + 1, 0, 0, + 0, 0, -1}, + }, + /* compass */ + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = {0, -1, 0, + -1, 0, 0, + 0, 0, -1}, + }, + .poweron = mpu_power_on, +}; + +static struct mpu_platform_data mpu_data_00 = { + .int_config = 0x12, + .orientation = {1, 0, 0, + 0, -1, 0, + 0, 0, -1}, + /* accel */ + .accel = { + .get_slave_descr = mantis_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x68, + .orientation = {1, 0, 0, + 0, -1, 0, + 0, 0, -1}, + }, + /* compass */ + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }, + .poweron = mpu_power_on, +}; +#endif /*CONFIG_MPU_SENSORS_MPU6050B1 */ + +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + +#ifdef CONFIG_SENSORS_AK8975 +static struct akm8975_platform_data akm8975_pdata = { + .gpio_data_ready_int = GPIO_MSENSE_RST, + .power_on = akm_power_on, +}; +#endif +#ifdef CONFIG_INPUT_BMP180 +static struct bmp_i2c_platform_data bmp180_pdata = { + .power_on = bmp180_power_on, +}; +#endif + +static struct i2c_board_info sns_i2c_borad_info[] = { +#ifdef CONFIG_MPU_SENSORS_MPU6050B1 + { + I2C_BOARD_INFO(SENSOR_MPU_NAME, 0x68), + .irq = MSM_GPIO_TO_INT(GPIO_MPU3050_INT), + .platform_data = &mpu_data, + }, +#endif +#ifdef CONFIG_SENSORS_AK8975 + { + I2C_BOARD_INFO("ak8975", 0x0C), + .platform_data = &akm8975_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_MSENSE_RST), + }, +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 + { + I2C_BOARD_INFO("mpu6050", 0x68), + .irq = MSM_GPIO_TO_INT(GPIO_MPU3050_INT), + .platform_data = &mpu6050_data, + }, +#endif +#ifdef CONFIG_MPU_SENSORS_AK8975_411 + { + I2C_BOARD_INFO("ak8975_mod", 0x0C), + .platform_data = &inv_mpu_ak8963_data, + .irq = MSM_GPIO_TO_INT(GPIO_MSENSE_RST), + }, +#endif +#ifdef CONFIG_INPUT_BMP180 + { + I2C_BOARD_INFO("bmp180", 0x77), + .platform_data = &bmp180_pdata, + }, +#endif + +}; +#endif + +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static void mpl_init(void) +{ + int ret = 0; + ret = gpio_request(GPIO_MPU3050_INT, "MPUIRQ"); + if (ret) + pr_err("%s gpio request %d err\n", __func__, GPIO_MPU3050_INT); + else + gpio_direction_input(GPIO_MPU3050_INT); + +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) + if (system_rev == BOARD_REV01) + mpu_data = mpu_data_01; + else if (system_rev < BOARD_REV01) + mpu_data = mpu_data_00; + mpu_data.reset = gpio_rev(GPIO_MAG_RST); +#elif defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + if (system_rev == BOARD_REV01) { + mpu6050_data = mpu6050_data_01; + inv_mpu_ak8963_data = inv_mpu_ak8963_data_01; + } else if (system_rev < BOARD_REV01) { + mpu6050_data = mpu6050_data_00; + inv_mpu_ak8963_data = inv_mpu_ak8963_data_00; + } else if (system_rev < BOARD_REV04) { + inv_mpu_ak8963_data = inv_mpu_ak8963_data_03; + } + if (system_rev < BOARD_REV06) + mpu6050_data.reset = gpio_rev(GPIO_MAG_RST); + else + mpu6050_data.reset = + PM8921_GPIO_PM_TO_SYS(gpio_rev(GPIO_MAG_RST)); +#endif +} +#endif + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) +static void opt_init(void) +{ + int ret = 0; + int prox_int = gpio_rev(ALS_INT); + struct pm_gpio prox_cfg = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + }; + + if (system_rev < BOARD_REV06) { + gpio_tlmm_config(GPIO_CFG(prox_int, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + } else { + prox_int = PM8921_GPIO_PM_TO_SYS(prox_int); + pm8xxx_gpio_config(prox_int, &prox_cfg); + } + + gpio_tlmm_config(GPIO_CFG(gpio_rev(ALS_SDA), 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(gpio_rev(ALS_SCL), 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + ret = gpio_request(prox_int, "PSVOUT"); + if (ret) { + pr_err("%s gpio request %d err\n", __func__, prox_int); + } else { + gpio_direction_input(prox_int); + gpio_free(prox_int); + } +} +#endif + +struct class *sec_class; +EXPORT_SYMBOL(sec_class); + +static void samsung_sys_class_init(void) +{ + pr_info("samsung sys class init.\n"); + + sec_class = class_create(THIS_MODULE, "sec"); + + if (IS_ERR(sec_class)) { + pr_err("Failed to create class(sec)!\n"); + return; + } + + pr_info("samsung sys class end.\n"); +}; + +#if defined(CONFIG_NFC_PN544) +static void pn544_conf_gpio(void) +{ + pr_debug("pn544_conf_gpio\n"); + + gpio_tlmm_config(GPIO_CFG(GPIO_NFC_SDA, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_NFC_SCL, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + return; +} + +static int __init pn544_init(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_NFC_IRQ, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + pn544_conf_gpio(); + return 0; +} +#endif + +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) ||\ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + +static int __init sensor_device_init(void) +{ + int ret = 0; + int mag_rst = gpio_rev(GPIO_MAG_RST); + struct pm_gpio mag_rst_cfg = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .disable_pin = 0, + }; + + if (system_rev < BOARD_REV06) { + gpio_tlmm_config(GPIO_CFG(mag_rst, 0, + GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + } else { + mag_rst = PM8921_GPIO_PM_TO_SYS(mag_rst); + pm8xxx_gpio_config(mag_rst, &mag_rst_cfg); + } + sensor_power_on_vdd(SNS_PWR_ON, SNS_PWR_ON); + ret = gpio_request(mag_rst, "MAG_RST"); + if (ret) { + pr_err("%s gpio request %d err\n", __func__, mag_rst); + } else { + gpio_direction_output(mag_rst, 0); + usleep_range(20, 20); + gpio_set_value_cansleep(mag_rst, 1); + } + + return 0; +} +#endif + +#if defined(CONFIG_SENSORS_AK8975) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_INPUT_BMP180) || defined(CONFIG_OPTICAL_GP2A) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static struct regulator *vsensor_2p85, *vsensor_1p8; +static int sensor_power_2p85_cnt, sensor_power_1p8_cnt; + +static void sensor_power_on_vdd(int onoff_l9, int onoff_lvs4) +{ + int ret; + + if (vsensor_2p85 == NULL) { + vsensor_2p85 = regulator_get(NULL, "8921_l9"); + if (IS_ERR(vsensor_2p85)) + return ; + + ret = regulator_set_voltage(vsensor_2p85, 2850000, 2850000); + if (ret) + pr_err("%s: error vsensor_2p85 setting voltage ret=%d\n", + __func__, ret); + } + if (vsensor_1p8 == NULL) { + vsensor_1p8 = regulator_get(NULL, "8921_lvs4"); + if (IS_ERR(vsensor_1p8)) + return ; + } + + if (onoff_l9 == SNS_PWR_ON) { + sensor_power_2p85_cnt++; + ret = regulator_enable(vsensor_2p85); + if (ret) + pr_err("%s: error enabling regulator\n", __func__); + } else if ((onoff_l9 == SNS_PWR_OFF)) { + sensor_power_2p85_cnt--; + if (regulator_is_enabled(vsensor_2p85)) { + ret = regulator_disable(vsensor_2p85); + if (ret) + pr_err("%s: error vsensor_2p85 enabling regulator\n", + __func__); + } + } + if (onoff_lvs4 == SNS_PWR_ON) { + sensor_power_1p8_cnt++; + ret = regulator_enable(vsensor_1p8); + if (ret) + pr_err("%s: error enabling regulator\n", __func__); + } else if ((onoff_lvs4 == SNS_PWR_OFF)) { + sensor_power_1p8_cnt--; + if (regulator_is_enabled(vsensor_1p8)) { + ret = regulator_disable(vsensor_1p8); + if (ret) + pr_err("%s: error vsensor_1p8 enabling regulator\n", + __func__); + } + } +} + +#endif +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static void mpu_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#ifdef CONFIG_SENSORS_AK8975 +static void akm_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#ifdef CONFIG_INPUT_BMP180 +static void bmp180_power_on(int onoff) +{ + sensor_power_on_vdd(SNS_PWR_KEEP, onoff); +} +#endif + +#if defined(CONFIG_OPTICAL_GP2AP020A00F) +static void gp2a_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#if defined(CONFIG_SENSORS_CM36651) +static void cm36651_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) +static void gp2a_led_onoff(int onoff) +{ + static struct regulator *reg_8921_leda; + static int prev_on; + int rc; + + if (onoff == prev_on) + return; + + if (!reg_8921_leda) { + reg_8921_leda = regulator_get(NULL, "8921_l16"); + rc = regulator_set_voltage(reg_8921_leda, + 3000000, 3000000); + if (rc) + pr_err("%s: error reg_8921_leda setting ret=%d\n", + __func__, rc); + } + + if (onoff) { + rc = regulator_enable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator enable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(on): success\n", __func__); + } else { + rc = regulator_disable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator disable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(off): success\n", __func__); + } + prev_on = onoff; +} +#endif + +#if defined(CONFIG_SENSORS_CM36651) + +static void cm36651_led_onoff(int onoff) +{ + static struct regulator *reg_8921_leda; + static int prev_on; + int rc; + + if (onoff == prev_on) + return; + + if (!reg_8921_leda) { + reg_8921_leda = regulator_get(NULL, "8921_l16"); + rc = regulator_set_voltage(reg_8921_leda, + 2800000, 2800000); + if (rc) + pr_err("%s: error reg_8921_leda setting ret=%d\n", + __func__, rc); + return; + } + + if (onoff) { + rc = regulator_enable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator enable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(on): success\n", __func__); + } else { + rc = regulator_disable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator disable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(off): success\n", __func__); + } + prev_on = onoff; +} +#endif + +#ifdef CONFIG_VP_A2220 +static int a2220_hw_init(void) +{ + int rc = 0; + + rc = gpio_request(gpio_rev(A2220_WAKEUP), "a2220_wakeup"); + if (rc < 0) { + pr_err("%s: gpio request wakeup pin failed\n", __func__); + goto err_alloc_data_failed; + } + + rc = gpio_direction_output(gpio_rev(A2220_WAKEUP), 1); + if (rc < 0) { + pr_err("%s: request wakeup gpio direction failed\n", __func__); + goto err_free_gpio; + } + + rc = gpio_request(MSM_AUD_A2220_RESET, "a2220_reset"); + if (rc < 0) { + pr_err("%s: gpio request reset pin failed\n", __func__); + goto err_free_gpio; + } + + rc = gpio_direction_output(MSM_AUD_A2220_RESET, 1); + if (rc < 0) { + pr_err("%s: request reset gpio direction failed\n", __func__); + goto err_free_gpio_all; + } + gpio_set_value(gpio_rev(A2220_WAKEUP), 1); + gpio_set_value(MSM_AUD_A2220_RESET, 1); + return rc; + +err_free_gpio_all: + gpio_free(MSM_AUD_A2220_RESET); +err_free_gpio: + gpio_free(gpio_rev(A2220_WAKEUP)); +err_alloc_data_failed: + pr_err("a2220_probe - failed\n"); + return rc; +} + +static struct a2220_platform_data a2220_data = { + .a2220_hw_init = a2220_hw_init, + .gpio_reset = MSM_AUD_A2220_RESET, +}; + +static struct i2c_board_info a2220_device[] __initdata = { + { + I2C_BOARD_INFO("audience_a2220", 0x3E), + .platform_data = &a2220_data, + }, +}; + +static struct i2c_gpio_platform_data a2220_i2c_gpio_data = { + .udelay = 1, +}; +#if 0 +static struct platform_device a2220_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_A2220_I2C_BUS_ID, + .dev.platform_data = &a2220_i2c_gpio_data, +}; +#endif +static struct gpiomux_setting a2220_gsbi_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_a2220_configs[] = { + { + .settings = { + [GPIOMUX_SUSPENDED] = &a2220_gsbi_config, + }, + }, + { + .settings = { + [GPIOMUX_SUSPENDED] = &a2220_gsbi_config, + }, + }, +}; +#endif +#ifdef CONFIG_WCD9310_CODEC + +#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS) + +/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement + * 4 micbiases are used to power various analog and digital + * microphones operating at 1800 mV. Technically, all micbiases + * can source from single cfilter since all microphones operate + * at the same voltage level. The arrangement below is to make + * sure all cfilters are exercised. LDO_H regulator ouput level + * does not need to be as high as 2.85V. It is choosen for + * microphone sensitivity purpose. + */ +#ifndef CONFIG_SLIMBUS_MSM_CTRL +static struct wcd9xxx_pdata tabla_i2c_platform_data = { + .irq = MSM_GPIO_TO_INT(58), + .irq_base = TABLA_INTERRUPT_BASE, + .num_irqs = NR_TABLA_IRQS, + .reset_gpio = PM8921_GPIO_PM_TO_SYS(38), + .micbias = { + .ldoh_v = TABLA_LDOH_2P85_V, + .cfilt1_mv = 1800, + .cfilt2_mv = 1800, + .cfilt3_mv = 1800, + .bias1_cfilt_sel = TABLA_CFILT1_SEL, + .bias2_cfilt_sel = TABLA_CFILT2_SEL, + .bias3_cfilt_sel = TABLA_CFILT3_SEL, + .bias4_cfilt_sel = TABLA_CFILT3_SEL, + }, + .regulator = { + { + .name = "CDC_VDD_CP", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX, + }, + { + .name = "CDC_VDDA_RX", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX, + }, + { + .name = "CDC_VDDA_TX", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX, + }, + { + .name = "VDDIO_CDC", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX, + }, + { + .name = "VDDD_CDC_D", + .min_uV = 1225000, + .max_uV = 1225000, + .optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX, + }, + { + .name = "CDC_VDDA_A_1P2V", + .min_uV = 1225000, + .max_uV = 1225000, + .optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX, + }, + }, +}; +#endif +#endif +#define MSM_WCNSS_PHYS 0x03000000 +#define MSM_WCNSS_SIZE 0x280000 + +static struct resource resources_wcnss_wlan[] = { + { + .start = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ, + .end = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ, + .name = "wcnss_wlanrx_irq", + .flags = IORESOURCE_IRQ, + }, + { + .start = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ, + .end = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ, + .name = "wcnss_wlantx_irq", + .flags = IORESOURCE_IRQ, + }, + { + .start = MSM_WCNSS_PHYS, + .end = MSM_WCNSS_PHYS + MSM_WCNSS_SIZE - 1, + .name = "wcnss_mmio", + .flags = IORESOURCE_MEM, + }, + { + .start = 84, + .end = 88, + .name = "wcnss_gpios_5wire", + .flags = IORESOURCE_IO, + }, +}; + +static struct qcom_wcnss_opts qcom_wcnss_pdata = { + .has_48mhz_xo = 1, +}; + +static struct platform_device msm_device_wcnss_wlan = { + .name = "wcnss_wlan", + .id = 0, + .num_resources = ARRAY_SIZE(resources_wcnss_wlan), + .resource = resources_wcnss_wlan, + .dev = {.platform_data = &qcom_wcnss_pdata}, +}; + +#ifdef CONFIG_QSEECOM +/* qseecom bus scaling */ +static struct msm_bus_vectors qseecom_clks_init_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = 0, + .ab = 0, + }, +}; + +static struct msm_bus_vectors qseecom_enable_dfab_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = 0, + .ab = 0, + }, +}; + +static struct msm_bus_vectors qseecom_enable_sfpb_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = (64 * 8) * 1000000UL, + .ab = (64 * 8) * 100000UL, + }, +}; + +static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = (64 * 8) * 1000000UL, + .ab = (64 * 8) * 100000UL, + }, +}; + +static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = { + { + ARRAY_SIZE(qseecom_clks_init_vectors), + qseecom_clks_init_vectors, + }, + { + ARRAY_SIZE(qseecom_enable_dfab_vectors), + qseecom_enable_dfab_vectors, + }, + { + ARRAY_SIZE(qseecom_enable_sfpb_vectors), + qseecom_enable_sfpb_vectors, + }, + { + ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors), + qseecom_enable_dfab_sfpb_vectors, + }, +}; + +static struct msm_bus_scale_pdata qseecom_bus_pdata = { + qseecom_hw_bus_scale_usecases, + ARRAY_SIZE(qseecom_hw_bus_scale_usecases), + .name = "qsee", +}; + +static struct platform_device qseecom_device = { + .name = "qseecom", + .id = 0, + .dev = { + .platform_data = &qseecom_bus_pdata, + }, +}; +#endif +#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \ + defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE) + +#define QCE_SIZE 0x10000 +#define QCE_0_BASE 0x18500000 + +#define QCE_HW_KEY_SUPPORT 0 +#define QCE_SHA_HMAC_SUPPORT 1 +#define QCE_SHARE_CE_RESOURCE 1 +#define QCE_CE_SHARED 0 + +/* Begin Bus scaling definitions */ +static struct msm_bus_vectors crypto_hw_init_vectors[] = { + { + .src = MSM_BUS_MASTER_ADM_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, + { + .src = MSM_BUS_MASTER_ADM_PORT1, + .dst = MSM_BUS_SLAVE_GSBI1_UART, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors crypto_hw_active_vectors[] = { + { + .src = MSM_BUS_MASTER_ADM_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 70000000UL, + .ib = 70000000UL, + }, + { + .src = MSM_BUS_MASTER_ADM_PORT1, + .dst = MSM_BUS_SLAVE_GSBI1_UART, + .ab = 2480000000UL, + .ib = 2480000000UL, + }, +}; + +static struct msm_bus_paths crypto_hw_bus_scale_usecases[] = { + { + ARRAY_SIZE(crypto_hw_init_vectors), + crypto_hw_init_vectors, + }, + { + ARRAY_SIZE(crypto_hw_active_vectors), + crypto_hw_active_vectors, + }, +}; + +static struct msm_bus_scale_pdata crypto_hw_bus_scale_pdata = { + crypto_hw_bus_scale_usecases, + ARRAY_SIZE(crypto_hw_bus_scale_usecases), + .name = "cryptohw", +}; +/* End Bus Scaling Definitions*/ + +static struct resource qcrypto_resources[] = { + [0] = { + .start = QCE_0_BASE, + .end = QCE_0_BASE + QCE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "crypto_channels", + .start = DMOV_CE_IN_CHAN, + .end = DMOV_CE_OUT_CHAN, + .flags = IORESOURCE_DMA, + }, + [2] = { + .name = "crypto_crci_in", + .start = DMOV_CE_IN_CRCI, + .end = DMOV_CE_IN_CRCI, + .flags = IORESOURCE_DMA, + }, + [3] = { + .name = "crypto_crci_out", + .start = DMOV_CE_OUT_CRCI, + .end = DMOV_CE_OUT_CRCI, + .flags = IORESOURCE_DMA, + }, +}; + +static struct resource qcedev_resources[] = { + [0] = { + .start = QCE_0_BASE, + .end = QCE_0_BASE + QCE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "crypto_channels", + .start = DMOV_CE_IN_CHAN, + .end = DMOV_CE_OUT_CHAN, + .flags = IORESOURCE_DMA, + }, + [2] = { + .name = "crypto_crci_in", + .start = DMOV_CE_IN_CRCI, + .end = DMOV_CE_IN_CRCI, + .flags = IORESOURCE_DMA, + }, + [3] = { + .name = "crypto_crci_out", + .start = DMOV_CE_OUT_CRCI, + .end = DMOV_CE_OUT_CRCI, + .flags = IORESOURCE_DMA, + }, +}; + +#endif + +#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \ + defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) + +static struct msm_ce_hw_support qcrypto_ce_hw_suppport = { + .ce_shared = QCE_CE_SHARED, + .shared_ce_resource = QCE_SHARE_CE_RESOURCE, + .hw_key_support = QCE_HW_KEY_SUPPORT, + .sha_hmac = QCE_SHA_HMAC_SUPPORT, + .bus_scale_table = &crypto_hw_bus_scale_pdata, +}; + +static struct platform_device qcrypto_device = { + .name = "qcrypto", + .id = 0, + .num_resources = ARRAY_SIZE(qcrypto_resources), + .resource = qcrypto_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &qcrypto_ce_hw_suppport, + }, +}; +#endif + +#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE) + +static struct msm_ce_hw_support qcedev_ce_hw_suppport = { + .ce_shared = QCE_CE_SHARED, + .shared_ce_resource = QCE_SHARE_CE_RESOURCE, + .hw_key_support = QCE_HW_KEY_SUPPORT, + .sha_hmac = QCE_SHA_HMAC_SUPPORT, + .bus_scale_table = &crypto_hw_bus_scale_pdata, +}; + +static struct platform_device qcedev_device = { + .name = "qce", + .id = 0, + .num_resources = ARRAY_SIZE(qcedev_resources), + .resource = qcedev_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &qcedev_ce_hw_suppport, + }, +}; +#endif + +#define MDM2AP_ERRFATAL 70 +#define AP2MDM_ERRFATAL 95 +#define MDM2AP_STATUS 69 +#define AP2MDM_STATUS 94 +#define AP2MDM_PMIC_RESET_N 80 +#define AP2MDM_KPDPWR_N 81 + +static struct resource mdm_resources[] = { + { + .start = MDM2AP_ERRFATAL, + .end = MDM2AP_ERRFATAL, + .name = "MDM2AP_ERRFATAL", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_ERRFATAL, + .end = AP2MDM_ERRFATAL, + .name = "AP2MDM_ERRFATAL", + .flags = IORESOURCE_IO, + }, + { + .start = MDM2AP_STATUS, + .end = MDM2AP_STATUS, + .name = "MDM2AP_STATUS", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_STATUS, + .end = AP2MDM_STATUS, + .name = "AP2MDM_STATUS", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_PMIC_RESET_N, + .end = AP2MDM_PMIC_RESET_N, + .name = "AP2MDM_PMIC_RESET_N", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_KPDPWR_N, + .end = AP2MDM_KPDPWR_N, + .name = "AP2MDM_KPDPWR_N", + .flags = IORESOURCE_IO, + }, +}; + +static struct mdm_platform_data mdm_platform_data = { + .mdm_version = "2.5", +}; + +static struct platform_device mdm_device = { + .name = "mdm2_modem", + .id = -1, + .num_resources = ARRAY_SIZE(mdm_resources), + .resource = mdm_resources, + .dev = { + .platform_data = &mdm_platform_data, + }, +}; + +static struct platform_device *mdm_devices[] __initdata = { + &mdm_device, +}; + +#define MSM_SHARED_RAM_PHYS 0x80000000 + +static void __init msm8960_map_io(void) +{ + msm_shared_ram_phys = MSM_SHARED_RAM_PHYS; + msm_map_msm8960_io(); + + if (socinfo_init() < 0) + pr_err("socinfo_init() failed!\n"); +#ifdef CONFIG_SEC_DEBUG + sec_getlog_supply_meminfo(0x40000000, 0x80000000, 0x00, 0x00); +#endif + +} + +static void __init msm8960_init_irq(void) +{ + struct msm_mpm_device_data *data = NULL; + +#ifdef CONFIG_MSM_MPM + data = &msm8960_mpm_dev_data; +#endif + + msm_mpm_irq_extn_init(data); + gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, + (void *)MSM_QGIC_CPU_BASE); +} + +static void __init msm8960_init_buses(void) +{ +#ifdef CONFIG_MSM_BUS_SCALING + msm_bus_rpm_set_mt_mask(); + msm_bus_8960_apps_fabric_pdata.rpm_enabled = 1; + msm_bus_8960_sys_fabric_pdata.rpm_enabled = 1; + msm_bus_8960_mm_fabric_pdata.rpm_enabled = 1; + msm_bus_apps_fabric.dev.platform_data = + &msm_bus_8960_apps_fabric_pdata; + msm_bus_sys_fabric.dev.platform_data = &msm_bus_8960_sys_fabric_pdata; + msm_bus_mm_fabric.dev.platform_data = &msm_bus_8960_mm_fabric_pdata; + msm_bus_sys_fpb.dev.platform_data = &msm_bus_8960_sys_fpb_pdata; + msm_bus_cpss_fpb.dev.platform_data = &msm_bus_8960_cpss_fpb_pdata; +#endif +} + +#ifdef CONFIG_S5C73M3 +static struct msm_spi_platform_data msm8960_qup_spi_gsbi11_pdata = { + .max_clock_speed = 48000000, /*15060000,*/ +}; +#endif + +#ifdef CONFIG_USB_MSM_OTG_72K +static struct msm_otg_platform_data msm_otg_pdata; +#else +static bool vbus_is_on; +static void msm_hsusb_vbus_power_max8627(bool on) +{ + int rc; + static struct regulator *mvs_otg_switch; + struct pm_gpio param = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 1, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + }; + + pr_info("%s, attached %d, vbus_is_on %d\n", __func__, on, vbus_is_on); + + if (vbus_is_on == on) + return; + + if (on) { + mvs_otg_switch = regulator_get(&msm8960_device_otg.dev, + "vbus_otg"); + if (IS_ERR(mvs_otg_switch)) { + pr_err("Unable to get mvs_otg_switch\n"); + return; + } + + rc = gpio_request(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + "usb_5v_en"); + if (rc < 0) { + pr_err("failed to request usb_5v_en gpio\n"); + goto put_mvs_otg; + } + + if (regulator_enable(mvs_otg_switch)) { + pr_err("unable to enable mvs_otg_switch\n"); + goto free_usb_5v_en; + } + + rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + ¶m); + if (rc < 0) { + pr_err("failed to configure usb_5v_en gpio\n"); + goto disable_mvs_otg; + } + vbus_is_on = true; + return; + } else { + gpio_set_value_cansleep(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + 0); +#ifdef CONFIG_USB_SWITCH_FSA9485 + fsa9485_otg_detach(); +#endif + } + +disable_mvs_otg: + regulator_disable(mvs_otg_switch); +free_usb_5v_en: + gpio_free(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN)); +put_mvs_otg: + regulator_put(mvs_otg_switch); + vbus_is_on = false; +} + +#ifdef CONFIG_CHARGER_SMB347 +static void msm_hsusb_vbus_power_smb347s(bool on) +{ + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + int ret = 0; + + pr_info("%s, attached %d, vbus_is_on %d\n", __func__, on, vbus_is_on); + + /* If VBUS is already on (or off), do nothing. */ + if (vbus_is_on == on) + return; + + if (on) + value.intval = POWER_SUPPLY_CAPACITY_OTG_ENABLE; + else + value.intval = POWER_SUPPLY_CAPACITY_OTG_DISABLE; + + if (psy) { + ret = psy->set_property(psy, POWER_SUPPLY_PROP_OTG, &value); + if (ret) { + pr_err("%s: fail to set power_suppy otg property(%d)\n", + __func__, ret); + } +#ifdef CONFIG_USB_SWITCH_FSA9485 + if (!on) + fsa9485_otg_detach(); +#endif + vbus_is_on = on; + } else { + pr_err("%s : psy is null!\n", __func__); + } +} +#endif + +static int msm_hsusb_vbus_power(bool on) +{ + if (system_rev < BOARD_REV03) + msm_hsusb_vbus_power_max8627(on); +#ifdef CONFIG_CHARGER_SMB347 + else + msm_hsusb_vbus_power_smb347s(on); +#endif + return 0; +} + +static int phy_settings[] = { + 0x44, 0x80, + 0x6F, 0x81, + 0x3C, 0x82, + 0x13, 0x83, + -1, +}; + +static int wr_phy_init_seq[] = { + 0x44, 0x80, /* set VBUS valid threshold + and disconnect valid threshold */ + 0x38, 0x81, /* update DC voltage level */ + 0x14, 0x82, /* set preemphasis and rise/fall time */ + 0x13, 0x83, /* set source impedance adjusment */ + -1}; + +static int liquid_v1_phy_init_seq[] = { + 0x44, 0x80,/* set VBUS valid threshold + and disconnect valid threshold */ + 0x3C, 0x81,/* update DC voltage level */ + 0x18, 0x82,/* set preemphasis and rise/fall time */ + 0x23, 0x83,/* set source impedance sdjusment */ + -1}; + +#ifdef CONFIG_MSM_BUS_SCALING +/* Bandwidth requests (zero) if no vote placed */ +static struct msm_bus_vectors usb_init_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +/* Bus bandwidth requests in Bytes/sec */ +static struct msm_bus_vectors usb_max_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 60000000, /* At least 480Mbps on bus. */ + .ib = 960000000, /* MAX bursts rate */ + }, +}; + +static struct msm_bus_paths usb_bus_scale_usecases[] = { + { + ARRAY_SIZE(usb_init_vectors), + usb_init_vectors, + }, + { + ARRAY_SIZE(usb_max_vectors), + usb_max_vectors, + }, +}; + +static struct msm_bus_scale_pdata usb_bus_scale_pdata = { + usb_bus_scale_usecases, + ARRAY_SIZE(usb_bus_scale_usecases), + .name = "usb", +}; +#endif + +static struct msm_otg_platform_data msm_otg_pdata = { + .mode = USB_OTG, + .otg_control = OTG_PMIC_CONTROL, + .phy_type = SNPS_28NM_INTEGRATED_PHY, + .pmic_id_irq = PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE), + .vbus_power = msm_hsusb_vbus_power, + .power_budget = 750, + .phy_init_seq = phy_settings, + .smb347s = true, +#ifdef CONFIG_MSM_BUS_SCALING + .bus_scale_table = &usb_bus_scale_pdata, +#endif +}; + +#ifdef CONFIG_USB_HOST_NOTIFY +static void __init msm_otg_power_init(void) +{ + if (system_rev >= BOARD_REV01) { + msm_otg_pdata.otg_power_gpio = + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_POWER); + msm_otg_pdata.otg_power_irq = + PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_OTG_POWER); + } + if (system_rev >= BOARD_REV03) + msm_otg_pdata.smb347s = true; + else + msm_otg_pdata.smb347s = false; +} +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC +#define HSIC_HUB_RESET_GPIO 91 +static struct msm_hsic_host_platform_data msm_hsic_pdata = { + .strobe = 150, + .data = 151, +}; +#else +static struct msm_hsic_host_platform_data msm_hsic_pdata; +#endif + +#define PID_MAGIC_ID 0x71432909 +#define SERIAL_NUM_MAGIC_ID 0x61945374 +#define SERIAL_NUMBER_LENGTH 127 +#define DLOAD_USB_BASE_ADD 0x2A03F0C8 + +struct magic_num_struct { + uint32_t pid; + uint32_t serial_num; +}; + +struct dload_struct { + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint16_t reserved4; + uint16_t pid; + char serial_number[SERIAL_NUMBER_LENGTH]; + uint16_t reserved5; + struct magic_num_struct magic_struct; +}; + +static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum) +{ + struct dload_struct __iomem *dload = 0; + + dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload)); + if (!dload) { + pr_err("%s: cannot remap I/O memory region: %08x\n", + __func__, DLOAD_USB_BASE_ADD); + return -ENXIO; + } + + pr_debug("%s: dload:%p pid:%x serial_num:%s\n", + __func__, dload, pid, snum); + /* update pid */ + dload->magic_struct.pid = PID_MAGIC_ID; + dload->pid = pid; + + /* update serial number */ + dload->magic_struct.serial_num = 0; + if (!snum) { + memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH); + goto out; + } + + dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID; + strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH); +out: + iounmap(dload); + return 0; +} + +static struct android_usb_platform_data android_usb_pdata = { + .update_pid_and_serial_num = usb_diag_update_pid_and_serial_num, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; + +static uint8_t spm_wfi_cmd_sequence[] __initdata = { + 0x03, 0x0f, +}; + +static uint8_t spm_retention_cmd_sequence[] __initdata = { + 0x00, 0x05, 0x03, 0x0D, + 0x0B, 0x00, 0x0f, +}; + +static uint8_t spm_power_collapse_without_rpm[] __initdata = { + 0x00, 0x24, 0x54, 0x10, + 0x09, 0x03, 0x01, + 0x10, 0x54, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +static uint8_t spm_power_collapse_with_rpm[] __initdata = { + 0x00, 0x24, 0x54, 0x10, + 0x09, 0x07, 0x01, 0x0B, + 0x10, 0x54, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +/* 8960AB has a different command to assert apc_pdn */ +static uint8_t spm_power_collapse_without_rpm_krait_v3[] __initdata = { + 0x00, 0x24, 0x84, 0x10, + 0x09, 0x03, 0x01, + 0x10, 0x84, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +static uint8_t spm_power_collapse_with_rpm_krait_v3[] __initdata = { + 0x00, 0x24, 0x84, 0x10, + 0x09, 0x07, 0x01, 0x0B, + 0x10, 0x84, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +static struct msm_spm_seq_entry msm_spm_boot_cpu_seq_list[] __initdata = { + [0] = { + .mode = MSM_SPM_MODE_CLOCK_GATING, + .notify_rpm = false, + .cmd = spm_wfi_cmd_sequence, + }, + [1] = { + .mode = MSM_SPM_MODE_POWER_RETENTION, + .notify_rpm = false, + .cmd = spm_retention_cmd_sequence, + }, + [2] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = false, + .cmd = spm_power_collapse_without_rpm, + }, + [3] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = true, + .cmd = spm_power_collapse_with_rpm, + }, +}; + +static struct msm_spm_seq_entry msm_spm_nonboot_cpu_seq_list[] __initdata = { + [0] = { + .mode = MSM_SPM_MODE_CLOCK_GATING, + .notify_rpm = false, + .cmd = spm_wfi_cmd_sequence, + }, + [1] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = false, + .cmd = spm_power_collapse_without_rpm, + }, + [2] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = true, + .cmd = spm_power_collapse_with_rpm, + }, +}; + +static struct msm_spm_platform_data msm_spm_data[] __initdata = { + [0] = { + .reg_base_addr = MSM_SAW0_BASE, + .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F, +#if defined(CONFIG_MSM_AVS_HW) + .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464, + .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000, +#endif + .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0084009C, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A4001C, + .vctl_timeout_us = 50, + .num_modes = ARRAY_SIZE(msm_spm_boot_cpu_seq_list), + .modes = msm_spm_boot_cpu_seq_list, + }, + [1] = { + .reg_base_addr = MSM_SAW1_BASE, + .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F, +#if defined(CONFIG_MSM_AVS_HW) + .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464, + .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000, +#endif + .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C, + .vctl_timeout_us = 50, + .num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list), + .modes = msm_spm_nonboot_cpu_seq_list, + }, +}; + +static uint8_t l2_spm_wfi_cmd_sequence[] __initdata = { + 0x00, 0x20, 0x03, 0x20, + 0x00, 0x0f, +}; + +static uint8_t l2_spm_gdhs_cmd_sequence[] __initdata = { + 0x00, 0x20, 0x34, 0x64, + 0x48, 0x07, 0x48, 0x20, + 0x50, 0x64, 0x04, 0x34, + 0x50, 0x0f, +}; +static uint8_t l2_spm_power_off_cmd_sequence[] __initdata = { + 0x00, 0x10, 0x34, 0x64, + 0x48, 0x07, 0x48, 0x10, + 0x50, 0x64, 0x04, 0x34, + 0x50, 0x0F, +}; + +static struct msm_spm_seq_entry msm_spm_l2_seq_list[] __initdata = { + [0] = { + .mode = MSM_SPM_L2_MODE_RETENTION, + .notify_rpm = false, + .cmd = l2_spm_wfi_cmd_sequence, + }, + [1] = { + .mode = MSM_SPM_L2_MODE_GDHS, + .notify_rpm = true, + .cmd = l2_spm_gdhs_cmd_sequence, + }, + [2] = { + .mode = MSM_SPM_L2_MODE_POWER_COLLAPSE, + .notify_rpm = true, + .cmd = l2_spm_power_off_cmd_sequence, + }, +}; + +static struct msm_spm_platform_data msm_spm_l2_data[] __initdata = { + [0] = { + .reg_base_addr = MSM_SAW_L2_BASE, + .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020, + .modes = msm_spm_l2_seq_list, + .num_modes = ARRAY_SIZE(msm_spm_l2_seq_list), + }, +}; + +#define PM_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33) +#define PM_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20) + +static struct msm_xo_voter *xo_handle_d1; + +static int isa1200_power(int on) +{ + int rc = 0; + + gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on); + + rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) : + msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF); + if (rc < 0) { + pr_err("%s: failed to %svote for TCXO D1 buffer%d\n", + __func__, on ? "" : "de-", rc); + goto err_xo_vote; + } + + return 0; + +err_xo_vote: + gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on); + return rc; +} + +static int isa1200_dev_setup(bool enable) +{ + int rc = 0; + + struct pm_gpio hap_gpio_config = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .vin_sel = 2, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + }; + + if (enable == true) { + rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config); + if (rc) { + pr_err("%s: pm8921 gpio %d config failed(%d)\n", + __func__, PM_HAP_EN_GPIO, rc); + return rc; + } + + rc = pm8xxx_gpio_config(PM_HAP_LEN_GPIO, &hap_gpio_config); + if (rc) { + pr_err("%s: pm8921 gpio %d config failed(%d)\n", + __func__, PM_HAP_LEN_GPIO, rc); + return rc; + } + + rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe"); + if (rc) { + pr_err("%s: unable to request gpio %d (%d)\n", + __func__, HAP_SHIFT_LVL_OE_GPIO, rc); + return rc; + } + + rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0); + if (rc) { + pr_err("%s: Unable to set direction\n", __func__); + goto free_gpio; + } + + xo_handle_d1 = msm_xo_get(MSM_XO_TCXO_D1, "isa1200"); + if (IS_ERR(xo_handle_d1)) { + rc = PTR_ERR(xo_handle_d1); + pr_err("%s: failed to get the handle for D1(%d)\n", + __func__, rc); + goto gpio_set_dir; + } + } else { + gpio_free(HAP_SHIFT_LVL_OE_GPIO); + + msm_xo_put(xo_handle_d1); + } + + return 0; + +gpio_set_dir: + gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0); +free_gpio: + gpio_free(HAP_SHIFT_LVL_OE_GPIO); + return rc; +} + +static struct isa1200_regulator isa1200_reg_data[] = { + { + .name = "vcc_i2c", + .min_uV = ISA_I2C_VTG_MIN_UV, + .max_uV = ISA_I2C_VTG_MAX_UV, + .load_uA = ISA_I2C_CURR_UA, + }, +}; + +static struct isa1200_platform_data isa1200_1_pdata = { + .name = "vibrator", + .dev_setup = isa1200_dev_setup, + .power_on = isa1200_power, + .hap_en_gpio = PM_HAP_EN_GPIO, + .hap_len_gpio = PM_HAP_LEN_GPIO, + .max_timeout = 15000, + .mode_ctrl = PWM_GEN_MODE, + .pwm_fd = { + .pwm_div = 256, + }, + .is_erm = false, + .smart_en = true, + .ext_clk_en = true, + .chip_en = 1, + .regulator_info = isa1200_reg_data, + .num_regulators = ARRAY_SIZE(isa1200_reg_data), +}; + +static struct i2c_board_info msm_isa1200_board_info[] __initdata = { + { + I2C_BOARD_INFO("isa1200_1", 0x90>>1), + .platform_data = &isa1200_1_pdata, + }, +}; + +#ifdef CONFIG_NFC_PN544 +static struct i2c_gpio_platform_data pn544_i2c_gpio_data = { + .sda_pin = GPIO_NFC_SDA, + .scl_pin = GPIO_NFC_SCL, + .udelay = 5, +}; + +static struct platform_device pn544_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_NFC_I2C_BUS_ID, + .dev = { + .platform_data = &pn544_i2c_gpio_data, + }, +}; + +static struct pn544_i2c_platform_data pn544_pdata = { + .conf_gpio = pn544_conf_gpio, + .irq_gpio = GPIO_NFC_IRQ, + .ven_gpio = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_NFC_EN), + .firm_gpio = GPIO_NFC_FIRMWARE, +}; + +static struct i2c_board_info pn544_info[] __initdata = { + { + I2C_BOARD_INFO("pn544", 0x2b), + .irq = MSM_GPIO_TO_INT(GPIO_NFC_IRQ), + .platform_data = &pn544_pdata, + }, +}; +#endif /* CONFIG_NFC_PN544 */ + +/* configuration data */ +static const u8 mxt_config_data[] = { + /* T6 Object */ + 0, 0, 0, 0, 0, 0, + /* T38 Object */ + 11, 0, 0, 6, 9, 11, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + /* T7 Object */ + 10, 10, 50, + /* T8 Object */ + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* T9 Object */ + 131, 0, 0, 26, 42, 0, 32, 60, 2, 5, + 0, 5, 5, 34, 10, 10, 10, 10, 85, 5, + 255, 2, 8, 9, 9, 9, 0, 0, 5, 20, + 0, 5, 45, 46, + /* T15 Object */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + /* T18 Object */ + 0, 0, + /* T22 Object */ + 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, + 0, 0, 255, 255, 255, 255, 0, + /* T24 Object */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* T25 Object */ + 3, 0, 188, 52, 52, 33, 0, 0, 0, 0, + 0, 0, 0, 0, + /* T27 Object */ + 0, 0, 0, 0, 0, 0, 0, + /* T28 Object */ + 0, 0, 0, 8, 8, 8, + /* T40 Object */ + 0, 0, 0, 0, 0, + /* T41 Object */ + 0, 0, 0, 0, 0, 0, + /* T43 Object */ + 0, 0, 0, 0, 0, 0, +}; + +static void mxt_init_hw_liquid(void) +{ + int rc; + + rc = gpio_request(GPIO_MXT_TS_IRQ, "mxt_ts_irq_gpio"); + if (rc) { + pr_err("%s: unable to request mxt_ts_irq gpio [%d]\n", + __func__, GPIO_MXT_TS_IRQ); + return; + } + + rc = gpio_direction_input(GPIO_MXT_TS_IRQ); + if (rc) { + pr_err("%s: unable to set_direction for mxt_ts_irq gpio [%d]\n", + __func__, GPIO_MXT_TS_IRQ); + goto err_irq_gpio_req; + } + + rc = gpio_request(GPIO_MXT_TS_LDO_EN, "mxt_ldo_en_gpio"); + if (rc) { + pr_err("%s: unable to request mxt_ldo_en gpio [%d]\n", + __func__, GPIO_MXT_TS_LDO_EN); + goto err_irq_gpio_req; + } + + rc = gpio_direction_output(GPIO_MXT_TS_LDO_EN, 1); + if (rc) { + pr_err("%s: unable to set_direction for mxt_ldo_en gpio [%d]\n", + __func__, GPIO_MXT_TS_LDO_EN); + goto err_ldo_gpio_req; + } +#if !defined(CONFIG_WIRELESS_CHARGING) + rc = gpio_request(GPIO_MXT_TS_RESET, "mxt_reset_gpio"); + if (rc) { + pr_err("%s: unable to request mxt_reset gpio [%d]\n", + __func__, GPIO_MXT_TS_RESET); + goto err_ldo_gpio_set_dir; + } + + rc = gpio_direction_output(GPIO_MXT_TS_RESET, 1); + if (rc) { + pr_err("%s: unable to set_direction for mxt_reset gpio [%d]\n", + __func__, GPIO_MXT_TS_RESET); + goto err_reset_gpio_req; + } +#endif + return; + +err_ldo_gpio_req: + gpio_free(GPIO_MXT_TS_LDO_EN); +err_irq_gpio_req: + gpio_free(GPIO_MXT_TS_IRQ); +} +#if 0 +static struct mxt_platform_data mxt_platform_data = { + .config = mxt_config_data, + .config_length = ARRAY_SIZE(mxt_config_data), + .x_line = 26, + .y_line = 42, + .x_size = 767, + .y_size = 1365, + .blen = 32, + .threshold = 40, + .voltage = 3300000, /* 3.3V */ + .orient = MXT_ROTATED_90, + .irqflags = IRQF_TRIGGER_FALLING, +}; + +static struct i2c_board_info mxt_device_info[] __initdata = { + { + I2C_BOARD_INFO("atmel_mxt_ts", 0x5b), + .platform_data = &mxt_platform_data, + .irq = MSM_GPIO_TO_INT(GPIO_MXT_TS_IRQ), + }, +}; +#endif +#ifndef CONFIG_SLIMBUS_MSM_CTRL +#define TABLA_I2C_SLAVE_ADDR 0x0d +#define TABLA_ANALOG_I2C_SLAVE_ADDR 0x77 +#define TABLA_DIGITAL1_I2C_SLAVE_ADDR 0x66 +#define TABLA_DIGITAL2_I2C_SLAVE_ADDR 0x55 + +static struct i2c_board_info tabla_device_info[] __initdata = { + { + I2C_BOARD_INFO("tabla top level", TABLA_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, + { + I2C_BOARD_INFO("tabla analog", TABLA_ANALOG_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, + { + I2C_BOARD_INFO("tabla digital1", TABLA_DIGITAL1_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, + { + I2C_BOARD_INFO("tabla digital2", TABLA_DIGITAL2_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, +}; +#endif +static struct i2c_board_info sii_device_info[] __initdata = { + { + I2C_BOARD_INFO("Sil-9244", 0x39), + .flags = I2C_CLIENT_WAKE, + .irq = MSM_GPIO_TO_INT(15), + }, +}; + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = { + .clk_freq = 400000, + .src_clk_rate = 24000000, +}; + +#ifndef CONFIG_SLIMBUS_MSM_CTRL +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi1_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; +#endif + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi7_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; +#ifdef CONFIG_VP_A2220 +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi8_pdata = { + .clk_freq = 400000, + .src_clk_rate = 24000000, +}; +#endif +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = { + .clk_freq = 400000, + .src_clk_rate = 24000000, +}; +#if 0 +static struct msm_rpm_platform_data msm_rpm_data = { + .reg_base_addrs = { + [MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE, + [MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400, + [MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600, + [MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00, + }, + + .irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ, + .irq_err = RPM_APCC_CPU0_GP_LOW_IRQ, + .irq_vmpm = RPM_APCC_CPU0_GP_MEDIUM_IRQ, + .msm_apps_ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008, + .msm_apps_ipc_rpm_val = 4, +}; +#endif + +#if 0 +static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = { + .base_addr = MSM_ACC0_BASE + 0x08, + .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE, + .mask = 1UL << 13, +}; +#endif + +#ifndef CONFIG_S5C73M3 +static struct ks8851_pdata spi_eth_pdata = { + .irq_gpio = KS8851_IRQ_GPIO, + .rst_gpio = KS8851_RST_GPIO, +}; + +static struct spi_board_info spi_board_info[] __initdata = { + { + .modalias = "ks8851", + .irq = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO), + .max_speed_hz = 19200000, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_0, + .platform_data = &spi_eth_pdata + }, + { + .modalias = "dsi_novatek_3d_panel_spi", + .max_speed_hz = 10800000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_0, + }, +}; +#endif +static struct platform_device msm_device_saw_core0 = { + .name = "saw-regulator", + .id = 0, + .dev = { + .platform_data = &msm_saw_regulator_pdata_s5, + }, +}; + +static struct platform_device msm_device_saw_core1 = { + .name = "saw-regulator", + .id = 1, + .dev = { + .platform_data = &msm_saw_regulator_pdata_s6, + }, +}; + +static struct tsens_platform_data msm_tsens_pdata = { + .slope = {910, 910, 910, 910, 910}, + .tsens_factor = 1000, + .hw_type = MSM_8960, + .tsens_num_sensor = 5, +}; + +static struct platform_device msm_tsens_device = { + .name = "tsens8960-tm", + .id = -1, +}; + +static struct msm_thermal_data msm_thermal_pdata = { + .sensor_id = 0, + .poll_ms = 250, + .limit_temp_degC = 60, + .temp_hysteresis_degC = 10, + .freq_step = 2, +}; + +/* Bluetooth */ +#ifdef CONFIG_BT_BCM4334 +static struct platform_device bcm4334_bluetooth_device = { + .name = "bcm4334_bluetooth", + .id = -1, +}; +#endif + +#ifdef CONFIG_MSM_FAKE_BATTERY +static struct platform_device fish_battery_device = { + .name = "fish_battery", +}; +#endif + +static struct platform_device msm8960_device_ext_5v_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = PM8921_MPP_PM_TO_SYS(7), + .dev = { + .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V], + }, +}; +#if 0 +static struct platform_device msm8960_device_ext_l2_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = 91, + .dev = { + .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2], + }, +}; +#endif +static struct platform_device msm8960_device_ext_3p3v_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = PM8921_GPIO_PM_TO_SYS(17), + .dev = { + .platform_data = + &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_3P3V], + }, +}; +#ifdef CONFIG_KEYBOARD_GPIO +static struct gpio_keys_button gpio_keys_button[] = { + { + .code = KEY_VOLUMEUP, + .type = EV_KEY, + .gpio = -1, + .active_low = 1, + .wakeup = 0, + .debounce_interval = 5, /* ms */ + .desc = "Vol Up", + }, + { + .code = KEY_VOLUMEDOWN, + .type = EV_KEY, + .gpio = -1, + .active_low = 1, + .wakeup = 0, + .debounce_interval = 5, /* ms */ + .desc = "Vol Down", + }, + { + .code = KEY_HOMEPAGE, + .type = EV_KEY, + .gpio = -1, + .active_low = 1, + .wakeup = 1, + .debounce_interval = 5, /* ms */ + .desc = "Home", + }, +}; +static struct gpio_keys_platform_data gpio_keys_platform_data = { + .buttons = gpio_keys_button, + .nbuttons = ARRAY_SIZE(gpio_keys_button), + .rep = 0, +}; + +static struct platform_device msm8960_gpio_keys_device = { + .name = "sec_keys", + .id = -1, + .dev = { + .platform_data = &gpio_keys_platform_data, + } +}; +#endif + +static struct platform_device msm8960_device_ext_otg_sw_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = PM8921_GPIO_PM_TO_SYS(42), + .dev = { + .platform_data = + &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_OTG_SW], + }, +}; + +static struct platform_device msm8960_device_rpm_regulator __devinitdata = { + .name = "rpm-regulator", + .id = -1, + .dev = { + .platform_data = &msm_rpm_regulator_pdata, + }, +}; + +static struct msm_rpm_log_platform_data msm_rpm_log_pdata = { + .phys_addr_base = 0x0010C000, + .reg_offsets = { + [MSM_RPM_LOG_PAGE_INDICES] = 0x00000080, + [MSM_RPM_LOG_PAGE_BUFFER] = 0x000000A0, + }, + .phys_size = SZ_8K, + .log_len = 4096, /* log's buffer length in bytes */ + .log_len_mask = (4096 >> 2) - 1, /* length mask in units of u32 */ +}; + +static struct platform_device msm_rpm_log_device = { + .name = "msm_rpm_log", + .id = -1, + .dev = { + .platform_data = &msm_rpm_log_pdata, + }, +}; + +#ifdef CONFIG_SAMSUNG_JACK +#define PMIC_GPIO_EAR_DET 36 +#define PMIC_GPIO_SHORT_SENDEND 32 +#define PMIC_GPIO_EAR_MICBIAS_EN 3 + +static struct sec_jack_zone jack_zones[] = { + [0] = { + .adc_high = 3, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_3POLE, + }, + [1] = { + .adc_high = 630, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_3POLE, + }, + [2] = { + .adc_high = 1720, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_4POLE, + }, + [3] = { + .adc_high = 9999, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_4POLE, + }, +}; + +/* To support 3-buttons earjack */ +static struct sec_jack_buttons_zone jack_buttons_zones[] = { + { + .code = KEY_MEDIA, + .adc_low = 0, + .adc_high = 93, + }, + { + .code = KEY_VOLUMEUP, + .adc_low = 94, + .adc_high = 217, + }, + { + .code = KEY_VOLUMEDOWN, + .adc_low = 218, + .adc_high = 450, + }, +}; + +static int get_sec_det_jack_state(void) +{ + return (gpio_get_value_cansleep( + PM8921_GPIO_PM_TO_SYS( + PMIC_GPIO_EAR_DET))) ^ 1; +} + +static int get_sec_send_key_state(void) +{ + struct pm_gpio ear_micbiase = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .vin_sel = PM_GPIO_VIN_S4, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + }; + + if (get_sec_det_jack_state()) { + pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + &ear_micbiase); + gpio_set_value_cansleep( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + 1); + } + return (gpio_get_value_cansleep( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_SHORT_SENDEND))) ^ 1; + + return 0; +} + +static void set_sec_micbias_state(bool state) +{ + pr_info("sec_jack: ear micbias %s\n", state ? "on" : "off"); + gpio_set_value_cansleep( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + state); +} + +static int sec_jack_get_adc_value(void) +{ + int rc = 0; + int retVal = 0; + struct pm8xxx_adc_chan_result result; + + rc = pm8xxx_adc_mpp_config_read( + PM8XXX_AMUX_MPP_3, + ADC_MPP_1_AMUX6_SCALE_DEFAULT, + &result); + if (rc) { + pr_err("%s : error reading mpp %d, rc = %d\n", + __func__, PM8XXX_AMUX_MPP_3, rc); + return rc; + } + retVal = ((int)result.physical)/1000; + return retVal; +} + +static struct sec_jack_platform_data sec_jack_data = { + .get_det_jack_state = get_sec_det_jack_state, + .get_send_key_state = get_sec_send_key_state, + .set_micbias_state = set_sec_micbias_state, + .get_adc_value = sec_jack_get_adc_value, + .zones = jack_zones, + .num_zones = ARRAY_SIZE(jack_zones), + .buttons_zones = jack_buttons_zones, + .num_buttons_zones = ARRAY_SIZE(jack_buttons_zones), + .det_int = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, + PMIC_GPIO_EAR_DET), + .send_int = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, + PMIC_GPIO_SHORT_SENDEND), +}; + +static struct platform_device sec_device_jack = { + .name = "sec_jack", + .id = -1, + .dev = { + .platform_data = &sec_jack_data, + }, +}; +#endif + +static struct platform_device *common_devices[] __initdata = { + &msm8960_device_dmov, + &msm_device_smd, + &msm8960_device_uart_gsbi5, + &msm_device_uart_dm6, + &msm_device_saw_core0, + &msm_device_saw_core1, + &msm8960_device_ext_5v_vreg, + &msm8960_device_ssbi_pmic, + &msm8960_device_ext_otg_sw_vreg, +#ifndef CONFIG_SLIMBUS_MSM_CTRL + &msm8960_device_qup_i2c_gsbi1, +#endif +#ifdef CONFIG_S5C73M3 + &msm8960_device_qup_spi_gsbi11, +#endif + &msm8960_device_qup_i2c_gsbi3, + &msm8960_device_qup_i2c_gsbi4, + &msm8960_device_qup_i2c_gsbi7, + &msm8960_device_qup_i2c_gsbi10, +#ifdef CONFIG_VP_A2220 + &msm8960_device_qup_i2c_gsbi8, +#endif +#ifndef CONFIG_MSM_DSPS + &msm8960_device_qup_i2c_gsbi12, +#endif + &msm_slim_ctrl, + &msm_device_wcnss_wlan, +#if defined(CONFIG_QSEECOM) + &qseecom_device, +#endif +#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \ + defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) + &qcrypto_device, +#endif + +#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE) + &qcedev_device, +#endif +#ifdef CONFIG_MSM_ROTATOR + &msm_rotator_device, +#endif + &msm_device_sps, +#ifdef CONFIG_MSM_FAKE_BATTERY + &fish_battery_device, +#endif + &fmem_device, +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + &android_pmem_device, + &android_pmem_adsp_device, + &android_pmem_audio_device, +#endif +#endif +#ifdef CONFIG_KEYBOARD_GPIO + &msm8960_gpio_keys_device, +#endif + &msm_device_vidc, + &msm_device_bam_dmux, + &msm_fm_platform_init, + +#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) +#ifdef CONFIG_MSM_USE_TSIF1 + &msm_device_tsif[1], +#else + &msm_device_tsif[0], +#endif +#endif + +#ifdef CONFIG_HW_RANDOM_MSM + &msm_device_rng, +#endif + &msm8960_rpm_device, +#ifdef CONFIG_ION_MSM + &ion_dev, +#endif + &msm_rpm_log_device, + &msm8960_rpm_stat_device, + &msm_device_tz_log, +#if 0 +#ifdef CONFIG_MSM_QDSS + &msm_etb_device, + &msm_tpiu_device, + &msm_funnel_device, + &msm_etm_device, +#endif +#endif + &msm_device_dspcrashd_8960, + &msm8960_device_watchdog, +#ifdef CONFIG_MSM_RTB + &msm_rtb_device, +#endif + &msm8960_device_cache_erp, +#ifdef CONFIG_MSM_CACHE_DUMP + &msm_cache_dump_device, +#endif + &msm8960_iommu_domain_device, + &msm_tsens_device, +}; + +static struct platform_device *m2_spr_devices[] __initdata = { + &msm_8960_q6_lpass, + &msm_8960_q6_mss_sw, + &msm_8960_q6_mss_fw, + &msm_8960_riva, + &msm_pil_tzapps, + &msm_pil_vidc, + &msm8960_device_otg, + &msm8960_device_gadget_peripheral, + &msm_device_hsusb_host, + &android_usb_device, + &msm_pcm, + &msm_multi_ch_pcm, + &msm_lowlatency_pcm, + &msm_pcm_routing, +#ifdef CONFIG_SLIMBUS_MSM_CTRL + &msm_cpudai0, + &msm_cpudai1, +#else + &msm_i2s_cpudai0, + &msm_i2s_cpudai1, +#endif + &msm_cpudai_hdmi_rx, + &msm_cpudai_bt_rx, + &msm_cpudai_bt_tx, + &msm_cpudai_fm_rx, + &msm_cpudai_fm_tx, + &msm_cpudai_auxpcm_rx, + &msm_cpudai_auxpcm_tx, + &msm_cpu_fe, + &msm_stub_codec, +#ifdef CONFIG_MSM_GEMINI + &msm8960_gemini_device, +#endif + &msm_voice, + &msm_voip, + &msm_lpa_pcm, + &msm_cpudai_afe_01_rx, + &msm_cpudai_afe_01_tx, + &msm_cpudai_afe_02_rx, + &msm_cpudai_afe_02_tx, + &msm_pcm_afe, + &msm_compr_dsp, + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + &mhl_i2c_gpio_device, +#endif +#ifdef CONFIG_USB_SWITCH_FSA9485 + &fsa_i2c_gpio_device, +#endif +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 + &touchkey_i2c_gpio_device, +#endif +#ifdef CONFIG_BATTERY_MAX17040 + &fuelgauge_i2c_gpio_device, +#endif +#ifdef CONFIG_BATTERY_SEC + &sec_device_battery, +#endif +#ifdef CONFIG_SAMSUNG_JACK + &sec_device_jack, +#endif + &msm_cpudai_incall_music_rx, + &msm_cpudai_incall_record_rx, + &msm_cpudai_incall_record_tx, + &msm_pcm_hostless, + &msm_bus_apps_fabric, + &msm_bus_sys_fabric, + &msm_bus_mm_fabric, + &msm_bus_sys_fpb, + &msm_bus_cpss_fpb, + &pn544_i2c_gpio_device, +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + &opt_i2c_gpio_device, +#if 0 +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) + &opt_gp2a, +#endif +#endif +#endif +#ifdef CONFIG_BT_BCM4334 + &bcm4334_bluetooth_device, +#endif +#ifdef CONFIG_VIBETONZ + &vibetonz_device, +#endif /* CONFIG_VIBETONZ */ +}; + +static void __init msm8960_i2c_init(void) +{ + msm8960_device_qup_i2c_gsbi4.dev.platform_data = + &msm8960_i2c_qup_gsbi4_pdata; + +#ifndef CONFIG_SLIMBUS_MSM_CTRL + msm8960_device_qup_i2c_gsbi1.dev.platform_data = + &msm8960_i2c_qup_gsbi1_pdata; +#endif + + msm8960_device_qup_i2c_gsbi7.dev.platform_data = + &msm8960_i2c_qup_gsbi7_pdata; + + msm8960_device_qup_i2c_gsbi3.dev.platform_data = + &msm8960_i2c_qup_gsbi3_pdata; + + msm8960_device_qup_i2c_gsbi10.dev.platform_data = + &msm8960_i2c_qup_gsbi10_pdata; +#ifdef CONFIG_VP_A2220 + msm8960_device_qup_i2c_gsbi8.dev.platform_data = + &msm8960_i2c_qup_gsbi8_pdata; +#endif + msm8960_device_qup_i2c_gsbi12.dev.platform_data = + &msm8960_i2c_qup_gsbi12_pdata; +} + +static void __init msm8960_gfx_init(void) +{ + struct kgsl_device_platform_data *kgsl_3d0_pdata = + msm_kgsl_3d0.dev.platform_data; + uint32_t soc_platform_version = socinfo_get_version(); + + kgsl_3d0_pdata->iommu_count = 1; + + if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) { + kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000; + kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000; + } + if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3) { + /* 8960v3 GPU registers returns 5 for patch release + * but it should be 6, so dummy up the chipid here + * based the platform type + */ + kgsl_3d0_pdata->chipid = ADRENO_CHIPID(2, 2, 0, 6); + } + + /* Register the 3D core */ + platform_device_register(&msm_kgsl_3d0); + + /* Register the 2D cores if we are not 8960PRO */ + if (!cpu_is_msm8960ab()) { + platform_device_register(&msm_kgsl_2d0); + platform_device_register(&msm_kgsl_2d1); + } +} +#if 0 +static struct msm_cpuidle_state msm_cstates[] __initdata = { + {0, 0, "C0", "WFI", + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT}, + + {0, 1, "C2", "POWER_COLLAPSE", + MSM_PM_SLEEP_MODE_POWER_COLLAPSE}, + + {1, 0, "C0", "WFI", + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT}, +}; + +static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = { + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + }, + + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + }, + + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 0, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + }, + + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 0, + .idle_enabled = 1, + .suspend_enabled = 0, + }, +}; +#endif +static struct msm_rpmrs_level msm_rpmrs_levels[] = { + { + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT, + MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE), + true, + 100, 650, 801, 200, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE), + false, + 8500, 51, 1122000, 8500, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE), + false, + 9000, 51, 1130300, 9000, + }, + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH), + false, + 10000, 51, 1130300, 10000, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE), + false, + 12000, 14, 2205900, 12000, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE), + false, + 18000, 12, 2364250, 18000, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH), + false, + 23500, 10, 2667000, 23500, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW), + false, + 29700, 5, 2867000, 30000, + }, +}; + +static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = { + .levels = &msm_rpmrs_levels[0], + .num_levels = ARRAY_SIZE(msm_rpmrs_levels), + .vdd_mem_levels = { + [MSM_RPMRS_VDD_MEM_RET_LOW] = 750000, + [MSM_RPMRS_VDD_MEM_RET_HIGH] = 750000, + [MSM_RPMRS_VDD_MEM_ACTIVE] = 1050000, + [MSM_RPMRS_VDD_MEM_MAX] = 1150000, + }, + .vdd_dig_levels = { + [MSM_RPMRS_VDD_DIG_RET_LOW] = 500000, + [MSM_RPMRS_VDD_DIG_RET_HIGH] = 750000, + [MSM_RPMRS_VDD_DIG_ACTIVE] = 950000, + [MSM_RPMRS_VDD_DIG_MAX] = 1150000, + }, + .vdd_mask = 0x7FFFFF, + .rpmrs_target_id = { + [MSM_RPMRS_ID_PXO_CLK] = MSM_RPM_ID_PXO_CLK, + [MSM_RPMRS_ID_L2_CACHE_CTL] = MSM_RPM_ID_LAST, + [MSM_RPMRS_ID_VDD_DIG_0] = MSM_RPM_ID_PM8921_S3_0, + [MSM_RPMRS_ID_VDD_DIG_1] = MSM_RPM_ID_PM8921_S3_1, + [MSM_RPMRS_ID_VDD_MEM_0] = MSM_RPM_ID_PM8921_L24_0, + [MSM_RPMRS_ID_VDD_MEM_1] = MSM_RPM_ID_PM8921_L24_1, + [MSM_RPMRS_ID_RPM_CTL] = MSM_RPM_ID_RPM_CTL, + }, +}; + +static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = { + .mode = MSM_PM_BOOT_CONFIG_TZ, +}; + +uint32_t msm_rpm_get_swfi_latency(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(msm_rpmrs_levels); i++) { + if (msm_rpmrs_levels[i].sleep_mode == + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT) + return msm_rpmrs_levels[i].latency_us; + } + + return 0; +} + +#ifdef CONFIG_I2C +#define I2C_SURF 1 +#define I2C_FFA (1 << 1) +#define I2C_RUMI (1 << 2) +#define I2C_SIM (1 << 3) +#define I2C_FLUID (1 << 4) +#define I2C_LIQUID (1 << 5) + +struct i2c_registry { + u8 machs; + int bus; + struct i2c_board_info *info; + int len; +}; + +#ifdef CONFIG_MSM_CAMERA +static struct i2c_board_info msm_camera_boardinfo[] __initdata = { +#ifdef CONFIG_S5C73M3 + { + I2C_BOARD_INFO("s5c73m3", 0x78>>1), + }, +#endif +#ifdef CONFIG_S5K6A3YX + { + I2C_BOARD_INFO("s5k6a3yx", 0x20), + }, +#endif +#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A + { + I2C_BOARD_INFO("sc628a", 0x6E), + }, +#endif +}; +#endif + +/*add for D2_ATT CAM_ISP_CORE power setting by MAX8952*/ +#ifdef CONFIG_REGULATOR_MAX8952 +static int max8952_is_used(void) +{ + if (system_rev >= 0x3) + return 1; + else + return 0; +} + +static struct regulator_consumer_supply max8952_consumer = + REGULATOR_SUPPLY("cam_isp_core", NULL); + +static struct max8952_platform_data m2_att_max8952_pdata = { + .gpio_vid0 = -1, /* NOT controlled by GPIO, HW default high*/ + .gpio_vid1 = -1, /* NOT controlled by GPIO, HW default high*/ + .gpio_en = CAM_CORE_EN, /* Controlled by GPIO, High enable */ + .default_mode = 3, /* vid0 = 1, vid1 = 1 */ + .dvs_mode = { 33, 33, 33, 43 }, /* 1.1V, 1.1V, 1.1V, 1.2V*/ + .sync_freq = 0, /* default: fastest */ + .ramp_speed = 0, /* default: fastest */ + .reg_data = { + .constraints = { + .name = "CAM_ISP_CORE", + .min_uV = 770000, + .max_uV = 1400000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &max8952_consumer, + }, +}; +#endif /*CONFIG_REGULATOR_MAX8952*/ + +#ifdef CONFIG_SAMSUNG_CMC624 +static struct i2c_board_info cmc624_i2c_borad_info[] = { + { + I2C_BOARD_INFO("cmc624", 0x38), + }, +}; +#endif + +#ifdef CONFIG_REGULATOR_MAX8952 +static struct i2c_board_info cmc624_max8952_i2c_borad_info[] = { + { + I2C_BOARD_INFO("cmc624", 0x38), + }, + + { + I2C_BOARD_INFO("max8952", 0xC0>>1), + .platform_data = &m2_att_max8952_pdata, + }, +}; +#endif /*CONFIG_REGULATOR_MAX8952*/ + +/* Sensors DSPS platform data */ +#ifdef CONFIG_MSM_DSPS +#define DSPS_PIL_GENERIC_NAME "dsps" +#endif /* CONFIG_MSM_DSPS */ + +static void __init msm8960_init_dsps(void) +{ +#ifdef CONFIG_MSM_DSPS + struct msm_dsps_platform_data *pdata = + msm_dsps_device.dev.platform_data; + pdata->pil_name = DSPS_PIL_GENERIC_NAME; + pdata->gpios = NULL; + pdata->gpios_num = 0; + + platform_device_register(&msm_dsps_device); +#endif /* CONFIG_MSM_DSPS */ +} + +static int hsic_peripheral_status = 1; +static DEFINE_MUTEX(hsic_status_lock); + +void peripheral_connect() +{ + mutex_lock(&hsic_status_lock); + if (hsic_peripheral_status) + goto out; + platform_device_add(&msm_device_hsic_host); + hsic_peripheral_status = 1; +out: + mutex_unlock(&hsic_status_lock); +} +EXPORT_SYMBOL(peripheral_connect); + +void peripheral_disconnect() +{ + mutex_lock(&hsic_status_lock); + if (!hsic_peripheral_status) + goto out; + platform_device_del(&msm_device_hsic_host); + hsic_peripheral_status = 0; +out: + mutex_unlock(&hsic_status_lock); +} +EXPORT_SYMBOL(peripheral_disconnect); + +static void __init msm8960_init_hsic(void) +{ +#ifdef CONFIG_USB_EHCI_MSM_HSIC + uint32_t version = socinfo_get_version(); + + if (SOCINFO_VERSION_MAJOR(version) == 1) + return; + + if (PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid()) + platform_device_register(&msm_device_hsic_host); +#endif +} + +#ifdef CONFIG_ISL9519_CHARGER +static struct isl_platform_data isl_data __initdata = { + .valid_n_gpio = 0, /* Not required when notify-by-pmic */ + .chg_detection_config = NULL, /* Not required when notify-by-pmic */ + .max_system_voltage = 4200, + .min_system_voltage = 3200, + .chgcurrent = 1000, /* 1900, */ + .term_current = 400, /* Need fine tuning */ + .input_current = 2048, +}; + +static struct i2c_board_info isl_charger_i2c_info[] __initdata = { + { + I2C_BOARD_INFO("isl9519q", 0x9), + .irq = 0, /* Not required when notify-by-pmic */ + .platform_data = &isl_data, + }, +}; +#endif /* CONFIG_ISL9519_CHARGER */ + +static struct i2c_registry msm8960_i2c_devices[] __initdata = { +#ifdef CONFIG_MSM_CAMERA + { + I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI, + MSM_8960_GSBI4_QUP_I2C_BUS_ID, + msm_camera_boardinfo, + ARRAY_SIZE(msm_camera_boardinfo), + }, +#endif +#ifdef CONFIG_ISL9519_CHARGER + { + I2C_LIQUID, + MSM_8960_GSBI10_QUP_I2C_BUS_ID, + isl_charger_i2c_info, + ARRAY_SIZE(isl_charger_i2c_info), + }, +#endif /* CONFIG_ISL9519_CHARGER */ +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_MHL_I2C_BUS_ID, + mhl_i2c_board_info, + ARRAY_SIZE(mhl_i2c_board_info), + }, +#endif +#ifdef CONFIG_USB_SWITCH_FSA9485 + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_FSA9485_I2C_BUS_ID, + micro_usb_i2c_devices_info, + ARRAY_SIZE(micro_usb_i2c_devices_info), + }, +#endif +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +{ + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_TOUCHKEY_I2C_BUS_ID, + touchkey_i2c_devices_info, + ARRAY_SIZE(touchkey_i2c_devices_info), + }, +#endif +#ifdef CONFIG_VP_A2220 + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_8960_GSBI8_QUP_I2C_BUS_ID, + a2220_device, + ARRAY_SIZE(a2220_device), + }, +#endif +#ifdef CONFIG_NFC_PN544 + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_NFC_I2C_BUS_ID, + pn544_info, + ARRAY_SIZE(pn544_info), + }, +#endif /* CONFIG_NFC_PN544 */ +#if 0 + { + I2C_LIQUID, + MSM_8960_GSBI3_QUP_I2C_BUS_ID, + mxt_device_info, + ARRAY_SIZE(mxt_device_info), + }, +#endif +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_SNS_I2C_BUS_ID, + sns_i2c_borad_info, + ARRAY_SIZE(sns_i2c_borad_info), + }, +#endif +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_OPT_I2C_BUS_ID, + opt_i2c_borad_info, + ARRAY_SIZE(opt_i2c_borad_info), + }, +#endif +#ifdef CONFIG_SAMSUNG_CMC624 + { + I2C_SURF | I2C_FFA | I2C_FLUID , + MSM_CMC624_I2C_BUS_ID, + cmc624_i2c_borad_info, + ARRAY_SIZE(cmc624_i2c_borad_info), + }, +#endif + { + I2C_LIQUID, + MSM_8960_GSBI10_QUP_I2C_BUS_ID, + sii_device_info, + ARRAY_SIZE(sii_device_info), + }, + { + I2C_LIQUID, + MSM_8960_GSBI10_QUP_I2C_BUS_ID, + msm_isa1200_board_info, + ARRAY_SIZE(msm_isa1200_board_info), + }, +#ifndef CONFIG_SLIMBUS_MSM_CTRL + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_8960_GSBI1_QUP_I2C_BUS_ID, + tabla_device_info, + ARRAY_SIZE(tabla_device_info), + }, +#endif +}; +#endif /* CONFIG_I2C */ + +static void __init register_i2c_devices(void) +{ +#ifdef CONFIG_I2C + u8 mach_mask = 0; + int i; + +#ifdef CONFIG_REGULATOR_MAX8952 +struct i2c_registry cmc624_max8952_i2c_devices = { + I2C_SURF | I2C_FFA | I2C_FLUID , + MSM_CMC624_I2C_BUS_ID, + cmc624_max8952_i2c_borad_info, + ARRAY_SIZE(cmc624_max8952_i2c_borad_info), + }; +#endif /*CONFIG_REGULATOR_MAX8952*/ + +#ifdef CONFIG_BATTERY_MAX17040 + struct i2c_registry msm8960_fg_i2c_devices = { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_FUELGAUGE_I2C_BUS_ID, + fg_i2c_board_info, + ARRAY_SIZE(fg_i2c_board_info), + }; +#endif /* CONFIG_BATTERY_MAX17040 */ +#if defined(CONFIG_CHARGER_SMB347) + struct i2c_registry msm8960_fg_smb_i2c_devices = { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_FUELGAUGE_I2C_BUS_ID, + fg_smb_i2c_board_info, + ARRAY_SIZE(fg_smb_i2c_board_info), + }; +#endif + + /* Build the matching 'supported_machs' bitmask */ + if (machine_is_msm8960_cdp()) + mach_mask = I2C_SURF; + else if (machine_is_msm8960_rumi3()) + mach_mask = I2C_RUMI; + else if (machine_is_msm8960_sim()) + mach_mask = I2C_SIM; + else if (machine_is_msm8960_fluid()) + mach_mask = I2C_FLUID; + else if (machine_is_msm8960_liquid()) + mach_mask = I2C_LIQUID; + else if (machine_is_msm8960_mtp()) + mach_mask = I2C_FFA; + else if (machine_is_M2_SPR()) + mach_mask = I2C_FFA; + else + pr_err("unmatched machine ID in register_i2c_devices\n"); + + /* Run the array and install devices as appropriate */ + for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) { + if (msm8960_i2c_devices[i].machs & mach_mask) + i2c_register_board_info(msm8960_i2c_devices[i].bus, + msm8960_i2c_devices[i].info, + msm8960_i2c_devices[i].len); + } + +#ifdef CONFIG_SAMSUNG_CMC624 +#ifdef CONFIG_REGULATOR_MAX8952 + if (max8952_is_used()) { + i2c_register_board_info(cmc624_max8952_i2c_devices.bus, + cmc624_max8952_i2c_devices.info, + cmc624_max8952_i2c_devices.len); + } +#endif /*CONFIG_REGULATOR_MAX8952*/ +#endif /*CONFIG_SAMSUNG_CMC624*/ + +#if defined(CONFIG_BATTERY_MAX17040) + if (!is_smb347_using()) { + i2c_register_board_info(msm8960_fg_i2c_devices.bus, + msm8960_fg_i2c_devices.info, + msm8960_fg_i2c_devices.len); + } +#if defined(CONFIG_CHARGER_SMB347) + else { + i2c_register_board_info(msm8960_fg_smb_i2c_devices.bus, + msm8960_fg_smb_i2c_devices.info, + msm8960_fg_smb_i2c_devices.len); + } +#endif /* CONFIG_CHARGER_SMB347 */ +#endif /* CONFIG_BATTERY_MAX17040 */ +#endif +} + +static void __init gpio_rev_init(void) +{ + /*KEY REV*/ + gpio_keys_button[0].gpio = gpio_rev(VOLUME_UP); + gpio_keys_button[1].gpio = gpio_rev(VOLUME_DOWN); + gpio_keys_platform_data.nbuttons = 2; + if (system_rev >= BOARD_REV06) { + gpio_tlmm_config(GPIO_CFG(GPIO_HOME_KEY, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + gpio_keys_button[2].gpio = GPIO_HOME_KEY; + gpio_keys_platform_data.nbuttons = ARRAY_SIZE(gpio_keys_button); + } +#if defined(CONFIG_SENSORS_CM36651) + if (system_rev < BOARD_REV06) + cm36651_pdata.irq = gpio_rev(ALS_INT); +#endif +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + opt_i2c_gpio_data.sda_pin = gpio_rev(ALS_SDA); + opt_i2c_gpio_data.scl_pin = gpio_rev(ALS_SCL); +#if defined(CONFIG_OPTICAL_GP2A) + if (system_rev < BOARD_REV06) { + opt_gp2a_data.irq = MSM_GPIO_TO_INT(gpio_rev(ALS_INT)); + opt_gp2a_data.ps_status = gpio_rev(ALS_INT); + } +#elif defined(CONFIG_OPTICAL_GP2AP020A00F) + if (system_rev < BOARD_REV06) + opt_gp2a_data.p_out = gpio_rev(ALS_INT); +#endif +#endif + a2220_i2c_gpio_data.sda_pin = gpio_rev(A2220_SDA); + a2220_i2c_gpio_data.scl_pin = gpio_rev(A2220_SCL); + a2220_data.gpio_wakeup = gpio_rev(A2220_WAKEUP); + msm8960_a2220_configs[0].gpio = gpio_rev(A2220_SDA); + msm8960_a2220_configs[1].gpio = gpio_rev(A2220_SCL); +#ifdef CONFIG_VIBETONZ + if (system_rev >= BOARD_REV03) { + msm_8960_vibrator_pdata.vib_en_gpio = PMIC_GPIO_VIB_ON; + msm_8960_vibrator_pdata.is_pmic_vib_en = 1; + } + if (system_rev >= BOARD_REV06) { + msm_8960_vibrator_pdata.haptic_pwr_en_gpio = \ + PMIC_GPIO_HAPTIC_PWR_EN; + msm_8960_vibrator_pdata.is_pmic_haptic_pwr_en = 1; + } +#endif /* CONFIG_VIBETONZ */ +} + +#ifdef CONFIG_SAMSUNG_JACK +static struct pm_gpio ear_det = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, +}; + +static struct pm_gpio short_sendend = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, +}; + +static struct pm_gpio ear_micbiase = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .vin_sel = PM_GPIO_VIN_S4, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, +}; + +static int secjack_gpio_init(void) +{ + int rc; + + rc = pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_DET), + &ear_det); + if (rc) { + pr_err("%s PMIC_GPIO_EAR_DET config failed\n", __func__); + return rc; + } + rc = pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_SHORT_SENDEND), + &short_sendend); + if (rc) { + pr_err("%s PMIC_GPIO_SHORT_SENDEND config failed\n", __func__); + return rc; + } + rc = gpio_request( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + "EAR_MICBIAS"); + if (rc) { + pr_err("failed to request ear micbias gpio\n"); + gpio_free(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN)); + return rc; + } + rc = pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + &ear_micbiase); + if (rc) { + pr_err("%s PMIC_GPIO_EAR_MICBIAS_EN config failed\n", __func__); + return rc; + } else { + gpio_direction_output(PM8921_GPIO_PM_TO_SYS( + PMIC_GPIO_EAR_MICBIAS_EN), 0); + } + + return rc; +} +#endif + +void main_mic_bias_init(void) +{ + int ret; + ret = gpio_request(GPIO_MAIN_MIC_BIAS, "LDO_BIAS"); + if (ret) { + pr_err("%s: ldo bias gpio %d request" + "failed\n", __func__, GPIO_MAIN_MIC_BIAS); + return; + } + gpio_direction_output(GPIO_MAIN_MIC_BIAS, 0); +} + +static int configure_codec_lineout_gpio(void) +{ + int ret; + struct pm_gpio param = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 1, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + }; + + ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS( + gpio_rev(LINEOUT_EN)), ¶m); + if (ret) { + pr_err("%s: Failed to configure Lineout EN" + " gpio %d\n", __func__, + PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN))); + return ret; + } else + gpio_direction_output(PM8921_GPIO_PM_TO_SYS( + gpio_rev(LINEOUT_EN)), 1); + return 0; +} + +static int tabla_codec_ldo_en_init(void) +{ + int ret; + + ret = gpio_request(PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN)), + "LINEOUT_EN"); + if (ret) { + pr_err("%s:External LDO gpio %d request" + "failed\n", __func__, + PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN))); + return ret; + } + gpio_direction_output(PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN)), 0); + return 0; +} + +static void __init msm8960ab_update_krait_spm(void) +{ + int i; + + /* Reset the AVS registers until we have support for AVS */ + for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) { + struct msm_spm_platform_data *pdata = &msm_spm_data[i]; + pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0; + pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0; + } + + /* Update the SPM sequences for SPC and PC */ + for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) { + int j; + struct msm_spm_platform_data *pdata = &msm_spm_data[i]; + for (j = 0; j < pdata->num_modes; j++) { + if (pdata->modes[j].cmd == + spm_power_collapse_without_rpm) + pdata->modes[j].cmd = + spm_power_collapse_without_rpm_krait_v3; + else if (pdata->modes[j].cmd == + spm_power_collapse_with_rpm) + pdata->modes[j].cmd = + spm_power_collapse_with_rpm_krait_v3; + } + } +} + +static void __init msm8960_tsens_init(void) +{ + if (cpu_is_msm8960()) + if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) + return; + + msm_tsens_early_init(&msm_tsens_pdata); +} + +static void __init samsung_m2_spr_init(void) +{ +#ifdef CONFIG_ANDROID_RAM_CONSOLE + platform_device_register(&ram_console_device); +#endif +#ifdef CONFIG_SEC_DEBUG + sec_debug_init(); +#endif + + if (meminfo_init(SYS_MEMORY, SZ_256M) < 0) + pr_err("meminfo_init() failed!\n"); + + platform_device_register(&msm_gpio_device); + msm8960_tsens_init(); + msm_thermal_init(&msm_thermal_pdata); + BUG_ON(msm_rpm_init(&msm8960_rpm_data)); + BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data)); + + gpio_rev_init(); + regulator_suppress_info_printing(); + if (msm_xo_init()) + pr_err("Failed to initialize XO votes\n"); + platform_device_register(&msm8960_device_rpm_regulator); + msm_clock_init(&msm8960_clock_init_data); + if (machine_is_msm8960_liquid()) + msm_otg_pdata.mhl_enable = true; + msm8960_device_otg.dev.platform_data = &msm_otg_pdata; + if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() || + machine_is_msm8960_cdp()) { + msm_otg_pdata.phy_init_seq = wr_phy_init_seq; + } else if (machine_is_msm8960_liquid()) { + msm_otg_pdata.phy_init_seq = + liquid_v1_phy_init_seq; + } + android_usb_pdata.swfi_latency = + msm_rpmrs_levels[0].latency_us; + +#ifdef CONFIG_USB_HOST_NOTIFY + msm_otg_power_init(); +#endif +#ifdef CONFIG_VP_A2220 + if (system_rev > BOARD_REV02) + msm_gpiomux_install(msm8960_a2220_configs, + ARRAY_SIZE(msm8960_a2220_configs)); +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC + if (machine_is_msm8960_liquid()) { + if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2) + msm_hsic_pdata.hub_reset = HSIC_HUB_RESET_GPIO; + } +#endif + msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata; + msm8960_init_gpiomux(); + +#ifndef CONFIG_S5C73M3 + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); +#endif +#ifdef CONFIG_S5C73M3 + msm8960_device_qup_spi_gsbi11.dev.platform_data = + &msm8960_qup_spi_gsbi11_pdata; +#endif + +#ifndef CONFIG_S5C73M3 + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); +#endif +#ifdef CONFIG_BATTERY_SEC + check_highblock_temp(); +#endif /*CONFIG_BATTERY_SEC*/ + msm8960_init_pmic(); + msm8960_i2c_init(); + msm8960_gfx_init(); + if (cpu_is_msm8960ab()) + msm8960ab_update_krait_spm(); + msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data)); + msm_spm_l2_init(msm_spm_l2_data); + msm8960_init_buses(); + if (cpu_is_msm8960ab()) { + platform_add_devices(msm8960ab_footswitch, + msm8960ab_num_footswitch); + } else { + platform_add_devices(msm8960_footswitch, + msm8960_num_footswitch); + } + if (machine_is_msm8960_liquid()) + platform_device_register(&msm8960_device_ext_3p3v_vreg); + if (cpu_is_msm8960ab()) + platform_device_register(&msm8960ab_device_acpuclk); + else + platform_device_register(&msm8960_device_acpuclk); + platform_add_devices(common_devices, ARRAY_SIZE(common_devices)); + msm8960_pm8921_gpio_mpp_init(); + platform_add_devices(m2_spr_devices, ARRAY_SIZE(m2_spr_devices)); + msm8960_init_hsic(); + msm8960_init_cam(); + msm8960_init_mmc(); + if (machine_is_msm8960_liquid()) + mxt_init_hw_liquid(); + samsung_sys_class_init(); + mms_tsp_input_init(); +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + sensor_device_init(); +#endif +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + mpl_init(); +#endif +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + opt_init(); +#endif +#if defined(CONFIG_NFC_PN544) + pn544_init(); +#endif + msm8960_mhl_gpio_init(); + register_i2c_devices(); + msm8960_init_fb(); + main_mic_bias_init(); + /* From REV07 onwards LINEOUT_EN is not used */ + if (system_rev < BOARD_REV07) { + tabla_codec_ldo_en_init(); + configure_codec_lineout_gpio(); + } + +#ifdef CONFIG_SAMSUNG_JACK + if (system_rev < BOARD_REV08) { + pr_info("%s : system rev = %d, MBHC Using\n", + __func__, system_rev); + memset(&sec_jack_data, 0, sizeof(sec_jack_data)); + } else { + pr_info("%s : system rev = %d, Secjack Using\n", + __func__, system_rev); + secjack_gpio_init(); + } +#endif + + msm8960_init_dsps(); +#if 0 + msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ); +#endif + change_memory_power = &msm8960_change_memory_power; + BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata)); +#if 0 + msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data); +#endif +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) + printk(KERN_INFO "[WIFI] system_rev = %d\n", system_rev); + if (system_rev >= BOARD_REV03) + brcm_wlan_init(); +#endif + msm_pm_set_tz_retention_flag(1); + + if (PLATFORM_IS_CHARM25()) + platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices)); + ion_adjust_secure_allocation(); +} + +MACHINE_START(M2_SPR, "SAMSUNG M2_SPR") + .map_io = msm8960_map_io, + .reserve = msm8960_reserve, + .init_irq = msm8960_init_irq, + .handle_irq = gic_handle_irq, + .timer = &msm_timer, + .init_machine = samsung_m2_spr_init, + .init_early = msm8960_allocate_memory_regions, + .init_very_early = msm8960_early_memory, + .restart = msm_restart, +MACHINE_END +#endif diff --git a/arch/arm/mach-msm/board-m2_vzw-gpiomux.c b/arch/arm/mach-msm/board-m2_vzw-gpiomux.c new file mode 100644 index 00000000000..5f073e531b5 --- /dev/null +++ b/arch/arm/mach-msm/board-m2_vzw-gpiomux.c @@ -0,0 +1,1103 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include "devices.h" +#include "board-8960.h" +#include +#include + +/* The SPI configurations apply to GSBI 1*/ +static struct gpiomux_setting spi_active = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_12MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting spi_suspended_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting spi_active_config2 = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting spi_suspended_config2 = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting gsbi3_suspended_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting gsbi1 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_12MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi3_active_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi5 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi7 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#ifdef CONFIG_VP_A2220 +static struct gpiomux_setting gsbi8 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +static struct gpiomux_setting audience_suspend_gpio_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif +static struct gpiomux_setting gsbi10 = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting gsbi12 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_mclk = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#if 0 +static struct gpiomux_setting audio_auxpcm[] = { + /* Suspended state */ + { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + }, + /* Active state */ + { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, + }, +}; +#endif +#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE) +static struct gpiomux_setting gpio_eth_config = { + .pull = GPIOMUX_PULL_NONE, + .drv = GPIOMUX_DRV_8MA, + .func = GPIOMUX_FUNC_GPIO, +}; +#endif +#if 0 +static struct gpiomux_setting slimbus = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_KEEPER, +}; +#endif +static struct gpiomux_setting gpio_key_active_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting gpio_key_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting wcnss_5wire_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting wcnss_5wire_active_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_6MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT +static struct gpiomux_setting sdc4_suspend_cfg = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting sdc4_suspend2_cfg = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting sdc4_active_cfg = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_16MA, + .pull = GPIOMUX_PULL_UP, +}; +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC +static struct gpiomux_setting hsic_act_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_12MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting hsic_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_OUT_LOW, +}; + +static struct gpiomux_setting hsic_hub_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif + +static struct gpiomux_setting hap_lvl_shft_suspended_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting hap_lvl_shft_active_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting ap2mdm_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting mdm2ap_status_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting mdm2ap_errfatal_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_16MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting mdp_vsync_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting mdp_vsync_active_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static struct gpiomux_setting hdmi_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting hdmi_active_1_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting hdmi_active_2_cfg = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; +#if 0 +static struct gpiomux_setting hdmi_active_3_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_IN, +}; +static struct gpiomux_setting hdmi_active_4_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, + .dir = GPIOMUX_OUT_HIGH, +}; +#endif +#endif +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +static struct gpiomux_setting mhl_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting mhl_active_1_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, + .dir = GPIOMUX_OUT_LOW, +}; +#if 0 +static struct gpiomux_setting mhl_active_2_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif +#endif + +#ifdef CONFIG_USB_SWITCH_FSA9485 +static struct gpiomux_setting fsa9485_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting fsa9485_active_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_fsa9485_configs[] __initdata = { + { + .gpio = 14, + .settings = { + [GPIOMUX_ACTIVE] = &fsa9485_active_cfg, + [GPIOMUX_SUSPENDED] = &fsa9485_suspend_cfg, + }, + }, + + { + .gpio = 73, + .settings = { + [GPIOMUX_ACTIVE] = &fsa9485_active_cfg, + [GPIOMUX_SUSPENDED] = &fsa9485_suspend_cfg, + }, + }, + + { + .gpio = 74, + .settings = { + [GPIOMUX_ACTIVE] = &fsa9485_active_cfg, + [GPIOMUX_SUSPENDED] = &fsa9485_suspend_cfg, + }, + }, +}; +#endif + +#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE) +static struct msm_gpiomux_config msm8960_ethernet_configs[] = { + { + .gpio = 90, + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_eth_config, + } + }, + { + .gpio = 89, + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_eth_config, + } + }, +}; +#endif + +struct msm_gpiomux_config msm8960_gpio_key_configs[] = { + { + .settings = { + [GPIOMUX_ACTIVE] = &gpio_key_active_cfg, + [GPIOMUX_SUSPENDED] = &gpio_key_suspend_cfg, + } + }, + { + .settings = { + [GPIOMUX_ACTIVE] = &gpio_key_active_cfg, + [GPIOMUX_SUSPENDED] = &gpio_key_suspend_cfg, + } + }, + { + .gpio = GPIO_HOME_KEY, + .settings = { + [GPIOMUX_ACTIVE] = &gpio_key_active_cfg, + [GPIOMUX_SUSPENDED] = &gpio_key_suspend_cfg, + } + }, +}; +#ifdef CONFIG_VP_A2220 +static struct msm_gpiomux_config audience_suspend_configs[] __initdata = { + { + .gpio = 35, /* 2MIC PW DN */ + .settings = { + [GPIOMUX_SUSPENDED] = &audience_suspend_gpio_config, + }, + }, + { + .gpio = 75, /* 2MIC RESET */ + .settings = { + [GPIOMUX_SUSPENDED] = &audience_suspend_gpio_config, + }, + }, +}; +#endif + +static struct msm_gpiomux_config msm8960_gsbi_configs[] __initdata = { + { + .gpio = 6, /* GSBI1 QUP SPI_DATA_MOSI */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = 7, /* GSBI1 QUP SPI_DATA_MISO */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = 8, /* GSBI1 QUP SPI_CS_N */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi1, + [GPIOMUX_ACTIVE] = &gsbi1, + }, + }, + { + .gpio = 9, /* GSBI1 QUP SPI_CLK */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi1, + [GPIOMUX_ACTIVE] = &gsbi1, + }, + }, + { + .gpio = 14, /* GSBI1 SPI_CS_1 */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config2, + [GPIOMUX_ACTIVE] = &spi_active_config2, + }, + }, + { + .gpio = 16, /* GSBI3 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg, + [GPIOMUX_ACTIVE] = &gsbi3_active_cfg, + }, + }, + { + .gpio = 17, /* GSBI3 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg, + [GPIOMUX_ACTIVE] = &gsbi3_active_cfg, + }, + }, + { + .gpio = 22, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 23, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 24, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 25, /* GSBI5 UART2 */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi5, + }, + }, + { + .gpio = 32, /* GSBI7 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi7, + }, + }, + { + .gpio = 33, /* GSBI7 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi7, + }, + }, +#ifdef CONFIG_S5C73M3 + { + .gpio = GPIO_CAM_SPI_MOSI, /* GSBI11 QUP SPI_DATA_MOSI */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = GPIO_CAM_SPI_MISO, /* GSBI11 QUP SPI_DATA_MISO */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = GPIO_CAM_SPI_SSN, /* GSBI11 QUP SPI_CS_N */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, + { + .gpio = GPIO_CAM_SPI_SCLK, /* GSBI11 QUP SPI_CLK */ + .settings = { + [GPIOMUX_SUSPENDED] = &spi_suspended_config, + [GPIOMUX_ACTIVE] = &spi_active, + }, + }, +#endif + { + .gpio = 44, /* GSBI12 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi12, + }, + }, + { + .gpio = 45, /* GSBI12 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi12, + }, + }, +#ifdef CONFIG_VP_A2220 + { + .gpio = 36, /* GSBI8 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi8, + }, + }, + { + .gpio = 37, /* GSBI8 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi8, + }, + }, +#endif + { + .gpio = 73, /* GSBI10 I2C QUP SDA */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi10, + }, + }, + { + .gpio = 74, /* GSBI10 I2C QUP SCL */ + .settings = { + [GPIOMUX_SUSPENDED] = &gsbi10, + }, + }, +}; +#if 0 +static struct msm_gpiomux_config msm8960_slimbus_config[] __initdata = { + { + .gpio = 60, /* slimbus data */ + .settings = { + [GPIOMUX_SUSPENDED] = &slimbus, + }, + }, + { + .gpio = 61, /* slimbus clk */ + .settings = { + [GPIOMUX_SUSPENDED] = &slimbus, + }, + }, +}; +#endif +static struct msm_gpiomux_config msm8960_audio_codec_configs[] __initdata = { + { + .gpio = 59, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_mclk, + }, + }, +}; + +static struct gpiomux_setting cdc_i2s_mclk = { + .func = GPIOMUX_FUNC_1, +#if defined(_d2usc_) + .drv = GPIOMUX_DRV_2MA, +#else + .drv = GPIOMUX_DRV_8MA, +#endif + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_rx_sclk = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_rx_dout = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_rx_ws = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_audio_i2s_rx_codec_configs[] = { + { + .gpio = 59, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_mclk, + }, + }, + { + .gpio = 60, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_rx_sclk, + }, + }, + { + .gpio = 61, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_rx_dout, + }, + }, + { + .gpio = 62, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_rx_ws, + }, + }, +}; + +static struct gpiomux_setting cdc_i2s_tx_sclk = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting cdc_i2s_tx_d0 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#if 0 +static struct gpiomux_setting cdc_i2s_tx_d1 = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; +#endif +static struct gpiomux_setting cdc_i2s_tx_ws = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_audio_i2s_tx_codec_configs[] = { + { + .gpio = 59, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_mclk, + }, + }, + { + .gpio = 55, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_tx_sclk, + }, + }, + { + .gpio = 56, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_tx_ws, + }, + }, + { + .gpio = 57, + .settings = { + [GPIOMUX_SUSPENDED] = &cdc_i2s_tx_d0, + }, + }, + +}; + +#if 0 +static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = { + { + .gpio = 63, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, + { + .gpio = 64, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, + { + .gpio = 65, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, + { + .gpio = 66, + .settings = { + [GPIOMUX_SUSPENDED] = &audio_auxpcm[0], + [GPIOMUX_ACTIVE] = &audio_auxpcm[1], + }, + }, +}; +#endif +static struct msm_gpiomux_config wcnss_5wire_interface[] = { + { + .gpio = 84, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 85, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 86, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 87, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, + { + .gpio = 88, + .settings = { + [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg, + [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg, + }, + }, +}; + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT +static struct msm_gpiomux_config sdc4_interface[] = { + { + .gpio = 83, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 84, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 85, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 86, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 87, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend_cfg, + }, + }, + { + .gpio = 88, + .settings = { + [GPIOMUX_ACTIVE] = &sdc4_active_cfg, + [GPIOMUX_SUSPENDED] = &sdc4_suspend2_cfg, + }, + }, +}; +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC +static struct msm_gpiomux_config msm8960_hsic_configs[] = { + { + .gpio = 150, /*HSIC_STROBE */ + .settings = { + [GPIOMUX_ACTIVE] = &hsic_act_cfg, + [GPIOMUX_SUSPENDED] = &hsic_sus_cfg, + }, + }, + { + .gpio = 151, /* HSIC_DATA */ + .settings = { + [GPIOMUX_ACTIVE] = &hsic_act_cfg, + [GPIOMUX_SUSPENDED] = &hsic_sus_cfg, + }, + }, + { + .gpio = 91, /* HSIC_HUB_RESET */ + .settings = { + [GPIOMUX_ACTIVE] = &hsic_hub_act_cfg, + [GPIOMUX_SUSPENDED] = &hsic_sus_cfg, + }, + }, +}; +#endif + +static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = { + { + .gpio = 47, + .settings = { + [GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config, + [GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config, + }, + }, +}; + +static struct msm_gpiomux_config mdm_configs[] __initdata = { + /* AP2MDM_STATUS */ + { + .gpio = 94, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_cfg, + } + }, + /* MDM2AP_STATUS */ + { + .gpio = 69, + .settings = { + [GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg, + } + }, + /* MDM2AP_ERRFATAL */ + { + .gpio = 70, + .settings = { + [GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg, + } + }, + /* AP2MDM_ERRFATAL */ + { + .gpio = 95, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_cfg, + } + }, + /* AP2MDM_KPDPWR_N */ + { + .gpio = 81, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg, + } + }, + /* AP2MDM_PMIC_RESET_N */ + { + .gpio = 80, + .settings = { + [GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg, + } + } +}; + +static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = { + { + .gpio = 0, + .settings = { + [GPIOMUX_ACTIVE] = &mdp_vsync_active_cfg, + [GPIOMUX_SUSPENDED] = &mdp_vsync_suspend_cfg, + }, + } +}; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static struct msm_gpiomux_config msm8960_hdmi_configs[] __initdata = { + { + .gpio = 99, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 100, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 101, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 102, + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_2_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, +}; +#endif +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +static struct msm_gpiomux_config msm8960_mhl_configs[] __initdata = { + { + .gpio = GPIO_MHL_EN, + .settings = { + [GPIOMUX_ACTIVE] = &mhl_active_1_cfg, + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_RST, + .settings = { + [GPIOMUX_ACTIVE] = &mhl_active_1_cfg, + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_WAKE_UP, + .settings = { + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_SDA, + .settings = { + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + { + .gpio = GPIO_MHL_SCL, + .settings = { + [GPIOMUX_SUSPENDED] = &mhl_suspend_cfg, + }, + }, + + + +}; +#endif + +#ifdef CONFIG_I2C + +#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3 +#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10 + +#endif + +static struct gpiomux_setting sec_ts_int_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting sec_ts_int_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct msm_gpiomux_config msm8960_sec_ts_configs[] = { + { /* TS INTERRUPT */ + .gpio = 11, + .settings = { + [GPIOMUX_ACTIVE] = &sec_ts_int_act_cfg, + [GPIOMUX_SUSPENDED] = &sec_ts_int_sus_cfg, + }, + }, +}; + + +static struct gpiomux_setting sec_prox_int_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct gpiomux_setting sec_prox_int_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_sec_sensor_configs[] = { + { /* PS INTERRUPT */ + .gpio = 42, + .settings = { + [GPIOMUX_ACTIVE] = &sec_prox_int_act_cfg, + [GPIOMUX_SUSPENDED] = &sec_prox_int_sus_cfg, + }, + }, +}; + +int __init msm8960_init_gpiomux(void) +{ + int rc = msm_gpiomux_init(NR_GPIO_IRQS); + if (rc) { + pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc); + return rc; + } + +#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE) + msm_gpiomux_install(msm8960_ethernet_configs, + ARRAY_SIZE(msm8960_ethernet_configs)); +#endif + + msm_gpiomux_install(msm8960_gsbi_configs, + ARRAY_SIZE(msm8960_gsbi_configs)); + +#ifdef CONFIG_VP_A2220 + msm_gpiomux_install(audience_suspend_configs, + ARRAY_SIZE(audience_suspend_configs)); +#endif + msm8960_gpio_key_configs[0].gpio = gpio_rev(VOLUME_UP); + msm8960_gpio_key_configs[1].gpio = gpio_rev(VOLUME_DOWN); + if (system_rev < BOARD_REV13) + msm_gpiomux_install(msm8960_gpio_key_configs, 2); + else + msm_gpiomux_install(msm8960_gpio_key_configs, + ARRAY_SIZE(msm8960_gpio_key_configs)); + + msm_gpiomux_install(msm8960_sec_ts_configs, + ARRAY_SIZE(msm8960_sec_ts_configs)); + + msm_gpiomux_install(msm8960_sec_sensor_configs, + ARRAY_SIZE(msm8960_sec_sensor_configs)); + + msm_gpiomux_install(msm8960_audio_codec_configs, + ARRAY_SIZE(msm8960_audio_codec_configs)); + +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + if (system_rev >= BOARD_REV09) + msm_gpiomux_install(sdc4_interface, ARRAY_SIZE(sdc4_interface)); + else +#endif + msm_gpiomux_install(wcnss_5wire_interface, + ARRAY_SIZE(wcnss_5wire_interface)); + + msm_gpiomux_install(msm8960_audio_i2s_rx_codec_configs, + ARRAY_SIZE(msm8960_audio_i2s_tx_codec_configs)); + + msm_gpiomux_install(msm8960_audio_i2s_tx_codec_configs, + ARRAY_SIZE(msm8960_audio_i2s_tx_codec_configs)); + +#ifdef CONFIG_USB_SWITCH_FSA9485 + msm_gpiomux_install(msm8960_fsa9485_configs, + ARRAY_SIZE(msm8960_fsa9485_configs)); +#endif + + if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() || + machine_is_msm8960_liquid() || machine_is_msm8960_cdp()) + msm_gpiomux_install(hap_lvl_shft_config, + ARRAY_SIZE(hap_lvl_shft_config)); + + if (PLATFORM_IS_CHARM25()) + msm_gpiomux_install(mdm_configs, + ARRAY_SIZE(mdm_configs)); + +#ifdef CONFIG_USB_EHCI_MSM_HSIC + if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) && + (PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid())) + msm_gpiomux_install(msm8960_hsic_configs, + ARRAY_SIZE(msm8960_hsic_configs)); +#endif + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL + msm_gpiomux_install(msm8960_hdmi_configs, + ARRAY_SIZE(msm8960_hdmi_configs)); +#endif +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + msm_gpiomux_install(msm8960_mhl_configs, + ARRAY_SIZE(msm8960_mhl_configs)); +#endif + + msm_gpiomux_install(msm8960_mdp_vsync_configs, + ARRAY_SIZE(msm8960_mdp_vsync_configs)); + + return 0; +} diff --git a/arch/arm/mach-msm/board-m2_vzw.c b/arch/arm/mach-msm/board-m2_vzw.c new file mode 100644 index 00000000000..c1fca5902c7 --- /dev/null +++ b/arch/arm/mach-msm/board-m2_vzw.c @@ -0,0 +1,5546 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ANDROID_PMEM +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef CONFIG_USB_MSM_OTG_72K +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SENSORS_AK8975 +#include +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1 +#include +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 +#include +#endif + +#ifdef CONFIG_OPTICAL_GP2A +#include +#endif +#ifdef CONFIG_OPTICAL_GP2AP020A00F +#include +#endif +#ifdef CONFIG_VP_A2220 +#include +#endif +#ifdef CONFIG_INPUT_BMP180 +#include +#endif +#ifdef CONFIG_WCD9310_CODEC +#include +#include +#include +#endif +#ifdef CONFIG_KEYBOARD_GPIO +#include +#endif +#ifdef CONFIG_USB_SWITCH_FSA9485 +#include +#include +#endif + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +#include +#endif + +#include +#ifdef CONFIG_PM8921_CHARGER +#include +#endif +#ifdef CONFIG_PM8921_SEC_CHARGER +#include +#endif +#ifdef CONFIG_BATTERY_SEC +#include +#endif +#ifdef CONFIG_CHARGER_SMB347 +#include +#endif +#ifdef CONFIG_BATTERY_MAX17040 +#include +#endif +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "timer.h" +#include "devices.h" +#include "devices-msm8x60.h" +#include "spm.h" +#include "board-8960.h" +#include "pm.h" +#include +#include "rpm_resources.h" +#include +#include "acpuclock.h" +#include "rpm_log.h" +#include "smd_private.h" +#ifdef CONFIG_NFC_PN544 +#include +#endif /* CONFIG_NFC_PN544 */ +#include "mach/board-msm8960-camera.h" +#include "pm-boot.h" +#include "msm_watchdog.h" +#ifdef CONFIG_SENSORS_CM36651 +#include +#endif +#ifdef CONFIG_REGULATOR_MAX8952 +#include +#include +#endif +#ifdef CONFIG_VIBETONZ +#include +#endif + +#ifdef CONFIG_SAMSUNG_JACK +#include +#endif + +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#endif + +#ifdef CONFIG_ANDROID_RAM_CONSOLE +#include +#endif + +extern int system_rev; +#ifdef CONFIG_TOUCHSCREEN_MMS144 +struct tsp_callbacks *charger_callbacks; +#endif + +static struct platform_device msm_fm_platform_init = { + .name = "iris_fm", + .id = -1, +}; + +#ifdef CONFIG_SEC_DEBUG +#include +#endif +unsigned int gpio_table[][GPIO_REV_MAX] = { +/* GPIO_INDEX Rev {#00,#01,#02,#03,#04,#05,#06,#07,#08,#09,#10,#11,#12,#13 } */ +/* MDP_VSYNC */ { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* VOLUME_UP */ { 12, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 50, 50, 50 }, +/* VOLUME_DOWN */ { 13, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81 }, +/* MHL_EN */ { 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19 }, +/* MHL_SDA */ { 97, 97, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95 }, +/* GPIO_MAG_RST */ { 66, 66, 66, 66, 66, 66, 66, 66, 66, 48, 48, 48, 48, 9 }, +/* ALS_INT */ { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 6 }, +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) +/* ALS_SDA */ { 63, 63, 63, 63, 63, 63, 63, 63, 63, 12, 12, 12, 12, 12 }, +/* ALS_SCL */ { 64, 64, 64, 64, 64, 64, 64, 64, 64, 13, 13, 13, 13, 13 }, +#endif +/* LCD_22V_EN */ { 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 4, 4, 4, 4 }, +/* LINEOUT_EN */ { -1, -1, -1, -1, -1, -1, -1, -1, 17, 5, 5, 5, 5, 5 }, +/* CAM_AF_EN */ { 54, 54, 54, 54, 54, 54, 54, 54, 54, 77, 77, 77, 77, 77 }, +/* CAM_FLASH_SW */ { 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 80 }, +/* A2220_WAKEUP */ { 79, 79, 79, 79, 79, 79, 79, 79, 79, 35, 35, 35, 35, 35 }, +/* A2220_SDA */ { 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 36, 36, 36, 36 }, +/* A2220_SCL */ { 13, 13, 13, 13, 13, 13, 13, 13, 13, 37, 37, 37, 37, 37 }, +/* BT_HOST_WAKE */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 10, 10, 10, 10 }, +/* BT_WAKE */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, 79, 79, 79, 79, 79 }, +/* BT_EN */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, 82, 82, 82, 82 }, +}; + +int gpio_rev(unsigned int index) +{ + if (system_rev >= GPIO_REV_MAX) + return -EINVAL; + + if (system_rev < BOARD_REV13) + return gpio_table[index][system_rev]; + else + return gpio_table[index][BOARD_REV13]; +} + +#if defined(CONFIG_OPTICAL_GP2AP020A00F) +static void gp2a_power_on(int onoff); +#endif + +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static void mpu_power_on(int onoff); +#endif + +#ifdef CONFIG_SENSORS_AK8975 +static void akm_power_on(int onoff); +#endif + +#ifdef CONFIG_INPUT_BMP180 +static void bmp180_power_on(int onoff); +#endif + +#ifdef CONFIG_SENSORS_CM36651 +static void cm36651_power_on(int onoff); +#endif + +#if defined(CONFIG_SENSORS_AK8975) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_INPUT_BMP180) || defined(CONFIG_OPTICAL_GP2A) || \ + defined(CONFIG_OPTICAL_GP2AP020A00F) || \ + defined(CONFIG_SENSORS_CM36651) +enum { + SNS_PWR_OFF, + SNS_PWR_ON, + SNS_PWR_KEEP +}; +#endif + + +#if defined(CONFIG_SENSORS_AK8975) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_INPUT_BMP180) || defined(CONFIG_OPTICAL_GP2A) +static void sensor_power_on_vdd(int, int); + +#endif + +#ifndef CONFIG_S5C73M3 +#define KS8851_RST_GPIO 89 +#define KS8851_IRQ_GPIO 90 +#endif + + +#define HAP_SHIFT_LVL_OE_GPIO 47 + +#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE) + +struct sx150x_platform_data msm8960_sx150x_data[] = { + [SX150X_CAM] = { + .gpio_base = GPIO_CAM_EXPANDER_BASE, + .oscio_is_gpo = false, + .io_pullup_ena = 0x0, + .io_pulldn_ena = 0xc0, + .io_open_drain_ena = 0x0, + .irq_summary = -1, + }, +}; + +#endif + +#ifdef CONFIG_I2C + +#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3 +#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10 + +#endif + +#if 0 +static struct gpiomux_setting sec_ts_ldo_act_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting sec_ts_ldo_sus_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct msm_gpiomux_config msm8960_sec_ts_configs[] = { + { /* TS LDO EN */ + .gpio = 10, + .settings = { + [GPIOMUX_ACTIVE] = &sec_ts_ldo_act_cfg, + [GPIOMUX_SUSPENDED] = &sec_ts_ldo_sus_cfg, + }, + }, +}; +#endif +#define MSM_PMEM_ADSP_SIZE 0x9600000 /* 150 Mbytes */ +#define MSM_PMEM_ADSP_SIZE_FOR_2GB 0xA500000 /* 165 Mbytes */ +#define MSM_PMEM_AUDIO_SIZE 0x4CF000 /* 1.375 Mbytes */ +#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */ +#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */ +#define MSM_HDMI_PRIM_PMEM_SIZE 0x4000000 /* 64 Mbytes */ + +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +#define HOLE_SIZE 0x20000 +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x280000 /* 2.5MB */ +#ifdef CONFIG_MSM_IOMMU +#define MSM_ION_MM_SIZE 0x3800000 +#define MSM_ION_SF_SIZE 0x0 +#define MSM_ION_SF_SIZE_FOR_2GB 0x0 +#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */ +#define MSM_ION_HEAP_NUM 7 +#else +#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE +#define MSM_ION_SF_SIZE 0x5000000 /* 80MB */ +#define MSM_ION_SF_SIZE_FOR_2GB 0x6400000 /* 100MB */ +#define MSM_ION_QSECOM_SIZE 0x1700000 /* (24MB) */ +#define MSM_ION_HEAP_NUM 8 +#endif +#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */ +#define MSM_ION_MFC_SIZE SZ_8K +#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE + +#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000) +#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE +#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE + +#define MSM8960_FIXED_AREA_START 0xb0000000 +#define MAX_FIXED_AREA_SIZE 0x10000000 +#define MSM_MM_FW_SIZE 0x200000 +#define MSM8960_FW_START (MSM8960_FIXED_AREA_START - MSM_MM_FW_SIZE) + +static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE; +#else +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000 +#define MSM_ION_HEAP_NUM 1 +#endif + +#ifdef CONFIG_KERNEL_PMEM_EBI_REGION +static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE; +static int __init pmem_kernel_ebi1_size_setup(char *p) +{ + pmem_kernel_ebi1_size = memparse(p, NULL); + return 0; +} +early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); +#endif + +#ifdef CONFIG_ANDROID_PMEM +static unsigned pmem_size = MSM_PMEM_SIZE; +static unsigned pmem_param_set; +static int __init pmem_size_setup(char *p) +{ + pmem_size = memparse(p, NULL); + pmem_param_set = 1; + return 0; +} +early_param("pmem_size", pmem_size_setup); + +static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE; + +static int __init pmem_adsp_size_setup(char *p) +{ + pmem_adsp_size = memparse(p, NULL); + return 0; +} +early_param("pmem_adsp_size", pmem_adsp_size_setup); + +static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE; + +static int __init pmem_audio_size_setup(char *p) +{ + pmem_audio_size = memparse(p, NULL); + return 0; +} +early_param("pmem_audio_size", pmem_audio_size_setup); +#endif + +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem", + .allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING, + .cached = 1, + .memory_type = MEMTYPE_EBI1, +}; + +static struct platform_device android_pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = {.platform_data = &android_pmem_pdata}, +}; + +static struct android_pmem_platform_data android_pmem_adsp_pdata = { + .name = "pmem_adsp", + .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, + .cached = 0, + .memory_type = MEMTYPE_EBI1, +}; +static struct platform_device android_pmem_adsp_device = { + .name = "android_pmem", + .id = 2, + .dev = { .platform_data = &android_pmem_adsp_pdata }, +}; + +static struct android_pmem_platform_data android_pmem_audio_pdata = { + .name = "pmem_audio", + .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, + .cached = 0, + .memory_type = MEMTYPE_EBI1, +}; + +static struct platform_device android_pmem_audio_device = { + .name = "android_pmem", + .id = 4, + .dev = { .platform_data = &android_pmem_audio_pdata }, +}; +#endif +#endif + +struct fmem_platform_data fmem_pdata = { +}; + +#define DSP_RAM_BASE_8960 0x8da00000 +#define DSP_RAM_SIZE_8960 0x1800000 +static int dspcrashd_pdata_8960 = 0xDEADDEAD; + +static struct resource resources_dspcrashd_8960[] = { + { + .name = "msm_dspcrashd", + .start = DSP_RAM_BASE_8960, + .end = DSP_RAM_BASE_8960 + DSP_RAM_SIZE_8960, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device msm_device_dspcrashd_8960 = { + .name = "msm_dspcrashd", + .num_resources = ARRAY_SIZE(resources_dspcrashd_8960), + .resource = resources_dspcrashd_8960, + .dev = { .platform_data = &dspcrashd_pdata_8960 }, +}; + +static struct memtype_reserve msm8960_reserve_table[] __initdata = { + [MEMTYPE_SMI] = { + }, + [MEMTYPE_EBI0] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, + [MEMTYPE_EBI1] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, +}; + +#if defined(CONFIG_MSM_RTB) +static struct msm_rtb_platform_data msm_rtb_pdata = { + .size = SZ_1M, +}; + +static int __init msm_rtb_set_buffer_size(char *p) +{ + int s; + + s = memparse(p, NULL); + msm_rtb_pdata.size = ALIGN(s, SZ_4K); + return 0; +} +early_param("msm_rtb_size", msm_rtb_set_buffer_size); + +static struct platform_device msm_rtb_device = { + .name = "msm_rtb", + .id = -1, + .dev = { + .platform_data = &msm_rtb_pdata, + }, +}; +#endif + +static void __init reserve_rtb_memory(void) +{ +#if defined(CONFIG_MSM_RTB) + msm8960_reserve_table[MEMTYPE_EBI1].size += msm_rtb_pdata.size; +#endif +} + +static void __init size_pmem_devices(void) +{ +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + android_pmem_adsp_pdata.size = pmem_adsp_size; + + if (!pmem_param_set) { + if (machine_is_msm8960_liquid()) + pmem_size = MSM_LIQUID_PMEM_SIZE; + if (msm8960_hdmi_as_primary_selected()) + pmem_size = MSM_HDMI_PRIM_PMEM_SIZE; + } + + android_pmem_pdata.size = pmem_size; + android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE; +#endif +#endif +} +#if 0 +static void __init reserve_memory_for(struct android_pmem_platform_data *p) +{ + msm8960_reserve_table[p->memory_type].size += p->size; +} +#endif +static void __init reserve_pmem_memory(void) +{ +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + reserve_memory_for(&android_pmem_adsp_pdata); + reserve_memory_for(&android_pmem_pdata); + reserve_memory_for(&android_pmem_audio_pdata); +#endif + msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; +#endif +} + +static int msm8960_paddr_to_memtype(unsigned int paddr) +{ + return MEMTYPE_EBI1; +} + +#define FMEM_ENABLED 0 + +#ifdef CONFIG_ION_MSM +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +static struct ion_cp_heap_pdata cp_mm_ion_pdata = { + .permission_type = IPT_TYPE_MM_CARVEOUT, + .align = SZ_64K, + .reusable = FMEM_ENABLED, + .mem_is_fmem = FMEM_ENABLED, + .fixed_position = FIXED_MIDDLE, + .iommu_map_all = 1, + .iommu_2x_map_domain = VIDEO_DOMAIN, +}; + +static struct ion_cp_heap_pdata cp_mfc_ion_pdata = { + .permission_type = IPT_TYPE_MFC_SHAREDMEM, + .align = PAGE_SIZE, + .reusable = 0, + .mem_is_fmem = FMEM_ENABLED, + .fixed_position = FIXED_HIGH, +}; + +static struct ion_co_heap_pdata co_ion_pdata = { + .adjacent_mem_id = INVALID_HEAP_ID, + .align = PAGE_SIZE, + .mem_is_fmem = 0, +}; + +static struct ion_co_heap_pdata fw_co_ion_pdata = { + .adjacent_mem_id = ION_CP_MM_HEAP_ID, + .align = SZ_128K, + .mem_is_fmem = FMEM_ENABLED, + .fixed_position = FIXED_LOW, +}; +#endif + +struct ion_platform_heap m2_ion_heaps[] = { + { + .id = ION_SYSTEM_HEAP_ID, + .type = ION_HEAP_TYPE_SYSTEM, + .name = ION_VMALLOC_HEAP_NAME, + }, +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + { + .id = ION_CP_MM_HEAP_ID, + .type = ION_HEAP_TYPE_CP, + .name = ION_MM_HEAP_NAME, + .size = MSM_ION_MM_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &cp_mm_ion_pdata, + }, + { + .id = ION_MM_FIRMWARE_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_MM_FIRMWARE_HEAP_NAME, + .size = MSM_ION_MM_FW_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &fw_co_ion_pdata, + }, + { + .id = ION_CP_MFC_HEAP_ID, + .type = ION_HEAP_TYPE_CP, + .name = ION_MFC_HEAP_NAME, + .size = MSM_ION_MFC_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &cp_mfc_ion_pdata, + }, +#ifndef CONFIG_MSM_IOMMU + { + .id = ION_SF_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_SF_HEAP_NAME, + .size = MSM_ION_SF_SIZE_FOR_2GB, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &co_ion_pdata, + }, +#endif + { + .id = ION_IOMMU_HEAP_ID, + .type = ION_HEAP_TYPE_IOMMU, + .name = ION_IOMMU_HEAP_NAME, + }, + { + .id = ION_QSECOM_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_QSECOM_HEAP_NAME, + .size = MSM_ION_QSECOM_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &co_ion_pdata, + }, + { + .id = ION_AUDIO_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_HEAP_NAME, + .size = MSM_ION_AUDIO_SIZE, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *) &co_ion_pdata, + }, +#endif +}; + +#if 0 +static u64 msm_dmamask = DMA_BIT_MASK(32); +static struct platform_device ion_mm_heap_device = { + .name = "ion-mm-heap-device", + .id = -1, + .dev = { + .dma_mask = &msm_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif +/** + * These heaps are listed in the order they will be allocated. Due to + * video hardware restrictions and content protection the FW heap has to + * be allocated adjacent (below) the MM heap and the MFC heap has to be + * allocated after the MM heap to ensure MFC heap is not more than 256MB + * away from the base address of the FW heap. + * However, the order of FW heap and MM heap doesn't matter since these + * two heaps are taken care of by separate code to ensure they are adjacent + * to each other. + * Don't swap the order unless you know what you are doing! + */ +static struct ion_platform_data ion_pdata = { + .nr = MSM_ION_HEAP_NUM, + .heaps = m2_ion_heaps, +}; + + +static struct platform_device ion_dev = { + .name = "ion-msm", + .id = 1, + .dev = { .platform_data = &ion_pdata }, +}; +#endif + +struct platform_device fmem_device = { + .name = "fmem", + .id = 1, + .dev = { .platform_data = &fmem_pdata }, +}; + +static void __init adjust_mem_for_liquid(void) +{ + unsigned int i; + + if (!pmem_param_set) { + if (machine_is_msm8960_liquid()) + msm_ion_sf_size = MSM_LIQUID_ION_SF_SIZE; + + if (msm8960_hdmi_as_primary_selected()) + msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE; + + if (machine_is_msm8960_liquid() || + msm8960_hdmi_as_primary_selected()) { + for (i = 0; i < ion_pdata.nr; i++) { + if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) { + ion_pdata.heaps[i].size = + msm_ion_sf_size; + pr_debug("msm_ion_sf_size 0x%x\n", + msm_ion_sf_size); + break; + } + } + } + } +} + +static void __init reserve_mem_for_ion(enum ion_memory_types mem_type, + unsigned long size) +{ + msm8960_reserve_table[mem_type].size += size; +} + +static void __init msm8960_reserve_fixed_area(unsigned long fixed_area_size) +{ +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + int ret; + + if (fixed_area_size > MAX_FIXED_AREA_SIZE) + panic("fixed area size is larger than %dM\n", + MAX_FIXED_AREA_SIZE >> 20); + + reserve_info->fixed_area_size = fixed_area_size; + reserve_info->fixed_area_start = MSM8960_FW_START; + + ret = memblock_remove(reserve_info->fixed_area_start, + reserve_info->fixed_area_size); + BUG_ON(ret); +#endif +} + + +/** + * Reserve memory for ION and calculate amount of reusable memory for fmem. + * We only reserve memory for heaps that are not reusable. However, we only + * support one reusable heap at the moment so we ignore the reusable flag for + * other than the first heap with reusable flag set. Also handle special case + * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be + * at a higher address than FW in addition to not more than 256MB away from the + * base address of the firmware. This means that if MM is reusable the other + * two heaps must be allocated in the same region as FW. This is handled by the + * mem_is_fmem flag in the platform data. In addition the MM heap must be + * adjacent to the FW heap for content protection purposes. + */ +static void __init reserve_ion_memory(void) +{ +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + unsigned int i; + unsigned int reusable_count = 0; + unsigned int fixed_size = 0; + unsigned int fixed_low_size, fixed_middle_size, fixed_high_size; + unsigned long fixed_low_start, fixed_middle_start, fixed_high_start; + struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1]; + + adjust_mem_for_liquid(); + fmem_pdata.size = 0; + fmem_pdata.reserved_size_low = 0; + fmem_pdata.reserved_size_high = 0; + fmem_pdata.align = PAGE_SIZE; + fixed_low_size = 0; + fixed_middle_size = 0; + fixed_high_size = 0; + + /* We only support 1 reusable heap. Check if more than one heap + * is specified as reusable and set as non-reusable if found. + */ + for (i = 0; i < ion_pdata.nr; ++i) { + struct ion_platform_heap *heap = &(ion_pdata.heaps[i]); + + if ((int)heap->type == ION_HEAP_TYPE_CP && heap->extra_data) { + struct ion_cp_heap_pdata *data = heap->extra_data; + + reusable_count += (data->reusable) ? 1 : 0; + + if (data->reusable && reusable_count > 1) { + pr_err("%s: Too many heaps specified as " + "reusable. Heap %s was not configured " + "as reusable.\n", __func__, heap->name); + data->reusable = 0; + } + } + } + + for (i = 0; i < ion_pdata.nr; ++i) { + struct ion_platform_heap *heap = + &(ion_pdata.heaps[i]); + int align = SZ_4K; + int iommu_map_all = 0; + int adjacent_mem_id = INVALID_HEAP_ID; + + if (heap->extra_data) { + int fixed_position = NOT_FIXED; + int mem_is_fmem = 0; + + if (!strcmp(heap->name, "mm") + && (mb->start >= 0xc0000000)) { + printk(KERN_ERR "heap->name %s, mb->start %x\n", + heap->name, mb->start); + heap->size = MSM_PMEM_ADSP_SIZE_FOR_2GB; + } + + switch ((int)heap->type) { + case ION_HEAP_TYPE_CP: + mem_is_fmem = ((struct ion_cp_heap_pdata *) + heap->extra_data)->mem_is_fmem; + fixed_position = ((struct ion_cp_heap_pdata *) + heap->extra_data)->fixed_position; + align = ((struct ion_cp_heap_pdata *) + heap->extra_data)->align; + iommu_map_all = + ((struct ion_cp_heap_pdata *) + heap->extra_data)->iommu_map_all; + break; + case ION_HEAP_TYPE_CARVEOUT: + mem_is_fmem = ((struct ion_co_heap_pdata *) + heap->extra_data)->mem_is_fmem; + fixed_position = ((struct ion_co_heap_pdata *) + heap->extra_data)->fixed_position; + adjacent_mem_id = ((struct ion_co_heap_pdata *) + heap->extra_data)->adjacent_mem_id; + break; + default: + break; + } + + if (iommu_map_all) { + if (heap->size & (SZ_64K-1)) { + heap->size = ALIGN(heap->size, SZ_64K); + pr_info("Heap %s not aligned to 64K. Adjusting size to %x\n", + heap->name, heap->size); + } + } + + if (mem_is_fmem && adjacent_mem_id != INVALID_HEAP_ID) + fmem_pdata.align = align; + + if (fixed_position != NOT_FIXED) + fixed_size += heap->size; + else + reserve_mem_for_ion(MEMTYPE_EBI1, heap->size); + + if (fixed_position == FIXED_LOW) + fixed_low_size += heap->size; + else if (fixed_position == FIXED_MIDDLE) + fixed_middle_size += heap->size; + else if (fixed_position == FIXED_HIGH) + fixed_high_size += heap->size; + + if (mem_is_fmem) + fmem_pdata.size += heap->size; + } + } + + if (!fixed_size) + return; + + if (fmem_pdata.size) { + fmem_pdata.reserved_size_low = fixed_low_size; + fmem_pdata.reserved_size_high = fixed_high_size; + } + + msm8960_reserve_fixed_area(fixed_size + MSM_MM_FW_SIZE); + + fixed_low_start = MSM8960_FIXED_AREA_START; + fixed_middle_start = fixed_low_start + fixed_low_size; + fixed_high_start = fixed_middle_start + fixed_middle_size; + + for (i = 0; i < ion_pdata.nr; ++i) { + struct ion_platform_heap *heap = &(ion_pdata.heaps[i]); + + if (heap->extra_data) { + int fixed_position = NOT_FIXED; + + switch ((int)heap->type) { + case ION_HEAP_TYPE_CP: + fixed_position = ((struct ion_cp_heap_pdata *) + heap->extra_data)->fixed_position; + break; + case ION_HEAP_TYPE_CARVEOUT: + fixed_position = ((struct ion_co_heap_pdata *) + heap->extra_data)->fixed_position; + break; + default: + break; + } + + switch (fixed_position) { + case FIXED_LOW: + heap->base = fixed_low_start; + break; + case FIXED_MIDDLE: + heap->base = fixed_middle_start; + break; + case FIXED_HIGH: + heap->base = fixed_high_start; + break; + default: + break; + } + } + } +#endif +} + +static void ion_adjust_secure_allocation(void) +{ + int i; + + for (i = 0; i < ion_pdata.nr; i++) { + struct ion_platform_heap *heap = + &(ion_pdata.heaps[i]); + + + if (heap->extra_data) { + switch ((int) heap->type) { + case ION_HEAP_TYPE_CP: + if (cpu_is_msm8960()) { + ((struct ion_cp_heap_pdata *) + heap->extra_data)->no_nonsecure_alloc = + 0; + } + + } + } + } +} + +static void __init reserve_mdp_memory(void) +{ + msm8960_mdp_writeback(msm8960_reserve_table); +} + +#if defined(CONFIG_MSM_CACHE_DUMP) +static struct msm_cache_dump_platform_data msm_cache_dump_pdata = { + .l2_size = L2_BUFFER_SIZE, +}; + +static struct platform_device msm_cache_dump_device = { + .name = "msm_cache_dump", + .id = -1, + .dev = { + .platform_data = &msm_cache_dump_pdata, + }, +}; + +#endif + +static void reserve_cache_dump_memory(void) +{ +#ifdef CONFIG_MSM_CACHE_DUMP + unsigned int spare; + unsigned int l1_size; + unsigned int total; + int ret; + + ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_GET_SIZE_COMMAND_ID, &spare, + sizeof(spare), &l1_size, sizeof(l1_size)); + + if (ret) + /* Fall back to something reasonable here */ + l1_size = L1_BUFFER_SIZE; + + total = l1_size + L2_BUFFER_SIZE; + + msm8960_reserve_table[MEMTYPE_EBI1].size += total; + msm_cache_dump_pdata.l1_size = l1_size; +#endif +} + +static void __init msm8960_calculate_reserve_sizes(void) +{ + size_pmem_devices(); + reserve_pmem_memory(); + reserve_ion_memory(); + reserve_mdp_memory(); + reserve_rtb_memory(); + reserve_cache_dump_memory(); +} + +static struct reserve_info msm8960_reserve_info __initdata = { + .memtype_reserve_table = msm8960_reserve_table, + .calculate_reserve_sizes = msm8960_calculate_reserve_sizes, + .reserve_fixed_area = msm8960_reserve_fixed_area, + .paddr_to_memtype = msm8960_paddr_to_memtype, +}; + +static int msm8960_memory_bank_size(void) +{ + return 1<<29; +} + +static void __init locate_unstable_memory(void) +{ + struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1]; + unsigned long bank_size; + unsigned long low, high; + + bank_size = msm8960_memory_bank_size(); + low = meminfo.bank[0].start; + high = mb->start + mb->size; + + /* Check if 32 bit overflow occured */ + if (high < mb->start) { + high = ~0UL; + mb->size-= 1 << 12; + } + + low &= ~(bank_size - 1); + + if (high - low <= bank_size) + return; + + msm8960_reserve_info.bank_size = bank_size; +#ifdef CONFIG_ENABLE_DMM + msm8960_reserve_info.low_unstable_address = mb->start - + MIN_MEMORY_BLOCK_SIZE + mb->size; + msm8960_reserve_info.max_unstable_size = 0 /* MIN_MEMORY_BLOCK_SIZE */; + pr_info("low unstable address %lx max size %lx bank size %lx\n", + msm8960_reserve_info.low_unstable_address, + msm8960_reserve_info.max_unstable_size, + msm8960_reserve_info.bank_size); +#else + msm8960_reserve_info.low_unstable_address = 0; + msm8960_reserve_info.max_unstable_size = 0; +#endif +} + +static void __init place_movable_zone(void) +{ +#ifdef CONFIG_ENABLE_DMM + movable_reserved_start = msm8960_reserve_info.low_unstable_address; + movable_reserved_size = msm8960_reserve_info.max_unstable_size; + pr_info("movable zone start %lx size %lx\n", + movable_reserved_start, movable_reserved_size); +#endif +} + +static void __init msm8960_early_memory(void) +{ + reserve_info = &msm8960_reserve_info; + locate_unstable_memory(); + place_movable_zone(); +} + +static char prim_panel_name[PANEL_NAME_MAX_LEN]; +static char ext_panel_name[PANEL_NAME_MAX_LEN]; +static int __init prim_display_setup(char *param) +{ + if (strnlen(param, PANEL_NAME_MAX_LEN)) + strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN); + return 0; +} +early_param("prim_display", prim_display_setup); + +static int __init ext_display_setup(char *param) +{ + if (strnlen(param, PANEL_NAME_MAX_LEN)) + strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN); + return 0; +} +early_param("ext_display", ext_display_setup); + +/* Exclude the last 4 kB to preserve the kexec hardboot page. */ +#ifdef CONFIG_ANDROID_RAM_CONSOLE +#define RAM_CONSOLE_START 0x9fde0000 +#define RAM_CONSOLE_SIZE 0x20000 + +static struct platform_device ram_console_device = { + .name = "ram_console", + .id = -1, +}; + +struct persistent_ram_descriptor ram_console_desc = { + .name = "ram_console", + .size = RAM_CONSOLE_SIZE, +}; + +struct persistent_ram ram_console_ram = { + .start = RAM_CONSOLE_START, + .size = RAM_CONSOLE_SIZE, + .num_descs = 1, + .descs = &ram_console_desc, +}; +#endif + +unsigned int address = 0xea000000; +unsigned int size = 0x100000; + +static void __init msm8960_reserve(void) +{ + int ret; + msm8960_set_display_params(prim_panel_name, ext_panel_name); + msm_reserve(); + if (fmem_pdata.size) { +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + if (reserve_info->fixed_area_size) { + fmem_pdata.phys = + reserve_info->fixed_area_start + MSM_MM_FW_SIZE; + pr_info("mm fw at %lx (fixed) size %x\n", + reserve_info->fixed_area_start, MSM_MM_FW_SIZE); + pr_info("fmem start %lx (fixed) size %lx\n", + fmem_pdata.phys, + fmem_pdata.size); + } +#endif + } + + if (system_rev >= 15) { + pr_err("Reserving memory at address %x size: %x\n", address, size); + ret = memblock_remove(address, size); + BUG_ON(ret); + } + +#ifdef CONFIG_KEXEC_HARDBOOT + memblock_remove(KEXEC_HB_PAGE_ADDR, SZ_4K); +#endif +} + +static int msm8960_change_memory_power(u64 start, u64 size, + int change_type) +{ + return soc_change_memory_power(start, size, change_type); +} + +static void __init msm8960_allocate_memory_regions(void) +{ + msm8960_allocate_fb_region(); +#ifdef CONFIG_ANDROID_RAM_CONSOLE + persistent_ram_early_init(&ram_console_ram); +#endif + +} +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +static void cypress_power_onoff(int onoff) +{ + int ret, rc; + static struct regulator *reg_l29, *reg_l10; + + pr_debug("power on entry\n"); + + if (!reg_l29) { + reg_l29 = regulator_get(NULL, "8921_l29"); + ret = regulator_set_voltage(reg_l29, 1800000, 1800000); + + if (IS_ERR(reg_l29)) { + pr_err("could not get 8921_l29, rc = %ld\n", + PTR_ERR(reg_l29)); + return; + } + } + + if (!reg_l10) { + reg_l10 = regulator_get(NULL, "8921_l10"); + ret = regulator_set_voltage(reg_l10, 3000000, 3000000); + + if (IS_ERR(reg_l10)) { + pr_err("could not get 8921_l10, rc = %ld\n", + PTR_ERR(reg_l10)); + return; + } + } + + if (onoff) { + ret = regulator_enable(reg_l29); + rc = regulator_enable(reg_l10); + if (ret) { + pr_err("enable l29 failed, rc=%d\n", ret); + return; + } + if (rc) { + pr_err("enable l10 failed, rc=%d\n", ret); + return; + } + pr_info("cypress_power_on is finished.\n"); + } else { + ret = regulator_disable(reg_l29); + rc = regulator_disable(reg_l10); + if (ret) { + pr_err("disable l29 failed, rc=%d\n", ret); + return; + } + if (rc) { + pr_err("enable l29failed, rc=%d\n", ret); + return; + } + pr_info("cypress_power_off is finished.\n"); + } +} + +static u8 touchkey_keycode[] = {KEY_BACK, KEY_MENU}; + +static struct cypress_touchkey_platform_data cypress_touchkey_pdata = { + .gpio_int = GPIO_TOUCH_KEY_INT, + .touchkey_keycode = touchkey_keycode, + .power_onoff = cypress_power_onoff, +}; + +static struct i2c_board_info touchkey_i2c_devices_info[] __initdata = { + { + I2C_BOARD_INFO("cypress_touchkey", 0x20), + .platform_data = &cypress_touchkey_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_TOUCH_KEY_INT), + }, +}; + +static struct i2c_gpio_platform_data cypress_touchkey_i2c_gpio_data = { + .sda_pin = GPIO_TOUCHKEY_SDA, + .scl_pin = GPIO_TOUCHKEY_SCL, + .udelay = 0, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0, +}; + +static struct platform_device touchkey_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_TOUCHKEY_I2C_BUS_ID, + .dev.platform_data = &cypress_touchkey_i2c_gpio_data, +}; + +#endif + +#ifdef CONFIG_USB_SWITCH_FSA9485 +static enum cable_type_t set_cable_status; +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD +static void fsa9485_mhl_cb(bool attached, int mhl_charge) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_mhl_cb attached (%d), mhl_charge(%d)\n", + attached, mhl_charge); + + if (attached) { + switch (mhl_charge) { + case 0: + case 1: + set_cable_status = CABLE_TYPE_USB; + break; + case 2: + set_cable_status = CABLE_TYPE_AC; + break; + } + } else { + set_cable_status = CABLE_TYPE_NONE; + } + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_USB: + value.intval = POWER_SUPPLY_TYPE_USB; + break; + case CABLE_TYPE_AC: + value.intval = POWER_SUPPLY_TYPE_MAINS; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("%s: invalid cable :%d\n", __func__, set_cable_status); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} +#else +static void fsa9485_mhl_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_mhl_cb attached %d\n", attached); + set_cable_status = attached ? CABLE_TYPE_MISC : CABLE_TYPE_NONE; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_MISC: + value.intval = POWER_SUPPLY_TYPE_MISC; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("%s: invalid cable :%d\n", __func__, set_cable_status); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} +#endif +static void fsa9485_otg_cb(bool attached) +{ + pr_info("fsa9485_otg_cb attached %d\n", attached); + + if (attached) { + pr_info("%s set id state\n", __func__); +// msm_otg_set_id_state(attached); + } +} + +static void fsa9485_usb_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_usb_cb attached %d\n", attached); + set_cable_status = attached ? CABLE_TYPE_USB : CABLE_TYPE_NONE; + + if (system_rev >= 0x9) { +// if (attached) { + pr_info("%s set vbus state\n", __func__); + msm_otg_set_vbus_state(attached); +// } + } + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_USB: + value.intval = POWER_SUPPLY_TYPE_USB; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("%s: invalid cable :%d\n", __func__, set_cable_status); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} + +static void fsa9485_charger_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9480_charger_cb attached %d\n", attached); + set_cable_status = attached ? CABLE_TYPE_AC : CABLE_TYPE_NONE; + + msm_otg_set_charging_state(attached); + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + +#ifdef CONFIG_TOUCHSCREEN_MMS144 + if (charger_callbacks && charger_callbacks->inform_charger) + charger_callbacks->inform_charger(charger_callbacks, attached); +#endif + + switch (set_cable_status) { + case CABLE_TYPE_AC: + value.intval = POWER_SUPPLY_TYPE_MAINS; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} + +static void fsa9485_uart_cb(bool attached) +{ + pr_info("fsa9485_uart_cb attached %d\n", attached); + + set_cable_status = attached ? CABLE_TYPE_UARTOFF : CABLE_TYPE_NONE; +} + +static struct switch_dev switch_dock = { + .name = "dock", +}; + +static void fsa9485_jig_cb(bool attached) +{ + pr_info("fsa9485_jig_cb attached %d\n", attached); + + set_cable_status = attached ? CABLE_TYPE_JIG : CABLE_TYPE_NONE; +} + +static void fsa9485_dock_cb(int attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9480_dock_cb attached %d\n", attached); + switch_set_state(&switch_dock, attached); + + set_cable_status = attached ? CABLE_TYPE_CARDOCK : CABLE_TYPE_NONE; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_CARDOCK: + value.intval = POWER_SUPPLY_TYPE_CARDOCK; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } +} + +static void fsa9485_usb_cdp_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_usb_cdp_cb attached %d\n", attached); + + set_cable_status = + attached ? CABLE_TYPE_CDP : CABLE_TYPE_NONE; + + if (system_rev >= 0x9) { + if (attached) { + pr_info("%s set vbus state\n", __func__); + msm_otg_set_vbus_state(attached); + } + } + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_CDP: + value.intval = POWER_SUPPLY_TYPE_USB_CDP; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } + +} +static void fsa9485_smartdock_cb(bool attached) +{ + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + pr_info("fsa9485_smartdock_cb attached %d\n", attached); + + set_cable_status = + attached ? CABLE_TYPE_SMART_DOCK : CABLE_TYPE_NONE; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return; + } + + switch (set_cable_status) { + case CABLE_TYPE_SMART_DOCK: + value.intval = POWER_SUPPLY_TYPE_USB_CDP; + break; + case CABLE_TYPE_NONE: + value.intval = POWER_SUPPLY_TYPE_BATTERY; + break; + default: + pr_err("invalid status:%d\n", attached); + return; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + if (ret) { + pr_err("%s: fail to set power_suppy ONLINE property(%d)\n", + __func__, ret); + } + +// msm_otg_set_smartdock_state(attached); +} + +static void fsa9485_audio_dock_cb(bool attached) +{ + pr_info("fsa9485_audio_dock_cb attached %d\n", attached); + +// msm_otg_set_smartdock_state(attached); +} + +static int fsa9485_dock_init(void) +{ + int ret; + + /* for CarDock, DeskDock */ + ret = switch_dev_register(&switch_dock); + if (ret < 0) { + pr_err("Failed to register dock switch. %d\n", ret); + return ret; + } + return 0; +} + +int msm8960_get_cable_type(void) +{ +#ifdef CONFIG_WIRELESS_CHARGING + union power_supply_propval value; + int i, ret = 0; + struct power_supply *psy; + + for (i = 0; i < 10; i++) { + psy = power_supply_get_by_name("battery"); + if (psy) + break; + } + if (i == 10) { + pr_err("%s: fail to get battery ps\n", __func__); + return -1; + } +#endif + + pr_info("cable type (%d) -----\n", set_cable_status); + + if (set_cable_status != CABLE_TYPE_NONE) { + switch (set_cable_status) { + case CABLE_TYPE_MISC: +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD + fsa9485_mhl_cb(1 , 0); +#else + fsa9485_mhl_cb(1); +#endif + break; + case CABLE_TYPE_USB: + fsa9485_usb_cb(1); + break; + case CABLE_TYPE_AC: + fsa9485_charger_cb(1); + break; +#ifdef CONFIG_WIRELESS_CHARGING + case CABLE_TYPE_WPC: + value.intval = POWER_SUPPLY_TYPE_WPC; + ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, + &value); + break; +#endif + default: + pr_err("invalid status:%d\n", set_cable_status); + break; + } + } + return set_cable_status; +} + +static struct i2c_gpio_platform_data fsa_i2c_gpio_data = { + .sda_pin = GPIO_USB_I2C_SDA, + .scl_pin = GPIO_USB_I2C_SCL, + .udelay = 2, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0, +}; + +static struct platform_device fsa_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_FSA9485_I2C_BUS_ID, + .dev.platform_data = &fsa_i2c_gpio_data, +}; + +static struct fsa9485_platform_data fsa9485_pdata = { + .otg_cb = fsa9485_otg_cb, + .usb_cb = fsa9485_usb_cb, + .charger_cb = fsa9485_charger_cb, + .uart_cb = fsa9485_uart_cb, + .jig_cb = fsa9485_jig_cb, + .dock_cb = fsa9485_dock_cb, + .dock_init = fsa9485_dock_init, + .usb_cdp_cb = fsa9485_usb_cdp_cb, + .smartdock_cb = fsa9485_smartdock_cb, + .audio_dock_cb = fsa9485_audio_dock_cb, +}; + +static struct i2c_board_info micro_usb_i2c_devices_info[] __initdata = { + { + I2C_BOARD_INFO("fsa9485", 0x4A >> 1), + .platform_data = &fsa9485_pdata, + .irq = MSM_GPIO_TO_INT(14), + }, +}; + +#endif + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + +static void msm8960_mhl_gpio_init(void) +{ + int ret; + + ret = gpio_request(GPIO_MHL_EN, "mhl_en"); + if (ret < 0) { + pr_err("mhl_en gpio_request is failed\n"); + return; + } + + ret = gpio_request(GPIO_MHL_RST, "mhl_rst"); + if (ret < 0) { + pr_err("mhl_rst gpio_request is failed\n"); + return; + } + +} + +static void mhl_gpio_config(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_RST, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); +} + +static struct i2c_gpio_platform_data mhl_i2c_gpio_data = { + .sda_pin = GPIO_MHL_SDA, + .scl_pin = GPIO_MHL_SCL, + .udelay = 3,/*(i2c clk speed: 500khz / udelay)*/ +}; + +static struct platform_device mhl_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_MHL_I2C_BUS_ID, + .dev = { + .platform_data = &mhl_i2c_gpio_data, + }, +}; +/* +gpio_interrupt pin is very changable each different h/w_rev or board. +*/ +int get_mhl_int_irq(void) +{ + return MSM_GPIO_TO_INT(GPIO_MHL_INT); +} + +static struct regulator *mhl_l12; + +static void sii9234_hw_onoff(bool onoff) +{ + int rc; + /*VPH_PWR : mhl_power_source + VMHL_3.3V, VSIL_A_1.2V, VMHL_1.8V + just power control with HDMI_EN pin or control Regulator12*/ + if (onoff) { + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + mhl_l12 = regulator_get(NULL, "8921_l12"); + rc = regulator_set_voltage(mhl_l12, 1200000, 1200000); + if (rc) + pr_err("error setting voltage\n"); + rc = regulator_enable(mhl_l12); + if (rc) + pr_err("error enabling regulator\n"); + usleep(1*1000); + + gpio_direction_output(GPIO_MHL_EN, 1); + } else { + gpio_direction_output(GPIO_MHL_EN, 0); + if (mhl_l12) { + rc = regulator_disable(mhl_l12); + if (rc) + pr_err("error disabling regulator\n"); + } + usleep_range(10000, 20000); + + if (gpio_direction_output(GPIO_MHL_RST, 0)) + pr_err("%s error in making GPIO_MHL_RST Low\n" + , __func__); + + gpio_tlmm_config(GPIO_CFG(GPIO_MHL_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + } + + return; +} + +static void sii9234_hw_reset(void) +{ + usleep_range(10000, 20000); + if (gpio_direction_output(GPIO_MHL_RST, 1)) + printk(KERN_ERR "%s error in making GPIO_MHL_RST HIGH\n", + __func__); + + usleep_range(5000, 20000); + if (gpio_direction_output(GPIO_MHL_RST, 0)) + printk(KERN_ERR "%s error in making GPIO_MHL_RST Low\n", + __func__); + + usleep_range(10000, 20000); + if (gpio_direction_output(GPIO_MHL_RST, 1)) + printk(KERN_ERR "%s error in making GPIO_MHL_RST HIGH\n", + __func__); + msleep(30); +} + +struct sii9234_platform_data sii9234_pdata = { + .get_irq = get_mhl_int_irq, + .hw_onoff = sii9234_hw_onoff, + .hw_reset = sii9234_hw_reset, + .gpio_cfg = mhl_gpio_config, + .swing_level = 0xEB, +#if defined(CONFIG_VIDEO_MHL_V2) + .vbus_present = fsa9485_mhl_cb, +#endif +}; + +static struct i2c_board_info mhl_i2c_board_info[] = { + { + I2C_BOARD_INFO("sii9234_mhl_tx", 0x72>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_tpi", 0x7A>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_hdmi_rx", 0x92>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_cbus", 0xC8>>1), + .platform_data = &sii9234_pdata, + }, +}; +#endif + +#ifdef CONFIG_BATTERY_SEC +static int is_sec_battery_using(void) +{ + if (system_rev >= 0x9) + return 1; + else + return 0; +} + +int check_battery_type(void) +{ + return BATT_TYPE_D2_ACTIVE; +} + +static struct sec_bat_platform_data sec_bat_pdata = { + .fuel_gauge_name = "fuelgauge", + .charger_name = "sec-charger", + .get_cable_type = msm8960_get_cable_type, + .sec_battery_using = is_sec_battery_using, + .check_batt_type = check_battery_type, + .iterm = 100, + .charge_duration = 8 * 60 * 60, + .recharge_duration = 2 * 60 * 60, + .max_voltage = 4350 * 1000, + .recharge_voltage = 4280 * 1000, + .event_block = 600, +#if defined(_d2usc_) + .high_block = 600, + .lpm_high_block = 600, +#else + .high_block = 510, + .lpm_high_block = 470, +#endif + .high_recovery = 440, + .high_recovery_wpc = 490, + .low_block = -50, + .low_recovery = -10, + .lpm_high_recovery = 440, + .lpm_low_block = -40, + .lpm_low_recovery = -10, + .wpc_charging_current = 700, +}; + +static struct platform_device sec_device_battery = { + .name = "sec-battery", + .id = -1, + .dev.platform_data = &sec_bat_pdata, +}; + +static void check_highblock_temp(void) +{ + if (system_rev < 0xd) + sec_bat_pdata.high_block = 600; +} + +#endif /* CONFIG_BATTERY_SEC */ + +static int is_smb347_using(void) +{ + if (system_rev >= 0x9) + return 1; + else + return 0; +} + +#ifdef CONFIG_CHARGER_SMB347 +static int is_smb347_inok_using(void) +{ + if (system_rev >= 0xc) + return 1; + + return 0; +} + +#ifdef CONFIG_WIRELESS_CHARGING +static void smb347_wireless_cb(void) +{ + set_cable_status = CABLE_TYPE_WPC; +} +#endif + +void smb347_hw_init(void) +{ + struct pm_gpio batt_int_param = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .function = PM_GPIO_FUNC_NORMAL, + }; + int rc = 0; + + gpio_tlmm_config(GPIO_CFG(GPIO_INOK_INT, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + + rc = gpio_request(GPIO_INOK_INT, "wpc-detect"); + if (rc < 0) { + pr_err("%s: GPIO_INOK_INT gpio_request failed\n", __func__); + return; + } + rc = gpio_direction_input(GPIO_INOK_INT); + if (rc < 0) { + pr_err("%s: GPIO_INOK_INT gpio_direction_input failed\n", + __func__); + return; + } + + if (system_rev >= 0xc) { + sec_bat_pdata.batt_int = + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT); + pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT), + &batt_int_param); + gpio_request( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT), + "batt_int"); + gpio_direction_input(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BATT_INT)); + } + pr_debug("%s : share gpioi2c with max17048\n", __func__); +} + +static int smb347_intr_trigger(int status) +{ + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + + if (!psy) { + pr_err("%s: fail to get battery ps\n", __func__); + return -ENODEV; + } + pr_info("%s : charging status =%d\n", __func__, status); + + value.intval = status; + + /*if (status) + value.intval = POWER_SUPPLY_STATUS_CHARGING; + else + value.intval = POWER_SUPPLY_STATUS_DISCHARGING;*/ + + return psy->set_property(psy, POWER_SUPPLY_PROP_STATUS, &value); +} + +static struct smb347_platform_data smb347_pdata = { + .hw_init = smb347_hw_init, + .chg_intr_trigger = smb347_intr_trigger, + .enable = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + .stat = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_CHG_STAT), + .smb347_using = is_smb347_using, + .inok = GPIO_INOK_INT, + .smb347_inok_using = is_smb347_inok_using, +#ifdef CONFIG_WIRELESS_CHARGING + .smb347_wpc_cb = smb347_wireless_cb, +#endif + .smb347_get_cable = msm8960_get_cable_type, +}; +#endif /* CONFIG_CHARGER_SMB347 */ + +#ifdef CONFIG_BATTERY_MAX17040 +void max17040_hw_init(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_FUEKGAUGE_I2C_SCL, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_FUELGAUGE_I2C_SDA, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_set_value(GPIO_FUEKGAUGE_I2C_SCL, 1); + gpio_set_value(GPIO_FUELGAUGE_I2C_SDA, 1); + + gpio_tlmm_config(GPIO_CFG(GPIO_FUEL_INT, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); +} + +static int max17040_low_batt_cb(void) +{ +#ifdef CONFIG_BATTERY_SEC + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + pr_err("%s: Low battery alert\n", __func__); + + + if (!psy) { + pr_err("%s: fail to get battery ps\n", __func__); + return -ENODEV; + } + + value.intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + return psy->set_property(psy, POWER_SUPPLY_PROP_CAPACITY_LEVEL, &value); +#else + pr_err("%s: Low battery alert\n", __func__); + + return 0; +#endif +} + +static struct max17040_platform_data max17043_pdata = { + .hw_init = max17040_hw_init, + .low_batt_cb = max17040_low_batt_cb, + .check_batt_type = check_battery_type, + .rcomp_value = 0x6d1c, +}; + +static struct i2c_gpio_platform_data fuelgauge_i2c_gpio_data = { + .sda_pin = GPIO_FUELGAUGE_I2C_SDA, + .scl_pin = GPIO_FUEKGAUGE_I2C_SCL, + .udelay = 2, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0, +}; + +static struct platform_device fuelgauge_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_FUELGAUGE_I2C_BUS_ID, + .dev.platform_data = &fuelgauge_i2c_gpio_data, +}; + +static struct i2c_board_info fg_i2c_board_info[] = { + { + I2C_BOARD_INFO("max17040", (0x6D >> 1)), + .platform_data = &max17043_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_FUEL_INT), + } +}; + +static struct i2c_board_info fg_smb_i2c_board_info[] = { +#ifdef CONFIG_CHARGER_SMB347 + { + I2C_BOARD_INFO("smb347", (0x0C >> 1)), + .platform_data = &smb347_pdata, + .irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_CHG_STAT), + }, +#endif + { + I2C_BOARD_INFO("max17040", (0x6D >> 1)), + .platform_data = &max17043_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_FUEL_INT), + } +}; +#endif /* CONFIG_BATTERY_MAX17040 */ + +#ifdef CONFIG_VIBETONZ +static struct vibrator_platform_data msm_8960_vibrator_pdata = { + .vib_model = HAPTIC_PWM, + .vib_pwm_gpio = GPIO_VIB_PWM, + .haptic_pwr_en_gpio = GPIO_HAPTIC_PWR_EN, + .vib_en_gpio = GPIO_VIB_ON, + .is_pmic_vib_en = 0, + .is_pmic_haptic_pwr_en = 0, +}; +static struct platform_device vibetonz_device = { + .name = "tspdrv", + .id = -1, + .dev = { + .platform_data = &msm_8960_vibrator_pdata , + }, +}; +#endif /* CONFIG_VIBETONZ */ + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) +static struct i2c_gpio_platform_data opt_i2c_gpio_data = { + .sda_pin = GPIO_SENSOR_ALS_SDA, + .scl_pin = GPIO_SENSOR_ALS_SCL, + .udelay = 5, +}; + +static struct platform_device opt_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_OPT_I2C_BUS_ID, + .dev = { + .platform_data = &opt_i2c_gpio_data, + }, +}; +#if defined(CONFIG_SENSORS_CM36651) +static void cm36651_led_onoff(int); + +static struct cm36651_platform_data cm36651_pdata = { + .cm36651_led_on = cm36651_led_onoff, + .cm36651_power_on = cm36651_power_on, + .irq = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_RGB_INT), + .threshold = 15, +}; +#endif +static struct i2c_board_info opt_i2c_borad_info[] = { + { +#if defined(CONFIG_OPTICAL_GP2A) + I2C_BOARD_INFO("gp2a", 0x88>>1), +#elif defined(CONFIG_OPTICAL_GP2AP020A00F) + I2C_BOARD_INFO("gp2a", 0x72>>1), +#endif + }, +#if defined(CONFIG_SENSORS_CM36651) + { + I2C_BOARD_INFO("cm36651", (0x30 >> 1)), + .platform_data = &cm36651_pdata, + }, +#endif +}; +#if 0 +static void gp2a_led_onoff(int); + +#if defined(CONFIG_OPTICAL_GP2A) +static struct opt_gp2a_platform_data opt_gp2a_data = { + .gp2a_led_on = gp2a_led_onoff, + .power_on = sensor_power_on_vdd, + .irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_RGB_INT), + .ps_status = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_RGB_INT), +}; +#elif defined(CONFIG_OPTICAL_GP2AP020A00F) +static struct gp2a_platform_data opt_gp2a_data = { + .gp2a_led_on = gp2a_led_onoff, + .power_on = gp2a_power_on, + .p_out = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_RGB_INT), + .adapt_num = MSM_OPT_I2C_BUS_ID, + .addr = 0x72>>1, + .version = 0, +}; +#endif + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) +static struct platform_device opt_gp2a = { + .name = "gp2a-opt", + .id = -1, + .dev = { + .platform_data = &opt_gp2a_data, + }, +}; +#endif +#endif +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 + struct mpu_platform_data mpu6050_data = { + .int_config = 0x10, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {-1, 0, 0, + 0, 1, 0, + 0, 0, -1}, + }; + + struct mpu_platform_data mpu6050_data_04 = { + .int_config = 0x10, + .orientation = {1, 0, 0, + 0, -1, 0, + 0, 0, -1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data_04 = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }; + + struct mpu_platform_data mpu6050_data_01 = { + .int_config = 0x10, + .orientation = {-1, 0, 0, + 0, 1, 0, + 0, 0, -1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data_01 = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }; + struct mpu_platform_data mpu6050_data_00 = { + .int_config = 0x10, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + .poweron = mpu_power_on, + }; + /* compass */ + static struct ext_slave_platform_data inv_mpu_ak8963_data_00 = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + }; +#endif + +#ifdef CONFIG_MPU_SENSORS_MPU6050B1 +#define SENSOR_MPU_NAME "mpu6050B1" +static struct mpu_platform_data mpu_data = { + .int_config = 0x12, + .orientation = {1, 0, 0, + 0, -1, 0, + 0, 0, -1}, + /* accel */ + .accel = { + .get_slave_descr = mantis_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x68, + .orientation = {1, 0, 0, + 0, -1, 0, + 0, 0, -1}, + }, + /* compass */ + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }, + .poweron = mpu_power_on, +}; + +static struct mpu_platform_data mpu_data_01 = { + .int_config = 0x12, + .orientation = {-1, 0, 0, + 0, 1, 0, + 0, 0, -1}, + /* accel */ + .accel = { + .get_slave_descr = mantis_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x68, + .orientation = {-1, 0, 0, + 0, 1, 0, + 0, 0, -1}, + }, + /* compass */ + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }, + .poweron = mpu_power_on, +}; + +static struct mpu_platform_data mpu_data_00 = { + .int_config = 0x12, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + /* accel */ + .accel = { + .get_slave_descr = mantis_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x68, + .orientation = {1, 0, 0, + 0, 1, 0, + 0, 0, 1}, + }, + /* compass */ + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = MSM_SNS_I2C_BUS_ID, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = {0, -1, 0, + 1, 0, 0, + 0, 0, 1}, + }, + .poweron = mpu_power_on, +}; +#endif /*CONFIG_MPU_SENSORS_MPU6050B1 */ + +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + +#ifdef CONFIG_SENSORS_AK8975 +static struct akm8975_platform_data akm8975_pdata = { + .gpio_data_ready_int = GPIO_MSENSE_RST, + .power_on = akm_power_on, +}; +#endif +#ifdef CONFIG_INPUT_BMP180 +static struct bmp_i2c_platform_data bmp180_pdata = { + .power_on = bmp180_power_on, +}; +#endif + +static struct i2c_board_info sns_i2c_borad_info[] = { +#ifdef CONFIG_MPU_SENSORS_MPU6050B1 + { + I2C_BOARD_INFO(SENSOR_MPU_NAME, 0x68), + .irq = MSM_GPIO_TO_INT(GPIO_MPU3050_INT), + .platform_data = &mpu_data, + }, +#endif +#ifdef CONFIG_SENSORS_AK8975 + { + I2C_BOARD_INFO("ak8975", 0x0C), + .platform_data = &akm8975_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_MSENSE_RST), + }, +#endif +#ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 + { + I2C_BOARD_INFO("mpu6050", 0x68), + .irq = MSM_GPIO_TO_INT(GPIO_MPU3050_INT), + .platform_data = &mpu6050_data, + }, +#endif +#ifdef CONFIG_MPU_SENSORS_AK8975_411 + { + I2C_BOARD_INFO("ak8975_mod", 0x0C), + .platform_data = &inv_mpu_ak8963_data, + .irq = MSM_GPIO_TO_INT(GPIO_MSENSE_RST), + }, +#endif +#ifdef CONFIG_INPUT_BMP180 + { + I2C_BOARD_INFO("bmp180", 0x77), + .platform_data = &bmp180_pdata, + }, +#endif + +}; +#endif + +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static void mpl_init(void) +{ + int ret = 0; + ret = gpio_request(GPIO_MPU3050_INT, "MPUIRQ"); + if (ret) + pr_err("%s gpio request %d err\n", __func__, GPIO_MPU3050_INT); + else + gpio_direction_input(GPIO_MPU3050_INT); + +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) + if (system_rev == BOARD_REV01) + mpu_data = mpu_data_01; + else if (system_rev < BOARD_REV01) + mpu_data = mpu_data_00; + mpu_data.reset = gpio_rev(GPIO_MAG_RST); +#elif defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + if (system_rev <= BOARD_REV04 && system_rev > BOARD_REV01) { + mpu6050_data = mpu6050_data_04; + inv_mpu_ak8963_data = inv_mpu_ak8963_data_04; + } else if (system_rev == BOARD_REV01) { + mpu6050_data = mpu6050_data_01; + inv_mpu_ak8963_data = inv_mpu_ak8963_data_01; + } else if (system_rev < BOARD_REV01) { + mpu6050_data = mpu6050_data_00; + inv_mpu_ak8963_data = inv_mpu_ak8963_data_00; + } + if (system_rev < BOARD_REV13) + mpu6050_data.reset = gpio_rev(GPIO_MAG_RST); + else + mpu6050_data.reset = + PM8921_GPIO_PM_TO_SYS(gpio_rev(GPIO_MAG_RST)); +#endif +} +#endif + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) +static void opt_init(void) +{ + int ret = 0; + int prox_int = gpio_rev(ALS_INT); + struct pm_gpio prox_cfg = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + }; + + if (system_rev < BOARD_REV13) { + gpio_tlmm_config(GPIO_CFG(prox_int, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + } else { + prox_int = PM8921_GPIO_PM_TO_SYS(prox_int); + pm8xxx_gpio_config(prox_int, &prox_cfg); + } + + gpio_tlmm_config(GPIO_CFG(gpio_rev(ALS_SDA), 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(gpio_rev(ALS_SCL), 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + ret = gpio_request(prox_int, "PSVOUT"); + if (ret) { + pr_err("%s gpio request %d err\n", __func__, prox_int); + } else { + gpio_direction_input(prox_int); + gpio_free(prox_int); + } +} +#endif + +struct class *sec_class; +EXPORT_SYMBOL(sec_class); + +static void samsung_sys_class_init(void) +{ + pr_info("samsung sys class init.\n"); + + sec_class = class_create(THIS_MODULE, "sec"); + + if (IS_ERR(sec_class)) { + pr_err("Failed to create class(sec)!\n"); + return; + } + + pr_info("samsung sys class end.\n"); +}; + +#if defined(CONFIG_NFC_PN544) +static void pn544_conf_gpio(void) +{ + pr_debug("pn544_conf_gpio\n"); + + gpio_tlmm_config(GPIO_CFG(GPIO_NFC_SDA, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_NFC_SCL, 0, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + return; +} + +static int __init pn544_init(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_NFC_IRQ, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + pn544_conf_gpio(); + return 0; +} +#endif + +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) ||\ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + +static int __init sensor_device_init(void) +{ + int ret = 0; + int mag_rst = gpio_rev(GPIO_MAG_RST); + struct pm_gpio mag_rst_cfg = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .disable_pin = 0, + }; + + if (system_rev < BOARD_REV13) { + gpio_tlmm_config(GPIO_CFG(mag_rst, 0, + GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + } else { + mag_rst = PM8921_GPIO_PM_TO_SYS(mag_rst); + pm8xxx_gpio_config(mag_rst, &mag_rst_cfg); + } + sensor_power_on_vdd(SNS_PWR_ON, SNS_PWR_ON); + ret = gpio_request(mag_rst, "MAG_RST"); + if (ret) { + pr_err("%s gpio request %d err\n", __func__, mag_rst); + } else { + gpio_direction_output(mag_rst, 0); + usleep_range(20, 20); + gpio_set_value_cansleep(mag_rst, 1); + } + + return 0; +} +#endif + +#if defined(CONFIG_SENSORS_AK8975) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_INPUT_BMP180) || defined(CONFIG_OPTICAL_GP2A) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static struct regulator *vsensor_2p85, *vsensor_1p8; +static int sensor_power_2p85_cnt, sensor_power_1p8_cnt; + +static void sensor_power_on_vdd(int onoff_l9, int onoff_lvs4) +{ + int ret; + + if (vsensor_2p85 == NULL) { + vsensor_2p85 = regulator_get(NULL, "8921_l9"); + if (IS_ERR(vsensor_2p85)) + return ; + + ret = regulator_set_voltage(vsensor_2p85, 2850000, 2850000); + if (ret) + pr_err("%s: error vsensor_2p85 setting voltage ret=%d\n", + __func__, ret); + } + if (vsensor_1p8 == NULL) { + vsensor_1p8 = regulator_get(NULL, "8921_lvs4"); + if (IS_ERR(vsensor_1p8)) + return ; + } + + if (onoff_l9 == SNS_PWR_ON) { + sensor_power_2p85_cnt++; + ret = regulator_enable(vsensor_2p85); + if (ret) + pr_err("%s: error enabling regulator\n", __func__); + } else if ((onoff_l9 == SNS_PWR_OFF)) { + sensor_power_2p85_cnt--; + if (regulator_is_enabled(vsensor_2p85)) { + ret = regulator_disable(vsensor_2p85); + if (ret) + pr_err("%s: error vsensor_2p85 enabling regulator\n", + __func__); + } + } + if (onoff_lvs4 == SNS_PWR_ON) { + sensor_power_1p8_cnt++; + ret = regulator_enable(vsensor_1p8); + if (ret) + pr_err("%s: error enabling regulator\n", __func__); + } else if ((onoff_lvs4 == SNS_PWR_OFF)) { + sensor_power_1p8_cnt--; + if (regulator_is_enabled(vsensor_1p8)) { + ret = regulator_disable(vsensor_1p8); + if (ret) + pr_err("%s: error vsensor_1p8 enabling regulator\n", + __func__); + } + } +} + +#endif +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) +static void mpu_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#ifdef CONFIG_SENSORS_AK8975 +static void akm_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#ifdef CONFIG_INPUT_BMP180 +static void bmp180_power_on(int onoff) +{ + sensor_power_on_vdd(SNS_PWR_KEEP, onoff); +} +#endif + +#if defined(CONFIG_OPTICAL_GP2AP020A00F) +static void gp2a_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#if defined(CONFIG_SENSORS_CM36651) +static void cm36651_power_on(int onoff) +{ + sensor_power_on_vdd(onoff, onoff); +} +#endif + +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) +static void gp2a_led_onoff(int onoff) +{ + static struct regulator *reg_8921_leda; + static int prev_on; + int rc; + + if (onoff == prev_on) + return; + + if (!reg_8921_leda) { + reg_8921_leda = regulator_get(NULL, "8921_l16"); + rc = regulator_set_voltage(reg_8921_leda, + 3000000, 3000000); + if (rc) + pr_err("%s: error reg_8921_leda setting ret=%d\n", + __func__, rc); + } + + if (onoff) { + rc = regulator_enable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator enable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(on): success\n", __func__); + } else { + rc = regulator_disable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator disable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(off): success\n", __func__); + } + prev_on = onoff; +} +#endif + +#if defined(CONFIG_SENSORS_CM36651) + +static void cm36651_led_onoff(int onoff) +{ + static struct regulator *reg_8921_leda; + static int prev_on; + int rc; + + if (onoff == prev_on) + return; + + if (!reg_8921_leda) { + reg_8921_leda = regulator_get(NULL, "8921_l16"); + rc = regulator_set_voltage(reg_8921_leda, + 2800000, 2800000); + if (rc) + pr_err("%s: error reg_8921_leda setting ret=%d\n", + __func__, rc); + return; + } + + if (onoff) { + rc = regulator_enable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator enable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(on): success\n", __func__); + } else { + rc = regulator_disable(reg_8921_leda); + if (rc) { + pr_err("'%s' regulator disable failed, rc=%d\n", + "reg_8921_leda", rc); + return; + } + pr_debug("%s(off): success\n", __func__); + } + prev_on = onoff; +} +#endif + +#ifdef CONFIG_VP_A2220 +static int a2220_hw_init(void) +{ + int rc = 0; + + rc = gpio_request(gpio_rev(A2220_WAKEUP), "a2220_wakeup"); + if (rc < 0) { + pr_err("%s: gpio request wakeup pin failed\n", __func__); + goto err_alloc_data_failed; + } + + rc = gpio_direction_output(gpio_rev(A2220_WAKEUP), 1); + if (rc < 0) { + pr_err("%s: request wakeup gpio direction failed\n", __func__); + goto err_free_gpio; + } + + rc = gpio_request(MSM_AUD_A2220_RESET, "a2220_reset"); + if (rc < 0) { + pr_err("%s: gpio request reset pin failed\n", __func__); + goto err_free_gpio; + } + + rc = gpio_direction_output(MSM_AUD_A2220_RESET, 1); + if (rc < 0) { + pr_err("%s: request reset gpio direction failed\n", __func__); + goto err_free_gpio_all; + } + gpio_set_value(gpio_rev(A2220_WAKEUP), 1); + gpio_set_value(MSM_AUD_A2220_RESET, 1); + return rc; + +err_free_gpio_all: + gpio_free(MSM_AUD_A2220_RESET); +err_free_gpio: + gpio_free(gpio_rev(A2220_WAKEUP)); +err_alloc_data_failed: + pr_err("a2220_probe - failed\n"); + return rc; +} + +static struct a2220_platform_data a2220_data = { + .a2220_hw_init = a2220_hw_init, + .gpio_reset = MSM_AUD_A2220_RESET, +}; + +static struct i2c_board_info a2220_device[] __initdata = { + { + I2C_BOARD_INFO("audience_a2220", 0x3E), + .platform_data = &a2220_data, + }, +}; + +static struct i2c_gpio_platform_data a2220_i2c_gpio_data = { + .udelay = 1, +}; +#if 0 +static struct platform_device a2220_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_A2220_I2C_BUS_ID, + .dev.platform_data = &a2220_i2c_gpio_data, +}; +#endif +static struct gpiomux_setting a2220_gsbi_config = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_8MA, + .pull = GPIOMUX_PULL_NONE, +}; + +static struct msm_gpiomux_config msm8960_a2220_configs[] = { + { + .settings = { + [GPIOMUX_SUSPENDED] = &a2220_gsbi_config, + }, + }, + { + .settings = { + [GPIOMUX_SUSPENDED] = &a2220_gsbi_config, + }, + }, +}; +#endif +#ifdef CONFIG_WCD9310_CODEC + +#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS) + +/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement + * 4 micbiases are used to power various analog and digital + * microphones operating at 1800 mV. Technically, all micbiases + * can source from single cfilter since all microphones operate + * at the same voltage level. The arrangement below is to make + * sure all cfilters are exercised. LDO_H regulator ouput level + * does not need to be as high as 2.85V. It is choosen for + * microphone sensitivity purpose. + */ +#ifndef CONFIG_SLIMBUS_MSM_CTRL +static struct wcd9xxx_pdata tabla_i2c_platform_data = { + .irq = MSM_GPIO_TO_INT(58), + .irq_base = TABLA_INTERRUPT_BASE, + .num_irqs = NR_TABLA_IRQS, + .reset_gpio = PM8921_GPIO_PM_TO_SYS(38), + .micbias = { + .ldoh_v = TABLA_LDOH_2P85_V, + .cfilt1_mv = 1800, + .cfilt2_mv = 1800, + .cfilt3_mv = 1800, + .bias1_cfilt_sel = TABLA_CFILT1_SEL, + .bias2_cfilt_sel = TABLA_CFILT2_SEL, + .bias3_cfilt_sel = TABLA_CFILT3_SEL, + .bias4_cfilt_sel = TABLA_CFILT3_SEL, + }, + .regulator = { + { + .name = "CDC_VDD_CP", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX, + }, + { + .name = "CDC_VDDA_RX", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX, + }, + { + .name = "CDC_VDDA_TX", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX, + }, + { + .name = "VDDIO_CDC", + .min_uV = 1800000, + .max_uV = 1800000, + .optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX, + }, + { + .name = "VDDD_CDC_D", + .min_uV = 1225000, + .max_uV = 1225000, + .optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX, + }, + { + .name = "CDC_VDDA_A_1P2V", + .min_uV = 1225000, + .max_uV = 1225000, + .optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX, + }, + }, +}; +#endif +#endif +#define MSM_WCNSS_PHYS 0x03000000 +#define MSM_WCNSS_SIZE 0x280000 + +static struct resource resources_wcnss_wlan[] = { + { + .start = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ, + .end = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ, + .name = "wcnss_wlanrx_irq", + .flags = IORESOURCE_IRQ, + }, + { + .start = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ, + .end = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ, + .name = "wcnss_wlantx_irq", + .flags = IORESOURCE_IRQ, + }, + { + .start = MSM_WCNSS_PHYS, + .end = MSM_WCNSS_PHYS + MSM_WCNSS_SIZE - 1, + .name = "wcnss_mmio", + .flags = IORESOURCE_MEM, + }, + { + .start = 84, + .end = 88, + .name = "wcnss_gpios_5wire", + .flags = IORESOURCE_IO, + }, +}; + +static struct qcom_wcnss_opts qcom_wcnss_pdata = { + .has_48mhz_xo = 1, +}; + +static struct platform_device msm_device_wcnss_wlan = { + .name = "wcnss_wlan", + .id = 0, + .num_resources = ARRAY_SIZE(resources_wcnss_wlan), + .resource = resources_wcnss_wlan, + .dev = {.platform_data = &qcom_wcnss_pdata}, +}; + +#ifdef CONFIG_QSEECOM +/* qseecom bus scaling */ +static struct msm_bus_vectors qseecom_clks_init_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = 0, + .ab = 0, + }, +}; + +static struct msm_bus_vectors qseecom_enable_dfab_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = 0, + .ab = 0, + }, +}; + +static struct msm_bus_vectors qseecom_enable_sfpb_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = 0, + .ab = 0, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = (64 * 8) * 1000000UL, + .ab = (64 * 8) * 100000UL, + }, +}; + +static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_SPS, + .ib = (492 * 8) * 1000000UL, + .ab = (492 * 8) * 100000UL, + }, + { + .src = MSM_BUS_MASTER_SPDM, + .dst = MSM_BUS_SLAVE_SPDM, + .ib = (64 * 8) * 1000000UL, + .ab = (64 * 8) * 100000UL, + }, +}; + +static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = { + { + ARRAY_SIZE(qseecom_clks_init_vectors), + qseecom_clks_init_vectors, + }, + { + ARRAY_SIZE(qseecom_enable_dfab_vectors), + qseecom_enable_dfab_vectors, + }, + { + ARRAY_SIZE(qseecom_enable_sfpb_vectors), + qseecom_enable_sfpb_vectors, + }, + { + ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors), + qseecom_enable_dfab_sfpb_vectors, + }, +}; + +static struct msm_bus_scale_pdata qseecom_bus_pdata = { + qseecom_hw_bus_scale_usecases, + ARRAY_SIZE(qseecom_hw_bus_scale_usecases), + .name = "qsee", +}; + +static struct platform_device qseecom_device = { + .name = "qseecom", + .id = 0, + .dev = { + .platform_data = &qseecom_bus_pdata, + }, +}; +#endif +#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \ + defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE) + +#define QCE_SIZE 0x10000 +#define QCE_0_BASE 0x18500000 + +#define QCE_HW_KEY_SUPPORT 0 +#define QCE_SHA_HMAC_SUPPORT 1 +#define QCE_SHARE_CE_RESOURCE 1 +#define QCE_CE_SHARED 0 + +/* Begin Bus scaling definitions */ +static struct msm_bus_vectors crypto_hw_init_vectors[] = { + { + .src = MSM_BUS_MASTER_ADM_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, + { + .src = MSM_BUS_MASTER_ADM_PORT1, + .dst = MSM_BUS_SLAVE_GSBI1_UART, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors crypto_hw_active_vectors[] = { + { + .src = MSM_BUS_MASTER_ADM_PORT0, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 70000000UL, + .ib = 70000000UL, + }, + { + .src = MSM_BUS_MASTER_ADM_PORT1, + .dst = MSM_BUS_SLAVE_GSBI1_UART, + .ab = 2480000000UL, + .ib = 2480000000UL, + }, +}; + +static struct msm_bus_paths crypto_hw_bus_scale_usecases[] = { + { + ARRAY_SIZE(crypto_hw_init_vectors), + crypto_hw_init_vectors, + }, + { + ARRAY_SIZE(crypto_hw_active_vectors), + crypto_hw_active_vectors, + }, +}; + +static struct msm_bus_scale_pdata crypto_hw_bus_scale_pdata = { + crypto_hw_bus_scale_usecases, + ARRAY_SIZE(crypto_hw_bus_scale_usecases), + .name = "cryptohw", +}; +/* End Bus Scaling Definitions*/ + +static struct resource qcrypto_resources[] = { + [0] = { + .start = QCE_0_BASE, + .end = QCE_0_BASE + QCE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "crypto_channels", + .start = DMOV_CE_IN_CHAN, + .end = DMOV_CE_OUT_CHAN, + .flags = IORESOURCE_DMA, + }, + [2] = { + .name = "crypto_crci_in", + .start = DMOV_CE_IN_CRCI, + .end = DMOV_CE_IN_CRCI, + .flags = IORESOURCE_DMA, + }, + [3] = { + .name = "crypto_crci_out", + .start = DMOV_CE_OUT_CRCI, + .end = DMOV_CE_OUT_CRCI, + .flags = IORESOURCE_DMA, + }, +}; + +static struct resource qcedev_resources[] = { + [0] = { + .start = QCE_0_BASE, + .end = QCE_0_BASE + QCE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "crypto_channels", + .start = DMOV_CE_IN_CHAN, + .end = DMOV_CE_OUT_CHAN, + .flags = IORESOURCE_DMA, + }, + [2] = { + .name = "crypto_crci_in", + .start = DMOV_CE_IN_CRCI, + .end = DMOV_CE_IN_CRCI, + .flags = IORESOURCE_DMA, + }, + [3] = { + .name = "crypto_crci_out", + .start = DMOV_CE_OUT_CRCI, + .end = DMOV_CE_OUT_CRCI, + .flags = IORESOURCE_DMA, + }, +}; + +#endif + +#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \ + defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) + +static struct msm_ce_hw_support qcrypto_ce_hw_suppport = { + .ce_shared = QCE_CE_SHARED, + .shared_ce_resource = QCE_SHARE_CE_RESOURCE, + .hw_key_support = QCE_HW_KEY_SUPPORT, + .sha_hmac = QCE_SHA_HMAC_SUPPORT, + .bus_scale_table = &crypto_hw_bus_scale_pdata, +}; + +static struct platform_device qcrypto_device = { + .name = "qcrypto", + .id = 0, + .num_resources = ARRAY_SIZE(qcrypto_resources), + .resource = qcrypto_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &qcrypto_ce_hw_suppport, + }, +}; +#endif + +#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE) + +static struct msm_ce_hw_support qcedev_ce_hw_suppport = { + .ce_shared = QCE_CE_SHARED, + .shared_ce_resource = QCE_SHARE_CE_RESOURCE, + .hw_key_support = QCE_HW_KEY_SUPPORT, + .sha_hmac = QCE_SHA_HMAC_SUPPORT, + .bus_scale_table = &crypto_hw_bus_scale_pdata, +}; + +static struct platform_device qcedev_device = { + .name = "qce", + .id = 0, + .num_resources = ARRAY_SIZE(qcedev_resources), + .resource = qcedev_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &qcedev_ce_hw_suppport, + }, +}; +#endif + +#define MDM2AP_ERRFATAL 70 +#define AP2MDM_ERRFATAL 95 +#define MDM2AP_STATUS 69 +#define AP2MDM_STATUS 94 +#define AP2MDM_PMIC_RESET_N 80 +#define AP2MDM_KPDPWR_N 81 + +static struct resource mdm_resources[] = { + { + .start = MDM2AP_ERRFATAL, + .end = MDM2AP_ERRFATAL, + .name = "MDM2AP_ERRFATAL", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_ERRFATAL, + .end = AP2MDM_ERRFATAL, + .name = "AP2MDM_ERRFATAL", + .flags = IORESOURCE_IO, + }, + { + .start = MDM2AP_STATUS, + .end = MDM2AP_STATUS, + .name = "MDM2AP_STATUS", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_STATUS, + .end = AP2MDM_STATUS, + .name = "AP2MDM_STATUS", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_PMIC_RESET_N, + .end = AP2MDM_PMIC_RESET_N, + .name = "AP2MDM_PMIC_RESET_N", + .flags = IORESOURCE_IO, + }, + { + .start = AP2MDM_KPDPWR_N, + .end = AP2MDM_KPDPWR_N, + .name = "AP2MDM_KPDPWR_N", + .flags = IORESOURCE_IO, + }, +}; + +static struct mdm_platform_data mdm_platform_data = { + .mdm_version = "2.5", +}; + +static struct platform_device mdm_device = { + .name = "mdm2_modem", + .id = -1, + .num_resources = ARRAY_SIZE(mdm_resources), + .resource = mdm_resources, + .dev = { + .platform_data = &mdm_platform_data, + }, +}; + +static struct platform_device *mdm_devices[] __initdata = { + &mdm_device, +}; + +#define MSM_SHARED_RAM_PHYS 0x80000000 + +static void __init msm8960_map_io(void) +{ + msm_shared_ram_phys = MSM_SHARED_RAM_PHYS; + msm_map_msm8960_io(); + + if (socinfo_init() < 0) + pr_err("socinfo_init() failed!\n"); +#ifdef CONFIG_SEC_DEBUG + sec_getlog_supply_meminfo(0x40000000, 0x80000000, 0x00, 0x00); +#endif + +} + +static void __init msm8960_init_irq(void) +{ + struct msm_mpm_device_data *data = NULL; + +#ifdef CONFIG_MSM_MPM + data = &msm8960_mpm_dev_data; +#endif + + msm_mpm_irq_extn_init(data); + gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, + (void *)MSM_QGIC_CPU_BASE); +} + +static void __init msm8960_init_buses(void) +{ +#ifdef CONFIG_MSM_BUS_SCALING + msm_bus_rpm_set_mt_mask(); + msm_bus_8960_apps_fabric_pdata.rpm_enabled = 1; + msm_bus_8960_sys_fabric_pdata.rpm_enabled = 1; + msm_bus_8960_mm_fabric_pdata.rpm_enabled = 1; + msm_bus_apps_fabric.dev.platform_data = + &msm_bus_8960_apps_fabric_pdata; + msm_bus_sys_fabric.dev.platform_data = &msm_bus_8960_sys_fabric_pdata; + msm_bus_mm_fabric.dev.platform_data = &msm_bus_8960_mm_fabric_pdata; + msm_bus_sys_fpb.dev.platform_data = &msm_bus_8960_sys_fpb_pdata; + msm_bus_cpss_fpb.dev.platform_data = &msm_bus_8960_cpss_fpb_pdata; +#endif +} + +#ifdef CONFIG_S5C73M3 +static struct msm_spi_platform_data msm8960_qup_spi_gsbi11_pdata = { + .max_clock_speed = 48000000, /*15060000,*/ +}; +#endif + +#ifdef CONFIG_USB_MSM_OTG_72K +static struct msm_otg_platform_data msm_otg_pdata; +#else +static bool vbus_is_on; +static void msm_hsusb_vbus_power_max8627(bool on) +{ + int rc; + static struct regulator *mvs_otg_switch; + struct pm_gpio param = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 1, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + }; + + pr_info("%s, attached %d, vbus_is_on %d\n", __func__, on, vbus_is_on); + + if (vbus_is_on == on) + return; + + if (on) { + mvs_otg_switch = regulator_get(&msm8960_device_otg.dev, + "vbus_otg"); + if (IS_ERR(mvs_otg_switch)) { + pr_err("Unable to get mvs_otg_switch\n"); + return; + } + + rc = gpio_request(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + "usb_5v_en"); + if (rc < 0) { + pr_err("failed to request usb_5v_en gpio\n"); + goto put_mvs_otg; + } + + if (regulator_enable(mvs_otg_switch)) { + pr_err("unable to enable mvs_otg_switch\n"); + goto free_usb_5v_en; + } + + rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + ¶m); + if (rc < 0) { + pr_err("failed to configure usb_5v_en gpio\n"); + goto disable_mvs_otg; + } + vbus_is_on = true; + return; + } else { + gpio_set_value_cansleep(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN), + 0); +#ifdef CONFIG_USB_SWITCH_FSA9485 + fsa9485_otg_detach(); +#endif + } + +disable_mvs_otg: + regulator_disable(mvs_otg_switch); +free_usb_5v_en: + gpio_free(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_EN)); +put_mvs_otg: + regulator_put(mvs_otg_switch); + vbus_is_on = false; +} + +#ifdef CONFIG_CHARGER_SMB347 +static void msm_hsusb_vbus_power_smb347s(bool on) +{ + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + int ret = 0; + + pr_info("%s, attached %d, vbus_is_on %d\n", __func__, on, vbus_is_on); + + /* If VBUS is already on (or off), do nothing. */ + if (vbus_is_on == on) + return; + + if (on) + value.intval = POWER_SUPPLY_CAPACITY_OTG_ENABLE; + else + value.intval = POWER_SUPPLY_CAPACITY_OTG_DISABLE; + + if (psy) { + ret = psy->set_property(psy, POWER_SUPPLY_PROP_OTG, &value); + if (ret) { + pr_err("%s: fail to set power_suppy otg property(%d)\n", + __func__, ret); + } +#ifdef CONFIG_USB_SWITCH_FSA9485 + if (!on) + fsa9485_otg_detach(); +#endif + vbus_is_on = on; + } else { + pr_err("%s : psy is null!\n", __func__); + } +} +#endif + +static int msm_hsusb_vbus_power(bool on) +{ + if (system_rev < BOARD_REV09) + msm_hsusb_vbus_power_max8627(on); +#ifdef CONFIG_CHARGER_SMB347 + else + msm_hsusb_vbus_power_smb347s(on); +#endif + return 0; +} + +static int phy_settings[] = { + 0x44, 0x80, + 0x6F, 0x81, + 0x3C, 0x82, + 0x13, 0x83, + -1, +}; + +static int wr_phy_init_seq[] = { + 0x44, 0x80, /* set VBUS valid threshold + and disconnect valid threshold */ + 0x38, 0x81, /* update DC voltage level */ + 0x14, 0x82, /* set preemphasis and rise/fall time */ + 0x13, 0x83, /* set source impedance adjusment */ + -1}; + +static int liquid_v1_phy_init_seq[] = { + 0x44, 0x80,/* set VBUS valid threshold + and disconnect valid threshold */ + 0x3C, 0x81,/* update DC voltage level */ + 0x18, 0x82,/* set preemphasis and rise/fall time */ + 0x23, 0x83,/* set source impedance sdjusment */ + -1}; + +#ifdef CONFIG_MSM_BUS_SCALING +/* Bandwidth requests (zero) if no vote placed */ +static struct msm_bus_vectors usb_init_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +/* Bus bandwidth requests in Bytes/sec */ +static struct msm_bus_vectors usb_max_vectors[] = { + { + .src = MSM_BUS_MASTER_SPS, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 60000000, /* At least 480Mbps on bus. */ + .ib = 960000000, /* MAX bursts rate */ + }, +}; + +static struct msm_bus_paths usb_bus_scale_usecases[] = { + { + ARRAY_SIZE(usb_init_vectors), + usb_init_vectors, + }, + { + ARRAY_SIZE(usb_max_vectors), + usb_max_vectors, + }, +}; + +static struct msm_bus_scale_pdata usb_bus_scale_pdata = { + usb_bus_scale_usecases, + ARRAY_SIZE(usb_bus_scale_usecases), + .name = "usb", +}; +#endif + +static struct msm_otg_platform_data msm_otg_pdata = { + .mode = USB_OTG, + .otg_control = OTG_PMIC_CONTROL, + .phy_type = SNPS_28NM_INTEGRATED_PHY, + .pmic_id_irq = PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE), + .vbus_power = msm_hsusb_vbus_power, + .power_budget = 750, + .phy_init_seq = phy_settings, + .smb347s = true, +#ifdef CONFIG_MSM_BUS_SCALING + .bus_scale_table = &usb_bus_scale_pdata, +#endif +}; + +#ifdef CONFIG_USB_HOST_NOTIFY +static void __init msm_otg_power_init(void) +{ + if (system_rev >= BOARD_REV04) { + msm_otg_pdata.otg_power_gpio = + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_OTG_POWER); + msm_otg_pdata.otg_power_irq = + PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_OTG_POWER); + } + if (system_rev >= BOARD_REV09) + msm_otg_pdata.smb347s = true; + else + msm_otg_pdata.smb347s = false; +} +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC +#define HSIC_HUB_RESET_GPIO 91 +static struct msm_hsic_host_platform_data msm_hsic_pdata = { + .strobe = 150, + .data = 151, +}; +#else +static struct msm_hsic_host_platform_data msm_hsic_pdata; +#endif + +#define PID_MAGIC_ID 0x71432909 +#define SERIAL_NUM_MAGIC_ID 0x61945374 +#define SERIAL_NUMBER_LENGTH 127 +#define DLOAD_USB_BASE_ADD 0x2A03F0C8 + +struct magic_num_struct { + uint32_t pid; + uint32_t serial_num; +}; + +struct dload_struct { + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint16_t reserved4; + uint16_t pid; + char serial_number[SERIAL_NUMBER_LENGTH]; + uint16_t reserved5; + struct magic_num_struct magic_struct; +}; + +static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum) +{ + struct dload_struct __iomem *dload = 0; + + dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload)); + if (!dload) { + pr_err("%s: cannot remap I/O memory region: %08x\n", + __func__, DLOAD_USB_BASE_ADD); + return -ENXIO; + } + + pr_debug("%s: dload:%p pid:%x serial_num:%s\n", + __func__, dload, pid, snum); + /* update pid */ + dload->magic_struct.pid = PID_MAGIC_ID; + dload->pid = pid; + + /* update serial number */ + dload->magic_struct.serial_num = 0; + if (!snum) { + memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH); + goto out; + } + + dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID; + strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH); +out: + iounmap(dload); + return 0; +} + +static struct android_usb_platform_data android_usb_pdata = { + .update_pid_and_serial_num = usb_diag_update_pid_and_serial_num, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; + +static uint8_t spm_wfi_cmd_sequence[] __initdata = { + 0x03, 0x0f, +}; + +static uint8_t spm_retention_cmd_sequence[] __initdata = { + 0x00, 0x05, 0x03, 0x0D, + 0x0B, 0x00, 0x0f, +}; + +static uint8_t spm_power_collapse_without_rpm[] __initdata = { + 0x00, 0x24, 0x54, 0x10, + 0x09, 0x03, 0x01, + 0x10, 0x54, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +static uint8_t spm_power_collapse_with_rpm[] __initdata = { + 0x00, 0x24, 0x54, 0x10, + 0x09, 0x07, 0x01, 0x0B, + 0x10, 0x54, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +/* 8960AB has a different command to assert apc_pdn */ +static uint8_t spm_power_collapse_without_rpm_krait_v3[] __initdata = { + 0x00, 0x24, 0x84, 0x10, + 0x09, 0x03, 0x01, + 0x10, 0x84, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +static uint8_t spm_power_collapse_with_rpm_krait_v3[] __initdata = { + 0x00, 0x24, 0x84, 0x10, + 0x09, 0x07, 0x01, 0x0B, + 0x10, 0x84, 0x30, 0x0C, + 0x24, 0x30, 0x0f, +}; + +static struct msm_spm_seq_entry msm_spm_boot_cpu_seq_list[] __initdata = { + [0] = { + .mode = MSM_SPM_MODE_CLOCK_GATING, + .notify_rpm = false, + .cmd = spm_wfi_cmd_sequence, + }, + [1] = { + .mode = MSM_SPM_MODE_POWER_RETENTION, + .notify_rpm = false, + .cmd = spm_retention_cmd_sequence, + }, + [2] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = false, + .cmd = spm_power_collapse_without_rpm, + }, + [3] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = true, + .cmd = spm_power_collapse_with_rpm, + }, +}; + +static struct msm_spm_seq_entry msm_spm_nonboot_cpu_seq_list[] __initdata = { + [0] = { + .mode = MSM_SPM_MODE_CLOCK_GATING, + .notify_rpm = false, + .cmd = spm_wfi_cmd_sequence, + }, + [1] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = false, + .cmd = spm_power_collapse_without_rpm, + }, + [2] = { + .mode = MSM_SPM_MODE_POWER_COLLAPSE, + .notify_rpm = true, + .cmd = spm_power_collapse_with_rpm, + }, +}; + +static struct msm_spm_platform_data msm_spm_data[] __initdata = { + [0] = { + .reg_base_addr = MSM_SAW0_BASE, + .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F, +#if defined(CONFIG_MSM_AVS_HW) + .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464, + .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000, +#endif + .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0084009C, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A4001C, + .vctl_timeout_us = 50, + .num_modes = ARRAY_SIZE(msm_spm_boot_cpu_seq_list), + .modes = msm_spm_boot_cpu_seq_list, + }, + [1] = { + .reg_base_addr = MSM_SAW1_BASE, + .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F, +#if defined(CONFIG_MSM_AVS_HW) + .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464, + .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000, +#endif + .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C, + .vctl_timeout_us = 50, + .num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list), + .modes = msm_spm_nonboot_cpu_seq_list, + }, +}; + +static uint8_t l2_spm_wfi_cmd_sequence[] __initdata = { + 0x00, 0x20, 0x03, 0x20, + 0x00, 0x0f, +}; + +static uint8_t l2_spm_gdhs_cmd_sequence[] __initdata = { + 0x00, 0x20, 0x34, 0x64, + 0x48, 0x07, 0x48, 0x20, + 0x50, 0x64, 0x04, 0x34, + 0x50, 0x0f, +}; +static uint8_t l2_spm_power_off_cmd_sequence[] __initdata = { + 0x00, 0x10, 0x34, 0x64, + 0x48, 0x07, 0x48, 0x10, + 0x50, 0x64, 0x04, 0x34, + 0x50, 0x0F, +}; + +static struct msm_spm_seq_entry msm_spm_l2_seq_list[] __initdata = { + [0] = { + .mode = MSM_SPM_L2_MODE_RETENTION, + .notify_rpm = false, + .cmd = l2_spm_wfi_cmd_sequence, + }, + [1] = { + .mode = MSM_SPM_L2_MODE_GDHS, + .notify_rpm = true, + .cmd = l2_spm_gdhs_cmd_sequence, + }, + [2] = { + .mode = MSM_SPM_L2_MODE_POWER_COLLAPSE, + .notify_rpm = true, + .cmd = l2_spm_power_off_cmd_sequence, + }, +}; + +static struct msm_spm_platform_data msm_spm_l2_data[] __initdata = { + [0] = { + .reg_base_addr = MSM_SAW_L2_BASE, + .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE, + .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020, + .modes = msm_spm_l2_seq_list, + .num_modes = ARRAY_SIZE(msm_spm_l2_seq_list), + }, +}; + +#define PM_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33) +#define PM_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20) + +static struct msm_xo_voter *xo_handle_d1; + +static int isa1200_power(int on) +{ + int rc = 0; + + gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on); + + rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) : + msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF); + if (rc < 0) { + pr_err("%s: failed to %svote for TCXO D1 buffer%d\n", + __func__, on ? "" : "de-", rc); + goto err_xo_vote; + } + + return 0; + +err_xo_vote: + gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on); + return rc; +} + +static int isa1200_dev_setup(bool enable) +{ + int rc = 0; + + struct pm_gpio hap_gpio_config = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .vin_sel = 2, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + }; + + if (enable == true) { + rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config); + if (rc) { + pr_err("%s: pm8921 gpio %d config failed(%d)\n", + __func__, PM_HAP_EN_GPIO, rc); + return rc; + } + + rc = pm8xxx_gpio_config(PM_HAP_LEN_GPIO, &hap_gpio_config); + if (rc) { + pr_err("%s: pm8921 gpio %d config failed(%d)\n", + __func__, PM_HAP_LEN_GPIO, rc); + return rc; + } + + rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe"); + if (rc) { + pr_err("%s: unable to request gpio %d (%d)\n", + __func__, HAP_SHIFT_LVL_OE_GPIO, rc); + return rc; + } + + rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0); + if (rc) { + pr_err("%s: Unable to set direction\n", __func__); + goto free_gpio; + } + + xo_handle_d1 = msm_xo_get(MSM_XO_TCXO_D1, "isa1200"); + if (IS_ERR(xo_handle_d1)) { + rc = PTR_ERR(xo_handle_d1); + pr_err("%s: failed to get the handle for D1(%d)\n", + __func__, rc); + goto gpio_set_dir; + } + } else { + gpio_free(HAP_SHIFT_LVL_OE_GPIO); + + msm_xo_put(xo_handle_d1); + } + + return 0; + +gpio_set_dir: + gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0); +free_gpio: + gpio_free(HAP_SHIFT_LVL_OE_GPIO); + return rc; +} + +static struct isa1200_regulator isa1200_reg_data[] = { + { + .name = "vcc_i2c", + .min_uV = ISA_I2C_VTG_MIN_UV, + .max_uV = ISA_I2C_VTG_MAX_UV, + .load_uA = ISA_I2C_CURR_UA, + }, +}; + +static struct isa1200_platform_data isa1200_1_pdata = { + .name = "vibrator", + .dev_setup = isa1200_dev_setup, + .power_on = isa1200_power, + .hap_en_gpio = PM_HAP_EN_GPIO, + .hap_len_gpio = PM_HAP_LEN_GPIO, + .max_timeout = 15000, + .mode_ctrl = PWM_GEN_MODE, + .pwm_fd = { + .pwm_div = 256, + }, + .is_erm = false, + .smart_en = true, + .ext_clk_en = true, + .chip_en = 1, + .regulator_info = isa1200_reg_data, + .num_regulators = ARRAY_SIZE(isa1200_reg_data), +}; + +static struct i2c_board_info msm_isa1200_board_info[] __initdata = { + { + I2C_BOARD_INFO("isa1200_1", 0x90>>1), + .platform_data = &isa1200_1_pdata, + }, +}; + +#ifdef CONFIG_NFC_PN544 +static struct i2c_gpio_platform_data pn544_i2c_gpio_data = { + .sda_pin = GPIO_NFC_SDA, + .scl_pin = GPIO_NFC_SCL, + .udelay = 5, +}; + +static struct platform_device pn544_i2c_gpio_device = { + .name = "i2c-gpio", + .id = MSM_NFC_I2C_BUS_ID, + .dev = { + .platform_data = &pn544_i2c_gpio_data, + }, +}; + +static struct pn544_i2c_platform_data pn544_pdata = { + .conf_gpio = pn544_conf_gpio, + .irq_gpio = GPIO_NFC_IRQ, + .ven_gpio = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_NFC_EN), + .firm_gpio = GPIO_NFC_FIRMWARE, +}; + +static struct i2c_board_info pn544_info[] __initdata = { + { + I2C_BOARD_INFO("pn544", 0x2b), + .irq = MSM_GPIO_TO_INT(GPIO_NFC_IRQ), + .platform_data = &pn544_pdata, + }, +}; +#endif /* CONFIG_NFC_PN544 */ + +/* configuration data */ +static const u8 mxt_config_data[] = { + /* T6 Object */ + 0, 0, 0, 0, 0, 0, + /* T38 Object */ + 11, 0, 0, 6, 9, 11, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + /* T7 Object */ + 10, 10, 50, + /* T8 Object */ + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* T9 Object */ + 131, 0, 0, 26, 42, 0, 32, 60, 2, 5, + 0, 5, 5, 34, 10, 10, 10, 10, 85, 5, + 255, 2, 8, 9, 9, 9, 0, 0, 5, 20, + 0, 5, 45, 46, + /* T15 Object */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + /* T18 Object */ + 0, 0, + /* T22 Object */ + 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, + 0, 0, 255, 255, 255, 255, 0, + /* T24 Object */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* T25 Object */ + 3, 0, 188, 52, 52, 33, 0, 0, 0, 0, + 0, 0, 0, 0, + /* T27 Object */ + 0, 0, 0, 0, 0, 0, 0, + /* T28 Object */ + 0, 0, 0, 8, 8, 8, + /* T40 Object */ + 0, 0, 0, 0, 0, + /* T41 Object */ + 0, 0, 0, 0, 0, 0, + /* T43 Object */ + 0, 0, 0, 0, 0, 0, +}; + +static void mxt_init_hw_liquid(void) +{ + int rc; + + rc = gpio_request(GPIO_MXT_TS_IRQ, "mxt_ts_irq_gpio"); + if (rc) { + pr_err("%s: unable to request mxt_ts_irq gpio [%d]\n", + __func__, GPIO_MXT_TS_IRQ); + return; + } + + rc = gpio_direction_input(GPIO_MXT_TS_IRQ); + if (rc) { + pr_err("%s: unable to set_direction for mxt_ts_irq gpio [%d]\n", + __func__, GPIO_MXT_TS_IRQ); + goto err_irq_gpio_req; + } + + rc = gpio_request(GPIO_MXT_TS_LDO_EN, "mxt_ldo_en_gpio"); + if (rc) { + pr_err("%s: unable to request mxt_ldo_en gpio [%d]\n", + __func__, GPIO_MXT_TS_LDO_EN); + goto err_irq_gpio_req; + } + + rc = gpio_direction_output(GPIO_MXT_TS_LDO_EN, 1); + if (rc) { + pr_err("%s: unable to set_direction for mxt_ldo_en gpio [%d]\n", + __func__, GPIO_MXT_TS_LDO_EN); + goto err_ldo_gpio_req; + } +#if !defined(CONFIG_WIRELESS_CHARGING) + rc = gpio_request(GPIO_MXT_TS_RESET, "mxt_reset_gpio"); + if (rc) { + pr_err("%s: unable to request mxt_reset gpio [%d]\n", + __func__, GPIO_MXT_TS_RESET); + goto err_ldo_gpio_set_dir; + } + + rc = gpio_direction_output(GPIO_MXT_TS_RESET, 1); + if (rc) { + pr_err("%s: unable to set_direction for mxt_reset gpio [%d]\n", + __func__, GPIO_MXT_TS_RESET); + goto err_reset_gpio_req; + } +#endif + return; + +err_ldo_gpio_req: + gpio_free(GPIO_MXT_TS_LDO_EN); +err_irq_gpio_req: + gpio_free(GPIO_MXT_TS_IRQ); +} +#if 0 +static struct mxt_platform_data mxt_platform_data = { + .config = mxt_config_data, + .config_length = ARRAY_SIZE(mxt_config_data), + .x_line = 26, + .y_line = 42, + .x_size = 767, + .y_size = 1365, + .blen = 32, + .threshold = 40, + .voltage = 3300000, /* 3.3V */ + .orient = MXT_ROTATED_90, + .irqflags = IRQF_TRIGGER_FALLING, +}; + +static struct i2c_board_info mxt_device_info[] __initdata = { + { + I2C_BOARD_INFO("atmel_mxt_ts", 0x5b), + .platform_data = &mxt_platform_data, + .irq = MSM_GPIO_TO_INT(GPIO_MXT_TS_IRQ), + }, +}; +#endif +#ifndef CONFIG_SLIMBUS_MSM_CTRL +#define TABLA_I2C_SLAVE_ADDR 0x0d +#define TABLA_ANALOG_I2C_SLAVE_ADDR 0x77 +#define TABLA_DIGITAL1_I2C_SLAVE_ADDR 0x66 +#define TABLA_DIGITAL2_I2C_SLAVE_ADDR 0x55 + +static struct i2c_board_info tabla_device_info[] __initdata = { + { + I2C_BOARD_INFO("tabla top level", TABLA_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, + { + I2C_BOARD_INFO("tabla analog", TABLA_ANALOG_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, + { + I2C_BOARD_INFO("tabla digital1", TABLA_DIGITAL1_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, + { + I2C_BOARD_INFO("tabla digital2", TABLA_DIGITAL2_I2C_SLAVE_ADDR), + .platform_data = &tabla_i2c_platform_data, + }, +}; +#endif +static struct i2c_board_info sii_device_info[] __initdata = { + { + I2C_BOARD_INFO("Sil-9244", 0x39), + .flags = I2C_CLIENT_WAKE, + .irq = MSM_GPIO_TO_INT(15), + }, +}; + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = { + .clk_freq = 400000, + .src_clk_rate = 24000000, +}; + +#ifndef CONFIG_SLIMBUS_MSM_CTRL +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi1_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; +#endif + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi7_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; + +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = { + .clk_freq = 100000, + .src_clk_rate = 24000000, +}; +#ifdef CONFIG_VP_A2220 +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi8_pdata = { + .clk_freq = 400000, + .src_clk_rate = 24000000, +}; +#endif +static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = { + .clk_freq = 400000, + .src_clk_rate = 24000000, +}; +#if 0 +static struct msm_rpm_platform_data msm_rpm_data = { + .reg_base_addrs = { + [MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE, + [MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400, + [MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600, + [MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00, + }, + + .irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ, + .irq_err = RPM_APCC_CPU0_GP_LOW_IRQ, + .irq_vmpm = RPM_APCC_CPU0_GP_MEDIUM_IRQ, + .msm_apps_ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008, + .msm_apps_ipc_rpm_val = 4, +}; +#endif + +#if 0 +static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = { + .base_addr = MSM_ACC0_BASE + 0x08, + .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE, + .mask = 1UL << 13, +}; +#endif + +#ifndef CONFIG_S5C73M3 +static struct ks8851_pdata spi_eth_pdata = { + .irq_gpio = KS8851_IRQ_GPIO, + .rst_gpio = KS8851_RST_GPIO, +}; + +static struct spi_board_info spi_board_info[] __initdata = { + { + .modalias = "ks8851", + .irq = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO), + .max_speed_hz = 19200000, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_0, + .platform_data = &spi_eth_pdata + }, + { + .modalias = "dsi_novatek_3d_panel_spi", + .max_speed_hz = 10800000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_0, + }, +}; +#endif +static struct platform_device msm_device_saw_core0 = { + .name = "saw-regulator", + .id = 0, + .dev = { + .platform_data = &msm_saw_regulator_pdata_s5, + }, +}; + +static struct platform_device msm_device_saw_core1 = { + .name = "saw-regulator", + .id = 1, + .dev = { + .platform_data = &msm_saw_regulator_pdata_s6, + }, +}; + +static struct tsens_platform_data msm_tsens_pdata = { + .slope = {910, 910, 910, 910, 910}, + .tsens_factor = 1000, + .hw_type = MSM_8960, + .tsens_num_sensor = 5, +}; + +static struct platform_device msm_tsens_device = { + .name = "tsens8960-tm", + .id = -1, +}; + +static struct msm_thermal_data msm_thermal_pdata = { + .sensor_id = 0, + .poll_ms = 250, + .limit_temp_degC = 60, + .temp_hysteresis_degC = 10, + .freq_step = 2, +}; + +/* Bluetooth */ +#ifdef CONFIG_BT_BCM4334 +static struct platform_device bcm4334_bluetooth_device = { + .name = "bcm4334_bluetooth", + .id = -1, +}; +#endif + +#ifdef CONFIG_MSM_FAKE_BATTERY +static struct platform_device fish_battery_device = { + .name = "fish_battery", +}; +#endif + +static struct platform_device msm8960_device_ext_5v_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = PM8921_MPP_PM_TO_SYS(7), + .dev = { + .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V], + }, +}; +#if 0 +static struct platform_device msm8960_device_ext_l2_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = 91, + .dev = { + .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2], + }, +}; +#endif +static struct platform_device msm8960_device_ext_3p3v_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = PM8921_GPIO_PM_TO_SYS(17), + .dev = { + .platform_data = + &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_3P3V], + }, +}; +#ifdef CONFIG_KEYBOARD_GPIO +static struct gpio_keys_button gpio_keys_button[] = { + { + .code = KEY_VOLUMEUP, + .type = EV_KEY, + .gpio = -1, + .active_low = 1, + .wakeup = 0, + .debounce_interval = 5, /* ms */ + .desc = "Vol Up", + }, + { + .code = KEY_VOLUMEDOWN, + .type = EV_KEY, + .gpio = -1, + .active_low = 1, + .wakeup = 0, + .debounce_interval = 5, /* ms */ + .desc = "Vol Down", + }, + { + .code = KEY_HOMEPAGE, + .type = EV_KEY, + .gpio = -1, + .active_low = 1, + .wakeup = 1, + .debounce_interval = 5, /* ms */ + .desc = "Home", + }, +}; +static struct gpio_keys_platform_data gpio_keys_platform_data = { + .buttons = gpio_keys_button, + .nbuttons = ARRAY_SIZE(gpio_keys_button), + .rep = 0, +}; + +static struct platform_device msm8960_gpio_keys_device = { + .name = "sec_keys", + .id = -1, + .dev = { + .platform_data = &gpio_keys_platform_data, + } +}; +#endif + +static struct platform_device msm8960_device_ext_otg_sw_vreg __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = PM8921_GPIO_PM_TO_SYS(42), + .dev = { + .platform_data = + &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_OTG_SW], + }, +}; + +static struct platform_device msm8960_device_rpm_regulator __devinitdata = { + .name = "rpm-regulator", + .id = -1, + .dev = { + .platform_data = &msm_rpm_regulator_pdata, + }, +}; + +static struct msm_rpm_log_platform_data msm_rpm_log_pdata = { + .phys_addr_base = 0x0010C000, + .reg_offsets = { + [MSM_RPM_LOG_PAGE_INDICES] = 0x00000080, + [MSM_RPM_LOG_PAGE_BUFFER] = 0x000000A0, + }, + .phys_size = SZ_8K, + .log_len = 4096, /* log's buffer length in bytes */ + .log_len_mask = (4096 >> 2) - 1, /* length mask in units of u32 */ +}; + +static struct platform_device msm_rpm_log_device = { + .name = "msm_rpm_log", + .id = -1, + .dev = { + .platform_data = &msm_rpm_log_pdata, + }, +}; + +#ifdef CONFIG_SAMSUNG_JACK +#define PMIC_GPIO_EAR_DET 36 +#define PMIC_GPIO_SHORT_SENDEND 32 +#define PMIC_GPIO_EAR_MICBIAS_EN 3 + +static struct sec_jack_zone jack_zones[] = { + [0] = { + .adc_high = 3, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_3POLE, + }, + [1] = { + .adc_high = 630, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_3POLE, + }, + [2] = { + .adc_high = 1720, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_4POLE, + }, + [3] = { + .adc_high = 9999, + .delay_ms = 10, + .check_count = 10, + .jack_type = SEC_HEADSET_4POLE, + }, +}; + +/* To support 3-buttons earjack */ +static struct sec_jack_buttons_zone jack_buttons_zones[] = { + { + .code = KEY_MEDIA, + .adc_low = 0, + .adc_high = 93, + }, + { + .code = KEY_VOLUMEUP, + .adc_low = 94, + .adc_high = 217, + }, + { + .code = KEY_VOLUMEDOWN, + .adc_low = 218, + .adc_high = 450, + }, +}; + +static int get_sec_det_jack_state(void) +{ + return (gpio_get_value_cansleep( + PM8921_GPIO_PM_TO_SYS( + PMIC_GPIO_EAR_DET))) ^ 1; +} + +static int get_sec_send_key_state(void) +{ + struct pm_gpio ear_micbiase = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .vin_sel = PM_GPIO_VIN_S4, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, + }; + + if (get_sec_det_jack_state()) { + pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + &ear_micbiase); + gpio_set_value_cansleep( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + 1); + } + return (gpio_get_value_cansleep( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_SHORT_SENDEND))) ^ 1; + + return 0; +} + +static void set_sec_micbias_state(bool state) +{ + pr_info("sec_jack: ear micbias %s\n", state ? "on" : "off"); + gpio_set_value_cansleep( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + state); +} + +static int sec_jack_get_adc_value(void) +{ + int rc = 0; + int retVal = 0; + struct pm8xxx_adc_chan_result result; + + rc = pm8xxx_adc_mpp_config_read( + PM8XXX_AMUX_MPP_3, + ADC_MPP_1_AMUX6_SCALE_DEFAULT, + &result); + if (rc) { + pr_err("%s : error reading mpp %d, rc = %d\n", + __func__, PM8XXX_AMUX_MPP_3, rc); + return rc; + } + retVal = ((int)result.physical)/1000; + return retVal; +} + +static struct sec_jack_platform_data sec_jack_data = { + .get_det_jack_state = get_sec_det_jack_state, + .get_send_key_state = get_sec_send_key_state, + .set_micbias_state = set_sec_micbias_state, + .get_adc_value = sec_jack_get_adc_value, + .zones = jack_zones, + .num_zones = ARRAY_SIZE(jack_zones), + .buttons_zones = jack_buttons_zones, + .num_buttons_zones = ARRAY_SIZE(jack_buttons_zones), + .det_int = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, + PMIC_GPIO_EAR_DET), + .send_int = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, + PMIC_GPIO_SHORT_SENDEND), +}; + +static struct platform_device sec_device_jack = { + .name = "sec_jack", + .id = -1, + .dev = { + .platform_data = &sec_jack_data, + }, +}; +#endif + +static struct platform_device *common_devices[] __initdata = { + &msm8960_device_dmov, + &msm_device_smd, + &msm8960_device_uart_gsbi5, + &msm_device_uart_dm6, + &msm_device_saw_core0, + &msm_device_saw_core1, + &msm8960_device_ext_5v_vreg, + &msm8960_device_ssbi_pmic, + &msm8960_device_ext_otg_sw_vreg, +#ifndef CONFIG_SLIMBUS_MSM_CTRL + &msm8960_device_qup_i2c_gsbi1, +#endif +#ifdef CONFIG_S5C73M3 + &msm8960_device_qup_spi_gsbi11, +#endif + &msm8960_device_qup_i2c_gsbi3, + &msm8960_device_qup_i2c_gsbi4, + &msm8960_device_qup_i2c_gsbi7, + &msm8960_device_qup_i2c_gsbi10, +#ifdef CONFIG_VP_A2220 + &msm8960_device_qup_i2c_gsbi8, +#endif +#ifndef CONFIG_MSM_DSPS + &msm8960_device_qup_i2c_gsbi12, +#endif + &msm_slim_ctrl, + &msm_device_wcnss_wlan, +#if defined(CONFIG_QSEECOM) + &qseecom_device, +#endif +#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \ + defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) + &qcrypto_device, +#endif + +#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \ + defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE) + &qcedev_device, +#endif +#ifdef CONFIG_MSM_ROTATOR + &msm_rotator_device, +#endif + &msm_device_sps, +#ifdef CONFIG_MSM_FAKE_BATTERY + &fish_battery_device, +#endif + &fmem_device, +#ifdef CONFIG_ANDROID_PMEM +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + &android_pmem_device, + &android_pmem_adsp_device, + &android_pmem_audio_device, +#endif +#endif +#ifdef CONFIG_KEYBOARD_GPIO + &msm8960_gpio_keys_device, +#endif + &msm_device_vidc, + &msm_device_bam_dmux, + &msm_fm_platform_init, + +#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) +#ifdef CONFIG_MSM_USE_TSIF1 + &msm_device_tsif[1], +#else + &msm_device_tsif[0], +#endif +#endif + +#ifdef CONFIG_HW_RANDOM_MSM + &msm_device_rng, +#endif + &msm8960_rpm_device, +#ifdef CONFIG_ION_MSM + &ion_dev, +#endif + &msm_rpm_log_device, + &msm8960_rpm_stat_device, + &msm_device_tz_log, +#if 0 +#ifdef CONFIG_MSM_QDSS + &msm_etb_device, + &msm_tpiu_device, + &msm_funnel_device, + &msm_etm_device, +#endif +#endif + &msm_device_dspcrashd_8960, + &msm8960_device_watchdog, +#ifdef CONFIG_MSM_RTB + &msm_rtb_device, +#endif + &msm8960_device_cache_erp, +#ifdef CONFIG_MSM_CACHE_DUMP + &msm_cache_dump_device, +#endif + &msm8960_iommu_domain_device, + &msm_tsens_device, +}; + +static struct platform_device *m2_vzw_devices[] __initdata = { + &msm_8960_q6_lpass, + &msm_8960_q6_mss_sw, + &msm_8960_q6_mss_fw, + &msm_8960_riva, + &msm_pil_tzapps, + &msm_pil_vidc, + &msm8960_device_otg, + &msm8960_device_gadget_peripheral, + &msm_device_hsusb_host, + &android_usb_device, + &msm_pcm, + &msm_multi_ch_pcm, + &msm_lowlatency_pcm, + &msm_pcm_routing, +#ifdef CONFIG_SLIMBUS_MSM_CTRL + &msm_cpudai0, + &msm_cpudai1, +#else + &msm_i2s_cpudai0, + &msm_i2s_cpudai1, +#endif + &msm_cpudai_hdmi_rx, + &msm_cpudai_bt_rx, + &msm_cpudai_bt_tx, + &msm_cpudai_fm_rx, + &msm_cpudai_fm_tx, + &msm_cpudai_auxpcm_rx, + &msm_cpudai_auxpcm_tx, + &msm_cpu_fe, + &msm_stub_codec, +#ifdef CONFIG_MSM_GEMINI + &msm8960_gemini_device, +#endif + &msm_voice, + &msm_voip, + &msm_lpa_pcm, + &msm_cpudai_afe_01_rx, + &msm_cpudai_afe_01_tx, + &msm_cpudai_afe_02_rx, + &msm_cpudai_afe_02_tx, + &msm_pcm_afe, + &msm_compr_dsp, + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + &mhl_i2c_gpio_device, +#endif +#ifdef CONFIG_USB_SWITCH_FSA9485 + &fsa_i2c_gpio_device, +#endif +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 + &touchkey_i2c_gpio_device, +#endif +#ifdef CONFIG_BATTERY_MAX17040 + &fuelgauge_i2c_gpio_device, +#endif +#ifdef CONFIG_BATTERY_SEC + &sec_device_battery, +#endif +#ifdef CONFIG_SAMSUNG_JACK + &sec_device_jack, +#endif + &msm_cpudai_incall_music_rx, + &msm_cpudai_incall_record_rx, + &msm_cpudai_incall_record_tx, + &msm_pcm_hostless, + &msm_bus_apps_fabric, + &msm_bus_sys_fabric, + &msm_bus_mm_fabric, + &msm_bus_sys_fpb, + &msm_bus_cpss_fpb, + &pn544_i2c_gpio_device, +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + &opt_i2c_gpio_device, +#if 0 +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) + &opt_gp2a, +#endif +#endif +#endif +#ifdef CONFIG_BT_BCM4334 + &bcm4334_bluetooth_device, +#endif +#ifdef CONFIG_VIBETONZ + &vibetonz_device, +#endif /* CONFIG_VIBETONZ */ +}; + +static void __init msm8960_i2c_init(void) +{ + msm8960_device_qup_i2c_gsbi4.dev.platform_data = + &msm8960_i2c_qup_gsbi4_pdata; + +#ifndef CONFIG_SLIMBUS_MSM_CTRL + msm8960_device_qup_i2c_gsbi1.dev.platform_data = + &msm8960_i2c_qup_gsbi1_pdata; +#endif + + msm8960_device_qup_i2c_gsbi7.dev.platform_data = + &msm8960_i2c_qup_gsbi7_pdata; + + msm8960_device_qup_i2c_gsbi3.dev.platform_data = + &msm8960_i2c_qup_gsbi3_pdata; + + msm8960_device_qup_i2c_gsbi10.dev.platform_data = + &msm8960_i2c_qup_gsbi10_pdata; +#ifdef CONFIG_VP_A2220 + msm8960_device_qup_i2c_gsbi8.dev.platform_data = + &msm8960_i2c_qup_gsbi8_pdata; +#endif + msm8960_device_qup_i2c_gsbi12.dev.platform_data = + &msm8960_i2c_qup_gsbi12_pdata; +} + +static void __init msm8960_gfx_init(void) +{ + struct kgsl_device_platform_data *kgsl_3d0_pdata = + msm_kgsl_3d0.dev.platform_data; + uint32_t soc_platform_version = socinfo_get_version(); + + kgsl_3d0_pdata->iommu_count = 1; + + if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) { + kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000; + kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000; + } + if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3) { + /* 8960v3 GPU registers returns 5 for patch release + * but it should be 6, so dummy up the chipid here + * based the platform type + */ + kgsl_3d0_pdata->chipid = ADRENO_CHIPID(2, 2, 0, 6); + } + + /* Register the 3D core */ + platform_device_register(&msm_kgsl_3d0); + + /* Register the 2D cores if we are not 8960PRO */ + if (!cpu_is_msm8960ab()) { + platform_device_register(&msm_kgsl_2d0); + platform_device_register(&msm_kgsl_2d1); + } +} +#if 0 +static struct msm_cpuidle_state msm_cstates[] __initdata = { + {0, 0, "C0", "WFI", + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT}, + + {0, 1, "C2", "POWER_COLLAPSE", + MSM_PM_SLEEP_MODE_POWER_COLLAPSE}, + + {1, 0, "C0", "WFI", + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT}, +}; + +static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = { + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + }, + + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + }, + + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 0, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + }, + + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 0, + .idle_enabled = 1, + .suspend_enabled = 0, + }, +}; +#endif +static struct msm_rpmrs_level msm_rpmrs_levels[] = { + { + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT, + MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE), + true, + 100, 650, 801, 200, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE), + false, + 8500, 51, 1122000, 8500, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE), + false, + 9000, 51, 1130300, 9000, + }, + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH), + false, + 10000, 51, 1130300, 10000, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE), + false, + 12000, 14, 2205900, 12000, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE), + false, + 18000, 12, 2364250, 18000, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH), + false, + 23500, 10, 2667000, 23500, + }, + + { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW), + false, + 29700, 5, 2867000, 30000, + }, +}; + +static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = { + .levels = &msm_rpmrs_levels[0], + .num_levels = ARRAY_SIZE(msm_rpmrs_levels), + .vdd_mem_levels = { + [MSM_RPMRS_VDD_MEM_RET_LOW] = 750000, + [MSM_RPMRS_VDD_MEM_RET_HIGH] = 750000, + [MSM_RPMRS_VDD_MEM_ACTIVE] = 1050000, + [MSM_RPMRS_VDD_MEM_MAX] = 1150000, + }, + .vdd_dig_levels = { + [MSM_RPMRS_VDD_DIG_RET_LOW] = 500000, + [MSM_RPMRS_VDD_DIG_RET_HIGH] = 750000, + [MSM_RPMRS_VDD_DIG_ACTIVE] = 950000, + [MSM_RPMRS_VDD_DIG_MAX] = 1150000, + }, + .vdd_mask = 0x7FFFFF, + .rpmrs_target_id = { + [MSM_RPMRS_ID_PXO_CLK] = MSM_RPM_ID_PXO_CLK, + [MSM_RPMRS_ID_L2_CACHE_CTL] = MSM_RPM_ID_LAST, + [MSM_RPMRS_ID_VDD_DIG_0] = MSM_RPM_ID_PM8921_S3_0, + [MSM_RPMRS_ID_VDD_DIG_1] = MSM_RPM_ID_PM8921_S3_1, + [MSM_RPMRS_ID_VDD_MEM_0] = MSM_RPM_ID_PM8921_L24_0, + [MSM_RPMRS_ID_VDD_MEM_1] = MSM_RPM_ID_PM8921_L24_1, + [MSM_RPMRS_ID_RPM_CTL] = MSM_RPM_ID_RPM_CTL, + }, +}; + +static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = { + .mode = MSM_PM_BOOT_CONFIG_TZ, +}; + +#ifdef CONFIG_I2C +#define I2C_SURF 1 +#define I2C_FFA (1 << 1) +#define I2C_RUMI (1 << 2) +#define I2C_SIM (1 << 3) +#define I2C_FLUID (1 << 4) +#define I2C_LIQUID (1 << 5) + +struct i2c_registry { + u8 machs; + int bus; + struct i2c_board_info *info; + int len; +}; + +#ifdef CONFIG_MSM_CAMERA +static struct i2c_board_info msm_camera_boardinfo[] __initdata = { +#ifdef CONFIG_S5C73M3 + { + I2C_BOARD_INFO("s5c73m3", 0x78>>1), + }, +#endif +#ifdef CONFIG_S5K6A3YX + { + I2C_BOARD_INFO("s5k6a3yx", 0x20), + }, +#endif +#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A + { + I2C_BOARD_INFO("sc628a", 0x6E), + }, +#endif +}; +#endif + +/*add for D2_ATT CAM_ISP_CORE power setting by MAX8952*/ +#ifdef CONFIG_REGULATOR_MAX8952 +static int max8952_is_used(void) +{ + if (system_rev >= 0x8) + return 1; + else + return 0; +} + +static struct regulator_consumer_supply max8952_consumer = + REGULATOR_SUPPLY("cam_isp_core", NULL); + +static struct max8952_platform_data m2_att_max8952_pdata = { + .gpio_vid0 = -1, /* NOT controlled by GPIO, HW default high*/ + .gpio_vid1 = -1, /* NOT controlled by GPIO, HW default high*/ + .gpio_en = CAM_CORE_EN, /* Controlled by GPIO, High enable */ + .default_mode = 3, /* vid0 = 1, vid1 = 1 */ + .dvs_mode = { 33, 33, 33, 43 }, /* 1.1V, 1.1V, 1.1V, 1.2V*/ + .sync_freq = 0, /* default: fastest */ + .ramp_speed = 0, /* default: fastest */ + .reg_data = { + .constraints = { + .name = "CAM_ISP_CORE", + .min_uV = 770000, + .max_uV = 1400000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &max8952_consumer, + }, +}; +#endif /*CONFIG_REGULATOR_MAX8952*/ + +#ifdef CONFIG_SAMSUNG_CMC624 +static struct i2c_board_info cmc624_i2c_borad_info[] = { + { + I2C_BOARD_INFO("cmc624", 0x38), + }, +}; +#endif + +#ifdef CONFIG_REGULATOR_MAX8952 +static struct i2c_board_info cmc624_max8952_i2c_borad_info[] = { + { + I2C_BOARD_INFO("cmc624", 0x38), + }, + + { + I2C_BOARD_INFO("max8952", 0xC0>>1), + .platform_data = &m2_att_max8952_pdata, + }, +}; +#endif /*CONFIG_REGULATOR_MAX8952*/ + +/* Sensors DSPS platform data */ +#ifdef CONFIG_MSM_DSPS +#define DSPS_PIL_GENERIC_NAME "dsps" +#endif /* CONFIG_MSM_DSPS */ + +static void __init msm8960_init_dsps(void) +{ +#ifdef CONFIG_MSM_DSPS + struct msm_dsps_platform_data *pdata = + msm_dsps_device.dev.platform_data; + pdata->pil_name = DSPS_PIL_GENERIC_NAME; + pdata->gpios = NULL; + pdata->gpios_num = 0; + + platform_device_register(&msm_dsps_device); +#endif /* CONFIG_MSM_DSPS */ +} + +static int hsic_peripheral_status = 1; +static DEFINE_MUTEX(hsic_status_lock); + +void peripheral_connect() +{ + mutex_lock(&hsic_status_lock); + if (hsic_peripheral_status) + goto out; + platform_device_add(&msm_device_hsic_host); + hsic_peripheral_status = 1; +out: + mutex_unlock(&hsic_status_lock); +} +EXPORT_SYMBOL(peripheral_connect); + +void peripheral_disconnect() +{ + mutex_lock(&hsic_status_lock); + if (!hsic_peripheral_status) + goto out; + platform_device_del(&msm_device_hsic_host); + hsic_peripheral_status = 0; +out: + mutex_unlock(&hsic_status_lock); +} +EXPORT_SYMBOL(peripheral_disconnect); + +static void __init msm8960_init_hsic(void) +{ +#ifdef CONFIG_USB_EHCI_MSM_HSIC + uint32_t version = socinfo_get_version(); + + if (SOCINFO_VERSION_MAJOR(version) == 1) + return; + + if (PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid()) + platform_device_register(&msm_device_hsic_host); +#endif +} + +#ifdef CONFIG_ISL9519_CHARGER +static struct isl_platform_data isl_data __initdata = { + .valid_n_gpio = 0, /* Not required when notify-by-pmic */ + .chg_detection_config = NULL, /* Not required when notify-by-pmic */ + .max_system_voltage = 4200, + .min_system_voltage = 3200, + .chgcurrent = 1000, /* 1900, */ + .term_current = 400, /* Need fine tuning */ + .input_current = 2048, +}; + +static struct i2c_board_info isl_charger_i2c_info[] __initdata = { + { + I2C_BOARD_INFO("isl9519q", 0x9), + .irq = 0, /* Not required when notify-by-pmic */ + .platform_data = &isl_data, + }, +}; +#endif /* CONFIG_ISL9519_CHARGER */ + +static struct i2c_registry msm8960_i2c_devices[] __initdata = { +#ifdef CONFIG_MSM_CAMERA + { + I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI, + MSM_8960_GSBI4_QUP_I2C_BUS_ID, + msm_camera_boardinfo, + ARRAY_SIZE(msm_camera_boardinfo), + }, +#endif +#ifdef CONFIG_ISL9519_CHARGER + { + I2C_LIQUID, + MSM_8960_GSBI10_QUP_I2C_BUS_ID, + isl_charger_i2c_info, + ARRAY_SIZE(isl_charger_i2c_info), + }, +#endif /* CONFIG_ISL9519_CHARGER */ +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_MHL_I2C_BUS_ID, + mhl_i2c_board_info, + ARRAY_SIZE(mhl_i2c_board_info), + }, +#endif +#ifdef CONFIG_USB_SWITCH_FSA9485 + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_FSA9485_I2C_BUS_ID, + micro_usb_i2c_devices_info, + ARRAY_SIZE(micro_usb_i2c_devices_info), + }, +#endif +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +{ + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_TOUCHKEY_I2C_BUS_ID, + touchkey_i2c_devices_info, + ARRAY_SIZE(touchkey_i2c_devices_info), + }, +#endif +#ifdef CONFIG_VP_A2220 + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_8960_GSBI8_QUP_I2C_BUS_ID, + a2220_device, + ARRAY_SIZE(a2220_device), + }, +#endif +#ifdef CONFIG_NFC_PN544 + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_NFC_I2C_BUS_ID, + pn544_info, + ARRAY_SIZE(pn544_info), + }, +#endif /* CONFIG_NFC_PN544 */ +#if 0 + { + I2C_LIQUID, + MSM_8960_GSBI3_QUP_I2C_BUS_ID, + mxt_device_info, + ARRAY_SIZE(mxt_device_info), + }, +#endif +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_SNS_I2C_BUS_ID, + sns_i2c_borad_info, + ARRAY_SIZE(sns_i2c_borad_info), + }, +#endif +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_OPT_I2C_BUS_ID, + opt_i2c_borad_info, + ARRAY_SIZE(opt_i2c_borad_info), + }, +#endif +#ifdef CONFIG_SAMSUNG_CMC624 + { + I2C_SURF | I2C_FFA | I2C_FLUID , + MSM_CMC624_I2C_BUS_ID, + cmc624_i2c_borad_info, + ARRAY_SIZE(cmc624_i2c_borad_info), + }, +#endif + { + I2C_LIQUID, + MSM_8960_GSBI10_QUP_I2C_BUS_ID, + sii_device_info, + ARRAY_SIZE(sii_device_info), + }, + { + I2C_LIQUID, + MSM_8960_GSBI10_QUP_I2C_BUS_ID, + msm_isa1200_board_info, + ARRAY_SIZE(msm_isa1200_board_info), + }, +#ifndef CONFIG_SLIMBUS_MSM_CTRL + { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_8960_GSBI1_QUP_I2C_BUS_ID, + tabla_device_info, + ARRAY_SIZE(tabla_device_info), + }, +#endif +}; +#endif /* CONFIG_I2C */ + +static void __init register_i2c_devices(void) +{ +#ifdef CONFIG_I2C + u8 mach_mask = 0; + int i; + +#ifdef CONFIG_REGULATOR_MAX8952 +struct i2c_registry cmc624_max8952_i2c_devices = { + I2C_SURF | I2C_FFA | I2C_FLUID , + MSM_CMC624_I2C_BUS_ID, + cmc624_max8952_i2c_borad_info, + ARRAY_SIZE(cmc624_max8952_i2c_borad_info), + }; +#endif /*CONFIG_REGULATOR_MAX8952*/ + +#ifdef CONFIG_BATTERY_MAX17040 + struct i2c_registry msm8960_fg_i2c_devices = { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_FUELGAUGE_I2C_BUS_ID, + fg_i2c_board_info, + ARRAY_SIZE(fg_i2c_board_info), + }; +#endif /* CONFIG_BATTERY_MAX17040 */ +#if defined(CONFIG_CHARGER_SMB347) + struct i2c_registry msm8960_fg_smb_i2c_devices = { + I2C_SURF | I2C_FFA | I2C_FLUID, + MSM_FUELGAUGE_I2C_BUS_ID, + fg_smb_i2c_board_info, + ARRAY_SIZE(fg_smb_i2c_board_info), + }; +#endif + + /* Build the matching 'supported_machs' bitmask */ + if (machine_is_msm8960_cdp()) + mach_mask = I2C_SURF; + else if (machine_is_msm8960_rumi3()) + mach_mask = I2C_RUMI; + else if (machine_is_msm8960_sim()) + mach_mask = I2C_SIM; + else if (machine_is_msm8960_fluid()) + mach_mask = I2C_FLUID; + else if (machine_is_msm8960_liquid()) + mach_mask = I2C_LIQUID; + else if (machine_is_msm8960_mtp()) + mach_mask = I2C_FFA; + else if (machine_is_M2_VZW()) + mach_mask = I2C_FFA; + else + pr_err("unmatched machine ID in register_i2c_devices\n"); + + /* Run the array and install devices as appropriate */ + for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) { + if (msm8960_i2c_devices[i].machs & mach_mask) + i2c_register_board_info(msm8960_i2c_devices[i].bus, + msm8960_i2c_devices[i].info, + msm8960_i2c_devices[i].len); + } + +#ifdef CONFIG_SAMSUNG_CMC624 +#ifdef CONFIG_REGULATOR_MAX8952 + if (max8952_is_used()) { + i2c_register_board_info(cmc624_max8952_i2c_devices.bus, + cmc624_max8952_i2c_devices.info, + cmc624_max8952_i2c_devices.len); + } +#endif /*CONFIG_REGULATOR_MAX8952*/ +#endif /*CONFIG_SAMSUNG_CMC624*/ + +#if defined(CONFIG_BATTERY_MAX17040) + if (!is_smb347_using()) { + i2c_register_board_info(msm8960_fg_i2c_devices.bus, + msm8960_fg_i2c_devices.info, + msm8960_fg_i2c_devices.len); + } +#if defined(CONFIG_CHARGER_SMB347) + else { + i2c_register_board_info(msm8960_fg_smb_i2c_devices.bus, + msm8960_fg_smb_i2c_devices.info, + msm8960_fg_smb_i2c_devices.len); + } +#endif /* CONFIG_CHARGER_SMB347 */ +#endif /* CONFIG_BATTERY_MAX17040 */ +#endif +} + +static void __init gpio_rev_init(void) +{ + /*KEY REV*/ + gpio_keys_button[0].gpio = gpio_rev(VOLUME_UP); + gpio_keys_button[1].gpio = gpio_rev(VOLUME_DOWN); + gpio_keys_platform_data.nbuttons = 2; + if (system_rev >= BOARD_REV13) { + gpio_tlmm_config(GPIO_CFG(GPIO_HOME_KEY, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_UP, GPIO_CFG_2MA), 1); + gpio_keys_button[2].gpio = GPIO_HOME_KEY; + gpio_keys_platform_data.nbuttons = ARRAY_SIZE(gpio_keys_button); + } +#if defined(CONFIG_SENSORS_CM36651) + if (system_rev < BOARD_REV13) + cm36651_pdata.irq = gpio_rev(ALS_INT); +#endif +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + opt_i2c_gpio_data.sda_pin = gpio_rev(ALS_SDA); + opt_i2c_gpio_data.scl_pin = gpio_rev(ALS_SCL); +#if defined(CONFIG_OPTICAL_GP2A) + if (system_rev < BOARD_REV13) { + opt_gp2a_data.irq = MSM_GPIO_TO_INT(gpio_rev(ALS_INT)); + opt_gp2a_data.ps_status = gpio_rev(ALS_INT); + } +#elif defined(CONFIG_OPTICAL_GP2AP020A00F) + if (system_rev < BOARD_REV13) + opt_gp2a_data.p_out = gpio_rev(ALS_INT); +#endif +#endif + a2220_i2c_gpio_data.sda_pin = gpio_rev(A2220_SDA); + a2220_i2c_gpio_data.scl_pin = gpio_rev(A2220_SCL); + a2220_data.gpio_wakeup = gpio_rev(A2220_WAKEUP); + msm8960_a2220_configs[0].gpio = gpio_rev(A2220_SDA); + msm8960_a2220_configs[1].gpio = gpio_rev(A2220_SCL); +#ifdef CONFIG_VIBETONZ + if (system_rev >= BOARD_REV09) { + msm_8960_vibrator_pdata.vib_en_gpio = PMIC_GPIO_VIB_ON; + msm_8960_vibrator_pdata.is_pmic_vib_en = 1; + } + if (system_rev >= BOARD_REV13) { + msm_8960_vibrator_pdata.haptic_pwr_en_gpio = \ + PMIC_GPIO_HAPTIC_PWR_EN; + msm_8960_vibrator_pdata.is_pmic_haptic_pwr_en = 1; + } +#endif /* CONFIG_VIBETONZ */ +} + +#ifdef CONFIG_SAMSUNG_JACK +static struct pm_gpio ear_det = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, +}; + +static struct pm_gpio short_sendend = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, +}; + +static struct pm_gpio ear_micbiase = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .out_strength = PM_GPIO_STRENGTH_HIGH, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + .vin_sel = PM_GPIO_VIN_S4, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 0, +}; + +static int secjack_gpio_init(void) +{ + int rc; + + rc = pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_DET), + &ear_det); + if (rc) { + pr_err("%s PMIC_GPIO_EAR_DET config failed\n", __func__); + return rc; + } + rc = pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_SHORT_SENDEND), + &short_sendend); + if (rc) { + pr_err("%s PMIC_GPIO_SHORT_SENDEND config failed\n", __func__); + return rc; + } + rc = gpio_request( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + "EAR_MICBIAS"); + if (rc) { + pr_err("failed to request ear micbias gpio\n"); + gpio_free(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN)); + return rc; + } + rc = pm8xxx_gpio_config( + PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_EAR_MICBIAS_EN), + &ear_micbiase); + if (rc) { + pr_err("%s PMIC_GPIO_EAR_MICBIAS_EN config failed\n", __func__); + return rc; + } else { + gpio_direction_output(PM8921_GPIO_PM_TO_SYS( + PMIC_GPIO_EAR_MICBIAS_EN), 0); + } + + return rc; +} +#endif + +void main_mic_bias_init(void) +{ + int ret; + ret = gpio_request(GPIO_MAIN_MIC_BIAS, "LDO_BIAS"); + if (ret) { + pr_err("%s: ldo bias gpio %d request" + "failed\n", __func__, GPIO_MAIN_MIC_BIAS); + return; + } + gpio_direction_output(GPIO_MAIN_MIC_BIAS, 0); +} + +static int configure_codec_lineout_gpio(void) +{ + int ret; + struct pm_gpio param = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 1, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + }; + + ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS( + gpio_rev(LINEOUT_EN)), ¶m); + if (ret) { + pr_err("%s: Failed to configure Lineout EN" + " gpio %d\n", __func__, + PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN))); + return ret; + } else + gpio_direction_output(PM8921_GPIO_PM_TO_SYS( + gpio_rev(LINEOUT_EN)), 1); + return 0; +} + +static int tabla_codec_ldo_en_init(void) +{ + int ret; + + ret = gpio_request(PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN)), + "LINEOUT_EN"); + if (ret) { + pr_err("%s:External LDO gpio %d request" + "failed\n", __func__, + PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN))); + return ret; + } + gpio_direction_output(PM8921_GPIO_PM_TO_SYS(gpio_rev(LINEOUT_EN)), 0); + return 0; +} + +static void __init msm8960ab_update_krait_spm(void) +{ + int i; + + /* Reset the AVS registers until we have support for AVS */ + for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) { + struct msm_spm_platform_data *pdata = &msm_spm_data[i]; + pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0; + pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0; + } + + /* Update the SPM sequences for SPC and PC */ + for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) { + int j; + struct msm_spm_platform_data *pdata = &msm_spm_data[i]; + for (j = 0; j < pdata->num_modes; j++) { + if (pdata->modes[j].cmd == + spm_power_collapse_without_rpm) + pdata->modes[j].cmd = + spm_power_collapse_without_rpm_krait_v3; + else if (pdata->modes[j].cmd == + spm_power_collapse_with_rpm) + pdata->modes[j].cmd = + spm_power_collapse_with_rpm_krait_v3; + } + } +} + +static void __init msm8960_tsens_init(void) +{ + if (cpu_is_msm8960()) + if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) + return; + + msm_tsens_early_init(&msm_tsens_pdata); +} + +static void __init samsung_m2_vzw_init(void) +{ +#ifdef CONFIG_ANDROID_RAM_CONSOLE + platform_device_register(&ram_console_device); +#endif +#ifdef CONFIG_SEC_DEBUG + sec_debug_init(); +#endif + + if (meminfo_init(SYS_MEMORY, SZ_256M) < 0) + pr_err("meminfo_init() failed!\n"); + + platform_device_register(&msm_gpio_device); + msm8960_tsens_init(); + msm_thermal_init(&msm_thermal_pdata); + BUG_ON(msm_rpm_init(&msm8960_rpm_data)); + BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data)); + + gpio_rev_init(); + regulator_suppress_info_printing(); + if (msm_xo_init()) + pr_err("Failed to initialize XO votes\n"); + platform_device_register(&msm8960_device_rpm_regulator); + msm_clock_init(&msm8960_clock_init_data); + if (machine_is_msm8960_liquid()) + msm_otg_pdata.mhl_enable = true; + msm8960_device_otg.dev.platform_data = &msm_otg_pdata; + if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() || + machine_is_msm8960_cdp()) { + msm_otg_pdata.phy_init_seq = wr_phy_init_seq; + } else if (machine_is_msm8960_liquid()) { + msm_otg_pdata.phy_init_seq = + liquid_v1_phy_init_seq; + } + android_usb_pdata.swfi_latency = + msm_rpmrs_levels[0].latency_us; + +#ifdef CONFIG_USB_HOST_NOTIFY + msm_otg_power_init(); +#endif +#ifdef CONFIG_VP_A2220 + if (system_rev > BOARD_REV02) + msm_gpiomux_install(msm8960_a2220_configs, + ARRAY_SIZE(msm8960_a2220_configs)); +#endif + +#ifdef CONFIG_USB_EHCI_MSM_HSIC + if (machine_is_msm8960_liquid()) { + if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2) + msm_hsic_pdata.hub_reset = HSIC_HUB_RESET_GPIO; + } +#endif + msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata; + msm8960_init_gpiomux(); + +#ifndef CONFIG_S5C73M3 + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); +#endif +#ifdef CONFIG_S5C73M3 + msm8960_device_qup_spi_gsbi11.dev.platform_data = + &msm8960_qup_spi_gsbi11_pdata; +#endif + +#ifndef CONFIG_S5C73M3 + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); +#endif +#ifdef CONFIG_BATTERY_SEC + check_highblock_temp(); +#endif /*CONFIG_BATTERY_SEC*/ + msm8960_init_pmic(); + msm8960_i2c_init(); + msm8960_gfx_init(); + if (cpu_is_msm8960ab()) + msm8960ab_update_krait_spm(); + msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data)); + msm_spm_l2_init(msm_spm_l2_data); + msm8960_init_buses(); + if (cpu_is_msm8960ab()) { + platform_add_devices(msm8960ab_footswitch, + msm8960ab_num_footswitch); + } else { + platform_add_devices(msm8960_footswitch, + msm8960_num_footswitch); + } + if (machine_is_msm8960_liquid()) + platform_device_register(&msm8960_device_ext_3p3v_vreg); + if (cpu_is_msm8960ab()) + platform_device_register(&msm8960ab_device_acpuclk); + else + platform_device_register(&msm8960_device_acpuclk); + platform_add_devices(common_devices, ARRAY_SIZE(common_devices)); + msm8960_pm8921_gpio_mpp_init(); + platform_add_devices(m2_vzw_devices, ARRAY_SIZE(m2_vzw_devices)); + msm8960_init_hsic(); + msm8960_init_cam(); + msm8960_init_mmc(); + if (machine_is_msm8960_liquid()) + mxt_init_hw_liquid(); + samsung_sys_class_init(); + mms_tsp_input_init(); +#if defined(CONFIG_SENSORS_AK8975) || defined(CONFIG_INPUT_BMP180) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + sensor_device_init(); +#endif +#if defined(CONFIG_MPU_SENSORS_MPU6050B1) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1_411) + mpl_init(); +#endif +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + opt_init(); +#endif +#if defined(CONFIG_NFC_PN544) + pn544_init(); +#endif + msm8960_mhl_gpio_init(); + register_i2c_devices(); + msm8960_init_fb(); + main_mic_bias_init(); + /* From REV13 onwards LINEOUT_EN is not used */ + if (system_rev < BOARD_REV13) { + tabla_codec_ldo_en_init(); + configure_codec_lineout_gpio(); + } + +#ifdef CONFIG_SAMSUNG_JACK + if (system_rev < BOARD_REV13) { + pr_info("%s : system rev = %d, MBHC Using\n", + __func__, system_rev); + memset(&sec_jack_data, 0, sizeof(sec_jack_data)); + } else { + pr_info("%s : system rev = %d, Secjack Using\n", + __func__, system_rev); + secjack_gpio_init(); + } +#endif + + msm8960_init_dsps(); +#if 0 + msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ); +#endif + change_memory_power = &msm8960_change_memory_power; + BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata)); +#if 0 + msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data); +#endif +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) + printk(KERN_INFO "[WIFI] system_rev = %d\n", system_rev); + if (system_rev >= BOARD_REV09) + brcm_wlan_init(); +#endif + msm_pm_set_tz_retention_flag(1); + + if (PLATFORM_IS_CHARM25()) + platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices)); + ion_adjust_secure_allocation(); +} + +MACHINE_START(M2_VZW, "SAMSUNG M2_VZW") + .map_io = msm8960_map_io, + .reserve = msm8960_reserve, + .init_irq = msm8960_init_irq, + .handle_irq = gic_handle_irq, + .timer = &msm_timer, + .init_machine = samsung_m2_vzw_init, + .init_early = msm8960_allocate_memory_regions, + .init_very_early = msm8960_early_memory, + .restart = msm_restart, +MACHINE_END +#endif diff --git a/arch/arm/mach-msm/board-mms-tsp.c b/arch/arm/mach-msm/board-mms-tsp.c new file mode 100644 index 00000000000..6ce42674a4f --- /dev/null +++ b/arch/arm/mach-msm/board-mms-tsp.c @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "board-8960.h" + +extern int system_rev; + +#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3 + +#define GPIO_TOUCH_IRQ 11 + +/* touch is on i2c3 */ +#define GPIO_TOUCH_SCL 17 +#define GPIO_TOUCH_SDA 16 +#define GPIO_LCD_TYPE PM8921_GPIO_PM_TO_SYS(44) + +/* #if !defined(CONFIG_TOUCHSCREEN_MXT224) +int touch_is_pressed; +EXPORT_SYMBOL(touch_is_pressed); +#endif */ + +static int melfas_mux_fw_flash(bool to_gpios) +{ + if (to_gpios) { + gpio_direction_output(GPIO_TOUCH_IRQ, 0); + gpio_tlmm_config(GPIO_CFG(GPIO_TOUCH_IRQ, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_direction_output(GPIO_TOUCH_SCL, 0); + gpio_tlmm_config(GPIO_CFG(GPIO_TOUCH_SCL, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_direction_output(GPIO_TOUCH_SDA, 0); + gpio_tlmm_config(GPIO_CFG(GPIO_TOUCH_SDA, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + } else { + gpio_direction_output(GPIO_TOUCH_IRQ, 1); + gpio_tlmm_config(GPIO_CFG(GPIO_TOUCH_IRQ, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_direction_output(GPIO_TOUCH_SCL, 1); + gpio_tlmm_config(GPIO_CFG(GPIO_TOUCH_SCL, 1, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_direction_output(GPIO_TOUCH_SDA, 1); + gpio_tlmm_config(GPIO_CFG(GPIO_TOUCH_SDA, 1, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + } + + return 0; +} + +void melfas_vdd_on(bool onoff) +{ + int ret = 0; + /* 3.3V */ + static struct regulator *reg_l17; + /* 1.8V */ +#ifdef CONFIG_MACH_M2_VZW + static struct regulator *reg_l11; + if (system_rev < BOARD_REV02) { + if (onoff) + gpio_direction_output(10, 1); + else + gpio_direction_output(10, 0); + } else +#endif + { +#if !defined(CONFIG_MACH_ESPRESSO_VZW) && !defined(CONFIG_MACH_ESPRESSO_ATT) \ + && !defined(CONFIG_MACH_ESPRESSO10_VZW) \ + && !defined(CONFIG_MACH_ESPRESSO_SPR) + static struct regulator *reg_lvs6; + + if (!reg_lvs6) { + reg_lvs6 = regulator_get(NULL, "8921_lvs6"); + if (IS_ERR(reg_lvs6)) { + pr_err("could not get 8921_lvs6, rc = %ld\n", + PTR_ERR(reg_lvs6)); + return; + } + } + + if (onoff) { + ret = regulator_enable(reg_lvs6); + if (ret) { + pr_err("enable lvs6 failed, rc=%d\n", ret); + return; + } + pr_info("tsp 1.8V on is finished.\n"); + } else { + if (regulator_is_enabled(reg_lvs6)) + ret = regulator_disable(reg_lvs6); + if (ret) { + pr_err("enable lvs6 failed, rc=%d\n", ret); + return; + } + pr_info("tsp 1.8V off is finished.\n"); + } + } + + + if (!reg_l17) { + reg_l17 = regulator_get(NULL, "8921_l17"); + if (IS_ERR(reg_l17)) { + pr_err("could not get 8921_l17, rc = %ld\n", + PTR_ERR(reg_l17)); + return; + } + ret = regulator_set_voltage(reg_l17, 3300000, 3300000); + if (ret) { + pr_err("%s: unable to set ldo17 voltage to 3.3V\n", + __func__); + return; + } + } + + if (onoff) { + ret = regulator_enable(reg_l17); + if (ret) { + pr_err("enable l17 failed, rc=%d\n", ret); + return; + } + pr_info("tsp 3.3V on is finished.\n"); + } else { + if (regulator_is_enabled(reg_l17)) + ret = regulator_disable(reg_l17); + + if (ret) { + pr_err("disable l17 failed, rc=%d\n", ret); + return; + } + pr_info("tsp 3.3V off is finished.\n"); + } +#else + /* 2.8V */ + if (machine_is_ESPRESSO_VZW() && system_rev < BOARD_REV03) { + if (!reg_l17) { + reg_l17 = regulator_get(NULL, "8921_l17"); + if (IS_ERR(reg_l17)) { + pr_err("could not get L17, rc=%ld\n", + PTR_ERR(reg_l17)); + return; + } + ret = regulator_set_voltage(reg_l17, + 2800000, 2800000); + if (ret) { + pr_err("%s: not set L17 to 2.8V\n", + __func__); + return; + } + } + + if (onoff) { + ret = regulator_enable(reg_l17); + if (ret) { + pr_err("l17 failed, rc=%d\n", ret); + return; + } + pr_info("tsp 2.8V on is finished.\n"); + } else { + if (regulator_is_enabled(reg_l17)) + ret = regulator_disable(reg_l17); + + if (ret) { + pr_err("disable l17 failed, rc=%d\n", + ret); + return; + } + pr_info("tsp 2.8V off is finished.\n"); + } + } else { + if (!reg_l11) { + reg_l11 = regulator_get(NULL, "8921_l11"); + if (IS_ERR(reg_l11)) { + pr_err("could not get L11, rc=%ld\n", + PTR_ERR(reg_l11)); + return; + } + ret = regulator_set_voltage(reg_l11, + 2800000, 2800000); + if (ret) { + pr_err("%s: not set L11 to 2.8V\n", + __func__); + return; + } + } + + if (onoff) { + ret = regulator_enable(reg_l11); + if (ret) { + pr_err("enable l11 failed, rc=%d\n", + ret); + return; + } + pr_info("tsp 2.8V on is finished.\n"); + } else { + if (regulator_is_enabled(reg_l11)) + ret = regulator_disable(reg_l11); + + if (ret) { + pr_err("disable l11 failed, rc=%d\n", + ret); + return; + } + pr_info("tsp 2.8V off is finished.\n"); + } + + + } + } + +#endif +} + +int is_melfas_vdd_on(void) +{ + int ret; + /* 3.3V */ + static struct regulator *reg_l17; +#if defined(CONFIG_MACH_ESPRESSO_VZW) || defined(CONFIG_MACH_ESPRESSO_ATT) \ + || defined(CONFIG_MACH_ESPRESSO10_VZW) \ + || defined(CONFIG_MACH_ESPRESSO_SPR) + static struct regulator *reg_l11; + if (system_rev < BOARD_REV03) { + if (!reg_l17) { + reg_l17 = regulator_get(NULL, "8921_l17"); + if (IS_ERR(reg_l17)) { + ret = PTR_ERR(reg_l17); + pr_err("could not get 8921_l17, rc = %d\n", + ret); + return ret; + } + ret = regulator_set_voltage(reg_l17, 2800000, 2800000); + if (ret) { + pr_err("%s: unable to set ldo17 voltage to 3.3V\n", + __func__); + return ret; + } + } + if (regulator_is_enabled(reg_l17)) + return 1; + else + return 0; + + } else { + if (!reg_l11) { + reg_l11 = regulator_get(NULL, "8921_l11"); + if (IS_ERR(reg_l11)) { + ret = PTR_ERR(reg_l11); + pr_err("could not get 8921_l11, rc = %d\n", + ret); + return ret; + } + ret = regulator_set_voltage(reg_l11, + 2800000, 2800000); + if (ret) { + pr_err("%s: not set L11 voltage to 3.3V\n", + __func__); + return ret; + } + } + + if (regulator_is_enabled(reg_l11)) + return 1; + else + return 0; + } +#else + if (!reg_l17) { + reg_l17 = regulator_get(NULL, "8921_l17"); + if (IS_ERR(reg_l17)) { + ret = PTR_ERR(reg_l17); + pr_err("could not get 8921_l17, rc = %d\n", + ret); + return ret; + } + ret = regulator_set_voltage(reg_l17, 3300000, 3300000); + if (ret) { + pr_err("%s: unable to set ldo17 voltage to 3.3V\n", + __func__); + return ret; + } + } + if (regulator_is_enabled(reg_l17)) + return 1; + else + return 0; + +#endif +} + +static void melfas_register_callback(struct tsp_callbacks *cb) +{ + charger_callbacks = cb; + pr_debug("[TSP] melfas_register_callback\n"); +} + +#if defined(CONFIG_TOUCHSCREEN_MMS136) || \ + defined(CONFIG_TOUCHSCREEN_MMS136_TABLET) +#define USE_TOUCHKEY 1 +static u8 touchkey_keycode[] = {KEY_MENU, KEY_HOMEPAGE, KEY_BACK}; +static u8 touchkey_keycode_4key[] = {KEY_BACK, KEY_HOMEPAGE, KEY_F3, KEY_MENU}; +#endif + +static struct mms_ts_platform_data mms_ts_pdata = { +#if defined(CONFIG_TOUCHSCREEN_MMS136) || \ + defined(CONFIG_TOUCHSCREEN_MMS136_TABLET) +#if defined(CONFIG_MACH_ESPRESSO_VZW) || defined(CONFIG_MACH_ESPRESSO_ATT) \ + || defined(CONFIG_MACH_ESPRESSO10_VZW) \ + || defined(CONFIG_MACH_ESPRESSO_SPR) + .max_x = 1024, + .max_y = 600, + .config_fw_version = "I705_MELFAS_0313", +#else + .max_x = 480, + .max_y = 800, + .register_cb = melfas_register_callback, +#endif + .use_touchkey = USE_TOUCHKEY, + .touchkey_keycode = touchkey_keycode, +#elif defined(CONFIG_TOUCHSCREEN_MMS144) + .max_x = 720, + .max_y = 1280, + .gpio_lcd_type = GPIO_LCD_TYPE, + .config_fw_version = "I747_Me_0507", + .register_cb = melfas_register_callback, +#endif + .mux_fw_flash = melfas_mux_fw_flash, + .vdd_on = melfas_vdd_on, + .is_vdd_on = is_melfas_vdd_on, + .gpio_resetb = GPIO_TOUCH_IRQ, + .gpio_scl = GPIO_TOUCH_SCL, + .gpio_sda = GPIO_TOUCH_SDA, + .check_module_type = false, +}; + +static struct i2c_board_info __initdata mms_i2c3_boardinfo_final[] = { + { + I2C_BOARD_INFO("mms_ts", 0x48), + .flags = I2C_CLIENT_WAKE, + .platform_data = &mms_ts_pdata, + .irq = MSM_GPIO_TO_INT(GPIO_TOUCH_IRQ), + }, +}; + +#ifdef CONFIG_MACH_M2_VZW +static void mms144_init(void) +{ + if (system_rev < BOARD_REV02) { + int ret; + + ret = gpio_request(10, "tsp_ldo_en"); + if (ret != 0) { + pr_err("tsp ldo request failed, ret=%d", ret); + return; + } + } +} +#endif + +#ifdef CONFIG_MACH_JASPER +static void mms136_tkey_init(void) +{ + if (system_rev >= BOARD_REV04) + mms_ts_pdata.touchkey_keycode = touchkey_keycode_4key; +} +#endif + +void __init mms_tsp_input_init(void) +{ + int ret; + +#ifdef CONFIG_MACH_M2_VZW + mms144_init(); +#endif +#ifdef CONFIG_MACH_JASPER + mms136_tkey_init(); +#endif + ret = gpio_request(GPIO_TOUCH_IRQ, "tsp_int"); + if (ret != 0) { + pr_err("tsp int request failed, ret=%d", ret); + goto err_int_gpio_request; + } + gpio_tlmm_config(GPIO_CFG(GPIO_TOUCH_IRQ, 0, + GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + ret = gpio_request(GPIO_TOUCH_SCL, "tsp_scl"); + if (ret != 0) { + pr_err("tsp scl request failed, ret=%d", ret); + goto err_scl_gpio_request; + } + ret = gpio_request(GPIO_TOUCH_SDA, "tsp_sda"); + if (ret != 0) { + pr_err("tsp sda request failed, ret=%d", ret); + goto err_sda_gpio_request; + } + melfas_vdd_on(1); + + i2c_register_board_info(MSM_8960_GSBI3_QUP_I2C_BUS_ID, + mms_i2c3_boardinfo_final, + ARRAY_SIZE(mms_i2c3_boardinfo_final)); + +err_sda_gpio_request: + gpio_free(GPIO_TOUCH_SCL); +err_scl_gpio_request: + gpio_free(GPIO_TOUCH_IRQ); +err_int_gpio_request: + ; +} diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c index 378952901c1..08f165defb1 100644 --- a/arch/arm/mach-msm/clock-8960.c +++ b/arch/arm/mach-msm/clock-8960.c @@ -5687,17 +5687,27 @@ static struct clk_lookup msm_clocks_8960_common[] __initdata = { CLK_LOOKUP("core_clk", gsbi10_uart_clk.c, ""), CLK_LOOKUP("core_clk", gsbi11_uart_clk.c, ""), CLK_LOOKUP("core_clk", gsbi12_uart_clk.c, ""), - CLK_LOOKUP("core_clk", gsbi1_qup_clk.c, "spi_qsd.0"), +#if defined(CONFIG_VP_A2220) + CLK_LOOKUP("core_clk", gsbi1_qup_clk.c, "qup_i2c.1"), +#elif defined(CONFIG_S5C73M3) + CLK_LOOKUP("core_clk", gsbi1_qup_clk.c, NULL), +#else + CLK_LOOKUP("core_clk", gsbi1_qup_clk.c, "spi_qsd.0"), +#endif CLK_LOOKUP("core_clk", gsbi2_qup_clk.c, ""), CLK_LOOKUP("core_clk", gsbi3_qup_clk.c, "qup_i2c.3"), CLK_LOOKUP("core_clk", gsbi4_qup_clk.c, "qup_i2c.4"), CLK_LOOKUP("core_clk", gsbi5_qup_clk.c, ""), CLK_LOOKUP("core_clk", gsbi6_qup_clk.c, ""), - CLK_LOOKUP("core_clk", gsbi7_qup_clk.c, ""), - CLK_LOOKUP("core_clk", gsbi8_qup_clk.c, ""), + CLK_LOOKUP("core_clk", gsbi7_qup_clk.c, "qup_i2c.7"), + CLK_LOOKUP("core_clk", gsbi8_qup_clk.c, "qup_i2c.8"), CLK_LOOKUP("core_clk", gsbi9_qup_clk.c, ""), CLK_LOOKUP("core_clk", gsbi10_qup_clk.c, "qup_i2c.10"), - CLK_LOOKUP("core_clk", gsbi11_qup_clk.c, ""), +#ifdef CONFIG_S5C73M3 + CLK_LOOKUP("core_clk", gsbi11_qup_clk.c, "spi_qsd.0"), +#else + CLK_LOOKUP("core_clk", gsbi11_qup_clk.c, NULL), +#endif CLK_LOOKUP("core_clk", gsbi12_qup_clk.c, "qup_i2c.12"), CLK_LOOKUP("core_clk", pdm_clk.c, ""), CLK_LOOKUP("mem_clk", pmem_clk.c, "msm_sps"), @@ -5727,20 +5737,31 @@ static struct clk_lookup msm_clocks_8960_common[] __initdata = { CLK_LOOKUP("core_clk", ce1_core_clk.c, "qce.0"), CLK_LOOKUP("core_clk", ce1_core_clk.c, "qcrypto.0"), CLK_LOOKUP("dma_bam_pclk", dma_bam_p_clk.c, NULL), - CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, "spi_qsd.0"), +#if defined(CONFIG_VP_A2220) + CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, "qup_i2c.1"), +#elif defined(CONFIG_S5C73M3) + CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, NULL), +#else + CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, "spi_qsd.0"), +#endif CLK_LOOKUP("iface_clk", gsbi2_p_clk.c, ""), CLK_LOOKUP("iface_clk", gsbi3_p_clk.c, "qup_i2c.3"), CLK_LOOKUP("iface_clk", gsbi4_p_clk.c, "qup_i2c.4"), CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "msm_serial_hsl.0"), CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "msm_serial_hs.0"), - CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, ""), + CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, "qup_i2c.7"), /* used on 8960 SGLTE for serial console */ CLK_LOOKUP("iface_clk", gsbi8_p_clk.c, "msm_serial_hsl.1"), /* used on 8960 standalone with Atheros Bluetooth */ CLK_LOOKUP("iface_clk", gsbi8_p_clk.c, "msm_serial_hs.2"), + CLK_LOOKUP("iface_clk", gsbi8_p_clk.c, "qup_i2c.8"), CLK_LOOKUP("iface_clk", gsbi9_p_clk.c, "msm_serial_hs.1"), CLK_LOOKUP("iface_clk", gsbi10_p_clk.c, "qup_i2c.10"), - CLK_LOOKUP("iface_clk", gsbi11_p_clk.c, ""), +#ifdef CONFIG_S5C73M3 + CLK_LOOKUP("iface_clk", gsbi11_p_clk.c, "spi_qsd.0"), +#else + CLK_LOOKUP("iface_clk", gsbi11_p_clk.c, NULL), +#endif CLK_LOOKUP("iface_clk", gsbi12_p_clk.c, "qup_i2c.12"), CLK_LOOKUP("iface_clk", tsif_p_clk.c, ""), CLK_LOOKUP("ref_clk", tsif_ref_clk.c, "msm_tspp.0"), @@ -5759,10 +5780,22 @@ static struct clk_lookup msm_clocks_8960_common[] __initdata = { CLK_LOOKUP("iface_clk", pmic_arb1_p_clk.c, ""), CLK_LOOKUP("core_clk", pmic_ssbi2_clk.c, ""), CLK_LOOKUP("mem_clk", rpm_msg_ram_p_clk.c, ""), + CLK_LOOKUP("cam_clk", cam0_clk.c, NULL), + CLK_LOOKUP("cam_clk", cam1_clk.c, NULL), + CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_isx012.0"), + CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_s5k5ccgx.0"), + CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_s5k4ecgx.0"), + CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_s5k6aa.0"), + CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_s5k8aay.0"), + CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_sr030pc50.0"), + CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_s5c73m3.0"), + CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_db8131m.0"), CLK_LOOKUP("cam_clk", cam0_clk.c, "4-001a"), CLK_LOOKUP("cam_clk", cam0_clk.c, "4-006c"), CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0048"), CLK_LOOKUP("cam_clk", cam2_clk.c, NULL), + CLK_LOOKUP("cam_clk", cam2_clk.c, "msm_camera_s5k6a3yx.0"), + CLK_LOOKUP("cam_clk", cam2_clk.c, "4-0045"), CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0020"), CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0034"), CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_csid.0"), @@ -5862,26 +5895,16 @@ static struct clk_lookup msm_clocks_8960_common[] __initdata = { CLK_LOOKUP("iface_clk", vfe_p_clk.c, "footswitch-8x60.8"), CLK_LOOKUP("vpe_pclk", vpe_p_clk.c, "msm_vpe.0"), CLK_LOOKUP("iface_clk", vpe_p_clk.c, "footswitch-8x60.9"), - CLK_LOOKUP("bit_clk", mi2s_bit_clk.c, - "msm-dai-q6-mi2s"), - CLK_LOOKUP("osr_clk", mi2s_osr_clk.c, - "msm-dai-q6-mi2s"), - CLK_LOOKUP("bit_clk", codec_i2s_mic_bit_clk.c, - "msm-dai-q6.1"), - CLK_LOOKUP("osr_clk", codec_i2s_mic_osr_clk.c, - "msm-dai-q6.1"), - CLK_LOOKUP("bit_clk", spare_i2s_mic_bit_clk.c, - "msm-dai-q6.5"), - CLK_LOOKUP("osr_clk", spare_i2s_mic_osr_clk.c, - "msm-dai-q6.5"), - CLK_LOOKUP("bit_clk", codec_i2s_spkr_bit_clk.c, - "msm-dai-q6.16384"), - CLK_LOOKUP("osr_clk", codec_i2s_spkr_osr_clk.c, - "msm-dai-q6.16384"), - CLK_LOOKUP("bit_clk", spare_i2s_spkr_bit_clk.c, - "msm-dai-q6.4"), - CLK_LOOKUP("osr_clk", spare_i2s_spkr_osr_clk.c, - "msm-dai-q6.4"), + CLK_LOOKUP("bit_clk", mi2s_bit_clk.c, NULL), + CLK_LOOKUP("osr_clk", mi2s_osr_clk.c, NULL), + CLK_LOOKUP("i2s_mic_bit_clk", codec_i2s_mic_bit_clk.c, NULL), + CLK_LOOKUP("i2s_mic_osr_clk", codec_i2s_mic_osr_clk.c, NULL), + CLK_LOOKUP("i2s_mic_bit_clk", spare_i2s_mic_bit_clk.c, NULL), + CLK_LOOKUP("i2s_mic_osr_clk", spare_i2s_mic_osr_clk.c, NULL), + CLK_LOOKUP("i2s_spkr_bit_clk", codec_i2s_spkr_bit_clk.c, NULL), + CLK_LOOKUP("i2s_spkr_osr_clk", codec_i2s_spkr_osr_clk.c, NULL), + CLK_LOOKUP("i2s_spkr_bit_clk", spare_i2s_spkr_bit_clk.c, NULL), + CLK_LOOKUP("i2s_spkr_osr_clk", spare_i2s_spkr_osr_clk.c, NULL), CLK_LOOKUP("pcm_clk", pcm_clk.c, "msm-dai-q6.2"), CLK_LOOKUP("pcm_clk", pcm_clk.c, "msm-dai-q6.3"), CLK_LOOKUP("sps_slimbus_clk", sps_slimbus_clk.c, NULL), diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c index 84b72d0c97a..aec5522d55a 100644 --- a/arch/arm/mach-msm/devices-8960.c +++ b/arch/arm/mach-msm/devices-8960.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1081,7 +1082,7 @@ struct msm_vidc_platform_data vidc_platform_data = { .disable_dmx = 0, .disable_fullhd = 0, .cont_mode_dpb_count = 18, - .fw_addr = 0x9fe00000, + .fw_addr = 0xafe00000, .enable_sec_metadata = 0, }; @@ -1705,7 +1706,46 @@ int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat) pdev->dev.platform_data = plat; return platform_device_register(pdev); } - +#if defined(CONFIG_MACH_M2_SPR) || defined(CONFIG_MACH_M2_VZW) || defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_M2_DCM) +static struct resource resources_qup_i2c_gsbi1[] = { + { + .name = "gsbi_qup_i2c_addr", + .start = MSM_GSBI1_PHYS, + .end = MSM_GSBI1_PHYS + 4 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "qup_phys_addr", + .start = MSM_GSBI1_QUP_PHYS, + .end = MSM_GSBI1_QUP_PHYS + MSM_QUP_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "qup_err_intr", + .start = MSM8960_GSBI1_QUP_IRQ, + .end = MSM8960_GSBI1_QUP_IRQ, + .flags = IORESOURCE_IRQ, + }, + { + .name = "i2c_clk", + .start = GPIO_CODEC_I2C_SCL, + .end = GPIO_CODEC_I2C_SCL, + .flags = IORESOURCE_IO, + }, + { + .name = "i2c_sda", + .start = GPIO_CODEC_I2C_SDA, + .end = GPIO_CODEC_I2C_SDA, + .flags = IORESOURCE_IO, + }, +}; +struct platform_device msm8960_device_qup_i2c_gsbi1 = { + .name = "qup_i2c", + .id = 1, + .num_resources = ARRAY_SIZE(resources_qup_i2c_gsbi1), + .resource = resources_qup_i2c_gsbi1, +}; +#endif static struct resource resources_qup_i2c_gsbi4[] = { { .name = "gsbi_qup_i2c_addr", @@ -1762,6 +1802,62 @@ struct platform_device msm8960_device_qup_i2c_gsbi3 = { .resource = resources_qup_i2c_gsbi3, }; +static struct resource resources_qup_i2c_gsbi7[] = { + { + .name = "gsbi_qup_i2c_addr", + .start = MSM_GSBI7_PHYS, + .end = MSM_GSBI7_PHYS + MSM_QUP_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "qup_phys_addr", + .start = MSM_GSBI7_QUP_PHYS, + .end = MSM_GSBI7_QUP_PHYS + 4 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "qup_err_intr", + .start = GSBI7_QUP_IRQ, + .end = GSBI7_QUP_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device msm8960_device_qup_i2c_gsbi7 = { + .name = "qup_i2c", + .id = 7, + .num_resources = ARRAY_SIZE(resources_qup_i2c_gsbi7), + .resource = resources_qup_i2c_gsbi7, +}; + +static struct resource resources_qup_i2c_gsbi8[] = { + { + .name = "gsbi_qup_i2c_addr", + .start = MSM_GSBI8_PHYS, + .end = MSM_GSBI8_PHYS + 4 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "qup_phys_addr", + .start = MSM_GSBI8_QUP_PHYS, + .end = MSM_GSBI8_QUP_PHYS + MSM_QUP_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "qup_err_intr", + .start = GSBI8_QUP_IRQ, + .end = GSBI8_QUP_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device msm8960_device_qup_i2c_gsbi8 = { + .name = "qup_i2c", + .id = 8, + .num_resources = ARRAY_SIZE(resources_qup_i2c_gsbi8), + .resource = resources_qup_i2c_gsbi8, +}; + static struct resource resources_qup_i2c_gsbi9[] = { { .name = "gsbi_qup_i2c_addr", @@ -2246,6 +2342,88 @@ struct platform_device msm8960_device_qup_spi_gsbi1 = { .resource = resources_qup_spi_gsbi1, }; +#ifdef CONFIG_S5C73M3 +static struct resource resources_qup_spi_gsbi11[] = { + { + .name = "spi_base", + .start = MSM_GSBI11_QUP_PHYS, + .end = MSM_GSBI11_QUP_PHYS + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "gsbi_base", + .start = MSM_GSBI11_PHYS, + .end = MSM_GSBI11_PHYS + 4 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "spi_irq_in", + .start = GSBI11_QUP_IRQ, + .end = GSBI11_QUP_IRQ, + .flags = IORESOURCE_IRQ, + }, + /*test: Qualcomm, DMA SPI, start */ + { + .name = "spidm_channels", + .start = 9, + .end = 10, + .flags = IORESOURCE_DMA, + }, + { + .name = "spidm_crci", + .start = 12, + .end = 13, + .flags = IORESOURCE_DMA, + }, + /*test: Qualcomm, DMA SPI, end */ + { + .name = "spi_clk", + .start = GPIO_CAM_SPI_SCLK, + .end = GPIO_CAM_SPI_SCLK, + .flags = IORESOURCE_IO, + }, + { + .name = "spi_miso", + .start = GPIO_CAM_SPI_MISO, + .end = GPIO_CAM_SPI_MISO, + .flags = IORESOURCE_IO, + }, + { + .name = "spi_mosi", + .start = GPIO_CAM_SPI_MOSI, + .end = GPIO_CAM_SPI_MOSI, + .flags = IORESOURCE_IO, + }, + { + .name = "spi_cs", + .start = GPIO_CAM_SPI_SSN, + .end = GPIO_CAM_SPI_SSN, + .flags = IORESOURCE_IO, + }, +#ifdef CONFIG_VP_A2220 + { + .name = "a2220_sda", + .start = GPIO_A2220_I2C_SDA, + .end = GPIO_A2220_I2C_SDA, + .flags = IORESOURCE_IO, + }, + { + .name = "a2220_sck", + .start = GPIO_A2220_I2C_SCL, + .end = GPIO_A2220_I2C_SCL, + .flags = IORESOURCE_IO, + }, +#endif +}; + +struct platform_device msm8960_device_qup_spi_gsbi11 = { + .name = "spi_qsd", + .id = 0, + .num_resources = ARRAY_SIZE(resources_qup_spi_gsbi11), + .resource = resources_qup_spi_gsbi11, +}; +#endif + struct platform_device msm_pcm = { .name = "msm-pcm-dsp", .id = -1, @@ -2276,6 +2454,16 @@ struct platform_device msm_cpudai1 = { .id = 0x4001, }; +struct platform_device msm_i2s_cpudai0 = { + .name = "msm-dai-q6", + .id = PRIMARY_I2S_RX, +}; + +struct platform_device msm_i2s_cpudai1 = { + .name = "msm-dai-q6", + .id = PRIMARY_I2S_TX, +}; + struct platform_device msm8960_cpudai_slimbus_2_rx = { .name = "msm-dai-q6", .id = 0x4004, @@ -2546,7 +2734,7 @@ static struct fs_driver_data vpe_fs_data = { }; struct platform_device *msm8960_footswitch[] __initdata = { - FS_8X60(FS_MDP, "vdd", "mdp.0", &mdp_fs_data), +// FS_8X60(FS_MDP, "vdd", "mdp.0", &mdp_fs_data), FS_8X60(FS_ROT, "vdd", "msm_rotator.0", &rot_fs_data), FS_8X60(FS_IJPEG, "vdd", "msm_gemini.0", &ijpeg_fs_data), FS_8X60(FS_VFE, "vdd", "msm_vfe.0", &vfe_fs_data), diff --git a/arch/arm/mach-msm/devices-msm8x60.h b/arch/arm/mach-msm/devices-msm8x60.h index fafe4e40deb..d8eba825afa 100644 --- a/arch/arm/mach-msm/devices-msm8x60.h +++ b/arch/arm/mach-msm/devices-msm8x60.h @@ -23,6 +23,24 @@ #define MSM_SSBI2_I2C_BUS_ID 7 #define MSM_SSBI3_I2C_BUS_ID 8 +/* add more I2C BUS */ +#define MSM_8960_GSBI1_QUP_I2C_BUS_ID 1 +#define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4 +#define MSM_8960_GSBI7_QUP_I2C_BUS_ID 7 + +#define MSM_MHL_I2C_BUS_ID 9 +#define MSM_FSA9485_I2C_BUS_ID 11 +#define MSM_SNS_I2C_BUS_ID 12 +#define MSM_FUELGAUGE_I2C_BUS_ID 13 +#define MSM_OPT_I2C_BUS_ID 14 +#define MSM_TOUCHKEY_I2C_BUS_ID 16 +#define MSM_NFC_I2C_BUS_ID 17 +#define MSM_A2220_I2C_BUS_ID 18 +#ifdef CONFIG_SAMSUNG_CMC624 +#define MSM_CMC624_I2C_BUS_ID 19 +#endif + + #ifdef CONFIG_SND_SOC_MSM8660_APQ extern struct platform_device msm_pcm; extern struct platform_device msm_pcm_routing; diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h index 5f3aa3a43f6..9249a7685a8 100644 --- a/arch/arm/mach-msm/devices.h +++ b/arch/arm/mach-msm/devices.h @@ -60,11 +60,20 @@ extern struct platform_device msm8960_device_uart_gsbi2; extern struct platform_device msm8960_device_uart_gsbi5; extern struct platform_device msm8960_device_uart_gsbi8; extern struct platform_device msm8960_device_ssbi_pmic; +extern struct platform_device msm8960_device_qup_i2c_gsbi1; extern struct platform_device msm8960_device_qup_i2c_gsbi3; extern struct platform_device msm8960_device_qup_i2c_gsbi4; +extern struct platform_device msm8960_device_qup_i2c_gsbi7; +extern struct platform_device msm8960_device_qup_i2c_gsbi8; extern struct platform_device msm8960_device_qup_i2c_gsbi9; extern struct platform_device msm8960_device_qup_i2c_gsbi10; extern struct platform_device msm8960_device_qup_i2c_gsbi12; +#ifndef CONFIG_S5C73M3 +extern struct platform_device msm8960_device_qup_spi_gsbi1; +#endif +#ifdef CONFIG_S5C73M3 +extern struct platform_device msm8960_device_qup_spi_gsbi11; +#endif extern struct platform_device msm8960_device_qup_spi_gsbi1; extern struct platform_device msm8960_gemini_device; extern struct platform_device msm8960_mercury_device; diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c index d5fe866013d..4366d3595f4 100644 --- a/arch/arm/mach-msm/footswitch-8x60.c +++ b/arch/arm/mach-msm/footswitch-8x60.c @@ -141,6 +141,7 @@ static int footswitch_enable(struct regulator_dev *rdev) struct fs_clk_data *clock; uint32_t regval, rc = 0; + printk(KERN_DEBUG "%s: %s\n", __func__, fs->desc.name); mutex_lock(&claim_lock); fs->is_claimed = true; mutex_unlock(&claim_lock); @@ -227,6 +228,7 @@ static int footswitch_disable(struct regulator_dev *rdev) struct fs_clk_data *clock; uint32_t regval, rc = 0; + printk(KERN_DEBUG "%s: %s\n", __func__, fs->desc.name); /* Return early if already disabled. */ regval = readl_relaxed(fs->gfs_ctl_reg); if ((regval & ENABLE_BIT) == 0) @@ -469,7 +471,7 @@ static struct footswitch footswitches[] = { FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops, GFX2D1_GFS_CTL_REG), FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops, GFX3D_GFS_CTL_REG), FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops, GEMINI_GFS_CTL_REG), - FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops, MDP_GFS_CTL_REG), +// FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops, MDP_GFS_CTL_REG), FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops, ROT_GFS_CTL_REG), FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops, VED_GFS_CTL_REG), FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops, VFE_GFS_CTL_REG), diff --git a/arch/arm/mach-msm/include/mach/board-msm8960-camera.h b/arch/arm/mach-msm/include/mach/board-msm8960-camera.h new file mode 100644 index 00000000000..4d3a8295bcb --- /dev/null +++ b/arch/arm/mach-msm/include/mach/board-msm8960-camera.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +#ifndef _SEC_CAM_PMIC_H +#define _SEC_CAM_PMIC_H + +#define ISX012_DEBUG +#ifdef ISX012_DEBUG +#define CAM_DEBUG(fmt, arg...) \ + do {\ + printk(KERN_INFO "[ISX012] %s:%d: " fmt "\n", \ + __func__, __LINE__, ##arg); } \ + while (0) + +#define cam_info(fmt, arg...) \ + do {\ + printk(KERN_INFO "[ISX012]" fmt "\n", ##arg); } \ + while (0) + +#define cam_err(fmt, arg...) \ + do {\ + printk(KERN_ERR "[ISX012] %s:%d:" fmt "\n", \ + __func__, __LINE__, ##arg); } \ + while (0) + +#else +#define CAM_DEBUG(fmt, arg...) +#define cam_info(fmt, arg...) +#define cam_err(fmt, arg...) +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 0f1bf5f7016..2da39064040 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -65,6 +65,19 @@ struct msm_camera_device_platform_data { struct msm_bus_scale_pdata *cam_bus_scale_table; }; +enum msm_camera_csi_data_format { + CSI_8BIT, + CSI_10BIT, + CSI_12BIT, +}; +struct msm_camera_csi_params { + enum msm_camera_csi_data_format data_format; + uint8_t lane_cnt; + uint8_t lane_assign; + uint8_t settle_cnt; + uint8_t dpcm_scheme; +}; + #ifdef CONFIG_SENSORS_MT9T013 struct msm_camera_legacy_device_platform_data { int sensor_reset; @@ -168,6 +181,19 @@ enum msm_sensor_type { YUV_SENSOR, }; +enum camera_vreg_type { + REG_LDO, + REG_VS, +}; + +struct camera_vreg_t { + char *reg_name; + enum camera_vreg_type type; + int min_voltage; + int max_voltage; + int op_mode; +}; + struct msm_gpio_set_tbl { unsigned gpio; unsigned long flags; @@ -179,12 +205,17 @@ struct msm_camera_csi_lane_params { uint16_t csi_lane_mask; uint8_t csi_phy_sel; }; - +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) /* D2 */ +struct msm_camera_gpio_conf { + void *cam_gpiomux_conf_tbl; + uint8_t cam_gpiomux_conf_tbl_size; + uint16_t *cam_gpio_tbl; + uint8_t cam_gpio_tbl_size; +}; +#else struct msm_camera_gpio_conf { void *cam_gpiomux_conf_tbl; uint8_t cam_gpiomux_conf_tbl_size; - struct gpio *cam_gpio_common_tbl; - uint8_t cam_gpio_common_tbl_size; struct gpio *cam_gpio_req_tbl; uint8_t cam_gpio_req_tbl_size; struct msm_gpio_set_tbl *cam_gpio_set_tbl; @@ -195,19 +226,7 @@ struct msm_camera_gpio_conf { uint32_t *camera_on_table; uint8_t camera_on_table_size; }; - -enum msm_camera_i2c_mux_mode { - MODE_R, - MODE_L, - MODE_DUAL -}; - -struct msm_camera_i2c_conf { - uint8_t use_i2c_mux; - struct platform_device *mux_dev; - enum msm_camera_i2c_mux_mode i2c_mux_mode; -}; - +#endif enum msm_camera_vreg_name_t { CAM_VDIG, CAM_VIO, @@ -224,6 +243,23 @@ struct msm_camera_sensor_platform_info { struct msm_camera_gpio_conf *gpio_conf; struct msm_camera_i2c_conf *i2c_conf; struct msm_camera_csi_lane_params *csi_lane_params; +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) /* D2 */ + int privacy_light; + void *privacy_light_info; + int vcm_pwd; + int vcm_enable; + int mclk; + int sensor_pwd; + int flash_set; + int flash_en; + void(*sensor_power_on) (int, int); + void(*sensor_power_off) (int); + void(*sensor_isp_reset) (void); + void(*sensor_get_fw) (u8 *isp_fw, u8 *phone_fw); + void(*sensor_set_isp_core) (int); + bool(*sensor_is_vdd_core_set) (void); +#endif + }; enum msm_camera_actuator_name { @@ -276,6 +312,10 @@ struct msm_camera_sensor_info { struct msm_actuator_info *actuator_info; int pmic_gpio_enable; struct msm_eeprom_info *eeprom_info; +#if defined(CONFIG_S5C73M3) && defined(CONFIG_S5K6A3YX) /* D2 */ + struct msm_camera_gpio_conf *gpio_conf; +#endif + }; struct msm_camera_board_info { @@ -433,6 +473,9 @@ struct mipi_dsi_platform_data { int (*get_lane_config)(void); char (*splash_is_enabled)(void); int target_type; + void (*lcd_rst_up)(void); + void (*lcd_rst_down)(void); + }; enum mipi_dsi_3d_ctrl { @@ -557,6 +600,17 @@ struct isp1763_platform_data { int (*setup_gpio)(int enable); }; #endif + +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +struct sec_esd_platform_data { + int esd_gpio_irq; +#if defined(CONFIG_SAMSUNG_CMC624) + int esd_gpio_cmc_irq; +#endif +}; +#endif + + /* common init routines for use by arch/arm/mach-msm/board-*.c */ #ifdef CONFIG_OF_DEVICE diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h index 1518cee9eb4..94b64105b46 100644 --- a/arch/arm/mach-msm/include/mach/camera.h +++ b/arch/arm/mach-msm/include/mach/camera.h @@ -18,14 +18,19 @@ #include #include #include -#include +#include #include #include "linux/types.h" #include #include +#include +#include #include -#include + +#if defined(CONFIG_MACH_ESPRESSO_VZW) +extern int cam_mode; +#endif #define CONFIG_MSM_CAMERA_DEBUG #ifdef CONFIG_MSM_CAMERA_DEBUG @@ -46,7 +51,7 @@ #define max_control_command_size 512 #define CROP_LEN 36 -enum vfe_mode_of_operation{ +enum vfe_mode_of_operation { VFE_MODE_OF_OPERATION_CONTINUOUS, VFE_MODE_OF_OPERATION_SNAPSHOT, VFE_MODE_OF_OPERATION_VIDEO, @@ -85,17 +90,15 @@ enum vfe_resp_msg { VFE_MSG_SYNC_TIMER1, VFE_MSG_SYNC_TIMER2, VFE_MSG_COMMON, - VFE_MSG_START, - VFE_MSG_START_RECORDING, /* 20 */ - VFE_MSG_CAPTURE, - VFE_MSG_JPEG_CAPTURE, + VFE_MSG_V32_START, + VFE_MSG_V32_START_RECORDING, /* 20 */ + VFE_MSG_V32_CAPTURE, + VFE_MSG_V32_JPEG_CAPTURE, VFE_MSG_OUTPUT_IRQ, - VFE_MSG_PREVIEW, + VFE_MSG_V2X_PREVIEW, + VFE_MSG_V2X_CAPTURE, VFE_MSG_OUTPUT_PRIMARY, VFE_MSG_OUTPUT_SECONDARY, - VFE_MSG_OUTPUT_TERTIARY1, - VFE_MSG_OUTPUT_TERTIARY2, - VFE_MSG_OUTPUT_TERTIARY3, }; enum vpe_resp_msg { @@ -116,6 +119,52 @@ enum msm_stereo_state { STEREO_RAW_SNAP_STARTED, }; +enum msm_ispif_intftype { + PIX0, + RDI0, + PIX1, + RDI1, + PIX2, + RDI2, +}; + +enum msm_ispif_vc { + VC0, + VC1, + VC2, + VC3, +}; + +enum msm_ispif_cid { + CID0, + CID1, + CID2, + CID3, + CID4, + CID5, + CID6, + CID7, + CID8, + CID9, + CID10, + CID11, + CID12, + CID13, + CID14, + CID15, +}; + +struct msm_ispif_params { + uint8_t intftype; + uint16_t cid_mask; + uint8_t csid; +}; + +struct msm_ispif_params_list { + uint32_t len; + struct msm_ispif_params params[3]; +}; + struct msm_vpe_phy_info { uint32_t sbuf_phy; uint32_t planar0_off; @@ -128,6 +177,33 @@ struct msm_vpe_phy_info { uint32_t frame_id; }; +struct msm_camera_csid_vc_cfg { + uint8_t cid; + uint8_t dt; + uint8_t decode_format; +}; + +struct msm_camera_csid_lut_params { + uint8_t num_cid; + struct msm_camera_csid_vc_cfg *vc_cfg; +}; + +struct msm_camera_csid_params { + uint8_t lane_cnt; + uint8_t lane_assign; + struct msm_camera_csid_lut_params lut_params; +}; + +struct msm_camera_csiphy_params { + uint8_t lane_cnt; + uint8_t settle_cnt; +}; + +struct msm_camera_csi2_params { + struct msm_camera_csid_params csid_params; + struct msm_camera_csiphy_params csiphy_params; +}; + #ifndef CONFIG_MSM_CAMERA_V4L2 #define VFE31_OUTPUT_MODE_PT (0x1 << 0) #define VFE31_OUTPUT_MODE_S (0x1 << 1) @@ -137,6 +213,17 @@ struct msm_vpe_phy_info { #define VFE31_OUTPUT_MODE_P_ALL_CHNLS (0x1 << 5) #endif +#define CSI_EMBED_DATA 0x12 +#define CSI_YUV422_8 0x1E +#define CSI_RAW8 0x2A +#define CSI_RAW10 0x2B +#define CSI_RAW12 0x2C + +#define CSI_DECODE_6BIT 0 +#define CSI_DECODE_8BIT 1 +#define CSI_DECODE_10BIT 2 +#define CSI_DECODE_DPCM_10_8_10 5 + struct msm_vfe_phy_info { uint32_t sbuf_phy; uint32_t planar0_off; @@ -162,7 +249,7 @@ struct msm_vfe_stats_msg { uint32_t frame_id; }; -struct video_crop_t{ +struct video_crop_t { uint32_t in1_w; uint32_t out1_w; uint32_t in1_h; @@ -259,6 +346,14 @@ struct msm_sensor_ctrl { enum msm_st_frame_packing s_snap_packing; }; +struct msm_actuator_ctrl { + int (*a_init_table)(void); + int (*a_power_up)(void *); + int (*a_power_down)(void *); + int (*a_create_subdevice)(void *, void *); + int (*a_config)(void __user *); +}; + struct msm_strobe_flash_ctrl { int (*strobe_flash_init) (struct msm_camera_sensor_strobe_flash_data *); @@ -267,94 +362,6 @@ struct msm_strobe_flash_ctrl { int (*strobe_flash_charge)(int32_t, int32_t, uint32_t); }; -enum cci_i2c_master_t { - MASTER_0, - MASTER_1, -}; - -enum cci_i2c_queue_t { - QUEUE_0, - QUEUE_1, -}; - -struct msm_camera_cci_client { - struct v4l2_subdev *cci_subdev; - uint32_t freq; - enum cci_i2c_master_t cci_i2c_master; - uint16_t sid; - uint16_t cid; - uint32_t timeout; - uint16_t retries; - uint16_t id_map; -}; - -enum msm_cci_cmd_type { - MSM_CCI_INIT, - MSM_CCI_RELEASE, - MSM_CCI_SET_SID, - MSM_CCI_SET_FREQ, - MSM_CCI_SET_SYNC_CID, - MSM_CCI_I2C_READ, - MSM_CCI_I2C_WRITE, - MSM_CCI_GPIO_WRITE, -}; - -struct msm_camera_cci_wait_sync_cfg { - uint16_t line; - uint16_t delay; -}; - -struct msm_camera_cci_gpio_cfg { - uint16_t gpio_queue; - uint16_t i2c_queue; -}; - -enum msm_camera_i2c_cmd_type { - MSM_CAMERA_I2C_CMD_WRITE, - MSM_CAMERA_I2C_CMD_POLL, -}; - -struct msm_camera_i2c_reg_conf { - uint16_t reg_addr; - uint16_t reg_data; - enum msm_camera_i2c_data_type dt; - enum msm_camera_i2c_cmd_type cmd_type; - int16_t mask; -}; - -struct msm_camera_cci_i2c_write_cfg { - struct msm_camera_i2c_reg_conf *reg_conf_tbl; - enum msm_camera_i2c_reg_addr_type addr_type; - enum msm_camera_i2c_data_type data_type; - uint16_t size; -}; - -struct msm_camera_cci_i2c_read_cfg { - uint16_t addr; - enum msm_camera_i2c_reg_addr_type addr_type; - uint8_t *data; - uint16_t num_byte; -}; - -struct msm_camera_cci_i2c_queue_info { - uint32_t max_queue_size; - uint32_t report_id; - uint32_t irq_en; - uint32_t capture_rep_data; -}; - -struct msm_camera_cci_ctrl { - int32_t status; - struct msm_camera_cci_client *cci_info; - enum msm_cci_cmd_type cmd; - union { - struct msm_camera_cci_i2c_write_cfg cci_i2c_write_cfg; - struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg; - struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg; - struct msm_camera_cci_gpio_cfg gpio_cfg; - } cfg; -}; - /* this structure is used in kernel */ struct msm_queue_cmd { struct list_head list_config; @@ -362,13 +369,11 @@ struct msm_queue_cmd { struct list_head list_frame; struct list_head list_pict; struct list_head list_vpe_frame; - struct list_head list_eventdata; enum msm_queue type; void *command; atomic_t on_heap; struct timespec ts; uint32_t error_code; - uint32_t trans_code; }; struct msm_device_queue { @@ -380,11 +385,6 @@ struct msm_device_queue { const char *name; }; -struct msm_mctl_stats_t { - struct hlist_head pmem_stats_list; - spinlock_t pmem_stats_spinlock; -}; - struct msm_sync { /* These two queues are accessed from a process context only * They contain pmem descriptors for the preview frames and the stats @@ -419,7 +419,8 @@ struct msm_sync { struct msm_camvpe_fn vpefn; struct msm_sensor_ctrl sctrl; struct msm_strobe_flash_ctrl sfctrl; - struct pm_qos_request idle_pm_qos; + struct msm_actuator_ctrl actctrl; + struct wake_lock wake_lock; struct platform_device *pdev; int16_t ignore_qcmd_type; uint8_t ignore_qcmd; @@ -458,6 +459,8 @@ struct msm_sync { spinlock_t abort_pict_lock; int snap_count; int thumb_count; + + uint32_t focus_state; }; #define MSM_APPS_ID_V4L2 "msm_v4l2" @@ -632,23 +635,36 @@ enum msm_bus_perf_setting { S_STEREO_VIDEO, S_STEREO_CAPTURE, S_DEFAULT, - S_LIVESHOT, - S_DUAL, - S_LOW_POWER, S_EXIT }; +enum msm_cam_mode { + MODE_R, + MODE_L, + MODE_DUAL +}; + +struct msm_cam_clk_info { + const char *clk_name; + long clk_rate; +}; + int msm_camio_enable(struct platform_device *dev); +int msm_camio_jpeg_clk_enable(void); +int msm_camio_jpeg_clk_disable(void); int msm_camio_vpe_clk_enable(uint32_t); int msm_camio_vpe_clk_disable(void); -void msm_camio_mode_config(enum msm_camera_i2c_mux_mode mode); +void msm_camio_mode_config(enum msm_cam_mode mode); int msm_camio_clk_enable(enum msm_camio_clk_type clk); int msm_camio_clk_disable(enum msm_camio_clk_type clk); int msm_camio_clk_config(uint32_t freq); void msm_camio_clk_rate_set(int rate); int msm_camio_vfe_clk_rate_set(int rate); void msm_camio_clk_rate_set_2(struct clk *clk, int rate); +#if defined(CONFIG_S5C73M3) +void msm_camio_clk_set_min_rate(struct clk *clk, int rate); +#endif void msm_camio_clk_axi_rate_set(int rate); void msm_disable_io_gpio_clk(struct platform_device *); @@ -656,8 +672,6 @@ void msm_camio_camif_pad_reg_reset(void); void msm_camio_camif_pad_reg_reset_2(void); void msm_camio_vfe_blk_reset(void); -void msm_camio_vfe_blk_reset_2(void); -void msm_camio_vfe_blk_reset_3(void); int32_t msm_camio_3d_enable(const struct msm_camera_sensor_info *sinfo); void msm_camio_3d_disable(void); @@ -670,16 +684,29 @@ int msm_camio_sensor_clk_on(struct platform_device *); int msm_camio_csi_config(struct msm_camera_csi_params *csi_params); int msm_camio_csiphy_config(struct msm_camera_csiphy_params *csiphy_params); int msm_camio_csid_config(struct msm_camera_csid_params *csid_params); +void msm_io_read_interrupt(void); +#if defined(CONFIG_S5C73M3) +void vfe32_process_ispif_sof_irq(int rdi); +#endif int add_axi_qos(void); int update_axi_qos(uint32_t freq); void release_axi_qos(void); -void msm_camera_io_w(u32 data, void __iomem *addr); -void msm_camera_io_w_mb(u32 data, void __iomem *addr); -u32 msm_camera_io_r(void __iomem *addr); -u32 msm_camera_io_r_mb(void __iomem *addr); -void msm_camera_io_dump(void __iomem *addr, int size); -void msm_camera_io_memcpy(void __iomem *dest_addr, - void __iomem *src_addr, u32 len); + +/* test: Qualcomm */ +#if defined(CONFIG_S5C73M3) +void msm_io_setBits(void __iomem *addr, int offset, int bitmask); +#endif + +void msm_io_w(u32 data, void __iomem *addr); +void msm_io_w_mb(u32 data, void __iomem *addr); +u32 msm_io_r(void __iomem *addr); +u32 msm_io_r_mb(void __iomem *addr); +#if defined(CONFIG_S5C73M3) +void msm_io_dump1(void __iomem *addr, int size); +#endif + +void msm_io_dump(void __iomem *addr, int size); +void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len); void msm_camio_set_perf_lvl(enum msm_bus_perf_setting); void msm_camio_bus_scale_cfg( struct msm_bus_scale_pdata *, enum msm_bus_perf_setting); @@ -693,16 +720,12 @@ int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, int msm_cam_core_reset(void); int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int config); + int num_vreg, struct regulator **reg_ptr, int config); int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int enable); + int num_vreg, struct regulator **reg_ptr, int enable); int msm_camera_config_gpio_table (struct msm_camera_sensor_info *sinfo, int gpio_en); int msm_camera_request_gpio_table (struct msm_camera_sensor_info *sinfo, int gpio_en); -void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, - enum msm_bus_perf_setting perf_setting); #endif diff --git a/arch/arm/mach-msm/include/mach/m2_att-gpio.h b/arch/arm/mach-msm/include/mach/m2_att-gpio.h new file mode 100644 index 00000000000..a1ca3c157ce --- /dev/null +++ b/arch/arm/mach-msm/include/mach/m2_att-gpio.h @@ -0,0 +1,205 @@ +/* + * m2_att-gpio.h + * + * header file supporting gpio functions for Samsung device + * + * COPYRIGHT(C) Samsung Electronics Co., Ltd. 2006-2011 All Right Reserved. + * + * 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. + */ + +/* MSM8960 GPIO */ +#define GPIO_MDP_VSYNC 0 +#define GPIO_MHL_RST 1 +#define GPIO_MSM_FLASH_CNTL_EN 2 +#define GPIO_CAM_MCLK2 2 /* > Rev10 */ +#define GPIO_MSM_FLASH_NOW 3 +#define GPIO_VFE_CAMIF_TIMER3_INT 4 +#define GPIO_CAM_MCLK0 5 +#define CAM_CORE_EN 6 +#define CAM_MIPI_EN 7 +#define GPIO_CODEC_I2C_SDA 8 +#define GPIO_CODEC_I2C_SCL 9 +#define GPIO_LCD_22V_EN 10 +#define GPIO_MXT_TS_IRQ 11 +#ifdef CONFIG_VP_A2220 +#define GPIO_A2220_I2C_SDA 12 +#define GPIO_A2220_I2C_SCL 13 +#endif +#define GPIO_FPGA_CS 14 +#define GPIO_MHL_WAKE_UP 15 +#define GPIO_MAIN_MIC_BIAS 18 +#define GPIO_MHL_EN 19 +#define GPIO_FUELGAUGE_I2C_SDA 24 +#define GPIO_FUEKGAUGE_I2C_SCL 25 + +#define GPIO_BT_UART_TXD 26 +#define GPIO_BT_UART_RXD 27 +#define GPIO_BT_UART_CTS 28 +#define GPIO_BT_UART_RTS 29 + +#define GPIO_NFC_SDA 32 +#define GPIO_NFC_SCL 33 + +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) +#define GPIO_CAM_SPI_MOSI 38 +#define GPIO_CAM_SPI_MISO 39 +#define GPIO_CAM_SPI_SSN 40 +#define GPIO_CAM_SPI_SCLK 41 +#endif + +#define GPIO_SENSOR_SNS_SDA 44 +#define GPIO_SENSOR_SNS_SCL 45 +#define GPIO_CAM_A_EN 46 +#define GPIO_HAPTIC_PWR_EN 47 /* < BOARD_REV08 */ + +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +#define GPIO_TOUCH_KEY_INT 42 +#define GPIO_TOUCHKEY_SCL 47 +#define GPIO_TOUCHKEY_SDA 48 +#endif + +#define GPIO_HOME_KEY 49 /* >= BOARD_REV08 */ + +#define GPIO_MXT_TS_LDO_EN 50 +#define GPIO_CAM_SENSOR_EN 51 +#define GPIO_INOK_INT 52 + +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) +#define GPIO_WL_REG_ON 43 +#define GPIO_WL_HOST_WAKE 54 +#endif + +#define GPIO_SENSOR_ALS_SDA 63 +#define GPIO_SENSOR_ALS_SCL 64 +#define GPIO_FUEL_INT 67 +#define GPIO_MSENSE_RST 68 +#define GPIO_MPU3050_INT 69 +#define GPIO_VIB_PWM 70 + +#ifdef CONFIG_SAMSUNG_CMC624 +#define GPIO_IMA_I2C_SDA 71 +#define GPIO_IMA_I2C_SCL 72 +#endif +#define GPIO_USB_I2C_SDA 73 +#define GPIO_USB_I2C_SCL 74 +#define CAM2_RST_N 76 +#define GPIO_VIB_ON 77 /* < BOARD_REV04 */ + +#define GPIO_KS8851_RST 89 +#define GPIO_KS8851_IRQ 90 + +#define GPIO_NFC_FIRMWARE 92 +#define GPIO_MHL_SDA 95 +#define GPIO_MHL_SCL 96 +#ifdef CONFIG_S5K6A3YX +#define GPIO_VT_CAM_SEN_DET 98 +#endif +#define GPIO_MHL_INT 99 + +#define GPIO_NFC_IRQ 106 +#define ISP_RESET 107 + +/* ES305B GPIO */ +#define MSM_AUD_A2220_WAKEUP 79 +#define MSM_AUD_A2220_RESET 75 + +/* PMIC8921 MPP */ +#define PMIC_MPP_FLASH_LED_UNLOCK 4 + +/* PMIC8921 GPIO */ +#define PMIC_GPIO_VIB_ON 4 +#define PMIC_MSM_FLASH_CNTL_EN 5 +#define PMIC_GPIO_RGB_INT 6 +#define PMIC_GPIO_ECOMPASS_RST 9 +#ifdef CONFIG_SAMSUNG_CMC624 +#define PMIC_GPIO_MLCD_ON 10 +#define PMIC_GPIO_IMA_PWR_EN 11 +#define PMIC_GPIO_IMA_CMC_EN 12 +#define PMIC_GPIO_IMA_nRST 13 +#define PMIC_GPIO_IMA_SLEEP 14 +#endif +#define PMIC_GPIO_SPK_EN 18 +#define PMIC_GPIO_VPS_EN 19 +#define PMIC_GPIO_NFC_EN 21 +#define PMIC_GPIO_OTG_EN -1 +#define PMIC_GPIO_HAPTIC_PWR_EN 22 +#define PMIC_GPIO_CODEC_RST 38 +#define PMIC_GPIO_OTG_POWER 42 +#define PMIC_GPIO_LCD_RST 43 + +#define PMIC_GPIO_CMC_ESD_DET 15 +#define PMIC_GPIO_VGH_ESD_DET 44 + +#if defined(CONFIG_CHARGER_SMB347) +#define PMIC_GPIO_CHG_EN PMIC_GPIO_OTG_EN +#define PMIC_GPIO_CHG_STAT 17 +#endif + +#define PMIC_GPIO_BATT_INT 37 + +/* gpio for changed list */ +enum { + BOARD_REV00, + BOARD_REV01, + BOARD_REV02, + BOARD_REV03, + BOARD_REV04, + BOARD_REV05, + BOARD_REV06, + BOARD_REV07, + BOARD_REV08, + BOARD_REV09, + BOARD_REV10, + BOARD_REV11, + BOARD_REV12, + BOARD_REV13, + BOARD_REV14, + BOARD_REV15, + BOARD_REV16, + BOARD_REV17, + BOARD_REV18, + BOARD_REV19, + BOARD_REV20, + BOARD_REV21, + BOARD_REV22, + BOARD_REV23, + BOARD_REV24, + BOARD_REV25, + GPIO_REV_MAX, +}; + +enum { + MDP_VSYNC, + VOLUME_UP, + VOLUME_DOWN, + GPIO_MAG_RST, + ALS_INT, +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + ALS_SDA, + ALS_SCL, +#endif + LCD_22V_EN, + LINEOUT_EN, + A2220_WAKEUP, + A2220_SDA, + A2220_SCL, + CAM_AF_EN, + CAM_FLASH_SW, + BT_HOST_WAKE, + BT_WAKE, + BT_EN, +}; diff --git a/arch/arm/mach-msm/include/mach/m2_spr-gpio.h b/arch/arm/mach-msm/include/mach/m2_spr-gpio.h new file mode 100644 index 00000000000..0c38993eb13 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/m2_spr-gpio.h @@ -0,0 +1,205 @@ +/* + * m2_spr-gpio.h + * + * header file supporting gpio functions for Samsung device + * + * COPYRIGHT(C) Samsung Electronics Co., Ltd. 2006-2011 All Right Reserved. + * + * 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. + */ + +/* MSM8960 GPIO */ +#define GPIO_MDP_VSYNC 0 +#define GPIO_MHL_RST 1 +#define GPIO_MSM_FLASH_CNTL_EN 2 +#define GPIO_CAM_MCLK2 2 /* > Rev08 */ +#define GPIO_MSM_FLASH_NOW 3 +#define GPIO_VFE_CAMIF_TIMER3_INT 4 +#define GPIO_CAM_MCLK0 5 +#define CAM_CORE_EN 6 +#define CAM_MIPI_EN 7 +#define GPIO_CODEC_I2C_SDA 8 +#define GPIO_CODEC_I2C_SCL 9 +#define GPIO_LCD_22V_EN 10 +#define GPIO_MXT_TS_IRQ 11 +#ifdef CONFIG_VP_A2220 +#define GPIO_A2220_I2C_SDA 12 +#define GPIO_A2220_I2C_SCL 13 +#endif +#define GPIO_FPGA_CS 14 +#define GPIO_MHL_WAKE_UP 15 +#define GPIO_MAIN_MIC_BIAS 18 +#define GPIO_MHL_EN 19 +#define GPIO_FUELGAUGE_I2C_SDA 24 +#define GPIO_FUEKGAUGE_I2C_SCL 25 + +#define GPIO_BT_UART_TXD 26 +#define GPIO_BT_UART_RXD 27 +#define GPIO_BT_UART_CTS 28 +#define GPIO_BT_UART_RTS 29 + +#define GPIO_NFC_SDA 32 +#define GPIO_NFC_SCL 33 + +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) +#define GPIO_CAM_SPI_MOSI 38 +#define GPIO_CAM_SPI_MISO 39 +#define GPIO_CAM_SPI_SSN 40 +#define GPIO_CAM_SPI_SCLK 41 +#endif + +#define GPIO_SENSOR_SNS_SDA 44 +#define GPIO_SENSOR_SNS_SCL 45 +#define GPIO_CAM_A_EN 46 +#define GPIO_HAPTIC_PWR_EN 47 /* < BOARD_REV06 */ + +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +#define GPIO_TOUCH_KEY_INT 42 +#define GPIO_TOUCHKEY_SCL 47 +#define GPIO_TOUCHKEY_SDA 48 +#endif + +#define GPIO_HOME_KEY 49 /* >= BOARD_REV06 */ + +#define GPIO_MXT_TS_LDO_EN 50 +#define GPIO_CAM_SENSOR_EN 51 +#define GPIO_INOK_INT 52 + +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) +#define GPIO_WL_REG_ON 43 +#define GPIO_WL_HOST_WAKE 54 +#endif + +#define GPIO_SENSOR_ALS_SDA 63 +#define GPIO_SENSOR_ALS_SCL 64 +#define GPIO_FUEL_INT 67 +#define GPIO_MSENSE_RST 68 +#define GPIO_MPU3050_INT 69 +#define GPIO_VIB_PWM 70 + +#ifdef CONFIG_SAMSUNG_CMC624 +#define GPIO_IMA_I2C_SDA 71 +#define GPIO_IMA_I2C_SCL 72 +#endif +#define GPIO_USB_I2C_SDA 73 +#define GPIO_USB_I2C_SCL 74 +#define CAM2_RST_N 76 +#define GPIO_VIB_ON 77 /* < BOARD_REV03 */ + +#define GPIO_KS8851_RST 89 +#define GPIO_KS8851_IRQ 90 + +#define GPIO_NFC_FIRMWARE 92 +#define GPIO_MHL_SDA 95 +#define GPIO_MHL_SCL 96 +#ifdef CONFIG_S5K6A3YX +#define GPIO_VT_CAM_SEN_DET 98 +#endif +#define GPIO_MHL_INT 99 + +#define GPIO_NFC_IRQ 106 +#define ISP_RESET 107 + +/* ES305B GPIO */ +#define MSM_AUD_A2220_WAKEUP 79 +#define MSM_AUD_A2220_RESET 75 + +/* PMIC8921 MPP */ +#define PMIC_MPP_FLASH_LED_UNLOCK 4 + +/* PMIC8921 GPIO */ +#define PMIC_GPIO_VIB_ON 4 +#define PMIC_MSM_FLASH_CNTL_EN 5 +#define PMIC_GPIO_RGB_INT 6 +#define PMIC_GPIO_ECOMPASS_RST 9 +#ifdef CONFIG_SAMSUNG_CMC624 +#define PMIC_GPIO_MLCD_ON 10 +#define PMIC_GPIO_IMA_PWR_EN 11 +#define PMIC_GPIO_IMA_CMC_EN 12 +#define PMIC_GPIO_IMA_nRST 13 +#define PMIC_GPIO_IMA_SLEEP 14 +#endif +#define PMIC_GPIO_SPK_EN 18 +#define PMIC_GPIO_VPS_EN 19 +#define PMIC_GPIO_NFC_EN 21 +#define PMIC_GPIO_OTG_EN -1 +#define PMIC_GPIO_HAPTIC_PWR_EN 22 +#define PMIC_GPIO_CODEC_RST 38 +#define PMIC_GPIO_OTG_POWER 42 +#define PMIC_GPIO_LCD_RST 43 + +#define PMIC_GPIO_CMC_ESD_DET 15 +#define PMIC_GPIO_VGH_ESD_DET 44 + +#if defined(CONFIG_CHARGER_SMB347) +#define PMIC_GPIO_CHG_EN PMIC_GPIO_OTG_EN +#define PMIC_GPIO_CHG_STAT 17 +#endif + +#define PMIC_GPIO_BATT_INT 37 + +/* gpio for changed list */ +enum { + BOARD_REV00, + BOARD_REV01, + BOARD_REV02, + BOARD_REV03, + BOARD_REV04, + BOARD_REV05, + BOARD_REV06, + BOARD_REV07, + BOARD_REV08, + BOARD_REV09, + BOARD_REV10, + BOARD_REV11, + BOARD_REV12, + BOARD_REV13, + BOARD_REV14, + BOARD_REV15, + BOARD_REV16, + BOARD_REV17, + BOARD_REV18, + BOARD_REV19, + BOARD_REV20, + BOARD_REV21, + BOARD_REV22, + BOARD_REV23, + BOARD_REV24, + BOARD_REV25, + GPIO_REV_MAX, +}; + +enum { + MDP_VSYNC, + VOLUME_UP, + VOLUME_DOWN, + GPIO_MAG_RST, + ALS_INT, +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + ALS_SDA, + ALS_SCL, +#endif + LCD_22V_EN, + LINEOUT_EN, + A2220_WAKEUP, + A2220_SDA, + A2220_SCL, + CAM_AF_EN, + CAM_FLASH_SW, + BT_HOST_WAKE, + BT_WAKE, + BT_EN, +}; diff --git a/arch/arm/mach-msm/include/mach/m2_vzw-gpio.h b/arch/arm/mach-msm/include/mach/m2_vzw-gpio.h new file mode 100644 index 00000000000..1385a1d9e39 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/m2_vzw-gpio.h @@ -0,0 +1,208 @@ +/* + * m2_vzw-gpio.h + * + * header file supporting gpio functions for Samsung device + * + * COPYRIGHT(C) Samsung Electronics Co., Ltd. 2006-2011 All Right Reserved. + * + * 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. + */ + +/* MSM8960 GPIO */ +#define GPIO_MDP_VSYNC 0 +#define GPIO_MHL_RST 1 +#define GPIO_MSM_FLASH_CNTL_EN 2 +#define GPIO_CAM_MCLK2 2 /* > Rev13 */ +#define GPIO_MSM_FLASH_NOW 3 +#define GPIO_VFE_CAMIF_TIMER3_INT 4 +#define GPIO_CAM_MCLK0 5 +#define CAM_CORE_EN 6 +#define CAM_MIPI_EN 7 +#define GPIO_CODEC_I2C_SDA 8 +#define GPIO_CODEC_I2C_SCL 9 +#define GPIO_LCD_22V_EN 10 +#define GPIO_MXT_TS_IRQ 11 +#ifdef CONFIG_VP_A2220 +#define GPIO_A2220_I2C_SDA 12 +#define GPIO_A2220_I2C_SCL 13 +#endif +#define GPIO_FPGA_CS 14 +#define GPIO_MHL_WAKE_UP 15 + +#define GPIO_MAIN_MIC_BIAS 18 +#define GPIO_MHL_EN 19 +#define GPIO_FUELGAUGE_I2C_SDA 24 +#define GPIO_FUEKGAUGE_I2C_SCL 25 + +#define GPIO_BT_UART_TXD 26 +#define GPIO_BT_UART_RXD 27 +#define GPIO_BT_UART_CTS 28 +#define GPIO_BT_UART_RTS 29 + +#define GPIO_NFC_SDA 32 +#define GPIO_NFC_SCL 33 + +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) +#define GPIO_CAM_SPI_MOSI 38 +#define GPIO_CAM_SPI_MISO 39 +#define GPIO_CAM_SPI_SSN 40 +#define GPIO_CAM_SPI_SCLK 41 +#endif + +#define GPIO_SENSOR_SNS_SDA 44 +#define GPIO_SENSOR_SNS_SCL 45 +#define GPIO_CAM_A_EN 46 +#define GPIO_HAPTIC_PWR_EN 47 /* < BOARD_REV13 */ + +#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH_236 +#define GPIO_TOUCH_KEY_INT 42 +#define GPIO_TOUCHKEY_SCL 47 +#define GPIO_TOUCHKEY_SDA 48 +#endif + +#define GPIO_HOME_KEY 49 /* >= BOARD_REV13 */ + +#define GPIO_MXT_TS_LDO_EN 50 +#define GPIO_CAM_SENSOR_EN 51 +#define GPIO_INOK_INT 52 + +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) +#define GPIO_WL_REG_ON 43 +#define GPIO_WL_HOST_WAKE 54 +#endif + +#define GPIO_SENSOR_ALS_SDA 63 +#define GPIO_SENSOR_ALS_SCL 64 +#define GPIO_FUEL_INT 67 +#define GPIO_MSENSE_RST 68 +#define GPIO_MPU3050_INT 69 +#define GPIO_VIB_PWM 70 + +#ifdef CONFIG_SAMSUNG_CMC624 +#define GPIO_IMA_I2C_SDA 71 +#define GPIO_IMA_I2C_SCL 72 +#endif +#define GPIO_USB_I2C_SDA 73 +#define GPIO_USB_I2C_SCL 74 +#define CAM2_RST_N 76 +#define GPIO_VIB_ON 77 /* < BOARD_REV09 */ + +#define GPIO_KS8851_RST 89 +#define GPIO_KS8851_IRQ 90 + +#define GPIO_NFC_FIRMWARE 92 +#define GPIO_MHL_SDA 95 +#define GPIO_MHL_SCL 96 +#ifdef CONFIG_S5K6A3YX +#define GPIO_VT_CAM_SEN_DET 98 +#endif + +#define GPIO_MHL_INT 99 + +#define GPIO_NFC_IRQ 106 +#define ISP_RESET 107 + +/* ES305B GPIO */ +#define MSM_AUD_A2220_WAKEUP 79 +#define MSM_AUD_A2220_RESET 75 + +/* PMIC8921 MPP */ +#define PMIC_MPP_FLASH_LED_UNLOCK 4 + +/* PMIC8921 GPIO */ +#define PMIC_GPIO_VIB_ON 4 +#define PMIC_MSM_FLASH_CNTL_EN 5 +#define PMIC_GPIO_RGB_INT 6 +#define PMIC_GPIO_ECOMPASS_RST 9 +#ifdef CONFIG_SAMSUNG_CMC624 +#define PMIC_GPIO_MLCD_ON 10 +#define PMIC_GPIO_IMA_PWR_EN 11 +#define PMIC_GPIO_IMA_CMC_EN 12 +#define PMIC_GPIO_IMA_nRST 13 +#define PMIC_GPIO_IMA_SLEEP 14 +#endif +#define PMIC_GPIO_SPK_EN 18 +#define PMIC_GPIO_VPS_EN 19 +#define PMIC_GPIO_NFC_EN 21 +#define PMIC_GPIO_OTG_EN -1 +#define PMIC_GPIO_HAPTIC_PWR_EN 22 +#define PMIC_GPIO_CODEC_RST 38 +#define PMIC_GPIO_OTG_POWER 42 +#define PMIC_GPIO_LCD_RST 43 + +#define PMIC_GPIO_CMC_ESD_DET 15 +#define PMIC_GPIO_VGH_ESD_DET 44 + +#if defined(CONFIG_CHARGER_SMB347) +#define PMIC_GPIO_CHG_EN PMIC_GPIO_OTG_EN +#define PMIC_GPIO_CHG_STAT 17 +#endif +#define PMIC_GPIO_BATT_INT 37 + +/* gpio for changed list */ +enum { + BOARD_REV00, + BOARD_REV01, + BOARD_REV02, + BOARD_REV03, + BOARD_REV04, + BOARD_REV05, + BOARD_REV06, + BOARD_REV07, + BOARD_REV08, + BOARD_REV09, + BOARD_REV10, + BOARD_REV11, + BOARD_REV12, + BOARD_REV13, + BOARD_REV14, + BOARD_REV15, + BOARD_REV16, + BOARD_REV17, + BOARD_REV18, + BOARD_REV19, + BOARD_REV20, + BOARD_REV21, + BOARD_REV22, + BOARD_REV23, + BOARD_REV24, + BOARD_REV25, + GPIO_REV_MAX, +}; + +enum { + MDP_VSYNC, + VOLUME_UP, + VOLUME_DOWN, + MHL_EN, + MHL_SDA, + GPIO_MAG_RST, + ALS_INT, +#if defined(CONFIG_OPTICAL_GP2A) || defined(CONFIG_OPTICAL_GP2AP020A00F) \ + || defined(CONFIG_SENSORS_CM36651) + ALS_SDA, + ALS_SCL, +#endif + LCD_22V_EN, + LINEOUT_EN, + CAM_AF_EN, + CAM_FLASH_SW, + A2220_WAKEUP, + A2220_SDA, + A2220_SCL, + BT_HOST_WAKE, + BT_WAKE, + BT_EN, +}; diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index 83296117c70..2201e4c1e60 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -19,6 +19,9 @@ /* physical offset of RAM */ #define PLAT_PHYS_OFFSET UL(CONFIG_PHYS_OFFSET) +#ifdef CONFIG_HAVE_END_MEM +#define END_MEM UL(CONFIG_END_MEM) +#endif #define MAX_PHYSMEM_BITS 32 #define SECTION_SIZE_BITS 28 diff --git a/arch/arm/mach-msm/include/mach/msm8960-gpio.h b/arch/arm/mach-msm/include/mach/msm8960-gpio.h new file mode 100644 index 00000000000..66405c9a454 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm8960-gpio.h @@ -0,0 +1,71 @@ +/* + * msm8960-gpio.h + * + * header file supporting gpio functions for Samsung device + * + * COPYRIGHT(C) Samsung Electronics Co., Ltd. 2006-2011 All Right Reserved. + * + * 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. + */ + +/* MSM8960 GPIO */ +#if defined(CONFIG_MACH_JAGUAR) +#include +#elif defined(CONFIG_MACH_M2_VZW) +#include +#elif defined(CONFIG_MACH_M2_ATT) +#include +#elif defined(CONFIG_MACH_M2_SPR) +#include +#elif defined(CONFIG_MACH_JASPER) +#include +#elif defined(CONFIG_MACH_APEXQ) +#include +#elif defined(CONFIG_MACH_M2_SKT) +#include +#elif defined(CONFIG_MACH_M2_DCM) +#include +#elif defined(CONFIG_MACH_K2_KDI) +#include +#elif defined(CONFIG_MACH_GOGH) +#include +#elif defined(CONFIG_MACH_INFINITE) +#include +#elif defined(CONFIG_MACH_AEGIS2) +#include +#elif defined(CONFIG_MACH_ESPRESSO_VZW) +#include +#elif defined(CONFIG_MACH_ESPRESSO_SPR) +#include +#elif defined(CONFIG_MACH_ESPRESSO_ATT) +#include +#elif defined(CONFIG_MACH_ESPRESSO10_VZW) +#include +#elif defined(CONFIG_MACH_ESPRESSO10_SPR) +#include +#elif defined(CONFIG_MACH_ESPRESSO10_ATT) +#include +#elif defined(CONFIG_MACH_COMANCHE) +#include +#elif defined(CONFIG_MACH_EXPRESS) +#include +#elif defined(CONFIG_MACH_ACCELERATE) +#include +#elif defined(CONFIG_MACH_STRETTO) +#include +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) +#include + +#endif diff --git a/arch/arm/mach-msm/include/mach/sec_debug.h b/arch/arm/mach-msm/include/mach/sec_debug.h new file mode 100644 index 00000000000..d006e22051d --- /dev/null +++ b/arch/arm/mach-msm/include/mach/sec_debug.h @@ -0,0 +1,530 @@ +/* + * sec_debug.h + * + * header file supporting debug functions for Samsung device + * + * COPYRIGHT(C) Samsung Electronics Co., Ltd. 2006-2011 All Right Reserved. + * + * 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. + */ + + +#ifndef SEC_DEBUG_H +#define SEC_DEBUG_H + +#include +#include + +#ifdef CONFIG_SEC_DEBUG +extern int sec_debug_init(void); +extern int sec_debug_dump_stack(void); +extern void sec_debug_hw_reset(void); +extern void sec_peripheral_secure_check_fail(void); +extern void sec_l1_dcache_check_fail(void); +extern void sec_debug_check_crash_key(unsigned int code, int value); +extern void sec_getlog_supply_fbinfo(void *p_fb, u32 res_x, u32 res_y, u32 bpp, + u32 frames); +extern void sec_getlog_supply_meminfo(u32 size0, u32 addr0, u32 size1, + u32 addr1); +extern void sec_getlog_supply_loggerinfo(void *p_main, void *p_radio, + void *p_events, void *p_system); +extern void sec_getlog_supply_kloginfo(void *klog_buf); + +extern void sec_gaf_supply_rqinfo(unsigned short curr_offset, + unsigned short rq_offset); +extern int sec_debug_is_enabled(void); +extern int sec_debug_is_enabled_for_ssr(void); +#else +static inline int sec_debug_init(void) +{ + return 0; +} +static inline int sec_debug_dump_stack(void) { + return 0; +} +static inline void sec_debug_check_crash_key(unsigned int code, int value) {} + +static inline void sec_getlog_supply_fbinfo(void *p_fb, u32 res_x, u32 res_y, + u32 bpp, u32 frames) +{ +} + +static inline void sec_getlog_supply_meminfo(u32 size0, u32 addr0, u32 size1, + u32 addr1) +{ +} + +static inline void sec_getlog_supply_loggerinfo(void *p_main, + void *p_radio, void *p_events, + void *p_system) +{ +} + +static inline void sec_getlog_supply_kloginfo(void *klog_buf) +{ +} + +static inline void sec_gaf_supply_rqinfo(unsigned short curr_offset, + unsigned short rq_offset) +{ +} + +static inline int sec_debug_is_enabled(void) {return 0; } +#endif + +#ifdef CONFIG_SEC_DEBUG_SCHED_LOG +extern void sec_debug_task_sched_log_short_msg(char *msg); +extern void sec_debug_task_sched_log(int cpu, struct task_struct *task); +extern void sec_debug_irq_sched_log(unsigned int irq, void *fn, int en); +extern void sec_debug_irq_sched_log_end(void); +extern void sec_debug_timer_log(unsigned int type, int int_lock, void *fn); +extern void sec_debug_sched_log_init(void); +#define secdbg_sched_msg(fmt, ...) \ + do { \ + char ___buf[16]; \ + snprintf(___buf, sizeof(___buf), fmt, ##__VA_ARGS__); \ + sec_debug_task_sched_log_short_msg(___buf); \ + } while (0) +#else +static inline void sec_debug_task_sched_log(int cpu, struct task_struct *task) +{ +} +static inline void sec_debug_irq_sched_log(unsigned int irq, void *fn, int en) +{ +} +static inline void sec_debug_irq_sched_log_end(void) +{ +} +static inline void sec_debug_timer_log(unsigned int type, + int int_lock, void *fn) +{ +} +static inline void sec_debug_sched_log_init(void) +{ +} +#define secdbg_sched_msg(fmt, ...) +#endif +#ifdef CONFIG_SEC_DEBUG_IRQ_EXIT_LOG +extern void sec_debug_irq_enterexit_log(unsigned int irq, + unsigned long long start_time); +#else +static inline void sec_debug_irq_enterexit_log(unsigned int irq, + unsigned long long start_time) +{ +} +#endif + +#ifdef CONFIG_SEC_DEBUG_SEMAPHORE_LOG +extern void debug_semaphore_init(void); +extern void debug_semaphore_down_log(struct semaphore *sem); +extern void debug_semaphore_up_log(struct semaphore *sem); +extern void debug_rwsemaphore_init(void); +extern void debug_rwsemaphore_down_log(struct rw_semaphore *sem, int dir); +extern void debug_rwsemaphore_up_log(struct rw_semaphore *sem); +#define debug_rwsemaphore_down_read_log(x) \ + debug_rwsemaphore_down_log(x, READ_SEM) +#define debug_rwsemaphore_down_write_log(x) \ + debug_rwsemaphore_down_log(x, WRITE_SEM) +#else +static inline void debug_semaphore_init(void) +{ +} +static inline void debug_semaphore_down_log(struct semaphore *sem) +{ +} +static inline void debug_semaphore_up_log(struct semaphore *sem) +{ +} +static inline void debug_rwsemaphore_init(void) +{ +} +static inline void debug_rwsemaphore_down_read_log(struct rw_semaphore *sem) +{ +} +static inline void debug_rwsemaphore_down_write_log(struct rw_semaphore *sem) +{ +} +static inline void debug_rwsemaphore_up_log(struct rw_semaphore *sem) +{ +} +#endif + +/* klaatu - schedule log */ +#ifdef CONFIG_SEC_DEBUG_SCHED_LOG +#define SCHED_LOG_MAX 1024 + +struct irq_log { + unsigned long long time; + int irq; + void *fn; + int en; + int preempt_count; + void *context; +}; + +struct irq_exit_log { + unsigned int irq; + unsigned long long time; + unsigned long long end_time; + unsigned long long elapsed_time; +}; + +struct sched_log { + unsigned long long time; + char comm[TASK_COMM_LEN]; + pid_t pid; +}; + + +struct timer_log { + unsigned long long time; + unsigned int type; + int int_lock; + void *fn; +}; +#endif /* CONFIG_SEC_DEBUG_SCHED_LOG */ + +#ifdef CONFIG_SEC_DEBUG_SEMAPHORE_LOG +#define SEMAPHORE_LOG_MAX 100 +struct sem_debug { + struct list_head list; + struct semaphore *sem; + struct task_struct *task; + pid_t pid; + int cpu; + /* char comm[TASK_COMM_LEN]; */ +}; + +enum { + READ_SEM, + WRITE_SEM +}; + +#define RWSEMAPHORE_LOG_MAX 100 +struct rwsem_debug { + struct list_head list; + struct rw_semaphore *sem; + struct task_struct *task; + pid_t pid; + int cpu; + int direction; + /* char comm[TASK_COMM_LEN]; */ +}; + +#endif /* CONFIG_SEC_DEBUG_SEMAPHORE_LOG */ + +#ifdef CONFIG_SEC_DEBUG_MSG_LOG +#define MSG_LOG_MAX 1024 +struct secmsg_log { + unsigned long long time; + char msg[64]; + void *caller0; + void *caller1; + char *task; +}; +#define secdbg_msg(fmt, ...) \ + sec_debug_msg_log(__builtin_return_address(0), fmt, ##__VA_ARGS__) +#else +#define secdbg_msg(fmt, ...) +#endif + +#ifdef CONFIG_SEC_DEBUG_DCVS_LOG +#define DCVS_LOG_MAX 256 + +struct dcvs_debug { + unsigned long long time; + int cpu_no; + unsigned int prev_freq; + unsigned int new_freq; +}; +extern void sec_debug_dcvs_log(int cpu_no, unsigned int prev_freq, + unsigned int new_freq); +#else +static inline void sec_debug_dcvs_log(int cpu_no, unsigned int prev_freq, + unsigned int new_freq) +{ +} + +#endif + +#ifdef CONFIG_SEC_DEBUG_FUELGAUGE_LOG +#define FG_LOG_MAX 128 + +struct fuelgauge_debug { + unsigned long long time; + unsigned int voltage; + unsigned short soc; + unsigned short charging_status; +}; +extern void sec_debug_fuelgauge_log(unsigned int voltage, unsigned short soc, + unsigned short charging_status); +#else +static inline void sec_debug_fuelgauge_log(unsigned int voltage, + unsigned short soc, unsigned short charging_status) +{ +} + +#endif + +/* for sec debug level */ +#define KERNEL_SEC_DEBUG_LEVEL_LOW (0x574F4C44) +#define KERNEL_SEC_DEBUG_LEVEL_MID (0x44494D44) +#define KERNEL_SEC_DEBUG_LEVEL_HIGH (0x47494844) +extern bool kernel_sec_set_debug_level(int level); +extern int kernel_sec_get_debug_level(void); +extern int ssr_panic_handler_for_sec_dbg(void); +__weak void dump_all_task_info(void); +__weak void dump_cpu_stat(void); +extern void emerg_pet_watchdog(void); + +#define LOCAL_CONFIG_PRINT_EXTRA_INFO + +/* #define CONFIG_SEC_DEBUG_SUBSYS */ +#ifdef CONFIG_SEC_DEBUG_SUBSYS + +extern void sec_debug_subsys_fill_fbinfo(int idx, void *fb, u32 xres, + u32 yres, u32 bpp, u32 color_mode); + +#define SEC_DEBUG_SUBSYS_MAGIC0 0xFFFFFFFF +#define SEC_DEBUG_SUBSYS_MAGIC1 0x5ECDEB6 +#define SEC_DEBUG_SUBSYS_MAGIC2 0x14F014F0 + /* high word : major version + * low word : minor version + * minor version changes should not affect LK behavior + */ +#define SEC_DEBUG_SUBSYS_MAGIC3 0x00010003 + + +#define TZBSP_CPU_COUNT 2 +/* CPU context for the monitor. */ +struct tzbsp_dump_cpu_ctx_s { + unsigned int mon_lr; + unsigned int mon_spsr; + unsigned int usr_r0; + unsigned int usr_r1; + unsigned int usr_r2; + unsigned int usr_r3; + unsigned int usr_r4; + unsigned int usr_r5; + unsigned int usr_r6; + unsigned int usr_r7; + unsigned int usr_r8; + unsigned int usr_r9; + unsigned int usr_r10; + unsigned int usr_r11; + unsigned int usr_r12; + unsigned int usr_r13; + unsigned int usr_r14; + unsigned int irq_spsr; + unsigned int irq_r13; + unsigned int irq_r14; + unsigned int svc_spsr; + unsigned int svc_r13; + unsigned int svc_r14; + unsigned int abt_spsr; + unsigned int abt_r13; + unsigned int abt_r14; + unsigned int und_spsr; + unsigned int und_r13; + unsigned int und_r14; + unsigned int fiq_spsr; + unsigned int fiq_r8; + unsigned int fiq_r9; + unsigned int fiq_r10; + unsigned int fiq_r11; + unsigned int fiq_r12; + unsigned int fiq_r13; + unsigned int fiq_r14; +}; + +struct tzbsp_dump_buf_s { + unsigned int sc_status[TZBSP_CPU_COUNT]; + struct tzbsp_dump_cpu_ctx_s sc_ns[TZBSP_CPU_COUNT]; + struct tzbsp_dump_cpu_ctx_s sec; +}; + +struct core_reg_info { + char name[12]; + unsigned int value; +}; + +struct sec_debug_subsys_excp { + char type[16]; + char task[16]; + char file[32]; + int line; + char msg[256]; + struct core_reg_info core_reg[64]; +}; + +struct sec_debug_subsys_excp_krait { + char pc_sym[64]; + char lr_sym[64]; + char panic_caller[64]; + char panic_msg[128]; + char thread[32]; +}; + +struct sec_debug_subsys_log { + unsigned int idx_paddr; + unsigned int log_paddr; + unsigned int size; +}; + +struct rgb_bit_info { + unsigned char r_off; + unsigned char r_len; + unsigned char g_off; + unsigned char g_len; + unsigned char b_off; + unsigned char b_len; + unsigned char a_off; + unsigned char a_len; +}; + +struct var_info { + char name[16]; + int sizeof_type; + unsigned int var_paddr; +}; +struct sec_debug_subsys_simple_var_mon { + int idx; + struct var_info var[32]; +}; + +struct sec_debug_subsys_fb { + unsigned int fb_paddr; + int xres; + int yres; + int bpp; + struct rgb_bit_info rgb_bitinfo; +}; + +struct sec_debug_subsys_sched_log { + unsigned int sched_idx_paddr; + unsigned int sched_buf_paddr; + unsigned int sched_struct_sz; + unsigned int sched_array_cnt; + unsigned int irq_idx_paddr; + unsigned int irq_buf_paddr; + unsigned int irq_struct_sz; + unsigned int irq_array_cnt; + unsigned int irq_exit_idx_paddr; + unsigned int irq_exit_buf_paddr; + unsigned int irq_exit_struct_sz; + unsigned int irq_exit_array_cnt; +}; + + +struct __log_struct_info { + unsigned int buffer_offset; + unsigned int w_off_offset; + unsigned int head_offset; + unsigned int size_offset; + unsigned int size_t_typesize; +}; + +struct __log_data { + unsigned int log_paddr; + unsigned int buffer_paddr; +}; + +struct sec_debug_subsys_logger_log_info { + struct __log_struct_info stinfo; + struct __log_data main; + struct __log_data system; + struct __log_data events; + struct __log_data radio; +}; + + +struct sec_debug_subsys_data { + char name[16]; + char state[16]; + struct sec_debug_subsys_log log; + struct sec_debug_subsys_excp excp; + struct sec_debug_subsys_simple_var_mon var_mon; +}; + +struct sec_debug_subsys_data_modem { + char name[16]; + char state[16]; + struct sec_debug_subsys_log log; + struct sec_debug_subsys_excp excp; + struct sec_debug_subsys_simple_var_mon var_mon; +}; + +struct sec_debug_subsys_data_krait { + char name[16]; + char state[16]; + int nr_cpus; + struct sec_debug_subsys_log log; + struct sec_debug_subsys_excp_krait excp; + struct sec_debug_subsys_simple_var_mon var_mon; + struct tzbsp_dump_buf_s **tz_core_dump; + struct sec_debug_subsys_fb fb_info; + struct sec_debug_subsys_sched_log sched_log; + struct sec_debug_subsys_logger_log_info logger_log; +}; + +struct sec_debug_subsys_private { + struct sec_debug_subsys_data_krait krait; + struct sec_debug_subsys_data rpm; + struct sec_debug_subsys_data_modem modem; + struct sec_debug_subsys_data dsps; +}; + +struct sec_debug_subsys { + unsigned int magic[4]; + struct sec_debug_subsys_data_krait *krait; + struct sec_debug_subsys_data *rpm; + struct sec_debug_subsys_data_modem *modem; + struct sec_debug_subsys_data *dsps; + + struct sec_debug_subsys_private priv; +}; + +extern void print_modem_dump_info(void); +extern int sec_debug_subsys_add_var_mon(char *name, unsigned int size, + unsigned int addr); +#define SEC_DEBUG_SUBSYS_ADD_VAR_TO_MONITOR(var) \ + sec_debug_subsys_add_var_mon(#var, sizeof(var), \ + (unsigned int)__pa(&var)) +#define SEC_DEBUG_SUBSYS_ADD_STR_TO_MONITOR(pstr) \ + sec_debug_subsys_add_var_mon(#pstr, -1, (unsigned int)__pa(pstr)) + +extern int get_fbinfo(int fb_num, unsigned int *fb_paddr, unsigned int *xres, + unsigned int *yres, unsigned int *bpp, + unsigned char *roff, unsigned char *rlen, + unsigned char *goff, unsigned char *glen, + unsigned char *boff, unsigned char *blen, + unsigned char *aoff, unsigned char *alen); +extern unsigned int msm_shared_ram_phys; +extern char *get_kernel_log_buf_paddr(void); +extern char *get_fb_paddr(void); +extern unsigned int get_wdog_regsave_paddr(void); + +extern unsigned int get_last_pet_paddr(void); +extern void sec_debug_subsys_set_kloginfo(unsigned int *idx_paddr, + unsigned int *log_paddr, unsigned int *size); +extern int sec_debug_subsys_set_logger_info( + struct sec_debug_subsys_logger_log_info *log_info); +int sec_debug_save_die_info(const char *str, struct pt_regs *regs); +int sec_debug_save_panic_info(const char *str, unsigned int caller); +extern void sec_debug_set_qc_dload_magic(int on); +extern uint32_t global_pvs; +#endif + +#endif /* SEC_DEBUG_H */ diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c index 6f58dd127af..d16ee4e73c4 100644 --- a/arch/arm/mach-msm/ipc_socket.c +++ b/arch/arm/mach-msm/ipc_socket.c @@ -190,10 +190,12 @@ static int msm_ipc_router_create(struct net *net, struct msm_ipc_port *port_ptr; void *pil; +#if 0 if (!check_permissions()) { pr_err("%s: Do not have permissions\n", __func__); return -EPERM; } +#endif if (unlikely(protocol != 0)) { pr_err("%s: Protocol not supported\n", __func__); diff --git a/arch/arm/mach-msm/mpm.h b/arch/arm/mach-msm/mpm.h new file mode 100644 index 00000000000..88e369c8174 --- /dev/null +++ b/arch/arm/mach-msm/mpm.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_MPM_H +#define __ARCH_ARM_MACH_MSM_MPM_H + +#include +#include + +enum msm_mpm_pin { + MSM_MPM_PIN_SDC3_DAT1 = 21, + MSM_MPM_PIN_SDC3_DAT3 = 22, + MSM_MPM_PIN_SDC4_DAT1 = 23, + MSM_MPM_PIN_SDC4_DAT3 = 24, +}; + +#define MSM_MPM_NR_MPM_IRQS 64 + +struct msm_mpm_device_data { + uint16_t *irqs_m2a; + unsigned int irqs_m2a_size; + uint16_t *bypassed_apps_irqs; + unsigned int bypassed_apps_irqs_size; + void __iomem *mpm_request_reg_base; + void __iomem *mpm_status_reg_base; + void __iomem *mpm_apps_ipc_reg; + unsigned int mpm_apps_ipc_val; + unsigned int mpm_ipc_irq; +}; + +#ifdef CONFIG_MSM_MPM +extern struct msm_mpm_device_data msm_mpm_dev_data; + +int msm_mpm_enable_pin(enum msm_mpm_pin pin, unsigned int enable); +int msm_mpm_set_pin_wake(enum msm_mpm_pin pin, unsigned int on); +int msm_mpm_set_pin_type(enum msm_mpm_pin pin, unsigned int flow_type); +bool msm_mpm_irqs_detectable(bool from_idle); +bool msm_mpm_gpio_irqs_detectable(bool from_idle); +void msm_mpm_enter_sleep(bool from_idle); +void msm_mpm_exit_sleep(bool from_idle); +void msm_mpm_irq_extn_init(void); +#else + +int msm_mpm_enable_irq(unsigned int irq, unsigned int enable) +{ return -ENODEV; } +int msm_mpm_set_irq_wake(unsigned int irq, unsigned int on) +{ return -ENODEV; } +int msm_mpm_set_irq_type(unsigned int irq, unsigned int flow_type) +{ return -ENODEV; } +int msm_mpm_enable_pin(enum msm_mpm_pin pin, unsigned int enable) +{ return -ENODEV; } +int msm_mpm_set_pin_wake(enum msm_mpm_pin pin, unsigned int on) +{ return -ENODEV; } +int msm_mpm_set_pin_type(enum msm_mpm_pin pin, unsigned int flow_type) +{ return -ENODEV; } +bool msm_mpm_irqs_detectable(bool from_idle) +{ return false; } +bool msm_mpm_gpio_irqs_detectable(bool from_idle) +{ return false; } +void msm_mpm_enter_sleep(bool from_idle) {} +void msm_mpm_exit_sleep(bool from_idle) {} +void msm_mpm_irq_extn_init(void) {} +#endif + + + +#endif /* __ARCH_ARM_MACH_MSM_MPM_H */ diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c index e5616b90b10..85dd7e404b2 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c @@ -459,6 +459,7 @@ uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata) int src, dest, nfab; struct msm_bus_fabric_device *deffab; + pr_err("%s: name: %s ", __func__, pdata->name); deffab = msm_bus_get_fabric_device(MSM_BUS_FAB_DEFAULT); if (!deffab) { MSM_BUS_ERR("Error finding default fabric\n"); diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c index b1c8b3010c7..3c40bec82b4 100644 --- a/arch/arm/mach-msm/msm_watchdog.c +++ b/arch/arm/mach-msm/msm_watchdog.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c index 7daf77d65f4..1daff1962a6 100644 --- a/arch/arm/mach-msm/restart.c +++ b/arch/arm/mach-msm/restart.c @@ -35,6 +35,10 @@ #include "msm_watchdog.h" #include "timer.h" +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#endif + #define WDT0_RST 0x38 #define WDT0_EN 0x40 #define WDT0_BARK_TIME 0x4C @@ -322,6 +326,18 @@ static int __init msm_pmic_restart_init(void) late_initcall(msm_pmic_restart_init); +#ifdef CONFIG_KEXEC_HARDBOOT +void msm_kexec_hardboot(void) +{ + /* Set PM8XXX PMIC to reset on power off. */ + pm8xxx_reset_pwr_off(1); + + /* Reboot with the recovery kernel since the boot kernel decompressor may + * not support the hardboot jump. */ + __raw_writel(0x77665502, restart_reason); +} +#endif + static int __init msm_restart_init(void) { #ifdef CONFIG_MSM_DLOAD_MODE @@ -336,6 +352,9 @@ static int __init msm_restart_init(void) msm_tmr0_base = msm_timer_get_timer0_base(); restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR; pm_power_off = msm_power_off; +#ifdef CONFIG_KEXEC_HARDBOOT + kexec_hardboot_hook = msm_kexec_hardboot; +#endif return 0; } diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 19ef5a61a41..521377acbda 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -178,7 +178,7 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, trace_user_fault(tsk, addr, fsr); -#ifdef CONFIG_DEBUG_USER +#if 0 /*CONFIG_DEBUG_USER*/ if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) || ((user_debug & UDBG_BUS) && (sig == SIGBUS))) { printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n", diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index a11842a0713..77a026e5b38 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -706,6 +706,29 @@ geneva_b5 MACH_GENEVA_B5 GENEVA_B5 3393 spear1340 MACH_SPEAR1340 SPEAR1340 3394 rexmas MACH_REXMAS REXMAS 3395 msm8960_cdp MACH_MSM8960_CDP MSM8960_CDP 3396 +M2_SPR MACH_M2_SPR M2_SPR 3396 +t_project MACH_T_PROJECT T_PROJECT 3396 +jaguar MACH_JAGUAR JAGUAR 3396 +kenos MACH_KENOS KENOS 3396 +M2_VZW MACH_M2_VZW M2_VZW 3396 +M2_ATT MACH_M2_ATT M2_ATT 3396 +M2_SKT MACH_M2_SKT M2_SKT 3396 +M2_DCM MACH_M2_DCM M2_DCM 3396 +K2_KDI MACH_K2_KDI K2_KDI 3396 +AEGIS2 MACH_AEGIS2 AEGIS2 3396 +ACCELERATE MACH_ACCELERATE ACCELERATE 3396 +COMANCHE MACH_COMANCHE COMANCHE 3396 +EXPRESS MACH_EXPRESS EXPRESS 3396 +JASPER MACH_JASPER JASPER 3396 +GOGH MACH_GOGH GOGH 3396 +INFINITE MACH_INFINITE INFINITE 3396 +APEXQ MACH_APEXQ APEXQ 3396 +ESPRESSO_VZW MACH_ESPRESSO_VZW ESPRESSO_VZW 3396 +ESPRESSO_SPR MACH_ESPRESSO_SPR ESPRESSO_SPR 3396 +ESPRESSO_ATT MACH_ESPRESSO_ATT ESPRESSO_ATT 3396 +ESPRESSO10_VZW MACH_ESPRESSO10_VZW ESPRESSO10_VZW 3396 +ESPRESSO10_SPR MACH_ESPRESSO10_SPR ESPRESSO10_SPR 3396 +ESPRESSO10_ATT MACH_ESPRESSO10_ATT ESPRESSO10_ATT 3396 msm8960_mtp MACH_MSM8960_MTP MSM8960_MTP 3397 msm8960_fluid MACH_MSM8960_FLUID MSM8960_FLUID 3398 msm8960_apq MACH_MSM8960_APQ MSM8960_APQ 3399 diff --git a/drivers/Kconfig b/drivers/Kconfig index a73d713f7df..fdaccc1d6ea 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -104,6 +104,8 @@ source "drivers/switch/Kconfig" source "drivers/accessibility/Kconfig" +source "drivers/accessory/Kconfig" + source "drivers/infiniband/Kconfig" source "drivers/edac/Kconfig" @@ -132,6 +134,12 @@ source "drivers/platform/Kconfig" source "drivers/clk/Kconfig" +source "drivers/sensors/Kconfig" + +source "drivers/battery/Kconfig" + +source "drivers/motor/Kconfig" + source "drivers/hwspinlock/Kconfig" source "drivers/clocksource/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index f461e83259d..c60857a1490 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -92,6 +92,7 @@ obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_ACCESSIBILITY) += accessibility/ +obj-$(CONFIG_ACCESSORY) += accessory/ obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_EDAC) += edac/ obj-$(CONFIG_MCA) += mca/ @@ -125,7 +126,9 @@ obj-y += platform/ obj-y += ieee802154/ #common clk code obj-y += clk/ - +obj-$(CONFIG_NEW_SENSORS) += sensors/ +obj-$(CONFIG_BATTERY_SAMSUNG) += battery/ +obj-$(CONFIG_VIBETONZ) += motor/ obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ obj-$(CONFIG_NFC) += nfc/ obj-$(CONFIG_IOMMU_SUPPORT) += iommu/ diff --git a/drivers/accessory/Kconfig b/drivers/accessory/Kconfig new file mode 100644 index 00000000000..c3e2ef7d7d4 --- /dev/null +++ b/drivers/accessory/Kconfig @@ -0,0 +1,26 @@ +# +# Accessory Configuration +# +source "drivers/accessory/mhl_tab_v2/Kconfig" + +menuconfig ACCESSORY + bool "Accessory devices" + default n + ---help--- + Provides support for detecting Accessory such as TA, Keyboard, OTG + + Say Y here to get to see options for Samsung Accessories + If you say N, all options in this submenu will be skipped and disabled. + +if ACCESSORY + +config 30PIN_CONN + tristate "Accessory detection driver" + +config SEC_KEYBOARD_DOCK + tristate "sec keyboard dock support" + +config CAMERON_HEALTH + bool "Cameron Health device support" + default n +endif # ACCESSORY diff --git a/drivers/accessory/Makefile b/drivers/accessory/Makefile new file mode 100644 index 00000000000..f0027946e22 --- /dev/null +++ b/drivers/accessory/Makefile @@ -0,0 +1,7 @@ +# +# makefile for accessory +# + +obj-$(CONFIG_30PIN_CONN) += sec_tablet_conn.o +obj-$(CONFIG_SEC_KEYBOARD_DOCK) += sec_keyboard.o +obj-$(CONFIG_VIDEO_MHL_TAB_V2) += mhl_tab_v2/ diff --git a/drivers/accessory/mhl_tab_v2/Kconfig b/drivers/accessory/mhl_tab_v2/Kconfig new file mode 100644 index 00000000000..4299afc25e1 --- /dev/null +++ b/drivers/accessory/mhl_tab_v2/Kconfig @@ -0,0 +1,23 @@ +# +# Copyright (c) 2012 SAMSUNG INDIA SOFTWARE OPERATIONS +# +# Manoj Prabhu B +# prabhu.manoj@samsung.com + + +config VIDEO_MHL_TAB_V2 + bool "Samsung Mobile HD Link Interface" + depends on MSM_VIDC && ARCH_MSM + default n + +config MHL_D3_SUPPORT + bool "Support D3 mode in mhl" + default n + +config MHL_NEW_CBUS_MSC_CMD + bool "Read DCAP for distinguish TA and USB" + default n + +config MHL_SWING_LEVEL + bool "Tune mhl drive strength" + default n diff --git a/drivers/accessory/mhl_tab_v2/Makefile b/drivers/accessory/mhl_tab_v2/Makefile new file mode 100644 index 00000000000..82d85e497b8 --- /dev/null +++ b/drivers/accessory/mhl_tab_v2/Makefile @@ -0,0 +1,10 @@ +# drivers/video/msm/mhl_v2/Makefile +# +# Copyright (c) 2012 SAMSUNG INDIA SOFTWARE OPERATIONS +# http://www.samsung.com/ +# Manoj Prabhu B +# prabhu.manoj@samsung.com + + + +obj-$(CONFIG_VIDEO_MHL_TAB_V2) += sii9234.o \ diff --git a/drivers/accessory/mhl_tab_v2/sii9234.c b/drivers/accessory/mhl_tab_v2/sii9234.c new file mode 100644 index 00000000000..3f915dcf980 --- /dev/null +++ b/drivers/accessory/mhl_tab_v2/sii9234.c @@ -0,0 +1,872 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * + * Authors: Adam Hampson + * Erik Gilling + * + * Additional contributions by : Shankar Bandal + * Dharam Kumar + * + * 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 "sii9234_driver.h" + +#ifdef CONFIG_MHL_SWING_LEVEL +#include + +static ssize_t sii9234_swing_test_show(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + return sprintf(buf, "mhl_show_value : 0x%x\n", + sii9234->pdata->swing_level); + +} +static ssize_t sii9234_swing_test_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + char temp[4] = { 0, }; + const char *p = buf; + int data, clk; + unsigned int value; + + while (*p != '\0') { + if (!isspace(*p)) + strncat(temp, p, 1); + p++; + } + + if (strlen(temp) != 2) + return -EINVAL; + + kstrtoul(temp, 10, &value); + data = value / 10; + clk = value % 10; + sii9234->pdata->swing_level = 0xc0; + sii9234->pdata->swing_level = sii9234->pdata->swing_level + | (data << 3) | clk; + sprintf(buf, "mhl_store_value : 0x%x\n", sii9234->pdata->swing_level); + return size; +} + +static CLASS_ATTR(swing, 0664, + sii9234_swing_test_show, sii9234_swing_test_store); +#endif /*CONFIG_MHL_SWING_LEVEL*/ +static int mhl_tx_write_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 value) +{ + int ret; + ret = i2c_smbus_write_byte_data(sii9234->pdata->mhl_tx_client, offset, + value); + if (ret < 0) + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, value); + return ret; +} + +static int mhl_tx_read_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 *value) +{ + int ret; + + if (!value) + return -EINVAL; + + ret = i2c_smbus_write_byte(sii9234->pdata->mhl_tx_client, offset); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + + ret = i2c_smbus_read_byte(sii9234->pdata->mhl_tx_client); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + + *value = ret & 0x000000FF; + + return 0; +} + + +static int mhl_tx_clear_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 mask) +{ + int ret; + u8 value; + + ret = mhl_tx_read_reg(sii9234, offset, &value); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, mask); + return ret; + } + + value &= ~mask; + + ret = mhl_tx_write_reg(sii9234, offset, value); + if (ret < 0) + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, mask); + return ret; +} + +static int tpi_write_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 value) +{ + int ret = 0; + ret = i2c_smbus_write_byte_data(sii9234->pdata->tpi_client, offset, + value); + if (ret < 0) + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, value); + return ret; +} + + +static int hdmi_rx_write_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 value) +{ + int ret; + ret = i2c_smbus_write_byte_data(sii9234->pdata->hdmi_rx_client, offset, + value); + if (ret < 0) + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, value); + return ret; +} + +static int cbus_write_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 value) +{ + return i2c_smbus_write_byte_data(sii9234->pdata->cbus_client, offset, + value); +} + +static int cbus_read_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 *value) +{ + int ret; + + if (!value) + return -EINVAL; + + ret = i2c_smbus_write_byte(sii9234->pdata->cbus_client, offset); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + + ret = i2c_smbus_read_byte(sii9234->pdata->cbus_client); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + + *value = ret & 0x000000FF; + + return 0; +} + + + + +static void sii9234_power_down(struct sii9234_data *sii9234) +{ + if (sii9234->pdata->vbus_present) + sii9234->pdata->vbus_present(false); + + tpi_write_reg(sii9234, TPI_DPD_REG, 0); + /*turn on&off hpd festure for only QCT HDMI*/ +} + + + +static int sii9234_cbus_init_for_9290(struct sii9234_data *sii9234) +{ + int ret = 0; + + ret = cbus_write_reg(sii9234, 0x1F, 0x02); + if (ret < 0) + return ret; + ret = cbus_write_reg(sii9234, 0x07, 0x30 | 0x06); + if (ret < 0) + return ret; + ret = cbus_write_reg(sii9234, 0x40, 0x03); + if (ret < 0) + return ret; + ret = cbus_write_reg(sii9234, 0x42, 0x06); + if (ret < 0) + return ret; + ret = cbus_write_reg(sii9234, 0x36, 0x0C); + if (ret < 0) + return ret; + ret = cbus_write_reg(sii9234, 0x3D, 0xFD); + if (ret < 0) + return ret; + ret = cbus_write_reg(sii9234, 0x1C, 0x00); + if (ret < 0) + return ret; + ret = cbus_write_reg(sii9234, 0x44, 0x00); + + return ret; +} + + +static int sii9234_30pin_reg_init_for_9290(struct sii9234_data *sii9234) +{ + int ret = 0; + u8 value; + pr_info("[: %s]++\n", __func__); + ret = tpi_write_reg(sii9234, 0x3D, 0x3F); + if (ret < 0) + return ret; + + ret = hdmi_rx_write_reg(sii9234, 0x11, 0x01); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x12, 0x15); + if (ret < 0) + return ret; + ret = mhl_tx_write_reg(sii9234, 0x08, 0x35); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x00, 0x00); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x13, 0x60); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x14, 0xF0); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x4B, 0x06); + if (ret < 0) + return ret; + + /* Analog PLL Control */ + ret = hdmi_rx_write_reg(sii9234, 0x17, 0x07); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x1A, 0x20); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x22, 0xE0); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x23, 0xC0); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x24, 0xA0); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x25, 0x80); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x26, 0x60); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x27, 0x40); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x28, 0x20); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x29, 0x00); + if (ret < 0) + return ret; + + ret = hdmi_rx_write_reg(sii9234, 0x4D, 0x02); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x4C, 0xA0); + if (ret < 0) + return ret; + + ret = mhl_tx_write_reg(sii9234, 0x80, 0x34); + if (ret < 0) + return ret; + + ret = hdmi_rx_write_reg(sii9234, 0x31, 0x0B); + if (ret < 0) + return ret; + ret = hdmi_rx_write_reg(sii9234, 0x45, 0x06); + if (ret < 0) + return ret; + ret = mhl_tx_write_reg(sii9234, 0xA0, 0xD0); + if (ret < 0) + return ret; + ret = mhl_tx_write_reg(sii9234, 0xA1, 0xFC); + if (ret < 0) + return ret; + + ret = mhl_tx_write_reg(sii9234, 0xA3 /*MHL_TX_MHLTX_CTL4_REG*/, + sii9234->pdata->swing_level); + if (ret < 0) + return ret; + ret = mhl_tx_write_reg(sii9234, 0xA6, 0x00); + if (ret < 0) + return ret; + + ret = mhl_tx_write_reg(sii9234, 0x2B, 0x01); + if (ret < 0) + return ret; + + /* CBUS & Discovery */ + ret = mhl_tx_read_reg(sii9234, 0x90/*MHL_TX_DISC_CTRL1_REG*/, &value); + if (ret < 0) + return ret; + value &= ~(1<<2); + value |= (1<<3); + ret = mhl_tx_write_reg(sii9234, 0x90 /*MHL_TX_DISC_CTRL1_REG*/, value); + if (ret < 0) + return ret; + + ret = mhl_tx_write_reg(sii9234, 0x91, 0xE5); + if (ret < 0) + return ret; + ret = mhl_tx_write_reg(sii9234, 0x94, 0x66); + if (ret < 0) + return ret; + + ret = cbus_read_reg(sii9234, 0x31, &value); + if (ret < 0) + return ret; + value |= 0x0C; + if (ret < 0) + return ret; + ret = cbus_write_reg(sii9234, 0x31, value); + if (ret < 0) + return ret; + + ret = mhl_tx_write_reg(sii9234, 0xA5, 0x80); + if (ret < 0) + return ret; + ret = mhl_tx_write_reg(sii9234, 0x95, 0x31); + if (ret < 0) + return ret; + ret = mhl_tx_write_reg(sii9234, 0x96, 0x22); + if (ret < 0) + return ret; + + ret = mhl_tx_read_reg(sii9234, 0x95/*MHL_TX_DISC_CTRL6_REG*/, &value); + if (ret < 0) + return ret; + value |= (1<<6); + ret = mhl_tx_write_reg(sii9234, 0x95/*MHL_TX_DISC_CTRL6_REG*/, value); + if (ret < 0) + return ret; + + ret = mhl_tx_write_reg(sii9234, 0x92, 0x46); + if (ret < 0) + return ret; + ret = mhl_tx_write_reg(sii9234, 0x93, 0xDC); + if (ret < 0) + return ret; + /*0x79=MHL_TX_INT_CTRL_REG*/ + ret = mhl_tx_clear_reg(sii9234, 0x79, (1<<2) | (1<<1)); + if (ret < 0) + return ret; + + mdelay(25); + /*0x95=MHL_TX_DISC_CTRL6_REG*/ + ret = mhl_tx_clear_reg(sii9234, 0x95, (1<<6)/*USB_ID_OVR*/); + if (ret < 0) + return ret; + + ret = mhl_tx_write_reg(sii9234, 0x90, 0x27); + if (ret < 0) + return ret; + + ret = sii9234_cbus_init_for_9290(sii9234); + if (ret < 0) + return ret; + + ret = mhl_tx_write_reg(sii9234, 0x05, 0x4); + if (ret < 0) + return ret; + ret = mhl_tx_write_reg(sii9234, 0x0D, 0x1C); + pr_info("[MHD: %s]--\n", __func__); + return ret; +} + +static int sii9234_30pin_init_for_9290(struct sii9234_data *sii9234) +{ + u8 value; + int ret = 0; + pr_info("[MHD: %s]++\n", __func__); + /* init registers */ + ret = sii9234_30pin_reg_init_for_9290(sii9234); + if (ret < 0) + goto unhandled; + + /* start tpi */ + ret = mhl_tx_write_reg(sii9234, 0xC7, 0x00); + if (ret < 0) + goto unhandled; + + /* enable interrupts */ + ret = mhl_tx_write_reg(sii9234, 0xBC, 0x01); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, 0xBD, 0x78); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, 0xBE, 0x01); + if (ret < 0) + goto unhandled; + + /* mhd rx connected */ + ret = mhl_tx_write_reg(sii9234, 0xBC, 0x01); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, 0xBD, 0xA0); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, 0xBE, 0x10); + if (ret < 0) + goto unhandled; + ret = cbus_write_reg(sii9234, 0x07, 0x30 | 0x0E); + if (ret < 0) + goto unhandled; + ret = cbus_write_reg(sii9234, 0x47, 0x03); + if (ret < 0) + goto unhandled; + ret = cbus_write_reg(sii9234, 0x21, 0x01); + if (ret < 0) + goto unhandled; + + /* enable mhd tx */ + ret = mhl_tx_clear_reg(sii9234, 0x1A, 1<<4); + if (ret < 0) + goto unhandled; + + /* set mhd power active mode */ + ret = mhl_tx_clear_reg(sii9234, 0x1E, 1<<1 | 1<<0); + if (ret < 0) + goto unhandled; + + ret = mhl_tx_write_reg(sii9234, 0xBC, 0x01); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, 0xBD, 0xA0); + if (ret < 0) + goto unhandled; + + ret = mhl_tx_read_reg(sii9234, 0xBE, &value); + if (ret < 0) + goto unhandled; + if ((value & (1<<7 | 1<<6)) != 0x00) { + /* Assert Mobile HD FIFO Reset */ + ret = mhl_tx_write_reg(sii9234, 0xBC, 0x01); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, 0xBD, 0x05); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, 0xBE, (1<<4 | 0x04)); + if (ret < 0) + goto unhandled; + mdelay(1); + /* Deassert Mobile HD FIFO Reset */ + ret = mhl_tx_write_reg(sii9234, 0xBC, 0x01); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, 0xBD, 0x05); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, 0xBE, 0x04); + if (ret < 0) + goto unhandled; + } + + /* This is tricky but there's no way to handle other accessories + * but sending UNHANDLED. + * return MHL_CON_HANDLED; + */ + pr_info("[MHD: %s]--\n", __func__); + return 0; +unhandled: + return -1; +} + + +u8 mhl_onoff_ex(bool onoff) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + + if (!sii9234 || !sii9234->pdata) { + pr_info("mhl_onoff_ex: getting resource is failed\n"); + return 2; + } + + if (sii9234->pdata->power_state == onoff) { + pr_info("mhl_onoff_ex: mhl already %s\n", onoff ? "on" : "off"); + return 2; + } + + sii9234->pdata->power_state = onoff; /*save power state*/ + + if (onoff) { + if (sii9234->pdata->hw_onoff) + sii9234->pdata->hw_onoff(1); + + if (sii9234->pdata->hw_reset) + sii9234->pdata->hw_reset(); + + mutex_lock(&sii9234->lock); + sii9234_30pin_init_for_9290(sii9234); + /*turn on hdm corei*/ + mhl_hpd_handler(true); + mutex_unlock(&sii9234->lock); + + } else { + + mutex_lock(&sii9234->lock); + /*turn off hdmi core*/ + mhl_hpd_handler(false); + sii9234_power_down(sii9234); + mutex_unlock(&sii9234->lock); + + if (sii9234->pdata->hw_onoff) + sii9234->pdata->hw_onoff(0); + } + + return sii9234->rgnd; +} +EXPORT_SYMBOL(mhl_onoff_ex); + + +#ifdef MHL_SS_FACTORY +#define SII_ID 0x92 +static ssize_t sysfs_check_mhl_command(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int size; + u8 sii_id1 = 0; + u8 sii_id2 = 0; + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + + if (sii9234->pdata->hw_onoff) + sii9234->pdata->hw_onoff(1); + + if (sii9234->pdata->hw_reset) + sii9234->pdata->hw_reset(); + + mhl_tx_read_reg(sii9234, MHL_TX_IDH_REG, &sii_id1); + mhl_tx_read_reg(sii9234, MHL_TX_IDL_REG, &sii_id2); + pr_info("sel_show sii_id: %X%X\n", sii_id1, sii_id2); + + if (sii9234->pdata->hw_onoff) + sii9234->pdata->hw_onoff(0); + + size = snprintf(buf, 10, "%d\n", sii_id1 == SII_ID ? 1 : 0); + + return size; + +} + +static CLASS_ATTR(test_result, 0664 , sysfs_check_mhl_command, NULL); +#endif /*MHL_SS_FACTORY*/ + +#ifdef CONFIG_PM +static int sii9234_mhl_tx_suspend(struct device *dev) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(dev); + + /*set config_gpio for mhl*/ + if (sii9234->pdata->gpio_cfg) + sii9234->pdata->gpio_cfg(); + + return 0; +} + +static int sii9234_mhl_tx_resume(struct device *dev) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(dev); + + /*set config_gpio for mhl*/ + if (sii9234->pdata->gpio_cfg) + sii9234->pdata->gpio_cfg(); + + return 0; +} + +static const struct dev_pm_ops sii9234_pm_ops = { + .suspend = sii9234_mhl_tx_suspend, + .resume = sii9234_mhl_tx_resume, +}; +#endif + +static int __devinit sii9234_mhl_tx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct sii9234_data *sii9234; + int ret = 0; +#ifdef MHL_SS_FACTORY + struct class *sec_mhl; +#endif + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + sii9234 = kzalloc(sizeof(struct sii9234_data), GFP_KERNEL); + if (!sii9234) { + dev_err(&client->dev, "failed to allocate driver data\n"); + return -ENOMEM; + } + + sii9234->pdata = client->dev.platform_data; + if (!sii9234->pdata) { + ret = -EINVAL; + goto err_exit1; + } + sii9234->pdata->mhl_tx_client = client; + + + mutex_init(&sii9234->lock); + + + i2c_set_clientdata(client, sii9234); + sii9244_mhldev = &client->dev; + if (sii9234->pdata->swing_level == 0) + sii9234->pdata->swing_level = 0xEB; + + +#ifdef MHL_SS_FACTORY + pr_info("create mhl sysfile\n"); + + sec_mhl = class_create(THIS_MODULE, "mhl"); + if (IS_ERR(sec_mhl)) { + pr_err("Failed to create class(sec_mhl)!\n"); + goto err_class; + } + + ret = class_create_file(sec_mhl, &class_attr_test_result); + if (ret) { + pr_err("[ERROR] Failed to create device file in sysfs entries!\n"); + goto err_exit2a; + } +#endif +#ifdef CONFIG_MHL_SWING_LEVEL + pr_info("create mhl sysfile\n"); + + ret = class_create_file(sec_mhl, &class_attr_swing); + if (ret) { + pr_err("[ERROR] failed to create swing sysfs file\n"); + goto err_exit2a; + } +#endif + return 0; + +err_class: +#ifdef CONFIG_MHL_SWING_LEVEL + class_remove_file(sec_mhl, &class_attr_swing); +#endif + +err_exit2a: +#if defined(MHL_SS_FACTORY) || defined(CONFIG_MHL_SWING_LEVEL) + class_destroy(sec_mhl); +#endif + +err_exit1: + kfree(sii9234); + return ret; +} + +static int __devinit sii9234_tpi_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sii9234_platform_data *pdata = client->dev.platform_data; + if (!pdata) + return -EINVAL; + pdata->tpi_client = client; + return 0; +} + +static int __devinit sii9234_hdmi_rx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sii9234_platform_data *pdata = client->dev.platform_data; + if (!pdata) + return -EINVAL; + + pdata->hdmi_rx_client = client; + return 0; +} + +static int __devinit sii9234_cbus_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sii9234_platform_data *pdata = client->dev.platform_data; + if (!pdata) + return -EINVAL; + + pdata->cbus_client = client; + return 0; +} + +static int __devexit sii9234_mhl_tx_remove(struct i2c_client *client) +{ + return 0; +} + +static int __devexit sii9234_tpi_remove(struct i2c_client *client) +{ + return 0; +} + +static int __devexit sii9234_hdmi_rx_remove(struct i2c_client *client) +{ + return 0; +} + +static int __devexit sii9234_cbus_remove(struct i2c_client *client) +{ + return 0; +} + +static const struct i2c_device_id sii9234_mhl_tx_id[] = { + {"sii9234_mhl_tx", 0}, + {} +}; + +static const struct i2c_device_id sii9234_tpi_id[] = { + {"sii9234_tpi", 0}, + {} +}; + +static const struct i2c_device_id sii9234_hdmi_rx_id[] = { + {"sii9234_hdmi_rx", 0}, + {} +}; + +static const struct i2c_device_id sii9234_cbus_id[] = { + {"sii9234_cbus", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, sii9234_mhl_tx_id); +MODULE_DEVICE_TABLE(i2c, sii9234_tpi_id); +MODULE_DEVICE_TABLE(i2c, sii9234_hdmi_rx_id); +MODULE_DEVICE_TABLE(i2c, sii9234_cbus_id); + +static struct i2c_driver sii9234_mhl_tx_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sii9234_mhl_tx", +#ifdef CONFIG_PM + .pm = &sii9234_pm_ops, +#endif + }, + .id_table = sii9234_mhl_tx_id, + .probe = sii9234_mhl_tx_i2c_probe, + .remove = __devexit_p(sii9234_mhl_tx_remove), + .command = NULL, +}; + +static struct i2c_driver sii9234_tpi_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sii9234_tpi", + }, + .id_table = sii9234_tpi_id, + .probe = sii9234_tpi_i2c_probe, + .remove = __devexit_p(sii9234_tpi_remove), +}; + +static struct i2c_driver sii9234_hdmi_rx_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sii9234_hdmi_rx", + }, + .id_table = sii9234_hdmi_rx_id, + .probe = sii9234_hdmi_rx_i2c_probe, + .remove = __devexit_p(sii9234_hdmi_rx_remove), +}; + +static struct i2c_driver sii9234_cbus_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sii9234_cbus", + }, + .id_table = sii9234_cbus_id, + .probe = sii9234_cbus_i2c_probe, + .remove = __devexit_p(sii9234_cbus_remove), +}; + +static int __init sii9234_init(void) +{ + int ret; + + ret = i2c_add_driver(&sii9234_mhl_tx_i2c_driver); + if (ret < 0) + return ret; + + ret = i2c_add_driver(&sii9234_tpi_i2c_driver); + if (ret < 0) + goto err_exit1; + + ret = i2c_add_driver(&sii9234_hdmi_rx_i2c_driver); + if (ret < 0) + goto err_exit2; + + ret = i2c_add_driver(&sii9234_cbus_i2c_driver); + if (ret < 0) + goto err_exit3; + + return 0; + +err_exit3: + i2c_del_driver(&sii9234_hdmi_rx_i2c_driver); +err_exit2: + i2c_del_driver(&sii9234_tpi_i2c_driver); +err_exit1: + i2c_del_driver(&sii9234_mhl_tx_i2c_driver); + pr_err("i2c_add_driver fail\n"); + return ret; +} + +static void __exit sii9234_exit(void) +{ + i2c_del_driver(&sii9234_cbus_i2c_driver); + i2c_del_driver(&sii9234_hdmi_rx_i2c_driver); + i2c_del_driver(&sii9234_tpi_i2c_driver); + i2c_del_driver(&sii9234_mhl_tx_i2c_driver); +} + +module_init(sii9234_init); +module_exit(sii9234_exit); diff --git a/drivers/accessory/mhl_tab_v2/sii9234_driver.h b/drivers/accessory/mhl_tab_v2/sii9234_driver.h new file mode 100644 index 00000000000..81ed4c543d0 --- /dev/null +++ b/drivers/accessory/mhl_tab_v2/sii9234_driver.h @@ -0,0 +1,504 @@ +/* + * opyright (C) 2011 Samsung Electronics + * + * Authors: Adam Hampson + * Erik Gilling + * + * Additional contributions by : Shankar Bandal + * Dharam Kumar + * + * 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 _SII9234_DRIVER_H_ +#define _SII9234_DRIVER_H_ + +#ifndef CONFIG_SII9234_RCP +#define CONFIG_SII9234_RCP 1 +#include +#endif + +/*Flag for MHL Factory test*/ +#define MHL_SS_FACTORY 1 + + +#define T_WAIT_TIMEOUT_RGND_INT 2000 +#define T_WAIT_TIMEOUT_DISC_INT 1000 +#define T_WAIT_TIMEOUT_RSEN_INT 200 + +#define T_SRC_VBUS_CBUS_TO_STABLE 200 +#define T_SRC_WAKE_PULSE_WIDTH_1 19 +#define T_SRC_WAKE_PULSE_WIDTH_2 60 +#define T_SRC_WAKE_TO_DISCOVER 500 +#define T_SRC_VBUS_CBUS_T0_STABLE 500 + +#define T_SRC_CBUS_FLOAT 100 +#define T_HPD_WIDTH 100 +#define T_SRC_RXSENSE_DEGLITCH 110 +#define T_SRC_CBUS_DEGLITCH 2 + +/* MHL TX Addr 0x72 Registers */ +#define MHL_TX_IDL_REG 0x02 +#define MHL_TX_IDH_REG 0x03 +#define MHL_TX_REV_REG 0x04 +#define MHL_TX_SRST 0x05 +#define MHL_TX_INTR1_REG 0x71 +#define MHL_TX_INTR2_REG 0x72 /* Not Documented */ +#define MHL_TX_INTR3_REG 0x73 /* Not Documented */ +#define MHL_TX_INTR4_REG 0x74 +#define MHL_TX_INTR1_ENABLE_REG 0x75 +#define MHL_TX_INTR2_ENABLE_REG 0x76 /* Not Documented */ +#define MHL_TX_INTR3_ENABLE_REG 0x77 /* Not Documented */ +#define MHL_TX_INTR4_ENABLE_REG 0x78 +#define MHL_TX_INT_CTRL_REG 0x79 +#define MHL_TX_TMDS_CCTRL 0x80 + +#define MHL_TX_DISC_CTRL1_REG 0x90 +#define MHL_TX_DISC_CTRL2_REG 0x91 +#define MHL_TX_DISC_CTRL3_REG 0x92 +#define MHL_TX_DISC_CTRL4_REG 0x93 + +#define MHL_TX_DISC_CTRL5_REG 0x94 +#define MHL_TX_DISC_CTRL6_REG 0x95 +#define MHL_TX_DISC_CTRL7_REG 0x96 +#define MHL_TX_DISC_CTRL8_REG 0x97 +#define MHL_TX_STAT1_REG 0x98 +#define MHL_TX_STAT2_REG 0x99 + +#define MHL_TX_MHLTX_CTL1_REG 0xA0 +#define MHL_TX_MHLTX_CTL2_REG 0xA1 +#define MHL_TX_MHLTX_CTL4_REG 0xA3 +#define MHL_TX_MHLTX_CTL6_REG 0xA5 +#define MHL_TX_MHLTX_CTL7_REG 0xA6 + +/* MHL TX SYS STAT Registers */ +#define MHL_TX_SYSSTAT_REG 0x09 + +/* MHL TX SYS STAT Register Bits */ +#define RSEN_STATUS (1<<2) + +/* MHL TX INTR4 Register Bits */ +#define RGND_READY_INT (1<<6) +#define VBUS_LOW_INT (1<<5) +#define CBUS_LKOUT_INT (1<<4) +#define MHL_DISC_FAIL_INT (1<<3) +#define MHL_EST_INT (1<<2) + +/* MHL TX INTR4_ENABLE 0x78 Register Bits */ +#define RGND_READY_MASK (1<<6) +#define CBUS_LKOUT_MASK (1<<4) +#define MHL_DISC_FAIL_MASK (1<<3) +#define MHL_EST_MASK (1<<2) + +/* MHL TX INTR1 Register Bits*/ +#define HPD_CHANGE_INT (1<<6) +#define RSEN_CHANGE_INT (1<<5) + +/* MHL TX INTR1_ENABLE 0x75 Register Bits*/ +#define HPD_CHANGE_INT_MASK (1<<6) +#define RSEN_CHANGE_INT_MASK (1<<5) + +/* CBUS_INT_1_ENABLE: CBUS Transaction Interrupt #1 Mask */ +#define CBUS_INTR1_ENABLE_REG 0x09 +#define CBUS_INTR2_ENABLE_REG 0x1F + +/* CBUS Interrupt Status Registers*/ +#define CBUS_INT_STATUS_1_REG 0x08 +#define CBUS_INT_STATUS_2_REG 0x1E + +/* CBUS INTR1 STATUS Register bits */ +#define MSC_RESP_ABORT (1<<6) +#define MSC_REQ_ABORT (1<<5) +#define MSC_REQ_DONE (1<<4) +#define MSC_MSG_RECD (1<<3) +#define CBUS_DDC_ABORT (1<<2) + +/* CBUS INTR1 STATUS 0x09 Enable Mask*/ +#define MSC_RESP_ABORT_MASK (1<<6) +#define MSC_REQ_ABORT_MASK (1<<5) +#define MSC_REQ_DONE_MASK (1<<4) +#define MSC_MSG_RECD_MASK (1<<3) +#define CBUS_DDC_ABORT_MASK (1<<2) + +/* CBUS INTR2 STATUS Register bits */ +#define WRT_STAT_RECD (1<<3) +#define SET_INT_RECD (1<<2) +#define WRT_BURST_RECD (1<<0) + +/* CBUS INTR2 STATUS 0x1F Enable Mask*/ +#define WRT_STAT_RECD_MASK (1<<3) +#define SET_INT_RECD_MASK (1<<2) +#define WRT_BURST_RECD_MASK (1<<0) + +#define MHL_INT_EDID_CHG (1<<1) + +#define MHL_RCHANGE_INT 0x20 +#define MHL_DCHANGE_INT 0x21 +#define MHL_INT_DCAP_CHG (1<<0) +#define MHL_INT_DSCR_CHG (1<<1) +#define MHL_INT_REQ_WRT (1<<2) +#define MHL_INT_GRT_WRT (1<<3) + +/* CBUS Control Registers*/ +/* Retry count for all MSC commands*/ +#define MSC_RETRY_FAIL_LIM_REG 0x1D + +#define MSC_REQ_ABORT_REASON_REG 0x0D +#define MSC_RESP_ABORT_REASON_REG 0x0E + +/* MSC Requestor/Responder Abort Reason Register bits*/ +#define ABORT_BY_PEER (1<<7) +#define UNDEF_CMD (1<<3) +#define TIMEOUT (1<<2) +#define PROTO_ERROR (1<<1) +#define MAX_FAIL (1<<0) + +#define REG_CBUS_INTR_STATUS 0x08 +/* Responder aborted DDC command at translation layer */ +#define BIT_DDC_ABORT (1<<2) +/* Responder sent a VS_MSG packet (response data or command.) */ +#define BIT_MSC_MSG_RCV (1<<3) + /* Responder sent ACK packet (not VS_MSG) */ +#define BIT_MSC_XFR_DONE (1<<4) + /* Command send aborted on TX side */ +#define BIT_MSC_XFR_ABORT (1<<5) +#define BIT_MSC_ABORT (1<<6) + +/* Set HPD came from Downstream, */ +#define SET_HPD_DOWNSTREAM (1<<6) + +/* MHL TX DISC1 Register Bits */ +#define DISC_EN (1<<0) + +/* MHL TX DISC2 Register Bits */ +#define SKIP_GND (1<<6) +#define ATT_THRESH_SHIFT 0x04 +#define ATT_THRESH_MASK (0x03 << ATT_THRESH_SHIFT) +#define USB_D_OEN (1<<3) +#define DEGLITCH_TIME_MASK 0x07 +#define DEGLITCH_TIME_2MS 0 +#define DEGLITCH_TIME_4MS 1 +#define DEGLITCH_TIME_8MS 2 +#define DEGLITCH_TIME_16MS 3 +#define DEGLITCH_TIME_40MS 4 +#define DEGLITCH_TIME_50MS 5 +#define DEGLITCH_TIME_60MS 6 +#define DEGLITCH_TIME_128MS 7 + +#define DISC_CTRL3_COMM_IMME (1<<7) +#define DISC_CTRL3_FORCE_MHL (1<<6) +#define DISC_CTRL3_FORCE_USB (1<<4) +#define DISC_CTRL3_USB_EN (1<<3) + +/* MHL TX DISC4 0x93 Register Bits*/ +#define CBUS_DISC_PUP_SEL_SHIFT 6 +#define CBUS_DISC_PUP_SEL_MASK (3<pre_connected && data->tx_ready) + serio_write(data->serio, cmd); +} + +static void sec_keyboard_power(struct work_struct *work) +{ + struct sec_keyboard_drvdata *data = container_of(work, + struct sec_keyboard_drvdata, power_dwork.work); + + if (UNKOWN_KEYLAYOUT == data->kl) { + data->acc_power(3, false); + data->pre_connected = false; + + if (data->check_uart_path) + data->check_uart_path(false); + } +} + +static void forced_wakeup(struct sec_keyboard_drvdata *data) +{ + input_report_key(data->input_dev, + KEY_WAKEUP, 1); + input_report_key(data->input_dev, + KEY_WAKEUP, 0); + input_sync(data->input_dev); +} + +static void sec_keyboard_remapkey(struct work_struct *work) +{ + unsigned int keycode = 0; + struct sec_keyboard_drvdata *data = container_of(work, + struct sec_keyboard_drvdata, remap_dwork.work); + + if (data->pressed[0x45] || data->pressed[0x48]) { + keycode = data->keycode[data->remap_key]; + input_report_key(data->input_dev, keycode, 1); + input_sync(data->input_dev); + } + data->remap_key = 0; +} + +static void release_all_keys(struct sec_keyboard_drvdata *data) +{ + int i; + printk(KERN_DEBUG "[Keyboard] Release the pressed keys.\n"); + for (i = 0; i < KEYBOARD_MAX; i++) { + if (data->pressed[i]) { + input_report_key(data->input_dev, data->keycode[i], 0); + data->pressed[i] = false; + } + input_sync(data->input_dev); + } +} + +static void sec_keyboard_process_data(struct work_struct *work) +{ + struct sec_keyboard_drvdata *data = container_of(work, + struct sec_keyboard_drvdata, handledata_dwork.work); + bool press; + unsigned int keycode; + unsigned char scan_code = data->scan_code; + + /* keyboard driver need the contry code*/ + if (data->kl == UNKOWN_KEYLAYOUT) { + switch (scan_code) { + case US_KEYBOARD: + data->kl = US_KEYLAYOUT; + data->keycode[49] = KEY_BACKSLASH; + /* for the wakeup state*/ + data->pre_kl = data->kl; + printk(KERN_DEBUG "[Keyboard] US keyboard is attacted.\n"); + break; + + case UK_KEYBOARD: + data->kl = UK_KEYLAYOUT; + data->keycode[49] = KEY_NUMERIC_POUND; + /* for the wakeup state*/ + data->pre_kl = data->kl; + printk(KERN_DEBUG "[Keyboard] UK keyboard is attacted.\n"); + break; + + default: + printk(KERN_DEBUG "[Keyboard] Unkown layout : %x\n", + scan_code); + break; + } + } else { + switch (scan_code) { + case 0x0: + release_all_keys(data); + break; + + case 0xca: /* Caps lock on */ + case 0xcb: /* Caps lock off */ + case 0xeb: /* US keyboard */ + case 0xec: /* UK keyboard */ + break; /* Ignore */ + + case 0x45: + case 0x48: + data->remap_key = scan_code; + data->pressed[scan_code] = true; + schedule_delayed_work(&data->remap_dwork, HZ/3); + break; + + case 0xc5: + case 0xc8: + keycode = (scan_code & 0x7f); + data->pressed[keycode] = false; + if (0 == data->remap_key) { + input_report_key(data->input_dev, + data->keycode[keycode], 0); + input_sync(data->input_dev); + } else { + cancel_delayed_work_sync(&data->remap_dwork); + if (0x48 == keycode) + keycode = KEY_NEXTSONG; + else + keycode = KEY_PREVIOUSSONG; + + input_report_key(data->input_dev, + keycode, 1); + input_report_key(data->input_dev, + keycode, 0); + input_sync(data->input_dev); + } + break; + + default: + keycode = (scan_code & 0x7f); + press = ((scan_code & 0x80) != 0x80); + + if (keycode >= KEYBOARD_MIN + || keycode <= KEYBOARD_MAX) { + data->pressed[keycode] = press; + input_report_key(data->input_dev, + data->keycode[keycode], press); + input_sync(data->input_dev); + } + break; + } + } +} + +static int check_keyboard_dock(struct sec_keyboard_callbacks *cb, bool val) +{ + struct sec_keyboard_drvdata *data = + container_of(cb, struct sec_keyboard_drvdata, callbacks); + int try_cnt = 0; + int max_cnt = 14; + + if (NULL == data->serio) + return 0; + + if (!val) + data->dockconnected = false; + else { + cancel_delayed_work_sync(&data->power_dwork); + /* wakeup by keyboard dock */ + if (data->pre_connected) { + if (UNKOWN_KEYLAYOUT != data->pre_kl) { + data->kl = data->pre_kl; + data->acc_power(3, true); + printk(KERN_DEBUG "[Keyboard] kl : %d\n", + data->pre_kl); + return 1; + } + } else + data->pre_kl = UNKOWN_KEYLAYOUT; + + data->pre_connected = true; + + /* to prevent the over current issue */ + data->acc_power(0, false); + + if (data->check_uart_path) + data->check_uart_path(true); + + msleep(200); + data->acc_power(3, true); + + /* try to get handshake data */ + for (try_cnt = 0; try_cnt < max_cnt; try_cnt++) { + msleep(50); + if (data->kl != UNKOWN_KEYLAYOUT) { + data->dockconnected = true; + break; + } + if (gpio_get_value(data->acc_int_gpio)) { + printk(KERN_DEBUG "[Keyboard] acc is disconnected.\n"); + break; + } + } + } + + if (data->dockconnected) + return 1; + else { + if (data->pre_connected) { + data->dockconnected = false; + schedule_delayed_work(&data->power_dwork, HZ/2); + + data->kl = UNKOWN_KEYLAYOUT; + release_all_keys(data); + } + return 0; + } +} + +static int sec_keyboard_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) +{ + struct sec_keyboard_drvdata *data = input_get_drvdata(dev); + + switch (type) { + case EV_LED: + if (value) + sec_keyboard_tx(data, 0xca); + else + sec_keyboard_tx(data, 0xcb); + return 0; + } + return -1; +} + +static ssize_t check_keyboard_connection(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sec_keyboard_drvdata *ddata = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", ddata->dockconnected); +} + +static DEVICE_ATTR(attached, S_IRUGO, check_keyboard_connection, NULL); + +static struct attribute *sec_keyboard_attributes[] = { + &dev_attr_attached.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = sec_keyboard_attributes, +}; + +static irqreturn_t sec_keyboard_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) +{ + struct sec_keyboard_drvdata *ddata = serio_get_drvdata(serio); + ddata->scan_code = data; + if (ddata->pre_connected) + schedule_delayed_work(&ddata->handledata_dwork, 0); + return IRQ_HANDLED; +} + +static int sec_keyboard_connect(struct serio *serio, struct serio_driver *drv) +{ + struct sec_keyboard_drvdata *data = container_of(drv, + struct sec_keyboard_drvdata, serio_driver); + printk(KERN_DEBUG "[Keyboard] %s", __func__); + data->serio = serio; + serio_set_drvdata(serio, data); + if (serio_open(serio, drv)) + printk(KERN_ERR "[Keyboard] failed to open serial port\n"); + else + data->tx_ready = true; + return 0; +} + +static void sec_keyboard_disconnect(struct serio *serio) +{ + struct sec_keyboard_drvdata *data = serio_get_drvdata(serio); + printk(KERN_DEBUG "[Keyboard] %s", __func__); + data->tx_ready = false; + serio_close(serio); +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void keyboard_early_suspend(struct early_suspend *early_sus) +{ + struct sec_keyboard_drvdata *data = container_of(early_sus, + struct sec_keyboard_drvdata, early_suspend); + + if (data->kl != UNKOWN_KEYLAYOUT) { + /* + if the command of the caps lock off is needed, + this command should be sent. + sec_keyboard_tx(0xcb); + msleep(20); + */ + release_all_keys(data); + sec_keyboard_tx(data, 0x10); /* the idle mode */ + } +} + +static void keyboard_late_resume(struct early_suspend *early_sus) +{ + struct sec_keyboard_drvdata *data = container_of(early_sus, + struct sec_keyboard_drvdata, early_suspend); + + if (data->kl != UNKOWN_KEYLAYOUT) + printk(KERN_DEBUG "[Keyboard] %s\n", __func__); + +} +#endif + +static int __devinit sec_keyboard_probe(struct platform_device *pdev) +{ + struct sec_keyboard_platform_data *pdata = pdev->dev.platform_data; + struct sec_keyboard_drvdata *ddata; + struct input_dev *input; + int i, error; + + if (pdata == NULL) { + printk(KERN_ERR "%s: no pdata\n", __func__); + return -ENODEV; + } + + ddata = kzalloc(sizeof(struct sec_keyboard_drvdata), GFP_KERNEL); + if (NULL == ddata) { + error = -ENOMEM; + goto err_alloc_mem; + } + + input = input_allocate_device(); + if (NULL == input) { + printk(KERN_ERR "[Keyboard] failed to allocate input device.\n"); + error = -ENOMEM; + goto err_free_mem; + } + + ddata->input_dev = input; + ddata->acc_power = pdata->acc_power; + ddata->check_uart_path = pdata->check_uart_path; + ddata->acc_int_gpio = pdata->accessory_irq_gpio; + ddata->led_on = false; + ddata->dockconnected = false; + ddata->pre_connected = false; + ddata->remap_key = 0; + ddata->kl = UNKOWN_KEYLAYOUT; + ddata->callbacks.check_keyboard_dock = check_keyboard_dock; + if (pdata->register_cb) + pdata->register_cb(&ddata->callbacks); + + memcpy(ddata->keycode, sec_keycodes, sizeof(sec_keycodes)); + + INIT_DELAYED_WORK(&ddata->remap_dwork, sec_keyboard_remapkey); + INIT_DELAYED_WORK(&ddata->power_dwork, sec_keyboard_power); + INIT_DELAYED_WORK(&ddata->handledata_dwork, sec_keyboard_process_data); + + platform_set_drvdata(pdev, ddata); + input_set_drvdata(input, ddata); + + input->name = pdev->name; + input->dev.parent = &pdev->dev; + input->id.bustype = BUS_RS232; + input->event = sec_keyboard_event; + + __set_bit(EV_KEY, input->evbit); + __set_bit(EV_LED, input->evbit); + __set_bit(LED_CAPSL, input->ledbit); + /* framework doesn't use repeat event */ + /* __set_bit(EV_REP, input->evbit); */ + + for (i = 0; i < KEYBOARD_SIZE; i++) { + if (KEY_RESERVED != ddata->keycode[i]) + input_set_capability(input, EV_KEY, ddata->keycode[i]); + } + + /* for the UK keyboard */ + input_set_capability(input, EV_KEY, KEY_NUMERIC_POUND); + + /* for the remaped keys */ + input_set_capability(input, EV_KEY, KEY_NEXTSONG); + input_set_capability(input, EV_KEY, KEY_PREVIOUSSONG); + + /* for the wakeup key */ + input_set_capability(input, EV_KEY, KEY_WAKEUP); + + error = input_register_device(input); + if (error < 0) { + printk(KERN_ERR "[Keyboard] failed to register input device.\n"); + error = -ENOMEM; + goto err_input_allocate_device; + } + + ddata->serio_driver.driver.name = pdev->name; + ddata->serio_driver.id_table = sec_serio_ids; + ddata->serio_driver.interrupt = sec_keyboard_interrupt, + ddata->serio_driver.connect = sec_keyboard_connect, + ddata->serio_driver.disconnect = sec_keyboard_disconnect, + + error = serio_register_driver(&ddata->serio_driver); + if (error < 0) { + printk(KERN_ERR "[Keyboard] failed to register serio\n"); + error = -ENOMEM; + goto err_reg_serio; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + ddata->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ddata->early_suspend.suspend = keyboard_early_suspend; + ddata->early_suspend.resume = keyboard_late_resume; + register_early_suspend(&ddata->early_suspend); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + + ddata->keyboard_dev = device_create(sec_class, NULL, 0, + ddata, "sec_keyboard"); + if (IS_ERR(ddata->keyboard_dev)) { + printk(KERN_ERR "[Keyboard] failed to create device for the sysfs\n"); + error = -ENODEV; + goto err_sysfs_create_group; + } + + error = sysfs_create_group(&ddata->keyboard_dev->kobj, &attr_group); + if (error) { + printk(KERN_ERR "[Keyboard] failed to create sysfs group\n"); + goto err_sysfs_create_group; + } + + return 0; + +err_sysfs_create_group: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ddata->early_suspend); +#endif + serio_unregister_driver(&ddata->serio_driver); +err_reg_serio: + input_free_device(input); +err_input_allocate_device: + del_timer_sync(&ddata->remap_dwork.timer); + del_timer_sync(&ddata->power_dwork.timer); +err_free_mem: + kfree(ddata); +err_alloc_mem: + + return error; + +} + +static int __devexit sec_keyboard_remove(struct platform_device *pdev) +{ + struct sec_keyboard_drvdata *data = platform_get_drvdata(pdev); + input_unregister_device(data->input_dev); + serio_unregister_driver(&data->serio_driver); + return 0; +} + +#ifndef CONFIG_HAS_EARLYSUSPEND +static int sec_keyboard_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct sec_keyboard_drvdata *data = platform_get_drvdata(pdev); + + if (data->kl != UNKOWN_KEYLAYOUT) + sec_keyboard_tx(data, 0x10); + + return 0; +} + +static int sec_keyboard_resume(struct platform_device *pdev) +{ + struct sec_keyboard_platform_data *pdata = pdev->dev.platform_data; + struct sec_keyboard_drvdata *data = platform_get_drvdata(pdev); + if (pdata->wakeup_key) { + if (KEY_WAKEUP == pdata->wakeup_key()) + forced_wakeup(data); + } + + return 0; +} +#endif + +static struct platform_driver sec_keyboard_driver = { + .probe = sec_keyboard_probe, + .remove = __devexit_p(sec_keyboard_remove), +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = sec_keyboard_suspend, + .resume = sec_keyboard_resume, +#endif + .driver = { + .name = "sec_keyboard", + .owner = THIS_MODULE, + } +}; + +static int __init sec_keyboard_init(void) +{ + return platform_driver_register(&sec_keyboard_driver); +} + +static void __exit sec_keyboard_exit(void) +{ + platform_driver_unregister(&sec_keyboard_driver); +} + +module_init(sec_keyboard_init); +module_exit(sec_keyboard_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SEC Keyboard Dock driver"); diff --git a/drivers/accessory/sec_keyboard.h b/drivers/accessory/sec_keyboard.h new file mode 100644 index 00000000000..18fa63f3cc7 --- /dev/null +++ b/drivers/accessory/sec_keyboard.h @@ -0,0 +1,231 @@ +/* + * sec_keyboard.h + * + * header file describing keyboard dock driver data and keyboard layout + * + * COPYRIGHT(C) Samsung Electronics Co., Ltd. 2006-2011 All Right Reserved. + * + * 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. + */ + +#ifndef _SEC_KEYBOARD_H_ +#define _SEC_KEYBOARD_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KEYBOARD_SIZE 128 +#define US_KEYBOARD 0xeb +#define UK_KEYBOARD 0xec + +#define KEYBOARD_MIN 0x4 +#define KEYBOARD_MAX 0x7f + +enum KEY_LAYOUT { + UNKOWN_KEYLAYOUT = 0, + US_KEYLAYOUT, + UK_KEYLAYOUT, +}; + +extern struct class *sec_class; + +static struct serio_device_id sec_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_SAMSUNG, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, sec_serio_ids); + +struct sec_keyboard_drvdata { + struct input_dev *input_dev; + struct device *keyboard_dev; + struct delayed_work remap_dwork; + struct delayed_work power_dwork; + struct delayed_work handledata_dwork; + struct sec_keyboard_callbacks callbacks; + struct serio *serio; + struct serio_driver serio_driver; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + void (*acc_power)(u8 token, bool active); + void (*check_uart_path)(bool en); + bool led_on; + bool dockconnected; + bool pre_connected; + bool pressed[KEYBOARD_SIZE]; + bool pre_uart_path; + bool tx_ready; + int acc_int_gpio; + unsigned int remap_key; + unsigned int kl; + unsigned int pre_kl; + unsigned short keycode[KEYBOARD_SIZE]; + unsigned long connected_time; + unsigned long disconnected_time; + unsigned char scan_code; +}; + +static const unsigned short sec_keycodes[KEYBOARD_SIZE] = { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_A, + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_ENTER, + KEY_BACK, + KEY_BACKSPACE, + KEY_TAB, + KEY_SPACE, + KEY_MINUS, + KEY_EQUAL, + KEY_LEFTBRACE, + KEY_RIGHTBRACE, + KEY_HOME, + KEY_RESERVED, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_GRAVE, + KEY_COMMA, + KEY_DOT, + KEY_SLASH, + KEY_CAPSLOCK, + KEY_TIME, + KEY_F3, + KEY_WWW, + KEY_EMAIL, + KEY_SCREENLOCK, + KEY_BRIGHTNESSDOWN, + KEY_BRIGHTNESSUP, + KEY_MUTE, + KEY_VOLUMEDOWN, + KEY_VOLUMEUP, + KEY_PLAY, + KEY_REWIND, + KEY_F15, + KEY_RESERVED, + KEY_FASTFORWARD, + KEY_MENU, + KEY_RESERVED, + KEY_RESERVED, + KEY_DELETE, + KEY_RESERVED, + KEY_RESERVED, + KEY_RIGHT, + KEY_LEFT, + KEY_DOWN, + KEY_UP, + KEY_NUMLOCK, + KEY_KPSLASH, + KEY_APOSTROPHE, + KEY_KPMINUS, + KEY_KPPLUS, + KEY_KPENTER, + KEY_KP1, + KEY_KP2, + KEY_KP3, + KEY_KP4, + KEY_KP5, + KEY_KP6, + KEY_KP7, + KEY_KP8, + KEY_KP9, + KEY_KPDOT, + KEY_RESERVED, + KEY_BACKSLASH, + KEY_F22, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_HANGEUL, + KEY_HANJA, + KEY_LEFTCTRL, + KEY_LEFTSHIFT, + KEY_F20, + KEY_SEARCH, + KEY_RIGHTCTRL, + KEY_RIGHTSHIFT, + KEY_F21, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_F17, +}; +#endif /*_SEC_KEYBOARD_H_*/ + diff --git a/drivers/accessory/sec_tablet_conn.c b/drivers/accessory/sec_tablet_conn.c new file mode 100644 index 00000000000..4a0aebc3ee1 --- /dev/null +++ b/drivers/accessory/sec_tablet_conn.c @@ -0,0 +1,615 @@ +/* + * tablet accessory detection driver. + * + * Copyright (C) 2012 Samsung Electronics Co.Ltd + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_VIDEO_MHL_TAB_V2 +#include "mhl_tab_v2/sii9234_driver.h" +#endif +#define SUBJECT "ACCESSORY" + +#define ACC_CONDEV_DBG(format, ...) \ + pr_info("[ "SUBJECT " (%s,%d) ] " format "\n", \ + __func__, __LINE__, ## __VA_ARGS__); + +#define DETECTION_INTR_DELAY (get_jiffies_64() + (HZ*15)) /* 20s */ + +enum accessory_type { + ACCESSORY_NONE = 0, + ACCESSORY_OTG, + ACCESSORY_LINEOUT, +#ifdef CONFIG_CAMERON_HEALTH + ACCESSORY_CAMERON, +#endif + ACCESSORY_CARMOUNT, + ACCESSORY_UNKNOWN, +}; + +enum dock_type { + DOCK_NONE = 0, + DOCK_DESK, + DOCK_KEYBOARD, +}; + +enum uevent_dock_type { + UEVENT_DOCK_NONE = 0, + UEVENT_DOCK_DESK, + UEVENT_DOCK_CAR, + UEVENT_DOCK_KEYBOARD = 9, + UEVENT_DOCK_CONNECTED = 255, +}; + +struct acc_con_info { + struct device *acc_dev; + struct acc_con_platform_data *pdata; + struct delayed_work acc_dwork; + struct delayed_work acc_id_dwork; + struct switch_dev dock_switch; + struct switch_dev ear_jack_switch; + struct wake_lock wake_lock; + struct mutex lock; + enum accessory_type current_accessory; + enum dock_type current_dock; + int accessory_irq; + int dock_irq; + int mhl_irq; +}; + +static int check_using_stmpe811_adc(void) +{ + return true; +} + +static int connector_detect_change(void) +{ + int i; + u32 adc = 0, adc_sum = 0; + u32 adc_buff[5] = {0}; + u32 mili_volt; + u32 adc_min = 0; + u32 adc_max = 0; + + for (i = 0; i < 5; i++) { + mili_volt = acc_get_adc_value(); + + adc_buff[i] = mili_volt; + adc_sum += adc_buff[i]; + if (i == 0) { + adc_min = adc_buff[0]; + adc_max = adc_buff[0]; + } else { + if (adc_max < adc_buff[i]) + adc_max = adc_buff[i]; + else if (adc_min > adc_buff[i]) + adc_min = adc_buff[i]; + } + msleep(20); + } + adc = (adc_sum - adc_max - adc_min)/3; + ACC_CONDEV_DBG("ACCESSORY_ID : ADC value = %d\n", adc); + return (int)adc; +} + +void acc_notified(struct acc_con_info *acc, int acc_adc) +{ + enum accessory_type current_accessory = ACCESSORY_NONE; + char *env_ptr; + char *stat_ptr; + char *envp[3]; +/* + value is changed for Espresso + 3 pole earjack 1.00 V ( 0.90~1.10V) adc: 1207~1256 + Car mount 1.38 V (1.24~1.45V) adc: 1680~1749 + 4 pole earjack just bundles is supported . adc :2189~2278 : No Warranty + OTG 2.2 V (2.00~2.35V) adc: 2676~2785 +*/ + + if (acc_adc != false) { + if (check_using_stmpe811_adc()) { + if ((1207 < acc_adc) && (1256 > acc_adc)) { + env_ptr = "ACCESSORY=lineout"; + current_accessory = ACCESSORY_LINEOUT; + } else if ((1680 < acc_adc) && (1749 > acc_adc)) { + env_ptr = "ACCESSORY=carmount"; + acc->current_accessory = ACCESSORY_CARMOUNT; + } else if ((2189 < acc_adc) && (2278 > acc_adc)) { + env_ptr = "ACCESSORY=lineout"; + current_accessory = ACCESSORY_LINEOUT; +#ifdef CONFIG_CAMERON_HEALTH + } else if ((2400 < acc_adc) && (2500 > acc_adc)) { + env_ptr = "ACCESSORY=cameron"; + current_accessory = ACCESSORY_CAMERON; +#endif + } else if ((2676 < acc_adc) && (2785 > acc_adc)) { + env_ptr = "ACCESSORY=OTG"; + current_accessory = ACCESSORY_OTG; + } else { + env_ptr = "ACCESSORY=unknown"; + current_accessory = ACCESSORY_UNKNOWN; + } + } else { /* not stmpe adc */ + if ((797 < acc_adc) && (1002 > acc_adc)) { + env_ptr = "ACCESSORY=lineout"; + current_accessory = ACCESSORY_LINEOUT; + } else if ((1134 < acc_adc) && (1352 > acc_adc)) { + env_ptr = "ACCESSORY=carmount"; + current_accessory = ACCESSORY_CARMOUNT; + } else if ((1400 < acc_adc) && (1690 > acc_adc)) { + env_ptr = "ACCESSORY=lineout"; + current_accessory = ACCESSORY_LINEOUT; + } else if ((1900 < acc_adc) && (2250 > acc_adc)) { + env_ptr = "ACCESSORY=OTG"; + current_accessory = ACCESSORY_OTG; + } else { + env_ptr = "ACCESSORY=unknown"; + current_accessory = ACCESSORY_UNKNOWN; + } + } + + if (current_accessory == acc->current_accessory) { + ACC_CONDEV_DBG("same accessory type is connected %d", + current_accessory); + return; + } + + if (acc->current_accessory != ACCESSORY_NONE) { + ACC_CONDEV_DBG("assuming prev accessory " + "disconnected %d", acc->current_accessory); + + if (acc->current_accessory == ACCESSORY_OTG) + envp[0] = "ACCESSORY=OTG"; + else if (acc->current_accessory == ACCESSORY_LINEOUT) + envp[0] = "ACCESSORY=lineout"; + else if (acc->current_accessory == ACCESSORY_CARMOUNT) + envp[0] = "ACCESSORY=carmount"; +#ifdef CONFIG_CAMERON_HEALTH + else if (acc->current_accessory == ACCESSORY_CAMERON) + envp[0] = "ACCESSORY=cameron"; +#endif + else + envp[0] = "ACCESSORY=unknown"; + + envp[1] = "STATE=offline"; + envp[2] = NULL; + kobject_uevent_env(&acc->acc_dev->kobj, + KOBJ_CHANGE, envp); + if ((acc->current_accessory == ACCESSORY_OTG) && + acc->pdata->otg_en) + acc->pdata->otg_en(0); + + if (acc->current_accessory == ACCESSORY_LINEOUT) + switch_set_state(&acc->ear_jack_switch, + UEVENT_DOCK_NONE); + + ACC_CONDEV_DBG("%s : %s", envp[0], envp[1]); + } + + acc->current_accessory = current_accessory; + + stat_ptr = "STATE=online"; + envp[0] = env_ptr; + envp[1] = stat_ptr; + envp[2] = NULL; + + if (acc->current_accessory == ACCESSORY_OTG) { + /* force acc power off to ensure otg detection */ + if (acc->pdata->acc_power) + acc->pdata->acc_power(0, false); + msleep(20); + + if (acc->pdata->otg_en) + acc->pdata->otg_en(1); + msleep(30); + } else if (acc->current_accessory == ACCESSORY_LINEOUT) + switch_set_state(&acc->ear_jack_switch, 1); +#ifdef CONFIG_CAMERON_HEALTH + else if (acc->current_accessory == ACCESSORY_CAMERON) { + /* To do, when the cameron health device is connected */ + + /* force acc power off to ensure otg detection */ + if (acc->pdata->acc_power) + acc->pdata->acc_power(0, false); + msleep(20); + + if (acc->pdata->cameron_health_en) + acc->pdata->cameron_health_en(1); + msleep(30); + } +#endif + kobject_uevent_env(&acc->acc_dev->kobj, KOBJ_CHANGE, envp); + ACC_CONDEV_DBG("%s : %s", env_ptr, stat_ptr); + } else { + if (acc->current_accessory == ACCESSORY_OTG) { + env_ptr = "ACCESSORY=OTG"; + } else if (acc->current_accessory == ACCESSORY_LINEOUT) { + env_ptr = "ACCESSORY=lineout"; + switch_set_state(&acc->ear_jack_switch, + UEVENT_DOCK_NONE); + } else if (acc->current_accessory == ACCESSORY_CARMOUNT) { + env_ptr = "ACCESSORY=carmount"; +#ifdef CONFIG_CAMERON_HEALTH + } else if (acc->current_accessory == ACCESSORY_CAMERON) { + env_ptr = "ACCESSORY=cameron"; +#endif + } else { + env_ptr = "ACCESSORY=unknown"; + } + + stat_ptr = "STATE=offline"; + envp[0] = env_ptr; + envp[1] = stat_ptr; + envp[2] = NULL; + kobject_uevent_env(&acc->acc_dev->kobj, KOBJ_CHANGE, envp); + if ((acc->current_accessory == ACCESSORY_OTG) && + acc->pdata->otg_en) + acc->pdata->otg_en(0); +#ifdef CONFIG_CAMERON_HEALTH + else if (acc->current_accessory == ACCESSORY_CAMERON) + acc->pdata->cameron_health_en(0); +#endif + acc->current_accessory = ACCESSORY_NONE; + ACC_CONDEV_DBG("%s : %s", env_ptr, stat_ptr); + } +} + +static void acc_dock_check(struct acc_con_info *acc, bool connected) +{ + char *env_ptr; + char *stat_ptr; + char *envp[3]; + + if (acc->current_dock == DOCK_KEYBOARD) + env_ptr = "DOCK=keyboard"; + else if (acc->current_dock == DOCK_DESK) + env_ptr = "DOCK=desk"; + else + env_ptr = "DOCK=unknown"; + + if (!connected) { + stat_ptr = "STATE=offline"; + acc->current_dock = DOCK_NONE; + } else { + stat_ptr = "STATE=online"; + } + + envp[0] = env_ptr; + envp[1] = stat_ptr; + envp[2] = NULL; + kobject_uevent_env(&acc->acc_dev->kobj, KOBJ_CHANGE, envp); + ACC_CONDEV_DBG("%s : %s", env_ptr, stat_ptr); +} + +static void check_acc_dock(struct acc_con_info *acc) +{ + if (gpio_get_value(acc->pdata->accessory_irq_gpio)) { + if (acc->current_dock == DOCK_NONE) + return; + ACC_CONDEV_DBG("docking station detached!!!"); + switch_set_state(&acc->dock_switch, UEVENT_DOCK_NONE); +#ifdef CONFIG_SEC_KEYBOARD_DOCK + acc->pdata->check_keyboard(false); +#endif +#if defined(CONFIG_VIDEO_MHL_TAB_V2) + /*call MHL deinit */ + mhl_onoff_ex(false); +#endif + acc_dock_check(acc, false); + } else { + ACC_CONDEV_DBG("docking station attached!!!"); + + switch_set_state(&acc->dock_switch, UEVENT_DOCK_CONNECTED); + msleep(100); + wake_lock(&acc->wake_lock); + +#ifdef CONFIG_SEC_KEYBOARD_DOCK + if (acc->pdata->check_keyboard(true)) { + acc->current_dock = DOCK_KEYBOARD; + ACC_CONDEV_DBG("[30PIN] keyboard dock " + "station attached!!!"); + switch_set_state(&acc->dock_switch, + UEVENT_DOCK_KEYBOARD); + } else +#endif /* CONFIG_SEC_KEYBOARD_DOCK */ + { + switch_set_state(&acc->dock_switch, UEVENT_DOCK_DESK); + acc->current_dock = DOCK_DESK; + } +#if defined(CONFIG_VIDEO_MHL_TAB_V2) + mhl_onoff_ex(true); +#endif + + acc_dock_check(acc, true); + + wake_unlock(&acc->wake_lock); + + } +} + +static irqreturn_t acc_con_interrupt(int irq, void *ptr) +{ + struct acc_con_info *acc = ptr; + + ACC_CONDEV_DBG(""); + + check_acc_dock(acc); + + return IRQ_HANDLED; +} + +#define DET_CHECK_TIME_MS 100 +#define DET_SLEEP_TIME_MS 10 +#define DETECTION_DELAY_MS 200 + +static irqreturn_t acc_ID_interrupt(int irq, void *dev_id) +{ + struct acc_con_info *acc = (struct acc_con_info *)dev_id; + int acc_ID_val = 0, pre_acc_ID_val = 0; + int time_left_ms = DET_CHECK_TIME_MS; + + ACC_CONDEV_DBG(""); + + while (time_left_ms > 0) { + acc_ID_val = acc->pdata->get_dock_state(); + + if (acc_ID_val == pre_acc_ID_val) + time_left_ms -= DET_SLEEP_TIME_MS; + else + time_left_ms = DET_CHECK_TIME_MS; + + pre_acc_ID_val = acc_ID_val; + msleep(DET_SLEEP_TIME_MS); + } + + ACC_CONDEV_DBG("IRQ_DOCK_GPIO is %d", acc_ID_val); + if (acc_ID_val == 0) { + ACC_CONDEV_DBG("Accessory detached"); + acc_notified(acc, false); + } else { + wake_lock(&acc->wake_lock); + schedule_delayed_work(&acc->acc_id_dwork, + msecs_to_jiffies(DETECTION_DELAY_MS)); + } + return IRQ_HANDLED; +} + +static int acc_con_interrupt_init(struct acc_con_info *acc) +{ + int ret = 0; + ACC_CONDEV_DBG(""); + + ret = gpio_request(acc->pdata->accessory_irq_gpio, "accessory"); + if (ret) { + ACC_CONDEV_DBG("gpio_request(accessory_irq)return: %d\n", ret); + return ret; + } + gpio_direction_input(acc->pdata->accessory_irq_gpio); + acc->accessory_irq = gpio_to_irq(acc->pdata->accessory_irq_gpio); + ret = request_threaded_irq(acc->accessory_irq, NULL, acc_con_interrupt, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "accessory_detect", acc); + if (ret) + ACC_CONDEV_DBG("request_irq(accessory_irq) return : %d\n", ret); + + ret = enable_irq_wake(acc->accessory_irq); + if (ret) + ACC_CONDEV_DBG("enable_irq_wake(accessory_irq) " + "return : %d\n", ret); + return ret; +} + +static int acc_ID_interrupt_init(struct acc_con_info *acc) +{ + int ret = 0; + ACC_CONDEV_DBG(""); + + ret = gpio_request(acc->pdata->dock_irq_gpio, "dock"); + if (ret) { + ACC_CONDEV_DBG("gpio_request(dock_irq)return: %d\n", ret); + return ret; + } + gpio_direction_input(acc->pdata->dock_irq_gpio); + acc->dock_irq = gpio_to_irq(acc->pdata->dock_irq_gpio); + ret = request_threaded_irq(acc->dock_irq, NULL, acc_ID_interrupt, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "dock_detect", acc); + if (ret) + ACC_CONDEV_DBG("request_irq(dock_irq) return : %d\n", ret); + + ret = enable_irq_wake(acc->dock_irq); + if (ret) + ACC_CONDEV_DBG("enable_irq_wake(dock_irq) return : %d\n", ret); + return ret; +} + +static void acc_delay_work(struct work_struct *work) +{ + struct acc_con_info *acc = container_of(work, + struct acc_con_info, acc_dwork.work); + int retval; + + retval = acc_con_interrupt_init(acc); + if (retval) { + ACC_CONDEV_DBG(" failed to initialize " + "the accessory detecty irq"); + goto err_irq_dock; + } + + retval = acc_ID_interrupt_init(acc); + if (retval) { + ACC_CONDEV_DBG(" failed to initialize the accessory ID irq"); + goto err_irq_acc; + } + + if (!gpio_get_value_cansleep(acc->pdata->accessory_irq_gpio)) + check_acc_dock(acc); + + if (acc->pdata->get_dock_state()) { + wake_lock(&acc->wake_lock); + schedule_delayed_work(&acc->acc_id_dwork, + msecs_to_jiffies(DETECTION_DELAY_MS)); + } + + return ; + +err_irq_acc: + free_irq(acc->accessory_irq, acc); +err_irq_dock: + switch_dev_unregister(&acc->ear_jack_switch); + return ; +} + +static void acc_id_delay_work(struct work_struct *work) +{ + struct acc_con_info *acc = container_of(work, + struct acc_con_info, acc_id_dwork.work); + int adc_val = 0; + if (!acc->pdata->get_dock_state()) { + ACC_CONDEV_DBG("ACCESSORY detached\n"); + wake_unlock(&acc->wake_lock); + return; + } else { + ACC_CONDEV_DBG("Accessory attached"); + adc_val = connector_detect_change(); + ACC_CONDEV_DBG("adc_val : %d", adc_val); + acc_notified(acc, adc_val); + } + wake_unlock(&acc->wake_lock); +} + +static int acc_con_probe(struct platform_device *pdev) +{ + struct acc_con_info *acc; + struct acc_con_platform_data *pdata = pdev->dev.platform_data; + int retval; + + ACC_CONDEV_DBG(""); + + if (pdata == NULL) { + pr_err("%s: no pdata\n", __func__); + return -ENODEV; + } + + acc = kzalloc(sizeof(*acc), GFP_KERNEL); + if (!acc) + return -ENOMEM; + + acc->pdata = pdata; + acc->current_dock = DOCK_NONE; + acc->current_accessory = ACCESSORY_NONE; + + mutex_init(&acc->lock); + + retval = dev_set_drvdata(&pdev->dev, acc); + if (retval < 0) + goto err_sw_dock; + + acc->acc_dev = &pdev->dev; + + acc->dock_switch.name = "dock"; + retval = switch_dev_register(&acc->dock_switch); + if (retval < 0) + goto err_sw_dock; + + acc->ear_jack_switch.name = "usb_audio"; + retval = switch_dev_register(&acc->ear_jack_switch); + if (retval < 0) + goto err_sw_jack; + + wake_lock_init(&acc->wake_lock, WAKE_LOCK_SUSPEND, "30pin_con"); + INIT_DELAYED_WORK(&acc->acc_dwork, acc_delay_work); + schedule_delayed_work(&acc->acc_dwork, msecs_to_jiffies(24000)); + INIT_DELAYED_WORK(&acc->acc_id_dwork, acc_id_delay_work); + + return 0; + +err_sw_jack: + switch_dev_unregister(&acc->dock_switch); +err_sw_dock: + kfree(acc); + + return retval; + +} + +static int acc_con_remove(struct platform_device *pdev) +{ + struct acc_con_info *acc = platform_get_drvdata(pdev); + + ACC_CONDEV_DBG(""); + + disable_irq_wake(acc->accessory_irq); + disable_irq_wake(acc->dock_irq); + free_irq(acc->accessory_irq, acc); + free_irq(acc->dock_irq, acc); + switch_dev_unregister(&acc->dock_switch); + switch_dev_unregister(&acc->ear_jack_switch); + kfree(acc); + + return 0; +} + +static int acc_con_suspend(struct platform_device *pdev, pm_message_t state) +{ + ACC_CONDEV_DBG(""); + return 0; +} + +static int acc_con_resume(struct platform_device *pdev) +{ + ACC_CONDEV_DBG(""); + return 0; +} + +static struct platform_driver acc_con_driver = { + .probe = acc_con_probe, + .remove = acc_con_remove, + .suspend = acc_con_suspend, + .resume = acc_con_resume, + .driver = { + .name = "acc_con", + .owner = THIS_MODULE, + }, +}; + +static int __init acc_con_init(void) +{ + ACC_CONDEV_DBG(""); + return platform_driver_register(&acc_con_driver); +} + +static void __exit acc_con_exit(void) +{ + platform_driver_unregister(&acc_con_driver); +} + +late_initcall(acc_con_init); +module_exit(acc_con_exit); + +MODULE_AUTHOR("Kyungrok Min "); +MODULE_DESCRIPTION("acc connector driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/base/core.c b/drivers/base/core.c index 8e01c9417f4..4e91fd65301 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -191,9 +191,8 @@ static void device_release(struct kobject *kobj) else if (dev->class && dev->class->dev_release) dev->class->dev_release(dev); else - WARN(1, KERN_ERR "Device '%s' does not have a release() " - "function, it is broken and must be fixed.\n", - dev_name(dev)); + pr_debug("Device '%s' does not have a release() function, " + "be careful\n", dev_name(dev)); kfree(p); } diff --git a/drivers/battery/Kconfig b/drivers/battery/Kconfig new file mode 100644 index 00000000000..d3432f01392 --- /dev/null +++ b/drivers/battery/Kconfig @@ -0,0 +1,166 @@ + +config BATTERY_SAMSUNG + tristate "samsung battery driver" + help + Say Y to include support for samsung battery driver + This battery driver integrated all battery-related functions + To see battery-related functions, + refer to sec_charging_common.h + + +# Fuel Gauge + +config FUELGAUGE_DUMMY + tristate "dummy fuel gauge driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for dummy fuel gauge driver. + This driver source code implemented + skeleton source code for fuel gauge functions. + +config FUELGAUGE_MAX17042 + tristate "MAX17042 fuel gauge driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for MAXIM MAX17042 fuel gauge driver. + This fuel-gauge can be used in voltage-tracking mode + or coulomb-counting mode. + +config FUELGAUGE_MAX17042_VOLTAGE_TRACKING + tristate "use MAX17042 fuel gauge only as voltage tracking" + default n + depends on FUELGAUGE_MAX17042 + help + Say Y to use MAX17042 fuel gauge + only as voltage tracking. + This mode is for target that consumes low current + like smart-phone. + +config FUELGAUGE_MAX17042_COULOMB_COUNTING + tristate "use MAX17042 fuel gauge as coulomb counting (including voltage tracking)" + default n + depends on FUELGAUGE_MAX17042 + help + Say Y to use MAX17042 fuel gauge + as coulomb counting (including voltage tracking). + This mode is for target that consumes high current + like tablet. + +config FUELGAUGE_MAX17048 + tristate "MAX17048 fuel gauge driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for MAXIM MAX17048 fuel gauge driver. + This fuel-gauge can be used + only in voltage-tracking mode. + +config FUELGAUGE_MAX17050 + tristate "MAX17050 fuel gauge driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for MAXIM MAX17047 or MAX17050 fuel gauge driver. + This fuel-gauge can be used in voltage-tracking mode + or coulomb-counting mode. + +config FUELGAUGE_MAX17050_VOLTAGE_TRACKING + tristate "use MAX17050 fuel gauge only as voltage tracking" + default n + depends on FUELGAUGE_MAX17050 + help + Say Y to use MAX17050 fuel gauge + only as voltage tracking. + This mode is for target that consumes low current + like smart-phone. + +config FUELGAUGE_MAX17050_COULOMB_COUNTING + tristate "use MAX17050 fuel gauge as coulomb counting (including voltage tracking)" + default n + depends on FUELGAUGE_MAX17050 + help + Say Y to use MAX17050 fuel gauge + as coulomb counting (including voltage tracking). + This mode is for target that consumes high current + like tablet. + + +# Charger + +config CHARGER_DUMMY + tristate "dummy charger driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for dummy charger driver. + This driver source code implemented + skeleton source code for charger functions. + +config CHARGER_MAX8903 + tristate "MAX8903 charger driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for MAXIM MAX8903 charger driver. + This driver source code implemented + all functions for MAX8903 charger. + +config CHARGER_SMB328 + tristate "SMB328 charger driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for Summit SMB328 charger driver. + This driver source code implemented + all functions for SMB328 charger. + +config CHARGER_SMB347 + tristate "SMB347 charger driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for Summit SMB347 charger driver. + This driver source code implemented + all functions for SMB347 charger. + +config CHARGER_BQ24157 + tristate "BQ24157 charger driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for TI BQ24157 charger driver. + This driver source code implemented + all functions for BQ24157 charger. + +config CHARGER_BQ24190 + tristate "BQ24190 charger driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for TI BQ24190 charger driver. + This driver source code implemented + all functions for BQ24190 charger. + +config CHARGER_BQ24191 + tristate "BQ24191 charger driver" + default n + depends on BATTERY_SAMSUNG + help + Say Y to include support + for TI BQ24191 charger driver. + This driver source code implemented + all functions for BQ24191 charger. + + diff --git a/drivers/battery/Makefile b/drivers/battery/Makefile new file mode 100644 index 00000000000..03c737bcdff --- /dev/null +++ b/drivers/battery/Makefile @@ -0,0 +1,15 @@ +obj-$(CONFIG_BATTERY_SAMSUNG) += sec_battery.o \ + sec_charger.o \ + sec_fuelgauge.o + +obj-$(CONFIG_FUELGAUGE_MAX17042) += max17042_fuelgauge.o +obj-$(CONFIG_FUELGAUGE_MAX17048) += max17048_fuelgauge.o +obj-$(CONFIG_FUELGAUGE_MAX17050) += max17050_fuelgauge.o + +obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o +obj-$(CONFIG_CHARGER_SMB328) += smb328_charger.o +obj-$(CONFIG_CHARGER_SMB347) += smb347_charger.o +obj-$(CONFIG_CHARGER_BQ24157) += bq24157_charger.o +obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o +obj-$(CONFIG_CHARGER_BQ24191) += bq24190_charger.o + diff --git a/drivers/battery/bq24157_charger.c b/drivers/battery/bq24157_charger.c new file mode 100644 index 00000000000..4d1235c06be --- /dev/null +++ b/drivers/battery/bq24157_charger.c @@ -0,0 +1,482 @@ +/* + * bq24157_charger.c + * Samsung BQ24157 Charger Driver + * + * Copyright (C) 2012 Samsung Electronics + * + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#define DEBUG + +#include + +static int bq24157_i2c_write(struct i2c_client *client, + int reg, u8 *buf) +{ + int ret; + ret = i2c_smbus_write_i2c_block_data(client, reg, 1, buf); + if (ret < 0) + dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret); + return ret; +} + +static int bq24157_i2c_read(struct i2c_client *client, + int reg, u8 *buf) +{ + int ret; + ret = i2c_smbus_read_i2c_block_data(client, reg, 1, buf); + if (ret < 0) + dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret); + return ret; +} + +static void bq24157_i2c_write_array(struct i2c_client *client, + u8 *buf, int size) +{ + int i; + for (i = 0; i < size; i += 3) + bq24157_i2c_write(client, (u8) (*(buf + i)), (buf + i) + 1); +} + +static void bq24157_set_command(struct i2c_client *client, + int reg, int datum) +{ + int val; + u8 data = 0; + val = bq24157_i2c_read(client, reg, &data); + if (val >= 0) { + dev_dbg(&client->dev, "%s : reg(0x%02x): 0x%02x(0x%02x)", + __func__, reg, data, datum); + if (data != datum) { + data = datum; + if (bq24157_i2c_write(client, reg, &data) < 0) + dev_err(&client->dev, + "%s : error!\n", __func__); + val = bq24157_i2c_read(client, reg, &data); + if (val >= 0) + dev_dbg(&client->dev, " => 0x%02x\n", data); + } + } +} + +static void bq24157_test_read(struct i2c_client *client) +{ + u8 data = 0; + u32 addr = 0; + for (addr = 0; addr <= 0x06; addr++) { + bq24157_i2c_read(client, addr, &data); + dev_dbg(&client->dev, + "bq24157 addr : 0x%02x data : 0x%02x\n", addr, data); + } +} + +static void bq24157_read_regs(struct i2c_client *client, char *str) +{ + u8 data = 0; + u32 addr = 0; + + for (addr = 0; addr <= 0x06; addr++) { + bq24157_i2c_read(client, addr, &data); + sprintf(str+strlen(str), "0x%x, ", data); + } +} + + +static int bq24157_get_charging_status(struct i2c_client *client) +{ + int status = POWER_SUPPLY_STATUS_UNKNOWN; + u8 data = 0; + + bq24157_i2c_read(client, BQ24157_STATUS, &data); + dev_info(&client->dev, + "%s : charger status(0x%02x)\n", __func__, data); + + data = (data & 0x30); + + switch (data) { + case 0x00: + status = POWER_SUPPLY_STATUS_DISCHARGING; + break; + case 0x10: + status = POWER_SUPPLY_STATUS_CHARGING; + break; + case 0x20: + status = POWER_SUPPLY_STATUS_FULL; + break; + case 0x30: + status = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + } + + return (int)status; +} + +static int bq24157_get_charging_health(struct i2c_client *client) +{ + int health = POWER_SUPPLY_HEALTH_GOOD; + u8 data = 0; + + bq24157_i2c_read(client, BQ24157_STATUS, &data); + dev_info(&client->dev, + "%s : charger status(0x%02x)\n", __func__, data); + + if ((data & 0x30) == 0x30) { /* check for fault */ + data = (data & 0x07); + + switch (data) { + case 0x01: + health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + break; + case 0x03: + health = POWER_SUPPLY_HEALTH_UNDERVOLTAGE; + break; + } + } + + return (int)health; +} + +static u8 bq24157_get_float_voltage_data( + int float_voltage) +{ + u8 data; + + if (float_voltage < 3500) + float_voltage = 3500; + + data = (float_voltage - 3500) / 20; + + return data << 2; +} + +static u8 bq24157_get_input_current_limit_data( + int input_current) +{ + u8 data; + + if (input_current <= 100) + data = 0x00; + else if (input_current <= 500) + data = 0x01; + else if (input_current <= 800) + data = 0x02; + else /* No limit */ + data = 0x03; + + return data << 6; +} + +static u8 bq24157_get_termination_current_limit_data( + int termination_current) +{ + u8 data; + + /* Rsns 0.068 Ohm */ + /* default offset 50mA */ + data = (termination_current - 50) / 50; + + return data; +} + +static u8 bq24157_get_fast_charging_current_data( + int fast_charging_current) +{ + u8 data; + + /* Rsns 0.068 Ohm */ + /* default offset 550mA */ + data = (fast_charging_current - 550) / 100; + + return data << 4; +} + +static void bq24157_set_safety_limits(struct i2c_client *client) +{ + struct sec_charger_info *charger = i2c_get_clientdata(client); + u8 data; + + data = 0x00; + data |= bq24157_get_fast_charging_current_data( + charger->pdata->charging_current[ + POWER_SUPPLY_TYPE_MAINS].fast_charging_current); + data |= ((charger->pdata->chg_float_voltage - 4200) / 20); + + bq24157_set_command(client, + BQ24157_SAFETY, data); +} + +static void bq24157_charger_function_conrol( + struct i2c_client *client) +{ + struct sec_charger_info *charger = i2c_get_clientdata(client); + u8 data; + + if (charger->charging_current < 0) { + dev_dbg(&client->dev, + "%s : OTG is activated. Ignore command!\n", __func__); + return; + } + + if (charger->cable_type == + POWER_SUPPLY_TYPE_BATTERY) { + /* Do Nothing */ + } else { + data = 0x02; + dev_dbg(&client->dev, "%s : float voltage (%dmV)\n", + __func__, charger->pdata->chg_float_voltage); + data |= bq24157_get_float_voltage_data( + charger->pdata->chg_float_voltage); + bq24157_set_command(client, + BQ24157_VOLTAGE, data); + + data = 0x00; + dev_dbg(&client->dev, "%s : fast charging current (%dmA)\n", + __func__, charger->charging_current); + data |= bq24157_get_fast_charging_current_data( + charger->charging_current); + dev_dbg(&client->dev, "%s : termination current (%dmA)\n", + __func__, charger->pdata->charging_current[ + charger->cable_type].full_check_current_1st); + data |= bq24157_get_termination_current_limit_data( + charger->pdata->charging_current[ + charger->cable_type].full_check_current_1st); + bq24157_set_command(client, + BQ24157_CURRENT, data); + + /* Input current limit */ + bq24157_i2c_read(client, BQ24157_CONTROL, &data); + dev_dbg(&client->dev, "%s : input current (%dmA)\n", + __func__, charger->pdata->charging_current + [charger->cable_type].input_current_limit); + data |= bq24157_get_input_current_limit_data( + charger->pdata->charging_current + [charger->cable_type].input_current_limit); + bq24157_set_command(client, + BQ24157_CONTROL, data); + + /* Special Charger Voltage : 4.520V + * Normal charge current + */ + bq24157_i2c_read(client, BQ24157_SPECIAL, &data); + data &= 0xdf; + bq24157_set_command(client, + BQ24157_SPECIAL, data); + + bq24157_i2c_read(client, BQ24157_CONTROL, &data); + /* Enable charging */ + data &= 0xfb; + /* Termination setting */ + switch (charger->pdata->full_check_type) { + case SEC_BATTERY_FULLCHARGED_CHGGPIO: + case SEC_BATTERY_FULLCHARGED_CHGINT: + case SEC_BATTERY_FULLCHARGED_CHGPSY: + /* Enable Current Termination */ + data |= 0x08; + break; + } + bq24157_set_command(client, + BQ24157_CONTROL, data); + } +} + +static void bq24157_charger_otg_conrol( + struct i2c_client *client) +{ + struct sec_charger_info *charger = i2c_get_clientdata(client); + u8 data; + + if (charger->cable_type == + POWER_SUPPLY_TYPE_BATTERY) { + dev_info(&client->dev, "%s : turn off OTG\n", __func__); + /* turn off OTG */ + bq24157_i2c_read(client, BQ24157_VOLTAGE, &data); + data &= 0xfe; + bq24157_set_command(client, + BQ24157_VOLTAGE, data); + } else { + dev_info(&client->dev, "%s : turn on OTG\n", __func__); + /* turn on OTG */ + bq24157_i2c_read(client, BQ24157_VOLTAGE, &data); + data |= 0x01; + bq24157_set_command(client, + BQ24157_VOLTAGE, data); + } +} + +bool sec_hal_chg_init(struct i2c_client *client) +{ + bq24157_test_read(client); + return true; +} + +bool sec_hal_chg_suspend(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_chg_resume(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_chg_get_property(struct i2c_client *client, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_charger_info *charger = i2c_get_clientdata(client); + u8 data; + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = bq24157_get_charging_status(client); + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = bq24157_get_charging_health(client); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (charger->charging_current) { + /* Rsns 0.068 Ohm */ + bq24157_i2c_read(client, BQ24157_CURRENT, &data); + val->intval = ((data & 0x78) >> 3) * 100; + } else + val->intval = 0; + dev_dbg(&client->dev, + "%s : set-current(%dmA), current now(%dmA)\n", + __func__, charger->charging_current, val->intval); + break; + default: + return false; + } + return true; +} + +bool sec_hal_chg_set_property(struct i2c_client *client, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sec_charger_info *charger = i2c_get_clientdata(client); + + switch (psp) { + /* val->intval : type */ + case POWER_SUPPLY_PROP_ONLINE: + if (charger->pdata->chg_gpio_en) { + if (gpio_request(charger->pdata->chg_gpio_en, + "CHG_EN") < 0) { + dev_err(&client->dev, + "failed to request vbus_in gpio\n"); + break; + } + if (charger->cable_type == + POWER_SUPPLY_TYPE_BATTERY) + gpio_set_value_cansleep( + charger->pdata->chg_gpio_en, + charger->pdata->chg_polarity_en ? + 0 : 1); + else + gpio_set_value_cansleep( + charger->pdata->chg_gpio_en, + charger->pdata->chg_polarity_en ? + 1 : 0); + gpio_free(charger->pdata->chg_gpio_en); + } + /* val->intval : charging current */ + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (charger->charging_current < 0) + bq24157_charger_otg_conrol(client); + else if (charger->charging_current > 0) + bq24157_charger_function_conrol(client); + else { + bq24157_charger_function_conrol(client); + bq24157_charger_otg_conrol(client); + } + bq24157_test_read(client); + break; + default: + return false; + } + return true; +} + +ssize_t sec_hal_chg_show_attrs(struct device *dev, + const ptrdiff_t offset, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_charger_info *chg = + container_of(psy, struct sec_charger_info, psy_chg); + int i = 0; + char *str = NULL; + + switch (offset) { +/* case CHG_REG: */ +/* break; */ + case CHG_DATA: + i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n", + chg->reg_data); + break; + case CHG_REGS: + str = kzalloc(sizeof(char)*1024, GFP_KERNEL); + if (!str) + return -ENOMEM; + + bq24157_read_regs(chg->client, str); + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", + str); + + kfree(str); + break; + default: + i = -EINVAL; + break; + } + + return i; +} + +ssize_t sec_hal_chg_store_attrs(struct device *dev, + const ptrdiff_t offset, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_charger_info *chg = + container_of(psy, struct sec_charger_info, psy_chg); + int ret = 0; + int x = 0; + u8 data = 0; + + switch (offset) { + case CHG_REG: + if (sscanf(buf, "%x\n", &x) == 1) { + chg->reg_addr = x; + bq24157_i2c_read(chg->client, + chg->reg_addr, &data); + chg->reg_data = data; + dev_dbg(dev, "%s: (read) addr = 0x%x, data = 0x%x\n", + __func__, chg->reg_addr, chg->reg_data); + ret = count; + } + break; + case CHG_DATA: + if (sscanf(buf, "%x\n", &x) == 1) { + data = (u8)x; + dev_dbg(dev, "%s: (write) addr = 0x%x, data = 0x%x\n", + __func__, chg->reg_addr, data); + bq24157_i2c_write(chg->client, + chg->reg_addr, &data); + ret = count; + } + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} diff --git a/drivers/battery/max17042_fuelgauge.c b/drivers/battery/max17042_fuelgauge.c new file mode 100644 index 00000000000..61d4174c6f5 --- /dev/null +++ b/drivers/battery/max17042_fuelgauge.c @@ -0,0 +1,2436 @@ +/* + * max17042_fuelgauge.c + * Samsung MAX17042 Fuel Gauge Driver + * + * Copyright (C) 2012 Samsung Electronics + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +#ifdef CONFIG_FUELGAUGE_MAX17042_VOLTAGE_TRACKING +static int max17042_write_reg(struct i2c_client *client, int reg, u8 *buf) +{ + int ret; + + ret = i2c_smbus_write_i2c_block_data(client, reg, 2, buf); + + if (ret < 0) + pr_err("%s: Error(%d)\n", __func__, ret); + + return ret; +} + +static int max17042_read_reg(struct i2c_client *client, int reg, u8 *buf) +{ + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, reg, 2, buf); + + if (ret < 0) + pr_err("%s: Error(%d)\n", __func__, ret); + + return ret; +} + +static void max17042_write_reg_array(struct i2c_client *client, + u8 *buf, int size) +{ + int i; + + for (i = 0; i < size; i += 3) + max17042_write_reg(client, (u8) (*(buf + i)), (buf + i) + 1); +} + +static void max17042_init_regs(struct i2c_client *client) +{ + u8 data[2]; + + if (max17042_read_reg(client, MAX17042_REG_FILTERCFG, data) < 0) + return; + + /* Clear average vcell (12 sec) */ + data[0] &= 0x8f; + + max17042_write_reg(client, MAX17042_REG_FILTERCFG, data); +} + +static void max17042_get_version(struct i2c_client *client) +{ + u8 data[2]; + + if (max17042_read_reg(client, MAX17042_REG_VERSION, data) < 0) + return; + + pr_debug("MAX17042 Fuel-Gauge Ver %d%d\n", data[0], data[1]); +} + +static void max17042_alert_init(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + + /* SALRT Threshold setting */ + data[0] = fuelgauge->pdata->fuel_alert_soc; + data[1] = 0xff; + max17042_write_reg(client, MAX17042_REG_SALRT_TH, data); + + /* VALRT Threshold setting */ + data[0] = 0x00; + data[1] = 0xff; + max17042_write_reg(client, MAX17042_REG_VALRT_TH, data); + + /* TALRT Threshold setting */ + data[0] = 0x80; + data[1] = 0x7f; + max17042_write_reg(client, MAX17042_REG_TALRT_TH, data); +} + +static bool max17042_check_status(struct i2c_client *client) +{ + u8 data[2]; + bool ret = false; + + /* check if Smn was generated */ + if (max17042_read_reg(client, MAX17042_REG_STATUS, data) < 0) + return ret; + + pr_info("%s : status_reg(%02x%02x)\n", __func__, data[1], data[0]); + + /* minimum SOC threshold exceeded. */ + if (data[1] & (0x1 << 2)) + ret = true; + + /* clear status reg */ + if (!ret) { + data[1] = 0; + max17042_write_reg(client, MAX17042_REG_STATUS, data); + msleep(200); + } + + return ret; +} + +static int max17042_set_temperature(struct i2c_client *client, int temperature) +{ + u8 data[2]; + + data[0] = 0; + data[1] = temperature; + max17042_write_reg(client, MAX17042_REG_TEMPERATURE, data); + + pr_debug("%s: temperature to (%d)\n", __func__, temperature); + + return temperature; +} + +static int max17042_get_temperature(struct i2c_client *client) +{ + u8 data[2]; + s32 temperature = 0; + + if (max17042_read_reg(client, MAX17042_REG_TEMPERATURE, data) < 0) + return -ERANGE; + + /* data[] store 2's compliment format number */ + if (data[1] & (0x1 << 7)) { + /* Negative */ + temperature = ((~(data[1])) & 0xFF) + 1; + temperature *= (-1000); + } else { + temperature = data[1] & 0x7F; + temperature *= 1000; + temperature += data[0] * 39 / 10; + } + + pr_debug("%s: temperature (%d)\n", __func__, temperature); + + return temperature; +} + +/* soc should be 0.1% unit */ +static int max17042_get_soc(struct i2c_client *client) +{ + u8 data[2]; + int soc; + + if (max17042_read_reg(client, MAX17042_REG_SOC_VF, data) < 0) + return -EINVAL; + + soc = ((data[1] * 100) + (data[0] * 100 / 256)) / 10; + + pr_debug("%s : raw capacity (%d)\n", __func__, soc); + + return min(soc, 1000); +} + +static int max17042_get_vfocv(struct i2c_client *client) +{ + u8 data[2]; + u32 vfocv = 0; + + if (max17042_read_reg(client, MAX17042_REG_VFOCV, data) < 0) + return -EINVAL; + + vfocv = ((data[0] >> 3) + (data[1] << 5)) * 625 / 1000; + + pr_debug("%s : vfocv (%d)\n", __func__, vfocv); + + return vfocv; +} + +static int max17042_get_vcell(struct i2c_client *client) +{ + u8 data[2]; + u32 vcell = 0; + + if (max17042_read_reg(client, MAX17042_REG_VCELL, data) < 0) + return -EINVAL; + + vcell = ((data[0] >> 3) + (data[1] << 5)) * 625 / 1000; + + pr_debug("%s : vcell (%d)\n", __func__, vcell); + + return vcell; +} + +static int max17042_get_avgvcell(struct i2c_client *client) +{ + u8 data[2]; + u32 avgvcell = 0; + + if (max17042_read_reg(client, MAX17042_REG_AVGVCELL, data) < 0) + return -EINVAL; + + avgvcell = ((data[0] >> 3) + (data[1] << 5)) * 625 / 1000; + + pr_debug("%s : avgvcell (%d)\n", __func__, avgvcell); + + return avgvcell; +} + +static int max17042_regs[] = { + MAX17042_REG_STATUS, /* 0x00 */ + MAX17042_REG_VALRT_TH, /* 0x01 */ + MAX17042_REG_TALRT_TH, /* 0x02 */ + MAX17042_REG_SALRT_TH, /* 0x03 */ + MAX17042_REG_TEMPERATURE, /* 0x08 */ + MAX17042_REG_VCELL, /* 0x09 */ + MAX17042_REG_AVGVCELL, /* 0x19 */ + MAX17042_REG_CONFIG, /* 0x1D */ + MAX17042_REG_VERSION, /* 0x21 */ + MAX17042_REG_LEARNCFG, /* 0x28 */ + MAX17042_REG_FILTERCFG, /* 0x29 */ + MAX17042_REG_MISCCFG, /* 0x2B */ + MAX17042_REG_CGAIN, /* 0x2E */ + MAX17042_REG_RCOMP, /* 0x38 */ + MAX17042_REG_VFOCV, /* 0xFB */ + MAX17042_REG_SOC_VF, /* 0xFF */ + -1, /* end */ +}; + +static void max17042_read_regs(struct i2c_client *client, char *str) +{ + int i; + u8 data = 0; + + for (i = 0; ; i++) { + if (max17042_regs[i] == -1) + break; + + max17042_read_reg(client, max17042_regs[i], &data); + sprintf(str+strlen(str), "%04xh, ", data); + } +} + +bool sec_hal_fg_init(struct i2c_client *client) +{ + /* initialize fuel gauge registers */ + max17042_init_regs(client); + + max17042_get_version(client); + + return true; +} + +bool sec_hal_fg_suspend(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_resume(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_fuelalert_init(struct i2c_client *client, int soc) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + + /* 1. Set max17042 alert configuration. */ + max17042_alert_init(client); + + if (max17042_read_reg(client, MAX17042_REG_CONFIG, data) + < 0) + return -1; + + /*Enable Alert (Aen = 1) */ + data[0] |= (0x1 << 2); + + max17042_write_reg(client, MAX17042_REG_CONFIG, data); + + pr_debug("%s : config_reg(%02x%02x) irq(%d)\n", + __func__, data[1], data[0], fuelgauge->pdata->fg_irq); + + return true; +} + +bool sec_hal_fg_is_fuelalerted(struct i2c_client *client) +{ + return max17042_check_status(client); +} + +bool sec_hal_fg_fuelalert_process(void *irq_data, bool is_fuel_alerted) +{ + struct sec_fuelgauge_info *fuelgauge = irq_data; + u8 data[2]; + + /* update SOC */ + /* max17042_get_soc(fuelgauge->client); */ + + if (is_fuel_alerted) { + if (max17042_read_reg(fuelgauge->client, + MAX17042_REG_CONFIG, data) < 0) + return false; + + data[1] |= (0x1 << 3); + + max17042_write_reg(fuelgauge->client, + MAX17042_REG_CONFIG, data); + + pr_info("%s: Fuel-alert Alerted!! (%02x%02x)\n", + __func__, data[1], data[0]); + } else { + if (max17042_read_reg(fuelgauge->client, + MAX17042_REG_CONFIG, data) + < 0) + return false; + + data[1] &= (~(0x1 << 3)); + + max17042_write_reg(fuelgauge->client, + MAX17042_REG_CONFIG, data); + + pr_info("%s: Fuel-alert Released!! (%02x%02x)\n", + __func__, data[1], data[0]); + } + + max17042_read_reg(fuelgauge->client, MAX17042_REG_VCELL, data); + pr_debug("%s : MAX17042_REG_VCELL(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_TEMPERATURE, data); + pr_debug("%s : MAX17042_REG_TEMPERATURE(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_CONFIG, data); + pr_debug("%s : MAX17042_REG_CONFIG(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_VFOCV, data); + pr_debug("%s : MAX17042_REG_VFOCV(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_SOC_VF, data); + pr_debug("%s : MAX17042_REG_SOC_VF(%02x%02x)\n", + __func__, data[1], data[0]); + + pr_debug("%s : FUEL GAUGE IRQ (%d)\n", + __func__, gpio_get_value(fuelgauge->pdata->fg_irq)); + +#if 0 + max17042_read_reg(fuelgauge->client, MAX17042_REG_STATUS, data); + pr_debug("%s : MAX17042_REG_STATUS(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_VALRT_TH, data); + pr_debug("%s : MAX17042_REG_VALRT_TH(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_TALRT_TH, data); + pr_debug("%s : MAX17042_REG_TALRT_TH(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_SALRT_TH, data); + pr_debug("%s : MAX17042_REG_SALRT_TH(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_AVGVCELL, data); + pr_debug("%s : MAX17042_REG_AVGVCELL(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_VERSION, data); + pr_debug("%s : MAX17042_REG_VERSION(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_LEARNCFG, data); + pr_debug("%s : MAX17042_REG_LEARNCFG(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_MISCCFG, data); + pr_debug("%s : MAX17042_REG_MISCCFG(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_CGAIN, data); + pr_debug("%s : MAX17042_REG_CGAIN(%02x%02x)\n", + __func__, data[1], data[0]); + + max17042_read_reg(fuelgauge->client, MAX17042_REG_RCOMP, data); + pr_debug("%s : MAX17042_REG_RCOMP(%02x%02x)\n", + __func__, data[1], data[0]); +#endif + + return true; +} + +bool sec_hal_fg_full_charged(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_get_property(struct i2c_client *client, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + /* Cell voltage (VCELL, mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = max17042_get_vcell(client); + break; + /* Additional Voltage Information (mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + switch (val->intval) { + case SEC_BATTEY_VOLTAGE_AVERAGE: + val->intval = max17042_get_avgvcell(client); + break; + case SEC_BATTEY_VOLTAGE_OCV: + val->intval = max17042_get_vfocv(client); + break; + } + break; + /* Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = 0; + break; + /* Average Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = 0; + break; + /* SOC (%) */ + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = max17042_get_soc(client); + break; + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + val->intval = max17042_get_temperature(client); + break; + default: + return false; + } + return true; +} + +bool sec_hal_fg_set_property(struct i2c_client *client, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + break; + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + max17042_set_temperature(client, val->intval); + break; + default: + return false; + } + return true; +} + +ssize_t sec_hal_fg_show_attrs(struct device *dev, + const ptrdiff_t offset, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int i = 0; + char *str = NULL; + + switch (offset) { +/* case FG_REG: */ +/* break; */ + case FG_DATA: + i += scnprintf(buf + i, PAGE_SIZE - i, "%02x%02x\n", + fg->reg_data[1], fg->reg_data[0]); + break; + case FG_REGS: + str = kzalloc(sizeof(char)*1024, GFP_KERNEL); + if (!str) + return -ENOMEM; + + max17042_read_regs(fg->client, str); + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", + str); + + kfree(str); + break; + default: + i = -EINVAL; + break; + } + + return i; +} + +ssize_t sec_hal_fg_store_attrs(struct device *dev, + const ptrdiff_t offset, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int ret = 0; + int x = 0; + u8 data[2]; + + switch (offset) { + case FG_REG: + if (sscanf(buf, "%x\n", &x) == 1) { + fg->reg_addr = x; + max17042_read_reg(fg->client, + fg->reg_addr, fg->reg_data); + pr_debug("%s: (read) addr = 0x%x, data = 0x%02x%02x\n", + __func__, fg->reg_addr, + fg->reg_data[1], fg->reg_data[0]); + } + ret = count; + break; + case FG_DATA: + if (sscanf(buf, "%x\n", &x) == 1) { + data[0] = (x & 0xFF00) >> 8; + data[1] = (x & 0x00FF); + pr_debug("%s: (write) addr = 0x%x, data = 0x%02x%02x\n", + __func__, fg->reg_addr, + data[1], data[0]); + max17042_write_reg(fg->client, + fg->reg_addr, data); + } + ret = count; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +#endif + +#ifdef CONFIG_FUELGAUGE_MAX17042_COULOMB_COUNTING +static int fg_get_battery_type(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + + return fuelgauge->info.battery_type; +} + +static int fg_i2c_read(struct i2c_client *client, + u8 reg, u8 *data, u8 length) +{ + s32 value; + + value = i2c_smbus_read_i2c_block_data(client, reg, length, data); + if (value < 0 || value != length) { + pr_err("%s: Failed to fg_i2c_read. status = %d\n", + __func__, value); + return -1; + } + + return 0; +} + +static int fg_i2c_write(struct i2c_client *client, + u8 reg, u8 *data, u8 length) +{ + s32 value; + + value = i2c_smbus_write_i2c_block_data(client, reg, length, data); + if (value < 0) { + pr_err("%s: Failed to fg_i2c_write, error code=%d\n", + __func__, value); + return -1; + } + + return 0; +} + +static int fg_read_register(struct i2c_client *client, + u8 addr) +{ + u8 data[2]; + + if (fg_i2c_read(client, addr, data, 2) < 0) { + pr_err("%s: Failed to read addr(0x%x)\n", __func__, addr); + return -1; + } + + return (data[1] << 8) | data[0]; +} + +static int fg_write_register(struct i2c_client *client, + u8 addr, u16 w_data) +{ + u8 data[2]; + + data[0] = w_data & 0xFF; + data[1] = w_data >> 8; + + if (fg_i2c_write(client, addr, data, 2) < 0) { + pr_err("%s: Failed to write addr(0x%x)\n", __func__, addr); + return -1; + } + + return 0; +} + +static int fg_read_16register(struct i2c_client *client, + u8 addr, u16 *r_data) +{ + u8 data[32]; + int i = 0; + + if (fg_i2c_read(client, addr, data, 32) < 0) { + pr_err("%s: Failed to read addr(0x%x)\n", __func__, addr); + return -1; + } + + for (i = 0; i < 16; i++) + r_data[i] = (data[2 * i + 1] << 8) | data[2 * i]; + + return 0; +} + +static void fg_write_and_verify_register(struct i2c_client *client, + u8 addr, u16 w_data) +{ + u16 r_data; + u8 retry_cnt = 2; + + while (retry_cnt) { + fg_write_register(client, addr, w_data); + r_data = fg_read_register(client, addr); + + if (r_data != w_data) { + pr_err("%s: verification failed (addr : 0x%x, w_data : 0x%x, r_data : 0x%x)\n", + __func__, addr, w_data, r_data); + retry_cnt--; + } else + break; + } +} + +static void fg_test_print(struct i2c_client *client) +{ + u8 data[2]; + u32 average_vcell; + u16 w_data; + u32 temp; + u32 temp2; + u16 reg_data; + + if (fg_i2c_read(client, AVR_VCELL_REG, data, 2) < 0) { + pr_err("%s: Failed to read VCELL\n", __func__); + return; + } + + w_data = (data[1]<<8) | data[0]; + + temp = (w_data & 0xFFF) * 78125; + average_vcell = temp / 1000000; + + temp = ((w_data & 0xF000) >> 4) * 78125; + temp2 = temp / 1000000; + average_vcell += (temp2 << 4); + + pr_info("%s : AVG_VCELL(%d), data(0x%04x)\n", __func__, + average_vcell, (data[1]<<8) | data[0]); + + reg_data = fg_read_register(client, FULLCAP_REG); + pr_info("%s : FULLCAP(%d), data(0x%04x)\n", __func__, + reg_data/2, reg_data); + + reg_data = fg_read_register(client, REMCAP_REP_REG); + pr_info("%s : REMCAP_REP(%d), data(0x%04x)\n", __func__, + reg_data/2, reg_data); + + reg_data = fg_read_register(client, REMCAP_MIX_REG); + pr_info("%s : REMCAP_MIX(%d), data(0x%04x)\n", __func__, + reg_data/2, reg_data); + + reg_data = fg_read_register(client, REMCAP_AV_REG); + pr_info("%s : REMCAP_AV(%d), data(0x%04x)\n", __func__, + reg_data/2, reg_data); + +} + +static void fg_periodic_read(struct i2c_client *client) +{ + u8 reg; + int i; + int data[0x10]; + + for (i = 0; i < 16; i++) { + for (reg = 0; reg < 0x10; reg++) + data[reg] = fg_read_register(client, reg + i * 0x10); + + pr_debug("%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,", + data[0x00], data[0x01], data[0x02], data[0x03], + data[0x04], data[0x05], data[0x06], data[0x07]); + pr_debug("%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,", + data[0x08], data[0x09], data[0x0a], data[0x0b], + data[0x0c], data[0x0d], data[0x0e], data[0x0f]); + if (i == 4) + i = 13; + } + pr_debug("\n"); +} + +static void fg_read_regs(struct i2c_client *client, char *str) +{ + u8 reg; + int i; + int data[0x10]; + + for (i = 0; i < 16; i++) { + for (reg = 0; reg < 0x10; reg++) + data[reg] = fg_read_register(client, reg + i * 0x10); + + sprintf(str, "%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,", + data[0x00], data[0x01], data[0x02], data[0x03], + data[0x04], data[0x05], data[0x06], data[0x07]); + sprintf(str, "%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,", + data[0x08], data[0x09], data[0x0a], data[0x0b], + data[0x0c], data[0x0d], data[0x0e], data[0x0f]); + if (i == 4) + i = 13; + } +} + +static int fg_read_vcell(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + u32 vcell; + u16 w_data; + u32 temp; + u32 temp2; + + if (fg_i2c_read(client, VCELL_REG, data, 2) < 0) { + pr_err("%s: Failed to read VCELL\n", __func__); + return -1; + } + + w_data = (data[1]<<8) | data[0]; + + temp = (w_data & 0xFFF) * 78125; + vcell = temp / 1000000; + + temp = ((w_data & 0xF000) >> 4) * 78125; + temp2 = temp / 1000000; + vcell += (temp2 << 4); + + if (!(fuelgauge->info.pr_cnt % PRINT_COUNT)) + pr_info("%s : VCELL(%d), data(0x%04x)\n", + __func__, vcell, (data[1]<<8) | data[0]); + + return vcell; +} + +static int fg_read_vfocv(struct i2c_client *client) +{ + u8 data[2]; + u32 vfocv = 0; + u16 w_data; + u32 temp; + u32 temp2; + + if (fg_i2c_read(client, VFOCV_REG, data, 2) < 0) { + pr_err("%s: Failed to read VFOCV\n", __func__); + return -1; + } + + w_data = (data[1]<<8) | data[0]; + + temp = (w_data & 0xFFF) * 78125; + vfocv = temp / 1000000; + + temp = ((w_data & 0xF000) >> 4) * 78125; + temp2 = temp / 1000000; + vfocv += (temp2 << 4); + + return vfocv; +} + +static int fg_check_battery_present(struct i2c_client *client) +{ + u8 status_data[2]; + int ret = 1; + + /* 1. Check Bst bit */ + if (fg_i2c_read(client, STATUS_REG, status_data, 2) < 0) { + pr_err("%s: Failed to read STATUS_REG\n", __func__); + return 0; + } + + if (status_data[0] & (0x1 << 3)) { + pr_info("%s - addr(0x01), data(0x%04x)\n", __func__, + (status_data[1]<<8) | status_data[0]); + pr_info("%s : battery is absent!!\n", __func__); + ret = 0; + } + + return ret; +} + + +static int fg_read_temp(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + int temper = 0; + + if (fg_check_battery_present(client)) { + if (fg_i2c_read(client, TEMPERATURE_REG, data, 2) < 0) { + pr_err("%s: Failed to read TEMPERATURE_REG\n", + __func__); + return -1; + } + + if (data[1]&(0x1 << 7)) { + temper = ((~(data[1]))&0xFF)+1; + temper *= (-1000); + } else { + temper = data[1] & 0x7f; + temper *= 1000; + temper += data[0] * 39 / 10; + + /* Adjust temperature over 47, + * only for SDI battery type + */ + if (fg_get_battery_type(client) == SDI_BATTERY_TYPE) { + if (temper >= 47000 && temper < 60000) + temper = (temper * SDI_TRIM1_1 / 100) - + SDI_TRIM1_2; + else if (temper >= 60000) + temper = (temper * SDI_TRIM2_1 / 100) - + 51000; + } + } + } else + temper = 20000; + + if (!(fuelgauge->info.pr_cnt % PRINT_COUNT)) + pr_info("%s : TEMPERATURE(%d), data(0x%04x)\n", __func__, + temper, (data[1]<<8) | data[0]); + + return temper/100; +} + +static int fg_read_vfsoc(struct i2c_client *client) +{ + u8 data[2]; + int soc; + + if (fg_i2c_read(client, VFSOC_REG, data, 2) < 0) { + pr_err("%s: Failed to read VFSOC\n", __func__); + return -1; + } + + soc = ((data[1] * 100) + (data[0] * 100 / 256)) / 10; + + return min(soc, 1000); +} + +/* soc should be 0.1% unit */ +static int fg_read_soc(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + int soc; + + if (fg_i2c_read(client, SOCREP_REG, data, 2) < 0) { + pr_err("%s: Failed to read SOCREP\n", __func__); + return -1; + } + + soc = ((data[1] * 100) + (data[0] * 100 / 256)) / 10; + + pr_debug("%s : raw capacity (%d)\n", __func__, soc); + + if (!(fuelgauge->info.pr_cnt % PRINT_COUNT)) + pr_debug("%s : raw capacity (%d), data(0x%04x)\n", + __func__, soc, (data[1]<<8) | data[0]); + + return min(soc, 1000); +} + +static int fg_read_current(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data1[2], data2[2]; + u32 temp, sign; + s32 i_current; + s32 avg_current; + + if (fg_i2c_read(client, CURRENT_REG, data1, 2) < 0) { + pr_err("%s: Failed to read CURRENT\n", __func__); + return -1; + } + + if (fg_i2c_read(client, AVG_CURRENT_REG, data2, 2) < 0) { + pr_err("%s: Failed to read AVERAGE CURRENT\n", __func__); + return -1; + } + + temp = ((data1[1]<<8) | data1[0]) & 0xFFFF; + if (temp & (0x1 << 15)) { + sign = NEGATIVE; + temp = (~temp & 0xFFFF) + 1; + } else + sign = POSITIVE; + + /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ + i_current = temp * 15625 / 100000; + if (sign) + i_current *= -1; + + temp = ((data2[1]<<8) | data2[0]) & 0xFFFF; + if (temp & (0x1 << 15)) { + sign = NEGATIVE; + temp = (~temp & 0xFFFF) + 1; + } else + sign = POSITIVE; + + /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ + avg_current = temp * 15625 / 100000; + if (sign) + avg_current *= -1; + + if (!(fuelgauge->info.pr_cnt++ % PRINT_COUNT)) { + fg_test_print(client); + pr_info("%s : CURRENT(%dmA), AVG_CURRENT(%dmA)\n", __func__, + i_current, avg_current); + fuelgauge->info.pr_cnt = 1; + /* Read max17042's all registers every 5 minute. */ + fg_periodic_read(client); + } + + return i_current; +} + +static int fg_read_avg_current(struct i2c_client *client) +{ + u8 data2[2]; + u32 temp, sign; + s32 avg_current; + + if (fg_i2c_read(client, AVG_CURRENT_REG, data2, 2) < 0) { + pr_err("%s: Failed to read AVERAGE CURRENT\n", __func__); + return -1; + } + + temp = ((data2[1]<<8) | data2[0]) & 0xFFFF; + if (temp & (0x1 << 15)) { + sign = NEGATIVE; + temp = (~temp & 0xFFFF) + 1; + } else + sign = POSITIVE; + + /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ + avg_current = temp * 15625 / 100000; + + if (sign) + avg_current *= -1; + + return avg_current; +} + +int fg_reset_soc(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + + /* delay for current stablization */ + msleep(500); + + pr_info("%s : Before quick-start - VCELL(%d), VFOCV(%d), VfSOC(%d), RepSOC(%d)\n", + __func__, fg_read_vcell(client), fg_read_vfocv(client), + fg_read_vfsoc(client), fg_read_soc(client)); + pr_info("%s : Before quick-start - current(%d), avg current(%d)\n", + __func__, fg_read_current(client), + fg_read_avg_current(client)); + + if (!fuelgauge->pdata->check_jig_status()) { + pr_info("%s : Return by No JIG_ON signal\n", __func__); + return 0; + } + + fg_write_register(client, CYCLES_REG, 0); + + if (fg_i2c_read(client, MISCCFG_REG, data, 2) < 0) { + pr_err("%s: Failed to read MiscCFG\n", __func__); + return -1; + } + + data[1] |= (0x1 << 2); + if (fg_i2c_write(client, MISCCFG_REG, data, 2) < 0) { + pr_err("%s: Failed to write MiscCFG\n", __func__); + return -1; + } + + msleep(250); + fg_write_register(client, FULLCAP_REG, fuelgauge->info.capacity); + msleep(500); + + pr_info("%s : After quick-start - VCELL(%d), VFOCV(%d), VfSOC(%d), RepSOC(%d)\n", + __func__, fg_read_vcell(client), fg_read_vfocv(client), + fg_read_vfsoc(client), fg_read_soc(client)); + pr_info("%s : After quick-start - current(%d), avg current(%d)\n", + __func__, fg_read_current(client), + fg_read_avg_current(client)); + fg_write_register(client, CYCLES_REG, 0x00a0); + +/* P8 is not turned off by Quickstart @3.4V + * (It's not a problem, depend on mode data) + * Power off for factory test(File system, etc..) */ +#if defined(CONFIG_MACH_P8_REV00) || defined(CONFIG_MACH_P8_REV01) || \ + defined(CONFIG_MACH_P8LTE_REV00) +#define QUICKSTART_POWER_OFF_VOLTAGE 3400 + vfocv = fg_read_vfocv(client); + if (vfocv < QUICKSTART_POWER_OFF_VOLTAGE) { + pr_info("%s: Power off condition(%d)\n", __func__, vfocv); + + fullcap = fg_read_register(client, FULLCAP_REG); + /* FullCAP * 0.009 */ + fg_write_register(client, REMCAP_REP_REG, + (u16)(fullcap * 9 / 1000)); + msleep(200); + pr_info("%s : new soc=%d, vfocv=%d\n", __func__, + fg_read_soc(client), vfocv); + } + + pr_info("%s : Additional step - VfOCV(%d), VfSOC(%d), RepSOC(%d)\n", + __func__, fg_read_vfocv(client), + fg_read_vfsoc(client), fg_read_soc(client)); +#endif + + return 0; +} + + +int fg_reset_capacity(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + + return fg_write_register(client, DESIGNCAP_REG, + fuelgauge->info.vfcapacity-1); +} + +int fg_adjust_capacity(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + + data[0] = 0; + data[1] = 0; + + /* 1. Write RemCapREP(05h)=0; */ + if (fg_i2c_write(client, REMCAP_REP_REG, data, 2) < 0) { + pr_err("%s: Failed to write RemCap_REP\n", __func__); + return -1; + } + msleep(200); + + pr_info("%s : After adjust - RepSOC(%d)\n", __func__, + fg_read_soc(client)); + + fuelgauge->info.soc_restart_flag = 1; + + return 0; +} + +void fg_low_batt_compensation(struct i2c_client *client, u32 level) +{ + int read_val; + u32 temp; + + pr_info("%s : Adjust SOCrep to %d!!\n", __func__, level); + + read_val = fg_read_register(client, FULLCAP_REG); + if (read_val < 0) + return; + + if (read_val > 2) /* 3% compensation */ + /* RemCapREP (05h) = FullCap(10h) x 0.0301 */ + temp = read_val * (level*100 + 1) / 10000; + else /* 1% compensation */ + /* RemCapREP (05h) = FullCap(10h) x 0.0090 */ + temp = read_val * (level*90) / 10000; + fg_write_register(client, REMCAP_REP_REG, (u16)temp); + + /* fuelgauge->info.low_batt_comp_flag = 1; */ +} + +static void fg_read_model_data(struct i2c_client *client) +{ + u16 data0[16], data1[16], data2[16]; + int i; + int relock_check; + + pr_info("[FG_Model] "); + + /* Unlock model access */ + fg_write_register(client, 0x62, 0x0059); + fg_write_register(client, 0x63, 0x00C4); + + /* Read model data */ + fg_read_16register(client, 0x80, data0); + fg_read_16register(client, 0x90, data1); + fg_read_16register(client, 0xa0, data2); + + /* Print model data */ + for (i = 0; i < 16; i++) + pr_info("0x%04x, ", data0[i]); + + for (i = 0; i < 16; i++) + pr_info("0x%04x, ", data1[i]); + + for (i = 0; i < 16; i++) { + if (i == 15) + pr_info("0x%04x", data2[i]); + else + pr_info("0x%04x, ", data2[i]); + } + + do { + relock_check = 0; + /* Lock model access */ + fg_write_register(client, 0x62, 0x0000); + fg_write_register(client, 0x63, 0x0000); + + /* Read model data again */ + fg_read_16register(client, 0x80, data0); + fg_read_16register(client, 0x90, data1); + fg_read_16register(client, 0xa0, data2); + + for (i = 0; i < 16; i++) { + if (data0[i] || data1[i] || data2[i]) { + pr_info("%s : data is non-zero, lock again!!\n", + __func__); + relock_check = 1; + } + } + } while (relock_check); + +} + +int fg_alert_init(struct i2c_client *client) +{ + u8 misccgf_data[2]; + u8 salrt_data[2]; + u8 config_data[2]; + u8 valrt_data[2]; + u8 talrt_data[2]; + u16 read_data = 0; + + /* Using RepSOC */ + if (fg_i2c_read(client, MISCCFG_REG, misccgf_data, 2) < 0) { + pr_err("%s: Failed to read MISCCFG_REG\n", __func__); + return -1; + } + misccgf_data[0] = misccgf_data[0] & ~(0x03); + + if (fg_i2c_write(client, MISCCFG_REG, misccgf_data, 2) < 0) { + pr_info("%s: Failed to write MISCCFG_REG\n", __func__); + return -1; + } + + /* SALRT Threshold setting */ + salrt_data[1] = 0xff; + salrt_data[0] = 0x01; + if (fg_i2c_write(client, SALRT_THRESHOLD_REG, salrt_data, 2) < 0) { + pr_info("%s: Failed to write SALRT_THRESHOLD_REG\n", __func__); + return -1; + } + + /* Reset VALRT Threshold setting (disable) */ + valrt_data[1] = 0xFF; + valrt_data[0] = 0x00; + if (fg_i2c_write(client, VALRT_THRESHOLD_REG, valrt_data, 2) < 0) { + pr_info("%s: Failed to write VALRT_THRESHOLD_REG\n", __func__); + return -1; + } + + read_data = fg_read_register(client, (u8)VALRT_THRESHOLD_REG); + if (read_data != 0xff00) + pr_err("%s : VALRT_THRESHOLD_REG is not valid (0x%x)\n", + __func__, read_data); + + /* Reset TALRT Threshold setting (disable) */ + talrt_data[1] = 0x7F; + talrt_data[0] = 0x80; + if (fg_i2c_write(client, TALRT_THRESHOLD_REG, talrt_data, 2) < 0) { + pr_info("%s: Failed to write TALRT_THRESHOLD_REG\n", __func__); + return -1; + } + + read_data = fg_read_register(client, (u8)TALRT_THRESHOLD_REG); + if (read_data != 0x7f80) + pr_err("%s : TALRT_THRESHOLD_REG is not valid (0x%x)\n", + __func__, read_data); + + mdelay(100); + + /* Enable SOC alerts */ + if (fg_i2c_read(client, CONFIG_REG, config_data, 2) < 0) { + pr_err("%s: Failed to read CONFIG_REG\n", __func__); + return -1; + } + config_data[0] = config_data[0] | (0x1 << 2); + + if (fg_i2c_write(client, CONFIG_REG, config_data, 2) < 0) { + pr_info("%s: Failed to write CONFIG_REG\n", __func__); + return -1; + } + + return 1; +} + +static int fg_check_status_reg(struct i2c_client *client) +{ + u8 status_data[2]; + int ret = 0; + + /* 1. Check Smn was generatedread */ + if (fg_i2c_read(client, STATUS_REG, status_data, 2) < 0) { + pr_err("%s: Failed to read STATUS_REG\n", __func__); + return -1; + } + pr_info("%s - addr(0x00), data(0x%04x)\n", __func__, + (status_data[1]<<8) | status_data[0]); + + if (status_data[1] & (0x1 << 2)) + ret = 1; + + /* 2. clear Status reg */ + status_data[1] = 0; + if (fg_i2c_write(client, STATUS_REG, status_data, 2) < 0) { + pr_info("%s: Failed to write STATUS_REG\n", __func__); + return -1; + } + + return ret; +} + +void fg_fullcharged_compensation(struct i2c_client *client, + u32 is_recharging, u32 pre_update) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + static int new_fullcap_data; + + pr_info("%s : is_recharging(%d), pre_update(%d)\n", + __func__, is_recharging, pre_update); + + new_fullcap_data = + fg_read_register(client, FULLCAP_REG); + if (new_fullcap_data < 0) + new_fullcap_data = fuelgauge->info.capacity; + + if (new_fullcap_data > + (fuelgauge->info.capacity * 110 / 100)) { + pr_info("%s : [Case 1] previous_fullcap = 0x%04x, NewFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_fullcap, + new_fullcap_data); + + new_fullcap_data = + (fuelgauge->info.capacity * 110) / 100; + fg_write_register(client, REMCAP_REP_REG, + (u16)(new_fullcap_data)); + fg_write_register(client, FULLCAP_REG, + (u16)(new_fullcap_data)); + } else if (new_fullcap_data < + (fuelgauge->info.capacity * 70 / 100)) { + pr_info("%s : [Case 5] previous_fullcap = 0x%04x, NewFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_fullcap, + new_fullcap_data); + + new_fullcap_data = + (fuelgauge->info.capacity * 70) / 100; + fg_write_register(client, REMCAP_REP_REG, + (u16)(new_fullcap_data)); + fg_write_register(client, FULLCAP_REG, + (u16)(new_fullcap_data)); + } else { + if (new_fullcap_data > + (fuelgauge->info.previous_fullcap * 105 / 100)) { + pr_info("%s : [Case 2] previous_fullcap = 0x%04x, NewFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_fullcap, + new_fullcap_data); + + new_fullcap_data = + (fuelgauge->info.previous_fullcap * 105) / 100; + fg_write_register(client, REMCAP_REP_REG, + (u16)(new_fullcap_data)); + fg_write_register(client, FULLCAP_REG, + (u16)(new_fullcap_data)); + } else if (new_fullcap_data < + (fuelgauge->info.previous_fullcap * 90 / 100)) { + pr_info("%s : [Case 3] previous_fullcap = 0x%04x, NewFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_fullcap, + new_fullcap_data); + + new_fullcap_data = + (fuelgauge->info.previous_fullcap * 90) / 100; + fg_write_register(client, REMCAP_REP_REG, + (u16)(new_fullcap_data)); + fg_write_register(client, FULLCAP_REG, + (u16)(new_fullcap_data)); + } else { + pr_info("%s : [Case 4] previous_fullcap = 0x%04x, NewFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_fullcap, + new_fullcap_data); + } + } + + /* 4. Write RepSOC(06h)=100%; */ + fg_write_register(client, SOCREP_REG, (u16)(0x64 << 8)); + + /* 5. Write MixSOC(0Dh)=100%; */ + fg_write_register(client, SOCMIX_REG, (u16)(0x64 << 8)); + + /* 6. Write AVSOC(0Eh)=100%; */ + fg_write_register(client, SOCAV_REG, (u16)(0x64 << 8)); + + /* if pre_update case, skip updating PrevFullCAP value. */ + if (!pre_update) + fuelgauge->info.previous_fullcap = + fg_read_register(client, FULLCAP_REG); + + pr_info("%s : (A) FullCap = 0x%04x, RemCap = 0x%04x\n", __func__, + fg_read_register(client, FULLCAP_REG), + fg_read_register(client, REMCAP_REP_REG)); + + fg_periodic_read(client); + +} + +void fg_check_vf_fullcap_range(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + static int new_vffullcap; + u16 print_flag = 1; + + new_vffullcap = fg_read_register(client, FULLCAP_NOM_REG); + if (new_vffullcap < 0) + new_vffullcap = fuelgauge->info.vfcapacity; + + if (new_vffullcap > + (fuelgauge->info.vfcapacity * 110 / 100)) { + pr_info("%s : [Case 1] previous_vffullcap = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_vffullcap, + new_vffullcap); + + new_vffullcap = + (fuelgauge->info.vfcapacity * 110) / 100; + + fg_write_register(client, DQACC_REG, + (u16)(new_vffullcap / 4)); + fg_write_register(client, DPACC_REG, (u16)0x3200); + } else if (new_vffullcap < + (fuelgauge->info.vfcapacity * 70 / 100)) { + pr_info("%s : [Case 5] previous_vffullcap = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_vffullcap, + new_vffullcap); + + new_vffullcap = + (fuelgauge->info.vfcapacity * 70) / 100; + + fg_write_register(client, DQACC_REG, + (u16)(new_vffullcap / 4)); + fg_write_register(client, DPACC_REG, (u16)0x3200); + } else { + if (new_vffullcap > + (fuelgauge->info.previous_vffullcap * 105 / 100)) { + pr_info("%s : [Case 2] previous_vffullcap = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_vffullcap, + new_vffullcap); + + new_vffullcap = + (fuelgauge->info.previous_vffullcap * 105) / + 100; + + fg_write_register(client, DQACC_REG, + (u16)(new_vffullcap / 4)); + fg_write_register(client, DPACC_REG, (u16)0x3200); + } else if (new_vffullcap < + (fuelgauge->info.previous_vffullcap * 90 / 100)) { + pr_info("%s : [Case 3] previous_vffullcap = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_vffullcap, + new_vffullcap); + + new_vffullcap = + (fuelgauge->info.previous_vffullcap * 90) / 100; + + fg_write_register(client, DQACC_REG, + (u16)(new_vffullcap / 4)); + fg_write_register(client, DPACC_REG, (u16)0x3200); + } else { + pr_info("%s : [Case 4] previous_vffullcap = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_vffullcap, + new_vffullcap); + print_flag = 0; + } + } + + /* delay for register setting (dQacc, dPacc) */ + if (print_flag) + msleep(300); + + fuelgauge->info.previous_vffullcap = + fg_read_register(client, FULLCAP_NOM_REG); + + if (print_flag) + pr_info("%s : VfFullCap(0x%04x), dQacc(0x%04x), dPacc(0x%04x)\n", + __func__, + fg_read_register(client, FULLCAP_NOM_REG), + fg_read_register(client, DQACC_REG), + fg_read_register(client, DPACC_REG)); + +} + +int fg_check_cap_corruption(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + int vfsoc = fg_read_vfsoc(client); + int repsoc = fg_read_soc(client); + int mixcap = fg_read_register(client, REMCAP_MIX_REG); + int vfocv = fg_read_register(client, VFOCV_REG); + int remcap = fg_read_register(client, REMCAP_REP_REG); + int fullcapacity = fg_read_register(client, FULLCAP_REG); + int vffullcapacity = fg_read_register(client, FULLCAP_NOM_REG); + u32 temp, temp2, new_vfocv, pr_vfocv; + int ret = 0; + + /* If usgin Jig or low batt compensation flag is set, + * then skip checking. + */ + if (fuelgauge->pdata->check_jig_status()) { + pr_info("%s : Return by Using Jig(%d)\n", __func__, + fuelgauge->pdata->check_jig_status()); + return 0; + } + + if (vfsoc < 0 || repsoc < 0 || mixcap < 0 || vfocv < 0 || + remcap < 0 || fullcapacity < 0 || vffullcapacity < 0) + return 0; + + /* Check full charge learning case. */ + if (((vfsoc >= 90) && ((remcap >= (fullcapacity * 995 / 1000)) && + (remcap <= (fullcapacity * 1005 / 1000)))) || + fuelgauge->info.low_batt_comp_flag || + fuelgauge->info.soc_restart_flag) { + pr_info("%s : RemCap(%d), FullCap(%d), SOC(%d), ", + __func__, (remcap/2), + (fullcapacity/2), repsoc); + pr_info("low_batt_comp_flag(%d), soc_restart_flag(%d)\n", + fuelgauge->info.low_batt_comp_flag, + fuelgauge->info.soc_restart_flag); + fuelgauge->info.previous_repsoc = repsoc; + fuelgauge->info.previous_remcap = remcap; + fuelgauge->info.previous_fullcapacity = fullcapacity; + if (fuelgauge->info.soc_restart_flag) + fuelgauge->info.soc_restart_flag = 0; + + ret = 1; + } + + /* ocv calculation for print */ + temp = (vfocv & 0xFFF) * 78125; + pr_vfocv = temp / 1000000; + + temp = ((vfocv & 0xF000) >> 4) * 78125; + temp2 = temp / 1000000; + pr_vfocv += (temp2 << 4); + + /* MixCap differ is greater than 265mAh */ + if ((((vfsoc+5) < fuelgauge->info.previous_vfsoc) || + (vfsoc > (fuelgauge->info.previous_vfsoc+5))) || + (((repsoc+5) < fuelgauge->info.previous_repsoc) || + (repsoc > (fuelgauge->info.previous_repsoc+5))) || + (((mixcap+530) < fuelgauge->info.previous_mixcap) || + (mixcap > (fuelgauge->info.previous_mixcap+530)))) { + fg_periodic_read(client); + + pr_info("[FG_Recovery] (B) VfSOC(%d), prevVfSOC(%d), RepSOC(%d), prevRepSOC(%d), MixCap(%d), prevMixCap(%d),VfOCV(0x%04x, %d)\n", + vfsoc, + fuelgauge->info.previous_vfsoc, + repsoc, fuelgauge->info.previous_repsoc, + (mixcap/2), + (fuelgauge->info.previous_mixcap/2), + vfocv, + pr_vfocv); + + mutex_lock(&fuelgauge->fg_lock); + + fg_write_and_verify_register(client, REMCAP_MIX_REG, + fuelgauge->info.previous_mixcap); + fg_write_register(client, VFOCV_REG, + fuelgauge->info.previous_vfocv); + mdelay(200); + + fg_write_and_verify_register(client, REMCAP_REP_REG, + fuelgauge->info.previous_remcap); + vfsoc = fg_read_register(client, VFSOC_REG); + fg_write_register(client, 0x60, 0x0080); + fg_write_and_verify_register(client, 0x48, vfsoc); + fg_write_register(client, 0x60, 0x0000); + + fg_write_and_verify_register(client, 0x45, + (fuelgauge->info.previous_vfcapacity / 4)); + fg_write_and_verify_register(client, 0x46, 0x3200); + fg_write_and_verify_register(client, FULLCAP_REG, + fuelgauge->info.previous_fullcapacity); + fg_write_and_verify_register(client, FULLCAP_NOM_REG, + fuelgauge->info.previous_vfcapacity); + + mutex_unlock(&fuelgauge->fg_lock); + + msleep(200); + + /* ocv calculation for print */ + new_vfocv = fg_read_register(client, VFOCV_REG); + temp = (new_vfocv & 0xFFF) * 78125; + pr_vfocv = temp / 1000000; + + temp = ((new_vfocv & 0xF000) >> 4) * 78125; + temp2 = temp / 1000000; + pr_vfocv += (temp2 << 4); + + pr_info("[FG_Recovery] (A) newVfSOC(%d), newRepSOC(%d), newMixCap(%d), newVfOCV(0x%04x, %d)\n", + fg_read_vfsoc(client), + fg_read_soc(client), + (fg_read_register(client, REMCAP_MIX_REG)/2), + new_vfocv, + pr_vfocv); + + fg_periodic_read(client); + + ret = 1; + } else { + fuelgauge->info.previous_vfsoc = vfsoc; + fuelgauge->info.previous_repsoc = repsoc; + fuelgauge->info.previous_remcap = remcap; + fuelgauge->info.previous_mixcap = mixcap; + fuelgauge->info.previous_fullcapacity = fullcapacity; + fuelgauge->info.previous_vfcapacity = vffullcapacity; + fuelgauge->info.previous_vfocv = vfocv; + } + + return ret; +} + +void fg_set_full_charged(struct i2c_client *client) +{ + pr_info("[FG_Set_Full] (B) FullCAP(%d), RemCAP(%d)\n", + (fg_read_register(client, FULLCAP_REG)/2), + (fg_read_register(client, REMCAP_REP_REG)/2)); + + fg_write_register(client, FULLCAP_REG, + (u16)fg_read_register(client, REMCAP_REP_REG)); + + pr_info("[FG_Set_Full] (A) FullCAP(%d), RemCAP(%d)\n", + (fg_read_register(client, FULLCAP_REG)/2), + (fg_read_register(client, REMCAP_REP_REG)/2)); +} + +static void display_low_batt_comp_cnt(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 type_str[10]; + + if (fg_get_battery_type(client) == SDI_BATTERY_TYPE) + sprintf(type_str, "SDI"); + else if (fg_get_battery_type(client) == ATL_BATTERY_TYPE) + sprintf(type_str, "ATL"); + else + sprintf(type_str, "Unknown"); + + pr_info("Check Array(%s) : [%d, %d], [%d, %d], ", type_str, + fuelgauge->info.low_batt_comp_cnt[0][0], + fuelgauge->info.low_batt_comp_cnt[0][1], + fuelgauge->info.low_batt_comp_cnt[1][0], + fuelgauge->info.low_batt_comp_cnt[1][1]); + pr_info("[%d, %d], [%d, %d], [%d, %d]\n", + fuelgauge->info.low_batt_comp_cnt[2][0], + fuelgauge->info.low_batt_comp_cnt[2][1], + fuelgauge->info.low_batt_comp_cnt[3][0], + fuelgauge->info.low_batt_comp_cnt[3][1], + fuelgauge->info.low_batt_comp_cnt[4][0], + fuelgauge->info.low_batt_comp_cnt[4][1]); +} + +static void add_low_batt_comp_cnt(struct i2c_client *client, + int range, int level) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + int i; + int j; + + /* Increase the requested count value, and reset others. */ + fuelgauge->info.low_batt_comp_cnt[range-1][level/2]++; + + for (i = 0; i < LOW_BATT_COMP_RANGE_NUM; i++) { + for (j = 0; j < LOW_BATT_COMP_LEVEL_NUM; j++) { + if (i == range-1 && j == level/2) + continue; + else + fuelgauge->info.low_batt_comp_cnt[i][j] = 0; + } + } +} + +void prevent_early_poweroff(struct i2c_client *client, + int vcell, int *fg_soc) +{ + int repsoc, repsoc_data = 0; + int read_val; + u8 data[2]; + + if (fg_i2c_read(client, SOCREP_REG, data, 2) < 0) { + pr_err("%s: Failed to read SOCREP\n", __func__); + return; + } + repsoc = data[1]; + repsoc_data = ((data[1] << 8) | data[0]); + + if (repsoc_data > POWER_OFF_SOC_HIGH_MARGIN) + return; + + pr_info("%s : soc=%d%%(0x%04x), vcell=%d\n", __func__, + repsoc, repsoc_data, vcell); + if (vcell > POWER_OFF_VOLTAGE_HIGH_MARGIN) { + read_val = fg_read_register(client, FULLCAP_REG); + /* FullCAP * 0.013 */ + fg_write_register(client, REMCAP_REP_REG, + (u16)(read_val * 13 / 1000)); + msleep(200); + *fg_soc = fg_read_soc(client); + pr_info("%s : new soc=%d, vcell=%d\n", __func__, + *fg_soc, vcell); + } +} + +void reset_low_batt_comp_cnt(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + + memset(fuelgauge->info.low_batt_comp_cnt, 0, + sizeof(fuelgauge->info.low_batt_comp_cnt)); +} + +static int check_low_batt_comp_condition( + struct i2c_client *client, int *nLevel) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + int i; + int j; + int ret = 0; + + for (i = 0; i < LOW_BATT_COMP_RANGE_NUM; i++) { + for (j = 0; j < LOW_BATT_COMP_LEVEL_NUM; j++) { + if (fuelgauge->info.low_batt_comp_cnt[i][j] >= + MAX_LOW_BATT_CHECK_CNT) { + display_low_batt_comp_cnt(client); + ret = 1; + *nLevel = j*2 + 1; + break; + } + } + } + + return ret; +} + +static int get_low_batt_threshold(struct i2c_client *client, + int range, int level, int nCurrent) +{ + int ret = 0; + + if (fg_get_battery_type(client) == SDI_BATTERY_TYPE) { + switch (range) { +/* P4W & P8 needs one more level */ +#if defined(CONFIG_MACH_P4W_REV00) || defined(CONFIG_MACH_P4W_REV01) || \ + defined(CONFIG_MACH_P8_REV00) || defined(CONFIG_MACH_P8_REV01) || \ + defined(CONFIG_MACH_P8LTE_REV00) + case 5: + if (level == 1) + ret = SDI_Range5_1_Offset + + ((nCurrent * SDI_Range5_1_Slope) / + 1000); + else if (level == 3) + ret = SDI_Range5_3_Offset + + ((nCurrent * SDI_Range5_3_Slope) / + 1000); + break; +#endif + case 4: + if (level == 1) + ret = SDI_Range4_1_Offset + + ((nCurrent * SDI_Range4_1_Slope) / + 1000); + else if (level == 3) + ret = SDI_Range4_3_Offset + + ((nCurrent * SDI_Range4_3_Slope) / + 1000); + break; + + case 3: + if (level == 1) + ret = SDI_Range3_1_Offset + + ((nCurrent * SDI_Range3_1_Slope) / + 1000); + else if (level == 3) + ret = SDI_Range3_3_Offset + + ((nCurrent * SDI_Range3_3_Slope) / + 1000); + break; + + case 2: + if (level == 1) + ret = SDI_Range2_1_Offset + + ((nCurrent * SDI_Range2_1_Slope) / + 1000); + else if (level == 3) + ret = SDI_Range2_3_Offset + + ((nCurrent * SDI_Range2_3_Slope) / + 1000); + break; + + case 1: + if (level == 1) + ret = SDI_Range1_1_Offset + + ((nCurrent * SDI_Range1_1_Slope) / + 1000); + else if (level == 3) + ret = SDI_Range1_3_Offset + + ((nCurrent * SDI_Range1_3_Slope) / + 1000); + break; + + default: + break; + } + } else if (fg_get_battery_type(client) == + ATL_BATTERY_TYPE) { + switch (range) { + case 4: + if (level == 1) + ret = ATL_Range4_1_Offset + + ((nCurrent * ATL_Range4_1_Slope) / + 1000); + else if (level == 3) + ret = ATL_Range4_3_Offset + + ((nCurrent * ATL_Range4_3_Slope) / + 1000); + break; + + case 3: + if (level == 1) + ret = ATL_Range3_1_Offset + + ((nCurrent * ATL_Range3_1_Slope) / + 1000); + else if (level == 3) + ret = ATL_Range3_3_Offset + + ((nCurrent * ATL_Range3_3_Slope) / + 1000); + break; + + case 2: + if (level == 1) + ret = ATL_Range2_1_Offset + + ((nCurrent * ATL_Range2_1_Slope) / + 1000); + else if (level == 3) + ret = ATL_Range2_3_Offset + + ((nCurrent * ATL_Range2_3_Slope) / + 1000); + break; + + case 1: + if (level == 1) + ret = ATL_Range1_1_Offset + + ((nCurrent * ATL_Range1_1_Slope) / + 1000); + else if (level == 3) + ret = ATL_Range1_3_Offset + + ((nCurrent * ATL_Range1_3_Slope) / + 1000); + break; + + default: + break; + } + } + + return ret; +} + +int low_batt_compensation(struct i2c_client *client, + int fg_soc, int fg_vcell, int fg_current) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + int fg_avg_current = 0; + int fg_min_current = 0; + int new_level = 0; + int bCntReset = 0; + + /* Not charging, flag is none, Under 3.60V or 3.45V */ + if (!fuelgauge->info.low_batt_comp_flag + && (fg_vcell <= fuelgauge->info.check_start_vol)) { + fg_avg_current = fg_read_avg_current(client); + fg_min_current = min(fg_avg_current, fg_current); + + if (fg_min_current < CURRENT_RANGE_MAX) { + if (fg_soc >= 2 && + fg_vcell < get_low_batt_threshold(client, + CURRENT_RANGE_MAX_NUM, 1, fg_min_current)) + add_low_batt_comp_cnt(client, + CURRENT_RANGE_MAX_NUM, 1); + else if (fg_soc >= 4 && + fg_vcell < get_low_batt_threshold(client, + CURRENT_RANGE_MAX_NUM, 3, fg_min_current)) + add_low_batt_comp_cnt(client, + CURRENT_RANGE_MAX_NUM, 3); + else + bCntReset = 1; + } +/* P4W & P8 needs more level */ +#if defined(CONFIG_MACH_P4W_REV00) || defined(CONFIG_MACH_P4W_REV01) || \ + defined(CONFIG_MACH_P8_REV00) || defined(CONFIG_MACH_P8_REV01) || \ + defined(CONFIG_MACH_P8LTE_REV00) + else if (fg_min_current >= CURRENT_RANGE5 && + fg_min_current < CURRENT_RANGE4) { + if (fg_soc >= 2 && fg_vcell < + get_low_batt_threshold(client, + 4, 1, fg_min_current)) + add_low_batt_comp_cnt(client, 4, 1); + else if (fg_soc >= 4 && fg_vcell < + get_low_batt_threshold(client, + 4, 3, fg_min_current)) + add_low_batt_comp_cnt(client, 4, 3); + else + bCntReset = 1; + } +#endif + else if (fg_min_current >= CURRENT_RANGE4 && + fg_min_current < CURRENT_RANGE3) { + if (fg_soc >= 2 && fg_vcell < + get_low_batt_threshold(client, + 3, 1, fg_min_current)) + add_low_batt_comp_cnt(client, 3, 1); + else if (fg_soc >= 4 && fg_vcell < + get_low_batt_threshold(client, + 3, 3, fg_min_current)) + add_low_batt_comp_cnt(client, 3, 3); + else + bCntReset = 1; + } else if (fg_min_current >= CURRENT_RANGE3 && + fg_min_current < CURRENT_RANGE2) { + if (fg_soc >= 2 && fg_vcell < + get_low_batt_threshold(client, + 2, 1, fg_min_current)) + add_low_batt_comp_cnt(client, 2, 1); + else if (fg_soc >= 4 && fg_vcell < + get_low_batt_threshold(client, + 2, 3, fg_min_current)) + add_low_batt_comp_cnt(client, 2, 3); + else + bCntReset = 1; + } else if (fg_min_current >= CURRENT_RANGE2 && + fg_min_current < CURRENT_RANGE1) { + if (fg_soc >= 2 && fg_vcell < + get_low_batt_threshold(client, + 1, 1, fg_min_current)) + add_low_batt_comp_cnt(client, 1, 1); + else if (fg_soc >= 4 && fg_vcell < + get_low_batt_threshold(client, + 1, 3, fg_min_current)) + add_low_batt_comp_cnt(client, 1, 3); + else + bCntReset = 1; + } + + + if (check_low_batt_comp_condition(client, &new_level)) { +#if defined(CONFIG_MACH_P8_REV00) || \ + defined(CONFIG_MACH_P8_REV01) || \ + defined(CONFIG_MACH_P8LTE_REV00) + /* Disable 3% low battery compensation (only for P8s) */ + /* duplicated action with 1% low battery compensation */ + if (new_level < 2) +#endif + fg_low_batt_compensation(client, new_level); + reset_low_batt_comp_cnt(client); + } + + if (bCntReset) + reset_low_batt_comp_cnt(client); + + /* if compensation finished, then read SOC again!!*/ + if (fuelgauge->info.low_batt_comp_flag) { + pr_info("%s : MIN_CURRENT(%d), AVG_CURRENT(%d), CURRENT(%d), SOC(%d), VCELL(%d)\n", + __func__, fg_min_current, fg_avg_current, + fg_current, fg_soc, fg_vcell); +#if defined(CONFIG_MACH_P8_REV00) || \ + defined(CONFIG_MACH_P8_REV01) || \ + defined(CONFIG_MACH_P8LTE_REV00) + /* Do not update soc right after low battery compensation */ + /* to prevent from powering-off suddenly (only for P8s) */ + pr_info("%s : SOC is set to %d\n", + __func__, fg_read_soc(client)); +#else + fg_soc = fg_read_soc(client); + pr_info("%s : SOC is set to %d\n", __func__, fg_soc); +#endif + } + } + +#if defined(CONFIG_MACH_P4W_REV00) || defined(CONFIG_MACH_P4W_REV01) || \ + defined(CONFIG_MACH_P2_REV00) || defined(CONFIG_MACH_P2_REV01) || \ + defined(CONFIG_MACH_P2_REV02) + /* Prevent power off over 3500mV */ + prevent_early_poweroff(fg_vcell, &fg_soc); +#endif + + return fg_soc; +} + +static void fg_set_battery_type(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + + u16 data; + u8 type_str[10]; + + data = fg_read_register(client, DESIGNCAP_REG); + + if ((data == sdi_vfcapacity) || (data == sdi_vfcapacity-1)) + fuelgauge->info.battery_type = SDI_BATTERY_TYPE; + else if ((data == atl_vfcapacity) || (data == atl_vfcapacity-1)) + fuelgauge->info.battery_type = ATL_BATTERY_TYPE; + else { + pr_info("%s : Unknown battery is set to SDI type.\n", __func__); + fuelgauge->info.battery_type = SDI_BATTERY_TYPE; + } + + if (fuelgauge->info.battery_type == SDI_BATTERY_TYPE) + sprintf(type_str, "SDI"); + else if (fuelgauge->info.battery_type == ATL_BATTERY_TYPE) + sprintf(type_str, "ATL"); + else + sprintf(type_str, "Unknown"); + + pr_info("%s : DesignCAP(0x%04x), Battery type(%s)\n", + __func__, data, type_str); + + switch (fuelgauge->info.battery_type) { + case ATL_BATTERY_TYPE: + fuelgauge->info.capacity = atl_capacity; + fuelgauge->info.vfcapacity = atl_vfcapacity; + break; + + case SDI_BATTERY_TYPE: + default: + fuelgauge->info.capacity = sdi_capacity; + fuelgauge->info.vfcapacity = sdi_vfcapacity; + break; + } + + /* If not initialized yet, then init threshold values. */ + if (!fuelgauge->info.check_start_vol) { + if (fuelgauge->info.battery_type == SDI_BATTERY_TYPE) + fuelgauge->info.check_start_vol = + sdi_low_bat_comp_start_vol; + else if (fuelgauge->info.battery_type == ATL_BATTERY_TYPE) + fuelgauge->info.check_start_vol = + atl_low_bat_comp_start_vol; + } + +} + +int get_fuelgauge_value(struct i2c_client *client, int data) +{ + int ret; + + switch (data) { + case FG_LEVEL: + ret = fg_read_soc(client); + break; + + case FG_TEMPERATURE: + ret = fg_read_temp(client); + break; + + case FG_VOLTAGE: + ret = fg_read_vcell(client); + break; + + case FG_CURRENT: + ret = fg_read_current(client); + break; + + case FG_CURRENT_AVG: + ret = fg_read_avg_current(client); + break; + + case FG_BATTERY_TYPE: + ret = fg_get_battery_type(client); + break; + + case FG_CHECK_STATUS: + ret = fg_check_status_reg(client); + break; + + case FG_VF_SOC: + ret = fg_read_vfsoc(client); + break; + + default: + ret = -1; + break; + } + + return ret; +} + +static bool check_UV_charging_case(struct i2c_client *client) +{ + int fg_vcell = get_fuelgauge_value(client, FG_VOLTAGE); + int fg_current = get_fuelgauge_value(client, FG_CURRENT); + int threshold = 0; + + if (get_fuelgauge_value(client, FG_BATTERY_TYPE) + == SDI_BATTERY_TYPE) + threshold = 3300 + ((fg_current * 17) / 100); + else if (get_fuelgauge_value(client, FG_BATTERY_TYPE) + == ATL_BATTERY_TYPE) + threshold = 3300 + ((fg_current * 13) / 100); + + if (fg_vcell <= threshold) + return 1; + else + return 0; +} + +static int get_fuelgauge_soc(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + union power_supply_propval value; + int fg_soc; + int fg_vfsoc; + int fg_vcell; + int fg_current; + int avg_current; + int recover_flag = 0; + + recover_flag = fg_check_cap_corruption(client); + + /* check VFcapacity every five minutes */ + if (!(fuelgauge->info.fg_chk_cnt++ % 10)) { + fg_check_vf_fullcap_range(client); + fuelgauge->info.fg_chk_cnt = 1; + } + + fg_soc = get_fuelgauge_value(client, FG_LEVEL); + if (fg_soc < 0) { + pr_info("Can't read soc!!!"); + fg_soc = fuelgauge->info.soc; + } + + if (!fuelgauge->pdata->check_jig_status() && + !fuelgauge->info.low_batt_comp_flag) { + if (((fg_soc+5) < fuelgauge->info.previous_repsoc) || + (fg_soc > (fuelgauge->info.previous_repsoc+5))) + fuelgauge->info.fg_skip = 1; + } + + /* skip one time (maximum 30 seconds) because of corruption. */ + if (fuelgauge->info.fg_skip) { + pr_info("%s: skip update until corruption check " + "is done (fg_skip_cnt:%d)\n", + __func__, ++fuelgauge->info.fg_skip_cnt); + fg_soc = fuelgauge->info.soc; + if (recover_flag || fuelgauge->info.fg_skip_cnt > 10) { + fuelgauge->info.fg_skip = 0; + fuelgauge->info.fg_skip_cnt = 0; + } + } + + if (fuelgauge->info.low_batt_boot_flag) { + fg_soc = 0; + + if (fuelgauge->pdata->check_cable_callback() != + POWER_SUPPLY_TYPE_BATTERY && + !check_UV_charging_case(client)) { + fg_adjust_capacity(client); + fuelgauge->info.low_batt_boot_flag = 0; + } + + if (fuelgauge->pdata->check_cable_callback() == + POWER_SUPPLY_TYPE_BATTERY) + fuelgauge->info.low_batt_boot_flag = 0; + } + + fg_vcell = get_fuelgauge_value(client, FG_VOLTAGE); + fg_current = get_fuelgauge_value(client, FG_CURRENT); + avg_current = get_fuelgauge_value(client, FG_CURRENT_AVG); + fg_vfsoc = get_fuelgauge_value(client, FG_VF_SOC); + + psy_do_property("battery", get, + POWER_SUPPLY_PROP_CHARGE_TYPE, value); + + /* P4-Creative does not set full flag by force */ +#if !defined(CONFIG_MACH_P4W_REV00) && !defined(CONFIG_MACH_P4W_REV01) + /* Algorithm for reducing time to fully charged (from MAXIM) */ + if (value.intval != SEC_BATTERY_CHARGING_NONE && + value.intval != SEC_BATTERY_CHARGING_RECHARGING && + fuelgauge->cable_type != POWER_SUPPLY_TYPE_USB && + /* Skip when first check after boot up */ + !fuelgauge->info.is_first_check && + (fg_vfsoc > VFSOC_FOR_FULLCAP_LEARNING && + (fg_current > LOW_CURRENT_FOR_FULLCAP_LEARNING && + fg_current < HIGH_CURRENT_FOR_FULLCAP_LEARNING) && + (avg_current > LOW_AVGCURRENT_FOR_FULLCAP_LEARNING && + avg_current < HIGH_AVGCURRENT_FOR_FULLCAP_LEARNING))) { + + if (fuelgauge->info.full_check_flag == 2) { + pr_info("%s: force fully charged SOC !! (%d)", + __func__, fuelgauge->info.full_check_flag); + fg_set_full_charged(client); + fg_soc = get_fuelgauge_value(client, FG_LEVEL); + } else if (fuelgauge->info.full_check_flag < 2) + pr_info("%s: full_check_flag (%d)", + __func__, fuelgauge->info.full_check_flag); + + /* prevent overflow */ + if (fuelgauge->info.full_check_flag++ > 10000) + fuelgauge->info.full_check_flag = 3; + } else + fuelgauge->info.full_check_flag = 0; +#endif + + /* Checks vcell level and tries to compensate SOC if needed.*/ + /* If jig cable is connected, then skip low batt compensation check. */ + if (!fuelgauge->pdata->check_jig_status() && + value.intval == SEC_BATTERY_CHARGING_NONE) + fg_soc = low_batt_compensation( + client, fg_soc, fg_vcell, fg_current); + + if (fuelgauge->info.is_first_check) + fuelgauge->info.is_first_check = false; + + fuelgauge->info.soc = fg_soc; + return fg_soc; +} + +static void full_comp_work_handler(struct work_struct *work) +{ + struct sec_fg_info *fg_info = + container_of(work, struct sec_fg_info, full_comp_work.work); + struct sec_fuelgauge_info *fuelgauge = + container_of(fg_info, struct sec_fuelgauge_info, info); + int avg_current; + union power_supply_propval value; + + avg_current = get_fuelgauge_value(fuelgauge->client, FG_CURRENT_AVG); + psy_do_property("battery", get, + POWER_SUPPLY_PROP_CHARGE_TYPE, value); + + if (avg_current >= 25) { + cancel_delayed_work(&fuelgauge->info.full_comp_work); + schedule_delayed_work(&fuelgauge->info.full_comp_work, 100); + } else { + pr_info("%s: full charge compensation start (avg_current %d)\n", + __func__, avg_current); + fg_fullcharged_compensation(fuelgauge->client, + (int)(value.intval == + SEC_BATTERY_CHARGING_RECHARGING), 0); + } +} + +bool sec_hal_fg_init(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = + i2c_get_clientdata(client); + + fuelgauge->info.is_first_check = true; + + fg_set_battery_type(client); + + /* Init parameters to prevent wrong compensation. */ + fuelgauge->info.previous_fullcap = + fg_read_register(client, FULLCAP_REG); + fuelgauge->info.previous_vffullcap = + fg_read_register(client, FULLCAP_NOM_REG); + /* Init FullCAP of first full charging. */ + fuelgauge->info.full_charged_cap = + fuelgauge->info.previous_fullcap; + + fuelgauge->info.previous_vfsoc = + fg_read_vfsoc(client); + fuelgauge->info.previous_repsoc = + fg_read_soc(client); + fuelgauge->info.previous_remcap = + fg_read_register(client, REMCAP_REP_REG); + fuelgauge->info.previous_mixcap = + fg_read_register(client, REMCAP_MIX_REG); + fuelgauge->info.previous_vfocv = + fg_read_register(client, VFOCV_REG); + fuelgauge->info.previous_fullcapacity = + fuelgauge->info.previous_fullcap; + fuelgauge->info.previous_vfcapacity = + fuelgauge->info.previous_vffullcap; + + fg_read_model_data(client); + fg_periodic_read(client); + + if (fuelgauge->pdata->check_cable_callback() == + POWER_SUPPLY_TYPE_BATTERY && + check_UV_charging_case(client)) + fuelgauge->info.low_batt_boot_flag = 1; + + INIT_DELAYED_WORK(&fuelgauge->info.full_comp_work, + full_comp_work_handler); + + return true; +} + +bool sec_hal_fg_suspend(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_resume(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_fuelalert_init(struct i2c_client *client, int soc) +{ + return true; +} + +bool sec_hal_fg_is_fuelalerted(struct i2c_client *client) +{ + return false; +} + +bool sec_hal_fg_fuelalert_process(void *irq_data, bool is_fuel_alerted) +{ + return true; +} + +bool sec_hal_fg_full_charged(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = + i2c_get_clientdata(client); + union power_supply_propval value; + + psy_do_property("battery", get, + POWER_SUPPLY_PROP_CHARGE_TYPE, value); + + /* full charge compensation algorithm by MAXIM */ + fg_fullcharged_compensation(client, + (int)(value.intval == SEC_BATTERY_CHARGING_RECHARGING), 1); + + cancel_delayed_work(&fuelgauge->info.full_comp_work); + schedule_delayed_work(&fuelgauge->info.full_comp_work, 100); + + return false; +} + +bool sec_hal_fg_reset(struct i2c_client *client) +{ + if (!fg_reset_soc(client)) + return true; + else + return false; +} + +bool sec_hal_fg_get_property(struct i2c_client *client, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + /* Cell voltage (VCELL, mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = get_fuelgauge_value(client, FG_VOLTAGE); + break; + /* Additional Voltage Information (mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + switch (val->intval) { + case SEC_BATTEY_VOLTAGE_AVERAGE: + val->intval = 0; + break; + case SEC_BATTEY_VOLTAGE_OCV: + val->intval = fg_read_vfocv(client); + break; + } + break; + /* Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = get_fuelgauge_value(client, FG_CURRENT); + break; + /* Average Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = get_fuelgauge_value(client, FG_CURRENT_AVG); + break; + /* SOC (%) */ + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = get_fuelgauge_soc(client); + break; + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + val->intval = get_fuelgauge_value(client, FG_TEMPERATURE); + break; + default: + return false; + } + return true; +} + +bool sec_hal_fg_set_property(struct i2c_client *client, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sec_fuelgauge_info *fuelgauge = + i2c_get_clientdata(client); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + if (val->intval != POWER_SUPPLY_TYPE_BATTERY) { + fuelgauge->info.low_batt_comp_flag = 0; + reset_low_batt_comp_cnt(client); + } + break; + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + break; + default: + return false; + } + return true; +} + +ssize_t sec_hal_fg_show_attrs(struct device *dev, + const ptrdiff_t offset, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int i = 0; + char *str = NULL; + + switch (offset) { +/* case FG_REG: */ +/* break; */ + case FG_DATA: + i += scnprintf(buf + i, PAGE_SIZE - i, "%02x%02x\n", + fg->reg_data[1], fg->reg_data[0]); + break; + case FG_REGS: + str = kzalloc(sizeof(char)*1024, GFP_KERNEL); + if (!str) + return -ENOMEM; + + fg_read_regs(fg->client, str); + pr_debug("%s: %s\n", __func__, str); + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", + str); + + kfree(str); + break; + default: + i = -EINVAL; + break; + } + + return i; +} + +ssize_t sec_hal_fg_store_attrs(struct device *dev, + const ptrdiff_t offset, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int ret = 0; + int x = 0; + u8 data[2]; + + switch (offset) { + case FG_REG: + if (sscanf(buf, "%x\n", &x) == 1) { + fg->reg_addr = x; + fg_i2c_read(fg->client, + fg->reg_addr, fg->reg_data, 2); + pr_debug("%s: (read) addr = 0x%x, data = 0x%02x%02x\n", + __func__, fg->reg_addr, + fg->reg_data[1], fg->reg_data[0]); + } + ret = count; + break; + case FG_DATA: + if (sscanf(buf, "%x\n", &x) == 1) { + data[0] = (x & 0xFF00) >> 8; + data[1] = (x & 0x00FF); + pr_debug("%s: (write) addr = 0x%x, data = 0x%02x%02x\n", + __func__, fg->reg_addr, data[1], data[0]); + fg_i2c_write(fg->client, + fg->reg_addr, data, 2); + } + ret = count; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +#endif + diff --git a/drivers/battery/max17048_fuelgauge.c b/drivers/battery/max17048_fuelgauge.c new file mode 100644 index 00000000000..4105ae56a1d --- /dev/null +++ b/drivers/battery/max17048_fuelgauge.c @@ -0,0 +1,422 @@ +/* + * max17048_fuelgauge.c + * Samsung MAX17048 Fuel Gauge Driver + * + * Copyright (C) 2012 Samsung Electronics + * + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include + +static int max17048_write_reg(struct i2c_client *client, int reg, u8 value) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, reg, value); + + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + return ret; +} + +static int max17048_read_reg(struct i2c_client *client, int reg) +{ + int ret; + + ret = i2c_smbus_read_byte_data(client, reg); + + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + return ret; +} + +static int max17048_read_word(struct i2c_client *client, int reg) +{ + int ret; + + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + return ret; +} + +static void max17048_reset(struct i2c_client *client) +{ + u16 reset_cmd; + + reset_cmd = swab16(0x5400); + + i2c_smbus_write_word_data(client, MAX17048_CMD_MSB, reset_cmd); + + msleep(300); +} + +static int max17048_get_vcell(struct i2c_client *client) +{ + u32 vcell; + u16 w_data; + u32 temp; + + temp = max17048_read_word(client, MAX17048_VCELL_MSB); + + w_data = swab16(temp); + + temp = ((w_data & 0xFFF0) >> 4) * 1250; + vcell = temp / 1000; + + dev_dbg(&client->dev, + "%s : vcell (%d)\n", __func__, vcell); + + return vcell; +} + +/* soc should be 0.1% unit */ +static int max17048_get_soc(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = + i2c_get_clientdata(client); + u8 data[2] = {0, 0}; + int temp, soc; + u64 psoc64 = 0; + u64 temp64; + u32 divisor = 10000000; + + temp = max17048_read_word(client, MAX17048_SOC_MSB); + + if (get_battery_data(fuelgauge).is_using_model_data) { + /* [ TempSOC = ((SOC1 * 256) + SOC2) * 0.001953125 ] */ + temp64 = swab16(temp); + psoc64 = temp64 * 1953125; + psoc64 = div_u64(psoc64, divisor); + soc = psoc64 & 0xffff; + soc /= 10; + } else { + data[0] = temp & 0xff; + data[1] = (temp & 0xff00) >> 8; + + soc = ((data[0] * 100) + (data[1] * 100 / 256)) / 10; + } + + dev_dbg(&client->dev, + "%s : raw capacity (%d), data(0x%04x)\n", + __func__, soc, (data[0]<<8) | data[1]); + + return soc; +} + +static void max17048_get_version(struct i2c_client *client) +{ + u16 w_data; + int temp; + + temp = max17048_read_word(client, MAX17048_VER_MSB); + + w_data = swab16(temp); + + dev_info(&client->dev, + "MAX17048 Fuel-Gauge Ver 0x%04x\n", w_data); +} + +static u16 max17048_get_rcomp(struct i2c_client *client) +{ + u16 w_data; + int temp; + + temp = max17048_read_word(client, MAX17048_RCOMP_MSB); + + w_data = swab16(temp); + + dev_dbg(&client->dev, + "%s : current rcomp = 0x%04x\n", + __func__, w_data); + + return w_data; +} + +static void max17048_set_rcomp(struct i2c_client *client, u16 new_rcomp) +{ + i2c_smbus_write_word_data(client, + MAX17048_RCOMP_MSB, swab16(new_rcomp)); +} + +static void max17048_rcomp_update(struct i2c_client *client, int temp) +{ + struct sec_fuelgauge_info *fuelgauge = + i2c_get_clientdata(client); + union power_supply_propval value; + + int starting_rcomp = 0; + int new_rcomp = 0; + int rcomp_current = 0; + + rcomp_current = max17048_get_rcomp(client); + + psy_do_property("battery", get, + POWER_SUPPLY_PROP_CHARGE_TYPE, value); + + if (value.intval) /* in charging */ + starting_rcomp = get_battery_data(fuelgauge).RCOMP_charging; + else + starting_rcomp = get_battery_data(fuelgauge).RCOMP0; + + if (temp > RCOMP0_TEMP) + new_rcomp = starting_rcomp + ((temp - RCOMP0_TEMP) * + get_battery_data(fuelgauge).temp_cohot / 1000); + else if (temp < RCOMP0_TEMP) + new_rcomp = starting_rcomp + ((temp - RCOMP0_TEMP) * + get_battery_data(fuelgauge).temp_cocold / 1000); + else + new_rcomp = starting_rcomp; + + if (new_rcomp > 255) + new_rcomp = 255; + else if (new_rcomp < 0) + new_rcomp = 0; + + new_rcomp <<= 8; + new_rcomp &= 0xff00; + /* not related to RCOMP */ + new_rcomp |= (rcomp_current & 0xff); + + if (rcomp_current != new_rcomp) { + dev_dbg(&client->dev, + "%s : RCOMP 0x%04x -> 0x%04x (0x%02x)\n", + __func__, rcomp_current, new_rcomp, + new_rcomp >> 8); + max17048_set_rcomp(client, new_rcomp); + } +} + +static void fg_read_regs(struct i2c_client *client, char *str) +{ + int data = 0; + u32 addr = 0; + + for (addr = 0x02; addr <= 0x04; addr += 2) { + data = max17048_read_word(client, addr); + sprintf(str + strlen(str), "0x%04x, ", data); + } + + /* "#" considered as new line in application */ + sprintf(str+strlen(str), "#"); + + for (addr = 0x08; addr <= 0x1a; addr += 2) { + data = max17048_read_word(client, addr); + sprintf(str + strlen(str), "0x%04x, ", data); + } +} + +bool sec_hal_fg_init(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = + i2c_get_clientdata(client); + + max17048_get_version(client); + + return true; +} + +bool sec_hal_fg_suspend(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_resume(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_fuelalert_init(struct i2c_client *client, int soc) +{ + u16 temp; + u8 data; + + temp = max17048_get_rcomp(client); + data = 32 - soc; /* set soc for fuel alert */ + temp &= 0xff00; + temp += data; + + dev_dbg(&client->dev, + "%s : new rcomp = 0x%04x\n", + __func__, temp); + + max17048_set_rcomp(client, temp); + + return true; +} + +bool sec_hal_fg_is_fuelalerted(struct i2c_client *client) +{ + u16 temp; + + temp = max17048_get_rcomp(client); + + if (temp & 0x20) /* ALRT is asserted */ + return true; + + return false; +} + +bool sec_hal_fg_fuelalert_process(void *irq_data, bool is_fuel_alerted) +{ + return true; +} + +bool sec_hal_fg_full_charged(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_reset(struct i2c_client *client) +{ + max17048_reset(client); + return true; +} + +bool sec_hal_fg_get_property(struct i2c_client *client, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + /* Cell voltage (VCELL, mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = max17048_get_vcell(client); + break; + /* Additional Voltage Information (mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + switch (val->intval) { + case SEC_BATTEY_VOLTAGE_AVERAGE: + break; + case SEC_BATTEY_VOLTAGE_OCV: + break; + } + break; + /* Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_NOW: + break; + /* Average Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_AVG: + break; + /* SOC (%) */ + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = max17048_get_soc(client); + break; + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + break; + default: + return false; + } + return true; +} + +bool sec_hal_fg_set_property(struct i2c_client *client, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + switch (psp) { + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + /* temperature is 0.1 degree, should be divide by 10 */ + max17048_rcomp_update(client, val->intval / 10); + break; + default: + return false; + } + return true; +} + +ssize_t sec_hal_fg_show_attrs(struct device *dev, + const ptrdiff_t offset, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int i = 0; + char *str = NULL; + + switch (offset) { + case FG_DATA: + i += scnprintf(buf + i, PAGE_SIZE - i, "%02x%02x\n", + fg->reg_data[1], fg->reg_data[0]); + break; + case FG_REGS: + str = kzalloc(sizeof(char)*1024, GFP_KERNEL); + if (!str) + return -ENOMEM; + + fg_read_regs(fg->client, str); + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", + str); + + kfree(str); + break; + default: + i = -EINVAL; + break; + } + + return i; +} + +ssize_t sec_hal_fg_store_attrs(struct device *dev, + const ptrdiff_t offset, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int ret = 0; + int x = 0; + u16 data; + + switch (offset) { + case FG_REG: + if (sscanf(buf, "%x\n", &x) == 1) { + fg->reg_addr = x; + data = max17048_read_word( + fg->client, fg->reg_addr); + fg->reg_data[0] = (data & 0xff00) >> 8; + fg->reg_data[1] = (data & 0x00ff); + + dev_dbg(&fg->client->dev, + "%s: (read) addr = 0x%x, data = 0x%02x%02x\n", + __func__, fg->reg_addr, + fg->reg_data[1], fg->reg_data[0]); + ret = count; + } + break; + case FG_DATA: + if (sscanf(buf, "%x\n", &x) == 1) { + dev_dbg(&fg->client->dev, + "%s: (write) addr = 0x%x, data = 0x%04x\n", + __func__, fg->reg_addr, x); + i2c_smbus_write_word_data(fg->client, + fg->reg_addr, swab16(x)); + ret = count; + } + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} diff --git a/drivers/battery/max17050_fuelgauge.c b/drivers/battery/max17050_fuelgauge.c new file mode 100644 index 00000000000..9d53615516e --- /dev/null +++ b/drivers/battery/max17050_fuelgauge.c @@ -0,0 +1,2315 @@ +/* + * max17050_fuelgauge.c + * Samsung MAX17050 Fuel Gauge Driver + * + * Copyright (C) 2012 Samsung Electronics + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define DEBUG + +#include + +#ifdef CONFIG_FUELGAUGE_MAX17050_VOLTAGE_TRACKING +static int max17050_write_reg(struct i2c_client *client, int reg, u8 *buf) +{ + int ret; + + ret = i2c_smbus_write_i2c_block_data(client, reg, 2, buf); + + if (ret < 0) + dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret); + + return ret; +} + +static int max17050_read_reg(struct i2c_client *client, int reg, u8 *buf) +{ + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, reg, 2, buf); + + if (ret < 0) + dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret); + + return ret; +} + +static void max17050_write_reg_array(struct i2c_client *client, + u8 *buf, int size) +{ + int i; + + for (i = 0; i < size; i += 3) + max17050_write_reg(client, (u8) (*(buf + i)), (buf + i) + 1); +} + +static void max17050_init_regs(struct i2c_client *client) +{ + u8 data[2]; + + if (max17050_read_reg(client, MAX17050_REG_FILTERCFG, data) < 0) + return; + + /* Clear average vcell (12 sec) */ + data[0] &= 0x8f; + + max17050_write_reg(client, MAX17050_REG_FILTERCFG, data); +} + +static void max17050_get_version(struct i2c_client *client) +{ + u8 data[2]; + + if (max17050_read_reg(client, MAX17050_REG_VERSION, data) < 0) + return; + + dev_dbg(&client->dev, "MAX17050 Fuel-Gauge Ver %d%d\n", + data[0], data[1]); +} + +static void max17050_alert_init(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + + /* SALRT Threshold setting */ + data[0] = fuelgauge->pdata->fuel_alert_soc; + data[1] = 0xff; + max17050_write_reg(client, MAX17050_REG_SALRT_TH, data); + + /* VALRT Threshold setting */ + data[0] = 0x00; + data[1] = 0xff; + max17050_write_reg(client, MAX17050_REG_VALRT_TH, data); + + /* TALRT Threshold setting */ + data[0] = 0x80; + data[1] = 0x7f; + max17050_write_reg(client, MAX17050_REG_TALRT_TH, data); +} + +static bool max17050_check_status(struct i2c_client *client) +{ + u8 data[2]; + bool ret = false; + + /* check if Smn was generated */ + if (max17050_read_reg(client, MAX17050_REG_STATUS, data) < 0) + return ret; + + dev_info(&client->dev, "%s: status_reg(%02x%02x)\n", + __func__, data[1], data[0]); + + /* minimum SOC threshold exceeded. */ + if (data[1] & (0x1 << 2)) + ret = true; + + /* clear status reg */ + if (!ret) { + data[1] = 0; + max17050_write_reg(client, MAX17050_REG_STATUS, data); + msleep(200); + } + + return ret; +} + +static int max17050_set_temperature(struct i2c_client *client, int temperature) +{ + u8 data[2]; + + data[0] = 0; + data[1] = temperature; + max17050_write_reg(client, MAX17050_REG_TEMPERATURE, data); + + dev_dbg(&client->dev, "%s: temperature to (%d)\n", + __func__, temperature); + + return temperature; +} + +static int max17050_get_temperature(struct i2c_client *client) +{ + u8 data[2]; + s32 temperature = 0; + + if (max17050_read_reg(client, MAX17050_REG_TEMPERATURE, data) < 0) + return -ERANGE; + + /* data[] store 2's compliment format number */ + if (data[1] & (0x1 << 7)) { + /* Negative */ + temperature = ((~(data[1])) & 0xFF) + 1; + temperature *= (-1000); + } else { + temperature = data[1] & 0x7F; + temperature *= 1000; + temperature += data[0] * 39 / 10; + } + + dev_dbg(&client->dev, "%s: temperature (%d)\n", + __func__, temperature); + + return temperature; +} + +/* soc should be 0.1% unit */ +static int max17050_get_soc(struct i2c_client *client) +{ + u8 data[2]; + int soc; + + if (max17050_read_reg(client, MAX17050_REG_SOC_VF, data) < 0) + return -EINVAL; + + soc = ((data[1] * 100) + (data[0] * 100 / 256)) / 10; + + dev_dbg(&client->dev, "%s: raw capacity (%d)\n", __func__, soc); + + return min(soc, 1000); +} + +static int max17050_get_vfocv(struct i2c_client *client) +{ + u8 data[2]; + u32 vfocv = 0; + + if (max17050_read_reg(client, MAX17050_REG_VFOCV, data) < 0) + return -EINVAL; + + vfocv = ((data[0] >> 3) + (data[1] << 5)) * 625 / 1000; + + dev_dbg(&client->dev, "%s: vfocv (%d)\n", __func__, vfocv); + + return vfocv; +} + +static int max17050_get_vcell(struct i2c_client *client) +{ + u8 data[2]; + u32 vcell = 0; + + if (max17050_read_reg(client, MAX17050_REG_VCELL, data) < 0) + return -EINVAL; + + vcell = ((data[0] >> 3) + (data[1] << 5)) * 625 / 1000; + + dev_dbg(&client->dev, "%s: vcell (%d)\n", __func__, vcell); + + return vcell; +} + +static int max17050_get_avgvcell(struct i2c_client *client) +{ + u8 data[2]; + u32 avgvcell = 0; + + if (max17050_read_reg(client, MAX17050_REG_AVGVCELL, data) < 0) + return -EINVAL; + + avgvcell = ((data[0] >> 3) + (data[1] << 5)) * 625 / 1000; + + dev_dbg(&client->dev, "%s: avgvcell (%d)\n", __func__, avgvcell); + + return avgvcell; +} + +bool sec_hal_fg_init(struct i2c_client *client) +{ + /* initialize fuel gauge registers */ + max17050_init_regs(client); + + max17050_get_version(client); + + return true; +} + +bool sec_hal_fg_suspend(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_resume(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_fuelalert_init(struct i2c_client *client, int soc) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + + /* 1. Set max17050 alert configuration. */ + max17050_alert_init(client); + + if (max17050_read_reg(client, MAX17050_REG_CONFIG, data) + < 0) + return -1; + + /*Enable Alert (Aen = 1) */ + data[0] |= (0x1 << 2); + + max17050_write_reg(client, MAX17050_REG_CONFIG, data); + + dev_dbg(&client->dev, "%s: config_reg(%02x%02x) irq(%d)\n", + __func__, data[1], data[0], fuelgauge->pdata->fg_gpio_irq); + + return true; +} + +bool sec_hal_fg_is_fuelalerted(struct i2c_client *client) +{ + return max17050_check_status(client); +} + +bool sec_hal_fg_fuelalert_process(void *irq_data, bool is_fuel_alerted) +{ + struct sec_fuelgauge_info *fuelgauge = irq_data; + u8 data[2]; + + /* update SOC */ + /* max17050_get_soc(fuelgauge->client); */ + + if (is_fuel_alerted) { + if (max17050_read_reg(fuelgauge->client, + MAX17050_REG_CONFIG, data) < 0) + return false; + + data[1] |= (0x1 << 3); + + max17050_write_reg(fuelgauge->client, + MAX17050_REG_CONFIG, data); + + dev_info(&fuelgauge->client->dev, + "%s: Fuel-alert Alerted!! (%02x%02x)\n", + __func__, data[1], data[0]); + } else { + if (max17050_read_reg(fuelgauge->client, + MAX17050_REG_CONFIG, data) + < 0) + return false; + + data[1] &= (~(0x1 << 3)); + + max17050_write_reg(fuelgauge->client, + MAX17050_REG_CONFIG, data); + + dev_info(&fuelgauge->client->dev, + "%s: Fuel-alert Released!! (%02x%02x)\n", + __func__, data[1], data[0]); + } + + max17050_read_reg(fuelgauge->client, MAX17050_REG_VCELL, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_VCELL(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_TEMPERATURE, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_TEMPERATURE(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_CONFIG, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_CONFIG(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_VFOCV, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_VFOCV(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_SOC_VF, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_SOC_VF(%02x%02x)\n", + __func__, data[1], data[0]); + + dev_dbg(&fuelgauge->client->dev, + "%s: FUEL GAUGE IRQ (%d)\n", + __func__, + gpio_get_value(irq_to_gpio(fuelgauge->pdata->fg_gpio_irq))); + +#if 0 + max17050_read_reg(fuelgauge->client, MAX17050_REG_STATUS, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_STATUS(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_VALRT_TH, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_VALRT_TH(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_TALRT_TH, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_TALRT_TH(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_SALRT_TH, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_SALRT_TH(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_AVGVCELL, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_AVGVCELL(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_VERSION, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_VERSION(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_LEARNCFG, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_LEARNCFG(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_MISCCFG, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_MISCCFG(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_CGAIN, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_CGAIN(%02x%02x)\n", + __func__, data[1], data[0]); + + max17050_read_reg(fuelgauge->client, MAX17050_REG_RCOMP, data); + dev_dbg(&fuelgauge->client->dev, + "%s: MAX17050_REG_RCOMP(%02x%02x)\n", + __func__, data[1], data[0]); +#endif + + return true; +} + +bool sec_hal_fg_full_charged(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_get_property(struct i2c_client *client, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + /* Cell voltage (VCELL, mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = max17050_get_vcell(client); + break; + /* Additional Voltage Information (mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + switch (val->intval) { + case SEC_BATTEY_VOLTAGE_AVERAGE: + val->intval = max17050_get_avgvcell(client); + break; + case SEC_BATTEY_VOLTAGE_OCV: + val->intval = max17050_get_vfocv(client); + break; + } + break; + /* Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = 0; + break; + /* Average Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = 0; + break; + /* SOC (%) */ + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = max17050_get_soc(client); + break; + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + val->intval = max17050_get_temperature(client); + break; + default: + return false; + } + return true; +} + +bool sec_hal_fg_set_property(struct i2c_client *client, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + switch (psp) { + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + max17050_set_temperature(client, val->intval); + break; + default: + return false; + } + return true; +} + +ssize_t sec_hal_fg_show_attrs(struct device *dev, + const ptrdiff_t offset, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int i = 0; + + switch (offset) { +/* case FG_REG: */ +/* break; */ + case FG_DATA: + i += scnprintf(buf + i, PAGE_SIZE - i, "%02x%02x\n", + fg->reg_data[1], fg->reg_data[0]); + break; + default: + i = -EINVAL; + break; + } + + return i; +} + +ssize_t sec_hal_fg_store_attrs(struct device *dev, + const ptrdiff_t offset, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int ret = 0; + int x = 0; + u8 data[2]; + + switch (offset) { + case FG_REG: + if (sscanf(buf, "%x\n", &x) == 1) { + fg->reg_addr = x; + max17050_read_reg(fg->client, + fg->reg_addr, fg->reg_data); + dev_dbg(&fg->client->dev, + "%s: (read) addr = 0x%x, data = 0x%02x%02x\n", + __func__, fg->reg_addr, + fg->reg_data[1], fg->reg_data[0]); + ret = count; + } + break; + case FG_DATA: + if (sscanf(buf, "%x\n", &x) == 1) { + data[0] = (x & 0xFF00) >> 8; + data[1] = (x & 0x00FF); + dev_dbg(&fg->client->dev, + "%s: (write) addr = 0x%x, data = 0x%02x%02x\n", + __func__, fg->reg_addr, data[1], data[0]); + max17050_write_reg(fg->client, + fg->reg_addr, data); + ret = count; + } + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +#endif + +#ifdef CONFIG_FUELGAUGE_MAX17050_COULOMB_COUNTING +static int fg_i2c_read(struct i2c_client *client, + u8 reg, u8 *data, u8 length) +{ + s32 value; + + value = i2c_smbus_read_i2c_block_data(client, reg, length, data); + if (value < 0 || value != length) { + dev_err(&client->dev, "%s: Error(%d)\n", + __func__, value); + return -1; + } + + return 0; +} + +static int fg_i2c_write(struct i2c_client *client, + u8 reg, u8 *data, u8 length) +{ + s32 value; + + value = i2c_smbus_write_i2c_block_data(client, reg, length, data); + if (value < 0) { + dev_err(&client->dev, "%s: Error(%d)\n", + __func__, value); + return -1; + } + + return 0; +} + +static int fg_read_register(struct i2c_client *client, + u8 addr) +{ + u8 data[2]; + + if (fg_i2c_read(client, addr, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read addr(0x%x)\n", + __func__, addr); + return -1; + } + + return (data[1] << 8) | data[0]; +} + +static int fg_write_register(struct i2c_client *client, + u8 addr, u16 w_data) +{ + u8 data[2]; + + data[0] = w_data & 0xFF; + data[1] = w_data >> 8; + + if (fg_i2c_write(client, addr, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to write addr(0x%x)\n", + __func__, addr); + return -1; + } + + return 0; +} + +static int fg_read_16register(struct i2c_client *client, + u8 addr, u16 *r_data) +{ + u8 data[32]; + int i = 0; + + if (fg_i2c_read(client, addr, data, 32) < 0) { + dev_err(&client->dev, "%s: Failed to read addr(0x%x)\n", + __func__, addr); + return -1; + } + + for (i = 0; i < 16; i++) + r_data[i] = (data[2 * i + 1] << 8) | data[2 * i]; + + return 0; +} + +static void fg_write_and_verify_register(struct i2c_client *client, + u8 addr, u16 w_data) +{ + u16 r_data; + u8 retry_cnt = 2; + + while (retry_cnt) { + fg_write_register(client, addr, w_data); + r_data = fg_read_register(client, addr); + + if (r_data != w_data) { + dev_err(&client->dev, + "%s: verification failed (addr: 0x%x, w_data: 0x%x, r_data: 0x%x)\n", + __func__, addr, w_data, r_data); + retry_cnt--; + } else + break; + } +} + +static void fg_test_print(struct i2c_client *client) +{ + u8 data[2]; + u32 average_vcell; + u16 w_data; + u32 temp; + u32 temp2; + u16 reg_data; + + if (fg_i2c_read(client, AVR_VCELL_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read VCELL\n", __func__); + return; + } + + w_data = (data[1]<<8) | data[0]; + + temp = (w_data & 0xFFF) * 78125; + average_vcell = temp / 1000000; + + temp = ((w_data & 0xF000) >> 4) * 78125; + temp2 = temp / 1000000; + average_vcell += (temp2 << 4); + + dev_info(&client->dev, "%s: AVG_VCELL(%d), data(0x%04x)\n", __func__, + average_vcell, (data[1]<<8) | data[0]); + + reg_data = fg_read_register(client, FULLCAP_REG); + dev_info(&client->dev, "%s: FULLCAP(%d), data(0x%04x)\n", __func__, + reg_data/2, reg_data); + + reg_data = fg_read_register(client, REMCAP_REP_REG); + dev_info(&client->dev, "%s: REMCAP_REP(%d), data(0x%04x)\n", __func__, + reg_data/2, reg_data); + + reg_data = fg_read_register(client, REMCAP_MIX_REG); + dev_info(&client->dev, "%s: REMCAP_MIX(%d), data(0x%04x)\n", __func__, + reg_data/2, reg_data); + + reg_data = fg_read_register(client, REMCAP_AV_REG); + dev_info(&client->dev, "%s: REMCAP_AV(%d), data(0x%04x)\n", __func__, + reg_data/2, reg_data); +} + +static void fg_periodic_read(struct i2c_client *client) +{ + u8 reg; + int i; + int data[0x10]; + char *str = NULL; + + str = kzalloc(sizeof(char)*1024, GFP_KERNEL); + if (!str) + return; + + for (i = 0; i < 16; i++) { + for (reg = 0; reg < 0x10; reg++) + data[reg] = fg_read_register(client, reg + i * 0x10); + + sprintf(str+strlen(str), + "%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,", + data[0x00], data[0x01], data[0x02], data[0x03], + data[0x04], data[0x05], data[0x06], data[0x07]); + sprintf(str+strlen(str), + "%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,%04xh,", + data[0x08], data[0x09], data[0x0a], data[0x0b], + data[0x0c], data[0x0d], data[0x0e], data[0x0f]); + if (i == 4) + i = 13; + } + + dev_info(&client->dev, "%s", str); + + kfree(str); +} + +static void fg_read_regs(struct i2c_client *client, char *str) +{ + int data = 0; + u32 addr = 0; + + for (addr = 0; addr <= 0x4f; addr++) { + data = fg_read_register(client, addr); + sprintf(str+strlen(str), "0x%04x, ", data); + } + + /* "#" considered as new line in application */ + sprintf(str+strlen(str), "#"); + + for (addr = 0xe0; addr <= 0xff; addr++) { + data = fg_read_register(client, addr); + sprintf(str+strlen(str), "0x%04x, ", data); + } +} + +static int fg_read_vcell(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + u32 vcell; + u16 w_data; + u32 temp; + u32 temp2; + + if (fg_i2c_read(client, VCELL_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read VCELL\n", __func__); + return -1; + } + + w_data = (data[1]<<8) | data[0]; + + temp = (w_data & 0xFFF) * 78125; + vcell = temp / 1000000; + + temp = ((w_data & 0xF000) >> 4) * 78125; + temp2 = temp / 1000000; + vcell += (temp2 << 4); + + if (!(fuelgauge->info.pr_cnt % PRINT_COUNT)) + dev_info(&client->dev, "%s: VCELL(%d), data(0x%04x)\n", + __func__, vcell, (data[1]<<8) | data[0]); + + return vcell; +} + +static int fg_read_vfocv(struct i2c_client *client) +{ + u8 data[2]; + u32 vfocv = 0; + u16 w_data; + u32 temp; + u32 temp2; + + if (fg_i2c_read(client, VFOCV_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read VFOCV\n", __func__); + return -1; + } + + w_data = (data[1]<<8) | data[0]; + + temp = (w_data & 0xFFF) * 78125; + vfocv = temp / 1000000; + + temp = ((w_data & 0xF000) >> 4) * 78125; + temp2 = temp / 1000000; + vfocv += (temp2 << 4); + + return vfocv; +} + +static int fg_read_avg_vcell(struct i2c_client *client) +{ + u8 data[2]; + u32 avg_vcell = 0; + u16 w_data; + u32 temp; + u32 temp2; + + if (fg_i2c_read(client, AVR_VCELL_REG, data, 2) < 0) { + dev_err(&client->dev, + "%s: Failed to read AVG_VCELL\n", __func__); + return -1; + } + + w_data = (data[1]<<8) | data[0]; + + temp = (w_data & 0xFFF) * 78125; + avg_vcell = temp / 1000000; + + temp = ((w_data & 0xF000) >> 4) * 78125; + temp2 = temp / 1000000; + avg_vcell += (temp2 << 4); + + return avg_vcell; +} + +static int fg_check_battery_present(struct i2c_client *client) +{ + u8 status_data[2]; + int ret = 1; + + /* 1. Check Bst bit */ + if (fg_i2c_read(client, STATUS_REG, status_data, 2) < 0) { + dev_err(&client->dev, + "%s: Failed to read STATUS_REG\n", __func__); + return 0; + } + + if (status_data[0] & (0x1 << 3)) { + dev_info(&client->dev, + "%s: addr(0x01), data(0x%04x)\n", __func__, + (status_data[1]<<8) | status_data[0]); + dev_info(&client->dev, "%s: battery is absent!!\n", __func__); + ret = 0; + } + + return ret; +} + + +static int fg_read_temp(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + int temper = 0; + int i; + + if (fg_check_battery_present(client)) { + if (fg_i2c_read(client, TEMPERATURE_REG, data, 2) < 0) { + dev_err(&client->dev, + "%s: Failed to read TEMPERATURE_REG\n", + __func__); + return -1; + } + + if (data[1]&(0x1 << 7)) { + temper = ((~(data[1]))&0xFF)+1; + temper *= (-1000); + temper -= ((~((int)data[0]))+1) * 39 / 10; + } else { + temper = data[1] & 0x7f; + temper *= 1000; + temper += data[0] * 39 / 10; + + /* Adjust temperature */ + for (i = 0; i < TEMP_RANGE_MAX_NUM-1; i++) { + if ((temper >= get_battery_data(fuelgauge). + temp_adjust_table[i][RANGE]) && + (temper < get_battery_data(fuelgauge). + temp_adjust_table[i+1][RANGE])) { + temper = (temper * + get_battery_data(fuelgauge). + temp_adjust_table[i][SLOPE] / + 100) - + get_battery_data(fuelgauge). + temp_adjust_table[i][OFFSET]; + } + } + if (i == TEMP_RANGE_MAX_NUM-1) + dev_dbg(&client->dev, + "%s : No adjustment for temperature\n", + __func__); + } + } else + temper = 20000; + + if (!(fuelgauge->info.pr_cnt % PRINT_COUNT)) + dev_info(&client->dev, "%s: TEMPERATURE(%d), data(0x%04x)\n", + __func__, temper, (data[1]<<8) | data[0]); + + return temper/100; +} + +/* soc should be 0.1% unit */ +static int fg_read_vfsoc(struct i2c_client *client) +{ + u8 data[2]; + int soc; + + if (fg_i2c_read(client, VFSOC_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read VFSOC\n", __func__); + return -1; + } + + soc = ((data[1] * 100) + (data[0] * 100 / 256)) / 10; + + return min(soc, 1000); +} + +/* soc should be 0.1% unit */ +static int fg_read_avsoc(struct i2c_client *client) +{ + u8 data[2]; + int soc; + + if (fg_i2c_read(client, SOCAV_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read AVSOC\n", __func__); + return -1; + } + + soc = ((data[1] * 100) + (data[0] * 100 / 256)) / 10; + + return min(soc, 1000); +} + +/* soc should be 0.1% unit */ +static int fg_read_soc(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + int soc; + + if (fg_i2c_read(client, SOCREP_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read SOCREP\n", __func__); + return -1; + } + + soc = ((data[1] * 100) + (data[0] * 100 / 256)) / 10; + + dev_dbg(&client->dev, "%s: raw capacity (%d)\n", __func__, soc); + + if (!(fuelgauge->info.pr_cnt % PRINT_COUNT)) + dev_dbg(&client->dev, "%s: raw capacity (%d), data(0x%04x)\n", + __func__, soc, (data[1]<<8) | data[0]); + + return min(soc, 1000); +} + +static int fg_read_fullcap(struct i2c_client *client) +{ + u8 data[2]; + int ret; + + if (fg_i2c_read(client, FULLCAP_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read FULLCAP\n", __func__); + return -1; + } + + ret = (data[1] << 8) + data[0]; + + return ret; +} + +static int fg_read_mixcap(struct i2c_client *client) +{ + u8 data[2]; + int ret; + + if (fg_i2c_read(client, REMCAP_MIX_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read REMCAP_MIX_REG\n", + __func__); + return -1; + } + + ret = (data[1] << 8) + data[0]; + + return ret; +} + +static int fg_read_avcap(struct i2c_client *client) +{ + u8 data[2]; + int ret; + + if (fg_i2c_read(client, REMCAP_AV_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read REMCAP_AV_REG\n", + __func__); + return -1; + } + + ret = (data[1] << 8) + data[0]; + + return ret; +} + +static int fg_read_repcap(struct i2c_client *client) +{ + u8 data[2]; + int ret; + + if (fg_i2c_read(client, REMCAP_REP_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read REMCAP_REP_REG\n", + __func__); + return -1; + } + + ret = (data[1] << 8) + data[0]; + + return ret; +} + +static int fg_read_current(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data1[2], data2[2]; + u32 temp, sign; + s32 i_current; + s32 avg_current; + + if (fg_i2c_read(client, CURRENT_REG, data1, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read CURRENT\n", + __func__); + return -1; + } + + if (fg_i2c_read(client, AVG_CURRENT_REG, data2, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read AVERAGE CURRENT\n", + __func__); + return -1; + } + + temp = ((data1[1]<<8) | data1[0]) & 0xFFFF; + if (temp & (0x1 << 15)) { + sign = NEGATIVE; + temp = (~temp & 0xFFFF) + 1; + } else + sign = POSITIVE; + + /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ + i_current = temp * 15625 / 100000; + if (sign) + i_current *= -1; + + temp = ((data2[1]<<8) | data2[0]) & 0xFFFF; + if (temp & (0x1 << 15)) { + sign = NEGATIVE; + temp = (~temp & 0xFFFF) + 1; + } else + sign = POSITIVE; + + /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ + avg_current = temp * 15625 / 100000; + if (sign) + avg_current *= -1; + + if (!(fuelgauge->info.pr_cnt++ % PRINT_COUNT)) { + fg_test_print(client); + dev_info(&client->dev, "%s: CURRENT(%dmA), AVG_CURRENT(%dmA)\n", + __func__, i_current, avg_current); + fuelgauge->info.pr_cnt = 1; + /* Read max17050's all registers every 5 minute. */ + fg_periodic_read(client); + } + + return i_current; +} + +static int fg_read_avg_current(struct i2c_client *client) +{ + u8 data2[2]; + u32 temp, sign; + s32 avg_current; + + if (fg_i2c_read(client, AVG_CURRENT_REG, data2, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read AVERAGE CURRENT\n", + __func__); + return -1; + } + + temp = ((data2[1]<<8) | data2[0]) & 0xFFFF; + if (temp & (0x1 << 15)) { + sign = NEGATIVE; + temp = (~temp & 0xFFFF) + 1; + } else + sign = POSITIVE; + + /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ + avg_current = temp * 15625 / 100000; + + if (sign) + avg_current *= -1; + + return avg_current; +} + +int fg_reset_soc(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + u8 data[2]; + int vfocv, fullcap; + + /* delay for current stablization */ + msleep(500); + + dev_info(&client->dev, + "%s: Before quick-start - VCELL(%d), VFOCV(%d), VfSOC(%d), RepSOC(%d)\n", + __func__, fg_read_vcell(client), fg_read_vfocv(client), + fg_read_vfsoc(client), fg_read_soc(client)); + dev_info(&client->dev, + "%s: Before quick-start - current(%d), avg current(%d)\n", + __func__, fg_read_current(client), + fg_read_avg_current(client)); + + if (!fuelgauge->pdata->check_jig_status()) { + dev_info(&client->dev, + "%s : Return by No JIG_ON signal\n", __func__); + return 0; + } + + fg_write_register(client, CYCLES_REG, 0); + + if (fg_i2c_read(client, MISCCFG_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read MiscCFG\n", __func__); + return -1; + } + + data[1] |= (0x1 << 2); + if (fg_i2c_write(client, MISCCFG_REG, data, 2) < 0) { + dev_err(&client->dev, + "%s: Failed to write MiscCFG\n", __func__); + return -1; + } + + msleep(250); + fg_write_register(client, FULLCAP_REG, + get_battery_data(fuelgauge).Capacity); + msleep(500); + + dev_info(&client->dev, + "%s: After quick-start - VCELL(%d), VFOCV(%d), VfSOC(%d), RepSOC(%d)\n", + __func__, fg_read_vcell(client), fg_read_vfocv(client), + fg_read_vfsoc(client), fg_read_soc(client)); + dev_info(&client->dev, + "%s: After quick-start - current(%d), avg current(%d)\n", + __func__, fg_read_current(client), + fg_read_avg_current(client)); + fg_write_register(client, CYCLES_REG, 0x00a0); + +/* P8 is not turned off by Quickstart @3.4V + * (It's not a problem, depend on mode data) + * Power off for factory test(File system, etc..) */ + vfocv = fg_read_vfocv(client); + if (vfocv < POWER_OFF_VOLTAGE_LOW_MARGIN) { + dev_info(&client->dev, "%s: Power off condition(%d)\n", + __func__, vfocv); + + fullcap = fg_read_register(client, FULLCAP_REG); + /* FullCAP * 0.009 */ + fg_write_register(client, REMCAP_REP_REG, + (u16)(fullcap * 9 / 1000)); + msleep(200); + dev_info(&client->dev, "%s: new soc=%d, vfocv=%d\n", __func__, + fg_read_soc(client), vfocv); + } + + dev_info(&client->dev, + "%s: Additional step - VfOCV(%d), VfSOC(%d), RepSOC(%d)\n", + __func__, fg_read_vfocv(client), + fg_read_vfsoc(client), fg_read_soc(client)); + + return 0; +} + + +int fg_reset_capacity_by_jig_connection(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + + dev_info(&client->dev, + "%s: DesignCap = Capacity - 1 (Jig Connection)\n", __func__); + + return fg_write_register(client, DESIGNCAP_REG, + get_battery_data(fuelgauge).Capacity-1); +} + +int fg_adjust_capacity(struct i2c_client *client) +{ + u8 data[2]; + + data[0] = 0; + data[1] = 0; + + /* 1. Write RemCapREP(05h)=0; */ + if (fg_i2c_write(client, REMCAP_REP_REG, data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to write RemCap_REP\n", + __func__); + return -1; + } + msleep(200); + + dev_info(&client->dev, "%s: After adjust - RepSOC(%d)\n", __func__, + fg_read_soc(client)); + + return 0; +} + +void fg_low_batt_compensation(struct i2c_client *client, u32 level) +{ + int read_val; + u32 temp; + + dev_info(&client->dev, "%s: Adjust SOCrep to %d!!\n", + __func__, level); + + read_val = fg_read_register(client, FULLCAP_REG); + if (read_val < 0) + return; + + if (read_val > 2) /* 3% compensation */ + /* RemCapREP (05h) = FullCap(10h) x 0.0301 */ + temp = read_val * (level*100 + 1) / 10000; + else /* 1% compensation */ + /* RemCapREP (05h) = FullCap(10h) x 0.0090 */ + temp = read_val * (level*90) / 10000; + fg_write_register(client, REMCAP_REP_REG, (u16)temp); +} + +static void fg_read_model_data(struct i2c_client *client) +{ + u16 data0[16], data1[16], data2[16]; + int i; + int relock_check; + + dev_info(&client->dev, "[FG_Model] "); + + /* Unlock model access */ + fg_write_register(client, 0x62, 0x0059); + fg_write_register(client, 0x63, 0x00C4); + + /* Read model data */ + fg_read_16register(client, 0x80, data0); + fg_read_16register(client, 0x90, data1); + fg_read_16register(client, 0xa0, data2); + + /* Print model data */ + for (i = 0; i < 16; i++) + dev_info(&client->dev, "0x%04x, ", data0[i]); + + for (i = 0; i < 16; i++) + dev_info(&client->dev, "0x%04x, ", data1[i]); + + for (i = 0; i < 16; i++) { + if (i == 15) + dev_info(&client->dev, "0x%04x", data2[i]); + else + dev_info(&client->dev, "0x%04x, ", data2[i]); + } + + do { + relock_check = 0; + /* Lock model access */ + fg_write_register(client, 0x62, 0x0000); + fg_write_register(client, 0x63, 0x0000); + + /* Read model data again */ + fg_read_16register(client, 0x80, data0); + fg_read_16register(client, 0x90, data1); + fg_read_16register(client, 0xa0, data2); + + for (i = 0; i < 16; i++) { + if (data0[i] || data1[i] || data2[i]) { + dev_dbg(&client->dev, + "%s: data is non-zero, lock again!!\n", + __func__); + relock_check = 1; + } + } + } while (relock_check); + +} + +static int fg_check_status_reg(struct i2c_client *client) +{ + u8 status_data[2]; + int ret = 0; + + /* 1. Check Smn was generatedread */ + if (fg_i2c_read(client, STATUS_REG, status_data, 2) < 0) { + dev_err(&client->dev, "%s: Failed to read STATUS_REG\n", + __func__); + return -1; + } + dev_info(&client->dev, "%s: addr(0x00), data(0x%04x)\n", __func__, + (status_data[1]<<8) | status_data[0]); + + if (status_data[1] & (0x1 << 2)) + ret = 1; + + /* 2. clear Status reg */ + status_data[1] = 0; + if (fg_i2c_write(client, STATUS_REG, status_data, 2) < 0) { + dev_info(&client->dev, "%s: Failed to write STATUS_REG\n", + __func__); + return -1; + } + + return ret; +} + +int get_fuelgauge_value(struct i2c_client *client, int data) +{ + int ret; + + switch (data) { + case FG_LEVEL: + ret = fg_read_soc(client); + break; + + case FG_TEMPERATURE: + ret = fg_read_temp(client); + break; + + case FG_VOLTAGE: + ret = fg_read_vcell(client); + break; + + case FG_CURRENT: + ret = fg_read_current(client); + break; + + case FG_CURRENT_AVG: + ret = fg_read_avg_current(client); + break; + + case FG_CHECK_STATUS: + ret = fg_check_status_reg(client); + break; + + case FG_VF_SOC: + ret = fg_read_vfsoc(client); + break; + + case FG_AV_SOC: + ret = fg_read_avsoc(client); + break; + + case FG_FULLCAP: + ret = fg_read_fullcap(client); + break; + + case FG_MIXCAP: + ret = fg_read_mixcap(client); + break; + + case FG_AVCAP: + ret = fg_read_avcap(client); + break; + + case FG_REPCAP: + ret = fg_read_repcap(client); + break; + + default: + ret = -1; + break; + } + + return ret; +} + +int fg_alert_init(struct i2c_client *client, int soc) +{ + u8 misccgf_data[2]; + u8 salrt_data[2]; + u8 config_data[2]; + u8 valrt_data[2]; + u8 talrt_data[2]; + u16 read_data = 0; + + /* Using RepSOC */ + if (fg_i2c_read(client, MISCCFG_REG, misccgf_data, 2) < 0) { + dev_err(&client->dev, + "%s: Failed to read MISCCFG_REG\n", __func__); + return -1; + } + misccgf_data[0] = misccgf_data[0] & ~(0x03); + + if (fg_i2c_write(client, MISCCFG_REG, misccgf_data, 2) < 0) { + dev_info(&client->dev, + "%s: Failed to write MISCCFG_REG\n", __func__); + return -1; + } + + /* SALRT Threshold setting */ + salrt_data[1] = 0xff; + salrt_data[0] = soc; + if (fg_i2c_write(client, SALRT_THRESHOLD_REG, salrt_data, 2) < 0) { + dev_info(&client->dev, + "%s: Failed to write SALRT_THRESHOLD_REG\n", __func__); + return -1; + } + + /* Reset VALRT Threshold setting (disable) */ + valrt_data[1] = 0xFF; + valrt_data[0] = 0x00; + if (fg_i2c_write(client, VALRT_THRESHOLD_REG, valrt_data, 2) < 0) { + dev_info(&client->dev, + "%s: Failed to write VALRT_THRESHOLD_REG\n", __func__); + return -1; + } + + read_data = fg_read_register(client, (u8)VALRT_THRESHOLD_REG); + if (read_data != 0xff00) + dev_err(&client->dev, + "%s: VALRT_THRESHOLD_REG is not valid (0x%x)\n", + __func__, read_data); + + /* Reset TALRT Threshold setting (disable) */ + talrt_data[1] = 0x7F; + talrt_data[0] = 0x80; + if (fg_i2c_write(client, TALRT_THRESHOLD_REG, talrt_data, 2) < 0) { + dev_info(&client->dev, + "%s: Failed to write TALRT_THRESHOLD_REG\n", __func__); + return -1; + } + + read_data = fg_read_register(client, (u8)TALRT_THRESHOLD_REG); + if (read_data != 0x7f80) + dev_err(&client->dev, + "%s: TALRT_THRESHOLD_REG is not valid (0x%x)\n", + __func__, read_data); + + mdelay(100); + + /* Enable SOC alerts */ + if (fg_i2c_read(client, CONFIG_REG, config_data, 2) < 0) { + dev_err(&client->dev, + "%s: Failed to read CONFIG_REG\n", __func__); + return -1; + } + config_data[0] = config_data[0] | (0x1 << 2); + + if (fg_i2c_write(client, CONFIG_REG, config_data, 2) < 0) { + dev_info(&client->dev, + "%s: Failed to write CONFIG_REG\n", __func__); + return -1; + } + + return 1; +} + +void fg_fullcharged_compensation(struct i2c_client *client, + u32 is_recharging, bool pre_update) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + static int new_fullcap_data; + + dev_info(&client->dev, "%s: is_recharging(%d), pre_update(%d)\n", + __func__, is_recharging, pre_update); + + new_fullcap_data = + fg_read_register(client, FULLCAP_REG); + if (new_fullcap_data < 0) + new_fullcap_data = get_battery_data(fuelgauge).Capacity; + + /* compare with initial capacity */ + if (new_fullcap_data > + (get_battery_data(fuelgauge).Capacity * 110 / 100)) { + dev_info(&client->dev, + "%s: [Case 1] capacity = 0x%04x, NewFullCap = 0x%04x\n", + __func__, get_battery_data(fuelgauge).Capacity, + new_fullcap_data); + + new_fullcap_data = + (get_battery_data(fuelgauge).Capacity * 110) / 100; + + fg_write_register(client, REMCAP_REP_REG, + (u16)(new_fullcap_data)); + fg_write_register(client, FULLCAP_REG, + (u16)(new_fullcap_data)); + } else if (new_fullcap_data < + (get_battery_data(fuelgauge).Capacity * 50 / 100)) { + dev_info(&client->dev, + "%s: [Case 5] capacity = 0x%04x, NewFullCap = 0x%04x\n", + __func__, get_battery_data(fuelgauge).Capacity, + new_fullcap_data); + + new_fullcap_data = + (get_battery_data(fuelgauge).Capacity * 50) / 100; + + fg_write_register(client, REMCAP_REP_REG, + (u16)(new_fullcap_data)); + fg_write_register(client, FULLCAP_REG, + (u16)(new_fullcap_data)); + } else { + /* compare with previous capacity */ + if (new_fullcap_data > + (fuelgauge->info.previous_fullcap * 110 / 100)) { + dev_info(&client->dev, + "%s: [Case 2] previous_fullcap = 0x%04x, NewFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_fullcap, + new_fullcap_data); + + new_fullcap_data = + (fuelgauge->info.previous_fullcap * 110) / 100; + + fg_write_register(client, REMCAP_REP_REG, + (u16)(new_fullcap_data)); + fg_write_register(client, FULLCAP_REG, + (u16)(new_fullcap_data)); + } else if (new_fullcap_data < + (fuelgauge->info.previous_fullcap * 90 / 100)) { + dev_info(&client->dev, + "%s: [Case 3] previous_fullcap = 0x%04x, NewFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_fullcap, + new_fullcap_data); + + new_fullcap_data = + (fuelgauge->info.previous_fullcap * 90) / 100; + + fg_write_register(client, REMCAP_REP_REG, + (u16)(new_fullcap_data)); + fg_write_register(client, FULLCAP_REG, + (u16)(new_fullcap_data)); + } else { + dev_info(&client->dev, + "%s: [Case 4] previous_fullcap = 0x%04x, NewFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_fullcap, + new_fullcap_data); + } + } + + /* 4. Write RepSOC(06h)=100%; */ + fg_write_register(client, SOCREP_REG, (u16)(0x64 << 8)); + + /* 5. Write MixSOC(0Dh)=100%; */ + fg_write_register(client, SOCMIX_REG, (u16)(0x64 << 8)); + + /* 6. Write AVSOC(0Eh)=100%; */ + fg_write_register(client, SOCAV_REG, (u16)(0x64 << 8)); + + /* if pre_update case, skip updating PrevFullCAP value. */ + if (!pre_update) + fuelgauge->info.previous_fullcap = + fg_read_register(client, FULLCAP_REG); + + dev_info(&client->dev, + "%s: (A) FullCap = 0x%04x, RemCap = 0x%04x\n", __func__, + fg_read_register(client, FULLCAP_REG), + fg_read_register(client, REMCAP_REP_REG)); + + fg_periodic_read(client); +} + +void fg_check_vf_fullcap_range(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + static int new_vffullcap; + bool is_vffullcap_changed = true; + + if (fuelgauge->pdata->check_jig_status()) + fg_reset_capacity_by_jig_connection(client); + + new_vffullcap = fg_read_register(client, FULLCAP_NOM_REG); + if (new_vffullcap < 0) + new_vffullcap = get_battery_data(fuelgauge).Capacity; + + /* compare with initial capacity */ + if (new_vffullcap > + (get_battery_data(fuelgauge).Capacity * 110 / 100)) { + dev_info(&client->dev, + "%s: [Case 1] capacity = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, get_battery_data(fuelgauge).Capacity, + new_vffullcap); + + new_vffullcap = + (get_battery_data(fuelgauge).Capacity * 110) / 100; + + fg_write_register(client, DQACC_REG, + (u16)(new_vffullcap / 4)); + fg_write_register(client, DPACC_REG, (u16)0x3200); + } else if (new_vffullcap < + (get_battery_data(fuelgauge).Capacity * 50 / 100)) { + dev_info(&client->dev, + "%s: [Case 5] capacity = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, get_battery_data(fuelgauge).Capacity, + new_vffullcap); + + new_vffullcap = + (get_battery_data(fuelgauge).Capacity * 50) / 100; + + fg_write_register(client, DQACC_REG, + (u16)(new_vffullcap / 4)); + fg_write_register(client, DPACC_REG, (u16)0x3200); + } else { + /* compare with previous capacity */ + if (new_vffullcap > + (fuelgauge->info.previous_vffullcap * 110 / 100)) { + dev_info(&client->dev, + "%s: [Case 2] previous_vffullcap = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_vffullcap, + new_vffullcap); + + new_vffullcap = + (fuelgauge->info.previous_vffullcap * 110) / + 100; + + fg_write_register(client, DQACC_REG, + (u16)(new_vffullcap / 4)); + fg_write_register(client, DPACC_REG, (u16)0x3200); + } else if (new_vffullcap < + (fuelgauge->info.previous_vffullcap * 90 / 100)) { + dev_info(&client->dev, + "%s: [Case 3] previous_vffullcap = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_vffullcap, + new_vffullcap); + + new_vffullcap = + (fuelgauge->info.previous_vffullcap * 90) / 100; + + fg_write_register(client, DQACC_REG, + (u16)(new_vffullcap / 4)); + fg_write_register(client, DPACC_REG, (u16)0x3200); + } else { + dev_info(&client->dev, + "%s: [Case 4] previous_vffullcap = 0x%04x, NewVfFullCap = 0x%04x\n", + __func__, fuelgauge->info.previous_vffullcap, + new_vffullcap); + is_vffullcap_changed = false; + } + } + + /* delay for register setting (dQacc, dPacc) */ + if (is_vffullcap_changed) + msleep(300); + + fuelgauge->info.previous_vffullcap = + fg_read_register(client, FULLCAP_NOM_REG); + + if (is_vffullcap_changed) + dev_info(&client->dev, + "%s : VfFullCap(0x%04x), dQacc(0x%04x), dPacc(0x%04x)\n", + __func__, + fg_read_register(client, FULLCAP_NOM_REG), + fg_read_register(client, DQACC_REG), + fg_read_register(client, DPACC_REG)); + +} + +void fg_set_full_charged(struct i2c_client *client) +{ + dev_info(&client->dev, "[FG_Set_Full] (B) FullCAP(%d), RemCAP(%d)\n", + (fg_read_register(client, FULLCAP_REG)/2), + (fg_read_register(client, REMCAP_REP_REG)/2)); + + fg_write_register(client, FULLCAP_REG, + (u16)fg_read_register(client, REMCAP_REP_REG)); + + dev_info(&client->dev, "[FG_Set_Full] (A) FullCAP(%d), RemCAP(%d)\n", + (fg_read_register(client, FULLCAP_REG)/2), + (fg_read_register(client, REMCAP_REP_REG)/2)); +} + +static void display_low_batt_comp_cnt(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + + pr_info("Check Array(%s): [%d, %d], [%d, %d], ", + get_battery_data(fuelgauge).type_str, + fuelgauge->info.low_batt_comp_cnt[0][0], + fuelgauge->info.low_batt_comp_cnt[0][1], + fuelgauge->info.low_batt_comp_cnt[1][0], + fuelgauge->info.low_batt_comp_cnt[1][1]); + pr_info("[%d, %d], [%d, %d], [%d, %d]\n", + fuelgauge->info.low_batt_comp_cnt[2][0], + fuelgauge->info.low_batt_comp_cnt[2][1], + fuelgauge->info.low_batt_comp_cnt[3][0], + fuelgauge->info.low_batt_comp_cnt[3][1], + fuelgauge->info.low_batt_comp_cnt[4][0], + fuelgauge->info.low_batt_comp_cnt[4][1]); +} + +static void add_low_batt_comp_cnt(struct i2c_client *client, + int range, int level) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + int i; + int j; + + /* Increase the requested count value, and reset others. */ + fuelgauge->info.low_batt_comp_cnt[range-1][level/2]++; + + for (i = 0; i < LOW_BATT_COMP_RANGE_NUM; i++) { + for (j = 0; j < LOW_BATT_COMP_LEVEL_NUM; j++) { + if (i == range-1 && j == level/2) + continue; + else + fuelgauge->info.low_batt_comp_cnt[i][j] = 0; + } + } +} + +void prevent_early_poweroff(struct i2c_client *client, + int vcell, int *fg_soc) +{ + int soc = 0; + int read_val; + + soc = get_fuelgauge_value(client, FG_LEVEL); + + if (soc > POWER_OFF_SOC_HIGH_MARGIN) + return; + + dev_info(&client->dev, "%s: soc=%d%%, vcell=%d\n", __func__, + soc, vcell); + + if (vcell > POWER_OFF_VOLTAGE_HIGH_MARGIN) { + read_val = fg_read_register(client, FULLCAP_REG); + /* FullCAP * 0.013 */ + fg_write_register(client, REMCAP_REP_REG, + (u16)(read_val * 13 / 1000)); + msleep(200); + *fg_soc = fg_read_soc(client); + dev_info(&client->dev, "%s : new soc=%d, vcell=%d\n", + __func__, *fg_soc, vcell); + } +} + +void reset_low_batt_comp_cnt(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + + memset(fuelgauge->info.low_batt_comp_cnt, 0, + sizeof(fuelgauge->info.low_batt_comp_cnt)); +} + +static int check_low_batt_comp_condition( + struct i2c_client *client, int *nLevel) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + int i; + int j; + int ret = 0; + + for (i = 0; i < LOW_BATT_COMP_RANGE_NUM; i++) { + for (j = 0; j < LOW_BATT_COMP_LEVEL_NUM; j++) { + if (fuelgauge->info.low_batt_comp_cnt[i][j] >= + MAX_LOW_BATT_CHECK_CNT) { + display_low_batt_comp_cnt(client); + ret = 1; + *nLevel = j*2 + 1; + break; + } + } + } + + return ret; +} + +static int get_low_batt_threshold(struct i2c_client *client, + int range, int nCurrent, int level) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + int ret = 0; + + ret = get_battery_data(fuelgauge).low_battery_table[range][OFFSET] + + ((nCurrent * + get_battery_data(fuelgauge).low_battery_table[range][SLOPE]) / + 1000); + + return ret; +} + +int low_batt_compensation(struct i2c_client *client, + int fg_soc, int fg_vcell, int fg_current) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + int fg_avg_current = 0; + int fg_min_current = 0; + int new_level = 0; + int i, table_size; + + /* Not charging, Under low battery comp voltage */ + if (fg_vcell <= get_battery_data(fuelgauge).low_battery_comp_voltage) { + fg_avg_current = fg_read_avg_current(client); + fg_min_current = min(fg_avg_current, fg_current); + + table_size = + sizeof(get_battery_data(fuelgauge).low_battery_table) / + (sizeof(s16)*TABLE_MAX); + + for (i = 1; i < CURRENT_RANGE_MAX_NUM; i++) { + if ((fg_min_current >= get_battery_data(fuelgauge). + low_battery_table[i-1][RANGE]) && + (fg_min_current < get_battery_data(fuelgauge). + low_battery_table[i][RANGE])) { + if (fg_soc >= 2 && fg_vcell < + get_low_batt_threshold(client, + i, fg_min_current, 1)) { + add_low_batt_comp_cnt( + client, i, 1); + } else { + reset_low_batt_comp_cnt(client); + } + } + } + + if (check_low_batt_comp_condition(client, &new_level)) { + fg_low_batt_compensation(client, new_level); + reset_low_batt_comp_cnt(client); + + /* Do not update soc right after + * low battery compensation + * to prevent from powering-off suddenly + */ + dev_info(&client->dev, + "%s: SOC is set to %d by low compensation!!\n", + __func__, fg_read_soc(client)); + } + } + + /* Prevent power off over 3500mV */ + prevent_early_poweroff(client, fg_vcell, &fg_soc); + + return fg_soc; +} + +static bool is_booted_in_low_battery(struct i2c_client *client) +{ + int fg_vcell = get_fuelgauge_value(client, FG_VOLTAGE); + int fg_current = get_fuelgauge_value(client, FG_CURRENT); + int threshold = 0; + + threshold = 3300 + ((fg_current * 17) / 100); + + if (fg_vcell <= threshold) + return true; + else + return false; +} + +static bool fuelgauge_recovery_handler(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + int current_soc; + int avsoc; + int temperature; + + if (fuelgauge->info.soc > LOW_BATTERY_SOC_REDUCE_UNIT) { + dev_err(&client->dev, + "%s: Reduce the Reported SOC by 1%%\n", + __func__); + current_soc = + get_fuelgauge_value(client, FG_LEVEL); + + if (current_soc) { + dev_info(&client->dev, + "%s: Returning to Normal discharge path\n", + __func__); + dev_info(&client->dev, + "%s: Actual SOC(%d) non-zero\n", + __func__, current_soc); + fuelgauge->info.is_low_batt_alarm = false; + } else { + temperature = + get_fuelgauge_value(client, FG_TEMPERATURE); + avsoc = + get_fuelgauge_value(client, FG_AV_SOC); + + if ((fuelgauge->info.soc > avsoc) || + (temperature < 0)) { + fuelgauge->info.soc -= + LOW_BATTERY_SOC_REDUCE_UNIT; + dev_err(&client->dev, + "%s: New Reduced RepSOC (%d)\n", + __func__, fuelgauge->info.soc); + } else + dev_info(&client->dev, + "%s: Waiting for recovery (AvSOC:%d)\n", + __func__, avsoc); + } + } + + return fuelgauge->info.is_low_batt_alarm; +} + +static int get_fuelgauge_soc(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + union power_supply_propval value; + int fg_soc; + int fg_vfsoc; + int fg_vcell; + int fg_current; + int avg_current; + ktime_t current_time; + struct timespec ts; + int fullcap_check_interval; + + if (fuelgauge->info.is_low_batt_alarm) + if (fuelgauge_recovery_handler(client)) + goto return_soc; + + current_time = alarm_get_elapsed_realtime(); + ts = ktime_to_timespec(current_time); + + /* check fullcap range */ + fullcap_check_interval = + (ts.tv_sec - fuelgauge->info.fullcap_check_interval); + if (fullcap_check_interval > + VFFULLCAP_CHECK_INTERVAL) { + dev_info(&client->dev, + "%s: check fullcap range (interval:%d)\n", + __func__, fullcap_check_interval); + fg_check_vf_fullcap_range(client); + fuelgauge->info.fullcap_check_interval = ts.tv_sec; + } + + fg_soc = get_fuelgauge_value(client, FG_LEVEL); + if (fg_soc < 0) { + dev_info(&client->dev, "Can't read soc!!!"); + fg_soc = fuelgauge->info.soc; + } + + if (fuelgauge->info.low_batt_boot_flag) { + fg_soc = 0; + + if (fuelgauge->pdata->check_cable_callback() != + POWER_SUPPLY_TYPE_BATTERY && + !is_booted_in_low_battery(client)) { + fg_adjust_capacity(client); + fuelgauge->info.low_batt_boot_flag = 0; + } + + if (fuelgauge->pdata->check_cable_callback() == + POWER_SUPPLY_TYPE_BATTERY) + fuelgauge->info.low_batt_boot_flag = 0; + } + + fg_vcell = get_fuelgauge_value(client, FG_VOLTAGE); + fg_current = get_fuelgauge_value(client, FG_CURRENT); + avg_current = get_fuelgauge_value(client, FG_CURRENT_AVG); + fg_vfsoc = get_fuelgauge_value(client, FG_VF_SOC); + + psy_do_property("battery", get, + POWER_SUPPLY_PROP_CHARGE_TYPE, value); + + /* Algorithm for reducing time to fully charged (from MAXIM) */ + if (value.intval != SEC_BATTERY_CHARGING_NONE && + value.intval != SEC_BATTERY_CHARGING_RECHARGING && + fuelgauge->cable_type != POWER_SUPPLY_TYPE_USB && + /* Skip when first check after boot up */ + !fuelgauge->info.is_first_check && + (fg_vfsoc > VFSOC_FOR_FULLCAP_LEARNING && + (fg_current > LOW_CURRENT_FOR_FULLCAP_LEARNING && + fg_current < HIGH_CURRENT_FOR_FULLCAP_LEARNING) && + (avg_current > LOW_AVGCURRENT_FOR_FULLCAP_LEARNING && + avg_current < HIGH_AVGCURRENT_FOR_FULLCAP_LEARNING))) { + + if (fuelgauge->info.full_check_flag == 2) { + dev_info(&client->dev, + "%s: force fully charged SOC !! (%d)", + __func__, fuelgauge->info.full_check_flag); + fg_set_full_charged(client); + fg_soc = get_fuelgauge_value(client, FG_LEVEL); + } else if (fuelgauge->info.full_check_flag < 2) + dev_info(&client->dev, + "%s: full_check_flag (%d)", + __func__, fuelgauge->info.full_check_flag); + + /* prevent overflow */ + if (fuelgauge->info.full_check_flag++ > 10000) + fuelgauge->info.full_check_flag = 3; + } else + fuelgauge->info.full_check_flag = 0; + + /* Checks vcell level and tries to compensate SOC if needed.*/ + /* If jig cable is connected, then skip low batt compensation check. */ + if (!fuelgauge->pdata->check_jig_status() && + value.intval == SEC_BATTERY_CHARGING_NONE) + fg_soc = low_batt_compensation( + client, fg_soc, fg_vcell, fg_current); + + if (fuelgauge->info.is_first_check) + fuelgauge->info.is_first_check = false; + + fuelgauge->info.soc = fg_soc; + +return_soc: + dev_dbg(&client->dev, "%s: soc(%d), low_batt_alarm(%d)\n", + __func__, fuelgauge->info.soc, + fuelgauge->info.is_low_batt_alarm); + + return fg_soc; +} + +static void full_comp_work_handler(struct work_struct *work) +{ + struct sec_fg_info *fg_info = + container_of(work, struct sec_fg_info, full_comp_work.work); + struct sec_fuelgauge_info *fuelgauge = + container_of(fg_info, struct sec_fuelgauge_info, info); + int avg_current; + union power_supply_propval value; + + avg_current = get_fuelgauge_value(fuelgauge->client, FG_CURRENT_AVG); + psy_do_property("battery", get, + POWER_SUPPLY_PROP_CHARGE_TYPE, value); + + if (avg_current >= 25) { + cancel_delayed_work(&fuelgauge->info.full_comp_work); + schedule_delayed_work(&fuelgauge->info.full_comp_work, 100); + } else { + dev_info(&fuelgauge->client->dev, + "%s: full charge compensation start (avg_current %d)\n", + __func__, avg_current); + fg_fullcharged_compensation(fuelgauge->client, + (int)(value.intval == + SEC_BATTERY_CHARGING_RECHARGING), false); + } +} + +bool sec_hal_fg_init(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = + i2c_get_clientdata(client); + ktime_t current_time; + struct timespec ts; + + current_time = alarm_get_elapsed_realtime(); + ts = ktime_to_timespec(current_time); + + fuelgauge->info.fullcap_check_interval = ts.tv_sec; + + fuelgauge->info.is_low_batt_alarm = false; + fuelgauge->info.is_first_check = true; + + /* Init parameters to prevent wrong compensation. */ + fuelgauge->info.previous_fullcap = + fg_read_register(client, FULLCAP_REG); + fuelgauge->info.previous_vffullcap = + fg_read_register(client, FULLCAP_NOM_REG); + + fg_read_model_data(client); + fg_periodic_read(client); + + if (fuelgauge->pdata->check_cable_callback() != + POWER_SUPPLY_TYPE_BATTERY && + is_booted_in_low_battery(client)) + fuelgauge->info.low_batt_boot_flag = 1; + + if (fuelgauge->pdata->check_jig_status()) + fg_reset_capacity_by_jig_connection(client); + + INIT_DELAYED_WORK(&fuelgauge->info.full_comp_work, + full_comp_work_handler); + + return true; +} + +bool sec_hal_fg_suspend(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_resume(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_fg_fuelalert_init(struct i2c_client *client, int soc) +{ + if (fg_alert_init(client, soc) > 0) + return true; + else + return false; +} + +bool sec_hal_fg_is_fuelalerted(struct i2c_client *client) +{ + if (get_fuelgauge_value(client, FG_CHECK_STATUS) > 0) + return true; + else + return false; +} + +bool sec_hal_fg_fuelalert_process(void *irq_data, bool is_fuel_alerted) +{ + struct sec_fuelgauge_info *fuelgauge = + (struct sec_fuelgauge_info *)irq_data; + union power_supply_propval value; + int overcurrent_limit_in_soc; + int current_soc = + get_fuelgauge_value(fuelgauge->client, FG_LEVEL); + + if (fuelgauge->info.soc <= STABLE_LOW_BATTERY_DIFF) + overcurrent_limit_in_soc = STABLE_LOW_BATTERY_DIFF_LOWBATT; + else + overcurrent_limit_in_soc = STABLE_LOW_BATTERY_DIFF; + + if ((fuelgauge->info.soc - current_soc) > + overcurrent_limit_in_soc) { + dev_info(&fuelgauge->client->dev, + "%s: Abnormal Current Consumption jump by %d units\n", + __func__, ((fuelgauge->info.soc - current_soc))); + dev_info(&fuelgauge->client->dev, + "%s: Last Reported SOC (%d).\n", + __func__, fuelgauge->info.soc); + + fuelgauge->info.is_low_batt_alarm = true; + + if (fuelgauge->info.soc >= + LOW_BATTERY_SOC_REDUCE_UNIT) + return true; + } + + psy_do_property("battery", get, + POWER_SUPPLY_PROP_CHARGE_TYPE, value); + + if (value.intval == + SEC_BATTERY_CHARGING_NONE) { + dev_err(&fuelgauge->client->dev, + "Set battery level as 0, power off.\n"); + fuelgauge->info.soc = 0; + value.intval = 0; + psy_do_property("battery", set, + POWER_SUPPLY_PROP_CAPACITY, value); + } + + return true; +} + +bool sec_hal_fg_full_charged(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = + i2c_get_clientdata(client); + union power_supply_propval value; + + psy_do_property("battery", get, + POWER_SUPPLY_PROP_CHARGE_TYPE, value); + + /* full charge compensation algorithm by MAXIM */ + fg_fullcharged_compensation(client, + (int)(value.intval == SEC_BATTERY_CHARGING_RECHARGING), true); + + cancel_delayed_work(&fuelgauge->info.full_comp_work); + schedule_delayed_work(&fuelgauge->info.full_comp_work, 100); + + return false; +} + +bool sec_hal_fg_reset(struct i2c_client *client) +{ + if (!fg_reset_soc(client)) + return true; + else + return false; +} + +bool sec_hal_fg_get_property(struct i2c_client *client, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + /* Cell voltage (VCELL, mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = get_fuelgauge_value(client, FG_VOLTAGE); + break; + /* Additional Voltage Information (mV) */ + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + switch (val->intval) { + case SEC_BATTEY_VOLTAGE_OCV: + val->intval = fg_read_vfocv(client); + break; + case SEC_BATTEY_VOLTAGE_AVERAGE: + default: + val->intval = fg_read_avg_vcell(client); + break; + } + break; + /* Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = get_fuelgauge_value(client, FG_CURRENT); + break; + /* Average Current (mA) */ + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = get_fuelgauge_value(client, FG_CURRENT_AVG); + break; + /* Full Capacity */ + case POWER_SUPPLY_PROP_ENERGY_NOW: + switch (val->intval) { + case SEC_BATTEY_CAPACITY_DESIGNED: + val->intval = get_fuelgauge_value(client, FG_FULLCAP); + break; + case SEC_BATTEY_CAPACITY_ABSOLUTE: + val->intval = get_fuelgauge_value(client, FG_MIXCAP); + break; + case SEC_BATTEY_CAPACITY_TEMPERARY: + val->intval = get_fuelgauge_value(client, FG_AVCAP); + break; + case SEC_BATTEY_CAPACITY_CURRENT: + val->intval = get_fuelgauge_value(client, FG_REPCAP); + break; + } + break; + /* SOC (%) */ + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = get_fuelgauge_soc(client); + break; + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + val->intval = get_fuelgauge_value(client, FG_TEMPERATURE); + break; + default: + return false; + } + return true; +} + +bool sec_hal_fg_set_property(struct i2c_client *client, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sec_fuelgauge_info *fuelgauge = + i2c_get_clientdata(client); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + if (val->intval != POWER_SUPPLY_TYPE_BATTERY) { + if (fuelgauge->info.is_low_batt_alarm) { + dev_info(&client->dev, + "%s: Reset low_batt_alarm\n", + __func__); + fuelgauge->info.is_low_batt_alarm = false; + } + + reset_low_batt_comp_cnt(client); + } + break; + /* Battery Temperature */ + case POWER_SUPPLY_PROP_TEMP: + /* Target Temperature */ + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + break; + default: + return false; + } + return true; +} + +ssize_t sec_hal_fg_show_attrs(struct device *dev, + const ptrdiff_t offset, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int i = 0; + char *str = NULL; + + switch (offset) { +/* case FG_REG: */ +/* break; */ + case FG_DATA: + i += scnprintf(buf + i, PAGE_SIZE - i, "%02x%02x\n", + fg->reg_data[1], fg->reg_data[0]); + break; + case FG_REGS: + str = kzalloc(sizeof(char)*1024, GFP_KERNEL); + if (!str) + return -ENOMEM; + + fg_read_regs(fg->client, str); + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", + str); + + kfree(str); + break; + default: + i = -EINVAL; + break; + } + + return i; +} + +ssize_t sec_hal_fg_store_attrs(struct device *dev, + const ptrdiff_t offset, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_fuelgauge_info *fg = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + int ret = 0; + int x = 0; + + switch (offset) { + case FG_REG: + if (sscanf(buf, "%x\n", &x) == 1) { + fg->reg_addr = x; + if (fg_i2c_read(fg->client, + fg->reg_addr, fg->reg_data, 2) < 0) { + dev_err(dev, "%s: Error in read\n", __func__); + break; + } + dev_dbg(dev, + "%s: (read) addr = 0x%x, data = 0x%02x%02x\n", + __func__, fg->reg_addr, + fg->reg_data[1], fg->reg_data[0]); + ret = count; + } + break; + case FG_DATA: + if (sscanf(buf, "%x\n", &x) == 1) { + dev_dbg(dev, "%s: (write) addr = 0x%x, data = 0x%04x\n", + __func__, fg->reg_addr, x); + fg_write_and_verify_register(fg->client, + fg->reg_addr, (u16)x); + ret = count; + } + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +#endif + diff --git a/drivers/battery/sec_battery.c b/drivers/battery/sec_battery.c new file mode 100644 index 00000000000..9d3d7ecb285 --- /dev/null +++ b/drivers/battery/sec_battery.c @@ -0,0 +1,2540 @@ +/* + * sec_battery.c + * Samsung Mobile Battery Driver + * + * Copyright (C) 2012 Samsung Electronics + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define DEBUG + +#include + +char *sec_bat_charging_mode_str[] = { + "None", + "Normal", + "Additional", + "Re-Charging" +}; + +char *sec_bat_status_str[] = { + "Unknown", + "Charging", + "Discharging", + "Not-charging", + "Full" +}; + +char *sec_bat_health_str[] = { + "Unknown", + "Good", + "Overheat", + "Dead", + "OverVoltage", + "UnspecFailure", + "Cold", + "UnderVoltage" +}; + +static int sec_bat_set_charge( + struct sec_battery_info *battery, + bool enable) +{ + union power_supply_propval val; + ktime_t current_time; + struct timespec ts; + + current_time = alarm_get_elapsed_realtime(); + ts = ktime_to_timespec(current_time); + + if (enable) { + val.intval = battery->cable_type; + /*Reset charging start time only in initial charging start */ + if (battery->charging_start_time == 0) { + battery->charging_start_time = ts.tv_sec; + battery->charging_next_time = + battery->pdata->charging_reset_time; + } + } else { + val.intval = POWER_SUPPLY_TYPE_BATTERY; + battery->charging_start_time = 0; + battery->charging_passed_time = 0; + battery->charging_next_time = 0; + battery->full_check_cnt = 0; + } + + battery->temp_high_cnt = 0; + battery->temp_low_cnt = 0; + battery->temp_recover_cnt = 0; + + psy_do_property("sec-charger", set, + POWER_SUPPLY_PROP_ONLINE, val); + + psy_do_property("sec-fuelgauge", set, + POWER_SUPPLY_PROP_ONLINE, val); + + return 0; +} + +static int sec_bat_get_adc_data(struct sec_battery_info *battery, + int adc_ch, int count) +{ + int adc_data; + int adc_max; + int adc_min; + int adc_total; + int i; + + adc_data = 0; + adc_max = 0; + adc_min = 0; + adc_total = 0; + + for (i = 0; i < count; i++) { + mutex_lock(&battery->adclock); + adc_data = adc_read(battery->pdata, adc_ch); + mutex_unlock(&battery->adclock); + + if (adc_data < 0) + goto err; + + if (i != 0) { + if (adc_data > adc_max) + adc_max = adc_data; + else if (adc_data < adc_min) + adc_min = adc_data; + } else { + adc_max = adc_data; + adc_min = adc_data; + } + adc_total += adc_data; + } + + return (adc_total - adc_max - adc_min) / (count - 2); +err: + return adc_data; +} + +static unsigned long calculate_average_adc( + struct sec_battery_info *battery, + int channel, int adc) +{ + unsigned int cnt = 0; + int total_adc = 0; + int average_adc = 0; + int index = 0; + + cnt = battery->adc_sample[channel].cnt; + total_adc = battery->adc_sample[channel].total_adc; + + if (adc < 0) { + dev_err(battery->dev, + "%s : Invalid ADC : %d\n", __func__, adc); + adc = battery->adc_sample[channel].average_adc; + } + + if (cnt < ADC_SAMPLE_COUNT) { + battery->adc_sample[channel].adc_arr[cnt] = adc; + battery->adc_sample[channel].index = cnt; + battery->adc_sample[channel].cnt = ++cnt; + + total_adc += adc; + average_adc = total_adc / cnt; + } else { + index = battery->adc_sample[channel].index; + if (++index >= ADC_SAMPLE_COUNT) + index = 0; + + total_adc = total_adc - + battery->adc_sample[channel].adc_arr[index] + adc; + average_adc = total_adc / ADC_SAMPLE_COUNT; + + battery->adc_sample[channel].adc_arr[index] = adc; + battery->adc_sample[channel].index = index; + } + + battery->adc_sample[channel].total_adc = total_adc; + battery->adc_sample[channel].average_adc = average_adc; + + return average_adc; +} + +static int sec_bat_get_adc_value( + struct sec_battery_info *battery, int channel) +{ + int adc; + + adc = sec_bat_get_adc_data(battery, channel, + battery->pdata->adc_check_count); + + if (adc < 0) { + dev_err(battery->dev, + "%s: Error in ADC\n", __func__); + return adc; + } + + return adc; +} + +static int sec_bat_get_charger_type_adc + (struct sec_battery_info *battery) +{ + /* It is true something valid is + connected to the device for charging. + By default this something is considered to be USB.*/ + int result = POWER_SUPPLY_TYPE_USB; + + int adc = 0; + int i; + + battery->pdata->cable_switch_check(); + + adc = sec_bat_get_adc_value(battery, + SEC_BAT_ADC_CHANNEL_CABLE_CHECK); + + battery->pdata->cable_switch_normal(); + + for (i = 0; i < SEC_SIZEOF_POWER_SUPPLY_TYPE; i++) + if ((adc > battery->pdata->cable_adc_value[i].min) && + (adc < battery->pdata->cable_adc_value[i].max)) + break; + if (i >= SEC_SIZEOF_POWER_SUPPLY_TYPE) + dev_err(battery->dev, + "%s : default USB\n", __func__); + else + result = i; + + dev_dbg(battery->dev, "%s : result(%d), adc(%d)\n", + __func__, result, adc); + + return result; +} + +static bool sec_bat_check_vf_adc(struct sec_battery_info *battery) +{ + int adc; + + adc = sec_bat_get_adc_data(battery, + SEC_BAT_ADC_CHANNEL_BAT_CHECK, + battery->pdata->adc_check_count); + + if (adc < 0) { + dev_err(battery->dev, "%s: VF ADC error\n", __func__); + adc = battery->check_adc_value; + } else + battery->check_adc_value = adc; + + if ((battery->check_adc_value < battery->pdata->check_adc_max) && + (battery->check_adc_value > battery->pdata->check_adc_min)) + return true; + else + return false; +} + +static bool sec_bat_check_by_psy(struct sec_battery_info *battery) +{ + char *psy_name; + union power_supply_propval value; + bool ret; + ret = true; + + switch (battery->pdata->battery_check_type) { + case SEC_BATTERY_CHECK_PMIC: + psy_name = battery->pdata->pmic_name; + break; + case SEC_BATTERY_CHECK_FUELGAUGE: + psy_name = "sec-fuelgauge"; + break; + case SEC_BATTERY_CHECK_CHARGER: + psy_name = "sec-charger"; + break; + default: + dev_err(battery->dev, + "%s: Invalid Battery Check Type\n", __func__); + ret = false; + goto battery_check_error; + break; + } + + psy_do_property(psy_name, get, + POWER_SUPPLY_PROP_PRESENT, value); + ret = (bool)value.intval; + +battery_check_error: + return ret; +} + +static bool sec_bat_check(struct sec_battery_info *battery) +{ + bool ret; + ret = true; + + if (battery->factory_mode) { + dev_dbg(battery->dev, "%s: No need to check in factory mode\n", + __func__); + return ret; + } + + if (battery->health != POWER_SUPPLY_HEALTH_GOOD && + battery->health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) { + dev_dbg(battery->dev, "%s: No need to check\n", __func__); + return ret; + } + + switch (battery->pdata->battery_check_type) { + case SEC_BATTERY_CHECK_ADC: + ret = sec_bat_check_vf_adc(battery); + break; + case SEC_BATTERY_CHECK_CALLBACK: + ret = battery->pdata->check_battery_callback(); + break; + case SEC_BATTERY_CHECK_PMIC: + case SEC_BATTERY_CHECK_FUELGAUGE: + case SEC_BATTERY_CHECK_CHARGER: + ret = sec_bat_check_by_psy(battery); + break; + case SEC_BATTERY_CHECK_INT: + ret = battery->present; + break; + case SEC_BATTERY_CHECK_NONE: + dev_dbg(battery->dev, "%s: No Check\n", __func__); + default: + break; + } + + return ret; +} + +static bool sec_bat_get_cable_type( + struct sec_battery_info *battery, + int cable_source_type) +{ + bool ret; + int cable_type; + + ret = false; + cable_type = battery->cable_type; + + if (cable_source_type & SEC_BATTERY_CABLE_SOURCE_CALLBACK) + cable_type = + battery->pdata->check_cable_callback(); + + if (cable_source_type & SEC_BATTERY_CABLE_SOURCE_ADC) { + if (gpio_get_value_cansleep( + battery->pdata->bat_gpio_ta_nconnected) ^ + battery->pdata->bat_polarity_ta_nconnected) + cable_type = POWER_SUPPLY_TYPE_BATTERY; + else + cable_type = + sec_bat_get_charger_type_adc(battery); + } + + if (battery->cable_type == cable_type) { + dev_dbg(battery->dev, + "%s: No need to change cable status\n", __func__); + } else { + if (cable_type < POWER_SUPPLY_TYPE_BATTERY || + cable_type >= SEC_SIZEOF_POWER_SUPPLY_TYPE) { + dev_err(battery->dev, + "%s: Invalid cable type\n", __func__); + } else { + battery->cable_type = cable_type; + battery->pdata->check_cable_result_callback( + battery->cable_type); + + ret = true; + + dev_dbg(battery->dev, "%s: Cable Changed (%d)\n", + __func__, battery->cable_type); + } + } + + return ret; +} + +static bool sec_bat_battery_cable_check(struct sec_battery_info *battery) +{ + if (!sec_bat_check(battery)) { + if (battery->check_count < battery->pdata->check_count) + battery->check_count++; + else { + dev_err(battery->dev, + "%s: Battery Disconnected\n", __func__); + battery->present = false; + battery->health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + + if (battery->status != + POWER_SUPPLY_STATUS_DISCHARGING) { + battery->status = + POWER_SUPPLY_STATUS_NOT_CHARGING; + sec_bat_set_charge(battery, false); + } + + battery->pdata->check_battery_result_callback(); + return false; + } + } else + battery->check_count = 0; + + battery->present = true; + + dev_dbg(battery->dev, "%s: Battery Connected\n", __func__); + + if (battery->pdata->cable_check_type & + SEC_BATTERY_CABLE_CHECK_POLLING) { + if (sec_bat_get_cable_type(battery, + battery->pdata->cable_source_type)) { + wake_lock(&battery->cable_wake_lock); + queue_work(battery->monitor_wqueue, + &battery->cable_work); + } + } + return true; +}; + +static int sec_bat_ovp_uvlo_by_psy(struct sec_battery_info *battery) +{ + char *psy_name; + union power_supply_propval value; + + value.intval = POWER_SUPPLY_HEALTH_GOOD; + + switch (battery->pdata->ovp_uvlo_check_type) { + case SEC_BATTERY_OVP_UVLO_PMICPOLLING: + psy_name = battery->pdata->pmic_name; + break; + case SEC_BATTERY_OVP_UVLO_CHGPOLLING: + psy_name = "sec-charger"; + break; + default: + dev_err(battery->dev, + "%s: Invalid OVP/UVLO Check Type\n", __func__); + goto ovp_uvlo_check_error; + break; + } + + psy_do_property(psy_name, get, + POWER_SUPPLY_PROP_HEALTH, value); + +ovp_uvlo_check_error: + return value.intval; +} + +static bool sec_bat_ovp_uvlo_result( + struct sec_battery_info *battery, int health) +{ + if (battery->health != health) { + battery->health = health; + switch (health) { + case POWER_SUPPLY_HEALTH_GOOD: + dev_info(battery->dev, "%s: Safe voltage\n", __func__); + battery->status = + POWER_SUPPLY_STATUS_CHARGING; + break; + case POWER_SUPPLY_HEALTH_OVERVOLTAGE: + case POWER_SUPPLY_HEALTH_UNDERVOLTAGE: + dev_info(battery->dev, + "%s: Unsafe voltage (%d)\n", + __func__, health); + battery->status = + POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + } + return true; + } + + return false; +} + +static bool sec_bat_ovp_uvlo(struct sec_battery_info *battery) +{ + int health; + + if (battery->health != POWER_SUPPLY_HEALTH_GOOD && + battery->health != POWER_SUPPLY_HEALTH_OVERVOLTAGE && + battery->health != POWER_SUPPLY_HEALTH_UNDERVOLTAGE) { + dev_dbg(battery->dev, "%s: No need to check\n", __func__); + return false; + } + + health = POWER_SUPPLY_HEALTH_GOOD; + + switch (battery->pdata->ovp_uvlo_check_type) { + case SEC_BATTERY_OVP_UVLO_CALLBACK: + health = battery->pdata->ovp_uvlo_callback(); + break; + case SEC_BATTERY_OVP_UVLO_PMICPOLLING: + case SEC_BATTERY_OVP_UVLO_CHGPOLLING: + health = sec_bat_ovp_uvlo_by_psy(battery); + break; + case SEC_BATTERY_OVP_UVLO_PMICINT: + case SEC_BATTERY_OVP_UVLO_CHGINT: + /* nothing for interrupt check */ + default: + break; + } + + return sec_bat_ovp_uvlo_result(battery, health); +} + +static bool sec_bat_check_recharge(struct sec_battery_info *battery) +{ + if ((battery->status == POWER_SUPPLY_STATUS_FULL || + (battery->status == POWER_SUPPLY_STATUS_CHARGING && + (battery->pdata->full_condition_type & + SEC_BATTERY_FULL_CONDITION_NOTIMEFULL))) && + (battery->charging_mode == SEC_BATTERY_CHARGING_NONE)) { + if ((battery->pdata->recharge_condition_type & + SEC_BATTERY_RECHARGE_CONDITION_SOC) && + (battery->capacity <= + battery->pdata->recharge_condition_soc)) { + dev_info(battery->dev, + "%s: Re-charging by SOC (%d)\n", + __func__, battery->capacity); + return true; + } + + if ((battery->pdata->recharge_condition_type & + SEC_BATTERY_RECHARGE_CONDITION_AVGVCELL) && + (battery->voltage_avg <= + battery->pdata->recharge_condition_avgvcell)) { + dev_info(battery->dev, + "%s: Re-charging by average VCELL (%d)\n", + __func__, battery->voltage_avg); + return true; + } + + if ((battery->pdata->recharge_condition_type & + SEC_BATTERY_RECHARGE_CONDITION_VCELL) && + (battery->voltage_now <= + battery->pdata->recharge_condition_vcell)) { + dev_info(battery->dev, + "%s: Re-charging by VCELL (%d)\n", + __func__, battery->voltage_now); + return true; + } + } + + return false; +} + +static bool sec_bat_voltage_check(struct sec_battery_info *battery) +{ + if (battery->status == POWER_SUPPLY_STATUS_DISCHARGING) { + dev_dbg(battery->dev, + "%s: Charging Disabled\n", __func__); + return true; + } + + /* OVP/UVLO check */ + if (sec_bat_ovp_uvlo(battery)) { + battery->pdata->ovp_uvlo_result_callback(battery->health); + return false; + } + + /* Re-Charging check */ + if (sec_bat_check_recharge(battery)) { + battery->charging_mode = SEC_BATTERY_CHARGING_RECHARGING; + sec_bat_set_charge(battery, true); + return false; + } + + return true; +} + +static bool sec_bat_get_temperature_by_adc( + struct sec_battery_info *battery, + enum power_supply_property psp, + union power_supply_propval *value) +{ + int temp = 0; + int temp_adc; + int low = 0; + int high = 0; + int mid = 0; + int channel; + sec_bat_adc_table_data_t *temp_adc_table; + unsigned int temp_adc_table_size; + + switch (psp) { + case POWER_SUPPLY_PROP_TEMP: + channel = SEC_BAT_ADC_CHANNEL_TEMP; + temp_adc_table = battery->pdata->temp_adc_table; + temp_adc_table_size = + battery->pdata->temp_adc_table_size; + break; + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + channel = SEC_BAT_ADC_CHANNEL_TEMP_AMBIENT; + temp_adc_table = battery->pdata->temp_amb_adc_table; + temp_adc_table_size = + battery->pdata->temp_amb_adc_table_size; + break; + default: + dev_err(battery->dev, + "%s: Invalid Property\n", __func__); + return false; + } + + temp_adc = sec_bat_get_adc_value(battery, channel); + if (temp_adc < 0) + return true; + battery->temp_adc = temp_adc; + + high = temp_adc_table_size - 1; + + while (low <= high) { + mid = (low + high) / 2; + if (temp_adc_table[mid].adc > temp_adc) + high = mid - 1; + else if (temp_adc_table[mid].adc < temp_adc) + low = mid + 1; + else + break; + } + /* index for ADC value will be bigger one between two indexes + * so if we will get base temperature value from mid-1 index + * but if ADC value is in outside of table, + * just get temperature by index + */ + if ((temp_adc_table[0].adc >= temp_adc) || + (temp_adc_table[temp_adc_table_size-1].adc <= temp_adc)) + temp = temp_adc_table[mid].temperature; + else + temp = temp_adc_table[mid-1].temperature; + + /* calculate middle value for temperature + * if mid is lowest or highest, + * just get temperature value by mid (limit value) + */ + if ((temp_adc_table[0].adc <= temp_adc) && + (temp_adc_table[temp_adc_table_size-1].adc >= temp_adc)) { + temp += + ((temp_adc_table[mid].temperature - + temp_adc_table[mid-1].temperature) * + (temp_adc - temp_adc_table[mid-1].adc)) / + (temp_adc_table[mid].adc - temp_adc_table[mid-1].adc); + } + + value->intval = temp; + + dev_dbg(battery->dev, + "%s: Temp(%d), Temp-ADC(%d)\n", + __func__, temp, temp_adc); + + return true; +} + +static bool sec_bat_temperature( + struct sec_battery_info *battery) +{ + bool ret; + ret = true; + + if (battery->pdata->event_check && battery->event) { + battery->temp_high_threshold = + battery->pdata->temp_high_threshold_event; + battery->temp_high_recovery = + battery->pdata->temp_high_recovery_event; + battery->temp_low_recovery = + battery->pdata->temp_low_recovery_event; + battery->temp_low_threshold = + battery->pdata->temp_low_threshold_event; + } else if (battery->pdata->is_lpm()) { + battery->temp_high_threshold = + battery->pdata->temp_high_threshold_lpm; + battery->temp_high_recovery = + battery->pdata->temp_high_recovery_lpm; + battery->temp_low_recovery = + battery->pdata->temp_low_recovery_lpm; + battery->temp_low_threshold = + battery->pdata->temp_low_threshold_lpm; + } else { + battery->temp_high_threshold = + battery->pdata->temp_high_threshold_normal; + battery->temp_high_recovery = + battery->pdata->temp_high_recovery_normal; + battery->temp_low_recovery = + battery->pdata->temp_low_recovery_normal; + battery->temp_low_threshold = + battery->pdata->temp_low_threshold_normal; + } + + dev_info(battery->dev, + "%s: HT(%d), HR(%d), LT(%d), LR(%d)\n", + __func__, battery->temp_high_threshold, + battery->temp_high_recovery, + battery->temp_low_threshold, + battery->temp_low_recovery); + return ret; +} + +static bool sec_bat_temperature_check( + struct sec_battery_info *battery) +{ + int temp_value; + bool health_changed; + + /* set health_changed true as default + * this value will be changed after temperature check + */ + health_changed = true; + + if (battery->status == POWER_SUPPLY_STATUS_DISCHARGING) { + dev_dbg(battery->dev, + "%s: Charging Disabled\n", __func__); + return true; + } + + if (battery->health != POWER_SUPPLY_HEALTH_GOOD && + battery->health != POWER_SUPPLY_HEALTH_OVERHEAT && + battery->health != POWER_SUPPLY_HEALTH_COLD) { + dev_dbg(battery->dev, "%s: No need to check\n", __func__); + return false; + } + + sec_bat_temperature(battery); + + switch (battery->pdata->temp_check_type) { + case SEC_BATTERY_TEMP_CHECK_ADC: + temp_value = battery->temp_adc; + break; + case SEC_BATTERY_TEMP_CHECK_TEMP: + temp_value = battery->temperature; + break; + default: + dev_err(battery->dev, + "%s: Invalid Temp Check Type\n", __func__); + return true; + } + + if (temp_value >= battery->temp_high_threshold) { + if (battery->health != POWER_SUPPLY_HEALTH_OVERHEAT) { + if (battery->temp_high_cnt < + battery->pdata->temp_check_count) + battery->temp_high_cnt++; + dev_dbg(battery->dev, + "%s: high count = %d\n", + __func__, battery->temp_high_cnt); + } + } else if ((temp_value <= battery->temp_high_recovery) && + (temp_value >= battery->temp_low_recovery)) { + if (battery->health == POWER_SUPPLY_HEALTH_OVERHEAT || + battery->health == POWER_SUPPLY_HEALTH_COLD) { + if (battery->temp_recover_cnt < + battery->pdata->temp_check_count) + battery->temp_recover_cnt++; + dev_dbg(battery->dev, + "%s: recovery count = %d\n", + __func__, battery->temp_recover_cnt); + } + } else if (temp_value <= battery->temp_low_threshold) { + if (battery->health != POWER_SUPPLY_HEALTH_COLD) { + if (battery->temp_low_cnt < + battery->pdata->temp_check_count) + battery->temp_low_cnt++; + dev_dbg(battery->dev, + "%s: low count = %d\n", + __func__, battery->temp_low_cnt); + } + } else { + battery->temp_high_cnt = 0; + battery->temp_low_cnt = 0; + battery->temp_recover_cnt = 0; + } + + if (battery->temp_high_cnt >= + battery->pdata->temp_check_count) + battery->health = POWER_SUPPLY_HEALTH_OVERHEAT; + else if (battery->temp_low_cnt >= + battery->pdata->temp_check_count) + battery->health = POWER_SUPPLY_HEALTH_COLD; + else if (battery->temp_recover_cnt >= + battery->pdata->temp_check_count) + battery->health = POWER_SUPPLY_HEALTH_GOOD; + else + health_changed = false; + + if (health_changed) { + if ((battery->health == POWER_SUPPLY_HEALTH_OVERHEAT) || + (battery->health == POWER_SUPPLY_HEALTH_COLD)) { + dev_info(battery->dev, + "%s: Unsafe Temperature\n", __func__); + battery->status = POWER_SUPPLY_STATUS_NOT_CHARGING; + /* change charging current to battery (default 0mA) */ + sec_bat_set_charge(battery, false); + } else { + dev_info(battery->dev, + "%s: Safe Temperature\n", __func__); + /* if recovered from not charging */ + if ((battery->health == POWER_SUPPLY_HEALTH_GOOD) && + (battery->status == + POWER_SUPPLY_STATUS_NOT_CHARGING)) { + if (battery->charging_mode == + SEC_BATTERY_CHARGING_RECHARGING) + battery->status = + POWER_SUPPLY_STATUS_FULL; + else /* Normal Charging */ + battery->status = + POWER_SUPPLY_STATUS_CHARGING; + /* turn on charger by cable type */ + sec_bat_set_charge(battery, true); + } + } + return false; + } + return true; +}; + +static void sec_bat_event_program_alarm( + struct sec_battery_info *battery, int seconds) +{ + ktime_t low_interval = ktime_set(seconds - 10, 0); + ktime_t slack = ktime_set(20, 0); + ktime_t next; + + next = ktime_add(battery->last_event_time, low_interval); + alarm_start_range(&battery->event_termination_alarm, + next, ktime_add(next, slack)); +} + +static void sec_bat_event_expired_timer_func(struct alarm *alarm) +{ + struct sec_battery_info *battery = + container_of(alarm, struct sec_battery_info, + event_termination_alarm); + + battery->event &= (~battery->event_wait); + dev_info(battery->dev, + "%s: event expired (0x%x)\n", __func__, battery->event); +} + +static void sec_bat_event_set( + struct sec_battery_info *battery, int event, int enable) +{ + if (!battery->pdata->event_check) + return; + + /* ignore duplicated deactivation of same event + * only if the event is one last event + */ + if (!enable && (battery->event == battery->event_wait)) { + dev_info(battery->dev, + "%s: ignore duplicated deactivation of same event\n", + __func__); + return; + } + + alarm_cancel(&battery->event_termination_alarm); + battery->event &= (~battery->event_wait); + + if (enable) { + battery->event_wait = 0; + battery->event |= event; + + dev_info(battery->dev, + "%s: event set (0x%x)\n", __func__, battery->event); + } else { + if (battery->event == 0) { + dev_dbg(battery->dev, + "%s: nothing to clear\n", __func__); + return; /* nothing to clear */ + } + battery->event_wait = event; + battery->last_event_time = alarm_get_elapsed_realtime(); + + sec_bat_event_program_alarm(battery, + battery->pdata->event_waiting_time); + dev_info(battery->dev, + "%s: start timer (curr 0x%x, wait 0x%x)\n", + __func__, battery->event, battery->event_wait); + } +} + +static bool sec_bat_check_fullcharged_condition( + struct sec_battery_info *battery) +{ + switch (battery->pdata->full_check_type) { + case SEC_BATTERY_FULLCHARGED_CHGGPIO: + case SEC_BATTERY_FULLCHARGED_CHGPSY: + /* NO additional full condition + * for full-charged check by charger + */ + return true; + case SEC_BATTERY_FULLCHARGED_CHGINT: + return false; + case SEC_BATTERY_FULLCHARGED_ADC: + case SEC_BATTERY_FULLCHARGED_ADC_DUAL: + case SEC_BATTERY_FULLCHARGED_FG_CURRENT: + case SEC_BATTERY_FULLCHARGED_FG_CURRENT_DUAL: + break; + } + + if (battery->pdata->full_condition_type & + SEC_BATTERY_FULL_CONDITION_SOC) { + if (battery->capacity < + battery->pdata->full_condition_soc) { + dev_dbg(battery->dev, + "%s: Not enough SOC (%d%%)\n", + __func__, battery->capacity); + return false; + } + } + + if (battery->pdata->full_condition_type & + SEC_BATTERY_FULL_CONDITION_VCELL) { + if (battery->voltage_now < + battery->pdata->full_condition_vcell) { + dev_dbg(battery->dev, + "%s: Not enough VCELL (%dmV)\n", + __func__, battery->voltage_now); + return false; + } + } + + if (battery->pdata->full_condition_type & + SEC_BATTERY_FULL_CONDITION_AVGVCELL) { + if (battery->voltage_avg < + battery->pdata->full_condition_avgvcell) { + dev_dbg(battery->dev, + "%s: Not enough AVGVCELL (%dmV)\n", + __func__, battery->voltage_avg); + return false; + } + } + + if (battery->pdata->full_condition_type & + SEC_BATTERY_FULL_CONDITION_OCV) { + if (battery->voltage_ocv < + battery->pdata->full_condition_ocv) { + dev_dbg(battery->dev, + "%s: Not enough OCV (%dmV)\n", + __func__, battery->voltage_ocv); + return false; + } + } + + return true; +} + +static bool sec_bat_time_management( + struct sec_battery_info *battery) +{ + unsigned long charging_time; + ktime_t current_time; + struct timespec ts; + + current_time = alarm_get_elapsed_realtime(); + ts = ktime_to_timespec(current_time); + + if (battery->charging_start_time == 0) { + dev_dbg(battery->dev, + "%s: Charging Disabled\n", __func__); + return true; + } + + if (ts.tv_sec >= battery->charging_start_time) + charging_time = ts.tv_sec - battery->charging_start_time; + else + charging_time = 0xFFFFFFFF - battery->charging_start_time + + ts.tv_sec; + + battery->charging_passed_time = charging_time; + + dev_info(battery->dev, + "%s: Charging Time : %ld secs\n", __func__, + battery->charging_passed_time); + + switch (battery->status) { + case POWER_SUPPLY_STATUS_FULL: + if (battery->charging_mode == SEC_BATTERY_CHARGING_RECHARGING && + (charging_time > + battery->pdata->recharging_total_time)) { + dev_dbg(battery->dev, + "%s: Recharging Timer Expired\n", __func__); + battery->charging_mode = SEC_BATTERY_CHARGING_NONE; + if (sec_bat_set_charge(battery, false)) { + dev_err(battery->dev, + "%s: Fail to Set Charger\n", __func__); + return true; + } + + return false; + } + break; + case POWER_SUPPLY_STATUS_CHARGING: + if ((battery->pdata->full_condition_type & + SEC_BATTERY_FULL_CONDITION_NOTIMEFULL) && + (battery->charging_mode == SEC_BATTERY_CHARGING_RECHARGING && + (charging_time > + battery->pdata->recharging_total_time))) { + dev_dbg(battery->dev, + "%s: Recharging Timer Expired\n", __func__); + if (battery->voltage_now > + battery->pdata->full_condition_vcell) + battery->status = + POWER_SUPPLY_STATUS_FULL; + battery->charging_mode = SEC_BATTERY_CHARGING_NONE; + if (sec_bat_set_charge(battery, false)) { + dev_err(battery->dev, + "%s: Fail to Set Charger\n", __func__); + return true; + } + return false; + } else if (battery->charging_mode == + SEC_BATTERY_CHARGING_NORMAL && + (charging_time > + battery->pdata->charging_total_time)) { + dev_dbg(battery->dev, + "%s: Charging Timer Expired\n", __func__); + if (battery->pdata->full_condition_type & + SEC_BATTERY_FULL_CONDITION_NOTIMEFULL) { + if (battery->voltage_now > + battery->pdata->full_condition_vcell) + battery->status = + POWER_SUPPLY_STATUS_FULL; + } else + battery->status = POWER_SUPPLY_STATUS_FULL; + battery->charging_mode = SEC_BATTERY_CHARGING_NONE; + if (sec_bat_set_charge(battery, false)) { + dev_err(battery->dev, + "%s: Fail to Set Charger\n", __func__); + return true; + } + + return false; + } + if (battery->pdata->charging_reset_time) { + if (charging_time > battery->charging_next_time) { + /*reset current in charging status */ + battery->charging_next_time = + battery->charging_passed_time + + (battery->pdata->charging_reset_time * + HZ); + + dev_dbg(battery->dev, + "%s: Reset charging current\n", + __func__); + if (sec_bat_set_charge(battery, true)) { + dev_err(battery->dev, + "%s: Fail to Set Charger\n", + __func__); + return true; + } + } + } + break; + default: + dev_err(battery->dev, + "%s: Undefine Battery Status\n", __func__); + return true; + } + + return true; +} + +static bool sec_bat_check_fullcharged( + struct sec_battery_info *battery) +{ + union power_supply_propval value; + int current_adc; + bool ret; + int err; + + ret = false; + + if (!sec_bat_check_fullcharged_condition(battery)) + goto not_full_charged; + + switch (battery->pdata->full_check_type) { + case SEC_BATTERY_FULLCHARGED_ADC_DUAL: + if (battery->charging_mode == + SEC_BATTERY_CHARGING_2ND) { + current_adc = + sec_bat_get_adc_value(battery, + SEC_BAT_ADC_CHANNEL_FULL_CHECK); + + dev_dbg(battery->dev, + "%s: Current ADC (%d)\n", + __func__, current_adc); + + if (current_adc < 0) + break; + battery->current_adc = current_adc; + + if (battery->current_adc < + battery->pdata->full_check_adc_2nd) { + battery->full_check_cnt++; + dev_dbg(battery->dev, + "%s: Full Check 2nd (%d)\n", + __func__, battery->full_check_cnt); + } else + battery->full_check_cnt = 0; + break; + } + case SEC_BATTERY_FULLCHARGED_ADC: + current_adc = + sec_bat_get_adc_value(battery, + SEC_BAT_ADC_CHANNEL_FULL_CHECK); + + dev_dbg(battery->dev, + "%s: Current ADC (%d)\n", + __func__, current_adc); + + if (current_adc < 0) + break; + battery->current_adc = current_adc; + + if (battery->current_adc < + battery->pdata->full_check_adc_1st) { + battery->full_check_cnt++; + dev_dbg(battery->dev, + "%s: Full Check ADC (%d)\n", + __func__, battery->full_check_cnt); + } else + battery->full_check_cnt = 0; + break; + + case SEC_BATTERY_FULLCHARGED_FG_CURRENT_DUAL: + if (battery->charging_mode == + SEC_BATTERY_CHARGING_2ND) { + if (battery->current_avg < + battery->pdata->charging_current[ + battery->cable_type].full_check_current_2nd) { + battery->full_check_cnt++; + dev_dbg(battery->dev, + "%s: Full Check Current 2nd (%d)\n", + __func__, battery->full_check_cnt); + } else + battery->full_check_cnt = 0; + break; + } + case SEC_BATTERY_FULLCHARGED_FG_CURRENT: + if (battery->current_avg < + battery->pdata->charging_current[ + battery->cable_type].full_check_current_1st) { + battery->full_check_cnt++; + dev_dbg(battery->dev, + "%s: Full Check Current (%d)\n", + __func__, battery->full_check_cnt); + } else + battery->full_check_cnt = 0; + break; + + case SEC_BATTERY_FULLCHARGED_CHGGPIO: + err = gpio_request( + battery->pdata->chg_gpio_full_check, + "GPIO_CHG_FULL"); + if (err) { + dev_err(battery->dev, + "%s: Error in Request of GPIO\n", __func__); + break; + } + if (!(gpio_get_value_cansleep( + battery->pdata->chg_gpio_full_check) ^ + !battery->pdata->chg_polarity_full_check)) { + battery->full_check_cnt++; + dev_dbg(battery->dev, + "%s: Full Check GPIO (%d)\n", + __func__, battery->full_check_cnt); + } else + battery->full_check_cnt = 0; + gpio_free(battery->pdata->chg_gpio_full_check); + break; + + case SEC_BATTERY_FULLCHARGED_CHGPSY: + psy_do_property("sec-charger", get, + POWER_SUPPLY_PROP_STATUS, value); + + if (value.intval == POWER_SUPPLY_STATUS_FULL) { + battery->full_check_cnt++; + dev_dbg(battery->dev, + "%s: Full Check Charger (%d)\n", + __func__, battery->full_check_cnt); + } else + battery->full_check_cnt = 0; + break; + + default: + dev_err(battery->dev, + "%s: Invalid Full Check\n", __func__); + break; + } + + if (battery->full_check_cnt >= + battery->pdata->full_check_count) { + battery->full_check_cnt = 0; + ret = true; + } + +not_full_charged: + return ret; +} + +static void sec_bat_do_fullcharged( + struct sec_battery_info *battery) +{ + union power_supply_propval value; + + if (((battery->pdata->full_check_type == + SEC_BATTERY_FULLCHARGED_ADC_DUAL) || + (battery->pdata->full_check_type == + SEC_BATTERY_FULLCHARGED_FG_CURRENT_DUAL)) && + (battery->charging_mode == + SEC_BATTERY_CHARGING_NORMAL)) { + battery->charging_mode = SEC_BATTERY_CHARGING_2ND; + } else { + battery->charging_mode = SEC_BATTERY_CHARGING_NONE; + sec_bat_set_charge(battery, false); + + value.intval = POWER_SUPPLY_STATUS_FULL; + psy_do_property("sec-fuelgauge", set, + POWER_SUPPLY_PROP_STATUS, value); + } + + /* platform can NOT get information of battery + * because wakeup time is too short to check uevent + * To make sure that target is wakeup if full-charged, + * activated wake lock in a few seconds + */ + wake_lock_timeout(&battery->vbus_wake_lock, HZ * 10); + battery->status = POWER_SUPPLY_STATUS_FULL; +} + +static bool sec_bat_fullcharged_check( + struct sec_battery_info *battery) +{ + if ((battery->charging_mode == SEC_BATTERY_CHARGING_NONE) || + (battery->status == POWER_SUPPLY_STATUS_NOT_CHARGING)) { + dev_dbg(battery->dev, + "%s: No Need to Check Full-Charged\n", __func__); + return true; + } + + if (sec_bat_check_fullcharged(battery)) + sec_bat_do_fullcharged(battery); + + dev_info(battery->dev, + "%s: Charging Mode : %s\n", __func__, + sec_bat_charging_mode_str[battery->charging_mode]); + + return true; +}; + +static void sec_bat_get_battery_info( + struct sec_battery_info *battery) +{ + union power_supply_propval value; + + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_VOLTAGE_NOW, value); + battery->voltage_now = value.intval; + + value.intval = SEC_BATTEY_VOLTAGE_AVERAGE; + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_VOLTAGE_AVG, value); + battery->voltage_avg = value.intval; + + value.intval = SEC_BATTEY_VOLTAGE_OCV; + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_VOLTAGE_AVG, value); + battery->voltage_ocv = value.intval; + + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_CURRENT_NOW, value); + battery->current_now = value.intval; + + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_CURRENT_AVG, value); + battery->current_avg = value.intval; + + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_CAPACITY, value); + battery->capacity = value.intval; + + switch (battery->pdata->thermal_source) { + case SEC_BATTERY_THERMAL_SOURCE_FG: + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_TEMP, value); + battery->temperature = value.intval; + + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_TEMP_AMBIENT, value); + battery->temper_amb = value.intval; + break; + case SEC_BATTERY_THERMAL_SOURCE_CALLBACK: + battery->pdata->get_temperature_callback( + POWER_SUPPLY_PROP_TEMP, &value); + psy_do_property("sec-fuelgauge", set, + POWER_SUPPLY_PROP_TEMP, value); + battery->temperature = value.intval; + + battery->pdata->get_temperature_callback( + POWER_SUPPLY_PROP_TEMP_AMBIENT, &value); + psy_do_property("sec-fuelgauge", set, + POWER_SUPPLY_PROP_TEMP_AMBIENT, value); + battery->temper_amb = value.intval; + break; + case SEC_BATTERY_THERMAL_SOURCE_ADC: + sec_bat_get_temperature_by_adc(battery, + POWER_SUPPLY_PROP_TEMP, &value); + psy_do_property("sec-fuelgauge", set, + POWER_SUPPLY_PROP_TEMP, value); + battery->temperature = value.intval; + + sec_bat_get_temperature_by_adc(battery, + POWER_SUPPLY_PROP_TEMP_AMBIENT, &value); + psy_do_property("sec-fuelgauge", set, + POWER_SUPPLY_PROP_TEMP_AMBIENT, value); + battery->temper_amb = value.intval; + break; + default: + break; + } + + dev_info(battery->dev, + "%s: %s, SOC(%d%%)\n", __func__, + battery->present ? "Connected" : "Disconnected", + battery->capacity); + dev_info(battery->dev, + "%s: Vnow(%dmV), Vavg(%dmV), Vocv(%dmV)\n", + __func__, battery->voltage_now, + battery->voltage_avg, battery->voltage_ocv); + dev_info(battery->dev, + "%s: Inow(%dmA), Iavg(%dmA), Iadc(%d)\n", + __func__, battery->current_now, + battery->current_avg, battery->current_adc); + dev_info(battery->dev, + "%s: Tbat(%d), Tamb(%d)\n", __func__, + battery->temperature, battery->temper_amb); +}; + +static void sec_bat_polling_work(struct work_struct *work) +{ + struct sec_battery_info *battery = container_of( + work, struct sec_battery_info, polling_work.work); + + wake_lock(&battery->monitor_wake_lock); + queue_work(battery->monitor_wqueue, &battery->monitor_work); + dev_dbg(battery->dev, "%s: Activated\n", __func__); +} + +static void sec_bat_program_alarm( + struct sec_battery_info *battery, int seconds) +{ + ktime_t low_interval = ktime_set(seconds, 0); + ktime_t slack = ktime_set(10, 0); + ktime_t next; + + next = ktime_add(battery->last_poll_time, low_interval); + alarm_start_range(&battery->polling_alarm, + next, ktime_add(next, slack)); +} + +static void sec_bat_alarm(struct alarm *alarm) +{ + struct sec_battery_info *battery = container_of(alarm, + struct sec_battery_info, polling_alarm); + + /* In wake up, monitor work will be queued in complete function + * To avoid duplicated queuing of monitor work, + * do NOT queue monitor work in wake up by polling alarm + */ + if (!battery->polling_in_sleep) { + wake_lock(&battery->monitor_wake_lock); + queue_work(battery->monitor_wqueue, &battery->monitor_work); + dev_dbg(battery->dev, "%s: Activated\n", __func__); + } +} + + +static unsigned int sec_bat_get_polling_time( + struct sec_battery_info *battery) +{ + if (battery->status == + POWER_SUPPLY_STATUS_FULL) + battery->polling_time = + battery->pdata->polling_time[ + POWER_SUPPLY_STATUS_CHARGING]; + else + battery->polling_time = + battery->pdata->polling_time[ + battery->status]; + + battery->polling_short = true; + + switch (battery->status) { + case POWER_SUPPLY_STATUS_CHARGING: + if (battery->polling_in_sleep) + battery->polling_short = false; + break; + case POWER_SUPPLY_STATUS_DISCHARGING: + if (battery->polling_in_sleep) + battery->polling_time = + battery->pdata->polling_time[ + SEC_BATTERY_POLLING_TIME_SLEEP]; + else + battery->polling_time = + battery->pdata->polling_time[ + battery->status]; + battery->polling_short = false; + break; + case POWER_SUPPLY_STATUS_FULL: + if (battery->polling_in_sleep) { + if (battery->charging_mode == + SEC_BATTERY_CHARGING_NONE) + battery->polling_time = + battery->pdata->polling_time[ + SEC_BATTERY_POLLING_TIME_SLEEP]; + battery->polling_short = false; + } else { + if (battery->charging_mode == + SEC_BATTERY_CHARGING_NONE) + battery->polling_short = false; + } + break; + } + + if (battery->polling_short) + return battery->pdata->polling_time[ + SEC_BATTERY_POLLING_TIME_BASIC]; + else + return battery->polling_time; +} + +static bool sec_bat_is_short_polling( + struct sec_battery_info *battery) +{ + if (battery->polling_short && + ((battery->polling_time / + battery->pdata->polling_time[ + SEC_BATTERY_POLLING_TIME_BASIC]) + > battery->polling_count)) + return true; + + return false; +} + +static void sec_bat_update_polling_count( + struct sec_battery_info *battery) +{ + /* do NOT change polling count in sleep + * even though it is short polling + * to keep polling count along sleep/wakeup + */ + if (battery->polling_short && battery->polling_in_sleep) + return; + + if (sec_bat_is_short_polling(battery)) + battery->polling_count++; + else + battery->polling_count = 1; /* initial value = 1 */ +} + +static void sec_bat_set_polling( + struct sec_battery_info *battery) +{ + unsigned int polling_time_temp; + + dev_dbg(battery->dev, "%s: Start\n", __func__); + + polling_time_temp = sec_bat_get_polling_time(battery); + + dev_dbg(battery->dev, + "%s: Status:%s, Sleep:%s, Charging:%s, Short Poll:%s\n", + __func__, sec_bat_status_str[battery->status], + battery->polling_in_sleep ? "Yes" : "No", + (battery->charging_mode == + SEC_BATTERY_CHARGING_NONE) ? "No" : "Yes", + battery->polling_short ? "Yes" : "No"); + dev_dbg(battery->dev, + "%s: Polling time %d/%d sec.\n", __func__, + battery->polling_short ? + (polling_time_temp * battery->polling_count) : + polling_time_temp, battery->polling_time); + + /* To sync with log above, + * change polling count after log is displayed + * Do NOT update polling count in initial monitor + */ + if (!battery->pdata->monitor_initial_count) + sec_bat_update_polling_count(battery); + else + dev_dbg(battery->dev, + "%s: Initial monitor %d times left.\n", __func__, + battery->pdata->monitor_initial_count); + + switch (battery->pdata->polling_type) { + case SEC_BATTERY_MONITOR_WORKQUEUE: + if (battery->pdata->monitor_initial_count) { + battery->pdata->monitor_initial_count--; + schedule_delayed_work(&battery->polling_work, HZ); + } else + schedule_delayed_work(&battery->polling_work, + polling_time_temp * HZ); + break; + case SEC_BATTERY_MONITOR_ALARM: + battery->last_poll_time = alarm_get_elapsed_realtime(); + if (battery->pdata->monitor_initial_count) { + battery->pdata->monitor_initial_count--; + sec_bat_program_alarm(battery, 1); + } else + sec_bat_program_alarm(battery, polling_time_temp); + break; + case SEC_BATTERY_MONITOR_TIMER: + break; + default: + break; + } + dev_dbg(battery->dev, "%s: End\n", __func__); +} + +static void sec_bat_monitor_work( + struct work_struct *work) +{ + struct sec_battery_info *battery = + container_of(work, struct sec_battery_info, + monitor_work); + + dev_dbg(battery->dev, "%s: Start\n", __func__); + + /* monitor once after wakeup */ + if (battery->polling_in_sleep) + battery->polling_in_sleep = false; + + sec_bat_get_battery_info(battery); + + /* 0. test mode */ + if (battery->test_activated) { + dev_dbg(battery->dev, "%s: Test Mode\n", __func__); + goto continue_monitor; + } + + /* 1. battery check */ + if (!sec_bat_battery_cable_check(battery)) + goto continue_monitor; + + /* 2. voltage check */ + if (!sec_bat_voltage_check(battery)) + goto continue_monitor; + + /* monitor short routine in initial monitor */ + if (battery->pdata->monitor_initial_count || + sec_bat_is_short_polling(battery)) + goto continue_monitor; + + /* 3. time management */ + if (!sec_bat_time_management(battery)) + goto continue_monitor; + + /* 4. temperature check */ + if (!sec_bat_temperature_check(battery)) + goto continue_monitor; + + /* 5. full charging check */ + sec_bat_fullcharged_check(battery); + +continue_monitor: + dev_info(battery->dev, + "%s: Status(%s), Health(%s), Cable(%d)\n", __func__, + sec_bat_status_str[battery->status], + sec_bat_health_str[battery->health], + battery->cable_type); + + battery->test_activated = false; + power_supply_changed(&battery->psy_bat); + + sec_bat_set_polling(battery); + + wake_unlock(&battery->monitor_wake_lock); + + dev_dbg(battery->dev, "%s: End\n", __func__); + + return; +} + +static void sec_bat_cable_work(struct work_struct *work) +{ + struct sec_battery_info *battery = container_of(work, + struct sec_battery_info, cable_work); + union power_supply_propval val; + + dev_dbg(battery->dev, "%s: Start\n", __func__); + /* platform can NOT get information of cable connection + * because wakeup time is too short to check uevent + * To make sure that target is wakeup + * if cable is connected and disconnected, + * activated wake lock in a few seconds + */ + wake_lock_timeout(&battery->vbus_wake_lock, HZ * 5); + + if (battery->cable_type == POWER_SUPPLY_TYPE_BATTERY) { + if (battery->status == POWER_SUPPLY_STATUS_FULL) + psy_do_property("sec-fuelgauge", set, + POWER_SUPPLY_PROP_CHARGE_FULL, val); + battery->charging_mode = SEC_BATTERY_CHARGING_NONE; + battery->status = POWER_SUPPLY_STATUS_DISCHARGING; + battery->health = POWER_SUPPLY_HEALTH_GOOD; + + if (sec_bat_set_charge(battery, false)) + goto end_of_cable_work; + } else { + /* Do NOT display the charging icon when OTG is enabled */ + if (battery->cable_type == POWER_SUPPLY_TYPE_OTG) { + battery->charging_mode = SEC_BATTERY_CHARGING_NONE; + battery->status = POWER_SUPPLY_STATUS_DISCHARGING; + } else { + battery->charging_mode = SEC_BATTERY_CHARGING_NORMAL; + battery->status = POWER_SUPPLY_STATUS_CHARGING; + } + + if (sec_bat_set_charge(battery, true)) + goto end_of_cable_work; + + /* No need for wakelock in Alarm */ + if (battery->pdata->polling_type != SEC_BATTERY_MONITOR_ALARM) + wake_lock(&battery->vbus_wake_lock); + } + + /* polling time should be reset when cable is changed + * polling_in_sleep should be reset also + * before polling time is re-calculated + * to prevent from counting 1 for events + * right after cable is connected + */ + battery->polling_in_sleep = false; + sec_bat_get_polling_time(battery); + + dev_dbg(battery->dev, + "%s: Status:%s, Sleep:%s, Charging:%s, Short Poll:%s\n", + __func__, sec_bat_status_str[battery->status], + battery->polling_in_sleep ? "Yes" : "No", + (battery->charging_mode == + SEC_BATTERY_CHARGING_NONE) ? "No" : "Yes", + battery->polling_short ? "Yes" : "No"); + dev_dbg(battery->dev, + "%s: Polling time is reset to %d sec.\n", __func__, + battery->polling_time); + + battery->polling_count = 1; /* initial value = 1 */ + + power_supply_changed(&battery->psy_ac); + power_supply_changed(&battery->psy_usb); + + wake_lock(&battery->monitor_wake_lock); + queue_work(battery->monitor_wqueue, &battery->monitor_work); +end_of_cable_work: + wake_unlock(&battery->cable_wake_lock); + dev_dbg(battery->dev, "%s: End\n", __func__); +} + +ssize_t sec_bat_show_attrs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_battery_info *battery = + container_of(psy, struct sec_battery_info, psy_bat); + const ptrdiff_t offset = attr - sec_battery_attrs; + int i = 0; + + switch (offset) { + case BATT_RESET_SOC: + break; + case BATT_READ_RAW_SOC: + break; + case BATT_READ_ADJ_SOC: + break; + case BATT_TYPE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", + battery->pdata->vendor); + break; + case BATT_VFOCV: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->voltage_ocv); + break; + case BATT_VOL_ADC: + break; + case BATT_VOL_ADC_CAL: + break; + case BATT_VOL_AVER: + break; + case BATT_VOL_ADC_AVER: + break; + case BATT_TEMP_ADC: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->temp_adc); + break; + case BATT_TEMP_AVER: + break; + case BATT_TEMP_ADC_AVER: + break; + case BATT_VF_ADC: + break; + + case BATT_LP_CHARGING: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->pdata->is_lpm() ? 1 : 0); + break; + case SIOP_ACTIVATED: + break; + case BATT_CHARGING_SOURCE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->cable_type); + break; + case FG_REG_DUMP: + break; + case FG_RESET_CAP: + break; + case FG_CAPACITY: + { + union power_supply_propval value; + + value.intval = + SEC_BATTEY_CAPACITY_DESIGNED; + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_ENERGY_NOW, value); + + i += scnprintf(buf + i, PAGE_SIZE - i, "0x%04x ", + value.intval); + + value.intval = + SEC_BATTEY_CAPACITY_ABSOLUTE; + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_ENERGY_NOW, value); + + i += scnprintf(buf + i, PAGE_SIZE - i, "0x%04x ", + value.intval); + + value.intval = + SEC_BATTEY_CAPACITY_TEMPERARY; + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_ENERGY_NOW, value); + + i += scnprintf(buf + i, PAGE_SIZE - i, "0x%04x ", + value.intval); + + value.intval = + SEC_BATTEY_CAPACITY_CURRENT; + psy_do_property("sec-fuelgauge", get, + POWER_SUPPLY_PROP_ENERGY_NOW, value); + + i += scnprintf(buf + i, PAGE_SIZE - i, "0x%04x\n", + value.intval); + } + break; + case AUTH: + break; + case CHG_CURRENT_ADC: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->current_adc); + break; + case WC_ADC: + break; + case WC_STATUS: + break; + + case FACTORY_MODE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->factory_mode); + break; + + case UPDATE: + break; + + case BATT_EVENT_2G_CALL: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_2G_CALL) ? 1 : 0); + break; + case BATT_EVENT_3G_CALL: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_3G_CALL) ? 1 : 0); + break; + case BATT_EVENT_MUSIC: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_MUSIC) ? 1 : 0); + break; + case BATT_EVENT_VIDEO: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_VIDEO) ? 1 : 0); + break; + case BATT_EVENT_BROWSER: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_BROWSER) ? 1 : 0); + break; + case BATT_EVENT_HOTSPOT: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_HOTSPOT) ? 1 : 0); + break; + case BATT_EVENT_CAMERA: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_CAMERA) ? 1 : 0); + break; + case BATT_EVENT_CAMCORDER: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_CAMCORDER) ? 1 : 0); + break; + case BATT_EVENT_DATA_CALL: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_DATA_CALL) ? 1 : 0); + break; + case BATT_EVENT_WIFI: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_WIFI) ? 1 : 0); + break; + case BATT_EVENT_WIBRO: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_WIBRO) ? 1 : 0); + break; + case BATT_EVENT_LTE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (battery->event & EVENT_LTE) ? 1 : 0); + break; + case BATT_EVENT: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->event); + break; + default: + i = -EINVAL; + } + + return i; +} + +ssize_t sec_bat_store_attrs( + struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_battery_info *battery = + container_of(psy, struct sec_battery_info, psy_bat); + const ptrdiff_t offset = attr - sec_battery_attrs; + int ret = 0; + int x = 0; + + switch (offset) { + case BATT_RESET_SOC: + /* Do NOT reset fuel gauge in charging mode */ + if (!battery->pdata->check_cable_callback()) { + union power_supply_propval value; + + value.intval = + SEC_FUELGAUGE_CAPACITY_TYPE_RESET; + psy_do_property("sec-fuelgauge", set, + POWER_SUPPLY_PROP_CAPACITY, value); + + /* update battery info */ + sec_bat_get_battery_info(battery); + } + ret = count; + break; + case BATT_READ_RAW_SOC: + break; + case BATT_READ_ADJ_SOC: + break; + case BATT_TYPE: + break; + case BATT_VFOCV: + break; + case BATT_VOL_ADC: + break; + case BATT_VOL_ADC_CAL: + break; + case BATT_VOL_AVER: + break; + case BATT_VOL_ADC_AVER: + break; + case BATT_TEMP_ADC: + break; + case BATT_TEMP_AVER: + break; + case BATT_TEMP_ADC_AVER: + break; + case BATT_VF_ADC: + break; + + case BATT_LP_CHARGING: + break; + case SIOP_ACTIVATED: + break; + case BATT_CHARGING_SOURCE: + break; + case FG_REG_DUMP: + break; + case FG_RESET_CAP: + break; + case FG_CAPACITY: + break; + case AUTH: + break; + case CHG_CURRENT_ADC: + break; + case WC_ADC: + break; + case WC_STATUS: + break; + case FACTORY_MODE: + if (sscanf(buf, "%d\n", &x) == 1) { + battery->factory_mode = x ? true : false; + ret = count; + } + break; + case UPDATE: + /* update battery info */ + sec_bat_get_battery_info(battery); + break; + + case BATT_EVENT_2G_CALL: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_2G_CALL, x); + ret = count; + } + break; + case BATT_EVENT_3G_CALL: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_3G_CALL, x); + ret = count; + } + break; + case BATT_EVENT_MUSIC: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_MUSIC, x); + ret = count; + } + break; + case BATT_EVENT_VIDEO: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_VIDEO, x); + ret = count; + } + break; + case BATT_EVENT_BROWSER: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_BROWSER, x); + ret = count; + } + break; + case BATT_EVENT_HOTSPOT: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_HOTSPOT, x); + ret = count; + } + break; + case BATT_EVENT_CAMERA: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_CAMERA, x); + ret = count; + } + break; + case BATT_EVENT_CAMCORDER: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_CAMCORDER, x); + ret = count; + } + break; + case BATT_EVENT_DATA_CALL: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_DATA_CALL, x); + ret = count; + } + break; + case BATT_EVENT_WIFI: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_WIFI, x); + ret = count; + } + break; + case BATT_EVENT_WIBRO: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_WIBRO, x); + ret = count; + } + break; + case BATT_EVENT_LTE: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_event_set(battery, EVENT_LTE, x); + ret = count; + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int sec_bat_create_attrs(struct device *dev) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(sec_battery_attrs); i++) { + rc = device_create_file(dev, &sec_battery_attrs[i]); + if (rc) + goto create_attrs_failed; + } + goto create_attrs_succeed; + +create_attrs_failed: + while (i--) + device_remove_file(dev, &sec_battery_attrs[i]); +create_attrs_succeed: + return rc; +} + +static int sec_bat_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sec_battery_info *battery = + container_of(psy, struct sec_battery_info, psy_bat); + + dev_dbg(battery->dev, + "%s: (%d,%d)\n", __func__, psp, val->intval); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if ((battery->pdata->full_check_type == + SEC_BATTERY_FULLCHARGED_CHGINT) && + (val->intval == POWER_SUPPLY_STATUS_FULL)) + sec_bat_do_fullcharged(battery); + battery->status = val->intval; + break; + case POWER_SUPPLY_PROP_HEALTH: + sec_bat_ovp_uvlo_result(battery, val->intval); + break; + case POWER_SUPPLY_PROP_ONLINE: + /* cable is attached or detached + * if val->intval is minus value, + * check cable by sec_bat_get_cable_type() + * although SEC_BATTERY_CABLE_SOURCE_EXTERNAL is set + */ + if ((val->intval >= POWER_SUPPLY_TYPE_BATTERY) && + (val->intval <= SEC_SIZEOF_POWER_SUPPLY_TYPE) && + (battery->pdata->cable_source_type & + SEC_BATTERY_CABLE_SOURCE_EXTERNAL)) { + /* skip cable work if cable is NOT changed */ + if (battery->cable_type != val->intval) { + battery->cable_type = val->intval; + battery->pdata->check_cable_result_callback( + battery->cable_type); + + wake_lock(&battery->cable_wake_lock); + queue_work(battery->monitor_wqueue, + &battery->cable_work); + } else { + dev_dbg(battery->dev, + "%s: Cable is NOT Changed(%d)\n", + __func__, battery->cable_type); + /* Do NOT activate cable work for NOT changed */ + } + } else { + if (sec_bat_get_cable_type(battery, + battery->pdata->cable_source_type)) { + wake_lock(&battery->cable_wake_lock); + queue_work(battery->monitor_wqueue, + &battery->cable_work); + } + } + break; + case POWER_SUPPLY_PROP_CAPACITY: + battery->capacity = val->intval; + power_supply_changed(&battery->psy_bat); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int sec_bat_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_battery_info *battery = + container_of(psy, struct sec_battery_info, psy_bat); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (battery->pdata->cable_check_type & + SEC_BATTERY_CABLE_CHECK_NOUSBCHARGE) { + switch (battery->cable_type) { + case POWER_SUPPLY_TYPE_USB: + case POWER_SUPPLY_TYPE_USB_DCP: + case POWER_SUPPLY_TYPE_USB_CDP: + case POWER_SUPPLY_TYPE_USB_ACA: + val->intval = + POWER_SUPPLY_STATUS_DISCHARGING; + return 0; + } + } + val->intval = battery->status; + break; + /* charging mode (differ from power supply) */ + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = battery->charging_mode; + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = battery->health; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = battery->present; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = battery->cable_type; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = battery->pdata->technology; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + /* voltage value should be in uV */ + val->intval = battery->voltage_now * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + /* voltage value should be in uV */ + val->intval = battery->voltage_avg * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = battery->current_now; + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = battery->current_avg; + break; + case POWER_SUPPLY_PROP_CAPACITY: + /* In full-charged status, SOC is always 100% */ + if (battery->status == POWER_SUPPLY_STATUS_FULL) + val->intval = 100; + else + val->intval = battery->capacity; + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = battery->temperature; + break; + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + val->intval = battery->temper_amb; + break; + default: + return -EINVAL; + } + return 0; +} + +static int sec_usb_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_battery_info *battery = + container_of(psy, struct sec_battery_info, psy_usb); + + if (psp != POWER_SUPPLY_PROP_ONLINE) + return -EINVAL; + + /* Set enable=1 only if the USB charger is connected */ + switch (battery->cable_type) { + case POWER_SUPPLY_TYPE_USB: + case POWER_SUPPLY_TYPE_USB_DCP: + case POWER_SUPPLY_TYPE_USB_CDP: + case POWER_SUPPLY_TYPE_USB_ACA: + val->intval = 1; + break; + default: + val->intval = 0; + break; + } + + return 0; +} + +static int sec_ac_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_battery_info *battery = + container_of(psy, struct sec_battery_info, psy_ac); + + if (psp != POWER_SUPPLY_PROP_ONLINE) + return -EINVAL; + + /* Set enable=1 only if the AC charger is connected */ + switch (battery->cable_type) { + case POWER_SUPPLY_TYPE_MAINS: + case POWER_SUPPLY_TYPE_MISC: + case POWER_SUPPLY_TYPE_CARDOCK: + case POWER_SUPPLY_TYPE_UARTOFF: + val->intval = 1; + break; + default: + val->intval = 0; + break; + } + + return 0; +} + +static irqreturn_t sec_bat_irq_thread(int irq, void *irq_data) +{ + struct sec_battery_info *battery = irq_data; + + if (battery->pdata->cable_check_type & + SEC_BATTERY_CABLE_CHECK_INT) { + if (sec_bat_get_cable_type(battery, + battery->pdata->cable_source_type)) { + wake_lock(&battery->cable_wake_lock); + queue_work(battery->monitor_wqueue, + &battery->cable_work); + } + } + + if (battery->pdata->battery_check_type == + SEC_BATTERY_CHECK_INT) { + battery->present = battery->pdata->check_battery_callback(); + + wake_lock(&battery->monitor_wake_lock); + queue_work(battery->monitor_wqueue, &battery->monitor_work); + } + + return IRQ_HANDLED; +} + +static int __devinit sec_battery_probe(struct platform_device *pdev) +{ + sec_battery_platform_data_t *pdata = dev_get_platdata(&pdev->dev); + struct sec_battery_info *battery; + int ret = 0; + int i; + + dev_dbg(&pdev->dev, + "%s: SEC Battery Driver Loading\n", __func__); + + battery = kzalloc(sizeof(*battery), GFP_KERNEL); + if (!battery) + return -ENOMEM; + + platform_set_drvdata(pdev, battery); + + battery->dev = &pdev->dev; + battery->pdata = pdata; + + mutex_init(&battery->adclock); + dev_dbg(battery->dev, "%s: ADC init\n", __func__); + for (i = 0; i < SEC_BAT_ADC_CHANNEL_FULL_CHECK; i++) + adc_init(pdev, pdata, i); + + wake_lock_init(&battery->monitor_wake_lock, WAKE_LOCK_SUSPEND, + "sec-battery-monitor"); + wake_lock_init(&battery->cable_wake_lock, WAKE_LOCK_SUSPEND, + "sec-battery-cable"); + wake_lock_init(&battery->vbus_wake_lock, WAKE_LOCK_SUSPEND, + "sec-battery-vbus"); + + /* initialization of battery info */ + battery->status = POWER_SUPPLY_STATUS_DISCHARGING; + battery->health = POWER_SUPPLY_HEALTH_GOOD; + battery->present = true; + + battery->polling_count = 1; /* initial value = 1 */ + battery->polling_time = pdata->polling_time[ + SEC_BATTERY_POLLING_TIME_DISCHARGING]; + battery->polling_in_sleep = false; + battery->polling_short = false; + + battery->check_count = 0; + battery->check_adc_count = 0; + battery->check_adc_value = 0; + + battery->charging_start_time = 0; + battery->charging_passed_time = 0; + battery->charging_next_time = 0; + + alarm_init(&battery->event_termination_alarm, + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + sec_bat_event_expired_timer_func); + + battery->temp_high_threshold = + pdata->temp_high_threshold_normal; + battery->temp_high_recovery = + pdata->temp_high_recovery_normal; + battery->temp_low_recovery = + pdata->temp_low_recovery_normal; + battery->temp_low_threshold = + pdata->temp_low_threshold_normal; + + battery->charging_mode = SEC_BATTERY_CHARGING_NONE; + battery->cable_type = POWER_SUPPLY_TYPE_BATTERY; + battery->test_activated = false; + battery->factory_mode = false; + + battery->psy_bat.name = "battery", + battery->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, + battery->psy_bat.properties = sec_battery_props, + battery->psy_bat.num_properties = ARRAY_SIZE(sec_battery_props), + battery->psy_bat.get_property = sec_bat_get_property, + battery->psy_bat.set_property = sec_bat_set_property, + battery->psy_usb.name = "usb", + battery->psy_usb.type = POWER_SUPPLY_TYPE_USB, + battery->psy_usb.supplied_to = supply_list, + battery->psy_usb.num_supplicants = ARRAY_SIZE(supply_list), + battery->psy_usb.properties = sec_power_props, + battery->psy_usb.num_properties = ARRAY_SIZE(sec_power_props), + battery->psy_usb.get_property = sec_usb_get_property, + battery->psy_ac.name = "ac", + battery->psy_ac.type = POWER_SUPPLY_TYPE_MAINS, + battery->psy_ac.supplied_to = supply_list, + battery->psy_ac.num_supplicants = ARRAY_SIZE(supply_list), + battery->psy_ac.properties = sec_power_props, + battery->psy_ac.num_properties = ARRAY_SIZE(sec_power_props), + battery->psy_ac.get_property = sec_ac_get_property; + + /* init power supplier framework */ + ret = power_supply_register(&pdev->dev, &battery->psy_bat); + if (ret) { + dev_err(battery->dev, + "%s: Failed to Register psy_bat\n", __func__); + goto err_wake_lock; + } + + ret = power_supply_register(&pdev->dev, &battery->psy_usb); + if (ret) { + dev_err(battery->dev, + "%s: Failed to Register psy_usb\n", __func__); + goto err_supply_unreg_bat; + } + + ret = power_supply_register(&pdev->dev, &battery->psy_ac); + if (ret) { + dev_err(battery->dev, + "%s: Failed to Register psy_ac\n", __func__); + goto err_supply_unreg_usb; + } + + if (!battery->pdata->bat_gpio_init()) { + dev_err(battery->dev, + "%s: Failed to Initialize GPIO\n", __func__); + goto err_supply_unreg_ac; + } + + /* create work queue */ + battery->monitor_wqueue = + create_singlethread_workqueue(dev_name(&pdev->dev)); + if (!battery->monitor_wqueue) { + dev_err(battery->dev, + "%s: Fail to Create Workqueue\n", __func__); + goto err_supply_unreg_ac; + } + INIT_WORK(&battery->monitor_work, sec_bat_monitor_work); + INIT_WORK(&battery->cable_work, sec_bat_cable_work); + + if (battery->pdata->bat_irq) { + ret = request_threaded_irq(battery->pdata->bat_irq, + NULL, sec_bat_irq_thread, + battery->pdata->bat_irq_attr, + "battery-irq", battery); + if (ret) { + dev_err(battery->dev, + "%s: Failed to Request IRQ\n", __func__); + goto err_workqueue; + } + + ret = enable_irq_wake(battery->pdata->bat_irq); + if (ret < 0) + dev_err(battery->dev, + "%s: Failed to Enable Wakeup Source(%d)\n", + __func__, ret); + } + + ret = sec_bat_create_attrs(battery->psy_bat.dev); + if (ret) { + dev_err(battery->dev, + "%s : Failed to create_attrs\n", __func__); + goto err_workqueue; + } + + switch (pdata->polling_type) { + case SEC_BATTERY_MONITOR_WORKQUEUE: + INIT_DELAYED_WORK_DEFERRABLE(&battery->polling_work, + sec_bat_polling_work); + break; + case SEC_BATTERY_MONITOR_ALARM: + battery->last_poll_time = alarm_get_elapsed_realtime(); + alarm_init(&battery->polling_alarm, + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + sec_bat_alarm); + break; + default: + break; + } + + wake_lock(&battery->monitor_wake_lock); + queue_work(battery->monitor_wqueue, &battery->monitor_work); + + pdata->initial_check(); + + dev_dbg(battery->dev, + "%s: SEC Battery Driver Loaded\n", __func__); + return 0; + +err_workqueue: + destroy_workqueue(battery->monitor_wqueue); +err_supply_unreg_ac: + power_supply_unregister(&battery->psy_ac); +err_supply_unreg_usb: + power_supply_unregister(&battery->psy_usb); +err_supply_unreg_bat: + power_supply_unregister(&battery->psy_bat); +err_wake_lock: + wake_lock_destroy(&battery->monitor_wake_lock); + wake_lock_destroy(&battery->cable_wake_lock); + wake_lock_destroy(&battery->vbus_wake_lock); + mutex_destroy(&battery->adclock); + kfree(battery); + + return ret; +} + +static int __devexit sec_battery_remove(struct platform_device *pdev) +{ + struct sec_battery_info *battery = platform_get_drvdata(pdev); + int i; + + dev_dbg(battery->dev, "%s: Start\n", __func__); + + switch (battery->pdata->polling_type) { + case SEC_BATTERY_MONITOR_WORKQUEUE: + cancel_delayed_work(&battery->polling_work); + break; + case SEC_BATTERY_MONITOR_ALARM: + alarm_cancel(&battery->polling_alarm); + break; + default: + break; + } + + alarm_cancel(&battery->event_termination_alarm); + flush_workqueue(battery->monitor_wqueue); + destroy_workqueue(battery->monitor_wqueue); + wake_lock_destroy(&battery->monitor_wake_lock); + wake_lock_destroy(&battery->cable_wake_lock); + wake_lock_destroy(&battery->vbus_wake_lock); + + mutex_destroy(&battery->adclock); + for (i = 0; i < SEC_BAT_ADC_CHANNEL_FULL_CHECK; i++) + adc_exit(battery->pdata, i); + + power_supply_unregister(&battery->psy_ac); + power_supply_unregister(&battery->psy_usb); + power_supply_unregister(&battery->psy_bat); + + kfree(battery); + + dev_dbg(battery->dev, "%s: End\n", __func__); + + return 0; +} + +static int sec_battery_prepare(struct device *dev) +{ + struct sec_battery_info *battery + = dev_get_drvdata(dev); + + dev_dbg(battery->dev, "%s: Start\n", __func__); + + switch (battery->pdata->polling_type) { + case SEC_BATTERY_MONITOR_WORKQUEUE: + cancel_delayed_work(&battery->polling_work); + break; + case SEC_BATTERY_MONITOR_ALARM: + alarm_cancel(&battery->polling_alarm); + break; + default: + break; + } + cancel_work_sync(&battery->monitor_work); + + battery->polling_in_sleep = true; + + sec_bat_set_polling(battery); + + /* cancel work for polling + * that is set in sec_bat_set_polling() + * no need for polling in sleep + */ + if (battery->pdata->polling_type == + SEC_BATTERY_MONITOR_WORKQUEUE) + cancel_delayed_work(&battery->polling_work); + + dev_dbg(battery->dev, "%s: End\n", __func__); + + return 0; +} + +static int sec_battery_suspend(struct device *dev) +{ + return 0; +} + +static int sec_battery_resume(struct device *dev) +{ + return 0; +} + +static void sec_battery_complete(struct device *dev) +{ + struct sec_battery_info *battery + = dev_get_drvdata(dev); + + dev_dbg(battery->dev, "%s: Start\n", __func__); + + /* cancel current alarm and reset after monitor work */ + if (battery->pdata->polling_type == SEC_BATTERY_MONITOR_ALARM) + alarm_cancel(&battery->polling_alarm); + + wake_lock(&battery->monitor_wake_lock); + queue_work(battery->monitor_wqueue, + &battery->monitor_work); + + dev_dbg(battery->dev, "%s: End\n", __func__); + + return; +} + +static void sec_battery_shutdown(struct device *dev) +{ +} + +static const struct dev_pm_ops sec_battery_pm_ops = { + .prepare = sec_battery_prepare, + .suspend = sec_battery_suspend, + .resume = sec_battery_resume, + .complete = sec_battery_complete, +}; + +static struct platform_driver sec_battery_driver = { + .driver = { + .name = "sec-battery", + .owner = THIS_MODULE, + .pm = &sec_battery_pm_ops, + .shutdown = sec_battery_shutdown, + }, + .probe = sec_battery_probe, + .remove = __devexit_p(sec_battery_remove), +}; + +static int __init sec_battery_init(void) +{ + return platform_driver_register(&sec_battery_driver); +} + +static void __exit sec_battery_exit(void) +{ + platform_driver_unregister(&sec_battery_driver); +} + +late_initcall(sec_battery_init); +module_exit(sec_battery_exit); + +MODULE_DESCRIPTION("Samsung Battery Driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/battery/sec_charger.c b/drivers/battery/sec_charger.c new file mode 100644 index 00000000000..838e11d9fc9 --- /dev/null +++ b/drivers/battery/sec_charger.c @@ -0,0 +1,396 @@ +/* + * sec_charger.c + * Samsung Mobile Charger Driver + * + * Copyright (C) 2012 Samsung Electronics + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define DEBUG + +#include + +static int sec_chg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_charger_info *charger = + container_of(psy, struct sec_charger_info, psy_chg); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = charger->charging_current ? 1 : 0; + break; + case POWER_SUPPLY_PROP_STATUS: + case POWER_SUPPLY_PROP_HEALTH: + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (!sec_hal_chg_get_property(charger->client, psp, val)) + return -EINVAL; + break; + default: + return -EINVAL; + } + return 0; +} + +static int sec_chg_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sec_charger_info *charger = + container_of(psy, struct sec_charger_info, psy_chg); + + switch (psp) { + /* val->intval : type */ + case POWER_SUPPLY_PROP_ONLINE: + charger->cable_type = val->intval; + if (val->intval == POWER_SUPPLY_TYPE_BATTERY) + charger->is_charging = false; + else + charger->is_charging = true; + + /* current setting */ + charger->charging_current = + charger->pdata->charging_current[ + val->intval].fast_charging_current; + + if (!sec_hal_chg_set_property(charger->client, psp, val)) + return -EINVAL; + break; + /* val->intval : charging current */ + case POWER_SUPPLY_PROP_CURRENT_NOW: + charger->charging_current = val->intval; + + if (!sec_hal_chg_set_property(charger->client, psp, val)) + return -EINVAL; + break; + default: + return -EINVAL; + } + return 0; +} + +static void sec_chg_isr_work(struct work_struct *work) +{ + struct sec_charger_info *charger = + container_of(work, struct sec_charger_info, isr_work.work); + union power_supply_propval val; + + dev_info(&charger->client->dev, + "%s: Charger Interrupt\n", __func__); + + if (charger->pdata->full_check_type == + SEC_BATTERY_FULLCHARGED_CHGINT) { + if (!sec_hal_chg_get_property(charger->client, + POWER_SUPPLY_PROP_STATUS, &val)) + return; + + switch (val.intval) { + case POWER_SUPPLY_STATUS_DISCHARGING: + dev_err(&charger->client->dev, + "%s: Interrupted but Discharging\n", __func__); + break; + + case POWER_SUPPLY_STATUS_NOT_CHARGING: + dev_err(&charger->client->dev, + "%s: Interrupted but NOT Charging\n", __func__); + break; + + case POWER_SUPPLY_STATUS_FULL: + dev_info(&charger->client->dev, + "%s: Interrupted by Full\n", __func__); + psy_do_property("battery", set, + POWER_SUPPLY_PROP_STATUS, val); + break; + + case POWER_SUPPLY_STATUS_CHARGING: + dev_err(&charger->client->dev, + "%s: Interrupted but Charging\n", __func__); + break; + + case POWER_SUPPLY_STATUS_UNKNOWN: + default: + dev_err(&charger->client->dev, + "%s: Invalid Charger Status\n", __func__); + break; + } + } + + if (charger->pdata->ovp_uvlo_check_type == + SEC_BATTERY_OVP_UVLO_CHGINT) { + if (!sec_hal_chg_get_property(charger->client, + POWER_SUPPLY_PROP_HEALTH, &val)) + return; + + switch (val.intval) { + case POWER_SUPPLY_HEALTH_OVERHEAT: + case POWER_SUPPLY_HEALTH_COLD: + dev_err(&charger->client->dev, + "%s: Interrupted but Hot/Cold\n", __func__); + break; + + case POWER_SUPPLY_HEALTH_DEAD: + dev_err(&charger->client->dev, + "%s: Interrupted but Dead\n", __func__); + break; + + case POWER_SUPPLY_HEALTH_OVERVOLTAGE: + case POWER_SUPPLY_HEALTH_UNDERVOLTAGE: + dev_info(&charger->client->dev, + "%s: Interrupted by OVP/UVLO\n", __func__); + psy_do_property("battery", set, + POWER_SUPPLY_PROP_HEALTH, val); + break; + + case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE: + dev_err(&charger->client->dev, + "%s: Interrupted but Unspec\n", __func__); + break; + + case POWER_SUPPLY_HEALTH_GOOD: + dev_err(&charger->client->dev, + "%s: Interrupted but Good\n", __func__); + break; + + case POWER_SUPPLY_HEALTH_UNKNOWN: + default: + dev_err(&charger->client->dev, + "%s: Invalid Charger Health\n", __func__); + break; + } + } +} + +static irqreturn_t sec_chg_irq_thread(int irq, void *irq_data) +{ + struct sec_charger_info *charger = irq_data; + + if ((charger->pdata->full_check_type == + SEC_BATTERY_FULLCHARGED_CHGINT) || + (charger->pdata->ovp_uvlo_check_type == + SEC_BATTERY_OVP_UVLO_CHGINT)) + schedule_delayed_work(&charger->isr_work, 0); + + return IRQ_HANDLED; +} + +static int sec_chg_create_attrs(struct device *dev) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(sec_charger_attrs); i++) { + rc = device_create_file(dev, &sec_charger_attrs[i]); + if (rc) + goto create_attrs_failed; + } + goto create_attrs_succeed; + +create_attrs_failed: + dev_err(dev, "%s: failed (%d)\n", __func__, rc); + while (i--) + device_remove_file(dev, &sec_charger_attrs[i]); +create_attrs_succeed: + return rc; +} + +ssize_t sec_chg_show_attrs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const ptrdiff_t offset = attr - sec_charger_attrs; + int i = 0; + + switch (offset) { + case CHG_REG: + case CHG_DATA: + case CHG_REGS: + i = sec_hal_chg_show_attrs(dev, offset, buf); + break; + default: + i = -EINVAL; + break; + } + + return i; +} + +ssize_t sec_chg_store_attrs(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + const ptrdiff_t offset = attr - sec_charger_attrs; + int ret = 0; + + switch (offset) { + case CHG_REG: + case CHG_DATA: + ret = sec_hal_chg_store_attrs(dev, offset, buf, count); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int __devinit sec_charger_probe( + struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = + to_i2c_adapter(client->dev.parent); + struct sec_charger_info *charger; + int ret = 0; + + dev_dbg(&client->dev, + "%s: SEC Charger Driver Loading\n", __func__); + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + return -EIO; + + charger = kzalloc(sizeof(*charger), GFP_KERNEL); + if (!charger) + return -ENOMEM; + + charger->client = client; + charger->pdata = client->dev.platform_data; + + i2c_set_clientdata(client, charger); + + charger->psy_chg.name = "sec-charger"; + charger->psy_chg.type = POWER_SUPPLY_TYPE_BATTERY; + charger->psy_chg.get_property = sec_chg_get_property; + charger->psy_chg.set_property = sec_chg_set_property; + charger->psy_chg.properties = sec_charger_props; + charger->psy_chg.num_properties = ARRAY_SIZE(sec_charger_props); + + if (!charger->pdata->chg_gpio_init()) { + dev_err(&client->dev, + "%s: Failed to Initialize GPIO\n", __func__); + goto err_free; + } + + if (!sec_hal_chg_init(charger->client)) { + dev_err(&client->dev, + "%s: Failed to Initialize Charger\n", __func__); + goto err_free; + } + + ret = power_supply_register(&client->dev, &charger->psy_chg); + if (ret) { + dev_err(&client->dev, + "%s: Failed to Register psy_chg\n", __func__); + goto err_free; + } + + if (charger->pdata->chg_irq) { + ret = request_threaded_irq(charger->pdata->chg_irq, + NULL, sec_chg_irq_thread, + charger->pdata->chg_irq_attr, + "charger-irq", charger); + if (ret) { + dev_err(&client->dev, + "%s: Failed to Reqeust IRQ\n", __func__); + goto err_supply_unreg; + } + + if (charger->pdata->full_check_type == + SEC_BATTERY_FULLCHARGED_CHGINT) { + ret = enable_irq_wake(charger->pdata->chg_irq); + if (ret < 0) + dev_err(&client->dev, + "%s: Failed to Enable Wakeup Source(%d)\n", + __func__, ret); + } + + INIT_DELAYED_WORK_DEFERRABLE( + &charger->isr_work, sec_chg_isr_work); + } + + ret = sec_chg_create_attrs(charger->psy_chg.dev); + if (ret) { + dev_err(&client->dev, + "%s : Failed to create_attrs\n", __func__); + goto err_supply_unreg; + } + + dev_dbg(&client->dev, + "%s: SEC Charger Driver Loaded\n", __func__); + return 0; + +err_supply_unreg: + power_supply_unregister(&charger->psy_chg); +err_free: + kfree(charger); + + return ret; +} + +static int __devexit sec_charger_remove( + struct i2c_client *client) +{ + return 0; +} + +static int sec_charger_suspend(struct i2c_client *client, + pm_message_t state) +{ + if (!sec_hal_chg_suspend(client)) + dev_err(&client->dev, + "%s: Failed to Suspend Charger\n", __func__); + + return 0; +} + +static int sec_charger_resume(struct i2c_client *client) +{ + if (!sec_hal_chg_resume(client)) + dev_err(&client->dev, + "%s: Failed to Resume Charger\n", __func__); + + return 0; +} + +static void sec_charger_shutdown(struct i2c_client *client) +{ +} + +static const struct i2c_device_id sec_charger_id[] = { + {"sec-charger", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, sec_charger_id); + +static struct i2c_driver sec_charger_driver = { + .driver = { + .name = "sec-charger", + }, + .probe = sec_charger_probe, + .remove = __devexit_p(sec_charger_remove), + .suspend = sec_charger_suspend, + .resume = sec_charger_resume, + .shutdown = sec_charger_shutdown, + .id_table = sec_charger_id, +}; + +static int __init sec_charger_init(void) +{ + return i2c_add_driver(&sec_charger_driver); +} + +static void __exit sec_charger_exit(void) +{ + i2c_del_driver(&sec_charger_driver); +} + +module_init(sec_charger_init); +module_exit(sec_charger_exit); + +MODULE_DESCRIPTION("Samsung Charger Driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/battery/sec_fuelgauge.c b/drivers/battery/sec_fuelgauge.c new file mode 100644 index 00000000000..4d347106e21 --- /dev/null +++ b/drivers/battery/sec_fuelgauge.c @@ -0,0 +1,473 @@ +/* + * sec_fuelgauge.c + * Samsung Mobile Fuel Gauge Driver + * + * Copyright (C) 2012 Samsung Electronics + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define DEBUG + +#include + +/* capacity is 0.1% unit */ +static void sec_fg_get_scaled_capacity( + struct sec_fuelgauge_info *fuelgauge, + union power_supply_propval *val) +{ + val->intval = (val->intval < fuelgauge->pdata->capacity_min) ? + 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 / + (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min)); + + dev_dbg(&fuelgauge->client->dev, + "%s: scaled capacity (%d.%d)\n", + __func__, val->intval/10, val->intval%10); +} + +/* capacity is integer */ +static void sec_fg_get_atomic_capacity( + struct sec_fuelgauge_info *fuelgauge, + union power_supply_propval *val) +{ + if (fuelgauge->capacity_old < val->intval) + val->intval = fuelgauge->capacity_old + 1; + else if (fuelgauge->capacity_old > val->intval) + val->intval = fuelgauge->capacity_old - 1; + + /* updated old capacity */ + fuelgauge->capacity_old = val->intval; +} + +static int sec_fg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_fuelgauge_info *fuelgauge = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + + switch (psp) { + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_CURRENT_AVG: + case POWER_SUPPLY_PROP_ENERGY_NOW: + case POWER_SUPPLY_PROP_CAPACITY: + case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + if (!sec_hal_fg_get_property(fuelgauge->client, psp, val)) + return -EINVAL; + if (psp == POWER_SUPPLY_PROP_CAPACITY) { + if (fuelgauge->pdata->capacity_calculation_type & + (SEC_FUELGAUGE_CAPACITY_TYPE_SCALE | + SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE)) + sec_fg_get_scaled_capacity(fuelgauge, val); + + /* capacity should be between 0% and 100% + * (0.1% degree) + */ + if (val->intval > 1000) + val->intval = 1000; + if (val->intval < 0) + val->intval = 0; + + /* get only integer part */ + if (val->intval > 0) + val->intval /= 10; + + /* (Only for atomic capacity) + * In initial time, capacity_old is 0. + * and in resume from sleep, + * capacity_old is too different from actual soc. + * should update capacity_old + * by val->intval in booting or resume. + */ + if (fuelgauge->initial_update_of_soc) { + /* updated old capacity */ + fuelgauge->capacity_old = val->intval; + fuelgauge->initial_update_of_soc = false; + break; + } + + if (fuelgauge->pdata->capacity_calculation_type & + SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC) + sec_fg_get_atomic_capacity(fuelgauge, val); + } + break; + default: + return -EINVAL; + } + return 0; +} + +static int sec_fg_calculate_dynamic_scale( + struct sec_fuelgauge_info *fuelgauge) +{ + union power_supply_propval raw_soc_val; + + if (!sec_hal_fg_get_property(fuelgauge->client, + POWER_SUPPLY_PROP_CAPACITY, + &raw_soc_val)) + return -EINVAL; + + if (raw_soc_val.intval < + fuelgauge->pdata->capacity_max - + fuelgauge->pdata->capacity_max_margin) { + fuelgauge->capacity_max = + fuelgauge->pdata->capacity_max - + fuelgauge->pdata->capacity_max_margin; + dev_dbg(&fuelgauge->client->dev, "%s: capacity_max (%d)", + __func__, fuelgauge->capacity_max); + } else { + fuelgauge->capacity_max = + (raw_soc_val.intval > 1000) ? 1000 : raw_soc_val.intval; + dev_dbg(&fuelgauge->client->dev, "%s: raw soc (%d)", + __func__, fuelgauge->capacity_max); + } + + fuelgauge->capacity_max = + ((fuelgauge->capacity_max - fuelgauge->pdata->capacity_min) + * 99 / 100) + fuelgauge->pdata->capacity_min; + + dev_info(&fuelgauge->client->dev, "%s: %d is used for capacity_max\n", + __func__, fuelgauge->capacity_max); + + return fuelgauge->capacity_max; +} + +static int sec_fg_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sec_fuelgauge_info *fuelgauge = + container_of(psy, struct sec_fuelgauge_info, psy_fg); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (val->intval == POWER_SUPPLY_STATUS_FULL) + sec_hal_fg_full_charged(fuelgauge->client); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + if (val->intval == POWER_SUPPLY_TYPE_BATTERY) { + if (fuelgauge->pdata->capacity_calculation_type & + SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE) + sec_fg_calculate_dynamic_scale(fuelgauge); + } + break; + case POWER_SUPPLY_PROP_ONLINE: + fuelgauge->cable_type = val->intval; + if (val->intval == POWER_SUPPLY_TYPE_BATTERY) + fuelgauge->is_charging = false; + else + fuelgauge->is_charging = true; + case POWER_SUPPLY_PROP_CAPACITY: + if (val->intval == SEC_FUELGAUGE_CAPACITY_TYPE_RESET) { + if (!sec_hal_fg_reset(fuelgauge->client)) + return -EINVAL; + else + break; + } + case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + if (!sec_hal_fg_set_property(fuelgauge->client, psp, val)) + return -EINVAL; + break; + default: + return -EINVAL; + } + return 0; +} + +static void sec_fg_isr_work(struct work_struct *work) +{ + struct sec_fuelgauge_info *fuelgauge = + container_of(work, struct sec_fuelgauge_info, isr_work.work); + + /* process for fuel gauge chip */ + sec_hal_fg_fuelalert_process(fuelgauge, fuelgauge->is_fuel_alerted); + + /* process for others */ + fuelgauge->pdata->fuelalert_process(fuelgauge->is_fuel_alerted); +} + +static irqreturn_t sec_fg_irq_thread(int irq, void *irq_data) +{ + struct sec_fuelgauge_info *fuelgauge = irq_data; + bool fuel_alerted; + + if (fuelgauge->pdata->fuel_alert_soc >= 0) { + fuel_alerted = + sec_hal_fg_is_fuelalerted(fuelgauge->client); + + dev_info(&fuelgauge->client->dev, + "%s: Fuel-alert %salerted!\n", + __func__, fuel_alerted ? "" : "NOT "); + + if (fuel_alerted == fuelgauge->is_fuel_alerted) { + if (!fuelgauge->pdata->repeated_fuelalert) { + dev_dbg(&fuelgauge->client->dev, + "%s: Fuel-alert Repeated (%d)\n", + __func__, fuelgauge->is_fuel_alerted); + return IRQ_HANDLED; + } + } + + if (fuel_alerted) + wake_lock(&fuelgauge->fuel_alert_wake_lock); + else + wake_unlock(&fuelgauge->fuel_alert_wake_lock); + + schedule_delayed_work(&fuelgauge->isr_work, 0); + + fuelgauge->is_fuel_alerted = fuel_alerted; + } + + return IRQ_HANDLED; +} + +static int sec_fg_create_attrs(struct device *dev) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(sec_fg_attrs); i++) { + rc = device_create_file(dev, &sec_fg_attrs[i]); + if (rc) + goto create_attrs_failed; + } + goto create_attrs_succeed; + +create_attrs_failed: + dev_err(dev, "%s: failed (%d)\n", __func__, rc); + while (i--) + device_remove_file(dev, &sec_fg_attrs[i]); +create_attrs_succeed: + return rc; +} + +ssize_t sec_fg_show_attrs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const ptrdiff_t offset = attr - sec_fg_attrs; + int i = 0; + + switch (offset) { + case FG_REG: + case FG_DATA: + case FG_REGS: + i = sec_hal_fg_show_attrs(dev, offset, buf); + break; + default: + i = -EINVAL; + break; + } + + return i; +} + +ssize_t sec_fg_store_attrs(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + const ptrdiff_t offset = attr - sec_fg_attrs; + int ret = 0; + + switch (offset) { + case FG_REG: + case FG_DATA: + ret = sec_hal_fg_store_attrs(dev, offset, buf, count); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int __devinit sec_fuelgauge_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct sec_fuelgauge_info *fuelgauge; + int ret = 0; + + dev_dbg(&client->dev, + "%s: SEC Fuelgauge Driver Loading\n", __func__); + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + return -EIO; + + fuelgauge = kzalloc(sizeof(*fuelgauge), GFP_KERNEL); + if (!fuelgauge) + return -ENOMEM; + + mutex_init(&fuelgauge->fg_lock); + + fuelgauge->client = client; + fuelgauge->pdata = client->dev.platform_data; + + i2c_set_clientdata(client, fuelgauge); + + fuelgauge->psy_fg.name = "sec-fuelgauge"; + fuelgauge->psy_fg.type = POWER_SUPPLY_TYPE_BATTERY; + fuelgauge->psy_fg.get_property = sec_fg_get_property; + fuelgauge->psy_fg.set_property = sec_fg_set_property; + fuelgauge->psy_fg.properties = sec_fuelgauge_props; + fuelgauge->psy_fg.num_properties = + ARRAY_SIZE(sec_fuelgauge_props); + fuelgauge->capacity_max = fuelgauge->pdata->capacity_max; + + if (!fuelgauge->pdata->fg_gpio_init()) { + dev_err(&client->dev, + "%s: Failed to Initialize GPIO\n", __func__); + goto err_free; + } + + if (!sec_hal_fg_init(fuelgauge->client)) { + dev_err(&client->dev, + "%s: Failed to Initialize Fuelgauge\n", __func__); + goto err_free; + } + + ret = power_supply_register(&client->dev, &fuelgauge->psy_fg); + if (ret) { + dev_err(&client->dev, + "%s: Failed to Register psy_fg\n", __func__); + goto err_free; + } + + if (fuelgauge->pdata->fg_irq) { + ret = request_threaded_irq(fuelgauge->pdata->fg_irq, + NULL, sec_fg_irq_thread, + fuelgauge->pdata->fg_irq_attr, + "fuelgauge-irq", fuelgauge); + if (ret) { + dev_err(&client->dev, + "%s: Failed to Reqeust IRQ\n", __func__); + goto err_supply_unreg; + } + + ret = enable_irq_wake(fuelgauge->pdata->fg_irq); + if (ret < 0) + dev_err(&client->dev, + "%s: Failed to Enable Wakeup Source(%d)\n", + __func__, ret); + + INIT_DELAYED_WORK_DEFERRABLE( + &fuelgauge->isr_work, sec_fg_isr_work); + } + + fuelgauge->is_fuel_alerted = false; + if (fuelgauge->pdata->fuel_alert_soc >= 0) { + if (sec_hal_fg_fuelalert_init(fuelgauge->client, + fuelgauge->pdata->fuel_alert_soc)) + wake_lock_init(&fuelgauge->fuel_alert_wake_lock, + WAKE_LOCK_SUSPEND, "fuel_alerted"); + else { + dev_err(&client->dev, + "%s: Failed to Initialize Fuel-alert\n", + __func__); + goto err_irq; + } + } + + fuelgauge->initial_update_of_soc = true; + + ret = sec_fg_create_attrs(fuelgauge->psy_fg.dev); + if (ret) { + dev_err(&client->dev, + "%s : Failed to create_attrs\n", __func__); + goto err_irq; + } + + dev_dbg(&client->dev, + "%s: SEC Fuelgauge Driver Loaded\n", __func__); + return 0; + +err_irq: + wake_lock_destroy(&fuelgauge->fuel_alert_wake_lock); +err_supply_unreg: + power_supply_unregister(&fuelgauge->psy_fg); +err_free: + mutex_destroy(&fuelgauge->fg_lock); + kfree(fuelgauge); + + return ret; +} + +static int __devexit sec_fuelgauge_remove( + struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + + if (fuelgauge->pdata->fuel_alert_soc >= 0) + wake_lock_destroy(&fuelgauge->fuel_alert_wake_lock); + + return 0; +} + +static int sec_fuelgauge_suspend( + struct i2c_client *client, pm_message_t state) +{ + if (!sec_hal_fg_suspend(client)) + dev_err(&client->dev, + "%s: Failed to Suspend Fuelgauge\n", __func__); + + return 0; +} + +static int sec_fuelgauge_resume(struct i2c_client *client) +{ + struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client); + + if (!sec_hal_fg_resume(client)) + dev_err(&client->dev, + "%s: Failed to Resume Fuelgauge\n", __func__); + + fuelgauge->initial_update_of_soc = true; + + return 0; +} + +static void sec_fuelgauge_shutdown(struct i2c_client *client) +{ +} + +static const struct i2c_device_id sec_fuelgauge_id[] = { + {"sec-fuelgauge", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, sec_fuelgauge_id); + +static struct i2c_driver sec_fuelgauge_driver = { + .driver = { + .name = "sec-fuelgauge", + }, + .probe = sec_fuelgauge_probe, + .remove = __devexit_p(sec_fuelgauge_remove), + .suspend = sec_fuelgauge_suspend, + .resume = sec_fuelgauge_resume, + .shutdown = sec_fuelgauge_shutdown, + .id_table = sec_fuelgauge_id, +}; + +static int __init sec_fuelgauge_init(void) +{ + return i2c_add_driver(&sec_fuelgauge_driver); +} + +static void __exit sec_fuelgauge_exit(void) +{ + i2c_del_driver(&sec_fuelgauge_driver); +} + +module_init(sec_fuelgauge_init); +module_exit(sec_fuelgauge_exit); + +MODULE_DESCRIPTION("Samsung Fuel Gauge Driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/battery/smb347_charger.c b/drivers/battery/smb347_charger.c new file mode 100644 index 00000000000..339c6ac1b6b --- /dev/null +++ b/drivers/battery/smb347_charger.c @@ -0,0 +1,685 @@ +/* + * smb347_charger.c + * Samsung SMB347 Charger Driver + * + * Copyright (C) 2012 Samsung Electronics + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define DEBUG + +#include +static int smb347_i2c_write(struct i2c_client *client, + int reg, u8 *buf) +{ + int ret; + ret = i2c_smbus_write_i2c_block_data(client, reg, 1, buf); + if (ret < 0) + dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret); + return ret; +} + +static int smb347_i2c_read(struct i2c_client *client, + int reg, u8 *buf) +{ + int ret; + ret = i2c_smbus_read_i2c_block_data(client, reg, 1, buf); + if (ret < 0) + dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret); + return ret; +} + +static void smb347_i2c_write_array(struct i2c_client *client, + u8 *buf, int size) +{ + int i; + for (i = 0; i < size; i += 3) + smb347_i2c_write(client, (u8) (*(buf + i)), (buf + i) + 1); +} + +static void smb347_set_command(struct i2c_client *client, + int reg, int datum) +{ + int val; + u8 data = 0; + val = smb347_i2c_read(client, reg, &data); + if (val >= 0) { + dev_dbg(&client->dev, "%s : reg(0x%02x): 0x%02x", + __func__, reg, data); + if (data != datum) { + data = datum; + if (smb347_i2c_write(client, reg, &data) < 0) + dev_err(&client->dev, + "%s : error!\n", __func__); + val = smb347_i2c_read(client, reg, &data); + if (val >= 0) + dev_dbg(&client->dev, " => 0x%02x\n", data); + } + } +} + +static void smb347_test_read(struct i2c_client *client) +{ + u8 data = 0; + u32 addr = 0; + for (addr = 0; addr <= 0x0f; addr++) { + smb347_i2c_read(client, addr, &data); + dev_dbg(&client->dev, + "smb347 addr : 0x%02x data : 0x%02x\n", addr, data); + } + for (addr = 0x30; addr <= 0x3f; addr++) { + smb347_i2c_read(client, addr, &data); + dev_dbg(&client->dev, + "smb347 addr : 0x%02x data : 0x%02x\n", addr, data); + } +} + +static void smb347_read_regs(struct i2c_client *client, char *str) +{ + u8 data = 0; + u32 addr = 0; + + for (addr = 0; addr <= 0x0f; addr++) { + smb347_i2c_read(client, addr, &data); + sprintf(str+strlen(str), "0x%x, ", data); + } + + /* "#" considered as new line in application */ + sprintf(str+strlen(str), "#"); + + for (addr = 0x30; addr <= 0x3f; addr++) { + smb347_i2c_read(client, addr, &data); + sprintf(str+strlen(str), "0x%x, ", data); + } +} + + +static int smb347_get_charging_status(struct i2c_client *client) +{ + int status = POWER_SUPPLY_STATUS_UNKNOWN; + u8 data_a = 0; + u8 data_b = 0; + u8 data_c = 0; + u8 data_d = 0; + u8 data_e = 0; + + smb347_i2c_read(client, SMB347_STATUS_A, &data_a); + dev_info(&client->dev, + "%s : charger status A(0x%02x)\n", __func__, data_a); + smb347_i2c_read(client, SMB347_STATUS_B, &data_b); + dev_info(&client->dev, + "%s : charger status B(0x%02x)\n", __func__, data_b); + smb347_i2c_read(client, SMB347_STATUS_C, &data_c); + dev_info(&client->dev, + "%s : charger status C(0x%02x)\n", __func__, data_c); + smb347_i2c_read(client, SMB347_STATUS_D, &data_d); + dev_info(&client->dev, + "%s : charger status D(0x%02x)\n", __func__, data_d); + smb347_i2c_read(client, SMB347_STATUS_E, &data_e); + dev_info(&client->dev, + "%s : charger status E(0x%02x)\n", __func__, data_e); + + /* At least one charge cycle terminated, + * Charge current < Termination Current + */ + if ((data_c & 0x20) == 0x20) { + /* top-off by full charging */ + status = POWER_SUPPLY_STATUS_FULL; + goto charging_status_end; + } + + /* Is enabled ? */ + if (data_c & 0x01) { + /* check for 0x06 : no charging (0b00) */ + /* not charging */ + if (!(data_c & 0x06)) { + status = POWER_SUPPLY_STATUS_NOT_CHARGING; + goto charging_status_end; + } else { + status = POWER_SUPPLY_STATUS_CHARGING; + goto charging_status_end; + } + } else + status = POWER_SUPPLY_STATUS_DISCHARGING; +charging_status_end: + return (int)status; +} + +static int smb347_get_charging_health(struct i2c_client *client) +{ + int health = POWER_SUPPLY_HEALTH_GOOD; + u8 data_a = 0; + u8 data_b = 0; + u8 data_c = 0; + u8 data_d = 0; + u8 data_e = 0; + + smb347_i2c_read(client, SMB347_STATUS_A, &data_a); + dev_info(&client->dev, + "%s : charger status A(0x%02x)\n", __func__, data_a); + smb347_i2c_read(client, SMB347_STATUS_B, &data_b); + dev_info(&client->dev, + "%s : charger status B(0x%02x)\n", __func__, data_b); + smb347_i2c_read(client, SMB347_STATUS_C, &data_c); + dev_info(&client->dev, + "%s : charger status C(0x%02x)\n", __func__, data_c); + smb347_i2c_read(client, SMB347_STATUS_D, &data_d); + dev_info(&client->dev, + "%s : charger status D(0x%02x)\n", __func__, data_d); + smb347_i2c_read(client, SMB347_STATUS_E, &data_e); + dev_info(&client->dev, + "%s : charger status E(0x%02x)\n", __func__, data_e); + + /* Is enabled ? */ + if (data_c & 0x01) { + if (!(data_a & 0x02)) /* Input current is NOT OK */ + health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + } + return (int)health; +} + +static void smb347_allow_volatile_writes(struct i2c_client *client) +{ + int val, reg; + u8 data; + reg = SMB347_COMMAND_A; + val = smb347_i2c_read(client, reg, &data); + if ((val >= 0) && !(data & 0x80)) { + dev_dbg(&client->dev, + "%s : reg(0x%02x): 0x%02x", __func__, reg, data); + data |= (0x1 << 7); + if (smb347_i2c_write(client, reg, &data) < 0) + dev_err(&client->dev, "%s : error!\n", __func__); + val = smb347_i2c_read(client, reg, &data); + if (val >= 0) { + data = (u8) data; + dev_dbg(&client->dev, " => 0x%02x\n", data); + } + } +} + +static u8 smb347_get_float_voltage_data( + int float_voltage) +{ + u8 data; + + if (float_voltage < 3500) + float_voltage = 3500; + + data = (float_voltage - 3500) / 20; + + return data; +} + +static u8 smb347_get_input_current_limit_data( + struct sec_charger_info *charger, int input_current) +{ + u8 data; + + if (input_current <= 300) + data = 0x0; + else if (input_current <= 500) + data = 0x1; + else if (input_current <= 700) + data = 0x2; + else if (input_current <= 900) + data = 0x3; + else if (input_current <= 1200) + data = 0x4; + else if (input_current <= 1500) + data = 0x5; + else if (input_current <= 1800) + data = 0x6; + else if (input_current <= 2000) + data = 0x7; + else if (input_current <= 2200) + data = 0x8; + else if (input_current <= 2500) + data = 0x9; + else + data = 0; + + return data; +} + +static u8 smb347_get_termination_current_limit_data( + int termination_current) +{ + u8 data; + + if (termination_current <= 37) + data = 0x0; + else if (termination_current <= 50) + data = 0x1; + else if (termination_current <= 100) + data = 0x2; + else if (termination_current <= 150) + data = 0x3; + else if (termination_current <= 200) + data = 0x4; + else if (termination_current <= 250) + data = 0x5; + else if (termination_current <= 500) + data = 0x6; + else if (termination_current <= 600) + data = 0x7; + else + data = 0; + + return data; +} + +static u8 smb347_get_fast_charging_current_data( + int fast_charging_current) +{ + u8 data; + + if (fast_charging_current <= 700) + data = 0x0; + else if (fast_charging_current <= 900) + data = 0x1; + else if (fast_charging_current <= 1200) + data = 0x2; + else if (fast_charging_current <= 1500) + data = 0x3; + else if (fast_charging_current <= 1800) + data = 0x4; + else if (fast_charging_current <= 2000) + data = 0x5; + else if (fast_charging_current <= 2200) + data = 0x6; + else if (fast_charging_current <= 2500) + data = 0x7; + else + data = 0; + + return data << 5; +} + +static void smb347_charger_function_conrol( + struct i2c_client *client) +{ + struct sec_charger_info *charger = i2c_get_clientdata(client); + u8 data; + + if (charger->charging_current < 0) { + dev_dbg(&client->dev, + "%s : OTG is activated. Ignore command!\n", __func__); + return; + } + smb347_allow_volatile_writes(client); + + if (charger->cable_type == + POWER_SUPPLY_TYPE_BATTERY) { + /* turn off charger */ + smb347_set_command(client, + SMB347_COMMAND_A, 0x80); + + /* high current mode for system current */ + smb347_set_command(client, + SMB347_COMMAND_B, 0x01); + } else { + /* Pre-charge curr 250mA */ + dev_dbg(&client->dev, + "%s : fast charging current (%dmA)\n", + __func__, charger->charging_current); + dev_dbg(&client->dev, + "%s : termination current (%dmA)\n", + __func__, charger->pdata->charging_current[ + charger->cable_type].full_check_current_1st); + data = 0x1c; + data |= smb347_get_fast_charging_current_data( + charger->charging_current); + data |= smb347_get_termination_current_limit_data( + charger->pdata->charging_current[ + charger->cable_type].full_check_current_1st); + smb347_set_command(client, + SMB347_CHARGE_CURRENT, data); + + /* Pin enable control */ + /* DCIN Input Pre-bias Enable */ + data = 0x01; + if (charger->pdata->chg_gpio_en) + data |= 0x40; + if (charger->pdata->chg_polarity_en) + data |= 0x20; + smb347_set_command(client, + SMB347_PIN_ENABLE_CONTROL, data); + + /* Input current limit */ + dev_dbg(&client->dev, "%s : input current (%dmA)\n", + __func__, charger->pdata->charging_current + [charger->cable_type].input_current_limit); + data = 0; + data = smb347_get_input_current_limit_data( + charger, + charger->pdata->charging_current + [charger->cable_type].input_current_limit); + smb347_set_command(client, + SMB347_INPUT_CURRENTLIMIT, data); + + /* + * Input to System FET by Register + * Enable AICL, VCHG + * Max System voltage =Vflt + 0.1v + * Input Source Priority : USBIN + */ + if (charger->pdata->chg_functions_setting & + SEC_CHARGER_NO_GRADUAL_CHARGING_CURRENT) + /* disable AICL */ + smb347_set_command(client, + SMB347_VARIOUS_FUNCTIONS, 0x85); + else + /* enable AICL */ + smb347_set_command(client, + SMB347_VARIOUS_FUNCTIONS, 0x95); + + /* Float voltage, Vprechg : 2.4V */ + dev_dbg(&client->dev, "%s : float voltage (%dmV)\n", + __func__, charger->pdata->chg_float_voltage); + data = 0; + data |= smb347_get_float_voltage_data( + charger->pdata->chg_float_voltage); + smb347_set_command(client, + SMB347_FLOAT_VOLTAGE, data); + + /* Charge control + * Automatic Recharge disable, + * Current Termination disable, + * BMD disable, Recharge Threshold =50mV, + * APSD disable */ + data = 0xC0; + switch (charger->pdata->full_check_type) { + case SEC_BATTERY_FULLCHARGED_CHGGPIO: + case SEC_BATTERY_FULLCHARGED_CHGINT: + case SEC_BATTERY_FULLCHARGED_CHGPSY: + /* Enable Current Termination */ + data &= 0xBF; + break; + } + smb347_set_command(client, + SMB347_CHARGE_CONTROL, data); + + /* STAT, Timer control : STAT active low, + * Complete time out 1527min. + */ + smb347_set_command(client, + SMB347_STAT_TIMERS_CONTROL, 0x1A); + + /* Pin/Enable + * USB 5/1/HC Dual state + * DCIN pre-bias Enable + */ + smb347_set_command(client, + SMB347_PIN_ENABLE_CONTROL, 0x09); + + /* Therm control : + * Therm monitor disable, + * Minimum System Voltage 3.60V + */ + smb347_set_command(client, + SMB347_THERM_CONTROL_A, 0x7F); + + /* USB selection : USB2.0(100mA/500mA), + * INOK polarity Active low + */ + smb347_set_command(client, + SMB347_SYSOK_USB30_SELECTION, 0x08); + + /* Other control + * Low batt detection disable + * Minimum System Voltage 3.60V + */ + smb347_set_command(client, + SMB347_OTHER_CONTROL_A, 0x00); + + /* OTG tlim therm control */ + smb347_set_command(client, + SMB347_OTG_TLIM_THERM_CONTROL, 0x3F); + + /* Limit cell temperature */ + smb347_set_command(client, + SMB347_LIMIT_CELL_TEMPERATURE_MONITOR, 0x01); + + /* Fault interrupt : Clear */ + smb347_set_command(client, + SMB347_FAULT_INTERRUPT, 0x00); + + /* STATUS ingerrupt : Clear */ + smb347_set_command(client, + SMB347_STATUS_INTERRUPT, 0x00); + + /* turn on charger */ + smb347_set_command(client, + SMB347_COMMAND_A, 0x82); + + /* HC or USB5 mode */ + switch (charger->cable_type) { + case POWER_SUPPLY_TYPE_MAINS: + case POWER_SUPPLY_TYPE_MISC: + /* High-current mode */ + data = 0x01; + break; + case POWER_SUPPLY_TYPE_USB: + case POWER_SUPPLY_TYPE_USB_DCP: + case POWER_SUPPLY_TYPE_USB_CDP: + case POWER_SUPPLY_TYPE_USB_ACA: + /* USB5 */ + data = 0x02; + break; + default: + /* USB1 */ + data = 0x00; + break; + } + smb347_set_command(client, + SMB347_COMMAND_B, data); + } +} + +static void smb347_charger_otg_conrol( + struct i2c_client *client) +{ + struct sec_charger_info *charger = i2c_get_clientdata(client); + smb347_allow_volatile_writes(client); + if (charger->cable_type == + POWER_SUPPLY_TYPE_BATTERY) { + /* turn off charger */ + smb347_set_command(client, + SMB347_COMMAND_A, 0x80); + } else { + /* turn on OTG */ + smb347_set_command(client, + SMB347_COMMAND_A, (0x1 << 4)); + } +} + +bool sec_hal_chg_init(struct i2c_client *client) +{ + smb347_test_read(client); + return true; +} + +bool sec_hal_chg_suspend(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_chg_resume(struct i2c_client *client) +{ + return true; +} + +bool sec_hal_chg_get_property(struct i2c_client *client, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_charger_info *charger = i2c_get_clientdata(client); + u8 data; + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = smb347_get_charging_status(client); + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = smb347_get_charging_health(client); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (charger->charging_current) { + smb347_i2c_read(client, SMB347_STATUS_B, &data); + if (data & 0x20) + switch (data & 0x18) { + case 0: + val->intval = 100; + break; + case 1: + val->intval = 150; + break; + case 2: + val->intval = 200; + break; + case 3: + val->intval = 250; + break; + } + else + switch (data & 0x07) { + case 0: + val->intval = 700; + break; + case 1: + val->intval = 900; + break; + case 2: + val->intval = 1200; + break; + case 3: + val->intval = 1500; + break; + case 4: + val->intval = 1800; + break; + case 5: + val->intval = 2000; + break; + case 6: + val->intval = 2200; + break; + case 7: + val->intval = 2500; + break; + } + } else + val->intval = 0; + dev_dbg(&client->dev, + "%s : set-current(%dmA), current now(%dmA)\n", + __func__, charger->charging_current, val->intval); + break; + default: + return false; + } + return true; +} + +bool sec_hal_chg_set_property(struct i2c_client *client, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sec_charger_info *charger = i2c_get_clientdata(client); + + switch (psp) { + /* val->intval : type */ + case POWER_SUPPLY_PROP_ONLINE: + /* val->intval : charging current */ + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (charger->charging_current < 0) + smb347_charger_otg_conrol(client); + else if (charger->charging_current > 0) + smb347_charger_function_conrol(client); + else { + smb347_charger_function_conrol(client); + smb347_charger_otg_conrol(client); + } + smb347_test_read(client); + break; + default: + return false; + } + return true; +} + +ssize_t sec_hal_chg_show_attrs(struct device *dev, + const ptrdiff_t offset, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_charger_info *chg = + container_of(psy, struct sec_charger_info, psy_chg); + int i = 0; + char *str = NULL; + + switch (offset) { + case CHG_DATA: + i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n", + chg->reg_data); + break; + case CHG_REGS: + str = kzalloc(sizeof(char)*1024, GFP_KERNEL); + if (!str) + return -ENOMEM; + + smb347_read_regs(chg->client, str); + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", + str); + + kfree(str); + break; + default: + i = -EINVAL; + break; + } + + return i; +} + +ssize_t sec_hal_chg_store_attrs(struct device *dev, + const ptrdiff_t offset, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct sec_charger_info *chg = + container_of(psy, struct sec_charger_info, psy_chg); + int ret = 0; + int x = 0; + u8 data = 0; + + switch (offset) { + case CHG_REG: + if (sscanf(buf, "%x\n", &x) == 1) { + chg->reg_addr = x; + smb347_i2c_read(chg->client, + chg->reg_addr, &data); + chg->reg_data = data; + dev_dbg(dev, "%s: (read) addr = 0x%x, data = 0x%x\n", + __func__, chg->reg_addr, chg->reg_data); + ret = count; + } + break; + case CHG_DATA: + if (sscanf(buf, "%x\n", &x) == 1) { + data = (u8)x; + dev_dbg(dev, "%s: (write) addr = 0x%x, data = 0x%x\n", + __func__, chg->reg_addr, data); + smb347_i2c_write(chg->client, + chg->reg_addr, &data); + ret = count; + } + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index a20a056b77b..ba595a44056 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -34,3 +34,5 @@ hci_uart-objs := $(hci_uart-y) obj-$(CONFIG_BT_MSM_SLEEP) += msm_bt_sleep.o msm_bt_sleep-objs := bluesleep.o obj-$(CONFIG_MSM_BT_POWER) += bluetooth-power.o +obj-$(CONFIG_BT_BCM4334) += bluesleep_bcm.o + diff --git a/drivers/bluetooth/bluesleep_bcm.c b/drivers/bluetooth/bluesleep_bcm.c new file mode 100644 index 00000000000..cc33f9b23c0 --- /dev/null +++ b/drivers/bluetooth/bluesleep_bcm.c @@ -0,0 +1,961 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + * + * 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) 2006-2007 - Motorola + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Date Author Comment + * ----------- -------------- -------------------------------- + * 2006-Apr-28 Motorola The kernel module for running the Bluetooth(R) + * Sleep-Mode Protocol from the Host side + * 2006-Sep-08 Motorola Added workqueue for handling sleep work. + * 2007-Jan-24 Motorola Added mbm_handle_ioi() call to ISR. + * 2009-Aug-10 Motorola Changed "add_timer" to "mod_timer" to solve + * race when flurry of queued work comes in. +*/ + +#include /* kernel module definitions */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* event notifications */ +#include "hci_uart.h" + +#define BT_SLEEP_DBG +#ifndef BT_SLEEP_DBG +#define BT_DBG(fmt, arg...) +#endif +/* + * Defines + */ + +#define VERSION "1.1" +#define PROC_DIR "bluetooth/sleep" + +/* enable/disable wake-on-bluetooth */ +#define BT_ENABLE_IRQ_WAKE 1 + +#define BT_BLUEDROID_SUPPORT 1 + +struct bluesleep_info { + unsigned host_wake; + unsigned ext_wake; + unsigned host_wake_irq; + struct uart_port *uport; + struct wake_lock wake_lock; + int has_ext_wake; +}; + +/* work function */ +static void bluesleep_sleep_work(struct work_struct *work); + +/* work queue */ +DECLARE_DELAYED_WORK(sleep_workqueue, bluesleep_sleep_work); + +/* Macros for handling sleep work */ +#define bluesleep_rx_busy() schedule_delayed_work(&sleep_workqueue, 0) +#define bluesleep_tx_busy() schedule_delayed_work(&sleep_workqueue, 0) +#define bluesleep_rx_idle() schedule_delayed_work(&sleep_workqueue, 0) +#define bluesleep_tx_idle() schedule_delayed_work(&sleep_workqueue, 0) + +/* 10 second timeout */ +#define TX_TIMER_INTERVAL 10 + +/* state variable names and bit positions */ +#define BT_PROTO 0x01 +#define BT_TXDATA 0x02 +#define BT_ASLEEP 0x04 +#define BT_SUSPEND 0x10 + +#if BT_BLUEDROID_SUPPORT +static bool has_lpm_enabled = false; +#else +/* global pointer to a single hci device. */ +static struct hci_dev *bluesleep_hdev; +#endif + +static struct platform_device *bluesleep_uart_dev; +static struct bluesleep_info *bsi; + +/* module usage */ +static atomic_t open_count = ATOMIC_INIT(1); + +/* + * Local function prototypes + */ +#if !BT_BLUEDROID_SUPPORT +static int bluesleep_hci_event(struct notifier_block *this, + unsigned long event, void *data); +#endif +static int bluesleep_start(void); +static void bluesleep_stop(void); + +/* + * Global variables + */ +/** Global state flags */ +static unsigned long flags; + +/** Tasklet to respond to change in hostwake line */ +static struct tasklet_struct hostwake_task; + +/** Transmission timer */ +static void bluesleep_tx_timer_expire(unsigned long data); +static DEFINE_TIMER(tx_timer, bluesleep_tx_timer_expire, 0, 0); + +/** Lock for state transitions */ +static spinlock_t rw_lock; + +#if !BT_BLUEDROID_SUPPORT +/** Notifier block for HCI events */ +struct notifier_block hci_event_nblock = { + .notifier_call = bluesleep_hci_event, +}; +#endif + +struct proc_dir_entry *bluetooth_dir, *sleep_dir; + +/* + * Local functions + */ +static void hsuart_power(int on) +{ + if (test_bit(BT_SUSPEND, &flags)) + return; + if (on) { + msm_hs_request_clock_on(bsi->uport); + msm_hs_set_mctrl(bsi->uport, TIOCM_RTS); + } else { + msm_hs_set_mctrl(bsi->uport, 0); + msm_hs_request_clock_off(bsi->uport); + } +} + +/** + * @return 1 if the Host can go to sleep, 0 otherwise. + */ +int bluesleep_can_sleep(void) +{ + /* check if WAKE_BT_GPIO and BT_WAKE_GPIO are both deasserted */ + int ext_wake = gpio_get_value(bsi->ext_wake); + int host_wake = gpio_get_value(bsi->host_wake); + int cs = !ext_wake && !host_wake && bsi->uport != NULL; + + BT_DBG + ("bluetooth_can_sleep: ext_wake=%d, host_wake=%d, uport=%d, cs=%d", + ext_wake, host_wake, (bsi->uport == NULL ? 0 : 1), cs); + return cs; +} + +void bluesleep_sleep_wakeup(void) +{ + if (test_bit(BT_ASLEEP, &flags)) { + BT_DBG("waking up..."); + wake_lock(&bsi->wake_lock); + /* Start the timer */ + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ)); + if (bsi->has_ext_wake == 1) + gpio_set_value(bsi->ext_wake, 1); + clear_bit(BT_ASLEEP, &flags); + /*Activating UART */ + hsuart_power(1); + } +} + +/** + * @brief@ main sleep work handling function which update the flags + * and activate and deactivate UART ,check FIFO. + */ +static void bluesleep_sleep_work(struct work_struct *work) +{ + if (bluesleep_can_sleep()) { + /* already asleep, this is an error case */ + if (test_bit(BT_ASLEEP, &flags)) { + BT_DBG("already asleep"); + return; + } + + if (msm_hs_tx_empty(bsi->uport)) { + BT_DBG("going to sleep"); + set_bit(BT_ASLEEP, &flags); + hsuart_power(0); + wake_lock_timeout(&bsi->wake_lock, HZ / 2); + } else { + mod_timer(&tx_timer, jiffies + TX_TIMER_INTERVAL * HZ); + } + } else if (!gpio_get_value(bsi->ext_wake) + && !test_bit(BT_ASLEEP, &flags)) { + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ)); + if (bsi->has_ext_wake == 1) + gpio_set_value(bsi->ext_wake, 1); + } else { + bluesleep_sleep_wakeup(); + } +} + +/** + * A tasklet function that runs in tasklet context and reads the value + * of the HOST_WAKE GPIO pin and further defer the work. + * @param data Not used. + */ +static void bluesleep_hostwake_task(unsigned long data) +{ + BT_DBG("hostwake line change"); + + spin_lock(&rw_lock); + if (gpio_get_value(bsi->host_wake)) + bluesleep_rx_busy(); + else + bluesleep_rx_idle(); + spin_unlock(&rw_lock); + +} + +#if !BT_BLUEDROID_SUPPORT +static void bluesleep_lpm_exit_lpm_locked(struct hci_dev *hdev) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&rw_lock, irq_flags); + + gpio_set_value(bsi->ext_wake, 1); + bluesleep_sleep_wakeup(); + + spin_unlock_irqrestore(&rw_lock, irq_flags); +} +#endif + +/** + * Handles proper timer action when outgoing data is delivered to the + * HCI line discipline. Sets BT_TXDATA. + */ +static void bluesleep_outgoing_data(void) +{ + /* log data passing by */ + set_bit(BT_TXDATA, &flags); + /* if the tx side is sleeping... */ + if (!gpio_get_value(bsi->ext_wake)) { + BT_DBG("tx was sleeping"); + bluesleep_sleep_wakeup(); + } +} + +#if BT_BLUEDROID_SUPPORT +static struct uart_port *bluesleep_get_uart_port(void) +{ + struct uart_port *uport = NULL; + if (bluesleep_uart_dev) + uport = (struct uart_port *) platform_get_drvdata(bluesleep_uart_dev); + else + BT_INFO("no uart device!"); + return uport; +} + +static int bluesleep_read_proc_lpm(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + *eof = 1; + return sprintf(page, "unsupported to read\n"); +} + +static int bluesleep_write_proc_lpm(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char b; + + if (count < 1) + return -EINVAL; + + if (copy_from_user(&b, buffer, 1)) + return -EFAULT; + + if (b == '0') { + /* HCI_DEV_UNREG */ + BT_DBG("bluesleep unregister"); + bluesleep_stop(); + has_lpm_enabled = false; + bsi->uport = NULL; + } else { + /* HCI_DEV_REG */ + if (!has_lpm_enabled) { + BT_DBG("bluesleep register"); + has_lpm_enabled = true; + bsi->uport = bluesleep_get_uart_port(); + /* if bluetooth started, start bluesleep */ + bluesleep_start(); + } + } + + return count; +} + +static int bluesleep_read_proc_btwrite(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + *eof = 1; + return sprintf(page, "unsupported to read\n"); +} + +static int bluesleep_write_proc_btwrite(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char b; + + if (count < 1) + return -EINVAL; + + if (copy_from_user(&b, buffer, 1)) + return -EFAULT; + + /* HCI_DEV_WRITE */ + if (b != '0') { + bluesleep_outgoing_data(); + } + + return count; +} +#else +/** + * Handles HCI device events. + * @param this Not used. + * @param event The event that occurred. + * @param data The HCI device associated with the event. + * @return NOTIFY_DONE. + */ +static int bluesleep_hci_event(struct notifier_block *this, + unsigned long event, void *data) +{ + struct hci_dev *hdev = (struct hci_dev *)data; + struct hci_uart *hu; + struct uart_state *state; + + if (!hdev) + return NOTIFY_DONE; + + switch (event) { + case HCI_DEV_REG: + if (!bluesleep_hdev) { + bluesleep_hdev = hdev; + hu = (struct hci_uart *)hdev->driver_data; + state = (struct uart_state *)hu->tty->driver_data; + bsi->uport = state->uart_port; + hdev->wake_peer = bluesleep_lpm_exit_lpm_locked; + /* if bluetooth started, start bluesleep */ + bluesleep_start(); + } + break; + case HCI_DEV_UNREG: + bluesleep_stop(); + bluesleep_hdev = NULL; + bsi->uport = NULL; + /* if bluetooth stopped, stop bluesleep also */ + break; + case HCI_DEV_WRITE: + bluesleep_outgoing_data(); + break; + } + + return NOTIFY_DONE; +} +#endif + +/** + * Handles transmission timer expiration. + * @param data Not used. + */ +static void bluesleep_tx_timer_expire(unsigned long data) +{ + unsigned long irq_flags; + + BT_DBG("Tx timer expired"); + + spin_lock_irqsave(&rw_lock, irq_flags); + + /* were we silent during the last timeout? */ + if (!test_bit(BT_TXDATA, &flags)) { + BT_DBG("Tx has been idle"); + if (bsi->has_ext_wake == 1) + gpio_set_value(bsi->ext_wake, 0); + bluesleep_tx_idle(); + } else { + BT_DBG("Tx data during last period"); + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ)); + } + + /* clear the incoming data flag */ + clear_bit(BT_TXDATA, &flags); + + spin_unlock_irqrestore(&rw_lock, irq_flags); +} + +/** + * Schedules a tasklet to run when receiving an interrupt on the + * HOST_WAKE GPIO pin. + * @param irq Not used. + * @param dev_id Not used. + */ +static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id) +{ + /* schedule a tasklet to handle the change in the host wake line */ + tasklet_schedule(&hostwake_task); + return IRQ_HANDLED; +} + +/** + * Starts the Sleep-Mode Protocol on the Host. + * @return On success, 0. On error, -1, and errno is set + * appropriately. + */ +static int bluesleep_start(void) +{ + int retval; + unsigned long irq_flags; + + spin_lock_irqsave(&rw_lock, irq_flags); + if (test_bit(BT_PROTO, &flags)) { + spin_unlock_irqrestore(&rw_lock, irq_flags); + return 0; + } + spin_unlock_irqrestore(&rw_lock, irq_flags); + + if (!atomic_dec_and_test(&open_count)) { + atomic_inc(&open_count); + return -EBUSY; + } + + /* start the timer */ + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ)); + + /* assert BT_WAKE */ + if (bsi->has_ext_wake == 1) + gpio_set_value(bsi->ext_wake, 0); +#if BT_ENABLE_IRQ_WAKE + retval = enable_irq_wake(bsi->host_wake_irq); + if (retval < 0) { + BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt"); + goto fail; + } +#endif + set_bit(BT_PROTO, &flags); + wake_lock(&bsi->wake_lock); + return 0; +fail: + del_timer(&tx_timer); + atomic_inc(&open_count); + + return retval; +} + +/** + * Stops the Sleep-Mode Protocol on the Host. + */ +static void bluesleep_stop(void) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&rw_lock, irq_flags); + if (!test_bit(BT_PROTO, &flags)) { + spin_unlock_irqrestore(&rw_lock, irq_flags); + return; + } + /* assert BT_WAKE */ + if (bsi->has_ext_wake == 1) + gpio_set_value(bsi->ext_wake, 0); + del_timer(&tx_timer); + clear_bit(BT_PROTO, &flags); + + atomic_inc(&open_count); + spin_unlock_irqrestore(&rw_lock, irq_flags); + + if (test_bit(BT_ASLEEP, &flags)) { + clear_bit(BT_ASLEEP, &flags); + hsuart_power(1); + } +#if BT_ENABLE_IRQ_WAKE + if (disable_irq_wake(bsi->host_wake_irq)) + BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n"); +#endif + wake_lock_timeout(&bsi->wake_lock, HZ / 2); +} + +/** + * Read the BT_WAKE GPIO pin value via the proc interface. + * When this function returns, page will contain a 1 if the + * pin is high, 0 otherwise. + * @param page Buffer for writing data. + * @param start Not used. + * @param offset Not used. + * @param count Not used. + * @param eof Whether or not there is more data to be read. + * @param data Not used. + * @return The number of bytes written. + */ +static int bluepower_read_proc_btwake(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + *eof = 1; + return sprintf(page, "btwake:%u\n", gpio_get_value(bsi->ext_wake)); +} + +/** + * Write the BT_WAKE GPIO pin value via the proc interface. + * @param file Not used. + * @param buffer The buffer to read from. + * @param count The number of bytes to be written. + * @param data Not used. + * @return On success, the number of bytes written. On error, -1, and + * errno is set appropriately. + */ +static int bluepower_write_proc_btwake(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char *buf; + + if (count < 1) + return -EINVAL; + + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, buffer, count)) { + kfree(buf); + return -EFAULT; + } + if (buf[0] == '0') { + if (bsi->has_ext_wake == 1) + gpio_set_value(bsi->ext_wake, 0); + } else if (buf[0] == '1') { + if (bsi->has_ext_wake == 1) + gpio_set_value(bsi->ext_wake, 1); + } else { + kfree(buf); + return -EINVAL; + } + + kfree(buf); + return count; +} + +/** + * Read the BT_HOST_WAKE GPIO pin value via the proc interface. + * When this function returns, page will contain a 1 if the pin + * is high, 0 otherwise. + * @param page Buffer for writing data. + * @param start Not used. + * @param offset Not used. + * @param count Not used. + * @param eof Whether or not there is more data to be read. + * @param data Not used. + * @return The number of bytes written. + */ +static int bluepower_read_proc_hostwake(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + *eof = 1; + return sprintf(page, "hostwake: %u\n", gpio_get_value(bsi->host_wake)); +} + +/** + * Read the low-power status of the Host via the proc interface. + * When this function returns, page contains a 1 if the Host + * is asleep, 0 otherwise. + * @param page Buffer for writing data. + * @param start Not used. + * @param offset Not used. + * @param count Not used. + * @param eof Whether or not there is more data to be read. + * @param data Not used. + * @return The number of bytes written. + */ +static int bluesleep_read_proc_asleep(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + unsigned int asleep; + + asleep = test_bit(BT_ASLEEP, &flags) ? 1 : 0; + *eof = 1; + return sprintf(page, "asleep: %u\n", asleep); +} + +/** + * Read the low-power protocol being used by the Host via the proc interface. + * When this function returns, page will contain a 1 if the Host + * is using the Sleep Mode Protocol, 0 otherwise. + * @param page Buffer for writing data. + * @param start Not used. + * @param offset Not used. + * @param count Not used. + * @param eof Whether or not there is more data to be read. + * @param data Not used. + * @return The number of bytes written. + */ +static int bluesleep_read_proc_proto(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + unsigned int proto; + + proto = test_bit(BT_PROTO, &flags) ? 1 : 0; + *eof = 1; + return sprintf(page, "proto: %u\n", proto); +} + +/** + * Modify the low-power protocol used by the Host via the proc interface. + * @param file Not used. + * @param buffer The buffer to read from. + * @param count The number of bytes to be written. + * @param data Not used. + * @return On success, the number of bytes written. On error, -1, and + * errno is set appropriately. + */ +static int bluesleep_write_proc_proto(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char proto; + + if (count < 1) + return -EINVAL; + + if (copy_from_user(&proto, buffer, 1)) + return -EFAULT; + + if (proto == '0') + bluesleep_stop(); + else + bluesleep_start(); + + /* claim that we wrote everything */ + return count; +} + +void bluesleep_setup_uart_port(struct platform_device *uart_dev) +{ + bluesleep_uart_dev = uart_dev; +} + +static int bluesleep_probe(struct platform_device *pdev) +{ + int ret; + struct resource *res; + + bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL); + if (!bsi) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_IO, + "gpio_host_wake"); + if (!res) { + BT_ERR("couldn't find host_wake gpio\n"); + ret = -ENODEV; + goto free_bsi; + } + bsi->host_wake = res->start; + + ret = gpio_request(bsi->host_wake, "bt_host_wake"); + if (ret) + goto free_bsi; + + res = platform_get_resource_byname(pdev, IORESOURCE_IO, + "gpio_ext_wake"); + + if (!res) + bsi->has_ext_wake = 0; + else + bsi->has_ext_wake = 1; + + if (bsi->has_ext_wake) { + bsi->ext_wake = res->start; + ret = gpio_request(bsi->ext_wake, "bt_ext_wake"); + if (ret) + goto free_bt_host_wake; + + } + + bsi->host_wake_irq = platform_get_irq_byname(pdev, "host_wake"); + if (bsi->host_wake_irq < 0) { + BT_ERR("couldn't find host_wake irq\n"); + ret = -ENODEV; + goto free_bt_ext_wake; + } + + ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr, + IRQF_DISABLED | IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, "bluetooth hostwake", NULL); + + if (ret < 0) { + BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ"); + goto free_bt_ext_wake; + } + + gpio_tlmm_config(GPIO_CFG(bsi->ext_wake, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_16MA), + GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG + (bsi->host_wake, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, + GPIO_CFG_16MA), GPIO_CFG_ENABLE); + + gpio_direction_input(bsi->host_wake); + gpio_direction_output(bsi->ext_wake, 0); + + wake_lock_init(&bsi->wake_lock, WAKE_LOCK_SUSPEND, "bluesleep"); + clear_bit(BT_SUSPEND, &flags); + + return 0; + +free_bt_ext_wake: + gpio_free(bsi->ext_wake); +free_bt_host_wake: + gpio_free(bsi->host_wake); +free_bsi: + kfree(bsi); + return ret; +} + +static int bluesleep_remove(struct platform_device *pdev) +{ + free_irq(bsi->host_wake_irq, NULL); + gpio_free(bsi->host_wake); + gpio_free(bsi->ext_wake); + wake_lock_destroy(&bsi->wake_lock); + kfree(bsi); + return 0; +} + +static int bluesleep_resume(struct platform_device *pdev) +{ + if (test_bit(BT_SUSPEND, &flags)) { + BT_DBG("bluesleep resuming...\n"); + if ((bsi->uport != NULL) && gpio_get_value(bsi->host_wake)) { + BT_DBG("bluesleep resume form BT event...\n"); + msm_hs_request_clock_on(bsi->uport); + msm_hs_set_mctrl(bsi->uport, TIOCM_RTS); + } + clear_bit(BT_SUSPEND, &flags); + } + return 0; +} + +static int bluesleep_suspend(struct platform_device *pdev, pm_message_t state) +{ + BT_DBG("bluesleep suspending...\n"); + set_bit(BT_SUSPEND, &flags); + return 0; +} + +static struct platform_driver bluesleep_driver = { + .probe = bluesleep_probe, + .remove = bluesleep_remove, + .suspend = bluesleep_suspend, + .resume = bluesleep_resume, + .driver = { + .name = "bluesleep_bcm", + .owner = THIS_MODULE, + }, +}; + +/** + * Initializes the module. + * @return On success, 0. On error, -1, and errno is set + * appropriately. + */ +static int __init bluesleep_init(void) +{ + int retval; + struct proc_dir_entry *ent; + + BT_INFO("BlueSleep Mode Driver Ver %s", VERSION); + + retval = platform_driver_register(&bluesleep_driver); + if (retval) + return retval; + + if (bsi == NULL) + return 0; + +#if !BT_BLUEDROID_SUPPORT + bluesleep_hdev = NULL; +#endif + + bluetooth_dir = proc_mkdir("bluetooth", NULL); + if (bluetooth_dir == NULL) { + BT_ERR("Unable to create /proc/bluetooth directory"); + return -ENOMEM; + } + + sleep_dir = proc_mkdir("sleep", bluetooth_dir); + if (sleep_dir == NULL) { + BT_ERR("Unable to create /proc/%s directory", PROC_DIR); + return -ENOMEM; + } + + /* Creating read/write "btwake" entry */ + ent = create_proc_entry("btwake", 0, sleep_dir); + if (ent == NULL) { + BT_ERR("Unable to create /proc/%s/btwake entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + ent->read_proc = bluepower_read_proc_btwake; + ent->write_proc = bluepower_write_proc_btwake; + + /* read only proc entries */ + if (create_proc_read_entry("hostwake", 0, sleep_dir, + bluepower_read_proc_hostwake, + NULL) == NULL) { + BT_ERR("Unable to create /proc/%s/hostwake entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + + /* read/write proc entries */ + ent = create_proc_entry("proto", 0, sleep_dir); + if (ent == NULL) { + BT_ERR("Unable to create /proc/%s/proto entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + ent->read_proc = bluesleep_read_proc_proto; + ent->write_proc = bluesleep_write_proc_proto; + + /* read only proc entries */ + if (create_proc_read_entry("asleep", 0, + sleep_dir, bluesleep_read_proc_asleep, + NULL) == NULL) { + BT_ERR("Unable to create /proc/%s/asleep entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } +#if BT_BLUEDROID_SUPPORT + /* read/write proc entries */ + ent = create_proc_entry("lpm", 0, sleep_dir); + if (ent == NULL) { + BT_ERR("Unable to create /proc/%s/lpm entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + ent->read_proc = bluesleep_read_proc_lpm; + ent->write_proc = bluesleep_write_proc_lpm; + + /* read/write proc entries */ + ent = create_proc_entry("btwrite", 0, sleep_dir); + if (ent == NULL) { + BT_ERR("Unable to create /proc/%s/btwrite entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + ent->read_proc = bluesleep_read_proc_btwrite; + ent->write_proc = bluesleep_write_proc_btwrite; +#endif + + flags = 0; /* clear all status bits */ + + /* Initialize spinlock. */ + spin_lock_init(&rw_lock); + + /* Initialize timer */ + init_timer(&tx_timer); + tx_timer.function = bluesleep_tx_timer_expire; + tx_timer.data = 0; + + /* initialize host wake tasklet */ + tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0); + + /* assert bt wake */ + if (bsi->has_ext_wake == 1) + gpio_set_value(bsi->ext_wake, 0); +#if !BT_BLUEDROID_SUPPORT + hci_register_notifier(&hci_event_nblock); +#endif + + return 0; + +fail: +#if BT_BLUEDROID_SUPPORT + remove_proc_entry("btwrite", sleep_dir); + remove_proc_entry("lpm", sleep_dir); +#endif + remove_proc_entry("asleep", sleep_dir); + remove_proc_entry("proto", sleep_dir); + remove_proc_entry("hostwake", sleep_dir); + remove_proc_entry("btwake", sleep_dir); + remove_proc_entry("sleep", bluetooth_dir); + remove_proc_entry("bluetooth", 0); + return retval; +} + +/** + * Cleans up the module. + */ +static void __exit bluesleep_exit(void) +{ + if (bsi == NULL) + return; + + /* assert bt wake */ + if (bsi->has_ext_wake == 1) + gpio_set_value(bsi->ext_wake, 0); + if (test_bit(BT_PROTO, &flags)) { + if (disable_irq_wake(bsi->host_wake_irq)) + BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n"); + free_irq(bsi->host_wake_irq, NULL); + del_timer(&tx_timer); + if (test_bit(BT_ASLEEP, &flags)) + hsuart_power(1); + } +#if !BT_BLUEDROID_SUPPORT + hci_unregister_notifier(&hci_event_nblock); +#endif + platform_driver_unregister(&bluesleep_driver); + +#if BT_BLUEDROID_SUPPORT + remove_proc_entry("btwrite", sleep_dir); + remove_proc_entry("lpm", sleep_dir); +#endif + remove_proc_entry("asleep", sleep_dir); + remove_proc_entry("proto", sleep_dir); + remove_proc_entry("hostwake", sleep_dir); + remove_proc_entry("btwake", sleep_dir); + remove_proc_entry("sleep", bluetooth_dir); + remove_proc_entry("bluetooth", 0); +} + +module_init(bluesleep_init); +module_exit(bluesleep_exit); + +MODULE_DESCRIPTION("Bluetooth Sleep Mode Driver ver %s " VERSION); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c index c80a58bdc73..1d71e7008b8 100644 --- a/drivers/char/msm_rotator.c +++ b/drivers/char/msm_rotator.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -99,6 +100,8 @@ #define HW_BASE_ADDR(height, y_stride) (((dstp0_ystride >> 5) << 11) - \ ((dst_height & 0x3f) * dstp0_ystride)) +#define WAIT_FENCE_TIMEOUT 200 + uint32_t rotator_hw_revision; static char rot_iommu_split_domain; @@ -1072,6 +1075,58 @@ static void put_img(struct file *p_file, struct ion_handle *p_ihdl, } #endif } +static int buf_fence_process(struct mdp_buf_fence *buf_fence) +{ + int i, fence_cnt = 0, ret; + struct sync_fence *fence; + struct sync_fence *acq_fence[MDP_MAX_FENCE_FD]; + int acq_fen_fd[MDP_MAX_FENCE_FD]; + + if (buf_fence->acq_fen_fd_cnt == 0) + return 0; + if (buf_fence->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) + return -EINVAL; + + for (i = 0; i < buf_fence->acq_fen_fd_cnt; i++) { + fence = sync_fence_fdget(buf_fence->acq_fen_fd[i]); + if (fence == NULL) { + pr_info("%s: null fence! i=%d fd=%d\n", __func__, i, + buf_fence->acq_fen_fd[i]); + ret = -EINVAL; + break; + } + acq_fence[i] = fence; + acq_fen_fd[i] = buf_fence->acq_fen_fd[i]; + } + fence_cnt = i; + if (ret) + goto buf_fence_err_1; + + for (i = 0; i < fence_cnt; i++) { + ret = sync_fence_wait(acq_fence[i], WAIT_FENCE_TIMEOUT); + if (ret < 0) { + pr_err("%s: sync_fence_wait failed! ret = %x\n", + __func__, ret); + break; + } + sync_fence_put(acq_fence[i]); + put_unused_fd(acq_fen_fd[i]); + } + if (ret) { + while (i < fence_cnt) { + sync_fence_put(acq_fence[i]); + put_unused_fd(acq_fen_fd[i]); + i++; + } + } + return ret; +buf_fence_err_1: + for (i = 0; i < fence_cnt; i++) { + sync_fence_put(acq_fence[i]); + put_unused_fd(acq_fen_fd[i]); + } + return ret; +} static int msm_rotator_do_rotate(unsigned long arg) { unsigned int status, format; @@ -1093,6 +1148,9 @@ static int msm_rotator_do_rotate(unsigned long arg) return -EFAULT; mutex_lock(&msm_rotator_dev->rotator_lock); + + buf_fence_process(&info.buf_fence); + for (s = 0; s < MAX_SESSIONS; s++) if ((msm_rotator_dev->rot_session[s] != NULL) && (info.session_id == diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c index d0056059488..e9b3bb372c8 100644 --- a/drivers/gpu/ion/ion.c +++ b/drivers/gpu/ion/ion.c @@ -1322,6 +1322,24 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; } + case ION_IOC_ALLOC_COMPAT: + { + struct ion_allocation_data_compat data; + + if (copy_from_user(&data, (void __user *)arg, sizeof(data))) + return -EFAULT; + data.handle = ion_alloc(client, data.len, data.align, + ion_full_heap_mask, 0); + + if (IS_ERR(data.handle)) + return PTR_ERR(data.handle); + + if (copy_to_user((void __user *)arg, &data, sizeof(data))) { + ion_free(client, data.handle); + return -EFAULT; + } + break; + } case ION_IOC_FREE: { struct ion_handle_data data; @@ -1358,6 +1376,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } case ION_IOC_IMPORT: + case ION_IOC_IMPORT_COMPAT: { struct ion_fd_data data; int ret = 0; @@ -1389,15 +1408,19 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return dev->custom_ioctl(client, data.cmd, data.arg); } case ION_IOC_CLEAN_CACHES: + case ION_IOC_CLEAN_CACHES_COMPAT: return client->dev->custom_ioctl(client, ION_IOC_CLEAN_CACHES, arg); case ION_IOC_INV_CACHES: + case ION_IOC_INV_CACHES_COMPAT: return client->dev->custom_ioctl(client, ION_IOC_INV_CACHES, arg); case ION_IOC_CLEAN_INV_CACHES: + case ION_IOC_CLEAN_INV_CACHES_COMPAT: return client->dev->custom_ioctl(client, ION_IOC_CLEAN_INV_CACHES, arg); case ION_IOC_GET_FLAGS: + case ION_IOC_GET_FLAGS_COMPAT: return client->dev->custom_ioctl(client, ION_IOC_GET_FLAGS, arg); default: diff --git a/drivers/hwmon/pm8xxx-adc-scale.c b/drivers/hwmon/pm8xxx-adc-scale.c index 9d66425b8ef..34cdf47c3eb 100644 --- a/drivers/hwmon/pm8xxx-adc-scale.c +++ b/drivers/hwmon/pm8xxx-adc-scale.c @@ -15,6 +15,7 @@ #include #include #include +#include #define KELVINMIL_DEGMIL 273160 /* Units for temperature below (on x axis) is in 0.1DegC as @@ -771,3 +772,22 @@ int32_t pm8xxx_adc_batt_scaler(struct pm8xxx_adc_arb_btm_param *btm_param, return rc; } EXPORT_SYMBOL_GPL(pm8xxx_adc_batt_scaler); +#ifdef CONFIG_PM8921_SEC_CHARGER +int32_t pm8xxx_adc_sec_board_therm_default(int32_t adc_code, + const struct pm8xxx_adc_properties *adc_properties, + const struct pm8xxx_adc_chan_properties *chan_properties, + struct pm8xxx_adc_chan_result *adc_chan_result) + { + adc_chan_result->adc_code = adc_code; + pr_debug("%s: adc_value: %d\n", __func__, + adc_chan_result->adc_code); + adc_chan_result->measurement = adc_chan_result->adc_code; + + return pm8xxx_adc_map_linear( + temp_table, + ARRAY_SIZE(temp_table), + adc_chan_result->adc_code, + &adc_chan_result->physical); + } +EXPORT_SYMBOL_GPL(pm8xxx_adc_sec_board_therm_default); +#endif diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c index 36333325495..d12a4cec841 100644 --- a/drivers/hwmon/pm8xxx-adc.c +++ b/drivers/hwmon/pm8xxx-adc.c @@ -173,8 +173,46 @@ static struct pm8xxx_adc_scale_fn adc_scale_fn[] = { [ADC_SCALE_PA_THERM] = {pm8xxx_adc_scale_pa_therm}, [ADC_SCALE_PMIC_THERM] = {pm8xxx_adc_scale_pmic_therm}, [ADC_SCALE_XOTHERM] = {pm8xxx_adc_tdkntcg_therm}, +#ifdef CONFIG_PM8921_SEC_CHARGER + [ADC_SCALE_SEC_BOARD_THERM] = {pm8xxx_adc_sec_board_therm_default}, +#endif }; +#define CHG_CNTRL_2 0x212 +#define EN_BATT_THERM_MASK1 0xEF +#define EN_BATT_THERM_MASK2 0x10 +int pm8921_enable_batt_therm(u8 en) +{ + int rc; + u8 reg; + struct pm8xxx_adc *adc_pmic = pmic_adc; + + rc = pm8xxx_readb(adc_pmic->dev->parent, CHG_CNTRL_2, ®); + if (rc) { + pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", + CHG_CNTRL_2, rc); + return rc; + } + + if (en == 0) { + reg &= EN_BATT_THERM_MASK1; + pr_info("[pm8921] disable Vref_batt_therm\n"); + } else { + reg |= EN_BATT_THERM_MASK2; + pr_info("[pm8921] enable Vref_batt_therm\n"); + } + + rc = pm8xxx_writeb(adc_pmic->dev->parent, CHG_CNTRL_2, reg); + if (rc) { + pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", + CHG_CNTRL_2, rc); + return rc; + } + return rc; + +} + + /* On PM8921 ADC the MPP needs to first be configured as an analog input to the AMUX pre-mux channel before issuing a read request. PM8921 MPP 8 is mapped to AMUX8 @@ -731,6 +769,14 @@ uint32_t pm8xxx_adc_read(enum pm8xxx_adc_channels channel, PM8XXX_CHANNEL_MPP_SCALE3_IDX; } +#ifdef CONFIG_SAMSUNG_JACK + if (channel == ADC_MPP_1_AMUX6_SCALE_DEFAULT) { + mpp_scale = PREMUX_MPP_SCALE_1; + adc_pmic->conv->amux_channel = + ADC_MPP_1_AMUX6 % PM8XXX_CHANNEL_MPP_SCALE1_IDX; + } +#endif + adc_pmic->conv->amux_mpp_channel = mpp_scale; adc_pmic->conv->amux_ip_rsv = adc_pmic->adc_channel[i].adc_rsv; adc_pmic->conv->decimation = adc_pmic->adc_channel[i].adc_decimation; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index badbc2be2b8..3093d1417a9 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -612,5 +612,5 @@ config KEYBOARD_W90P910 module will be called w90p910_keypad. endif - +source "drivers/input/keyboard/cypress_touchkey_236/Kconfig" diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 61b57eff5e0..9d655e27287 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o +obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys_sec.o obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o @@ -54,3 +55,4 @@ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_QCIKBD) += qci_kbd.o obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o obj-$(CONFIG_KEYBOARD_PMIC8058) += pmic8058-keypad.o +obj-$(CONFIG_KEYBOARD_CYPRESS_TOUCH_236) += cypress_touchkey_236/ diff --git a/drivers/input/keyboard/cypress_touchkey_236/Kconfig b/drivers/input/keyboard/cypress_touchkey_236/Kconfig new file mode 100644 index 00000000000..d40b8a377aa --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/Kconfig @@ -0,0 +1,12 @@ +# +# Cypress touchkey configuration +# + +config KEYBOARD_CYPRESS_TOUCH_236 + tristate "Cypress touchkey support" + default n + help + Say Y here to enable the + cypress touchkey. + To compile this driver as a + module, choose M here. diff --git a/drivers/input/keyboard/cypress_touchkey_236/Makefile b/drivers/input/keyboard/cypress_touchkey_236/Makefile new file mode 100644 index 00000000000..52a64d7adcb --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Cypress touchkey driver +# + +obj-$(CONFIG_KEYBOARD_CYPRESS_TOUCH_236) += cypress-touchkey-236.o issp_main.o issp_routines.o issp_driver_routines.o diff --git a/drivers/input/keyboard/cypress_touchkey_236/apexq_tkey_fw.h b/drivers/input/keyboard/cypress_touchkey_236/apexq_tkey_fw.h new file mode 100644 index 00000000000..d27054e9a92 --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/apexq_tkey_fw.h @@ -0,0 +1,704 @@ +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +unsigned char firmware_data[8192] = { +0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x00, 0x68, 0x7e, +0x7e, 0x30, 0x30, 0x30, 0x7d, 0x04, 0x9e, 0x7e, 0x7e, 0x30, 0x30, 0x30, +0x7d, 0x05, 0xeb, 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x40, 0x71, 0x10, 0x62, +0xe3, 0x06, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, +0x38, 0x5d, 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, 0xfa, 0x01, 0x40, 0x4f, +0x5b, 0x01, 0x03, 0x53, 0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, 0x40, +0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, 0xef, 0x18, 0x60, 0xd5, +0x55, 0xf8, 0x00, 0x55, 0xf9, 0x00, 0x71, 0x10, 0x62, 0xe0, 0x1a, 0x70, +0xef, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x41, 0xe1, 0xfe, 0x70, 0xef, 0x62, +0xe3, 0x38, 0x62, 0xd1, 0x03, 0x50, 0x80, 0x4e, 0x62, 0xd3, 0x03, 0x62, +0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, 0x00, 0x71, 0xc0, 0x7c, 0x03, +0x0b, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x57, 0xb2, 0x08, 0x28, 0x53, 0x49, +0x18, 0x75, 0x09, 0x00, 0x28, 0x4b, 0x51, 0x49, 0x80, 0x04, 0x75, 0x09, +0x00, 0x62, 0xe3, 0x00, 0x08, 0x28, 0x60, 0xd5, 0x74, 0xa0, 0x4b, 0x18, +0x75, 0x09, 0x00, 0x08, 0x28, 0x53, 0x49, 0x18, 0x75, 0x09, 0x00, 0x08, +0x28, 0xa0, 0x1c, 0x53, 0x48, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, +0x49, 0x47, 0x49, 0xff, 0xb0, 0x06, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x18, +0x7a, 0x48, 0xbf, 0xeb, 0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, +0x53, 0x48, 0x50, 0x00, 0x3f, 0x49, 0x47, 0x49, 0xff, 0xb0, 0x08, 0x5d, +0xd5, 0x74, 0x60, 0xd5, 0x50, 0x00, 0x7a, 0x48, 0xbf, 0xef, 0x18, 0x8f, +0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, 0xef, 0x62, 0xe0, 0x00, +0x41, 0xfe, 0xe7, 0x43, 0xfe, 0x10, 0x71, 0x10, 0x62, 0xe0, 0x1a, 0x70, +0xef, 0x62, 0xe2, 0x00, 0x7c, 0x18, 0x13, 0x8f, 0xff, 0x7f, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x01, 0x99, +0x03, 0x33, 0x06, 0x66, 0x0c, 0xcc, 0x19, 0x99, 0x33, 0x33, 0x66, 0x66, +0xcc, 0xcc, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0b, 0xff, 0x18, 0x00, +0x2f, 0xff, 0x5f, 0xff, 0xbf, 0xff, 0x01, 0x66, 0x02, 0xcc, 0x05, 0x99, +0x0b, 0x32, 0x16, 0x66, 0x2c, 0xcc, 0x59, 0x98, 0xb3, 0x32, 0x01, 0x33, +0x02, 0x66, 0x04, 0xcc, 0x09, 0x99, 0x13, 0x33, 0x26, 0x65, 0x4c, 0xcc, +0x99, 0x99, 0x1a, 0xb1, 0x70, 0xef, 0x62, 0x61, 0x00, 0x62, 0xfd, 0x00, +0x62, 0xcd, 0x00, 0x62, 0xce, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, +0x62, 0xa0, 0x00, 0x62, 0xa1, 0x80, 0x62, 0xa2, 0xc0, 0x62, 0xa3, 0x0c, +0x62, 0xa8, 0x00, 0x62, 0xa6, 0x00, 0x62, 0xa7, 0x00, 0x62, 0x7c, 0x33, +0x62, 0x7a, 0x00, 0x62, 0x7b, 0x00, 0x62, 0x79, 0x00, 0x62, 0x36, 0x00, +0x62, 0x37, 0x00, 0x62, 0x38, 0x00, 0x62, 0x39, 0x00, 0x62, 0x3a, 0x00, +0x62, 0x3b, 0x00, 0x62, 0x3c, 0x00, 0x62, 0x3d, 0x00, 0x62, 0x3e, 0x00, +0x62, 0x3f, 0x00, 0x62, 0x40, 0x00, 0x62, 0x41, 0x00, 0x62, 0x42, 0x00, +0x62, 0x43, 0x00, 0x62, 0x44, 0x00, 0x62, 0x45, 0x00, 0x62, 0x46, 0x00, +0x62, 0x47, 0x00, 0x62, 0x48, 0x00, 0x62, 0x49, 0x00, 0x62, 0x4a, 0x00, +0x62, 0x4b, 0x00, 0x62, 0x4c, 0x00, 0x62, 0x4d, 0x00, 0x62, 0x4e, 0x00, +0x62, 0x4f, 0x00, 0x62, 0xca, 0x20, 0x62, 0xd6, 0x44, 0x62, 0xcf, 0x00, +0x62, 0xcb, 0x00, 0x62, 0xc8, 0x00, 0x62, 0xcc, 0x00, 0x62, 0xc9, 0x00, +0x62, 0xd7, 0x00, 0x62, 0xa9, 0x00, 0x62, 0x2b, 0x00, 0x62, 0xb0, 0x00, +0x62, 0xb3, 0x02, 0x62, 0xb6, 0x00, 0x62, 0xb2, 0x00, 0x62, 0xb5, 0x00, +0x62, 0xb8, 0x00, 0x62, 0xb1, 0x00, 0x62, 0xb4, 0x00, 0x62, 0xb7, 0x00, +0x62, 0x33, 0x00, 0x62, 0x34, 0x00, 0x62, 0x35, 0x00, 0x71, 0x10, 0x62, +0x54, 0x00, 0x62, 0x55, 0x00, 0x62, 0x56, 0x00, 0x62, 0x57, 0x00, 0x62, +0x58, 0x00, 0x62, 0x59, 0x00, 0x62, 0x5a, 0x00, 0x62, 0x5b, 0x00, 0x62, +0xdc, 0x00, 0x62, 0xe2, 0x00, 0x62, 0xdd, 0x00, 0x62, 0xd8, 0x02, 0x62, +0xd9, 0x00, 0x62, 0xda, 0x00, 0x62, 0xdb, 0x00, 0x62, 0xdf, 0x00, 0x62, +0x29, 0x00, 0x62, 0x30, 0x00, 0x62, 0xbd, 0x00, 0x70, 0xef, 0x70, 0xef, +0x62, 0x00, 0x08, 0x71, 0x10, 0x62, 0x00, 0x00, 0x62, 0x01, 0x92, 0x70, +0xef, 0x62, 0x04, 0x17, 0x71, 0x10, 0x62, 0x04, 0x14, 0x62, 0x05, 0xbc, +0x70, 0xef, 0x62, 0x08, 0x00, 0x71, 0x10, 0x62, 0x08, 0x00, 0x62, 0x09, +0x28, 0x70, 0xef, 0x62, 0x0c, 0x00, 0x71, 0x10, 0x62, 0x0c, 0x00, 0x62, +0x0d, 0x00, 0x70, 0xef, 0x62, 0x10, 0x00, 0x71, 0x10, 0x62, 0x10, 0x00, +0x62, 0x11, 0x00, 0x70, 0xef, 0x62, 0x01, 0x00, 0x62, 0x05, 0x00, 0x62, +0x09, 0x00, 0x62, 0x0d, 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, 0x7f, 0x55, +0x02, 0x08, 0x55, 0x03, 0x17, 0x55, 0x04, 0x00, 0x7c, 0x03, 0x18, 0x7f, +0x7c, 0x01, 0xb4, 0x70, 0xef, 0x7f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, +0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x62, 0xd0, +0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, 0xe0, 0x08, 0x21, 0xf8, 0x29, 0x00, +0x70, 0xfe, 0x60, 0xe0, 0x70, 0xef, 0x4b, 0x4b, 0x4b, 0x4b, 0x51, 0x02, +0x21, 0xf7, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, +0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, +0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, +0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, +0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, +0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, +0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, +0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, +0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, +0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x47, 0x00, 0x00, 0x49, +0x01, 0x00, 0x29, 0x08, 0x60, 0x00, 0x57, 0x01, 0x79, 0xbf, 0xfe, 0x18, +0x71, 0x10, 0x60, 0xe0, 0x70, 0xef, 0x71, 0x01, 0x7f, 0x08, 0x67, 0x67, +0x67, 0x67, 0x21, 0x0f, 0xff, 0x40, 0x9f, 0x4e, 0x18, 0x21, 0x0f, 0xff, +0x39, 0x9f, 0x47, 0x7f, 0x08, 0x10, 0x28, 0xa0, 0x0b, 0x9f, 0x3f, 0x20, +0x18, 0x75, 0xdf, 0xf5, 0x74, 0x8f, 0xf2, 0x38, 0xfe, 0x7f, 0x52, 0x00, +0xa0, 0x08, 0x10, 0x9f, 0x2d, 0x20, 0x75, 0x8f, 0xf6, 0x70, 0x3f, 0x71, +0xc0, 0x7f, 0x50, 0x0d, 0x9f, 0x20, 0x50, 0x0a, 0x9f, 0x1c, 0x7f, 0x70, +0xbf, 0x62, 0xd3, 0x03, 0x4f, 0x52, 0xfb, 0xa0, 0x15, 0x7b, 0xfb, 0x52, +0xfc, 0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9f, 0x05, 0x4f, 0x62, 0xd3, +0x03, 0x77, 0xfd, 0x8f, 0xe9, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x3d, 0xfa, +0x00, 0xb0, 0x06, 0x3d, 0xfb, 0x00, 0xa0, 0x18, 0x10, 0x52, 0xfc, 0x59, +0xfd, 0x28, 0x9e, 0xe6, 0x20, 0x07, 0xfd, 0x01, 0x0f, 0xfc, 0x00, 0x17, +0xfb, 0x01, 0x1f, 0xfa, 0x00, 0x8f, 0xe0, 0x7f, 0x50, 0x01, 0x80, 0x03, +0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xfb, +0x80, 0x04, 0x2e, 0x03, 0x04, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, 0x71, +0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, +0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xef, 0x80, +0x04, 0x2e, 0x03, 0x10, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, 0x71, 0xc0, +0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x10, 0x70, 0x3f, 0x71, 0x80, +0x5d, 0xd3, 0x08, 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x51, 0x08, 0x60, +0xd3, 0x2e, 0x05, 0x80, 0x49, 0xd7, 0x08, 0xa0, 0x09, 0x26, 0x05, 0xf0, +0x2e, 0x05, 0x00, 0x80, 0x08, 0x49, 0xd7, 0x20, 0xa0, 0x03, 0x80, 0xa6, +0x51, 0x05, 0x21, 0x0e, 0xe0, 0x01, 0x80, 0x11, 0x80, 0x67, 0x80, 0x79, +0x80, 0x47, 0x80, 0x96, 0x80, 0x94, 0x80, 0x92, 0x80, 0x90, 0x80, 0x97, +0x5d, 0xd8, 0x21, 0xfe, 0x39, 0x40, 0xa0, 0x06, 0x62, 0xd7, 0x00, 0x80, +0x8a, 0x49, 0xd8, 0x01, 0xb0, 0x0f, 0x55, 0x0c, 0x02, 0x26, 0x05, 0xf0, +0x2e, 0x05, 0x02, 0x62, 0xd7, 0x10, 0x80, 0x77, 0x55, 0x0c, 0x01, 0x26, +0x05, 0xf0, 0x2e, 0x05, 0x06, 0x5f, 0x07, 0x06, 0x51, 0x09, 0x02, 0x07, +0x5c, 0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, 0x62, 0xd7, 0x14, 0x80, 0x5b, +0x51, 0x0a, 0x78, 0x3a, 0x07, 0xc0, 0x0f, 0x51, 0x09, 0x02, 0x07, 0x5c, +0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, 0x2e, 0x05, 0x20, 0x60, 0xd8, 0x62, +0xd7, 0x04, 0x80, 0x3f, 0x5d, 0xd8, 0x3a, 0x0a, 0xd0, 0x2b, 0xa0, 0x29, +0x53, 0x07, 0x53, 0x06, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x04, 0x80, 0x18, +0x51, 0x0b, 0x78, 0x3a, 0x07, 0xc0, 0x16, 0x51, 0x09, 0x02, 0x07, 0x5c, +0x5d, 0xd8, 0x54, 0x00, 0x2e, 0x05, 0x10, 0x76, 0x07, 0x80, 0x01, 0x62, +0xd7, 0x10, 0x80, 0x0f, 0x62, 0xd7, 0x00, 0x80, 0x0a, 0x26, 0x05, 0xf0, +0x2e, 0x05, 0x00, 0x55, 0x0c, 0x00, 0x18, 0x60, 0xd0, 0x18, 0x60, 0xd3, +0x20, 0x18, 0x7e, 0x62, 0xd0, 0x00, 0x71, 0x10, 0x41, 0x04, 0xfc, 0x43, +0x05, 0x03, 0x70, 0xef, 0x26, 0x03, 0xfc, 0x51, 0x03, 0x60, 0x04, 0x55, +0x0c, 0x00, 0x90, 0x28, 0x90, 0x2d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x50, +0x00, 0x53, 0x06, 0x71, 0x10, 0x43, 0x04, 0x03, 0x43, 0x05, 0x03, 0x70, +0xef, 0x2e, 0x03, 0x03, 0x51, 0x03, 0x60, 0x04, 0x7f, 0x62, 0xd0, 0x00, +0x51, 0x05, 0x21, 0xb0, 0x26, 0x05, 0x4f, 0x7f, 0x41, 0xe0, 0x7f, 0x43, +0xe0, 0x80, 0x7f, 0x43, 0xd6, 0x31, 0x7f, 0x41, 0xe0, 0x7f, 0x41, 0xd6, +0xfe, 0x7f, 0x62, 0xd0, 0x00, 0x4f, 0x52, 0xfd, 0x53, 0x0a, 0x52, 0xfc, +0x53, 0x0b, 0x52, 0xfb, 0x53, 0x09, 0x52, 0xfa, 0x53, 0x08, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x08, 0x5d, 0xa4, 0x04, 0x1b, 0x5d, 0xa5, 0x0c, 0x1a, +0x55, 0x1c, 0x01, 0x18, 0x7e, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, +0x53, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x8e, 0x62, 0xd3, 0x00, +0x13, 0x7c, 0x62, 0xd3, 0x00, 0x54, 0x80, 0x62, 0xd3, 0x00, 0x52, 0x8d, +0x62, 0xd3, 0x00, 0x1b, 0x7b, 0x62, 0xd3, 0x00, 0x54, 0x7f, 0x48, 0x7f, +0x80, 0xb0, 0x33, 0x3d, 0x7f, 0x00, 0xb0, 0x7b, 0x51, 0x0d, 0x3b, 0x80, +0xc0, 0x75, 0x52, 0x80, 0x58, 0x1e, 0x01, 0x00, 0x6d, 0x62, 0xd3, 0x00, +0x05, 0x4a, 0xc0, 0x09, 0x51, 0x0f, 0x3b, 0x4a, 0xd0, 0x12, 0xa0, 0x10, +0x56, 0x4a, 0x00, 0x5b, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x07, 0x7c, 0x01, +0x0f, 0x7b, 0x00, 0x80, 0x41, 0x3d, 0x7f, 0xff, 0xb0, 0x09, 0x50, 0xff, +0x12, 0x0e, 0x3b, 0x80, 0xc0, 0x20, 0x62, 0xd3, 0x00, 0x56, 0x80, 0x00, +0x56, 0x7f, 0x00, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x51, 0x78, +0xd0, 0x03, 0x50, 0x00, 0x54, 0x51, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, +0x2c, 0x62, 0xd3, 0x00, 0x52, 0x8e, 0x62, 0xd3, 0x00, 0x54, 0x7c, 0x62, +0xd3, 0x00, 0x52, 0x8d, 0x62, 0xd3, 0x00, 0x54, 0x7b, 0x51, 0x1e, 0x64, +0x5c, 0x62, 0xd3, 0x00, 0x56, 0x80, 0x00, 0x56, 0x7f, 0x00, 0x5b, 0x67, +0x5c, 0x62, 0xd3, 0x00, 0x51, 0x12, 0x54, 0x51, 0x70, 0x3f, 0x71, 0xc0, +0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x08, 0x5c, 0x62, 0xd3, +0x00, 0x52, 0x4c, 0x53, 0x19, 0x55, 0x18, 0x00, 0x18, 0x08, 0x90, 0x7e, +0x62, 0xd3, 0x00, 0x23, 0x4e, 0xb0, 0x2c, 0x51, 0x10, 0x04, 0x19, 0x0e, +0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x80, 0x12, 0x19, +0x52, 0x7f, 0x1a, 0x18, 0xc0, 0x39, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, +0x52, 0x4f, 0x78, 0x54, 0x4f, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x3e, +0x80, 0x18, 0x51, 0x10, 0x14, 0x19, 0x1e, 0x18, 0x00, 0x18, 0x64, 0x5c, +0x62, 0xd3, 0x00, 0x52, 0x80, 0x12, 0x19, 0x52, 0x7f, 0x1a, 0x18, 0xc0, +0x0e, 0x5b, 0x67, 0x90, 0x31, 0x62, 0xd3, 0x00, 0x2d, 0x4e, 0x50, 0x01, +0x80, 0x24, 0x5b, 0x67, 0x08, 0x90, 0x23, 0x73, 0x62, 0xd3, 0x00, 0x25, +0x4e, 0x62, 0xd3, 0x00, 0x20, 0x51, 0x11, 0x54, 0x4f, 0x50, 0x00, 0x80, +0x0d, 0x5b, 0x67, 0x90, 0x0d, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x4e, 0x50, +0x00, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x5c, 0x18, +0x21, 0x07, 0xf0, 0x01, 0x7f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, +0x80, 0x70, 0xbf, 0x70, 0xbf, 0x62, 0xd3, 0x00, 0x50, 0x02, 0x78, 0x08, +0x5c, 0x56, 0x4c, 0x1e, 0x18, 0x78, 0xdf, 0xf8, 0x70, 0x3f, 0x71, 0xc0, +0x7f, 0x08, 0x91, 0xb2, 0x70, 0xbf, 0x18, 0x08, 0x64, 0x5c, 0x62, 0xd3, +0x00, 0x52, 0x8e, 0x62, 0xd3, 0x00, 0x54, 0x7c, 0x62, 0xd3, 0x00, 0x52, +0x8d, 0x62, 0xd3, 0x00, 0x54, 0x7b, 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x14, 0x00, 0x50, 0x02, 0x78, +0x08, 0x9f, 0x0e, 0x39, 0x01, 0xb0, 0x04, 0x55, 0x14, 0x01, 0x18, 0x78, +0xdf, 0xf3, 0x51, 0x14, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x9e, 0x3e, 0x18, +0x78, 0xdf, 0xfa, 0x7f, 0x98, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, +0x97, 0xd8, 0xd9, 0xda, 0xdb, 0xdf, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, +0x3f, 0x7f, 0xff, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x62, 0xd3, 0x00, 0x57, +0x00, 0x56, 0x4e, 0x00, 0x79, 0xdf, 0xfb, 0x62, 0xd3, 0x00, 0x57, 0x01, +0x50, 0x03, 0x54, 0x4f, 0x79, 0xdf, 0xfc, 0x62, 0xd3, 0x00, 0x50, 0x14, +0x57, 0x01, 0x54, 0x51, 0x79, 0xdf, 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x55, +0x0d, 0x14, 0x55, 0x0e, 0x05, 0x55, 0x0f, 0x14, 0x55, 0x10, 0x01, 0x55, +0x11, 0x03, 0x55, 0x12, 0x14, 0x55, 0x22, 0x04, 0x55, 0x1f, 0x14, 0x43, +0x61, 0x0d, 0x57, 0x00, 0x50, 0x02, 0x90, 0xae, 0x50, 0x04, 0xff, 0x98, +0x29, 0x00, 0x60, 0xa9, 0x62, 0xa0, 0x08, 0x43, 0xa2, 0x04, 0x62, 0xa3, +0x70, 0x43, 0x7a, 0x01, 0x43, 0xaa, 0x02, 0x43, 0xdf, 0x01, 0x50, 0x01, +0x57, 0x09, 0x90, 0x20, 0x90, 0x55, 0x57, 0x01, 0x50, 0xb3, 0x91, 0x5d, +0x50, 0x01, 0x57, 0x0d, 0x90, 0x12, 0x90, 0x47, 0x7f, 0x53, 0x22, 0xff, +0x67, 0x29, 0x00, 0x60, 0xa9, 0x51, 0x21, 0x58, 0x20, 0x90, 0x01, 0x7f, +0x62, 0xd0, 0x00, 0x21, 0x03, 0x53, 0x21, 0x64, 0x64, 0x64, 0x64, 0x64, +0x29, 0x80, 0x60, 0xa1, 0x5b, 0x78, 0x21, 0x0f, 0x29, 0x08, 0x74, 0x53, +0x20, 0x12, 0x22, 0x02, 0x21, 0x5c, 0x50, 0x00, 0x53, 0x1d, 0x53, 0x23, +0x29, 0x01, 0x79, 0xa0, 0x08, 0x64, 0x6b, 0x1d, 0x6b, 0x23, 0x8f, 0xf5, +0x60, 0xb5, 0x51, 0x1d, 0x60, 0xb4, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x90, +0x28, 0x90, 0x5a, 0x18, 0x78, 0xdf, 0xf8, 0x7f, 0x41, 0xdf, 0xfe, 0x71, +0x10, 0x41, 0xd8, 0xfd, 0x70, 0xef, 0x41, 0x61, 0xf3, 0x41, 0xa2, 0xfb, +0x41, 0xa0, 0xf7, 0x62, 0xa3, 0x00, 0x62, 0xa9, 0x00, 0x41, 0xaa, 0xfd, +0x7f, 0x02, 0x20, 0x02, 0x08, 0x64, 0x5c, 0xff, 0xf8, 0x4b, 0x74, 0xff, +0xf4, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1d, 0x10, 0x5b, 0x64, 0x64, 0x5c, +0x71, 0x10, 0x5e, 0x01, 0x2a, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, +0x00, 0x22, 0x1d, 0x61, 0x00, 0x36, 0x1d, 0xff, 0x18, 0xfe, 0xd6, 0x5c, +0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x7f, 0x62, 0xd0, 0x00, +0x10, 0x73, 0x53, 0x1d, 0x71, 0x10, 0x5b, 0xfe, 0xc0, 0x5c, 0x5e, 0x00, +0x22, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x18, 0x64, 0x64, 0x5c, 0x71, 0x10, +0x5e, 0x01, 0x22, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, 0x00, 0x2a, +0x1d, 0x61, 0x00, 0x70, 0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, +0x1e, 0x50, 0x00, 0x53, 0x1a, 0x53, 0x1b, 0x51, 0x1e, 0x5c, 0x62, 0xd3, +0x00, 0x52, 0x24, 0x53, 0x1f, 0x43, 0xa0, 0x01, 0x51, 0x1f, 0x60, 0xfd, +0x41, 0xa3, 0xdf, 0x51, 0x1e, 0x9f, 0x7a, 0x9f, 0x81, 0x58, 0x23, 0x55, +0x1c, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, 0x43, 0xb3, 0x01, 0x51, +0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1e, 0x9f, 0x5f, 0x9f, 0x91, +0x43, 0xa3, 0x20, 0x41, 0xa0, 0xfe, 0x62, 0xfd, 0x00, 0x50, 0xff, 0x4c, +0x1b, 0x14, 0x1b, 0x51, 0x20, 0x11, 0x08, 0xfe, 0x4d, 0x4c, 0x1a, 0x1c, +0x1a, 0xd0, 0x07, 0x55, 0x1a, 0x00, 0x55, 0x1b, 0x00, 0x51, 0x1e, 0x64, +0x5c, 0x62, 0xd3, 0x00, 0x51, 0x1b, 0x54, 0x8e, 0x51, 0x1a, 0x54, 0x8d, +0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x9f, 0x86, 0x18, 0x78, 0xdf, 0xfa, +0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x27, 0x5a, 0x26, 0x55, 0x1e, +0x01, 0x62, 0xd3, 0x00, 0x58, 0x1e, 0x56, 0x24, 0x80, 0x55, 0x29, 0x08, +0x55, 0x28, 0x80, 0x51, 0x1e, 0x9f, 0x63, 0x51, 0x1e, 0x9f, 0x5f, 0x70, +0xbf, 0x58, 0x1e, 0x62, 0xd3, 0x00, 0x51, 0x1b, 0x3a, 0x27, 0x51, 0x1a, +0x1a, 0x26, 0xd0, 0x06, 0x51, 0x28, 0x73, 0x25, 0x24, 0x68, 0x28, 0x26, +0x28, 0x7f, 0x51, 0x28, 0x2d, 0x24, 0x7a, 0x29, 0xbf, 0xd6, 0x7a, 0x1e, +0xdf, 0xc4, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0xa4, +0x11, 0xd0, 0x51, 0xa3, 0x19, 0x07, 0xd0, 0x12, 0x7c, 0x13, 0x7d, 0x39, +0x0f, 0xa0, 0x16, 0x62, 0xd0, 0x00, 0x76, 0xa4, 0x0e, 0xa3, 0x00, 0x80, +0x0c, 0x62, 0xd0, 0x00, 0x55, 0xa4, 0x00, 0x55, 0xa3, 0x00, 0x90, 0xbe, +0x7f, 0x62, 0xd0, 0x00, 0x3c, 0xb0, 0xf0, 0xd0, 0x03, 0x76, 0xb0, 0x62, +0xd0, 0x00, 0x51, 0x2f, 0x21, 0x7f, 0x53, 0x49, 0x51, 0xb0, 0x3a, 0x49, +0xb0, 0x55, 0x7c, 0x13, 0x7d, 0x62, 0xd0, 0x00, 0x53, 0xb1, 0x3c, 0xb1, +0x0f, 0xa0, 0x3d, 0x3c, 0xac, 0x00, 0xb0, 0x1c, 0x55, 0x95, 0x00, 0x55, +0x96, 0x00, 0x51, 0xb1, 0x53, 0x48, 0x55, 0x49, 0x00, 0x06, 0x48, 0x95, +0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd5, 0x50, 0x08, 0x3f, 0x48, 0x62, +0xd0, 0x00, 0x55, 0xa8, 0x00, 0x3c, 0xaf, 0x00, 0xb0, 0x0a, 0x7c, 0x14, +0x44, 0x62, 0xd0, 0x00, 0x55, 0xaf, 0x01, 0x62, 0xd0, 0x00, 0x55, 0xa7, +0x03, 0x80, 0x0c, 0x62, 0xd0, 0x00, 0x3c, 0xaa, 0x00, 0xb0, 0x04, 0x55, +0xaa, 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0xa4, 0x00, 0x55, 0xa3, 0x00, +0x3c, 0xaf, 0x01, 0xb0, 0x33, 0x7a, 0xa7, 0x3c, 0xa7, 0x00, 0xb0, 0x3a, +0x3c, 0xaf, 0x01, 0xb0, 0x0a, 0x7c, 0x14, 0xd7, 0x62, 0xd0, 0x00, 0x55, +0xaf, 0x00, 0x62, 0xd0, 0x00, 0x3c, 0xac, 0x00, 0xb0, 0x0e, 0x51, 0xb1, +0x53, 0x48, 0x55, 0x49, 0x00, 0x06, 0x48, 0x95, 0x7c, 0x1a, 0x5b, 0x62, +0xd0, 0x00, 0x55, 0xb0, 0x00, 0x80, 0x0f, 0x62, 0xd0, 0x00, 0x3c, 0xaa, +0x01, 0xb0, 0x07, 0x55, 0xaa, 0x00, 0x55, 0xb0, 0x00, 0x7f, 0x10, 0x4f, +0x38, 0x16, 0x62, 0xd0, 0x00, 0x3c, 0xab, 0x00, 0xb0, 0x05, 0x51, 0x9d, +0x53, 0x24, 0x56, 0x0d, 0x00, 0x80, 0x67, 0x56, 0x00, 0x00, 0x80, 0x5b, +0x62, 0xd0, 0x00, 0x3c, 0xab, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x48, +0x55, 0x49, 0x00, 0x06, 0x48, 0x9d, 0x7c, 0x19, 0x6d, 0x52, 0x00, 0x53, +0x46, 0x55, 0x47, 0x00, 0x06, 0x46, 0x24, 0x7c, 0x1a, 0x30, 0x10, 0x52, +0x00, 0x7c, 0x09, 0x2a, 0x20, 0x10, 0x7c, 0x05, 0xb5, 0x62, 0xd0, 0x00, +0x20, 0x39, 0x00, 0xbf, 0xee, 0x7c, 0x18, 0xdc, 0x52, 0x0d, 0x7c, 0x1a, +0x67, 0x02, 0x48, 0x53, 0x48, 0x51, 0x47, 0x0a, 0x49, 0x53, 0x49, 0x7c, +0x1a, 0x3c, 0x06, 0x46, 0x8d, 0x0e, 0x47, 0x00, 0x51, 0x47, 0x7c, 0x19, +0x79, 0x7c, 0x19, 0x8f, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0xa2, 0x77, +0x0d, 0x3d, 0x0d, 0x03, 0xcf, 0x96, 0x56, 0x00, 0x00, 0x81, 0x05, 0x7c, +0x18, 0xc0, 0x7c, 0x19, 0x28, 0x51, 0x49, 0x60, 0xd4, 0x3e, 0x48, 0x54, +0x0e, 0x3e, 0x48, 0x54, 0x0f, 0x52, 0x00, 0x53, 0x48, 0x55, 0x49, 0x00, +0x55, 0x46, 0x06, 0x55, 0x47, 0x00, 0x55, 0x41, 0x00, 0x55, 0x40, 0x00, +0x3c, 0x47, 0x00, 0xb0, 0x06, 0x3c, 0x46, 0x00, 0xa0, 0x1a, 0x70, 0xfb, +0x6e, 0x47, 0x6e, 0x46, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x48, 0x04, +0x41, 0x51, 0x49, 0x0c, 0x40, 0x65, 0x48, 0x6b, 0x49, 0x8f, 0xde, 0x5f, +0x48, 0x41, 0x5f, 0x49, 0x40, 0x62, 0xd0, 0x00, 0x5a, 0x46, 0x06, 0x46, +0x03, 0x51, 0x46, 0x04, 0x48, 0x0e, 0x49, 0x03, 0x51, 0x49, 0x60, 0xd4, +0x3e, 0x48, 0x54, 0x10, 0x3e, 0x48, 0x54, 0x11, 0x52, 0x00, 0x53, 0x48, +0x55, 0x49, 0x00, 0x55, 0x46, 0x06, 0x55, 0x47, 0x00, 0x55, 0x41, 0x00, +0x55, 0x40, 0x00, 0x3c, 0x47, 0x00, 0xb0, 0x06, 0x3c, 0x46, 0x00, 0xa0, +0x1a, 0x70, 0xfb, 0x6e, 0x47, 0x6e, 0x46, 0xd0, 0x0c, 0x62, 0xd0, 0x00, +0x51, 0x48, 0x04, 0x41, 0x51, 0x49, 0x0c, 0x40, 0x65, 0x48, 0x6b, 0x49, +0x8f, 0xde, 0x5f, 0x48, 0x41, 0x5f, 0x49, 0x40, 0x62, 0xd0, 0x00, 0x5a, +0x46, 0x06, 0x46, 0x05, 0x51, 0x46, 0x04, 0x48, 0x0e, 0x49, 0x03, 0x51, +0x49, 0x60, 0xd4, 0x3e, 0x48, 0x54, 0x12, 0x3e, 0x48, 0x54, 0x13, 0x50, +0x03, 0x08, 0x5a, 0x48, 0x06, 0x48, 0x0e, 0x08, 0x51, 0x48, 0x08, 0x7c, +0x17, 0x67, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, 0x48, 0x54, 0x15, 0x51, +0x49, 0x54, 0x14, 0x7c, 0x18, 0xb4, 0x7c, 0x19, 0xa7, 0x7c, 0x19, 0xfc, +0x06, 0x48, 0x7b, 0x7c, 0x1a, 0x07, 0x7c, 0x18, 0xb4, 0x51, 0x48, 0x01, +0x63, 0x7c, 0x19, 0xc8, 0x51, 0x48, 0x01, 0x6b, 0x7c, 0x19, 0xc8, 0x06, +0x48, 0x73, 0x7c, 0x1a, 0x07, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xf8, +0x38, 0xea, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x16, 0x10, 0x57, 0x09, 0x50, +0x01, 0x7c, 0x08, 0x64, 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x10, 0x08, +0x57, 0xa2, 0x28, 0x53, 0x49, 0x18, 0x75, 0x09, 0x00, 0x28, 0x53, 0x48, +0x20, 0x10, 0x51, 0x49, 0x08, 0x51, 0x48, 0x20, 0x7c, 0x09, 0xa9, 0x20, +0x10, 0x57, 0x0d, 0x50, 0x01, 0x7c, 0x08, 0x64, 0x20, 0x62, 0xd0, 0x00, +0x3c, 0xab, 0x01, 0xb0, 0x0b, 0x51, 0x24, 0x53, 0x30, 0x51, 0x25, 0x53, +0x31, 0x80, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x9d, 0x53, 0x24, 0x51, 0x9e, +0x53, 0x25, 0x10, 0x50, 0x00, 0x7c, 0x09, 0x2a, 0x20, 0x56, 0x0d, 0x00, +0x80, 0x67, 0x56, 0x00, 0x00, 0x80, 0x5b, 0x62, 0xd0, 0x00, 0x3c, 0xab, +0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x06, 0x48, +0x9d, 0x7c, 0x19, 0x6d, 0x52, 0x00, 0x53, 0x46, 0x55, 0x47, 0x00, 0x06, +0x46, 0x24, 0x7c, 0x1a, 0x30, 0x10, 0x52, 0x00, 0x7c, 0x09, 0x2a, 0x20, +0x10, 0x7c, 0x05, 0xb5, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, +0x7c, 0x18, 0xdc, 0x52, 0x0d, 0x7c, 0x1a, 0x67, 0x02, 0x48, 0x53, 0x48, +0x51, 0x47, 0x0a, 0x49, 0x53, 0x49, 0x7c, 0x1a, 0x3c, 0x06, 0x46, 0x8d, +0x0e, 0x47, 0x00, 0x51, 0x47, 0x7c, 0x19, 0x79, 0x7c, 0x19, 0x8f, 0x77, +0x00, 0x3d, 0x00, 0x02, 0xcf, 0xa2, 0x77, 0x0d, 0x3d, 0x0d, 0x03, 0xcf, +0x96, 0x56, 0x00, 0x00, 0x81, 0x05, 0x7c, 0x18, 0xc0, 0x7c, 0x19, 0x28, +0x51, 0x49, 0x60, 0xd4, 0x3e, 0x48, 0x54, 0x0e, 0x3e, 0x48, 0x54, 0x0f, +0x52, 0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x55, 0x46, 0x06, 0x55, 0x47, +0x00, 0x55, 0x41, 0x00, 0x55, 0x40, 0x00, 0x3c, 0x47, 0x00, 0xb0, 0x06, +0x3c, 0x46, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x47, 0x6e, 0x46, 0xd0, +0x0c, 0x62, 0xd0, 0x00, 0x51, 0x48, 0x04, 0x41, 0x51, 0x49, 0x0c, 0x40, +0x65, 0x48, 0x6b, 0x49, 0x8f, 0xde, 0x5f, 0x48, 0x41, 0x5f, 0x49, 0x40, +0x62, 0xd0, 0x00, 0x5a, 0x46, 0x06, 0x46, 0x03, 0x51, 0x46, 0x04, 0x48, +0x0e, 0x49, 0x03, 0x51, 0x49, 0x60, 0xd4, 0x3e, 0x48, 0x54, 0x10, 0x3e, +0x48, 0x54, 0x11, 0x52, 0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x55, 0x46, +0x06, 0x55, 0x47, 0x00, 0x55, 0x41, 0x00, 0x55, 0x40, 0x00, 0x3c, 0x47, +0x00, 0xb0, 0x06, 0x3c, 0x46, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x47, +0x6e, 0x46, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x48, 0x04, 0x41, 0x51, +0x49, 0x0c, 0x40, 0x65, 0x48, 0x6b, 0x49, 0x8f, 0xde, 0x5f, 0x48, 0x41, +0x5f, 0x49, 0x40, 0x62, 0xd0, 0x00, 0x5a, 0x46, 0x06, 0x46, 0x05, 0x51, +0x46, 0x04, 0x48, 0x0e, 0x49, 0x03, 0x51, 0x49, 0x60, 0xd4, 0x3e, 0x48, +0x54, 0x12, 0x3e, 0x48, 0x54, 0x13, 0x50, 0x03, 0x08, 0x5a, 0x48, 0x06, +0x48, 0x0e, 0x08, 0x51, 0x48, 0x08, 0x7c, 0x17, 0x67, 0x38, 0xfd, 0x62, +0xd0, 0x00, 0x51, 0x48, 0x54, 0x15, 0x51, 0x49, 0x54, 0x14, 0x7c, 0x18, +0xb4, 0x7c, 0x19, 0xa7, 0x7c, 0x19, 0xfc, 0x06, 0x48, 0x7b, 0x7c, 0x1a, +0x07, 0x7c, 0x18, 0xb4, 0x51, 0x48, 0x01, 0x63, 0x7c, 0x19, 0xc8, 0x51, +0x48, 0x01, 0x6b, 0x7c, 0x19, 0xc8, 0x06, 0x48, 0x73, 0x7c, 0x1a, 0x07, +0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xf8, 0x56, 0x00, 0x00, 0x80, 0x19, +0x7c, 0x18, 0xc0, 0x06, 0x48, 0x24, 0x7c, 0x19, 0x6d, 0x52, 0x00, 0x53, +0x46, 0x55, 0x47, 0x00, 0x06, 0x46, 0x30, 0x7c, 0x1a, 0x30, 0x77, 0x00, +0x3d, 0x00, 0x02, 0xcf, 0xe4, 0x38, 0xea, 0x20, 0x7f, 0x10, 0x4f, 0x38, +0x02, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x01, 0x02, 0x53, 0x48, 0x52, 0xfb, +0x09, 0x00, 0x7c, 0x19, 0x9c, 0x52, 0xfc, 0x01, 0x04, 0x53, 0x46, 0x52, +0xfb, 0x7c, 0x19, 0x84, 0x12, 0x48, 0x51, 0x47, 0x1a, 0x49, 0xc0, 0x6f, +0x52, 0xfc, 0x53, 0x48, 0x52, 0xfb, 0x7c, 0x19, 0x9c, 0x52, 0xfc, 0x01, +0x02, 0x53, 0x46, 0x52, 0xfb, 0x7c, 0x19, 0x84, 0x12, 0x48, 0x51, 0x47, +0x1a, 0x49, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, 0x19, 0xe6, 0x54, +0x00, 0x3e, 0x48, 0x54, 0x01, 0x80, 0xb3, 0x62, 0xd0, 0x00, 0x52, 0xfc, +0x01, 0x04, 0x53, 0x48, 0x52, 0xfb, 0x09, 0x00, 0x7c, 0x19, 0x9c, 0x52, +0xfc, 0x53, 0x46, 0x52, 0xfb, 0x60, 0xd4, 0x3e, 0x46, 0x53, 0x47, 0x3e, +0x46, 0x12, 0x48, 0x51, 0x47, 0x1a, 0x49, 0xc0, 0x10, 0x52, 0xfc, 0x01, +0x04, 0x7c, 0x19, 0xe6, 0x54, 0x00, 0x3e, 0x48, 0x54, 0x01, 0x80, 0x7e, +0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x48, 0x52, 0xfb, 0x7c, 0x19, 0xf1, +0x80, 0x70, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x48, 0x52, 0xfb, 0x7c, +0x19, 0x9c, 0x52, 0xfc, 0x01, 0x04, 0x53, 0x46, 0x52, 0xfb, 0x7c, 0x19, +0x84, 0x12, 0x48, 0x51, 0x47, 0x1a, 0x49, 0xc0, 0x10, 0x52, 0xfc, 0x01, +0x04, 0x7c, 0x19, 0xe6, 0x54, 0x00, 0x3e, 0x48, 0x54, 0x01, 0x80, 0x42, +0x62, 0xd0, 0x00, 0x52, 0xfc, 0x01, 0x02, 0x53, 0x48, 0x52, 0xfb, 0x09, +0x00, 0x7c, 0x19, 0x9c, 0x52, 0xfc, 0x53, 0x46, 0x52, 0xfb, 0x60, 0xd4, +0x3e, 0x46, 0x53, 0x47, 0x3e, 0x46, 0x12, 0x48, 0x51, 0x47, 0x1a, 0x49, +0xc0, 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, 0x19, 0xe6, 0x54, 0x00, 0x3e, +0x48, 0x54, 0x01, 0x80, 0x0d, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x48, +0x52, 0xfb, 0x7c, 0x19, 0xf1, 0x62, 0xd0, 0x00, 0x52, 0x01, 0x53, 0x48, +0x52, 0x00, 0x53, 0x49, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x05, +0x62, 0xd0, 0x00, 0x55, 0xb3, 0x00, 0x56, 0x00, 0x00, 0x80, 0x38, 0x62, +0xd0, 0x00, 0x3c, 0xab, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x48, 0x55, +0x49, 0x00, 0x06, 0x48, 0x9d, 0x7c, 0x19, 0x6d, 0x52, 0x00, 0x53, 0x46, +0x55, 0x47, 0x00, 0x06, 0x46, 0x24, 0x7c, 0x1a, 0x30, 0x10, 0x52, 0x00, +0x7c, 0x09, 0x2a, 0x20, 0x10, 0x7c, 0x05, 0xb5, 0x62, 0xd0, 0x00, 0x20, +0x39, 0x00, 0xbf, 0xee, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0xc5, 0x56, +0x00, 0x00, 0x82, 0xab, 0x62, 0xd0, 0x00, 0x3c, 0xb2, 0x02, 0xa0, 0x9f, +0x7c, 0x18, 0xb4, 0x51, 0x48, 0x01, 0x7b, 0x7c, 0x18, 0xcb, 0x06, 0x48, +0x8d, 0x7c, 0x19, 0x6d, 0x7c, 0x19, 0xd9, 0xd0, 0x16, 0x7c, 0x18, 0xb4, +0x51, 0x48, 0x01, 0x7b, 0x7c, 0x18, 0xcb, 0x06, 0x48, 0x8d, 0x7c, 0x19, +0x6d, 0x7c, 0x1a, 0x73, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb4, +0x51, 0x48, 0x01, 0x8d, 0x7c, 0x18, 0xcb, 0x06, 0x48, 0x7b, 0x7c, 0x19, +0x6d, 0x7c, 0x1a, 0x73, 0x50, 0x2c, 0x13, 0x02, 0x50, 0x01, 0x1b, 0x01, +0xc0, 0x4e, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb4, 0x51, 0x48, 0x01, 0x73, +0x7c, 0x18, 0xcb, 0x06, 0x48, 0x8d, 0x7c, 0x19, 0x6d, 0x7c, 0x19, 0xd9, +0xd0, 0x16, 0x7c, 0x18, 0xb4, 0x51, 0x48, 0x01, 0x73, 0x7c, 0x18, 0xcb, +0x06, 0x48, 0x8d, 0x7c, 0x19, 0x6d, 0x7c, 0x1a, 0x8d, 0x80, 0x17, 0x62, +0xd0, 0x00, 0x7c, 0x18, 0xb4, 0x51, 0x48, 0x01, 0x8d, 0x7c, 0x18, 0xcb, +0x06, 0x48, 0x73, 0x7c, 0x19, 0x6d, 0x7c, 0x1a, 0x8d, 0x50, 0x2c, 0x13, +0x04, 0x50, 0x01, 0x1b, 0x03, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x76, 0xb3, +0x82, 0x03, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb4, 0x51, 0x48, 0x01, 0x8d, +0x7c, 0x18, 0xcb, 0x06, 0x48, 0x73, 0x7c, 0x19, 0x6d, 0x7c, 0x19, 0xd9, +0xd0, 0x5a, 0x7c, 0x18, 0xb4, 0x7c, 0x19, 0xb2, 0x06, 0x46, 0x01, 0x0e, +0x47, 0x00, 0x7c, 0x19, 0x8f, 0x7c, 0x18, 0xb4, 0x51, 0x48, 0x01, 0x8d, +0x7c, 0x18, 0xcb, 0x06, 0x48, 0x73, 0x7c, 0x19, 0x6d, 0x7c, 0x19, 0xd9, +0xd0, 0xb4, 0x7c, 0x18, 0xb4, 0x7c, 0x19, 0xb2, 0x06, 0x46, 0x01, 0x0e, +0x47, 0x00, 0x7c, 0x19, 0x8f, 0x97, 0xf1, 0x40, 0x51, 0x48, 0x01, 0x8d, +0x7c, 0x18, 0xcb, 0x06, 0x48, 0x73, 0x7c, 0x19, 0x6d, 0x7c, 0x19, 0xd9, +0xd0, 0x90, 0x97, 0xdc, 0x40, 0x7c, 0x19, 0xb2, 0x06, 0x46, 0x01, 0x0e, +0x47, 0x00, 0x7c, 0x19, 0x8f, 0x80, 0x7f, 0x62, 0xd0, 0x00, 0x97, 0xc8, +0x40, 0x51, 0x48, 0x01, 0x8d, 0x97, 0xd8, 0x40, 0x06, 0x48, 0x73, 0x7c, +0x19, 0x6d, 0x3e, 0x48, 0x12, 0x46, 0x51, 0x49, 0x1a, 0x47, 0xd0, 0x62, +0x97, 0xae, 0x40, 0x7c, 0x19, 0xb2, 0x16, 0x46, 0x01, 0x1e, 0x47, 0x00, +0x7c, 0x19, 0x8f, 0x97, 0x9f, 0x40, 0x51, 0x48, 0x01, 0x8d, 0x97, 0xaf, +0x40, 0x06, 0x48, 0x73, 0x7c, 0x19, 0x6d, 0x3e, 0x48, 0x12, 0x46, 0x51, +0x49, 0x1a, 0x47, 0xd0, 0x39, 0x97, 0x85, 0x40, 0x7c, 0x19, 0xb2, 0x16, +0x46, 0x01, 0x1e, 0x47, 0x00, 0x7c, 0x19, 0x8f, 0x97, 0x76, 0x40, 0x51, +0x48, 0x01, 0x8d, 0x97, 0x86, 0x40, 0x06, 0x48, 0x73, 0x7c, 0x19, 0x6d, +0x3e, 0x48, 0x12, 0x46, 0x51, 0x49, 0x1a, 0x47, 0xd0, 0x10, 0x97, 0x5c, +0x40, 0x7c, 0x19, 0xb2, 0x16, 0x46, 0x01, 0x1e, 0x47, 0x00, 0x7c, 0x19, +0x8f, 0x62, 0xd0, 0x00, 0x97, 0x4a, 0x40, 0x51, 0x48, 0x01, 0x6b, 0x97, +0x5a, 0x40, 0x06, 0x48, 0x63, 0x0e, 0x49, 0x00, 0x7c, 0x19, 0x8f, 0x97, +0x37, 0x40, 0x51, 0x48, 0x01, 0x73, 0x97, 0x47, 0x40, 0x06, 0x48, 0x6b, +0x0e, 0x49, 0x00, 0x7c, 0x19, 0x8f, 0x97, 0x24, 0x40, 0x51, 0x48, 0x01, +0x8d, 0x97, 0x34, 0x40, 0x06, 0x48, 0x73, 0x0e, 0x49, 0x00, 0x97, 0xef, +0x40, 0x97, 0x11, 0x40, 0x7c, 0x19, 0xa7, 0x53, 0x47, 0x7c, 0x1a, 0x9a, +0x53, 0x44, 0x08, 0x51, 0x45, 0x53, 0x43, 0x18, 0x53, 0x42, 0x65, 0x42, +0x6b, 0x43, 0x06, 0x48, 0x6b, 0x97, 0xae, 0x40, 0x3e, 0x48, 0x53, 0x48, +0x51, 0x42, 0x04, 0x48, 0x51, 0x43, 0x0c, 0x49, 0x51, 0x44, 0x04, 0x48, +0x51, 0x45, 0x0c, 0x49, 0x70, 0xfb, 0x6e, 0x49, 0x6e, 0x48, 0x7c, 0x1a, +0x48, 0x10, 0x52, 0x00, 0x7c, 0x05, 0xf9, 0x20, 0x62, 0xd0, 0x00, 0x96, +0xcb, 0x40, 0x51, 0x48, 0x01, 0x8d, 0x96, 0xdb, 0x40, 0x06, 0x48, 0x7b, +0x97, 0x77, 0x40, 0x97, 0xe0, 0x40, 0xd0, 0x25, 0x52, 0x00, 0x53, 0x48, +0x55, 0x49, 0x00, 0x06, 0x48, 0x99, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, +0xd4, 0x3e, 0x48, 0x7a, 0x48, 0x53, 0x47, 0x06, 0x47, 0x01, 0x51, 0x49, +0x60, 0xd5, 0x51, 0x47, 0x3f, 0x48, 0x80, 0x0a, 0x96, 0x9e, 0x40, 0x06, +0x48, 0x99, 0x7c, 0x1a, 0x5b, 0x96, 0x95, 0x40, 0x06, 0x48, 0x99, 0x97, +0x3c, 0x40, 0x50, 0x05, 0x3a, 0x49, 0xd0, 0x41, 0x96, 0x7a, 0x40, 0x51, +0x48, 0x01, 0x7b, 0x53, 0x46, 0x51, 0x49, 0x09, 0x00, 0x53, 0x47, 0x06, +0x48, 0x8d, 0x97, 0x21, 0x40, 0x3e, 0x48, 0x53, 0x48, 0x51, 0x47, 0x7c, +0x1a, 0x9a, 0x02, 0x48, 0x53, 0x48, 0x51, 0x45, 0x0a, 0x49, 0x53, 0x49, +0x97, 0xe6, 0x40, 0x52, 0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x06, 0x48, +0x99, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x48, +0x77, 0x00, 0x3d, 0x00, 0x02, 0xcd, 0x52, 0x62, 0xd0, 0x00, 0x3c, 0xb2, +0x02, 0xb0, 0x9a, 0x56, 0x00, 0x00, 0x80, 0x90, 0x62, 0xd0, 0x00, 0x96, +0x23, 0x40, 0x51, 0x48, 0x01, 0x8d, 0x96, 0x33, 0x40, 0x06, 0x48, 0x38, +0x0e, 0x49, 0x00, 0x96, 0xee, 0x40, 0x96, 0x10, 0x40, 0x51, 0x48, 0x01, +0x7b, 0x96, 0x20, 0x40, 0x06, 0x48, 0x3c, 0x0e, 0x49, 0x00, 0x96, 0xdb, +0x40, 0x95, 0xfd, 0x40, 0x51, 0x48, 0x01, 0x7b, 0x96, 0x0d, 0x40, 0x51, +0x48, 0x01, 0x8d, 0x53, 0x44, 0x51, 0x49, 0x97, 0xb7, 0x40, 0x51, 0x46, +0x12, 0x44, 0x51, 0x47, 0x1a, 0x45, 0xd0, 0x2b, 0x97, 0x66, 0x40, 0x51, +0x46, 0x01, 0x7b, 0x53, 0x44, 0x51, 0x47, 0x97, 0x9f, 0x40, 0x06, 0x46, +0x8d, 0x0e, 0x47, 0x00, 0x51, 0x47, 0x60, 0xd4, 0x3e, 0x46, 0x53, 0x47, +0x3e, 0x46, 0x12, 0x44, 0x54, 0x02, 0x51, 0x47, 0x1a, 0x45, 0x54, 0x01, +0x80, 0x07, 0x56, 0x02, 0x00, 0x56, 0x01, 0x00, 0x62, 0xd0, 0x00, 0x06, +0x48, 0x34, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd5, 0x52, 0x01, 0x3f, +0x48, 0x52, 0x02, 0x3f, 0x48, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x6d, +0x62, 0xd0, 0x00, 0x3c, 0xb2, 0x02, 0xa0, 0x18, 0x3c, 0xb3, 0x00, 0xa0, +0x13, 0x50, 0x01, 0x08, 0x50, 0x2c, 0x08, 0x90, 0x0e, 0x38, 0xfe, 0x7c, +0x0a, 0xde, 0x10, 0x7c, 0x07, 0xb5, 0x20, 0x38, 0xfb, 0x20, 0x7f, 0x10, +0x4f, 0x80, 0x02, 0x40, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x48, 0x52, +0xfb, 0x53, 0x49, 0x51, 0x48, 0x11, 0x01, 0x54, 0xfc, 0x51, 0x49, 0x19, +0x00, 0x54, 0xfb, 0x3c, 0x49, 0x00, 0xbf, 0xe4, 0x3c, 0x48, 0x00, 0xbf, +0xdf, 0x20, 0x7f, 0x10, 0x7c, 0x04, 0x7f, 0x7c, 0x04, 0x5c, 0x20, 0x7f, +0x10, 0x7c, 0x04, 0x7b, 0x7c, 0x04, 0x58, 0x20, 0x7f, 0x62, 0xd0, 0x00, +0x51, 0x4c, 0x12, 0x80, 0x50, 0x00, 0x1a, 0x7f, 0xd0, 0x0f, 0x51, 0x4d, +0x12, 0x82, 0x50, 0x00, 0x1a, 0x81, 0xd0, 0x05, 0x50, 0x0f, 0x80, 0x17, +0x62, 0xd0, 0x00, 0x51, 0x82, 0x12, 0x80, 0x51, 0x81, 0x1a, 0x7f, 0xd0, +0x05, 0x50, 0x00, 0x80, 0x06, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x7f, 0x10, +0x4f, 0x38, 0x05, 0x62, 0xd0, 0x00, 0x51, 0x80, 0x54, 0x02, 0x51, 0x7f, +0x54, 0x01, 0x56, 0x04, 0x00, 0x56, 0x00, 0x00, 0x56, 0x03, 0x00, 0x80, +0x61, 0x94, 0xf5, 0x40, 0x06, 0x48, 0x4c, 0x0e, 0x49, 0x00, 0x51, 0x49, +0x60, 0xd4, 0x3e, 0x48, 0x53, 0x48, 0x96, 0x60, 0x40, 0x06, 0x46, 0x7f, +0x0e, 0x47, 0x00, 0x51, 0x47, 0x95, 0x92, 0x40, 0x51, 0x48, 0x12, 0x46, +0x50, 0x00, 0x1a, 0x47, 0xd0, 0x03, 0x77, 0x03, 0x62, 0xd0, 0x00, 0x94, +0xbb, 0x40, 0x06, 0x48, 0x7f, 0x95, 0x6e, 0x40, 0x3e, 0x48, 0x53, 0x48, +0x52, 0x02, 0x12, 0x48, 0x52, 0x01, 0x1a, 0x49, 0xd0, 0x1a, 0x94, 0xa4, +0x40, 0x06, 0x48, 0x7f, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd4, 0x3e, +0x48, 0x54, 0x01, 0x3e, 0x48, 0x54, 0x02, 0x52, 0x00, 0x54, 0x04, 0x77, +0x00, 0x3d, 0x00, 0x02, 0xcf, 0x9c, 0x50, 0x01, 0x3b, 0x03, 0xd0, 0x08, +0x62, 0xd0, 0x00, 0x50, 0x0f, 0x80, 0x06, 0x52, 0x04, 0x62, 0xd0, 0x00, +0x38, 0xfb, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x70, 0xfe, 0x62, 0xd0, +0x00, 0x26, 0x2a, 0xf0, 0x51, 0xb1, 0x01, 0x01, 0x53, 0x49, 0x51, 0x2a, +0x2a, 0x49, 0x53, 0x2a, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x05, +0xb5, 0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, 0x01, 0x00, 0x56, +0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0xb5, 0x62, 0xd0, 0x00, 0x20, +0x53, 0x49, 0x47, 0x49, 0x20, 0xa0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, +0x50, 0x04, 0x08, 0x9e, 0xb6, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, +0x52, 0x01, 0x11, 0xdc, 0x52, 0x00, 0x19, 0x05, 0xcf, 0xd7, 0x56, 0x01, +0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0xb5, 0x62, 0xd0, +0x00, 0x20, 0x53, 0x49, 0x47, 0x49, 0x20, 0xb0, 0x03, 0x80, 0x1a, 0x50, +0x00, 0x08, 0x50, 0x04, 0x08, 0x9e, 0x84, 0x38, 0xfe, 0x77, 0x01, 0x0f, +0x00, 0x00, 0x52, 0x01, 0x11, 0x2c, 0x52, 0x00, 0x19, 0x01, 0xcf, 0xd7, +0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x70, +0xfe, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0xf0, 0x51, 0xb1, 0x01, 0x09, 0x53, +0x49, 0x51, 0x2a, 0x2a, 0x49, 0x53, 0x2a, 0x71, 0x01, 0x62, 0xe3, 0x38, +0x10, 0x7c, 0x05, 0xb5, 0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, +0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0xb5, 0x62, +0xd0, 0x00, 0x20, 0x53, 0x49, 0x47, 0x49, 0x20, 0xa0, 0x03, 0x80, 0x1a, +0x50, 0x00, 0x08, 0x50, 0x04, 0x08, 0x9e, 0x23, 0x38, 0xfe, 0x77, 0x01, +0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, 0xdc, 0x52, 0x00, 0x19, 0x05, 0xcf, +0xd7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, +0xb5, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x49, 0x47, 0x49, 0x20, 0xb0, 0x03, +0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x04, 0x08, 0x9d, 0xf1, 0x38, 0xfe, +0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, 0x2c, 0x52, 0x00, 0x19, +0x01, 0xcf, 0xd7, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, +0x38, 0x04, 0x62, 0xd0, 0x00, 0x51, 0x2a, 0x21, 0xf0, 0x54, 0x00, 0x51, +0x2d, 0x54, 0x01, 0x3d, 0x00, 0x10, 0xb0, 0x2a, 0x55, 0xa8, 0x00, 0x3c, +0xac, 0x01, 0xb0, 0x09, 0x55, 0x95, 0x00, 0x55, 0x96, 0x00, 0x80, 0x0f, +0x62, 0xd0, 0x00, 0x3c, 0xaf, 0x01, 0xa0, 0x07, 0x55, 0x95, 0x00, 0x55, +0x96, 0x00, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0x0f, 0x81, +0x76, 0x3d, 0x00, 0x20, 0xb0, 0x18, 0x62, 0xd0, 0x00, 0x55, 0xa8, 0x01, +0x55, 0xa9, 0x00, 0x55, 0x95, 0x08, 0x55, 0x96, 0x08, 0x56, 0x00, 0x00, +0x26, 0x2a, 0x0f, 0x81, 0x5a, 0x3d, 0x00, 0x30, 0xb0, 0x0f, 0x62, 0xd0, +0x00, 0x55, 0xb2, 0x00, 0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x81, 0x47, +0x3d, 0x00, 0x40, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, 0xb2, 0x02, 0x56, +0x00, 0x00, 0x26, 0x2a, 0x0f, 0x81, 0x34, 0x3d, 0x00, 0x50, 0xb0, 0xa7, +0x52, 0x01, 0x54, 0x03, 0x56, 0x02, 0x00, 0x3d, 0x02, 0x00, 0xb0, 0x06, +0x3d, 0x03, 0x01, 0xa0, 0x21, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, +0x02, 0xa0, 0x28, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x04, 0xa0, +0x36, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x08, 0xa0, 0x48, 0x80, +0x62, 0x62, 0xd0, 0x00, 0x55, 0xab, 0x01, 0x51, 0x2f, 0x29, 0x80, 0x53, +0x2f, 0x7c, 0x0c, 0x70, 0x80, 0x51, 0x62, 0xd0, 0x00, 0x51, 0x2b, 0x53, +0x4c, 0x51, 0x2b, 0x53, 0x4d, 0x51, 0x2b, 0x53, 0x2e, 0x51, 0x2c, 0x53, +0x0e, 0x55, 0x0d, 0x00, 0x80, 0x39, 0x62, 0xd0, 0x00, 0x51, 0x2b, 0x53, +0x2f, 0x3c, 0xab, 0x00, 0xa0, 0x09, 0x51, 0x2f, 0x29, 0x80, 0x53, 0x2f, +0x80, 0x25, 0x62, 0xd0, 0x00, 0x26, 0x2f, 0x7f, 0x80, 0x1d, 0x62, 0xd0, +0x00, 0x55, 0xab, 0x00, 0x26, 0x2f, 0x7f, 0x51, 0x9d, 0x53, 0x24, 0x51, +0x24, 0x53, 0x30, 0x51, 0x9e, 0x53, 0x25, 0x51, 0x25, 0x53, 0x31, 0x7c, +0x0c, 0x70, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0x0f, 0x55, +0x2b, 0x06, 0x55, 0x2c, 0x05, 0x55, 0x2d, 0x00, 0x80, 0x89, 0x3d, 0x00, +0x60, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, 0xac, 0x01, 0x56, 0x00, 0x00, +0x26, 0x2a, 0x0f, 0x80, 0x76, 0x3d, 0x00, 0x70, 0xb0, 0x0f, 0x62, 0xd0, +0x00, 0x55, 0xac, 0x00, 0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x80, 0x63, +0x3d, 0x00, 0x80, 0xb0, 0x5e, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, +0x2a, 0x0f, 0x9c, 0x9f, 0x10, 0x7c, 0x08, 0xa8, 0x7c, 0x05, 0xcb, 0x20, +0x70, 0xfe, 0x93, 0xce, 0x40, 0x62, 0xda, 0x00, 0x71, 0x10, 0x41, 0xdc, +0xfe, 0x70, 0xcf, 0x43, 0x01, 0x08, 0x43, 0x00, 0x08, 0x50, 0x00, 0x08, +0x50, 0x1e, 0x08, 0x9c, 0x52, 0x38, 0xfe, 0x71, 0x01, 0x43, 0xe0, 0x10, +0x43, 0xff, 0x08, 0x70, 0xfe, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, +0x10, 0x7c, 0x07, 0xd7, 0x7c, 0x05, 0x7f, 0x7c, 0x05, 0xc0, 0x20, 0x93, +0x06, 0x40, 0x62, 0xe3, 0x38, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, +0x2a, 0x0f, 0x38, 0xfc, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x3c, 0xa8, 0x00, +0xa0, 0x13, 0x9c, 0x3f, 0x62, 0xd0, 0x00, 0x3c, 0xa9, 0x00, 0xb0, 0x33, +0x55, 0xa9, 0x01, 0x7c, 0x0a, 0xde, 0x80, 0x2b, 0x62, 0xd0, 0x00, 0x50, +0x01, 0x3a, 0x95, 0xd0, 0x08, 0x10, 0x7c, 0x04, 0x7f, 0x20, 0x80, 0x06, +0x10, 0x7c, 0x04, 0x7b, 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x96, +0xd0, 0x08, 0x10, 0x7c, 0x04, 0x5c, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, +0x58, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x03, 0x56, 0x02, 0x00, 0x56, 0x01, +0x00, 0x56, 0x00, 0x00, 0x80, 0x3e, 0x62, 0xd0, 0x00, 0x91, 0x39, 0x40, +0x52, 0xfc, 0x04, 0x48, 0x52, 0xfb, 0x0c, 0x49, 0x51, 0x49, 0x60, 0xd4, +0x3e, 0x48, 0x53, 0x49, 0x3e, 0x48, 0x53, 0x48, 0x52, 0x02, 0x12, 0x48, +0x52, 0x01, 0x1a, 0x49, 0xd0, 0x18, 0x91, 0x18, 0x40, 0x52, 0xfc, 0x04, +0x48, 0x52, 0xfb, 0x0c, 0x49, 0x51, 0x49, 0x60, 0xd4, 0x3e, 0x48, 0x54, +0x01, 0x3e, 0x48, 0x54, 0x02, 0x77, 0x00, 0x52, 0x00, 0x3b, 0xfa, 0xcf, +0xbe, 0x62, 0xd0, 0x00, 0x52, 0x02, 0x53, 0x48, 0x52, 0x01, 0x53, 0x49, +0x38, 0xfd, 0x20, 0x7f, 0x10, 0x7c, 0x04, 0x0a, 0x20, 0x10, 0x50, 0x04, +0x08, 0x50, 0x00, 0x08, 0x50, 0x8d, 0x08, 0x7c, 0x04, 0x13, 0x38, 0xfd, +0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, 0x08, 0x50, 0x7b, 0x08, 0x7c, +0x04, 0x13, 0x38, 0xfd, 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, 0x08, +0x50, 0x7f, 0x08, 0x7c, 0x04, 0x13, 0x38, 0xfd, 0x20, 0x10, 0x50, 0x00, +0x7c, 0x03, 0x2e, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x2e, 0x20, 0x10, +0x50, 0xff, 0x7c, 0x03, 0x2e, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0xab, +0x00, 0x55, 0xac, 0x01, 0x10, 0x7c, 0x04, 0x7f, 0x7c, 0x04, 0x5c, 0x20, +0x9b, 0x45, 0x62, 0xe3, 0x38, 0x92, 0x7b, 0x40, 0x43, 0x00, 0x08, 0x62, +0xd0, 0x00, 0x55, 0x2a, 0x08, 0x55, 0x2b, 0x06, 0x55, 0x2c, 0x05, 0x55, +0x2e, 0x1e, 0x55, 0x2f, 0x03, 0x55, 0x30, 0x17, 0x55, 0x31, 0x1e, 0x55, +0x32, 0x00, 0x55, 0x33, 0x00, 0x3c, 0xab, 0x00, 0xa0, 0x09, 0x51, 0x2f, +0x29, 0x80, 0x53, 0x2f, 0x80, 0x07, 0x62, 0xd0, 0x00, 0x26, 0x2f, 0x7f, +0x10, 0x50, 0x00, 0x08, 0x50, 0x2a, 0x08, 0x50, 0x06, 0x08, 0x50, 0x16, +0x08, 0x7c, 0x05, 0xd2, 0x38, 0xfc, 0x7c, 0x05, 0x7f, 0x7c, 0x05, 0xc0, +0x20, 0x91, 0x9c, 0x40, 0x10, 0x7c, 0x07, 0xd7, 0x7c, 0x07, 0x5d, 0x20, +0x62, 0xd0, 0x00, 0x06, 0x4c, 0x0a, 0x7c, 0x0c, 0x70, 0x80, 0x22, 0x62, +0xe3, 0x38, 0x7c, 0x0f, 0x80, 0x10, 0x7c, 0x07, 0x9b, 0x62, 0xd0, 0x00, +0x20, 0x39, 0x00, 0xa0, 0x09, 0x7c, 0x09, 0xf7, 0x7c, 0x0a, 0x21, 0x80, +0x04, 0x7c, 0x0a, 0x8f, 0x9c, 0xbc, 0x9e, 0x72, 0x8f, 0xde, 0x8f, 0xff, +0x52, 0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x65, 0x48, 0x6b, 0x49, 0x7f, +0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x7f, 0x53, +0x46, 0x51, 0x49, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x46, 0x53, 0x47, 0x3e, +0x46, 0x53, 0x46, 0x7f, 0x52, 0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x55, +0x46, 0x06, 0x55, 0x47, 0x00, 0x55, 0x41, 0x00, 0x55, 0x40, 0x00, 0x3c, +0x47, 0x00, 0xb0, 0x06, 0x3c, 0x46, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, +0x47, 0x6e, 0x46, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x48, 0x04, 0x41, +0x51, 0x49, 0x0c, 0x40, 0x65, 0x48, 0x6b, 0x49, 0x8f, 0xde, 0x5f, 0x48, +0x41, 0x5f, 0x49, 0x40, 0x62, 0xd0, 0x00, 0x5a, 0x46, 0x06, 0x46, 0x01, +0x51, 0x46, 0x04, 0x48, 0x0e, 0x49, 0x03, 0x7f, 0x55, 0x46, 0x06, 0x55, +0x47, 0x00, 0x55, 0x41, 0x00, 0x55, 0x40, 0x00, 0x3c, 0x47, 0x00, 0xb0, +0x06, 0x3c, 0x46, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x47, 0x6e, 0x46, +0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x48, 0x04, 0x41, 0x51, 0x49, 0x0c, +0x40, 0x65, 0x48, 0x6b, 0x49, 0x8f, 0xde, 0x5f, 0x48, 0x41, 0x5f, 0x49, +0x40, 0x62, 0xd0, 0x00, 0x5a, 0x46, 0x06, 0x46, 0x01, 0x51, 0x46, 0x04, +0x48, 0x0e, 0x49, 0x03, 0x7f, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd4, +0x3e, 0x48, 0x53, 0x49, 0x7f, 0x60, 0xd4, 0x3e, 0x46, 0x53, 0x47, 0x3e, +0x46, 0x53, 0x46, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x46, 0x53, 0x47, +0x3e, 0x46, 0x7f, 0x51, 0x49, 0x60, 0xd5, 0x51, 0x47, 0x3f, 0x48, 0x51, +0x46, 0x3f, 0x48, 0x7f, 0x60, 0xd4, 0x3e, 0x48, 0x53, 0x49, 0x3e, 0x48, +0x53, 0x48, 0x7f, 0x51, 0x48, 0x01, 0x8d, 0x53, 0x46, 0x51, 0x49, 0x09, +0x00, 0x7f, 0x06, 0x48, 0x8d, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd4, +0x3e, 0x48, 0x53, 0x47, 0x3e, 0x48, 0x16, 0x48, 0x02, 0x53, 0x46, 0x7f, +0x53, 0x46, 0x51, 0x49, 0x09, 0x00, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x46, +0x52, 0x15, 0x3f, 0x46, 0x7f, 0x3e, 0x48, 0x53, 0x48, 0x51, 0x46, 0x12, +0x48, 0x51, 0x47, 0x1a, 0x49, 0x7f, 0x53, 0x48, 0x52, 0xfb, 0x09, 0x00, +0x60, 0xd4, 0x3e, 0x48, 0x7f, 0x60, 0xd4, 0x3e, 0x48, 0x54, 0x00, 0x3e, +0x48, 0x54, 0x01, 0x7f, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x46, 0x52, 0x15, +0x3f, 0x46, 0x7f, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd5, 0x52, 0x14, +0x3f, 0x48, 0x52, 0x15, 0x3f, 0x48, 0x7f, 0x71, 0x10, 0x41, 0x04, 0xfe, +0x41, 0x05, 0xfe, 0x41, 0x04, 0xfd, 0x41, 0x05, 0xfd, 0x70, 0xcf, 0x43, +0x04, 0x01, 0x43, 0x04, 0x02, 0x71, 0x01, 0x7f, 0x0e, 0x47, 0x00, 0x51, +0x47, 0x60, 0xd5, 0x51, 0x49, 0x3f, 0x46, 0x7f, 0x52, 0x00, 0x53, 0x46, +0x55, 0x47, 0x00, 0x65, 0x46, 0x6b, 0x47, 0x7f, 0x70, 0xfb, 0x6e, 0x49, +0x6e, 0x48, 0x51, 0x47, 0x60, 0xd5, 0x51, 0x49, 0x3f, 0x46, 0x51, 0x48, +0x3f, 0x46, 0x7f, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd5, 0x50, 0x00, +0x3f, 0x48, 0x7f, 0x53, 0x46, 0x55, 0x47, 0x00, 0x65, 0x46, 0x6b, 0x47, +0x51, 0x46, 0x7f, 0x3e, 0x48, 0x12, 0x46, 0x54, 0x02, 0x51, 0x49, 0x1a, +0x47, 0x54, 0x01, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x44, 0x53, 0x45, +0x3e, 0x44, 0x53, 0x44, 0x7f, 0x3e, 0x48, 0x12, 0x46, 0x54, 0x04, 0x51, +0x49, 0x1a, 0x47, 0x54, 0x03, 0x7f, 0x60, 0xd4, 0x3e, 0x46, 0x53, 0x45, +0x3e, 0x46, 0x16, 0x46, 0x02, 0x7f, 0x71, 0x10, 0x41, 0x00, 0xf7, 0x41, +0x01, 0xf7, 0x70, 0xcf, 0x7f, 0x00, 0x2a, 0x00, 0x16, 0x00, 0x53, 0x00, +0x28, 0x00, 0x83, 0x00, 0x0a, 0x00, 0x91, 0x00, 0x04, 0x00, 0x95, 0x04, +0x08, 0x08, 0x08, 0x08, 0x00, 0x99, 0x00, 0x04, 0x00, 0x9d, 0x02, 0x17, +0x1e, 0x00, 0x9f, 0x00, 0x08, 0x00, 0xa7, 0x07, 0x03, 0x01, 0x01, 0x00, +0x00, 0x01, 0x02, 0x00, 0xae, 0x00, 0x06, 0xff, 0x00, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/cypress_touchkey_236/cypress-touchkey-236.c b/drivers/input/keyboard/cypress_touchkey_236/cypress-touchkey-236.c new file mode 100644 index 00000000000..7afcf04fd20 --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/cypress-touchkey-236.c @@ -0,0 +1,1265 @@ +/* + * cypress_touchkey.c - Platform data for cypress touchkey driver + * + * Copyright (C) 2011 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#define SEC_TOUCHKEY_DEBUG +/* #define SEC_TOUCHKEY_VERBOSE_DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cypress_tkey_fw.h" +#include +#include +#include +#include +#include + +#define CYPRESS_GEN 0X00 +#define CYPRESS_FW_VER 0X01 +#define CYPRESS_MODULE_VER 0X02 +#define CYPRESS_2ND_HOST 0X03 +#define CYPRESS_THRESHOLD 0X04 +#define CYPRESS_AUTO_CAL_FLG 0X05 + +#define CYPRESS_IDAC_MENU 0X07 +#define CYPRESS_IDAC_BACK 0X06 +#define CYPRESS_IDAC_HOME 0X08 + +#define CYPRESS_DIFF_MENU 0x0C +#define CYPRESS_DIFF_BACK 0x0A +#define CYPRESS_DIFF_HOME 0x0E + +#define CYPRESS_RAW_DATA_MENU 0x10 +#define CYPRESS_RAW_DATA_BACK 0x0E +#define CYPRESS_RAW_DATA_HOME 0x12 +#define CYPRESS_RAW_DATA_BACK_GOGH 0x14 + +#define CYPRESS_LED_ON 0X10 +#define CYPRESS_LED_OFF 0X20 +#define CYPRESS_DATA_UPDATE 0X40 +#define CYPRESS_AUTO_CAL 0X50 +#define CYPRESS_LED_CONTROL_ON 0X60 +#define CYPRESS_LED_CONTROL_OFF 0X70 +#define CYPRESS_SLEEP 0X80 +static int vol_mv_level = 33; +extern int system_rev; + + +#define TOUCHKEY_BACKLIGHT "button-backlight" + + +/* bit masks*/ +#define PRESS_BIT_MASK 0X08 +#define KEYCODE_BIT_MASK 0X07 + +#define TOUCHKEY_LOG(k, v) dev_notice(&info->client->dev, "key[%d] %d\n", k, v); +#define FUNC_CALLED dev_notice(&info->client->dev, "%s: called.\n", __func__); + +#define NUM_OF_RETRY_UPDATE 3 +#define NUM_OF_KEY 4 + +struct cypress_touchkey_info { + struct i2c_client *client; + struct cypress_touchkey_platform_data *pdata; + struct input_dev *input_dev; + struct early_suspend early_suspend; + char phys[32]; + unsigned char keycode[NUM_OF_KEY]; + u8 sensitivity[NUM_OF_KEY]; + int irq; + u8 fw_ver; + void (*power_onoff)(int); + int touchkey_update_status; + struct led_classdev leds; + enum led_brightness brightness; + struct mutex touchkey_led_mutex; + struct workqueue_struct *led_wq; + struct work_struct led_work; + bool is_powering_on; + +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void cypress_touchkey_early_suspend(struct early_suspend *h); +static void cypress_touchkey_late_resume(struct early_suspend *h); +#endif + +static int touchkey_led_status; +static int touchled_cmd_reversed; + +static void cypress_touchkey_led_work(struct work_struct *work) +{ + struct cypress_touchkey_info *info = + container_of(work, struct cypress_touchkey_info, led_work); + u8 buf; + int ret; + + if (info->brightness == LED_OFF) + buf = CYPRESS_LED_OFF; + else + buf = CYPRESS_LED_ON; + + mutex_lock(&info->touchkey_led_mutex); + + ret = i2c_smbus_write_byte_data(info->client, CYPRESS_GEN, buf); + if (ret < 0) + touchled_cmd_reversed = 1; + + touchkey_led_status = buf; + + mutex_unlock(&info->touchkey_led_mutex); +} + +static void cypress_touchkey_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + /* Must not sleep, use a workqueue if needed */ + struct cypress_touchkey_info *info = + container_of(led_cdev, struct cypress_touchkey_info, leds); + + info->brightness = brightness; + + queue_work(info->led_wq, &info->led_work); +} + +static void change_touch_key_led_voltage(int vol_mv) +{ + struct regulator *tled_regulator; + int ret; + vol_mv_level = vol_mv; + + tled_regulator = regulator_get(NULL, "8921_l10"); + if (IS_ERR(tled_regulator)) { + pr_err("%s: failed to get resource %s\n", __func__, + "touch_led"); + return; + } + ret = regulator_set_voltage(tled_regulator, + vol_mv * 100000, vol_mv * 100000); + if (ret) + printk(KERN_ERR"error setting voltage\n"); + regulator_put(tled_regulator); +} + +static ssize_t brightness_control(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int data; + + if (sscanf(buf, "%d\n", &data) == 1) { + printk(KERN_ERR"[TouchKey] touch_led_brightness: %d\n", data); + change_touch_key_led_voltage(data); + } else { + printk(KERN_ERR "[TouchKey] touch_led_brightness Error\n"); + } + return size; +} + +static ssize_t brightness_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + + count = sprintf(buf, "%d\n", vol_mv_level); + + printk(KERN_DEBUG "[TouchKey] Touch LED voltage = %d\n", vol_mv_level); + return count; +} + +static irqreturn_t cypress_touchkey_interrupt(int irq, void *dev_id) +{ + struct cypress_touchkey_info *info = dev_id; + u8 buf[10] = {0,}; + int code; + int press; + int ret; + + ret = gpio_get_value(info->pdata->gpio_int); + if (ret) { + dev_err(&info->client->dev, "not real interrupt (%d).\n", ret); + goto out; + } + + if (info->is_powering_on) { + dev_err(&info->client->dev, "%s: ignoring spurious boot " + "interrupt\n", __func__); + return IRQ_HANDLED; + } + +#if defined(SEC_TOUCHKEY_VERBOSE_DEBUG) + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_GEN, ARRAY_SIZE(buf), buf); + if (ret != ARRAY_SIZE(buf)) { + dev_err(&info->client->dev, "interrupt failed with %d.\n", ret); + goto out; + } + print_hex_dump(KERN_DEBUG, "cypress_touchkey: ", + DUMP_PREFIX_OFFSET, 32, 1, buf, 10, false); +#else + buf[0] = i2c_smbus_read_byte_data(info->client, CYPRESS_GEN); + if (buf[0] < 0) { + dev_err(&info->client->dev, "interrupt failed with %d.\n", ret); + goto out; + } +#endif + press = !(buf[0] & PRESS_BIT_MASK); + code = (int)(buf[0] & KEYCODE_BIT_MASK) - 1; + dev_dbg(&info->client->dev, + "[TouchKey]press=%d, code=%d\n", press, code); + + if (code < 0) { + dev_err(&info->client->dev, + "not profer interrupt 0x%2X.\n", buf[0]); + goto out; + } + +#if defined(SEC_TOUCHKEY_DEBUG) + TOUCHKEY_LOG(info->keycode[code], press); +#endif + + if (touch_is_pressed && press) { + printk(KERN_ERR "[TouchKey] don't send event because touch is pressed.\n"); + printk(KERN_ERR "[TouchKey] touch_pressed = %d\n", + touch_is_pressed); + } else { + input_report_key(info->input_dev, info->keycode[code], press); + input_sync(info->input_dev); + } + +out: + return IRQ_HANDLED; +} + +static void cypress_touchkey_con_hw(struct cypress_touchkey_info *dev_info, + bool flag) +{ + struct cypress_touchkey_info *info = dev_info; + + gpio_set_value(info->pdata->gpio_led_en, flag ? 1 : 0); + +#if defined(SEC_TOUCHKEY_DEBUG) + dev_notice(&info->client->dev, + "%s : called with flag %d.\n", __func__, flag); +#endif +} + + +static int cypress_touchkey_auto_cal(struct cypress_touchkey_info *dev_info) +{ + struct cypress_touchkey_info *info = dev_info; + u8 data[6] = { 0, }; + int count = 0; + int ret = 0; + unsigned short retry = 0; + while (retry < 3) { + + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_GEN, 4, data); + if (ret < 0) { + printk(KERN_ERR "[TouchKey]i2c read fail.\n"); + return ret; + } + data[0] = 0x50; + data[3] = 0x01; + + count = i2c_smbus_write_i2c_block_data(info->client, + CYPRESS_GEN, 4, data); + printk(KERN_DEBUG + "[TouchKey] data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", + data[0], data[1], data[2], data[3]); + + msleep(50); + + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_GEN, 6, data); + + if ((data[5] & 0x80)) { + printk(KERN_DEBUG "[Touchkey] autocal Enabled\n"); + break; + } else { + printk(KERN_DEBUG "[Touchkey] autocal disabled, retry %d\n", + retry); + } + retry = retry + 1; + } + + if (retry == 3) + printk(KERN_DEBUG "[Touchkey] autocal failed\n"); + + return count; +} + +static int cypress_touchkey_led_on(struct cypress_touchkey_info *dev_info) +{ + struct cypress_touchkey_info *info = dev_info; + u8 buf = CYPRESS_LED_ON; + + int ret; + ret = i2c_smbus_write_byte_data(info->client, CYPRESS_GEN, buf); + if (ret < 0) { + dev_err(&info->client->dev, + "[Touchkey] i2c write error [%d]\n", ret); + } + return ret; +} + +static int cypress_touchkey_led_off(struct cypress_touchkey_info *dev_info) +{ + struct cypress_touchkey_info *info = dev_info; + u8 buf = CYPRESS_LED_OFF; + + int ret; + ret = i2c_smbus_write_byte_data(info->client, CYPRESS_GEN, buf); + if (ret < 0) { + dev_err(&info->client->dev, + "[Touchkey] i2c write error [%d]\n", ret); + } + return ret; +} + +static ssize_t touch_version_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + u8 data; + int count; + + data = i2c_smbus_read_byte_data(info->client, CYPRESS_FW_VER); + count = snprintf(buf, 20, "0x%02x\n", data); + + dev_dbg(&info->client->dev, + "[TouchKey] %s : FW Ver 0x%02x\n", __func__, data); + + return count; +} + +static ssize_t touch_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + + count = snprintf(buf, 20, "0x%02x\n", BIN_FW_VERSION); + return count; +} + +static ssize_t touchkey_firm_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + int count = 0; + char buff[16] = {0}; + dev_dbg(&info->client->dev, "[TouchKey] touchkey_update_status: %d\n", + info->touchkey_update_status); + if (info->touchkey_update_status == 0) + count = snprintf(buff, sizeof(buff), "PASS\n"); + else if (info->touchkey_update_status == 1) + count = snprintf(buff, sizeof(buff), "Downloading\n"); + else if (info->touchkey_update_status == -1) + count = snprintf(buff, sizeof(buff), "Fail\n"); + return count; +} + +static ssize_t touch_update_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + int count = 0; + char buff[16] = {0}; + + dev_dbg(&info->client->dev, "[TouchKey] touchkey_update_read: %d\n", + info->touchkey_update_status); + if (info->touchkey_update_status == 0) + count = snprintf(buff, sizeof(buff), "PASS\n"); + else if (info->touchkey_update_status == 1) + count = snprintf(buff, sizeof(buff), "Downloading\n"); + else if (info->touchkey_update_status == -1) + count = snprintf(buff, sizeof(buff), "Fail\n"); + return count; +} + + +static ssize_t touch_update_write(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + int count = 0; + int retry = NUM_OF_RETRY_UPDATE; + char buff[16] = {0}; + u8 data; + + info->touchkey_update_status = 1; + dev_err(dev, "[TOUCHKEY] touch_update_write!\n"); + + disable_irq(info->irq); + + while (retry--) { + if (ISSP_main() == 0) { + dev_err(&info->client->dev, + "[TOUCHKEY] Update success!\n"); + msleep(50); + cypress_touchkey_auto_cal(info); + info->touchkey_update_status = 0; + count = 1; + enable_irq(info->irq); + break; + } + dev_err(&info->client->dev, + "[TOUCHKEY] Touchkey_update failed... retry...\n"); + } + + if (retry <= 0) { + if (info->pdata->gpio_led_en) + cypress_touchkey_con_hw(info, false); + msleep(300); + count = 0; + dev_err(&info->client->dev, "[TOUCHKEY]Touchkey_update fail\n"); + info->touchkey_update_status = -1; + return count; + } + + msleep(500); + + data = i2c_smbus_read_byte_data(info->client, CYPRESS_FW_VER); + count = snprintf(buff, sizeof(buff), "0x%02x\n", data); + dev_err(&info->client->dev, + "[TouchKey] %s : FW Ver 0x%02x\n", __func__, data); + + return count; +} + +static ssize_t touch_led_control(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + int data; + + dev_dbg(&info->client->dev, "called %s\n", __func__); + data = kstrtoul(buf, (int)NULL, 0); + if (data == 1) { + if (data) + cypress_touchkey_led_on(info); + else + cypress_touchkey_led_off(info); +#if defined(SEC_TOUCHKEY_DEBUG) + dev_dbg(&info->client->dev, + "[TouchKey] touch_led_control : %d\n", data); +#endif + } else + dev_dbg(&info->client->dev, "[TouchKey] touch_led_control Error\n"); + + return size; +} + +static ssize_t touch_sensitivity_control(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + int ret; + + ret = i2c_smbus_write_byte_data(info->client, + CYPRESS_GEN, CYPRESS_DATA_UPDATE); + if (ret < 0) { + dev_err(&info->client->dev, + "[Touchkey] fail to CYPRESS_DATA_UPDATE.\n"); + return ret; + } + msleep(150); + return size; +} + +static ssize_t touchkey_menu_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u8 menu_sensitivity; + u8 data[2] = {0,}; + int ret; + bool touchkey; + + touchkey = info->pdata->touchkey_order; + if (machine_is_GOGH()) { + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_DIFF_BACK, ARRAY_SIZE(data), data); + } else { + ret = i2c_smbus_read_i2c_block_data(info->client, + touchkey ? CYPRESS_DIFF_BACK : CYPRESS_DIFF_MENU, + ARRAY_SIZE(data), data); + } + if (ret != ARRAY_SIZE(data)) { + dev_err(&info->client->dev, + "[TouchKey] fail to read menu sensitivity.\n"); + return ret; + } + menu_sensitivity = ((0x00FF & data[0])<<8) | data[1]; + + dev_dbg(&info->client->dev, "called %s , data : %d %d\n", + __func__, data[0], data[1]); + return snprintf(buf, 20, "%d\n", menu_sensitivity); + +} + +static ssize_t touchkey_back_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u8 back_sensitivity; + u8 data[2] = {0,}; + int ret; + bool touchkey; + + touchkey = info->pdata->touchkey_order; + if (machine_is_GOGH()) { + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_DIFF_HOME, ARRAY_SIZE(data), data); + + } else { + ret = i2c_smbus_read_i2c_block_data(info->client, + touchkey ? CYPRESS_DIFF_MENU : CYPRESS_DIFF_BACK, + ARRAY_SIZE(data), data); + } + if (ret != ARRAY_SIZE(data)) { + dev_err(&info->client->dev, + "[TouchKey] fail to read back sensitivity.\n"); + return ret; + } + + back_sensitivity = ((0x00FF & data[0])<<8) | data[1]; + + dev_dbg(&info->client->dev, "called %s , data : %d %d\n", + __func__, data[0], data[1]); + return snprintf(buf, 20, "%d\n", back_sensitivity); + +} + +static ssize_t touchkey_home_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u8 home_sensitivity; + u8 data[2] = {0,}; + int ret; + + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_DIFF_MENU, ARRAY_SIZE(data), data); + if (ret != ARRAY_SIZE(data)) { + dev_err(&info->client->dev, + "[TouchKey] fail to read home sensitivity.\n"); + return ret; + } + + home_sensitivity = ((0x00FF & data[0])<<8) | data[1]; + + dev_dbg(&info->client->dev, "called %s , data : %d %d\n", + __func__, data[0], data[1]); + return snprintf(buf, 20, "%d\n", home_sensitivity); + +} + +static ssize_t touchkey_raw_data0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u16 raw_data0; + u8 data[2] = {0,}; + int ret; + bool touchkey; + + touchkey = info->pdata->touchkey_order; + if (machine_is_GOGH()) { + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_RAW_DATA_MENU, ARRAY_SIZE(data), data); + + } else { + ret = i2c_smbus_read_i2c_block_data(info->client, + touchkey ? CYPRESS_RAW_DATA_BACK : CYPRESS_RAW_DATA_MENU, + ARRAY_SIZE(data), data); + } + if (ret != ARRAY_SIZE(data)) { + dev_err(&info->client->dev, + "[TouchKey] fail to read MENU raw data.\n"); + return ret; + } + + raw_data0 = ((0x00FF & data[0])<<8) | data[1]; + + dev_dbg(&info->client->dev, "called %s , data : %d %d\n", + __func__, data[0], data[1]); + return snprintf(buf, 20, "%d\n", raw_data0); + +} + +static ssize_t touchkey_raw_data1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u16 raw_data1; + u8 data[2] = {0,}; + int ret; + bool touchkey; + + touchkey = info->pdata->touchkey_order; + if (machine_is_GOGH()) { + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_RAW_DATA_BACK_GOGH, ARRAY_SIZE(data), data); + } else { + ret = i2c_smbus_read_i2c_block_data(info->client, + touchkey ? CYPRESS_RAW_DATA_MENU : CYPRESS_RAW_DATA_BACK, + ARRAY_SIZE(data), data); + } + if (ret != ARRAY_SIZE(data)) { + dev_err(&info->client->dev, + "[TouchKey] fail to read HOME raw data.\n"); + return ret; + } + + raw_data1 = ((0x00FF & data[0])<<8) | data[1]; + + dev_dbg(&info->client->dev, "called %s , data : %d %d\n", + __func__, data[0], data[1]); + return snprintf(buf, 20, "%d\n", raw_data1); + +} + +static ssize_t touchkey_raw_data2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u16 raw_data1; + u8 data[2] = {0,}; + int ret; + + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_RAW_DATA_HOME, ARRAY_SIZE(data), data); + + if (ret != ARRAY_SIZE(data)) { + dev_err(&info->client->dev, + "[TouchKey] fail to read HOME raw data.\n"); + return ret; + } + + raw_data1 = ((0x00FF & data[0])<<8) | data[1]; + + dev_dbg(&info->client->dev, "called %s , data : %d %d\n", + __func__, data[0], data[1]); + return snprintf(buf, 20, "%d\n", raw_data1); + +} + + +static ssize_t touchkey_idac0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u8 idac0; + u8 data = 0; + bool touchkey; + + touchkey = info->pdata->touchkey_order; + if (machine_is_GOGH()) { + data = i2c_smbus_read_byte_data(info->client, + CYPRESS_IDAC_BACK); + } else { + data = i2c_smbus_read_byte_data(info->client, + touchkey ? CYPRESS_IDAC_BACK : CYPRESS_IDAC_MENU); + } + dev_dbg(&info->client->dev, "called %s , data : %d\n", __func__, data); + idac0 = data; + return snprintf(buf, 20, "%d\n", idac0); + +} + +static ssize_t touchkey_idac1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u8 idac1; + u8 data = 0; + bool touchkey; + + touchkey = info->pdata->touchkey_order; + if (machine_is_GOGH()) { + data = i2c_smbus_read_byte_data(info->client, + CYPRESS_IDAC_MENU); + } else { + data = i2c_smbus_read_byte_data(info->client, + touchkey ? CYPRESS_IDAC_MENU : CYPRESS_IDAC_BACK); + } + dev_dbg(&info->client->dev, "called %s , data : %d\n", __func__, data); + idac1 = data; + return snprintf(buf, 20, "%d\n", idac1); + +} + +static ssize_t touchkey_idac2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u8 idac1; + u8 data = 0; + + data = i2c_smbus_read_byte_data(info->client, CYPRESS_IDAC_HOME); + + dev_dbg(&info->client->dev, "called %s , data : %d\n", __func__, data); + idac1 = data; + return snprintf(buf, 20, "%d\n", idac1); + +} + +static ssize_t touchkey_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + static u8 touchkey_threshold; + u8 data = 0; + + data = i2c_smbus_read_byte_data(info->client, CYPRESS_THRESHOLD); + + dev_dbg(&info->client->dev, "called %s , data : %d\n", __func__, data); + touchkey_threshold = data; + return snprintf(buf, 20, "%d\n", touchkey_threshold); +} + +static ssize_t touch_autocal_testmode(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + int count = 0; + int on_off; + if (sscanf(buf, "%d\n", &on_off) == 1) { + printk(KERN_ERR "[TouchKey] Test Mode : %d\n", on_off); + if (on_off == 1) { + count = i2c_smbus_write_byte_data(info->client, + CYPRESS_GEN, CYPRESS_DATA_UPDATE); + } + } else { + if (info->pdata->gpio_led_en) { + cypress_touchkey_con_hw(info, false); + msleep(50); + cypress_touchkey_con_hw(info, true); + msleep(50); + } + cypress_touchkey_auto_cal(info); + } + + return count; +} + +static ssize_t autocalibration_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + int data; + + sscanf(buf, "%d\n", &data); + + if (data == 1) + cypress_touchkey_auto_cal(info); + return 0; +} + +static ssize_t autocalibration_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[6]; + int ret; + struct cypress_touchkey_info *info = dev_get_drvdata(dev); + + printk(KERN_DEBUG "[Touchkey] %s\n", __func__); + + ret = i2c_smbus_read_i2c_block_data(info->client, + CYPRESS_GEN, 6, data); + if ((data[5] & 0x80)) + return sprintf(buf, "Enabled\n"); + else + return sprintf(buf, "Disabled\n"); +} + +static DEVICE_ATTR(touchkey_firm_update_status, + S_IRUGO | S_IWUSR | S_IWGRP, touchkey_firm_status_show, NULL); +static DEVICE_ATTR(touchkey_firm_version_panel, S_IRUGO, + touch_version_read, NULL); +static DEVICE_ATTR(touchkey_firm_version_phone, S_IRUGO, + touch_version_show, NULL); +static DEVICE_ATTR(touchkey_firm_update, S_IRUGO | S_IWUSR | S_IWGRP, + touch_update_read, touch_update_write); +static DEVICE_ATTR(touchkey_brightness, S_IRUGO, + NULL, touch_led_control); +static DEVICE_ATTR(touch_sensitivity, S_IRUGO | S_IWUSR | S_IWGRP, + NULL, touch_sensitivity_control); +static DEVICE_ATTR(touchkey_menu, S_IRUGO, touchkey_menu_show, NULL); +static DEVICE_ATTR(touchkey_back, S_IRUGO, touchkey_back_show, NULL); +static DEVICE_ATTR(touchkey_home, S_IRUGO, touchkey_home_show, NULL); +static DEVICE_ATTR(touchkey_raw_data0, S_IRUGO, touchkey_raw_data0_show, NULL); +static DEVICE_ATTR(touchkey_raw_data1, S_IRUGO, touchkey_raw_data1_show, NULL); +static DEVICE_ATTR(touchkey_raw_data2, S_IRUGO, touchkey_raw_data2_show, NULL); +static DEVICE_ATTR(touchkey_idac0, S_IRUGO, touchkey_idac0_show, NULL); +static DEVICE_ATTR(touchkey_idac1, S_IRUGO, touchkey_idac1_show, NULL); +static DEVICE_ATTR(touchkey_idac2, S_IRUGO, touchkey_idac2_show, NULL); +static DEVICE_ATTR(touchkey_threshold, S_IRUGO, touchkey_threshold_show, NULL); +static DEVICE_ATTR(touchkey_autocal_start, S_IRUGO | S_IWUSR | S_IWGRP, + NULL, touch_autocal_testmode); +static DEVICE_ATTR(autocal_enable, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + autocalibration_enable); +static DEVICE_ATTR(autocal_stat, S_IRUGO | S_IWUSR | S_IWGRP, + autocalibration_status, NULL); +static DEVICE_ATTR(touchkey_brightness_level, S_IRUGO | S_IWUSR | S_IWGRP, + brightness_level_show, brightness_control); + + +static int __devinit cypress_touchkey_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct cypress_touchkey_platform_data *pdata = + client->dev.platform_data; + struct cypress_touchkey_info *info; + struct input_dev *input_dev; + int ret = 0; + int i; +#if defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_DCM) \ + || defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_K2_KDI) + int retry = NUM_OF_RETRY_UPDATE; +#endif + int ic_fw_ver; + + struct device *sec_touchkey; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -EIO; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, "fail to memory allocation.\n"); + goto err_mem_alloc; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev, "fail to allocate input device.\n"); + goto err_input_dev_alloc; + } + + info->client = client; + info->input_dev = input_dev; + info->pdata = client->dev.platform_data; + info->irq = client->irq; + info->power_onoff = pdata->power_onoff; + info->touchkey_update_status = 0; + memcpy(info->keycode, pdata->touchkey_keycode, + sizeof(pdata->touchkey_keycode)); + snprintf(info->phys, sizeof(info->phys), + "%s/input0", dev_name(&client->dev)); + input_dev->name = "sec_touchkey"; + input_dev->phys = info->phys; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + + info->is_powering_on = true; + + info->power_onoff(1); + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_KEY, input_dev->evbit); + set_bit(EV_LED, input_dev->evbit); + set_bit(LED_MISC, input_dev->ledbit); + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) + set_bit(info->keycode[i], input_dev->keybit); + + input_set_drvdata(input_dev, info); + mutex_init(&info->touchkey_led_mutex); + + ret = input_register_device(input_dev); + if (ret) { + dev_err(&client->dev, "[TOUCHKEY] failed to register input dev (%d).\n", + ret); + goto err_reg_input_dev; + } + + i2c_set_clientdata(client, info); + + if (info->pdata->gpio_led_en) { + ret = gpio_request(info->pdata->gpio_led_en, + "gpio_touchkey_led"); + if (ret < 0) { + dev_err(&client->dev, + "gpio_touchkey_led gpio_request is failed\n"); + goto err_gpio_request; + } + gpio_tlmm_config(GPIO_CFG(info->pdata->gpio_led_en, 0, + GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + + cypress_touchkey_con_hw(info, true); + } + + ret = request_threaded_irq(client->irq, NULL, + cypress_touchkey_interrupt, + IRQF_TRIGGER_FALLING, client->dev.driver->name, info); + if (ret < 0) { + dev_err(&client->dev, "Failed to request IRQ %d (err: %d).\n", + client->irq, ret); + goto err_req_irq; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + info->early_suspend.suspend = cypress_touchkey_early_suspend; + info->early_suspend.resume = cypress_touchkey_late_resume; + register_early_suspend(&info->early_suspend); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + + info->led_wq = create_singlethread_workqueue("cypress_touchkey"); + INIT_WORK(&info->led_work, cypress_touchkey_led_work); + + info->leds.name = TOUCHKEY_BACKLIGHT; + info->leds.brightness = LED_FULL; + info->leds.max_brightness = LED_FULL; + info->leds.brightness_set = cypress_touchkey_brightness_set; + + ret = led_classdev_register(&client->dev, &info->leds); + if (ret) + goto err_req_irq; + + msleep(20); + ic_fw_ver = i2c_smbus_read_byte_data(client, CYPRESS_FW_VER); + dev_err(&client->dev, "Touchkey FW Version: 0x%02x\n", ic_fw_ver); + +#if defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_DCM) \ + || defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_K2_KDI) + dev_err(&client->dev, "Touchkey FW Version: 0x%02x, system_rev: %x\n", + ic_fw_ver, system_rev); + if (0 /* ic_fw_ver < BIN_FW_VERSION */) { + dev_err(&client->dev, "[TOUCHKEY] touchkey_update Start!!\n"); + disable_irq(client->irq); + + while (retry--) { + if (ISSP_main() == 0) { + dev_err(&client->dev, "[TOUCHKEY] Update success!\n"); + enable_irq(client->irq); + break; + } + dev_err(&client->dev, + "[TOUCHKEY] Touchkey_update failed... retry...\n"); + } + + if (retry <= 0) { + if (info->pdata->gpio_led_en) + cypress_touchkey_con_hw(info, false); + msleep(300); + dev_err(&client->dev, "[TOUCHKEY]Touchkey_update fail\n"); + } + + msleep(500); + + ic_fw_ver = i2c_smbus_read_byte_data(info->client, + CYPRESS_FW_VER); + dev_err(&client->dev, + "[TouchKey] %s : FW Ver 0x%02x\n", __func__, ic_fw_ver); + } else { + dev_err(&client->dev, "[TouchKey] FW update does not need!\n"); + } +#endif + cypress_touchkey_auto_cal(info); + sec_touchkey = device_create(sec_class, NULL, 0, NULL, "sec_touchkey"); + if (IS_ERR(sec_touchkey)) { + pr_err("Failed to create device(sec_touchkey)!\n"); + goto err_sysfs; + } + dev_set_drvdata(sec_touchkey, info); + + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_firm_update_status) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_firm_update.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_firm_update) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_firm_update.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_firm_version_panel) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_firm_version_panel.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_firm_version_phone) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_firm_version_phone.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_brightness) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_brightness.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touch_sensitivity) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touch_sensitivity.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_menu) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_menu.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_back) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_back.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_home) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_home.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_raw_data0) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_raw_data0.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_raw_data1) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_raw_data1.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_raw_data2) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_raw_data2.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, &dev_attr_touchkey_idac0) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_idac0.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, &dev_attr_touchkey_idac1) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_idac1.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, &dev_attr_touchkey_idac2) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_idac2.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_threshold) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_threshold.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_autocal_start) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_autocal_start.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_autocal_enable) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_autocal_enable.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_autocal_stat) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_autocal_stat.attr.name); + goto err_sysfs; + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_brightness_level) < 0) { + printk(KERN_ERR "Failed to create device file(%s)!\n", + dev_attr_touchkey_brightness_level.attr.name); + goto err_sysfs; + } + info->is_powering_on = false; + return 0; + +err_req_irq: +err_gpio_request: + input_unregister_device(input_dev); +err_reg_input_dev: + input_free_device(input_dev); + input_dev = NULL; + mutex_destroy(&info->touchkey_led_mutex); +err_input_dev_alloc: + kfree(info); +err_sysfs: + return -ENXIO; +err_mem_alloc: + return ret; + +} + +static int __devexit cypress_touchkey_remove(struct i2c_client *client) +{ + struct cypress_touchkey_info *info = i2c_get_clientdata(client); + if (info->irq >= 0) + free_irq(info->irq, info); + mutex_destroy(&info->touchkey_led_mutex); + led_classdev_unregister(&info->leds); + input_unregister_device(info->input_dev); + input_free_device(info->input_dev); + kfree(info); + return 0; +} + +#if defined(CONFIG_PM) || defined(CONFIG_HAS_EARLYSUSPEND) +static int cypress_touchkey_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cypress_touchkey_info *info = i2c_get_clientdata(client); + int ret = 0; + + info->is_powering_on = true; + disable_irq(info->irq); + if (info->pdata->gpio_led_en) + cypress_touchkey_con_hw(info, false); + info->power_onoff(0); + return ret; +} + +static int cypress_touchkey_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cypress_touchkey_info *info = i2c_get_clientdata(client); + int ret = 0; + info->power_onoff(1); + if (info->pdata->gpio_led_en) + cypress_touchkey_con_hw(info, true); + msleep(100); + + cypress_touchkey_auto_cal(info); + + if (touchled_cmd_reversed) { + touchled_cmd_reversed = 0; + i2c_smbus_write_byte_data(info->client, + CYPRESS_GEN, touchkey_led_status); + printk(KERN_DEBUG "LED returned on\n"); + } + + + enable_irq(info->irq); + + + info->is_powering_on = false; + return ret; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void cypress_touchkey_early_suspend(struct early_suspend *h) +{ + struct cypress_touchkey_info *info; + info = container_of(h, struct cypress_touchkey_info, early_suspend); + cypress_touchkey_suspend(&info->client->dev); +} + +static void cypress_touchkey_late_resume(struct early_suspend *h) +{ + struct cypress_touchkey_info *info; + info = container_of(h, struct cypress_touchkey_info, early_suspend); + cypress_touchkey_resume(&info->client->dev); +} +#endif + +static const struct i2c_device_id cypress_touchkey_id[] = { + {"cypress_touchkey", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cypress_touchkey_id); + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static const struct dev_pm_ops cypress_touchkey_pm_ops = { + .suspend = cypress_touchkey_suspend, + .resume = cypress_touchkey_resume, +}; +#endif + +struct i2c_driver cypress_touchkey_driver = { + .probe = cypress_touchkey_probe, + .remove = cypress_touchkey_remove, + .driver = { + .name = "cypress_touchkey", +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) + .pm = &cypress_touchkey_pm_ops, +#endif + }, + .id_table = cypress_touchkey_id, +}; + +static int __init cypress_touchkey_init(void) +{ + int ret = 0; + + ret = i2c_add_driver(&cypress_touchkey_driver); + if (ret) { + pr_err("[TouchKey] cypress touch keypad registration failed. ret= %d\n", + ret); + } + + return ret; +} + +static void __exit cypress_touchkey_exit(void) +{ + i2c_del_driver(&cypress_touchkey_driver); +} + +late_initcall(cypress_touchkey_init); +module_exit(cypress_touchkey_exit); + +MODULE_DESCRIPTION("Touchkey driver for Cypress touchkey controller "); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/cypress_touchkey_236/cypress_tkey_fw.h b/drivers/input/keyboard/cypress_touchkey_236/cypress_tkey_fw.h new file mode 100644 index 00000000000..de5f40aaab4 --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/cypress_tkey_fw.h @@ -0,0 +1,43 @@ +/* + * Cypress Touchkey firmware list + * + * Copyright (C) 2011 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#if defined(CONFIG_MACH_JAGUAR) +#define BIN_FW_VERSION 0x06 +#ifdef _CYPRESS_TKEY_FW_H +#include "jaguar_tkey_fw.h" +#endif + +#elif defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_VZW) \ + || defined(CONFIG_MACH_M2_SPR) || defined(CONFIG_MACH_M2_DCM) \ + || defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_K2_KDI) +#define BIN_FW_VERSION 0x06 +#ifdef _CYPRESS_TKEY_FW_H +#include "d2_tkey_fw.h" +#endif + +#elif defined(CONFIG_MACH_GOGH) +#define BIN_FW_VERSION 0x0E +#ifdef _CYPRESS_TKEY_FW_H +#include "gogh_tkey_fw.h" +#endif + +#elif defined(CONFIG_MACH_APEXQ) +#define BIN_FW_VERSION 0x06 +#ifdef _CYPRESS_TKEY_FW_H +#include "apexq_tkey_fw.h" +#endif + +#else +#define BIN_FW_VERSION 0x00 +#ifdef _CYPRESS_TKEY_FW_H +unsigned char firmware_data[8192]; +#endif +#endif diff --git a/drivers/input/keyboard/cypress_touchkey_236/d2_tkey_fw.h b/drivers/input/keyboard/cypress_touchkey_236/d2_tkey_fw.h new file mode 100644 index 00000000000..cf416f7b444 --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/d2_tkey_fw.h @@ -0,0 +1,1047 @@ +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +/* fw version 0x06 */ + +unsigned char firmware_data[8192] = { +0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7d, 0x00, 0x68, 0x7e, +0x7e, 0x30, 0x30, 0x30, 0x7d, 0x04, 0xce, 0x7e, +0x7e, 0x30, 0x30, 0x30, 0x7d, 0x06, 0x1b, 0x7e, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x40, 0x71, 0x10, 0x62, 0xe3, 0x06, 0x70, 0xef, +0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, +0x38, 0x5d, 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, +0xfa, 0x01, 0x40, 0x4f, 0x5b, 0x01, 0x03, 0x53, +0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, 0x40, +0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, +0xef, 0x18, 0x60, 0xd5, 0x55, 0xf8, 0x00, 0x55, +0xf9, 0x00, 0x71, 0x10, 0x62, 0xe0, 0x1a, 0x70, +0xef, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x41, 0xe1, +0xfe, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x62, 0xd1, +0x03, 0x50, 0x80, 0x4e, 0x62, 0xd3, 0x03, 0x62, +0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, 0x00, +0x71, 0xc0, 0x7c, 0x03, 0x3b, 0x62, 0xd0, 0x00, +0x50, 0x01, 0x57, 0xe2, 0x08, 0x28, 0x53, 0x58, +0x18, 0x75, 0x09, 0x00, 0x28, 0x4b, 0x51, 0x58, +0x80, 0x04, 0x75, 0x09, 0x00, 0x62, 0xe3, 0x00, +0x08, 0x28, 0x60, 0xd5, 0x74, 0xa0, 0x4b, 0x18, +0x75, 0x09, 0x00, 0x08, 0x28, 0x53, 0x58, 0x18, +0x75, 0x09, 0x00, 0x08, 0x28, 0xa0, 0x1c, 0x53, +0x57, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, +0x58, 0x47, 0x58, 0xff, 0xb0, 0x06, 0x5d, 0xd5, +0x74, 0x60, 0xd5, 0x18, 0x7a, 0x57, 0xbf, 0xeb, +0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, +0x53, 0x57, 0x50, 0x00, 0x3f, 0x58, 0x47, 0x58, +0xff, 0xb0, 0x08, 0x5d, 0xd5, 0x74, 0x60, 0xd5, +0x50, 0x00, 0x7a, 0x57, 0xbf, 0xef, 0x18, 0x8f, +0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, +0xef, 0x62, 0xe0, 0x00, 0x41, 0xfe, 0xe7, 0x43, +0xfe, 0x10, 0x71, 0x10, 0x62, 0xe0, 0x1a, 0x70, +0xef, 0x62, 0xe2, 0x00, 0x7c, 0x18, 0x88, 0x8f, +0xff, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x01, 0x99, 0x03, 0x33, 0x06, 0x66, +0x0c, 0xcc, 0x19, 0x99, 0x33, 0x33, 0x66, 0x66, +0xcc, 0xcc, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, +0x0b, 0xff, 0x18, 0x00, 0x2f, 0xff, 0x5f, 0xff, +0xbf, 0xff, 0x01, 0x66, 0x02, 0xcc, 0x05, 0x99, +0x0b, 0x32, 0x16, 0x66, 0x2c, 0xcc, 0x59, 0x98, +0xb3, 0x32, 0x01, 0x4d, 0x02, 0x9a, 0x05, 0x33, +0x0a, 0x66, 0x14, 0xcd, 0x29, 0x99, 0x53, 0x33, +0xa6, 0x66, 0x01, 0x33, 0x02, 0x66, 0x04, 0xcc, +0x09, 0x99, 0x13, 0x33, 0x26, 0x65, 0x4c, 0xcc, +0x99, 0x99, 0x01, 0x19, 0x02, 0x33, 0x04, 0x66, +0x08, 0xcc, 0x11, 0x99, 0x25, 0x26, 0x46, 0x65, +0x8c, 0xcc, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, +0x08, 0x00, 0x0f, 0xff, 0x20, 0x00, 0x3f, 0xff, +0x7f, 0xff, 0x1a, 0xf5, 0x70, 0xef, 0x62, 0x61, +0x00, 0x62, 0xfd, 0x00, 0x62, 0xcd, 0x00, 0x62, +0xce, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, +0x62, 0xa0, 0x00, 0x62, 0xa1, 0x80, 0x62, 0xa2, +0xc0, 0x62, 0xa3, 0x0c, 0x62, 0xa8, 0x00, 0x62, +0xa6, 0x00, 0x62, 0xa7, 0x00, 0x62, 0x7c, 0x33, +0x62, 0x7a, 0x00, 0x62, 0x7b, 0x00, 0x62, 0x79, +0x00, 0x62, 0x36, 0x00, 0x62, 0x37, 0x00, 0x62, +0x38, 0x00, 0x62, 0x39, 0x00, 0x62, 0x3a, 0x00, +0x62, 0x3b, 0x00, 0x62, 0x3c, 0x00, 0x62, 0x3d, +0x00, 0x62, 0x3e, 0x00, 0x62, 0x3f, 0x00, 0x62, +0x40, 0x00, 0x62, 0x41, 0x00, 0x62, 0x42, 0x00, +0x62, 0x43, 0x00, 0x62, 0x44, 0x00, 0x62, 0x45, +0x00, 0x62, 0x46, 0x00, 0x62, 0x47, 0x00, 0x62, +0x48, 0x00, 0x62, 0x49, 0x00, 0x62, 0x4a, 0x00, +0x62, 0x4b, 0x00, 0x62, 0x4c, 0x00, 0x62, 0x4d, +0x00, 0x62, 0x4e, 0x00, 0x62, 0x4f, 0x00, 0x62, +0xca, 0x20, 0x62, 0xd6, 0x44, 0x62, 0xcf, 0x00, +0x62, 0xcb, 0x00, 0x62, 0xc8, 0x00, 0x62, 0xcc, +0x00, 0x62, 0xc9, 0x00, 0x62, 0xd7, 0x00, 0x62, +0xa9, 0x00, 0x62, 0x2b, 0x00, 0x62, 0xb0, 0x00, +0x62, 0xb3, 0x02, 0x62, 0xb6, 0x00, 0x62, 0xb2, +0x00, 0x62, 0xb5, 0x00, 0x62, 0xb8, 0x00, 0x62, +0xb1, 0x00, 0x62, 0xb4, 0x00, 0x62, 0xb7, 0x00, +0x62, 0x33, 0x00, 0x62, 0x34, 0x00, 0x62, 0x35, +0x00, 0x71, 0x10, 0x62, 0x54, 0x00, 0x62, 0x55, +0x00, 0x62, 0x56, 0x00, 0x62, 0x57, 0x00, 0x62, +0x58, 0x00, 0x62, 0x59, 0x00, 0x62, 0x5a, 0x00, +0x62, 0x5b, 0x00, 0x62, 0xdc, 0x00, 0x62, 0xe2, +0x00, 0x62, 0xdd, 0x00, 0x62, 0xd8, 0x02, 0x62, +0xd9, 0x00, 0x62, 0xda, 0x00, 0x62, 0xdb, 0x00, +0x62, 0xdf, 0x00, 0x62, 0x29, 0x00, 0x62, 0x30, +0x00, 0x62, 0xbd, 0x00, 0x70, 0xef, 0x70, 0xef, +0x62, 0x00, 0x08, 0x71, 0x10, 0x62, 0x00, 0x08, +0x62, 0x01, 0x92, 0x70, 0xef, 0x62, 0x04, 0x17, +0x71, 0x10, 0x62, 0x04, 0x14, 0x62, 0x05, 0xbc, +0x70, 0xef, 0x62, 0x08, 0x00, 0x71, 0x10, 0x62, +0x08, 0x00, 0x62, 0x09, 0x28, 0x70, 0xef, 0x62, +0x0c, 0x00, 0x71, 0x10, 0x62, 0x0c, 0x00, 0x62, +0x0d, 0x00, 0x70, 0xef, 0x62, 0x10, 0x00, 0x71, +0x10, 0x62, 0x10, 0x00, 0x62, 0x11, 0x00, 0x70, +0xef, 0x62, 0x01, 0x00, 0x62, 0x05, 0x00, 0x62, +0x09, 0x00, 0x62, 0x0d, 0x00, 0x62, 0x11, 0x00, +0x70, 0xef, 0x7f, 0x55, 0x02, 0x08, 0x55, 0x03, +0x17, 0x55, 0x04, 0x00, 0x7c, 0x03, 0x48, 0x7f, +0x7c, 0x01, 0xe4, 0x70, 0xef, 0x7f, 0x30, 0x31, +0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, +0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x62, 0xd0, +0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, 0xe0, 0x08, +0x21, 0xf8, 0x29, 0x00, 0x70, 0xfe, 0x60, 0xe0, +0x70, 0xef, 0x4b, 0x4b, 0x4b, 0x4b, 0x51, 0x02, +0x21, 0xf7, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, +0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, +0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, +0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, +0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, +0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, +0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, +0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, +0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, +0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, +0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, +0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, +0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, +0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, +0x80, 0x01, 0x60, 0x00, 0x47, 0x00, 0x00, 0x49, +0x01, 0x00, 0x29, 0x08, 0x60, 0x00, 0x57, 0x01, +0x79, 0xbf, 0xfe, 0x18, 0x71, 0x10, 0x60, 0xe0, +0x70, 0xef, 0x71, 0x01, 0x7f, 0x08, 0x67, 0x67, +0x67, 0x67, 0x21, 0x0f, 0xff, 0x40, 0x9f, 0x4e, +0x18, 0x21, 0x0f, 0xff, 0x39, 0x9f, 0x47, 0x7f, +0x08, 0x10, 0x28, 0xa0, 0x0b, 0x9f, 0x3f, 0x20, +0x18, 0x75, 0xdf, 0xf5, 0x74, 0x8f, 0xf2, 0x38, +0xfe, 0x7f, 0x52, 0x00, 0xa0, 0x08, 0x10, 0x9f, +0x2d, 0x20, 0x75, 0x8f, 0xf6, 0x70, 0x3f, 0x71, +0xc0, 0x7f, 0x50, 0x0d, 0x9f, 0x20, 0x50, 0x0a, +0x9f, 0x1c, 0x7f, 0x70, 0xbf, 0x62, 0xd3, 0x03, +0x4f, 0x52, 0xfb, 0xa0, 0x15, 0x7b, 0xfb, 0x52, +0xfc, 0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9f, +0x05, 0x4f, 0x62, 0xd3, 0x03, 0x77, 0xfd, 0x8f, +0xe9, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x3d, 0xfa, +0x00, 0xb0, 0x06, 0x3d, 0xfb, 0x00, 0xa0, 0x18, +0x10, 0x52, 0xfc, 0x59, 0xfd, 0x28, 0x9e, 0xe6, +0x20, 0x07, 0xfd, 0x01, 0x0f, 0xfc, 0x00, 0x17, +0xfb, 0x01, 0x1f, 0xfa, 0x00, 0x8f, 0xe0, 0x7f, +0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, +0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xfb, +0x80, 0x04, 0x2e, 0x03, 0x04, 0x51, 0x03, 0x60, +0x04, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, +0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, +0x26, 0x03, 0xef, 0x80, 0x04, 0x2e, 0x03, 0x10, +0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, 0x71, 0xc0, +0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x10, +0x70, 0x3f, 0x71, 0x80, 0x5d, 0xd3, 0x08, 0x5d, +0xd0, 0x08, 0x62, 0xd0, 0x00, 0x51, 0x08, 0x60, +0xd3, 0x2e, 0x05, 0x80, 0x49, 0xd7, 0x08, 0xa0, +0x09, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x00, 0x80, +0x08, 0x49, 0xd7, 0x20, 0xa0, 0x03, 0x80, 0xa6, +0x51, 0x05, 0x21, 0x0e, 0xe0, 0x01, 0x80, 0x11, +0x80, 0x67, 0x80, 0x79, 0x80, 0x47, 0x80, 0x96, +0x80, 0x94, 0x80, 0x92, 0x80, 0x90, 0x80, 0x97, +0x5d, 0xd8, 0x21, 0xfe, 0x39, 0x40, 0xa0, 0x06, +0x62, 0xd7, 0x00, 0x80, 0x8a, 0x49, 0xd8, 0x01, +0xb0, 0x0f, 0x55, 0x0c, 0x02, 0x26, 0x05, 0xf0, +0x2e, 0x05, 0x02, 0x62, 0xd7, 0x10, 0x80, 0x77, +0x55, 0x0c, 0x01, 0x26, 0x05, 0xf0, 0x2e, 0x05, +0x06, 0x5f, 0x07, 0x06, 0x51, 0x09, 0x02, 0x07, +0x5c, 0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, 0x62, +0xd7, 0x14, 0x80, 0x5b, 0x51, 0x0a, 0x78, 0x3a, +0x07, 0xc0, 0x0f, 0x51, 0x09, 0x02, 0x07, 0x5c, +0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, 0x2e, 0x05, +0x20, 0x60, 0xd8, 0x62, 0xd7, 0x04, 0x80, 0x3f, +0x5d, 0xd8, 0x3a, 0x0a, 0xd0, 0x2b, 0xa0, 0x29, +0x53, 0x07, 0x53, 0x06, 0x26, 0x05, 0xf0, 0x2e, +0x05, 0x04, 0x80, 0x18, 0x51, 0x0b, 0x78, 0x3a, +0x07, 0xc0, 0x16, 0x51, 0x09, 0x02, 0x07, 0x5c, +0x5d, 0xd8, 0x54, 0x00, 0x2e, 0x05, 0x10, 0x76, +0x07, 0x80, 0x01, 0x62, 0xd7, 0x10, 0x80, 0x0f, +0x62, 0xd7, 0x00, 0x80, 0x0a, 0x26, 0x05, 0xf0, +0x2e, 0x05, 0x00, 0x55, 0x0c, 0x00, 0x18, 0x60, +0xd0, 0x18, 0x60, 0xd3, 0x20, 0x18, 0x7e, 0x62, +0xd0, 0x00, 0x71, 0x10, 0x41, 0x04, 0xfc, 0x43, +0x05, 0x03, 0x70, 0xef, 0x26, 0x03, 0xfc, 0x51, +0x03, 0x60, 0x04, 0x55, 0x0c, 0x00, 0x90, 0x28, +0x90, 0x2d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x50, +0x00, 0x53, 0x06, 0x71, 0x10, 0x43, 0x04, 0x03, +0x43, 0x05, 0x03, 0x70, 0xef, 0x2e, 0x03, 0x03, +0x51, 0x03, 0x60, 0x04, 0x7f, 0x62, 0xd0, 0x00, +0x51, 0x05, 0x21, 0xb0, 0x26, 0x05, 0x4f, 0x7f, +0x41, 0xe0, 0x7f, 0x43, 0xe0, 0x80, 0x7f, 0x43, +0xd6, 0x31, 0x7f, 0x41, 0xe0, 0x7f, 0x41, 0xd6, +0xfe, 0x7f, 0x62, 0xd0, 0x00, 0x4f, 0x52, 0xfd, +0x53, 0x0a, 0x52, 0xfc, 0x53, 0x0b, 0x52, 0xfb, +0x53, 0x09, 0x52, 0xfa, 0x53, 0x08, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x08, 0x5d, 0xa4, 0x04, 0x1b, +0x5d, 0xa5, 0x0c, 0x1a, 0x55, 0x1c, 0x01, 0x18, +0x7e, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, +0x53, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, +0x8c, 0x62, 0xd3, 0x00, 0x13, 0x7a, 0x62, 0xd3, +0x00, 0x54, 0x7e, 0x62, 0xd3, 0x00, 0x52, 0x8b, +0x62, 0xd3, 0x00, 0x1b, 0x79, 0x62, 0xd3, 0x00, +0x54, 0x7d, 0x48, 0x7d, 0x80, 0xb0, 0x33, 0x3d, +0x7d, 0x00, 0xb0, 0x7b, 0x51, 0x0d, 0x3b, 0x7e, +0xc0, 0x75, 0x52, 0x7e, 0x58, 0x1e, 0x01, 0x00, +0x6d, 0x62, 0xd3, 0x00, 0x05, 0x40, 0xc0, 0x09, +0x51, 0x0f, 0x3b, 0x40, 0xd0, 0x12, 0xa0, 0x10, +0x56, 0x40, 0x00, 0x5b, 0x64, 0x5c, 0x62, 0xd3, +0x00, 0x07, 0x7a, 0x01, 0x0f, 0x79, 0x00, 0x80, +0x41, 0x3d, 0x7d, 0xff, 0xb0, 0x09, 0x50, 0xff, +0x12, 0x0e, 0x3b, 0x7e, 0xc0, 0x20, 0x62, 0xd3, +0x00, 0x56, 0x7e, 0x00, 0x56, 0x7d, 0x00, 0x5b, +0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x47, 0x78, +0xd0, 0x03, 0x50, 0x00, 0x54, 0x47, 0x08, 0x5b, +0x64, 0x5c, 0x18, 0xb0, 0x2c, 0x62, 0xd3, 0x00, +0x52, 0x8c, 0x62, 0xd3, 0x00, 0x54, 0x7a, 0x62, +0xd3, 0x00, 0x52, 0x8b, 0x62, 0xd3, 0x00, 0x54, +0x79, 0x51, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, +0x56, 0x7e, 0x00, 0x56, 0x7d, 0x00, 0x5b, 0x67, +0x5c, 0x62, 0xd3, 0x00, 0x51, 0x12, 0x54, 0x47, +0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0xbf, 0x62, +0xd0, 0x00, 0x70, 0xbf, 0x08, 0x5c, 0x62, 0xd3, +0x00, 0x52, 0x42, 0x53, 0x19, 0x55, 0x18, 0x00, +0x18, 0x08, 0x90, 0x7e, 0x62, 0xd3, 0x00, 0x23, +0x44, 0xb0, 0x2c, 0x51, 0x10, 0x04, 0x19, 0x0e, +0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, 0x00, +0x52, 0x7e, 0x12, 0x19, 0x52, 0x7d, 0x1a, 0x18, +0xc0, 0x39, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, +0x52, 0x45, 0x78, 0x54, 0x45, 0x08, 0x5b, 0x64, +0x5c, 0x18, 0xb0, 0x3e, 0x80, 0x18, 0x51, 0x10, +0x14, 0x19, 0x1e, 0x18, 0x00, 0x18, 0x64, 0x5c, +0x62, 0xd3, 0x00, 0x52, 0x7e, 0x12, 0x19, 0x52, +0x7d, 0x1a, 0x18, 0xc0, 0x0e, 0x5b, 0x67, 0x90, +0x31, 0x62, 0xd3, 0x00, 0x2d, 0x44, 0x50, 0x01, +0x80, 0x24, 0x5b, 0x67, 0x08, 0x90, 0x23, 0x73, +0x62, 0xd3, 0x00, 0x25, 0x44, 0x62, 0xd3, 0x00, +0x20, 0x51, 0x11, 0x54, 0x45, 0x50, 0x00, 0x80, +0x0d, 0x5b, 0x67, 0x90, 0x0d, 0x73, 0x62, 0xd3, +0x00, 0x25, 0x44, 0x50, 0x00, 0x70, 0x3f, 0x71, +0xc0, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x5c, 0x18, +0x21, 0x07, 0xf0, 0x01, 0x7f, 0x01, 0x02, 0x04, +0x08, 0x10, 0x20, 0x40, 0x80, 0x70, 0xbf, 0x70, +0xbf, 0x62, 0xd3, 0x00, 0x50, 0x02, 0x78, 0x08, +0x5c, 0x56, 0x42, 0x19, 0x18, 0x78, 0xdf, 0xf8, +0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x91, 0xb2, +0x70, 0xbf, 0x18, 0x08, 0x64, 0x5c, 0x62, 0xd3, +0x00, 0x52, 0x8c, 0x62, 0xd3, 0x00, 0x54, 0x7a, +0x62, 0xd3, 0x00, 0x52, 0x8b, 0x62, 0xd3, 0x00, +0x54, 0x79, 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x14, +0x00, 0x50, 0x02, 0x78, 0x08, 0x9f, 0x0e, 0x39, +0x01, 0xb0, 0x04, 0x55, 0x14, 0x01, 0x18, 0x78, +0xdf, 0xf3, 0x51, 0x14, 0x7f, 0x50, 0x02, 0x78, +0x08, 0x9e, 0x3e, 0x18, 0x78, 0xdf, 0xfa, 0x7f, +0x98, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, +0x97, 0xd8, 0xd9, 0xda, 0xdb, 0xdf, 0x00, 0x01, +0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x70, +0xbf, 0x62, 0xd0, 0x00, 0x62, 0xd3, 0x00, 0x57, +0x00, 0x56, 0x44, 0x00, 0x79, 0xdf, 0xfb, 0x62, +0xd3, 0x00, 0x57, 0x01, 0x50, 0x03, 0x54, 0x45, +0x79, 0xdf, 0xfc, 0x62, 0xd3, 0x00, 0x50, 0x14, +0x57, 0x01, 0x54, 0x47, 0x79, 0xdf, 0xfc, 0x70, +0x3f, 0x71, 0xc0, 0x55, 0x0d, 0x14, 0x55, 0x0e, +0x05, 0x55, 0x0f, 0x14, 0x55, 0x10, 0x01, 0x55, +0x11, 0x03, 0x55, 0x12, 0x14, 0x55, 0x22, 0x04, +0x55, 0x1f, 0x14, 0x43, 0x61, 0x0d, 0x57, 0x00, +0x50, 0x02, 0x90, 0xae, 0x50, 0x04, 0xff, 0x98, +0x29, 0x00, 0x60, 0xa9, 0x62, 0xa0, 0x08, 0x43, +0xa2, 0x04, 0x62, 0xa3, 0x70, 0x43, 0x7a, 0x01, +0x43, 0xaa, 0x02, 0x43, 0xdf, 0x01, 0x50, 0x01, +0x57, 0x09, 0x90, 0x20, 0x90, 0x55, 0x57, 0x01, +0x50, 0xb3, 0x91, 0x5d, 0x50, 0x01, 0x57, 0x0e, +0x90, 0x12, 0x90, 0x47, 0x7f, 0x53, 0x22, 0xff, +0x67, 0x29, 0x00, 0x60, 0xa9, 0x51, 0x21, 0x58, +0x20, 0x90, 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x21, +0x03, 0x53, 0x21, 0x64, 0x64, 0x64, 0x64, 0x64, +0x29, 0x80, 0x60, 0xa1, 0x5b, 0x78, 0x21, 0x0f, +0x29, 0x08, 0x74, 0x53, 0x20, 0x12, 0x22, 0x02, +0x21, 0x5c, 0x50, 0x00, 0x53, 0x1d, 0x53, 0x23, +0x29, 0x01, 0x79, 0xa0, 0x08, 0x64, 0x6b, 0x1d, +0x6b, 0x23, 0x8f, 0xf5, 0x60, 0xb5, 0x51, 0x1d, +0x60, 0xb4, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x90, +0x28, 0x90, 0x5a, 0x18, 0x78, 0xdf, 0xf8, 0x7f, +0x41, 0xdf, 0xfe, 0x71, 0x10, 0x41, 0xd8, 0xfd, +0x70, 0xef, 0x41, 0x61, 0xf3, 0x41, 0xa2, 0xfb, +0x41, 0xa0, 0xf7, 0x62, 0xa3, 0x00, 0x62, 0xa9, +0x00, 0x41, 0xaa, 0xfd, 0x7f, 0x02, 0x20, 0x02, +0x08, 0x64, 0x5c, 0xff, 0xf8, 0x4b, 0x74, 0xff, +0xf4, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1d, 0x10, +0x5b, 0x64, 0x64, 0x5c, 0x71, 0x10, 0x5e, 0x01, +0x2a, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, +0x00, 0x22, 0x1d, 0x61, 0x00, 0x36, 0x1d, 0xff, +0x18, 0xfe, 0xd6, 0x5c, 0x5e, 0x00, 0x2a, 0x1d, +0x61, 0x00, 0x70, 0xef, 0x7f, 0x62, 0xd0, 0x00, +0x10, 0x73, 0x53, 0x1d, 0x71, 0x10, 0x5b, 0xfe, +0xc0, 0x5c, 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, +0x70, 0xef, 0x18, 0x64, 0x64, 0x5c, 0x71, 0x10, +0x5e, 0x01, 0x22, 0x1d, 0x61, 0x01, 0x36, 0x1d, +0xff, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, +0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, +0x1e, 0x50, 0x00, 0x53, 0x1a, 0x53, 0x1b, 0x51, +0x1e, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x24, 0x53, +0x1f, 0x43, 0xa0, 0x01, 0x51, 0x1f, 0x60, 0xfd, +0x41, 0xa3, 0xdf, 0x51, 0x1e, 0x9f, 0x7a, 0x9f, +0x81, 0x58, 0x23, 0x55, 0x1c, 0x00, 0x62, 0xa5, +0x00, 0x62, 0xa4, 0x00, 0x43, 0xb3, 0x01, 0x51, +0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1e, +0x9f, 0x5f, 0x9f, 0x91, 0x43, 0xa3, 0x20, 0x41, +0xa0, 0xfe, 0x62, 0xfd, 0x00, 0x50, 0xff, 0x4c, +0x1b, 0x14, 0x1b, 0x51, 0x20, 0x11, 0x08, 0xfe, +0x4d, 0x4c, 0x1a, 0x1c, 0x1a, 0xd0, 0x07, 0x55, +0x1a, 0x00, 0x55, 0x1b, 0x00, 0x51, 0x1e, 0x64, +0x5c, 0x62, 0xd3, 0x00, 0x51, 0x1b, 0x54, 0x8c, +0x51, 0x1a, 0x54, 0x8b, 0x70, 0x3f, 0x71, 0xc0, +0x7f, 0x08, 0x9f, 0x86, 0x18, 0x78, 0xdf, 0xfa, +0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x27, +0x5a, 0x26, 0x55, 0x1e, 0x01, 0x62, 0xd3, 0x00, +0x58, 0x1e, 0x56, 0x24, 0x80, 0x55, 0x29, 0x08, +0x55, 0x28, 0x80, 0x51, 0x1e, 0x9f, 0x63, 0x51, +0x1e, 0x9f, 0x5f, 0x70, 0xbf, 0x58, 0x1e, 0x62, +0xd3, 0x00, 0x51, 0x1b, 0x3a, 0x27, 0x51, 0x1a, +0x1a, 0x26, 0xd0, 0x06, 0x51, 0x28, 0x73, 0x25, +0x24, 0x68, 0x28, 0x26, 0x28, 0x7f, 0x51, 0x28, +0x2d, 0x24, 0x7a, 0x29, 0xbf, 0xd6, 0x7a, 0x1e, +0xdf, 0xc4, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, +0xd0, 0x00, 0x51, 0xa0, 0x11, 0x10, 0x51, 0x9f, +0x19, 0x0e, 0xd0, 0x12, 0x7c, 0x14, 0x1d, 0x39, +0x0f, 0xa0, 0x16, 0x62, 0xd0, 0x00, 0x76, 0xa0, +0x0e, 0x9f, 0x00, 0x80, 0x0c, 0x62, 0xd0, 0x00, +0x55, 0xa0, 0x00, 0x55, 0x9f, 0x00, 0x90, 0xa9, +0x7f, 0x62, 0xd0, 0x00, 0x3c, 0xa7, 0xf0, 0xd0, +0x03, 0x76, 0xa7, 0x62, 0xd0, 0x00, 0x51, 0x2f, +0x21, 0x7f, 0x53, 0x58, 0x51, 0xa7, 0x3a, 0x58, +0xb0, 0x50, 0x7c, 0x14, 0x1d, 0x62, 0xd0, 0x00, +0x53, 0xad, 0x3c, 0xad, 0x0f, 0xa0, 0x3d, 0x3c, +0xa9, 0x00, 0xb0, 0x1c, 0x55, 0x93, 0x00, 0x55, +0x94, 0x00, 0x51, 0xad, 0x53, 0x57, 0x55, 0x58, +0x00, 0x06, 0x57, 0x93, 0x0e, 0x58, 0x00, 0x51, +0x58, 0x60, 0xd5, 0x50, 0x08, 0x3f, 0x57, 0x62, +0xd0, 0x00, 0x55, 0xa5, 0x00, 0x3c, 0xac, 0x00, +0xb0, 0x0a, 0x7c, 0x14, 0xb2, 0x62, 0xd0, 0x00, +0x55, 0xac, 0x01, 0x62, 0xd0, 0x00, 0x55, 0xb0, +0x03, 0x80, 0x07, 0x62, 0xd0, 0x00, 0x55, 0xa7, +0x00, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0xa0, 0x00, +0x55, 0x9f, 0x00, 0x3c, 0xac, 0x01, 0xb0, 0x31, +0x7a, 0xb0, 0x3c, 0xb0, 0x00, 0xb0, 0x2a, 0x3c, +0xac, 0x01, 0xb0, 0x0a, 0x7c, 0x15, 0x45, 0x62, +0xd0, 0x00, 0x55, 0xac, 0x00, 0x62, 0xd0, 0x00, +0x3c, 0xa9, 0x00, 0xb0, 0x0e, 0x51, 0xad, 0x53, +0x57, 0x55, 0x58, 0x00, 0x06, 0x57, 0x93, 0x7c, +0x1a, 0xcf, 0x62, 0xd0, 0x00, 0x55, 0xa7, 0x00, +0x7f, 0x10, 0x4f, 0x38, 0x16, 0x62, 0xd0, 0x00, +0x3c, 0xa8, 0x00, 0xb0, 0x05, 0x51, 0x9b, 0x53, +0x24, 0x56, 0x0d, 0x00, 0x80, 0x67, 0x56, 0x00, +0x00, 0x80, 0x5b, 0x62, 0xd0, 0x00, 0x3c, 0xa8, +0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x57, 0x55, +0x58, 0x00, 0x06, 0x57, 0x9b, 0x7c, 0x19, 0xf9, +0x52, 0x00, 0x53, 0x55, 0x55, 0x56, 0x00, 0x06, +0x55, 0x24, 0x7c, 0x1a, 0xc3, 0x10, 0x52, 0x00, +0x7c, 0x09, 0x5a, 0x20, 0x10, 0x7c, 0x05, 0xe5, +0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, +0x7c, 0x19, 0x52, 0x52, 0x0d, 0x7c, 0x1a, 0xb7, +0x02, 0x57, 0x53, 0x57, 0x51, 0x56, 0x0a, 0x58, +0x53, 0x58, 0x7c, 0x1a, 0x85, 0x06, 0x55, 0x8b, +0x0e, 0x56, 0x00, 0x51, 0x56, 0x7c, 0x19, 0xe3, +0x7c, 0x1a, 0x05, 0x77, 0x00, 0x3d, 0x00, 0x02, +0xcf, 0xa2, 0x77, 0x0d, 0x3d, 0x0d, 0x03, 0xcf, +0x96, 0x56, 0x00, 0x00, 0x81, 0x06, 0x7c, 0x19, +0x47, 0x7c, 0x19, 0x9e, 0x51, 0x58, 0x60, 0xd4, +0x3e, 0x57, 0x54, 0x0e, 0x3e, 0x57, 0x54, 0x0f, +0x52, 0x00, 0x53, 0x57, 0x55, 0x58, 0x00, 0x55, +0x55, 0x06, 0x55, 0x56, 0x00, 0x55, 0x52, 0x00, +0x55, 0x51, 0x00, 0x3c, 0x56, 0x00, 0xb0, 0x06, +0x3c, 0x55, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, +0x56, 0x6e, 0x55, 0xd0, 0x0c, 0x62, 0xd0, 0x00, +0x51, 0x57, 0x04, 0x52, 0x51, 0x58, 0x0c, 0x51, +0x65, 0x57, 0x6b, 0x58, 0x8f, 0xde, 0x5f, 0x57, +0x52, 0x5f, 0x58, 0x51, 0x62, 0xd0, 0x00, 0x5a, +0x55, 0x06, 0x55, 0x03, 0x51, 0x55, 0x04, 0x57, +0x0e, 0x58, 0x03, 0x51, 0x58, 0x60, 0xd4, 0x3e, +0x57, 0x54, 0x10, 0x3e, 0x57, 0x54, 0x11, 0x52, +0x00, 0x53, 0x57, 0x55, 0x58, 0x00, 0x55, 0x55, +0x06, 0x55, 0x56, 0x00, 0x55, 0x52, 0x00, 0x55, +0x51, 0x00, 0x3c, 0x56, 0x00, 0xb0, 0x06, 0x3c, +0x55, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x56, +0x6e, 0x55, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, +0x57, 0x04, 0x52, 0x51, 0x58, 0x0c, 0x51, 0x65, +0x57, 0x6b, 0x58, 0x8f, 0xde, 0x5f, 0x57, 0x52, +0x5f, 0x58, 0x51, 0x62, 0xd0, 0x00, 0x5a, 0x55, +0x06, 0x55, 0x05, 0x51, 0x55, 0x04, 0x57, 0x0e, +0x58, 0x03, 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, +0x54, 0x12, 0x3e, 0x57, 0x54, 0x13, 0x50, 0x03, +0x08, 0x5a, 0x57, 0x06, 0x57, 0x0e, 0x08, 0x51, +0x57, 0x08, 0x7c, 0x17, 0xdc, 0x38, 0xfd, 0x62, +0xd0, 0x00, 0x51, 0x57, 0x54, 0x15, 0x51, 0x58, +0x54, 0x14, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, +0x8b, 0x7c, 0x1a, 0x33, 0x06, 0x57, 0x79, 0x7c, +0x1a, 0x6a, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, +0x61, 0x7c, 0x1a, 0x33, 0x51, 0x57, 0x01, 0x69, +0x7c, 0x1a, 0x33, 0x06, 0x57, 0x71, 0x7c, 0x1a, +0x6a, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xf7, +0x38, 0xea, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x16, +0x10, 0x57, 0x09, 0x50, 0x01, 0x7c, 0x08, 0x94, +0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x10, 0x08, +0x57, 0xc2, 0x28, 0x53, 0x58, 0x18, 0x75, 0x09, +0x00, 0x28, 0x53, 0x57, 0x20, 0x10, 0x51, 0x58, +0x08, 0x51, 0x57, 0x20, 0x7c, 0x09, 0xd9, 0x20, +0x10, 0x57, 0x0e, 0x50, 0x01, 0x7c, 0x08, 0x94, +0x20, 0x62, 0xd0, 0x00, 0x3c, 0xa8, 0x01, 0xb0, +0x0b, 0x51, 0x24, 0x53, 0x30, 0x51, 0x25, 0x53, +0x31, 0x80, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x9b, +0x53, 0x24, 0x51, 0x9c, 0x53, 0x25, 0x10, 0x50, +0x00, 0x7c, 0x09, 0x5a, 0x20, 0x56, 0x0d, 0x00, +0x80, 0x67, 0x56, 0x00, 0x00, 0x80, 0x5b, 0x62, +0xd0, 0x00, 0x3c, 0xa8, 0x00, 0xb0, 0x1b, 0x52, +0x00, 0x53, 0x57, 0x55, 0x58, 0x00, 0x06, 0x57, +0x9b, 0x7c, 0x19, 0xf9, 0x52, 0x00, 0x53, 0x55, +0x55, 0x56, 0x00, 0x06, 0x55, 0x24, 0x7c, 0x1a, +0xc3, 0x10, 0x52, 0x00, 0x7c, 0x09, 0x5a, 0x20, +0x10, 0x7c, 0x05, 0xe5, 0x62, 0xd0, 0x00, 0x20, +0x39, 0x00, 0xbf, 0xee, 0x7c, 0x19, 0x52, 0x52, +0x0d, 0x7c, 0x1a, 0xb7, 0x02, 0x57, 0x53, 0x57, +0x51, 0x56, 0x0a, 0x58, 0x53, 0x58, 0x7c, 0x1a, +0x85, 0x06, 0x55, 0x8b, 0x0e, 0x56, 0x00, 0x51, +0x56, 0x7c, 0x19, 0xe3, 0x7c, 0x1a, 0x05, 0x77, +0x00, 0x3d, 0x00, 0x02, 0xcf, 0xa2, 0x77, 0x0d, +0x3d, 0x0d, 0x03, 0xcf, 0x96, 0x56, 0x00, 0x00, +0x81, 0x06, 0x7c, 0x19, 0x47, 0x7c, 0x19, 0x9e, +0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x0e, +0x3e, 0x57, 0x54, 0x0f, 0x52, 0x00, 0x53, 0x57, +0x55, 0x58, 0x00, 0x55, 0x55, 0x06, 0x55, 0x56, +0x00, 0x55, 0x52, 0x00, 0x55, 0x51, 0x00, 0x3c, +0x56, 0x00, 0xb0, 0x06, 0x3c, 0x55, 0x00, 0xa0, +0x1a, 0x70, 0xfb, 0x6e, 0x56, 0x6e, 0x55, 0xd0, +0x0c, 0x62, 0xd0, 0x00, 0x51, 0x57, 0x04, 0x52, +0x51, 0x58, 0x0c, 0x51, 0x65, 0x57, 0x6b, 0x58, +0x8f, 0xde, 0x5f, 0x57, 0x52, 0x5f, 0x58, 0x51, +0x62, 0xd0, 0x00, 0x5a, 0x55, 0x06, 0x55, 0x03, +0x51, 0x55, 0x04, 0x57, 0x0e, 0x58, 0x03, 0x51, +0x58, 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x10, 0x3e, +0x57, 0x54, 0x11, 0x52, 0x00, 0x53, 0x57, 0x55, +0x58, 0x00, 0x55, 0x55, 0x06, 0x55, 0x56, 0x00, +0x55, 0x52, 0x00, 0x55, 0x51, 0x00, 0x3c, 0x56, +0x00, 0xb0, 0x06, 0x3c, 0x55, 0x00, 0xa0, 0x1a, +0x70, 0xfb, 0x6e, 0x56, 0x6e, 0x55, 0xd0, 0x0c, +0x62, 0xd0, 0x00, 0x51, 0x57, 0x04, 0x52, 0x51, +0x58, 0x0c, 0x51, 0x65, 0x57, 0x6b, 0x58, 0x8f, +0xde, 0x5f, 0x57, 0x52, 0x5f, 0x58, 0x51, 0x62, +0xd0, 0x00, 0x5a, 0x55, 0x06, 0x55, 0x05, 0x51, +0x55, 0x04, 0x57, 0x0e, 0x58, 0x03, 0x51, 0x58, +0x60, 0xd4, 0x3e, 0x57, 0x54, 0x12, 0x3e, 0x57, +0x54, 0x13, 0x50, 0x03, 0x08, 0x5a, 0x57, 0x06, +0x57, 0x0e, 0x08, 0x51, 0x57, 0x08, 0x7c, 0x17, +0xdc, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, 0x57, +0x54, 0x15, 0x51, 0x58, 0x54, 0x14, 0x7c, 0x19, +0x2a, 0x51, 0x57, 0x01, 0x8b, 0x7c, 0x1a, 0x33, +0x06, 0x57, 0x79, 0x7c, 0x1a, 0x6a, 0x7c, 0x19, +0x2a, 0x51, 0x57, 0x01, 0x61, 0x7c, 0x1a, 0x33, +0x51, 0x57, 0x01, 0x69, 0x7c, 0x1a, 0x33, 0x06, +0x57, 0x71, 0x7c, 0x1a, 0x6a, 0x77, 0x00, 0x3d, +0x00, 0x02, 0xce, 0xf7, 0x56, 0x00, 0x00, 0x80, +0x19, 0x7c, 0x19, 0x47, 0x06, 0x57, 0x24, 0x7c, +0x19, 0xf9, 0x52, 0x00, 0x53, 0x55, 0x55, 0x56, +0x00, 0x06, 0x55, 0x30, 0x7c, 0x1a, 0xc3, 0x77, +0x00, 0x3d, 0x00, 0x02, 0xcf, 0xe4, 0x38, 0xea, +0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x62, 0xd0, +0x00, 0x52, 0xfc, 0x01, 0x02, 0x53, 0x57, 0x52, +0xfb, 0x09, 0x00, 0x7c, 0x1a, 0x12, 0x52, 0xfc, +0x01, 0x04, 0x53, 0x55, 0x52, 0xfb, 0x7c, 0x19, +0xee, 0x12, 0x57, 0x51, 0x56, 0x1a, 0x58, 0xc0, +0x6f, 0x52, 0xfc, 0x53, 0x57, 0x52, 0xfb, 0x7c, +0x1a, 0x12, 0x52, 0xfc, 0x01, 0x02, 0x53, 0x55, +0x52, 0xfb, 0x7c, 0x19, 0xee, 0x12, 0x57, 0x51, +0x56, 0x1a, 0x58, 0xc0, 0x10, 0x52, 0xfc, 0x01, +0x02, 0x7c, 0x1a, 0x51, 0x54, 0x00, 0x3e, 0x57, +0x54, 0x01, 0x80, 0xb3, 0x62, 0xd0, 0x00, 0x52, +0xfc, 0x01, 0x04, 0x53, 0x57, 0x52, 0xfb, 0x09, +0x00, 0x7c, 0x1a, 0x12, 0x52, 0xfc, 0x53, 0x55, +0x52, 0xfb, 0x60, 0xd4, 0x3e, 0x55, 0x53, 0x56, +0x3e, 0x55, 0x12, 0x57, 0x51, 0x56, 0x1a, 0x58, +0xc0, 0x10, 0x52, 0xfc, 0x01, 0x04, 0x7c, 0x1a, +0x51, 0x54, 0x00, 0x3e, 0x57, 0x54, 0x01, 0x80, +0x7e, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x57, +0x52, 0xfb, 0x7c, 0x1a, 0x7a, 0x80, 0x70, 0x62, +0xd0, 0x00, 0x52, 0xfc, 0x53, 0x57, 0x52, 0xfb, +0x7c, 0x1a, 0x12, 0x52, 0xfc, 0x01, 0x04, 0x53, +0x55, 0x52, 0xfb, 0x7c, 0x19, 0xee, 0x12, 0x57, +0x51, 0x56, 0x1a, 0x58, 0xc0, 0x10, 0x52, 0xfc, +0x01, 0x04, 0x7c, 0x1a, 0x51, 0x54, 0x00, 0x3e, +0x57, 0x54, 0x01, 0x80, 0x42, 0x62, 0xd0, 0x00, +0x52, 0xfc, 0x01, 0x02, 0x53, 0x57, 0x52, 0xfb, +0x09, 0x00, 0x7c, 0x1a, 0x12, 0x52, 0xfc, 0x53, +0x55, 0x52, 0xfb, 0x60, 0xd4, 0x3e, 0x55, 0x53, +0x56, 0x3e, 0x55, 0x12, 0x57, 0x51, 0x56, 0x1a, +0x58, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, +0x1a, 0x51, 0x54, 0x00, 0x3e, 0x57, 0x54, 0x01, +0x80, 0x0d, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, +0x57, 0x52, 0xfb, 0x7c, 0x1a, 0x7a, 0x62, 0xd0, +0x00, 0x52, 0x01, 0x53, 0x57, 0x52, 0x00, 0x53, +0x58, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, +0x05, 0x62, 0xd0, 0x00, 0x55, 0xaf, 0x00, 0x56, +0x00, 0x00, 0x80, 0x38, 0x62, 0xd0, 0x00, 0x3c, +0xa8, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x57, +0x55, 0x58, 0x00, 0x06, 0x57, 0x9b, 0x7c, 0x19, +0xf9, 0x52, 0x00, 0x53, 0x55, 0x55, 0x56, 0x00, +0x06, 0x55, 0x24, 0x7c, 0x1a, 0xc3, 0x10, 0x52, +0x00, 0x7c, 0x09, 0x5a, 0x20, 0x10, 0x7c, 0x05, +0xe5, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, +0xee, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0xc5, +0x56, 0x00, 0x00, 0x82, 0x86, 0x62, 0xd0, 0x00, +0x3c, 0xae, 0x02, 0xa0, 0x9f, 0x7c, 0x19, 0x2a, +0x51, 0x57, 0x01, 0x79, 0x7c, 0x19, 0x36, 0x06, +0x57, 0x8b, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, 0x44, +0xd0, 0x16, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, +0x79, 0x7c, 0x19, 0x36, 0x06, 0x57, 0x8b, 0x7c, +0x19, 0xf9, 0x7c, 0x1a, 0xdb, 0x80, 0x17, 0x62, +0xd0, 0x00, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, +0x8b, 0x7c, 0x19, 0x36, 0x06, 0x57, 0x79, 0x7c, +0x19, 0xf9, 0x7c, 0x1a, 0xdb, 0x50, 0x5e, 0x13, +0x02, 0x50, 0x01, 0x1b, 0x01, 0xc0, 0x4e, 0x62, +0xd0, 0x00, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, +0x71, 0x7c, 0x19, 0x36, 0x06, 0x57, 0x8b, 0x7c, +0x19, 0xf9, 0x7c, 0x1a, 0x44, 0xd0, 0x16, 0x7c, +0x19, 0x2a, 0x51, 0x57, 0x01, 0x71, 0x7c, 0x19, +0x36, 0x06, 0x57, 0x8b, 0x7c, 0x19, 0xf9, 0x7c, +0x1a, 0xe8, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x7c, +0x19, 0x2a, 0x51, 0x57, 0x01, 0x8b, 0x7c, 0x19, +0x36, 0x06, 0x57, 0x71, 0x7c, 0x19, 0xf9, 0x7c, +0x1a, 0xe8, 0x50, 0x5e, 0x13, 0x04, 0x50, 0x01, +0x1b, 0x03, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x76, +0xaf, 0x81, 0xde, 0x62, 0xd0, 0x00, 0x7c, 0x19, +0x2a, 0x51, 0x57, 0x01, 0x8b, 0x7c, 0x19, 0x36, +0x06, 0x57, 0x71, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, +0x44, 0xd0, 0x5a, 0x7c, 0x19, 0x2a, 0x7c, 0x1a, +0x1d, 0x06, 0x55, 0x01, 0x0e, 0x56, 0x00, 0x7c, +0x1a, 0x05, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, +0x8b, 0x7c, 0x19, 0x36, 0x06, 0x57, 0x71, 0x7c, +0x19, 0xf9, 0x7c, 0x1a, 0x44, 0xd0, 0xb4, 0x7c, +0x19, 0x2a, 0x7c, 0x1a, 0x1d, 0x06, 0x55, 0x01, +0x0e, 0x56, 0x00, 0x7c, 0x1a, 0x05, 0x7c, 0x19, +0x2a, 0x51, 0x57, 0x01, 0x8b, 0x7c, 0x19, 0x36, +0x06, 0x57, 0x71, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, +0x44, 0xd0, 0x90, 0x7c, 0x19, 0x2a, 0x7c, 0x1a, +0x1d, 0x06, 0x55, 0x01, 0x0e, 0x56, 0x00, 0x7c, +0x1a, 0x05, 0x80, 0x7f, 0x62, 0xd0, 0x00, 0x7c, +0x19, 0x2a, 0x51, 0x57, 0x01, 0x8b, 0x7c, 0x19, +0x36, 0x06, 0x57, 0x71, 0x7c, 0x19, 0xf9, 0x3e, +0x57, 0x12, 0x55, 0x51, 0x58, 0x1a, 0x56, 0xd0, +0x62, 0x7c, 0x19, 0x2a, 0x7c, 0x1a, 0x1d, 0x16, +0x55, 0x01, 0x1e, 0x56, 0x00, 0x7c, 0x1a, 0x05, +0x97, 0xf8, 0x40, 0x51, 0x57, 0x01, 0x8b, 0x97, +0xfd, 0x40, 0x06, 0x57, 0x71, 0x7c, 0x19, 0xf9, +0x3e, 0x57, 0x12, 0x55, 0x51, 0x58, 0x1a, 0x56, +0xd0, 0x39, 0x97, 0xde, 0x40, 0x7c, 0x1a, 0x1d, +0x16, 0x55, 0x01, 0x1e, 0x56, 0x00, 0x7c, 0x1a, +0x05, 0x97, 0xcf, 0x40, 0x51, 0x57, 0x01, 0x8b, +0x97, 0xd4, 0x40, 0x06, 0x57, 0x71, 0x7c, 0x19, +0xf9, 0x3e, 0x57, 0x12, 0x55, 0x51, 0x58, 0x1a, +0x56, 0xd0, 0x10, 0x97, 0xb5, 0x40, 0x7c, 0x1a, +0x1d, 0x16, 0x55, 0x01, 0x1e, 0x56, 0x00, 0x7c, +0x1a, 0x05, 0x62, 0xd0, 0x00, 0x97, 0xa3, 0x40, +0x51, 0x57, 0x01, 0x69, 0x97, 0xa8, 0x40, 0x06, +0x57, 0x61, 0x0e, 0x58, 0x00, 0x7c, 0x1a, 0x05, +0x97, 0x90, 0x40, 0x51, 0x57, 0x01, 0x71, 0x97, +0x95, 0x40, 0x06, 0x57, 0x69, 0x0e, 0x58, 0x00, +0x7c, 0x1a, 0x05, 0x97, 0x7d, 0x40, 0x51, 0x57, +0x01, 0x8b, 0x97, 0x82, 0x40, 0x06, 0x57, 0x71, +0x0e, 0x58, 0x00, 0x7c, 0x1a, 0x05, 0x10, 0x52, +0x00, 0x7c, 0x06, 0x29, 0x20, 0x62, 0xd0, 0x00, +0x97, 0x60, 0x40, 0x51, 0x57, 0x01, 0x8b, 0x97, +0x65, 0x40, 0x06, 0x57, 0x79, 0x7c, 0x19, 0xf9, +0x7c, 0x1a, 0x44, 0xd0, 0x25, 0x52, 0x00, 0x53, +0x57, 0x55, 0x58, 0x00, 0x06, 0x57, 0x97, 0x0e, +0x58, 0x00, 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, +0x7a, 0x57, 0x53, 0x56, 0x06, 0x56, 0x01, 0x51, +0x58, 0x60, 0xd5, 0x51, 0x56, 0x3f, 0x57, 0x80, +0x0a, 0x97, 0x44, 0x40, 0x06, 0x57, 0x97, 0x7c, +0x1a, 0xcf, 0x97, 0x3b, 0x40, 0x06, 0x57, 0x97, +0x97, 0xe7, 0x40, 0x50, 0x05, 0x3a, 0x58, 0xd0, +0x58, 0x97, 0x0f, 0x40, 0x51, 0x57, 0x01, 0x79, +0x53, 0x55, 0x51, 0x58, 0x09, 0x00, 0x53, 0x56, +0x06, 0x57, 0x8b, 0x97, 0xcc, 0x40, 0x3e, 0x57, +0x53, 0x57, 0x51, 0x56, 0x60, 0xd4, 0x3e, 0x55, +0x53, 0x54, 0x3e, 0x55, 0x16, 0x55, 0x02, 0x02, +0x57, 0x53, 0x57, 0x51, 0x54, 0x0a, 0x58, 0x53, +0x58, 0x70, 0xfb, 0x6e, 0x58, 0x6e, 0x57, 0x51, +0x56, 0x60, 0xd5, 0x51, 0x58, 0x3f, 0x55, 0x51, +0x57, 0x3f, 0x55, 0x52, 0x00, 0x53, 0x57, 0x55, +0x58, 0x00, 0x06, 0x57, 0x97, 0x0e, 0x58, 0x00, +0x51, 0x58, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x57, +0x77, 0x00, 0x3d, 0x00, 0x02, 0xcd, 0x77, 0x62, +0xd0, 0x00, 0x3c, 0xae, 0x02, 0xb1, 0x10, 0x56, +0x00, 0x00, 0x81, 0x06, 0x62, 0xd0, 0x00, 0x96, +0xa1, 0x40, 0x51, 0x57, 0x01, 0x8b, 0x96, 0xa6, +0x40, 0x06, 0x57, 0x38, 0x0e, 0x58, 0x00, 0x97, +0x6c, 0x40, 0x96, 0x8e, 0x40, 0x51, 0x57, 0x01, +0x79, 0x96, 0x93, 0x40, 0x06, 0x57, 0x3c, 0x0e, +0x58, 0x00, 0x97, 0x59, 0x40, 0x96, 0x7b, 0x40, +0x51, 0x57, 0x01, 0x79, 0x96, 0x80, 0x40, 0x51, +0x57, 0x01, 0x8b, 0x53, 0x53, 0x51, 0x58, 0x97, +0xe9, 0x40, 0x51, 0x55, 0x12, 0x53, 0x51, 0x56, +0x1a, 0x54, 0xd0, 0x21, 0x97, 0xb7, 0x40, 0x51, +0x55, 0x01, 0x79, 0x53, 0x53, 0x51, 0x56, 0x97, +0xd1, 0x40, 0x06, 0x55, 0x8b, 0x97, 0x7d, 0x40, +0x12, 0x53, 0x54, 0x02, 0x51, 0x56, 0x1a, 0x54, +0x54, 0x01, 0x80, 0x07, 0x56, 0x02, 0x00, 0x56, +0x01, 0x00, 0x62, 0xd0, 0x00, 0x06, 0x57, 0x34, +0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd5, 0x52, +0x01, 0x3f, 0x57, 0x52, 0x02, 0x3f, 0x57, 0x96, +0x21, 0x40, 0x51, 0x57, 0x01, 0x8b, 0x96, 0x26, +0x40, 0x06, 0x57, 0x38, 0x0e, 0x58, 0x00, 0x96, +0xec, 0x40, 0x96, 0x0e, 0x40, 0x51, 0x57, 0x01, +0x79, 0x96, 0x13, 0x40, 0x06, 0x57, 0x3c, 0x0e, +0x58, 0x00, 0x96, 0xd9, 0x40, 0x95, 0xfb, 0x40, +0x51, 0x57, 0x01, 0x79, 0x96, 0x00, 0x40, 0x51, +0x57, 0x01, 0x8b, 0x53, 0x53, 0x51, 0x58, 0x97, +0x69, 0x40, 0x51, 0x55, 0x12, 0x53, 0x51, 0x56, +0x1a, 0x54, 0xd0, 0x21, 0x97, 0x37, 0x40, 0x51, +0x55, 0x01, 0x79, 0x53, 0x53, 0x51, 0x56, 0x97, +0x51, 0x40, 0x06, 0x55, 0x8b, 0x96, 0xfd, 0x40, +0x12, 0x53, 0x54, 0x04, 0x51, 0x56, 0x1a, 0x54, +0x54, 0x03, 0x80, 0x07, 0x56, 0x04, 0x00, 0x56, +0x03, 0x00, 0x62, 0xd0, 0x00, 0x06, 0x57, 0x34, +0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd5, 0x52, +0x03, 0x3f, 0x57, 0x52, 0x04, 0x3f, 0x57, 0x77, +0x00, 0x3d, 0x00, 0x02, 0xce, 0xf7, 0x62, 0xd0, +0x00, 0x3c, 0xae, 0x02, 0xa0, 0x18, 0x3c, 0xaf, +0x00, 0xa0, 0x13, 0x50, 0x01, 0x08, 0x50, 0x2c, +0x08, 0x90, 0x0e, 0x38, 0xfe, 0x7c, 0x0a, 0xf9, +0x10, 0x7c, 0x07, 0xe5, 0x20, 0x38, 0xfb, 0x20, +0x7f, 0x10, 0x4f, 0x80, 0x02, 0x40, 0x62, 0xd0, +0x00, 0x52, 0xfc, 0x53, 0x57, 0x52, 0xfb, 0x53, +0x58, 0x51, 0x57, 0x11, 0x01, 0x54, 0xfc, 0x51, +0x58, 0x19, 0x00, 0x54, 0xfb, 0x3c, 0x58, 0x00, +0xbf, 0xe4, 0x3c, 0x57, 0x00, 0xbf, 0xdf, 0x20, +0x7f, 0x10, 0x7c, 0x04, 0xaf, 0x7c, 0x04, 0x8c, +0x20, 0x7f, 0x10, 0x7c, 0x04, 0xab, 0x7c, 0x04, +0x88, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0x42, +0x12, 0x7e, 0x50, 0x00, 0x1a, 0x7d, 0xd0, 0x0f, +0x51, 0x43, 0x12, 0x80, 0x50, 0x00, 0x1a, 0x7f, +0xd0, 0x05, 0x50, 0x0f, 0x80, 0x17, 0x62, 0xd0, +0x00, 0x51, 0x80, 0x12, 0x7e, 0x51, 0x7f, 0x1a, +0x7d, 0xd0, 0x05, 0x50, 0x00, 0x80, 0x06, 0x62, +0xd0, 0x00, 0x50, 0x01, 0x7f, 0x10, 0x4f, 0x38, +0x05, 0x62, 0xd0, 0x00, 0x51, 0x7e, 0x54, 0x02, +0x51, 0x7d, 0x54, 0x01, 0x56, 0x04, 0x00, 0x56, +0x00, 0x00, 0x56, 0x03, 0x00, 0x80, 0x61, 0x95, +0x0e, 0x40, 0x06, 0x57, 0x42, 0x0e, 0x58, 0x00, +0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, 0x53, 0x57, +0x96, 0x3b, 0x40, 0x06, 0x55, 0x7d, 0x0e, 0x56, +0x00, 0x51, 0x56, 0x95, 0x8e, 0x40, 0x51, 0x57, +0x12, 0x55, 0x50, 0x00, 0x1a, 0x56, 0xd0, 0x03, +0x77, 0x03, 0x62, 0xd0, 0x00, 0x94, 0xc3, 0x40, +0x06, 0x57, 0x7d, 0x95, 0x8c, 0x40, 0x3e, 0x57, +0x53, 0x57, 0x52, 0x02, 0x12, 0x57, 0x52, 0x01, +0x1a, 0x58, 0xd0, 0x1a, 0x94, 0xac, 0x40, 0x06, +0x57, 0x7d, 0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, +0xd4, 0x3e, 0x57, 0x54, 0x01, 0x3e, 0x57, 0x54, +0x02, 0x52, 0x00, 0x54, 0x04, 0x77, 0x00, 0x3d, +0x00, 0x02, 0xcf, 0x9c, 0x50, 0x01, 0x3b, 0x03, +0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, 0x0f, 0x80, +0x06, 0x52, 0x04, 0x62, 0xd0, 0x00, 0x38, 0xfb, +0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x70, 0xfe, +0x62, 0xd0, 0x00, 0x26, 0x2a, 0xf0, 0x51, 0xad, +0x01, 0x01, 0x53, 0x58, 0x51, 0x2a, 0x2a, 0x58, +0x53, 0x2a, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, +0x7c, 0x05, 0xe5, 0x62, 0xd0, 0x00, 0x20, 0x41, +0x00, 0xf7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, +0x80, 0x21, 0x10, 0x7c, 0x05, 0xe5, 0x62, 0xd0, +0x00, 0x20, 0x53, 0x58, 0x47, 0x58, 0x20, 0xa0, +0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x01, +0x08, 0x9e, 0xb6, 0x38, 0xfe, 0x77, 0x01, 0x0f, +0x00, 0x00, 0x52, 0x01, 0x11, 0x0a, 0x52, 0x00, +0x19, 0x04, 0xcf, 0xd7, 0x56, 0x01, 0x00, 0x56, +0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0xe5, +0x62, 0xd0, 0x00, 0x20, 0x53, 0x58, 0x47, 0x58, +0x20, 0xb0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, +0x50, 0x01, 0x08, 0x9e, 0x84, 0x38, 0xfe, 0x77, +0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, 0xce, +0x52, 0x00, 0x19, 0x00, 0xcf, 0xd7, 0x43, 0x00, +0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, +0x02, 0x70, 0xfe, 0x62, 0xd0, 0x00, 0x26, 0x2a, +0xf0, 0x51, 0xad, 0x01, 0x09, 0x53, 0x58, 0x51, +0x2a, 0x2a, 0x58, 0x53, 0x2a, 0x71, 0x01, 0x62, +0xe3, 0x38, 0x10, 0x7c, 0x05, 0xe5, 0x62, 0xd0, +0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, 0x01, 0x00, +0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, +0xe5, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x58, 0x47, +0x58, 0x20, 0xa0, 0x03, 0x80, 0x1a, 0x50, 0x00, +0x08, 0x50, 0x01, 0x08, 0x9e, 0x23, 0x38, 0xfe, +0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, +0x0a, 0x52, 0x00, 0x19, 0x04, 0xcf, 0xd7, 0x56, +0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, +0x7c, 0x05, 0xe5, 0x62, 0xd0, 0x00, 0x20, 0x53, +0x58, 0x47, 0x58, 0x20, 0xb0, 0x03, 0x80, 0x1a, +0x50, 0x00, 0x08, 0x50, 0x01, 0x08, 0x9d, 0xf1, +0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, +0x01, 0x11, 0xce, 0x52, 0x00, 0x19, 0x00, 0xcf, +0xd7, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, +0x10, 0x4f, 0x38, 0x04, 0x62, 0xd0, 0x00, 0x51, +0x2a, 0x21, 0xf0, 0x54, 0x00, 0x51, 0x2d, 0x54, +0x01, 0x3d, 0x00, 0x10, 0xb0, 0x2a, 0x55, 0xa5, +0x00, 0x3c, 0xa9, 0x01, 0xb0, 0x09, 0x55, 0x93, +0x00, 0x55, 0x94, 0x00, 0x80, 0x0f, 0x62, 0xd0, +0x00, 0x3c, 0xac, 0x01, 0xa0, 0x07, 0x55, 0x93, +0x00, 0x55, 0x94, 0x00, 0x56, 0x00, 0x00, 0x62, +0xd0, 0x00, 0x26, 0x2a, 0x0f, 0x81, 0x7d, 0x3d, +0x00, 0x20, 0xb0, 0x18, 0x62, 0xd0, 0x00, 0x55, +0xa5, 0x01, 0x55, 0xa6, 0x00, 0x55, 0x93, 0x08, +0x55, 0x94, 0x08, 0x56, 0x00, 0x00, 0x26, 0x2a, +0x0f, 0x81, 0x61, 0x3d, 0x00, 0x30, 0xb0, 0x0f, +0x62, 0xd0, 0x00, 0x55, 0xae, 0x00, 0x56, 0x00, +0x00, 0x26, 0x2a, 0x0f, 0x81, 0x4e, 0x3d, 0x00, +0x40, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, 0xae, +0x02, 0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x81, +0x3b, 0x3d, 0x00, 0x50, 0xb0, 0xa7, 0x52, 0x01, +0x54, 0x03, 0x56, 0x02, 0x00, 0x3d, 0x02, 0x00, +0xb0, 0x06, 0x3d, 0x03, 0x01, 0xa0, 0x21, 0x3d, +0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x02, 0xa0, +0x28, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, +0x04, 0xa0, 0x36, 0x3d, 0x02, 0x00, 0xb0, 0x06, +0x3d, 0x03, 0x08, 0xa0, 0x48, 0x80, 0x62, 0x62, +0xd0, 0x00, 0x55, 0xa8, 0x01, 0x51, 0x2f, 0x29, +0x80, 0x53, 0x2f, 0x7c, 0x0c, 0x8c, 0x80, 0x51, +0x62, 0xd0, 0x00, 0x51, 0x2b, 0x53, 0x42, 0x51, +0x2b, 0x53, 0x43, 0x51, 0x2b, 0x53, 0x2e, 0x51, +0x2c, 0x53, 0x0e, 0x55, 0x0d, 0x00, 0x80, 0x39, +0x62, 0xd0, 0x00, 0x51, 0x2b, 0x53, 0x2f, 0x3c, +0xa8, 0x00, 0xa0, 0x09, 0x51, 0x2f, 0x29, 0x80, +0x53, 0x2f, 0x80, 0x25, 0x62, 0xd0, 0x00, 0x26, +0x2f, 0x7f, 0x80, 0x1d, 0x62, 0xd0, 0x00, 0x55, +0xa8, 0x00, 0x26, 0x2f, 0x7f, 0x51, 0x9b, 0x53, +0x24, 0x51, 0x24, 0x53, 0x30, 0x51, 0x9c, 0x53, +0x25, 0x51, 0x25, 0x53, 0x31, 0x7c, 0x0c, 0x8c, +0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2a, +0x0f, 0x55, 0x2b, 0x06, 0x55, 0x2c, 0x05, 0x55, +0x2d, 0x00, 0x80, 0x90, 0x3d, 0x00, 0x60, 0xb0, +0x0f, 0x62, 0xd0, 0x00, 0x55, 0xa9, 0x01, 0x56, +0x00, 0x00, 0x26, 0x2a, 0x0f, 0x80, 0x7d, 0x3d, +0x00, 0x70, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, +0xa9, 0x00, 0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, +0x80, 0x6a, 0x3d, 0x00, 0x80, 0xb0, 0x65, 0x56, +0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0x0f, +0x9c, 0x9f, 0x10, 0x7c, 0x08, 0xd8, 0x7c, 0x05, +0xfb, 0x20, 0x70, 0xfe, 0x71, 0x10, 0x41, 0x00, +0xf7, 0x41, 0x01, 0xf7, 0x70, 0xcf, 0x62, 0xda, +0x00, 0x71, 0x10, 0x41, 0xdc, 0xfe, 0x70, 0xcf, +0x43, 0x01, 0x08, 0x43, 0x00, 0x08, 0x50, 0x00, +0x08, 0x50, 0x1e, 0x08, 0x9c, 0x4b, 0x38, 0xfe, +0x71, 0x01, 0x43, 0xe0, 0x10, 0x43, 0xff, 0x08, +0x70, 0xfe, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, +0x40, 0x10, 0x7c, 0x08, 0x07, 0x7c, 0x05, 0xaf, +0x7c, 0x05, 0xf0, 0x20, 0x93, 0x0b, 0x40, 0x62, +0xe3, 0x38, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, +0x26, 0x2a, 0x0f, 0x38, 0xfc, 0x20, 0x7f, 0x62, +0xd0, 0x00, 0x3c, 0xa5, 0x00, 0xa0, 0x13, 0x9c, +0x38, 0x62, 0xd0, 0x00, 0x3c, 0xa6, 0x00, 0xb0, +0x33, 0x55, 0xa6, 0x01, 0x7c, 0x0a, 0xf9, 0x80, +0x2b, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x93, +0xd0, 0x08, 0x10, 0x7c, 0x04, 0xaf, 0x20, 0x80, +0x06, 0x10, 0x7c, 0x04, 0xab, 0x20, 0x62, 0xd0, +0x00, 0x50, 0x01, 0x3a, 0x94, 0xd0, 0x08, 0x10, +0x7c, 0x04, 0x8c, 0x20, 0x80, 0x06, 0x10, 0x7c, +0x04, 0x88, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x03, +0x56, 0x02, 0x00, 0x56, 0x01, 0x00, 0x56, 0x00, +0x00, 0x80, 0x3e, 0x62, 0xd0, 0x00, 0x91, 0x3a, +0x40, 0x52, 0xfc, 0x04, 0x57, 0x52, 0xfb, 0x0c, +0x58, 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, 0x53, +0x58, 0x3e, 0x57, 0x53, 0x57, 0x52, 0x02, 0x12, +0x57, 0x52, 0x01, 0x1a, 0x58, 0xd0, 0x18, 0x91, +0x19, 0x40, 0x52, 0xfc, 0x04, 0x57, 0x52, 0xfb, +0x0c, 0x58, 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, +0x54, 0x01, 0x3e, 0x57, 0x54, 0x02, 0x77, 0x00, +0x52, 0x00, 0x3b, 0xfa, 0xcf, 0xbe, 0x62, 0xd0, +0x00, 0x52, 0x02, 0x53, 0x57, 0x52, 0x01, 0x53, +0x58, 0x38, 0xfd, 0x20, 0x7f, 0x10, 0x7c, 0x04, +0x3a, 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, +0x08, 0x50, 0x8b, 0x08, 0x7c, 0x04, 0x43, 0x38, +0xfd, 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, +0x08, 0x50, 0x79, 0x08, 0x7c, 0x04, 0x43, 0x38, +0xfd, 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, +0x08, 0x50, 0x7d, 0x08, 0x7c, 0x04, 0x43, 0x38, +0xfd, 0x20, 0x10, 0x50, 0x00, 0x7c, 0x03, 0x5e, +0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x5e, 0x20, +0x10, 0x50, 0xff, 0x7c, 0x03, 0x5e, 0x20, 0x7f, +0x62, 0xd0, 0x00, 0x55, 0xa8, 0x00, 0x55, 0xa9, +0x01, 0x10, 0x7c, 0x04, 0xaf, 0x7c, 0x04, 0x8c, +0x20, 0x9b, 0x3e, 0x62, 0xe3, 0x38, 0x71, 0x10, +0x43, 0x00, 0x08, 0x41, 0x01, 0xf7, 0x70, 0xcf, +0x43, 0x00, 0x08, 0x62, 0xd0, 0x00, 0x55, 0x2a, +0x08, 0x55, 0x2b, 0x06, 0x55, 0x2c, 0x05, 0x55, +0x2e, 0x19, 0x55, 0x2f, 0x03, 0x55, 0x30, 0x56, +0x55, 0x31, 0x45, 0x55, 0x32, 0x00, 0x55, 0x33, +0x00, 0x3c, 0xa8, 0x00, 0xa0, 0x09, 0x51, 0x2f, +0x29, 0x80, 0x53, 0x2f, 0x80, 0x07, 0x62, 0xd0, +0x00, 0x26, 0x2f, 0x7f, 0x10, 0x50, 0x00, 0x08, +0x50, 0x2a, 0x08, 0x50, 0x06, 0x08, 0x50, 0x16, +0x08, 0x7c, 0x06, 0x02, 0x38, 0xfc, 0x7c, 0x05, +0xaf, 0x7c, 0x05, 0xf0, 0x20, 0x91, 0x9a, 0x40, +0x10, 0x7c, 0x08, 0x07, 0x7c, 0x07, 0x8d, 0x20, +0x7c, 0x0c, 0x8c, 0x80, 0x22, 0x62, 0xe3, 0x38, +0x7c, 0x0f, 0x9d, 0x10, 0x7c, 0x07, 0xcb, 0x62, +0xd0, 0x00, 0x20, 0x39, 0x00, 0xa0, 0x09, 0x7c, +0x0a, 0x27, 0x7c, 0x0a, 0x51, 0x80, 0x04, 0x7c, +0x0a, 0xba, 0x9c, 0xb4, 0x9e, 0x71, 0x8f, 0xde, +0x8f, 0xff, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, +0x00, 0x65, 0x57, 0x6b, 0x58, 0x7f, 0x53, 0x55, +0x51, 0x58, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x55, +0x53, 0x56, 0x3e, 0x55, 0x53, 0x55, 0x7f, 0x62, +0xd0, 0x00, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, +0x00, 0x7f, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, +0x00, 0x55, 0x55, 0x06, 0x55, 0x56, 0x00, 0x55, +0x52, 0x00, 0x55, 0x51, 0x00, 0x3c, 0x56, 0x00, +0xb0, 0x06, 0x3c, 0x55, 0x00, 0xa0, 0x1a, 0x70, +0xfb, 0x6e, 0x56, 0x6e, 0x55, 0xd0, 0x0c, 0x62, +0xd0, 0x00, 0x51, 0x57, 0x04, 0x52, 0x51, 0x58, +0x0c, 0x51, 0x65, 0x57, 0x6b, 0x58, 0x8f, 0xde, +0x5f, 0x57, 0x52, 0x5f, 0x58, 0x51, 0x62, 0xd0, +0x00, 0x5a, 0x55, 0x06, 0x55, 0x01, 0x51, 0x55, +0x04, 0x57, 0x0e, 0x58, 0x03, 0x7f, 0x55, 0x55, +0x06, 0x55, 0x56, 0x00, 0x55, 0x52, 0x00, 0x55, +0x51, 0x00, 0x3c, 0x56, 0x00, 0xb0, 0x06, 0x3c, +0x55, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x56, +0x6e, 0x55, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, +0x57, 0x04, 0x52, 0x51, 0x58, 0x0c, 0x51, 0x65, +0x57, 0x6b, 0x58, 0x8f, 0xde, 0x5f, 0x57, 0x52, +0x5f, 0x58, 0x51, 0x62, 0xd0, 0x00, 0x5a, 0x55, +0x06, 0x55, 0x01, 0x51, 0x55, 0x04, 0x57, 0x0e, +0x58, 0x03, 0x7f, 0x60, 0xd4, 0x3e, 0x55, 0x53, +0x56, 0x3e, 0x55, 0x53, 0x55, 0x7f, 0x09, 0x00, +0x60, 0xd4, 0x3e, 0x55, 0x53, 0x56, 0x3e, 0x55, +0x7f, 0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd4, +0x3e, 0x57, 0x53, 0x58, 0x7f, 0x51, 0x58, 0x60, +0xd5, 0x51, 0x56, 0x3f, 0x57, 0x51, 0x55, 0x3f, +0x57, 0x7f, 0x60, 0xd4, 0x3e, 0x57, 0x53, 0x58, +0x3e, 0x57, 0x53, 0x57, 0x7f, 0x06, 0x57, 0x8b, +0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd4, 0x3e, +0x57, 0x53, 0x56, 0x3e, 0x57, 0x16, 0x57, 0x02, +0x53, 0x55, 0x7f, 0x53, 0x55, 0x51, 0x58, 0x09, +0x00, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x55, 0x52, +0x15, 0x3f, 0x55, 0x7f, 0x3e, 0x57, 0x53, 0x57, +0x51, 0x55, 0x12, 0x57, 0x51, 0x56, 0x1a, 0x58, +0x7f, 0x53, 0x57, 0x52, 0xfb, 0x09, 0x00, 0x60, +0xd4, 0x3e, 0x57, 0x7f, 0x0e, 0x56, 0x00, 0x51, +0x56, 0x60, 0xd4, 0x3e, 0x55, 0x53, 0x56, 0x3e, +0x55, 0x7f, 0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, +0xd5, 0x52, 0x14, 0x3f, 0x57, 0x52, 0x15, 0x3f, +0x57, 0x7f, 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x00, +0x3e, 0x57, 0x54, 0x01, 0x7f, 0x52, 0x00, 0x53, +0x55, 0x55, 0x56, 0x00, 0x65, 0x55, 0x6b, 0x56, +0x7f, 0x71, 0x10, 0x41, 0x04, 0xfe, 0x41, 0x05, +0xfe, 0x41, 0x04, 0xfd, 0x41, 0x05, 0xfd, 0x70, +0xcf, 0x43, 0x04, 0x01, 0x43, 0x04, 0x02, 0x71, +0x01, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x53, +0x53, 0x54, 0x3e, 0x53, 0x53, 0x53, 0x7f, 0x53, +0x55, 0x55, 0x56, 0x00, 0x65, 0x55, 0x6b, 0x56, +0x51, 0x55, 0x7f, 0x0e, 0x56, 0x00, 0x51, 0x56, +0x60, 0xd5, 0x51, 0x58, 0x3f, 0x55, 0x7f, 0x0e, +0x58, 0x00, 0x51, 0x58, 0x60, 0xd5, 0x50, 0x00, +0x3f, 0x57, 0x7f, 0x3e, 0x57, 0x12, 0x55, 0x54, +0x02, 0x51, 0x58, 0x1a, 0x56, 0x54, 0x01, 0x7f, +0x3e, 0x57, 0x12, 0x55, 0x54, 0x04, 0x51, 0x58, +0x1a, 0x56, 0x54, 0x03, 0x7f, 0x00, 0x2a, 0x00, +0x16, 0x00, 0x49, 0x00, 0x08, 0x00, 0x59, 0x00, +0x20, 0x00, 0x81, 0x00, 0x0a, 0x00, 0x8f, 0x00, +0x04, 0x00, 0x93, 0x04, 0x08, 0x08, 0x08, 0x08, +0x00, 0x97, 0x00, 0x04, 0x00, 0x9b, 0x02, 0x56, +0x45, 0x00, 0x9d, 0x00, 0x08, 0x00, 0xa5, 0x06, +0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0xab, +0x00, 0x05, 0x00, 0xb0, 0x01, 0x03, 0xff, 0x00, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/cypress_touchkey_236/gogh_tkey_fw.h b/drivers/input/keyboard/cypress_touchkey_236/gogh_tkey_fw.h new file mode 100644 index 00000000000..391a733b18c --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/gogh_tkey_fw.h @@ -0,0 +1,707 @@ +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +/* fw version 0x0E */ + +unsigned char firmware_data[8192] = { +0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x00, 0x68, 0x7e, +0x7e, 0x30, 0x30, 0x30, 0x7d, 0x04, 0x83, 0x7e, 0x7e, 0x30, 0x30, 0x30, +0x7d, 0x05, 0xd0, 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x40, 0x71, 0x10, 0x62, +0xe3, 0x06, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, +0x38, 0x5d, 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, 0xfa, 0x01, 0x40, 0x4f, +0x5b, 0x01, 0x03, 0x53, 0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, 0x40, +0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, 0xef, 0x18, 0x60, 0xd5, +0x55, 0xf8, 0x00, 0x55, 0xf9, 0x00, 0x71, 0x10, 0x62, 0xe0, 0x1a, 0x70, +0xef, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x41, 0xe1, 0xfe, 0x70, 0xef, 0x62, +0xe3, 0x38, 0x62, 0xd1, 0x03, 0x50, 0x80, 0x4e, 0x62, 0xd3, 0x03, 0x62, +0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, 0x00, 0x71, 0xc0, 0x7c, 0x03, +0x0e, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x57, 0xb2, 0x08, 0x28, 0x53, 0x68, +0x18, 0x75, 0x09, 0x00, 0x28, 0x4b, 0x51, 0x68, 0x80, 0x04, 0x75, 0x09, +0x00, 0x62, 0xe3, 0x00, 0x08, 0x28, 0x60, 0xd5, 0x74, 0xa0, 0x4b, 0x18, +0x75, 0x09, 0x00, 0x08, 0x28, 0x53, 0x68, 0x18, 0x75, 0x09, 0x00, 0x08, +0x28, 0xa0, 0x1c, 0x53, 0x67, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, +0x68, 0x47, 0x68, 0xff, 0xb0, 0x06, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x18, +0x7a, 0x67, 0xbf, 0xeb, 0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, +0x53, 0x67, 0x50, 0x00, 0x3f, 0x68, 0x47, 0x68, 0xff, 0xb0, 0x08, 0x5d, +0xd5, 0x74, 0x60, 0xd5, 0x50, 0x00, 0x7a, 0x67, 0xbf, 0xef, 0x18, 0x8f, +0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, 0xef, 0x62, 0xe0, 0x00, +0x41, 0xfe, 0xe7, 0x43, 0xfe, 0x10, 0x71, 0x10, 0x62, 0xe0, 0x1a, 0x70, +0xef, 0x62, 0xe2, 0x00, 0x7c, 0x1b, 0x74, 0x8f, 0xff, 0x7f, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x01, 0x99, +0x03, 0x33, 0x06, 0x66, 0x0c, 0xcc, 0x19, 0x99, 0x33, 0x33, 0x66, 0x66, +0xcc, 0xcc, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0b, 0xff, 0x18, 0x00, +0x2f, 0xff, 0x5f, 0xff, 0xbf, 0xff, 0x01, 0x66, 0x02, 0xcc, 0x05, 0x99, +0x0b, 0x32, 0x16, 0x66, 0x2c, 0xcc, 0x59, 0x98, 0xb3, 0x32, 0x01, 0x33, +0x02, 0x66, 0x04, 0xcc, 0x09, 0x99, 0x13, 0x33, 0x26, 0x65, 0x4c, 0xcc, +0x99, 0x99, 0x1e, 0x10, 0x70, 0xef, 0x62, 0x61, 0x00, 0x62, 0xfd, 0x00, +0x62, 0xcd, 0x00, 0x62, 0xce, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, +0x62, 0xa0, 0x00, 0x62, 0xa1, 0x80, 0x62, 0xa2, 0xc0, 0x62, 0xa3, 0x0c, +0x62, 0xa8, 0x00, 0x62, 0xa6, 0x00, 0x62, 0xa7, 0x00, 0x62, 0x7c, 0x33, +0x62, 0x7a, 0x00, 0x62, 0x7b, 0x00, 0x62, 0x79, 0x00, 0x62, 0x36, 0x00, +0x62, 0x37, 0x00, 0x62, 0x38, 0x00, 0x62, 0x39, 0x00, 0x62, 0x3a, 0x00, +0x62, 0x3b, 0x00, 0x62, 0x3c, 0x00, 0x62, 0x3d, 0x00, 0x62, 0x3e, 0x00, +0x62, 0x3f, 0x00, 0x62, 0x40, 0x00, 0x62, 0x41, 0x00, 0x62, 0x42, 0x00, +0x62, 0x43, 0x00, 0x62, 0x44, 0x00, 0x62, 0x45, 0x00, 0x62, 0x46, 0x00, +0x62, 0x47, 0x00, 0x62, 0x48, 0x00, 0x62, 0x49, 0x00, 0x62, 0x4a, 0x00, +0x62, 0x4b, 0x00, 0x62, 0x4c, 0x00, 0x62, 0x4d, 0x00, 0x62, 0x4e, 0x00, +0x62, 0x4f, 0x00, 0x62, 0xca, 0x20, 0x62, 0xd6, 0x44, 0x62, 0xcf, 0x00, +0x62, 0xcb, 0x00, 0x62, 0xc8, 0x00, 0x62, 0xcc, 0x00, 0x62, 0xc9, 0x00, +0x62, 0xd7, 0x00, 0x62, 0xa9, 0x00, 0x62, 0x2b, 0x00, 0x62, 0xb0, 0x00, +0x62, 0xb3, 0x02, 0x62, 0xb6, 0x00, 0x62, 0xb2, 0x00, 0x62, 0xb5, 0x00, +0x62, 0xb8, 0x00, 0x62, 0xb1, 0x00, 0x62, 0xb4, 0x00, 0x62, 0xb7, 0x00, +0x62, 0x33, 0x00, 0x62, 0x34, 0x00, 0x62, 0x35, 0x00, 0x71, 0x10, 0x62, +0x54, 0x00, 0x62, 0x55, 0x00, 0x62, 0x56, 0x00, 0x62, 0x57, 0x00, 0x62, +0x58, 0x00, 0x62, 0x59, 0x00, 0x62, 0x5a, 0x00, 0x62, 0x5b, 0x00, 0x62, +0xdc, 0x00, 0x62, 0xe2, 0x00, 0x62, 0xd1, 0x00, 0x62, 0xdd, 0x00, 0x62, +0xd8, 0x02, 0x62, 0xd9, 0xb0, 0x62, 0xda, 0x00, 0x62, 0xdb, 0x00, 0x62, +0xdf, 0x00, 0x62, 0x29, 0x00, 0x62, 0x30, 0x00, 0x62, 0xbd, 0x00, 0x70, +0xef, 0x70, 0xef, 0x62, 0x00, 0x18, 0x71, 0x10, 0x62, 0x00, 0x18, 0x62, +0x01, 0x92, 0x70, 0xef, 0x62, 0x04, 0x03, 0x71, 0x10, 0x62, 0x04, 0x03, +0x62, 0x05, 0xbf, 0x70, 0xef, 0x62, 0x08, 0x28, 0x71, 0x10, 0x62, 0x08, +0x28, 0x62, 0x09, 0x28, 0x70, 0xef, 0x62, 0x0c, 0x00, 0x71, 0x10, 0x62, +0x0c, 0x00, 0x62, 0x0d, 0x00, 0x70, 0xef, 0x62, 0x10, 0x00, 0x71, 0x10, +0x62, 0x10, 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, 0x62, 0x01, 0x00, 0x62, +0x05, 0x00, 0x62, 0x09, 0x00, 0x62, 0x0d, 0x00, 0x62, 0x11, 0x00, 0x70, +0xef, 0x7f, 0x55, 0x02, 0x18, 0x55, 0x03, 0x03, 0x55, 0x04, 0x28, 0x7c, +0x03, 0x1b, 0x7f, 0x7c, 0x01, 0xb4, 0x70, 0xef, 0x7f, 0x30, 0x31, 0x32, +0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, +0x46, 0x62, 0xd0, 0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, 0xe0, 0x08, 0x21, +0xf8, 0x29, 0x00, 0x70, 0xfe, 0x60, 0xe0, 0x70, 0xef, 0x4b, 0x4b, 0x4b, +0x4b, 0x51, 0x02, 0x21, 0xf7, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, +0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, +0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, +0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, +0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, +0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, +0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, +0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, +0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, +0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x47, +0x00, 0x00, 0x49, 0x01, 0x00, 0x29, 0x08, 0x60, 0x00, 0x57, 0x01, 0x79, +0xbf, 0xfe, 0x18, 0x71, 0x10, 0x60, 0xe0, 0x70, 0xef, 0x71, 0x01, 0x7f, +0x08, 0x67, 0x67, 0x67, 0x67, 0x21, 0x0f, 0xff, 0x40, 0x9f, 0x4e, 0x18, +0x21, 0x0f, 0xff, 0x39, 0x9f, 0x47, 0x7f, 0x08, 0x10, 0x28, 0xa0, 0x0b, +0x9f, 0x3f, 0x20, 0x18, 0x75, 0xdf, 0xf5, 0x74, 0x8f, 0xf2, 0x38, 0xfe, +0x7f, 0x50, 0x0d, 0x9f, 0x30, 0x50, 0x0a, 0x9f, 0x2c, 0x7f, 0x70, 0xbf, +0x62, 0xd3, 0x03, 0x4f, 0x52, 0xfb, 0xa0, 0x15, 0x7b, 0xfb, 0x52, 0xfc, +0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9f, 0x15, 0x4f, 0x62, 0xd3, 0x03, +0x77, 0xfd, 0x8f, 0xe9, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, +0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x02, +0xef, 0x80, 0x04, 0x2e, 0x02, 0x10, 0x51, 0x02, 0x60, 0x00, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, +0x29, 0x00, 0xa0, 0x06, 0x26, 0x04, 0xf7, 0x80, 0x04, 0x2e, 0x04, 0x08, +0x51, 0x04, 0x60, 0x08, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, +0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x04, +0xdf, 0x80, 0x04, 0x2e, 0x04, 0x20, 0x51, 0x04, 0x60, 0x08, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x08, 0x10, 0x70, 0x3f, 0x71, 0x80, 0x5d, 0xd3, 0x08, +0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x51, 0x08, 0x60, 0xd3, 0x2e, 0x05, +0x80, 0x49, 0xd7, 0x08, 0xa0, 0x09, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x00, +0x80, 0x08, 0x49, 0xd7, 0x20, 0xa0, 0x03, 0x80, 0xa6, 0x51, 0x05, 0x21, +0x0e, 0xe0, 0x01, 0x80, 0x11, 0x80, 0x67, 0x80, 0x79, 0x80, 0x47, 0x80, +0x96, 0x80, 0x94, 0x80, 0x92, 0x80, 0x90, 0x80, 0x97, 0x5d, 0xd8, 0x21, +0xfe, 0x39, 0x40, 0xa0, 0x06, 0x62, 0xd7, 0x00, 0x80, 0x8a, 0x49, 0xd8, +0x01, 0xb0, 0x0f, 0x55, 0x0c, 0x02, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x02, +0x62, 0xd7, 0x10, 0x80, 0x77, 0x55, 0x0c, 0x01, 0x26, 0x05, 0xf0, 0x2e, +0x05, 0x06, 0x5f, 0x07, 0x06, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, 0x00, +0x60, 0xd8, 0x76, 0x07, 0x62, 0xd7, 0x14, 0x80, 0x5b, 0x51, 0x0a, 0x78, +0x3a, 0x07, 0xc0, 0x0f, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, 0x00, 0x60, +0xd8, 0x76, 0x07, 0x2e, 0x05, 0x20, 0x60, 0xd8, 0x62, 0xd7, 0x04, 0x80, +0x3f, 0x5d, 0xd8, 0x3a, 0x0a, 0xd0, 0x2b, 0xa0, 0x29, 0x53, 0x07, 0x53, +0x06, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x04, 0x80, 0x18, 0x51, 0x0b, 0x78, +0x3a, 0x07, 0xc0, 0x16, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x5d, 0xd8, 0x54, +0x00, 0x2e, 0x05, 0x10, 0x76, 0x07, 0x80, 0x01, 0x62, 0xd7, 0x10, 0x80, +0x0f, 0x62, 0xd7, 0x00, 0x80, 0x0a, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x00, +0x55, 0x0c, 0x00, 0x18, 0x60, 0xd0, 0x18, 0x60, 0xd3, 0x20, 0x18, 0x7e, +0x62, 0xd0, 0x00, 0x71, 0x10, 0x41, 0x04, 0xfc, 0x43, 0x05, 0x03, 0x70, +0xef, 0x26, 0x03, 0xfc, 0x51, 0x03, 0x60, 0x04, 0x55, 0x0c, 0x00, 0x90, +0x28, 0x90, 0x2d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x50, 0x00, 0x53, 0x06, +0x71, 0x10, 0x43, 0x04, 0x03, 0x43, 0x05, 0x03, 0x70, 0xef, 0x2e, 0x03, +0x03, 0x51, 0x03, 0x60, 0x04, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0x05, 0x21, +0xb0, 0x26, 0x05, 0x4f, 0x7f, 0x41, 0xe0, 0x7f, 0x43, 0xe0, 0x80, 0x7f, +0x43, 0xd6, 0x31, 0x7f, 0x41, 0xe0, 0x7f, 0x41, 0xd6, 0xfe, 0x7f, 0x62, +0xd0, 0x00, 0x4f, 0x52, 0xfd, 0x53, 0x0a, 0x52, 0xfc, 0x53, 0x0b, 0x52, +0xfb, 0x53, 0x09, 0x52, 0xfa, 0x53, 0x08, 0x70, 0x3f, 0x71, 0xc0, 0x7f, +0x08, 0x5d, 0xa4, 0x04, 0x1b, 0x5d, 0xa5, 0x0c, 0x1a, 0x55, 0x1c, 0x01, +0x18, 0x7e, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x53, 0x1e, 0x64, +0x5c, 0x62, 0xd3, 0x00, 0x52, 0x98, 0x62, 0xd3, 0x00, 0x13, 0x55, 0x62, +0xd3, 0x00, 0x54, 0x5b, 0x62, 0xd3, 0x00, 0x52, 0x97, 0x62, 0xd3, 0x00, +0x1b, 0x54, 0x62, 0xd3, 0x00, 0x54, 0x5a, 0x48, 0x5a, 0x80, 0xb0, 0x33, +0x3d, 0x5a, 0x00, 0xb0, 0x7b, 0x51, 0x0d, 0x3b, 0x5b, 0xc0, 0x75, 0x52, +0x5b, 0x58, 0x1e, 0x01, 0x00, 0x6d, 0x62, 0xd3, 0x00, 0x05, 0x47, 0xc0, +0x09, 0x51, 0x0f, 0x3b, 0x47, 0xd0, 0x12, 0xa0, 0x10, 0x56, 0x47, 0x00, +0x5b, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x07, 0x55, 0x01, 0x0f, 0x54, 0x00, +0x80, 0x41, 0x3d, 0x5a, 0xff, 0xb0, 0x09, 0x50, 0xff, 0x12, 0x0e, 0x3b, +0x5b, 0xc0, 0x20, 0x62, 0xd3, 0x00, 0x56, 0x5b, 0x00, 0x56, 0x5a, 0x00, +0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x51, 0x78, 0xd0, 0x03, 0x50, +0x00, 0x54, 0x51, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x2c, 0x62, 0xd3, +0x00, 0x52, 0x98, 0x62, 0xd3, 0x00, 0x54, 0x55, 0x62, 0xd3, 0x00, 0x52, +0x97, 0x62, 0xd3, 0x00, 0x54, 0x54, 0x51, 0x1e, 0x64, 0x5c, 0x62, 0xd3, +0x00, 0x56, 0x5b, 0x00, 0x56, 0x5a, 0x00, 0x5b, 0x67, 0x5c, 0x62, 0xd3, +0x00, 0x51, 0x12, 0x54, 0x51, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0xbf, +0x62, 0xd0, 0x00, 0x70, 0xbf, 0x08, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x4a, +0x53, 0x19, 0x55, 0x18, 0x00, 0x18, 0x08, 0x90, 0x7e, 0x62, 0xd3, 0x00, +0x23, 0x4d, 0xb0, 0x2c, 0x51, 0x10, 0x04, 0x19, 0x0e, 0x18, 0x00, 0x18, +0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x5b, 0x12, 0x19, 0x52, 0x5a, 0x1a, +0x18, 0xc0, 0x39, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x4e, 0x78, +0x54, 0x4e, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x3e, 0x80, 0x18, 0x51, +0x10, 0x14, 0x19, 0x1e, 0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, 0x00, +0x52, 0x5b, 0x12, 0x19, 0x52, 0x5a, 0x1a, 0x18, 0xc0, 0x0e, 0x5b, 0x67, +0x90, 0x31, 0x62, 0xd3, 0x00, 0x2d, 0x4d, 0x50, 0x01, 0x80, 0x24, 0x5b, +0x67, 0x08, 0x90, 0x23, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x4d, 0x62, 0xd3, +0x00, 0x20, 0x51, 0x11, 0x54, 0x4e, 0x50, 0x00, 0x80, 0x0d, 0x5b, 0x67, +0x90, 0x0d, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x4d, 0x50, 0x00, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x5c, 0x18, 0x21, 0x07, 0xf0, +0x01, 0x7f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x70, 0xbf, +0x70, 0xbf, 0x62, 0xd3, 0x00, 0x50, 0x03, 0x78, 0x08, 0x5c, 0x56, 0x4a, +0x2d, 0x18, 0x78, 0xdf, 0xf8, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, 0xd0, +0x00, 0x55, 0x14, 0x00, 0x50, 0x03, 0x78, 0x08, 0x9f, 0x34, 0x39, 0x01, +0xb0, 0x04, 0x55, 0x14, 0x01, 0x18, 0x78, 0xdf, 0xf3, 0x51, 0x14, 0x7f, +0x50, 0x03, 0x78, 0x08, 0x9e, 0x64, 0x18, 0x78, 0xdf, 0xfa, 0x7f, 0x98, +0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0xd8, 0xd9, 0xda, 0xdb, +0xdf, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x70, 0xbf, +0x62, 0xd0, 0x00, 0x62, 0xd3, 0x00, 0x57, 0x00, 0x56, 0x4d, 0x00, 0x79, +0xdf, 0xfb, 0x62, 0xd3, 0x00, 0x57, 0x02, 0x50, 0x03, 0x54, 0x4e, 0x79, +0xdf, 0xfc, 0x62, 0xd3, 0x00, 0x50, 0x14, 0x57, 0x02, 0x54, 0x51, 0x79, +0xdf, 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x55, 0x0d, 0x28, 0x55, 0x0e, 0x05, +0x55, 0x0f, 0x14, 0x55, 0x10, 0x01, 0x55, 0x11, 0x03, 0x55, 0x12, 0x14, +0x55, 0x22, 0x04, 0x55, 0x1f, 0x14, 0x43, 0x61, 0x0d, 0x57, 0x00, 0x50, +0x02, 0x90, 0x9b, 0x50, 0x04, 0xff, 0x98, 0x29, 0x00, 0x60, 0xa9, 0x62, +0xa0, 0x08, 0x43, 0xa2, 0x04, 0x62, 0xa3, 0x70, 0x43, 0x7a, 0x01, 0x43, +0xdf, 0x01, 0x50, 0x01, 0x57, 0x0c, 0x90, 0x11, 0x90, 0x46, 0x57, 0x0d, +0x50, 0x99, 0x91, 0x45, 0x50, 0x01, 0x57, 0x0e, 0x90, 0x03, 0x90, 0x38, +0x7f, 0x62, 0xd0, 0x00, 0x21, 0x03, 0x53, 0x21, 0x64, 0x64, 0x64, 0x64, +0x64, 0x29, 0x80, 0x60, 0xa1, 0x5b, 0x78, 0x21, 0x0f, 0x29, 0x08, 0x74, +0x53, 0x20, 0x12, 0x22, 0x02, 0x21, 0x5c, 0x50, 0x00, 0x53, 0x1d, 0x53, +0x23, 0x29, 0x01, 0x79, 0xa0, 0x08, 0x64, 0x6b, 0x1d, 0x6b, 0x23, 0x8f, +0xf5, 0x60, 0xb5, 0x51, 0x1d, 0x60, 0xb4, 0x7f, 0x50, 0x03, 0x78, 0x08, +0x90, 0x27, 0x90, 0x59, 0x18, 0x78, 0xdf, 0xf8, 0x7f, 0x41, 0xdf, 0xfe, +0x71, 0x10, 0x41, 0xd8, 0xfd, 0x70, 0xef, 0x41, 0x61, 0xf3, 0x41, 0xa2, +0xfb, 0x41, 0xa0, 0xf7, 0x62, 0xa3, 0x00, 0x62, 0xa9, 0x00, 0x7f, 0x01, +0x80, 0x01, 0x20, 0x01, 0x10, 0x64, 0x5c, 0xff, 0xf6, 0x4b, 0x74, 0xff, +0xf2, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1d, 0x10, 0x5b, 0x64, 0x64, 0x5c, +0x71, 0x10, 0x5e, 0x01, 0x2a, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, +0x00, 0x22, 0x1d, 0x61, 0x00, 0x36, 0x1d, 0xff, 0x18, 0xfe, 0xe9, 0x5c, +0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x7f, 0x62, 0xd0, 0x00, +0x10, 0x73, 0x53, 0x1d, 0x71, 0x10, 0x5b, 0xfe, 0xd3, 0x5c, 0x5e, 0x00, +0x22, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x18, 0x64, 0x64, 0x5c, 0x71, 0x10, +0x5e, 0x01, 0x22, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, 0x00, 0x2a, +0x1d, 0x61, 0x00, 0x70, 0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, +0x1e, 0x50, 0x00, 0x53, 0x1a, 0x53, 0x1b, 0x51, 0x1e, 0x5c, 0x62, 0xd3, +0x00, 0x52, 0x24, 0x53, 0x1f, 0x43, 0xa0, 0x01, 0x51, 0x1f, 0x60, 0xfd, +0x41, 0xa3, 0xdf, 0x51, 0x1e, 0x9f, 0x7a, 0x9f, 0x81, 0x58, 0x23, 0x55, +0x1c, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, 0x43, 0xb3, 0x01, 0x51, +0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1e, 0x9f, 0x5f, 0x9f, 0x91, +0x43, 0xa3, 0x20, 0x41, 0xa0, 0xfe, 0x62, 0xfd, 0x00, 0x50, 0xff, 0x4c, +0x1b, 0x14, 0x1b, 0x51, 0x20, 0x11, 0x08, 0xfe, 0x60, 0x4c, 0x1a, 0x1c, +0x1a, 0xd0, 0x07, 0x55, 0x1a, 0x00, 0x55, 0x1b, 0x00, 0x51, 0x1e, 0x64, +0x5c, 0x62, 0xd3, 0x00, 0x51, 0x1b, 0x54, 0x98, 0x51, 0x1a, 0x54, 0x97, +0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x28, +0x5a, 0x27, 0x55, 0x1e, 0x02, 0x62, 0xd3, 0x00, 0x58, 0x1e, 0x56, 0x24, +0x80, 0x55, 0x2a, 0x08, 0x55, 0x29, 0x80, 0x51, 0x1e, 0x9f, 0x6b, 0x51, +0x1e, 0x9f, 0x67, 0x70, 0xbf, 0x58, 0x1e, 0x62, 0xd3, 0x00, 0x51, 0x1b, +0x3a, 0x28, 0x51, 0x1a, 0x1a, 0x27, 0xd0, 0x06, 0x51, 0x29, 0x73, 0x25, +0x24, 0x68, 0x29, 0x26, 0x29, 0x7f, 0x51, 0x29, 0x2d, 0x24, 0x7a, 0x2a, +0xbf, 0xd6, 0x7a, 0x1e, 0xdf, 0xc4, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, +0xd0, 0x00, 0x51, 0xb2, 0x11, 0xdc, 0x51, 0xb1, 0x19, 0x05, 0xd0, 0x12, +0x7c, 0x16, 0xfd, 0x39, 0x0f, 0xa0, 0x16, 0x62, 0xd0, 0x00, 0x76, 0xb2, +0x0e, 0xb1, 0x00, 0x80, 0x0c, 0x62, 0xd0, 0x00, 0x55, 0xb2, 0x00, 0x55, +0xb1, 0x00, 0x90, 0xc1, 0x7f, 0x62, 0xd0, 0x00, 0x3c, 0xc0, 0xf0, 0xd0, +0x03, 0x76, 0xc0, 0x62, 0xd0, 0x00, 0x51, 0x30, 0x21, 0x7f, 0x53, 0x68, +0x51, 0xc0, 0x3a, 0x68, 0xb0, 0x58, 0x7c, 0x16, 0xfd, 0x62, 0xd0, 0x00, +0x53, 0xc1, 0x3c, 0xc1, 0x0f, 0xa0, 0x40, 0x3c, 0xb9, 0x00, 0xb0, 0x1f, +0x55, 0xa1, 0x00, 0x55, 0xa2, 0x00, 0x55, 0xa3, 0x00, 0x51, 0xc1, 0x53, +0x67, 0x55, 0x68, 0x00, 0x06, 0x67, 0xa1, 0x0e, 0x68, 0x00, 0x51, 0x68, +0x60, 0xd5, 0x50, 0x08, 0x3f, 0x67, 0x62, 0xd0, 0x00, 0x55, 0xb8, 0x00, +0x3c, 0xbf, 0x00, 0xb0, 0x0a, 0x7c, 0x17, 0x92, 0x62, 0xd0, 0x00, 0x55, +0xbf, 0x01, 0x62, 0xd0, 0x00, 0x55, 0xbc, 0x03, 0x80, 0x0c, 0x62, 0xd0, +0x00, 0x3c, 0xc3, 0x00, 0xb0, 0x04, 0x55, 0xc3, 0x01, 0x7f, 0x62, 0xd0, +0x00, 0x55, 0xb2, 0x00, 0x55, 0xb1, 0x00, 0x3c, 0xbf, 0x01, 0xb0, 0x33, +0x7a, 0xbc, 0x3c, 0xbc, 0x00, 0xb0, 0x3a, 0x3c, 0xbf, 0x01, 0xb0, 0x0a, +0x7c, 0x18, 0x1f, 0x62, 0xd0, 0x00, 0x55, 0xbf, 0x00, 0x62, 0xd0, 0x00, +0x3c, 0xb9, 0x00, 0xb0, 0x0e, 0x51, 0xc1, 0x53, 0x67, 0x55, 0x68, 0x00, +0x06, 0x67, 0xa1, 0x7c, 0x1d, 0xea, 0x62, 0xd0, 0x00, 0x55, 0xc0, 0x00, +0x80, 0x0f, 0x62, 0xd0, 0x00, 0x3c, 0xc3, 0x01, 0xb0, 0x07, 0x55, 0xc3, +0x00, 0x55, 0xc0, 0x00, 0x7f, 0x10, 0x4f, 0x38, 0x1c, 0x62, 0xd0, 0x00, +0x3c, 0xbb, 0x00, 0xb0, 0x05, 0x51, 0xa5, 0x53, 0x24, 0x56, 0x13, 0x00, +0x81, 0x16, 0x56, 0x00, 0x00, 0x81, 0x0a, 0x62, 0xd0, 0x00, 0x3c, 0xbb, +0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x67, 0x55, 0x68, 0x00, 0x06, 0x67, +0xa5, 0x7c, 0x1d, 0x37, 0x52, 0x00, 0x53, 0x65, 0x55, 0x66, 0x00, 0x06, +0x65, 0x24, 0x7c, 0x1d, 0xde, 0x10, 0x52, 0x00, 0x7c, 0x08, 0xd6, 0x20, +0x10, 0x7c, 0x05, 0x9a, 0x20, 0x62, 0xd0, 0x00, 0x39, 0x00, 0xbf, 0xee, +0x3d, 0x00, 0x00, 0xb0, 0x27, 0x7c, 0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x65, +0x65, 0x6b, 0x66, 0x50, 0x00, 0x08, 0x50, 0x03, 0x08, 0x51, 0x66, 0x08, +0x51, 0x65, 0x08, 0x7c, 0x1c, 0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, +0x38, 0xfe, 0x7c, 0x1c, 0xb9, 0x80, 0x82, 0x3d, 0x00, 0x01, 0xb0, 0x2c, +0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x55, 0x63, 0x03, +0x7c, 0x1c, 0x5b, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x66, 0x08, +0x51, 0x65, 0x08, 0x7c, 0x1c, 0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, +0x38, 0xfe, 0x7c, 0x1c, 0xb9, 0x80, 0x52, 0x3d, 0x00, 0x02, 0xb0, 0x21, +0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x55, 0x63, 0x03, +0x7c, 0x1c, 0x5b, 0x70, 0xfb, 0x6e, 0x66, 0x6e, 0x65, 0x70, 0xfb, 0x6e, +0x66, 0x6e, 0x65, 0x7c, 0x1c, 0xb9, 0x80, 0x2d, 0x3d, 0x00, 0x03, 0xb0, +0x28, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x65, 0x65, +0x6b, 0x66, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x66, 0x08, 0x51, +0x65, 0x08, 0x7c, 0x1c, 0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, +0xfe, 0x7c, 0x1c, 0xb9, 0x7c, 0x1c, 0x9d, 0x7c, 0x1c, 0xf2, 0x52, 0x13, +0x7c, 0x1d, 0xd2, 0x02, 0x67, 0x53, 0x67, 0x51, 0x66, 0x0a, 0x68, 0x53, +0x68, 0x7c, 0x1d, 0xa0, 0x06, 0x65, 0x97, 0x0e, 0x66, 0x00, 0x51, 0x66, +0x7c, 0x1c, 0xdc, 0x7c, 0x1c, 0xb9, 0x77, 0x00, 0x3d, 0x00, 0x03, 0xce, +0xf3, 0x77, 0x13, 0x3d, 0x13, 0x03, 0xce, 0xe7, 0x56, 0x00, 0x00, 0x81, +0x06, 0x7c, 0x1c, 0x9d, 0x7c, 0x1c, 0xf2, 0x51, 0x68, 0x60, 0xd4, 0x3e, +0x67, 0x54, 0x14, 0x3e, 0x67, 0x54, 0x15, 0x52, 0x00, 0x53, 0x67, 0x55, +0x68, 0x00, 0x55, 0x65, 0x06, 0x55, 0x66, 0x00, 0x55, 0x62, 0x00, 0x55, +0x61, 0x00, 0x3c, 0x66, 0x00, 0xb0, 0x06, 0x3c, 0x65, 0x00, 0xa0, 0x1a, +0x70, 0xfb, 0x6e, 0x66, 0x6e, 0x65, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, +0x67, 0x04, 0x62, 0x51, 0x68, 0x0c, 0x61, 0x65, 0x67, 0x6b, 0x68, 0x8f, +0xde, 0x5f, 0x67, 0x62, 0x5f, 0x68, 0x61, 0x62, 0xd0, 0x00, 0x5a, 0x65, +0x06, 0x65, 0x03, 0x51, 0x65, 0x04, 0x67, 0x0e, 0x68, 0x03, 0x51, 0x68, +0x60, 0xd4, 0x3e, 0x67, 0x54, 0x16, 0x3e, 0x67, 0x54, 0x17, 0x52, 0x00, +0x53, 0x67, 0x55, 0x68, 0x00, 0x55, 0x65, 0x06, 0x55, 0x66, 0x00, 0x55, +0x62, 0x00, 0x55, 0x61, 0x00, 0x3c, 0x66, 0x00, 0xb0, 0x06, 0x3c, 0x65, +0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x66, 0x6e, 0x65, 0xd0, 0x0c, 0x62, +0xd0, 0x00, 0x51, 0x67, 0x04, 0x62, 0x51, 0x68, 0x0c, 0x61, 0x65, 0x67, +0x6b, 0x68, 0x8f, 0xde, 0x5f, 0x67, 0x62, 0x5f, 0x68, 0x61, 0x62, 0xd0, +0x00, 0x5a, 0x65, 0x06, 0x65, 0x05, 0x51, 0x65, 0x04, 0x67, 0x0e, 0x68, +0x03, 0x51, 0x68, 0x60, 0xd4, 0x3e, 0x67, 0x54, 0x18, 0x3e, 0x67, 0x54, +0x19, 0x50, 0x03, 0x08, 0x5a, 0x67, 0x06, 0x67, 0x14, 0x08, 0x51, 0x67, +0x08, 0x7c, 0x1a, 0xd4, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, 0x67, 0x54, +0x1b, 0x51, 0x68, 0x54, 0x1a, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, +0x7c, 0x1d, 0x4e, 0x06, 0x67, 0x54, 0x7c, 0x1d, 0x85, 0x7c, 0x1c, 0x91, +0x51, 0x67, 0x01, 0x71, 0x7c, 0x1d, 0x4e, 0x51, 0x67, 0x01, 0x69, 0x7c, +0x1d, 0x4e, 0x06, 0x67, 0x81, 0x7c, 0x1d, 0x85, 0x77, 0x00, 0x3d, 0x00, +0x03, 0xce, 0xf7, 0x38, 0xe4, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x1c, 0x10, +0x57, 0x09, 0x50, 0x01, 0x7c, 0x08, 0x11, 0x20, 0x62, 0xd0, 0x00, 0x50, +0x01, 0x10, 0x57, 0xa2, 0x08, 0x28, 0x53, 0x68, 0x18, 0x75, 0x09, 0x00, +0x28, 0x53, 0x67, 0x51, 0x68, 0x08, 0x51, 0x67, 0x20, 0x7c, 0x09, 0x4d, +0x57, 0x0e, 0x50, 0x01, 0x7c, 0x08, 0x11, 0x20, 0x62, 0xd0, 0x00, 0x3c, +0xbb, 0x01, 0xb0, 0x0f, 0x51, 0x24, 0x53, 0x31, 0x51, 0x25, 0x53, 0x32, +0x51, 0x26, 0x53, 0x33, 0x80, 0x10, 0x62, 0xd0, 0x00, 0x51, 0xa5, 0x53, +0x24, 0x51, 0xa6, 0x53, 0x25, 0x51, 0xa7, 0x53, 0x26, 0x10, 0x50, 0x00, +0x7c, 0x08, 0xd6, 0x20, 0x56, 0x13, 0x00, 0x81, 0x16, 0x56, 0x00, 0x00, +0x81, 0x0a, 0x62, 0xd0, 0x00, 0x3c, 0xbb, 0x00, 0xb0, 0x1b, 0x52, 0x00, +0x53, 0x67, 0x55, 0x68, 0x00, 0x06, 0x67, 0xa5, 0x7c, 0x1d, 0x37, 0x52, +0x00, 0x53, 0x65, 0x55, 0x66, 0x00, 0x06, 0x65, 0x24, 0x7c, 0x1d, 0xde, +0x10, 0x52, 0x00, 0x7c, 0x08, 0xd6, 0x20, 0x10, 0x7c, 0x05, 0x9a, 0x20, +0x62, 0xd0, 0x00, 0x39, 0x00, 0xbf, 0xee, 0x3d, 0x00, 0x00, 0xb0, 0x27, +0x7c, 0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x65, 0x65, 0x6b, 0x66, 0x50, 0x00, +0x08, 0x50, 0x03, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, 0x7c, 0x1c, +0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x7c, 0x1c, 0xb9, +0x80, 0x82, 0x3d, 0x00, 0x01, 0xb0, 0x2c, 0x62, 0xd0, 0x00, 0x7c, 0x1c, +0x91, 0x7c, 0x1c, 0xc6, 0x55, 0x63, 0x03, 0x7c, 0x1c, 0x5b, 0x50, 0x00, +0x08, 0x50, 0x05, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, 0x7c, 0x1c, +0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x7c, 0x1c, 0xb9, +0x80, 0x52, 0x3d, 0x00, 0x02, 0xb0, 0x21, 0x62, 0xd0, 0x00, 0x7c, 0x1c, +0x91, 0x7c, 0x1c, 0xc6, 0x55, 0x63, 0x03, 0x7c, 0x1c, 0x5b, 0x70, 0xfb, +0x6e, 0x66, 0x6e, 0x65, 0x70, 0xfb, 0x6e, 0x66, 0x6e, 0x65, 0x7c, 0x1c, +0xb9, 0x80, 0x2d, 0x3d, 0x00, 0x03, 0xb0, 0x28, 0x62, 0xd0, 0x00, 0x7c, +0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x65, 0x65, 0x6b, 0x66, 0x50, 0x00, 0x08, +0x50, 0x05, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, 0x7c, 0x1c, 0x16, +0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x7c, 0x1c, 0xb9, 0x7c, +0x1c, 0x9d, 0x7c, 0x1c, 0xf2, 0x52, 0x13, 0x7c, 0x1d, 0xd2, 0x02, 0x67, +0x53, 0x67, 0x51, 0x66, 0x0a, 0x68, 0x53, 0x68, 0x7c, 0x1d, 0xa0, 0x06, +0x65, 0x97, 0x0e, 0x66, 0x00, 0x51, 0x66, 0x7c, 0x1c, 0xdc, 0x7c, 0x1c, +0xb9, 0x77, 0x00, 0x3d, 0x00, 0x03, 0xce, 0xf3, 0x77, 0x13, 0x3d, 0x13, +0x03, 0xce, 0xe7, 0x56, 0x00, 0x00, 0x81, 0x06, 0x7c, 0x1c, 0x9d, 0x7c, +0x1c, 0xf2, 0x51, 0x68, 0x60, 0xd4, 0x3e, 0x67, 0x54, 0x14, 0x3e, 0x67, +0x54, 0x15, 0x52, 0x00, 0x53, 0x67, 0x55, 0x68, 0x00, 0x55, 0x65, 0x06, +0x55, 0x66, 0x00, 0x55, 0x62, 0x00, 0x55, 0x61, 0x00, 0x3c, 0x66, 0x00, +0xb0, 0x06, 0x3c, 0x65, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x66, 0x6e, +0x65, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x67, 0x04, 0x62, 0x51, 0x68, +0x0c, 0x61, 0x65, 0x67, 0x6b, 0x68, 0x8f, 0xde, 0x5f, 0x67, 0x62, 0x5f, +0x68, 0x61, 0x62, 0xd0, 0x00, 0x5a, 0x65, 0x06, 0x65, 0x03, 0x51, 0x65, +0x04, 0x67, 0x0e, 0x68, 0x03, 0x51, 0x68, 0x60, 0xd4, 0x3e, 0x67, 0x54, +0x16, 0x3e, 0x67, 0x54, 0x17, 0x52, 0x00, 0x53, 0x67, 0x55, 0x68, 0x00, +0x55, 0x65, 0x06, 0x55, 0x66, 0x00, 0x55, 0x62, 0x00, 0x55, 0x61, 0x00, +0x3c, 0x66, 0x00, 0xb0, 0x06, 0x3c, 0x65, 0x00, 0xa0, 0x1a, 0x70, 0xfb, +0x6e, 0x66, 0x6e, 0x65, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x67, 0x04, +0x62, 0x51, 0x68, 0x0c, 0x61, 0x65, 0x67, 0x6b, 0x68, 0x8f, 0xde, 0x5f, +0x67, 0x62, 0x5f, 0x68, 0x61, 0x62, 0xd0, 0x00, 0x5a, 0x65, 0x06, 0x65, +0x05, 0x51, 0x65, 0x04, 0x67, 0x0e, 0x68, 0x03, 0x51, 0x68, 0x60, 0xd4, +0x3e, 0x67, 0x54, 0x18, 0x3e, 0x67, 0x54, 0x19, 0x50, 0x03, 0x08, 0x5a, +0x67, 0x06, 0x67, 0x14, 0x08, 0x51, 0x67, 0x08, 0x7c, 0x1a, 0xd4, 0x38, +0xfd, 0x62, 0xd0, 0x00, 0x51, 0x67, 0x54, 0x1b, 0x51, 0x68, 0x54, 0x1a, +0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, 0x7c, 0x1d, 0x4e, 0x06, 0x67, +0x54, 0x7c, 0x1d, 0x85, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x71, 0x7c, +0x1d, 0x4e, 0x51, 0x67, 0x01, 0x69, 0x7c, 0x1d, 0x4e, 0x06, 0x67, 0x81, +0x7c, 0x1d, 0x85, 0x77, 0x00, 0x3d, 0x00, 0x03, 0xce, 0xf7, 0x56, 0x00, +0x00, 0x80, 0x19, 0x7c, 0x1c, 0x9d, 0x06, 0x67, 0x24, 0x7c, 0x1d, 0x37, +0x52, 0x00, 0x53, 0x65, 0x55, 0x66, 0x00, 0x06, 0x65, 0x31, 0x7c, 0x1d, +0xde, 0x77, 0x00, 0x3d, 0x00, 0x03, 0xcf, 0xe4, 0x38, 0xe4, 0x20, 0x7f, +0x10, 0x4f, 0x38, 0x02, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x01, 0x02, 0x53, +0x67, 0x52, 0xfb, 0x09, 0x00, 0x7c, 0x1d, 0x43, 0x52, 0xfc, 0x01, 0x04, +0x53, 0x65, 0x52, 0xfb, 0x7c, 0x1c, 0xe7, 0x12, 0x67, 0x51, 0x66, 0x1a, +0x68, 0xc0, 0x6f, 0x52, 0xfc, 0x53, 0x67, 0x52, 0xfb, 0x7c, 0x1d, 0x43, +0x52, 0xfc, 0x01, 0x02, 0x53, 0x65, 0x52, 0xfb, 0x7c, 0x1c, 0xe7, 0x12, +0x67, 0x51, 0x66, 0x1a, 0x68, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, +0x1d, 0x6c, 0x54, 0x00, 0x3e, 0x67, 0x54, 0x01, 0x80, 0xb3, 0x62, 0xd0, +0x00, 0x52, 0xfc, 0x01, 0x04, 0x53, 0x67, 0x52, 0xfb, 0x09, 0x00, 0x7c, +0x1d, 0x43, 0x52, 0xfc, 0x53, 0x65, 0x52, 0xfb, 0x60, 0xd4, 0x3e, 0x65, +0x53, 0x66, 0x3e, 0x65, 0x12, 0x67, 0x51, 0x66, 0x1a, 0x68, 0xc0, 0x10, +0x52, 0xfc, 0x01, 0x04, 0x7c, 0x1d, 0x6c, 0x54, 0x00, 0x3e, 0x67, 0x54, +0x01, 0x80, 0x7e, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x67, 0x52, 0xfb, +0x7c, 0x1d, 0x95, 0x80, 0x70, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x67, +0x52, 0xfb, 0x7c, 0x1d, 0x43, 0x52, 0xfc, 0x01, 0x04, 0x53, 0x65, 0x52, +0xfb, 0x7c, 0x1c, 0xe7, 0x12, 0x67, 0x51, 0x66, 0x1a, 0x68, 0xc0, 0x10, +0x52, 0xfc, 0x01, 0x04, 0x7c, 0x1d, 0x6c, 0x54, 0x00, 0x3e, 0x67, 0x54, +0x01, 0x80, 0x42, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x01, 0x02, 0x53, 0x67, +0x52, 0xfb, 0x09, 0x00, 0x7c, 0x1d, 0x43, 0x52, 0xfc, 0x53, 0x65, 0x52, +0xfb, 0x60, 0xd4, 0x3e, 0x65, 0x53, 0x66, 0x3e, 0x65, 0x12, 0x67, 0x51, +0x66, 0x1a, 0x68, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, 0x1d, 0x6c, +0x54, 0x00, 0x3e, 0x67, 0x54, 0x01, 0x80, 0x0d, 0x62, 0xd0, 0x00, 0x52, +0xfc, 0x53, 0x67, 0x52, 0xfb, 0x7c, 0x1d, 0x95, 0x62, 0xd0, 0x00, 0x52, +0x01, 0x53, 0x67, 0x52, 0x00, 0x53, 0x68, 0x38, 0xfe, 0x20, 0x7f, 0x10, +0x4f, 0x38, 0x05, 0x62, 0xd0, 0x00, 0x55, 0xba, 0x00, 0x56, 0x00, 0x00, +0x80, 0xe4, 0x62, 0xd0, 0x00, 0x3c, 0xbb, 0x00, 0xb0, 0x1b, 0x52, 0x00, +0x53, 0x67, 0x55, 0x68, 0x00, 0x06, 0x67, 0xa5, 0x7c, 0x1d, 0x37, 0x52, +0x00, 0x53, 0x65, 0x55, 0x66, 0x00, 0x06, 0x65, 0x24, 0x7c, 0x1d, 0xde, +0x10, 0x52, 0x00, 0x7c, 0x08, 0xd6, 0x20, 0x10, 0x7c, 0x05, 0x9a, 0x20, +0x62, 0xd0, 0x00, 0x39, 0x00, 0xbf, 0xee, 0x3d, 0x00, 0x00, 0xb0, 0x27, +0x7c, 0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x65, 0x65, 0x6b, 0x66, 0x50, 0x00, +0x08, 0x50, 0x03, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, 0x7c, 0x1c, +0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x7c, 0x1c, 0xb9, +0x80, 0x82, 0x3d, 0x00, 0x01, 0xb0, 0x2c, 0x62, 0xd0, 0x00, 0x7c, 0x1c, +0x91, 0x7c, 0x1c, 0xc6, 0x55, 0x63, 0x03, 0x7c, 0x1c, 0x5b, 0x50, 0x00, +0x08, 0x50, 0x05, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, 0x7c, 0x1c, +0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x7c, 0x1c, 0xb9, +0x80, 0x52, 0x3d, 0x00, 0x02, 0xb0, 0x21, 0x62, 0xd0, 0x00, 0x7c, 0x1c, +0x91, 0x7c, 0x1c, 0xc6, 0x55, 0x63, 0x03, 0x7c, 0x1c, 0x5b, 0x70, 0xfb, +0x6e, 0x66, 0x6e, 0x65, 0x70, 0xfb, 0x6e, 0x66, 0x6e, 0x65, 0x7c, 0x1c, +0xb9, 0x80, 0x2d, 0x3d, 0x00, 0x03, 0xb0, 0x28, 0x62, 0xd0, 0x00, 0x7c, +0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x65, 0x65, 0x6b, 0x66, 0x50, 0x00, 0x08, +0x50, 0x05, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, 0x7c, 0x1c, 0x16, +0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x7c, 0x1c, 0xb9, 0x77, +0x00, 0x3d, 0x00, 0x03, 0xcf, 0x19, 0x56, 0x00, 0x00, 0x82, 0x86, 0x62, +0xd0, 0x00, 0x3c, 0xc2, 0x02, 0xa0, 0x9f, 0x7c, 0x1c, 0x91, 0x51, 0x67, +0x01, 0x54, 0x7c, 0x1c, 0xa8, 0x06, 0x67, 0x97, 0x7c, 0x1d, 0x37, 0x7c, +0x1d, 0x5f, 0xd0, 0x16, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x54, 0x7c, +0x1c, 0xa8, 0x06, 0x67, 0x97, 0x7c, 0x1d, 0x37, 0x7c, 0x1e, 0x03, 0x80, +0x17, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, 0x7c, +0x1c, 0xa8, 0x06, 0x67, 0x54, 0x7c, 0x1d, 0x37, 0x7c, 0x1e, 0x03, 0x50, +0x90, 0x13, 0x02, 0x50, 0x01, 0x1b, 0x01, 0xc0, 0x4e, 0x62, 0xd0, 0x00, +0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x81, 0x7c, 0x1c, 0xa8, 0x06, 0x67, +0x97, 0x7c, 0x1d, 0x37, 0x7c, 0x1d, 0x5f, 0xd0, 0x16, 0x7c, 0x1c, 0x91, +0x51, 0x67, 0x01, 0x81, 0x7c, 0x1c, 0xa8, 0x06, 0x67, 0x97, 0x7c, 0x1d, +0x37, 0x7c, 0x1d, 0xf6, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x91, +0x51, 0x67, 0x01, 0x97, 0x7c, 0x1c, 0xa8, 0x06, 0x67, 0x81, 0x7c, 0x1d, +0x37, 0x7c, 0x1d, 0xf6, 0x50, 0x90, 0x13, 0x04, 0x50, 0x01, 0x1b, 0x03, +0xd0, 0x08, 0x62, 0xd0, 0x00, 0x76, 0xba, 0x81, 0xde, 0x62, 0xd0, 0x00, +0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, 0x7c, 0x1c, 0xa8, 0x06, 0x67, +0x81, 0x7c, 0x1d, 0x37, 0x7c, 0x1d, 0x5f, 0xd0, 0x5a, 0x7c, 0x1c, 0x91, +0x7c, 0x1c, 0xc6, 0x06, 0x65, 0x01, 0x0e, 0x66, 0x00, 0x7c, 0x1c, 0xb9, +0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, 0x7c, 0x1c, 0xa8, 0x06, 0x67, +0x81, 0x7c, 0x1d, 0x37, 0x7c, 0x1d, 0x5f, 0xd0, 0xb4, 0x7c, 0x1c, 0x91, +0x7c, 0x1c, 0xc6, 0x06, 0x65, 0x01, 0x0e, 0x66, 0x00, 0x7c, 0x1c, 0xb9, +0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, 0x7c, 0x1c, 0xa8, 0x06, 0x67, +0x81, 0x7c, 0x1d, 0x37, 0x7c, 0x1d, 0x5f, 0xd0, 0x90, 0x7c, 0x1c, 0x91, +0x7c, 0x1c, 0xc6, 0x06, 0x65, 0x01, 0x0e, 0x66, 0x00, 0x7c, 0x1c, 0xb9, +0x80, 0x7f, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, +0x7c, 0x1c, 0xa8, 0x06, 0x67, 0x81, 0x7c, 0x1d, 0x37, 0x3e, 0x67, 0x12, +0x65, 0x51, 0x68, 0x1a, 0x66, 0xd0, 0x62, 0x7c, 0x1c, 0x91, 0x7c, 0x1c, +0xc6, 0x16, 0x65, 0x01, 0x1e, 0x66, 0x00, 0x7c, 0x1c, 0xb9, 0x7c, 0x1c, +0x91, 0x51, 0x67, 0x01, 0x97, 0x7c, 0x1c, 0xa8, 0x06, 0x67, 0x81, 0x7c, +0x1d, 0x37, 0x3e, 0x67, 0x12, 0x65, 0x51, 0x68, 0x1a, 0x66, 0xd0, 0x39, +0x7c, 0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x16, 0x65, 0x01, 0x1e, 0x66, 0x00, +0x7c, 0x1c, 0xb9, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, 0x7c, 0x1c, +0xa8, 0x06, 0x67, 0x81, 0x7c, 0x1d, 0x37, 0x3e, 0x67, 0x12, 0x65, 0x51, +0x68, 0x1a, 0x66, 0xd0, 0x10, 0x7c, 0x1c, 0x91, 0x7c, 0x1c, 0xc6, 0x16, +0x65, 0x01, 0x1e, 0x66, 0x00, 0x7c, 0x1c, 0xb9, 0x62, 0xd0, 0x00, 0x7c, +0x1c, 0x91, 0x51, 0x67, 0x01, 0x69, 0x7c, 0x1c, 0xa8, 0x06, 0x67, 0x71, +0x0e, 0x68, 0x00, 0x7c, 0x1c, 0xb9, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, +0x81, 0x7c, 0x1c, 0xa8, 0x06, 0x67, 0x69, 0x0e, 0x68, 0x00, 0x7c, 0x1c, +0xb9, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, 0x7c, 0x1c, 0xa8, 0x06, +0x67, 0x81, 0x0e, 0x68, 0x00, 0x7c, 0x1c, 0xb9, 0x10, 0x52, 0x00, 0x7c, +0x05, 0xde, 0x20, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, +0x97, 0x7c, 0x1c, 0xa8, 0x06, 0x67, 0x54, 0x7c, 0x1d, 0x37, 0x7c, 0x1d, +0x5f, 0xd0, 0x25, 0x52, 0x00, 0x53, 0x67, 0x55, 0x68, 0x00, 0x06, 0x67, +0xad, 0x0e, 0x68, 0x00, 0x51, 0x68, 0x60, 0xd4, 0x3e, 0x67, 0x7a, 0x67, +0x53, 0x66, 0x06, 0x66, 0x01, 0x51, 0x68, 0x60, 0xd5, 0x51, 0x66, 0x3f, +0x67, 0x80, 0x0a, 0x7c, 0x1c, 0x9d, 0x06, 0x67, 0xad, 0x7c, 0x1d, 0xea, +0x7c, 0x1c, 0x9d, 0x06, 0x67, 0xad, 0x7c, 0x1d, 0x37, 0x50, 0x05, 0x3a, +0x68, 0xd0, 0x58, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x54, 0x53, 0x65, +0x51, 0x68, 0x09, 0x00, 0x53, 0x66, 0x06, 0x67, 0x97, 0x7c, 0x1d, 0x37, +0x3e, 0x67, 0x53, 0x67, 0x51, 0x66, 0x60, 0xd4, 0x3e, 0x65, 0x53, 0x64, +0x3e, 0x65, 0x16, 0x65, 0x02, 0x02, 0x67, 0x53, 0x67, 0x51, 0x64, 0x0a, +0x68, 0x53, 0x68, 0x70, 0xfb, 0x6e, 0x68, 0x6e, 0x67, 0x51, 0x66, 0x60, +0xd5, 0x51, 0x68, 0x3f, 0x65, 0x51, 0x67, 0x3f, 0x65, 0x52, 0x00, 0x53, +0x67, 0x55, 0x68, 0x00, 0x06, 0x67, 0xad, 0x0e, 0x68, 0x00, 0x51, 0x68, +0x60, 0xd5, 0x50, 0x00, 0x3f, 0x67, 0x77, 0x00, 0x3d, 0x00, 0x03, 0xcd, +0x77, 0x62, 0xd0, 0x00, 0x3c, 0xc2, 0x02, 0xb2, 0x50, 0x56, 0x00, 0x00, +0x82, 0x46, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x97, +0x7c, 0x1c, 0xa8, 0x06, 0x67, 0x3b, 0x0e, 0x68, 0x00, 0x7c, 0x1c, 0xb9, +0x7c, 0x1c, 0x91, 0x51, 0x67, 0x01, 0x54, 0x7c, 0x1c, 0xa8, 0x06, 0x67, +0x41, 0x0e, 0x68, 0x00, 0x7c, 0x1c, 0xb9, 0x7c, 0x1c, 0x91, 0x51, 0x67, +0x01, 0x54, 0x7c, 0x1c, 0xa8, 0x51, 0x67, 0x01, 0x97, 0x53, 0x63, 0x51, +0x68, 0x7c, 0x1d, 0xac, 0x51, 0x65, 0x12, 0x63, 0x51, 0x66, 0x1a, 0x64, +0xd0, 0x21, 0x7c, 0x1d, 0xa0, 0x51, 0x65, 0x01, 0x54, 0x53, 0x63, 0x51, +0x66, 0x7c, 0x1d, 0xac, 0x06, 0x65, 0x97, 0x7c, 0x1d, 0x77, 0x12, 0x63, +0x54, 0x02, 0x51, 0x66, 0x1a, 0x64, 0x54, 0x01, 0x80, 0x07, 0x56, 0x02, +0x00, 0x56, 0x01, 0x00, 0x62, 0xd0, 0x00, 0x06, 0x67, 0x35, 0x0e, 0x68, +0x00, 0x51, 0x68, 0x60, 0xd5, 0x52, 0x01, 0x3f, 0x67, 0x52, 0x02, 0x3f, +0x67, 0x3d, 0x00, 0x00, 0xb0, 0x41, 0x97, 0xe9, 0x40, 0x51, 0x67, 0x01, +0x97, 0x97, 0xf9, 0x40, 0x55, 0x63, 0x03, 0x97, 0xa6, 0x40, 0x70, 0xfb, +0x6e, 0x66, 0x6e, 0x65, 0x06, 0x67, 0x3b, 0x0e, 0x68, 0x00, 0x97, 0xf5, +0x40, 0x97, 0xca, 0x40, 0x51, 0x67, 0x01, 0x54, 0x97, 0xda, 0x40, 0x55, +0x63, 0x03, 0x97, 0x87, 0x40, 0x70, 0xfb, 0x6e, 0x66, 0x6e, 0x65, 0x06, +0x67, 0x41, 0x0e, 0x68, 0x00, 0x97, 0xd6, 0x40, 0x81, 0x1f, 0x3d, 0x00, +0x01, 0xb0, 0x66, 0x62, 0xd0, 0x00, 0x97, 0xa1, 0x40, 0x51, 0x67, 0x01, +0x97, 0x97, 0xb1, 0x40, 0x55, 0x63, 0x05, 0x97, 0x5e, 0x40, 0x50, 0x00, +0x08, 0x50, 0x03, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, 0x7c, 0x1c, +0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x06, 0x67, 0x3b, +0x0e, 0x68, 0x00, 0x97, 0x9c, 0x40, 0x97, 0x71, 0x40, 0x51, 0x67, 0x01, +0x54, 0x97, 0x81, 0x40, 0x55, 0x63, 0x05, 0x97, 0x2e, 0x40, 0x50, 0x00, +0x08, 0x50, 0x03, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, 0x7c, 0x1c, +0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x06, 0x67, 0x41, +0x0e, 0x68, 0x00, 0x97, 0x6c, 0x40, 0x80, 0xb5, 0x3d, 0x00, 0x02, 0xb0, +0x6a, 0x62, 0xd0, 0x00, 0x97, 0x37, 0x40, 0x51, 0x67, 0x01, 0x97, 0x97, +0x47, 0x40, 0x65, 0x65, 0x6b, 0x66, 0x65, 0x65, 0x6b, 0x66, 0x50, 0x00, +0x08, 0x50, 0x03, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, 0x7c, 0x1c, +0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x06, 0x67, 0x3b, +0x0e, 0x68, 0x00, 0x97, 0x30, 0x40, 0x97, 0x05, 0x40, 0x51, 0x67, 0x01, +0x54, 0x97, 0x15, 0x40, 0x65, 0x65, 0x6b, 0x66, 0x65, 0x65, 0x6b, 0x66, +0x50, 0x00, 0x08, 0x50, 0x03, 0x08, 0x51, 0x66, 0x08, 0x51, 0x65, 0x08, +0x7c, 0x1c, 0x16, 0x18, 0x53, 0x65, 0x18, 0x53, 0x66, 0x38, 0xfe, 0x06, +0x67, 0x41, 0x0e, 0x68, 0x00, 0x96, 0xfe, 0x40, 0x80, 0x47, 0x3d, 0x00, +0x03, 0xb0, 0x42, 0x62, 0xd0, 0x00, 0x96, 0xc9, 0x40, 0x51, 0x67, 0x01, +0x97, 0x96, 0xd9, 0x40, 0x55, 0x63, 0x05, 0x96, 0x86, 0x40, 0x70, 0xfb, +0x6e, 0x66, 0x6e, 0x65, 0x06, 0x67, 0x3b, 0x0e, 0x68, 0x00, 0x96, 0xd5, +0x40, 0x96, 0xaa, 0x40, 0x51, 0x67, 0x01, 0x54, 0x96, 0xba, 0x40, 0x55, +0x63, 0x05, 0x96, 0x67, 0x40, 0x70, 0xfb, 0x6e, 0x66, 0x6e, 0x65, 0x06, +0x67, 0x41, 0x0e, 0x68, 0x00, 0x96, 0xb6, 0x40, 0x62, 0xd0, 0x00, 0x96, +0x88, 0x40, 0x51, 0x67, 0x01, 0x54, 0x96, 0x98, 0x40, 0x51, 0x67, 0x01, +0x97, 0x53, 0x63, 0x51, 0x68, 0x97, 0x91, 0x40, 0x51, 0x65, 0x12, 0x63, +0x51, 0x66, 0x1a, 0x64, 0xd0, 0x21, 0x97, 0x78, 0x40, 0x51, 0x65, 0x01, +0x54, 0x53, 0x63, 0x51, 0x66, 0x97, 0x79, 0x40, 0x06, 0x65, 0x97, 0x97, +0x3e, 0x40, 0x12, 0x63, 0x54, 0x04, 0x51, 0x66, 0x1a, 0x64, 0x54, 0x03, +0x80, 0x07, 0x56, 0x04, 0x00, 0x56, 0x03, 0x00, 0x62, 0xd0, 0x00, 0x06, +0x67, 0x35, 0x0e, 0x68, 0x00, 0x51, 0x68, 0x60, 0xd5, 0x52, 0x03, 0x3f, +0x67, 0x52, 0x04, 0x3f, 0x67, 0x77, 0x00, 0x3d, 0x00, 0x03, 0xcd, 0xb7, +0x62, 0xd0, 0x00, 0x3c, 0xc2, 0x02, 0xa0, 0x18, 0x3c, 0xba, 0x00, 0xa0, +0x13, 0x50, 0x01, 0x08, 0x50, 0x2c, 0x08, 0x90, 0x0e, 0x38, 0xfe, 0x7c, +0x0a, 0x85, 0x10, 0x7c, 0x07, 0x74, 0x20, 0x38, 0xfb, 0x20, 0x7f, 0x10, +0x4f, 0x80, 0x02, 0x40, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x67, 0x52, +0xfb, 0x53, 0x68, 0x51, 0x67, 0x11, 0x01, 0x54, 0xfc, 0x51, 0x68, 0x19, +0x00, 0x54, 0xfb, 0x3c, 0x68, 0x00, 0xbf, 0xe4, 0x3c, 0x67, 0x00, 0xbf, +0xdf, 0x20, 0x7f, 0x10, 0x7c, 0x04, 0x69, 0x7c, 0x04, 0x4b, 0x7c, 0x04, +0x2d, 0x20, 0x7f, 0x10, 0x7c, 0x04, 0x65, 0x7c, 0x04, 0x47, 0x7c, 0x04, +0x29, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0x4a, 0x12, 0x5b, 0x50, 0x00, +0x1a, 0x5a, 0xd0, 0x0f, 0x51, 0x4b, 0x12, 0x5d, 0x50, 0x00, 0x1a, 0x5c, +0xd0, 0x05, 0x50, 0x0f, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x51, 0x5d, 0x12, +0x5b, 0x51, 0x5c, 0x1a, 0x5a, 0xd0, 0x05, 0x50, 0x00, 0x80, 0x06, 0x62, +0xd0, 0x00, 0x50, 0x01, 0x7f, 0x10, 0x4f, 0x38, 0x05, 0x62, 0xd0, 0x00, +0x51, 0x5b, 0x54, 0x02, 0x51, 0x5a, 0x54, 0x01, 0x56, 0x04, 0x00, 0x56, +0x00, 0x00, 0x56, 0x03, 0x00, 0x80, 0x61, 0x95, 0x84, 0x40, 0x06, 0x67, +0x4a, 0x0e, 0x68, 0x00, 0x51, 0x68, 0x60, 0xd4, 0x3e, 0x67, 0x53, 0x67, +0x96, 0x76, 0x40, 0x06, 0x65, 0x5a, 0x0e, 0x66, 0x00, 0x51, 0x66, 0x95, +0xa7, 0x40, 0x51, 0x67, 0x12, 0x65, 0x50, 0x00, 0x1a, 0x66, 0xd0, 0x03, +0x77, 0x03, 0x62, 0xd0, 0x00, 0x95, 0x4a, 0x40, 0x06, 0x67, 0x5a, 0x95, +0xea, 0x40, 0x3e, 0x67, 0x53, 0x67, 0x52, 0x02, 0x12, 0x67, 0x52, 0x01, +0x1a, 0x68, 0xd0, 0x1a, 0x95, 0x33, 0x40, 0x06, 0x67, 0x5a, 0x0e, 0x68, +0x00, 0x51, 0x68, 0x60, 0xd4, 0x3e, 0x67, 0x54, 0x01, 0x3e, 0x67, 0x54, +0x02, 0x52, 0x00, 0x54, 0x04, 0x77, 0x00, 0x3d, 0x00, 0x03, 0xcf, 0x9c, +0x50, 0x01, 0x3b, 0x03, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, 0x0f, 0x80, +0x06, 0x52, 0x04, 0x62, 0xd0, 0x00, 0x38, 0xfb, 0x20, 0x7f, 0x10, 0x4f, +0x38, 0x02, 0x70, 0xfe, 0x62, 0xd0, 0x00, 0x26, 0x2b, 0xf0, 0x51, 0xc1, +0x01, 0x01, 0x2c, 0x2b, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x05, +0x9a, 0x20, 0x62, 0xd0, 0x00, 0x41, 0x00, 0xf7, 0x56, 0x01, 0x00, 0x56, +0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0x9a, 0x20, 0x62, 0xd0, 0x00, +0x53, 0x68, 0x47, 0x68, 0x20, 0xa0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, +0x50, 0x04, 0x08, 0x9e, 0xb6, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, +0x52, 0x01, 0x11, 0xdc, 0x52, 0x00, 0x19, 0x05, 0xcf, 0xd7, 0x56, 0x01, +0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0x9a, 0x20, 0x62, +0xd0, 0x00, 0x53, 0x68, 0x47, 0x68, 0x20, 0xb0, 0x03, 0x80, 0x1a, 0x50, +0x00, 0x08, 0x50, 0x04, 0x08, 0x9e, 0x84, 0x38, 0xfe, 0x77, 0x01, 0x0f, +0x00, 0x00, 0x52, 0x01, 0x11, 0x2c, 0x52, 0x00, 0x19, 0x01, 0xcf, 0xd7, +0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x70, +0xfe, 0x62, 0xd0, 0x00, 0x26, 0x2b, 0xf0, 0x51, 0xc1, 0x01, 0x09, 0x2c, +0x2b, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x05, 0x9a, 0x20, 0x62, +0xd0, 0x00, 0x41, 0x00, 0xf7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, +0x21, 0x10, 0x7c, 0x05, 0x9a, 0x20, 0x62, 0xd0, 0x00, 0x53, 0x68, 0x47, +0x68, 0x20, 0xa0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x04, 0x08, +0x9e, 0x29, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, +0xdc, 0x52, 0x00, 0x19, 0x05, 0xcf, 0xd7, 0x56, 0x01, 0x00, 0x56, 0x00, +0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0x9a, 0x20, 0x62, 0xd0, 0x00, 0x53, +0x68, 0x47, 0x68, 0x20, 0xb0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, +0x04, 0x08, 0x9d, 0xf7, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, +0x01, 0x11, 0x2c, 0x52, 0x00, 0x19, 0x01, 0xcf, 0xd7, 0x43, 0x00, 0x08, +0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x04, 0x62, 0xd0, 0x00, 0x51, +0x2b, 0x21, 0xf0, 0x54, 0x00, 0x51, 0x2e, 0x54, 0x01, 0x3d, 0x00, 0x10, +0xb0, 0x30, 0x55, 0xb8, 0x00, 0x3c, 0xb9, 0x01, 0xb0, 0x0c, 0x55, 0xa1, +0x00, 0x55, 0xa2, 0x00, 0x55, 0xa3, 0x00, 0x80, 0x12, 0x62, 0xd0, 0x00, +0x3c, 0xbf, 0x01, 0xa0, 0x0a, 0x55, 0xa1, 0x00, 0x55, 0xa2, 0x00, 0x55, +0xa3, 0x00, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2b, 0x0f, 0x81, +0x86, 0x3d, 0x00, 0x20, 0xb0, 0x1b, 0x62, 0xd0, 0x00, 0x55, 0xb8, 0x01, +0x55, 0xbe, 0x00, 0x55, 0xa1, 0x08, 0x55, 0xa2, 0x08, 0x55, 0xa3, 0x08, +0x56, 0x00, 0x00, 0x26, 0x2b, 0x0f, 0x81, 0x67, 0x3d, 0x00, 0x30, 0xb0, +0x0f, 0x62, 0xd0, 0x00, 0x55, 0xc2, 0x00, 0x56, 0x00, 0x00, 0x26, 0x2b, +0x0f, 0x81, 0x54, 0x3d, 0x00, 0x40, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, +0xc2, 0x02, 0x56, 0x00, 0x00, 0x26, 0x2b, 0x0f, 0x81, 0x41, 0x3d, 0x00, +0x50, 0xb0, 0xad, 0x52, 0x01, 0x54, 0x03, 0x56, 0x02, 0x00, 0x3d, 0x02, +0x00, 0xb0, 0x06, 0x3d, 0x03, 0x01, 0xa0, 0x21, 0x3d, 0x02, 0x00, 0xb0, +0x06, 0x3d, 0x03, 0x02, 0xa0, 0x25, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, +0x03, 0x04, 0xa0, 0x37, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x08, +0xa0, 0x46, 0x80, 0x68, 0x62, 0xd0, 0x00, 0x55, 0xbb, 0x01, 0x2e, 0x30, +0x80, 0x7c, 0x0c, 0xc7, 0x80, 0x5a, 0x62, 0xd0, 0x00, 0x51, 0x2c, 0x53, +0x4a, 0x51, 0x2c, 0x53, 0x4b, 0x51, 0x2c, 0x53, 0x4c, 0x51, 0x2c, 0x53, +0x2f, 0x51, 0x2d, 0x53, 0x0e, 0x55, 0x0d, 0x00, 0x80, 0x3e, 0x62, 0xd0, +0x00, 0x51, 0x2c, 0x53, 0x30, 0x3c, 0xbb, 0x00, 0xa0, 0x06, 0x2e, 0x30, +0x80, 0x80, 0x2d, 0x62, 0xd0, 0x00, 0x26, 0x30, 0x7f, 0x80, 0x25, 0x62, +0xd0, 0x00, 0x55, 0xbb, 0x00, 0x26, 0x30, 0x7f, 0x51, 0xa5, 0x53, 0x24, +0x51, 0x24, 0x53, 0x31, 0x51, 0xa6, 0x53, 0x25, 0x51, 0x25, 0x53, 0x32, +0x51, 0xa7, 0x53, 0x26, 0x51, 0x26, 0x53, 0x33, 0x7c, 0x0c, 0xc7, 0x56, +0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2b, 0x0f, 0x55, 0x2c, 0x0e, 0x55, +0x2d, 0x03, 0x55, 0x2e, 0x00, 0x80, 0x90, 0x3d, 0x00, 0x60, 0xb0, 0x0f, +0x62, 0xd0, 0x00, 0x55, 0xb9, 0x01, 0x56, 0x00, 0x00, 0x26, 0x2b, 0x0f, +0x80, 0x7d, 0x3d, 0x00, 0x70, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, 0xb9, +0x00, 0x56, 0x00, 0x00, 0x26, 0x2b, 0x0f, 0x80, 0x6a, 0x3d, 0x00, 0x80, +0xb0, 0x65, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2b, 0x0f, 0x9c, +0x96, 0x10, 0x7c, 0x08, 0x55, 0x7c, 0x05, 0xb0, 0x20, 0x70, 0xfe, 0x71, +0x10, 0x41, 0x00, 0xf7, 0x41, 0x01, 0xf7, 0x70, 0xcf, 0x62, 0xda, 0x00, +0x71, 0x10, 0x41, 0xdc, 0xfe, 0x70, 0xcf, 0x43, 0x01, 0x08, 0x43, 0x00, +0x08, 0x50, 0x00, 0x08, 0x50, 0x1e, 0x08, 0x9c, 0x42, 0x38, 0xfe, 0x71, +0x01, 0x43, 0xe0, 0x10, 0x43, 0xff, 0x08, 0x70, 0xfe, 0x40, 0x40, 0x40, +0x40, 0x40, 0x40, 0x40, 0x10, 0x7c, 0x07, 0x96, 0x7c, 0x05, 0x64, 0x7c, +0x05, 0xa5, 0x20, 0x93, 0x50, 0x40, 0x62, 0xe3, 0x38, 0x56, 0x00, 0x00, +0x62, 0xd0, 0x00, 0x26, 0x2b, 0x0f, 0x38, 0xfc, 0x20, 0x7f, 0x62, 0xd0, +0x00, 0x3c, 0xb8, 0x00, 0xa0, 0x13, 0x9c, 0x2f, 0x62, 0xd0, 0x00, 0x3c, +0xbe, 0x00, 0xb0, 0x48, 0x55, 0xbe, 0x01, 0x7c, 0x0a, 0x85, 0x80, 0x40, +0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0xa1, 0xd0, 0x08, 0x10, 0x7c, 0x04, +0x69, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0x65, 0x20, 0x62, 0xd0, 0x00, +0x50, 0x01, 0x3a, 0xa2, 0xd0, 0x08, 0x10, 0x7c, 0x04, 0x4b, 0x20, 0x80, +0x06, 0x10, 0x7c, 0x04, 0x47, 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, +0xa3, 0xd0, 0x08, 0x10, 0x7c, 0x04, 0x2d, 0x20, 0x80, 0x06, 0x10, 0x7c, +0x04, 0x29, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x03, 0x56, 0x02, 0x00, 0x56, +0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x3e, 0x62, 0xd0, 0x00, 0x91, 0xa9, +0x40, 0x52, 0xfc, 0x04, 0x67, 0x52, 0xfb, 0x0c, 0x68, 0x51, 0x68, 0x60, +0xd4, 0x3e, 0x67, 0x53, 0x68, 0x3e, 0x67, 0x53, 0x67, 0x52, 0x02, 0x12, +0x67, 0x52, 0x01, 0x1a, 0x68, 0xd0, 0x18, 0x91, 0x88, 0x40, 0x52, 0xfc, +0x04, 0x67, 0x52, 0xfb, 0x0c, 0x68, 0x51, 0x68, 0x60, 0xd4, 0x3e, 0x67, +0x54, 0x01, 0x3e, 0x67, 0x54, 0x02, 0x77, 0x00, 0x52, 0x00, 0x3b, 0xfa, +0xcf, 0xbe, 0x62, 0xd0, 0x00, 0x52, 0x02, 0x53, 0x67, 0x52, 0x01, 0x53, +0x68, 0x38, 0xfd, 0x20, 0x7f, 0x10, 0x7c, 0x03, 0xfd, 0x50, 0x06, 0x08, +0x50, 0x00, 0x08, 0x50, 0x97, 0x08, 0x7c, 0x04, 0x06, 0x38, 0xfd, 0x50, +0x06, 0x08, 0x50, 0x00, 0x08, 0x50, 0x54, 0x08, 0x7c, 0x04, 0x06, 0x38, +0xfd, 0x50, 0x06, 0x08, 0x50, 0x00, 0x08, 0x50, 0x5a, 0x08, 0x7c, 0x04, +0x06, 0x38, 0xfd, 0x50, 0x00, 0x7c, 0x03, 0x31, 0x50, 0xff, 0x7c, 0x03, +0x31, 0x50, 0xff, 0x7c, 0x03, 0x31, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x55, +0xbb, 0x00, 0x55, 0xb9, 0x01, 0x10, 0x7c, 0x04, 0x69, 0x7c, 0x04, 0x4b, +0x7c, 0x04, 0x2d, 0x20, 0x9b, 0x29, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x43, +0x00, 0x08, 0x43, 0x01, 0x08, 0x70, 0xcf, 0x43, 0x00, 0x08, 0x62, 0xd0, +0x00, 0x55, 0x2b, 0x08, 0x55, 0x2c, 0x0e, 0x55, 0x2d, 0x03, 0x55, 0x2f, +0x2d, 0x55, 0x30, 0x03, 0x55, 0x31, 0x0d, 0x55, 0x32, 0x0d, 0x55, 0x33, +0x0f, 0x55, 0x34, 0x00, 0x3c, 0xbb, 0x00, 0xa0, 0x06, 0x2e, 0x30, 0x80, +0x80, 0x07, 0x62, 0xd0, 0x00, 0x26, 0x30, 0x7f, 0x10, 0x50, 0x00, 0x08, +0x50, 0x2b, 0x08, 0x50, 0x06, 0x08, 0x50, 0x1c, 0x08, 0x7c, 0x05, 0xb7, +0x38, 0xfc, 0x7c, 0x05, 0x64, 0x7c, 0x05, 0xa5, 0x20, 0x91, 0xd6, 0x40, +0x10, 0x7c, 0x07, 0x96, 0x7c, 0x07, 0x42, 0x20, 0x7c, 0x0c, 0xc7, 0x80, +0x22, 0x62, 0xe3, 0x38, 0x7c, 0x10, 0x8b, 0x10, 0x7c, 0x07, 0x5a, 0x20, +0x62, 0xd0, 0x00, 0x39, 0x00, 0xa0, 0x09, 0x7c, 0x09, 0x9b, 0x7c, 0x09, +0xc5, 0x80, 0x04, 0x7c, 0x0a, 0x36, 0x9c, 0x9c, 0x9e, 0x68, 0x8f, 0xde, +0x8f, 0xff, 0x10, 0x4f, 0x7c, 0x1c, 0x21, 0x20, 0x70, 0x3f, 0x71, 0xc0, +0x7f, 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, 0x00, 0x53, 0x61, 0x53, +0x62, 0x55, 0x60, 0x10, 0x66, 0xfc, 0x6c, 0xfb, 0x6b, 0x61, 0x6b, 0x62, +0x51, 0x61, 0x1b, 0xfa, 0x51, 0x62, 0x1b, 0xf9, 0xc0, 0x09, 0x53, 0x62, +0x52, 0xfa, 0x1c, 0x61, 0x77, 0xfc, 0x7a, 0x60, 0xbf, 0xe3, 0x51, 0x61, +0x54, 0xfa, 0x51, 0x62, 0x54, 0xf9, 0x18, 0x60, 0xd0, 0x7f, 0x30, 0x55, +0x64, 0x00, 0x55, 0x62, 0x00, 0x55, 0x61, 0x00, 0x3c, 0x64, 0x00, 0xb0, +0x06, 0x3c, 0x63, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x64, 0x6e, 0x63, +0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x65, 0x04, 0x62, 0x51, 0x66, 0x0c, +0x61, 0x65, 0x65, 0x6b, 0x66, 0x8f, 0xde, 0x5f, 0x65, 0x62, 0x5f, 0x66, +0x61, 0x62, 0xd0, 0x00, 0x7f, 0x52, 0x00, 0x53, 0x67, 0x55, 0x68, 0x00, +0x65, 0x67, 0x6b, 0x68, 0x7f, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x67, +0x55, 0x68, 0x00, 0x7f, 0x53, 0x65, 0x51, 0x68, 0x09, 0x00, 0x60, 0xd4, +0x3e, 0x65, 0x53, 0x66, 0x3e, 0x65, 0x53, 0x65, 0x7f, 0x51, 0x68, 0x60, +0xd5, 0x51, 0x66, 0x3f, 0x67, 0x51, 0x65, 0x3f, 0x67, 0x7f, 0x06, 0x67, +0x97, 0x0e, 0x68, 0x00, 0x51, 0x68, 0x60, 0xd4, 0x3e, 0x67, 0x53, 0x66, +0x3e, 0x67, 0x16, 0x67, 0x02, 0x53, 0x65, 0x7f, 0x60, 0xd4, 0x3e, 0x65, +0x53, 0x66, 0x3e, 0x65, 0x53, 0x65, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, +0x65, 0x53, 0x66, 0x3e, 0x65, 0x7f, 0x55, 0x65, 0x06, 0x55, 0x66, 0x00, +0x55, 0x62, 0x00, 0x55, 0x61, 0x00, 0x3c, 0x66, 0x00, 0xb0, 0x06, 0x3c, +0x65, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x66, 0x6e, 0x65, 0xd0, 0x0c, +0x62, 0xd0, 0x00, 0x51, 0x67, 0x04, 0x62, 0x51, 0x68, 0x0c, 0x61, 0x65, +0x67, 0x6b, 0x68, 0x8f, 0xde, 0x5f, 0x67, 0x62, 0x5f, 0x68, 0x61, 0x62, +0xd0, 0x00, 0x5a, 0x65, 0x06, 0x65, 0x01, 0x51, 0x65, 0x04, 0x67, 0x0e, +0x68, 0x03, 0x7f, 0x0e, 0x68, 0x00, 0x51, 0x68, 0x60, 0xd4, 0x3e, 0x67, +0x53, 0x68, 0x7f, 0x60, 0xd4, 0x3e, 0x67, 0x53, 0x68, 0x3e, 0x67, 0x53, +0x67, 0x7f, 0x53, 0x65, 0x51, 0x68, 0x09, 0x00, 0x60, 0xd5, 0x52, 0x1a, +0x3f, 0x65, 0x52, 0x1b, 0x3f, 0x65, 0x7f, 0x3e, 0x67, 0x53, 0x67, 0x51, +0x65, 0x12, 0x67, 0x51, 0x66, 0x1a, 0x68, 0x7f, 0x53, 0x67, 0x52, 0xfb, +0x09, 0x00, 0x60, 0xd4, 0x3e, 0x67, 0x7f, 0x0e, 0x66, 0x00, 0x51, 0x66, +0x60, 0xd4, 0x3e, 0x65, 0x53, 0x66, 0x3e, 0x65, 0x7f, 0x0e, 0x68, 0x00, +0x51, 0x68, 0x60, 0xd5, 0x52, 0x1a, 0x3f, 0x67, 0x52, 0x1b, 0x3f, 0x67, +0x7f, 0x60, 0xd4, 0x3e, 0x67, 0x54, 0x00, 0x3e, 0x67, 0x54, 0x01, 0x7f, +0x52, 0x00, 0x53, 0x65, 0x55, 0x66, 0x00, 0x65, 0x65, 0x6b, 0x66, 0x7f, +0x09, 0x00, 0x60, 0xd4, 0x3e, 0x63, 0x53, 0x64, 0x3e, 0x63, 0x53, 0x63, +0x7f, 0x71, 0x10, 0x41, 0x04, 0xfe, 0x41, 0x05, 0xfe, 0x41, 0x04, 0xfd, +0x41, 0x05, 0xfd, 0x70, 0xcf, 0x43, 0x04, 0x01, 0x43, 0x04, 0x02, 0x71, +0x01, 0x7f, 0x53, 0x65, 0x55, 0x66, 0x00, 0x65, 0x65, 0x6b, 0x66, 0x51, +0x65, 0x7f, 0x0e, 0x66, 0x00, 0x51, 0x66, 0x60, 0xd5, 0x51, 0x68, 0x3f, +0x65, 0x7f, 0x0e, 0x68, 0x00, 0x51, 0x68, 0x60, 0xd5, 0x50, 0x00, 0x3f, +0x67, 0x7f, 0x3e, 0x67, 0x12, 0x65, 0x54, 0x04, 0x51, 0x68, 0x1a, 0x66, +0x54, 0x03, 0x7f, 0x3e, 0x67, 0x12, 0x65, 0x54, 0x02, 0x51, 0x68, 0x1a, +0x66, 0x54, 0x01, 0x7f, 0x00, 0x2b, 0x00, 0x1c, 0x00, 0x69, 0x00, 0x2e, +0x00, 0x9d, 0x00, 0x04, 0x00, 0xa1, 0x07, 0x08, 0x08, 0x08, 0x08, 0x0d, +0x0d, 0x0f, 0x00, 0xa8, 0x00, 0x0f, 0x00, 0xb7, 0x08, 0x02, 0x01, 0x01, +0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0xbf, 0x00, 0x05, 0xff, 0x00, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; + diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_defs.h b/drivers/input/keyboard/cypress_touchkey_236/issp_defs.h new file mode 100644 index 00000000000..5eda5a1e8cc --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_defs.h @@ -0,0 +1,61 @@ + /* filename: ISSP_Defs.h +*/ + +#include "issp_revision.h" + +#ifdef PROJECT_REV_304 + +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +#ifndef INC_ISSP_DEFS + +#define INC_ISSP_DEFS + + + +#include "issp_directives.h" + + + + /* Block-Verify Uses 64-Bytes of RAM */ + +/* kevi added + */ +#define MAX_TARGET_DATABUFF_LEN 1024 +/* Address Numbers for Bytes within a Block */ +#define TARGET_DATABUFF_LEN 128/*64*/ + + +/* + The number of Flash blocks in each part is defined here. This is used in + + main programming loop when programming and verifying the blocks. + +*/ +/* For example, radon is 2 */ +#define NUM_BANKS 1 +/* Block Numbers for Program Data */ +#define BLOCKS_PER_BANK 64/*128*/ + +#define SECURITY_BYTES_PER_BANK 64 + + +#endif /*(INC_ISSP_DEFS)*/ +#endif /*(PROJECT_REV_)*/ + /*end of file ISSP_Defs.h*/ diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_delays.h b/drivers/input/keyboard/cypress_touchkey_236/issp_delays.h new file mode 100644 index 00000000000..b373168b1a0 --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_delays.h @@ -0,0 +1,82 @@ +/* //filename: ISSP_Delays.h +*/ +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +#ifndef INC_ISSP_DELAYS +#define INC_ISSP_DELAYS + +/* + The Delay() routine, in ISSP_Driver_Routines.c, has a delay of n+3 usec, + where n is the value passed to the routine. This is true for the m8c micro- + processor in the PSoC when it is running at a CPU clock of 24MHz. + + PROCESSOR_SPECIFIC + If another processor is used, or if the m8c is running at a slower clock + speed, then the delay parameters will be different. This file makes changing + the delays simpiler when porting the program to other processors. +*/ + +/* DELAY_M is the slope of the Delay = Mx + B equation +*/ +#define DELAY_M 1 +/* DELAY_B is the offset of the delay in Delay = Mx + B. +*/ +#define DELAY_B 3 +/* + + CAUTION: + For the above parameters the minimum delay value is 3 (this would result in + 0 being passed for a minimum delay. A value less than 3 would actually + create a negative number, causing a very long delay + + + TRANSITION_TIMEOUT is a loop counter for a 100msec timeout when waiting for + a high-to-low transition. This is used in the polling loop of + fDetectHiLoTransition(). Each pass through the loop takes approximately 15 + usec. 100 msec is about 6740 loops. 13480 +*/ +#define TRANSITION_TIMEOUT (65535*10) +/* + XRES_DELAY is the time duration for which XRES is asserted. This defines + a 63 usec delay. + The minimum Xres time (from the device datasheet) is 10 usec. +*/ +#define XRES_CLK_DELAY ((63 - DELAY_B) / DELAY_M) +/* + POWER_CYCLE_DELAY is the time required when power is cycled to the target + device to create a power reset after programming has been completed. The + actual time of this delay will vary from system to system depending on the + bypass capacitor size. A delay of 150 usec is used here. +*/ +#define POWER_CYCLE_DELAY ((150 - DELAY_B) / DELAY_M) +/* + DELAY_100us delays 100 usec. This is used in fXRESInitializeTargetForISSP to + time the wait for Vdd to become stable after a power up. A loop runs 10 of + these for a total delay of 1 msec. +*/ +#define DELAY100us ((100 - DELAY_B) / DELAY_M) + +#endif /* (INC_ISSP_DELAYS) +*/ +#endif /* (PROJECT_REV_) +*/ +/* end of file ISSP_Delays.h */ diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_directives.h b/drivers/input/keyboard/cypress_touchkey_236/issp_directives.h new file mode 100644 index 00000000000..8523b5310f9 --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_directives.h @@ -0,0 +1,194 @@ +/* filename: ISSP_Directives.h */ +#include "issp_revision.h" +#ifdef PROJECT_REV_304 + +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +/*--------------------- Compiler Directives ---------------------------------- +*/ +#ifndef INC_ISSP_DIRECTIVES +#define INC_ISSP_DIRECTIVES + + /* + This directive will enable a Genral Purpose test-point on P1.7 + It can be toggled as needed to measure timing, execution, etc... + A "Test Point" sets a GPIO pin of the host processor high or low. This GPIO + pin can be observed with an oscilloscope to verify the timing of key + programming steps. TPs have been added in main() that set Port 0, pin 1 + high during bulk erase, during each block write and during security write. + The timing of these programming steps should be verified as correct as part + of the validation process of the final program. + + **************************************************************************** + ************* USER ATTENTION REQUIRED: TARGET SUPPLY VOLTAGE *************** + **************************************************************************** + This directive causes the proper Initialization vector #3 to be sent + to the Target, based on what the Target Vdd programming voltage will + be. Either 5V (if #define enabled) or 3.3V (if #define disabled). + */ + +/* +#define TARGET_VOLTAGE_IS_5V +*/ + +/* + **************************************************************************** + **************** USER ATTENTION REQUIRED: PROGRAMMING MODE ***************** + **************************************************************************** + This directive selects whether code that uses reset programming mode or code + that uses power cycle programming is use. Reset programming mode uses the + external reset pin (XRES) to enter programming mode. Power cycle programming + mode uses the power-on reset to enter programming mode. + Applying signals to various pins on the target device must be done in a + deliberate order when using power cycle mode. Otherwise, high signals to GPIO + pins on the target will power the PSoC through the protection diodes. +*/ + +#define CY8C20236 +/* +#define RESET_MODE + +*/ + +/* +#define TX_ON + +#define CY8C20236 +*/ + +/* +#define LCD_ON +*/ + + /***************************************************************************** + ****************** USER ATTENTION REQUIRED: TARGET PSOC ******************** + **************************************************************************** + The directives below enable support for various PSoC devices. The root part + number to be programmed should be un-commented so that its value becomes + defined. All other devices should be commented out. + Select one device to be supported below: + + **** CY821x34 devices **** +*/ + + +/* +#define CY8C21234 +#define CY8C21334 +#define CY8C21434 +#define CY8C21534 + +*/ + +#define CY8C20x66 + /* Quark */ + + +/*----------------------------------------------------------------------------- + The directives below are used for Krypton. + See the Krypton programming spec 001-15870 rev *A for more details. (The + spec uses "mnemonics" instead of "directives" +-----------------------------------------------------------------------------*/ +#ifdef CY8C20x66 + #define TSYNC + + #define ID_SETUP_1/*PTJ: ID_SETUP_1 is similar to init1_v*/ + #define ID_SETUP_2/*PTJ: ID_SETUP_2 is similar to init2_v*/ + #define SET_BLOCK_NUM + #define CHECKSUM_SETUP/*PTJ: CHECKSUM_SETUP_20x66 is + the same as CHECKSUM-SETUP in 001-15870*/ + #define READ_CHECKSUM + #define PROGRAM_AND_VERIFY/*PTJ: PROGRAM_BLOCK_20x66 is the + same as PROGRAM-AND-VERIFY in 001-15870*/ + #define ERASE + #define SECURE + #define READ_SECURITY + #define READ_WRITE_SETUP + #define WRITE_BYTE + #define VERIFY_SETUP + #define READ_STATUS + #define READ_BYTE + /*READ_ID_WORD PTJ: 3rd Party Progrmmer will have to write + code to handle this directive, we do it out own way in this + code, see read_id_v*/ +#endif +/*----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// The directives below are used to define various sets of vectors that differ +// for more than one set of PSoC parts. +//----------------------------------------------------------------------------- +// **** Select a Checksum Setup Vector ****/ +#ifdef CY8C21x23 + #define CHECKSUM_SETUP_21_27 +#endif +#ifdef CY8C21x34 + #define CHECKSUM_SETUP_21_27 +#endif +#ifdef CY8C24x23A + #define CHECKSUM_SETUP_24_24A +#endif +#ifdef CY8C24x94 + #define CHECKSUM_SETUP_24_29 +#endif +#ifdef CY8C27x43 + #define CHECKSUM_SETUP_21_27 +#endif +#ifdef CY8C29x66 + #define CHECKSUM_SETUP_24_29 +#endif + +/*** Select a Program Block Vector ****/ + +#ifdef CY8C21x23 + #define PROGRAM_BLOCK_21_24_29 +#endif +#ifdef CY8C21x34 + #define PROGRAM_BLOCK_21_24_29 +#endif +#ifdef CY8C24x23A + #define PROGRAM_BLOCK_21_24_29 +#endif +#ifdef CY8C24x94 + #define PROGRAM_BLOCK_21_24_29 +#endif +#ifdef CY8C27x43 + #define PROGRAM_BLOCK_27 +#endif +#ifdef CY8C29x66 + #define PROGRAM_BLOCK_21_24_29 +#endif + +/*----------------------------------------------------------------------------- +// The directives below are used to control switching banks if the device is +// has multiple banks of Flash. +//----------------------------------------------------------------------------- +// **** Select a Checksum Setup Vector ****/ +#ifdef CY8C24x94 + #define MULTI_BANK +#endif +#ifdef CY8C29x66 + #define MULTI_BANK +#endif + +#endif /*(INC_ISSP_DIRECTIVES)*/ +#endif /*(PROJECT_REV_) */ +/* end of file ISSP_Directives.h */ + diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_driver_routines.c b/drivers/input/keyboard/cypress_touchkey_236/issp_driver_routines.c new file mode 100644 index 00000000000..41374032f5b --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_driver_routines.c @@ -0,0 +1,530 @@ +/* filename: ISSP_Driver_Routines.c */ +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +/* +#include +#include "PSoCAPI.h" +*/ +#include +#include +#include +#include +#include +#include +#include + +#include "issp_defs.h" +#include "issp_errors.h" +#include "issp_directives.h" +#include "issp_extern.h" +#include +#define _CYPRESS_TKEY_FW_H +#include "cypress_tkey_fw.h" + +#define SECURITY_DATA 0xFF + +#define SCLK_PIN 0x20 /* p2_5 */ +#define SDATA_PIN 0x08 /* p2_3 */ +#define XRES_PIN 0x10 /* p1_5 */ +#define TARGET_VDD 0x08 /* p1_3 */ + + + /*============================================================================ + LoadArrayWithSecurityData() + !!!!!!!!!!!!!!!!!!FOR TEST!!!!!!!!!!!!!!!!!!!!!!!!!! + PROCESSOR_SPECIFIC + Most likely this data will be fed to the Host by some other means, ie: I2C, + RS232, etc., or will be fixed in the host. The security data should come + from the hex file. + bStart - the starting byte in the array for loading data + bLength - the number of byte to write into the array + bType - the security data to write over the range defined by bStart and + bLength + ============================================================================ +*/ +void LoadArrayWithSecurityData(unsigned char bStart, + unsigned char bLength, unsigned char bType) +{ + /* Now, write the desired security-bytes for the range specified */ + for (bTargetDataPtr = bStart; + bTargetDataPtr < bLength; bTargetDataPtr++) + abTargetDataOUT[bTargetDataPtr] = bType; +} + + +void Delay(unsigned int n) +{ + while (n) { + asm("nop"); + n -= 1; + } +} + + /* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + LoadProgramData() + The final application should load program data from HEX file generated by + PSoC Designer into a 64 byte host ram buffer. + 1. Read data from next line in hex file into ram buffer. One record + (line) is 64 bytes of data. + 2. Check host ram buffer + record data (Address, # of bytes) against hex + record checksum at end of record line + 3. If error reread data from file or abort + 4. Exit this Function and Program block or verify the block. + This demo program will, instead, load predetermined data into each block. + The demo does it this way because there is no comm link to get data. + **************************************************************************** +*/ +void LoadProgramData(unsigned char bBlockNum, unsigned char bBankNum) +{ + /* >>> The following call is for demo use only. <<< + Function InitTargetTestData fills buffer for demo +*/ + int dataNum; + for (dataNum = 0; dataNum < TARGET_DATABUFF_LEN; dataNum++) { + abTargetDataOUT[dataNum] = + firmware_data[bBlockNum * TARGET_DATABUFF_LEN + dataNum]; + } + +} + + +/* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + fLoadSecurityData() + Load security data from hex file into 64 byte host ram buffer. In a fully + functional program (not a demo) this routine should do the following: + 1. Read data from security record in hex file into ram buffer. + 2. Check host ram buffer + record data (Address, # of bytes) against hex + record checksum at end of record line + 3. If error reread security data from file or abort + 4. Exit this Function and Program block + In this demo routine, all of the security data is set to unprotected (0x00) + and it returns. + This function always returns PASS. The flag return is reserving + functionality for non-demo versions. + **************************************************************************** +*/ +signed char fLoadSecurityData(unsigned char bBankNum) +{ +/* >>> The following call is for demo use only. <<< + Function LoadArrayWithSecurityData fills buffer for demo +*/ + LoadArrayWithSecurityData(0, SecurityBytesPerBank, SECURITY_DATA); + /* PTJ: 0x1B (00 01 10 11) is more interesting security data + than 0x00 for testing purposes */ + + /* Note: + Error checking should be added for the final version as noted above. + For demo use this function just returns PASS. */ + return PASS; +} + + +/* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + fSDATACheck() + Check SDATA pin for high or low logic level and return value to calling + routine. + Returns: + 0 if the pin was low. + 1 if the pin was high. + **************************************************************************** +*/ +unsigned char fSDATACheck(void) +{ +#ifdef PSOC3_5 + if (gpio_get_value(GPIO_TOUCHKEY_SDA)) + return 1; + else + return 0; +#else + if (gpio_get_value(GPIO_TOUCHKEY_SDA)) + return 1; + else + return 0; +#endif +} + + +/* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SCLKHigh() + Set the SCLK pin High + **************************************************************************** +*/ +void SCLKHigh(void) +{ + gpio_direction_output(GPIO_TOUCHKEY_SCL, 1); +} + + + /* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SCLKLow() + Make Clock pin Low + **************************************************************************** +*/ +void SCLKLow(void) +{ + gpio_direction_output(GPIO_TOUCHKEY_SCL, 0); +} + +#ifndef RESET_MODE + /*Only needed for power cycle mode + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SetSCLKHiZ() + Set SCLK pin to HighZ drive mode. + **************************************************************************** +*/ +void SetSCLKHiZ(void) +{ + gpio_direction_input(GPIO_TOUCHKEY_SCL); +} +#endif + + /* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SetSCLKStrong() + Set SCLK to an output (Strong drive mode) + **************************************************************************** +*/ +void SetSCLKStrong(void) +{ + gpio_direction_output(GPIO_TOUCHKEY_SCL, 0); +} + + + /* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SetSDATAHigh() + Make SDATA pin High + **************************************************************************** +*/ +void SetSDATAHigh(void) +{ + gpio_direction_output(GPIO_TOUCHKEY_SDA, 1); +} + + /* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SetSDATALow() + Make SDATA pin Low + **************************************************************************** +*/ +void SetSDATALow(void) +{ + gpio_direction_output(GPIO_TOUCHKEY_SDA, 0); +} + + /* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SetSDATAHiZ() + Set SDATA pin to an input (HighZ drive mode). + **************************************************************************** +*/ +void SetSDATAHiZ(void) +{ + gpio_direction_input(GPIO_TOUCHKEY_SDA); +} + + /* 0BIT 1BIT + 10 :strong, 11:open drain low, 00:pull-up,01:hi-z +*/ + +void SetSDATAOpenDrain(void) +{ + +} + +/* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SetSDATAStrong() + Set SDATA for transmission (Strong drive mode) -- as opposed to being set to + High Z for receiving data. + **************************************************************************** +*/ +void SetSDATAStrong(void) +{ + gpio_direction_output(GPIO_TOUCHKEY_SDA, 0); +} + +#ifdef RESET_MODE + /* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SetXRESStrong() + Set external reset (XRES) to an output (Strong drive mode). + **************************************************************************** +*/ +void SetXRESStrong(void) +{ + +} + + /* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + AssertXRES() + Set XRES pin High + **************************************************************************** +*/ +void AssertXRES(void) +{ + +} + +/* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + DeassertXRES() + Set XRES pin low. + **************************************************************************** +*/ +void DeassertXRES(void) +{ + +} +#else + + /* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + SetTargetVDDStrong() + Set VDD pin (PWR) to an output (Strong drive mode). + **************************************************************************** +*/ +void SetTargetVDDStrong(void) +{ + +} + +/* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + ApplyTargetVDD() + Provide power to the target PSoC's Vdd pin through a GPIO. + **************************************************************************** +*/ + +static void cypress_power_onoff(int onoff) +{ + if (machine_is_GOGH()) { + if (onoff) + gpio_direction_output(51, 1); + else + gpio_direction_output(51, 0); + } else { + int ret, rc; + static struct regulator *reg_l29, *reg_l10, *reg_lvs5; + + if (!reg_l29) { + reg_l29 = regulator_get(NULL, "8921_l29"); + if ((machine_is_jaguar()) && (system_rev == 16)) + ret = regulator_set_voltage(reg_l29, + 1900000, 1900000); + else + ret = regulator_set_voltage(reg_l29, + 1800000, 1800000); + + if (IS_ERR(reg_l29)) { + pr_err("could not get 8921_l29, rc = %ld\n", + PTR_ERR(reg_l29)); + return; + } + } + + if (machine_is_APEXQ()) { + if (!reg_lvs5) { + reg_lvs5 = regulator_get(NULL, "8921_lvs5"); + if (IS_ERR(reg_lvs5)) { + pr_err("could not get 8921_lvs5, rc = %ld\n", + PTR_ERR(reg_lvs5)); + return; + } + } + } else { + if (!reg_l10) { + reg_l10 = regulator_get(NULL, "8921_l10"); + if (machine_is_jaguar()) + ret = regulator_set_voltage(reg_l10, + 2900000, 2900000); + else + ret = regulator_set_voltage(reg_l10, + 3000000, 3000000); + if (IS_ERR(reg_l10)) { + pr_err("could not get 8921_l10, rc = %ld\n", + PTR_ERR(reg_l10)); + return; + } + } + } + + if (onoff) { + ret = regulator_enable(reg_l29); + if (machine_is_APEXQ()) + rc = regulator_enable(reg_lvs5); + else + rc = regulator_enable(reg_l10); + + if (ret) { + pr_err("enable l29 failed, rc=%d\n", ret); + return; + } + + if (rc) { + if (machine_is_APEXQ()) + pr_err("enable lvs5 failed, rc=%d\n", + rc); + else + pr_err("enable l10 failed, rc=%d\n", + rc); + return; + } + pr_info("cypress_power_on is finished.\n"); + } else { + ret = regulator_disable(reg_l29); + if (machine_is_APEXQ()) + rc = regulator_disable(reg_lvs5); + else + rc = regulator_disable(reg_l10); + if (ret) { + pr_err("disable l29 failed, rc=%d\n", ret); + return; + } + if (rc) { + if (machine_is_APEXQ()) + pr_err("disable lvs5 failed, rc=%d\n", + rc); + else + pr_err("enable l10 failed, rc=%d\n", + rc); + return; + } + pr_info("cypress_power_off is finished.\n"); + } + } +} + +void ApplyTargetVDD(void) +{ + gpio_direction_input(GPIO_TOUCHKEY_SDA); + gpio_direction_input(GPIO_TOUCHKEY_SCL); + cypress_power_onoff(1); +} + +/* + ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** + **************************************************************************** + **** PROCESSOR SPECIFIC **** + **************************************************************************** + **** USER ATTENTION REQUIRED **** + **************************************************************************** + RemoveTargetVDD() + Remove power from the target PSoC's Vdd pin. + **************************************************************************** +*/ +void RemoveTargetVDD(void) +{ + cypress_power_onoff(0); +} +#endif + + +#endif /* (PROJECT_REV_) */ +/* end of file ISSP_Drive_Routines.c */ + diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_errors.h b/drivers/input/keyboard/cypress_touchkey_236/issp_errors.h new file mode 100644 index 00000000000..e28879f4568 --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_errors.h @@ -0,0 +1,66 @@ +/* filename: ISSP_Errors.h */ +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +#ifndef INC_ISSP_ERRORS +#define INC_ISSP_ERRORS + +/* The following are defines for error messages from the ISSP program. */ +#define PASS 0 +/* PASS is used to indicate that a function completed successfully. */ +#define ERROR -1 +/* + ERROR is a generic failure used within lower level functions before the + error is reported. This should not be seen as an error that is reported + from main. +*/ +#define INIT_ERROR 1 +/* INIT_ERROR means a step in chip initialization failed. +*/ +#define SiID_ERROR 2 +/* + SiID_ERROR means that the Silicon ID check failed. This happens if the + target part does not match the device type that the ISSP program is + configured for. + +*/ +#define ERASE_ERROR 3 +/*/ ERASE_ERROR means that the bulk erase step failed. +*/ +#define BLOCK_ERROR 4 +/* + BLOCK_ERROR means that a step in programming a Flash block or the verify + of the block failed. + +*/ +#define VERIFY_ERROR 5 +/* VERIFY_ERROR means that the checksum verification failed.*/ +#define SECURITY_ERROR 6 +/* SECURITY_ERROR means that the write of the security information failed.*/ +#define STATUS_ERROR 7 + + +#define CHECKSUM_ERROR 8 + + +#endif /*(INC_ISSP_ERRORS)*/ +#endif /*(PROJECT_REV_)*/ +/*end of file ISSP_Errors.h*/ diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_extern.h b/drivers/input/keyboard/cypress_touchkey_236/issp_extern.h new file mode 100644 index 00000000000..b1345a59500 --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_extern.h @@ -0,0 +1,102 @@ +/* filename: ISSP_Extern.h */ +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +#ifndef INC_ISSP_EXTERN +#define INC_ISSP_EXTERN + +#include "issp_directives.h" +#include "issp_defs.h" + +extern signed char fXRESInitializeTargetForISSP(void); +extern signed char fPowerCycleInitializeTargetForISSP(void); +extern signed char fEraseTarget(void); +extern unsigned int iLoadTarget(void); +extern void ReStartTarget(void); +extern signed char fVerifySiliconID(void); +extern signed char fAccTargetBankChecksum(unsigned int *); +extern void SetBankNumber(unsigned char); +extern signed char fProgramTargetBlock(unsigned char, unsigned char); +extern signed char fVerifyTargetBlock(unsigned char, unsigned char); +/* PTJ: VERIFY-SETUP */ +extern signed char fVerifySetup(unsigned char, unsigned char); +/* PTJ: read bytes after VERIFY-SETUP */ +extern signed char fReadByteLoop(void); +extern signed char fSecureTargetFlash(void); +extern signed char fReadStatus(void);/*PTJ:R-STATUS*/ +extern signed char fReadCalRegisters(void); +extern signed char fReadWriteSetup(void);/*PTJ:RW-SETUP*/ +extern signed char fReadSecurity(void);/*PTJ: READ-SECURITY*/ +extern signed char fSyncDisable(void);/*PTJ: SYNC-DISABLE rev 307*/ +extern signed char fSyncEnable(void);/*PTJ: SYNC-ENABLE rev 307 */ + +extern void InitTargetTestData(void); +extern void LoadArrayWithSecurityData(unsigned char, + unsigned char, unsigned char); + +extern void LoadProgramData(unsigned char, unsigned char); +extern signed char fLoadSecurityData(unsigned char); +extern void Delay(unsigned int); +extern unsigned char fSDATACheck(void); +extern void SCLKHigh(void); +extern void SCLKLow(void); +#ifndef RESET_MODE /*only needed when power cycle mode*/ +extern void SetSCLKHiZ(void); +#endif +extern void SetSCLKStrong(void); + +extern void SetSDATAHigh(void); +extern void SetSDATALow(void); + +extern void SetSDATAHiZ(void); +extern void SetSDATAOpenDrain(void); +extern void SetSDATAStrong(void); + +extern void AssertXRES(void); +extern void DeassertXRES(void); +extern void SetXRESStrong(void); +extern void ApplyTargetVDD(void); +extern void RemoveTargetVDD(void); +extern void SetTargetVDDStrong(void); + + +#ifdef TX_ON +extern void TX8SW_PutHexHalf(char ch); +extern void TX8SW_PutHexByte(unsigned char ch); +extern void TX8SW_PutHexWord(unsigned int ch); +#endif + +extern unsigned char fIsError; +/* Address Numbers for Bytes within a Block */ +extern unsigned char TargetDatabufLen; +/* For example, radon is 2 */ +extern unsigned char NumBanks; +/* Block Numbers for Program Data */ +extern unsigned char BlocksPerBank; +extern unsigned char SecurityBytesPerBank; +extern unsigned char bTargetDataPtr; +extern unsigned char abTargetDataOUT[MAX_TARGET_DATABUFF_LEN]; +extern unsigned char TargetDatabufLen; + +extern unsigned int system_rev; +#endif /* (INC_ISSP_EXTERN) */ +#endif /* (PROJECT_REV_) */ +/* end of file ISSP_Extern.h */ diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_main.c b/drivers/input/keyboard/cypress_touchkey_236/issp_main.c new file mode 100644 index 00000000000..7fbe30ae110 --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_main.c @@ -0,0 +1,462 @@ + /* filename: main.c +*/ +#include "issp_revision.h" +#ifdef PROJECT_REV_304 + +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + +/* ############################################################################ + ################### CRITICAL PROJECT CONSTRAINTS ######################## + ############################################################################ + + ISSP programming can only occur within a temperature range of 5C to 50C. + - This project is written without temperature compensation and using + programming pulse-widths that match those used by programmers such as the + Mini-Prog and the ISSP Programmer. + This means that the die temperature of the PSoC device cannot be outside + of the above temperature range. + If a wider temperature range is required, contact your Cypress Semi- + conductor FAE or sales person for assistance. + + The project can be configured to program devices at 5V or at 3.3V. + - Initialization of the device is different for different voltages. The + initialization is hardcoded and can only be set for one voltage range. + The supported voltages ranges are 3.3V (3.0V to 3.6V) and 5V (4.75V to + 5.25V). See the device datasheet for more details. If varying voltage + ranges must be supported, contact your Cypress Semiconductor FAE or sales + person for assistance. + - ISSP programming for the 2.7V range (2.7V to 3.0V) is not supported. + + This program does not support programming all PSoC Devices + - It does not support obsoleted PSoC devices. A list of devices that are + not supported is shown here: + CY8C22x13 - not supported + CY8C24x23 - not supported (CY8C24x23A is supported) + CY8C25x43 - not supported + CY8C26x43 - not supported + - It does not suport devices that have not been released for sale at the + time this version was created. If you need to ISSP program a newly released + device, please contact Cypress Semiconductor Applications, your FAE or + sales person for assistance. + The CY8C20x23 devices are not supported at the time of this release. +*/ + + +/* + PSoC In-System Serial Programming (ISSP) Template + This PSoC Project is designed to be used as a template for designs that + require PSoC ISSP Functions. + + This project is based on the AN2026 series of Application Notes. That app + note should be referenced before any modifications to this project are made. + + The subroutines and files were created in such a way as to allow easy cut & + paste as needed. There are no customer-specific functions in this project. + This demo of the code utilizes a PSoC as the Host. + + Some of the subroutines could be merged, or otherwise reduced, but they have + been written as independently as possible so that the specific steps involved + within each function can easily be seen. By merging things, some code-space + savings could be realized. + + As is, and with all features enabled, the project consumes approximately 3500 + bytes of code space, and 19-Bytes of RAM (not including stack usage). The + Block-Verify requires a 64-Byte buffer for read-back verification. This same + buffer could be used to hold the (actual) incoming program data. + + Please refer to the compiler-directives file "directives.h" to see the various + features. + + The pin used in this project are assigned as shown below. The HOST pins are + arbitrary and any 3 pins could be used (the masks used to control the pins + must be changed). The TARGET pins cannot be changed, these are fixed function + pins on the PSoC. + The PWR pin is used to provide power to the target device + if power cycle programming mode is used. + The compiler directive RESET_MODE in ISSP_directives.h + is used to select the programming mode. This pin could control the enable on + a voltage regulator, or could control the gate of a FET that is used to turn + the power to the PSoC on. + The TP pin is a Test Point pin that can be used signal from the host processor + that the program has completed certain tasks. Predefined test points are + included that can be used to observe the timing for bulk erasing, block + programming and security programming. + + SIGNAL HOST TARGET + --------------------- + SDATA P1.0 P1.0 + SCLK P1.1 P1.1 + XRES P2.0 XRES + PWR P2.1 Vdd + TP P0.7 n/a + + For test & demonstration, this project generates the program data internally. + It does not take-in the data from an external source such as I2C, UART, SPI, + etc. However, the program was written in such a way to be portable into such + designs. The spirit of this project was to keep it stripped to the minimum + functions required to do the ISSP functions only, thereby making a portable + framework for integration with other projects. + + The high-level functions have been written in C in order to be portable to + other processors. The low-level functions that are processor dependent, such + as toggling pins and implementing specific delays, are all found in the file + ISSP_Drive_Routines.c. These functions must be converted to equivalent + functions for the HOST processor. Care must be taken to meet the timing + requirements when converting to a new processor. ISSP timing information can + be found in Application Note AN2026. All of the sections of this program + that need to be modified for the host processor have "PROCESSOR_SPECIFIC" in + the comments. By performing a "Find in files" using "PROCESSOR_SPECIFIC" these + sections can easily be identified. + + The variables in this project use Hungarian notation. Hungarian prepends a + lower case letter to each variable that identifies the variable type. The + prefixes used in this program are defined below: + b = byte length variable, signed char and unsigned char + i = 2-byte length variable, signed int and unsigned int + f = byte length variable used as a flag (TRUE = 0, FALSE != 0) + ab = an array of byte length variables + + + After this program has been ported to the desired host processor the timing + of the signals must be confirmed. The maximum SCLK frequency must be checked + as well as the timing of the bulk erase, block write and security write + pulses. + + The maximum SCLK frequency for the target device can be found in the device + datasheet under AC Programming Specifications with a Symbol of "Fsclk". + An oscilloscope should be used to make sure that no half-cycles (the high + time or the low time) are shorter than the half-period of the maximum + freqency. In other words, if the maximum SCLK frequency is 8MHz, there can be + no high or low pulses shorter than 1/(2*8MHz), or 62.5 nsec. + + The test point (TP) functions, enabled by the define USE_TP, provide an output + from the host processor that brackets the timing of the internal bulk erase, + block write and security write programming pulses. An oscilloscope, along with + break points in the PSoC ICE Debugger should be used to verify the timing of + the programming. The Application Note, "Host-Sourced Serial Programming" + explains how to do these measurements and should be consulted for the expected + timing of the erase and program pulses. + +*/ + + + +/* +---------------------------------------------------------------------------- + C main line +---------------------------------------------------------------------------- +*/ + +/* +#include +#include "PSoCAPI.h" +*/ + +/* + ------ Declarations Associated with ISSP Files & Routines ------- + Add these to your project as needed. + +*/ +#include "issp_extern.h" +#include "issp_directives.h" +#include "issp_defs.h" +#include "issp_errors.h" + +#include + +/* ------------------------------------------------------------------------- */ + +unsigned char bBankCounter; +unsigned int iBlockCounter; +unsigned int iChecksumData; +unsigned int iChecksumTarget; +/* Address Numbers for Bytes within a Block */ +unsigned char TargetDatabufLen = TARGET_DATABUFF_LEN; +/* For example, radon is 2 */ +unsigned char NumBanks = NUM_BANKS; +/* Block Numbers for Program Data */ +unsigned char BlocksPerBank = BLOCKS_PER_BANK; +unsigned char SecurityBytesPerBank = SECURITY_BYTES_PER_BANK; +/* received data counter */ +unsigned int RxCounter; + +unsigned char TopMenu = 0xFF; +char MenuCountdown = 10; + +#ifdef TX_ON +void TX8SW_PutHexHalf(char ch) +{ + if (ch >= 10) + TX8SW_PutChar(ch + 'A'-10); + else + TX8SW_PutChar(ch + '0'); +} + +void TX8SW_PutHexWord(unsigned int ch) +{ + TX8SW_PutSHexByte(ch>>8); + TX8SW_PutSHexByte(ch&0xff); +} +#endif + +/* + ========================================================================= + ErrorTrap() + Return is not valid from main for PSOC, so this ErrorTrap routine is used. + For some systems returning an error code will work best. For those, the + calls to ErrorTrap() should be replaced with a return(bErrorNumber). For + other systems another method of reporting an error could be added to this + function -- such as reporting over a communcations port. + ========================================================================= +*/ +void ErrorTrap(unsigned char bErrorNumber) +{ + #ifndef RESET_MODE + /* + Set all pins to highZ to avoid back powering the PSoC through the GPIO + protection diodes. + */ + SetSCLKHiZ(); + SetSDATAHiZ(); + /* If Power Cycle programming, turn off the target */ + RemoveTargetVDD(); + #endif + + #ifdef TX_ON + TX8SW_PutCRLF(); + TX8SW_CPutString("ErrorTrap"); + TX8SW_PutSHexByte(bErrorNumber); + #endif + pr_err("[TKEY] ErrorTrap..%d\n", bErrorNumber); + + /* while (1) + ; + */ + +} + +/* ========================================================================= */ +/* MAIN LOOP */ +/* Based on the diagram in the AN2026 */ +/* ========================================================================= */ + +int ISSP_main(void) +{ + /* + -- This example section of commands show the high-level calls to ------- + -- perform Target Initialization, SilcionID Test, Bulk-Erase, Target --- + -- RAM Load, FLASH-Block Program, and Target Checksum Verification. ---- + */ + pr_err("[TKEY] start..\n"); + + SetSCLKHiZ(); + SetSDATAHiZ(); + /* Cycle power on the target to cause a reset */ + RemoveTargetVDD(); + + #ifdef TX_ON + TX8SW_Start(); + TX8SW_CPutString("\r\nSee HSSP Spec. 40-95004"); + TX8SW_CPutString("\r\nStart HSSP...."); + #endif + +/* +>>>> ISSP Programming Starts Here <<<< + +Acquire the device through reset or power cycle +*/ + +#ifdef RESET_MODE + /* Initialize the Host & Target for ISSP operations */ + fIsError = fXRESInitializeTargetForISSP(); + if (fIsError != 0) + ErrorTrap(fIsError); +#else + /* Initialize the Host & Target for ISSP operations */ + fIsError = fPowerCycleInitializeTargetForISSP(); + + if (fIsError != 0) + ErrorTrap(fIsError); +#endif +/*#if 0 +Run the SiliconID Verification, and proceed according to result. + fIsError = fVerifySiliconID(); + if (fIsError != 0) + ErrorTrap(fIsError); +#endif*/ +#ifdef TX_ON + TX8SW_PutCRLF(); + TX8SW_CPutString("End VerifySiliconID"); +#endif + + /* Bulk-Erase the Device. */ + + fIsError = fEraseTarget(); + if (fIsError != 0) + ErrorTrap(fIsError); + + #ifdef TX_ON + TX8SW_PutCRLF(); + TX8SW_CPutString("End EraseTarget"); + TX8SW_PutCRLF(); + TX8SW_CPutString("Program Flash Blocks Start"); + TX8SW_PutCRLF(); + #endif + +/* program flash block */ + +/* + Program Flash blocks with predetermined data. In the final application + this data should come from the HEX output of PSoC Designer. +*/ + iChecksumData = 0; /* Calculte the device checksum as you go*/ + for (bBankCounter = 0; bBankCounter < NUM_BANKS; bBankCounter++) { + /*PTJ: NUM_BANKS should be 1 for Krypton*/ + for (iBlockCounter = 0; iBlockCounter < BLOCKS_PER_BANK; + iBlockCounter++) { + /*printk("Program Loop : iBlockCounter %d\n" + ,iBlockCounter); + INTLOCK(); + local_irq_save(flags); + PTJ: READ-WRITE-SETUP used here to select SRAM + Bank 1, and TSYNC Enable*/ + #ifdef CY8C20x66 + fIsError = fSyncEnable(); + if (fIsError) { + ErrorTrap(fIsError); + return fIsError; + } + fIsError = fReadWriteSetup(); + if (fIsError) { + /*send write command - swanhan*/ + ErrorTrap(fIsError); + return fIsError; + } + #endif + /*firmware read. + //LoadProgramData(bBankCounter, (unsigned char)iBlockCounter); + //PTJ: this loads the Hydra with test data, not the krypton + //PTJ: this loads the Hydra with test data, not the krypton*/ + LoadProgramData((unsigned char)iBlockCounter, bBankCounter); + iChecksumData += iLoadTarget();/*PTJ: this loads the Krypton*/ + /*dog_kick();*/ + fIsError = fProgramTargetBlock(bBankCounter, + (unsigned char)iBlockCounter); + if (fIsError) { + ErrorTrap(fIsError); + return fIsError; + } +#ifdef CY8C20x66 /*PTJ: READ-STATUS after PROGRAM-AND-VERIFY*/ +#if defined(CONFIG_KOR_MODEL_SHV_E160S) || defined(CONFIG_KOR_MODEL_SHV_E160K) + || defined(CONFIG_KOR_MODEL_SHV_E160L) + msleep(50); +#endif + fIsError = fReadStatus(); + if (fIsError) { + ErrorTrap(fIsError); + return fIsError; + } +#endif + } + } +/* +PTJ: Doing Verify +PTJ: this code isnt needed in the program flow +because we use PROGRAM-AND-VERIFY (ProgramAndVerify SROM Func) +PTJ: which has Verify built into it. +Verify included for completeness in case host desires to do +a stand-alone verify at a later date. +*/ + for (bBankCounter = 0; bBankCounter < NUM_BANKS; bBankCounter++) { + /*PTJ: READ-WRITE-SETUP used here to select SRAM Bank 1*/ +#ifdef CY8C20x66 + fIsError = fSyncEnable(); + if (fIsError) {/*PTJ: 307, added for tsync enable testing.*/ + ErrorTrap(fIsError); + return fIsError; + } + fIsError = fReadWriteSetup(); + if (fIsError) { + ErrorTrap(fIsError); + return fIsError; + } +#endif + /*Load one bank of security data from hex file into buffer*/ + fIsError = fLoadSecurityData(bBankCounter); + if (fIsError) { + ErrorTrap(fIsError); + return fIsError; + } + /*Secure one bank of the target flash*/ + fIsError = fSecureTargetFlash(); + if (fIsError) { + ErrorTrap(fIsError); + return fIsError; + } + } + /*printk("Program security data END\n");*/ +/* + Program security data into target PSoC. In the final application this + data should come from the HEX output of PSoC Designer. +*/ + fIsError = fLoadSecurityData(bBankCounter); + if (fIsError) { + ErrorTrap(fIsError); + return fIsError; + } + + #ifdef CY8C20x66 + fIsError = fReadSecurity(); + if (fIsError) { + ErrorTrap(fIsError); + return fIsError; + } + #endif + +/* checksum */ + /*=======================================================// + //PTJ: Doing Checksum after READ-SECURITY*/ + iChecksumTarget = 0; +for (bBankCounter = 0; bBankCounter < NUM_BANKS; bBankCounter++) { + fIsError = fAccTargetBankChecksum(&iChecksumTarget); + if (fIsError) { + ErrorTrap(fIsError); + return fIsError; + } +} +pr_err("Checksum : iChecksumTarget (0x%X)\n", (unsigned char)iChecksumTarget); +pr_err("Checksum : iChecksumData (0x%X)\n", (unsigned char)iChecksumData); + +if ((unsigned short)(iChecksumTarget&0xffff) != + (unsigned short) (iChecksumData & 0xffff)) { + ErrorTrap(VERIFY_ERROR); + return fIsError; +} + + /* *** SUCCESS *** + // At this point, the Target has been successfully Initialize, ID-Checked, + // Bulk-Erased, Block-Loaded, Block-Programmed, Block-Verified, and Device- + // Checksum Verified. + // You may want to restart Your Target PSoC Here.*/ + ReStartTarget(); + return 0; +} +#endif /* (PROJECT_REV_) */ + diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_revision.h b/drivers/input/keyboard/cypress_touchkey_236/issp_revision.h new file mode 100644 index 00000000000..cb449b9ecbe --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_revision.h @@ -0,0 +1,33 @@ + /*filename: ISSP_Revision.h + + * Copyright 2006-2007, Cypress Semiconductor Corporation. + + * 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. + */ + +#ifndef INC_ISSP_REVISION +#define INC_ISSP_REVISION + /*The PROJECT_REV_xyz is used to make sure that the files in the project + are all from the same revision of the program. Each file starts with an + ifdef that will prevent the file from being compiled if it is not the + correct revision + Set the revision to 3.04 +*/ +#define PROJECT_REV_304 + + +#endif /*(INC_ISSP_REVISION) */ +/* end of file ISSP_Revision.h */ diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_routines.c b/drivers/input/keyboard/cypress_touchkey_236/issp_routines.c new file mode 100644 index 00000000000..efd1996367b --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_routines.c @@ -0,0 +1,1031 @@ +/* filename: ISSP_Routines.c +*/ +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ + + +/* +#include +#include "PSoCAPI.h" +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#include +#include */ +#include +#include +#include +#include +#include +#include + +#include "issp_defs.h" +#include "issp_vectors.h" +#include "issp_extern.h" +#include "issp_errors.h" +#include "issp_directives.h" +#include "issp_delays.h" + +unsigned char bTargetDataIN; +unsigned char abTargetDataOUT[MAX_TARGET_DATABUFF_LEN]; + +unsigned char bTargetAddress; +unsigned char bTargetDataPtr; +unsigned char bTargetID[10]; +unsigned char bTargetStatus[10]; +/*PTJ: created to support READ-STATUS in fReadStatus()*/ + +unsigned char fIsError; + +/* ((((((((((((((((((((( LOW-LEVEL ISSP SUBROUTINE SECTION )))))))))))))))))))) + (( The subroutines in this section use functions from the C file )) + (( ISSP_Drive_Routines.c. The functions in that file interface to the )) + (( processor specific hardware. So, these functions should work as is, if )) + (( the routines in ISSP_Drive_Routines.c are correctly converted. )) + (((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))) +*/ + + /*============================================================================ + RunClock() + Description: + Run Clock without sending/receiving bits. Use this when transitioning from + write to read and read to write "num_cycles" is number of SCLK cycles, not + number of counter cycles. + + SCLK cannot run faster than the specified maximum frequency of 8MHz. Some + processors may need to have delays added after setting SCLK low and setting + SCLK high in order to not exceed this specification. The maximum frequency + of SCLK should be measured as part of validation of the final program + + ============================================================================ +*/ +void RunClock(unsigned int iNumCycles) +{ + int i; + + for (i = 0; i < iNumCycles; i++) { + SCLKLow(); + SCLKHigh(); + } +} + + /*============================================================================ + bReceiveBit() + Clocks the SCLK pin (high-low-high) and reads the status of the SDATA pin + after the rising edge. + + SCLK cannot run faster than the specified maximum frequency of 8MHz. Some + processors may need to have delays added after setting SCLK low and setting + SCLK high in order to not exceed this specification. The maximum frequency + of SCLK should be measured as part of validation of the final program + + Returns: + 0 if SDATA was low + 1 if SDATA was high + ============================================================================ +*/ +unsigned char bReceiveBit(void) +{ + SCLKLow(); + SCLKHigh(); + if (fSDATACheck()) + return 1; + else + return 0; +} + + /*============================================================================ + bReceiveByte() + Calls ReceiveBit 8 times to receive one byte. + Returns: + The 8-bit values recieved. + ============================================================================ +*/ +unsigned char bReceiveByte(void) +{ + unsigned char b; + unsigned char bCurrByte = 0x00; + + for (b = 0; b < 8; b++) + bCurrByte = (bCurrByte<<1) + bReceiveBit(); + + return bCurrByte; +} + + + /* + ============================================================================ + SendByte() + This routine sends up to one byte of a vector, one bit at a time. + bCurrByte the byte that contains the bits to be sent. + bSize the number of bits to be sent. Valid values are 1 to 8. + + SCLK cannot run faster than the specified maximum frequency of 8MHz. Some + processors may need to have delays added after setting SCLK low and setting + SCLK high in order to not exceed this specification. The maximum frequency + of SCLK should be measured as part of validation of the final program + + There is no returned value. + ============================================================================ +*/ +void SendByte(unsigned char bCurrByte, unsigned char bSize) +{ + unsigned char b = 0; + + for (b = 0; b < bSize; b++) { + if (bCurrByte & 0x80) { + SetSDATAHigh(); + SCLKHigh(); + SCLKLow(); + } else { + SetSDATALow(); + SCLKHigh(); + SCLKLow(); + } + bCurrByte = bCurrByte << 1; + } +} + + /*============================================================================ + SendVector() + This routine sends the vector specifed. All vectors constant strings found + in ISSP_Vectors.h. The data line is returned to HiZ after the vector is + sent. + bVect a pointer to the vector to be sent. + nNumBits the number of bits to be sent. + bCurrByte scratch var to keep the byte to be sent. + + There is no returned value. + ============================================================================ +*/ +void SendVector(const unsigned char *bVect, unsigned int iNumBits) +{ + SetSDATAStrong(); + while (iNumBits > 0) { + if (iNumBits >= 8) { + SendByte(*(bVect), 8); + iNumBits -= 8; + bVect++; + } else { + SendByte(*(bVect), iNumBits); + iNumBits = 0; + } + } + SetSDATAHiZ(); +} + + +/* + ============================================================================ + fDetectHiLoTransition() + Waits for transition from SDATA = 1 to SDATA = 0. Has a 100 msec timeout. + TRANSITION_TIMEOUT is a loop counter for a 100msec timeout when waiting for + a high-to-low transition. This is used in the polling loop of + fDetectHiLoTransition(). The timing of the while(1) loops can be calculated + and the number of loops is counted, using iTimer, to determine when 100 + msec has passed. + + SCLK cannot run faster than the specified maximum frequency of 8MHz. Some + processors may need to have delays added after setting SCLK low and setting + SCLK high in order to not exceed this specification. The maximum frequency + of SCLK should be measured as part of validation of the final program + + Returns: + 0 if successful + -1 if timed out. + ============================================================================ + +*/ +signed char fDetectHiLoTransition(void) +{ + /* nTimer breaks out of the while loops if the wait in the two loops totals + more than 100 msec. Making this static makes the loop run a faster. + This is really a processor/compiler dependency and it not needed. +*/ + unsigned long int iTimer = 0; + + /* NOTE: + These loops look unconventional, but it is necessary to check SDATA_PIN + as shown because the transition can be missed otherwise, due to the + length of the SDATA Low-High-Low after certain commands. + + Generate clocks for the target to pull SDATA High + + */ + iTimer = TRANSITION_TIMEOUT; + + SetSCLKStrong(); + while (1) { + SCLKLow(); + /*Delay(DELAY100us); + Delay(CLK_DELAY); */ + if (fSDATACheck()) /* exit once SDATA goes HI */ + break; + SCLKHigh(); + /*Delay(DELAY100us); + Delay(CLK_DELAY); + If the wait is too long then timeout*/ + if (iTimer-- == 0) + return ERROR; + } + /*printk(KERN_ERR"[TKEY] *****1\n");*/ + /* + Generate Clocks and wait for Target to pull SDATA Low again + */ + iTimer = TRANSITION_TIMEOUT; + while (1) { + SCLKLow(); + /*udelay(1);*/ + if (!fSDATACheck()) /* exit once SDATA returns LOW */ + break; + /*SCLKHigh(); + udelay(300); + If the wait is too long then timeout */ + if (iTimer-- == 0) + return ERROR; + } + /*printk(KERN_ERR"[TKEY] *****2\n");*/ + return PASS; +} + + +/* ((((((((((((((((((((( HIGH-LEVEL ISSP ROUTINE SECTION )))))))))))))))))))))) + (( These functions are mostly made of calls to the low level routines )) + (( above. This should isolate the processor-specific changes so that )) + (( these routines do not need to be modified. )) + (((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))) +*/ + +#ifdef RESET_MODE + /*============================================================================ + fXRESInitializeTargetForISSP() + Implements the intialization vectors for the device. + Returns: + 0 if successful + INIT_ERROR if timed out on handshake to the device. + ============================================================================ +*/ +signed char fXRESInitializeTargetForISSP(void) +{ + /*Configure the pins for initialization*/ + SetSDATAHiZ(); + SetSCLKStrong(); + SCLKLow(); + SetXRESStrong(); + + /* Cycle reset and put the device + in programming mode when it exits reset */ + AssertXRES(); + Delay(XRES_CLK_DELAY); + DeassertXRES(); + + /* + !!! NOTE: + The timing spec that requires that the first Init-Vector happen within + 1 msec after the reset/power up. For this reason, it is not advisable + to separate the above RESET_MODE or POWER_CYCLE_MODE code from the + Init-Vector instructions below. Doing so could introduce excess delay + and cause the target device to exit ISSP Mode. + + PTJ: Send id_setup_1 instead of init1_v + PTJ: both send CA Test Key and do a Calibrate1 SROM function + */ + SendVector(id_setup_1, num_bits_id_setup_1); + fIsError = fDetectHiLoTransition(); + if (fIsError != 0) + return INIT_ERROR; + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + /* + NOTE: DO NOT not wait for HiLo on SDATA after vector Init-3 + it does not occur (per spec). + */ + return PASS; +} + +#else /* else = the part is power cycle programmed */ +/* + ============================================================================ + fPowerCycleInitializeTargetForISSP() + Implements the intialization vectors for the device. + The first time fDetectHiLoTransition is called the Clk pin is highZ because + the clock is not needed during acquire. + Returns: + 0 if successful + INIT_ERROR if timed out on handshake to the device. + ============================================================================ + +*/ +signed char fPowerCycleInitializeTargetForISSP(void) +{ + unsigned char n; + +/* + Set all pins to highZ to avoid back powering the PSoC through the GPIO + protection diodes. +*/ + SetSCLKHiZ(); + SetSDATAHiZ(); + + /* Turn on power to the target device before other signals */ + SetTargetVDDStrong(); + for (n = 0; n < 200; n++) + Delay(50000); + ApplyTargetVDD(); + /* wait 1msec for the power to stabilize */ + + for (n = 0; n < 10; n++) + Delay(DELAY100us); + /*printk(KERN_ERR"[TKEY] ___1111\n");*/ + + /* + Set SCLK to high Z so there is no clock and wait for a high to low + transition on SDAT. SCLK is not needed this time. + + */ + SetSCLKHiZ(); + fIsError = fDetectHiLoTransition(); + /*printk(KERN_ERR"[TKEY] ___2222 %d\n",fIsError);*/ + if (fIsError != 0) + return INIT_ERROR; + + /*Configure the pins for initialization */ + SetSDATAHiZ(); + SetSCLKStrong(); + SCLKLow(); +/*PTJ: DO NOT SET A BREAKPOINT HERE AND EXPECT SILICON ID TO PASS! + + !!! NOTE: + The timing spec that requires that the first Init-Vector happen within + 1 msec after the reset/power up. For this reason, it is not advisable + to separate the above RESET_MODE or POWER_CYCLE_MODE code from the + Init-Vector instructions below. Doing so could introduce excess delay + and cause the target device to exit ISSP Mode. + + */ + + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + /*20100114 KJHW(Jason) : 0114 by KJHW */ + + + SendVector(id_setup_1, num_bits_id_setup_1); + + fIsError = fDetectHiLoTransition(); + if (fIsError != 0) + return INIT_ERROR; + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + /* + NOTE: DO NOT not wait for HiLo on SDATA after vector Init-3 + it does not occur (per spec). + */ + return PASS; +} +#endif + + +/* ============================================================================ +// fVerifySiliconID() +// Returns: +// 0 if successful +// Si_ID_ERROR if timed out on handshake to the device. +// ==========================================================================*/ +signed char fVerifySiliconID(void) +{ + SendVector(id_setup_2, num_bits_id_setup_2); + fIsError = fDetectHiLoTransition(); + if (fIsError) { + /*printk("fVerifySiliconID(): fDetectHiLoTransition Error\n");*/ + return SiID_ERROR; + } + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + SendVector(tsync_enable, num_bits_tsync_enable); + + /*Send Read ID vector and get Target ID*/ + SendVector(read_id_v, 11);/* Read-MSB Vector is the first 11-Bits*/ + RunClock(2);/* Two SCLK cycles between write & read*/ + bTargetID[0] = bReceiveByte(); + RunClock(1); + SendVector(read_id_v+2, 12);/* 1+11 bits starting from the 3rd byte*/ + + RunClock(2);/* Read-LSB Command*/ + bTargetID[1] = bReceiveByte(); + + RunClock(1); + SendVector(read_id_v+4, 1);/* 1 bit starting from the 5th byte*/ + + /*read Revision ID from Accumulator A and Accumulator X*/ + SendVector(read_id_v+5, 11);/*11 bits starting from the 6th byte*/ + RunClock(2); + bTargetID[2] = bReceiveByte();/*Read from Acc.X*/ + RunClock(1); + SendVector(read_id_v+7, 12);/*1+11 bits starting from the 8th byte*/ + RunClock(2); + bTargetID[3] = bReceiveByte();/*Read from Acc.A*/ + + RunClock(1); + SendVector(read_id_v+4, 1);/*1bit starting from the 5th byte,*/ + SendVector(tsync_disable, num_bits_tsync_disable); + + return PASS; +} + +/* PTJ: ======================================================================= +// fReadStatus() +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// =========================================================================*/ +signed char fReadStatus(void) +{ + SendVector(tsync_enable, num_bits_tsync_enable); + /*Send Read ID vector and get Target ID*/ + SendVector(read_id_v, 11);/* Read-MSB Vector is the first 11-Bits*/ + RunClock(2); /* Two SCLK cycles between write & read*/ + bTargetStatus[0] = bReceiveByte(); + RunClock(1); + /*SendVector(read_id_v+2, 12);// 12 bits starting from the 3rd character + + //RunClock(2); // Read-LSB Command + //bTargetStatus[1] = bReceiveByte(); + //RunClock(1);*/ + SendVector(read_id_v+4, 1);/* 1 bit starting from the 5th character*/ + SendVector(tsync_disable, num_bits_tsync_disable); + + if (bTargetStatus[0] == target_status00_v) + return PASS; + /*PTJ: Status = 00 means Success, the SROM function did + what it was supposed to*/ + if (bTargetStatus[0] == target_status01_v) + return STATUS_ERROR; + /*PTJ: Status = 01 means that function is not allowed because of block + level protection, for test with verify_setup (VERIFY-SETUP)*/ + if (bTargetStatus[0] == target_status03_v) + return STATUS_ERROR; + /*PTJ: Status = 03 is fatal error, SROM halted*/ + if (bTargetStatus[0] == target_status04_v) + return STATUS_ERROR; + /*PTJ: Status = 04 means there was a checksum faliure with either + the smart write code checksum, or the smart write paramters + checksum, for test with PROGRAM-AND-VERIFY*/ + if (bTargetStatus[0] == target_status06_v) + return STATUS_ERROR; + /*PTJ: Status = 06 means that Calibrate1 failed, for test with + id_setup_1 (ID-SETUP-1)*/ + else + return STATUS_ERROR; +} + + +/* PTJ: ======================================================================= +// fReadCalRegisters() +// PTJ: use this to read some cal registers that should be loaded by + Calibrate1 in id_setup_1 +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// ==========================================================================*/ +signed char fReadCalRegisters(void) +{ + SendVector(tsync_enable, num_bits_tsync_enable); + SendVector(Switch_Bank1, 22); + SendVector(read_IMOtrim, 11);/* Read-MSB Vector is the first 11-Bits*/ + RunClock(2);/* Two SCLK cycles between write & read*/ + bTargetStatus[0] = bReceiveByte(); + RunClock(1); + /*Set SDATA to Strong Drive here because SendByte() does not*/ + SetSDATAStrong(); + SendByte(read_reg_end, 1); + + SendVector(read_SPCtrim, 11);/* Read-MSB Vector is the first 11-Bits*/ + RunClock(2);/* Two SCLK cycles between write & read*/ + bTargetStatus[1] = bReceiveByte(); + RunClock(1); + /* Set SDATA to Strong Drive here because SendByte() does not*/ + SetSDATAStrong(); + SendByte(read_reg_end, 1); + + SendVector(read_VBGfinetrim, 11);/* Read-MSB Vector is the first + 11-Bits*/ + RunClock(2);/* Two SCLK cycles between write & read*/ + bTargetStatus[2] = bReceiveByte(); + RunClock(1); + /*Set SDATA to Strong Drive here because SendByte() does not*/ + SetSDATAStrong(); + SendByte(read_reg_end, 1); + + SendVector(Switch_Bank0, 22); + + SendVector(tsync_disable, num_bits_tsync_disable); + + if (bTargetStatus[0] == target_status00_v) { + return PASS; + /*PTJ: Status = 00 means Success, the SROM function + did what it was supposed to*/ + } + return PASS; +} + +/* PTJ: ======================================================================= +// fReadWriteSetup() +// PTJ: The READ-WRITE-SETUP vector will enable TSYNC and switches the device +// to SRAM bank1 for PROGRAM-AND-VERIFY, SECURE and VERIFY-SETUP. +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// ==========================================================================*/ +signed char fReadWriteSetup(void) +{ + SendVector(read_write_setup, num_bits_read_write_setup); + return PASS; + /*PTJ: is there anything else that should be done?*/ +} + +/* PTJ: ======================================================================= +// fSyncEnable() +// PTJ: The SYNC-ENABLE vector will enable TSYNC +// +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// ==========================================================================*/ +signed char fSyncEnable(void) +{ + SendVector(tsync_enable, num_bits_tsync_enable); + /*PTJ: 307 for tsync enable testing*/ + return PASS; + /*PTJ: is there anything else that should be done?*/ +} + +/* PTJ: ======================================================================= +// fSyncDisable() +// PTJ: The SYNC-ENABLE vector will enable TSYNC +// +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// =========================================================================*/ +signed char fSyncDisable(void) +{ + SendVector(tsync_disable, num_bits_tsync_disable); + /*PTJ: 307 for tsync enable testing*/ + return PASS; +} + +/* ============================================================================ + fEraseTarget() + Perform a bulk erase of the target device. + Returns: + 0 if successful + ERASE_ERROR if timed out on handshake to the device. + ============================================================================ + +*/ + +signed char fEraseTarget(void) +{ + SendVector(erase, num_bits_erase); + fIsError = fDetectHiLoTransition(); + if (fIsError != 0) + return ERASE_ERROR; + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + return PASS; +} + + + /*============================================================================ + LoadTarget() + Transfers data from array in Host to RAM buffer in the target. + Returns the checksum of the data. + ============================================================================*/ +unsigned int iLoadTarget(void) +{ + unsigned char bTemp; + unsigned int iChecksumData = 0; + /*Set SDATA to Strong Drive here because SendByte() does not */ + SetSDATAStrong(); + bTargetAddress = 0x00; + bTargetDataPtr = 0x00; + while (bTargetDataPtr < TargetDatabufLen) { + bTemp = abTargetDataOUT[bTargetDataPtr]; + iChecksumData += bTemp; + SendByte(write_byte_start, 4); + /*PTJ: we need to be able to write 128 bytes from address 0x80 to 0xFF*/ + SendByte(bTargetAddress, 7); + /*PTJ: we need to be able to write 128 bytes from address 0x80 to 0xFF*/ + SendByte(bTemp, 8); + SendByte(write_byte_end, 3); + bTargetAddress += 2; + /*PTJ: inc by 2 in order to support a 128 byte address + space, MSB~1 for address*/ + bTargetDataPtr++; + } + + return iChecksumData; + } + + +#ifdef MULTI_BANK +/* ============================================================================ +// SetBankNumber() +// Set the bank number in the target device. +// Returns: +// none +// ==========================================================================*/ +void SetBankNumber(unsigned char bBankNumber) +{ + /*Send the bank-select vector.*/ + SendVector(set_bank_number, 33); + /* Set the drive here because SendByte() does not.*/ + SetSDATAStrong(); + SendByte(bBankNumber, 8); + SendVector(set_bank_number_end, 25); +} +#endif + /*============================================================================ + fProgramTargetBlock() + Program one block with data that has been loaded into a RAM buffer in the + target device. + Returns: + 0 if successful + BLOCK_ERROR if timed out on handshake to the device. + ============================================================================ +*/ + +signed char fProgramTargetBlock(unsigned char bBankNumber, + unsigned char bBlockNumber) +{ + SendVector(tsync_enable, num_bits_tsync_enable); + SendVector(set_block_num, num_bits_set_block_num); + /* Set the drive here because SendByte() does not.*/ + SetSDATAStrong(); + SendByte(bBlockNumber, 8); + SendByte(set_block_num_end, 3); + SendVector(tsync_disable, num_bits_tsync_disable); + /*Send the program-block vector.*/ + SendVector(program_and_verify, num_bits_program_and_verify); + /*PTJ: PROGRAM-AND-VERIFY + wait for acknowledge from target.*/ + fIsError = fDetectHiLoTransition(); + if (fIsError) + return BLOCK_ERROR; + /* Send the Wait-For-Poll-End vector*/ + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + return PASS; + + /*PTJ: Don't do READ-STATUS here because that will + //PTJ: require that we return multiple error values, if error occurs*/ +} + + + /*============================================================================ + fAddTargetBankChecksum() + Reads and adds the target bank checksum to the referenced accumulator. + Returns: + 0 if successful + VERIFY_ERROR if timed out on handshake to the device. + ============================================================================ +*/ + +signed char fAccTargetBankChecksum(unsigned int *pAcc) +{ + unsigned int wCheckSumData = 0; + + SendVector(checksum_v, num_bits_checksum); + + fIsError = fDetectHiLoTransition(); + if (fIsError != 0) + return CHECKSUM_ERROR; + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + SendVector(tsync_enable, num_bits_tsync_enable); + SendVector(read_checksum_v, 11); /*first 11-bits is ReadCKSum-MSB*/ + RunClock(2); /*Two SCLKs between write & read*/ + bTargetDataIN = bReceiveByte(); + wCheckSumData = bTargetDataIN<<8; + RunClock(1); + /*12 bits starting from 3rd character*/ + SendVector(read_checksum_v + 2, 12); + + RunClock(2); /* Read-LSB Command*/ + bTargetDataIN = bReceiveByte(); + wCheckSumData |= (bTargetDataIN & 0xFF); + RunClock(1); + /*Send the final bit of the command */ + SendVector(read_checksum_v + 3, 1); + /* Send the final bit of the command + PTJ: read_checksum_v may have to change if TSYNC needs to be enabled*/ + SendVector(tsync_disable, num_bits_tsync_disable); + + *pAcc = wCheckSumData; + + return PASS; +} + +/* + + ============================================================================ + ReStartTarget() + After programming, the target PSoC must be reset to take it out of + programming mode. This routine performs a reset. + ============================================================================ +*/ + +void ReStartTarget(void) +{ + int i; + #ifdef RESET_MODE + /* Assert XRES, then release, then disable XRES-Enable */ + AssertXRES(); + Delay(XRES_CLK_DELAY); + DeassertXRES(); + #else + /* Set all pins to highZ to avoid back powering + the PSoC through the GPIO protection diodes. + */ + SetSCLKHiZ(); + SetSDATAHiZ(); + /* Cycle power on the target to cause a reset */ + RemoveTargetVDD(); + for (i = 0; i < 100; i++) + Delay(50000); + ApplyTargetVDD(); + #endif +} + + /*============================================================================ + fVerifySetup() + Verify the block just written to. This can be done byte-by-byte before the + protection bits are set. + Returns: + 0 if successful + BLOCK_ERROR if timed out on handshake to the device. + ============================================================================ +*/ + +signed char fVerifySetup(unsigned char bBankNumber, unsigned char bBlockNumber) +{ + SendVector(tsync_enable, num_bits_tsync_enable); + SendVector(set_block_num, num_bits_set_block_num); + + /* Set the drive here because SendByte() does not */ + SetSDATAStrong(); + SendByte(bBlockNumber, 8); + SendByte(set_block_num_end, 3); + + SendVector(tsync_disable, num_bits_tsync_disable); + SendVector(verify_setup, num_bits_my_verify_setup); + fIsError = fDetectHiLoTransition(); + if (fIsError != 0) + return VERIFY_ERROR; + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + return PASS; +} + + /*============================================================================ + fReadByteLoop() + Reads the data back from Target SRAM and compares it to expected data in + Host SRAM + Returns: + 0 if successful + BLOCK_ERROR if timed out on handshake to the device. + ============================================================================ +*/ + +signed char fReadByteLoop(void) +{ + bTargetAddress = 0; + bTargetDataPtr = 0; + + while (bTargetDataPtr < TargetDatabufLen) { + /* Send Read Byte vector and then get a byte from Target */ + SendVector(read_byte_v, 4); + /* Set the drive here because SendByte() does not */ + SetSDATAStrong(); + SendByte(bTargetAddress, 7); + + /* Run two SCLK cycles between writing and reading */ + RunClock(2); + /* Set to HiZ so Target can drive SDATA */ + SetSDATAHiZ(); + bTargetDataIN = bReceiveByte(); + + RunClock(1); + /* Send the ReadByte Vector End */ + SendVector(read_byte_v + 1, 1); + + if (bTargetDataIN != abTargetDataOUT[bTargetDataPtr]) { + #ifdef TX_ON + TX8SW_PutCRLF(); + TX8SW_CPutString("bTargetDataIN : "); + TX8SW_PutSHexByte(bTargetDataIN); + TX8SW_CPutString(" abTargetDataOUT : "); + TX8SW_PutSHexByte(abTargetDataOUT[bTargetDataPtr]); + #endif + return BLOCK_ERROR; + } + + bTargetDataPtr++; + bTargetAddress += 2; + + } + + return PASS; +} + + +/* ============================================================================ +// fVerifyTargetBlock() +// Verify the block just written to. This can be done byte-by-byte before the +// protection bits are set. +// Returns: +// 0 if successful +// BLOCK_ERROR if timed out on handshake to the device. +// ==========================================================================*/ +signed char fVerifyTargetBlock(unsigned char bBankNumber, + unsigned char bBlockNumber) +{ + SendVector(set_block_number, 11); + /*Set the drive here because SendByte() does not*/ + SetSDATAStrong(); + SendByte(bBlockNumber, 8); + SendByte(set_block_number_end, 3); + + SendVector(verify_setup_v, num_bits_verify_setup); + fIsError = fDetectHiLoTransition(); + if (fIsError) + return BLOCK_ERROR; + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + bTargetAddress = 0; + bTargetDataPtr = 0; + while (bTargetDataPtr < TARGET_DATABUFF_LEN) { + /*Send Read Byte vector and then get a byte from Target*/ + SendVector(read_byte_v, 4); + /*PTJ 308: this was changed from sending the first 5 bits to sending + the first 4 Set the drive here because SendByte() does not*/ + SetSDATAStrong(); + SendByte(bTargetAddress, 6); + RunClock(2);/* Run two SCLK cycles between writing and reading*/ + SetSDATAHiZ();/* Set to HiZ so Target can drive SDATA*/ + bTargetDataIN = bReceiveByte(); + RunClock(1); + SendVector(read_byte_v + 1, 1);/* Send the ReadByte Vector End*/ + /* Test the Byte that was read from the Target against the original + // value (already in the 128-Byte array "abTargetDataOUT[]"). If it + // matches, then bump the address & pointer,loop-back and continue. + // If it does NOT match abort the loop and return an error.*/ + if (bTargetDataIN != abTargetDataOUT[bTargetDataPtr]) + return BLOCK_ERROR; + bTargetDataPtr++; + /* Increment the address by four to accomodate 6-Bit addressing + (puts the 6-bit address into MSBit locations for "SendByte()").*/ + bTargetAddress += 4; + } + return PASS; +} + +/* + fSecureTargetFlash() + Before calling, load the array, abTargetDataOUT, with the desired security + settings using LoadArrayWithSecurityData(StartAddress,Length,SecurityType). + The can be called multiple times with different SecurityTypes as needed for + particular Flash Blocks. Or set them all the same using the call below: + LoadArrayWithSecurityData(0,SECURITY_BYTES_PER_BANK, 0); + Returns: + 0 if successful + SECURITY_ERROR if timed out on handshake to the device. + ============================================================================ +*/ + +signed char fSecureTargetFlash(void) +{ + unsigned char bTemp; + + bTargetAddress = 0x00; + bTargetDataPtr = 0x00; + + SetSDATAStrong(); + while (bTargetDataPtr < SecurityBytesPerBank) { + bTemp = abTargetDataOUT[bTargetDataPtr]; + SendByte(write_byte_start, 4); + SendByte(bTargetAddress, 7); + SendByte(bTemp, 8); + SendByte(write_byte_end, 3); + + bTargetAddress += 2; + /*PTJ: inc by 2 in order to support a 128 byte address space*/ + bTargetDataPtr++; + } + + SendVector(secure, num_bits_secure); + fIsError = fDetectHiLoTransition(); + if (fIsError != 0) + return SECURITY_ERROR; + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + return PASS; +} + +/* ============================================================================ +// PTJ: fReadSecurity() +// This reads from SM0 with Read Supervisory SPC command. +// Need to have SPC Test Mode enabled before using these commands? +// Returns: +// 0 if successful +// __________ if timed out on handshake to the device. +// =========================================================================*/ +signed char fReadSecurity(void) +{ + SendVector(ReadSecuritySetup, num_bits_ReadSecuritySetup); + /*SendVector(SPCTestMode_enable, num_bits_SPCTestMode_enable);*/ + bTargetAddress = 0x00; + while (bTargetAddress < (SECURITY_BYTES_PER_BANK * 2)) { + /*PTJ: we do SECURITY_BYTES_PER_BANK * 2 because we + bTargetAddress += 2 PTJ: TSYNC Enable*/ + SendVector(tsync_enable, num_bits_tsync_enable); + SendVector(read_security_pt1, num_bits_read_security_pt1); + /* Set the drive here because SendByte() does not.*/ + SetSDATAStrong(); + SendByte(bTargetAddress, 7); + /*PTJ: hardcode MSb of address as 0 in bit stream*/ + SendVector(read_security_pt1_end, num_bits_read_security_pt1_end); + /*PTJ: TSYNC Disable*/ + SendVector(tsync_disable, num_bits_tsync_disable); + SendVector(read_security_pt2, num_bits_read_security_pt2); + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + SendVector(read_security_pt3, num_bits_read_security_pt3); + SetSDATAStrong(); + SendByte(bTargetAddress, 7); + SendVector(read_security_pt3_end, num_bits_read_security_pt3_end); + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + bTargetAddress += 2; + } + + bTargetAddress = 0x00; + bTargetDataPtr = 0x00; + + SendVector(tsync_enable, num_bits_tsync_enable); + /*PTJ: 307, added for tsync testing*/ + while (bTargetAddress < (SECURITY_BYTES_PER_BANK * 2)) { + /*PTJ: we do SECURITY_BYTES_PER_BANK * 2 because we + bTargetAddress += 2*/ + + /*Send Read Byte vector and then get a byte from Target*/ + SendVector(read_byte_v, 4); + /* Set the drive here because SendByte() does not*/ + SetSDATAStrong(); + SendByte(bTargetAddress, 7); + RunClock(2); /* Run two SCLK cycles between writing and reading*/ + SetSDATAHiZ(); /* Set to HiZ so Target can drive SDATA*/ + bTargetDataIN = bReceiveByte(); + RunClock(1); + SendVector(read_byte_v + 1, 1); /* Send the ReadByte Vector End*/ + + /*Test the Byte that was read from the Target against the original + value (already in the 128-Byte array "abTargetDataOUT[]"). If it + matches, then bump the address & pointer,loop-back and continue. + If it does NOT match abort the loop and return and error.*/ + if (bTargetDataIN != abTargetDataOUT[bTargetDataPtr]) + return BLOCK_ERROR; + /* Increment the address by two to accomodate 7-Bit addressing*/ + /* (puts the 7-bit address into MSBit locations for "SendByte()").*/ + bTargetDataPtr++; + bTargetAddress += 2; + } + +SendVector(tsync_disable, num_bits_tsync_disable); +/*PTJ: 307, added for tsync testing*/ +return PASS; +} + +#endif /*(PROJECT_REV_) */ +/* end of file ISSP_Routines.c */ diff --git a/drivers/input/keyboard/cypress_touchkey_236/issp_vectors.h b/drivers/input/keyboard/cypress_touchkey_236/issp_vectors.h new file mode 100644 index 00000000000..4e85ba2db8d --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/issp_vectors.h @@ -0,0 +1,1089 @@ +/* filename: ISSP_Vectors.h*/ +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +//CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +//INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +//MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +//BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +//OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +//BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +//LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, +// WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// Cypress reserves the right to make changes without further notice to the +// materials described herein. Cypress does not assume any liability arising +// out of the application or use of any product or circuit described herein. +// Cypress does not authorize its products for use as critical components in +// life-support systems where a malfunction or failure may reasonably be +// expected to result in significant injury to the user. The inclusion of +// Cypress? product in a life-support systems application implies that the +// manufacturer assumes all risk of such use and in doing so indemnifies +// Cypress against all charges. +// +// Use may be limited by and subject to the applicable Cypress software +// license agreement. +// +//-------------------------------------------------------------------------*/ +#ifndef INC_ISSP_VECTORS +#define INC_ISSP_VECTORS + + #include "issp_directives.h" + +#define HEX_DEFINE +/* ------------------------- PSoC CY8C20x66 Devices -------------------------*/ + +#ifdef CY8C20236/* 2009.03.26. kimc*/ + unsigned char target_id_v[] = {0x00, 0xb3, 0x52, 0x21}; + /*ID for CY8C20236*/ +#endif +#ifdef CY8C20246/* 2009.03.26. kimc*/ + unsigned char target_id_v[] = {0x00, 0xAA, 0x52, 0x21}; + /*ID for CY8C20246*/ +#endif +#ifdef CY8C20266 + unsigned char target_id_v[] = {0x00, 0x96, 0x52, 0x21}; + /*ID for CY8C20266*/ +#endif +#ifdef CY8C20366 + unsigned char target_id_v[] = {0x00, 0x97, 0x52, 0x21}; + /*ID for CY8C20366*/ +#endif +#ifdef CY8C20466 + unsigned char target_id_v[] = {0x00, 0x98, 0x52, 0x21}; + /*ID for CY8C20466*/ +#endif +#ifdef CY8C20566 + unsigned char target_id_v[] = {0x00, 0x99, 0x52, 0x21}; + /*ID for CY8C20566*/ +#endif +#ifdef CY8C20666 + unsigned char target_id_v[] = {0x00, 0x9c, 0x52, 0x21}; + /*ID for CY8C20666*/ +#endif +#ifdef CY8C20066 + unsigned char target_id_v[] = {0x00, 0x9a, 0x52, 0x21}; + /*ID for CY8C20066*/ +#endif +#ifdef CY8C200661 + unsigned char target_id_v[] = {0x00, 0x9b, 0x52, 0x21}; + /*ID for CY8C200661*/ +#endif + +#ifdef CY8C20x66 + unsigned char target_status00_v = 0x00;/*PTJ: Status = 00 means + Success, the SROM function did what it was supposed to*/ + unsigned char target_status01_v = 0x01; +/*PTJ: Status = 01 means that function is not allowed because of block +level protection, for test with verify_setup (VERIFY-SETUP)*/ + unsigned char target_status03_v = 0x03; +/*PTJ: Status = 03 is fatal error, SROM halted*/ + unsigned char target_status04_v = 0x04; +/*PTJ: Status = 04 means that ___ for test with ___ (PROGRAM-AND-VERIFY)*/ + unsigned char target_status06_v = 0x06; +/*PTJ: Status = 06 means that Calibrate1 failed, for test +with id_setup_1 (ID-SETUP-1)*/ +#endif + +/********** CY8CTMA30x, CY8CTMG30x, CY8CTST30x series by KIMC, 2009.08.11 ***/ +/* ------------------------- PSoC CY8CTMA30x, CY8CTMG30x, CY8CTST30x Devices-- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CY8CTST300_36 /*CY8CTST300_36LQXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x06, 0x71, 0x70, 0x11}; +#endif +#ifdef CY8CTST300_48 /*CY8CTST300_48LTXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x06, 0x72, 0x70, 0x11}; +#endif +#ifdef CY8CTST300_49 /*CY8CTST300_49FNXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x06, 0x73, 0x70, 0x11}; +#endif +#ifdef CY8CTMA300_36 /*CY8CTMA300_36LQXI // 2009.08.11, Test OK.*/ + unsigned char target_id_v[] = {0x05, 0x71, 0x70, 0x11}; +#endif +#ifdef CY8CTMA300_48 /*CY8CTMA300_48LTXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x72, 0x70, 0x11}; +#endif +#ifdef CY8CTMA300_49 /*CY8CTMA300_49FNXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x73, 0x70, 0x11}; +#endif +#ifdef CY8CTMG300_36 /*CY8CTMG300_36LQXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x07, 0x71, 0x70, 0x11}; +#endif +#ifdef CY8CTMG300_48 /*CY8CTMG300_48LTXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x07, 0x72, 0x70, 0x11}; +#endif +#ifdef CY8CTMG300_49 /*CY8CTMG300_49FNXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x07, 0x73, 0x70, 0x11}; +#endif +#ifdef CY8CTMG300B_36 /*CY8CTMG300B_36LQXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x07, 0x75, 0x70, 0x11}; +#endif +#ifdef CY8CTMA300B_36 /*CY8CTMA300B_36LQXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x74, 0x70, 0x11}; +#endif +#ifdef CY8CTST300B_36 /* CY8CTST300B_36LQXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x06, 0x74, 0x70, 0x11}; +#endif +#ifdef CY8CTMA301_36 /*CY8CTMA301_36LQXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x75, 0x70, 0x11}; +#endif +#ifdef CY8CTMA301_48 /*CY8CTMA301_48LTXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x76, 0x70, 0x11}; +#endif +#ifdef CY8CTMA301D_36 /*CY8CTMA301D_36LQXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x77, 0x70, 0x11}; +#endif +#ifdef CY8CTMA301D_48 /*CY8CTMA301D_48LTXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x78, 0x70, 0x11}; +#endif +#ifdef CY8CTMA300D_36 /* CY8CTMA300D_36LQXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x79, 0x70, 0x11}; +#endif +#ifdef CY8CTMA300D_48 /* CY8CTMA300D_48LTXI // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x80, 0x70, 0x11}; +#endif +#ifdef CY8CTMA300D_49 /* CY8CTMA300D_49FNXIT // 2009.08.11, not tested.*/ + unsigned char target_id_v[] = {0x05, 0x81, 0x70, 0x11}; +#endif +/******************************************************************************/ + + +/********** CY8CTMG/TST series modified by KJHW, 2009.08.14 *******************/ +/* Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CY8CTMG110 +unsigned char target_id_v[] = {0x07, 0x38};/*ID for CY8CTMG110*/ + +unsigned char target_status00_v = 0x00; +/*PTJ: Status = 00 means Success, the SROM function did what +it was supposed to*/ +unsigned char target_status01_v = 0x01; +/*PTJ: Status = 01 means that function is not allowed because of block +level protection,for test with verify_setup (VERIFY-SETUP)*/ +unsigned char target_status03_v = 0x03; +/*PTJ: Status = 03 is fatal error, SROM halted*/ +unsigned char target_status04_v = 0x04;/*PTJ: Status = 04 means that + ___ for test with ___ (PROGRAM-AND-VERIFY)*/ +unsigned char target_status06_v = 0x06; +/*PTJ: Status = 06 means that Calibrate1 failed, +for test with id_setup_1 (ID-SETUP-1)*/ +#endif + +#ifdef CY8CTST200_24PIN + unsigned char target_id_v[] = {0x06, 0x6D, 0x52, 0x21}; + /*ID for CY8CTST200*/ +#endif +#ifdef CY8CTST200_32PIN + unsigned char target_id_v[] = {0x06, 0x6E, 0x52, 0x21}; + /*ID for CY8CTST200*/ +#endif +#ifdef CY8CTMG200_24PIN + unsigned char target_id_v[] = {0x07, 0x6D, 0x52, 0x21}; + /*ID for CY8CTMG200*/ +#endif +#ifdef CY8CTMG200_32PIN + unsigned char target_id_v[] = {0x07, 0x6E, 0x52, 0x21}; + /*ID for CY8CTMG200*/ +#endif + +/* ****************************************************************************/ + + +/* ------------------------- PSoC CY8C21x23 Devices --------------------------- + Modifying these tables is NOT recommendended. Doing so will all but + guarantee an ISSP error, unless updated vectors have been recommended or + provided by Cypress Semiconductor. + --------------------------------------------------------------------------*/ +#ifdef CY8C21123 + unsigned char target_id_v[] = {0x00, 0x17};/*ID for CY8C21123*/ +#endif +#ifdef CY8C21223 + unsigned char target_id_v[] = {0x00, 0x18};/*ID for CY8C21223*/ +#endif +#ifdef CY8C21323 + unsigned char target_id_v[] = {0x00, 0x19};/*ID for CY8C2132*/ +#endif +#ifdef CY8C21002 + unsigned char target_id_v[] = {0x00, 0x3F};/*ID for CY8C21x23 ICE pod*/ +#endif + +/* ------------------------- PSoC CY8C21x34 Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CY8C21234 + unsigned char target_id_v[] = {0x00, 0x36};/*ID for CY8C21234*/ +#endif +#ifdef CY8C21334 + unsigned char target_id_v[] = {0x00, 0x37};/*ID for CY8C21334*/ +#endif +#ifdef CY8C21434 + unsigned char target_id_v[] = {0x00, 0x38};/*ID for CY8C21434*/ +#endif +#ifdef CY8C21534 + unsigned char target_id_v[] = {0x00, 0x40};/*ID for CY8C21534*/ +#endif +#ifdef CY8C21634 + unsigned char target_id_v[] = {0x00, 0x49};/*ID for CY8C21634*/ +#endif +#ifdef CY8C21001 + unsigned char target_id_v[] = {0x00, 0x39};/*ID for CY8C21x34 ICE pod*/ +#endif + + +/* ------------------------- PSoC CY8C24x23A Devices -------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CY8C24123A + unsigned char target_id_v[] = {0x00, 0x32};/*ID for CY8C24123A*/ +#endif +#ifdef CY8C24223A + unsigned char target_id_v[] = {0x00, 0x33};/*ID for CY8C24223A*/ +#endif +#ifdef CY8C24423A + unsigned char target_id_v[] = {0x00, 0x34};/*ID for CY8C24423A*/ +#endif +#ifdef CY8C24000A + unsigned char target_id_v[] = {0x00, 0x35};/*ID for CY8C24x23A ICE pod*/ +#endif + + +/* ------------------------- PSoC CY8C24x94 Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CY8C24794 + unsigned char target_id_v[] = {0x00, 0x1D};/*ID for CY8C24794*/ +#endif +#ifdef CY8C24894 + unsigned char target_id_v[] = {0x00, 0x1F};/*ID for CY8C24894*/ +#endif +#ifdef CY8C24994 + unsigned char target_id_v[] = {0x00, 0x59};/*ID for CY8C24994*/ +#endif +#ifdef CY8C24094 + unsigned char target_id_v[] = {0x00, 0x1B};/*ID for CY8C24094*/ +#endif + + +/* ------------------------- PSoC CY8C27x43 Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CY8C27143 + unsigned char target_id_v[] = {0x00, 0x09};/*ID for CY8C27143*/ +#endif +#ifdef CY8C27243 + unsigned char target_id_v[] = {0x00, 0x0A};/*ID for CY8C27243*/ +#endif +#ifdef CY8C27443 + unsigned char target_id_v[] = {0x00, 0x0B};/*ID for CY8C27443*/ +#endif +#ifdef CY8C27543 + unsigned char target_id_v[] = {0x00, 0x0C};/*ID for CY8C27543*/ +#endif +#ifdef CY8C27643 + unsigned char target_id_v[] = {0x00, 0x0D};/*ID for CY8C27643*/ +#endif +#ifdef CY8C27002 + unsigned char target_id_v[] = {0x00, 0x0E};/*ID for CY8C27x43 ICE pod*/ +#endif + + +/* ------------------------- PSoC CY8C29x66 Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CY8C29466 + unsigned char target_id_v[] = {0x00, 0x2A};/*ID for CY8C29466*/ +#endif +#ifdef CY8C29566 + unsigned char target_id_v[] = {0x00, 0x2B};/*ID for CY8C29566*/ +#endif +#ifdef CY8C29666 + unsigned char target_id_v[] = {0x00, 0x2C};/*ID for CY8C29666*/ +#endif +#ifdef CY8C29866 + unsigned char target_id_v[] = {0x00, 0x2D};/*ID for CY8C29866*/ +#endif +#ifdef CY8C29002 + unsigned char target_id_v[] = {0x00, 0x2E};/*ID for CY8C29002*/ +#endif + +/* --------- CY8C20x66 Vectors ------------------------------------------------ +// --------------------------------------------------------------------------*/ +#ifdef TSYNC + const unsigned int num_bits_tsync_enable = 110; + const unsigned char tsync_enable[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE2, 0x1F, 0x7F, 0x02, 0x7D, 0xC4, 0x09, + 0xF7, 0x00, 0x1F, 0xDE, 0xE0, 0x1C +#else + 0b11011110, 0b11100010, 0b00011111, 0b01111111, 0b00000010, 0b01111101, + 0b11000100, 0b00001001, 0b11110111, 0b00000000, 0b00011111, 0b11011110, + 0b11100000, 0b00011100 +#endif + }; + const unsigned int num_bits_tsync_disable = 110; + const unsigned char tsync_disable[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE2, 0x1F, 0x71, 0x00, 0x7D, 0xFC, 0x01, + 0xF7, 0x00, 0x1F, 0xDE, 0xE0, 0x1C +#else + 0b11011110, 0b11100010, 0b00011111, 0b01110001, 0b00000000, 0b01111101, + 0b11111100, 0b00000001, 0b11110111, 0b00000000, 0b00011111, 0b11011110, + 0b11100000, 0b00011100 +#endif + }; +#endif + +#ifdef CY8CTMx30x + #ifdef ID_SETUP_1 + const unsigned int num_bits_id_setup_1 = 616; + /*KIMC, 2009.08.11, PTJ: id_setup_1 with TSYNC enabled for + MW and disabled for IOW*/ + const unsigned char id_setup_1[] = { + 0b11001010, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00001101, 0b11101110, + 0b00100001, 0b11110111, 0b11110000, 0b00100111, 0b11011100, 0b01000000, + 0b10011111, 0b01110000, 0b00000001, 0b11111101, 0b11101110, 0b00000001, + 0b11100111, 0b11000001, 0b11010111, 0b10011111, 0b00100000, 0b01111110, + 0b00111111, 0b10011101, 0b01111000, 0b11110110, 0b00100001, 0b11110111, + 0b10111000, 0b10000111, 0b11011111, 0b11000000, 0b00011111, 0b01110001, + 0b00000000, 0b01111101, 0b11000000, 0b00000111, 0b11110111, 0b10111000, + 0b00000111, 0b11011110, 0b10000000, 0b01111111, 0b01111010, 0b10000000, + 0b01111101, 0b11101100, 0b00000001, 0b11110111, 0b10000000, 0b01001111, + 0b11011111, 0b00000000, 0b00011111, 0b01111100, 0b10100000, 0b01111101, + 0b11110100, 0b01100001, 0b11110111, 0b11111000, 0b10010111 + }; + #endif +#else + #ifdef ID_SETUP_1 + const unsigned int num_bits_id_setup_1 = 594; + /*PTJ: id_setup_1 with TSYNC enabled for MW and disabled for IOW*/ + const unsigned char id_setup_1[] = { +#ifdef HEX_DEFINE + 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0D, 0xEE, 0x21, 0xF7, 0xF0, 0x27, 0xDC, 0x40, + 0x9F, 0x70, 0x01, 0xFD, 0xEE, 0x01, /*0x21, */0xE7, 0xC1, + 0xD7, 0x9F, 0x20, 0x7E, 0x7D, 0x88, 0x7D, 0xEE, + 0x21, 0xF7, 0xF0, 0x07, 0xDC, 0x40, 0x1F, 0x70, + 0x01, 0xFD, 0xEE, 0x01, 0xF7, 0xA0, 0x1F, 0xDE, + 0xA0, 0x1F, 0x7B, 0x00, 0x7D, 0xE0, 0x13, 0xF7, + 0xC0, 0x07, 0xDF, 0x28, 0x1F, 0x7D, 0x18, 0x7D, + 0xFE, 0x25, 0xC0 +#else + 0b11001010, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00001101, 0b11101110, + 0b00100001, 0b11110111, 0b11110000, 0b00100111, 0b11011100, 0b01000000, + 0b10011111, 0b01110000, 0b00000001, 0b11111101, 0b11101110, 0b00100001, + 0b11100111, 0b11000001, 0b11010111, 0b10011111, 0b00100000, 0b01111110, + 0b01111101, 0b10001000, 0b01111101, 0b11101110, 0b00100001, 0b11110111, + 0b11110000, 0b00000111, 0b11011100, 0b01000000, 0b00011111, 0b01110000, + 0b00000001, 0b11111101, 0b11101110, 0b00000001, 0b11110111, 0b10100000, + 0b00011111, 0b11011110, 0b10100000, 0b00011111, 0b01111011, 0b00000000, + 0b01111101, 0b11100000, 0b00010011, 0b11110111, 0b11000000, 0b00000111, + 0b11011111, 0b00101000, 0b00011111, 0b01111101, 0b00011000, 0b01111101, + 0b11111110, 0b00100101, 0b11000000 +#endif + }; + #endif +#endif + + +#ifdef SET_BLOCK_NUM + const unsigned int num_bits_set_block_num = 11;/*PTJ:*/ + const unsigned char set_block_num[] = { +#ifdef HEX_DEFINE + 0x9f, 0x40, 0x1c +#else + 0b11011110, 0b11100000, 0b00011110, 0b01111101, 0b00000000, 0b01110000 +#endif + }; + const unsigned int num_bits_set_block_num_end = 3; + /*PTJ: this selects the first three bits of set_block_num_end*/ + const unsigned char set_block_num_end = 0xE0; +#endif + +#ifdef READ_WRITE_SETUP + const unsigned int num_bits_read_write_setup = 66;/*PTJ:*/ + const unsigned char read_write_setup[] = { +#ifdef HEX_DEFINE + 0xde, 0xf0, 0x1f, 0x78, 0x00, 0x7d, 0xa0, 0x03, + 0xc0 +#else + 0b11011110, 0b11110000, 0b00011111, 0b01111000, 0b00000000, 0b01111101, + 0b10100000, 0b00000011, 0b11000000 +#endif + }; +#endif + +#ifdef VERIFY_SETUP + const unsigned int num_bits_my_verify_setup = 440; + const unsigned char verify_setup[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0xfc, 0x81, + 0xf9, 0xf7, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf6, 0xa8, + 0x0f, 0xde, 0x80, 0x7f, 0x7a, 0x80, 0x7d, 0xec, + 0x01, 0xf7, 0x80, 0x0f, 0xdf, 0x00, 0x1f, 0x7c, + 0xa0, 0xfd, 0xf4, 0x61, 0xf7, 0xf8, 0x97 +#else + 0b11011110, 0b11100010, 0b00011111, 0b01111111, 0b00000010, 0b01111101, + 0b11000100, 0b00001001, 0b11110111, 0b00000000, 0b00011111, 0b10011111, + 0b00000111, 0b01011110, 0b01111100, 0b10000001, 0b11111001, 0b11110111, + 0b00000001, 0b11110111, 0b11110000, 0b00000111, 0b11011100, 0b01000000, + 0b00011111, 0b01110000, 0b00000001, 0b11111101, 0b11101110, 0b00000001, + 0b11110110, 0b10101000, 0b00001111, 0b11011110, 0b10000000, 0b01111111, + 0b01111010, 0b10000000, 0b01111101, 0b11101100, 0b00000001, 0b11110111, + 0b10000000, 0b00001111, 0b11011111, 0b00000000, 0b00011111, 0b01111100, + 0b10100000, 0b01111101, 0b11110100, 0b01100001, 0b11110111, 0b11111000, + 0b10010111 +#endif + }; +#endif + +#ifdef ERASE + const unsigned int num_bits_erase = 396; + /*PTJ: erase with TSYNC Enable and Disable*/ + const unsigned char erase[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x85, + 0xfd, 0xfc, 0x01, 0xf7, 0x10, 0x07, 0xdc, 0x00, + 0x7f, 0x7b, 0x80, 0x7d, 0xe0, 0x0b, 0xf7, 0xa0, + 0x1f, 0xd7, 0xa0, 0x1f, 0x7b, 0x04, 0x7d, 0xf0, + 0x01, 0xf7, 0xc9, 0x87, 0xdf, 0x48, 0x1f, 0x7f, + 0x89, 0x70 +#else + 0b11011110, 0b11100010, 0b00011111, 0b01111111, 0b00000010, 0b01111101, + 0b11000100, 0b00001001, 0b11110111, 0b00000000, 0b00011111, 0b10011111, + 0b00000111, 0b01011110, 0b01111100, 0b10000101, 0b11111101, 0b11111100, + 0b00000001, 0b11110111, 0b00010000, 0b00000111, 0b11011100, 0b00000000, + 0b01111111, 0b01111011, 0b10000000, 0b01111101, 0b11100000, 0b00001011, + 0b11110111, 0b10100000, 0b00011111, 0b11011110, 0b10100000, 0b00011111, + 0b01111011, 0b00000100, 0b01111101, 0b11110000, 0b00000001, 0b11110111, + 0b11001001, 0b10000111, 0b11011111, 0b01001000, 0b00011111, 0b01111111, + 0b10001001, 0b01110000 +#endif + }; +#endif + +#ifdef SECURE + const unsigned int num_bits_secure = 440; + /*PTJ: secure with TSYNC Enable and Disable*/ + const unsigned char secure[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x81, + 0xf9, 0xf7, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf6, 0xa0, + 0x0f, 0xde, 0x80, 0x7f, 0x7a, 0x80, 0x7d, 0xec, + 0x01, 0xf7, 0x80, 0x27, 0xdf, 0x00, 0x1f, 0x7c, + 0xa0, 0x7d, 0xf4, 0x61, 0xf7, 0xf8, 0x97 +#else + 0b11011110, 0b11100010, 0b00011111, 0b01111111, 0b00000010, 0b01111101, + 0b11000100, 0b00001001, 0b11110111, 0b00000000, 0b00011111, 0b10011111, + 0b00000111, 0b01011110, 0b01111100, 0b10000001, 0b11111001, 0b11110111, + 0b00000001, 0b11110111, 0b11110000, 0b00000111, 0b11011100, 0b01000000, + 0b00011111, 0b01110000, 0b00000001, 0b11111101, 0b11101110, 0b00000001, + 0b11110110, 0b10100000, 0b00001111, 0b11011110, 0b10000000, 0b01111111, + 0b01111010, 0b10000000, 0b01111101, 0b11101100, 0b00000001, 0b11110111, + 0b10000000, 0b00100111, 0b11011111, 0b00000000, 0b00011111, 0b01111100, + 0b10100000, 0b01111101, 0b11110100, 0b01100001, 0b11110111, 0b11111000, + 0b10010111 +#endif + }; +#endif + +#ifdef READ_SECURITY + const unsigned int num_bits_ReadSecuritySetup = 88; + /*PTJ: READ-SECURITY-SETUP*/ + const unsigned char ReadSecuritySetup[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x60, 0x88, 0x7d, 0x84, 0x21, + 0xf7, 0xb8, 0x07 +#else + 0b11011110, 0b11100010, 0b00011111, 0b01100000, 0b10001000, 0b01111101, + 0b10000100, 0b00100001, 0b11110111, 0b10111000, 0b00000111 +#endif + }; + const unsigned int num_bits_read_security_pt1 = 78; + /*PTJ: This sends the beginning of the Read Supervisory command*/ + const unsigned char read_security_pt1[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x72, 0x87, 0x7d, 0xca, 0x01, + 0xf7, 0x28 +#else + 0b11011110, 0b11100010, 0b00011111, 0b01110010, 0b10000111, 0b01111101, + 0b11001010, 0b00000001, 0b11110111, 0b00101000 +#endif + }; + + const unsigned int num_bits_read_security_pt1_end = 25; + /*PTJ: this finishes the Address Low command and sends + the Address High command*/ + const unsigned char read_security_pt1_end[] = { +#ifdef HEX_DEFINE + 0xfb, 0x94, 0x03, 0x80 +#else + 0b11111011, 0b10010100, 0b00000011, 0b10000000 +#endif + }; + + const unsigned int num_bits_read_security_pt2 = 198; + /*PTJ: load the test queue with the op code + for MOV 1,E5h register into Accumulator A*/ + const unsigned char read_security_pt2[] = { +#ifdef HEX_DEFINE + 0xde, 0xe0, 0x1f, 0x7a, 0x01, 0xfd, 0xea, 0x01, + 0xf7, 0xb0, 0x07, 0xdf, 0x0b, 0xbf, 0x7c, 0xf2, + 0xfd, 0xf4, 0x61, 0xf7, 0xb8, 0x87, 0xdf, 0xe2, + 0x5c +#else + 0b11011110, 0b11100000, 0b00011111, 0b01111010, 0b00000001, 0b11111101, + 0b11101010, 0b00000001, 0b11110111, 0b10110000, 0b00000111, 0b11011111, + 0b00001011, 0b10111111, 0b01111100, 0b11110010, 0b11111101, 0b11110100, + 0b01100001, 0b11110111, 0b10111000, 0b10000111, 0b11011111, 0b11100010, + 0b01011100 +#endif + }; + + const unsigned int num_bits_read_security_pt3 = 122;/*PTJ:*/ + const unsigned char read_security_pt3[] = { +#ifdef HEX_DEFINE + 0xde, 0xe0, 0x1f, 0x7a, 0x01, 0xfd, 0xea, 0x01, + 0xf7, 0xb0, 0x07, 0xdf, 0x0a, 0x7f, 0x7c, 0xc0 +#else + 0b11011110, 0b11100000, 0b00011111, 0b01111010, 0b00000001, 0b11111101, + 0b11101010, 0b00000001, 0b11110111, 0b10110000, 0b00000111, 0b11011111, + 0b00001010, 0b01111111, 0b01111100, 0b11000000 +#endif + }; + + const unsigned int num_bits_read_security_pt3_end = 47;/*PTJ:*/ + const unsigned char read_security_pt3_end[] = { +#ifdef HEX_DEFINE + 0xfb, 0xe8, 0xc3, 0xef, 0xf1, 0x2e +#else + 0b11111011, 0b11101000, 0b11000011, 0b11101111, 0b11110001, 0b00101110 +#endif + }; +#endif + + +/* --------- CY8C20x66 Checksum Setup Vector ---------------------------------- +// --------------------------------------------------------------------------*/ +#ifdef CHECKSUM_SETUP + const unsigned int num_bits_checksum = 418; + /*PTJ: Checksum with TSYNC Enable and Disable*/ + const unsigned char checksum_v[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x81, + 0xf9, 0xf4, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf7, 0xa0, + 0x1f, 0xde, 0xa0, 0x1f, 0x7b, 0x00, 0x7d, 0xe0, + 0x0f, 0xf7, 0xc0, 0x07, 0xdf, 0x28, 0x1f, 0x7d, + 0x18, 0x7d, 0xfe, 0x25, 0xc0 +#else + 0b11011110, 0b11100010, 0b00011111, 0b01111111, 0b00000010, 0b01111101, + 0b11000100, 0b00001001, 0b11110111, 0b00000000, 0b00011111, 0b10011111, + 0b00000111, 0b01011110, 0b01111100, 0b10000001, 0b11111001, 0b11110100, + 0b00000001, 0b11110111, 0b11110000, 0b00000111, 0b11011100, 0b01000000, + 0b00011111, 0b01110000, 0b00000001, 0b11111101, 0b11101110, 0b00000001, + 0b11110111, 0b10100000, 0b00011111, 0b11011110, 0b10100000, 0b00011111, + 0b01111011, 0b00000000, 0b01111101, 0b11100000, 0b00001111, 0b11110111, + 0b11000000, 0b00000111, 0b11011111, 0b00101000, 0b00011111, 0b01111101, + 0b00011000, 0b01111101, 0b11111110, 0b00100101, 0b11000000 +#endif + }; +#endif + + +/* --------- CY8C21x23, CY8C21x34 & CY8C27x43 Checksum Setup Vectors ---------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CHECKSUM_SETUP_21_27 + const unsigned int num_bits_checksum = 286; + const unsigned char checksum_v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF7, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1E, 0x7D, 0x00, 0x7D, 0xE0, 0x0F, 0xF7, 0xC0, + 0x07, 0xDF, 0xE2, 0x5C +#else + 0b11011110, 0b11100000, 0b00011111, 0b01111011, 0b00000000, 0b01111001, + 0b11110000, 0b01110101, 0b11100111, 0b11001000, 0b00011111, 0b11011110, + 0b10100000, 0b00011111, 0b01111010, 0b00000001, 0b11111001, 0b11110111, + 0b00000001, 0b11110111, 0b11001001, 0b10000111, 0b11011111, 0b01001000, + 0b00011110, 0b01111101, 0b00000000, 0b01111101, 0b11100000, 0b00001111, + 0b11110111, 0b11000000, 0b00000111, 0b11011111, 0b11100010, 0b01011100 +#endif + }; +#endif + + +/* -------------- CY8C24x23 & CY8C24x23A Checksum Setup Vectors --------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CHECKSUM_SETUP_24_24A + const unsigned int num_bits_checksum = 286; + const unsigned char checksum_v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF7, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1E, 0x7D, 0x20, 0x7D, 0xE0, 0x0F, 0xF7, 0xC0, + 0x07, 0xDF, 0xE2, 0x5C +#else + 0b11011110, 0b11100000, 0b00011111, 0b01111011, 0b00000000, 0b01111001, + 0b11110000, 0b01110101, 0b11100111, 0b11001000, 0b00011111, 0b11011110, + 0b10100000, 0b00011111, 0b01111010, 0b00000001, 0b11111001, 0b11110111, + 0b00000001, 0b11110111, 0b11001001, 0b10000111, 0b11011111, 0b01001000, + 0b00011110, 0b01111101, 0b00100000, 0b01111101, 0b11100000, 0b00001111, + 0b11110111, 0b11000000, 0b00000111, 0b11011111, 0b11100010, 0b01011100 +#endif + }; +#endif + + +/* -------------- CY8C24x94 & CY8C29x66 Checksum Setup Vectors ---------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// --------------------------------------------------------------------------*/ +#ifdef CHECKSUM_SETUP_24_29 + const unsigned int num_bits_checksum = 286; + const unsigned char checksum_v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF6, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1E, 0x7D, 0x40, 0x7D, 0xE0, 0x0F, 0xF7, 0xC0, + 0x07, 0xDF, 0xE2, 0x5C +#else + 0b11011110, 0b11100000, 0b00011111, 0b01111011, 0b00000000, 0b01111001, + 0b11110000, 0b01110101, 0b11100111, 0b11001000, 0b00011111, 0b11011110, + 0b10100000, 0b00011111, 0b01111010, 0b00000001, 0b11111001, 0b11110110, + 0b00000001, 0b11110111, 0b11001001, 0b10000111, 0b11011111, 0b01001000, + 0b00011110, 0b01111101, 0b00100000, 0b01111101, 0b11100000, 0b00001111, + 0b11110111, 0b11000000, 0b00000111, 0b11011111, 0b11100010, 0b01011100 +#endif + }; +#endif + +/* ---- CY8C20x66 Program Block Vector ---------------------------------------- +// +// --------------------------------------------------------------------------*/ +#ifdef PROGRAM_AND_VERIFY + const unsigned int num_bits_program_and_verify = 440; + /*KIMC, PTJ: length of program_block[], not including + zero padding at end*/ + const unsigned char program_and_verify[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x81, + 0xf9, 0xf7, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf6, 0xa0, + 0x0f, 0xde, 0x80, 0x7f, 0x7a, 0x80, 0x7d, 0xec, + 0x01, 0xf7, 0x80, 0x57, 0xdf, 0x00, 0x1f, 0x7c, + 0xa0, 0x7d, 0xf4, 0x61, 0xf7, 0xf8, 0x97 + #else + 0b00011011110, 0b11100010, 0b00011111, 0b01111111, 0b00000010, + 0b01111101, 0b11000100, 0b00001001, 0b00011110111, 0b00000000, + 0b00011111, 0b10011111, 0b00000111, 0b01011110, 0b01111100, 0b10000001, + 0b00011111001, 0b11110111, 0b00000001, 0b11110111, 0b11110000, + 0b00000111, 0b11011100, 0b01000000, 0b00000011111, 0b01110000, + 0b00000001, 0b11111101, 0b11101110, 0b00000001, 0b11110110, 0b10100000, + 0b00000001111, 0b11011110, 0b10000000, 0b01111111, 0b01111010, + 0b10000000, 0b01111101, 0b11101100, 0b00000000001, 0b11110111, + 0b10000000, 0b01010111, 0b11011111, 0b00000000, 0b00011111, 0b01111100, + 0b00010100000, 0b01111101, 0b11110100, 0b01100001, 0b11110111, + 0b11111000, 0b10010111 + #endif + }; +#endif + +/* ---- CY8C21xxx, CY8C24x23A, CY8C24x94 & CY8C29x66 Program Block Vectors ---- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------*/ +#ifdef PROGRAM_BLOCK_21_24_29 + const unsigned int num_bits_program_block = 308; + const unsigned char program_block[] = { +#ifdef HEX_DEFINE + 0x9F, 0x8A, 0x9E, 0x7F, 0x2B, 0x7D, 0xEE, 0x01, + 0xF7, 0xB0, 0x07, 0x9F, 0x07, 0x5E, 0x7C, 0x81, + 0xFD, 0xEA, 0x01, 0xF7, 0xA0, 0x1F, 0x9F, 0x70, + 0x1F, 0x7C, 0x98, 0x7D, 0xF4, 0x81, 0xF7, 0x80, + 0x17, 0xDF, 0x00, 0x1F, 0x7F, 0x89, 0x70 +#else + 0b10011111, 0b10001010, 0b10011110, 0b01111111, 0b00101011, 0b01111101, + 0b11101110, 0b00000001, 0b11110111, 0b10110000, 0b00000111, 0b10011111, + 0b00000111, 0b01011110, 0b01111100, 0b10000001, 0b11111101, 0b11101010, + 0b00000001, 0b11110111, 0b10100000, 0b00011111, 0b10011111, 0b01110000, + 0b00011111, 0b01111100, 0b10011000, 0b01111101, 0b11110100, 0b10000001, + 0b11110111, 0b10000000, 0b00010111, 0b11011111, 0b00000000, 0b00011111, + 0b01111111, 0b10001001, 0b01110000 +#endif + }; +#endif + +/* --------------------- CY8C27x43 Program Block Vectors----------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------*/ +#ifdef PROGRAM_BLOCK_27 + const unsigned int num_bits_program_block = 308; + const unsigned char program_block[] = { +#ifdef HEX_DEFINE + 0x9F, 0x82, 0xBE, 0x7F, 0x2B, 0x7D, 0xEE, 0x01, + 0xF7, 0xB0, 0x07, 0x9F, 0x07, 0x5E, 0x7C, 0x81, + 0xFD, 0xEA, 0x01, 0xF7, 0xA0, 0x1F, 0x9F, 0x70, + 0x1F, 0x7C, 0x98, 0x7D, 0xF4, 0x81, 0xF7, 0x80, + 0x17, 0xDF, 0x00, 0x1F, 0x7F, 0x89, 0x70 +#else + 0b10011111, 0b10000010, 0b10111110, 0b01111111, 0b00101011, 0b01111101, + 0b11101110, 0b00000001, 0b11110111, 0b10110000, 0b00000111, 0b10011111, + 0b00000111, 0b01011110, 0b01111100, 0b10000001, 0b11111101, 0b11101010, + 0b00000001, 0b11110111, 0b10100000, 0b00011111, 0b10011111, 0b01110000, + 0b00011111, 0b01111100, 0b10011000, 0b01111101, 0b11110100, 0b10000001, + 0b11110111, 0b10000000, 0b00010111, 0b11011111, 0b00000000, 0b00011111, + 0b01111111, 0b10001001, 0b01110000 +#endif + }; +#endif + +/* ----------------------------- General PSoC Vectors-------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------*/ + const unsigned int num_bits_init1 = 396; + const unsigned char init1_v[] = { +#ifdef HEX_DEFINE + 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0D, 0xEE, 0x01, 0xF7, 0xB0, 0x07, 0x9F, 0x07, + 0x5E, 0x7C, 0x81, 0xFD, 0xEA, 0x01, 0xF7, 0xA0, + 0x1F, 0x9F, 0x70, 0x1F, 0x7C, 0x98, 0x7D, 0xF4, + 0x81, 0xF7, 0x80, 0x4F, 0xDF, 0x00, 0x1F, 0x7F, + 0x89, 0x70 +#else + 0b11001010, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00001101, 0b11101110, + 0b00000001, 0b11110111, 0b10110000, 0b00000111, 0b10011111, 0b00000111, + 0b01011110, 0b01111100, 0b10000001, 0b11111101, 0b11101010, 0b00000001, + 0b11110111, 0b10100000, 0b00011111, 0b10011111, 0b01110000, 0b00011111, + 0b01111100, 0b10011000, 0b01111101, 0b11110100, 0b10000001, 0b11110111, + 0b10000000, 0b01001111, 0b11011111, 0b00000000, 0b00011111, 0b01111111, + 0b10001001, 0b01110000 +#endif + }; + + const unsigned int num_bits_init2 = 286; + const unsigned char init2_v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF7, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1E, 0x7D, 0x00, 0xFD, 0xE0, 0x0D, 0xF7, 0xC0, + 0x07, 0xDF, 0xE2, 0x5C +#else + 0b11011110, 0b11100000, 0b00011111, 0b01111011, 0b00000000, 0b01111001, + 0b11110000, 0b01110101, 0b11100111, 0b11001000, 0b00011111, 0b11011110, + 0b10100000, 0b00011111, 0b01111010, 0b00000001, 0b11111001, 0b11110111, + 0b00000001, 0b11110111, 0b11001001, 0b10000111, 0b11011111, 0b01001000, + 0b00011110, 0b01111101, 0b00000000, 0b11111101, 0b11100000, 0b00001101, + 0b11110111, 0b11000000, 0b00000111, 0b11011111, 0b11100010, 0b01011100 +#endif + }; + + const unsigned int num_bits_init3_5v = 836; + const unsigned char init3_5v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7A, 0x01, 0xFD, 0xEA, 0x01, + 0xF7, 0xB0, 0x47, 0xDF, 0x0A, 0x3F, 0x7C, 0xFE, + 0x7D, 0xF4, 0x61, 0xF7, 0xF8, 0x97, 0x00, 0x00, + 0x03, 0x7B, 0x80, 0x7D, 0xE8, 0x07, 0xF7, 0xA8, + 0x07, 0xDE, 0xC1, 0x1F, 0x7C, 0x30, 0x7D, 0xF3, + 0xD5, 0xF7, 0xD1, 0x87, 0xDE, 0xE2, 0x1F, 0x7F, + 0x89, 0x70, 0x00, 0x00, 0x37, 0xB8, 0x07, 0xDE, + 0x80, 0x7F, 0x7A, 0x80, 0x7D, 0xEC, 0x11, 0xF7, + 0xC2, 0x8F, 0xDF, 0x3F, 0xBF, 0x7D, 0x18, 0x7D, + 0xFE, 0x25, 0xC0, 0x00, 0x00, 0xDE, 0xE0, 0x1F, + 0x7A, 0x01, 0xFD, 0xEA, 0x01, 0xF7, 0xB0, 0x47, + 0xDF, 0x0C, 0x1F, 0x7C, 0xF4, 0x7D, 0xF4, 0x61, + 0xF7, 0xB8, 0x87, 0xDF, 0xE2, 0x5C, 0x00, 0x00, + 0x00 +#else + 0b11011110, 0b11100000, 0b00011111, 0b01111010, 0b00000001, 0b11111101, + 0b11101010, 0b00000001, 0b11110111, 0b10110000, 0b01000111, 0b11011111, + 0b00001010, 0b00111111, 0b01111100, 0b11111110, 0b01111101, 0b11110100, + 0b01100001, 0b11110111, 0b11111000, 0b10010111, 0b00000000, 0b00000000, + 0b00000011, 0b01111011, 0b10000000, 0b01111101, 0b11101000, 0b00000111, + 0b11110111, 0b10101000, 0b00000111, 0b11011110, 0b11000001, 0b00011111, + 0b01111100, 0b00110000, 0b01111101, 0b11110011, 0b11010101, 0b11110111, + 0b11010001, 0b10000111, 0b11011110, 0b11100010, 0b00011111, 0b01111111, + 0b10001001, 0b01110000, 0b00000000, 0b00000000, 0b00110111, 0b10111000, + 0b00000111, 0b11011110, 0b10000000, 0b01111111, 0b01111010, 0b10000000, + 0b01111101, 0b11101100, 0b00010001, 0b11110111, 0b11000010, 0b10001111, + 0b11011111, 0b00111111, 0b10111111, 0b01111101, 0b00011000, 0b01111101, + 0b11111110, 0b00100101, 0b11000000, 0b00000000, 0b00000000, 0b11011110, + 0b11100000, 0b00011111, 0b01111010, 0b00000001, 0b11111101, 0b11101010, + 0b00000001, 0b11110111, 0b10110000, 0b01000111, 0b11011111, 0b00001100, + 0b00011111, 0b01111100, 0b11110100, 0b01111101, 0b11110100, 0b01100001, + 0b11110111, 0b10111000, 0b10000111, 0b11011111, 0b11100010, 0b01011100, + 0b00000000, 0b00000000, 0b00000000 +#endif + }; + + const unsigned int num_bits_init3_3v = 836; + const unsigned char init3_3v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7A, 0x01, 0xFD, 0xEA, 0x01, + 0xF7, 0xB0, 0x47, 0xDF, 0x0A, 0x3F, 0x7C, 0xFC, + 0x7D, 0xF4, 0x61, 0xF7, 0xF8, 0x97, 0x00, 0x00, + 0x03, 0x7B, 0x80, 0x7D, 0xE8, 0x07, 0xF7, 0xA8, + 0x07, 0xDE, 0xC1, 0x1F, 0x7C, 0x30, 0x7D, 0xF3, + 0xD5, 0xF7, 0xD1, 0x87, 0xDE, 0xE2, 0x1F, 0x7F, + 0x89, 0x70, 0x00, 0x00, 0x37, 0xB8, 0x07, 0xDE, + 0x80, 0x7F, 0x7A, 0x80, 0x7D, 0xEC, 0x11, 0xF7, + 0xC2, 0x8F, 0xDF, 0x3F, 0x3F, 0x7D, 0x18, 0x7D, + 0xFE, 0x25, 0xC0, 0x00, 0x00, 0xDE, 0xE0, 0x1F, + 0x7A, 0x01, 0xFD, 0xEA, 0x01, 0xF7, 0xB0, 0x47, + 0xDF, 0x0C, 0x1F, 0x7C, 0xF4, 0x7D, 0xF4, 0x61, + 0xF7, 0xB8, 0x87, 0xDF, 0xE2, 0x5C, 0x00, 0x00, + 0x00 +#else + 0b11011110, 0b11100000, 0b00011111, 0b01111010, 0b00000001, 0b11111101, + 0b11101010, 0b00000001, 0b11110111, 0b10110000, 0b01000111, 0b11011111, + 0b00001010, 0b00111111, 0b01111100, 0b11111100, 0b01111101, 0b11110100, + 0b01100001, 0b11110111, 0b11111000, 0b10010111, 0b00000000, 0b00000000, + 0b00000011, 0b01111011, 0b10000000, 0b01111101, 0b11101000, 0b00000111, + 0b11110111, 0b10101000, 0b00000111, 0b11011110, 0b11000001, 0b00011111, + 0b01111100, 0b00110000, 0b01111101, 0b11110011, 0b11010101, 0b11110111, + 0b11010001, 0b10000111, 0b11011110, 0b11100010, 0b00011111, 0b01111111, + 0b10001001, 0b01110000, 0b00000000, 0b00000000, 0b00110111, 0b10111000, + 0b00000111, 0b11011110, 0b10000000, 0b01111111, 0b01111010, 0b10000000, + 0b01111101, 0b11101100, 0b00010001, 0b11110111, 0b11000010, 0b10001111, + 0b11011111, 0b00111111, 0b00111111, 0b01111101, 0b00011000, 0b01111101, + 0b11111110, 0b00100101, 0b11000000, 0b00000000, 0b00000000, 0b11011110, + 0b11100000, 0b00011111, 0b01111010, 0b00000001, 0b11111101, 0b11101010, + 0b00000001, 0b11110111, 0b10110000, 0b01000111, 0b11011111, 0b00001100, + 0b00011111, 0b01111100, 0b11110100, 0b01111101, 0b11110100, 0b01100001, + 0b11110111, 0b10111000, 0b10000111, 0b11011111, 0b11100010, 0b01011100, + 0b00000000, 0b00000000, 0b00000000 +#endif + }; +#ifdef ID_SETUP_2 + const unsigned int num_bits_id_setup_2 = 418; + /*PTJ: id_setup_2 with TSYNC Disable (TSYNC enabled before with + SendVector(tsync_enable....)*/ + const unsigned char id_setup_2[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x81, + 0xf9, 0xf4, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf7, 0xa0, + 0x1f, 0xde, 0xa0, 0x1f, 0x7b, 0x00, 0x7d, 0xe0, + 0x0d, 0xf7, 0xc0, 0x07, 0xdf, 0x28, 0x1f, 0x7d, + 0x18, 0x7d, 0xfe, 0x25, 0xc0 +#else + 0b11011110, 0b11100010, 0b00011111, 0b01111111, 0b00000010, 0b01111101, + 0b11000100, 0b00001001, 0b11110111, 0b00000000, 0b00011111, 0b10011111, + 0b00000111, 0b01011110, 0b01111100, 0b10000001, 0b11111001, 0b11110100, + 0b00000001, 0b11110111, 0b11110000, 0b00000111, 0b11011100, 0b01000000, + 0b00011111, 0b01110000, 0b00000001, 0b11111101, 0b11101110, 0b00000001, + 0b11110111, 0b10100000, 0b00011111, 0b11011110, 0b10100000, 0b00011111, + 0b01111011, 0b00000000, 0b01111101, 0b11100000, 0b00001101, 0b11110111, + 0b11000000, 0b00000111, 0b11011111, 0b00101000, 0b00011111, 0b01111101, + 0b00011000, 0b01111101, 0b11111110, 0b00100101, 0b11000000 +#endif + }; +#endif + + const unsigned int num_bits_erase_all = 308; + const unsigned char erase_all_v[] = { +#ifdef HEX_DEFINE + 0x9F, 0x82, 0xBE, 0x7F, 0x2B, 0x7D, 0xEE, 0x01, + 0xF7, 0xB0, 0x07, 0x9F, 0x07, 0x5E, 0x7C, 0x81, + 0xFD, 0xEA, 0x01, 0xF7, 0xA0, 0x1F, 0x9F, 0x70, + 0x1F, 0x7C, 0x98, 0x7D, 0xF4, 0x81, 0xF7, 0x80, + 0x2F, 0xDF, 0x00, 0x1F, 0x7F, 0x89, 0x70 +#else + 0b10011111, 0b10000010, 0b10111110, 0b01111111, 0b00101011, 0b01111101, + 0b11101110, 0b00000001, 0b11110111, 0b10110000, 0b00000111, 0b10011111, + 0b00000111, 0b01011110, 0b01111100, 0b10000001, 0b11111101, 0b11101010, + 0b00000001, 0b11110111, 0b10100000, 0b00011111, 0b10011111, 0b01110000, + 0b00011111, 0b01111100, 0b10011000, 0b01111101, 0b11110100, 0b10000001, + 0b11110111, 0b10000000, 0b00101111, 0b11011111, 0b00000000, 0b00011111, + 0b01111111, 0b10001001, 0b01110000 +#endif + }; + + + const unsigned char read_id_v[] = { +#ifdef HEX_DEFINE + 0xBF, 0x00, 0xDF, 0x90, 0x00, 0xFE, 0x60, 0xFF, 0x00 +#else + 0b10111111, 0b00000000, 0b11011111, 0b10010000, 0b00000000, 0b11111110, + 0b0110000, 0b11111111, 0b00000000 +#endif + }; + + const unsigned char Switch_Bank1[] = { + /*PTJ: use this to switch between register banks*/ +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1c +#else + 0b11011110, 0b11100010, 0b00011100 +#endif + }; + + const unsigned char Switch_Bank0[] = { + /*PTJ: use this to switch between register banks*/ +#ifdef HEX_DEFINE + 0xde, 0xe0, 0x1c +#else + 0b11011110, 0b11100000, 0b00011100 +#endif + }; + + const unsigned char read_IMOtrim[] = { + /*PTJ: read the 1,E8h register after id__setup_1 to + see if the cal data was loaded properly.*/ +#ifdef HEX_DEFINE + 0xfd, 0x00, 0x10 +#else + 0b11111101, 0b00000000, 0b00010000 +#endif + }; + const unsigned char read_SPCtrim[] = { + /*PTJ: read the 1,E7h register after id__setup_1 to + see if the cal data was loaded properly.*/ +#ifdef HEX_DEFINE + 0xfc, 0xe0, 0x10 +#else + 0b11111100, 0b11100000, 0b00010000 +#endif + }; + const unsigned char read_VBGfinetrim[] = { + /*PTJ: read the 1,D7h register after id__setup_1 to + see if the cal data was loaded properly.*/ +#ifdef HEX_DEFINE + 0xfa, 0xe0, 0x08 +#else + 0b11111010, 0b11100000, 0b0001000 +#endif + }; + const unsigned char read_reg_end = 0x80; + /*PTJ: this is the final '1' after a MR command*/ + + const unsigned char write_byte_start = 0x90; + /*PTJ: this is set to SRAM 0x80*/ + const unsigned char write_byte_end = 0xE0; + + const unsigned char set_block_number[] = {0x9F, 0x40, 0xE0}; + const unsigned char set_block_number_end = 0xE0; +#ifdef MULTI_BANK + const unsigned char set_bank_number[] = { + 0xDE, 0xE2, 0x1F, 0x7D, 0x00}; + const unsigned char set_bank_number_end[] = { + 0xFB, 0xDC, 0x03, 0x80}; +#endif + + /*const unsigned char num_bits_wait_and_poll_end = 40; + //PTJ 308: commented out*/ + const unsigned char num_bits_wait_and_poll_end = 30; + /*PTJ 308: added to match spec*/ + const unsigned char wait_and_poll_end[] = { + 0x00, 0x00, 0x00, 0x00 /*PTJ 308: added to match spec*/ + };/* forty '0's per the spec*/ + + const unsigned char read_checksum_v[] = { + #ifdef HEX_DEFINE + 0xBF, 0x20, 0xDF, 0x80, 0x80 + #else + 0b10111111, 0b00100000, 0b11011111, 0b10000000, 0b10000000 + #endif + }; + + const unsigned char read_byte_v[] = { + #ifdef HEX_DEFINE + 0xB0, 0x80 + #else + 0b10110000, 0b10000000 + #endif + }; + const unsigned int num_bits_verify_setup = 264; + const unsigned char verify_setup_v[] = { + #ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF7, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1F, 0x78, 0x00, 0xFD, 0xF0, 0x01, 0xF7, 0xF8, + 0x97 + #else + 0b11011110, 0b11100000, 0b00011111, 0b01111011, 0b00000000, 0b01111001, + 0b11110000, 0b01110101, 0b11100111, 0b11001000, 0b00011111, 0b11011110, + 0b10100000, 0b00011111, 0b01111010, 0b00000001, 0b11111001, 0b11110111, + 0b00000001, 0b11110111, 0b11001001, 0b10000111, 0b11011111, 0b01001000, + 0b00011111, 0b01111000, 0b00000000, 0b11111101, 0b11110000, 0b00000001, + 0b11110111, 0b11111000, 0b10010111 + #endif + }; + const unsigned int num_bits_security = 308; + const unsigned char security_v[] = { + #ifdef HEX_DEFINE + 0x9F, 0x8A, 0x9E, 0x7F, 0x2B, 0x7D, 0xEE, 0x01, + 0xF7, 0xB0, 0x07, 0x9F, 0x07, 0x5E, 0x7C, 0x81, + 0xFD, 0xEA, 0x01, 0xF7, 0xA0, 0x1F, 0x9F, 0x70, + 0x1F, 0x7C, 0x98, 0x7D, 0xF4, 0x81, 0xF7, 0x80, + 0x27, 0xDF, 0x00, 0x1F, 0x7F, 0x89, 0x70 + #else + 0b10011111, 0b10001010, 0b10011110, 0b01111111, 0b00101011, 0b01111101, + 0b11101110, 0b00000001, 0b11110111, 0b10110000, 0b00000111, 0b10011111, + 0b00000111, 0b01011110, 0b01111100, 0b10000001, 0b11111101, 0b11101010, + 0b00000001, 0b11110111, 0b10100000, 0b00011111, 0b10011111, 0b01110000, + 0b00011111, 0b01111100, 0b10011000, 0b01111101, 0b11110100, 0b10000001, + 0b11110111, 0b10000000, 0b00100111, 0b11011111, 0b00000000, 0b00011111, + 0b01111111, 0b10001001, 0b01110000 + #endif + }; + +#endif /*(INC_ISSP_VECTORS)*/ +#endif /*(PROJECT_REV_)*/ +/*end of file ISSP_Vectors.h*/ diff --git a/drivers/input/keyboard/cypress_touchkey_236/jaguar_tkey_fw.h b/drivers/input/keyboard/cypress_touchkey_236/jaguar_tkey_fw.h new file mode 100644 index 00000000000..9a806b96b7e --- /dev/null +++ b/drivers/input/keyboard/cypress_touchkey_236/jaguar_tkey_fw.h @@ -0,0 +1,1045 @@ +/* +* Copyright 2006-2007, Cypress Semiconductor Corporation. + +* 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. +*/ +/* frimware 0x06 */ +unsigned char firmware_data[8192] = { +0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7d, 0x00, 0x68, 0x7e, +0x7e, 0x30, 0x30, 0x30, 0x7d, 0x04, 0x9e, 0x7e, +0x7e, 0x30, 0x30, 0x30, 0x7d, 0x05, 0xeb, 0x7e, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x40, 0x71, 0x10, 0x62, 0xe3, 0x06, 0x70, 0xef, +0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, +0x38, 0x5d, 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, +0xfa, 0x01, 0x40, 0x4f, 0x5b, 0x01, 0x03, 0x53, +0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, 0x40, +0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, +0xef, 0x18, 0x60, 0xd5, 0x55, 0xf8, 0x00, 0x55, +0xf9, 0x00, 0x71, 0x10, 0x62, 0xe0, 0x1a, 0x70, +0xef, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x41, 0xe1, +0xfe, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x62, 0xd1, +0x03, 0x50, 0x80, 0x4e, 0x62, 0xd3, 0x03, 0x62, +0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, 0x00, +0x71, 0xc0, 0x7c, 0x03, 0x0b, 0x62, 0xd0, 0x00, +0x50, 0x01, 0x57, 0xb2, 0x08, 0x28, 0x53, 0x49, +0x18, 0x75, 0x09, 0x00, 0x28, 0x4b, 0x51, 0x49, +0x80, 0x04, 0x75, 0x09, 0x00, 0x62, 0xe3, 0x00, +0x08, 0x28, 0x60, 0xd5, 0x74, 0xa0, 0x4b, 0x18, +0x75, 0x09, 0x00, 0x08, 0x28, 0x53, 0x49, 0x18, +0x75, 0x09, 0x00, 0x08, 0x28, 0xa0, 0x1c, 0x53, +0x48, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, +0x49, 0x47, 0x49, 0xff, 0xb0, 0x06, 0x5d, 0xd5, +0x74, 0x60, 0xd5, 0x18, 0x7a, 0x48, 0xbf, 0xeb, +0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, +0x53, 0x48, 0x50, 0x00, 0x3f, 0x49, 0x47, 0x49, +0xff, 0xb0, 0x08, 0x5d, 0xd5, 0x74, 0x60, 0xd5, +0x50, 0x00, 0x7a, 0x48, 0xbf, 0xef, 0x18, 0x8f, +0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, +0xef, 0x62, 0xe0, 0x00, 0x41, 0xfe, 0xe7, 0x43, +0xfe, 0x10, 0x71, 0x10, 0x62, 0xe0, 0x1a, 0x70, +0xef, 0x62, 0xe2, 0x00, 0x7c, 0x17, 0xf2, 0x8f, +0xff, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x01, 0x99, 0x03, 0x33, 0x06, 0x66, +0x0c, 0xcc, 0x19, 0x99, 0x33, 0x33, 0x66, 0x66, +0xcc, 0xcc, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, +0x0b, 0xff, 0x18, 0x00, 0x2f, 0xff, 0x5f, 0xff, +0xbf, 0xff, 0x01, 0x66, 0x02, 0xcc, 0x05, 0x99, +0x0b, 0x32, 0x16, 0x66, 0x2c, 0xcc, 0x59, 0x98, +0xb3, 0x32, 0x01, 0x33, 0x02, 0x66, 0x04, 0xcc, +0x09, 0x99, 0x13, 0x33, 0x26, 0x65, 0x4c, 0xcc, +0x99, 0x99, 0x1a, 0x86, 0x70, 0xef, 0x62, 0x61, +0x00, 0x62, 0xfd, 0x00, 0x62, 0xcd, 0x00, 0x62, +0xce, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, +0x62, 0xa0, 0x00, 0x62, 0xa1, 0x80, 0x62, 0xa2, +0xc0, 0x62, 0xa3, 0x0c, 0x62, 0xa8, 0x00, 0x62, +0xa6, 0x00, 0x62, 0xa7, 0x00, 0x62, 0x7c, 0x33, +0x62, 0x7a, 0x00, 0x62, 0x7b, 0x00, 0x62, 0x79, +0x00, 0x62, 0x36, 0x00, 0x62, 0x37, 0x00, 0x62, +0x38, 0x00, 0x62, 0x39, 0x00, 0x62, 0x3a, 0x00, +0x62, 0x3b, 0x00, 0x62, 0x3c, 0x00, 0x62, 0x3d, +0x00, 0x62, 0x3e, 0x00, 0x62, 0x3f, 0x00, 0x62, +0x40, 0x00, 0x62, 0x41, 0x00, 0x62, 0x42, 0x00, +0x62, 0x43, 0x00, 0x62, 0x44, 0x00, 0x62, 0x45, +0x00, 0x62, 0x46, 0x00, 0x62, 0x47, 0x00, 0x62, +0x48, 0x00, 0x62, 0x49, 0x00, 0x62, 0x4a, 0x00, +0x62, 0x4b, 0x00, 0x62, 0x4c, 0x00, 0x62, 0x4d, +0x00, 0x62, 0x4e, 0x00, 0x62, 0x4f, 0x00, 0x62, +0xca, 0x20, 0x62, 0xd6, 0x44, 0x62, 0xcf, 0x00, +0x62, 0xcb, 0x00, 0x62, 0xc8, 0x00, 0x62, 0xcc, +0x00, 0x62, 0xc9, 0x00, 0x62, 0xd7, 0x00, 0x62, +0xa9, 0x00, 0x62, 0x2b, 0x00, 0x62, 0xb0, 0x00, +0x62, 0xb3, 0x02, 0x62, 0xb6, 0x00, 0x62, 0xb2, +0x00, 0x62, 0xb5, 0x00, 0x62, 0xb8, 0x00, 0x62, +0xb1, 0x00, 0x62, 0xb4, 0x00, 0x62, 0xb7, 0x00, +0x62, 0x33, 0x00, 0x62, 0x34, 0x00, 0x62, 0x35, +0x00, 0x71, 0x10, 0x62, 0x54, 0x00, 0x62, 0x55, +0x00, 0x62, 0x56, 0x00, 0x62, 0x57, 0x00, 0x62, +0x58, 0x00, 0x62, 0x59, 0x00, 0x62, 0x5a, 0x00, +0x62, 0x5b, 0x00, 0x62, 0xdc, 0x00, 0x62, 0xe2, +0x00, 0x62, 0xdd, 0x00, 0x62, 0xd8, 0x02, 0x62, +0xd9, 0x00, 0x62, 0xda, 0x00, 0x62, 0xdb, 0x00, +0x62, 0xdf, 0x00, 0x62, 0x29, 0x00, 0x62, 0x30, +0x00, 0x62, 0xbd, 0x00, 0x70, 0xef, 0x70, 0xef, +0x62, 0x00, 0x08, 0x71, 0x10, 0x62, 0x00, 0x08, +0x62, 0x01, 0x92, 0x70, 0xef, 0x62, 0x04, 0x17, +0x71, 0x10, 0x62, 0x04, 0x14, 0x62, 0x05, 0xbc, +0x70, 0xef, 0x62, 0x08, 0x00, 0x71, 0x10, 0x62, +0x08, 0x00, 0x62, 0x09, 0x28, 0x70, 0xef, 0x62, +0x0c, 0x00, 0x71, 0x10, 0x62, 0x0c, 0x00, 0x62, +0x0d, 0x00, 0x70, 0xef, 0x62, 0x10, 0x00, 0x71, +0x10, 0x62, 0x10, 0x00, 0x62, 0x11, 0x00, 0x70, +0xef, 0x62, 0x01, 0x00, 0x62, 0x05, 0x00, 0x62, +0x09, 0x00, 0x62, 0x0d, 0x00, 0x62, 0x11, 0x00, +0x70, 0xef, 0x7f, 0x55, 0x02, 0x08, 0x55, 0x03, +0x17, 0x55, 0x04, 0x00, 0x7c, 0x03, 0x18, 0x7f, +0x7c, 0x01, 0xb4, 0x70, 0xef, 0x7f, 0x30, 0x31, +0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, +0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x62, 0xd0, +0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, 0xe0, 0x08, +0x21, 0xf8, 0x29, 0x00, 0x70, 0xfe, 0x60, 0xe0, +0x70, 0xef, 0x4b, 0x4b, 0x4b, 0x4b, 0x51, 0x02, +0x21, 0xf7, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, +0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, +0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, +0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, +0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, +0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, +0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, +0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, +0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, +0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, +0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, +0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, +0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, +0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, +0x80, 0x01, 0x60, 0x00, 0x47, 0x00, 0x00, 0x49, +0x01, 0x00, 0x29, 0x08, 0x60, 0x00, 0x57, 0x01, +0x79, 0xbf, 0xfe, 0x18, 0x71, 0x10, 0x60, 0xe0, +0x70, 0xef, 0x71, 0x01, 0x7f, 0x08, 0x67, 0x67, +0x67, 0x67, 0x21, 0x0f, 0xff, 0x40, 0x9f, 0x4e, +0x18, 0x21, 0x0f, 0xff, 0x39, 0x9f, 0x47, 0x7f, +0x08, 0x10, 0x28, 0xa0, 0x0b, 0x9f, 0x3f, 0x20, +0x18, 0x75, 0xdf, 0xf5, 0x74, 0x8f, 0xf2, 0x38, +0xfe, 0x7f, 0x52, 0x00, 0xa0, 0x08, 0x10, 0x9f, +0x2d, 0x20, 0x75, 0x8f, 0xf6, 0x70, 0x3f, 0x71, +0xc0, 0x7f, 0x50, 0x0d, 0x9f, 0x20, 0x50, 0x0a, +0x9f, 0x1c, 0x7f, 0x70, 0xbf, 0x62, 0xd3, 0x03, +0x4f, 0x52, 0xfb, 0xa0, 0x15, 0x7b, 0xfb, 0x52, +0xfc, 0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9f, +0x05, 0x4f, 0x62, 0xd3, 0x03, 0x77, 0xfd, 0x8f, +0xe9, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x3d, 0xfa, +0x00, 0xb0, 0x06, 0x3d, 0xfb, 0x00, 0xa0, 0x18, +0x10, 0x52, 0xfc, 0x59, 0xfd, 0x28, 0x9e, 0xe6, +0x20, 0x07, 0xfd, 0x01, 0x0f, 0xfc, 0x00, 0x17, +0xfb, 0x01, 0x1f, 0xfa, 0x00, 0x8f, 0xe0, 0x7f, +0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, +0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xfb, +0x80, 0x04, 0x2e, 0x03, 0x04, 0x51, 0x03, 0x60, +0x04, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, +0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, +0x26, 0x03, 0xef, 0x80, 0x04, 0x2e, 0x03, 0x10, +0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, 0x71, 0xc0, +0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x10, +0x70, 0x3f, 0x71, 0x80, 0x5d, 0xd3, 0x08, 0x5d, +0xd0, 0x08, 0x62, 0xd0, 0x00, 0x51, 0x08, 0x60, +0xd3, 0x2e, 0x05, 0x80, 0x49, 0xd7, 0x08, 0xa0, +0x09, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x00, 0x80, +0x08, 0x49, 0xd7, 0x20, 0xa0, 0x03, 0x80, 0xa6, +0x51, 0x05, 0x21, 0x0e, 0xe0, 0x01, 0x80, 0x11, +0x80, 0x67, 0x80, 0x79, 0x80, 0x47, 0x80, 0x96, +0x80, 0x94, 0x80, 0x92, 0x80, 0x90, 0x80, 0x97, +0x5d, 0xd8, 0x21, 0xfe, 0x39, 0x40, 0xa0, 0x06, +0x62, 0xd7, 0x00, 0x80, 0x8a, 0x49, 0xd8, 0x01, +0xb0, 0x0f, 0x55, 0x0c, 0x02, 0x26, 0x05, 0xf0, +0x2e, 0x05, 0x02, 0x62, 0xd7, 0x10, 0x80, 0x77, +0x55, 0x0c, 0x01, 0x26, 0x05, 0xf0, 0x2e, 0x05, +0x06, 0x5f, 0x07, 0x06, 0x51, 0x09, 0x02, 0x07, +0x5c, 0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, 0x62, +0xd7, 0x14, 0x80, 0x5b, 0x51, 0x0a, 0x78, 0x3a, +0x07, 0xc0, 0x0f, 0x51, 0x09, 0x02, 0x07, 0x5c, +0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, 0x2e, 0x05, +0x20, 0x60, 0xd8, 0x62, 0xd7, 0x04, 0x80, 0x3f, +0x5d, 0xd8, 0x3a, 0x0a, 0xd0, 0x2b, 0xa0, 0x29, +0x53, 0x07, 0x53, 0x06, 0x26, 0x05, 0xf0, 0x2e, +0x05, 0x04, 0x80, 0x18, 0x51, 0x0b, 0x78, 0x3a, +0x07, 0xc0, 0x16, 0x51, 0x09, 0x02, 0x07, 0x5c, +0x5d, 0xd8, 0x54, 0x00, 0x2e, 0x05, 0x10, 0x76, +0x07, 0x80, 0x01, 0x62, 0xd7, 0x10, 0x80, 0x0f, +0x62, 0xd7, 0x00, 0x80, 0x0a, 0x26, 0x05, 0xf0, +0x2e, 0x05, 0x00, 0x55, 0x0c, 0x00, 0x18, 0x60, +0xd0, 0x18, 0x60, 0xd3, 0x20, 0x18, 0x7e, 0x62, +0xd0, 0x00, 0x71, 0x10, 0x41, 0x04, 0xfc, 0x43, +0x05, 0x03, 0x70, 0xef, 0x26, 0x03, 0xfc, 0x51, +0x03, 0x60, 0x04, 0x55, 0x0c, 0x00, 0x90, 0x28, +0x90, 0x2d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x50, +0x00, 0x53, 0x06, 0x71, 0x10, 0x43, 0x04, 0x03, +0x43, 0x05, 0x03, 0x70, 0xef, 0x2e, 0x03, 0x03, +0x51, 0x03, 0x60, 0x04, 0x7f, 0x62, 0xd0, 0x00, +0x51, 0x05, 0x21, 0xb0, 0x26, 0x05, 0x4f, 0x7f, +0x41, 0xe0, 0x7f, 0x43, 0xe0, 0x80, 0x7f, 0x43, +0xd6, 0x31, 0x7f, 0x41, 0xe0, 0x7f, 0x41, 0xd6, +0xfe, 0x7f, 0x62, 0xd0, 0x00, 0x4f, 0x52, 0xfd, +0x53, 0x0a, 0x52, 0xfc, 0x53, 0x0b, 0x52, 0xfb, +0x53, 0x09, 0x52, 0xfa, 0x53, 0x08, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x08, 0x5d, 0xa4, 0x04, 0x1b, +0x5d, 0xa5, 0x0c, 0x1a, 0x55, 0x1c, 0x01, 0x18, +0x7e, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, +0x53, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, +0x9a, 0x62, 0xd3, 0x00, 0x13, 0x7c, 0x62, 0xd3, +0x00, 0x54, 0x80, 0x62, 0xd3, 0x00, 0x52, 0x99, +0x62, 0xd3, 0x00, 0x1b, 0x7b, 0x62, 0xd3, 0x00, +0x54, 0x7f, 0x48, 0x7f, 0x80, 0xb0, 0x33, 0x3d, +0x7f, 0x00, 0xb0, 0x7b, 0x51, 0x0d, 0x3b, 0x80, +0xc0, 0x75, 0x52, 0x80, 0x58, 0x1e, 0x01, 0x00, +0x6d, 0x62, 0xd3, 0x00, 0x05, 0x4a, 0xc0, 0x09, +0x51, 0x0f, 0x3b, 0x4a, 0xd0, 0x12, 0xa0, 0x10, +0x56, 0x4a, 0x00, 0x5b, 0x64, 0x5c, 0x62, 0xd3, +0x00, 0x07, 0x7c, 0x01, 0x0f, 0x7b, 0x00, 0x80, +0x41, 0x3d, 0x7f, 0xff, 0xb0, 0x09, 0x50, 0xff, +0x12, 0x0e, 0x3b, 0x80, 0xc0, 0x20, 0x62, 0xd3, +0x00, 0x56, 0x80, 0x00, 0x56, 0x7f, 0x00, 0x5b, +0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x51, 0x78, +0xd0, 0x03, 0x50, 0x00, 0x54, 0x51, 0x08, 0x5b, +0x64, 0x5c, 0x18, 0xb0, 0x2c, 0x62, 0xd3, 0x00, +0x52, 0x9a, 0x62, 0xd3, 0x00, 0x54, 0x7c, 0x62, +0xd3, 0x00, 0x52, 0x99, 0x62, 0xd3, 0x00, 0x54, +0x7b, 0x51, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, +0x56, 0x80, 0x00, 0x56, 0x7f, 0x00, 0x5b, 0x67, +0x5c, 0x62, 0xd3, 0x00, 0x51, 0x12, 0x54, 0x51, +0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0xbf, 0x62, +0xd0, 0x00, 0x70, 0xbf, 0x08, 0x5c, 0x62, 0xd3, +0x00, 0x52, 0x4c, 0x53, 0x19, 0x55, 0x18, 0x00, +0x18, 0x08, 0x90, 0x7e, 0x62, 0xd3, 0x00, 0x23, +0x4e, 0xb0, 0x2c, 0x51, 0x10, 0x04, 0x19, 0x0e, +0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, 0x00, +0x52, 0x80, 0x12, 0x19, 0x52, 0x7f, 0x1a, 0x18, +0xc0, 0x39, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, +0x52, 0x4f, 0x78, 0x54, 0x4f, 0x08, 0x5b, 0x64, +0x5c, 0x18, 0xb0, 0x3e, 0x80, 0x18, 0x51, 0x10, +0x14, 0x19, 0x1e, 0x18, 0x00, 0x18, 0x64, 0x5c, +0x62, 0xd3, 0x00, 0x52, 0x80, 0x12, 0x19, 0x52, +0x7f, 0x1a, 0x18, 0xc0, 0x0e, 0x5b, 0x67, 0x90, +0x31, 0x62, 0xd3, 0x00, 0x2d, 0x4e, 0x50, 0x01, +0x80, 0x24, 0x5b, 0x67, 0x08, 0x90, 0x23, 0x73, +0x62, 0xd3, 0x00, 0x25, 0x4e, 0x62, 0xd3, 0x00, +0x20, 0x51, 0x11, 0x54, 0x4f, 0x50, 0x00, 0x80, +0x0d, 0x5b, 0x67, 0x90, 0x0d, 0x73, 0x62, 0xd3, +0x00, 0x25, 0x4e, 0x50, 0x00, 0x70, 0x3f, 0x71, +0xc0, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x5c, 0x18, +0x21, 0x07, 0xf0, 0x01, 0x7f, 0x01, 0x02, 0x04, +0x08, 0x10, 0x20, 0x40, 0x80, 0x70, 0xbf, 0x70, +0xbf, 0x62, 0xd3, 0x00, 0x50, 0x02, 0x78, 0x08, +0x5c, 0x56, 0x4c, 0x1e, 0x18, 0x78, 0xdf, 0xf8, +0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x91, 0xb2, +0x70, 0xbf, 0x18, 0x08, 0x64, 0x5c, 0x62, 0xd3, +0x00, 0x52, 0x9a, 0x62, 0xd3, 0x00, 0x54, 0x7c, +0x62, 0xd3, 0x00, 0x52, 0x99, 0x62, 0xd3, 0x00, +0x54, 0x7b, 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, +0x71, 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x14, +0x00, 0x50, 0x02, 0x78, 0x08, 0x9f, 0x0e, 0x39, +0x01, 0xb0, 0x04, 0x55, 0x14, 0x01, 0x18, 0x78, +0xdf, 0xf3, 0x51, 0x14, 0x7f, 0x50, 0x02, 0x78, +0x08, 0x9e, 0x3e, 0x18, 0x78, 0xdf, 0xfa, 0x7f, +0x98, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, +0x97, 0xd8, 0xd9, 0xda, 0xdb, 0xdf, 0x00, 0x01, +0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x70, +0xbf, 0x62, 0xd0, 0x00, 0x62, 0xd3, 0x00, 0x57, +0x00, 0x56, 0x4e, 0x00, 0x79, 0xdf, 0xfb, 0x62, +0xd3, 0x00, 0x57, 0x01, 0x50, 0x03, 0x54, 0x4f, +0x79, 0xdf, 0xfc, 0x62, 0xd3, 0x00, 0x50, 0x14, +0x57, 0x01, 0x54, 0x51, 0x79, 0xdf, 0xfc, 0x70, +0x3f, 0x71, 0xc0, 0x55, 0x0d, 0x19, 0x55, 0x0e, +0x05, 0x55, 0x0f, 0x14, 0x55, 0x10, 0x01, 0x55, +0x11, 0x03, 0x55, 0x12, 0x14, 0x55, 0x22, 0x04, +0x55, 0x1f, 0x14, 0x43, 0x61, 0x0d, 0x57, 0x00, +0x50, 0x02, 0x90, 0xae, 0x50, 0x04, 0xff, 0x98, +0x29, 0x00, 0x60, 0xa9, 0x62, 0xa0, 0x08, 0x43, +0xa2, 0x04, 0x62, 0xa3, 0x70, 0x43, 0x7a, 0x01, +0x43, 0xaa, 0x02, 0x43, 0xdf, 0x01, 0x50, 0x01, +0x57, 0x09, 0x90, 0x20, 0x90, 0x55, 0x57, 0x01, +0x50, 0xb3, 0x91, 0x5d, 0x50, 0x00, 0x57, 0x0d, +0x90, 0x12, 0x90, 0x47, 0x7f, 0x53, 0x22, 0xff, +0x67, 0x29, 0x00, 0x60, 0xa9, 0x51, 0x21, 0x58, +0x20, 0x90, 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x21, +0x03, 0x53, 0x21, 0x64, 0x64, 0x64, 0x64, 0x64, +0x29, 0x80, 0x60, 0xa1, 0x5b, 0x78, 0x21, 0x0f, +0x29, 0x08, 0x74, 0x53, 0x20, 0x12, 0x22, 0x02, +0x21, 0x5c, 0x50, 0x00, 0x53, 0x1d, 0x53, 0x23, +0x29, 0x01, 0x79, 0xa0, 0x08, 0x64, 0x6b, 0x1d, +0x6b, 0x23, 0x8f, 0xf5, 0x60, 0xb5, 0x51, 0x1d, +0x60, 0xb4, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x90, +0x28, 0x90, 0x5a, 0x18, 0x78, 0xdf, 0xf8, 0x7f, +0x41, 0xdf, 0xfe, 0x71, 0x10, 0x41, 0xd8, 0xfd, +0x70, 0xef, 0x41, 0x61, 0xf3, 0x41, 0xa2, 0xfb, +0x41, 0xa0, 0xf7, 0x62, 0xa3, 0x00, 0x62, 0xa9, +0x00, 0x41, 0xaa, 0xfd, 0x7f, 0x02, 0x20, 0x02, +0x08, 0x64, 0x5c, 0xff, 0xf8, 0x4b, 0x74, 0xff, +0xf4, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1d, 0x10, +0x5b, 0x64, 0x64, 0x5c, 0x71, 0x10, 0x5e, 0x01, +0x2a, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, +0x00, 0x22, 0x1d, 0x61, 0x00, 0x36, 0x1d, 0xff, +0x18, 0xfe, 0xd6, 0x5c, 0x5e, 0x00, 0x2a, 0x1d, +0x61, 0x00, 0x70, 0xef, 0x7f, 0x62, 0xd0, 0x00, +0x10, 0x73, 0x53, 0x1d, 0x71, 0x10, 0x5b, 0xfe, +0xc0, 0x5c, 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, +0x70, 0xef, 0x18, 0x64, 0x64, 0x5c, 0x71, 0x10, +0x5e, 0x01, 0x22, 0x1d, 0x61, 0x01, 0x36, 0x1d, +0xff, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, +0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, +0x1e, 0x50, 0x00, 0x53, 0x1a, 0x53, 0x1b, 0x51, +0x1e, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x24, 0x53, +0x1f, 0x43, 0xa0, 0x01, 0x51, 0x1f, 0x60, 0xfd, +0x41, 0xa3, 0xdf, 0x51, 0x1e, 0x9f, 0x7a, 0x9f, +0x81, 0x58, 0x23, 0x55, 0x1c, 0x00, 0x62, 0xa5, +0x00, 0x62, 0xa4, 0x00, 0x43, 0xb3, 0x01, 0x51, +0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1e, +0x9f, 0x5f, 0x9f, 0x91, 0x43, 0xa3, 0x20, 0x41, +0xa0, 0xfe, 0x62, 0xfd, 0x00, 0x50, 0xff, 0x4c, +0x1b, 0x14, 0x1b, 0x51, 0x20, 0x11, 0x08, 0xfe, +0x4d, 0x4c, 0x1a, 0x1c, 0x1a, 0xd0, 0x07, 0x55, +0x1a, 0x00, 0x55, 0x1b, 0x00, 0x51, 0x1e, 0x64, +0x5c, 0x62, 0xd3, 0x00, 0x51, 0x1b, 0x54, 0x9a, +0x51, 0x1a, 0x54, 0x99, 0x70, 0x3f, 0x71, 0xc0, +0x7f, 0x08, 0x9f, 0x86, 0x18, 0x78, 0xdf, 0xfa, +0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x27, +0x5a, 0x26, 0x55, 0x1e, 0x01, 0x62, 0xd3, 0x00, +0x58, 0x1e, 0x56, 0x24, 0x80, 0x55, 0x29, 0x08, +0x55, 0x28, 0x80, 0x51, 0x1e, 0x9f, 0x63, 0x51, +0x1e, 0x9f, 0x5f, 0x70, 0xbf, 0x58, 0x1e, 0x62, +0xd3, 0x00, 0x51, 0x1b, 0x3a, 0x27, 0x51, 0x1a, +0x1a, 0x26, 0xd0, 0x06, 0x51, 0x28, 0x73, 0x25, +0x24, 0x68, 0x28, 0x26, 0x28, 0x7f, 0x51, 0x28, +0x2d, 0x24, 0x7a, 0x29, 0xbf, 0xd6, 0x7a, 0x1e, +0xdf, 0xc4, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, +0xd0, 0x00, 0x51, 0xa2, 0x11, 0x35, 0x51, 0xa1, +0x19, 0x0c, 0xd0, 0x12, 0x7c, 0x13, 0x9a, 0x39, +0x0f, 0xa0, 0x16, 0x62, 0xd0, 0x00, 0x76, 0xa2, +0x0e, 0xa1, 0x00, 0x80, 0x0c, 0x62, 0xd0, 0x00, +0x55, 0xa2, 0x00, 0x55, 0xa1, 0x00, 0x90, 0xa9, +0x7f, 0x62, 0xd0, 0x00, 0x3c, 0xa9, 0xf0, 0xd0, +0x03, 0x76, 0xa9, 0x62, 0xd0, 0x00, 0x51, 0x2f, +0x21, 0x7f, 0x53, 0x49, 0x51, 0xa9, 0x3a, 0x49, +0xb0, 0x50, 0x7c, 0x13, 0x9a, 0x62, 0xd0, 0x00, +0x53, 0xaf, 0x3c, 0xaf, 0x0f, 0xa0, 0x3d, 0x3c, +0xab, 0x00, 0xb0, 0x1c, 0x55, 0x91, 0x00, 0x55, +0x92, 0x00, 0x51, 0xaf, 0x53, 0x48, 0x55, 0x49, +0x00, 0x06, 0x48, 0x91, 0x0e, 0x49, 0x00, 0x51, +0x49, 0x60, 0xd5, 0x50, 0x08, 0x3f, 0x48, 0x62, +0xd0, 0x00, 0x55, 0xa7, 0x00, 0x3c, 0xae, 0x00, +0xb0, 0x0a, 0x7c, 0x14, 0x2f, 0x62, 0xd0, 0x00, +0x55, 0xae, 0x01, 0x62, 0xd0, 0x00, 0x55, 0xb2, +0x03, 0x80, 0x07, 0x62, 0xd0, 0x00, 0x55, 0xa9, +0x00, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0xa2, 0x00, +0x55, 0xa1, 0x00, 0x3c, 0xae, 0x01, 0xb0, 0x31, +0x7a, 0xb2, 0x3c, 0xb2, 0x00, 0xb0, 0x2a, 0x3c, +0xae, 0x01, 0xb0, 0x0a, 0x7c, 0x14, 0xc2, 0x62, +0xd0, 0x00, 0x55, 0xae, 0x00, 0x62, 0xd0, 0x00, +0x3c, 0xab, 0x00, 0xb0, 0x0e, 0x51, 0xaf, 0x53, +0x48, 0x55, 0x49, 0x00, 0x06, 0x48, 0x91, 0x7c, +0x1a, 0x3b, 0x62, 0xd0, 0x00, 0x55, 0xa9, 0x00, +0x7f, 0x10, 0x4f, 0x38, 0x16, 0x62, 0xd0, 0x00, +0x3c, 0xaa, 0x00, 0xb0, 0x05, 0x51, 0x9d, 0x53, +0x24, 0x56, 0x0d, 0x00, 0x80, 0x67, 0x56, 0x00, +0x00, 0x80, 0x5b, 0x62, 0xd0, 0x00, 0x3c, 0xaa, +0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x48, 0x55, +0x49, 0x00, 0x06, 0x48, 0x9d, 0x7c, 0x19, 0x4d, +0x52, 0x00, 0x53, 0x46, 0x55, 0x47, 0x00, 0x06, +0x46, 0x24, 0x7c, 0x1a, 0x1c, 0x10, 0x52, 0x00, +0x7c, 0x09, 0x2a, 0x20, 0x10, 0x7c, 0x05, 0xb5, +0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, +0x7c, 0x18, 0xbc, 0x52, 0x0d, 0x7c, 0x1a, 0x47, +0x02, 0x48, 0x53, 0x48, 0x51, 0x47, 0x0a, 0x49, +0x53, 0x49, 0x7c, 0x1a, 0x10, 0x06, 0x46, 0x99, +0x0e, 0x47, 0x00, 0x51, 0x47, 0x7c, 0x19, 0x64, +0x7c, 0x19, 0x6f, 0x77, 0x00, 0x3d, 0x00, 0x02, +0xcf, 0xa2, 0x77, 0x0d, 0x3d, 0x0d, 0x03, 0xcf, +0x96, 0x56, 0x00, 0x00, 0x81, 0x05, 0x7c, 0x18, +0xa0, 0x7c, 0x19, 0x08, 0x51, 0x49, 0x60, 0xd4, +0x3e, 0x48, 0x54, 0x0e, 0x3e, 0x48, 0x54, 0x0f, +0x52, 0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x55, +0x46, 0x06, 0x55, 0x47, 0x00, 0x55, 0x41, 0x00, +0x55, 0x40, 0x00, 0x3c, 0x47, 0x00, 0xb0, 0x06, +0x3c, 0x46, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, +0x47, 0x6e, 0x46, 0xd0, 0x0c, 0x62, 0xd0, 0x00, +0x51, 0x48, 0x04, 0x41, 0x51, 0x49, 0x0c, 0x40, +0x65, 0x48, 0x6b, 0x49, 0x8f, 0xde, 0x5f, 0x48, +0x41, 0x5f, 0x49, 0x40, 0x62, 0xd0, 0x00, 0x5a, +0x46, 0x06, 0x46, 0x03, 0x51, 0x46, 0x04, 0x48, +0x0e, 0x49, 0x03, 0x51, 0x49, 0x60, 0xd4, 0x3e, +0x48, 0x54, 0x10, 0x3e, 0x48, 0x54, 0x11, 0x52, +0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x55, 0x46, +0x06, 0x55, 0x47, 0x00, 0x55, 0x41, 0x00, 0x55, +0x40, 0x00, 0x3c, 0x47, 0x00, 0xb0, 0x06, 0x3c, +0x46, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x47, +0x6e, 0x46, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, +0x48, 0x04, 0x41, 0x51, 0x49, 0x0c, 0x40, 0x65, +0x48, 0x6b, 0x49, 0x8f, 0xde, 0x5f, 0x48, 0x41, +0x5f, 0x49, 0x40, 0x62, 0xd0, 0x00, 0x5a, 0x46, +0x06, 0x46, 0x05, 0x51, 0x46, 0x04, 0x48, 0x0e, +0x49, 0x03, 0x51, 0x49, 0x60, 0xd4, 0x3e, 0x48, +0x54, 0x12, 0x3e, 0x48, 0x54, 0x13, 0x50, 0x03, +0x08, 0x5a, 0x48, 0x06, 0x48, 0x0e, 0x08, 0x51, +0x48, 0x08, 0x7c, 0x17, 0x46, 0x38, 0xfd, 0x62, +0xd0, 0x00, 0x51, 0x48, 0x54, 0x15, 0x51, 0x49, +0x54, 0x14, 0x7c, 0x18, 0x94, 0x7c, 0x19, 0x87, +0x7c, 0x19, 0xec, 0x06, 0x48, 0x7b, 0x7c, 0x19, +0xdc, 0x7c, 0x18, 0x94, 0x51, 0x48, 0x01, 0x63, +0x7c, 0x19, 0xa8, 0x51, 0x48, 0x01, 0x6b, 0x7c, +0x19, 0xa8, 0x06, 0x48, 0x73, 0x7c, 0x19, 0xdc, +0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xf8, 0x38, +0xea, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x16, 0x10, +0x57, 0x09, 0x50, 0x01, 0x7c, 0x08, 0x64, 0x20, +0x62, 0xd0, 0x00, 0x50, 0x01, 0x10, 0x08, 0x57, +0xa2, 0x28, 0x53, 0x49, 0x18, 0x75, 0x09, 0x00, +0x28, 0x53, 0x48, 0x20, 0x10, 0x51, 0x49, 0x08, +0x51, 0x48, 0x20, 0x7c, 0x09, 0xa9, 0x20, 0x10, +0x57, 0x0d, 0x50, 0x00, 0x7c, 0x08, 0x64, 0x20, +0x62, 0xd0, 0x00, 0x3c, 0xaa, 0x01, 0xb0, 0x0b, +0x51, 0x24, 0x53, 0x30, 0x51, 0x25, 0x53, 0x31, +0x80, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x9d, 0x53, +0x24, 0x51, 0x9e, 0x53, 0x25, 0x10, 0x50, 0x00, +0x7c, 0x09, 0x2a, 0x20, 0x56, 0x0d, 0x00, 0x80, +0x67, 0x56, 0x00, 0x00, 0x80, 0x5b, 0x62, 0xd0, +0x00, 0x3c, 0xaa, 0x00, 0xb0, 0x1b, 0x52, 0x00, +0x53, 0x48, 0x55, 0x49, 0x00, 0x06, 0x48, 0x9d, +0x7c, 0x19, 0x4d, 0x52, 0x00, 0x53, 0x46, 0x55, +0x47, 0x00, 0x06, 0x46, 0x24, 0x7c, 0x1a, 0x1c, +0x10, 0x52, 0x00, 0x7c, 0x09, 0x2a, 0x20, 0x10, +0x7c, 0x05, 0xb5, 0x62, 0xd0, 0x00, 0x20, 0x39, +0x00, 0xbf, 0xee, 0x7c, 0x18, 0xbc, 0x52, 0x0d, +0x7c, 0x1a, 0x47, 0x02, 0x48, 0x53, 0x48, 0x51, +0x47, 0x0a, 0x49, 0x53, 0x49, 0x7c, 0x1a, 0x10, +0x06, 0x46, 0x99, 0x0e, 0x47, 0x00, 0x51, 0x47, +0x7c, 0x19, 0x64, 0x7c, 0x19, 0x6f, 0x77, 0x00, +0x3d, 0x00, 0x02, 0xcf, 0xa2, 0x77, 0x0d, 0x3d, +0x0d, 0x03, 0xcf, 0x96, 0x56, 0x00, 0x00, 0x81, +0x05, 0x7c, 0x18, 0xa0, 0x7c, 0x19, 0x08, 0x51, +0x49, 0x60, 0xd4, 0x3e, 0x48, 0x54, 0x0e, 0x3e, +0x48, 0x54, 0x0f, 0x52, 0x00, 0x53, 0x48, 0x55, +0x49, 0x00, 0x55, 0x46, 0x06, 0x55, 0x47, 0x00, +0x55, 0x41, 0x00, 0x55, 0x40, 0x00, 0x3c, 0x47, +0x00, 0xb0, 0x06, 0x3c, 0x46, 0x00, 0xa0, 0x1a, +0x70, 0xfb, 0x6e, 0x47, 0x6e, 0x46, 0xd0, 0x0c, +0x62, 0xd0, 0x00, 0x51, 0x48, 0x04, 0x41, 0x51, +0x49, 0x0c, 0x40, 0x65, 0x48, 0x6b, 0x49, 0x8f, +0xde, 0x5f, 0x48, 0x41, 0x5f, 0x49, 0x40, 0x62, +0xd0, 0x00, 0x5a, 0x46, 0x06, 0x46, 0x03, 0x51, +0x46, 0x04, 0x48, 0x0e, 0x49, 0x03, 0x51, 0x49, +0x60, 0xd4, 0x3e, 0x48, 0x54, 0x10, 0x3e, 0x48, +0x54, 0x11, 0x52, 0x00, 0x53, 0x48, 0x55, 0x49, +0x00, 0x55, 0x46, 0x06, 0x55, 0x47, 0x00, 0x55, +0x41, 0x00, 0x55, 0x40, 0x00, 0x3c, 0x47, 0x00, +0xb0, 0x06, 0x3c, 0x46, 0x00, 0xa0, 0x1a, 0x70, +0xfb, 0x6e, 0x47, 0x6e, 0x46, 0xd0, 0x0c, 0x62, +0xd0, 0x00, 0x51, 0x48, 0x04, 0x41, 0x51, 0x49, +0x0c, 0x40, 0x65, 0x48, 0x6b, 0x49, 0x8f, 0xde, +0x5f, 0x48, 0x41, 0x5f, 0x49, 0x40, 0x62, 0xd0, +0x00, 0x5a, 0x46, 0x06, 0x46, 0x05, 0x51, 0x46, +0x04, 0x48, 0x0e, 0x49, 0x03, 0x51, 0x49, 0x60, +0xd4, 0x3e, 0x48, 0x54, 0x12, 0x3e, 0x48, 0x54, +0x13, 0x50, 0x03, 0x08, 0x5a, 0x48, 0x06, 0x48, +0x0e, 0x08, 0x51, 0x48, 0x08, 0x7c, 0x17, 0x46, +0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, 0x48, 0x54, +0x15, 0x51, 0x49, 0x54, 0x14, 0x7c, 0x18, 0x94, +0x7c, 0x19, 0x87, 0x7c, 0x19, 0xec, 0x06, 0x48, +0x7b, 0x7c, 0x19, 0xdc, 0x7c, 0x18, 0x94, 0x51, +0x48, 0x01, 0x63, 0x7c, 0x19, 0xa8, 0x51, 0x48, +0x01, 0x6b, 0x7c, 0x19, 0xa8, 0x06, 0x48, 0x73, +0x7c, 0x19, 0xdc, 0x77, 0x00, 0x3d, 0x00, 0x02, +0xce, 0xf8, 0x56, 0x00, 0x00, 0x80, 0x19, 0x7c, +0x18, 0xa0, 0x06, 0x48, 0x24, 0x7c, 0x19, 0x4d, +0x52, 0x00, 0x53, 0x46, 0x55, 0x47, 0x00, 0x06, +0x46, 0x30, 0x7c, 0x1a, 0x1c, 0x77, 0x00, 0x3d, +0x00, 0x02, 0xcf, 0xe4, 0x38, 0xea, 0x20, 0x7f, +0x10, 0x4f, 0x38, 0x02, 0x62, 0xd0, 0x00, 0x52, +0xfc, 0x01, 0x02, 0x53, 0x48, 0x52, 0xfb, 0x09, +0x00, 0x7c, 0x19, 0x7c, 0x52, 0xfc, 0x01, 0x04, +0x53, 0x46, 0x52, 0xfb, 0x7c, 0x19, 0x59, 0x12, +0x48, 0x51, 0x47, 0x1a, 0x49, 0xc0, 0x6f, 0x52, +0xfc, 0x53, 0x48, 0x52, 0xfb, 0x7c, 0x19, 0x7c, +0x52, 0xfc, 0x01, 0x02, 0x53, 0x46, 0x52, 0xfb, +0x7c, 0x19, 0x59, 0x12, 0x48, 0x51, 0x47, 0x1a, +0x49, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, +0x19, 0xc6, 0x54, 0x00, 0x3e, 0x48, 0x54, 0x01, +0x80, 0xb3, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x01, +0x04, 0x53, 0x48, 0x52, 0xfb, 0x09, 0x00, 0x7c, +0x19, 0x7c, 0x52, 0xfc, 0x53, 0x46, 0x52, 0xfb, +0x60, 0xd4, 0x3e, 0x46, 0x53, 0x47, 0x3e, 0x46, +0x12, 0x48, 0x51, 0x47, 0x1a, 0x49, 0xc0, 0x10, +0x52, 0xfc, 0x01, 0x04, 0x7c, 0x19, 0xc6, 0x54, +0x00, 0x3e, 0x48, 0x54, 0x01, 0x80, 0x7e, 0x62, +0xd0, 0x00, 0x52, 0xfc, 0x53, 0x48, 0x52, 0xfb, +0x7c, 0x19, 0xd1, 0x80, 0x70, 0x62, 0xd0, 0x00, +0x52, 0xfc, 0x53, 0x48, 0x52, 0xfb, 0x7c, 0x19, +0x7c, 0x52, 0xfc, 0x01, 0x04, 0x53, 0x46, 0x52, +0xfb, 0x7c, 0x19, 0x59, 0x12, 0x48, 0x51, 0x47, +0x1a, 0x49, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x04, +0x7c, 0x19, 0xc6, 0x54, 0x00, 0x3e, 0x48, 0x54, +0x01, 0x80, 0x42, 0x62, 0xd0, 0x00, 0x52, 0xfc, +0x01, 0x02, 0x53, 0x48, 0x52, 0xfb, 0x09, 0x00, +0x7c, 0x19, 0x7c, 0x52, 0xfc, 0x53, 0x46, 0x52, +0xfb, 0x60, 0xd4, 0x3e, 0x46, 0x53, 0x47, 0x3e, +0x46, 0x12, 0x48, 0x51, 0x47, 0x1a, 0x49, 0xc0, +0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, 0x19, 0xc6, +0x54, 0x00, 0x3e, 0x48, 0x54, 0x01, 0x80, 0x0d, +0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x48, 0x52, +0xfb, 0x7c, 0x19, 0xd1, 0x62, 0xd0, 0x00, 0x52, +0x01, 0x53, 0x48, 0x52, 0x00, 0x53, 0x49, 0x38, +0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x05, 0x62, +0xd0, 0x00, 0x55, 0xb1, 0x00, 0x56, 0x00, 0x00, +0x80, 0x38, 0x62, 0xd0, 0x00, 0x3c, 0xaa, 0x00, +0xb0, 0x1b, 0x52, 0x00, 0x53, 0x48, 0x55, 0x49, +0x00, 0x06, 0x48, 0x9d, 0x7c, 0x19, 0x4d, 0x52, +0x00, 0x53, 0x46, 0x55, 0x47, 0x00, 0x06, 0x46, +0x24, 0x7c, 0x1a, 0x1c, 0x10, 0x52, 0x00, 0x7c, +0x09, 0x2a, 0x20, 0x10, 0x7c, 0x05, 0xb5, 0x62, +0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, 0x77, +0x00, 0x3d, 0x00, 0x02, 0xcf, 0xc5, 0x56, 0x00, +0x00, 0x82, 0xab, 0x62, 0xd0, 0x00, 0x3c, 0xb0, +0x02, 0xa0, 0x9f, 0x7c, 0x18, 0x94, 0x51, 0x48, +0x01, 0x7b, 0x7c, 0x18, 0xab, 0x06, 0x48, 0x99, +0x7c, 0x19, 0x4d, 0x7c, 0x19, 0xb9, 0xd0, 0x16, +0x7c, 0x18, 0x94, 0x51, 0x48, 0x01, 0x7b, 0x7c, +0x18, 0xab, 0x06, 0x48, 0x99, 0x7c, 0x19, 0x4d, +0x7c, 0x1a, 0x60, 0x80, 0x17, 0x62, 0xd0, 0x00, +0x7c, 0x18, 0x94, 0x51, 0x48, 0x01, 0x99, 0x7c, +0x18, 0xab, 0x06, 0x48, 0x7b, 0x7c, 0x19, 0x4d, +0x7c, 0x1a, 0x60, 0x50, 0x90, 0x13, 0x02, 0x50, +0x01, 0x1b, 0x01, 0xc0, 0x4e, 0x62, 0xd0, 0x00, +0x7c, 0x18, 0x94, 0x51, 0x48, 0x01, 0x73, 0x7c, +0x18, 0xab, 0x06, 0x48, 0x99, 0x7c, 0x19, 0x4d, +0x7c, 0x19, 0xb9, 0xd0, 0x16, 0x7c, 0x18, 0x94, +0x51, 0x48, 0x01, 0x73, 0x7c, 0x18, 0xab, 0x06, +0x48, 0x99, 0x7c, 0x19, 0x4d, 0x7c, 0x1a, 0x6d, +0x80, 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0x94, +0x51, 0x48, 0x01, 0x99, 0x7c, 0x18, 0xab, 0x06, +0x48, 0x73, 0x7c, 0x19, 0x4d, 0x7c, 0x1a, 0x6d, +0x50, 0x90, 0x13, 0x04, 0x50, 0x01, 0x1b, 0x03, +0xd0, 0x08, 0x62, 0xd0, 0x00, 0x76, 0xb1, 0x82, +0x03, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0x94, 0x51, +0x48, 0x01, 0x99, 0x7c, 0x18, 0xab, 0x06, 0x48, +0x73, 0x7c, 0x19, 0x4d, 0x7c, 0x19, 0xb9, 0xd0, +0x5a, 0x7c, 0x18, 0x94, 0x7c, 0x19, 0x92, 0x06, +0x46, 0x01, 0x0e, 0x47, 0x00, 0x7c, 0x19, 0x6f, +0x7c, 0x18, 0x94, 0x51, 0x48, 0x01, 0x99, 0x7c, +0x18, 0xab, 0x06, 0x48, 0x73, 0x7c, 0x19, 0x4d, +0x7c, 0x19, 0xb9, 0xd0, 0xb4, 0x97, 0xf5, 0x40, +0x7c, 0x19, 0x92, 0x06, 0x46, 0x01, 0x0e, 0x47, +0x00, 0x7c, 0x19, 0x6f, 0x97, 0xe6, 0x40, 0x51, +0x48, 0x01, 0x99, 0x97, 0xf6, 0x40, 0x06, 0x48, +0x73, 0x7c, 0x19, 0x4d, 0x7c, 0x19, 0xb9, 0xd0, +0x90, 0x97, 0xd1, 0x40, 0x7c, 0x19, 0x92, 0x06, +0x46, 0x01, 0x0e, 0x47, 0x00, 0x7c, 0x19, 0x6f, +0x80, 0x7f, 0x62, 0xd0, 0x00, 0x97, 0xbd, 0x40, +0x51, 0x48, 0x01, 0x99, 0x97, 0xcd, 0x40, 0x06, +0x48, 0x73, 0x7c, 0x19, 0x4d, 0x3e, 0x48, 0x12, +0x46, 0x51, 0x49, 0x1a, 0x47, 0xd0, 0x62, 0x97, +0xa3, 0x40, 0x7c, 0x19, 0x92, 0x16, 0x46, 0x01, +0x1e, 0x47, 0x00, 0x7c, 0x19, 0x6f, 0x97, 0x94, +0x40, 0x51, 0x48, 0x01, 0x99, 0x97, 0xa4, 0x40, +0x06, 0x48, 0x73, 0x7c, 0x19, 0x4d, 0x3e, 0x48, +0x12, 0x46, 0x51, 0x49, 0x1a, 0x47, 0xd0, 0x39, +0x97, 0x7a, 0x40, 0x7c, 0x19, 0x92, 0x16, 0x46, +0x01, 0x1e, 0x47, 0x00, 0x7c, 0x19, 0x6f, 0x97, +0x6b, 0x40, 0x51, 0x48, 0x01, 0x99, 0x97, 0x7b, +0x40, 0x06, 0x48, 0x73, 0x7c, 0x19, 0x4d, 0x3e, +0x48, 0x12, 0x46, 0x51, 0x49, 0x1a, 0x47, 0xd0, +0x10, 0x97, 0x51, 0x40, 0x7c, 0x19, 0x92, 0x16, +0x46, 0x01, 0x1e, 0x47, 0x00, 0x7c, 0x19, 0x6f, +0x62, 0xd0, 0x00, 0x97, 0x3f, 0x40, 0x51, 0x48, +0x01, 0x6b, 0x97, 0x4f, 0x40, 0x06, 0x48, 0x63, +0x0e, 0x49, 0x00, 0x7c, 0x19, 0x6f, 0x97, 0x2c, +0x40, 0x51, 0x48, 0x01, 0x73, 0x97, 0x3c, 0x40, +0x06, 0x48, 0x6b, 0x0e, 0x49, 0x00, 0x97, 0xf7, +0x40, 0x97, 0x19, 0x40, 0x51, 0x48, 0x01, 0x99, +0x97, 0x29, 0x40, 0x06, 0x48, 0x73, 0x0e, 0x49, +0x00, 0x97, 0xe4, 0x40, 0x97, 0x06, 0x40, 0x97, +0xf6, 0x40, 0x53, 0x47, 0x7c, 0x1a, 0x7a, 0x53, +0x44, 0x08, 0x51, 0x45, 0x53, 0x43, 0x18, 0x53, +0x42, 0x65, 0x42, 0x6b, 0x43, 0x06, 0x48, 0x6b, +0x97, 0xa3, 0x40, 0x3e, 0x48, 0x53, 0x48, 0x51, +0x42, 0x04, 0x48, 0x51, 0x43, 0x0c, 0x49, 0x51, +0x44, 0x04, 0x48, 0x51, 0x45, 0x0c, 0x49, 0x70, +0xfb, 0x6e, 0x49, 0x6e, 0x48, 0x7c, 0x1a, 0x28, +0x10, 0x52, 0x00, 0x7c, 0x05, 0xf9, 0x20, 0x62, +0xd0, 0x00, 0x96, 0xc0, 0x40, 0x51, 0x48, 0x01, +0x99, 0x96, 0xd0, 0x40, 0x06, 0x48, 0x7b, 0x97, +0x6c, 0x40, 0x97, 0xd5, 0x40, 0xd0, 0x25, 0x52, +0x00, 0x53, 0x48, 0x55, 0x49, 0x00, 0x06, 0x48, +0x95, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd4, +0x3e, 0x48, 0x7a, 0x48, 0x53, 0x47, 0x06, 0x47, +0x01, 0x51, 0x49, 0x60, 0xd5, 0x51, 0x47, 0x3f, +0x48, 0x80, 0x0a, 0x96, 0x93, 0x40, 0x06, 0x48, +0x95, 0x7c, 0x1a, 0x3b, 0x96, 0x8a, 0x40, 0x06, +0x48, 0x95, 0x97, 0x31, 0x40, 0x50, 0x05, 0x3a, +0x49, 0xd0, 0x41, 0x96, 0x6f, 0x40, 0x51, 0x48, +0x01, 0x7b, 0x53, 0x46, 0x51, 0x49, 0x09, 0x00, +0x53, 0x47, 0x06, 0x48, 0x99, 0x97, 0x16, 0x40, +0x3e, 0x48, 0x53, 0x48, 0x51, 0x47, 0x7c, 0x1a, +0x7a, 0x02, 0x48, 0x53, 0x48, 0x51, 0x45, 0x0a, +0x49, 0x53, 0x49, 0x97, 0xdb, 0x40, 0x52, 0x00, +0x53, 0x48, 0x55, 0x49, 0x00, 0x06, 0x48, 0x95, +0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, 0xd5, 0x50, +0x00, 0x3f, 0x48, 0x77, 0x00, 0x3d, 0x00, 0x02, +0xcd, 0x52, 0x62, 0xd0, 0x00, 0x3c, 0xb0, 0x02, +0xb0, 0x9a, 0x56, 0x00, 0x00, 0x80, 0x90, 0x62, +0xd0, 0x00, 0x96, 0x18, 0x40, 0x51, 0x48, 0x01, +0x99, 0x96, 0x28, 0x40, 0x06, 0x48, 0x38, 0x0e, +0x49, 0x00, 0x96, 0xe3, 0x40, 0x96, 0x05, 0x40, +0x51, 0x48, 0x01, 0x7b, 0x96, 0x15, 0x40, 0x06, +0x48, 0x3c, 0x0e, 0x49, 0x00, 0x96, 0xd0, 0x40, +0x95, 0xf2, 0x40, 0x51, 0x48, 0x01, 0x7b, 0x96, +0x02, 0x40, 0x51, 0x48, 0x01, 0x99, 0x53, 0x44, +0x51, 0x49, 0x97, 0x9f, 0x40, 0x51, 0x46, 0x12, +0x44, 0x51, 0x47, 0x1a, 0x45, 0xd0, 0x2b, 0x97, +0x4f, 0x40, 0x51, 0x46, 0x01, 0x7b, 0x53, 0x44, +0x51, 0x47, 0x97, 0x87, 0x40, 0x06, 0x46, 0x99, +0x0e, 0x47, 0x00, 0x51, 0x47, 0x60, 0xd4, 0x3e, +0x46, 0x53, 0x47, 0x3e, 0x46, 0x12, 0x44, 0x54, +0x02, 0x51, 0x47, 0x1a, 0x45, 0x54, 0x01, 0x80, +0x07, 0x56, 0x02, 0x00, 0x56, 0x01, 0x00, 0x62, +0xd0, 0x00, 0x06, 0x48, 0x34, 0x0e, 0x49, 0x00, +0x51, 0x49, 0x60, 0xd5, 0x52, 0x01, 0x3f, 0x48, +0x52, 0x02, 0x3f, 0x48, 0x77, 0x00, 0x3d, 0x00, +0x02, 0xcf, 0x6d, 0x62, 0xd0, 0x00, 0x3c, 0xb0, +0x02, 0xa0, 0x18, 0x3c, 0xb1, 0x00, 0xa0, 0x13, +0x50, 0x01, 0x08, 0x50, 0x2c, 0x08, 0x90, 0x0e, +0x38, 0xfe, 0x7c, 0x0a, 0xc9, 0x10, 0x7c, 0x07, +0xb5, 0x20, 0x38, 0xfb, 0x20, 0x7f, 0x10, 0x4f, +0x80, 0x02, 0x40, 0x62, 0xd0, 0x00, 0x52, 0xfc, +0x53, 0x48, 0x52, 0xfb, 0x53, 0x49, 0x51, 0x48, +0x11, 0x01, 0x54, 0xfc, 0x51, 0x49, 0x19, 0x00, +0x54, 0xfb, 0x3c, 0x49, 0x00, 0xbf, 0xe4, 0x3c, +0x48, 0x00, 0xbf, 0xdf, 0x20, 0x7f, 0x10, 0x7c, +0x04, 0x7f, 0x7c, 0x04, 0x5c, 0x20, 0x7f, 0x10, +0x7c, 0x04, 0x7b, 0x7c, 0x04, 0x58, 0x20, 0x7f, +0x62, 0xd0, 0x00, 0x51, 0x4c, 0x12, 0x80, 0x50, +0x00, 0x1a, 0x7f, 0xd0, 0x0f, 0x51, 0x4d, 0x12, +0x82, 0x50, 0x00, 0x1a, 0x81, 0xd0, 0x05, 0x50, +0x0f, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x51, 0x82, +0x12, 0x80, 0x51, 0x81, 0x1a, 0x7f, 0xd0, 0x05, +0x50, 0x00, 0x80, 0x06, 0x62, 0xd0, 0x00, 0x50, +0x01, 0x7f, 0x10, 0x4f, 0x38, 0x05, 0x62, 0xd0, +0x00, 0x51, 0x80, 0x54, 0x02, 0x51, 0x7f, 0x54, +0x01, 0x56, 0x04, 0x00, 0x56, 0x00, 0x00, 0x56, +0x03, 0x00, 0x80, 0x61, 0x94, 0xea, 0x40, 0x06, +0x48, 0x4c, 0x0e, 0x49, 0x00, 0x51, 0x49, 0x60, +0xd4, 0x3e, 0x48, 0x53, 0x48, 0x96, 0x49, 0x40, +0x06, 0x46, 0x7f, 0x0e, 0x47, 0x00, 0x51, 0x47, +0x95, 0x92, 0x40, 0x51, 0x48, 0x12, 0x46, 0x50, +0x00, 0x1a, 0x47, 0xd0, 0x03, 0x77, 0x03, 0x62, +0xd0, 0x00, 0x94, 0xb0, 0x40, 0x06, 0x48, 0x7f, +0x95, 0x63, 0x40, 0x3e, 0x48, 0x53, 0x48, 0x52, +0x02, 0x12, 0x48, 0x52, 0x01, 0x1a, 0x49, 0xd0, +0x1a, 0x94, 0x99, 0x40, 0x06, 0x48, 0x7f, 0x0e, +0x49, 0x00, 0x51, 0x49, 0x60, 0xd4, 0x3e, 0x48, +0x54, 0x01, 0x3e, 0x48, 0x54, 0x02, 0x52, 0x00, +0x54, 0x04, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, +0x9c, 0x50, 0x01, 0x3b, 0x03, 0xd0, 0x08, 0x62, +0xd0, 0x00, 0x50, 0x0f, 0x80, 0x06, 0x52, 0x04, +0x62, 0xd0, 0x00, 0x38, 0xfb, 0x20, 0x7f, 0x10, +0x4f, 0x38, 0x02, 0x70, 0xfe, 0x62, 0xd0, 0x00, +0x26, 0x2a, 0xf0, 0x51, 0xaf, 0x01, 0x01, 0x53, +0x49, 0x51, 0x2a, 0x2a, 0x49, 0x53, 0x2a, 0x71, +0x01, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x05, 0xb5, +0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, +0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, +0x7c, 0x05, 0xb5, 0x62, 0xd0, 0x00, 0x20, 0x53, +0x49, 0x47, 0x49, 0x20, 0xa0, 0x03, 0x80, 0x1a, +0x50, 0x00, 0x08, 0x50, 0x04, 0x08, 0x9e, 0xb6, +0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, +0x01, 0x11, 0xdc, 0x52, 0x00, 0x19, 0x05, 0xcf, +0xd7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, +0x21, 0x10, 0x7c, 0x05, 0xb5, 0x62, 0xd0, 0x00, +0x20, 0x53, 0x49, 0x47, 0x49, 0x20, 0xb0, 0x03, +0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x04, 0x08, +0x9e, 0x84, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, +0x00, 0x52, 0x01, 0x11, 0x2c, 0x52, 0x00, 0x19, +0x01, 0xcf, 0xd7, 0x43, 0x00, 0x08, 0x38, 0xfe, +0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x70, 0xfe, +0x62, 0xd0, 0x00, 0x26, 0x2a, 0xf0, 0x51, 0xaf, +0x01, 0x09, 0x53, 0x49, 0x51, 0x2a, 0x2a, 0x49, +0x53, 0x2a, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, +0x7c, 0x05, 0xb5, 0x62, 0xd0, 0x00, 0x20, 0x41, +0x00, 0xf7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, +0x80, 0x21, 0x10, 0x7c, 0x05, 0xb5, 0x62, 0xd0, +0x00, 0x20, 0x53, 0x49, 0x47, 0x49, 0x20, 0xa0, +0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x04, +0x08, 0x9e, 0x23, 0x38, 0xfe, 0x77, 0x01, 0x0f, +0x00, 0x00, 0x52, 0x01, 0x11, 0xdc, 0x52, 0x00, +0x19, 0x05, 0xcf, 0xd7, 0x56, 0x01, 0x00, 0x56, +0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0xb5, +0x62, 0xd0, 0x00, 0x20, 0x53, 0x49, 0x47, 0x49, +0x20, 0xb0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, +0x50, 0x04, 0x08, 0x9d, 0xf1, 0x38, 0xfe, 0x77, +0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, 0x2c, +0x52, 0x00, 0x19, 0x01, 0xcf, 0xd7, 0x43, 0x00, +0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, +0x04, 0x62, 0xd0, 0x00, 0x51, 0x2a, 0x21, 0xf0, +0x54, 0x00, 0x51, 0x2d, 0x54, 0x01, 0x3d, 0x00, +0x10, 0xb0, 0x2a, 0x55, 0xa7, 0x00, 0x3c, 0xab, +0x01, 0xb0, 0x09, 0x55, 0x91, 0x00, 0x55, 0x92, +0x00, 0x80, 0x0f, 0x62, 0xd0, 0x00, 0x3c, 0xae, +0x01, 0xa0, 0x07, 0x55, 0x91, 0x00, 0x55, 0x92, +0x00, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, +0x2a, 0x0f, 0x81, 0x6a, 0x3d, 0x00, 0x20, 0xb0, +0x18, 0x62, 0xd0, 0x00, 0x55, 0xa7, 0x01, 0x55, +0xa8, 0x00, 0x55, 0x91, 0x08, 0x55, 0x92, 0x08, +0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x81, 0x4e, +0x3d, 0x00, 0x40, 0xb0, 0x0f, 0x62, 0xd0, 0x00, +0x55, 0xb0, 0x02, 0x56, 0x00, 0x00, 0x26, 0x2a, +0x0f, 0x81, 0x3b, 0x3d, 0x00, 0x50, 0xb0, 0xa7, +0x52, 0x01, 0x54, 0x03, 0x56, 0x02, 0x00, 0x3d, +0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x01, 0xa0, +0x21, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, +0x02, 0xa0, 0x28, 0x3d, 0x02, 0x00, 0xb0, 0x06, +0x3d, 0x03, 0x04, 0xa0, 0x36, 0x3d, 0x02, 0x00, +0xb0, 0x06, 0x3d, 0x03, 0x08, 0xa0, 0x48, 0x80, +0x62, 0x62, 0xd0, 0x00, 0x55, 0xaa, 0x01, 0x51, +0x2f, 0x29, 0x80, 0x53, 0x2f, 0x7c, 0x0c, 0x5b, +0x80, 0x51, 0x62, 0xd0, 0x00, 0x51, 0x2b, 0x53, +0x4c, 0x51, 0x2b, 0x53, 0x4d, 0x51, 0x2b, 0x53, +0x2e, 0x51, 0x2c, 0x53, 0x0e, 0x55, 0x0d, 0x00, +0x80, 0x39, 0x62, 0xd0, 0x00, 0x51, 0x2b, 0x53, +0x2f, 0x3c, 0xaa, 0x00, 0xa0, 0x09, 0x51, 0x2f, +0x29, 0x80, 0x53, 0x2f, 0x80, 0x25, 0x62, 0xd0, +0x00, 0x26, 0x2f, 0x7f, 0x80, 0x1d, 0x62, 0xd0, +0x00, 0x55, 0xaa, 0x00, 0x26, 0x2f, 0x7f, 0x51, +0x9d, 0x53, 0x24, 0x51, 0x24, 0x53, 0x30, 0x51, +0x9e, 0x53, 0x25, 0x51, 0x25, 0x53, 0x31, 0x7c, +0x0c, 0x5b, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, +0x26, 0x2a, 0x0f, 0x55, 0x2b, 0x06, 0x55, 0x2c, +0x08, 0x55, 0x2d, 0x00, 0x80, 0x90, 0x3d, 0x00, +0x60, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, 0xab, +0x01, 0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x80, +0x7d, 0x3d, 0x00, 0x70, 0xb0, 0x0f, 0x62, 0xd0, +0x00, 0x55, 0xab, 0x00, 0x56, 0x00, 0x00, 0x26, +0x2a, 0x0f, 0x80, 0x6a, 0x3d, 0x00, 0x80, 0xb0, +0x65, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, +0x2a, 0x0f, 0x9c, 0xb2, 0x10, 0x7c, 0x08, 0xa8, +0x7c, 0x05, 0xcb, 0x20, 0x70, 0xfe, 0x71, 0x10, +0x41, 0x00, 0xf7, 0x41, 0x01, 0xf7, 0x70, 0xcf, +0x62, 0xda, 0x00, 0x71, 0x10, 0x41, 0xdc, 0xfe, +0x70, 0xcf, 0x43, 0x01, 0x08, 0x43, 0x00, 0x08, +0x50, 0x00, 0x08, 0x50, 0x1e, 0x08, 0x9c, 0x5e, +0x38, 0xfe, 0x71, 0x01, 0x43, 0xe0, 0x10, 0x43, +0xff, 0x08, 0x70, 0xfe, 0x40, 0x40, 0x40, 0x40, +0x40, 0x40, 0x40, 0x10, 0x7c, 0x07, 0xd7, 0x7c, +0x05, 0x7f, 0x7c, 0x05, 0xc0, 0x20, 0x93, 0x07, +0x40, 0x62, 0xe3, 0x38, 0x56, 0x00, 0x00, 0x62, +0xd0, 0x00, 0x26, 0x2a, 0x0f, 0x38, 0xfc, 0x20, +0x7f, 0x62, 0xd0, 0x00, 0x3c, 0xa7, 0x00, 0xa0, +0x13, 0x9c, 0x4b, 0x62, 0xd0, 0x00, 0x3c, 0xa8, +0x00, 0xb0, 0x33, 0x55, 0xa8, 0x01, 0x7c, 0x0a, +0xc9, 0x80, 0x2b, 0x62, 0xd0, 0x00, 0x50, 0x01, +0x3a, 0x91, 0xd0, 0x08, 0x10, 0x7c, 0x04, 0x7f, +0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0x7b, 0x20, +0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x92, 0xd0, +0x08, 0x10, 0x7c, 0x04, 0x5c, 0x20, 0x80, 0x06, +0x10, 0x7c, 0x04, 0x58, 0x20, 0x7f, 0x10, 0x4f, +0x38, 0x03, 0x56, 0x02, 0x00, 0x56, 0x01, 0x00, +0x56, 0x00, 0x00, 0x80, 0x3e, 0x62, 0xd0, 0x00, +0x91, 0x3a, 0x40, 0x52, 0xfc, 0x04, 0x48, 0x52, +0xfb, 0x0c, 0x49, 0x51, 0x49, 0x60, 0xd4, 0x3e, +0x48, 0x53, 0x49, 0x3e, 0x48, 0x53, 0x48, 0x52, +0x02, 0x12, 0x48, 0x52, 0x01, 0x1a, 0x49, 0xd0, +0x18, 0x91, 0x19, 0x40, 0x52, 0xfc, 0x04, 0x48, +0x52, 0xfb, 0x0c, 0x49, 0x51, 0x49, 0x60, 0xd4, +0x3e, 0x48, 0x54, 0x01, 0x3e, 0x48, 0x54, 0x02, +0x77, 0x00, 0x52, 0x00, 0x3b, 0xfa, 0xcf, 0xbe, +0x62, 0xd0, 0x00, 0x52, 0x02, 0x53, 0x48, 0x52, +0x01, 0x53, 0x49, 0x38, 0xfd, 0x20, 0x7f, 0x10, +0x7c, 0x04, 0x0a, 0x20, 0x10, 0x50, 0x04, 0x08, +0x50, 0x00, 0x08, 0x50, 0x99, 0x08, 0x7c, 0x04, +0x13, 0x38, 0xfd, 0x20, 0x10, 0x50, 0x04, 0x08, +0x50, 0x00, 0x08, 0x50, 0x7b, 0x08, 0x7c, 0x04, +0x13, 0x38, 0xfd, 0x20, 0x10, 0x50, 0x04, 0x08, +0x50, 0x00, 0x08, 0x50, 0x7f, 0x08, 0x7c, 0x04, +0x13, 0x38, 0xfd, 0x20, 0x10, 0x50, 0x00, 0x7c, +0x03, 0x2e, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, +0x2e, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x2e, +0x20, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0xaa, 0x00, +0x55, 0xab, 0x01, 0x10, 0x7c, 0x04, 0x7f, 0x7c, +0x04, 0x5c, 0x20, 0x9b, 0x51, 0x62, 0xe3, 0x38, +0x71, 0x10, 0x43, 0x00, 0x08, 0x41, 0x01, 0xf7, +0x70, 0xcf, 0x43, 0x00, 0x08, 0x62, 0xd0, 0x00, +0x55, 0x2a, 0x08, 0x55, 0x2b, 0x06, 0x55, 0x2c, +0x08, 0x55, 0x2e, 0x1e, 0x55, 0x2f, 0x05, 0x55, +0x30, 0x21, 0x55, 0x31, 0x1f, 0x55, 0x32, 0x00, +0x55, 0x33, 0x00, 0x3c, 0xaa, 0x00, 0xa0, 0x09, +0x51, 0x2f, 0x29, 0x80, 0x53, 0x2f, 0x80, 0x07, +0x62, 0xd0, 0x00, 0x26, 0x2f, 0x7f, 0x10, 0x50, +0x00, 0x08, 0x50, 0x2a, 0x08, 0x50, 0x06, 0x08, +0x50, 0x16, 0x08, 0x7c, 0x05, 0xd2, 0x38, 0xfc, +0x7c, 0x05, 0x7f, 0x7c, 0x05, 0xc0, 0x20, 0x91, +0x96, 0x40, 0x10, 0x7c, 0x07, 0xd7, 0x7c, 0x07, +0x5d, 0x20, 0x7c, 0x0c, 0x5b, 0x80, 0x22, 0x62, +0xe3, 0x38, 0x7c, 0x0f, 0x6b, 0x10, 0x7c, 0x07, +0x9b, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xa0, +0x09, 0x7c, 0x09, 0xf7, 0x7c, 0x0a, 0x21, 0x80, +0x04, 0x7c, 0x0a, 0x8a, 0x9c, 0xc7, 0x9e, 0x71, +0x8f, 0xde, 0x8f, 0xff, 0x52, 0x00, 0x53, 0x48, +0x55, 0x49, 0x00, 0x65, 0x48, 0x6b, 0x49, 0x7f, +0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x48, 0x55, +0x49, 0x00, 0x7f, 0x53, 0x46, 0x51, 0x49, 0x09, +0x00, 0x60, 0xd4, 0x3e, 0x46, 0x53, 0x47, 0x3e, +0x46, 0x53, 0x46, 0x7f, 0x52, 0x00, 0x53, 0x48, +0x55, 0x49, 0x00, 0x55, 0x46, 0x06, 0x55, 0x47, +0x00, 0x55, 0x41, 0x00, 0x55, 0x40, 0x00, 0x3c, +0x47, 0x00, 0xb0, 0x06, 0x3c, 0x46, 0x00, 0xa0, +0x1a, 0x70, 0xfb, 0x6e, 0x47, 0x6e, 0x46, 0xd0, +0x0c, 0x62, 0xd0, 0x00, 0x51, 0x48, 0x04, 0x41, +0x51, 0x49, 0x0c, 0x40, 0x65, 0x48, 0x6b, 0x49, +0x8f, 0xde, 0x5f, 0x48, 0x41, 0x5f, 0x49, 0x40, +0x62, 0xd0, 0x00, 0x5a, 0x46, 0x06, 0x46, 0x01, +0x51, 0x46, 0x04, 0x48, 0x0e, 0x49, 0x03, 0x7f, +0x55, 0x46, 0x06, 0x55, 0x47, 0x00, 0x55, 0x41, +0x00, 0x55, 0x40, 0x00, 0x3c, 0x47, 0x00, 0xb0, +0x06, 0x3c, 0x46, 0x00, 0xa0, 0x1a, 0x70, 0xfb, +0x6e, 0x47, 0x6e, 0x46, 0xd0, 0x0c, 0x62, 0xd0, +0x00, 0x51, 0x48, 0x04, 0x41, 0x51, 0x49, 0x0c, +0x40, 0x65, 0x48, 0x6b, 0x49, 0x8f, 0xde, 0x5f, +0x48, 0x41, 0x5f, 0x49, 0x40, 0x62, 0xd0, 0x00, +0x5a, 0x46, 0x06, 0x46, 0x01, 0x51, 0x46, 0x04, +0x48, 0x0e, 0x49, 0x03, 0x7f, 0x0e, 0x49, 0x00, +0x51, 0x49, 0x60, 0xd4, 0x3e, 0x48, 0x53, 0x49, +0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x46, 0x53, +0x47, 0x3e, 0x46, 0x7f, 0x60, 0xd4, 0x3e, 0x46, +0x53, 0x47, 0x3e, 0x46, 0x53, 0x46, 0x7f, 0x51, +0x49, 0x60, 0xd5, 0x51, 0x47, 0x3f, 0x48, 0x51, +0x46, 0x3f, 0x48, 0x7f, 0x60, 0xd4, 0x3e, 0x48, +0x53, 0x49, 0x3e, 0x48, 0x53, 0x48, 0x7f, 0x51, +0x48, 0x01, 0x99, 0x53, 0x46, 0x51, 0x49, 0x09, +0x00, 0x7f, 0x06, 0x48, 0x99, 0x0e, 0x49, 0x00, +0x51, 0x49, 0x60, 0xd4, 0x3e, 0x48, 0x53, 0x47, +0x3e, 0x48, 0x16, 0x48, 0x02, 0x53, 0x46, 0x7f, +0x53, 0x46, 0x51, 0x49, 0x09, 0x00, 0x60, 0xd5, +0x52, 0x14, 0x3f, 0x46, 0x52, 0x15, 0x3f, 0x46, +0x7f, 0x3e, 0x48, 0x53, 0x48, 0x51, 0x46, 0x12, +0x48, 0x51, 0x47, 0x1a, 0x49, 0x7f, 0x53, 0x48, +0x52, 0xfb, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x48, +0x7f, 0x60, 0xd4, 0x3e, 0x48, 0x54, 0x00, 0x3e, +0x48, 0x54, 0x01, 0x7f, 0x0e, 0x49, 0x00, 0x51, +0x49, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x48, 0x52, +0x15, 0x3f, 0x48, 0x7f, 0x60, 0xd5, 0x52, 0x14, +0x3f, 0x46, 0x52, 0x15, 0x3f, 0x46, 0x7f, 0x71, +0x10, 0x41, 0x04, 0xfe, 0x41, 0x05, 0xfe, 0x41, +0x04, 0xfd, 0x41, 0x05, 0xfd, 0x70, 0xcf, 0x43, +0x04, 0x01, 0x43, 0x04, 0x02, 0x71, 0x01, 0x7f, +0x52, 0x00, 0x53, 0x46, 0x55, 0x47, 0x00, 0x65, +0x46, 0x6b, 0x47, 0x7f, 0x0e, 0x47, 0x00, 0x51, +0x47, 0x60, 0xd5, 0x51, 0x49, 0x3f, 0x46, 0x7f, +0x70, 0xfb, 0x6e, 0x49, 0x6e, 0x48, 0x51, 0x47, +0x60, 0xd5, 0x51, 0x49, 0x3f, 0x46, 0x51, 0x48, +0x3f, 0x46, 0x7f, 0x0e, 0x49, 0x00, 0x51, 0x49, +0x60, 0xd5, 0x50, 0x00, 0x3f, 0x48, 0x7f, 0x53, +0x46, 0x55, 0x47, 0x00, 0x65, 0x46, 0x6b, 0x47, +0x51, 0x46, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, +0x44, 0x53, 0x45, 0x3e, 0x44, 0x53, 0x44, 0x7f, +0x3e, 0x48, 0x12, 0x46, 0x54, 0x02, 0x51, 0x49, +0x1a, 0x47, 0x54, 0x01, 0x7f, 0x3e, 0x48, 0x12, +0x46, 0x54, 0x04, 0x51, 0x49, 0x1a, 0x47, 0x54, +0x03, 0x7f, 0x60, 0xd4, 0x3e, 0x46, 0x53, 0x45, +0x3e, 0x46, 0x16, 0x46, 0x02, 0x7f, 0x00, 0x2a, +0x00, 0x16, 0x00, 0x53, 0x00, 0x28, 0x00, 0x83, +0x00, 0x0e, 0x00, 0x91, 0x04, 0x08, 0x08, 0x08, +0x08, 0x00, 0x95, 0x00, 0x04, 0x00, 0x9d, 0x02, +0x21, 0x1f, 0x00, 0x9f, 0x00, 0x08, 0x00, 0xa7, +0x06, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, +0xad, 0x00, 0x05, 0x00, 0xb2, 0x01, 0x03, 0xff, +0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/gpio_keys_sec.c b/drivers/input/keyboard/gpio_keys_sec.c new file mode 100644 index 00000000000..4035b857f48 --- /dev/null +++ b/drivers/input/keyboard/gpio_keys_sec.c @@ -0,0 +1,810 @@ +/* + * Driver for keys on GPIO lines capable of generating interrupts. + * + * Copyright 2005 Phil Blundell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SEC_DEBUG +#include +#endif + +struct gpio_button_data { + struct gpio_keys_button *button; + struct input_dev *input; + struct timer_list timer; + struct work_struct work; + int timer_debounce; /* in msecs */ + bool disabled; +}; + +struct gpio_keys_drvdata { + struct input_dev *input; + struct mutex disable_lock; + unsigned int n_buttons; + int (*enable)(struct device *dev); + void (*disable)(struct device *dev); + struct gpio_button_data data[0]; +}; + +static int button_pressed ; + +/* + * SYSFS interface for enabling/disabling keys and switches: + * + * There are 4 attributes under /sys/devices/platform/gpio-keys/ + * keys [ro] - bitmap of keys (EV_KEY) which can be + * disabled + * switches [ro] - bitmap of switches (EV_SW) which can be + * disabled + * disabled_keys [rw] - bitmap of keys currently disabled + * disabled_switches [rw] - bitmap of switches currently disabled + * + * Userland can change these values and hence disable event generation + * for each key (or switch). Disabling a key means its interrupt line + * is disabled. + * + * For example, if we have following switches set up as gpio-keys: + * SW_DOCK = 5 + * SW_CAMERA_LENS_COVER = 9 + * SW_KEYPAD_SLIDE = 10 + * SW_FRONT_PROXIMITY = 11 + * This is read from switches: + * 11-9,5 + * Next we want to disable proximity (11) and dock (5), we write: + * 11,5 + * to file disabled_switches. Now proximity and dock IRQs are disabled. + * This can be verified by reading the file disabled_switches: + * 11,5 + * If we now want to enable proximity (11) switch we write: + * 5 + * to disabled_switches. + * + * We can disable only those keys which don't allow sharing the irq. + */ + +/** + * get_n_events_by_type() - returns maximum number of events per @type + * @type: type of button (%EV_KEY, %EV_SW) + * + * Return value of this function can be used to allocate bitmap + * large enough to hold all bits for given type. + */ +static inline int get_n_events_by_type(int type) +{ + BUG_ON(type != EV_SW && type != EV_KEY); + + return (type == EV_KEY) ? KEY_CNT : SW_CNT; +} + +/** + * gpio_keys_disable_button() - disables given GPIO button + * @bdata: button data for button to be disabled + * + * Disables button pointed by @bdata. This is done by masking + * IRQ line. After this function is called, button won't generate + * input events anymore. Note that one can only disable buttons + * that don't share IRQs. + * + * Make sure that @bdata->disable_lock is locked when entering + * this function to avoid races when concurrent threads are + * disabling buttons at the same time. + */ +static void gpio_keys_disable_button(struct gpio_button_data *bdata) +{ + if (!bdata->disabled) { + /* + * Disable IRQ and possible debouncing timer. + */ + disable_irq(gpio_to_irq(bdata->button->gpio)); + if (bdata->timer_debounce) + del_timer_sync(&bdata->timer); + + bdata->disabled = true; + } +} + +/** + * gpio_keys_enable_button() - enables given GPIO button + * @bdata: button data for button to be disabled + * + * Enables given button pointed by @bdata. + * + * Make sure that @bdata->disable_lock is locked when entering + * this function to avoid races with concurrent threads trying + * to enable the same button at the same time. + */ +static void gpio_keys_enable_button(struct gpio_button_data *bdata) +{ + if (bdata->disabled) { + enable_irq(gpio_to_irq(bdata->button->gpio)); + bdata->disabled = false; + } +} + +/** + * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons + * @ddata: pointer to drvdata + * @buf: buffer where stringified bitmap is written + * @type: button type (%EV_KEY, %EV_SW) + * @only_disabled: does caller want only those buttons that are + * currently disabled or all buttons that can be + * disabled + * + * This function writes buttons that can be disabled to @buf. If + * @only_disabled is true, then @buf contains only those buttons + * that are currently disabled. Returns 0 on success or negative + * errno on failure. + */ +static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata, + char *buf, unsigned int type, + bool only_disabled) +{ + int n_events = get_n_events_by_type(type); + unsigned long *bits; + ssize_t ret; + int i; + + bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL); + if (!bits) + return -ENOMEM; + + for (i = 0; i < ddata->n_buttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + + if (bdata->button->type != type) + continue; + + if (only_disabled && !bdata->disabled) + continue; + + __set_bit(bdata->button->code, bits); + } + + ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events); + buf[ret++] = '\n'; + buf[ret] = '\0'; + + kfree(bits); + + return ret; +} + +/** + * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap + * @ddata: pointer to drvdata + * @buf: buffer from userspace that contains stringified bitmap + * @type: button type (%EV_KEY, %EV_SW) + * + * This function parses stringified bitmap from @buf and disables/enables + * GPIO buttons accordinly. Returns 0 on success and negative error + * on failure. + */ +static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, + const char *buf, unsigned int type) +{ + int n_events = get_n_events_by_type(type); + unsigned long *bits; + ssize_t error; + int i; + + bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL); + if (!bits) + return -ENOMEM; + + error = bitmap_parselist(buf, bits, n_events); + if (error) + goto out; + + /* First validate */ + for (i = 0; i < ddata->n_buttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + + if (bdata->button->type != type) + continue; + + if (test_bit(bdata->button->code, bits) && + !bdata->button->can_disable) { + error = -EINVAL; + goto out; + } + } + + mutex_lock(&ddata->disable_lock); + + for (i = 0; i < ddata->n_buttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + + if (bdata->button->type != type) + continue; + + if (test_bit(bdata->button->code, bits)) + gpio_keys_disable_button(bdata); + else + gpio_keys_enable_button(bdata); + } + + mutex_unlock(&ddata->disable_lock); + +out: + kfree(bits); + return error; +} + +#define ATTR_SHOW_FN(name, type, only_disabled) \ +static ssize_t gpio_keys_show_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct platform_device *pdev = to_platform_device(dev); \ + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \ + \ + return gpio_keys_attr_show_helper(ddata, buf, \ + type, only_disabled); \ +} + +ATTR_SHOW_FN(keys, EV_KEY, false); +ATTR_SHOW_FN(switches, EV_SW, false); +ATTR_SHOW_FN(disabled_keys, EV_KEY, true); +ATTR_SHOW_FN(disabled_switches, EV_SW, true); + +/* + * ATTRIBUTES: + * + * /sys/devices/platform/gpio-keys/keys [ro] + * /sys/devices/platform/gpio-keys/switches [ro] + */ +static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL); +static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL); + +#define ATTR_STORE_FN(name, type) \ +static ssize_t gpio_keys_store_##name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, \ + size_t count) \ +{ \ + struct platform_device *pdev = to_platform_device(dev); \ + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \ + ssize_t error; \ + \ + error = gpio_keys_attr_store_helper(ddata, buf, type); \ + if (error) \ + return error; \ + \ + return count; \ +} + +ATTR_STORE_FN(disabled_keys, EV_KEY); +ATTR_STORE_FN(disabled_switches, EV_SW); + +/* + * ATTRIBUTES: + * + * /sys/devices/platform/gpio-keys/disabled_keys [rw] + * /sys/devices/platform/gpio-keys/disables_switches [rw] + */ +static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO, + gpio_keys_show_disabled_keys, + gpio_keys_store_disabled_keys); +static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO, + gpio_keys_show_disabled_switches, + gpio_keys_store_disabled_switches); + +static struct attribute *gpio_keys_attrs[] = { + &dev_attr_keys.attr, + &dev_attr_switches.attr, + &dev_attr_disabled_keys.attr, + &dev_attr_disabled_switches.attr, + NULL, +}; + +static struct attribute_group gpio_keys_attr_group = { + .attrs = gpio_keys_attrs, +}; + +static void gpio_keys_report_event(struct gpio_button_data *bdata) +{ + struct gpio_keys_button *button = bdata->button; + struct input_dev *input = bdata->input; + unsigned int type = button->type ?: EV_KEY; + int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ + button->active_low; + static int count; + +#ifdef CONFIG_SEC_DEBUG + sec_debug_check_crash_key(button->code, state); +#endif + + if (type == EV_ABS) { + if (state) + input_event(input, type, button->code, button->value); + } else { + if (button->code == KEY_HOMEPAGE && count == 1) { + if (!!state) { + input_event(input, type, button->code, + !!state); + button_pressed = 1; + } else { + if (button_pressed == 0) { + button_pressed = 1; + /*send home key press event to + input subsytem if release event + detected before press event */ + input_event(input, type, + button->code, 1); + } + /*send home key release event to input + subsystem */ + input_event(input, type, + button->code, 0); + } + } else { + input_event(input, type, button->code, !!state); + if (button->code == KEY_HOMEPAGE) + count = 1; + } + } + input_sync(input); +} + +static void gpio_keys_work_func(struct work_struct *work) +{ + struct gpio_button_data *bdata = + container_of(work, struct gpio_button_data, work); + + gpio_keys_report_event(bdata); +} + +static void gpio_keys_timer(unsigned long _data) +{ + struct gpio_button_data *data = (struct gpio_button_data *)_data; + + schedule_work(&data->work); +} + +static irqreturn_t gpio_keys_isr(int irq, void *dev_id) +{ + struct gpio_button_data *bdata = dev_id; + struct gpio_keys_button *button = bdata->button; + + BUG_ON(irq != gpio_to_irq(button->gpio)); + + if (bdata->timer_debounce) + mod_timer(&bdata->timer, + jiffies + msecs_to_jiffies(bdata->timer_debounce)); + else + schedule_work(&bdata->work); + + return IRQ_HANDLED; +} + +static int __devinit gpio_keys_setup_key(struct platform_device *pdev, + struct gpio_button_data *bdata, + struct gpio_keys_button *button) +{ + const char *desc = button->desc ? button->desc : "gpio_keys"; + struct device *dev = &pdev->dev; + unsigned long irqflags; + int irq, error; + + setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata); + INIT_WORK(&bdata->work, gpio_keys_work_func); + + error = gpio_request(button->gpio, desc); + if (error < 0) { + dev_err(dev, "failed to request GPIO %d, error %d\n", + button->gpio, error); + goto fail2; + } + + error = gpio_direction_input(button->gpio); + if (error < 0) { + dev_err(dev, "failed to configure" + " direction for GPIO %d, error %d\n", + button->gpio, error); + goto fail3; + } + + if (button->debounce_interval) { + error = gpio_set_debounce(button->gpio, + button->debounce_interval * 1000); + /* use timer if gpiolib doesn't provide debounce */ + if (error < 0) + bdata->timer_debounce = button->debounce_interval; + } + + irq = gpio_to_irq(button->gpio); + if (irq < 0) { + error = irq; + dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n", + button->gpio, error); + goto fail3; + } + + irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + /* + * If platform has specified that the button can be disabled, + * we don't want it to share the interrupt line. + */ + if (!button->can_disable) + irqflags |= IRQF_SHARED; + + error = request_any_context_irq(irq, gpio_keys_isr, irqflags, + desc, bdata); + if (error < 0) { + dev_err(dev, "Unable to claim irq %d; error %d\n", + irq, error); + goto fail3; + } + + return 0; + +fail3: + gpio_free(button->gpio); +fail2: + return error; +} + +static int gpio_keys_open(struct input_dev *input) +{ + struct gpio_keys_drvdata *ddata = input_get_drvdata(input); + + return ddata->enable ? ddata->enable(input->dev.parent) : 0; +} + +static void gpio_keys_close(struct input_dev *input) +{ + struct gpio_keys_drvdata *ddata = input_get_drvdata(input); + + if (ddata->disable) + ddata->disable(input->dev.parent); +} + +static ssize_t sysfs_key_onoff_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + struct gpio_button_data *button; + int index ; + int state = 0; + for (index = 0; index < ddata->n_buttons; index++) { + button = &ddata->data[index]; +#if defined(CONFIG_MACH_AEGIS2) || defined(CONFIG_MACH_APEXQ) + if (button->button->code == SW_LID) + continue; +#endif + state = (gpio_get_value_cansleep(button->button->gpio) ? 1 : 0)\ + ^ button->button->active_low; + if (state == 1) + break; + } + pr_info("key state:%d\n", state); + return snprintf(buf, 5, "%d\n", state); +} + +#if defined(CONFIG_MACH_AEGIS2) || defined(CONFIG_MACH_APEXQ) +static ssize_t sysfs_qwerty_flip_onoff_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); + int i; + for (i = 0; i < ddata->n_buttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + struct gpio_keys_button *button = bdata->button; + if (button->code != SW_LID) + continue; + return sprintf(buf, "%d\n", gpio_get_value_cansleep(button->gpio)); + } + return sprintf(buf, "%d\n", -1); +} +#endif + +static DEVICE_ATTR(sec_key_pressed, 0664 , sysfs_key_onoff_show, NULL); + +/* the volume keys can be the wakeup keys in special case */ +static ssize_t wakeup_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + int n_events = get_n_events_by_type(EV_KEY); + unsigned long *bits; + ssize_t error; + int i; + + bits = kcalloc(BITS_TO_LONGS(n_events), + sizeof(*bits), GFP_KERNEL); + if (!bits) + return -ENOMEM; + + error = bitmap_parselist(buf, bits, n_events); + if (error) + goto out; + + for (i = 0; i < ddata->n_buttons; i++) { + struct gpio_button_data *button = &ddata->data[i]; + if (button->button->type == EV_KEY) { + if (test_bit(button->button->code, bits)) + button->button->wakeup = 1; + else + button->button->wakeup = 0; + pr_info("%s wakeup status %d\n", button->button->desc,\ + button->button->wakeup); + } + } + +out: + kfree(bits); + return count; +} + +static DEVICE_ATTR(wakeup_keys, 0664, NULL, wakeup_enable); + + +#if defined(CONFIG_MACH_AEGIS2) || defined(CONFIG_MACH_APEXQ) +static DEVICE_ATTR(sec_qwerty_flip_pressed, 0444, sysfs_qwerty_flip_onoff_show, +NULL); +#endif + +static int __devinit gpio_keys_probe(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct gpio_keys_drvdata *ddata; + struct device *dev = &pdev->dev; + struct input_dev *input; + int i, error; + int wakeup = 0; + struct device *sec_key; + #if defined(CONFIG_MACH_AEGIS2) || defined(CONFIG_MACH_APEXQ) + struct device *sec_qwerty_flip ; + #endif + int ret; + ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + + pdata->nbuttons * sizeof(struct gpio_button_data), + GFP_KERNEL); + input = input_allocate_device(); + if (!ddata || !input) { + dev_err(dev, "failed to allocate state\n"); + error = -ENOMEM; + goto fail1; + } + + ddata->input = input; + ddata->n_buttons = pdata->nbuttons; + ddata->enable = pdata->enable; + ddata->disable = pdata->disable; + mutex_init(&ddata->disable_lock); + + platform_set_drvdata(pdev, ddata); + input_set_drvdata(input, ddata); + + input->name = "sec_keys"; + input->phys = "gpio-keys/input0"; + input->dev.parent = &pdev->dev; + input->open = gpio_keys_open; + input->close = gpio_keys_close; + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + /* Enable auto repeat feature of Linux input subsystem */ + if (pdata->rep) + __set_bit(EV_REP, input->evbit); + + /* Enable keyled for gpio keys */ + if (pdata->keyled) { + __set_bit(EV_LED, input->evbit); + __set_bit(LED_MISC, input->ledbit); + } + + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + struct gpio_button_data *bdata = &ddata->data[i]; + unsigned int type = button->type ?: EV_KEY; + + bdata->input = input; + bdata->button = button; + + error = gpio_keys_setup_key(pdev, bdata, button); + if (error) + goto fail2; + + if (button->wakeup) + wakeup = 1; + + input_set_capability(input, type, button->code); + } + + error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group); + if (error) { + dev_err(dev, "Unable to export keys/switches, error: %d\n", + error); + goto fail2; + } + + error = input_register_device(input); + if (error) { + dev_err(dev, "Unable to register input device, error: %d\n", + error); + goto fail3; + } + + /* get current state of buttons */ + for (i = 0; i < pdata->nbuttons; i++) + gpio_keys_report_event(&ddata->data[i]); + input_sync(input); + + sec_key = device_create(sec_class, NULL, 0, NULL, "sec_key"); + if (IS_ERR(sec_key)) + pr_err("Failed to create device(sec_key)!\n"); + + ret = device_create_file(sec_key, &dev_attr_sec_key_pressed); + if (ret) { + pr_err("Failed to create device file in sysfs entries(%s)!\n", + dev_attr_sec_key_pressed.attr.name); + } + + #if defined(CONFIG_MACH_AEGIS2) || defined(CONFIG_MACH_APEXQ) + sec_qwerty_flip = device_create(sec_class, NULL, 0, NULL, + "sec_qwerty_flip"); + if (IS_ERR(sec_qwerty_flip)) + pr_err("Failed to create device(sec_qwerty_flip)!\n"); + + ret = device_create_file(sec_qwerty_flip, + &dev_attr_sec_qwerty_flip_pressed); + if (ret) { + pr_err("Failed to create device file in sysfs entries(%s)!\n", + dev_attr_sec_qwerty_flip_pressed.attr.name); + } + #endif + ret = device_create_file(sec_key, &dev_attr_wakeup_keys); + if (ret < 0) { + pr_err("Failed to create device file(%s), error: %d\n", + dev_attr_wakeup_keys.attr.name, ret); + } + + dev_set_drvdata(sec_key, ddata); + #if defined(CONFIG_MACH_AEGIS2) || defined(CONFIG_MACH_APEXQ) + dev_set_drvdata(sec_qwerty_flip, ddata); + #endif + device_init_wakeup(&pdev->dev, 1); + + return 0; + + fail3: + sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); + fail2: + while (--i >= 0) { + free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); + if (ddata->data[i].timer_debounce) + del_timer_sync(&ddata->data[i].timer); + cancel_work_sync(&ddata->data[i].work); + gpio_free(pdata->buttons[i].gpio); + } + + platform_set_drvdata(pdev, NULL); + fail1: + input_free_device(input); + kfree(ddata); + + return error; +} + +static int __devexit gpio_keys_remove(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); + struct input_dev *input = ddata->input; + int i; + + sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); + + device_init_wakeup(&pdev->dev, 0); + + for (i = 0; i < pdata->nbuttons; i++) { + int irq = gpio_to_irq(pdata->buttons[i].gpio); + free_irq(irq, &ddata->data[i]); + if (ddata->data[i].timer_debounce) + del_timer_sync(&ddata->data[i].timer); + cancel_work_sync(&ddata->data[i].work); + gpio_free(pdata->buttons[i].gpio); + } + + input_unregister_device(input); + + return 0; +} + + +#ifdef CONFIG_PM +static int gpio_keys_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + int i; + if (device_may_wakeup(&pdev->dev)) { + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + if (button->wakeup) { + int irq = gpio_to_irq(button->gpio); + enable_irq_wake(irq); + } + } + } + return 0; +} + +static int gpio_keys_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + int i; + + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + if (button->wakeup && device_may_wakeup(&pdev->dev)) { + int irq = gpio_to_irq(button->gpio); + disable_irq_wake(irq); + } + } + return 0; +} + +static const struct dev_pm_ops gpio_keys_pm_ops = { + .suspend = gpio_keys_suspend, + .resume = gpio_keys_resume, +}; +#endif + +static struct platform_driver gpio_keys_device_driver = { + .probe = gpio_keys_probe, + .remove = __devexit_p(gpio_keys_remove), + .driver = { + .name = "sec_keys", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &gpio_keys_pm_ops, +#endif + } +}; + +static int __init gpio_keys_init(void) +{ + return platform_driver_register(&gpio_keys_device_driver); +} + +static void __exit gpio_keys_exit(void) +{ + platform_driver_unregister(&gpio_keys_device_driver); +} + +module_init(gpio_keys_init); +module_exit(gpio_keys_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Phil Blundell "); +MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); +MODULE_ALIAS("platform:gpio-keys"); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index f6c647ca350..a18036f9fa0 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -73,6 +73,16 @@ config INPUT_BMA150 To compile this driver as a module, choose M here: the module will be called bma150. +config INPUT_BMP180 + depends on I2C && SYSFS + tristate "BMP180 digital pressure sensor" + help + If you say yes here you get support for the Bosch Sensortec + BMP180 digital pressure sensor. + + To compile this driver as a module, choose M here: the + module will be called bmp180. + config INPUT_PCSPKR tristate "PC Speaker support" depends on PCSPKR_PLATFORM diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 97d97825f56..42b7dc2c7f4 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o obj-$(CONFIG_INPUT_BMA150) += bma150.o +obj-$(CONFIG_INPUT_BMP180) += bmp180.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o diff --git a/drivers/input/misc/bmp180.c b/drivers/input/misc/bmp180.c new file mode 100644 index 00000000000..adf025da18a --- /dev/null +++ b/drivers/input/misc/bmp180.c @@ -0,0 +1,841 @@ +/* + * Copyright (C) 2011 Samsung Electronics. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 + +#define BMP180_DRV_NAME "bmp180" +#define DRIVER_VERSION "1.0" + +#define BMP_VENDOR "BOCH" +#define BMP_PART_ID "BMP180" + +#define CALIBRATION_FILE_PATH "/efs/FactoryApp/baro_delta" + +struct bmp180_eeprom_data { + s16 AC1, AC2, AC3; + u16 AC4, AC5, AC6; + s16 B1, B2; + s16 MB, MC, MD; +}; + +struct bmp180_data { + struct i2c_client *client; + struct mutex lock; + struct workqueue_struct *wq; + struct work_struct work_pressure; + struct input_dev *input_dev; + struct hrtimer timer; +#ifdef FACTORY_TEST + struct class *class; + struct device *dev; + s32 cal_data; +#endif + ktime_t poll_delay; + u8 oversampling_rate; + struct bmp180_eeprom_data bmp180_eeprom_vals; + bool enabled; + bool on_before_suspend; + void (*power_on) (int); +}; + +static int bmp180_i2c_read(struct i2c_client *client, u8 cmd, + u8 *buf, int len) +{ + int err; + int tries = 0; + + do { + err = i2c_smbus_read_i2c_block_data(client, cmd, len, buf); + if (err == len) + return 0; + } while (++tries < I2C_TRIES); + + return err; +} + +static int bmp180_i2c_write(struct i2c_client *client, u8 cmd, u8 data) +{ + int err; + int tries = 0; + + do { + err = i2c_smbus_write_byte_data(client, cmd, data); + if (!err) + return 0; + } while (++tries < I2C_TRIES); + + return err; +} + +static void bmp180_enable(struct bmp180_data *barom) +{ + pr_debug("%s: bmp180_enable\n", __func__); + mutex_lock(&barom->lock); + if (!barom->enabled) { + barom->enabled = true; + pr_debug("%s: start timer\n", __func__); + + hrtimer_start(&barom->timer, barom->poll_delay, + HRTIMER_MODE_REL); + } + mutex_unlock(&barom->lock); +} + +static void bmp180_disable(struct bmp180_data *barom) +{ + mutex_lock(&barom->lock); + if (barom->enabled) { + barom->enabled = false; + pr_debug("%s: stop timer\n", __func__); + hrtimer_cancel(&barom->timer); + cancel_work_sync(&barom->work_pressure); + } + mutex_unlock(&barom->lock); +} + +static int bmp180_get_raw_temperature(struct bmp180_data *barom, + u16 *raw_temperature) +{ + int err; + u16 buf; + + pr_debug("%s: read uncompensated temperature value\n", __func__); + err = bmp180_i2c_write(barom->client, BMP180_TAKE_MEAS_REG, + BMP180_MEAS_TEMP); + if (err) { + pr_err("%s: can't write BMP180_TAKE_MEAS_REG\n", __func__); + + return err; + } + + usleep(5000); + + err = bmp180_i2c_read(barom->client, BMP180_READ_MEAS_REG_U, + (u8 *)&buf, 2); + if (err) { + pr_err("%s: Fail to read uncompensated temperature\n", + __func__); + + return err; + } + *raw_temperature = be16_to_cpu(buf); + pr_debug("%s: uncompensated temperature: %d\n", + __func__, *raw_temperature); + + return err; +} + +static int bmp180_get_raw_pressure(struct bmp180_data *barom, + u32 *raw_pressure) +{ + int err; + u32 buf = 0; + + pr_debug("%s: read uncompensated pressure value\n", __func__); + + err = bmp180_i2c_write(barom->client, BMP180_TAKE_MEAS_REG, + BMP180_MEAS_PRESS_OVERSAMP_0 | + (barom->oversampling_rate << 6)); + if (err) { + pr_err("%s: can't write BMP180_TAKE_MEAS_REG\n", __func__); + + return err; + } + + msleep(2+(3 << barom->oversampling_rate)); + + err = bmp180_i2c_read(barom->client, BMP180_READ_MEAS_REG_U, + ((u8 *)&buf)+1, 3); + if (err) { + pr_err("%s: Fail to read uncompensated pressure\n", __func__); + + return err; + } + + *raw_pressure = be32_to_cpu(buf); + *raw_pressure >>= (8 - barom->oversampling_rate); + pr_debug("%s: uncompensated pressure: %d\n", + __func__, *raw_pressure); + + return err; +} + +static int bmp180_get_pressure_data_body(struct bmp180_data *barom) +{ + u16 raw_temperature; + u32 raw_pressure; + long x1, x2, x3, b3, b5, b6; + unsigned long b4, b7; + long p; + int pressure; + int temperature = 0; + + if (bmp180_get_raw_temperature(barom, &raw_temperature)) { + pr_err("%s: can't read uncompensated temperature\n", __func__); + return -1; + } + +#ifdef FACTORY_TEST + x1 = ((raw_temperature - barom->bmp180_eeprom_vals.AC6) + * barom->bmp180_eeprom_vals.AC5) >> 15; + x2 = (barom->bmp180_eeprom_vals.MC << 11) + / (x1 + barom->bmp180_eeprom_vals.MD); + temperature = (x1 + x2 + 8) >> 4; + + if (temperature == 0) { + pr_info("%s, temperature = 0\n", __func__); + temperature = -1; + } + input_report_rel(barom->input_dev, REL_Z, temperature); + input_sync(barom->input_dev); +#endif + + if (bmp180_get_raw_pressure(barom, &raw_pressure)) { + pr_err("%s: Fail to read uncompensated pressure\n", + __func__); + + return -1; + } + + x1 = ((raw_temperature - barom->bmp180_eeprom_vals.AC6) * + barom->bmp180_eeprom_vals.AC5) >> 15; + x2 = (barom->bmp180_eeprom_vals.MC << 11) / + (x1 + barom->bmp180_eeprom_vals.MD); + b5 = x1 + x2; + + b6 = (b5 - 4000); + x1 = (barom->bmp180_eeprom_vals.B2 * ((b6 * b6) >> 12)) >> 11; + x2 = (barom->bmp180_eeprom_vals.AC2 * b6) >> 11; + x3 = x1 + x2; + b3 = (((((long)barom->bmp180_eeprom_vals.AC1) * 4 + + x3) << barom->oversampling_rate) + 2) >> 2; + x1 = (barom->bmp180_eeprom_vals.AC3 * b6) >> 13; + x2 = (barom->bmp180_eeprom_vals.B1 * (b6 * b6 >> 12)) >> 16; + x3 = ((x1 + x2) + 2) >> 2; + b4 = (barom->bmp180_eeprom_vals.AC4 * + (unsigned long)(x3 + 32768)) >> 15; + b7 = ((unsigned long)raw_pressure - b3) * + (50000 >> barom->oversampling_rate); + if (b7 < 0x80000000) + p = (b7 * 2) / b4; + else + p = (b7 / b4) * 2; + + x1 = (p >> 8) * (p >> 8); + x1 = (x1 * 3038) >> 16; + x2 = (-7357 * p) >> 16; + pressure = p + ((x1 + x2 + 3791) >> 4); + pr_debug("%s: calibrated pressure: %d\n", + __func__, pressure); + + return pressure; +} + +static void bmp180_get_pressure_data(struct work_struct *work) +{ + struct bmp180_data *barom = + container_of(work, struct bmp180_data, work_pressure); + + int pressure = bmp180_get_pressure_data_body(barom); + + pressure -= barom->cal_data; + if (pressure == 0) { + pr_info("%s, temperature = 0\n", __func__); + pressure = -1; + } + input_report_rel(barom->input_dev, REL_X, pressure); + input_sync(barom->input_dev); + + return; +} + + +#ifdef FACTORY_TEST +static int bmp180_open_calibration(struct bmp180_data *barom) +{ + struct file *cal_filp = NULL; + int err = 0; + mm_segment_t old_fs; + char read_data[10] = {0,}; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("%s: Can't open calibration file\n", __func__); + set_fs(old_fs); + err = PTR_ERR(cal_filp); + return err; + } + + err = cal_filp->f_op->read(cal_filp, + read_data, sizeof(char)*10, &cal_filp->f_pos); + if (err <= 0) { + pr_err("%s: Can't read the cal data from file\n", __func__); + err = -EIO; + } + + err = kstrtoint(read_data, 10, &barom->cal_data); + if (err < 0) { + pr_err("error strtoint %s\n", __func__); + err = -EIO; + } + pr_debug("%s: offset (%d)\n", __func__, + barom->cal_data); + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return err; +} + +static int bmp180_do_calibrate(struct device *dev, bool do_calib, + int pressure_from_outside) +{ + struct bmp180_data *barom = dev_get_drvdata(dev); + int err = 0; + + if (do_calib) + barom->cal_data = pressure_from_outside; + else + barom->cal_data = 0; + + printk(KERN_INFO "%s: cal data (%d)\n", __func__, barom->cal_data); + + return err; +} +#endif + +static int bmp180_input_init(struct bmp180_data *barom) +{ + int err; + + pr_debug("%s: enter\n", __func__); + + barom->input_dev = input_allocate_device(); + if (!barom->input_dev) { + pr_err("%s: could not allocate input device\n", __func__); + + return -ENOMEM; + } + input_set_drvdata(barom->input_dev, barom); + barom->input_dev->name = "barometer_sensor"; + + /* pressure */ + input_set_capability(barom->input_dev, EV_REL, REL_X); + +#ifdef FACTORY_TEST + + /* reference altitude */ + input_set_capability(barom->input_dev, EV_REL, REL_Y); + + /* temperature */ + input_set_capability(barom->input_dev, EV_REL, REL_Z); + +#endif + + pr_debug("%s: registering barometer input device\n", __func__); + + err = input_register_device(barom->input_dev); + if (err) { + pr_err("%s: unable to register input polled device %s\n", + __func__, barom->input_dev->name); + + goto err_register_device; + } + + goto done; + +err_register_device: + input_free_device(barom->input_dev); +done: + return err; +} + +static void bmp180_input_cleanup(struct bmp180_data *barom) +{ + input_unregister_device(barom->input_dev); + input_free_device(barom->input_dev); +} + +static int bmp180_read_store_eeprom_val(struct bmp180_data *barom) +{ + int err; + u16 buf[11]; + + err = bmp180_i2c_read(barom->client, BMP180_EEPROM_AC1_U, + (u8 *)buf, 22); + if (err) { + pr_err("%s: Cannot read EEPROM values\n", __func__); + return err; + } + barom->bmp180_eeprom_vals.AC1 = be16_to_cpu(buf[0]); + barom->bmp180_eeprom_vals.AC2 = be16_to_cpu(buf[1]); + barom->bmp180_eeprom_vals.AC3 = be16_to_cpu(buf[2]); + barom->bmp180_eeprom_vals.AC4 = be16_to_cpu(buf[3]); + barom->bmp180_eeprom_vals.AC5 = be16_to_cpu(buf[4]); + barom->bmp180_eeprom_vals.AC6 = be16_to_cpu(buf[5]); + barom->bmp180_eeprom_vals.B1 = be16_to_cpu(buf[6]); + barom->bmp180_eeprom_vals.B2 = be16_to_cpu(buf[7]); + barom->bmp180_eeprom_vals.MB = be16_to_cpu(buf[8]); + barom->bmp180_eeprom_vals.MC = be16_to_cpu(buf[9]); + barom->bmp180_eeprom_vals.MD = be16_to_cpu(buf[10]); + + return 0; +} + +static enum hrtimer_restart bmp180_timer_func(struct hrtimer *timer) +{ + struct bmp180_data *barom = container_of(timer, + struct bmp180_data, timer); + + pr_debug("%s: start\n", __func__); + + queue_work(barom->wq, &barom->work_pressure); + hrtimer_forward_now(&barom->timer, barom->poll_delay); + return HRTIMER_RESTART; +} + +static ssize_t bmp180_poll_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp180_data *barom = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%lld\n", + ktime_to_ns(barom->poll_delay)); +} + +static ssize_t bmp180_poll_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err; + int64_t new_delay; + struct bmp180_data *barom = dev_get_drvdata(dev); + + err = kstrtoll(buf, 10, &new_delay); + if (err < 0) + return err; + + pr_debug("%s: new delay = %lldns, old delay = %lldns\n", + __func__, new_delay, ktime_to_ns(barom->poll_delay)); + + if (new_delay < DELAY_LOWBOUND || new_delay > DELAY_UPBOUND) + return -EINVAL; + + mutex_lock(&barom->lock); + if (new_delay != ktime_to_ns(barom->poll_delay)) + barom->poll_delay = ns_to_ktime(new_delay); + + mutex_unlock(&barom->lock); + + return size; +} + +static ssize_t bmp180_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp180_data *barom = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", barom->enabled); +} + +static ssize_t bmp180_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + bool new_value; + struct bmp180_data *barom = dev_get_drvdata(dev); + + + if (sysfs_streq(buf, "1")) { + new_value = true; + } else if (sysfs_streq(buf, "0")) { + new_value = false; + } else { + pr_err("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + pr_debug("%s: new_value = %d, old state = %d\n", + __func__, new_value, barom->enabled); + + if (new_value) { + bmp180_open_calibration(barom); + bmp180_enable(barom); + } else { + bmp180_disable(barom); + } + + return size; +} + +static ssize_t bmp180_oversampling_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp180_data *barom = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", barom->oversampling_rate); +} + +static ssize_t bmp180_oversampling_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp180_data *barom = dev_get_drvdata(dev); + + unsigned long oversampling; + int success = kstrtoul(buf, 10, &oversampling); + if (success == 0) { + if (oversampling > 3) + oversampling = 3; + barom->oversampling_rate = oversampling; + return count; + } + return success; +} + +static DEVICE_ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + bmp180_poll_delay_show, bmp180_poll_delay_store); + +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, + bmp180_enable_show, bmp180_enable_store); + +static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO, + bmp180_oversampling_show, bmp180_oversampling_store); + +static struct attribute *bmp180_sysfs_attrs[] = { + &dev_attr_enable.attr, + &dev_attr_poll_delay.attr, + &dev_attr_oversampling.attr, + NULL +}; + +static struct attribute_group bmp180_attribute_group = { + .attrs = bmp180_sysfs_attrs, +}; + +#ifdef FACTORY_TEST +static ssize_t eeprom_check_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp180_data *barom = dev_get_drvdata(dev); + int val = 1; + + if (barom->bmp180_eeprom_vals.AC1 != 0 && + barom->bmp180_eeprom_vals.AC1 != 0xFFFF) + goto done; + if (barom->bmp180_eeprom_vals.AC2 != 0 && + barom->bmp180_eeprom_vals.AC2 != 0xFFFF) + goto done; + if (barom->bmp180_eeprom_vals.AC3 != 0 && + barom->bmp180_eeprom_vals.AC3 != 0xFFFF) + goto done; + if (barom->bmp180_eeprom_vals.AC4 != 0 && + barom->bmp180_eeprom_vals.AC4 != 0xFFFF) + goto done; + if (barom->bmp180_eeprom_vals.AC5 != 0 && + barom->bmp180_eeprom_vals.AC5 != 0xFFFF) + goto done; + if (barom->bmp180_eeprom_vals.AC6 != 0 && + barom->bmp180_eeprom_vals.AC6 != 0xFFFF) + goto done; + + val = -1; + +done: + return snprintf(buf, PAGE_SIZE, "%d", val); +} + +static ssize_t sea_level_pressure_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct bmp180_data *barom = dev_get_drvdata(dev); + unsigned int new_sea_level_pressure; + int err; + + err = kstrtouint(buf, 10, &new_sea_level_pressure); + if (err < 0) + return err; + + if (new_sea_level_pressure == 0) { + pr_info("%s, barom->temperature = 0\n", __func__); + new_sea_level_pressure = -1; + } + input_report_rel(barom->input_dev, REL_Y, new_sea_level_pressure); + input_sync(barom->input_dev); + + return size; +} + +static ssize_t bmp180_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", BMP_VENDOR); +} + +static ssize_t bmp180_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", BMP_PART_ID); +} + +static ssize_t factory_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp180_data *barom = dev_get_drvdata(dev); + return sprintf(buf, "%d", barom->cal_data); +} + +static ssize_t factory_calibration(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int pressure_from_outside; + + sscanf(buf, "%d", &pressure_from_outside); + + bmp180_do_calibrate(dev, true, pressure_from_outside); + + return size; +} + +static DEVICE_ATTR(eeprom_check, S_IRUSR | S_IRGRP, + eeprom_check_show, NULL); + +static DEVICE_ATTR(sea_level_pressure, S_IRUGO | S_IWUSR, + NULL, sea_level_pressure_store); + +static DEVICE_ATTR(vendor, S_IRUGO, + bmp180_vendor_show, NULL); + +static DEVICE_ATTR(name, S_IRUGO, + bmp180_name_show, NULL); + +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, + factory_calibration_show, factory_calibration); + +static struct device_attribute *barom_sensor_attrs[] = { + &dev_attr_eeprom_check, + &dev_attr_sea_level_pressure, + &dev_attr_calibration, + &dev_attr_vendor, + &dev_attr_name, + NULL, +}; + +#endif + +static int __devinit bmp180_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err; + struct bmp_i2c_platform_data *platform_data; + struct bmp180_data *barom; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s: client not i2c capable\n", __func__); + + return -EIO; + } + + barom = kzalloc(sizeof(*barom), GFP_KERNEL); + if (!barom) { + pr_err("%s: failed to allocate memory for module\n", __func__); + return -ENOMEM; + } + + if (client->dev.platform_data != NULL) { + platform_data = client->dev.platform_data; + barom->power_on = platform_data->power_on; + } + if (barom->power_on) + barom->power_on(1); + + mutex_init(&barom->lock); + barom->client = client; + + i2c_set_clientdata(client, barom); + + err = bmp180_read_store_eeprom_val(barom); + if (err) { + pr_err("%s: Reading the EEPROM failed\n", __func__); + err = -ENODEV; + goto err_read_eeprom; + } + + hrtimer_init(&barom->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + barom->poll_delay = ns_to_ktime(DELAY_DEFAULT); + barom->timer.function = bmp180_timer_func; + + barom->wq = create_singlethread_workqueue("bmp180_wq"); + if (!barom->wq) { + err = -ENOMEM; + pr_err("%s: could not create workqueue\n", __func__); + + goto err_create_workqueue; + } + + INIT_WORK(&barom->work_pressure, bmp180_get_pressure_data); + + err = bmp180_input_init(barom); + if (err) { + pr_err("%s: could not create input device\n", __func__); + + goto err_input_init; + } + err = sysfs_create_group(&barom->input_dev->dev.kobj, + &bmp180_attribute_group); + if (err) { + pr_err("%s: could not create sysfs group\n", __func__); + goto err_sysfs_create_group; + } + +#ifdef FACTORY_TEST + /* sysfs for factory test */ + + err = sensors_register(barom->dev, barom, barom_sensor_attrs, + "barometer_sensor"); + if (err) { + pr_err("%s: cound not register barometer_sensor(%d).\n", + __func__, err); + goto err_sysfs_register; + } + +#endif + goto done; + +err_sysfs_register: +err_sysfs_create_group: + sysfs_remove_group(&barom->input_dev->dev.kobj, + &bmp180_attribute_group); + bmp180_input_cleanup(barom); +err_input_init: + destroy_workqueue(barom->wq); +err_create_workqueue: +err_read_eeprom: + mutex_destroy(&barom->lock); + kfree(barom); +done: + return err; +} + +static int __devexit bmp180_remove(struct i2c_client *client) +{ + /* TO DO: revisit ordering here once _probe order is finalized */ + struct bmp180_data *barom = i2c_get_clientdata(client); + + pr_debug("%s: bmp180_remove +\n", __func__); + + sysfs_remove_group(&barom->input_dev->dev.kobj, + &bmp180_attribute_group); + + bmp180_disable(barom); + + bmp180_input_cleanup(barom); + + destroy_workqueue(barom->wq); + + mutex_destroy(&barom->lock); + kfree(barom); + + pr_debug("%s: bmp180_remove -\n", __func__); + return 0; +} + +static int bmp180_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bmp180_data *barom = i2c_get_clientdata(client); + pr_debug("%s: on_before_suspend %d\n", + __func__, barom->on_before_suspend); + if (barom->power_on) + barom->power_on(1); + + if (barom->on_before_suspend) + bmp180_enable(barom); + return 0; +} + +static int bmp180_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bmp180_data *barom = i2c_get_clientdata(client); + + barom->on_before_suspend = barom->enabled; + pr_debug("%s: on_before_suspend %d\n", + __func__, barom->on_before_suspend); + bmp180_disable(barom); + if (barom->power_on) + barom->power_on(0); + + return 0; +} + +static const struct i2c_device_id bmp180_id[] = { + {BMP180_DRV_NAME, 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, bmp180_id); +static const struct dev_pm_ops bmp180_pm_ops = { + .suspend = bmp180_suspend, + .resume = bmp180_resume, +}; + +static struct i2c_driver bmp180_driver = { + .driver = { + .name = BMP180_DRV_NAME, + .owner = THIS_MODULE, + .pm = &bmp180_pm_ops, + }, + .probe = bmp180_probe, + .remove = __devexit_p(bmp180_remove), + .id_table = bmp180_id, +}; + +static int __init bmp180_init(void) +{ + return i2c_add_driver(&bmp180_driver); +} + +static void __exit bmp180_exit(void) +{ + i2c_del_driver(&bmp180_driver); + + return; +} + +MODULE_AUTHOR("Hyoung Wook Ham "); +MODULE_DESCRIPTION("BMP180 Pressure sensor driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(DRIVER_VERSION); + +module_init(bmp180_init); +module_exit(bmp180_exit); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index bc51a2ab76b..712f353e999 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -98,6 +98,42 @@ config TOUCHSCREEN_AD7879_SPI To compile this driver as a module, choose M here: the module will be called ad7879-spi. +config TOUCHSCREEN_MMS144 + tristate "Melfas MMS144 Touchscreen" + depends on I2C + help + Say Y here if you have Melfas MMS144 series I2C touchscreen, + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called mms_ts. + +config TOUCHSCREEN_MMS136 + tristate "Melfas MMS136 Touchscreen" + depends on I2C + help + Say Y here if you have Melfas MMS136 series I2C touchscreen, + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called mms_ts. + +config TOUCHSCREEN_MMS136_TABLET + tristate "Melfas MMS136 Touchscreen at table model" + depends on I2C + help + Say Y here if you have Melfas MMS136 series I2C touchscreen at tablet, + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called mms_ts. + config TOUCHSCREEN_ATMEL_MXT tristate "Atmel mXT I2C Touchscreen" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index abb9aa2144b..64493b1c64b 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -82,3 +82,7 @@ obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC) += cyttsp-i2c-qc.o obj-$(CONFIG_TOUCHSCREEN_LGE_COMMON) += lge_touch_core.o obj-$(CONFIG_TOUCHSCREEN_LGE_SYNAPTICS) += touch_synaptics.o obj-$(CONFIG_TOUCHSCREEN_LGE_SYNAPTICS) += touch_synaptics_ds4_fw_upgrade.o +obj-$(CONFIG_TOUCHSCREEN_FT5X06) += ft5x06_ts.o +obj-$(CONFIG_TOUCHSCREEN_MMS144) += mms_ts_144.o +obj-$(CONFIG_TOUCHSCREEN_MMS136) += mms_ts_136.o +obj-$(CONFIG_TOUCHSCREEN_MMS136_TABLET) += mms_ts_136_tablet.o diff --git a/drivers/input/touchscreen/d2_465_fw.h b/drivers/input/touchscreen/d2_465_fw.h new file mode 100644 index 00000000000..f5e6e085a42 --- /dev/null +++ b/drivers/input/touchscreen/d2_465_fw.h @@ -0,0 +1,2652 @@ + +const size_t MELFAS_465_binary_nLength = 0x7C00; + +const u8 MELFAS_465_binary[] = { +0x00, 0x20, 0x00, 0x20, 0x79, 0x02, 0x00, 0x00, 0x39, 0x02, 0x00, 0x00, +0x3D, 0x02, 0x00, 0x00, 0x41, 0x02, 0x00, 0x00, 0x45, 0x02, 0x00, 0x00, +0x49, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x02, 0x00, 0x00, +0x51, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x02, 0x00, 0x00, +0x59, 0x02, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00, +0x25, 0x01, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x35, 0x02, 0x00, 0x00, +0x71, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x30, 0xB5, 0x11, 0x4B, 0x11, 0x4A, 0x1B, 0x88, 0x12, 0x78, 0xD3, 0x18, +0xDB, 0xB2, 0xE1, 0x2B, 0x02, 0xD0, 0xE5, 0x2B, 0x17, 0xD1, 0x09, 0xE0, +0x0D, 0x49, 0x0E, 0x4A, 0x04, 0x23, 0x01, 0x3B, 0xDB, 0xB2, 0xC8, 0x5C, +0x98, 0x54, 0x00, 0x2B, 0xF9, 0xD1, 0x0C, 0xE0, 0x0A, 0x4C, 0x09, 0x48, +0x0A, 0x49, 0x0B, 0x4A, 0x04, 0x23, 0x01, 0x3B, 0xDB, 0xB2, 0xE5, 0x5C, +0x1D, 0x54, 0xCD, 0x5C, 0x9D, 0x54, 0x00, 0x2B, 0xF7, 0xD1, 0x30, 0xBD, +0x28, 0x00, 0x00, 0x20, 0x2A, 0x00, 0x00, 0x20, 0x2D, 0x00, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x50, 0x35, 0x00, 0x00, 0x20, 0x31, 0x00, 0x00, 0x20, +0x10, 0x00, 0x00, 0x50, 0x03, 0x4A, 0x00, 0x23, 0x13, 0x70, 0x80, 0x22, +0xD2, 0x05, 0x13, 0x70, 0x70, 0x47, 0xC0, 0x46, 0x00, 0x00, 0x00, 0x20, +0x06, 0x4B, 0x00, 0x22, 0x5A, 0x70, 0x80, 0x23, 0xDB, 0x05, 0x59, 0x69, +0x04, 0x4A, 0x0A, 0x40, 0x5A, 0x61, 0x59, 0x69, 0x03, 0x4A, 0x0A, 0x40, +0x5A, 0x61, 0x70, 0x47, 0x00, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xFE, +0xFF, 0xFF, 0xFF, 0xEF, 0x70, 0xB5, 0xA0, 0x23, 0xDB, 0x05, 0x1C, 0x7A, +0x24, 0x4D, 0x0F, 0x22, 0x14, 0x40, 0x2A, 0x78, 0x23, 0x4E, 0x00, 0x2A, +0x06, 0xD0, 0x23, 0x4B, 0x1B, 0x68, 0x98, 0x47, 0x00, 0x23, 0x2B, 0x70, +0x34, 0x70, 0x3A, 0xE0, 0x9B, 0x7A, 0x32, 0x78, 0xE1, 0x07, 0x02, 0xD5, +0x1E, 0x4A, 0x13, 0x80, 0x07, 0xE0, 0x08, 0x21, 0x0C, 0x42, 0x0A, 0xD0, +0x1C, 0x4B, 0x1A, 0x78, 0x52, 0x18, 0xD2, 0xB2, 0x1A, 0x70, 0xFF, 0xF7, +0x8D, 0xFF, 0x1A, 0x4B, 0x1B, 0x68, 0x98, 0x47, 0x19, 0xE0, 0xA1, 0x07, +0x0D, 0xD5, 0x08, 0x2A, 0x01, 0xD0, 0x01, 0x2A, 0x01, 0xD1, 0x16, 0x4B, +0x02, 0xE0, 0x12, 0x4A, 0x13, 0x80, 0x15, 0x4B, 0x1B, 0x68, 0x98, 0x47, +0x00, 0x22, 0x10, 0x4B, 0x08, 0xE0, 0x63, 0x07, 0x07, 0xD5, 0x11, 0x4B, +0x1B, 0x68, 0x98, 0x47, 0x0C, 0x4B, 0x1A, 0x78, 0x08, 0x32, 0xD2, 0xB2, +0x1A, 0x70, 0x07, 0x4B, 0x01, 0x22, 0x1C, 0x70, 0xA0, 0x23, 0xDB, 0x05, +0x1A, 0x72, 0x0B, 0x49, 0x10, 0x22, 0x1A, 0x72, 0x00, 0x22, 0x0A, 0x70, +0x1A, 0x72, 0x70, 0xBD, 0x2C, 0x00, 0x00, 0x20, 0x2B, 0x00, 0x00, 0x20, +0x24, 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, 0x20, 0x2A, 0x00, 0x00, 0x20, +0x1C, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x20, 0x03, 0x4A, 0x00, 0x23, 0x93, 0x70, 0x80, 0x22, +0xD2, 0x05, 0x53, 0x70, 0x70, 0x47, 0xC0, 0x46, 0x00, 0x00, 0x00, 0x20, +0x70, 0x47, 0xC0, 0x46, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x38, 0xB5, 0x80, 0x23, +0xDB, 0x05, 0xFB, 0x21, 0x5A, 0x68, 0x59, 0x60, 0x99, 0x68, 0x08, 0x21, +0x99, 0x60, 0x00, 0x22, 0xD9, 0x68, 0xDA, 0x60, 0x19, 0x6C, 0x80, 0x21, +0xC9, 0x01, 0x19, 0x64, 0x19, 0x69, 0x44, 0x49, 0x19, 0x61, 0x44, 0x4B, +0x44, 0x49, 0x00, 0xE0, 0x04, 0xC3, 0x8B, 0x42, 0xFC, 0xD3, 0x43, 0x4B, +0x43, 0x4A, 0x9B, 0x0A, 0xDB, 0xB2, 0x13, 0x70, 0x42, 0x4B, 0x43, 0x49, +0x1B, 0x68, 0x9B, 0x0A, 0xDB, 0xB2, 0x53, 0x70, 0x41, 0x4B, 0x1B, 0x68, +0x9B, 0x0A, 0xDB, 0xB2, 0x93, 0x70, 0x40, 0x4B, 0x1B, 0x68, 0x9B, 0x0A, +0xDB, 0xB2, 0xD3, 0x70, 0x00, 0x23, 0x0B, 0x70, 0x03, 0x23, 0x08, 0xE0, +0x58, 0x1C, 0x15, 0x5C, 0xD4, 0x5C, 0xA5, 0x42, 0x07, 0xD9, 0xD4, 0x5C, +0x01, 0x34, 0xE4, 0xB2, 0x0C, 0x54, 0x01, 0x3B, 0xDB, 0xB2, 0xFF, 0x2B, +0xF2, 0xD1, 0x30, 0x4A, 0x11, 0x78, 0x35, 0x4A, 0x11, 0x70, 0x11, 0x1C, +0xFF, 0x2B, 0x03, 0xD1, 0x2D, 0x4B, 0xDB, 0x78, 0x1E, 0x2B, 0x04, 0xD9, +0xFF, 0x23, 0x4B, 0x70, 0x8B, 0x70, 0xCB, 0x70, 0x0B, 0xE0, 0x2A, 0x4B, +0x1B, 0x68, 0x1B, 0x78, 0x53, 0x70, 0x2A, 0x4B, 0x1B, 0x68, 0x1B, 0x78, +0x93, 0x70, 0x29, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0xD3, 0x70, 0x28, 0x4B, +0xDA, 0x78, 0xFF, 0x2A, 0x08, 0xD0, 0x9A, 0x78, 0xFF, 0x2A, 0x05, 0xD0, +0x5B, 0x78, 0xFF, 0x2B, 0x02, 0xD0, 0x00, 0xF0, 0x67, 0xF8, 0x38, 0xBD, +0x22, 0x4B, 0x23, 0x4A, 0xC0, 0x21, 0x13, 0x60, 0x22, 0x4A, 0x49, 0x00, +0x13, 0x60, 0x22, 0x4A, 0x22, 0x48, 0x13, 0x60, 0x22, 0x4A, 0x13, 0x60, +0x22, 0x4B, 0x02, 0x22, 0x5A, 0x50, 0xC0, 0x21, 0x91, 0x40, 0x5C, 0x58, +0x20, 0x40, 0x58, 0x50, 0x1F, 0x49, 0x04, 0x24, 0x08, 0x69, 0x20, 0x43, +0x08, 0x61, 0x62, 0xB6, 0x1A, 0x60, 0x80, 0x23, 0xDB, 0x05, 0x1A, 0x6C, +0x80, 0x22, 0x12, 0x02, 0x1A, 0x64, 0x1A, 0x6C, 0x80, 0x22, 0xD2, 0x01, +0x1A, 0x64, 0x9A, 0x68, 0x80, 0x22, 0x52, 0x00, 0x9A, 0x60, 0xA0, 0x22, +0xD2, 0x05, 0x91, 0x68, 0x14, 0x49, 0x91, 0x60, 0x1A, 0x6C, 0x00, 0x22, +0x1A, 0x64, 0xFE, 0xE7, 0x10, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, +0x3C, 0x00, 0x00, 0x20, 0xFF, 0x03, 0x00, 0x00, 0x31, 0x00, 0x00, 0x20, +0x08, 0x04, 0x00, 0x00, 0x35, 0x00, 0x00, 0x20, 0x0C, 0x04, 0x00, 0x00, +0x10, 0x04, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x20, 0xF9, 0x03, 0x00, 0x00, +0x24, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x20, 0x1C, 0x00, 0x00, 0x20, +0xFF, 0x00, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x20, 0x00, 0xE1, 0x00, 0xE0, +0x00, 0xED, 0x00, 0xE0, 0x00, 0x00, 0xC8, 0x42, 0x70, 0x47, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x4D, 0x31, 0x48, 0x30, 0x43, 0x4F, 0x34, 0x35, +0xFF, 0x5B, 0x00, 0x00, 0xFF, 0x73, 0x00, 0x00, 0xFF, 0x7B, 0x00, 0x00, +0xF7, 0xB5, 0x03, 0xF0, 0xC7, 0xFC, 0x05, 0xF0, 0x31, 0xF8, 0x00, 0x20, +0x05, 0xF0, 0xF2, 0xFB, 0x4E, 0x4B, 0x33, 0x33, 0x1B, 0x78, 0x5E, 0x42, +0x73, 0x41, 0x10, 0x26, 0xF6, 0x1A, 0x4C, 0x4B, 0x1E, 0x70, 0x4C, 0x4B, +0x1A, 0x68, 0x01, 0x3A, 0x53, 0x42, 0x5A, 0x41, 0x4A, 0x4B, 0x1A, 0x70, +0x4A, 0x4B, 0x1C, 0x78, 0x00, 0x2C, 0x22, 0xD1, 0x49, 0x4A, 0x01, 0x25, +0x14, 0x70, 0x1D, 0x70, 0x00, 0xF0, 0x52, 0xFA, 0x47, 0x4B, 0x28, 0x1C, +0xDA, 0x78, 0x9A, 0x70, 0x5C, 0x70, 0x05, 0xF0, 0xD1, 0xFB, 0x03, 0xF0, +0x83, 0xFB, 0x01, 0xF0, 0x1B, 0xFB, 0x80, 0x23, 0xDB, 0x05, 0x1A, 0x6C, +0x7F, 0x21, 0x8A, 0x43, 0x1A, 0x64, 0x00, 0xF0, 0xF9, 0xFD, 0x02, 0xF0, +0x4F, 0xFF, 0x01, 0xF0, 0x0F, 0xFB, 0x01, 0xF0, 0xA7, 0xFA, 0x3C, 0x4B, +0x02, 0x20, 0x1B, 0x68, 0x98, 0x47, 0x3B, 0x4C, 0x23, 0x78, 0x00, 0x2B, +0x03, 0xD1, 0x3A, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x0F, 0xD0, 0x23, 0x78, +0x00, 0xF0, 0x98, 0xFC, 0x22, 0x78, 0x2E, 0x4B, 0x00, 0x2A, 0x01, 0xD0, +0x1E, 0x70, 0x01, 0xE0, 0x0D, 0x22, 0x1A, 0x70, 0x31, 0x4A, 0x00, 0x23, +0x13, 0x70, 0x31, 0x4A, 0x13, 0x70, 0x2C, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x2C, 0xD0, 0x2F, 0x4D, 0x2B, 0x78, 0x00, 0x2B, 0x28, 0xD0, 0x2A, 0x4C, +0x13, 0x20, 0x23, 0x68, 0x98, 0x47, 0x00, 0xF0, 0x0F, 0xFA, 0x03, 0xF0, +0x0C, 0xFB, 0x03, 0xF0, 0x8F, 0xFA, 0x29, 0x4B, 0x18, 0x78, 0x01, 0xF0, +0xA5, 0xF8, 0x00, 0xF0, 0xCB, 0xFD, 0x27, 0x4A, 0x01, 0x23, 0x13, 0x70, +0x26, 0x4A, 0x13, 0x80, 0x02, 0xF0, 0xE2, 0xFF, 0x2B, 0x78, 0x00, 0x2B, +0xFC, 0xD1, 0x23, 0x68, 0x14, 0x20, 0x98, 0x47, 0x00, 0xF0, 0xF6, 0xF9, +0x03, 0xF0, 0xF3, 0xFA, 0x03, 0xF0, 0x76, 0xFA, 0x1C, 0x4B, 0x18, 0x78, +0x01, 0xF0, 0x8C, 0xF8, 0x10, 0x4B, 0x1E, 0x70, 0x00, 0xF0, 0x82, 0xFF, +0x0E, 0x4C, 0x27, 0x78, 0x78, 0xB2, 0x13, 0x28, 0x00, 0xD9, 0x8D, 0xE1, +0x05, 0xF0, 0xD2, 0xF8, 0x74, 0x00, 0x8C, 0x01, 0x78, 0x01, 0x8C, 0x01, +0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, +0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, 0x68, 0x00, 0x8C, 0x01, 0x3A, 0x00, +0x30, 0x00, 0x5F, 0x00, 0x8C, 0x01, 0x89, 0x01, 0xAE, 0x09, 0x00, 0x20, +0x1D, 0x03, 0x00, 0x20, 0x50, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0xE9, 0x01, 0x00, 0x20, 0xEA, 0x01, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, +0xF8, 0x01, 0x00, 0x20, 0xE8, 0x01, 0x00, 0x20, 0xE7, 0x01, 0x00, 0x20, +0xE5, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0xF6, 0x03, 0x00, 0x20, +0x08, 0x03, 0x00, 0x20, 0xB1, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x00, 0xF0, +0x81, 0xFE, 0xB0, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD0, 0x55, 0xE1, +0xAE, 0x4C, 0x23, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0xAD, 0x49, +0x03, 0xF0, 0xBC, 0xFC, 0x23, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x21, +0x00, 0x20, 0xAA, 0x4A, 0x0B, 0x1C, 0x00, 0x90, 0x03, 0xF0, 0x5A, 0xFC, +0xA8, 0x4B, 0x98, 0x78, 0x03, 0xF0, 0x7C, 0xFA, 0xA7, 0x4D, 0xE8, 0x7B, +0x03, 0xF0, 0x56, 0xF8, 0xA6, 0x4C, 0x20, 0x60, 0x28, 0x7C, 0x03, 0xF0, +0x51, 0xF8, 0x11, 0x23, 0x60, 0x60, 0xEB, 0x56, 0xEA, 0x7B, 0x53, 0x43, +0xA3, 0x60, 0x9A, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0xA0, 0x4B, 0x1B, 0x78, +0xA0, 0x4B, 0x18, 0x78, 0x01, 0xF0, 0x18, 0xF8, 0x95, 0x4B, 0x9D, 0x4D, +0x00, 0x24, 0x1C, 0x70, 0x2B, 0x78, 0x00, 0xF0, 0x2D, 0xFD, 0x03, 0xF0, +0x8F, 0xFF, 0x00, 0xF0, 0x29, 0xFD, 0x2C, 0x70, 0x8F, 0x4B, 0x01, 0x24, +0x1C, 0x70, 0x00, 0xF0, 0x9F, 0xFC, 0x97, 0x4B, 0x1B, 0x68, 0x9A, 0x05, +0x13, 0xD5, 0x96, 0x4A, 0x96, 0x4B, 0x04, 0x20, 0x1A, 0x60, 0x96, 0x4B, +0x19, 0x68, 0x01, 0x43, 0x19, 0x60, 0x19, 0x68, 0x02, 0x20, 0x81, 0x43, +0x19, 0x60, 0x19, 0x68, 0x0C, 0x43, 0x1C, 0x60, 0x91, 0x4B, 0x00, 0x21, +0x19, 0x60, 0x91, 0x4B, 0x1A, 0x60, 0x91, 0x4C, 0x03, 0x20, 0x23, 0x68, +0x98, 0x47, 0x03, 0xF0, 0x43, 0xF8, 0x23, 0x68, 0x05, 0x20, 0x98, 0x47, +0x02, 0xF0, 0xE8, 0xFF, 0x8C, 0x4C, 0x8D, 0x4D, 0x01, 0x20, 0x40, 0x42, +0x21, 0x1C, 0x2A, 0x1C, 0x04, 0xF0, 0x4A, 0xFC, 0x79, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x03, 0xD0, 0x0C, 0x20, 0x88, 0x49, 0x03, 0xF0, 0x52, 0xFC, +0x87, 0x4A, 0x23, 0x68, 0x13, 0x80, 0x2B, 0x68, 0x53, 0x80, 0x73, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, 0x00, 0x93, +0x0C, 0x20, 0x0B, 0x1C, 0x03, 0xF0, 0xEA, 0xFB, 0x7B, 0x4C, 0x06, 0x20, +0x23, 0x68, 0x98, 0x47, 0x03, 0xF0, 0xF8, 0xFF, 0x04, 0xF0, 0x68, 0xF9, +0x04, 0xF0, 0x96, 0xFB, 0x00, 0xF0, 0x62, 0xF9, 0x04, 0xF0, 0x04, 0xFD, +0x04, 0xF0, 0x7C, 0xFE, 0x78, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x2A, 0xD1, +0x23, 0x68, 0x07, 0x20, 0x98, 0x47, 0x01, 0xF0, 0x55, 0xFA, 0x23, 0x68, +0x08, 0x20, 0x98, 0x47, 0x02, 0xF0, 0xB6, 0xFF, 0x02, 0xF0, 0xBE, 0xFF, +0x23, 0x68, 0x09, 0x20, 0x98, 0x47, 0x01, 0xF0, 0x6D, 0xFA, 0x01, 0xF0, +0xD5, 0xFB, 0x23, 0x68, 0x0A, 0x20, 0x98, 0x47, 0x01, 0xF0, 0x72, 0xFC, +0x02, 0xF0, 0x48, 0xFB, 0x23, 0x68, 0x0B, 0x20, 0x98, 0x47, 0x01, 0xF0, +0xBC, 0xFE, 0x01, 0xF0, 0xDB, 0xFF, 0x23, 0x68, 0x0E, 0x20, 0x98, 0x47, +0x02, 0xF0, 0x88, 0xF8, 0x02, 0xF0, 0xF6, 0xF9, 0x23, 0x68, 0x10, 0x20, +0x98, 0x47, 0x00, 0xF0, 0x81, 0xF9, 0x5B, 0x4B, 0x0F, 0x20, 0x1B, 0x68, +0x98, 0x47, 0x5E, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x3C, 0xD1, 0x02, 0xF0, +0x53, 0xFA, 0x5C, 0x4B, 0x1A, 0x68, 0x5C, 0x4B, 0x00, 0x2A, 0x04, 0xD1, +0x5B, 0x49, 0x09, 0x68, 0x00, 0x29, 0x00, 0xDD, 0x1A, 0x70, 0x47, 0x4A, +0x19, 0x78, 0x32, 0x32, 0x12, 0x78, 0x91, 0x42, 0x01, 0xD3, 0x00, 0x22, +0x1A, 0x70, 0x1B, 0x78, 0x00, 0x2B, 0x21, 0xD1, 0x53, 0x4B, 0x51, 0x4C, +0x1B, 0x68, 0x00, 0x2B, 0x09, 0xDD, 0x20, 0x68, 0x00, 0x28, 0x06, 0xD1, +0x39, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x02, 0xD0, 0x4E, 0x49, 0x03, 0xF0, +0xD3, 0xFB, 0x4E, 0x4B, 0x1B, 0x68, 0x98, 0x47, 0x23, 0x68, 0x00, 0x2B, +0x0A, 0xDD, 0x49, 0x4B, 0x18, 0x68, 0x00, 0x28, 0x06, 0xD1, 0x31, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x02, 0xD0, 0x48, 0x49, 0x03, 0xF0, 0xC2, 0xFB, +0x02, 0xF0, 0x76, 0xFA, 0x41, 0x4B, 0x1A, 0x78, 0x01, 0x32, 0x1A, 0x70, +0x32, 0x4B, 0x1B, 0x68, 0x9A, 0x05, 0x23, 0xD5, 0x34, 0x4B, 0x18, 0x68, +0x2A, 0x4B, 0x1A, 0x79, 0x19, 0x78, 0x2F, 0x4B, 0x18, 0x1A, 0x53, 0x1C, +0x98, 0x40, 0x04, 0xF0, 0x8B, 0xFF, 0x23, 0x4C, 0x2F, 0x4D, 0x23, 0x78, +0x28, 0x60, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x39, 0x49, 0x03, 0xF0, +0xA3, 0xFB, 0x23, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x00, 0x20, 0x01, 0x21, +0x2A, 0x1C, 0x04, 0x23, 0x00, 0x90, 0x03, 0xF0, 0x41, 0xFB, 0x24, 0x4B, +0x01, 0x21, 0x1A, 0x68, 0x8A, 0x43, 0x1A, 0x60, 0x80, 0x23, 0xDB, 0x05, +0x9A, 0x6C, 0x01, 0x21, 0x0A, 0x43, 0x9A, 0x64, 0x00, 0xF0, 0x22, 0xFC, +0x2D, 0x4B, 0x00, 0x20, 0x18, 0x56, 0x00, 0xF0, 0x61, 0xFE, 0x17, 0xE0, +0x0F, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x05, 0x20, 0x29, 0x49, +0x03, 0xF0, 0x7E, 0xFB, 0x01, 0x20, 0x00, 0xF0, 0xFD, 0xFE, 0x00, 0x20, +0x00, 0xF0, 0xFA, 0xFE, 0x13, 0x23, 0x23, 0x70, 0x06, 0xE0, 0x00, 0xF0, +0x11, 0xFC, 0x03, 0xE0, 0x13, 0x4B, 0x11, 0x20, 0x1B, 0x68, 0x98, 0x47, +0x20, 0x4B, 0x1F, 0x70, 0xEB, 0xE5, 0xC0, 0x46, 0xEA, 0x01, 0x00, 0x20, +0xE0, 0x01, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0x30, 0x59, 0x00, 0x00, +0xAC, 0x0A, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0xFC, 0x02, 0x00, 0x20, 0x1D, 0x03, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x58, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x00, 0x14, 0xE0, 0x00, 0xE0, +0x10, 0xE0, 0x00, 0xE0, 0x18, 0xE0, 0x00, 0xE0, 0xFC, 0x01, 0x00, 0x20, +0xF8, 0x01, 0x00, 0x20, 0x34, 0x11, 0x00, 0x20, 0x38, 0x11, 0x00, 0x20, +0x34, 0x59, 0x00, 0x00, 0x54, 0x11, 0x00, 0x20, 0x48, 0x11, 0x00, 0x20, +0x20, 0x01, 0x00, 0x20, 0xCA, 0x00, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0x3A, 0x59, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x43, 0x59, 0x00, 0x00, +0x4D, 0x59, 0x00, 0x00, 0xB3, 0x01, 0x00, 0x20, 0x5A, 0x59, 0x00, 0x00, +0x56, 0x00, 0x00, 0x20, 0x08, 0xB5, 0x01, 0xF0, 0x9D, 0xFD, 0x01, 0xF0, +0xB7, 0xFD, 0x03, 0x4B, 0x1B, 0x68, 0x98, 0x47, 0x02, 0xF0, 0xD6, 0xF9, +0x08, 0xBD, 0xC0, 0x46, 0x00, 0x02, 0x00, 0x20, 0x10, 0xB5, 0x04, 0xF0, +0xED, 0xFD, 0x05, 0x4C, 0x00, 0x20, 0x23, 0x68, 0x98, 0x47, 0x04, 0xF0, +0x17, 0xFE, 0x23, 0x68, 0x01, 0x20, 0x98, 0x47, 0x10, 0xBD, 0xC0, 0x46, +0xF8, 0x01, 0x00, 0x20, 0x7F, 0xB5, 0x17, 0x4D, 0x17, 0x4B, 0x5B, 0x1B, +0x03, 0x93, 0x17, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x00, 0x20, +0x01, 0x21, 0x03, 0xAA, 0x04, 0x23, 0x00, 0x90, 0x03, 0xF0, 0xA4, 0xFA, +0x12, 0x4E, 0x18, 0xE0, 0x14, 0x2C, 0x00, 0xDD, 0x14, 0x24, 0xE1, 0xB2, +0x08, 0x1C, 0x03, 0xE0, 0x01, 0x38, 0xC0, 0xB2, 0x2B, 0x5C, 0x33, 0x54, +0x00, 0x28, 0xF9, 0xD1, 0x0A, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x04, 0xD0, +0x09, 0x4A, 0x01, 0x23, 0x00, 0x90, 0x03, 0xF0, 0x8D, 0xFA, 0x03, 0x9B, +0x2D, 0x19, 0x1B, 0x1B, 0x03, 0x93, 0x03, 0x9C, 0x00, 0x2C, 0xE3, 0xD1, +0x7F, 0xBD, 0xC0, 0x46, 0x0C, 0x1E, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, 0x13, 0xB5, 0x1E, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x37, 0xD0, 0x1D, 0x4C, 0x00, 0x23, 0x23, 0x70, +0x1C, 0x4B, 0x04, 0x20, 0x1B, 0x68, 0x98, 0x47, 0x1B, 0x4B, 0x1C, 0x4A, +0x59, 0x68, 0x1B, 0x68, 0x11, 0x80, 0x53, 0x80, 0x1A, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, 0x00, 0x93, 0x18, 0x20, +0x0B, 0x1C, 0x03, 0xF0, 0x5F, 0xFA, 0x23, 0x78, 0x15, 0x4C, 0x00, 0x2B, +0x1A, 0xD0, 0x13, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, +0x12, 0x49, 0x03, 0xF0, 0xAB, 0xFA, 0x12, 0x4A, 0x01, 0x23, 0x13, 0x70, +0x22, 0x68, 0x02, 0x2A, 0x04, 0xDC, 0xD2, 0x18, 0x22, 0x60, 0x0F, 0x4A, +0x13, 0x70, 0x08, 0xE0, 0xFF, 0xF7, 0x74, 0xFF, 0x0D, 0x4B, 0x0D, 0x22, +0x1A, 0x70, 0x00, 0x23, 0x23, 0x60, 0x00, 0xE0, 0x23, 0x60, 0x13, 0xBD, +0x1C, 0x03, 0x00, 0x20, 0x3D, 0x11, 0x00, 0x20, 0xF8, 0x01, 0x00, 0x20, +0x70, 0x01, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0x84, 0x01, 0x00, 0x20, 0xCC, 0x58, 0x00, 0x00, 0x48, 0x11, 0x00, 0x20, +0x14, 0x09, 0x00, 0x20, 0x1D, 0x03, 0x00, 0x20, 0xF0, 0xB5, 0xBC, 0x4B, +0x85, 0xB0, 0x04, 0x33, 0xDB, 0x7F, 0x00, 0x24, 0xBA, 0x49, 0x0A, 0x22, +0x09, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x10, 0x1C, 0x58, 0x43, 0x08, 0x18, +0x3C, 0x25, 0x40, 0x5F, 0x00, 0x28, 0x00, 0xD0, 0x01, 0x24, 0x00, 0x2B, +0xF3, 0xD1, 0xB4, 0x4B, 0xB4, 0x4A, 0x1B, 0x78, 0x07, 0xE0, 0x01, 0x3B, +0xDB, 0xB2, 0x19, 0x1D, 0x49, 0x00, 0x89, 0x5E, 0x00, 0x29, 0x00, 0xD0, +0x01, 0x24, 0x00, 0x2B, 0xF5, 0xD1, 0xAF, 0x4A, 0x00, 0x2C, 0x04, 0xD1, +0x13, 0x68, 0xAE, 0x49, 0x8B, 0x42, 0x01, 0xD0, 0x01, 0x33, 0x13, 0x60, +0xAC, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0xA6, 0x4B, 0x1A, 0x68, 0xA4, 0x4B, +0x00, 0x2A, 0x00, 0xD0, 0x80, 0xE0, 0xA5, 0x4A, 0x12, 0x68, 0x00, 0x2A, +0x7C, 0xD1, 0x34, 0x33, 0x1B, 0x78, 0x00, 0x2B, 0x46, 0xD1, 0xA5, 0x4B, +0x1A, 0x78, 0x01, 0x2A, 0x1A, 0xD1, 0xA4, 0x4B, 0x18, 0x78, 0x00, 0x28, +0x16, 0xD1, 0x1A, 0x70, 0xA2, 0x4B, 0xA3, 0x49, 0x18, 0x70, 0xA3, 0x4B, +0x08, 0x70, 0x1B, 0x78, 0x00, 0x2B, 0x02, 0xD0, 0xA1, 0x49, 0x03, 0xF0, +0x2F, 0xFA, 0x9A, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x01, 0xF0, 0xA0, 0xFC, +0x01, 0xF0, 0xBA, 0xFC, 0x97, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x68, 0xE1, +0x8E, 0x4D, 0x9B, 0x4A, 0x2B, 0x1C, 0x3C, 0x33, 0x1B, 0x78, 0x12, 0x68, +0x9A, 0x42, 0x1F, 0xDB, 0x95, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, +0x00, 0x20, 0x96, 0x49, 0x03, 0xF0, 0x14, 0xFA, 0x95, 0x4B, 0x3D, 0x35, +0x1A, 0x68, 0x01, 0x32, 0x1A, 0x60, 0x29, 0x78, 0x8A, 0x42, 0x0F, 0xDB, +0x00, 0x20, 0x18, 0x60, 0x8B, 0x4B, 0x18, 0x70, 0x88, 0x4B, 0x18, 0x70, +0x8A, 0x4B, 0x1B, 0x78, 0x83, 0x42, 0x02, 0xD0, 0x8D, 0x49, 0x03, 0xF0, +0xFF, 0xF9, 0x82, 0x4B, 0x02, 0x22, 0x1A, 0x70, 0x83, 0x4B, 0x8B, 0x4A, +0x00, 0x21, 0x19, 0x70, 0x10, 0x68, 0x85, 0x4B, 0x19, 0x60, 0x13, 0x1C, +0x88, 0x42, 0x0E, 0xDD, 0x01, 0x38, 0x10, 0x60, 0x8C, 0x42, 0x00, 0xD0, +0x11, 0x60, 0x1A, 0x68, 0x01, 0x2A, 0x00, 0xD0, 0x17, 0xE1, 0x00, 0x22, +0x1A, 0x60, 0x76, 0x4B, 0x03, 0x22, 0x1A, 0x70, 0x27, 0xE1, 0x80, 0x4B, +0x80, 0x49, 0x04, 0x33, 0xDB, 0x8F, 0x8B, 0x42, 0x00, 0xD1, 0x0A, 0xE1, +0x7E, 0x49, 0x09, 0x68, 0x99, 0x42, 0x00, 0xDA, 0x05, 0xE1, 0x68, 0x4B, +0x6B, 0x48, 0x19, 0x1C, 0x3E, 0x31, 0x09, 0x78, 0x00, 0x68, 0x88, 0x42, +0x00, 0xDA, 0xFC, 0xE0, 0x3F, 0x33, 0x1B, 0x78, 0x13, 0x60, 0xF8, 0xE0, +0x04, 0x33, 0xD8, 0x7F, 0x00, 0x23, 0x1A, 0x1C, 0x74, 0x49, 0x31, 0xE0, +0x01, 0x38, 0xC0, 0xB2, 0x0A, 0x24, 0x44, 0x43, 0x5D, 0x4F, 0x3D, 0x19, +0x3C, 0x26, 0xAD, 0x5F, 0x00, 0x2D, 0x27, 0xDD, 0x0C, 0x19, 0x3C, 0x27, +0xE4, 0x5F, 0x00, 0x2C, 0x22, 0xDD, 0x44, 0x00, 0x0D, 0x19, 0xAF, 0x88, +0x56, 0x4D, 0x3E, 0xB2, 0x2C, 0x19, 0xA4, 0x88, 0x25, 0xB2, 0x76, 0x1B, +0x02, 0xD4, 0x3C, 0x1B, 0xA4, 0xB2, 0x01, 0xE0, 0xE4, 0x1B, 0xA4, 0xB2, +0x05, 0x1C, 0x64, 0x4E, 0x4F, 0x4F, 0x10, 0x35, 0x6D, 0x00, 0xA2, 0x18, +0xAC, 0x5B, 0xED, 0x5B, 0x27, 0xB2, 0x2E, 0xB2, 0x92, 0xB2, 0xBF, 0x1B, +0x02, 0xD4, 0x64, 0x1B, 0xA4, 0xB2, 0x01, 0xE0, 0x2C, 0x1B, 0xA4, 0xB2, +0xE3, 0x18, 0x9B, 0xB2, 0x00, 0x28, 0xCB, 0xD1, 0x55, 0x49, 0x08, 0x60, +0x4B, 0x49, 0x0C, 0x78, 0x42, 0x49, 0x00, 0x2C, 0x40, 0xD0, 0x34, 0x31, +0x0B, 0x78, 0x00, 0x2B, 0x00, 0xD0, 0xB2, 0xE0, 0x49, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x02, 0xD0, 0x52, 0x49, 0x03, 0xF0, 0x7D, 0xF9, 0x4F, 0x4C, +0x51, 0x4A, 0x23, 0x68, 0x13, 0x80, 0x51, 0x4B, 0x1B, 0x68, 0x53, 0x80, +0x42, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, +0x00, 0x93, 0x00, 0x20, 0x0B, 0x1C, 0x03, 0xF0, 0x13, 0xF9, 0x32, 0x49, +0x20, 0x68, 0x4A, 0x8F, 0x39, 0x4B, 0x90, 0x42, 0x14, 0xDA, 0x41, 0x4A, +0x46, 0x48, 0x45, 0x32, 0x12, 0x78, 0x00, 0x68, 0x90, 0x42, 0x0D, 0xDA, +0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD0, 0x88, 0xE0, 0x36, 0x4B, 0x3C, 0x31, +0x1A, 0x68, 0x09, 0x78, 0x8A, 0x42, 0x00, 0xDB, 0x81, 0xE0, 0x01, 0x32, +0x1A, 0x60, 0x7E, 0xE0, 0x01, 0x22, 0x1A, 0x70, 0x30, 0x4A, 0x00, 0x23, +0x13, 0x60, 0x31, 0x4A, 0x13, 0x60, 0x76, 0xE0, 0x08, 0x1C, 0x34, 0x30, +0x00, 0x78, 0x00, 0x28, 0x71, 0xD1, 0x32, 0x48, 0x09, 0x8F, 0x00, 0x68, +0x88, 0x42, 0x09, 0xDB, 0x2D, 0x49, 0x33, 0x48, 0x45, 0x31, 0x09, 0x78, +0x00, 0x68, 0x88, 0x42, 0x02, 0xDB, 0x21, 0x49, 0x01, 0x20, 0x08, 0x70, +0x20, 0x49, 0x09, 0x78, 0x00, 0x29, 0x08, 0xD1, 0x14, 0x49, 0x08, 0x8F, +0x26, 0x49, 0x88, 0x42, 0x59, 0xD0, 0x1B, 0x49, 0x09, 0x78, 0x00, 0x29, +0x55, 0xD0, 0x11, 0x49, 0x09, 0x68, 0x01, 0x29, 0x05, 0xDC, 0x0E, 0x49, +0xC9, 0x8E, 0x8A, 0x42, 0x01, 0xD8, 0x8B, 0x42, 0x48, 0xD9, 0x15, 0x4B, +0x00, 0x20, 0x18, 0x70, 0x11, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x11, 0x4B, +0x18, 0x70, 0x12, 0x4B, 0x1B, 0x78, 0x83, 0x42, 0x02, 0xD0, 0x11, 0x49, +0x03, 0xF0, 0x0E, 0xF9, 0x09, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x01, 0xF0, +0x7F, 0xFB, 0x01, 0xF0, 0x99, 0xFB, 0x34, 0xE0, 0xAE, 0x09, 0x00, 0x20, +0x9C, 0x0D, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, 0xE0, 0x00, 0x00, 0x20, +0xC8, 0x01, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x7F, 0xB3, 0x01, 0x00, 0x20, +0xB4, 0x01, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, 0xD4, 0x01, 0x00, 0x20, +0xDC, 0x01, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0xD6, 0x58, 0x00, 0x00, +0xD8, 0x01, 0x00, 0x20, 0xE0, 0x58, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x20, +0xE8, 0x58, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0xFF, 0xFF, 0x00, 0x00, 0x34, 0x11, 0x00, 0x20, 0x20, 0x03, 0x00, 0x20, +0xF1, 0x58, 0x00, 0x00, 0x54, 0x11, 0x00, 0x20, 0x38, 0x11, 0x00, 0x20, +0x0D, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x0D, 0x4B, 0x34, 0x33, 0x1B, 0x78, +0x00, 0x2B, 0x10, 0xD0, 0x0B, 0x4B, 0x1A, 0x78, 0x00, 0x2A, 0x0C, 0xD0, +0x0A, 0x4A, 0x00, 0x21, 0x51, 0x56, 0x03, 0x29, 0x07, 0xD0, 0x09, 0x49, +0x09, 0x78, 0x48, 0x42, 0x41, 0x41, 0x01, 0x31, 0x11, 0x70, 0x00, 0x22, +0x1A, 0x70, 0x05, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, 0xB4, 0x01, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0xDC, 0x01, 0x00, 0x20, 0xB3, 0x01, 0x00, 0x20, +0xDD, 0x01, 0x00, 0x20, 0x10, 0xB5, 0x54, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x0A, 0xD0, 0x53, 0x4B, 0x1B, 0x68, 0x98, 0x47, 0x01, 0xF0, 0x1A, 0xFB, +0x01, 0xF0, 0x34, 0xFB, 0x01, 0xF0, 0x56, 0xFF, 0x02, 0xF0, 0x90, 0xFB, +0x4E, 0x4B, 0x02, 0x21, 0x1A, 0x68, 0x8A, 0x43, 0x1A, 0x60, 0x19, 0x68, +0x80, 0x22, 0xD2, 0x05, 0x90, 0x68, 0x91, 0x60, 0x19, 0x68, 0x08, 0x20, +0x81, 0x43, 0x19, 0x60, 0x19, 0x68, 0x90, 0x68, 0x91, 0x60, 0x19, 0x68, +0x04, 0x20, 0x81, 0x43, 0x19, 0x60, 0x1B, 0x68, 0x91, 0x68, 0x93, 0x60, +0x40, 0x4B, 0x18, 0x78, 0x42, 0x4B, 0x1B, 0x78, 0x00, 0x28, 0x32, 0xD0, +0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x40, 0x49, 0x03, 0xF0, 0x7A, 0xF8, +0x3F, 0x4B, 0x80, 0x22, 0x19, 0x68, 0x52, 0x00, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0xA0, 0x23, 0xDB, 0x05, 0x99, 0x68, 0x9A, 0x60, 0x37, 0x4B, +0x3A, 0x4A, 0x19, 0x68, 0x0A, 0x40, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, +0xDB, 0x05, 0x99, 0x68, 0x9A, 0x60, 0x37, 0x4A, 0x01, 0x21, 0x11, 0x70, +0x19, 0x68, 0x80, 0x22, 0x52, 0x04, 0x0A, 0x43, 0x1A, 0x60, 0xC0, 0x46, +0xC0, 0x46, 0xC0, 0x46, 0xC0, 0x46, 0x62, 0xB6, 0x31, 0x4A, 0x19, 0x68, +0x0A, 0x40, 0x1A, 0x60, 0xBF, 0xF3, 0x6F, 0x8F, 0xFA, 0x20, 0xC0, 0x00, +0x02, 0xF0, 0x6E, 0xFC, 0x11, 0xE0, 0x00, 0x2B, 0x02, 0xD0, 0x2C, 0x49, +0x03, 0xF0, 0x48, 0xF8, 0x2B, 0x48, 0x02, 0xF0, 0x65, 0xFC, 0x2B, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x05, 0xD1, 0x2A, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x01, 0xD1, 0x02, 0xF0, 0x59, 0xFE, 0x1D, 0x4B, 0x02, 0x21, 0x1A, 0x68, +0x0A, 0x43, 0x1A, 0x60, 0x19, 0x68, 0x80, 0x22, 0xD2, 0x05, 0x90, 0x68, +0x91, 0x60, 0x23, 0x49, 0x01, 0x31, 0xC8, 0x7F, 0x08, 0x21, 0x00, 0x28, +0x06, 0xD0, 0x18, 0x68, 0x01, 0x43, 0x19, 0x60, 0x19, 0x68, 0x90, 0x68, +0x91, 0x60, 0x05, 0xE0, 0x18, 0x68, 0x88, 0x43, 0x18, 0x60, 0x19, 0x68, +0x90, 0x68, 0x91, 0x60, 0x1A, 0x68, 0x04, 0x21, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0xFA, 0x20, 0x99, 0x68, 0xC0, 0x00, +0x9A, 0x60, 0x02, 0xF0, 0x31, 0xFC, 0x06, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x06, 0xD0, 0x12, 0x4C, 0x0D, 0x20, 0x23, 0x68, 0x98, 0x47, 0x23, 0x68, +0x12, 0x20, 0x98, 0x47, 0x10, 0xBD, 0xC0, 0x46, 0xE8, 0x01, 0x00, 0x20, +0x68, 0x00, 0x00, 0x20, 0x14, 0x00, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0xF7, 0x58, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x20, 0xFF, 0xFE, 0xFF, 0xFF, +0x2C, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0x58, 0x00, 0x00, +0x40, 0x42, 0x0F, 0x00, 0xE5, 0x01, 0x00, 0x20, 0xE4, 0x01, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0xF8, 0x01, 0x00, 0x20, 0x10, 0xB5, 0x31, 0x4B, +0x02, 0x24, 0x19, 0x78, 0x30, 0x4B, 0x4A, 0xB2, 0x1B, 0x78, 0x00, 0x2B, +0x25, 0xD0, 0x2F, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x21, 0xD1, 0x2E, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x1D, 0xD1, 0x2D, 0x4B, 0xA2, 0x42, 0x07, 0xD0, +0x2C, 0x48, 0x80, 0x7B, 0x00, 0x28, 0x03, 0xD1, 0x2B, 0x48, 0x00, 0x68, +0x00, 0x28, 0x03, 0xD0, 0x00, 0x21, 0x19, 0x60, 0x01, 0x24, 0x0E, 0xE0, +0x28, 0x4A, 0x18, 0x68, 0x92, 0x68, 0x90, 0x42, 0x01, 0xDA, 0x01, 0x30, +0x18, 0x60, 0x00, 0x29, 0x36, 0xD0, 0x21, 0x4B, 0x00, 0x24, 0x1B, 0x68, +0x93, 0x42, 0x16, 0xDA, 0x30, 0xE0, 0x63, 0xB2, 0x93, 0x42, 0x2D, 0xD0, +0x01, 0x2B, 0x1D, 0xD0, 0x02, 0x2B, 0x02, 0xD0, 0x00, 0x2B, 0x0C, 0xD0, +0x24, 0xE0, 0x1D, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, +0x1B, 0x49, 0x02, 0xF0, 0xA5, 0xFF, 0x00, 0x20, 0x02, 0xF0, 0x78, 0xFB, +0x18, 0xE0, 0x17, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, +0x16, 0x49, 0x02, 0xF0, 0x99, 0xFF, 0x12, 0x4B, 0x58, 0x68, 0x02, 0xF0, +0x6B, 0xFB, 0x0B, 0xE0, 0x10, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, +0x00, 0x20, 0x11, 0x49, 0x02, 0xF0, 0x8C, 0xFF, 0x0B, 0x4B, 0x18, 0x68, +0x02, 0xF0, 0x5E, 0xFB, 0x02, 0x4B, 0x1C, 0x70, 0x02, 0xF0, 0x4C, 0xFB, +0x10, 0xBD, 0xC0, 0x46, 0x3C, 0x00, 0x00, 0x20, 0x1C, 0x03, 0x00, 0x20, +0xE3, 0x01, 0x00, 0x20, 0xE2, 0x01, 0x00, 0x20, 0x5C, 0x00, 0x00, 0x20, +0x70, 0x01, 0x00, 0x20, 0xE0, 0x00, 0x00, 0x20, 0xFC, 0x02, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0x05, 0x59, 0x00, 0x00, 0x0A, 0x59, 0x00, 0x00, +0x0F, 0x59, 0x00, 0x00, 0x08, 0xB5, 0x02, 0xF0, 0x5F, 0xFB, 0x08, 0xBD, +0x08, 0xB5, 0x02, 0xF0, 0x4D, 0xFB, 0x08, 0xBD, 0x08, 0xB5, 0x02, 0xF0, +0xE5, 0xFA, 0x80, 0x23, 0xDB, 0x05, 0x9A, 0x6C, 0x01, 0x21, 0x0A, 0x43, +0x9A, 0x64, 0xFF, 0xF7, 0xF1, 0xFF, 0x08, 0xBD, 0xF0, 0xB5, 0x87, 0xB0, +0xFF, 0xF7, 0xF0, 0xFF, 0x78, 0x4A, 0x79, 0x4C, 0x53, 0x78, 0x15, 0x78, +0x78, 0x48, 0x10, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x9A, 0x1C, 0x67, 0x46, +0xB2, 0x18, 0x79, 0x01, 0x52, 0x00, 0x12, 0x5B, 0xC9, 0x18, 0x4F, 0x00, +0x3A, 0x52, 0x73, 0x4A, 0x00, 0x27, 0x8F, 0x54, 0x00, 0x2B, 0xEF, 0xD1, +0x63, 0x46, 0x5A, 0x1E, 0xD2, 0xB2, 0x00, 0x2B, 0x04, 0xD0, 0x56, 0x1C, +0x2B, 0x1C, 0xB6, 0x01, 0x94, 0x46, 0xF3, 0xE7, 0x6C, 0x4B, 0x6D, 0x4C, +0x1B, 0x78, 0x6D, 0x48, 0x67, 0x49, 0x6D, 0x4A, 0x0E, 0xE0, 0x01, 0x3B, +0xDB, 0xB2, 0xE5, 0x5C, 0xC6, 0x5C, 0x01, 0x35, 0x02, 0x36, 0xAD, 0x01, +0xAD, 0x19, 0x6D, 0x00, 0x6E, 0x5A, 0x5D, 0x00, 0xAE, 0x52, 0x67, 0x4D, +0x00, 0x26, 0xEE, 0x54, 0x00, 0x2B, 0xEE, 0xD1, 0x65, 0x25, 0x03, 0x95, +0x5B, 0x4C, 0x66, 0xE0, 0xFF, 0xF7, 0xB2, 0xFF, 0x26, 0x78, 0x63, 0x78, +0x05, 0x96, 0x2D, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x58, 0x4F, 0xF0, 0x18, +0x04, 0x9D, 0x40, 0x00, 0x9A, 0x1C, 0xC0, 0x5B, 0xAD, 0x18, 0x54, 0x4F, +0x6D, 0x00, 0xEF, 0x5B, 0xC7, 0x1B, 0x04, 0xD4, 0x51, 0x4F, 0xED, 0x5B, +0x45, 0x1B, 0x02, 0x95, 0x03, 0xE0, 0x4F, 0x4F, 0xED, 0x5B, 0x2D, 0x1A, +0x02, 0x95, 0x04, 0x98, 0x87, 0x18, 0x4C, 0x48, 0x7F, 0x00, 0xC0, 0x5B, +0x4B, 0x4F, 0x84, 0x46, 0xF0, 0x18, 0x42, 0x00, 0x15, 0x1C, 0x62, 0x46, +0xEA, 0x53, 0x49, 0x4D, 0x2F, 0x5C, 0x02, 0x9D, 0xBD, 0x42, 0x00, 0xDA, +0x3D, 0x1C, 0x46, 0x4F, 0x3D, 0x54, 0x00, 0x2B, 0xD2, 0xD1, 0x0B, 0x1C, +0x59, 0x1E, 0xC9, 0xB2, 0x00, 0x2B, 0x05, 0xD0, 0x48, 0x1C, 0x80, 0x01, +0x05, 0x9B, 0x4E, 0x01, 0x04, 0x90, 0xF2, 0xE7, 0x3F, 0x4B, 0x3C, 0x4A, +0x1B, 0x78, 0x22, 0xE0, 0x3E, 0x4D, 0x01, 0x3B, 0xDB, 0xB2, 0x3E, 0x4F, +0xEE, 0x5C, 0x3E, 0x48, 0xFD, 0x5C, 0x59, 0x00, 0x01, 0x36, 0x09, 0x5A, +0x02, 0x35, 0xB0, 0x01, 0x40, 0x19, 0x40, 0x00, 0x87, 0x5A, 0x80, 0x5A, +0xCF, 0x1B, 0x01, 0xD4, 0x09, 0x1A, 0x00, 0xE0, 0x41, 0x1A, 0xB6, 0x01, +0x75, 0x19, 0x2F, 0x48, 0x6D, 0x00, 0x46, 0x5B, 0x33, 0x48, 0x5D, 0x00, +0x2E, 0x52, 0x33, 0x48, 0xC5, 0x5C, 0xA9, 0x42, 0x00, 0xDA, 0x29, 0x1C, +0xC1, 0x54, 0x00, 0x2B, 0xDA, 0xD1, 0x03, 0x9B, 0x01, 0x3B, 0xDB, 0xB2, +0x03, 0x93, 0x00, 0x2B, 0x92, 0xD1, 0x61, 0x78, 0x24, 0x78, 0x24, 0x4A, +0x04, 0x94, 0x1E, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x45, 0x01, 0xED, 0x18, +0x21, 0x4F, 0x6D, 0x00, 0xEE, 0x5B, 0x25, 0x88, 0xAC, 0x46, 0x9D, 0x1C, +0x66, 0x45, 0x09, 0xD9, 0x27, 0x88, 0xF6, 0x1B, 0x8F, 0x01, 0xBC, 0x46, +0x65, 0x44, 0x6D, 0x00, 0xB6, 0xB2, 0xAF, 0x5A, 0xAE, 0x52, 0x05, 0xE0, +0x8E, 0x01, 0x75, 0x19, 0x6D, 0x00, 0xAE, 0x5A, 0x00, 0x26, 0xAE, 0x52, +0x00, 0x2B, 0xE1, 0xD1, 0x01, 0x1C, 0x48, 0x1E, 0xC0, 0xB2, 0x00, 0x29, +0x05, 0xD0, 0x41, 0x1C, 0x18, 0x4F, 0xCC, 0x01, 0x04, 0x9B, 0xE4, 0x19, +0xF2, 0xE7, 0x11, 0x4B, 0x13, 0x4F, 0x1B, 0x78, 0x10, 0x4E, 0x15, 0x48, +0x10, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0xF5, 0x5C, 0x13, 0x49, 0xED, 0x01, +0x5A, 0x00, 0x6D, 0x18, 0xD4, 0x5B, 0x29, 0x88, 0x8C, 0x42, 0x03, 0xD9, +0x2D, 0x88, 0x64, 0x1B, 0x84, 0x52, 0x01, 0xE0, 0x00, 0x25, 0x85, 0x52, +0x00, 0x2B, 0xEC, 0xD1, 0x07, 0xB0, 0xF0, 0xBD, 0x0A, 0x03, 0x00, 0x20, +0x00, 0x40, 0x00, 0x40, 0xF8, 0x03, 0x00, 0x20, 0xB3, 0x0A, 0x00, 0x20, +0x7C, 0x09, 0x00, 0x20, 0x30, 0x75, 0x00, 0x00, 0x2A, 0x75, 0x00, 0x00, +0x14, 0x02, 0x00, 0x20, 0xA4, 0x0A, 0x00, 0x20, 0x02, 0x40, 0x00, 0x40, +0x3C, 0x0D, 0x00, 0x20, 0x82, 0x40, 0x00, 0x40, 0xF0, 0xB5, 0x87, 0xB0, +0x02, 0xF0, 0x4A, 0xF8, 0x02, 0xF0, 0x60, 0xF9, 0x00, 0x28, 0xFB, 0xD1, +0x52, 0x4B, 0x1B, 0x78, 0x02, 0x2B, 0x09, 0xD0, 0x51, 0x4B, 0x52, 0x49, +0x40, 0x33, 0x1A, 0x78, 0x53, 0x42, 0x54, 0x18, 0xE0, 0x54, 0x01, 0x33, +0x93, 0x42, 0xFA, 0xDD, 0x4C, 0x4E, 0x4E, 0x4F, 0x33, 0x1C, 0x40, 0x33, +0x1C, 0x78, 0x64, 0x42, 0x0C, 0xE0, 0xFA, 0x78, 0x80, 0x23, 0x12, 0x19, +0xD2, 0xB2, 0xDB, 0x05, 0x1A, 0x71, 0xFF, 0xF7, 0xC1, 0xFE, 0x28, 0x78, +0x20, 0x18, 0x03, 0xF0, 0xED, 0xFD, 0x01, 0x34, 0x35, 0x1C, 0x40, 0x35, +0x2B, 0x78, 0x9C, 0x42, 0xED, 0xDD, 0x00, 0x26, 0x25, 0xE0, 0x2C, 0x78, +0x2F, 0x1C, 0x64, 0x42, 0x40, 0x3F, 0x1A, 0xE0, 0x3E, 0x4B, 0xDA, 0x78, +0x80, 0x23, 0x12, 0x19, 0xDB, 0x05, 0xD2, 0xB2, 0x1A, 0x71, 0xFF, 0xF7, +0xA7, 0xFE, 0x2D, 0x78, 0x04, 0xA9, 0x65, 0x19, 0x05, 0xAA, 0x28, 0x1C, +0x03, 0xF0, 0xF2, 0xFD, 0x35, 0x49, 0x04, 0x9B, 0x4A, 0x5D, 0xFF, 0x2B, +0x00, 0xDD, 0xFF, 0x23, 0x9A, 0x42, 0x00, 0xDA, 0x1A, 0x1C, 0x4A, 0x55, +0x01, 0x34, 0x3D, 0x1C, 0x40, 0x35, 0x2B, 0x78, 0x9C, 0x42, 0xDF, 0xDD, +0x01, 0x36, 0x2F, 0x4A, 0x2B, 0x4D, 0x13, 0x78, 0x40, 0x35, 0x9E, 0x42, +0xD3, 0xDB, 0x01, 0xF0, 0xDF, 0xFF, 0x2C, 0x49, 0x2A, 0x78, 0x0D, 0x78, +0x2B, 0x49, 0x27, 0x48, 0x09, 0x78, 0x01, 0x23, 0x03, 0x91, 0x9B, 0x1A, +0x00, 0x21, 0x29, 0x4C, 0x10, 0x18, 0x94, 0x46, 0x11, 0xE0, 0xC6, 0x18, +0x72, 0x1E, 0x12, 0x78, 0xC7, 0x5C, 0x6A, 0x43, 0x02, 0x92, 0x03, 0x9A, +0x57, 0x43, 0x02, 0x9A, 0xD7, 0x19, 0x72, 0x78, 0x6A, 0x43, 0xBA, 0x18, +0x94, 0x42, 0x01, 0xDB, 0x94, 0xB2, 0x19, 0x1C, 0x01, 0x33, 0x9C, 0x45, +0xEB, 0xDC, 0x19, 0x4B, 0x1D, 0x4C, 0xDA, 0x78, 0x51, 0x18, 0xC9, 0xB2, +0x99, 0x70, 0x13, 0x4B, 0x18, 0x78, 0x00, 0x28, 0x05, 0xD1, 0x23, 0x78, +0x00, 0x2B, 0x02, 0xD0, 0x18, 0x49, 0x02, 0xF0, 0xB7, 0xFD, 0x23, 0x78, +0x00, 0x2B, 0x0B, 0xD0, 0x0D, 0x4B, 0x00, 0x20, 0x40, 0x33, 0x19, 0x78, +0x0C, 0x4A, 0x49, 0x00, 0x01, 0x31, 0xC9, 0xB2, 0x01, 0x23, 0x00, 0x90, +0x02, 0xF0, 0x50, 0xFD, 0x0E, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, +0x01, 0x21, 0x00, 0x20, 0x0D, 0x4A, 0x0B, 0x1C, 0x00, 0x90, 0x02, 0xF0, +0x45, 0xFD, 0x07, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, 0xE0, 0x01, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x93, 0x01, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, +0x87, 0x0D, 0x00, 0x20, 0x54, 0x00, 0x00, 0x20, 0x55, 0x00, 0x00, 0x20, +0xFF, 0xFF, 0x00, 0x00, 0xEB, 0x01, 0x00, 0x20, 0x16, 0x59, 0x00, 0x00, +0xAC, 0x0A, 0x00, 0x20, 0x13, 0xB5, 0x24, 0x4B, 0x24, 0x4C, 0x1B, 0x68, +0x00, 0x2B, 0x0E, 0xD0, 0x23, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, +0x21, 0x49, 0x02, 0xF0, 0x77, 0xFD, 0xFF, 0xF7, 0x69, 0xFA, 0x23, 0x78, +0x00, 0x2B, 0x02, 0xD1, 0x02, 0xF0, 0x38, 0xF8, 0xFE, 0xE7, 0x23, 0x78, +0x00, 0x2B, 0x09, 0xD0, 0x1B, 0x4C, 0x23, 0x68, 0xDA, 0x00, 0x05, 0xD5, +0xFF, 0xF7, 0x5A, 0xFA, 0x22, 0x68, 0x19, 0x4B, 0x13, 0x40, 0x23, 0x60, +0x14, 0x4C, 0x23, 0x78, 0x00, 0x2B, 0x22, 0xD0, 0x14, 0x4B, 0x1B, 0x68, +0x5A, 0x01, 0x1E, 0xD5, 0x14, 0x49, 0x00, 0x20, 0x02, 0xF0, 0x56, 0xFD, +0x13, 0x4B, 0x14, 0x4A, 0x19, 0x88, 0x11, 0x80, 0x59, 0x88, 0x51, 0x80, +0x99, 0x88, 0x91, 0x80, 0xDB, 0x88, 0xD3, 0x80, 0x10, 0x4B, 0x1B, 0x78, +0x13, 0x81, 0x23, 0x78, 0x00, 0x2B, 0x05, 0xD0, 0x00, 0x20, 0x05, 0x21, +0x02, 0x23, 0x00, 0x90, 0x02, 0xF0, 0xE8, 0xFC, 0x05, 0x4B, 0x0B, 0x4A, +0x19, 0x68, 0x0A, 0x40, 0x1A, 0x60, 0x13, 0xBD, 0x0C, 0x1E, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0x1C, 0x59, 0x00, 0x00, 0x58, 0x00, 0x00, 0x20, +0xFF, 0xFF, 0xFF, 0xEF, 0x23, 0x59, 0x00, 0x00, 0x04, 0x02, 0x00, 0x20, +0x54, 0x11, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xFB, +0x10, 0xB5, 0x02, 0x28, 0x04, 0xD0, 0x03, 0x28, 0x45, 0xD0, 0x01, 0x28, +0x33, 0xD1, 0x15, 0xE0, 0xFF, 0xF7, 0xF2, 0xF9, 0x29, 0x4B, 0x2A, 0x4C, +0x40, 0x33, 0x1B, 0x78, 0x29, 0x49, 0x50, 0x22, 0x23, 0x70, 0x29, 0x48, +0x04, 0xF0, 0xA0, 0xF9, 0x28, 0x4B, 0x0D, 0x20, 0x1B, 0x68, 0x98, 0x47, +0xFF, 0xF7, 0xF0, 0xF9, 0x23, 0x78, 0x10, 0x2B, 0x1A, 0xD1, 0x14, 0xE0, +0xFF, 0xF7, 0xDC, 0xF9, 0x1E, 0x4B, 0x1F, 0x4C, 0x40, 0x33, 0x1B, 0x78, +0x21, 0x49, 0x50, 0x22, 0x23, 0x70, 0x1E, 0x48, 0x04, 0xF0, 0x8A, 0xF9, +0x1D, 0x4B, 0x0C, 0x20, 0x1B, 0x68, 0x98, 0x47, 0xFF, 0xF7, 0xDA, 0xF9, +0x23, 0x78, 0x10, 0x2B, 0x04, 0xD1, 0x1B, 0x4B, 0xDA, 0x78, 0x9A, 0x70, +0x02, 0xF0, 0xD1, 0xFA, 0x02, 0xF0, 0x54, 0xFA, 0x20, 0xE0, 0x18, 0x4B, +0x1A, 0x78, 0x00, 0x2A, 0x05, 0xD0, 0x17, 0x4A, 0x11, 0x68, 0x01, 0x31, +0x11, 0x60, 0x00, 0x22, 0x1A, 0x70, 0x15, 0x4B, 0x1A, 0x68, 0x13, 0x2A, +0x05, 0xDD, 0x00, 0x22, 0x1A, 0x60, 0x0A, 0x4B, 0x10, 0x22, 0x1A, 0x70, +0x0C, 0xE0, 0x0F, 0x4B, 0x1A, 0x68, 0x3B, 0x2A, 0x08, 0xDD, 0x00, 0x22, +0x1A, 0x60, 0x0E, 0x4B, 0x01, 0x20, 0x1B, 0x68, 0x98, 0x47, 0x0D, 0x4B, +0x01, 0x22, 0x1A, 0x70, 0x10, 0xBD, 0xC0, 0x46, 0xAE, 0x09, 0x00, 0x20, +0x1D, 0x03, 0x00, 0x20, 0x4A, 0x74, 0x00, 0x00, 0x48, 0x0D, 0x00, 0x20, +0xF8, 0x01, 0x00, 0x20, 0x9A, 0x74, 0x00, 0x00, 0xAA, 0x0A, 0x00, 0x20, +0xC4, 0x01, 0x00, 0x20, 0xC0, 0x01, 0x00, 0x20, 0xBC, 0x01, 0x00, 0x20, +0x6C, 0x00, 0x00, 0x20, 0xE7, 0x01, 0x00, 0x20, 0x10, 0xB5, 0x0C, 0x4B, +0x01, 0x22, 0x99, 0x79, 0x00, 0x23, 0x00, 0xE0, 0x23, 0x1C, 0x5C, 0x1C, +0x10, 0x1C, 0xE4, 0xB2, 0x98, 0x40, 0x81, 0x42, 0xF8, 0xDA, 0x07, 0x4A, +0x07, 0x21, 0x13, 0x71, 0x80, 0x22, 0xD2, 0x05, 0x0B, 0x40, 0x19, 0x02, +0x10, 0x6C, 0x04, 0x4B, 0x03, 0x40, 0x0B, 0x43, 0x13, 0x64, 0x10, 0xBD, +0x48, 0x0D, 0x00, 0x20, 0x5C, 0x00, 0x00, 0x20, 0xFF, 0xF8, 0xFF, 0xFF, +0x06, 0x4B, 0x07, 0x22, 0xD9, 0x79, 0x80, 0x23, 0xDB, 0x05, 0x18, 0x6C, +0x11, 0x40, 0x04, 0x4A, 0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x64, +0x70, 0x47, 0xC0, 0x46, 0x48, 0x0D, 0x00, 0x20, 0xFF, 0xF8, 0xFF, 0xFF, +0xF0, 0xB5, 0x8D, 0xB0, 0x04, 0x90, 0xFF, 0xF7, 0xC9, 0xFF, 0xC7, 0x4B, +0xC7, 0x48, 0xDE, 0x78, 0x00, 0x21, 0x05, 0x96, 0x9C, 0x78, 0x07, 0xE0, +0x01, 0x3B, 0xDB, 0xB2, 0xEE, 0x18, 0x76, 0x00, 0x31, 0x52, 0x00, 0x2B, +0xF8, 0xD1, 0x05, 0x92, 0x05, 0x9A, 0x05, 0x9E, 0x01, 0x3A, 0xD2, 0xB2, +0x00, 0x2E, 0x02, 0xD0, 0x23, 0x1C, 0x55, 0x01, 0xF3, 0xE7, 0x04, 0x9F, +0x00, 0x2F, 0x05, 0xD0, 0xBB, 0x4B, 0x05, 0x9E, 0x5B, 0x7B, 0x06, 0x96, +0x03, 0x93, 0x04, 0xE0, 0xB9, 0x4B, 0x02, 0x27, 0x9B, 0x78, 0x06, 0x97, +0x03, 0x93, 0x68, 0x46, 0x0C, 0x21, 0x0B, 0x56, 0xB2, 0x4C, 0x0B, 0x93, +0x5B, 0x42, 0x09, 0x93, 0xAA, 0xE0, 0x6A, 0x46, 0x18, 0x23, 0x9A, 0x56, +0xE6, 0x7A, 0x27, 0x1C, 0x02, 0x92, 0x0D, 0xE0, 0x30, 0x1C, 0x00, 0x21, +0x2A, 0x1C, 0x02, 0x9B, 0x02, 0xF0, 0x4C, 0xF9, 0x30, 0x1C, 0x01, 0x21, +0x2A, 0x1C, 0x02, 0x9B, 0x02, 0xF0, 0x46, 0xF9, 0x01, 0x36, 0xF6, 0xB2, +0xBB, 0x7A, 0xFA, 0x7A, 0xD2, 0x18, 0x3B, 0x1C, 0x96, 0x42, 0xEB, 0xDB, +0x04, 0x9E, 0x00, 0x2E, 0x00, 0xD1, 0x0E, 0x3D, 0x68, 0x46, 0x18, 0x21, +0x08, 0x56, 0x5E, 0x7B, 0x9E, 0x4F, 0x02, 0x90, 0x0D, 0xE0, 0x30, 0x1C, +0x00, 0x21, 0x2A, 0x1C, 0x02, 0x9B, 0x02, 0xF0, 0x2D, 0xF9, 0x30, 0x1C, +0x01, 0x21, 0x2A, 0x1C, 0x02, 0x9B, 0x02, 0xF0, 0x27, 0xF9, 0x01, 0x36, +0xF6, 0xB2, 0x7A, 0x7B, 0x3B, 0x7B, 0xD3, 0x18, 0x9E, 0x42, 0xEC, 0xDB, +0xFF, 0xF7, 0xAE, 0xFC, 0x96, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, +0x01, 0x23, 0x18, 0x1C, 0x19, 0x1C, 0x0B, 0xAA, 0x00, 0x93, 0x02, 0xF0, +0xAD, 0xFB, 0x00, 0x25, 0x8C, 0x4E, 0x90, 0x4F, 0x0E, 0xE0, 0x3B, 0x78, +0x00, 0x2B, 0x09, 0xD0, 0x8E, 0x4B, 0xEA, 0x01, 0xD2, 0x18, 0x00, 0x23, +0xB1, 0x78, 0x01, 0x20, 0x00, 0x93, 0x02, 0x23, 0x02, 0xF0, 0x9C, 0xFB, +0x01, 0x35, 0xED, 0xB2, 0xF3, 0x78, 0x9D, 0x42, 0xED, 0xD3, 0x0B, 0x9A, +0xB6, 0x78, 0xD2, 0xB2, 0x02, 0x96, 0x07, 0x92, 0x80, 0x4D, 0x39, 0xE0, +0x01, 0x3B, 0xDB, 0xB2, 0x08, 0x9E, 0x99, 0x1C, 0x71, 0x18, 0x82, 0x4F, +0x49, 0x00, 0xCE, 0x5B, 0xD1, 0x18, 0x48, 0x00, 0x40, 0x5B, 0xB7, 0xB2, +0xB8, 0x42, 0x14, 0xDC, 0xC0, 0x1B, 0x01, 0x1C, 0x80, 0x31, 0x01, 0xDA, +0x80, 0x20, 0x40, 0x42, 0xD7, 0x18, 0x7F, 0x28, 0x00, 0xDD, 0x7F, 0x20, +0x79, 0x49, 0x78, 0x54, 0xD1, 0x18, 0x48, 0x00, 0x2E, 0x52, 0x1C, 0x27, +0x6E, 0x46, 0x77, 0x48, 0xBE, 0x5D, 0x0E, 0x54, 0x13, 0xE0, 0x04, 0x9E, +0x00, 0x2E, 0x10, 0xD0, 0x74, 0x4E, 0xB0, 0x42, 0x08, 0xD0, 0x71, 0x4E, +0x8E, 0x57, 0x80, 0x19, 0x87, 0x42, 0x03, 0xDA, 0x6F, 0x48, 0x0E, 0x5C, +0x01, 0x36, 0x0E, 0x54, 0xD1, 0x18, 0x01, 0x27, 0x49, 0x00, 0x7F, 0x42, +0x6F, 0x52, 0x00, 0x2B, 0xC6, 0xD1, 0x63, 0x46, 0x5E, 0x1E, 0xF6, 0xB2, +0x00, 0x2B, 0x06, 0xD0, 0x72, 0x1C, 0x92, 0x01, 0x08, 0x92, 0x02, 0x9B, +0x72, 0x01, 0xB4, 0x46, 0xF1, 0xE7, 0x0B, 0x9B, 0x01, 0x3B, 0x0B, 0x93, +0x0B, 0x9D, 0x09, 0x9E, 0xB5, 0x42, 0x00, 0xDB, 0x4F, 0xE7, 0x04, 0x9F, +0x00, 0x2F, 0x45, 0xD0, 0xA0, 0x78, 0xE3, 0x78, 0x04, 0x90, 0x61, 0x78, +0x56, 0x4A, 0x06, 0x91, 0x24, 0x78, 0x02, 0x94, 0x11, 0x7C, 0xD0, 0x7A, +0x5B, 0x4C, 0x08, 0x18, 0xC0, 0xB2, 0x07, 0x90, 0x12, 0x7B, 0x89, 0x18, +0xC9, 0xB2, 0x08, 0x91, 0x55, 0x4A, 0x28, 0xE0, 0x03, 0x9E, 0x01, 0x3B, +0xDB, 0xB2, 0x00, 0x2E, 0x01, 0xD1, 0xC7, 0x18, 0xD6, 0x55, 0x06, 0x9E, +0xB1, 0x42, 0x02, 0xD2, 0x02, 0x9F, 0xBB, 0x42, 0x0C, 0xD3, 0xEF, 0x18, +0xC6, 0x18, 0x09, 0x97, 0x97, 0x5D, 0xBC, 0x46, 0x09, 0x9F, 0xE7, 0x5D, +0xBC, 0x44, 0x08, 0x9F, 0xBC, 0x44, 0x67, 0x46, 0x97, 0x55, 0x0B, 0xE0, +0xEF, 0x18, 0xC6, 0x18, 0x09, 0x97, 0x97, 0x5D, 0xBC, 0x46, 0x09, 0x9F, +0xE7, 0x5D, 0xBC, 0x44, 0x07, 0x9F, 0xBC, 0x44, 0x67, 0x46, 0x97, 0x55, +0x00, 0x2B, 0xD7, 0xD1, 0x0B, 0x1C, 0x59, 0x1E, 0xC9, 0xB2, 0x00, 0x2B, +0x3E, 0xD0, 0x26, 0x25, 0x04, 0x9B, 0x48, 0x01, 0x4D, 0x43, 0xF3, 0xE7, +0x63, 0x7C, 0xE2, 0x79, 0x07, 0x25, 0x9A, 0x18, 0x03, 0x92, 0x34, 0x4A, +0xA0, 0x7B, 0x02, 0x21, 0x52, 0x5E, 0x26, 0x79, 0xAD, 0x1A, 0x6D, 0x00, +0x86, 0x19, 0xED, 0xB2, 0x34, 0x49, 0x84, 0x46, 0x09, 0xE0, 0xB8, 0x18, +0x44, 0x5C, 0x01, 0x32, 0x2C, 0x19, 0x44, 0x54, 0xD2, 0xB2, 0xB2, 0x42, +0xF7, 0xDB, 0x01, 0x33, 0xDB, 0xB2, 0x03, 0x9A, 0x93, 0x42, 0x02, 0xDA, +0x62, 0x46, 0x5F, 0x01, 0xF5, 0xE7, 0x23, 0x4A, 0x2A, 0x49, 0x10, 0x7C, +0xD3, 0x7B, 0x56, 0x79, 0x95, 0x79, 0x9E, 0x19, 0x45, 0x19, 0x84, 0x46, +0x09, 0xE0, 0xB8, 0x18, 0x44, 0x5C, 0x01, 0x32, 0x0E, 0x3C, 0x44, 0x54, +0xD2, 0xB2, 0xAA, 0x42, 0xF7, 0xDB, 0x01, 0x33, 0xDB, 0xB2, 0xB3, 0x42, +0x02, 0xDA, 0x62, 0x46, 0x5F, 0x01, 0xF6, 0xE7, 0x1A, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x13, 0xD0, 0x05, 0x20, 0x1F, 0x49, 0x02, 0xF0, 0x10, 0xFB, +0x0E, 0xE0, 0x2B, 0x78, 0x00, 0x2B, 0x08, 0xD0, 0x18, 0x4B, 0x72, 0x01, +0xA1, 0x78, 0xD2, 0x18, 0x05, 0x20, 0x01, 0x23, 0x00, 0x93, 0x02, 0xF0, +0xAB, 0xFA, 0x01, 0x36, 0xF6, 0xB2, 0x02, 0xE0, 0x0A, 0x4C, 0x0E, 0x4D, +0x05, 0x9E, 0xE3, 0x78, 0xB3, 0x42, 0xEA, 0xD8, 0x00, 0x21, 0x01, 0x20, +0x0A, 0x1C, 0x40, 0x42, 0x02, 0x23, 0x02, 0xF0, 0x01, 0xF8, 0x01, 0x20, +0x40, 0x42, 0x01, 0x21, 0x00, 0x22, 0x02, 0x23, 0x01, 0xF0, 0xFA, 0xFF, +0xA4, 0x78, 0x25, 0xE0, 0x0A, 0x03, 0x00, 0x20, 0xF8, 0x03, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x04, 0x02, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0x84, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x64, 0x0E, 0x00, 0x20, +0xB3, 0x0A, 0x00, 0x20, 0xFF, 0xFF, 0x00, 0x00, 0x36, 0x75, 0x00, 0x00, +0x2A, 0x59, 0x00, 0x00, 0x01, 0x3C, 0x00, 0x21, 0xE4, 0xB2, 0x0A, 0x1C, +0x20, 0x1C, 0x01, 0x23, 0x01, 0xF0, 0xD8, 0xFF, 0x01, 0x21, 0x20, 0x1C, +0x00, 0x22, 0x0B, 0x1C, 0x01, 0xF0, 0xD2, 0xFF, 0x00, 0x2C, 0xEF, 0xD1, +0xFF, 0xF7, 0x30, 0xFE, 0x0D, 0xB0, 0xF0, 0xBD, 0x08, 0xB5, 0x03, 0xF0, +0xBF, 0xFD, 0x05, 0x4B, 0x01, 0x20, 0x1B, 0x68, 0x98, 0x47, 0x01, 0x20, +0x04, 0xF0, 0x1E, 0xF9, 0x01, 0xF0, 0xD6, 0xFD, 0x08, 0xBD, 0xC0, 0x46, +0xF8, 0x01, 0x00, 0x20, 0xF7, 0xB5, 0x2C, 0x4A, 0x00, 0x20, 0x10, 0x60, +0x2B, 0x4A, 0x2C, 0x4E, 0x11, 0x8C, 0x2C, 0x4A, 0x11, 0x60, 0x72, 0x1D, +0xD2, 0x7F, 0xF1, 0x7D, 0x50, 0x1E, 0x44, 0x42, 0x60, 0x41, 0x29, 0x4C, +0x08, 0x1A, 0x00, 0x90, 0x20, 0x60, 0xB0, 0x1D, 0xC5, 0x7F, 0x37, 0x7E, +0x6B, 0x1E, 0x58, 0x42, 0x58, 0x41, 0x3B, 0x1A, 0x01, 0x93, 0x63, 0x60, +0x01, 0x2A, 0x02, 0xD1, 0x00, 0x20, 0x20, 0x81, 0x05, 0xE0, 0x26, 0x23, +0xF0, 0x5E, 0x49, 0x00, 0x03, 0xF0, 0xB4, 0xFE, 0x20, 0x81, 0x01, 0x2D, +0x02, 0xD1, 0x00, 0x23, 0x63, 0x81, 0x05, 0xE0, 0x28, 0x23, 0xF0, 0x5E, +0x79, 0x00, 0x03, 0xF0, 0xA9, 0xFE, 0x60, 0x81, 0x15, 0x4F, 0x01, 0x9B, +0x28, 0x20, 0x3E, 0x5E, 0x59, 0x00, 0x70, 0x00, 0x80, 0x19, 0x03, 0xF0, +0x9F, 0xFE, 0x40, 0x43, 0x12, 0x4C, 0x43, 0x00, 0x80, 0x00, 0xE3, 0x60, +0xC3, 0x18, 0x23, 0x61, 0x26, 0x20, 0x3D, 0x5E, 0x00, 0x9B, 0x68, 0x00, +0x59, 0x00, 0x40, 0x19, 0x03, 0xF0, 0x90, 0xFE, 0x2C, 0x37, 0x60, 0x61, +0xA0, 0x61, 0x3B, 0x78, 0x00, 0x2B, 0x02, 0xD1, 0xE6, 0x61, 0x25, 0x62, +0x01, 0xE0, 0xE5, 0x61, 0x26, 0x62, 0x07, 0x4B, 0x01, 0x22, 0x52, 0x42, +0x5A, 0x60, 0xF7, 0xBD, 0x9C, 0x0D, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x20, 0x02, 0x00, 0x20, 0x24, 0x09, 0x00, 0x20, +0xCC, 0x00, 0x00, 0x20, 0xF0, 0xB5, 0x24, 0x4B, 0x87, 0xB0, 0x1E, 0x7E, +0xDB, 0x7D, 0x72, 0x1C, 0xD9, 0x1C, 0x02, 0x33, 0x03, 0x93, 0x05, 0x92, +0x00, 0x23, 0x20, 0x4A, 0x04, 0x91, 0x18, 0x1C, 0x05, 0x9C, 0xE5, 0x1A, +0xEF, 0x01, 0x01, 0x97, 0xBC, 0x5A, 0xB8, 0x52, 0x04, 0x9C, 0xAD, 0x01, +0x29, 0x19, 0x4F, 0x00, 0xBC, 0x5A, 0x1A, 0x4C, 0xB8, 0x52, 0x00, 0x27, +0x2F, 0x55, 0x0F, 0x55, 0x01, 0x99, 0x18, 0x4F, 0x01, 0x33, 0xCF, 0x19, +0x02, 0x97, 0x39, 0x88, 0x38, 0x80, 0x03, 0x99, 0x6F, 0x18, 0x79, 0x00, +0x01, 0x91, 0x89, 0x5A, 0x01, 0x99, 0x88, 0x52, 0x12, 0x49, 0x6D, 0x18, +0x00, 0x21, 0x29, 0x70, 0x39, 0x55, 0xF7, 0x1A, 0x0C, 0x4D, 0x01, 0x37, +0xD8, 0xDA, 0x00, 0x22, 0x01, 0x36, 0x03, 0x9B, 0x11, 0x1C, 0xB6, 0x01, +0x58, 0x00, 0x2F, 0x5A, 0x2A, 0x52, 0xF0, 0x18, 0x47, 0x00, 0xEC, 0x5B, +0xEA, 0x53, 0x06, 0x4F, 0xF9, 0x54, 0x01, 0x3B, 0x39, 0x54, 0x01, 0x2B, +0xF2, 0xD1, 0x07, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, 0xAE, 0x09, 0x00, 0x20, +0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x40, 0x02, 0x40, 0x00, 0x40, +0x01, 0x20, 0x00, 0x40, 0xF7, 0xB5, 0x0D, 0x4B, 0x19, 0x7E, 0xDE, 0x7D, +0x48, 0x1C, 0x01, 0x36, 0x00, 0x23, 0x01, 0x90, 0x01, 0x9C, 0x32, 0x1C, +0xE7, 0x1A, 0xBF, 0x01, 0x95, 0x1C, 0xAC, 0x46, 0xBC, 0x44, 0x07, 0x4C, +0x00, 0x25, 0x60, 0x46, 0x01, 0x3A, 0x05, 0x55, 0x50, 0x1C, 0xF5, 0xDA, +0x01, 0x33, 0xCA, 0x1A, 0x01, 0x32, 0xED, 0xDA, 0xF7, 0xBD, 0xC0, 0x46, +0xAE, 0x09, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, 0x00, 0xB5, 0x0D, 0x4B, +0x08, 0x22, 0x9B, 0x5E, 0x0C, 0x4A, 0x11, 0x1C, 0x35, 0x31, 0x09, 0x78, +0x12, 0x7F, 0x4B, 0x43, 0x52, 0xB2, 0x9B, 0x11, 0x93, 0x42, 0x00, 0xDA, +0x13, 0x1C, 0x08, 0x4A, 0x13, 0x60, 0x80, 0x22, 0xD2, 0x05, 0x1B, 0x05, +0x19, 0x09, 0x90, 0x69, 0x05, 0x4B, 0x03, 0x40, 0x0B, 0x43, 0x93, 0x61, +0x00, 0xBD, 0xC0, 0x46, 0x70, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x38, 0x0D, 0x00, 0x20, 0xFF, 0xFF, 0x00, 0xF0, 0xF0, 0xB5, 0xA9, 0x4A, +0xA9, 0x48, 0x11, 0x68, 0x07, 0x68, 0x93, 0xB0, 0x8C, 0x46, 0x0D, 0x22, +0x00, 0x21, 0x7F, 0x25, 0xFF, 0x24, 0x01, 0x97, 0x90, 0x00, 0x83, 0x18, +0xA4, 0x4E, 0x5B, 0x00, 0xF3, 0x18, 0x99, 0x87, 0x00, 0x27, 0x38, 0x33, +0x1F, 0x72, 0x67, 0x46, 0x39, 0x50, 0x01, 0x3A, 0x01, 0x9F, 0xD2, 0xB2, +0x39, 0x50, 0x00, 0x26, 0xDD, 0x72, 0x5D, 0x72, 0x1C, 0x73, 0x9C, 0x72, +0xD9, 0x80, 0xFF, 0x2A, 0xE8, 0xD1, 0x9B, 0x4A, 0x9B, 0x4B, 0x11, 0x7E, +0x98, 0x68, 0x9B, 0x4C, 0x97, 0x4D, 0x01, 0x39, 0x04, 0x90, 0xA6, 0x81, +0x2E, 0x60, 0x88, 0x42, 0x02, 0xDA, 0x01, 0x30, 0x04, 0x90, 0x98, 0x60, +0xDE, 0x68, 0x11, 0x96, 0x00, 0x2E, 0x02, 0xDD, 0x01, 0x3E, 0x11, 0x96, +0xDE, 0x60, 0xD1, 0x7D, 0x1A, 0x68, 0x01, 0x39, 0x8A, 0x42, 0x01, 0xDA, +0x01, 0x32, 0x1A, 0x60, 0x5A, 0x68, 0x00, 0x2A, 0x01, 0xDD, 0x01, 0x3A, +0x5A, 0x60, 0x04, 0x9F, 0x11, 0x98, 0x87, 0x42, 0x00, 0xDA, 0xA3, 0xE0, +0x19, 0x68, 0x5B, 0x68, 0x84, 0x4A, 0x06, 0x93, 0x88, 0x4B, 0x12, 0x68, +0x1B, 0x68, 0x86, 0x4C, 0x0D, 0x93, 0x80, 0x4B, 0x10, 0x91, 0x1B, 0x68, +0x09, 0x92, 0x0A, 0x93, 0xA4, 0x89, 0x84, 0x48, 0x0C, 0x94, 0x06, 0x9D, +0x10, 0x9E, 0xB5, 0x42, 0x00, 0xDD, 0x81, 0xE0, 0x04, 0x9A, 0x6F, 0x46, +0x10, 0x21, 0x01, 0x32, 0xCF, 0x5D, 0x92, 0x01, 0x33, 0x1C, 0x02, 0x92, +0x07, 0x97, 0x05, 0xE0, 0x00, 0x27, 0x2F, 0x54, 0x06, 0x9F, 0x01, 0x3B, +0x9F, 0x42, 0x71, 0xDC, 0x02, 0x99, 0x9C, 0x1C, 0x0D, 0x19, 0x2A, 0x5C, +0x77, 0x4E, 0x69, 0x00, 0x89, 0x5B, 0x0E, 0x2A, 0xF0, 0xD8, 0x0D, 0x9D, +0x49, 0x1B, 0x00, 0x2A, 0x00, 0xD1, 0x71, 0xE0, 0x01, 0x3A, 0xD4, 0xB2, +0x09, 0x9E, 0x04, 0x9F, 0xA2, 0x00, 0xB5, 0x18, 0x4F, 0x43, 0x2E, 0x68, +0xB4, 0x46, 0x67, 0x44, 0x2F, 0x60, 0x0A, 0x9D, 0x0E, 0x1C, 0xAF, 0x18, +0x3D, 0x68, 0x5E, 0x43, 0xAC, 0x46, 0x15, 0x19, 0x6D, 0x00, 0x01, 0x95, +0x62, 0x4D, 0x66, 0x44, 0xAC, 0x46, 0x01, 0x9D, 0x3E, 0x60, 0xAC, 0x44, +0x65, 0x46, 0xAF, 0x8F, 0x38, 0x35, 0x2E, 0x7A, 0xCF, 0x19, 0x03, 0x96, +0x09, 0x26, 0xAE, 0x57, 0xAF, 0x80, 0x01, 0x96, 0x0C, 0x9E, 0x6F, 0x46, +0xB4, 0x46, 0x01, 0x26, 0xB4, 0x44, 0x03, 0x9E, 0x01, 0x36, 0x03, 0x96, +0x66, 0x46, 0xB6, 0xB2, 0x0C, 0x96, 0x0C, 0x26, 0xF7, 0x5D, 0x04, 0x9E, +0x2F, 0x72, 0x01, 0x9F, 0xBE, 0x42, 0x00, 0xDA, 0x6E, 0x72, 0x51, 0x4E, +0x15, 0x19, 0x6D, 0x00, 0x75, 0x19, 0x38, 0x35, 0x0A, 0x26, 0xAE, 0x57, +0x04, 0x9F, 0xB7, 0x42, 0x00, 0xDD, 0xAF, 0x72, 0x4B, 0x4E, 0x15, 0x19, +0x6D, 0x00, 0x75, 0x19, 0x38, 0x35, 0x0B, 0x26, 0xAE, 0x57, 0xB3, 0x42, +0x00, 0xDA, 0xEB, 0x72, 0x15, 0x19, 0x46, 0x4F, 0x6D, 0x00, 0x7D, 0x19, +0x38, 0x35, 0x0C, 0x26, 0xAE, 0x57, 0xB3, 0x42, 0x00, 0xDD, 0x2B, 0x73, +0x12, 0x19, 0x41, 0x4C, 0x52, 0x00, 0xA2, 0x18, 0x3E, 0x25, 0x54, 0x5F, +0x38, 0x32, 0xA1, 0x42, 0x8E, 0xDD, 0x06, 0x9F, 0x01, 0x3B, 0xD1, 0x80, +0x9F, 0x42, 0x8D, 0xDD, 0x04, 0x99, 0x11, 0x9A, 0x01, 0x39, 0x04, 0x91, +0x91, 0x42, 0x00, 0xDB, 0x71, 0xE7, 0x6B, 0x46, 0x30, 0x24, 0xE4, 0x5A, +0x38, 0x4B, 0x9C, 0x81, 0x13, 0xB0, 0xF0, 0xBD, 0x02, 0x39, 0xCA, 0x43, +0xD2, 0x17, 0x11, 0x40, 0x03, 0x91, 0x04, 0x9E, 0x03, 0x9F, 0x71, 0x43, +0x5F, 0x43, 0x0E, 0x91, 0x00, 0x25, 0xD9, 0xB2, 0x0F, 0x97, 0x05, 0x91, +0x03, 0x22, 0x01, 0x95, 0x9C, 0x46, 0x08, 0x94, 0x31, 0x4E, 0x32, 0x4F, +0x07, 0x9C, 0xB1, 0x5C, 0x05, 0x9D, 0xBB, 0x5C, 0x61, 0x18, 0xEB, 0x18, +0x49, 0xB2, 0x01, 0x31, 0x5B, 0xB2, 0x89, 0x01, 0x02, 0x33, 0xCB, 0x18, +0x1C, 0x5C, 0x65, 0xB2, 0x69, 0x1E, 0x0D, 0x29, 0x27, 0xD8, 0x08, 0x9B, +0x02, 0x9F, 0x8E, 0x00, 0xFF, 0x18, 0x0B, 0x97, 0x09, 0x9F, 0x71, 0x18, +0xBB, 0x19, 0x0A, 0x9F, 0x49, 0x00, 0xBF, 0x19, 0x1B, 0x4E, 0x00, 0x97, +0x01, 0x9F, 0x71, 0x18, 0x38, 0x31, 0x00, 0x2F, 0x1A, 0xD1, 0xE4, 0xB2, +0x01, 0x94, 0x0B, 0x9D, 0x0E, 0x34, 0xE4, 0xB2, 0x2C, 0x54, 0x1C, 0x68, +0x0E, 0x9E, 0x00, 0x9F, 0xA4, 0x19, 0x1C, 0x60, 0x3B, 0x68, 0x0F, 0x9C, +0x03, 0x9D, 0x1B, 0x19, 0x3B, 0x60, 0x8C, 0x88, 0x0B, 0x7A, 0x2C, 0x19, +0x01, 0x33, 0x8C, 0x80, 0x0B, 0x72, 0x53, 0x1E, 0x00, 0x2A, 0x10, 0xD0, +0xDA, 0xB2, 0xBF, 0xE7, 0x02, 0x9E, 0x08, 0x99, 0x01, 0x9C, 0x73, 0x18, +0x1F, 0x2C, 0xF4, 0xD0, 0xAC, 0x42, 0xF2, 0xD0, 0x1F, 0x25, 0x1F, 0x26, +0x1D, 0x54, 0x01, 0x96, 0x53, 0x1E, 0x00, 0x2A, 0xEE, 0xD1, 0x63, 0x46, +0x18, 0xE7, 0xC0, 0x46, 0x44, 0x00, 0x00, 0x20, 0x48, 0x00, 0x00, 0x20, +0x24, 0x02, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0xE4, 0x10, 0x00, 0x20, +0x70, 0x01, 0x00, 0x20, 0x38, 0x0D, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, +0x00, 0x40, 0x00, 0x40, 0xF4, 0x59, 0x00, 0x00, 0xF0, 0x59, 0x00, 0x00, +0xF0, 0xB5, 0x89, 0xB0, 0x0F, 0x23, 0x46, 0x49, 0xFF, 0x22, 0x02, 0xE0, +0x58, 0x18, 0x01, 0x38, 0x02, 0x70, 0x01, 0x3B, 0x00, 0x2B, 0xF9, 0xD1, +0x42, 0x4B, 0xD8, 0x68, 0x19, 0x68, 0x9A, 0x68, 0x5B, 0x68, 0x01, 0x90, +0x03, 0x93, 0x40, 0x4B, 0x02, 0x91, 0x1B, 0x68, 0x04, 0x93, 0x3F, 0x4B, +0x5B, 0x7F, 0x06, 0x93, 0x68, 0xE0, 0x07, 0x9B, 0x88, 0x1C, 0x3D, 0x4A, +0x18, 0x18, 0x83, 0x5C, 0x5B, 0xB2, 0x1F, 0x2B, 0x5A, 0xD1, 0x3B, 0x4A, +0x40, 0x00, 0x82, 0x5A, 0x04, 0x9D, 0x04, 0x20, 0x52, 0x1B, 0x05, 0x92, +0x38, 0x4A, 0x01, 0x38, 0xC0, 0xB2, 0x14, 0x56, 0x37, 0x4A, 0x64, 0x44, +0x12, 0x56, 0x01, 0x34, 0x8A, 0x18, 0xA4, 0x01, 0x02, 0x32, 0x31, 0x4E, +0xA2, 0x18, 0xB4, 0x5C, 0x0E, 0x2C, 0x41, 0xD8, 0x1F, 0x2B, 0x3E, 0xD0, +0xA3, 0x42, 0x3D, 0xD0, 0x00, 0x2C, 0x3B, 0xD0, 0x0A, 0x27, 0x5D, 0x1E, +0x7D, 0x43, 0x2E, 0x4A, 0x2D, 0x4E, 0x55, 0x19, 0x62, 0x1E, 0x7A, 0x43, +0xB2, 0x18, 0x3E, 0x27, 0xEE, 0x5F, 0x3E, 0x27, 0xD5, 0x5F, 0x1A, 0x1C, +0xAE, 0x42, 0x00, 0xDD, 0x22, 0x1C, 0x0A, 0x25, 0x01, 0x3A, 0x6A, 0x43, +0x25, 0x4E, 0x06, 0x9D, 0xB2, 0x18, 0x3E, 0x27, 0xD2, 0x5F, 0x05, 0x9E, +0x6A, 0x43, 0x92, 0x11, 0x96, 0x42, 0x1D, 0xDD, 0x9C, 0x42, 0x02, 0xD9, +0x1A, 0x1C, 0x23, 0x1C, 0x14, 0x1C, 0x5E, 0x1E, 0x15, 0x4A, 0xF6, 0xB2, +0x97, 0x5D, 0x00, 0x25, 0x00, 0x97, 0x6F, 0x46, 0x7D, 0x57, 0x01, 0x3C, +0xE4, 0xB2, 0x6F, 0x1C, 0x09, 0xD0, 0xA5, 0x42, 0x03, 0xDA, 0x6D, 0x46, +0x2D, 0x78, 0x15, 0x55, 0x06, 0xE0, 0xA5, 0x42, 0x04, 0xDD, 0xE4, 0xB2, +0x54, 0x55, 0x94, 0x55, 0x00, 0xE0, 0x23, 0x1C, 0x00, 0x28, 0xAB, 0xD1, +0x01, 0x39, 0x03, 0x9E, 0xB1, 0x42, 0x98, 0xDA, 0x62, 0x46, 0x01, 0x3A, +0x01, 0x9F, 0xBA, 0x42, 0x05, 0xDB, 0x53, 0x1C, 0x9B, 0x01, 0x02, 0x99, +0x07, 0x93, 0x94, 0x46, 0xF1, 0xE7, 0x09, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, +0xEC, 0x02, 0x00, 0x20, 0xE4, 0x10, 0x00, 0x20, 0x38, 0x0D, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, +0xF4, 0x59, 0x00, 0x00, 0xF0, 0x59, 0x00, 0x00, 0x24, 0x02, 0x00, 0x20, +0xF0, 0xB5, 0xD4, 0x4A, 0x8D, 0xB0, 0x11, 0x68, 0x00, 0x23, 0xD0, 0x18, +0xBE, 0x30, 0x00, 0x24, 0x00, 0x5F, 0x0A, 0x3B, 0x44, 0x1E, 0xA0, 0x41, +0x1D, 0x1C, 0x09, 0x18, 0x8C, 0x35, 0xF4, 0xD1, 0xCD, 0x4B, 0x11, 0x60, +0x1B, 0x68, 0xBE, 0x32, 0x03, 0x93, 0xCC, 0x4B, 0x0E, 0x24, 0x1B, 0x68, +0x05, 0x93, 0xCB, 0x4E, 0x01, 0x3C, 0x33, 0x57, 0x5F, 0x1C, 0x01, 0xD1, +0x73, 0xE0, 0x03, 0x1C, 0xC7, 0x4D, 0xE8, 0x56, 0x46, 0x1C, 0xFA, 0xD1, +0x2B, 0x55, 0x5F, 0x1C, 0x6B, 0xD0, 0x03, 0x98, 0x9D, 0x00, 0x46, 0x19, +0x37, 0x68, 0xA0, 0x00, 0xBC, 0x46, 0x03, 0x9F, 0x3F, 0x58, 0xBC, 0x44, +0x67, 0x46, 0x37, 0x60, 0x05, 0x9E, 0x05, 0x9F, 0x75, 0x19, 0x2E, 0x68, +0x38, 0x58, 0xB9, 0x4F, 0x30, 0x18, 0x0A, 0x26, 0x28, 0x60, 0x30, 0x1C, +0x58, 0x43, 0x38, 0x18, 0x38, 0x30, 0x09, 0x27, 0xC7, 0x57, 0x55, 0x79, +0xBC, 0x46, 0x6F, 0xB2, 0xBC, 0x45, 0x00, 0xDD, 0x45, 0x72, 0x5E, 0x43, +0xB0, 0x4D, 0x90, 0x79, 0xAE, 0x19, 0x38, 0x36, 0x0A, 0x27, 0xF7, 0x57, +0x45, 0xB2, 0xAF, 0x42, 0x00, 0xDA, 0xB0, 0x72, 0xD6, 0x79, 0xAB, 0x4F, +0x06, 0x96, 0x0A, 0x26, 0x30, 0x1C, 0x58, 0x43, 0x38, 0x18, 0x38, 0x30, +0x0B, 0x25, 0x45, 0x57, 0xAC, 0x46, 0x6D, 0x46, 0x18, 0x35, 0x2D, 0x78, +0x6D, 0xB2, 0xAC, 0x45, 0x03, 0xDD, 0x6F, 0x46, 0x18, 0x25, 0xEF, 0x5D, +0xC7, 0x72, 0x5E, 0x43, 0xA0, 0x4D, 0x10, 0x7A, 0xAF, 0x19, 0x38, 0x37, +0x0C, 0x26, 0xBE, 0x57, 0x45, 0xB2, 0xAE, 0x42, 0x00, 0xDA, 0x38, 0x73, +0x0A, 0x20, 0x58, 0x43, 0x56, 0x88, 0x9A, 0x4F, 0x06, 0x96, 0x38, 0x18, +0x3E, 0x26, 0x85, 0x5F, 0x18, 0x26, 0xAC, 0x46, 0x6D, 0x46, 0x75, 0x5F, +0x38, 0x30, 0x0A, 0x26, 0xAC, 0x45, 0x03, 0xDA, 0x6F, 0x46, 0x18, 0x25, +0xEF, 0x5B, 0xC7, 0x80, 0x5E, 0x43, 0x91, 0x48, 0x01, 0x39, 0x87, 0x19, +0xBB, 0x8F, 0x10, 0x88, 0xC3, 0x18, 0xBB, 0x87, 0x38, 0x37, 0x10, 0x79, +0x3B, 0x7A, 0xC3, 0x18, 0x3B, 0x72, 0x0A, 0x3A, 0x00, 0x2C, 0x00, 0xD0, +0x81, 0xE7, 0x89, 0x4F, 0x26, 0x1C, 0x3D, 0x1C, 0x3C, 0x35, 0x03, 0x95, +0x39, 0x60, 0x25, 0x1C, 0x88, 0x48, 0x00, 0x22, 0x33, 0x18, 0x9A, 0x56, +0x01, 0x32, 0x19, 0xD1, 0x1D, 0x70, 0xB5, 0x42, 0x12, 0xD0, 0x82, 0x4B, +0xB1, 0x00, 0x1A, 0x68, 0xAB, 0x00, 0x50, 0x58, 0xD0, 0x50, 0x80, 0x4A, +0x7D, 0x48, 0x12, 0x68, 0x51, 0x58, 0xD1, 0x50, 0x0A, 0x22, 0x13, 0x1C, +0x6B, 0x43, 0xC0, 0x18, 0x3C, 0x30, 0x03, 0x99, 0x03, 0xF0, 0x78, 0xFB, +0x3B, 0x68, 0x01, 0x35, 0x9D, 0x42, 0x05, 0xDA, 0x03, 0x99, 0x01, 0x36, +0x0A, 0x31, 0x03, 0x91, 0x0E, 0x2E, 0xD9, 0xD1, 0x76, 0x4B, 0x1B, 0x68, +0xDA, 0x06, 0x3B, 0xD5, 0x75, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, +0x04, 0x20, 0x74, 0x49, 0x01, 0xF0, 0xD4, 0xFE, 0x00, 0x25, 0x73, 0x4E, +0x2C, 0xE0, 0x69, 0x1C, 0x89, 0x01, 0x33, 0x68, 0x77, 0x68, 0x71, 0x4A, +0x03, 0x91, 0xA4, 0x46, 0x12, 0xE0, 0x03, 0x9C, 0x99, 0x1C, 0x61, 0x18, +0x88, 0x5C, 0x40, 0xB2, 0x44, 0x1E, 0x0D, 0x2C, 0x09, 0xD8, 0x66, 0x4C, +0x20, 0x18, 0x01, 0x38, 0x00, 0x78, 0x40, 0xB2, 0x44, 0x1C, 0x02, 0xD0, +0x01, 0x30, 0xC0, 0xB2, 0x88, 0x54, 0x01, 0x3B, 0xBB, 0x42, 0xEA, 0xDA, +0x61, 0x4B, 0x64, 0x46, 0x1B, 0x78, 0x00, 0x2B, 0x09, 0xD0, 0x63, 0x4B, +0x63, 0x4F, 0xAA, 0x01, 0xD9, 0x7D, 0xD2, 0x19, 0x01, 0x23, 0x04, 0x20, +0x00, 0x93, 0x01, 0xF0, 0x4D, 0xFE, 0x01, 0x35, 0x5D, 0x4F, 0x3B, 0x7E, +0x9D, 0x42, 0xCE, 0xDB, 0x5D, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x10, 0xDD, +0x5C, 0x4B, 0x5D, 0x4A, 0x99, 0x89, 0x11, 0x80, 0x1B, 0x89, 0x53, 0x80, +0x52, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, +0x00, 0x93, 0x17, 0x20, 0x0B, 0x1C, 0x01, 0xF0, 0x33, 0xFE, 0x48, 0x4B, +0x55, 0x48, 0x1D, 0x1C, 0x40, 0xCD, 0x4F, 0x49, 0x07, 0x96, 0x47, 0x89, +0x08, 0x97, 0x0A, 0x8D, 0x47, 0x68, 0x16, 0xB2, 0x05, 0x96, 0x86, 0x69, +0x09, 0x97, 0xB7, 0xB2, 0xD2, 0x1B, 0x04, 0x97, 0x92, 0xB2, 0x31, 0x31, +0x09, 0x78, 0x0A, 0x92, 0x3E, 0x4A, 0x00, 0x20, 0x06, 0x91, 0x17, 0x68, +0x03, 0x90, 0x2F, 0xE0, 0x03, 0x9A, 0x0A, 0x23, 0x53, 0x43, 0x01, 0xCF, +0x05, 0x99, 0x48, 0x43, 0x37, 0x49, 0xCB, 0x18, 0x3C, 0x22, 0x99, 0x5E, +0x09, 0x9B, 0x59, 0x43, 0x03, 0xF0, 0x8E, 0xFA, 0x08, 0x99, 0x42, 0x4A, +0x08, 0x18, 0x13, 0x78, 0x80, 0xB2, 0x28, 0x80, 0x00, 0x2B, 0x15, 0xD1, +0x00, 0xB2, 0xB0, 0x42, 0x07, 0xDA, 0x06, 0x9B, 0x80, 0x1B, 0x58, 0x43, +0x04, 0x99, 0x80, 0x11, 0x08, 0x18, 0x28, 0x80, 0x0A, 0xE0, 0x05, 0x9A, +0x10, 0x1A, 0xB0, 0x42, 0x06, 0xDA, 0x06, 0x9B, 0x80, 0x1B, 0x58, 0x43, +0x0A, 0x99, 0x80, 0x11, 0x08, 0x1A, 0x28, 0x80, 0x03, 0x9A, 0x02, 0x35, +0x01, 0x32, 0x03, 0x92, 0x03, 0x9B, 0x07, 0x98, 0x83, 0x42, 0xCB, 0xDB, +0x20, 0x4D, 0x2E, 0x49, 0x2D, 0x68, 0x28, 0x4A, 0x05, 0x95, 0x0E, 0x89, +0x0D, 0x68, 0x07, 0x96, 0xD3, 0x8C, 0x08, 0x95, 0x4D, 0x69, 0x1F, 0xB2, +0xAE, 0xB2, 0x11, 0x1C, 0x04, 0x97, 0x06, 0x96, 0x2F, 0x31, 0x09, 0x78, +0x9B, 0x1B, 0x9B, 0xB2, 0x09, 0x91, 0x30, 0x32, 0x12, 0x78, 0x15, 0x4E, +0x0B, 0x93, 0x16, 0x4B, 0x00, 0x20, 0x0A, 0x92, 0x1F, 0x68, 0x20, 0x36, +0x03, 0x90, 0x50, 0xE0, 0x03, 0x9A, 0x0A, 0x23, 0x53, 0x43, 0x01, 0xCF, +0x04, 0x99, 0x48, 0x43, 0x0D, 0x49, 0x5B, 0x18, 0x3C, 0x22, 0x99, 0x5E, +0x08, 0x9B, 0x59, 0x43, 0x03, 0xF0, 0x3A, 0xFA, 0x07, 0x99, 0x18, 0x4A, +0x08, 0x18, 0x13, 0x78, 0x80, 0xB2, 0x30, 0x80, 0x00, 0x2B, 0x36, 0xD1, +0x00, 0xB2, 0xA8, 0x42, 0x28, 0xDA, 0x09, 0x9B, 0x40, 0x1B, 0x58, 0x43, +0x06, 0x99, 0x80, 0x11, 0x08, 0x18, 0x30, 0x80, 0x2B, 0xE0, 0xC0, 0x46, +0x24, 0x02, 0x00, 0x20, 0x48, 0x00, 0x00, 0x20, 0x44, 0x00, 0x00, 0x20, +0xEC, 0x02, 0x00, 0x20, 0x58, 0x00, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0x60, 0x59, 0x00, 0x00, 0xE4, 0x10, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, +0xAE, 0x09, 0x00, 0x20, 0x42, 0x20, 0x00, 0x40, 0x9C, 0x0D, 0x00, 0x20, +0x70, 0x01, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, 0x24, 0x09, 0x00, 0x20, +0xDF, 0x01, 0x00, 0x20, 0x04, 0x9A, 0x10, 0x1A, 0xA8, 0x42, 0x06, 0xDA, +0x0A, 0x9B, 0x40, 0x1B, 0x58, 0x43, 0x0B, 0x99, 0x80, 0x11, 0x08, 0x1A, +0x30, 0x80, 0x03, 0x9A, 0x02, 0x36, 0x01, 0x32, 0x03, 0x92, 0x03, 0x9B, +0x05, 0x98, 0x83, 0x42, 0xAA, 0xDB, 0x1B, 0x4B, 0x1A, 0x1C, 0x2A, 0x32, +0x17, 0x78, 0x1A, 0x1C, 0x2B, 0x32, 0x12, 0x78, 0x28, 0x21, 0x5E, 0x5E, +0x03, 0x92, 0x26, 0x25, 0x5A, 0x5F, 0x2C, 0x33, 0x04, 0x92, 0x1B, 0x78, +0x14, 0x49, 0x06, 0x93, 0x00, 0x25, 0xB4, 0x46, 0x1D, 0xE0, 0x00, 0x26, +0x8B, 0x5F, 0x00, 0x2B, 0x16, 0xD0, 0x11, 0x4A, 0xA8, 0x18, 0x04, 0x23, +0xC2, 0x5E, 0x20, 0x26, 0x83, 0x5F, 0x00, 0x2F, 0x01, 0xD0, 0x66, 0x46, +0xB2, 0x1A, 0x03, 0x9E, 0x00, 0x2E, 0x01, 0xD0, 0x04, 0x9E, 0xF3, 0x1A, +0x06, 0x9E, 0x00, 0x2E, 0x02, 0xD0, 0x16, 0x1C, 0x1A, 0x1C, 0x33, 0x1C, +0x82, 0x80, 0x03, 0x84, 0x01, 0x34, 0x0A, 0x31, 0x02, 0x35, 0x05, 0x9E, +0xB4, 0x42, 0xDE, 0xDB, 0x0D, 0xB0, 0xF0, 0xBD, 0xAE, 0x09, 0x00, 0x20, +0x60, 0x02, 0x00, 0x20, 0x24, 0x02, 0x00, 0x20, 0x30, 0xB5, 0x0A, 0x4B, +0x00, 0x21, 0x04, 0x33, 0xDB, 0x7F, 0x09, 0x4A, 0x0A, 0x24, 0x08, 0x1C, +0x07, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x25, 0x1C, 0x5D, 0x43, 0x55, 0x19, +0xA9, 0x87, 0x05, 0x4D, 0xE8, 0x54, 0x00, 0x2B, 0xF5, 0xD1, 0x13, 0x60, +0x30, 0xBD, 0xC0, 0x46, 0xAE, 0x09, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0x64, 0x01, 0x00, 0x20, 0x00, 0xB5, 0x08, 0x4A, 0x01, 0x23, 0x5B, 0x42, +0x53, 0x60, 0x07, 0x4B, 0x00, 0x21, 0x11, 0x60, 0x1B, 0x78, 0x04, 0xE0, +0x01, 0x3B, 0xDB, 0xB2, 0x18, 0x1D, 0x40, 0x00, 0x81, 0x52, 0x00, 0x2B, +0xF8, 0xD1, 0x00, 0xBD, 0xE0, 0x00, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, +0x49, 0x43, 0x40, 0x43, 0x40, 0x18, 0x70, 0x47, 0x70, 0x47, 0xF0, 0xB5, +0x83, 0x4B, 0x00, 0x22, 0x04, 0x33, 0xD9, 0x7F, 0x87, 0xB0, 0x0B, 0x1C, +0x81, 0x48, 0x0A, 0x26, 0x15, 0x1C, 0x07, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, +0x34, 0x1C, 0x5C, 0x43, 0x04, 0x19, 0xA2, 0x87, 0x38, 0x34, 0x25, 0x72, +0x04, 0x1C, 0x00, 0x2B, 0xF4, 0xD1, 0x7B, 0x4B, 0x1A, 0x68, 0x0B, 0x1C, +0x91, 0x42, 0x00, 0xDD, 0x13, 0x1C, 0x23, 0x60, 0x78, 0x48, 0x79, 0x4A, +0x79, 0x4B, 0x0E, 0x24, 0xFF, 0x21, 0x01, 0x3C, 0xE4, 0xB2, 0xA5, 0x00, +0x01, 0x55, 0xAB, 0x50, 0x00, 0x2C, 0xF8, 0xD1, 0x6F, 0x4B, 0x25, 0x1C, +0x04, 0x33, 0xDB, 0x7F, 0x26, 0x1C, 0x03, 0x93, 0x72, 0x4B, 0x1B, 0x69, +0x04, 0x93, 0x6D, 0x4B, 0x1B, 0x68, 0x05, 0x93, 0x47, 0xE0, 0x70, 0x4C, +0x63, 0x5D, 0x00, 0x2B, 0x42, 0xD0, 0x6F, 0x4C, 0xAB, 0x00, 0xE3, 0x58, +0x04, 0x9C, 0x1B, 0x01, 0x1B, 0x19, 0x01, 0x93, 0x6C, 0x4B, 0x6A, 0x00, +0x01, 0x27, 0xD3, 0x18, 0x00, 0x24, 0x7F, 0x42, 0x02, 0x93, 0x20, 0xE0, +0x0A, 0x23, 0x63, 0x43, 0x60, 0x48, 0xC3, 0x18, 0x3C, 0x21, 0x5B, 0x5E, +0x00, 0x2B, 0x16, 0xD0, 0x02, 0x9A, 0x63, 0x00, 0xC3, 0x18, 0x98, 0x88, +0x93, 0x88, 0x5B, 0x4A, 0xC0, 0x1A, 0x23, 0x1C, 0x10, 0x33, 0x5B, 0x00, +0x99, 0x5A, 0x02, 0x9A, 0x00, 0xB2, 0x13, 0x8B, 0xC9, 0x1A, 0x09, 0xB2, +0xFF, 0xF7, 0x98, 0xFF, 0x01, 0x9B, 0x98, 0x42, 0x01, 0xDA, 0x27, 0x1C, +0x01, 0x90, 0x01, 0x34, 0xE4, 0xB2, 0x05, 0x98, 0x84, 0x42, 0xDB, 0xDB, +0x79, 0x1C, 0x0D, 0xD0, 0x4F, 0x4B, 0x50, 0x49, 0xD8, 0x57, 0xBA, 0x00, +0x01, 0x30, 0x04, 0xD0, 0x88, 0x58, 0x01, 0x9C, 0xA0, 0x42, 0x03, 0xDD, +0x00, 0xE0, 0x01, 0x9C, 0x8C, 0x50, 0xDD, 0x55, 0x01, 0x35, 0x03, 0x9C, +0xEB, 0xB2, 0xA3, 0x42, 0xB3, 0xD3, 0x34, 0x1C, 0x00, 0x25, 0x44, 0x4E, +0x28, 0xE0, 0x44, 0x48, 0x47, 0x5D, 0x7B, 0xB2, 0x01, 0x33, 0x21, 0xD0, +0x69, 0x00, 0xFF, 0xB2, 0x3E, 0x4B, 0x71, 0x18, 0x89, 0x88, 0x7A, 0x00, +0x9A, 0x18, 0x91, 0x80, 0x29, 0x1C, 0x10, 0x31, 0x3A, 0x1C, 0x49, 0x00, +0x89, 0x5B, 0x10, 0x32, 0x52, 0x00, 0xD1, 0x52, 0x0A, 0x22, 0x10, 0x1C, +0x78, 0x43, 0x11, 0x1C, 0x69, 0x43, 0x1B, 0x18, 0x18, 0x1C, 0x71, 0x18, +0x3C, 0x30, 0x3C, 0x31, 0x03, 0xF0, 0x3A, 0xF9, 0x34, 0x4B, 0xAA, 0x00, +0xD2, 0x58, 0x37, 0x4B, 0xBF, 0x00, 0xFA, 0x50, 0x01, 0x35, 0xED, 0xB2, +0x33, 0x68, 0x9D, 0x42, 0xD3, 0xDB, 0x3D, 0xE0, 0x2D, 0x4E, 0x33, 0x57, +0x01, 0x33, 0x36, 0xD1, 0x0A, 0x23, 0x63, 0x43, 0xEB, 0x18, 0x3C, 0x20, +0x1B, 0x5E, 0x00, 0x2B, 0x2F, 0xD0, 0x25, 0x4B, 0x2E, 0x4A, 0x04, 0x33, +0xDF, 0x7F, 0x00, 0x23, 0x26, 0xE0, 0x29, 0x4E, 0xF6, 0x5C, 0x00, 0x2E, +0x20, 0xD1, 0x00, 0x26, 0x90, 0x5F, 0x00, 0x28, 0x1C, 0xD1, 0x21, 0x4A, +0x67, 0x00, 0x11, 0x55, 0x1E, 0x49, 0x1D, 0x48, 0xCF, 0x19, 0xBF, 0x88, +0x5A, 0x00, 0x82, 0x18, 0x97, 0x80, 0x27, 0x1C, 0x10, 0x37, 0x1A, 0x1C, +0x7F, 0x00, 0x7F, 0x5A, 0x10, 0x32, 0x52, 0x00, 0x17, 0x52, 0x0A, 0x22, +0x53, 0x43, 0xC0, 0x18, 0x13, 0x1C, 0x63, 0x43, 0xC9, 0x18, 0x3C, 0x31, +0x3C, 0x30, 0x03, 0xF0, 0xF9, 0xF8, 0x04, 0xE0, 0x01, 0x33, 0x0A, 0x32, +0xD9, 0xB2, 0xB9, 0x42, 0xD5, 0xD3, 0x01, 0x34, 0xE4, 0xB2, 0x00, 0xE0, +0x0D, 0x4D, 0x2B, 0x68, 0x9C, 0x42, 0xBD, 0xDB, 0x09, 0x4B, 0x0C, 0x49, +0x04, 0x33, 0xDD, 0x7F, 0x12, 0x4B, 0xFF, 0x20, 0x1C, 0x1C, 0x0E, 0x34, +0x1A, 0x78, 0xAA, 0x42, 0x02, 0xD2, 0x8A, 0x5C, 0x1A, 0x70, 0x00, 0xE0, +0x18, 0x70, 0x01, 0x33, 0xA3, 0x42, 0xF5, 0xD1, 0x07, 0xB0, 0xF0, 0xBD, +0xAE, 0x09, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, 0x24, 0x02, 0x00, 0x20, +0xE8, 0x03, 0x00, 0x20, 0xF8, 0x10, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x7F, +0x24, 0x09, 0x00, 0x20, 0xEC, 0x01, 0x00, 0x20, 0xF8, 0x00, 0x00, 0x20, +0x80, 0x09, 0x00, 0x20, 0xD8, 0x0D, 0x00, 0x20, 0xEC, 0x02, 0x00, 0x20, +0xF7, 0xB5, 0x42, 0x4B, 0x00, 0x21, 0x19, 0x60, 0x41, 0x4B, 0x0A, 0x24, +0x19, 0x60, 0x41, 0x4B, 0x08, 0x1C, 0x04, 0x33, 0xDB, 0x7F, 0x40, 0x4D, +0x1A, 0x1C, 0xA4, 0x46, 0x11, 0xE0, 0x01, 0x3A, 0xD2, 0xB2, 0x26, 0x1C, +0x56, 0x43, 0xAE, 0x19, 0x38, 0x36, 0x36, 0x7A, 0xB0, 0x42, 0x00, 0xDA, +0x30, 0x1C, 0x66, 0x46, 0x56, 0x43, 0xAE, 0x19, 0x3C, 0x27, 0xF6, 0x5F, +0xB1, 0x42, 0x00, 0xDA, 0x31, 0x1C, 0x00, 0x2A, 0xEB, 0xD1, 0x32, 0x4A, +0x50, 0x60, 0x11, 0x60, 0x2F, 0x4A, 0x0A, 0x20, 0x11, 0x68, 0x31, 0x4A, +0x07, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x04, 0x1C, 0x5C, 0x43, 0x14, 0x19, +0x38, 0x34, 0x24, 0x7A, 0x09, 0x19, 0x14, 0x1C, 0x00, 0x2B, 0xF4, 0xD1, +0x27, 0x4B, 0x19, 0x60, 0x13, 0x68, 0x00, 0x2B, 0x0F, 0xDD, 0x26, 0x4B, +0x28, 0x4A, 0x5B, 0x68, 0x11, 0x80, 0x53, 0x80, 0x27, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, 0x00, 0x93, 0x1D, 0x20, +0x0B, 0x1C, 0x01, 0xF0, 0x8F, 0xFB, 0x23, 0x68, 0x00, 0x2B, 0x19, 0xDD, +0x21, 0x4A, 0x08, 0x23, 0xD1, 0x5E, 0x21, 0x4B, 0x0C, 0x24, 0x12, 0x5F, +0x18, 0x1C, 0x3D, 0x33, 0x1B, 0x78, 0x3C, 0x30, 0x53, 0x43, 0x00, 0x78, +0x9B, 0x11, 0xC3, 0x18, 0x99, 0x42, 0x09, 0xDC, 0x18, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x19, 0x49, 0x01, 0xF0, 0xCC, 0xFB, +0xFF, 0xF7, 0x40, 0xFE, 0x11, 0x4B, 0x17, 0x4A, 0x1B, 0x68, 0x12, 0x78, +0x93, 0x42, 0x12, 0xDB, 0x0B, 0x4B, 0x12, 0x4A, 0x18, 0x68, 0xD1, 0x8E, +0x0A, 0x4B, 0x88, 0x42, 0x03, 0xDB, 0x11, 0x8F, 0x58, 0x68, 0x88, 0x42, +0x03, 0xDA, 0x52, 0x8F, 0x5B, 0x68, 0x93, 0x42, 0x07, 0xDB, 0x0E, 0x4B, +0x01, 0x22, 0x1A, 0x70, 0x03, 0xE0, 0x00, 0x2B, 0x01, 0xD1, 0x0B, 0x4A, +0x13, 0x70, 0xF7, 0xBD, 0x4C, 0x11, 0x00, 0x20, 0x0C, 0x02, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x68, 0x59, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0xF5, 0x00, 0x00, 0x20, +0x38, 0xB5, 0x04, 0x1C, 0x08, 0x1C, 0x00, 0x2A, 0x07, 0xD0, 0x54, 0x43, +0x58, 0x43, 0xD1, 0x18, 0x20, 0x18, 0x4D, 0x10, 0x40, 0x19, 0x02, 0xF0, +0xB5, 0xFF, 0x38, 0xBD, 0x10, 0xB5, 0x43, 0x1A, 0xDC, 0x17, 0x1B, 0x19, +0x63, 0x40, 0xFF, 0xF7, 0xEB, 0xFF, 0x10, 0xBD, 0xF0, 0xB5, 0xA9, 0x4B, +0x00, 0x25, 0x04, 0x33, 0x87, 0xB0, 0xDC, 0x7F, 0x2E, 0x1C, 0x46, 0xE0, +0x01, 0x3C, 0xE4, 0xB2, 0x0A, 0x22, 0x62, 0x43, 0x99, 0x18, 0x38, 0x31, +0x88, 0x88, 0x00, 0x28, 0x3D, 0xD0, 0xA2, 0x4F, 0x3F, 0x5D, 0x00, 0x2F, +0x2A, 0xD1, 0xA1, 0x49, 0x09, 0x78, 0x00, 0x29, 0x07, 0xD0, 0x9A, 0x18, +0x01, 0x21, 0x3C, 0x32, 0x1D, 0x20, 0x02, 0x23, 0x00, 0x91, 0x01, 0xF0, +0x07, 0xFB, 0x0A, 0x20, 0x60, 0x43, 0x9B, 0x4B, 0x9B, 0x49, 0x18, 0x18, +0x3C, 0x27, 0xC2, 0x5F, 0x38, 0x30, 0x94, 0x46, 0x26, 0x27, 0xCA, 0x5F, +0x1F, 0x1C, 0x94, 0x45, 0x08, 0xDB, 0x4E, 0x31, 0x0A, 0x78, 0x96, 0x49, +0x00, 0x7A, 0x49, 0x68, 0x4A, 0x43, 0x92, 0x11, 0x90, 0x42, 0x16, 0xDA, +0x0A, 0x22, 0x62, 0x43, 0xBA, 0x18, 0xD5, 0x87, 0x38, 0x32, 0x16, 0x72, +0x95, 0x80, 0x08, 0xE0, 0x8D, 0x4A, 0x00, 0xB2, 0x28, 0x27, 0xD2, 0x5F, +0x82, 0x42, 0x08, 0xDD, 0xCD, 0x80, 0x0E, 0x72, 0x8D, 0x80, 0x8B, 0x4A, +0xA1, 0x00, 0x8D, 0x50, 0x1A, 0x68, 0x01, 0x3A, 0x1A, 0x60, 0x85, 0x4B, +0x00, 0x2C, 0xB5, 0xD1, 0x1C, 0x60, 0x87, 0x4B, 0x9C, 0x73, 0x7F, 0x4B, +0x04, 0x33, 0xDC, 0x7F, 0xC7, 0xE0, 0x01, 0x3C, 0xE4, 0xB2, 0x0A, 0x23, +0x63, 0x43, 0xED, 0x18, 0xAA, 0x8F, 0x38, 0x35, 0x00, 0x2A, 0x00, 0xD1, +0x93, 0xE0, 0x7C, 0x4B, 0x12, 0xB2, 0x1B, 0x8D, 0x19, 0xB2, 0x52, 0x1A, +0x52, 0x10, 0x5B, 0x00, 0xD3, 0x18, 0xAB, 0x80, 0x7A, 0x4B, 0x9A, 0x7B, +0x00, 0x2A, 0x0D, 0xD1, 0x79, 0x4A, 0x12, 0x57, 0x00, 0x2A, 0x09, 0xD1, +0x78, 0x4A, 0x01, 0x21, 0x11, 0x70, 0x80, 0x22, 0xD2, 0x05, 0x50, 0x69, +0x00, 0x0E, 0x00, 0x06, 0x01, 0x43, 0x51, 0x61, 0x01, 0x22, 0x9A, 0x73, +0x73, 0x4E, 0x71, 0x4B, 0x1A, 0x57, 0x33, 0x78, 0x9A, 0x42, 0x70, 0xDB, +0x6F, 0x4B, 0x1A, 0x78, 0x00, 0x2A, 0x01, 0xD0, 0x00, 0x22, 0x1A, 0x70, +0x66, 0x4D, 0x62, 0x00, 0x2B, 0x68, 0x01, 0x33, 0x2B, 0x60, 0xAB, 0x18, +0x04, 0x27, 0xD9, 0x5F, 0x6A, 0x4B, 0x9A, 0x18, 0x04, 0x26, 0x90, 0x5F, +0x22, 0x1C, 0x10, 0x32, 0x52, 0x00, 0x57, 0x5F, 0x03, 0x97, 0xD7, 0x5E, +0x0A, 0x1A, 0xD3, 0x17, 0x03, 0x9E, 0xD2, 0x18, 0x5A, 0x40, 0xF3, 0x1B, +0xDE, 0x17, 0x9B, 0x19, 0x73, 0x40, 0xD3, 0x18, 0x04, 0x93, 0x59, 0x4B, +0x2E, 0x22, 0x9E, 0x5E, 0x04, 0x9B, 0x32, 0x1C, 0x05, 0x96, 0xFF, 0xF7, +0x39, 0xFF, 0x05, 0x9A, 0x04, 0x9B, 0x06, 0x1C, 0x03, 0x99, 0x38, 0x1C, +0xFF, 0xF7, 0x32, 0xFF, 0x4D, 0x4A, 0x13, 0x1C, 0x2D, 0x33, 0x1B, 0x78, +0x2A, 0x1C, 0x5B, 0xB2, 0x9E, 0x42, 0x07, 0xDD, 0x55, 0x49, 0xC9, 0x69, +0xCF, 0x1A, 0xBE, 0x42, 0x03, 0xDB, 0x4E, 0x1E, 0xF6, 0x1A, 0x00, 0xE0, +0x1E, 0x1C, 0x45, 0x4B, 0x2E, 0x33, 0x1B, 0x78, 0x5B, 0xB2, 0x98, 0x42, +0x07, 0xDD, 0x4E, 0x49, 0x09, 0x6A, 0xCF, 0x1A, 0xB8, 0x42, 0x03, 0xDB, +0x48, 0x1E, 0xC0, 0x1A, 0x00, 0xE0, 0x18, 0x1C, 0x63, 0x00, 0xD3, 0x18, +0x9E, 0x80, 0x23, 0x1C, 0x10, 0x33, 0x5B, 0x00, 0xE8, 0x52, 0x0A, 0x25, +0x65, 0x43, 0x3D, 0x4B, 0x43, 0x4E, 0x30, 0x20, 0x1F, 0x5E, 0x76, 0x19, +0x55, 0x19, 0x3C, 0x21, 0x70, 0x5E, 0x3C, 0x22, 0xA9, 0x5E, 0x3A, 0x1C, +0xFF, 0xF7, 0x0A, 0xFF, 0x38, 0x36, 0xA8, 0x87, 0x38, 0x35, 0x30, 0x7A, +0x29, 0x7A, 0x3A, 0x1C, 0xFF, 0xF7, 0x02, 0xFF, 0x28, 0x72, 0x31, 0x4B, +0x62, 0x00, 0x99, 0x18, 0x37, 0x48, 0x89, 0x88, 0x82, 0x18, 0x91, 0x80, +0x22, 0x1C, 0x10, 0x32, 0x52, 0x00, 0xD1, 0x5A, 0x11, 0x52, 0x0A, 0x22, +0x11, 0x1C, 0x61, 0x43, 0x40, 0x18, 0x59, 0x18, 0x0D, 0x1C, 0x3C, 0x30, +0x3C, 0x31, 0x02, 0xF0, 0x01, 0xFF, 0x3C, 0x23, 0xEA, 0x5E, 0x38, 0x35, +0x29, 0x4B, 0x00, 0x2A, 0x0C, 0xD0, 0x24, 0x49, 0x1A, 0x5D, 0x32, 0x31, +0x09, 0x78, 0x50, 0xB2, 0x88, 0x42, 0x06, 0xDA, 0x01, 0x32, 0x1A, 0x55, +0x01, 0x23, 0x5B, 0x42, 0xAB, 0x80, 0x00, 0xE0, 0x1A, 0x55, 0x1C, 0x4D, +0x00, 0x2C, 0x00, 0xD0, 0x33, 0xE7, 0x22, 0x4E, 0x29, 0x68, 0x32, 0x68, +0x22, 0x4B, 0x91, 0x42, 0x25, 0xDA, 0x19, 0x68, 0x17, 0x48, 0x01, 0x31, +0x19, 0x60, 0x3E, 0x30, 0x00, 0x78, 0x40, 0xB2, 0x81, 0x42, 0x1C, 0xDA, +0x0F, 0x4B, 0x2A, 0x60, 0x04, 0x33, 0xDC, 0x7F, 0x14, 0xE0, 0x01, 0x3C, +0xE4, 0xB2, 0x63, 0x00, 0xF2, 0x18, 0x92, 0x88, 0xEB, 0x18, 0x9A, 0x80, +0x23, 0x1C, 0x10, 0x33, 0x5B, 0x00, 0x9A, 0x5B, 0x5A, 0x53, 0x0A, 0x22, +0x11, 0x1C, 0x61, 0x43, 0x68, 0x18, 0x71, 0x18, 0x3C, 0x30, 0x3C, 0x31, +0x02, 0xF0, 0xC0, 0xFE, 0x00, 0x2C, 0xE8, 0xD1, 0x00, 0xE0, 0x1C, 0x60, +0x07, 0xB0, 0xF0, 0xBD, 0xAE, 0x09, 0x00, 0x20, 0xEC, 0x01, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x0C, 0x02, 0x00, 0x20, 0xF8, 0x00, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, +0x3E, 0x11, 0x00, 0x20, 0xE2, 0x01, 0x00, 0x20, 0x7A, 0x0D, 0x00, 0x20, +0x20, 0x03, 0x00, 0x20, 0x24, 0x09, 0x00, 0x20, 0x60, 0x01, 0x00, 0x20, +0xF0, 0xB5, 0x31, 0x4B, 0x31, 0x4D, 0x1E, 0x78, 0x31, 0x4B, 0x00, 0x27, +0x1A, 0x1C, 0x2F, 0x60, 0x2B, 0x32, 0x12, 0x78, 0x89, 0xB0, 0x04, 0x92, +0x50, 0x00, 0x1A, 0x1C, 0x06, 0x90, 0x32, 0x32, 0x12, 0x78, 0x07, 0x92, +0x30, 0x22, 0x99, 0x5E, 0x6B, 0x68, 0x05, 0x91, 0x02, 0x93, 0x03, 0x97, +0x42, 0xE0, 0x01, 0x3E, 0xF6, 0xB2, 0x33, 0x1D, 0x5B, 0x00, 0x01, 0x93, +0xEB, 0x5A, 0x00, 0x2B, 0x34, 0xD0, 0x04, 0x98, 0x1B, 0xB2, 0x1B, 0x1A, +0x06, 0x99, 0x5B, 0x10, 0xCB, 0x18, 0x01, 0x9A, 0x20, 0x48, 0x9B, 0xB2, +0xAB, 0x52, 0xF2, 0x00, 0x81, 0x58, 0x84, 0x18, 0x07, 0x98, 0x1B, 0xB2, +0x81, 0x42, 0x07, 0xDA, 0x1B, 0x48, 0x01, 0x31, 0x81, 0x50, 0x01, 0x99, +0x00, 0x22, 0x63, 0x60, 0x6A, 0x52, 0x21, 0xE0, 0x60, 0x68, 0x01, 0x37, +0x1A, 0x1A, 0xD1, 0x17, 0x84, 0x46, 0x50, 0x18, 0x05, 0x9A, 0x48, 0x40, +0x11, 0x18, 0x00, 0x90, 0x60, 0x46, 0x42, 0x43, 0x94, 0x46, 0x00, 0x9A, +0x53, 0x43, 0x62, 0x46, 0xD0, 0x18, 0x4B, 0x10, 0xC0, 0x18, 0x02, 0xF0, +0xED, 0xFD, 0x01, 0x9B, 0x03, 0x99, 0x60, 0x60, 0xE8, 0x52, 0x81, 0x42, +0x04, 0xDB, 0x05, 0xE0, 0x09, 0x48, 0xF2, 0x00, 0x83, 0x50, 0x01, 0xE0, +0x02, 0x96, 0x03, 0x90, 0x00, 0x2E, 0xBA, 0xD1, 0x02, 0x99, 0x09, 0xB0, +0x2F, 0x60, 0x69, 0x60, 0xF0, 0xBD, 0xC0, 0x46, 0x7C, 0x09, 0x00, 0x20, +0xE0, 0x00, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x48, 0x09, 0x00, 0x20, +0xF7, 0xB5, 0x27, 0x4B, 0x27, 0x49, 0x04, 0x33, 0xDB, 0x7F, 0x27, 0x4A, +0x27, 0x48, 0x42, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x1C, 0x1C, 0x14, 0x34, +0x64, 0x00, 0x04, 0x19, 0x04, 0x25, 0x64, 0x5F, 0x00, 0x2C, 0x27, 0xD0, +0x0A, 0x24, 0x5C, 0x43, 0x0C, 0x19, 0x3C, 0x26, 0xA4, 0x5F, 0x00, 0x2C, +0x20, 0xD0, 0x5C, 0x00, 0x0E, 0x19, 0xB6, 0x88, 0x05, 0x19, 0x37, 0xB2, +0xBC, 0x46, 0x04, 0x27, 0xEF, 0x5F, 0x65, 0x46, 0xED, 0x1B, 0x6F, 0x10, +0xBE, 0x19, 0x14, 0x19, 0xA6, 0x80, 0x1C, 0x1C, 0x10, 0x34, 0x64, 0x00, +0x0E, 0x5B, 0x1C, 0x1C, 0x0C, 0x34, 0x37, 0xB2, 0x64, 0x00, 0xBC, 0x46, +0x25, 0x5E, 0x67, 0x46, 0x7F, 0x1B, 0x7F, 0x10, 0xBE, 0x19, 0xA6, 0x52, +0x10, 0x4C, 0x01, 0x26, 0xE6, 0x54, 0x10, 0xE0, 0x0B, 0x4D, 0x5C, 0x00, +0x2E, 0x19, 0xB6, 0x88, 0x14, 0x19, 0xA6, 0x80, 0x1E, 0x1C, 0x10, 0x36, +0x1C, 0x1C, 0x76, 0x00, 0x76, 0x5B, 0x0C, 0x34, 0x64, 0x00, 0x16, 0x53, +0x07, 0x4C, 0x00, 0x26, 0xE6, 0x54, 0x00, 0x2B, 0xBA, 0xD1, 0x0B, 0x68, +0x13, 0x60, 0xF7, 0xBD, 0xAE, 0x09, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0x80, 0x09, 0x00, 0x20, 0x20, 0x01, 0x00, 0x20, 0xEC, 0x01, 0x00, 0x20, +0xF7, 0xB5, 0x35, 0x4A, 0x35, 0x4B, 0x11, 0x1C, 0x33, 0x31, 0x34, 0x32, +0x0E, 0x78, 0x12, 0x78, 0x04, 0x33, 0xDB, 0x7F, 0x32, 0x49, 0x01, 0x92, +0xB4, 0x46, 0x32, 0x4A, 0x4B, 0xE0, 0x32, 0x48, 0x01, 0x3B, 0xDB, 0xB2, +0xC4, 0x5C, 0x01, 0x98, 0x00, 0x2C, 0x00, 0xD1, 0x60, 0x46, 0x5E, 0x00, +0x8D, 0x19, 0x96, 0x19, 0x04, 0x27, 0xF6, 0x5F, 0xAD, 0x88, 0x00, 0x96, +0x00, 0x9F, 0x2E, 0xB2, 0xBE, 0x1B, 0xF7, 0x17, 0xF6, 0x19, 0x7E, 0x40, +0x86, 0x42, 0x10, 0xDA, 0x1E, 0x1C, 0x0C, 0x36, 0x76, 0x00, 0xB6, 0x5E, +0x1F, 0x1C, 0x10, 0x37, 0x00, 0x96, 0x7F, 0x00, 0xCF, 0x5F, 0x00, 0x9E, +0xF7, 0x1B, 0xFE, 0x17, 0xBF, 0x19, 0x77, 0x40, 0x00, 0x97, 0x87, 0x42, +0x18, 0xDB, 0x58, 0x00, 0x10, 0x18, 0x1E, 0x1C, 0x85, 0x80, 0x10, 0x36, +0x19, 0x4D, 0x18, 0x1C, 0x76, 0x00, 0x0C, 0x30, 0x75, 0x5B, 0x40, 0x00, +0x15, 0x52, 0x18, 0x1C, 0x14, 0x30, 0x40, 0x00, 0x10, 0x18, 0x04, 0x27, +0xC0, 0x5F, 0x00, 0x28, 0x04, 0xDD, 0x00, 0x2C, 0x02, 0xD1, 0x13, 0x48, +0x01, 0x24, 0xC4, 0x54, 0x0A, 0x24, 0x5C, 0x43, 0x0E, 0x4D, 0x18, 0x1C, +0x2C, 0x19, 0x14, 0x30, 0x0D, 0x4D, 0x40, 0x00, 0xA4, 0x8F, 0x28, 0x18, +0x84, 0x80, 0x00, 0x2B, 0xB1, 0xD1, 0x0A, 0x68, 0x09, 0x4B, 0x0B, 0x49, +0x1A, 0x60, 0x0B, 0x4B, 0x1A, 0x78, 0x0B, 0x4B, 0x1A, 0x70, 0x0B, 0x4A, +0x0B, 0x1C, 0x31, 0xCA, 0x31, 0xC3, 0xC0, 0xCA, 0xC0, 0xC3, 0xF7, 0xBD, +0x48, 0x0D, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0x20, 0x01, 0x00, 0x20, 0x64, 0x01, 0x00, 0x20, 0xCC, 0x00, 0x00, 0x20, +0xF5, 0x00, 0x00, 0x20, 0xF4, 0x00, 0x00, 0x20, 0xE0, 0x00, 0x00, 0x20, +0xF7, 0xB5, 0x19, 0x48, 0x01, 0x23, 0x5B, 0x42, 0x43, 0x60, 0x18, 0x4B, +0x1A, 0x78, 0x18, 0x4B, 0x19, 0x1C, 0x2B, 0x33, 0x1E, 0x78, 0x2A, 0x31, +0x0F, 0x78, 0x00, 0x23, 0xB4, 0x46, 0x1E, 0xE0, 0x01, 0x3A, 0xD2, 0xB2, +0x13, 0x4C, 0x51, 0x00, 0x61, 0x5A, 0x0E, 0xB2, 0xF6, 0x43, 0xF6, 0x17, +0x0E, 0x40, 0x11, 0x1D, 0x49, 0x00, 0xB5, 0xB2, 0x0E, 0x52, 0x00, 0x2D, +0x0F, 0xD0, 0x0E, 0x4E, 0x2D, 0xB2, 0x8E, 0x5F, 0x00, 0x2E, 0x04, 0xDC, +0xBD, 0x42, 0x07, 0xDA, 0x00, 0x25, 0x0D, 0x52, 0x05, 0xE0, 0x65, 0x45, +0x02, 0xDA, 0x00, 0x26, 0x0E, 0x52, 0x00, 0xE0, 0x01, 0x33, 0x00, 0x2A, +0xDE, 0xD1, 0x01, 0x4A, 0x13, 0x60, 0xF7, 0xBD, 0xE0, 0x00, 0x00, 0x20, +0x7C, 0x09, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x3C, 0x0D, 0x00, 0x20, +0xCC, 0x00, 0x00, 0x20, 0xEF, 0xF3, 0x08, 0x80, 0x70, 0x47, 0x00, 0xBA, +0x70, 0x47, 0x40, 0xBA, 0x70, 0x47, 0xC0, 0xBA, 0x70, 0x47, 0x70, 0xB5, +0x00, 0x28, 0x16, 0xDA, 0xC0, 0xB2, 0x0F, 0x23, 0x03, 0x40, 0x08, 0x3B, +0x12, 0x4A, 0x9B, 0x08, 0x9B, 0x00, 0x9B, 0x18, 0x03, 0x22, 0x10, 0x40, +0x90, 0x40, 0xFF, 0x22, 0x5D, 0x68, 0x14, 0x1C, 0x84, 0x40, 0x89, 0x01, +0xA5, 0x43, 0x0A, 0x40, 0x82, 0x40, 0x28, 0x1C, 0x10, 0x43, 0x58, 0x60, +0x11, 0xE0, 0x03, 0x24, 0x82, 0x08, 0x09, 0x4B, 0x20, 0x40, 0xC0, 0x32, +0xA0, 0x40, 0x92, 0x00, 0xFF, 0x24, 0xD5, 0x58, 0x26, 0x1C, 0x86, 0x40, +0x89, 0x01, 0xB5, 0x43, 0x0C, 0x40, 0x84, 0x40, 0x28, 0x1C, 0x20, 0x43, +0xD0, 0x50, 0x70, 0xBD, 0x18, 0xED, 0x00, 0xE0, 0x00, 0xE1, 0x00, 0xE0, +0x08, 0x4B, 0x40, 0x22, 0x19, 0x68, 0x7F, 0x20, 0x49, 0x06, 0x49, 0x0E, +0x11, 0x43, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, +0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x3F, 0x22, 0x19, 0x68, 0x7F, 0x20, +0x11, 0x40, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, +0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x08, 0x4A, 0x19, 0x68, 0x18, 0x68, +0x89, 0x04, 0x89, 0x0E, 0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0x08, 0x4B, 0x40, 0x22, +0x19, 0x68, 0x18, 0x68, 0x49, 0x04, 0x49, 0x0E, 0x11, 0x43, 0x06, 0x4A, +0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, +0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, +0xFF, 0x80, 0xFF, 0xFF, 0x08, 0x4B, 0x20, 0x22, 0x19, 0x68, 0x7F, 0x20, +0x49, 0x06, 0x49, 0x0E, 0x11, 0x43, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x5F, 0x22, +0x19, 0x68, 0x7F, 0x20, 0x11, 0x40, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0xBE, 0x21, +0x1A, 0x68, 0xC9, 0x01, 0x18, 0x68, 0x11, 0x40, 0x05, 0x4A, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x08, 0x4B, 0x20, 0x22, 0x19, 0x68, 0x18, 0x68, 0x49, 0x04, 0x49, 0x0E, +0x11, 0x43, 0x06, 0x4A, 0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0x80, 0x23, 0xDB, 0x05, +0x18, 0x6C, 0x80, 0x00, 0xC0, 0x0F, 0x70, 0x47, 0x08, 0x4B, 0x10, 0x22, +0x19, 0x68, 0x7F, 0x20, 0x49, 0x06, 0x49, 0x0E, 0x11, 0x43, 0x1A, 0x68, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, +0x07, 0x4B, 0x6F, 0x22, 0x19, 0x68, 0x7F, 0x20, 0x11, 0x40, 0x1A, 0x68, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, +0x00, 0xB5, 0x0B, 0x4B, 0x19, 0x68, 0x00, 0x28, 0x04, 0xD0, 0x49, 0x06, +0x49, 0x0E, 0x10, 0x22, 0x11, 0x43, 0x01, 0xE0, 0x6F, 0x22, 0x11, 0x40, +0x1A, 0x68, 0x7F, 0x20, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x00, 0xBD, 0xC0, 0x46, +0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0xDE, 0x21, 0x1A, 0x68, 0xC9, 0x01, +0x18, 0x68, 0x11, 0x40, 0x05, 0x4A, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0x08, 0x4B, 0x10, 0x22, +0x19, 0x68, 0x18, 0x68, 0x49, 0x04, 0x49, 0x0E, 0x11, 0x43, 0x06, 0x4A, +0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, +0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, +0xFF, 0x80, 0xFF, 0xFF, 0x80, 0x23, 0xDB, 0x05, 0x18, 0x6C, 0xC0, 0x00, +0xC0, 0x0F, 0x70, 0x47, 0x08, 0x4B, 0x01, 0x22, 0x19, 0x68, 0x7F, 0x20, +0x49, 0x06, 0x49, 0x0E, 0x11, 0x43, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x7E, 0x22, +0x19, 0x68, 0x7F, 0x20, 0x11, 0x40, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0xFC, 0x21, +0x1A, 0x68, 0xC9, 0x01, 0x18, 0x68, 0x11, 0x40, 0x05, 0x4A, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x08, 0x4B, 0x01, 0x22, 0x19, 0x68, 0x18, 0x68, 0x49, 0x04, 0x49, 0x0E, +0x11, 0x43, 0x06, 0x4A, 0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0x80, 0x23, 0xDB, 0x05, +0x18, 0x6C, 0xC0, 0x01, 0xC0, 0x0F, 0x70, 0x47, 0x08, 0x4B, 0x02, 0x22, +0x19, 0x68, 0x7F, 0x20, 0x49, 0x06, 0x49, 0x0E, 0x11, 0x43, 0x1A, 0x68, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, +0x07, 0x4B, 0x7D, 0x22, 0x19, 0x68, 0x7F, 0x20, 0x11, 0x40, 0x1A, 0x68, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, +0x07, 0x4B, 0xFA, 0x21, 0x1A, 0x68, 0xC9, 0x01, 0x18, 0x68, 0x11, 0x40, +0x05, 0x4A, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, +0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, +0xFF, 0x80, 0xFF, 0xFF, 0x08, 0x4B, 0x02, 0x22, 0x19, 0x68, 0x18, 0x68, +0x49, 0x04, 0x49, 0x0E, 0x11, 0x43, 0x06, 0x4A, 0x09, 0x02, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x80, 0x23, 0xDB, 0x05, 0x18, 0x6C, 0x80, 0x01, 0xC0, 0x0F, 0x70, 0x47, +0x08, 0x4B, 0x04, 0x22, 0x19, 0x68, 0x7F, 0x20, 0x49, 0x06, 0x49, 0x0E, +0x11, 0x43, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, +0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x7B, 0x22, 0x19, 0x68, 0x7F, 0x20, +0x11, 0x40, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, +0x08, 0x00, 0x00, 0x20, 0x00, 0xB5, 0x0B, 0x4B, 0x19, 0x68, 0x00, 0x28, +0x04, 0xD0, 0x49, 0x06, 0x49, 0x0E, 0x04, 0x22, 0x11, 0x43, 0x01, 0xE0, +0x7B, 0x22, 0x11, 0x40, 0x1A, 0x68, 0x7F, 0x20, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x00, 0xBD, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0xF6, 0x21, +0x1A, 0x68, 0xC9, 0x01, 0x18, 0x68, 0x11, 0x40, 0x05, 0x4A, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x08, 0x4B, 0x04, 0x22, 0x19, 0x68, 0x18, 0x68, 0x49, 0x04, 0x49, 0x0E, +0x11, 0x43, 0x06, 0x4A, 0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0x80, 0x23, 0xDB, 0x05, +0x18, 0x6C, 0x40, 0x01, 0xC0, 0x0F, 0x70, 0x47, 0x10, 0xB5, 0x80, 0x23, +0xDB, 0x05, 0x04, 0x1D, 0x98, 0x69, 0x3F, 0x22, 0x14, 0x40, 0x90, 0x43, +0x20, 0x43, 0x01, 0x24, 0x98, 0x61, 0x88, 0x1C, 0x21, 0x40, 0x41, 0x18, +0x0A, 0x40, 0x11, 0x02, 0x98, 0x69, 0x02, 0x4A, 0x02, 0x40, 0x0A, 0x43, +0x9A, 0x61, 0x10, 0xBD, 0xFF, 0xC0, 0xFF, 0xFF, 0x06, 0x4B, 0x7F, 0x22, +0x19, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x18, 0x6C, 0x01, 0x39, 0x90, 0x43, +0x11, 0x40, 0x02, 0x1C, 0x0A, 0x43, 0x1A, 0x64, 0x70, 0x47, 0xC0, 0x46, +0x18, 0x09, 0x00, 0x20, 0x80, 0x23, 0xDB, 0x05, 0x1A, 0x6C, 0x7F, 0x21, +0x8A, 0x43, 0x01, 0x21, 0x0A, 0x43, 0x1A, 0x64, 0x70, 0x47, 0x80, 0x23, +0xDB, 0x05, 0xDA, 0x69, 0x0F, 0x21, 0x8A, 0x43, 0x02, 0x21, 0x0A, 0x43, +0xDA, 0x61, 0xDA, 0x69, 0xF0, 0x21, 0x8A, 0x43, 0x30, 0x21, 0x0A, 0x43, +0xDA, 0x61, 0x0C, 0x4A, 0x11, 0x79, 0x01, 0x39, 0xC9, 0xB2, 0x59, 0x77, +0xD8, 0x69, 0x0A, 0x49, 0x01, 0x40, 0x80, 0x20, 0xC0, 0x02, 0x01, 0x43, +0xD9, 0x61, 0xD8, 0x69, 0x07, 0x49, 0x01, 0x40, 0xA0, 0x20, 0xC0, 0x03, +0x01, 0x43, 0xD9, 0x61, 0x92, 0x79, 0x01, 0x3A, 0xD2, 0xB2, 0xDA, 0x77, +0x70, 0x47, 0xC0, 0x46, 0x04, 0x02, 0x00, 0x20, 0xFF, 0xFF, 0xF0, 0xFF, +0xFF, 0xFF, 0x0F, 0xFF, 0x30, 0xB5, 0x1A, 0x4A, 0x1A, 0x4B, 0x11, 0x88, +0x1A, 0x4C, 0xC9, 0x18, 0x80, 0x23, 0xDB, 0x05, 0x89, 0xB2, 0x18, 0x8C, +0x19, 0x84, 0x59, 0x8C, 0x00, 0x21, 0x59, 0x84, 0x50, 0x88, 0x16, 0x4D, +0x01, 0x19, 0x89, 0xB2, 0x9A, 0x8C, 0x99, 0x84, 0x42, 0x1E, 0xDC, 0x8C, +0x92, 0xB2, 0x44, 0x19, 0xDA, 0x84, 0xA4, 0xB2, 0x1D, 0x8D, 0x1C, 0x85, +0x10, 0x4C, 0x00, 0x19, 0x80, 0xB2, 0x5C, 0x8D, 0x58, 0x85, 0x98, 0x8D, +0x99, 0x85, 0xD8, 0x8D, 0xDA, 0x85, 0x18, 0x8E, 0x19, 0x86, 0x58, 0x8E, +0x5A, 0x86, 0x98, 0x8E, 0x99, 0x86, 0xD8, 0x8E, 0xDA, 0x86, 0x18, 0x8F, +0x19, 0x87, 0x58, 0x8F, 0x5A, 0x87, 0x98, 0x8F, 0x99, 0x87, 0xD9, 0x8F, +0xDA, 0x87, 0x30, 0xBD, 0x04, 0x02, 0x00, 0x20, 0xFF, 0x07, 0x00, 0x00, +0xFF, 0x03, 0x00, 0x00, 0xFF, 0x05, 0x00, 0x00, 0xFF, 0x01, 0x00, 0x00, +0x30, 0xB5, 0x22, 0x4B, 0xEE, 0x24, 0x1A, 0x68, 0xE4, 0x01, 0x14, 0x40, +0x20, 0x48, 0x1A, 0x68, 0x7F, 0x21, 0x02, 0x40, 0x22, 0x43, 0x1A, 0x60, +0x1C, 0x68, 0x80, 0x22, 0xD2, 0x05, 0x15, 0x69, 0x14, 0x61, 0x1C, 0x4C, +0xA4, 0x7C, 0x00, 0x2C, 0x16, 0xD0, 0x1C, 0x68, 0x04, 0x25, 0x64, 0x04, +0x64, 0x0E, 0x2C, 0x43, 0x1D, 0x68, 0x0C, 0x40, 0x24, 0x02, 0x28, 0x40, +0x20, 0x43, 0x18, 0x60, 0x18, 0x68, 0x14, 0x69, 0x10, 0x61, 0x1C, 0x68, +0x7B, 0x20, 0x20, 0x40, 0x1C, 0x68, 0x8C, 0x43, 0x21, 0x1C, 0x01, 0x43, +0x19, 0x60, 0x15, 0xE0, 0x1C, 0x68, 0x04, 0x25, 0x64, 0x06, 0x64, 0x0E, +0x2C, 0x43, 0x1D, 0x68, 0x0C, 0x40, 0x8D, 0x43, 0x29, 0x1C, 0x21, 0x43, +0x19, 0x60, 0x19, 0x68, 0x14, 0x69, 0x11, 0x61, 0x1C, 0x68, 0xF6, 0x21, +0xC9, 0x01, 0x21, 0x40, 0x1C, 0x68, 0x20, 0x40, 0x08, 0x43, 0x18, 0x60, +0x1B, 0x68, 0x11, 0x69, 0x13, 0x61, 0x30, 0xBD, 0x08, 0x00, 0x00, 0x20, +0xFF, 0x80, 0xFF, 0xFF, 0xAE, 0x09, 0x00, 0x20, 0x00, 0xB5, 0x72, 0xB6, +0x0F, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x0F, 0x4B, 0x9A, 0x7C, 0x0F, 0x4B, +0x00, 0x2A, 0x07, 0xD0, 0x1A, 0x68, 0xF6, 0x21, 0xC9, 0x01, 0x11, 0x40, +0x18, 0x68, 0x0C, 0x4A, 0x02, 0x40, 0x05, 0xE0, 0x19, 0x68, 0x7B, 0x22, +0x11, 0x40, 0x1A, 0x68, 0x7F, 0x20, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x62, 0xB6, +0x00, 0xBD, 0xC0, 0x46, 0x64, 0x00, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0x00, 0xB5, 0x72, 0xB6, +0x10, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x10, 0x4B, 0x9A, 0x7C, 0x10, 0x4B, +0x19, 0x68, 0x00, 0x2A, 0x08, 0xD0, 0x49, 0x04, 0x04, 0x22, 0x49, 0x0E, +0x11, 0x43, 0x18, 0x68, 0x0C, 0x4A, 0x09, 0x02, 0x02, 0x40, 0x06, 0xE0, +0x49, 0x06, 0x04, 0x22, 0x49, 0x0E, 0x11, 0x43, 0x1A, 0x68, 0x7F, 0x20, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x62, 0xB6, 0x00, 0xBD, 0x64, 0x00, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x01, 0x4B, 0x18, 0x78, 0x70, 0x47, 0xC0, 0x46, 0x64, 0x00, 0x00, 0x20, +0x00, 0xB5, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x6C, 0x80, 0x22, 0xD2, 0x01, +0x0A, 0x43, 0x1A, 0x64, 0x23, 0x4A, 0x80, 0x21, 0x10, 0x68, 0x49, 0x00, +0x01, 0x43, 0x11, 0x60, 0x12, 0x68, 0x99, 0x68, 0x9A, 0x60, 0x19, 0x6C, +0x80, 0x22, 0x12, 0x02, 0x0A, 0x43, 0x1A, 0x64, 0x19, 0x6C, 0x1D, 0x4A, +0x0A, 0x40, 0x1A, 0x64, 0x1C, 0x4B, 0x7F, 0x22, 0x59, 0x7B, 0x1C, 0x4B, +0x11, 0x40, 0x18, 0x68, 0x1B, 0x4A, 0x09, 0x04, 0x02, 0x40, 0x0A, 0x43, +0x1A, 0x60, 0x19, 0x68, 0xA0, 0x22, 0xD2, 0x05, 0x90, 0x68, 0x91, 0x60, +0x18, 0x68, 0x17, 0x49, 0x01, 0x40, 0x84, 0x20, 0xC0, 0x05, 0x01, 0x43, +0x19, 0x60, 0x19, 0x68, 0x90, 0x68, 0x91, 0x60, 0x13, 0x49, 0x09, 0x78, +0x49, 0xB2, 0x00, 0x29, 0x02, 0xD0, 0x01, 0x29, 0x0C, 0xD1, 0x03, 0xE0, +0x18, 0x68, 0x10, 0x49, 0x01, 0x40, 0x03, 0xE0, 0x18, 0x68, 0x80, 0x21, +0x09, 0x04, 0x01, 0x43, 0x19, 0x60, 0x1B, 0x68, 0x91, 0x68, 0x93, 0x60, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x6C, 0x0A, 0x4A, 0x0A, 0x40, 0x1A, 0x64, +0x00, 0xBD, 0xC0, 0x46, 0x14, 0x00, 0x00, 0x20, 0xFF, 0x7F, 0xFF, 0xFF, +0xAE, 0x09, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0x80, 0xFF, +0xFF, 0xFF, 0xFF, 0x80, 0xFA, 0x02, 0x00, 0x20, 0xFF, 0xFF, 0x7F, 0xFF, +0xFF, 0xBF, 0xFF, 0xFF, 0x04, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x80, 0x23, +0xDB, 0x05, 0x99, 0x6C, 0x91, 0x43, 0x99, 0x64, 0x1A, 0x70, 0x70, 0x47, +0x00, 0x00, 0x00, 0x20, 0x03, 0x4A, 0x01, 0x23, 0x13, 0x70, 0x80, 0x22, +0xD2, 0x05, 0x53, 0x70, 0x70, 0x47, 0xC0, 0x46, 0x02, 0x00, 0x00, 0x20, +0x00, 0xB5, 0x06, 0x4B, 0x72, 0xB6, 0x1A, 0x78, 0x00, 0x2A, 0x04, 0xD0, +0xC0, 0x46, 0xC0, 0x46, 0x62, 0xB6, 0x30, 0xBF, 0xF6, 0xE7, 0x62, 0xB6, +0x00, 0xBD, 0xC0, 0x46, 0x02, 0x00, 0x00, 0x20, 0x38, 0xB5, 0x09, 0x4B, +0x09, 0x49, 0x9A, 0x78, 0x1C, 0x79, 0x51, 0x43, 0x08, 0x4B, 0x05, 0x1C, +0xC9, 0x18, 0x08, 0x48, 0x02, 0xF0, 0x74, 0xF8, 0x06, 0x4B, 0x29, 0x1C, +0x01, 0x34, 0x58, 0x43, 0xA1, 0x40, 0x02, 0xF0, 0x6D, 0xF8, 0x38, 0xBD, +0xAA, 0x0A, 0x00, 0x20, 0x44, 0xFE, 0xFF, 0xFF, 0xFE, 0x24, 0x02, 0x00, +0x40, 0x42, 0x0F, 0x00, 0x05, 0x4B, 0x19, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x5A, 0x69, 0x09, 0x02, 0x12, 0x0E, 0x09, 0x0A, 0x12, 0x06, 0x0A, 0x43, +0x5A, 0x61, 0x70, 0x47, 0x04, 0x00, 0x00, 0x20, 0x01, 0x4B, 0x18, 0x60, +0x70, 0x47, 0xC0, 0x46, 0x04, 0x00, 0x00, 0x20, 0x05, 0x4B, 0x01, 0x22, +0x1A, 0x70, 0x80, 0x23, 0xDB, 0x05, 0x59, 0x69, 0x80, 0x22, 0x52, 0x04, +0x0A, 0x43, 0x5A, 0x61, 0x70, 0x47, 0xC0, 0x46, 0x01, 0x00, 0x00, 0x20, +0x00, 0xB5, 0x05, 0x4B, 0x72, 0xB6, 0x1A, 0x78, 0x00, 0x2A, 0x03, 0xD0, +0xC0, 0x46, 0xC0, 0x46, 0x62, 0xB6, 0xF7, 0xE7, 0x62, 0xB6, 0x00, 0xBD, +0x00, 0x00, 0x00, 0x20, 0x00, 0xB5, 0x10, 0x4B, 0x1B, 0x68, 0x9A, 0x05, +0x0C, 0xD5, 0x0F, 0x4A, 0x0F, 0x4B, 0x72, 0xB6, 0x11, 0x78, 0x00, 0x29, +0x02, 0xD1, 0x19, 0x78, 0x00, 0x29, 0x11, 0xD0, 0xC0, 0x46, 0xC0, 0x46, +0x62, 0xB6, 0xF4, 0xE7, 0x08, 0x4A, 0x09, 0x4B, 0x72, 0xB6, 0x11, 0x78, +0x00, 0x29, 0x02, 0xD1, 0x19, 0x78, 0x00, 0x29, 0x04, 0xD0, 0xC0, 0x46, +0xC0, 0x46, 0x62, 0xB6, 0x30, 0xBF, 0xF3, 0xE7, 0x62, 0xB6, 0x00, 0xBD, +0x58, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, +0x70, 0xB5, 0x13, 0x49, 0x13, 0x4B, 0x04, 0x24, 0x19, 0x60, 0x13, 0x4B, +0x13, 0x4D, 0x1A, 0x68, 0x22, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x02, 0x24, +0xA2, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x01, 0x24, 0x22, 0x43, 0x0F, 0x4C, +0x1A, 0x60, 0x00, 0x22, 0x22, 0x60, 0x0E, 0x4A, 0x11, 0x60, 0x2E, 0x78, +0x2D, 0x79, 0x70, 0x43, 0x01, 0x35, 0xE8, 0x40, 0x09, 0x1A, 0x11, 0x60, +0x20, 0x68, 0x11, 0x68, 0x88, 0x42, 0xFB, 0xD2, 0x1A, 0x68, 0x01, 0x21, +0x8A, 0x43, 0x1A, 0x60, 0x70, 0xBD, 0xC0, 0x46, 0xFF, 0xFF, 0xFF, 0x00, +0x14, 0xE0, 0x00, 0xE0, 0x10, 0xE0, 0x00, 0xE0, 0xAA, 0x0A, 0x00, 0x20, +0x18, 0xE0, 0x00, 0xE0, 0xFC, 0x01, 0x00, 0x20, 0x00, 0xB5, 0x00, 0x23, +0x06, 0x4A, 0x98, 0x42, 0x02, 0xDB, 0xD3, 0x1C, 0xDB, 0x7F, 0x43, 0x43, +0x02, 0x32, 0xD2, 0x7F, 0x01, 0x30, 0x52, 0xB2, 0x90, 0x40, 0x18, 0x18, +0x40, 0x18, 0x00, 0xBD, 0xAE, 0x09, 0x00, 0x20, 0xF0, 0xB5, 0x85, 0xB0, +0x05, 0x1C, 0x0C, 0x1C, 0x16, 0x1C, 0x00, 0x29, 0x05, 0xD0, 0x2B, 0x4B, +0x02, 0x33, 0xDB, 0x7F, 0x5B, 0xB2, 0x00, 0x2B, 0x4E, 0xD0, 0x21, 0x1C, +0x28, 0x1C, 0xFF, 0xF7, 0xDD, 0xFF, 0x27, 0x49, 0x27, 0x4F, 0x4A, 0x7A, +0x09, 0x7A, 0x13, 0x19, 0x51, 0x18, 0x02, 0x91, 0x41, 0x01, 0xCF, 0x19, +0x00, 0x22, 0x03, 0x97, 0x84, 0x46, 0x13, 0xE0, 0x22, 0x48, 0xC1, 0x56, +0x58, 0x1C, 0xC0, 0xB2, 0xCF, 0x0F, 0x01, 0x90, 0x7F, 0x18, 0x03, 0x98, +0x7F, 0x10, 0xC7, 0x19, 0x08, 0x37, 0x00, 0x97, 0x6F, 0x46, 0x38, 0x79, +0x00, 0x9F, 0x02, 0x33, 0xB8, 0x70, 0x01, 0x27, 0x8F, 0x40, 0x3A, 0x43, +0x02, 0x98, 0x83, 0x42, 0xE8, 0xDB, 0x15, 0x4B, 0x60, 0x46, 0xDF, 0x79, +0x61, 0x42, 0x61, 0x41, 0x5B, 0x7C, 0x79, 0x18, 0x1C, 0x19, 0x49, 0x10, +0x01, 0x39, 0x01, 0x34, 0x89, 0x06, 0x24, 0x05, 0x0C, 0x43, 0x22, 0x43, +0x0E, 0x49, 0x10, 0x4C, 0x40, 0x01, 0x43, 0x18, 0x0F, 0x4F, 0x01, 0x19, +0x4C, 0x68, 0x4A, 0x60, 0xAA, 0x1C, 0xD2, 0xB2, 0xC0, 0x19, 0x02, 0x71, +0x00, 0x2E, 0x07, 0xD0, 0x0B, 0x4A, 0x01, 0x21, 0x52, 0x57, 0x91, 0x40, +0x0A, 0x1C, 0x99, 0x69, 0x9A, 0x61, 0x01, 0xE0, 0x9A, 0x69, 0x9E, 0x61, +0x05, 0xB0, 0xF0, 0xBD, 0xAE, 0x09, 0x00, 0x20, 0x0A, 0x03, 0x00, 0x20, +0x00, 0x10, 0x00, 0x40, 0x10, 0x75, 0x00, 0x00, 0x18, 0x10, 0x00, 0x40, +0x10, 0x10, 0x00, 0x40, 0xEA, 0x74, 0x00, 0x00, 0x10, 0xB5, 0x08, 0x4B, +0x00, 0x21, 0x1B, 0x68, 0x01, 0x3B, 0x08, 0xE0, 0x06, 0x4C, 0x58, 0x01, +0x09, 0x22, 0x00, 0x19, 0x84, 0x18, 0xA1, 0x72, 0x01, 0x3A, 0xFB, 0xD2, +0x01, 0x3B, 0x00, 0x2B, 0xF4, 0xDA, 0x10, 0xBD, 0x18, 0x09, 0x00, 0x20, +0x00, 0x10, 0x00, 0x40, 0x38, 0xB5, 0xFF, 0xF7, 0xE7, 0xFF, 0x00, 0x21, +0x01, 0x20, 0x0A, 0x1C, 0x40, 0x42, 0xFF, 0xF7, 0x75, 0xFF, 0x01, 0x20, +0x40, 0x42, 0x01, 0x21, 0x00, 0x22, 0xFF, 0xF7, 0x6F, 0xFF, 0x0A, 0x4D, +0xAC, 0x7B, 0x0B, 0xE0, 0x20, 0x1C, 0x00, 0x21, 0x01, 0x22, 0xFF, 0xF7, +0x67, 0xFF, 0x01, 0x21, 0x20, 0x1C, 0x0A, 0x1C, 0xFF, 0xF7, 0x62, 0xFF, +0x01, 0x34, 0xE4, 0xB2, 0xAA, 0x7B, 0x2B, 0x79, 0xD3, 0x18, 0x9C, 0x42, +0xEE, 0xDB, 0x38, 0xBD, 0x0A, 0x03, 0x00, 0x20, 0xF0, 0xB5, 0x85, 0xB0, +0x05, 0x1C, 0x0E, 0x1C, 0x02, 0x92, 0x1F, 0x1C, 0x00, 0x29, 0x05, 0xD0, +0x21, 0x4B, 0x02, 0x33, 0xDB, 0x7F, 0x5B, 0xB2, 0x00, 0x2B, 0x3B, 0xD0, +0x31, 0x1C, 0x28, 0x1C, 0xFF, 0xF7, 0x34, 0xFF, 0x1D, 0x4A, 0xC0, 0xB2, +0x01, 0x90, 0x53, 0x7A, 0x12, 0x7A, 0xF6, 0x18, 0x9A, 0x18, 0x1B, 0x4B, +0xB9, 0x1E, 0x1B, 0x7C, 0x48, 0x1E, 0x81, 0x41, 0x49, 0x42, 0xF6, 0xB2, +0x03, 0x91, 0x9C, 0x46, 0x24, 0xE0, 0x00, 0x2F, 0x07, 0xD1, 0x26, 0x21, +0x71, 0x43, 0x15, 0x4B, 0x49, 0x19, 0xCC, 0x5C, 0x64, 0x44, 0xE4, 0xB2, +0x08, 0xE0, 0x01, 0x2F, 0x04, 0xD1, 0x73, 0x01, 0x11, 0x49, 0x5B, 0x19, +0x5C, 0x5C, 0x01, 0xE0, 0x03, 0x9B, 0x1C, 0x40, 0x0F, 0x4B, 0x02, 0x99, +0x9B, 0x57, 0x02, 0x36, 0xD8, 0x0F, 0xC0, 0x18, 0x63, 0x18, 0xDB, 0xB2, +0x00, 0x93, 0x01, 0x9B, 0x40, 0x10, 0x59, 0x01, 0x6B, 0x46, 0x08, 0x18, +0x1B, 0x78, 0x09, 0x49, 0xF6, 0xB2, 0x43, 0x54, 0x96, 0x42, 0xD8, 0xDB, +0x05, 0xB0, 0xF0, 0xBD, 0xAE, 0x09, 0x00, 0x20, 0x0A, 0x03, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x36, 0x75, 0x00, 0x00, 0xB3, 0x0A, 0x00, 0x20, +0x10, 0x75, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x70, 0xB5, 0x2A, 0x4B, +0x2A, 0x4A, 0x19, 0x68, 0x80, 0x24, 0x0A, 0x40, 0x1A, 0x60, 0x1A, 0x68, +0xE4, 0x05, 0x28, 0x4D, 0xA1, 0x68, 0xA2, 0x60, 0x69, 0x7A, 0x03, 0x22, +0x18, 0x68, 0x11, 0x40, 0x25, 0x4A, 0x89, 0x04, 0x02, 0x40, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0xA1, 0x68, 0xA2, 0x60, 0x19, 0x68, 0x80, 0x22, +0x52, 0x03, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0xA1, 0x68, 0xA2, 0x60, +0x29, 0x7A, 0x18, 0x68, 0x07, 0x26, 0x1D, 0x4A, 0x31, 0x40, 0x49, 0x05, +0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0xA1, 0x68, 0xA2, 0x60, +0xA9, 0x7B, 0x0F, 0x29, 0x25, 0xD8, 0xEA, 0x7B, 0x0F, 0x2A, 0x22, 0xD8, +0x18, 0x68, 0x09, 0x07, 0x00, 0x01, 0x00, 0x09, 0x01, 0x43, 0x19, 0x60, +0x0F, 0x21, 0x0A, 0x40, 0x18, 0x68, 0x11, 0x06, 0x11, 0x4A, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1B, 0x68, 0xA2, 0x68, 0xA3, 0x60, 0xFF, 0xF7, +0x49, 0xFC, 0x0E, 0x4A, 0x63, 0x6C, 0x13, 0x43, 0x63, 0x64, 0xFF, 0xF7, +0x5C, 0xFC, 0xFF, 0xF7, 0x87, 0xFC, 0xEB, 0x79, 0x0A, 0x4A, 0x1E, 0x40, +0x33, 0x02, 0x26, 0x6C, 0x16, 0x40, 0x1E, 0x43, 0x26, 0x64, 0x70, 0xBD, +0x14, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFC, 0xFF, 0x48, 0x0D, 0x00, 0x20, +0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xF8, 0xFF, 0xFF, 0x00, 0xB5, 0x80, 0x21, +0xC9, 0x05, 0x0B, 0x79, 0x5A, 0x1E, 0xD2, 0xB2, 0x98, 0x42, 0x09, 0xDD, +0x00, 0xE0, 0x0B, 0x71, 0x01, 0x33, 0xDB, 0xB2, 0x83, 0x42, 0xFA, 0xDD, +0x04, 0xE0, 0x0A, 0x71, 0x01, 0x3A, 0xD2, 0xB2, 0x82, 0x42, 0xFA, 0xDA, +0x00, 0xBD, 0x38, 0xB5, 0x17, 0x4C, 0xA0, 0x78, 0xFF, 0xF7, 0xE6, 0xFF, +0x80, 0x23, 0xDB, 0x05, 0x21, 0x79, 0x5A, 0x68, 0xC9, 0x07, 0x52, 0x00, +0x52, 0x08, 0x0A, 0x43, 0x5A, 0x60, 0x60, 0x79, 0x03, 0x22, 0x5D, 0x68, +0x10, 0x49, 0x10, 0x40, 0x80, 0x03, 0x29, 0x40, 0x01, 0x43, 0x59, 0x60, +0xA0, 0x79, 0x0E, 0x49, 0x5D, 0x68, 0x10, 0x40, 0x00, 0x03, 0x29, 0x40, +0x01, 0x43, 0x59, 0x60, 0xE0, 0x79, 0x0B, 0x49, 0x5D, 0x68, 0x10, 0x40, +0x29, 0x40, 0x80, 0x02, 0x01, 0x43, 0x59, 0x60, 0x21, 0x7A, 0x58, 0x68, +0x0A, 0x40, 0x11, 0x02, 0x06, 0x4A, 0x02, 0x40, 0x0A, 0x43, 0x5A, 0x60, +0x38, 0xBD, 0xC0, 0x46, 0xAA, 0x0A, 0x00, 0x20, 0xFF, 0x3F, 0xFF, 0xFF, +0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, +0xF8, 0xB5, 0x80, 0x23, 0xDB, 0x05, 0x1A, 0x68, 0x7A, 0x4A, 0x00, 0x21, +0x08, 0x20, 0x19, 0x60, 0x10, 0x60, 0x14, 0x68, 0x9D, 0x68, 0x9C, 0x60, +0x77, 0x4C, 0x21, 0x60, 0x24, 0x68, 0xDD, 0x68, 0xDC, 0x60, 0xFE, 0x25, +0x75, 0x4C, 0xED, 0x01, 0x25, 0x60, 0x24, 0x68, 0x1D, 0x69, 0x1C, 0x61, +0x5C, 0x69, 0x59, 0x61, 0x9C, 0x69, 0x99, 0x61, 0xDC, 0x69, 0xD9, 0x61, +0x1C, 0x6C, 0x80, 0x24, 0xE4, 0x01, 0x1C, 0x64, 0x5C, 0x6C, 0x59, 0x64, +0x9C, 0x6C, 0x6D, 0x4C, 0x99, 0x64, 0x21, 0x60, 0xA0, 0x24, 0xE4, 0x05, +0xA5, 0x68, 0xA1, 0x60, 0x1C, 0x6C, 0x6A, 0x49, 0x21, 0x40, 0x19, 0x64, +0x1C, 0x68, 0x80, 0x21, 0x49, 0x05, 0x21, 0x43, 0x19, 0x60, 0x67, 0x49, +0x01, 0x31, 0xC9, 0x7F, 0x00, 0x29, 0x03, 0xD0, 0x11, 0x68, 0x08, 0x43, +0x10, 0x60, 0x02, 0xE0, 0x11, 0x68, 0x81, 0x43, 0x11, 0x60, 0x11, 0x68, +0x98, 0x68, 0x99, 0x60, 0x13, 0x68, 0x04, 0x26, 0x33, 0x43, 0x13, 0x60, +0x13, 0x68, 0x80, 0x25, 0xED, 0x05, 0xA9, 0x68, 0xAB, 0x60, 0x13, 0x68, +0x02, 0x27, 0x3B, 0x43, 0x13, 0x60, 0x13, 0x68, 0xA9, 0x68, 0xAB, 0x60, +0x13, 0x68, 0x01, 0x20, 0x83, 0x43, 0x13, 0x60, 0x13, 0x68, 0xAA, 0x68, +0xAB, 0x60, 0xFF, 0xF7, 0xED, 0xFE, 0x54, 0x4B, 0x1C, 0x22, 0x9A, 0x56, +0xA9, 0x69, 0x53, 0x4B, 0x12, 0x05, 0xF2, 0x40, 0x0B, 0x40, 0x13, 0x43, +0xAB, 0x61, 0xFF, 0xF7, 0x61, 0xFE, 0x50, 0x4A, 0x50, 0x4B, 0x01, 0x21, +0x1A, 0x60, 0x50, 0x4B, 0x08, 0x24, 0x1A, 0x68, 0x10, 0x20, 0x32, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0xBA, 0x43, 0x1A, 0x60, 0x4C, 0x4B, 0xC0, 0x22, +0x52, 0x00, 0x99, 0x50, 0x20, 0x21, 0x9F, 0x50, 0x9E, 0x50, 0x9C, 0x50, +0x98, 0x50, 0x99, 0x50, 0x40, 0x21, 0x99, 0x50, 0xC0, 0x22, 0xBA, 0x40, +0x98, 0x58, 0xFF, 0x24, 0xA0, 0x43, 0xC0, 0x24, 0x20, 0x43, 0x98, 0x50, +0x9C, 0x58, 0x43, 0x48, 0x04, 0x40, 0x9C, 0x50, 0x9C, 0x58, 0x42, 0x48, +0x20, 0x40, 0x80, 0x24, 0x24, 0x04, 0x04, 0x43, 0x9C, 0x50, 0x9C, 0x58, +0x24, 0x02, 0x24, 0x0A, 0x2C, 0x43, 0x9C, 0x50, 0xC1, 0x22, 0xBA, 0x40, +0x98, 0x58, 0x04, 0x1C, 0xFF, 0x20, 0x84, 0x43, 0x0C, 0x43, 0x9C, 0x50, +0x9C, 0x58, 0x37, 0x48, 0x20, 0x40, 0x80, 0x24, 0x24, 0x02, 0x20, 0x43, +0x98, 0x50, 0x98, 0x58, 0x34, 0x4C, 0x20, 0x40, 0x98, 0x50, 0x34, 0x4A, +0x10, 0x69, 0x30, 0x43, 0x10, 0x61, 0x62, 0xB6, 0x08, 0x22, 0x01, 0x20, +0x1E, 0x60, 0x18, 0x60, 0x1F, 0x60, 0x1A, 0x60, 0x2F, 0x4B, 0x20, 0x20, +0x10, 0x24, 0xDC, 0x67, 0xD8, 0x67, 0xD9, 0x67, 0xFF, 0xF7, 0x46, 0xFC, +0x21, 0x4C, 0xE0, 0x7D, 0x21, 0x7E, 0xFF, 0xF7, 0xFB, 0xFA, 0xE3, 0x7C, +0x00, 0x2B, 0x26, 0xD0, 0x1A, 0x4B, 0x01, 0x21, 0x18, 0x68, 0x27, 0x4A, +0x40, 0x00, 0x40, 0x0E, 0x08, 0x43, 0x19, 0x68, 0x00, 0x06, 0x11, 0x40, +0x01, 0x43, 0x19, 0x60, 0x19, 0x68, 0x28, 0x69, 0x29, 0x61, 0x19, 0x68, +0x49, 0x00, 0x49, 0x0E, 0x0F, 0x43, 0x39, 0x06, 0x1F, 0x68, 0x17, 0x40, +0x0F, 0x43, 0x1F, 0x60, 0x19, 0x68, 0x28, 0x69, 0x29, 0x61, 0x19, 0x68, +0x49, 0x00, 0x49, 0x0E, 0x0E, 0x43, 0x19, 0x68, 0x36, 0x06, 0x0A, 0x40, +0x32, 0x43, 0x1A, 0x60, 0x1B, 0x68, 0x2A, 0x69, 0x2B, 0x61, 0xFF, 0xF7, +0xD4, 0xFE, 0xFF, 0xF7, 0xC1, 0xF8, 0xFF, 0xF7, 0x0F, 0xF9, 0xFF, 0xF7, +0x7D, 0xF9, 0xFF, 0xF7, 0x65, 0xFB, 0xF8, 0xBD, 0x14, 0x00, 0x00, 0x20, +0x10, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x20, +0xFF, 0xFF, 0x7F, 0xFF, 0xAE, 0x09, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x14, 0xE0, 0x00, 0xE0, +0x10, 0xE0, 0x00, 0xE0, 0x00, 0xE1, 0x00, 0xE0, 0xFF, 0x00, 0xFF, 0xFF, +0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xED, 0x00, 0xE0, 0x04, 0xE1, 0x00, 0xE0, +0xFF, 0xFF, 0xFF, 0x80, 0x08, 0xB5, 0x0C, 0x4A, 0x0C, 0x4B, 0x0D, 0x49, +0x01, 0xE0, 0x01, 0xCA, 0x01, 0xC3, 0x8B, 0x42, 0xFB, 0xD3, 0x0B, 0x4B, +0x0B, 0x49, 0x00, 0x22, 0x00, 0xE0, 0x04, 0xC3, 0x8B, 0x42, 0xFC, 0xD3, +0xFF, 0xF7, 0x26, 0xF8, 0x08, 0x4B, 0x00, 0x22, 0x00, 0xE0, 0x04, 0xC3, +0x83, 0x42, 0xFC, 0xD3, 0x08, 0xBD, 0xC0, 0x46, 0xF8, 0x59, 0x00, 0x00, +0x3C, 0x00, 0x00, 0x20, 0x5C, 0x00, 0x00, 0x20, 0x5C, 0x00, 0x00, 0x20, +0xEC, 0x11, 0x00, 0x20, 0x0C, 0x1E, 0x00, 0x20, 0x00, 0xB5, 0x13, 0x4B, +0x1B, 0x68, 0x01, 0x2B, 0x02, 0xD0, 0x08, 0x2B, 0x1E, 0xD1, 0x0F, 0xE0, +0x10, 0x4B, 0x11, 0x4A, 0x1A, 0x60, 0x11, 0x4A, 0x5A, 0x60, 0x11, 0x4A, +0x11, 0x4B, 0x1A, 0x60, 0x11, 0x4B, 0x12, 0x4A, 0x1A, 0x60, 0x12, 0x4A, +0x5A, 0x60, 0x12, 0x4A, 0x9A, 0x60, 0x0D, 0xE0, 0x09, 0x4B, 0x08, 0x4A, +0x09, 0x49, 0x13, 0x60, 0x51, 0x60, 0x0A, 0x4A, 0x13, 0x60, 0x0A, 0x4A, +0x13, 0x60, 0x53, 0x60, 0x93, 0x60, 0x0C, 0x4B, 0x01, 0x22, 0x1A, 0x70, +0x00, 0xBD, 0xC0, 0x46, 0x50, 0x11, 0x00, 0x20, 0x68, 0x00, 0x00, 0x20, +0xF9, 0x03, 0x00, 0x00, 0x85, 0x3F, 0x00, 0x00, 0xBD, 0x3F, 0x00, 0x00, +0x00, 0x02, 0x00, 0x20, 0x18, 0x00, 0x00, 0x20, 0xC9, 0x40, 0x00, 0x00, +0xB1, 0x42, 0x00, 0x00, 0x15, 0x44, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x20, +0x00, 0xB5, 0x00, 0x23, 0xC2, 0x5C, 0x01, 0x33, 0x00, 0x2A, 0xFB, 0xD1, +0x01, 0x3B, 0xD8, 0xB2, 0x00, 0xBD, 0xC0, 0x46, 0xF7, 0xB5, 0x1C, 0x1C, +0x08, 0xAB, 0x1F, 0x78, 0x26, 0x4B, 0x0E, 0x1C, 0x1B, 0x68, 0x01, 0x21, +0x81, 0x40, 0x0B, 0x42, 0x44, 0xD0, 0x00, 0x2F, 0x07, 0xD0, 0x04, 0x2C, +0x32, 0xD8, 0x22, 0x4B, 0x19, 0x5D, 0x05, 0x33, 0x00, 0x91, 0x1F, 0x5D, +0x08, 0xE0, 0x04, 0x2C, 0x2E, 0xD8, 0x1E, 0x4B, 0x19, 0x1C, 0x0A, 0x31, +0x09, 0x5D, 0x0F, 0x33, 0x1F, 0x5D, 0x00, 0x91, 0x03, 0x2C, 0x28, 0xD0, +0x00, 0x2C, 0x28, 0xD0, 0x28, 0xE0, 0x3A, 0x20, 0x21, 0x1C, 0x01, 0xF0, +0x5D, 0xFC, 0x86, 0x42, 0x05, 0xDD, 0x6B, 0x46, 0x1B, 0x78, 0xC0, 0xB2, +0x2B, 0x70, 0x68, 0x70, 0x02, 0xE0, 0x2F, 0x70, 0x30, 0x1C, 0x6E, 0x70, +0x36, 0x1A, 0x60, 0x43, 0x01, 0x99, 0x00, 0x23, 0x69, 0x60, 0xAB, 0x60, +0x09, 0x18, 0xF6, 0xB2, 0x01, 0x91, 0xFF, 0xF7, 0xE3, 0xFA, 0xFF, 0xF7, +0x37, 0xFB, 0x00, 0x28, 0xFB, 0xD1, 0x0B, 0xE0, 0x0F, 0x23, 0x00, 0x27, +0x00, 0x93, 0x05, 0xE0, 0x0F, 0x21, 0x00, 0x91, 0x02, 0xE0, 0x02, 0x24, +0x00, 0xE0, 0x01, 0x24, 0x04, 0x4D, 0x01, 0x92, 0x00, 0x2E, 0xD2, 0xD1, +0xF7, 0xBD, 0xC0, 0x46, 0x58, 0x00, 0x00, 0x20, 0x6F, 0x59, 0x00, 0x00, +0x70, 0x00, 0x00, 0x20, 0x38, 0xB5, 0x11, 0x4B, 0x01, 0x22, 0x1B, 0x68, +0x82, 0x40, 0x0D, 0x1C, 0x13, 0x42, 0x19, 0xD0, 0x0E, 0x4C, 0x0B, 0x23, +0x23, 0x70, 0x08, 0x1C, 0xFF, 0xF7, 0x90, 0xFF, 0x60, 0x70, 0x63, 0x78, +0x07, 0x22, 0x02, 0x33, 0x13, 0x40, 0x93, 0x42, 0x03, 0xD1, 0x63, 0x78, +0x01, 0x3B, 0xDB, 0xB2, 0x63, 0x70, 0x00, 0x23, 0x65, 0x60, 0xA3, 0x60, +0xFF, 0xF7, 0xAA, 0xFA, 0xFF, 0xF7, 0xFE, 0xFA, 0x00, 0x28, 0xFB, 0xD1, +0x38, 0xBD, 0xC0, 0x46, 0x58, 0x00, 0x00, 0x20, 0x70, 0x00, 0x00, 0x20, +0x1F, 0xB5, 0x0B, 0x4C, 0x6B, 0x46, 0xD8, 0x73, 0x23, 0x78, 0x00, 0x2B, +0x03, 0xD0, 0x00, 0x20, 0x08, 0x49, 0xFF, 0xF7, 0xCD, 0xFF, 0x23, 0x78, +0x00, 0x2B, 0x07, 0xD0, 0x6A, 0x46, 0x01, 0x21, 0x00, 0x20, 0x0F, 0x32, +0x04, 0x23, 0x00, 0x91, 0xFF, 0xF7, 0x6A, 0xFF, 0x1F, 0xBD, 0xC0, 0x46, +0xEB, 0x01, 0x00, 0x20, 0x83, 0x59, 0x00, 0x00, 0xF8, 0xB5, 0xFF, 0xF7, +0xD7, 0xFA, 0x00, 0x28, 0x70, 0xD1, 0x39, 0x4B, 0x1A, 0x68, 0x00, 0x2A, +0x03, 0xDC, 0x38, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x3E, 0xDD, 0x37, 0x49, +0x03, 0x23, 0x0B, 0x70, 0x36, 0x4B, 0x04, 0x33, 0xDB, 0x7F, 0x1C, 0x1C, +0x9A, 0x42, 0x00, 0xDA, 0xD3, 0xB2, 0x4B, 0x70, 0x0A, 0x21, 0x8C, 0x46, +0x32, 0x4A, 0x00, 0x23, 0x2D, 0x49, 0x1F, 0xE0, 0x01, 0x33, 0x03, 0xE0, +0x66, 0x46, 0x5E, 0x43, 0x00, 0x20, 0x76, 0x18, 0x0A, 0x30, 0x37, 0x18, +0x32, 0x25, 0x7F, 0x5F, 0x00, 0x2F, 0xF3, 0xD0, 0xA3, 0x42, 0x13, 0xDA, +0x58, 0x00, 0x08, 0x18, 0x80, 0x88, 0xDE, 0x00, 0x10, 0x70, 0x00, 0xB2, +0x00, 0x12, 0x80, 0x19, 0x50, 0x70, 0x18, 0x1C, 0x10, 0x30, 0x40, 0x00, +0x08, 0x5A, 0x01, 0x33, 0x90, 0x70, 0x00, 0x0A, 0xD0, 0x70, 0x04, 0x32, +0xA3, 0x42, 0xDF, 0xDB, 0x1D, 0x4B, 0x1F, 0x4A, 0x5A, 0x60, 0x00, 0x22, +0x9A, 0x60, 0xFF, 0xF7, 0x3D, 0xFA, 0xFF, 0xF7, 0x91, 0xFA, 0x00, 0x28, +0xFB, 0xD1, 0x29, 0xE0, 0x1A, 0x4A, 0x53, 0x68, 0x01, 0x33, 0x25, 0xD0, +0x15, 0x4B, 0x13, 0x21, 0x19, 0x70, 0x11, 0x68, 0x94, 0x46, 0x59, 0x70, +0x16, 0x4B, 0x14, 0x49, 0x1D, 0x78, 0x03, 0x1C, 0x0D, 0xE0, 0x23, 0x1C, +0x01, 0xE0, 0x5E, 0x00, 0x66, 0x44, 0x02, 0x30, 0x34, 0x18, 0x06, 0x22, +0xA7, 0x5E, 0x5C, 0x1C, 0x00, 0x2F, 0xF4, 0xD0, 0x0B, 0x70, 0x23, 0x1C, +0x01, 0x31, 0x00, 0x20, 0xAB, 0x42, 0xF0, 0xDB, 0x07, 0x4B, 0x09, 0x4A, +0x98, 0x60, 0x5A, 0x60, 0xFF, 0xF7, 0x12, 0xFA, 0xFF, 0xF7, 0x66, 0xFA, +0x00, 0x28, 0xFB, 0xD1, 0xF8, 0xBD, 0xC0, 0x46, 0x9C, 0x0D, 0x00, 0x20, +0x20, 0x01, 0x00, 0x20, 0x70, 0x00, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0xF0, 0x09, 0x00, 0x20, 0xE0, 0x00, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, +0x08, 0xB5, 0x64, 0x4B, 0x1B, 0x88, 0x1D, 0x2B, 0x47, 0xD0, 0x1A, 0xD8, +0x05, 0x2B, 0x00, 0xD1, 0x96, 0xE0, 0x0D, 0xD8, 0x02, 0x2B, 0x63, 0xD0, +0x03, 0xD8, 0x01, 0x2B, 0x00, 0xD0, 0xB7, 0xE0, 0x57, 0xE0, 0x03, 0x2B, +0x00, 0xD1, 0x87, 0xE0, 0x04, 0x2B, 0x00, 0xD0, 0xB0, 0xE0, 0x8F, 0xE0, +0x07, 0x2B, 0x65, 0xD0, 0x5C, 0xD3, 0x1B, 0x2B, 0x1C, 0xD0, 0x1C, 0x2B, +0x00, 0xD0, 0xA7, 0xE0, 0x22, 0xE0, 0x22, 0x2B, 0x40, 0xD0, 0x08, 0xD8, +0x1F, 0x2B, 0x5D, 0xD0, 0x2A, 0xD3, 0x20, 0x2B, 0x5E, 0xD0, 0x21, 0x2B, +0x00, 0xD0, 0x9B, 0xE0, 0x5E, 0xE0, 0x41, 0x2B, 0x64, 0xD0, 0x03, 0xD8, +0x40, 0x2B, 0x00, 0xD0, 0x94, 0xE0, 0x5B, 0xE0, 0x42, 0x2B, 0x61, 0xD0, +0x60, 0x2B, 0x00, 0xD0, 0x8E, 0xE0, 0x72, 0xE0, 0x48, 0x4A, 0x49, 0x4B, +0x12, 0x78, 0x01, 0x20, 0x19, 0x68, 0x90, 0x40, 0x02, 0x1C, 0x0A, 0x43, +0x1A, 0x60, 0x83, 0xE0, 0x43, 0x49, 0x44, 0x4B, 0x09, 0x78, 0x1A, 0x68, +0x01, 0x20, 0x88, 0x40, 0x82, 0x43, 0x1A, 0x60, 0x7A, 0xE0, 0x3F, 0x4B, +0x1A, 0x78, 0x40, 0x4B, 0x1A, 0x70, 0x75, 0xE0, 0x3C, 0x4B, 0x0D, 0x21, +0x1A, 0x78, 0x3E, 0x4B, 0x1A, 0x70, 0x3C, 0x4A, 0x11, 0x70, 0x1A, 0x78, +0x3C, 0x4B, 0x00, 0x2A, 0x02, 0xD0, 0x00, 0x22, 0x5A, 0x70, 0x67, 0xE0, +0x3A, 0x4A, 0x52, 0x78, 0x5A, 0x70, 0x63, 0xE0, 0x33, 0x4B, 0x1A, 0x78, +0x38, 0x4B, 0x1A, 0x70, 0x5E, 0xE0, 0x31, 0x4B, 0x1A, 0x78, 0x37, 0x4B, +0x1A, 0x60, 0xFD, 0xF7, 0x09, 0xFC, 0x57, 0xE0, 0x2D, 0x4B, 0x1A, 0x78, +0x34, 0x4B, 0x9A, 0x70, 0x98, 0x78, 0xFF, 0xF7, 0x8D, 0xFC, 0x4F, 0xE0, +0x29, 0x4B, 0x1A, 0x78, 0x30, 0x4B, 0x9A, 0x70, 0x29, 0x4B, 0x0F, 0x22, +0x1A, 0x70, 0x47, 0xE0, 0x2E, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x43, 0xE0, +0x2D, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x3F, 0xE0, 0x0C, 0x20, 0xFD, 0xF7, +0x85, 0xF9, 0x3B, 0xE0, 0x0D, 0x20, 0xFD, 0xF7, 0x81, 0xF9, 0x37, 0xE0, +0x28, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x33, 0xE0, 0x27, 0x4B, 0x01, 0x22, +0x1A, 0x70, 0x2F, 0xE0, 0x26, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x2B, 0xE0, +0x25, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x27, 0xE0, 0x24, 0x4B, 0x01, 0x22, +0x1A, 0x70, 0x14, 0x4B, 0x1A, 0x78, 0x23, 0x4B, 0x1A, 0x70, 0x1F, 0xE0, +0x11, 0x4B, 0x1A, 0x78, 0x1E, 0x4B, 0x9A, 0x70, 0x1A, 0xE0, 0x0F, 0x4B, +0x1A, 0x78, 0x1F, 0x4B, 0x1A, 0x70, 0x1A, 0x78, 0x10, 0x4B, 0x01, 0x3A, +0x01, 0x2A, 0x03, 0xD8, 0x40, 0x33, 0x0F, 0x22, 0x1A, 0x70, 0x0D, 0xE0, +0x1A, 0x4A, 0x40, 0x33, 0x12, 0x78, 0x00, 0x2A, 0x04, 0xD0, 0x19, 0x4A, +0x40, 0x32, 0x12, 0x78, 0x1A, 0x70, 0x03, 0xE0, 0x08, 0x4A, 0x40, 0x32, +0x12, 0x78, 0x1A, 0x70, 0x08, 0xBD, 0xC0, 0x46, 0x28, 0x00, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x50, 0x58, 0x00, 0x00, 0x20, 0x1D, 0x03, 0x00, 0x20, +0xE3, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x4A, 0x74, 0x00, 0x00, +0xDE, 0x01, 0x00, 0x20, 0x50, 0x11, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, +0xE4, 0x01, 0x00, 0x20, 0xDC, 0x01, 0x00, 0x20, 0xE8, 0x01, 0x00, 0x20, +0xE7, 0x01, 0x00, 0x20, 0xE5, 0x01, 0x00, 0x20, 0x8B, 0x01, 0x00, 0x20, +0xE6, 0x01, 0x00, 0x20, 0x92, 0x01, 0x00, 0x20, 0xE0, 0x01, 0x00, 0x20, +0xDD, 0x01, 0x00, 0x20, 0x9A, 0x74, 0x00, 0x00, 0x30, 0xB5, 0x4A, 0x4B, +0x1B, 0x88, 0x34, 0x2B, 0x47, 0xD0, 0x0C, 0xD8, 0x2E, 0x2B, 0x4F, 0xD0, +0x04, 0xD8, 0x00, 0x2B, 0x14, 0xD0, 0x1D, 0x2B, 0x78, 0xD1, 0x16, 0xE0, +0x2F, 0x2B, 0x51, 0xD0, 0x30, 0x2B, 0x73, 0xD1, 0x56, 0xE0, 0x38, 0x2B, +0x66, 0xD0, 0x04, 0xD8, 0x35, 0x2B, 0x39, 0xD0, 0x37, 0x2B, 0x6B, 0xD1, +0x5B, 0xE0, 0x39, 0x2B, 0x63, 0xD0, 0x86, 0x2B, 0x66, 0xD1, 0x09, 0xE0, +0x3B, 0x4B, 0x5A, 0x7B, 0x3B, 0x4B, 0x1A, 0x70, 0x6F, 0xE0, 0x3B, 0x4B, +0x1A, 0x78, 0x39, 0x4B, 0x1A, 0x70, 0x6A, 0xE0, 0x39, 0x49, 0x3A, 0x4A, +0x0B, 0x78, 0x00, 0x2B, 0x0F, 0xD1, 0x10, 0x78, 0x34, 0x49, 0x08, 0x70, +0x50, 0x78, 0x37, 0x49, 0x08, 0x70, 0x52, 0x68, 0xD1, 0x18, 0x36, 0x4C, +0x08, 0x78, 0x19, 0x19, 0x01, 0x33, 0x08, 0x70, 0x06, 0x2B, 0xF7, 0xD1, +0x55, 0xE0, 0x52, 0x68, 0x00, 0x23, 0x08, 0x78, 0x2B, 0x4D, 0xC0, 0x18, +0x02, 0x38, 0x10, 0x18, 0x04, 0x78, 0x58, 0x19, 0x01, 0x33, 0x04, 0x70, +0x08, 0x2B, 0xF4, 0xD1, 0x47, 0xE0, 0x2C, 0x4B, 0x1A, 0x68, 0x25, 0x4B, +0x1A, 0x60, 0x42, 0xE0, 0x80, 0x23, 0xDB, 0x05, 0x1A, 0x79, 0x22, 0x4B, +0x1A, 0x70, 0x3C, 0xE0, 0x22, 0x4B, 0x27, 0x4A, 0x1B, 0x78, 0x1F, 0x49, +0xD3, 0x18, 0x1A, 0x68, 0x5B, 0x68, 0x0A, 0x60, 0x4B, 0x60, 0x32, 0xE0, +0x1A, 0x4B, 0x1A, 0x1C, 0x2C, 0x32, 0x11, 0x78, 0x19, 0x4A, 0x00, 0x29, +0x07, 0xD1, 0x09, 0xE0, 0x16, 0x4B, 0x1A, 0x1C, 0x2C, 0x32, 0x11, 0x78, +0x15, 0x4A, 0x00, 0x29, 0x02, 0xD1, 0xDB, 0x8C, 0x13, 0x80, 0x20, 0xE0, +0x1B, 0x8D, 0x13, 0x80, 0x1D, 0xE0, 0x19, 0x4B, 0x1A, 0x78, 0x10, 0x4B, +0x1A, 0x70, 0x18, 0xE0, 0x17, 0x4B, 0x1A, 0x78, 0x0D, 0x4B, 0x1A, 0x70, +0x13, 0xE0, 0x16, 0x4B, 0x1A, 0x78, 0x0B, 0x4B, 0x1A, 0x70, 0x0E, 0xE0, +0x90, 0x3B, 0x9A, 0xB2, 0x13, 0x2A, 0x0A, 0xD8, 0x09, 0x4A, 0x5B, 0x01, +0x12, 0x78, 0x06, 0x49, 0x9B, 0x18, 0x10, 0x4A, 0x9B, 0x18, 0x1A, 0x68, +0x5B, 0x68, 0x0A, 0x60, 0x4B, 0x60, 0x30, 0xBD, 0x28, 0x00, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x50, 0x1D, 0x03, 0x00, 0x20, +0x2A, 0x00, 0x00, 0x20, 0x70, 0x00, 0x00, 0x20, 0x0D, 0x00, 0x00, 0x50, +0x0E, 0x00, 0x00, 0x50, 0x1C, 0x09, 0x00, 0x20, 0xB1, 0x09, 0x00, 0x20, +0xFF, 0x5B, 0x00, 0x00, 0xFF, 0x73, 0x00, 0x00, 0xFF, 0x7B, 0x00, 0x00, +0xB3, 0x0A, 0x00, 0x20, 0x08, 0xB5, 0x08, 0x4B, 0x1B, 0x88, 0x86, 0x2B, +0x0B, 0xD1, 0x07, 0x4B, 0x9A, 0x68, 0x01, 0x2A, 0x02, 0xDC, 0x9A, 0x68, +0x01, 0x32, 0x9A, 0x60, 0x9B, 0x68, 0x02, 0x2B, 0x01, 0xD1, 0xFF, 0xF7, +0x71, 0xF8, 0x08, 0xBD, 0x28, 0x00, 0x00, 0x20, 0x70, 0x00, 0x00, 0x20, +0x7F, 0xB5, 0x31, 0x4C, 0x03, 0x90, 0x23, 0x78, 0x0D, 0x1C, 0x16, 0x1C, +0x00, 0x2B, 0x03, 0xD0, 0x01, 0x20, 0x2E, 0x49, 0xFF, 0xF7, 0x6E, 0xFD, +0x23, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x21, 0x08, 0x1C, 0x03, 0xAA, +0x04, 0x23, 0x00, 0x91, 0xFF, 0xF7, 0x0C, 0xFD, 0x28, 0x4B, 0x03, 0x99, +0x1B, 0x78, 0x28, 0x4A, 0x00, 0x2B, 0x15, 0xD1, 0x13, 0x1C, 0x4A, 0x33, +0x00, 0x20, 0x1B, 0x5E, 0x8E, 0x1B, 0x9E, 0x42, 0x05, 0xDC, 0x13, 0x1C, +0x4C, 0x33, 0x00, 0x20, 0x1B, 0x5E, 0x9E, 0x42, 0x08, 0xDA, 0x21, 0x48, +0x01, 0x23, 0x03, 0x70, 0x20, 0x48, 0x03, 0x70, 0x20, 0x48, 0x03, 0x70, +0x20, 0x48, 0x03, 0x70, 0x53, 0x78, 0x00, 0x2B, 0x04, 0xD0, 0x1F, 0x4B, +0x5B, 0x5D, 0x59, 0x43, 0x89, 0x11, 0x03, 0x91, 0x1D, 0x4B, 0x6A, 0x00, +0xD0, 0x5A, 0x1D, 0x4B, 0x03, 0x99, 0xD4, 0x5E, 0xC0, 0x08, 0x14, 0x4A, +0x89, 0xB2, 0x04, 0x1B, 0x64, 0x1A, 0x56, 0x7C, 0x24, 0xB2, 0x19, 0x4B, +0xB4, 0x42, 0x02, 0xDC, 0x76, 0x42, 0xB4, 0x42, 0x02, 0xDA, 0x00, 0x24, +0x5C, 0x55, 0x05, 0xE0, 0x5C, 0x5D, 0x96, 0x7C, 0xA6, 0x42, 0x01, 0xD0, +0x01, 0x34, 0x5C, 0x55, 0x43, 0x1A, 0x9B, 0xB2, 0x92, 0x7E, 0x19, 0xB2, +0x91, 0x42, 0x02, 0xDB, 0x09, 0x4A, 0x01, 0x21, 0x11, 0x70, 0x0C, 0x4A, +0x6D, 0x00, 0xAB, 0x52, 0x7F, 0xBD, 0xC0, 0x46, 0xEB, 0x01, 0x00, 0x20, +0x87, 0x59, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x48, 0x11, 0x00, 0x20, 0x14, 0x09, 0x00, 0x20, 0x30, 0x11, 0x00, 0x20, +0xC4, 0x01, 0x00, 0x20, 0x92, 0x7B, 0x00, 0x00, 0x14, 0x02, 0x00, 0x20, +0x3C, 0x0D, 0x00, 0x20, 0xA4, 0x0A, 0x00, 0x20, 0xF0, 0xB5, 0x48, 0x4B, +0x89, 0xB0, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x46, 0x49, +0xFF, 0xF7, 0xF4, 0xFC, 0x45, 0x4A, 0x00, 0x23, 0x13, 0x70, 0x45, 0x4A, +0x0C, 0x20, 0x01, 0x38, 0xC0, 0xB2, 0x81, 0x00, 0x8B, 0x50, 0x00, 0x28, +0xF9, 0xD1, 0x42, 0x4B, 0x42, 0x4A, 0x18, 0x70, 0x01, 0x23, 0x13, 0x70, +0x41, 0x4A, 0x13, 0x70, 0x41, 0x4B, 0x19, 0x7E, 0x04, 0x91, 0xDA, 0x7D, +0x05, 0x92, 0x1B, 0x7D, 0x06, 0x93, 0x0B, 0x1C, 0x2D, 0xE0, 0x01, 0x3B, +0xDB, 0xB2, 0x5D, 0x1C, 0x3C, 0x4C, 0xEA, 0x01, 0x12, 0x19, 0x16, 0x88, +0x3B, 0x49, 0x5A, 0x00, 0x5C, 0x01, 0x56, 0x52, 0xAD, 0x01, 0x05, 0x9A, +0x07, 0x94, 0x9C, 0x46, 0x1A, 0xE0, 0x01, 0x3A, 0xD2, 0xB2, 0x93, 0x1C, +0xEB, 0x18, 0x36, 0x4C, 0x5B, 0x00, 0x19, 0x5B, 0x06, 0x9B, 0x00, 0x2B, +0x05, 0xD0, 0xD3, 0x1C, 0xEB, 0x18, 0x5B, 0x00, 0x1B, 0x5B, 0xC9, 0x18, +0x49, 0x10, 0x07, 0x9C, 0xA7, 0x18, 0x7B, 0x00, 0x1C, 0x1C, 0x2F, 0x4B, +0xE1, 0x52, 0x2F, 0x4C, 0x01, 0x23, 0x89, 0x1B, 0x3B, 0x55, 0x40, 0x18, +0x00, 0x2A, 0xE2, 0xD1, 0x63, 0x46, 0x00, 0x2B, 0xCF, 0xD1, 0x25, 0x4B, +0x04, 0x9C, 0xD9, 0x7D, 0x61, 0x43, 0x01, 0xF0, 0xCF, 0xF8, 0x28, 0x4B, +0x05, 0x1C, 0x58, 0x8C, 0x27, 0x4C, 0x00, 0x28, 0x02, 0xD1, 0x40, 0x23, +0x23, 0x60, 0x07, 0xE0, 0x80, 0x01, 0x29, 0x1C, 0x01, 0xF0, 0xC2, 0xF8, +0x6E, 0x28, 0x00, 0xDD, 0x6E, 0x20, 0x20, 0x60, 0x12, 0x4C, 0x23, 0x78, +0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x1F, 0x49, 0xFF, 0xF7, 0x8A, 0xFC, +0x1B, 0x4B, 0x1E, 0x4A, 0x5B, 0x8C, 0x55, 0x80, 0x13, 0x80, 0x23, 0x78, +0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, 0x00, 0x93, 0x00, 0x20, +0x0B, 0x1C, 0xFF, 0xF7, 0x23, 0xFC, 0x18, 0x4B, 0x18, 0x48, 0x1B, 0x78, +0x00, 0x22, 0x18, 0x49, 0x04, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x5C, 0x00, +0xC2, 0x54, 0x62, 0x52, 0x00, 0x2B, 0xF8, 0xD1, 0x09, 0xB0, 0xF0, 0xBD, +0xEB, 0x01, 0x00, 0x20, 0x8D, 0x59, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x20, +0xBC, 0x11, 0x00, 0x20, 0xF4, 0x10, 0x00, 0x20, 0x20, 0x09, 0x00, 0x20, +0x3C, 0x11, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x02, 0x40, 0x00, 0x40, +0x94, 0x11, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0xF8, 0x03, 0x00, 0x20, +0xB3, 0x0A, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x78, 0x09, 0x00, 0x20, +0x96, 0x59, 0x00, 0x00, 0x54, 0x11, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, +0xA4, 0x0A, 0x00, 0x20, 0x14, 0x02, 0x00, 0x20, 0xF0, 0xB5, 0xA0, 0x4A, +0x00, 0x23, 0x13, 0x70, 0x9F, 0x4A, 0x85, 0xB0, 0x13, 0x70, 0x9F, 0x4A, +0x13, 0x70, 0x9F, 0x4A, 0x13, 0x70, 0x9F, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x03, 0xD0, 0x01, 0x20, 0x9D, 0x49, 0xFF, 0xF7, 0x31, 0xFC, 0x00, 0x24, +0x9C, 0x4D, 0x9A, 0x4E, 0x11, 0xE0, 0x33, 0x78, 0x00, 0x2B, 0x0C, 0xD0, +0xEB, 0x7D, 0x29, 0x7D, 0x99, 0x48, 0xC9, 0x18, 0xE2, 0x01, 0x00, 0x23, +0x12, 0x18, 0x00, 0x93, 0xC9, 0xB2, 0x01, 0x20, 0x02, 0x23, 0xFF, 0xF7, +0xC5, 0xFB, 0x01, 0x34, 0xE4, 0xB2, 0x29, 0x7E, 0x8C, 0x42, 0xEA, 0xD3, +0x92, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD1, 0x0D, 0xE1, 0x91, 0x4B, +0x1A, 0x78, 0x00, 0x2A, 0x1F, 0xD1, 0x90, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x1B, 0xD0, 0xEB, 0x7D, 0x8E, 0x4C, 0x07, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, +0x5D, 0x01, 0x2D, 0x18, 0x2A, 0x55, 0x00, 0x2B, 0xF8, 0xD1, 0x03, 0x1C, +0x58, 0x1E, 0xC0, 0xB2, 0x00, 0x2B, 0x01, 0xD0, 0x0B, 0x1C, 0xF6, 0xE7, +0x87, 0x4A, 0x86, 0x48, 0x12, 0x78, 0x49, 0x01, 0x03, 0xE0, 0x01, 0x3A, +0xD2, 0xB2, 0x8C, 0x18, 0x23, 0x54, 0x00, 0x2A, 0xF9, 0xD1, 0x80, 0x4B, +0x7E, 0x4A, 0x19, 0x78, 0x1B, 0x78, 0x11, 0x70, 0x00, 0x2B, 0x70, 0xD0, +0x78, 0x4B, 0x1A, 0x7E, 0xD9, 0x7D, 0x02, 0x92, 0x1B, 0x7D, 0x03, 0x93, +0x22, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x59, 0x1C, 0x89, 0x01, 0xC8, 0x19, +0x79, 0x4C, 0x03, 0x9D, 0x40, 0x00, 0x00, 0x5B, 0x00, 0x2D, 0x04, 0xD0, +0x89, 0x19, 0x49, 0x00, 0x09, 0x5B, 0x40, 0x18, 0x40, 0x10, 0x59, 0x01, +0x89, 0x18, 0x74, 0x4D, 0x4C, 0x00, 0x65, 0x5B, 0x6F, 0x4C, 0xED, 0x08, +0x0C, 0x5D, 0x28, 0x1A, 0x84, 0x42, 0x04, 0xDA, 0xFF, 0x28, 0x00, 0xDD, +0xFF, 0x20, 0x6B, 0x4D, 0x68, 0x54, 0x00, 0x2B, 0xDD, 0xD1, 0x11, 0x1C, +0x4A, 0x1E, 0xD2, 0xB2, 0x00, 0x29, 0x03, 0xD0, 0x02, 0x9B, 0x97, 0x1C, +0xD6, 0x1C, 0xF4, 0xE7, 0x5F, 0x4A, 0x65, 0x4B, 0x17, 0x7E, 0x1B, 0x78, +0x62, 0x49, 0x7F, 0x01, 0x10, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x64, 0x4E, +0x5A, 0x00, 0x94, 0x5B, 0xF8, 0x18, 0x45, 0x56, 0x26, 0xB2, 0x2A, 0x1C, +0xB5, 0x42, 0x00, 0xDA, 0x22, 0x1C, 0x12, 0xB2, 0xFF, 0x2A, 0x00, 0xDD, +0xFF, 0x22, 0x42, 0x54, 0x00, 0x2B, 0xEC, 0xD1, 0x50, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x03, 0xD0, 0x03, 0x20, 0x5A, 0x49, 0xFF, 0xF7, 0x94, 0xFB, +0x00, 0x24, 0x4E, 0x4D, 0x4B, 0x4E, 0x0E, 0xE0, 0x33, 0x78, 0x00, 0x2B, +0x09, 0xD0, 0x50, 0x4B, 0x62, 0x01, 0xD2, 0x18, 0x00, 0x23, 0xE9, 0x7D, +0x03, 0x20, 0x00, 0x93, 0x01, 0x23, 0xFF, 0xF7, 0x2B, 0xFB, 0x01, 0x34, +0xE4, 0xB2, 0x2B, 0x7E, 0xA3, 0x42, 0xED, 0xD8, 0x40, 0x4A, 0x01, 0x23, +0x13, 0x70, 0x3D, 0x4A, 0x13, 0x70, 0x3B, 0x4A, 0x13, 0x70, 0x3E, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x6D, 0xD0, 0x49, 0x4B, 0x1B, 0x68, 0x58, 0x02, +0x69, 0xD5, 0x3C, 0x4A, 0x80, 0x24, 0x16, 0x7D, 0x13, 0x7E, 0xD2, 0x7D, +0x45, 0x4D, 0xB6, 0x18, 0xF6, 0xB2, 0x24, 0x06, 0xB4, 0x46, 0x18, 0xE0, +0x01, 0x3B, 0xDB, 0xB2, 0x42, 0x49, 0x5A, 0x00, 0x5F, 0x1C, 0x56, 0x5A, +0xBF, 0x01, 0x62, 0x46, 0x0D, 0xE0, 0x01, 0x3A, 0xD2, 0xB2, 0x91, 0x1C, +0x79, 0x18, 0x37, 0x48, 0x49, 0x00, 0x09, 0x5A, 0x89, 0x1B, 0x8C, 0x42, +0x00, 0xDA, 0x0C, 0x1C, 0x8D, 0x42, 0x00, 0xDD, 0x0D, 0x1C, 0x00, 0x2A, +0xEF, 0xD1, 0x00, 0x2B, 0xE4, 0xD1, 0x16, 0x20, 0x36, 0x49, 0xFF, 0xF7, +0x45, 0xFB, 0x25, 0x4B, 0x35, 0x4A, 0x1B, 0x78, 0x14, 0x80, 0x55, 0x80, +0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, 0x00, 0x93, 0x16, 0x20, +0x0B, 0x1C, 0xFF, 0xF7, 0xDF, 0xFA, 0x26, 0x4B, 0x80, 0x20, 0x1B, 0x78, +0x2A, 0x49, 0x00, 0x06, 0x2D, 0x4E, 0x2E, 0x4D, 0x19, 0xE0, 0x01, 0x3B, +0xDB, 0xB2, 0xF7, 0x5C, 0x7A, 0x1C, 0x94, 0x46, 0x64, 0x46, 0xEA, 0x5C, +0xA4, 0x01, 0xA4, 0x46, 0x02, 0x32, 0x62, 0x44, 0x1D, 0x4C, 0x52, 0x00, +0x12, 0x5B, 0x22, 0x4C, 0x7F, 0x00, 0x94, 0x46, 0x3A, 0x5B, 0x64, 0x46, +0xA2, 0x1A, 0x90, 0x42, 0x00, 0xDA, 0x10, 0x1C, 0x91, 0x42, 0x00, 0xDD, +0x11, 0x1C, 0x00, 0x2B, 0xE3, 0xD1, 0x0C, 0x4B, 0x1C, 0x4A, 0x1B, 0x78, +0x10, 0x80, 0x51, 0x80, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, +0x00, 0x93, 0x16, 0x20, 0x0B, 0x1C, 0xFF, 0xF7, 0xAD, 0xFA, 0x05, 0xB0, +0xF0, 0xBD, 0xC0, 0x46, 0xAC, 0x09, 0x00, 0x20, 0x14, 0x09, 0x00, 0x20, +0x30, 0x11, 0x00, 0x20, 0x48, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0xA7, 0x59, 0x00, 0x00, 0xAE, 0x09, 0x00, 0x20, 0x84, 0x40, 0x00, 0x40, +0x1C, 0x03, 0x00, 0x20, 0xE1, 0x01, 0x00, 0x20, 0xE3, 0x01, 0x00, 0x20, +0x64, 0x0E, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, +0xF8, 0x03, 0x00, 0x20, 0x3C, 0x0D, 0x00, 0x20, 0xAB, 0x59, 0x00, 0x00, +0x58, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x7F, 0x94, 0x11, 0x00, 0x20, +0xB1, 0x59, 0x00, 0x00, 0x54, 0x11, 0x00, 0x20, 0x30, 0x75, 0x00, 0x00, +0x2A, 0x75, 0x00, 0x00, 0xF0, 0xB5, 0xB3, 0x4B, 0xA5, 0xB0, 0x1B, 0x78, +0x00, 0x2B, 0x00, 0xD0, 0xFC, 0xE1, 0xB1, 0x4A, 0xB1, 0x4C, 0x12, 0x78, +0xB1, 0x4D, 0xB2, 0x4E, 0x64, 0x7C, 0x52, 0xB2, 0x6B, 0x60, 0x2B, 0x60, +0x6B, 0x82, 0x6B, 0x81, 0x2B, 0x82, 0x2B, 0x81, 0x33, 0x60, 0xB3, 0x60, +0x1B, 0x92, 0xAD, 0x4F, 0xFF, 0x22, 0xAD, 0x4B, 0x72, 0x60, 0xF2, 0x60, +0x11, 0x94, 0x3F, 0x7E, 0x1B, 0x78, 0xA9, 0x4C, 0x09, 0x97, 0x0B, 0x93, +0xE4, 0x7D, 0xA4, 0x4D, 0x08, 0x94, 0x46, 0x23, 0xED, 0x5E, 0xA2, 0x4F, +0x0E, 0x95, 0x48, 0x23, 0xFF, 0x5E, 0xA3, 0x4C, 0x0F, 0x97, 0x24, 0x7D, +0x19, 0x21, 0x0C, 0x94, 0x9D, 0x4D, 0xA2, 0x4B, 0x11, 0x9E, 0x6D, 0x78, +0x1B, 0x68, 0x76, 0x42, 0x9A, 0x4F, 0x0D, 0x95, 0x12, 0x93, 0x1D, 0x96, +0xBF, 0x7C, 0x98, 0x4C, 0x22, 0x97, 0x2D, 0x23, 0xE3, 0x5C, 0x1B, 0x9D, +0x13, 0x93, 0x10, 0x23, 0x5B, 0x1B, 0x1E, 0x93, 0x18, 0x26, 0xA6, 0x57, +0x1C, 0x27, 0x14, 0x96, 0xE7, 0x57, 0x00, 0x22, 0x18, 0x97, 0x61, 0x56, +0x00, 0x24, 0x00, 0x23, 0x00, 0x25, 0x23, 0x91, 0x17, 0x94, 0x00, 0x26, +0x00, 0x27, 0xFF, 0x21, 0xFF, 0x24, 0x06, 0x92, 0x05, 0x93, 0x10, 0x95, +0x1A, 0x96, 0x15, 0x97, 0x19, 0x91, 0x21, 0x92, 0x1F, 0x93, 0x16, 0x94, +0x1C, 0x95, 0x09, 0x9C, 0x00, 0x2C, 0x00, 0xD1, 0x28, 0xE1, 0x09, 0x9B, +0x89, 0x4E, 0x01, 0x3B, 0xDB, 0xB2, 0x09, 0x93, 0x5B, 0x00, 0x9B, 0x5B, +0x08, 0x9F, 0x0A, 0x93, 0x00, 0x2F, 0xF0, 0xD0, 0x09, 0x9F, 0x85, 0x49, +0x01, 0x37, 0xFB, 0x01, 0x5B, 0x18, 0x1B, 0x88, 0x0A, 0x9C, 0x0E, 0x9D, +0x1A, 0x1B, 0x95, 0x42, 0x00, 0xDA, 0x8E, 0xE1, 0x0F, 0x9E, 0x96, 0x42, +0x00, 0xDD, 0x87, 0xE1, 0x09, 0x9C, 0xBF, 0x01, 0x01, 0x21, 0x02, 0x25, +0x00, 0x22, 0x60, 0x01, 0x03, 0x97, 0x2C, 0xE0, 0x7A, 0x4D, 0x84, 0x18, +0x64, 0x00, 0x6E, 0x46, 0x18, 0x27, 0x2C, 0x5B, 0xBD, 0x5F, 0xE4, 0x1A, +0xAC, 0x42, 0x01, 0xDD, 0xA7, 0xB2, 0x06, 0x97, 0x6E, 0x46, 0x14, 0x27, +0xBD, 0x5F, 0xAC, 0x42, 0x01, 0xDA, 0xA4, 0xB2, 0x05, 0x94, 0x82, 0x18, +0x70, 0x4F, 0x52, 0x00, 0xBB, 0x52, 0x08, 0x9A, 0xCB, 0xB2, 0x9A, 0x42, +0xBD, 0xD9, 0x03, 0x9E, 0x8D, 0x1C, 0x73, 0x19, 0x6C, 0x4F, 0x5B, 0x00, +0xDB, 0x5B, 0x0A, 0x9E, 0x0E, 0x9F, 0x0A, 0x1C, 0x9C, 0x1B, 0xBC, 0x42, +0x00, 0xDD, 0x38, 0xE1, 0x0F, 0x9E, 0x01, 0x31, 0xB4, 0x42, 0x00, 0xDA, +0xD2, 0xE0, 0x0C, 0x9F, 0x00, 0x2F, 0x07, 0xD0, 0x03, 0x9E, 0xD4, 0x1C, +0x34, 0x19, 0x62, 0x4F, 0x64, 0x00, 0xE4, 0x5B, 0xE3, 0x18, 0x5B, 0x10, +0x0D, 0x9C, 0x00, 0x2C, 0x06, 0xD0, 0x5F, 0x4E, 0x84, 0x18, 0xA4, 0x5D, +0x12, 0x9F, 0x63, 0x43, 0x7B, 0x43, 0x1B, 0x13, 0x0B, 0x9C, 0x00, 0x2C, +0xBA, 0xD0, 0x86, 0x18, 0x57, 0x4F, 0x74, 0x00, 0x3F, 0x5B, 0xBC, 0x46, +0x58, 0x4F, 0xBC, 0x57, 0x66, 0x46, 0xF6, 0x08, 0x34, 0x1B, 0x07, 0x94, +0x6F, 0x46, 0x18, 0x24, 0x04, 0x96, 0xE7, 0x5F, 0x07, 0x9E, 0xF4, 0x1A, +0xBC, 0x42, 0x01, 0xDD, 0xA7, 0xB2, 0x06, 0x97, 0x6E, 0x46, 0x14, 0x27, +0xBE, 0x5F, 0xB4, 0x42, 0x01, 0xDA, 0xA6, 0xB2, 0x05, 0x96, 0x11, 0x9F, +0xBC, 0x42, 0x5D, 0xDD, 0x84, 0x18, 0xA4, 0x46, 0x4B, 0x4C, 0x00, 0x27, +0x66, 0x46, 0x37, 0x55, 0x04, 0x9F, 0x13, 0x9E, 0xFC, 0x1A, 0x00, 0x2E, +0x08, 0xD0, 0x1B, 0x9F, 0x07, 0x9C, 0x1E, 0x9E, 0x7B, 0x43, 0x74, 0x43, +0x04, 0x9F, 0x1C, 0x19, 0x24, 0x11, 0x3C, 0x1B, 0x23, 0x1C, 0x7F, 0x33, +0x17, 0xDA, 0x40, 0x4E, 0x82, 0x18, 0x80, 0x23, 0xB3, 0x54, 0x23, 0x9A, +0x21, 0x9E, 0xA3, 0x1A, 0xF6, 0x18, 0x21, 0x96, 0x1F, 0xAF, 0x00, 0x23, +0xFB, 0x5E, 0x9C, 0x42, 0x01, 0xDC, 0xA4, 0xB2, 0x1F, 0x94, 0x03, 0x9A, +0x35, 0x4C, 0x55, 0x19, 0x6D, 0x00, 0x00, 0x27, 0x2B, 0x5B, 0x2F, 0x53, +0x83, 0xE7, 0x83, 0x18, 0x7E, 0x2C, 0x36, 0xDD, 0x32, 0x4E, 0x7F, 0x27, +0xF7, 0x54, 0x14, 0x9F, 0xBC, 0x42, 0x03, 0xDB, 0x17, 0x9E, 0xE3, 0x1B, +0xF6, 0x18, 0x17, 0x96, 0x10, 0xAF, 0x00, 0x23, 0xFB, 0x5E, 0x9C, 0x42, +0x24, 0xDC, 0xA3, 0xB2, 0x18, 0x9E, 0xB4, 0x42, 0x11, 0xDB, 0x1A, 0x9F, +0x09, 0x9C, 0xA7, 0x42, 0x00, 0xDA, 0x1A, 0x94, 0x16, 0x9E, 0x09, 0x9C, +0xA6, 0x42, 0x00, 0xDD, 0x16, 0x94, 0x15, 0x9E, 0x96, 0x42, 0x00, 0xDA, +0x15, 0x92, 0x19, 0x9F, 0xBA, 0x42, 0x00, 0xDA, 0x19, 0x92, 0x03, 0x9A, +0x1D, 0x4C, 0x55, 0x19, 0x6D, 0x00, 0x2A, 0x5B, 0x2B, 0x53, 0x54, 0xE7, +0x1D, 0x9E, 0x87, 0x18, 0xB4, 0x42, 0x0E, 0xDA, 0x1B, 0x4C, 0x00, 0x26, +0x3E, 0x55, 0x9F, 0xE7, 0xA3, 0xB2, 0x10, 0x93, 0xD8, 0xE7, 0x17, 0x4E, +0xF4, 0x54, 0x00, 0x2C, 0xC7, 0xDA, 0x23, 0x9F, 0xBC, 0x42, 0xAF, 0xDC, +0xA9, 0xE7, 0x14, 0x4E, 0x20, 0x97, 0xBC, 0x5D, 0x22, 0x9E, 0x67, 0xB2, +0xB7, 0x42, 0x8D, 0xD0, 0x20, 0x9F, 0x10, 0x4E, 0x01, 0x34, 0xBC, 0x55, +0x88, 0xE7, 0xC0, 0x46, 0xAC, 0x09, 0x00, 0x20, 0x4C, 0x00, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, 0xE4, 0x10, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x1C, 0x03, 0x00, 0x20, 0x78, 0x09, 0x00, 0x20, +0x94, 0x11, 0x00, 0x20, 0x04, 0x40, 0x00, 0x40, 0xF8, 0x03, 0x00, 0x20, +0x00, 0x40, 0x00, 0x40, 0x12, 0x79, 0x00, 0x00, 0x64, 0x0E, 0x00, 0x20, +0xB3, 0x0A, 0x00, 0x20, 0x09, 0x9C, 0x01, 0x27, 0x1C, 0x97, 0x00, 0x2C, +0x00, 0xD0, 0xD6, 0xE6, 0x6D, 0x46, 0x6F, 0x46, 0x18, 0x26, 0x14, 0x21, +0x76, 0x5B, 0xC9, 0x5B, 0x3F, 0x4D, 0x17, 0x9A, 0x10, 0xAC, 0x2F, 0x1C, +0x2E, 0x82, 0x69, 0x82, 0x2A, 0x60, 0x25, 0x88, 0x1A, 0x9E, 0x3C, 0x1C, +0x3D, 0x81, 0x3B, 0x4F, 0x16, 0x99, 0x15, 0x9A, 0x19, 0x9B, 0xBE, 0x60, +0x1F, 0xAE, 0xF9, 0x60, 0x3A, 0x60, 0x7B, 0x60, 0x21, 0x9D, 0x37, 0x88, +0x0B, 0x99, 0x65, 0x60, 0x67, 0x81, 0x00, 0x29, 0x24, 0xD0, 0x34, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x33, 0x4B, 0x1B, 0x68, 0x00, 0x2B, +0x1C, 0xDD, 0x32, 0x4C, 0x23, 0x78, 0x00, 0x2B, 0x52, 0xD1, 0x31, 0x4D, +0x2B, 0x7E, 0x00, 0x2B, 0x14, 0xD0, 0x30, 0x4D, 0x09, 0x9F, 0x01, 0x26, +0x23, 0x78, 0x00, 0x2B, 0x08, 0xD0, 0x2C, 0x4A, 0x03, 0x20, 0xD1, 0x7D, +0x7A, 0x01, 0x52, 0x19, 0x01, 0x23, 0x00, 0x96, 0xFF, 0xF7, 0xAE, 0xF8, +0x27, 0x49, 0x01, 0x37, 0x0B, 0x7E, 0xFF, 0xB2, 0xBB, 0x42, 0xED, 0xD8, +0x24, 0x4C, 0x23, 0x7D, 0x00, 0x2B, 0x13, 0xD0, 0x22, 0x7E, 0xE4, 0x7D, +0x01, 0x3A, 0x23, 0x49, 0xD2, 0xB2, 0x02, 0x34, 0x00, 0x20, 0x53, 0x1C, +0x9B, 0x01, 0x1B, 0x19, 0x5B, 0x00, 0x01, 0x3A, 0x5D, 0x5A, 0xD2, 0xB2, +0x5D, 0x5A, 0x58, 0x52, 0xF5, 0xE7, 0x01, 0x26, 0x1C, 0x96, 0x74, 0xE6, +0x13, 0x4D, 0x1B, 0x4E, 0x08, 0x21, 0x69, 0x5E, 0xB3, 0x7E, 0x1A, 0x48, +0x1A, 0x4A, 0xCD, 0x17, 0xDC, 0x0F, 0x00, 0x78, 0x99, 0x42, 0x65, 0x41, +0x15, 0x70, 0x00, 0x28, 0x0A, 0xD1, 0x1C, 0x9F, 0x00, 0x2F, 0x07, 0xD0, +0x01, 0x23, 0x13, 0x70, 0x14, 0x4A, 0x15, 0x49, 0x13, 0x70, 0x15, 0x4A, +0x0B, 0x70, 0x13, 0x70, 0x25, 0xB0, 0xF0, 0xBD, 0x01, 0x25, 0x1C, 0x95, +0x55, 0xE6, 0x01, 0x24, 0x1C, 0x94, 0x52, 0xE6, 0x03, 0x20, 0x10, 0x49, +0xFF, 0xF7, 0xC2, 0xF8, 0xA7, 0xE7, 0xC0, 0x46, 0x70, 0x01, 0x00, 0x20, +0xE4, 0x10, 0x00, 0x20, 0xDE, 0x01, 0x00, 0x20, 0x20, 0x01, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x64, 0x0E, 0x00, 0x20, +0x00, 0x40, 0x00, 0x40, 0x48, 0x0D, 0x00, 0x20, 0xE4, 0x01, 0x00, 0x20, +0x14, 0x09, 0x00, 0x20, 0x30, 0x11, 0x00, 0x20, 0x48, 0x11, 0x00, 0x20, +0xC4, 0x01, 0x00, 0x20, 0xEC, 0x59, 0x00, 0x00, 0xF0, 0xB5, 0x2F, 0x4B, +0x85, 0xB0, 0x1C, 0x78, 0x2E, 0x4D, 0x2F, 0x4E, 0x10, 0xE0, 0x01, 0x3C, +0xE4, 0xB2, 0x2B, 0x57, 0x32, 0x57, 0x59, 0x1C, 0x02, 0x32, 0x89, 0x01, +0x89, 0x18, 0x2B, 0x4A, 0x49, 0x00, 0x88, 0x5A, 0x2A, 0x4A, 0x5B, 0x00, +0x9A, 0x5A, 0x21, 0x1C, 0xFF, 0xF7, 0x10, 0xFB, 0x00, 0x2C, 0xEC, 0xD1, +0x27, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x08, 0xD0, 0x20, 0x4B, 0x03, 0x20, +0x19, 0x78, 0x01, 0x23, 0x00, 0x93, 0x24, 0x4A, 0x02, 0x23, 0xFF, 0xF7, +0x23, 0xF8, 0x23, 0x4B, 0x1E, 0x49, 0x18, 0x78, 0x9A, 0x78, 0x84, 0x1C, +0x03, 0x92, 0xDE, 0x78, 0x00, 0x23, 0x02, 0x94, 0x0D, 0xE0, 0xA4, 0x01, +0xE4, 0x19, 0x64, 0x00, 0x65, 0x5A, 0x00, 0x25, 0x65, 0x52, 0x01, 0x32, +0x02, 0xE0, 0x02, 0x9C, 0x00, 0x22, 0xE7, 0x18, 0xB4, 0x1A, 0xF2, 0xD1, +0x01, 0x33, 0x03, 0x9D, 0x1A, 0x18, 0xAA, 0x42, 0xF5, 0xDB, 0x15, 0x4B, +0x10, 0x49, 0x58, 0x78, 0xDE, 0x78, 0x42, 0x1C, 0x01, 0x23, 0x5B, 0x42, +0x02, 0x92, 0x00, 0x22, 0x9F, 0x1C, 0x08, 0xE0, 0x02, 0x9D, 0xAC, 0x18, +0xA4, 0x01, 0xE4, 0x19, 0x64, 0x00, 0x65, 0x5A, 0x00, 0x25, 0x65, 0x52, +0x01, 0x32, 0x14, 0x18, 0xB4, 0x42, 0xF3, 0xDB, 0x03, 0x9A, 0x01, 0x33, +0x93, 0x42, 0xEC, 0xDB, 0x05, 0xB0, 0xF0, 0xBD, 0x7C, 0x09, 0x00, 0x20, +0x30, 0x75, 0x00, 0x00, 0x2A, 0x75, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, +0x94, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0x3C, 0x0D, 0x00, 0x20, +0x0A, 0x03, 0x00, 0x20, 0x30, 0xB5, 0x0C, 0x4B, 0x0C, 0x4C, 0xDB, 0x78, +0x0C, 0x49, 0x10, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x5A, 0x1C, 0x0B, 0x4D, +0xD2, 0x01, 0x52, 0x19, 0x45, 0x1C, 0x03, 0xD1, 0x15, 0x88, 0x5A, 0x00, +0x55, 0x52, 0x04, 0xE0, 0x15, 0x88, 0x5A, 0x01, 0x12, 0x18, 0x52, 0x00, +0x15, 0x53, 0x00, 0x2B, 0xEC, 0xD1, 0x30, 0xBD, 0x0A, 0x03, 0x00, 0x20, +0xF8, 0x03, 0x00, 0x20, 0x94, 0x11, 0x00, 0x20, 0x02, 0x40, 0x00, 0x40, +0xF0, 0xB5, 0x8D, 0xB0, 0x0A, 0x91, 0x0B, 0x92, 0x63, 0x4B, 0x41, 0x1C, +0x0C, 0xD1, 0x63, 0x4A, 0x63, 0x49, 0x12, 0x7E, 0x01, 0x3A, 0x03, 0x92, +0xDA, 0x78, 0x5E, 0x78, 0x54, 0x00, 0x00, 0x23, 0x55, 0x1C, 0x64, 0x18, +0x94, 0x46, 0x0E, 0xE0, 0xDC, 0x7B, 0x5A, 0x79, 0xA2, 0x18, 0x01, 0x3A, +0x10, 0xE0, 0x5C, 0x4A, 0xE9, 0x18, 0xC9, 0x01, 0x89, 0x18, 0x0A, 0x88, +0x5F, 0x00, 0xE2, 0x53, 0x0A, 0x88, 0x00, 0x22, 0x0A, 0x80, 0x01, 0x3B, +0x67, 0x46, 0xDA, 0x19, 0xB2, 0x42, 0xF0, 0xDA, 0x03, 0x9A, 0x00, 0x24, +0x56, 0x01, 0x54, 0x4D, 0x36, 0x18, 0x00, 0x23, 0x76, 0x00, 0x11, 0x1C, +0x08, 0x93, 0x07, 0x93, 0x06, 0x93, 0x05, 0x93, 0x03, 0x95, 0x09, 0x96, +0xA4, 0x46, 0x55, 0xE0, 0x44, 0x1C, 0x04, 0xD1, 0x4A, 0x4C, 0x56, 0x00, +0x34, 0x19, 0xE4, 0x5A, 0x04, 0xE0, 0x4B, 0x4C, 0x09, 0x9F, 0x3E, 0x19, +0x5C, 0x01, 0x34, 0x5B, 0x4E, 0x1C, 0x46, 0x4F, 0x04, 0x96, 0xF6, 0x01, +0xF6, 0x19, 0x37, 0x88, 0x24, 0xB2, 0x3E, 0xB2, 0x45, 0x4F, 0xA6, 0x1B, +0x54, 0x00, 0xE7, 0x19, 0xF4, 0x17, 0xFE, 0x52, 0x36, 0x19, 0x66, 0x40, +0x0F, 0x1C, 0x01, 0x24, 0xA7, 0x43, 0xB9, 0x42, 0x09, 0xD1, 0x07, 0x9C, +0xA4, 0x19, 0x07, 0x94, 0xB5, 0x42, 0x00, 0xDD, 0x35, 0x1C, 0x06, 0x9F, +0xB7, 0x42, 0x0B, 0xDB, 0x0D, 0xE0, 0x08, 0x9C, 0x03, 0x9F, 0xA4, 0x19, +0x08, 0x94, 0xB7, 0x42, 0x00, 0xDD, 0x03, 0x96, 0x05, 0x9C, 0xB4, 0x42, +0x02, 0xDB, 0x02, 0xE0, 0x06, 0x96, 0x00, 0xE0, 0x05, 0x96, 0x04, 0x9E, +0xF4, 0x01, 0x2F, 0x4E, 0xA4, 0x19, 0x47, 0x1C, 0x0E, 0xD1, 0x27, 0x88, +0x2B, 0x4E, 0x04, 0x97, 0x57, 0x00, 0xBE, 0x19, 0x02, 0x96, 0x10, 0x27, +0x6E, 0x46, 0xBF, 0x5B, 0x02, 0x9E, 0xF7, 0x52, 0x26, 0x88, 0x00, 0x26, +0x26, 0x80, 0x05, 0xE0, 0x27, 0x88, 0x27, 0x4E, 0x09, 0x9C, 0xA6, 0x19, +0x5C, 0x01, 0x37, 0x53, 0x01, 0x39, 0x02, 0x3B, 0x61, 0x45, 0xA7, 0xDA, +0x01, 0x30, 0x13, 0xD1, 0x23, 0x4C, 0x23, 0x78, 0x00, 0x2B, 0x03, 0xD0, +0x01, 0x20, 0x22, 0x49, 0xFE, 0xF7, 0x76, 0xFF, 0x23, 0x78, 0x00, 0x2B, +0x08, 0xD0, 0x17, 0x4B, 0x01, 0x20, 0xD9, 0x78, 0x00, 0x23, 0x00, 0x93, +0x16, 0x4A, 0x02, 0x23, 0xFE, 0xF7, 0x12, 0xFF, 0x07, 0x9E, 0x08, 0x9F, +0x0A, 0x9C, 0xF3, 0x19, 0x23, 0x60, 0x05, 0x9E, 0x03, 0x9F, 0x06, 0x9C, +0xF3, 0x1B, 0x65, 0x1B, 0x9D, 0x42, 0x00, 0xDA, 0x1D, 0x1C, 0x0B, 0x9E, +0x12, 0x4C, 0x35, 0x60, 0x23, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x0B, 0x20, +0x11, 0x49, 0xFE, 0xF7, 0x53, 0xFF, 0x23, 0x78, 0x00, 0x2B, 0x08, 0xD0, +0x06, 0x4B, 0x0B, 0x20, 0x19, 0x7E, 0x01, 0x23, 0x00, 0x93, 0x09, 0x4A, +0x02, 0x23, 0xFE, 0xF7, 0xEF, 0xFE, 0x0D, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, +0x0A, 0x03, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x94, 0x11, 0x00, 0x20, +0x02, 0x40, 0x00, 0x40, 0xFF, 0xFF, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x20, +0x54, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0xC2, 0x59, 0x00, 0x00, +0xC9, 0x59, 0x00, 0x00, 0xF0, 0xB5, 0xA6, 0x4B, 0x85, 0xB0, 0x1D, 0x78, +0x00, 0x2D, 0x29, 0xD0, 0xA4, 0x4B, 0xA5, 0x4C, 0x18, 0x78, 0xA5, 0x4B, +0x46, 0xB2, 0x19, 0x68, 0x5B, 0x68, 0xB2, 0x00, 0xCB, 0x18, 0x13, 0x51, +0x82, 0x1D, 0xD2, 0xB2, 0x00, 0x25, 0x06, 0x23, 0x01, 0x3B, 0xDB, 0xB2, +0xF1, 0x1A, 0x00, 0xD5, 0x0C, 0x31, 0x89, 0x00, 0x09, 0x59, 0x6D, 0x18, +0x11, 0x1C, 0x0B, 0x2A, 0x01, 0xD9, 0x0C, 0x39, 0xC9, 0xB2, 0x89, 0x00, +0x61, 0x58, 0x01, 0x3A, 0x6D, 0x1A, 0xD2, 0xB2, 0x00, 0x2B, 0xEB, 0xD1, +0x01, 0x30, 0x93, 0x4A, 0xC0, 0xB2, 0x10, 0x70, 0x40, 0xB2, 0x0B, 0x28, +0x00, 0xDD, 0x13, 0x70, 0x92, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD0, +0x15, 0xE1, 0x91, 0x4B, 0x14, 0x21, 0x5B, 0x5E, 0x9D, 0x42, 0x02, 0xDA, +0x8F, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x8B, 0x4B, 0x10, 0x22, 0x9E, 0x5E, +0x12, 0x24, 0x1B, 0x5F, 0xF6, 0x1A, 0x85, 0x4B, 0x18, 0x78, 0x00, 0x28, +0x16, 0xD1, 0x8A, 0x4B, 0x8A, 0x4F, 0x1B, 0x68, 0x8A, 0x4C, 0xBB, 0x80, +0x23, 0x78, 0x3E, 0x80, 0x00, 0x2B, 0x02, 0xD0, 0x88, 0x49, 0xFE, 0xF7, +0xDD, 0xFE, 0x23, 0x78, 0x00, 0x2B, 0x07, 0xD0, 0x01, 0x23, 0x02, 0x21, +0x00, 0x93, 0x00, 0x20, 0x3A, 0x1C, 0x0B, 0x1C, 0xFE, 0xF7, 0x7A, 0xFE, +0x7C, 0x4B, 0x9A, 0x7D, 0x96, 0x42, 0x07, 0xDC, 0x80, 0x4B, 0x1A, 0x78, +0x51, 0xB2, 0x02, 0x29, 0x08, 0xDC, 0x01, 0x32, 0x1A, 0x70, 0x05, 0xE0, +0xDB, 0x7D, 0x9E, 0x42, 0x02, 0xDB, 0x7B, 0x4B, 0x00, 0x22, 0x1A, 0x70, +0x71, 0x4B, 0x76, 0x4A, 0x59, 0x68, 0x1B, 0x68, 0x15, 0x80, 0xCB, 0x18, +0x53, 0x80, 0x74, 0x4B, 0x96, 0x80, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, +0x01, 0x23, 0x00, 0x93, 0x19, 0x20, 0x03, 0x21, 0x02, 0x23, 0xFE, 0xF7, +0x55, 0xFE, 0x6B, 0x4B, 0x64, 0x4C, 0x1B, 0x78, 0x00, 0x2B, 0x61, 0xD0, +0x6B, 0x4D, 0x2B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x19, 0x20, 0x6C, 0x49, +0xFE, 0xF7, 0xA0, 0xFE, 0x69, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x05, 0xD1, +0x22, 0x78, 0x00, 0x2A, 0x52, 0xD0, 0x61, 0x4A, 0x13, 0x70, 0x4F, 0xE0, +0x03, 0x2B, 0x4D, 0xD1, 0x2B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, +0x63, 0x49, 0xFE, 0xF7, 0x8D, 0xFE, 0x55, 0x4B, 0x62, 0x4A, 0x19, 0x78, +0x00, 0x29, 0x1A, 0xD1, 0x01, 0x20, 0x18, 0x70, 0x13, 0x7E, 0xD6, 0x7D, +0x5F, 0x4D, 0x60, 0x4A, 0x0B, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0xF8, 0x18, +0x44, 0x00, 0xA1, 0x5A, 0xC9, 0x00, 0xA1, 0x52, 0x00, 0x21, 0x41, 0x55, +0x00, 0x2B, 0xF4, 0xD1, 0x63, 0x46, 0x59, 0x1E, 0xC9, 0xB2, 0x00, 0x2B, +0x23, 0xD0, 0x33, 0x1C, 0x4F, 0x01, 0x8C, 0x46, 0xF4, 0xE7, 0x13, 0x7E, +0xD6, 0x7D, 0x54, 0x4A, 0x0E, 0xE0, 0x01, 0x3B, 0x51, 0x4D, 0xDB, 0xB2, +0xFC, 0x18, 0x60, 0x00, 0x64, 0x57, 0xE4, 0x00, 0x02, 0x94, 0x84, 0x5A, +0x02, 0x9D, 0x64, 0x1B, 0x84, 0x52, 0x00, 0x2B, 0xF1, 0xD1, 0x0B, 0x1C, +0x59, 0x1E, 0xC9, 0xB2, 0x00, 0x2B, 0x02, 0xD0, 0x33, 0x1C, 0x4F, 0x01, +0xF5, 0xE7, 0x3A, 0x4A, 0x11, 0x1C, 0x30, 0x31, 0x08, 0xC2, 0x8A, 0x42, +0xFC, 0xD1, 0x3B, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x44, 0x4B, 0x01, 0x22, +0x1A, 0x70, 0x60, 0xE0, 0x22, 0x78, 0x43, 0x4B, 0x00, 0x2A, 0x06, 0xD1, +0x40, 0x4A, 0x01, 0x21, 0x11, 0x70, 0x1A, 0x68, 0x52, 0x18, 0x1A, 0x60, +0x55, 0xE0, 0x00, 0x22, 0x1A, 0x60, 0x39, 0x4B, 0x3D, 0x48, 0x1C, 0x7E, +0xDB, 0x7D, 0x39, 0x49, 0x02, 0x93, 0x2D, 0x4B, 0x9B, 0x7C, 0x03, 0x93, +0x11, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0xF2, 0x18, 0x14, 0x56, 0x03, 0x9D, +0xAC, 0x42, 0x07, 0xD1, 0x31, 0x4D, 0x54, 0x00, 0x57, 0x57, 0x65, 0x5A, +0xEF, 0x1B, 0x67, 0x52, 0x00, 0x24, 0x14, 0x54, 0x00, 0x2B, 0xEE, 0xD1, +0x64, 0x46, 0x65, 0x1E, 0xED, 0xB2, 0x00, 0x2C, 0x03, 0xD0, 0x02, 0x9B, +0x6E, 0x01, 0xAC, 0x46, 0xF4, 0xE7, 0x2D, 0x4B, 0x1B, 0x68, 0x5D, 0x07, +0x2B, 0xD5, 0x20, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x22, 0xD0, 0x02, 0x20, +0x29, 0x49, 0xFE, 0xF7, 0x09, 0xFE, 0x1D, 0xE0, 0xE9, 0x7D, 0x62, 0x01, +0x0B, 0x1C, 0x21, 0x48, 0x02, 0x92, 0x08, 0xE0, 0x01, 0x3B, 0x02, 0x9A, +0xDB, 0xB2, 0xD2, 0x18, 0x52, 0x00, 0x12, 0x5A, 0x5F, 0x00, 0xD2, 0x08, +0xBA, 0x53, 0x00, 0x2B, 0xF4, 0xD1, 0x13, 0x4A, 0x12, 0x78, 0x00, 0x2A, +0x05, 0xD0, 0x02, 0x20, 0x00, 0x93, 0x0F, 0x4A, 0x03, 0x1C, 0xFE, 0xF7, +0x95, 0xFD, 0x01, 0x34, 0xE4, 0xB2, 0x01, 0xE0, 0x11, 0x4D, 0x0B, 0x4E, +0x2B, 0x7E, 0xA3, 0x42, 0xDC, 0xD8, 0x05, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, +0x1C, 0x03, 0x00, 0x20, 0xF4, 0x10, 0x00, 0x20, 0xBC, 0x11, 0x00, 0x20, +0x70, 0x01, 0x00, 0x20, 0x14, 0x09, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x3C, 0x11, 0x00, 0x20, 0x34, 0x11, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0xCE, 0x59, 0x00, 0x00, 0x20, 0x09, 0x00, 0x20, +0xD5, 0x59, 0x00, 0x00, 0xDE, 0x59, 0x00, 0x00, 0xAE, 0x09, 0x00, 0x20, +0x64, 0x0E, 0x00, 0x20, 0xF8, 0x03, 0x00, 0x20, 0x48, 0x11, 0x00, 0x20, +0xBC, 0x01, 0x00, 0x20, 0xB3, 0x0A, 0x00, 0x20, 0x58, 0x00, 0x00, 0x20, +0xE7, 0x59, 0x00, 0x00, 0xF0, 0xB5, 0x25, 0x4B, 0x87, 0xB0, 0x1B, 0x78, +0x00, 0x2B, 0x2B, 0xD1, 0x23, 0x4A, 0x24, 0x4B, 0x90, 0x7C, 0x1B, 0x78, +0x04, 0x90, 0xD2, 0x7E, 0x22, 0x4D, 0x52, 0xB2, 0x92, 0xB2, 0x05, 0x92, +0x21, 0x4A, 0x1D, 0xE0, 0x01, 0x3B, 0x21, 0x4C, 0xDB, 0xB2, 0xE1, 0x5C, +0x04, 0x9F, 0xB9, 0x42, 0x16, 0xD1, 0x59, 0x00, 0x88, 0x5A, 0x00, 0x28, +0x07, 0xD0, 0x6E, 0x5A, 0x6F, 0x46, 0x34, 0xB2, 0xA4, 0x46, 0x14, 0x24, +0xE7, 0x5F, 0xBC, 0x45, 0x05, 0xDA, 0x59, 0x00, 0x6E, 0x5A, 0xF6, 0x00, +0x80, 0x1B, 0x50, 0x52, 0x01, 0xE0, 0x80, 0x1B, 0x88, 0x52, 0x14, 0x4F, +0x00, 0x21, 0xF9, 0x54, 0x00, 0x2B, 0xDF, 0xD1, 0x0E, 0x4B, 0x12, 0x4C, +0x19, 0x78, 0x0F, 0x48, 0x0B, 0x1C, 0x05, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, +0x5A, 0x00, 0x15, 0x5A, 0xED, 0x08, 0x15, 0x53, 0x00, 0x2B, 0xF7, 0xD1, +0x0C, 0x4A, 0x12, 0x78, 0x00, 0x2A, 0x05, 0xD0, 0x02, 0x20, 0x00, 0x93, +0x08, 0x4A, 0x03, 0x1C, 0xFE, 0xF7, 0x14, 0xFD, 0x07, 0xB0, 0xF0, 0xBD, +0x30, 0x11, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, +0x3C, 0x0D, 0x00, 0x20, 0x14, 0x02, 0x00, 0x20, 0xA4, 0x0A, 0x00, 0x20, +0x54, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0x10, 0xB5, 0x09, 0x49, +0x50, 0x22, 0x09, 0x48, 0x00, 0xF0, 0xE2, 0xF9, 0x08, 0x4C, 0x09, 0x49, +0x20, 0x1C, 0x42, 0x22, 0x00, 0xF0, 0xDC, 0xF9, 0x07, 0x4B, 0xA2, 0x7B, +0x1A, 0x60, 0xE3, 0x7D, 0xE3, 0x76, 0x23, 0x7E, 0x23, 0x77, 0x10, 0xBD, +0x4A, 0x74, 0x00, 0x00, 0x48, 0x0D, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0x08, 0x74, 0x00, 0x00, 0x50, 0x11, 0x00, 0x20, 0x08, 0xB5, 0x04, 0x49, +0x04, 0x4B, 0x41, 0x43, 0x04, 0x48, 0xC9, 0x18, 0x00, 0xF0, 0x60, 0xF9, +0xC0, 0xB2, 0x08, 0xBD, 0x44, 0xFE, 0xFF, 0xFF, 0xFE, 0x24, 0x02, 0x00, +0x40, 0x42, 0x0F, 0x00, 0x10, 0xB5, 0x15, 0x4C, 0x00, 0x23, 0x23, 0x71, +0x03, 0x23, 0x63, 0x71, 0x02, 0x23, 0x23, 0x72, 0x12, 0x4B, 0x98, 0x78, +0x02, 0x38, 0x03, 0x28, 0x1D, 0xD8, 0x00, 0xF0, 0xE7, 0xF8, 0x0B, 0x04, +0x02, 0x14, 0xC7, 0x20, 0x00, 0xE0, 0xD7, 0x20, 0xE0, 0x70, 0xFF, 0xF7, +0xD9, 0xFF, 0x02, 0x23, 0x20, 0x70, 0x0E, 0xE0, 0xF4, 0x20, 0xE0, 0x70, +0xFF, 0xF7, 0xD2, 0xFF, 0x02, 0x23, 0x20, 0x70, 0xA3, 0x71, 0x01, 0x23, +0x06, 0xE0, 0xF4, 0x20, 0xE0, 0x70, 0xFF, 0xF7, 0xC9, 0xFF, 0x01, 0x23, +0x20, 0x70, 0xA3, 0x71, 0xE3, 0x71, 0x10, 0xBD, 0xAA, 0x0A, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0xF0, 0xB5, 0x59, 0x4B, 0x87, 0xB0, 0x1A, 0x68, +0x58, 0x4B, 0x08, 0x2A, 0x01, 0xD1, 0x01, 0x22, 0x00, 0xE0, 0x00, 0x22, +0x1A, 0x70, 0x56, 0x4B, 0x56, 0x4C, 0x01, 0x33, 0xDB, 0x7F, 0x00, 0x2B, +0x00, 0xD1, 0xE3, 0x71, 0x23, 0x78, 0x01, 0x25, 0xA2, 0x79, 0x28, 0x1C, +0xD9, 0x00, 0x90, 0x40, 0x82, 0xB2, 0xCB, 0x1A, 0x53, 0x43, 0x50, 0x4E, +0xDB, 0x10, 0xDB, 0xB2, 0x33, 0x80, 0x22, 0x78, 0xFA, 0x23, 0xA0, 0x79, +0x9B, 0x00, 0x53, 0x43, 0x4C, 0x4F, 0x29, 0x1C, 0x81, 0x40, 0x88, 0xB2, +0xB9, 0x88, 0x58, 0x43, 0x09, 0x01, 0x00, 0xF0, 0xFB, 0xF8, 0xC1, 0xB2, +0x71, 0x80, 0x23, 0x78, 0x2D, 0x22, 0xA0, 0x79, 0x53, 0x43, 0x2A, 0x1C, +0x82, 0x40, 0x90, 0xB2, 0x58, 0x43, 0x6B, 0x46, 0x19, 0x81, 0x09, 0x01, +0x00, 0xF0, 0xEC, 0xF8, 0xC0, 0xB2, 0xB0, 0x80, 0x23, 0x7A, 0xB9, 0x79, +0xD8, 0x00, 0x18, 0x1A, 0xA9, 0x40, 0xC0, 0x00, 0x49, 0x19, 0xE0, 0x30, +0x48, 0x43, 0xA2, 0x79, 0x6C, 0x46, 0x08, 0x21, 0x61, 0x5E, 0x90, 0x40, +0x49, 0x01, 0x00, 0xF0, 0x8B, 0xF8, 0x34, 0x4A, 0xF0, 0x80, 0x11, 0x7D, +0xD0, 0x7D, 0x36, 0x4B, 0x08, 0x18, 0xC0, 0xB2, 0x18, 0x70, 0x17, 0x7E, +0x5F, 0x70, 0x56, 0x7E, 0x01, 0x96, 0x96, 0x7F, 0x01, 0x9C, 0x66, 0x43, +0xF4, 0xB2, 0x20, 0x18, 0xC0, 0xB2, 0x98, 0x70, 0x02, 0x90, 0x96, 0x7E, +0x03, 0x96, 0x03, 0x98, 0xD6, 0x7F, 0x46, 0x43, 0xF0, 0xB2, 0xC7, 0x19, +0xFF, 0xB2, 0xDF, 0x70, 0xD6, 0x7E, 0xB4, 0x46, 0x61, 0x44, 0x61, 0x18, +0xC9, 0xB2, 0x19, 0x71, 0x16, 0x7F, 0x80, 0x19, 0x02, 0x9E, 0xC0, 0xB2, +0x74, 0x1A, 0x3F, 0x1A, 0xE6, 0xB2, 0xFF, 0xB2, 0x58, 0x71, 0x9E, 0x71, +0xDF, 0x71, 0xBC, 0x46, 0x57, 0x7D, 0xEC, 0x1B, 0x04, 0x97, 0x27, 0x1C, +0x77, 0x43, 0xFF, 0xB2, 0x05, 0x97, 0x9F, 0x73, 0x97, 0x7D, 0x64, 0x46, +0xED, 0x1B, 0x65, 0x43, 0x47, 0x43, 0x04, 0x9C, 0x5F, 0x74, 0x4C, 0x43, +0x18, 0x72, 0x6F, 0x46, 0x14, 0x20, 0xC7, 0x5D, 0xED, 0xB2, 0xE4, 0xB2, +0xDD, 0x73, 0x1C, 0x74, 0x5D, 0x72, 0x99, 0x72, 0xDF, 0x72, 0x1E, 0x73, +0x5C, 0x73, 0x51, 0x7F, 0x12, 0x4B, 0x00, 0x29, 0x03, 0xD0, 0x69, 0x46, +0x09, 0x79, 0x19, 0x70, 0x03, 0xE0, 0x01, 0x9C, 0x03, 0x9E, 0x74, 0x43, +0x1C, 0x70, 0x93, 0x1C, 0x03, 0x32, 0x02, 0x9F, 0xD2, 0x7F, 0xDB, 0x7F, +0xBA, 0x18, 0x5B, 0xB2, 0x01, 0x32, 0x9A, 0x40, 0x09, 0x4B, 0x07, 0xB0, +0x1A, 0x60, 0xF0, 0xBD, 0x50, 0x11, 0x00, 0x20, 0xFA, 0x02, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, 0x04, 0x02, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x0A, 0x03, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, +0x18, 0x09, 0x00, 0x20, 0x02, 0xB4, 0x71, 0x46, 0x49, 0x08, 0x49, 0x00, +0x09, 0x5C, 0x49, 0x00, 0x8E, 0x44, 0x02, 0xBC, 0x70, 0x47, 0xC0, 0x46, +0x03, 0xB4, 0x71, 0x46, 0x49, 0x08, 0x40, 0x00, 0x49, 0x00, 0x09, 0x5A, +0x49, 0x00, 0x8E, 0x44, 0x03, 0xBC, 0x70, 0x47, 0x00, 0x29, 0x34, 0xD0, +0x01, 0x23, 0x00, 0x22, 0x10, 0xB4, 0x88, 0x42, 0x2C, 0xD3, 0x01, 0x24, +0x24, 0x07, 0xA1, 0x42, 0x04, 0xD2, 0x81, 0x42, 0x02, 0xD2, 0x09, 0x01, +0x1B, 0x01, 0xF8, 0xE7, 0xE4, 0x00, 0xA1, 0x42, 0x04, 0xD2, 0x81, 0x42, +0x02, 0xD2, 0x49, 0x00, 0x5B, 0x00, 0xF8, 0xE7, 0x88, 0x42, 0x01, 0xD3, +0x40, 0x1A, 0x1A, 0x43, 0x4C, 0x08, 0xA0, 0x42, 0x02, 0xD3, 0x00, 0x1B, +0x5C, 0x08, 0x22, 0x43, 0x8C, 0x08, 0xA0, 0x42, 0x02, 0xD3, 0x00, 0x1B, +0x9C, 0x08, 0x22, 0x43, 0xCC, 0x08, 0xA0, 0x42, 0x02, 0xD3, 0x00, 0x1B, +0xDC, 0x08, 0x22, 0x43, 0x00, 0x28, 0x03, 0xD0, 0x1B, 0x09, 0x01, 0xD0, +0x09, 0x09, 0xE3, 0xE7, 0x10, 0x1C, 0x10, 0xBC, 0x70, 0x47, 0x00, 0x28, +0x01, 0xD0, 0x00, 0x20, 0xC0, 0x43, 0x07, 0xB4, 0x02, 0x48, 0x02, 0xA1, +0x40, 0x18, 0x02, 0x90, 0x03, 0xBD, 0xC0, 0x46, 0xD9, 0x00, 0x00, 0x00, +0x00, 0x29, 0xF0, 0xD0, 0x03, 0xB5, 0xFF, 0xF7, 0xB9, 0xFF, 0x0E, 0xBC, +0x42, 0x43, 0x89, 0x1A, 0x18, 0x47, 0xC0, 0x46, 0x00, 0x29, 0x41, 0xD0, +0x10, 0xB4, 0x04, 0x1C, 0x4C, 0x40, 0xA4, 0x46, 0x01, 0x23, 0x00, 0x22, +0x00, 0x29, 0x00, 0xD5, 0x49, 0x42, 0x00, 0x28, 0x00, 0xD5, 0x40, 0x42, +0x88, 0x42, 0x2C, 0xD3, 0x01, 0x24, 0x24, 0x07, 0xA1, 0x42, 0x04, 0xD2, +0x81, 0x42, 0x02, 0xD2, 0x09, 0x01, 0x1B, 0x01, 0xF8, 0xE7, 0xE4, 0x00, +0xA1, 0x42, 0x04, 0xD2, 0x81, 0x42, 0x02, 0xD2, 0x49, 0x00, 0x5B, 0x00, +0xF8, 0xE7, 0x88, 0x42, 0x01, 0xD3, 0x40, 0x1A, 0x1A, 0x43, 0x4C, 0x08, +0xA0, 0x42, 0x02, 0xD3, 0x00, 0x1B, 0x5C, 0x08, 0x22, 0x43, 0x8C, 0x08, +0xA0, 0x42, 0x02, 0xD3, 0x00, 0x1B, 0x9C, 0x08, 0x22, 0x43, 0xCC, 0x08, +0xA0, 0x42, 0x02, 0xD3, 0x00, 0x1B, 0xDC, 0x08, 0x22, 0x43, 0x00, 0x28, +0x03, 0xD0, 0x1B, 0x09, 0x01, 0xD0, 0x09, 0x09, 0xE3, 0xE7, 0x10, 0x1C, +0x64, 0x46, 0x00, 0x2C, 0x00, 0xD5, 0x40, 0x42, 0x10, 0xBC, 0x70, 0x47, +0x00, 0x28, 0x06, 0xD0, 0x03, 0xDB, 0x00, 0x20, 0xC0, 0x43, 0x40, 0x08, +0x01, 0xE0, 0x80, 0x20, 0x00, 0x06, 0x07, 0xB4, 0x02, 0x48, 0x02, 0xA1, +0x40, 0x18, 0x02, 0x90, 0x03, 0xBD, 0xC0, 0x46, 0x19, 0x00, 0x00, 0x00, +0x00, 0x29, 0xEB, 0xD0, 0x03, 0xB5, 0xFF, 0xF7, 0xA7, 0xFF, 0x0E, 0xBC, +0x42, 0x43, 0x89, 0x1A, 0x18, 0x47, 0xC0, 0x46, 0x70, 0x47, 0xC0, 0x46, +0xF0, 0xB5, 0x05, 0x1C, 0x0F, 0x2A, 0x2F, 0xD9, 0x0B, 0x1C, 0x03, 0x43, +0x05, 0x1C, 0x9C, 0x07, 0x2C, 0xD1, 0x0C, 0x1C, 0x03, 0x1C, 0x15, 0x1C, +0x26, 0x68, 0x10, 0x3D, 0x1E, 0x60, 0x66, 0x68, 0x5E, 0x60, 0xA6, 0x68, +0x9E, 0x60, 0xE6, 0x68, 0x10, 0x34, 0xDE, 0x60, 0x10, 0x33, 0x0F, 0x2D, +0xF2, 0xD8, 0x13, 0x1C, 0x10, 0x3B, 0x1B, 0x09, 0x01, 0x33, 0x1B, 0x01, +0xC5, 0x18, 0xC9, 0x18, 0x0F, 0x23, 0x1A, 0x40, 0x03, 0x2A, 0x0F, 0xD9, +0x0E, 0x1C, 0x2C, 0x1C, 0x13, 0x1C, 0x80, 0xCE, 0x04, 0x3B, 0x80, 0xC4, +0x03, 0x2B, 0xFA, 0xD8, 0x13, 0x1F, 0x9B, 0x08, 0x01, 0x33, 0x9B, 0x00, +0x03, 0x24, 0x22, 0x40, 0xC9, 0x18, 0xED, 0x18, 0x00, 0x2A, 0x05, 0xD0, +0x00, 0x23, 0xCC, 0x5C, 0xEC, 0x54, 0x01, 0x33, 0x93, 0x42, 0xFA, 0xD1, +0xF0, 0xBD, 0xC0, 0x46, 0x50, 0x61, 0x6C, 0x6D, 0x20, 0x49, 0x6E, 0x69, +0x74, 0x00, 0x27, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x27, 0x20, 0x4E, 0x00, +0x4E, 0x2D, 0x6C, 0x65, 0x73, 0x73, 0x21, 0x00, 0x27, 0x45, 0x78, 0x69, +0x74, 0x27, 0x20, 0x4E, 0x00, 0x4E, 0x20, 0x53, 0x2F, 0x50, 0x00, 0x53, +0x6C, 0x65, 0x65, 0x70, 0x00, 0x53, 0x2D, 0x72, 0x65, 0x73, 0x65, 0x74, +0x00, 0x46, 0x41, 0x53, 0x54, 0x00, 0x49, 0x64, 0x6C, 0x65, 0x00, 0x41, +0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x53, 0x70, 0x65, 0x63, 0x74, 0x00, +0x53, 0x74, 0x61, 0x63, 0x6B, 0x21, 0x00, 0x52, 0x45, 0x47, 0x56, 0x41, +0x4C, 0x00, 0x44, 0x65, 0x6C, 0x61, 0x79, 0x00, 0x4F, 0x53, 0x43, 0x00, +0x4E, 0x4F, 0x49, 0x53, 0x45, 0x00, 0x54, 0x6F, 0x75, 0x63, 0x68, 0x20, +0x4F, 0x6E, 0x00, 0x54, 0x6F, 0x75, 0x63, 0x68, 0x20, 0x4F, 0x46, 0x46, +0x00, 0x4C, 0x54, 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x49, 0x4E, +0x47, 0x00, 0x46, 0x69, 0x78, 0x65, 0x64, 0x00, 0x47, 0x2D, 0x41, 0x66, +0x74, 0x65, 0x72, 0x00, 0x3D, 0x48, 0x6F, 0x76, 0x6F, 0x72, 0x00, 0x12, +0x0E, 0x07, 0x0D, 0x0A, 0x12, 0x04, 0x06, 0x0C, 0x09, 0x12, 0x0F, 0x05, +0x11, 0x08, 0x12, 0x00, 0x01, 0x10, 0x02, 0x45, 0x72, 0x72, 0x00, 0x4B, +0x65, 0x79, 0x20, 0x52, 0x00, 0x52, 0x45, 0x46, 0x20, 0x49, 0x4E, 0x49, +0x54, 0x00, 0x43, 0x6D, 0x44, 0x65, 0x6C, 0x74, 0x61, 0x20, 0x52, 0x65, +0x66, 0x2F, 0x52, 0x65, 0x61, 0x6C, 0x00, 0x52, 0x61, 0x77, 0x00, 0x4D, +0x41, 0x58, 0x20, 0x49, 0x00, 0x43, 0x4D, 0x5F, 0x44, 0x45, 0x4C, 0x54, +0x41, 0x5F, 0x4D, 0x41, 0x58, 0x5F, 0x4D, 0x49, 0x4E, 0x00, 0x54, 0x78, +0x6C, 0x65, 0x73, 0x73, 0x00, 0x44, 0x69, 0x66, 0x66, 0x00, 0x44, 0x49, +0x46, 0x46, 0x2F, 0x4E, 0x00, 0x42, 0x69, 0x67, 0x20, 0x47, 0x72, 0x61, +0x64, 0x00, 0x4E, 0x65, 0x67, 0x2D, 0x45, 0x64, 0x67, 0x65, 0x00, 0x52, +0x65, 0x66, 0x00, 0x00, 0x2D, 0x49, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x01, +0x00, 0xFF, 0x01, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, +0xA0, 0x0D, 0x00, 0x20, 0x28, 0x02, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x00, +0x54, 0x11, 0x00, 0x20, 0x01, 0x02, 0xFF, 0x00, 0x01, 0x04, 0x00, 0x04, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x45, 0x4D, 0x31, 0x48, 0x30, +0x50, 0x52, 0x34, 0x35, 0x08, 0xB5, 0x00, 0x28, 0x02, 0xD0, 0x01, 0x28, +0x24, 0xD1, 0x07, 0xE0, 0x12, 0x4B, 0x13, 0x4A, 0x1A, 0x60, 0x13, 0x4B, +0x58, 0x60, 0x98, 0x60, 0xD8, 0x60, 0x1B, 0xE0, 0x11, 0x4B, 0x1B, 0x68, +0x10, 0x2B, 0x15, 0xD1, 0x10, 0x4A, 0x11, 0x4B, 0x1A, 0x60, 0x11, 0x4A, +0x11, 0x4B, 0x1A, 0x60, 0x11, 0x4A, 0x12, 0x4B, 0x1A, 0x60, 0x12, 0x4A, +0x12, 0x4B, 0x1A, 0x60, 0x12, 0x4A, 0x13, 0x4B, 0x1A, 0x60, 0x13, 0x4A, +0x13, 0x4B, 0x1A, 0x60, 0x13, 0x4A, 0x14, 0x4B, 0x1A, 0x60, 0x01, 0xE0, +0xFE, 0xF7, 0xCC, 0xF8, 0x08, 0xBD, 0xC0, 0x46, 0xF8, 0x01, 0x00, 0x20, +0x49, 0x68, 0x00, 0x00, 0xF8, 0x08, 0x00, 0x20, 0x50, 0x11, 0x00, 0x20, +0xA9, 0x5C, 0x00, 0x00, 0x68, 0x00, 0x00, 0x20, 0x5D, 0x63, 0x00, 0x00, +0x6C, 0x00, 0x00, 0x20, 0x65, 0x61, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, +0xC5, 0x6E, 0x00, 0x00, 0x18, 0x00, 0x00, 0x20, 0xFD, 0x5C, 0x00, 0x00, +0x1C, 0x00, 0x00, 0x20, 0xE1, 0x5C, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, +0xAB, 0x5C, 0x00, 0x00, 0x24, 0x00, 0x00, 0x20, 0x70, 0x47, 0xA0, 0x23, +0xDB, 0x05, 0x01, 0x22, 0x1A, 0x72, 0x09, 0x49, 0x10, 0x22, 0x1A, 0x72, +0x00, 0x22, 0x0A, 0x70, 0x1A, 0x72, 0x07, 0x4B, 0x80, 0x22, 0x19, 0x68, +0x52, 0x00, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x99, 0x68, 0x9A, 0x60, 0x70, 0x47, 0xC0, 0x46, 0x0C, 0x00, 0x00, 0x20, +0x14, 0x00, 0x00, 0x20, 0x08, 0xB5, 0x05, 0x4B, 0x1B, 0x88, 0xDB, 0xB2, +0x10, 0x2B, 0x01, 0xD0, 0xAF, 0x2B, 0x01, 0xD1, 0xFD, 0xF7, 0x12, 0xFC, +0x08, 0xBD, 0xC0, 0x46, 0x28, 0x00, 0x00, 0x20, 0x38, 0xB5, 0xBE, 0x4A, +0x13, 0x88, 0x1B, 0xB2, 0xA8, 0x2B, 0x00, 0xD1, 0xB3, 0xE1, 0x40, 0xDC, +0x0B, 0x2B, 0x00, 0xD1, 0xD9, 0xE0, 0x1E, 0xDC, 0x06, 0x2B, 0x00, 0xD1, +0xB5, 0xE0, 0x0E, 0xDC, 0x03, 0x2B, 0x00, 0xD1, 0x99, 0xE0, 0x03, 0xDC, +0x02, 0x2B, 0x00, 0xD0, 0xC1, 0xE1, 0x87, 0xE0, 0x04, 0x2B, 0x00, 0xD1, +0x9A, 0xE0, 0x05, 0x2B, 0x00, 0xD0, 0xBA, 0xE1, 0xA0, 0xE0, 0x08, 0x2B, +0x00, 0xD1, 0xDC, 0xE0, 0x00, 0xDA, 0xA6, 0xE0, 0x09, 0x2B, 0x00, 0xD1, +0xA8, 0xE0, 0x0A, 0x2B, 0x00, 0xD0, 0xAE, 0xE1, 0xB4, 0xE0, 0x30, 0x2B, +0x00, 0xD1, 0xAC, 0xE0, 0x0A, 0xDC, 0x0D, 0x2B, 0x00, 0xD1, 0xC2, 0xE0, +0x00, 0xDA, 0xB7, 0xE0, 0x0F, 0x2B, 0x51, 0xD0, 0x10, 0x2B, 0x00, 0xD0, +0x9F, 0xE1, 0x58, 0xE0, 0x61, 0x2B, 0x00, 0xD1, 0x92, 0xE1, 0x03, 0xDC, +0x31, 0x2B, 0x00, 0xD0, 0x97, 0xE1, 0x8D, 0xE0, 0x62, 0x2B, 0x00, 0xD1, +0x8F, 0xE1, 0x64, 0x2B, 0x00, 0xD0, 0x90, 0xE1, 0x81, 0xE1, 0xF4, 0x2B, +0x00, 0xD1, 0xD3, 0xE0, 0x1E, 0xDC, 0xEF, 0x2B, 0x00, 0xD1, 0x60, 0xE1, +0x0E, 0xDC, 0xAF, 0x2B, 0x00, 0xD1, 0x4A, 0xE1, 0x03, 0xDC, 0xAE, 0x2B, +0x00, 0xD0, 0x80, 0xE1, 0x3E, 0xE1, 0xBF, 0x2B, 0x00, 0xD1, 0x5E, 0xE1, +0xEE, 0x2B, 0x00, 0xD0, 0x79, 0xE1, 0x4C, 0xE1, 0xF1, 0x2B, 0x00, 0xD1, +0xA3, 0xE0, 0x00, 0xDA, 0x9E, 0xE0, 0xF2, 0x2B, 0x00, 0xD1, 0xA6, 0xE0, +0xF3, 0x2B, 0x00, 0xD0, 0x6D, 0xE1, 0xAB, 0xE0, 0xF9, 0x2B, 0x00, 0xD1, +0xDF, 0xE0, 0x0B, 0xDC, 0xF6, 0x2B, 0x00, 0xD1, 0xBF, 0xE0, 0x00, 0xDA, +0xB3, 0xE0, 0xF7, 0x2B, 0x00, 0xD1, 0xC1, 0xE0, 0xF8, 0x2B, 0x00, 0xD0, +0x5D, 0xE1, 0xC9, 0xE0, 0xFB, 0x2B, 0x00, 0xD1, 0xE1, 0xE0, 0x00, 0xDA, +0xD6, 0xE0, 0xFC, 0x2B, 0x00, 0xD1, 0xE5, 0xE0, 0xFD, 0x2B, 0x00, 0xD0, +0x51, 0xE1, 0xEA, 0xE0, 0x7B, 0x4C, 0x23, 0x68, 0x00, 0x2B, 0x01, 0xD1, +0xFD, 0xF7, 0x80, 0xFB, 0x22, 0x68, 0x79, 0x4B, 0xD2, 0x00, 0x1A, 0x70, +0x45, 0xE1, 0x78, 0x49, 0x78, 0x4A, 0x00, 0x23, 0x08, 0x78, 0x75, 0x4D, +0xC0, 0x18, 0x14, 0x5C, 0x58, 0x19, 0x01, 0x33, 0x04, 0x70, 0x08, 0x2B, +0xF6, 0xD1, 0x38, 0xE1, 0x73, 0x4A, 0x0F, 0x23, 0x26, 0x20, 0x11, 0x5E, +0x28, 0x25, 0x52, 0x5F, 0x09, 0x11, 0x12, 0x12, 0x99, 0x43, 0x13, 0x40, +0x6B, 0x4A, 0xCB, 0x18, 0x13, 0x70, 0x68, 0x4B, 0x1A, 0x88, 0x03, 0x23, +0x12, 0xB2, 0x9A, 0x1A, 0x6A, 0x4B, 0x19, 0x8D, 0x66, 0x4B, 0xD1, 0x54, +0x63, 0x4B, 0x1A, 0x88, 0x04, 0x23, 0x12, 0xB2, 0x9A, 0x1A, 0x66, 0x4B, +0xD9, 0x8C, 0x62, 0x4B, 0xD1, 0x54, 0x18, 0xE1, 0x64, 0x4B, 0xDA, 0x8C, +0x5F, 0x4B, 0x1A, 0x70, 0x13, 0xE1, 0x62, 0x4B, 0x34, 0x33, 0x1A, 0x78, +0x5C, 0x4B, 0x1A, 0x70, 0x0D, 0xE1, 0x5E, 0x4B, 0xDA, 0x7B, 0x5A, 0x4B, +0x1A, 0x70, 0x08, 0xE1, 0x5D, 0x4B, 0x1A, 0x78, 0x57, 0x4B, 0x00, 0x2A, +0x02, 0xD0, 0x02, 0x22, 0x1A, 0x70, 0x00, 0xE1, 0x01, 0x22, 0x1A, 0x70, +0xFD, 0xE0, 0x58, 0x4B, 0x1A, 0x78, 0x52, 0x4B, 0x1A, 0x70, 0xF8, 0xE0, +0x56, 0x4B, 0x1A, 0x78, 0x4F, 0x4B, 0x1A, 0x70, 0xF3, 0xE0, 0x12, 0x88, +0x54, 0x49, 0x12, 0xB2, 0x9B, 0x1A, 0x09, 0x78, 0x4B, 0x4A, 0x99, 0x54, +0x48, 0x4B, 0x1A, 0x88, 0x50, 0x4B, 0x12, 0xB2, 0x59, 0x78, 0x0C, 0x23, +0x9A, 0x1A, 0x47, 0x4B, 0xD1, 0x54, 0x44, 0x4B, 0x1A, 0x88, 0x4D, 0x4B, +0x12, 0xB2, 0x19, 0x78, 0x0D, 0x23, 0x9A, 0x1A, 0x42, 0x4B, 0xD1, 0x54, +0xD9, 0xE0, 0x45, 0x4B, 0xDA, 0x8D, 0x40, 0x4B, 0x1A, 0x70, 0xD4, 0xE0, +0x3E, 0x4B, 0x42, 0x22, 0x1A, 0x70, 0x3B, 0x4B, 0x0C, 0x21, 0x1A, 0x88, +0xF1, 0x23, 0x12, 0xB2, 0x9A, 0x1A, 0x3A, 0x4B, 0xD1, 0x54, 0x37, 0x4B, +0x1A, 0x88, 0x3B, 0x4B, 0x12, 0xB2, 0x59, 0x78, 0xF2, 0x23, 0x9A, 0x1A, +0x35, 0x4B, 0xD1, 0x54, 0x32, 0x4B, 0xA8, 0x21, 0x1A, 0x88, 0xF3, 0x23, +0x12, 0xB2, 0x9A, 0x1A, 0x31, 0x4B, 0xD1, 0x54, 0x2E, 0x4B, 0x1A, 0x88, +0x38, 0x4B, 0x12, 0xB2, 0x19, 0x78, 0xF4, 0x23, 0x9A, 0x1A, 0x2D, 0x4B, +0xD1, 0x54, 0x2A, 0x4B, 0x1A, 0x88, 0x35, 0x4B, 0x12, 0xB2, 0x19, 0x78, +0xF5, 0x23, 0x9A, 0x1A, 0x28, 0x4B, 0xD1, 0x54, 0xA5, 0xE0, 0x28, 0x4B, +0x29, 0x4A, 0x1B, 0x78, 0xD3, 0x18, 0xDA, 0x78, 0x24, 0x4B, 0x1A, 0x70, +0x21, 0x4B, 0x26, 0x49, 0x1A, 0x88, 0x23, 0x4B, 0x12, 0xB2, 0x1B, 0x78, +0xCB, 0x18, 0x19, 0x79, 0xF7, 0x23, 0x9A, 0x1A, 0x1E, 0x4B, 0xD1, 0x54, +0x1B, 0x4B, 0x1A, 0x88, 0x1F, 0x4B, 0x12, 0xB2, 0x59, 0x79, 0xF8, 0x23, +0x9A, 0x1A, 0x1A, 0x4B, 0xD1, 0x54, 0x17, 0x4B, 0x1A, 0x88, 0x1B, 0x4B, +0x12, 0xB2, 0x99, 0x79, 0xF9, 0x23, 0x9A, 0x1A, 0x15, 0x4B, 0xD1, 0x54, +0x12, 0x4B, 0x1A, 0x88, 0x16, 0x4B, 0x12, 0xB2, 0xD9, 0x79, 0xFA, 0x23, +0x9A, 0x1A, 0x11, 0x4B, 0xD1, 0x54, 0x0E, 0x4B, 0x1A, 0x88, 0x12, 0x4B, +0x12, 0xB2, 0x19, 0x7A, 0xFB, 0x23, 0x9A, 0x1A, 0x0C, 0x4B, 0xD1, 0x54, +0x09, 0x4B, 0x1A, 0x88, 0x0D, 0x4B, 0x12, 0xB2, 0x59, 0x7A, 0xFC, 0x23, +0x9A, 0x1A, 0x08, 0x4B, 0xD1, 0x54, 0x05, 0x4B, 0x1A, 0x88, 0x09, 0x4B, +0x12, 0xB2, 0x99, 0x7A, 0xFD, 0x23, 0x9A, 0x1A, 0x03, 0x4B, 0xD1, 0x54, +0x5B, 0xE0, 0xC0, 0x46, 0x28, 0x00, 0x00, 0x20, 0x98, 0x0D, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x50, 0x2A, 0x00, 0x00, 0x20, 0xEC, 0x11, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, +0xDF, 0x01, 0x00, 0x20, 0x0A, 0x03, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, +0xFF, 0x73, 0x00, 0x00, 0xFF, 0x7B, 0x00, 0x00, 0x20, 0x4B, 0x1A, 0x78, +0x20, 0x4B, 0x1A, 0x70, 0xFD, 0xF7, 0x70, 0xFA, 0x39, 0xE0, 0x1F, 0x49, +0x1F, 0x4A, 0x00, 0x23, 0x0C, 0x68, 0x10, 0x78, 0x1B, 0x4D, 0x20, 0x18, +0xC4, 0x5C, 0x58, 0x19, 0x01, 0x33, 0x04, 0x70, 0x08, 0x2B, 0xF5, 0xD1, +0x2B, 0xE0, 0x1A, 0x4B, 0x1A, 0x7E, 0x16, 0x4B, 0x1A, 0x70, 0x19, 0x4B, +0x1A, 0x88, 0x17, 0x4B, 0x12, 0xB2, 0xD9, 0x7D, 0xEF, 0x23, 0x9A, 0x1A, +0x11, 0x4B, 0xD1, 0x54, 0x1D, 0xE0, 0x11, 0x49, 0x11, 0x4A, 0x00, 0x23, +0x0C, 0x68, 0x10, 0x78, 0x0D, 0x4D, 0x20, 0x18, 0xC4, 0x5C, 0x58, 0x19, +0x01, 0x33, 0x04, 0x70, 0x08, 0x2B, 0xF5, 0xD1, 0xFD, 0xF7, 0x44, 0xFA, +0x0D, 0xE0, 0x0D, 0x4B, 0x1A, 0x78, 0x07, 0x4B, 0x1A, 0x70, 0x08, 0xE0, +0x0B, 0x4B, 0x9A, 0x78, 0x04, 0x4B, 0x1A, 0x70, 0x03, 0xE0, 0x09, 0x4B, +0xDA, 0x78, 0x02, 0x4B, 0x1A, 0x70, 0x38, 0xBD, 0xF6, 0x03, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x50, 0x34, 0x0D, 0x00, 0x20, 0x2A, 0x00, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x28, 0x00, 0x00, 0x20, 0xFF, 0x5B, 0x00, 0x00, +0x35, 0x00, 0x00, 0x20, 0x08, 0xB5, 0x03, 0x1C, 0x50, 0x1E, 0x06, 0x28, +0x35, 0xD8, 0xFF, 0xF7, 0xF5, 0xFA, 0x04, 0x0A, 0x2A, 0x1B, 0x15, 0x2A, +0x2A, 0x00, 0x18, 0x4A, 0x01, 0x23, 0x13, 0x70, 0x17, 0x4A, 0x13, 0x70, +0x29, 0xE0, 0x16, 0x4A, 0x9B, 0x01, 0x59, 0x18, 0x02, 0x20, 0x15, 0x4B, +0x10, 0x70, 0x49, 0x00, 0x14, 0x4A, 0xC9, 0x18, 0x11, 0x60, 0x1E, 0xE0, +0xFD, 0xF7, 0x06, 0xFA, 0x0E, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x18, 0xE0, +0x0D, 0x4A, 0x5B, 0x01, 0x59, 0x18, 0x01, 0x20, 0x0E, 0x4B, 0x10, 0x70, +0x5A, 0x56, 0x0E, 0x4B, 0x00, 0x2A, 0x00, 0xDC, 0x00, 0x22, 0x1A, 0x80, +0x09, 0x4A, 0x13, 0x60, 0x09, 0xE0, 0x06, 0x4A, 0x02, 0x20, 0x5B, 0x01, +0x10, 0x70, 0xC9, 0x18, 0x08, 0x4A, 0x49, 0x00, 0x89, 0x18, 0x04, 0x4A, +0x11, 0x60, 0x08, 0xBD, 0xE5, 0x01, 0x00, 0x20, 0xF6, 0x03, 0x00, 0x20, +0x84, 0x40, 0x00, 0x40, 0x34, 0x0D, 0x00, 0x20, 0x64, 0x0E, 0x00, 0x20, +0x08, 0x03, 0x00, 0x20, 0xF8, 0x03, 0x00, 0x20, 0xF0, 0xB5, 0x8B, 0xB0, +0xFD, 0xF7, 0x02, 0xFA, 0x00, 0x28, 0xFB, 0xD1, 0x70, 0x4A, 0x23, 0x23, +0xD2, 0x5C, 0x00, 0x2A, 0x00, 0xD1, 0x9C, 0xE0, 0x6E, 0x4B, 0x60, 0x24, +0x1D, 0x78, 0x6E, 0x4B, 0x2D, 0x01, 0x19, 0x78, 0x64, 0x42, 0x2C, 0x43, +0x09, 0x01, 0x20, 0x25, 0x6B, 0x4E, 0x29, 0x43, 0x34, 0x25, 0x75, 0x5D, +0x01, 0x32, 0xE4, 0xB2, 0xC9, 0xB2, 0xD2, 0xB2, 0x08, 0x94, 0x09, 0x91, +0x07, 0x92, 0x67, 0x48, 0x67, 0x4B, 0x06, 0x95, 0x00, 0x21, 0x01, 0x22, +0x00, 0x24, 0x42, 0xE0, 0x6D, 0x46, 0x08, 0x26, 0x75, 0x5F, 0x03, 0x95, +0x01, 0x9F, 0x03, 0x9E, 0x3F, 0x11, 0x35, 0x12, 0xBC, 0x46, 0x0F, 0x27, +0x2F, 0x40, 0x03, 0x97, 0x65, 0x46, 0x0F, 0x27, 0xBD, 0x43, 0xAC, 0x46, +0x05, 0x79, 0xE6, 0x00, 0x05, 0x95, 0x5C, 0x4D, 0x03, 0x9F, 0x75, 0x19, +0x08, 0x9E, 0x16, 0x43, 0x01, 0x96, 0x66, 0x46, 0x37, 0x43, 0xBC, 0x46, +0x6F, 0x46, 0x3F, 0x79, 0x66, 0x46, 0x2F, 0x70, 0x6E, 0x70, 0x6F, 0x46, +0x08, 0x26, 0xF7, 0x5D, 0x6E, 0x46, 0xAF, 0x70, 0x10, 0x27, 0xBE, 0x5D, +0x6F, 0x46, 0xEE, 0x70, 0x14, 0x26, 0xF7, 0x5D, 0x2F, 0x71, 0x1E, 0x78, +0x6E, 0x71, 0x5E, 0x68, 0xFF, 0x2E, 0x00, 0xDD, 0xFF, 0x26, 0xAE, 0x71, +0x9E, 0x68, 0xFF, 0x2E, 0x00, 0xDD, 0xFF, 0x26, 0x01, 0x34, 0xEE, 0x71, +0xE4, 0xB2, 0x01, 0x32, 0x07, 0x9D, 0xD2, 0xB2, 0x0A, 0x30, 0x0C, 0x33, +0x02, 0x31, 0xAA, 0x42, 0x3B, 0xD0, 0x00, 0x26, 0x85, 0x5F, 0x00, 0x2D, +0x3B, 0xDD, 0x43, 0x4F, 0x43, 0x4E, 0xCF, 0x19, 0x05, 0x97, 0x3F, 0x8C, +0x75, 0x18, 0x04, 0x97, 0x18, 0x27, 0xEE, 0x5F, 0x10, 0x27, 0xB4, 0x46, +0x6E, 0x46, 0xBE, 0x5F, 0x67, 0x46, 0x01, 0x96, 0xF6, 0x1B, 0xF7, 0x17, +0xF6, 0x19, 0x7E, 0x40, 0x03, 0x96, 0x05, 0x9E, 0xAF, 0x88, 0xB6, 0x88, +0xBC, 0x46, 0x02, 0x96, 0x06, 0x9F, 0x03, 0x9E, 0xBE, 0x42, 0x9B, 0xDA, +0x08, 0x26, 0x6F, 0x46, 0xF7, 0x5F, 0x03, 0x97, 0x03, 0x9E, 0x67, 0x46, +0x3F, 0xB2, 0xF6, 0x1B, 0xF7, 0x17, 0xF6, 0x19, 0x7E, 0x40, 0xB4, 0x46, +0x06, 0x9E, 0x66, 0x45, 0x90, 0xDD, 0x2C, 0x27, 0xED, 0x5F, 0x00, 0x2D, +0x8C, 0xDD, 0x01, 0x32, 0x07, 0x9D, 0xD2, 0xB2, 0x0A, 0x30, 0x0C, 0x33, +0x02, 0x31, 0xAA, 0x42, 0xC3, 0xD1, 0x00, 0x2C, 0x38, 0xD1, 0x0B, 0xB0, +0xF0, 0xBD, 0x26, 0x4E, 0x75, 0x18, 0x2C, 0x27, 0xEE, 0x5F, 0x00, 0x2E, +0xB1, 0xDD, 0x2E, 0x8B, 0x05, 0x27, 0xEF, 0x57, 0x02, 0x96, 0x6E, 0x46, +0x08, 0x36, 0xBC, 0x46, 0x00, 0x27, 0xF7, 0x5F, 0xAD, 0x88, 0x3E, 0x11, +0xE7, 0x00, 0x03, 0x97, 0x04, 0x95, 0x67, 0x46, 0x0F, 0x25, 0x3D, 0x40, +0x05, 0x95, 0x0F, 0x25, 0xAE, 0x43, 0x01, 0x96, 0x16, 0x4F, 0x03, 0x9E, +0x01, 0x34, 0xF5, 0x19, 0x09, 0x9E, 0x01, 0x9F, 0x16, 0x43, 0xB4, 0x46, +0x05, 0x9E, 0xE4, 0xB2, 0x37, 0x43, 0x66, 0x46, 0x2E, 0x70, 0x6F, 0x70, +0x10, 0x26, 0x6F, 0x46, 0xF7, 0x5D, 0x6E, 0x46, 0xAF, 0x70, 0x08, 0x27, +0xBE, 0x5D, 0x00, 0x27, 0xEE, 0x70, 0x2F, 0x71, 0x6F, 0x71, 0xAF, 0x71, +0xEF, 0x71, 0x80, 0xE7, 0x0B, 0x4B, 0x1C, 0x60, 0xFD, 0xF7, 0xCA, 0xF8, +0xC1, 0xE7, 0xC0, 0x46, 0xAE, 0x09, 0x00, 0x20, 0xF5, 0x00, 0x00, 0x20, +0xF4, 0x00, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0xD8, 0x0D, 0x00, 0x20, +0x2C, 0x13, 0x00, 0x20, 0xEC, 0x11, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0x20, 0x01, 0x00, 0x20, 0x98, 0x0D, 0x00, 0x20, 0x10, 0xB5, 0x04, 0x1C, +0xFD, 0xF7, 0x06, 0xF9, 0x00, 0x28, 0xFB, 0xD1, 0x0A, 0x4B, 0x01, 0x2C, +0x02, 0xD0, 0x02, 0x2C, 0x05, 0xD1, 0x02, 0xE0, 0x0F, 0x22, 0x1A, 0x70, +0x01, 0xE0, 0x0E, 0x22, 0x1A, 0x70, 0x00, 0x22, 0x5A, 0x70, 0x9A, 0x70, +0xDA, 0x70, 0x04, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xFD, 0xF7, 0x9A, 0xF8, +0x10, 0xBD, 0xC0, 0x46, 0xEC, 0x11, 0x00, 0x20, 0x98, 0x0D, 0x00, 0x20, +0xF0, 0xB5, 0x8B, 0xB0, 0x04, 0x93, 0x10, 0xAB, 0x1B, 0x78, 0x01, 0x92, +0x07, 0x93, 0x4C, 0x4B, 0x04, 0x1C, 0x03, 0x60, 0x80, 0x23, 0x1B, 0x06, +0x0B, 0x60, 0x0D, 0x1C, 0x17, 0x78, 0x86, 0xE0, 0x48, 0x4A, 0x49, 0x4B, +0x28, 0x20, 0x10, 0x5E, 0x47, 0x49, 0x78, 0x43, 0x0A, 0x26, 0x8E, 0x5F, +0x59, 0x68, 0xFF, 0xF7, 0xDD, 0xF9, 0x00, 0xB2, 0x30, 0x18, 0x7A, 0x1C, +0x01, 0x99, 0x06, 0x90, 0x93, 0x01, 0x8E, 0x78, 0x05, 0x92, 0x09, 0x93, +0x69, 0xE0, 0x09, 0x99, 0xB3, 0x1C, 0xCB, 0x18, 0x3E, 0x49, 0x5A, 0x5C, +0x1F, 0x2A, 0x29, 0xD1, 0x00, 0x20, 0x04, 0x23, 0x01, 0x1C, 0x02, 0x93, +0x94, 0x46, 0x08, 0x94, 0x3A, 0x4A, 0x01, 0x3B, 0xDB, 0xB2, 0xD4, 0x56, +0x39, 0x4A, 0x3C, 0x19, 0xD2, 0x56, 0x01, 0x34, 0xB2, 0x18, 0x03, 0x92, +0xA4, 0x01, 0x02, 0x32, 0xA4, 0x18, 0x33, 0x4A, 0x02, 0x94, 0x12, 0x5D, +0x02, 0x92, 0x00, 0x2A, 0x02, 0xD0, 0x0E, 0x2A, 0x02, 0xD9, 0x02, 0xE0, +0x01, 0x20, 0x00, 0xE0, 0x11, 0x1C, 0x00, 0x2B, 0xE4, 0xD1, 0x62, 0x46, +0x08, 0x9C, 0x00, 0x29, 0x04, 0xD0, 0x00, 0x28, 0x02, 0xD0, 0x0A, 0x1C, +0x0E, 0x32, 0xD2, 0xB2, 0x13, 0x1C, 0x0F, 0x3B, 0x0C, 0x2B, 0x32, 0xD8, +0x28, 0x4B, 0x0E, 0x3A, 0xD2, 0xB2, 0x9A, 0x18, 0x01, 0x23, 0x5B, 0x42, +0xD3, 0x56, 0x07, 0x99, 0x8B, 0x42, 0x28, 0xD1, 0x04, 0x9A, 0x06, 0x99, +0x13, 0x68, 0x5B, 0x1A, 0x1A, 0xB2, 0x04, 0x9B, 0x02, 0x92, 0x5B, 0x68, +0x03, 0x93, 0x1B, 0x4B, 0x08, 0x22, 0x99, 0x5E, 0x18, 0x4A, 0x08, 0x91, +0x26, 0x21, 0x50, 0x5E, 0x19, 0x68, 0x70, 0x43, 0xFF, 0xF7, 0x80, 0xF9, +0x08, 0x9A, 0x03, 0x9B, 0x00, 0xB2, 0x10, 0x18, 0x18, 0x1A, 0x01, 0xB2, +0x02, 0x98, 0xFB, 0xF7, 0xF3, 0xFF, 0x23, 0x68, 0x98, 0x42, 0x02, 0xDA, +0x20, 0x60, 0x27, 0x71, 0x66, 0x71, 0x2B, 0x68, 0x98, 0x42, 0x02, 0xDD, +0x28, 0x60, 0x2F, 0x71, 0x6E, 0x71, 0x01, 0x36, 0xF6, 0xB2, 0x01, 0x99, +0x03, 0x23, 0xCB, 0x56, 0x9E, 0x42, 0x90, 0xDD, 0x6A, 0x46, 0x14, 0x23, +0x9F, 0x5C, 0x01, 0x99, 0x01, 0x23, 0xCB, 0x56, 0x9F, 0x42, 0x00, 0xDC, +0x72, 0xE7, 0x0B, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, 0xFF, 0xFF, 0xFF, 0x7F, +0xAE, 0x09, 0x00, 0x20, 0x24, 0x09, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, +0xF4, 0x59, 0x00, 0x00, 0xF0, 0x59, 0x00, 0x00, 0xEC, 0x02, 0x00, 0x20, +0xF0, 0xB5, 0x97, 0xB0, 0x1C, 0x1C, 0x1C, 0xAB, 0x1B, 0x78, 0x6F, 0x46, +0x0D, 0x93, 0x00, 0x23, 0x10, 0x93, 0x11, 0x93, 0x12, 0x93, 0x13, 0x93, +0x14, 0x93, 0x15, 0x93, 0x46, 0x78, 0x0D, 0x1C, 0x01, 0x96, 0x3F, 0x79, +0x51, 0x1C, 0x7F, 0xB2, 0x03, 0x97, 0x33, 0x1C, 0xB9, 0x42, 0x01, 0xDA, +0x93, 0x1C, 0xDB, 0xB2, 0x39, 0x21, 0x69, 0x44, 0x0B, 0x70, 0x06, 0x78, +0x08, 0x21, 0x02, 0x96, 0x6F, 0x46, 0xCF, 0x57, 0x51, 0x1E, 0x04, 0x97, +0x33, 0x1C, 0xB9, 0x42, 0x01, 0xDD, 0x93, 0x1E, 0xDB, 0xB2, 0x0E, 0xA9, +0x0B, 0x70, 0xC6, 0x78, 0x6F, 0x46, 0x00, 0x96, 0x3F, 0x78, 0x61, 0x1C, +0x7F, 0xB2, 0x05, 0x97, 0x33, 0x1C, 0xB9, 0x42, 0x01, 0xDA, 0xA3, 0x1C, +0xDB, 0xB2, 0x3B, 0x21, 0x69, 0x44, 0x0B, 0x70, 0x87, 0x78, 0x61, 0x1E, +0x7E, 0xB2, 0x06, 0x96, 0x3B, 0x1C, 0xB1, 0x42, 0x01, 0xDD, 0xA3, 0x1E, +0xDB, 0xB2, 0x3A, 0x20, 0x68, 0x44, 0x03, 0x70, 0xA7, 0x4B, 0xA8, 0x49, +0x0A, 0x20, 0x1E, 0x5E, 0x07, 0x96, 0x28, 0x20, 0x0E, 0x5E, 0x08, 0x96, +0x5E, 0x68, 0x09, 0x96, 0x08, 0x20, 0x1E, 0x5E, 0x1B, 0x68, 0x0A, 0x96, +0x26, 0x20, 0x0E, 0x5E, 0x08, 0x98, 0x09, 0x99, 0x50, 0x43, 0x0B, 0x96, +0x0C, 0x93, 0xFF, 0xF7, 0xED, 0xF8, 0x07, 0x99, 0x2E, 0x68, 0x03, 0xB2, +0xCB, 0x18, 0xF3, 0x1A, 0x9E, 0x19, 0x09, 0x98, 0x76, 0x1A, 0x70, 0x43, +0x08, 0x99, 0xFF, 0xF7, 0xE1, 0xF8, 0x06, 0x1C, 0x0B, 0x98, 0x0C, 0x99, +0x60, 0x43, 0xFF, 0xF7, 0xDB, 0xF8, 0x0A, 0x9C, 0x6D, 0x68, 0x03, 0xB2, +0xE3, 0x18, 0xEB, 0x1A, 0x5D, 0x19, 0x0C, 0x98, 0x2D, 0x1B, 0x68, 0x43, +0x0B, 0x99, 0xFF, 0xF7, 0xCF, 0xF8, 0x03, 0x9D, 0x73, 0x1C, 0xAB, 0x42, +0x02, 0xDA, 0xB3, 0x1C, 0xDB, 0xB2, 0x01, 0x93, 0x69, 0x46, 0x0A, 0x79, +0x04, 0x9C, 0x3D, 0x21, 0x69, 0x44, 0x73, 0x1E, 0x0A, 0x70, 0xA3, 0x42, +0x02, 0xDD, 0x02, 0x3E, 0xF6, 0xB2, 0x02, 0x96, 0x6D, 0x46, 0x08, 0x26, +0x76, 0x5D, 0x05, 0x9C, 0x0F, 0xAD, 0x43, 0x1C, 0x2E, 0x70, 0xA3, 0x42, +0x02, 0xDA, 0x83, 0x1C, 0xDB, 0xB2, 0x00, 0x93, 0x6D, 0x46, 0x2E, 0x78, +0x06, 0x9C, 0x3F, 0x25, 0x6D, 0x44, 0x43, 0x1E, 0x2E, 0x70, 0xA3, 0x42, +0x01, 0xDD, 0x87, 0x1E, 0xFF, 0xB2, 0x7A, 0x4B, 0x3E, 0x25, 0x1B, 0x68, +0x6D, 0x44, 0x2F, 0x70, 0x03, 0x93, 0x02, 0x25, 0x01, 0x3D, 0xED, 0xB2, +0xAA, 0x00, 0x0E, 0xA9, 0x8B, 0x18, 0x01, 0x24, 0x1C, 0x57, 0x38, 0x26, +0xB6, 0x18, 0x6F, 0x46, 0xF0, 0x5D, 0xAC, 0x46, 0x05, 0x94, 0x00, 0x93, +0x5D, 0xE0, 0x00, 0x9D, 0x03, 0x26, 0xAE, 0x57, 0x47, 0x1C, 0xBB, 0x01, +0xA9, 0x78, 0x04, 0x96, 0x01, 0x97, 0x02, 0x93, 0x4E, 0xE0, 0x02, 0x9C, +0x8E, 0x1C, 0x6A, 0x4D, 0xA3, 0x19, 0x5B, 0x5D, 0x1F, 0x2B, 0x1A, 0xD1, +0x04, 0x24, 0x68, 0x4D, 0x01, 0x3C, 0xE4, 0xB2, 0x2F, 0x57, 0xC7, 0x19, +0x01, 0x37, 0x06, 0x97, 0x65, 0x4F, 0x3D, 0x57, 0x4D, 0x19, 0x02, 0x35, +0x07, 0x95, 0x06, 0x9D, 0xAF, 0x01, 0x07, 0x9D, 0x7F, 0x19, 0x5F, 0x4D, +0xED, 0x5D, 0x6F, 0x1E, 0x06, 0x95, 0x0D, 0x2F, 0x00, 0xD9, 0x1D, 0x1C, +0x2B, 0x1C, 0x00, 0x2C, 0xE5, 0xD1, 0x1C, 0x1C, 0x0F, 0x3C, 0xE4, 0xB2, +0x0F, 0x2C, 0x02, 0xD8, 0x0E, 0x3B, 0xDB, 0xB2, 0x01, 0xE0, 0x00, 0x2B, +0x20, 0xD0, 0x58, 0x4F, 0x0D, 0x9C, 0xFB, 0x18, 0x01, 0x3B, 0x1B, 0x78, +0x5B, 0xB2, 0xA3, 0x42, 0x18, 0xD1, 0x02, 0x9D, 0x54, 0x4B, 0xAE, 0x19, +0x76, 0x00, 0xF3, 0x5A, 0x03, 0x9E, 0x9B, 0x1B, 0x00, 0x2B, 0x0F, 0xDD, +0x05, 0x1C, 0x5D, 0x43, 0x10, 0xAC, 0x16, 0x59, 0x75, 0x19, 0x15, 0x51, +0x0D, 0x1C, 0x5D, 0x43, 0x12, 0xAC, 0x16, 0x59, 0x75, 0x19, 0x15, 0x51, +0x14, 0xAC, 0x15, 0x59, 0xEB, 0x18, 0x13, 0x51, 0x01, 0x31, 0xC9, 0xB2, +0x04, 0x9F, 0xB9, 0x42, 0xAD, 0xDD, 0x69, 0x46, 0x08, 0x79, 0x05, 0x9C, +0xA0, 0x42, 0x9E, 0xDD, 0x65, 0x46, 0x00, 0x2D, 0x8C, 0xD1, 0x3B, 0x4C, +0x3B, 0x4E, 0x0A, 0x25, 0x67, 0x5F, 0x28, 0x25, 0x75, 0x5F, 0x14, 0x9E, +0x10, 0x98, 0x01, 0x96, 0x01, 0x99, 0x66, 0x68, 0x68, 0x43, 0x71, 0x43, +0xFF, 0xF7, 0x1C, 0xF8, 0x00, 0xB2, 0x38, 0x18, 0x02, 0x90, 0x15, 0x98, +0x00, 0x90, 0x00, 0x99, 0x11, 0x98, 0x71, 0x43, 0x68, 0x43, 0xFF, 0xF7, +0x11, 0xF8, 0x2F, 0x4A, 0x00, 0xB2, 0x08, 0x21, 0x66, 0x5E, 0x26, 0x25, +0x55, 0x5F, 0x24, 0x68, 0x00, 0x99, 0x3F, 0x18, 0x13, 0x98, 0x61, 0x43, +0x68, 0x43, 0xFF, 0xF7, 0x03, 0xF8, 0x00, 0xB2, 0x30, 0x18, 0x00, 0x90, +0x01, 0x99, 0x12, 0x98, 0x61, 0x43, 0x68, 0x43, 0xFE, 0xF7, 0xFA, 0xFF, +0x00, 0x9C, 0x00, 0xB2, 0x36, 0x18, 0xA6, 0x1B, 0x00, 0x2E, 0x02, 0xDD, +0x02, 0x9D, 0x7F, 0x1B, 0x02, 0xE0, 0x02, 0x9C, 0x76, 0x42, 0xE7, 0x1B, +0x3B, 0x1E, 0x30, 0xD0, 0x80, 0x23, 0x00, 0x2E, 0x29, 0xD0, 0xBE, 0x42, +0x2B, 0xD0, 0x79, 0x42, 0x8E, 0x42, 0x26, 0xD0, 0x73, 0x42, 0x1F, 0x4C, +0x9F, 0x42, 0x06, 0xDA, 0xB0, 0x01, 0xFE, 0xF7, 0xDD, 0xFF, 0x23, 0x5C, +0x01, 0x3B, 0xFF, 0x3B, 0x1D, 0xE0, 0x00, 0x2F, 0x06, 0xDA, 0x88, 0x01, +0x31, 0x1C, 0xFE, 0xF7, 0xD3, 0xFF, 0x23, 0x5C, 0x5B, 0x42, 0x14, 0xE0, +0xB7, 0x42, 0x05, 0xDA, 0xB8, 0x01, 0x31, 0x1C, 0xFE, 0xF7, 0xCA, 0xFF, +0x23, 0x5C, 0x0C, 0xE0, 0xB0, 0x01, 0x39, 0x1C, 0xFE, 0xF7, 0xC4, 0xFF, +0x80, 0x23, 0x22, 0x5C, 0x5B, 0x00, 0x9B, 0x1A, 0x03, 0xE0, 0x5B, 0x00, +0x01, 0xE0, 0x80, 0x23, 0x5B, 0x42, 0x2D, 0x20, 0x58, 0x43, 0x17, 0xB0, +0xC0, 0x11, 0x40, 0x42, 0xF0, 0xBD, 0xC0, 0x46, 0x24, 0x09, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x38, 0x0D, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, +0xF4, 0x59, 0x00, 0x00, 0xF0, 0x59, 0x00, 0x00, 0xEC, 0x02, 0x00, 0x20, +0x00, 0x40, 0x00, 0x40, 0xE8, 0x6F, 0x00, 0x00, 0xF0, 0xB5, 0x8F, 0xB0, +0x14, 0x28, 0x00, 0xD9, 0x93, 0xE2, 0xFE, 0xF7, 0x43, 0xFF, 0x15, 0x00, +0x92, 0x02, 0x23, 0x00, 0x92, 0x02, 0x2D, 0x00, 0x92, 0x02, 0x92, 0x02, +0x38, 0x00, 0x92, 0x02, 0xD2, 0x00, 0x92, 0x02, 0x92, 0x02, 0xD6, 0x00, +0x92, 0x02, 0xDF, 0x00, 0x4E, 0x02, 0x9C, 0x01, 0x92, 0x02, 0x92, 0x02, +0x79, 0x02, 0x8D, 0x02, 0xD3, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD0, +0x77, 0xE2, 0xD2, 0x4C, 0x01, 0x23, 0xF2, 0x20, 0x23, 0x72, 0xE0, 0x70, +0xFE, 0xF7, 0x12, 0xFE, 0x20, 0x70, 0x6E, 0xE2, 0xCE, 0x4B, 0x03, 0x22, +0x1A, 0x70, 0xCE, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0xCD, 0x4B, 0x00, 0x22, +0x1A, 0x61, 0x64, 0xE2, 0xCC, 0x49, 0x00, 0x23, 0x0A, 0x68, 0x9A, 0x42, +0x02, 0xDD, 0x4B, 0x68, 0xD3, 0x18, 0xDB, 0x0F, 0xC9, 0x4A, 0x13, 0x70, +0x59, 0xE2, 0xC6, 0x4B, 0x00, 0x22, 0x1A, 0x60, 0xC5, 0x4B, 0x06, 0x27, +0x08, 0x20, 0x1B, 0x5E, 0x22, 0x2B, 0x00, 0xDC, 0x03, 0x27, 0xF9, 0x0F, +0xC3, 0x4D, 0x1B, 0x24, 0x00, 0x26, 0x05, 0x91, 0x23, 0x1C, 0x40, 0x33, +0x5B, 0x00, 0x58, 0x5B, 0x23, 0x1C, 0x80, 0x33, 0x5B, 0x00, 0x5B, 0x5B, +0x00, 0xB2, 0x1B, 0xB2, 0xC0, 0x18, 0x23, 0x1C, 0xC0, 0x33, 0x5B, 0x00, +0x5B, 0x5B, 0xA0, 0x22, 0x1B, 0xB2, 0xC0, 0x18, 0x63, 0x1C, 0xFF, 0x33, +0x5B, 0x00, 0x5B, 0x5B, 0x52, 0x00, 0x1B, 0xB2, 0xC0, 0x18, 0xA3, 0x18, +0x5B, 0x00, 0x5B, 0x5B, 0xC0, 0x21, 0x1B, 0xB2, 0x49, 0x00, 0xC0, 0x18, +0x63, 0x18, 0x5B, 0x00, 0x5B, 0x5B, 0xE0, 0x22, 0x1B, 0xB2, 0x52, 0x00, +0xC0, 0x18, 0xA3, 0x18, 0x5B, 0x00, 0x5B, 0x5B, 0x80, 0x21, 0x1B, 0xB2, +0x89, 0x00, 0xC0, 0x18, 0x63, 0x18, 0x5B, 0x00, 0x5B, 0x5B, 0x90, 0x22, +0x1B, 0xB2, 0x92, 0x00, 0xC0, 0x18, 0xA3, 0x18, 0x5B, 0x00, 0x5B, 0x5B, +0xA0, 0x21, 0x1B, 0xB2, 0x89, 0x00, 0xC0, 0x18, 0x63, 0x18, 0x5B, 0x00, +0x5B, 0x5B, 0xB0, 0x22, 0x1B, 0xB2, 0x92, 0x00, 0xC0, 0x18, 0xA3, 0x18, +0x5B, 0x00, 0x5B, 0x5B, 0xC0, 0x21, 0x1B, 0xB2, 0x89, 0x00, 0xC0, 0x18, +0x63, 0x18, 0x5B, 0x00, 0x5B, 0x5B, 0xD0, 0x22, 0x92, 0x00, 0x1B, 0xB2, +0xC0, 0x18, 0xA3, 0x18, 0x5B, 0x00, 0x5B, 0x5B, 0xE0, 0x21, 0x1B, 0xB2, +0x89, 0x00, 0xC0, 0x18, 0x63, 0x18, 0x5B, 0x00, 0x5B, 0x5B, 0x0E, 0x21, +0x1B, 0xB2, 0xC0, 0x18, 0xFE, 0xF7, 0xF4, 0xFE, 0x40, 0x10, 0x04, 0x90, +0x0E, 0x22, 0x93, 0x01, 0x8F, 0x49, 0x1B, 0x19, 0x5B, 0x00, 0xC8, 0x5A, +0x04, 0x99, 0x40, 0x1A, 0x80, 0xB2, 0x03, 0x90, 0x0C, 0x21, 0x68, 0x46, +0x08, 0x5E, 0x02, 0x90, 0x00, 0x28, 0x0B, 0xDD, 0x58, 0x5B, 0x69, 0x46, +0x0C, 0x20, 0x41, 0x5A, 0x59, 0x53, 0x02, 0x98, 0x05, 0x99, 0xC3, 0x17, +0xB8, 0x42, 0x4B, 0x41, 0xF6, 0x18, 0x02, 0xE0, 0x00, 0x20, 0x59, 0x5B, +0x58, 0x53, 0x01, 0x3A, 0x00, 0x2A, 0xDE, 0xD1, 0x01, 0x3C, 0x01, 0x2C, +0x00, 0xD0, 0x77, 0xE7, 0x7A, 0x4B, 0x1E, 0x60, 0xBF, 0xE1, 0x7D, 0x4B, +0x00, 0x22, 0x1A, 0x60, 0xBB, 0xE1, 0x77, 0x4B, 0xDB, 0x68, 0x00, 0x2B, +0x00, 0xD0, 0xB6, 0xE1, 0x02, 0x20, 0xFF, 0xF7, 0xA5, 0xFC, 0xB2, 0xE1, +0x77, 0x4B, 0x04, 0x33, 0xDC, 0x7F, 0x71, 0x4B, 0x25, 0x1C, 0x1F, 0x68, +0x75, 0x4B, 0x1B, 0x68, 0x04, 0x93, 0x10, 0xE0, 0x01, 0x3D, 0xED, 0xB2, +0x0A, 0x26, 0x6E, 0x43, 0x72, 0x49, 0x8E, 0x19, 0x3C, 0x22, 0xB3, 0x5E, +0x38, 0x36, 0x00, 0x2B, 0x05, 0xD0, 0x30, 0x7A, 0x04, 0x99, 0x78, 0x43, +0xFE, 0xF7, 0xA2, 0xFE, 0x30, 0x72, 0x00, 0x2D, 0xEC, 0xD1, 0x6C, 0x4B, +0x1A, 0x78, 0x6C, 0x4B, 0x00, 0x2A, 0x02, 0xD0, 0x32, 0x33, 0x1D, 0x70, +0x92, 0xE0, 0x6A, 0x4A, 0x32, 0x33, 0x12, 0x78, 0x00, 0x2A, 0x04, 0xD0, +0x68, 0x4A, 0x32, 0x32, 0x12, 0x78, 0x1A, 0x70, 0x88, 0xE0, 0x67, 0x4A, +0x32, 0x32, 0x12, 0x78, 0x1A, 0x70, 0x83, 0xE0, 0x01, 0x3C, 0xE4, 0xB2, +0x0A, 0x23, 0x63, 0x43, 0x5D, 0x4A, 0xD3, 0x18, 0x3C, 0x20, 0x1B, 0x5E, +0x00, 0x2B, 0x7A, 0xD0, 0x63, 0x00, 0xD3, 0x18, 0x04, 0x21, 0x5B, 0x5E, +0x21, 0x1C, 0x10, 0x31, 0x07, 0x93, 0x49, 0x00, 0x8A, 0x5E, 0x29, 0x1C, +0x08, 0x92, 0x2C, 0x31, 0x09, 0x78, 0x00, 0x29, 0x13, 0xD0, 0x29, 0x1C, +0x07, 0x92, 0x08, 0x93, 0x2A, 0x31, 0x09, 0x78, 0x00, 0x29, 0x03, 0xD0, +0x28, 0x20, 0x29, 0x5E, 0x8A, 0x1A, 0x07, 0x92, 0x2A, 0x1C, 0x2B, 0x32, +0x12, 0x78, 0x00, 0x2A, 0x03, 0xD0, 0x26, 0x21, 0x6A, 0x5E, 0xD3, 0x1A, +0x08, 0x93, 0x0A, 0x23, 0x63, 0x43, 0x48, 0x48, 0x4D, 0x49, 0xC3, 0x18, +0x38, 0x33, 0x5B, 0x7A, 0xC9, 0x68, 0x5B, 0xB2, 0x01, 0x3B, 0x0D, 0xAA, +0x8B, 0x42, 0x00, 0xDA, 0x0B, 0x1C, 0x13, 0x70, 0x0A, 0x23, 0x63, 0x43, +0xC0, 0x18, 0x38, 0x30, 0x0A, 0x23, 0x45, 0x49, 0xC3, 0x56, 0x89, 0x68, +0x01, 0x33, 0x8B, 0x42, 0x00, 0xDD, 0x0B, 0x1C, 0x53, 0x70, 0x0A, 0x23, +0x63, 0x43, 0x3A, 0x48, 0x3F, 0x49, 0xC3, 0x18, 0x38, 0x33, 0xDB, 0x7A, +0x49, 0x68, 0x5B, 0xB2, 0x01, 0x3B, 0x0D, 0xAA, 0x8B, 0x42, 0x00, 0xDA, +0x0B, 0x1C, 0x93, 0x70, 0x0A, 0x23, 0x63, 0x43, 0xC0, 0x18, 0x38, 0x30, +0x0C, 0x23, 0x37, 0x49, 0xC3, 0x56, 0x09, 0x68, 0x01, 0x33, 0x8B, 0x42, +0x00, 0xDD, 0x0B, 0x1C, 0x0C, 0x27, 0x0B, 0xAE, 0x67, 0x43, 0xD3, 0x70, +0x09, 0xA8, 0x31, 0x1C, 0x0D, 0xAA, 0x07, 0xAB, 0x00, 0x94, 0xFF, 0xF7, +0x21, 0xFC, 0x2F, 0x4B, 0x09, 0x9A, 0xDF, 0x19, 0x7B, 0x1D, 0xFF, 0x33, +0x5A, 0x64, 0x0B, 0x9A, 0x0D, 0xA8, 0x1A, 0x64, 0x04, 0x22, 0x05, 0x23, +0xB2, 0x56, 0xF3, 0x56, 0x07, 0xA9, 0x00, 0x94, 0xFF, 0xF7, 0xBE, 0xFC, +0x41, 0x37, 0xFF, 0x37, 0x38, 0x70, 0x00, 0xE0, 0x1B, 0x4D, 0x00, 0x2C, +0x00, 0xD0, 0x77, 0xE7, 0xF5, 0xE0, 0x19, 0x4B, 0x04, 0x33, 0xDE, 0x7F, +0x85, 0xE0, 0x21, 0x4B, 0x01, 0x3E, 0x21, 0x4D, 0xF6, 0xB2, 0x9A, 0x57, +0x2B, 0x78, 0x9A, 0x42, 0x00, 0xDA, 0x7C, 0xE0, 0x0C, 0x20, 0x05, 0x1C, +0x75, 0x43, 0x1A, 0x4C, 0xC8, 0x21, 0x65, 0x19, 0x89, 0x00, 0x6B, 0x18, +0x1A, 0x78, 0x41, 0x35, 0xFF, 0x21, 0x69, 0x56, 0x57, 0xB2, 0x79, 0x1A, +0x0D, 0x1C, 0x5A, 0x35, 0x2C, 0xDA, 0x4C, 0x3A, 0x1A, 0x70, 0x2D, 0xE0, +0xE5, 0x01, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, 0x55, 0x00, 0x00, 0x20, +0x54, 0x00, 0x00, 0x20, 0xF8, 0x08, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, +0x3D, 0x11, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x38, 0x0D, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x4C, 0x11, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0xF5, 0x00, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, +0x9A, 0x74, 0x00, 0x00, 0x4A, 0x74, 0x00, 0x00, 0xE4, 0x10, 0x00, 0x20, +0xEC, 0x11, 0x00, 0x20, 0x3E, 0x11, 0x00, 0x20, 0x7A, 0x0D, 0x00, 0x20, +0x5A, 0x29, 0x01, 0xDD, 0x4C, 0x32, 0x1A, 0x70, 0x70, 0x43, 0x24, 0x18, +0xC8, 0x20, 0x80, 0x00, 0x23, 0x18, 0x41, 0x34, 0xFF, 0x34, 0x00, 0x20, +0x00, 0x21, 0x18, 0x56, 0x61, 0x56, 0x5A, 0x22, 0xFB, 0xF7, 0xEE, 0xFD, +0xC0, 0xB2, 0x43, 0xB2, 0x19, 0x1C, 0x20, 0x70, 0x5A, 0x31, 0x02, 0xDA, +0x4C, 0x38, 0x20, 0x70, 0x03, 0xE0, 0x5A, 0x2B, 0x01, 0xDD, 0x4C, 0x30, +0x20, 0x70, 0x0C, 0x23, 0x73, 0x43, 0x46, 0x4A, 0xD3, 0x18, 0x5C, 0x1D, +0xFF, 0x34, 0x62, 0x6C, 0x1D, 0x1C, 0xFC, 0x35, 0xA9, 0x6C, 0x52, 0x12, +0x62, 0x64, 0xC9, 0x22, 0x49, 0x12, 0x92, 0x00, 0xA9, 0x64, 0x1F, 0x1C, +0x9B, 0x18, 0x18, 0x68, 0x1E, 0x22, 0xFB, 0xF7, 0xCB, 0xFD, 0xC8, 0x23, +0x9B, 0x00, 0x08, 0x37, 0xA8, 0x64, 0x61, 0x6C, 0xF8, 0x58, 0x1E, 0x22, +0xFB, 0xF7, 0xC2, 0xFD, 0x60, 0x64, 0x00, 0x2E, 0x00, 0xD0, 0x76, 0xE7, +0x35, 0x4C, 0xC8, 0x23, 0xA0, 0x25, 0x9B, 0x00, 0x6D, 0x00, 0xE0, 0x18, +0x61, 0x19, 0x78, 0x22, 0xFE, 0xF7, 0xCA, 0xFD, 0x31, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x5A, 0xD1, 0x30, 0x4A, 0x13, 0x68, 0x01, 0x2B, 0x0D, 0xD1, +0xFC, 0x34, 0xA1, 0x6C, 0x95, 0x29, 0x52, 0xDD, 0xE1, 0x6C, 0x1E, 0x29, +0x4F, 0xDC, 0x40, 0x32, 0x12, 0x78, 0x1D, 0x2A, 0x4B, 0xD9, 0x2A, 0x4A, +0x13, 0x70, 0x48, 0xE0, 0x00, 0x2B, 0x46, 0xD1, 0x27, 0x4B, 0x1E, 0x70, +0x43, 0xE0, 0x27, 0x4B, 0x23, 0x49, 0x5A, 0x68, 0x01, 0x2A, 0x0C, 0xD1, +0x9A, 0x68, 0x01, 0x2A, 0x17, 0xD1, 0x0A, 0x70, 0x00, 0x21, 0x99, 0x60, +0x22, 0x49, 0xDA, 0x60, 0x34, 0x31, 0x0A, 0x70, 0x21, 0x49, 0x0A, 0x70, +0x0D, 0xE0, 0x00, 0x2A, 0x0B, 0xD1, 0x98, 0x68, 0x01, 0x28, 0x08, 0xD1, +0x0A, 0x70, 0x1C, 0x49, 0x02, 0x20, 0x34, 0x31, 0x0A, 0x70, 0x1B, 0x49, +0x9A, 0x60, 0x08, 0x70, 0xDA, 0x60, 0x14, 0x4B, 0x1A, 0x78, 0x19, 0x4B, +0x01, 0x2A, 0x02, 0xD1, 0x02, 0x22, 0x1A, 0x70, 0x1B, 0xE0, 0x01, 0x22, +0x1A, 0x70, 0x18, 0xE0, 0x15, 0x4B, 0x04, 0x22, 0x9A, 0x70, 0x87, 0x22, +0x52, 0x00, 0x9A, 0x80, 0x20, 0x22, 0x9A, 0x71, 0x05, 0x22, 0x01, 0x21, +0xDA, 0x71, 0x9A, 0x73, 0x0F, 0x22, 0x19, 0x72, 0xDA, 0x73, 0x03, 0x21, +0x00, 0x22, 0x59, 0x72, 0x1A, 0x70, 0x04, 0xE0, 0x0B, 0x48, 0x0C, 0x49, +0x50, 0x22, 0xFE, 0xF7, 0x6B, 0xFD, 0x0F, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, +0xEC, 0x11, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0xF5, 0x00, 0x00, 0x20, 0xF8, 0x08, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0xB3, 0x01, 0x00, 0x20, 0x40, 0x00, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x4A, 0x74, 0x00, 0x00, 0x38, 0xB5, 0x50, 0x28, 0x05, 0xD1, 0x3B, 0x4B, +0x01, 0x20, 0x18, 0x60, 0xFE, 0xF7, 0x28, 0xFF, 0x6F, 0xE0, 0x39, 0x4B, +0x40, 0x28, 0x01, 0xD1, 0x01, 0x24, 0x1C, 0x70, 0x1B, 0x78, 0x00, 0x2B, +0x67, 0xD0, 0x41, 0x38, 0x0E, 0x28, 0x64, 0xD8, 0xFE, 0xF7, 0x7A, 0xFC, +0x08, 0x12, 0x08, 0x2D, 0x08, 0x47, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, +0x63, 0x63, 0x5E, 0x00, 0x2F, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x2F, 0x4B, +0x1A, 0x80, 0x2F, 0x4A, 0x13, 0x60, 0xFC, 0xF7, 0x67, 0xFB, 0x50, 0xE0, +0x2A, 0x48, 0x2C, 0x4B, 0xFF, 0x2A, 0x0B, 0xD1, 0x2B, 0x4A, 0xC9, 0x01, +0x12, 0x78, 0x52, 0x00, 0xD2, 0xB2, 0x02, 0x70, 0x29, 0x4A, 0x89, 0x18, +0x19, 0x60, 0xFC, 0xF7, 0x57, 0xFB, 0x40, 0xE0, 0x89, 0x01, 0x8A, 0x18, +0x25, 0x49, 0x52, 0x00, 0x02, 0x24, 0x52, 0x18, 0x04, 0x70, 0x1A, 0x60, +0xFC, 0xF7, 0x4C, 0xFB, 0x35, 0xE0, 0x1D, 0x4C, 0x1E, 0x4B, 0x21, 0x48, +0xFF, 0x2A, 0x0A, 0xD1, 0x1D, 0x4A, 0x89, 0x01, 0x12, 0x78, 0x40, 0x18, +0x52, 0x00, 0xD2, 0xB2, 0x22, 0x70, 0x18, 0x60, 0xFC, 0xF7, 0x3C, 0xFB, +0x25, 0xE0, 0x49, 0x01, 0x52, 0x18, 0x52, 0x00, 0x02, 0x25, 0x80, 0x18, +0x25, 0x70, 0x18, 0x60, 0xFC, 0xF7, 0x32, 0xFB, 0x1B, 0xE0, 0x10, 0x4C, +0x11, 0x4B, 0x15, 0x48, 0xFF, 0x2A, 0x08, 0xD1, 0x10, 0x4A, 0x49, 0x01, +0x92, 0x78, 0x40, 0x18, 0x22, 0x70, 0x18, 0x60, 0xFC, 0xF7, 0x24, 0xFB, +0x0D, 0xE0, 0x49, 0x01, 0x52, 0x18, 0x01, 0x25, 0x80, 0x18, 0x25, 0x70, +0x18, 0x60, 0xFC, 0xF7, 0x1B, 0xFB, 0x04, 0xE0, 0x0B, 0x4A, 0x00, 0x23, +0x13, 0x70, 0x02, 0x4A, 0x13, 0x70, 0x38, 0xBD, 0x50, 0x11, 0x00, 0x20, +0xE5, 0x01, 0x00, 0x20, 0xF6, 0x03, 0x00, 0x20, 0x08, 0x03, 0x00, 0x20, +0x34, 0x0D, 0x00, 0x20, 0x0A, 0x03, 0x00, 0x20, 0x84, 0x40, 0x00, 0x40, +0xF8, 0x03, 0x00, 0x20, 0xB3, 0x0A, 0x00, 0x20, 0x1D, 0x03, 0x00, 0x20, +0x08, 0xB5, 0x3C, 0x4B, 0x1B, 0x88, 0x30, 0x2B, 0x16, 0xD0, 0x06, 0xD8, +0x09, 0x2B, 0x26, 0xD0, 0x0A, 0x2B, 0x3B, 0xD0, 0x01, 0x2B, 0x6B, 0xD1, +0x06, 0xE0, 0xA0, 0x2B, 0x40, 0xD0, 0xB0, 0x2B, 0x5A, 0xD0, 0x5F, 0x2B, +0x64, 0xD1, 0x4D, 0xE0, 0x33, 0x4A, 0x11, 0x78, 0x0E, 0x22, 0x11, 0x42, +0x5E, 0xD1, 0x32, 0x4A, 0x13, 0x70, 0x5B, 0xE0, 0x2F, 0x4B, 0x31, 0x4A, +0x1B, 0x78, 0x12, 0x78, 0x01, 0x2B, 0x05, 0xD1, 0x00, 0x2A, 0x53, 0xD1, +0x2E, 0x4A, 0x53, 0x60, 0x93, 0x60, 0x4F, 0xE0, 0x01, 0x2A, 0x4D, 0xD1, +0x2B, 0x4B, 0x00, 0x21, 0x59, 0x60, 0x9A, 0x60, 0x48, 0xE0, 0x2A, 0x4B, +0x34, 0x33, 0x1B, 0x78, 0x00, 0x2B, 0x43, 0xD0, 0x23, 0x4B, 0x1B, 0x78, +0x01, 0x2B, 0x05, 0xD1, 0x26, 0x4A, 0x13, 0x70, 0x22, 0x4B, 0x00, 0x22, +0x1A, 0x70, 0x39, 0xE0, 0x02, 0x2B, 0x37, 0xD1, 0x22, 0x4A, 0x01, 0x23, +0x13, 0x70, 0x1E, 0x4A, 0x13, 0x70, 0x31, 0xE0, 0x20, 0x4B, 0x1A, 0x78, +0x00, 0x2A, 0x02, 0xD1, 0x01, 0x22, 0x1A, 0x70, 0x2A, 0xE0, 0x00, 0x22, +0x1A, 0x70, 0x27, 0xE0, 0x15, 0x4B, 0x1C, 0x4A, 0x18, 0x78, 0x1C, 0x4B, +0x1A, 0x28, 0x06, 0xD1, 0x19, 0x78, 0x1B, 0x4B, 0x10, 0x78, 0x1A, 0x78, +0xFF, 0xF7, 0xAA, 0xF8, 0x1A, 0xE0, 0x11, 0x78, 0x1A, 0x78, 0xFF, 0xF7, +0x11, 0xFF, 0x15, 0xE0, 0x0C, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x11, 0xD0, +0x14, 0x4B, 0x08, 0x22, 0x1A, 0x60, 0xFA, 0xF7, 0x0F, 0xFD, 0x0B, 0xE0, +0x07, 0x4B, 0x1B, 0x78, 0x1A, 0x2B, 0x07, 0xD1, 0x0C, 0x4B, 0x18, 0x78, +0x0C, 0x4B, 0x19, 0x78, 0x0C, 0x4B, 0x1A, 0x78, 0xFF, 0xF7, 0x8E, 0xF8, +0x08, 0xBD, 0xC0, 0x46, 0x28, 0x00, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x50, +0xE8, 0x01, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, 0xF8, 0x08, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0xDC, 0x01, 0x00, 0x20, 0xDF, 0x01, 0x00, 0x20, +0x0E, 0x00, 0x00, 0x50, 0x0D, 0x00, 0x00, 0x50, 0x10, 0x00, 0x00, 0x50, +0x50, 0x11, 0x00, 0x20, 0x00, 0x03, 0x06, 0x09, 0x0D, 0x10, 0x13, 0x16, +0x19, 0x1C, 0x1F, 0x22, 0x25, 0x28, 0x2A, 0x2D, 0x30, 0x33, 0x35, 0x38, +0x3A, 0x3D, 0x3F, 0x42, 0x44, 0x46, 0x49, 0x4B, 0x4D, 0x4F, 0x51, 0x53, +0x55, 0x57, 0x59, 0x5B, 0x5D, 0x5E, 0x60, 0x62, 0x63, 0x65, 0x66, 0x68, +0x69, 0x6B, 0x6C, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, +0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x04, 0x4D, 0x31, 0x48, 0x30, +0x50, 0x42, 0x34, 0x35, 0x25, 0x44, 0x01, 0x34, 0x38, 0x30, 0x47, 0x59, +0x30, 0x31, 0x00, 0x00, 0x00, 0x48, 0x10, 0x5A, 0x1E, 0x0A, 0x01, 0x01, +0x00, 0x00, 0x00, 0x1A, 0x0E, 0x00, 0x00, 0x1A, 0x0E, 0x00, 0x00, 0x00, +0x01, 0x01, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x05, 0xD0, 0x02, 0x00, 0x00, +0x00, 0x01, 0x01, 0x50, 0x50, 0x50, 0x01, 0x01, 0x00, 0x00, 0x66, 0x00, +0x3A, 0x00, 0x23, 0x00, 0x04, 0x03, 0x32, 0x32, 0x10, 0x00, 0x01, 0x01, +0x04, 0x00, 0xC2, 0x01, 0x18, 0x03, 0x02, 0x03, 0x00, 0x00, 0x00, 0x04, +0x05, 0x0F, 0x00, 0x07, 0x04, 0x00, 0x6A, 0xFF, 0x14, 0x19, 0x0A, 0xF6, +0x0A, 0xF6, 0x07, 0x23, 0x1E, 0x00, 0x00, 0x80, 0x6A, 0x02, 0x00, 0x00, +0x1E, 0x00, 0x19, 0x00, 0x0F, 0x0A, 0x3C, 0x01, 0x2D, 0x00, 0x1E, 0x00, +0x02, 0x01, 0x01, 0x14, 0x32, 0x00, 0x32, 0x00, 0xFF, 0x7F, 0x01, 0x01, +0x01, 0x07, 0x0A, 0x00, 0x32, 0x00, 0x0A, 0x05, 0x49, 0x04, 0xC7, 0x00, +0xFF, 0x7F, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0xF4, 0x01, +0x2A, 0x03, 0x06, 0x01, 0x00, 0x00, 0x00, 0x04, 0x05, 0x0F, 0x00, 0x08, +0x04, 0x00, 0xD4, 0xFE, 0x14, 0x1E, 0x0A, 0xF6, 0x0C, 0xF6, 0x08, 0x23, +0x1E, 0x00, 0x00, 0x80, 0xAE, 0x02, 0x00, 0x00, 0x32, 0x00, 0x28, 0x00, +0x0F, 0x0A, 0x3C, 0x01, 0x2D, 0x00, 0x1E, 0x00, 0x02, 0x01, 0x01, 0x14, +0x96, 0x00, 0x64, 0x00, 0xFF, 0x7F, 0x01, 0x01, 0x01, 0x07, 0x0A, 0x00, +0x32, 0x00, 0x0A, 0x05, 0x1C, 0x03, 0x90, 0x00, 0xFF, 0x7F, 0x00, 0x80, +0x19, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0A, 0x0B, 0x0C, +0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x19, 0x1A, 0x1B, +0x1C, 0x1D, 0x1E, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, +0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x08, 0x08, 0x08, 0x07, 0x07, +0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, +0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x08, 0x08, 0x07, +0x07, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, +0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x08, +0x08, 0x07, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x04, 0x04, +0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x09, 0x08, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, +0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, +0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x08, 0x08, 0x07, 0x07, 0x07, 0x06, 0x06, 0x05, 0x05, 0x05, +0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, +0x03, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x05, +0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, +0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x07, 0x07, 0x06, 0x06, +0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, +0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x07, 0x06, +0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, +0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, +0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x03, +0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x07, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, +0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, +0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x07, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, +0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, +0x03, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x04, +0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, +0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, +0x05, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, +0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x06, 0x05, +0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, +0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x04, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x3F, +0x42, 0x42, 0x47, 0x46, 0x4B, 0x4B, 0x4A, 0x4D, 0x4A, 0x4A, 0x4B, 0x4E, +0x50, 0x4E, 0x50, 0x50, 0x52, 0x50, 0x52, 0x57, 0x55, 0x59, 0x59, 0x49, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3B, 0x3E, 0x3F, 0x40, 0x41, +0x41, 0x42, 0x45, 0x43, 0x45, 0x46, 0x47, 0x48, 0x48, 0x4A, 0x48, 0x4A, +0x48, 0x4B, 0x4E, 0x4E, 0x4E, 0x4E, 0x52, 0x4E, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x40, 0x3A, 0x3C, 0x3D, 0x3F, 0x3F, 0x42, 0x41, 0x43, 0x43, +0x43, 0x46, 0x46, 0x45, 0x46, 0x46, 0x48, 0x48, 0x4A, 0x4A, 0x4A, 0x4D, +0x4D, 0x4E, 0x52, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x38, +0x3D, 0x3F, 0x40, 0x40, 0x42, 0x3F, 0x42, 0x43, 0x43, 0x43, 0x45, 0x46, +0x45, 0x47, 0x47, 0x46, 0x46, 0x48, 0x4B, 0x4A, 0x4D, 0x4E, 0x50, 0x50, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3B, 0x3D, 0x3A, 0x3E, 0x40, +0x41, 0x42, 0x42, 0x43, 0x45, 0x46, 0x45, 0x46, 0x47, 0x48, 0x46, 0x47, +0x4B, 0x4A, 0x4D, 0x4E, 0x4D, 0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x42, 0x3B, 0x3C, 0x3C, 0x3E, 0x3E, 0x3E, 0x41, 0x42, 0x41, +0x42, 0x43, 0x45, 0x45, 0x46, 0x46, 0x45, 0x47, 0x4A, 0x48, 0x4A, 0x4E, +0x4D, 0x4D, 0x4D, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x3A, +0x3C, 0x3B, 0x3E, 0x3D, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x43, 0x47, 0x45, +0x43, 0x45, 0x47, 0x45, 0x46, 0x4A, 0x47, 0x4A, 0x4A, 0x4E, 0x4B, 0x4B, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x39, 0x3C, 0x3E, 0x3D, 0x40, +0x3F, 0x40, 0x42, 0x42, 0x42, 0x42, 0x43, 0x45, 0x45, 0x47, 0x47, 0x47, +0x46, 0x4A, 0x4A, 0x4A, 0x4B, 0x4D, 0x4D, 0x53, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x40, 0x3A, 0x3A, 0x3B, 0x3D, 0x3D, 0x3F, 0x3E, 0x3F, 0x41, +0x40, 0x42, 0x43, 0x45, 0x45, 0x43, 0x45, 0x46, 0x46, 0x48, 0x47, 0x46, +0x48, 0x4B, 0x4B, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3A, +0x3C, 0x3E, 0x3D, 0x3D, 0x40, 0x3F, 0x3F, 0x41, 0x41, 0x42, 0x42, 0x45, +0x45, 0x46, 0x45, 0x46, 0x43, 0x47, 0x48, 0x48, 0x4A, 0x4A, 0x4A, 0x4E, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3A, 0x3D, 0x3E, 0x3F, 0x3E, +0x40, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x43, 0x45, 0x43, 0x45, 0x45, 0x43, +0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x4B, 0x4B, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x40, 0x3B, 0x3D, 0x3E, 0x3E, 0x3E, 0x3E, 0x40, 0x41, 0x43, +0x43, 0x45, 0x42, 0x43, 0x45, 0x46, 0x45, 0x45, 0x46, 0x47, 0x46, 0x47, +0x47, 0x4A, 0x4A, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3A, +0x3D, 0x3C, 0x3E, 0x3D, 0x3F, 0x40, 0x40, 0x42, 0x42, 0x45, 0x42, 0x41, +0x43, 0x48, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4B, 0x4B, 0x49, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x41, 0x45, 0x42, 0x46, 0x46, +0x45, 0x47, 0x48, 0x4B, 0x4A, 0x4A, 0x4A, 0x4E, 0x4E, 0x4D, 0x4E, 0x4E, +0x4E, 0x50, 0x50, 0x50, 0x50, 0x52, 0x55, 0x58, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x45, 0x04, +}; + diff --git a/drivers/input/touchscreen/d2_fw.h b/drivers/input/touchscreen/d2_fw.h new file mode 100644 index 00000000000..99533f75c15 --- /dev/null +++ b/drivers/input/touchscreen/d2_fw.h @@ -0,0 +1,2664 @@ +/* + * d2_fw.h - Touchscreen Firmware for Melfas MMS-series touch controllers + * + * ISP reflashing code based on original code from Melfas. + * + * 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. + * + */ + +const size_t MELFAS_binary_nLength = 0x7C00; + +const u8 MELFAS_binary[] = { +0x00, 0x20, 0x00, 0x20, 0x79, 0x02, 0x00, 0x00, 0x39, 0x02, 0x00, 0x00, +0x3D, 0x02, 0x00, 0x00, 0x41, 0x02, 0x00, 0x00, 0x45, 0x02, 0x00, 0x00, +0x49, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x02, 0x00, 0x00, +0x51, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x02, 0x00, 0x00, +0x59, 0x02, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00, +0x25, 0x01, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x35, 0x02, 0x00, 0x00, +0x71, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, +0x30, 0xB5, 0x11, 0x4B, 0x11, 0x4A, 0x1B, 0x88, 0x12, 0x78, 0xD3, 0x18, +0xDB, 0xB2, 0xE1, 0x2B, 0x02, 0xD0, 0xE5, 0x2B, 0x17, 0xD1, 0x09, 0xE0, +0x0D, 0x49, 0x0E, 0x4A, 0x04, 0x23, 0x01, 0x3B, 0xDB, 0xB2, 0xC8, 0x5C, +0x98, 0x54, 0x00, 0x2B, 0xF9, 0xD1, 0x0C, 0xE0, 0x0A, 0x4C, 0x09, 0x48, +0x0A, 0x49, 0x0B, 0x4A, 0x04, 0x23, 0x01, 0x3B, 0xDB, 0xB2, 0xE5, 0x5C, +0x1D, 0x54, 0xCD, 0x5C, 0x9D, 0x54, 0x00, 0x2B, 0xF7, 0xD1, 0x30, 0xBD, +0x28, 0x00, 0x00, 0x20, 0x2A, 0x00, 0x00, 0x20, 0x2D, 0x00, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x50, 0x35, 0x00, 0x00, 0x20, 0x31, 0x00, 0x00, 0x20, +0x10, 0x00, 0x00, 0x50, 0x03, 0x4A, 0x00, 0x23, 0x13, 0x70, 0x80, 0x22, +0xD2, 0x05, 0x13, 0x70, 0x70, 0x47, 0xC0, 0x46, 0x00, 0x00, 0x00, 0x20, +0x06, 0x4B, 0x00, 0x22, 0x5A, 0x70, 0x80, 0x23, 0xDB, 0x05, 0x59, 0x69, +0x04, 0x4A, 0x0A, 0x40, 0x5A, 0x61, 0x59, 0x69, 0x03, 0x4A, 0x0A, 0x40, +0x5A, 0x61, 0x70, 0x47, 0x00, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xFE, +0xFF, 0xFF, 0xFF, 0xEF, 0x70, 0xB5, 0xA0, 0x23, 0xDB, 0x05, 0x1C, 0x7A, +0x24, 0x4D, 0x0F, 0x22, 0x14, 0x40, 0x2A, 0x78, 0x23, 0x4E, 0x00, 0x2A, +0x06, 0xD0, 0x23, 0x4B, 0x1B, 0x68, 0x98, 0x47, 0x00, 0x23, 0x2B, 0x70, +0x34, 0x70, 0x3A, 0xE0, 0x9B, 0x7A, 0x32, 0x78, 0xE1, 0x07, 0x02, 0xD5, +0x1E, 0x4A, 0x13, 0x80, 0x07, 0xE0, 0x08, 0x21, 0x0C, 0x42, 0x0A, 0xD0, +0x1C, 0x4B, 0x1A, 0x78, 0x52, 0x18, 0xD2, 0xB2, 0x1A, 0x70, 0xFF, 0xF7, +0x8D, 0xFF, 0x1A, 0x4B, 0x1B, 0x68, 0x98, 0x47, 0x19, 0xE0, 0xA1, 0x07, +0x0D, 0xD5, 0x08, 0x2A, 0x01, 0xD0, 0x01, 0x2A, 0x01, 0xD1, 0x16, 0x4B, +0x02, 0xE0, 0x12, 0x4A, 0x13, 0x80, 0x15, 0x4B, 0x1B, 0x68, 0x98, 0x47, +0x00, 0x22, 0x10, 0x4B, 0x08, 0xE0, 0x63, 0x07, 0x07, 0xD5, 0x11, 0x4B, +0x1B, 0x68, 0x98, 0x47, 0x0C, 0x4B, 0x1A, 0x78, 0x08, 0x32, 0xD2, 0xB2, +0x1A, 0x70, 0x07, 0x4B, 0x01, 0x22, 0x1C, 0x70, 0xA0, 0x23, 0xDB, 0x05, +0x1A, 0x72, 0x0B, 0x49, 0x10, 0x22, 0x1A, 0x72, 0x00, 0x22, 0x0A, 0x70, +0x1A, 0x72, 0x70, 0xBD, 0x2C, 0x00, 0x00, 0x20, 0x2B, 0x00, 0x00, 0x20, +0x24, 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, 0x20, 0x2A, 0x00, 0x00, 0x20, +0x1C, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x20, 0x03, 0x4A, 0x00, 0x23, 0x93, 0x70, 0x80, 0x22, +0xD2, 0x05, 0x53, 0x70, 0x70, 0x47, 0xC0, 0x46, 0x00, 0x00, 0x00, 0x20, +0x70, 0x47, 0xC0, 0x46, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, +0x00, 0xB5, 0xFE, 0xE7, 0x00, 0xB5, 0xFE, 0xE7, 0x38, 0xB5, 0x80, 0x23, +0xDB, 0x05, 0xFB, 0x21, 0x5A, 0x68, 0x59, 0x60, 0x99, 0x68, 0x08, 0x21, +0x99, 0x60, 0x00, 0x22, 0xD9, 0x68, 0xDA, 0x60, 0x19, 0x6C, 0x80, 0x21, +0xC9, 0x01, 0x19, 0x64, 0x19, 0x69, 0x44, 0x49, 0x19, 0x61, 0x44, 0x4B, +0x44, 0x49, 0x00, 0xE0, 0x04, 0xC3, 0x8B, 0x42, 0xFC, 0xD3, 0x43, 0x4B, +0x43, 0x4A, 0x9B, 0x0A, 0xDB, 0xB2, 0x13, 0x70, 0x42, 0x4B, 0x43, 0x49, +0x1B, 0x68, 0x9B, 0x0A, 0xDB, 0xB2, 0x53, 0x70, 0x41, 0x4B, 0x1B, 0x68, +0x9B, 0x0A, 0xDB, 0xB2, 0x93, 0x70, 0x40, 0x4B, 0x1B, 0x68, 0x9B, 0x0A, +0xDB, 0xB2, 0xD3, 0x70, 0x00, 0x23, 0x0B, 0x70, 0x03, 0x23, 0x08, 0xE0, +0x58, 0x1C, 0x15, 0x5C, 0xD4, 0x5C, 0xA5, 0x42, 0x07, 0xD9, 0xD4, 0x5C, +0x01, 0x34, 0xE4, 0xB2, 0x0C, 0x54, 0x01, 0x3B, 0xDB, 0xB2, 0xFF, 0x2B, +0xF2, 0xD1, 0x30, 0x4A, 0x11, 0x78, 0x35, 0x4A, 0x11, 0x70, 0x11, 0x1C, +0xFF, 0x2B, 0x03, 0xD1, 0x2D, 0x4B, 0xDB, 0x78, 0x1E, 0x2B, 0x04, 0xD9, +0xFF, 0x23, 0x4B, 0x70, 0x8B, 0x70, 0xCB, 0x70, 0x0B, 0xE0, 0x2A, 0x4B, +0x1B, 0x68, 0x1B, 0x78, 0x53, 0x70, 0x2A, 0x4B, 0x1B, 0x68, 0x1B, 0x78, +0x93, 0x70, 0x29, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0xD3, 0x70, 0x28, 0x4B, +0xDA, 0x78, 0xFF, 0x2A, 0x08, 0xD0, 0x9A, 0x78, 0xFF, 0x2A, 0x05, 0xD0, +0x5B, 0x78, 0xFF, 0x2B, 0x02, 0xD0, 0x00, 0xF0, 0x67, 0xF8, 0x38, 0xBD, +0x22, 0x4B, 0x23, 0x4A, 0xC0, 0x21, 0x13, 0x60, 0x22, 0x4A, 0x49, 0x00, +0x13, 0x60, 0x22, 0x4A, 0x22, 0x48, 0x13, 0x60, 0x22, 0x4A, 0x13, 0x60, +0x22, 0x4B, 0x02, 0x22, 0x5A, 0x50, 0xC0, 0x21, 0x91, 0x40, 0x5C, 0x58, +0x20, 0x40, 0x58, 0x50, 0x1F, 0x49, 0x04, 0x24, 0x08, 0x69, 0x20, 0x43, +0x08, 0x61, 0x62, 0xB6, 0x1A, 0x60, 0x80, 0x23, 0xDB, 0x05, 0x1A, 0x6C, +0x80, 0x22, 0x12, 0x02, 0x1A, 0x64, 0x1A, 0x6C, 0x80, 0x22, 0xD2, 0x01, +0x1A, 0x64, 0x9A, 0x68, 0x80, 0x22, 0x52, 0x00, 0x9A, 0x60, 0xA0, 0x22, +0xD2, 0x05, 0x91, 0x68, 0x14, 0x49, 0x91, 0x60, 0x1A, 0x6C, 0x00, 0x22, +0x1A, 0x64, 0xFE, 0xE7, 0x10, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, +0x3C, 0x00, 0x00, 0x20, 0xFF, 0x03, 0x00, 0x00, 0x31, 0x00, 0x00, 0x20, +0x08, 0x04, 0x00, 0x00, 0x35, 0x00, 0x00, 0x20, 0x0C, 0x04, 0x00, 0x00, +0x10, 0x04, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x20, 0xF9, 0x03, 0x00, 0x00, +0x24, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x20, 0x1C, 0x00, 0x00, 0x20, +0xFF, 0x00, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x20, 0x00, 0xE1, 0x00, 0xE0, +0x00, 0xED, 0x00, 0xE0, 0x00, 0x00, 0xC8, 0x42, 0x70, 0x47, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x4D, 0x31, 0x48, 0x30, 0x43, 0x4F, 0x34, 0x35, +0xFF, 0x5B, 0x00, 0x00, 0xFF, 0x73, 0x00, 0x00, 0xFF, 0x7B, 0x00, 0x00, +0xF7, 0xB5, 0x03, 0xF0, 0xC3, 0xFC, 0x05, 0xF0, 0x33, 0xF8, 0x00, 0x20, +0x05, 0xF0, 0xF2, 0xFB, 0x4E, 0x4B, 0x33, 0x33, 0x1B, 0x78, 0x5E, 0x42, +0x73, 0x41, 0x10, 0x26, 0xF6, 0x1A, 0x4C, 0x4B, 0x1E, 0x70, 0x4C, 0x4B, +0x1A, 0x68, 0x01, 0x3A, 0x53, 0x42, 0x5A, 0x41, 0x4A, 0x4B, 0x1A, 0x70, +0x4A, 0x4B, 0x1C, 0x78, 0x00, 0x2C, 0x22, 0xD1, 0x49, 0x4A, 0x01, 0x25, +0x14, 0x70, 0x1D, 0x70, 0x00, 0xF0, 0x52, 0xFA, 0x47, 0x4B, 0x28, 0x1C, +0xDA, 0x78, 0x9A, 0x70, 0x5C, 0x70, 0x05, 0xF0, 0xD1, 0xFB, 0x03, 0xF0, +0x7F, 0xFB, 0x01, 0xF0, 0x17, 0xFB, 0x80, 0x23, 0xDB, 0x05, 0x1A, 0x6C, +0x7F, 0x21, 0x8A, 0x43, 0x1A, 0x64, 0x00, 0xF0, 0xF5, 0xFD, 0x02, 0xF0, +0x4B, 0xFF, 0x01, 0xF0, 0x0B, 0xFB, 0x01, 0xF0, 0xA3, 0xFA, 0x3C, 0x4B, +0x02, 0x20, 0x1B, 0x68, 0x98, 0x47, 0x3B, 0x4C, 0x23, 0x78, 0x00, 0x2B, +0x03, 0xD1, 0x3A, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x0F, 0xD0, 0x23, 0x78, +0x00, 0xF0, 0x94, 0xFC, 0x22, 0x78, 0x2E, 0x4B, 0x00, 0x2A, 0x01, 0xD0, +0x1E, 0x70, 0x01, 0xE0, 0x0D, 0x22, 0x1A, 0x70, 0x31, 0x4A, 0x00, 0x23, +0x13, 0x70, 0x31, 0x4A, 0x13, 0x70, 0x2C, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x2C, 0xD0, 0x2F, 0x4D, 0x2B, 0x78, 0x00, 0x2B, 0x28, 0xD0, 0x2A, 0x4C, +0x13, 0x20, 0x23, 0x68, 0x98, 0x47, 0x00, 0xF0, 0x0F, 0xFA, 0x03, 0xF0, +0x08, 0xFB, 0x03, 0xF0, 0x8B, 0xFA, 0x29, 0x4B, 0x18, 0x78, 0x01, 0xF0, +0xA1, 0xF8, 0x00, 0xF0, 0xC7, 0xFD, 0x27, 0x4A, 0x01, 0x23, 0x13, 0x70, +0x26, 0x4A, 0x13, 0x80, 0x02, 0xF0, 0xDE, 0xFF, 0x2B, 0x78, 0x00, 0x2B, +0xFC, 0xD1, 0x23, 0x68, 0x14, 0x20, 0x98, 0x47, 0x00, 0xF0, 0xF6, 0xF9, +0x03, 0xF0, 0xEF, 0xFA, 0x03, 0xF0, 0x72, 0xFA, 0x1C, 0x4B, 0x18, 0x78, +0x01, 0xF0, 0x88, 0xF8, 0x10, 0x4B, 0x1E, 0x70, 0x00, 0xF0, 0x7E, 0xFF, +0x0E, 0x4C, 0x27, 0x78, 0x78, 0xB2, 0x13, 0x28, 0x00, 0xD9, 0x8D, 0xE1, +0x05, 0xF0, 0xD4, 0xF8, 0x74, 0x00, 0x8C, 0x01, 0x78, 0x01, 0x8C, 0x01, +0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, +0x8C, 0x01, 0x8C, 0x01, 0x8C, 0x01, 0x68, 0x00, 0x8C, 0x01, 0x3A, 0x00, +0x30, 0x00, 0x5F, 0x00, 0x8C, 0x01, 0x89, 0x01, 0xAE, 0x09, 0x00, 0x20, +0x1D, 0x03, 0x00, 0x20, 0x50, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0xE9, 0x01, 0x00, 0x20, 0xEA, 0x01, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, +0xF8, 0x01, 0x00, 0x20, 0xE8, 0x01, 0x00, 0x20, 0xE7, 0x01, 0x00, 0x20, +0xE5, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0xF6, 0x03, 0x00, 0x20, +0x08, 0x03, 0x00, 0x20, 0xB1, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x00, 0xF0, +0x7D, 0xFE, 0xB0, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD0, 0x55, 0xE1, +0xAE, 0x4C, 0x23, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0xAD, 0x49, +0x03, 0xF0, 0xB8, 0xFC, 0x23, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x21, +0x00, 0x20, 0xAA, 0x4A, 0x0B, 0x1C, 0x00, 0x90, 0x03, 0xF0, 0x56, 0xFC, +0xA8, 0x4B, 0x98, 0x78, 0x03, 0xF0, 0x78, 0xFA, 0xA7, 0x4D, 0xE8, 0x7B, +0x03, 0xF0, 0x52, 0xF8, 0xA6, 0x4C, 0x20, 0x60, 0x28, 0x7C, 0x03, 0xF0, +0x4D, 0xF8, 0x11, 0x23, 0x60, 0x60, 0xEB, 0x56, 0xEA, 0x7B, 0x53, 0x43, +0xA3, 0x60, 0x9A, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0xA0, 0x4B, 0x1B, 0x78, +0xA0, 0x4B, 0x18, 0x78, 0x01, 0xF0, 0x14, 0xF8, 0x95, 0x4B, 0x9D, 0x4D, +0x00, 0x24, 0x1C, 0x70, 0x2B, 0x78, 0x00, 0xF0, 0x29, 0xFD, 0x03, 0xF0, +0x8B, 0xFF, 0x00, 0xF0, 0x25, 0xFD, 0x2C, 0x70, 0x8F, 0x4B, 0x01, 0x24, +0x1C, 0x70, 0x00, 0xF0, 0x9B, 0xFC, 0x97, 0x4B, 0x1B, 0x68, 0x9A, 0x05, +0x13, 0xD5, 0x96, 0x4A, 0x96, 0x4B, 0x04, 0x20, 0x1A, 0x60, 0x96, 0x4B, +0x19, 0x68, 0x01, 0x43, 0x19, 0x60, 0x19, 0x68, 0x02, 0x20, 0x81, 0x43, +0x19, 0x60, 0x19, 0x68, 0x0C, 0x43, 0x1C, 0x60, 0x91, 0x4B, 0x00, 0x21, +0x19, 0x60, 0x91, 0x4B, 0x1A, 0x60, 0x91, 0x4C, 0x03, 0x20, 0x23, 0x68, +0x98, 0x47, 0x03, 0xF0, 0x3F, 0xF8, 0x23, 0x68, 0x05, 0x20, 0x98, 0x47, +0x02, 0xF0, 0xE4, 0xFF, 0x8C, 0x4C, 0x8D, 0x4D, 0x01, 0x20, 0x40, 0x42, +0x21, 0x1C, 0x2A, 0x1C, 0x04, 0xF0, 0x4C, 0xFC, 0x79, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x03, 0xD0, 0x0C, 0x20, 0x88, 0x49, 0x03, 0xF0, 0x4E, 0xFC, +0x87, 0x4A, 0x23, 0x68, 0x13, 0x80, 0x2B, 0x68, 0x53, 0x80, 0x73, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, 0x00, 0x93, +0x0C, 0x20, 0x0B, 0x1C, 0x03, 0xF0, 0xE6, 0xFB, 0x7B, 0x4C, 0x06, 0x20, +0x23, 0x68, 0x98, 0x47, 0x03, 0xF0, 0xF4, 0xFF, 0x04, 0xF0, 0x64, 0xF9, +0x04, 0xF0, 0x98, 0xFB, 0x00, 0xF0, 0x62, 0xF9, 0x04, 0xF0, 0x06, 0xFD, +0x04, 0xF0, 0x7E, 0xFE, 0x78, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x2A, 0xD1, +0x23, 0x68, 0x07, 0x20, 0x98, 0x47, 0x01, 0xF0, 0x51, 0xFA, 0x23, 0x68, +0x08, 0x20, 0x98, 0x47, 0x02, 0xF0, 0xB2, 0xFF, 0x02, 0xF0, 0xBA, 0xFF, +0x23, 0x68, 0x09, 0x20, 0x98, 0x47, 0x01, 0xF0, 0x69, 0xFA, 0x01, 0xF0, +0xD1, 0xFB, 0x23, 0x68, 0x0A, 0x20, 0x98, 0x47, 0x01, 0xF0, 0x6E, 0xFC, +0x02, 0xF0, 0x44, 0xFB, 0x23, 0x68, 0x0B, 0x20, 0x98, 0x47, 0x01, 0xF0, +0xB8, 0xFE, 0x01, 0xF0, 0xD7, 0xFF, 0x23, 0x68, 0x0E, 0x20, 0x98, 0x47, +0x02, 0xF0, 0x84, 0xF8, 0x02, 0xF0, 0xF2, 0xF9, 0x23, 0x68, 0x10, 0x20, +0x98, 0x47, 0x00, 0xF0, 0x81, 0xF9, 0x5B, 0x4B, 0x0F, 0x20, 0x1B, 0x68, +0x98, 0x47, 0x5E, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x3C, 0xD1, 0x02, 0xF0, +0x4F, 0xFA, 0x5C, 0x4B, 0x1A, 0x68, 0x5C, 0x4B, 0x00, 0x2A, 0x04, 0xD1, +0x5B, 0x49, 0x09, 0x68, 0x00, 0x29, 0x00, 0xDD, 0x1A, 0x70, 0x47, 0x4A, +0x19, 0x78, 0x32, 0x32, 0x12, 0x78, 0x91, 0x42, 0x01, 0xD3, 0x00, 0x22, +0x1A, 0x70, 0x1B, 0x78, 0x00, 0x2B, 0x21, 0xD1, 0x53, 0x4B, 0x51, 0x4C, +0x1B, 0x68, 0x00, 0x2B, 0x09, 0xDD, 0x20, 0x68, 0x00, 0x28, 0x06, 0xD1, +0x39, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x02, 0xD0, 0x4E, 0x49, 0x03, 0xF0, +0xCF, 0xFB, 0x4E, 0x4B, 0x1B, 0x68, 0x98, 0x47, 0x23, 0x68, 0x00, 0x2B, +0x0A, 0xDD, 0x49, 0x4B, 0x18, 0x68, 0x00, 0x28, 0x06, 0xD1, 0x31, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x02, 0xD0, 0x48, 0x49, 0x03, 0xF0, 0xBE, 0xFB, +0x02, 0xF0, 0x72, 0xFA, 0x41, 0x4B, 0x1A, 0x78, 0x01, 0x32, 0x1A, 0x70, +0x32, 0x4B, 0x1B, 0x68, 0x9A, 0x05, 0x23, 0xD5, 0x34, 0x4B, 0x18, 0x68, +0x2A, 0x4B, 0x1A, 0x79, 0x19, 0x78, 0x2F, 0x4B, 0x18, 0x1A, 0x53, 0x1C, +0x98, 0x40, 0x04, 0xF0, 0x8D, 0xFF, 0x23, 0x4C, 0x2F, 0x4D, 0x23, 0x78, +0x28, 0x60, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x39, 0x49, 0x03, 0xF0, +0x9F, 0xFB, 0x23, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x00, 0x20, 0x01, 0x21, +0x2A, 0x1C, 0x04, 0x23, 0x00, 0x90, 0x03, 0xF0, 0x3D, 0xFB, 0x24, 0x4B, +0x01, 0x21, 0x1A, 0x68, 0x8A, 0x43, 0x1A, 0x60, 0x80, 0x23, 0xDB, 0x05, +0x9A, 0x6C, 0x01, 0x21, 0x0A, 0x43, 0x9A, 0x64, 0x00, 0xF0, 0x1E, 0xFC, +0x2D, 0x4B, 0x00, 0x20, 0x18, 0x56, 0x00, 0xF0, 0x5D, 0xFE, 0x17, 0xE0, +0x0F, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x05, 0x20, 0x29, 0x49, +0x03, 0xF0, 0x7A, 0xFB, 0x01, 0x20, 0x00, 0xF0, 0xF9, 0xFE, 0x00, 0x20, +0x00, 0xF0, 0xF6, 0xFE, 0x13, 0x23, 0x23, 0x70, 0x06, 0xE0, 0x00, 0xF0, +0x0D, 0xFC, 0x03, 0xE0, 0x13, 0x4B, 0x11, 0x20, 0x1B, 0x68, 0x98, 0x47, +0x20, 0x4B, 0x1F, 0x70, 0xEB, 0xE5, 0xC0, 0x46, 0xEA, 0x01, 0x00, 0x20, +0xE0, 0x01, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0x34, 0x59, 0x00, 0x00, +0xAC, 0x0A, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0xFC, 0x02, 0x00, 0x20, 0x1D, 0x03, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x58, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x00, 0x14, 0xE0, 0x00, 0xE0, +0x10, 0xE0, 0x00, 0xE0, 0x18, 0xE0, 0x00, 0xE0, 0xFC, 0x01, 0x00, 0x20, +0xF8, 0x01, 0x00, 0x20, 0x34, 0x11, 0x00, 0x20, 0x38, 0x11, 0x00, 0x20, +0x38, 0x59, 0x00, 0x00, 0x54, 0x11, 0x00, 0x20, 0x48, 0x11, 0x00, 0x20, +0x20, 0x01, 0x00, 0x20, 0xCA, 0x00, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0x3E, 0x59, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x47, 0x59, 0x00, 0x00, +0x51, 0x59, 0x00, 0x00, 0xB3, 0x01, 0x00, 0x20, 0x5E, 0x59, 0x00, 0x00, +0x56, 0x00, 0x00, 0x20, 0x08, 0xB5, 0x01, 0xF0, 0x99, 0xFD, 0x01, 0xF0, +0xB3, 0xFD, 0x03, 0x4B, 0x1B, 0x68, 0x98, 0x47, 0x02, 0xF0, 0xD2, 0xF9, +0x08, 0xBD, 0xC0, 0x46, 0x00, 0x02, 0x00, 0x20, 0x10, 0xB5, 0x04, 0xF0, +0xEF, 0xFD, 0x05, 0x4C, 0x00, 0x20, 0x23, 0x68, 0x98, 0x47, 0x04, 0xF0, +0x19, 0xFE, 0x23, 0x68, 0x01, 0x20, 0x98, 0x47, 0x10, 0xBD, 0xC0, 0x46, +0xF8, 0x01, 0x00, 0x20, 0x7F, 0xB5, 0x17, 0x4D, 0x17, 0x4B, 0x5B, 0x1B, +0x03, 0x93, 0x17, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x00, 0x20, +0x01, 0x21, 0x03, 0xAA, 0x04, 0x23, 0x00, 0x90, 0x03, 0xF0, 0xA0, 0xFA, +0x12, 0x4E, 0x18, 0xE0, 0x14, 0x2C, 0x00, 0xDD, 0x14, 0x24, 0xE1, 0xB2, +0x08, 0x1C, 0x03, 0xE0, 0x01, 0x38, 0xC0, 0xB2, 0x2B, 0x5C, 0x33, 0x54, +0x00, 0x28, 0xF9, 0xD1, 0x0A, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x04, 0xD0, +0x09, 0x4A, 0x01, 0x23, 0x00, 0x90, 0x03, 0xF0, 0x89, 0xFA, 0x03, 0x9B, +0x2D, 0x19, 0x1B, 0x1B, 0x03, 0x93, 0x03, 0x9C, 0x00, 0x2C, 0xE3, 0xD1, +0x7F, 0xBD, 0xC0, 0x46, 0x0C, 0x1E, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, 0x13, 0xB5, 0x1E, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x37, 0xD0, 0x1D, 0x4C, 0x00, 0x23, 0x23, 0x70, +0x1C, 0x4B, 0x04, 0x20, 0x1B, 0x68, 0x98, 0x47, 0x1B, 0x4B, 0x1C, 0x4A, +0x59, 0x68, 0x1B, 0x68, 0x11, 0x80, 0x53, 0x80, 0x1A, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, 0x00, 0x93, 0x18, 0x20, +0x0B, 0x1C, 0x03, 0xF0, 0x5B, 0xFA, 0x23, 0x78, 0x15, 0x4C, 0x00, 0x2B, +0x1A, 0xD0, 0x13, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, +0x12, 0x49, 0x03, 0xF0, 0xA7, 0xFA, 0x12, 0x4A, 0x01, 0x23, 0x13, 0x70, +0x22, 0x68, 0x02, 0x2A, 0x04, 0xDC, 0xD2, 0x18, 0x22, 0x60, 0x0F, 0x4A, +0x13, 0x70, 0x08, 0xE0, 0xFF, 0xF7, 0x74, 0xFF, 0x0D, 0x4B, 0x0D, 0x22, +0x1A, 0x70, 0x00, 0x23, 0x23, 0x60, 0x00, 0xE0, 0x23, 0x60, 0x13, 0xBD, +0x1C, 0x03, 0x00, 0x20, 0x3D, 0x11, 0x00, 0x20, 0xF8, 0x01, 0x00, 0x20, +0x70, 0x01, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0x84, 0x01, 0x00, 0x20, 0xD0, 0x58, 0x00, 0x00, 0x48, 0x11, 0x00, 0x20, +0x14, 0x09, 0x00, 0x20, 0x1D, 0x03, 0x00, 0x20, 0xF0, 0xB5, 0xBA, 0x4B, +0x85, 0xB0, 0x04, 0x33, 0xDB, 0x7F, 0x00, 0x24, 0xB8, 0x49, 0x0A, 0x22, +0x09, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x10, 0x1C, 0x58, 0x43, 0x08, 0x18, +0x3C, 0x25, 0x40, 0x5F, 0x00, 0x28, 0x00, 0xD0, 0x01, 0x24, 0x00, 0x2B, +0xF3, 0xD1, 0xB2, 0x4B, 0xB2, 0x4A, 0x1B, 0x78, 0x07, 0xE0, 0x01, 0x3B, +0xDB, 0xB2, 0x19, 0x1D, 0x49, 0x00, 0x89, 0x5E, 0x00, 0x29, 0x00, 0xD0, +0x01, 0x24, 0x00, 0x2B, 0xF5, 0xD1, 0xAD, 0x4A, 0x00, 0x2C, 0x04, 0xD1, +0x13, 0x68, 0xAC, 0x49, 0x8B, 0x42, 0x01, 0xD0, 0x01, 0x33, 0x13, 0x60, +0xAA, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0xA4, 0x4B, 0x1A, 0x68, 0xA2, 0x4B, +0x00, 0x2A, 0x7C, 0xD1, 0xA3, 0x4A, 0x12, 0x68, 0x00, 0x2A, 0x78, 0xD1, +0x1A, 0x1C, 0x34, 0x32, 0x10, 0x78, 0x00, 0x28, 0x41, 0xD1, 0xA3, 0x4A, +0x12, 0x78, 0x01, 0x2A, 0x17, 0xD1, 0xA2, 0x4B, 0x18, 0x70, 0xA2, 0x4B, +0x1A, 0x70, 0xA2, 0x4B, 0x18, 0x70, 0xA2, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x02, 0xD0, 0xA1, 0x49, 0x03, 0xF0, 0x2E, 0xFA, 0x99, 0x4B, 0x01, 0x22, +0x1A, 0x70, 0x01, 0xF0, 0x9F, 0xFC, 0x01, 0xF0, 0xB9, 0xFC, 0x97, 0x4B, +0x00, 0x22, 0x1A, 0x70, 0x67, 0xE1, 0x9B, 0x4A, 0x3C, 0x33, 0x1B, 0x78, +0x12, 0x68, 0x9A, 0x42, 0x1F, 0xDB, 0x96, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x02, 0xD0, 0x97, 0x49, 0x03, 0xF0, 0x16, 0xFA, 0x96, 0x4B, 0x87, 0x49, +0x1A, 0x68, 0x3D, 0x31, 0x01, 0x32, 0x1A, 0x60, 0x09, 0x78, 0x8A, 0x42, +0x0F, 0xDB, 0x00, 0x20, 0x18, 0x60, 0x8A, 0x4B, 0x18, 0x70, 0x8A, 0x4B, +0x18, 0x70, 0x8B, 0x4B, 0x1B, 0x78, 0x83, 0x42, 0x02, 0xD0, 0x8E, 0x49, +0x03, 0xF0, 0x00, 0xFA, 0x82, 0x4B, 0x02, 0x22, 0x1A, 0x70, 0x85, 0x4B, +0x8B, 0x4A, 0x00, 0x21, 0x19, 0x70, 0x10, 0x68, 0x85, 0x4B, 0x19, 0x60, +0x13, 0x1C, 0x88, 0x42, 0x0E, 0xDD, 0x01, 0x38, 0x10, 0x60, 0x8C, 0x42, +0x00, 0xD0, 0x11, 0x60, 0x1A, 0x68, 0x01, 0x2A, 0x00, 0xD0, 0x18, 0xE1, +0x00, 0x22, 0x1A, 0x60, 0x76, 0x4B, 0x03, 0x22, 0x1A, 0x70, 0x28, 0xE1, +0x80, 0x4B, 0x81, 0x49, 0x04, 0x33, 0xDB, 0x8F, 0x8B, 0x42, 0x00, 0xD1, +0x0B, 0xE1, 0x7F, 0x49, 0x09, 0x68, 0x99, 0x42, 0x00, 0xDA, 0x06, 0xE1, +0x68, 0x4B, 0x6C, 0x48, 0x19, 0x1C, 0x3E, 0x31, 0x09, 0x78, 0x00, 0x68, +0x88, 0x42, 0x00, 0xDA, 0xFD, 0xE0, 0x3F, 0x33, 0x1B, 0x78, 0x13, 0x60, +0xF9, 0xE0, 0x04, 0x33, 0xD8, 0x7F, 0x00, 0x23, 0x1A, 0x1C, 0x75, 0x49, +0x31, 0xE0, 0x01, 0x38, 0xC0, 0xB2, 0x0A, 0x24, 0x44, 0x43, 0x5E, 0x4F, +0x3D, 0x19, 0x3C, 0x26, 0xAD, 0x5F, 0x00, 0x2D, 0x27, 0xDD, 0x0C, 0x19, +0x3C, 0x27, 0xE4, 0x5F, 0x00, 0x2C, 0x22, 0xDD, 0x44, 0x00, 0x0D, 0x19, +0xAF, 0x88, 0x57, 0x4D, 0x3E, 0xB2, 0x2C, 0x19, 0xA4, 0x88, 0x25, 0xB2, +0x76, 0x1B, 0x02, 0xD4, 0x3C, 0x1B, 0xA4, 0xB2, 0x01, 0xE0, 0xE4, 0x1B, +0xA4, 0xB2, 0x05, 0x1C, 0x64, 0x4E, 0x50, 0x4F, 0x10, 0x35, 0x6D, 0x00, +0xA2, 0x18, 0xAC, 0x5B, 0xED, 0x5B, 0x27, 0xB2, 0x2E, 0xB2, 0x92, 0xB2, +0xBF, 0x1B, 0x02, 0xD4, 0x64, 0x1B, 0xA4, 0xB2, 0x01, 0xE0, 0x2C, 0x1B, +0xA4, 0xB2, 0xE3, 0x18, 0x9B, 0xB2, 0x00, 0x28, 0xCB, 0xD1, 0x56, 0x49, +0x08, 0x60, 0x4D, 0x49, 0x0C, 0x78, 0x43, 0x49, 0x00, 0x2C, 0x40, 0xD0, +0x34, 0x31, 0x0B, 0x78, 0x00, 0x2B, 0x00, 0xD0, 0xB3, 0xE0, 0x4A, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x02, 0xD0, 0x53, 0x49, 0x03, 0xF0, 0x7E, 0xF9, +0x4F, 0x4C, 0x52, 0x4A, 0x23, 0x68, 0x13, 0x80, 0x51, 0x4B, 0x1B, 0x68, +0x53, 0x80, 0x43, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, +0x02, 0x21, 0x00, 0x93, 0x00, 0x20, 0x0B, 0x1C, 0x03, 0xF0, 0x14, 0xF9, +0x32, 0x49, 0x20, 0x68, 0x4A, 0x8F, 0x3B, 0x4B, 0x90, 0x42, 0x14, 0xDA, +0x41, 0x4A, 0x47, 0x48, 0x45, 0x32, 0x12, 0x78, 0x00, 0x68, 0x90, 0x42, +0x0D, 0xDA, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD0, 0x89, 0xE0, 0x37, 0x4B, +0x3C, 0x31, 0x1A, 0x68, 0x09, 0x78, 0x8A, 0x42, 0x00, 0xDB, 0x82, 0xE0, +0x01, 0x32, 0x1A, 0x60, 0x7F, 0xE0, 0x01, 0x22, 0x1A, 0x70, 0x31, 0x4A, +0x00, 0x23, 0x13, 0x60, 0x31, 0x4A, 0x13, 0x60, 0x77, 0xE0, 0x08, 0x1C, +0x34, 0x30, 0x00, 0x78, 0x00, 0x28, 0x72, 0xD1, 0x32, 0x48, 0x09, 0x8F, +0x00, 0x68, 0x88, 0x42, 0x09, 0xDB, 0x2E, 0x49, 0x33, 0x48, 0x45, 0x31, +0x09, 0x78, 0x00, 0x68, 0x88, 0x42, 0x02, 0xDB, 0x22, 0x49, 0x01, 0x20, +0x08, 0x70, 0x1F, 0x49, 0x09, 0x78, 0x00, 0x29, 0x08, 0xD1, 0x15, 0x49, +0x08, 0x8F, 0x27, 0x49, 0x88, 0x42, 0x5A, 0xD0, 0x1C, 0x49, 0x09, 0x78, +0x00, 0x29, 0x56, 0xD0, 0x11, 0x49, 0x09, 0x68, 0x01, 0x29, 0x05, 0xDC, +0x0E, 0x49, 0xC9, 0x8E, 0x8A, 0x42, 0x01, 0xD8, 0x8B, 0x42, 0x49, 0xD9, +0x13, 0x4B, 0x00, 0x20, 0x18, 0x70, 0x13, 0x4B, 0x01, 0x22, 0x1A, 0x70, +0x12, 0x4B, 0x18, 0x70, 0x12, 0x4B, 0x1B, 0x78, 0x83, 0x42, 0x02, 0xD0, +0x11, 0x49, 0x03, 0xF0, 0x0F, 0xF9, 0x0A, 0x4B, 0x01, 0x22, 0x1A, 0x70, +0x01, 0xF0, 0x80, 0xFB, 0x01, 0xF0, 0x9A, 0xFB, 0x35, 0xE0, 0xC0, 0x46, +0xAE, 0x09, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, +0xE0, 0x00, 0x00, 0x20, 0xC8, 0x01, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x7F, +0xB3, 0x01, 0x00, 0x20, 0xB4, 0x01, 0x00, 0x20, 0xDC, 0x01, 0x00, 0x20, +0xDD, 0x01, 0x00, 0x20, 0xD4, 0x01, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0xDA, 0x58, 0x00, 0x00, 0xD8, 0x01, 0x00, 0x20, 0xE4, 0x58, 0x00, 0x00, +0xD0, 0x01, 0x00, 0x20, 0xEC, 0x58, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0xFF, 0xFF, 0x00, 0x00, 0x34, 0x11, 0x00, 0x20, +0x20, 0x03, 0x00, 0x20, 0xF5, 0x58, 0x00, 0x00, 0x54, 0x11, 0x00, 0x20, +0x38, 0x11, 0x00, 0x20, 0x0D, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x0D, 0x4B, +0x34, 0x33, 0x1B, 0x78, 0x00, 0x2B, 0x10, 0xD0, 0x0B, 0x4B, 0x1A, 0x78, +0x00, 0x2A, 0x0C, 0xD0, 0x0A, 0x4A, 0x00, 0x21, 0x51, 0x56, 0x03, 0x29, +0x07, 0xD0, 0x09, 0x49, 0x09, 0x78, 0x48, 0x42, 0x41, 0x41, 0x01, 0x31, +0x11, 0x70, 0x00, 0x22, 0x1A, 0x70, 0x05, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, +0xB4, 0x01, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0xDC, 0x01, 0x00, 0x20, +0xB3, 0x01, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, 0x10, 0xB5, 0x54, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x0A, 0xD0, 0x53, 0x4B, 0x1B, 0x68, 0x98, 0x47, +0x01, 0xF0, 0x1A, 0xFB, 0x01, 0xF0, 0x34, 0xFB, 0x01, 0xF0, 0x56, 0xFF, +0x02, 0xF0, 0x90, 0xFB, 0x4E, 0x4B, 0x02, 0x21, 0x1A, 0x68, 0x8A, 0x43, +0x1A, 0x60, 0x19, 0x68, 0x80, 0x22, 0xD2, 0x05, 0x90, 0x68, 0x91, 0x60, +0x19, 0x68, 0x08, 0x20, 0x81, 0x43, 0x19, 0x60, 0x19, 0x68, 0x90, 0x68, +0x91, 0x60, 0x19, 0x68, 0x04, 0x20, 0x81, 0x43, 0x19, 0x60, 0x1B, 0x68, +0x91, 0x68, 0x93, 0x60, 0x40, 0x4B, 0x18, 0x78, 0x42, 0x4B, 0x1B, 0x78, +0x00, 0x28, 0x32, 0xD0, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x40, 0x49, +0x03, 0xF0, 0x7A, 0xF8, 0x3F, 0x4B, 0x80, 0x22, 0x19, 0x68, 0x52, 0x00, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0xA0, 0x23, 0xDB, 0x05, 0x99, 0x68, +0x9A, 0x60, 0x37, 0x4B, 0x3A, 0x4A, 0x19, 0x68, 0x0A, 0x40, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x99, 0x68, 0x9A, 0x60, 0x37, 0x4A, +0x01, 0x21, 0x11, 0x70, 0x19, 0x68, 0x80, 0x22, 0x52, 0x04, 0x0A, 0x43, +0x1A, 0x60, 0xC0, 0x46, 0xC0, 0x46, 0xC0, 0x46, 0xC0, 0x46, 0x62, 0xB6, +0x31, 0x4A, 0x19, 0x68, 0x0A, 0x40, 0x1A, 0x60, 0xBF, 0xF3, 0x6F, 0x8F, +0xFA, 0x20, 0xC0, 0x00, 0x02, 0xF0, 0x6E, 0xFC, 0x11, 0xE0, 0x00, 0x2B, +0x02, 0xD0, 0x2C, 0x49, 0x03, 0xF0, 0x48, 0xF8, 0x2B, 0x48, 0x02, 0xF0, +0x65, 0xFC, 0x2B, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x05, 0xD1, 0x2A, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x01, 0xD1, 0x02, 0xF0, 0x59, 0xFE, 0x1D, 0x4B, +0x02, 0x21, 0x1A, 0x68, 0x0A, 0x43, 0x1A, 0x60, 0x19, 0x68, 0x80, 0x22, +0xD2, 0x05, 0x90, 0x68, 0x91, 0x60, 0x23, 0x49, 0x01, 0x31, 0xC8, 0x7F, +0x08, 0x21, 0x00, 0x28, 0x06, 0xD0, 0x18, 0x68, 0x01, 0x43, 0x19, 0x60, +0x19, 0x68, 0x90, 0x68, 0x91, 0x60, 0x05, 0xE0, 0x18, 0x68, 0x88, 0x43, +0x18, 0x60, 0x19, 0x68, 0x90, 0x68, 0x91, 0x60, 0x1A, 0x68, 0x04, 0x21, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0xFA, 0x20, +0x99, 0x68, 0xC0, 0x00, 0x9A, 0x60, 0x02, 0xF0, 0x31, 0xFC, 0x06, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x12, 0x4C, 0x0D, 0x20, 0x23, 0x68, +0x98, 0x47, 0x23, 0x68, 0x12, 0x20, 0x98, 0x47, 0x10, 0xBD, 0xC0, 0x46, +0xE8, 0x01, 0x00, 0x20, 0x68, 0x00, 0x00, 0x20, 0x14, 0x00, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0xFB, 0x58, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x20, +0xFF, 0xFE, 0xFF, 0xFF, 0x2C, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xFE, +0x01, 0x59, 0x00, 0x00, 0x40, 0x42, 0x0F, 0x00, 0xE5, 0x01, 0x00, 0x20, +0xE4, 0x01, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0xF8, 0x01, 0x00, 0x20, +0x10, 0xB5, 0x31, 0x4B, 0x02, 0x24, 0x19, 0x78, 0x30, 0x4B, 0x4A, 0xB2, +0x1B, 0x78, 0x00, 0x2B, 0x25, 0xD0, 0x2F, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x21, 0xD1, 0x2E, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x1D, 0xD1, 0x2D, 0x4B, +0xA2, 0x42, 0x07, 0xD0, 0x2C, 0x48, 0x80, 0x7B, 0x00, 0x28, 0x03, 0xD1, +0x2B, 0x48, 0x00, 0x68, 0x00, 0x28, 0x03, 0xD0, 0x00, 0x21, 0x19, 0x60, +0x01, 0x24, 0x0E, 0xE0, 0x28, 0x4A, 0x18, 0x68, 0x92, 0x68, 0x90, 0x42, +0x01, 0xDA, 0x01, 0x30, 0x18, 0x60, 0x00, 0x29, 0x36, 0xD0, 0x21, 0x4B, +0x00, 0x24, 0x1B, 0x68, 0x93, 0x42, 0x16, 0xDA, 0x30, 0xE0, 0x63, 0xB2, +0x93, 0x42, 0x2D, 0xD0, 0x01, 0x2B, 0x1D, 0xD0, 0x02, 0x2B, 0x02, 0xD0, +0x00, 0x2B, 0x0C, 0xD0, 0x24, 0xE0, 0x1D, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x03, 0xD0, 0x00, 0x20, 0x1B, 0x49, 0x02, 0xF0, 0xA5, 0xFF, 0x00, 0x20, +0x02, 0xF0, 0x78, 0xFB, 0x18, 0xE0, 0x17, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x03, 0xD0, 0x00, 0x20, 0x16, 0x49, 0x02, 0xF0, 0x99, 0xFF, 0x12, 0x4B, +0x58, 0x68, 0x02, 0xF0, 0x6B, 0xFB, 0x0B, 0xE0, 0x10, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x11, 0x49, 0x02, 0xF0, 0x8C, 0xFF, +0x0B, 0x4B, 0x18, 0x68, 0x02, 0xF0, 0x5E, 0xFB, 0x02, 0x4B, 0x1C, 0x70, +0x02, 0xF0, 0x4C, 0xFB, 0x10, 0xBD, 0xC0, 0x46, 0x3C, 0x00, 0x00, 0x20, +0x1C, 0x03, 0x00, 0x20, 0xE3, 0x01, 0x00, 0x20, 0xE2, 0x01, 0x00, 0x20, +0x5C, 0x00, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, 0xE0, 0x00, 0x00, 0x20, +0xFC, 0x02, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0x09, 0x59, 0x00, 0x00, +0x0E, 0x59, 0x00, 0x00, 0x13, 0x59, 0x00, 0x00, 0x08, 0xB5, 0x02, 0xF0, +0x5F, 0xFB, 0x08, 0xBD, 0x08, 0xB5, 0x02, 0xF0, 0x4D, 0xFB, 0x08, 0xBD, +0x08, 0xB5, 0x02, 0xF0, 0xE5, 0xFA, 0x80, 0x23, 0xDB, 0x05, 0x9A, 0x6C, +0x01, 0x21, 0x0A, 0x43, 0x9A, 0x64, 0xFF, 0xF7, 0xF1, 0xFF, 0x08, 0xBD, +0xF0, 0xB5, 0x87, 0xB0, 0xFF, 0xF7, 0xF0, 0xFF, 0x78, 0x4A, 0x79, 0x4C, +0x53, 0x78, 0x15, 0x78, 0x78, 0x48, 0x10, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, +0x9A, 0x1C, 0x67, 0x46, 0xB2, 0x18, 0x79, 0x01, 0x52, 0x00, 0x12, 0x5B, +0xC9, 0x18, 0x4F, 0x00, 0x3A, 0x52, 0x73, 0x4A, 0x00, 0x27, 0x8F, 0x54, +0x00, 0x2B, 0xEF, 0xD1, 0x63, 0x46, 0x5A, 0x1E, 0xD2, 0xB2, 0x00, 0x2B, +0x04, 0xD0, 0x56, 0x1C, 0x2B, 0x1C, 0xB6, 0x01, 0x94, 0x46, 0xF3, 0xE7, +0x6C, 0x4B, 0x6D, 0x4C, 0x1B, 0x78, 0x6D, 0x48, 0x67, 0x49, 0x6D, 0x4A, +0x0E, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0xE5, 0x5C, 0xC6, 0x5C, 0x01, 0x35, +0x02, 0x36, 0xAD, 0x01, 0xAD, 0x19, 0x6D, 0x00, 0x6E, 0x5A, 0x5D, 0x00, +0xAE, 0x52, 0x67, 0x4D, 0x00, 0x26, 0xEE, 0x54, 0x00, 0x2B, 0xEE, 0xD1, +0x65, 0x25, 0x03, 0x95, 0x5B, 0x4C, 0x66, 0xE0, 0xFF, 0xF7, 0xB2, 0xFF, +0x26, 0x78, 0x63, 0x78, 0x05, 0x96, 0x2D, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, +0x58, 0x4F, 0xF0, 0x18, 0x04, 0x9D, 0x40, 0x00, 0x9A, 0x1C, 0xC0, 0x5B, +0xAD, 0x18, 0x54, 0x4F, 0x6D, 0x00, 0xEF, 0x5B, 0xC7, 0x1B, 0x04, 0xD4, +0x51, 0x4F, 0xED, 0x5B, 0x45, 0x1B, 0x02, 0x95, 0x03, 0xE0, 0x4F, 0x4F, +0xED, 0x5B, 0x2D, 0x1A, 0x02, 0x95, 0x04, 0x98, 0x87, 0x18, 0x4C, 0x48, +0x7F, 0x00, 0xC0, 0x5B, 0x4B, 0x4F, 0x84, 0x46, 0xF0, 0x18, 0x42, 0x00, +0x15, 0x1C, 0x62, 0x46, 0xEA, 0x53, 0x49, 0x4D, 0x2F, 0x5C, 0x02, 0x9D, +0xBD, 0x42, 0x00, 0xDA, 0x3D, 0x1C, 0x46, 0x4F, 0x3D, 0x54, 0x00, 0x2B, +0xD2, 0xD1, 0x0B, 0x1C, 0x59, 0x1E, 0xC9, 0xB2, 0x00, 0x2B, 0x05, 0xD0, +0x48, 0x1C, 0x80, 0x01, 0x05, 0x9B, 0x4E, 0x01, 0x04, 0x90, 0xF2, 0xE7, +0x3F, 0x4B, 0x3C, 0x4A, 0x1B, 0x78, 0x22, 0xE0, 0x3E, 0x4D, 0x01, 0x3B, +0xDB, 0xB2, 0x3E, 0x4F, 0xEE, 0x5C, 0x3E, 0x48, 0xFD, 0x5C, 0x59, 0x00, +0x01, 0x36, 0x09, 0x5A, 0x02, 0x35, 0xB0, 0x01, 0x40, 0x19, 0x40, 0x00, +0x87, 0x5A, 0x80, 0x5A, 0xCF, 0x1B, 0x01, 0xD4, 0x09, 0x1A, 0x00, 0xE0, +0x41, 0x1A, 0xB6, 0x01, 0x75, 0x19, 0x2F, 0x48, 0x6D, 0x00, 0x46, 0x5B, +0x33, 0x48, 0x5D, 0x00, 0x2E, 0x52, 0x33, 0x48, 0xC5, 0x5C, 0xA9, 0x42, +0x00, 0xDA, 0x29, 0x1C, 0xC1, 0x54, 0x00, 0x2B, 0xDA, 0xD1, 0x03, 0x9B, +0x01, 0x3B, 0xDB, 0xB2, 0x03, 0x93, 0x00, 0x2B, 0x92, 0xD1, 0x61, 0x78, +0x24, 0x78, 0x24, 0x4A, 0x04, 0x94, 0x1E, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, +0x45, 0x01, 0xED, 0x18, 0x21, 0x4F, 0x6D, 0x00, 0xEE, 0x5B, 0x25, 0x88, +0xAC, 0x46, 0x9D, 0x1C, 0x66, 0x45, 0x09, 0xD9, 0x27, 0x88, 0xF6, 0x1B, +0x8F, 0x01, 0xBC, 0x46, 0x65, 0x44, 0x6D, 0x00, 0xB6, 0xB2, 0xAF, 0x5A, +0xAE, 0x52, 0x05, 0xE0, 0x8E, 0x01, 0x75, 0x19, 0x6D, 0x00, 0xAE, 0x5A, +0x00, 0x26, 0xAE, 0x52, 0x00, 0x2B, 0xE1, 0xD1, 0x01, 0x1C, 0x48, 0x1E, +0xC0, 0xB2, 0x00, 0x29, 0x05, 0xD0, 0x41, 0x1C, 0x18, 0x4F, 0xCC, 0x01, +0x04, 0x9B, 0xE4, 0x19, 0xF2, 0xE7, 0x11, 0x4B, 0x13, 0x4F, 0x1B, 0x78, +0x10, 0x4E, 0x15, 0x48, 0x10, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0xF5, 0x5C, +0x13, 0x49, 0xED, 0x01, 0x5A, 0x00, 0x6D, 0x18, 0xD4, 0x5B, 0x29, 0x88, +0x8C, 0x42, 0x03, 0xD9, 0x2D, 0x88, 0x64, 0x1B, 0x84, 0x52, 0x01, 0xE0, +0x00, 0x25, 0x85, 0x52, 0x00, 0x2B, 0xEC, 0xD1, 0x07, 0xB0, 0xF0, 0xBD, +0x0A, 0x03, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0xF8, 0x03, 0x00, 0x20, +0xB3, 0x0A, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, 0x30, 0x75, 0x00, 0x00, +0x2A, 0x75, 0x00, 0x00, 0x14, 0x02, 0x00, 0x20, 0xA4, 0x0A, 0x00, 0x20, +0x02, 0x40, 0x00, 0x40, 0x3C, 0x0D, 0x00, 0x20, 0x82, 0x40, 0x00, 0x40, +0xF0, 0xB5, 0x87, 0xB0, 0x02, 0xF0, 0x4A, 0xF8, 0x02, 0xF0, 0x60, 0xF9, +0x00, 0x28, 0xFB, 0xD1, 0x52, 0x4B, 0x1B, 0x78, 0x02, 0x2B, 0x09, 0xD0, +0x51, 0x4B, 0x52, 0x49, 0x40, 0x33, 0x1A, 0x78, 0x53, 0x42, 0x54, 0x18, +0xE0, 0x54, 0x01, 0x33, 0x93, 0x42, 0xFA, 0xDD, 0x4C, 0x4E, 0x4E, 0x4F, +0x33, 0x1C, 0x40, 0x33, 0x1C, 0x78, 0x64, 0x42, 0x0C, 0xE0, 0xFA, 0x78, +0x80, 0x23, 0x12, 0x19, 0xD2, 0xB2, 0xDB, 0x05, 0x1A, 0x71, 0xFF, 0xF7, +0xC1, 0xFE, 0x28, 0x78, 0x20, 0x18, 0x03, 0xF0, 0xF3, 0xFD, 0x01, 0x34, +0x35, 0x1C, 0x40, 0x35, 0x2B, 0x78, 0x9C, 0x42, 0xED, 0xDD, 0x00, 0x26, +0x25, 0xE0, 0x2C, 0x78, 0x2F, 0x1C, 0x64, 0x42, 0x40, 0x3F, 0x1A, 0xE0, +0x3E, 0x4B, 0xDA, 0x78, 0x80, 0x23, 0x12, 0x19, 0xDB, 0x05, 0xD2, 0xB2, +0x1A, 0x71, 0xFF, 0xF7, 0xA7, 0xFE, 0x2D, 0x78, 0x04, 0xA9, 0x65, 0x19, +0x05, 0xAA, 0x28, 0x1C, 0x03, 0xF0, 0xF8, 0xFD, 0x35, 0x49, 0x04, 0x9B, +0x4A, 0x5D, 0xFF, 0x2B, 0x00, 0xDD, 0xFF, 0x23, 0x9A, 0x42, 0x00, 0xDA, +0x1A, 0x1C, 0x4A, 0x55, 0x01, 0x34, 0x3D, 0x1C, 0x40, 0x35, 0x2B, 0x78, +0x9C, 0x42, 0xDF, 0xDD, 0x01, 0x36, 0x2F, 0x4A, 0x2B, 0x4D, 0x13, 0x78, +0x40, 0x35, 0x9E, 0x42, 0xD3, 0xDB, 0x01, 0xF0, 0xDF, 0xFF, 0x2C, 0x49, +0x2A, 0x78, 0x0D, 0x78, 0x2B, 0x49, 0x27, 0x48, 0x09, 0x78, 0x01, 0x23, +0x03, 0x91, 0x9B, 0x1A, 0x00, 0x21, 0x29, 0x4C, 0x10, 0x18, 0x94, 0x46, +0x11, 0xE0, 0xC6, 0x18, 0x72, 0x1E, 0x12, 0x78, 0xC7, 0x5C, 0x6A, 0x43, +0x02, 0x92, 0x03, 0x9A, 0x57, 0x43, 0x02, 0x9A, 0xD7, 0x19, 0x72, 0x78, +0x6A, 0x43, 0xBA, 0x18, 0x94, 0x42, 0x01, 0xDB, 0x94, 0xB2, 0x19, 0x1C, +0x01, 0x33, 0x9C, 0x45, 0xEB, 0xDC, 0x19, 0x4B, 0x1D, 0x4C, 0xDA, 0x78, +0x51, 0x18, 0xC9, 0xB2, 0x99, 0x70, 0x13, 0x4B, 0x18, 0x78, 0x00, 0x28, +0x05, 0xD1, 0x23, 0x78, 0x00, 0x2B, 0x02, 0xD0, 0x18, 0x49, 0x02, 0xF0, +0xB7, 0xFD, 0x23, 0x78, 0x00, 0x2B, 0x0B, 0xD0, 0x0D, 0x4B, 0x00, 0x20, +0x40, 0x33, 0x19, 0x78, 0x0C, 0x4A, 0x49, 0x00, 0x01, 0x31, 0xC9, 0xB2, +0x01, 0x23, 0x00, 0x90, 0x02, 0xF0, 0x50, 0xFD, 0x0E, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x06, 0xD0, 0x01, 0x21, 0x00, 0x20, 0x0D, 0x4A, 0x0B, 0x1C, +0x00, 0x90, 0x02, 0xF0, 0x45, 0xFD, 0x07, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, +0xE0, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x93, 0x01, 0x00, 0x20, +0xAA, 0x0A, 0x00, 0x20, 0x87, 0x0D, 0x00, 0x20, 0x54, 0x00, 0x00, 0x20, +0x55, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0x00, 0x00, 0xEB, 0x01, 0x00, 0x20, +0x1A, 0x59, 0x00, 0x00, 0xAC, 0x0A, 0x00, 0x20, 0x13, 0xB5, 0x24, 0x4B, +0x24, 0x4C, 0x1B, 0x68, 0x00, 0x2B, 0x0E, 0xD0, 0x23, 0x78, 0x00, 0x2B, +0x03, 0xD0, 0x00, 0x20, 0x21, 0x49, 0x02, 0xF0, 0x77, 0xFD, 0xFF, 0xF7, +0x6D, 0xFA, 0x23, 0x78, 0x00, 0x2B, 0x02, 0xD1, 0x02, 0xF0, 0x38, 0xF8, +0xFE, 0xE7, 0x23, 0x78, 0x00, 0x2B, 0x09, 0xD0, 0x1B, 0x4C, 0x23, 0x68, +0xDA, 0x00, 0x05, 0xD5, 0xFF, 0xF7, 0x5E, 0xFA, 0x22, 0x68, 0x19, 0x4B, +0x13, 0x40, 0x23, 0x60, 0x14, 0x4C, 0x23, 0x78, 0x00, 0x2B, 0x22, 0xD0, +0x14, 0x4B, 0x1B, 0x68, 0x5A, 0x01, 0x1E, 0xD5, 0x14, 0x49, 0x00, 0x20, +0x02, 0xF0, 0x56, 0xFD, 0x13, 0x4B, 0x14, 0x4A, 0x19, 0x88, 0x11, 0x80, +0x59, 0x88, 0x51, 0x80, 0x99, 0x88, 0x91, 0x80, 0xDB, 0x88, 0xD3, 0x80, +0x10, 0x4B, 0x1B, 0x78, 0x13, 0x81, 0x23, 0x78, 0x00, 0x2B, 0x05, 0xD0, +0x00, 0x20, 0x05, 0x21, 0x02, 0x23, 0x00, 0x90, 0x02, 0xF0, 0xE8, 0xFC, +0x05, 0x4B, 0x0B, 0x4A, 0x19, 0x68, 0x0A, 0x40, 0x1A, 0x60, 0x13, 0xBD, +0x0C, 0x1E, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0x20, 0x59, 0x00, 0x00, +0x58, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xEF, 0x27, 0x59, 0x00, 0x00, +0x04, 0x02, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, +0xFF, 0xFF, 0xFF, 0xFB, 0x10, 0xB5, 0x02, 0x28, 0x04, 0xD0, 0x03, 0x28, +0x45, 0xD0, 0x01, 0x28, 0x33, 0xD1, 0x15, 0xE0, 0xFF, 0xF7, 0xF6, 0xF9, +0x29, 0x4B, 0x2A, 0x4C, 0x40, 0x33, 0x1B, 0x78, 0x29, 0x49, 0x50, 0x22, +0x23, 0x70, 0x29, 0x48, 0x04, 0xF0, 0xA6, 0xF9, 0x28, 0x4B, 0x0D, 0x20, +0x1B, 0x68, 0x98, 0x47, 0xFF, 0xF7, 0xF4, 0xF9, 0x23, 0x78, 0x10, 0x2B, +0x1A, 0xD1, 0x14, 0xE0, 0xFF, 0xF7, 0xE0, 0xF9, 0x1E, 0x4B, 0x1F, 0x4C, +0x40, 0x33, 0x1B, 0x78, 0x21, 0x49, 0x50, 0x22, 0x23, 0x70, 0x1E, 0x48, +0x04, 0xF0, 0x90, 0xF9, 0x1D, 0x4B, 0x0C, 0x20, 0x1B, 0x68, 0x98, 0x47, +0xFF, 0xF7, 0xDE, 0xF9, 0x23, 0x78, 0x10, 0x2B, 0x04, 0xD1, 0x1B, 0x4B, +0xDA, 0x78, 0x9A, 0x70, 0x02, 0xF0, 0xD1, 0xFA, 0x02, 0xF0, 0x54, 0xFA, +0x20, 0xE0, 0x18, 0x4B, 0x1A, 0x78, 0x00, 0x2A, 0x05, 0xD0, 0x17, 0x4A, +0x11, 0x68, 0x01, 0x31, 0x11, 0x60, 0x00, 0x22, 0x1A, 0x70, 0x15, 0x4B, +0x1A, 0x68, 0x13, 0x2A, 0x05, 0xDD, 0x00, 0x22, 0x1A, 0x60, 0x0A, 0x4B, +0x10, 0x22, 0x1A, 0x70, 0x0C, 0xE0, 0x0F, 0x4B, 0x1A, 0x68, 0x3B, 0x2A, +0x08, 0xDD, 0x00, 0x22, 0x1A, 0x60, 0x0E, 0x4B, 0x01, 0x20, 0x1B, 0x68, +0x98, 0x47, 0x0D, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x10, 0xBD, 0xC0, 0x46, +0xAE, 0x09, 0x00, 0x20, 0x1D, 0x03, 0x00, 0x20, 0x4A, 0x74, 0x00, 0x00, +0x48, 0x0D, 0x00, 0x20, 0xF8, 0x01, 0x00, 0x20, 0x9A, 0x74, 0x00, 0x00, +0xAA, 0x0A, 0x00, 0x20, 0xC4, 0x01, 0x00, 0x20, 0xC0, 0x01, 0x00, 0x20, +0xBC, 0x01, 0x00, 0x20, 0x6C, 0x00, 0x00, 0x20, 0xE7, 0x01, 0x00, 0x20, +0x10, 0xB5, 0x0C, 0x4B, 0x01, 0x22, 0x99, 0x79, 0x00, 0x23, 0x00, 0xE0, +0x23, 0x1C, 0x5C, 0x1C, 0x10, 0x1C, 0xE4, 0xB2, 0x98, 0x40, 0x81, 0x42, +0xF8, 0xDA, 0x07, 0x4A, 0x07, 0x21, 0x13, 0x71, 0x80, 0x22, 0xD2, 0x05, +0x0B, 0x40, 0x19, 0x02, 0x10, 0x6C, 0x04, 0x4B, 0x03, 0x40, 0x0B, 0x43, +0x13, 0x64, 0x10, 0xBD, 0x48, 0x0D, 0x00, 0x20, 0x5C, 0x00, 0x00, 0x20, +0xFF, 0xF8, 0xFF, 0xFF, 0x06, 0x4B, 0x07, 0x22, 0xD9, 0x79, 0x80, 0x23, +0xDB, 0x05, 0x18, 0x6C, 0x11, 0x40, 0x04, 0x4A, 0x09, 0x02, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x64, 0x70, 0x47, 0xC0, 0x46, 0x48, 0x0D, 0x00, 0x20, +0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0xB5, 0x8D, 0xB0, 0x04, 0x90, 0xFF, 0xF7, +0xC9, 0xFF, 0xC7, 0x4B, 0xC7, 0x48, 0xDE, 0x78, 0x00, 0x21, 0x05, 0x96, +0x9C, 0x78, 0x07, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0xEE, 0x18, 0x76, 0x00, +0x31, 0x52, 0x00, 0x2B, 0xF8, 0xD1, 0x05, 0x92, 0x05, 0x9A, 0x05, 0x9E, +0x01, 0x3A, 0xD2, 0xB2, 0x00, 0x2E, 0x02, 0xD0, 0x23, 0x1C, 0x55, 0x01, +0xF3, 0xE7, 0x04, 0x9F, 0x00, 0x2F, 0x05, 0xD0, 0xBB, 0x4B, 0x05, 0x9E, +0x5B, 0x7B, 0x06, 0x96, 0x03, 0x93, 0x04, 0xE0, 0xB9, 0x4B, 0x02, 0x27, +0x9B, 0x78, 0x06, 0x97, 0x03, 0x93, 0x68, 0x46, 0x0C, 0x21, 0x0B, 0x56, +0xB2, 0x4C, 0x0B, 0x93, 0x5B, 0x42, 0x09, 0x93, 0xAA, 0xE0, 0x6A, 0x46, +0x18, 0x23, 0x9A, 0x56, 0xE6, 0x7A, 0x27, 0x1C, 0x02, 0x92, 0x0D, 0xE0, +0x30, 0x1C, 0x00, 0x21, 0x2A, 0x1C, 0x02, 0x9B, 0x02, 0xF0, 0x4C, 0xF9, +0x30, 0x1C, 0x01, 0x21, 0x2A, 0x1C, 0x02, 0x9B, 0x02, 0xF0, 0x46, 0xF9, +0x01, 0x36, 0xF6, 0xB2, 0xBB, 0x7A, 0xFA, 0x7A, 0xD2, 0x18, 0x3B, 0x1C, +0x96, 0x42, 0xEB, 0xDB, 0x04, 0x9E, 0x00, 0x2E, 0x00, 0xD1, 0x0E, 0x3D, +0x68, 0x46, 0x18, 0x21, 0x08, 0x56, 0x5E, 0x7B, 0x9E, 0x4F, 0x02, 0x90, +0x0D, 0xE0, 0x30, 0x1C, 0x00, 0x21, 0x2A, 0x1C, 0x02, 0x9B, 0x02, 0xF0, +0x2D, 0xF9, 0x30, 0x1C, 0x01, 0x21, 0x2A, 0x1C, 0x02, 0x9B, 0x02, 0xF0, +0x27, 0xF9, 0x01, 0x36, 0xF6, 0xB2, 0x7A, 0x7B, 0x3B, 0x7B, 0xD3, 0x18, +0x9E, 0x42, 0xEC, 0xDB, 0xFF, 0xF7, 0xAE, 0xFC, 0x96, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x18, 0x1C, 0x19, 0x1C, 0x0B, 0xAA, +0x00, 0x93, 0x02, 0xF0, 0xAD, 0xFB, 0x00, 0x25, 0x8C, 0x4E, 0x90, 0x4F, +0x0E, 0xE0, 0x3B, 0x78, 0x00, 0x2B, 0x09, 0xD0, 0x8E, 0x4B, 0xEA, 0x01, +0xD2, 0x18, 0x00, 0x23, 0xB1, 0x78, 0x01, 0x20, 0x00, 0x93, 0x02, 0x23, +0x02, 0xF0, 0x9C, 0xFB, 0x01, 0x35, 0xED, 0xB2, 0xF3, 0x78, 0x9D, 0x42, +0xED, 0xD3, 0x0B, 0x9A, 0xB6, 0x78, 0xD2, 0xB2, 0x02, 0x96, 0x07, 0x92, +0x80, 0x4D, 0x39, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x08, 0x9E, 0x99, 0x1C, +0x71, 0x18, 0x82, 0x4F, 0x49, 0x00, 0xCE, 0x5B, 0xD1, 0x18, 0x48, 0x00, +0x40, 0x5B, 0xB7, 0xB2, 0xB8, 0x42, 0x14, 0xDC, 0xC0, 0x1B, 0x01, 0x1C, +0x80, 0x31, 0x01, 0xDA, 0x80, 0x20, 0x40, 0x42, 0xD7, 0x18, 0x7F, 0x28, +0x00, 0xDD, 0x7F, 0x20, 0x79, 0x49, 0x78, 0x54, 0xD1, 0x18, 0x48, 0x00, +0x2E, 0x52, 0x1C, 0x27, 0x6E, 0x46, 0x77, 0x48, 0xBE, 0x5D, 0x0E, 0x54, +0x13, 0xE0, 0x04, 0x9E, 0x00, 0x2E, 0x10, 0xD0, 0x74, 0x4E, 0xB0, 0x42, +0x08, 0xD0, 0x71, 0x4E, 0x8E, 0x57, 0x80, 0x19, 0x87, 0x42, 0x03, 0xDA, +0x6F, 0x48, 0x0E, 0x5C, 0x01, 0x36, 0x0E, 0x54, 0xD1, 0x18, 0x01, 0x27, +0x49, 0x00, 0x7F, 0x42, 0x6F, 0x52, 0x00, 0x2B, 0xC6, 0xD1, 0x63, 0x46, +0x5E, 0x1E, 0xF6, 0xB2, 0x00, 0x2B, 0x06, 0xD0, 0x72, 0x1C, 0x92, 0x01, +0x08, 0x92, 0x02, 0x9B, 0x72, 0x01, 0xB4, 0x46, 0xF1, 0xE7, 0x0B, 0x9B, +0x01, 0x3B, 0x0B, 0x93, 0x0B, 0x9D, 0x09, 0x9E, 0xB5, 0x42, 0x00, 0xDB, +0x4F, 0xE7, 0x04, 0x9F, 0x00, 0x2F, 0x45, 0xD0, 0xA0, 0x78, 0xE3, 0x78, +0x04, 0x90, 0x61, 0x78, 0x56, 0x4A, 0x06, 0x91, 0x24, 0x78, 0x02, 0x94, +0x11, 0x7C, 0xD0, 0x7A, 0x5B, 0x4C, 0x08, 0x18, 0xC0, 0xB2, 0x07, 0x90, +0x12, 0x7B, 0x89, 0x18, 0xC9, 0xB2, 0x08, 0x91, 0x55, 0x4A, 0x28, 0xE0, +0x03, 0x9E, 0x01, 0x3B, 0xDB, 0xB2, 0x00, 0x2E, 0x01, 0xD1, 0xC7, 0x18, +0xD6, 0x55, 0x06, 0x9E, 0xB1, 0x42, 0x02, 0xD2, 0x02, 0x9F, 0xBB, 0x42, +0x0C, 0xD3, 0xEF, 0x18, 0xC6, 0x18, 0x09, 0x97, 0x97, 0x5D, 0xBC, 0x46, +0x09, 0x9F, 0xE7, 0x5D, 0xBC, 0x44, 0x08, 0x9F, 0xBC, 0x44, 0x67, 0x46, +0x97, 0x55, 0x0B, 0xE0, 0xEF, 0x18, 0xC6, 0x18, 0x09, 0x97, 0x97, 0x5D, +0xBC, 0x46, 0x09, 0x9F, 0xE7, 0x5D, 0xBC, 0x44, 0x07, 0x9F, 0xBC, 0x44, +0x67, 0x46, 0x97, 0x55, 0x00, 0x2B, 0xD7, 0xD1, 0x0B, 0x1C, 0x59, 0x1E, +0xC9, 0xB2, 0x00, 0x2B, 0x3E, 0xD0, 0x26, 0x25, 0x04, 0x9B, 0x48, 0x01, +0x4D, 0x43, 0xF3, 0xE7, 0x63, 0x7C, 0xE2, 0x79, 0x07, 0x25, 0x9A, 0x18, +0x03, 0x92, 0x34, 0x4A, 0xA0, 0x7B, 0x02, 0x21, 0x52, 0x5E, 0x26, 0x79, +0xAD, 0x1A, 0x6D, 0x00, 0x86, 0x19, 0xED, 0xB2, 0x34, 0x49, 0x84, 0x46, +0x09, 0xE0, 0xB8, 0x18, 0x44, 0x5C, 0x01, 0x32, 0x2C, 0x19, 0x44, 0x54, +0xD2, 0xB2, 0xB2, 0x42, 0xF7, 0xDB, 0x01, 0x33, 0xDB, 0xB2, 0x03, 0x9A, +0x93, 0x42, 0x02, 0xDA, 0x62, 0x46, 0x5F, 0x01, 0xF5, 0xE7, 0x23, 0x4A, +0x2A, 0x49, 0x10, 0x7C, 0xD3, 0x7B, 0x56, 0x79, 0x95, 0x79, 0x9E, 0x19, +0x45, 0x19, 0x84, 0x46, 0x09, 0xE0, 0xB8, 0x18, 0x44, 0x5C, 0x01, 0x32, +0x0E, 0x3C, 0x44, 0x54, 0xD2, 0xB2, 0xAA, 0x42, 0xF7, 0xDB, 0x01, 0x33, +0xDB, 0xB2, 0xB3, 0x42, 0x02, 0xDA, 0x62, 0x46, 0x5F, 0x01, 0xF6, 0xE7, +0x1A, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x13, 0xD0, 0x05, 0x20, 0x1F, 0x49, +0x02, 0xF0, 0x10, 0xFB, 0x0E, 0xE0, 0x2B, 0x78, 0x00, 0x2B, 0x08, 0xD0, +0x18, 0x4B, 0x72, 0x01, 0xA1, 0x78, 0xD2, 0x18, 0x05, 0x20, 0x01, 0x23, +0x00, 0x93, 0x02, 0xF0, 0xAB, 0xFA, 0x01, 0x36, 0xF6, 0xB2, 0x02, 0xE0, +0x0A, 0x4C, 0x0E, 0x4D, 0x05, 0x9E, 0xE3, 0x78, 0xB3, 0x42, 0xEA, 0xD8, +0x00, 0x21, 0x01, 0x20, 0x0A, 0x1C, 0x40, 0x42, 0x02, 0x23, 0x02, 0xF0, +0x01, 0xF8, 0x01, 0x20, 0x40, 0x42, 0x01, 0x21, 0x00, 0x22, 0x02, 0x23, +0x01, 0xF0, 0xFA, 0xFF, 0xA4, 0x78, 0x25, 0xE0, 0x0A, 0x03, 0x00, 0x20, +0xF8, 0x03, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x04, 0x02, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0x84, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, +0x64, 0x0E, 0x00, 0x20, 0xB3, 0x0A, 0x00, 0x20, 0xFF, 0xFF, 0x00, 0x00, +0x36, 0x75, 0x00, 0x00, 0x2E, 0x59, 0x00, 0x00, 0x01, 0x3C, 0x00, 0x21, +0xE4, 0xB2, 0x0A, 0x1C, 0x20, 0x1C, 0x01, 0x23, 0x01, 0xF0, 0xD8, 0xFF, +0x01, 0x21, 0x20, 0x1C, 0x00, 0x22, 0x0B, 0x1C, 0x01, 0xF0, 0xD2, 0xFF, +0x00, 0x2C, 0xEF, 0xD1, 0xFF, 0xF7, 0x30, 0xFE, 0x0D, 0xB0, 0xF0, 0xBD, +0x08, 0xB5, 0x03, 0xF0, 0xC5, 0xFD, 0x05, 0x4B, 0x01, 0x20, 0x1B, 0x68, +0x98, 0x47, 0x01, 0x20, 0x04, 0xF0, 0x22, 0xF9, 0x01, 0xF0, 0xD6, 0xFD, +0x08, 0xBD, 0xC0, 0x46, 0xF8, 0x01, 0x00, 0x20, 0xF7, 0xB5, 0x2C, 0x4A, +0x00, 0x20, 0x10, 0x60, 0x2B, 0x4A, 0x2C, 0x4E, 0x11, 0x8C, 0x2C, 0x4A, +0x11, 0x60, 0x72, 0x1D, 0xD2, 0x7F, 0xF1, 0x7D, 0x50, 0x1E, 0x44, 0x42, +0x60, 0x41, 0x29, 0x4C, 0x08, 0x1A, 0x00, 0x90, 0x20, 0x60, 0xB0, 0x1D, +0xC5, 0x7F, 0x37, 0x7E, 0x6B, 0x1E, 0x58, 0x42, 0x58, 0x41, 0x3B, 0x1A, +0x01, 0x93, 0x63, 0x60, 0x01, 0x2A, 0x02, 0xD1, 0x00, 0x20, 0x20, 0x81, +0x05, 0xE0, 0x26, 0x23, 0xF0, 0x5E, 0x49, 0x00, 0x03, 0xF0, 0xBA, 0xFE, +0x20, 0x81, 0x01, 0x2D, 0x02, 0xD1, 0x00, 0x23, 0x63, 0x81, 0x05, 0xE0, +0x28, 0x23, 0xF0, 0x5E, 0x79, 0x00, 0x03, 0xF0, 0xAF, 0xFE, 0x60, 0x81, +0x15, 0x4F, 0x01, 0x9B, 0x28, 0x20, 0x3E, 0x5E, 0x59, 0x00, 0x70, 0x00, +0x80, 0x19, 0x03, 0xF0, 0xA5, 0xFE, 0x40, 0x43, 0x12, 0x4C, 0x43, 0x00, +0x80, 0x00, 0xE3, 0x60, 0xC3, 0x18, 0x23, 0x61, 0x26, 0x20, 0x3D, 0x5E, +0x00, 0x9B, 0x68, 0x00, 0x59, 0x00, 0x40, 0x19, 0x03, 0xF0, 0x96, 0xFE, +0x2C, 0x37, 0x60, 0x61, 0xA0, 0x61, 0x3B, 0x78, 0x00, 0x2B, 0x02, 0xD1, +0xE6, 0x61, 0x25, 0x62, 0x01, 0xE0, 0xE5, 0x61, 0x26, 0x62, 0x07, 0x4B, +0x01, 0x22, 0x52, 0x42, 0x5A, 0x60, 0xF7, 0xBD, 0x9C, 0x0D, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x20, 0x02, 0x00, 0x20, +0x24, 0x09, 0x00, 0x20, 0xCC, 0x00, 0x00, 0x20, 0xF0, 0xB5, 0x24, 0x4B, +0x87, 0xB0, 0x1E, 0x7E, 0xDB, 0x7D, 0x72, 0x1C, 0xD9, 0x1C, 0x02, 0x33, +0x03, 0x93, 0x05, 0x92, 0x00, 0x23, 0x20, 0x4A, 0x04, 0x91, 0x18, 0x1C, +0x05, 0x9C, 0xE5, 0x1A, 0xEF, 0x01, 0x01, 0x97, 0xBC, 0x5A, 0xB8, 0x52, +0x04, 0x9C, 0xAD, 0x01, 0x29, 0x19, 0x4F, 0x00, 0xBC, 0x5A, 0x1A, 0x4C, +0xB8, 0x52, 0x00, 0x27, 0x2F, 0x55, 0x0F, 0x55, 0x01, 0x99, 0x18, 0x4F, +0x01, 0x33, 0xCF, 0x19, 0x02, 0x97, 0x39, 0x88, 0x38, 0x80, 0x03, 0x99, +0x6F, 0x18, 0x79, 0x00, 0x01, 0x91, 0x89, 0x5A, 0x01, 0x99, 0x88, 0x52, +0x12, 0x49, 0x6D, 0x18, 0x00, 0x21, 0x29, 0x70, 0x39, 0x55, 0xF7, 0x1A, +0x0C, 0x4D, 0x01, 0x37, 0xD8, 0xDA, 0x00, 0x22, 0x01, 0x36, 0x03, 0x9B, +0x11, 0x1C, 0xB6, 0x01, 0x58, 0x00, 0x2F, 0x5A, 0x2A, 0x52, 0xF0, 0x18, +0x47, 0x00, 0xEC, 0x5B, 0xEA, 0x53, 0x06, 0x4F, 0xF9, 0x54, 0x01, 0x3B, +0x39, 0x54, 0x01, 0x2B, 0xF2, 0xD1, 0x07, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, +0xAE, 0x09, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x40, +0x02, 0x40, 0x00, 0x40, 0x01, 0x20, 0x00, 0x40, 0xF7, 0xB5, 0x0D, 0x4B, +0x19, 0x7E, 0xDE, 0x7D, 0x48, 0x1C, 0x01, 0x36, 0x00, 0x23, 0x01, 0x90, +0x01, 0x9C, 0x32, 0x1C, 0xE7, 0x1A, 0xBF, 0x01, 0x95, 0x1C, 0xAC, 0x46, +0xBC, 0x44, 0x07, 0x4C, 0x00, 0x25, 0x60, 0x46, 0x01, 0x3A, 0x05, 0x55, +0x50, 0x1C, 0xF5, 0xDA, 0x01, 0x33, 0xCA, 0x1A, 0x01, 0x32, 0xED, 0xDA, +0xF7, 0xBD, 0xC0, 0x46, 0xAE, 0x09, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, +0x00, 0xB5, 0x0D, 0x4B, 0x08, 0x22, 0x9B, 0x5E, 0x0C, 0x4A, 0x11, 0x1C, +0x35, 0x31, 0x09, 0x78, 0x12, 0x7F, 0x4B, 0x43, 0x52, 0xB2, 0x9B, 0x11, +0x93, 0x42, 0x00, 0xDA, 0x13, 0x1C, 0x08, 0x4A, 0x13, 0x60, 0x80, 0x22, +0xD2, 0x05, 0x1B, 0x05, 0x19, 0x09, 0x90, 0x69, 0x05, 0x4B, 0x03, 0x40, +0x0B, 0x43, 0x93, 0x61, 0x00, 0xBD, 0xC0, 0x46, 0x70, 0x01, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x38, 0x0D, 0x00, 0x20, 0xFF, 0xFF, 0x00, 0xF0, +0xF0, 0xB5, 0xA9, 0x4A, 0xA9, 0x48, 0x11, 0x68, 0x07, 0x68, 0x93, 0xB0, +0x8C, 0x46, 0x0D, 0x22, 0x00, 0x21, 0x7F, 0x25, 0xFF, 0x24, 0x01, 0x97, +0x90, 0x00, 0x83, 0x18, 0xA4, 0x4E, 0x5B, 0x00, 0xF3, 0x18, 0x99, 0x87, +0x00, 0x27, 0x38, 0x33, 0x1F, 0x72, 0x67, 0x46, 0x39, 0x50, 0x01, 0x3A, +0x01, 0x9F, 0xD2, 0xB2, 0x39, 0x50, 0x00, 0x26, 0xDD, 0x72, 0x5D, 0x72, +0x1C, 0x73, 0x9C, 0x72, 0xD9, 0x80, 0xFF, 0x2A, 0xE8, 0xD1, 0x9B, 0x4A, +0x9B, 0x4B, 0x11, 0x7E, 0x98, 0x68, 0x9B, 0x4C, 0x97, 0x4D, 0x01, 0x39, +0x04, 0x90, 0xA6, 0x81, 0x2E, 0x60, 0x88, 0x42, 0x02, 0xDA, 0x01, 0x30, +0x04, 0x90, 0x98, 0x60, 0xDE, 0x68, 0x11, 0x96, 0x00, 0x2E, 0x02, 0xDD, +0x01, 0x3E, 0x11, 0x96, 0xDE, 0x60, 0xD1, 0x7D, 0x1A, 0x68, 0x01, 0x39, +0x8A, 0x42, 0x01, 0xDA, 0x01, 0x32, 0x1A, 0x60, 0x5A, 0x68, 0x00, 0x2A, +0x01, 0xDD, 0x01, 0x3A, 0x5A, 0x60, 0x04, 0x9F, 0x11, 0x98, 0x87, 0x42, +0x00, 0xDA, 0xA3, 0xE0, 0x19, 0x68, 0x5B, 0x68, 0x84, 0x4A, 0x06, 0x93, +0x88, 0x4B, 0x12, 0x68, 0x1B, 0x68, 0x86, 0x4C, 0x0D, 0x93, 0x80, 0x4B, +0x10, 0x91, 0x1B, 0x68, 0x09, 0x92, 0x0A, 0x93, 0xA4, 0x89, 0x84, 0x48, +0x0C, 0x94, 0x06, 0x9D, 0x10, 0x9E, 0xB5, 0x42, 0x00, 0xDD, 0x81, 0xE0, +0x04, 0x9A, 0x6F, 0x46, 0x10, 0x21, 0x01, 0x32, 0xCF, 0x5D, 0x92, 0x01, +0x33, 0x1C, 0x02, 0x92, 0x07, 0x97, 0x05, 0xE0, 0x00, 0x27, 0x2F, 0x54, +0x06, 0x9F, 0x01, 0x3B, 0x9F, 0x42, 0x71, 0xDC, 0x02, 0x99, 0x9C, 0x1C, +0x0D, 0x19, 0x2A, 0x5C, 0x77, 0x4E, 0x69, 0x00, 0x89, 0x5B, 0x0E, 0x2A, +0xF0, 0xD8, 0x0D, 0x9D, 0x49, 0x1B, 0x00, 0x2A, 0x00, 0xD1, 0x71, 0xE0, +0x01, 0x3A, 0xD4, 0xB2, 0x09, 0x9E, 0x04, 0x9F, 0xA2, 0x00, 0xB5, 0x18, +0x4F, 0x43, 0x2E, 0x68, 0xB4, 0x46, 0x67, 0x44, 0x2F, 0x60, 0x0A, 0x9D, +0x0E, 0x1C, 0xAF, 0x18, 0x3D, 0x68, 0x5E, 0x43, 0xAC, 0x46, 0x15, 0x19, +0x6D, 0x00, 0x01, 0x95, 0x62, 0x4D, 0x66, 0x44, 0xAC, 0x46, 0x01, 0x9D, +0x3E, 0x60, 0xAC, 0x44, 0x65, 0x46, 0xAF, 0x8F, 0x38, 0x35, 0x2E, 0x7A, +0xCF, 0x19, 0x03, 0x96, 0x09, 0x26, 0xAE, 0x57, 0xAF, 0x80, 0x01, 0x96, +0x0C, 0x9E, 0x6F, 0x46, 0xB4, 0x46, 0x01, 0x26, 0xB4, 0x44, 0x03, 0x9E, +0x01, 0x36, 0x03, 0x96, 0x66, 0x46, 0xB6, 0xB2, 0x0C, 0x96, 0x0C, 0x26, +0xF7, 0x5D, 0x04, 0x9E, 0x2F, 0x72, 0x01, 0x9F, 0xBE, 0x42, 0x00, 0xDA, +0x6E, 0x72, 0x51, 0x4E, 0x15, 0x19, 0x6D, 0x00, 0x75, 0x19, 0x38, 0x35, +0x0A, 0x26, 0xAE, 0x57, 0x04, 0x9F, 0xB7, 0x42, 0x00, 0xDD, 0xAF, 0x72, +0x4B, 0x4E, 0x15, 0x19, 0x6D, 0x00, 0x75, 0x19, 0x38, 0x35, 0x0B, 0x26, +0xAE, 0x57, 0xB3, 0x42, 0x00, 0xDA, 0xEB, 0x72, 0x15, 0x19, 0x46, 0x4F, +0x6D, 0x00, 0x7D, 0x19, 0x38, 0x35, 0x0C, 0x26, 0xAE, 0x57, 0xB3, 0x42, +0x00, 0xDD, 0x2B, 0x73, 0x12, 0x19, 0x41, 0x4C, 0x52, 0x00, 0xA2, 0x18, +0x3E, 0x25, 0x54, 0x5F, 0x38, 0x32, 0xA1, 0x42, 0x8E, 0xDD, 0x06, 0x9F, +0x01, 0x3B, 0xD1, 0x80, 0x9F, 0x42, 0x8D, 0xDD, 0x04, 0x99, 0x11, 0x9A, +0x01, 0x39, 0x04, 0x91, 0x91, 0x42, 0x00, 0xDB, 0x71, 0xE7, 0x6B, 0x46, +0x30, 0x24, 0xE4, 0x5A, 0x38, 0x4B, 0x9C, 0x81, 0x13, 0xB0, 0xF0, 0xBD, +0x02, 0x39, 0xCA, 0x43, 0xD2, 0x17, 0x11, 0x40, 0x03, 0x91, 0x04, 0x9E, +0x03, 0x9F, 0x71, 0x43, 0x5F, 0x43, 0x0E, 0x91, 0x00, 0x25, 0xD9, 0xB2, +0x0F, 0x97, 0x05, 0x91, 0x03, 0x22, 0x01, 0x95, 0x9C, 0x46, 0x08, 0x94, +0x31, 0x4E, 0x32, 0x4F, 0x07, 0x9C, 0xB1, 0x5C, 0x05, 0x9D, 0xBB, 0x5C, +0x61, 0x18, 0xEB, 0x18, 0x49, 0xB2, 0x01, 0x31, 0x5B, 0xB2, 0x89, 0x01, +0x02, 0x33, 0xCB, 0x18, 0x1C, 0x5C, 0x65, 0xB2, 0x69, 0x1E, 0x0D, 0x29, +0x27, 0xD8, 0x08, 0x9B, 0x02, 0x9F, 0x8E, 0x00, 0xFF, 0x18, 0x0B, 0x97, +0x09, 0x9F, 0x71, 0x18, 0xBB, 0x19, 0x0A, 0x9F, 0x49, 0x00, 0xBF, 0x19, +0x1B, 0x4E, 0x00, 0x97, 0x01, 0x9F, 0x71, 0x18, 0x38, 0x31, 0x00, 0x2F, +0x1A, 0xD1, 0xE4, 0xB2, 0x01, 0x94, 0x0B, 0x9D, 0x0E, 0x34, 0xE4, 0xB2, +0x2C, 0x54, 0x1C, 0x68, 0x0E, 0x9E, 0x00, 0x9F, 0xA4, 0x19, 0x1C, 0x60, +0x3B, 0x68, 0x0F, 0x9C, 0x03, 0x9D, 0x1B, 0x19, 0x3B, 0x60, 0x8C, 0x88, +0x0B, 0x7A, 0x2C, 0x19, 0x01, 0x33, 0x8C, 0x80, 0x0B, 0x72, 0x53, 0x1E, +0x00, 0x2A, 0x10, 0xD0, 0xDA, 0xB2, 0xBF, 0xE7, 0x02, 0x9E, 0x08, 0x99, +0x01, 0x9C, 0x73, 0x18, 0x1F, 0x2C, 0xF4, 0xD0, 0xAC, 0x42, 0xF2, 0xD0, +0x1F, 0x25, 0x1F, 0x26, 0x1D, 0x54, 0x01, 0x96, 0x53, 0x1E, 0x00, 0x2A, +0xEE, 0xD1, 0x63, 0x46, 0x18, 0xE7, 0xC0, 0x46, 0x44, 0x00, 0x00, 0x20, +0x48, 0x00, 0x00, 0x20, 0x24, 0x02, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0xE4, 0x10, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, 0x38, 0x0D, 0x00, 0x20, +0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0xF8, 0x59, 0x00, 0x00, +0xF4, 0x59, 0x00, 0x00, 0xF0, 0xB5, 0x89, 0xB0, 0x0F, 0x23, 0x46, 0x49, +0xFF, 0x22, 0x02, 0xE0, 0x58, 0x18, 0x01, 0x38, 0x02, 0x70, 0x01, 0x3B, +0x00, 0x2B, 0xF9, 0xD1, 0x42, 0x4B, 0xD8, 0x68, 0x19, 0x68, 0x9A, 0x68, +0x5B, 0x68, 0x01, 0x90, 0x03, 0x93, 0x40, 0x4B, 0x02, 0x91, 0x1B, 0x68, +0x04, 0x93, 0x3F, 0x4B, 0x5B, 0x7F, 0x06, 0x93, 0x68, 0xE0, 0x07, 0x9B, +0x88, 0x1C, 0x3D, 0x4A, 0x18, 0x18, 0x83, 0x5C, 0x5B, 0xB2, 0x1F, 0x2B, +0x5A, 0xD1, 0x3B, 0x4A, 0x40, 0x00, 0x82, 0x5A, 0x04, 0x9D, 0x04, 0x20, +0x52, 0x1B, 0x05, 0x92, 0x38, 0x4A, 0x01, 0x38, 0xC0, 0xB2, 0x14, 0x56, +0x37, 0x4A, 0x64, 0x44, 0x12, 0x56, 0x01, 0x34, 0x8A, 0x18, 0xA4, 0x01, +0x02, 0x32, 0x31, 0x4E, 0xA2, 0x18, 0xB4, 0x5C, 0x0E, 0x2C, 0x41, 0xD8, +0x1F, 0x2B, 0x3E, 0xD0, 0xA3, 0x42, 0x3D, 0xD0, 0x00, 0x2C, 0x3B, 0xD0, +0x0A, 0x27, 0x5D, 0x1E, 0x7D, 0x43, 0x2E, 0x4A, 0x2D, 0x4E, 0x55, 0x19, +0x62, 0x1E, 0x7A, 0x43, 0xB2, 0x18, 0x3E, 0x27, 0xEE, 0x5F, 0x3E, 0x27, +0xD5, 0x5F, 0x1A, 0x1C, 0xAE, 0x42, 0x00, 0xDD, 0x22, 0x1C, 0x0A, 0x25, +0x01, 0x3A, 0x6A, 0x43, 0x25, 0x4E, 0x06, 0x9D, 0xB2, 0x18, 0x3E, 0x27, +0xD2, 0x5F, 0x05, 0x9E, 0x6A, 0x43, 0x92, 0x11, 0x96, 0x42, 0x1D, 0xDD, +0x9C, 0x42, 0x02, 0xD9, 0x1A, 0x1C, 0x23, 0x1C, 0x14, 0x1C, 0x5E, 0x1E, +0x15, 0x4A, 0xF6, 0xB2, 0x97, 0x5D, 0x00, 0x25, 0x00, 0x97, 0x6F, 0x46, +0x7D, 0x57, 0x01, 0x3C, 0xE4, 0xB2, 0x6F, 0x1C, 0x09, 0xD0, 0xA5, 0x42, +0x03, 0xDA, 0x6D, 0x46, 0x2D, 0x78, 0x15, 0x55, 0x06, 0xE0, 0xA5, 0x42, +0x04, 0xDD, 0xE4, 0xB2, 0x54, 0x55, 0x94, 0x55, 0x00, 0xE0, 0x23, 0x1C, +0x00, 0x28, 0xAB, 0xD1, 0x01, 0x39, 0x03, 0x9E, 0xB1, 0x42, 0x98, 0xDA, +0x62, 0x46, 0x01, 0x3A, 0x01, 0x9F, 0xBA, 0x42, 0x05, 0xDB, 0x53, 0x1C, +0x9B, 0x01, 0x02, 0x99, 0x07, 0x93, 0x94, 0x46, 0xF1, 0xE7, 0x09, 0xB0, +0xF0, 0xBD, 0xC0, 0x46, 0xEC, 0x02, 0x00, 0x20, 0xE4, 0x10, 0x00, 0x20, +0x38, 0x0D, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, +0x00, 0x40, 0x00, 0x40, 0xF8, 0x59, 0x00, 0x00, 0xF4, 0x59, 0x00, 0x00, +0x24, 0x02, 0x00, 0x20, 0xF0, 0xB5, 0xD4, 0x4A, 0x8D, 0xB0, 0x11, 0x68, +0x00, 0x23, 0xD0, 0x18, 0xBE, 0x30, 0x00, 0x24, 0x00, 0x5F, 0x0A, 0x3B, +0x44, 0x1E, 0xA0, 0x41, 0x1D, 0x1C, 0x09, 0x18, 0x8C, 0x35, 0xF4, 0xD1, +0xCD, 0x4B, 0x11, 0x60, 0x1B, 0x68, 0xBE, 0x32, 0x03, 0x93, 0xCC, 0x4B, +0x0E, 0x24, 0x1B, 0x68, 0x05, 0x93, 0xCB, 0x4E, 0x01, 0x3C, 0x33, 0x57, +0x5F, 0x1C, 0x01, 0xD1, 0x73, 0xE0, 0x03, 0x1C, 0xC7, 0x4D, 0xE8, 0x56, +0x46, 0x1C, 0xFA, 0xD1, 0x2B, 0x55, 0x5F, 0x1C, 0x6B, 0xD0, 0x03, 0x98, +0x9D, 0x00, 0x46, 0x19, 0x37, 0x68, 0xA0, 0x00, 0xBC, 0x46, 0x03, 0x9F, +0x3F, 0x58, 0xBC, 0x44, 0x67, 0x46, 0x37, 0x60, 0x05, 0x9E, 0x05, 0x9F, +0x75, 0x19, 0x2E, 0x68, 0x38, 0x58, 0xB9, 0x4F, 0x30, 0x18, 0x0A, 0x26, +0x28, 0x60, 0x30, 0x1C, 0x58, 0x43, 0x38, 0x18, 0x38, 0x30, 0x09, 0x27, +0xC7, 0x57, 0x55, 0x79, 0xBC, 0x46, 0x6F, 0xB2, 0xBC, 0x45, 0x00, 0xDD, +0x45, 0x72, 0x5E, 0x43, 0xB0, 0x4D, 0x90, 0x79, 0xAE, 0x19, 0x38, 0x36, +0x0A, 0x27, 0xF7, 0x57, 0x45, 0xB2, 0xAF, 0x42, 0x00, 0xDA, 0xB0, 0x72, +0xD6, 0x79, 0xAB, 0x4F, 0x06, 0x96, 0x0A, 0x26, 0x30, 0x1C, 0x58, 0x43, +0x38, 0x18, 0x38, 0x30, 0x0B, 0x25, 0x45, 0x57, 0xAC, 0x46, 0x6D, 0x46, +0x18, 0x35, 0x2D, 0x78, 0x6D, 0xB2, 0xAC, 0x45, 0x03, 0xDD, 0x6F, 0x46, +0x18, 0x25, 0xEF, 0x5D, 0xC7, 0x72, 0x5E, 0x43, 0xA0, 0x4D, 0x10, 0x7A, +0xAF, 0x19, 0x38, 0x37, 0x0C, 0x26, 0xBE, 0x57, 0x45, 0xB2, 0xAE, 0x42, +0x00, 0xDA, 0x38, 0x73, 0x0A, 0x20, 0x58, 0x43, 0x56, 0x88, 0x9A, 0x4F, +0x06, 0x96, 0x38, 0x18, 0x3E, 0x26, 0x85, 0x5F, 0x18, 0x26, 0xAC, 0x46, +0x6D, 0x46, 0x75, 0x5F, 0x38, 0x30, 0x0A, 0x26, 0xAC, 0x45, 0x03, 0xDA, +0x6F, 0x46, 0x18, 0x25, 0xEF, 0x5B, 0xC7, 0x80, 0x5E, 0x43, 0x91, 0x48, +0x01, 0x39, 0x87, 0x19, 0xBB, 0x8F, 0x10, 0x88, 0xC3, 0x18, 0xBB, 0x87, +0x38, 0x37, 0x10, 0x79, 0x3B, 0x7A, 0xC3, 0x18, 0x3B, 0x72, 0x0A, 0x3A, +0x00, 0x2C, 0x00, 0xD0, 0x81, 0xE7, 0x89, 0x4F, 0x26, 0x1C, 0x3D, 0x1C, +0x3C, 0x35, 0x03, 0x95, 0x39, 0x60, 0x25, 0x1C, 0x88, 0x48, 0x00, 0x22, +0x33, 0x18, 0x9A, 0x56, 0x01, 0x32, 0x19, 0xD1, 0x1D, 0x70, 0xB5, 0x42, +0x12, 0xD0, 0x82, 0x4B, 0xB1, 0x00, 0x1A, 0x68, 0xAB, 0x00, 0x50, 0x58, +0xD0, 0x50, 0x80, 0x4A, 0x7D, 0x48, 0x12, 0x68, 0x51, 0x58, 0xD1, 0x50, +0x0A, 0x22, 0x13, 0x1C, 0x6B, 0x43, 0xC0, 0x18, 0x3C, 0x30, 0x03, 0x99, +0x03, 0xF0, 0x7E, 0xFB, 0x3B, 0x68, 0x01, 0x35, 0x9D, 0x42, 0x05, 0xDA, +0x03, 0x99, 0x01, 0x36, 0x0A, 0x31, 0x03, 0x91, 0x0E, 0x2E, 0xD9, 0xD1, +0x76, 0x4B, 0x1B, 0x68, 0xDA, 0x06, 0x3B, 0xD5, 0x75, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x03, 0xD0, 0x04, 0x20, 0x74, 0x49, 0x01, 0xF0, 0xD4, 0xFE, +0x00, 0x25, 0x73, 0x4E, 0x2C, 0xE0, 0x69, 0x1C, 0x89, 0x01, 0x33, 0x68, +0x77, 0x68, 0x71, 0x4A, 0x03, 0x91, 0xA4, 0x46, 0x12, 0xE0, 0x03, 0x9C, +0x99, 0x1C, 0x61, 0x18, 0x88, 0x5C, 0x40, 0xB2, 0x44, 0x1E, 0x0D, 0x2C, +0x09, 0xD8, 0x66, 0x4C, 0x20, 0x18, 0x01, 0x38, 0x00, 0x78, 0x40, 0xB2, +0x44, 0x1C, 0x02, 0xD0, 0x01, 0x30, 0xC0, 0xB2, 0x88, 0x54, 0x01, 0x3B, +0xBB, 0x42, 0xEA, 0xDA, 0x61, 0x4B, 0x64, 0x46, 0x1B, 0x78, 0x00, 0x2B, +0x09, 0xD0, 0x63, 0x4B, 0x63, 0x4F, 0xAA, 0x01, 0xD9, 0x7D, 0xD2, 0x19, +0x01, 0x23, 0x04, 0x20, 0x00, 0x93, 0x01, 0xF0, 0x4D, 0xFE, 0x01, 0x35, +0x5D, 0x4F, 0x3B, 0x7E, 0x9D, 0x42, 0xCE, 0xDB, 0x5D, 0x4B, 0x1B, 0x68, +0x00, 0x2B, 0x10, 0xDD, 0x5C, 0x4B, 0x5D, 0x4A, 0x99, 0x89, 0x11, 0x80, +0x1B, 0x89, 0x53, 0x80, 0x52, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, +0x01, 0x23, 0x02, 0x21, 0x00, 0x93, 0x17, 0x20, 0x0B, 0x1C, 0x01, 0xF0, +0x33, 0xFE, 0x48, 0x4B, 0x55, 0x48, 0x1D, 0x1C, 0x40, 0xCD, 0x4F, 0x49, +0x07, 0x96, 0x47, 0x89, 0x08, 0x97, 0x0A, 0x8D, 0x47, 0x68, 0x16, 0xB2, +0x05, 0x96, 0x86, 0x69, 0x09, 0x97, 0xB7, 0xB2, 0xD2, 0x1B, 0x04, 0x97, +0x92, 0xB2, 0x31, 0x31, 0x09, 0x78, 0x0A, 0x92, 0x3E, 0x4A, 0x00, 0x20, +0x06, 0x91, 0x17, 0x68, 0x03, 0x90, 0x2F, 0xE0, 0x03, 0x9A, 0x0A, 0x23, +0x53, 0x43, 0x01, 0xCF, 0x05, 0x99, 0x48, 0x43, 0x37, 0x49, 0xCB, 0x18, +0x3C, 0x22, 0x99, 0x5E, 0x09, 0x9B, 0x59, 0x43, 0x03, 0xF0, 0x94, 0xFA, +0x08, 0x99, 0x42, 0x4A, 0x08, 0x18, 0x13, 0x78, 0x80, 0xB2, 0x28, 0x80, +0x00, 0x2B, 0x15, 0xD1, 0x00, 0xB2, 0xB0, 0x42, 0x07, 0xDA, 0x06, 0x9B, +0x80, 0x1B, 0x58, 0x43, 0x04, 0x99, 0x80, 0x11, 0x08, 0x18, 0x28, 0x80, +0x0A, 0xE0, 0x05, 0x9A, 0x10, 0x1A, 0xB0, 0x42, 0x06, 0xDA, 0x06, 0x9B, +0x80, 0x1B, 0x58, 0x43, 0x0A, 0x99, 0x80, 0x11, 0x08, 0x1A, 0x28, 0x80, +0x03, 0x9A, 0x02, 0x35, 0x01, 0x32, 0x03, 0x92, 0x03, 0x9B, 0x07, 0x98, +0x83, 0x42, 0xCB, 0xDB, 0x20, 0x4D, 0x2E, 0x49, 0x2D, 0x68, 0x28, 0x4A, +0x05, 0x95, 0x0E, 0x89, 0x0D, 0x68, 0x07, 0x96, 0xD3, 0x8C, 0x08, 0x95, +0x4D, 0x69, 0x1F, 0xB2, 0xAE, 0xB2, 0x11, 0x1C, 0x04, 0x97, 0x06, 0x96, +0x2F, 0x31, 0x09, 0x78, 0x9B, 0x1B, 0x9B, 0xB2, 0x09, 0x91, 0x30, 0x32, +0x12, 0x78, 0x15, 0x4E, 0x0B, 0x93, 0x16, 0x4B, 0x00, 0x20, 0x0A, 0x92, +0x1F, 0x68, 0x20, 0x36, 0x03, 0x90, 0x50, 0xE0, 0x03, 0x9A, 0x0A, 0x23, +0x53, 0x43, 0x01, 0xCF, 0x04, 0x99, 0x48, 0x43, 0x0D, 0x49, 0x5B, 0x18, +0x3C, 0x22, 0x99, 0x5E, 0x08, 0x9B, 0x59, 0x43, 0x03, 0xF0, 0x40, 0xFA, +0x07, 0x99, 0x18, 0x4A, 0x08, 0x18, 0x13, 0x78, 0x80, 0xB2, 0x30, 0x80, +0x00, 0x2B, 0x36, 0xD1, 0x00, 0xB2, 0xA8, 0x42, 0x28, 0xDA, 0x09, 0x9B, +0x40, 0x1B, 0x58, 0x43, 0x06, 0x99, 0x80, 0x11, 0x08, 0x18, 0x30, 0x80, +0x2B, 0xE0, 0xC0, 0x46, 0x24, 0x02, 0x00, 0x20, 0x48, 0x00, 0x00, 0x20, +0x44, 0x00, 0x00, 0x20, 0xEC, 0x02, 0x00, 0x20, 0x58, 0x00, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0x64, 0x59, 0x00, 0x00, 0xE4, 0x10, 0x00, 0x20, +0x00, 0x20, 0x00, 0x40, 0xAE, 0x09, 0x00, 0x20, 0x42, 0x20, 0x00, 0x40, +0x9C, 0x0D, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, +0x24, 0x09, 0x00, 0x20, 0xDF, 0x01, 0x00, 0x20, 0x04, 0x9A, 0x10, 0x1A, +0xA8, 0x42, 0x06, 0xDA, 0x0A, 0x9B, 0x40, 0x1B, 0x58, 0x43, 0x0B, 0x99, +0x80, 0x11, 0x08, 0x1A, 0x30, 0x80, 0x03, 0x9A, 0x02, 0x36, 0x01, 0x32, +0x03, 0x92, 0x03, 0x9B, 0x05, 0x98, 0x83, 0x42, 0xAA, 0xDB, 0x1B, 0x4B, +0x1A, 0x1C, 0x2A, 0x32, 0x17, 0x78, 0x1A, 0x1C, 0x2B, 0x32, 0x12, 0x78, +0x28, 0x21, 0x5E, 0x5E, 0x03, 0x92, 0x26, 0x25, 0x5A, 0x5F, 0x2C, 0x33, +0x04, 0x92, 0x1B, 0x78, 0x14, 0x49, 0x06, 0x93, 0x00, 0x25, 0xB4, 0x46, +0x1D, 0xE0, 0x00, 0x26, 0x8B, 0x5F, 0x00, 0x2B, 0x16, 0xD0, 0x11, 0x4A, +0xA8, 0x18, 0x04, 0x23, 0xC2, 0x5E, 0x20, 0x26, 0x83, 0x5F, 0x00, 0x2F, +0x01, 0xD0, 0x66, 0x46, 0xB2, 0x1A, 0x03, 0x9E, 0x00, 0x2E, 0x01, 0xD0, +0x04, 0x9E, 0xF3, 0x1A, 0x06, 0x9E, 0x00, 0x2E, 0x02, 0xD0, 0x16, 0x1C, +0x1A, 0x1C, 0x33, 0x1C, 0x82, 0x80, 0x03, 0x84, 0x01, 0x34, 0x0A, 0x31, +0x02, 0x35, 0x05, 0x9E, 0xB4, 0x42, 0xDE, 0xDB, 0x0D, 0xB0, 0xF0, 0xBD, +0xAE, 0x09, 0x00, 0x20, 0x60, 0x02, 0x00, 0x20, 0x24, 0x02, 0x00, 0x20, +0x30, 0xB5, 0x0A, 0x4B, 0x00, 0x21, 0x04, 0x33, 0xDB, 0x7F, 0x09, 0x4A, +0x0A, 0x24, 0x08, 0x1C, 0x07, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x25, 0x1C, +0x5D, 0x43, 0x55, 0x19, 0xA9, 0x87, 0x05, 0x4D, 0xE8, 0x54, 0x00, 0x2B, +0xF5, 0xD1, 0x13, 0x60, 0x30, 0xBD, 0xC0, 0x46, 0xAE, 0x09, 0x00, 0x20, +0x9C, 0x0D, 0x00, 0x20, 0x64, 0x01, 0x00, 0x20, 0x00, 0xB5, 0x08, 0x4A, +0x01, 0x23, 0x5B, 0x42, 0x53, 0x60, 0x07, 0x4B, 0x00, 0x21, 0x11, 0x60, +0x1B, 0x78, 0x04, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x18, 0x1D, 0x40, 0x00, +0x81, 0x52, 0x00, 0x2B, 0xF8, 0xD1, 0x00, 0xBD, 0xE0, 0x00, 0x00, 0x20, +0x7C, 0x09, 0x00, 0x20, 0x49, 0x43, 0x40, 0x43, 0x40, 0x18, 0x70, 0x47, +0x70, 0x47, 0xF0, 0xB5, 0x83, 0x4B, 0x00, 0x22, 0x04, 0x33, 0xD9, 0x7F, +0x87, 0xB0, 0x0B, 0x1C, 0x81, 0x48, 0x0A, 0x26, 0x15, 0x1C, 0x07, 0xE0, +0x01, 0x3B, 0xDB, 0xB2, 0x34, 0x1C, 0x5C, 0x43, 0x04, 0x19, 0xA2, 0x87, +0x38, 0x34, 0x25, 0x72, 0x04, 0x1C, 0x00, 0x2B, 0xF4, 0xD1, 0x7B, 0x4B, +0x1A, 0x68, 0x0B, 0x1C, 0x91, 0x42, 0x00, 0xDD, 0x13, 0x1C, 0x23, 0x60, +0x78, 0x48, 0x79, 0x4A, 0x79, 0x4B, 0x0E, 0x24, 0xFF, 0x21, 0x01, 0x3C, +0xE4, 0xB2, 0xA5, 0x00, 0x01, 0x55, 0xAB, 0x50, 0x00, 0x2C, 0xF8, 0xD1, +0x6F, 0x4B, 0x25, 0x1C, 0x04, 0x33, 0xDB, 0x7F, 0x26, 0x1C, 0x03, 0x93, +0x72, 0x4B, 0x1B, 0x69, 0x04, 0x93, 0x6D, 0x4B, 0x1B, 0x68, 0x05, 0x93, +0x47, 0xE0, 0x70, 0x4C, 0x63, 0x5D, 0x00, 0x2B, 0x42, 0xD0, 0x6F, 0x4C, +0xAB, 0x00, 0xE3, 0x58, 0x04, 0x9C, 0x1B, 0x01, 0x1B, 0x19, 0x01, 0x93, +0x6C, 0x4B, 0x6A, 0x00, 0x01, 0x27, 0xD3, 0x18, 0x00, 0x24, 0x7F, 0x42, +0x02, 0x93, 0x20, 0xE0, 0x0A, 0x23, 0x63, 0x43, 0x60, 0x48, 0xC3, 0x18, +0x3C, 0x21, 0x5B, 0x5E, 0x00, 0x2B, 0x16, 0xD0, 0x02, 0x9A, 0x63, 0x00, +0xC3, 0x18, 0x98, 0x88, 0x93, 0x88, 0x5B, 0x4A, 0xC0, 0x1A, 0x23, 0x1C, +0x10, 0x33, 0x5B, 0x00, 0x99, 0x5A, 0x02, 0x9A, 0x00, 0xB2, 0x13, 0x8B, +0xC9, 0x1A, 0x09, 0xB2, 0xFF, 0xF7, 0x98, 0xFF, 0x01, 0x9B, 0x98, 0x42, +0x01, 0xDA, 0x27, 0x1C, 0x01, 0x90, 0x01, 0x34, 0xE4, 0xB2, 0x05, 0x98, +0x84, 0x42, 0xDB, 0xDB, 0x79, 0x1C, 0x0D, 0xD0, 0x4F, 0x4B, 0x50, 0x49, +0xD8, 0x57, 0xBA, 0x00, 0x01, 0x30, 0x04, 0xD0, 0x88, 0x58, 0x01, 0x9C, +0xA0, 0x42, 0x03, 0xDD, 0x00, 0xE0, 0x01, 0x9C, 0x8C, 0x50, 0xDD, 0x55, +0x01, 0x35, 0x03, 0x9C, 0xEB, 0xB2, 0xA3, 0x42, 0xB3, 0xD3, 0x34, 0x1C, +0x00, 0x25, 0x44, 0x4E, 0x28, 0xE0, 0x44, 0x48, 0x47, 0x5D, 0x7B, 0xB2, +0x01, 0x33, 0x21, 0xD0, 0x69, 0x00, 0xFF, 0xB2, 0x3E, 0x4B, 0x71, 0x18, +0x89, 0x88, 0x7A, 0x00, 0x9A, 0x18, 0x91, 0x80, 0x29, 0x1C, 0x10, 0x31, +0x3A, 0x1C, 0x49, 0x00, 0x89, 0x5B, 0x10, 0x32, 0x52, 0x00, 0xD1, 0x52, +0x0A, 0x22, 0x10, 0x1C, 0x78, 0x43, 0x11, 0x1C, 0x69, 0x43, 0x1B, 0x18, +0x18, 0x1C, 0x71, 0x18, 0x3C, 0x30, 0x3C, 0x31, 0x03, 0xF0, 0x40, 0xF9, +0x34, 0x4B, 0xAA, 0x00, 0xD2, 0x58, 0x37, 0x4B, 0xBF, 0x00, 0xFA, 0x50, +0x01, 0x35, 0xED, 0xB2, 0x33, 0x68, 0x9D, 0x42, 0xD3, 0xDB, 0x3D, 0xE0, +0x2D, 0x4E, 0x33, 0x57, 0x01, 0x33, 0x36, 0xD1, 0x0A, 0x23, 0x63, 0x43, +0xEB, 0x18, 0x3C, 0x20, 0x1B, 0x5E, 0x00, 0x2B, 0x2F, 0xD0, 0x25, 0x4B, +0x2E, 0x4A, 0x04, 0x33, 0xDF, 0x7F, 0x00, 0x23, 0x26, 0xE0, 0x29, 0x4E, +0xF6, 0x5C, 0x00, 0x2E, 0x20, 0xD1, 0x00, 0x26, 0x90, 0x5F, 0x00, 0x28, +0x1C, 0xD1, 0x21, 0x4A, 0x67, 0x00, 0x11, 0x55, 0x1E, 0x49, 0x1D, 0x48, +0xCF, 0x19, 0xBF, 0x88, 0x5A, 0x00, 0x82, 0x18, 0x97, 0x80, 0x27, 0x1C, +0x10, 0x37, 0x1A, 0x1C, 0x7F, 0x00, 0x7F, 0x5A, 0x10, 0x32, 0x52, 0x00, +0x17, 0x52, 0x0A, 0x22, 0x53, 0x43, 0xC0, 0x18, 0x13, 0x1C, 0x63, 0x43, +0xC9, 0x18, 0x3C, 0x31, 0x3C, 0x30, 0x03, 0xF0, 0xFF, 0xF8, 0x04, 0xE0, +0x01, 0x33, 0x0A, 0x32, 0xD9, 0xB2, 0xB9, 0x42, 0xD5, 0xD3, 0x01, 0x34, +0xE4, 0xB2, 0x00, 0xE0, 0x0D, 0x4D, 0x2B, 0x68, 0x9C, 0x42, 0xBD, 0xDB, +0x09, 0x4B, 0x0C, 0x49, 0x04, 0x33, 0xDD, 0x7F, 0x12, 0x4B, 0xFF, 0x20, +0x1C, 0x1C, 0x0E, 0x34, 0x1A, 0x78, 0xAA, 0x42, 0x02, 0xD2, 0x8A, 0x5C, +0x1A, 0x70, 0x00, 0xE0, 0x18, 0x70, 0x01, 0x33, 0xA3, 0x42, 0xF5, 0xD1, +0x07, 0xB0, 0xF0, 0xBD, 0xAE, 0x09, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0x24, 0x02, 0x00, 0x20, 0xE8, 0x03, 0x00, 0x20, 0xF8, 0x10, 0x00, 0x20, +0xFF, 0xFF, 0xFF, 0x7F, 0x24, 0x09, 0x00, 0x20, 0xEC, 0x01, 0x00, 0x20, +0xF8, 0x00, 0x00, 0x20, 0x80, 0x09, 0x00, 0x20, 0xD8, 0x0D, 0x00, 0x20, +0xEC, 0x02, 0x00, 0x20, 0xF7, 0xB5, 0x42, 0x4B, 0x00, 0x21, 0x19, 0x60, +0x41, 0x4B, 0x0A, 0x24, 0x19, 0x60, 0x41, 0x4B, 0x08, 0x1C, 0x04, 0x33, +0xDB, 0x7F, 0x40, 0x4D, 0x1A, 0x1C, 0xA4, 0x46, 0x11, 0xE0, 0x01, 0x3A, +0xD2, 0xB2, 0x26, 0x1C, 0x56, 0x43, 0xAE, 0x19, 0x38, 0x36, 0x36, 0x7A, +0xB0, 0x42, 0x00, 0xDA, 0x30, 0x1C, 0x66, 0x46, 0x56, 0x43, 0xAE, 0x19, +0x3C, 0x27, 0xF6, 0x5F, 0xB1, 0x42, 0x00, 0xDA, 0x31, 0x1C, 0x00, 0x2A, +0xEB, 0xD1, 0x32, 0x4A, 0x50, 0x60, 0x11, 0x60, 0x2F, 0x4A, 0x0A, 0x20, +0x11, 0x68, 0x31, 0x4A, 0x07, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x04, 0x1C, +0x5C, 0x43, 0x14, 0x19, 0x38, 0x34, 0x24, 0x7A, 0x09, 0x19, 0x14, 0x1C, +0x00, 0x2B, 0xF4, 0xD1, 0x27, 0x4B, 0x19, 0x60, 0x13, 0x68, 0x00, 0x2B, +0x0F, 0xDD, 0x26, 0x4B, 0x28, 0x4A, 0x5B, 0x68, 0x11, 0x80, 0x53, 0x80, +0x27, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, +0x00, 0x93, 0x1D, 0x20, 0x0B, 0x1C, 0x01, 0xF0, 0x8F, 0xFB, 0x23, 0x68, +0x00, 0x2B, 0x19, 0xDD, 0x21, 0x4A, 0x08, 0x23, 0xD1, 0x5E, 0x21, 0x4B, +0x0C, 0x24, 0x12, 0x5F, 0x18, 0x1C, 0x3D, 0x33, 0x1B, 0x78, 0x3C, 0x30, +0x53, 0x43, 0x00, 0x78, 0x9B, 0x11, 0xC3, 0x18, 0x99, 0x42, 0x09, 0xDC, +0x18, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x19, 0x49, +0x01, 0xF0, 0xCC, 0xFB, 0xFF, 0xF7, 0x40, 0xFE, 0x11, 0x4B, 0x17, 0x4A, +0x1B, 0x68, 0x12, 0x78, 0x93, 0x42, 0x12, 0xDB, 0x0B, 0x4B, 0x12, 0x4A, +0x18, 0x68, 0xD1, 0x8E, 0x0A, 0x4B, 0x88, 0x42, 0x03, 0xDB, 0x11, 0x8F, +0x58, 0x68, 0x88, 0x42, 0x03, 0xDA, 0x52, 0x8F, 0x5B, 0x68, 0x93, 0x42, +0x07, 0xDB, 0x0E, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x03, 0xE0, 0x00, 0x2B, +0x01, 0xD1, 0x0B, 0x4A, 0x13, 0x70, 0xF7, 0xBD, 0x4C, 0x11, 0x00, 0x20, +0x0C, 0x02, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0x54, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x6C, 0x59, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, +0xF5, 0x00, 0x00, 0x20, 0x38, 0xB5, 0x04, 0x1C, 0x08, 0x1C, 0x00, 0x2A, +0x07, 0xD0, 0x54, 0x43, 0x58, 0x43, 0xD1, 0x18, 0x20, 0x18, 0x4D, 0x10, +0x40, 0x19, 0x02, 0xF0, 0xBB, 0xFF, 0x38, 0xBD, 0x10, 0xB5, 0x43, 0x1A, +0xDC, 0x17, 0x1B, 0x19, 0x63, 0x40, 0xFF, 0xF7, 0xEB, 0xFF, 0x10, 0xBD, +0xF0, 0xB5, 0xA9, 0x4B, 0x00, 0x25, 0x04, 0x33, 0x87, 0xB0, 0xDC, 0x7F, +0x2E, 0x1C, 0x46, 0xE0, 0x01, 0x3C, 0xE4, 0xB2, 0x0A, 0x22, 0x62, 0x43, +0x99, 0x18, 0x38, 0x31, 0x88, 0x88, 0x00, 0x28, 0x3D, 0xD0, 0xA2, 0x4F, +0x3F, 0x5D, 0x00, 0x2F, 0x2A, 0xD1, 0xA1, 0x49, 0x09, 0x78, 0x00, 0x29, +0x07, 0xD0, 0x9A, 0x18, 0x01, 0x21, 0x3C, 0x32, 0x1D, 0x20, 0x02, 0x23, +0x00, 0x91, 0x01, 0xF0, 0x07, 0xFB, 0x0A, 0x20, 0x60, 0x43, 0x9B, 0x4B, +0x9B, 0x49, 0x18, 0x18, 0x3C, 0x27, 0xC2, 0x5F, 0x38, 0x30, 0x94, 0x46, +0x26, 0x27, 0xCA, 0x5F, 0x1F, 0x1C, 0x94, 0x45, 0x08, 0xDB, 0x4E, 0x31, +0x0A, 0x78, 0x96, 0x49, 0x00, 0x7A, 0x49, 0x68, 0x4A, 0x43, 0x92, 0x11, +0x90, 0x42, 0x16, 0xDA, 0x0A, 0x22, 0x62, 0x43, 0xBA, 0x18, 0xD5, 0x87, +0x38, 0x32, 0x16, 0x72, 0x95, 0x80, 0x08, 0xE0, 0x8D, 0x4A, 0x00, 0xB2, +0x28, 0x27, 0xD2, 0x5F, 0x82, 0x42, 0x08, 0xDD, 0xCD, 0x80, 0x0E, 0x72, +0x8D, 0x80, 0x8B, 0x4A, 0xA1, 0x00, 0x8D, 0x50, 0x1A, 0x68, 0x01, 0x3A, +0x1A, 0x60, 0x85, 0x4B, 0x00, 0x2C, 0xB5, 0xD1, 0x1C, 0x60, 0x87, 0x4B, +0x9C, 0x73, 0x7F, 0x4B, 0x04, 0x33, 0xDC, 0x7F, 0xC7, 0xE0, 0x01, 0x3C, +0xE4, 0xB2, 0x0A, 0x23, 0x63, 0x43, 0xED, 0x18, 0xAA, 0x8F, 0x38, 0x35, +0x00, 0x2A, 0x00, 0xD1, 0x93, 0xE0, 0x7C, 0x4B, 0x12, 0xB2, 0x1B, 0x8D, +0x19, 0xB2, 0x52, 0x1A, 0x52, 0x10, 0x5B, 0x00, 0xD3, 0x18, 0xAB, 0x80, +0x7A, 0x4B, 0x9A, 0x7B, 0x00, 0x2A, 0x0D, 0xD1, 0x79, 0x4A, 0x12, 0x57, +0x00, 0x2A, 0x09, 0xD1, 0x78, 0x4A, 0x01, 0x21, 0x11, 0x70, 0x80, 0x22, +0xD2, 0x05, 0x50, 0x69, 0x00, 0x0E, 0x00, 0x06, 0x01, 0x43, 0x51, 0x61, +0x01, 0x22, 0x9A, 0x73, 0x73, 0x4E, 0x71, 0x4B, 0x1A, 0x57, 0x33, 0x78, +0x9A, 0x42, 0x70, 0xDB, 0x6F, 0x4B, 0x1A, 0x78, 0x00, 0x2A, 0x01, 0xD0, +0x00, 0x22, 0x1A, 0x70, 0x66, 0x4D, 0x62, 0x00, 0x2B, 0x68, 0x01, 0x33, +0x2B, 0x60, 0xAB, 0x18, 0x04, 0x27, 0xD9, 0x5F, 0x6A, 0x4B, 0x9A, 0x18, +0x04, 0x26, 0x90, 0x5F, 0x22, 0x1C, 0x10, 0x32, 0x52, 0x00, 0x57, 0x5F, +0x03, 0x97, 0xD7, 0x5E, 0x0A, 0x1A, 0xD3, 0x17, 0x03, 0x9E, 0xD2, 0x18, +0x5A, 0x40, 0xF3, 0x1B, 0xDE, 0x17, 0x9B, 0x19, 0x73, 0x40, 0xD3, 0x18, +0x04, 0x93, 0x59, 0x4B, 0x2E, 0x22, 0x9E, 0x5E, 0x04, 0x9B, 0x32, 0x1C, +0x05, 0x96, 0xFF, 0xF7, 0x39, 0xFF, 0x05, 0x9A, 0x04, 0x9B, 0x06, 0x1C, +0x03, 0x99, 0x38, 0x1C, 0xFF, 0xF7, 0x32, 0xFF, 0x4D, 0x4A, 0x13, 0x1C, +0x2D, 0x33, 0x1B, 0x78, 0x2A, 0x1C, 0x5B, 0xB2, 0x9E, 0x42, 0x07, 0xDD, +0x55, 0x49, 0xC9, 0x69, 0xCF, 0x1A, 0xBE, 0x42, 0x03, 0xDB, 0x4E, 0x1E, +0xF6, 0x1A, 0x00, 0xE0, 0x1E, 0x1C, 0x45, 0x4B, 0x2E, 0x33, 0x1B, 0x78, +0x5B, 0xB2, 0x98, 0x42, 0x07, 0xDD, 0x4E, 0x49, 0x09, 0x6A, 0xCF, 0x1A, +0xB8, 0x42, 0x03, 0xDB, 0x48, 0x1E, 0xC0, 0x1A, 0x00, 0xE0, 0x18, 0x1C, +0x63, 0x00, 0xD3, 0x18, 0x9E, 0x80, 0x23, 0x1C, 0x10, 0x33, 0x5B, 0x00, +0xE8, 0x52, 0x0A, 0x25, 0x65, 0x43, 0x3D, 0x4B, 0x43, 0x4E, 0x30, 0x20, +0x1F, 0x5E, 0x76, 0x19, 0x55, 0x19, 0x3C, 0x21, 0x70, 0x5E, 0x3C, 0x22, +0xA9, 0x5E, 0x3A, 0x1C, 0xFF, 0xF7, 0x0A, 0xFF, 0x38, 0x36, 0xA8, 0x87, +0x38, 0x35, 0x30, 0x7A, 0x29, 0x7A, 0x3A, 0x1C, 0xFF, 0xF7, 0x02, 0xFF, +0x28, 0x72, 0x31, 0x4B, 0x62, 0x00, 0x99, 0x18, 0x37, 0x48, 0x89, 0x88, +0x82, 0x18, 0x91, 0x80, 0x22, 0x1C, 0x10, 0x32, 0x52, 0x00, 0xD1, 0x5A, +0x11, 0x52, 0x0A, 0x22, 0x11, 0x1C, 0x61, 0x43, 0x40, 0x18, 0x59, 0x18, +0x0D, 0x1C, 0x3C, 0x30, 0x3C, 0x31, 0x02, 0xF0, 0x07, 0xFF, 0x3C, 0x23, +0xEA, 0x5E, 0x38, 0x35, 0x29, 0x4B, 0x00, 0x2A, 0x0C, 0xD0, 0x24, 0x49, +0x1A, 0x5D, 0x32, 0x31, 0x09, 0x78, 0x50, 0xB2, 0x88, 0x42, 0x06, 0xDA, +0x01, 0x32, 0x1A, 0x55, 0x01, 0x23, 0x5B, 0x42, 0xAB, 0x80, 0x00, 0xE0, +0x1A, 0x55, 0x1C, 0x4D, 0x00, 0x2C, 0x00, 0xD0, 0x33, 0xE7, 0x22, 0x4E, +0x29, 0x68, 0x32, 0x68, 0x22, 0x4B, 0x91, 0x42, 0x25, 0xDA, 0x19, 0x68, +0x17, 0x48, 0x01, 0x31, 0x19, 0x60, 0x3E, 0x30, 0x00, 0x78, 0x40, 0xB2, +0x81, 0x42, 0x1C, 0xDA, 0x0F, 0x4B, 0x2A, 0x60, 0x04, 0x33, 0xDC, 0x7F, +0x14, 0xE0, 0x01, 0x3C, 0xE4, 0xB2, 0x63, 0x00, 0xF2, 0x18, 0x92, 0x88, +0xEB, 0x18, 0x9A, 0x80, 0x23, 0x1C, 0x10, 0x33, 0x5B, 0x00, 0x9A, 0x5B, +0x5A, 0x53, 0x0A, 0x22, 0x11, 0x1C, 0x61, 0x43, 0x68, 0x18, 0x71, 0x18, +0x3C, 0x30, 0x3C, 0x31, 0x02, 0xF0, 0xC6, 0xFE, 0x00, 0x2C, 0xE8, 0xD1, +0x00, 0xE0, 0x1C, 0x60, 0x07, 0xB0, 0xF0, 0xBD, 0xAE, 0x09, 0x00, 0x20, +0xEC, 0x01, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x0C, 0x02, 0x00, 0x20, 0xF8, 0x00, 0x00, 0x20, +0x70, 0x01, 0x00, 0x20, 0x3E, 0x11, 0x00, 0x20, 0xE2, 0x01, 0x00, 0x20, +0x7A, 0x0D, 0x00, 0x20, 0x20, 0x03, 0x00, 0x20, 0x24, 0x09, 0x00, 0x20, +0x60, 0x01, 0x00, 0x20, 0xF0, 0xB5, 0x31, 0x4B, 0x31, 0x4D, 0x1E, 0x78, +0x31, 0x4B, 0x00, 0x27, 0x1A, 0x1C, 0x2F, 0x60, 0x2B, 0x32, 0x12, 0x78, +0x89, 0xB0, 0x04, 0x92, 0x50, 0x00, 0x1A, 0x1C, 0x06, 0x90, 0x32, 0x32, +0x12, 0x78, 0x07, 0x92, 0x30, 0x22, 0x99, 0x5E, 0x6B, 0x68, 0x05, 0x91, +0x02, 0x93, 0x03, 0x97, 0x42, 0xE0, 0x01, 0x3E, 0xF6, 0xB2, 0x33, 0x1D, +0x5B, 0x00, 0x01, 0x93, 0xEB, 0x5A, 0x00, 0x2B, 0x34, 0xD0, 0x04, 0x98, +0x1B, 0xB2, 0x1B, 0x1A, 0x06, 0x99, 0x5B, 0x10, 0xCB, 0x18, 0x01, 0x9A, +0x20, 0x48, 0x9B, 0xB2, 0xAB, 0x52, 0xF2, 0x00, 0x81, 0x58, 0x84, 0x18, +0x07, 0x98, 0x1B, 0xB2, 0x81, 0x42, 0x07, 0xDA, 0x1B, 0x48, 0x01, 0x31, +0x81, 0x50, 0x01, 0x99, 0x00, 0x22, 0x63, 0x60, 0x6A, 0x52, 0x21, 0xE0, +0x60, 0x68, 0x01, 0x37, 0x1A, 0x1A, 0xD1, 0x17, 0x84, 0x46, 0x50, 0x18, +0x05, 0x9A, 0x48, 0x40, 0x11, 0x18, 0x00, 0x90, 0x60, 0x46, 0x42, 0x43, +0x94, 0x46, 0x00, 0x9A, 0x53, 0x43, 0x62, 0x46, 0xD0, 0x18, 0x4B, 0x10, +0xC0, 0x18, 0x02, 0xF0, 0xF3, 0xFD, 0x01, 0x9B, 0x03, 0x99, 0x60, 0x60, +0xE8, 0x52, 0x81, 0x42, 0x04, 0xDB, 0x05, 0xE0, 0x09, 0x48, 0xF2, 0x00, +0x83, 0x50, 0x01, 0xE0, 0x02, 0x96, 0x03, 0x90, 0x00, 0x2E, 0xBA, 0xD1, +0x02, 0x99, 0x09, 0xB0, 0x2F, 0x60, 0x69, 0x60, 0xF0, 0xBD, 0xC0, 0x46, +0x7C, 0x09, 0x00, 0x20, 0xE0, 0x00, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x48, 0x09, 0x00, 0x20, 0xF7, 0xB5, 0x27, 0x4B, 0x27, 0x49, 0x04, 0x33, +0xDB, 0x7F, 0x27, 0x4A, 0x27, 0x48, 0x42, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, +0x1C, 0x1C, 0x14, 0x34, 0x64, 0x00, 0x04, 0x19, 0x04, 0x25, 0x64, 0x5F, +0x00, 0x2C, 0x27, 0xD0, 0x0A, 0x24, 0x5C, 0x43, 0x0C, 0x19, 0x3C, 0x26, +0xA4, 0x5F, 0x00, 0x2C, 0x20, 0xD0, 0x5C, 0x00, 0x0E, 0x19, 0xB6, 0x88, +0x05, 0x19, 0x37, 0xB2, 0xBC, 0x46, 0x04, 0x27, 0xEF, 0x5F, 0x65, 0x46, +0xED, 0x1B, 0x6F, 0x10, 0xBE, 0x19, 0x14, 0x19, 0xA6, 0x80, 0x1C, 0x1C, +0x10, 0x34, 0x64, 0x00, 0x0E, 0x5B, 0x1C, 0x1C, 0x0C, 0x34, 0x37, 0xB2, +0x64, 0x00, 0xBC, 0x46, 0x25, 0x5E, 0x67, 0x46, 0x7F, 0x1B, 0x7F, 0x10, +0xBE, 0x19, 0xA6, 0x52, 0x10, 0x4C, 0x01, 0x26, 0xE6, 0x54, 0x10, 0xE0, +0x0B, 0x4D, 0x5C, 0x00, 0x2E, 0x19, 0xB6, 0x88, 0x14, 0x19, 0xA6, 0x80, +0x1E, 0x1C, 0x10, 0x36, 0x1C, 0x1C, 0x76, 0x00, 0x76, 0x5B, 0x0C, 0x34, +0x64, 0x00, 0x16, 0x53, 0x07, 0x4C, 0x00, 0x26, 0xE6, 0x54, 0x00, 0x2B, +0xBA, 0xD1, 0x0B, 0x68, 0x13, 0x60, 0xF7, 0xBD, 0xAE, 0x09, 0x00, 0x20, +0x9C, 0x0D, 0x00, 0x20, 0x80, 0x09, 0x00, 0x20, 0x20, 0x01, 0x00, 0x20, +0xEC, 0x01, 0x00, 0x20, 0xF7, 0xB5, 0x35, 0x4A, 0x35, 0x4B, 0x11, 0x1C, +0x33, 0x31, 0x34, 0x32, 0x0E, 0x78, 0x12, 0x78, 0x04, 0x33, 0xDB, 0x7F, +0x32, 0x49, 0x01, 0x92, 0xB4, 0x46, 0x32, 0x4A, 0x4B, 0xE0, 0x32, 0x48, +0x01, 0x3B, 0xDB, 0xB2, 0xC4, 0x5C, 0x01, 0x98, 0x00, 0x2C, 0x00, 0xD1, +0x60, 0x46, 0x5E, 0x00, 0x8D, 0x19, 0x96, 0x19, 0x04, 0x27, 0xF6, 0x5F, +0xAD, 0x88, 0x00, 0x96, 0x00, 0x9F, 0x2E, 0xB2, 0xBE, 0x1B, 0xF7, 0x17, +0xF6, 0x19, 0x7E, 0x40, 0x86, 0x42, 0x10, 0xDA, 0x1E, 0x1C, 0x0C, 0x36, +0x76, 0x00, 0xB6, 0x5E, 0x1F, 0x1C, 0x10, 0x37, 0x00, 0x96, 0x7F, 0x00, +0xCF, 0x5F, 0x00, 0x9E, 0xF7, 0x1B, 0xFE, 0x17, 0xBF, 0x19, 0x77, 0x40, +0x00, 0x97, 0x87, 0x42, 0x18, 0xDB, 0x58, 0x00, 0x10, 0x18, 0x1E, 0x1C, +0x85, 0x80, 0x10, 0x36, 0x19, 0x4D, 0x18, 0x1C, 0x76, 0x00, 0x0C, 0x30, +0x75, 0x5B, 0x40, 0x00, 0x15, 0x52, 0x18, 0x1C, 0x14, 0x30, 0x40, 0x00, +0x10, 0x18, 0x04, 0x27, 0xC0, 0x5F, 0x00, 0x28, 0x04, 0xDD, 0x00, 0x2C, +0x02, 0xD1, 0x13, 0x48, 0x01, 0x24, 0xC4, 0x54, 0x0A, 0x24, 0x5C, 0x43, +0x0E, 0x4D, 0x18, 0x1C, 0x2C, 0x19, 0x14, 0x30, 0x0D, 0x4D, 0x40, 0x00, +0xA4, 0x8F, 0x28, 0x18, 0x84, 0x80, 0x00, 0x2B, 0xB1, 0xD1, 0x0A, 0x68, +0x09, 0x4B, 0x0B, 0x49, 0x1A, 0x60, 0x0B, 0x4B, 0x1A, 0x78, 0x0B, 0x4B, +0x1A, 0x70, 0x0B, 0x4A, 0x0B, 0x1C, 0x31, 0xCA, 0x31, 0xC3, 0xC0, 0xCA, +0xC0, 0xC3, 0xF7, 0xBD, 0x48, 0x0D, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0x9C, 0x0D, 0x00, 0x20, 0x20, 0x01, 0x00, 0x20, 0x64, 0x01, 0x00, 0x20, +0xCC, 0x00, 0x00, 0x20, 0xF5, 0x00, 0x00, 0x20, 0xF4, 0x00, 0x00, 0x20, +0xE0, 0x00, 0x00, 0x20, 0xF7, 0xB5, 0x19, 0x48, 0x01, 0x23, 0x5B, 0x42, +0x43, 0x60, 0x18, 0x4B, 0x1A, 0x78, 0x18, 0x4B, 0x19, 0x1C, 0x2B, 0x33, +0x1E, 0x78, 0x2A, 0x31, 0x0F, 0x78, 0x00, 0x23, 0xB4, 0x46, 0x1E, 0xE0, +0x01, 0x3A, 0xD2, 0xB2, 0x13, 0x4C, 0x51, 0x00, 0x61, 0x5A, 0x0E, 0xB2, +0xF6, 0x43, 0xF6, 0x17, 0x0E, 0x40, 0x11, 0x1D, 0x49, 0x00, 0xB5, 0xB2, +0x0E, 0x52, 0x00, 0x2D, 0x0F, 0xD0, 0x0E, 0x4E, 0x2D, 0xB2, 0x8E, 0x5F, +0x00, 0x2E, 0x04, 0xDC, 0xBD, 0x42, 0x07, 0xDA, 0x00, 0x25, 0x0D, 0x52, +0x05, 0xE0, 0x65, 0x45, 0x02, 0xDA, 0x00, 0x26, 0x0E, 0x52, 0x00, 0xE0, +0x01, 0x33, 0x00, 0x2A, 0xDE, 0xD1, 0x01, 0x4A, 0x13, 0x60, 0xF7, 0xBD, +0xE0, 0x00, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x3C, 0x0D, 0x00, 0x20, 0xCC, 0x00, 0x00, 0x20, 0xEF, 0xF3, 0x08, 0x80, +0x70, 0x47, 0x00, 0xBA, 0x70, 0x47, 0x40, 0xBA, 0x70, 0x47, 0xC0, 0xBA, +0x70, 0x47, 0x70, 0xB5, 0x00, 0x28, 0x16, 0xDA, 0xC0, 0xB2, 0x0F, 0x23, +0x03, 0x40, 0x08, 0x3B, 0x12, 0x4A, 0x9B, 0x08, 0x9B, 0x00, 0x9B, 0x18, +0x03, 0x22, 0x10, 0x40, 0x90, 0x40, 0xFF, 0x22, 0x5D, 0x68, 0x14, 0x1C, +0x84, 0x40, 0x89, 0x01, 0xA5, 0x43, 0x0A, 0x40, 0x82, 0x40, 0x28, 0x1C, +0x10, 0x43, 0x58, 0x60, 0x11, 0xE0, 0x03, 0x24, 0x82, 0x08, 0x09, 0x4B, +0x20, 0x40, 0xC0, 0x32, 0xA0, 0x40, 0x92, 0x00, 0xFF, 0x24, 0xD5, 0x58, +0x26, 0x1C, 0x86, 0x40, 0x89, 0x01, 0xB5, 0x43, 0x0C, 0x40, 0x84, 0x40, +0x28, 0x1C, 0x20, 0x43, 0xD0, 0x50, 0x70, 0xBD, 0x18, 0xED, 0x00, 0xE0, +0x00, 0xE1, 0x00, 0xE0, 0x08, 0x4B, 0x40, 0x22, 0x19, 0x68, 0x7F, 0x20, +0x49, 0x06, 0x49, 0x0E, 0x11, 0x43, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x3F, 0x22, +0x19, 0x68, 0x7F, 0x20, 0x11, 0x40, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x08, 0x4A, +0x19, 0x68, 0x18, 0x68, 0x89, 0x04, 0x89, 0x0E, 0x09, 0x02, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x08, 0x4B, 0x40, 0x22, 0x19, 0x68, 0x18, 0x68, 0x49, 0x04, 0x49, 0x0E, +0x11, 0x43, 0x06, 0x4A, 0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0x08, 0x4B, 0x20, 0x22, +0x19, 0x68, 0x7F, 0x20, 0x49, 0x06, 0x49, 0x0E, 0x11, 0x43, 0x1A, 0x68, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, +0x07, 0x4B, 0x5F, 0x22, 0x19, 0x68, 0x7F, 0x20, 0x11, 0x40, 0x1A, 0x68, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, +0x07, 0x4B, 0xBE, 0x21, 0x1A, 0x68, 0xC9, 0x01, 0x18, 0x68, 0x11, 0x40, +0x05, 0x4A, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, +0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, +0xFF, 0x80, 0xFF, 0xFF, 0x08, 0x4B, 0x20, 0x22, 0x19, 0x68, 0x18, 0x68, +0x49, 0x04, 0x49, 0x0E, 0x11, 0x43, 0x06, 0x4A, 0x09, 0x02, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x80, 0x23, 0xDB, 0x05, 0x18, 0x6C, 0x80, 0x00, 0xC0, 0x0F, 0x70, 0x47, +0x08, 0x4B, 0x10, 0x22, 0x19, 0x68, 0x7F, 0x20, 0x49, 0x06, 0x49, 0x0E, +0x11, 0x43, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, +0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x6F, 0x22, 0x19, 0x68, 0x7F, 0x20, +0x11, 0x40, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, +0x08, 0x00, 0x00, 0x20, 0x00, 0xB5, 0x0B, 0x4B, 0x19, 0x68, 0x00, 0x28, +0x04, 0xD0, 0x49, 0x06, 0x49, 0x0E, 0x10, 0x22, 0x11, 0x43, 0x01, 0xE0, +0x6F, 0x22, 0x11, 0x40, 0x1A, 0x68, 0x7F, 0x20, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x00, 0xBD, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0xDE, 0x21, +0x1A, 0x68, 0xC9, 0x01, 0x18, 0x68, 0x11, 0x40, 0x05, 0x4A, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x08, 0x4B, 0x10, 0x22, 0x19, 0x68, 0x18, 0x68, 0x49, 0x04, 0x49, 0x0E, +0x11, 0x43, 0x06, 0x4A, 0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0x80, 0x23, 0xDB, 0x05, +0x18, 0x6C, 0xC0, 0x00, 0xC0, 0x0F, 0x70, 0x47, 0x08, 0x4B, 0x01, 0x22, +0x19, 0x68, 0x7F, 0x20, 0x49, 0x06, 0x49, 0x0E, 0x11, 0x43, 0x1A, 0x68, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, +0x07, 0x4B, 0x7E, 0x22, 0x19, 0x68, 0x7F, 0x20, 0x11, 0x40, 0x1A, 0x68, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, +0x07, 0x4B, 0xFC, 0x21, 0x1A, 0x68, 0xC9, 0x01, 0x18, 0x68, 0x11, 0x40, +0x05, 0x4A, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, +0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, +0xFF, 0x80, 0xFF, 0xFF, 0x08, 0x4B, 0x01, 0x22, 0x19, 0x68, 0x18, 0x68, +0x49, 0x04, 0x49, 0x0E, 0x11, 0x43, 0x06, 0x4A, 0x09, 0x02, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x80, 0x23, 0xDB, 0x05, 0x18, 0x6C, 0xC0, 0x01, 0xC0, 0x0F, 0x70, 0x47, +0x08, 0x4B, 0x02, 0x22, 0x19, 0x68, 0x7F, 0x20, 0x49, 0x06, 0x49, 0x0E, +0x11, 0x43, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, +0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x7D, 0x22, 0x19, 0x68, 0x7F, 0x20, +0x11, 0x40, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0xC0, 0x46, +0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0xFA, 0x21, 0x1A, 0x68, 0xC9, 0x01, +0x18, 0x68, 0x11, 0x40, 0x05, 0x4A, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0x08, 0x4B, 0x02, 0x22, +0x19, 0x68, 0x18, 0x68, 0x49, 0x04, 0x49, 0x0E, 0x11, 0x43, 0x06, 0x4A, +0x09, 0x02, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, +0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, +0xFF, 0x80, 0xFF, 0xFF, 0x80, 0x23, 0xDB, 0x05, 0x18, 0x6C, 0x80, 0x01, +0xC0, 0x0F, 0x70, 0x47, 0x08, 0x4B, 0x04, 0x22, 0x19, 0x68, 0x7F, 0x20, +0x49, 0x06, 0x49, 0x0E, 0x11, 0x43, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x07, 0x4B, 0x7B, 0x22, +0x19, 0x68, 0x7F, 0x20, 0x11, 0x40, 0x1A, 0x68, 0x82, 0x43, 0x0A, 0x43, +0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, +0x70, 0x47, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, 0x00, 0xB5, 0x0B, 0x4B, +0x19, 0x68, 0x00, 0x28, 0x04, 0xD0, 0x49, 0x06, 0x49, 0x0E, 0x04, 0x22, +0x11, 0x43, 0x01, 0xE0, 0x7B, 0x22, 0x11, 0x40, 0x1A, 0x68, 0x7F, 0x20, +0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x19, 0x69, 0x1A, 0x61, 0x00, 0xBD, 0xC0, 0x46, 0x08, 0x00, 0x00, 0x20, +0x07, 0x4B, 0xF6, 0x21, 0x1A, 0x68, 0xC9, 0x01, 0x18, 0x68, 0x11, 0x40, +0x05, 0x4A, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, +0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, +0xFF, 0x80, 0xFF, 0xFF, 0x08, 0x4B, 0x04, 0x22, 0x19, 0x68, 0x18, 0x68, +0x49, 0x04, 0x49, 0x0E, 0x11, 0x43, 0x06, 0x4A, 0x09, 0x02, 0x02, 0x40, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x70, 0x47, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x80, 0x23, 0xDB, 0x05, 0x18, 0x6C, 0x40, 0x01, 0xC0, 0x0F, 0x70, 0x47, +0x10, 0xB5, 0x80, 0x23, 0xDB, 0x05, 0x04, 0x1D, 0x98, 0x69, 0x3F, 0x22, +0x14, 0x40, 0x90, 0x43, 0x20, 0x43, 0x01, 0x24, 0x98, 0x61, 0x88, 0x1C, +0x21, 0x40, 0x41, 0x18, 0x0A, 0x40, 0x11, 0x02, 0x98, 0x69, 0x02, 0x4A, +0x02, 0x40, 0x0A, 0x43, 0x9A, 0x61, 0x10, 0xBD, 0xFF, 0xC0, 0xFF, 0xFF, +0x06, 0x4B, 0x7F, 0x22, 0x19, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x18, 0x6C, +0x01, 0x39, 0x90, 0x43, 0x11, 0x40, 0x02, 0x1C, 0x0A, 0x43, 0x1A, 0x64, +0x70, 0x47, 0xC0, 0x46, 0x18, 0x09, 0x00, 0x20, 0x80, 0x23, 0xDB, 0x05, +0x1A, 0x6C, 0x7F, 0x21, 0x8A, 0x43, 0x01, 0x21, 0x0A, 0x43, 0x1A, 0x64, +0x70, 0x47, 0x80, 0x23, 0xDB, 0x05, 0xDA, 0x69, 0x0F, 0x21, 0x8A, 0x43, +0x02, 0x21, 0x0A, 0x43, 0xDA, 0x61, 0xDA, 0x69, 0xF0, 0x21, 0x8A, 0x43, +0x30, 0x21, 0x0A, 0x43, 0xDA, 0x61, 0x0C, 0x4A, 0x11, 0x79, 0x01, 0x39, +0xC9, 0xB2, 0x59, 0x77, 0xD8, 0x69, 0x0A, 0x49, 0x01, 0x40, 0x80, 0x20, +0xC0, 0x02, 0x01, 0x43, 0xD9, 0x61, 0xD8, 0x69, 0x07, 0x49, 0x01, 0x40, +0xA0, 0x20, 0xC0, 0x03, 0x01, 0x43, 0xD9, 0x61, 0x92, 0x79, 0x01, 0x3A, +0xD2, 0xB2, 0xDA, 0x77, 0x70, 0x47, 0xC0, 0x46, 0x04, 0x02, 0x00, 0x20, +0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x30, 0xB5, 0x1A, 0x4A, +0x1A, 0x4B, 0x11, 0x88, 0x1A, 0x4C, 0xC9, 0x18, 0x80, 0x23, 0xDB, 0x05, +0x89, 0xB2, 0x18, 0x8C, 0x19, 0x84, 0x59, 0x8C, 0x00, 0x21, 0x59, 0x84, +0x50, 0x88, 0x16, 0x4D, 0x01, 0x19, 0x89, 0xB2, 0x9A, 0x8C, 0x99, 0x84, +0x42, 0x1E, 0xDC, 0x8C, 0x92, 0xB2, 0x44, 0x19, 0xDA, 0x84, 0xA4, 0xB2, +0x1D, 0x8D, 0x1C, 0x85, 0x10, 0x4C, 0x00, 0x19, 0x80, 0xB2, 0x5C, 0x8D, +0x58, 0x85, 0x98, 0x8D, 0x99, 0x85, 0xD8, 0x8D, 0xDA, 0x85, 0x18, 0x8E, +0x19, 0x86, 0x58, 0x8E, 0x5A, 0x86, 0x98, 0x8E, 0x99, 0x86, 0xD8, 0x8E, +0xDA, 0x86, 0x18, 0x8F, 0x19, 0x87, 0x58, 0x8F, 0x5A, 0x87, 0x98, 0x8F, +0x99, 0x87, 0xD9, 0x8F, 0xDA, 0x87, 0x30, 0xBD, 0x04, 0x02, 0x00, 0x20, +0xFF, 0x07, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0xFF, 0x05, 0x00, 0x00, +0xFF, 0x01, 0x00, 0x00, 0x30, 0xB5, 0x22, 0x4B, 0xEE, 0x24, 0x1A, 0x68, +0xE4, 0x01, 0x14, 0x40, 0x20, 0x48, 0x1A, 0x68, 0x7F, 0x21, 0x02, 0x40, +0x22, 0x43, 0x1A, 0x60, 0x1C, 0x68, 0x80, 0x22, 0xD2, 0x05, 0x15, 0x69, +0x14, 0x61, 0x1C, 0x4C, 0xA4, 0x7C, 0x00, 0x2C, 0x16, 0xD0, 0x1C, 0x68, +0x04, 0x25, 0x64, 0x04, 0x64, 0x0E, 0x2C, 0x43, 0x1D, 0x68, 0x0C, 0x40, +0x24, 0x02, 0x28, 0x40, 0x20, 0x43, 0x18, 0x60, 0x18, 0x68, 0x14, 0x69, +0x10, 0x61, 0x1C, 0x68, 0x7B, 0x20, 0x20, 0x40, 0x1C, 0x68, 0x8C, 0x43, +0x21, 0x1C, 0x01, 0x43, 0x19, 0x60, 0x15, 0xE0, 0x1C, 0x68, 0x04, 0x25, +0x64, 0x06, 0x64, 0x0E, 0x2C, 0x43, 0x1D, 0x68, 0x0C, 0x40, 0x8D, 0x43, +0x29, 0x1C, 0x21, 0x43, 0x19, 0x60, 0x19, 0x68, 0x14, 0x69, 0x11, 0x61, +0x1C, 0x68, 0xF6, 0x21, 0xC9, 0x01, 0x21, 0x40, 0x1C, 0x68, 0x20, 0x40, +0x08, 0x43, 0x18, 0x60, 0x1B, 0x68, 0x11, 0x69, 0x13, 0x61, 0x30, 0xBD, +0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, 0xAE, 0x09, 0x00, 0x20, +0x00, 0xB5, 0x72, 0xB6, 0x0F, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x0F, 0x4B, +0x9A, 0x7C, 0x0F, 0x4B, 0x00, 0x2A, 0x07, 0xD0, 0x1A, 0x68, 0xF6, 0x21, +0xC9, 0x01, 0x11, 0x40, 0x18, 0x68, 0x0C, 0x4A, 0x02, 0x40, 0x05, 0xE0, +0x19, 0x68, 0x7B, 0x22, 0x11, 0x40, 0x1A, 0x68, 0x7F, 0x20, 0x82, 0x43, +0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, +0x1A, 0x61, 0x62, 0xB6, 0x00, 0xBD, 0xC0, 0x46, 0x64, 0x00, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0xFF, 0x80, 0xFF, 0xFF, +0x00, 0xB5, 0x72, 0xB6, 0x10, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x10, 0x4B, +0x9A, 0x7C, 0x10, 0x4B, 0x19, 0x68, 0x00, 0x2A, 0x08, 0xD0, 0x49, 0x04, +0x04, 0x22, 0x49, 0x0E, 0x11, 0x43, 0x18, 0x68, 0x0C, 0x4A, 0x09, 0x02, +0x02, 0x40, 0x06, 0xE0, 0x49, 0x06, 0x04, 0x22, 0x49, 0x0E, 0x11, 0x43, +0x1A, 0x68, 0x7F, 0x20, 0x82, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x19, 0x69, 0x1A, 0x61, 0x62, 0xB6, 0x00, 0xBD, +0x64, 0x00, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, +0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x4B, 0x18, 0x78, 0x70, 0x47, 0xC0, 0x46, +0x64, 0x00, 0x00, 0x20, 0x00, 0xB5, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x6C, +0x80, 0x22, 0xD2, 0x01, 0x0A, 0x43, 0x1A, 0x64, 0x23, 0x4A, 0x80, 0x21, +0x10, 0x68, 0x49, 0x00, 0x01, 0x43, 0x11, 0x60, 0x12, 0x68, 0x99, 0x68, +0x9A, 0x60, 0x19, 0x6C, 0x80, 0x22, 0x12, 0x02, 0x0A, 0x43, 0x1A, 0x64, +0x19, 0x6C, 0x1D, 0x4A, 0x0A, 0x40, 0x1A, 0x64, 0x1C, 0x4B, 0x7F, 0x22, +0x59, 0x7B, 0x1C, 0x4B, 0x11, 0x40, 0x18, 0x68, 0x1B, 0x4A, 0x09, 0x04, +0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x19, 0x68, 0xA0, 0x22, 0xD2, 0x05, +0x90, 0x68, 0x91, 0x60, 0x18, 0x68, 0x17, 0x49, 0x01, 0x40, 0x84, 0x20, +0xC0, 0x05, 0x01, 0x43, 0x19, 0x60, 0x19, 0x68, 0x90, 0x68, 0x91, 0x60, +0x13, 0x49, 0x09, 0x78, 0x49, 0xB2, 0x00, 0x29, 0x02, 0xD0, 0x01, 0x29, +0x0C, 0xD1, 0x03, 0xE0, 0x18, 0x68, 0x10, 0x49, 0x01, 0x40, 0x03, 0xE0, +0x18, 0x68, 0x80, 0x21, 0x09, 0x04, 0x01, 0x43, 0x19, 0x60, 0x1B, 0x68, +0x91, 0x68, 0x93, 0x60, 0x80, 0x23, 0xDB, 0x05, 0x19, 0x6C, 0x0A, 0x4A, +0x0A, 0x40, 0x1A, 0x64, 0x00, 0xBD, 0xC0, 0x46, 0x14, 0x00, 0x00, 0x20, +0xFF, 0x7F, 0xFF, 0xFF, 0xAE, 0x09, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x20, +0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFA, 0x02, 0x00, 0x20, +0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x04, 0x4B, 0x01, 0x22, +0x1A, 0x70, 0x80, 0x23, 0xDB, 0x05, 0x99, 0x6C, 0x91, 0x43, 0x99, 0x64, +0x1A, 0x70, 0x70, 0x47, 0x00, 0x00, 0x00, 0x20, 0x03, 0x4A, 0x01, 0x23, +0x13, 0x70, 0x80, 0x22, 0xD2, 0x05, 0x53, 0x70, 0x70, 0x47, 0xC0, 0x46, +0x02, 0x00, 0x00, 0x20, 0x00, 0xB5, 0x06, 0x4B, 0x72, 0xB6, 0x1A, 0x78, +0x00, 0x2A, 0x04, 0xD0, 0xC0, 0x46, 0xC0, 0x46, 0x62, 0xB6, 0x30, 0xBF, +0xF6, 0xE7, 0x62, 0xB6, 0x00, 0xBD, 0xC0, 0x46, 0x02, 0x00, 0x00, 0x20, +0x38, 0xB5, 0x09, 0x4B, 0x09, 0x49, 0x9A, 0x78, 0x1C, 0x79, 0x51, 0x43, +0x08, 0x4B, 0x05, 0x1C, 0xC9, 0x18, 0x08, 0x48, 0x02, 0xF0, 0x7A, 0xF8, +0x06, 0x4B, 0x29, 0x1C, 0x01, 0x34, 0x58, 0x43, 0xA1, 0x40, 0x02, 0xF0, +0x73, 0xF8, 0x38, 0xBD, 0xAA, 0x0A, 0x00, 0x20, 0x44, 0xFE, 0xFF, 0xFF, +0xFE, 0x24, 0x02, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x05, 0x4B, 0x19, 0x68, +0x80, 0x23, 0xDB, 0x05, 0x5A, 0x69, 0x09, 0x02, 0x12, 0x0E, 0x09, 0x0A, +0x12, 0x06, 0x0A, 0x43, 0x5A, 0x61, 0x70, 0x47, 0x04, 0x00, 0x00, 0x20, +0x01, 0x4B, 0x18, 0x60, 0x70, 0x47, 0xC0, 0x46, 0x04, 0x00, 0x00, 0x20, +0x05, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x80, 0x23, 0xDB, 0x05, 0x59, 0x69, +0x80, 0x22, 0x52, 0x04, 0x0A, 0x43, 0x5A, 0x61, 0x70, 0x47, 0xC0, 0x46, +0x01, 0x00, 0x00, 0x20, 0x00, 0xB5, 0x05, 0x4B, 0x72, 0xB6, 0x1A, 0x78, +0x00, 0x2A, 0x03, 0xD0, 0xC0, 0x46, 0xC0, 0x46, 0x62, 0xB6, 0xF7, 0xE7, +0x62, 0xB6, 0x00, 0xBD, 0x00, 0x00, 0x00, 0x20, 0x00, 0xB5, 0x10, 0x4B, +0x1B, 0x68, 0x9A, 0x05, 0x0C, 0xD5, 0x0F, 0x4A, 0x0F, 0x4B, 0x72, 0xB6, +0x11, 0x78, 0x00, 0x29, 0x02, 0xD1, 0x19, 0x78, 0x00, 0x29, 0x11, 0xD0, +0xC0, 0x46, 0xC0, 0x46, 0x62, 0xB6, 0xF4, 0xE7, 0x08, 0x4A, 0x09, 0x4B, +0x72, 0xB6, 0x11, 0x78, 0x00, 0x29, 0x02, 0xD1, 0x19, 0x78, 0x00, 0x29, +0x04, 0xD0, 0xC0, 0x46, 0xC0, 0x46, 0x62, 0xB6, 0x30, 0xBF, 0xF3, 0xE7, +0x62, 0xB6, 0x00, 0xBD, 0x58, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, +0x00, 0x00, 0x00, 0x20, 0x70, 0xB5, 0x13, 0x49, 0x13, 0x4B, 0x04, 0x24, +0x19, 0x60, 0x13, 0x4B, 0x13, 0x4D, 0x1A, 0x68, 0x22, 0x43, 0x1A, 0x60, +0x1A, 0x68, 0x02, 0x24, 0xA2, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x01, 0x24, +0x22, 0x43, 0x0F, 0x4C, 0x1A, 0x60, 0x00, 0x22, 0x22, 0x60, 0x0E, 0x4A, +0x11, 0x60, 0x2E, 0x78, 0x2D, 0x79, 0x70, 0x43, 0x01, 0x35, 0xE8, 0x40, +0x09, 0x1A, 0x11, 0x60, 0x20, 0x68, 0x11, 0x68, 0x88, 0x42, 0xFB, 0xD2, +0x1A, 0x68, 0x01, 0x21, 0x8A, 0x43, 0x1A, 0x60, 0x70, 0xBD, 0xC0, 0x46, +0xFF, 0xFF, 0xFF, 0x00, 0x14, 0xE0, 0x00, 0xE0, 0x10, 0xE0, 0x00, 0xE0, +0xAA, 0x0A, 0x00, 0x20, 0x18, 0xE0, 0x00, 0xE0, 0xFC, 0x01, 0x00, 0x20, +0x00, 0xB5, 0x00, 0x23, 0x06, 0x4A, 0x98, 0x42, 0x02, 0xDB, 0xD3, 0x1C, +0xDB, 0x7F, 0x43, 0x43, 0x02, 0x32, 0xD2, 0x7F, 0x01, 0x30, 0x52, 0xB2, +0x90, 0x40, 0x18, 0x18, 0x40, 0x18, 0x00, 0xBD, 0xAE, 0x09, 0x00, 0x20, +0xF0, 0xB5, 0x85, 0xB0, 0x05, 0x1C, 0x0C, 0x1C, 0x16, 0x1C, 0x00, 0x29, +0x05, 0xD0, 0x2B, 0x4B, 0x02, 0x33, 0xDB, 0x7F, 0x5B, 0xB2, 0x00, 0x2B, +0x4E, 0xD0, 0x21, 0x1C, 0x28, 0x1C, 0xFF, 0xF7, 0xDD, 0xFF, 0x27, 0x49, +0x27, 0x4F, 0x4A, 0x7A, 0x09, 0x7A, 0x13, 0x19, 0x51, 0x18, 0x02, 0x91, +0x41, 0x01, 0xCF, 0x19, 0x00, 0x22, 0x03, 0x97, 0x84, 0x46, 0x13, 0xE0, +0x22, 0x48, 0xC1, 0x56, 0x58, 0x1C, 0xC0, 0xB2, 0xCF, 0x0F, 0x01, 0x90, +0x7F, 0x18, 0x03, 0x98, 0x7F, 0x10, 0xC7, 0x19, 0x08, 0x37, 0x00, 0x97, +0x6F, 0x46, 0x38, 0x79, 0x00, 0x9F, 0x02, 0x33, 0xB8, 0x70, 0x01, 0x27, +0x8F, 0x40, 0x3A, 0x43, 0x02, 0x98, 0x83, 0x42, 0xE8, 0xDB, 0x15, 0x4B, +0x60, 0x46, 0xDF, 0x79, 0x61, 0x42, 0x61, 0x41, 0x5B, 0x7C, 0x79, 0x18, +0x1C, 0x19, 0x49, 0x10, 0x01, 0x39, 0x01, 0x34, 0x89, 0x06, 0x24, 0x05, +0x0C, 0x43, 0x22, 0x43, 0x0E, 0x49, 0x10, 0x4C, 0x40, 0x01, 0x43, 0x18, +0x0F, 0x4F, 0x01, 0x19, 0x4C, 0x68, 0x4A, 0x60, 0xAA, 0x1C, 0xD2, 0xB2, +0xC0, 0x19, 0x02, 0x71, 0x00, 0x2E, 0x07, 0xD0, 0x0B, 0x4A, 0x01, 0x21, +0x52, 0x57, 0x91, 0x40, 0x0A, 0x1C, 0x99, 0x69, 0x9A, 0x61, 0x01, 0xE0, +0x9A, 0x69, 0x9E, 0x61, 0x05, 0xB0, 0xF0, 0xBD, 0xAE, 0x09, 0x00, 0x20, +0x0A, 0x03, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x10, 0x75, 0x00, 0x00, +0x18, 0x10, 0x00, 0x40, 0x10, 0x10, 0x00, 0x40, 0xEA, 0x74, 0x00, 0x00, +0x10, 0xB5, 0x08, 0x4B, 0x00, 0x21, 0x1B, 0x68, 0x01, 0x3B, 0x08, 0xE0, +0x06, 0x4C, 0x58, 0x01, 0x09, 0x22, 0x00, 0x19, 0x84, 0x18, 0xA1, 0x72, +0x01, 0x3A, 0xFB, 0xD2, 0x01, 0x3B, 0x00, 0x2B, 0xF4, 0xDA, 0x10, 0xBD, +0x18, 0x09, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x38, 0xB5, 0xFF, 0xF7, +0xE7, 0xFF, 0x00, 0x21, 0x01, 0x20, 0x0A, 0x1C, 0x40, 0x42, 0xFF, 0xF7, +0x75, 0xFF, 0x01, 0x20, 0x40, 0x42, 0x01, 0x21, 0x00, 0x22, 0xFF, 0xF7, +0x6F, 0xFF, 0x0A, 0x4D, 0xAC, 0x7B, 0x0B, 0xE0, 0x20, 0x1C, 0x00, 0x21, +0x01, 0x22, 0xFF, 0xF7, 0x67, 0xFF, 0x01, 0x21, 0x20, 0x1C, 0x0A, 0x1C, +0xFF, 0xF7, 0x62, 0xFF, 0x01, 0x34, 0xE4, 0xB2, 0xAA, 0x7B, 0x2B, 0x79, +0xD3, 0x18, 0x9C, 0x42, 0xEE, 0xDB, 0x38, 0xBD, 0x0A, 0x03, 0x00, 0x20, +0xF0, 0xB5, 0x85, 0xB0, 0x05, 0x1C, 0x0E, 0x1C, 0x02, 0x92, 0x1F, 0x1C, +0x00, 0x29, 0x05, 0xD0, 0x21, 0x4B, 0x02, 0x33, 0xDB, 0x7F, 0x5B, 0xB2, +0x00, 0x2B, 0x3B, 0xD0, 0x31, 0x1C, 0x28, 0x1C, 0xFF, 0xF7, 0x34, 0xFF, +0x1D, 0x4A, 0xC0, 0xB2, 0x01, 0x90, 0x53, 0x7A, 0x12, 0x7A, 0xF6, 0x18, +0x9A, 0x18, 0x1B, 0x4B, 0xB9, 0x1E, 0x1B, 0x7C, 0x48, 0x1E, 0x81, 0x41, +0x49, 0x42, 0xF6, 0xB2, 0x03, 0x91, 0x9C, 0x46, 0x24, 0xE0, 0x00, 0x2F, +0x07, 0xD1, 0x26, 0x21, 0x71, 0x43, 0x15, 0x4B, 0x49, 0x19, 0xCC, 0x5C, +0x64, 0x44, 0xE4, 0xB2, 0x08, 0xE0, 0x01, 0x2F, 0x04, 0xD1, 0x73, 0x01, +0x11, 0x49, 0x5B, 0x19, 0x5C, 0x5C, 0x01, 0xE0, 0x03, 0x9B, 0x1C, 0x40, +0x0F, 0x4B, 0x02, 0x99, 0x9B, 0x57, 0x02, 0x36, 0xD8, 0x0F, 0xC0, 0x18, +0x63, 0x18, 0xDB, 0xB2, 0x00, 0x93, 0x01, 0x9B, 0x40, 0x10, 0x59, 0x01, +0x6B, 0x46, 0x08, 0x18, 0x1B, 0x78, 0x09, 0x49, 0xF6, 0xB2, 0x43, 0x54, +0x96, 0x42, 0xD8, 0xDB, 0x05, 0xB0, 0xF0, 0xBD, 0xAE, 0x09, 0x00, 0x20, +0x0A, 0x03, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x36, 0x75, 0x00, 0x00, +0xB3, 0x0A, 0x00, 0x20, 0x10, 0x75, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, +0x70, 0xB5, 0x2A, 0x4B, 0x2A, 0x4A, 0x19, 0x68, 0x80, 0x24, 0x0A, 0x40, +0x1A, 0x60, 0x1A, 0x68, 0xE4, 0x05, 0x28, 0x4D, 0xA1, 0x68, 0xA2, 0x60, +0x69, 0x7A, 0x03, 0x22, 0x18, 0x68, 0x11, 0x40, 0x25, 0x4A, 0x89, 0x04, +0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0xA1, 0x68, 0xA2, 0x60, +0x19, 0x68, 0x80, 0x22, 0x52, 0x03, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0xA1, 0x68, 0xA2, 0x60, 0x29, 0x7A, 0x18, 0x68, 0x07, 0x26, 0x1D, 0x4A, +0x31, 0x40, 0x49, 0x05, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, +0xA1, 0x68, 0xA2, 0x60, 0xA9, 0x7B, 0x0F, 0x29, 0x25, 0xD8, 0xEA, 0x7B, +0x0F, 0x2A, 0x22, 0xD8, 0x18, 0x68, 0x09, 0x07, 0x00, 0x01, 0x00, 0x09, +0x01, 0x43, 0x19, 0x60, 0x0F, 0x21, 0x0A, 0x40, 0x18, 0x68, 0x11, 0x06, +0x11, 0x4A, 0x02, 0x40, 0x0A, 0x43, 0x1A, 0x60, 0x1B, 0x68, 0xA2, 0x68, +0xA3, 0x60, 0xFF, 0xF7, 0x49, 0xFC, 0x0E, 0x4A, 0x63, 0x6C, 0x13, 0x43, +0x63, 0x64, 0xFF, 0xF7, 0x5C, 0xFC, 0xFF, 0xF7, 0x87, 0xFC, 0xEB, 0x79, +0x0A, 0x4A, 0x1E, 0x40, 0x33, 0x02, 0x26, 0x6C, 0x16, 0x40, 0x1E, 0x43, +0x26, 0x64, 0x70, 0xBD, 0x14, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFC, 0xFF, +0x48, 0x0D, 0x00, 0x20, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, +0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xF8, 0xFF, 0xFF, +0x00, 0xB5, 0x80, 0x21, 0xC9, 0x05, 0x0B, 0x79, 0x5A, 0x1E, 0xD2, 0xB2, +0x98, 0x42, 0x09, 0xDD, 0x00, 0xE0, 0x0B, 0x71, 0x01, 0x33, 0xDB, 0xB2, +0x83, 0x42, 0xFA, 0xDD, 0x04, 0xE0, 0x0A, 0x71, 0x01, 0x3A, 0xD2, 0xB2, +0x82, 0x42, 0xFA, 0xDA, 0x00, 0xBD, 0x38, 0xB5, 0x17, 0x4C, 0xA0, 0x78, +0xFF, 0xF7, 0xE6, 0xFF, 0x80, 0x23, 0xDB, 0x05, 0x21, 0x79, 0x5A, 0x68, +0xC9, 0x07, 0x52, 0x00, 0x52, 0x08, 0x0A, 0x43, 0x5A, 0x60, 0x60, 0x79, +0x03, 0x22, 0x5D, 0x68, 0x10, 0x49, 0x10, 0x40, 0x80, 0x03, 0x29, 0x40, +0x01, 0x43, 0x59, 0x60, 0xA0, 0x79, 0x0E, 0x49, 0x5D, 0x68, 0x10, 0x40, +0x00, 0x03, 0x29, 0x40, 0x01, 0x43, 0x59, 0x60, 0xE0, 0x79, 0x0B, 0x49, +0x5D, 0x68, 0x10, 0x40, 0x29, 0x40, 0x80, 0x02, 0x01, 0x43, 0x59, 0x60, +0x21, 0x7A, 0x58, 0x68, 0x0A, 0x40, 0x11, 0x02, 0x06, 0x4A, 0x02, 0x40, +0x0A, 0x43, 0x5A, 0x60, 0x38, 0xBD, 0xC0, 0x46, 0xAA, 0x0A, 0x00, 0x20, +0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, +0xFF, 0xFC, 0xFF, 0xFF, 0xF8, 0xB5, 0x80, 0x23, 0xDB, 0x05, 0x1A, 0x68, +0x7A, 0x4A, 0x00, 0x21, 0x08, 0x20, 0x19, 0x60, 0x10, 0x60, 0x14, 0x68, +0x9D, 0x68, 0x9C, 0x60, 0x77, 0x4C, 0x21, 0x60, 0x24, 0x68, 0xDD, 0x68, +0xDC, 0x60, 0xFE, 0x25, 0x75, 0x4C, 0xED, 0x01, 0x25, 0x60, 0x24, 0x68, +0x1D, 0x69, 0x1C, 0x61, 0x5C, 0x69, 0x59, 0x61, 0x9C, 0x69, 0x99, 0x61, +0xDC, 0x69, 0xD9, 0x61, 0x1C, 0x6C, 0x80, 0x24, 0xE4, 0x01, 0x1C, 0x64, +0x5C, 0x6C, 0x59, 0x64, 0x9C, 0x6C, 0x6D, 0x4C, 0x99, 0x64, 0x21, 0x60, +0xA0, 0x24, 0xE4, 0x05, 0xA5, 0x68, 0xA1, 0x60, 0x1C, 0x6C, 0x6A, 0x49, +0x21, 0x40, 0x19, 0x64, 0x1C, 0x68, 0x80, 0x21, 0x49, 0x05, 0x21, 0x43, +0x19, 0x60, 0x67, 0x49, 0x01, 0x31, 0xC9, 0x7F, 0x00, 0x29, 0x03, 0xD0, +0x11, 0x68, 0x08, 0x43, 0x10, 0x60, 0x02, 0xE0, 0x11, 0x68, 0x81, 0x43, +0x11, 0x60, 0x11, 0x68, 0x98, 0x68, 0x99, 0x60, 0x13, 0x68, 0x04, 0x26, +0x33, 0x43, 0x13, 0x60, 0x13, 0x68, 0x80, 0x25, 0xED, 0x05, 0xA9, 0x68, +0xAB, 0x60, 0x13, 0x68, 0x02, 0x27, 0x3B, 0x43, 0x13, 0x60, 0x13, 0x68, +0xA9, 0x68, 0xAB, 0x60, 0x13, 0x68, 0x01, 0x20, 0x83, 0x43, 0x13, 0x60, +0x13, 0x68, 0xAA, 0x68, 0xAB, 0x60, 0xFF, 0xF7, 0xED, 0xFE, 0x54, 0x4B, +0x1C, 0x22, 0x9A, 0x56, 0xA9, 0x69, 0x53, 0x4B, 0x12, 0x05, 0xF2, 0x40, +0x0B, 0x40, 0x13, 0x43, 0xAB, 0x61, 0xFF, 0xF7, 0x61, 0xFE, 0x50, 0x4A, +0x50, 0x4B, 0x01, 0x21, 0x1A, 0x60, 0x50, 0x4B, 0x08, 0x24, 0x1A, 0x68, +0x10, 0x20, 0x32, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0xBA, 0x43, 0x1A, 0x60, +0x4C, 0x4B, 0xC0, 0x22, 0x52, 0x00, 0x99, 0x50, 0x20, 0x21, 0x9F, 0x50, +0x9E, 0x50, 0x9C, 0x50, 0x98, 0x50, 0x99, 0x50, 0x40, 0x21, 0x99, 0x50, +0xC0, 0x22, 0xBA, 0x40, 0x98, 0x58, 0xFF, 0x24, 0xA0, 0x43, 0xC0, 0x24, +0x20, 0x43, 0x98, 0x50, 0x9C, 0x58, 0x43, 0x48, 0x04, 0x40, 0x9C, 0x50, +0x9C, 0x58, 0x42, 0x48, 0x20, 0x40, 0x80, 0x24, 0x24, 0x04, 0x04, 0x43, +0x9C, 0x50, 0x9C, 0x58, 0x24, 0x02, 0x24, 0x0A, 0x2C, 0x43, 0x9C, 0x50, +0xC1, 0x22, 0xBA, 0x40, 0x98, 0x58, 0x04, 0x1C, 0xFF, 0x20, 0x84, 0x43, +0x0C, 0x43, 0x9C, 0x50, 0x9C, 0x58, 0x37, 0x48, 0x20, 0x40, 0x80, 0x24, +0x24, 0x02, 0x20, 0x43, 0x98, 0x50, 0x98, 0x58, 0x34, 0x4C, 0x20, 0x40, +0x98, 0x50, 0x34, 0x4A, 0x10, 0x69, 0x30, 0x43, 0x10, 0x61, 0x62, 0xB6, +0x08, 0x22, 0x01, 0x20, 0x1E, 0x60, 0x18, 0x60, 0x1F, 0x60, 0x1A, 0x60, +0x2F, 0x4B, 0x20, 0x20, 0x10, 0x24, 0xDC, 0x67, 0xD8, 0x67, 0xD9, 0x67, +0xFF, 0xF7, 0x46, 0xFC, 0x21, 0x4C, 0xE0, 0x7D, 0x21, 0x7E, 0xFF, 0xF7, +0xFB, 0xFA, 0xE3, 0x7C, 0x00, 0x2B, 0x26, 0xD0, 0x1A, 0x4B, 0x01, 0x21, +0x18, 0x68, 0x27, 0x4A, 0x40, 0x00, 0x40, 0x0E, 0x08, 0x43, 0x19, 0x68, +0x00, 0x06, 0x11, 0x40, 0x01, 0x43, 0x19, 0x60, 0x19, 0x68, 0x28, 0x69, +0x29, 0x61, 0x19, 0x68, 0x49, 0x00, 0x49, 0x0E, 0x0F, 0x43, 0x39, 0x06, +0x1F, 0x68, 0x17, 0x40, 0x0F, 0x43, 0x1F, 0x60, 0x19, 0x68, 0x28, 0x69, +0x29, 0x61, 0x19, 0x68, 0x49, 0x00, 0x49, 0x0E, 0x0E, 0x43, 0x19, 0x68, +0x36, 0x06, 0x0A, 0x40, 0x32, 0x43, 0x1A, 0x60, 0x1B, 0x68, 0x2A, 0x69, +0x2B, 0x61, 0xFF, 0xF7, 0xD4, 0xFE, 0xFF, 0xF7, 0xC1, 0xF8, 0xFF, 0xF7, +0x0F, 0xF9, 0xFF, 0xF7, 0x7D, 0xF9, 0xFF, 0xF7, 0x65, 0xFB, 0xF8, 0xBD, +0x14, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0x7F, 0xFF, 0xAE, 0x09, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, +0x14, 0xE0, 0x00, 0xE0, 0x10, 0xE0, 0x00, 0xE0, 0x00, 0xE1, 0x00, 0xE0, +0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xED, 0x00, 0xE0, +0x04, 0xE1, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x80, 0x08, 0xB5, 0x0C, 0x4A, +0x0C, 0x4B, 0x0D, 0x49, 0x01, 0xE0, 0x01, 0xCA, 0x01, 0xC3, 0x8B, 0x42, +0xFB, 0xD3, 0x0B, 0x4B, 0x0B, 0x49, 0x00, 0x22, 0x00, 0xE0, 0x04, 0xC3, +0x8B, 0x42, 0xFC, 0xD3, 0xFF, 0xF7, 0x26, 0xF8, 0x08, 0x4B, 0x00, 0x22, +0x00, 0xE0, 0x04, 0xC3, 0x83, 0x42, 0xFC, 0xD3, 0x08, 0xBD, 0xC0, 0x46, +0xFC, 0x59, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x20, 0x5C, 0x00, 0x00, 0x20, +0x5C, 0x00, 0x00, 0x20, 0xEC, 0x11, 0x00, 0x20, 0x0C, 0x1E, 0x00, 0x20, +0x00, 0xB5, 0x13, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0x02, 0xD0, 0x08, 0x2B, +0x1E, 0xD1, 0x0F, 0xE0, 0x10, 0x4B, 0x11, 0x4A, 0x1A, 0x60, 0x11, 0x4A, +0x5A, 0x60, 0x11, 0x4A, 0x11, 0x4B, 0x1A, 0x60, 0x11, 0x4B, 0x12, 0x4A, +0x1A, 0x60, 0x12, 0x4A, 0x5A, 0x60, 0x12, 0x4A, 0x9A, 0x60, 0x0D, 0xE0, +0x09, 0x4B, 0x08, 0x4A, 0x09, 0x49, 0x13, 0x60, 0x51, 0x60, 0x0A, 0x4A, +0x13, 0x60, 0x0A, 0x4A, 0x13, 0x60, 0x53, 0x60, 0x93, 0x60, 0x0C, 0x4B, +0x01, 0x22, 0x1A, 0x70, 0x00, 0xBD, 0xC0, 0x46, 0x50, 0x11, 0x00, 0x20, +0x68, 0x00, 0x00, 0x20, 0xF9, 0x03, 0x00, 0x00, 0x7D, 0x3F, 0x00, 0x00, +0xB5, 0x3F, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x18, 0x00, 0x00, 0x20, +0xC1, 0x40, 0x00, 0x00, 0xA9, 0x42, 0x00, 0x00, 0x0D, 0x44, 0x00, 0x00, +0xE4, 0x01, 0x00, 0x20, 0x00, 0xB5, 0x00, 0x23, 0xC2, 0x5C, 0x01, 0x33, +0x00, 0x2A, 0xFB, 0xD1, 0x01, 0x3B, 0xD8, 0xB2, 0x00, 0xBD, 0xC0, 0x46, +0xF7, 0xB5, 0x1C, 0x1C, 0x08, 0xAB, 0x1F, 0x78, 0x26, 0x4B, 0x0E, 0x1C, +0x1B, 0x68, 0x01, 0x21, 0x81, 0x40, 0x0B, 0x42, 0x44, 0xD0, 0x00, 0x2F, +0x07, 0xD0, 0x04, 0x2C, 0x32, 0xD8, 0x22, 0x4B, 0x19, 0x5D, 0x05, 0x33, +0x00, 0x91, 0x1F, 0x5D, 0x08, 0xE0, 0x04, 0x2C, 0x2E, 0xD8, 0x1E, 0x4B, +0x19, 0x1C, 0x0A, 0x31, 0x09, 0x5D, 0x0F, 0x33, 0x1F, 0x5D, 0x00, 0x91, +0x03, 0x2C, 0x28, 0xD0, 0x00, 0x2C, 0x28, 0xD0, 0x28, 0xE0, 0x3A, 0x20, +0x21, 0x1C, 0x01, 0xF0, 0x63, 0xFC, 0x86, 0x42, 0x05, 0xDD, 0x6B, 0x46, +0x1B, 0x78, 0xC0, 0xB2, 0x2B, 0x70, 0x68, 0x70, 0x02, 0xE0, 0x2F, 0x70, +0x30, 0x1C, 0x6E, 0x70, 0x36, 0x1A, 0x60, 0x43, 0x01, 0x99, 0x00, 0x23, +0x69, 0x60, 0xAB, 0x60, 0x09, 0x18, 0xF6, 0xB2, 0x01, 0x91, 0xFF, 0xF7, +0xE3, 0xFA, 0xFF, 0xF7, 0x37, 0xFB, 0x00, 0x28, 0xFB, 0xD1, 0x0B, 0xE0, +0x0F, 0x23, 0x00, 0x27, 0x00, 0x93, 0x05, 0xE0, 0x0F, 0x21, 0x00, 0x91, +0x02, 0xE0, 0x02, 0x24, 0x00, 0xE0, 0x01, 0x24, 0x04, 0x4D, 0x01, 0x92, +0x00, 0x2E, 0xD2, 0xD1, 0xF7, 0xBD, 0xC0, 0x46, 0x58, 0x00, 0x00, 0x20, +0x73, 0x59, 0x00, 0x00, 0x70, 0x00, 0x00, 0x20, 0x38, 0xB5, 0x11, 0x4B, +0x01, 0x22, 0x1B, 0x68, 0x82, 0x40, 0x0D, 0x1C, 0x13, 0x42, 0x19, 0xD0, +0x0E, 0x4C, 0x0B, 0x23, 0x23, 0x70, 0x08, 0x1C, 0xFF, 0xF7, 0x90, 0xFF, +0x60, 0x70, 0x63, 0x78, 0x07, 0x22, 0x02, 0x33, 0x13, 0x40, 0x93, 0x42, +0x03, 0xD1, 0x63, 0x78, 0x01, 0x3B, 0xDB, 0xB2, 0x63, 0x70, 0x00, 0x23, +0x65, 0x60, 0xA3, 0x60, 0xFF, 0xF7, 0xAA, 0xFA, 0xFF, 0xF7, 0xFE, 0xFA, +0x00, 0x28, 0xFB, 0xD1, 0x38, 0xBD, 0xC0, 0x46, 0x58, 0x00, 0x00, 0x20, +0x70, 0x00, 0x00, 0x20, 0x1F, 0xB5, 0x0B, 0x4C, 0x6B, 0x46, 0xD8, 0x73, +0x23, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x08, 0x49, 0xFF, 0xF7, +0xCD, 0xFF, 0x23, 0x78, 0x00, 0x2B, 0x07, 0xD0, 0x6A, 0x46, 0x01, 0x21, +0x00, 0x20, 0x0F, 0x32, 0x04, 0x23, 0x00, 0x91, 0xFF, 0xF7, 0x6A, 0xFF, +0x1F, 0xBD, 0xC0, 0x46, 0xEB, 0x01, 0x00, 0x20, 0x87, 0x59, 0x00, 0x00, +0xF8, 0xB5, 0xFF, 0xF7, 0xD7, 0xFA, 0x00, 0x28, 0x70, 0xD1, 0x39, 0x4B, +0x1A, 0x68, 0x00, 0x2A, 0x03, 0xDC, 0x38, 0x4B, 0x1B, 0x68, 0x00, 0x2B, +0x3E, 0xDD, 0x37, 0x49, 0x03, 0x23, 0x0B, 0x70, 0x36, 0x4B, 0x04, 0x33, +0xDB, 0x7F, 0x1C, 0x1C, 0x9A, 0x42, 0x00, 0xDA, 0xD3, 0xB2, 0x4B, 0x70, +0x0A, 0x21, 0x8C, 0x46, 0x32, 0x4A, 0x00, 0x23, 0x2D, 0x49, 0x1F, 0xE0, +0x01, 0x33, 0x03, 0xE0, 0x66, 0x46, 0x5E, 0x43, 0x00, 0x20, 0x76, 0x18, +0x0A, 0x30, 0x37, 0x18, 0x32, 0x25, 0x7F, 0x5F, 0x00, 0x2F, 0xF3, 0xD0, +0xA3, 0x42, 0x13, 0xDA, 0x58, 0x00, 0x08, 0x18, 0x80, 0x88, 0xDE, 0x00, +0x10, 0x70, 0x00, 0xB2, 0x00, 0x12, 0x80, 0x19, 0x50, 0x70, 0x18, 0x1C, +0x10, 0x30, 0x40, 0x00, 0x08, 0x5A, 0x01, 0x33, 0x90, 0x70, 0x00, 0x0A, +0xD0, 0x70, 0x04, 0x32, 0xA3, 0x42, 0xDF, 0xDB, 0x1D, 0x4B, 0x1F, 0x4A, +0x5A, 0x60, 0x00, 0x22, 0x9A, 0x60, 0xFF, 0xF7, 0x3D, 0xFA, 0xFF, 0xF7, +0x91, 0xFA, 0x00, 0x28, 0xFB, 0xD1, 0x29, 0xE0, 0x1A, 0x4A, 0x53, 0x68, +0x01, 0x33, 0x25, 0xD0, 0x15, 0x4B, 0x13, 0x21, 0x19, 0x70, 0x11, 0x68, +0x94, 0x46, 0x59, 0x70, 0x16, 0x4B, 0x14, 0x49, 0x1D, 0x78, 0x03, 0x1C, +0x0D, 0xE0, 0x23, 0x1C, 0x01, 0xE0, 0x5E, 0x00, 0x66, 0x44, 0x02, 0x30, +0x34, 0x18, 0x06, 0x22, 0xA7, 0x5E, 0x5C, 0x1C, 0x00, 0x2F, 0xF4, 0xD0, +0x0B, 0x70, 0x23, 0x1C, 0x01, 0x31, 0x00, 0x20, 0xAB, 0x42, 0xF0, 0xDB, +0x07, 0x4B, 0x09, 0x4A, 0x98, 0x60, 0x5A, 0x60, 0xFF, 0xF7, 0x12, 0xFA, +0xFF, 0xF7, 0x66, 0xFA, 0x00, 0x28, 0xFB, 0xD1, 0xF8, 0xBD, 0xC0, 0x46, +0x9C, 0x0D, 0x00, 0x20, 0x20, 0x01, 0x00, 0x20, 0x70, 0x00, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0xF0, 0x09, 0x00, 0x20, 0xE0, 0x00, 0x00, 0x20, +0x7C, 0x09, 0x00, 0x20, 0x08, 0xB5, 0x64, 0x4B, 0x1B, 0x88, 0x1D, 0x2B, +0x47, 0xD0, 0x1A, 0xD8, 0x05, 0x2B, 0x00, 0xD1, 0x96, 0xE0, 0x0D, 0xD8, +0x02, 0x2B, 0x63, 0xD0, 0x03, 0xD8, 0x01, 0x2B, 0x00, 0xD0, 0xB7, 0xE0, +0x57, 0xE0, 0x03, 0x2B, 0x00, 0xD1, 0x87, 0xE0, 0x04, 0x2B, 0x00, 0xD0, +0xB0, 0xE0, 0x8F, 0xE0, 0x07, 0x2B, 0x65, 0xD0, 0x5C, 0xD3, 0x1B, 0x2B, +0x1C, 0xD0, 0x1C, 0x2B, 0x00, 0xD0, 0xA7, 0xE0, 0x22, 0xE0, 0x22, 0x2B, +0x40, 0xD0, 0x08, 0xD8, 0x1F, 0x2B, 0x5D, 0xD0, 0x2A, 0xD3, 0x20, 0x2B, +0x5E, 0xD0, 0x21, 0x2B, 0x00, 0xD0, 0x9B, 0xE0, 0x5E, 0xE0, 0x41, 0x2B, +0x64, 0xD0, 0x03, 0xD8, 0x40, 0x2B, 0x00, 0xD0, 0x94, 0xE0, 0x5B, 0xE0, +0x42, 0x2B, 0x61, 0xD0, 0x60, 0x2B, 0x00, 0xD0, 0x8E, 0xE0, 0x72, 0xE0, +0x48, 0x4A, 0x49, 0x4B, 0x12, 0x78, 0x01, 0x20, 0x19, 0x68, 0x90, 0x40, +0x02, 0x1C, 0x0A, 0x43, 0x1A, 0x60, 0x83, 0xE0, 0x43, 0x49, 0x44, 0x4B, +0x09, 0x78, 0x1A, 0x68, 0x01, 0x20, 0x88, 0x40, 0x82, 0x43, 0x1A, 0x60, +0x7A, 0xE0, 0x3F, 0x4B, 0x1A, 0x78, 0x40, 0x4B, 0x1A, 0x70, 0x75, 0xE0, +0x3C, 0x4B, 0x0D, 0x21, 0x1A, 0x78, 0x3E, 0x4B, 0x1A, 0x70, 0x3C, 0x4A, +0x11, 0x70, 0x1A, 0x78, 0x3C, 0x4B, 0x00, 0x2A, 0x02, 0xD0, 0x00, 0x22, +0x5A, 0x70, 0x67, 0xE0, 0x3A, 0x4A, 0x52, 0x78, 0x5A, 0x70, 0x63, 0xE0, +0x33, 0x4B, 0x1A, 0x78, 0x38, 0x4B, 0x1A, 0x70, 0x5E, 0xE0, 0x31, 0x4B, +0x1A, 0x78, 0x37, 0x4B, 0x1A, 0x60, 0xFD, 0xF7, 0x09, 0xFC, 0x57, 0xE0, +0x2D, 0x4B, 0x1A, 0x78, 0x34, 0x4B, 0x9A, 0x70, 0x98, 0x78, 0xFF, 0xF7, +0x8D, 0xFC, 0x4F, 0xE0, 0x29, 0x4B, 0x1A, 0x78, 0x30, 0x4B, 0x9A, 0x70, +0x29, 0x4B, 0x0F, 0x22, 0x1A, 0x70, 0x47, 0xE0, 0x2E, 0x4B, 0x01, 0x22, +0x1A, 0x70, 0x43, 0xE0, 0x2D, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x3F, 0xE0, +0x0C, 0x20, 0xFD, 0xF7, 0x85, 0xF9, 0x3B, 0xE0, 0x0D, 0x20, 0xFD, 0xF7, +0x81, 0xF9, 0x37, 0xE0, 0x28, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x33, 0xE0, +0x27, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x2F, 0xE0, 0x26, 0x4B, 0x01, 0x22, +0x1A, 0x70, 0x2B, 0xE0, 0x25, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x27, 0xE0, +0x24, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x14, 0x4B, 0x1A, 0x78, 0x23, 0x4B, +0x1A, 0x70, 0x1F, 0xE0, 0x11, 0x4B, 0x1A, 0x78, 0x1E, 0x4B, 0x9A, 0x70, +0x1A, 0xE0, 0x0F, 0x4B, 0x1A, 0x78, 0x1F, 0x4B, 0x1A, 0x70, 0x1A, 0x78, +0x10, 0x4B, 0x01, 0x3A, 0x01, 0x2A, 0x03, 0xD8, 0x40, 0x33, 0x0F, 0x22, +0x1A, 0x70, 0x0D, 0xE0, 0x1A, 0x4A, 0x40, 0x33, 0x12, 0x78, 0x00, 0x2A, +0x04, 0xD0, 0x19, 0x4A, 0x40, 0x32, 0x12, 0x78, 0x1A, 0x70, 0x03, 0xE0, +0x08, 0x4A, 0x40, 0x32, 0x12, 0x78, 0x1A, 0x70, 0x08, 0xBD, 0xC0, 0x46, +0x28, 0x00, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x50, 0x58, 0x00, 0x00, 0x20, +0x1D, 0x03, 0x00, 0x20, 0xE3, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x4A, 0x74, 0x00, 0x00, 0xDE, 0x01, 0x00, 0x20, 0x50, 0x11, 0x00, 0x20, +0xAA, 0x0A, 0x00, 0x20, 0xE4, 0x01, 0x00, 0x20, 0xDC, 0x01, 0x00, 0x20, +0xE8, 0x01, 0x00, 0x20, 0xE7, 0x01, 0x00, 0x20, 0xE5, 0x01, 0x00, 0x20, +0x8B, 0x01, 0x00, 0x20, 0xE6, 0x01, 0x00, 0x20, 0x92, 0x01, 0x00, 0x20, +0xE0, 0x01, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, 0x9A, 0x74, 0x00, 0x00, +0x30, 0xB5, 0x4A, 0x4B, 0x1B, 0x88, 0x34, 0x2B, 0x47, 0xD0, 0x0C, 0xD8, +0x2E, 0x2B, 0x4F, 0xD0, 0x04, 0xD8, 0x00, 0x2B, 0x14, 0xD0, 0x1D, 0x2B, +0x78, 0xD1, 0x16, 0xE0, 0x2F, 0x2B, 0x51, 0xD0, 0x30, 0x2B, 0x73, 0xD1, +0x56, 0xE0, 0x38, 0x2B, 0x66, 0xD0, 0x04, 0xD8, 0x35, 0x2B, 0x39, 0xD0, +0x37, 0x2B, 0x6B, 0xD1, 0x5B, 0xE0, 0x39, 0x2B, 0x63, 0xD0, 0x86, 0x2B, +0x66, 0xD1, 0x09, 0xE0, 0x3B, 0x4B, 0x5A, 0x7B, 0x3B, 0x4B, 0x1A, 0x70, +0x6F, 0xE0, 0x3B, 0x4B, 0x1A, 0x78, 0x39, 0x4B, 0x1A, 0x70, 0x6A, 0xE0, +0x39, 0x49, 0x3A, 0x4A, 0x0B, 0x78, 0x00, 0x2B, 0x0F, 0xD1, 0x10, 0x78, +0x34, 0x49, 0x08, 0x70, 0x50, 0x78, 0x37, 0x49, 0x08, 0x70, 0x52, 0x68, +0xD1, 0x18, 0x36, 0x4C, 0x08, 0x78, 0x19, 0x19, 0x01, 0x33, 0x08, 0x70, +0x06, 0x2B, 0xF7, 0xD1, 0x55, 0xE0, 0x52, 0x68, 0x00, 0x23, 0x08, 0x78, +0x2B, 0x4D, 0xC0, 0x18, 0x02, 0x38, 0x10, 0x18, 0x04, 0x78, 0x58, 0x19, +0x01, 0x33, 0x04, 0x70, 0x08, 0x2B, 0xF4, 0xD1, 0x47, 0xE0, 0x2C, 0x4B, +0x1A, 0x68, 0x25, 0x4B, 0x1A, 0x60, 0x42, 0xE0, 0x80, 0x23, 0xDB, 0x05, +0x1A, 0x79, 0x22, 0x4B, 0x1A, 0x70, 0x3C, 0xE0, 0x22, 0x4B, 0x27, 0x4A, +0x1B, 0x78, 0x1F, 0x49, 0xD3, 0x18, 0x1A, 0x68, 0x5B, 0x68, 0x0A, 0x60, +0x4B, 0x60, 0x32, 0xE0, 0x1A, 0x4B, 0x1A, 0x1C, 0x2C, 0x32, 0x11, 0x78, +0x19, 0x4A, 0x00, 0x29, 0x07, 0xD1, 0x09, 0xE0, 0x16, 0x4B, 0x1A, 0x1C, +0x2C, 0x32, 0x11, 0x78, 0x15, 0x4A, 0x00, 0x29, 0x02, 0xD1, 0xDB, 0x8C, +0x13, 0x80, 0x20, 0xE0, 0x1B, 0x8D, 0x13, 0x80, 0x1D, 0xE0, 0x19, 0x4B, +0x1A, 0x78, 0x10, 0x4B, 0x1A, 0x70, 0x18, 0xE0, 0x17, 0x4B, 0x1A, 0x78, +0x0D, 0x4B, 0x1A, 0x70, 0x13, 0xE0, 0x16, 0x4B, 0x1A, 0x78, 0x0B, 0x4B, +0x1A, 0x70, 0x0E, 0xE0, 0x90, 0x3B, 0x9A, 0xB2, 0x13, 0x2A, 0x0A, 0xD8, +0x09, 0x4A, 0x5B, 0x01, 0x12, 0x78, 0x06, 0x49, 0x9B, 0x18, 0x10, 0x4A, +0x9B, 0x18, 0x1A, 0x68, 0x5B, 0x68, 0x0A, 0x60, 0x4B, 0x60, 0x30, 0xBD, +0x28, 0x00, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x50, +0x1D, 0x03, 0x00, 0x20, 0x2A, 0x00, 0x00, 0x20, 0x70, 0x00, 0x00, 0x20, +0x0D, 0x00, 0x00, 0x50, 0x0E, 0x00, 0x00, 0x50, 0x1C, 0x09, 0x00, 0x20, +0xB1, 0x09, 0x00, 0x20, 0xFF, 0x5B, 0x00, 0x00, 0xFF, 0x73, 0x00, 0x00, +0xFF, 0x7B, 0x00, 0x00, 0xB3, 0x0A, 0x00, 0x20, 0x08, 0xB5, 0x08, 0x4B, +0x1B, 0x88, 0x86, 0x2B, 0x0B, 0xD1, 0x07, 0x4B, 0x9A, 0x68, 0x01, 0x2A, +0x02, 0xDC, 0x9A, 0x68, 0x01, 0x32, 0x9A, 0x60, 0x9B, 0x68, 0x02, 0x2B, +0x01, 0xD1, 0xFF, 0xF7, 0x71, 0xF8, 0x08, 0xBD, 0x28, 0x00, 0x00, 0x20, +0x70, 0x00, 0x00, 0x20, 0x7F, 0xB5, 0x31, 0x4C, 0x03, 0x90, 0x23, 0x78, +0x0D, 0x1C, 0x16, 0x1C, 0x00, 0x2B, 0x03, 0xD0, 0x01, 0x20, 0x2E, 0x49, +0xFF, 0xF7, 0x6E, 0xFD, 0x23, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x21, +0x08, 0x1C, 0x03, 0xAA, 0x04, 0x23, 0x00, 0x91, 0xFF, 0xF7, 0x0C, 0xFD, +0x28, 0x4B, 0x03, 0x99, 0x1B, 0x78, 0x28, 0x4A, 0x00, 0x2B, 0x15, 0xD1, +0x13, 0x1C, 0x4A, 0x33, 0x00, 0x20, 0x1B, 0x5E, 0x8E, 0x1B, 0x9E, 0x42, +0x05, 0xDC, 0x13, 0x1C, 0x4C, 0x33, 0x00, 0x20, 0x1B, 0x5E, 0x9E, 0x42, +0x08, 0xDA, 0x21, 0x48, 0x01, 0x23, 0x03, 0x70, 0x20, 0x48, 0x03, 0x70, +0x20, 0x48, 0x03, 0x70, 0x20, 0x48, 0x03, 0x70, 0x53, 0x78, 0x00, 0x2B, +0x04, 0xD0, 0x1F, 0x4B, 0x5B, 0x5D, 0x59, 0x43, 0x89, 0x11, 0x03, 0x91, +0x1D, 0x4B, 0x6A, 0x00, 0xD0, 0x5A, 0x1D, 0x4B, 0x03, 0x99, 0xD4, 0x5E, +0xC0, 0x08, 0x14, 0x4A, 0x89, 0xB2, 0x04, 0x1B, 0x64, 0x1A, 0x56, 0x7C, +0x24, 0xB2, 0x19, 0x4B, 0xB4, 0x42, 0x02, 0xDC, 0x76, 0x42, 0xB4, 0x42, +0x02, 0xDA, 0x00, 0x24, 0x5C, 0x55, 0x05, 0xE0, 0x5C, 0x5D, 0x96, 0x7C, +0xA6, 0x42, 0x01, 0xD0, 0x01, 0x34, 0x5C, 0x55, 0x43, 0x1A, 0x9B, 0xB2, +0x92, 0x7E, 0x19, 0xB2, 0x91, 0x42, 0x02, 0xDB, 0x09, 0x4A, 0x01, 0x21, +0x11, 0x70, 0x0C, 0x4A, 0x6D, 0x00, 0xAB, 0x52, 0x7F, 0xBD, 0xC0, 0x46, +0xEB, 0x01, 0x00, 0x20, 0x8B, 0x59, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x48, 0x11, 0x00, 0x20, 0x14, 0x09, 0x00, 0x20, +0x30, 0x11, 0x00, 0x20, 0xC4, 0x01, 0x00, 0x20, 0x92, 0x7B, 0x00, 0x00, +0x14, 0x02, 0x00, 0x20, 0x3C, 0x0D, 0x00, 0x20, 0xA4, 0x0A, 0x00, 0x20, +0xF0, 0xB5, 0x48, 0x4B, 0x89, 0xB0, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, +0x00, 0x20, 0x46, 0x49, 0xFF, 0xF7, 0xF4, 0xFC, 0x45, 0x4A, 0x00, 0x23, +0x13, 0x70, 0x45, 0x4A, 0x0C, 0x20, 0x01, 0x38, 0xC0, 0xB2, 0x81, 0x00, +0x8B, 0x50, 0x00, 0x28, 0xF9, 0xD1, 0x42, 0x4B, 0x42, 0x4A, 0x18, 0x70, +0x01, 0x23, 0x13, 0x70, 0x41, 0x4A, 0x13, 0x70, 0x41, 0x4B, 0x19, 0x7E, +0x04, 0x91, 0xDA, 0x7D, 0x05, 0x92, 0x1B, 0x7D, 0x06, 0x93, 0x0B, 0x1C, +0x2D, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x5D, 0x1C, 0x3C, 0x4C, 0xEA, 0x01, +0x12, 0x19, 0x16, 0x88, 0x3B, 0x49, 0x5A, 0x00, 0x5C, 0x01, 0x56, 0x52, +0xAD, 0x01, 0x05, 0x9A, 0x07, 0x94, 0x9C, 0x46, 0x1A, 0xE0, 0x01, 0x3A, +0xD2, 0xB2, 0x93, 0x1C, 0xEB, 0x18, 0x36, 0x4C, 0x5B, 0x00, 0x19, 0x5B, +0x06, 0x9B, 0x00, 0x2B, 0x05, 0xD0, 0xD3, 0x1C, 0xEB, 0x18, 0x5B, 0x00, +0x1B, 0x5B, 0xC9, 0x18, 0x49, 0x10, 0x07, 0x9C, 0xA7, 0x18, 0x7B, 0x00, +0x1C, 0x1C, 0x2F, 0x4B, 0xE1, 0x52, 0x2F, 0x4C, 0x01, 0x23, 0x89, 0x1B, +0x3B, 0x55, 0x40, 0x18, 0x00, 0x2A, 0xE2, 0xD1, 0x63, 0x46, 0x00, 0x2B, +0xCF, 0xD1, 0x25, 0x4B, 0x04, 0x9C, 0xD9, 0x7D, 0x61, 0x43, 0x01, 0xF0, +0xD5, 0xF8, 0x28, 0x4B, 0x05, 0x1C, 0x58, 0x8C, 0x27, 0x4C, 0x00, 0x28, +0x02, 0xD1, 0x40, 0x23, 0x23, 0x60, 0x07, 0xE0, 0x80, 0x01, 0x29, 0x1C, +0x01, 0xF0, 0xC8, 0xF8, 0x6E, 0x28, 0x00, 0xDD, 0x6E, 0x20, 0x20, 0x60, +0x12, 0x4C, 0x23, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x00, 0x20, 0x1F, 0x49, +0xFF, 0xF7, 0x8A, 0xFC, 0x1B, 0x4B, 0x1E, 0x4A, 0x5B, 0x8C, 0x55, 0x80, +0x13, 0x80, 0x23, 0x78, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, +0x00, 0x93, 0x00, 0x20, 0x0B, 0x1C, 0xFF, 0xF7, 0x23, 0xFC, 0x18, 0x4B, +0x18, 0x48, 0x1B, 0x78, 0x00, 0x22, 0x18, 0x49, 0x04, 0xE0, 0x01, 0x3B, +0xDB, 0xB2, 0x5C, 0x00, 0xC2, 0x54, 0x62, 0x52, 0x00, 0x2B, 0xF8, 0xD1, +0x09, 0xB0, 0xF0, 0xBD, 0xEB, 0x01, 0x00, 0x20, 0x91, 0x59, 0x00, 0x00, +0x1C, 0x03, 0x00, 0x20, 0xBC, 0x11, 0x00, 0x20, 0xF4, 0x10, 0x00, 0x20, +0x20, 0x09, 0x00, 0x20, 0x3C, 0x11, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0x02, 0x40, 0x00, 0x40, 0x94, 0x11, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, +0xF8, 0x03, 0x00, 0x20, 0xB3, 0x0A, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x78, 0x09, 0x00, 0x20, 0x9A, 0x59, 0x00, 0x00, 0x54, 0x11, 0x00, 0x20, +0x7C, 0x09, 0x00, 0x20, 0xA4, 0x0A, 0x00, 0x20, 0x14, 0x02, 0x00, 0x20, +0xF0, 0xB5, 0xA0, 0x4A, 0x00, 0x23, 0x13, 0x70, 0x9F, 0x4A, 0x85, 0xB0, +0x13, 0x70, 0x9F, 0x4A, 0x13, 0x70, 0x9F, 0x4A, 0x13, 0x70, 0x9F, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x01, 0x20, 0x9D, 0x49, 0xFF, 0xF7, +0x31, 0xFC, 0x00, 0x24, 0x9C, 0x4D, 0x9A, 0x4E, 0x11, 0xE0, 0x33, 0x78, +0x00, 0x2B, 0x0C, 0xD0, 0xEB, 0x7D, 0x29, 0x7D, 0x99, 0x48, 0xC9, 0x18, +0xE2, 0x01, 0x00, 0x23, 0x12, 0x18, 0x00, 0x93, 0xC9, 0xB2, 0x01, 0x20, +0x02, 0x23, 0xFF, 0xF7, 0xC5, 0xFB, 0x01, 0x34, 0xE4, 0xB2, 0x29, 0x7E, +0x8C, 0x42, 0xEA, 0xD3, 0x92, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD1, +0x0D, 0xE1, 0x91, 0x4B, 0x1A, 0x78, 0x00, 0x2A, 0x1F, 0xD1, 0x90, 0x4B, +0x1B, 0x78, 0x00, 0x2B, 0x1B, 0xD0, 0xEB, 0x7D, 0x8E, 0x4C, 0x07, 0xE0, +0x01, 0x3B, 0xDB, 0xB2, 0x5D, 0x01, 0x2D, 0x18, 0x2A, 0x55, 0x00, 0x2B, +0xF8, 0xD1, 0x03, 0x1C, 0x58, 0x1E, 0xC0, 0xB2, 0x00, 0x2B, 0x01, 0xD0, +0x0B, 0x1C, 0xF6, 0xE7, 0x87, 0x4A, 0x86, 0x48, 0x12, 0x78, 0x49, 0x01, +0x03, 0xE0, 0x01, 0x3A, 0xD2, 0xB2, 0x8C, 0x18, 0x23, 0x54, 0x00, 0x2A, +0xF9, 0xD1, 0x80, 0x4B, 0x7E, 0x4A, 0x19, 0x78, 0x1B, 0x78, 0x11, 0x70, +0x00, 0x2B, 0x70, 0xD0, 0x78, 0x4B, 0x1A, 0x7E, 0xD9, 0x7D, 0x02, 0x92, +0x1B, 0x7D, 0x03, 0x93, 0x22, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x59, 0x1C, +0x89, 0x01, 0xC8, 0x19, 0x79, 0x4C, 0x03, 0x9D, 0x40, 0x00, 0x00, 0x5B, +0x00, 0x2D, 0x04, 0xD0, 0x89, 0x19, 0x49, 0x00, 0x09, 0x5B, 0x40, 0x18, +0x40, 0x10, 0x59, 0x01, 0x89, 0x18, 0x74, 0x4D, 0x4C, 0x00, 0x65, 0x5B, +0x6F, 0x4C, 0xED, 0x08, 0x0C, 0x5D, 0x28, 0x1A, 0x84, 0x42, 0x04, 0xDA, +0xFF, 0x28, 0x00, 0xDD, 0xFF, 0x20, 0x6B, 0x4D, 0x68, 0x54, 0x00, 0x2B, +0xDD, 0xD1, 0x11, 0x1C, 0x4A, 0x1E, 0xD2, 0xB2, 0x00, 0x29, 0x03, 0xD0, +0x02, 0x9B, 0x97, 0x1C, 0xD6, 0x1C, 0xF4, 0xE7, 0x5F, 0x4A, 0x65, 0x4B, +0x17, 0x7E, 0x1B, 0x78, 0x62, 0x49, 0x7F, 0x01, 0x10, 0xE0, 0x01, 0x3B, +0xDB, 0xB2, 0x64, 0x4E, 0x5A, 0x00, 0x94, 0x5B, 0xF8, 0x18, 0x45, 0x56, +0x26, 0xB2, 0x2A, 0x1C, 0xB5, 0x42, 0x00, 0xDA, 0x22, 0x1C, 0x12, 0xB2, +0xFF, 0x2A, 0x00, 0xDD, 0xFF, 0x22, 0x42, 0x54, 0x00, 0x2B, 0xEC, 0xD1, +0x50, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x03, 0x20, 0x5A, 0x49, +0xFF, 0xF7, 0x94, 0xFB, 0x00, 0x24, 0x4E, 0x4D, 0x4B, 0x4E, 0x0E, 0xE0, +0x33, 0x78, 0x00, 0x2B, 0x09, 0xD0, 0x50, 0x4B, 0x62, 0x01, 0xD2, 0x18, +0x00, 0x23, 0xE9, 0x7D, 0x03, 0x20, 0x00, 0x93, 0x01, 0x23, 0xFF, 0xF7, +0x2B, 0xFB, 0x01, 0x34, 0xE4, 0xB2, 0x2B, 0x7E, 0xA3, 0x42, 0xED, 0xD8, +0x40, 0x4A, 0x01, 0x23, 0x13, 0x70, 0x3D, 0x4A, 0x13, 0x70, 0x3B, 0x4A, +0x13, 0x70, 0x3E, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x6D, 0xD0, 0x49, 0x4B, +0x1B, 0x68, 0x58, 0x02, 0x69, 0xD5, 0x3C, 0x4A, 0x80, 0x24, 0x16, 0x7D, +0x13, 0x7E, 0xD2, 0x7D, 0x45, 0x4D, 0xB6, 0x18, 0xF6, 0xB2, 0x24, 0x06, +0xB4, 0x46, 0x18, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0x42, 0x49, 0x5A, 0x00, +0x5F, 0x1C, 0x56, 0x5A, 0xBF, 0x01, 0x62, 0x46, 0x0D, 0xE0, 0x01, 0x3A, +0xD2, 0xB2, 0x91, 0x1C, 0x79, 0x18, 0x37, 0x48, 0x49, 0x00, 0x09, 0x5A, +0x89, 0x1B, 0x8C, 0x42, 0x00, 0xDA, 0x0C, 0x1C, 0x8D, 0x42, 0x00, 0xDD, +0x0D, 0x1C, 0x00, 0x2A, 0xEF, 0xD1, 0x00, 0x2B, 0xE4, 0xD1, 0x16, 0x20, +0x36, 0x49, 0xFF, 0xF7, 0x45, 0xFB, 0x25, 0x4B, 0x35, 0x4A, 0x1B, 0x78, +0x14, 0x80, 0x55, 0x80, 0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x02, 0x21, +0x00, 0x93, 0x16, 0x20, 0x0B, 0x1C, 0xFF, 0xF7, 0xDF, 0xFA, 0x26, 0x4B, +0x80, 0x20, 0x1B, 0x78, 0x2A, 0x49, 0x00, 0x06, 0x2D, 0x4E, 0x2E, 0x4D, +0x19, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0xF7, 0x5C, 0x7A, 0x1C, 0x94, 0x46, +0x64, 0x46, 0xEA, 0x5C, 0xA4, 0x01, 0xA4, 0x46, 0x02, 0x32, 0x62, 0x44, +0x1D, 0x4C, 0x52, 0x00, 0x12, 0x5B, 0x22, 0x4C, 0x7F, 0x00, 0x94, 0x46, +0x3A, 0x5B, 0x64, 0x46, 0xA2, 0x1A, 0x90, 0x42, 0x00, 0xDA, 0x10, 0x1C, +0x91, 0x42, 0x00, 0xDD, 0x11, 0x1C, 0x00, 0x2B, 0xE3, 0xD1, 0x0C, 0x4B, +0x1C, 0x4A, 0x1B, 0x78, 0x10, 0x80, 0x51, 0x80, 0x00, 0x2B, 0x06, 0xD0, +0x01, 0x23, 0x02, 0x21, 0x00, 0x93, 0x16, 0x20, 0x0B, 0x1C, 0xFF, 0xF7, +0xAD, 0xFA, 0x05, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, 0xAC, 0x09, 0x00, 0x20, +0x14, 0x09, 0x00, 0x20, 0x30, 0x11, 0x00, 0x20, 0x48, 0x11, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0xAB, 0x59, 0x00, 0x00, 0xAE, 0x09, 0x00, 0x20, +0x84, 0x40, 0x00, 0x40, 0x1C, 0x03, 0x00, 0x20, 0xE1, 0x01, 0x00, 0x20, +0xE3, 0x01, 0x00, 0x20, 0x64, 0x0E, 0x00, 0x20, 0x7C, 0x09, 0x00, 0x20, +0x00, 0x40, 0x00, 0x40, 0xF8, 0x03, 0x00, 0x20, 0x3C, 0x0D, 0x00, 0x20, +0xAF, 0x59, 0x00, 0x00, 0x58, 0x00, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x7F, +0x94, 0x11, 0x00, 0x20, 0xB5, 0x59, 0x00, 0x00, 0x54, 0x11, 0x00, 0x20, +0x30, 0x75, 0x00, 0x00, 0x2A, 0x75, 0x00, 0x00, 0xF0, 0xB5, 0xB3, 0x4B, +0xA5, 0xB0, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD0, 0x01, 0xE2, 0xB1, 0x4A, +0xB1, 0x4C, 0x12, 0x78, 0xB1, 0x4D, 0xB2, 0x4E, 0x64, 0x7C, 0x52, 0xB2, +0x6B, 0x60, 0x2B, 0x60, 0x6B, 0x82, 0x6B, 0x81, 0x2B, 0x82, 0x2B, 0x81, +0x33, 0x60, 0xB3, 0x60, 0x1B, 0x92, 0xAD, 0x4F, 0xFF, 0x22, 0xAD, 0x4B, +0x72, 0x60, 0xF2, 0x60, 0x11, 0x94, 0x3F, 0x7E, 0x1B, 0x78, 0xA9, 0x4C, +0x09, 0x97, 0x0B, 0x93, 0xE4, 0x7D, 0xA4, 0x4D, 0x08, 0x94, 0x46, 0x23, +0xED, 0x5E, 0xA2, 0x4F, 0x0E, 0x95, 0x48, 0x23, 0xFF, 0x5E, 0xA3, 0x4C, +0x0F, 0x97, 0x24, 0x7D, 0x2D, 0x23, 0x0C, 0x94, 0x9D, 0x4D, 0xA2, 0x4E, +0x11, 0x9F, 0x6D, 0x78, 0x36, 0x68, 0x7F, 0x42, 0x9A, 0x4C, 0x0D, 0x95, +0x12, 0x96, 0x1D, 0x97, 0xA4, 0x7C, 0x98, 0x4D, 0x22, 0x94, 0xEB, 0x5C, +0x1B, 0x9E, 0x13, 0x93, 0x10, 0x23, 0x9B, 0x1B, 0x1E, 0x93, 0x18, 0x27, +0xEF, 0x57, 0x1C, 0x20, 0x14, 0x97, 0x28, 0x56, 0x19, 0x21, 0x18, 0x90, +0x69, 0x56, 0x00, 0x23, 0x00, 0x22, 0x00, 0x24, 0x23, 0x91, 0x05, 0x93, +0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0xFF, 0x20, 0x00, 0x21, 0xFF, 0x23, +0x06, 0x92, 0x17, 0x94, 0x10, 0x95, 0x1A, 0x96, 0x15, 0x97, 0x19, 0x90, +0x21, 0x91, 0x1F, 0x92, 0x16, 0x93, 0x1C, 0x94, 0x09, 0x9C, 0x00, 0x2C, +0x00, 0xD1, 0x27, 0xE1, 0x09, 0x9B, 0x89, 0x4D, 0x01, 0x3B, 0xDB, 0xB2, +0x09, 0x93, 0x5B, 0x00, 0x5B, 0x5B, 0x08, 0x9E, 0x0A, 0x93, 0x00, 0x2E, +0xF0, 0xD0, 0x09, 0x9F, 0x84, 0x48, 0x01, 0x37, 0xFB, 0x01, 0x1B, 0x18, +0x1B, 0x88, 0x0A, 0x99, 0x0E, 0x9C, 0x5A, 0x1A, 0x94, 0x42, 0x00, 0xDA, +0x92, 0xE1, 0x0F, 0x9D, 0x95, 0x42, 0x00, 0xDD, 0x8B, 0xE1, 0x09, 0x9E, +0xBF, 0x01, 0x01, 0x21, 0x02, 0x25, 0x00, 0x22, 0x70, 0x01, 0x03, 0x97, +0x2C, 0xE0, 0x7A, 0x4D, 0x84, 0x18, 0x64, 0x00, 0x6E, 0x46, 0x18, 0x27, +0x2C, 0x5B, 0xBD, 0x5F, 0xE4, 0x1A, 0xAC, 0x42, 0x01, 0xDD, 0xA7, 0xB2, +0x06, 0x97, 0x6E, 0x46, 0x14, 0x27, 0xBD, 0x5F, 0xAC, 0x42, 0x01, 0xDA, +0xA4, 0xB2, 0x05, 0x94, 0x82, 0x18, 0x70, 0x4F, 0x52, 0x00, 0xBB, 0x52, +0x08, 0x9A, 0xCB, 0xB2, 0x9A, 0x42, 0xBD, 0xD9, 0x03, 0x9A, 0x8D, 0x1C, +0x53, 0x19, 0x6C, 0x4C, 0x5B, 0x00, 0x1B, 0x5B, 0x0A, 0x9E, 0x0E, 0x9F, +0x0A, 0x1C, 0x9C, 0x1B, 0xBC, 0x42, 0x00, 0xDD, 0x38, 0xE1, 0x0F, 0x9E, +0x01, 0x31, 0xB4, 0x42, 0x00, 0xDA, 0xD1, 0xE0, 0x0C, 0x9F, 0x00, 0x2F, +0x07, 0xD0, 0x03, 0x9E, 0xD4, 0x1C, 0x34, 0x19, 0x61, 0x4F, 0x64, 0x00, +0xE4, 0x5B, 0xE3, 0x18, 0x5B, 0x10, 0x0D, 0x9C, 0x00, 0x2C, 0x06, 0xD0, +0x5E, 0x4E, 0x84, 0x18, 0xA4, 0x5D, 0x12, 0x9F, 0x63, 0x43, 0x7B, 0x43, +0x1B, 0x13, 0x0B, 0x9C, 0x00, 0x2C, 0xBA, 0xD0, 0x86, 0x18, 0x57, 0x4F, +0x74, 0x00, 0x3F, 0x5B, 0xBC, 0x46, 0x58, 0x4F, 0xBC, 0x57, 0x66, 0x46, +0xF6, 0x08, 0x34, 0x1B, 0x07, 0x94, 0x6F, 0x46, 0x18, 0x24, 0x04, 0x96, +0xE7, 0x5F, 0x07, 0x9E, 0xF4, 0x1A, 0xBC, 0x42, 0x01, 0xDD, 0xA7, 0xB2, +0x06, 0x97, 0x6E, 0x46, 0x14, 0x27, 0xBE, 0x5F, 0xB4, 0x42, 0x01, 0xDA, +0xA6, 0xB2, 0x05, 0x96, 0x11, 0x9F, 0xBC, 0x42, 0x5D, 0xDD, 0x84, 0x18, +0xA4, 0x46, 0x4B, 0x4C, 0x00, 0x27, 0x66, 0x46, 0x37, 0x55, 0x04, 0x9F, +0x13, 0x9E, 0xFC, 0x1A, 0x00, 0x2E, 0x08, 0xD0, 0x1B, 0x9F, 0x07, 0x9C, +0x1E, 0x9E, 0x7B, 0x43, 0x74, 0x43, 0x04, 0x9F, 0x1C, 0x19, 0x24, 0x11, +0x3C, 0x1B, 0x23, 0x1C, 0x7F, 0x33, 0x17, 0xDA, 0x3F, 0x4E, 0x82, 0x18, +0x80, 0x23, 0xB3, 0x54, 0x23, 0x9A, 0x21, 0x9E, 0xA3, 0x1A, 0xF6, 0x18, +0x21, 0x96, 0x1F, 0xAF, 0x00, 0x23, 0xFB, 0x5E, 0x9C, 0x42, 0x01, 0xDC, +0xA4, 0xB2, 0x1F, 0x94, 0x03, 0x9A, 0x35, 0x4C, 0x55, 0x19, 0x6D, 0x00, +0x00, 0x27, 0x2B, 0x5B, 0x2F, 0x53, 0x83, 0xE7, 0x83, 0x18, 0x7E, 0x2C, +0x36, 0xDD, 0x32, 0x4E, 0x7F, 0x27, 0xF7, 0x54, 0x14, 0x9F, 0xBC, 0x42, +0x03, 0xDB, 0x17, 0x9E, 0xE3, 0x1B, 0xF6, 0x18, 0x17, 0x96, 0x10, 0xAF, +0x00, 0x23, 0xFB, 0x5E, 0x9C, 0x42, 0x24, 0xDC, 0xA3, 0xB2, 0x18, 0x9E, +0xB4, 0x42, 0x11, 0xDB, 0x1A, 0x9F, 0x09, 0x9C, 0xA7, 0x42, 0x00, 0xDA, +0x1A, 0x94, 0x16, 0x9E, 0x09, 0x9C, 0xA6, 0x42, 0x00, 0xDD, 0x16, 0x94, +0x15, 0x9E, 0x96, 0x42, 0x00, 0xDA, 0x15, 0x92, 0x19, 0x9F, 0xBA, 0x42, +0x00, 0xDA, 0x19, 0x92, 0x03, 0x9A, 0x1D, 0x4C, 0x55, 0x19, 0x6D, 0x00, +0x2A, 0x5B, 0x2B, 0x53, 0x54, 0xE7, 0x1D, 0x9E, 0x87, 0x18, 0xB4, 0x42, +0x0E, 0xDA, 0x1B, 0x4C, 0x00, 0x26, 0x3E, 0x55, 0x9F, 0xE7, 0xA3, 0xB2, +0x10, 0x93, 0xD8, 0xE7, 0x16, 0x4E, 0xF4, 0x54, 0x00, 0x2C, 0xC7, 0xDA, +0x23, 0x9F, 0xBC, 0x42, 0xAF, 0xDC, 0xA9, 0xE7, 0x13, 0x4E, 0x20, 0x97, +0xBC, 0x5D, 0x22, 0x9E, 0x67, 0xB2, 0xB7, 0x42, 0x8D, 0xD0, 0x20, 0x9F, +0x0F, 0x4E, 0x01, 0x34, 0xBC, 0x55, 0x88, 0xE7, 0xAC, 0x09, 0x00, 0x20, +0x4C, 0x00, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, +0xE4, 0x10, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x1C, 0x03, 0x00, 0x20, +0x78, 0x09, 0x00, 0x20, 0x94, 0x11, 0x00, 0x20, 0x04, 0x40, 0x00, 0x40, +0xF8, 0x03, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x12, 0x79, 0x00, 0x00, +0x64, 0x0E, 0x00, 0x20, 0xB3, 0x0A, 0x00, 0x20, 0x09, 0x9C, 0x01, 0x27, +0x1C, 0x97, 0x00, 0x2C, 0x00, 0xD0, 0xD7, 0xE6, 0x6D, 0x46, 0x6F, 0x46, +0x18, 0x26, 0x14, 0x20, 0x76, 0x5B, 0xC0, 0x5B, 0x41, 0x4D, 0x17, 0x99, +0x10, 0xAC, 0x2F, 0x1C, 0x2E, 0x82, 0x68, 0x82, 0x29, 0x60, 0x25, 0x88, +0x21, 0x9B, 0x3C, 0x1C, 0x3D, 0x81, 0x1A, 0x9E, 0x3C, 0x4F, 0x63, 0x60, +0x1F, 0xAC, 0x25, 0x88, 0xBE, 0x60, 0x16, 0x98, 0x15, 0x99, 0x19, 0x9A, +0x37, 0x4C, 0x0B, 0x9E, 0xF8, 0x60, 0x39, 0x60, 0x7A, 0x60, 0x65, 0x81, +0x00, 0x2E, 0x24, 0xD0, 0x35, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, +0x34, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x1C, 0xDD, 0x33, 0x4C, 0x23, 0x78, +0x00, 0x2B, 0x56, 0xD1, 0x32, 0x4F, 0x3B, 0x7E, 0x00, 0x2B, 0x14, 0xD0, +0x31, 0x4D, 0x09, 0x9F, 0x01, 0x26, 0x23, 0x78, 0x00, 0x2B, 0x08, 0xD0, +0x2D, 0x48, 0x7A, 0x01, 0xC1, 0x7D, 0x52, 0x19, 0x03, 0x20, 0x01, 0x23, +0x00, 0x96, 0xFF, 0xF7, 0xAD, 0xF8, 0x29, 0x49, 0x01, 0x37, 0x0B, 0x7E, +0xFF, 0xB2, 0xBB, 0x42, 0xED, 0xD8, 0x26, 0x4C, 0x23, 0x7D, 0x00, 0x2B, +0x13, 0xD0, 0x22, 0x7E, 0xE4, 0x7D, 0x01, 0x3A, 0x24, 0x49, 0xD2, 0xB2, +0x02, 0x34, 0x00, 0x20, 0x53, 0x1C, 0x9B, 0x01, 0x1B, 0x19, 0x5B, 0x00, +0x01, 0x3A, 0x5D, 0x5A, 0xD2, 0xB2, 0x5D, 0x5A, 0x58, 0x52, 0xF5, 0xE7, +0x01, 0x26, 0x1C, 0x96, 0x74, 0xE6, 0x1D, 0x4D, 0x1D, 0x4E, 0xAB, 0x7E, +0x32, 0x68, 0x13, 0x4F, 0x53, 0x43, 0x08, 0x21, 0x79, 0x5E, 0x1B, 0x48, +0x9B, 0x11, 0x1B, 0x4A, 0xCD, 0x17, 0xDC, 0x0F, 0x00, 0x78, 0x99, 0x42, +0x65, 0x41, 0x15, 0x70, 0x00, 0x28, 0x0A, 0xD1, 0x1C, 0x9C, 0x00, 0x2C, +0x07, 0xD0, 0x01, 0x23, 0x13, 0x70, 0x15, 0x4A, 0x15, 0x49, 0x13, 0x70, +0x15, 0x4A, 0x0B, 0x70, 0x13, 0x70, 0x25, 0xB0, 0xF0, 0xBD, 0x01, 0x25, +0x1C, 0x95, 0x51, 0xE6, 0x01, 0x24, 0x1C, 0x94, 0x4E, 0xE6, 0x03, 0x20, +0x10, 0x49, 0xFF, 0xF7, 0xBD, 0xF8, 0xA3, 0xE7, 0x70, 0x01, 0x00, 0x20, +0xE4, 0x10, 0x00, 0x20, 0xDE, 0x01, 0x00, 0x20, 0x20, 0x01, 0x00, 0x20, +0xEB, 0x01, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x64, 0x0E, 0x00, 0x20, +0x00, 0x40, 0x00, 0x40, 0x48, 0x0D, 0x00, 0x20, 0x78, 0x09, 0x00, 0x20, +0xE4, 0x01, 0x00, 0x20, 0x14, 0x09, 0x00, 0x20, 0x30, 0x11, 0x00, 0x20, +0x48, 0x11, 0x00, 0x20, 0xC4, 0x01, 0x00, 0x20, 0xF0, 0x59, 0x00, 0x00, +0xF0, 0xB5, 0x2F, 0x4B, 0x85, 0xB0, 0x1C, 0x78, 0x2E, 0x4D, 0x2F, 0x4E, +0x10, 0xE0, 0x01, 0x3C, 0xE4, 0xB2, 0x2B, 0x57, 0x32, 0x57, 0x59, 0x1C, +0x02, 0x32, 0x89, 0x01, 0x89, 0x18, 0x2B, 0x4A, 0x49, 0x00, 0x88, 0x5A, +0x2A, 0x4A, 0x5B, 0x00, 0x9A, 0x5A, 0x21, 0x1C, 0xFF, 0xF7, 0x0A, 0xFB, +0x00, 0x2C, 0xEC, 0xD1, 0x27, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x08, 0xD0, +0x20, 0x4B, 0x03, 0x20, 0x19, 0x78, 0x01, 0x23, 0x00, 0x93, 0x24, 0x4A, +0x02, 0x23, 0xFF, 0xF7, 0x1D, 0xF8, 0x23, 0x4B, 0x1E, 0x49, 0x18, 0x78, +0x9A, 0x78, 0x84, 0x1C, 0x03, 0x92, 0xDE, 0x78, 0x00, 0x23, 0x02, 0x94, +0x0D, 0xE0, 0xA4, 0x01, 0xE4, 0x19, 0x64, 0x00, 0x65, 0x5A, 0x00, 0x25, +0x65, 0x52, 0x01, 0x32, 0x02, 0xE0, 0x02, 0x9C, 0x00, 0x22, 0xE7, 0x18, +0xB4, 0x1A, 0xF2, 0xD1, 0x01, 0x33, 0x03, 0x9D, 0x1A, 0x18, 0xAA, 0x42, +0xF5, 0xDB, 0x15, 0x4B, 0x10, 0x49, 0x58, 0x78, 0xDE, 0x78, 0x42, 0x1C, +0x01, 0x23, 0x5B, 0x42, 0x02, 0x92, 0x00, 0x22, 0x9F, 0x1C, 0x08, 0xE0, +0x02, 0x9D, 0xAC, 0x18, 0xA4, 0x01, 0xE4, 0x19, 0x64, 0x00, 0x65, 0x5A, +0x00, 0x25, 0x65, 0x52, 0x01, 0x32, 0x14, 0x18, 0xB4, 0x42, 0xF3, 0xDB, +0x03, 0x9A, 0x01, 0x33, 0x93, 0x42, 0xEC, 0xDB, 0x05, 0xB0, 0xF0, 0xBD, +0x7C, 0x09, 0x00, 0x20, 0x30, 0x75, 0x00, 0x00, 0x2A, 0x75, 0x00, 0x00, +0x00, 0x40, 0x00, 0x40, 0x94, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0x3C, 0x0D, 0x00, 0x20, 0x0A, 0x03, 0x00, 0x20, 0x30, 0xB5, 0x0C, 0x4B, +0x0C, 0x4C, 0xDB, 0x78, 0x0C, 0x49, 0x10, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, +0x5A, 0x1C, 0x0B, 0x4D, 0xD2, 0x01, 0x52, 0x19, 0x45, 0x1C, 0x03, 0xD1, +0x15, 0x88, 0x5A, 0x00, 0x55, 0x52, 0x04, 0xE0, 0x15, 0x88, 0x5A, 0x01, +0x12, 0x18, 0x52, 0x00, 0x15, 0x53, 0x00, 0x2B, 0xEC, 0xD1, 0x30, 0xBD, +0x0A, 0x03, 0x00, 0x20, 0xF8, 0x03, 0x00, 0x20, 0x94, 0x11, 0x00, 0x20, +0x02, 0x40, 0x00, 0x40, 0xF0, 0xB5, 0x8D, 0xB0, 0x0A, 0x91, 0x0B, 0x92, +0x63, 0x4B, 0x41, 0x1C, 0x0C, 0xD1, 0x63, 0x4A, 0x63, 0x49, 0x12, 0x7E, +0x01, 0x3A, 0x03, 0x92, 0xDA, 0x78, 0x5E, 0x78, 0x54, 0x00, 0x00, 0x23, +0x55, 0x1C, 0x64, 0x18, 0x94, 0x46, 0x0E, 0xE0, 0xDC, 0x7B, 0x5A, 0x79, +0xA2, 0x18, 0x01, 0x3A, 0x10, 0xE0, 0x5C, 0x4A, 0xE9, 0x18, 0xC9, 0x01, +0x89, 0x18, 0x0A, 0x88, 0x5F, 0x00, 0xE2, 0x53, 0x0A, 0x88, 0x00, 0x22, +0x0A, 0x80, 0x01, 0x3B, 0x67, 0x46, 0xDA, 0x19, 0xB2, 0x42, 0xF0, 0xDA, +0x03, 0x9A, 0x00, 0x24, 0x56, 0x01, 0x54, 0x4D, 0x36, 0x18, 0x00, 0x23, +0x76, 0x00, 0x11, 0x1C, 0x08, 0x93, 0x07, 0x93, 0x06, 0x93, 0x05, 0x93, +0x03, 0x95, 0x09, 0x96, 0xA4, 0x46, 0x55, 0xE0, 0x44, 0x1C, 0x04, 0xD1, +0x4A, 0x4C, 0x56, 0x00, 0x34, 0x19, 0xE4, 0x5A, 0x04, 0xE0, 0x4B, 0x4C, +0x09, 0x9F, 0x3E, 0x19, 0x5C, 0x01, 0x34, 0x5B, 0x4E, 0x1C, 0x46, 0x4F, +0x04, 0x96, 0xF6, 0x01, 0xF6, 0x19, 0x37, 0x88, 0x24, 0xB2, 0x3E, 0xB2, +0x45, 0x4F, 0xA6, 0x1B, 0x54, 0x00, 0xE7, 0x19, 0xF4, 0x17, 0xFE, 0x52, +0x36, 0x19, 0x66, 0x40, 0x0F, 0x1C, 0x01, 0x24, 0xA7, 0x43, 0xB9, 0x42, +0x09, 0xD1, 0x07, 0x9C, 0xA4, 0x19, 0x07, 0x94, 0xB5, 0x42, 0x00, 0xDD, +0x35, 0x1C, 0x06, 0x9F, 0xB7, 0x42, 0x0B, 0xDB, 0x0D, 0xE0, 0x08, 0x9C, +0x03, 0x9F, 0xA4, 0x19, 0x08, 0x94, 0xB7, 0x42, 0x00, 0xDD, 0x03, 0x96, +0x05, 0x9C, 0xB4, 0x42, 0x02, 0xDB, 0x02, 0xE0, 0x06, 0x96, 0x00, 0xE0, +0x05, 0x96, 0x04, 0x9E, 0xF4, 0x01, 0x2F, 0x4E, 0xA4, 0x19, 0x47, 0x1C, +0x0E, 0xD1, 0x27, 0x88, 0x2B, 0x4E, 0x04, 0x97, 0x57, 0x00, 0xBE, 0x19, +0x02, 0x96, 0x10, 0x27, 0x6E, 0x46, 0xBF, 0x5B, 0x02, 0x9E, 0xF7, 0x52, +0x26, 0x88, 0x00, 0x26, 0x26, 0x80, 0x05, 0xE0, 0x27, 0x88, 0x27, 0x4E, +0x09, 0x9C, 0xA6, 0x19, 0x5C, 0x01, 0x37, 0x53, 0x01, 0x39, 0x02, 0x3B, +0x61, 0x45, 0xA7, 0xDA, 0x01, 0x30, 0x13, 0xD1, 0x23, 0x4C, 0x23, 0x78, +0x00, 0x2B, 0x03, 0xD0, 0x01, 0x20, 0x22, 0x49, 0xFE, 0xF7, 0x70, 0xFF, +0x23, 0x78, 0x00, 0x2B, 0x08, 0xD0, 0x17, 0x4B, 0x01, 0x20, 0xD9, 0x78, +0x00, 0x23, 0x00, 0x93, 0x16, 0x4A, 0x02, 0x23, 0xFE, 0xF7, 0x0C, 0xFF, +0x07, 0x9E, 0x08, 0x9F, 0x0A, 0x9C, 0xF3, 0x19, 0x23, 0x60, 0x05, 0x9E, +0x03, 0x9F, 0x06, 0x9C, 0xF3, 0x1B, 0x65, 0x1B, 0x9D, 0x42, 0x00, 0xDA, +0x1D, 0x1C, 0x0B, 0x9E, 0x12, 0x4C, 0x35, 0x60, 0x23, 0x78, 0x00, 0x2B, +0x03, 0xD0, 0x0B, 0x20, 0x11, 0x49, 0xFE, 0xF7, 0x4D, 0xFF, 0x23, 0x78, +0x00, 0x2B, 0x08, 0xD0, 0x06, 0x4B, 0x0B, 0x20, 0x19, 0x7E, 0x01, 0x23, +0x00, 0x93, 0x09, 0x4A, 0x02, 0x23, 0xFE, 0xF7, 0xE9, 0xFE, 0x0D, 0xB0, +0xF0, 0xBD, 0xC0, 0x46, 0x0A, 0x03, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0x94, 0x11, 0x00, 0x20, 0x02, 0x40, 0x00, 0x40, 0xFF, 0xFF, 0x00, 0x00, +0xF8, 0x03, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0xC6, 0x59, 0x00, 0x00, 0xCD, 0x59, 0x00, 0x00, 0xF0, 0xB5, 0xA6, 0x4B, +0x85, 0xB0, 0x1D, 0x78, 0x00, 0x2D, 0x29, 0xD0, 0xA4, 0x4B, 0xA5, 0x4C, +0x18, 0x78, 0xA5, 0x4B, 0x46, 0xB2, 0x19, 0x68, 0x5B, 0x68, 0xB2, 0x00, +0xCB, 0x18, 0x13, 0x51, 0x82, 0x1D, 0xD2, 0xB2, 0x00, 0x25, 0x06, 0x23, +0x01, 0x3B, 0xDB, 0xB2, 0xF1, 0x1A, 0x00, 0xD5, 0x0C, 0x31, 0x89, 0x00, +0x09, 0x59, 0x6D, 0x18, 0x11, 0x1C, 0x0B, 0x2A, 0x01, 0xD9, 0x0C, 0x39, +0xC9, 0xB2, 0x89, 0x00, 0x61, 0x58, 0x01, 0x3A, 0x6D, 0x1A, 0xD2, 0xB2, +0x00, 0x2B, 0xEB, 0xD1, 0x01, 0x30, 0x93, 0x4A, 0xC0, 0xB2, 0x10, 0x70, +0x40, 0xB2, 0x0B, 0x28, 0x00, 0xDD, 0x13, 0x70, 0x92, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x00, 0xD0, 0x15, 0xE1, 0x91, 0x4B, 0x14, 0x21, 0x5B, 0x5E, +0x9D, 0x42, 0x02, 0xDA, 0x8F, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x8B, 0x4B, +0x10, 0x22, 0x9E, 0x5E, 0x12, 0x24, 0x1B, 0x5F, 0xF6, 0x1A, 0x85, 0x4B, +0x18, 0x78, 0x00, 0x28, 0x16, 0xD1, 0x8A, 0x4B, 0x8A, 0x4F, 0x1B, 0x68, +0x8A, 0x4C, 0xBB, 0x80, 0x23, 0x78, 0x3E, 0x80, 0x00, 0x2B, 0x02, 0xD0, +0x88, 0x49, 0xFE, 0xF7, 0xD7, 0xFE, 0x23, 0x78, 0x00, 0x2B, 0x07, 0xD0, +0x01, 0x23, 0x02, 0x21, 0x00, 0x93, 0x00, 0x20, 0x3A, 0x1C, 0x0B, 0x1C, +0xFE, 0xF7, 0x74, 0xFE, 0x7C, 0x4B, 0x9A, 0x7D, 0x96, 0x42, 0x07, 0xDC, +0x80, 0x4B, 0x1A, 0x78, 0x51, 0xB2, 0x02, 0x29, 0x08, 0xDC, 0x01, 0x32, +0x1A, 0x70, 0x05, 0xE0, 0xDB, 0x7D, 0x9E, 0x42, 0x02, 0xDB, 0x7B, 0x4B, +0x00, 0x22, 0x1A, 0x70, 0x71, 0x4B, 0x76, 0x4A, 0x59, 0x68, 0x1B, 0x68, +0x15, 0x80, 0xCB, 0x18, 0x53, 0x80, 0x74, 0x4B, 0x96, 0x80, 0x1B, 0x78, +0x00, 0x2B, 0x06, 0xD0, 0x01, 0x23, 0x00, 0x93, 0x19, 0x20, 0x03, 0x21, +0x02, 0x23, 0xFE, 0xF7, 0x4F, 0xFE, 0x6B, 0x4B, 0x64, 0x4C, 0x1B, 0x78, +0x00, 0x2B, 0x61, 0xD0, 0x6B, 0x4D, 0x2B, 0x78, 0x00, 0x2B, 0x03, 0xD0, +0x19, 0x20, 0x6C, 0x49, 0xFE, 0xF7, 0x9A, 0xFE, 0x69, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x05, 0xD1, 0x22, 0x78, 0x00, 0x2A, 0x52, 0xD0, 0x61, 0x4A, +0x13, 0x70, 0x4F, 0xE0, 0x03, 0x2B, 0x4D, 0xD1, 0x2B, 0x78, 0x00, 0x2B, +0x03, 0xD0, 0x00, 0x20, 0x63, 0x49, 0xFE, 0xF7, 0x87, 0xFE, 0x55, 0x4B, +0x62, 0x4A, 0x19, 0x78, 0x00, 0x29, 0x1A, 0xD1, 0x01, 0x20, 0x18, 0x70, +0x13, 0x7E, 0xD6, 0x7D, 0x5F, 0x4D, 0x60, 0x4A, 0x0B, 0xE0, 0x01, 0x3B, +0xDB, 0xB2, 0xF8, 0x18, 0x44, 0x00, 0xA1, 0x5A, 0xC9, 0x00, 0xA1, 0x52, +0x00, 0x21, 0x41, 0x55, 0x00, 0x2B, 0xF4, 0xD1, 0x63, 0x46, 0x59, 0x1E, +0xC9, 0xB2, 0x00, 0x2B, 0x23, 0xD0, 0x33, 0x1C, 0x4F, 0x01, 0x8C, 0x46, +0xF4, 0xE7, 0x13, 0x7E, 0xD6, 0x7D, 0x54, 0x4A, 0x0E, 0xE0, 0x01, 0x3B, +0x51, 0x4D, 0xDB, 0xB2, 0xFC, 0x18, 0x60, 0x00, 0x64, 0x57, 0xE4, 0x00, +0x02, 0x94, 0x84, 0x5A, 0x02, 0x9D, 0x64, 0x1B, 0x84, 0x52, 0x00, 0x2B, +0xF1, 0xD1, 0x0B, 0x1C, 0x59, 0x1E, 0xC9, 0xB2, 0x00, 0x2B, 0x02, 0xD0, +0x33, 0x1C, 0x4F, 0x01, 0xF5, 0xE7, 0x3A, 0x4A, 0x11, 0x1C, 0x30, 0x31, +0x08, 0xC2, 0x8A, 0x42, 0xFC, 0xD1, 0x3B, 0x4B, 0x00, 0x22, 0x1A, 0x70, +0x44, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x60, 0xE0, 0x22, 0x78, 0x43, 0x4B, +0x00, 0x2A, 0x06, 0xD1, 0x40, 0x4A, 0x01, 0x21, 0x11, 0x70, 0x1A, 0x68, +0x52, 0x18, 0x1A, 0x60, 0x55, 0xE0, 0x00, 0x22, 0x1A, 0x60, 0x39, 0x4B, +0x3D, 0x48, 0x1C, 0x7E, 0xDB, 0x7D, 0x39, 0x49, 0x02, 0x93, 0x2D, 0x4B, +0x9B, 0x7C, 0x03, 0x93, 0x11, 0xE0, 0x01, 0x3B, 0xDB, 0xB2, 0xF2, 0x18, +0x14, 0x56, 0x03, 0x9D, 0xAC, 0x42, 0x07, 0xD1, 0x31, 0x4D, 0x54, 0x00, +0x57, 0x57, 0x65, 0x5A, 0xEF, 0x1B, 0x67, 0x52, 0x00, 0x24, 0x14, 0x54, +0x00, 0x2B, 0xEE, 0xD1, 0x64, 0x46, 0x65, 0x1E, 0xED, 0xB2, 0x00, 0x2C, +0x03, 0xD0, 0x02, 0x9B, 0x6E, 0x01, 0xAC, 0x46, 0xF4, 0xE7, 0x2D, 0x4B, +0x1B, 0x68, 0x5D, 0x07, 0x2B, 0xD5, 0x20, 0x4B, 0x1B, 0x78, 0x00, 0x2B, +0x22, 0xD0, 0x02, 0x20, 0x29, 0x49, 0xFE, 0xF7, 0x03, 0xFE, 0x1D, 0xE0, +0xE9, 0x7D, 0x62, 0x01, 0x0B, 0x1C, 0x21, 0x48, 0x02, 0x92, 0x08, 0xE0, +0x01, 0x3B, 0x02, 0x9A, 0xDB, 0xB2, 0xD2, 0x18, 0x52, 0x00, 0x12, 0x5A, +0x5F, 0x00, 0xD2, 0x08, 0xBA, 0x53, 0x00, 0x2B, 0xF4, 0xD1, 0x13, 0x4A, +0x12, 0x78, 0x00, 0x2A, 0x05, 0xD0, 0x02, 0x20, 0x00, 0x93, 0x0F, 0x4A, +0x03, 0x1C, 0xFE, 0xF7, 0x8F, 0xFD, 0x01, 0x34, 0xE4, 0xB2, 0x01, 0xE0, +0x11, 0x4D, 0x0B, 0x4E, 0x2B, 0x7E, 0xA3, 0x42, 0xDC, 0xD8, 0x05, 0xB0, +0xF0, 0xBD, 0xC0, 0x46, 0x1C, 0x03, 0x00, 0x20, 0xF4, 0x10, 0x00, 0x20, +0xBC, 0x11, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, 0x14, 0x09, 0x00, 0x20, +0x48, 0x0D, 0x00, 0x20, 0x3C, 0x11, 0x00, 0x20, 0x34, 0x11, 0x00, 0x20, +0x54, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, 0xD2, 0x59, 0x00, 0x00, +0x20, 0x09, 0x00, 0x20, 0xD9, 0x59, 0x00, 0x00, 0xE2, 0x59, 0x00, 0x00, +0xAE, 0x09, 0x00, 0x20, 0x64, 0x0E, 0x00, 0x20, 0xF8, 0x03, 0x00, 0x20, +0x48, 0x11, 0x00, 0x20, 0xBC, 0x01, 0x00, 0x20, 0xB3, 0x0A, 0x00, 0x20, +0x58, 0x00, 0x00, 0x20, 0xEB, 0x59, 0x00, 0x00, 0xF0, 0xB5, 0x25, 0x4B, +0x87, 0xB0, 0x1B, 0x78, 0x00, 0x2B, 0x2B, 0xD1, 0x23, 0x4A, 0x24, 0x4B, +0x90, 0x7C, 0x1B, 0x78, 0x04, 0x90, 0xD2, 0x7E, 0x22, 0x4D, 0x52, 0xB2, +0x92, 0xB2, 0x05, 0x92, 0x21, 0x4A, 0x1D, 0xE0, 0x01, 0x3B, 0x21, 0x4C, +0xDB, 0xB2, 0xE1, 0x5C, 0x04, 0x9F, 0xB9, 0x42, 0x16, 0xD1, 0x59, 0x00, +0x88, 0x5A, 0x00, 0x28, 0x07, 0xD0, 0x6E, 0x5A, 0x6F, 0x46, 0x34, 0xB2, +0xA4, 0x46, 0x14, 0x24, 0xE7, 0x5F, 0xBC, 0x45, 0x05, 0xDA, 0x59, 0x00, +0x6E, 0x5A, 0xF6, 0x00, 0x80, 0x1B, 0x50, 0x52, 0x01, 0xE0, 0x80, 0x1B, +0x88, 0x52, 0x14, 0x4F, 0x00, 0x21, 0xF9, 0x54, 0x00, 0x2B, 0xDF, 0xD1, +0x0E, 0x4B, 0x12, 0x4C, 0x19, 0x78, 0x0F, 0x48, 0x0B, 0x1C, 0x05, 0xE0, +0x01, 0x3B, 0xDB, 0xB2, 0x5A, 0x00, 0x15, 0x5A, 0xED, 0x08, 0x15, 0x53, +0x00, 0x2B, 0xF7, 0xD1, 0x0C, 0x4A, 0x12, 0x78, 0x00, 0x2A, 0x05, 0xD0, +0x02, 0x20, 0x00, 0x93, 0x08, 0x4A, 0x03, 0x1C, 0xFE, 0xF7, 0x0E, 0xFD, +0x07, 0xB0, 0xF0, 0xBD, 0x30, 0x11, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x7C, 0x09, 0x00, 0x20, 0x3C, 0x0D, 0x00, 0x20, 0x14, 0x02, 0x00, 0x20, +0xA4, 0x0A, 0x00, 0x20, 0x54, 0x11, 0x00, 0x20, 0xEB, 0x01, 0x00, 0x20, +0x10, 0xB5, 0x09, 0x49, 0x50, 0x22, 0x09, 0x48, 0x00, 0xF0, 0xE2, 0xF9, +0x08, 0x4C, 0x09, 0x49, 0x20, 0x1C, 0x42, 0x22, 0x00, 0xF0, 0xDC, 0xF9, +0x07, 0x4B, 0xA2, 0x7B, 0x1A, 0x60, 0xE3, 0x7D, 0xE3, 0x76, 0x23, 0x7E, +0x23, 0x77, 0x10, 0xBD, 0x4A, 0x74, 0x00, 0x00, 0x48, 0x0D, 0x00, 0x20, +0xAE, 0x09, 0x00, 0x20, 0x08, 0x74, 0x00, 0x00, 0x50, 0x11, 0x00, 0x20, +0x08, 0xB5, 0x04, 0x49, 0x04, 0x4B, 0x41, 0x43, 0x04, 0x48, 0xC9, 0x18, +0x00, 0xF0, 0x60, 0xF9, 0xC0, 0xB2, 0x08, 0xBD, 0x44, 0xFE, 0xFF, 0xFF, +0xFE, 0x24, 0x02, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x10, 0xB5, 0x15, 0x4C, +0x00, 0x23, 0x23, 0x71, 0x03, 0x23, 0x63, 0x71, 0x02, 0x23, 0x23, 0x72, +0x12, 0x4B, 0x98, 0x78, 0x02, 0x38, 0x03, 0x28, 0x1D, 0xD8, 0x00, 0xF0, +0xE7, 0xF8, 0x0B, 0x04, 0x02, 0x14, 0xC7, 0x20, 0x00, 0xE0, 0xD7, 0x20, +0xE0, 0x70, 0xFF, 0xF7, 0xD9, 0xFF, 0x02, 0x23, 0x20, 0x70, 0x0E, 0xE0, +0xF4, 0x20, 0xE0, 0x70, 0xFF, 0xF7, 0xD2, 0xFF, 0x02, 0x23, 0x20, 0x70, +0xA3, 0x71, 0x01, 0x23, 0x06, 0xE0, 0xF4, 0x20, 0xE0, 0x70, 0xFF, 0xF7, +0xC9, 0xFF, 0x01, 0x23, 0x20, 0x70, 0xA3, 0x71, 0xE3, 0x71, 0x10, 0xBD, +0xAA, 0x0A, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0xF0, 0xB5, 0x59, 0x4B, +0x87, 0xB0, 0x1A, 0x68, 0x58, 0x4B, 0x08, 0x2A, 0x01, 0xD1, 0x01, 0x22, +0x00, 0xE0, 0x00, 0x22, 0x1A, 0x70, 0x56, 0x4B, 0x56, 0x4C, 0x01, 0x33, +0xDB, 0x7F, 0x00, 0x2B, 0x00, 0xD1, 0xE3, 0x71, 0x23, 0x78, 0x01, 0x25, +0xA2, 0x79, 0x28, 0x1C, 0xD9, 0x00, 0x90, 0x40, 0x82, 0xB2, 0xCB, 0x1A, +0x53, 0x43, 0x50, 0x4E, 0xDB, 0x10, 0xDB, 0xB2, 0x33, 0x80, 0x22, 0x78, +0xFA, 0x23, 0xA0, 0x79, 0x9B, 0x00, 0x53, 0x43, 0x4C, 0x4F, 0x29, 0x1C, +0x81, 0x40, 0x88, 0xB2, 0xB9, 0x88, 0x58, 0x43, 0x09, 0x01, 0x00, 0xF0, +0xFB, 0xF8, 0xC1, 0xB2, 0x71, 0x80, 0x23, 0x78, 0x2D, 0x22, 0xA0, 0x79, +0x53, 0x43, 0x2A, 0x1C, 0x82, 0x40, 0x90, 0xB2, 0x58, 0x43, 0x6B, 0x46, +0x19, 0x81, 0x09, 0x01, 0x00, 0xF0, 0xEC, 0xF8, 0xC0, 0xB2, 0xB0, 0x80, +0x23, 0x7A, 0xB9, 0x79, 0xD8, 0x00, 0x18, 0x1A, 0xA9, 0x40, 0xC0, 0x00, +0x49, 0x19, 0xE0, 0x30, 0x48, 0x43, 0xA2, 0x79, 0x6C, 0x46, 0x08, 0x21, +0x61, 0x5E, 0x90, 0x40, 0x49, 0x01, 0x00, 0xF0, 0x8B, 0xF8, 0x34, 0x4A, +0xF0, 0x80, 0x11, 0x7D, 0xD0, 0x7D, 0x36, 0x4B, 0x08, 0x18, 0xC0, 0xB2, +0x18, 0x70, 0x17, 0x7E, 0x5F, 0x70, 0x56, 0x7E, 0x01, 0x96, 0x96, 0x7F, +0x01, 0x9C, 0x66, 0x43, 0xF4, 0xB2, 0x20, 0x18, 0xC0, 0xB2, 0x98, 0x70, +0x02, 0x90, 0x96, 0x7E, 0x03, 0x96, 0x03, 0x98, 0xD6, 0x7F, 0x46, 0x43, +0xF0, 0xB2, 0xC7, 0x19, 0xFF, 0xB2, 0xDF, 0x70, 0xD6, 0x7E, 0xB4, 0x46, +0x61, 0x44, 0x61, 0x18, 0xC9, 0xB2, 0x19, 0x71, 0x16, 0x7F, 0x80, 0x19, +0x02, 0x9E, 0xC0, 0xB2, 0x74, 0x1A, 0x3F, 0x1A, 0xE6, 0xB2, 0xFF, 0xB2, +0x58, 0x71, 0x9E, 0x71, 0xDF, 0x71, 0xBC, 0x46, 0x57, 0x7D, 0xEC, 0x1B, +0x04, 0x97, 0x27, 0x1C, 0x77, 0x43, 0xFF, 0xB2, 0x05, 0x97, 0x9F, 0x73, +0x97, 0x7D, 0x64, 0x46, 0xED, 0x1B, 0x65, 0x43, 0x47, 0x43, 0x04, 0x9C, +0x5F, 0x74, 0x4C, 0x43, 0x18, 0x72, 0x6F, 0x46, 0x14, 0x20, 0xC7, 0x5D, +0xED, 0xB2, 0xE4, 0xB2, 0xDD, 0x73, 0x1C, 0x74, 0x5D, 0x72, 0x99, 0x72, +0xDF, 0x72, 0x1E, 0x73, 0x5C, 0x73, 0x51, 0x7F, 0x12, 0x4B, 0x00, 0x29, +0x03, 0xD0, 0x69, 0x46, 0x09, 0x79, 0x19, 0x70, 0x03, 0xE0, 0x01, 0x9C, +0x03, 0x9E, 0x74, 0x43, 0x1C, 0x70, 0x93, 0x1C, 0x03, 0x32, 0x02, 0x9F, +0xD2, 0x7F, 0xDB, 0x7F, 0xBA, 0x18, 0x5B, 0xB2, 0x01, 0x32, 0x9A, 0x40, +0x09, 0x4B, 0x07, 0xB0, 0x1A, 0x60, 0xF0, 0xBD, 0x50, 0x11, 0x00, 0x20, +0xFA, 0x02, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0xAA, 0x0A, 0x00, 0x20, +0x04, 0x02, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x0A, 0x03, 0x00, 0x20, +0x7C, 0x09, 0x00, 0x20, 0x18, 0x09, 0x00, 0x20, 0x02, 0xB4, 0x71, 0x46, +0x49, 0x08, 0x49, 0x00, 0x09, 0x5C, 0x49, 0x00, 0x8E, 0x44, 0x02, 0xBC, +0x70, 0x47, 0xC0, 0x46, 0x03, 0xB4, 0x71, 0x46, 0x49, 0x08, 0x40, 0x00, +0x49, 0x00, 0x09, 0x5A, 0x49, 0x00, 0x8E, 0x44, 0x03, 0xBC, 0x70, 0x47, +0x00, 0x29, 0x34, 0xD0, 0x01, 0x23, 0x00, 0x22, 0x10, 0xB4, 0x88, 0x42, +0x2C, 0xD3, 0x01, 0x24, 0x24, 0x07, 0xA1, 0x42, 0x04, 0xD2, 0x81, 0x42, +0x02, 0xD2, 0x09, 0x01, 0x1B, 0x01, 0xF8, 0xE7, 0xE4, 0x00, 0xA1, 0x42, +0x04, 0xD2, 0x81, 0x42, 0x02, 0xD2, 0x49, 0x00, 0x5B, 0x00, 0xF8, 0xE7, +0x88, 0x42, 0x01, 0xD3, 0x40, 0x1A, 0x1A, 0x43, 0x4C, 0x08, 0xA0, 0x42, +0x02, 0xD3, 0x00, 0x1B, 0x5C, 0x08, 0x22, 0x43, 0x8C, 0x08, 0xA0, 0x42, +0x02, 0xD3, 0x00, 0x1B, 0x9C, 0x08, 0x22, 0x43, 0xCC, 0x08, 0xA0, 0x42, +0x02, 0xD3, 0x00, 0x1B, 0xDC, 0x08, 0x22, 0x43, 0x00, 0x28, 0x03, 0xD0, +0x1B, 0x09, 0x01, 0xD0, 0x09, 0x09, 0xE3, 0xE7, 0x10, 0x1C, 0x10, 0xBC, +0x70, 0x47, 0x00, 0x28, 0x01, 0xD0, 0x00, 0x20, 0xC0, 0x43, 0x07, 0xB4, +0x02, 0x48, 0x02, 0xA1, 0x40, 0x18, 0x02, 0x90, 0x03, 0xBD, 0xC0, 0x46, +0xD9, 0x00, 0x00, 0x00, 0x00, 0x29, 0xF0, 0xD0, 0x03, 0xB5, 0xFF, 0xF7, +0xB9, 0xFF, 0x0E, 0xBC, 0x42, 0x43, 0x89, 0x1A, 0x18, 0x47, 0xC0, 0x46, +0x00, 0x29, 0x41, 0xD0, 0x10, 0xB4, 0x04, 0x1C, 0x4C, 0x40, 0xA4, 0x46, +0x01, 0x23, 0x00, 0x22, 0x00, 0x29, 0x00, 0xD5, 0x49, 0x42, 0x00, 0x28, +0x00, 0xD5, 0x40, 0x42, 0x88, 0x42, 0x2C, 0xD3, 0x01, 0x24, 0x24, 0x07, +0xA1, 0x42, 0x04, 0xD2, 0x81, 0x42, 0x02, 0xD2, 0x09, 0x01, 0x1B, 0x01, +0xF8, 0xE7, 0xE4, 0x00, 0xA1, 0x42, 0x04, 0xD2, 0x81, 0x42, 0x02, 0xD2, +0x49, 0x00, 0x5B, 0x00, 0xF8, 0xE7, 0x88, 0x42, 0x01, 0xD3, 0x40, 0x1A, +0x1A, 0x43, 0x4C, 0x08, 0xA0, 0x42, 0x02, 0xD3, 0x00, 0x1B, 0x5C, 0x08, +0x22, 0x43, 0x8C, 0x08, 0xA0, 0x42, 0x02, 0xD3, 0x00, 0x1B, 0x9C, 0x08, +0x22, 0x43, 0xCC, 0x08, 0xA0, 0x42, 0x02, 0xD3, 0x00, 0x1B, 0xDC, 0x08, +0x22, 0x43, 0x00, 0x28, 0x03, 0xD0, 0x1B, 0x09, 0x01, 0xD0, 0x09, 0x09, +0xE3, 0xE7, 0x10, 0x1C, 0x64, 0x46, 0x00, 0x2C, 0x00, 0xD5, 0x40, 0x42, +0x10, 0xBC, 0x70, 0x47, 0x00, 0x28, 0x06, 0xD0, 0x03, 0xDB, 0x00, 0x20, +0xC0, 0x43, 0x40, 0x08, 0x01, 0xE0, 0x80, 0x20, 0x00, 0x06, 0x07, 0xB4, +0x02, 0x48, 0x02, 0xA1, 0x40, 0x18, 0x02, 0x90, 0x03, 0xBD, 0xC0, 0x46, +0x19, 0x00, 0x00, 0x00, 0x00, 0x29, 0xEB, 0xD0, 0x03, 0xB5, 0xFF, 0xF7, +0xA7, 0xFF, 0x0E, 0xBC, 0x42, 0x43, 0x89, 0x1A, 0x18, 0x47, 0xC0, 0x46, +0x70, 0x47, 0xC0, 0x46, 0xF0, 0xB5, 0x05, 0x1C, 0x0F, 0x2A, 0x2F, 0xD9, +0x0B, 0x1C, 0x03, 0x43, 0x05, 0x1C, 0x9C, 0x07, 0x2C, 0xD1, 0x0C, 0x1C, +0x03, 0x1C, 0x15, 0x1C, 0x26, 0x68, 0x10, 0x3D, 0x1E, 0x60, 0x66, 0x68, +0x5E, 0x60, 0xA6, 0x68, 0x9E, 0x60, 0xE6, 0x68, 0x10, 0x34, 0xDE, 0x60, +0x10, 0x33, 0x0F, 0x2D, 0xF2, 0xD8, 0x13, 0x1C, 0x10, 0x3B, 0x1B, 0x09, +0x01, 0x33, 0x1B, 0x01, 0xC5, 0x18, 0xC9, 0x18, 0x0F, 0x23, 0x1A, 0x40, +0x03, 0x2A, 0x0F, 0xD9, 0x0E, 0x1C, 0x2C, 0x1C, 0x13, 0x1C, 0x80, 0xCE, +0x04, 0x3B, 0x80, 0xC4, 0x03, 0x2B, 0xFA, 0xD8, 0x13, 0x1F, 0x9B, 0x08, +0x01, 0x33, 0x9B, 0x00, 0x03, 0x24, 0x22, 0x40, 0xC9, 0x18, 0xED, 0x18, +0x00, 0x2A, 0x05, 0xD0, 0x00, 0x23, 0xCC, 0x5C, 0xEC, 0x54, 0x01, 0x33, +0x93, 0x42, 0xFA, 0xD1, 0xF0, 0xBD, 0xC0, 0x46, 0x50, 0x61, 0x6C, 0x6D, +0x20, 0x49, 0x6E, 0x69, 0x74, 0x00, 0x27, 0x45, 0x6E, 0x74, 0x65, 0x72, +0x27, 0x20, 0x4E, 0x00, 0x4E, 0x2D, 0x6C, 0x65, 0x73, 0x73, 0x21, 0x00, +0x27, 0x45, 0x78, 0x69, 0x74, 0x27, 0x20, 0x4E, 0x00, 0x4E, 0x20, 0x53, +0x2F, 0x50, 0x00, 0x53, 0x6C, 0x65, 0x65, 0x70, 0x00, 0x53, 0x2D, 0x72, +0x65, 0x73, 0x65, 0x74, 0x00, 0x46, 0x41, 0x53, 0x54, 0x00, 0x49, 0x64, +0x6C, 0x65, 0x00, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x53, 0x70, +0x65, 0x63, 0x74, 0x00, 0x53, 0x74, 0x61, 0x63, 0x6B, 0x21, 0x00, 0x52, +0x45, 0x47, 0x56, 0x41, 0x4C, 0x00, 0x44, 0x65, 0x6C, 0x61, 0x79, 0x00, +0x4F, 0x53, 0x43, 0x00, 0x4E, 0x4F, 0x49, 0x53, 0x45, 0x00, 0x54, 0x6F, +0x75, 0x63, 0x68, 0x20, 0x4F, 0x6E, 0x00, 0x54, 0x6F, 0x75, 0x63, 0x68, +0x20, 0x4F, 0x46, 0x46, 0x00, 0x4C, 0x54, 0x5F, 0x50, 0x52, 0x4F, 0x46, +0x49, 0x4C, 0x49, 0x4E, 0x47, 0x00, 0x46, 0x69, 0x78, 0x65, 0x64, 0x00, +0x47, 0x2D, 0x41, 0x66, 0x74, 0x65, 0x72, 0x00, 0x3D, 0x48, 0x6F, 0x76, +0x6F, 0x72, 0x00, 0x12, 0x0E, 0x07, 0x0D, 0x0A, 0x12, 0x04, 0x06, 0x0C, +0x09, 0x12, 0x0F, 0x05, 0x11, 0x08, 0x12, 0x00, 0x01, 0x10, 0x02, 0x45, +0x72, 0x72, 0x00, 0x4B, 0x65, 0x79, 0x20, 0x52, 0x00, 0x52, 0x45, 0x46, +0x20, 0x49, 0x4E, 0x49, 0x54, 0x00, 0x43, 0x6D, 0x44, 0x65, 0x6C, 0x74, +0x61, 0x20, 0x52, 0x65, 0x66, 0x2F, 0x52, 0x65, 0x61, 0x6C, 0x00, 0x52, +0x61, 0x77, 0x00, 0x4D, 0x41, 0x58, 0x20, 0x49, 0x00, 0x43, 0x4D, 0x5F, +0x44, 0x45, 0x4C, 0x54, 0x41, 0x5F, 0x4D, 0x41, 0x58, 0x5F, 0x4D, 0x49, +0x4E, 0x00, 0x54, 0x78, 0x6C, 0x65, 0x73, 0x73, 0x00, 0x44, 0x69, 0x66, +0x66, 0x00, 0x44, 0x49, 0x46, 0x46, 0x2F, 0x4E, 0x00, 0x42, 0x69, 0x67, +0x20, 0x47, 0x72, 0x61, 0x64, 0x00, 0x4E, 0x65, 0x67, 0x2D, 0x45, 0x64, +0x67, 0x65, 0x00, 0x52, 0x65, 0x66, 0x00, 0x00, 0x2D, 0x49, 0x00, 0x00, +0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0x01, 0x00, 0xFF, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x00, 0xA0, 0x0D, 0x00, 0x20, 0x28, 0x02, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x00, 0x54, 0x11, 0x00, 0x20, 0x01, 0x02, 0xFF, 0x00, +0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x45, 0x4D, 0x31, 0x48, 0x30, +0x50, 0x52, 0x34, 0x35, 0x08, 0xB5, 0x00, 0x28, 0x02, 0xD0, 0x01, 0x28, +0x24, 0xD1, 0x07, 0xE0, 0x12, 0x4B, 0x13, 0x4A, 0x1A, 0x60, 0x13, 0x4B, +0x58, 0x60, 0x98, 0x60, 0xD8, 0x60, 0x1B, 0xE0, 0x11, 0x4B, 0x1B, 0x68, +0x10, 0x2B, 0x15, 0xD1, 0x10, 0x4A, 0x11, 0x4B, 0x1A, 0x60, 0x11, 0x4A, +0x11, 0x4B, 0x1A, 0x60, 0x11, 0x4A, 0x12, 0x4B, 0x1A, 0x60, 0x12, 0x4A, +0x12, 0x4B, 0x1A, 0x60, 0x12, 0x4A, 0x13, 0x4B, 0x1A, 0x60, 0x13, 0x4A, +0x13, 0x4B, 0x1A, 0x60, 0x13, 0x4A, 0x14, 0x4B, 0x1A, 0x60, 0x01, 0xE0, +0xFE, 0xF7, 0xC8, 0xF8, 0x08, 0xBD, 0xC0, 0x46, 0xF8, 0x01, 0x00, 0x20, +0xC1, 0x68, 0x00, 0x00, 0xF8, 0x08, 0x00, 0x20, 0x50, 0x11, 0x00, 0x20, +0xA9, 0x5C, 0x00, 0x00, 0x68, 0x00, 0x00, 0x20, 0x81, 0x68, 0x00, 0x00, +0x6C, 0x00, 0x00, 0x20, 0x2D, 0x66, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, +0x49, 0x71, 0x00, 0x00, 0x18, 0x00, 0x00, 0x20, 0x05, 0x62, 0x00, 0x00, +0x1C, 0x00, 0x00, 0x20, 0xE9, 0x61, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, +0xAB, 0x5C, 0x00, 0x00, 0x24, 0x00, 0x00, 0x20, 0x70, 0x47, 0xA0, 0x23, +0xDB, 0x05, 0x01, 0x22, 0x1A, 0x72, 0x09, 0x49, 0x10, 0x22, 0x1A, 0x72, +0x00, 0x22, 0x0A, 0x70, 0x1A, 0x72, 0x07, 0x4B, 0x80, 0x22, 0x19, 0x68, +0x52, 0x00, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x80, 0x23, 0xDB, 0x05, +0x99, 0x68, 0x9A, 0x60, 0x70, 0x47, 0xC0, 0x46, 0x0C, 0x00, 0x00, 0x20, +0x14, 0x00, 0x00, 0x20, 0x00, 0xB5, 0x5A, 0x28, 0x07, 0xD0, 0x05, 0x4B, +0x59, 0x28, 0x01, 0xDD, 0xB4, 0x22, 0x10, 0x1A, 0x40, 0x00, 0x18, 0x5A, +0x00, 0xE0, 0x02, 0x48, 0x00, 0xBD, 0xC0, 0x46, 0x90, 0x72, 0x00, 0x00, +0xFF, 0xFF, 0x00, 0x00, 0x00, 0xB5, 0x00, 0x28, 0x0E, 0xD0, 0xB4, 0x28, +0x0E, 0xD0, 0x08, 0x4B, 0x5A, 0x28, 0x04, 0xDC, 0x5A, 0x22, 0x10, 0x1A, +0x40, 0x00, 0x18, 0x5A, 0x07, 0xE0, 0x5A, 0x38, 0x40, 0x00, 0x18, 0x5A, +0x40, 0x42, 0x02, 0xE0, 0x02, 0x48, 0x00, 0xE0, 0x02, 0x48, 0x00, 0xBD, +0x90, 0x72, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, +0xF0, 0xB5, 0x9B, 0xB0, 0x0E, 0x93, 0x11, 0x90, 0x0B, 0x91, 0x08, 0x78, +0xC9, 0x4B, 0x03, 0x90, 0x49, 0x78, 0x16, 0x1C, 0x49, 0xB2, 0x12, 0x91, +0x0A, 0x20, 0x1A, 0x5E, 0x00, 0x25, 0x13, 0x92, 0xC5, 0x4A, 0x2C, 0x1C, +0x28, 0x20, 0x11, 0x5E, 0x2F, 0x1C, 0x14, 0x91, 0x59, 0x68, 0x15, 0x91, +0xC2, 0x49, 0x09, 0x68, 0x0D, 0x91, 0x08, 0x21, 0x58, 0x5E, 0x1B, 0x68, +0x17, 0x90, 0x26, 0x21, 0x50, 0x5E, 0x19, 0x93, 0x18, 0x90, 0x04, 0x95, +0x06, 0x95, 0x05, 0x95, 0x09, 0x95, 0x0A, 0x95, 0x08, 0x95, 0x95, 0xE0, +0x03, 0x9A, 0x14, 0x98, 0x15, 0x99, 0x50, 0x43, 0xFF, 0xF7, 0xFA, 0xFC, +0x13, 0x9B, 0x00, 0xB2, 0x18, 0x18, 0x33, 0x68, 0x0B, 0x99, 0xC3, 0x1A, +0x0B, 0x98, 0x0C, 0x93, 0x80, 0x78, 0x03, 0x9A, 0x02, 0x90, 0xC9, 0x78, +0x01, 0x32, 0x49, 0xB2, 0x93, 0x01, 0x16, 0x91, 0x0F, 0x92, 0x10, 0x93, +0x75, 0xE0, 0x02, 0x9A, 0x10, 0x99, 0x02, 0x32, 0x88, 0x18, 0xAC, 0x49, +0x43, 0x5C, 0x0E, 0x2B, 0x27, 0xD9, 0x04, 0x23, 0x94, 0x46, 0xAA, 0x48, +0x01, 0x3B, 0xDB, 0xB2, 0xC2, 0x56, 0x03, 0x99, 0x8A, 0x18, 0xA8, 0x49, +0x01, 0x32, 0xC8, 0x56, 0x02, 0x99, 0x92, 0x01, 0x08, 0x18, 0x02, 0x30, +0xA2, 0x49, 0x10, 0x18, 0x0A, 0x5C, 0x01, 0x3A, 0xD2, 0xB2, 0x0D, 0x2A, +0x0E, 0xD8, 0xA2, 0x48, 0x0E, 0x99, 0x82, 0x56, 0x8A, 0x42, 0x09, 0xD1, +0x10, 0x9B, 0x62, 0x46, 0x9A, 0x18, 0x9F, 0x48, 0x52, 0x00, 0x13, 0x5A, +0x0D, 0x99, 0x5B, 0x1A, 0x07, 0x93, 0x12, 0xE0, 0x00, 0x2B, 0xDA, 0xD1, +0x41, 0xE0, 0x00, 0x2B, 0x3F, 0xD0, 0x98, 0x4A, 0x0E, 0x99, 0xD3, 0x18, +0x01, 0x3B, 0x1B, 0x78, 0x5B, 0xB2, 0x8B, 0x42, 0x37, 0xD1, 0x95, 0x4A, +0x40, 0x00, 0x83, 0x5A, 0x0D, 0x98, 0x1B, 0x1A, 0x07, 0x93, 0x07, 0x99, +0x00, 0x29, 0x2E, 0xD0, 0x02, 0x9A, 0x18, 0x98, 0x19, 0x99, 0x50, 0x43, +0xFF, 0xF7, 0x9E, 0xFC, 0x07, 0x9A, 0x17, 0x9B, 0x08, 0x99, 0x00, 0xB2, +0x89, 0x18, 0x18, 0x18, 0x73, 0x68, 0x08, 0x91, 0x0C, 0x99, 0xC0, 0x1A, +0x13, 0x1C, 0x4B, 0x43, 0x42, 0x43, 0x00, 0x28, 0x0B, 0xDC, 0x00, 0x29, +0x04, 0xDD, 0xFF, 0x18, 0x0A, 0x9B, 0x9B, 0x1A, 0x0A, 0x93, 0x12, 0xE0, +0x09, 0x98, 0xE4, 0x1A, 0x80, 0x1A, 0x09, 0x90, 0x0D, 0xE0, 0x0C, 0x99, +0x00, 0x29, 0x06, 0xDC, 0x05, 0x98, 0x06, 0x99, 0xC0, 0x1A, 0x89, 0x18, +0x05, 0x90, 0x06, 0x91, 0x03, 0xE0, 0x04, 0x98, 0xAD, 0x18, 0xC0, 0x18, +0x04, 0x90, 0x02, 0x9B, 0x01, 0x33, 0xDB, 0xB2, 0x02, 0x93, 0x02, 0x99, +0x16, 0x9A, 0x91, 0x42, 0x85, 0xDD, 0x0F, 0xAB, 0x1B, 0x78, 0x03, 0x93, +0x03, 0x98, 0x12, 0x99, 0x88, 0x42, 0x00, 0xDC, 0x64, 0xE7, 0x05, 0x9A, +0x04, 0x98, 0x94, 0x46, 0x63, 0x46, 0x3A, 0x1B, 0x19, 0x1A, 0x02, 0x97, +0xD1, 0x42, 0x02, 0xD4, 0x00, 0x21, 0x07, 0x91, 0x0D, 0xE0, 0x06, 0x9A, +0x06, 0x95, 0x15, 0x1C, 0x04, 0x9A, 0x09, 0x99, 0x04, 0x93, 0x0A, 0x9B, +0x05, 0x92, 0x27, 0x1C, 0x01, 0x22, 0x02, 0x9C, 0x0A, 0x91, 0x09, 0x93, +0x07, 0x92, 0x05, 0x9B, 0x04, 0x99, 0xF8, 0x18, 0x00, 0x19, 0x40, 0x18, +0x08, 0x99, 0xFF, 0xF7, 0x43, 0xFC, 0x02, 0x90, 0x00, 0x28, 0x64, 0xD0, +0x0A, 0x9A, 0x06, 0x9B, 0x09, 0x99, 0xD0, 0x18, 0x40, 0x18, 0x40, 0x19, +0x08, 0x99, 0xFF, 0xF7, 0x37, 0xFC, 0x03, 0x90, 0x03, 0x9A, 0x5A, 0x20, +0x00, 0x2A, 0x56, 0xD0, 0x02, 0x9B, 0x2D, 0x20, 0x9A, 0x42, 0x52, 0xD0, +0x93, 0x42, 0x24, 0xDA, 0x11, 0x1C, 0x98, 0x01, 0xFF, 0xF7, 0x28, 0xFC, +0x05, 0x1C, 0x05, 0x98, 0x04, 0x99, 0x3F, 0x1B, 0x3F, 0x18, 0x78, 0x1A, +0xC3, 0x43, 0xDB, 0x17, 0x18, 0x40, 0x08, 0x99, 0xFF, 0xF7, 0x1C, 0xFC, +0x03, 0x99, 0x80, 0x01, 0xFF, 0xF7, 0x18, 0xFC, 0x4B, 0x4B, 0x1A, 0x1C, +0x3F, 0x28, 0x00, 0xDD, 0x3F, 0x20, 0x1B, 0x5C, 0x3F, 0x2D, 0x00, 0xDD, +0x3F, 0x25, 0x51, 0x5D, 0x2D, 0x20, 0x41, 0x1A, 0xC9, 0x18, 0x58, 0x43, +0xFF, 0xF7, 0x08, 0xFC, 0x2B, 0xE0, 0x03, 0x9A, 0x02, 0x99, 0x90, 0x01, +0xFF, 0xF7, 0x02, 0xFC, 0x3F, 0x28, 0x00, 0xDD, 0x3F, 0x20, 0x3F, 0x4B, +0x09, 0x99, 0x1C, 0x5C, 0x0A, 0x9B, 0x06, 0x9A, 0x58, 0x1A, 0x80, 0x18, +0x40, 0x1B, 0xC3, 0x43, 0xDB, 0x17, 0x08, 0x99, 0x18, 0x40, 0xFF, 0xF7, +0xF1, 0xFB, 0x02, 0x99, 0x80, 0x01, 0xFF, 0xF7, 0xED, 0xFB, 0x3F, 0x28, +0x00, 0xDD, 0x3F, 0x20, 0x34, 0x4B, 0x5A, 0x22, 0x1B, 0x5C, 0x2D, 0x20, +0xD1, 0x1A, 0x00, 0x1B, 0x12, 0x1B, 0x48, 0x43, 0x5A, 0x43, 0x87, 0x23, +0x1C, 0x1B, 0x80, 0x18, 0x61, 0x1A, 0xFF, 0xF7, 0xDB, 0xFB, 0x07, 0x9B, +0x00, 0x2B, 0x00, 0xD0, 0x40, 0x42, 0x11, 0x99, 0x5A, 0x24, 0x24, 0x1A, +0x08, 0x70, 0x20, 0x1C, 0xFF, 0xF7, 0x8A, 0xFE, 0x09, 0x90, 0x20, 0x1C, +0xFF, 0xF7, 0x74, 0xFE, 0x0B, 0x9A, 0x0A, 0x90, 0x01, 0x23, 0xD3, 0x56, +0x17, 0x78, 0x0F, 0x93, 0x1A, 0x4B, 0x1B, 0x4A, 0x0A, 0x21, 0x58, 0x5E, +0x00, 0x24, 0x10, 0x90, 0x28, 0x21, 0x50, 0x5E, 0x18, 0x49, 0x12, 0x90, +0x09, 0x68, 0x58, 0x68, 0x07, 0x91, 0x13, 0x90, 0x08, 0x20, 0x19, 0x5E, +0x1B, 0x68, 0x15, 0x91, 0x26, 0x20, 0x11, 0x5E, 0x17, 0x93, 0x16, 0x91, +0x05, 0x94, 0x04, 0x94, 0x02, 0x94, 0xA8, 0xE0, 0x12, 0x98, 0x13, 0x99, +0x78, 0x43, 0xFF, 0xF7, 0xA7, 0xFB, 0x10, 0x99, 0x00, 0xB2, 0x33, 0x68, +0x08, 0x18, 0xC3, 0x1A, 0x03, 0x93, 0x0B, 0x9A, 0x03, 0x99, 0x03, 0x23, +0x0A, 0x98, 0xD3, 0x56, 0x95, 0x78, 0x09, 0x9A, 0x48, 0x43, 0x4A, 0x43, +0x14, 0x93, 0x7B, 0x1C, 0x18, 0x90, 0x98, 0x01, 0x19, 0x92, 0x0C, 0x93, +0x0D, 0x90, 0x87, 0xE0, 0x24, 0x09, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0x38, 0x0D, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, 0xF8, 0x59, 0x00, 0x00, +0xF4, 0x59, 0x00, 0x00, 0xEC, 0x02, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, +0x50, 0x72, 0x00, 0x00, 0x0D, 0x99, 0xAA, 0x1C, 0x88, 0x18, 0x4E, 0x49, +0x43, 0x5C, 0x0E, 0x2B, 0x25, 0xD9, 0x04, 0x23, 0x94, 0x46, 0x4C, 0x48, +0x01, 0x3B, 0xDB, 0xB2, 0x4B, 0x49, 0xC2, 0x56, 0xC8, 0x56, 0xBA, 0x18, +0x01, 0x32, 0x28, 0x18, 0x92, 0x01, 0x02, 0x30, 0x45, 0x49, 0x10, 0x18, +0x0A, 0x5C, 0x01, 0x3A, 0xD2, 0xB2, 0x0D, 0x2A, 0x0E, 0xD8, 0x45, 0x48, +0x0E, 0x99, 0x82, 0x56, 0x8A, 0x42, 0x09, 0xD1, 0x0D, 0x9B, 0x62, 0x46, +0x9A, 0x18, 0x42, 0x48, 0x52, 0x00, 0x13, 0x5A, 0x07, 0x99, 0x5B, 0x1A, +0x06, 0x93, 0x12, 0xE0, 0x00, 0x2B, 0xDC, 0xD1, 0x46, 0xE0, 0x00, 0x2B, +0x44, 0xD0, 0x3B, 0x4A, 0x0E, 0x99, 0xD3, 0x18, 0x01, 0x3B, 0x1B, 0x78, +0x5B, 0xB2, 0x8B, 0x42, 0x3C, 0xD1, 0x38, 0x4A, 0x40, 0x00, 0x83, 0x5A, +0x07, 0x98, 0x1B, 0x1A, 0x06, 0x93, 0x06, 0x99, 0x00, 0x29, 0x33, 0xD0, +0x16, 0x98, 0x17, 0x99, 0x68, 0x43, 0xFF, 0xF7, 0x39, 0xFB, 0x15, 0x9A, +0x00, 0xB2, 0x73, 0x68, 0x10, 0x18, 0x1B, 0x1A, 0x01, 0x93, 0x01, 0x98, +0x03, 0x9B, 0x06, 0x9A, 0x09, 0x99, 0x5A, 0x43, 0x41, 0x43, 0x06, 0x9B, +0x43, 0x43, 0x18, 0x98, 0x09, 0x1A, 0x00, 0x29, 0x04, 0xDD, 0x05, 0x99, +0xE4, 0x18, 0x89, 0x18, 0x05, 0x91, 0x03, 0xE0, 0x05, 0x98, 0xE4, 0x1A, +0x80, 0x1A, 0x05, 0x90, 0x01, 0x99, 0x0A, 0x98, 0x48, 0x43, 0x19, 0x99, +0x40, 0x18, 0x00, 0x28, 0x06, 0xDD, 0x02, 0x98, 0x04, 0x99, 0x80, 0x18, +0xC9, 0x18, 0x02, 0x90, 0x04, 0x91, 0x05, 0xE0, 0x02, 0x98, 0x04, 0x99, +0x80, 0x1A, 0xC9, 0x1A, 0x02, 0x90, 0x04, 0x91, 0x01, 0x35, 0xED, 0xB2, +0x14, 0x9A, 0x95, 0x42, 0x86, 0xDD, 0x0C, 0xAB, 0x1F, 0x78, 0x0F, 0x98, +0x87, 0x42, 0x00, 0xDC, 0x52, 0xE7, 0x08, 0x99, 0x02, 0x98, 0xFF, 0xF7, +0xFB, 0xFA, 0x08, 0x99, 0x07, 0x1C, 0x04, 0x98, 0xFF, 0xF7, 0xF6, 0xFA, +0x08, 0x99, 0x05, 0x1C, 0x05, 0x98, 0xFF, 0xF7, 0xF1, 0xFA, 0x08, 0x99, +0x06, 0x1C, 0x20, 0x1C, 0xFF, 0xF7, 0xEC, 0xFA, 0x7F, 0x43, 0x76, 0x43, +0x6D, 0x43, 0x40, 0x43, 0x11, 0x99, 0x7D, 0x19, 0x30, 0x18, 0xAD, 0x11, +0x80, 0x11, 0x1B, 0xB0, 0x4D, 0x60, 0x88, 0x60, 0xF0, 0xBD, 0xC0, 0x46, +0x00, 0x20, 0x00, 0x40, 0xF8, 0x59, 0x00, 0x00, 0xF4, 0x59, 0x00, 0x00, +0xEC, 0x02, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x08, 0xB5, 0x05, 0x4B, +0x1B, 0x88, 0xDB, 0xB2, 0x10, 0x2B, 0x01, 0xD0, 0xAF, 0x2B, 0x01, 0xD1, +0xFD, 0xF7, 0x8A, 0xF9, 0x08, 0xBD, 0xC0, 0x46, 0x28, 0x00, 0x00, 0x20, +0x38, 0xB5, 0xC1, 0x4A, 0x13, 0x88, 0x1B, 0xB2, 0xAE, 0x2B, 0x00, 0xD1, +0x59, 0xE1, 0x3B, 0xDC, 0x0C, 0x2B, 0x00, 0xD1, 0xD2, 0xE0, 0x1B, 0xDC, +0x05, 0x2B, 0x00, 0xD1, 0xA6, 0xE0, 0x08, 0xDC, 0x03, 0x2B, 0x00, 0xD1, +0x8F, 0xE0, 0x00, 0xDD, 0x96, 0xE0, 0x02, 0x2B, 0x00, 0xD0, 0xA5, 0xE1, +0x7C, 0xE0, 0x09, 0x2B, 0x00, 0xD1, 0xA4, 0xE0, 0x03, 0xDC, 0x06, 0x2B, +0x00, 0xD0, 0x9D, 0xE1, 0x99, 0xE0, 0x0A, 0x2B, 0x00, 0xD1, 0xAC, 0xE0, +0x0B, 0x2B, 0x00, 0xD0, 0x96, 0xE1, 0xAD, 0xE0, 0x31, 0x2B, 0x00, 0xD1, +0x95, 0xE0, 0x08, 0xDC, 0x10, 0x2B, 0x5A, 0xD0, 0x30, 0x2B, 0x00, 0xD1, +0x9A, 0xE0, 0x0F, 0x2B, 0x00, 0xD0, 0x89, 0xE1, 0x48, 0xE0, 0x62, 0x2B, +0x00, 0xD1, 0x81, 0xE1, 0x03, 0xDC, 0x61, 0x2B, 0x00, 0xD0, 0x81, 0xE1, +0x77, 0xE1, 0x64, 0x2B, 0x00, 0xD1, 0x6F, 0xE1, 0xA8, 0x2B, 0x00, 0xD0, +0x7A, 0xE1, 0x5B, 0xE1, 0xF4, 0x2B, 0x00, 0xD1, 0xBC, 0xE0, 0x19, 0xDC, +0xEF, 0x2B, 0x00, 0xD1, 0x2E, 0xE1, 0x09, 0xDC, 0xBF, 0x2B, 0x00, 0xD1, +0x50, 0xE1, 0xEE, 0x2B, 0x00, 0xD1, 0x23, 0xE1, 0xAF, 0x2B, 0x00, 0xD0, +0x68, 0xE1, 0x11, 0xE1, 0xF1, 0x2B, 0x00, 0xD1, 0x91, 0xE0, 0x00, 0xDA, +0x8C, 0xE0, 0xF2, 0x2B, 0x00, 0xD1, 0x94, 0xE0, 0xF3, 0x2B, 0x00, 0xD0, +0x5C, 0xE1, 0x99, 0xE0, 0xF9, 0x2B, 0x00, 0xD1, 0xCD, 0xE0, 0x0B, 0xDC, +0xF6, 0x2B, 0x00, 0xD1, 0xAD, 0xE0, 0x00, 0xDA, 0xA1, 0xE0, 0xF7, 0x2B, +0x00, 0xD1, 0xAF, 0xE0, 0xF8, 0x2B, 0x00, 0xD0, 0x4C, 0xE1, 0xB7, 0xE0, +0xFB, 0x2B, 0x00, 0xD1, 0xCF, 0xE0, 0x00, 0xDA, 0xC4, 0xE0, 0xFC, 0x2B, +0x00, 0xD1, 0xD3, 0xE0, 0xFD, 0x2B, 0x00, 0xD0, 0x40, 0xE1, 0xD8, 0xE0, +0x83, 0x4C, 0x23, 0x68, 0x00, 0x2B, 0x01, 0xD1, 0xFD, 0xF7, 0x02, 0xF9, +0x22, 0x68, 0x81, 0x4B, 0xD2, 0x00, 0x1A, 0x70, 0x34, 0xE1, 0x80, 0x49, +0x80, 0x4A, 0x00, 0x23, 0x08, 0x78, 0x7D, 0x4D, 0xC0, 0x18, 0x14, 0x5C, +0x58, 0x19, 0x01, 0x33, 0x04, 0x70, 0x08, 0x2B, 0xF6, 0xD1, 0x27, 0xE1, +0x7B, 0x4A, 0x0F, 0x23, 0x26, 0x20, 0x11, 0x5E, 0x28, 0x25, 0x52, 0x5F, +0x09, 0x11, 0x12, 0x12, 0x99, 0x43, 0x13, 0x40, 0x73, 0x4A, 0xCB, 0x18, +0x13, 0x70, 0x70, 0x4B, 0x1A, 0x88, 0x03, 0x23, 0x12, 0xB2, 0x9A, 0x1A, +0x72, 0x4B, 0x19, 0x8D, 0x6E, 0x4B, 0xD1, 0x54, 0x6B, 0x4B, 0x1A, 0x88, +0x04, 0x23, 0x12, 0xB2, 0x9A, 0x1A, 0x6E, 0x4B, 0xD9, 0x8C, 0x6A, 0x4B, +0xD1, 0x54, 0x07, 0xE1, 0x6C, 0x4B, 0xDA, 0x8C, 0x67, 0x4B, 0x1A, 0x70, +0x02, 0xE1, 0x6A, 0x4B, 0x34, 0x33, 0x1A, 0x78, 0x64, 0x4B, 0x1A, 0x70, +0xFC, 0xE0, 0x68, 0x4B, 0x1A, 0x78, 0x62, 0x4B, 0x00, 0x2A, 0x02, 0xD0, +0x02, 0x22, 0x1A, 0x70, 0xF4, 0xE0, 0x01, 0x22, 0x1A, 0x70, 0xF1, 0xE0, +0x62, 0x4B, 0x1A, 0x78, 0x5C, 0x4B, 0x1A, 0x70, 0xEC, 0xE0, 0x61, 0x4B, +0x1A, 0x78, 0x5A, 0x4B, 0x1A, 0x70, 0xE7, 0xE0, 0x12, 0x88, 0x5F, 0x4B, +0x12, 0xB2, 0x19, 0x78, 0x0B, 0x23, 0x9A, 0x1A, 0x55, 0x4B, 0xD1, 0x54, +0x52, 0x4B, 0x1A, 0x88, 0x5A, 0x4B, 0x12, 0xB2, 0x59, 0x78, 0x0C, 0x23, +0x9A, 0x1A, 0x51, 0x4B, 0xD1, 0x54, 0xD5, 0xE0, 0x4F, 0x4B, 0x42, 0x22, +0x1A, 0x70, 0x4C, 0x4B, 0x01, 0x21, 0x1A, 0x88, 0xF1, 0x23, 0x12, 0xB2, +0x9A, 0x1A, 0x4B, 0x4B, 0xD1, 0x54, 0x48, 0x4B, 0x1A, 0x88, 0x4C, 0x4B, +0x12, 0xB2, 0x59, 0x78, 0xF2, 0x23, 0x9A, 0x1A, 0x46, 0x4B, 0xD1, 0x54, +0x43, 0x4B, 0xBB, 0x21, 0x1A, 0x88, 0xF3, 0x23, 0x12, 0xB2, 0x9A, 0x1A, +0x42, 0x4B, 0xD1, 0x54, 0x3F, 0x4B, 0x1A, 0x88, 0x48, 0x4B, 0x12, 0xB2, +0x19, 0x78, 0xF4, 0x23, 0x9A, 0x1A, 0x3E, 0x4B, 0xD1, 0x54, 0x3B, 0x4B, +0x1A, 0x88, 0x45, 0x4B, 0x12, 0xB2, 0x19, 0x78, 0xF5, 0x23, 0x9A, 0x1A, +0x39, 0x4B, 0xD1, 0x54, 0xA6, 0xE0, 0x39, 0x4B, 0x3A, 0x4A, 0x1B, 0x78, +0xD3, 0x18, 0xDA, 0x78, 0x35, 0x4B, 0x1A, 0x70, 0x32, 0x4B, 0x37, 0x49, +0x1A, 0x88, 0x34, 0x4B, 0x12, 0xB2, 0x1B, 0x78, 0xCB, 0x18, 0x19, 0x79, +0xF7, 0x23, 0x9A, 0x1A, 0x2F, 0x4B, 0xD1, 0x54, 0x2C, 0x4B, 0x1A, 0x88, +0x30, 0x4B, 0x12, 0xB2, 0x59, 0x79, 0xF8, 0x23, 0x9A, 0x1A, 0x2B, 0x4B, +0xD1, 0x54, 0x28, 0x4B, 0x1A, 0x88, 0x2C, 0x4B, 0x12, 0xB2, 0x99, 0x79, +0xF9, 0x23, 0x9A, 0x1A, 0x26, 0x4B, 0xD1, 0x54, 0x23, 0x4B, 0x1A, 0x88, +0x27, 0x4B, 0x12, 0xB2, 0xD9, 0x79, 0xFA, 0x23, 0x9A, 0x1A, 0x22, 0x4B, +0xD1, 0x54, 0x1F, 0x4B, 0x1A, 0x88, 0x23, 0x4B, 0x12, 0xB2, 0x19, 0x7A, +0xFB, 0x23, 0x9A, 0x1A, 0x1D, 0x4B, 0xD1, 0x54, 0x1A, 0x4B, 0x1A, 0x88, +0x1E, 0x4B, 0x12, 0xB2, 0x59, 0x7A, 0xFC, 0x23, 0x9A, 0x1A, 0x19, 0x4B, +0xD1, 0x54, 0x16, 0x4B, 0x1A, 0x88, 0x1A, 0x4B, 0x12, 0xB2, 0x99, 0x7A, +0xFD, 0x23, 0x9A, 0x1A, 0x14, 0x4B, 0xD1, 0x54, 0x5C, 0xE0, 0x1D, 0x4B, +0x1A, 0x78, 0x12, 0x4B, 0x1A, 0x70, 0xFD, 0xF7, 0x1F, 0xF8, 0x55, 0xE0, +0x1A, 0x49, 0x10, 0x4A, 0x00, 0x23, 0x0C, 0x68, 0x10, 0x78, 0x0D, 0x4D, +0x20, 0x18, 0xC4, 0x5C, 0x58, 0x19, 0x01, 0x33, 0x04, 0x70, 0x08, 0x2B, +0xF5, 0xD1, 0x47, 0xE0, 0x0B, 0x4B, 0x1A, 0x7E, 0x07, 0x4B, 0x1A, 0x70, +0x04, 0x4B, 0x1A, 0x88, 0x08, 0x4B, 0x12, 0xB2, 0xD9, 0x7D, 0xEF, 0x23, +0x9A, 0x1A, 0x03, 0x4B, 0xD1, 0x54, 0x39, 0xE0, 0x28, 0x00, 0x00, 0x20, +0x98, 0x0D, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x50, 0x2A, 0x00, 0x00, 0x20, +0xEC, 0x11, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0xDD, 0x01, 0x00, 0x20, 0xDF, 0x01, 0x00, 0x20, 0x0A, 0x03, 0x00, 0x20, +0xFF, 0x73, 0x00, 0x00, 0xFF, 0x7B, 0x00, 0x00, 0xF6, 0x03, 0x00, 0x20, +0x34, 0x0D, 0x00, 0x20, 0x0F, 0x49, 0x10, 0x4A, 0x00, 0x23, 0x0C, 0x68, +0x10, 0x78, 0x0F, 0x4D, 0x20, 0x18, 0xC4, 0x5C, 0x58, 0x19, 0x01, 0x33, +0x04, 0x70, 0x08, 0x2B, 0xF5, 0xD1, 0xFC, 0xF7, 0xD7, 0xFF, 0x0D, 0xE0, +0x0A, 0x4B, 0x1A, 0x78, 0x08, 0x4B, 0x1A, 0x70, 0x08, 0xE0, 0x09, 0x4B, +0x9A, 0x78, 0x06, 0x4B, 0x1A, 0x70, 0x03, 0xE0, 0x06, 0x4B, 0xDA, 0x78, +0x03, 0x4B, 0x1A, 0x70, 0x38, 0xBD, 0xC0, 0x46, 0x34, 0x0D, 0x00, 0x20, +0x2A, 0x00, 0x00, 0x20, 0x0C, 0x00, 0x00, 0x50, 0xFF, 0x5B, 0x00, 0x00, +0x35, 0x00, 0x00, 0x20, 0x08, 0xB5, 0x03, 0x1C, 0x50, 0x1E, 0x06, 0x28, +0x35, 0xD8, 0xFF, 0xF7, 0x93, 0xF8, 0x04, 0x0A, 0x2A, 0x1B, 0x15, 0x2A, +0x2A, 0x00, 0x18, 0x4A, 0x01, 0x23, 0x13, 0x70, 0x17, 0x4A, 0x13, 0x70, +0x29, 0xE0, 0x16, 0x4A, 0x9B, 0x01, 0x59, 0x18, 0x02, 0x20, 0x15, 0x4B, +0x10, 0x70, 0x49, 0x00, 0x14, 0x4A, 0xC9, 0x18, 0x11, 0x60, 0x1E, 0xE0, +0xFC, 0xF7, 0x9E, 0xFF, 0x0E, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x18, 0xE0, +0x0D, 0x4A, 0x5B, 0x01, 0x59, 0x18, 0x01, 0x20, 0x0E, 0x4B, 0x10, 0x70, +0x5A, 0x56, 0x0E, 0x4B, 0x00, 0x2A, 0x00, 0xDC, 0x00, 0x22, 0x1A, 0x80, +0x09, 0x4A, 0x13, 0x60, 0x09, 0xE0, 0x06, 0x4A, 0x02, 0x20, 0x5B, 0x01, +0x10, 0x70, 0xC9, 0x18, 0x08, 0x4A, 0x49, 0x00, 0x89, 0x18, 0x04, 0x4A, +0x11, 0x60, 0x08, 0xBD, 0xE5, 0x01, 0x00, 0x20, 0xF6, 0x03, 0x00, 0x20, +0x84, 0x40, 0x00, 0x40, 0x34, 0x0D, 0x00, 0x20, 0x64, 0x0E, 0x00, 0x20, +0x08, 0x03, 0x00, 0x20, 0xF8, 0x03, 0x00, 0x20, 0xF0, 0xB5, 0x87, 0x4C, +0x23, 0x23, 0xE3, 0x5C, 0x8D, 0xB0, 0x00, 0x2B, 0x12, 0xD0, 0x01, 0x3B, +0xDB, 0xB2, 0x84, 0x4D, 0x84, 0x49, 0x00, 0xE0, 0x13, 0x1C, 0x9A, 0x00, +0xD2, 0x18, 0x52, 0x00, 0x8A, 0x18, 0x3C, 0x26, 0x90, 0x5F, 0x5A, 0x1E, +0x46, 0x1E, 0xB0, 0x41, 0xE8, 0x54, 0xD2, 0xB2, 0x00, 0x2B, 0xF1, 0xD1, +0xFC, 0xF7, 0x82, 0xFF, 0x00, 0x28, 0xFB, 0xD1, 0x23, 0x23, 0xE4, 0x5C, +0x07, 0x94, 0x00, 0x2C, 0x00, 0xD1, 0xA3, 0xE0, 0x78, 0x4B, 0x60, 0x22, +0x19, 0x78, 0x78, 0x4B, 0x09, 0x01, 0x1B, 0x78, 0x52, 0x42, 0x0A, 0x43, +0x76, 0x4C, 0x20, 0x21, 0x1B, 0x01, 0x0B, 0x43, 0x34, 0x21, 0x61, 0x5C, +0x74, 0x48, 0x09, 0x91, 0x00, 0x21, 0x74, 0x4F, 0x08, 0x91, 0x6E, 0x49, +0xD2, 0xB2, 0xDB, 0xB2, 0x0A, 0x92, 0x0B, 0x93, 0xC4, 0x19, 0x00, 0x23, +0x01, 0x22, 0x01, 0x91, 0x3E, 0xE0, 0x01, 0x99, 0x6E, 0x4D, 0x6F, 0x4F, +0xC9, 0x18, 0x8C, 0x46, 0x79, 0x5D, 0x6E, 0x4F, 0xFD, 0x18, 0x67, 0x46, +0xBF, 0x88, 0x04, 0x97, 0xAF, 0x88, 0x06, 0x97, 0x67, 0x46, 0x3F, 0x8C, +0xBC, 0x46, 0x2F, 0x8B, 0x03, 0x97, 0x00, 0x29, 0x22, 0xD1, 0x61, 0x46, +0x09, 0xB2, 0x6F, 0x46, 0x05, 0x91, 0x0C, 0x37, 0x00, 0x21, 0x79, 0x5E, +0x05, 0x9F, 0x79, 0x1A, 0xCF, 0x17, 0xC9, 0x19, 0x79, 0x40, 0x09, 0x9F, +0xB9, 0x42, 0x65, 0xDA, 0x10, 0x27, 0x69, 0x46, 0x79, 0x5E, 0x03, 0x91, +0x69, 0x46, 0x18, 0x31, 0x00, 0x27, 0xCF, 0x5F, 0x03, 0x99, 0xCF, 0x1B, +0xF9, 0x17, 0x7F, 0x18, 0x4F, 0x40, 0x09, 0x99, 0xB9, 0x42, 0x55, 0xDD, +0x2C, 0x27, 0xED, 0x5F, 0x00, 0x2D, 0x57, 0xDD, 0x07, 0x9E, 0x55, 0x1C, +0x02, 0x33, 0x01, 0x30, 0x0C, 0x34, 0x96, 0x42, 0x45, 0xDD, 0x2A, 0x1C, +0x01, 0x9D, 0x9E, 0x00, 0xF6, 0x18, 0xAE, 0x19, 0x3C, 0x27, 0xF5, 0x5F, +0x00, 0x2D, 0xB8, 0xDC, 0x4D, 0x4E, 0xF5, 0x18, 0x2C, 0x27, 0xEE, 0x5F, +0x00, 0x2E, 0xE9, 0xDD, 0x06, 0x78, 0x00, 0x2E, 0xE6, 0xD0, 0x05, 0x21, +0x69, 0x56, 0x2E, 0x8B, 0x8C, 0x46, 0x08, 0x99, 0xAD, 0x88, 0xC9, 0x00, +0x37, 0xB2, 0x03, 0x91, 0x04, 0x95, 0x61, 0x46, 0x0F, 0x25, 0x0D, 0x40, +0x3F, 0x11, 0x0F, 0x21, 0x8F, 0x43, 0x03, 0x99, 0x2F, 0x43, 0x8C, 0x46, +0x3E, 0x49, 0x08, 0x9D, 0x8C, 0x44, 0x0B, 0x99, 0x01, 0x35, 0x11, 0x43, +0x05, 0x95, 0x65, 0x46, 0x29, 0x70, 0x6F, 0x70, 0x6D, 0x46, 0x10, 0x27, +0x7F, 0x5D, 0x00, 0x21, 0x65, 0x46, 0xEE, 0x70, 0xAF, 0x70, 0x29, 0x71, +0x69, 0x71, 0xA9, 0x71, 0xE9, 0x71, 0x14, 0x26, 0x6D, 0x46, 0x75, 0x5D, +0x07, 0x9E, 0x08, 0x95, 0x01, 0x70, 0x55, 0x1C, 0x02, 0x33, 0x01, 0x30, +0x0C, 0x34, 0x96, 0x42, 0xB9, 0xDC, 0x08, 0x9F, 0x00, 0x2F, 0x42, 0xD1, +0x0D, 0xB0, 0xF0, 0xBD, 0x2D, 0x4F, 0xD7, 0x19, 0x01, 0x3F, 0x3F, 0x78, +0x00, 0x2F, 0xA3, 0xD0, 0x69, 0x46, 0x10, 0x27, 0x7D, 0x5E, 0x08, 0x99, +0x2D, 0x12, 0x03, 0x95, 0xC9, 0x00, 0x05, 0x9D, 0x02, 0x91, 0x03, 0x99, +0x2F, 0x11, 0x0F, 0x25, 0x0D, 0x40, 0x40, 0x36, 0x03, 0x95, 0x36, 0x78, +0x0F, 0x25, 0xAF, 0x43, 0x05, 0x97, 0x06, 0x96, 0x02, 0x9F, 0x1E, 0x4E, +0x05, 0x99, 0xF5, 0x19, 0x0A, 0x9F, 0x03, 0x9E, 0x17, 0x43, 0x0E, 0x43, +0x2F, 0x70, 0x6E, 0x70, 0x10, 0x27, 0x6E, 0x46, 0xBE, 0x5D, 0x69, 0x46, +0xAE, 0x70, 0x18, 0x26, 0x71, 0x5C, 0x67, 0x46, 0xEF, 0x70, 0x29, 0x71, +0x26, 0x78, 0x6E, 0x71, 0x66, 0x68, 0xFF, 0x2E, 0x00, 0xDD, 0xFF, 0x26, +0xAE, 0x71, 0xA6, 0x68, 0xFF, 0x2E, 0x00, 0xDD, 0xFF, 0x26, 0x08, 0x9F, +0xEE, 0x71, 0x01, 0x37, 0xFF, 0xB2, 0x01, 0x25, 0x08, 0x97, 0x05, 0x70, +0x6C, 0xE7, 0x0E, 0x4B, 0x1F, 0x60, 0xFC, 0xF7, 0x39, 0xFE, 0xB7, 0xE7, +0xAE, 0x09, 0x00, 0x20, 0xEC, 0x01, 0x00, 0x20, 0x9C, 0x0D, 0x00, 0x20, +0xF5, 0x00, 0x00, 0x20, 0xF4, 0x00, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0xF4, 0x16, 0x00, 0x20, 0x38, 0xFC, 0xFF, 0xFF, 0x04, 0x05, 0x00, 0x00, +0xEC, 0x11, 0x00, 0x20, 0x20, 0x01, 0x00, 0x20, 0x64, 0x01, 0x00, 0x20, +0x98, 0x0D, 0x00, 0x20, 0x10, 0xB5, 0x04, 0x1C, 0xFC, 0xF7, 0x70, 0xFE, +0x00, 0x28, 0xFB, 0xD1, 0x0A, 0x4B, 0x01, 0x2C, 0x02, 0xD0, 0x02, 0x2C, +0x05, 0xD1, 0x02, 0xE0, 0x0F, 0x22, 0x1A, 0x70, 0x01, 0xE0, 0x0E, 0x22, +0x1A, 0x70, 0x00, 0x22, 0xDA, 0x70, 0x9A, 0x70, 0x5A, 0x70, 0x04, 0x4B, +0x01, 0x22, 0x1A, 0x60, 0xFC, 0xF7, 0x04, 0xFE, 0x10, 0xBD, 0xC0, 0x46, +0xEC, 0x11, 0x00, 0x20, 0x98, 0x0D, 0x00, 0x20, 0xF0, 0xB5, 0x8B, 0xB0, +0x14, 0x28, 0x00, 0xD9, 0xA3, 0xE3, 0xFE, 0xF7, 0x09, 0xFF, 0x15, 0x00, +0xA2, 0x03, 0x43, 0x00, 0xA2, 0x03, 0x59, 0x00, 0xA2, 0x03, 0x64, 0x00, +0x88, 0x00, 0xA2, 0x03, 0xFB, 0x00, 0xA2, 0x03, 0xA2, 0x03, 0x48, 0x01, +0xA2, 0x03, 0x54, 0x01, 0x30, 0x03, 0xB7, 0x02, 0xA2, 0x03, 0xA2, 0x03, +0x8C, 0x03, 0x9D, 0x03, 0xC0, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD0, +0x87, 0xE3, 0xBF, 0x4C, 0x01, 0x23, 0xF2, 0x20, 0x23, 0x72, 0xE0, 0x70, +0xFE, 0xF7, 0xD8, 0xFD, 0xBC, 0x4B, 0x20, 0x70, 0x1B, 0x78, 0xAA, 0x2B, +0x00, 0xD0, 0x7A, 0xE3, 0xBA, 0x4A, 0xBB, 0x4B, 0x11, 0x78, 0xBB, 0x4A, +0x1B, 0x78, 0x12, 0x78, 0xC9, 0x18, 0x91, 0x42, 0x00, 0xD0, 0x70, 0xE3, +0xB8, 0x4A, 0xE0, 0x78, 0x40, 0x32, 0x12, 0x78, 0x59, 0xB2, 0x41, 0x18, +0x89, 0x18, 0xFF, 0x29, 0x03, 0xDD, 0xD2, 0x43, 0xD2, 0xB2, 0xE2, 0x70, +0x63, 0xE3, 0xE2, 0x78, 0xD3, 0x18, 0xDB, 0xB2, 0xE3, 0x70, 0x5E, 0xE3, +0xB0, 0x4A, 0x00, 0x23, 0x13, 0x70, 0xA0, 0x21, 0xAF, 0x4A, 0xC9, 0x00, +0x53, 0x54, 0xAF, 0x49, 0xA1, 0x20, 0x53, 0x54, 0xAE, 0x49, 0xC0, 0x00, +0x53, 0x54, 0x0A, 0x21, 0x12, 0x18, 0x01, 0x39, 0xC9, 0xB2, 0x88, 0x18, +0x03, 0x70, 0x00, 0x29, 0xF9, 0xD1, 0x48, 0xE3, 0xA9, 0x49, 0x00, 0x23, +0x0A, 0x68, 0x9A, 0x42, 0x02, 0xDD, 0x4B, 0x68, 0xD3, 0x18, 0xDB, 0x0F, +0xA6, 0x4A, 0x13, 0x70, 0x3D, 0xE3, 0xA6, 0x4B, 0xA0, 0x49, 0x9B, 0x69, +0xA0, 0x4A, 0x00, 0x2B, 0x0D, 0xD1, 0x8B, 0x5C, 0x19, 0x20, 0x01, 0x2B, +0x11, 0xD0, 0xA2, 0x4B, 0x1B, 0x78, 0x01, 0x2B, 0x02, 0xD1, 0xA1, 0x4B, +0x98, 0x7E, 0x0A, 0xE0, 0xA0, 0x4B, 0x98, 0x7E, 0x07, 0xE0, 0x8A, 0x5C, +0x08, 0x20, 0x01, 0x2A, 0x03, 0xD1, 0x19, 0x20, 0x03, 0x2B, 0x00, 0xD0, +0x08, 0x20, 0x9C, 0x4B, 0x80, 0x01, 0x19, 0x68, 0xFE, 0xF7, 0xDC, 0xFE, +0x8E, 0x4B, 0x98, 0x76, 0x19, 0xE3, 0x94, 0x4B, 0x00, 0x22, 0x1A, 0x60, +0x93, 0x4A, 0x11, 0x78, 0x96, 0x4A, 0x00, 0x29, 0x03, 0xD0, 0x02, 0x21, +0x11, 0x70, 0x08, 0x27, 0x08, 0xE0, 0x01, 0x21, 0x11, 0x70, 0x8B, 0x4A, +0x06, 0x27, 0x08, 0x21, 0x52, 0x5E, 0x22, 0x2A, 0x00, 0xDC, 0x03, 0x27, +0x5D, 0x69, 0x1C, 0x69, 0x1B, 0x68, 0x00, 0x26, 0x05, 0x95, 0x04, 0x94, +0x03, 0x93, 0x02, 0x96, 0x1A, 0x25, 0x47, 0xE0, 0x00, 0x20, 0x0E, 0x23, +0xAE, 0x1C, 0x01, 0x3B, 0xDB, 0xB2, 0x5A, 0x1C, 0x92, 0x01, 0x87, 0x49, +0x92, 0x19, 0x52, 0x00, 0x52, 0x5A, 0x0C, 0x1C, 0x12, 0xB2, 0x80, 0x18, +0x00, 0x2B, 0xF2, 0xD1, 0x1C, 0x21, 0xFE, 0xF7, 0xA7, 0xFE, 0xFA, 0x0F, +0x06, 0x90, 0x0E, 0x23, 0x07, 0x92, 0x01, 0x3B, 0xDB, 0xB2, 0x58, 0x1C, +0x82, 0x01, 0x92, 0x19, 0x00, 0x90, 0x52, 0x00, 0xA2, 0x5A, 0x90, 0xB2, +0x11, 0xB2, 0x02, 0x9A, 0x8A, 0x42, 0x03, 0xDA, 0xC1, 0xB2, 0x02, 0x91, +0x05, 0x95, 0x04, 0x93, 0x06, 0x9A, 0x80, 0x1A, 0x80, 0xB2, 0x01, 0x90, +0x68, 0x46, 0x04, 0x22, 0x82, 0x5E, 0x00, 0x98, 0x81, 0x01, 0x89, 0x19, +0x49, 0x00, 0x00, 0x2A, 0x0D, 0xDD, 0x00, 0x91, 0x68, 0x46, 0x61, 0x5A, +0x81, 0x88, 0x00, 0x98, 0x21, 0x52, 0x07, 0x98, 0xD1, 0x17, 0xBA, 0x42, +0x41, 0x41, 0x03, 0x9A, 0x52, 0x18, 0x03, 0x92, 0x02, 0xE0, 0x00, 0x20, +0x62, 0x5A, 0x60, 0x52, 0x00, 0x2B, 0xCE, 0xD1, 0x01, 0x3D, 0xED, 0xB2, +0xFF, 0x2D, 0xB3, 0xD1, 0x5E, 0x4B, 0x04, 0x9C, 0x05, 0x9D, 0x03, 0x9E, +0x1C, 0x61, 0x5D, 0x61, 0x1E, 0x60, 0xA6, 0xE2, 0x61, 0x4B, 0x62, 0x48, +0x00, 0x24, 0x1C, 0x60, 0x82, 0x68, 0xC3, 0x68, 0x9A, 0x42, 0x00, 0xDA, +0x9D, 0xE2, 0x0C, 0x25, 0xD6, 0x0F, 0x95, 0x42, 0x66, 0x41, 0x92, 0x19, +0xDE, 0x17, 0x41, 0x68, 0xF6, 0x1A, 0x00, 0x68, 0xF6, 0x0F, 0x9B, 0x1B, +0x18, 0x27, 0xC6, 0x0F, 0x87, 0x42, 0x66, 0x41, 0x80, 0x19, 0xCE, 0x17, +0x76, 0x1A, 0xF6, 0x0F, 0x89, 0x1B, 0x41, 0x1A, 0xC8, 0x0F, 0x8D, 0x42, +0x44, 0x41, 0xE4, 0xB2, 0x00, 0x2C, 0x08, 0xD1, 0xD3, 0x1A, 0xD9, 0x0F, +0x0B, 0x22, 0x9A, 0x42, 0x4C, 0x41, 0xE4, 0xB2, 0x00, 0x2C, 0x00, 0xD1, +0x79, 0xE2, 0x4D, 0x4B, 0x1A, 0x78, 0x0E, 0x23, 0x00, 0x2A, 0x13, 0xD1, +0x73, 0xE2, 0x5F, 0x1C, 0x1A, 0x22, 0xBF, 0x01, 0x01, 0x3A, 0xD2, 0xB2, +0x91, 0x1C, 0x79, 0x18, 0x0D, 0x5D, 0x00, 0x2D, 0x02, 0xD0, 0x01, 0x25, +0x0D, 0x55, 0x02, 0xE0, 0x49, 0x00, 0x0E, 0x5A, 0x0D, 0x52, 0x00, 0x2A, +0xF0, 0xD1, 0x01, 0xE0, 0x41, 0x4C, 0x3D, 0x48, 0x01, 0x3B, 0xDB, 0xB2, +0xFF, 0x2B, 0xE6, 0xD1, 0x59, 0xE2, 0x3F, 0x4B, 0x34, 0x33, 0x1A, 0x78, +0x00, 0x2A, 0x00, 0xD0, 0x53, 0xE2, 0x01, 0x22, 0x1A, 0x70, 0x02, 0x20, +0xFF, 0xF7, 0x86, 0xFE, 0x4D, 0xE2, 0x2E, 0x4B, 0x2B, 0x4A, 0x99, 0x69, +0x01, 0x29, 0x73, 0xD0, 0x2C, 0x48, 0x04, 0x78, 0xFF, 0x20, 0x01, 0x2C, +0x00, 0xD0, 0x10, 0x20, 0x14, 0x89, 0x25, 0x1C, 0x0B, 0x3D, 0xAD, 0xB2, +0x09, 0x2D, 0x00, 0xD9, 0x82, 0xE0, 0x0C, 0x27, 0xD2, 0x5F, 0x05, 0x2A, +0x00, 0xDD, 0x7D, 0xE0, 0x2E, 0x4A, 0x24, 0xB2, 0x40, 0x32, 0x12, 0x78, +0xA2, 0x42, 0x77, 0xDA, 0x2C, 0x4A, 0x12, 0x68, 0x82, 0x42, 0x73, 0xDA, +0x00, 0x29, 0x03, 0xD1, 0x1C, 0x4B, 0x03, 0x22, 0x9A, 0x61, 0x6F, 0xE0, +0x03, 0x29, 0x6D, 0xD1, 0x15, 0x4A, 0x14, 0x4B, 0x99, 0x5C, 0xA0, 0x22, +0xD2, 0x00, 0x01, 0x29, 0x03, 0xD1, 0x99, 0x5C, 0x01, 0x31, 0x99, 0x54, +0x02, 0xE0, 0x99, 0x5C, 0x02, 0x31, 0x99, 0x54, 0x9A, 0x5C, 0x01, 0x2A, +0x5C, 0xD9, 0x11, 0x4A, 0x01, 0x21, 0x91, 0x61, 0xA0, 0x22, 0x00, 0x21, +0xD2, 0x00, 0x99, 0x54, 0x54, 0xE0, 0xC0, 0x46, 0xE5, 0x01, 0x00, 0x20, +0xAA, 0x0A, 0x00, 0x20, 0x28, 0x7C, 0x00, 0x00, 0x29, 0x7C, 0x00, 0x00, +0x2A, 0x7C, 0x00, 0x00, 0x2B, 0x7C, 0x00, 0x00, 0x48, 0x0D, 0x00, 0x20, +0x54, 0x00, 0x00, 0x20, 0xEC, 0x11, 0x00, 0x20, 0x0C, 0x05, 0x00, 0x00, +0x04, 0x05, 0x00, 0x00, 0x70, 0x01, 0x00, 0x20, 0x3D, 0x11, 0x00, 0x20, +0xF8, 0x08, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, 0x9A, 0x74, 0x00, 0x00, +0x4A, 0x74, 0x00, 0x00, 0x78, 0x09, 0x00, 0x20, 0x40, 0x00, 0x00, 0x20, +0x00, 0x40, 0x00, 0x40, 0x38, 0x0D, 0x00, 0x20, 0xE4, 0x10, 0x00, 0x20, +0xF5, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, 0xAE, 0x09, 0x00, 0x20, +0x9C, 0x0D, 0x00, 0x20, 0x4C, 0x11, 0x00, 0x20, 0x10, 0x89, 0xC7, 0x49, +0x04, 0x1C, 0x0A, 0x3C, 0xA4, 0xB2, 0x0A, 0x2C, 0x0B, 0xD8, 0x0C, 0x24, +0x12, 0x5F, 0x05, 0x2A, 0x07, 0xDC, 0x0A, 0x1C, 0x40, 0x32, 0x12, 0x78, +0x00, 0xB2, 0x82, 0x42, 0x01, 0xDA, 0x00, 0x22, 0xDA, 0x60, 0xDA, 0x68, +0x59, 0x2A, 0x05, 0xDC, 0x09, 0x68, 0x00, 0x29, 0x04, 0xD1, 0x01, 0x32, +0xDA, 0x60, 0x01, 0xE0, 0x00, 0x22, 0x9A, 0x61, 0xB9, 0x4B, 0x1A, 0x78, +0xB9, 0x4B, 0x00, 0x2A, 0x08, 0xD1, 0x99, 0x69, 0x01, 0x29, 0x05, 0xD1, +0xB7, 0x49, 0x08, 0x25, 0x49, 0x5F, 0x21, 0x29, 0x00, 0xDD, 0x9A, 0x61, +0x99, 0x69, 0xB5, 0x4B, 0x01, 0x29, 0x06, 0xD1, 0x3C, 0x22, 0xDA, 0x85, +0x0F, 0x22, 0xDA, 0x84, 0x0A, 0x22, 0x1A, 0x85, 0x0A, 0xE0, 0x2D, 0x20, +0xD8, 0x85, 0x28, 0x21, 0x00, 0x2A, 0x02, 0xD0, 0xD8, 0x84, 0x19, 0x85, +0x02, 0xE0, 0x23, 0x22, 0xD9, 0x84, 0x1A, 0x85, 0xA7, 0x4B, 0x19, 0x78, +0x00, 0x29, 0x68, 0xD1, 0xA4, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x64, 0xDD, +0xA6, 0x4A, 0xA4, 0x4B, 0x12, 0x7F, 0x18, 0x7D, 0x52, 0xB2, 0x02, 0x92, +0x1A, 0x69, 0x02, 0x38, 0x02, 0x3A, 0x02, 0x24, 0xC0, 0xB2, 0xD2, 0xB2, +0x64, 0x42, 0x0F, 0x1C, 0x0B, 0x1C, 0x04, 0x90, 0x21, 0xE0, 0x1E, 0x1C, +0x19, 0x22, 0x82, 0x42, 0x5E, 0x41, 0xF6, 0xB2, 0x00, 0x2E, 0x0F, 0xD0, +0x66, 0x46, 0x00, 0x2E, 0x0C, 0xD0, 0x03, 0x9A, 0x86, 0x1C, 0x96, 0x19, +0x98, 0x4A, 0x76, 0x00, 0xB6, 0x5A, 0x02, 0x9A, 0x96, 0x42, 0x03, 0xDB, +0xF7, 0x19, 0x01, 0x31, 0xBF, 0xB2, 0xC9, 0xB2, 0x01, 0x30, 0x01, 0x35, +0xC0, 0xB2, 0x03, 0x2D, 0xE3, 0xD1, 0x05, 0x9A, 0x01, 0x34, 0x01, 0x32, +0xD2, 0xB2, 0x03, 0x2C, 0x0D, 0xD0, 0x0D, 0x25, 0x18, 0x1C, 0x95, 0x42, +0x58, 0x41, 0x56, 0x1C, 0xC0, 0xB2, 0x02, 0x25, 0xB6, 0x01, 0x84, 0x46, +0x6D, 0x42, 0x04, 0x98, 0x03, 0x96, 0x05, 0x92, 0xCF, 0xE7, 0x85, 0x4B, +0x1E, 0x89, 0x83, 0x4B, 0x9C, 0x69, 0x00, 0x2C, 0x1D, 0xD1, 0xF5, 0x01, +0x7D, 0x19, 0x2D, 0xB2, 0x01, 0x31, 0x28, 0x1C, 0xFE, 0xF7, 0xFC, 0xFC, +0x81, 0x4B, 0x80, 0xB2, 0x27, 0x1C, 0x83, 0x42, 0x67, 0x41, 0xFB, 0xB2, +0x00, 0x2B, 0x0E, 0xD0, 0x7E, 0x4B, 0xEA, 0x0F, 0xAB, 0x42, 0x54, 0x41, +0xE4, 0xB2, 0x00, 0x2C, 0x07, 0xD0, 0x74, 0x4B, 0x36, 0xB2, 0x40, 0x33, +0x1B, 0x78, 0xB3, 0x42, 0x01, 0xDD, 0xFB, 0xF7, 0x29, 0xFB, 0x78, 0x4B, +0x0A, 0x24, 0x1A, 0x78, 0x6E, 0x4D, 0x53, 0x42, 0x5A, 0x41, 0x71, 0x4B, +0x52, 0x00, 0x32, 0x33, 0x1A, 0x70, 0x27, 0x1C, 0x01, 0x3C, 0xE4, 0xB2, +0x39, 0x1C, 0x61, 0x43, 0x6B, 0x18, 0x3C, 0x20, 0x1B, 0x5E, 0x00, 0x2B, +0x15, 0xD0, 0x63, 0x00, 0xEB, 0x18, 0x04, 0x22, 0x9B, 0x5E, 0x0C, 0x20, +0x08, 0x93, 0x23, 0x1C, 0x10, 0x33, 0x60, 0x43, 0x5B, 0x00, 0x5B, 0x5F, +0x41, 0x30, 0x09, 0x93, 0x68, 0x4B, 0xFF, 0x30, 0x69, 0x18, 0xC0, 0x18, +0x41, 0x31, 0x08, 0xAA, 0x23, 0x1C, 0xFE, 0xF7, 0x91, 0xFF, 0x3B, 0x1C, +0x63, 0x43, 0x5A, 0x4E, 0x5B, 0x4A, 0xF6, 0x18, 0x38, 0x36, 0x33, 0x7A, +0x10, 0x68, 0x58, 0x43, 0x60, 0x4B, 0x19, 0x68, 0xFE, 0xF7, 0xAE, 0xFC, +0x30, 0x72, 0x00, 0x2C, 0xD0, 0xD1, 0xEA, 0xE0, 0x53, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x00, 0xD0, 0xE5, 0xE0, 0x54, 0x4B, 0x58, 0x49, 0x32, 0x33, +0x18, 0x78, 0x50, 0x4B, 0x58, 0x4C, 0x9B, 0x69, 0x47, 0x1E, 0x02, 0x93, +0x0B, 0x5D, 0xBC, 0x46, 0x0A, 0x22, 0x01, 0x3A, 0xD2, 0xB2, 0x0C, 0x21, +0x51, 0x43, 0x51, 0x4C, 0x47, 0x4D, 0x61, 0x18, 0x0C, 0x1C, 0x05, 0x31, +0xFF, 0x31, 0x4E, 0x6C, 0x0A, 0x21, 0x51, 0x43, 0xFC, 0x34, 0x69, 0x18, +0xA7, 0x6C, 0x3C, 0x25, 0x4C, 0x5F, 0x38, 0x31, 0x00, 0x2C, 0x22, 0xD0, +0xBC, 0x1B, 0xE5, 0x17, 0x64, 0x19, 0x6C, 0x40, 0x49, 0x4D, 0xE4, 0xB2, +0xAD, 0x56, 0x65, 0x45, 0x0F, 0xD1, 0x11, 0x2C, 0x16, 0xD8, 0x02, 0x9C, +0x00, 0x2C, 0x14, 0xD0, 0x28, 0x2F, 0x11, 0xDC, 0x28, 0x2E, 0x0F, 0xDC, +0x06, 0x25, 0x4C, 0x5F, 0x09, 0x7A, 0x02, 0x34, 0x8C, 0x42, 0x0A, 0xDA, +0x08, 0xE0, 0x85, 0x42, 0x07, 0xDB, 0x00, 0x2B, 0x05, 0xD1, 0x14, 0x23, +0xA3, 0x42, 0x9B, 0x41, 0x5B, 0x42, 0x00, 0xE0, 0x01, 0x23, 0x00, 0x2A, +0xC5, 0xD1, 0x2D, 0x4C, 0x0A, 0x21, 0x01, 0x39, 0xC9, 0xB2, 0x00, 0x2B, +0x0D, 0xD0, 0x0A, 0x25, 0x4D, 0x43, 0x65, 0x19, 0x3E, 0x27, 0xEE, 0x5F, +0x00, 0x20, 0x02, 0x96, 0x02, 0x9F, 0x14, 0x25, 0xF6, 0x0F, 0xBD, 0x42, +0x46, 0x41, 0x75, 0x42, 0x2B, 0x40, 0x0A, 0x25, 0x4D, 0x43, 0x65, 0x19, +0x3C, 0x20, 0x2D, 0x5E, 0x00, 0x2D, 0x01, 0xD0, 0x01, 0x32, 0xD2, 0xB2, +0x00, 0x29, 0xE2, 0xD1, 0x26, 0x49, 0x28, 0x4C, 0x0B, 0x55, 0x00, 0x2A, +0x7B, 0xD1, 0x27, 0x48, 0x0A, 0x23, 0x01, 0x3B, 0xDB, 0xB2, 0xC2, 0x54, +0x00, 0x2B, 0xFA, 0xD1, 0x22, 0x4D, 0x4B, 0x55, 0x71, 0xE0, 0x18, 0x4B, +0x9A, 0x69, 0x00, 0x2A, 0x10, 0xD0, 0x21, 0x4A, 0x12, 0x68, 0x00, 0x2A, +0x0C, 0xDD, 0x12, 0x4A, 0x12, 0x68, 0x01, 0x2A, 0x08, 0xD1, 0x1E, 0x4A, +0x12, 0x78, 0x00, 0x2A, 0x04, 0xD0, 0x1D, 0x4A, 0x12, 0x68, 0x00, 0x2A, +0x00, 0xD1, 0x9A, 0x61, 0x9A, 0x69, 0x00, 0x2A, 0x04, 0xD1, 0xA0, 0x21, +0x12, 0x48, 0xC9, 0x00, 0x42, 0x54, 0xDA, 0x60, 0x9A, 0x68, 0x01, 0x2A, +0x51, 0xD1, 0x00, 0x22, 0x9A, 0x60, 0x5B, 0x68, 0x01, 0x2B, 0x2B, 0xD1, +0x04, 0x4A, 0x13, 0x70, 0x12, 0x4A, 0x34, 0x32, 0x13, 0x70, 0x12, 0x4A, +0x13, 0x70, 0x44, 0xE0, 0x9C, 0x0D, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, +0xF8, 0x08, 0x00, 0x20, 0x70, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, +0x00, 0x40, 0x00, 0x40, 0x8F, 0x01, 0x00, 0x00, 0x5F, 0x09, 0x00, 0x00, +0xF5, 0x00, 0x00, 0x20, 0xEC, 0x11, 0x00, 0x20, 0x4C, 0x11, 0x00, 0x20, +0x04, 0x05, 0x00, 0x00, 0x3E, 0x11, 0x00, 0x20, 0x20, 0x01, 0x00, 0x20, +0x48, 0x11, 0x00, 0x20, 0xBC, 0x11, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0xB3, 0x01, 0x00, 0x20, 0x00, 0x2B, 0x1E, 0xD1, 0x10, 0x4A, 0x13, 0x70, +0x10, 0x4A, 0x34, 0x32, 0x13, 0x70, 0x10, 0x4B, 0x02, 0x22, 0x1A, 0x70, +0x15, 0xE0, 0x0F, 0x4B, 0x04, 0x22, 0x9A, 0x70, 0x87, 0x22, 0x52, 0x00, +0x9A, 0x80, 0x40, 0x22, 0x9A, 0x71, 0x06, 0x22, 0xDA, 0x71, 0x01, 0x22, +0x1A, 0x72, 0x03, 0x22, 0x5A, 0x72, 0x00, 0x22, 0x1A, 0x70, 0x04, 0xE0, +0x06, 0x48, 0x07, 0x49, 0x50, 0x22, 0xFE, 0xF7, 0x21, 0xFC, 0x0B, 0xB0, +0xF0, 0xBD, 0xC0, 0x46, 0xDD, 0x01, 0x00, 0x20, 0xAE, 0x09, 0x00, 0x20, +0xB3, 0x01, 0x00, 0x20, 0x48, 0x0D, 0x00, 0x20, 0x4A, 0x74, 0x00, 0x00, +0x38, 0xB5, 0x50, 0x28, 0x05, 0xD1, 0x3B, 0x4B, 0x01, 0x20, 0x18, 0x60, +0xFE, 0xF7, 0xE6, 0xFD, 0x6F, 0xE0, 0x39, 0x4B, 0x40, 0x28, 0x01, 0xD1, +0x01, 0x24, 0x1C, 0x70, 0x1B, 0x78, 0x00, 0x2B, 0x67, 0xD0, 0x41, 0x38, +0x0E, 0x28, 0x64, 0xD8, 0xFE, 0xF7, 0x3A, 0xFB, 0x08, 0x12, 0x08, 0x2D, +0x08, 0x47, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x5E, 0x00, +0x2F, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x2F, 0x4B, 0x1A, 0x80, 0x2F, 0x4A, +0x13, 0x60, 0xFC, 0xF7, 0x21, 0xFA, 0x50, 0xE0, 0x2A, 0x48, 0x2C, 0x4B, +0xFF, 0x2A, 0x0B, 0xD1, 0x2B, 0x4A, 0xC9, 0x01, 0x12, 0x78, 0x52, 0x00, +0xD2, 0xB2, 0x02, 0x70, 0x29, 0x4A, 0x89, 0x18, 0x19, 0x60, 0xFC, 0xF7, +0x11, 0xFA, 0x40, 0xE0, 0x89, 0x01, 0x8A, 0x18, 0x25, 0x49, 0x52, 0x00, +0x02, 0x24, 0x52, 0x18, 0x04, 0x70, 0x1A, 0x60, 0xFC, 0xF7, 0x06, 0xFA, +0x35, 0xE0, 0x1D, 0x4C, 0x1E, 0x4B, 0x21, 0x48, 0xFF, 0x2A, 0x0A, 0xD1, +0x1D, 0x4A, 0x89, 0x01, 0x12, 0x78, 0x40, 0x18, 0x52, 0x00, 0xD2, 0xB2, +0x22, 0x70, 0x18, 0x60, 0xFC, 0xF7, 0xF6, 0xF9, 0x25, 0xE0, 0x49, 0x01, +0x52, 0x18, 0x52, 0x00, 0x02, 0x25, 0x80, 0x18, 0x25, 0x70, 0x18, 0x60, +0xFC, 0xF7, 0xEC, 0xF9, 0x1B, 0xE0, 0x10, 0x4C, 0x11, 0x4B, 0x15, 0x48, +0xFF, 0x2A, 0x08, 0xD1, 0x10, 0x4A, 0x49, 0x01, 0x92, 0x78, 0x40, 0x18, +0x22, 0x70, 0x18, 0x60, 0xFC, 0xF7, 0xDE, 0xF9, 0x0D, 0xE0, 0x49, 0x01, +0x52, 0x18, 0x01, 0x25, 0x80, 0x18, 0x25, 0x70, 0x18, 0x60, 0xFC, 0xF7, +0xD5, 0xF9, 0x04, 0xE0, 0x0B, 0x4A, 0x00, 0x23, 0x13, 0x70, 0x02, 0x4A, +0x13, 0x70, 0x38, 0xBD, 0x50, 0x11, 0x00, 0x20, 0xE5, 0x01, 0x00, 0x20, +0xF6, 0x03, 0x00, 0x20, 0x08, 0x03, 0x00, 0x20, 0x34, 0x0D, 0x00, 0x20, +0x0A, 0x03, 0x00, 0x20, 0x84, 0x40, 0x00, 0x40, 0xF8, 0x03, 0x00, 0x20, +0xB3, 0x0A, 0x00, 0x20, 0x1D, 0x03, 0x00, 0x20, 0x08, 0xB5, 0x35, 0x4B, +0x1B, 0x88, 0x33, 0x2B, 0x29, 0xD0, 0x06, 0xD8, 0x0A, 0x2B, 0x2F, 0xD0, +0x30, 0x2B, 0x11, 0xD0, 0x01, 0x2B, 0x5D, 0xD1, 0x06, 0xE0, 0xA0, 0x2B, +0x32, 0xD0, 0xB0, 0x2B, 0x4C, 0xD0, 0x5F, 0x2B, 0x56, 0xD1, 0x3F, 0xE0, +0x2C, 0x4A, 0x11, 0x78, 0x0E, 0x22, 0x11, 0x42, 0x50, 0xD1, 0x2B, 0x4A, +0x13, 0x70, 0x4D, 0xE0, 0x28, 0x4B, 0x2A, 0x4A, 0x1B, 0x78, 0x12, 0x78, +0x01, 0x2B, 0x05, 0xD1, 0x00, 0x2A, 0x45, 0xD1, 0x27, 0x4A, 0x53, 0x60, +0x93, 0x60, 0x41, 0xE0, 0x01, 0x2A, 0x3F, 0xD1, 0x24, 0x4B, 0x00, 0x21, +0x59, 0x60, 0x9A, 0x60, 0x3A, 0xE0, 0x1F, 0x4B, 0x22, 0x4A, 0x19, 0x78, +0x22, 0x4B, 0x01, 0x29, 0x00, 0xD0, 0x00, 0x21, 0xD1, 0x54, 0x31, 0xE0, +0x20, 0x4B, 0x1A, 0x78, 0x00, 0x2A, 0x02, 0xD1, 0x01, 0x22, 0x1A, 0x70, +0x2A, 0xE0, 0x00, 0x22, 0x1A, 0x70, 0x27, 0xE0, 0x15, 0x4B, 0x1C, 0x4A, +0x18, 0x78, 0x1C, 0x4B, 0x1A, 0x28, 0x06, 0xD1, 0x19, 0x78, 0x1B, 0x4B, +0x10, 0x78, 0x1A, 0x78, 0xFF, 0xF7, 0xDA, 0xF9, 0x1A, 0xE0, 0x11, 0x78, +0x1A, 0x78, 0xFF, 0xF7, 0x1F, 0xFF, 0x15, 0xE0, 0x0C, 0x4B, 0x1B, 0x78, +0x00, 0x2B, 0x11, 0xD0, 0x14, 0x4B, 0x08, 0x22, 0x1A, 0x60, 0xFA, 0xF7, +0xD7, 0xFB, 0x0B, 0xE0, 0x07, 0x4B, 0x1B, 0x78, 0x1A, 0x2B, 0x07, 0xD1, +0x0C, 0x4B, 0x18, 0x78, 0x0C, 0x4B, 0x19, 0x78, 0x0C, 0x4B, 0x1A, 0x78, +0xFF, 0xF7, 0xBE, 0xF9, 0x08, 0xBD, 0xC0, 0x46, 0x28, 0x00, 0x00, 0x20, +0x0C, 0x00, 0x00, 0x50, 0xE8, 0x01, 0x00, 0x20, 0xDD, 0x01, 0x00, 0x20, +0xF8, 0x08, 0x00, 0x20, 0xEC, 0x11, 0x00, 0x20, 0x0C, 0x05, 0x00, 0x00, +0xDF, 0x01, 0x00, 0x20, 0x0E, 0x00, 0x00, 0x50, 0x0D, 0x00, 0x00, 0x50, +0x10, 0x00, 0x00, 0x50, 0x50, 0x11, 0x00, 0x20, 0x00, 0x01, 0x02, 0x03, +0x04, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0B, 0x0C, 0x0D, +0x0E, 0x0F, 0x10, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17, +0x18, 0x18, 0x19, 0x1A, 0x1B, 0x1B, 0x1C, 0x1D, 0x1D, 0x1E, 0x1F, 0x1F, +0x20, 0x21, 0x21, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x27, +0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, +0x00, 0x00, 0x78, 0x04, 0xEF, 0x08, 0x66, 0x0D, 0xDB, 0x11, 0x50, 0x16, +0xC2, 0x1A, 0x33, 0x1F, 0xA1, 0x23, 0x0C, 0x28, 0x74, 0x2C, 0xD9, 0x30, +0x39, 0x35, 0x96, 0x39, 0xEE, 0x3D, 0x42, 0x42, 0x90, 0x46, 0xD9, 0x4A, +0x1B, 0x4F, 0x58, 0x53, 0x8E, 0x57, 0xBE, 0x5B, 0xE6, 0x5F, 0x07, 0x64, +0x1F, 0x68, 0x30, 0x6C, 0x39, 0x70, 0x38, 0x74, 0x2F, 0x78, 0x1C, 0x7C, +0xFF, 0x7F, 0xD9, 0x83, 0xA8, 0x87, 0x6D, 0x8B, 0x27, 0x8F, 0xD5, 0x92, +0x79, 0x96, 0x10, 0x9A, 0x9B, 0x9D, 0x1B, 0xA1, 0x8D, 0xA4, 0xF3, 0xA7, +0x4B, 0xAB, 0x97, 0xAE, 0xD4, 0xB1, 0x04, 0xB5, 0x26, 0xB8, 0x39, 0xBB, +0x3E, 0xBE, 0x34, 0xC1, 0x1B, 0xC4, 0xF2, 0xC6, 0xBA, 0xC9, 0x73, 0xCC, +0x1B, 0xCF, 0xB3, 0xD1, 0x3B, 0xD4, 0xB2, 0xD6, 0x19, 0xD9, 0x6E, 0xDB, +0xB3, 0xDD, 0xE6, 0xDF, 0x08, 0xE2, 0x18, 0xE4, 0x16, 0xE6, 0x03, 0xE8, +0xDD, 0xE9, 0xA5, 0xEB, 0x5B, 0xED, 0xFE, 0xEE, 0x8F, 0xF0, 0x0D, 0xF2, +0x77, 0xF3, 0xCF, 0xF4, 0x14, 0xF6, 0x46, 0xF7, 0x64, 0xF8, 0x6F, 0xF9, +0x67, 0xFA, 0x4B, 0xFB, 0x1B, 0xFC, 0xD8, 0xFC, 0x81, 0xFD, 0x17, 0xFE, +0x98, 0xFE, 0x06, 0xFF, 0x5F, 0xFF, 0xA5, 0xFF, 0xD7, 0xFF, 0xF5, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x20, 0x4D, 0x31, 0x48, 0x30, +0x50, 0x42, 0x34, 0x35, 0x25, 0x44, 0x01, 0x34, 0x38, 0x30, 0x47, 0x59, +0x30, 0x31, 0x00, 0x00, 0x00, 0x48, 0x10, 0x5A, 0x28, 0x1E, 0x01, 0x01, +0x00, 0x00, 0x00, 0x1A, 0x0E, 0x00, 0x00, 0x1A, 0x0E, 0x00, 0x00, 0x00, +0x01, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0xD0, 0x02, 0x00, 0x00, +0x00, 0x01, 0x01, 0x50, 0x50, 0x50, 0x01, 0x01, 0x00, 0x00, 0x62, 0x00, +0x4B, 0x00, 0x23, 0x00, 0x04, 0x03, 0x32, 0x32, 0x10, 0x00, 0x01, 0x01, +0x04, 0x00, 0x08, 0x02, 0x18, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x04, +0x05, 0x0F, 0x00, 0x07, 0x05, 0x00, 0xC0, 0xF9, 0x14, 0x1E, 0x0A, 0xF6, +0x0F, 0x00, 0x05, 0x14, 0x1E, 0x00, 0xA2, 0x29, 0xDE, 0x01, 0x00, 0x00, +0x28, 0x00, 0x23, 0x00, 0x0F, 0x0A, 0x3C, 0x01, 0x2D, 0x00, 0x00, 0x00, +0x02, 0x01, 0x01, 0x14, 0x32, 0x00, 0x32, 0x00, 0xFF, 0x7F, 0x00, 0x01, +0x01, 0x07, 0x0B, 0x00, 0x32, 0x00, 0x0A, 0x05, 0xD0, 0x03, 0xB3, 0x00, +0xFF, 0x7F, 0x00, 0x80, 0x01, 0x00, 0x01, 0x01, 0x04, 0x00, 0x08, 0x02, +0x30, 0x04, 0x03, 0x03, 0x00, 0x00, 0x00, 0x04, 0x05, 0x0F, 0x00, 0x08, +0x06, 0x00, 0xC0, 0xF9, 0x14, 0x1E, 0x0A, 0xF6, 0x19, 0x00, 0x08, 0x23, +0x1E, 0x00, 0xA2, 0x29, 0xDE, 0x01, 0x00, 0x00, 0x2D, 0x00, 0x28, 0x00, +0x0F, 0x0A, 0x3C, 0x01, 0x2D, 0x00, 0x1E, 0x00, 0x02, 0x01, 0x01, 0x14, +0x96, 0x00, 0x32, 0x00, 0xFF, 0x7F, 0x01, 0x01, 0x01, 0x07, 0x0A, 0x00, +0x32, 0x00, 0x0A, 0x05, 0xD0, 0x03, 0xB3, 0x00, 0xFF, 0x7F, 0x00, 0x80, +0x19, 0x00, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x15, 0x14, 0x13, +0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x06, 0x05, 0x04, +0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x08, +0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, +0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, +0x02, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, +0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, +0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, +0x03, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, +0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, +0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x01, 0x02, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, +0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x4E, +0x4E, 0x4E, 0x4D, 0x4D, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4A, 0x4B, 0x4B, +0x4A, 0x47, 0x4A, 0x48, 0x47, 0x47, 0x47, 0x47, 0x45, 0x45, 0x48, 0x4B, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x47, 0x48, 0x45, 0x47, 0x45, +0x45, 0x45, 0x45, 0x45, 0x43, 0x43, 0x45, 0x46, 0x46, 0x43, 0x41, 0x42, +0x42, 0x41, 0x41, 0x41, 0x3E, 0x40, 0x42, 0x48, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x52, 0x48, 0x47, 0x48, 0x48, 0x47, 0x46, 0x48, 0x47, 0x46, +0x48, 0x45, 0x45, 0x43, 0x42, 0x43, 0x42, 0x41, 0x42, 0x45, 0x43, 0x42, +0x42, 0x43, 0x41, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4A, +0x4A, 0x48, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x45, 0x43, +0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x45, 0x41, 0x4A, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x4D, 0x4B, 0x4A, 0x4B, 0x4A, +0x48, 0x47, 0x48, 0x48, 0x46, 0x47, 0x48, 0x4A, 0x47, 0x42, 0x45, 0x46, +0x42, 0x46, 0x45, 0x43, 0x45, 0x45, 0x46, 0x4B, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x55, 0x4E, 0x4B, 0x4B, 0x4B, 0x4A, 0x48, 0x4A, 0x47, 0x47, +0x48, 0x48, 0x48, 0x46, 0x43, 0x45, 0x46, 0x43, 0x45, 0x46, 0x42, 0x43, +0x45, 0x46, 0x46, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x4E, +0x4D, 0x4B, 0x48, 0x4A, 0x4A, 0x4A, 0x48, 0x4A, 0x4A, 0x4A, 0x4A, 0x45, +0x46, 0x45, 0x46, 0x46, 0x45, 0x46, 0x43, 0x46, 0x45, 0x46, 0x46, 0x4D, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x50, 0x4D, 0x4D, 0x47, 0x48, +0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x45, 0x46, 0x46, 0x45, +0x43, 0x45, 0x45, 0x43, 0x46, 0x46, 0x46, 0x4B, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x52, 0x4D, 0x4A, 0x4A, 0x48, 0x4A, 0x47, 0x46, 0x48, 0x48, +0x48, 0x47, 0x45, 0x45, 0x46, 0x45, 0x46, 0x45, 0x41, 0x43, 0x43, 0x45, +0x41, 0x46, 0x47, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x4D, +0x4B, 0x4A, 0x47, 0x48, 0x46, 0x46, 0x46, 0x46, 0x46, 0x45, 0x45, 0x45, +0x46, 0x46, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x43, 0x45, 0x45, 0x4B, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4B, 0x4A, 0x48, 0x48, 0x46, +0x45, 0x45, 0x46, 0x47, 0x46, 0x45, 0x43, 0x42, 0x42, 0x41, 0x41, 0x40, +0x41, 0x41, 0x40, 0x42, 0x41, 0x42, 0x43, 0x48, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x50, 0x4B, 0x48, 0x48, 0x47, 0x47, 0x45, 0x46, 0x43, 0x45, +0x45, 0x43, 0x41, 0x3F, 0x3F, 0x41, 0x40, 0x40, 0x40, 0x42, 0x3F, 0x42, +0x42, 0x40, 0x42, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x4B, +0x4A, 0x47, 0x45, 0x45, 0x43, 0x46, 0x45, 0x45, 0x45, 0x42, 0x42, 0x41, +0x3E, 0x42, 0x41, 0x41, 0x41, 0x40, 0x3E, 0x40, 0x41, 0x40, 0x40, 0x43, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x4B, 0x4D, 0x4D, 0x4B, 0x4A, +0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x48, 0x48, 0x47, 0x45, 0x45, 0x46, 0x45, +0x45, 0x46, 0x43, 0x46, 0x46, 0x46, 0x46, 0x4A, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x45, 0x20, +}; + + diff --git a/drivers/input/touchscreen/mms_ts_136.c b/drivers/input/touchscreen/mms_ts_136.c new file mode 100644 index 00000000000..c14fae16fab --- /dev/null +++ b/drivers/input/touchscreen/mms_ts_136.c @@ -0,0 +1,2776 @@ +/* + * mms_ts.c - Touchscreen driver for Melfas MMS-series touch controllers + * + * Copyright (C) 2011 Google Inc. + * Author: Dima Zavin + * Simon Wilson + * + * ISP reflashing code based on original code from Melfas. + * + * 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. + * + */ + +#define DEBUG +/* #define VERBOSE_DEBUG */ +/* #define SEC_TSP_DEBUG */ +#define SEC_TSP_VERBOSE_DEBUG + +/* #define FORCE_FW_FLASH */ +/* #define FORCE_FW_PASS */ +/* #define ESD_DEBUG */ + +#define SEC_TSP_FACTORY_TEST +#define SEC_TSP_FW_UPDATE +#define TSP_BUF_SIZE 1024 +#define FAIL -1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "mms_ts_fw.h" + +#define MAX_FINGERS 10 +#define MAX_WIDTH 30 +#define MAX_PRESSURE 255 + +/* Registers */ +#define MMS_MODE_CONTROL 0x01 +#define MMS_XYRES_HI 0x02 +#define MMS_XRES_LO 0x03 +#define MMS_YRES_LO 0x04 + +#define MMS_INPUT_EVENT_PKT_SZ 0x0F +#define MMS_INPUT_EVENT0 0x10 +#define FINGER_EVENT_SZ 6 + +#define MMS_TSP_REVISION 0xF0 +#define MMS_HW_REVISION 0xF1 +#define MMS_COMPAT_GROUP 0xF2 +#define MMS_FW_VERSION 0xF5 + +enum { + ISP_MODE_FLASH_ERASE = 0x59F3, + ISP_MODE_FLASH_WRITE = 0x62CD, + ISP_MODE_FLASH_READ = 0x6AC9, +}; + +/* each address addresses 4-byte words */ +#define ISP_MAX_FW_SIZE (0x1F00 * 4) +#define ISP_IC_INFO_ADDR 0x1F00 + +#ifdef CONFIG_SEC_DVFS +#define TOUCH_BOOSTER 1 +#define TOUCH_BOOSTER_OFF_TIME 100 +#define TOUCH_BOOSTER_CHG_TIME 200 +#endif + +#ifdef SEC_TSP_FW_UPDATE + +#define WORD_SIZE 4 + +#define ISC_PKT_SIZE 1029 +#define ISC_PKT_DATA_SIZE 1024 +#define ISC_PKT_HEADER_SIZE 3 +#define ISC_PKT_NUM 31 + +#define ISC_ENTER_ISC_CMD 0x5F +#define ISC_ENTER_ISC_DATA 0x01 +#define ISC_CMD 0xAE +#define ISC_ENTER_UPDATE_DATA 0x55 +#define ISC_ENTER_UPDATE_DATA_LEN 9 +#define ISC_DATA_WRITE_SUB_CMD 0xF1 +#define ISC_EXIT_ISC_SUB_CMD 0x0F +#define ISC_EXIT_ISC_SUB_CMD2 0xF0 +#define ISC_CHECK_STATUS_CMD 0xAF +#define ISC_CONFIRM_CRC 0x03 +#define ISC_DEFAULT_CRC 0xFFFF + +#endif + +#ifdef SEC_TSP_FACTORY_TEST +#define TX_NUM 20 +#define RX_NUM 12 +#define NODE_NUM 240 /* 20x12 */ + +/* VSC(Vender Specific Command) */ +#define MMS_VSC_CMD 0xB0 /* vendor specific command */ +#define MMS_VSC_MODE 0x1A /* mode of vendor */ + +#define MMS_VSC_CMD_ENTER 0X01 +#define MMS_VSC_CMD_CM_DELTA 0X02 +#define MMS_VSC_CMD_CM_ABS 0X03 +#define MMS_VSC_CMD_EXIT 0X05 +#define MMS_VSC_CMD_INTENSITY 0X04 +#define MMS_VSC_CMD_RAW 0X06 +#define MMS_VSC_CMD_REFER 0X07 +#define VSC_INTENSITY_TK 0x14 +#define VSC_RAW_TK 0x16 +#define VSC_THRESHOLD_TK 0x18 + + +#define TSP_CMD_STR_LEN 32 +#define TSP_CMD_RESULT_STR_LEN 512 +#define TSP_CMD_PARAM_NUM 8 +#endif /* SEC_TSP_FACTORY_TEST */ + +int touch_is_pressed; +EXPORT_SYMBOL(touch_is_pressed); + +enum fw_flash_mode { + ISP_FLASH, + ISC_FLASH, +}; + +#define NUM_OF_KEY 4 + +enum { + BUILT_IN = 0, + UMS, +}; + +struct mms_ts_info { + struct i2c_client *client; + struct input_dev *input_dev; + char phys[32]; + + int max_x; + int max_y; + + bool invert_x; + bool invert_y; + const u8 *config_fw_version; + int irq; + + struct mms_ts_platform_data *pdata; + + char *fw_name; + struct early_suspend early_suspend; +#if TOUCH_BOOSTER + struct delayed_work work_dvfs_off; + struct delayed_work work_dvfs_chg; + bool dvfs_lock_status; + struct mutex dvfs_lock; +#endif + + /* protects the enabled flag */ + struct mutex lock; + bool enabled; + +#ifdef SEC_TKEY_FACTORY_TEST + struct device *dev_tk; + bool *key_pressed; +#endif + enum fw_flash_mode fw_flash_mode; + bool use_touchkey; + unsigned char keycode[NUM_OF_KEY]; + + void (*register_cb)(void *); + struct tsp_callbacks callbacks; + bool ta_status; + bool noise_mode; + +#if defined(SEC_TSP_DEBUG) || defined(SEC_TSP_VERBOSE_DEBUG) + unsigned char finger_state[MAX_FINGERS]; +#endif + +#if defined(SEC_TSP_FW_UPDATE) + u8 fw_update_state; +#endif + u8 fw_ic_ver; + +#if defined(SEC_TSP_FACTORY_TEST) + struct list_head cmd_list_head; + u8 cmd_state; + char cmd[TSP_CMD_STR_LEN]; + int cmd_param[TSP_CMD_PARAM_NUM]; + char cmd_result[TSP_CMD_RESULT_STR_LEN]; + struct mutex cmd_lock; + bool cmd_is_running; + + unsigned int reference[NODE_NUM]; + unsigned int raw[NODE_NUM]; /* CM_ABS */ + unsigned int inspection[NODE_NUM];/* CM_DELTA */ + unsigned int intensity[NODE_NUM]; + bool ft_flag; +#endif /* SEC_TSP_FACTORY_TEST */ +}; + +struct mms_fw_image { + __le32 hdr_len; + __le32 data_len; + __le32 fw_ver; + __le32 hdr_ver; + u8 data[0]; +} __packed; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mms_ts_early_suspend(struct early_suspend *h); +static void mms_ts_late_resume(struct early_suspend *h); +#endif + +#if defined(SEC_TSP_FACTORY_TEST) +#define TSP_CMD(name, func) .cmd_name = name, .cmd_func = func + +struct tsp_cmd { + struct list_head list; + const char *cmd_name; + void (*cmd_func)(void *device_data); +}; + +static void fw_update(void *device_data); +static void get_fw_ver_bin(void *device_data); +static void get_fw_ver_ic(void *device_data); +static void get_config_ver(void *device_data); +static void get_threshold(void *device_data); +static void module_off_master(void *device_data); +static void module_on_master(void *device_data); +static void get_chip_vendor(void *device_data); +static void get_chip_name(void *device_data); +static void get_reference(void *device_data); +static void get_cm_abs(void *device_data); +static void get_cm_delta(void *device_data); +static void get_intensity(void *device_data); +static void get_x_num(void *device_data); +static void get_y_num(void *device_data); +static void run_reference_read(void *device_data); +static void run_cm_abs_read(void *device_data); +static void run_cm_delta_read(void *device_data); +static void run_intensity_read(void *device_data); +static void not_support_cmd(void *device_data); + +struct tsp_cmd tsp_cmds[] = { + {TSP_CMD("fw_update", fw_update),}, + {TSP_CMD("get_fw_ver_bin", get_fw_ver_bin),}, + {TSP_CMD("get_fw_ver_ic", get_fw_ver_ic),}, + {TSP_CMD("get_config_ver", get_config_ver),}, + {TSP_CMD("get_threshold", get_threshold),}, + {TSP_CMD("module_off_master", module_off_master),}, + {TSP_CMD("module_on_master", module_on_master),}, + {TSP_CMD("module_off_slave", not_support_cmd),}, + {TSP_CMD("module_on_slave", not_support_cmd),}, + {TSP_CMD("get_chip_vendor", get_chip_vendor),}, + {TSP_CMD("get_chip_name", get_chip_name),}, + {TSP_CMD("get_x_num", get_x_num),}, + {TSP_CMD("get_y_num", get_y_num),}, + {TSP_CMD("get_reference", get_reference),}, + {TSP_CMD("get_cm_abs", get_cm_abs),}, + {TSP_CMD("get_cm_delta", get_cm_delta),}, + {TSP_CMD("get_intensity", get_intensity),}, + {TSP_CMD("run_reference_read", run_reference_read),}, + {TSP_CMD("run_cm_abs_read", run_cm_abs_read),}, + {TSP_CMD("run_cm_delta_read", run_cm_delta_read),}, + {TSP_CMD("run_intensity_read", run_intensity_read),}, + {TSP_CMD("not_support_cmd", not_support_cmd),}, +}; +#endif + +#if TOUCH_BOOSTER +static void change_dvfs_lock(struct work_struct *work) +{ + struct mms_ts_info *info = container_of(work, + struct mms_ts_info, work_dvfs_chg.work); + int ret; + + mutex_lock(&info->dvfs_lock); + ret = cpufreq_set_limit(TOUCH_BOOSTER_FIRST_STOP, 0); + mutex_unlock(&info->dvfs_lock); + + if (ret < 0) + pr_err("%s: 1booster stop failed(%d)\n",\ + __func__, __LINE__); + else + pr_info("[TSP] %s", __func__); +} + +static void set_dvfs_off(struct work_struct *work) +{ + struct mms_ts_info *info = container_of(work, + struct mms_ts_info, work_dvfs_off.work); + mutex_lock(&info->dvfs_lock); + cpufreq_set_limit(TOUCH_BOOSTER_FIRST_STOP, 0); + cpufreq_set_limit(TOUCH_BOOSTER_SECOND_STOP, 0); + info->dvfs_lock_status = false; + mutex_unlock(&info->dvfs_lock); + + pr_info("[TSP] DVFS Off!"); +} + +static void set_dvfs_lock(struct mms_ts_info *info, uint32_t on) +{ + int ret = 0, ret2 = 0; + + mutex_lock(&info->dvfs_lock); + if (on == 0) { + if (info->dvfs_lock_status) { + cancel_delayed_work(&info->work_dvfs_chg); + schedule_delayed_work(&info->work_dvfs_off, + msecs_to_jiffies(TOUCH_BOOSTER_OFF_TIME)); + } + } else if (on == 1) { + cancel_delayed_work(&info->work_dvfs_off); + if (!info->dvfs_lock_status) { + ret = cpufreq_set_limit(TOUCH_BOOSTER_SECOND_START, 0); + ret2 = cpufreq_set_limit(TOUCH_BOOSTER_FIRST_START, 0); + if (ret < 0 || ret2 < 0) + pr_err("%s: cpu lock failed(%d, %d)\n",\ + __func__, ret, ret2); + + schedule_delayed_work(&info->work_dvfs_chg, + msecs_to_jiffies(TOUCH_BOOSTER_CHG_TIME)); + info->dvfs_lock_status = true; + pr_info("[TSP] DVFS On!"); + } + } else if (on == 2) { + cancel_delayed_work(&info->work_dvfs_off); + cancel_delayed_work(&info->work_dvfs_chg); + schedule_work(&info->work_dvfs_off.work); + } + mutex_unlock(&info->dvfs_lock); +} +#endif + +static void release_all_fingers(struct mms_ts_info *info) +{ +#ifdef SEC_TSP_DEBUG + struct i2c_client *client = info->client; +#endif + int i; + + printk(KERN_DEBUG "[TSP] %s\n", __func__); + + for (i = 0; i < MAX_FINGERS; i++) { +#ifdef SEC_TSP_DEBUG + if (info->finger_state[i] == 1) { + dev_notice(&client->dev, "finger %d up(force)\n", i); + } +#endif + info->finger_state[i] = 0; + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, + false); + } + input_sync(info->input_dev); +#if TOUCH_BOOSTER + set_dvfs_lock(info, 2); + pr_info("[TSP] dvfs_lock free.\n "); +#endif +} + +static inline void mms_pwr_on_reset(struct mms_ts_info *info); + +static void reset_mms_ts(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + + if (info->enabled == false) + return; + + dev_notice(&client->dev, "%s++\n", __func__); + disable_irq_nosync(info->irq); + info->enabled = false; + touch_is_pressed = 0; + + release_all_fingers(info); + + mms_pwr_on_reset(info); + enable_irq(info->irq); + info->enabled = true; + + dev_notice(&client->dev, "%s--\n", __func__); + +} + +static void mms_set_noise_mode(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + + if (!info->noise_mode) + return; + dev_notice(&client->dev, "%s\n", __func__); + + if (info->ta_status) { + dev_notice(&client->dev, "TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x30, 0x1); + } else { + dev_notice(&client->dev, "TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x30, 0x2); + info->noise_mode = 0; + } +} + +static void melfas_ta_cb(struct tsp_callbacks *cb, bool ta_status) +{ + struct mms_ts_info *info = + container_of(cb, struct mms_ts_info, callbacks); + struct i2c_client *client = info->client; + + dev_notice(&client->dev, "%s\n", __func__); + + info->ta_status = ta_status; + if (!ta_status) + mms_set_noise_mode(info); +} + +static irqreturn_t mms_ts_interrupt(int irq, void *dev_id) +{ + struct mms_ts_info *info = dev_id; + struct i2c_client *client = info->client; + u8 buf[MAX_FINGERS*FINGER_EVENT_SZ] = { 0 }; + int ret; + int i; + int sz; + u8 reg = MMS_INPUT_EVENT0; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .buf = ®, + .len = 1, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = buf, + }, + }; + + sz = i2c_smbus_read_byte_data(client, MMS_INPUT_EVENT_PKT_SZ); + if (sz < 0) { + dev_err(&client->dev, "%s bytes=%d\n", __func__, sz); + for (i = 0; i < 50; i++) { + sz = i2c_smbus_read_byte_data(client, + MMS_INPUT_EVENT_PKT_SZ); + if (sz > 0) + break; + } + + if (i == 50) { + dev_dbg(&client->dev, "i2c failed... reset!!\n"); + reset_mms_ts(info); + goto out; + } + } + /* BUG_ON(sz > MAX_FINGERS*FINGER_EVENT_SZ); */ + if (sz == 0) + goto out; + + if (sz > MAX_FINGERS*FINGER_EVENT_SZ) { + dev_err(&client->dev, "[TSP] abnormal data inputed.\n"); + goto out; + } + + msg[1].len = sz; + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(&client->dev, + "failed to read %d bytes of touch data (%d)\n", + sz, ret); + goto out; + } + +#if defined(VERBOSE_DEBUG) + print_hex_dump(KERN_DEBUG, "mms_ts raw: ", + DUMP_PREFIX_OFFSET, 32, 1, buf, sz, false); + +#endif + if (buf[0] == 0x0F) { /* ESD */ + dev_dbg(&client->dev, "ESD DETECT.... reset!!\n"); + reset_mms_ts(info); + goto out; + } + + if (buf[0] == 0x0E) { /* NOISE MODE */ + dev_dbg(&client->dev, "[TSP] noise mode enter!!\n"); + info->noise_mode = 1 ; + mms_set_noise_mode(info); + goto out; + } + + for (i = 0; i < sz; i += FINGER_EVENT_SZ) { + u8 *tmp = &buf[i]; + int id = (tmp[0] & 0xf) - 1; + int x = tmp[2] | ((tmp[1] & 0xf) << 8); + int y = tmp[3] | (((tmp[1] >> 4) & 0xf) << 8); + int type = (tmp[0] & 0x60) >> 5; /* 01:screen, 10:key */ + int action = (tmp[0] & 0x80) >> 7; + + if (info->use_touchkey && type == 0x02) { + input_report_key(info->input_dev, + info->keycode[id], action); +#ifdef SEC_TSP_DEBUG + dev_notice(&client->dev, + "touchkey : keycode=%d action=%d\n", + info->keycode[id], action); +#else + dev_notice(&client->dev, + "touchkey action=%d\n", action); +#endif +#ifdef SEC_TKEY_FACTORY_TEST + info->key_pressed[id] = action; +#endif + } else { + if (info->invert_x) { + x = info->max_x - x; + if (x < 0) + x = 0; + } + if (info->invert_y) { + y = info->max_y - y; + if (y < 0) + y = 0; + } + + if ((tmp[0] & 0x80) == 0) { +#if defined(SEC_TSP_DEBUG) + dev_dbg(&client->dev, + "finger id[%d]: x=%d y=%d w=%d p=%d\n" + , id, x, y, tmp[4], tmp[5]); +#else + dev_notice(&client->dev, "finger %d up\n", id); +#endif + input_mt_slot(info->input_dev, id); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, false); + +#if defined(SEC_TSP_DEBUG) || defined(SEC_TSP_VERBOSE_DEBUG) + info->finger_state[id] = 0; +#endif + continue; + } + + input_mt_slot(info->input_dev, id); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, true); + input_report_abs(info->input_dev, + ABS_MT_TOUCH_MAJOR, tmp[4]); + input_report_abs(info->input_dev, + ABS_MT_PRESSURE, tmp[5]); + input_report_abs(info->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(info->input_dev, + ABS_MT_POSITION_Y, y); +#if defined(SEC_TSP_DEBUG) + if (info->finger_state[id] == 0) { + info->finger_state[id] = 1; + dev_dbg(&client->dev, + "finger id[%d]:x=%d y=%d w=%d p=%d\n" + , id, x, y, tmp[4], tmp[5]); + } +#else + if (info->finger_state[id] == 0) { + info->finger_state[id] = 1; + dev_notice(&client->dev, "finger %d down\n" + , id); + } +#endif + } + } + input_sync(info->input_dev); + + touch_is_pressed = 0; + + for (i = 0; i < MAX_FINGERS; i++) { + if (info->finger_state[i] == 1) + touch_is_pressed++; + } +#if TOUCH_BOOSTER + set_dvfs_lock(info, !!touch_is_pressed); +#endif + +out: + return IRQ_HANDLED; +} + +static void hw_reboot(struct mms_ts_info *info, bool bootloader) +{ + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, bootloader ? 0 : 1); + gpio_direction_output(info->pdata->gpio_scl, bootloader ? 0 : 1); + gpio_direction_output(info->pdata->gpio_resetb, 0); + msleep(30); + info->pdata->vdd_on(1); + msleep(30); + + if (bootloader) { + gpio_set_value(info->pdata->gpio_scl, 0); + gpio_set_value(info->pdata->gpio_sda, 1); + } else { + gpio_set_value(info->pdata->gpio_resetb, 1); + gpio_direction_input(info->pdata->gpio_resetb); + gpio_direction_input(info->pdata->gpio_scl); + gpio_direction_input(info->pdata->gpio_sda); + } + msleep(40); +} + +static inline void hw_reboot_bootloader(struct mms_ts_info *info) +{ + hw_reboot(info, true); +} + +static inline void hw_reboot_normal(struct mms_ts_info *info) +{ + hw_reboot(info, false); +} + +static inline void mms_pwr_on_reset(struct mms_ts_info *info) +{ + struct i2c_adapter *adapter = to_i2c_adapter(info->client->dev.parent); + + if (!info->pdata->mux_fw_flash) { + dev_info(&info->client->dev, + "missing platform data, can't do power-on-reset\n"); + return; + } + + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, 1); + gpio_direction_output(info->pdata->gpio_scl, 1); + gpio_direction_output(info->pdata->gpio_resetb, 1); + msleep(50); + info->pdata->vdd_on(1); + msleep(50); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + /* TODO: Seems long enough for the firmware to boot. + * Find the right value */ + msleep(250); +} + +static void isp_toggle_clk(struct mms_ts_info *info, int start_lvl, int end_lvl, + int hold_us) +{ + gpio_set_value(info->pdata->gpio_scl, start_lvl); + udelay(hold_us); + gpio_set_value(info->pdata->gpio_scl, end_lvl); + udelay(hold_us); +} + +/* 1 <= cnt <= 32 bits to write */ +static void isp_send_bits(struct mms_ts_info *info, u32 data, int cnt) +{ + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 0); + + /* clock out the bits, msb first */ + while (cnt--) { + gpio_set_value(info->pdata->gpio_sda, (data >> cnt) & 1); + udelay(3); + isp_toggle_clk(info, 1, 0, 3); + } +} + +/* 1 <= cnt <= 32 bits to read */ +static u32 isp_recv_bits(struct mms_ts_info *info, int cnt) +{ + u32 data = 0; + + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_set_value(info->pdata->gpio_sda, 0); + gpio_direction_input(info->pdata->gpio_sda); + + /* clock in the bits, msb first */ + while (cnt--) { + isp_toggle_clk(info, 0, 1, 1); + data = (data << 1) | (!!gpio_get_value(info->pdata->gpio_sda)); + } + + gpio_direction_output(info->pdata->gpio_sda, 0); + return data; +} + +static void isp_enter_mode(struct mms_ts_info *info, u32 mode) +{ + int cnt; + unsigned long flags; + + local_irq_save(flags); + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 1); + + mode &= 0xffff; + for (cnt = 15; cnt >= 0; cnt--) { + gpio_set_value(info->pdata->gpio_resetb, (mode >> cnt) & 1); + udelay(3); + isp_toggle_clk(info, 1, 0, 3); + } + + gpio_set_value(info->pdata->gpio_resetb, 0); + local_irq_restore(flags); +} + +static void isp_exit_mode(struct mms_ts_info *info) +{ + int i; + unsigned long flags; + + local_irq_save(flags); + gpio_direction_output(info->pdata->gpio_resetb, 0); + udelay(3); + + for (i = 0; i < 10; i++) + isp_toggle_clk(info, 1, 0, 3); + local_irq_restore(flags); +} + +static void flash_set_address(struct mms_ts_info *info, u16 addr) +{ + /* Only 13 bits of addr are valid. + * The addr is in bits 13:1 of cmd */ + isp_send_bits(info, (u32)(addr & 0x1fff) << 1, 18); +} + +static void flash_erase(struct mms_ts_info *info) +{ + isp_enter_mode(info, ISP_MODE_FLASH_ERASE); + + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 1); + + /* 4 clock cycles with different timings for the erase to + * get processed, clk is already 0 from above */ + udelay(7); + isp_toggle_clk(info, 1, 0, 3); + udelay(7); + isp_toggle_clk(info, 1, 0, 3); + usleep_range(25000, 35000); + isp_toggle_clk(info, 1, 0, 3); + usleep_range(150, 200); + isp_toggle_clk(info, 1, 0, 3); + + gpio_set_value(info->pdata->gpio_sda, 0); + + isp_exit_mode(info); +} + +static u32 flash_readl(struct mms_ts_info *info, u16 addr) +{ + int i; + u32 val; + unsigned long flags; + + local_irq_save(flags); + isp_enter_mode(info, ISP_MODE_FLASH_READ); + flash_set_address(info, addr); + + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 0); + udelay(40); + + /* data load cycle */ + for (i = 0; i < 6; i++) + isp_toggle_clk(info, 1, 0, 10); + + val = isp_recv_bits(info, 32); + isp_exit_mode(info); + local_irq_restore(flags); + + return val; +} + +static void flash_writel(struct mms_ts_info *info, u16 addr, u32 val) +{ + unsigned long flags; + + local_irq_save(flags); + isp_enter_mode(info, ISP_MODE_FLASH_WRITE); + flash_set_address(info, addr); + isp_send_bits(info, val, 32); + + gpio_direction_output(info->pdata->gpio_sda, 1); + /* 6 clock cycles with different timings for the data to get written + * into flash */ + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 6); + isp_toggle_clk(info, 0, 1, 12); + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 3); + + isp_toggle_clk(info, 1, 0, 1); + + gpio_direction_output(info->pdata->gpio_sda, 0); + isp_exit_mode(info); + local_irq_restore(flags); + usleep_range(300, 400); +} + +static bool flash_is_erased(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + u32 val; + u16 addr; + + for (addr = 0; addr < (ISP_MAX_FW_SIZE / 4); addr++) { + udelay(40); + val = flash_readl(info, addr); + + if (val != 0xffffffff) { + dev_dbg(&client->dev, + "addr 0x%x not erased: 0x%08x != 0xffffffff\n", + addr, val); + return false; + } + } + return true; +} + +static int fw_write_image(struct mms_ts_info *info, const u8 *data, size_t len) +{ + struct i2c_client *client = info->client; + u16 addr = 0; + + for (addr = 0; addr < (len / 4); addr++, data += 4) { + u32 val = get_unaligned_le32(data); + u32 verify_val; + int retries = 3; + + while (retries--) { + flash_writel(info, addr, val); + verify_val = flash_readl(info, addr); + if (val == verify_val) + break; + dev_err(&client->dev, + "mismatch @ addr 0x%x: 0x%x != 0x%x\n", + addr, verify_val, val); + continue; + } + if (retries < 0) + return -ENXIO; + } + + return 0; +} + +static int fw_download(struct mms_ts_info *info, const u8 *data, size_t len) +{ + struct i2c_client *client = info->client; + u32 val; + int ret = 0; + + if (len % 4) { + dev_err(&client->dev, + "fw image size (%d) must be a multiple of 4 bytes\n", + len); + return -EINVAL; + } else if (len > ISP_MAX_FW_SIZE) { + dev_err(&client->dev, + "fw image is too big, %d > %d\n", len, ISP_MAX_FW_SIZE); + return -EINVAL; + } + + dev_info(&client->dev, "fw download start\n"); + + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_resetb, 0); + + hw_reboot_bootloader(info); + + val = flash_readl(info, ISP_IC_INFO_ADDR); + dev_info(&client->dev, "IC info: 0x%02x (%x)\n", val & 0xff, val); + + dev_info(&client->dev, "fw erase...\n"); + flash_erase(info); + if (!flash_is_erased(info)) { + ret = -ENXIO; + goto err; + } + + dev_info(&client->dev, "fw write...\n"); + /* XXX: what does this do?! */ + flash_writel(info, ISP_IC_INFO_ADDR, 0xffffff00 | (val & 0xff)); + usleep_range(1000, 1500); + ret = fw_write_image(info, data, len); + if (ret) + goto err; + usleep_range(1000, 1500); + + hw_reboot_normal(info); + usleep_range(1000, 1500); + dev_info(&client->dev, "fw download done...\n"); + return 0; + +err: + dev_err(&client->dev, "fw download failed...\n"); + hw_reboot_normal(info); + return ret; +} + +#if defined(SEC_TSP_ISC_FW_UPDATE) +static u16 gen_crc(u8 data, u16 pre_crc) +{ + u16 crc; + u16 cur; + u16 temp; + u16 bit_1; + u16 bit_2; + int i; + + crc = pre_crc; + for (i = 7; i >= 0; i--) { + cur = ((data >> i) & 0x01) ^ (crc & 0x0001); + bit_1 = cur ^ (crc >> 11 & 0x01); + bit_2 = cur ^ (crc >> 4 & 0x01); + temp = (cur << 4) | (crc >> 12 & 0x0F); + temp = (temp << 7) | (bit_1 << 6) | (crc >> 5 & 0x3F); + temp = (temp << 4) | (bit_2 << 3) | (crc >> 1 & 0x0007); + crc = temp; + } + return crc; +} + +static int isc_fw_download(struct mms_ts_info *info, const u8 *data, + size_t len) +{ + u8 *buff; + u16 crc_buf; + int src_idx; + int dest_idx; + int ret; + int i, j; + + buff = kzalloc(ISC_PKT_SIZE, GFP_KERNEL); + if (!buff) { + dev_err(&info->client->dev, "%s: failed to allocate memory\n", + __func__); + ret = -1; + goto err_mem_alloc; + } + + /* enterring ISC mode */ + *buff = ISC_ENTER_ISC_DATA; + ret = i2c_smbus_write_byte_data(info->client, + ISC_ENTER_ISC_CMD, *buff); + if (ret < 0) { + dev_err(&info->client->dev, + "fail to enter ISC mode(err=%d)\n", ret); + goto fail_to_isc_enter; + } + usleep_range(10000, 20000); + dev_info(&info->client->dev, "Enter ISC mode\n"); + + /*enter ISC update mode */ + *buff = ISC_ENTER_UPDATE_DATA; + ret = i2c_smbus_write_i2c_block_data(info->client, + ISC_CMD, + ISC_ENTER_UPDATE_DATA_LEN, buff); + if (ret < 0) { + dev_err(&info->client->dev, + "fail to enter ISC update mode(err=%d)\n", ret); + goto fail_to_isc_update; + } + dev_info(&info->client->dev, "Enter ISC update mode\n"); + + /* firmware write */ + *buff = ISC_CMD; + *(buff + 1) = ISC_DATA_WRITE_SUB_CMD; + for (i = 0; i < ISC_PKT_NUM; i++) { + *(buff + 2) = i; + crc_buf = gen_crc(*(buff + 2), ISC_DEFAULT_CRC); + + for (j = 0; j < ISC_PKT_DATA_SIZE; j++) { + dest_idx = ISC_PKT_HEADER_SIZE + j; + src_idx = i * ISC_PKT_DATA_SIZE + + ((int)(j / WORD_SIZE)) * WORD_SIZE - + (j % WORD_SIZE) + 3; + *(buff + dest_idx) = *(data + src_idx); + crc_buf = gen_crc(*(buff + dest_idx), crc_buf); + } + + *(buff + ISC_PKT_DATA_SIZE + ISC_PKT_HEADER_SIZE + 1) = + crc_buf & 0xFF; + *(buff + ISC_PKT_DATA_SIZE + ISC_PKT_HEADER_SIZE) = + crc_buf >> 8 & 0xFF; + + ret = i2c_master_send(info->client, buff, ISC_PKT_SIZE); + if (ret < 0) { + dev_err(&info->client->dev, + "fail to firmware writing on packet %d.(%d)\n", + i, ret); + goto fail_to_fw_write; + } + usleep_range(1, 5); + + /* confirm CRC */ + ret = i2c_smbus_read_byte_data(info->client, + ISC_CHECK_STATUS_CMD); + if (ret == ISC_CONFIRM_CRC) { + dev_info(&info->client->dev, + "updating %dth firmware data packet.\n", i); + } else { + dev_err(&info->client->dev, + "fail to firmware update on %dth (%X).\n", + i, ret); + ret = -1; + goto fail_to_confirm_crc; + } + } + + ret = 0; + +fail_to_confirm_crc: +fail_to_fw_write: + /* exit ISC mode */ + *buff = ISC_EXIT_ISC_SUB_CMD; + *(buff + 1) = ISC_EXIT_ISC_SUB_CMD2; + i2c_smbus_write_i2c_block_data(info->client, ISC_CMD, 2, buff); + usleep_range(10000, 20000); +fail_to_isc_update: + hw_reboot_normal(info); +fail_to_isc_enter: + kfree(buff); +err_mem_alloc: + return ret; +} +#endif /* SEC_TSP_ISC_FW_UPDATE */ + +static int get_fw_version(struct mms_ts_info *info) +{ + int ret; + int retries = 3; + + do { + ret = i2c_smbus_read_byte_data(info->client, MMS_FW_VERSION); + } while (ret < 0 && retries-- > 0); + + return ret; +} + +static int get_hw_version(struct mms_ts_info *info) +{ + int ret; + int retries = 3; + + /* this seems to fail sometimes after a reset.. retry a few times */ + do { + ret = i2c_smbus_read_byte_data(info->client, MMS_HW_REVISION); + } while (ret < 0 && retries-- > 0); + + return ret; +} + +static int mms_ts_enable(struct mms_ts_info *info, int wakeupcmd) +{ + mutex_lock(&info->lock); + if (info->enabled) + goto out; + /* wake up the touch controller. */ + if (wakeupcmd == 1) { + i2c_smbus_write_byte_data(info->client, 0, 0); + usleep_range(3000, 5000); + } + info->enabled = true; + enable_irq(info->irq); +out: + mutex_unlock(&info->lock); + return 0; +} + +static int mms_ts_disable(struct mms_ts_info *info, int sleepcmd) +{ + mutex_lock(&info->lock); + if (!info->enabled) + goto out; + disable_irq(info->irq); + if (sleepcmd == 1) { + i2c_smbus_write_byte_data(info->client, MMS_MODE_CONTROL, 0); + usleep_range(10000, 12000); + } + info->enabled = false; + touch_is_pressed = 0; +out: + mutex_unlock(&info->lock); + return 0; +} + +static int mms_ts_finish_config(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + int ret; + + ret = request_threaded_irq(client->irq, NULL, mms_ts_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "mms_ts", info); + if (ret < 0) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_req_irq; + } + + info->irq = client->irq; + barrier(); + + dev_info(&client->dev, + "Melfas MMS-series touch controller initialized\n"); + + return 0; + +err_req_irq: + return ret; +} + +static int mms_ts_fw_load(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret = 0; + int ver, module_rev; + int retries = 3; + + ver = get_fw_version(info); + info->fw_ic_ver = ver; + dev_info(&client->dev, + "[TSP]fw version 0x%02x !!!!\n", ver); + + if (ver < 0) { + ver = 0; + dev_err(&client->dev, + "can't read version,controller dead? FW update!\n"); + } + + module_rev = get_hw_version(info); + dev_info(&client->dev, + "[TSP]MODULE revision 0x%02x !!!!\n", module_rev); + + if (module_rev < 0) { + module_rev = 0; + dev_err(&client->dev, + "can't read revision,controller dead?\n"); + goto out; + } + + if (!info->pdata || !info->pdata->mux_fw_flash) { + ret = 1; + dev_err(&client->dev, + "fw cannot be updated, missing platform data\n"); + goto out; + } + + if (module_rev == 0x10 && info->pdata->check_module_type) { + dev_info(&client->dev, + "fw version update does not need - old module\n"); + goto done; + } + + if (machine_is_JASPER() && (system_rev < 0x4)) { + dev_info(&client->dev, + "fw update does not need - old module(3key)\n"); + goto done; + } + + if (ver >= FW_VERSION) { + dev_info(&client->dev, + "fw version update does not need\n"); + goto done; + } + + while (retries--) { + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + if (machine_is_JASPER() && (module_rev == 0x1)) { + ret = fw_download(info, OFILM_binary, + MELFAS_binary_nLength); + } else if (machine_is_JASPER() && (module_rev == 0x32)) { + ret = fw_download(info, OFILM_binary, + MELFAS_binary_nLength); + } else if (machine_is_JASPER() && (module_rev == 0x2)) { + ret = fw_download(info, MELFAS_binary, + MELFAS_binary_nLength); + } else if (machine_is_GOGH()) { + ret = fw_download(info, MELFAS_binary, + MELFAS_binary_nLength); + } else { + goto done; + } + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + if (ret < 0) { + dev_err(&client->dev, "retrying flashing\n"); + continue; + } + + ver = get_fw_version(info); + info->fw_ic_ver = ver; + + if (ver == FW_VERSION) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + goto done; + } else { + dev_err(&client->dev, + "ERROR: fw update succeeded, but fw version is still wrong (0x%x != 0x%x)\n", + ver, FW_VERSION); + } + dev_err(&client->dev, "retrying flashing\n"); + } + +out: + return ret; + +done: + ret = mms_ts_finish_config(info); + return ret; +} + +#ifdef SEC_TSP_FACTORY_TEST +static void set_default_result(struct mms_ts_info *info) +{ + char delim = ':'; + + memset(info->cmd_result, 0x00, ARRAY_SIZE(info->cmd_result)); + memcpy(info->cmd_result, info->cmd, strlen(info->cmd)); + strncat(info->cmd_result, &delim, 1); +} + +static void set_cmd_result(struct mms_ts_info *info, char *buff, int len) +{ + strncat(info->cmd_result, buff, len); +} + +static inline int msm_irq_to_gpio(unsigned irq) +{ + /* TODO : Need to verify chip->base=0 */ + return irq - MSM_GPIO_TO_INT(0); +} +static void get_raw_data_all(struct mms_ts_info *info, u8 cmd) +{ + u8 w_buf[6]; + u8 read_buffer[2]; /* 52 */ + char buff[TSP_CMD_STR_LEN] = {0}; + int gpio; + int ret; + int i, j; + u32 max_value, min_value; + u32 raw_data; + int tx_diff = 0; + if (machine_is_JASPER()) + tx_diff = 1; + + gpio = msm_irq_to_gpio(info->irq); + disable_irq(info->irq); + + w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */ + w_buf[1] = MMS_VSC_MODE; /* mode of vendor */ + w_buf[2] = 0; /* tx line */ + w_buf[3] = 0; /* rx line */ + w_buf[4] = 0; /* reserved */ + w_buf[5] = 0; /* sub command */ + + if (cmd == MMS_VSC_CMD_EXIT) { + w_buf[5] = MMS_VSC_CMD_EXIT; /* exit test mode */ + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + touch_is_pressed = 0; + release_all_fingers(info); + info->pdata->vdd_on(0); + msleep(30); + info->pdata->vdd_on(1); + msleep(120); + enable_irq(info->irq); + return ; + } + + /* MMS_VSC_CMD_CM_DELTA or MMS_VSC_CMD_CM_ABS + * this two mode need to enter the test mode + * exit command must be followed by testing. + */ + if (cmd == MMS_VSC_CMD_CM_DELTA || cmd == MMS_VSC_CMD_CM_ABS) { + /* enter the debug mode */ + w_buf[2] = 0x0; /* tx */ + w_buf[3] = 0x0; /* rx */ + w_buf[5] = MMS_VSC_CMD_ENTER; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + + /* wating for the interrupt */ + while (gpio_get_value(gpio)) + udelay(100); + } + + max_value = 0; + min_value = 0; + + for (i = 0; i < RX_NUM; i++) { + for (j = 0; j < (TX_NUM - tx_diff); j++) { + + w_buf[2] = j; /* tx */ + w_buf[3] = i; /* rx */ + w_buf[5] = cmd; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + + usleep_range(1, 5); + + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, + 2, read_buffer); + if (ret < 0) + goto err_i2c; + + raw_data = ((u16)read_buffer[1] << 8) | read_buffer[0]; + + if (i == 0 && j == 0) { + max_value = min_value = raw_data; + } else { + max_value = max(max_value, raw_data); + min_value = min(min_value, raw_data); + } + + if (cmd == MMS_VSC_CMD_INTENSITY) { + info->intensity[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "[TSP] intensity[%d][%d] = %d\n", + i, j, info->intensity[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_CM_DELTA) { + info->inspection[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "[TSP] delta[%d][%d] = %d\n", + i, j, info->inspection[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_CM_ABS) { + info->raw[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "[TSP] raw[%d][%d] = %d\n", + i, j, info->raw[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_REFER) { + info->reference[j * RX_NUM + i] = + raw_data >> 3; + dev_dbg(&info->client->dev, "[TSP] reference[%d][%d] = %d\n", + i, j, info->reference[j * RX_NUM + i]); + } + } + } + + snprintf(buff, sizeof(buff), "%d,%d", min_value, max_value); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + enable_irq(info->irq); + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); +} + +#if defined(ESD_DEBUG) || defined(SEC_TKEY_FACTORY_TEST) +static u32 get_raw_data_one(struct mms_ts_info *info, u16 rx_idx, u16 tx_idx, + u8 cmd) +{ + u8 w_buf[6]; + u8 read_buffer[2]; + int ret; + u32 raw_data; + + w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */ + w_buf[1] = MMS_VSC_MODE; /* mode of vendor */ + w_buf[2] = 0; /* tx line */ + w_buf[3] = 0; /* rx line */ + w_buf[4] = 0; /* reserved */ + w_buf[5] = 0; /* sub command */ + + if (cmd != MMS_VSC_CMD_INTENSITY && cmd != MMS_VSC_CMD_RAW && + cmd != MMS_VSC_CMD_REFER && cmd != VSC_INTENSITY_TK && + cmd != VSC_RAW_TK) { + dev_err(&info->client->dev, "%s: not profer command(cmd=%d)\n", + __func__, cmd); + return FAIL; + } + + w_buf[2] = tx_idx; /* tx */ + w_buf[3] = rx_idx; /* rx */ + w_buf[5] = cmd; /* sub command */ + + ret = i2c_smbus_write_i2c_block_data(info->client, w_buf[0], 5, + &w_buf[1]); + if (ret < 0) + goto err_i2c; + + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, 2, + read_buffer); + if (ret < 0) + goto err_i2c; + + raw_data = ((u16)read_buffer[1] << 8) | read_buffer[0]; + if (cmd == MMS_VSC_CMD_REFER) + raw_data = raw_data >> 4; + + return raw_data; + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); + return FAIL; +} +#endif + +static ssize_t show_close_tsp_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->ft_flag = 0; + + return snprintf(buf, TSP_BUF_SIZE, "%u\n", 0); +} + +static int check_rx_tx_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[TSP_CMD_STR_LEN] = {0}; + int node; + int tx_diff = 0; + if (machine_is_JASPER()) + tx_diff = 1; + + if (info->cmd_param[0] < 0 || + info->cmd_param[0] >= (TX_NUM - tx_diff) || + info->cmd_param[1] < 0 || + info->cmd_param[1] >= RX_NUM) { + snprintf(buff, sizeof(buff) , "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: parameter error: %u,%u\n", + __func__, info->cmd_param[0], + info->cmd_param[1]); + node = -1; + return node; + } + node = info->cmd_param[1] * RX_NUM + info->cmd_param[0]; + dev_info(&info->client->dev, "%s: node = %d\n", __func__, + node); + return node; + +} + +static void not_support_cmd(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + char buff[16] = {0}; + + set_default_result(info); + sprintf(buff, "%s", "NA"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 4; + dev_info(&info->client->dev, "%s: \"%s(%d)\"\n", __func__, + buff, strnlen(buff, sizeof(buff))); + return; +} + +static void fw_update(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + struct i2c_client *client = info->client; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret = 0; + int ver, module_rev; + int retries = 3; + const u8 *buff = 0; + mm_segment_t old_fs = {0}; + struct file *fp = NULL; + long fsize = 0, nread = 0; + + #define MMS_TS "/sdcard/melfas_fw.bin" + + set_default_result(info); + + module_rev = get_hw_version(info); + dev_info(&client->dev, + "[TSP]MODULE revision 0x%02x !!!!\n", module_rev); + + if (module_rev == 0x10 && info->pdata->check_module_type) { + dev_err(&client->dev, + "fw version update does not need - old module\n"); + goto do_not_need_update; + } + + if (info->cmd_param[0] == 0 + && info->fw_ic_ver >= FW_VERSION) { + dev_info(&client->dev, + "fw version update does not need\n"); + goto do_not_need_update; + } + + switch (info->cmd_param[0]) { + case BUILT_IN: + if (machine_is_JASPER() && (module_rev == 0x1)) + buff = OFILM_binary; + else + buff = MELFAS_binary; + fsize = MELFAS_binary_nLength; + dev_info(&client->dev, "built in fw is loaded!!\n"); + break; + + case UMS: + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(MMS_TS, O_RDONLY, S_IRUSR); + if (IS_ERR(fp)) { + dev_err(&client->dev, + "fail to open fw in ums (%s)\n", MMS_TS); + goto err_open; + } + fsize = fp->f_path.dentry->d_inode->i_size; + + buff = kzalloc((size_t)fsize, GFP_KERNEL); + if (!buff) { + dev_err(&client->dev, "fail to alloc buffer for fw\n"); + goto err_alloc; + } + + nread = vfs_read(fp, (char __user *)buff, fsize, &fp->f_pos); + if (nread != fsize) { + dev_err(&client->dev, "fail to read file %s (nread = %ld)\n", + MMS_TS, nread); + goto err_fw_size; + } + + filp_close(fp, current->files); + set_fs(old_fs); + dev_info(&client->dev, "ums fw is loaded!!\n"); + break; + + default: + dev_err(&client->dev, "invalid fw file type!!\n"); + goto not_support; + } + + disable_irq(info->irq); + while (retries--) { + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + ret = fw_download(info, (const u8 *)buff, + (const size_t)fsize); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + if (ret < 0) { + dev_err(&client->dev, "retrying flashing\n"); + continue; + } + + ver = get_fw_version(info); + info->fw_ic_ver = ver; + + if (ver == FW_VERSION) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + info->cmd_state = 2; + enable_irq(info->irq); + return; + } else { + dev_err(&client->dev, + "ERROR :fw version is still wrong (0x%x != 0x%x)\n", + ver, FW_VERSION); + } + dev_err(&client->dev, "retrying flashing\n"); + } + +err_fw_size: + kfree(buff); +err_alloc: + filp_close(fp, NULL); +err_open: + set_fs(old_fs); +not_support: +do_not_need_update: + info->cmd_state = 2; + return; +} + +static void get_fw_ver_bin(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + snprintf(buff, sizeof(buff), "%#02x", FW_VERSION); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_fw_ver_ic(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int ver; + + set_default_result(info); + + ver = info->fw_ic_ver; + snprintf(buff, sizeof(buff), "%#02x", ver); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_config_ver(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[20] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", info->config_fw_version); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_threshold(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int threshold; + + set_default_result(info); + + threshold = i2c_smbus_read_byte_data(info->client, 0x05); + if (threshold < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + return; + } + snprintf(buff, sizeof(buff), "%d", threshold); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void module_off_master(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[3] = {0}; + + mutex_lock(&info->lock); + if (info->enabled) { + disable_irq(info->irq); + info->enabled = false; + touch_is_pressed = 0; + } + mutex_unlock(&info->lock); + + info->pdata->vdd_on(0); + + if (info->pdata->is_vdd_on() == 0) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = 2; + else + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: %s\n", __func__, buff); +} + +static void module_on_master(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[3] = {0}; + + mms_pwr_on_reset(info); + + mutex_lock(&info->lock); + if (!info->enabled) { + enable_irq(info->irq); + info->enabled = true; + } + mutex_unlock(&info->lock); + + if (info->pdata->is_vdd_on() == 1) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = 2; + else + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: %s\n", __func__, buff); + +} + +static void get_chip_vendor(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", "MELFAS"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_chip_name(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", "MMS136"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_reference(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return ; + + val = info->reference[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_cm_abs(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->raw[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); + } + +static void get_cm_delta(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->inspection[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_intensity(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return ; + + val = info->intensity[node]; + + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_x_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int val; + + set_default_result(info); + val = i2c_smbus_read_byte_data(info->client, 0xEF); + if (val < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_info(&info->client->dev, + "%s: fail to read num of x (%d).\n", __func__, val); + return ; + } + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_y_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int val; + + set_default_result(info); + val = i2c_smbus_read_byte_data(info->client, 0xEE); + if (val < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_info(&info->client->dev, + "%s: fail to read num of y (%d).\n", __func__, val); + + return ; + } + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void run_reference_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_REFER); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s:\n", __func__); +} + +static void run_cm_abs_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_CM_ABS); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s:\n", __func__); +} + +static void run_cm_delta_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_CM_DELTA); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s:\n", __func__); +} + +static void run_intensity_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_INTENSITY); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s:\n", __func__); +} + +static ssize_t store_cmd(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + + char *cur, *start, *end; + char buff[TSP_CMD_STR_LEN] = {0}; + int len, i; + struct tsp_cmd *tsp_cmd_ptr = NULL; + char delim = ','; + bool cmd_found = false; + int param_cnt = 0; + + + if (info->cmd_is_running == true) { + dev_err(&info->client->dev, "tsp_cmd: other cmd is running.\n"); + goto err_out; + } + + + /* check lock */ + mutex_lock(&info->cmd_lock); + info->cmd_is_running = true; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = 1; + + for (i = 0; i < ARRAY_SIZE(info->cmd_param); i++) + info->cmd_param[i] = 0; + + len = (int)count; + if (*(buf + len - 1) == '\n') + len--; + memset(info->cmd, 0x00, ARRAY_SIZE(info->cmd)); + memcpy(info->cmd, buf, len); + + cur = strchr(buf, (int)delim); + if (cur) + memcpy(buff, buf, cur - buf); + else + memcpy(buff, buf, len); + + /* find command */ + list_for_each_entry(tsp_cmd_ptr, &info->cmd_list_head, list) { + if (!strcmp(buff, tsp_cmd_ptr->cmd_name)) { + cmd_found = true; + break; + } + } + + /* set not_support_cmd */ + if (!cmd_found) { + list_for_each_entry(tsp_cmd_ptr, &info->cmd_list_head, list) { + if (!strcmp("not_support_cmd", tsp_cmd_ptr->cmd_name)) + break; + } + } + + /* parsing parameters */ + if (cur && cmd_found) { + cur++; + start = cur; + memset(buff, 0x00, ARRAY_SIZE(buff)); + do { + if (*cur == delim || cur - buf == len) { + end = cur; + memcpy(buff, start, end - start); + *(buff + strlen(buff)) = '\0'; + if (kstrtoint(buff, 10, + info->cmd_param + param_cnt) < 0) + goto err_out; + start = cur + 1; + memset(buff, 0x00, ARRAY_SIZE(buff)); + param_cnt++; + } + cur++; + } while (cur - buf <= len); + } + + dev_info(&client->dev, "cmd = %s\n", tsp_cmd_ptr->cmd_name); + for (i = 0; i < param_cnt; i++) + dev_info(&client->dev, "cmd param %d= %d\n", i, + info->cmd_param[i]); + + tsp_cmd_ptr->cmd_func(info); + +err_out: + return count; +} + +static ssize_t show_cmd_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + char buff[16] = {0}; + + dev_info(&info->client->dev, "tsp cmd: status:%d\n", + info->cmd_state); + + if (info->cmd_state == 0) + snprintf(buff, sizeof(buff), "WAITING"); + + else if (info->cmd_state == 1) + snprintf(buff, sizeof(buff), "RUNNING"); + + else if (info->cmd_state == 2) + snprintf(buff, sizeof(buff), "OK"); + + else if (info->cmd_state == 3) + snprintf(buff, sizeof(buff), "FAIL"); + + else if (info->cmd_state == 4) + snprintf(buff, sizeof(buff), "NOT_APPLICABLE"); + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", buff); +} + +static ssize_t show_cmd_result(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + + dev_info(&info->client->dev, "tsp cmd: result: %s\n", info->cmd_result); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = 0; + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", info->cmd_result); +} + +#ifdef ESD_DEBUG + +static bool intensity_log_flag; + +static ssize_t show_intensity_logging_on(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + struct file *fp; + char log_data[160] = {0,}; + char buff[16] = {0,}; + mm_segment_t old_fs; + long nwrite; + u32 val; + int i, y, c; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + +#define MELFAS_DEBUG_LOG_PATH "/sdcard/melfas_log" + + dev_info(&client->dev, "%s: start.\n", __func__); + fp = filp_open(MELFAS_DEBUG_LOG_PATH, O_RDWR|O_CREAT, + S_IRWXU|S_IRWXG|S_IRWXO); + if (IS_ERR(fp)) { + dev_err(&client->dev, "%s: fail to open log file\n", __func__); + goto open_err; + } + + intensity_log_flag = 1; + do { + for (y = 0; y < 3; y++) { + /* for tx chanel 0~2 */ + memset(log_data, 0x00, 160); + + snprintf(buff, 16, "%1u: ", y); + strncat(log_data, buff, strnlen(buff, 16)); + + for (i = 0; i < RX_NUM; i++) { + val = get_raw_data_one(info, i, y, + MMS_VSC_CMD_INTENSITY); + snprintf(buff, 16, "%5u, ", val); + strncat(log_data, buff, strnlen(buff, 16)); + } + memset(buff, '\n', 2); + c = (y == 2) ? 2 : 1; + strncat(log_data, buff, c); + nwrite = vfs_write(fp, (const char __user *)log_data, + strnlen(log_data, 160), &fp->f_pos); + } + usleep_range(5000); + } while (intensity_log_flag); + + filp_close(fp, current->files); + set_fs(old_fs); + + return 0; + + open_err: + set_fs(old_fs); + return FAIL; +} + +static ssize_t show_intensity_logging_off(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + intensity_log_flag = 0; + usleep_range(10000); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + return 0; +} + +#endif + +#ifdef SEC_TKEY_FACTORY_TEST +static ssize_t tkey_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int tkey_threshold; + + tkey_threshold = i2c_smbus_read_byte_data(info->client, + VSC_THRESHOLD_TK); + dev_info(&client->dev, "touch key threshold: %d\n", tkey_threshold); + + return snprintf(buf, sizeof(int), "%d\n", tkey_threshold); +} + +static ssize_t back_key_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int i, ret, val; + + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) { + if (info->keycode[i] == KEY_BACK) + break; + } + dev_info(&client->dev, "back key state: %d\n", info->key_pressed[i]); + + /* back key*/ + disable_irq(info->irq); + + ret = get_raw_data_one(info, 0, 0, VSC_INTENSITY_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + enable_irq(info->irq); + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t home_key_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int i, ret, val; + + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) { + if (info->keycode[i] == KEY_HOMEPAGE) + break; + } + dev_info(&client->dev, "back key state: %d\n", info->key_pressed[i]); + + /* home key*/ + disable_irq(info->irq); + + ret = get_raw_data_one(info, 0, 1, VSC_INTENSITY_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + enable_irq(info->irq); + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t recent_key_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int i, ret, val; + + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) { + if (info->keycode[i] == KEY_F3) + break; + } + dev_info(&client->dev, "back key state: %d\n", info->key_pressed[i]); + + /* recent key*/ + disable_irq(info->irq); + + ret = get_raw_data_one(info, 0, 2, VSC_INTENSITY_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + enable_irq(info->irq); + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t menu_key_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int i, ret, val; + + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) { + if (info->keycode[i] == KEY_MENU) + break; + } + dev_info(&client->dev, "back key state: %d\n", info->key_pressed[i]); + + /* recent key*/ + disable_irq(info->irq); + + ret = get_raw_data_one(info, 0, 3, VSC_INTENSITY_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + enable_irq(info->irq); + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t tkey_rawcounter_show0(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + u32 ret; + u16 val; + + /* back key*/ + disable_irq(info->irq); + + ret = get_raw_data_one(info, 0, 0, VSC_RAW_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + enable_irq(info->irq); + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t tkey_rawcounter_show1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int ret; + u16 val; + + /* home key*/ + disable_irq(info->irq); + + ret = get_raw_data_one(info, 0, 1, VSC_RAW_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + enable_irq(info->irq); + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t tkey_rawcounter_show2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int ret; + u16 val; + + /* recent key*/ + disable_irq(info->irq); + + ret = get_raw_data_one(info, 0, 2, VSC_RAW_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + enable_irq(info->irq); + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} + +static ssize_t tkey_rawcounter_show3(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int ret; + u16 val; + + /* menu key*/ + disable_irq(info->irq); + + ret = get_raw_data_one(info, 0, 3, VSC_RAW_TK); + if (ret < 0) + dev_err(&client->dev, "%s: fail to read (%d)\n", __func__, ret); + + enable_irq(info->irq); + val = (u16)ret; + + dev_info(&client->dev, "%s: val=%d\n", __func__, val); + return sprintf(buf, "%d\n", val); +} +#endif + +#ifdef SEC_TKEY_FACTORY_TEST +static DEVICE_ATTR(touchkey_threshold, S_IRUGO, tkey_threshold_show, NULL); +static DEVICE_ATTR(touchkey_back, S_IRUGO, back_key_state_show, NULL); +static DEVICE_ATTR(touchkey_home, S_IRUGO, home_key_state_show, NULL); +static DEVICE_ATTR(touchkey_recent, S_IRUGO, recent_key_state_show, NULL); +static DEVICE_ATTR(touchkey_menu, S_IRUGO, menu_key_state_show, NULL); +static DEVICE_ATTR(touchkey_raw_data0, S_IRUGO, tkey_rawcounter_show0, NULL) ; +static DEVICE_ATTR(touchkey_raw_data1, S_IRUGO, tkey_rawcounter_show1, NULL) ; +static DEVICE_ATTR(touchkey_raw_data2, S_IRUGO, tkey_rawcounter_show2, NULL) ; +static DEVICE_ATTR(touchkey_raw_data3, S_IRUGO, tkey_rawcounter_show3, NULL) ; + +static struct attribute *touchkey_attributes[] = { + &dev_attr_touchkey_threshold.attr, + &dev_attr_touchkey_back.attr, + &dev_attr_touchkey_home.attr, + &dev_attr_touchkey_recent.attr, + &dev_attr_touchkey_menu.attr, + &dev_attr_touchkey_raw_data0.attr, + &dev_attr_touchkey_raw_data1.attr, + &dev_attr_touchkey_raw_data2.attr, + &dev_attr_touchkey_raw_data3.attr, + NULL, +}; +static struct attribute_group touchkey_attr_group = { + .attrs = touchkey_attributes, +}; + +static int factory_init_tk(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + int ret; + + info->dev_tk = device_create(sec_class, NULL, (dev_t)NULL, info, + "sec_touchkey"); + if (IS_ERR(info->dev_tk)) { + dev_err(&client->dev, "Failed to create fac touchkey dev\n"); + ret = -ENODEV; + info->dev_tk = NULL; + goto err_create_dev_tk; + } + + ret = sysfs_create_group(&info->dev_tk->kobj, &touchkey_attr_group); + if (ret) { + dev_err(&client->dev, + "Failed to create sysfs (touchkey_attr_group).\n"); + ret = (ret > 0) ? -ret : ret; + goto err_create_tk_sysfs; + } + + info->key_pressed = kzalloc(sizeof(bool) * ARRAY_SIZE(info->keycode), + GFP_KERNEL); + if (!info->key_pressed) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_alloc; + } + + return 0; + +err_alloc: + sysfs_remove_group(&info->dev_tk->kobj, &touchkey_attr_group); +err_create_tk_sysfs: +err_create_dev_tk: + return ret; +} +#endif + +static DEVICE_ATTR(close_tsp_test, S_IRUGO, show_close_tsp_test, NULL); +static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, store_cmd); +static DEVICE_ATTR(cmd_status, S_IRUGO, show_cmd_status, NULL); +static DEVICE_ATTR(cmd_result, S_IRUGO, show_cmd_result, NULL); +#ifdef ESD_DEBUG +static DEVICE_ATTR(intensity_logging_on, S_IRUGO, show_intensity_logging_on, + NULL); +static DEVICE_ATTR(intensity_logging_off, S_IRUGO, show_intensity_logging_off, + NULL); +#endif + +static struct attribute *sec_touch_facotry_attributes[] = { + &dev_attr_close_tsp_test.attr, + &dev_attr_cmd.attr, + &dev_attr_cmd_status.attr, + &dev_attr_cmd_result.attr, +#ifdef ESD_DEBUG + &dev_attr_intensity_logging_on.attr, + &dev_attr_intensity_logging_off.attr, +#endif + NULL, +}; + +static struct attribute_group sec_touch_factory_attr_group = { + .attrs = sec_touch_facotry_attributes, +}; +#endif /* SEC_TSP_FACTORY_TEST */ + +static int __devinit mms_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct mms_ts_info *info; + struct input_dev *input_dev; + int ret = 0; + int i = 0; +#ifdef SEC_TSP_FACTORY_TEST + struct device *fac_dev_ts; +#endif + touch_is_pressed = 0; + + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -EIO; + + info = kzalloc(sizeof(struct mms_ts_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_alloc; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev, "Failed to allocate memory for input device\n"); + ret = -ENOMEM; + goto err_input_alloc; + } + + info->client = client; + info->input_dev = input_dev; + info->pdata = client->dev.platform_data; + info->irq = -1; + mutex_init(&info->lock); + if (info->pdata) { + info->max_x = info->pdata->max_x; + info->max_y = info->pdata->max_y; + info->invert_x = info->pdata->invert_x; + info->invert_y = info->pdata->invert_y; + info->config_fw_version = info->pdata->config_fw_version; + info->register_cb = info->pdata->register_cb; + } else { + info->max_x = 480; + info->max_y = 800; + } + + info->callbacks.inform_charger = melfas_ta_cb; + if (info->register_cb) + info->register_cb(&info->callbacks); + + input_mt_init_slots(input_dev, MAX_FINGERS); + + snprintf(info->phys, sizeof(info->phys), + "%s/input0", dev_name(&client->dev)); + input_dev->name = "sec_touchscreen"; /*= "Melfas MMSxxx Touchscreen";*/ + input_dev->phys = info->phys; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_WIDTH, 0, 0); + input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, MAX_PRESSURE, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, info->max_x, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, info->max_y, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, + 9, 0, 0); + + if (info->pdata->use_touchkey) { + dev_info(&client->dev, + "Melfas ts use touchkey\n"); + info->use_touchkey = info->pdata->use_touchkey; + memcpy(info->keycode, info->pdata->touchkey_keycode, + sizeof(info->pdata->touchkey_keycode)); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(EV_LED, input_dev->evbit); + __set_bit(LED_MISC, input_dev->ledbit); + for (i = 0; i < ARRAY_SIZE(info->keycode); i++) + set_bit(info->keycode[i], input_dev->keybit); + } + + input_set_drvdata(input_dev, info); + + ret = input_register_device(input_dev); + if (ret) { + dev_err(&client->dev, "failed to register input dev (%d)\n", + ret); + goto err_reg_input_dev; + } + +#if TOUCH_BOOSTER + mutex_init(&info->dvfs_lock); + INIT_DELAYED_WORK(&info->work_dvfs_off, set_dvfs_off); + INIT_DELAYED_WORK(&info->work_dvfs_chg, change_dvfs_lock); + info->dvfs_lock_status = false; +#endif + + i2c_set_clientdata(client, info); + + ret = mms_ts_fw_load(info); + if (ret) { + dev_err(&client->dev, "failed to initialize (%d)\n", ret); + goto err_config; + } + + info->enabled = true; + +#ifdef CONFIG_HAS_EARLYSUSPEND + info->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + info->early_suspend.suspend = mms_ts_early_suspend; + info->early_suspend.resume = mms_ts_late_resume; + register_early_suspend(&info->early_suspend); +#endif + +#ifdef SEC_TSP_FACTORY_TEST + INIT_LIST_HEAD(&info->cmd_list_head); + for (i = 0; i < ARRAY_SIZE(tsp_cmds); i++) + list_add_tail(&tsp_cmds[i].list, &info->cmd_list_head); + + mutex_init(&info->cmd_lock); + info->cmd_is_running = false; + + fac_dev_ts = device_create(sec_class, + NULL, 0, info, "tsp"); + if (IS_ERR(fac_dev_ts)) + dev_err(&client->dev, "Failed to create device for the sysfs\n"); + + ret = sysfs_create_group(&fac_dev_ts->kobj, + &sec_touch_factory_attr_group); + if (ret) + dev_err(&client->dev, "Failed to create sysfs group\n"); +#endif + + +#ifdef SEC_TKEY_FACTORY_TEST + ret = factory_init_tk(info); + if (ret < 0) { + dev_err(&client->dev, "failed to init factory init (tk)\n"); + goto err_factory_init; + } +#endif + return 0; + +#ifdef SEC_TKEY_FACTORY_TEST +err_factory_init: + free_irq(info->irq, info); +#endif +err_config: + input_unregister_device(input_dev); + input_dev = NULL; +err_reg_input_dev: + input_free_device(input_dev); +err_input_alloc: + kfree(info->fw_name); + kfree(info); +err_alloc: + return ret; +} + +static int __devexit mms_ts_remove(struct i2c_client *client) +{ + struct mms_ts_info *info = i2c_get_clientdata(client); + + if (info->irq >= 0) + free_irq(info->irq, info); + input_unregister_device(info->input_dev); +#ifdef SEC_TKEY_FACTORY_TEST + sysfs_remove_group(&info->dev_tk->kobj, &touchkey_attr_group); + kfree(info->key_pressed); +#endif + kfree(info->fw_name); + kfree(info); + + return 0; +} + +#if defined(CONFIG_PM) || defined(CONFIG_HAS_EARLYSUSPEND) +static int mms_ts_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mms_ts_info *info = i2c_get_clientdata(client); + + dev_notice(&info->client->dev, "%s: users=%d\n", __func__, + info->input_dev->users); + mutex_lock(&info->input_dev->mutex); + if (!info->input_dev->users) + goto out; + + mms_ts_disable(info, 0); + touch_is_pressed = 0; + release_all_fingers(info); + info->pdata->vdd_on(0); + +out: + mutex_unlock(&info->input_dev->mutex); + return 0; +} + +static int mms_ts_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mms_ts_info *info = i2c_get_clientdata(client); + int ret = 0; + + dev_notice(&info->client->dev, "%s: users=%d\n", __func__, + info->input_dev->users); + info->pdata->vdd_on(1); + msleep(120); + mms_set_noise_mode(info); + mutex_lock(&info->input_dev->mutex); + if (info->input_dev->users) + ret = mms_ts_enable(info, 0); + mutex_unlock(&info->input_dev->mutex); + + return ret; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mms_ts_early_suspend(struct early_suspend *h) +{ + struct mms_ts_info *info; + info = container_of(h, struct mms_ts_info, early_suspend); + mms_ts_suspend(&info->client->dev); +} + +static void mms_ts_late_resume(struct early_suspend *h) +{ + struct mms_ts_info *info; + info = container_of(h, struct mms_ts_info, early_suspend); + mms_ts_resume(&info->client->dev); +} +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static const struct dev_pm_ops mms_ts_pm_ops = { + .suspend = mms_ts_suspend, + .resume = mms_ts_resume, +}; +#endif + +static const struct i2c_device_id mms_ts_id[] = { + { "mms_ts", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mms_ts_id); + +static struct i2c_driver mms_ts_driver = { + .probe = mms_ts_probe, + .remove = __devexit_p(mms_ts_remove), + .driver = { + .name = "mms_ts", +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) + .pm = &mms_ts_pm_ops, +#endif + }, + .id_table = mms_ts_id, +}; + +static int __init mms_ts_init(void) +{ + + return i2c_add_driver(&mms_ts_driver); +} + +static void __exit mms_ts_exit(void) +{ + i2c_del_driver(&mms_ts_driver); +} + +module_init(mms_ts_init); +module_exit(mms_ts_exit); + +/* Module information */ +MODULE_DESCRIPTION("Touchscreen driver for Melfas MMS-series controllers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/mms_ts_136_tablet.c b/drivers/input/touchscreen/mms_ts_136_tablet.c new file mode 100644 index 00000000000..03ff4c18691 --- /dev/null +++ b/drivers/input/touchscreen/mms_ts_136_tablet.c @@ -0,0 +1,2481 @@ +/* + * mms_ts.c - Touchscreen driver for Melfas MMS-series touch controllers + * + * Copyright (C) 2011 Google Inc. + * Author: Dima Zavin + * Simon Wilson + * + * ISP reflashing code based on original code from Melfas. + * + * 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. + * + */ + +#define DEBUG +/* #define VERBOSE_DEBUG */ +#define SEC_TSP_DEBUG +/* #define SEC_TSP_VERBOSE_DEBUG */ + +/* #define FORCE_FW_FLASH */ +/* #define FORCE_FW_PASS */ +/* #define ESD_DEBUG */ + +#define SEC_TSP_FACTORY_TEST +#define SEC_TSP_FW_UPDATE +#define TSP_BUF_SIZE 1024 +#define FAIL -1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include "mms_ts_fw.h" +#include "../../../arch/arm/mach-msm/board-8960.h" + + + + +#define MAX_FINGERS 10 +#define MAX_WIDTH 30 +#define MAX_PRESSURE 255 + +/* Registers */ +#define MMS_MODE_CONTROL 0x01 +#define MMS_XYRES_HI 0x02 +#define MMS_XRES_LO 0x03 +#define MMS_YRES_LO 0x04 + +#define MMS_INPUT_EVENT_PKT_SZ 0x0F +#define MMS_INPUT_EVENT0 0x10 +#define FINGER_EVENT_SZ 6 + +#define MMS_TSP_REVISION 0xF0 +#define MMS_HW_REVISION 0xF1 +#define MMS_COMPAT_GROUP 0xF2 +#define MMS_FW_VERSION 0xF5 + +enum { + ISP_MODE_FLASH_ERASE = 0x59F3, + ISP_MODE_FLASH_WRITE = 0x62CD, + ISP_MODE_FLASH_READ = 0x6AC9, +}; + +/* each address addresses 4-byte words */ +#define ISP_MAX_FW_SIZE (0x1F00 * 4) +#define ISP_IC_INFO_ADDR 0x1F00 + +#ifdef CONFIG_SEC_DVFS +#define TOUCH_BOOSTER 1 +#define TOUCH_BOOSTER_OFF_TIME 100 +#define TOUCH_BOOSTER_CHG_TIME 200 +#endif + +#ifdef SEC_TSP_FW_UPDATE + +#define WORD_SIZE 4 + +#define ISC_PKT_SIZE 1029 +#define ISC_PKT_DATA_SIZE 1024 +#define ISC_PKT_HEADER_SIZE 3 +#define ISC_PKT_NUM 31 + +#define ISC_ENTER_ISC_CMD 0x5F +#define ISC_ENTER_ISC_DATA 0x01 +#define ISC_CMD 0xAE +#define ISC_ENTER_UPDATE_DATA 0x55 +#define ISC_ENTER_UPDATE_DATA_LEN 9 +#define ISC_DATA_WRITE_SUB_CMD 0xF1 +#define ISC_EXIT_ISC_SUB_CMD 0x0F +#define ISC_EXIT_ISC_SUB_CMD2 0xF0 +#define ISC_CHECK_STATUS_CMD 0xAF +#define ISC_CONFIRM_CRC 0x03 +#define ISC_DEFAULT_CRC 0xFFFF + +#endif + +#ifdef SEC_TSP_FACTORY_TEST +#define TX_NUM 22 +#define RX_NUM 13 +#define NODE_NUM 286 /* 22x13 */ + +/* VSC(Vender Specific Command) */ +#define MMS_VSC_CMD 0xB0 /* vendor specific command */ +#define MMS_VSC_MODE 0x1A /* mode of vendor */ + +#define MMS_VSC_CMD_ENTER 0X01 +#define MMS_VSC_CMD_CM_DELTA 0X02 +#define MMS_VSC_CMD_CM_ABS 0X03 +#define MMS_VSC_CMD_EXIT 0X05 +#define MMS_VSC_CMD_INTENSITY 0X04 +#define MMS_VSC_CMD_RAW 0X06 +#define MMS_VSC_CMD_REFER 0X07 +#define MMS_VSC_CMD_SELFTEST 0X08 + + +#define TSP_CMD_STR_LEN 32 +#define TSP_CMD_RESULT_STR_LEN 512 +#define TSP_CMD_PARAM_NUM 8 +#endif /* SEC_TSP_FACTORY_TEST */ +enum fw_flash_mode { + ISP_FLASH, + ISC_FLASH, +}; + +#define NUM_OF_KEY 3 + +enum { + BUILT_IN = 0, + UMS, +}; + +struct mms_ts_info { + struct i2c_client *client; + struct input_dev *input_dev; + char phys[32]; + + int max_x; + int max_y; + + bool invert_x; + bool invert_y; + const u8 *config_fw_version; + int irq; + + struct mms_ts_platform_data *pdata; + + char *fw_name; + struct early_suspend early_suspend; + int touch_is_pressed; +#if TOUCH_BOOSTER + struct delayed_work work_dvfs_off; + struct delayed_work work_dvfs_chg; + bool dvfs_lock_status; + struct mutex dvfs_lock; +#endif + + /* protects the enabled flag */ + struct mutex lock; + bool enabled; + + enum fw_flash_mode fw_flash_mode; +#if defined(SEC_TSP_DEBUG) || defined(SEC_TSP_VERBOSE_DEBUG) + unsigned char finger_state[MAX_FINGERS]; +#endif + +#if defined(SEC_TSP_FW_UPDATE) + u8 fw_update_state; +#endif + u8 fw_ic_ver; + +#if defined(SEC_TSP_FACTORY_TEST) + struct list_head cmd_list_head; + u8 cmd_state; + char cmd[TSP_CMD_STR_LEN]; + int cmd_param[TSP_CMD_PARAM_NUM]; + char cmd_result[TSP_CMD_RESULT_STR_LEN]; + struct mutex cmd_lock; + bool cmd_is_running; + + unsigned int reference[NODE_NUM]; + unsigned int raw[NODE_NUM]; /* CM_ABS */ + unsigned int inspection[NODE_NUM];/* CM_DELTA */ + unsigned int intensity[NODE_NUM]; + bool ft_flag; + bool if_con_sense_flag; +#endif /* SEC_TSP_FACTORY_TEST */ +}; + +static int get_if_con_sense_state(void) +{ + return (gpio_get_value_cansleep( + PM8921_GPIO_PM_TO_SYS(28))) ^ 1; +} + +struct mms_fw_image { + __le32 hdr_len; + __le32 data_len; + __le32 fw_ver; + __le32 hdr_ver; + u8 data[0]; +} __packed; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mms_ts_early_suspend(struct early_suspend *h); +static void mms_ts_late_resume(struct early_suspend *h); +#endif + +#if defined(SEC_TSP_FACTORY_TEST) +#define TSP_CMD(name, func) .cmd_name = name, .cmd_func = func + +struct tsp_cmd { + struct list_head list; + const char *cmd_name; + void (*cmd_func)(void *device_data); +}; + +static void fw_update(void *device_data); +static void get_fw_ver_bin(void *device_data); +static void get_fw_ver_ic(void *device_data); +static void get_config_ver(void *device_data); +static void get_threshold(void *device_data); +static void module_off_master(void *device_data); +static void module_on_master(void *device_data); +static void get_chip_vendor(void *device_data); +static void get_chip_name(void *device_data); +static void get_reference(void *device_data); +static void get_cm_abs(void *device_data); +static void get_cm_delta(void *device_data); +static void get_intensity(void *device_data); +static void get_x_num(void *device_data); +static void get_y_num(void *device_data); +static void run_reference_read(void *device_data); +static void run_cm_abs_read(void *device_data); +static void run_cm_delta_read(void *device_data); +static void run_intensity_read(void *device_data); +static void not_support_cmd(void *device_data); + +struct tsp_cmd tsp_cmds[] = { + {TSP_CMD("fw_update", fw_update),}, + {TSP_CMD("get_fw_ver_bin", get_fw_ver_bin),}, + {TSP_CMD("get_fw_ver_ic", get_fw_ver_ic),}, + {TSP_CMD("get_config_ver", get_config_ver),}, + {TSP_CMD("get_threshold", get_threshold),}, + {TSP_CMD("module_off_master", module_off_master),}, + {TSP_CMD("module_on_master", module_on_master),}, + {TSP_CMD("module_off_slave", not_support_cmd),}, + {TSP_CMD("module_on_slave", not_support_cmd),}, + {TSP_CMD("get_chip_vendor", get_chip_vendor),}, + {TSP_CMD("get_chip_name", get_chip_name),}, + {TSP_CMD("get_x_num", get_x_num),}, + {TSP_CMD("get_y_num", get_y_num),}, + {TSP_CMD("get_reference", get_reference),}, + {TSP_CMD("get_cm_abs", get_cm_abs),}, + {TSP_CMD("get_cm_delta", get_cm_delta),}, + {TSP_CMD("get_intensity", get_intensity),}, + {TSP_CMD("run_reference_read", run_reference_read),}, + {TSP_CMD("run_cm_abs_read", run_cm_abs_read),}, + {TSP_CMD("run_cm_delta_read", run_cm_delta_read),}, + {TSP_CMD("run_intensity_read", run_intensity_read),}, + {TSP_CMD("not_support_cmd", not_support_cmd),}, +}; +#endif + +#if TOUCH_BOOSTER +static void change_dvfs_lock(struct work_struct *work) +{ + struct mms_ts_info *info = container_of(work, + struct mms_ts_info, work_dvfs_chg.work); + int ret; + + mutex_lock(&info->dvfs_lock); + ret = cpufreq_set_limit(TOUCH_BOOSTER_FIRST_STOP, 0); + mutex_unlock(&info->dvfs_lock); + + if (ret < 0) + pr_err("%s: 1booster stop failed(%d)\n", + __func__, __LINE__); + else + pr_info("[TSP] %s\n", __func__); +} + +static void set_dvfs_off(struct work_struct *work) +{ + struct mms_ts_info *info = container_of(work, + struct mms_ts_info, work_dvfs_off.work); + int ret; + mutex_lock(&info->dvfs_lock); + cpufreq_set_limit(TOUCH_BOOSTER_FIRST_STOP, 0); + cpufreq_set_limit(TOUCH_BOOSTER_SECOND_STOP, 0); + info->dvfs_lock_status = false; + mutex_unlock(&info->dvfs_lock); + + pr_info("[TSP] DVFS Off!\n"); +} + +static void set_dvfs_lock(struct mms_ts_info *info, uint32_t on) +{ + int ret = 0, ret2 = 0; + + mutex_lock(&info->dvfs_lock); + if (on == 0) { + if (info->dvfs_lock_status) { + cancel_delayed_work(&info->work_dvfs_chg); + schedule_delayed_work(&info->work_dvfs_off, + msecs_to_jiffies(TOUCH_BOOSTER_OFF_TIME)); + } + } else if (on == 1) { + cancel_delayed_work(&info->work_dvfs_off); + if (!info->dvfs_lock_status) { + ret = cpufreq_set_limit(TOUCH_BOOSTER_SECOND_START, 0); + ret2 = cpufreq_set_limit(TOUCH_BOOSTER_FIRST_START, 0); + if (ret < 0 || ret2 < 0) + pr_err("%s: cpu lock failed(%d, %d)\n", + __func__, ret, ret2); + + schedule_delayed_work(&info->work_dvfs_chg, + msecs_to_jiffies(TOUCH_BOOSTER_CHG_TIME)); + info->dvfs_lock_status = true; + pr_info("[TSP] DVFS On!\n"); + } + } else if (on == 2) { + cancel_delayed_work(&info->work_dvfs_off); + cancel_delayed_work(&info->work_dvfs_chg); + schedule_work(&info->work_dvfs_off.work); + } + mutex_unlock(&info->dvfs_lock); +} +#endif + + + + +static void set_cmd_result(struct mms_ts_info *info, char *buff, int len); +static inline void mms_pwr_on_reset(struct mms_ts_info *info); + +static void reset_mms_ts(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + int i; + + if (info->enabled == false) + return; + + dev_notice(&client->dev, "%s++\n", __func__); + disable_irq_nosync(info->irq); + info->enabled = false; + info->touch_is_pressed = 0; + + for (i = 0; i < MAX_FINGERS; i++) { +#ifdef SEC_TSP_DEBUG + if (info->finger_state[i] == 1) + dev_notice(&client->dev, "finger %d up(force)\n", i); + + info->finger_state[i] = 0; +#endif + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, + false); + } + input_sync(info->input_dev); + +#if TOUCH_BOOSTER + set_dvfs_lock(info, 2); + pr_info("[TSP] dvfs_lock free.\n "); +#endif + + mms_pwr_on_reset(info); + enable_irq(info->irq); + info->enabled = true; + + dev_notice(&client->dev, "%s--\n", __func__); + +} + +static irqreturn_t mms_ts_interrupt(int irq, void *dev_id) +{ + struct mms_ts_info *info = dev_id; + struct i2c_client *client = info->client; + u8 buf[MAX_FINGERS*FINGER_EVENT_SZ] = { 0 }; + int ret; + int i; + int sz; + u8 reg = MMS_INPUT_EVENT0; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .buf = ®, + .len = 1, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = buf, + }, + }; + + sz = i2c_smbus_read_byte_data(client, MMS_INPUT_EVENT_PKT_SZ); + if (sz < 0) { + dev_err(&client->dev, "%s bytes=%d\n", __func__, sz); + for (i = 0; i < 50; i++) { + sz = i2c_smbus_read_byte_data(client, + MMS_INPUT_EVENT_PKT_SZ); + if (sz > 0) + break; + } + + if (i == 50) { + dev_dbg(&client->dev, "i2c failed... reset!!\n"); + goto err_i2c_fail; + } + } + + if (sz > MAX_FINGERS*FINGER_EVENT_SZ) { + dev_err(&client->dev, "[TSP] abnormal data inputed.\n"); + goto out; + } + + if (sz == 0) + goto out; + + msg[1].len = sz; + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(&client->dev, + "failed to read %d bytes of touch data (%d), mms reset\n", + sz, ret); + goto out; + } + +#if defined(VERBOSE_DEBUG) + print_hex_dump(KERN_DEBUG, "mms_ts raw: ", + DUMP_PREFIX_OFFSET, 32, 1, buf, sz, false); + +#endif + + if (buf[0] == 0xF) { + dev_dbg(&client->dev, "Burst / ESD detected\n"); + if (info->if_con_sense_flag) { + printk(KERN_ERR "PBA state, no reset!!"); + return IRQ_HANDLED; + } else { + printk(KERN_ERR "ESD detected, reset!!"); + goto err_i2c_fail; + } + } + + for (i = 0; i < sz; i += FINGER_EVENT_SZ) { + u8 *tmp = &buf[i]; + int id = (tmp[0] & 0xf) - 1; + int x = tmp[2] | ((tmp[1] & 0xf) << 8); + int y = tmp[3] | (((tmp[1] >> 4) & 0xf) << 8); + + if (info->invert_x) { + x = info->max_x - x; + if (x < 0) + x = 0; + } + if (info->invert_y) { + y = info->max_y - y; + if (y < 0) + y = 0; + } + + if (id >= MAX_FINGERS) { + dev_dbg(&client->dev, + "is not normal coordinate, mms reset [%d]\n", id); + goto err_not_normal; + } + + if ((tmp[0] & 0x80) == 0) { + dev_dbg(&client->dev, "finger [%d] up\n", id); + + input_mt_slot(info->input_dev, id); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, false); + +#if defined(SEC_TSP_DEBUG) || defined(SEC_TSP_VERBOSE_DEBUG) + info->finger_state[id] = 0; +#endif + continue; + } + + input_mt_slot(info->input_dev, id); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, true); + input_report_abs(info->input_dev, + ABS_MT_TOUCH_MAJOR, tmp[4]); + input_report_abs(info->input_dev, + ABS_MT_PRESSURE, tmp[5]); + input_report_abs(info->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(info->input_dev, + ABS_MT_POSITION_Y, y); + + if (info->finger_state[id] == 0) { + info->finger_state[id] = 1; + dev_dbg(&client->dev, + "finger %d down\n", id); + } + + } + input_sync(info->input_dev); + + info->touch_is_pressed = 0; + + for (i = 0; i < MAX_FINGERS; i++) { + if (info->finger_state[i] == 1) + info->touch_is_pressed++; + } + +#if TOUCH_BOOSTER + set_dvfs_lock(info, !!info->touch_is_pressed); +#endif + + +out: + return IRQ_HANDLED; +err_not_normal: +err_i2c_fail: + reset_mms_ts(info); + return IRQ_HANDLED; +} + +static void hw_reboot(struct mms_ts_info *info, bool bootloader) +{ + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, bootloader ? 0 : 1); + gpio_direction_output(info->pdata->gpio_scl, bootloader ? 0 : 1); + gpio_direction_output(info->pdata->gpio_resetb, 0); + msleep(30); + info->pdata->vdd_on(1); + msleep(30); + + if (bootloader) { + gpio_set_value(info->pdata->gpio_scl, 0); + gpio_set_value(info->pdata->gpio_sda, 1); + } else { + gpio_set_value(info->pdata->gpio_resetb, 1); + gpio_direction_input(info->pdata->gpio_resetb); + gpio_direction_input(info->pdata->gpio_scl); + gpio_direction_input(info->pdata->gpio_sda); + } + msleep(40); +} + +static inline void hw_reboot_bootloader(struct mms_ts_info *info) +{ + hw_reboot(info, true); +} + +static inline void hw_reboot_normal(struct mms_ts_info *info) +{ + hw_reboot(info, false); +} + +static inline void mms_pwr_on_reset(struct mms_ts_info *info) +{ + struct i2c_adapter *adapter = to_i2c_adapter(info->client->dev.parent); + + if (!info->pdata->mux_fw_flash) { + dev_info(&info->client->dev, + "missing platform data, can't do power-on-reset\n"); + return; + } + + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, 1); + gpio_direction_output(info->pdata->gpio_scl, 1); + gpio_direction_output(info->pdata->gpio_resetb, 1); + msleep(50); + info->pdata->vdd_on(1); + msleep(50); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + /* TODO: Seems long enough for the firmware to boot. + * Find the right value */ + msleep(250); +} + +static void isp_toggle_clk(struct mms_ts_info *info, int start_lvl, int end_lvl, + int hold_us) +{ + gpio_set_value(info->pdata->gpio_scl, start_lvl); + udelay(hold_us); + gpio_set_value(info->pdata->gpio_scl, end_lvl); + udelay(hold_us); +} + +/* 1 <= cnt <= 32 bits to write */ +static void isp_send_bits(struct mms_ts_info *info, u32 data, int cnt) +{ + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 0); + + /* clock out the bits, msb first */ + while (cnt--) { + gpio_set_value(info->pdata->gpio_sda, (data >> cnt) & 1); + udelay(3); + isp_toggle_clk(info, 1, 0, 3); + } +} + +/* 1 <= cnt <= 32 bits to read */ +static u32 isp_recv_bits(struct mms_ts_info *info, int cnt) +{ + u32 data = 0; + + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_set_value(info->pdata->gpio_sda, 0); + gpio_direction_input(info->pdata->gpio_sda); + + /* clock in the bits, msb first */ + while (cnt--) { + isp_toggle_clk(info, 0, 1, 1); + data = (data << 1) | (!!gpio_get_value(info->pdata->gpio_sda)); + } + + gpio_direction_output(info->pdata->gpio_sda, 0); + return data; +} + +static void isp_enter_mode(struct mms_ts_info *info, u32 mode) +{ + int cnt; + unsigned long flags; + + local_irq_save(flags); + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 1); + + mode &= 0xffff; + for (cnt = 15; cnt >= 0; cnt--) { + gpio_set_value(info->pdata->gpio_resetb, (mode >> cnt) & 1); + udelay(3); + isp_toggle_clk(info, 1, 0, 3); + } + + gpio_set_value(info->pdata->gpio_resetb, 0); + local_irq_restore(flags); +} + +static void isp_exit_mode(struct mms_ts_info *info) +{ + int i; + unsigned long flags; + + local_irq_save(flags); + gpio_direction_output(info->pdata->gpio_resetb, 0); + udelay(3); + + for (i = 0; i < 10; i++) + isp_toggle_clk(info, 1, 0, 3); + local_irq_restore(flags); +} + +static void flash_set_address(struct mms_ts_info *info, u16 addr) +{ + /* Only 13 bits of addr are valid. + * The addr is in bits 13:1 of cmd */ + isp_send_bits(info, (u32)(addr & 0x1fff) << 1, 18); +} + +static void flash_erase(struct mms_ts_info *info) +{ + isp_enter_mode(info, ISP_MODE_FLASH_ERASE); + + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 1); + + /* 4 clock cycles with different timings for the erase to + * get processed, clk is already 0 from above */ + udelay(7); + isp_toggle_clk(info, 1, 0, 3); + udelay(7); + isp_toggle_clk(info, 1, 0, 3); + usleep_range(25000, 35000); + isp_toggle_clk(info, 1, 0, 3); + usleep_range(150, 200); + isp_toggle_clk(info, 1, 0, 3); + + gpio_set_value(info->pdata->gpio_sda, 0); + + isp_exit_mode(info); +} + +static u32 flash_readl(struct mms_ts_info *info, u16 addr) +{ + int i; + u32 val; + unsigned long flags; + + local_irq_save(flags); + isp_enter_mode(info, ISP_MODE_FLASH_READ); + flash_set_address(info, addr); + + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 0); + udelay(40); + + /* data load cycle */ + for (i = 0; i < 6; i++) + isp_toggle_clk(info, 1, 0, 10); + + val = isp_recv_bits(info, 32); + isp_exit_mode(info); + local_irq_restore(flags); + + return val; +} + +static void flash_writel(struct mms_ts_info *info, u16 addr, u32 val) +{ + unsigned long flags; + + local_irq_save(flags); + isp_enter_mode(info, ISP_MODE_FLASH_WRITE); + flash_set_address(info, addr); + isp_send_bits(info, val, 32); + + gpio_direction_output(info->pdata->gpio_sda, 1); + /* 6 clock cycles with different timings for the data to get written + * into flash */ + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 6); + isp_toggle_clk(info, 0, 1, 12); + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 3); + + isp_toggle_clk(info, 1, 0, 1); + + gpio_direction_output(info->pdata->gpio_sda, 0); + isp_exit_mode(info); + local_irq_restore(flags); + usleep_range(300, 400); +} + +static bool flash_is_erased(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + u32 val; + u16 addr; + + for (addr = 0; addr < (ISP_MAX_FW_SIZE / 4); addr++) { + udelay(40); + val = flash_readl(info, addr); + + if (val != 0xffffffff) { + dev_dbg(&client->dev, + "addr 0x%x not erased: 0x%08x != 0xffffffff\n", + addr, val); + return false; + } + } + return true; +} + +static int fw_write_image(struct mms_ts_info *info, const u8 *data, size_t len) +{ + struct i2c_client *client = info->client; + u16 addr = 0; + + for (addr = 0; addr < (len / 4); addr++, data += 4) { + u32 val = get_unaligned_le32(data); + u32 verify_val; + int retries = 3; + + while (retries--) { + flash_writel(info, addr, val); + verify_val = flash_readl(info, addr); + if (val == verify_val) + break; + dev_err(&client->dev, + "mismatch @ addr 0x%x: 0x%x != 0x%x\n", + addr, verify_val, val); + continue; + } + if (retries < 0) + return -ENXIO; + } + + return 0; +} + +static int fw_download(struct mms_ts_info *info, const u8 *data, size_t len) +{ + struct i2c_client *client = info->client; + u32 val; + int ret = 0; + + if (len % 4) { + dev_err(&client->dev, + "fw image size (%d) must be a multiple of 4 bytes\n", + len); + return -EINVAL; + } else if (len > ISP_MAX_FW_SIZE) { + dev_err(&client->dev, + "fw image is too big, %d > %d\n", len, ISP_MAX_FW_SIZE); + return -EINVAL; + } + + dev_info(&client->dev, "fw download start\n"); + + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_resetb, 0); + + hw_reboot_bootloader(info); + + val = flash_readl(info, ISP_IC_INFO_ADDR); + dev_info(&client->dev, "IC info: 0x%02x (%x)\n", val & 0xff, val); + + dev_info(&client->dev, "fw erase...\n"); + flash_erase(info); + if (!flash_is_erased(info)) { + ret = -ENXIO; + goto err; + } + + dev_info(&client->dev, "fw write...\n"); + /* XXX: what does this do?! */ + flash_writel(info, ISP_IC_INFO_ADDR, 0xffffff00 | (val & 0xff)); + usleep_range(1000, 1500); + ret = fw_write_image(info, data, len); + if (ret) + goto err; + usleep_range(1000, 1500); + + hw_reboot_normal(info); + usleep_range(1000, 1500); + dev_info(&client->dev, "fw download done...\n"); + return 0; + +err: + dev_err(&client->dev, "fw download failed...\n"); + hw_reboot_normal(info); + return ret; +} + +#if defined(SEC_TSP_ISC_FW_UPDATE) +static u16 gen_crc(u8 data, u16 pre_crc) +{ + u16 crc; + u16 cur; + u16 temp; + u16 bit_1; + u16 bit_2; + int i; + + crc = pre_crc; + for (i = 7; i >= 0; i--) { + cur = ((data >> i) & 0x01) ^ (crc & 0x0001); + bit_1 = cur ^ (crc >> 11 & 0x01); + bit_2 = cur ^ (crc >> 4 & 0x01); + temp = (cur << 4) | (crc >> 12 & 0x0F); + temp = (temp << 7) | (bit_1 << 6) | (crc >> 5 & 0x3F); + temp = (temp << 4) | (bit_2 << 3) | (crc >> 1 & 0x0007); + crc = temp; + } + return crc; +} + +static int isc_fw_download(struct mms_ts_info *info, const u8 *data, + size_t len) +{ + u8 *buff; + u16 crc_buf; + int src_idx; + int dest_idx; + int ret; + int i, j; + + buff = kzalloc(ISC_PKT_SIZE, GFP_KERNEL); + if (!buff) { + dev_err(&info->client->dev, "%s: failed to allocate memory\n", + __func__); + ret = -1; + goto err_mem_alloc; + } + + /* enterring ISC mode */ + *buff = ISC_ENTER_ISC_DATA; + ret = i2c_smbus_write_byte_data(info->client, + ISC_ENTER_ISC_CMD, *buff); + if (ret < 0) { + dev_err(&info->client->dev, + "fail to enter ISC mode(err=%d)\n", ret); + goto fail_to_isc_enter; + } + usleep_range(10000, 20000); + dev_info(&info->client->dev, "Enter ISC mode\n"); + + /*enter ISC update mode */ + *buff = ISC_ENTER_UPDATE_DATA; + ret = i2c_smbus_write_i2c_block_data(info->client, + ISC_CMD, + ISC_ENTER_UPDATE_DATA_LEN, buff); + if (ret < 0) { + dev_err(&info->client->dev, + "fail to enter ISC update mode(err=%d)\n", ret); + goto fail_to_isc_update; + } + dev_info(&info->client->dev, "Enter ISC update mode\n"); + + /* firmware write */ + *buff = ISC_CMD; + *(buff + 1) = ISC_DATA_WRITE_SUB_CMD; + for (i = 0; i < ISC_PKT_NUM; i++) { + *(buff + 2) = i; + crc_buf = gen_crc(*(buff + 2), ISC_DEFAULT_CRC); + + for (j = 0; j < ISC_PKT_DATA_SIZE; j++) { + dest_idx = ISC_PKT_HEADER_SIZE + j; + src_idx = i * ISC_PKT_DATA_SIZE + + ((int)(j / WORD_SIZE)) * WORD_SIZE - + (j % WORD_SIZE) + 3; + *(buff + dest_idx) = *(data + src_idx); + crc_buf = gen_crc(*(buff + dest_idx), crc_buf); + } + + *(buff + ISC_PKT_DATA_SIZE + ISC_PKT_HEADER_SIZE + 1) = + crc_buf & 0xFF; + *(buff + ISC_PKT_DATA_SIZE + ISC_PKT_HEADER_SIZE) = + crc_buf >> 8 & 0xFF; + + ret = i2c_master_send(info->client, buff, ISC_PKT_SIZE); + if (ret < 0) { + dev_err(&info->client->dev, + "fail to firmware writing on packet %d.(%d)\n", + i, ret); + goto fail_to_fw_write; + } + usleep_range(1, 5); + + /* confirm CRC */ + ret = i2c_smbus_read_byte_data(info->client, + ISC_CHECK_STATUS_CMD); + if (ret == ISC_CONFIRM_CRC) { + dev_info(&info->client->dev, + "updating %dth firmware data packet.\n", i); + } else { + dev_err(&info->client->dev, + "fail to firmware update on %dth (%X).\n", + i, ret); + ret = -1; + goto fail_to_confirm_crc; + } + } + + ret = 0; + +fail_to_confirm_crc: +fail_to_fw_write: + /* exit ISC mode */ + *buff = ISC_EXIT_ISC_SUB_CMD; + *(buff + 1) = ISC_EXIT_ISC_SUB_CMD2; + i2c_smbus_write_i2c_block_data(info->client, ISC_CMD, 2, buff); + usleep_range(10000, 20000); +fail_to_isc_update: + hw_reboot_normal(info); +fail_to_isc_enter: + kfree(buff); +err_mem_alloc: + return ret; +} +#endif /* SEC_TSP_ISC_FW_UPDATE */ + +static int get_fw_version(struct mms_ts_info *info) +{ + int ret; + int retries = 3; + + do { + ret = i2c_smbus_read_byte_data(info->client, MMS_FW_VERSION); + } while (ret < 0 && retries-- > 0); + + return ret; +} + +static int get_hw_version(struct mms_ts_info *info) +{ + int ret; + int retries = 3; + + /* this seems to fail sometimes after a reset.. retry a few times */ + do { + ret = i2c_smbus_read_byte_data(info->client, MMS_HW_REVISION); + } while (ret < 0 && retries-- > 0); + + return ret; +} + +static int mms_ts_enable(struct mms_ts_info *info, int wakeupcmd) +{ + mutex_lock(&info->lock); + if (info->enabled) + goto out; + /* wake up the touch controller. */ + if (wakeupcmd == 1) { + i2c_smbus_write_byte_data(info->client, 0, 0); + usleep_range(3000, 5000); + } + info->enabled = true; + enable_irq(info->irq); +out: + mutex_unlock(&info->lock); + return 0; +} + +static int mms_ts_disable(struct mms_ts_info *info, int sleepcmd) +{ + mutex_lock(&info->lock); + if (!info->enabled) + goto out; + disable_irq(info->irq); + if (sleepcmd == 1) { + i2c_smbus_write_byte_data(info->client, MMS_MODE_CONTROL, 0); + usleep_range(10000, 12000); + } + info->enabled = false; + info->touch_is_pressed = 0; +out: + mutex_unlock(&info->lock); + return 0; +} + +static int mms_ts_finish_config(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + int ret; + + ret = request_threaded_irq(client->irq, NULL, mms_ts_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "mms_ts", info); + if (ret < 0) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_req_irq; + } + + info->irq = client->irq; + barrier(); + + dev_info(&client->dev, + "Melfas MMS-series touch controller initialized\n"); + + return 0; + +err_req_irq: + return ret; +} + +static int mms_ts_fw_load(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret = 0; + int ver, module_rev; + int retries = 3; + + ver = get_fw_version(info); + info->fw_ic_ver = ver; + dev_info(&client->dev, + "[TSP]fw version 0x%02x !!!!\n", ver); + + if (ver < 0) { + ver = 0; + dev_err(&client->dev, + "can't read version,controller dead? FW update!\n"); + } + + module_rev = get_hw_version(info); + dev_info(&client->dev, + "[TSP]MODULE revision 0x%02x !!!!\n", module_rev); + + if (module_rev < 0) { + module_rev = 0; + dev_err(&client->dev, + "can't read revision,controller dead? FW update!\n"); + } + + if (!info->pdata || !info->pdata->mux_fw_flash) { + ret = 1; + dev_err(&client->dev, + "fw cannot be updated, missing platform data\n"); + goto out; + } + + if (module_rev == 0x10 && info->pdata->check_module_type) { + dev_info(&client->dev, + "fw version update does not need - old module\n"); + goto done; + } + + if (ver >= FW_VERSION) { + dev_info(&client->dev, + "fw version update does not need\n"); + goto done; + } + + while (retries--) { + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + ret = fw_download(info, MELFAS_binary, MELFAS_binary_nLength); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + if (ret < 0) { + dev_err(&client->dev, "retrying flashing\n"); + continue; + } + + ver = get_fw_version(info); + info->fw_ic_ver = ver; + + if (ver == FW_VERSION) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + goto done; + } else { + dev_err(&client->dev, + "ERROR: fw update succeeded, but fw version is still wrong (0x%x != 0x%x)\n", + ver, FW_VERSION); + } + dev_err(&client->dev, "retrying flashing\n"); + } + +out: + return ret; + +done: + ret = mms_ts_finish_config(info); + return ret; +} + +#ifdef SEC_TSP_FACTORY_TEST +static inline int msm_irq_to_gpio(unsigned irq) +{ + /* TODO : Need to verify chip->base=0 */ + return irq - MSM_GPIO_TO_INT(0); +} +static void get_raw_data_all(struct mms_ts_info *info, u8 cmd) +{ + u8 w_buf[6]; + u8 read_buffer[2]; /* 52 */ + char buff[TSP_CMD_STR_LEN] = {0}; + int gpio; + int ret; + int i, j; + u32 max_val = 0, min_val = 0; + u32 raw_data; + + gpio = msm_irq_to_gpio(info->irq); + disable_irq(info->irq); + + w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */ + w_buf[1] = MMS_VSC_MODE; /* mode of vendor */ + w_buf[2] = 0; /* tx line */ + w_buf[3] = 0; /* rx line */ + w_buf[4] = 0; /* reserved */ + w_buf[5] = 0; /* sub command */ + + if (cmd == MMS_VSC_CMD_EXIT) { + w_buf[5] = MMS_VSC_CMD_EXIT; /* exit test mode */ + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + info->pdata->vdd_on(0); + msleep(30); + info->pdata->vdd_on(1); + msleep(120); + enable_irq(info->irq); + return ; + } + + /* MMS_VSC_CMD_CM_DELTA or MMS_VSC_CMD_CM_ABS + * this two mode need to enter the test mode + * exit command must be followed by testing. + */ + if (cmd == MMS_VSC_CMD_CM_DELTA || cmd == MMS_VSC_CMD_CM_ABS) { + /* enter the debug mode */ + w_buf[2] = 0x0; /* tx */ + w_buf[3] = 0x0; /* rx */ + w_buf[5] = MMS_VSC_CMD_ENTER; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + + /* wating for the interrupt */ + while (gpio_get_value(gpio)) + udelay(100); + } + + for (i = 0; i < RX_NUM; i++) { + for (j = 0; j < TX_NUM; j++) { + + w_buf[2] = j; /* tx */ + w_buf[3] = i; /* rx */ + w_buf[5] = cmd; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + + usleep_range(1, 5); + + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, + 2, read_buffer); + if (ret < 0) + goto err_i2c; + + raw_data = ((u16)read_buffer[1] << 8) | read_buffer[0]; + + if (i == 0 && j == 0) + max_val = min_val = raw_data; + + max_val = max(max_val, raw_data); + min_val = min(min_val, raw_data); + + if (cmd == MMS_VSC_CMD_INTENSITY) { + info->intensity[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "[TSP] intensity[%d][%d] = %d\n", + i, j, info->intensity[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_CM_DELTA) { + info->inspection[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "[TSP] delta[%d][%d] = %d\n", + i, j, info->inspection[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_CM_ABS) { + info->raw[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "[TSP] raw[%d][%d] = %d\n", + i, j, info->raw[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_REFER) { + info->reference[j * RX_NUM + i] = + raw_data >> 3; + dev_dbg(&info->client->dev, "[TSP] reference[%d][%d] = %d\n", + i, j, info->reference[j * RX_NUM + i]); + } + } + } + + snprintf(buff, sizeof(buff), "%d,%d", min_val, max_val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + enable_irq(info->irq); + return; + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); + return; +} + +#ifdef ESD_DEBUG +static u32 get_raw_data_one(struct mms_ts_info *info, u16 rx_idx, u16 tx_idx, + u8 cmd) +{ + u8 w_buf[6]; + u8 read_buffer[2]; + int ret; + u32 raw_data; + + w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */ + w_buf[1] = MMS_VSC_MODE; /* mode of vendor */ + w_buf[2] = 0; /* tx line */ + w_buf[3] = 0; /* rx line */ + w_buf[4] = 0; /* reserved */ + w_buf[5] = 0; /* sub command */ + + if (cmd != MMS_VSC_CMD_INTENSITY && cmd != MMS_VSC_CMD_RAW && + cmd != MMS_VSC_CMD_REFER) { + dev_err(&info->client->dev, "%s: not profer command(cmd=%d)\n", + __func__, cmd); + return FAIL; + } + + w_buf[2] = tx_idx; /* tx */ + w_buf[3] = rx_idx; /* rx */ + w_buf[5] = cmd; /* sub command */ + + ret = i2c_smbus_write_i2c_block_data(info->client, w_buf[0], 5, + &w_buf[1]); + if (ret < 0) + goto err_i2c; + + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, 2, + read_buffer); + if (ret < 0) + goto err_i2c; + + raw_data = ((u16)read_buffer[1] << 8) | read_buffer[0]; + if (cmd == MMS_VSC_CMD_REFER) + raw_data = raw_data >> 4; + + return raw_data; + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); + return FAIL; +} +#endif + +static ssize_t show_close_tsp_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->ft_flag = 0; + + return snprintf(buf, TSP_BUF_SIZE, "%u\n", 0); +} + +static void set_default_result(struct mms_ts_info *info) +{ + char delim = ':'; + + memset(info->cmd_result, 0x00, ARRAY_SIZE(info->cmd_result)); + memcpy(info->cmd_result, info->cmd, strlen(info->cmd)); + strncat(info->cmd_result, &delim, 1); +} + +static void set_cmd_result(struct mms_ts_info *info, char *buff, int len) +{ + strncat(info->cmd_result, buff, len); +} + +static int check_rx_tx_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[TSP_CMD_STR_LEN] = {0}; + int node; + + if (info->cmd_param[0] < 0 || + info->cmd_param[0] >= RX_NUM || + info->cmd_param[1] < 0 || + info->cmd_param[1] >= TX_NUM) { + snprintf(buff, sizeof(buff) , "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: parameter error: %u,%u\n", + __func__, info->cmd_param[0], + info->cmd_param[1]); + node = -1; + return node; + } + node = info->cmd_param[1] * RX_NUM + info->cmd_param[0]; + dev_info(&info->client->dev, "%s: node = %d\n", __func__, + node); + return node; + +} + +static void not_support_cmd(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + char buff[16] = {0}; + + set_default_result(info); + sprintf(buff, "%s", "NA"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 4; + dev_info(&info->client->dev, "%s: \"%s(%d)\"\n", __func__, + buff, strnlen(buff, sizeof(buff))); + return; +} + +static void fw_update(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + struct i2c_client *client = info->client; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret = 0; + int ver, module_rev; + int retries = 3; + const u8 *buff; + mm_segment_t old_fs = {0}; + struct file *fp = {0}; + long fsize, nread; + + #define MMS_TS "/sdcard/melfas_fw.bin" + + set_default_result(info); + + module_rev = get_hw_version(info); + dev_info(&client->dev, + "[TSP]MODULE revision 0x%02x !!!!\n", module_rev); + + if (module_rev == 0x10 && info->pdata->check_module_type) { + dev_err(&client->dev, + "fw version update does not need - old module\n"); + goto do_not_need_update; + } + + if (info->cmd_param[0] == 0 + && info->fw_ic_ver >= FW_VERSION) { + dev_info(&client->dev, + "fw version update does not need\n"); + goto do_not_need_update; + } + + switch (info->cmd_param[0]) { + case BUILT_IN: + buff = MELFAS_binary; + fsize = MELFAS_binary_nLength; + dev_info(&client->dev, "built in fw is loaded!!\n"); + break; + + case UMS: + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(MMS_TS, O_RDONLY, S_IRUSR); + + if (IS_ERR(fp)) { + dev_err(&client->dev, + "file %s open error:%d\n", MMS_TS, (s32)fp); + goto err_open; + } + + fsize = fp->f_path.dentry->d_inode->i_size; + + buff = kzalloc((size_t)fsize, GFP_KERNEL); + if (!buff) { + dev_err(&client->dev, "fail to alloc buffer for fw\n"); + goto err_alloc; + } + + nread = vfs_read(fp, (char __user *)buff, fsize, &fp->f_pos); + if (nread != fsize) { + dev_err(&client->dev, "fail to read file %s (nread = %ld)\n", + MMS_TS, nread); + goto err_fw_size; + } + + filp_close(fp, current->files); + set_fs(old_fs); + dev_info(&client->dev, "ums fw is loaded!!\n"); + break; + + default: + dev_err(&client->dev, "invalid fw file type!!\n"); + goto not_support; + } + + disable_irq(info->irq); + while (retries--) { + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + ret = fw_download(info, (const u8 *)buff, + (const size_t)fsize); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + if (ret < 0) { + dev_err(&client->dev, "retrying flashing\n"); + continue; + } + + ver = get_fw_version(info); + info->fw_ic_ver = ver; + + if (ver == FW_VERSION) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + info->cmd_state = 2; + enable_irq(info->irq); + return; + } else { + dev_err(&client->dev, + "ERROR :fw version is still wrong (0x%x != 0x%x)\n", + ver, FW_VERSION); + } + dev_err(&client->dev, "retrying flashing\n"); + } + +err_fw_size: + kfree(buff); +err_alloc: + filp_close(fp, NULL); +err_open: + set_fs(old_fs); +not_support: +do_not_need_update: + info->cmd_state = 2; + return; +} + +static void get_fw_ver_bin(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + snprintf(buff, sizeof(buff), "%#02x", FW_VERSION); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_fw_ver_ic(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int ver; + + set_default_result(info); + + ver = info->fw_ic_ver; + snprintf(buff, sizeof(buff), "%#02x", ver); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_config_ver(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[20] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", info->config_fw_version); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_threshold(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int threshold; + + set_default_result(info); + + threshold = i2c_smbus_read_byte_data(info->client, 0x05); + if (threshold < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + return; + } + snprintf(buff, sizeof(buff), "%d", threshold); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void module_off_master(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[3] = {0}; + + mutex_lock(&info->lock); + if (info->enabled) { + disable_irq(info->irq); + info->enabled = false; + info->touch_is_pressed = 0; + } + mutex_unlock(&info->lock); + + info->pdata->vdd_on(0); + + if (info->pdata->is_vdd_on() == 0) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = 2; + else + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: %s\n", __func__, buff); +} + +static void module_on_master(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[3] = {0}; + + mms_pwr_on_reset(info); + + mutex_lock(&info->lock); + if (!info->enabled) { + enable_irq(info->irq); + info->enabled = true; + } + mutex_unlock(&info->lock); + + if (info->pdata->is_vdd_on() == 1) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = 2; + else + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: %s\n", __func__, buff); + +} + +static void get_chip_vendor(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", "MELFAS"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_chip_name(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", "MMS136"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_reference(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return ; + + val = info->reference[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_cm_abs(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->raw[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); + } + +static void get_cm_delta(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->inspection[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_intensity(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return ; + + val = info->intensity[node]; + + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_x_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int val; + + set_default_result(info); + val = i2c_smbus_read_byte_data(info->client, 0xEF); + if (val < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_info(&info->client->dev, + "%s: fail to read num of x (%d).\n", __func__, val); + return ; + } + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_y_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int val; + + set_default_result(info); + val = i2c_smbus_read_byte_data(info->client, 0xEE); + if (val < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_info(&info->client->dev, + "%s: fail to read num of y (%d).\n", __func__, val); + + return ; + } + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void run_reference_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_REFER); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s:\n", __func__); +} + +static void run_cm_abs_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_CM_ABS); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s:\n", __func__); +} + +static void run_cm_delta_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_CM_DELTA); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s:\n", __func__); +} + +static void run_intensity_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_INTENSITY); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s:\n", __func__); +} + +static ssize_t store_cmd(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + + char *cur, *start, *end; + char buff[TSP_CMD_STR_LEN] = {0}; + int len, i; + struct tsp_cmd *tsp_cmd_ptr = NULL; + char delim = ','; + bool cmd_found = false; + int param_cnt = 0; + + + if (info->cmd_is_running == true) { + dev_err(&info->client->dev, "tsp_cmd: other cmd is running.\n"); + goto err_out; + } + + + /* check lock */ + mutex_lock(&info->cmd_lock); + info->cmd_is_running = true; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = 1; + + for (i = 0; i < ARRAY_SIZE(info->cmd_param); i++) + info->cmd_param[i] = 0; + + len = (int)count; + if (*(buf + len - 1) == '\n') + len--; + memset(info->cmd, 0x00, ARRAY_SIZE(info->cmd)); + memcpy(info->cmd, buf, len); + + cur = strchr(buf, (int)delim); + if (cur) + memcpy(buff, buf, cur - buf); + else + memcpy(buff, buf, len); + + /* find command */ + list_for_each_entry(tsp_cmd_ptr, &info->cmd_list_head, list) { + if (!strcmp(buff, tsp_cmd_ptr->cmd_name)) { + cmd_found = true; + break; + } + } + + /* set not_support_cmd */ + if (!cmd_found) { + list_for_each_entry(tsp_cmd_ptr, &info->cmd_list_head, list) { + if (!strcmp("not_support_cmd", tsp_cmd_ptr->cmd_name)) + break; + } + } + + /* parsing parameters */ + if (cur && cmd_found) { + cur++; + start = cur; + memset(buff, 0x00, ARRAY_SIZE(buff)); + do { + if (*cur == delim || cur - buf == len) { + end = cur; + memcpy(buff, start, end - start); + *(buff + strlen(buff)) = '\0'; + if (kstrtoint(buff, 10, + info->cmd_param + param_cnt) < 0) + goto err_out; + start = cur + 1; + memset(buff, 0x00, ARRAY_SIZE(buff)); + param_cnt++; + } + cur++; + } while (cur - buf <= len); + } + + dev_info(&client->dev, "cmd = %s\n", tsp_cmd_ptr->cmd_name); + for (i = 0; i < param_cnt; i++) + dev_info(&client->dev, "cmd param %d= %d\n", i, + info->cmd_param[i]); + + tsp_cmd_ptr->cmd_func(info); + +err_out: + return count; +} + +static ssize_t show_cmd_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + char buff[16] = {0}; + + dev_info(&info->client->dev, "tsp cmd: status:%d\n", + info->cmd_state); + + if (info->cmd_state == 0) + snprintf(buff, sizeof(buff), "WAITING"); + + else if (info->cmd_state == 1) + snprintf(buff, sizeof(buff), "RUNNING"); + + else if (info->cmd_state == 2) + snprintf(buff, sizeof(buff), "OK"); + + else if (info->cmd_state == 3) + snprintf(buff, sizeof(buff), "FAIL"); + + else if (info->cmd_state == 4) + snprintf(buff, sizeof(buff), "NOT_APPLICABLE"); + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", buff); +} + +static ssize_t show_cmd_result(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + + dev_info(&info->client->dev, "tsp cmd: result: %s\n", info->cmd_result); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = 0; + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", info->cmd_result); +} + +static ssize_t show_raw_data(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + + u8 w_buf[6]; + u8 read_buffer[2]; + int ret; + int i, j; + int ftn_ret = 0; + int intensity, reference; + + disable_irq(info->irq); + + w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */ + w_buf[1] = MMS_VSC_MODE; /* mode of vendor */ + w_buf[2] = 0; /* tx line */ + w_buf[3] = 0; /* rx line */ + w_buf[4] = 0; /* reserved */ + w_buf[5] = 0; /* sub command */ + + for (i = 0; i < RX_NUM; i++) { + for (j = 0; j < TX_NUM; j++) { + w_buf[2] = j; /* tx */ + w_buf[3] = i; /* rx */ + + w_buf[5] = MMS_VSC_CMD_INTENSITY; + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + usleep_range(1, 5); + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, + 2, read_buffer); + if (ret < 0) + goto err_i2c; + intensity = read_buffer[0]; + + if (intensity & 0x08) + intensity -= 256; + + dev_dbg(&info->client->dev, "[TSP] intensity[%d][%d] = %d\n", + i, j, intensity); + + w_buf[5] = MMS_VSC_CMD_REFER; + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + usleep_range(1, 5); + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, + 2, read_buffer); + if (ret < 0) + goto err_i2c; + reference = (((u16)read_buffer[1] << 8) | + read_buffer[0]) >> 3; + dev_dbg(&info->client->dev, "[TSP] reference[%d][%d] = %d\n", + i, j, reference); + + ftn_ret += sprintf(buf+ftn_ret, "%3d %3d\n", + intensity, reference); + } + } + + enable_irq(info->irq); + reset_mms_ts(info); + printk(KERN_ERR "%s: return = %d\n", __func__, ftn_ret) ; + + return ftn_ret; + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c\n", + __func__); + return 0; +} + +#ifdef ESD_DEBUG + +static bool intensity_log_flag; + +static ssize_t show_intensity_logging_on(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + struct file *fp; + char log_data[160] = {0,}; + char buff[16] = {0,}; + mm_segment_t old_fs; + long nwrite; + u32 val; + int i, y, c; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + +#define MELFAS_DEBUG_LOG_PATH "/sdcard/melfas_log" + + dev_info(&client->dev, "%s: start.\n", __func__); + fp = filp_open(MELFAS_DEBUG_LOG_PATH, O_RDWR|O_CREAT, + S_IRWXU|S_IRWXG|S_IRWXO); + if (IS_ERR(fp)) { + dev_err(&client->dev, "%s: fail to open log file\n", __func__); + goto open_err; + } + + intensity_log_flag = 1; + do { + for (y = 0; y < 3; y++) { + /* for tx chanel 0~2 */ + memset(log_data, 0x00, 160); + + snprintf(buff, 16, "%1u: ", y); + strncat(log_data, buff, strnlen(buff, 16)); + + for (i = 0; i < RX_NUM; i++) { + val = get_raw_data_one(info, i, y, + MMS_VSC_CMD_INTENSITY); + snprintf(buff, 16, "%5u, ", val); + strncat(log_data, buff, strnlen(buff, 16)); + } + memset(buff, '\n', 2); + c = (y == 2) ? 2 : 1; + strncat(log_data, buff, c); + nwrite = vfs_write(fp, (const char __user *)log_data, + strnlen(log_data, 160), &fp->f_pos); + } + usleep_range(5000); + } while (intensity_log_flag); + + filp_close(fp, current->files); + set_fs(old_fs); + + return 0; + + open_err: + set_fs(old_fs); + return FAIL; +} + +static ssize_t show_intensity_logging_off(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + intensity_log_flag = 0; + usleep_range(10000); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + return 0; +} + +#endif + +static DEVICE_ATTR(close_tsp_test, S_IRUGO, show_close_tsp_test, NULL); +static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, store_cmd); +static DEVICE_ATTR(cmd_status, S_IRUGO, show_cmd_status, NULL); +static DEVICE_ATTR(cmd_result, S_IRUGO, show_cmd_result, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, show_raw_data, NULL); +#ifdef ESD_DEBUG +static DEVICE_ATTR(intensity_logging_on, S_IRUGO, show_intensity_logging_on, + NULL); +static DEVICE_ATTR(intensity_logging_off, S_IRUGO, show_intensity_logging_off, + NULL); +#endif + +static struct attribute *sec_touch_facotry_attributes[] = { + &dev_attr_close_tsp_test.attr, + &dev_attr_cmd.attr, + &dev_attr_cmd_status.attr, + &dev_attr_cmd_result.attr, + &dev_attr_raw_data.attr, +#ifdef ESD_DEBUG + &dev_attr_intensity_logging_on.attr, + &dev_attr_intensity_logging_off.attr, +#endif + NULL, +}; + +static struct attribute_group sec_touch_factory_attr_group = { + .attrs = sec_touch_facotry_attributes, +}; +#endif /* SEC_TSP_FACTORY_TEST */ + +static int __devinit mms_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct mms_ts_info *info; + struct input_dev *input_dev; + int ret = 0; + int i = 0; +#ifdef SEC_TSP_FACTORY_TEST + struct device *fac_dev_ts; +#endif + + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -EIO; + + info = kzalloc(sizeof(struct mms_ts_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_mem_alloc; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev, "Failed to allocate memory for intput device\n"); + goto err_alloc; + } + + info->client = client; + info->input_dev = input_dev; + info->pdata = client->dev.platform_data; + info->irq = -1; + info->touch_is_pressed = 0; + mutex_init(&info->lock); + if (info->pdata) { + info->max_x = info->pdata->max_x; + info->max_y = info->pdata->max_y; + info->invert_x = info->pdata->invert_x; + info->invert_y = info->pdata->invert_y; + info->config_fw_version = info->pdata->config_fw_version; + } else { + info->max_x = 1024; + info->max_y = 600; + } + + input_mt_init_slots(input_dev, MAX_FINGERS); + + snprintf(info->phys, sizeof(info->phys), + "%s/input0", dev_name(&client->dev)); + input_dev->name = "sec_touchscreen"; /*= "Melfas MMSxxx Touchscreen";*/ + input_dev->phys = info->phys; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_WIDTH, 0, 0); + input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, MAX_PRESSURE, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, info->max_x, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, info->max_y, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, + 9, 0, 0); + + input_set_drvdata(input_dev, info); + + ret = input_register_device(input_dev); + if (ret) { + dev_err(&client->dev, "failed to register input dev (%d)\n", + ret); + goto err_reg_input_dev; + } + +#if TOUCH_BOOSTER + mutex_init(&info->dvfs_lock); + INIT_DELAYED_WORK(&info->work_dvfs_off, set_dvfs_off); + INIT_DELAYED_WORK(&info->work_dvfs_chg, change_dvfs_lock); + info->dvfs_lock_status = false; +#endif + + i2c_set_clientdata(client, info); + + ret = mms_ts_fw_load(info); + if (ret) { + dev_err(&client->dev, "failed to initialize (%d)\n", ret); + goto err_config; + } + + info->enabled = true; + +#ifdef CONFIG_HAS_EARLYSUSPEND + info->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + info->early_suspend.suspend = mms_ts_early_suspend; + info->early_suspend.resume = mms_ts_late_resume; + register_early_suspend(&info->early_suspend); +#endif + +#ifdef SEC_TSP_FACTORY_TEST + INIT_LIST_HEAD(&info->cmd_list_head); + for (i = 0; i < ARRAY_SIZE(tsp_cmds); i++) + list_add_tail(&tsp_cmds[i].list, &info->cmd_list_head); + + mutex_init(&info->cmd_lock); + info->cmd_is_running = false; + + fac_dev_ts = device_create(sec_class, + NULL, 0, info, "tsp"); + if (IS_ERR(fac_dev_ts)) + dev_err(&client->dev, "Failed to create device for the sysfs\n"); + + ret = sysfs_create_group(&fac_dev_ts->kobj, + &sec_touch_factory_attr_group); + if (ret) + dev_err(&client->dev, "Failed to create sysfs group\n"); + if (get_if_con_sense_state()) { + info->if_con_sense_flag = true; + printk(KERN_ERR "if_con_sense_flag = true"); + } else { + info->if_con_sense_flag = false; + printk(KERN_ERR "if_con_sense_flag = false"); + } +#endif + + return 0; + +err_config: + input_unregister_device(input_dev); + input_dev = NULL; +err_reg_input_dev: +err_alloc: + input_free_device(input_dev); + kfree(info->fw_name); + kfree(info); +err_mem_alloc: + return ret; +} + +static int __devexit mms_ts_remove(struct i2c_client *client) +{ + struct mms_ts_info *info = i2c_get_clientdata(client); + + if (info->irq >= 0) + free_irq(info->irq, info); + input_unregister_device(info->input_dev); + kfree(info->fw_name); + kfree(info); + + return 0; +} + +#if defined(CONFIG_PM) || defined(CONFIG_HAS_EARLYSUSPEND) +static int mms_ts_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mms_ts_info *info = i2c_get_clientdata(client); + int i; +#ifdef SEC_TSP_DEBUG + int mt_val; +#endif + + dev_notice(&info->client->dev, "%s: users=%d\n", __func__, + info->input_dev->users); + mutex_lock(&info->input_dev->mutex); + if (!info->input_dev->users) + goto out; + + mms_ts_disable(info, 0); + info->touch_is_pressed = 0; + for (i = 0; i < MAX_FINGERS; i++) { + +#ifdef SEC_TSP_DEBUG + input_mt_slot(info->input_dev, i); + mt_val = input_mt_get_value(&info->input_dev-> + mt[info->input_dev->slot], ABS_MT_TRACKING_ID); + + if ((info->finger_state[i] == 1 && mt_val == -1) || + (info->finger_state[i] == 0 && mt_val != -1)) + dev_notice(&client->dev, "mismatch occured. (%d)\n", i); + + if (info->finger_state[i] == 1) { + info->finger_state[i] = 0; + dev_notice(&client->dev, "finger %d up(force)\n", i); + } +#endif + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, + false); + } + input_sync(info->input_dev); + +#if TOUCH_BOOSTER + set_dvfs_lock(info, 2); + pr_info("[TSP] dvfs_lock free.\n"); +#endif + + info->pdata->vdd_on(0); + +out: + mutex_unlock(&info->input_dev->mutex); + return 0; +} + +static int mms_ts_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mms_ts_info *info = i2c_get_clientdata(client); + int ret = 0; + + dev_notice(&info->client->dev, "%s: users=%d\n", __func__, + info->input_dev->users); + info->pdata->vdd_on(1); + msleep(120); + mutex_lock(&info->input_dev->mutex); + if (info->input_dev->users) + ret = mms_ts_enable(info, 0); + mutex_unlock(&info->input_dev->mutex); + + return ret; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mms_ts_early_suspend(struct early_suspend *h) +{ + struct mms_ts_info *info; + info = container_of(h, struct mms_ts_info, early_suspend); + mms_ts_suspend(&info->client->dev); +} + +static void mms_ts_late_resume(struct early_suspend *h) +{ + struct mms_ts_info *info; + info = container_of(h, struct mms_ts_info, early_suspend); + mms_ts_resume(&info->client->dev); +} +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static const struct dev_pm_ops mms_ts_pm_ops = { + .suspend = mms_ts_suspend, + .resume = mms_ts_resume, +}; +#endif + +static const struct i2c_device_id mms_ts_id[] = { + { "mms_ts", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mms_ts_id); + +static struct i2c_driver mms_ts_driver = { + .probe = mms_ts_probe, + .remove = __devexit_p(mms_ts_remove), + .driver = { + .name = "mms_ts", +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) + .pm = &mms_ts_pm_ops, +#endif + }, + .id_table = mms_ts_id, +}; + +static int __init mms_ts_init(void) +{ + + return i2c_add_driver(&mms_ts_driver); +} + +static void __exit mms_ts_exit(void) +{ + i2c_del_driver(&mms_ts_driver); +} + +module_init(mms_ts_init); +module_exit(mms_ts_exit); + +/* Module information */ +MODULE_DESCRIPTION("Touchscreen driver for Melfas MMS-series controllers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/mms_ts_144.c b/drivers/input/touchscreen/mms_ts_144.c new file mode 100644 index 00000000000..a47fb9ba084 --- /dev/null +++ b/drivers/input/touchscreen/mms_ts_144.c @@ -0,0 +1,3199 @@ +/* + * mms_ts.c - Touchscreen driver for Melfas MMS-series touch controllers + * + * Copyright (C) 2011 Google Inc. + * Author: Dima Zavin + * Simon Wilson + * + * ISP reflashing code based on original code from Melfas. + * + * 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. + * + */ + +#define DEBUG +/* #define VERBOSE_DEBUG */ +/* #define SEC_TSP_DEBUG */ +#define SEC_TSP_VERBOSE_DEBUG + +/* #define FORCE_FW_FLASH */ +/* #define FORCE_FW_PASS */ +/* #define ESD_DEBUG */ + +#define SEC_TSP_FACTORY_TEST +#define SEC_TSP_FW_UPDATE +#define TSP_BUF_SIZE 1024 +#define FAIL -1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "mms_ts_fw.h" + +#define MAX_FINGERS 10 +#define MAX_WIDTH 30 +#define MAX_PRESSURE 255 +#define MAX_ANGLE 90 +#define MIN_ANGLE -90 + +/* Registers */ +#define MMS_MODE_CONTROL 0x01 +#define MMS_XYRES_HI 0x02 +#define MMS_XRES_LO 0x03 +#define MMS_YRES_LO 0x04 + +#define MMS_INPUT_EVENT_PKT_SZ 0x0F +#define MMS_INPUT_EVENT0 0x10 +#define FINGER_EVENT_SZ 8 + +#define MMS_TSP_REVISION 0xF0 +#define MMS_HW_REVISION 0xF1 +#define MMS_COMPAT_GROUP 0xF2 +#define MMS_FW_VERSION 0xF3 + +enum { + ISP_MODE_FLASH_ERASE = 0x59F3, + ISP_MODE_FLASH_WRITE = 0x62CD, + ISP_MODE_FLASH_READ = 0x6AC9, +}; + +/* each address addresses 4-byte words */ +#define ISP_MAX_FW_SIZE (0x1F00 * 4) +#define ISP_IC_INFO_ADDR 0x1F00 + +#if 0 +#define TOUCH_BOOSTER 1 +#define TOUCH_BOOSTER_OFF_TIME 100 +#define TOUCH_BOOSTER_CHG_TIME 200 +#endif + +#ifdef SEC_TSP_FW_UPDATE + +#define WORD_SIZE 4 + +#define ISC_PKT_SIZE 1029 +#define ISC_PKT_DATA_SIZE 1024 +#define ISC_PKT_HEADER_SIZE 3 +#define ISC_PKT_NUM 31 + +#define ISC_ENTER_ISC_CMD 0x5F +#define ISC_ENTER_ISC_DATA 0x01 +#define ISC_CMD 0xAE +#define ISC_ENTER_UPDATE_DATA 0x55 +#define ISC_ENTER_UPDATE_DATA_LEN 9 +#define ISC_DATA_WRITE_SUB_CMD 0xF1 +#define ISC_EXIT_ISC_SUB_CMD 0x0F +#define ISC_EXIT_ISC_SUB_CMD2 0xF0 +#define ISC_CHECK_STATUS_CMD 0xAF +#define ISC_CONFIRM_CRC 0x03 +#define ISC_DEFAULT_CRC 0xFFFF + +#endif + +#ifdef SEC_TSP_FACTORY_TEST +#define TX_NUM 26 +#define RX_NUM 14 +#define NODE_NUM 364 /* 26x14 */ + +/* VSC(Vender Specific Command) */ +#define MMS_VSC_CMD 0xB0 /* vendor specific command */ +#define MMS_VSC_MODE 0x1A /* mode of vendor */ + +#define MMS_VSC_CMD_ENTER 0X01 +#define MMS_VSC_CMD_CM_DELTA 0X02 +#define MMS_VSC_CMD_CM_ABS 0X03 +#define MMS_VSC_CMD_EXIT 0X05 +#define MMS_VSC_CMD_INTENSITY 0X04 +#define MMS_VSC_CMD_RAW 0X06 +#define MMS_VSC_CMD_REFER 0X07 + +#define TSP_CMD_STR_LEN 32 +#define TSP_CMD_RESULT_STR_LEN 512 +#define TSP_CMD_PARAM_NUM 8 +#endif /* SEC_TSP_FACTORY_TEST */ + +#if defined(CONFIG_MACH_STRETTO) || defined(CONFIG_MACH_SUPERIORLTE_SKT) +#define ISC_DL_MODE 0 +#else +#define ISC_DL_MODE 1 +#endif + +#if ISC_DL_MODE +/* Default configuration of ISC mode */ + +#define DEFAULT_SLAVE_ADDR 0x48 + +#define SECTION_NUM 4 +#define SECTION_NAME_LEN 5 + +#define PAGE_HEADER 3 +#define PAGE_DATA 1024 +#define PAGE_TAIL 2 +#define PACKET_SIZE (PAGE_HEADER + PAGE_DATA + PAGE_TAIL) +#define TS_WRITE_REGS_LEN 1030 + +#define TIMEOUT_CNT 10 +#define STRING_BUF_LEN 100 + + +/* State Registers */ +#define MIP_ADDR_INPUT_INFORMATION 0x01 + +#define ISC_ADDR_VERSION 0xE1 +#define ISC_ADDR_SECTION_PAGE_INFO 0xE5 + +/* Config Update Commands */ +#define ISC_CMD_ENTER_ISC 0x5F +#define ISC_CMD_ENTER_ISC_PARA1 0x01 +#define ISC_CMD_UPDATE_MODE 0xAE +#define ISC_SUBCMD_ENTER_UPDATE 0x55 +#define ISC_SUBCMD_DATA_WRITE 0XF1 +#define ISC_SUBCMD_LEAVE_UPDATE_PARA1 0x0F +#define ISC_SUBCMD_LEAVE_UPDATE_PARA2 0xF0 +#define ISC_CMD_CONFIRM_STATUS 0xAF + +#define ISC_STATUS_UPDATE_MODE 0x01 +#define ISC_STATUS_CRC_CHECK_SUCCESS 0x03 + +#define ISC_CHAR_2_BCD(num) (((num/10)<<4) + (num%10)) +#define ISC_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +static const char section_name[SECTION_NUM][SECTION_NAME_LEN] = { + "BOOT", "CORE", "PRIV", "PUBL" +}; + +static const unsigned char crc0_buf[31] = { + 0x1D, 0x2C, 0x05, 0x34, 0x95, 0xA4, 0x8D, 0xBC, + 0x59, 0x68, 0x41, 0x70, 0xD1, 0xE0, 0xC9, 0xF8, + 0x3F, 0x0E, 0x27, 0x16, 0xB7, 0x86, 0xAF, 0x9E, + 0x7B, 0x4A, 0x63, 0x52, 0xF3, 0xC2, 0xEB +}; + +static const unsigned char crc1_buf[31] = { + 0x1E, 0x9C, 0xDF, 0x5D, 0x76, 0xF4, 0xB7, 0x35, + 0x2A, 0xA8, 0xEB, 0x69, 0x42, 0xC0, 0x83, 0x01, + 0x04, 0x86, 0xC5, 0x47, 0x6C, 0xEE, 0xAD, 0x2F, + 0x30, 0xB2, 0xF1, 0x73, 0x58, 0xDA, 0x99 +}; + +enum eISCRet_t { + ISC_NONE = -1, + ISC_SUCCESS = 0, + ISC_FILE_OPEN_ERROR, + ISC_FILE_CLOSE_ERROR, + ISC_FILE_FORMAT_ERROR, + ISC_WRITE_BUFFER_ERROR, + ISC_I2C_ERROR, + ISC_UPDATE_MODE_ENTER_ERROR, + ISC_CRC_ERROR, + ISC_VALIDATION_ERROR, + ISC_COMPATIVILITY_ERROR, + ISC_UPDATE_SECTION_ERROR, + ISC_SLAVE_ERASE_ERROR, + ISC_SLAVE_DOWNLOAD_ERROR, + ISC_DOWNLOAD_WHEN_SLAVE_IS_UPDATED_ERROR, + ISC_INITIAL_PACKET_ERROR, + ISC_NO_NEED_UPDATE_ERROR, + ISC_LIMIT +}; + +enum eErrCode_t { + EC_NONE = -1, + EC_DEPRECATED = 0, + EC_BOOTLOADER_RUNNING = 1, + EC_BOOT_ON_SUCCEEDED = 2, + EC_ERASE_END_MARKER_ON_SLAVE_FINISHED = 3, + EC_SLAVE_DOWNLOAD_STARTS = 4, + EC_SLAVE_DOWNLOAD_FINISHED = 5, + EC_2CHIP_HANDSHAKE_FAILED = 0x0E, + EC_ESD_PATTERN_CHECKED = 0x0F, + EC_LIMIT +}; + +enum eSectionType_t { + SEC_NONE = -1, + SEC_BOOTLOADER = 0, + SEC_CORE, + SEC_PRIVATE_CONFIG, + SEC_PUBLIC_CONFIG, + SEC_LIMIT +}; + +struct tISCFWInfo_t { + unsigned char version; + unsigned char compatible_version; + unsigned char start_addr; + unsigned char end_addr; +}; + +static struct tISCFWInfo_t mbin_info[SECTION_NUM]; +static struct tISCFWInfo_t ts_info[SECTION_NUM]; /* read F/W version from IC */ +static bool section_update_flag[SECTION_NUM]; + +const struct firmware *fw_mbin[SECTION_NUM]; + +static unsigned char g_wr_buf[1024 + 3 + 2]; +#endif + +int touch_is_pressed; +EXPORT_SYMBOL(touch_is_pressed); + +enum fw_flash_mode { + ISP_FLASH, + ISC_FLASH, +}; + +enum { + BUILT_IN = 0, + UMS, +}; + +struct mms_ts_info { + struct i2c_client *client; + struct input_dev *input_dev; + char phys[32]; + + int max_x; + int max_y; + + bool invert_x; + bool invert_y; + const u8 *config_fw_version; + int irq; + + struct mms_ts_platform_data *pdata; + + char *fw_name; + struct early_suspend early_suspend; +#ifdef TOUCH_BOOSTER + struct delayed_work work_dvfs_off; + struct delayed_work work_dvfs_chg; + bool dvfs_lock_status; + struct mutex dvfs_lock; +#endif + + /* protects the enabled flag */ + struct mutex lock; + bool enabled; + + enum fw_flash_mode fw_flash_mode; + void (*register_cb)(struct tsp_callbacks *); + struct tsp_callbacks callbacks; + bool ta_status; + bool noise_mode; + +#if defined(SEC_TSP_DEBUG) || defined(SEC_TSP_VERBOSE_DEBUG) + unsigned char finger_state[MAX_FINGERS]; +#endif + +#if defined(SEC_TSP_FW_UPDATE) + u8 fw_update_state; +#endif +u8 fw_ic_ver; + +#if defined(SEC_TSP_FACTORY_TEST) + struct list_head cmd_list_head; + u8 cmd_state; + char cmd[TSP_CMD_STR_LEN]; + int cmd_param[TSP_CMD_PARAM_NUM]; + char cmd_result[TSP_CMD_RESULT_STR_LEN]; + struct mutex cmd_lock; + bool cmd_is_running; + + unsigned int reference[NODE_NUM]; + unsigned int raw[NODE_NUM]; /* CM_ABS */ + unsigned int inspection[NODE_NUM];/* CM_DELTA */ + unsigned int intensity[NODE_NUM]; + bool ft_flag; +#endif /* SEC_TSP_FACTORY_TEST */ +}; + +struct mms_fw_image { + __le32 hdr_len; + __le32 data_len; + __le32 fw_ver; + __le32 hdr_ver; + u8 data[0]; +} __packed; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mms_ts_early_suspend(struct early_suspend *h); +static void mms_ts_late_resume(struct early_suspend *h); +#endif + +#if defined(SEC_TSP_FACTORY_TEST) +#define TSP_CMD(name, func) .cmd_name = name, .cmd_func = func + +struct tsp_cmd { + struct list_head list; + const char *cmd_name; + void (*cmd_func)(void *device_data); +}; + +static void fw_update(void *device_data); +static void get_fw_ver_bin(void *device_data); +static void get_fw_ver_ic(void *device_data); +static void get_config_ver(void *device_data); +static void get_threshold(void *device_data); +static void module_off_master(void *device_data); +static void module_on_master(void *device_data); +static void get_chip_vendor(void *device_data); +static void get_chip_name(void *device_data); +static void get_reference(void *device_data); +static void get_cm_abs(void *device_data); +static void get_cm_delta(void *device_data); +static void get_intensity(void *device_data); +static void get_x_num(void *device_data); +static void get_y_num(void *device_data); +static void run_reference_read(void *device_data); +static void run_cm_abs_read(void *device_data); +static void run_cm_delta_read(void *device_data); +static void run_intensity_read(void *device_data); +static void not_support_cmd(void *device_data); + +struct tsp_cmd tsp_cmds[] = { + {TSP_CMD("fw_update", fw_update),}, + {TSP_CMD("get_fw_ver_bin", get_fw_ver_bin),}, + {TSP_CMD("get_fw_ver_ic", get_fw_ver_ic),}, + {TSP_CMD("get_config_ver", get_config_ver),}, + {TSP_CMD("get_threshold", get_threshold),}, + {TSP_CMD("module_off_master", module_off_master),}, + {TSP_CMD("module_on_master", module_on_master),}, + {TSP_CMD("module_off_slave", not_support_cmd),}, + {TSP_CMD("module_on_slave", not_support_cmd),}, + {TSP_CMD("get_chip_vendor", get_chip_vendor),}, + {TSP_CMD("get_chip_name", get_chip_name),}, + {TSP_CMD("get_x_num", get_x_num),}, + {TSP_CMD("get_y_num", get_y_num),}, + {TSP_CMD("get_reference", get_reference),}, + {TSP_CMD("get_cm_abs", get_cm_abs),}, + {TSP_CMD("get_cm_delta", get_cm_delta),}, + {TSP_CMD("get_intensity", get_intensity),}, + {TSP_CMD("run_reference_read", run_reference_read),}, + {TSP_CMD("run_cm_abs_read", run_cm_abs_read),}, + {TSP_CMD("run_cm_delta_read", run_cm_delta_read),}, + {TSP_CMD("run_intensity_read", run_intensity_read),}, + {TSP_CMD("not_support_cmd", not_support_cmd),}, +}; +#endif + +#ifdef TOUCH_BOOSTER +static void change_dvfs_lock(struct work_struct *work) +{ + struct mms_ts_info *info = container_of(work, + struct mms_ts_info, work_dvfs_chg.work); + int ret; + + mutex_lock(&info->dvfs_lock); + ret = cpufreq_set_limit(TOUCH_BOOSTER_FIRST_STOP, 0); + mutex_unlock(&info->dvfs_lock); + + if (ret < 0) + pr_err("%s: 1booster stop failed(%d)\n",\ + __func__, __LINE__); + else + pr_info("[TSP] %s", __func__); +} + +static void set_dvfs_off(struct work_struct *work) +{ + struct mms_ts_info *info = container_of(work, + struct mms_ts_info, work_dvfs_off.work); + mutex_lock(&info->dvfs_lock); + cpufreq_set_limit(TOUCH_BOOSTER_FIRST_STOP, 0); + cpufreq_set_limit(TOUCH_BOOSTER_SECOND_STOP, 0); + info->dvfs_lock_status = false; + mutex_unlock(&info->dvfs_lock); + + pr_info("[TSP] DVFS Off!"); +} + +static void set_dvfs_lock(struct mms_ts_info *info, uint32_t on) +{ + int ret = 0, ret2 = 0; + + mutex_lock(&info->dvfs_lock); + if (on == 0) { + if (info->dvfs_lock_status) { + cancel_delayed_work(&info->work_dvfs_chg); + schedule_delayed_work(&info->work_dvfs_off, + msecs_to_jiffies(TOUCH_BOOSTER_OFF_TIME)); + } + } else if (on == 1) { + cancel_delayed_work(&info->work_dvfs_off); + if (!info->dvfs_lock_status) { + ret = cpufreq_set_limit(TOUCH_BOOSTER_SECOND_START, 0); + ret2 = cpufreq_set_limit(TOUCH_BOOSTER_FIRST_START, 0); + if (ret < 0 || ret2 < 0) + pr_err("%s: cpu lock failed(%d, %d)\n",\ + __func__, ret, ret2); + + schedule_delayed_work(&info->work_dvfs_chg, + msecs_to_jiffies(TOUCH_BOOSTER_CHG_TIME)); + info->dvfs_lock_status = true; + pr_info("[TSP] DVFS On!"); + } + } else if (on == 2) { + cancel_delayed_work(&info->work_dvfs_off); + cancel_delayed_work(&info->work_dvfs_chg); + schedule_work(&info->work_dvfs_off.work); + } + mutex_unlock(&info->dvfs_lock); +} +#endif + +static void release_all_fingers(struct mms_ts_info *info) +{ +#ifdef SEC_TSP_DEBUG + struct i2c_client *client = info->client; +#endif + int i; + + printk(KERN_DEBUG "[TSP] %s\n", __func__); + + for (i = 0; i < MAX_FINGERS; i++) { +#ifdef SEC_TSP_DEBUG + if (info->finger_state[i] == 1) { + dev_dbg(&client->dev, "finger %d up(force)\n", i); + } +#endif + info->finger_state[i] = 0; + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, + false); + } + input_sync(info->input_dev); +#ifdef TOUCH_BOOSTER + set_dvfs_lock(info, 2); + pr_info("[TSP] dvfs_lock free.\n "); +#endif +} + +static void mms_set_noise_mode(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + + if (!(info->noise_mode && info->enabled)) + return; + dev_notice(&client->dev, "%s\n", __func__); + + if (info->ta_status) { + dev_notice(&client->dev, "noise_mode & TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x30, 0x1); + } else { + dev_notice(&client->dev, "noise_mode & TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x30, 0x2); + } +} + +static inline void mms_pwr_on_reset(struct mms_ts_info *info); + +static void reset_mms_ts(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + + if (info->enabled == false) + return; + + dev_notice(&client->dev, "%s++\n", __func__); + disable_irq_nosync(info->irq); + info->enabled = false; + touch_is_pressed = 0; + + release_all_fingers(info); + + mms_pwr_on_reset(info); + enable_irq(info->irq); + info->enabled = true; + + if (info->ta_status) { + dev_notice(&client->dev, "TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x1); + } else { + dev_notice(&client->dev, "TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x2); + mms_set_noise_mode(info); + } + + dev_notice(&client->dev, "%s--\n", __func__); +} + +static void melfas_ta_cb(struct tsp_callbacks *cb, bool ta_status) +{ + struct mms_ts_info *info = + container_of(cb, struct mms_ts_info, callbacks); + struct i2c_client *client = info->client; + + dev_notice(&client->dev, "%s\n", __func__); + + info->ta_status = ta_status; + + if (info->enabled) { + if (info->ta_status) { + dev_notice(&client->dev, "TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x1); + } else { + dev_notice(&client->dev, "TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x2); + mms_set_noise_mode(info); + } + } +} + +static irqreturn_t mms_ts_interrupt(int irq, void *dev_id) +{ + struct mms_ts_info *info = dev_id; + struct i2c_client *client = info->client; + u8 buf[MAX_FINGERS*FINGER_EVENT_SZ] = { 0 }; + int ret; + int i; + int sz; + u8 reg = MMS_INPUT_EVENT0; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .buf = ®, + .len = 1, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = buf, + }, + }; + + sz = i2c_smbus_read_byte_data(client, MMS_INPUT_EVENT_PKT_SZ); + if (sz < 0) { + dev_err(&client->dev, "%s bytes=%d\n", __func__, sz); + for (i = 0; i < 50; i++) { + sz = i2c_smbus_read_byte_data(client, + MMS_INPUT_EVENT_PKT_SZ); + if (sz > 0) + break; + } + + if (i == 50) { + dev_dbg(&client->dev, "i2c failed... reset!!\n"); + reset_mms_ts(info); + goto out; + } + } + /* BUG_ON(sz > MAX_FINGERS*FINGER_EVENT_SZ); */ + if (sz == 0) + goto out; + + if (sz > MAX_FINGERS*FINGER_EVENT_SZ) { + dev_err(&client->dev, "[TSP] abnormal data inputed.\n"); + goto out; + } + + msg[1].len = sz; + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(&client->dev, + "failed to read %d bytes of touch data (%d)\n", + sz, ret); + goto out; + } + +#if defined(VERBOSE_DEBUG) + print_hex_dump(KERN_DEBUG, "mms_ts raw: ", + DUMP_PREFIX_OFFSET, 32, 1, buf, sz, false); + +#endif + if (buf[0] == 0x0F) { /* ESD */ + dev_dbg(&client->dev, "ESD DETECT.... reset!!\n"); + reset_mms_ts(info); + goto out; + } + + if (buf[0] == 0x0E) { /* NOISE MODE */ + dev_dbg(&client->dev, "[TSP] noise mode enter!!\n"); + info->noise_mode = 1 ; + mms_set_noise_mode(info); + goto out; + } + + for (i = 0; i < sz; i += FINGER_EVENT_SZ) { + u8 *tmp = &buf[i]; + int id = (tmp[0] & 0xf) - 1; + int x = tmp[2] | ((tmp[1] & 0xf) << 8); + int y = tmp[3] | (((tmp[1] >> 4) & 0xf) << 8); + int angle = (tmp[5] >= 127) ? (-(256 - tmp[5])) : tmp[5]; + int palm = (buf[0] & 0x10) >> 4; + if (info->invert_x) { + x = info->max_x - x; + if (x < 0) + x = 0; + } + if (info->invert_y) { + y = info->max_y - y; + if (y < 0) + y = 0; + } + if (id >= MAX_FINGERS) { + dev_notice(&client->dev, \ + "finger id error [%d]\n", id); + reset_mms_ts(info); + goto out; + } + + if ((tmp[0] & 0x80) == 0) { +#if defined(SEC_TSP_DEBUG) + dev_dbg(&client->dev, + "finger id[%d]: x=%d y=%d p=%d w=%d major=%d minor=%d angle=%d palm=%d\n" + , id, x, y, tmp[5], tmp[4], tmp[6], tmp[7] + , angle, palm); +#endif + input_mt_slot(info->input_dev, id); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, false); + +#if defined(SEC_TSP_DEBUG) || defined(SEC_TSP_VERBOSE_DEBUG) + info->finger_state[id] = 0; +#endif + continue; + } + + input_mt_slot(info->input_dev, id); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, true); + input_report_abs(info->input_dev, ABS_MT_WIDTH_MAJOR, tmp[4]); +#if defined(CONFIG_MACH_K2_KDI) + input_report_abs(info->input_dev, ABS_MT_POSITION_X, + (info->max_x - x)); + input_report_abs(info->input_dev, ABS_MT_POSITION_Y, + (info->max_y - y)); +#else + input_report_abs(info->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y); +#endif + input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, tmp[6]); + input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, tmp[7]); + input_report_abs(info->input_dev, ABS_MT_ANGLE, angle); + input_report_abs(info->input_dev, ABS_MT_PALM, palm); +#if defined(SEC_TSP_DEBUG) + if (info->finger_state[id] == 0) { + info->finger_state[id] = 1; + dev_dbg(&client->dev, + "finger id[%d]: x=%d y=%d p=%d w=%d major=%d minor=%d angle=%d palm=%d\n" + , id, x, y, tmp[5], tmp[4], tmp[6], tmp[7] + , angle, palm); + } +#else + if (info->finger_state[id] == 0) { + info->finger_state[id] = 1; + } +#endif + } + + input_sync(info->input_dev); + touch_is_pressed = 0; + + for (i = 0; i < MAX_FINGERS; i++) { + if (info->finger_state[i] == 1) + touch_is_pressed++; + } + +#ifdef TOUCH_BOOSTER + set_dvfs_lock(info, !!touch_is_pressed); +#endif + +out: + return IRQ_HANDLED; +} + +#if ISC_DL_MODE +static int mms100_i2c_read(struct i2c_client *client, + u16 addr, u16 length, u8 *value) +{ + struct i2c_adapter *adapter = client->adapter; + struct i2c_msg msg; + int ret = -1; + + msg.addr = client->addr; + msg.flags = 0x00; + msg.len = 1; + msg.buf = (u8 *) &addr; + + ret = i2c_transfer(adapter, &msg, 1); + + if (ret >= 0) { + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = length; + msg.buf = (u8 *) value; + + ret = i2c_transfer(adapter, &msg, 1); + } + + if (ret < 0) + pr_err("[TSP] : read error : [%d]", ret); + + return ret; +} + + +static int mms100_reset(struct mms_ts_info *info) +{ + info->pdata->vdd_on(0); + msleep(30); + info->pdata->vdd_on(1); + msleep(300); + + return ISC_SUCCESS; +} +/* +static int mms100_check_operating_mode(struct i2c_client *_client, + const int _error_code) +{ + int ret; + unsigned char rd_buf = 0x00; + + if(_client == NULL) + pr_err("[TSP ISC] _client is null"); + + ret = mms100_i2c_read(_client, ISC_ADDR_VERSION, 1, &rd_buf); + + if (ret<0) { + pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return _error_code; + } + + return ISC_SUCCESS; +} +*/ +static int mms100_get_version_info(struct i2c_client *_client) +{ + int i, ret; + unsigned char rd_buf[8]; + + /* config version brust read (core, private, public) */ + ret = mms100_i2c_read(_client, ISC_ADDR_VERSION, 4, rd_buf); + + if (ret < 0) { + pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + for (i = 0; i < SECTION_NUM; i++) + ts_info[i].version = rd_buf[i]; + + ts_info[SEC_CORE].compatible_version = + ts_info[SEC_BOOTLOADER].version; + ts_info[SEC_PRIVATE_CONFIG].compatible_version = + ts_info[SEC_PUBLIC_CONFIG].compatible_version = + ts_info[SEC_CORE].version; + + ret = mms100_i2c_read(_client, ISC_ADDR_SECTION_PAGE_INFO, 8, rd_buf); + + if (ret < 0) { + pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + for (i = 0; i < SECTION_NUM; i++) { + ts_info[i].start_addr = rd_buf[i]; + ts_info[i].end_addr = rd_buf[i + SECTION_NUM]; + } + + for (i = 0; i < SECTION_NUM; i++) { + pr_info("TS : Section(%d) version: 0x%02X\n", + i, ts_info[i].version); + pr_info("TS : Section(%d) Start Address: 0x%02X\n", + i, ts_info[i].start_addr); + pr_info("TS : Section(%d) End Address: 0x%02X\n", + i, ts_info[i].end_addr); + pr_info("TS : Section(%d) Compatibility: 0x%02X\n", + i, ts_info[i].compatible_version); + } + + return ISC_SUCCESS; +} + +static int mms100_seek_section_info(void) +{ + int i; + char str_buf[STRING_BUF_LEN]; + char name_buf[SECTION_NAME_LEN]; + int version; + int page_num; + + const unsigned char *buf; + int next_ptr; + + for (i = 0; i < SECTION_NUM; i++) { + if (fw_mbin[i] == NULL) { + buf = NULL; + pr_info("[TSP ISC] fw_mbin[%d]->data is NULL", i); + } else { + buf = fw_mbin[i]->data; + } + + if (buf == NULL) { + mbin_info[i].version = ts_info[i].version; + mbin_info[i].compatible_version = + ts_info[i].compatible_version; + mbin_info[i].start_addr = ts_info[i].start_addr; + mbin_info[i].end_addr = ts_info[i].end_addr; + } else { + next_ptr = 0; + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "SECTION_NAME")); + + sscanf(buf + next_ptr, "%s%s", str_buf, name_buf); + + if (strncmp(section_name[i], name_buf, + SECTION_NAME_LEN)) + return ISC_FILE_FORMAT_ERROR; + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "SECTION_VERSION")); + + sscanf(buf + next_ptr, "%s%d", str_buf, &version); + mbin_info[i].version = ISC_CHAR_2_BCD(version); + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "START_PAGE_ADDR")); + + sscanf(buf + next_ptr, "%s%d", str_buf, &page_num); + mbin_info[i].start_addr = page_num; + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "END_PAGE_ADDR")); + + sscanf(buf + next_ptr, "%s%d", str_buf, &page_num); + mbin_info[i].end_addr = page_num; + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "COMPATIBLE_VERSION")); + + sscanf(buf + next_ptr, "%s%d", str_buf, &version); + mbin_info[i].compatible_version = + ISC_CHAR_2_BCD(version); + + do { + sscanf(buf + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "[Binary]")); + + if (mbin_info[i].version == 0xFF) + return ISC_FILE_FORMAT_ERROR; + } + } + + for (i = 0; i < SECTION_NUM; i++) { + pr_info("[TSP ISC] MBin : Section(%d) Version: 0x%02X\n", + i, mbin_info[i].version); + pr_info("[TSP ISC] MBin : Section(%d) Start Address: 0x%02X\n", + i, mbin_info[i].start_addr); + pr_info("[TSP ISC] MBin : Section(%d) End Address: 0x%02X\n", + i, mbin_info[i].end_addr); + pr_info("[TSP ISC] MBin : Section(%d) Compatibility: 0x%02X\n", + i, mbin_info[i].compatible_version); + } + + return ISC_SUCCESS; +} + +static int mms100_compare_version_info(struct i2c_client *_client) +{ + int i, ret; + unsigned char expected_compatibility[SECTION_NUM]; + + if (mms100_get_version_info(_client) != ISC_SUCCESS) + return ISC_I2C_ERROR; + + ret = mms100_seek_section_info(); + + /* Check update areas , 0 : bootloader 1: core 2: private 3: public */ + for (i = 0; i < SECTION_NUM; i++) { + if ((mbin_info[i].version == 0) || + (mbin_info[i].version != ts_info[i].version)) { + section_update_flag[i] = true; + pr_info("[TSP ISC] [%d] section will be updated!", i); + } + } + + section_update_flag[0] = false; /* Bootloader */ + section_update_flag[1] = true; /* Core */ + section_update_flag[2] = true; /* Private */ + section_update_flag[3] = true; /* Public */ + pr_info("[TSP ISC] [%d] [%d] [%d]", section_update_flag[1], + section_update_flag[2], section_update_flag[3]); + + if (section_update_flag[SEC_BOOTLOADER]) { + expected_compatibility[SEC_CORE] = + mbin_info[SEC_BOOTLOADER].version; + } else { + expected_compatibility[SEC_CORE] = + ts_info[SEC_BOOTLOADER].version; + } + + if (section_update_flag[SEC_CORE]) { + expected_compatibility[SEC_PUBLIC_CONFIG] = + expected_compatibility[SEC_PRIVATE_CONFIG] = + mbin_info[SEC_CORE].version; + } else { + expected_compatibility[SEC_PUBLIC_CONFIG] = + expected_compatibility[SEC_PRIVATE_CONFIG] = + ts_info[SEC_CORE].version; + } + + for (i = SEC_CORE; i < SEC_PUBLIC_CONFIG; i++) { + if (section_update_flag[i]) { + pr_info("[TSP ISC] section_update_flag(%d), 0x%02x, 0x%02x\n", + i, expected_compatibility[i], + mbin_info[i].compatible_version); + + if (expected_compatibility[i] != + mbin_info[i].compatible_version) + return ISC_COMPATIVILITY_ERROR; + } else { + pr_info("[TSP ISC] !section_update_flag(%d), 0x%02x, 0x%02x\n", + i, expected_compatibility[i], + ts_info[i].compatible_version); + if (expected_compatibility[i] != + ts_info[i].compatible_version) + return ISC_COMPATIVILITY_ERROR; + } + } + + return ISC_SUCCESS; +} + +static int mms100_enter_ISC_mode(struct i2c_client *_client) +{ + int ret; + unsigned char wr_buf[2]; + + pr_info("[TSP ISC] %s\n", __func__); + + wr_buf[0] = ISC_CMD_ENTER_ISC; + wr_buf[1] = ISC_CMD_ENTER_ISC_PARA1; + + ret = i2c_master_send(_client, wr_buf, 2); + + if (ret < 0) { + pr_info("[TSP ISC] %s,%d: i2c write fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + msleep(50); + + return ISC_SUCCESS; +} + +static int mms100_enter_config_update(struct i2c_client *_client) +{ + int ret; + unsigned char wr_buf[10] = {0,}; + unsigned char rd_buf; + + wr_buf[0] = ISC_CMD_UPDATE_MODE; + wr_buf[1] = ISC_SUBCMD_ENTER_UPDATE; + + ret = i2c_master_send(_client, wr_buf, 10); + if (ret < 0) { + pr_info("[TSP ISC] %s,%d: i2c write fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + ret = mms100_i2c_read(_client, ISC_CMD_CONFIRM_STATUS, 1, &rd_buf); + if (ret < 0) { + pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + if (rd_buf != ISC_STATUS_UPDATE_MODE) + return ISC_UPDATE_MODE_ENTER_ERROR; + + pr_info("[TSP ISC]End mms100_enter_config_update()\n"); + + return ISC_SUCCESS; +} + +static int mms100_ISC_clear_page(struct i2c_client *_client, + unsigned char _page_addr) +{ + int ret; + unsigned char rd_buf; + + memset(&g_wr_buf[3], 0xFF, PAGE_DATA); + + g_wr_buf[0] = ISC_CMD_UPDATE_MODE; /* command */ + g_wr_buf[1] = ISC_SUBCMD_DATA_WRITE; /* sub_command */ + g_wr_buf[2] = _page_addr; + + g_wr_buf[PAGE_HEADER + PAGE_DATA] = crc0_buf[_page_addr]; + g_wr_buf[PAGE_HEADER + PAGE_DATA + 1] = crc1_buf[_page_addr]; + + ret = i2c_master_send(_client, g_wr_buf, PACKET_SIZE); + if (ret < 0) { + pr_info("[TSP ISC] %s,%d: i2c write fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + ret = mms100_i2c_read(_client, ISC_CMD_CONFIRM_STATUS, 1, &rd_buf); + if (ret < 0) { + pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + if (rd_buf != ISC_STATUS_CRC_CHECK_SUCCESS) + return ISC_UPDATE_MODE_ENTER_ERROR; + + pr_info("[TSP ISC]End mms100_ISC_clear_page()\n"); + return ISC_SUCCESS; + +} + +static int mms100_ISC_clear_validate_markers(struct i2c_client *_client) +{ + int ret_msg; + int i, j; + bool is_matched_address; + + for (i = SEC_CORE; i <= SEC_PUBLIC_CONFIG; i++) { + if (section_update_flag[i]) { + if (ts_info[i].end_addr <= 30 && + ts_info[i].end_addr > 0) { + ret_msg = mms100_ISC_clear_page(_client, + ts_info[i].end_addr); + + if (ret_msg != ISC_SUCCESS) + return ret_msg; + } + } + } + + for (i = SEC_CORE; i <= SEC_PUBLIC_CONFIG; i++) { + if (section_update_flag[i]) { + is_matched_address = false; + for (j = SEC_CORE; j <= SEC_PUBLIC_CONFIG; j++) { + if (mbin_info[i].end_addr == + ts_info[i].end_addr) { + is_matched_address = true; + break; + } + } + + if (!is_matched_address) { + if (mbin_info[i].end_addr <= 30 && + mbin_info[i].end_addr > 0) { + ret_msg = mms100_ISC_clear_page(_client, + mbin_info[i].end_addr); + + if (ret_msg != ISC_SUCCESS) + return ret_msg; + } + } + } + } + + return ISC_SUCCESS; +} + +static int mms100_update_section_data(struct i2c_client *_client) +{ + int i, ret, next_ptr; + unsigned char rd_buf; + const unsigned char *ptr_fw; + char str_buf[STRING_BUF_LEN]; + int page_addr; + + for (i = 0; i < SECTION_NUM; i++) { + if (section_update_flag[i]) { + pr_info("[TSP ISC] section data i2c flash : [%d]", i); + + next_ptr = 0; + ptr_fw = fw_mbin[i]->data; + + do { + sscanf(ptr_fw + next_ptr, "%s", str_buf); + next_ptr += strlen(str_buf) + 1; + } while (!strstr(str_buf, "[Binary]")); + ptr_fw = ptr_fw + next_ptr + 2; + + for (page_addr = mbin_info[i].start_addr; + page_addr <= mbin_info[i].end_addr; + page_addr++) { + if (page_addr - mbin_info[i].start_addr > 0) + ptr_fw += PACKET_SIZE; + + if ((ptr_fw[0] != ISC_CMD_UPDATE_MODE) || + (ptr_fw[1] != ISC_SUBCMD_DATA_WRITE) || + (ptr_fw[2] != page_addr)) + return ISC_WRITE_BUFFER_ERROR; + + ret = i2c_master_send(_client, + ptr_fw, PACKET_SIZE); + if (ret < 0) { + pr_info("[TSP ISC] %s,%d: i2c write fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + ret = mms100_i2c_read(_client, + ISC_CMD_CONFIRM_STATUS, 1, &rd_buf); + if (ret < 0) { + pr_info("[TSP ISC] %s,%d: i2c read fail[%d]\n", + __func__, __LINE__, ret); + return ISC_I2C_ERROR; + } + + if (rd_buf != ISC_STATUS_CRC_CHECK_SUCCESS) + return ISC_CRC_ERROR; + + section_update_flag[i] = false; + + pr_info("[TSP ISC] msleep(2000)"); + msleep(300); + + } + } + } + + pr_info("[TSP ISC]End mms100_update_section_data()\n"); + return ISC_SUCCESS; +} + +static int mms100_open_mbinary(struct i2c_client *_client) +{ + int ret = 0; + + ret += request_firmware(&(fw_mbin[1]), + "tsp_melfas/CORE.fw", &_client->dev); + ret += request_firmware(&(fw_mbin[2]), + "tsp_melfas/PRIV.fw", &_client->dev); + ret += request_firmware(&(fw_mbin[3]), + "tsp_melfas/PUBL.fw", &_client->dev); + + if (!ret) + return ISC_SUCCESS; + else { + pr_info("[TSP ISC] request_firmware fail"); + return ISC_FILE_OPEN_ERROR; + } +} + +static int mms100_close_mbinary(void) +{ + int i; + + for (i = 0; i < SECTION_NUM; i++) { + if (fw_mbin[i] != NULL) + release_firmware(fw_mbin[i]); + } + return ISC_SUCCESS; +} + +int mms100_ISC_download_mbinary(struct mms_ts_info *info) +{ + struct i2c_client *_client = info->client; + int ret_msg = ISC_NONE; + + pr_info("[TSP ISC] %s\n", __func__); + + mms100_reset(info); +/* + ret_msg = mms100_check_operating_mode(_client, EC_BOOT_ON_SUCCEEDED); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; +*/ + ret_msg = mms100_open_mbinary(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + /* Config version Check */ + ret_msg = mms100_compare_version_info(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + ret_msg = mms100_enter_ISC_mode(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + ret_msg = mms100_enter_config_update(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + ret_msg = mms100_ISC_clear_validate_markers(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + pr_info("[TSP ISC]mms100_update_section_data start"); + + ret_msg = mms100_update_section_data(_client); + if (ret_msg != ISC_SUCCESS) + goto ISC_ERROR_HANDLE; + + pr_info("[TSP ISC]mms100_update_section_data end"); + + pr_info("[TSP ISC]FIRMWARE_UPDATE_FINISHED!!!\n"); + + ret_msg = ISC_SUCCESS; + +ISC_ERROR_HANDLE: + if (ret_msg != ISC_SUCCESS) + pr_info("[TSP ISC]ISC_ERROR_CODE: %d\n", ret_msg); + + mms100_reset(info); + mms100_close_mbinary(); + + return ret_msg; +} +#endif /* ISC_DL_MODE start */ + +static void hw_reboot(struct mms_ts_info *info, bool bootloader) +{ + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, bootloader ? 0 : 1); + gpio_direction_output(info->pdata->gpio_scl, bootloader ? 0 : 1); + gpio_direction_output(info->pdata->gpio_resetb, 0); + msleep(30); + info->pdata->vdd_on(1); + msleep(30); + + if (bootloader) { + gpio_set_value(info->pdata->gpio_scl, 0); + gpio_set_value(info->pdata->gpio_sda, 1); + } else { + gpio_set_value(info->pdata->gpio_resetb, 1); + gpio_direction_input(info->pdata->gpio_resetb); + gpio_direction_input(info->pdata->gpio_scl); + gpio_direction_input(info->pdata->gpio_sda); + } + msleep(40); +} + +static inline void hw_reboot_bootloader(struct mms_ts_info *info) +{ + hw_reboot(info, true); +} + +static inline void hw_reboot_normal(struct mms_ts_info *info) +{ + hw_reboot(info, false); +} + +static inline void mms_pwr_on_reset(struct mms_ts_info *info) +{ + struct i2c_adapter *adapter = to_i2c_adapter(info->client->dev.parent); + + if (!info->pdata->mux_fw_flash) { + dev_info(&info->client->dev, + "missing platform data, can't do power-on-reset\n"); + return; + } + + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, 1); + gpio_direction_output(info->pdata->gpio_scl, 1); + gpio_direction_output(info->pdata->gpio_resetb, 1); + msleep(50); + info->pdata->vdd_on(1); + msleep(50); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + /* TODO: Seems long enough for the firmware to boot. + * Find the right value */ + msleep(250); +} + +static void isp_toggle_clk(struct mms_ts_info *info, int start_lvl, int end_lvl, + int hold_us) +{ + gpio_set_value(info->pdata->gpio_scl, start_lvl); + udelay(hold_us); + gpio_set_value(info->pdata->gpio_scl, end_lvl); + udelay(hold_us); +} + +/* 1 <= cnt <= 32 bits to write */ +static void isp_send_bits(struct mms_ts_info *info, u32 data, int cnt) +{ + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 0); + + /* clock out the bits, msb first */ + while (cnt--) { + gpio_set_value(info->pdata->gpio_sda, (data >> cnt) & 1); + udelay(3); + isp_toggle_clk(info, 1, 0, 3); + } +} + +/* 1 <= cnt <= 32 bits to read */ +static u32 isp_recv_bits(struct mms_ts_info *info, int cnt) +{ + u32 data = 0; + + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_set_value(info->pdata->gpio_sda, 0); + gpio_direction_input(info->pdata->gpio_sda); + + /* clock in the bits, msb first */ + while (cnt--) { + isp_toggle_clk(info, 0, 1, 1); + data = (data << 1) | (!!gpio_get_value(info->pdata->gpio_sda)); + } + + gpio_direction_output(info->pdata->gpio_sda, 0); + return data; +} + +static void isp_enter_mode(struct mms_ts_info *info, u32 mode) +{ + int cnt; + unsigned long flags; + + local_irq_save(flags); + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 1); + + mode &= 0xffff; + for (cnt = 15; cnt >= 0; cnt--) { + gpio_set_value(info->pdata->gpio_resetb, (mode >> cnt) & 1); + udelay(3); + isp_toggle_clk(info, 1, 0, 3); + } + + gpio_set_value(info->pdata->gpio_resetb, 0); + local_irq_restore(flags); +} + +static void isp_exit_mode(struct mms_ts_info *info) +{ + int i; + unsigned long flags; + + local_irq_save(flags); + gpio_direction_output(info->pdata->gpio_resetb, 0); + udelay(3); + + for (i = 0; i < 10; i++) + isp_toggle_clk(info, 1, 0, 3); + local_irq_restore(flags); +} + +static void flash_set_address(struct mms_ts_info *info, u16 addr) +{ + /* Only 13 bits of addr are valid. + * The addr is in bits 13:1 of cmd */ + isp_send_bits(info, (u32)(addr & 0x1fff) << 1, 18); +} + +static void flash_erase(struct mms_ts_info *info) +{ + isp_enter_mode(info, ISP_MODE_FLASH_ERASE); + + gpio_direction_output(info->pdata->gpio_resetb, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 1); + + /* 4 clock cycles with different timings for the erase to + * get processed, clk is already 0 from above */ + udelay(7); + isp_toggle_clk(info, 1, 0, 3); + udelay(7); + isp_toggle_clk(info, 1, 0, 3); + usleep_range(25000, 35000); + isp_toggle_clk(info, 1, 0, 3); + usleep_range(150, 200); + isp_toggle_clk(info, 1, 0, 3); + + gpio_set_value(info->pdata->gpio_sda, 0); + + isp_exit_mode(info); +} + +static u32 flash_readl(struct mms_ts_info *info, u16 addr) +{ + int i; + u32 val; + unsigned long flags; + + local_irq_save(flags); + isp_enter_mode(info, ISP_MODE_FLASH_READ); + flash_set_address(info, addr); + + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_sda, 0); + udelay(40); + + /* data load cycle */ + for (i = 0; i < 6; i++) + isp_toggle_clk(info, 1, 0, 10); + + val = isp_recv_bits(info, 32); + isp_exit_mode(info); + local_irq_restore(flags); + + return val; +} + +static void flash_writel(struct mms_ts_info *info, u16 addr, u32 val) +{ + unsigned long flags; + + local_irq_save(flags); + isp_enter_mode(info, ISP_MODE_FLASH_WRITE); + flash_set_address(info, addr); + isp_send_bits(info, val, 32); + + gpio_direction_output(info->pdata->gpio_sda, 1); + /* 6 clock cycles with different timings for the data to get written + * into flash */ + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 6); + isp_toggle_clk(info, 0, 1, 12); + isp_toggle_clk(info, 0, 1, 3); + isp_toggle_clk(info, 0, 1, 3); + + isp_toggle_clk(info, 1, 0, 1); + + gpio_direction_output(info->pdata->gpio_sda, 0); + isp_exit_mode(info); + local_irq_restore(flags); + usleep_range(300, 400); +} + +static bool flash_is_erased(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + u32 val; + u16 addr; + + for (addr = 0; addr < (ISP_MAX_FW_SIZE / 4); addr++) { + udelay(40); + val = flash_readl(info, addr); + + if (val != 0xffffffff) { + dev_dbg(&client->dev, + "addr 0x%x not erased: 0x%08x != 0xffffffff\n", + addr, val); + return false; + } + } + return true; +} + +static int fw_write_image(struct mms_ts_info *info, const u8 *data, size_t len) +{ + struct i2c_client *client = info->client; + u16 addr = 0; + + for (addr = 0; addr < (len / 4); addr++, data += 4) { + u32 val = get_unaligned_le32(data); + u32 verify_val; + int retries = 3; + + while (retries--) { + flash_writel(info, addr, val); + verify_val = flash_readl(info, addr); + if (val == verify_val) + break; + dev_err(&client->dev, + "mismatch @ addr 0x%x: 0x%x != 0x%x\n", + addr, verify_val, val); + continue; + } + if (retries < 0) + return -ENXIO; + } + + return 0; +} + +static int fw_download(struct mms_ts_info *info, const u8 *data, size_t len) +{ + struct i2c_client *client = info->client; + u32 val; + int ret = 0; + + if (len % 4) { + dev_err(&client->dev, + "fw image size (%d) must be a multiple of 4 bytes\n", + len); + return -EINVAL; + } else if (len > ISP_MAX_FW_SIZE) { + dev_err(&client->dev, + "fw image is too big, %d > %d\n", len, ISP_MAX_FW_SIZE); + return -EINVAL; + } + + dev_info(&client->dev, "fw download start\n"); + + info->pdata->vdd_on(0); + gpio_direction_output(info->pdata->gpio_sda, 0); + gpio_direction_output(info->pdata->gpio_scl, 0); + gpio_direction_output(info->pdata->gpio_resetb, 0); + + hw_reboot_bootloader(info); + + val = flash_readl(info, ISP_IC_INFO_ADDR); + dev_info(&client->dev, "IC info: 0x%02x (%x)\n", val & 0xff, val); + + dev_info(&client->dev, "fw erase...\n"); + flash_erase(info); + if (!flash_is_erased(info)) { + ret = -ENXIO; + goto err; + } + + dev_info(&client->dev, "fw write...\n"); + /* XXX: what does this do?! */ + flash_writel(info, ISP_IC_INFO_ADDR, 0xffffff00 | (val & 0xff)); + usleep_range(1000, 1500); + ret = fw_write_image(info, data, len); + if (ret) + goto err; + usleep_range(1000, 1500); + + hw_reboot_normal(info); + usleep_range(1000, 1500); + dev_info(&client->dev, "fw download done...\n"); + return 0; + +err: + dev_err(&client->dev, "fw download failed...\n"); + hw_reboot_normal(info); + return ret; +} + +#if defined(SEC_TSP_ISC_FW_UPDATE) +static u16 gen_crc(u8 data, u16 pre_crc) +{ + u16 crc; + u16 cur; + u16 temp; + u16 bit_1; + u16 bit_2; + int i; + + crc = pre_crc; + for (i = 7; i >= 0; i--) { + cur = ((data >> i) & 0x01) ^ (crc & 0x0001); + bit_1 = cur ^ (crc >> 11 & 0x01); + bit_2 = cur ^ (crc >> 4 & 0x01); + temp = (cur << 4) | (crc >> 12 & 0x0F); + temp = (temp << 7) | (bit_1 << 6) | (crc >> 5 & 0x3F); + temp = (temp << 4) | (bit_2 << 3) | (crc >> 1 & 0x0007); + crc = temp; + } + return crc; +} + +static int isc_fw_download(struct mms_ts_info *info, const u8 *data, + size_t len) +{ + u8 *buff; + u16 crc_buf; + int src_idx; + int dest_idx; + int ret; + int i, j; + + buff = kzalloc(ISC_PKT_SIZE, GFP_KERNEL); + if (!buff) { + dev_err(&info->client->dev, "%s: failed to allocate memory\n", + __func__); + ret = -1; + goto err_mem_alloc; + } + + /* enterring ISC mode */ + *buff = ISC_ENTER_ISC_DATA; + ret = i2c_smbus_write_byte_data(info->client, + ISC_ENTER_ISC_CMD, *buff); + if (ret < 0) { + dev_err(&info->client->dev, + "fail to enter ISC mode(err=%d)\n", ret); + goto fail_to_isc_enter; + } + usleep_range(10000, 20000); + dev_info(&info->client->dev, "Enter ISC mode\n"); + + /*enter ISC update mode */ + *buff = ISC_ENTER_UPDATE_DATA; + ret = i2c_smbus_write_i2c_block_data(info->client, + ISC_CMD, + ISC_ENTER_UPDATE_DATA_LEN, buff); + if (ret < 0) { + dev_err(&info->client->dev, + "fail to enter ISC update mode(err=%d)\n", ret); + goto fail_to_isc_update; + } + dev_info(&info->client->dev, "Enter ISC update mode\n"); + + /* firmware write */ + *buff = ISC_CMD; + *(buff + 1) = ISC_DATA_WRITE_SUB_CMD; + for (i = 0; i < ISC_PKT_NUM; i++) { + *(buff + 2) = i; + crc_buf = gen_crc(*(buff + 2), ISC_DEFAULT_CRC); + + for (j = 0; j < ISC_PKT_DATA_SIZE; j++) { + dest_idx = ISC_PKT_HEADER_SIZE + j; + src_idx = i * ISC_PKT_DATA_SIZE + + ((int)(j / WORD_SIZE)) * WORD_SIZE - + (j % WORD_SIZE) + 3; + *(buff + dest_idx) = *(data + src_idx); + crc_buf = gen_crc(*(buff + dest_idx), crc_buf); + } + + *(buff + ISC_PKT_DATA_SIZE + ISC_PKT_HEADER_SIZE + 1) = + crc_buf & 0xFF; + *(buff + ISC_PKT_DATA_SIZE + ISC_PKT_HEADER_SIZE) = + crc_buf >> 8 & 0xFF; + + ret = i2c_master_send(info->client, buff, ISC_PKT_SIZE); + if (ret < 0) { + dev_err(&info->client->dev, + "fail to firmware writing on packet %d.(%d)\n", + i, ret); + goto fail_to_fw_write; + } + usleep_range(1, 5); + + /* confirm CRC */ + ret = i2c_smbus_read_byte_data(info->client, + ISC_CHECK_STATUS_CMD); + if (ret == ISC_CONFIRM_CRC) { + dev_info(&info->client->dev, + "updating %dth firmware data packet.\n", i); + } else { + dev_err(&info->client->dev, + "fail to firmware update on %dth (%X).\n", + i, ret); + ret = -1; + goto fail_to_confirm_crc; + } + } + + ret = 0; + +fail_to_confirm_crc: +fail_to_fw_write: + /* exit ISC mode */ + *buff = ISC_EXIT_ISC_SUB_CMD; + *(buff + 1) = ISC_EXIT_ISC_SUB_CMD2; + i2c_smbus_write_i2c_block_data(info->client, ISC_CMD, 2, buff); + usleep_range(10000, 20000); +fail_to_isc_update: + hw_reboot_normal(info); +fail_to_isc_enter: + kfree(buff); +err_mem_alloc: + return ret; +} +#endif /* SEC_TSP_ISC_FW_UPDATE */ + +static int get_fw_version(struct mms_ts_info *info) +{ + int ret; + int retries = 3; + + /* this seems to fail sometimes after a reset.. retry a few times */ + do { + ret = i2c_smbus_read_byte_data(info->client, MMS_FW_VERSION); + } while (ret < 0 && retries-- > 0); + + return ret; +} + +static int get_hw_version(struct mms_ts_info *info) +{ + int ret; + int retries = 3; + + /* this seems to fail sometimes after a reset.. retry a few times */ + do { + ret = i2c_smbus_read_byte_data(info->client, MMS_HW_REVISION); + } while (ret < 0 && retries-- > 0); + + return ret; +} + +static int mms_ts_enable(struct mms_ts_info *info, int wakeupcmd) +{ + mutex_lock(&info->lock); + if (info->enabled) + goto out; + /* wake up the touch controller. */ + if (wakeupcmd == 1) { + i2c_smbus_write_byte_data(info->client, 0, 0); + usleep_range(3000, 5000); + } + info->enabled = true; + enable_irq(info->irq); +out: + mutex_unlock(&info->lock); + return 0; +} + +static int mms_ts_disable(struct mms_ts_info *info, int sleepcmd) +{ + mutex_lock(&info->lock); + if (!info->enabled) + goto out; + disable_irq(info->irq); + if (sleepcmd == 1) { + i2c_smbus_write_byte_data(info->client, MMS_MODE_CONTROL, 0); + usleep_range(10000, 12000); + } + info->enabled = false; + touch_is_pressed = 0; +out: + mutex_unlock(&info->lock); + return 0; +} + +static int mms_ts_finish_config(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + int ret; + + ret = request_threaded_irq(client->irq, NULL, mms_ts_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "mms_ts", info); + if (ret < 0) { + ret = 1; + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_req_irq; + } + + info->irq = client->irq; + barrier(); + + dev_info(&client->dev, + "Melfas MMS-series touch controller initialized\n"); + + return 0; + +err_req_irq: + return ret; +} +#if !ISC_DL_MODE +static int mms_ts_fw_info(struct mms_ts_info *info) +{ + struct i2c_client *client = info->client; + int ret = 0; + int ver, hw_rev; + + ver = get_fw_version(info); + info->fw_ic_ver = ver; + dev_info(&client->dev, + "[TSP]fw version 0x%02x !!!!\n", ver); + + hw_rev = get_hw_version(info); + dev_info(&client->dev, + "[TSP] hw rev = %x\n", hw_rev); + + if (ver < 0 || hw_rev < 0) { + ret = 1; + dev_err(&client->dev, + "i2c fail...tsp driver unload.\n"); + return ret; + } + + if (!info->pdata || !info->pdata->mux_fw_flash) { + ret = 1; + dev_err(&client->dev, + "fw cannot be updated, missing platform data\n"); + return ret; + } + + ret = mms_ts_finish_config(info); + + return ret; +} +#endif + +#if ISC_DL_MODE +static int mms_ts_fw_load(struct mms_ts_info *info) +{ + + struct i2c_client *client = info->client; + /*struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);*/ + int ret = 0; + int ver, hw_rev; + /*int retries = 3;*/ + + ver = get_fw_version(info); + info->fw_ic_ver = ver; + dev_info(&client->dev, + "[TSP]fw version 0x%02x !!!!\n", ver); + + hw_rev = get_hw_version(info); + dev_info(&client->dev, + "[TSP]hw rev = 0x%02x\n", hw_rev); + + if (ver < 0 || hw_rev < 0) { + ret = 1; + dev_err(&client->dev, + "i2c fail...tsp driver unload.\n"); + } + + if (!info->pdata || !info->pdata->mux_fw_flash) { + ret = 1; + dev_err(&client->dev, + "fw cannot be updated, missing platform data\n"); + goto out; + } + + if (hw_rev == 0xC) { + dev_err(&client->dev, + "[TSP] support only 4.8 inch panel. Do not update"); + goto done; + } + + dev_err(&client->dev, + "[TSP] ISC Ver [0x%02x] [0x%02x] [0x%02x]", + i2c_smbus_read_byte_data(info->client, 0xF3), + i2c_smbus_read_byte_data(info->client, 0xF4), + i2c_smbus_read_byte_data(info->client, 0xF5)); + + if (ver >= FW_VERSION && ver != 0xFF + && ver != 0x00 && ver != 0x45) { + dev_err(&client->dev, + "[TSP] fw is latest. Do not update."); + goto done; + } else { + dev_err(&client->dev, + "[TSP] fw update [0x%02x -> 0x%02x]", + ver, FW_VERSION); + } + + ret = mms100_ISC_download_mbinary(info); + + if (ret == 0) { + dev_err(&client->dev, + "[TSP] mms100_ISC_download_mbinary success"); + goto done; + } else { + dev_err(&client->dev, + "[TSP] mms100_ISC_download_mbinary fail [%d]", ret); + ret = 1; + } +out: + return ret; + +done: + ret = mms_ts_finish_config(info); + return ret; +} +#endif + +#ifdef SEC_TSP_FACTORY_TEST +static void set_default_result(struct mms_ts_info *info) +{ + char delim = ':'; + + memset(info->cmd_result, 0x00, ARRAY_SIZE(info->cmd_result)); + memcpy(info->cmd_result, info->cmd, strlen(info->cmd)); + strncat(info->cmd_result, &delim, 1); +} + +static void set_cmd_result(struct mms_ts_info *info, char *buff, int len) +{ + strncat(info->cmd_result, buff, len); +} + +static inline int msm_irq_to_gpio(unsigned irq) +{ + /* TODO : Need to verify chip->base=0 */ + return irq - MSM_GPIO_TO_INT(0); +} +static void get_raw_data_all(struct mms_ts_info *info, u8 cmd) +{ + u8 w_buf[6]; + u8 read_buffer[2]; /* 52 */ + char buff[TSP_CMD_STR_LEN] = {0}; + int gpio; + int ret; + int i, j; + u32 max_value, min_value; + u32 raw_data; + + gpio = msm_irq_to_gpio(info->irq); + disable_irq(info->irq); + + w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */ + w_buf[1] = MMS_VSC_MODE; /* mode of vendor */ + w_buf[2] = 0; /* tx line */ + w_buf[3] = 0; /* rx line */ + w_buf[4] = 0; /* reserved */ + w_buf[5] = 0; /* sub command */ + + if (cmd == MMS_VSC_CMD_EXIT) { + w_buf[5] = MMS_VSC_CMD_EXIT; /* exit test mode */ + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + touch_is_pressed = 0; + release_all_fingers(info); +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) + set_esd_disable(); +#endif + info->pdata->vdd_on(0); + msleep(30); + info->pdata->vdd_on(1); + msleep(120); + enable_irq(info->irq); +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) + set_esd_enable(); +#endif + return ; + } + + /* MMS_VSC_CMD_CM_DELTA or MMS_VSC_CMD_CM_ABS + * this two mode need to enter the test mode + * exit command must be followed by testing. + */ + if (cmd == MMS_VSC_CMD_CM_DELTA || cmd == MMS_VSC_CMD_CM_ABS) { + /* enter the debug mode */ + w_buf[2] = 0x0; /* tx */ + w_buf[3] = 0x0; /* rx */ + w_buf[5] = MMS_VSC_CMD_ENTER; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + + /* wating for the interrupt */ + while (gpio_get_value(gpio)) + udelay(100); + } + + max_value = 0; + min_value = 0; + + for (i = 0; i < RX_NUM; i++) { + for (j = 0; j < TX_NUM; j++) { + + w_buf[2] = j; /* tx */ + w_buf[3] = i; /* rx */ + w_buf[5] = cmd; + + ret = i2c_smbus_write_i2c_block_data(info->client, + w_buf[0], 5, &w_buf[1]); + if (ret < 0) + goto err_i2c; + + usleep_range(1, 5); + + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, + 2, read_buffer); + if (ret < 0) + goto err_i2c; + + raw_data = ((u16)read_buffer[1] << 8) | read_buffer[0]; + + if (i == 0 && j == 0) { + max_value = min_value = raw_data; + } else { + max_value = max(max_value, raw_data); + min_value = min(min_value, raw_data); + } + + if (cmd == MMS_VSC_CMD_INTENSITY) { + info->intensity[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "[TSP] intensity[%d][%d] = %d\n", + i, j, info->intensity[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_CM_DELTA) { + info->inspection[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "[TSP] delta[%d][%d] = %d\n", + i, j, info->inspection[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_CM_ABS) { + info->raw[j * RX_NUM + i] = raw_data; + dev_dbg(&info->client->dev, "[TSP] raw[%d][%d] = %d\n", + i, j, info->raw[j * RX_NUM + i]); + } else if (cmd == MMS_VSC_CMD_REFER) { + info->reference[j * RX_NUM + i] = + raw_data >> 3; + dev_dbg(&info->client->dev, "[TSP] reference[%d][%d] = %d\n", + i, j, info->reference[j * RX_NUM + i]); + } + } + } + + snprintf(buff, sizeof(buff), "%d,%d", min_value, max_value); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + enable_irq(info->irq); + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); +} + +#ifdef ESD_DEBUG +static u32 get_raw_data_one(struct mms_ts_info *info, u16 rx_idx, u16 tx_idx, + u8 cmd) +{ + u8 w_buf[6]; + u8 read_buffer[2]; + int ret; + u32 raw_data; + + w_buf[0] = MMS_VSC_CMD; /* vendor specific command id */ + w_buf[1] = MMS_VSC_MODE; /* mode of vendor */ + w_buf[2] = 0; /* tx line */ + w_buf[3] = 0; /* rx line */ + w_buf[4] = 0; /* reserved */ + w_buf[5] = 0; /* sub command */ + + if (cmd != MMS_VSC_CMD_INTENSITY && cmd != MMS_VSC_CMD_RAW && + cmd != MMS_VSC_CMD_REFER) { + dev_err(&info->client->dev, "%s: not profer command(cmd=%d)\n", + __func__, cmd); + return FAIL; + } + + w_buf[2] = tx_idx; /* tx */ + w_buf[3] = rx_idx; /* rx */ + w_buf[5] = cmd; /* sub command */ + + ret = i2c_smbus_write_i2c_block_data(info->client, w_buf[0], 5, + &w_buf[1]); + if (ret < 0) + goto err_i2c; + + ret = i2c_smbus_read_i2c_block_data(info->client, 0xBF, 2, + read_buffer); + if (ret < 0) + goto err_i2c; + + raw_data = ((u16)read_buffer[1] << 8) | read_buffer[0]; + if (cmd == MMS_VSC_CMD_REFER) + raw_data = raw_data >> 4; + + return raw_data; + +err_i2c: + dev_err(&info->client->dev, "%s: fail to i2c (cmd=%d)\n", + __func__, cmd); + return FAIL; +} +#endif + +static ssize_t show_close_tsp_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->ft_flag = 0; + + return snprintf(buf, TSP_BUF_SIZE, "%u\n", 0); +} + +static int check_rx_tx_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[TSP_CMD_STR_LEN] = {0}; + int node; + + if (info->cmd_param[0] < 0 || + info->cmd_param[0] >= TX_NUM || + info->cmd_param[1] < 0 || + info->cmd_param[1] >= RX_NUM) { + snprintf(buff, sizeof(buff) , "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: parameter error: %u,%u\n", + __func__, info->cmd_param[0], + info->cmd_param[1]); + node = -1; + return node; + } + node = info->cmd_param[1] * RX_NUM + info->cmd_param[0]; + dev_info(&info->client->dev, "%s: node = %d\n", __func__, + node); + return node; + +} + +static void not_support_cmd(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + char buff[16] = {0}; + + set_default_result(info); + sprintf(buff, "%s", "NA"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 4; + dev_info(&info->client->dev, "%s: \"%s(%d)\"\n", __func__, + buff, strnlen(buff, sizeof(buff))); + return; +} + +static void fw_update(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + struct i2c_client *client = info->client; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret = 0; + int fw_ver = 0, ver = 0, hw_rev = 0, fw_bin_ver = 0; + int retries = 5; + const u8 *buff = 0; + mm_segment_t old_fs = {0}; + struct file *fp = NULL; + long fsize = 0, nread = 0; + + #define MMS_TS "/sdcard/melfas_fw.bin" + + set_default_result(info); + + hw_rev = get_hw_version(info); + if (hw_rev == 0x1 || hw_rev == 0x32) + fw_bin_ver = FW_VERSION; + else if (hw_rev == 0x0C) + fw_bin_ver = FW_465_VERSION; + + fw_ver = get_fw_version(info); + dev_info(&client->dev, + "fw_ic_ver = 0x%02x, fw_bin_ver = 0x%02x\n", + fw_ver, fw_bin_ver); + + if (info->cmd_param[0] == 0 + && fw_ver >= fw_bin_ver) { + dev_info(&client->dev, + "fw version update does not need\n"); + goto do_not_need_update; + } + + switch (info->cmd_param[0]) { + case BUILT_IN: + if (hw_rev == 0x1 || hw_rev == 0x32) { + buff = MELFAS_binary; + fsize = MELFAS_binary_nLength; + dev_info(&client->dev, "built in 4.8 fw is loaded!!\n"); + } else if (hw_rev == 0x0C) { + buff = MELFAS_465_binary; + fsize = MELFAS_465_binary_nLength; + dev_info(&client->dev, "built in 4.65 fw is loaded!!\n"); + } + break; + + case UMS: + old_fs = get_fs(); + set_fs(get_ds()); + + fp = filp_open(MMS_TS, O_RDONLY, 0); + if (IS_ERR(fp)) { + dev_err(&client->dev, + "file %s open error:%d\n", MMS_TS, (s32)fp); + info->cmd_state = 3; + goto err_open; + } + + fsize = fp->f_path.dentry->d_inode->i_size; + + buff = kzalloc((size_t)fsize, GFP_KERNEL); + if (!buff) { + dev_err(&client->dev, "fail to alloc buffer for fw\n"); + info->cmd_state = 3; + goto err_alloc; + } + + nread = vfs_read(fp, (char __user *)buff, fsize, &fp->f_pos); + if (nread != fsize) { + dev_err(&client->dev, "fail to read file %s (nread = %ld)\n", + MMS_TS, nread); + info->cmd_state = 3; + goto err_fw_size; + } + + filp_close(fp, current->files); + set_fs(old_fs); + dev_info(&client->dev, "ums fw is loaded!!\n"); + break; + + default: + dev_err(&client->dev, "invalid fw file type!!\n"); + goto not_support; + } + + disable_irq(info->irq); + while (retries--) { + i2c_lock_adapter(adapter); + info->pdata->mux_fw_flash(true); + + ret = fw_download(info, (const u8 *)buff, + (const size_t)fsize); + + info->pdata->mux_fw_flash(false); + i2c_unlock_adapter(adapter); + + if (ret < 0) { + dev_err(&client->dev, "retrying flashing\n"); + continue; + } + + ver = get_fw_version(info); + info->fw_ic_ver = ver; + + if (info->cmd_param[0] == 1) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + info->cmd_state = 2; + enable_irq(info->irq); + return; + } else if (ver == fw_bin_ver) { + dev_info(&client->dev, + "fw update done. ver = 0x%02x\n", ver); + info->cmd_state = 2; + enable_irq(info->irq); + return; + } else { + dev_err(&client->dev, + "ERROR : fw version is still wrong (0x%x != 0x%x)\n", + ver, FW_VERSION); + } + dev_err(&client->dev, "retrying flashing\n"); + } + +err_fw_size: + kfree(buff); +err_alloc: + filp_close(fp, NULL); +err_open: + set_fs(old_fs); +not_support: +do_not_need_update: + info->cmd_state = 2; + return; +} + +static void get_fw_ver_bin(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int hw_rev; + + set_default_result(info); + hw_rev = get_hw_version(info); + if (hw_rev == 0x01) + snprintf(buff, sizeof(buff), "%#02x", FW_VERSION); + else + snprintf(buff, sizeof(buff), "%#02x", FW_465_VERSION); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_fw_ver_ic(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int ver; + + set_default_result(info); + + ver = get_fw_version(info); + + snprintf(buff, sizeof(buff), "%#02x", ver); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_config_ver(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[20] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", info->config_fw_version); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_threshold(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int threshold; + + set_default_result(info); + + threshold = i2c_smbus_read_byte_data(info->client, 0x05); + if (threshold < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + return; + } + snprintf(buff, sizeof(buff), "%d", threshold); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void module_off_master(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[3] = {0}; + + mutex_lock(&info->lock); + if (info->enabled) { + disable_irq(info->irq); + info->enabled = false; + touch_is_pressed = 0; + } + mutex_unlock(&info->lock); + + info->pdata->vdd_on(0); + + if (info->pdata->is_vdd_on() == 0) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = 2; + else + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: %s\n", __func__, buff); +} + +static void module_on_master(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[3] = {0}; + + mms_pwr_on_reset(info); + + mutex_lock(&info->lock); + if (!info->enabled) { + enable_irq(info->irq); + info->enabled = true; + } + mutex_unlock(&info->lock); + + if (info->pdata->is_vdd_on() == 1) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = 2; + else + info->cmd_state = 3; + + dev_info(&info->client->dev, "%s: %s\n", __func__, buff); + +} + +static void get_chip_vendor(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", "MELFAS"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_chip_name(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + + set_default_result(info); + + snprintf(buff, sizeof(buff), "%s", "MMS144"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); +} + +static void get_reference(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->reference[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, + buff, strnlen(buff, sizeof(buff))); + +} + +static void get_cm_abs(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->raw[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_cm_delta(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->inspection[node]; + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_intensity(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + unsigned int val; + int node; + + set_default_result(info); + node = check_rx_tx_num(info); + + if (node < 0) + return; + + val = info->intensity[node]; + + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_x_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int val; + + set_default_result(info); + val = i2c_smbus_read_byte_data(info->client, 0xEF); + if (val < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_info(&info->client->dev, + "%s: fail to read num of x (%d).\n", __func__, val); + + return ; + } + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void get_y_num(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + char buff[16] = {0}; + int val; + + set_default_result(info); + val = i2c_smbus_read_byte_data(info->client, 0xEE); + if (val < 0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 3; + + dev_info(&info->client->dev, + "%s: fail to read num of y (%d).\n", __func__, val); + + return ; + } + snprintf(buff, sizeof(buff), "%u", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s: %s(%d)\n", __func__, buff, + strnlen(buff, sizeof(buff))); +} + +static void run_reference_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_REFER); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s\n", __func__); +} + +static void run_cm_abs_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_CM_ABS); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s\n", __func__); +} + +static void run_cm_delta_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_CM_DELTA); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s\n", __func__); +} + +static void run_intensity_read(void *device_data) +{ + struct mms_ts_info *info = (struct mms_ts_info *)device_data; + + set_default_result(info); + get_raw_data_all(info, MMS_VSC_CMD_INTENSITY); + info->cmd_state = 2; + + dev_info(&info->client->dev, "%s\n", __func__); +} + +static ssize_t store_cmd(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + + char *cur, *start, *end; + char buff[TSP_CMD_STR_LEN] = {0}; + int len, i; + struct tsp_cmd *tsp_cmd_ptr = NULL; + char delim = ','; + bool cmd_found = false; + int param_cnt = 0; + + + if (info->cmd_is_running == true) { + dev_err(&info->client->dev, "tsp_cmd: other cmd is running.\n"); + goto err_out; + } + + + /* check lock */ + mutex_lock(&info->cmd_lock); + info->cmd_is_running = true; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = 1; + + for (i = 0; i < ARRAY_SIZE(info->cmd_param); i++) + info->cmd_param[i] = 0; + + len = (int)count; + if (*(buf + len - 1) == '\n') + len--; + memset(info->cmd, 0x00, ARRAY_SIZE(info->cmd)); + memcpy(info->cmd, buf, len); + + cur = strchr(buf, (int)delim); + if (cur) + memcpy(buff, buf, cur - buf); + else + memcpy(buff, buf, len); + + /* find command */ + list_for_each_entry(tsp_cmd_ptr, &info->cmd_list_head, list) { + if (!strcmp(buff, tsp_cmd_ptr->cmd_name)) { + cmd_found = true; + break; + } + } + + /* set not_support_cmd */ + if (!cmd_found) { + list_for_each_entry(tsp_cmd_ptr, &info->cmd_list_head, list) { + if (!strcmp("not_support_cmd", tsp_cmd_ptr->cmd_name)) + break; + } + } + + /* parsing parameters */ + if (cur && cmd_found) { + cur++; + start = cur; + memset(buff, 0x00, ARRAY_SIZE(buff)); + do { + if (*cur == delim || cur - buf == len) { + end = cur; + memcpy(buff, start, end - start); + *(buff + strlen(buff)) = '\0'; + if (kstrtoint(buff, 10, + info->cmd_param + param_cnt) < 0) + goto err_out; + start = cur + 1; + memset(buff, 0x00, ARRAY_SIZE(buff)); + param_cnt++; + } + cur++; + } while (cur - buf <= len); + } + + dev_info(&client->dev, "cmd = %s\n", tsp_cmd_ptr->cmd_name); + for (i = 0; i < param_cnt; i++) + dev_info(&client->dev, "cmd param %d= %d\n", i, + info->cmd_param[i]); + + tsp_cmd_ptr->cmd_func(info); + + +err_out: + return count; +} + +static ssize_t show_cmd_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + char buff[16] = {0}; + + dev_info(&info->client->dev, "tsp cmd: status:%d\n", + info->cmd_state); + + if (info->cmd_state == 0) + snprintf(buff, sizeof(buff), "WAITING"); + + else if (info->cmd_state == 1) + snprintf(buff, sizeof(buff), "RUNNING"); + + else if (info->cmd_state == 2) + snprintf(buff, sizeof(buff), "OK"); + + else if (info->cmd_state == 3) + snprintf(buff, sizeof(buff), "FAIL"); + + else if (info->cmd_state == 4) + snprintf(buff, sizeof(buff), "NOT_APPLICABLE"); + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", buff); +} + +static ssize_t show_cmd_result(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + + dev_info(&info->client->dev, "tsp cmd: result: %s\n", info->cmd_result); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = 0; + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", info->cmd_result); +} + +#ifdef ESD_DEBUG + +static bool intensity_log_flag; + +static ssize_t show_intensity_logging_on(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + struct file *fp; + char log_data[160] = {0,}; + char buff[16] = {0,}; + mm_segment_t old_fs; + long nwrite; + u32 val; + int i, y, c; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + +#define MELFAS_DEBUG_LOG_PATH "/sdcard/melfas_log" + + dev_info(&client->dev, "%s: start.\n", __func__); + fp = filp_open(MELFAS_DEBUG_LOG_PATH, O_RDWR|O_CREAT, + S_IRWXU|S_IRWXG|S_IRWXO); + if (IS_ERR(fp)) { + dev_err(&client->dev, "%s: fail to open log file\n", __func__); + goto open_err; + } + + intensity_log_flag = 1; + do { + for (y = 0; y < 3; y++) { + /* for tx chanel 0~2 */ + memset(log_data, 0x00, 160); + + snprintf(buff, 16, "%1u: ", y); + strncat(log_data, buff, strnlen(buff, 16)); + + for (i = 0; i < RX_NUM; i++) { + val = get_raw_data_one(info, i, y, + MMS_VSC_CMD_INTENSITY); + snprintf(buff, 16, "%5u, ", val); + strncat(log_data, buff, strnlen(buff, 16)); + } + memset(buff, '\n', 2); + c = (y == 2) ? 2 : 1; + strncat(log_data, buff, c); + nwrite = vfs_write(fp, (const char __user *)log_data, + strnlen(log_data, 160), &fp->f_pos); + } + usleep_range(5000); + } while (intensity_log_flag); + + filp_close(fp, current->files); + set_fs(old_fs); + + return 0; + + open_err: + set_fs(old_fs); + return FAIL; +} + +static ssize_t show_intensity_logging_off(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct mms_ts_info *info = dev_get_drvdata(dev); + intensity_log_flag = 0; + usleep_range(10000); + get_raw_data_all(info, MMS_VSC_CMD_EXIT); + return 0; +} + +#endif + +static DEVICE_ATTR(close_tsp_test, S_IRUGO, show_close_tsp_test, NULL); +static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, store_cmd); +static DEVICE_ATTR(cmd_status, S_IRUGO, show_cmd_status, NULL); +static DEVICE_ATTR(cmd_result, S_IRUGO, show_cmd_result, NULL); +#ifdef ESD_DEBUG +static DEVICE_ATTR(intensity_logging_on, S_IRUGO, show_intensity_logging_on, + NULL); +static DEVICE_ATTR(intensity_logging_off, S_IRUGO, show_intensity_logging_off, + NULL); +#endif + +static struct attribute *sec_touch_facotry_attributes[] = { + &dev_attr_close_tsp_test.attr, + &dev_attr_cmd.attr, + &dev_attr_cmd_status.attr, + &dev_attr_cmd_result.attr, +#ifdef ESD_DEBUG + &dev_attr_intensity_logging_on.attr, + &dev_attr_intensity_logging_off.attr, +#endif + NULL, +}; + +static struct attribute_group sec_touch_factory_attr_group = { + .attrs = sec_touch_facotry_attributes, +}; +#endif /* SEC_TSP_FACTORY_TEST */ + +static int __devinit mms_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct mms_ts_info *info; + struct input_dev *input_dev; + int ret = 0; +#ifdef SEC_TSP_FACTORY_TEST + int i; + struct device *fac_dev_ts; +#endif + touch_is_pressed = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -EIO; + + info = kzalloc(sizeof(struct mms_ts_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_alloc; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev, "Failed to allocate memory for input device\n"); + ret = -ENOMEM; + goto err_input_alloc; + } + + info->client = client; + info->input_dev = input_dev; + info->pdata = client->dev.platform_data; + info->irq = -1; + mutex_init(&info->lock); + if (info->pdata) { + info->max_x = info->pdata->max_x; + info->max_y = info->pdata->max_y; + info->invert_x = info->pdata->invert_x; + info->invert_y = info->pdata->invert_y; + info->config_fw_version = info->pdata->config_fw_version; + info->register_cb = info->pdata->register_cb; + } else { + info->max_x = 720; + info->max_y = 1280; + } + + i2c_set_clientdata(client, info); + + info->callbacks.inform_charger = melfas_ta_cb; + if (info->register_cb) + info->register_cb(&info->callbacks); + + input_mt_init_slots(input_dev, MAX_FINGERS); + + snprintf(info->phys, sizeof(info->phys), + "%s/input0", dev_name(&client->dev)); + input_dev->name = "sec_touchscreen"; /*= "Melfas MMSxxx Touchscreen";*/ + input_dev->phys = info->phys; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, MAX_WIDTH, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, info->max_x, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, info->max_y, 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MAJOR, + 0, MAX_PRESSURE, 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MINOR, + 0, MAX_PRESSURE, 0, 0); + input_set_abs_params(input_dev, ABS_MT_ANGLE, + MIN_ANGLE, MAX_ANGLE, 0, 0); + input_set_abs_params(input_dev, ABS_MT_PALM, + 0, 1, 0, 0); + input_set_drvdata(input_dev, info); + + ret = input_register_device(input_dev); + if (ret) { + dev_err(&client->dev, "failed to register input dev (%d)\n", + ret); + goto err_reg_input_dev; + } + +#ifdef TOUCH_BOOSTER + mutex_init(&info->dvfs_lock); + INIT_DELAYED_WORK(&info->work_dvfs_off, set_dvfs_off); + INIT_DELAYED_WORK(&info->work_dvfs_chg, change_dvfs_lock); + info->dvfs_lock_status = false; +#endif + +#if ISC_DL_MODE + ret = mms_ts_fw_load(info); +#else + ret = mms_ts_fw_info(info); +#endif + if (ret) + dev_err(&client->dev, "failed to check the firmware"); + + info->enabled = true; + +#ifdef CONFIG_HAS_EARLYSUSPEND + info->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + info->early_suspend.suspend = mms_ts_early_suspend; + info->early_suspend.resume = mms_ts_late_resume; + register_early_suspend(&info->early_suspend); +#endif + +#ifdef SEC_TSP_FACTORY_TEST + INIT_LIST_HEAD(&info->cmd_list_head); + for (i = 0; i < ARRAY_SIZE(tsp_cmds); i++) + list_add_tail(&tsp_cmds[i].list, &info->cmd_list_head); + + mutex_init(&info->cmd_lock); + info->cmd_is_running = false; + + fac_dev_ts = device_create(sec_class, + NULL, 0, info, "tsp"); + if (IS_ERR(fac_dev_ts)) + dev_err(&client->dev, "Failed to create device for the sysfs\n"); + + ret = sysfs_create_group(&fac_dev_ts->kobj, + &sec_touch_factory_attr_group); + if (ret) + dev_err(&client->dev, "Failed to create sysfs group\n"); +#endif + + return 0; + +err_reg_input_dev: + input_free_device(input_dev); +err_input_alloc: + kfree(info->fw_name); + kfree(info); +err_alloc: + return ret; +} + +static int __devexit mms_ts_remove(struct i2c_client *client) +{ + struct mms_ts_info *info = i2c_get_clientdata(client); + + if (info->irq >= 0) + free_irq(info->irq, info); + input_unregister_device(info->input_dev); + kfree(info->fw_name); + kfree(info); + + return 0; +} + +#if defined(CONFIG_PM) || defined(CONFIG_HAS_EARLYSUSPEND) +static int mms_ts_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mms_ts_info *info = i2c_get_clientdata(client); +#ifdef SEC_TSP_DEBUG + int mt_val; +#endif + + dev_notice(&info->client->dev, "%s: users=%d\n", __func__, + info->input_dev->users); + mutex_lock(&info->input_dev->mutex); + if (!info->input_dev->users) + goto out; + + mms_ts_disable(info, 0); + touch_is_pressed = 0; + release_all_fingers(info); + info->pdata->vdd_on(0); + msleep(50); + +out: + mutex_unlock(&info->input_dev->mutex); + return 0; +} + +static int mms_ts_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mms_ts_info *info = i2c_get_clientdata(client); + int ret = 0; + + dev_notice(&info->client->dev, "%s: users=%d\n", __func__, + info->input_dev->users); + info->pdata->vdd_on(1); + msleep(120); + + if (info->ta_status) { + dev_notice(&client->dev, "TA connect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x1); + } else { + dev_notice(&client->dev, "TA disconnect!!!\n"); + i2c_smbus_write_byte_data(info->client, 0x33, 0x2); + } + + mms_set_noise_mode(info); + mutex_lock(&info->input_dev->mutex); + if (info->input_dev->users) + ret = mms_ts_enable(info, 0); + mutex_unlock(&info->input_dev->mutex); + + return ret; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mms_ts_early_suspend(struct early_suspend *h) +{ + struct mms_ts_info *info; + info = container_of(h, struct mms_ts_info, early_suspend); + mms_ts_suspend(&info->client->dev); +} + +static void mms_ts_late_resume(struct early_suspend *h) +{ + struct mms_ts_info *info; + info = container_of(h, struct mms_ts_info, early_suspend); + mms_ts_resume(&info->client->dev); +} +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static const struct dev_pm_ops mms_ts_pm_ops = { + .suspend = mms_ts_suspend, + .resume = mms_ts_resume, +}; +#endif + +static const struct i2c_device_id mms_ts_id[] = { + { "mms_ts", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mms_ts_id); + +static struct i2c_driver mms_ts_driver = { + .probe = mms_ts_probe, + .remove = __devexit_p(mms_ts_remove), + .driver = { + .name = "mms_ts", +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) + .pm = &mms_ts_pm_ops, +#endif + }, + .id_table = mms_ts_id, +}; + +static int __init mms_ts_init(void) +{ +#ifdef CONFIG_BATTERY_SEC + if (poweroff_charging) { + pr_info("%s : LPM Charging Mode!!\n", __func__); + return 0; + } +#endif + + return i2c_add_driver(&mms_ts_driver); +} + +static void __exit mms_ts_exit(void) +{ + i2c_del_driver(&mms_ts_driver); +} + +module_init(mms_ts_init); +module_exit(mms_ts_exit); + +/* Module information */ +MODULE_DESCRIPTION("Touchscreen driver for Melfas MMS-series controllers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/mms_ts_fw.h b/drivers/input/touchscreen/mms_ts_fw.h new file mode 100644 index 00000000000..0650103bcec --- /dev/null +++ b/drivers/input/touchscreen/mms_ts_fw.h @@ -0,0 +1,65 @@ +/* Melfas MMS-100 seies firmware list */ + +#if defined(CONFIG_TOUCHSCREEN_MMS136) || \ + defined(CONFIG_TOUCHSCREEN_MMS136_TABLET) + +#if defined(CONFIG_MACH_JASPER) +#define SEC_TKEY_FACTORY_TEST +#define FW_VERSION 0x23 +#include "jasper_fw.h" +#elif defined(CONFIG_MACH_APEXQ) +#define FW_VERSION 0x1 +#include "apexq_fw.h" +#elif defined(CONFIG_MACH_INFINITE) +#define SEC_TKEY_FACTORY_TEST +#define FW_VERSION 0x1 +#include "infinite_fw.h" +#elif defined(CONFIG_MACH_GOGH) +#define FW_VERSION 0x11 +#include "gogh_fw.h" +#elif defined(CONFIG_MACH_ESPRESSO_ATT) || defined(CONFIG_MACH_ESPRESSO_VZW) \ + || defined(CONFIG_MACH_ESPRESSO_SPR) +#define FW_VERSION 0x16 +#include "espresso_fw.h" +#else +#define FW_VERSION 0x0 +const size_t MELFAS_binary_nLength = 0x00; +const u8 MELFAS_binary[] = { + +}; +#endif + +#elif defined(CONFIG_TOUCHSCREEN_MMS144) + +#if defined(CONFIG_MACH_M2_VZW) || defined(CONFIG_MACH_M2_ATT)\ + || defined(CONFIG_MACH_M2_SPR) || defined(CONFIG_MACH_M2_SKT)\ + || defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_STRETTO)\ + || defined(CONFIG_MACH_SUPERIORLTE_SKT)\ + || defined(CONFIG_MACH_K2_KDI) +/* 4.8" OCTA LCD */ +#define FW_VERSION 0xBB +#include "d2_fw.h" +/* 4.65" OCTA LCD */ +#define FW_465_VERSION 0xA8 +#include "d2_465_fw.h" +#else +/* 4.8" OCTA LCD */ +#define FW_VERSION 0x0 +const size_t MELFAS_binary_nLength = 0x00; +const u8 MELFAS_binary[] = { + +}; + +/* 4.65" OCTA LCD */ +#define FW_465_VERSION 0x0 +const size_t MELFAS_465_binary_nLength = 0x00; +const u8 MELFAS_465_binary[] = { + +}; +#endif +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +extern void set_esd_enable(void); +extern void set_esd_disable(void); +#endif + +#endif diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index c688898cbf3..8bd5ff57b09 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o -obj-$(CONFIG_LEDS_PM8XXX) += leds-pm8xxx.o +obj-$(CONFIG_LEDS_PM8XXX) += leds-pm8xxx-m2.o obj-$(CONFIG_LEDS_QPNP) += leds-qpnp.o obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o diff --git a/drivers/leds/leds-pm8xxx-m2.c b/drivers/leds/leds-pm8xxx-m2.c new file mode 100644 index 00000000000..72673ca8d44 --- /dev/null +++ b/drivers/leds/leds-pm8xxx-m2.c @@ -0,0 +1,1287 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SSBI_REG_ADDR_DRV_KEYPAD 0x48 +#define PM8XXX_DRV_KEYPAD_BL_MASK 0xf0 +#define PM8XXX_DRV_KEYPAD_BL_SHIFT 0x04 + +#define SSBI_REG_ADDR_FLASH_DRV0 0x49 +#define PM8XXX_DRV_FLASH_MASK 0xf0 +#define PM8XXX_DRV_FLASH_SHIFT 0x04 + +#define SSBI_REG_ADDR_FLASH_DRV1 0xFB + +#define SSBI_REG_ADDR_LED_CTRL_BASE 0x131 +#define SSBI_REG_ADDR_LED_CTRL(n) (SSBI_REG_ADDR_LED_CTRL_BASE + (n)) +#define PM8XXX_DRV_LED_CTRL_MASK 0xf8 +#define PM8XXX_DRV_LED_CTRL_SHIFT 0x03 + +#define MAX_FLASH_LED_CURRENT 300 +#define MAX_LC_LED_CURRENT 40 +#define MAX_KP_BL_LED_CURRENT 300 + +#define PM8XXX_ID_LED_CURRENT_FACTOR 2 /* Iout = x * 2mA */ +#define PM8XXX_ID_FLASH_CURRENT_FACTOR 20 /* Iout = x * 20mA */ + +#define PM8XXX_FLASH_MODE_DBUS1 1 +#define PM8XXX_FLASH_MODE_DBUS2 2 +#define PM8XXX_FLASH_MODE_PWM 3 + +#define MAX_LC_LED_BRIGHTNESS 20 +#define MAX_FLASH_BRIGHTNESS 15 +#define MAX_KB_LED_BRIGHTNESS 15 + +#define PM8XXX_LED_OFFSET(id) ((id) - PM8XXX_ID_LED_0) + +#define PM8XXX_LED_PWM_FLAGS (PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP |\ + PM_PWM_LUT_REVERSE | PM_PWM_LUT_PAUSE_HI_EN | \ + PM_PWM_LUT_PAUSE_LO_EN) + +/* low_powermode is for led blinking level */ +int low_powermode; +#define LOW_POWERMODE_DIVIDER 9 + +/** + * struct pm8xxx_led_data - internal led data structure + * @led_classdev - led class device + * @id - led index + * @work - workqueue for led + * @lock - to protect the transactions + * @reg - cached value of led register + * @pwm_dev - pointer to PWM device if LED is driven using PWM + * @pwm_channel - PWM channel ID + * @pwm_period_us - PWM period in micro seconds + * @pwm_duty_cycles - struct that describes PWM duty cycles info + */ +struct pm8xxx_led_data { + struct led_classdev cdev; + int id; + u8 reg; + struct device *dev; + struct work_struct work; + struct mutex lock; + struct pwm_device *pwm_dev; + int pwm_channel; + u32 pwm_period_us; + struct pm8xxx_pwm_duty_cycles *pwm_duty_cycles; +}; + + +static void led_kp_set(struct pm8xxx_led_data *led, enum led_brightness value) +{ + int rc; + u8 level; + + level = (value << PM8XXX_DRV_KEYPAD_BL_SHIFT) & + PM8XXX_DRV_KEYPAD_BL_MASK; + + led->reg &= ~PM8XXX_DRV_KEYPAD_BL_MASK; + led->reg |= level; + + rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_DRV_KEYPAD, + led->reg); + if (rc < 0) + dev_err(led->cdev.dev, + "can't set keypad backlight level rc=%d\n", rc); +} + +static void led_lc_set(struct pm8xxx_led_data *led, enum led_brightness value) +{ + int rc, offset; + u8 level; + level = (value << PM8XXX_DRV_LED_CTRL_SHIFT) & + PM8XXX_DRV_LED_CTRL_MASK; + + offset = PM8XXX_LED_OFFSET(led->id); + + led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK; + led->reg |= level; + + rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), + led->reg); + if (rc) + dev_err(led->cdev.dev, "can't set (%d) led value rc=%d\n", + led->id, rc); +} + +static void +led_flash_set(struct pm8xxx_led_data *led, enum led_brightness value) +{ + int rc; + u8 level; + u16 reg_addr; + + level = (value << PM8XXX_DRV_FLASH_SHIFT) & + PM8XXX_DRV_FLASH_MASK; + + led->reg &= ~PM8XXX_DRV_FLASH_MASK; + led->reg |= level; + + if (led->id == PM8XXX_ID_FLASH_LED_0) + reg_addr = SSBI_REG_ADDR_FLASH_DRV0; + else + reg_addr = SSBI_REG_ADDR_FLASH_DRV1; + + rc = pm8xxx_writeb(led->dev->parent, reg_addr, led->reg); + if (rc < 0) + dev_err(led->cdev.dev, "can't set flash led%d level rc=%d\n", + led->id, rc); +} + +static int pm8xxx_led_pwm_work(struct pm8xxx_led_data *led) +{ + int duty_us; + int rc = 0; + + if (led->pwm_duty_cycles == NULL) { + duty_us = (led->pwm_period_us * led->cdev.brightness) / + LED_FULL; + rc = pwm_config(led->pwm_dev, duty_us, led->pwm_period_us); + if (led->cdev.brightness) + rc = pwm_enable(led->pwm_dev); + else + pwm_disable(led->pwm_dev); + } else { + rc = pm8xxx_pwm_lut_enable(led->pwm_dev, led->cdev.brightness); + } + + return rc; +} + +static void __pm8xxx_led_work(struct pm8xxx_led_data *led, + enum led_brightness level) +{ + mutex_lock(&led->lock); + + switch (led->id) { + case PM8XXX_ID_LED_KB_LIGHT: + led_kp_set(led, level); + break; + case PM8XXX_ID_LED_0: + case PM8XXX_ID_LED_1: + case PM8XXX_ID_LED_2: + level = level / PM8XXX_ID_LED_CURRENT_FACTOR; + led_lc_set(led, level); + break; + case PM8XXX_ID_FLASH_LED_0: + case PM8XXX_ID_FLASH_LED_1: + led_flash_set(led, level); + break; + } + + mutex_unlock(&led->lock); +} + +static void pm8xxx_led_work(struct work_struct *work) +{ + int rc; + + struct pm8xxx_led_data *led = container_of(work, + struct pm8xxx_led_data, work); + + if (led->pwm_dev == NULL) { + __pm8xxx_led_work(led, led->cdev.brightness); + } else { + rc = pm8xxx_led_pwm_work(led); + if (rc) + pr_err("could not configure PWM mode for LED:%d\n", + led->id); + } +} + +static void pm8xxx_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct pm8xxx_led_data *led; + + led = container_of(led_cdev, struct pm8xxx_led_data, cdev); + + if (value < LED_OFF || value > led->cdev.max_brightness) { + dev_err(led->cdev.dev, "Invalid brightness value exceeds\n"); + return; + } + led->cdev.brightness = value; + schedule_work(&led->work); +} + +static int pm8xxx_set_led_mode_and_max_brightness(struct pm8xxx_led_data *led, + enum pm8xxx_led_modes led_mode, int max_current) +{ + int rc = 0; + + switch (led->id) { + case PM8XXX_ID_LED_0: + case PM8XXX_ID_LED_1: + case PM8XXX_ID_LED_2: + led->cdev.max_brightness = LED_FULL; + led->reg = led_mode; + break; + case PM8XXX_ID_LED_KB_LIGHT: + case PM8XXX_ID_FLASH_LED_0: + case PM8XXX_ID_FLASH_LED_1: + led->cdev.max_brightness = max_current / + PM8XXX_ID_FLASH_CURRENT_FACTOR; + if (led->cdev.max_brightness > MAX_FLASH_BRIGHTNESS) + led->cdev.max_brightness = MAX_FLASH_BRIGHTNESS; + + switch (led_mode) { + case PM8XXX_LED_MODE_PWM1: + case PM8XXX_LED_MODE_PWM2: + case PM8XXX_LED_MODE_PWM3: + led->reg = PM8XXX_FLASH_MODE_PWM; + break; + case PM8XXX_LED_MODE_DTEST1: + led->reg = PM8XXX_FLASH_MODE_DBUS1; + break; + case PM8XXX_LED_MODE_DTEST2: + led->reg = PM8XXX_FLASH_MODE_DBUS2; + break; + default: + led->reg = PM8XXX_LED_MODE_MANUAL; + break; + } + break; + default: + rc = -EINVAL; + pr_err("LED Id is invalid"); + break; + } + + return rc; +} + +static enum led_brightness pm8xxx_led_get(struct led_classdev *led_cdev) +{ + struct pm8xxx_led_data *led; + + led = container_of(led_cdev, struct pm8xxx_led_data, cdev); + + return led->cdev.brightness; +} + +static int __devinit get_init_value(struct pm8xxx_led_data *led, u8 *val) +{ + int rc = -1 , offset = 0; + u16 addr = 0; + + switch (led->id) { + case PM8XXX_ID_LED_KB_LIGHT: + addr = SSBI_REG_ADDR_DRV_KEYPAD; + break; + case PM8XXX_ID_LED_0: + case PM8XXX_ID_LED_1: + case PM8XXX_ID_LED_2: + offset = PM8XXX_LED_OFFSET(led->id); + addr = SSBI_REG_ADDR_LED_CTRL(offset); + break; + case PM8XXX_ID_FLASH_LED_0: + addr = SSBI_REG_ADDR_FLASH_DRV0; + break; + case PM8XXX_ID_FLASH_LED_1: + addr = SSBI_REG_ADDR_FLASH_DRV1; + break; + default: + return rc; + } + + rc = pm8xxx_readb(led->dev->parent, addr, val); + if (rc) + dev_err(led->cdev.dev, "can't get led(%d) level rc=%d\n", + led->id, rc); + + return rc; +} + +static int pm8xxx_led_pwm_configure(struct pm8xxx_led_data *led, + int lo_pause, int hi_pause) +{ + int start_idx, idx_len, duty_us, rc; + + led->pwm_dev = pwm_request(led->pwm_channel, + led->cdev.name); + + if (IS_ERR_OR_NULL(led->pwm_dev)) { + pr_err("could not acquire PWM Channel %d, " + "error %ld\n", led->pwm_channel, + PTR_ERR(led->pwm_dev)); + led->pwm_dev = NULL; + return -ENODEV; + } + + if (led->pwm_duty_cycles != NULL) { + start_idx = led->pwm_duty_cycles->start_idx; + idx_len = led->pwm_duty_cycles->num_duty_pcts; + + if (idx_len >= PM_PWM_LUT_SIZE && start_idx) { + pr_err("Wrong LUT size or index\n"); + return -EINVAL; + } + if ((start_idx + idx_len) > PM_PWM_LUT_SIZE) { + pr_err("Exceed LUT limit\n"); + return -EINVAL; + } + + rc = pm8xxx_pwm_lut_config(led->pwm_dev, led->pwm_period_us, + led->pwm_duty_cycles->duty_pcts, + led->pwm_duty_cycles->duty_ms, + start_idx, idx_len, lo_pause, hi_pause, + PM8XXX_LED_PWM_FLAGS); + } else { + duty_us = led->pwm_period_us; + rc = pwm_config(led->pwm_dev, duty_us, led->pwm_period_us); + } + + return rc; +} + +#ifndef CONFIG_LEDS_PM8XXX +#define CONFIG_LEDS_PM8XXX +#endif +struct leds_dev_data { + struct pm8xxx_led_data *led; + struct pm8xxx_led_platform_data *pdata ; + atomic_t op_flag; + struct mutex led_work_lock; + struct work_struct work_pat_batt_chrg; + struct work_struct work_pat_chrg_err; + struct work_struct work_pat_miss_noti; + struct work_struct work_pat_in_lowbat; + struct work_struct work_pat_full_chrg; + struct work_struct work_pat_powering; +}; +#ifdef CONFIG_LEDS_PM8XXX + +static void pm8xxx_led_work_pat_led_off(struct leds_dev_data *info) +{ + int loop_cnt; + + mutex_lock(&info->led_work_lock); + if (info->pdata->led_power_on) + info->pdata->led_power_on(0); + for (loop_cnt = 0 ; loop_cnt < ((info->pdata->led_core->num_leds) - 1) ; + loop_cnt++) { + __pm8xxx_led_work(&info->led[loop_cnt], 0); + if (info->led[loop_cnt].pwm_dev != NULL) + pwm_free(info->led[loop_cnt].pwm_dev); + } + + mutex_unlock(&info->led_work_lock); + +} +static void pm8xxx_led_work_pat_powering(struct work_struct *work) +{ + struct leds_dev_data *info = + container_of(work, struct leds_dev_data, work_pat_powering); + struct pm8xxx_led_config *led_cfg; + int loop_cnt; + + if (!atomic_read(&info->op_flag)) { + pr_info("LED turns off before turns on, op:%d\n", + atomic_read(&info->op_flag)); + return; + } + + pm8xxx_led_work_pat_led_off(info); + mutex_lock(&info->led_work_lock); + + for (loop_cnt = PM8XXX_LED_PAT6_GREEN ; + loop_cnt <= PM8XXX_LED_PAT6_BLUE ; + loop_cnt++) { + led_cfg = &info->pdata->configs[loop_cnt]; + + pm8xxx_set_led_mode_and_max_brightness(&info->led[loop_cnt], + led_cfg->mode, led_cfg->max_current); + + __pm8xxx_led_work(&info->led[loop_cnt], led_cfg->max_current); + + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[loop_cnt], + 200, 200); + } + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT6_GREEN].cdev, + led_cfg->max_current); + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT6_BLUE].cdev, + led_cfg->max_current); + + mutex_unlock(&info->led_work_lock); +} +static void pm8xxx_led_work_pat_full_chrg(struct work_struct *work) +{ + struct leds_dev_data *info = + container_of(work, struct leds_dev_data, work_pat_full_chrg); + struct pm8xxx_led_config *led_cfg; + + if (!atomic_read(&info->op_flag)) { + pr_info("LED turns off before turns on, op:%d\n", + atomic_read(&info->op_flag)); + return; + } + + pm8xxx_led_work_pat_led_off(info); + mutex_lock(&info->led_work_lock); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT5_GREEN]; + + pm8xxx_set_led_mode_and_max_brightness( + &info->led[PM8XXX_LED_PAT5_GREEN], + led_cfg->mode, led_cfg->max_current); + + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT5_GREEN], + led_cfg->max_current); + + if (low_powermode) { + led_cfg->pwm_duty_cycles->duty_pcts[0] + = 100/LOW_POWERMODE_DIVIDER; + led_cfg->pwm_duty_cycles->duty_pcts[1] + = 100/LOW_POWERMODE_DIVIDER; + } else { + led_cfg->pwm_duty_cycles->duty_pcts[0] = 100; + led_cfg->pwm_duty_cycles->duty_pcts[1] = 100; + } + + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT5_GREEN], + 0, 0); + + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT5_GREEN].cdev, + led_cfg->max_current); + + mutex_unlock(&info->led_work_lock); + +} +static void pm8xxx_led_work_pat_in_lowbat(struct work_struct *work) +{ + struct leds_dev_data *info = + container_of(work, struct leds_dev_data, work_pat_in_lowbat); + struct pm8xxx_led_config *led_cfg; + + if (!atomic_read(&info->op_flag)) { + pr_info("LED turns off before turns on, op:%d\n", + atomic_read(&info->op_flag)); + return; + } + + pm8xxx_led_work_pat_led_off(info); + + mutex_lock(&info->led_work_lock); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT4_RED]; + pm8xxx_set_led_mode_and_max_brightness(&info->led[PM8XXX_LED_PAT4_RED], + led_cfg->mode, led_cfg->max_current); + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT4_RED], + led_cfg->max_current); + + if (low_powermode) { + led_cfg->pwm_duty_cycles->duty_pcts[1] + = 100/LOW_POWERMODE_DIVIDER; + } else { + led_cfg->pwm_duty_cycles->duty_pcts[1] = 100; + } + + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT4_RED], + 5000, 500); + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT4_RED].cdev, + led_cfg->max_current); + mutex_unlock(&info->led_work_lock); + +} +static void pm8xxx_led_work_pat_miss_noti(struct work_struct *work) +{ + struct leds_dev_data *info = + container_of(work, struct leds_dev_data, work_pat_miss_noti); + struct pm8xxx_led_config *led_cfg; + + if (!atomic_read(&info->op_flag)) { + pr_info("LED turns off before turns on, op:%d\n", + atomic_read(&info->op_flag)); + return; + } + + pm8xxx_led_work_pat_led_off(info); + mutex_lock(&info->led_work_lock); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT3_BLUE]; + + pm8xxx_set_led_mode_and_max_brightness(&info->led[PM8XXX_LED_PAT3_BLUE], + led_cfg->mode, led_cfg->max_current); + + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT3_BLUE], + led_cfg->max_current); + + if (low_powermode) { + led_cfg->pwm_duty_cycles->duty_pcts[1] + = 100/LOW_POWERMODE_DIVIDER; + } else { + led_cfg->pwm_duty_cycles->duty_pcts[1] = 100; + } + + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT3_BLUE], + 5000, 500); + + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT3_BLUE].cdev, + led_cfg->max_current); + + mutex_unlock(&info->led_work_lock); +} + +static void pm8xxx_led_work_pat_chrg_err(struct work_struct *work) +{ + struct leds_dev_data *info = + container_of(work, struct leds_dev_data, work_pat_chrg_err); + struct pm8xxx_led_config *led_cfg; + + if (!atomic_read(&info->op_flag)) { + pr_info("LED turns off before turns on, op:%d\n", + atomic_read(&info->op_flag)); + return; + } + + pm8xxx_led_work_pat_led_off(info); + mutex_lock(&info->led_work_lock); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT2_RED]; + + pm8xxx_set_led_mode_and_max_brightness(&info->led[PM8XXX_LED_PAT2_RED], + led_cfg->mode, led_cfg->max_current); + + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT2_RED], + led_cfg->max_current); + + if (low_powermode) { + led_cfg->pwm_duty_cycles->duty_pcts[1] + = 100/LOW_POWERMODE_DIVIDER; + } else { + led_cfg->pwm_duty_cycles->duty_pcts[1] = 100; + } + + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT2_RED], + 500, 500); + + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT2_RED].cdev, + led_cfg->max_current); + + mutex_unlock(&info->led_work_lock); +} + + +static void pm8xxx_led_work_pat_batt_chrg(struct work_struct *work) +{ + struct leds_dev_data *info = + container_of(work, struct leds_dev_data, work_pat_batt_chrg); + struct pm8xxx_led_config *led_cfg; + + if (!atomic_read(&info->op_flag)) { + pr_info("LED turns off before turns on, op:%d\n", + atomic_read(&info->op_flag)); + return; + } + pm8xxx_led_work_pat_led_off(info); + mutex_lock(&info->led_work_lock); + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT1_RED]; + + pm8xxx_set_led_mode_and_max_brightness(&info->led[PM8XXX_LED_PAT1_RED], + led_cfg->mode, led_cfg->max_current); + + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT1_RED], + led_cfg->max_current); + + if (low_powermode) { + led_cfg->pwm_duty_cycles->duty_pcts[0] + = 100/LOW_POWERMODE_DIVIDER; + led_cfg->pwm_duty_cycles->duty_pcts[1] + = 100/LOW_POWERMODE_DIVIDER; + } else { + led_cfg->pwm_duty_cycles->duty_pcts[0] = 100; + led_cfg->pwm_duty_cycles->duty_pcts[1] = 100; + } + + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT1_RED], + 0, 0); + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT1_RED].cdev, + led_cfg->max_current); + mutex_unlock(&info->led_work_lock); + +} + +static ssize_t led_pattern_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct leds_dev_data *info = dev_get_drvdata(dev); + return snprintf(buf, 4, "%u\n", atomic_read(&info->op_flag)); +} + +static ssize_t led_pattern_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct leds_dev_data *info = dev_get_drvdata(dev); + + if (buf[0] == '1') { + if ((info->pdata->led_power_on)) + info->pdata->led_power_on(1); + atomic_set(&info->op_flag , 1); + pr_info("LED Battery Charging Pattern on\n"); + schedule_work(&info->work_pat_batt_chrg); + + } else if (buf[0] == '2') { + if ((info->pdata->led_power_on)) + info->pdata->led_power_on(1); + atomic_set(&info->op_flag , 2); + pr_info("LED Battery Charging Error Pattern on\n"); + schedule_work(&info->work_pat_chrg_err); + + } else if (buf[0] == '3') { + if ((info->pdata->led_power_on)) + info->pdata->led_power_on(1); + atomic_set(&info->op_flag , 3); + pr_info("LED Missed Call Notifications pattern on\n"); + schedule_work(&info->work_pat_miss_noti); + + } else if (buf[0] == '4') { + if ((info->pdata->led_power_on)) + info->pdata->led_power_on(1); + atomic_set(&info->op_flag , 4); + pr_info("LED Low Battery Pattern on\n"); + schedule_work(&info->work_pat_in_lowbat); + + } else if (buf[0] == '5') { + if ((info->pdata->led_power_on)) + info->pdata->led_power_on(1); + + atomic_set(&info->op_flag , 5); + pr_info("LED Full Battery Charging Pattern on\n"); + schedule_work(&info->work_pat_full_chrg); + + } else if (buf[0] == '6') { + if ((info->pdata->led_power_on)) + info->pdata->led_power_on(1); + atomic_set(&info->op_flag , 6); + pr_info("LED Powering on pattern\n"); + schedule_work(&info->work_pat_powering); + + } else if (buf[0] == '7') { + if ((info->pdata->led_power_on)) + info->pdata->led_power_on(1); + atomic_set(&info->op_flag , 7); + schedule_work(&info->work_pat_powering); + + } else if (buf[0] == '0') { + atomic_set(&info->op_flag , 0); + pr_info("LED turned off\n"); + pm8xxx_led_work_pat_led_off(info); + } + return size; + +} + +static DEVICE_ATTR(led_pattern, S_IRUGO | S_IWUSR | S_IWGRP, + led_pattern_show, led_pattern_store); + +static ssize_t led_lowpower_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#if 0 + struct leds_dev_data *info = dev_get_drvdata(dev); +#endif + return snprintf(buf, 4, "%d\n", low_powermode); +} + +static ssize_t led_lowpower_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ +#if 0 + struct leds_dev_data *info = dev_get_drvdata(dev); +#endif + if (buf[0] == '1') + low_powermode = 1; + else + low_powermode = 0; + return size; +} + +static DEVICE_ATTR(led_lowpower, S_IRUGO | S_IWUSR | S_IWGRP, + led_lowpower_show, led_lowpower_store); + + +static ssize_t led_r_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int brightness; + struct leds_dev_data *info = dev_get_drvdata(dev); + brightness = pm8xxx_led_get(&info->led[PM8XXX_LED_PAT7_RED].cdev); + return snprintf(buf, 4, "%u\n", brightness); +} + +static ssize_t led_r_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct leds_dev_data *info = dev_get_drvdata(dev); + struct pm8xxx_led_config *led_cfg; + unsigned int brightness = 0; + unsigned int num_digits = size; + unsigned int loop_cnt = 0; + int temp; + + printk(KERN_DEBUG "led_r brightness =%s, numdigs=%u\n", + buf, num_digits); + while ((buf[loop_cnt] >= '0') && (buf[loop_cnt] <= '9') && + (loop_cnt < num_digits)) { + brightness = brightness*10 + (buf[loop_cnt] - '0'); + loop_cnt++; + } + + printk(KERN_DEBUG "led_r brightness =%u\n", brightness); + + if (brightness < 0 || brightness > 255) { + printk(KERN_WARNING "led_r brightness is out of range"); + return -1; + } + temp = pm8xxx_led_get(&info->led[PM8XXX_LED_PAT7_RED].cdev); + + if (brightness == 0 && temp == 0) + return size; + if (atomic_read(&info->op_flag)) + atomic_set(&info->op_flag, 0); + + pm8xxx_led_work_pat_led_off(info); + + mutex_lock(&info->led_work_lock); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT7_RED]; + + pm8xxx_set_led_mode_and_max_brightness(&info->led[PM8XXX_LED_PAT7_RED], + led_cfg->mode, led_cfg->max_current); + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT7_RED], + led_cfg->max_current); + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT7_RED], 0, 0); + + if (brightness && (info->pdata->led_power_on)) + info->pdata->led_power_on(1); + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT7_RED].cdev, brightness); + mutex_unlock(&info->led_work_lock); + + return size; + +} + +static DEVICE_ATTR(led_r, S_IRUGO | S_IWUSR | S_IWGRP, + led_r_show, led_r_store); + +static ssize_t led_g_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int brightness; + struct leds_dev_data *info = dev_get_drvdata(dev); + brightness = pm8xxx_led_get(&info->led[PM8XXX_LED_PAT7_GREEN].cdev); + return snprintf(buf, 4, "%u\n", brightness); +} + +static ssize_t led_g_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct leds_dev_data *info = dev_get_drvdata(dev); + struct pm8xxx_led_config *led_cfg; + unsigned int brightness = 0; + unsigned int num_digits = size; + unsigned int loop_cnt = 0; + int temp; + printk(KERN_DEBUG "led_g brightness =%s, numdigs=%u\n", + buf, num_digits); + while ((buf[loop_cnt] >= '0') && (buf[loop_cnt] <= '9') && + (loop_cnt < num_digits)) { + brightness = brightness*10 + (buf[loop_cnt] - '0'); + loop_cnt++; + } + printk(KERN_DEBUG "led_g brightness =%u\n", brightness); + + if (brightness < 0 || brightness > 255) { + printk(KERN_WARNING "led_g brightness is out of range"); + return -1; + } + temp = pm8xxx_led_get(&info->led[PM8XXX_LED_PAT7_GREEN].cdev); + if (brightness == 0 && temp == 0) + return size; + if (atomic_read(&info->op_flag)) + atomic_set(&info->op_flag, 0); + + pm8xxx_led_work_pat_led_off(info); + mutex_lock(&info->led_work_lock); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT7_GREEN]; + + pm8xxx_set_led_mode_and_max_brightness( + &info->led[PM8XXX_LED_PAT7_GREEN], + led_cfg->mode, led_cfg->max_current); + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT7_GREEN], + led_cfg->max_current); + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT7_GREEN], + 0, 0); + if (brightness && (info->pdata->led_power_on)) + info->pdata->led_power_on(1); + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT7_GREEN].cdev, brightness); + mutex_unlock(&info->led_work_lock); + return size; + +} + +static DEVICE_ATTR(led_g, S_IRUGO | S_IWUSR | S_IWGRP, + led_g_show, led_g_store); + +static ssize_t led_b_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int brightness; + struct leds_dev_data *info = dev_get_drvdata(dev); + brightness = pm8xxx_led_get(&info->led[PM8XXX_LED_PAT7_BLUE].cdev); + return snprintf(buf, 4, "%u\n", brightness); +} + +static ssize_t led_b_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct leds_dev_data *info = dev_get_drvdata(dev); + struct pm8xxx_led_config *led_cfg; + unsigned int brightness = 0; + unsigned int num_digits = size; + unsigned int loop_cnt = 0; + int temp; + printk(KERN_DEBUG "led_b brightness =%s, numdigs=%u\n", + buf, num_digits); + while ((buf[loop_cnt] >= '0') && (buf[loop_cnt] <= '9') && + (loop_cnt < num_digits)) { + brightness = brightness*10 + (buf[loop_cnt] - '0'); + loop_cnt++; + } + printk(KERN_DEBUG "led_b brightness =%u\n", brightness); + + if (brightness < 0 || brightness > 255) { + printk(KERN_WARNING "led_b brightness is out of range"); + return -1; + } + temp = pm8xxx_led_get(&info->led[PM8XXX_LED_PAT7_BLUE].cdev); + if (brightness == 0 && temp == 0) + return size; + if (atomic_read(&info->op_flag)) + atomic_set(&info->op_flag, 0); + + pm8xxx_led_work_pat_led_off(info); + mutex_lock(&info->led_work_lock); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT7_BLUE]; + + pm8xxx_set_led_mode_and_max_brightness(&info->led[PM8XXX_LED_PAT7_BLUE], + led_cfg->mode, led_cfg->max_current); + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT7_BLUE], + led_cfg->max_current); + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT7_BLUE], + 0, 0); + if (brightness && (info->pdata->led_power_on)) + info->pdata->led_power_on(1); + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT7_BLUE].cdev, brightness); + mutex_unlock(&info->led_work_lock); + + return size; + +} + +static DEVICE_ATTR(led_b, S_IRUGO | S_IWUSR | S_IWGRP, + led_b_show, led_b_store); + +static ssize_t led_blink_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int brightness; + int size = 0; + struct leds_dev_data *info = dev_get_drvdata(dev); + brightness = pm8xxx_led_get(&info->led[PM8XXX_LED_PAT8_RED].cdev); + size += snprintf(buf, 24, "%x ", brightness); + brightness = pm8xxx_led_get(&info->led[PM8XXX_LED_PAT8_GREEN].cdev); + size += snprintf(buf+size, 24, "%x ", brightness); + brightness = pm8xxx_led_get(&info->led[PM8XXX_LED_PAT8_BLUE].cdev); + size += snprintf(buf+size, 24, "%x ", brightness); + buf[size] = 0; + return size; +} + +static unsigned int hex_to_dec(char c1, char c2) +{ + unsigned int ret_val = 0; + if (c1 >= '0' && c1 <= '9') + ret_val = (c1 - '0'); + else if (c1 >= 'A' && c1 <= 'F') + ret_val = (c1 - 'A') + 10; + else if (c1 >= 'a' && c1 <= 'f') + ret_val = (c1 - 'a') + 10; + + ret_val = ret_val * 16; + + if (c2 >= '0' && c2 <= '9') + ret_val += (c2 - '0'); + else if (c2 >= 'A' && c2 <= 'F') + ret_val += (c2 - 'A') + 10; + else if (c2 >= 'a' && c2 <= 'f') + ret_val += (c2 - 'a') + 10; + + return ret_val; + +} +static ssize_t led_blink_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct leds_dev_data *info = dev_get_drvdata(dev); + struct pm8xxx_led_config *led_cfg; + unsigned int brightness_r = 0; + unsigned int brightness_g = 0; + unsigned int brightness_b = 0; + unsigned int loop_cnt = 0; + unsigned int delayon = 0; + unsigned int delayoff = 0; + unsigned int argb_count = 0; + bool is_blinking; + + printk(KERN_ALERT "[LED_blink_store] is \"%s\" (pid %i)\n", + current->comm, current->pid); + printk(KERN_ALERT "led_blink input =%s, size=%d\n", buf, size); + + if (size < 7) { + printk(KERN_DEBUG "led_blink: Invlid input\n"); + return size; + } + if (buf[8] == ' ') { /*case of RGB delay_on delay_off*/ + for (loop_cnt = 9; loop_cnt < size-1; loop_cnt++) { + delayon = delayon*10 + (buf[loop_cnt] - '0'); + if (buf[loop_cnt+1] == ' ') { + loop_cnt += 2; + break; + } + } + for (; loop_cnt < size-1; loop_cnt++) + delayoff = delayoff*10 + (buf[loop_cnt] - '0'); + } + else if (buf[10] == ' ') { /*case of ARGB delay_on delay_off*/ + argb_count = 1; + for (loop_cnt = 11; loop_cnt < size-1; loop_cnt++) { + delayon = delayon*10 + (buf[loop_cnt] - '0'); + if (buf[loop_cnt+1] == ' ') { + loop_cnt += 2; + break; + } + } + for (; loop_cnt < size-1; loop_cnt++) + delayoff = delayoff*10 + (buf[loop_cnt] - '0'); + } + else if (size > 9) { /*case of ARGB*/ + argb_count = 1; + } + atomic_set(&info->op_flag , 0); + /*buf[0], buf[1] contains 0x, so ignore it. case of RGB*/ + if (!argb_count) { + brightness_r = hex_to_dec(buf[2], buf[3]); + brightness_g = hex_to_dec(buf[4], buf[5]); + brightness_b = hex_to_dec(buf[6], buf[7]); + } + /*buf[0], buf[1] contains 0x, so ignore it. + buf[2], buf[3] contains A (alpha value), ignore it.case of ARGB*/ + else { + brightness_r = hex_to_dec(buf[4], buf[5]); + brightness_g = hex_to_dec(buf[6], buf[7]); + brightness_b = hex_to_dec(buf[8], buf[9]); + } + + is_blinking = delayon > 0 || delayoff > 0; + + pm8xxx_led_work_pat_led_off(info); + mutex_lock(&info->led_work_lock); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT8_BLUE]; + brightness_b = brightness_b * 100 / 255; + led_cfg->pwm_duty_cycles->duty_pcts[0] = is_blinking ? 0 : brightness_b; + led_cfg->pwm_duty_cycles->duty_pcts[1] = brightness_b; + pm8xxx_set_led_mode_and_max_brightness(&info->led[PM8XXX_LED_PAT8_BLUE], + led_cfg->mode, led_cfg->max_current); + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT8_BLUE], + led_cfg->max_current); + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT8_BLUE], + delayoff, delayon); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT8_GREEN]; + brightness_g = brightness_g * 100 / 255; + led_cfg->pwm_duty_cycles->duty_pcts[0] = is_blinking ? 0 : brightness_g; + led_cfg->pwm_duty_cycles->duty_pcts[1] = brightness_g; + pm8xxx_set_led_mode_and_max_brightness( + &info->led[PM8XXX_LED_PAT8_GREEN], + led_cfg->mode, led_cfg->max_current); + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT8_GREEN], + led_cfg->max_current); + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT8_GREEN], + delayoff, delayon); + + led_cfg = &info->pdata->configs[PM8XXX_LED_PAT8_RED]; + brightness_r = brightness_r * 100 / 255; + led_cfg->pwm_duty_cycles->duty_pcts[0] = is_blinking ? 0 : brightness_r; + led_cfg->pwm_duty_cycles->duty_pcts[1] = brightness_r; + pm8xxx_set_led_mode_and_max_brightness(&info->led[PM8XXX_LED_PAT8_RED], + led_cfg->mode, led_cfg->max_current); + __pm8xxx_led_work(&info->led[PM8XXX_LED_PAT8_RED], + led_cfg->max_current); + if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) + pm8xxx_led_pwm_configure(&info->led[PM8XXX_LED_PAT8_RED], + delayoff, delayon); + + if ((brightness_r || brightness_g || brightness_b) && + (info->pdata->led_power_on)) + info->pdata->led_power_on(1); + printk(KERN_DEBUG "[LED] USER : R:%d,G:%d,B:%d\n", + brightness_r, brightness_g, brightness_b); + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT8_RED].cdev, + led_cfg->max_current); + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT8_GREEN].cdev, + led_cfg->max_current); + pm8xxx_led_set(&info->led[PM8XXX_LED_PAT8_BLUE].cdev, + led_cfg->max_current); + + mutex_unlock(&info->led_work_lock); + + return size; + +} + +static DEVICE_ATTR(led_blink, S_IRUGO | S_IWUSR | S_IWGRP, + led_blink_show, led_blink_store); + +static void led_virtual_dev(struct leds_dev_data *info) +{ + struct device *sec_led; + int error = 0; + mutex_init(&info->led_work_lock); + + INIT_WORK(&info->work_pat_batt_chrg, pm8xxx_led_work_pat_batt_chrg); + PREPARE_WORK(&info->work_pat_batt_chrg, pm8xxx_led_work_pat_batt_chrg); + + INIT_WORK(&info->work_pat_chrg_err, pm8xxx_led_work_pat_chrg_err); + PREPARE_WORK(&info->work_pat_chrg_err, pm8xxx_led_work_pat_chrg_err); + + INIT_WORK(&info->work_pat_miss_noti, pm8xxx_led_work_pat_miss_noti); + PREPARE_WORK(&info->work_pat_miss_noti, pm8xxx_led_work_pat_miss_noti); + + INIT_WORK(&info->work_pat_in_lowbat, pm8xxx_led_work_pat_in_lowbat); + PREPARE_WORK(&info->work_pat_in_lowbat, pm8xxx_led_work_pat_in_lowbat); + + INIT_WORK(&info->work_pat_full_chrg, pm8xxx_led_work_pat_full_chrg); + PREPARE_WORK(&info->work_pat_full_chrg, pm8xxx_led_work_pat_full_chrg); + + INIT_WORK(&info->work_pat_powering, pm8xxx_led_work_pat_powering); + PREPARE_WORK(&info->work_pat_powering, pm8xxx_led_work_pat_powering); + + sec_led = device_create(sec_class, NULL, 0, NULL, "led"); + error = dev_set_drvdata(sec_led, info); + if (error) + pr_err("Failed to set sec_led driver data"); + error = device_create_file(sec_led, &dev_attr_led_pattern); + if (error) + pr_err("Failed to create /sys/class/sec/led/led_pattern"); + error = device_create_file(sec_led, &dev_attr_led_lowpower); + if (error) + pr_err("Failed to create /sys/class/sec/led/led_lowpower"); + error = device_create_file(sec_led, &dev_attr_led_r); + if (error) + pr_err("Failed to create /sys/class/sec/led/led_r"); + error = device_create_file(sec_led, &dev_attr_led_g); + if (error) + pr_err("Failed to create /sys/class/sec/led/led_g"); + error = device_create_file(sec_led, &dev_attr_led_b); + if (error) + pr_err("Failed to create /sys/class/sec/led/led_b"); + error = device_create_file(sec_led, &dev_attr_led_blink); + if (error) + pr_err("Failed to create /sys/class/sec/led/led_blink"); + +} +#endif + +static int __devinit pm8xxx_led_probe(struct platform_device *pdev) +{ + const struct led_platform_data *pcore_data; + struct led_info *curr_led; + struct pm8xxx_led_config *led_cfg; + struct pm8xxx_led_data *led, *led_dat; + struct leds_dev_data *info; + struct pm8xxx_led_platform_data *pdata ; + int rc = -1, i = 0; + pdata = pdev->dev.platform_data; + if (pdata == NULL) { + dev_err(&pdev->dev, "platform data not supplied\n"); + return -EINVAL; + } + + pcore_data = pdata->led_core; + + if (pcore_data->num_leds != pdata->num_configs) { + dev_err(&pdev->dev, "#no. of led configs and #no. of led" + "entries are not equal\n"); + return -EINVAL; + } + + led = kcalloc(pcore_data->num_leds, sizeof(*led), GFP_KERNEL); + if (led == NULL) { + dev_err(&pdev->dev, "failed to alloc memory\n"); + return -ENOMEM; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + dev_err(&pdev->dev, "fail to memory allocation.\n"); + rc = -ENOMEM; + goto fail_mem_check; + } + + info->pdata = pdata; + info->led = led; + + for (i = 0; i < pcore_data->num_leds; i++) { + curr_led = &pcore_data->leds[i]; + led_dat = &led[i]; + led_cfg = &pdata->configs[i]; + + led_dat->id = led_cfg->id; + led_dat->pwm_channel = led_cfg->pwm_channel; + led_dat->pwm_period_us = led_cfg->pwm_period_us; + led_dat->pwm_duty_cycles = led_cfg->pwm_duty_cycles; + + if (!((led_dat->id >= PM8XXX_ID_LED_KB_LIGHT) && + (led_dat->id <= PM8XXX_ID_FLASH_LED_1))) { + dev_err(&pdev->dev, "invalid LED ID (%d) specified\n", + led_dat->id); + rc = -EINVAL; + goto fail_id_check; + } + + led_dat->cdev.name = curr_led->name; + led_dat->cdev.default_trigger = curr_led->default_trigger; + led_dat->cdev.brightness_set = pm8xxx_led_set; + led_dat->cdev.brightness_get = pm8xxx_led_get; + led_dat->cdev.brightness = LED_OFF; + led_dat->cdev.flags = curr_led->flags; + led_dat->dev = &pdev->dev; + + rc = get_init_value(led_dat, &led_dat->reg); + if (rc < 0) + goto fail_id_check; + + rc = pm8xxx_set_led_mode_and_max_brightness(led_dat, + led_cfg->mode, led_cfg->max_current); + if (rc < 0) + goto fail_id_check; + + mutex_init(&led_dat->lock); + INIT_WORK(&led_dat->work, pm8xxx_led_work); + if (led_dat->id == PM8XXX_ID_LED_KB_LIGHT) + __pm8xxx_led_work(led_dat, LED_FULL); + else + __pm8xxx_led_work(led_dat, LED_OFF); + } + + platform_set_drvdata(pdev, info); + + led_virtual_dev(info); + + low_powermode = 0; + + return 0; + +fail_id_check: + if (i > 0) { + for (i = i - 1; i >= 0; i--) { + mutex_destroy(&led[i].lock); + led_classdev_unregister(&led[i].cdev); + if (led[i].pwm_dev != NULL) + pwm_free(led[i].pwm_dev); + } + } + kfree(info); +fail_mem_check: + kfree(led); + return rc; +} + +static int __devexit pm8xxx_led_remove(struct platform_device *pdev) +{ + int i; + const struct led_platform_data *pdata = + pdev->dev.platform_data; + struct leds_dev_data *info = platform_get_drvdata(pdev); + + for (i = 0; i < pdata->num_leds; i++) { + cancel_work_sync(&info->led[i].work); + mutex_destroy(&info->led[i].lock); + led_classdev_unregister(&info->led[i].cdev); + if (info->led[i].pwm_dev != NULL) + pwm_free(info->led[i].pwm_dev); + } + + kfree(info->led); + kfree(info); + return 0; +} + +static struct platform_driver pm8xxx_led_driver = { + .probe = pm8xxx_led_probe, + .remove = __devexit_p(pm8xxx_led_remove), + .driver = { + .name = PM8XXX_LEDS_DEV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init pm8xxx_led_init(void) +{ + return platform_driver_register(&pm8xxx_led_driver); +} +subsys_initcall(pm8xxx_led_init); + +static void __exit pm8xxx_led_exit(void) +{ + platform_driver_unregister(&pm8xxx_led_driver); +} +module_exit(pm8xxx_led_exit); + +MODULE_DESCRIPTION("PM8XXX LEDs driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("platform:pm8xxx-led"); + + diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 0d2d91c1c8c..3f9591e1dfc 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1195,7 +1195,7 @@ config MSM_CAMERA_DEBUG help Enable printk() debug for msm camera - +source "drivers/media/video/msm_zsl/Kconfig" source "drivers/media/video/msm/Kconfig" endif # V4L_PLATFORM_DRIVERS diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index fd736c3d44f..552aaa8ee0b 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -211,8 +211,11 @@ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-y += davinci/ - +ifeq ($(CONFIG_S5C73M3),y) +obj-$(CONFIG_MSM_CAMERA) += msm_zsl/ +else obj-$(CONFIG_MSM_CAMERA) += msm/ +endif obj-$(CONFIG_ARCH_OMAP) += omap/ obj-$(CONFIG_MSM_VIDC_V4L2) += msm_vidc/ obj-$(CONFIG_MSM_WFD) += msm_wfd/ diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig index e9b4e2b6d25..9d393c74955 100644 --- a/drivers/media/video/msm/Kconfig +++ b/drivers/media/video/msm/Kconfig @@ -98,6 +98,21 @@ config MT9P012 default y ---help--- MICRON 5M Bayer Sensor with Autofocus +config S5C73M3 + bool "Sensor S5C73M3 (8M)" + default n + ---help--- + LSI 8 MP CMOS Sensor +config S5K6A3YX + bool "Sensor S5K6A3YX (BAYER 2M)" + default n + ---help--- + Samsung 2 MP Bayer Sensor +config S5K8AAY + bool "Sensor S5K8AAY (1.3M)" + default n + ---help--- + LSI 1.3 MP CMOS Sensor choice prompt "AF module" diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile index cd228a1139f..78976499b7e 100644 --- a/drivers/media/video/msm/sensors/Makefile +++ b/drivers/media/video/msm/sensors/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o obj-$(CONFIG_OV7692) += ov7692_v4l2.o obj-$(CONFIG_VX6953) += vx6953.o +obj-$(CONFIG_S5C73M3) += s5c73m3.o s5c73m3_spi.o +obj-$(CONFIG_S5K6A3YX) += s5k6a3yx.o diff --git a/drivers/media/video/msm/sensors/s5c73m3.c b/drivers/media/video/msm/sensors/s5c73m3.c new file mode 100644 index 00000000000..605f35e22bc --- /dev/null +++ b/drivers/media/video/msm/sensors/s5c73m3.c @@ -0,0 +1,3901 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "msm.h" +#include "s5c73m3.h" +#include "msm_ispif.h" +#include +#include + +#define SENSOR_NAME "s5c73m3" +#define PLATFORM_DRIVER_NAME "msm_camera_s5c73m3" + +#define S5C73M3_FW_PATH "/mnt/sdcard/SlimISP.bin" +#define S5C73M3_FW_REQUEST_PATH "/system/cameradata/" +#define S5C73M3_FW_REQUEST_SECOND_PATH "/data/" + +#define MOVIEMODE_FLASH 17 +#define FLASHMODE_FLASH 18 + +#define ERROR 1 + +#define IN_AUTO_MODE 1 +#define IN_MACRO_MODE 2 + +#undef QC_TEST + +/*#define YUV_PREVIEW*/ +#define SPI_DMA_MODE + +static uint32_t op_pixel_clk1; +const int camcorder_30fps = 30; + +struct s5c73m3_work { + struct work_struct work; +}; + +static struct s5c73m3_work *s5c73m3_sensorw; +static struct i2c_client *s5c73m3_client; + +struct s5c73m3_ctrl { + const struct msm_camera_sensor_info *sensordata; + struct v4l2_subdev *sensor_dev; + + int op_mode; + int dtp_mode; + int app_mode; + int vtcall_mode; + int started; + int isCapture; + int flash_mode; + int hdr_mode; + int low_light_mode; + int low_light_mode_size; + int jpeg_size; + int preview_size; + int preview_size_width; + int preview_size_height; + int wide_preview; + int i2c_write_check; + int wb; + int scene; + int fps; + bool isAeLock; + bool isAwbLock; + bool camcorder_mode; + bool vdis_mode; + bool anti_shake_mode; + int record_size_width; + int record_size_height; + int fw_index; + int zoomPreValue; + + u8 sensor_fw[10]; + u8 phone_fw[10]; + u32 crc_table[256]; + u32 sensor_size; +}; + +static unsigned int config_csi2; +static struct s5c73m3_ctrl *s5c73m3_ctrl; + +struct s5c73m3_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; +static int32_t s5c73m3_sensor_setting(int update_type, int rt); +static int s5c73m3_set_touch_auto_focus(); +static int s5c73m3_wait_ISP_status(void); +static int s5c73m3_set_fps(int fps); +static int s5c73m3_set_af_mode(int val); +static int s5c73m3_open_firmware_file(const char *filename, + u8 *buf, u16 offset, u16 size); + + +static DECLARE_WAIT_QUEUE_HEAD(s5c73m3_wait_queue); + + +static char *Fbuf; /*static QCTK*/ +static char FW_buf[409600] = {0}; /*static QCTK 400KB*/ + +#define CHECK_ERR(x) if ((x) < 0) { \ + cam_err("i2c failed, err %d\n", x); \ + return x; \ + } + +static char fw_path[40] = {0}; +static char fw_path_in_data[40] = {0}; +struct s5c73m3_fw_version camfw_info[S5C73M3_PATH_MAX]; + +static int s5c73m3_i2c_write(unsigned short addr, unsigned short data) +{ + unsigned char buf[4]; + int i, err; + int retry_count = 5; + struct i2c_msg msg = {s5c73m3_client->addr, 0, sizeof(buf), buf}; + + if (!s5c73m3_client->adapter) { + cam_err("s5c73m3_client->adapter is not!!\n"); + return -EIO; + } + + buf[0] = addr >> 8; + buf[1] = addr & 0xff; + buf[2] = data >> 8; + buf[3] = data & 0xff; + + cam_i2c_dbg("addr %#x, data %#x\n", addr, data); + + for (i = retry_count; i; i--) { + err = i2c_transfer(s5c73m3_client->adapter, &msg, 1); + if (err == 1) + break; + + msleep(20); + } + + if (err != 1) { + cam_err("fail i2c_transfer!!\n"); + err = -EIO; + return err; + } + + return err; +} + +static void s5c73m3_i2c_write_check(void) +{ + int index = 0; + + do { + if (s5c73m3_ctrl->i2c_write_check == 1) { + cam_err("i2c is writing now!!, index : %d\n", index); + index++; + usleep(1*1000); + } else + break; + + } while (index < 20); + + if (index == 20) { + cam_err("error index : %d\n", index); + s5c73m3_ctrl->i2c_write_check = 0; + } +} + +static int s5c73m3_i2c_write_block(const u32 regs[], int size) +{ + int i, err = 0; + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + for (i = 0; i < size; i++) { + err = s5c73m3_i2c_write((regs[i]>>16), regs[i]); + if (err < 0) { + s5c73m3_ctrl->i2c_write_check = 0; + cam_err("fail s5c73m3_i2c_write!!\n"); + break; + } + } + s5c73m3_ctrl->i2c_write_check = 0; + return err; +} + +static int s5c73m3_i2c_read(unsigned short addr, unsigned short *data) +{ + unsigned char buf[2]; + int i, err; + int retry_count = 5; + struct i2c_msg msg = {s5c73m3_client->addr, 0, sizeof(buf), buf}; + + if (!s5c73m3_client->adapter) { + cam_err("s5c73m3_client->adapter is not!!\n"); + return -ENODEV; + } + + buf[0] = addr >> 8; + buf[1] = addr & 0xff; + + for (i = retry_count; i; i--) { + err = i2c_transfer(s5c73m3_client->adapter, &msg, 1); + if (err == 1) + break; + + msleep(20); + } + + if (err != 1) { + cam_err("fail i2c_transfer!!\n"); + err = -EIO; + return err; + } + + msg.flags = I2C_M_RD; + + for (i = retry_count; i; i--) { + err = i2c_transfer(s5c73m3_client->adapter, &msg, 1); + if (err == 1) + break; + msleep(20); + } + + if (err != 1) { + cam_err("fail i2c_transfer!!\n"); + err = -EIO; + return err; + } + + *data = ((buf[0] << 8) | buf[1]); + + return err; +} + +static int s5c73m3_writeb(unsigned short addr, unsigned short data) +{ + int err; + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + + err = s5c73m3_i2c_write(0x0050, 0x0009); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, 0x5000); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, addr); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, data); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, 0x5080); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, 0x0001); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + + s5c73m3_ctrl->i2c_write_check = 0; + + return err; +} + +static int s5c73m3_write(unsigned short addr1, + unsigned short addr2, unsigned short data) +{ + int err; + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + + err = s5c73m3_i2c_write(0x0050, addr1); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, addr2); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, data); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + + s5c73m3_ctrl->i2c_write_check = 0; + + return err; +} + +static int s5c73m3_read(unsigned short addr1, + unsigned short addr2, unsigned short *data) +{ + int err; + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + + err = s5c73m3_i2c_write(0xfcfc, 0x3310); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0058, addr1); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x005C, addr2); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_read(0x0F14, data); + if (err < 0) + cam_err("fail s5c73m3_i2c_read!!\n"); + + s5c73m3_ctrl->i2c_write_check = 0; + + return err; +} + +static int s5c73m3_set_timing_register_for_vdd(void) +{ + int err = 0; + + err = s5c73m3_write(0x3010, 0x0018, 0x0618); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x001C, 0x10C1); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x0020, 0x249E); + CHECK_ERR(err); + + return err; +} + +static int s5c73m3_i2c_check_status_with_CRC(void) +{ + int err = 0; + int index = 0; + u16 status = 0; + u16 i2c_status = 0; + u16 i2c_seq_status = 0; + + do { + err = s5c73m3_read(0x0009, S5C73M3_STATUS, &status); + err = s5c73m3_read(0x0009, + S5C73M3_I2C_ERR_STATUS, &i2c_status); + if (i2c_status & ERROR_STATUS_CHECK_BIN_CRC) { + CAM_DBG_M("failed to check CRC value of ISP Ram\n"); + err = -1; + break; + } + + if (status == 0xffff) + break; + + index++; + udelay(500); + } while (index < 2000); /* 1 sec */ + + if (index >= 2000) { + err = s5c73m3_read(0x0009, + S5C73M3_I2C_ERR_STATUS, &i2c_status); + err = s5c73m3_read(0x0009, + S5C73M3_I2C_SEQ_STATUS, &i2c_seq_status); + CAM_DBG_M("TimeOut!! index:%d,status:%#x\n", + index, + status); + CAM_DBG_M("i2c_stauts:%#x,i2c_seq_status:%#x\n", + i2c_status, + i2c_seq_status); + + err = -1; + } + + return err; +} + +void s5c73m3_make_CRC_table(u32 *table, u32 id) +{ + u32 i, j, k; + + for (i = 0; i < 256; ++i) { + k = i; + for (j = 0; j < 8; ++j) { + if (k & 1) + k = (k >> 1) ^ id; + else + k >>= 1; + } + table[i] = k; + } +} + +static int s5c73m3_reset_module(bool powerReset) +{ + int err = 0; + + CAM_DBG_M("E\n"); + + if (powerReset) { + s5c73m3_ctrl->sensordata->sensor_platform_info \ + ->sensor_power_off(0); + s5c73m3_ctrl->sensordata->sensor_platform_info \ + ->sensor_power_on(0, 0); + s5c73m3_ctrl->sensordata->sensor_platform_info \ + ->sensor_power_on(0, 1); + } else { + s5c73m3_ctrl->sensordata->sensor_platform_info \ + ->sensor_isp_reset(); + } + + err = s5c73m3_set_timing_register_for_vdd(); + CHECK_ERR(err); + + CAM_DBG_M("X\n"); + + return err; +} + +void s5c73m3_sensor_reset(void) +{ + s5c73m3_ctrl->sensordata->sensor_platform_info->sensor_isp_reset(); +} + +static int s5c73m3_wait_ISP_status(void) +{ + int err = 0; + u16 stream_status = 0; + u16 pre_stream_status = 0; + int index = 0; + + CAM_DBG_H("Entered\n"); + + /*Waiting until ISP will be prepared*/ + do { + err = s5c73m3_read(0x0009, 0x5080, &stream_status); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_H("stream_status1 = 0x%#x\n", stream_status); + + if (stream_status == 0xffff) + break; + + ++index; + CAM_DBG_H("Waiting until to finish handling a command" + "in ISP =====>> %d\n", index); + usleep(500); /* Just for test delay */ + + } while (index < 400); + + if (index == 400) { + cam_err("FAIL : ISP has been not prepared!! : 0x%#x\n", + stream_status); + + err = s5c73m3_read(0x0009, 0x599E, &stream_status); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + cam_err("0009_599E = 0x%#x\n", stream_status); + + err = s5c73m3_read(0x0009, 0x59A6, &stream_status); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + cam_err("0009_59A6 = 0x%#x\n", stream_status); + + return -EIO; + } + + return err; +} + +void s5c73m3_jpeg_update(void) +{ + int count = 0; + int status = 0; + + CAM_DBG_H("Entered\n"); + +} + +static int s5c73m3_sensor_af_status(void) +{ + int ret = 0; + int status = 0; + + CAM_DBG_H("Entered\n"); +} + +static int s5c73m3_sensor_af_result(void) +{ + int ret = 0; + int status = 0; + + CAM_DBG_H("Entered\n"); +} + +static int s5c73m3_set_antibanding(int val) +{ + int err = 0; + int antibanding_mode = 0; + + CAM_DBG_M("E, value %d\n", val); + + switch (val) { + case ANTI_BANDING_OFF: + antibanding_mode = S5C73M3_FLICKER_NONE; + break; + case ANTI_BANDING_50HZ: + antibanding_mode = S5C73M3_FLICKER_AUTO_50HZ; + break; + case ANTI_BANDING_60HZ: + antibanding_mode = S5C73M3_FLICKER_AUTO_60HZ; + break; + case ANTI_BANDING_AUTO: + default: + antibanding_mode = S5C73M3_FLICKER_AUTO; + break; + + } + + err = s5c73m3_writeb(S5C73M3_FLICKER_MODE, antibanding_mode); + CHECK_ERR(err); + + return err; +} + +static int s5c73m3_set_flash(int val) +{ + int err; + CAM_DBG_H("E, value %d\n", val); + +retry: + switch (val) { + case MAIN_CAMERA_FLASH_OFF: + err = s5c73m3_writeb(S5C73M3_FLASH_MODE, + S5C73M3_FLASH_MODE_OFF); + CHECK_ERR(err); + err = s5c73m3_writeb(S5C73M3_FLASH_TORCH, + S5C73M3_FLASH_TORCH_OFF); + CHECK_ERR(err); + break; + + case MAIN_CAMERA_FLASH_AUTO: + err = s5c73m3_writeb(S5C73M3_FLASH_TORCH, + S5C73M3_FLASH_TORCH_OFF); + CHECK_ERR(err); + err = s5c73m3_writeb(S5C73M3_FLASH_MODE, + S5C73M3_FLASH_MODE_AUTO); + CHECK_ERR(err); + break; + + case MAIN_CAMERA_FLASH_ON: + err = s5c73m3_writeb(S5C73M3_FLASH_TORCH, + S5C73M3_FLASH_TORCH_OFF); + CHECK_ERR(err); + err = s5c73m3_writeb(S5C73M3_FLASH_MODE, + S5C73M3_FLASH_MODE_ON); + CHECK_ERR(err); + break; + + case MAIN_CAMERA_FLASH_TORCH: + err = s5c73m3_writeb(S5C73M3_FLASH_MODE, + S5C73M3_FLASH_MODE_OFF); + CHECK_ERR(err); + err = s5c73m3_writeb(S5C73M3_FLASH_TORCH, + S5C73M3_FLASH_TORCH_ON); + CHECK_ERR(err); + break; + + default: + cam_err("invalid value, %d\n", val); + val = CAMERA_FLASH_OFF; + goto retry; + } + flash_mode = val; + + CAM_DBG_H("X\n"); + return 0; +} + +static int s5c73m3_set_preview(void) +{ + CAM_DBG_H("Entered\n"); +} + +static int s5c73m3_set_capture(void) +{ + int32_t rc = 0; + CAM_DBG_H("Entered\n"); + /*frame capture*/ + s5c73m3_ctrl->isCapture = 1; + if (s5c73m3_sensor_setting(UPDATE_PERIODIC, RES_CAPTURE) < 0) { + cam_err("fail s5c73m3_sensor_setting fullsize!!\n"); + return rc; +} + + return rc; +} + +bool s5c73m3_CAF_enabled(void) +{ + bool val = false; + + CAM_DBG_H("Entered\n"); + + if (camera_focus.mode >= + FOCUS_MODE_CONTINOUS && + camera_focus.mode <= + FOCUS_MODE_CONTINOUS_VIDEO) { + val = true; + } + + return val; +} + +static int s5c73m3_s_stream_preview(int enable, int rt) +{ + int err = 0; + u16 stream_status = 0; + u16 pre_stream_status = 0; + int index = 0; + + CAM_DBG_M("Entered, enable %d\n", enable); + + if (enable) { + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } +#if defined(YUV_PREVIEW) + CAM_DBG_M("YUV_PREVIEW\n"); + err = s5c73m3_i2c_write_block(S5C73M3_YUV_PREVIEW, + sizeof(S5C73M3_YUV_PREVIEW)/ + sizeof(S5C73M3_YUV_PREVIEW[0])); + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } +#else + switch (rt) { /*nishu rhint*/ + case RES_PREVIEW: + CAM_DBG_H("Camcorder Interleaved Preview\n"); + if ((s5c73m3_ctrl->record_size_width >= 1920) && + (s5c73m3_ctrl->record_size_height >= 1080)) { + if (s5c73m3_ctrl->vdis_mode == true) { + CAM_DBG_M("FHD VDIS preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_FHD_VDIS, + sizeof(S5C73M3_FHD_VDIS)/ + sizeof(S5C73M3_FHD_VDIS[0])); + } else { + CAM_DBG_M("FHD Normal preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_FHD, + sizeof(S5C73M3_FHD)/ + sizeof(S5C73M3_FHD[0])); + } + } else if ((s5c73m3_ctrl->record_size_width >= 1280) || + (s5c73m3_ctrl->record_size_height >= 720)) { + if (s5c73m3_ctrl->vdis_mode == true) { + CAM_DBG_M("HD VDIS preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_HD_VDIS, + sizeof(S5C73M3_HD_VDIS)/ + sizeof(S5C73M3_HD_VDIS[0])); + } else { + CAM_DBG_M("HD Normal preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_HD, + sizeof(S5C73M3_HD)/ + sizeof(S5C73M3_HD[0])); + } + } else { + if (s5c73m3_ctrl->wide_preview) { + CAM_DBG_M("WVGA preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_WVGA, + sizeof(S5C73M3_WVGA)/ + sizeof(S5C73M3_WVGA[0])); + } else { + CAM_DBG_M("VGA preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_VGA, + sizeof(S5C73M3_VGA)/ + sizeof(S5C73M3_VGA[0])); + } + } + + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MOVIE_CAF_START); + + s5c73m3_set_fps(camcorder_30fps); + /* Set VFE to turbo mode */ + op_pixel_clk1 = 320000000; + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_PCLK_CHANGE, &op_pixel_clk1); + break; + + case RES_CAPTURE: + CAM_DBG_M("Camera Interleaved Preview\n"); + + if (s5c73m3_ctrl->hdr_mode == 1) { + CAM_DBG_H("Start HDR\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_HDR, + sizeof(S5C73M3_HDR)/ + sizeof(S5C73M3_HDR[0]) + ); + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } + + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } else if (s5c73m3_ctrl->low_light_mode_size == 1) { + CAM_DBG_H("Start Low Light Shot\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_LLS, + sizeof(S5C73M3_LLS)/ + sizeof(S5C73M3_LLS[0]) + ); + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } + + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } else { + CAM_DBG_M("preview_size : %x\n", + s5c73m3_ctrl->preview_size); + CAM_DBG_M("jpeg_size : %x\n", + s5c73m3_ctrl->jpeg_size); + err = s5c73m3_i2c_write_block( + S5C73M3_PREVIEW, + sizeof(S5C73M3_PREVIEW)/ + sizeof(S5C73M3_PREVIEW[0])); + + err = s5c73m3_writeb(S5C73M3_CHG_MODE, + S5C73M3_YUV_MODE | + s5c73m3_ctrl->preview_size | + s5c73m3_ctrl->jpeg_size); + } + + err = s5c73m3_writeb(S5C73M3_SENSOR_STREAMING, + S5C73M3_SENSOR_STREAMING_ON); + + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + + /* Set VFE to turbo mode */ + op_pixel_clk1 = 320000000; + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_PCLK_CHANGE, &op_pixel_clk1); + break; + + default: + err = -1; + break; + + }; + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } +#endif + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } + + return err; +} + + +static int s5c73m3_sensor_setting(int update_type, int rt) +{ + int32_t rc = 0; + int index = 0; + u16 stream_status = 0; + u16 temp, temp1, temp2, temp3 = 0; + + struct msm_camera_csid_params s5c73m3_csid_params; + struct msm_camera_csiphy_params s5c73m3_csiphy_params; + + CAM_DBG_M("Entered\n"); + + switch (update_type) { + case REG_INIT: + break; + + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + CAM_DBG_H("UPDATE_PERIODIC\n"); +#if defined(YUV_PREVIEW) + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_OFF_IMMEDIATELY)); +#endif + +#ifdef QC_TEST + do { + rc = s5c73m3_read( + 0x0009, 0x5804, &stream_status); + if (rc < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_M("#####1stream_status : %x\n", + stream_status); + index++; + msleep(30); + } while (index < 10); +#endif + + if (config_csi2 == 0) { + struct msm_camera_csid_vc_cfg + s5c73m3_vccfg[] = { + {0, 0x1E, CSI_DECODE_8BIT}, + {1, CSI_EMBED_DATA, CSI_DECODE_8BIT}, +#if !defined(YUV_PREVIEW) + {2, 0x30, CSI_DECODE_8BIT}, +#endif + }; + s5c73m3_csid_params.lane_cnt = 4; + s5c73m3_csid_params.lane_assign = 0xe4; + s5c73m3_csid_params.lut_params.num_cid = + ARRAY_SIZE(s5c73m3_vccfg); + s5c73m3_csid_params.lut_params.vc_cfg = + &s5c73m3_vccfg[0]; + s5c73m3_csiphy_params.lane_cnt = 4; + s5c73m3_csiphy_params.settle_cnt = 0x27; + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_CSID_CFG, + &s5c73m3_csid_params); + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_CID_CHANGE, NULL); + mb(); + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_CSIPHY_CFG, + &s5c73m3_csiphy_params); + mb(); + /*s5c73m3_delay_msecs_stdby*/ + /*msleep(20);*/ + config_csi2 = 1; + } + + if (rc < 0) { + cam_err("fail!!\n"); + return rc; + } + + rc = s5c73m3_s_stream_preview(1, rt); + if (rc < 0) { + cam_err("failed s5c73m3_s_stream_preview!!\n"); + return -EIO; + } + +#if defined(YUV_PREVIEW) + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_ON_FRAME_BOUNDARY)); +#endif + +#ifdef QC_TEST + do { + rc = s5c73m3_read(0x0009, 0x5804, + &stream_status); + if (rc < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_M("#####2stream_status : %x\n", + stream_status); + index++; + msleep(30); + } while (index < 20); + + rc = s5c73m3_read(0x0009, 0x583C, &stream_status); + if (rc < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_M("#####0x583C : %x\n", + stream_status); + + s5c73m3_read(0x2A00, 0x0060, &temp); + CAM_DBG_M("### 1 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x0064, &temp); + CAM_DBG_M("### 2 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x008C, &temp); + CAM_DBG_M("### 3 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x0090, &temp); + CAM_DBG_M("### 4 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x01CC, &temp); + CAM_DBG_M("### 5 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x002C, &temp1); + s5c73m3_read(0x2A00, 0x0030, &temp2); + s5c73m3_read(0x2A00, 0x0034, &temp3); + temp = (temp1<<16)|(temp2<<8)|temp3; + CAM_DBG_M("### jpeg size : %#x\n", temp); + + s5c73m3_read(0x2A00, 0x0100, &temp); + CAM_DBG_M("### preview buffer : %#x\n", temp); + + s5c73m3_read(0x2A00, 0x0104, &temp); + CAM_DBG_M("### jpeg buffer : %#x\n", temp); + +#endif + if (s5c73m3_CAF_enabled()) + s5c73m3_set_af_mode(camera_focus.mode); + + } + break; + default: + cam_err("fail!!\n"); + rc = -EINVAL; + break; + } + + CAM_DBG_M("sensor setting is done!!\n"); + return rc; +} + +static int s5c73m3_video_config(int mode) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, mode %d\n", mode); + + if (s5c73m3_sensor_setting(UPDATE_PERIODIC, RES_PREVIEW) < 0) { + cam_err("fail s5c73m3_sensor_setting!!\n"); + return rc; + } + + return rc; +} + +static int s5c73m3_set_sensor_mode(int mode) +{ + int err = 0; + CAM_DBG_M("Entered, mode %d\n", mode); + + switch (mode) { + case SENSOR_PREVIEW_MODE: + case SENSOR_VIDEO_MODE: + s5c73m3_ctrl->camcorder_mode = true; + if (s5c73m3_ctrl->isCapture == 1) { + s5c73m3_ctrl->isCapture = 0; + err = s5c73m3_set_preview(); + if (err < 0) { + cam_err("fail s5c73m3_set_preview!!\n"); + return err; + } + } + + err = s5c73m3_video_config(mode); + if (err < 0) { + cam_err("fail s5c73m3_video_config!!\n"); + return err; + } + break; + + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + s5c73m3_ctrl->camcorder_mode = false; + err = s5c73m3_set_capture(); + if (err < 0) { + cam_err("fail s5c73m3_set_capture!!\n"); + return err; + } + break; + + default: + return 0; + } + return 0; +} + +static int s5c73m3_set_effect(int effect) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, effect %d\n", effect); + switch (effect) { + case CAMERA_EFFECT_OFF: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_NONE); + break; + + case CAMERA_EFFECT_MONO: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_MONO); + break; + + case CAMERA_EFFECT_NEGATIVE: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_NEGATIVE); + break; + + case CAMERA_EFFECT_SEPIA: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_SEPIA); + break; + + case CAMERA_EFFECT_WASHED: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_WASHED); + break; + + case CAMERA_EFFECT_VINTAGE_WARM: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_VINTAGE_WARM); + break; + + case CAMERA_EFFECT_VINTAGE_COLD: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_VINTAGE_COLD); + break; + + case CAMERA_EFFECT_SOLARIZE: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_SOLARIZE); + break; + + case CAMERA_EFFECT_POSTERIZE: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POSTERIZE); + break; + + case CAMERA_EFFECT_POINT_COLOR_1: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POINT_COLOR_1); + break; + + case CAMERA_EFFECT_POINT_COLOR_2: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POINT_COLOR_2); + break; + + case CAMERA_EFFECT_POINT_COLOR_3: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POINT_COLOR_3); + break; + + case CAMERA_EFFECT_POINT_COLOR_4: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POINT_COLOR_4); + break; + + default: + CAM_DBG_M("default effect\n"); + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_NONE); + return 0; +} + return rc; +} + +static int s5c73m3_set_whitebalance(int wb) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, %d\n", wb); + + switch (wb) { + case CAMERA_WHITE_BALANCE_AUTO: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_AUTO); + break; + + case CAMERA_WHITE_BALANCE_INCANDESCENT: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_INCANDESCENT); + break; + + case CAMERA_WHITE_BALANCE_FLUORESCENT: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_FLUORESCENT1); + break; + + case CAMERA_WHITE_BALANCE_DAYLIGHT: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_DAYLIGHT); + break; + + case CAMERA_WHITE_BALANCE_CLOUDY_DAYLIGHT: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_CLOUDY); + break; + + default: + CAM_DBG_M("default WB mode\n"); + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_AUTO); + break; + } + s5c73m3_ctrl->wb = wb; + + return rc; +} + +static int s5c73m3_set_ev(int ev) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, ev %d\n", ev); + + switch (ev) { + case CAMERA_EV_M4: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_M20); + break; + + case CAMERA_EV_M3: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_M15); + break; + + case CAMERA_EV_M2: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_M10); + break; + + case CAMERA_EV_M1: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_M05); + break; + + case CAMERA_EV_DEFAULT: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_ZERO); + break; + + case CAMERA_EV_P1: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_P05); + break; + + case CAMERA_EV_P2: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_P10); + break; + + case CAMERA_EV_P3: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_P15); + break; + + case CAMERA_EV_P4: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_P20); + break; + + default: + CAM_DBG_M("default ev mode\n"); + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_ZERO); + break; + } + return rc; +} + +static int s5c73m3_set_scene_mode(int mode) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, mode %d\n", mode); + + switch (mode) { + case CAMERA_SCENE_AUTO: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_NONE); + break; + + case CAMERA_SCENE_LANDSCAPE: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_LANDSCAPE); + break; + + case CAMERA_SCENE_DAWN: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_DAWN); + break; + + case CAMERA_SCENE_BEACH: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_BEACH); + break; + + case CAMERA_SCENE_SUNSET: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_SUNSET); + break; + + case CAMERA_SCENE_NIGHT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_NIGHT); + break; + + case CAMERA_SCENE_PORTRAIT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_PORTRAIT); + break; + + case CAMERA_SCENE_AGAINST_LIGHT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_AGAINSTLIGHT); + break; + + case CAMERA_SCENE_SPORT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_SPORTS); + break; + + case CAMERA_SCENE_FALL: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_FALL); + break; + + case CAMERA_SCENE_TEXT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_TEXT); + break; + + case CAMERA_SCENE_CANDLE: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_CANDLE); + break; + + case CAMERA_SCENE_FIRE: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_FIRE); + break; + + case CAMERA_SCENE_PARTY: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_INDOOR); + break; + + default: + CAM_DBG_M("default scene mode\n"); + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_NONE); + break; + } + s5c73m3_ctrl->scene = mode; + + return rc; +} + +static int s5c73m3_set_iso(int iso) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, iso %d\n", iso); + switch (iso) { + case CAMERA_ISO_MODE_AUTO: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_AUTO); + break; + + case CAMERA_ISO_MODE_100: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_100); + break; + + case CAMERA_ISO_MODE_200: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_200); + break; + + case CAMERA_ISO_MODE_400: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_400); + break; + + case CAMERA_ISO_MODE_800: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_800); + break; + + default: + CAM_DBG_M("default iso mode\n"); + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_AUTO); + break; + } + return rc; +} + +static int s5c73m3_set_metering(int mode) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, mode %d\n", mode); + switch (mode) { + case CAMERA_CENTER_WEIGHT: + rc = s5c73m3_writeb(S5C73M3_METER, + S5C73M3_METER_CENTER); + break; + + case CAMERA_AVERAGE: + rc = s5c73m3_writeb(S5C73M3_METER, + S5C73M3_METER_AVERAGE); + break; + + case CAMERA_SPOT: + rc = s5c73m3_writeb(S5C73M3_METER, + S5C73M3_METER_SPOT); + break; + + default: + CAM_DBG_M("default metering mode\n"); + rc = s5c73m3_writeb(S5C73M3_METER, + S5C73M3_METER_CENTER); + break; + } + return rc; +} + +static int s5c73m3_set_zoom(int level) +{ + int32_t rc = 0; + int err; + int diff = 0; + + CAM_DBG_H("Entered, zoom %d\n", level); + +retry: + if (level < 0 || level > 30) { + cam_err("invalid value, %d\n", level); + level = 0; + s5c73m3_ctrl->zoomPreValue = 0; + goto retry; + } + + if (s5c73m3_ctrl->zoomPreValue > level) + diff = s5c73m3_ctrl->zoomPreValue - level; + else + diff = level - s5c73m3_ctrl->zoomPreValue; + + if (diff > 2) { + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } else + usleep(10*1000); + + s5c73m3_ctrl->zoomPreValue = level; + + err = s5c73m3_i2c_write(0x0050, 0x0009); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, 0x5000); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, S5C73M3_ZOOM_STEP); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, level); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, 0x5080); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, 0x0001); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + + + if (rc < 0) { + cam_err("fail s5c73m3_zoom!!\n"); + return rc; + } + + return rc; +} + +static int s5c73m3_set_jpeg_quality(int quality) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, quality %d\n", quality); + + if (quality <= 80) /* LOW for camcorder */ + rc = s5c73m3_writeb(S5C73M3_IMAGE_QUALITY, + S5C73M3_IMAGE_QUALITY_LOW); + else if (quality <= 90) /* Normal */ + rc = s5c73m3_writeb(S5C73M3_IMAGE_QUALITY, + S5C73M3_IMAGE_QUALITY_NORMAL); + else if (quality <= 95) /* Fine */ + rc = s5c73m3_writeb(S5C73M3_IMAGE_QUALITY, + S5C73M3_IMAGE_QUALITY_FINE); + else /* Superfine */ + rc = s5c73m3_writeb(S5C73M3_IMAGE_QUALITY, + S5C73M3_IMAGE_QUALITY_SUPERFINE); + + if (rc < 0) { + cam_err("fail s5c73m3_quality!!\n"); + return rc; + } + + return rc; +} + +static int s5c73m3_set_face_detection(int val) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, Face detection %d\n", val); + +retry: + switch (val) { + case FACE_DETECTION_ON: + rc = s5c73m3_writeb(S5C73M3_FACE_DET, + S5C73M3_FACE_DET_ON); + break; + + case FACE_DETECTION_OFF: + rc = s5c73m3_writeb(S5C73M3_FACE_DET, + S5C73M3_FACE_DET_OFF); + break; + + default: + cam_err("invalid value, %d\n", val); + val = FACE_DETECTION_OFF; + goto retry; + } + + return rc; +} + +static int s5c73m3_aeawb_lock_unlock(int32_t ae_lock, int32_t awb_lock) +{ + int err = 0; + + CAM_DBG_H("Entered, wb :%d\n", s5c73m3_ctrl->wb); + + if (ae_lock) { + CAM_DBG_M("ae lock"); + err = s5c73m3_writeb(S5C73M3_AE_CON, S5C73M3_AE_STOP); + CHECK_ERR(err); + s5c73m3_ctrl->isAeLock = true; + } else { + CAM_DBG_M("ae unlock"); + err = s5c73m3_writeb(S5C73M3_AE_CON, S5C73M3_AE_START); + CHECK_ERR(err); + s5c73m3_ctrl->isAeLock = false; + } + + if (s5c73m3_ctrl->wb == CAMERA_WHITE_BALANCE_AUTO && + s5c73m3_ctrl->scene != CAMERA_SCENE_SUNSET && + s5c73m3_ctrl->scene != CAMERA_SCENE_DAWN && + s5c73m3_ctrl->scene != CAMERA_SCENE_CANDLE) { + if (awb_lock) { + CAM_DBG_M("awb lock"); + err = s5c73m3_writeb(S5C73M3_AWB_CON, + S5C73M3_AWB_STOP); + CHECK_ERR(err); + s5c73m3_ctrl->isAwbLock = true; + } else { + CAM_DBG_M("awb unlock"); + err = s5c73m3_writeb(S5C73M3_AWB_CON, + S5C73M3_AWB_START); + CHECK_ERR(err); + s5c73m3_ctrl->isAwbLock = false; + } + } + + return 0; +} + +static int s5c73m3_set_focus(int val) +{ + u16 isneed_flash = false; + int err = 0; + + CAM_DBG_M("%s, mode %#x\n", + val ? "start" : "stop", camera_focus.mode); + + camera_focus.status = 0; + + if (val) { + isflash = S5C73M3_ISNEED_FLASH_ON; + + if (!s5c73m3_ctrl->camcorder_mode) + s5c73m3_aeawb_lock_unlock(1, 1); + if (camera_focus.mode == FOCUS_MODE_TOUCH) + err = s5c73m3_set_touch_auto_focus(); + else { + err = s5c73m3_writeb(S5C73M3_AF_CON, + S5C73M3_AF_CON_START); + } + } else { + s5c73m3_aeawb_lock_unlock(0, 0); + err = s5c73m3_writeb(S5C73M3_STILL_MAIN_FLASH + , S5C73M3_STILL_MAIN_FLASH_CANCEL); + err = s5c73m3_writeb(S5C73M3_AF_CON, S5C73M3_AF_CON_STOP); + isflash = S5C73M3_ISNEED_FLASH_UNDEFINED; + } + + CHECK_ERR(err); + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_set_caf_focus(int val) +{ + u16 isneed_flash = false; + int err = 0; + + CAM_DBG_M("%s, mode %#x\n", + val ? "start" : "stop", camera_focus.mode); + + if (val) { + if (camera_focus.mode == FOCUS_MODE_CONTINOUS_VIDEO) { + CAM_DBG_M("Movie CAF\n"); + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MOVIE_CAF_START); + } else { + CAM_DBG_M("Preview CAF\n"); + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_PREVIEW_CAF_START); + } + } else { + err = s5c73m3_writeb(S5C73M3_AF_CON, S5C73M3_AF_CON_STOP); + } + + CHECK_ERR(err); + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_get_pre_flash(int val) +{ + int err = 0; + u16 pre_flash = false; + + err = s5c73m3_read(0x0009, + S5C73M3_STILL_PRE_FLASH | 0x5000, &pre_flash); + isPreflashFired |= pre_flash; + + return err; +} + +static int s5c73m3_get_af_result() +{ + int ret = 0; + u16 af_status = S5C73M3_AF_STATUS_UNFOCUSED; + /*u16 temp_status = 0;*/ + + CAM_DBG_M("Entered\n"); + + ret = s5c73m3_read(0x0009, S5C73M3_AF_STATUS, &af_status); + + switch (af_status) { + case S5C73M3_AF_STATUS_FOCUSING: + case S5C73M3_CAF_STATUS_FOCUSING: + case S5C73M3_CAF_STATUS_FIND_SEARCHING_DIR: + case S5C73M3_CAF_STATUS_INITIALIZE: + case S5C73M3_AF_STATUS_INVALID: + ret = MSM_V4L2_AF_STATUS_IN_PROGRESS; + break; + + case S5C73M3_AF_STATUS_FOCUSED: + case S5C73M3_CAF_STATUS_FOCUSED: + ret = MSM_V4L2_AF_STATUS_SUCCESS; + break; + + case S5C73M3_AF_STATUS_UNFOCUSED: + default: + ret = MSM_V4L2_AF_STATUS_FAIL; + break; + } + camera_focus.status = af_status; + + return ret; +} + +static int s5c73m3_set_af_mode(int val) +{ + int err; + CAM_DBG_M("Entered, new mode %d, old mode %d\n", + val, camera_focus.mode); + +retry: + switch (val) { + case FOCUS_MODE_AUTO: + case FOCUS_MODE_INFINITY: + if (camera_focus.mode >= + FOCUS_MODE_CONTINOUS_PICTURE) { + err = s5c73m3_writeb(S5C73M3_AF_CON, + S5C73M3_AF_CON_STOP); + } + + if (camera_focus.mode != + FOCUS_MODE_CONTINOUS_PICTURE) { + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_NORMAL); + CHECK_ERR(err); + } + camera_focus.mode = val; + camera_focus.caf_mode = S5C73M3_AF_MODE_NORMAL; + break; + + case FOCUS_MODE_MACRO: + if (camera_focus.mode != + FOCUS_MODE_CONTINOUS_PICTURE_MACRO) { + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MACRO); + CHECK_ERR(err); + } + camera_focus.mode = val; + camera_focus.caf_mode = S5C73M3_AF_MODE_MACRO; + break; + + case FOCUS_MODE_CONTINOUS_PICTURE: + if (val != camera_focus.mode && + camera_focus.caf_mode != S5C73M3_AF_MODE_NORMAL) { + camera_focus.mode = val; + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_NORMAL); + CHECK_ERR(err); + camera_focus.caf_mode = S5C73M3_AF_MODE_NORMAL; + } + + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_PREVIEW_CAF_START); + CHECK_ERR(err); + break; + + case FOCUS_MODE_CONTINOUS_PICTURE_MACRO: + if (val != camera_focus.mode && + camera_focus.caf_mode != S5C73M3_AF_MODE_MACRO) { + camera_focus.mode = val; + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MACRO); + CHECK_ERR(err); + camera_focus.caf_mode = S5C73M3_AF_MODE_MACRO; + } + + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_PREVIEW_CAF_START); + CHECK_ERR(err); + break; + + case FOCUS_MODE_CONTINOUS_VIDEO: + camera_focus.mode = val; + + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MOVIE_CAF_START); + CHECK_ERR(err); + break; + + case FOCUS_MODE_FACEDETECT: + camera_focus.mode = val; + break; + + case FOCUS_MODE_TOUCH: + camera_focus.mode = val; + break; + + default: + cam_err("invalid value, %d\n", val); + val = FOCUS_MODE_AUTO; + goto retry; + } + + camera_focus.mode = val; + + CAM_DBG_H("X\n"); + return 0; +} + +static int s5c73m3_set_touch_auto_focus() +{ + int err; + + CAM_DBG_M("s5c73m3_set_touch_auto_focus\n"); + CAM_DBG_H("Touch Position(%d,%d)\n", + camera_focus.pos_x, camera_focus.pos_y); + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + + err = s5c73m3_i2c_write(0xfcfc, 0x3310); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0050, 0x0009); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, S5C73M3_AF_TOUCH_POSITION); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, camera_focus.pos_x); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, camera_focus.pos_y); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, s5c73m3_ctrl->preview_size_width); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, s5c73m3_ctrl->preview_size_height); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0050, 0x0009); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, 0x5000); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, 0x0E0A); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, 0x0000); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, 0x5080); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, 0x0001); + CHECK_ERR(err); + + s5c73m3_ctrl->i2c_write_check = 0; + + return 0; +} + +static int s5c73m3_capture_firework() +{ + int err = 0; + CAM_DBG_H("E\n"); + + err = s5c73m3_writeb(S5C73M3_FIREWORK_CAPTURE, 0x0001); + CHECK_ERR(err); + + return err; +} + +static int s5c73m3_capture_nightshot() +{ + int err = 0; + CAM_DBG_H("E\n"); + + err = s5c73m3_writeb(S5C73M3_NIGHTSHOT_CAPTURE, 0x0001); + CHECK_ERR(err); + + return err; +} + +static int s5c73m3_start_capture(int val) +{ + int err = 0; + u16 isneed_flash = false; + u16 pre_flash = false; + + isPreflashFired = false; + + err = s5c73m3_read(0x0009, + S5C73M3_STILL_PRE_FLASH | 0x5000, &pre_flash); + + if (flash_mode == MAIN_CAMERA_FLASH_ON) { + if (!pre_flash) { + err = s5c73m3_writeb(S5C73M3_STILL_PRE_FLASH + , S5C73M3_STILL_PRE_FLASH_FIRE); + isPreflashFired = true; + msleep(100); + } + err = s5c73m3_writeb(S5C73M3_STILL_MAIN_FLASH + , S5C73M3_STILL_MAIN_FLASH_FIRE); + CAM_DBG_H("full flash!!!\n"); + } else if (flash_mode == MAIN_CAMERA_FLASH_AUTO) { + if (pre_flash) { + err = s5c73m3_writeb(S5C73M3_STILL_MAIN_FLASH + , S5C73M3_STILL_MAIN_FLASH_FIRE); + } else if (isflash != S5C73M3_ISNEED_FLASH_ON) { + err = s5c73m3_read(0x0009, + S5C73M3_AE_ISNEEDFLASH | 0x5000, &isneed_flash); + if (isneed_flash) { + err = s5c73m3_writeb(S5C73M3_STILL_PRE_FLASH + , S5C73M3_STILL_PRE_FLASH_FIRE); + isPreflashFired = true; + msleep(100); + err = s5c73m3_writeb(S5C73M3_STILL_MAIN_FLASH + , S5C73M3_STILL_MAIN_FLASH_FIRE); + CAM_DBG_H("full flash with CAF!!!\n"); + } + } + } + + isflash = S5C73M3_ISNEED_FLASH_UNDEFINED; + + return 0; +} + + +static int s5c73m3_set_wdr(int val) +{ + int err; + CAM_DBG_H("E, value %d\n", val); + +retry: + switch (val) { + case WDR_OFF: + err = s5c73m3_writeb(S5C73M3_WDR, + S5C73M3_WDR_OFF); + CHECK_ERR(err); + break; + + case WDR_ON: + err = s5c73m3_writeb(S5C73M3_WDR, + S5C73M3_WDR_ON); + CHECK_ERR(err); + break; + + default: + cam_err("invalid value, %d\n", val); + val = WDR_OFF; + goto retry; + } + + CAM_DBG_H("X\n"); + return 0; +} + +static int s5c73m3_set_HDR(int val) +{ + int err = 0; + CAM_DBG_H("E, value %d\n", val); + s5c73m3_ctrl->hdr_mode = val; + +#if defined(TEMP_REMOVE) + /* this case for JPEG HDR */ + if (val) { + err = s5c73m3_writeb(S5C73M3_AE_AUTO_BRAKET, + S5C73M3_AE_AUTO_BRAKET_EV20); + CHECK_ERR(err); + } + + /* this case for interealved JPEG HDR(full yuv : 420) */ + if (val) { + err = s5c73m3_i2c_write_block(S5C73M3_HDR, + sizeof(S5C73M3_HDR)/ + sizeof(S5C73M3_HDR[0])); + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } +#endif + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_start_HDR(int val) +{ + int err = 0; + CAM_DBG_H("E, value %d\n", val); + + if (s5c73m3_ctrl->hdr_mode & val) { + CAM_DBG_H("SET AE_BRACKET\n"); + err = s5c73m3_writeb(S5C73M3_AE_AUTO_BRAKET, + S5C73M3_AE_AUTO_BRAKET_EV20); + CHECK_ERR(err); + } + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_set_low_light(int val) +{ + int err = 0; + CAM_DBG_H("E, value %d\n", val); + + s5c73m3_ctrl->low_light_mode = val; + + if (s5c73m3_ctrl->low_light_mode) { + CAM_DBG_H("LLS mode : 0N\n"); + err = s5c73m3_writeb(S5C73M3_LLS_MODE, + S5C73M3_LLS_MODE_ON); + CHECK_ERR(err); + } else { + CAM_DBG_H("LLS mode : OFF\n"); + err = s5c73m3_writeb(S5C73M3_LLS_MODE, + S5C73M3_LLS_MODE_OFF); + CHECK_ERR(err); + } + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_set_antishake(int val) +{ + CAM_DBG_H("Entered, %d\n", val); + + int err = 0; + if (val) { + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_ANTI_SHAKE_ON); + CHECK_ERR(err); + s5c73m3_ctrl->anti_shake_mode = true; + } else { + if (s5c73m3_ctrl->anti_shake_mode) { + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_AUTO_MODE_AE_SET); + CHECK_ERR(err); + s5c73m3_ctrl->anti_shake_mode = false; + } + } + return err; +} + +static int s5c73m3_set_jpeg_size(int width, int height) +{ + int32_t rc = 0; + CAM_DBG_M("Entered, width : %d, height : %d\n", width, height); + + if (width == 3264 && height == 2448) + s5c73m3_ctrl->jpeg_size = 0x00F0; + else if (width == 3264 && height == 1836) + s5c73m3_ctrl->jpeg_size = 0x00E0; + else if (width == 1024 && height == 768) + s5c73m3_ctrl->jpeg_size = 0x00D0; + else if (width == 3264 && height == 2176) + s5c73m3_ctrl->jpeg_size = 0x00C0; + else if (width == 2560 && height == 1920) + s5c73m3_ctrl->jpeg_size = 0x00B0; + else if (width == 2560 && height == 1440) + s5c73m3_ctrl->jpeg_size = 0x00A0; + else if (width == 2048 && height == 1536) + s5c73m3_ctrl->jpeg_size = 0x0090; + else if (width == 2048 && height == 1152) + s5c73m3_ctrl->jpeg_size = 0x0080; + else if (width == 1600 && height == 1200) + s5c73m3_ctrl->jpeg_size = 0x0070; + else if (width == 1600 && height == 900) + s5c73m3_ctrl->jpeg_size = 0x0060; + else if (width == 1280 && height == 960) + s5c73m3_ctrl->jpeg_size = 0x0050; + else if (width == 1280 && height == 720) + s5c73m3_ctrl->jpeg_size = 0x0040; + else if (width == 960 && height == 720) + s5c73m3_ctrl->jpeg_size = 0x0030; + else if (width == 960 && height == 540) + s5c73m3_ctrl->jpeg_size = 0x0020; + else if (width == 640 && height == 480) + s5c73m3_ctrl->jpeg_size = 0x0010; + else + s5c73m3_ctrl->jpeg_size = 0x00F0; + + return rc; +} + +static int s5c73m3_set_record_size(int width, int height) +{ + int32_t rc = 0; + CAM_DBG_M("Entered, width : %d, height : %d\n", width, height); + s5c73m3_ctrl->record_size_width = width; + s5c73m3_ctrl->record_size_height = height; + + return rc; +} + +static int s5c73m3_set_face_beauty(int val) +{ + CAM_DBG_H("Entered, %d\n", val); + return 0; +} + +static int s5c73m3_set_fps(int fps) +{ + int err; + + CAM_DBG_M("Entered, %s mode fps %d\n", + s5c73m3_ctrl->camcorder_mode ? "camcorder" : "camera", + fps); + + /* It can't support camera mode */ + if (s5c73m3_ctrl->camcorder_mode == 0) { + CAM_DBG_M("set default fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_AUTO_MODE_AE_SET); + CHECK_ERR(err); + } else { + switch (fps) { + case 30: + CAM_DBG_M("set 30fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_FIXED_30FPS); + CHECK_ERR(err); + break; + + case 20: + CAM_DBG_M("set 20fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_FIXED_20FPS); + CHECK_ERR(err); + break; + + case 15: + CAM_DBG_M("set 15fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_FIXED_15FPS); + CHECK_ERR(err); + break; + + case 7: + CAM_DBG_M("set 7fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_FIXED_7FPS); + CHECK_ERR(err); + break; + + default: + cam_err("invalid value, %d\n", fps); + } + } + + s5c73m3_ctrl->fps = fps; + + return 0; +} + +static int s5c73m3_set_face_zoom(int val) +{ + int err; + + CAM_DBG_M("s5c73m3_set_face_zoom, %d\n", val); + CAM_DBG_H("Touch Position(%d,%d)\n", + camera_focus.pos_x, camera_focus.pos_y); + CAM_DBG_H("Preview Size(%d,%d)\n", + s5c73m3_ctrl->preview_size_width, + s5c73m3_ctrl->preview_size_height); + + err = s5c73m3_writeb(S5C73M3_AF_CON, + S5C73M3_AF_CON_STOP); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0xfcfc, 0x3310); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0050, 0x0009); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, S5C73M3_AF_TOUCH_POSITION); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, camera_focus.pos_x); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, camera_focus.pos_y); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, s5c73m3_ctrl->preview_size_width); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, s5c73m3_ctrl->preview_size_height); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0050, 0x0009); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, 0x5000); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, S5C73M3_AF_FACE_ZOOM); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, val); /*0:reset, 1:Start*/ + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, 0x5080); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, 0x0001); + CHECK_ERR(err); + + udelay(400); + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_PREVIEW_CAF_START); + CHECK_ERR(err); + + return 0; +} + +static int s5c73m3_set_vdis(int onoff) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, VDIS onoff %d\n", onoff); + + switch (onoff) { + case 0: + s5c73m3_ctrl->vdis_mode = false; + break; + + case 1: + s5c73m3_ctrl->vdis_mode = true; + break; + + default: + CAM_DBG_M("unexpected ev mode\n"); + break; + } + return rc; +} + +static int s5c73m3_get_lux(void) +{ + int err = 0; + int lux_val = 0; + + err = s5c73m3_read(0x0009, 0x5C88, &lux_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + + return lux_val; +} + +static int s5c73m3_set_preview_size(int32_t width, int32_t height) +{ + CAM_DBG_H("Entered, width %d, height %d\n", + width, height); + + s5c73m3_ctrl->preview_size_width = width; + s5c73m3_ctrl->preview_size_height = height; + + if ((width == 1008 && height == 672) || + (width == 720 && height == 480)) + s5c73m3_ctrl->preview_size = 0x000F; + else if (width == 352 && height == 288) + s5c73m3_ctrl->preview_size = 0x000E; + else if (width == 3264 && height == 2448) + s5c73m3_ctrl->preview_size = 0x000D; + else if (width == 2304 && height == 1296) + s5c73m3_ctrl->preview_size = 0x000C; + else if (width == 720 && height == 480) + s5c73m3_ctrl->preview_size = 0x000B; + else if (width == 1920 && height == 1080) + s5c73m3_ctrl->preview_size = 0x000A; + else if (width == 800 && height == 600) + s5c73m3_ctrl->preview_size = 0x0009; + else if (width == 1600 && height == 1200) + s5c73m3_ctrl->preview_size = 0x0008; + else if (width == 1536 && height == 864) + s5c73m3_ctrl->preview_size = 0x0007; + else if (width == 1280 && height == 720) + s5c73m3_ctrl->preview_size = 0x0006; + else if (width == 1184 && height == 666) + s5c73m3_ctrl->preview_size = 0x0005; + else if (width == 960 && height == 720) + s5c73m3_ctrl->preview_size = 0x0004; + else if (width == 880 && height == 720) + s5c73m3_ctrl->preview_size = 0x0003; + else if (width == 640 && height == 480) + s5c73m3_ctrl->preview_size = 0x0002; + else if (width == 320 && height == 240) + s5c73m3_ctrl->preview_size = 0x0001; + else + s5c73m3_ctrl->preview_size = 0x0004; + + if ((width == 1920 && height == 1080) || + (width == 1280 && height == 720) || + (width == 720 && height == 480)) + s5c73m3_ctrl->wide_preview = 1; + else + s5c73m3_ctrl->wide_preview = 0; + + return 0; +} + +static int s5c73m3_load_fw(void) +{ +#if defined(SPI_DMA_MODE) + #define FW_WRITE_SIZE 65536 +#endif + + struct device *dev = s5c73m3_ctrl->sensor_dev->v4l2_dev->dev; + int err, txSize; + + struct file *fp = NULL; + mm_segment_t old_fs; + long fsize, nread; + + CAM_DBG_M("Entered\n"); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if (s5c73m3_ctrl->fw_index == S5C73M3_SD_CARD || + s5c73m3_ctrl->fw_index == S5C73M3_IN_DATA) { + + if (s5c73m3_ctrl->fw_index == S5C73M3_SD_CARD) + fp = filp_open(S5C73M3_FW_PATH, O_RDONLY, 0); + else + fp = filp_open(fw_path_in_data, O_RDONLY, 0); + if (IS_ERR(fp)) { + cam_err("failed to filp_open\n"); + goto out; + } + } else { + fp = filp_open(fw_path, O_RDONLY, 0); + if (IS_ERR(fp)) { + cam_err("failed to filp_open\n"); + goto out; + } + } + + fsize = fp->f_path.dentry->d_inode->i_size; + + CAM_DBG_M("index %d is opened\n", + s5c73m3_ctrl->fw_index); + CAM_DBG_M("fsize is %d\n", fsize); + + Fbuf = (char *)roundup((unsigned int)FW_buf, 64); /*ALRAN 64*/ + nread = vfs_read(fp, (char __user *)Fbuf, + fsize, &fp->f_pos); + if (nread != fsize) { + cam_err("failed to read firmware file, %ld Bytes\n", nread); + err = -EIO; + goto out; + } + set_fs(old_fs); + +#if defined(SPI_DMA_MODE) + txSize = FW_WRITE_SIZE; /*QCTK*/ +#else + txSize = 8; +#endif + err = s5c73m3_spi_write(Fbuf, fsize, txSize); + + if (err < 0) { + cam_err("s5c73m3_spi_write falied\n"); + goto out; + } + + CAM_DBG_M("Exit\n"); + +out: + filp_close(fp, current->files); + set_fs(old_fs); + + return err; +} + +static int s5c73m3_SPI_booting(void) +{ + u16 read_val; + int i, err; + u32 test_start_pointer = 0, test_end_pointer = 0; + + CAM_DBG_M("Entered\n"); + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + udelay(400); + + /*Check boot done*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + if (read_val == 0x0C) + break; + + udelay(100); + } + + if (read_val != 0x0C) { + cam_err("boot fail, read_val %#x\n", read_val); + return -EIO; + } + + /*P,M,S and Boot Mode*/ + err = s5c73m3_write(0x3010, 0x0014, 0x2146); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + err = s5c73m3_write(0x3010, 0x0010, 0x210C); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + udelay(200); + + /*Check SPI ready*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + + if (read_val == 0x210D) + break; + + udelay(100); + } + + if (read_val != 0x210D) { + cam_err("SPI not ready, read_val %#x\n", read_val); + return -EIO; + } + + /*download fw by SPI*/ + err = s5c73m3_load_fw(); + if (err < 0) { + cam_err("failed s5c73m3_load_fw!!\n"); + return -EIO; + } + + /*ARM reset*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFD); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + /*remap*/ + err = s5c73m3_write(0x3010, 0x00A4, 0x0183); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + +#if defined(DEBUG_LEVEL_HIGH) + /* check FW version name */ + CAM_DBG_H("FW version is : "); + for (i = 0; i < 19; i++) { + err = s5c73m3_read(0x0000, 0x0060+i, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_H("%c%c", read_val&0xff, + (read_val>>8)&0xff); + i++; + } +#endif + + /*ARM go again*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + return 0; +} + +static int s5c73m3_dump_fw(void) +{ + return 0; +} + +static int s5c73m3_get_sensor_fw_binary() +{ + u16 read_val; + int i, rxSize; + int err = 0; + struct file *fp = NULL; + mm_segment_t old_fs; + long ret = 0; + char l_fw_path[40] = {0}; + u8 mem0 = 0, mem1 = 0; + u32 CRC = 0; + u32 DataCRC = 0; + u32 IntOriginalCRC = 0; + u32 crc_index = 0; + int retryCnt = 2; + + CAM_DBG_M("Entered\n"); + + if (s5c73m3_ctrl->sensor_fw[0] == 'O') { + sprintf(l_fw_path, "%sSlimISP_G%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[1]); + } else if (s5c73m3_ctrl->sensor_fw[0] == 'S') { + sprintf(l_fw_path, "%sSlimISP_Z%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[1]); + } else { + sprintf(l_fw_path, "%sSlimISP_%c%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[0], + s5c73m3_ctrl->sensor_fw[1]); + } + + /* Make CRC Table */ + s5c73m3_make_CRC_table((u32 *)&s5c73m3_ctrl->crc_table, 0xEDB88320); + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + CHECK_ERR(err); + + udelay(400); + + /*Check boot done*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + CHECK_ERR(err); + + if (read_val == 0x0C) + break; + + udelay(100); + } + + if (read_val != 0x0C) { + cam_err("boot fail, read_val %#x\n", read_val); + return -EINVAL; + } + + /* Change I/O Driver Current in order to read from F-ROM */ + err = s5c73m3_write(0x3010, 0x0120, 0x0820); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x0124, 0x0820); + CHECK_ERR(err); + + /*P,M,S and Boot Mode*/ + err = s5c73m3_write(0x3010, 0x0014, 0x2146); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x0010, 0x230C); + CHECK_ERR(err); + + udelay(200); + + /*Check SPI ready*/ + for (i = 0; i < 300; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + CHECK_ERR(err); + + if (read_val == 0x230E) + break; + + udelay(100); + } + + if (read_val != 0x230E) { + cam_err("SPI not ready, read_val %#x\n", read_val); + return -EINVAL; + } + + /*ARM reset*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFD); + CHECK_ERR(err); + + /*remap*/ + err = s5c73m3_write(0x3010, 0x00A4, 0x0183); + CHECK_ERR(err); + + /*ARM go again*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + CHECK_ERR(err); + + mdelay(200); + +retry: + mem0 = 0, mem1 = 0; + CRC = 0; + DataCRC = 0; + IntOriginalCRC = 0; + crc_index = 0; + + /* SPI Copy mode ready I2C CMD */ + err = s5c73m3_writeb(0x0924, 0x0000); + CHECK_ERR(err); + CAM_DBG_M("sent SPI ready CMD\n"); + + rxSize = 64*1024; + mdelay(10); + s5c73m3_wait_ISP_status(); + + Fbuf = (char *)roundup((unsigned int)FW_buf, 64); /*ALRAN 64*/ + err = s5c73m3_spi_read(Fbuf, + s5c73m3_ctrl->sensor_size, rxSize); + CHECK_ERR(err); + + CRC = ~CRC; + for (crc_index = 0; crc_index < (s5c73m3_ctrl->sensor_size-4)/2 + ; crc_index++) { + /*low byte*/ + mem0 = (unsigned char)(Fbuf[crc_index*2] & 0x00ff); + /*high byte*/ + mem1 = (unsigned char)(Fbuf[crc_index*2+1] & 0x00ff); + CRC = s5c73m3_ctrl->crc_table[(CRC ^ (mem0)) & 0xFF] \ + ^ (CRC >> 8); + CRC = s5c73m3_ctrl->crc_table[(CRC ^ (mem1)) & 0xFF] \ + ^ (CRC >> 8); + } + CRC = ~CRC; + + DataCRC = (CRC&0x000000ff)<<24; + DataCRC += (CRC&0x0000ff00)<<8; + DataCRC += (CRC&0x00ff0000)>>8; + DataCRC += (CRC&0xff000000)>>24; + CAM_DBG_M("made CSC value by S/W = 0x%x\n", DataCRC); + + IntOriginalCRC = (Fbuf[s5c73m3_ctrl->sensor_size-4]&0x00ff)<<24; + IntOriginalCRC += (Fbuf[s5c73m3_ctrl->sensor_size-3]&0x00ff)<<16; + IntOriginalCRC += (Fbuf[s5c73m3_ctrl->sensor_size-2]&0x00ff)<<8; + IntOriginalCRC += (Fbuf[s5c73m3_ctrl->sensor_size-1]&0x00ff); + CAM_DBG_M("Original CRC Int = 0x%x\n", IntOriginalCRC); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if (IntOriginalCRC == DataCRC) { + fp = filp_open(l_fw_path, O_WRONLY|O_CREAT, 0644); + if (IS_ERR(fp) || fp == NULL) { + cam_err("failed to open %s, err %ld\n", + l_fw_path, PTR_ERR(fp)); + err = -EINVAL; + goto out; + } + + ret = vfs_write(fp, (char __user *)Fbuf, + s5c73m3_ctrl->sensor_size, &fp->f_pos); + + memcpy(s5c73m3_ctrl->phone_fw, + s5c73m3_ctrl->sensor_fw, + S5C73M3_FW_VER_LEN); + s5c73m3_ctrl->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; + + CAM_DBG_M("Changed to Phone_version = %s\n", + s5c73m3_ctrl->phone_fw); + } else { + if (retryCnt > 0) { + set_fs(old_fs); + retryCnt--; + goto retry; + } + } + + if (fp != NULL) + filp_close(fp, current->files); + +out: + set_fs(old_fs); + + CAM_DBG_M("Exit\n"); + + return err; +} + +static int s5c73m3_get_sensor_fw_version(void) +{ + u16 read_val; + int i, err; + u32 test_start_pointer = 0, test_end_pointer = 0; + u16 temp_buf; + + CAM_DBG_H("Entered\n"); + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + udelay(400); + + /*Check boot done*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + if (read_val == 0x0C) + break; + + udelay(100); + } + + if (read_val != 0x0C) { + cam_err("boot fail, read_val %#x\n", read_val); + return -EIO; + } + + /* Change I/O Driver Current in order to read from F-ROM */ + err = s5c73m3_write(0x3010, 0x0120, 0x0820); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + err = s5c73m3_write(0x3010, 0x0124, 0x0820); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + /* Offset Setting */ + err = s5c73m3_write(0x0001, 0x0418, 0x0008); + CHECK_ERR(err); + + /*P,M,S and Boot Mode*/ + err = s5c73m3_write(0x3010, 0x0014, 0x2146); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + err = s5c73m3_write(0x3010, 0x0010, 0x230C); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + udelay(200); + + /*Check SPI ready*/ + for (i = 0; i < 300; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + + if (read_val == 0x230E) + break; + + udelay(100); + } + + if (read_val != 0x230E) { + cam_err("SPI not ready, read_val %#x\n", read_val); + return -EIO; + } + + /*ARM reset*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFD); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + /*remap*/ + err = s5c73m3_write(0x3010, 0x00A4, 0x0183); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + +#if defined(TEMP_REMOVE) + /*ARM go again*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + /* check FW version name */ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x0000, 0x0060+i*2, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + s5c73m3_ctrl->sensor_fw[i*2] = read_val&0x00ff; + s5c73m3_ctrl->sensor_fw[i*2+1] = (read_val&0xff00)>>8; + } + s5c73m3_ctrl->sensor_fw[i*2+2] = ' '; +#else + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x0000, i*2, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + s5c73m3_ctrl->sensor_fw[i*2] = read_val&0x00ff; + s5c73m3_ctrl->sensor_fw[i*2+1] = (read_val&0xff00)>>8; + } + s5c73m3_ctrl->sensor_fw[i*2+2] = ' '; +#endif + + s5c73m3_ctrl->sensor_size = 0; + for (i = 0; i < 2; i++) { + err = s5c73m3_read(0x0000, 0x0014+i*2, &temp_buf); + s5c73m3_ctrl->sensor_size += temp_buf<<(i*16); + CHECK_ERR(err); + } + + if ((s5c73m3_ctrl->sensor_fw[0] >= 'A') + && s5c73m3_ctrl->sensor_fw[0] <= 'Z') { + cam_err("sensor_fw = %s\n", + s5c73m3_ctrl->sensor_fw); + return 0; + } else { + cam_err("Sensor is not connected!!\n"); + return -EIO; + } +} + +static int s5c73m3_open_firmware_file(const char *filename, + u8 *buf, u16 offset, u16 size) { + struct file *fp; + int err = 0; + mm_segment_t old_fs; + long nread; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(fp)) { + err = -ENOENT; + goto out; + } else { + CAM_DBG_H("%s is opened\n", filename); + } + + err = vfs_llseek(fp, offset, SEEK_SET); + if (err < 0) { + cam_err("failed to fseek, %d\n", err); + goto out; + } + + nread = vfs_read(fp, (char __user *)buf, size, &fp->f_pos); + + if (nread != size) { + cam_err("failed to read firmware file, %ld Bytes\n", nread); + err = -EIO; + goto out; + } +out: + if (!IS_ERR(fp)) + filp_close(fp, current->files); + + set_fs(old_fs); + + return err; +} + +static int s5c73m3_compare_date(char *camfw_info_ver1, + char *camfw_info_ver2) +{ + u8 date1[5] = {0,}; + u8 date2[5] = {0,}; + + strncpy((char *)&date1, camfw_info_ver1, 4); + strncpy((char *)&date2, camfw_info_ver2, 4); + CAM_DBG_M("date1 = %s, date2 = %s\n, compare result = %d", + date1, + date2, + strcmp((char *)&date1, (char *)&date2)); + + return strcmp((char *)&date1, (char *)&date2); +} + +static int s5c73m3_get_phone_fw_version(void) +{ +#if defined(SPI_DMA_MODE) +#define FW_WRITE_SIZE 65536 +#endif + + struct device *dev = s5c73m3_ctrl->sensor_dev->v4l2_dev->dev; + static char *buf; /*static*/ + int err = 0; + int retVal = 0; + int fw_requested = 1; + + CAM_DBG_M("Entered\n"); + + buf = vmalloc(S5C73M3_FW_VER_LEN+1); + if (!buf) { + cam_err("failed to allocate memory\n"); + err = -ENOMEM; + goto out; + } + + if (s5c73m3_ctrl->sensor_fw[0] == 'O') { + sprintf(fw_path, "%sSlimISP_G%c.bin", + S5C73M3_FW_REQUEST_PATH, + s5c73m3_ctrl->sensor_fw[1]); + sprintf(fw_path_in_data, "%sSlimISP_G%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[1]); + } else if (s5c73m3_ctrl->sensor_fw[0] == 'S') { + sprintf(fw_path, "%sSlimISP_Z%c.bin", + S5C73M3_FW_REQUEST_PATH, + s5c73m3_ctrl->sensor_fw[1]); + sprintf(fw_path_in_data, "%sSlimISP_G%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[1]); + } else { + sprintf(fw_path, "%sSlimISP_%c%c.bin", + S5C73M3_FW_REQUEST_PATH, + s5c73m3_ctrl->sensor_fw[0], + s5c73m3_ctrl->sensor_fw[1]); + sprintf(fw_path_in_data, "%sSlimISP_%c%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[0], + s5c73m3_ctrl->sensor_fw[1]); + } + + retVal = s5c73m3_open_firmware_file(S5C73M3_FW_PATH, + buf, + S5C73M3_FW_VER_FILE_CUR, + S5C73M3_FW_VER_LEN); + if (retVal >= 0) { + camfw_info[S5C73M3_SD_CARD].opened = 1; + memcpy(camfw_info[S5C73M3_SD_CARD].ver, + buf, + S5C73M3_FW_VER_LEN); + camfw_info[S5C73M3_SD_CARD] + .ver[S5C73M3_FW_VER_LEN+1] = '\0'; + s5c73m3_ctrl->fw_index = S5C73M3_SD_CARD; + fw_requested = 0; + } + +request_fw: + if (fw_requested) { + /* check fw in data folder */ + retVal = s5c73m3_open_firmware_file(fw_path_in_data, + buf, + S5C73M3_FW_VER_FILE_CUR, + S5C73M3_FW_VER_LEN); + if (retVal >= 0) { + camfw_info[S5C73M3_IN_DATA].opened = 1; + memcpy(camfw_info[S5C73M3_IN_DATA].ver, + buf, + S5C73M3_FW_VER_LEN); + camfw_info[S5C73M3_IN_DATA] + .ver[S5C73M3_FW_VER_LEN+1] = '\0'; + } + + /* check fw in system folder */ + retVal = s5c73m3_open_firmware_file(fw_path, + buf, + S5C73M3_FW_VER_FILE_CUR, + S5C73M3_FW_VER_LEN); + if (retVal >= 0) { + camfw_info[S5C73M3_IN_SYSTEM].opened = 1; + memcpy(camfw_info[S5C73M3_IN_SYSTEM].ver, + buf, + S5C73M3_FW_VER_LEN); + camfw_info[S5C73M3_IN_SYSTEM] + .ver[S5C73M3_FW_VER_LEN+1] = '\0'; + } + + /* compare */ + if (camfw_info[S5C73M3_IN_DATA].opened == 0 && + camfw_info[S5C73M3_IN_SYSTEM].opened == 1) { + s5c73m3_ctrl->fw_index = S5C73M3_IN_SYSTEM; + } else if (camfw_info[S5C73M3_IN_DATA].opened == 1 && + camfw_info[S5C73M3_IN_SYSTEM].opened == 0) { + s5c73m3_ctrl->fw_index = S5C73M3_IN_DATA; + } else if (camfw_info[S5C73M3_IN_DATA].opened == 1 && + camfw_info[S5C73M3_IN_SYSTEM].opened == 1) { + int i = 1; + retVal = s5c73m3_compare_date( + (char *)(&camfw_info[S5C73M3_IN_DATA].ver[2]), + (char *)(&camfw_info[S5C73M3_IN_SYSTEM].ver[2])); + + while (1) { + if (camfw_info[S5C73M3_IN_DATA].ver[i] != + camfw_info[S5C73M3_IN_SYSTEM].ver[i]) { + cam_err("FW is diff!\n"); + retVal = 1; + break; + } + if (--i < 0) { + CAM_DBG_M("FW is same!!\n"); + break; + } + } + if (retVal <= 0) { + /*unlink(&fw_path_in_data);*/ + s5c73m3_ctrl->fw_index = S5C73M3_IN_SYSTEM; + } else { + s5c73m3_ctrl->fw_index = S5C73M3_IN_DATA; + } + } else { + CAM_DBG_M("can't open %s. download from F-ROM\n", + s5c73m3_ctrl->sensor_fw); + + s5c73m3_reset_module(true); + + retVal = s5c73m3_get_sensor_fw_binary(); + CHECK_ERR(retVal); + goto request_fw; + } + } + + memcpy(s5c73m3_ctrl->phone_fw, + camfw_info[s5c73m3_ctrl->fw_index].ver, + S5C73M3_FW_VER_LEN); + s5c73m3_ctrl->phone_fw[S5C73M3_FW_VER_LEN+1] = '\0'; + CAM_DBG_M("Phone_version = %s(index=%d)\n", + s5c73m3_ctrl->phone_fw, s5c73m3_ctrl->fw_index); + +out: + if (buf != NULL) + vfree(buf); + + CAM_DBG_M("Exit\n"); + return err; +} + +static int s5c73m3_update_camerafw_to_FROM(void) +{ + int err; + int index = 0; + u16 status = 0; + + do { + /* stauts 0 : not ready ISP */ + if (status == 0) { + err = s5c73m3_writeb(0x0906, 0x0000); + CHECK_ERR(err); + } + + err = s5c73m3_read(0x0009, 0x5906, &status); + /* Success : 0x05, Fail : 0x07 , Progressing : 0xFFFF*/ + if (status == 0x0005 || + status == 0x0007) + break; + + index++; + msleep(20); + } while (index < 500); /* 10 sec */ + + + if (status == 0x0007) + return -EIO; + else + return 0; +} + +static int s5c73m3_SPI_booting_by_ISP(void) +{ + u16 read_val; + u16 sensor_fw; + u16 sensor_type; + u16 temp_buf; + int i; + int err = 0; + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + CHECK_ERR(err); + + udelay(400); + + /*Check boot done*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + CHECK_ERR(err); + + if (read_val == 0x0C) + break; + + udelay(100); + } + + if (read_val != 0x0C) { + cam_err("boot fail, read_val %#x\n", read_val); + return -1; + } + + /*P,M,S and Boot Mode*/ + err = s5c73m3_write(0x3010, 0x0014, 0x2146); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x0010, 0x230C); + CHECK_ERR(err); + + udelay(200); + + /*Check SPI ready*/ + for (i = 0; i < 300; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + CHECK_ERR(err); + + if (read_val == 0x230E) + break; + + udelay(100); + } + + if (read_val != 0x230E) { + cam_err("SPI not ready, read_val %#x\n", read_val); + return -1; + } + + /*ARM reset*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFD); + CHECK_ERR(err); + + /*remap*/ + err = s5c73m3_write(0x3010, 0x00A4, 0x0183); + CHECK_ERR(err); + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + CHECK_ERR(err); + + return err; +} + +static int s5c73m3_check_fw_date(void) +{ + u8 sensor_date[5] = {0,}; + u8 phone_date[5] = {0,}; + + int i = 1; + while (1) { + if (s5c73m3_ctrl->sensor_fw[i] != + s5c73m3_ctrl->phone_fw[i]) { + cam_err("Sensor is diff!\n"); + cam_err("Sensor_date = %s, " + "Phone_date = %s\n", + s5c73m3_ctrl->sensor_fw, + s5c73m3_ctrl->phone_fw); + return 1; + } + if (--i < 0) { + CAM_DBG_M("FW is same!!\n"); + break; + } + } + + strncpy((char *)&sensor_date, + &s5c73m3_ctrl->sensor_fw[2], 4); + strncpy((char *)&phone_date, + (const char *)&s5c73m3_ctrl->phone_fw[2], 4); + CAM_DBG_M("Sensor_date = %s, Phone_date = %s\n, " + "compare result = %d", + sensor_date, + phone_date, + strcmp((char *)&sensor_date, (char *)&phone_date)); + + return strcmp((char *)&sensor_date, (char *)&phone_date); +} + +static int s5c73m3_check_fw(const struct msm_camera_sensor_info *data, + bool download) +{ + int err = 0; + int retVal; + int i = 0; + + CAM_DBG_M("Enter\n"); + + if (!download) { + for (i = 0; i < S5C73M3_PATH_MAX; i++) + camfw_info[i].opened = 0; + + err = s5c73m3_get_sensor_fw_version(); + if (err < 0) { + cam_err("failed s5c73m3_get_sensor_fw_version!!\n"); + return -EIO; + } + err = s5c73m3_get_phone_fw_version(); + if (err < 0) { + cam_err("failed s5c73m3_get_phone_fw_version!!\n"); + return -EIO; + } + } + + data->sensor_platform_info->sensor_get_fw(&s5c73m3_ctrl->sensor_fw, + &s5c73m3_ctrl->phone_fw); + + retVal = s5c73m3_check_fw_date(); + + /* retVal = 0 : Same Version + retVal < 0 : Phone Version is latest Version than sensorFW. + retVal > 0 : Sensor Version is latest version than phoenFW. */ + if (retVal <= 0 || download || s5c73m3_ctrl->fw_index == 0) { + if (s5c73m3_ctrl->fw_index == 0) + CAM_DBG_M("Loading From PhoneFW forced......\n"); + else + CAM_DBG_M("Loading From PhoneFW......\n"); + + if ((s5c73m3_ctrl->phone_fw[0] >= 'A') + && s5c73m3_ctrl->phone_fw[0] <= 'Z') { + s5c73m3_reset_module(false); + err = s5c73m3_SPI_booting(); + if (err < 0) { + cam_err("failed s5c73m3_SPI_booting!!\n"); + return -EIO; + } + if (download) { + err = s5c73m3_update_camerafw_to_FROM(); + if (err < 0) { + cam_err("failed s5c73m3_update_camerafw_to_FROM!!\n"); + return -EIO; + } + } + } else { + cam_err("phone FW is wrong!!\n"); + return -EIO; + } + } else { + CAM_DBG_M("Loading From SensorFW......\n"); + s5c73m3_reset_module(true); + err = s5c73m3_get_sensor_fw_binary(); + if (err < 0) { + cam_err("failed s5c73m3_get_sensor_fw_binary!!\n"); + return -EIO; + } + /* check fw in data folder */ + { + static char *buf; /*static*/ + buf = vmalloc(S5C73M3_FW_VER_LEN+1); + if (buf == NULL) { + cam_err("Mem allocation failed\n"); + return -EIO; + } + retVal = s5c73m3_open_firmware_file(fw_path_in_data, + buf, + S5C73M3_FW_VER_FILE_CUR, + S5C73M3_FW_VER_LEN); + if (retVal >= 0) { + camfw_info[S5C73M3_IN_DATA].opened = 1; + memcpy(camfw_info[S5C73M3_IN_DATA].ver, + buf, + S5C73M3_FW_VER_LEN); + camfw_info[S5C73M3_IN_DATA] + .ver[S5C73M3_FW_VER_LEN+1] = '\0'; + s5c73m3_ctrl->fw_index = S5C73M3_IN_DATA; + memcpy(s5c73m3_ctrl->phone_fw, + camfw_info[s5c73m3_ctrl->fw_index].ver, + S5C73M3_FW_VER_LEN); + s5c73m3_ctrl->phone_fw[S5C73M3_FW_VER_LEN+1] = '\0'; + CAM_DBG_M("FW is %s!!\n", &s5c73m3_ctrl->phone_fw); + data->sensor_platform_info->sensor_get_fw( + &s5c73m3_ctrl->sensor_fw, + &s5c73m3_ctrl->phone_fw); + } else + cam_err("Warnning!! can't check FW!\n"); + if (buf) + vfree(buf); + } + } +#if defined(TEMP_REMOVE) + data->sensor_platform_info->sensor_get_fw(&s5c73m3_ctrl->sensor_fw, + &s5c73m3_ctrl->phone_fw); + + if ((s5c73m3_ctrl->phone_fw[0] >= 'A') + && s5c73m3_ctrl->phone_fw[0] <= 'Z') { + s5c73m3_sensor_reset(); + + err = s5c73m3_SPI_booting(); + if (err < 0) { + cam_err("failed s5c73m3_SPI_booting!!\n"); + return -EIO; + } + } +#endif + + CAM_DBG_M("Exit\n"); + return 0; +} + +static int s5c73m3_init_param(void) +{ + int err = 0; + + CAM_DBG_H("Entered\n"); + + err = s5c73m3_i2c_write_block(S5C73M3_INIT, + sizeof(S5C73M3_INIT)/sizeof(S5C73M3_INIT[0])); + + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } + + return err; +} + +static int s5c73m3_read_vdd_core(void) +{ + u16 read_val; + int err; + + CAM_DBG_M("Entered\n"); + + /*Initialize OTP Controller*/ + err = s5c73m3_write(0x3800, 0xA004, 0x0000); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA000, 0x0004); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0D8, 0x0000); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0DC, 0x0004); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0C4, 0x4000); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0D4, 0x0015); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA000, 0x0001); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0B4, 0x9F90); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA09C, 0x9A95); + CHECK_ERR(err); + + /*Page Select*/ + err = s5c73m3_write(0x3800, 0xA0C4, 0x4800); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0C4, 0x4400); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0C4, 0x4200); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA004, 0x00C0); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA000, 0x0001); + CHECK_ERR(err); + + /*Read Data*/ + err = s5c73m3_read(0x3800, 0xA034, &read_val); + CHECK_ERR(err); + CAM_DBG_M("vdd_core_info %#x\n", read_val); + + err = s5c73m3_read(0x3800, 0xA040, &read_val); + CHECK_ERR(err); + CAM_DBG_M("chip info#1 %#x\n", read_val); + + err = s5c73m3_read(0x3800, 0xA044, &read_val); + CHECK_ERR(err); + CAM_DBG_M("chip info#2 %#x\n", read_val); + + err = s5c73m3_read(0x3800, 0xA048, &read_val); + CHECK_ERR(err); + CAM_DBG_M("chip info#3 %#x\n", read_val); + + /*Read Data End*/ + err = s5c73m3_write(0x3800, 0xA000, 0x0000); + CHECK_ERR(err); + + if (read_val & 0x200) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1150000); + else if (read_val & 0x800) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1100000); + else if (read_val & 0x2000) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1050000); + else if (read_val & 0x8000) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1000000); + else +#if defined(CONFIG_MACH_M2_DCM) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1230000); +#else + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1150000); +#endif + + CAM_DBG_H("X\n"); + + return 0; +} + +static int s5c73m3_set_af_softlanding(void) +{ + int err = 0; + CAM_DBG_M("Entered\n"); + + err = s5c73m3_writeb(S5C73M3_AF_SOFTLANDING, + S5C73M3_AF_SOFTLANDING_ON); + CHECK_ERR(err); + + return 0; +} + +static int s5c73m3_sensor_init_probe(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + int retVal = 0; + int temp = 0; + + CAM_DBG_M("Entered\n"); + + /*data->sensor_platform_info->sensor_power_on(0);*/ + usleep(5*1000); + + if (!data->sensor_platform_info->sensor_is_vdd_core_set()) { + rc = s5c73m3_read_vdd_core(); + if (rc < 0) { + cam_err("failed s5c73m3_read_vdd_core!!\n"); + return -EIO; + } + } + rc = s5c73m3_set_timing_register_for_vdd(); + CHECK_ERR(rc); + + rc = s5c73m3_check_fw(data, 0); + /*rc = s5c73m3_SPI_booting();*/ + if (rc < 0) { + cam_err("failed s5c73m3_check_fw!!\n"); + return -EIO; + } + + rc = s5c73m3_i2c_check_status_with_CRC(); + if (rc < 0) { + cam_err("ISP is not ready. retry loading fw!!\n"); + /* retry */ + retVal = s5c73m3_check_fw_date(); + + /* retVal = 0 : Same Version + retVal < 0 : Phone Version is latest Version than sensorFW. + retVal > 0 : Sensor Version is latest version than phoenFW. */ + if (retVal <= 0) { + cam_err("Loading From PhoneFW......\n"); + s5c73m3_reset_module(false); + rc = s5c73m3_SPI_booting(); + CHECK_ERR(rc); + } else { + cam_err("Loading From SensorFW......\n"); + s5c73m3_reset_module(true); + rc = s5c73m3_get_sensor_fw_binary(); + CHECK_ERR(rc); + } + } + + return rc; +} + + +int s5c73m3_sensor_init(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + + CAM_DBG_M("Entered\n"); + + if (!s5c73m3_ctrl) { + cam_err("s5c73m3_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + if (data) + s5c73m3_ctrl->sensordata = data; + + s5c73m3_ctrl->i2c_write_check = 0; + s5c73m3_ctrl->fps = 0; + s5c73m3_ctrl->low_light_mode_size = 0; + + config_csi2 = 0; + rc = s5c73m3_sensor_init_probe(data); + if (rc < 0) + cam_err("s5c73m3_sensor_init failed!\n"); + +init_done: + return rc; +} + +static int s5c73m3_init_client(struct i2c_client *client) +{ + CAM_DBG_M("Entered\n"); + + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&s5c73m3_wait_queue); + return 0; +} + +void sensor_native_control(void __user *arg) +{ + struct ioctl_native_cmd ctrl_info; + int err = 0; + + if (copy_from_user((void *)&ctrl_info, + (const void *)arg, sizeof(ctrl_info))) + CAM_DBG_M("fail copy_from_user!\n"); + + CAM_DBG_M("Entered, %d, %d, %d, %d\n", + ctrl_info.mode, ctrl_info.address, + ctrl_info.value_1, ctrl_info.value_2); + + switch (ctrl_info.mode) { + + case EXT_CAM_EV: + s5c73m3_set_ev(ctrl_info.value_1); + break; + + case EXT_CAM_EFFECT: + s5c73m3_set_effect(ctrl_info.value_1); + break; + + case EXT_CAM_SCENE_MODE: + s5c73m3_set_scene_mode(ctrl_info.value_1); + break; + + case EXT_CAM_ISO: + s5c73m3_set_iso(ctrl_info.value_1); + break; + + case EXT_CAM_METERING: + s5c73m3_set_metering(ctrl_info.value_1); + break; + + case EXT_CAM_WB: + s5c73m3_set_whitebalance(ctrl_info.value_1); + break; + + case EXT_CAM_QUALITY: + s5c73m3_set_jpeg_quality(ctrl_info.value_1); + break; + + case EXT_CAM_ZOOM: + s5c73m3_set_zoom(ctrl_info.value_1); + break; + + case EXT_CAM_FD_MODE: + s5c73m3_set_face_detection(ctrl_info.value_1); + break; + + case EXT_CAM_SET_WDR: + s5c73m3_set_wdr(ctrl_info.value_1); + break; + + case EXT_CAM_SET_HDR: + s5c73m3_set_HDR(ctrl_info.value_1); + break; + + case EXT_CAM_START_HDR: + s5c73m3_start_HDR(ctrl_info.value_1); + break; + + case EXT_CAM_SET_LOW_LIGHT_MODE: + s5c73m3_set_low_light(ctrl_info.value_1); + break; + + case EXT_CAM_SET_LOW_LIGHT_SIZE: + s5c73m3_ctrl->low_light_mode_size = ctrl_info.value_1; + break; + + case EXT_CAM_SET_ANTI_SHAKE: + s5c73m3_set_antishake(ctrl_info.value_1); + break; + + case EXT_CAM_SET_BEAUTY_SHOT: + s5c73m3_set_face_beauty(ctrl_info.value_1); + break; + + case EXT_CAM_SET_FPS: + s5c73m3_set_fps(ctrl_info.value_1); + break; + + case EXT_CAM_AF: + CAM_DBG_M("Entered %s mode %d\n", + "EXT_CAM_AF", ctrl_info.address); + + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + if (ctrl_info.address == MSM_V4L2_AF_SET_AUTO_FOCUS) { + err = s5c73m3_set_focus(ctrl_info.value_1); + } else if (ctrl_info.address == + MSM_V4L2_AF_SET_AUTO_FOCUS_MODE) { + err = s5c73m3_set_af_mode(ctrl_info.value_1); + } else if (ctrl_info.address == + MSM_V4L2_AF_GET_AUTO_FOCUS) { + ctrl_info.value_1 = camera_focus.mode; + } else if (ctrl_info.address == + MSM_V4L2_AF_GET_AUTO_FOCUS_RESULT) { + ctrl_info.value_1 = s5c73m3_get_af_result(); + } else if (ctrl_info.address == + MSM_V4L2_AF_SET_AUTO_FOCUS_DEFAULT_POSITION) { + err = s5c73m3_set_af_mode(ctrl_info.value_1); + } else if (ctrl_info.address == + MSM_V4L2_AF_CANCEL_AUTO_FOCUS) { + err = s5c73m3_set_focus(ctrl_info.value_1); + } else if (ctrl_info.address == + MSM_V4L2_CAF_FOCUS) { + err = s5c73m3_set_caf_focus(ctrl_info.value_1); + } else{ /* MSM_V4L2_AF_COMMAND_MAX */ + cam_err("%s can't support %d\n", + "EXT_CAM_AF", ctrl_info.address); + } + break; + + case EXT_CAM_SET_TOUCHAF_POS: + CAM_DBG_H("Entered %s\n", + "EXT_CAM_SET_TOUCHAF_POS"); + CAM_DBG_H("w %d, h %d\n", + ctrl_info.value_1, ctrl_info.value_2); + camera_focus.pos_x = ctrl_info.value_1; + camera_focus.pos_y = ctrl_info.value_2; + break; + + case EXT_CAM_FLASH_MODE: + s5c73m3_set_flash(ctrl_info.value_1); + break; + + case EXT_CAM_START_CAPTURE: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + err = s5c73m3_start_capture(ctrl_info.value_1); + + if (s5c73m3_ctrl->scene == CAMERA_SCENE_FIRE) + err = s5c73m3_capture_firework(); + else if (s5c73m3_ctrl->scene == CAMERA_SCENE_NIGHT) + err = s5c73m3_capture_nightshot(); + break; + + case EXT_CAM_SET_JPEG_SIZE: + err = s5c73m3_set_jpeg_size(ctrl_info.value_1, + ctrl_info.value_2); + break; + + case EXT_CAM_SET_RECORD_SIZE: + err = s5c73m3_set_record_size(ctrl_info.value_1, + ctrl_info.value_2); + break; + + case EXT_CAM_SET_PREVIEW_SIZE: + err = s5c73m3_set_preview_size(ctrl_info.value_1, + ctrl_info.value_2); + break; + + case EXT_CAM_GET_FLASH_STATUS: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + err = s5c73m3_get_pre_flash(ctrl_info.value_1); + ctrl_info.value_1 = isPreflashFired; + break; + + case EXT_CAM_START_AE_AWB_LOCK: + err = s5c73m3_aeawb_lock_unlock(ctrl_info.value_1, + ctrl_info.value_2); + break; + + case EXT_CAM_GET_AE_AWB_LOCK: + ctrl_info.value_1 = s5c73m3_ctrl->isAeLock; + ctrl_info.value_2 = s5c73m3_ctrl->isAwbLock; + break; + + case EXT_CAM_SET_VDIS: + s5c73m3_set_vdis(ctrl_info.value_1); + break; + + case EXT_CAM_GET_LUX: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + ctrl_info.value_1 = s5c73m3_get_lux(); + break; + + case EXT_CAM_SET_FACE_ZOOM: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + err = s5c73m3_set_face_zoom(ctrl_info.value_1); + break; + + case EXT_CAM_UPDATE_FW: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + if (ctrl_info.value_1 == CAM_FW_MODE_DUMP) + err = s5c73m3_dump_fw(); + else if (ctrl_info.value_1 == CAM_FW_MODE_UPDATE) + err = s5c73m3_check_fw(s5c73m3_ctrl->sensordata, 1); + else + err = 0; + break; + + case EXT_CAM_ANTI_BANDING: + err = s5c73m3_set_antibanding(ctrl_info.value_1); + break; + + default: + CAM_DBG_M("default mode\n"); + break; + } + + if (err < 0) + cam_err("failed sensor_native_control handle " + "ctrl_info.mode %d\n", ctrl_info.mode); + + if (copy_to_user((void *)arg, + (const void *)&ctrl_info, sizeof(ctrl_info))) + CAM_DBG_M("fail copy_to_user!\n"); + +} + +int s5c73m3_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cfg_data; + long rc = 0; + + CAM_DBG_M("Entered\n"); + + if (copy_from_user(&cfg_data, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + cam_err("s5c73m3_ioctl, cfgtype = %d, mode = %d\n", + cfg_data.cfgtype, cfg_data.mode); + + switch (cfg_data.cfgtype) { + case CFG_SET_MODE: + rc = s5c73m3_set_sensor_mode( + cfg_data.mode); + break; + + case CFG_GET_AF_MAX_STEPS: + default: + rc = 0; + cam_err("Invalid cfgtype\n"); + break; + } + + return rc; +} + +int s5c73m3_sensor_release(void) +{ + int rc = 0; + int temp = 0; + CAM_DBG_M("Entered\n"); + s5c73m3_set_af_softlanding(); + usleep(10*1000); + /*power off the LDOs*/ + /*s5c73m3_ctrl->sensordata->sensor_platform_info->sensor_power_off(0);*/ + + return rc; +} + +static int s5c73m3_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CAM_DBG_M("Entered\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + rc = -ENOTSUPP; + goto probe_failure; + } + + s5c73m3_sensorw = + kzalloc(sizeof(struct s5c73m3_work), GFP_KERNEL); + + if (!s5c73m3_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, s5c73m3_sensorw); + s5c73m3_init_client(client); + s5c73m3_client = client; + + + CAM_DBG_M("Exit\n"); + + return 0; + +probe_failure: + kfree(s5c73m3_sensorw); + s5c73m3_sensorw = NULL; + cam_err("s5c73m3_probe failed!\n"); + return rc; +} + +static const struct i2c_device_id s5c73m3_i2c_id[] = { + { SENSOR_NAME, 0}, + { }, +}; + +static struct i2c_driver s5c73m3_i2c_driver = { + .id_table = s5c73m3_i2c_id, + .probe = s5c73m3_i2c_probe, + .remove = __exit_p(s5c73m3_i2c_remove), + .driver = { + .name = SENSOR_NAME, + }, +}; + + +static int s5c73m3_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int ret = -EIO; + int rc = i2c_add_driver(&s5c73m3_i2c_driver); + CAM_DBG_M("Entered\n"); + + if (rc < 0 || s5c73m3_client == NULL) { + cam_err("%d :%d\n", rc, s5c73m3_client); + rc = -ENOTSUPP; + goto probe_done; + } + + ret = s5c73m3_spi_init(); + if (ret) + cam_err("failed to register s5c73mc fw - %x\n", ret); + +#if !defined(CONFIG_S5C73M3) && !defined(CONFIG_S5K6A3YX) + msm_camio_clk_rate_set(24000000); +#endif + + s->s_init = s5c73m3_sensor_init; + s->s_release = s5c73m3_sensor_release; + s->s_config = s5c73m3_sensor_config; + s->s_camera_type = BACK_CAMERA_2D; + s->s_mount_angle = 90; + +probe_done: + cam_err("Probe_done!!\n"); + return rc; +} + + +static struct s5c73m3_format s5c73m3_subdev_info[] = { + { +#if defined(YUV_PREVIEW) + .code = V4L2_MBUS_FMT_YUYV8_2X8, +#else + .code = V4L2_MBUS_FMT_SBGGR10_1X10, +#endif + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static int s5c73m3_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + CAM_DBG_H("Entered, index %d\n", index); + if ((unsigned int)index >= ARRAY_SIZE(s5c73m3_subdev_info)) + return -EINVAL; + + *code = s5c73m3_subdev_info[index].code; + return 0; +} + +static struct v4l2_subdev_core_ops s5c73m3_subdev_core_ops; +static struct v4l2_subdev_video_ops s5c73m3_subdev_video_ops = { + .enum_mbus_fmt = s5c73m3_enum_fmt, +}; + +static struct v4l2_subdev_ops s5c73m3_subdev_ops = { + .core = &s5c73m3_subdev_core_ops, + .video = &s5c73m3_subdev_video_ops, +}; + +static int s5c73m3_sensor_probe_cb(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + int rc = 0; + CAM_DBG_M("Entered\n"); + + rc = s5c73m3_sensor_probe(info, s); + if (rc < 0) + return rc; + + s5c73m3_ctrl = kzalloc(sizeof(struct s5c73m3_ctrl), GFP_KERNEL); + if (!s5c73m3_ctrl) { + cam_err("s5c73m3_sensor_probe failed!\n"); + return -ENOMEM; + } + + /* probe is successful, init a v4l2 subdevice */ + if (sdev) { + v4l2_i2c_subdev_init(sdev, s5c73m3_client, + &s5c73m3_subdev_ops); + s5c73m3_ctrl->sensor_dev = sdev; + } else { + cam_err("sdev is null in probe_cb\n"); + } + return rc; +} + +static int __s5c73m3_probe(struct platform_device *pdev) +{ + CAM_DBG_M("S5C73M3 probe\n"); + + return msm_sensor_register(pdev, s5c73m3_sensor_probe_cb); +} + +static struct platform_driver msm_camera_driver = { + .probe = __s5c73m3_probe, + .driver = { + .name = PLATFORM_DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init s5c73m3_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(s5c73m3_init); +MODULE_DESCRIPTION("Samsung 8 MP camera driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm/sensors/s5c73m3.h b/drivers/media/video/msm/sensors/s5c73m3.h new file mode 100644 index 00000000000..a0b21fa1e12 --- /dev/null +++ b/drivers/media/video/msm/sensors/s5c73m3.h @@ -0,0 +1,1066 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __S5C73M3_H__ +#define __S5C73M3_H__ + +#include +#include + +/*#define DEBUG_LEVEL_HIGH */ +#define DEBUG_LEVEL_MID + +/* #define DEBUG_CAM_I2C */ + +#if defined(DEBUG_LEVEL_HIGH) +#define CAM_DBG_H(fmt, arg...)\ + do { \ + printk(KERN_ERR "[%s:%d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) +#define CAM_DBG_M(fmt, arg...)\ + do { \ + printk(KERN_ERR "[%s:%d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) +#elif defined(DEBUG_LEVEL_MID) +#define CAM_DBG_H(fmt, arg...) +#define CAM_DBG_M(fmt, arg...)\ + do { \ + printk(KERN_ERR "[%s:%d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) +#else +#define CAM_DBG_H(fmt, arg...) +#define CAM_DBG_M(fmt, arg...) +#endif + +#if defined(DEBUG_CAM_I2C) +#define cam_i2c_dbg(fmt, arg...) \ + do { \ + printk(KERN_ERR "[%s : % d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) +#else +#define cam_i2c_dbg(fmt, arg...) +#endif + +#define cam_err(fmt, arg...) \ + do { \ + printk(KERN_ERR "[%s : % d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) + +#define CAPTURE_FLASH 1 +#define MOVIE_FLASH 0 + +#define S5C73M3_FW_VER_LEN 6 +#define S5C73M3_FW_VER_FILE_CUR 0x60 +/* level at or below which we need to enable flash when in auto mode */ +#define LOW_LIGHT_LEVEL 0x20 + + +/* DTP */ +#define DTP_OFF 0 +#define DTP_ON 1 +#define DTP_OFF_ACK 2 +#define DTP_ON_ACK 3 + +struct s5c73m3_userset { + unsigned int focus_mode; + unsigned int focus_status; + unsigned int continuous_af; + + unsigned int metering; + unsigned int exposure; + unsigned int wb; + unsigned int iso; + int contrast; + int saturation; + int sharpness; + int brightness; + int scene; + unsigned int zoom; + unsigned int effect; /* Color FX (AKA Color tone) */ + unsigned int scenemode; + unsigned int detectmode; + unsigned int antishake; + unsigned int fps; + unsigned int flash_mode; + unsigned int flash_state; + + unsigned int stabilize; /* IS */ + + unsigned int strobe; + unsigned int jpeg_quality; + /*unsigned int preview_size;*/ + /*struct m5mo_preview_size preview_size;*/ + unsigned int preview_size_idx; + unsigned int capture_size; + unsigned int thumbnail_size; + + +}; + + +/*extern struct s5c73m3_reg s5c73m3_regs;*/ +struct reg_struct_init { + /* PLL setting */ + uint8_t pre_pll_clk_div; /* 0x0305 */ + uint8_t plstatim; /* 0x302b */ + uint8_t reg_3024; /*ox3024*/ + uint8_t image_orientation; /* 0x0101*/ + uint8_t vndmy_ablmgshlmt; /*0x300a*/ + uint8_t y_opbaddr_start_di; /*0x3014*/ + uint8_t reg_0x3015; /*0x3015*/ + uint8_t reg_0x301c; /*0x301c*/ + uint8_t reg_0x302c; /*0x302c*/ + uint8_t reg_0x3031; /*0x3031*/ + uint8_t reg_0x3041; /* 0x3041 */ + uint8_t reg_0x3051; /* 0x3051 */ + uint8_t reg_0x3053; /* 0x3053 */ + uint8_t reg_0x3057; /* 0x3057 */ + uint8_t reg_0x305c; /* 0x305c */ + uint8_t reg_0x305d; /* 0x305d */ + uint8_t reg_0x3060; /* 0x3060 */ + uint8_t reg_0x3065; /* 0x3065 */ + uint8_t reg_0x30aa; /* 0x30aa */ + uint8_t reg_0x30ab; + uint8_t reg_0x30b0; + uint8_t reg_0x30b2; + uint8_t reg_0x30d3; + uint8_t reg_0x3106; + uint8_t reg_0x310c; + uint8_t reg_0x3304; + uint8_t reg_0x3305; + uint8_t reg_0x3306; + uint8_t reg_0x3307; + uint8_t reg_0x3308; + uint8_t reg_0x3309; + uint8_t reg_0x330a; + uint8_t reg_0x330b; + uint8_t reg_0x330c; + uint8_t reg_0x330d; + uint8_t reg_0x330f; + uint8_t reg_0x3381; +}; + +struct reg_struct { + uint8_t pll_multiplier; /* 0x0307 */ + uint8_t frame_length_lines_hi; /* 0x0340*/ + uint8_t frame_length_lines_lo; /* 0x0341*/ + uint8_t y_addr_start; /* 0x347 */ + uint8_t y_add_end; /* 0x034b */ + uint8_t x_output_size_msb; /* 0x034c */ + uint8_t x_output_size_lsb; /* 0x034d */ + uint8_t y_output_size_msb; /* 0x034e */ + uint8_t y_output_size_lsb; /* 0x034f */ + uint8_t x_even_inc; /* 0x0381 */ + uint8_t x_odd_inc; /* 0x0383 */ + uint8_t y_even_inc; /* 0x0385 */ + uint8_t y_odd_inc; /* 0x0387 */ + uint8_t hmodeadd; /* 0x3001 */ + uint8_t vmodeadd; /* 0x3016 */ + uint8_t vapplinepos_start;/*ox3069*/ + uint8_t vapplinepos_end;/*306b*/ + uint8_t shutter; /* 0x3086 */ + uint8_t haddave; /* 0x30e8 */ + uint8_t lanesel; /* 0x3301 */ +}; + +struct s5c73m3_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum s5c73m3_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +struct s5c73m3_focus { + unsigned int mode; + unsigned int caf_mode; + unsigned int lock; + unsigned int status; + unsigned int touch; + unsigned int pos_x; + unsigned int pos_y; +}; + +struct s5c73m3_fw_version { + unsigned int index; + unsigned int opened; + char path[25]; + char ver[10]; +}; + +enum s5c73m_flash_mode { + MAIN_CAMERA_FLASH_OFF, + MAIN_CAMERA_FLASH_ON, + MAIN_CAMERA_FLASH_AUTO, + MAIN_CAMERA_FLASH_TORCH, + MAIN_CAMERA_FLASH_MAX +}; + +enum s5c73m_fd_mode { + FACE_DETECTION_OFF, + FACE_DETECTION_ON, + FACE_DETECTION_MAX +}; + +enum s5c73m_jpeg_size { + JPEG_3264_2448, + JPEG_3264_1836, + JPEG_2048_1536, + JPEG_2048_1152, + JPEG_1600_1200, + JPEG_1280_720, + JPEG_640_480 +}; + +enum s5c73m3_isneed_flash_tristate { + S5C73M3_ISNEED_FLASH_OFF = 0x00, + S5C73M3_ISNEED_FLASH_ON = 0x01, + S5C73M3_ISNEED_FLASH_UNDEFINED = 0x02, +}; + +enum s5c73m3_wdr_mode { + WDR_OFF, + WDR_ON, + WDR_MAX, +}; + +struct s5c73m3_focus camera_focus; +enum s5c73m_flash_mode flash_mode; +char isflash; +unsigned int isPreflashFired; + +enum s5c73m3_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +enum s5c73m3_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum s5c73m3_fw_path { + S5C73M3_SD_CARD, + S5C73M3_IN_DATA, + S5C73M3_IN_SYSTEM, + S5C73M3_PATH_MAX, +}; + + +#define S5C73M3_IMG_OUTPUT 0x0902 +#define S5C73M3_HDR_OUTPUT 0x0008 +#define S5C73M3_YUV_OUTPUT 0x0009 +#define S5C73M3_INTERLEAVED_OUTPUT 0x000D +#define S5C73M3_HYBRID_OUTPUT 0x0016 + +#define S5C73M3_STILL_PRE_FLASH 0x0A00 +#define S5C73M3_STILL_PRE_FLASH_FIRE 0x0000 +#define S5C73M3_STILL_PRE_FLASH_NON_FIRED 0x0000 +#define S5C73M3_STILL_PRE_FLASH_FIRED 0x0001 + +#define S5C73M3_STILL_MAIN_FLASH 0x0A02 +#define S5C73M3_STILL_MAIN_FLASH_CANCEL 0x0001 +#define S5C73M3_STILL_MAIN_FLASH_FIRE 0x0002 + + +#define S5C73M3_ZOOM_STEP 0x0B00 + + +#define S5C73M3_IMAGE_EFFECT 0x0B0A +#define S5C73M3_IMAGE_EFFECT_NONE 0x0001 +#define S5C73M3_IMAGE_EFFECT_NEGATIVE 0x0002 +#define S5C73M3_IMAGE_EFFECT_AQUA 0x0003 +#define S5C73M3_IMAGE_EFFECT_SEPIA 0x0004 +#define S5C73M3_IMAGE_EFFECT_MONO 0x0005 +#define S5C73M3_IMAGE_EFFECT_SKETCH 0x0006 +#define S5C73M3_IMAGE_EFFECT_WASHED 0x0007 +#define S5C73M3_IMAGE_EFFECT_VINTAGE_WARM 0x0008 +#define S5C73M3_IMAGE_EFFECT_VINTAGE_COLD 0x0009 +#define S5C73M3_IMAGE_EFFECT_SOLARIZE 0x000A +#define S5C73M3_IMAGE_EFFECT_POSTERIZE 0x000B +#define S5C73M3_IMAGE_EFFECT_POINT_COLOR_1 0x000C +#define S5C73M3_IMAGE_EFFECT_POINT_COLOR_2 0x000D +#define S5C73M3_IMAGE_EFFECT_POINT_COLOR_3 0x000E +#define S5C73M3_IMAGE_EFFECT_POINT_COLOR_4 0x000F + + +#define S5C73M3_IMAGE_QUALITY 0x0B0C +#define S5C73M3_IMAGE_QUALITY_SUPERFINE 0x0000 +#define S5C73M3_IMAGE_QUALITY_FINE 0x0001 +#define S5C73M3_IMAGE_QUALITY_NORMAL 0x0002 +#define S5C73M3_IMAGE_QUALITY_LOW 0x0003 + +#define S5C73M3_FLASH_MODE 0x0B0E +#define S5C73M3_FLASH_MODE_OFF 0x0000 +#define S5C73M3_FLASH_MODE_ON 0x0001 +#define S5C73M3_FLASH_MODE_AUTO 0x0002 + +#define S5C73M3_FLASH_STATUS 0x0B80 +#define S5C73M3_FLASH_STATUS_OFF 0x0001 +#define S5C73M3_FLASH_STATUS_ON 0x0002 +#define S5C73M3_FLASH_STATUS_AUTO 0x0003 + +#define S5C73M3_FLASH_TORCH 0x0B12 +#define S5C73M3_FLASH_TORCH_OFF 0x0000 +#define S5C73M3_FLASH_TORCH_ON 0x0001 + +#define S5C73M3_AE_ISNEEDFLASH 0x0CBA +#define S5C73M3_AE_ISNEEDFLASH_OFF 0x0000 +#define S5C73M3_AE_ISNEEDFLASH_ON 0x0001 + + +#define S5C73M3_CHG_MODE 0x0B10 +#define S5C73M3_YUV_MODE 0x8000 +#define S5C73M3_INTERLEAVED_MODE 0x8000 +#define S5C73M3_CHG_MODE_YUV_320_240 0x8001 +#define S5C73M3_CHG_MODE_YUV_640_480 0x8002 +#define S5C73M3_CHG_MODE_YUV_880_720 0x8003 +#define S5C73M3_CHG_MODE_YUV_960_720 0x8004 +#define S5C73M3_CHG_MODE_YUV_1184_666 0x8005 +#define S5C73M3_CHG_MODE_YUV_1280_720 0x8006 +#define S5C73M3_CHG_MODE_YUV_1280_960 0x8007 +#define S5C73M3_CHG_MODE_YUV_1600_1200 0x8008 +#define S5C73M3_CHG_MODE_YUV_1632_1224 0x8009 +#define S5C73M3_CHG_MODE_YUV_1920_1080 0x800A +#define S5C73M3_CHG_MODE_YUV_1920_1440 0x800B +#define S5C73M3_CHG_MODE_YUV_2304_1296 0x800C +#define S5C73M3_CHG_MODE_YUV_2304_1728 0x800D +#define S5C73M3_CHG_MODE_JPEG_640_480 0x0010 +#define S5C73M3_CHG_MODE_JPEG_800_450 0x0020 +#define S5C73M3_CHG_MODE_JPEG_800_600 0x0030 +#define S5C73M3_CHG_MODE_JPEG_1280_720 0x0040 +#define S5C73M3_CHG_MODE_JPEG_1280_960 0x0050 +#define S5C73M3_CHG_MODE_JPEG_1600_960 0x0060 +#define S5C73M3_CHG_MODE_JPEG_1600_1200 0x0070 +#define S5C73M3_CHG_MODE_JPEG_2048_1152 0x0080 +#define S5C73M3_CHG_MODE_JPEG_2048_1536 0x0090 +#define S5C73M3_CHG_MODE_JPEG_2560_1440 0x00A0 +#define S5C73M3_CHG_MODE_JPEG_2560_1920 0x00B0 +#define S5C73M3_CHG_MODE_JPEG_3072_1728 0x00C0 +#define S5C73M3_CHG_MODE_JPEG_3264_2304 0x00D0 +#define S5C73M3_CHG_MODE_JPEG_3264_1836 0x00E0 +#define S5C73M3_CHG_MODE_JPEG_3264_2448 0x00F0 + + +#define S5C73M3_AF_CON 0x0E00 +#define S5C73M3_AF_CON_STOP 0x0000 +#define S5C73M3_AF_CON_SCAN 0x0001/*AF_SCAN:Full Search*/ +#define S5C73M3_AF_CON_START 0x0002/*AF_START:Fast Search*/ + +#define S5C73M3_AF_STATUS 0x5E80 + +#define S5C73M3_AF_TOUCH_AF 0x0E0A + +#define S5C73M3_AF_CAL 0x0E06 + +#define S5C73M3_CAF_STATUS_FIND_SEARCHING_DIR 0x0001 +#define S5C73M3_CAF_STATUS_FOCUSING 0x0002 +#define S5C73M3_CAF_STATUS_FOCUSED 0x0003 +#define S5C73M3_CAF_STATUS_INITIALIZE 0x0004 + +#define S5C73M3_AF_STATUS_INVALID 0x0010 +#define S5C73M3_AF_STATUS_FOCUSING 0x0020 +#define S5C73M3_AF_STATUS_FOCUSED 0x0030/*SUCCESS*/ +#define S5C73M3_AF_STATUS_UNFOCUSED 0x0040/*FAIL*/ + +#define S5C73M3_AF_TOUCH_POSITION 0x5E8E + +#define S5C73M3_AF_FACE_ZOOM 0x0E10 + +#define S5C73M3_AF_MODE 0x0E02 +#define S5C73M3_AF_MODE_NORMAL 0x0000 +#define S5C73M3_AF_MODE_MACRO 0x0001 +#define S5C73M3_AF_MODE_MOVIE_CAF_START 0x0002 +#define S5C73M3_AF_MODE_MOVIE_CAF_STOP 0x0003 +#define S5C73M3_AF_MODE_PREVIEW_CAF_START 0x0004 +#define S5C73M3_AF_MODE_PREVIEW_CAF_STOP 0x0005 + +#define S5C73M3_AF_SOFTLANDING 0x0E16 +#define S5C73M3_AF_SOFTLANDING_ON 0x0000 + +#define S5C73M3_FACE_DET 0x0E0C +#define S5C73M3_FACE_DET_OFF 0x0000 +#define S5C73M3_FACE_DET_ON 0x0001 + +#define S5C73M3_FACE_DET_OSD 0x0E0E +#define S5C73M3_FACE_DET_OSD_OFF 0x0000 +#define S5C73M3_FACE_DET_OSD_ON 0x0001 + +#define S5C73M3_AE_CON 0x0C00 +#define S5C73M3_AE_STOP 0x0000/*LOCK*/ +#define S5C73M3_AE_START 0x0001/*UNLOCK*/ + +#define S5C73M3_ISO 0x0C02 +#define S5C73M3_ISO_AUTO 0x0000 +#define S5C73M3_ISO_100 0x0001 +#define S5C73M3_ISO_200 0x0002 +#define S5C73M3_ISO_400 0x0003 +#define S5C73M3_ISO_800 0x0004 +#define S5C73M3_ISO_SPORTS 0x0005 +#define S5C73M3_ISO_NIGHT 0x0006 +#define S5C73M3_ISO_INDOOR 0x0007 + +#define S5C73M3_EV 0x0C04 +#define S5C73M3_EV_M20 0x0000 +#define S5C73M3_EV_M15 0x0001 +#define S5C73M3_EV_M10 0x0002 +#define S5C73M3_EV_M05 0x0003 +#define S5C73M3_EV_ZERO 0x0004 +#define S5C73M3_EV_P05 0x0005 +#define S5C73M3_EV_P10 0x0006 +#define S5C73M3_EV_P15 0x0007 +#define S5C73M3_EV_P20 0x0008 + +#define S5C73M3_METER 0x0C06 +#define S5C73M3_METER_CENTER 0x0000 +#define S5C73M3_METER_SPOT 0x0001 +#define S5C73M3_METER_AVERAGE 0x0002 +#define S5C73M3_METER_SMART 0x0003 + +#define S5C73M3_WDR 0x0C08 +#define S5C73M3_WDR_OFF 0x0000 +#define S5C73M3_WDR_ON 0x0001 + +#define S5C73M3_FLICKER_MODE 0x0C12 +#define S5C73M3_FLICKER_NONE 0x0000 +#define S5C73M3_FLICKER_MANUAL_50HZ 0x0001 +#define S5C73M3_FLICKER_MANUAL_60HZ 0x0002 +#define S5C73M3_FLICKER_AUTO 0x0003 +#define S5C73M3_FLICKER_AUTO_50HZ 0x0004 +#define S5C73M3_FLICKER_AUTO_60HZ 0x0005 + +#define S5C73M3_AE_MODE 0x0C1E +#define S5C73M3_AUTO_MODE_AE_SET 0x0000 +#define S5C73M3_FIXED_30FPS 0x0002 +#define S5C73M3_FIXED_20FPS 0x0003 +#define S5C73M3_FIXED_15FPS 0x0004 +#define S5C73M3_FIXED_7FPS 0x0009 +#define S5C73M3_ANTI_SHAKE_ON 0x0013 + +#define S5C73M3_SHARPNESS 0x0C14 +#define S5C73M3_SHARPNESS_0 0x0000 +#define S5C73M3_SHARPNESS_1 0x0001 +#define S5C73M3_SHARPNESS_2 0x0002 +#define S5C73M3_SHARPNESS_M1 0x0003 +#define S5C73M3_SHARPNESS_M2 0x0004 + +#define S5C73M3_SATURATION 0x0C16 +#define S5C73M3_SATURATION_0 0x0000 +#define S5C73M3_SATURATION_1 0x0001 +#define S5C73M3_SATURATION_2 0x0002 +#define S5C73M3_SATURATION_M1 0x0003 +#define S5C73M3_SATURATION_M2 0x0004 + +#define S5C73M3_CONTRAST 0x0C18 +#define S5C73M3_CONTRAST_0 0x0000 +#define S5C73M3_CONTRAST_1 0x0001 +#define S5C73M3_CONTRAST_2 0x0002 +#define S5C73M3_CONTRAST_M1 0x0003 +#define S5C73M3_CONTRAST_M2 0x0004 + +#define S5C73M3_SCENE_MODE 0x0C1A +#define S5C73M3_SCENE_MODE_NONE 0x0000 +#define S5C73M3_SCENE_MODE_PORTRAIT 0x0001 +#define S5C73M3_SCENE_MODE_LANDSCAPE 0x0002 +#define S5C73M3_SCENE_MODE_SPORTS 0x0003 +#define S5C73M3_SCENE_MODE_INDOOR 0x0004 +#define S5C73M3_SCENE_MODE_BEACH 0x0005 +#define S5C73M3_SCENE_MODE_SUNSET 0x0006 +#define S5C73M3_SCENE_MODE_DAWN 0x0007 +#define S5C73M3_SCENE_MODE_FALL 0x0008 +#define S5C73M3_SCENE_MODE_NIGHT 0x0009 +#define S5C73M3_SCENE_MODE_AGAINSTLIGHT 0x000A +#define S5C73M3_SCENE_MODE_FIRE 0x000B +#define S5C73M3_SCENE_MODE_TEXT 0x000C +#define S5C73M3_SCENE_MODE_CANDLE 0x000D + +#define S5C73M3_FIREWORK_CAPTURE 0x0C20 +#define S5C73M3_NIGHTSHOT_CAPTURE 0x0C22 + +#define S5C73M3_AE_AUTO_BRAKET 0x0B14 +#define S5C73M3_AE_AUTO_BRAKET_EV05 0x0080 +#define S5C73M3_AE_AUTO_BRAKET_EV10 0xC100 +#define S5C73M3_AE_AUTO_BRAKET_EV15 0x0180 +#define S5C73M3_AE_AUTO_BRAKET_EV20 0x8200 + +#define S5C73M3_LLS_MODE 0x0C2C +#define S5C73M3_LLS_MODE_ON 0x0001 +#define S5C73M3_LLS_MODE_OFF 0x0000 + +#define S5C73M3_SENSOR_STREAMING 0x090A +#define S5C73M3_SENSOR_STREAMING_OFF 0x0000 +#define S5C73M3_SENSOR_STREAMING_ON 0x0001 + +#define S5C73M3_AWB_MODE 0x0D02 +#define S5C73M3_AWB_MODE_INCANDESCENT 0x0000 +#define S5C73M3_AWB_MODE_FLUORESCENT1 0x0001 +#define S5C73M3_AWB_MODE_FLUORESCENT2 0x0002 +#define S5C73M3_AWB_MODE_DAYLIGHT 0x0003 +#define S5C73M3_AWB_MODE_CLOUDY 0x0004 +#define S5C73M3_AWB_MODE_AUTO 0x0005 + +#define S5C73M3_AWB_CON 0x0D00 +#define S5C73M3_AWB_STOP 0x0000/*LOCK*/ +#define S5C73M3_AWB_START 0x0001/*UNLOCK*/ + +#define S5C73M3_HYBRID_CAPTURE 0x0996 + +/* S5C73M3 Sensor Mode */ +#define S5C73M3_SYSINIT_MODE 0x0 +#define S5C73M3_PARMSET_MODE 0x1 +#define S5C73M3_MONITOR_MODE 0x2 +#define S5C73M3_STILLCAP_MODE 0x3 + +#define S5C73M3_STATUS 0x5080 +#define S5C73M3_I2C_ERR_STATUS 0x599E +#define S5C73M3_I2C_SEQ_STATUS 0x59A6 +#define ERROR_STATUS_CHECK_BIN_CRC (1<<0x8) + +static const u32 S5C73M3_INIT[] = { +0x00500009, +0x00545000, +0x0F140B08, +0x0F140000, +0x0F140900, +0x0F140403, /*640MHz*/ +0x00545080, +0x0F140002 +}; + +/* +MIPI_BIT_RATE_360MHz=0, +MIPI_BIT_RATE_450MHz=1, +MIPI_BIT_RATE_540MHz=2, +MIPI_BIT_RATE_640MHz=3, +MIPI_BIT_RATE_720MHz=4, +MIPI_BIT_RATE_750MHz=5, +*/ +static u32 S5C73M3_YUV_PREVIEW[] = { + 0x00500009, + 0x00545000, + 0x0F140902, + 0x0F140009, + 0x0F140900, /* MIPI OUTPUT CLK */ + 0x0F140401, /* MIPI_BIT_RATE_450MHz=1 */ + 0x0F140B10, + 0x0F148004, + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140004, +}; + +static u32 S5C73M3_HDR[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MiPi 0xetting */ + 0x0F140403, /* Lane:4 , DataRate:3(640Mbp0x) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :D(interleave)0x14VC */ + 0x0F140B10, + 0x0F14801D, /* (1:640x480 JPEG D:3264 2448 YUV) */ + 0x00545080, + 0x0F140003, +}; + +static u32 S5C73M3_LLS[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MiPi 0xetting */ + 0x0F140403, /* Lane:4 , DataRate:3(640Mbp0x) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :D(interleave)0x14VC */ + 0x0F140B10, + 0x0F14801D, /* (1:640x480 JPEG D:3264 2448 YUV) */ + 0x00545080, + 0x0F140003, +}; + +static u32 S5C73M3_FHD_VDIS[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140003, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F14811C, /*E:3264X1836 JPEG, C:2304 x 1296 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_FHD[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481EA, /*E:3264X1836 JPEG, A:1920 x 1080 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_HD_VDIS[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148117, /*E:3264X1836 JPEG, 7: YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_HD[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481E6, /*E:3264X1836 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_WVGA[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481CF, /*C:3264X2176 JPEG, F:1008X672 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_VGA[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481F2, /*F:3264X2448 JPEG, 2:640 x 480 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_PREVIEW[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x00545080, + 0x0F140003, +}; + +/* Below Not used settings will be removed later */ +static u32 S5C73M3_INTERLEAVED_PREVIEW[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140401, /*450MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140003, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1480F4, /*F:3264X2448 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_8M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1480F4, /*F:3264X2448 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_6M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1480E6, /*E:3264X1836 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_3_2M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148094, /*9:2048X1536 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_2_4M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148086, /*8:2048X1156 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_2M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148074, /*7:1600X1200 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_1M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148046, /*4:1280X720 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_VGA[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148014, /*1:640X480 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_INTERLEAVED_PREVIEW_HD[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1480F6, /*F:3264X2448 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_STND[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481FA, /*F:3264X2448 JPEG, A:1920 x 1080 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_WIDE[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481EA, /*E:3264X1836 JPEG, A:1920 x 1080 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_INTERLEAVED_PREVIEW_30[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140402, /*540MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148074, /*F:1600X1200 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +/* MIPI 4lane(540Mhz),30fps, YUV 1920x1080(FHD), JPEG : 1600x1200(2M) */ +static u32 S5C73M3_INTERLEAVED_CAMCORDER_1[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MIPI Setting */ + 0x0F140402, /* Mipi Lane 4:4Lane, + DataRate(1:450Mbps, 2:540Mbps 3:640Mbps, 4:720Mbps) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :14 + (For Qualcomm VC Interleaved) */ + 0x0F14091A, /* ISP PCLK Set */ + 0x0F140004, /* Mhz 0:27 1:129.6 + 2:140 3:194.4 4:264Mhz */ + 0x0F140B10, /* Mode Change */ + 0x0F14807A, /* 7:1600x1200 JPEG A:1920x1080 YUV */ + 0x0F140C1E, /* Frame rate set */ + 0x0F140002, /* 0 : 30~15f/s 1:24~30f/s 2:30f/s + 3:20f/s 4:15f/s fixed 5:24f/s 6:27f/s */ + 0x0F14090A, /* Sensor Stream control */ + 0x0F140001, /* 0 : Stop 1:Start */ + 0x00545080, /* Run I2C Function */ + 0x0F140006, +}; + +/* MIPI 4lane(540Mhz),30fps, YUV 1920x1080(FHD), JPEG : 2560x1920 */ +static u32 S5C73M3_INTERLEAVED_CAMCORDER_2[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MIPI Setting */ + 0x0F140402, /* Mipi Lane 4:4Lane, + DataRate(1:450Mbps, 2:540Mbps 3:640Mbps, 4:720Mbps) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :14 (For Qualcomm VC Interleaved) */ + 0x0F14091A, /* ISP PCLK Set */ + 0x0F140004, /* Mhz 0:27 1:129.6 + 2:140 3:194.4 4:264Mhz */ + 0x0F140B10, /* Mode Change */ + 0x0F1480BA, /* B:2560x1920 JPEG A:1920x1080 YUV */ + 0x0F140C1E, /* Frame rate set */ + 0x0F140002, /* 0 : 30~15f/s 1:24~30f/s 2:30f/s + 3:20f/s 4:15f/s fixed 5:24f/s 6:27f/s */ + 0x0F14090A, /* Sensor Stream control */ + 0x0F140001, /* 0 : Stop 1:Start */ + 0x00545080, /* Run I2C Function */ + 0x0F140006, +}; + +/* MIPI 4lane(540Mhz),30fps, YUV 1920x1080(FHD), JPEG : 3264x1836(6M wide) */ +static u32 S5C73M3_INTERLEAVED_CAMCORDER_3[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MIPI Setting */ + 0x0F140402, /* Mipi Lane 4:4Lane, + DataRate(1:450Mbps, 2:540Mbps 3:640Mbps, 4:720Mbps) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :14 (For Qualcomm VC Interleaved) */ + 0x0F14091A, /* ISP PCLK Set */ + 0x0F140004, /* Mhz 0:27 1:129.6 + 2:140 3:194.4 4:264Mhz */ + 0x0F140B10, /* Mode Change */ + 0x0F1480EA, /* E:3264x1836 JPEG A:1920x1080 YUV */ + 0x0F140C1E, /* Frame rate set */ + 0x0F140002, /* 0 : 30~15f/s 1:24~30f/s 2:30f/s + 3:20f/s 4:15f/s fixed 5:24f/s 6:27f/s */ + 0x0F14090A, /* Sensor Stream control */ + 0x0F140001, /* 0 : Stop 1:Start */ + 0x00545080, /* Run I2C Function */ + 0x0F140006, +}; + +/* MIPI 4lane(540Mhz),30fps, YUV 1920x1080(FHD), JPEG : 3264x2448(8M wide) */ +static u32 S5C73M3_INTERLEAVED_CAMCORDER_4[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MIPI Setting */ + 0x0F140402, /* Mipi Lane 4:4Lane, + DataRate(1:450Mbps, 2:540Mbps 3:640Mbps, 4:720Mbps) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :14 (For Qualcomm VC Interleaved) */ + 0x0F14091A, /* ISP PCLK Set */ + 0x0F140004, /* Mhz 0:27 1:129.6 + 2:140 3:194.4 4:264Mhz */ + 0x0F140B10, /* Mode Change */ + 0x0F1480FA, /* F:3264x2448 JPEG A:1920x1080 YUV */ + 0x0F140C1E, /* Frame rate set */ + 0x0F140002, /* 0 : 30~15f/s 1:24~30f/s 2:30f/s + 3:20f/s 4:15f/s fixed 5:24f/s 6:27f/s */ + 0x0F14090A, /* Sensor Stream control */ + 0x0F140001, /* 0 : Stop 1:Start */ + 0x00545080, /* Run I2C Function */ + 0x0F140006, +}; + +static u32 S5C73M3_OTP_CONTROL[] = { +0xFCFC3310, +0x00503800, +0x0054A004, +0x0F140000, +0x0054A000, +0x0F140004, +0x0054A0D8, +0x0F140000, +0x0054A0DC, +0x0F140004, +0x0054A0C4, +0x0F144000, +0x0054A0D4, +0x0F140015, +0x0054A000, +0x0F140001, +0x0054A0B4, +0x0F149F90, +0x0054A09C, +0x0F149A95, +}; + +static u32 S5C73M3_OTP_PAGE[] = { +0x0054A0C4, +0x0F144800, +0x0054A0C4, +0x0F144400, +0x0054A0C4, +0x0F144200, +0x0054A004, +0x0F1400C0, +0x0054A000, +0x0F140001, +}; + +extern int s5c73m3_spi_read(u8 *buf, size_t len, const int rxSize); +extern int s5c73m3_spi_write(const u8 *addr, const int len, const int txSize); +extern int s5c73m3_spi_init(void); +extern void print_ldos(void); +#endif /* __S5C73M3_H__ */ diff --git a/drivers/media/video/msm/sensors/s5c73m3_spi.c b/drivers/media/video/msm/sensors/s5c73m3_spi.c new file mode 100644 index 00000000000..2a126d7af12 --- /dev/null +++ b/drivers/media/video/msm/sensors/s5c73m3_spi.c @@ -0,0 +1,234 @@ +/* + * driver for S5C73M3 SPI + * + * Copyright (c) 2011, Samsung Electronics. All rights reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include + +#define cam_err(fmt, arg...) \ + do { \ + printk(KERN_ERR "[%s:%d] " fmt , \ + __func__, __LINE__, ##arg); \ + } \ + while (0) + +static struct spi_device *g_spi; + +/* If AP can't change the endian to BIG */ +/* for s5c73m ISP, this option must is required.*/ +/* This option depends on SPI_DMA_MODE */ +/* in camera driver file*/ +/*#define CHANGE_ENDIAN */ + +static inline +int spi_xmit(const u8 *addr, const int len) +{ + int ret; +#if defined(CHANGE_ENDIAN) + u8 buf[8] = {0}; +#endif + + struct spi_message msg; + + struct spi_transfer xfer = { + .len = len, +#if !defined(CHANGE_ENDIAN) + .tx_buf = addr, + /*QCTK ALRAN QUP_CONFIG 0-4 bits BIG ENDIAN*/ + .bits_per_word = 32, +#else + .tx_buf = buf, +#endif + }; + +#if defined(CHANGE_ENDIAN) + buf[0] = addr[3]; + buf[1] = addr[2]; + buf[2] = addr[1]; + buf[3] = addr[0]; + + buf[4] = addr[7]; + buf[5] = addr[6]; + buf[6] = addr[5]; + buf[7] = addr[4]; +#endif + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + ret = spi_sync(g_spi, &msg); + + if (ret < 0) + cam_err("error %d\n", ret); + + return ret; +} + +static inline +int spi_xmit_rx(u8 *in_buf, size_t len) +{ + int ret; + u8 read_out_buf[2]; + + struct spi_message msg; + struct spi_transfer xfer = { + .tx_buf = read_out_buf, + .rx_buf = in_buf, + .len = len, + .cs_change = 0, + }; + + spi_message_init(&msg); + + spi_message_add_tail(&xfer, &msg); + + ret = spi_sync(g_spi, &msg); + + if (ret < 0) + cam_err("%s - error %d\n", + __func__, ret); + + return ret; +} + +int s5c73m3_spi_read(u8 *buf, size_t len, const int rxSize) +{ + int k; + int ret = 0; + int z = 0; + + u8 paddingData[32]; + u8 temp_buf[4] = {0}; + u32 count = len/rxSize; + u32 extra = len%rxSize; + + for (k = 0; k < count; k++) { + ret = spi_xmit_rx(&buf[rxSize*k], rxSize); + if (ret < 0) { + cam_err("%s - error %d\n", + __func__, ret); + return -EINVAL; + } + } + + if (extra != 0) { + ret = spi_xmit_rx(&buf[rxSize*k], extra); + if (ret < 0) { + cam_err("%s - error %d\n", + __func__, ret); + return -EINVAL; + } + } + + for (k = 0; k < len-3; k += 4) { + memcpy(temp_buf, (char *)&buf[k], sizeof(temp_buf)); + buf[k] = temp_buf[3]; + buf[k+1] = temp_buf[2]; + buf[k+2] = temp_buf[1]; + buf[k+3] = temp_buf[0]; + } + + return 0; +} + +int s5c73m3_spi_write(const u8 *addr, const int len, const int txSize) +{ + int i, j = 0; + int ret = 0; + u8 paddingData[8]; + u32 count = len/txSize; + u32 extra = len%txSize; + cam_err("Entered\n"); + cam_err("count = %d extra = %d\n", count, extra); + + memset(paddingData, 0, sizeof(paddingData)); + + for (i = 0 ; i < count ; i++) { + ret = spi_xmit(&addr[j], txSize); + j += txSize; + if (ret < 0) { + cam_err("failed to write spi_xmit\n"); + goto exit_err; + } + } + + if (extra) { + ret = spi_xmit(&addr[j], extra); + if (ret < 0) { + cam_err("failed to write spi_xmit\n"); + goto exit_err; + } + } + + for (i = 0; i < 4; i++) { + memset(paddingData, 0, sizeof(paddingData)); + ret = spi_xmit(paddingData, 8); + if (ret < 0) { + cam_err("failed to write spi_xmit\n"); + goto exit_err; + } + } + cam_err("Finish!!\n"); +exit_err: + return ret; +} + +static int s5c73m3_spi_probe(struct spi_device *spi) +{ + int ret; + + cam_err("Entered\n"); + + if (spi_setup(spi)) { + cam_err("failed to setup spi for s5c73m3_spi\n"); + ret = -EINVAL; + goto err_setup; + } + + g_spi = spi; + + cam_err("s5c73m3_spi successfully probed\n"); + + return 0; + +err_setup: + return ret; +} + +static int __devexit s5c73m3_spi_remove(struct spi_device *spi) +{ + return 0; +} + +static struct spi_driver s5c73m3_spi_driver = { + .driver = { + .name = "s5c73m3_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = s5c73m3_spi_probe, + .remove = __devexit_p(s5c73m3_spi_remove), +}; + +int s5c73m3_spi_init(void) +{ + cam_err("Entered\n"); + + return spi_register_driver(&s5c73m3_spi_driver); +} + +void s5c73m3_spi_exit(void) +{ + spi_unregister_driver(&s5c73m3_spi_driver); +} diff --git a/drivers/media/video/msm/sensors/s5k6a3yx.c b/drivers/media/video/msm/sensors/s5k6a3yx.c new file mode 100644 index 00000000000..a044da34c2d --- /dev/null +++ b/drivers/media/video/msm/sensors/s5k6a3yx.c @@ -0,0 +1,558 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_sensor.h" +#define SENSOR_NAME "s5k6a3yx" +#define PLATFORM_DRIVER_NAME "msm_camera_s5k6a3yx" + +DEFINE_MUTEX(s5k6a3yx_mut); +static struct msm_sensor_ctrl_t s5k6a3yx_s_ctrl; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_start_settings[] = { + {0x0100, 0x01}, +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_stop_settings[] = { + {0x0100, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_groupon_settings[] = { + {0x104, 0x01}, +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_groupoff_settings[] = { + {0x104, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_mode0_settings[] = { + {0x0344, 0x00}, /* x_addr_start MSB */ + {0x0345, 0x00}, /* x_addr_start LSB */ + {0x0346, 0x00}, /* y_addr_start MSB */ + {0x0347, 0x00}, /* y_addr_start LSB */ + {0x0348, 0x05}, /* x_addr_end MSB */ + {0x0349, 0x83}, /* x_addr_end LSB */ + {0x034A, 0x05}, /* y_addr_end MSB */ + {0x034B, 0x83}, /* y_addr_end LSB */ + {0x034C, 0x05}, /* x_output_size */ + {0x034D, 0x84}, /* x_output_size */ + {0x034E, 0x05}, /* y_output_size */ + {0x034F, 0x84}, /* y_output_size */ +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_mode1_settings[] = { + {0x0344, 0x00}, /* x_addr_start MSB */ + {0x0345, 0x00}, /* x_addr_start LSB */ + {0x0346, 0x00}, /* y_addr_start MSB */ + {0x0347, 0x00}, /* y_addr_start LSB */ + {0x0348, 0x05}, /* x_addr_end MSB */ + {0x0349, 0x83}, /* x_addr_end LSB */ + {0x034A, 0x05}, /* y_addr_end MSB */ + {0x034B, 0x83}, /* y_addr_end LSB */ + {0x034C, 0x05}, /* x_output_size */ + {0x034D, 0x80}, /* x_output_size */ + {0x034E, 0x05}, /* y_output_size */ + {0x034F, 0x84}, /* y_output_size */ +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_recommend_settings[] = { + {0x0100, 0x00}, /* Streaming off */ + {0x3061, 0x55}, + {0x3062, 0x54}, + {0x5703, 0x07}, + {0x5704, 0x07}, + {0x305E, 0x0D}, + {0x305F, 0x2E}, + {0x3052, 0x01}, + {0x300B, 0x28}, + {0x300C, 0x2E}, + {0x3004, 0x0A}, + {0x5700, 0x08}, + {0x3005, 0x3D}, + {0x3008, 0x1E}, + {0x3025, 0x40}, + {0x3023, 0x20}, + {0x3029, 0xFF}, + {0x302A, 0xFF}, + {0x3505, 0x41}, + {0x3506, 0x00}, + {0x3521, 0x01}, + {0x3522, 0x01}, + {0x3D20, 0x63}, + {0x3095, 0x15}, + {0x3110, 0x01}, + {0x3111, 0x62}, + {0x3112, 0x0E}, + {0x3113, 0xBC}, + {0x311D, 0x30}, + {0x311F, 0x40}, + {0x3009, 0x1E}, + {0x0138, 0x00}, + /* MIPI CLK 720Mbps */ + {0x0305, 0x06}, /* pre_pll_clk_div */ + {0x0306, 0x00}, /* pll_multiplier MSB */ + {0x0307, 0xB4}, /* pll_multiplier LSB */ + {0x0820, 0x02}, /* requested_link_bit_rate_mbps MSB MSB */ + {0x0821, 0xD0}, /* requested_link_bit_rate_mbps MSB LSB */ + {0x0822, 0x00}, /* requested_link_bit_rate_mbps LSB MSB */ + {0x0823, 0x00}, /* requested_link_bit_rate_mbps LSB LSB */ + {0x0101, 0x00}, /* image_orientation */ + {0x0111, 0x02}, /* CSI_signaling_mode */ + {0x0112, 0x0A}, /* CSI_data_format MSB */ + {0x0113, 0x0A}, /* CSI_data_format LSB */ + {0x0136, 0x18}, /* extclk_frequency_mhz MSB */ + {0x0137, 0x00}, /* extclk_frequency_mhz LSB */ + {0x0200, 0x01}, /* fine_integration_time MSB */ + {0x0201, 0xD3}, /* fine_integration_time LSB */ + {0x0202, 0x05}, /* coarse_integration_time MSB */ + {0x0203, 0xA6}, /* coarse_integration_time LSB */ + {0x0204, 0x00}, /* analogue_gain_code_global MSB */ + {0x0205, 0x20}, /* analogue_gain_code_global LSB */ + {0x0340, 0x05}, /* frame_length_lines MSB */ + {0x0341, 0xAA}, /* frame_length_lines LSB */ + {0x0342, 0x06}, /* line_length_pck MSB */ + {0x0343, 0x42}, /* line_length_pck LSB */ + {0x0381, 0x01}, /* x_even_inc */ + {0x0383, 0x01}, /* x_odd_inc */ + {0x0385, 0x01}, /* y_even_inc */ + {0x0387, 0x01}, /* y_odd_inc */ + {0x0408, 0x00}, /* digital_crop_x_offset MSB */ + {0x0409, 0x00}, /* digital_crop_x_offset LSB */ + {0x040A, 0x00}, /* digital_crop_y_offset MSB */ + {0x040B, 0x00}, /* digital_crop_y_offset LSB */ + {0x040C, 0x05}, /* digital_crop_image_width MSB */ + {0x040D, 0x84}, /* digital_crop_image_width LSB */ + {0x040E, 0x05}, /* digital_crop_image_height MSB */ + {0x040F, 0x84}, /* digital_crop_image_height LSB */ + {0x0900, 0x00}, /* binning_mode */ + {0x0105, 0x01}, /* frame mask */ + }; + +static struct v4l2_subdev_info s5k6a3yx_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static struct msm_camera_i2c_conf_array s5k6a3yx_init_conf[] = { + {&s5k6a3yx_recommend_settings[0], + ARRAY_SIZE(s5k6a3yx_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA} +}; + +static struct msm_camera_i2c_conf_array s5k6a3yx_confs[] = { + {&s5k6a3yx_mode0_settings[0], + ARRAY_SIZE(s5k6a3yx_mode0_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}, + {&s5k6a3yx_mode1_settings[0], + ARRAY_SIZE(s5k6a3yx_mode1_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}, +}; + +static struct msm_sensor_output_info_t s5k6a3yx_dimensions[] = { + /* mode 0 */ + { + .x_output = 0x0584, /* 1412 */ + .y_output = 0x0584, /* 1412 */ + .line_length_pclk = 0x0642, /* 1602 */ + .frame_length_lines = 0x05AA, /* 1450*/ + .vt_pixel_clk = 72000000, /*76800000*/ + .op_pixel_clk = 72000000, /*76800000*/ + .binning_factor = 1, + }, + /* mode 1 */ + { + .x_output = 0x0580, /* 1408 */ + .y_output = 0x0584, /* 1412 */ + .line_length_pclk = 0x0642, /* 1602 */ + .frame_length_lines = 0x05AA, /* 1450*/ + .vt_pixel_clk = 72000000, /*76800000*/ + .op_pixel_clk = 72000000, /*76800000*/ + .binning_factor = 1, + }, +}; + +static struct msm_camera_csid_vc_cfg s5k6a3yx_cid_cfg[] = { + {0, CSI_RAW10, CSI_DECODE_10BIT}, +}; + +static struct msm_camera_csi2_params s5k6a3yx_csi_params = { + .csid_params = { + .lane_assign = 0xe4, + .lane_cnt = 1, + .lut_params = { + .num_cid = ARRAY_SIZE(s5k6a3yx_cid_cfg), + .vc_cfg = s5k6a3yx_cid_cfg, + }, + }, + .csiphy_params = { + .lane_cnt = 1, + .settle_cnt = 0x20, /* MIPI CLK 720Mbps */ + }, +}; + +static struct msm_camera_csi2_params *s5k6a3yx_csi_params_array[] = { + &s5k6a3yx_csi_params, + &s5k6a3yx_csi_params, +}; + +static struct msm_sensor_output_reg_addr_t s5k6a3yx_reg_addr = { + .x_output = 0x34C, + .y_output = 0x34E, + .line_length_pclk = 0x342, + .frame_length_lines = 0x340, +}; + +static struct msm_sensor_id_info_t s5k6a3yx_id_info = { + .sensor_id_reg_addr = 0x0, + .sensor_id = 0x0000, +}; + +static struct msm_sensor_exp_gain_info_t s5k6a3yx_exp_gain_info = { + .coarse_int_time_addr = 0x202, + .global_gain_addr = 0x204, + .vert_offset = 8, +}; + +#if !defined(CONFIG_S5C73M3) +void sensor_native_control(void __user *arg) +{ + printk(KERN_DEBUG "%s Entered\n", __func__); +} +#endif + +static int s5k6a3yx_sensor_config(void __user *argp) +{ + return msm_sensor_config(&s5k6a3yx_s_ctrl, argp); +} + +static int s5k6a3yx_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + return msm_sensor_open_init(&s5k6a3yx_s_ctrl, data); +} + +static int s5k6a3yx_sensor_release(void) +{ + return msm_sensor_release(&s5k6a3yx_s_ctrl); +} + +static const struct i2c_device_id s5k6a3yx_i2c_id[] = { + {SENSOR_NAME, (kernel_ulong_t)&s5k6a3yx_s_ctrl}, + { } +}; + +static struct i2c_driver s5k6a3yx_i2c_driver = { + .id_table = s5k6a3yx_i2c_id, + .probe = msm_sensor_i2c_probe, + .driver = { + .name = SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client s5k6a3yx_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static int s5k6a3yx_sensor_v4l2_probe(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + printk(KERN_DEBUG "#######s5k6a3yx_sensor_v4l2_probe #########\n"); + return msm_sensor_v4l2_probe(&s5k6a3yx_s_ctrl, info, sdev, s); +} + +static int s5k6a3yx_probe(struct platform_device *pdev) +{ + printk(KERN_DEBUG "############# s5k6a3yx_probe ##############\n"); + return msm_sensor_register(pdev, s5k6a3yx_sensor_v4l2_probe); +} + +struct platform_driver s5k6a3yx_driver = { + .probe = s5k6a3yx_probe, + .driver = { + .name = PLATFORM_DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_sensor_init_module(void) +{ + return platform_driver_register(&s5k6a3yx_driver); +} + +static struct v4l2_subdev_core_ops s5k6a3yx_subdev_core_ops; +static struct v4l2_subdev_video_ops s5k6a3yx_subdev_video_ops = { + .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt, +}; + +static struct v4l2_subdev_ops s5k6a3yx_subdev_ops = { + .core = &s5k6a3yx_subdev_core_ops, + .video = &s5k6a3yx_subdev_video_ops, +}; + +static void s5k6a3yx_write_exp_params( + struct msm_sensor_ctrl_t *s_ctrl, + uint32_t gain, + uint32_t fl_lines, + uint32_t line) +{ + +uint8_t msb_fl_lines, lsb_fl_lines; +uint8_t msb_line, lsb_line; +uint8_t msb_gain, lsb_gain; + + CDBG("%s gain %d fl %d line %d\n", + __func__, + gain, + fl_lines, + line); + s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl); + + + msb_fl_lines = (uint8_t)((fl_lines >> 8) & 0xFF); + lsb_fl_lines = (uint8_t)(fl_lines & 0xFF); + + msb_line = (uint8_t)((line >> 8) & 0xFF); + lsb_line = (uint8_t)(line & 0xFF); + + msb_gain = (uint8_t)((gain >> 8) & 0xFF); + lsb_gain = (uint8_t)(gain & 0xFF); + + CDBG("%s : %d %d %d %d %d %d\n", + __func__, msb_fl_lines, lsb_fl_lines, msb_line + , lsb_line, msb_gain, lsb_gain); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines, + msb_fl_lines, MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines+1, + lsb_fl_lines, MSM_CAMERA_I2C_BYTE_DATA); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, msb_line, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr+1, lsb_line, + MSM_CAMERA_I2C_BYTE_DATA); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr, msb_gain, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr+1, lsb_gain, + MSM_CAMERA_I2C_BYTE_DATA); + + s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl); +} + +static void s5k6a3yx_write_fl_lines( + struct msm_sensor_ctrl_t *s_ctrl, + uint32_t gain, + uint32_t fl_lines, + uint32_t line) +{ + uint8_t msb_fl_lines, lsb_fl_lines; + uint8_t msb_line, lsb_line; + + CDBG("%s gain %d fl %d line %d", + __func__, + gain, + fl_lines, + line); + s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl); + + + msb_fl_lines = (uint8_t)((fl_lines >> 8) & 0xFF); + lsb_fl_lines = (uint8_t)(fl_lines & 0xFF); + + msb_line = (uint8_t)((line >> 8) & 0xFF); + lsb_line = (uint8_t)(line & 0xFF); + + CDBG("%s : %d %d %d %d", + __func__, msb_fl_lines, lsb_fl_lines, msb_line, lsb_line); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines, + msb_fl_lines, MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines + 1, + lsb_fl_lines, MSM_CAMERA_I2C_BYTE_DATA); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, msb_line, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr+1, lsb_line, + MSM_CAMERA_I2C_BYTE_DATA); + + + s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl); +} + +static void s5k6a3yx_write_gain( + struct msm_sensor_ctrl_t *s_ctrl, + uint32_t gain, + uint32_t fl_lines, + uint32_t line) +{ + uint8_t msb_gain, lsb_gain; + + CDBG("%s gain %d fl %d line %d\n", + __func__, + gain, + fl_lines, + line); + s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl); + + msb_gain = (uint8_t)((gain >> 8) & 0xFF); + lsb_gain = (uint8_t)(gain & 0xFF); + + CDBG("%s : %d %d", + __func__, msb_gain, lsb_gain); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr, msb_gain, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr+1, lsb_gain, + MSM_CAMERA_I2C_BYTE_DATA); + + s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl); +} + +static int32_t s5k6a3yx_write_exp_gain( + struct msm_sensor_ctrl_t *s_ctrl, + uint16_t gain, + uint32_t line) +{ + int rc = 0; + uint32_t fl_lines = 0; + uint8_t offset; + static uint32_t old_gain; + static uint32_t old_line; + static uint32_t old_fl_lines; + + CDBG("%s E gain %d line %d\n", __func__, gain, line); + CDBG("%s E old_gain %d old_fl %d old_line %d\n", + __func__, + old_gain, + old_fl_lines, + old_line); + + if ((gain == old_gain) && (line == old_line)) { + CDBG("%s XXX\n", __func__); + return rc; + } + + fl_lines = s_ctrl->curr_frame_length_lines; + fl_lines = (fl_lines * s_ctrl->fps_divider) / Q10; + offset = s_ctrl->sensor_exp_gain_info->vert_offset; + + if (line > (fl_lines - offset)) + fl_lines = line + offset; + + s5k6a3yx_write_exp_params(s_ctrl, gain, fl_lines, line); + + old_gain = gain; + old_line = line; + old_fl_lines = fl_lines; + + CDBG("%s X old_gain %d old_line %d\n", __func__, old_gain, old_line); + + return rc; +} + + +static int32_t s5k6a3yx_write_snapshot_exp_gain( + struct msm_sensor_ctrl_t *s_ctrl, + uint16_t gain, + uint32_t line) +{ + int rc = 0; + uint32_t fl_lines = 0; + uint8_t offset; + + CDBG("%s E gain %d line %d\n", __func__, gain, line); + + fl_lines = s_ctrl->curr_frame_length_lines; + fl_lines = (fl_lines * s_ctrl->fps_divider) / Q10; + offset = s_ctrl->sensor_exp_gain_info->vert_offset; + + if (line > (fl_lines - offset)) + fl_lines = line + offset; + + s5k6a3yx_write_exp_params(s_ctrl, gain, fl_lines, line); + + return rc; +} + +static struct msm_sensor_fn_t s5k6a3yx_func_tbl = { + .sensor_start_stream = msm_sensor_start_stream, + .sensor_stop_stream = msm_sensor_stop_stream, + .sensor_group_hold_on = msm_sensor_group_hold_on, + .sensor_group_hold_off = msm_sensor_group_hold_off, + .sensor_set_fps = msm_sensor_set_fps, + + .sensor_write_exp_gain = s5k6a3yx_write_exp_gain, + .sensor_write_snapshot_exp_gain = s5k6a3yx_write_snapshot_exp_gain, + + .sensor_setting = msm_sensor_setting, + .sensor_set_sensor_mode = msm_sensor_set_sensor_mode, + .sensor_mode_init = msm_sensor_mode_init, + .sensor_get_output_info = msm_sensor_get_output_info, + .sensor_config = s5k6a3yx_sensor_config, + .sensor_open_init = s5k6a3yx_sensor_open_init, + .sensor_release = s5k6a3yx_sensor_release, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_probe = msm_sensor_probe, +}; + +static struct msm_sensor_reg_t s5k6a3yx_regs = { + .default_data_type = MSM_CAMERA_I2C_BYTE_DATA, + .start_stream_conf = s5k6a3yx_start_settings, + .start_stream_conf_size = ARRAY_SIZE(s5k6a3yx_start_settings), + .stop_stream_conf = s5k6a3yx_stop_settings, + .stop_stream_conf_size = ARRAY_SIZE(s5k6a3yx_stop_settings), + .group_hold_on_conf = s5k6a3yx_groupon_settings, + .group_hold_on_conf_size = ARRAY_SIZE(s5k6a3yx_groupon_settings), + .group_hold_off_conf = s5k6a3yx_groupoff_settings, + .group_hold_off_conf_size = + ARRAY_SIZE(s5k6a3yx_groupoff_settings), + .init_settings = &s5k6a3yx_init_conf[0], + .init_size = ARRAY_SIZE(s5k6a3yx_init_conf), + .mode_settings = &s5k6a3yx_confs[0], + .output_settings = &s5k6a3yx_dimensions[0], + .num_conf = ARRAY_SIZE(s5k6a3yx_confs), +}; + +static struct msm_sensor_ctrl_t s5k6a3yx_s_ctrl = { + .msm_sensor_reg = &s5k6a3yx_regs, + .sensor_i2c_client = &s5k6a3yx_sensor_i2c_client, + .sensor_i2c_addr = 0x20, + .sensor_output_reg_addr = &s5k6a3yx_reg_addr, + .sensor_id_info = &s5k6a3yx_id_info, + .sensor_exp_gain_info = &s5k6a3yx_exp_gain_info, + .cam_mode = MSM_SENSOR_MODE_INVALID, + .csi_params = &s5k6a3yx_csi_params_array[0], + .msm_sensor_mutex = &s5k6a3yx_mut, + .sensor_i2c_driver = &s5k6a3yx_i2c_driver, + .sensor_v4l2_subdev_info = s5k6a3yx_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k6a3yx_subdev_info), + .sensor_v4l2_subdev_ops = &s5k6a3yx_subdev_ops, + .func_tbl = &s5k6a3yx_func_tbl, +}; + +module_init(msm_sensor_init_module); +MODULE_DESCRIPTION("Samsung 2 MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/Kconfig b/drivers/media/video/msm_zsl/Kconfig new file mode 100644 index 00000000000..0928111c5fc --- /dev/null +++ b/drivers/media/video/msm_zsl/Kconfig @@ -0,0 +1,242 @@ +config MSM_CAMERA_V4L2 + bool "MSM Camera V4L2 Interface" + depends on MSM_CAMERA + default n + ---help--- + This flag enables V4L2 interface of MSM + camera driver. If enabled, application interacts + with /dev/video0 through V4L2 APIs. Otherwise, + native APIs are used through /dev/config0, /dev/frame0, + and /dev/control0. + +comment "Camera Sensor Selection" +config MT9T013 + bool "Sensor mt9t013 (BAYER 3M)" + depends on MSM_CAMERA && !ARCH_MSM8X60 && !ARCH_MSM8960 && !MSM_CAMERA_V4L2 + default n + ---help--- + MICRON 3M Bayer Sensor with AutoFocus +config MT9D113 + bool "Sensor mt9d113 (YUV 2M)" + depends on MSM_CAMERA && ARCH_MSM8X60 && !MSM_CAMERA_V4L2 + default n + ---help--- + MICRON 2M YUV Sensor + This sensor is the front camera on QT8660. + This uses csi mipi interface. + This sensor is used only on QT device. +config MT9D112 + bool "Sensor mt9d112 (YUV 2M)" + depends on MSM_CAMERA && !ARCH_MSM8X60 && !ARCH_MSM8960 && !MSM_CAMERA_V4L2 + default n + ---help--- + MICRON 2M YUV Sensor +config ISX012 + bool "Sensor ISX012 (5M)" + default n + ---help--- + SONY 5 MP CMOS Sensor +config S5C73M3 + bool "Sensor S5C73M3 (8M)" + default n + ---help--- + LSI 8 MP CMOS Sensor +config S5K6A3YX + bool "Sensor S5K6A3YX (BAYER 2M)" + default n + ---help--- + Samsung 2 MP Bayer Sensor +config S5K8AAY + bool "Sensor S5K8AAY (1.3M)" + default n + ---help--- + LSI 1.3 MP CMOS Sensor +#config S5K6AA +# bool "Sensor S5K6AA (1.3M)" +# default n +# ---help--- +# LSI 1.3 MP CMOS Sensor + +config OV5640 + bool "Sensor OV5640 (YUV 5M)" + depends on MSM_CAMERA && !MSM_CAMERA_V4L2 + default n + ---help--- + Omni 5M YUV Sensor +config WEBCAM_OV7692_QRD + bool "Sensor OV7692 QRD(VGA YUV)" + depends on MSM_CAMERA && ARCH_MSM7X27A && !MSM_CAMERA_V4L2 + default n + ---help--- + Omni Vision VGA YUV Sensor for QRD Devices +config MT9M114 + bool "Sensor MT9M114 (YUV 1.26M)" + depends on MSM_CAMERA && ARCH_MSM8960 + default n + ---help--- + APTINA 1.26 MP yuv Sensor +config WEBCAM_OV7692 + bool "Sensor OV7692 (VGA YUV)" + depends on MSM_CAMERA && ARCH_MSM8X60 && !MSM_CAMERA_V4L2 + default n + ---help--- + Omni Vision VGA YUV Sensor. +config WEBCAM_OV9726 + bool "Sensor OV9726 (VGA Bayer)" + depends on MSM_CAMERA && (ARCH_MSM8X60 || ARCH_MSM7X30 || ARCH_MSM7X27A) && !MSM_CAMERA_V4L2 + default n + ---help--- + Omni Vision VGA Bayer Sensor. +# This Senosr is used as a webcam. +# This uses the CSI interface. +config VX6953 + bool "Sensor VX6953 (BAYER 5M)" + depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60) + default n + ---help--- + STM 5M Bayer Sensor with EDOF +config SN12M0PZ + bool "Sensor sn12m0pz (Bayer 12 MP)" + depends on MSM_CAMERA && ARCH_MSM7X30 && !MSM_CAMERA_V4L2 + default n + ---help--- + Sony 12 MP Bayer Sensor +config MT9P012 + bool "Sensor mt9p012 (BAYER 5M)" + depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2 + default n + ---help--- + MICRON 5M Bayer Sensor with Autofocus + +choice + prompt "AF module" + depends on MT9P012 && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2 + default MSM_CAMERA_AF_FOXCONN + +config MSM_CAMERA_AF_FOXCONN + bool "FOXCONN Module" + help + This driver supports FOXCONN AF module for 5M Bayer sensor + +config MSM_CAMERA_AF_BAM + bool "BAM Module" + help + This driver supports BAM AF module for 5M Bayer sensor + +endchoice + +config MT9P012_KM + bool "Sensor mt9p012 KM module (BAYER 5M)" + depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2 + default n + ---help--- + MICRON 5M Bayer Sensor KM modules with Autofocus + +config MT9E013 + bool "Sensor mt9e013 module (BAYER 8M)" + depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM7X27A) && !MSM_CAMERA_V4L2 + default n + ---help--- + Aptina 8M Bayer Sensor modules with Autofocus + +config IMX074_ACT + bool "Actuator IMX074 (BAYER 13.5M)" + depends on MSM_CAMERA && ARCH_MSM8960 + default n + ---help--- + Actuator for SONY 13.5 MP Bayer Sensor + +config S5K3E2FX + bool "Sensor s5k3e2fx (Samsung 5M)" + depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2 + default n + ---help--- + Samsung 5M with Autofocus + +config QS_S5K4E1 + bool "Sensor qs_s5k4e1 (Samsung 5M)" + depends on MSM_CAMERA && ARCH_MSM8X60 && !MSM_CAMERA_V4L2 + default n + ---help--- + Samsung 5M with Autofocus + +config S5K4E1 + bool "Sensor Sensor s5k4e1 (Samsung 5M)" + depends on MSM_CAMERA + default n + ---help--- + Support for S5k4E1 samsung sensor driver. + It is a Bayer 5MP sensor with auto focus and it supports + two mipi lanes, required for msm7x2xA platform. + Say Y here if this is msm7x2xA variant platform. + +config MSM_CAMERA_FLASH_SC628A + bool "Qualcomm MSM camera sc628a flash support" + depends on MSM_CAMERA + default n + ---help--- + Enable support for LED flash for msm camera. + It is a samtech charge pump flash driver and it + supports spotlight and flash light modes with + differrent current levels. + +config IMX072 + bool "Sensor imx072 (Sony 5M)" + default n + ---help--- + Support for IMX072 sony sensor driver. + It is a Bayer 5MP sensor with auto focus and it supports + two mipi lanes, required for msm7x2xA platform. + Say Y here if this is msm7x2xA variant platform. + +#config QS_MT9P017 +# bool "Sensor qs_mt9p017 (Aptina 3D 5M)" +# depends on MSM_CAMERA +# ---help--- +# Aptina 3D 5M with Autofocus + +config VB6801 + bool "Sensor vb6801" + depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2 + ---help--- + 5M with flash + +config MSM_CAMERA_FLASH + bool "Qualcomm MSM camera flash support" + depends on MSM_CAMERA + default y + ---help--- + Enable support for LED flash for msm camera + +config MSM_CAMERA_SENSOR + bool "Qualcomm MSM camera sensor support" + depends on MSM_CAMERA + +config MSM_ACTUATOR + bool "Qualcomm MSM actuator support" + depends on MSM_CAMERA + +config MSM_GEMINI + tristate "Qualcomm MSM Gemini Jpeg Engine support" + depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960) + default n + ---help--- + Enable support for Gemini Jpeg Engine + +config MSM_VPE + tristate "Qualcomm MSM Video Pre-processing Engine support" + depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60) + default y + ---help--- + Enable support for Video Pre-processing Engine + +config QUP_EXCLUSIVE_TO_CAMERA + bool "QUP exclusive to camera" + depends on MSM_CAMERA + default y + ---help--- + This flag enabled states that QUP + is exclusive to camera. In case this + is disabled, the lvs1 voltage is enabled + by QUP in the board file as QUP is used by + applications other than camera. diff --git a/drivers/media/video/msm_zsl/Makefile b/drivers/media/video/msm_zsl/Makefile new file mode 100644 index 00000000000..9aa48a5ae68 --- /dev/null +++ b/drivers/media/video/msm_zsl/Makefile @@ -0,0 +1,50 @@ +GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) +ifeq ($(GCC_VERSION),0404) +CFLAGS_REMOVE_msm_vfe8x.o = -Wframe-larger-than=1024 +endif + +ifeq ($(CONFIG_MSM_CAMERA_V4L2),y) + EXTRA_CFLAGS += -Idrivers/media/video/msm_zsl/csi + obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o + obj-$(CONFIG_MSM_CAMERA) += io/ sensors/ actuators/ csi/ +else + obj-$(CONFIG_MSM_CAMERA) += msm_camera.o +endif +obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/ +obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o +obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o msm_io7x.o +obj-$(CONFIG_ARCH_MSM7X27A) += msm_vfe7x27a.o msm_io_7x27a.o +obj-$(CONFIG_ARCH_MSM7X30) += msm_vfe31.o msm_io_vfe31.o msm_vpe1.o +obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o msm_io8x.o +obj-$(CONFIG_ARCH_MSM8X60) += msm_vfe31.o msm_io_8x60.o msm_vpe1.o +obj-$(CONFIG_ARCH_MSM8960) += msm_io_8960.o msm_vfe32.o msm_vpe.o +obj-$(CONFIG_MT9T013) += mt9t013.o mt9t013_reg.o +obj-$(CONFIG_SN12M0PZ) += sn12m0pz.o sn12m0pz_reg.o +obj-$(CONFIG_MT9P012) += mt9p012_reg.o +obj-$(CONFIG_MSM_CAMERA_AF_FOXCONN) += mt9p012_fox.o +obj-$(CONFIG_MSM_CAMERA_AF_BAM) += mt9p012_bam.o +obj-$(CONFIG_MT9P012_KM) += mt9p012_km.o mt9p012_km_reg.o +obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o +obj-$(CONFIG_S5K3E2FX) += s5k3e2fx.o +obj-$(CONFIG_S5K4E1) += s5k4e1.o s5k4e1_reg.o +#FIXME: Merge the two ifeq causes VX6953 preview not coming up. +ifeq ($(CONFIG_MSM_CAMERA_V4L2),y) + obj-$(CONFIG_VX6953) += vx6953_v4l2.o vx6953_reg_v4l2.o + obj-$(CONFIG_IMX074) += imx074_v4l2.o imx074_reg.o + obj-$(CONFIG_ISX012) += isx012_v4l2.o + obj-$(CONFIG_S5K6AA) += s5k6aa_v4l2.o cam_pmic_s5k6aa.o + obj-$(CONFIG_S5K8AAY) += s5k8aay_v4l2.o +else + obj-$(CONFIG_VX6953) += vx6953.o vx6953_reg.o + obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o +endif +obj-$(CONFIG_QS_S5K4E1) += qs_s5k4e1.o qs_s5k4e1_reg.o +obj-$(CONFIG_VB6801) += vb6801.o +obj-$(CONFIG_IMX072) += imx072.o imx072_reg.o +obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o +obj-$(CONFIG_WEBCAM_OV7692) += ov7692.o +obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd.o +obj-$(CONFIG_OV5640) += ov5640.o +obj-$(CONFIG_MT9D112) += mt9d112.o mt9d112_reg.o + +obj-$(CONFIG_MT9D113) += mt9d113.o mt9d113_reg.o diff --git a/drivers/media/video/msm_zsl/actuators/Makefile b/drivers/media/video/msm_zsl/actuators/Makefile new file mode 100644 index 00000000000..8426f39c0c0 --- /dev/null +++ b/drivers/media/video/msm_zsl/actuators/Makefile @@ -0,0 +1,5 @@ +GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) +EXTRA_CFLAGS += -Idrivers/media/video/msm_zsl +EXTRA_CFLAGS += -Idrivers/media/video/msm_zsl/io +obj-$(CONFIG_MSM_ACTUATOR) += msm_actuator.o +obj-$(CONFIG_IMX074_ACT) += imx074_act.o diff --git a/drivers/media/video/msm_zsl/actuators/imx074_act.c b/drivers/media/video/msm_zsl/actuators/imx074_act.c new file mode 100644 index 00000000000..e01d2c7e646 --- /dev/null +++ b/drivers/media/video/msm_zsl/actuators/imx074_act.c @@ -0,0 +1,259 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_actuator.h" +#include "msm_camera_i2c.h" + +#define IMX074_TOTAL_STEPS_NEAR_TO_FAR 41 +DEFINE_MUTEX(imx074_act_mutex); +static struct msm_actuator_ctrl_t imx074_act_t; + +static struct region_params_t g_regions[] = { + /* step_bound[0] - macro side boundary + * step_bound[1] - infinity side boundary + */ + /* Region 1 */ + { + .step_bound = {IMX074_TOTAL_STEPS_NEAR_TO_FAR, 0}, + .code_per_step = 2, + }, +}; + +static uint16_t g_scenario[] = { + /* MOVE_NEAR and MOVE_FAR dir*/ + IMX074_TOTAL_STEPS_NEAR_TO_FAR, +}; + +static struct damping_params_t g_damping[] = { + /* MOVE_NEAR Dir */ + /* Scene 1 => Damping params */ + { + .damping_step = 0xFF, + .damping_delay = 0, + }, +}; + +static struct damping_t g_damping_params[] = { + /* MOVE_NEAR and MOVE_FAR dir */ + /* Region 1 */ + { + .ringing_params = g_damping, + }, +}; + +static int32_t imx074_wrapper_i2c_write(struct msm_actuator_ctrl_t *a_ctrl, + int16_t next_lens_position, void *params) +{ + msm_camera_i2c_write(&a_ctrl->i2c_client, + 0x00, + next_lens_position, + MSM_CAMERA_I2C_BYTE_DATA); + return 0; +} + +int32_t imx074_act_write_focus( + struct msm_actuator_ctrl_t *a_ctrl, + uint16_t curr_lens_pos, + struct damping_params_t *damping_params, + int8_t sign_direction, + int16_t code_boundary) +{ + int32_t rc = 0; + uint16_t dac_value = 0; + + LINFO("%s called, curr lens pos = %d, code_boundary = %d\n", + __func__, + curr_lens_pos, + code_boundary); + + if (sign_direction == 1) + dac_value = (code_boundary - curr_lens_pos) | 0x80; + else + dac_value = (curr_lens_pos - code_boundary); + + LINFO("%s dac_value = %d\n", + __func__, + dac_value); + + rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, dac_value, NULL); + + return rc; +} + +static int32_t imx074_set_default_focus( + struct msm_actuator_ctrl_t *a_ctrl) +{ + int32_t rc = 0; + + if (!a_ctrl->step_position_table) + a_ctrl->func_tbl.actuator_init_table(a_ctrl); + + if (a_ctrl->curr_step_pos != 0) { + rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, 0x7F, NULL); + rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, 0x7F, NULL); + a_ctrl->curr_step_pos = 0; + } else if (a_ctrl->func_tbl.actuator_init_focus) + rc = a_ctrl->func_tbl.actuator_init_focus(a_ctrl); + return rc; +} + +static int32_t imx074_act_init_focus(struct msm_actuator_ctrl_t *a_ctrl) +{ + int32_t rc; + LINFO("%s called\n", + __func__); + /* Initialize to infinity */ + msm_camera_i2c_write(&a_ctrl->i2c_client, + 0x01, + 0xA9, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(&a_ctrl->i2c_client, + 0x02, + 0xD2, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(&a_ctrl->i2c_client, + 0x03, + 0x0C, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(&a_ctrl->i2c_client, + 0x04, + 0x14, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(&a_ctrl->i2c_client, + 0x05, + 0xB6, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(&a_ctrl->i2c_client, + 0x06, + 0x4F, + MSM_CAMERA_I2C_BYTE_DATA); + + rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, 0x7F, NULL); + rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, 0x7F, NULL); + a_ctrl->curr_step_pos = 0; + return rc; +} + +static const struct i2c_device_id imx074_act_i2c_id[] = { + {"imx074_act", (kernel_ulong_t)&imx074_act_t}, + { } +}; + +static int imx074_act_config( + void __user *argp) +{ + LINFO("%s called\n", __func__); + return (int) msm_actuator_config(&imx074_act_t, argp); +} + +static int imx074_i2c_add_driver_table( + void) +{ + LINFO("%s called\n", __func__); + return (int) msm_actuator_init_table(&imx074_act_t); +} + +static struct i2c_driver imx074_act_i2c_driver = { + .id_table = imx074_act_i2c_id, + .probe = msm_actuator_i2c_probe, + .remove = __exit_p(imx074_act_i2c_remove), + .driver = { + .name = "imx074_act", + }, +}; + +static int __init imx074_i2c_add_driver( + void) +{ + LINFO("%s called\n", __func__); + return i2c_add_driver(imx074_act_t.i2c_driver); +} + +static struct v4l2_subdev_core_ops imx074_act_subdev_core_ops; + +static struct v4l2_subdev_ops imx074_act_subdev_ops = { + .core = &imx074_act_subdev_core_ops, +}; + +static int32_t imx074_act_create_subdevice( + void *board_info, + void *sdev) +{ + LINFO("%s called\n", __func__); + + return (int) msm_actuator_create_subdevice(&imx074_act_t, + (struct i2c_board_info const *)board_info, + (struct v4l2_subdev *)sdev); +} + +static struct msm_actuator_ctrl_t imx074_act_t = { + .i2c_driver = &imx074_act_i2c_driver, + .i2c_addr = 0xE4, + .act_v4l2_subdev_ops = &imx074_act_subdev_ops, + .actuator_ext_ctrl = { + .a_init_table = imx074_i2c_add_driver_table, + .a_create_subdevice = imx074_act_create_subdevice, + .a_config = imx074_act_config, + }, + + .i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + }, + + .set_info = { + .total_steps = IMX074_TOTAL_STEPS_NEAR_TO_FAR, + }, + + .curr_step_pos = 0, + .curr_region_index = 0, + .initial_code = 0x7F, + .actuator_mutex = &imx074_act_mutex, + + .func_tbl = { + .actuator_init_table = msm_actuator_init_table, + .actuator_move_focus = msm_actuator_move_focus, + .actuator_write_focus = imx074_act_write_focus, + .actuator_set_default_focus = imx074_set_default_focus, + .actuator_init_focus = imx074_act_init_focus, + .actuator_i2c_write = imx074_wrapper_i2c_write, + }, + + .get_info = { + .focal_length_num = 46, + .focal_length_den = 10, + .f_number_num = 265, + .f_number_den = 100, + .f_pix_num = 14, + .f_pix_den = 10, + .total_f_dist_num = 197681, + .total_f_dist_den = 1000, + }, + + /* Initialize scenario */ + .ringing_scenario[MOVE_NEAR] = g_scenario, + .scenario_size[MOVE_NEAR] = ARRAY_SIZE(g_scenario), + .ringing_scenario[MOVE_FAR] = g_scenario, + .scenario_size[MOVE_FAR] = ARRAY_SIZE(g_scenario), + + /* Initialize region params */ + .region_params = g_regions, + .region_size = ARRAY_SIZE(g_regions), + + /* Initialize damping params */ + .damping[MOVE_NEAR] = g_damping_params, + .damping[MOVE_FAR] = g_damping_params, +}; + +subsys_initcall(imx074_i2c_add_driver); +MODULE_DESCRIPTION("IMX074 actuator"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/actuators/msm_actuator.c b/drivers/media/video/msm_zsl/actuators/msm_actuator.c new file mode 100755 index 00000000000..892636d9ee7 --- /dev/null +++ b/drivers/media/video/msm_zsl/actuators/msm_actuator.c @@ -0,0 +1,340 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include "msm_actuator.h" + +int32_t msm_actuator_write_focus( + struct msm_actuator_ctrl_t *a_ctrl, + uint16_t curr_lens_pos, + struct damping_params_t *damping_params, + int8_t sign_direction, + int16_t code_boundary) +{ + int32_t rc = 0; + int16_t next_lens_pos = 0; + uint16_t damping_code_step = 0; + uint16_t wait_time = 0; + + damping_code_step = damping_params->damping_step; + wait_time = damping_params->damping_delay; + + /* Write code based on damping_code_step in a loop */ + for (next_lens_pos = + curr_lens_pos + (sign_direction * damping_code_step); + (sign_direction * next_lens_pos) <= + (sign_direction * code_boundary); + next_lens_pos = + (next_lens_pos + + (sign_direction * damping_code_step))) { + rc = a_ctrl->func_tbl. + actuator_i2c_write(a_ctrl, next_lens_pos, + damping_params->hw_params); + curr_lens_pos = next_lens_pos; + usleep(wait_time); + } + + if (curr_lens_pos != code_boundary) { + rc = a_ctrl->func_tbl. + actuator_i2c_write(a_ctrl, code_boundary, + damping_params->hw_params); + usleep(wait_time); + } + return rc; +} + + +int32_t msm_actuator_move_focus( + struct msm_actuator_ctrl_t *a_ctrl, + int dir, + int32_t num_steps) +{ + int32_t rc = 0; + int8_t sign_dir = 0; + uint16_t curr_scene = 0; + uint16_t scenario_size = 0; + uint16_t index = 0; + uint16_t step_boundary = 0; + uint16_t target_step_pos = 0; + uint16_t target_lens_pos = 0; + int16_t dest_step_pos = 0; + uint16_t curr_lens_pos = 0; + LINFO("%s called, dir %d, num_steps %d\n", + __func__, + dir, + num_steps); + + /* Determine sign direction */ + if (dir == MOVE_NEAR) + sign_dir = 1; + else if (dir == MOVE_FAR) + sign_dir = -1; + else { + pr_err("Illegal focus direction\n"); + rc = -EINVAL; + return rc; + } + + /* Determine destination step position */ + dest_step_pos = a_ctrl->curr_step_pos + + (sign_dir * num_steps); + + if (dest_step_pos < 0) + dest_step_pos = 0; + else if (dest_step_pos > a_ctrl->set_info.total_steps) + dest_step_pos = a_ctrl->set_info.total_steps; + + if (dest_step_pos == a_ctrl->curr_step_pos) + return rc; + + /* Determine scenario */ + scenario_size = a_ctrl->scenario_size[dir]; + for (index = 0; index < scenario_size; index++) { + if (num_steps <= a_ctrl->ringing_scenario[dir][index]) { + curr_scene = index; + break; + } + } + + curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos]; + CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n", + a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos); + + while (a_ctrl->curr_step_pos != dest_step_pos) { + step_boundary = + a_ctrl->region_params[a_ctrl->curr_region_index]. + step_bound[dir]; + if ((dest_step_pos * sign_dir) <= + (step_boundary * sign_dir)) { + + target_step_pos = dest_step_pos; + target_lens_pos = + a_ctrl->step_position_table[target_step_pos]; + curr_lens_pos = a_ctrl->func_tbl. + actuator_write_focus( + a_ctrl, + curr_lens_pos, + &(a_ctrl->damping[dir]\ + [a_ctrl->curr_region_index]. + ringing_params[curr_scene]), + sign_dir, + target_lens_pos); + + } else { + target_step_pos = step_boundary; + target_lens_pos = + a_ctrl->step_position_table[target_step_pos]; + curr_lens_pos = a_ctrl->func_tbl. + actuator_write_focus( + a_ctrl, + curr_lens_pos, + &(a_ctrl->damping[dir]\ + [a_ctrl->curr_region_index]. + ringing_params[curr_scene]), + sign_dir, + target_lens_pos); + + a_ctrl->curr_region_index += sign_dir; + } + a_ctrl->curr_step_pos = target_step_pos; + } + + return rc; +} + +int32_t msm_actuator_init_table( + struct msm_actuator_ctrl_t *a_ctrl) +{ + int16_t code_per_step = 0; + int32_t rc = 0; + int16_t cur_code = 0; + int16_t step_index = 0, region_index = 0; + uint16_t step_boundary = 0; + LINFO("%s called\n", __func__); + + if (a_ctrl->func_tbl.actuator_set_params) + a_ctrl->func_tbl.actuator_set_params(a_ctrl); + + /* Fill step position table */ + a_ctrl->step_position_table = + kmalloc(sizeof(uint16_t) * (a_ctrl->set_info.total_steps + 1), + GFP_KERNEL); + cur_code = a_ctrl->initial_code; + a_ctrl->step_position_table[step_index++] = cur_code; + for (region_index = 0; + region_index < a_ctrl->region_size; + region_index++) { + code_per_step = + a_ctrl->region_params[region_index].code_per_step; + step_boundary = + a_ctrl->region_params[region_index]. + step_bound[MOVE_NEAR]; + if (a_ctrl->set_info.total_steps < step_boundary) { + pr_err("%s: Region params / total steps mismatch\n", + __func__); + kfree(a_ctrl->step_position_table); + a_ctrl->step_position_table = NULL; + return -EINVAL; + } + for (; step_index <= step_boundary; + step_index++) { + cur_code += code_per_step; + a_ctrl->step_position_table[step_index] = cur_code; + } + } + for (step_index = 0; + step_index < a_ctrl->set_info.total_steps; + step_index++) { + CDBG("step_position_table[%d]= %d\n", + step_index, + a_ctrl->step_position_table[step_index]); + } + + a_ctrl->curr_step_pos = 0; + a_ctrl->curr_region_index = 0; + + return rc; +} + +int32_t msm_actuator_set_default_focus( + struct msm_actuator_ctrl_t *a_ctrl) +{ + int32_t rc = 0; + LINFO("%s called\n", __func__); + + if (!a_ctrl->step_position_table) + a_ctrl->func_tbl.actuator_init_table(a_ctrl); + + if (a_ctrl->curr_step_pos != 0) + rc = a_ctrl->func_tbl.actuator_move_focus(a_ctrl, MOVE_FAR, + a_ctrl->curr_step_pos); + else if (a_ctrl->func_tbl.actuator_init_focus) + rc = a_ctrl->func_tbl.actuator_init_focus(a_ctrl); + return rc; +} + +int32_t msm_actuator_af_power_down(struct msm_actuator_ctrl_t *a_ctrl) +{ + int32_t rc = 0; + LINFO("%s called\n", __func__); + + if (a_ctrl->step_position_table[a_ctrl->curr_step_pos] != + a_ctrl->initial_code) { + rc = a_ctrl->func_tbl.actuator_set_default_focus(a_ctrl); + LINFO("%s after msm_actuator_set_default_focus\n", __func__); + } + kfree(a_ctrl->step_position_table); + return rc; +} + +int32_t msm_actuator_config( + struct msm_actuator_ctrl_t *a_ctrl, + void __user *argp) +{ + struct msm_actuator_cfg_data cdata; + int32_t rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct msm_actuator_cfg_data))) + return -EFAULT; + mutex_lock(a_ctrl->actuator_mutex); + LINFO("%s called, type %d\n", __func__, cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_ACTUATOR_INFO: + cdata.is_af_supported = 1; + cdata.cfg.get_info = a_ctrl->get_info; + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct msm_actuator_cfg_data))) + rc = -EFAULT; + break; + case CFG_SET_ACTUATOR_INFO: + a_ctrl->set_info = cdata.cfg.set_info; + rc = a_ctrl->func_tbl.actuator_init_table(a_ctrl); + if (rc < 0) + LERROR("%s init table failed %d\n", __func__, rc); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = a_ctrl->func_tbl.actuator_set_default_focus(a_ctrl); + if (rc < 0) + LERROR("%s move focus failed %d\n", __func__, rc); + break; + + case CFG_MOVE_FOCUS: + rc = a_ctrl->func_tbl.actuator_move_focus(a_ctrl, + cdata.cfg.move.dir, + cdata.cfg.move.num_steps); + if (rc < 0) + LERROR("%s move focus failed %d\n", __func__, rc); + break; + + default: + break; + } + mutex_unlock(a_ctrl->actuator_mutex); + return rc; +} + +int32_t msm_actuator_i2c_probe( + struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct msm_actuator_ctrl_t *act_ctrl_t = NULL; + LINFO("%s called\n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("i2c_check_functionality failed\n"); + goto probe_failure; + } + + act_ctrl_t = (struct msm_actuator_ctrl_t *)(id->driver_data); + i2c_set_clientdata(client, (void *)&act_ctrl_t->actuator_ext_ctrl); + LINFO("%s client = %x act ctrl t = %x\n", + __func__, + (unsigned int) client, + (unsigned int)&act_ctrl_t->actuator_ext_ctrl); + act_ctrl_t->i2c_client.client = client; + if (act_ctrl_t->i2c_addr != 0) + act_ctrl_t->i2c_client.client->addr = + act_ctrl_t->i2c_addr; + + /* act_ctrl_t->func_tbl.actuator_init_table(act_ctrl_t); */ + LINFO("%s succeeded\n", __func__); + return rc; + +probe_failure: + pr_err("%s failed! rc = %d\n", __func__, rc); + return rc; +} + +int32_t msm_actuator_create_subdevice(struct msm_actuator_ctrl_t *a_ctrl, + struct i2c_board_info const *board_info, + struct v4l2_subdev *sdev) +{ + int32_t rc = 0; + + LINFO("%s called\n", __func__); + + /* Store the sub device in actuator structure */ + a_ctrl->sdev = sdev; + + /* Assign name for sub device */ + snprintf(sdev->name, sizeof(sdev->name), "%s", board_info->type); + + /* Initialize sub device */ + v4l2_i2c_subdev_init(sdev, + a_ctrl->i2c_client.client, + a_ctrl->act_v4l2_subdev_ops); + + return rc; +} diff --git a/drivers/media/video/msm_zsl/actuators/msm_actuator.h b/drivers/media/video/msm_zsl/actuators/msm_actuator.h new file mode 100644 index 00000000000..6fad8ddf9d3 --- /dev/null +++ b/drivers/media/video/msm_zsl/actuators/msm_actuator.h @@ -0,0 +1,127 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ +#ifndef MSM_ACTUATOR_H +#define MSM_ACTUATOR_H + +#include +#include +#include +#include +#include "msm_camera_i2c.h" + +#ifdef LERROR +#undef LERROR +#endif + +#ifdef LINFO +#undef LINFO +#endif + +#define LERROR(fmt, args...) pr_err(fmt, ##args) + +#define CONFIG_MSM_CAMERA_ACT_DBG 0 + +#if CONFIG_MSM_CAMERA_ACT_DBG +#define LINFO(fmt, args...) printk(fmt, ##args) +#else +#define LINFO(fmt, args...) CDBG(fmt, ##args) +#endif + +struct msm_actuator_ctrl_t; + +struct region_params_t { + /* [0] = ForwardDirection Macro boundary + [1] = ReverseDirection Inf boundary + */ + uint16_t step_bound[2]; + uint16_t code_per_step; +}; + +struct damping_params_t { + uint16_t damping_step; + uint16_t damping_delay; + void *hw_params; +}; + +struct damping_t { + struct damping_params_t *ringing_params; +}; + +struct msm_actuator_func_tbl { + int32_t (*actuator_i2c_write_b_af)(struct msm_actuator_ctrl_t *, + uint8_t, + uint8_t); + int32_t (*actuator_init_table)(struct msm_actuator_ctrl_t *); + int32_t (*actuator_init_focus)(struct msm_actuator_ctrl_t *); + int32_t (*actuator_set_default_focus) (struct msm_actuator_ctrl_t *); + int32_t (*actuator_set_params)(struct msm_actuator_ctrl_t *); + int32_t (*actuator_move_focus) (struct msm_actuator_ctrl_t *, + int, + int32_t); + int (*actuator_power_down) (struct msm_actuator_ctrl_t *); + int32_t (*actuator_config)(void __user *); + int32_t (*actuator_i2c_write)(struct msm_actuator_ctrl_t *, + int16_t, void *); + int32_t (*actuator_write_focus)(struct msm_actuator_ctrl_t *, + uint16_t, + struct damping_params_t *, + int8_t, + int16_t); +}; + +struct msm_actuator_ctrl_t { + uint32_t i2c_addr; + struct i2c_driver *i2c_driver; + struct msm_camera_i2c_client i2c_client; + struct mutex *actuator_mutex; + struct msm_actuator_ctrl actuator_ext_ctrl; + struct msm_actuator_func_tbl func_tbl; + struct v4l2_subdev *sdev; + struct v4l2_subdev_ops *act_v4l2_subdev_ops; + struct msm_actuator_set_info_t set_info; + struct msm_actuator_get_info_t get_info; + + int16_t initial_code; + int16_t curr_step_pos; + uint16_t curr_region_index; + uint16_t *step_position_table; + uint16_t *ringing_scenario[2]; + uint16_t scenario_size[2]; + struct region_params_t *region_params; + uint16_t region_size; + struct damping_t *damping[2]; + void *user_data; +}; + +int32_t msm_actuator_i2c_write_b_af(struct msm_actuator_ctrl_t *a_ctrl, + uint8_t msb, + uint8_t lsb); +int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, + void __user *cfg_data); +int32_t msm_actuator_move_focus(struct msm_actuator_ctrl_t *a_ctrl, + int direction, + int32_t num_steps); +int32_t msm_actuator_init_table(struct msm_actuator_ctrl_t *a_ctrl); +int32_t msm_actuator_set_default_focus(struct msm_actuator_ctrl_t *a_ctrl); +int32_t msm_actuator_af_power_down(struct msm_actuator_ctrl_t *a_ctrl); +int32_t msm_actuator_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id); +int32_t msm_actuator_write_focus(struct msm_actuator_ctrl_t *a_ctrl, + uint16_t curr_lens_pos, + struct damping_params_t *damping_params, + int8_t sign_direction, + int16_t code_boundary); +int32_t msm_actuator_create_subdevice(struct msm_actuator_ctrl_t *a_ctrl, + struct i2c_board_info const *board_info, + struct v4l2_subdev *sdev); + +#endif diff --git a/drivers/media/video/msm_zsl/cam_pmic_s5k6aa.c b/drivers/media/video/msm_zsl/cam_pmic_s5k6aa.c new file mode 100644 index 00000000000..95d4c12af22 --- /dev/null +++ b/drivers/media/video/msm_zsl/cam_pmic_s5k6aa.c @@ -0,0 +1,135 @@ + + +/*************************************************************** +CAMERA Power control +****************************************************************/ + + + + +#include +#include +#include +#include +#include + +#include +#include "cam_pmic.h" + + + +struct regulator *l11_s5k6aa,*l12_s5k6aa,*l16_s5k6aa,*l18_s5k6aa,*l29_s5k6aa; + + +/* CAM power + CAM_SENSOR_A_2.8 : VREG_L16 : l16 + CAM_SENSOR_IO_1.8 : VREG_L29 : l29 + CAM_AF_2.8 : VREG_L11 : l11 + CAM_SENSOR_CORE1.2 : VREG_L12 : l12 + CAM_ISP_CORE_1.2 : CAM_CORE_EN(GPIO 6) + + CAM_DVDD_1.5 : VREG_L18 : l18 +*/ +void cam_ldo_power_on_s5k6aa(void) +{ + int ret = 0; + int temp = 0; + printk("[s5k6aa]cam_ldo_power_on\n"); + +//CAM_IO_1.8V + l29_s5k6aa = regulator_get(NULL, "8921_l29"); + ret = regulator_set_voltage(l29_s5k6aa, 1800000, 1800000); + if (ret) { + printk("%s: error setting voltage\n", __func__); + } + ret = regulator_enable(l29_s5k6aa); + if (ret) { + printk("%s: error enabling regulator\n", __func__); + } + mdelay(5); + +// CAM_A_2.8V + l16_s5k6aa = regulator_get(NULL, "8921_l16"); + ret = regulator_set_voltage(l16_s5k6aa, 2800000, 2800000); + if (ret) { + printk("%s: error setting voltage\n", __func__); + } + ret = regulator_enable(l16_s5k6aa); + if (ret) { + printk("%s: error enabling regulator\n", __func__); + } + mdelay(5); + +//CAM_DVDD_1.5V(sub) + l18_s5k6aa = regulator_get(NULL, "8921_l18"); + ret = regulator_set_voltage(l18_s5k6aa, 1500000, 1500000); + if (ret) { + printk("%s: error setting voltage\n", __func__); + } + ret = regulator_enable(l18_s5k6aa); + if (ret) { + printk("%s: error enabling regulator\n", __func__); + } + mdelay(5); +} + +void cam_ldo_power_off_s5k6aa(void) +{ + int ret = 0; + printk("#### cam_ldo_power_off ####\n"); + + // 3M_AF 2.8V + if (l11_s5k6aa) { + ret = regulator_disable(l11_s5k6aa); + if (ret) { + printk("%s: error disabling regulator\n", __func__); + } + //regulator_put(lvs0); + } + mdelay(5); + + //CAM_IO_1.8V + if (l29_s5k6aa) { + ret = regulator_disable(l29_s5k6aa); + if (ret) { + printk("%s: error disabling regulator\n", __func__); + } + //regulator_put(lvs0); + } + mdelay(5); + + //VT_CORE_1.5V(sub) + if (l18_s5k6aa) { + ret = regulator_disable(l18_s5k6aa); + if (ret) { + printk("%s: error disabling regulator\n", __func__); + } + //regulator_put(lvs0); + } + mdelay(5); + + //SENSOR_CORE_1.2V + if (l12_s5k6aa) { + ret = regulator_disable(l12_s5k6aa); + if (ret) { + printk("%s: error disabling regulator\n", __func__); + } + //regulator_put(lvs0); + } + mdelay(5); + + // CAM_A_2.8V + if (l16_s5k6aa) { + ret = regulator_disable(l16_s5k6aa); + if (ret) { + printk("%s: error disabling regulator\n", __func__); + } + //regulator_put(lvs0); + } + mdelay(5); + + //CAM_ISP_CORE_1.2 + gpio_set_value_cansleep(CAM_CORE_EN, LOW); + mdelay(5); + +} diff --git a/drivers/media/video/msm_zsl/cam_pmic_s5k6aa.h b/drivers/media/video/msm_zsl/cam_pmic_s5k6aa.h new file mode 100644 index 00000000000..0415b77cdfd --- /dev/null +++ b/drivers/media/video/msm_zsl/cam_pmic_s5k6aa.h @@ -0,0 +1,35 @@ + +#ifndef _SEC_CAM_PMIC_H +#define _SEC_CAM_PMIC_H + + +#if 0 +#define CAM_8M_RST 50 +#define CAM_VGA_RST 41 + +#define CAM_MEGA_EN 37 + +#define CAM_VGA_EN 42 + +#define CAM_PMIC_STBY 37 + +#define CAM_IO_EN 37 +#endif + + +#define ISP_INT 4 +#define CAM_CORE_EN 6 +//#define 5M_RST 107 +#define VT_RST 76 +#define VT_EN 18 + +#define ON 1 +#define OFF 0 +#define LOW 0 +#define HIGH 1 + +void cam_ldo_power_on_s5k6aa(void); +void cam_ldo_power_off_s5k6aa(void); + + +#endif diff --git a/drivers/media/video/msm_zsl/csi/Makefile b/drivers/media/video/msm_zsl/csi/Makefile new file mode 100644 index 00000000000..db597cb910b --- /dev/null +++ b/drivers/media/video/msm_zsl/csi/Makefile @@ -0,0 +1,3 @@ +GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) +EXTRA_CFLAGS += -Idrivers/media/video/msm_zsl +obj-$(CONFIG_ARCH_MSM8960) += msm_csiphy.o msm_csid.o msm_ispif.o diff --git a/drivers/media/video/msm_zsl/csi/msm_csid.c b/drivers/media/video/msm_zsl/csi/msm_csid.c new file mode 100644 index 00000000000..bfb7900e66f --- /dev/null +++ b/drivers/media/video/msm_zsl/csi/msm_csid.c @@ -0,0 +1,355 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "msm_csid.h" +#include "msm.h" + +#define V4L2_IDENT_CSID 50002 + +/* MIPI CSID registers */ +#define CSID_HW_VERSION_ADDR 0x0 +#define CSID_CORE_CTRL_ADDR 0x4 +#define CSID_RST_CMD_ADDR 0x8 +#define CSID_CID_LUT_VC_0_ADDR 0xc +#define CSID_CID_LUT_VC_1_ADDR 0x10 +#define CSID_CID_LUT_VC_2_ADDR 0x14 +#define CSID_CID_LUT_VC_3_ADDR 0x18 +#define CSID_CID_n_CFG_ADDR 0x1C +#define CSID_IRQ_CLEAR_CMD_ADDR 0x5c +#define CSID_IRQ_MASK_ADDR 0x60 +#define CSID_IRQ_STATUS_ADDR 0x64 +#define CSID_CAPTURED_UNMAPPED_LONG_PKT_HDR_ADDR 0x68 +#define CSID_CAPTURED_MMAPPED_LONG_PKT_HDR_ADDR 0x6c +#define CSID_CAPTURED_SHORT_PKT_ADDR 0x70 +#define CSID_CAPTURED_LONG_PKT_HDR_ADDR 0x74 +#define CSID_CAPTURED_LONG_PKT_FTR_ADDR 0x78 +#define CSID_PIF_MISR_DL0_ADDR 0x7C +#define CSID_PIF_MISR_DL1_ADDR 0x80 +#define CSID_PIF_MISR_DL2_ADDR 0x84 +#define CSID_PIF_MISR_DL3_ADDR 0x88 +#define CSID_STATS_TOTAL_PKTS_RCVD_ADDR 0x8C +#define CSID_STATS_ECC_ADDR 0x90 +#define CSID_STATS_CRC_ADDR 0x94 +#define CSID_TG_CTRL_ADDR 0x9C +#define CSID_TG_VC_CFG_ADDR 0xA0 +#define CSID_TG_DT_n_CFG_0_ADDR 0xA8 +#define CSID_TG_DT_n_CFG_1_ADDR 0xAC +#define CSID_TG_DT_n_CFG_2_ADDR 0xB0 +#define CSID_TG_DT_n_CFG_3_ADDR 0xD8 + +#define DBG_CSID 0 + +static int msm_csid_cid_lut( + struct msm_camera_csid_lut_params *csid_lut_params, + void __iomem *csidbase) +{ + int rc = 0, i = 0; + uint32_t val = 0; + + for (i = 0; i < csid_lut_params->num_cid && i < 4; i++) { + if (csid_lut_params->vc_cfg[i].dt < 0x12 || + csid_lut_params->vc_cfg[i].dt > 0x37) { + CDBG("%s: unsupported data type 0x%x\n", + __func__, csid_lut_params->vc_cfg[i].dt); + return rc; + } + val = msm_io_r(csidbase + CSID_CID_LUT_VC_0_ADDR + + (csid_lut_params->vc_cfg[i].cid >> 2) * 4) + & ~(0xFF << csid_lut_params->vc_cfg[i].cid * 8); + val |= csid_lut_params->vc_cfg[i].dt << + csid_lut_params->vc_cfg[i].cid * 8; + msm_io_w(val, csidbase + CSID_CID_LUT_VC_0_ADDR + + (csid_lut_params->vc_cfg[i].cid >> 2) * 4); + val = csid_lut_params->vc_cfg[i].decode_format << 4 | 0x3; + msm_io_w(val, csidbase + CSID_CID_n_CFG_ADDR + + (csid_lut_params->vc_cfg[i].cid * 4)); + } + return rc; +} + +static int msm_csid_config(struct csid_cfg_params *cfg_params) +{ + int rc = 0; + uint32_t val = 0; + struct csid_device *csid_dev; + struct msm_camera_csid_params *csid_params; + void __iomem *csidbase; + csid_dev = v4l2_get_subdevdata(cfg_params->subdev); + csidbase = csid_dev->base; + csid_params = cfg_params->parms; + val = csid_params->lane_cnt - 1; + val |= csid_params->lane_assign << 2; + val |= 0x1 << 10; + val |= 0x1 << 11; + val |= 0x1 << 12; + val |= 0x1 << 13; + val |= 0x1 << 28; + msm_io_w(val, csidbase + CSID_CORE_CTRL_ADDR); + + rc = msm_csid_cid_lut(&csid_params->lut_params, csidbase); + if (rc < 0) + return rc; + msm_io_w(0x7fF10800 | 0x100, csidbase + CSID_IRQ_MASK_ADDR); + msm_io_w(0x7fF10800 | 0x100, csidbase + CSID_IRQ_CLEAR_CMD_ADDR); + + msleep(20); + return rc; +} + +#if DBG_CSID +static irqreturn_t msm_csid_irq(int irq_num, void *data) +{ + uint32_t irq; + struct csid_device *csid_dev = data; + irq = msm_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR); + CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n", + __func__, csid_dev->pdev->id, irq); + msm_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR); + + if (irq & 0x100) { + printk(KERN_DEBUG "Long p.c.: %x, short : %x\n", + msm_io_r(csid_dev->base + 0x74), + msm_io_r(csid_dev->base + 0x70)); + msm_io_w(0x19 , csid_dev->base + 0x08); + } + return IRQ_HANDLED; +} +#endif +static int msm_csid_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_CSID; + chip->revision = 0; + return 0; +} + +static struct msm_cam_clk_info csid_clk_info[] = { + {"csi_src_clk", 177780000}, + {"csi_clk", -1}, + {"csi_phy_clk", -1}, + {"csi_pclk", -1}, +}; + +static struct camera_vreg_t csid_vreg_info[] = { + {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000}, +}; + +static int msm_csid_init(struct v4l2_subdev *sd, uint32_t *csid_version) +{ + int rc = 0; + struct csid_device *csid_dev; + csid_dev = v4l2_get_subdevdata(sd); + if (csid_dev == NULL) { + rc = -ENOMEM; + return rc; + } + + csid_dev->base = ioremap(csid_dev->mem->start, + resource_size(csid_dev->mem)); + if (!csid_dev->base) { + rc = -ENOMEM; + return rc; + } + + rc = msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info, + ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1); + if (rc < 0) { + pr_err("%s: regulator on failed\n", __func__); + goto vreg_config_failed; + } + + rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info, + ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1); + if (rc < 0) { + pr_err("%s: regulator enable failed\n", __func__); + goto vreg_enable_failed; + } + + rc = msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, + csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 1); + if (rc < 0) { + pr_err("%s: regulator enable failed\n", __func__); + goto clk_enable_failed; + } + + csid_dev->hw_version = + msm_io_r(csid_dev->base + CSID_HW_VERSION_ADDR); + *csid_version = csid_dev->hw_version; + +#if DBG_CSID + rc = request_irq(csid_dev->irq->start, msm_csid_irq, + IRQF_TRIGGER_RISING, "csid", new_csid_dev); + if (rc < 0) { + msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, + csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0); + iounmap(csid_dev->base); + return rc; + } +#endif + + *csid_version = csid_dev->hw_version; + + return 0; + +clk_enable_failed: + msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info, + ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0); +vreg_enable_failed: + msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info, + ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0); +vreg_config_failed: + iounmap(csid_dev->base); + csid_dev->base = NULL; + return rc; +} + +static int msm_csid_release(struct v4l2_subdev *sd) +{ + struct csid_device *csid_dev; + csid_dev = v4l2_get_subdevdata(sd); + +#if DBG_CSID + free_irq((csid_dev->irq->start, 0); +#endif + + msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, + csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0); + + msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info, + ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0); + + msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info, + ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0); + + iounmap(csid_dev->base); + csid_dev->base = NULL; + return 0; +} + +static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = -ENOIOCTLCMD; + struct csid_cfg_params cfg_params; + struct csid_device *csid_dev = v4l2_get_subdevdata(sd); + mutex_lock(&csid_dev->mutex); + switch (cmd) { + case VIDIOC_MSM_CSID_CFG: + cfg_params.subdev = sd; + cfg_params.parms = arg; + rc = msm_csid_config((struct csid_cfg_params *)&cfg_params); + break; + case VIDIOC_MSM_CSID_INIT: + rc = msm_csid_init(sd, (uint32_t *)arg); + break; + case VIDIOC_MSM_CSID_RELEASE: + rc = msm_csid_release(sd); + break; + default: + pr_err("%s: command not found\n", __func__); + } + mutex_unlock(&csid_dev->mutex); + return rc; +} + +static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = { + .g_chip_ident = &msm_csid_subdev_g_chip_ident, + .ioctl = &msm_csid_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_csid_subdev_ops = { + .core = &msm_csid_subdev_core_ops, +}; + +static int __devinit csid_probe(struct platform_device *pdev) +{ + struct csid_device *new_csid_dev; + int rc = 0; + CDBG("%s: device id = %d\n", __func__, pdev->id); + new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL); + if (!new_csid_dev) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + v4l2_subdev_init(&new_csid_dev->subdev, &msm_csid_subdev_ops); + v4l2_set_subdevdata(&new_csid_dev->subdev, new_csid_dev); + platform_set_drvdata(pdev, &new_csid_dev->subdev); + mutex_init(&new_csid_dev->mutex); + + new_csid_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csid"); + if (!new_csid_dev->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto csid_no_resource; + } + new_csid_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "csid"); + if (!new_csid_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto csid_no_resource; + } + new_csid_dev->io = request_mem_region(new_csid_dev->mem->start, + resource_size(new_csid_dev->mem), pdev->name); + if (!new_csid_dev->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto csid_no_resource; + } + + new_csid_dev->pdev = pdev; + + + return 0; +#if 0 +ioremap_fail: +#endif +csid_no_resource: + release_mem_region(new_csid_dev->mem->start, + resource_size(new_csid_dev->mem)); + mutex_destroy(&new_csid_dev->mutex); + kfree(new_csid_dev); + return 0; +} + +static struct platform_driver csid_driver = { + .probe = csid_probe, + .driver = { + .name = MSM_CSID_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_csid_init_module(void) +{ + return platform_driver_register(&csid_driver); +} + +static void __exit msm_csid_exit_module(void) +{ + platform_driver_unregister(&csid_driver); +} + +module_init(msm_csid_init_module); +module_exit(msm_csid_exit_module); +MODULE_DESCRIPTION("MSM CSID driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/csi/msm_csid.h b/drivers/media/video/msm_zsl/csi/msm_csid.h new file mode 100644 index 00000000000..34c25cbaaf9 --- /dev/null +++ b/drivers/media/video/msm_zsl/csi/msm_csid.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_CSID_H +#define MSM_CSID_H + +#include +#include +#include + +struct csid_device { + struct platform_device *pdev; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *irq; + struct resource *io; + struct regulator *csi_vdd; + void __iomem *base; + struct mutex mutex; + uint32_t hw_version; + + struct clk *csid_clk[5]; +}; + +struct csid_cfg_params { + struct v4l2_subdev *subdev; + void *parms; +}; + +#define VIDIOC_MSM_CSID_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csid_cfg_params) + +#define VIDIOC_MSM_CSID_INIT \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*) + +#define VIDIOC_MSM_CSID_RELEASE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_subdev*) + +#endif diff --git a/drivers/media/video/msm_zsl/csi/msm_csiphy.c b/drivers/media/video/msm_zsl/csi/msm_csiphy.c new file mode 100644 index 00000000000..5d76d06a8d5 --- /dev/null +++ b/drivers/media/video/msm_zsl/csi/msm_csiphy.c @@ -0,0 +1,325 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_csiphy.h" +#include "msm.h" + +#define DBG_CSIPHY 0 + +#define V4L2_IDENT_CSIPHY 50003 + +/*MIPI CSI PHY registers*/ +#define MIPI_CSIPHY_LNn_CFG1_ADDR 0x0 +#define MIPI_CSIPHY_LNn_CFG2_ADDR 0x4 +#define MIPI_CSIPHY_LNn_CFG3_ADDR 0x8 +#define MIPI_CSIPHY_LNn_CFG4_ADDR 0xC +#define MIPI_CSIPHY_LNn_CFG5_ADDR 0x10 +#define MIPI_CSIPHY_LNCK_CFG1_ADDR 0x100 +#define MIPI_CSIPHY_LNCK_CFG2_ADDR 0x104 +#define MIPI_CSIPHY_LNCK_CFG3_ADDR 0x108 +#define MIPI_CSIPHY_LNCK_CFG4_ADDR 0x10C +#define MIPI_CSIPHY_LNCK_CFG5_ADDR 0x110 +#define MIPI_CSIPHY_LNCK_MISC1_ADDR 0x128 +#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR 0x1E0 +#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR 0x1E8 +#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR 0x0144 +#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR 0x0180 +#define MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR 0x0184 +#define MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR 0x0188 +#define MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR 0x018C +#define MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR 0x0190 +#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR 0x01A0 +#define MIPI_CSIPHY_INTERRUPT_MASK1_ADDR 0x01A4 +#define MIPI_CSIPHY_INTERRUPT_MASK2_ADDR 0x01A8 +#define MIPI_CSIPHY_INTERRUPT_MASK3_ADDR 0x01AC +#define MIPI_CSIPHY_INTERRUPT_MASK4_ADDR 0x01B0 +#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR 0x01C0 +#define MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR 0x01C4 +#define MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR 0x01C8 +#define MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR 0x01CC +#define MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR 0x01D0 + +int msm_csiphy_config(struct csiphy_cfg_params *cfg_params) +{ + int rc = 0; + int i = 0; + uint32_t val = 0; + struct csiphy_device *csiphy_dev; + struct msm_camera_csiphy_params *csiphy_params; + void __iomem *csiphybase; + csiphy_dev = v4l2_get_subdevdata(cfg_params->subdev); + csiphybase = csiphy_dev->base; + csiphy_params = cfg_params->parms; + if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) { + CDBG("%s: unsupported lane cnt %d\n", + __func__, csiphy_params->lane_cnt); + return rc; + } + + val = 0x3; + msm_io_w((((1 << csiphy_params->lane_cnt) - 1) << 2) | val, + csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR); + msm_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR); + msm_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR); + + for (i = 0; i < csiphy_params->lane_cnt; i++) { + + msm_io_w(0x10, csiphybase + MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i); + msm_io_w(csiphy_params->settle_cnt, + csiphybase + MIPI_CSIPHY_LNn_CFG3_ADDR + 0x40*i); + msm_io_w(0x00000052, + csiphybase + MIPI_CSIPHY_LNn_CFG5_ADDR + 0x40*i); + } + + msm_io_w(0x10, csiphybase + MIPI_CSIPHY_LNCK_CFG2_ADDR); + msm_io_w(csiphy_params->settle_cnt, + csiphybase + MIPI_CSIPHY_LNCK_CFG3_ADDR); + msm_io_w(0x5, csiphybase + MIPI_CSIPHY_LNCK_CFG4_ADDR); + msm_io_w(0x2, csiphybase + MIPI_CSIPHY_LNCK_CFG5_ADDR); + msm_io_w(0x0, csiphybase + 0x128); + + + /* Enable all CSIPHY logs */ + msm_io_w(0x3F, + csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR); + msm_io_w(0x3F, + csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR); + + for (i = 1; i <= csiphy_params->lane_cnt; i++) { + msm_io_w(0x7F, + csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR + 0x4*i); + msm_io_w(0x7F, + csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i); + } + + return rc; +} +#if DBG_CSIPHY +static irqreturn_t msm_csiphy_irq(int irq_num, void *data) +{ + uint32_t irq; + struct csiphy_device *csiphy_dev = data; + irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR); + msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR); + CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS0 = 0x%x\n", + __func__, csiphy_dev->pdev->id, irq); + irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR); + msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR); + CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS1 = 0x%x\n", + __func__, csiphy_dev->pdev->id, irq); + irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR); + msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR); + CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS2 = 0x%x\n", + __func__, csiphy_dev->pdev->id, irq); + irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR); + msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR); + CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS3 = 0x%x\n", + __func__, csiphy_dev->pdev->id, irq); + irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR); + msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR); + CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS4 = 0x%x\n", + __func__, csiphy_dev->pdev->id, irq); + msm_io_w(0x1, csiphy_dev->base + 0x164); + msm_io_w(0x0, csiphy_dev->base + 0x164); + return IRQ_HANDLED; +} +#endif +static int msm_csiphy_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_CSIPHY; + chip->revision = 0; + return 0; +} + +static struct msm_cam_clk_info csiphy_clk_info[] = { + {"csiphy_timer_src_clk", 177780000}, + {"csiphy_timer_clk", -1}, +}; + +static int msm_csiphy_init(struct v4l2_subdev *sd) +{ + int rc = 0; + struct csiphy_device *csiphy_dev; + csiphy_dev = v4l2_get_subdevdata(sd); + if (csiphy_dev == NULL) { + rc = -ENOMEM; + return rc; + } + + csiphy_dev->base = ioremap(csiphy_dev->mem->start, + resource_size(csiphy_dev->mem)); + if (!csiphy_dev->base) { + rc = -ENOMEM; + return rc; + } + + rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info, + csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 1); + + if (rc < 0) { + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + return rc; + } + +#if DBG_CSIPHY + rc = request_irq(new_csiphy_dev->irq->start, msm_csiphy_irq, + IRQF_TRIGGER_RISING, "csiphy", new_csiphy_dev); + if (rc < 0) { + pr_err("%s: irq request fail\n", __func__); + return -EBUSY; + } +#endif + + return 0; +} + +static int msm_csiphy_release(struct v4l2_subdev *sd) +{ + struct csiphy_device *csiphy_dev; + int i; + csiphy_dev = v4l2_get_subdevdata(sd); + for (i = 0; i < 4; i++) + msm_io_w(0x0, csiphy_dev->base + + MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i); + + msm_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_LNCK_CFG2_ADDR); + msm_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR); + +#if DBG_CSIPHY + free_irq(csiphy_dev->irq->start); +#endif + msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info, + csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 0); + + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + return 0; +} + +static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = -ENOIOCTLCMD; + struct csiphy_cfg_params cfg_params; + struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); + mutex_lock(&csiphy_dev->mutex); + switch (cmd) { + case VIDIOC_MSM_CSIPHY_CFG: + cfg_params.subdev = sd; + cfg_params.parms = arg; + rc = msm_csiphy_config( + (struct csiphy_cfg_params *)&cfg_params); + break; + case VIDIOC_MSM_CSIPHY_INIT: + rc = msm_csiphy_init(sd); + break; + case VIDIOC_MSM_CSIPHY_RELEASE: + rc = msm_csiphy_release(sd); + break; + default: + pr_err("%s: command not found\n", __func__); + } + mutex_unlock(&csiphy_dev->mutex); + return rc; +} + +static struct v4l2_subdev_core_ops msm_csiphy_subdev_core_ops = { + .g_chip_ident = &msm_csiphy_subdev_g_chip_ident, + .ioctl = &msm_csiphy_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_csiphy_subdev_ops = { + .core = &msm_csiphy_subdev_core_ops, +}; + +static int __devinit csiphy_probe(struct platform_device *pdev) +{ + struct csiphy_device *new_csiphy_dev; + int rc = 0; + CDBG("%s: device id = %d\n", __func__, pdev->id); + new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL); + if (!new_csiphy_dev) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + v4l2_subdev_init(&new_csiphy_dev->subdev, &msm_csiphy_subdev_ops); + v4l2_set_subdevdata(&new_csiphy_dev->subdev, new_csiphy_dev); + platform_set_drvdata(pdev, &new_csiphy_dev->subdev); + + mutex_init(&new_csiphy_dev->mutex); + + new_csiphy_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csiphy"); + if (!new_csiphy_dev->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto csiphy_no_resource; + } + new_csiphy_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "csiphy"); + if (!new_csiphy_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto csiphy_no_resource; + } + new_csiphy_dev->io = request_mem_region(new_csiphy_dev->mem->start, + resource_size(new_csiphy_dev->mem), pdev->name); + if (!new_csiphy_dev->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto csiphy_no_resource; + } + + + new_csiphy_dev->pdev = pdev; + return 0; + +csiphy_no_resource: + mutex_destroy(&new_csiphy_dev->mutex); + kfree(new_csiphy_dev); + return 0; +} + +static struct platform_driver csiphy_driver = { + .probe = csiphy_probe, + .driver = { + .name = MSM_CSIPHY_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_csiphy_init_module(void) +{ + return platform_driver_register(&csiphy_driver); +} + +static void __exit msm_csiphy_exit_module(void) +{ + platform_driver_unregister(&csiphy_driver); +} + +module_init(msm_csiphy_init_module); +module_exit(msm_csiphy_exit_module); +MODULE_DESCRIPTION("MSM CSIPHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/csi/msm_csiphy.h b/drivers/media/video/msm_zsl/csi/msm_csiphy.h new file mode 100644 index 00000000000..522a1c15d38 --- /dev/null +++ b/drivers/media/video/msm_zsl/csi/msm_csiphy.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_CSIPHY_H +#define MSM_CSIPHY_H + +#include +#include +#include + +struct csiphy_device { + struct platform_device *pdev; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *irq; + struct resource *io; + void __iomem *base; + struct mutex mutex; + + struct clk *csiphy_clk[2]; +}; + +struct csiphy_cfg_params { + struct v4l2_subdev *subdev; + void *parms; +}; + +#define VIDIOC_MSM_CSIPHY_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct csiphy_cfg_params) + +#define VIDIOC_MSM_CSIPHY_INIT \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct v4l2_subdev*) + +#define VIDIOC_MSM_CSIPHY_RELEASE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct v4l2_subdev*) + +#endif diff --git a/drivers/media/video/msm_zsl/csi/msm_ispif.c b/drivers/media/video/msm_zsl/csi/msm_ispif.c new file mode 100644 index 00000000000..44185d04cb4 --- /dev/null +++ b/drivers/media/video/msm_zsl/csi/msm_ispif.c @@ -0,0 +1,968 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +/*[[ aswoogi_zsl*/ +#include +#include +/*]]*/ +#include +#include +#include "msm_ispif.h" +#include "msm.h" + +#define QC_TEST +#define V4L2_IDENT_ISPIF 50001 +#define CSID_VERSION_V2 0x2000011 + +/* ISPIF registers */ + +#define ISPIF_RST_CMD_ADDR 0X00 +#define ISPIF_INTF_CMD_ADDR 0X04 +#define ISPIF_CTRL_ADDR 0X08 +#define ISPIF_INPUT_SEL_ADDR 0X0C +#define ISPIF_PIX_INTF_CID_MASK_ADDR 0X10 +#define ISPIF_RDI_INTF_CID_MASK_ADDR 0X14 +#define ISPIF_PIX_1_INTF_CID_MASK_ADDR 0X38 +#define ISPIF_RDI_1_INTF_CID_MASK_ADDR 0X3C +#define ISPIF_PIX_STATUS_ADDR 0X24 +#define ISPIF_RDI_STATUS_ADDR 0X28 +#define ISPIF_RDI_1_STATUS_ADDR 0X64 +#define ISPIF_IRQ_MASK_ADDR 0X0100 +#define ISPIF_IRQ_CLEAR_ADDR 0X0104 +#define ISPIF_IRQ_STATUS_ADDR 0X0108 +#define ISPIF_IRQ_MASK_1_ADDR 0X010C +#define ISPIF_IRQ_CLEAR_1_ADDR 0X0110 +#define ISPIF_IRQ_STATUS_1_ADDR 0X0114 +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x0124 + +/*ISPIF RESET BITS*/ + +#define VFE_CLK_DOMAIN_RST 31 +#define RDI_CLK_DOMAIN_RST 30 +#define PIX_CLK_DOMAIN_RST 29 +#define AHB_CLK_DOMAIN_RST 28 +#define RDI_1_CLK_DOMAIN_RST 27 +#define RDI_1_VFE_RST_STB 13 +#define RDI_1_CSID_RST_STB 12 +#define RDI_VFE_RST_STB 7 +#define RDI_CSID_RST_STB 6 +#define PIX_VFE_RST_STB 4 +#define PIX_CSID_RST_STB 3 +#define SW_REG_RST_STB 2 +#define MISC_LOGIC_RST_STB 1 +#define STROBED_RST_EN 0 + +#define PIX_INTF_0_OVERFLOW_IRQ 12 +#define RAW_INTF_0_OVERFLOW_IRQ 25 +#define RAW_INTF_1_OVERFLOW_IRQ 25 +#define RESET_DONE_IRQ 27 + +#ifdef QC_TEST /*aswoogi_zsl */ +#define ISPIF_IRQ_STATUS_MASK 0xA497000 +#else +#define ISPIF_IRQ_STATUS_MASK 0xA493000 +#endif +#define ISPIF_IRQ_1_STATUS_MASK 0xA493000 +#define ISPIF_IRQ_STATUS_RDI_SOF_MASK 0x492000 +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1 + +#define MAX_CID 15 + +static struct ispif_device *ispif; + +static uint32_t global_intf_cmd_mask = 0xFFFFFFFF; + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_intf_reset(uint8_t intfmask) +{ + int rc = 0; + uint32_t data = 0x1; + uint8_t intfnum = 0, mask = intfmask; + while (mask != 0) { /*nsync */ + if (!(intfmask & (0x1 << intfnum))) { + mask >>= 1; + intfnum++; + continue; + } + switch (intfnum) { + case PIX0: + data = (0x1 << STROBED_RST_EN) + + (0x1 << PIX_VFE_RST_STB) + + (0x1 << PIX_CSID_RST_STB); + /*msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); */ + break; + + case RDI0: + data = (0x1 << STROBED_RST_EN) + + (0x1 << RDI_VFE_RST_STB) + + (0x1 << RDI_CSID_RST_STB); + /*msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); */ + break; + + case RDI1: + data = (0x1 << STROBED_RST_EN) + + (0x1 << RDI_1_VFE_RST_STB) + + (0x1 << RDI_1_CSID_RST_STB); + /*msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); */ + break; + + default: + rc = -EINVAL; + break; + } + mask >>= 1; + intfnum++; + } /*end while */ + if (rc >= 0) { + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + rc = wait_for_completion_interruptible(&ispif->reset_complete); + } + return rc; +} +#else +static int msm_ispif_intf_reset(uint8_t intftype) +{ + int rc = 0; + uint32_t data; + + switch (intftype) { + case PIX0: + data = (0x1 << STROBED_RST_EN) + + (0x1 << PIX_VFE_RST_STB) + (0x1 << PIX_CSID_RST_STB); + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + break; + + case RDI0: + data = (0x1 << STROBED_RST_EN) + + (0x1 << RDI_VFE_RST_STB) + (0x1 << RDI_CSID_RST_STB); + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + break; + + case RDI1: + data = (0x1 << STROBED_RST_EN) + + (0x1 << RDI_1_VFE_RST_STB) + (0x1 << RDI_1_CSID_RST_STB); + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + break; + + default: + rc = -EINVAL; + break; + } + if (rc >= 0) + rc = wait_for_completion_interruptible(&ispif->reset_complete); + + return rc; +} +#endif + +static int msm_ispif_reset(void) +{ + uint32_t data = (0x1 << STROBED_RST_EN) + + (0x1 << SW_REG_RST_STB) + + (0x1 << MISC_LOGIC_RST_STB) + + (0x1 << PIX_VFE_RST_STB) + + (0x1 << PIX_CSID_RST_STB) + + (0x1 << RDI_VFE_RST_STB) + + (0x1 << RDI_CSID_RST_STB) + + (0x1 << RDI_1_VFE_RST_STB) + (0x1 << RDI_1_CSID_RST_STB); + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + return wait_for_completion_interruptible(&ispif->reset_complete); +} + +static int msm_ispif_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_ISPIF; + chip->revision = 0; + return 0; +} + +static void msm_ispif_sel_csid_core(uint8_t intftype, uint8_t csid) +{ + int rc = 0; + uint32_t data; + if (ispif->ispif_clk[intftype] == NULL) { + pr_err("%s: ispif NULL clk\n", __func__); + return; + } + + rc = clk_set_rate(ispif->ispif_clk[intftype], csid); + if (rc < 0) + pr_err("%s: clk_set_rate failed %d\n", __func__, rc); + + data = msm_io_r(ispif->base + ISPIF_INPUT_SEL_ADDR); + data |= csid << (intftype * 4); + msm_io_w(data, ispif->base + ISPIF_INPUT_SEL_ADDR); +} + +static void msm_ispif_enable_intf_cids(uint8_t intftype, uint16_t cid_mask) +{ + uint32_t data; + mutex_lock(&ispif->mutex); + switch (intftype) { + case PIX0: + data = msm_io_r(ispif->base + ISPIF_PIX_INTF_CID_MASK_ADDR); + data |= cid_mask; + msm_io_w(data, ispif->base + ISPIF_PIX_INTF_CID_MASK_ADDR); + break; + + case RDI0: + data = msm_io_r(ispif->base + ISPIF_RDI_INTF_CID_MASK_ADDR); + data |= cid_mask; + msm_io_w(data, ispif->base + ISPIF_RDI_INTF_CID_MASK_ADDR); + break; + + case RDI1: + data = msm_io_r(ispif->base + ISPIF_RDI_1_INTF_CID_MASK_ADDR); + data |= cid_mask; + msm_io_w(data, ispif->base + ISPIF_RDI_1_INTF_CID_MASK_ADDR); + break; + } + mutex_unlock(&ispif->mutex); +} + +static int msm_ispif_config(struct msm_ispif_params_list *params_list) +{ + uint32_t params_len; + struct msm_ispif_params *ispif_params; + uint32_t data, data1; + int rc = 0, i = 0; + params_len = params_list->len; + ispif_params = params_list->params; + CDBG("Enable interface\n"); + data = msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR); + data1 = msm_io_r(ispif->base + ISPIF_RDI_STATUS_ADDR); + if (((data & 0xf) != 0xf) || ((data1 & 0xf) != 0xf)) + return -EBUSY; + msm_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_ADDR); + for (i = 0; i < params_len; i++) { + msm_ispif_sel_csid_core(ispif_params[i].intftype, + ispif_params[i].csid); + msm_ispif_enable_intf_cids(ispif_params[i].intftype, + ispif_params[i].cid_mask); + } + + msm_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + ISPIF_IRQ_MASK_ADDR); + msm_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + ISPIF_IRQ_CLEAR_ADDR); + msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + /* test: Qualcomm */ +#ifndef QC_TEST /*aswoogi_zsl*/ + CDBG("Dumping ISPIF registers\n"); +/* + msm_io_w(ISPIF_IRQ_STATUS_MASK | 0x18, ispif->base + + ISPIF_IRQ_MASK_ADDR); + msm_io_w(ISPIF_IRQ_STATUS_MASK | 0x18, ispif->base + + ISPIF_IRQ_CLEAR_ADDR); + msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); +*/ + msm_io_dump(ispif->base, 500); + CDBG("Hardcoding some other ISPIF registers\n"); + /*msm_io_w(0x00000000, ispif->base + 0x0004);*/ + msm_io_w(0x0001, ispif->base + 0x0010); + /* msm_io_w(0x0004, ispif->base + 0x0014); */ + +#endif + + return rc; +} + +static uint32_t msm_ispif_get_cid_mask(uint8_t intftype) +{ + uint32_t mask = 0; + switch (intftype) { + case PIX0: + mask = msm_io_r(ispif->base + ISPIF_PIX_INTF_CID_MASK_ADDR); + break; + + case RDI0: + mask = msm_io_r(ispif->base + ISPIF_RDI_INTF_CID_MASK_ADDR); + break; + + case RDI1: + mask = msm_io_r(ispif->base + ISPIF_RDI_1_INTF_CID_MASK_ADDR); + break; + + default: + break; + } + return mask; +} + +#ifdef QC_TEST /*aswoogi_zsl */ +static void msm_ispif_intf_cmd(uint8_t intfmask, uint8_t intf_cmd_mask) +{ + uint8_t vc = 0, val = 0; + uint8_t mask = intfmask, intfnum = 0; + uint32_t cid_mask = 0; + while (mask != 0) { + if (!(intfmask & (0x1 << intfnum))) { /*nsync */ + mask >>= 1; + intfnum++; + continue; + } + + cid_mask = msm_ispif_get_cid_mask(intfnum); + vc = 0; + + while (cid_mask != 0) { + if ((cid_mask & 0xf) != 0x0) { + val = (intf_cmd_mask >> (vc * 2)) & 0x3; + global_intf_cmd_mask |= + (0x3 << ((vc * 2) + (intfnum * 8))); + global_intf_cmd_mask &= ~((0x3 & ~val) + << ((vc * 2) + + (intfnum * 8))); + CDBG("nishu intf cmd 0x%x\n", + global_intf_cmd_mask); + } + vc++; + cid_mask >>= 4; + } + mask >>= 1; + intfnum++; + } + msm_io_w(global_intf_cmd_mask, ispif->base + ISPIF_INTF_CMD_ADDR); +} +#else +static void msm_ispif_intf_cmd(uint8_t intftype, uint8_t intf_cmd_mask) +{ + uint8_t vc = 0, val = 0; + uint32_t cid_mask = msm_ispif_get_cid_mask(intftype); + + while (cid_mask != 0) { + if ((cid_mask & 0xf) != 0x0) { + val = (intf_cmd_mask >> (vc * 2)) & 0x3; + global_intf_cmd_mask &= ~((0x3 & ~val) + << ((vc * 2) + + (intftype * 8))); + CDBG("intf cmd 0x%x\n", global_intf_cmd_mask); + msm_io_w(global_intf_cmd_mask, + ispif->base + ISPIF_INTF_CMD_ADDR); + } + vc++; + cid_mask >>= 4; + } +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_abort_intf_transfer(uint8_t intfmask) +{ + int rc = 0; + uint8_t intf_cmd_mask = 0xAA; + uint8_t intfnum = 0, mask = intfmask; + + pr_info("abort stream request %d\n", intfmask); + /*mutex_lock(&ispif->mutex); */ + msm_ispif_intf_cmd(intfmask, intf_cmd_mask); + /*rc = msm_ispif_intf_reset(intf); */ + while (mask != 0) { + if (mask & (0x1 << intfnum)) + global_intf_cmd_mask |= 0xFF << (intfnum * 8); + mask >>= 1; + intfnum++; + } + /*mutex_unlock(&ispif->mutex); */ + return rc; +} +#else +static int msm_ispif_abort_intf_transfer(uint8_t intf) +{ + int rc = 0; + uint8_t intf_cmd_mask = 0xAA; + + CDBG("abort stream request\n"); + mutex_lock(&ispif->mutex); + msm_ispif_intf_cmd(intf, intf_cmd_mask); + rc = msm_ispif_intf_reset(intf); + global_intf_cmd_mask |= 0xFF << (intf * 8); + mutex_unlock(&ispif->mutex); + return rc; +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_start_intf_transfer(uint8_t intfmask) +{ + uint8_t intf_cmd_mask = 0x55; + int rc = 0; + + CDBG("start stream request %d\n", intfmask); + mutex_lock(&ispif->mutex); + rc = msm_ispif_intf_reset(intfmask); /*nishu */ + /*switch (intfmask) {//nsync + case PIX0: + data = msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR); + break; + + case RDI0: + data = msm_io_r(ispif->base + ISPIF_RDI_STATUS_ADDR); + ispif->start_ack_pending = 1; + break; + + case RDI1: + data = msm_io_r(ispif->base + ISPIF_RDI_1_STATUS_ADDR); + ispif->start_ack_pending = 1; + break; + } */ + msm_ispif_intf_cmd(intfmask, intf_cmd_mask); + if (intfmask & 0xb) { + CDBG("pix 0-rdi0-rdi1 interface\n"); + msm_io_dump1(ispif->base, 0x150); + } + mutex_unlock(&ispif->mutex); + return rc; +} +#else +static int msm_ispif_start_intf_transfer(uint8_t intf) +{ + uint32_t data; + uint8_t intf_cmd_mask = 0x55; + int rc = 0; + + CDBG("start stream request\n"); + mutex_lock(&ispif->mutex); + switch (intf) { + case PIX0: + data = msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR); + if ((data & 0xf) != 0xf) { + CDBG("interface is busy\n"); + mutex_unlock(&ispif->mutex); + return -EBUSY; + } + break; + + case RDI0: + data = msm_io_r(ispif->base + ISPIF_RDI_STATUS_ADDR); + ispif->start_ack_pending = 1; + break; + + case RDI1: + data = msm_io_r(ispif->base + ISPIF_RDI_1_STATUS_ADDR); + ispif->start_ack_pending = 1; + break; + } + msm_ispif_intf_cmd(intf, intf_cmd_mask); + mutex_unlock(&ispif->mutex); + return rc; +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_stop_intf_transfer(uint8_t intfmask) +{ + int rc = 0; + uint8_t intf_cmd_mask = 0x00; + uint8_t intfnum = 0, mask = intfmask; + CDBG("stop stream request %d\n", intfmask); + /*mutex_lock(&ispif->mutex); */ /*nishu*/ + msm_ispif_intf_cmd(intfmask, intf_cmd_mask); + switch (intfnum) { /*nsync change later*/ + case PIX0: +/* while ((msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR) //nsync + & 0xf) != 0xf) { + CDBG("Wait for Idle\n"); + } + break; +*/ + case RDI0: + case RDI1: + break; + default: + break; + } + while (mask != 0) { /*nsyncs */ + if (mask & (0x1 << intfnum)) + global_intf_cmd_mask |= 0xFF << (intfnum * 8); + mask >>= 1; + intfnum++; + } + /*mutex_unlock(&ispif->mutex); */ + return rc; +} +#else +static int msm_ispif_stop_intf_transfer(uint8_t intf) +{ + int rc = 0; + uint8_t intf_cmd_mask = 0x00; + CDBG("stop stream request\n"); + mutex_lock(&ispif->mutex); + msm_ispif_intf_cmd(intf, intf_cmd_mask); + switch (intf) { + case PIX0: + while ((msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR) + & 0xf) != 0xf) { + CDBG("Wait for Idle\n"); + } + break; + + case RDI0: + while ((msm_io_r(ispif->base + ISPIF_RDI_STATUS_ADDR) + & 0xf) != 0xf) { + CDBG("Wait for Idle\n"); + } + break; + default: + break; + } + global_intf_cmd_mask |= 0xFF << (intf * 8); + mutex_unlock(&ispif->mutex); + return rc; +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_subdev_video_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + int32_t cmd = enable & ((1 << ISPIF_S_STREAM_SHIFT) - 1); + uint8_t intfmask = enable >> ISPIF_S_STREAM_SHIFT; + int rc = -EINVAL; + + BUG_ON(!ispif); + switch (cmd) { + case ISPIF_ON_FRAME_BOUNDARY: + +/*Qualcomm: Front camera hack*/ + intfmask = 11; + rc = msm_ispif_start_intf_transfer(intfmask); + break; + case ISPIF_OFF_FRAME_BOUNDARY: + rc = msm_ispif_stop_intf_transfer(intfmask); + break; + case ISPIF_OFF_IMMEDIATELY: + rc = msm_ispif_abort_intf_transfer(intfmask); + break; + default: + break; + } + return rc; +} +#else +static int msm_ispif_subdev_video_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + int32_t cmd = enable & ((1 << ISPIF_S_STREAM_SHIFT) - 1); + enum msm_ispif_intftype intf = enable >> ISPIF_S_STREAM_SHIFT; + int rc = -EINVAL; + + BUG_ON(!ispif); + switch (cmd) { + case ISPIF_ON_FRAME_BOUNDARY: + rc = msm_ispif_start_intf_transfer(intf); + break; + case ISPIF_OFF_FRAME_BOUNDARY: + rc = msm_ispif_stop_intf_transfer(intf); + break; + case ISPIF_OFF_IMMEDIATELY: + rc = msm_ispif_abort_intf_transfer(intf); + break; + default: + break; + } + return rc; +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +atomic_t ispif_irq_cnt; +spinlock_t ispif_tasklet_lock; +struct list_head ispif_tasklet_q; + +struct ispif_isr_queue_cmd { + struct list_head list; + uint32_t ispifInterruptStatus0; + uint32_t ispifInterruptStatus1; +}; + +static void ispif_do_tasklet(unsigned long data) +{ + unsigned long flags; + + struct ispif_isr_queue_cmd *qcmd = NULL; + + CDBG("=== ispif_do_tasklet start ===\n"); + + while (atomic_read(&ispif_irq_cnt)) { + spin_lock_irqsave(&ispif_tasklet_lock, flags); + qcmd = list_first_entry(&ispif_tasklet_q, + struct ispif_isr_queue_cmd, list); + atomic_sub(1, &ispif_irq_cnt); + + if (!qcmd) { + spin_unlock_irqrestore(&ispif_tasklet_lock, flags); + return; + } + + list_del(&qcmd->list); + spin_unlock_irqrestore(&ispif_tasklet_lock, flags); + + if (qcmd->ispifInterruptStatus0 & + ISPIF_IRQ_STATUS_RDI_SOF_MASK) { + CDBG("ispif rdi irq status %x\n", + qcmd->ispifInterruptStatus0); + vfe32_process_ispif_sof_irq(RDI_0); + } + if (qcmd->ispifInterruptStatus1 & + ISPIF_IRQ_STATUS_RDI_SOF_MASK) { + vfe32_process_ispif_sof_irq(RDI_1); + CDBG("ispif rdi1 irq status %x\n", + qcmd->ispifInterruptStatus1); + } + + kfree(qcmd); + } + CDBG("=== ispif_do_tasklet end ===\n"); +} + +DECLARE_TASKLET(ispif_tasklet, ispif_do_tasklet, 0); + +static void ispif_process_irq(struct ispif_irq_status *out) +{ + unsigned long flags; + struct ispif_isr_queue_cmd *qcmd; + + CDBG("ispif_process_irq\n"); + + qcmd = kzalloc(sizeof(struct ispif_isr_queue_cmd), GFP_ATOMIC); + if (!qcmd) { + pr_err("ispif_process_irq: qcmd malloc failed!\n"); + return; + } + qcmd->ispifInterruptStatus0 = out->ispifIrqStatus0; + qcmd->ispifInterruptStatus1 = out->ispifIrqStatus1; + + spin_lock_irqsave(&ispif_tasklet_lock, flags); + list_add_tail(&qcmd->list, &ispif_tasklet_q); + + atomic_add(1, &ispif_irq_cnt); + spin_unlock_irqrestore(&ispif_tasklet_lock, flags); + tasklet_schedule(&ispif_tasklet); + return; +} +#endif + +#ifdef QC_TEST +static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out) +{ + out->ispifIrqStatus0 = msm_io_r(ispif->base + ISPIF_IRQ_STATUS_ADDR); + out->ispifIrqStatus1 = msm_io_r(ispif->base + ISPIF_IRQ_STATUS_1_ADDR); + CDBG("nishu ispif->irq: Irq_status0 = 0x%x\n", + out->ispifIrqStatus0);/*nishu */ + msm_io_w(out->ispifIrqStatus0, ispif->base + ISPIF_IRQ_CLEAR_ADDR); + msm_io_w(out->ispifIrqStatus1, ispif->base + ISPIF_IRQ_CLEAR_1_ADDR); + + if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) { + if (out->ispifIrqStatus0 & (0x1 << RESET_DONE_IRQ)) + complete(&ispif->reset_complete); + if (out->ispifIrqStatus0 & (0x1 << PIX_INTF_0_OVERFLOW_IRQ)) + pr_err("%s: pix intf 0 overflow.\n", __func__); + if (out->ispifIrqStatus0 & (0x1 << RAW_INTF_0_OVERFLOW_IRQ)) + pr_err("%s: rdi intf 0 overflow.\n", __func__); + if ((out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_RDI_SOF_MASK) || + (out->ispifIrqStatus1 & ISPIF_IRQ_STATUS_RDI_SOF_MASK)) { + ispif_process_irq(out); + } + } + if (out->ispifIrqStatus1 & (0x1 << RAW_INTF_0_OVERFLOW_IRQ)) + pr_err("%s: RDI intf 1 overflow.\n", __func__); + /*msm_io_w(out->ispifIrqStatus0,nishu */ + /*ispif->base + ISPIF_IRQ_CLEAR_ADDR); */ + msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); +} +#else +static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out) +{ + out->ispifIrqStatus0 = msm_io_r(ispif->base + ISPIF_IRQ_STATUS_ADDR); + CDBG("ispif->irq: Irq_status0 = 0x%x\n", out->ispifIrqStatus0); + if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) { + if (out->ispifIrqStatus0 & (0x1 << RESET_DONE_IRQ)) + complete(&ispif->reset_complete); + if (out->ispifIrqStatus0 & (0x1 << PIX_INTF_0_OVERFLOW_IRQ)) + pr_err("%s: pix intf 0 overflow.\n", __func__); + if (out->ispifIrqStatus0 & (0x1 << RAW_INTF_0_OVERFLOW_IRQ)) + pr_err("%s: rdi intf 0 overflow.\n", __func__); + if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_RDI_SOF_MASK) { + if (ispif->start_ack_pending) { + v4l2_subdev_notify(&ispif->subdev, + NOTIFY_ISP_MSG_EVT, + (void *)MSG_ID_START_ACK); + ispif->start_ack_pending = 0; + /* stop stream at frame boundary */ + msm_ispif_stop_intf_transfer(RDI0); + } + v4l2_subdev_notify(&ispif->subdev, NOTIFY_ISP_MSG_EVT, + (void *)MSG_ID_SOF_ACK); + } + } + msm_io_w(out->ispifIrqStatus0, ispif->base + ISPIF_IRQ_CLEAR_ADDR); + msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); +} +#endif + +static irqreturn_t msm_io_ispif_irq(int irq_num, void *data) +{ + struct ispif_irq_status irq; + msm_ispif_read_irq_status(&irq); + return IRQ_HANDLED; +} + +static struct msm_cam_clk_info ispif_clk_info[] = { + {"csi_pix_clk", 0}, + {"csi_rdi_clk", 0}, + {"csi_pix1_clk", 0}, + {"csi_rdi1_clk", 0}, + {"csi_rdi2_clk", 0}, +}; + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_init(const uint32_t *csid_version) +{ + int rc = 0; + spin_lock_init(&ispif_tasklet_lock); /*nishu */ + INIT_LIST_HEAD(&ispif_tasklet_q); + rc = request_irq(ispif->irq->start, msm_io_ispif_irq, + IRQF_TRIGGER_RISING, "ispif", 0); + + global_intf_cmd_mask = 0xFFFFFFFF; + init_completion(&ispif->reset_complete); + + ispif->csid_version = *csid_version; + if (ispif->csid_version == CSID_VERSION_V2) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, + ARRAY_SIZE(ispif_clk_info), 1); + if (rc < 0) + return rc; + } else { + rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, 2, 1); + if (rc < 0) + return rc; + } + + rc = msm_ispif_reset(); + return rc; +} + +static void msm_ispif_release(struct v4l2_subdev *sd) +{ + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + + if (ispif->csid_version == CSID_VERSION_V2) + msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, ARRAY_SIZE(ispif_clk_info), + 0); + else + msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, 2, 0); + + CDBG("%s, free_irq\n", __func__); + free_irq(ispif->irq->start, 0); + tasklet_kill(&ispif_tasklet); /*nishu */ +} +#else +static int msm_ispif_init(const uint32_t *csid_version) +{ + int rc = 0; + rc = request_irq(ispif->irq->start, msm_io_ispif_irq, + IRQF_TRIGGER_RISING, "ispif", 0); + + global_intf_cmd_mask = 0xFFFFFFFF; + init_completion(&ispif->reset_complete); + + ispif->csid_version = *csid_version; + if (ispif->csid_version == CSID_VERSION_V2) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, + ARRAY_SIZE(ispif_clk_info), 1); + if (rc < 0) + return rc; + } else { + rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, 2, 1); + if (rc < 0) + return rc; + } + + rc = msm_ispif_reset(); + return rc; +} + +static void msm_ispif_release(struct v4l2_subdev *sd) +{ + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + + CDBG("%s, free_irq\n", __func__); + free_irq(ispif->irq->start, 0); + tasklet_kill(&ispif_tasklet); + + if (ispif->csid_version == CSID_VERSION_V2) + msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, ARRAY_SIZE(ispif_clk_info), + 0); + else + msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, 2, 0); +} +#endif + +void msm_ispif_vfe_get_cid(uint8_t intftype, char *cids, int *num) +{ + uint32_t data = 0; + int i = 0, j = 0; + switch (intftype) { + case PIX0: + data = msm_io_r(ispif->base + ISPIF_PIX_INTF_CID_MASK_ADDR); + break; + + case RDI0: + data = msm_io_r(ispif->base + ISPIF_RDI_INTF_CID_MASK_ADDR); + break; + + case RDI1: + data = msm_io_r(ispif->base + ISPIF_RDI_1_INTF_CID_MASK_ADDR); + break; + + default: + break; + } + for (i = 0; i <= MAX_CID; i++) { + if ((data & 0x1) == 0x1) { + cids[j++] = i; + (*num)++; + } + data >>= 1; + } +} + +static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, + void *arg) +{ + switch (cmd) { + case VIDIOC_MSM_ISPIF_CFG: + return msm_ispif_config((struct msm_ispif_params_list *)arg); + case VIDIOC_MSM_ISPIF_INIT: + return msm_ispif_init((uint32_t *) arg); + case VIDIOC_MSM_ISPIF_RELEASE: + msm_ispif_release(sd); + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct v4l2_subdev_core_ops msm_ispif_subdev_core_ops = { + .g_chip_ident = &msm_ispif_subdev_g_chip_ident, + .ioctl = &msm_ispif_subdev_ioctl, +}; + +static struct v4l2_subdev_video_ops msm_ispif_subdev_video_ops = { + .s_stream = &msm_ispif_subdev_video_s_stream, +}; + +static const struct v4l2_subdev_ops msm_ispif_subdev_ops = { + .core = &msm_ispif_subdev_core_ops, + .video = &msm_ispif_subdev_video_ops, +}; + +static int __devinit ispif_probe(struct platform_device *pdev) +{ + int rc = 0; + CDBG("%s\n", __func__); + ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL); + if (!ispif) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + v4l2_subdev_init(&ispif->subdev, &msm_ispif_subdev_ops); + v4l2_set_subdevdata(&ispif->subdev, ispif); + platform_set_drvdata(pdev, &ispif->subdev); + snprintf(ispif->subdev.name, sizeof(ispif->subdev.name), "ispif"); + mutex_init(&ispif->mutex); + + ispif->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "ispif"); + if (!ispif->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto ispif_no_resource; + } + ispif->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "ispif"); + if (!ispif->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto ispif_no_resource; + } + ispif->io = request_mem_region(ispif->mem->start, + resource_size(ispif->mem), pdev->name); + if (!ispif->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto ispif_no_resource; + } + ispif->base = ioremap(ispif->mem->start, resource_size(ispif->mem)); + if (!ispif->base) { + rc = -ENOMEM; + goto ispif_no_mem; + } + + ispif->pdev = pdev; + return 0; + +ispif_no_mem: + release_mem_region(ispif->mem->start, resource_size(ispif->mem)); +ispif_no_resource: + mutex_destroy(&ispif->mutex); + kfree(ispif); + return rc; +} + +static struct platform_driver ispif_driver = { + .probe = ispif_probe, + .driver = { + .name = MSM_ISPIF_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_ispif_init_module(void) +{ + return platform_driver_register(&ispif_driver); +} + +static void __exit msm_ispif_exit_module(void) +{ + platform_driver_unregister(&ispif_driver); +} + +module_init(msm_ispif_init_module); +module_exit(msm_ispif_exit_module); +MODULE_DESCRIPTION("MSM ISP Interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/csi/msm_ispif.h b/drivers/media/video/msm_zsl/csi/msm_ispif.h new file mode 100644 index 00000000000..2aff9fa54ed --- /dev/null +++ b/drivers/media/video/msm_zsl/csi/msm_ispif.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_ISPIF_H +#define MSM_ISPIF_H + +#include +#include +#include + +struct ispif_irq_status { + uint32_t ispifIrqStatus0; + uint32_t ispifIrqStatus1; +}; + +struct ispif_device { + struct platform_device *pdev; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *irq; + struct resource *io; + void __iomem *base; + struct mutex mutex; + uint8_t start_ack_pending; + struct completion reset_complete; + uint32_t csid_version; + struct clk *ispif_clk[5]; +}; + +#define VIDIOC_MSM_ISPIF_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_ispif_params) + +#define VIDIOC_MSM_ISPIF_INIT \ + _IO('V', BASE_VIDIOC_PRIVATE + 2) + +#define VIDIOC_MSM_ISPIF_RELEASE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct v4l2_subdev*) + +#define ISPIF_STREAM(intf, action) (((intf)< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct i2c_client *sx150x_client; +struct timer_list timer_flash; +static struct msm_camera_sensor_info *sensor_data; +enum msm_cam_flash_stat{ + MSM_CAM_FLASH_OFF, + MSM_CAM_FLASH_ON, +}; + +#if defined CONFIG_MSM_CAMERA_FLASH_SC628A +static struct i2c_client *sc628a_client; + +static const struct i2c_device_id sc628a_i2c_id[] = { + {"sc628a", 0}, + { } +}; + +static int32_t sc628a_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(sc628a_client->adapter, msg, 1) < 0) { + CDBG("sc628a_i2c_txdata faild 0x%x\n", saddr); + return -EIO; + } + + return 0; +} + +static int32_t sc628a_i2c_write_b_flash(uint8_t waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[2]; + if (!sc628a_client) + return -ENOTSUPP; + + memset(buf, 0, sizeof(buf)); + buf[0] = waddr; + buf[1] = bdata; + + rc = sc628a_i2c_txdata(sc628a_client->addr>>1, buf, 2); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + usleep_range(4000, 5000); + + return rc; +} + +static int sc628a_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("sc628a_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("i2c_check_functionality failed\n"); + goto probe_failure; + } + + sc628a_client = client; + + CDBG("sc628a_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + pr_err("sc628a_probe failed! rc = %d\n", rc); + return rc; +} + +static struct i2c_driver sc628a_i2c_driver = { + .id_table = sc628a_i2c_id, + .probe = sc628a_i2c_probe, + .remove = __exit_p(sc628a_i2c_remove), + .driver = { + .name = "sc628a", + }, +}; +#endif + +static int config_flash_gpio_table(enum msm_cam_flash_stat stat, + struct msm_camera_sensor_strobe_flash_data *sfdata) +{ + int rc = 0, i = 0; + int msm_cam_flash_gpio_tbl[][2] = { + {sfdata->flash_trigger, 1}, + {sfdata->flash_charge, 1}, + {sfdata->flash_charge_done, 0} + }; + + if (stat == MSM_CAM_FLASH_ON) { + for (i = 0; i < ARRAY_SIZE(msm_cam_flash_gpio_tbl); i++) { + rc = gpio_request(msm_cam_flash_gpio_tbl[i][0], + "CAM_FLASH_GPIO"); + if (unlikely(rc < 0)) { + pr_err("%s not able to get gpio\n", __func__); + for (i--; i >= 0; i--) + gpio_free(msm_cam_flash_gpio_tbl[i][0]); + break; + } + if (msm_cam_flash_gpio_tbl[i][1]) + gpio_direction_output( + msm_cam_flash_gpio_tbl[i][0], 0); + else + gpio_direction_input( + msm_cam_flash_gpio_tbl[i][0]); + } + } else { + for (i = 0; i < ARRAY_SIZE(msm_cam_flash_gpio_tbl); i++) { + gpio_direction_input(msm_cam_flash_gpio_tbl[i][0]); + gpio_free(msm_cam_flash_gpio_tbl[i][0]); + } + } + return rc; +} + +int msm_camera_flash_current_driver( + struct msm_camera_sensor_flash_current_driver *current_driver, + unsigned led_state) +{ + int rc = 0; +#if defined CONFIG_LEDS_PMIC8058 + int idx; + const struct pmic8058_leds_platform_data *driver_channel = + current_driver->driver_channel; + int num_leds = driver_channel->num_leds; + + CDBG("%s: led_state = %d\n", __func__, led_state); + + /* Evenly distribute current across all channels */ + switch (led_state) { + case MSM_CAMERA_LED_OFF: + for (idx = 0; idx < num_leds; ++idx) { + rc = pm8058_set_led_current( + driver_channel->leds[idx].id, 0); + if (rc < 0) + pr_err( + "%s: FAIL name = %s, rc = %d\n", + __func__, + driver_channel->leds[idx].name, + rc); + } + break; + + case MSM_CAMERA_LED_LOW: + for (idx = 0; idx < num_leds; ++idx) { + rc = pm8058_set_led_current( + driver_channel->leds[idx].id, + current_driver->low_current/num_leds); + if (rc < 0) + pr_err( + "%s: FAIL name = %s, rc = %d\n", + __func__, + driver_channel->leds[idx].name, + rc); + } + break; + + case MSM_CAMERA_LED_HIGH: + for (idx = 0; idx < num_leds; ++idx) { + rc = pm8058_set_led_current( + driver_channel->leds[idx].id, + current_driver->high_current/num_leds); + if (rc < 0) + pr_err( + "%s: FAIL name = %s, rc = %d\n", + __func__, + driver_channel->leds[idx].name, + rc); + } + break; + case MSM_CAMERA_LED_INIT: + case MSM_CAMERA_LED_RELEASE: + break; + + default: + rc = -EFAULT; + break; + } + CDBG("msm_camera_flash_led_pmic8058: return %d\n", rc); +#endif /* CONFIG_LEDS_PMIC8058 */ + return rc; +} +int msm_camera_flash_external( + struct msm_camera_sensor_flash_external *external, + unsigned led_state) +{ + int rc = 0; + +#if defined CONFIG_MSM_CAMERA_FLASH_SC628A + switch (led_state) { + + case MSM_CAMERA_LED_INIT: + if (!sc628a_client) { + rc = i2c_add_driver(&sc628a_i2c_driver); + if (rc < 0 || sc628a_client == NULL) { + rc = -ENOTSUPP; + CDBG("I2C add driver failed"); + return rc; + } + } +#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE) + if (external->expander_info && !sx150x_client) { + struct i2c_adapter *adapter = + i2c_get_adapter(external->expander_info->bus_id); + if (adapter) + sx150x_client = i2c_new_device(adapter, + external->expander_info->board_info); + if (!sx150x_client || !adapter) { + rc = -ENOTSUPP; + i2c_del_driver(&sc628a_i2c_driver); + sc628a_client = NULL; + return rc; + } + } +#endif + rc = gpio_request(external->led_en, "sc628a"); + if (!rc) { + gpio_direction_output(external->led_en, 1); + } else { + goto err1; + } + rc = gpio_request(external->led_flash_en, "sc628a"); + if (!rc) { + gpio_direction_output(external->led_flash_en, 1); + break; + } + + gpio_set_value_cansleep(external->led_en, 0); + gpio_free(external->led_en); + +err1: + i2c_del_driver(&sc628a_i2c_driver); + sc628a_client = NULL; + + break; + + case MSM_CAMERA_LED_RELEASE: + if (sc628a_client) { + gpio_set_value_cansleep(external->led_en, 0); + gpio_free(external->led_en); + gpio_set_value_cansleep(external->led_flash_en, 0); + gpio_free(external->led_flash_en); + } +#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE) + if (external->expander_info && sx150x_client) { + i2c_unregister_device(sx150x_client); + sx150x_client = NULL; + } +#endif + break; + + case MSM_CAMERA_LED_OFF: + rc = sc628a_i2c_write_b_flash(0x02, 0x0); + if (sc628a_client) { + gpio_set_value_cansleep(external->led_en, 0); + gpio_set_value_cansleep(external->led_flash_en, 0); + } + break; + + case MSM_CAMERA_LED_LOW: + if (sc628a_client) { + gpio_set_value_cansleep(external->led_en, 1); + gpio_set_value_cansleep(external->led_flash_en, 1); + usleep_range(2000, 3000); + } + rc = sc628a_i2c_write_b_flash(0x02, 0x06); + break; + + case MSM_CAMERA_LED_HIGH: + if (sc628a_client) { + gpio_set_value_cansleep(external->led_en, 1); + gpio_set_value_cansleep(external->led_flash_en, 1); + usleep_range(2000, 3000); + } + rc = sc628a_i2c_write_b_flash(0x02, 0x49); + break; + + default: + rc = -EFAULT; + break; + } +#endif + + return rc; +} + +static int msm_camera_flash_pwm( + struct msm_camera_sensor_flash_pwm *pwm, + unsigned led_state) +{ + int rc = 0; + int PWM_PERIOD = USEC_PER_SEC / pwm->freq; + + static struct pwm_device *flash_pwm; + + if (!flash_pwm) { + flash_pwm = pwm_request(pwm->channel, "camera-flash"); + if (flash_pwm == NULL || IS_ERR(flash_pwm)) { + pr_err("%s: FAIL pwm_request(): flash_pwm=%p\n", + __func__, flash_pwm); + flash_pwm = NULL; + return -ENXIO; + } + } + + switch (led_state) { + case MSM_CAMERA_LED_LOW: + rc = pwm_config(flash_pwm, + (PWM_PERIOD/pwm->max_load)*pwm->low_load, + PWM_PERIOD); + if (rc >= 0) + rc = pwm_enable(flash_pwm); + break; + + case MSM_CAMERA_LED_HIGH: + rc = pwm_config(flash_pwm, + (PWM_PERIOD/pwm->max_load)*pwm->high_load, + PWM_PERIOD); + if (rc >= 0) + rc = pwm_enable(flash_pwm); + break; + + case MSM_CAMERA_LED_OFF: + pwm_disable(flash_pwm); + break; + case MSM_CAMERA_LED_INIT: + case MSM_CAMERA_LED_RELEASE: + break; + + default: + rc = -EFAULT; + break; + } + return rc; +} + +int msm_camera_flash_pmic( + struct msm_camera_sensor_flash_pmic *pmic, + unsigned led_state) +{ + int rc = 0; + + switch (led_state) { + case MSM_CAMERA_LED_OFF: + rc = pmic->pmic_set_current(pmic->led_src_1, 0); + if (pmic->num_of_src > 1) + rc = pmic->pmic_set_current(pmic->led_src_2, 0); + break; + + case MSM_CAMERA_LED_LOW: + rc = pmic->pmic_set_current(pmic->led_src_1, + pmic->low_current); + if (pmic->num_of_src > 1) + rc = pmic->pmic_set_current(pmic->led_src_2, 0); + break; + + case MSM_CAMERA_LED_HIGH: + rc = pmic->pmic_set_current(pmic->led_src_1, + pmic->high_current); + if (pmic->num_of_src > 1) + rc = pmic->pmic_set_current(pmic->led_src_2, + pmic->high_current); + break; + + case MSM_CAMERA_LED_INIT: + case MSM_CAMERA_LED_RELEASE: + break; + + default: + rc = -EFAULT; + break; + } + CDBG("flash_set_led_state: return %d\n", rc); + + return rc; +} + +int32_t msm_camera_flash_set_led_state( + struct msm_camera_sensor_flash_data *fdata, unsigned led_state) +{ + int32_t rc; + + if (fdata->flash_type != MSM_CAMERA_FLASH_LED || + fdata->flash_src == NULL) + return -ENODEV; + + switch (fdata->flash_src->flash_sr_type) { + case MSM_CAMERA_FLASH_SRC_PMIC: + rc = msm_camera_flash_pmic(&fdata->flash_src->_fsrc.pmic_src, + led_state); + break; + + case MSM_CAMERA_FLASH_SRC_PWM: + rc = msm_camera_flash_pwm(&fdata->flash_src->_fsrc.pwm_src, + led_state); + break; + + case MSM_CAMERA_FLASH_SRC_CURRENT_DRIVER: + rc = msm_camera_flash_current_driver( + &fdata->flash_src->_fsrc.current_driver_src, + led_state); + break; + + case MSM_CAMERA_FLASH_SRC_EXT: + rc = msm_camera_flash_external( + &fdata->flash_src->_fsrc.ext_driver_src, + led_state); + break; + + default: + rc = -ENODEV; + break; + } + + return rc; +} + +static int msm_strobe_flash_xenon_charge(int32_t flash_charge, + int32_t charge_enable, uint32_t flash_recharge_duration) +{ + gpio_set_value_cansleep(flash_charge, charge_enable); + if (charge_enable) { + timer_flash.expires = jiffies + + msecs_to_jiffies(flash_recharge_duration); + /* add timer for the recharge */ + if (!timer_pending(&timer_flash)) + add_timer(&timer_flash); + } else + del_timer_sync(&timer_flash); + return 0; +} + +static void strobe_flash_xenon_recharge_handler(unsigned long data) +{ + unsigned long flags; + struct msm_camera_sensor_strobe_flash_data *sfdata = + (struct msm_camera_sensor_strobe_flash_data *)data; + + spin_lock_irqsave(&sfdata->timer_lock, flags); + msm_strobe_flash_xenon_charge(sfdata->flash_charge, 1, + sfdata->flash_recharge_duration); + spin_unlock_irqrestore(&sfdata->timer_lock, flags); + + return; +} + +static irqreturn_t strobe_flash_charge_ready_irq(int irq_num, void *data) +{ + struct msm_camera_sensor_strobe_flash_data *sfdata = + (struct msm_camera_sensor_strobe_flash_data *)data; + + /* put the charge signal to low */ + gpio_set_value_cansleep(sfdata->flash_charge, 0); + + return IRQ_HANDLED; +} + +static int msm_strobe_flash_xenon_init( + struct msm_camera_sensor_strobe_flash_data *sfdata) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&sfdata->spin_lock, flags); + if (!sfdata->state) { + + rc = config_flash_gpio_table(MSM_CAM_FLASH_ON, sfdata); + if (rc < 0) { + pr_err("%s: gpio_request failed\n", __func__); + goto go_out; + } + rc = request_irq(sfdata->irq, strobe_flash_charge_ready_irq, + IRQF_TRIGGER_RISING, "charge_ready", sfdata); + if (rc < 0) { + pr_err("%s: request_irq failed %d\n", __func__, rc); + goto go_out; + } + + spin_lock_init(&sfdata->timer_lock); + /* setup timer */ + init_timer(&timer_flash); + timer_flash.function = strobe_flash_xenon_recharge_handler; + timer_flash.data = (unsigned long)sfdata; + } + sfdata->state++; +go_out: + spin_unlock_irqrestore(&sfdata->spin_lock, flags); + + return rc; +} + +static int msm_strobe_flash_xenon_release +(struct msm_camera_sensor_strobe_flash_data *sfdata, int32_t final_release) +{ + unsigned long flags; + + spin_lock_irqsave(&sfdata->spin_lock, flags); + if (sfdata->state > 0) { + if (final_release) + sfdata->state = 0; + else + sfdata->state--; + + if (!sfdata->state) { + free_irq(sfdata->irq, sfdata); + config_flash_gpio_table(MSM_CAM_FLASH_OFF, sfdata); + if (timer_pending(&timer_flash)) + del_timer_sync(&timer_flash); + } + } + spin_unlock_irqrestore(&sfdata->spin_lock, flags); + return 0; +} + +static void msm_strobe_flash_xenon_fn_init + (struct msm_strobe_flash_ctrl *strobe_flash_ptr) +{ + strobe_flash_ptr->strobe_flash_init = + msm_strobe_flash_xenon_init; + strobe_flash_ptr->strobe_flash_charge = + msm_strobe_flash_xenon_charge; + strobe_flash_ptr->strobe_flash_release = + msm_strobe_flash_xenon_release; +} + +int msm_strobe_flash_init(struct msm_sync *sync, uint32_t sftype) +{ + int rc = 0; + switch (sftype) { + case MSM_CAMERA_STROBE_FLASH_XENON: + if (sync->sdata->strobe_flash_data) { + msm_strobe_flash_xenon_fn_init(&sync->sfctrl); + rc = sync->sfctrl.strobe_flash_init( + sync->sdata->strobe_flash_data); + } else + return -ENODEV; + break; + default: + rc = -ENODEV; + } + return rc; +} + +int msm_strobe_flash_ctrl(struct msm_camera_sensor_strobe_flash_data *sfdata, + struct strobe_flash_ctrl_data *strobe_ctrl) +{ + int rc = 0; + switch (strobe_ctrl->type) { + case STROBE_FLASH_CTRL_INIT: + if (!sfdata) + return -ENODEV; + rc = msm_strobe_flash_xenon_init(sfdata); + break; + case STROBE_FLASH_CTRL_CHARGE: + rc = msm_strobe_flash_xenon_charge(sfdata->flash_charge, + strobe_ctrl->charge_en, + sfdata->flash_recharge_duration); + break; + case STROBE_FLASH_CTRL_RELEASE: + if (sfdata) + rc = msm_strobe_flash_xenon_release(sfdata, 0); + break; + default: + pr_err("Invalid Strobe Flash State\n"); + rc = -EINVAL; + } + return rc; +} + +int msm_flash_ctrl(struct msm_camera_sensor_info *sdata, + struct flash_ctrl_data *flash_info) +{ + int rc = 0; + sensor_data = sdata; + switch (flash_info->flashtype) { + case LED_FLASH: + rc = msm_camera_flash_set_led_state(sdata->flash_data, + flash_info->ctrl_data.led_state); + break; + case STROBE_FLASH: + rc = msm_strobe_flash_ctrl(sdata->strobe_flash_data, + &(flash_info->ctrl_data.strobe_ctrl)); + break; + default: + pr_err("Invalid Flash MODE\n"); + rc = -EINVAL; + } + return rc; +} diff --git a/drivers/media/video/msm_zsl/gemini/Makefile b/drivers/media/video/msm_zsl/gemini/Makefile new file mode 100644 index 00000000000..3e2fc9740de --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/Makefile @@ -0,0 +1,2 @@ +GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) +obj-$(CONFIG_MSM_GEMINI) += msm_gemini_dev.o msm_gemini_sync.o msm_gemini_core.o msm_gemini_hw.o msm_gemini_platform.o diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_common.h b/drivers/media/video/msm_zsl/gemini/msm_gemini_common.h new file mode 100644 index 00000000000..0ddedc5013f --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_common.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_GEMINI_COMMON_H +#define MSM_GEMINI_COMMON_H + +#define MSM_GEMINI_DEBUG +#ifdef MSM_GEMINI_DEBUG +#define GMN_DBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define GMN_DBG(fmt, args...) do { } while (0) +#endif + +#define GMN_PR_ERR pr_err + +enum GEMINI_MODE { + GEMINI_MODE_DISABLE, + GEMINI_MODE_OFFLINE, + GEMINI_MODE_REALTIME, + GEMINI_MODE_REALTIME_ROTATION +}; + +enum GEMINI_ROTATION { + GEMINI_ROTATION_0, + GEMINI_ROTATION_90, + GEMINI_ROTATION_180, + GEMINI_ROTATION_270 +}; + +#endif /* MSM_GEMINI_COMMON_H */ diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_core.c b/drivers/media/video/msm_zsl/gemini/msm_gemini_core.c new file mode 100644 index 00000000000..5682e37cff3 --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_core.c @@ -0,0 +1,253 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include "msm_gemini_hw.h" +#include "msm_gemini_core.h" +#include "msm_gemini_platform.h" +#include "msm_gemini_common.h" + +static struct msm_gemini_hw_pingpong fe_pingpong_buf; +static struct msm_gemini_hw_pingpong we_pingpong_buf; +static int we_pingpong_index; +static int reset_done_ack; +static spinlock_t reset_lock; +static wait_queue_head_t reset_wait; + +int msm_gemini_core_reset(uint8_t op_mode, void *base, int size) +{ + unsigned long flags; + int rc = 0; + int tm = 500; /*500ms*/ + memset(&fe_pingpong_buf, 0, sizeof(fe_pingpong_buf)); + fe_pingpong_buf.is_fe = 1; + we_pingpong_index = 0; + memset(&we_pingpong_buf, 0, sizeof(we_pingpong_buf)); + spin_lock_irqsave(&reset_lock, flags); + reset_done_ack = 0; + msm_gemini_hw_reset(base, size); + spin_unlock_irqrestore(&reset_lock, flags); + rc = wait_event_interruptible_timeout( + reset_wait, + reset_done_ack, + msecs_to_jiffies(tm)); + + if (!reset_done_ack) { + GMN_DBG("%s: reset ACK failed %d", __func__, rc); + return -EBUSY; + } + + GMN_DBG("%s: reset_done_ack rc %d", __func__, rc); + spin_lock_irqsave(&reset_lock, flags); + reset_done_ack = 0; + spin_unlock_irqrestore(&reset_lock, flags); + + if (op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) { + /* Nothing needed for fe buffer cfg, config we only */ + msm_gemini_hw_we_buffer_cfg(1); + } else { + /* Nothing needed for fe buffer cfg, config we only */ + msm_gemini_hw_we_buffer_cfg(0); + } + + /* @todo wait for reset done irq */ + + return 0; +} + +void msm_gemini_core_release(int release_buf) +{ + int i = 0; + for (i = 0; i < 2; i++) { + if (we_pingpong_buf.buf_status[i] && release_buf) + msm_gemini_platform_p2v(we_pingpong_buf.buf[i].file, +#if !defined(CONFIG_MSM_IOMMU) + &we_pingpong_buf.buf[i].msm_buffer, +#endif + &we_pingpong_buf.buf[i].handle); + we_pingpong_buf.buf_status[i] = 0; + } +} + +void msm_gemini_core_init(void) +{ + init_waitqueue_head(&reset_wait); + spin_lock_init(&reset_lock); +} + +int msm_gemini_core_fe_start(void) +{ + msm_gemini_hw_fe_start(); + return 0; +} + +/* fetch engine */ +int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf) +{ + GMN_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__, + (int) buf->y_buffer_addr, buf->y_len, + (int) buf->cbcr_buffer_addr, buf->cbcr_len); + return msm_gemini_hw_pingpong_update(&fe_pingpong_buf, buf); +} + +void *msm_gemini_core_fe_pingpong_irq(int gemini_irq_status, void *context) +{ + return msm_gemini_hw_pingpong_irq(&fe_pingpong_buf); +} + +/* write engine */ +int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf) +{ + int rc; + GMN_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__, + (int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr, + buf->y_len); + we_pingpong_buf.buf_status[we_pingpong_index] = 0; + we_pingpong_index = (we_pingpong_index + 1)%2; + rc = msm_gemini_hw_pingpong_update(&we_pingpong_buf, buf); + return 0; +} + +int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf) +{ + int i = 0; + for (i = 0; i < 2; i++) { + if (we_pingpong_buf.buf[i].y_buffer_addr + == buf->y_buffer_addr) + we_pingpong_buf.buf_status[i] = 0; + } + return 0; +} + +void *msm_gemini_core_we_pingpong_irq(int gemini_irq_status, void *context) +{ + GMN_DBG("%s:%d]\n", __func__, __LINE__); + + return msm_gemini_hw_pingpong_irq(&we_pingpong_buf); +} + +void *msm_gemini_core_framedone_irq(int gemini_irq_status, void *context) +{ + struct msm_gemini_hw_buf *buf_p; + + GMN_DBG("%s:%d]\n", __func__, __LINE__); + + buf_p = msm_gemini_hw_pingpong_active_buffer(&we_pingpong_buf); + if (buf_p) { + buf_p->framedone_len = msm_gemini_hw_encode_output_size(); + GMN_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__, + buf_p->framedone_len); + } + + return buf_p; +} + +void *msm_gemini_core_reset_ack_irq(int gemini_irq_status, void *context) +{ + /* @todo return the status back to msm_gemini_core_reset */ + GMN_DBG("%s:%d]\n", __func__, __LINE__); + return NULL; +} + +void *msm_gemini_core_err_irq(int gemini_irq_status, void *context) +{ + GMN_PR_ERR("%s:%d]\n", __func__, gemini_irq_status); + return NULL; +} + +static int (*msm_gemini_irq_handler) (int, void *, void *); + +irqreturn_t msm_gemini_core_irq(int irq_num, void *context) +{ + void *data = NULL; + unsigned long flags; + int gemini_irq_status; + + GMN_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num); + + spin_lock_irqsave(&reset_lock, flags); + reset_done_ack = 1; + spin_unlock_irqrestore(&reset_lock, flags); + gemini_irq_status = msm_gemini_hw_irq_get_status(); + + GMN_DBG("%s:%d] gemini_irq_status = %0x\n", __func__, __LINE__, + gemini_irq_status); + + /*For reset and framedone IRQs, clear all bits*/ + if (gemini_irq_status & 0x400) { + wake_up(&reset_wait); + msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK, + JPEG_IRQ_CLEAR_ALL); + } else if (gemini_irq_status & 0x1) { + msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK, + JPEG_IRQ_CLEAR_ALL); + } else { + msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK, + gemini_irq_status); + } + + if (msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) { + data = msm_gemini_core_framedone_irq(gemini_irq_status, + context); + if (msm_gemini_irq_handler) + msm_gemini_irq_handler( + MSM_GEMINI_HW_MASK_COMP_FRAMEDONE, + context, data); + } + + if (msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status)) { + data = msm_gemini_core_fe_pingpong_irq(gemini_irq_status, + context); + if (msm_gemini_irq_handler) + msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_FE, + context, data); + } + + if (msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) && + !msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) { + data = msm_gemini_core_we_pingpong_irq(gemini_irq_status, + context); + if (msm_gemini_irq_handler) + msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_WE, + context, data); + } + + if (msm_gemini_hw_irq_is_reset_ack(gemini_irq_status)) { + data = msm_gemini_core_reset_ack_irq(gemini_irq_status, + context); + if (msm_gemini_irq_handler) + msm_gemini_irq_handler( + MSM_GEMINI_HW_MASK_COMP_RESET_ACK, + context, data); + } + + /* Unexpected/unintended HW interrupt */ + if (msm_gemini_hw_irq_is_err(gemini_irq_status)) { + data = msm_gemini_core_err_irq(gemini_irq_status, context); + if (msm_gemini_irq_handler) + msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_ERR, + context, data); + } + + return IRQ_HANDLED; +} + +void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *)) +{ + msm_gemini_irq_handler = irq_handler; +} + +void msm_gemini_core_irq_remove(void) +{ + msm_gemini_irq_handler = NULL; +} diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_core.h b/drivers/media/video/msm_zsl/gemini/msm_gemini_core.h new file mode 100644 index 00000000000..f240505fc2d --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_core.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_GEMINI_CORE_H +#define MSM_GEMINI_CORE_H + +#include +#include "msm_gemini_hw.h" + +#define msm_gemini_core_buf msm_gemini_hw_buf + +irqreturn_t msm_gemini_core_irq(int irq_num, void *context); + +void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *)); +void msm_gemini_core_irq_remove(void); + +int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf); +int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf); +int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf); + +int msm_gemini_core_reset(uint8_t op_mode, void *base, int size); +int msm_gemini_core_fe_start(void); + +void msm_gemini_core_release(int); +void msm_gemini_core_init(void); +#endif /* MSM_GEMINI_CORE_H */ diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_dev.c b/drivers/media/video/msm_zsl/gemini/msm_gemini_dev.c new file mode 100644 index 00000000000..0226f7ee039 --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_dev.c @@ -0,0 +1,207 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "msm_gemini_sync.h" +#include "msm_gemini_common.h" + +#define MSM_GEMINI_NAME "gemini" + +static int msm_gemini_open(struct inode *inode, struct file *filp) +{ + int rc; + + struct msm_gemini_device *pgmn_dev = container_of(inode->i_cdev, + struct msm_gemini_device, cdev); + filp->private_data = pgmn_dev; + + GMN_DBG("%s:%d]\n", __func__, __LINE__); + + rc = __msm_gemini_open(pgmn_dev); + + GMN_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, + filp->f_path.dentry->d_name.name, pgmn_dev->open_count); + + return rc; +} + +static int msm_gemini_release(struct inode *inode, struct file *filp) +{ + int rc; + + struct msm_gemini_device *pgmn_dev = filp->private_data; + + GMN_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__); + + rc = __msm_gemini_release(pgmn_dev); + + GMN_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, + filp->f_path.dentry->d_name.name, pgmn_dev->open_count); + return rc; +} + +static long msm_gemini_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int rc; + struct msm_gemini_device *pgmn_dev = filp->private_data; + + GMN_DBG(KERN_INFO "%s:%d] cmd = %d\n", __func__, __LINE__, + _IOC_NR(cmd)); + + rc = __msm_gemini_ioctl(pgmn_dev, cmd, arg); + + GMN_DBG("%s:%d]\n", __func__, __LINE__); + return rc; +} + +static const struct file_operations msm_gemini_fops = { + .owner = THIS_MODULE, + .open = msm_gemini_open, + .release = msm_gemini_release, + .unlocked_ioctl = msm_gemini_ioctl, +}; + +static struct class *msm_gemini_class; +static dev_t msm_gemini_devno; +static struct msm_gemini_device *msm_gemini_device_p; + +static int msm_gemini_init(struct platform_device *pdev) +{ + int rc = -1; + struct device *dev; + + GMN_DBG("%s:%d]\n", __func__, __LINE__); + + msm_gemini_device_p = __msm_gemini_init(pdev); + if (msm_gemini_device_p == NULL) { + GMN_PR_ERR("%s: initialization failed\n", __func__); + goto fail; + } + + rc = alloc_chrdev_region(&msm_gemini_devno, 0, 1, MSM_GEMINI_NAME); + if (rc < 0) { + GMN_PR_ERR("%s: failed to allocate chrdev\n", __func__); + goto fail_1; + } + + if (!msm_gemini_class) { + msm_gemini_class = class_create(THIS_MODULE, MSM_GEMINI_NAME); + if (IS_ERR(msm_gemini_class)) { + rc = PTR_ERR(msm_gemini_class); + GMN_PR_ERR("%s: create device class failed\n", + __func__); + goto fail_2; + } + } + + dev = device_create(msm_gemini_class, NULL, + MKDEV(MAJOR(msm_gemini_devno), MINOR(msm_gemini_devno)), NULL, + "%s%d", MSM_GEMINI_NAME, 0); + + if (IS_ERR(dev)) { + GMN_PR_ERR("%s: error creating device\n", __func__); + rc = -ENODEV; + goto fail_3; + } + + cdev_init(&msm_gemini_device_p->cdev, &msm_gemini_fops); + msm_gemini_device_p->cdev.owner = THIS_MODULE; + msm_gemini_device_p->cdev.ops = + (const struct file_operations *) &msm_gemini_fops; + rc = cdev_add(&msm_gemini_device_p->cdev, msm_gemini_devno, 1); + if (rc < 0) { + GMN_PR_ERR("%s: error adding cdev\n", __func__); + rc = -ENODEV; + goto fail_4; + } + + GMN_DBG("%s %s: success\n", __func__, MSM_GEMINI_NAME); + + return rc; + +fail_4: + device_destroy(msm_gemini_class, msm_gemini_devno); + +fail_3: + class_destroy(msm_gemini_class); + +fail_2: + unregister_chrdev_region(msm_gemini_devno, 1); + +fail_1: + __msm_gemini_exit(msm_gemini_device_p); + +fail: + return rc; +} + +static void msm_gemini_exit(void) +{ + cdev_del(&msm_gemini_device_p->cdev); + device_destroy(msm_gemini_class, msm_gemini_devno); + class_destroy(msm_gemini_class); + unregister_chrdev_region(msm_gemini_devno, 1); + + __msm_gemini_exit(msm_gemini_device_p); +} + +static int __msm_gemini_probe(struct platform_device *pdev) +{ + int rc; + rc = msm_gemini_init(pdev); + return rc; +} + +static int __msm_gemini_remove(struct platform_device *pdev) +{ + msm_gemini_exit(); + return 0; +} + +static struct platform_driver msm_gemini_driver = { + .probe = __msm_gemini_probe, + .remove = __msm_gemini_remove, + .driver = { + .name = "msm_gemini", + .owner = THIS_MODULE, + }, +}; + +static int __init msm_gemini_driver_init(void) +{ + int rc; + rc = platform_driver_register(&msm_gemini_driver); + return rc; +} + +static void __exit msm_gemini_driver_exit(void) +{ + platform_driver_unregister(&msm_gemini_driver); +} + +MODULE_DESCRIPTION("msm gemini jpeg driver"); +MODULE_VERSION("msm gemini 0.1"); + +module_init(msm_gemini_driver_init); +module_exit(msm_gemini_driver_exit); diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_hw.c b/drivers/media/video/msm_zsl/gemini/msm_gemini_hw.c new file mode 100644 index 00000000000..eb039359281 --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_hw.c @@ -0,0 +1,524 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include "msm_gemini_hw.h" +#include "msm_gemini_common.h" + +#include + +static void *gemini_region_base; +static uint32_t gemini_region_size; + +int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw, + struct msm_gemini_hw_buf *buf) +{ + int buf_free_index = -1; + + if (!pingpong_hw->buf_status[0]) { + buf_free_index = 0; + } else if (!pingpong_hw->buf_status[1]) { + buf_free_index = 1; + } else { + GMN_PR_ERR("%s:%d: pingpong buffer busy\n", __func__, __LINE__); + return -1; + } + + pingpong_hw->buf[buf_free_index] = *buf; + pingpong_hw->buf_status[buf_free_index] = 1; + + if (pingpong_hw->is_fe) { + /* it is fe */ + msm_gemini_hw_fe_buffer_update( + &pingpong_hw->buf[buf_free_index], buf_free_index); + } else { + /* it is we */ + msm_gemini_hw_we_buffer_update( + &pingpong_hw->buf[buf_free_index], buf_free_index); + } + return 0; +} + +void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw) +{ + struct msm_gemini_hw_buf *buf_p = NULL; + + if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) { + buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; + pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0; + } + + pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index; + + return (void *) buf_p; +} + +void *msm_gemini_hw_pingpong_active_buffer( + struct msm_gemini_hw_pingpong *pingpong_hw) +{ + struct msm_gemini_hw_buf *buf_p = NULL; + + if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) + buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; + + return (void *) buf_p; +} + +struct msm_gemini_hw_cmd hw_cmd_irq_get_status[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_READ, 1, HWIO_JPEG_IRQ_STATUS_ADDR, + HWIO_JPEG_IRQ_STATUS_RMSK, {0} }, +}; + +int msm_gemini_hw_irq_get_status(void) +{ + uint32_t n_irq_status = 0; + rmb(); + n_irq_status = msm_gemini_hw_read(&hw_cmd_irq_get_status[0]); + rmb(); + return n_irq_status; +} + +struct msm_gemini_hw_cmd hw_cmd_encode_output_size[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_READ, 1, + HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR, + HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK, {0} }, +}; + +long msm_gemini_hw_encode_output_size(void) +{ + uint32_t encode_output_size = 0; + + encode_output_size = msm_gemini_hw_read(&hw_cmd_encode_output_size[0]); + + return encode_output_size; +} + +struct msm_gemini_hw_cmd hw_cmd_irq_clear[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR, + HWIO_JPEG_IRQ_CLEAR_RMSK, {JPEG_IRQ_CLEAR_ALL} }, +}; + +void msm_gemini_hw_irq_clear(uint32_t mask, uint32_t data) +{ + GMN_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data); + hw_cmd_irq_clear[0].mask = mask; + hw_cmd_irq_clear[0].data = data; + msm_gemini_hw_write(&hw_cmd_irq_clear[0]); +} + +struct msm_gemini_hw_cmd hw_cmd_fe_ping_update[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR, + HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PING_ADDR_ADDR, + HWIO_JPEG_FE_Y_PING_ADDR_RMSK, {0} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR, + HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK, {0} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR, + HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} }, +}; + +struct msm_gemini_hw_cmd hw_cmd_fe_pong_update[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR, + HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PONG_ADDR_ADDR, + HWIO_JPEG_FE_Y_PONG_ADDR_RMSK, {0} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR, + HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK, {0} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR, + HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} }, +}; + +void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input, + uint8_t pingpong_index) +{ + uint32_t n_reg_val = 0; + + struct msm_gemini_hw_cmd *hw_cmd_p; + + if (pingpong_index == 0) { + hw_cmd_p = &hw_cmd_fe_ping_update[0]; + n_reg_val = ((((p_input->num_of_mcu_rows - 1) << + HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) & + HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) | + (((p_input->num_of_mcu_rows - 1) << + HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) & + HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK)); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + + n_reg_val = ((p_input->y_buffer_addr << + HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT) & + HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + + n_reg_val = ((p_input->cbcr_buffer_addr<< + HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT) & + HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + + msm_gemini_hw_write(hw_cmd_p); + } else if (pingpong_index == 1) { + hw_cmd_p = &hw_cmd_fe_pong_update[0]; + n_reg_val = ((((p_input->num_of_mcu_rows - 1) << + HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) & + HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) | + (((p_input->num_of_mcu_rows - 1) << + HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) & + HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK)); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + + n_reg_val = ((p_input->y_buffer_addr << + HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT) & + HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + + n_reg_val = ((p_input->cbcr_buffer_addr<< + HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT) & + HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + + msm_gemini_hw_write(hw_cmd_p); + } else { + /* shall not get to here */ + } + + return; +} + +struct msm_gemini_hw_cmd hw_cmd_fe_start[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR, + HWIO_JPEG_FE_CMD_RMSK, {JPEG_OFFLINE_CMD_START} }, +}; + +void msm_gemini_hw_fe_start(void) +{ + msm_gemini_hw_write(&hw_cmd_fe_start[0]); + + return; +} + +struct msm_gemini_hw_cmd hw_cmd_we_buffer_cfg[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_THRESHOLD_ADDR, + HWIO_JPEG_WE_Y_THRESHOLD_RMSK, {0} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_UB_CFG_ADDR, + HWIO_JPEG_WE_Y_UB_CFG_RMSK, {JPEG_WE_YUB_ENCODE} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR, + HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK, {0} }, +}; + +/* first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH + second dimension is for offline and real-time settings + */ +static const uint32_t GEMINI_WE_Y_THRESHOLD[2][2] = { + { 0x00000190, 0x000001ff }, + { 0x0000016a, 0x000001ff } +}; + +/* first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH + second dimension is for offline and real-time settings + */ +static const uint32_t GEMINI_WE_CBCR_THRESHOLD[2][2] = { + { 0x00000190, 0x000001ff }, + { 0x0000016a, 0x000001ff } +}; + +void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime) +{ + uint32_t n_reg_val = 0; + + struct msm_gemini_hw_cmd *hw_cmd_p = &hw_cmd_we_buffer_cfg[0]; + + n_reg_val = (((GEMINI_WE_Y_THRESHOLD[1][is_realtime] << + HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) & + HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) | + ((GEMINI_WE_Y_THRESHOLD[0][is_realtime] << + HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) & + HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK)); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + + msm_gemini_hw_write(hw_cmd_p++); + + /* @todo maybe not for realtime? */ + n_reg_val = (((GEMINI_WE_CBCR_THRESHOLD[1][is_realtime] << + HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) & + HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) | + ((GEMINI_WE_CBCR_THRESHOLD[0][is_realtime] << + HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) & + HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK)); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p); + + return; +} + +struct msm_gemini_hw_cmd hw_cmd_we_ping_update[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR, + HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK, {0} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_ADDR_ADDR, + HWIO_JPEG_WE_Y_PING_ADDR_RMSK, {0} }, +}; + +struct msm_gemini_hw_cmd hw_cmd_we_pong_update[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR, + HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK, {0} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_ADDR_ADDR, + HWIO_JPEG_WE_Y_PONG_ADDR_RMSK, {0} }, +}; + +void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input, + uint8_t pingpong_index) +{ + uint32_t n_reg_val = 0; + + struct msm_gemini_hw_cmd *hw_cmd_p; + + if (pingpong_index == 0) { + hw_cmd_p = &hw_cmd_we_ping_update[0]; + + n_reg_val = ((p_input->y_len << + HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) & + HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + + n_reg_val = p_input->y_buffer_addr; + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + } else if (pingpong_index == 1) { + hw_cmd_p = &hw_cmd_we_pong_update[0]; + + n_reg_val = ((p_input->y_len << + HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) & + HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK); + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + + n_reg_val = p_input->y_buffer_addr; + hw_cmd_p->data = n_reg_val; + msm_gemini_hw_write(hw_cmd_p++); + } else { + /* shall not get to here */ + } + + return; +} + +struct msm_gemini_hw_cmd hw_cmd_reset[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR, + HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_DISABLE_ALL} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR, + HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_CLEAR_ALL} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR, + HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, + {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_RESET_CMD_ADDR, + HWIO_JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} }, +}; + +void msm_gemini_hw_init(void *base, int size) +{ + gemini_region_base = base; + gemini_region_size = size; +} + +void msm_gemini_hw_reset(void *base, int size) +{ + struct msm_gemini_hw_cmd *hw_cmd_p; + + hw_cmd_p = &hw_cmd_reset[0]; + + wmb(); + msm_gemini_hw_write(hw_cmd_p++); + msm_gemini_hw_write(hw_cmd_p++); + msm_gemini_hw_write(hw_cmd_p++); + msm_gemini_hw_write(hw_cmd_p); + wmb(); + + return; +} + +uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p) +{ + uint32_t *paddr; + uint32_t data; + + paddr = gemini_region_base + hw_cmd_p->offset; + + data = readl(paddr); + data &= hw_cmd_p->mask; + + GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n", + __func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n, + hw_cmd_p->offset, hw_cmd_p->mask, data); + return data; +} + +void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p) +{ + uint32_t *paddr; + uint32_t old_data, new_data; + + /* type, repeat n times, offset, mask, data or pdata */ + GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n", + __func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n, + hw_cmd_p->offset, hw_cmd_p->mask, hw_cmd_p->data); + + paddr = gemini_region_base + hw_cmd_p->offset; + + if (hw_cmd_p->mask == 0xffffffff) { + old_data = 0; + } else { + old_data = readl(paddr); + old_data &= ~hw_cmd_p->mask; + } + + new_data = hw_cmd_p->data & hw_cmd_p->mask; + new_data |= old_data; + writel(new_data, paddr); +} + +int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us) +{ + int tm = hw_cmd_p->n; + uint32_t data; + uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask; + + data = msm_gemini_hw_read(hw_cmd_p); + if (data != wait_data) { + while (tm) { + udelay(m_us); + data = msm_gemini_hw_read(hw_cmd_p); + if (data == wait_data) + break; + tm--; + } + } + hw_cmd_p->data = data; + return tm; +} + +void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us) +{ + int tm = hw_cmd_p->n; + while (tm) { + udelay(m_us); + tm--; + } +} + +int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds) +{ + int is_copy_to_user = -1; + uint32_t data; + + while (m_cmds--) { + if (hw_cmd_p->offset > gemini_region_size) { + GMN_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__, + __LINE__, hw_cmd_p->offset, gemini_region_size); + return -EFAULT; + } + + switch (hw_cmd_p->type) { + case MSM_GEMINI_HW_CMD_TYPE_READ: + hw_cmd_p->data = msm_gemini_hw_read(hw_cmd_p); + is_copy_to_user = 1; + break; + + case MSM_GEMINI_HW_CMD_TYPE_WRITE: + msm_gemini_hw_write(hw_cmd_p); + break; + + case MSM_GEMINI_HW_CMD_TYPE_WRITE_OR: + data = msm_gemini_hw_read(hw_cmd_p); + hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) | + data; + msm_gemini_hw_write(hw_cmd_p); + break; + + case MSM_GEMINI_HW_CMD_TYPE_UWAIT: + msm_gemini_hw_wait(hw_cmd_p, 1); + break; + + case MSM_GEMINI_HW_CMD_TYPE_MWAIT: + msm_gemini_hw_wait(hw_cmd_p, 1000); + break; + + case MSM_GEMINI_HW_CMD_TYPE_UDELAY: + msm_gemini_hw_delay(hw_cmd_p, 1); + break; + + case MSM_GEMINI_HW_CMD_TYPE_MDELAY: + msm_gemini_hw_delay(hw_cmd_p, 1000); + break; + + default: + GMN_PR_ERR("wrong hw command type\n"); + break; + } + + hw_cmd_p++; + } + return is_copy_to_user; +} + +void msm_gemini_hw_region_dump(int size) +{ + uint32_t *p; + uint8_t *p8; + + if (size > gemini_region_size) + GMN_PR_ERR("%s:%d] wrong region dump size\n", + __func__, __LINE__); + + p = (uint32_t *) gemini_region_base; + while (size >= 16) { + GMN_DBG("0x%08X] %08X %08X %08X %08X\n", + gemini_region_size - size, + readl(p), readl(p+1), readl(p+2), readl(p+3)); + p += 4; + size -= 16; + } + + if (size > 0) { + uint32_t d; + GMN_DBG("0x%08X] ", gemini_region_size - size); + while (size >= 4) { + GMN_DBG("%08X ", readl(p++)); + size -= 4; + } + + d = readl(p); + p8 = (uint8_t *) &d; + while (size) { + GMN_DBG("%02X", *p8++); + size--; + } + + GMN_DBG("\n"); + } +} diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_hw.h b/drivers/media/video/msm_zsl/gemini/msm_gemini_hw.h new file mode 100644 index 00000000000..c8142443f51 --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_hw.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_GEMINI_HW_H +#define MSM_GEMINI_HW_H + +#include +#include "msm_gemini_hw_reg.h" +#include +#include + +struct msm_gemini_hw_buf { + struct msm_gemini_buf vbuf; + struct file *file; + uint32_t framedone_len; + uint32_t y_buffer_addr; + uint32_t y_len; + uint32_t cbcr_buffer_addr; + uint32_t cbcr_len; + uint32_t num_of_mcu_rows; +#if !defined(CONFIG_MSM_IOMMU) + struct msm_mapped_buffer *msm_buffer; + int *subsystem_id; +#endif + struct ion_handle *handle; +}; + +struct msm_gemini_hw_pingpong { + uint8_t is_fe; /* 1: fe; 0: we */ + struct msm_gemini_hw_buf buf[2]; + int buf_status[2]; + int buf_active_index; +}; + +int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw, + struct msm_gemini_hw_buf *buf); +void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw); +void *msm_gemini_hw_pingpong_active_buffer(struct msm_gemini_hw_pingpong + *pingpong_hw); + +void msm_gemini_hw_irq_clear(uint32_t, uint32_t); +int msm_gemini_hw_irq_get_status(void); +long msm_gemini_hw_encode_output_size(void); +#define MSM_GEMINI_HW_MASK_COMP_FRAMEDONE \ + MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK +#define MSM_GEMINI_HW_MASK_COMP_FE \ + MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK +#define MSM_GEMINI_HW_MASK_COMP_WE \ + (MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \ + MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK) +#define MSM_GEMINI_HW_MASK_COMP_RESET_ACK \ + MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK +#define MSM_GEMINI_HW_MASK_COMP_ERR \ + (MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK | \ + MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK | \ + MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK | \ + MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK | \ + MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK | \ + MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK | \ + MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK | \ + MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK) + +#define msm_gemini_hw_irq_is_frame_done(gemini_irq_status) \ + (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FRAMEDONE) +#define msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status) \ + (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FE) +#define msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) \ + (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_WE) +#define msm_gemini_hw_irq_is_reset_ack(gemini_irq_status) \ + (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_RESET_ACK) +#define msm_gemini_hw_irq_is_err(gemini_irq_status) \ + (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_ERR) + +void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input, + uint8_t pingpong_index); +void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input, + uint8_t pingpong_index); + +void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime); + +void msm_gemini_hw_fe_start(void); +void msm_gemini_hw_clk_cfg(void); + +void msm_gemini_hw_reset(void *base, int size); +void msm_gemini_hw_irq_cfg(void); +void msm_gemini_hw_init(void *base, int size); + +uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p); +void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p); +int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us); +void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us); +int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds); +void msm_gemini_hw_region_dump(int size); + +#define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP 128MHz */ +#define MSM_GEMINI_PIPELINE_CLK_140MHZ 140 /* 9MP 140MHz */ +#define MSM_GEMINI_PIPELINE_CLK_200MHZ 153 /* 12MP 153MHz */ + +#endif /* MSM_GEMINI_HW_H */ diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_hw_reg.h b/drivers/media/video/msm_zsl/gemini/msm_gemini_hw_reg.h new file mode 100644 index 00000000000..4bddfbba4a9 --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_hw_reg.h @@ -0,0 +1,176 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_GEMINI_HW_REG_H +#define MSM_GEMINI_HW_REG_H + +#define GEMINI_REG_BASE 0 + +#define MSM_GEMINI_HW_IRQ_MASK_ADDR 0x00000014 +#define MSM_GEMINI_HW_IRQ_MASK_RMSK 0xffffffff +#define MSM_GEMINI_HW_IRQ_MASK_SHFT 0 +#define MSM_GEMINI_HW_IRQ_DISABLE 0 +#define MSM_GEMINI_HW_IRQ_ENABLE 0xffffffff + +#define MSM_GEMINI_HW_IRQ_CLEAR_ADDR 0x00000018 +#define MSM_GEMINI_HW_IRQ_CLEAR_RMSK 0xffffffff +#define MSM_GEMINI_HW_IRQ_CLEAR_SHFT 0 +#define MSM_GEMINI_HW_IRQ_CLEAR 0xffffffff + +#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001 +#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000 + +#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000002 +#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001 + +#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004 +#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002 + +#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008 +#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003 + +#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010 +#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004 + +#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020 +#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005 + +#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK 0x00000040 +#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_SHIFT 0x00000006 + +#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK 0x00000080 +#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_SHIFT 0x00000007 + +#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK 0x00000100 +#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_SHIFT 0x00000008 + +#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK 0x00000200 +#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_SHIFT 0x00000009 + +#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK 0x00000400 +#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a + +#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800 +#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b + +#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK 0x00001000 +#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_SHIFT 0x0000000c + +#define JPEG_BUS_CMD_HALT_REQ 0x00000001 + +#define JPEG_REALTIME_CMD_STOP_FB 0x00000000 +#define JPEG_REALTIME_CMD_STOP_IM 0x00000003 +#define JPEG_REALTIME_CMD_START 0x00000001 + +#define JPEG_OFFLINE_CMD_START 0x00000003 + +#define JPEG_DMI_CFG_DISABLE 0x00000000 +#define JPEG_DMI_ADDR_START 0x00000000 + +#define JPEG_FE_CMD_BUFFERRELOAD 0x00000001 + +#define JPEG_WE_YUB_ENCODE 0x01ff0000 + +#define JPEG_RESET_DEFAULT 0x0004ffff /* cfff? */ + +#define JPEG_IRQ_DISABLE_ALL 0x00000000 +#define JPEG_IRQ_CLEAR_ALL 0xffffffff +#define JPEG_IRQ_ALLSOURCES_ENABLE 0xffffffff + +#define HWIO_JPEG_FE_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x00000080) +#define HWIO_JPEG_FE_BUFFER_CFG_RMSK 0x1fff1fff + +#define HWIO_JPEG_FE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x00000084) +#define HWIO_JPEG_FE_Y_PING_ADDR_RMSK 0xffffffff + +#define HWIO_JPEG_FE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000088) +#define HWIO_JPEG_FE_Y_PONG_ADDR_RMSK 0xffffffff + +#define HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x0000008c) +#define HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK 0xffffffff + +#define HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000090) +#define HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK 0xffffffff + +#define HWIO_JPEG_FE_CMD_ADDR (GEMINI_REG_BASE + 0x00000094) +#define HWIO_JPEG_FE_CMD_RMSK 0x3 + +#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK 0x1fff0000 +#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT 0x10 +#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK 0x1fff +#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT 0 + +#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK 0xffffffff +#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT 0 + +#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK 0xffffffff +#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT 0 + +#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK 0xffffffff +#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT 0 + +#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK 0xffffffff +#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT 0 + +#define HWIO_JPEG_WE_Y_THRESHOLD_ADDR (GEMINI_REG_BASE + 0x000000c0) +#define HWIO_JPEG_WE_Y_THRESHOLD_RMSK 0x1ff01ff + +#define HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR (GEMINI_REG_BASE + 0x000000c4) +#define HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK 0x1ff01ff + +#define HWIO_JPEG_WE_Y_UB_CFG_ADDR (GEMINI_REG_BASE + 0x000000e8) +#define HWIO_JPEG_WE_Y_UB_CFG_RMSK 0x1ff01ff + +#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000 +#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10 +#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff +#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0 + +#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000 +#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10 +#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff +#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0 + +#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000c8) +#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK 0x7fffff + +#define HWIO_JPEG_WE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x000000d8) +#define HWIO_JPEG_WE_Y_PING_ADDR_RMSK 0xfffffff8 + +#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000cc) +#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK 0x7fffff + +#define HWIO_JPEG_WE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x000000dc) +#define HWIO_JPEG_WE_Y_PONG_ADDR_RMSK 0xfffffff8 + +#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff +#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0 + +#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff +#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0 + +#define HWIO_JPEG_IRQ_MASK_ADDR (GEMINI_REG_BASE + 0x00000014) +#define HWIO_JPEG_IRQ_MASK_RMSK 0xffffffff + +#define HWIO_JPEG_IRQ_CLEAR_ADDR (GEMINI_REG_BASE + 0x00000018) +#define HWIO_JPEG_IRQ_CLEAR_RMSK 0xffffffff + +#define HWIO_JPEG_RESET_CMD_ADDR (GEMINI_REG_BASE + 0x00000004) +#define HWIO_JPEG_RESET_CMD_RMSK 0xe004ffff + +#define HWIO_JPEG_IRQ_STATUS_ADDR (GEMINI_REG_BASE + 0x0000001c) +#define HWIO_JPEG_IRQ_STATUS_RMSK 0xffffffff + +#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR (GEMINI_REG_BASE + 0x00000034) +#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK 0xffffff + +#endif /* MSM_GEMINI_HW_REG_H */ diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_platform.c b/drivers/media/video/msm_zsl/gemini/msm_gemini_platform.c new file mode 100644 index 00000000000..687e19a277c --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_platform.c @@ -0,0 +1,228 @@ +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_gemini_platform.h" +#include "msm_gemini_common.h" +#include "msm_gemini_hw.h" + +/* AXI rate in KHz */ +#define MSM_SYSTEM_BUS_RATE 160000 +struct ion_client *gemini_client; + +void msm_gemini_platform_p2v(struct file *file, +#if !defined(CONFIG_MSM_IOMMU) + struct msm_mapped_buffer **msm_buffer, +#endif + struct ion_handle **ionhandle) +{ +#if !defined(CONFIG_MSM_IOMMU) + if (msm_subsystem_unmap_buffer( + (struct msm_mapped_buffer *)*msm_buffer) < 0) + pr_err("%s: umapped stat memory\n", __func__); + *msm_buffer = NULL; +#endif + +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +#if defined(CONFIG_MSM_IOMMU) + ion_unmap_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL); +#endif + ion_free(gemini_client, *ionhandle); + *ionhandle = NULL; +#elif CONFIG_ANDROID_PMEM + put_pmem_file(file); +#endif +} + +uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p, +#if !defined(CONFIG_MSM_IOMMU) + struct msm_mapped_buffer **msm_buffer, + int *subsys_id, struct ion_handle **ionhandle) +#else + struct ion_handle **ionhandle) +#endif +{ + unsigned long paddr; + unsigned long size; + int rc; +#if !defined(CONFIG_MSM_IOMMU) + int flags; +#endif + +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + *ionhandle = ion_import_dma_buf(gemini_client, fd); + if (IS_ERR_OR_NULL(*ionhandle)) + return 0; +#if !defined(CONFIG_MSM_IOMMU) + rc = ion_phys(gemini_client, *ionhandle, &paddr, (size_t *)&size); +#else + rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL, + SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0); +#endif +#elif CONFIG_ANDROID_PMEM + unsigned long kvstart; + rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p); +#else + rc = 0; + paddr = 0; + size = 0; +#endif + if (rc < 0) { + GMN_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd, + rc); +#if !defined(CONFIG_MSM_IOMMU) + return 0; +#else + goto error1; +#endif + } + + /* validate user input */ + if (len > size) { + GMN_PR_ERR("%s: invalid offset + len\n", __func__); +#if !defined(CONFIG_MSM_IOMMU) + return 0; +#else + goto error1; +#endif + } + +#if !defined(CONFIG_MSM_IOMMU) + flags = MSM_SUBSYSTEM_MAP_IOVA; + *subsys_id = MSM_SUBSYSTEM_CAMERA; + *msm_buffer = msm_subsystem_map_buffer(paddr, size, + flags, subsys_id, 1); + if (IS_ERR((void *)*msm_buffer)) { + pr_err("%s: msm_subsystem_map_buffer failed\n", __func__); +#else + return paddr; +error1: +#endif + +#if !defined(CONFIG_MSM_IOMMU) +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_free(gemini_client, *ionhandle); + *ionhandle = NULL; +#elif CONFIG_ANDROID_PMEM + put_pmem_file(*file_p); +#endif + return 0; + } + paddr = ((struct msm_mapped_buffer *)*msm_buffer)->iova[0]; + return paddr; + +#else /*CONFIG_MSM_IOMMU*/ +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_free(gemini_client, *ionhandle); + return 0; +#endif +#endif +} + +int msm_gemini_platform_init(struct platform_device *pdev, + struct resource **mem, + void **base, + int *irq, + irqreturn_t (*handler) (int, void *), + void *context) +{ + int rc = -1; + int gemini_irq; + struct resource *gemini_mem, *gemini_io, *gemini_irq_res; + void *gemini_base; + + gemini_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!gemini_mem) { + GMN_PR_ERR("%s: no mem resource?\n", __func__); + return -ENODEV; + } + + gemini_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!gemini_irq_res) { + GMN_PR_ERR("no irq resource?\n"); + return -ENODEV; + } + gemini_irq = gemini_irq_res->start; + + gemini_io = request_mem_region(gemini_mem->start, + resource_size(gemini_mem), pdev->name); + if (!gemini_io) { + GMN_PR_ERR("%s: region already claimed\n", __func__); + return -EBUSY; + } + + gemini_base = ioremap(gemini_mem->start, resource_size(gemini_mem)); + if (!gemini_base) { + rc = -ENOMEM; + GMN_PR_ERR("%s: ioremap failed\n", __func__); + goto fail1; + } + + rc = msm_camio_jpeg_clk_enable(); + if (rc) { + GMN_PR_ERR("%s: clk failed rc = %d\n", __func__, rc); + goto fail2; + } + + msm_gemini_hw_init(gemini_base, resource_size(gemini_mem)); + rc = request_irq(gemini_irq, handler, IRQF_TRIGGER_RISING, "gemini", + context); + if (rc) { + GMN_PR_ERR("%s: request_irq failed, %d\n", __func__, + gemini_irq); + goto fail3; + } + + *mem = gemini_mem; + *base = gemini_base; + *irq = gemini_irq; + +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + gemini_client = msm_ion_client_create(-1, "camera/gemini"); +#endif + GMN_DBG("%s:%d] success\n", __func__, __LINE__); + + return rc; + +fail3: + msm_camio_jpeg_clk_disable(); +fail2: + iounmap(gemini_base); +fail1: + release_mem_region(gemini_mem->start, resource_size(gemini_mem)); + GMN_DBG("%s:%d] fail\n", __func__, __LINE__); + return rc; +} + +int msm_gemini_platform_release(struct resource *mem, void *base, int irq, + void *context) +{ + int result; + + free_irq(irq, context); + result = msm_camio_jpeg_clk_disable(); + iounmap(base); + release_mem_region(mem->start, resource_size(mem)); +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_client_destroy(gemini_client); +#endif + GMN_DBG("%s:%d] success\n", __func__, __LINE__); + return result; +} diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_platform.h b/drivers/media/video/msm_zsl/gemini/msm_gemini_platform.h new file mode 100644 index 00000000000..5c251c55219 --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_platform.h @@ -0,0 +1,44 @@ +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_GEMINI_PLATFORM_H +#define MSM_GEMINI_PLATFORM_H + +#include +#include +#include +void msm_gemini_platform_p2v(struct file *file, +#if !defined(CONFIG_MSM_IOMMU) + struct msm_mapped_buffer **msm_buffer, +#endif + struct ion_handle **ionhandle); +uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file, +#if !defined(CONFIG_MSM_IOMMU) + struct msm_mapped_buffer **msm_buffer, + int *subsys_id, struct ion_handle **ionhandle); +#else + struct ion_handle **ionhandle); +#endif + +int msm_gemini_platform_clk_enable(void); +int msm_gemini_platform_clk_disable(void); + +int msm_gemini_platform_init(struct platform_device *pdev, + struct resource **mem, + void **base, + int *irq, + irqreturn_t (*handler) (int, void *), + void *context); +int msm_gemini_platform_release(struct resource *mem, void *base, int irq, + void *context); + +#endif /* MSM_GEMINI_PLATFORM_H */ diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_sync.c b/drivers/media/video/msm_zsl/gemini/msm_gemini_sync.c new file mode 100644 index 00000000000..9e2806a9728 --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_sync.c @@ -0,0 +1,887 @@ +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include "msm_gemini_sync.h" +#include "msm_gemini_core.h" +#include "msm_gemini_platform.h" +#include "msm_gemini_common.h" + +static int release_buf; + +/*************** queue helper ****************/ +inline void msm_gemini_q_init(char const *name, struct msm_gemini_q *q_p) +{ + GMN_DBG("%s:%d] %s\n", __func__, __LINE__, name); + q_p->name = name; + spin_lock_init(&q_p->lck); + INIT_LIST_HEAD(&q_p->q); + init_waitqueue_head(&q_p->wait); + q_p->unblck = 0; +} + +inline void *msm_gemini_q_out(struct msm_gemini_q *q_p) +{ + unsigned long flags; + struct msm_gemini_q_entry *q_entry_p = NULL; + void *data = NULL; + + GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + spin_lock_irqsave(&q_p->lck, flags); + if (!list_empty(&q_p->q)) { + q_entry_p = list_first_entry(&q_p->q, struct msm_gemini_q_entry, + list); + list_del_init(&q_entry_p->list); + } + spin_unlock_irqrestore(&q_p->lck, flags); + + if (q_entry_p) { + data = q_entry_p->data; + kfree(q_entry_p); + } else { + GMN_DBG("%s:%d] %s no entry\n", __func__, __LINE__, + q_p->name); + } + + return data; +} + +inline int msm_gemini_q_in(struct msm_gemini_q *q_p, void *data) +{ + unsigned long flags; + + struct msm_gemini_q_entry *q_entry_p; + + GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + + q_entry_p = kmalloc(sizeof(struct msm_gemini_q_entry), GFP_ATOMIC); + if (!q_entry_p) { + GMN_PR_ERR("%s: no mem\n", __func__); + return -1; + } + q_entry_p->data = data; + + spin_lock_irqsave(&q_p->lck, flags); + list_add_tail(&q_entry_p->list, &q_p->q); + spin_unlock_irqrestore(&q_p->lck, flags); + + return 0; +} + +inline int msm_gemini_q_in_buf(struct msm_gemini_q *q_p, + struct msm_gemini_core_buf *buf) +{ + struct msm_gemini_core_buf *buf_p; + + GMN_DBG("%s:%d]\n", __func__, __LINE__); + buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC); + if (!buf_p) { + GMN_PR_ERR("%s: no mem\n", __func__); + return -1; + } + + memcpy(buf_p, buf, sizeof(struct msm_gemini_core_buf)); + + msm_gemini_q_in(q_p, buf_p); + return 0; +} + +inline int msm_gemini_q_wait(struct msm_gemini_q *q_p) +{ + int tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */ + int rc; + + GMN_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name); + rc = wait_event_interruptible_timeout(q_p->wait, + (!list_empty_careful(&q_p->q) || q_p->unblck), + msecs_to_jiffies(tm)); + GMN_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name); + if (list_empty_careful(&q_p->q)) { + if (rc == 0) { + rc = -ETIMEDOUT; + GMN_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__, + q_p->name); + } else if (q_p->unblck) { + GMN_DBG("%s:%d] %s unblock is true\n", __func__, + __LINE__, q_p->name); + q_p->unblck = 0; + rc = -ECANCELED; + } else if (rc < 0) { + GMN_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__, + q_p->name, rc); + } + } + return rc; +} + +inline int msm_gemini_q_wakeup(struct msm_gemini_q *q_p) +{ + GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + wake_up(&q_p->wait); + return 0; +} + +inline int msm_gemini_q_unblock(struct msm_gemini_q *q_p) +{ + GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + q_p->unblck = 1; + wake_up(&q_p->wait); + return 0; +} + +inline void msm_gemini_outbuf_q_cleanup(struct msm_gemini_q *q_p) +{ + struct msm_gemini_core_buf *buf_p; + GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + do { + buf_p = msm_gemini_q_out(q_p); + if (buf_p) { + msm_gemini_platform_p2v(buf_p->file, +#if !defined(CONFIG_MSM_IOMMU) + &buf_p->msm_buffer, &buf_p->handle); +#else + &buf_p->handle); +#endif + GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); +#if !defined(CONFIG_MSM_IOMMU) + kfree(buf_p->subsystem_id); +#endif + kfree(buf_p); + } + } while (buf_p); + q_p->unblck = 0; +} + +inline void msm_gemini_q_cleanup(struct msm_gemini_q *q_p) +{ + void *data; + GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + do { + data = msm_gemini_q_out(q_p); + if (data) { + GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + kfree(data); + } + } while (data); + q_p->unblck = 0; +} + +/*************** event queue ****************/ + +int msm_gemini_framedone_irq(struct msm_gemini_device *pgmn_dev, + struct msm_gemini_core_buf *buf_in) +{ + int rc = 0; + + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + + if (buf_in) { + buf_in->vbuf.framedone_len = buf_in->framedone_len; + buf_in->vbuf.type = MSM_GEMINI_EVT_FRAMEDONE; + GMN_DBG("%s:%d] 0x%08x %d framedone_len %d\n", + __func__, __LINE__, + (int) buf_in->y_buffer_addr, buf_in->y_len, + buf_in->vbuf.framedone_len); + rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, buf_in); + } else { + GMN_PR_ERR("%s:%d] no output return buffer\n", + __func__, __LINE__); + rc = -1; + } + + if (buf_in) + rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q); + + return rc; +} + +int msm_gemini_evt_get(struct msm_gemini_device *pgmn_dev, + void __user *to) +{ + struct msm_gemini_core_buf *buf_p; + struct msm_gemini_ctrl_cmd ctrl_cmd; + + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + + msm_gemini_q_wait(&pgmn_dev->evt_q); + buf_p = msm_gemini_q_out(&pgmn_dev->evt_q); + + if (!buf_p) { + GMN_DBG("%s:%d] no buffer\n", __func__, __LINE__); + return -EAGAIN; + } + + ctrl_cmd.type = buf_p->vbuf.type; + kfree(buf_p); + + GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) ctrl_cmd.value, ctrl_cmd.len); + + if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) { + GMN_PR_ERR("%s:%d]\n", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_gemini_evt_get_unblock(struct msm_gemini_device *pgmn_dev) +{ + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_gemini_q_unblock(&pgmn_dev->evt_q); + return 0; +} + +void msm_gemini_reset_ack_irq(struct msm_gemini_device *pgmn_dev) +{ + GMN_DBG("%s:%d]\n", __func__, __LINE__); +} + +void msm_gemini_err_irq(struct msm_gemini_device *pgmn_dev, + int event) +{ + int rc = 0; + struct msm_gemini_core_buf buf; + + GMN_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event); + + buf.vbuf.type = MSM_GEMINI_EVT_ERR; + rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, &buf); + if (!rc) + rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q); + + if (!rc) + GMN_PR_ERR("%s:%d] err err\n", __func__, __LINE__); + + return; +} + +/*************** output queue ****************/ + +int msm_gemini_we_pingpong_irq(struct msm_gemini_device *pgmn_dev, + struct msm_gemini_core_buf *buf_in) +{ + int rc = 0; + struct msm_gemini_core_buf *buf_out; + + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (buf_in) { + GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_in->y_buffer_addr, buf_in->y_len); + rc = msm_gemini_q_in_buf(&pgmn_dev->output_rtn_q, buf_in); + } else { + GMN_DBG("%s:%d] no output return buffer\n", __func__, + __LINE__); + rc = -1; + } + + buf_out = msm_gemini_q_out(&pgmn_dev->output_buf_q); + + if (buf_out) { + rc = msm_gemini_core_we_buf_update(buf_out); + kfree(buf_out); + } else { + msm_gemini_core_we_buf_reset(buf_in); + GMN_DBG("%s:%d] no output buffer\n", __func__, __LINE__); + rc = -2; + } + + if (buf_in) + rc = msm_gemini_q_wakeup(&pgmn_dev->output_rtn_q); + + return rc; +} + +int msm_gemini_output_get(struct msm_gemini_device *pgmn_dev, void __user *to) +{ + struct msm_gemini_core_buf *buf_p; + struct msm_gemini_buf buf_cmd; + + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + + msm_gemini_q_wait(&pgmn_dev->output_rtn_q); + buf_p = msm_gemini_q_out(&pgmn_dev->output_rtn_q); + + if (!buf_p) { + GMN_DBG("%s:%d] no output buffer return\n", + __func__, __LINE__); + return -EAGAIN; + } + + buf_cmd = buf_p->vbuf; +#if !defined(CONFIG_MSM_IOMMU) + msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer, + &buf_p->handle); + kfree(buf_p->subsystem_id); +#endif + kfree(buf_p); + + GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_cmd.vaddr, buf_cmd.y_len); + + if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { + GMN_PR_ERR("%s:%d]", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_gemini_output_get_unblock(struct msm_gemini_device *pgmn_dev) +{ + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_gemini_q_unblock(&pgmn_dev->output_rtn_q); + return 0; +} + +int msm_gemini_output_buf_enqueue(struct msm_gemini_device *pgmn_dev, + void __user *arg) +{ + struct msm_gemini_buf buf_cmd; + struct msm_gemini_core_buf *buf_p; + + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) { + GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC); + if (!buf_p) { + GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); + return -1; + } + + GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, (int) buf_cmd.vaddr, + buf_cmd.y_len); + +#if !defined(CONFIG_MSM_IOMMU) + buf_p->subsystem_id = kmalloc(sizeof(int), GFP_ATOMIC); + if (!buf_p->subsystem_id) { + GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); + kfree(buf_p); + return -ENOMEM; + } + buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd, + buf_cmd.y_len, &buf_p->file, &buf_p->msm_buffer, + buf_p->subsystem_id, &buf_p->handle); +#else + buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd, + buf_cmd.y_len, &buf_p->file, &buf_p->handle); +#endif + if (!buf_p->y_buffer_addr) { + GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); +#if !defined(CONFIG_MSM_IOMMU) + kfree(buf_p->subsystem_id); +#endif + kfree(buf_p); + return -1; + } + buf_p->y_len = buf_cmd.y_len; + buf_p->vbuf = buf_cmd; + + msm_gemini_q_in(&pgmn_dev->output_buf_q, buf_p); + return 0; +} + +/*************** input queue ****************/ + +int msm_gemini_fe_pingpong_irq(struct msm_gemini_device *pgmn_dev, + struct msm_gemini_core_buf *buf_in) +{ + struct msm_gemini_core_buf *buf_out; + int rc = 0; + + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (buf_in) { + GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_in->y_buffer_addr, buf_in->y_len); + rc = msm_gemini_q_in_buf(&pgmn_dev->input_rtn_q, buf_in); + } else { + GMN_DBG("%s:%d] no input return buffer\n", __func__, + __LINE__); + rc = -1; + } + + buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q); + + if (buf_out) { + rc = msm_gemini_core_fe_buf_update(buf_out); + kfree(buf_out); + msm_gemini_core_fe_start(); + } else { + GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__); + rc = -2; + } + + if (buf_in) + rc = msm_gemini_q_wakeup(&pgmn_dev->input_rtn_q); + + return rc; +} + +int msm_gemini_input_get(struct msm_gemini_device *pgmn_dev, void __user * to) +{ + struct msm_gemini_core_buf *buf_p; + struct msm_gemini_buf buf_cmd; + + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_gemini_q_wait(&pgmn_dev->input_rtn_q); + buf_p = msm_gemini_q_out(&pgmn_dev->input_rtn_q); + + if (!buf_p) { + GMN_DBG("%s:%d] no input buffer return\n", + __func__, __LINE__); + return -EAGAIN; + } + + buf_cmd = buf_p->vbuf; +#if !defined(CONFIG_MSM_IOMMU) + msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer, + &buf_p->handle); + kfree(buf_p->subsystem_id); +#else + msm_gemini_platform_p2v(buf_p->file, &buf_p->handle); +#endif + kfree(buf_p); + + GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_cmd.vaddr, buf_cmd.y_len); + + if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { + GMN_PR_ERR("%s:%d]\n", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_gemini_input_get_unblock(struct msm_gemini_device *pgmn_dev) +{ + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_gemini_q_unblock(&pgmn_dev->input_rtn_q); + return 0; +} + +int msm_gemini_input_buf_enqueue(struct msm_gemini_device *pgmn_dev, + void __user *arg) +{ + struct msm_gemini_core_buf *buf_p; + struct msm_gemini_buf buf_cmd; + + if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) { + GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC); + if (!buf_p) { + GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); + return -1; + } + + GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_cmd.vaddr, buf_cmd.y_len); + +#if !defined(CONFIG_MSM_IOMMU) + buf_p->subsystem_id = kmalloc(sizeof(int), GFP_ATOMIC); + if (!buf_p->subsystem_id) { + GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); + kfree(buf_p); + return -ENOMEM; + } +#endif + buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd, + buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file, +#if !defined(CONFIG_MSM_IOMMU) + &buf_p->msm_buffer, buf_p->subsystem_id, &buf_p->handle) + + buf_cmd.offset; +#else + &buf_p->handle) + buf_cmd.offset; +#endif + buf_p->y_len = buf_cmd.y_len; + + buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len; + buf_p->cbcr_len = buf_cmd.cbcr_len; + + buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows; + + if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) { + GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); +#if !defined(CONFIG_MSM_IOMMU) + kfree(buf_p->subsystem_id); +#endif + kfree(buf_p); + return -1; + } + buf_p->vbuf = buf_cmd; + + msm_gemini_q_in(&pgmn_dev->input_buf_q, buf_p); + + return 0; +} + +int msm_gemini_irq(int event, void *context, void *data) +{ + struct msm_gemini_device *pgmn_dev = + (struct msm_gemini_device *) context; + + switch (event) { + case MSM_GEMINI_HW_MASK_COMP_FRAMEDONE: + msm_gemini_framedone_irq(pgmn_dev, data); + msm_gemini_we_pingpong_irq(pgmn_dev, data); + break; + + case MSM_GEMINI_HW_MASK_COMP_FE: + msm_gemini_fe_pingpong_irq(pgmn_dev, data); + break; + + case MSM_GEMINI_HW_MASK_COMP_WE: + msm_gemini_we_pingpong_irq(pgmn_dev, data); + break; + + case MSM_GEMINI_HW_MASK_COMP_RESET_ACK: + msm_gemini_reset_ack_irq(pgmn_dev); + break; + + case MSM_GEMINI_HW_MASK_COMP_ERR: + default: + msm_gemini_err_irq(pgmn_dev, event); + break; + } + + return 0; +} + +int __msm_gemini_open(struct msm_gemini_device *pgmn_dev) +{ + int rc; + + mutex_lock(&pgmn_dev->lock); + if (pgmn_dev->open_count) { + /* only open once */ + GMN_PR_ERR("%s:%d] busy\n", __func__, __LINE__); + mutex_unlock(&pgmn_dev->lock); + return -EBUSY; + } + pgmn_dev->open_count++; + mutex_unlock(&pgmn_dev->lock); + + msm_gemini_core_irq_install(msm_gemini_irq); + rc = msm_gemini_platform_init(pgmn_dev->pdev, + &pgmn_dev->mem, &pgmn_dev->base, + &pgmn_dev->irq, msm_gemini_core_irq, pgmn_dev); + if (rc) { + GMN_PR_ERR("%s:%d] platform_init fail %d\n", __func__, + __LINE__, rc); + return rc; + } + + GMN_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n", + __func__, __LINE__, + pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq); + + msm_gemini_q_cleanup(&pgmn_dev->evt_q); + msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q); + msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q); + msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q); + msm_gemini_q_cleanup(&pgmn_dev->input_buf_q); + msm_gemini_core_init(); + + GMN_DBG("%s:%d] success\n", __func__, __LINE__); + return rc; +} + +int __msm_gemini_release(struct msm_gemini_device *pgmn_dev) +{ + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + mutex_lock(&pgmn_dev->lock); + if (!pgmn_dev->open_count) { + GMN_PR_ERR(KERN_ERR "%s: not opened\n", __func__); + mutex_unlock(&pgmn_dev->lock); + return -EINVAL; + } + pgmn_dev->open_count--; + mutex_unlock(&pgmn_dev->lock); + + msm_gemini_core_release(release_buf); + msm_gemini_q_cleanup(&pgmn_dev->evt_q); + msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q); + msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q); + msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q); + msm_gemini_outbuf_q_cleanup(&pgmn_dev->input_buf_q); + + if (pgmn_dev->open_count) + GMN_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__); + + msm_gemini_platform_release(pgmn_dev->mem, pgmn_dev->base, + pgmn_dev->irq, pgmn_dev); + + return 0; +} + +int msm_gemini_ioctl_hw_cmd(struct msm_gemini_device *pgmn_dev, + void * __user arg) +{ + struct msm_gemini_hw_cmd hw_cmd; + int is_copy_to_user; + + if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_gemini_hw_cmd))) { + GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + is_copy_to_user = msm_gemini_hw_exec_cmds(&hw_cmd, 1); + GMN_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x, pdata %x\n", + __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset, + hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata); + + if (is_copy_to_user >= 0) { + if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) { + GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + } + + return 0; +} + +int msm_gemini_ioctl_hw_cmds(struct msm_gemini_device *pgmn_dev, + void * __user arg) +{ + int is_copy_to_user; + int len; + uint32_t m; + struct msm_gemini_hw_cmds *hw_cmds_p; + struct msm_gemini_hw_cmd *hw_cmd_p; + + if (copy_from_user(&m, arg, sizeof(m))) { + GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + len = sizeof(struct msm_gemini_hw_cmds) + + sizeof(struct msm_gemini_hw_cmd) * (m - 1); + hw_cmds_p = kmalloc(len, GFP_KERNEL); + if (!hw_cmds_p) { + GMN_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len); + return -EFAULT; + } + + if (copy_from_user(hw_cmds_p, arg, len)) { + GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + kfree(hw_cmds_p); + return -EFAULT; + } + + hw_cmd_p = (struct msm_gemini_hw_cmd *) &(hw_cmds_p->hw_cmd); + + is_copy_to_user = msm_gemini_hw_exec_cmds(hw_cmd_p, m); + + if (is_copy_to_user >= 0) { + if (copy_to_user(arg, hw_cmds_p, len)) { + GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + kfree(hw_cmds_p); + return -EFAULT; + } + } + kfree(hw_cmds_p); + return 0; +} + +int msm_gemini_start(struct msm_gemini_device *pgmn_dev, void * __user arg) +{ + struct msm_gemini_core_buf *buf_out; + struct msm_gemini_core_buf *buf_out_free[2] = {NULL, NULL}; + int i, rc; + + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + + release_buf = 1; + for (i = 0; i < 2; i++) { + buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q); + + if (buf_out) { + msm_gemini_core_fe_buf_update(buf_out); + kfree(buf_out); + } else { + GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__); + break; + } + } + + for (i = 0; i < 2; i++) { + buf_out_free[i] = msm_gemini_q_out(&pgmn_dev->output_buf_q); + + if (buf_out_free[i]) { + msm_gemini_core_we_buf_update(buf_out_free[i]); + } else if (i == 1) { + /* set the pong to same address as ping */ + buf_out_free[0]->y_len >>= 1; + buf_out_free[0]->y_buffer_addr += + buf_out_free[0]->y_len; + msm_gemini_core_we_buf_update(buf_out_free[0]); + /* since ping and pong are same buf release only once*/ + release_buf = 0; + } else { + GMN_DBG("%s:%d] no output buffer\n", + __func__, __LINE__); + break; + } + } + + for (i = 0; i < 2; i++) + kfree(buf_out_free[i]); + + rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, arg); + GMN_DBG("%s:%d]\n", __func__, __LINE__); + return rc; +} + +int msm_gemini_ioctl_reset(struct msm_gemini_device *pgmn_dev, + void * __user arg) +{ + int rc; + struct msm_gemini_ctrl_cmd ctrl_cmd; + + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) { + GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + pgmn_dev->op_mode = ctrl_cmd.type; + + rc = msm_gemini_core_reset(pgmn_dev->op_mode, pgmn_dev->base, + resource_size(pgmn_dev->mem)); + return rc; +} + +int msm_gemini_ioctl_test_dump_region(struct msm_gemini_device *pgmn_dev, + unsigned long arg) +{ + GMN_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_gemini_hw_region_dump(arg); + return 0; +} + +long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + switch (cmd) { + case MSM_GMN_IOCTL_GET_HW_VERSION: + GMN_DBG("%s:%d] VERSION 1\n", __func__, __LINE__); + rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_GMN_IOCTL_RESET: + rc = msm_gemini_ioctl_reset(pgmn_dev, (void __user *) arg); + break; + + case MSM_GMN_IOCTL_STOP: + rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + break; + + case MSM_GMN_IOCTL_START: + rc = msm_gemini_start(pgmn_dev, (void __user *) arg); + break; + + case MSM_GMN_IOCTL_INPUT_BUF_ENQUEUE: + rc = msm_gemini_input_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_GMN_IOCTL_INPUT_GET: + rc = msm_gemini_input_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_GMN_IOCTL_INPUT_GET_UNBLOCK: + rc = msm_gemini_input_get_unblock(pgmn_dev); + break; + + case MSM_GMN_IOCTL_OUTPUT_BUF_ENQUEUE: + rc = msm_gemini_output_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_GMN_IOCTL_OUTPUT_GET: + rc = msm_gemini_output_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_GMN_IOCTL_OUTPUT_GET_UNBLOCK: + rc = msm_gemini_output_get_unblock(pgmn_dev); + break; + + case MSM_GMN_IOCTL_EVT_GET: + rc = msm_gemini_evt_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_GMN_IOCTL_EVT_GET_UNBLOCK: + rc = msm_gemini_evt_get_unblock(pgmn_dev); + break; + + case MSM_GMN_IOCTL_HW_CMD: + rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_GMN_IOCTL_HW_CMDS: + rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + break; + + case MSM_GMN_IOCTL_TEST_DUMP_REGION: + rc = msm_gemini_ioctl_test_dump_region(pgmn_dev, arg); + break; + + default: + GMN_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n", + __func__, __LINE__, _IOC_NR(cmd)); + rc = -EINVAL; + break; + } + return rc; +} + +struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev) +{ + struct msm_gemini_device *pgmn_dev; + + pgmn_dev = kzalloc(sizeof(struct msm_gemini_device), GFP_ATOMIC); + if (!pgmn_dev) { + GMN_PR_ERR("%s:%d]no mem\n", __func__, __LINE__); + return NULL; + } + + mutex_init(&pgmn_dev->lock); + + pgmn_dev->pdev = pdev; + + msm_gemini_q_init("evt_q", &pgmn_dev->evt_q); + msm_gemini_q_init("output_rtn_q", &pgmn_dev->output_rtn_q); + msm_gemini_q_init("output_buf_q", &pgmn_dev->output_buf_q); + msm_gemini_q_init("input_rtn_q", &pgmn_dev->input_rtn_q); + msm_gemini_q_init("input_buf_q", &pgmn_dev->input_buf_q); + + return pgmn_dev; +} + +int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev) +{ + mutex_destroy(&pgmn_dev->lock); + kfree(pgmn_dev); + return 0; +} diff --git a/drivers/media/video/msm_zsl/gemini/msm_gemini_sync.h b/drivers/media/video/msm_zsl/gemini/msm_gemini_sync.h new file mode 100644 index 00000000000..6c69a9212d4 --- /dev/null +++ b/drivers/media/video/msm_zsl/gemini/msm_gemini_sync.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_GEMINI_SYNC_H +#define MSM_GEMINI_SYNC_H + +#include +#include +#include +#include +#include "msm_gemini_core.h" + +struct msm_gemini_q { + char const *name; + struct list_head q; + spinlock_t lck; + wait_queue_head_t wait; + int unblck; +}; + +struct msm_gemini_q_entry { + struct list_head list; + void *data; +}; + +struct msm_gemini_device { + struct platform_device *pdev; + struct resource *mem; + int irq; + void *base; + + struct device *device; + struct cdev cdev; + struct mutex lock; + char open_count; + uint8_t op_mode; + + /* event queue including frame done & err indications + */ + struct msm_gemini_q evt_q; + + /* output return queue + */ + struct msm_gemini_q output_rtn_q; + + /* output buf queue + */ + struct msm_gemini_q output_buf_q; + + /* input return queue + */ + struct msm_gemini_q input_rtn_q; + + /* input buf queue + */ + struct msm_gemini_q input_buf_q; +}; + +int __msm_gemini_open(struct msm_gemini_device *pgmn_dev); +int __msm_gemini_release(struct msm_gemini_device *pgmn_dev); + +long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev, + unsigned int cmd, unsigned long arg); + +struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev); +int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev); + +#endif /* MSM_GEMINI_SYNC_H */ diff --git a/drivers/media/video/msm_zsl/imx072.c b/drivers/media/video/msm_zsl/imx072.c new file mode 100644 index 00000000000..7e3417824f8 --- /dev/null +++ b/drivers/media/video/msm_zsl/imx072.c @@ -0,0 +1,1184 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "imx072.h" + +/* SENSOR REGISTER DEFINES */ +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD_OFF 0x00 +#define GROUPED_PARAMETER_HOLD 0x01 +/* Integration Time */ +#define REG_COARSE_INTEGRATION_TIME 0x0202 +/* Gain */ +#define REG_GLOBAL_GAIN 0x0204 + +/* PLL registers */ +#define REG_FRAME_LENGTH_LINES 0x0340 +#define REG_LINE_LENGTH_PCK 0x0342 + +/* 16bit address - 8 bit context register structure */ +#define Q8 0x00000100 +#define Q10 0x00000400 +#define IMX072_MASTER_CLK_RATE 24000000 +#define IMX072_OFFSET 3 + +/* AF Total steps parameters */ +#define IMX072_AF_I2C_ADDR 0x18 +#define IMX072_TOTAL_STEPS_NEAR_TO_FAR 30 + +static uint16_t imx072_step_position_table[IMX072_TOTAL_STEPS_NEAR_TO_FAR+1]; +static uint16_t imx072_nl_region_boundary1; +static uint16_t imx072_nl_region_code_per_step1; +static uint16_t imx072_l_region_code_per_step = 12; +static uint16_t imx072_sw_damping_time_wait = 8; +static uint16_t imx072_af_initial_code = 350; +static uint16_t imx072_damping_threshold = 10; + +struct imx072_work_t { + struct work_struct work; +}; + +static struct imx072_work_t *imx072_sensorw; +static struct i2c_client *imx072_client; + +struct imx072_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + + uint32_t sensormode; + uint32_t fps_divider;/* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */ + uint16_t fps; + + uint16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + + enum imx072_resolution_t prev_res; + enum imx072_resolution_t pict_res; + enum imx072_resolution_t curr_res; + enum imx072_test_mode_t set_test; + enum imx072_cam_mode_t cam_mode; +}; + +static uint16_t prev_line_length_pck; +static uint16_t prev_frame_length_lines; +static uint16_t snap_line_length_pck; +static uint16_t snap_frame_length_lines; + +static bool CSI_CONFIG; +static struct imx072_ctrl_t *imx072_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(imx072_wait_queue); +DEFINE_MUTEX(imx072_mut); + +#ifdef CONFIG_DEBUG_FS +static int cam_debug_init(void); +static struct dentry *debugfs_base; +#endif + +static int imx072_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + if (i2c_transfer(imx072_client->adapter, msgs, 2) < 0) { + pr_err("imx072_i2c_rxdata faild 0x%x\n", saddr); + return -EIO; + } + return 0; +} + +static int32_t imx072_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(imx072_client->adapter, msg, 1) < 0) { + pr_err("imx072_i2c_txdata faild 0x%x\n", saddr); + return -EIO; + } + + return 0; +} + +static int32_t imx072_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + rc = imx072_i2c_rxdata(imx072_client->addr>>1, buf, rlen); + if (rc < 0) { + pr_err("imx072_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + CDBG("imx072_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata); + return rc; +} + +static int32_t imx072_i2c_write_w_sensor(unsigned short waddr, + uint16_t wdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[4]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00) >> 8; + buf[3] = (wdata & 0x00FF); + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata); + rc = imx072_i2c_txdata(imx072_client->addr>>1, buf, 4); + if (rc < 0) { + pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + } + return rc; +} + +static int32_t imx072_i2c_write_b_sensor(unsigned short waddr, + uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[3]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata); + rc = imx072_i2c_txdata(imx072_client->addr>>1, buf, 3); + if (rc < 0) + pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + return rc; +} + +static int32_t imx072_i2c_write_b_af(uint8_t msb, uint8_t lsb) +{ + int32_t rc = -EFAULT; + unsigned char buf[2]; + + buf[0] = msb; + buf[1] = lsb; + rc = imx072_i2c_txdata(IMX072_AF_I2C_ADDR>>1, buf, 2); + if (rc < 0) + pr_err("af_i2c_write faield msb = 0x%x lsb = 0x%x", + msb, lsb); + return rc; +} + +static int32_t imx072_i2c_write_w_table(struct imx072_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + for (i = 0; i < num; i++) { + rc = imx072_i2c_write_b_sensor(reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +static void imx072_group_hold_on(void) +{ + imx072_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); +} + +static void imx072_group_hold_off(void) +{ + imx072_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF); +} + +static void imx072_start_stream(void) +{ + imx072_i2c_write_b_sensor(0x0100, 0x01); +} + +static void imx072_stop_stream(void) +{ + imx072_i2c_write_b_sensor(0x0100, 0x00); +} + +static void imx072_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint32_t divider, d1, d2; + + d1 = prev_frame_length_lines * 0x00000400 / snap_frame_length_lines; + d2 = prev_line_length_pck * 0x00000400 / snap_line_length_pck; + divider = d1 * d2 / 0x400; + + /*Verify PCLK settings and frame sizes.*/ + *pfps = (uint16_t) (fps * divider / 0x400); +} + +static uint16_t imx072_get_prev_lines_pf(void) +{ + return prev_frame_length_lines; +} + +static uint16_t imx072_get_prev_pixels_pl(void) +{ + return prev_line_length_pck; +} + +static uint16_t imx072_get_pict_lines_pf(void) +{ + return snap_frame_length_lines; +} + +static uint16_t imx072_get_pict_pixels_pl(void) +{ + return snap_line_length_pck; +} + +static uint32_t imx072_get_pict_max_exp_lc(void) +{ + return snap_frame_length_lines * 24; +} + +static int32_t imx072_set_fps(struct fps_cfg *fps) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + total_lines_per_frame = (uint16_t) + ((prev_frame_length_lines * + imx072_ctrl->fps_divider)/0x400); + imx072_ctrl->fps_divider = fps->fps_div; + imx072_ctrl->pict_fps_divider = fps->pict_fps_div; + + imx072_group_hold_on(); + rc = imx072_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES, + total_lines_per_frame); + imx072_group_hold_off(); + return rc; +} + +static int32_t imx072_write_exp_gain(uint16_t gain, uint32_t line) +{ + uint32_t fl_lines = 0; + uint8_t offset; + int32_t rc = 0; + if (imx072_ctrl->curr_res == imx072_ctrl->prev_res) + fl_lines = prev_frame_length_lines; + else if (imx072_ctrl->curr_res == imx072_ctrl->pict_res) + fl_lines = snap_frame_length_lines; + line = (line * imx072_ctrl->fps_divider) / Q10; + offset = IMX072_OFFSET; + if (line > (fl_lines - offset)) + fl_lines = line + offset; + + imx072_group_hold_on(); + rc = imx072_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES, fl_lines); + rc = imx072_i2c_write_w_sensor(REG_COARSE_INTEGRATION_TIME, line); + rc = imx072_i2c_write_w_sensor(REG_GLOBAL_GAIN, gain); + imx072_group_hold_off(); + return rc; +} + +static int32_t imx072_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + rc = imx072_write_exp_gain(gain, line); + return rc; +} + +static int32_t imx072_sensor_setting(int update_type, int rt) +{ + + int32_t rc = 0; + struct msm_camera_csi_params imx072_csi_params; + + imx072_stop_stream(); + msleep(30); + if (update_type == REG_INIT) { + msleep(20); + CSI_CONFIG = 0; + imx072_i2c_write_w_table(imx072_regs.rec_settings, + imx072_regs.rec_size); + } else if (update_type == UPDATE_PERIODIC) { +#ifdef CONFIG_DEBUG_FS + cam_debug_init(); +#endif + msleep(20); + if (!CSI_CONFIG) { + imx072_csi_params.lane_cnt = 2; + imx072_csi_params.data_format = CSI_10BIT; + imx072_csi_params.lane_assign = 0xe4; + imx072_csi_params.dpcm_scheme = 0; + imx072_csi_params.settle_cnt = 0x18; + msm_camio_vfe_clk_rate_set(192000000); + rc = msm_camio_csi_config(&imx072_csi_params); + msleep(100); + CSI_CONFIG = 1; + } + imx072_i2c_write_w_table( + imx072_regs.conf_array[rt].conf, + imx072_regs.conf_array[rt].size); + imx072_start_stream(); + msleep(30); + } + return rc; +} + +static int32_t imx072_video_config(int mode) +{ + + int32_t rc = 0; + /* change sensor resolution if needed */ + if (imx072_sensor_setting(UPDATE_PERIODIC, + imx072_ctrl->prev_res) < 0) + return rc; + + imx072_ctrl->curr_res = imx072_ctrl->prev_res; + imx072_ctrl->sensormode = mode; + return rc; +} + +static int32_t imx072_snapshot_config(int mode) +{ + int32_t rc = 0; + /*change sensor resolution if needed */ + if (imx072_ctrl->curr_res != imx072_ctrl->pict_res) { + if (imx072_sensor_setting(UPDATE_PERIODIC, + imx072_ctrl->pict_res) < 0) + return rc; + } + + imx072_ctrl->curr_res = imx072_ctrl->pict_res; + imx072_ctrl->sensormode = mode; + return rc; +} + +static int32_t imx072_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + /* change sensor resolution if needed */ + if (imx072_ctrl->curr_res != imx072_ctrl->pict_res) { + if (imx072_sensor_setting(UPDATE_PERIODIC, + imx072_ctrl->pict_res) < 0) + return rc; + } + + imx072_ctrl->curr_res = imx072_ctrl->pict_res; + imx072_ctrl->sensormode = mode; + return rc; +} + +static int32_t imx072_mode_init(int mode, struct sensor_init_cfg init_info) +{ + int32_t rc = 0; + CDBG("%s: %d\n", __func__, __LINE__); + if (mode != imx072_ctrl->cam_mode) { + imx072_ctrl->prev_res = init_info.prev_res; + imx072_ctrl->pict_res = init_info.pict_res; + imx072_ctrl->cam_mode = mode; + + prev_frame_length_lines = + imx072_regs.conf_array[imx072_ctrl->prev_res]. + conf[IMX072_FRAME_LENGTH_LINES_HI].wdata << 8 | + imx072_regs.conf_array[imx072_ctrl->prev_res]. + conf[IMX072_FRAME_LENGTH_LINES_LO].wdata; + prev_line_length_pck = + imx072_regs.conf_array[imx072_ctrl->prev_res]. + conf[IMX072_LINE_LENGTH_PCK_HI].wdata << 8 | + imx072_regs.conf_array[imx072_ctrl->prev_res]. + conf[IMX072_LINE_LENGTH_PCK_LO].wdata; + snap_frame_length_lines = + imx072_regs.conf_array[imx072_ctrl->pict_res]. + conf[IMX072_FRAME_LENGTH_LINES_HI].wdata << 8 | + imx072_regs.conf_array[imx072_ctrl->pict_res]. + conf[IMX072_FRAME_LENGTH_LINES_LO].wdata; + snap_line_length_pck = + imx072_regs.conf_array[imx072_ctrl->pict_res]. + conf[IMX072_LINE_LENGTH_PCK_HI].wdata << 8 | + imx072_regs.conf_array[imx072_ctrl->pict_res]. + conf[IMX072_LINE_LENGTH_PCK_LO].wdata; + + rc = imx072_sensor_setting(REG_INIT, + imx072_ctrl->prev_res); + } + return rc; +} + +static int32_t imx072_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + imx072_ctrl->prev_res = res; + rc = imx072_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + imx072_ctrl->pict_res = res; + rc = imx072_snapshot_config(mode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + imx072_ctrl->pict_res = res; + rc = imx072_raw_snapshot_config(mode); + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +#define DIV_CEIL(x, y) ((x/y + ((x%y) ? 1 : 0))) +static int32_t imx072_move_focus(int direction, + int32_t num_steps) +{ + int32_t rc = 0; + int16_t step_direction, dest_lens_position, dest_step_position; + uint8_t code_val_msb, code_val_lsb; + int16_t next_lens_position, target_dist, small_step; + + if (direction == MOVE_NEAR) + step_direction = 1; + else if (direction == MOVE_FAR) + step_direction = -1; + else { + pr_err("Illegal focus direction\n"); + return -EINVAL; + } + dest_step_position = imx072_ctrl->curr_step_pos + + (step_direction * num_steps); + + if (dest_step_position < 0) + dest_step_position = 0; + else if (dest_step_position > IMX072_TOTAL_STEPS_NEAR_TO_FAR) + dest_step_position = IMX072_TOTAL_STEPS_NEAR_TO_FAR; + + if (dest_step_position == imx072_ctrl->curr_step_pos) { + CDBG("imx072 same position No-Move exit\n"); + return rc; + } + CDBG("%s Index = [%d]\n", __func__, dest_step_position); + + dest_lens_position = imx072_step_position_table[dest_step_position]; + CDBG("%s lens_position value = %d\n", __func__, dest_lens_position); + target_dist = step_direction * (dest_lens_position - + imx072_ctrl->curr_lens_pos); + if (step_direction < 0 && (target_dist >= + (imx072_step_position_table[imx072_damping_threshold] + - imx072_af_initial_code))) { + small_step = DIV_CEIL(target_dist, 10); + imx072_sw_damping_time_wait = 30; + } else { + small_step = DIV_CEIL(target_dist, 4); + imx072_sw_damping_time_wait = 20; + } + + CDBG("%s: small_step:%d, wait_time:%d\n", __func__, small_step, + imx072_sw_damping_time_wait); + for (next_lens_position = imx072_ctrl->curr_lens_pos + + (step_direction * small_step); + (step_direction * next_lens_position) <= + (step_direction * dest_lens_position); + next_lens_position += (step_direction * small_step)) { + + code_val_msb = ((next_lens_position & 0x03F0) >> 4); + code_val_lsb = ((next_lens_position & 0x000F) << 4); + CDBG("position value = %d\n", next_lens_position); + CDBG("movefocus vcm_msb = %d\n", code_val_msb); + CDBG("movefocus vcm_lsb = %d\n", code_val_lsb); + rc = imx072_i2c_write_b_af(code_val_msb, code_val_lsb); + if (rc < 0) { + pr_err("imx072_move_focus failed writing i2c\n"); + return rc; + } + imx072_ctrl->curr_lens_pos = next_lens_position; + usleep(imx072_sw_damping_time_wait*100); + } + if (imx072_ctrl->curr_lens_pos != dest_lens_position) { + code_val_msb = ((dest_lens_position & 0x03F0) >> 4); + code_val_lsb = ((dest_lens_position & 0x000F) << 4); + CDBG("position value = %d\n", dest_lens_position); + CDBG("movefocus vcm_msb = %d\n", code_val_msb); + CDBG("movefocus vcm_lsb = %d\n", code_val_lsb); + rc = imx072_i2c_write_b_af(code_val_msb, code_val_lsb); + if (rc < 0) { + pr_err("imx072_move_focus failed writing i2c\n"); + return rc; + } + usleep(imx072_sw_damping_time_wait * 100); + } + imx072_ctrl->curr_lens_pos = dest_lens_position; + imx072_ctrl->curr_step_pos = dest_step_position; + return rc; + +} + +static int32_t imx072_init_focus(void) +{ + uint8_t i; + int32_t rc = 0; + + imx072_step_position_table[0] = imx072_af_initial_code; + for (i = 1; i <= IMX072_TOTAL_STEPS_NEAR_TO_FAR; i++) { + if (i <= imx072_nl_region_boundary1) + imx072_step_position_table[i] = + imx072_step_position_table[i-1] + + imx072_nl_region_code_per_step1; + else + imx072_step_position_table[i] = + imx072_step_position_table[i-1] + + imx072_l_region_code_per_step; + + if (imx072_step_position_table[i] > 1023) + imx072_step_position_table[i] = 1023; + } + imx072_ctrl->curr_lens_pos = 0; + + return rc; +} + +static int32_t imx072_set_default_focus(void) +{ + int32_t rc = 0; + uint8_t code_val_msb, code_val_lsb; + int16_t dest_lens_position = 0; + + CDBG("%s Index = [%d]\n", __func__, 0); + if (imx072_ctrl->curr_step_pos != 0) + rc = imx072_move_focus(MOVE_FAR, + imx072_ctrl->curr_step_pos); + else { + dest_lens_position = imx072_af_initial_code; + code_val_msb = ((dest_lens_position & 0x03F0) >> 4); + code_val_lsb = ((dest_lens_position & 0x000F) << 4); + + CDBG("position value = %d\n", dest_lens_position); + CDBG("movefocus vcm_msb = %d\n", code_val_msb); + CDBG("movefocus vcm_lsb = %d\n", code_val_lsb); + rc = imx072_i2c_write_b_af(code_val_msb, code_val_lsb); + if (rc < 0) { + pr_err("imx072_set_default_focus failed writing i2c\n"); + return rc; + } + + imx072_ctrl->curr_lens_pos = dest_lens_position; + imx072_ctrl->curr_step_pos = 0; + + } + usleep(5000); + return rc; +} + +static int32_t imx072_af_power_down(void) +{ + int32_t rc = 0; + int32_t i = 0; + int16_t dest_lens_position = imx072_af_initial_code; + + if (imx072_ctrl->curr_lens_pos != 0) { + rc = imx072_set_default_focus(); + CDBG("%s after imx072_set_default_focus\n", __func__); + msleep(40); + /*to avoid the sound during the power off. + brings the actuator to mechanical infinity gradually.*/ + for (i = 0; i < IMX072_TOTAL_STEPS_NEAR_TO_FAR; i++) { + dest_lens_position = dest_lens_position - + (imx072_af_initial_code / + IMX072_TOTAL_STEPS_NEAR_TO_FAR); + CDBG("position value = %d\n", dest_lens_position); + rc = imx072_i2c_write_b_af( + ((dest_lens_position & 0x03F0) >> 4), + ((dest_lens_position & 0x000F) << 4)); + CDBG("count = %d\n", i); + msleep(20); + if (rc < 0) { + pr_err("imx072_set_default_focus failed writing i2c\n"); + return rc; + } + } + rc = imx072_i2c_write_b_af(0x00, 00); + msleep(40); + } + rc = imx072_i2c_write_b_af(0x80, 00); + return rc; +} + +static int32_t imx072_power_down(void) +{ + int32_t rc = 0; + + rc = imx072_af_power_down(); + return rc; +} + +static int imx072_probe_init_done(const struct msm_camera_sensor_info *data) +{ + pr_err("probe done\n"); + gpio_free(data->sensor_reset); + return 0; +} + +static int imx072_probe_init_sensor( + const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + uint16_t chipid = 0; + + CDBG("%s: %d\n", __func__, __LINE__); + rc = gpio_request(data->sensor_reset, "imx072"); + CDBG(" imx072_probe_init_sensor\n"); + if (!rc) { + pr_err("sensor_reset = %d\n", rc); + gpio_direction_output(data->sensor_reset, 0); + msleep(50); + gpio_set_value_cansleep(data->sensor_reset, 1); + msleep(20); + } else + goto gpio_req_fail; + + CDBG(" imx072_probe_init_sensor is called\n"); + rc = imx072_i2c_read(0x0, &chipid, 2); + CDBG("ID: %d\n", chipid); + /* 4. Compare sensor ID to IMX072 ID: */ + if (chipid != 0x0045) { + rc = -ENODEV; + pr_err("imx072_probe_init_sensor chip id doesnot match\n"); + goto init_probe_fail; + } + + return rc; +init_probe_fail: + pr_err(" imx072_probe_init_sensor fails\n"); + gpio_set_value_cansleep(data->sensor_reset, 0); + imx072_probe_init_done(data); + if (data->vcm_enable) { + int ret = gpio_request(data->vcm_pwd, "imx072_af"); + if (!ret) { + gpio_direction_output(data->vcm_pwd, 0); + msleep(20); + gpio_free(data->vcm_pwd); + } + } +gpio_req_fail: + return rc; +} + +int imx072_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + + CDBG("%s: %d\n", __func__, __LINE__); + imx072_ctrl = kzalloc(sizeof(struct imx072_ctrl_t), GFP_KERNEL); + if (!imx072_ctrl) { + pr_err("imx072_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + imx072_ctrl->fps_divider = 1 * 0x00000400; + imx072_ctrl->pict_fps_divider = 1 * 0x00000400; + imx072_ctrl->set_test = TEST_OFF; + imx072_ctrl->cam_mode = MODE_INVALID; + + if (data) + imx072_ctrl->sensordata = data; + if (rc < 0) { + pr_err("Calling imx072_sensor_open_init fail1\n"); + return rc; + } + CDBG("%s: %d\n", __func__, __LINE__); + /* enable mclk first */ + msm_camio_clk_rate_set(IMX072_MASTER_CLK_RATE); + rc = imx072_probe_init_sensor(data); + if (rc < 0) + goto init_fail; + + imx072_init_focus(); + imx072_ctrl->fps = 30*Q8; + if (rc < 0) { + gpio_set_value_cansleep(data->sensor_reset, 0); + goto init_fail; + } else + goto init_done; +init_fail: + pr_err("init_fail\n"); + imx072_probe_init_done(data); +init_done: + pr_err("init_done\n"); + return rc; +} + +static int imx072_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&imx072_wait_queue); + return 0; +} + +static const struct i2c_device_id imx072_i2c_id[] = { + {"imx072", 0}, + { } +}; + +static int imx072_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("imx072_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("i2c_check_functionality failed\n"); + goto probe_failure; + } + + imx072_sensorw = kzalloc(sizeof(struct imx072_work_t), + GFP_KERNEL); + if (!imx072_sensorw) { + pr_err("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, imx072_sensorw); + imx072_init_client(client); + imx072_client = client; + + msleep(50); + + CDBG("imx072_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + pr_err("imx072_probe failed! rc = %d\n", rc); + return rc; +} + +static int imx072_send_wb_info(struct wb_info_cfg *wb) +{ + return 0; + +} + +static int __exit imx072_remove(struct i2c_client *client) +{ + struct imx072_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + imx072_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver imx072_i2c_driver = { + .id_table = imx072_i2c_id, + .probe = imx072_i2c_probe, + .remove = __exit_p(imx072_i2c_remove), + .driver = { + .name = "imx072", + }, +}; + +int imx072_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&imx072_mut); + CDBG("imx072_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + imx072_get_pict_fps( + cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = + imx072_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = + imx072_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = + imx072_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + imx072_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + imx072_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = imx072_set_fps(&(cdata.cfg.fps)); + break; + case CFG_SET_EXP_GAIN: + rc = imx072_write_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + case CFG_SET_PICT_EXP_GAIN: + rc = imx072_set_pict_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + case CFG_SET_MODE: + rc = imx072_set_sensor_mode(cdata.mode, cdata.rs); + break; + case CFG_PWR_DOWN: + rc = imx072_power_down(); + break; + case CFG_MOVE_FOCUS: + rc = imx072_move_focus(cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + case CFG_SET_DEFAULT_FOCUS: + imx072_set_default_focus(); + break; + case CFG_GET_AF_MAX_STEPS: + cdata.max_steps = IMX072_TOTAL_STEPS_NEAR_TO_FAR; + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_SET_EFFECT: + break; + case CFG_SEND_WB_INFO: + rc = imx072_send_wb_info( + &(cdata.cfg.wb_info)); + break; + case CFG_SENSOR_INIT: + rc = imx072_mode_init(cdata.mode, + cdata.cfg.init_info); + break; + case CFG_SET_LENS_SHADING: + break; + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&imx072_mut); + + return rc; +} + +static int imx072_sensor_release(void) +{ + int rc = -EBADF; + mutex_lock(&imx072_mut); + imx072_power_down(); + gpio_set_value_cansleep(imx072_ctrl->sensordata->sensor_reset, 0); + msleep(20); + gpio_free(imx072_ctrl->sensordata->sensor_reset); + if (imx072_ctrl->sensordata->vcm_enable) { + gpio_set_value_cansleep(imx072_ctrl->sensordata->vcm_pwd, 0); + gpio_free(imx072_ctrl->sensordata->vcm_pwd); + } + kfree(imx072_ctrl); + imx072_ctrl = NULL; + pr_err("imx072_release completed\n"); + mutex_unlock(&imx072_mut); + + return rc; +} + +static int imx072_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(&imx072_i2c_driver); + if (rc < 0 || imx072_client == NULL) { + rc = -ENOTSUPP; + pr_err("I2C add driver failed"); + goto probe_fail; + } + msm_camio_clk_rate_set(IMX072_MASTER_CLK_RATE); + rc = imx072_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + s->s_init = imx072_sensor_open_init; + s->s_release = imx072_sensor_release; + s->s_config = imx072_sensor_config; + s->s_mount_angle = info->sensor_platform_info->mount_angle; + + gpio_set_value_cansleep(info->sensor_reset, 0); + imx072_probe_init_done(info); + if (info->vcm_enable) { + rc = gpio_request(info->vcm_pwd, "imx072_af"); + if (!rc) { + gpio_direction_output(info->vcm_pwd, 0); + msleep(20); + gpio_free(info->vcm_pwd); + } else + return rc; + } + pr_info("imx072_sensor_probe : SUCCESS\n"); + return rc; + +probe_fail: + pr_err("imx072_sensor_probe: SENSOR PROBE FAILS!\n"); + return rc; +} + +static int __imx072_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, imx072_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __imx072_probe, + .driver = { + .name = "msm_camera_imx072", + .owner = THIS_MODULE, + }, +}; + +static int __init imx072_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(imx072_init); +void imx072_exit(void) +{ + i2c_del_driver(&imx072_i2c_driver); +} +MODULE_DESCRIPTION("Aptina 8 MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); + +#ifdef CONFIG_DEBUG_FS +static bool streaming = 1; + +static int cam_debug_stream_set(void *data, u64 val) +{ + int rc = 0; + + if (val) { + imx072_start_stream(); + streaming = 1; + } else { + imx072_stop_stream(); + streaming = 0; + } + + return rc; +} + +static int cam_debug_stream_get(void *data, u64 *val) +{ + *val = streaming; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(cam_stream, cam_debug_stream_get, + cam_debug_stream_set, "%llu\n"); + + + +static int imx072_set_af_codestep(void *data, u64 val) +{ + imx072_l_region_code_per_step = val; + imx072_init_focus(); + return 0; +} + +static int imx072_get_af_codestep(void *data, u64 *val) +{ + *val = imx072_l_region_code_per_step; + return 0; +} + +static uint16_t imx072_linear_total_step = IMX072_TOTAL_STEPS_NEAR_TO_FAR; +static int imx072_set_linear_total_step(void *data, u64 val) +{ + imx072_linear_total_step = val; + return 0; +} + +static int imx072_af_linearity_test(void *data, u64 *val) +{ + int i = 0; + + imx072_set_default_focus(); + msleep(3000); + for (i = 0; i < imx072_linear_total_step; i++) { + imx072_move_focus(MOVE_NEAR, 1); + CDBG("moved to index =[%d]\n", i); + msleep(1000); + } + + for (i = 0; i < imx072_linear_total_step; i++) { + imx072_move_focus(MOVE_FAR, 1); + CDBG("moved to index =[%d]\n", i); + msleep(1000); + } + return 0; +} + +static uint16_t imx072_step_val = IMX072_TOTAL_STEPS_NEAR_TO_FAR; +static uint8_t imx072_step_dir = MOVE_NEAR; +static int imx072_af_step_config(void *data, u64 val) +{ + imx072_step_val = val & 0xFFFF; + imx072_step_dir = (val >> 16) & 0x1; + return 0; +} + +static int imx072_af_step(void *data, u64 *val) +{ + int i = 0; + int dir = MOVE_NEAR; + imx072_set_default_focus(); + msleep(3000); + if (imx072_step_dir == 1) + dir = MOVE_FAR; + + for (i = 0; i < imx072_step_val; i += 4) { + imx072_move_focus(dir, 4); + msleep(1000); + } + imx072_set_default_focus(); + msleep(3000); + return 0; +} + +static int imx072_af_set_resolution(void *data, u64 val) +{ + imx072_init_focus(); + return 0; +} + +static int imx072_af_get_resolution(void *data, u64 *val) +{ + *val = 0xFF; + return 0; +} + + + +DEFINE_SIMPLE_ATTRIBUTE(af_codeperstep, imx072_get_af_codestep, + imx072_set_af_codestep, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(af_linear, imx072_af_linearity_test, + imx072_set_linear_total_step, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(af_step, imx072_af_step, + imx072_af_step_config, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(af_step_res, imx072_af_get_resolution, + imx072_af_set_resolution, "%llu\n"); + +static int cam_debug_init(void) +{ + struct dentry *cam_dir; + debugfs_base = debugfs_create_dir("sensor", NULL); + if (!debugfs_base) + return -ENOMEM; + + cam_dir = debugfs_create_dir("imx072", debugfs_base); + if (!cam_dir) + return -ENOMEM; + + if (!debugfs_create_file("stream", S_IRUGO | S_IWUSR, cam_dir, + NULL, &cam_stream)) + return -ENOMEM; + + if (!debugfs_create_file("af_codeperstep", S_IRUGO | S_IWUSR, cam_dir, + NULL, &af_codeperstep)) + return -ENOMEM; + if (!debugfs_create_file("af_linear", S_IRUGO | S_IWUSR, cam_dir, + NULL, &af_linear)) + return -ENOMEM; + if (!debugfs_create_file("af_step", S_IRUGO | S_IWUSR, cam_dir, + NULL, &af_step)) + return -ENOMEM; + + if (!debugfs_create_file("af_step_res", S_IRUGO | S_IWUSR, cam_dir, + NULL, &af_step_res)) + return -ENOMEM; + + return 0; +} +#endif diff --git a/drivers/media/video/msm_zsl/imx072.h b/drivers/media/video/msm_zsl/imx072.h new file mode 100644 index 00000000000..e3d279fe353 --- /dev/null +++ b/drivers/media/video/msm_zsl/imx072.h @@ -0,0 +1,79 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef IMX072_H +#define IMX072_H +#include +#include +extern struct imx072_reg imx072_regs; + +struct imx072_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +struct imx072_i2c_conf_array { + struct imx072_i2c_reg_conf *conf; + unsigned short size; +}; + +enum imx072_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum imx072_resolution_t { + QTR_2D_SIZE, + FULL_2D_SIZE, + QTR_3D_SIZE, + FULL_3D_SIZE, + INVALID_SIZE +}; +enum imx072_setting { + RES_PREVIEW, + RES_CAPTURE, + RES_3D_PREVIEW, + RES_3D_CAPTURE +}; +enum imx072_cam_mode_t { + MODE_2D_RIGHT, + MODE_2D_LEFT, + MODE_3D, + MODE_INVALID +}; +enum imx072_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum imx072_reg_mode { + IMX072_FRAME_LENGTH_LINES_HI = 0, + IMX072_FRAME_LENGTH_LINES_LO, + IMX072_LINE_LENGTH_PCK_HI, + IMX072_LINE_LENGTH_PCK_LO, +}; + +struct imx072_reg { + const struct imx072_i2c_reg_conf *rec_settings; + const unsigned short rec_size; + const struct imx072_i2c_conf_array *conf_array; +}; +#endif /* IMX072_H */ diff --git a/drivers/media/video/msm_zsl/imx072_reg.c b/drivers/media/video/msm_zsl/imx072_reg.c new file mode 100644 index 00000000000..ea7554815b7 --- /dev/null +++ b/drivers/media/video/msm_zsl/imx072_reg.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "imx072.h" + +struct imx072_i2c_reg_conf imx072_prev_settings[] = { + {0x0340, 0x03},/*frame_length*/ + {0x0341, 0xF7},/*frame_length*/ + {0x0342, 0x0A},/*line_length*/ + {0x0343, 0xE0},/*line_length*/ + {0x0344, 0x00},/*x_addr_start*/ + {0x0345, 0x00},/*x_addr_start*/ + {0x0346, 0x00},/*y_addr_start*/ + {0x0347, 0x00},/*y_addr_start*/ + {0x0348, 0x0A},/*x_addr_end*/ + {0x0349, 0x2F},/*x_addr_end*/ + {0x034A, 0x07},/*y_addr_end*/ + {0x034B, 0xA7},/*y_addr_end*/ + {0x034C, 0x05},/*x_out_size*/ + {0x034D, 0x18},/*x_out_size*/ + {0x034E, 0x03},/*y_out_size*/ + {0x034F, 0xD4},/*y_out_size*/ + {0x0381, 0x01},/*x_even_inc*/ + {0x0383, 0x03},/*x_odd_inc*/ + {0x0385, 0x01},/*y_even_inc*/ + {0x0387, 0x03},/*y_odd_inc*/ + {0x3016, 0x06},/*VMODEADD*/ + {0x3017, 0x40}, + {0x3069, 0x24}, + {0x306A, 0x00}, + {0x306B, 0xCB}, + {0x306C, 0x07}, + {0x30E8, 0x86}, + {0x3304, 0x03}, + {0x3305, 0x02}, + {0x3306, 0x0A}, + {0x3307, 0x02}, + {0x3308, 0x11}, + {0x3309, 0x04}, + {0x330A, 0x05}, + {0x330B, 0x04}, + {0x330C, 0x05}, + {0x330D, 0x04}, + {0x330E, 0x01}, + {0x3301, 0x80}, +}; + +struct imx072_i2c_reg_conf imx072_snap_settings[] = { + {0x0340, 0x07},/*frame_length*/ + {0x0341, 0xEE},/*frame_length*/ + {0x0342, 0x0A},/*line_length*/ + {0x0343, 0xE0},/*line_length*/ + {0x0344, 0x00},/*x_addr_start*/ + {0x0345, 0x00},/*x_addr_start*/ + {0x0346, 0x00},/*y_addr_start*/ + {0x0347, 0x00},/*y_addr_start*/ + {0x0348, 0x0A},/*x_addr_end*/ + {0x0349, 0x2F},/*x_addr_end*/ + {0x034A, 0x07},/*y_addr_end*/ + {0x034B, 0xA7},/*y_addr_end*/ + {0x034C, 0x0A},/*x_out_size*/ + {0x034D, 0x30},/*x_out_size*/ + {0x034E, 0x07},/*y_out_size*/ + {0x034F, 0xA8},/*y_out_size*/ + {0x0381, 0x01},/*x_even_inc*/ + {0x0383, 0x01},/*x_odd_inc*/ + {0x0385, 0x01},/*y_even_inc*/ + {0x0387, 0x01},/*y_odd_inc*/ + {0x3016, 0x06},/*VMODEADD*/ + {0x3017, 0x40}, + {0x3069, 0x24}, + {0x306A, 0x00}, + {0x306B, 0xCB}, + {0x306C, 0x07}, + {0x30E8, 0x06}, + {0x3304, 0x05}, + {0x3305, 0x04}, + {0x3306, 0x15}, + {0x3307, 0x02}, + {0x3308, 0x11}, + {0x3309, 0x07}, + {0x330A, 0x05}, + {0x330B, 0x04}, + {0x330C, 0x05}, + {0x330D, 0x04}, + {0x330E, 0x01}, + {0x3301, 0x00}, +}; + +struct imx072_i2c_reg_conf imx072_recommend_settings[] = { + {0x0307, 0x12}, + {0x302B, 0x4B}, + {0x0101, 0x03}, + {0x300A, 0x80}, + {0x3014, 0x08}, + {0x3015, 0x37}, + {0x3017, 0x40}, + {0x301C, 0x01}, + {0x3031, 0x28}, + {0x3040, 0x00}, + {0x3041, 0x60}, + {0x3051, 0x24}, + {0x3053, 0x34}, + {0x3055, 0x3B}, + {0x3057, 0xC0}, + {0x3060, 0x30}, + {0x3065, 0x00}, + {0x30AA, 0x88}, + {0x30AB, 0x1C}, + {0x30B0, 0x32}, + {0x30B2, 0x83}, + {0x30D3, 0x04}, + {0x310E, 0xDD}, + {0x31A4, 0xD8}, + {0x31A6, 0x17}, + {0x31AC, 0xCF}, + {0x31AE, 0xF1}, + {0x31B4, 0xD8}, + {0x31B6, 0x17}, + {0x3304, 0x05}, + {0x3305, 0x04}, + {0x3306, 0x15}, + {0x3307, 0x02}, + {0x3308, 0x11}, + {0x3309, 0x07}, + {0x330A, 0x05}, + {0x330B, 0x04}, + {0x330C, 0x05}, + {0x330D, 0x04}, + {0x330E, 0x01}, + {0x30d8, 0x20}, +}; + +struct imx072_i2c_conf_array imx072_confs[] = { + {&imx072_prev_settings[0], ARRAY_SIZE(imx072_prev_settings)}, + {&imx072_snap_settings[0], ARRAY_SIZE(imx072_snap_settings)}, +}; + +struct imx072_reg imx072_regs = { + .rec_settings = &imx072_recommend_settings[0], + .rec_size = ARRAY_SIZE(imx072_recommend_settings), + .conf_array = &imx072_confs[0], +}; diff --git a/drivers/media/video/msm_zsl/imx074.c b/drivers/media/video/msm_zsl/imx074.c new file mode 100644 index 00000000000..b84dac6233c --- /dev/null +++ b/drivers/media/video/msm_zsl/imx074.c @@ -0,0 +1,1413 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "imx074.h" + +/*SENSOR REGISTER DEFINES*/ +#define IMX074_EEPROM_SLAVE_ADDR 0x52 +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD_OFF 0x00 +#define GROUPED_PARAMETER_HOLD 0x01 +#define REG_MODE_SELECT 0x100 +#define MODE_SELECT_STANDBY_MODE 0x00 +#define MODE_SELECT_STREAM 0x01 +/* Integration Time */ +#define REG_COARSE_INTEGRATION_TIME_HI 0x0202 +#define REG_COARSE_INTEGRATION_TIME_LO 0x0203 +/* Gain */ +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204 +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205 +/* PLL registers */ +#define REG_PLL_MULTIPLIER 0x0307 +#define REG_PRE_PLL_CLK_DIV 0x0305 +#define REG_PLSTATIM 0x302b +#define REG_3024 0x3024 +#define REG_IMAGE_ORIENTATION 0x0101 +#define REG_VNDMY_ABLMGSHLMT 0x300a +#define REG_Y_OPBADDR_START_DI 0x3014 +#define REG_3015 0x3015 +#define REG_301C 0x301C +#define REG_302C 0x302C +#define REG_3031 0x3031 +#define REG_3041 0x3041 +#define REG_3051 0x3051 +#define REG_3053 0x3053 +#define REG_3057 0x3057 +#define REG_305C 0x305C +#define REG_305D 0x305D +#define REG_3060 0x3060 +#define REG_3065 0x3065 +#define REG_30AA 0x30AA +#define REG_30AB 0x30AB +#define REG_30B0 0x30B0 +#define REG_30B2 0x30B2 +#define REG_30D3 0x30D3 +#define REG_3106 0x3106 +#define REG_310C 0x310C +#define REG_3304 0x3304 +#define REG_3305 0x3305 +#define REG_3306 0x3306 +#define REG_3307 0x3307 +#define REG_3308 0x3308 +#define REG_3309 0x3309 +#define REG_330A 0x330A +#define REG_330B 0x330B +#define REG_330C 0x330C +#define REG_330D 0x330D +#define REG_330F 0x330F +#define REG_3381 0x3381 + +/* mode setting */ +#define REG_FRAME_LENGTH_LINES_HI 0x0340 +#define REG_FRAME_LENGTH_LINES_LO 0x0341 +#define REG_YADDR_START 0x0347 +#define REG_YAAAR_END 0x034b +#define REG_X_OUTPUT_SIZE_MSB 0x034c +#define REG_X_OUTPUT_SIZE_LSB 0x034d +#define REG_Y_OUTPUT_SIZE_MSB 0x034e +#define REG_Y_OUTPUT_SIZE_LSB 0x034f +#define REG_X_EVEN_INC 0x0381 +#define REG_X_ODD_INC 0x0383 +#define REG_Y_EVEN_INC 0x0385 +#define REG_Y_ODD_INC 0x0387 +#define REG_HMODEADD 0x3001 +#define REG_VMODEADD 0x3016 +#define REG_VAPPLINE_START 0x3069 +#define REG_VAPPLINE_END 0x306b +#define REG_SHUTTER 0x3086 +#define REG_HADDAVE 0x30e8 +#define REG_LANESEL 0x3301 +/* Test Pattern */ +#define REG_TEST_PATTERN_MODE 0x0601 + +#define REG_LINE_LENGTH_PCK_HI 0x0342 +#define REG_LINE_LENGTH_PCK_LO 0x0343 +/*..... TYPE DECLARATIONS.....*/ +#define IMX074_OFFSET 3 +#define IMX074_DEFAULT_MASTER_CLK_RATE 24000000 +/* Full Size */ +#define IMX074_FULL_SIZE_WIDTH 4208 +#define IMX074_FULL_SIZE_HEIGHT 3120 +#define IMX074_FULL_SIZE_DUMMY_PIXELS 0 +#define IMX074_FULL_SIZE_DUMMY_LINES 0 +/* Quarter Size */ +#define IMX074_QTR_SIZE_WIDTH 2104 +#define IMX074_QTR_SIZE_HEIGHT 1560 +#define IMX074_QTR_SIZE_DUMMY_PIXELS 0 +#define IMX074_QTR_SIZE_DUMMY_LINES 0 +/* Blanking as measured on the scope */ +/* Full Size */ +#define IMX074_HRZ_FULL_BLK_PIXELS 264 +#define IMX074_VER_FULL_BLK_LINES 96 +/* Quarter Size */ +#define IMX074_HRZ_QTR_BLK_PIXELS 2368 +#define IMX074_VER_QTR_BLK_LINES 21 +#define Q8 0x100 +#define Q10 0x400 +#define IMX074_AF_I2C_SLAVE_ID 0x72 +#define IMX074_STEPS_NEAR_TO_CLOSEST_INF 52 +#define IMX074_TOTAL_STEPS_NEAR_TO_FAR 52 +static uint32_t imx074_l_region_code_per_step = 2; + +struct imx074_work_t { + struct work_struct work; +}; + +static struct imx074_work_t *imx074_sensorw; +static struct i2c_client *imx074_client; + +struct imx074_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + uint32_t sensormode; + uint32_t fps_divider;/* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */ + uint16_t fps; + int16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + enum imx074_resolution_t prev_res; + enum imx074_resolution_t pict_res; + enum imx074_resolution_t curr_res; + enum imx074_test_mode_t set_test; + unsigned short imgaddr; +}; +static uint8_t imx074_delay_msecs_stdby = 5; +static uint16_t imx074_delay_msecs_stream = 5; +static int32_t config_csi; + +static struct imx074_ctrl_t *imx074_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(imx074_wait_queue); +DEFINE_MUTEX(imx074_mut); + +/*=============================================================*/ + +static int imx074_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 2, + .buf = rxdata, + }, + }; + if (i2c_transfer(imx074_client->adapter, msgs, 2) < 0) { + CDBG("imx074_i2c_rxdata failed!\n"); + return -EIO; + } + return 0; +} +static int32_t imx074_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(imx074_client->adapter, msg, 1) < 0) { + CDBG("imx074_i2c_txdata faild 0x%x\n", imx074_client->addr); + return -EIO; + } + + return 0; +} + + +static int32_t imx074_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + rc = imx074_i2c_rxdata(imx074_client->addr, buf, rlen); + if (rc < 0) { + CDBG("imx074_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + return rc; +} + +static int imx074_af_i2c_rxdata_b(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 1, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 1, + .buf = rxdata, + }, + }; + + if (i2c_transfer(imx074_client->adapter, msgs, 2) < 0) { + CDBG("imx074_i2c_rxdata_b failed!\n"); + return -EIO; + } + + return 0; +} + +static int32_t imx074_i2c_read_w_eeprom(unsigned short raddr, + unsigned short *rdata) +{ + int32_t rc; + unsigned char buf; + if (!rdata) + return -EIO; + /* Read 2 bytes in sequence */ + buf = (raddr & 0x00FF); + rc = imx074_af_i2c_rxdata_b(IMX074_EEPROM_SLAVE_ADDR, &buf, 1); + if (rc < 0) { + CDBG("imx074_i2c_read_eeprom 0x%x failed!\n", raddr); + return rc; + } + *rdata = buf<<8; + + /* Read Second byte of data */ + buf = (raddr & 0x00FF) + 1; + rc = imx074_af_i2c_rxdata_b(IMX074_EEPROM_SLAVE_ADDR, &buf, 1); + if (rc < 0) { + CDBG("imx074_i2c_read_eeprom 0x%x failed!\n", raddr); + return rc; + } + *rdata |= buf; + return rc; +} + +static int32_t imx074_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[3]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata); + rc = imx074_i2c_txdata(imx074_client->addr, buf, 3); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + return rc; +} +static int16_t imx074_i2c_write_b_af(unsigned short saddr, + unsigned short baddr, unsigned short bdata) +{ + int32_t rc; + unsigned char buf[2]; + memset(buf, 0, sizeof(buf)); + buf[0] = baddr; + buf[1] = bdata; + rc = imx074_i2c_txdata(saddr, buf, 2); + if (rc < 0) + CDBG("AFi2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!", + saddr, baddr, bdata); + return rc; +} + +static int32_t imx074_i2c_write_w_table(struct imx074_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + for (i = 0; i < num; i++) { + rc = imx074_i2c_write_b_sensor(reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} +static int16_t imx074_af_init(void) +{ + int32_t rc; + /* Initialize waveform */ + rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x01, 0xA9); + rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x02, 0xD2); + rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x03, 0x0C); + rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x04, 0x14); + rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x05, 0xB6); + rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x06, 0x4F); + return rc; +} + +static void imx074_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint16_t preview_frame_length_lines, snapshot_frame_length_lines; + uint32_t divider, d1; + uint32_t pclk_mult;/*Q10 */ + /* Total frame_length_lines and line_length_pck for preview */ + preview_frame_length_lines = IMX074_QTR_SIZE_HEIGHT + + IMX074_VER_QTR_BLK_LINES; + /* Total frame_length_lines and line_length_pck for snapshot */ + snapshot_frame_length_lines = IMX074_FULL_SIZE_HEIGHT + + IMX074_VER_FULL_BLK_LINES; + d1 = preview_frame_length_lines * 0x00010000 / + snapshot_frame_length_lines; + pclk_mult = + (uint32_t) ((imx074_regs.reg_pat[RES_CAPTURE].pll_multiplier * + 0x00010000) / + (imx074_regs.reg_pat[RES_PREVIEW].pll_multiplier)); + divider = d1 * pclk_mult / 0x00010000; + *pfps = (uint16_t) (fps * divider / 0x00010000); +} + +static uint16_t imx074_get_prev_lines_pf(void) +{ + if (imx074_ctrl->prev_res == QTR_SIZE) + return IMX074_QTR_SIZE_HEIGHT + IMX074_VER_QTR_BLK_LINES; + else + return IMX074_FULL_SIZE_HEIGHT + IMX074_VER_FULL_BLK_LINES; + +} + +static uint16_t imx074_get_prev_pixels_pl(void) +{ + if (imx074_ctrl->prev_res == QTR_SIZE) + return IMX074_QTR_SIZE_WIDTH + IMX074_HRZ_QTR_BLK_PIXELS; + else + return IMX074_FULL_SIZE_WIDTH + IMX074_HRZ_FULL_BLK_PIXELS; +} + +static uint16_t imx074_get_pict_lines_pf(void) +{ + if (imx074_ctrl->pict_res == QTR_SIZE) + return IMX074_QTR_SIZE_HEIGHT + + IMX074_VER_QTR_BLK_LINES; + else + return IMX074_FULL_SIZE_HEIGHT + + IMX074_VER_FULL_BLK_LINES; +} + +static uint16_t imx074_get_pict_pixels_pl(void) +{ + if (imx074_ctrl->pict_res == QTR_SIZE) + return IMX074_QTR_SIZE_WIDTH + + IMX074_HRZ_QTR_BLK_PIXELS; + else + return IMX074_FULL_SIZE_WIDTH + + IMX074_HRZ_FULL_BLK_PIXELS; +} + +static uint32_t imx074_get_pict_max_exp_lc(void) +{ + if (imx074_ctrl->pict_res == QTR_SIZE) + return (IMX074_QTR_SIZE_HEIGHT + + IMX074_VER_QTR_BLK_LINES)*24; + else + return (IMX074_FULL_SIZE_HEIGHT + + IMX074_VER_FULL_BLK_LINES)*24; +} + +static int32_t imx074_set_fps(struct fps_cfg *fps) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + imx074_ctrl->fps_divider = fps->fps_div; + imx074_ctrl->pict_fps_divider = fps->pict_fps_div; + if (imx074_ctrl->curr_res == QTR_SIZE) { + total_lines_per_frame = (uint16_t)(((IMX074_QTR_SIZE_HEIGHT + + IMX074_VER_QTR_BLK_LINES) * + imx074_ctrl->fps_divider) / 0x400); + } else { + total_lines_per_frame = (uint16_t)(((IMX074_FULL_SIZE_HEIGHT + + IMX074_VER_FULL_BLK_LINES) * + imx074_ctrl->pict_fps_divider) / 0x400); + } + if (imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI, + ((total_lines_per_frame & 0xFF00) >> 8)) < 0) + return rc; + if (imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO, + (total_lines_per_frame & 0x00FF)) < 0) + return rc; + return rc; +} + +static int32_t imx074_write_exp_gain(uint16_t gain, uint32_t line) +{ + static uint16_t max_legal_gain = 0x00E0; + uint8_t gain_msb, gain_lsb; + uint8_t intg_time_msb, intg_time_lsb; + uint8_t frame_length_line_msb, frame_length_line_lsb; + uint16_t frame_length_lines; + int32_t rc = -1; + + CDBG("imx074_write_exp_gain : gain = %d line = %d", gain, line); + if (imx074_ctrl->curr_res == QTR_SIZE) { + frame_length_lines = IMX074_QTR_SIZE_HEIGHT + + IMX074_VER_QTR_BLK_LINES; + frame_length_lines = frame_length_lines * + imx074_ctrl->fps_divider / 0x400; + } else { + frame_length_lines = IMX074_FULL_SIZE_HEIGHT + + IMX074_VER_FULL_BLK_LINES; + frame_length_lines = frame_length_lines * + imx074_ctrl->pict_fps_divider / 0x400; + } + if (line > (frame_length_lines - IMX074_OFFSET)) + frame_length_lines = line + IMX074_OFFSET; + + CDBG("imx074 setting line = %d\n", line); + + + CDBG("imx074 setting frame_length_lines = %d\n", + frame_length_lines); + + if (gain > max_legal_gain) + /* range: 0 to 224 */ + gain = max_legal_gain; + + /* update gain registers */ + gain_msb = (uint8_t) ((gain & 0xFF00) >> 8); + gain_lsb = (uint8_t) (gain & 0x00FF); + + frame_length_line_msb = (uint8_t) ((frame_length_lines & 0xFF00) >> 8); + frame_length_line_lsb = (uint8_t) (frame_length_lines & 0x00FF); + + /* update line count registers */ + intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8); + intg_time_lsb = (uint8_t) (line & 0x00FF); + + rc = imx074_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + CDBG("imx074 setting REG_ANALOGUE_GAIN_CODE_GLOBAL_HI = 0x%X\n", + gain_msb); + rc = imx074_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_HI, + gain_msb); + if (rc < 0) + return rc; + CDBG("imx074 setting REG_ANALOGUE_GAIN_CODE_GLOBAL_LO = 0x%X\n", + gain_lsb); + rc = imx074_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + gain_lsb); + if (rc < 0) + return rc; + + CDBG("imx074 setting REG_FRAME_LENGTH_LINES_HI = 0x%X\n", + frame_length_line_msb); + rc = imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI, + frame_length_line_msb); + if (rc < 0) + return rc; + + CDBG("imx074 setting REG_FRAME_LENGTH_LINES_LO = 0x%X\n", + frame_length_line_lsb); + rc = imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO, + frame_length_line_lsb); + if (rc < 0) + return rc; + + CDBG("imx074 setting REG_COARSE_INTEGRATION_TIME_HI = 0x%X\n", + intg_time_msb); + rc = imx074_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_HI, + intg_time_msb); + if (rc < 0) + return rc; + + CDBG("imx074 setting REG_COARSE_INTEGRATION_TIME_LO = 0x%X\n", + intg_time_lsb); + rc = imx074_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LO, + intg_time_lsb); + if (rc < 0) + return rc; + + rc = imx074_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t imx074_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + rc = imx074_write_exp_gain(gain, line); + return rc; +} + +static int32_t imx074_move_focus(int direction, + int32_t num_steps) +{ + int32_t step_direction, dest_step_position, bit_mask; + int32_t rc = 0; + + if (num_steps == 0) + return rc; + + if (direction == MOVE_NEAR) { + step_direction = 1; + bit_mask = 0x80; + } else if (direction == MOVE_FAR) { + step_direction = -1; + bit_mask = 0x00; + } else { + CDBG("imx074_move_focus: Illegal focus direction"); + return -EINVAL; + } + dest_step_position = imx074_ctrl->curr_step_pos + + (step_direction * num_steps); + if (dest_step_position < 0) + dest_step_position = 0; + else if (dest_step_position > IMX074_TOTAL_STEPS_NEAR_TO_FAR) + dest_step_position = IMX074_TOTAL_STEPS_NEAR_TO_FAR; + rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00, + ((num_steps * imx074_l_region_code_per_step) | bit_mask)); + CDBG("%s: Index: %d\n", __func__, dest_step_position); + imx074_ctrl->curr_step_pos = dest_step_position; + return rc; +} + + +static int32_t imx074_set_default_focus(uint8_t af_step) +{ + int32_t rc; + /* Initialize to infinity */ + rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00, 0x7F); + rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00, 0x7F); + imx074_ctrl->curr_step_pos = 0; + return rc; +} +static int32_t imx074_test(enum imx074_test_mode_t mo) +{ + int32_t rc = 0; + if (mo == TEST_OFF) + return rc; + else { + /* Set mo to 2 inorder to enable test pattern*/ + if (imx074_i2c_write_b_sensor(REG_TEST_PATTERN_MODE, + (uint8_t) mo) < 0) { + return rc; + } + } + return rc; +} +static int32_t imx074_sensor_setting(int update_type, int rt) +{ + int32_t rc = 0; + struct msm_camera_csi_params imx074_csi_params; + switch (update_type) { + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct imx074_i2c_reg_conf init_tbl[] = { + {REG_PRE_PLL_CLK_DIV, + imx074_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLSTATIM, + imx074_regs.reg_pat_init[0]. + plstatim}, + {REG_3024, + imx074_regs.reg_pat_init[0]. + reg_3024}, + {REG_IMAGE_ORIENTATION, + imx074_regs.reg_pat_init[0]. + image_orientation}, + {REG_VNDMY_ABLMGSHLMT, + imx074_regs.reg_pat_init[0]. + vndmy_ablmgshlmt}, + {REG_Y_OPBADDR_START_DI, + imx074_regs.reg_pat_init[0]. + y_opbaddr_start_di}, + {REG_3015, + imx074_regs.reg_pat_init[0]. + reg_0x3015}, + {REG_301C, + imx074_regs.reg_pat_init[0]. + reg_0x301c}, + {REG_302C, + imx074_regs.reg_pat_init[0]. + reg_0x302c}, + {REG_3031, + imx074_regs.reg_pat_init[0].reg_0x3031}, + {REG_3041, + imx074_regs.reg_pat_init[0].reg_0x3041}, + {REG_3051, + imx074_regs.reg_pat_init[0].reg_0x3051}, + {REG_3053, + imx074_regs.reg_pat_init[0].reg_0x3053}, + {REG_3057, + imx074_regs.reg_pat_init[0].reg_0x3057}, + {REG_305C, + imx074_regs.reg_pat_init[0].reg_0x305c}, + {REG_305D, + imx074_regs.reg_pat_init[0].reg_0x305d}, + {REG_3060, + imx074_regs.reg_pat_init[0].reg_0x3060}, + {REG_3065, + imx074_regs.reg_pat_init[0].reg_0x3065}, + {REG_30AA, + imx074_regs.reg_pat_init[0].reg_0x30aa}, + {REG_30AB, + imx074_regs.reg_pat_init[0].reg_0x30ab}, + {REG_30B0, + imx074_regs.reg_pat_init[0].reg_0x30b0}, + {REG_30B2, + imx074_regs.reg_pat_init[0].reg_0x30b2}, + {REG_30D3, + imx074_regs.reg_pat_init[0].reg_0x30d3}, + {REG_3106, + imx074_regs.reg_pat_init[0].reg_0x3106}, + {REG_310C, + imx074_regs.reg_pat_init[0].reg_0x310c}, + {REG_3304, + imx074_regs.reg_pat_init[0].reg_0x3304}, + {REG_3305, + imx074_regs.reg_pat_init[0].reg_0x3305}, + {REG_3306, + imx074_regs.reg_pat_init[0].reg_0x3306}, + {REG_3307, + imx074_regs.reg_pat_init[0].reg_0x3307}, + {REG_3308, + imx074_regs.reg_pat_init[0].reg_0x3308}, + {REG_3309, + imx074_regs.reg_pat_init[0].reg_0x3309}, + {REG_330A, + imx074_regs.reg_pat_init[0].reg_0x330a}, + {REG_330B, + imx074_regs.reg_pat_init[0].reg_0x330b}, + {REG_330C, + imx074_regs.reg_pat_init[0].reg_0x330c}, + {REG_330D, + imx074_regs.reg_pat_init[0].reg_0x330d}, + {REG_330F, + imx074_regs.reg_pat_init[0].reg_0x330f}, + {REG_3381, + imx074_regs.reg_pat_init[0].reg_0x3381}, + }; + struct imx074_i2c_reg_conf init_mode_tbl[] = { + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD}, + {REG_PLL_MULTIPLIER, + imx074_regs.reg_pat[rt]. + pll_multiplier}, + {REG_FRAME_LENGTH_LINES_HI, + imx074_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + imx074_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_YADDR_START , + imx074_regs.reg_pat[rt]. + y_addr_start}, + {REG_YAAAR_END, + imx074_regs.reg_pat[rt]. + y_add_end}, + {REG_X_OUTPUT_SIZE_MSB, + imx074_regs.reg_pat[rt]. + x_output_size_msb}, + {REG_X_OUTPUT_SIZE_LSB, + imx074_regs.reg_pat[rt]. + x_output_size_lsb}, + {REG_Y_OUTPUT_SIZE_MSB, + imx074_regs.reg_pat[rt]. + y_output_size_msb}, + {REG_Y_OUTPUT_SIZE_LSB , + imx074_regs.reg_pat[rt]. + y_output_size_lsb}, + {REG_X_EVEN_INC, + imx074_regs.reg_pat[rt]. + x_even_inc}, + {REG_X_ODD_INC, + imx074_regs.reg_pat[rt]. + x_odd_inc}, + {REG_Y_EVEN_INC, + imx074_regs.reg_pat[rt]. + y_even_inc}, + {REG_Y_ODD_INC, + imx074_regs.reg_pat[rt]. + y_odd_inc}, + {REG_HMODEADD, + imx074_regs.reg_pat[rt]. + hmodeadd}, + {REG_VMODEADD, + imx074_regs.reg_pat[rt]. + vmodeadd}, + {REG_VAPPLINE_START, + imx074_regs.reg_pat[rt]. + vapplinepos_start}, + {REG_VAPPLINE_END, + imx074_regs.reg_pat[rt]. + vapplinepos_end}, + {REG_SHUTTER, + imx074_regs.reg_pat[rt]. + shutter}, + {REG_HADDAVE, + imx074_regs.reg_pat[rt]. + haddave}, + {REG_LANESEL, + imx074_regs.reg_pat[rt]. + lanesel}, + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF}, + + }; + /* reset fps_divider */ + imx074_ctrl->fps = 30 * Q8; + imx074_ctrl->fps_divider = 1 * 0x400; + /* stop streaming */ + rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE); + if (rc < 0) + return rc; + msleep(imx074_delay_msecs_stdby); + rc = imx074_i2c_write_w_table(&init_tbl[0], + ARRAY_SIZE(init_tbl)); + if (rc < 0) + return rc; + rc = imx074_i2c_write_w_table(&init_mode_tbl[0], + ARRAY_SIZE(init_mode_tbl)); + if (rc < 0) + return rc; + rc = imx074_test(imx074_ctrl->set_test); + return rc; + } + break; + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct imx074_i2c_reg_conf mode_tbl[] = { + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD}, + {REG_PLL_MULTIPLIER, + imx074_regs.reg_pat[rt]. + pll_multiplier}, + {REG_FRAME_LENGTH_LINES_HI, + imx074_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + imx074_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_YADDR_START , + imx074_regs.reg_pat[rt]. + y_addr_start}, + {REG_YAAAR_END, + imx074_regs.reg_pat[rt]. + y_add_end}, + {REG_X_OUTPUT_SIZE_MSB, + imx074_regs.reg_pat[rt]. + x_output_size_msb}, + {REG_X_OUTPUT_SIZE_LSB, + imx074_regs.reg_pat[rt]. + x_output_size_lsb}, + {REG_Y_OUTPUT_SIZE_MSB, + imx074_regs.reg_pat[rt]. + y_output_size_msb}, + {REG_Y_OUTPUT_SIZE_LSB , + imx074_regs.reg_pat[rt]. + y_output_size_lsb}, + {REG_X_EVEN_INC, + imx074_regs.reg_pat[rt]. + x_even_inc}, + {REG_X_ODD_INC, + imx074_regs.reg_pat[rt]. + x_odd_inc}, + {REG_Y_EVEN_INC, + imx074_regs.reg_pat[rt]. + y_even_inc}, + {REG_Y_ODD_INC, + imx074_regs.reg_pat[rt]. + y_odd_inc}, + {REG_HMODEADD, + imx074_regs.reg_pat[rt]. + hmodeadd}, + {REG_VMODEADD, + imx074_regs.reg_pat[rt]. + vmodeadd}, + {REG_VAPPLINE_START, + imx074_regs.reg_pat[rt]. + vapplinepos_start}, + {REG_VAPPLINE_END, + imx074_regs.reg_pat[rt]. + vapplinepos_end}, + {REG_SHUTTER, + imx074_regs.reg_pat[rt]. + shutter}, + {REG_HADDAVE, + imx074_regs.reg_pat[rt]. + haddave}, + {REG_LANESEL, + imx074_regs.reg_pat[rt]. + lanesel}, + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF}, + }; + + /* stop streaming */ + rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE); + msleep(imx074_delay_msecs_stdby); + if (config_csi == 0) { + imx074_csi_params.lane_cnt = 4; + imx074_csi_params.data_format = CSI_10BIT; + imx074_csi_params.lane_assign = 0xe4; + imx074_csi_params.dpcm_scheme = 0; + imx074_csi_params.settle_cnt = 0x14; + rc = msm_camio_csi_config(&imx074_csi_params); + /*imx074_delay_msecs_stdby*/ + msleep(imx074_delay_msecs_stream); + config_csi = 1; + } + rc = imx074_i2c_write_w_table(&mode_tbl[0], + ARRAY_SIZE(mode_tbl)); + if (rc < 0) + return rc; + rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STREAM); + if (rc < 0) + return rc; + msleep(imx074_delay_msecs_stream); + } + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + + +static int32_t imx074_video_config(int mode) +{ + + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + if (imx074_ctrl->prev_res == QTR_SIZE) { + rt = RES_PREVIEW; + } else { + rt = RES_CAPTURE; + } + if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + imx074_ctrl->curr_res = imx074_ctrl->prev_res; + imx074_ctrl->sensormode = mode; + return rc; +} + +static int32_t imx074_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt = RES_PREVIEW; /* TODO: Used without initialization, guessing. */ + /* change sensor resolution if needed */ + if (imx074_ctrl->curr_res != imx074_ctrl->pict_res) { + if (imx074_ctrl->pict_res == QTR_SIZE) { + rt = RES_PREVIEW; + } else { + rt = RES_CAPTURE; + } + } + if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + imx074_ctrl->curr_res = imx074_ctrl->pict_res; + imx074_ctrl->sensormode = mode; + return rc; +} +static int32_t imx074_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt = RES_PREVIEW; /* TODO: Used without initialization, guessing. */ + /* change sensor resolution if needed */ + if (imx074_ctrl->curr_res != imx074_ctrl->pict_res) { + if (imx074_ctrl->pict_res == QTR_SIZE) { + rt = RES_PREVIEW; + } else { + rt = RES_CAPTURE; + } + } + if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + imx074_ctrl->curr_res = imx074_ctrl->pict_res; + imx074_ctrl->sensormode = mode; + return rc; +} +static int32_t imx074_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = imx074_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + rc = imx074_snapshot_config(mode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + rc = imx074_raw_snapshot_config(mode); + break; + default: + rc = -EINVAL; + break; + } + return rc; +} +static int32_t imx074_power_down(void) +{ + imx074_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE); + msleep(imx074_delay_msecs_stdby); + return 0; +} +static int imx074_probe_init_done(const struct msm_camera_sensor_info *data) +{ + gpio_set_value_cansleep(data->sensor_reset, 0); + gpio_direction_input(data->sensor_reset); + gpio_free(data->sensor_reset); + return 0; +} + +static int imx074_read_eeprom_data(struct sensor_cfg_data *cfg) +{ + int32_t rc = 0; + uint16_t eepromdata = 0; + uint8_t addr = 0; + + addr = 0x10; + rc = imx074_i2c_read_w_eeprom(addr, &eepromdata); + if (rc < 0) { + CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr); + return rc; + } + cfg->cfg.calib_info.r_over_g = eepromdata; + + addr = 0x12; + rc = imx074_i2c_read_w_eeprom(addr, &eepromdata); + if (rc < 0) { + CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr); + return rc; + } + cfg->cfg.calib_info.b_over_g = eepromdata; + + addr = 0x14; + rc = imx074_i2c_read_w_eeprom(addr, &eepromdata); + if (rc < 0) { + CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr); + return rc; + } + cfg->cfg.calib_info.gr_over_gb = eepromdata; + + addr = 0x1A; + rc = imx074_i2c_read_w_eeprom(addr, &eepromdata); + if (rc < 0) { + CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr); + return rc; + } + cfg->cfg.calib_info.macro_2_inf = eepromdata; + + addr = 0x1C; + rc = imx074_i2c_read_w_eeprom(addr, &eepromdata); + if (rc < 0) { + CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr); + return rc; + } + cfg->cfg.calib_info.inf_2_macro = eepromdata; + + addr = 0x1E; + rc = imx074_i2c_read_w_eeprom(addr, &eepromdata); + if (rc < 0) { + CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr); + return rc; + } + cfg->cfg.calib_info.stroke_amt = eepromdata; + + addr = 0x20; + rc = imx074_i2c_read_w_eeprom(addr, &eepromdata); + if (rc < 0) { + CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr); + return rc; + } + cfg->cfg.calib_info.af_pos_1m = eepromdata; + + addr = 0x22; + rc = imx074_i2c_read_w_eeprom(addr, &eepromdata); + if (rc < 0) { + CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr); + return rc; + } + cfg->cfg.calib_info.af_pos_inf = eepromdata; + + return rc; +} + +static int imx074_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + unsigned short chipidl, chipidh; + CDBG("%s: %d\n", __func__, __LINE__); + rc = gpio_request(data->sensor_reset, "imx074"); + CDBG(" imx074_probe_init_sensor \n"); + if (!rc) { + CDBG("sensor_reset = %d\n", rc); + gpio_direction_output(data->sensor_reset, 0); + usleep_range(5000, 6000); + gpio_set_value_cansleep(data->sensor_reset, 1); + usleep_range(5000, 6000); + } else { + CDBG("gpio reset fail"); + goto init_probe_done; + } + CDBG("imx074_probe_init_sensor is called\n"); + /* 3. Read sensor Model ID: */ + rc = imx074_i2c_read(0x0000, &chipidh, 1); + if (rc < 0) { + CDBG("Model read failed\n"); + goto init_probe_fail; + } + rc = imx074_i2c_read(0x0001, &chipidl, 1); + if (rc < 0) { + CDBG("Model read failed\n"); + goto init_probe_fail; + } + CDBG("imx074 model_id = 0x%x 0x%x\n", chipidh, chipidl); + /* 4. Compare sensor ID to IMX074 ID: */ + if (chipidh != 0x00 || chipidl != 0x74) { + rc = -ENODEV; + CDBG("imx074_probe_init_sensor fail chip id doesnot match\n"); + goto init_probe_fail; + } + goto init_probe_done; +init_probe_fail: + CDBG("imx074_probe_init_sensor fails\n"); + imx074_probe_init_done(data); +init_probe_done: + CDBG(" imx074_probe_init_sensor finishes\n"); + return rc; + } +static int32_t imx074_poweron_af(void) +{ + int32_t rc = 0; + CDBG("imx074 enable AF actuator, gpio = %d\n", + imx074_ctrl->sensordata->vcm_pwd); + rc = gpio_request(imx074_ctrl->sensordata->vcm_pwd, "imx074"); + if (!rc) { + gpio_direction_output(imx074_ctrl->sensordata->vcm_pwd, 1); + msleep(20); + rc = imx074_af_init(); + if (rc < 0) + CDBG("imx074 AF initialisation failed\n"); + } else { + CDBG("%s: AF PowerON gpio_request failed %d\n", __func__, rc); + } + return rc; +} +static void imx074_poweroff_af(void) +{ + gpio_set_value_cansleep(imx074_ctrl->sensordata->vcm_pwd, 0); + gpio_free(imx074_ctrl->sensordata->vcm_pwd); +} +/* camsensor_iu060f_imx074_reset */ +int imx074_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + CDBG("%s: %d\n", __func__, __LINE__); + CDBG("Calling imx074_sensor_open_init\n"); + imx074_ctrl = kzalloc(sizeof(struct imx074_ctrl_t), GFP_KERNEL); + if (!imx074_ctrl) { + CDBG("imx074_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + imx074_ctrl->fps_divider = 1 * 0x00000400; + imx074_ctrl->pict_fps_divider = 1 * 0x00000400; + imx074_ctrl->fps = 30 * Q8; + imx074_ctrl->set_test = TEST_OFF; + imx074_ctrl->prev_res = QTR_SIZE; + imx074_ctrl->pict_res = FULL_SIZE; + imx074_ctrl->curr_res = INVALID_SIZE; + config_csi = 0; + + if (data) + imx074_ctrl->sensordata = data; + + /* enable mclk first */ + msm_camio_clk_rate_set(IMX074_DEFAULT_MASTER_CLK_RATE); + usleep_range(1000, 2000); + rc = imx074_probe_init_sensor(data); + if (rc < 0) { + CDBG("Calling imx074_sensor_open_init fail\n"); + goto probe_fail; + } + + rc = imx074_sensor_setting(REG_INIT, RES_PREVIEW); + if (rc < 0) { + CDBG("imx074_sensor_setting failed\n"); + goto init_fail; + } + if (machine_is_msm8x60_fluid()) + rc = imx074_poweron_af(); + else + rc = imx074_af_init(); + if (rc < 0) { + CDBG("AF initialisation failed\n"); + goto init_fail; + } else + goto init_done; +probe_fail: + CDBG(" imx074_sensor_open_init probe fail\n"); + kfree(imx074_ctrl); + return rc; +init_fail: + CDBG(" imx074_sensor_open_init fail\n"); + imx074_probe_init_done(data); + kfree(imx074_ctrl); +init_done: + CDBG("imx074_sensor_open_init done\n"); + return rc; +} +static int imx074_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&imx074_wait_queue); + return 0; +} + +static const struct i2c_device_id imx074_i2c_id[] = { + {"imx074", 0}, + { } +}; + +static int imx074_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("imx074_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + imx074_sensorw = kzalloc(sizeof(struct imx074_work_t), GFP_KERNEL); + if (!imx074_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, imx074_sensorw); + imx074_init_client(client); + imx074_client = client; + + + CDBG("imx074_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("imx074_probe failed! rc = %d\n", rc); + return rc; +} + +static int __exit imx074_remove(struct i2c_client *client) +{ + struct imx074_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + imx074_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver imx074_i2c_driver = { + .id_table = imx074_i2c_id, + .probe = imx074_i2c_probe, + .remove = __exit_p(imx074_i2c_remove), + .driver = { + .name = "imx074", + }, +}; + +int imx074_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&imx074_mut); + CDBG("imx074_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + imx074_get_pict_fps( + cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = + imx074_get_prev_lines_pf(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = + imx074_get_prev_pixels_pl(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = + imx074_get_pict_lines_pf(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + imx074_get_pict_pixels_pl(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + imx074_get_pict_max_exp_lc(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = imx074_set_fps(&(cdata.cfg.fps)); + break; + case CFG_SET_EXP_GAIN: + rc = + imx074_write_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + case CFG_SET_PICT_EXP_GAIN: + rc = + imx074_set_pict_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + case CFG_SET_MODE: + rc = imx074_set_sensor_mode(cdata.mode, + cdata.rs); + break; + case CFG_PWR_DOWN: + rc = imx074_power_down(); + break; + case CFG_GET_CALIB_DATA: + rc = imx074_read_eeprom_data(&cdata); + if (rc < 0) + break; + if (copy_to_user((void *)argp, + &cdata, + sizeof(cdata))) + rc = -EFAULT; + break; + case CFG_MOVE_FOCUS: + rc = + imx074_move_focus( + cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + case CFG_SET_DEFAULT_FOCUS: + rc = + imx074_set_default_focus( + cdata.cfg.focus.steps); + break; + case CFG_GET_AF_MAX_STEPS: + cdata.max_steps = IMX074_STEPS_NEAR_TO_CLOSEST_INF; + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_SET_EFFECT: + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&imx074_mut); + + return rc; +} +static int imx074_sensor_release(void) +{ + int rc = -EBADF; + mutex_lock(&imx074_mut); + if (machine_is_msm8x60_fluid()) + imx074_poweroff_af(); + imx074_power_down(); + gpio_set_value_cansleep(imx074_ctrl->sensordata->sensor_reset, 0); + msleep(5); + gpio_direction_input(imx074_ctrl->sensordata->sensor_reset); + gpio_free(imx074_ctrl->sensordata->sensor_reset); + kfree(imx074_ctrl); + imx074_ctrl = NULL; + CDBG("imx074_release completed\n"); + mutex_unlock(&imx074_mut); + + return rc; +} + +static int imx074_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(&imx074_i2c_driver); + if (rc < 0 || imx074_client == NULL) { + rc = -ENOTSUPP; + goto probe_fail; + } + msm_camio_clk_rate_set(IMX074_DEFAULT_MASTER_CLK_RATE); + rc = imx074_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + s->s_init = imx074_sensor_open_init; + s->s_release = imx074_sensor_release; + s->s_config = imx074_sensor_config; + s->s_mount_angle = info->sensor_platform_info->mount_angle; + imx074_probe_init_done(info); + return rc; + +probe_fail: + CDBG("imx074_sensor_probe: SENSOR PROBE FAILS!\n"); + i2c_del_driver(&imx074_i2c_driver); + return rc; +} + +static int __imx074_probe(struct platform_device *pdev) +{ + + return msm_camera_drv_start(pdev, imx074_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __imx074_probe, + .driver = { + .name = "msm_camera_imx074", + .owner = THIS_MODULE, + }, +}; + +static int __init imx074_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(imx074_init); + +MODULE_DESCRIPTION("Sony 13 MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/imx074.h b/drivers/media/video/msm_zsl/imx074.h new file mode 100644 index 00000000000..8be0fb70d86 --- /dev/null +++ b/drivers/media/video/msm_zsl/imx074.h @@ -0,0 +1,118 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef IMX074_H +#define IMX074_H +#include +#include +extern struct imx074_reg imx074_regs; +struct reg_struct_init { + /* PLL setting */ + uint8_t pre_pll_clk_div; /* 0x0305 */ + uint8_t plstatim; /* 0x302b */ + uint8_t reg_3024; /*ox3024*/ + uint8_t image_orientation; /* 0x0101*/ + uint8_t vndmy_ablmgshlmt; /*0x300a*/ + uint8_t y_opbaddr_start_di; /*0x3014*/ + uint8_t reg_0x3015; /*0x3015*/ + uint8_t reg_0x301c; /*0x301c*/ + uint8_t reg_0x302c; /*0x302c*/ + uint8_t reg_0x3031; /*0x3031*/ + uint8_t reg_0x3041; /* 0x3041 */ + uint8_t reg_0x3051; /* 0x3051 */ + uint8_t reg_0x3053; /* 0x3053 */ + uint8_t reg_0x3057; /* 0x3057 */ + uint8_t reg_0x305c; /* 0x305c */ + uint8_t reg_0x305d; /* 0x305d */ + uint8_t reg_0x3060; /* 0x3060 */ + uint8_t reg_0x3065; /* 0x3065 */ + uint8_t reg_0x30aa; /* 0x30aa */ + uint8_t reg_0x30ab; + uint8_t reg_0x30b0; + uint8_t reg_0x30b2; + uint8_t reg_0x30d3; + uint8_t reg_0x3106; + uint8_t reg_0x310c; + uint8_t reg_0x3304; + uint8_t reg_0x3305; + uint8_t reg_0x3306; + uint8_t reg_0x3307; + uint8_t reg_0x3308; + uint8_t reg_0x3309; + uint8_t reg_0x330a; + uint8_t reg_0x330b; + uint8_t reg_0x330c; + uint8_t reg_0x330d; + uint8_t reg_0x330f; + uint8_t reg_0x3381; +}; + +struct reg_struct { + uint8_t pll_multiplier; /* 0x0307 */ + uint8_t frame_length_lines_hi; /* 0x0340*/ + uint8_t frame_length_lines_lo; /* 0x0341*/ + uint8_t y_addr_start; /* 0x347 */ + uint8_t y_add_end; /* 0x034b */ + uint8_t x_output_size_msb; /* 0x034c */ + uint8_t x_output_size_lsb; /* 0x034d */ + uint8_t y_output_size_msb; /* 0x034e */ + uint8_t y_output_size_lsb; /* 0x034f */ + uint8_t x_even_inc; /* 0x0381 */ + uint8_t x_odd_inc; /* 0x0383 */ + uint8_t y_even_inc; /* 0x0385 */ + uint8_t y_odd_inc; /* 0x0387 */ + uint8_t hmodeadd; /* 0x3001 */ + uint8_t vmodeadd; /* 0x3016 */ + uint8_t vapplinepos_start;/*ox3069*/ + uint8_t vapplinepos_end;/*306b*/ + uint8_t shutter; /* 0x3086 */ + uint8_t haddave; /* 0x30e8 */ + uint8_t lanesel; /* 0x3301 */ +}; + +struct imx074_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum imx074_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum imx074_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +enum imx074_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +struct imx074_reg { + const struct reg_struct_init *reg_pat_init; + const struct reg_struct *reg_pat; +}; +#endif /* IMX074_H */ diff --git a/drivers/media/video/msm_zsl/imx074_reg.c b/drivers/media/video/msm_zsl/imx074_reg.c new file mode 100644 index 00000000000..ccc9b2f1092 --- /dev/null +++ b/drivers/media/video/msm_zsl/imx074_reg.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include "imx074.h" +const struct reg_struct_init imx074_reg_init[1] = { + { + /* PLL setting */ + 0x02, /* pll_divider 0x0305 */ + 0x4B, /* plstatim 0x302b */ + 0x03, /* reg_3024 */ + 0x00, /* image_orientation 0x0101 */ + 0x80, /* vndmy_ablmgshlmt 0x300a*/ + 0x08, /* y_opbaddr_start_di 3014*/ + 0x37, /* 0x3015*/ + 0x01, /* 0x301c*/ + 0x05, /* 0x302c*/ + 0x26, /* 0x3031*/ + 0x60, /* 0x3041*/ + 0x24, /* 0x3051 CLK DIV*/ + 0x34, /* 0x3053*/ + 0xc0, /* 0x3057*/ + 0x09, /* 0x305c*/ + 0x07, /* 0x305d */ + 0x30, /* 0x3060 */ + 0x00, /* 0x3065 */ + 0x08, /* 0x30aa */ + 0x1c, /* 0x30ab */ + 0x32, /* 0x30b0 */ + 0x83, /* 0x30b2 */ + 0x04, /* 0x30d3 */ + 0x78, /* 0x3106 */ + 0x82, /* 0x310c */ + 0x05, /* 0x3304 */ + 0x04, /* 0x3305 */ + 0x11, /* 0x3306 */ + 0x02, /* 0x3307 */ + 0x0c, /* 0x3308 */ + 0x06, /* 0x3309 */ + 0x08, /* 0x330a */ + 0x04, /* 0x330b */ + 0x08, /* 0x330c */ + 0x06, /* 0x330d */ + 0x01, /* 0x330f */ + 0x00, /* 0x3381 */ + + } +}; + +/* Preview / Snapshot register settings */ +const struct reg_struct imx074_reg_pat[2] = { + /*preview*/ + { + 0x2D, /*pll_multiplier*/ + 0x06, /*frame_length_lines_hi 0x0340*/ + 0x2D, /* frame_length_lines_lo 0x0341*/ + 0x00, /* y_addr_start 0x347 */ + 0x2F, /* y_add_end 0x034b */ + 0x08, /* x_output_size_msb0x034c */ + 0x38, /* x_output_size_lsb0x034d */ + 0x06, /* y_output_size_msb0x034e */ + 0x18, /* y_output_size_lsb0x034f */ + 0x01, /* x_even_inc 0x0381 */ + 0x03, /* x_odd_inc 0x0383 */ + 0x01, /* y_even_inc 0x0385 */ + 0x03, /* y_odd_inc 0x0387 */ + 0x80, /* hmodeadd0x3001 */ + 0x16, /* vmodeadd0x3016 */ + 0x24, /* vapplinepos_startox3069*/ + 0x53, /* vapplinepos_end306b*/ + 0x00,/* shutter 0x3086 */ + 0x80, /* haddave 0x30e8 */ + 0x83, /* lanesel 0x3301 */ + }, + + /*snapshot*/ + { + 0x26, /*pll_multiplier*/ + 0x0C, /* frame_length_lines_hi 0x0340*/ + 0x90, /* frame_length_lines_lo 0x0341*/ + 0x00, /* y_addr_start 0x347 */ + 0x2F, /* y_add_end 0x034b */ + 0x10, /* x_output_size_msb0x034c */ + 0x70, /* x_output_size_lsb0x034d */ + 0x0c, /* y_output_size_msb0x034e */ + 0x30, /* y_output_size_lsb0x034f */ + 0x01, /* x_even_inc 0x0381 */ + 0x01, /* x_odd_inc 0x0383 */ + 0x01, /* y_even_inc 0x0385 */ + 0x01, /* y_odd_inc 0x0387 */ + 0x00, /* hmodeadd0x3001 */ + 0x06, /* vmodeadd0x3016 */ + 0x24, /* vapplinepos_startox3069*/ + 0x53, /* vapplinepos_end306b*/ + 0x00, /* shutter 0x3086 */ + 0x00, /* haddave 0x30e8 */ + 0x03, /* lanesel 0x3301 */ + } +}; +struct imx074_reg imx074_regs = { + .reg_pat_init = &imx074_reg_init[0], + .reg_pat = &imx074_reg_pat[0], +}; diff --git a/drivers/media/video/msm_zsl/io/Makefile b/drivers/media/video/msm_zsl/io/Makefile new file mode 100644 index 00000000000..584738de780 --- /dev/null +++ b/drivers/media/video/msm_zsl/io/Makefile @@ -0,0 +1,3 @@ +GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) +obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_eeprom.o +obj-$(CONFIG_MSM_CAMERA) += msm_io_util.o diff --git a/drivers/media/video/msm_zsl/io/msm_camera_eeprom.c b/drivers/media/video/msm_zsl/io/msm_camera_eeprom.c new file mode 100644 index 00000000000..fb1a17e5ad4 --- /dev/null +++ b/drivers/media/video/msm_zsl/io/msm_camera_eeprom.c @@ -0,0 +1,95 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include "msm_camera_eeprom.h" + +int32_t msm_camera_eeprom_init(struct msm_camera_eeprom_client *ectrl, + struct i2c_adapter *adapter) +{ + CDBG("%s: open", __func__); + ectrl->i2c_client->client = + i2c_new_dummy(adapter, ectrl->i2c_addr >> 1); + if (ectrl->i2c_client->client == NULL) { + CDBG("%s: eeprom i2c get client failed\n", __func__); + return -EFAULT; + } + ectrl->i2c_client->client->addr = ectrl->i2c_addr; + CDBG("%s: done", __func__); + return 0; +} + +int32_t msm_camera_eeprom_release(struct msm_camera_eeprom_client *ectrl) +{ + if (ectrl->i2c_client->client != NULL) { + i2c_unregister_device(ectrl->i2c_client->client); + ectrl->i2c_client->client = NULL; + } + return 0; +} + +int32_t msm_camera_eeprom_read(struct msm_camera_eeprom_client *ectrl, + uint16_t reg_addr, void *data, uint32_t num_byte, + uint16_t convert_endian) +{ + int rc = 0; + if (ectrl->func_tbl.eeprom_set_dev_addr != NULL) + ectrl->func_tbl.eeprom_set_dev_addr(ectrl, ®_addr); + + if (!convert_endian) { + rc = msm_camera_i2c_read_seq( + ectrl->i2c_client, reg_addr, data, num_byte); + } else { + unsigned char buf[num_byte]; + uint8_t *data_ptr = (uint8_t *) data; + int i; + rc = msm_camera_i2c_read_seq( + ectrl->i2c_client, reg_addr, buf, num_byte); + for (i = 0; i < num_byte; i++) + data_ptr[i] = buf[num_byte-i-1]; + } + return rc; +} + +int32_t msm_camera_eeprom_read_tbl(struct msm_camera_eeprom_client *ectrl, + struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size) +{ + int i, rc = 0; + CDBG("%s: open", __func__); + if (read_tbl == NULL) + return rc; + + for (i = 0; i < tbl_size; i++) { + rc = msm_camera_eeprom_read + (ectrl, read_tbl[i].reg_addr, + read_tbl[i].dest_ptr, read_tbl[i].num_byte, + read_tbl[i].convert_endian); + if (rc < 0) { + CDBG("%s: read failed\n", __func__); + return rc; + } + } + CDBG("%s: done", __func__); + return rc; +} + +int32_t msm_camera_eeprom_get_data(struct msm_camera_eeprom_client *ectrl, + struct sensor_eeprom_data_t *edata) +{ + int rc = 0; + if (edata->index >= ectrl->data_tbl_size) + return -EFAULT; + if (copy_to_user(edata->eeprom_data, + ectrl->data_tbl[edata->index].data, + ectrl->data_tbl[edata->index].size)) + rc = -EFAULT; + return rc; +} diff --git a/drivers/media/video/msm_zsl/io/msm_camera_eeprom.h b/drivers/media/video/msm_zsl/io/msm_camera_eeprom.h new file mode 100644 index 00000000000..0813c3c5700 --- /dev/null +++ b/drivers/media/video/msm_zsl/io/msm_camera_eeprom.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include "msm_camera_i2c.h" + +struct msm_camera_eeprom_client; + +struct msm_camera_eeprom_fn_t { + int32_t (*eeprom_init) + (struct msm_camera_eeprom_client *ectrl, + struct i2c_adapter *adapter); + int32_t (*eeprom_release) + (struct msm_camera_eeprom_client *ectrl); + int32_t (*eeprom_get_data) + (struct msm_camera_eeprom_client *ectrl, + struct sensor_eeprom_data_t *edata); + void (*eeprom_set_dev_addr) + (struct msm_camera_eeprom_client*, uint16_t*); +}; + +struct msm_camera_eeprom_read_t { + uint16_t reg_addr; + void *dest_ptr; + uint32_t num_byte; + uint16_t convert_endian; +}; + +struct msm_camera_eeprom_data_t { + void *data; + uint16_t size; +}; + +struct msm_camera_eeprom_client { + struct msm_camera_i2c_client *i2c_client; + uint16_t i2c_addr; + struct msm_camera_eeprom_fn_t func_tbl; + struct msm_camera_eeprom_read_t *read_tbl; + uint16_t read_tbl_size; + struct msm_camera_eeprom_data_t *data_tbl; + uint16_t data_tbl_size; +}; + +int32_t msm_camera_eeprom_init(struct msm_camera_eeprom_client *ectrl, + struct i2c_adapter *adapter); +int32_t msm_camera_eeprom_release(struct msm_camera_eeprom_client *ectrl); +int32_t msm_camera_eeprom_read(struct msm_camera_eeprom_client *ectrl, + uint16_t reg_addr, void *data, uint32_t num_byte, + uint16_t convert_endian); +int32_t msm_camera_eeprom_read_tbl(struct msm_camera_eeprom_client *ectrl, + struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size); +int32_t msm_camera_eeprom_get_data(struct msm_camera_eeprom_client *ectrl, + struct sensor_eeprom_data_t *edata); diff --git a/drivers/media/video/msm_zsl/io/msm_camera_i2c.c b/drivers/media/video/msm_zsl/io/msm_camera_i2c.c new file mode 100644 index 00000000000..a7f47570190 --- /dev/null +++ b/drivers/media/video/msm_zsl/io/msm_camera_i2c.c @@ -0,0 +1,427 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include "msm_camera_i2c.h" + +int32_t msm_camera_i2c_rxdata(struct msm_camera_i2c_client *dev_client, + unsigned char *rxdata, int data_length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->client->addr >> 1; + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = dev_client->addr_type, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = data_length, + .buf = rxdata, + }, + }; + rc = i2c_transfer(dev_client->client->adapter, msgs, 2); + if (rc < 0) + S_I2C_DBG("msm_camera_i2c_rxdata failed 0x%x\n", saddr); + return rc; +} + +int32_t msm_camera_i2c_txdata(struct msm_camera_i2c_client *dev_client, + unsigned char *txdata, int length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->client->addr >> 1; + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + rc = i2c_transfer(dev_client->client->adapter, msg, 1); + if (rc < 0) + S_I2C_DBG("msm_camera_i2c_txdata faild 0x%x\n", saddr); + return rc; +} + +int32_t msm_camera_i2c_write(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+data_type]; + uint8_t len = 0; + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + S_I2C_DBG("%s reg addr = 0x%x data type: %d\n", + __func__, addr, data_type); + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, len, buf[len]); + len = 1; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, len, buf[len]); + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, len+1, buf[len+1]); + len = 2; + } + S_I2C_DBG("Data: 0x%x\n", data); + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) { + buf[len] = data; + S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); + len += 1; + } else if (data_type == MSM_CAMERA_I2C_WORD_DATA) { + buf[len] = data >> BITS_PER_BYTE; + buf[len+1] = data; + S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); + S_I2C_DBG("Byte %d: 0x%x\n", len+1, buf[len+1]); + len += 2; + } + + rc = msm_camera_i2c_txdata(client, buf, len); + if (rc < 0) + S_I2C_DBG("%s fail\n", __func__); + return rc; +} + +int32_t msm_camera_i2c_write_seq(struct msm_camera_i2c_client *client, + uint16_t addr, uint8_t *data, uint16_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+num_byte]; + uint8_t len = 0, i = 0; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", + __func__, addr, num_byte); + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, len, buf[len]); + len = 1; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, len, buf[len]); + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, len+1, buf[len+1]); + len = 2; + } + for (i = 0; i < num_byte; i++) { + buf[i+len] = data[i]; + S_I2C_DBG("Byte %d: 0x%x\n", i+len, buf[i+len]); + S_I2C_DBG("Data: 0x%x\n", data[i]); + } + + rc = msm_camera_i2c_txdata(client, buf, len+num_byte); + if (rc < 0) + S_I2C_DBG("%s fail\n", __func__); + return rc; +} + +int32_t msm_camera_i2c_set_mask(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t mask, + enum msm_camera_i2c_data_type data_type, uint16_t set_mask) +{ + int32_t rc; + uint16_t reg_data; + + rc = msm_camera_i2c_read(client, addr, ®_data, data_type); + if (rc < 0) { + S_I2C_DBG("%s read fail\n", __func__); + return rc; + } + S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n", + __func__, addr, reg_data, mask); + + if (set_mask) + reg_data |= mask; + else + reg_data &= ~mask; + S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data); + + rc = msm_camera_i2c_write(client, addr, reg_data, data_type); + if (rc < 0) + S_I2C_DBG("%s write fail\n", __func__); + + return rc; +} + +int32_t msm_camera_i2c_compare(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EIO; + uint16_t reg_data = 0; + int data_len = 0; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + data_len = data_type; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + data_len = MSM_CAMERA_I2C_BYTE_DATA; + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + data_len = MSM_CAMERA_I2C_WORD_DATA; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + rc = msm_camera_i2c_read(client, + addr, ®_data, data_len); + if (rc < 0) + return rc; + + rc = 0; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + if (data == reg_data) + return rc; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_SET_WORD_MASK: + if ((reg_data & data) == data) + return rc; + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + if (!(reg_data & data)) + return rc; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + S_I2C_DBG("%s: Register and data does not match\n", __func__); + rc = 1; + return rc; +} + +int32_t msm_camera_i2c_poll(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EIO; + int i; + S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", + __func__, addr, data, data_type); + + for (i = 0; i < 20; i++) { + rc = msm_camera_i2c_compare(client, + addr, data, data_type); + if (rc == 0 || rc < 0) + break; + usleep_range(10000, 11000); + } + return rc; +} + +int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type) +{ + int i; + int32_t rc = -EFAULT; + for (i = 0; i < size; i++) { + enum msm_camera_i2c_data_type dt; + if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) { + rc = msm_camera_i2c_poll(client, reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_addr, reg_conf_tbl->dt); + } else { + if (reg_conf_tbl->dt == 0) + dt = data_type; + else + dt = reg_conf_tbl->dt; + + switch (dt) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + rc = msm_camera_i2c_write( + client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, dt); + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + rc = msm_camera_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + rc = msm_camera_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 0); + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + rc = msm_camera_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + rc = msm_camera_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 0); + break; + default: + pr_err("%s: Unsupport data type: %d\n", + __func__, dt); + break; + } + } + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +int32_t msm_camera_i2c_read(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+data_type]; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + } + rc = msm_camera_i2c_rxdata(client, buf, data_type); + if (rc < 0) { + S_I2C_DBG("%s fail\n", __func__); + return rc; + } + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) + *data = buf[0]; + else + *data = buf[0] << 8 | buf[1]; + + S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); + return rc; +} + +int32_t msm_camera_i2c_read_seq(struct msm_camera_i2c_client *client, + uint16_t addr, uint8_t *data, uint16_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+num_byte]; + int i; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + } + rc = msm_camera_i2c_rxdata(client, buf, num_byte); + if (rc < 0) { + S_I2C_DBG("%s fail\n", __func__); + return rc; + } + + S_I2C_DBG("%s addr = 0x%x", __func__, addr); + for (i = 0; i < num_byte; i++) { + data[i] = buf[i]; + S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); + S_I2C_DBG("Data: 0x%x\n", data[i]); + } + return rc; +} + +int32_t msm_sensor_write_conf_array(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_conf_array *array, uint16_t index) +{ + int32_t rc; + + rc = msm_camera_i2c_write_tbl(client, + (struct msm_camera_i2c_reg_conf *) array[index].conf, + array[index].size, array[index].data_type); + if (array[index].delay > 20) + msleep(array[index].delay); + else + usleep_range(array[index].delay*1000, + (array[index].delay+1)*1000); + return rc; +} + +int32_t msm_sensor_write_enum_conf_array(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_enum_conf_array *conf, + uint16_t enum_val) +{ + int32_t rc = -1, i; + for (i = 0; i < conf->num_enum; i++) { + if (conf->conf_enum[i] == enum_val) + break; + if (conf->conf_enum[i] > enum_val) + break; + } + if (i == conf->num_enum) + i = conf->num_enum - 1; + + if (i >= conf->num_index) + return rc; + + rc = msm_sensor_write_all_conf_array(client, + &conf->conf[i*conf->num_conf], conf->num_conf); + + if (conf->delay > 20) + msleep(conf->delay); + else + usleep_range(conf->delay*1000, + (conf->delay+1)*1000); + return rc; +} + +int32_t msm_sensor_write_all_conf_array(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_conf_array *array, uint16_t size) +{ + int32_t rc = 0, i; + for (i = 0; i < size; i++) { + rc = msm_sensor_write_conf_array(client, array, i); + if (rc < 0) + break; + } + return rc; +} diff --git a/drivers/media/video/msm_zsl/io/msm_camera_i2c.h b/drivers/media/video/msm_zsl/io/msm_camera_i2c.h new file mode 100644 index 00000000000..16074cd3430 --- /dev/null +++ b/drivers/media/video/msm_zsl/io/msm_camera_i2c.h @@ -0,0 +1,118 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_CAMERA_I2C_H +#define MSM_CAMERA_I2C_H + +#include +#include +#include + +#define CONFIG_MSM_CAMERA_I2C_DBG 0 + +#if CONFIG_MSM_CAMERA_I2C_DBG +#define S_I2C_DBG(fmt, args...) printk(fmt, ##args) +#else +#define S_I2C_DBG(fmt, args...) CDBG(fmt, ##args) +#endif +enum msm_camera_i2c_reg_addr_type { + MSM_CAMERA_I2C_BYTE_ADDR = 1, + MSM_CAMERA_I2C_WORD_ADDR, +}; +struct msm_camera_i2c_client { + struct i2c_client *client; + enum msm_camera_i2c_reg_addr_type addr_type; +}; +enum msm_camera_i2c_data_type { + MSM_CAMERA_I2C_BYTE_DATA = 1, + MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_SET_BYTE_MASK, + MSM_CAMERA_I2C_UNSET_BYTE_MASK, + MSM_CAMERA_I2C_SET_WORD_MASK, + MSM_CAMERA_I2C_UNSET_WORD_MASK, +}; +enum msm_camera_i2c_cmd_type { + MSM_CAMERA_I2C_CMD_WRITE, + MSM_CAMERA_I2C_CMD_POLL, +}; + +struct msm_camera_i2c_reg_conf { + uint16_t reg_addr; + uint16_t reg_data; + enum msm_camera_i2c_data_type dt; + enum msm_camera_i2c_cmd_type cmd_type; +}; + +struct msm_camera_i2c_conf_array { + struct msm_camera_i2c_reg_conf *conf; + uint16_t size; + uint16_t delay; + enum msm_camera_i2c_data_type data_type; + int (*pre_process) (void); + int (*post_process) (void); +}; + +struct msm_camera_i2c_enum_conf_array { + struct msm_camera_i2c_conf_array *conf; + int *conf_enum; + uint16_t num_enum; + uint16_t num_index; + uint16_t num_conf; + uint16_t delay; + enum msm_camera_i2c_data_type data_type; +}; + +int32_t msm_camera_i2c_rxdata(struct msm_camera_i2c_client *client, + unsigned char *rxdata, int data_length); + +int32_t msm_camera_i2c_txdata(struct msm_camera_i2c_client *client, + unsigned char *txdata, int length); + +int32_t msm_camera_i2c_read(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_i2c_read_seq(struct msm_camera_i2c_client *client, + uint16_t addr, uint8_t *data, uint16_t num_byte); + +int32_t msm_camera_i2c_write(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_i2c_write_seq(struct msm_camera_i2c_client *client, + uint16_t addr, uint8_t *data, uint16_t num_byte); + +int32_t msm_camera_i2c_set_mask(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t mask, + enum msm_camera_i2c_data_type data_type, uint16_t flag); + +int32_t msm_camera_i2c_compare(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_i2c_poll(struct msm_camera_i2c_client *client, + uint16_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_sensor_write_conf_array(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_conf_array *array, uint16_t index); + +int32_t msm_sensor_write_enum_conf_array(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_enum_conf_array *conf, uint16_t enum_val); + +int32_t msm_sensor_write_all_conf_array(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_conf_array *array, uint16_t size); +#endif diff --git a/drivers/media/video/msm_zsl/io/msm_io_util.c b/drivers/media/video/msm_zsl/io/msm_io_util.c new file mode 100644 index 00000000000..e1c31a34664 --- /dev/null +++ b/drivers/media/video/msm_zsl/io/msm_io_util.c @@ -0,0 +1,182 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, + struct clk **clk_ptr, int num_clk, int enable) +{ + int i; + int rc = 0; + if (enable) { + for (i = 0; i < num_clk; i++) { + clk_ptr[i] = clk_get(dev, clk_info[i].clk_name); + if (IS_ERR(clk_ptr[i])) { + pr_err("%s get failed\n", clk_info[i].clk_name); + rc = PTR_ERR(clk_ptr[i]); + goto cam_clk_get_err; + } + if (clk_info[i].clk_rate >= 0) { + rc = clk_set_rate(clk_ptr[i], + clk_info[i].clk_rate); + if (rc < 0) { + pr_err("%s set failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; + } + } + rc = clk_prepare_enable(clk_ptr[i]); + if (rc < 0) { + pr_err("%s enable failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; + } + } + } else { + for (i = num_clk - 1; i >= 0; i--) { + if (clk_ptr[i] != NULL) + clk_disable_unprepare(clk_ptr[i]); + clk_put(clk_ptr[i]); + } + } + return rc; + + +cam_clk_set_err: + clk_put(clk_ptr[i]); +cam_clk_get_err: + for (i--; i >= 0; i--) { + if (clk_ptr[i] != NULL) { + clk_disable_unprepare(clk_ptr[i]); + clk_put(clk_ptr[i]); + } + } + return rc; +} + +int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, struct regulator **reg_ptr, int config) +{ + int i = 0; + int rc = 0; + struct camera_vreg_t *curr_vreg; + if (config) { + for (i = 0; i < num_vreg; i++) { + curr_vreg = &cam_vreg[i]; + reg_ptr[i] = regulator_get(dev, + curr_vreg->reg_name); + if (IS_ERR(reg_ptr[i])) { + pr_err("%s: %s get failed\n", + __func__, + curr_vreg->reg_name); + reg_ptr[i] = NULL; + goto vreg_get_fail; + } + if (curr_vreg->type == REG_LDO) { + rc = regulator_set_voltage( + reg_ptr[i], + curr_vreg->min_voltage, + curr_vreg->max_voltage); + if (rc < 0) { + pr_err( + "%s: %s set voltage failed\n", + __func__, + curr_vreg->reg_name); + goto vreg_set_voltage_fail; + } + rc = regulator_set_optimum_mode( + reg_ptr[i], + curr_vreg->op_mode); + if (rc < 0) { + pr_err( + "%s: %s set optimum mode failed\n", + __func__, + curr_vreg->reg_name); + goto vreg_set_opt_mode_fail; + } + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + curr_vreg = &cam_vreg[i]; + if (reg_ptr[i]) { + if (curr_vreg->type == REG_LDO) { + regulator_set_optimum_mode( + reg_ptr[i], 0); + regulator_set_voltage( + reg_ptr[i], + 0, curr_vreg->max_voltage); + } + regulator_put(reg_ptr[i]); + reg_ptr[i] = NULL; + } + } + } + return 0; + +vreg_unconfig: +if (curr_vreg->type == REG_LDO) + regulator_set_optimum_mode(reg_ptr[i], 0); + +vreg_set_opt_mode_fail: +if (curr_vreg->type == REG_LDO) + regulator_set_voltage(reg_ptr[i], 0, + curr_vreg->max_voltage); + +vreg_set_voltage_fail: + regulator_put(reg_ptr[i]); + reg_ptr[i] = NULL; + +vreg_get_fail: + for (i--; i >= 0; i--) { + curr_vreg = &cam_vreg[i]; + goto vreg_unconfig; + } + return -ENODEV; +} + +int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, struct regulator **reg_ptr, int enable) +{ + int i = 0, rc = 0; + if (enable) { + for (i = 0; i < num_vreg; i++) { + if (IS_ERR(reg_ptr[i])) { + pr_err("%s: %s null regulator\n", + __func__, cam_vreg[i].reg_name); + goto disable_vreg; + } + rc = regulator_enable(reg_ptr[i]); + if (rc < 0) { + pr_err("%s: %s enable failed\n", + __func__, cam_vreg[i].reg_name); + goto disable_vreg; + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) + regulator_disable(reg_ptr[i]); + } + return rc; +disable_vreg: + for (i--; i >= 0; i--) { + regulator_disable(reg_ptr[i]); + goto disable_vreg; + } + return rc; +} diff --git a/drivers/media/video/msm_zsl/isx012.c b/drivers/media/video/msm_zsl/isx012.c new file mode 100644 index 00000000000..9b2cf5cef5b --- /dev/null +++ b/drivers/media/video/msm_zsl/isx012.c @@ -0,0 +1,623 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "isx012.h" +#include "isx012_regs.h" +#include "cam_pmic.h" + + +//#define CONFIG_LOAD_FILE + + +#define ISX012_WRITE_LIST(A) isx012_i2c_write_list(A,(sizeof(A) / sizeof(A[0])),#A); + + + +struct isx012_work { + struct work_struct work; +}; + +static struct isx012_work *isx012_sensorw; +static struct i2c_client *isx012_client; + +static unsigned int config_csi2; +static struct isx012_ctrl *isx012_ctrl; + +static DECLARE_WAIT_QUEUE_HEAD(isx012_wait_queue); + +/** + * isx012_i2c_read_multi: Read (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * @r_data: buffer where data is read + * @r_len: number of bytes to read + * + * Returns 0 on success, <0 on error + */ + +#if 0 +static int isx012_i2c_read_multi(unsigned short subaddr, unsigned long *data) +{ + unsigned char buf[4]; + struct i2c_msg msg = {isx012_client->addr, 0, 2, buf}; + + int err = 0; + + if (!isx012_client->adapter) { + //dev_err(&isx012_client->dev, "%s: %d can't search i2c client adapter\n", __func__, __LINE__); + return -EIO; + } + + buf[0] = subaddr>> 8; + buf[1] = subaddr & 0xff; + + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (unlikely(err < 0)) { + //dev_err(&isx012_client->dev, "%s: %d register read fail\n", __func__, __LINE__); + return -EIO; + } + + msg.flags = I2C_M_RD; + msg.len = 4; + + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (unlikely(err < 0)) { + //dev_err(&isx012_client->dev, "%s: %d register read fail\n", __func__, __LINE__); + return -EIO; + } + + /* + * Data comes in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + *data = *(unsigned long *)(&buf); + + return err; +} + + +/** + * isx012_i2c_read: Read (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @data: data to be read + * + * Returns 0 on success, <0 on error + */ +static inline int isx012_i2c_read(unsigned short subaddr, unsigned short *data) +{ + unsigned char buf[2]; + struct i2c_msg msg = {isx012_client->addr, 0, 2, buf}; + + int err = 0; + + if (!isx012_client->adapter) { + //dev_err(&isx012_client->dev, "%s: %d can't search i2c client adapter\n", __func__, __LINE__); + return -EIO; + } + + buf[0] = subaddr>> 8; + buf[1] = subaddr & 0xff; + + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (unlikely(err < 0)) { + //dev_err(&isx012_client->dev, "%s: %d register read fail\n", __func__, __LINE__); + return -EIO; + } + + msg.flags = I2C_M_RD; + + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (unlikely(err < 0)) { + //dev_err(&isx012_client->dev, "%s: %d register read fail\n", __func__, __LINE__); + return -EIO; + } + + /* + * Data comes in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + *data = *(unsigned short *)(&buf); + + return err; +} + +#endif +/** + * isx012_i2c_write_multi: Write (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * + * Returns 0 on success, <0 on error + */ +static inline int isx012_i2c_write_multi(unsigned short addr, unsigned int w_data, unsigned int w_len) +{ + unsigned char buf[w_len+2]; + struct i2c_msg msg = {isx012_client->addr, 0, w_len+2, buf}; + + int retry_count = 5; + int err = 0; + + if (!isx012_client->adapter) { + //dev_err(&isx012_client->dev, "%s: %d can't search i2c client adapter\n", __func__, __LINE__); + return -EIO; + } + + buf[0] = addr >> 8; + buf[1] = addr & 0xff; + + /* + * Data should be written in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + if(w_len == 1) { + buf[2] = (unsigned char)w_data; + } else if(w_len == 2) { + *((unsigned short *)&buf[2]) = (unsigned short)w_data; + } else { + *((unsigned int *)&buf[2]) = w_data; + } + +#ifdef ISX012_DEBUG + { + int j; + printk("isx012 i2c write W: "); + for(j = 0; j <= w_len+1; j++) + { + printk("0x%02x ", buf[j]); + } + printk("\n"); + } +#endif + + while(retry_count--) { + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (likely(err == 1)) + break; +// msleep(POLL_TIME_MS); + } + + return (err == 1) ? 0 : -EIO; +} + +static int isx012_i2c_write_list(isx012_short_t regs[], int size, char *name) +{ + +#ifdef CONFIG_LOAD_FILE + isx012_regs_table_write(client, name); +#else + int err = 0; + int i = 0; + + if (!isx012_client->adapter) { + printk(KERN_ERR "%s: %d can't search i2c client adapter\n", __func__, __LINE__); + return -EIO; + } + + for (i = 0; i < size; i++) { + err = isx012_i2c_write_multi(regs[i].subaddr, regs[i].value, regs[i].len); + if (unlikely(err < 0)) { + //dev_err(isx012_client, "%s: register set failed\n", __func__); + return -EIO; + } + } +#endif + + return 0; +} + + +////////////////////////////////////////////////////////////// +#ifdef FACTORY_TEST +extern struct class *sec_class; +struct device *isx012_dev; + +static ssize_t cameratype_file_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char sensor_info[30] = "isx012"; + return sprintf(buf, "%s\n", sensor_info); +} + +static ssize_t cameratype_file_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + /*Reserved*/ + return size; +} + +//static DEVICE_ATTR(cameratype, 0666, cameratype_file_cmd_show, cameratype_file_cmd_store); +static struct device_attribute isx012_camtype_attr = { + .attr = { + .name = "camtype", + .mode = (S_IRUGO | S_IWUGO)}, + .show = cameratype_file_cmd_show, + .store = cameratype_file_cmd_store +}; + +static ssize_t cameraflash_file_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /*Reserved*/ + return 0; +} + +static ssize_t cameraflash_file_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int value; + + sscanf(buf, "%d", &value); + + if (value == 0) { + printk(KERN_INFO "[Factory flash]OFF\n"); + isx012_set_flash(MOVIE_FLASH,0); + } else { + printk(KERN_INFO "[Factory flash]ON\n"); + isx012_set_flash(MOVIE_FLASH,1); + } + + return size; +} + +//static DEVICE_ATTR(cameraflash, 0666, cameraflash_file_cmd_show, cameraflash_file_cmd_store); +static struct device_attribute isx012_cameraflash_attr = { + .attr = { + .name = "cameraflash", + .mode = (S_IRUGO | S_IWUGO)}, + .show = cameraflash_file_cmd_show, + .store = cameraflash_file_cmd_store +}; +#endif +////////////////////////////////////////////////////////////// + +int isx012_mipi_mode(int mode) +{ + int rc = 0; + struct msm_camera_csi_params isx012_csi_params; + + CAM_DEBUG("%s E\n",__FUNCTION__); + + if (!config_csi2) { + isx012_csi_params.lane_cnt = 1; + isx012_csi_params.data_format = CSI_8BIT; + isx012_csi_params.lane_assign = 0xe4; + isx012_csi_params.dpcm_scheme = 0; + isx012_csi_params.settle_cnt = 24;// 0x14; //0x7; //0x14; + rc = msm_camio_csi_config(&isx012_csi_params); + if (rc < 0) + printk(KERN_ERR "config csi controller failed \n"); + config_csi2 = 1; + } + CAM_DEBUG("%s X\n",__FUNCTION__); + return rc; +} + + +int isx012_start(void) +{ + int rc=0; +// unsigned short read_value; +// unsigned short id = 0; + + CAM_DEBUG("%s E\n",__FUNCTION__); + CAM_DEBUG("I2C address : 0x%x\n",isx012_client->addr); + + if(isx012_ctrl->started) { + CAM_DEBUG("%s X : already started\n",__FUNCTION__); + return rc; + } + + isx012_mipi_mode(1); + msleep(300); //=> Please add some delay + + ISX012_WRITE_LIST(isx012_init_reg); +// isx012_i2c_write_list(isx012_init_reg,sizeof(isx012_init_reg)/sizeof(isx012_init_reg[0]),"isx012_init_reg"); + + return 0; + +} + +void isx012_set_preview(void) +{ + +} + +void isx012_set_capture(void) +{ +} + +static long isx012_set_sensor_mode(int mode) +{ + CAM_DEBUG("s5k5ccaf_set_sensor_mode : %d\n",mode); + switch (mode) { + case SENSOR_PREVIEW_MODE: + isx012_start(); + isx012_set_preview(); + break; + + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + isx012_set_capture(); + break; + default: + return -EINVAL; + } + return 0; +} + + + +static int isx012_sensor_init_probe(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + printk("[S5K5CCGX] sensor_init_probe()\n"); + +/* gpio_set_value_cansleep(CAM_3M_RST, LOW); + gpio_set_value_cansleep(CAM_3M_STBY, LOW); + gpio_set_value_cansleep(CAM_VGA_RST, LOW); + gpio_set_value_cansleep(CAM_VGA_STBY, LOW); + */ + + //cam_ldo_power_on(); // move to msm_camera.c (Jeonhk 20110622) + + msm_camio_clk_rate_set(24000000); + +/* + gpio_set_value_cansleep(CAM_3M_STBY, HIGH); + udelay(20); + gpio_set_value_cansleep(CAM_3M_RST, HIGH); + mdelay(10); +*/ + +#ifdef CONFIG_LOAD_FILE + mdelay(100); + ISX012_WRITE_LIST(isx012_init0); +#endif + + return rc; +} + + +int isx012_sensor_init(const struct msm_camera_sensor_info *data) +{ + int rc = 0; +// int i = 0; + + isx012_ctrl = kzalloc(sizeof(struct isx012_ctrl), GFP_KERNEL); + if (!isx012_ctrl) { + CDBG("isx012_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + if (data) + isx012_ctrl->sensordata = data; + + config_csi2 = 0; +#ifdef CONFIG_LOAD_FILE + isx012_regs_table_init(); +#endif + + rc = isx012_sensor_init_probe(data); + if (rc < 0) { + CDBG("isx012_sensor_init failed!\n"); + goto init_fail; + } + +init_done: + return rc; + +init_fail: + kfree(isx012_ctrl); + return rc; +} + +static int isx012_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&isx012_wait_queue); + return 0; +} + +int isx012_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cfg_data; + long rc = 0; + + if (copy_from_user(&cfg_data, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + /* down(&isx012_sem); */ + + CDBG("isx012_ioctl, cfgtype = %d, mode = %d\n", + cfg_data.cfgtype, cfg_data.mode); + + switch (cfg_data.cfgtype) { + case CFG_SET_MODE: + rc = isx012_set_sensor_mode( + cfg_data.mode); + break; + + case CFG_SET_EFFECT: + //rc = isx012_set_effect(cfg_data.mode, cfg_data.cfg.effect); + break; + + case CFG_GET_AF_MAX_STEPS: + default: + rc = -EINVAL; + printk("isx012_sensor_config : Invalid cfgtype ! %d\n",cfg_data.cfgtype); + break; + } + + /* up(&isx012_sem); */ + + return rc; +} + +int isx012_sensor_release(void) +{ + int rc = 0; + + printk("[isx012] isx012_sensor_release\n"); + + kfree(isx012_ctrl); + /* up(&isx012_sem); */ + +#ifdef CONFIG_LOAD_FILE + isx012_regs_table_exit(); +#endif +/* gpio_set_value_cansleep(CAM_3M_RST, LOW); + mdelay(1); + gpio_set_value_cansleep(CAM_3M_STBY, LOW); + mdelay(1); +*/ +// gpio_set_value(CAM_IO_EN, 0); + cam_ldo_power_off(); + return rc; +} + +static int isx012_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + rc = -ENOTSUPP; + goto probe_failure; + } + + isx012_sensorw = + kzalloc(sizeof(struct isx012_work), GFP_KERNEL); + + if (!isx012_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, isx012_sensorw); + isx012_init_client(client); + isx012_client = client; + + + CDBG("isx012_probe succeeded!\n"); + + return 0; + +probe_failure: + kfree(isx012_sensorw); + isx012_sensorw = NULL; + CDBG("isx012_probe failed!\n"); + return rc; +} + +static const struct i2c_device_id isx012_i2c_id[] = { + { "isx012", 0}, + { }, +}; + +static struct i2c_driver isx012_i2c_driver = { + .id_table = isx012_i2c_id, + .probe = isx012_i2c_probe, + .remove = __exit_p(isx012_i2c_remove), + .driver = { + .name = "isx012", + }, +}; + + +static int isx012_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + + int rc = i2c_add_driver(&isx012_i2c_driver); + if (rc < 0 || isx012_client == NULL) { + rc = -ENOTSUPP; + goto probe_done; + } + + //rc = isx012_sensor_init_probe(info); + if (rc < 0) + goto probe_done; + + s->s_init = isx012_sensor_init; + s->s_release = isx012_sensor_release; + s->s_config = isx012_sensor_config; + s->s_camera_type = BACK_CAMERA_2D; + s->s_mount_angle = 90; // HC - 0/180, GB - 90/270 + + +probe_done: + CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__); + return rc; +} + +static int __isx012_probe(struct platform_device *pdev) +{ + printk("############# ISX012 probe ##############\n"); +#if 0 // sysfs for factory test + isx012_dev = device_create(sec_class, NULL, 0, NULL, "sec_isx012"); + + if (IS_ERR(isx012_dev)) { + printk("Failed to create device!"); + return -1; + } + + if (device_create_file(isx012_dev, &isx012_cameraflash_attr) < 0) { + printk("Failed to create device file!(%s)!\n", isx012_cameraflash_attr.attr.name); + return -1; + } + + if (device_create_file(isx012_dev, &isx012_camtype_attr) < 0) { + printk("Failed to create device file!(%s)!\n", isx012_camtype_attr.attr.name); + return -1; + } +#endif + return msm_camera_drv_start(pdev, isx012_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __isx012_probe, + .driver = { + .name = "msm_camera_isx012", + .owner = THIS_MODULE, + }, +}; + +static int __init isx012_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(isx012_init); diff --git a/drivers/media/video/msm_zsl/isx012.h b/drivers/media/video/msm_zsl/isx012.h new file mode 100644 index 00000000000..afca30a3fea --- /dev/null +++ b/drivers/media/video/msm_zsl/isx012.h @@ -0,0 +1,201 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __ISX012_H__ +#define __ISX012_H__ + +#include +#include + +#define ISX012_DEBUG +#ifdef ISX012_DEBUG +#define CAM_DEBUG(fmt, arg...) \ + do {\ + printk("\033[[ISX012] %s:%d: " fmt "\033[0m\n", __FUNCTION__, __LINE__, ##arg); } \ + while (0) + +#define cam_info(fmt, arg...) \ + do {\ + printk(KERN_INFO "[ISX012]" fmt "\n", ##arg); } \ + while (0) + +#define cam_err(fmt, arg...) \ + do {\ + printk(KERN_ERR "[ISX012] %s:%d:" fmt "\n", __FUNCTION__, __LINE__, ##arg); } \ + while (0) + +#else +#define CAM_DEBUG(fmt, arg...) +#define cam_info(fmt, arg...) +#define cam_err(fmt, arg...) +#endif + + +#define CAPTURE_FLASH 1 +#define MOVIE_FLASH 0 + +/* level at or below which we need to enable flash when in auto mode */ +#define LOW_LIGHT_LEVEL 0x20 + +#define LOWLIGHT_DEFAULT 0x002B /*for tuning*/ +#define LOWLIGHT_ISO50 0xB52A /*for tuning*/ +#define LOWLIGHT_ISO100 0x9DBA /*for tuning*/ +#define LOWLIGHT_ISO200 0x864A /*for tuning*/ +#define LOWLIGHT_ISO400 0x738A /*for tuning*/ + +/* DTP */ +#define DTP_OFF 0 +#define DTP_ON 1 +#define DTP_OFF_ACK 2 +#define DTP_ON_ACK 3 + +#define PREVIEW_MODE 0 +#define MOVIE_MODE 1 + +struct isx012_userset { + unsigned int focus_mode; + unsigned int focus_status; + unsigned int continuous_af; + + unsigned int metering; + unsigned int exposure; + unsigned int wb; + unsigned int iso; + int contrast; + int saturation; + int sharpness; + int brightness; + int scene; + unsigned int zoom; + unsigned int effect; /* Color FX (AKA Color tone) */ + unsigned int scenemode; + unsigned int detectmode; + unsigned int antishake; + unsigned int fps; + unsigned int flash_mode; + unsigned int flash_state; + unsigned int stabilize; /* IS */ + unsigned int strobe; + unsigned int jpeg_quality; + /*unsigned int preview_size;*/ +/* struct m5mo_preview_size preview_size;*/ + unsigned int preview_size_idx; + unsigned int capture_size; + unsigned int thumbnail_size; + +}; + + +/*extern struct isx012_reg isx012_regs;*/ +struct reg_struct_init { + /* PLL setting */ + uint8_t pre_pll_clk_div; /* 0x0305 */ + uint8_t plstatim; /* 0x302b */ + uint8_t reg_3024; /*ox3024*/ + uint8_t image_orientation; /* 0x0101*/ + uint8_t vndmy_ablmgshlmt; /*0x300a*/ + uint8_t y_opbaddr_start_di; /*0x3014*/ + uint8_t reg_0x3015; /*0x3015*/ + uint8_t reg_0x301c; /*0x301c*/ + uint8_t reg_0x302c; /*0x302c*/ + uint8_t reg_0x3031; /*0x3031*/ + uint8_t reg_0x3041; /* 0x3041 */ + uint8_t reg_0x3051; /* 0x3051 */ + uint8_t reg_0x3053; /* 0x3053 */ + uint8_t reg_0x3057; /* 0x3057 */ + uint8_t reg_0x305c; /* 0x305c */ + uint8_t reg_0x305d; /* 0x305d */ + uint8_t reg_0x3060; /* 0x3060 */ + uint8_t reg_0x3065; /* 0x3065 */ + uint8_t reg_0x30aa; /* 0x30aa */ + uint8_t reg_0x30ab; + uint8_t reg_0x30b0; + uint8_t reg_0x30b2; + uint8_t reg_0x30d3; + uint8_t reg_0x3106; + uint8_t reg_0x310c; + uint8_t reg_0x3304; + uint8_t reg_0x3305; + uint8_t reg_0x3306; + uint8_t reg_0x3307; + uint8_t reg_0x3308; + uint8_t reg_0x3309; + uint8_t reg_0x330a; + uint8_t reg_0x330b; + uint8_t reg_0x330c; + uint8_t reg_0x330d; + uint8_t reg_0x330f; + uint8_t reg_0x3381; +}; + +struct reg_struct { + uint8_t pll_multiplier; /* 0x0307 */ + uint8_t frame_length_lines_hi; /* 0x0340*/ + uint8_t frame_length_lines_lo; /* 0x0341*/ + uint8_t y_addr_start; /* 0x347 */ + uint8_t y_add_end; /* 0x034b */ + uint8_t x_output_size_msb; /* 0x034c */ + uint8_t x_output_size_lsb; /* 0x034d */ + uint8_t y_output_size_msb; /* 0x034e */ + uint8_t y_output_size_lsb; /* 0x034f */ + uint8_t x_even_inc; /* 0x0381 */ + uint8_t x_odd_inc; /* 0x0383 */ + uint8_t y_even_inc; /* 0x0385 */ + uint8_t y_odd_inc; /* 0x0387 */ + uint8_t hmodeadd; /* 0x3001 */ + uint8_t vmodeadd; /* 0x3016 */ + uint8_t vapplinepos_start;/*ox3069*/ + uint8_t vapplinepos_end;/*306b*/ + uint8_t shutter; /* 0x3086 */ + uint8_t haddave; /* 0x30e8 */ + uint8_t lanesel; /* 0x3301 */ +}; + +struct isx012_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum isx012_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum isx012_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +enum isx012_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; +/* +struct isx012_reg { + const struct reg_struct_init *reg_pat_init; + const struct reg_struct *reg_pat; +}; +*/ +#endif /* __ISX012_H__ */ diff --git a/drivers/media/video/msm_zsl/isx012_regs.h b/drivers/media/video/msm_zsl/isx012_regs.h new file mode 100644 index 00000000000..fde2ed4c066 --- /dev/null +++ b/drivers/media/video/msm_zsl/isx012_regs.h @@ -0,0 +1,8979 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifdef __ISX012_H__ +#define __ISX012_H__ + + +struct isx012_short_t { + unsigned short subaddr; + unsigned int value; + unsigned int len; +}; + +struct isx012_short_t ISX012_Init_Reg[] = { + {0x66C2, 0x0C, 0x01},/*AF_INTERNAL_LENSDRV_ADRS*/ + {0x66C3, 0x02, 0x01},/*AF_INTERNAL_LENSDRV_SIZE*/ + {0x66C5, 0x14, 0x01},/*AF_INTERNAL_LENSDRV_SHIFT*/ + {0x66C8, 0x0000, 0x02},/*AF_INTERNAL_LENSDRV_FIXEDPTN*/ + {0x66CA, 0x000F, 0x02}, + {0x000B, 0x01, 0x01},/*AF_EXT : AF driver start*/ + + + /*ISX012_Initial_Setting.ini*/ + + + /* AE window add V02*/ + {0x6000, 0x05, 0x01}, /* CENTER_FIXWEIGHT_00_TYPE1 :*/ + {0x6001, 0x05, 0x01}, /* CENTER_FIXWEIGHT_01_TYPE1 :*/ + {0x6002, 0x05, 0x01}, /* CENTER_FIXWEIGHT_02_TYPE1 :*/ + {0x6003, 0x05, 0x01}, /* CENTER_FIXWEIGHT_03_TYPE1 :*/ + {0x6004, 0x05, 0x01}, /* CENTER_FIXWEIGHT_04_TYPE1 :*/ + {0x6005, 0x05, 0x01}, /* CENTER_FIXWEIGHT_05_TYPE1 :*/ + {0x6006, 0x05, 0x01}, /* CENTER_FIXWEIGHT_06_TYPE1 :*/ + {0x6007, 0x05, 0x01}, /* CENTER_FIXWEIGHT_07_TYPE1 :*/ + {0x6008, 0x05, 0x01}, /* CENTER_FIXWEIGHT_08_TYPE1 :*/ + {0x6009, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_09_TYPE1 :*/ + {0x600A, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_10_TYPE1 :*/ + {0x600B, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_11_TYPE1 :*/ + {0x600C, 0x17, 0x01}, /* CENTER_FIXWEIGHT_12_TYPE1 :*/ + {0x600D, 0x19, 0x01}, /* CENTER_FIXWEIGHT_13_TYPE1 :*/ + {0x600E, 0x17, 0x01}, /* CENTER_FIXWEIGHT_14_TYPE1 :*/ + {0x600F, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_15_TYPE1 :*/ + {0x6010, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_16_TYPE1 :*/ + {0x6011, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_17_TYPE1 :*/ + {0x6012, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_18_TYPE1 :*/ + {0x6013, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_19_TYPE1 :*/ + {0x6014, 0x14, 0x01}, /* CENTER_FIXWEIGHT_20_TYPE1 :*/ + {0x6015, 0x28, 0x01}, /* CENTER_FIXWEIGHT_21_TYPE1 :*/ + {0x6016, 0x3D, 0x01}, /* CENTER_FIXWEIGHT_22_TYPE1 :*/ + {0x6017, 0x28, 0x01}, /* CENTER_FIXWEIGHT_23_TYPE1 :*/ + {0x6018, 0x14, 0x01}, /* CENTER_FIXWEIGHT_24_TYPE1 :*/ + {0x6019, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_25_TYPE1 :*/ + {0x601A, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_26_TYPE1 :*/ + {0x601B, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_27_TYPE1 :*/ + {0x601C, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_28_TYPE1 :*/ + {0x601D, 0x23, 0x01}, /* CENTER_FIXWEIGHT_29_TYPE1 :*/ + {0x601E, 0x3D, 0x01}, /* CENTER_FIXWEIGHT_30_TYPE1 :*/ + {0x601F, 0x52, 0x01}, /* CENTER_FIXWEIGHT_31_TYPE1 :*/ + {0x6020, 0x3D, 0x01}, /* CENTER_FIXWEIGHT_32_TYPE1 :*/ + {0x6021, 0x23, 0x01}, /* CENTER_FIXWEIGHT_33_TYPE1 :*/ + {0x6022, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_34_TYPE1 :*/ + {0x6023, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_35_TYPE1 :*/ + {0x6024, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_36_TYPE1 :*/ + {0x6025, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_37_TYPE1 :*/ + {0x6026, 0x14, 0x01}, /* CENTER_FIXWEIGHT_38_TYPE1 :*/ + {0x6027, 0x28, 0x01}, /* CENTER_FIXWEIGHT_39_TYPE1 :*/ + {0x6028, 0x3D, 0x01}, /* CENTER_FIXWEIGHT_40_TYPE1 :*/ + {0x6029, 0x28, 0x01}, /* CENTER_FIXWEIGHT_41_TYPE1 :*/ + {0x602A, 0x14, 0x01}, /* CENTER_FIXWEIGHT_42_TYPE1 :*/ + {0x602B, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_43_TYPE1 :*/ + {0x602C, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_44_TYPE1 :*/ + {0x602D, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_45_TYPE1 :*/ + {0x602E, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_46_TYPE1 :*/ + {0x602F, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_47_TYPE1 :*/ + {0x6030, 0x0D, 0x01}, /* CENTER_FIXWEIGHT_48_TYPE1 :*/ + {0x6031, 0x2A, 0x01}, /* CENTER_FIXWEIGHT_49_TYPE1 :*/ + {0x6032, 0x0D, 0x01}, /* CENTER_FIXWEIGHT_50_TYPE1 :*/ + {0x6033, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_51_TYPE1 :*/ + {0x6034, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_52_TYPE1 :*/ + {0x6035, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_53_TYPE1 :*/ + {0x6036, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_54_TYPE1 :*/ + {0x6037, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_55_TYPE1 :*/ + {0x6038, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_56_TYPE1 :*/ + {0x6039, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_57_TYPE1 :*/ + {0x603A, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_58_TYPE1 :*/ + {0x603B, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_59_TYPE1 :*/ + {0x603C, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_60_TYPE1 :*/ + {0x603D, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_61_TYPE1 :*/ + {0x603E, 0x0A, 0x01}, /* CENTER_FIXWEIGHT_62_TYPE1 :*/ + + + /*AF filter*/ + {0x6D14, 0x0001, 0x02}, /* HPF_HBPF_CORSL_Y1 : */ + {0x6D16, 0x0001, 0x02}, /* HPF_HBPF_CORSL_Y2 : */ + {0x6D18, 0x0002, 0x02}, /* HPF_HBPF_CORSL_Y3 : */ + {0x6D1A, 0x0005, 0x02}, /* HPF_HBPF_CORSL_Y4 : */ + + {0x6D20, 0x0004, 0x02}, /* HPF_HBPF_CORL_Y1 : */ + {0x6D22, 0x0004, 0x02}, /* HPF_HBPF_CORL_Y2 : */ + {0x6D24, 0x000F, 0x02}, /* HPF_HBPF_CORL_Y3 : */ + {0x6D26, 0x001E, 0x02}, /* HPF_HBPF_CORL_Y4 : */ + + {0x6D2C, 0x000E, 0x02}, /* HPF_HBPF_CORH_Y1 : */ + {0x6D2E, 0x000F, 0x02}, /* HPF_HBPF_CORH_Y2 : */ + {0x6D30, 0x0022, 0x02}, /* HPF_HBPF_CORH_Y3 : */ + {0x6D32, 0x004D, 0x02}, /* HPF_HBPF_CORH_Y4 : */ + + {0x6D44, 0x0001, 0x02}, /* HPF_LBPF_CORSL_Y1 :*/ + {0x6D46, 0x0001, 0x02}, /* HPF_LBPF_CORSL_Y2 :*/ + {0x6D48, 0x0002, 0x02}, /* HPF_LBPF_CORSL_Y3 :*/ + {0x6D4A, 0x0004, 0x02}, /* HPF_LBPF_CORSL_Y4 :*/ + + {0x6D50, 0x03FF, 0x02}, /* HPF_LBPF_CORL_Y1 : */ + {0x6D52, 0x03FF, 0x02}, /* HPF_LBPF_CORL_Y2 : */ + {0x6D54, 0x03FF, 0x02}, /* HPF_LBPF_CORL_Y3 : */ + {0x6D56, 0x03FF, 0x02}, /* HPF_LBPF_CORL_Y4 : */ + + {0x6D5C, 0x03FF, 0x02}, /* HPF_LBPF_CORH_Y1 : */ + {0x6D5E, 0x03FF, 0x02}, /* HPF_LBPF_CORH_Y2 : */ + {0x6D60, 0x03FF, 0x02}, /* HPF_LBPF_CORH_Y3 : */ + {0x6D62, 0x03FF, 0x02}, /* HPF_LBPF_CORH_Y4 : */ + + {0x6D74, 0x0001, 0x02}, /* HPF_VHBPF_CORSL_Y1 : */ + {0x6D76, 0x0001, 0x02}, /* HPF_VHBPF_CORSL_Y2 : */ + {0x6D78, 0x0002, 0x02}, /* HPF_VHBPF_CORSL_Y3 : */ + {0x6D7A, 0x0005, 0x02}, /* HPF_VHBPF_CORSL_Y4 : */ + + {0x6D80, 0x0004, 0x02}, /* HPF_VHBPF_CORL_Y1 : */ + {0x6D82, 0x0005, 0x02}, /* HPF_VHBPF_CORL_Y2 : */ + {0x6D84, 0x000C, 0x02}, /* HPF_VHBPF_CORL_Y3 : */ + {0x6D86, 0x001C, 0x02}, /* HPF_VHBPF_CORL_Y4 : */ + + {0x6D8C, 0x000D, 0x02}, /* HPF_VHBPF_CORH_Y1 : */ + {0x6D8E, 0x0010, 0x02}, /* HPF_VHBPF_CORH_Y2 : */ + {0x6D90, 0x0026, 0x02}, /* HPF_VHBPF_CORH_Y3 : */ + {0x6D92, 0x004D, 0x02}, /* HPF_VHBPF_CORH_Y4 : */ + + /*CAF*/ + {0x6622, 0x0004, 0x02}, /* AF_CAF_PARAM_WOBBLE_STEP :*/ + {0x6624, 0x0008, 0x02}, /* AF_CAF_CLIMB_STEP :*/ + {0x6687, 0x01, 0x01}, /* AF_CAF_CLIMB_PEAK_BACK_STEP_ENABLE :*/ + {0x6698, 0x00, 0x01}, /* AF_CAF_WOBBLE_FILTER_ENABLE :*/ + {0x66A4, 0x06, 0x01}, /* AF_CAF_OPD_FLAT_MOVE_ENABLE :*/ + {0x66B0, 0x0002, 0x02}, /* AF_CAF_WAIT_FOR_AF_STABLE_TH :*/ + {0x5003, 0x04, 0x01}, /* Z1_HOLD = 1*/ + /*110819*/ + {0x6696, 0x16, 0x01}, /*AF_CAF_WOBBLE_START_INTERVAL_COUNTER*/ + {0x6716, 0x0000, 0x02}, /* CAF_LVD_WOB_HBPF_VAL1 :*/ + {0x6718, 0x0000, 0x02}, /* CAF_LVD_WOB_HBPF_VAL2 :*/ + {0x671A, 0x00C8, 0x02}, /* CAF_LVD_WOB_HBPF_RATE1 :*/ + {0x671C, 0x00C8, 0x02}, /* CAF_LVD_WOB_HBPF_RATE2 :*/ + {0x671E, 0x00, 0x01}, /* CAF_LVD_WOB_HBPF_SHIFT :*/ + {0x6720, 0x0000, 0x02}, /* CAF_LVD_WOB_LBPF_VAL1 :*/ + {0x6722, 0x0000, 0x02}, /* CAF_LVD_WOB_LBPF_VAL2 :*/ + {0x6724, 0x0014, 0x02}, /* CAF_LVD_WOB_LBPF_RATE1 :*/ + {0x6726, 0x0014, 0x02}, /* CAF_LVD_WOB_LBPF_RATE2 :*/ + {0x6728, 0x00, 0x01}, /* CAF_LVD_WOB_LBPF_SHIFT :*/ + {0x672A, 0x0000, 0x02}, /* CAF_LVD_CLMP_HBPF_VAL1 :*/ + {0x672C, 0x0000, 0x02}, /* CAF_LVD_CLMP_HBPF_VAL2 :*/ + {0x672E, 0x012C, 0x02}, /* CAF_LVD_CLMP_HBPF_RATE1 :*/ + {0x6730, 0x012C, 0x02}, /* CAF_LVD_CLMP_HBPF_RATE2 :*/ + {0x6732, 0x00, 0x01}, /* CAF_LVD_CLMP_HBPF_SHIFT :*/ + {0x6734, 0x0000, 0x02}, /* CAF_LVD_CLMP_LBPF_VAL1 :*/ + {0x6736, 0x0000, 0x02}, /* CAF_LVD_CLMP_LBPF_VAL2 :*/ + {0x6738, 0x0046, 0x02}, /* CAF_LVD_CLMP_LBPF_RATE1 :*/ + {0x673A, 0x0046, 0x02}, /* CAF_LVD_CLMP_LBPF_RATE2 :*/ + {0x673C, 0x00, 0x01}, /* CAF_LVD_CLMP_LBPF_SHIFT :*/ + {0x661E, 0x00C8, 0x02}, /*AF_CAF_FAR_POSITION*/ + {0x6620, 0x02A8, 0x02}, /*AF_CAF_NEAR_POSITION*/ + + /*SAF*/ + {0x00B2, 0x02, 0x01}, /* AFMODE_MONI : manual AF mode*/ + {0x028E, 0x00, 0x01}, /* AF_SN1_2 :*/ + {0x028F, 0x00, 0x01}, /* AF_SN3_4 :*/ + {0x0290, 0x00, 0x01}, /* AF_SN5_6 :*/ + {0x0291, 0x00, 0x01}, /* AF_SN7_8 :*/ + {0x0292, 0x00, 0x01}, /* AF_SN9_10 :*/ + {0x0293, 0x00, 0x01}, /* AF_SN11_12 :*/ + {0x6604, 0x00, 0x01}, /* AF_SEARCH_DIR :*/ + {0x6616, 0x01, 0x01}, /* AF_DIRECTBACK_F :On=1*/ + {0x661B, 0x03, 0x01}, /* AF_OPDDATA_SAVE :*/ + {0x661C, 0x00, 0x01}, /* AF_MONOTONY_POS :*/ + {0x663E, 0x01, 0x01}, /* AF_SEARCH_SECOND_DIR :*/ + {0x663F, 0x01, 0x01}, /* AF_DIRECTBACK_SECOND_F :*/ + {0x6674, 0x00, 0x01}, /* AF_MONICHG_MOVE_F :*/ + {0x6675, 0x01, 0x01}, /* CAP_AF_CANCEL_F :*/ + {0x6676, 0x02, 0x01}, /* AF_SAxF_MODE :*/ + {0x669E, 0x02, 0x01}, /* AF_SECOND_WND_CHK :*/ + {0x6600, 0x00C8, 0x02}, /* AF_SEARCH_AREA_LOW :*/ + {0x6602, 0x02A8, 0x02}, /* AF_SEARCH_AREA_HIGH :*/ + {0x6640, 0x02, 0x01}, /* AF_DROPN_ON_PEAK_DETECT_SECOND :*/ + {0x6641, 0x02, 0x01}, /* AF_UPN_ON_PEAK_DETECT_SECOND :*/ + {0x6642, 0x02, 0x01}, /*AF_DROPRATE_ON_DETECT_SECOND_HBPF*/ + {0x6643, 0x02, 0x01}, /*AF_DROPRATE_ON_DETECT_SECOND_LBPF*/ + {0x6644, 0x14, 0x01}, /* AF_UPRATE_ON_PEAK_DETECT_HBPF_SECOND :*/ + {0x6646, 0x08, 0x01}, /* AF_OPD_WEIGHT_TH :*/ + {0x664A, 0x04, 0x01}, /* AF_DROPN_ON_PEAK_DETECT :*/ + {0x664B, 0x02, 0x01}, /* AF_UPN_ON_PEAK_DETECT :*/ + {0x664C, 0xFF, 0x01}, /* AF_UPRATE_ON_PEAK_DETECT_HBPF :*/ + {0x665A, 0x00C8, 0x02}, /* AF_LENSPOS_ON_AFNG :*/ + {0x665C, 0x0018, 0x02}, /* AF_DRV_AMOUNT_TONEAR_F :*/ + {0x665E, 0x0008, 0x02}, /* AF_DRV_AMOUNT_TONEAR_S :*/ + {0x6660, 0x0018, 0x02}, /* AF_DRV_AMOUNT_TOFAR_F :*/ + {0x6662, 0x0008, 0x02}, /* AF_DRV_AMOUNT_TOFAR_S :*/ + {0x6666, 0x00C8, 0x02}, /* AF_AREA_LOW_TYPE1 :*/ + {0x6668, 0x02A8, 0x02}, /* AF_AREA_HIGH_TYPE1 :*/ + {0x669A, 0x01F4, 0x02}, /* AF_OPD_MONOTONYUP_HBPF_TH :*/ + {0x66E4, 0x50, 0x01}, /* AF_TH_1STDEPEND_HBPF_RATE :*/ + {0x66EE, 0x07D0, 0x02}, /* AF_LVD_HBPF_VAL1_1ST :*/ + {0x66F0, 0x7530, 0x02}, /* AF_LVD_HBPF_VAL2_1ST :*/ + {0x66F2, 0x004C, 0x02}, /* AF_LVD_HBPF_RATE1_1ST :*/ + {0x66F4, 0x0019, 0x02}, /* AF_LVD_HBPF_RATE2_1ST :*/ + {0x66F6, 0x00, 0x01}, /* AF_LVD_HBPF_SHIFT_1ST :*/ + {0x6702, 0x03E8, 0x02}, /* AF_LVD_HBPF_VAL1_2ND :*/ + {0x6704, 0x4E20, 0x02}, /* AF_LVD_HBPF_VAL2_2ND :*/ + {0x6706, 0x0003, 0x02}, /* AF_LVD_HBPF_RATE1_2ND :*/ + {0x6708, 0x0003, 0x02}, /* AF_LVD_HBPF_RATE2_2ND :*/ + {0x670A, 0x00, 0x01}, /* AF_LVD_HBPF_SHIFT_2ND :*/ + {0x6742, 0x0020, 0x02}, /* AF_SEARCH_OFFSET_FAR :*/ + {0x6744, 0x0018, 0x02}, /* AF_SEARCH_OFFSET_NEAR :*/ + /*chooys add*/ + {0x6677, 0x00, 0x01}, /* AF_SEND_PARTITION : Use=1*/ + {0x6678, 0x20, 0x01}, /* AF_SENDNUM_ALL*/ + {0x6679, 0x01, 0x01}, /* AF_SENDNUM_UP*/ + {0x667A, 0x01, 0x01}, /* AF_SENDNUM_DOWN*/ + {0x667C, 0x0002, 0x02}, /* AF_SENDAMOUNT_ADDLIMIT*/ + {0x667E, 0x0020, 0x02}, /*AF_SENDLINE*/ + + + {0x6A50, 0x03F6, 0x02}, /*AF_OPD4_HDELAY (3A) = 1014*/ + {0x6A52, 0x0280, 0x02}, /*AF_OPD4_VDELAY (3A) = 640*/ + {0x6A54, 0x0234, 0x02}, /*AF_OPD4_HVALID (3A) = 564*/ + {0x6A56, 0x0298, 0x02}, /*AF_OPD4_VVALID (3A) = 664*/ + {0x6A58, 0x0360, 0x02}, /*AF_OPD4_HDELAY (3B) = 864*/ + {0x6A5A, 0x021C, 0x02}, /*AF_OPD4_VDELAY (3B) = 540*/ + {0x6A5C, 0x0360, 0x02}, /*AF_OPD4_HVALID (3B) = 864*/ + {0x6A5E, 0x0360, 0x02}, /*AF_OPD4_VVALID (3B) = 864*/ + {0x6A80, 0x01, 0x01}, /*AF_OPD1A_WEIGHT*/ + {0x6A81, 0x01, 0x01}, /*AF_OPD1B_WEIGHT*/ + {0x6A82, 0x00, 0x01}, /*AF_OPD2A_WEIGHT*/ + {0x6A83, 0x00, 0x01}, /*AF_OPD2B_WEIGHT*/ + {0x6A84, 0x08, 0x01}, /*AF_OPD3A_WEIGHT*/ + {0x6A85, 0x06, 0x01}, /*AF_OPD3B_WEIGHT*/ + {0x6A86, 0x00, 0x01}, /*AF_OPD4A_WEIGHT*/ + {0x6A87, 0x00, 0x01}, /*AF_OPD4B_WEIGHT*/ + {0x6A88, 0x00, 0x01}, /*AF_OPD5A_WEIGHT*/ + {0x6A89, 0x00, 0x01}, /*AF_OPD5B_WEIGHT*/ + /*lee haknoh add*/ + {0x661C, 0x00, 0x01}, + /*S,66BE, 0F,8, AF_JUDGE_CONF*/ + /*S,669A, 01F4,16, AF_OPD_MONOTONYUP_HBPF_TH*/ + /*S,669C, 03E8,16, AF_OPD_MONOTONYUP_LBPF_TH*/ + {0x673D, 0x01, 0x01}, /*AF_MANUAL_MOVE_TYTPE :*/ + {0x6648, 0x00C8, 0x02}, /*AF_MANUAL_POS*/ + {0x66E0, 0x00C8, 0x02}, /*AF_POS_INF_SET*/ + {0x66E2, 0x02A8, 0x02}, /*AF_POS_MACRO_SET*/ + {0x00B2, 0x02, 0x01}, /*AFMODE_MONI : Manual AF mode*/ + + {0x00F7, 0x52, 0x01}, /* INIT_QLTY0 : Standard 82*/ + {0x00F8, 0x59, 0x01}, /* INIT_QLTY1 : Fine 89*/ + {0x00F9, 0x5F, 0x01}, /* INIT_QLTY2 : SuperFine 95*/ + + /* normal scene1 preview, capture AE line*/ + {0x0326, 0x21, 0x01}, /* SHTCTRLTIME1_TYPE1 :*/ + {0x0327, 0x19, 0x01}, /* AGCGAIN1_TYPE1 :*/ + {0x0328, 0x52, 0x01}, /* SHTCTRLTIME2_TYPE1 :*/ + {0x0329, 0x23, 0x01}, /* AGCGAIN2_TYPE1 :*/ + {0x032A, 0x3E, 0x01}, /* SHTCTRLTIME3_TYPE1 :*/ + {0x032B, 0x3D, 0x01}, /* AGCGAIN3_TYPE1 :*/ + + /* half release max 20 fps normal AE mode*/ + {0x032C, 0x64, 0x01}, /* SHTCTRLTIME1_TYPE2*/ + {0x032D, 0x40, 0x01}, /* AGCGAIN1_TYPE2*/ + {0x032E, 0x64, 0x01}, /* SHTCTRLTIME2_TYPE2*/ + {0x032F, 0x40, 0x01}, /* AGCGAIN2_TYPE2*/ + {0x0330, 0x32, 0x01}, /* SHTCTRLTIME3_TYPE2*/ + {0x0331, 0x40, 0x01}, /* AGCGAIN3_TYPE2*/ + + {0x0332, 0x21, 0x01}, /* SHTCTRLTIME1_TYPE3 :*/ + {0x0333, 0x3C, 0x01}, /* AGCGAIN1_TYPE3 :*/ + {0x0334, 0x21, 0x01}, /* SHTCTRLTIME2_TYPE3 :*/ + {0x0335, 0x3C, 0x01}, /* AGCGAIN2_TYPE3 :*/ + {0x0336, 0x10, 0x01}, /* SHTCTRLTIME3_TYPE3 :*/ + {0x0337, 0x3C, 0x01}, /* AGCGAIN3_TYPE3 :*/ + + {0x0344, 0x21, 0x01}, /* SHTCTRLTIME1_TYPE6 :*/ + {0x0345, 0x17, 0x01}, /* AGCGAIN1_TYPE6 :*/ + {0x0346, 0x52, 0x01}, /* SHTCTRLTIME2_TYPE6 :*/ + {0x0347, 0x21, 0x01}, /* AGCGAIN2_TYPE6 :*/ + {0x0348, 0xFA, 0x01}, /* SHTCTRLTIME3_TYPE6 :*/ + {0x0349, 0x3D, 0x01}, /* AGCGAIN3_TYPE6 :*/ + + /* fire mode line*/ + {0x0356, 0x01, 0x01}, /* SHTCTRLTIME1_TYPE9 :*/ + {0x0357, 0x00, 0x01}, /* AGCGAIN1_TYPE9 :*/ + {0x0358, 0x01, 0x01}, /* SHTCTRLTIME2_TYPE9 :*/ + {0x0359, 0x00, 0x01}, /* AGCGAIN2_TYPE9 :*/ + {0x035A, 0xFF, 0x01}, /* SHTCTRLTIME3_TYPE9 :*/ + {0x035B, 0x00, 0x01}, /* AGCGAIN3_TYPE9 :*/ + + /* fire mode AF line*/ + {0x035C, 0x01, 0x01}, /* SHTCTRLTIME1_TYPE10 :*/ + {0x035D, 0x00, 0x01}, /* AGCGAIN1_TYPE10 :*/ + {0x035E, 0x01, 0x01}, /* SHTCTRLTIME2_TYPE10 :*/ + {0x035F, 0x00, 0x01}, /* AGCGAIN2_TYPE10 :*/ + {0x0360, 0xFF, 0x01}, /* SHTCTRLTIME3_TYPE10 :*/ + {0x0361, 0x00, 0x01}, /* AGCGAIN3_TYPE10 :*/ + + + /*AE ref tunning*/ + {0x5E8A, 0x00, 0x01}, /* EVREF_GAIN_A :*/ + {0x5E8B, 0x00, 0x01}, /* EVREF_GAIN_B :*/ + {0x5E8C, 0xFC, 0x01}, /* EVREF_GAIN_C :*/ + {0x5E8D, 0xFC, 0x01}, /* EVREF_GAIN_D :*/ + {0x5E8E, 0xFC, 0x01}, /* EVREF_GAIN_E :*/ + {0x5E8F, 0x90, 0x01}, /* EVREF_TH_A :*/ + {0x5E90, 0x94, 0x01}, /* EVREF_TH_B :*/ + {0x5E91, 0xA5, 0x01}, /* EVREF_TH_C :*/ + {0x5E92, 0xC0, 0x01}, /* EVREF_TH_D :*/ + {0x5E93, 0xD5, 0x01}, /* EVREF_TH_E :*/ + + + /*gamma Ilumi*/ + {0x9211, 0x58, 0x01}, /* GAIN_TH_A_TYPE3 :*/ + {0x9212, 0x63, 0x01}, /* GAIN_TH_B_TYPE3 :*/ + {0x9213, 0x9F, 0x01}, /* GAIN_TH_C_TYPE3 :*/ + + {0x984E, 0x0A, 0x01}, /* GAMMA0_0CLIP_A :*/ + {0x984F, 0x0A, 0x01}, /* GAMMA0_0CLIP_B :*/ + {0x9850, 0x05, 0x01}, /* GAMMA0_0CLIP_C :*/ + {0x9851, 0x1E, 0x01}, /* GAMMA0_SLOPE_A :*/ + {0x9852, 0x1E, 0x01}, /* GAMMA0_SLOPE_B :*/ + {0x9853, 0x1E, 0x01}, /* GAMMA0_SLOPE_C :*/ + {0x9854, 0x0A, 0x01}, /* GAMMA1_0CLIP_A :*/ + {0x9855, 0x0F, 0x01}, /* GAMMA1_0CLIP_B :*/ + {0x9856, 0x0F, 0x01}, /* GAMMA1_0CLIP_C :*/ + {0x9857, 0x32, 0x01}, /* GAMMA1_SLOPE_A :*/ + {0x9858, 0x1E, 0x01}, /* GAMMA1_SLOPE_B :*/ + {0x9859, 0x1E, 0x01}, /* GAMMA1_SLOPE_C :*/ + + + /*Gammma Table 0*/ + {0x7000, 0x0000, 0x02}, /* G0_KNOT_G0 :*/ + {0x7002, 0x000A, 0x02}, /* G0_KNOT_G1 :*/ + {0x7004, 0x0023, 0x02}, /* G0_KNOT_G2 :*/ + {0x7006, 0x0038, 0x02}, /* G0_KNOT_G3 :*/ + {0x7008, 0x0046, 0x02}, /* G0_KNOT_G4 :*/ + {0x700A, 0x0053, 0x02}, /* G0_KNOT_G5 :*/ + {0x700C, 0x005A, 0x02}, /* G0_KNOT_G6 :*/ + {0x700E, 0x0063, 0x02}, /* G0_KNOT_G7 :*/ + {0x7010, 0x006D, 0x02}, /* G0_KNOT_G8 :*/ + {0x7012, 0x0076, 0x02}, /* G0_KNOT_G9 :*/ + {0x7014, 0x0055, 0x02}, /* G0_KNOT_G10 :*/ + {0x7016, 0x008E, 0x02}, /* G0_KNOT_G11 :*/ + {0x7018, 0x00B9, 0x02}, /* G0_KNOT_G12 :*/ + {0x701A, 0x00D5, 0x02}, /* G0_KNOT_G13 :*/ + {0x701C, 0x00E4, 0x02}, /* G0_KNOT_G14 :*/ + {0x701E, 0x00F0, 0x02}, /* G0_KNOT_G15 :*/ + {0x7020, 0x00F9, 0x02}, /* G0_KNOT_G16 :*/ + {0x7022, 0x0103, 0x02}, /* G0_KNOT_G17 :*/ + {0x7024, 0x010C, 0x02}, /* G0_KNOT_G18 :*/ + {0x7026, 0x00, 0x01}, /* G0_KNOT_R0_OFFSET :*/ + {0x7027, 0x00, 0x01}, /* G0_KNOT_R2_OFFSET :*/ + {0x7028, 0x00, 0x01}, /* G0_KNOT_R4_OFFSET :*/ + {0x7029, 0x00, 0x01}, /* G0_KNOT_R6_OFFSET :*/ + {0x702A, 0x00, 0x01}, /* G0_KNOT_R8_OFFSET :*/ + {0x702B, 0x00, 0x01}, /* G0_KNOT_R10_OFFSET :*/ + {0x702C, 0x00, 0x01}, /* G0_KNOT_R12_OFFSET :*/ + {0x702D, 0x00, 0x01}, /* G0_KNOT_R14_OFFSET :*/ + {0x702E, 0x00, 0x01}, /* G0_KNOT_R16_OFFSET :*/ + {0x702F, 0x00, 0x01}, /* G0_KNOT_R18_OFFSET :*/ + {0x7030, 0x00, 0x01}, /* G0_KNOT_B0_OFFSET :*/ + {0x7031, 0x00, 0x01}, /* G0_KNOT_B2_OFFSET :*/ + {0x7032, 0x00, 0x01}, /* G0_KNOT_B4_OFFSET :*/ + {0x7033, 0x00, 0x01}, /* G0_KNOT_B6_OFFSET :*/ + {0x7034, 0x00, 0x01}, /* G0_KNOT_B8_OFFSET :*/ + {0x7035, 0x00, 0x01}, /* G0_KNOT_B10_OFFSET :*/ + {0x7036, 0x00, 0x01}, /* G0_KNOT_B12_OFFSET :*/ + {0x7037, 0x00, 0x01}, /* G0_KNOT_B14_OFFSET :*/ + {0x7038, 0x00, 0x01}, /* G0_KNOT_B16_OFFSET :*/ + {0x7039, 0x00, 0x01}, /* G0_KNOT_B18_OFFSET :*/ + {0x703A, 0x0611, 0x02}, /* G0_LOWGM_ON_R :*/ + {0x703C, 0x1E0A, 0x02}, /* G0_0CLIP_R :*/ + {0x703E, 0x0611, 0x02}, /* G0_LOWGM_ON_G :*/ + {0x7040, 0x1E0A, 0x02}, /* G0_0CLIP_G :*/ + {0x7042, 0x0611, 0x02}, /* G0_LOWGM_ON_B :*/ + {0x7044, 0x1E0A, 0x02}, /* G0_0CLIP_B :*/ + {0x7046, 0x91, 0x01}, /* G0_KNOT_GAINCTRL_TH_L :*/ + {0x7047, 0x96, 0x01}, /* G0_KNOT_GAINCTRL_TH_H :*/ + {0x7048, 0x0000, 0x02}, /* G0_KNOT_L_G0 :*/ + {0x704A, 0x0007, 0x02}, /* G0_KNOT_L_G1 :*/ + {0x704C, 0x001D, 0x02}, /* G0_KNOT_L_G2 :*/ + {0x704E, 0x002F, 0x02}, /* G0_KNOT_L_G3 :*/ + {0x7050, 0x003D, 0x02}, /* G0_KNOT_L_G4 :*/ + {0x7052, 0x004A, 0x02}, /* G0_KNOT_L_G5 :*/ + {0x7054, 0x0051, 0x02}, /* G0_KNOT_L_G6 :*/ + {0x7056, 0x005A, 0x02}, /* G0_KNOT_L_G7 :*/ + {0x7058, 0x0061, 0x02}, /* G0_KNOT_L_G8 :*/ + {0x705A, 0x006A, 0x02}, /* G0_KNOT_L_G9 :*/ + {0x705C, 0x0049, 0x02}, /* G0_KNOT_L_G10 :*/ + {0x705E, 0x0082, 0x02}, /* G0_KNOT_L_G11 :*/ + {0x7060, 0x00AD, 0x02}, /* G0_KNOT_L_G12 :*/ + {0x7062, 0x00CC, 0x02}, /* G0_KNOT_L_G13 :*/ + {0x7064, 0x00E1, 0x02}, /* G0_KNOT_L_G14 :*/ + {0x7066, 0x00ED, 0x02}, /* G0_KNOT_L_G15 :*/ + {0x7068, 0x00F6, 0x02}, /* G0_KNOT_L_G16 :*/ + {0x706A, 0x0106, 0x02}, /* G0_KNOT_L_G17 :*/ + {0x706C, 0x010C, 0x02}, /* G0_KNOT_L_G18 :*/ + + /*Gammma Table 1*/ + {0x7200, 0x0000, 0x02}, /* G1_KNOT_G0 :*/ + {0x7202, 0x0008, 0x02}, /* G1_KNOT_G1 :*/ + {0x7204, 0x0020, 0x02}, /* G1_KNOT_G2 :*/ + {0x7206, 0x0037, 0x02}, /* G1_KNOT_G3 :*/ + {0x7208, 0x004D, 0x02}, /* G1_KNOT_G4 :*/ + {0x720A, 0x0064, 0x02}, /* G1_KNOT_G5 :*/ + {0x720C, 0x006E, 0x02}, /* G1_KNOT_G6 :*/ + {0x720E, 0x0072, 0x02}, /* G1_KNOT_G7 :*/ + {0x7210, 0x007A, 0x02}, /* G1_KNOT_G8 :*/ + {0x7212, 0x007E, 0x02}, /* G1_KNOT_G9 :*/ + {0x7214, 0x0064, 0x02}, /* G1_KNOT_G10 :*/ + {0x7216, 0x0093, 0x02}, /* G1_KNOT_G11 :*/ + {0x7218, 0x00B7, 0x02}, /* G1_KNOT_G12 :*/ + {0x721A, 0x00CD, 0x02}, /* G1_KNOT_G13 :*/ + {0x721C, 0x00DD, 0x02}, /* G1_KNOT_G14 :*/ + {0x721E, 0x00ED, 0x02}, /* G1_KNOT_G15 :*/ + {0x7220, 0x00F9, 0x02}, /* G1_KNOT_G16 :*/ + {0x7222, 0x0102, 0x02}, /* G1_KNOT_G17 :*/ + {0x7224, 0x0101, 0x02}, /* G1_KNOT_G18 :*/ + {0x7226, 0x00, 0x01}, /* G1_KNOT_R0_OFFSET :*/ + {0x7227, 0x00, 0x01}, /* G1_KNOT_R2_OFFSET :*/ + {0x7228, 0x00, 0x01}, /* G1_KNOT_R4_OFFSET :*/ + {0x7229, 0x00, 0x01}, /* G1_KNOT_R6_OFFSET :*/ + {0x722A, 0x00, 0x01}, /* G1_KNOT_R8_OFFSET :*/ + {0x722B, 0x00, 0x01}, /* G1_KNOT_R10_OFFSET :*/ + {0x722C, 0x00, 0x01}, /* G1_KNOT_R12_OFFSET :*/ + {0x722D, 0x00, 0x01}, /* G1_KNOT_R14_OFFSET :*/ + {0x722E, 0x00, 0x01}, /* G1_KNOT_R16_OFFSET :*/ + {0x722F, 0x00, 0x01}, /* G1_KNOT_R18_OFFSET :*/ + {0x7230, 0x00, 0x01}, /* G1_KNOT_B0_OFFSET :*/ + {0x7231, 0x00, 0x01}, /* G1_KNOT_B2_OFFSET :*/ + {0x7232, 0x00, 0x01}, /* G1_KNOT_B4_OFFSET :*/ + {0x7233, 0x00, 0x01}, /* G1_KNOT_B6_OFFSET :*/ + {0x7234, 0x00, 0x01}, /* G1_KNOT_B8_OFFSET :*/ + {0x7235, 0x00, 0x01}, /* G1_KNOT_B10_OFFSET :*/ + {0x7236, 0x00, 0x01}, /* G1_KNOT_B12_OFFSET :*/ + {0x7237, 0x00, 0x01}, /* G1_KNOT_B14_OFFSET :*/ + {0x7238, 0x00, 0x01}, /* G1_KNOT_B16_OFFSET :*/ + {0x7239, 0x00, 0x01}, /* G1_KNOT_B18_OFFSET :*/ + {0x723A, 0x0321, 0x02}, /* G1_LOWGM_ON_R :*/ + {0x723C, 0x0C00, 0x02}, /* G1_0CLIP_R :*/ + {0x723E, 0x0321, 0x02}, /* G1_LOWGM_ON_G :*/ + {0x7240, 0x0C00, 0x02}, /* G1_0CLIP_G :*/ + {0x7242, 0x0321, 0x02}, /* G1_LOWGM_ON_B :*/ + {0x7244, 0x0C00, 0x02}, /* G1_0CLIP_B :*/ + + + /*AWB tuning*/ + {0x64A4, 0xFF, 0x01}, /* OUTFRM_LEFT00 :*/ + {0x64A5, 0xFF, 0x01}, /* OUTFRM_LEFT01 :*/ + {0x64A6, 0xFF, 0x01}, /* OUTFRM_LEFT02 :*/ + {0x64A7, 0xFF, 0x01}, /* OUTFRM_LEFT03 :*/ + {0x64A8, 0xFF, 0x01}, /* OUTFRM_LEFT04 :*/ + {0x64A9, 0xFF, 0x01}, /* OUTFRM_LEFT05 :*/ + {0x64AA, 0xFF, 0x01}, /* OUTFRM_LEFT06 :*/ + {0x64AB, 0xFF, 0x01}, /* OUTFRM_LEFT07 :*/ + {0x64AC, 0xFF, 0x01}, /* OUTFRM_LEFT08 :*/ + {0x64AD, 0xFD, 0x01}, /* OUTFRM_LEFT09 :*/ + {0x64AE, 0xCB, 0x01}, /* OUTFRM_LEFT10 :*/ + {0x64AF, 0xA9, 0x01}, /* OUTFRM_LEFT11 :*/ + {0x64B0, 0x90, 0x01}, /* OUTFRM_LEFT12 :*/ + {0x64B1, 0x7D, 0x01}, /* OUTFRM_LEFT13 :*/ + {0x64B2, 0x70, 0x01}, /* OUTFRM_LEFT14 :*/ + {0x64B3, 0x65, 0x01}, /* OUTFRM_LEFT15 :*/ + {0x64B4, 0x5C, 0x01}, /* OUTFRM_LEFT16 :*/ + {0x64B5, 0x55, 0x01}, /* OUTFRM_LEFT17 :*/ + {0x64B6, 0x4F, 0x01}, /* OUTFRM_LEFT18 :*/ + {0x64B7, 0x32, 0x01}, /* OUTFRM_LEFT19 :*/ + {0x64B8, 0x4D, 0x01}, /* OUTFRM_LEFT20 :*/ + {0x64B9, 0x40, 0x01}, /* OUTFRM_LEFT21 :*/ + {0x64BA, 0x2D, 0x01}, /* OUTFRM_LEFT22 :*/ + {0x64BB, 0x2B, 0x01}, /* OUTFRM_LEFT23 :*/ + {0x64BC, 0x29, 0x01}, /* OUTFRM_LEFT24 :*/ + {0x64BD, 0x27, 0x01}, /* OUTFRM_LEFT25 :*/ + {0x64BE, 0x25, 0x01}, /* OUTFRM_LEFT26 :*/ + {0x64BF, 0x23, 0x01}, /* OUTFRM_LEFT27 :*/ + {0x64C0, 0x21, 0x01}, /* OUTFRM_LEFT28 :*/ + {0x64C1, 0x1F, 0x01}, /* OUTFRM_LEFT29 :*/ + {0x64C2, 0x1D, 0x01}, /* OUTFRM_LEFT30 :*/ + {0x64C3, 0x1B, 0x01}, /* OUTFRM_LEFT31 :*/ + {0x64C4, 0x1A, 0x01}, /* OUTFRM_LEFT32 :*/ + {0x64C5, 0x1A, 0x01}, /* OUTFRM_LEFT33 :*/ + {0x64C6, 0x1A, 0x01}, /* OUTFRM_LEFT34 :*/ + {0x64C7, 0x28, 0x01}, /* OUTFRM_LEFT35 :*/ + {0x64C8, 0x27, 0x01}, /* OUTFRM_LEFT36 :*/ + {0x64C9, 0x26, 0x01}, /* OUTFRM_LEFT37 :*/ + {0x64CA, 0xFF, 0x01}, /* OUTFRM_RIGHT00 :*/ + {0x64CB, 0xFF, 0x01}, /* OUTFRM_RIGHT01 :*/ + {0x64CC, 0xFF, 0x01}, /* OUTFRM_RIGHT02 :*/ + {0x64CD, 0xFF, 0x01}, /* OUTFRM_RIGHT03 :*/ + {0x64CE, 0xFF, 0x01}, /* OUTFRM_RIGHT04 :*/ + {0x64CF, 0xFF, 0x01}, /* OUTFRM_RIGHT05 :*/ + {0x64D0, 0xFF, 0x01}, /* OUTFRM_RIGHT06 :*/ + {0x64D1, 0xFF, 0x01}, /* OUTFRM_RIGHT07 :*/ + {0x64D2, 0xFF, 0x01}, /* OUTFRM_RIGHT08 :*/ + {0x64D3, 0xFF, 0x01}, /* OUTFRM_RIGHT09 :*/ + {0x64D4, 0xD3, 0x01}, /* OUTFRM_RIGHT10 :*/ + {0x64D5, 0xB1, 0x01}, /* OUTFRM_RIGHT11 :*/ + {0x64D6, 0x98, 0x01}, /* OUTFRM_RIGHT12 :*/ + {0x64D7, 0x85, 0x01}, /* OUTFRM_RIGHT13 :*/ + {0x64D8, 0x78, 0x01}, /* OUTFRM_RIGHT14 :*/ + {0x64D9, 0x6D, 0x01}, /* OUTFRM_RIGHT15 :*/ + {0x64DA, 0x64, 0x01}, /* OUTFRM_RIGHT16 :*/ + {0x64DB, 0x5D, 0x01}, /* OUTFRM_RIGHT17 :*/ + {0x64DC, 0x57, 0x01}, /* OUTFRM_RIGHT18 :*/ + {0x64DD, 0x63, 0x01}, /* OUTFRM_RIGHT19 :*/ + {0x64DE, 0x5E, 0x01}, /* OUTFRM_RIGHT20 :*/ + {0x64DF, 0x5A, 0x01}, /* OUTFRM_RIGHT21 :*/ + {0x64E0, 0x56, 0x01}, /* OUTFRM_RIGHT22 :*/ + {0x64E1, 0x52, 0x01}, /* OUTFRM_RIGHT23 :*/ + {0x64E2, 0x50, 0x01}, /* OUTFRM_RIGHT24 :*/ + {0x64E3, 0x4E, 0x01}, /* OUTFRM_RIGHT25 :*/ + {0x64E4, 0x4C, 0x01}, /* OUTFRM_RIGHT26 :*/ + {0x64E5, 0x4A, 0x01}, /* OUTFRM_RIGHT27 :*/ + {0x64E6, 0x48, 0x01}, /* OUTFRM_RIGHT28 :*/ + {0x64E7, 0x46, 0x01}, /* OUTFRM_RIGHT29 :*/ + {0x64E8, 0x44, 0x01}, /* OUTFRM_RIGHT30 :*/ + {0x64E9, 0x43, 0x01}, /* OUTFRM_RIGHT31 :*/ + {0x64EA, 0x42, 0x01}, /* OUTFRM_RIGHT32 :*/ + {0x64EB, 0x42, 0x01}, /* OUTFRM_RIGHT33 :*/ + {0x64EC, 0x42, 0x01}, /* OUTFRM_RIGHT34 :*/ + {0x64ED, 0x30, 0x01}, /* OUTFRM_RIGHT35 :*/ + {0x64EE, 0x2F, 0x01}, /* OUTFRM_RIGHT36 :*/ + {0x64EF, 0x2E, 0x01}, /* OUTFRM_RIGHT37 :*/ + {0x64F0, 0x1D92, 0x02}, /* OUTFRM_TOP :*/ + {0x64F2, 0x1400, 0x02}, /* OUTFRM_BOTM :*/ + {0x64F4, 0x19, 0x01}, /* OUTFRM_FLTOP :*/ + {0x64F5, 0x14, 0x01}, /* OUTFRM_FLBOTM :*/ + {0x64F6, 0xFF, 0x01}, /* OUTAIM_LEFT00 :*/ + {0x64F7, 0xFF, 0x01}, /* OUTAIM_LEFT01 :*/ + {0x64F8, 0xFF, 0x01}, /* OUTAIM_LEFT02 :*/ + {0x64F9, 0xFF, 0x01}, /* OUTAIM_LEFT03 :*/ + {0x64FA, 0xFF, 0x01}, /* OUTAIM_LEFT04 :*/ + {0x64FB, 0xFF, 0x01}, /* OUTAIM_LEFT05 :*/ + {0x64FC, 0xFF, 0x01}, /* OUTAIM_LEFT06 :*/ + {0x64FD, 0xFF, 0x01}, /* OUTAIM_LEFT07 :*/ + {0x64FE, 0xFF, 0x01}, /* OUTAIM_LEFT08 :*/ + {0x64FF, 0xFF, 0x01}, /* OUTAIM_LEFT09 :*/ + {0x6500, 0x91, 0x01}, /* OUTAIM_LEFT10 :*/ + {0x6501, 0x91, 0x01}, /* OUTAIM_LEFT11 :*/ + {0x6502, 0x91, 0x01}, /* OUTAIM_LEFT12 :*/ + {0x6503, 0x66, 0x01}, /* OUTAIM_LEFT13 :*/ + {0x6504, 0x5D, 0x01}, /* OUTAIM_LEFT14 :*/ + {0x6505, 0x3C, 0x01}, /* OUTAIM_LEFT15 :*/ + {0x6506, 0x3C, 0x01}, /* OUTAIM_LEFT16 :*/ + {0x6507, 0x3C, 0x01}, /* OUTAIM_LEFT17 :*/ + {0x6508, 0x3A, 0x01}, /* OUTAIM_LEFT18 :*/ + {0x6509, 0x39, 0x01}, /* OUTAIM_LEFT19 :*/ + {0x650A, 0x40, 0x01}, /* OUTAIM_LEFT20 :*/ + {0x650B, 0x46, 0x01}, /* OUTAIM_LEFT21 :*/ + {0x650C, 0x42, 0x01}, /* OUTAIM_LEFT22 :*/ + {0x650D, 0x40, 0x01}, /* OUTAIM_LEFT23 :*/ + {0x650E, 0x3C, 0x01}, /* OUTAIM_LEFT24 :*/ + {0x650F, 0x37, 0x01}, /* OUTAIM_LEFT25 :*/ + {0x6510, 0x34, 0x01}, /* OUTAIM_LEFT26 :*/ + {0x6511, 0x32, 0x01}, /* OUTAIM_LEFT27 :*/ + {0x6512, 0x2F, 0x01}, /* OUTAIM_LEFT28 :*/ + {0x6513, 0x2E, 0x01}, /* OUTAIM_LEFT29 :*/ + {0x6514, 0x2C, 0x01}, /* OUTAIM_LEFT30 :*/ + {0x6515, 0x2A, 0x01}, /* OUTAIM_LEFT31 :*/ + {0x6516, 0x2D, 0x01}, /* OUTAIM_LEFT32 :*/ + {0x6517, 0x2C, 0x01}, /* OUTAIM_LEFT33 :*/ + {0x6518, 0x2B, 0x01}, /* OUTAIM_LEFT34 :*/ + {0x6519, 0x2A, 0x01}, /* OUTAIM_LEFT35 :*/ + {0x651A, 0x29, 0x01}, /* OUTAIM_LEFT36 :*/ + {0x651B, 0x28, 0x01}, /* OUTAIM_LEFT37 :*/ + {0x651C, 0xFF, 0x01}, /* OUTAIM_RIGHT00 :*/ + {0x651D, 0xFF, 0x01}, /* OUTAIM_RIGHT01 :*/ + {0x651E, 0xFF, 0x01}, /* OUTAIM_RIGHT02 :*/ + {0x651F, 0xFF, 0x01}, /* OUTAIM_RIGHT03 :*/ + {0x6520, 0xFF, 0x01}, /* OUTAIM_RIGHT04 :*/ + {0x6521, 0xFF, 0x01}, /* OUTAIM_RIGHT05 :*/ + {0x6522, 0xFF, 0x01}, /* OUTAIM_RIGHT06 :*/ + {0x6523, 0xFF, 0x01}, /* OUTAIM_RIGHT07 :*/ + {0x6524, 0xFF, 0x01}, /* OUTAIM_RIGHT08 :*/ + {0x6525, 0xFF, 0x01}, /* OUTAIM_RIGHT09 :*/ + {0x6526, 0xD9, 0x01}, /* OUTAIM_RIGHT10 :*/ + {0x6527, 0xB7, 0x01}, /* OUTAIM_RIGHT11 :*/ + {0x6528, 0x96, 0x01}, /* OUTAIM_RIGHT12 :*/ + {0x6529, 0x6C, 0x01}, /* OUTAIM_RIGHT13 :*/ + {0x652A, 0x64, 0x01}, /* OUTAIM_RIGHT14 :*/ + {0x652B, 0x62, 0x01}, /* OUTAIM_RIGHT15 :*/ + {0x652C, 0x62, 0x01}, /* OUTAIM_RIGHT16 :*/ + {0x652D, 0x61, 0x01}, /* OUTAIM_RIGHT17 :*/ + {0x652E, 0x60, 0x01}, /* OUTAIM_RIGHT18 :*/ + {0x652F, 0x5E, 0x01}, /* OUTAIM_RIGHT19 :*/ + {0x6530, 0x5B, 0x01}, /* OUTAIM_RIGHT20 :*/ + {0x6531, 0x4F, 0x01}, /* OUTAIM_RIGHT21 :*/ + {0x6532, 0x4B, 0x01}, /* OUTAIM_RIGHT22 :*/ + {0x6533, 0x49, 0x01}, /* OUTAIM_RIGHT23 :*/ + {0x6534, 0x44, 0x01}, /* OUTAIM_RIGHT24 :*/ + {0x6535, 0x3F, 0x01}, /* OUTAIM_RIGHT25 :*/ + {0x6536, 0x3D, 0x01}, /* OUTAIM_RIGHT26 :*/ + {0x6537, 0x3B, 0x01}, /* OUTAIM_RIGHT27 :*/ + {0x6538, 0x3B, 0x01}, /* OUTAIM_RIGHT28 :*/ + {0x6539, 0x3A, 0x01}, /* OUTAIM_RIGHT29 :*/ + {0x653A, 0x38, 0x01}, /* OUTAIM_RIGHT30 :*/ + {0x653B, 0x38, 0x01}, /* OUTAIM_RIGHT31 :*/ + {0x653C, 0x33, 0x01}, /* OUTAIM_RIGHT32 :*/ + {0x653D, 0x32, 0x01}, /* OUTAIM_RIGHT33 :*/ + {0x653E, 0x31, 0x01}, /* OUTAIM_RIGHT34 :*/ + {0x653F, 0x30, 0x01}, /* OUTAIM_RIGHT35 :*/ + {0x6540, 0x2F, 0x01}, /* OUTAIM_RIGHT36 :*/ + {0x6541, 0x2E, 0x01}, /* OUTAIM_RIGHT37 :*/ + {0x6542, 0x1B3E, 0x02}, /* OUTAIM_TOP :*/ + {0x6544, 0x1716, 0x02}, /* OUTAIM_BOTM :*/ + {0x6546, 0x19, 0x01}, /* OUTAIM_FLTOP :*/ + {0x6547, 0x17, 0x01}, /* OUTAIM_FLBOTM :*/ + {0x65AA, 0x78, 0x01}, /* OUT_CTMP_FRM_BG0 :*/ + {0x65AB, 0x74, 0x01}, /* OUT_CTMP_FRM_BG1 :*/ + {0x65AC, 0x70, 0x01}, /* OUT_CTMP_FRM_BG2 :*/ + {0x65AD, 0x6D, 0x01}, /* OUT_CTMP_FRM_BG3 :*/ + {0x65AE, 0x67, 0x01}, /* OUT_CTMP_FRM_BG4 :*/ + {0x65AF, 0x65, 0x01}, /* OUT_CTMP_FRM_BG5 :*/ + {0x65B0, 0x61, 0x01}, /* OUT_CTMP_FRM_BG6 :*/ + {0x65B1, 0x5C, 0x01}, /* OUT_CTMP_FRM_BG7 :*/ + {0x65B2, 0x56, 0x01}, /* OUT_CTMP_FRM_BG8 :*/ + {0x65B3, 0x52, 0x01}, /* OUT_CTMP_FRM_BG9 :*/ + {0x65B4, 0x4E, 0x01}, /* OUT_CTMP_FRM_BG10 :*/ + {0x65B5, 0x19, 0x01}, /* OUT_CTMP_FRM_RG0 :*/ + {0x65B6, 0x27, 0x01}, /* OUT_CTMP_FRM_RG1 :*/ + {0x65B7, 0x32, 0x01}, /* OUT_CTMP_FRM_RG2 :*/ + {0x65B8, 0x3E, 0x01}, /* OUT_CTMP_FRM_RG3 :*/ + {0x65B9, 0x45, 0x01}, /* OUT_CTMP_FRM_RG4 :*/ + {0x65BA, 0x54, 0x01}, /* OUT_CTMP_FRM_RG5 :*/ + {0x65BB, 0x5E, 0x01}, /* OUT_CTMP_FRM_RG6 :*/ + {0x65BC, 0x00, 0x01}, /* OUT_CTMP_WEIGHT00_01 :*/ + {0x65BD, 0x00, 0x01}, /* OUT_CTMP_WEIGHT02_03 :*/ + {0x65BE, 0x00, 0x01}, /* OUT_CTMP_WEIGHT04_05 :*/ + {0x65BF, 0x00, 0x01}, /* OUT_CTMP_WEIGHT06_07 :*/ + {0x65C0, 0x00, 0x01}, /* OUT_CTMP_WEIGHT08_09 :*/ + {0x65C1, 0x00, 0x01}, /* OUT_CTMP_WEIGHT10_11 :*/ + {0x65C2, 0x00, 0x01}, /* OUT_CTMP_WEIGHT12_13 :*/ + {0x65C3, 0x00, 0x01}, /* OUT_CTMP_WEIGHT14_15 :*/ + {0x65C4, 0x00, 0x01}, /* OUT_CTMP_WEIGHT16_17 :*/ + {0x65C5, 0x00, 0x01}, /* OUT_CTMP_WEIGHT18_19 :*/ + {0x65C6, 0x00, 0x01}, /* OUT_CTMP_WEIGHT20_21 :*/ + {0x65C7, 0x00, 0x01}, /* OUT_CTMP_WEIGHT22_23 :*/ + {0x65C8, 0x10, 0x01}, /* OUT_CTMP_WEIGHT24_25 :*/ + {0x65C9, 0x11, 0x01}, /* OUT_CTMP_WEIGHT26_27 :*/ + {0x65CA, 0x00, 0x01}, /* OUT_CTMP_WEIGHT28_29 :*/ + {0x65CB, 0x20, 0x01}, /* OUT_CTMP_WEIGHT30_31 :*/ + {0x65CC, 0x22, 0x01}, /* OUT_CTMP_WEIGHT32_33 :*/ + {0x65CD, 0x00, 0x01}, /* OUT_CTMP_WEIGHT34_35 :*/ + {0x65CE, 0x30, 0x01}, /* OUT_CTMP_WEIGHT36_37 :*/ + {0x65CF, 0x33, 0x01}, /* OUT_CTMP_WEIGHT38_39 :*/ + {0x65D0, 0x00, 0x01}, /* OUT_CTMP_WEIGHT40_41 :*/ + {0x65D1, 0x20, 0x01}, /* OUT_CTMP_WEIGHT42_43 :*/ + {0x65D2, 0x22, 0x01}, /* OUT_CTMP_WEIGHT44_45 :*/ + {0x65D3, 0x00, 0x01}, /* OUT_CTMP_WEIGHT46_47 :*/ + {0x65D4, 0x00, 0x01}, /* OUT_CTMP_WEIGHT48_49 :*/ + {0x65D5, 0x00, 0x01}, /* OUT_CTMP_WEIGHT50_51 :*/ + {0x65D6, 0x00, 0x01}, /* OUT_CTMP_WEIGHT52_53 :*/ + {0x65D7, 0x00, 0x01}, /* OUT_CTMP_WEIGHT54_55 :*/ + {0x65D8, 0x00, 0x01}, /* OUT_CTMP_WEIGHT56_57 :*/ + {0x65D9, 0x00, 0x01}, /* OUT_CTMP_WEIGHT58_59 :*/ + + {0x6400, 0xAA, 0x01}, /* INFRM_LEFT00 :*/ + {0x6401, 0xAA, 0x01}, /* INFRM_LEFT01 :*/ + {0x6402, 0xAA, 0x01}, /* INFRM_LEFT02 :*/ + {0x6403, 0xAA, 0x01}, /* INFRM_LEFT03 :*/ + {0x6404, 0xAA, 0x01}, /* INFRM_LEFT04 :*/ + {0x6405, 0xAA, 0x01}, /* INFRM_LEFT05 :*/ + {0x6406, 0xAA, 0x01}, /* INFRM_LEFT06 :*/ + {0x6407, 0xAA, 0x01}, /* INFRM_LEFT07 :*/ + {0x6408, 0xAA, 0x01}, /* INFRM_LEFT08 :*/ + {0x6409, 0xAE, 0x01}, /* INFRM_LEFT09 :*/ + {0x640A, 0xA0, 0x01}, /* INFRM_LEFT10 :*/ + {0x640B, 0x8C, 0x01}, /* INFRM_LEFT11 :*/ + {0x640C, 0x72, 0x01}, /* INFRM_LEFT12 :*/ + {0x640D, 0x64, 0x01}, /* INFRM_LEFT13 :*/ + {0x640E, 0x5A, 0x01}, /* INFRM_LEFT14 :*/ + {0x640F, 0x52, 0x01}, /* INFRM_LEFT15 :*/ + {0x6410, 0x4B, 0x01}, /* INFRM_LEFT16 :*/ + {0x6411, 0x46, 0x01}, /* INFRM_LEFT17 :*/ + {0x6412, 0x40, 0x01}, /* INFRM_LEFT18 :*/ + {0x6413, 0x3A, 0x01}, /* INFRM_LEFT19 :*/ + {0x6414, 0x36, 0x01}, /* INFRM_LEFT20 :*/ + {0x6415, 0x34, 0x01}, /* INFRM_LEFT21 :*/ + {0x6416, 0x31, 0x01}, /* INFRM_LEFT22 :*/ + {0x6417, 0x2E, 0x01}, /* INFRM_LEFT23 :*/ + {0x6418, 0x2D, 0x01}, /* INFRM_LEFT24 :*/ + {0x6419, 0x29, 0x01}, /* INFRM_LEFT25 :*/ + {0x641A, 0x28, 0x01}, /* INFRM_LEFT26 :*/ + {0x641B, 0x26, 0x01}, /* INFRM_LEFT27 :*/ + {0x641C, 0x25, 0x01}, /* INFRM_LEFT28 :*/ + {0x641D, 0x25, 0x01}, /* INFRM_LEFT29 :*/ + {0x641E, 0x23, 0x01}, /* INFRM_LEFT30 :*/ + {0x641F, 0x20, 0x01}, /* INFRM_LEFT31 :*/ + {0x6420, 0x1D, 0x01}, /* INFRM_LEFT32 :*/ + {0x6421, 0x1A, 0x01}, /* INFRM_LEFT33 :*/ + {0x6422, 0x18, 0x01}, /* INFRM_LEFT34 :*/ + {0x6423, 0x17, 0x01}, /* INFRM_LEFT35 :*/ + {0x6424, 0x16, 0x01}, /* INFRM_LEFT36 :*/ + {0x6425, 0x17, 0x01}, /* INFRM_LEFT37 :*/ + {0x6426, 0xAF, 0x01}, /* INFRM_RIGHT00 :*/ + {0x6427, 0xAF, 0x01}, /* INFRM_RIGHT01 :*/ + {0x6428, 0xAF, 0x01}, /* INFRM_RIGHT02 :*/ + {0x6429, 0xAF, 0x01}, /* INFRM_RIGHT03 :*/ + {0x642A, 0xAF, 0x01}, /* INFRM_RIGHT04 :*/ + {0x642B, 0xAF, 0x01}, /* INFRM_RIGHT05 :*/ + {0x642C, 0xAF, 0x01}, /* INFRM_RIGHT06 :*/ + {0x642D, 0xAF, 0x01}, /* INFRM_RIGHT07 :*/ + {0x642E, 0xAF, 0x01}, /* INFRM_RIGHT08 :*/ + {0x642F, 0xAA, 0x01}, /* INFRM_RIGHT09 :*/ + {0x6430, 0xB2, 0x01}, /* INFRM_RIGHT10 :*/ + {0x6431, 0xB4, 0x01}, /* INFRM_RIGHT11 :*/ + {0x6432, 0xB6, 0x01}, /* INFRM_RIGHT12 :*/ + {0x6433, 0xB4, 0x01}, /* INFRM_RIGHT13 :*/ + {0x6434, 0x9B, 0x01}, /* INFRM_RIGHT14 :*/ + {0x6435, 0x82, 0x01}, /* INFRM_RIGHT15 :*/ + {0x6436, 0x78, 0x01}, /* INFRM_RIGHT16 :*/ + {0x6437, 0x72, 0x01}, /* INFRM_RIGHT17 :*/ + {0x6438, 0x6C, 0x01}, /* INFRM_RIGHT18 :*/ + {0x6439, 0x67, 0x01}, /* INFRM_RIGHT19 :*/ + {0x643A, 0x63, 0x01}, /* INFRM_RIGHT20 :*/ + {0x643B, 0x5E, 0x01}, /* INFRM_RIGHT21 :*/ + {0x643C, 0x58, 0x01}, /* INFRM_RIGHT22 :*/ + {0x643D, 0x53, 0x01}, /* INFRM_RIGHT23 :*/ + {0x643E, 0x4E, 0x01}, /* INFRM_RIGHT24 :*/ + {0x643F, 0x4A, 0x01}, /* INFRM_RIGHT25 :*/ + {0x6440, 0x46, 0x01}, /* INFRM_RIGHT26 :*/ + {0x6441, 0x42, 0x01}, /* INFRM_RIGHT27 :*/ + {0x6442, 0x3F, 0x01}, /* INFRM_RIGHT28 :*/ + {0x6443, 0x3C, 0x01}, /* INFRM_RIGHT29 :*/ + {0x6444, 0x3A, 0x01}, /* INFRM_RIGHT30 :*/ + {0x6445, 0x38, 0x01}, /* INFRM_RIGHT31 :*/ + {0x6446, 0x37, 0x01}, /* INFRM_RIGHT32 :*/ + {0x6447, 0x2E, 0x01}, /* INFRM_RIGHT33 :*/ + {0x6448, 0x2D, 0x01}, /* INFRM_RIGHT34 :*/ + {0x6449, 0x2C, 0x01}, /* INFRM_RIGHT35 :*/ + {0x644A, 0x2C, 0x01}, /* INFRM_RIGHT36 :*/ + {0x644B, 0x36, 0x01}, /* INFRM_RIGHT37 :*/ + {0x644C, 0x232F, 0x02}, /* INFRM_TOP :*/ + {0x644E, 0x0940, 0x02}, /* INFRM_BOTM :*/ + {0x6450, 0x19, 0x01}, /* INFRM_FLTOP :*/ + {0x6451, 0x10, 0x01}, /* INFRM_FLBOTM :*/ + {0x6452, 0x91, 0x01}, /* INAIM_LEFT00 :*/ + {0x6453, 0x91, 0x01}, /* INAIM_LEFT01 :*/ + {0x6454, 0x91, 0x01}, /* INAIM_LEFT02 :*/ + {0x6455, 0x91, 0x01}, /* INAIM_LEFT03 :*/ + {0x6456, 0x91, 0x01}, /* INAIM_LEFT04 :*/ + {0x6457, 0x91, 0x01}, /* INAIM_LEFT05 :*/ + {0x6458, 0x91, 0x01}, /* INAIM_LEFT06 :*/ + {0x6459, 0x91, 0x01}, /* INAIM_LEFT07 :*/ + {0x645A, 0x91, 0x01}, /* INAIM_LEFT08 :*/ + {0x645B, 0x91, 0x01}, /* INAIM_LEFT09 :*/ + {0x645C, 0x91, 0x01}, /* INAIM_LEFT10 :*/ + {0x645D, 0x91, 0x01}, /* INAIM_LEFT11 :*/ + {0x645E, 0x91, 0x01}, /* INAIM_LEFT12 :*/ + {0x645F, 0x66, 0x01}, /* INAIM_LEFT13 :*/ + {0x6460, 0x5D, 0x01}, /* INAIM_LEFT14 :*/ + {0x6461, 0x55, 0x01}, /* INAIM_LEFT15 :*/ + {0x6462, 0x4E, 0x01}, /* INAIM_LEFT16 :*/ + {0x6463, 0x47, 0x01}, /* INAIM_LEFT17 :*/ + {0x6464, 0x42, 0x01}, /* INAIM_LEFT18 :*/ + {0x6465, 0x3C, 0x01}, /* INAIM_LEFT19 :*/ + {0x6466, 0x38, 0x01}, /* INAIM_LEFT20 :*/ + {0x6467, 0x36, 0x01}, /* INAIM_LEFT21 :*/ + {0x6468, 0x33, 0x01}, /* INAIM_LEFT22 :*/ + {0x6469, 0x30, 0x01}, /* INAIM_LEFT23 :*/ + {0x646A, 0x2F, 0x01}, /* INAIM_LEFT24 :*/ + {0x646B, 0x2B, 0x01}, /* INAIM_LEFT25 :*/ + {0x646C, 0x29, 0x01}, /* INAIM_LEFT26 :*/ + {0x646D, 0x27, 0x01}, /* INAIM_LEFT27 :*/ + {0x646E, 0x26, 0x01}, /* INAIM_LEFT28 :*/ + {0x646F, 0x28, 0x01}, /* INAIM_LEFT29 :*/ + {0x6470, 0x2A, 0x01}, /* INAIM_LEFT30 :*/ + {0x6471, 0x28, 0x01}, /* INAIM_LEFT31 :*/ + {0x6472, 0x26, 0x01}, /* INAIM_LEFT32 :*/ + {0x6473, 0x24, 0x01}, /* INAIM_LEFT33 :*/ + {0x6474, 0x29, 0x01}, /* INAIM_LEFT34 :*/ + {0x6475, 0x28, 0x01}, /* INAIM_LEFT35 :*/ + {0x6476, 0x29, 0x01}, /* INAIM_LEFT36 :*/ + {0x6477, 0x26, 0x01}, /* INAIM_LEFT37 :*/ + {0x6478, 0xFF, 0x01}, /* INAIM_RIGHT00 :*/ + {0x6479, 0xFF, 0x01}, /* INAIM_RIGHT01 :*/ + {0x647A, 0xFF, 0x01}, /* INAIM_RIGHT02 :*/ + {0x647B, 0xFF, 0x01}, /* INAIM_RIGHT03 :*/ + {0x647C, 0xFF, 0x01}, /* INAIM_RIGHT04 :*/ + {0x647D, 0xFF, 0x01}, /* INAIM_RIGHT05 :*/ + {0x647E, 0xFF, 0x01}, /* INAIM_RIGHT06 :*/ + {0x647F, 0xFF, 0x01}, /* INAIM_RIGHT07 :*/ + {0x6480, 0xFF, 0x01}, /* INAIM_RIGHT08 :*/ + {0x6481, 0xFF, 0x01}, /* INAIM_RIGHT09 :*/ + {0x6482, 0xD9, 0x01}, /* INAIM_RIGHT10 :*/ + {0x6483, 0xB7, 0x01}, /* INAIM_RIGHT11 :*/ + {0x6484, 0x96, 0x01}, /* INAIM_RIGHT12 :*/ + {0x6485, 0x68, 0x01}, /* INAIM_RIGHT13 :*/ + {0x6486, 0x70, 0x01}, /* INAIM_RIGHT14 :*/ + {0x6487, 0x72, 0x01}, /* INAIM_RIGHT15 :*/ + {0x6488, 0x71, 0x01}, /* INAIM_RIGHT16 :*/ + {0x6489, 0x6B, 0x01}, /* INAIM_RIGHT17 :*/ + {0x648A, 0x65, 0x01}, /* INAIM_RIGHT18 :*/ + {0x648B, 0x60, 0x01}, /* INAIM_RIGHT19 :*/ + {0x648C, 0x5B, 0x01}, /* INAIM_RIGHT20 :*/ + {0x648D, 0x56, 0x01}, /* INAIM_RIGHT21 :*/ + {0x648E, 0x51, 0x01}, /* INAIM_RIGHT22 :*/ + {0x648F, 0x4C, 0x01}, /* INAIM_RIGHT23 :*/ + {0x6490, 0x47, 0x01}, /* INAIM_RIGHT24 :*/ + {0x6491, 0x44, 0x01}, /* INAIM_RIGHT25 :*/ + {0x6492, 0x41, 0x01}, /* INAIM_RIGHT26 :*/ + {0x6493, 0x3E, 0x01}, /* INAIM_RIGHT27 :*/ + {0x6494, 0x3B, 0x01}, /* INAIM_RIGHT28 :*/ + {0x6495, 0x39, 0x01}, /* INAIM_RIGHT29 :*/ + {0x6496, 0x37, 0x01}, /* INAIM_RIGHT30 :*/ + {0x6497, 0x34, 0x01}, /* INAIM_RIGHT31 :*/ + {0x6498, 0x33, 0x01}, /* INAIM_RIGHT32 :*/ + {0x6499, 0x32, 0x01}, /* INAIM_RIGHT33 :*/ + {0x649A, 0x31, 0x01}, /* INAIM_RIGHT34 :*/ + {0x649B, 0x30, 0x01}, /* INAIM_RIGHT35 :*/ + {0x649C, 0x2F, 0x01}, /* INAIM_RIGHT36 :*/ + {0x649D, 0x2E, 0x01}, /* INAIM_RIGHT37 :*/ + {0x649E, 0x1E00, 0x02}, /* INAIM_TOP :*/ + {0x64A0, 0x0D90, 0x02}, /* INAIM_BOTM :*/ + {0x64A2, 0x18, 0x01}, /* INAIM_FLTOP :*/ + {0x64A3, 0x10, 0x01}, /* INAIM_FLBOTM :*/ + + + /*AWB_setting*/ + {0x629A, 0x13, 0x01}, /* CAT_AWB_2 :*/ + {0x629B, 0x41, 0x01}, /* CAT_AWB_3 :*/ + {0x625F, 0x35, 0x01}, /* CAT_AWB_1 :*/ + + {0x6548, 0x1926, 0x02}, /* OUTAIM_TOP_BLUESKY :*/ + + /*Hue, Gain setting*/ + {0x6E86, 0x0000, 0x02}, /* IBYHUE1_POS1 :*/ + {0x6E88, 0xFFF5, 0x02}, /* IRYHUE1_POS1 :*/ + {0x6E8A, 0xFFF8, 0x02}, /* IBYHUE2_POS1 :*/ + {0x6E8C, 0xFFF5, 0x02}, /* IRYHUE2_POS1 :*/ + {0x6E8E, 0xFFF8, 0x02}, /* IBYHUE3_POS1 :*/ + {0x6E90, 0xFFEE, 0x02}, /* IRYHUE3_POS1 :*/ + {0x6E92, 0x0000, 0x02}, /* IBYHUE4_POS1 :*/ + {0x6E94, 0xFFEC, 0x02}, /* IRYHUE4_POS1 :*/ + {0x6E96, 0x0000, 0x02}, /* IBYHUE1_POS2 :*/ + {0x6E98, 0xFFF5, 0x02}, /* IRYHUE1_POS2 :*/ + {0x6E9A, 0xFFF8, 0x02}, /* IBYHUE2_POS2 :*/ + {0x6E9C, 0xFFF5, 0x02}, /* IRYHUE2_POS2 :*/ + {0x6E9E, 0xFFF8, 0x02}, /* IBYHUE3_POS2 :*/ + {0x6EA0, 0xFFEE, 0x02}, /* IRYHUE3_POS2 :*/ + {0x6EA2, 0x0000, 0x02}, /* IBYHUE4_POS2 :*/ + {0x6EA4, 0xFFEC, 0x02}, /* IRYHUE4_POS2 :*/ + {0x6EA6, 0x0000, 0x02}, /* IBYHUE1_POS3 :*/ + {0x6EA8, 0xFFF5, 0x02}, /* IRYHUE1_POS3 :*/ + {0x6EAA, 0xFFF8, 0x02}, /* IBYHUE2_POS3 :*/ + {0x6EAC, 0xFFF5, 0x02}, /* IRYHUE2_POS3 :*/ + {0x6EAE, 0xFFF8, 0x02}, /* IBYHUE3_POS3 :*/ + {0x6EB0, 0xFFEE, 0x02}, /* IRYHUE3_POS3 :*/ + {0x6EB2, 0x0000, 0x02}, /* IBYHUE4_POS3 :*/ + {0x6EB4, 0xFFEC, 0x02}, /* IRYHUE4_POS3 :*/ + {0x6EB6, 0x0000, 0x02}, /* IBYHUE1_POS4 :*/ + {0x6EB8, 0xFFF5, 0x02}, /* IRYHUE1_POS4 :*/ + {0x6EBA, 0xFFF8, 0x02}, /* IBYHUE2_POS4 :*/ + {0x6EBC, 0xFFF5, 0x02}, /* IRYHUE2_POS4 :*/ + {0x6EBE, 0xFFF8, 0x02}, /* IBYHUE3_POS4 :*/ + {0x6EC0, 0xFFEE, 0x02}, /* IRYHUE3_POS4 :*/ + {0x6EC2, 0x0000, 0x02}, /* IBYHUE4_POS4 :*/ + {0x6EC4, 0xFFEC, 0x02}, /* IRYHUE4_POS4 :*/ + {0x6EC6, 0x0000, 0x02}, /* IBYHUE1_POS5 :*/ + {0x6EC8, 0xFFF5, 0x02}, /* IRYHUE1_POS5 :*/ + {0x6ECA, 0xFFF8, 0x02}, /* IBYHUE2_POS5 :*/ + {0x6ECC, 0xFFF5, 0x02}, /* IRYHUE2_POS5 :*/ + {0x6ECE, 0xFFF8, 0x02}, /* IBYHUE3_POS5 :*/ + {0x6ED0, 0xFFEE, 0x02}, /* IRYHUE3_POS5 :*/ + {0x6ED2, 0x0000, 0x02}, /* IBYHUE4_POS5 :*/ + {0x6ED4, 0xFFEC, 0x02}, /* IRYHUE4_POS5 :*/ + {0x6ED6, 0x0000, 0x02}, /* IBYHUE1_POS6 :*/ + {0x6ED8, 0xFFF5, 0x02}, /* IRYHUE1_POS6 :*/ + {0x6EDA, 0xFFF8, 0x02}, /* IBYHUE2_POS6 :*/ + {0x6EDC, 0xFFF5, 0x02}, /* IRYHUE2_POS6 :*/ + {0x6EDE, 0xFFF8, 0x02}, /* IBYHUE3_POS6 :*/ + {0x6EE0, 0xFFEE, 0x02}, /* IRYHUE3_POS6 :*/ + {0x6EE2, 0x0000, 0x02}, /* IBYHUE4_POS6 :*/ + {0x6EE4, 0xFFEC, 0x02}, /* IRYHUE4_POS6 :*/ + {0x6EE6, 0x0000, 0x02}, /* IBYHUE1_POS7 :*/ + {0x6EE8, 0xFFF5, 0x02}, /* IRYHUE1_POS7 :*/ + {0x6EEA, 0xFFF8, 0x02}, /* IBYHUE2_POS7 :*/ + {0x6EEC, 0xFFF5, 0x02}, /* IRYHUE2_POS7 :*/ + {0x6EEE, 0xFFF8, 0x02}, /* IBYHUE3_POS7 :*/ + {0x6EF0, 0xFFEE, 0x02}, /* IRYHUE3_POS7 :*/ + {0x6EF2, 0x0000, 0x02}, /* IBYHUE4_POS7 :*/ + {0x6EF4, 0xFFEC, 0x02}, /* IRYHUE4_POS7 :*/ + {0x6EF6, 0xFFFA, 0x02}, /* IBYHUE1_OUT :*/ + {0x6EF8, 0xFFF1, 0x02}, /* IRYHUE1_OUT :*/ + {0x6EFA, 0x0000, 0x02}, /* IBYHUE2_OUT :*/ + {0x6EFC, 0xFFF1, 0x02}, /* IRYHUE2_OUT :*/ + {0x6EFE, 0x0000, 0x02}, /* IBYHUE3_OUT :*/ + {0x6F00, 0xFFED, 0x02}, /* IRYHUE3_OUT :*/ + {0x6F02, 0xFFFA, 0x02}, /* IBYHUE4_OUT :*/ + {0x6F04, 0xFFED, 0x02}, /* IRYHUE4_OUT :*/ + {0x6F06, 0x0000, 0x02}, /* IBYHUE1_R2_POS4 :*/ + {0x6F08, 0xFFF6, 0x02}, /* IRYHUE1_R2_POS4 :*/ + {0x6F0A, 0xFFF8, 0x02}, /* IBYHUE2_R2_POS4 :*/ + {0x6F0C, 0xFFF7, 0x02}, /* IRYHUE2_R2_POS4 :*/ + {0x6F0E, 0xFFF8, 0x02}, /* IBYHUE3_R2_POS4 :*/ + {0x6F10, 0xFFEE, 0x02}, /* IRYHUE3_R2_POS4 :*/ + {0x6F12, 0x0000, 0x02}, /* IBYHUE4_R2_POS4 :*/ + {0x6F14, 0xFFEC, 0x02}, /* IRYHUE4_R2_POS4 :*/ + {0x6F16, 0x0000, 0x02}, /* IBYHUE1_R2_POS5 :*/ + {0x6F18, 0xFFF6, 0x02}, /* IRYHUE1_R2_POS5 :*/ + {0x6F1A, 0xFFF8, 0x02}, /* IBYHUE2_R2_POS5 :*/ + {0x6F1C, 0xFFF7, 0x02}, /* IRYHUE2_R2_POS5 :*/ + {0x6F1E, 0xFFF8, 0x02}, /* IBYHUE3_R2_POS5 :*/ + {0x6F20, 0xFFEE, 0x02}, /* IRYHUE3_R2_POS5 :*/ + {0x6F22, 0x0000, 0x02}, /* IBYHUE4_R2_POS5 :*/ + {0x6F24, 0xFFEC, 0x02}, /* IRYHUE4_R2_POS5 :*/ + {0x6F26, 0x4E, 0x01}, /* IRYGAIN1_POS1 :*/ + {0x6F27, 0x50, 0x01}, /* IBYGAIN1_POS1 :*/ + {0x6F28, 0x4E, 0x01}, /* IRYGAIN2_POS1 :*/ + {0x6F29, 0x5A, 0x01}, /* IBYGAIN2_POS1 :*/ + {0x6F2A, 0x50, 0x01}, /* IRYGAIN3_POS1 :*/ + {0x6F2B, 0x5A, 0x01}, /* IBYGAIN3_POS1 :*/ + {0x6F2C, 0x50, 0x01}, /* IRYGAIN4_POS1 :*/ + {0x6F2D, 0x50, 0x01}, /* IBYGAIN4_POS1 :*/ + {0x6F2E, 0x4E, 0x01}, /* IRYGAIN1_POS2 :*/ + {0x6F2F, 0x50, 0x01}, /* IBYGAIN1_POS2 :*/ + {0x6F30, 0x4E, 0x01}, /* IRYGAIN2_POS2 :*/ + {0x6F31, 0x5A, 0x01}, /* IBYGAIN2_POS2 :*/ + {0x6F32, 0x50, 0x01}, /* IRYGAIN3_POS2 :*/ + {0x6F33, 0x5A, 0x01}, /* IBYGAIN3_POS2 :*/ + {0x6F34, 0x50, 0x01}, /* IRYGAIN4_POS2 :*/ + {0x6F35, 0x50, 0x01}, /* IBYGAIN4_POS2 :*/ + {0x6F36, 0x4E, 0x01}, /* IRYGAIN1_POS3 :*/ + {0x6F37, 0x50, 0x01}, /* IBYGAIN1_POS3 :*/ + {0x6F38, 0x4E, 0x01}, /* IRYGAIN2_POS3 :*/ + {0x6F39, 0x5A, 0x01}, /* IBYGAIN2_POS3 :*/ + {0x6F3A, 0x50, 0x01}, /* IRYGAIN3_POS3 :*/ + {0x6F3B, 0x5A, 0x01}, /* IBYGAIN3_POS3 :*/ + {0x6F3C, 0x50, 0x01}, /* IRYGAIN4_POS3 :*/ + {0x6F3D, 0x50, 0x01}, /* IBYGAIN4_POS3 :*/ + {0x6F3E, 0x4E, 0x01}, /* IRYGAIN1_POS4 :*/ + {0x6F3F, 0x50, 0x01}, /* IBYGAIN1_POS4 :*/ + {0x6F40, 0x4E, 0x01}, /* IRYGAIN2_POS4 :*/ + {0x6F41, 0x5A, 0x01}, /* IBYGAIN2_POS4 :*/ + {0x6F42, 0x50, 0x01}, /* IRYGAIN3_POS4 :*/ + {0x6F43, 0x5A, 0x01}, /* IBYGAIN3_POS4 :*/ + {0x6F44, 0x50, 0x01}, /* IRYGAIN4_POS4 :*/ + {0x6F45, 0x50, 0x01}, /* IBYGAIN4_POS4 :*/ + {0x6F46, 0x4E, 0x01}, /* IRYGAIN1_POS5 :*/ + {0x6F47, 0x50, 0x01}, /* IBYGAIN1_POS5 :*/ + {0x6F48, 0x4E, 0x01}, /* IRYGAIN2_POS5 :*/ + {0x6F49, 0x5A, 0x01}, /* IBYGAIN2_POS5 :*/ + {0x6F4A, 0x50, 0x01}, /* IRYGAIN3_POS5 :*/ + {0x6F4B, 0x5A, 0x01}, /* IBYGAIN3_POS5 :*/ + {0x6F4C, 0x50, 0x01}, /* IRYGAIN4_POS5 :*/ + {0x6F4D, 0x50, 0x01}, /* IBYGAIN4_POS5 :*/ + {0x6F4E, 0x4E, 0x01}, /* IRYGAIN1_POS6 :*/ + {0x6F4F, 0x50, 0x01}, /* IBYGAIN1_POS6 :*/ + {0x6F50, 0x4E, 0x01}, /* IRYGAIN2_POS6 :*/ + {0x6F51, 0x5A, 0x01}, /* IBYGAIN2_POS6 :*/ + {0x6F52, 0x50, 0x01}, /* IRYGAIN3_POS6 :*/ + {0x6F53, 0x5A, 0x01}, /* IBYGAIN3_POS6 :*/ + {0x6F54, 0x50, 0x01}, /* IRYGAIN4_POS6 :*/ + {0x6F55, 0x50, 0x01}, /* IBYGAIN4_POS6 :*/ + {0x6F56, 0x4E, 0x01}, /* IRYGAIN1_POS7 :*/ + {0x6F57, 0x50, 0x01}, /* IBYGAIN1_POS7 :*/ + {0x6F58, 0x4E, 0x01}, /* IRYGAIN2_POS7 :*/ + {0x6F59, 0x5A, 0x01}, /* IBYGAIN2_POS7 :*/ + {0x6F5A, 0x50, 0x01}, /* IRYGAIN3_POS7 :*/ + {0x6F5B, 0x5A, 0x01}, /* IBYGAIN3_POS7 :*/ + {0x6F5C, 0x50, 0x01}, /* IRYGAIN4_POS7 :*/ + {0x6F5D, 0x50, 0x01}, /* IBYGAIN4_POS7 :*/ + {0x6F5E, 0x55, 0x01}, /* IRYGAIN1_OUT :*/ + {0x6F5F, 0x55, 0x01}, /* IBYGAIN1_OUT :*/ + {0x6F60, 0x55, 0x01}, /* IRYGAIN2_OUT :*/ + {0x6F61, 0x59, 0x01}, /* IBYGAIN2_OUT :*/ + {0x6F62, 0x55, 0x01}, /* IRYGAIN3_OUT :*/ + {0x6F63, 0x59, 0x01}, /* IBYGAIN3_OUT :*/ + {0x6F64, 0x55, 0x01}, /* IRYGAIN4_OUT :*/ + {0x6F65, 0x55, 0x01}, /* IBYGAIN4_OUT :*/ + {0x6F66, 0x4E, 0x01}, /* IRYGAIN1_R2_POS4 :*/ + {0x6F67, 0x50, 0x01}, /* IBYGAIN1_R2_POS4 :*/ + {0x6F68, 0x4E, 0x01}, /* IRYGAIN2_R2_POS4 :*/ + {0x6F69, 0x5A, 0x01}, /* IBYGAIN2_R2_POS4 :*/ + {0x6F6A, 0x50, 0x01}, /* IRYGAIN3_R2_POS4 :*/ + {0x6F6B, 0x5A, 0x01}, /* IBYGAIN3_R2_POS4 :*/ + {0x6F6C, 0x50, 0x01}, /* IRYGAIN4_R2_POS4 :*/ + {0x6F6D, 0x50, 0x01}, /* IBYGAIN4_R2_POS4 :*/ + {0x6F6E, 0x4E, 0x01}, /* IRYGAIN1_R2_POS5 :*/ + {0x6F6F, 0x50, 0x01}, /* IBYGAIN1_R2_POS5 :*/ + {0x6F70, 0x4E, 0x01}, /* IRYGAIN2_R2_POS5 :*/ + {0x6F71, 0x5A, 0x01}, /* IBYGAIN2_R2_POS5 :*/ + {0x6F72, 0x50, 0x01}, /* IRYGAIN3_R2_POS5 :*/ + {0x6F73, 0x5A, 0x01}, /* IBYGAIN3_R2_POS5 :*/ + {0x6F74, 0x50, 0x01}, /* IRYGAIN4_R2_POS5 :*/ + {0x6F75, 0x50, 0x01}, /* IBYGAIN4_R2_POS5 :*/ + + + /*LMT outdoor setting*/ + {0x6E54, 0xFF9C, 0x02}, /* LM_GRG_OUT :*/ + {0x6E56, 0x0002, 0x02}, /* LM_GRB_OUT :*/ + {0x6E58, 0xFFEC, 0x02}, /* LM_GGR_OUT :*/ + {0x6E5A, 0xFFF9, 0x02}, /* LM_GGB_OUT :*/ + {0x6E5C, 0xFFF0, 0x02}, /* LM_GBR_OUT :*/ + {0x6E5E, 0xFFDC, 0x02}, /* LM_GBG_OUT :*/ + + /*MC3 ON&OFF*/ + {0x6C49, 0xF5, 0x01}, /* MAIN_CONFIG4 :*/ + + + {0x941F, 0x00, 0x01}, /* AP_N_GC_POS_CORE_A :*/ + {0x9420, 0x00, 0x01}, /* AP_N_GC_POS_CORE_B :*/ + {0x9421, 0x02, 0x01}, /* AP_N_GC_POS_CORE_C1 :*/ + {0x9422, 0x01, 0x01}, /* AP_N_GC_POS_CORE_C2 :*/ + {0x9423, 0x20, 0x01}, /* AP_N_GC_POS_SLOPE_A :*/ + {0x9424, 0x0D, 0x01}, /* AP_N_GC_POS_SLOPE_B :*/ + {0x9425, 0x0F, 0x01}, /* AP_N_GC_POS_SLOPE_C1 :*/ + {0x9426, 0x08, 0x01}, /* AP_N_GC_POS_SLOPE_C2 :*/ + {0x9427, 0x00, 0x01}, /* AP_N_GC_NEG_CORE_A :*/ + {0x9428, 0x00, 0x01}, /* AP_N_GC_NEG_CORE_B :*/ + {0x9429, 0x02, 0x01}, /* AP_N_GC_NEG_CORE_C1 :*/ + {0x942A, 0x01, 0x01}, /* AP_N_GC_NEG_CORE_C2 :*/ + {0x942B, 0x20, 0x01}, /* AP_N_GC_NEG_SLOPE_A :*/ + {0x942C, 0x13, 0x01}, /* AP_N_GC_NEG_SLOPE_B :*/ + {0x942D, 0x10, 0x01}, /* AP_N_GC_NEG_SLOPE_C1 :*/ + {0x942E, 0x08, 0x01}, /* AP_N_GC_NEG_SLOPE_C2 :*/ + {0x942F, 0x20, 0x01}, /* AP_N_GAIN_POS_A :*/ + {0x9430, 0x3C, 0x01}, /* AP_N_GAIN_POS_B :*/ + {0x9431, 0x33, 0x01}, /* AP_N_GAIN_POS_C1 :*/ + {0x9432, 0x30, 0x01}, /* AP_N_GAIN_POS_C2 :*/ + {0x9433, 0x20, 0x01}, /* AP_N_GAIN_NEG_A :*/ + {0x9434, 0x48, 0x01}, /* AP_N_GAIN_NEG_B :*/ + {0x9435, 0x37, 0x01}, /* AP_N_GAIN_NEG_C1 :*/ + {0x9436, 0x38, 0x01}, /* AP_N_GAIN_NEG_C2 :*/ + + {0x9437, 0x01, 0x01}, /* AP_H_GC_POS_CORE_A :*/ + {0x9438, 0x01, 0x01}, /* AP_H_GC_POS_CORE_B :*/ + {0x9439, 0x00, 0x01}, /* AP_H_GC_POS_CORE_C1 :*/ + {0x943A, 0x00, 0x01}, /* AP_H_GC_POS_CORE_C2 :*/ + {0x943B, 0x38, 0x01}, /* AP_H_GC_POS_SLOPE_A :*/ + {0x943C, 0x3F, 0x01}, /* AP_H_GC_POS_SLOPE_B :*/ + {0x943D, 0x30, 0x01}, /* AP_H_GC_POS_SLOPE_C1 :*/ + {0x943E, 0x13, 0x01}, /* AP_H_GC_POS_SLOPE_C2 :*/ + {0x943F, 0x00, 0x01}, /* AP_H_GC_NEG_CORE_A :*/ + {0x9440, 0x01, 0x01}, /* AP_H_GC_NEG_CORE_B :*/ + {0x9441, 0x00, 0x01}, /* AP_H_GC_NEG_CORE_C1 :*/ + {0x9442, 0x00, 0x01}, /* AP_H_GC_NEG_CORE_C2 :*/ + {0x9443, 0x38, 0x01}, /* AP_H_GC_NEG_SLOPE_A :*/ + {0x9444, 0x09, 0x01}, /* AP_H_GC_NEG_SLOPE_B :*/ + {0x9445, 0x2D, 0x01}, /* AP_H_GC_NEG_SLOPE_C1 :*/ + {0x9446, 0x0A, 0x01}, /* AP_H_GC_NEG_SLOPE_C2 :*/ + {0x9447, 0x50, 0x01}, /* AP_H_GAIN_POS_A :*/ + {0x9448, 0x38, 0x01}, /* AP_H_GAIN_POS_B :*/ + {0x9449, 0x50, 0x01}, /* AP_H_GAIN_POS_C1 :*/ + {0x944A, 0x87, 0x01}, /* AP_H_GAIN_POS_C2 :*/ + {0x944B, 0x50, 0x01}, /* AP_H_GAIN_NEG_A :*/ + {0x944C, 0x40, 0x01}, /* AP_H_GAIN_NEG_B :*/ + {0x944D, 0x48, 0x01}, /* AP_H_GAIN_NEG_C1 :*/ + {0x944E, 0x87, 0x01}, /* AP_H_GAIN_NEG_C2 :*/ + {0x944F, 0x01, 0x01}, /* AP_L_GC_POS_CORE_A :*/ + {0x9450, 0x00, 0x01}, /* AP_L_GC_POS_CORE_B :*/ + {0x9451, 0x00, 0x01}, /* AP_L_GC_POS_CORE_C1 :*/ + {0x9452, 0x04, 0x01}, /* AP_L_GC_POS_CORE_C2*/ + {0x9453, 0x24, 0x01}, /* AP_L_GC_POS_SLOPE_A :*/ + {0x9454, 0x20, 0x01}, /* AP_L_GC_POS_SLOPE_B :*/ + {0x9455, 0x08, 0x01}, /* AP_L_GC_POS_SLOPE_C1 :*/ + {0x9456, 0x08, 0x01}, /* AP_L_GC_POS_SLOPE_C2 :*/ + {0x9457, 0x01, 0x01}, /* AP_L_GC_NEG_CORE_A :*/ + {0x9458, 0x00, 0x01}, /* AP_L_GC_NEG_CORE_B :*/ + {0x9459, 0x00, 0x01}, /* AP_L_GC_NEG_CORE_C1*/ + {0x945A, 0x04, 0x01}, /* AP_L_GC_NEG_CORE_C2*/ + {0x945B, 0x24, 0x01}, /* AP_L_GC_NEG_SLOPE_A :*/ + {0x945C, 0x20, 0x01}, /* AP_L_GC_NEG_SLOPE_B :*/ + {0x945D, 0x04, 0x01}, /* AP_L_GC_NEG_SLOPE_C1 :*/ + {0x945E, 0x04, 0x01}, /* AP_L_GC_NEG_SLOPE_C2 :*/ + {0x945F, 0x0A, 0x01}, /* AP_L_GAIN_POS_A :*/ + {0x9460, 0x11, 0x01}, /* AP_L_GAIN_POS_B :*/ + {0x9461, 0x1C, 0x01}, /* AP_L_GAIN_POS_C1 :*/ + {0x9462, 0x60, 0x01}, /* AP_L_GAIN_POS_C2 :*/ + {0x9463, 0x08, 0x01}, /* AP_L_GAIN_NEG_A :*/ + {0x9464, 0x0B, 0x01}, /* AP_L_GAIN_NEG_B :*/ + {0x9465, 0x0A, 0x01}, /* AP_L_GAIN_NEG_C1 :*/ + {0x9466, 0x20, 0x01}, /* AP_L_GAIN_NEG_C2 :*/ + + {0x9468, 0x0200, 0x02}, /* AP_N_GC_POS_TH_A :*/ + {0x946A, 0x00C0, 0x02}, /* AP_N_GC_POS_TH_B :*/ + {0x946C, 0x0168, 0x02}, /* AP_N_GC_POS_TH_C1 :*/ + {0x946E, 0x0168, 0x02}, /* AP_N_GC_POS_TH_C2 :*/ + {0x9470, 0x0200, 0x02}, /* AP_N_GC_NEG_TH_A :*/ + {0x9472, 0x00C0, 0x02}, /* AP_N_GC_NEG_TH_B :*/ + {0x9474, 0x00B4, 0x02}, /* AP_N_GC_NEG_TH_C1 :*/ + {0x9476, 0x00B4, 0x02}, /* AP_N_GC_NEG_TH_C2 :*/ + {0x9478, 0x0000, 0x02}, /* AP_N_LD_DARK_TH_A :*/ + {0x947A, 0x0000, 0x02}, /* AP_N_LD_DARK_TH_B :*/ + {0x947C, 0x0000, 0x02}, /* AP_N_LD_DARK_TH_C1 :*/ + {0x947E, 0x0000, 0x02}, /* AP_N_LD_DARK_TH_C2 :*/ + {0x9480, 0x0096, 0x02}, /* AP_N_LD_HIGH_TH0_X_A:*/ + {0x9482, 0x0050, 0x02}, /* AP_N_LD_HIGH_TH0_X_B :*/ + {0x9484, 0x0050, 0x02}, /* AP_N_LD_HIGH_TH0_X_C1 :*/ + {0x9486, 0x0050, 0x02}, /* AP_N_LD_HIGH_TH0_X_C2 :*/ + {0x9488, 0x0080, 0x02}, /* AP_N_LD_HIGH_TH0_Y_A :*/ + {0x948A, 0x0080, 0x02}, /* AP_N_LD_HIGH_TH0_Y_B :*/ + {0x948C, 0x0080, 0x02}, /* AP_N_LD_HIGH_TH0_Y_C1 :*/ + {0x948E, 0x0080, 0x02}, /* AP_N_LD_HIGH_TH0_Y_C2 :*/ + {0x9490, 0x00C8, 0x02}, /* AP_N_LD_HIGH_TH1_X_A :*/ + {0x9492, 0x012C, 0x02}, /* AP_N_LD_HIGH_TH1_X_B :*/ + {0x9494, 0x00C8, 0x02}, /* AP_N_LD_HIGH_TH1_X_C1 :*/ + {0x9496, 0x00C8, 0x02}, /* AP_N_LD_HIGH_TH1_X_C2*/ + {0x9498, 0x01F4, 0x02}, /* AP_N_LD_HIGH_TH2_X_A :*/ + {0x949A, 0x0200, 0x02}, /* AP_N_LD_HIGH_TH2_X_B :*/ + {0x949C, 0x0200, 0x02}, /* AP_N_LD_HIGH_TH2_X_C1 :*/ + {0x949E, 0x0200, 0x02}, /* AP_N_LD_HIGH_TH2_X_C2 :*/ + + + {0x94A0, 0x0050, 0x02}, /* AP_H_GC_POS_TH_A :*/ + {0x94A2, 0x00A0, 0x02}, /* AP_H_GC_POS_TH_B :*/ + {0x94A4, 0x0033, 0x02}, /* AP_H_GC_POS_TH_C1 :*/ + {0x94A6, 0x0033, 0x02}, /* AP_H_GC_POS_TH_C2 :*/ + {0x94A8, 0x0050, 0x02}, /* AP_H_GC_NEG_TH_A :*/ + {0x94AA, 0x00A0, 0x02}, /* AP_H_GC_NEG_TH_B :*/ + {0x94AC, 0x0033, 0x02}, /* AP_H_GC_NEG_TH_C1 :*/ + {0x94AE, 0x0033, 0x02}, /* AP_H_GC_NEG_TH_C2 :*/ + {0x94B0, 0x0021, 0x02}, /* AP_H_LD_DARK_TH_A :*/ + {0x94B2, 0x0000, 0x02}, /* AP_H_LD_DARK_TH_B :*/ + {0x94B4, 0x0000, 0x02}, /* AP_H_LD_DARK_TH_C1 :*/ + {0x94B6, 0x0000, 0x02}, /* AP_H_LD_DARK_TH_C2*/ + {0x94B8, 0x01F4, 0x02}, /* AP_H_LD_HIGH_TH0_X_A :*/ + {0x94BA, 0x0083, 0x02}, /* AP_H_LD_HIGH_TH0_X_B :*/ + {0x94BC, 0x0064, 0x02}, /* AP_H_LD_HIGH_TH0_X_C1 :*/ + {0x94BE, 0x0064, 0x02}, /* AP_H_LD_HIGH_TH0_X_C2 :*/ + {0x94C0, 0x0080, 0x02}, /* AP_H_LD_HIGH_TH0_Y_A :*/ + {0x94C2, 0x0080, 0x02}, /* AP_H_LD_HIGH_TH0_Y_B :*/ + {0x94C4, 0x0080, 0x02}, /* AP_H_LD_HIGH_TH0_Y_C1 :*/ + {0x94C6, 0x0080, 0x02}, /* AP_H_LD_HIGH_TH0_Y_C2 :*/ + {0x94C8, 0x0244, 0x02}, /* AP_H_LD_HIGH_TH1_X_A :*/ + {0x94CA, 0x01AA, 0x02}, /* AP_H_LD_HIGH_TH1_X_B :*/ + {0x94CC, 0x00C8, 0x02}, /* AP_H_LD_HIGH_TH1_X_C1 :*/ + {0x94CE, 0x00C8, 0x02}, /* AP_H_LD_HIGH_TH1_X_C2 :*/ + {0x94D0, 0x02EC, 0x02}, /* AP_H_LD_HIGH_TH2_X_A :*/ + {0x94D2, 0x01EF, 0x02}, /* AP_H_LD_HIGH_TH2_X_B :*/ + {0x94D4, 0x01E0, 0x02}, /* AP_H_LD_HIGH_TH2_X_C1 :*/ + {0x94D6, 0x01E0, 0x02}, /* AP_H_LD_HIGH_TH2_X_C2 :*/ + {0x94D8, 0x0001, 0x02}, /* AP_L_GC_POS_TH_A :*/ + {0x94DA, 0x0040, 0x02}, /* AP_L_GC_POS_TH_B :*/ + {0x94DC, 0x0010, 0x02}, /* AP_L_GC_POS_TH_C1 :*/ + {0x94DE, 0x0010, 0x02}, /* AP_L_GC_POS_TH_C2 :*/ + {0x94E0, 0x0001, 0x02}, /* AP_L_GC_NEG_TH_A :*/ + {0x94E2, 0x0030, 0x02}, /* AP_L_GC_NEG_TH_B :*/ + {0x94E4, 0x0020, 0x02}, /* AP_L_GC_NEG_TH_C1 :*/ + {0x94E6, 0x0020, 0x02}, /* AP_L_GC_NEG_TH_C2 :*/ + {0x94E8, 0x0000, 0x02}, /* AP_L_LD_DARK_TH_A :*/ + {0x94EA, 0x0000, 0x02}, /* AP_L_LD_DARK_TH_B :*/ + {0x94EC, 0x0000, 0x02}, /* AP_L_LD_DARK_TH_C1 :*/ + {0x94EE, 0x0000, 0x02}, /* AP_L_LD_DARK_TH_C2 :*/ + {0x94F0, 0x015E, 0x02}, /* AP_L_LD_HIGH_TH0_X_A :*/ + {0x94F2, 0x015E, 0x02}, /* AP_L_LD_HIGH_TH0_X_B :*/ + {0x94F4, 0x0010, 0x02}, /* AP_L_LD_HIGH_TH0_X_C1 :*/ + {0x94F6, 0x0010, 0x02}, /* AP_L_LD_HIGH_TH0_X_C2 :*/ + {0x94F8, 0x0080, 0x02}, /* AP_L_LD_HIGH_TH0_Y_A :*/ + {0x94FA, 0x0080, 0x02}, /* AP_L_LD_HIGH_TH0_Y_B :*/ + {0x94FC, 0x0080, 0x02}, /* AP_L_LD_HIGH_TH0_Y_C1 :*/ + {0x94FE, 0x0080, 0x02}, /* AP_L_LD_HIGH_TH0_Y_C2 :*/ + {0x9500, 0x0226, 0x02}, /* AP_L_LD_HIGH_TH1_X_A :*/ + {0x9502, 0x0226, 0x02}, /* AP_L_LD_HIGH_TH1_X_B :*/ + {0x9504, 0x0020, 0x02}, /* AP_L_LD_HIGH_TH1_X_C1 :*/ + {0x9506, 0x0020, 0x02}, /* AP_L_LD_HIGH_TH1_X_C2 :*/ + {0x9508, 0x02A2, 0x02}, /* AP_L_LD_HIGH_TH2_X_A :*/ + {0x950A, 0x028A, 0x02}, /* AP_L_LD_HIGH_TH2_X_B :*/ + {0x950C, 0x0050, 0x02}, /* AP_L_LD_HIGH_TH2_X_C1 :*/ + {0x950E, 0x0050, 0x02}, /* AP_L_LD_HIGH_TH2_X_C2 :*/ + + {0x9510, 0x0020, 0x02}, /* AP_POST_LIM_POS_A :*/ + {0x9512, 0x0060, 0x02}, /* AP_POST_LIM_POS_B :*/ + {0x9514, 0x0060, 0x02}, /* AP_POST_LIM_POS_C1 :*/ + {0x9516, 0x0060, 0x02}, /* AP_POST_LIM_POS_C2 :*/ + {0x9518, 0x0030, 0x02}, /* AP_POST_LIM_NEG_A :*/ + {0x951A, 0x0048, 0x02}, /* AP_POST_LIM_NEG_B :*/ + {0x951C, 0x0048, 0x02}, /* AP_POST_LIM_NEG_C1 :*/ + {0x951E, 0x0048, 0x02}, /* AP_POST_LIM_NEG_C2 :*/ + {0x9520, 0x0000, 0x02}, /* AP_POST_CORE_POS_A :*/ + {0x9522, 0x0000, 0x02}, /* AP_POST_CORE_POS_B :*/ + {0x9524, 0x0001, 0x02}, /* AP_POST_CORE_POS_C1 :*/ + {0x9526, 0x0001, 0x02}, /* AP_POST_CORE_POS_C2 :*/ + {0x9528, 0x0002, 0x02}, /* AP_POST_CORE_NEG_A :*/ + {0x952A, 0x0000, 0x02}, /* AP_POST_CORE_NEG_B :*/ + {0x952C, 0x0000, 0x02}, /* AP_POST_CORE_NEG_C1 :*/ + {0x952E, 0x0000, 0x02}, /* AP_POST_CORE_NEG_C2 :*/ + + {0x9530, 0x0000, 0x02}, /* AP_N_LD_DARK_SLOPE_A*/ + {0x9532, 0x0000, 0x02}, + {0x9534, 0x0000, 0x02}, /* AP_N_LD_DARK_SLOPE_B :*/ + {0x9536, 0x0000, 0x02}, + {0x9538, 0x0000, 0x02}, /* AP_N_LD_DARK_SLOPE_C1 :*/ + {0x953A, 0x0000, 0x02}, + {0x953C, 0x0000, 0x02}, /* AP_N_LD_DARK_SLOPE_C2 :*/ + {0x953E, 0x0000, 0x02}, + {0x9540, 0x0061, 0x02}, /* AP_N_LD_HIGH_SLOPE0_A*/ + {0x9542, 0x0000, 0x02}, + {0x9544, 0x0031, 0x02}, /* AP_N_LD_HIGH_SLOPE0_B :*/ + {0x9546, 0x0000, 0x02}, + {0x9548, 0x0000, 0x02}, /* AP_N_LD_HIGH_SLOPE0_C1 :*/ + {0x954A, 0x0000, 0x02}, + {0x954C, 0x0000, 0x02}, /* AP_N_LD_HIGH_SLOPE0_C2 :*/ + {0x954E, 0x0000, 0x02}, + {0x9550, 0x001C, 0x02}, /* AP_N_LD_HIGH_SLOPE1_A*/ + {0x9552, 0x0000, 0x02}, + {0x9554, 0x000C, 0x02}, /* AP_N_LD_HIGH_SLOPE1_B :*/ + {0x9556, 0x0000, 0x02}, + {0x9558, 0x001A, 0x02}, /* AP_N_LD_HIGH_SLOPE1_C1 :*/ + {0x955A, 0x0000, 0x02}, + {0x955C, 0x001A, 0x02}, /* AP_N_LD_HIGH_SLOPE1_C2 :*/ + {0x955E, 0x0000, 0x02}, + {0x9560, 0x0000, 0x02}, /* AP_N_LD_HIGH_SLOPE2_A*/ + {0x9562, 0x0000, 0x02}, + {0x9564, 0x0005, 0x02}, /* AP_N_LD_HIGH_SLOPE2_B :*/ + {0x9566, 0x0000, 0x02}, + {0x9568, 0x0014, 0x02}, /* AP_N_LD_HIGH_SLOPE2_C1 :*/ + {0x956A, 0x0000, 0x02}, + {0x956C, 0x0014, 0x02}, /* AP_N_LD_HIGH_SLOPE2_C2 :*/ + {0x956E, 0x0000, 0x02}, + {0x9570, 0x0000, 0x02}, /* AP_H_LD_DARK_SLOPE_A*/ + {0x9572, 0x0000, 0x02}, + {0x9574, 0x0000, 0x02}, /* AP_H_LD_DARK_SLOPE_B :*/ + {0x9576, 0x0000, 0x02}, + {0x9578, 0x0000, 0x02}, /* AP_H_LD_DARK_SLOPE_C1 :*/ + {0x957A, 0x0000, 0x02}, + {0x957C, 0x0000, 0x02}, /* AP_H_LD_DARK_SLOPE_C2 :*/ + {0x957E, 0x0000, 0x02}, + {0x9580, 0x0025, 0x02}, /* AP_H_LD_HIGH_SLOPE0_A*/ + {0x9582, 0x0000, 0x02}, + {0x9584, 0x0025, 0x02}, /* AP_H_LD_HIGH_SLOPE0_B :*/ + {0x9586, 0x0000, 0x02}, + {0x9588, 0x0064, 0x02}, /* AP_H_LD_HIGH_SLOPE0_C1 :*/ + {0x958A, 0x0000, 0x02}, + {0x958C, 0x0064, 0x02}, /* AP_H_LD_HIGH_SLOPE0_C2 :*/ + {0x958E, 0x0000, 0x02}, + {0x9590, 0x0050, 0x02}, /* AP_H_LD_HIGH_SLOPE1_A*/ + {0x9592, 0x0000, 0x02}, + {0x9594, 0x0050, 0x02}, /* AP_H_LD_HIGH_SLOPE1_B :*/ + {0x9596, 0x0000, 0x02}, + {0x9598, 0x0004, 0x02}, /* AP_H_LD_HIGH_SLOPE1_C1 :*/ + {0x959A, 0x0000, 0x02}, + {0x959C, 0x0004, 0x02}, /* AP_H_LD_HIGH_SLOPE1_C2 :*/ + {0x959E, 0x0000, 0x02}, + {0x95A0, 0x0000, 0x02}, /* AP_H_LD_HIGH_SLOPE2_A*/ + {0x95A2, 0x0000, 0x02}, + {0x95A4, 0x0000, 0x02}, /* AP_H_LD_HIGH_SLOPE2_B :*/ + {0x95A6, 0x0000, 0x02}, + {0x95A8, 0x000D, 0x02}, /* AP_H_LD_HIGH_SLOPE2_C1 :*/ + {0x95AA, 0x0000, 0x02}, + {0x95AC, 0x000D, 0x02}, /* AP_H_LD_HIGH_SLOPE2_C2 :*/ + {0x95AE, 0x0000, 0x02}, + {0x95B0, 0x0000, 0x02}, /* AP_L_LD_DARK_SLOPE_A :*/ + {0x95B2, 0x0000, 0x02}, + {0x95B4, 0x0000, 0x02}, /* AP_L_LD_DARK_SLOPE_B :*/ + {0x95B6, 0x0000, 0x02}, + {0x95B8, 0x0000, 0x02}, /* AP_L_LD_DARK_SLOPE_C1 :*/ + {0x95BA, 0x0000, 0x02}, + {0x95BC, 0x0000, 0x02}, /* AP_L_LD_DARK_SLOPE_C2 :*/ + {0x95BE, 0x0000, 0x02}, + {0x95C0, 0x0020, 0x02}, /* AP_L_LD_HIGH_SLOPE0_A :*/ + {0x95C2, 0x0000, 0x02}, + {0x95C4, 0x0023, 0x02}, /* AP_L_LD_HIGH_SLOPE0_B :*/ + {0x95C6, 0x0000, 0x02}, + {0x95C8, 0x012C, 0x02}, /* AP_L_LD_HIGH_SLOPE0_C1 :*/ + {0x95CA, 0x0000, 0x02}, + {0x95CC, 0x012C, 0x02}, /* AP_L_LD_HIGH_SLOPE0_C2 :*/ + {0x95CE, 0x0000, 0x02}, + {0x95D0, 0x0051, 0x02}, /* AP_L_LD_HIGH_SLOPE1_A :*/ + {0x95D2, 0x0000, 0x02}, + {0x95D4, 0x0050, 0x02}, /* AP_L_LD_HIGH_SLOPE1_B :*/ + {0x95D6, 0x0000, 0x02}, + {0x95D8, 0x0058, 0x02}, /* AP_L_LD_HIGH_SLOPE1_C1 :*/ + {0x95DA, 0x0000, 0x02}, + {0x95DC, 0x0058, 0x02}, /* AP_L_LD_HIGH_SLOPE1_C2 :*/ + {0x95DE, 0x0000, 0x02}, + {0x95E0, 0x0000, 0x02}, /* AP_L_LD_HIGH_SLOPE2_A :*/ + {0x95E2, 0x0000, 0x02}, + {0x95E4, 0x0050, 0x02}, /* AP_L_LD_HIGH_SLOPE2_B :*/ + {0x95E6, 0x0000, 0x02}, + {0x95E8, 0x002A, 0x02}, /* AP_L_LD_HIGH_SLOPE2_C1 :*/ + {0x95EA, 0x0000, 0x02}, + {0x95EC, 0x002A, 0x02}, /* AP_L_LD_HIGH_SLOPE2_C2 :*/ + {0x95EE, 0x0000, 0x02}, + {0x6C47, 0x0F, 0x01}, /* MAIN_CONFIG2 :*/ + {0x6C48, 0x03, 0x01}, /* MAIN_CONFIG3 :*/ + {0x9805, 0x06, 0x01}, /* CS_SLP_C_A :*/ + {0x9806, 0x06, 0x01}, /* CS_SLP_C_B :*/ + {0x9807, 0x06, 0x01}, /* CS_SLP_C_C :*/ + {0x9808, 0x20, 0x01}, /* CS_SLP_YC_A :*/ + {0x9809, 0x20, 0x01}, /* CS_SLP_YC_B :*/ + {0x980A, 0x20, 0x01}, /* CS_SLP_YC_C :*/ + {0x980B, 0x20, 0x01}, /* CS_SLP_Y_A :*/ + {0x980C, 0x20, 0x01}, /* CS_SLP_Y_B :*/ + {0x980D, 0x20, 0x01}, /* CS_SLP_Y_C :*/ + {0x980E, 0x14, 0x01}, /* CS_CBHLEV_A :*/ + {0x980F, 0x14, 0x01}, /* CS_CBHLEV_B :*/ + {0x9810, 0x14, 0x01}, /* CS_CBHLEV_C :*/ + {0x9811, 0x14, 0x01}, /* CS_CRHLEV_A :*/ + {0x9812, 0x14, 0x01}, /* CS_CRHLEV_B :*/ + {0x9813, 0x14, 0x01}, /* CS_CRHLEV_C :*/ + {0x9802, 0x77, 0x01}, /* CS_YHCOEF_A :*/ + {0x9803, 0x77, 0x01}, /* CS_YHCOEF_B :*/ + {0x9804, 0x77, 0x01}, /* CS_YHCOEF_C :*/ + {0x9808, 0x20, 0x01}, /* CS_SLP_YC_A :*/ + {0x9809, 0x20, 0x01}, /* CS_SLP_YC_B :*/ + {0x980A, 0x20, 0x01}, /* CS_SLP_YC_C :*/ + {0x980B, 0x20, 0x01}, /* CS_SLP_Y_A :*/ + {0x980C, 0x20, 0x01}, /* CS_SLP_Y_B :*/ + {0x980D, 0x20, 0x01}, /* CS_SLP_Y_C :*/ + {0x9814, 0x14, 0x01}, /* CS_CBHLEV_Y_A :*/ + {0x9815, 0x14, 0x01}, /* CS_CBHLEV_Y_B :*/ + {0x9816, 0x14, 0x01}, /* CS_CBHLEV_Y_C :*/ + {0x9817, 0x00, 0x01}, /* CS_CRHLEV_Y_A :*/ + {0x9818, 0x00, 0x01}, /* CS_CRHLEV_Y_B :*/ + {0x9819, 0x00, 0x01}, /* CS_CRHLEV_Y_C :*/ + {0x9836, 0x0000, 0x02}, /* CS_CBLLEV_Y_A :*/ + {0x9838, 0x0000, 0x02}, /* CS_CBLLEV_Y_B :*/ + {0x983A, 0x0000, 0x02}, /* CS_CBLLEV_Y_C :*/ + {0x983C, 0xFFEC, 0x02}, /* CS_CRLLEV_Y_A :*/ + {0x983E, 0xFFEC, 0x02}, /* CS_CRLLEV_Y_B :*/ + {0x9840, 0xFFEC, 0x02}, /* CS_CRLLEV_Y_C :*/ + {0x981A, 0x03, 0x01}, /* CS_SLP_YC_L_A :*/ + {0x981B, 0x03, 0x01}, /* CS_SLP_YC_L_B :*/ + {0x981C, 0x03, 0x01}, /* CS_SLP_YC_L_C :*/ + {0x981D, 0x32, 0x01}, /* CS_SLP_Y_L_A :*/ + {0x981E, 0x20, 0x01}, /* CS_SLP_Y_L_B :*/ + {0x981F, 0x20, 0x01}, /* CS_SLP_Y_L_C :*/ + {0x9820, 0x1E, 0x01}, /* CS_YLCOEF_A :*/ + {0x9821, 0x1E, 0x01}, /* CS_YLCOEF_B :*/ + {0x9822, 0x1E, 0x01}, /* CS_YLCOEF_C :*/ + {0x9823, 0x32, 0x01}, /* CS_CBHLEV_Y_L_A :*/ + {0x9824, 0x32, 0x01}, /* CS_CBHLEV_Y_L_B :*/ + {0x9825, 0x32, 0x01}, /* CS_CBHLEV_Y_L_C :*/ + {0x9826, 0x32, 0x01}, /* CS_CRHLEV_Y_L_A :*/ + {0x9827, 0x32, 0x01}, /* CS_CRHLEV_Y_L_B :*/ + {0x9828, 0x32, 0x01}, /* CS_CRHLEV_Y_L_C :*/ + {0x982A, 0xFFEC, 0x02}, /* CS_CBLLEV_A :*/ + {0x982C, 0xFFEC, 0x02}, /* CS_CBLLEV_B :*/ + {0x982E, 0xFFEC, 0x02}, /* CS_CBLLEV_C :*/ + {0x9830, 0xFFEC, 0x02}, /* CS_CRLLEV_A :*/ + {0x9832, 0xFFEC, 0x02}, /* CS_CRLLEV_B :*/ + {0x9834, 0xFFEC, 0x02}, /* CS_CRLLEV_C :*/ + {0x9836, 0x0000, 0x02}, /* CS_CBLLEV_Y_A :*/ + {0x9838, 0x0000, 0x02}, /* CS_CBLLEV_Y_B :*/ + {0x983A, 0x0000, 0x02}, /* CS_CBLLEV_Y_C :*/ + {0x983C, 0xFFEC, 0x02}, /* CS_CRLLEV_Y_A :*/ + {0x983E, 0xFFEC, 0x02}, /* CS_CRLLEV_Y_B :*/ + {0x9840, 0xFFEC, 0x02}, /* CS_CRLLEV_Y_C :*/ + {0x9842, 0xFFCE, 0x02}, /* CS_CBLLEV_Y_L_A :*/ + {0x9844, 0xFFCE, 0x02}, /* CS_CBLLEV_Y_L_B :*/ + {0x9846, 0xFFCE, 0x02}, /* CS_CBLLEV_Y_L_C :*/ + {0x9848, 0xFFCE, 0x02}, /* CS_CRLLEV_Y_L_A :*/ + {0x984A, 0xFFCE, 0x02}, /* CS_CRLLEV_Y_L_B :*/ + {0x984C, 0xFFCE, 0x02}, /* CS_CRLLEV_Y_L_C :*/ + + /*CNR*/ + {0x6C4A, 0x07, 0x01}, /* MAIN_CONFIG5 :*/ + {0x6C4C, 0x190A, 0x02}, /* CNR_CTRL_TH_H :*/ + {0x6C4E, 0x1000, 0x02}, /* CNR_CTRL_TH_L :*/ + {0x9866, 0x40, 0x01}, /* CNR_PREHNR_GAIN_A :*/ + {0x9867, 0x00, 0x01}, /* CNR_PREHNR_GAIN_B :*/ + {0x9868, 0x00, 0x01}, /* CNR_PREHNR_GAIN_C :*/ + {0x9869, 0x32, 0x01}, /* CNR_NLM_TH_CR_H_A :*/ + {0x986A, 0x04, 0x01}, /* CNR_NLM_TH_CR_H_B :*/ + {0x986B, 0x04, 0x01}, /* CNR_NLM_TH_CR_H_C :*/ + {0x986C, 0x32, 0x01}, /* CNR_NLM_TH_CR_L_A :*/ + {0x986D, 0x04, 0x01}, /* CNR_NLM_TH_CR_L_B :*/ + {0x986E, 0x04, 0x01}, /* CNR_NLM_TH_CR_L_C :*/ + {0x986F, 0x32, 0x01}, /* CNR_NLM_TH_CR_M_H_A :*/ + {0x9870, 0x04, 0x01}, /* CNR_NLM_TH_CR_M_H_B :*/ + {0x9871, 0x04, 0x01}, /* CNR_NLM_TH_CR_M_H_C :*/ + {0x9872, 0x32, 0x01}, /* CNR_NLM_TH_CR_M_L_A :*/ + {0x9873, 0x04, 0x01}, /* CNR_NLM_TH_CR_M_L_B :*/ + {0x9874, 0x04, 0x01}, /* CNR_NLM_TH_CR_M_L_C :*/ + {0x9875, 0x32, 0x01}, /* CNR_NLM_TH_CB_H_A :*/ + {0x9876, 0x04, 0x01}, /* CNR_NLM_TH_CB_H_B :*/ + {0x9877, 0x04, 0x01}, /* CNR_NLM_TH_CB_H_C :*/ + {0x9878, 0x32, 0x01}, /* CNR_NLM_TH_CB_L_A :*/ + {0x9879, 0x04, 0x01}, /* CNR_NLM_TH_CB_L_B :*/ + {0x987A, 0x04, 0x01}, /* CNR_NLM_TH_CB_L_C :*/ + {0x987B, 0x32, 0x01}, /* CNR_NLM_TH_CB_M_H_A :*/ + {0x987C, 0x04, 0x01}, /* CNR_NLM_TH_CB_M_H_B :*/ + {0x987D, 0x04, 0x01}, /* CNR_NLM_TH_CB_M_H_C :*/ + {0x987E, 0x32, 0x01}, /* CNR_NLM_TH_CB_M_L_A :*/ + {0x987F, 0x04, 0x01}, /* CNR_NLM_TH_CB_M_L_B :*/ + {0x9880, 0x04, 0x01}, /* CNR_NLM_TH_CB_M_L_C :*/ + {0x9881, 0x7F, 0x01}, /* CNR_VE_TH_CR_H_A :*/ + {0x9882, 0x01, 0x01}, /* CNR_VE_TH_CR_H_B :*/ + {0x9883, 0x01, 0x01}, /* CNR_VE_TH_CR_H_C :*/ + {0x9884, 0x7F, 0x01}, /* CNR_VE_TH_CR_L_A :*/ + {0x9885, 0x01, 0x01}, /* CNR_VE_TH_CR_L_B :*/ + {0x9886, 0x01, 0x01}, /* CNR_VE_TH_CR_L_C :*/ + {0x9887, 0x7F, 0x01}, /* CNR_VE_TH_CR_M_H_A :*/ + {0x9888, 0x01, 0x01}, /* CNR_VE_TH_CR_M_H_B :*/ + {0x9889, 0x01, 0x01}, /* CNR_VE_TH_CR_M_H_C :*/ + {0x988A, 0x7F, 0x01}, /* CNR_VE_TH_CR_M_L_A :*/ + {0x988B, 0x01, 0x01}, /* CNR_VE_TH_CR_M_L_B :*/ + {0x988C, 0x01, 0x01}, /* CNR_VE_TH_CR_M_L_C :*/ + {0x988D, 0x7F, 0x01}, /* CNR_VE_TH_CB_H_A :*/ + {0x988E, 0x01, 0x01}, /* CNR_VE_TH_CB_H_B :*/ + {0x988F, 0x01, 0x01}, /* CNR_VE_TH_CB_H_C :*/ + {0x9890, 0x7F, 0x01}, /* CNR_VE_TH_CB_L_A :*/ + {0x9891, 0x01, 0x01}, /* CNR_VE_TH_CB_L_B :*/ + {0x9892, 0x01, 0x01}, /* CNR_VE_TH_CB_L_C :*/ + {0x9893, 0x7F, 0x01}, /* CNR_VE_TH_CB_M_H_A :*/ + {0x9894, 0x01, 0x01}, /* CNR_VE_TH_CB_M_H_B :*/ + {0x9895, 0x01, 0x01}, /* CNR_VE_TH_CB_M_H_C :*/ + {0x9896, 0x7F, 0x01}, /* CNR_VE_TH_CB_M_L_A :*/ + {0x9897, 0x01, 0x01}, /* CNR_VE_TH_CB_M_L_B :*/ + {0x9898, 0x01, 0x01}, /* CNR_VE_TH_CB_M_L_C :*/ + {0x9881, 0x7F, 0x01}, /* CNR_VE_TH_CR_H_A :*/ + {0x9882, 0x01, 0x01}, /* CNR_VE_TH_CR_H_B :*/ + {0x9883, 0x01, 0x01}, /* CNR_VE_TH_CR_H_C :*/ + {0x9884, 0x7F, 0x01}, /* CNR_VE_TH_CR_L_A :*/ + {0x9885, 0x01, 0x01}, /* CNR_VE_TH_CR_L_B :*/ + {0x9886, 0x01, 0x01}, /* CNR_VE_TH_CR_L_C :*/ + {0x9887, 0x7F, 0x01}, /* CNR_VE_TH_CR_M_H_A :*/ + {0x9888, 0x01, 0x01}, /* CNR_VE_TH_CR_M_H_B :*/ + {0x9889, 0x01, 0x01}, /* CNR_VE_TH_CR_M_H_C :*/ + {0x988A, 0x7F, 0x01}, /* CNR_VE_TH_CR_M_L_A :*/ + {0x988B, 0x01, 0x01}, /* CNR_VE_TH_CR_M_L_B :*/ + {0x988C, 0x01, 0x01}, /* CNR_VE_TH_CR_M_L_C :*/ + {0x988D, 0x7F, 0x01}, /* CNR_VE_TH_CB_H_A :*/ + {0x988E, 0x01, 0x01}, /* CNR_VE_TH_CB_H_B :*/ + {0x988F, 0x01, 0x01}, /* CNR_VE_TH_CB_H_C :*/ + {0x9890, 0x7F, 0x01}, /* CNR_VE_TH_CB_L_A :*/ + {0x9891, 0x01, 0x01}, /* CNR_VE_TH_CB_L_B :*/ + {0x9892, 0x01, 0x01}, /* CNR_VE_TH_CB_L_C :*/ + {0x9893, 0x7F, 0x01}, /* CNR_VE_TH_CB_M_H_A :*/ + {0x9894, 0x01, 0x01}, /* CNR_VE_TH_CB_M_H_B :*/ + {0x9895, 0x01, 0x01}, /* CNR_VE_TH_CB_M_H_C :*/ + {0x9896, 0x7F, 0x01}, /* CNR_VE_TH_CB_M_L_A :*/ + {0x9897, 0x01, 0x01}, /* CNR_VE_TH_CB_M_L_B :*/ + {0x9898, 0x01, 0x01}, /* CNR_VE_TH_CB_M_L_C :*/ + {0x989A, 0x0066, 0x02}, /* CNR_COEF_CR_H_A :*/ + {0x989C, 0x0100, 0x02}, /* CNR_COEF_CR_H_B :*/ + {0x989E, 0x0100, 0x02}, /* CNR_COEF_CR_H_C :*/ + {0x98A0, 0x0066, 0x02}, /* CNR_COEF_CR_L_A :*/ + {0x98A2, 0x0100, 0x02}, /* CNR_COEF_CR_L_B :*/ + {0x98A4, 0x0100, 0x02}, /* CNR_COEF_CR_L_C :*/ + {0x98A6, 0x0066, 0x02}, /* CNR_COEF_CR_M_H_A :*/ + {0x98A8, 0x0100, 0x02}, /* CNR_COEF_CR_M_H_B :*/ + {0x98AA, 0x0100, 0x02}, /* CNR_COEF_CR_M_H_C :*/ + {0x98AC, 0x0066, 0x02}, /* CNR_COEF_CR_M_L_A :*/ + {0x98AE, 0x0100, 0x02}, /* CNR_COEF_CR_M_L_B :*/ + {0x98B0, 0x0100, 0x02}, /* CNR_COEF_CR_M_L_C :*/ + {0x98B2, 0x0066, 0x02}, /* CNR_COEF_CB_H_A :*/ + {0x98B4, 0x0100, 0x02}, /* CNR_COEF_CB_H_B :*/ + {0x98B6, 0x0100, 0x02}, /* CNR_COEF_CB_H_C :*/ + {0x98B8, 0x0066, 0x02}, /* CNR_COEF_CB_L_A :*/ + {0x98BA, 0x0100, 0x02}, /* CNR_COEF_CB_L_B :*/ + {0x98BC, 0x0100, 0x02}, /* CNR_COEF_CB_L_C :*/ + {0x98BE, 0x0066, 0x02}, /* CNR_COEF_CB_M_H_A :*/ + {0x98C0, 0x0100, 0x02}, /* CNR_COEF_CB_M_H_B :*/ + {0x98C2, 0x0100, 0x02}, /* CNR_COEF_CB_M_H_C :*/ + {0x98C4, 0x0066, 0x02}, /* CNR_COEF_CB_M_L_A :*/ + {0x98C6, 0x0100, 0x02}, /* CNR_COEF_CB_M_L_B :*/ + {0x98C8, 0x0100, 0x02}, /* CNR_COEF_CB_M_L_C :*/ + {0x98CA, 0x1770, 0x02}, /* CNR_EDGE_GAIN_CR_H_A :*/ + {0x98CC, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CR_H_B :*/ + {0x98CE, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CR_H_C :*/ + {0x98D0, 0x1770, 0x02}, /* CNR_EDGE_GAIN_CR_L_A :*/ + {0x98D2, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CR_L_B :*/ + {0x98D4, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CR_L_C :*/ + {0x98D6, 0x1770, 0x02}, /* CNR_EDGE_GAIN_CR_M_H_A :*/ + {0x98D8, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CR_M_H_B :*/ + {0x98DA, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CR_M_H_C :*/ + {0x98DC, 0x1770, 0x02}, /* CNR_EDGE_GAIN_CR_M_L_A :*/ + {0x98DE, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CR_M_L_B :*/ + {0x98E0, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CR_M_L_C :*/ + {0x98E2, 0x1770, 0x02}, /* CNR_EDGE_GAIN_CB_H_A :*/ + {0x98E4, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CB_H_B :*/ + {0x98E6, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CB_H_C :*/ + {0x98E8, 0x1770, 0x02}, /* CNR_EDGE_GAIN_CB_L_A :*/ + {0x98EA, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CB_L_B :*/ + {0x98EC, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CB_L_C :*/ + {0x98EE, 0x1770, 0x02}, /* CNR_EDGE_GAIN_CB_M_H_A :*/ + {0x98F0, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CB_M_H_B :*/ + {0x98F2, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CB_M_H_C :*/ + {0x98F4, 0x1770, 0x02}, /* CNR_EDGE_GAIN_CB_M_L_A :*/ + {0x98F6, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CB_M_L_B :*/ + {0x98F8, 0x07D0, 0x02}, /* CNR_EDGE_GAIN_CB_M_L_C :*/ + {0x98FA, 0x7530, 0x02}, /* CNR_EDGE_TH_CR_H_A :*/ + {0x98FC, 0x0000, 0x02}, /* CNR_EDGE_TH_CR_H_B :*/ + {0x98FE, 0x0000, 0x02}, /* CNR_EDGE_TH_CR_H_C :*/ + {0x9900, 0x7530, 0x02}, /* CNR_EDGE_TH_CR_L_A :*/ + {0x9902, 0x0000, 0x02}, /* CNR_EDGE_TH_CR_L_B :*/ + {0x9904, 0x0000, 0x02}, /* CNR_EDGE_TH_CR_L_C :*/ + {0x9906, 0x7530, 0x02}, /* CNR_EDGE_TH_CR_M_H_A :*/ + {0x9908, 0x0000, 0x02}, /* CNR_EDGE_TH_CR_M_H_B :*/ + {0x990A, 0x0000, 0x02}, /* CNR_EDGE_TH_CR_M_H_C :*/ + {0x990C, 0x7530, 0x02}, /* CNR_EDGE_TH_CR_M_L_A :*/ + {0x990E, 0x0000, 0x02}, /* CNR_EDGE_TH_CR_M_L_B :*/ + {0x9910, 0x0000, 0x02}, /* CNR_EDGE_TH_CR_M_L_C :*/ + {0x9912, 0x7530, 0x02}, /* CNR_EDGE_TH_CB_H_A :*/ + {0x9914, 0x0000, 0x02}, /* CNR_EDGE_TH_CB_H_B :*/ + {0x9916, 0x0000, 0x02}, /* CNR_EDGE_TH_CB_H_C :*/ + {0x9918, 0x7530, 0x02}, /* CNR_EDGE_TH_CB_L_A :*/ + {0x991A, 0x0000, 0x02}, /* CNR_EDGE_TH_CB_L_B :*/ + {0x991C, 0x0000, 0x02}, /* CNR_EDGE_TH_CB_L_C :*/ + {0x991E, 0x7530, 0x02}, /* CNR_EDGE_TH_CB_M_H_A :*/ + {0x9920, 0x0000, 0x02}, /* CNR_EDGE_TH_CB_M_H_B :*/ + {0x9922, 0x0000, 0x02}, /* CNR_EDGE_TH_CB_M_H_C :*/ + {0x9924, 0x7530, 0x02}, /* CNR_EDGE_TH_CB_M_L_A :*/ + {0x9926, 0x0000, 0x02}, /* CNR_EDGE_TH_CB_M_L_B :*/ + {0x9928, 0x0000, 0x02}, /* CNR_EDGE_TH_CB_M_L_C :*/ + + /*ITP NR*/ + {0x5005, 0xBB, 0x01}, /* DM_SW1 :*/ + {0x5006, 0x03, 0x01}, /* DM_SW2 :*/ + {0x9608, 0x0000, 0x02}, /* DS_GRADCORE_A :*/ + {0x960A, 0x0004, 0x02}, /* DS_GRADCORE_B :*/ + {0x960C, 0x0000, 0x02}, /* DS_GRADCORE_C1 :*/ + {0x960E, 0x0000, 0x02}, /* DS_GRADCORE_C2 :*/ + {0x9610, 0x000A, 0x02}, /* DS_GRADLIM_A :*/ + {0x9612, 0x0019, 0x02}, /* DS_GRADLIM_B :*/ + {0x9614, 0x0020, 0x02}, /* DS_GRADLIM_C1 :*/ + {0x9616, 0x0020, 0x02}, /* DS_GRADLIM_C2 :*/ + {0x9600, 0x0080, 0x02}, /* DS_NOISELVL_A :*/ + {0x9602, 0x0039, 0x02}, /* DS_NOISELVL_B :*/ + {0x9604, 0x0030, 0x02}, /* DS_NOISELVL_C1 :*/ + {0x9606, 0x0030, 0x02}, /* DS_NOISELVL_C2*/ + {0x9670, 0x14, 0x01}, /* YN_SLOPELIMIT_A :*/ + {0x9671, 0x20, 0x01}, /* YN_SLOPELIMIT_B :*/ + {0x9672, 0x20, 0x01}, /* YN_SLOPELIMIT_C1 :*/ + {0x9673, 0x20, 0x01}, /* YN_SLOPELIMIT_C2 :*/ + {0x9674, 0x0032, 0x02}, /* YN_LNRTH_CORE_A :*/ + {0x9676, 0x0006, 0x02}, /* YN_LNRTH_CORE_B :*/ + {0x9678, 0x0003, 0x02}, /* YN_LNRTH_CORE_C1 :*/ + {0x967A, 0x0003, 0x02}, /* YN_LNRTH_CORE_C2 :*/ + {0x967C, 0x0032, 0x02}, /* YN_LNRTH_LIM_A :*/ + {0x967E, 0x0058, 0x02}, /* YN_LNRTH_LIM_B :*/ + {0x9680, 0x00A0, 0x02}, /* YN_LNRTH_LIM_C1 :*/ + {0x9682, 0x00A0, 0x02}, /* YN_LNRTH_LIM_C2 :*/ + {0x9684, 0x000F, 0x02}, /* LN_CNRTH_A :*/ + {0x9686, 0x0014, 0x02}, /* LN_CNRTH_B :*/ + {0x9688, 0x0014, 0x02}, /* LN_CNRTH_C1 :*/ + {0x968A, 0x0014, 0x02}, /* LN_CNRTH_C2 :*/ + {0x968C, 0x0100, 0x02}, /* CS_BLEND_LL_A :*/ + {0x968E, 0x0000, 0x02}, /* CS_BLEND_LL_B :*/ + {0x9690, 0x03FF, 0x02}, /* CS_BLEND_LL_C1 :*/ + {0x9692, 0x03FF, 0x02}, /* CS_BLEND_LL_C2 :*/ + {0x9628, 0x0008, 0x02}, /* DS_HLNLBLENDCORE_A :*/ + {0x962A, 0x0003, 0x02}, /* DS_HLNLBLENDCORE_B :*/ + {0x962C, 0x0000, 0x02}, /* DS_HLNLBLENDCORE_C1 :*/ + {0x962E, 0x0000, 0x02}, /* DS_HLNLBLENDCORE_C2 :*/ + {0x9630, 0x0018, 0x02}, /* DS_HLNLBLENDLIM_A :*/ + {0x9632, 0x0024, 0x02}, /* DS_HLNLBLENDLIM_B :*/ + {0x9634, 0x0028, 0x02}, /* DS_HLNLBLENDLIM_C1 :*/ + {0x9636, 0x0028, 0x02}, /* DS_HLNLBLENDLIM_C2 :*/ + {0x9638, 0x0000, 0x02}, /* DS_MNBLENDCORE_A :*/ + {0x963A, 0x000C, 0x02}, /* DS_MNBLENDCORE_B :*/ + {0x963C, 0x0000, 0x02}, /* DS_MNBLENDCORE_C1 :*/ + {0x963E, 0x0000, 0x02}, /* DS_MNBLENDCORE_C2 :*/ + {0x9640, 0x0020, 0x02}, /* DS_MNBLENDLIM_A :*/ + {0x9642, 0x0030, 0x02}, /* DS_MNBLENDLIM_B :*/ + {0x9644, 0x0080, 0x02}, /* DS_MNBLENDLIM_C1 :*/ + {0x9646, 0x0080, 0x02}, /* DS_MNBLENDLIM_C2 :*/ + {0x9648, 0x0008, 0x02}, /* DS_MHBLENDCORE_A :*/ + {0x964A, 0x0005, 0x02}, /* DS_MHBLENDCORE_B :*/ + {0x964C, 0x0001, 0x02}, /* DS_MHBLENDCORE_C1 :*/ + {0x964E, 0x0001, 0x02}, /* DS_MHBLENDCORE_C2 :*/ + {0x9650, 0x0018, 0x02}, /* DS_MHBLENDLIM_A :*/ + {0x9652, 0x0037, 0x02}, /* DS_MHBLENDLIM_B :*/ + {0x9654, 0x0050, 0x02}, /* DS_MHBLENDLIM_C1 :*/ + {0x9656, 0x0050, 0x02}, /* DS_MHBLENDLIM_C2 :*/ + {0x9668, 0x0008, 0x02}, /* DS_NAPMSKLIM_A :*/ + {0x966A, 0x0010, 0x02}, /* DS_NAPMSKLIM_B :*/ + {0x966C, 0x0018, 0x02}, /* DS_NAPMSKLIM_C1 :*/ + {0x966E, 0x0018, 0x02}, /* DS_NAPMSKLIM_C2 :*/ + {0x9618, 0x0018, 0x02}, /* DS_ZIPSUPCORE_A :*/ + {0x961A, 0x0018, 0x02}, /* DS_ZIPSUPCORE_B :*/ + {0x961C, 0x0004, 0x02}, /* DS_ZIPSUPCORE_C1 :*/ + {0x961E, 0x0004, 0x02}, /* DS_ZIPSUPCORE_C2 :*/ + {0x9620, 0x0010, 0x02}, /* DS_ZIPSUPLIM_A :*/ + {0x9622, 0x0010, 0x02}, /* DS_ZIPSUPLIM_B :*/ + {0x9624, 0x0010, 0x02}, /* DS_ZIPSUPLIM_C1 :*/ + {0x9626, 0x0010, 0x02}, /* DS_ZIPSUPLIM_C2 :*/ + {0x9658, 0x0020, 0x02}, /* DS_ICDCORE_A :*/ + {0x965A, 0x0010, 0x02}, /* DS_ICDCORE_B :*/ + {0x965C, 0x0000, 0x02}, /* DS_ICDCORE_C1 :*/ + {0x965E, 0x0000, 0x02}, /* DS_ICDCORE_C2 :*/ + {0x9660, 0x0020, 0x02}, /* DS_ICDLIM_A :*/ + {0x9662, 0x0040, 0x02}, /* DS_ICDLIM_B :*/ + {0x9664, 0x0040, 0x02}, /* DS_ICDLIM_C1 :*/ + {0x9666, 0x0040, 0x02}, /* DS_ICDLIM_C2 :*/ + {0x9694, 0x000C, 0x02}, /* CS_EDGE_CSUP_CORE_A :*/ + {0x9696, 0x000C, 0x02}, /* CS_EDGE_CSUP_CORE_B :*/ + {0x9698, 0x000C, 0x02}, /* CS_EDGE_CSUP_CORE_C1 :*/ + {0x969A, 0x0006, 0x02}, /* CS_EDGE_CSUP_CORE_C2 :*/ + {0x969C, 0x000C, 0x02}, /* CS_EDGE_CSUP_LIM_A :*/ + {0x969E, 0x000C, 0x02}, /* CS_EDGE_CSUP_LIM_B :*/ + {0x96A0, 0x0010, 0x02}, /* CS_EDGE_CSUP_LIM_C1 :*/ + {0x96A2, 0x0008, 0x02}, /* CS_EDGE_CSUP_LIM_C2 :*/ + {0x96A4, 0x0180, 0x02}, /* CS_SPOT_CSUP_CORE_A :*/ + {0x96A6, 0x0180, 0x02}, /* CS_SPOT_CSUP_CORE_B :*/ + {0x96A8, 0x0100, 0x02}, /* CS_SPOT_CSUP_CORE_C1 :*/ + {0x96AA, 0x0100, 0x02}, /* CS_SPOT_CSUP_CORE_C2 :*/ + {0x96AC, 0x000A, 0x02}, /* CS_SPOT_CSUP_LIM_A :*/ + {0x96AE, 0x000A, 0x02}, /* CS_SPOT_CSUP_LIM_B :*/ + {0x96B0, 0x0018, 0x02}, /* CS_SPOT_CSUP_LIM_C1 :*/ + {0x96B2, 0x0018, 0x02}, /* CS_SPOT_CSUP_LIM_C2 :*/ + + {0x9800, 0x40, 0x01}, + {0x9801, 0x80, 0x01}, + + {0x9217, 0x3C, 0x01}, /* GAIN_TH_A_TYPE5 :*/ + {0x9218, 0x28, 0x01}, /* GAIN_TH_B_TYPE5 :*/ + {0x9219, 0x1E, 0x01}, /* GAIN_TH_C_TYPE5 :*/ + + {0x928F, 0x05, 0x01}, /* CNR_PREHNR_GAIN_SEL :*/ + {0x9290, 0x05, 0x01}, /* CNR_NLM_TH_CR_H_SEL :*/ + {0x9291, 0x05, 0x01}, /* CNR_NLM_TH_CR_L_SEL :*/ + {0x9292, 0x05, 0x01}, /* CNR_NLM_TH_CR_M_H_SEL :*/ + {0x9293, 0x05, 0x01}, /* CNR_NLM_TH_CR_M_L_SEL :*/ + {0x9294, 0x05, 0x01}, /* CNR_NLM_TH_CB_H_SEL :*/ + {0x9295, 0x05, 0x01}, /* CNR_NLM_TH_CB_L_SEL :*/ + {0x9296, 0x05, 0x01}, /* CNR_NLM_TH_CB_M_H_SEL :*/ + {0x9297, 0x05, 0x01}, /* CNR_NLM_TH_CB_M_L_SEL :*/ + {0x9298, 0x05, 0x01}, /* CNR_VE_TH_CR_H_SEL :*/ + {0x9299, 0x05, 0x01}, /* CNR_VE_TH_CR_L_SEL :*/ + {0x929A, 0x05, 0x01}, /* CNR_VE_TH_CR_M_H_SEL :*/ + {0x929B, 0x05, 0x01}, /* CNR_VE_TH_CR_M_L_SEL :*/ + {0x929C, 0x05, 0x01}, /* CNR_VE_TH_CB_H_SEL :*/ + {0x929D, 0x05, 0x01}, /* CNR_VE_TH_CB_L_SEL :*/ + {0x929E, 0x05, 0x01}, /* CNR_VE_TH_CB_M_H_SEL :*/ + {0x929F, 0x05, 0x01}, /* CNR_VE_TH_CB_M_L_SEL :*/ + {0x92A0, 0x05, 0x01}, /* CNR_COEF_CR_H_SEL :*/ + {0x92A1, 0x05, 0x01}, /* CNR_COEF_CR_L_SEL :*/ + {0x92A2, 0x05, 0x01}, /* CNR_COEF_CR_M_H_SEL :*/ + {0x92A3, 0x05, 0x01}, /* CNR_COEF_CR_M_L_SEL :*/ + {0x92A4, 0x05, 0x01}, /* CNR_COEF_CB_H_SEL :*/ + {0x92A5, 0x05, 0x01}, /* CNR_COEF_CB_L_SEL :*/ + {0x92A6, 0x05, 0x01}, /* CNR_COEF_CB_M_H_SEL :*/ + {0x92A7, 0x05, 0x01}, /* CNR_COEF_CB_M_L_SEL :*/ + {0x92A8, 0x05, 0x01}, /* CNR_EDGE_GAIN_CR_H_SEL :*/ + {0x92A9, 0x05, 0x01}, /* CNR_EDGE_GAIN_CR_L_SEL :*/ + {0x92AA, 0x05, 0x01}, /* CNR_EDGE_GAIN_CR_M_H_SEL :*/ + {0x92AB, 0x05, 0x01}, /* CNR_EDGE_GAIN_CR_M_L_SEL :*/ + {0x92AC, 0x05, 0x01}, /* CNR_EDGE_GAIN_CB_H_SEL :*/ + {0x92AD, 0x05, 0x01}, /* CNR_EDGE_GAIN_CB_L_SEL :*/ + {0x92AE, 0x05, 0x01}, /* CNR_EDGE_GAIN_CB_M_H_SEL :*/ + {0x92AF, 0x05, 0x01}, /* CNR_EDGE_GAIN_CB_M_L_SEL :*/ + {0x92B0, 0x05, 0x01}, /* CNR_EDGE_TH_CR_H_SEL :*/ + {0x92B1, 0x05, 0x01}, /* CNR_EDGE_TH_CR_L_SEL :*/ + {0x92B2, 0x05, 0x01}, /* CNR_EDGE_TH_CR_M_H_SEL :*/ + {0x92B3, 0x05, 0x01}, /* CNR_EDGE_TH_CR_M_L_SEL :*/ + {0x92B4, 0x05, 0x01}, /* CNR_EDGE_TH_CB_H_SEL :*/ + {0x92B5, 0x05, 0x01}, /* CNR_EDGE_TH_CB_L_SEL :*/ + {0x92B6, 0x05, 0x01}, /* CNR_EDGE_TH_CB_M_H_SEL :*/ + {0x92B7, 0x05, 0x01}, /* CNR_EDGE_TH_CB_M_L_SEL :*/ + + /*MWB & AWB*/ + {0x6244, 0x0B81, 0x02}, /* USER0R :*/ + {0x6246, 0x1832, 0x02}, /* USER0B :*/ + {0x6248, 0x09C8, 0x02}, /* USER1R : Daylight*/ + {0x624A, 0x1A06, 0x02}, /* USER1B :*/ + {0x624C, 0x09C8, 0x02}, /* USER2R : Cloudy*/ + {0x624E, 0x1A06, 0x02}, /* USER2B :*/ + {0x6250, 0x0CFE, 0x02}, /* USER3R : Fluorescent*/ + {0x6252, 0x1121, 0x02}, /* USER3B :*/ + {0x6254, 0x115F, 0x02}, /* USER4R :*/ + {0x6256, 0x0E40, 0x02}, /* USER4B :*/ + + {0x6270, 0xFDF1, 0x02}, /* USER2_CONT_SHIFT_R : Cloudy cont shift*/ + {0x6272, 0x02F8, 0x02}, /* USER2_CONT_SHIFT_B :*/ + + {0x62C6, 0x1120, 0x02}, /* A_LIGHT_R :*/ + {0x62C8, 0x0E99, 0x02}, /* A_LIGHT_B :*/ + {0x62CA, 0xFFD0, 0x02}, /* A_LIGHT_AIM_SHIFT_R :*/ + {0x62CC, 0x00A2, 0x02}, /* A_LIGHT_AIM_SHIFT_B :*/ + {0x62CE, 0x04, 0x01}, /* A_LIGHT_SCOPE_S_UP :*/ + {0x62CF, 0x04, 0x01}, /* A_LIGHT_SCOPE_S_DOWN :*/ + {0x62D0, 0x04, 0x01}, /* A_LIGHT_SCOPE_S_RIGHT :*/ + {0x62D1, 0x04, 0x01}, /* A_LIGHT_SCOPE_S_LEFT :*/ + {0x62D2, 0x14, 0x01}, /* A_LIGHT_SCOPE_L_UP :*/ + {0x62D3, 0x14, 0x01}, /* A_LIGHT_SCOPE_L_DOWN :*/ + {0x62D4, 0x14, 0x01}, /* A_LIGHT_SCOPE_L_RIGHT :*/ + {0x62D5, 0x14, 0x01}, /* A_LIGHT_SCOPE_L_LEFT :*/ + {0x62D6, 0x1532, 0x02}, /* H_LIGHT_R :*/ + {0x62D8, 0x0DFC, 0x02}, /* H_LIGHT_B :*/ + {0x62DA, 0x0000, 0x02}, /* H_LIGHT_AIM_SHIFT_R :*/ + {0x62DC, 0xFFB0, 0x02}, /* H_LIGHT_AIM_SHIFT_B :*/ + {0x62DE, 0x0A, 0x01}, /* H_LIGHT_SCOPE_S_UP :*/ + {0x62DF, 0x0A, 0x01}, /* H_LIGHT_SCOPE_S_DOWN :*/ + {0x62E0, 0x0A, 0x01}, /* H_LIGHT_SCOPE_S_RIGHT :*/ + {0x62E1, 0x04, 0x01}, /* H_LIGHT_SCOPE_S_LEFT :*/ + {0x62E2, 0x14, 0x01}, /* H_LIGHT_SCOPE_L_UP :*/ + {0x62E3, 0x2C, 0x01}, /* H_LIGHT_SCOPE_L_DOWN :*/ + {0x62E4, 0x14, 0x01}, /* H_LIGHT_SCOPE_L_RIGHT :*/ + {0x62E5, 0x19, 0x01}, /* H_LIGHT_SCOPE_L_LEFT :*/ + + + /*MC3 Setting*/ + {0x7600, 0x07, 0x01}, /* MC3_PXDEF0_SEL :*/ + {0x7601, 0x07, 0x01}, /* MC3_PYDEF0_SEL :*/ + {0x7602, 0x07, 0x01}, /* MC3_PXDEF1_SEL :*/ + {0x7603, 0x07, 0x01}, /* MC3_PYDEF1_SEL :*/ + {0x7604, 0x07, 0x01}, /* MC3_PXDEF2_SEL :*/ + {0x7605, 0x07, 0x01}, /* MC3_PYDEF2_SEL :*/ + {0x7606, 0x07, 0x01}, /* MC3_PXDEF3_SEL :*/ + {0x7607, 0x07, 0x01}, /* MC3_PYDEF3_SEL :*/ + {0x7608, 0x40, 0x01}, /* MC3_PXDEF0_A :*/ + {0x7609, 0x40, 0x01}, /* MC3_PXDEF0_B :*/ + {0x760A, 0x40, 0x01}, /* MC3_PXDEF0_C :*/ + {0x760B, 0x40, 0x01}, /* MC3_PYDEF0_A :*/ + {0x760C, 0x40, 0x01}, /* MC3_PYDEF0_B :*/ + {0x760D, 0x40, 0x01}, /* MC3_PYDEF0_C :*/ + {0x760E, 0x40, 0x01}, /* MC3_PXDEF1_A :*/ + {0x760F, 0x40, 0x01}, /* MC3_PXDEF1_B :*/ + {0x7610, 0x40, 0x01}, /* MC3_PXDEF1_C :*/ + {0x7611, 0x40, 0x01}, /* MC3_PYDEF1_A :*/ + {0x7612, 0x40, 0x01}, /* MC3_PYDEF1_B :*/ + {0x7613, 0x40, 0x01}, /* MC3_PYDEF1_C :*/ + {0x7614, 0x40, 0x01}, /* MC3_PXDEF2_A :*/ + {0x7615, 0x40, 0x01}, /* MC3_PXDEF2_B :*/ + {0x7616, 0x40, 0x01}, /* MC3_PXDEF2_C :*/ + {0x7617, 0x40, 0x01}, /* MC3_PYDEF2_A :*/ + {0x7618, 0x40, 0x01}, /* MC3_PYDEF2_B :*/ + {0x7619, 0x40, 0x01}, /* MC3_PYDEF2_C :*/ + {0x761A, 0x40, 0x01}, /* MC3_PXDEF3_A :*/ + {0x761B, 0x40, 0x01}, /* MC3_PXDEF3_B :*/ + {0x761C, 0x40, 0x01}, /* MC3_PXDEF3_C :*/ + {0x761D, 0x40, 0x01}, /* MC3_PYDEF3_A :*/ + {0x761E, 0x40, 0x01}, /* MC3_PYDEF3_B :*/ + {0x761F, 0x40, 0x01}, /* MC3_PYDEF3_C :*/ + {0x7620, 0x00, 0x01}, /* MC3_LUMSL0_IN :*/ + {0x7621, 0x00, 0x01}, /* MC3_LUMSL1_IN :*/ + {0x7622, 0x00, 0x01}, /* MC3_LUMSL2_IN :*/ + {0x7623, 0x06, 0x01}, /* MC3_LUMSL3_IN :*/ + {0x7624, 0x00, 0x01}, /* MC3_LUMSL0_OUT :*/ + {0x7625, 0x03, 0x01}, /* MC3_LUMSL1_OUT :*/ + {0x7626, 0x00, 0x01}, /* MC3_LUMSL2_OUT :*/ + {0x7627, 0x00, 0x01}, /* MC3_LUMSL3_OUT :*/ + {0x7628, 0x0000, 0x02}, /* MC3_L0DEF0_IN :*/ + {0x762A, 0x0000, 0x02}, /* MC3_L0DEF1_IN :*/ + {0x762C, 0x0000, 0x02}, /* MC3_L0DEF2_IN :*/ + {0x762E, 0x00E6, 0x02}, /* MC3_L0DEF3_IN :*/ + {0x7630, 0x0000, 0x02}, /* MC3_L0DEF0_OUT :*/ + {0x7632, 0x0082, 0x02}, /* MC3_L0DEF1_OUT :*/ + {0x7634, 0x0000, 0x02}, /* MC3_L0DEF2_OUT :*/ + {0x7636, 0x0000, 0x02}, /* MC3_L0DEF3_OUT :*/ + {0x7638, 0x41, 0x01}, /* MC3_RDEF0_POS1 :*/ + {0x7639, 0x32, 0x01}, /* MC3_RDEF1_POS1 :*/ + {0x763A, 0x46, 0x01}, /* MC3_RDEF2_POS1 :*/ + {0x763B, 0x71, 0x01}, /* MC3_RDEF3_POS1 :*/ + {0x763C, 0x41, 0x01}, /* MC3_RDEF0_POS2 :*/ + {0x763D, 0x32, 0x01}, /* MC3_RDEF1_POS2 :*/ + {0x763E, 0x46, 0x01}, /* MC3_RDEF2_POS2 :*/ + {0x763F, 0x71, 0x01}, /* MC3_RDEF3_POS2 :*/ + {0x7640, 0x3C, 0x01}, /* MC3_RDEF0_POS3 :*/ + {0x7641, 0x32, 0x01}, /* MC3_RDEF1_POS3 :*/ + {0x7642, 0x46, 0x01}, /* MC3_RDEF2_POS3 :*/ + {0x7643, 0x71, 0x01}, /* MC3_RDEF3_POS3 :*/ + {0x7644, 0x46, 0x01}, /* MC3_RDEF0_POS4 :*/ + {0x7645, 0x32, 0x01}, /* MC3_RDEF1_POS4 :*/ + {0x7646, 0x46, 0x01}, /* MC3_RDEF2_POS4 :*/ + {0x7647, 0x71, 0x01}, /* MC3_RDEF3_POS4 :*/ + {0x7648, 0x46, 0x01}, /* MC3_RDEF0_POS5 :*/ + {0x7649, 0x32, 0x01}, /* MC3_RDEF1_POS5 :*/ + {0x764A, 0x46, 0x01}, /* MC3_RDEF2_POS5 :*/ + {0x764B, 0x71, 0x01}, /* MC3_RDEF3_POS5 :*/ + {0x764C, 0x46, 0x01}, /* MC3_RDEF0_POS6 :*/ + {0x764D, 0x32, 0x01}, /* MC3_RDEF1_POS6 :*/ + {0x764E, 0x46, 0x01}, /* MC3_RDEF2_POS6 :*/ + {0x764F, 0x71, 0x01}, /* MC3_RDEF3_POS6 :*/ + {0x7650, 0x46, 0x01}, /* MC3_RDEF0_POS7 :*/ + {0x7651, 0x32, 0x01}, /* MC3_RDEF1_POS7 :*/ + {0x7652, 0x46, 0x01}, /* MC3_RDEF2_POS7 :*/ + {0x7653, 0x71, 0x01}, /* MC3_RDEF3_POS7 :*/ + {0x7654, 0x2D, 0x01}, /* MC3_RDEF0_OUT :*/ + {0x7655, 0x2D, 0x01}, /* MC3_RDEF1_OUT :*/ + {0x7656, 0x62, 0x01}, /* MC3_RDEF2_OUT :*/ + {0x7657, 0x54, 0x01}, /* MC3_RDEF3_OUT :*/ + {0x7658, 0x46, 0x01}, /* MC3_RDEF0_R2_POS4 :*/ + {0x7659, 0x32, 0x01}, /* MC3_RDEF1_R2_POS4 :*/ + {0x765A, 0x46, 0x01}, /* MC3_RDEF2_R2_POS4 :*/ + {0x765B, 0x71, 0x01}, /* MC3_RDEF3_R2_POS4 :*/ + {0x765C, 0x46, 0x01}, /* MC3_RDEF0_R2_POS5 :*/ + {0x765D, 0x32, 0x01}, /* MC3_RDEF1_R2_POS5 :*/ + {0x765E, 0x46, 0x01}, /* MC3_RDEF2_R2_POS5 :*/ + {0x765F, 0x71, 0x01}, /* MC3_RDEF3_R2_POS5 :*/ + {0x7660, 0xFFBA, 0x02}, /* MC3_X0DEF0_POS1 :*/ + {0x7662, 0xFFBA, 0x02}, /* MC3_Y0DEF0_POS1 :*/ + {0x7664, 0xFFD0, 0x02}, /* MC3_X0DEF1_POS1 :*/ + {0x7666, 0x0037, 0x02}, /* MC3_Y0DEF1_POS1 :*/ + {0x7668, 0xFFD3, 0x02}, /* MC3_X0DEF2_POS1 :*/ + {0x766A, 0xFFF6, 0x02}, /* MC3_Y0DEF2_POS1 :*/ + {0x766C, 0x003B, 0x02}, /* MC3_X0DEF3_POS1 :*/ + {0x766E, 0xFFBB, 0x02}, /* MC3_Y0DEF3_POS1 :*/ + {0x7670, 0xFFBA, 0x02}, /* MC3_X0DEF0_POS2 :*/ + {0x7672, 0xFFBA, 0x02}, /* MC3_Y0DEF0_POS2 :*/ + {0x7674, 0xFFD0, 0x02}, /* MC3_X0DEF1_POS2 :*/ + {0x7676, 0x0037, 0x02}, /* MC3_Y0DEF1_POS2 :*/ + {0x7678, 0xFFD3, 0x02}, /* MC3_X0DEF2_POS2 :*/ + {0x767A, 0xFFF6, 0x02}, /* MC3_Y0DEF2_POS2 :*/ + {0x767C, 0x003B, 0x02}, /* MC3_X0DEF3_POS2 :*/ + {0x767E, 0xFFBB, 0x02}, /* MC3_Y0DEF3_POS2 :*/ + {0x7680, 0xFFCE, 0x02}, /* MC3_X0DEF0_POS3 :*/ + {0x7682, 0xFFBA, 0x02}, /* MC3_Y0DEF0_POS3 :*/ + {0x7684, 0xFFD0, 0x02}, /* MC3_X0DEF1_POS3 :*/ + {0x7686, 0x0037, 0x02}, /* MC3_Y0DEF1_POS3 :*/ + {0x7688, 0xFFD3, 0x02}, /* MC3_X0DEF2_POS3 :*/ + {0x768A, 0xFFF6, 0x02}, /* MC3_Y0DEF2_POS3 :*/ + {0x768C, 0x003B, 0x02}, /* MC3_X0DEF3_POS3 :*/ + {0x768E, 0xFFBB, 0x02}, /* MC3_Y0DEF3_POS3 :*/ + {0x7690, 0xFFCE, 0x02}, /* MC3_X0DEF0_POS4 :*/ + {0x7692, 0xFFC9, 0x02}, /* MC3_Y0DEF0_POS4 :*/ + {0x7694, 0xFFD0, 0x02}, /* MC3_X0DEF1_POS4 :*/ + {0x7696, 0x0037, 0x02}, /* MC3_Y0DEF1_POS4 :*/ + {0x7698, 0xFFD3, 0x02}, /* MC3_X0DEF2_POS4 :*/ + {0x769A, 0xFFF6, 0x02}, /* MC3_Y0DEF2_POS4 :*/ + {0x769C, 0x003B, 0x02}, /* MC3_X0DEF3_POS4 :*/ + {0x769E, 0xFFBB, 0x02}, /* MC3_Y0DEF3_POS4 :*/ + {0x76A0, 0xFFCE, 0x02}, /* MC3_X0DEF0_POS5 :*/ + {0x76A2, 0xFFC9, 0x02}, /* MC3_Y0DEF0_POS5 :*/ + {0x76A4, 0xFFD0, 0x02}, /* MC3_X0DEF1_POS5 :*/ + {0x76A6, 0x0037, 0x02}, /* MC3_Y0DEF1_POS5 :*/ + {0x76A8, 0xFFD3, 0x02}, /* MC3_X0DEF2_POS5 :*/ + {0x76AA, 0xFFF6, 0x02}, /* MC3_Y0DEF2_POS5 :*/ + {0x76AC, 0x003B, 0x02}, /* MC3_X0DEF3_POS5 :*/ + {0x76AE, 0xFFBB, 0x02}, /* MC3_Y0DEF3_POS5 :*/ + {0x76B0, 0xFFCE, 0x02}, /* MC3_X0DEF0_POS6 :*/ + {0x76B2, 0xFFC9, 0x02}, /* MC3_Y0DEF0_POS6 :*/ + {0x76B4, 0xFFD0, 0x02}, /* MC3_X0DEF1_POS6 :*/ + {0x76B6, 0x0037, 0x02}, /* MC3_Y0DEF1_POS6 :*/ + {0x76B8, 0xFFD3, 0x02}, /* MC3_X0DEF2_POS6 :*/ + {0x76BA, 0xFFF6, 0x02}, /* MC3_Y0DEF2_POS6 :*/ + {0x76BC, 0x003B, 0x02}, /* MC3_X0DEF3_POS6 :*/ + {0x76BE, 0xFFBB, 0x02}, /* MC3_Y0DEF3_POS6 :*/ + {0x76C0, 0xFFCE, 0x02}, /* MC3_X0DEF0_POS7 :*/ + {0x76C2, 0xFFC9, 0x02}, /* MC3_Y0DEF0_POS7 :*/ + {0x76C4, 0xFFD0, 0x02}, /* MC3_X0DEF1_POS7 :*/ + {0x76C6, 0x0037, 0x02}, /* MC3_Y0DEF1_POS7 :*/ + {0x76C8, 0xFFD3, 0x02}, /* MC3_X0DEF2_POS7 :*/ + {0x76CA, 0xFFF6, 0x02}, /* MC3_Y0DEF2_POS7 :*/ + {0x76CC, 0x003B, 0x02}, /* MC3_X0DEF3_POS7 :*/ + {0x76CE, 0xFFBB, 0x02}, /* MC3_Y0DEF3_POS7 :*/ + {0x76D0, 0xFF7E, 0x02}, /* MC3_X0DEF0_OUT :*/ + {0x76D2, 0xFFE2, 0x02}, /* MC3_Y0DEF0_OUT :*/ + {0x76D4, 0x003C, 0x02}, /* MC3_X0DEF1_OUT :*/ + {0x76D6, 0xFFEC, 0x02}, /* MC3_Y0DEF1_OUT :*/ + {0x76D8, 0xFFD0, 0x02}, /* MC3_X0DEF2_OUT :*/ + {0x76DA, 0x0037, 0x02}, /* MC3_Y0DEF2_OUT :*/ + {0x76DC, 0xFFC4, 0x02}, /* MC3_X0DEF3_OUT :*/ + {0x76DE, 0xFFEC, 0x02}, /* MC3_Y0DEF3_OUT :*/ + {0x76E0, 0xFFCE, 0x02}, /* MC3_X0DEF0_R2_POS4 :*/ + {0x76E2, 0xFFC9, 0x02}, /* MC3_Y0DEF0_R2_POS4 :*/ + {0x76E4, 0xFFD0, 0x02}, /* MC3_X0DEF1_R2_POS4 :*/ + {0x76E6, 0x0037, 0x02}, /* MC3_Y0DEF1_R2_POS4 :*/ + {0x76E8, 0xFFD3, 0x02}, /* MC3_X0DEF2_R2_POS4 :*/ + {0x76EA, 0xFFF6, 0x02}, /* MC3_Y0DEF2_R2_POS4 :*/ + {0x76EC, 0x003B, 0x02}, /* MC3_X0DEF3_R2_POS4 :*/ + {0x76EE, 0xFFBB, 0x02}, /* MC3_Y0DEF3_R2_POS4 :*/ + {0x76F0, 0xFFCE, 0x02}, /* MC3_X0DEF0_R2_POS5 :*/ + {0x76F2, 0xFFC9, 0x02}, /* MC3_Y0DEF0_R2_POS5 :*/ + {0x76F4, 0xFFD0, 0x02}, /* MC3_X0DEF1_R2_POS5 :*/ + {0x76F6, 0x0037, 0x02}, /* MC3_Y0DEF1_R2_POS5 :*/ + {0x76F8, 0xFFD3, 0x02}, /* MC3_X0DEF2_R2_POS5 :*/ + {0x76FA, 0xFFF6, 0x02}, /* MC3_Y0DEF2_R2_POS5 :*/ + {0x76FC, 0x003B, 0x02}, /* MC3_X0DEF3_R2_POS5 :*/ + {0x76FE, 0xFFBB, 0x02}, /* MC3_Y0DEF3_R2_POS5 :*/ + {0x7700, 0x0019, 0x02}, /* MC3_PXDEF0_POS1 :*/ + {0x7702, 0xFF66, 0x02}, /* MC3_PYDEF0_POS1 :*/ + {0x7704, 0x0019, 0x02}, /* MC3_PXDEF1_POS1 :*/ + {0x7706, 0x0033, 0x02}, /* MC3_PYDEF1_POS1 :*/ + {0x7708, 0x0000, 0x02}, /* MC3_PXDEF2_POS1 :*/ + {0x770A, 0x0000, 0x02}, /* MC3_PYDEF2_POS1 :*/ + {0x770C, 0xFFD7, 0x02}, /* MC3_PXDEF3_POS1 :*/ + {0x770E, 0x0068, 0x02}, /* MC3_PYDEF3_POS1 :*/ + {0x7710, 0x0000, 0x02}, /* MC3_PXDEF0_POS2 :*/ + {0x7712, 0xFF66, 0x02}, /* MC3_PYDEF0_POS2 :*/ + {0x7714, 0x0019, 0x02}, /* MC3_PXDEF1_POS2 :*/ + {0x7716, 0x0026, 0x02}, /* MC3_PYDEF1_POS2 :*/ + {0x7718, 0x0000, 0x02}, /* MC3_PXDEF2_POS2 :*/ + {0x771A, 0x0000, 0x02}, /* MC3_PYDEF2_POS2 :*/ + {0x771C, 0xFFD7, 0x02}, /* MC3_PXDEF3_POS2 :*/ + {0x771E, 0x0068, 0x02}, /* MC3_PYDEF3_POS2 :*/ + {0x7720, 0x0000, 0x02}, /* MC3_PXDEF0_POS3 :*/ + {0x7722, 0xFF80, 0x02}, /* MC3_PYDEF0_POS3 :*/ + {0x7724, 0x0000, 0x02}, /* MC3_PXDEF1_POS3 :*/ + {0x7726, 0x0000, 0x02}, /* MC3_PYDEF1_POS3 :*/ + {0x7728, 0x0000, 0x02}, /* MC3_PXDEF2_POS3 :*/ + {0x772A, 0x0000, 0x02}, /* MC3_PYDEF2_POS3 :*/ + {0x772C, 0xFFD7, 0x02}, /* MC3_PXDEF3_POS3 :*/ + {0x772E, 0x0068, 0x02}, /* MC3_PYDEF3_POS3 :*/ + {0x7730, 0x0000, 0x02}, /* MC3_PXDEF0_POS4 :*/ + {0x7732, 0xFFCC, 0x02}, /* MC3_PYDEF0_POS4 :*/ + {0x7734, 0x0000, 0x02}, /* MC3_PXDEF1_POS4 :*/ + {0x7736, 0x0000, 0x02}, /* MC3_PYDEF1_POS4 :*/ + {0x7738, 0x0000, 0x02}, /* MC3_PXDEF2_POS4 :*/ + {0x773A, 0x0000, 0x02}, /* MC3_PYDEF2_POS4 :*/ + {0x773C, 0xFFD7, 0x02}, /* MC3_PXDEF3_POS4 :*/ + {0x773E, 0x0068, 0x02}, /* MC3_PYDEF3_POS4 :*/ + {0x7740, 0x0000, 0x02}, /* MC3_PXDEF0_POS5 :*/ + {0x7742, 0xFFCC, 0x02}, /* MC3_PYDEF0_POS5 :*/ + {0x7744, 0x0000, 0x02}, /* MC3_PXDEF1_POS5 :*/ + {0x7746, 0x0000, 0x02}, /* MC3_PYDEF1_POS5 :*/ + {0x7748, 0x0000, 0x02}, /* MC3_PXDEF2_POS5 :*/ + {0x774A, 0x0000, 0x02}, /* MC3_PYDEF2_POS5 :*/ + {0x774C, 0xFFD7, 0x02}, /* MC3_PXDEF3_POS5 :*/ + {0x774E, 0x0068, 0x02}, /* MC3_PYDEF3_POS5 :*/ + {0x7750, 0xFFB3, 0x02}, /* MC3_PXDEF0_POS6 :*/ + {0x7752, 0x0000, 0x02}, /* MC3_PYDEF0_POS6 :*/ + {0x7754, 0x0000, 0x02}, /* MC3_PXDEF1_POS6 :*/ + {0x7756, 0x0000, 0x02}, /* MC3_PYDEF1_POS6 :*/ + {0x7758, 0x0000, 0x02}, /* MC3_PXDEF2_POS6 :*/ + {0x775A, 0x0000, 0x02}, /* MC3_PYDEF2_POS6 :*/ + {0x775C, 0xFFD7, 0x02}, /* MC3_PXDEF3_POS6 :*/ + {0x775E, 0x0068, 0x02}, /* MC3_PYDEF3_POS6 :*/ + {0x7760, 0xFFB3, 0x02}, /* MC3_PXDEF0_POS7 :*/ + {0x7762, 0x0000, 0x02}, /* MC3_PYDEF0_POS7 :*/ + {0x7764, 0x0000, 0x02}, /* MC3_PXDEF1_POS7 :*/ + {0x7766, 0x0000, 0x02}, /* MC3_PYDEF1_POS7 :*/ + {0x7768, 0x0000, 0x02}, /* MC3_PXDEF2_POS7 :*/ + {0x776A, 0x0000, 0x02}, /* MC3_PYDEF2_POS7 :*/ + {0x776C, 0xFFD7, 0x02}, /* MC3_PXDEF3_POS7 :*/ + {0x776E, 0x0068, 0x02}, /* MC3_PYDEF3_POS7 :*/ + {0x7770, 0x0019, 0x02}, /* MC3_PXDEF0_OUT :*/ + {0x7772, 0xFFE6, 0x02}, /* MC3_PYDEF0_OUT :*/ + {0x7774, 0x0000, 0x02}, /* MC3_PXDEF1_OUT :*/ + {0x7776, 0x0000, 0x02}, /* MC3_PYDEF1_OUT :*/ + {0x7778, 0x001E, 0x02}, /* MC3_PXDEF2_OUT :*/ + {0x777A, 0xFFF7, 0x02}, /* MC3_PYDEF2_OUT :*/ + {0x777C, 0xFFE1, 0x02}, /* MC3_PXDEF3_OUT :*/ + {0x777E, 0xFFEB, 0x02}, /* MC3_PYDEF3_OUT :*/ + {0x7780, 0x0000, 0x02}, /* MC3_PXDEF0_R2_POS4 :*/ + {0x7782, 0xFFCC, 0x02}, /* MC3_PYDEF0_R2_POS4 :*/ + {0x7784, 0x0000, 0x02}, /* MC3_PXDEF1_R2_POS4 :*/ + {0x7786, 0x0000, 0x02}, /* MC3_PYDEF1_R2_POS4 :*/ + {0x7788, 0x0000, 0x02}, /* MC3_PXDEF2_R2_POS4 :*/ + {0x778A, 0x0000, 0x02}, /* MC3_PYDEF2_R2_POS4 :*/ + {0x778C, 0xFFD7, 0x02}, /* MC3_PXDEF3_R2_POS4 :*/ + {0x778E, 0x0068, 0x02}, /* MC3_PYDEF3_R2_POS4 :*/ + {0x7790, 0x0000, 0x02}, /* MC3_PXDEF0_R2_POS5 :*/ + {0x7792, 0xFFCC, 0x02}, /* MC3_PYDEF0_R2_POS5 :*/ + {0x7794, 0x0000, 0x02}, /* MC3_PXDEF1_R2_POS5 :*/ + {0x7796, 0x0000, 0x02}, /* MC3_PYDEF1_R2_POS5 :*/ + {0x7798, 0x0000, 0x02}, /* MC3_PXDEF2_R2_POS5 :*/ + {0x779A, 0x0000, 0x02}, /* MC3_PYDEF2_R2_POS5 :*/ + {0x779C, 0xFFD7, 0x02}, /* MC3_PXDEF3_R2_POS5 :*/ + {0x779E, 0x0068, 0x02}, /* MC3_PYDEF3_R2_POS5 :*/ + + + {0x6C44, 0x13, 0x01}, /* G_CTRL_SEL :*/ + {0x0363, 0x95, 0x01}, /* PICT3_GAMMA_MONI1 :*/ + {0x0366, 0x95, 0x01}, /* PICT3_GAMMA_CAP1 :*/ + + + /*Scene Mode Setting*/ + {0x0282, 0x20, 0x01}, /*AWB_SN1 :*/ + {0x0283, 0x20, 0x01}, /*AWB_SN2 :*/ + {0x0284, 0x20, 0x01}, /*AWB_SN3 :*/ + {0x0285, 0x20, 0x01}, /*AWB_SN4 :*/ + {0x0286, 0x20, 0x01}, /*AWB_SN5 :*/ + {0x0287, 0x25, 0x01}, /*AWB_SN6 :*/ + {0x0288, 0x20, 0x01}, /*AWB_SN7 :*/ + {0x0289, 0x20, 0x01}, /*AWB_SN8 :*/ + {0x028A, 0x20, 0x01}, /*AWB_SN9 :*/ + {0x028B, 0x20, 0x01}, /*AWB_SN10 :*/ + {0x028C, 0x20, 0x01}, /*AWB_SN11 :*/ + {0x028D, 0x20, 0x01}, /*AWB_SN12 :*/ + {0x028E, 0x00, 0x01}, /*AF_SN1_2 :*/ + {0x028F, 0x00, 0x01}, /*AF_SN3_4 :*/ + {0x0290, 0x00, 0x01}, /*AF_SN5_6 :*/ + {0x0291, 0x00, 0x01}, /*AF_SN7_8 :*/ + {0x0292, 0x00, 0x01}, /*AF_SN9_10 :*/ + {0x0293, 0x00, 0x01}, /*AF_SN11_12 :*/ + {0x0294, 0x00, 0x01}, /*AE_SN1 :*/ + {0x0295, 0x00, 0x01}, /*AE_SN2 :*/ + {0x0296, 0x00, 0x01}, /*AE_SN3 :*/ + {0x0297, 0x40, 0x01}, /*AE_SN4 :*/ + {0x0298, 0x20, 0x01}, /*AE_SN5 :*/ + {0x0299, 0x00, 0x01}, /*AE_SN6 :*/ + {0x029A, 0x00, 0x01}, /*AE_SN7 :*/ + {0x029B, 0x00, 0x01}, /*AE_SN8 :*/ + {0x029C, 0x20, 0x01}, /*AE_SN9 :*/ + {0x029D, 0x00, 0x01}, /*AE_SN10 :*/ + {0x029E, 0x00, 0x01}, /*AE_SN11 :*/ + {0x029F, 0x00, 0x01}, /*AE_SN12 :*/ + {0x02A8, 0x00, 0x01}, /*ISO_TYPE1 : AUTO*/ + {0x02A9, 0x04, 0x01}, /*ISO_TYPE2 : ISO50*/ + {0x02AA, 0x0A, 0x01}, /*ISO_TYPE3 : ISO200*/ + {0x02AB, 0x00, 0x01}, /*ISO_TYPE4 :*/ + {0x02AC, 0x01, 0x01}, /*AE_SUB_SN1 :*/ + {0x02AD, 0x03, 0x01}, /*AE_SUB_SN2 :*/ + {0x02AE, 0x01, 0x01}, /*AE_SUB_SN3 :*/ + {0x02AF, 0x01, 0x01}, /*AE_SUB_SN4 :*/ + {0x02B0, 0x01, 0x01}, /*AE_SUB_SN5 :*/ + {0x02B1, 0x01, 0x01}, /*AE_SUB_SN6 :*/ + {0x02B2, 0x01, 0x01}, /*AE_SUB_SN7 :*/ + {0x02B3, 0x01, 0x01}, /*AE_SUB_SN8 :*/ + {0x02B4, 0x01, 0x01}, /*AE_SUB_SN9 :*/ + {0x02B5, 0x01, 0x01}, /*AE_SUB_SN10 :*/ + {0x02B6, 0x02, 0x01}, /*AE_SUB_SN11 :*/ + {0x02B7, 0x01, 0x01}, /*AE_SUB_SN12 :*/ + {0x02EA, 0x00, 0x01}, /* EVREF_MONI_SN1_2 :*/ + {0x02EB, 0x00, 0x01}, /* EVREF_MONI_SN3_4 :*/ + {0x02EC, 0x03, 0x01}, /* EVREF_MONI_SN5_6 :*/ + {0x02ED, 0x00, 0x01}, /* EVREF_MONI_SN7_8 :*/ + {0x02EE, 0x00, 0x01}, /* EVREF_MONI_SN9_10 :*/ + {0x02EF, 0x00, 0x01}, /* EVREF_MONI_SN11_12 :*/ + {0x02F0, 0x01, 0x01}, /* EVREF_CAP_SN1_2 :*/ + {0x02F1, 0x00, 0x01}, /* EVREF_CAP_SN3_4 :*/ + {0x02F2, 0x03, 0x01}, /* EVREF_CAP_SN5_6 :*/ + {0x02F3, 0x00, 0x01}, /* EVREF_CAP_SN7_8 :*/ + {0x02F4, 0x00, 0x01}, /* EVREF_CAP_SN9_10 :*/ + {0x02F5, 0x00, 0x01}, /* EVREF_CAP_SN11_12 :*/ + {0x02F6, 0x00, 0x01}, /* EVREF_MOVIE_SN1_2 :*/ + {0x02F7, 0x00, 0x01}, /* EVREF_MOVIE_SN3_4 :*/ + {0x02F8, 0x03, 0x01}, /* EVREF_MOVIE_SN5_6 :*/ + {0x02F9, 0x00, 0x01}, /* EVREF_MOVIE_SN7_8 :*/ + {0x02FA, 0x00, 0x01}, /* EVREF_MOVIE_SN9_10 :*/ + {0x02FB, 0x00, 0x01}, /* EVREF_MOVIE_SN11_12 :*/ + {0x038F, 0x00, 0x01}, /*PICT1_SN1 :*/ + {0x0390, 0xA4, 0x01}, /*PICT1_SN2 :*/ + {0x0391, 0x00, 0x01}, /*PICT1_SN3 :*/ + {0x0392, 0x04, 0x01}, /*PICT1_SN4 :*/ + {0x0393, 0x04, 0x01}, /*PICT1_SN5 :*/ + {0x0394, 0x00, 0x01}, /*PICT1_SN6 :*/ + {0x0395, 0x50, 0x01}, /*PICT1_SN7 :*/ + {0x0396, 0x00, 0x01}, /*PICT1_SN8 :*/ + {0x0397, 0x00, 0x01}, /*PICT1_SN9 :*/ + {0x0398, 0xA0, 0x01}, /*PICT1_SN10 :*/ + {0x0399, 0x00, 0x01}, /*PICT1_SN11 :*/ + {0x039A, 0x00, 0x01}, /*PICT1_SN12 :*/ + {0x039B, 0x00, 0x01}, /*UIHUE_TYPE1 :*/ + {0x039C, 0x00, 0x01}, /*UIHUE_TYPE2 :*/ + {0x039D, 0x00, 0x01}, /*UIHUE_TYPE3 :*/ + {0x039E, 0x80, 0x01}, /*UISATURATION_TYPE1 :*/ + {0x039F, 0x9E, 0x01}, /*UISATURATION_TYPE2 :*/ + {0x03A0, 0xBC, 0x01}, /*UISATURATION_TYPE3 :*/ + {0x03A1, 0x20, 0x01}, /*UISHARPNESS_POS_TYPE1 :*/ + {0x03A2, 0x14, 0x01}, /*UISHARPNESS_POS_TYPE2 :*/ + {0x03A3, 0x2C, 0x01}, /*UISHARPNESS_POS_TYPE3 :*/ + {0x03A4, 0x20, 0x01}, /*UISHARPNESS_NEG_TYPE1 :*/ + {0x03A5, 0x14, 0x01}, /*UISHARPNESS_NEG_TYPE2 :*/ + {0x03A6, 0x2C, 0x01}, /*UISHARPNESS_NEG_TYPE3 :*/ + {0x030E, 0x00, 0x01}, /* AELINE_HALF_SN1_2 :*/ + {0x030F, 0x03, 0x01}, /* AELINE_HALF_SN3_4 :*/ + {0x0310, 0x00, 0x01}, /* AELINE_HALF_SN5_6 :*/ + {0x0311, 0x60, 0x01}, /* AELINE_HALF_SN7_8 :*/ + {0x0312, 0x09, 0x01}, /* AELINE_HALF_SN9_10 :*/ + {0x0313, 0x00, 0x01}, /* AELINE_HALF_SN11_12 :*/ +}; + +/* ISX012-0 +MIPI 2LANE 648 +PLL 648MHz +DCK 81 +inifile +size address data +*/ +struct isx012_short_t ISX012_Pll_Setting_2[] = { + {0x0007, 0x01, 0x01}, /* PLL_CKSEL: PLL 648MHz*/ + {0x0008, 0x03, 0x01}, /* SRCCK_DIV: 1/8 frequency*/ + + {0x0004, 0x02, 0x01}, /*I2C_ADR_SEL 2: MIPI selected*/ + {0x5008, 0x00, 0x01}, /*ENDIAN_SEL : 0:Little Endian*/ + {0x6DA8, 0x01, 0x01}, /*SHD_CoEF (OTP shading ON flag)*/ + + {0x00C4, 0x11, 0x01}, /* VIF_CLKCONFIG1*/ + {0x00C5, 0x11, 0x01}, /* VIF_CLKCONFIG2*/ + {0x00C6, 0x11, 0x01}, /* VIF_CLKCONFIG3*/ + {0x00C7, 0x11, 0x01}, /* VIF_CLKCONFIG4*/ + {0x00C8, 0x11, 0x01}, /* VIF_CLKCONFIG5*/ + {0x00C9, 0x11, 0x01}, /* VIF_CLKCONFIG6*/ + {0x00CA, 0x11, 0x01}, /* VIF_CLKCONFIG7*/ + {0x018C, 0x0000, 0x02}, /* VADJ_SENS_1_1*/ + {0x018E, 0x0000, 0x02}, /* VADJ_SENS_1_2*/ + {0x0190, 0x0000, 0x02}, /* VADJ_SENS_1_4*/ + {0x0192, 0x0000, 0x02}, /* VADJ_SENS_1_8*/ + {0x0194, 0x0000, 0x02}, /* VADJ_SENS_HD_1_1*/ + {0x0196, 0x0000, 0x02}, /* VADJ_SENS_HD_1_2*/ + {0x6A16, 0x0400, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_1*/ + {0x6A18, 0x03C0, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_2*/ + {0x6A1A, 0x01E0, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_4*/ + {0x6A1C, 0x00E0, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_8*/ + {0x6A1E, 0x0400, 0x02}, /* FLC_OPD_HEIGHT_HD_1_1*/ + {0x6A20, 0x02C0, 0x02}, /* FLC_OPD_HEIGHT_HD_1_2*/ + {0x0016, 0x0010, 0x02}, /* GPIO_FUNCSEL: GPIO setting*/ + {0x5C01, 0x00, 0x01}, /* RGLANESEL*/ + {0x5C04, 0x04, 0x01}, /* RGTLPX :*/ + {0x5C05, 0x03, 0x01}, /* RGTCLKPREPARE :*/ + {0x5C06, 0x14, 0x01}, /* RGTCLKZERO :*/ + {0x5C07, 0x02, 0x01}, /* RGTCLKPRE :*/ + {0x5C08, 0x11, 0x01}, /* RGTCLKPOST :*/ + {0x5C09, 0x05, 0x01}, /* RGTCLKTRAIL :*/ + {0x5C0A, 0x07, 0x01}, /* RGTHSEXIT :*/ + {0x5C0B, 0x03, 0x01}, /* RGTHSPREPARE :*/ + {0x5C0C, 0x07, 0x01}, /* RGTHSZERO :*/ + {0x5C0D, 0x05, 0x01}, /* RGTHSTRAIL :*/ + + {0x0009, 0x01, 0x01}, /* EXT_PLL_CKSEL : PLL 648MHz*/ + {0x00D0, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT1*/ + {0x00D1, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT2*/ + {0x00D4, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT5*/ + {0x00D5, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT6*/ + {0x00D8, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT9*/ + {0x00D9, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT10*/ + + {0x0089, 0x00, 0x01},/*OUTFMT_MONI*/ + {0x0090, 0x0280, 0x02},/*HSIZE_MONI : 640*/ + {0x0096, 0x01E0, 0x02},/*VSIZE_MONI : 480*/ + {0x0083, 0x01, 0x01},/*SENSMODE_MONI*/ + {0x0086, 0x02, 0x01},/*FPSTYPE_MONI*/ + {0x0081, 0x00, 0x01},/*MODESEL*/ + {0x0082, 0x01, 0x01},/*MONI_REFRESH*/ + + {0x0006, 0x16, 0x01}, /*INCK_SET : 24MHz*/ +}; + +/* ISX012-0 +MIPI 2LANE 432/LANE +PLL 432MHz +DCK 54 +inifile +size address data +*/ +struct isx012_short_t ISX012_Pll_Setting_3[] = { + {0x0007, 0x00, 0x01}, /* PLL_CKSEL: PLL 432MHz*/ + {0x0008, 0x00, 0x01}, /* SRCCK_DIV: 1/5 frequency*/ + + {0x0004, 0x02, 0x01}, /*I2C_ADR_SEL 2: MIPI selected*/ + {0x5008, 0x00, 0x01}, /*ENDIAN_SEL : 0:Little Endian*/ + {0x6DA8, 0x01, 0x01}, /*SHD_CoEF (OTP shading ON flag)*/ + + {0x00C4, 0x11, 0x01}, /* VIF_CLKCONFIG1*/ + {0x00C5, 0x11, 0x01}, /* VIF_CLKCONFIG2*/ + {0x00C6, 0x11, 0x01}, /* VIF_CLKCONFIG3*/ + {0x00C7, 0x11, 0x01}, /* VIF_CLKCONFIG4*/ + {0x00C8, 0x11, 0x01}, /* VIF_CLKCONFIG5*/ + {0x00C9, 0x11, 0x01}, /* VIF_CLKCONFIG6*/ + {0x00CA, 0x11, 0x01}, /* VIF_CLKCONFIG7*/ + {0x00CC, 0x11, 0x01}, /* VIF_CLKCONFIG9*/ + {0x00CD, 0x11, 0x01}, /* VIF_CLKCONFIG10*/ + {0x6A12, 0x11, 0x01}, /* VIF_CLKCONFIG13 for RAW8*/ + {0x6A13, 0x11, 0x01}, /* VIF_CLKCONFIG14 for RAW8*/ + {0x6A14, 0x11, 0x01}, /* VIF_CLKCONFIG15 for RAW8*/ + {0x6A15, 0x11, 0x01}, /* VIF_CLKCONFIG16 for RAW8*/ + {0x018C, 0x0000, 0x02}, /* VADJ_SENS_1_1*/ + {0x018E, 0x0000, 0x02}, /* VADJ_SENS_1_2*/ + {0x0190, 0x0000, 0x02}, /* VADJ_SENS_1_4*/ + {0x0192, 0x0000, 0x02}, /* VADJ_SENS_1_8*/ + {0x0194, 0x0027, 0x02}, /* VADJ_SENS_HD_1_1l*/ + {0x0196, 0x0015, 0x02}, /* VADJ_SENS_HD_1_2*/ + {0x6A16, 0x0440, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_1*/ + {0x6A18, 0x03C0, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_2*/ + {0x6A1A, 0x01E0, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_4*/ + {0x6A1C, 0x00E0, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_8*/ + {0x6A1E, 0x0420, 0x02}, /* FLC_OPD_HEIGHT_HD_1_1l*/ + {0x6A20, 0x02C0, 0x02}, /* FLC_OPD_HEIGHT_HD_1_2*/ + {0x0016, 0x0010, 0x02}, /* GPIO_FUNCSEL*/ + {0x5C01, 0x00, 0x01}, /* RGLANESEL :*/ + {0x5C04, 0x04, 0x01}, /* RGTLPX :*/ + {0x5C05, 0x03, 0x01}, /* RGTCLKPREPARE :*/ + {0x5C06, 0x0E, 0x01}, /* RGTCLKZERO :*/ + {0x5C07, 0x02, 0x01}, /* RGTCLKPRE :*/ + {0x5C08, 0x0B, 0x01}, /* RGTCLKPOST :*/ + {0x5C09, 0x05, 0x01}, /* RGTCLKTRAIL :*/ + {0x5C0A, 0x07, 0x01}, /* RGTHSEXIT :*/ + {0x5C0B, 0x03, 0x01}, /* RGTHSPREPARE :*/ + {0x5C0C, 0x07, 0x01}, /* RGTHSZERO :*/ + {0x5C0D, 0x05, 0x01}, /* RGTHSTRAIL :*/ + + {0x0009, 0x01, 0x01}, /* EXT_PLL_CKSEL:PLL648MHz*/ + {0x000A, 0x03, 0x01}, /* EXT_SRCCK_DIV:1/8 freq*/ + {0x00D8, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT9*/ + {0x00D9, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT10*/ + {0x00DA, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT11*/ + {0x00DB, 0x11, 0x01}, /* VIF_CLKCONFIG_EXT12*/ + {0x00AC, 0x02, 0x01}, /* PLL_CHG_SEL*/ + + {0x0089, 0x00, 0x01},/*OUTFMT_MONI*/ + {0x0090, 0x0280, 0x02},/*HSIZE_MONI : 640*/ + {0x0096, 0x01E0, 0x02},/*VSIZE_MONI : 480*/ + {0x0083, 0x01, 0x01},/*SENSMODE_MONI*/ + {0x0086, 0x02, 0x01},/*FPSTYPE_MONI*/ + {0x0081, 0x00, 0x01},/*MODESEL*/ + {0x0082, 0x01, 0x01},/*MONI_REFRESH*/ + + {0x0006, 0x16, 0x01}, /*INCK_SET : 24MHz*/ +}; + +struct isx012_short_t ISX012_Camcorder_SizeSetting[] = { + {0x0094, 0x0500, 0x02}, /*HSIZE_MOVIE : 1280*/ + {0x009A, 0x02D0, 0x02}, /*VSIZE_MOVIE : 720*/ +}; + +struct isx012_short_t ISX012_Camcorder_Mode[] = { + {0x008B, 0x00, 0x01}, /*OUTFMT_MOVIE*/ + {0x0085, 0x01, 0x01}, /*SENSMODE_MOVIE*/ + {0x0088, 0x02, 0x01}, /*FPSTYPE_MOVIE*/ + {0x0012, 0x02, 0x01}, /*INTCLR0*/ + {0x0081, 0x03, 0x01}, /*MODESEL*/ + {0x0082, 0x01, 0x01}, /*MONI_REFRESH*/ +}; + +struct isx012_short_t ISX012_Preview_SizeSetting[] = { + {0x0090, 0x0280, 0x02}, /*HSIZE_MONI : 640*/ + {0x0096, 0x01E0, 0x02}, /*VSIZE_MONI : 480*/ +}; + +struct isx012_short_t ISX012_1920_Preview_SizeSetting[] = { + {0x0090, 0x0780, 0x02}, /*HSIZE_MONI : 1920*/ + {0x0096, 0x0438, 0x02}, /*VSIZE_MONI : 1080*/ +}; + +struct isx012_short_t ISX012_1280_Preview_SizeSetting[] = { + {0x0090, 0x0500, 0x02}, /*HSIZE_MONI : 1280*/ + {0x0096, 0x02D0, 0x02}, /*VSIZE_MONI : 720*/ +}; + +struct isx012_short_t ISX012_800_Preview_SizeSetting[] = { + {0x0090, 0x0320, 0x02}, /*HSIZE_MONI : 800*/ + {0x0096, 0x01E0, 0x02}, /*VSIZE_MONI : 480*/ +}; + +struct isx012_short_t ISX012_720_Preview_SizeSetting[] = { + {0x0090, 0x02D0, 0x02}, /*HSIZE_MONI : 720*/ + {0x0096, 0x01E0, 0x02}, /*VSIZE_MONI : 480*/ +}; + +struct isx012_short_t ISX012_640_Preview_SizeSetting[] = { + {0x0090, 0x0280, 0x02}, /*HSIZE_MONI : 640*/ + {0x0096, 0x01E0, 0x02}, /*VSIZE_MONI : 480*/ +}; + +struct isx012_short_t ISX012_Preview_Mode[] = { + {0x0089, 0x00, 0x01}, /*OUTFMT_MONI*/ + {0x0083, 0x01, 0x01}, /*SENSMODE_MONI*/ + {0x0086, 0x02, 0x01}, /*FPSTYPE_MONI*/ + {0x0012, 0x02, 0x01}, /*INTCLR0*/ + {0x00F7, 0x52, 0x01}, /* INIT_QLTY0 : Standard 82*/ + {0x00F8, 0x59, 0x01}, /* INIT_QLTY1 : Fine 89*/ + {0x00F9, 0x5F, 0x01}, /* INIT_QLTY2 : SuperFine 95*/ + {0x0081, 0x00, 0x01}, /*MODESEL*/ + {0x0082, 0x01, 0x01}, /*MONI_REFRESH*/ +}; + +struct isx012_short_t ISX012_Halfrelease_Mode[] = { + {0x00B1, 0x01, 0x01}, /*AF_RESTART_F*/ + {0xFFFF, 0x21, 0x01},/*$wait, 33*/ + {0x0081, 0x01, 0x01}, /*MODESEL*/ +}; + +struct isx012_short_t ISX012_AF_Cancel_Macro_ON[] = { + {0x00B2, 0x02, 0x01}, /*AFMODE_MONI : Manual AF mode*/ + {0x0081, 0x00, 0x01}, /*MODESEL : Monitoring mode*/ + {0xFFFF, 0x42, 0x01},/*$wait, 66*/ + {0x6648, 0x02A8, 0x02}, /*AF_MANUAL_POS*/ + {0x00B1, 0x01, 0x01}, /*AF_RESTART_F*/ +}; + +struct isx012_short_t ISX012_AF_Cancel_Macro_OFF[] = { + {0x00B2, 0x02, 0x01}, /*AFMODE_MONI : Manual AF mode*/ + {0x0081, 0x00, 0x01}, /*MODESEL : Monitoring mode*/ + {0xFFFF, 0x42, 0x01},/*$wait, 66*/ + {0x6648, 0x00C8, 0x02}, /*AF_MANUAL_POS*/ + {0x00B1, 0x01, 0x01}, /*AF_RESTART_F*/ +}; + +struct isx012_short_t ISX012_AF_ReStart[] = { + {0x00B1, 0x01, 0x01}, /*AF_RESTART_F*/ +}; + +struct isx012_short_t ISX012_AF_Macro_OFF[] = { + {0x0081, 0x00, 0x01}, /*MODESEL : Monitoring mode*/ + {0x6648, 0x00C8, 0x02}, /*AF_MANUAL_POS*/ + {0x66DC, 0x02A8, 0x02}, /*AF_JUDGE_MONO_POS_S*/ + {0x028E, 0x00, 0x01}, /*AF_SEARCH_DIR : NEAR->FAR*/ + {0xFFFF, 0x21, 0x01},/*$wait, 33*/ +}; + +struct isx012_short_t ISX012_AF_Macro_ON[] = { + {0x0081, 0x00, 0x01}, /*MODESEL : Monitoring mode*/ + {0x6648, 0x02A8, 0x02}, /*AF_MANUAL_POS*/ + {0x66DC, 0x00C8, 0x02}, /*AF_JUDGE_MONO_POS_S*/ + {0x028E, 0x01, 0x01}, /*AF_SEARCH_DIR : NEAR->FAR*/ + {0xFFFF, 0x21, 0x01},/*$wait, 33*/ +}; + +struct isx012_short_t ISX012_AF_SAF[] = { + {0x00B1, 0x01, 0x01}, /*AF_RESTART_F*/ + {0xFFFF, 0x21, 0x01},/*$wait, 33*/ + {0x0081, 0x01, 0x01}, /*MODESEL*/ +}; + +struct isx012_short_t ISX012_AF_SAF_OFF[] = { + {0x00B2, 0x02, 0x01}, /*AFMODE_MONI : Manual AF mode*/ + {0x0081, 0x00, 0x01}, /*MODESEL : Monitoring mode*/ +}; + +struct isx012_short_t ISX012_Brightness_0[] = { + {0x01C6, 0x00, 0x01}, /*UIBRIGHTNESS*/ +}; + +struct isx012_short_t ISX012_Brightness_M1[] = { + {0x01C6, 0xFF, 0x01}, +}; + +struct isx012_short_t ISX012_Brightness_M2[] = { + {0x01C6, 0xFD, 0x01}, +}; + +struct isx012_short_t ISX012_Brightness_M3[] = { + {0x01C6, 0xFC, 0x01}, +}; + +struct isx012_short_t ISX012_Brightness_M4[] = { + {0x01C6, 0xFA, 0x01}, +}; + +struct isx012_short_t ISX012_Brightness_P1[] = { + {0x01C6, 0x01, 0x01}, +}; + +struct isx012_short_t ISX012_Brightness_P2[] = { + {0x01C6, 0x03, 0x01}, +}; + +struct isx012_short_t ISX012_Brightness_P3[] = { + {0x01C6, 0x04, 0x01}, +}; + +struct isx012_short_t ISX012_Brightness_P4[] = { + {0x01C6, 0x06, 0x01}, +}; + +struct isx012_short_t ISX012_Contrast_0[] = { + {0x01C7, 0x80, 0x01}, /*UICONTRAST*/ +}; + +struct isx012_short_t ISX012_Contrast_N1[] = { + {0x01C7, 0x6C, 0x01}, /*UICONTRAST*/ +}; + +struct isx012_short_t ISX012_Contrast_N2[] = { + {0x01C7, 0x58, 0x01}, /*UICONTRAST*/ +}; + +struct isx012_short_t ISX012_Contrast_P1[] = { + {0x01C7, 0x94, 0x01}, /*UICONTRAST*/ +}; + +struct isx012_short_t ISX012_Contrast_P2[] = { + {0x01C7, 0xA8, 0x01}, /*UICONTRAST*/ +}; + +struct isx012_short_t ISX012_Effect_Pastel[] = { + {0x01C5, 0x05, 0x01}, /*FMODE*/ +}; + +struct isx012_short_t ISX012_Effect_Monotone[] = { + {0x01C5, 0x04, 0x01}, /*FMODE*/ +}; + +struct isx012_short_t ISX012_Effect_Negative[] = { + {0x01C5, 0x02, 0x01}, /*FMODE*/ +}; + +struct isx012_short_t ISX012_Effect_Normal[] = { + {0x01C5, 0x00, 0x01}, /*FMODE*/ +}; + +struct isx012_short_t ISX012_Effect_Sepia[] = { + {0x01C5, 0x03, 0x01}, /*FMODE*/ +}; + +struct isx012_short_t ISX012_Potometry_CenterWeight[] = { + {0x02AC, 0x01, 0x01}, /*AE_SUB_SN1*/ + {0x02B6, 0x01, 0x01}, /*AE_SUB_SN11*/ +}; + +struct isx012_short_t ISX012_Potometry_Average[] = { + {0x02AC, 0x00, 0x01}, /*AE_SUB_SN1*/ +}; + +struct isx012_short_t ISX012_Potometry_Spot[] = { + {0x02AC, 0x02, 0x01}, /*AE_SUB_SN1*/ + {0x02B6, 0x02, 0x01}, /*AE_SUB_SN11*/ +}; + +struct isx012_short_t ISX012_ExpSetting_Default[] = { + {0x0180, 0x00, 0x01}, /*EVSEL*/ +}; + +struct isx012_short_t ISX012_ExpSetting_M1Step[] = { + {0x0180, 0xFF, 0x01}, /*EVSEL*/ +}; + +struct isx012_short_t ISX012_ExpSetting_M2Step[] = { + {0x0180, 0xFE, 0x01}, /*EVSEL*/ +}; + +struct isx012_short_t ISX012_ExpSetting_M3Step[] = { + {0x0180, 0xFD, 0x01}, /*EVSEL*/ +}; + +struct isx012_short_t ISX012_ExpSetting_M4Step[] = { + {0x0180, 0xFC, 0x01}, /*EVSEL*/ +}; + +struct isx012_short_t ISX012_ExpSetting_P1Step[] = { + {0x0180, 0x01, 0x01}, /*EVSEL*/ +}; + +struct isx012_short_t ISX012_ExpSetting_P2Step[] = { + {0x0180, 0x02, 0x01}, /*EVSEL*/ +}; + +struct isx012_short_t ISX012_ExpSetting_P3Step[] = { + {0x0180, 0x03, 0x01}, /*EVSEL*/ +}; + +struct isx012_short_t ISX012_ExpSetting_P4Step[] = { + {0x0180, 0x04, 0x01}, /*EVSEL*/ +}; + +struct isx012_short_t ISX012_ISO_50[] = { + {0x02A8, 0x04, 0x01}, /*ISO_TYPE1*/ +}; + +struct isx012_short_t ISX012_ISO_100[] = { + {0x02A8, 0x07, 0x01}, /*ISO_TYPE1*/ +}; + +struct isx012_short_t ISX012_ISO_200[] = { + {0x02A8, 0x0A, 0x01}, /*ISO_TYPE1*/ +}; + +struct isx012_short_t ISX012_ISO_400[] = { + {0x02A8, 0x0D, 0x01}, /*ISO_TYPE1*/ +}; + +struct isx012_short_t ISX012_ISO_800[] = { + {0x02A8, 0x10, 0x01}, /*ISO_TYPE1*/ +}; + +struct isx012_short_t ISX012_ISO_AUTO[] = { + {0x02A8, 0x00, 0x01}, /*ISO_TYPE1*/ +}; + +struct isx012_short_t ISX012_Capture_SizeSetting[] = { + {0x0092, 0x0A20, 0x02}, /*HSIZE_CAP : 2592*/ + {0x0098, 0x0798, 0x02}, /*VSIZE_CAP : 1944*/ +}; + +struct isx012_short_t ISX012_Capture_Mode[] = { + {0x008A, 0x00, 0x01}, /*OUTFMT_CAP*/ + {0x0084, 0x00, 0x01}, /*SENSMODE_CAP*/ + {0x0087, 0x03, 0x01}, /*FPSTYPE_CAP*/ + {0x0012, 0x06, 0x01}, /*INTCLR0*/ + {0x0081, 0x02, 0x01}, /*MODESEL*/ + {0x0082, 0x01, 0x01}, /*MONI_REFRESH*/ +}; + + +struct isx012_short_t ISX012_Flash_ON[] = { +/*Flash_ON_SET*/ +{0x8801, 0xB7, 0x01}, +{0x8802, 0x00, 0x01}, +{0x8803, 0x15, 0x01}, +{0x8804, 0x16, 0x01}, +{0x8805, 0x00, 0x01}, +{0x8806, 0x10, 0x01}, +{0x8807, 0x81, 0x01}, +{0x8808, 0x01, 0x01}, +{0x8809, 0x05, 0x01}, +{0x880A, 0xAE, 0x01}, +{0x880B, 0x01, 0x01}, +{0x880C, 0x01, 0x01}, +{0x880D, 0x23, 0x01}, +{0x880E, 0x62, 0x01}, +{0x880F, 0x01, 0x01}, +{0x8810, 0x26, 0x01}, +{0x8811, 0x62, 0x01}, +{0x8812, 0x01, 0x01}, +{0x8813, 0x27, 0x01}, +{0x8814, 0x62, 0x01}, +{0x8815, 0x01, 0x01}, +{0x8816, 0x28, 0x01}, +{0x8817, 0x62, 0x01}, +{0x8818, 0x01, 0x01}, +{0x8819, 0x29, 0x01}, +{0x881A, 0x62, 0x01}, +{0x881B, 0x01, 0x01}, +{0x881C, 0x3D, 0x01}, +{0x881D, 0x5E, 0x01}, +{0x881E, 0x0F, 0x01}, +{0x881F, 0x32, 0x01}, +{0x8820, 0x5E, 0x01}, +{0x8821, 0x0B, 0x01}, +{0x8822, 0x2E, 0x01}, +{0x8823, 0x5E, 0x01}, +{0x8824, 0x3C, 0x01}, +{0x8825, 0x0A, 0x01}, +{0x8826, 0x50, 0x01}, +{0x8827, 0x01, 0x01}, +{0x8828, 0xAF, 0x01}, +{0x8829, 0x01, 0x01}, +{0x882A, 0x01, 0x01}, +{0x882B, 0x24, 0x01}, +{0x882C, 0x62, 0x01}, +{0x882D, 0x01, 0x01}, +{0x882E, 0x00, 0x01}, +{0x882F, 0x50, 0x01}, +{0x8830, 0x00, 0x01}, +{0x8831, 0x81, 0x01}, +{0x8832, 0x00, 0x01}, +{0x8833, 0x01, 0x01}, +}; + + +struct isx012_short_t ISX012_Flash_OFF[] = { +/*Flash_OFF_RESET*/ +{0x8801, 0xB7, 0x01}, +{0x8802, 0x00, 0x01}, +{0x8803, 0x00, 0x01}, +{0x8804, 0x16, 0x01}, +{0x8805, 0x00, 0x01}, +{0x8806, 0x10, 0x01}, +{0x8807, 0x81, 0x01}, +{0x8808, 0x01, 0x01}, +{0x8809, 0x00, 0x01}, +{0x880A, 0xAE, 0x01}, +{0x880B, 0x01, 0x01}, +{0x880C, 0x00, 0x01}, +{0x880D, 0x23, 0x01}, +{0x880E, 0x62, 0x01}, +{0x880F, 0x04, 0x01}, +{0x8810, 0x26, 0x01}, +{0x8811, 0x62, 0x01}, +{0x8812, 0x02, 0x01}, +{0x8813, 0x27, 0x01}, +{0x8814, 0x62, 0x01}, +{0x8815, 0x02, 0x01}, +{0x8816, 0x28, 0x01}, +{0x8817, 0x62, 0x01}, +{0x8818, 0x02, 0x01}, +{0x8819, 0x29, 0x01}, +{0x881A, 0x62, 0x01}, +{0x881B, 0x02, 0x01}, +{0x881C, 0x3D, 0x01}, +{0x881D, 0x5E, 0x01}, +{0x881E, 0x0A, 0x01}, +{0x881F, 0x32, 0x01}, +{0x8820, 0x5E, 0x01}, +{0x8821, 0x0F, 0x01}, +{0x8822, 0x2E, 0x01}, +{0x8823, 0x5E, 0x01}, +{0x8824, 0x1A, 0x01}, +{0x8825, 0x0A, 0x01}, +{0x8826, 0x50, 0x01}, +{0x8827, 0x00, 0x01}, +{0x8828, 0xAF, 0x01}, +{0x8829, 0x01, 0x01}, +{0x882A, 0x00, 0x01}, +{0x882B, 0x24, 0x01}, +{0x882C, 0x62, 0x01}, +{0x882D, 0x10, 0x01}, +{0x882E, 0x00, 0x01}, +{0x882F, 0x50, 0x01}, +{0x8830, 0x00, 0x01}, +{0x8831, 0x81, 0x01}, +{0x8832, 0x00, 0x01}, +{0x8833, 0x00, 0x01}, +{0x0308, 0x00, 0x01}, /* AELINE_MONI_SN1_2*/ +{0x030E, 0x00, 0x01}, /* AELINE_HALF_SN1_2*/ +{0x031A, 0x00, 0x01}, /* AELINE_CAP_SN1_2*/ +{0x0314, 0x00, 0x01}, /* AELINE_HALF_AFEND_SN1_2*/ +{0x0294, 0x00, 0x01}, /* AE_SN1*/ +{0x029E, 0x00, 0x01}, /* AE_SN11*/ +}; + + +struct isx012_short_t ISX012_Saturation_0[] = { + {0x039E, 0x80, 0x01}, /*UISATURATION_TYPE1*/ +}; + +struct isx012_short_t ISX012_Saturation_N1[] = { + {0x039E, 0x62, 0x01}, /*UISATURATION_TYPE1*/ +}; + +struct isx012_short_t ISX012_Saturation_N2[] = { + {0x039E, 0x44, 0x01}, /*UISATURATION_TYPE1*/ +}; + +struct isx012_short_t ISX012_Saturation_P1[] = { + {0x039E, 0x9E, 0x01}, /*UISATURATION_TYPE1*/ +}; + +struct isx012_short_t ISX012_Saturation_P2[] = { + {0x039E, 0xBC, 0x01}, /*UISATURATION_TYPE1*/ +}; + +struct isx012_short_t ISX012_Scene_Auto[] = { + {0x0280, 0x00, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Landscape[] = { + {0x03A3, 0x2C, 0x01}, /*UISHARPNESS_POS_TYPE3 : +1*/ + {0x03A6, 0x2C, 0x01}, /*UISHARPNESS_NEG_TYPE3 : +1*/ + {0x0280, 0x01, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Sports[] = { + {0x0280, 0x02, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Indoor[] = { + {0x0280, 0x03, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Beach_Snow[] = { + {0x0280, 0x04, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Sunset[] = { + {0x0394, 0x00, 0x01}, /*PICT1_SN6 :*/ + {0x0287, 0x25, 0x01}, /*AWB_SN6 : daylight*/ + {0x0394, 0x00, 0x01}, /*PICT1_SN6 :*/ + {0x0280, 0x05, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Dawn[] = { + {0x0394, 0x00, 0x01}, /*PICT1_SN6 :*/ + {0x0287, 0x28, 0x01}, /*AWB_SN6 : CWF*/ + {0x0394, 0x00, 0x01}, /*PICT1_SN6 :*/ + {0x0280, 0x05, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_CandleLight[] = { + {0x0394, 0x00, 0x01}, /*PICT1_SN6 :*/ + {0x0287, 0x25, 0x01}, /*AWB_SN6 : daylight*/ + {0x0394, 0x00, 0x01}, /*PICT1_SN6 :*/ + {0x0280, 0x05, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Fallcolor[] = { + {0x0394, 0x08, 0x01}, /*PICT1_SN6 : saturation : +2*/ + {0x0287, 0x20, 0x01}, /*AWB_SN6 : AWB*/ + {0x0394, 0x08, 0x01}, /*PICT1_SN6 :*/ + {0x0280, 0x05, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Portrait[] = { + {0x0280, 0x06, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Nightmode[] = { + {0x0280, 0x07, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Firework[] = { + {0x0280, 0x08, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Document[] = { + {0x03A3, 0x38, 0x01}, /*UISHARPNESS_POS_TYPE3 : +2*/ + {0x03A6, 0x38, 0x01}, /*UISHARPNESS_NEG_TYPE3 : +2*/ + {0x0280, 0x09, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Scene_Backlight[] = { + {0x0280, 0x10, 0x01}, /*SCENE_SELECT*/ +}; + +struct isx012_short_t ISX012_Sharpness_0[] = { + {0x00A1, 0x20, 0x01}, /*UISHARPNESS_POS_TYPE1*/ + {0x00A4, 0x20, 0x01}, /*UISHARPNESS_NEG_TYPE1*/ +}; + +struct isx012_short_t ISX012_Sharpness_N1[] = { + {0x00A1, 0x14, 0x01}, /*UISHARPNESS_POS_TYPE1*/ + {0x00A4, 0x14, 0x01}, /*UISHARPNESS_NEG_TYPE1*/ +}; + +struct isx012_short_t ISX012_Sharpness_N2[] = { + {0x00A1, 0x08, 0x01}, /*UISHARPNESS_POS_TYPE1*/ + {0x00A4, 0x08, 0x01}, /*UISHARPNESS_NEG_TYPE1*/ +}; + +struct isx012_short_t ISX012_Sharpness_P1[] = { + {0x00A1, 0x2C, 0x01}, /*UISHARPNESS_POS_TYPE1*/ + {0x00A4, 0x2C, 0x01}, /*UISHARPNESS_NEG_TYPE1*/ +}; + +struct isx012_short_t ISX012_Sharpness_P2[] = { + {0x00A1, 0x38, 0x01}, /*UISHARPNESS_POS_TYPE1*/ + {0x00A4, 0x38, 0x01}, /*UISHARPNESS_NEG_TYPE1*/ +}; + +struct isx012_short_t ISX012_WB_Auto[] = { + {0x0282, 0x20, 0x01}, /*AWB_SN1*/ +}; + +struct isx012_short_t ISX012_WB_Cloudy[] = { + {0x0282, 0x26, 0x01}, /*AWB_SN1*/ +}; + +struct isx012_short_t ISX012_WB_Daylight[] = { + {0x0282, 0x25, 0x01}, /*AWB_SN1*/ +}; + +struct isx012_short_t ISX012_WB_Fluorescent[] = { + {0x0282, 0x27, 0x01}, /*AWB_SN1*/ +}; + +struct isx012_short_t ISX012_WB_Incandescent[] = { + {0x0282, 0x28, 0x01}, /*AWB_SN1*/ +}; + +struct isx012_short_t ISX012_Image_Quality_Standard[] = { + {0x00F6, 0x00, 0x01}, /*JPG_QLTY*/ + {0x0082, 0x01, 0x01}, /*MONI_REFRESH*/ +}; + +struct isx012_short_t ISX012_Image_Quality_Fine[] = { + {0x00F6, 0x01, 0x01}, /*JPG_QLTY*/ + {0x0082, 0x01, 0x01}, /*MONI_REFRESH*/ +}; + +struct isx012_short_t ISX012_Image_Quality_Super_Fine[] = { + {0x00F6, 0x02, 0x01}, /*JPG_QLTY*/ + {0x0082, 0x01, 0x01}, /*MONI_REFRESH*/ +}; + +struct isx012_short_t ISX012_Image_Quality_Table[] = { + {0x00F7, 0x52, 0x01}, /* INIT_QLTY0 : Standard 82*/ + {0x00F8, 0x59, 0x01}, /* INIT_QLTY1 : Fine 89*/ + {0x00F9, 0x5F, 0x01}, /* INIT_QLTY2 : SuperFine 95*/ +}; + +struct isx012_short_t ISX012_Sensor_Off_VCM[] = { + {0x00B2, 0x02, 0x01}, /*AFMODE_MONI : Manual AF mode*/ + {0x0081, 0x00, 0x01}, /*MODESEL : Monitoring mode*/ + {0x6648, 0x00C8, 0x02}, /*AF_MANUAL_POS*/ + {0x00B1, 0x01, 0x01}, /*AF_RESTART_F*/ + {0xFFFF, 0x42, 0x01},/*$wait, 66*/ +}; + +struct isx012_short_t ISX012_DTP_Init[] = { + {0x01BC, 0x50, 0x01}, + {0x5E00, 0x07, 0x01}, + + {0x6804, 0x1000, 0x02}, + {0x6806, 0x1000, 0x02}, + {0x6808, 0x0100, 0x02}, + {0x680A, 0x0100, 0x02}, + {0x6818, 0x00, 0x01}, + {0x6819, 0x00, 0x01}, + + {0x036B, 0x11, 0x01}, + {0x0377, 0x11, 0x01}, + {0x0383, 0x11, 0x01}, + + {0x6C44, 0x00, 0x01}, + + {0x6C4A, 0x07, 0x01}, + + {0x5005, 0xBB, 0x01}, + {0x5006, 0x03, 0x01}, + {0x0362, 0x00, 0x01}, + + {0x6C0B, 0x04, 0x01}, + {0x9800, 0x80, 0x01}, + {0x9801, 0x80, 0x01}, + + {0x6C46, 0x00, 0x01}, + {0x6C47, 0x00, 0x01}, + {0x6C48, 0x00, 0x01}, + {0x6C49, 0x00, 0x01}, + {0x6C4A, 0x00, 0x01}, + + + {0x5001, 0x04, 0x01}, + {0x5002, 0x00, 0x01}, + {0x5003, 0x07, 0x01}, + {0x5004, 0x00, 0x01}, + {0x5005, 0x00, 0x01}, + {0x5006, 0x00, 0x01}, + {0x5007, 0x00, 0x01}, + {0x5009, 0x00, 0x01}, + {0x500A, 0x00, 0x01}, + {0x500B, 0x00, 0x01}, + {0x500C, 0x00FA, 0x02}, + {0x500E, 0x06D0, 0x02}, + {0x5010, 0x02F8, 0x02}, + {0x5012, 0x0118, 0x02}, + {0x5014, 0x0028, 0x02}, + {0x5016, 0x0370, 0x02}, + {0x5018, 0x0208, 0x02}, + {0x501A, 0x00, 0x01}, + {0x501B, 0x19, 0x01}, + {0x501C, 0x5180, 0x02}, + {0x501E, 0x0001, 0x02}, + + {0x6E86, 0x0000, 0x02}, + {0x6E88, 0xFFF5, 0x02}, + {0x6E8A, 0xFFF8, 0x02}, + {0x6E8C, 0xFFF5, 0x02}, + {0x6E8E, 0xFFF8, 0x02}, + {0x6E90, 0xFFEE, 0x02}, + {0x6E92, 0x0000, 0x02}, + {0x6E94, 0xFFEC, 0x02}, + {0x6F26, 0x4E, 0x01}, + {0x6F27, 0x50, 0x01}, + {0x6F28, 0x4E, 0x01}, + {0x6F29, 0x5A, 0x01}, + {0x6F2A, 0x50, 0x01}, + {0x6F2B, 0x5A, 0x01}, + {0x6F2C, 0x50, 0x01}, + {0x6F2D, 0x50, 0x01}, + + {0x5E12, 0x0037, 0x02}, + {0x5E14, 0x0000, 0x02}, + {0x0294, 0x03, 0x01}, + + {0x625F, 0x35, 0x01}, + {0x0282, 0x05, 0x01}, + + {0x5021, 0x00, 0x01}, + {0x5022, 0x01, 0x01}, + {0x5023, 0x04, 0x01}, + {0x5024, 0x0000, 0x02}, + {0x5026, 0x00, 0x01}, + {0x5020, 0x01, 0x01}, +}; + +struct isx012_short_t ISX012_DTP_Stop[] = { + {0x01BC, 0x57, 0x01}, + {0x5E00, 0x00, 0x01}, + {0x6804, 0x11F0, 0x02}, + {0x6806, 0x106F, 0x02}, + {0x6808, 0x014C, 0x02}, + {0x680A, 0x021E, 0x02}, + {0x6818, 0x00, 0x01}, + {0x6819, 0x00, 0x01}, + {0x036B, 0x80, 0x01}, + {0x0377, 0x80, 0x01}, + {0x0383, 0x80, 0x01}, + {0x6C44, 0x13, 0x01}, + {0x6C4A, 0x07, 0x01}, + {0x5005, 0xBB, 0x01}, + {0x5006, 0x03, 0x01}, + {0x0362, 0x55, 0x01}, + {0x6C0B, 0x00, 0x01}, + {0x9800, 0x40, 0x01}, + {0x9801, 0x80, 0x01}, + {0x6C46, 0x1C, 0x01}, + {0x6C47, 0x0F, 0x01}, + {0x6C48, 0x03, 0x01}, + {0x6C49, 0xF5, 0x01}, + {0x6C4A, 0x07, 0x01}, + {0x5001, 0x04, 0x01}, + {0x5002, 0x01, 0x01}, + {0x5003, 0x04, 0x01}, + {0x5004, 0x00, 0x01}, + {0x5005, 0xBB, 0x01}, + {0x5006, 0x03, 0x01}, + {0x5007, 0x01, 0x01}, + {0x5009, 0x00, 0x01}, + {0x500A, 0x00, 0x01}, + {0x500B, 0x00, 0x01}, + {0x500C, 0x00FA, 0x02}, + {0x500E, 0x06D0, 0x02}, + {0x5010, 0x02F8, 0x02}, + {0x5012, 0x0118, 0x02}, + {0x5014, 0x0028, 0x02}, + {0x5016, 0x0370, 0x02}, + {0x5018, 0x0208, 0x02}, + {0x501A, 0x00, 0x01}, + {0x501B, 0x50, 0x01}, + {0x501C, 0x5180, 0x02}, + {0x501E, 0x0001, 0x02}, + {0x6E86, 0x0000, 0x02}, + {0x6E88, 0xFFF5, 0x02}, + {0x6E8A, 0xFFF8, 0x02}, + {0x6E8C, 0xFFF5, 0x02}, + {0x6E8E, 0xFFF8, 0x02}, + {0x6E90, 0xFFEE, 0x02}, + {0x6E92, 0x0000, 0x02}, + {0x6E94, 0xFFEC, 0x02}, + {0x6F26, 0x4E, 0x01}, + {0x6F27, 0x50, 0x01}, + {0x6F28, 0x4E, 0x01}, + {0x6F29, 0x5A, 0x01}, + {0x6F2A, 0x50, 0x01}, + {0x6F2B, 0x5A, 0x01}, + {0x6F2C, 0x50, 0x01}, + {0x6F2D, 0x50, 0x01}, + {0x5E12, 0x014A, 0x02}, + {0x5E14, 0x000D, 0x02}, + {0x0294, 0x00, 0x01}, + {0x625F, 0x35, 0x01}, + {0x0282, 0x20, 0x01}, + {0x5021, 0x00, 0x01}, + {0x5022, 0x00, 0x01}, + {0x5023, 0x00, 0x01}, + {0x5024, 0x0000, 0x02}, + {0x5026, 0x00, 0x01}, + {0x5020, 0x00, 0x01}, +}; + + +struct isx012_short_t ISX012_Shading_Nocal[] = { + {0x01BC, 0x50, 0x01}, /* CXC OFF SHD OFF*/ + + {0xEB00, 0x8282, 0x02}, /*valid_code*/ + {0xEB02, 0xFF, 0x01}, + {0xEB03, 0xC4, 0x01}, + {0xEB04, 0x3F, 0x01}, + {0xEB05, 0xF1, 0x01}, + {0xEB06, 0x3F, 0x01}, + {0xEB07, 0x00, 0x01}, + {0xEB08, 0x12, 0x01}, + {0xEB09, 0x7E, 0x01}, + {0xEB0A, 0x83, 0x01}, + {0xEB0B, 0xFF, 0x01}, + {0xEB0C, 0xF0, 0x01}, + {0xEB0D, 0x47, 0x01}, + {0xEB0E, 0x04, 0x01}, + {0xEB0F, 0x12, 0x01}, + {0xEB10, 0x81, 0x01}, + {0xEB11, 0xC4, 0x01}, + {0xEB12, 0x3F, 0x01}, + {0xEB13, 0xF1, 0x01}, + {0xEB14, 0x4F, 0x01}, + {0xEB15, 0xFC, 0x01}, + {0xEB16, 0x0F, 0x01}, + {0xEB17, 0x80, 0x01}, + {0xEB18, 0x84, 0x01}, + {0xEB19, 0xDF, 0x01}, + {0xEB1A, 0xE0, 0x01}, + {0xEB1B, 0x3F, 0x01}, + {0xEB1C, 0xFC, 0x01}, + {0xEB1D, 0x11, 0x01}, + {0xEB1E, 0x81, 0x01}, + {0xEB1F, 0x44, 0x01}, + {0xEB20, 0x20, 0x01}, + {0xEB21, 0x11, 0x01}, + {0xEB22, 0x38, 0x01}, + {0xEB23, 0x04, 0x01}, + {0xEB24, 0x0E, 0x01}, + {0xEB25, 0x01, 0x01}, + {0xEB26, 0xC3, 0x01}, + {0xEB27, 0xBF, 0x01}, + {0xEB28, 0x00, 0x01}, + {0xEB29, 0x30, 0x01}, + {0xEB2A, 0x00, 0x01}, + {0xEB2B, 0x0C, 0x01}, + {0xEB2C, 0x82, 0x01}, + {0xEB2D, 0x43, 0x01}, + {0xEB2E, 0x40, 0x01}, + {0xEB2F, 0x11, 0x01}, + {0xEB30, 0x50, 0x01}, + {0xEB31, 0x08, 0x01}, + {0xEB32, 0x0E, 0x01}, + {0xEB33, 0x82, 0x01}, + {0xEB34, 0xC3, 0x01}, + {0xEB35, 0xA0, 0x01}, + {0xEB36, 0x00, 0x01}, + {0xEB37, 0x18, 0x01}, + {0xEB38, 0x00, 0x01}, + {0xEB39, 0x04, 0x01}, + {0xEB3A, 0x81, 0x01}, + {0xEB3B, 0x01, 0x01}, + {0xEB3C, 0xC0, 0x01}, + {0xEB3D, 0x00, 0x01}, + {0xEB3E, 0x38, 0x01}, + {0xEB3F, 0x00, 0x01}, + {0xEB40, 0x0E, 0x01}, + {0xEB41, 0x83, 0x01}, + {0xEB42, 0xC2, 0x01}, + {0xEB43, 0xA0, 0x01}, + {0xEB44, 0x10, 0x01}, + {0xEB45, 0x18, 0x01}, + {0xEB46, 0x00, 0x01}, + {0xEB47, 0x04, 0x01}, + {0xEB48, 0x01, 0x01}, + {0xEB49, 0x01, 0x01}, + {0xEB4A, 0x00, 0x01}, + {0xEB4B, 0x00, 0x01}, + {0xEB4C, 0x18, 0x01}, + {0xEB4D, 0x08, 0x01}, + {0xEB4E, 0x0A, 0x01}, + {0xEB4F, 0x82, 0x01}, + {0xEB50, 0x02, 0x01}, + {0xEB51, 0x60, 0x01}, + {0xEB52, 0x00, 0x01}, + {0xEB53, 0x18, 0x01}, + {0xEB54, 0x04, 0x01}, + {0xEB55, 0x02, 0x01}, + {0xEB56, 0x81, 0x01}, + {0xEB57, 0x40, 0x01}, + {0xEB58, 0x20, 0x01}, + {0xEB59, 0x00, 0x01}, + {0xEB5A, 0x08, 0x01}, + {0xEB5B, 0x04, 0x01}, + {0xEB5C, 0x04, 0x01}, + {0xEB5D, 0x02, 0x01}, + {0xEB5E, 0x82, 0x01}, + {0xEB5F, 0x80, 0x01}, + {0xEB60, 0x30, 0x01}, + {0xEB61, 0x18, 0x01}, + {0xEB62, 0x0C, 0x01}, + {0xEB63, 0x06, 0x01}, + {0xEB64, 0x82, 0x01}, + {0xEB65, 0xC0, 0x01}, + {0xEB66, 0xFF, 0x01}, + {0xEB67, 0x0F, 0x01}, + {0xEB68, 0x00, 0x01}, + {0xEB69, 0x04, 0x01}, + {0xEB6A, 0x00, 0x01}, + {0xEB6B, 0x80, 0x01}, + {0xEB6C, 0x00, 0x01}, + {0xEB6D, 0x40, 0x01}, + {0xEB6E, 0x00, 0x01}, + {0xEB6F, 0x10, 0x01}, + {0xEB70, 0x00, 0x01}, + {0xEB71, 0x04, 0x01}, + {0xEB72, 0x00, 0x01}, + {0xEB73, 0x81, 0x01}, + {0xEB74, 0x60, 0x01}, + {0xEB75, 0x20, 0x01}, + {0xEB76, 0x00, 0x01}, + {0xEB77, 0x04, 0x01}, + {0xEB78, 0xFE, 0x01}, + {0xEB79, 0x82, 0x01}, + {0xEB7A, 0xC0, 0x01}, + {0xEB7B, 0x40, 0x01}, + {0xEB7C, 0x30, 0x01}, + {0xEB7D, 0x18, 0x01}, + {0xEB7E, 0x0C, 0x01}, + {0xEB7F, 0x06, 0x01}, + {0xEB80, 0x80, 0x01}, + {0xEB81, 0x01, 0x01}, + {0xEB82, 0x60, 0x01}, + {0xEB83, 0x30, 0x01}, + {0xEB84, 0x18, 0x01}, + {0xEB85, 0x08, 0x01}, + {0xEB86, 0x04, 0x01}, + {0xEB87, 0x80, 0x01}, + {0xEB88, 0xC0, 0x01}, + {0xEB89, 0x40, 0x01}, + {0xEB8A, 0x20, 0x01}, + {0xEB8B, 0x10, 0x01}, + {0xEB8C, 0x0C, 0x01}, + {0xEB8D, 0x06, 0x01}, + {0xEB8E, 0x83, 0x01}, + {0xEB8F, 0x41, 0x01}, + {0xEB90, 0x80, 0x01}, + {0xEB91, 0x10, 0x01}, + {0xEB92, 0x20, 0x01}, + {0xEB93, 0x04, 0x01}, + {0xEB94, 0x06, 0x01}, + {0xEB95, 0x82, 0x01}, + {0xEB96, 0x41, 0x01}, + {0xEB97, 0x60, 0x01}, + {0xEB98, 0x30, 0x01}, + {0xEB99, 0x28, 0x01}, + {0xEB9A, 0x08, 0x01}, + {0xEB9B, 0x08, 0x01}, + {0xEB9C, 0x82, 0x01}, + {0xEB9D, 0x82, 0x01}, + {0xEB9E, 0xA0, 0x01}, + {0xEB9F, 0xE0, 0x01}, + {0xEBA0, 0x2F, 0x01}, + {0xEBA1, 0xF8, 0x01}, + {0xEBA2, 0x0B, 0x01}, + {0xEBA3, 0x02, 0x01}, + {0xEBA4, 0x42, 0x01}, + {0xEBA5, 0xA0, 0x01}, + {0xEBA6, 0x20, 0x01}, + {0xEBA7, 0x28, 0x01}, + {0xEBA8, 0x10, 0x01}, + {0xEBA9, 0x0C, 0x01}, + {0xEBAA, 0x03, 0x01}, + {0xEBAB, 0x82, 0x01}, + {0xEBAC, 0xA0, 0x01}, + {0xEBAD, 0x20, 0x01}, + {0xEBAE, 0x28, 0x01}, + {0xEBAF, 0xF8, 0x01}, + {0xEBB0, 0x0B, 0x01}, + {0xEBB1, 0xFE, 0x01}, + {0xEBB2, 0x82, 0x01}, + {0xEBB3, 0x80, 0x01}, + {0xEBB4, 0x10, 0x01}, + {0xEBB5, 0x28, 0x01}, + {0xEBB6, 0x08, 0x01}, + {0xEBB7, 0x0A, 0x01}, + {0xEBB8, 0x04, 0x01}, + {0xEBB9, 0xC3, 0x01}, + {0xEBBA, 0x80, 0x01}, + {0xEBBB, 0x20, 0x01}, + {0xEBBC, 0x28, 0x01}, + {0xEBBD, 0x08, 0x01}, + {0xEBBE, 0x0A, 0x01}, + {0xEBBF, 0x03, 0x01}, + {0xEBC0, 0xFB, 0x01}, + {0xEBC1, 0xC0, 0x01}, + {0xEBC2, 0x3E, 0x01}, + {0xEBC3, 0xC0, 0x01}, + {0xEBC4, 0x0F, 0x01}, + {0xEBC5, 0xF4, 0x01}, + {0xEBC6, 0x02, 0x01}, + {0xEBC7, 0xFC, 0x01}, + {0xEBC8, 0x20, 0x01}, + {0xEBC9, 0x2F, 0x01}, + {0xEBCA, 0xB8, 0x01}, + {0xEBCB, 0x03, 0x01}, + {0xEBCC, 0xF8, 0x01}, + {0xEBCD, 0x00, 0x01}, + {0xEBCE, 0xFE, 0x01}, + {0xEBCF, 0xC0, 0x01}, + {0xEBD0, 0x3E, 0x01}, + {0xEBD1, 0xB0, 0x01}, + {0xEBD2, 0x0F, 0x01}, + {0xEBD3, 0xF0, 0x01}, + {0xEBD4, 0x03, 0x01}, + {0xEBD5, 0xBD, 0x01}, + {0xEBD6, 0x00, 0x01}, + {0xEBD7, 0x3F, 0x01}, + {0xEBD8, 0xC8, 0x01}, + {0xEBD9, 0x0B, 0x01}, + {0xEBDA, 0xEE, 0x01}, + {0xEBDB, 0x00, 0x01}, + {0xEBDC, 0x3E, 0x01}, + {0xEBDD, 0x80, 0x01}, + {0xEBDE, 0x2F, 0x01}, + {0xEBDF, 0xC8, 0x01}, + {0xEBE0, 0x0B, 0x01}, + {0xEBE1, 0xF2, 0x01}, + {0xEBE2, 0x83, 0x01}, + {0xEBE3, 0xBC, 0x01}, + {0xEBE4, 0xA0, 0x01}, + {0xEBE5, 0x0E, 0x01}, + {0xEBE6, 0xC0, 0x01}, + {0xEBE7, 0x03, 0x01}, + {0xEBE8, 0xF4, 0x01}, + {0xEBE9, 0x81, 0x01}, + {0xEBEA, 0x3D, 0x01}, + {0xEBEB, 0x00, 0x01}, + {0xEBEC, 0x0F, 0x01}, + {0xEBED, 0xC0, 0x01}, + {0xEBEE, 0x0F, 0x01}, + {0xEBEF, 0xEE, 0x01}, + {0xEBF0, 0x83, 0x01}, + {0xEBF1, 0xBB, 0x01}, + {0xEBF2, 0x60, 0x01}, + {0xEBF3, 0x0F, 0x01}, + {0xEBF4, 0xB8, 0x01}, + {0xEBF5, 0xFF, 0x01}, + {0xEBF6, 0xF3, 0x01}, + {0xEBF7, 0xFF, 0x01}, + {0xEBF8, 0x3C, 0x01}, + {0xEBF9, 0x40, 0x01}, + {0xEBFA, 0x0F, 0x01}, + {0xEBFB, 0xC8, 0x01}, + {0xEBFC, 0x03, 0x01}, + {0xEBFD, 0xF2, 0x01}, + {0xEBFE, 0x04, 0x01}, + {0xEBFF, 0x3E, 0x01}, + {0xEC00, 0x81, 0x01}, + {0xEC01, 0x0F, 0x01}, + {0xEC02, 0xD0, 0x01}, + {0xEC03, 0x03, 0x01}, + {0xEC04, 0xF6, 0x01}, + {0xEC05, 0x00, 0x01}, + {0xEC06, 0x3D, 0x01}, + {0xEC07, 0xE0, 0x01}, + {0xEC08, 0xFE, 0x01}, + {0xEC09, 0xD7, 0x01}, + {0xEC0A, 0x03, 0x01}, + {0xEC0B, 0xF4, 0x01}, + {0xEC0C, 0x00, 0x01}, + {0xEC0D, 0x3D, 0x01}, + {0xEC0E, 0xE1, 0x01}, + {0xEC0F, 0x4F, 0x01}, + {0xEC10, 0xF8, 0x01}, + {0xEC11, 0x0F, 0x01}, + {0xEC12, 0xF4, 0x01}, + {0xEC13, 0x80, 0x01}, + {0xEC14, 0xFE, 0x01}, + {0xEC15, 0x9F, 0x01}, + {0xEC16, 0x0F, 0x01}, + {0xEC17, 0xE0, 0x01}, + {0xEC18, 0x03, 0x01}, + {0xEC19, 0xFA, 0x01}, + {0xEC1A, 0x80, 0x01}, + {0xEC1B, 0x3D, 0x01}, + {0xEC1C, 0x60, 0x01}, + {0xEC1D, 0x5F, 0x01}, + {0xEC1E, 0xF0, 0x01}, + {0xEC1F, 0x17, 0x01}, + {0xEC20, 0xFC, 0x01}, + {0xEC21, 0x02, 0x01}, + {0xEC22, 0x41, 0x01}, + {0xEC23, 0xC0, 0x01}, + {0xEC24, 0x1F, 0x01}, + {0xEC25, 0xF8, 0x01}, + {0xEC26, 0x03, 0x01}, + {0xEC27, 0x02, 0x01}, + {0xEC28, 0xFF, 0x01}, + {0xEC29, 0x3F, 0x01}, + {0xEC2A, 0xC0, 0x01}, + {0xEC2B, 0x0F, 0x01}, + {0xEC2C, 0xF0, 0x01}, + {0xEC2D, 0x1F, 0x01}, + {0xEC2E, 0x04, 0x01}, + {0xEC2F, 0x07, 0x01}, + {0xEC30, 0x41, 0x01}, + {0xEC31, 0x61, 0x01}, + {0xEC32, 0x20, 0x01}, + {0xEC33, 0x10, 0x01}, + {0xEC34, 0x04, 0x01}, + {0xEC35, 0x04, 0x01}, + {0xEC36, 0x81, 0x01}, + {0xEC37, 0x3F, 0x01}, + {0xEC38, 0x80, 0x01}, + {0xEC39, 0x20, 0x01}, + {0xEC3A, 0x10, 0x01}, + {0xEC3B, 0x08, 0x01}, + {0xEC3C, 0x04, 0x01}, + {0xEC3D, 0x05, 0x01}, + {0xEC3E, 0x41, 0x01}, + {0xEC3F, 0x41, 0x01}, + {0xEC40, 0x50, 0x01}, + {0xEC41, 0x30, 0x01}, + {0xEC42, 0x10, 0x01}, + {0xEC43, 0x02, 0x01}, + {0xEC44, 0x82, 0x01}, + {0xEC45, 0x81, 0x01}, + {0xEC46, 0xC0, 0x01}, + {0xEC47, 0x20, 0x01}, + {0xEC48, 0x18, 0x01}, + {0xEC49, 0x0C, 0x01}, + {0xEC4A, 0x04, 0x01}, + {0xEC4B, 0x03, 0x01}, + {0xEC4C, 0xC1, 0x01}, + {0xEC4D, 0x21, 0x01}, + {0xEC4E, 0x70, 0x01}, + {0xEC4F, 0x08, 0x01}, + {0xEC50, 0x20, 0x01}, + {0xEC51, 0x02, 0x01}, + {0xEC52, 0x84, 0x01}, + {0xEC53, 0x83, 0x01}, + {0xEC54, 0xC0, 0x01}, + {0xEC55, 0x20, 0x01}, + {0xEC56, 0x20, 0x01}, + {0xEC57, 0x04, 0x01}, + {0xEC58, 0x04, 0x01}, + {0xEC59, 0x02, 0x01}, + {0xEC5A, 0x82, 0x01}, + {0xEC5B, 0x80, 0x01}, + {0xEC5C, 0x50, 0x01}, + {0xEC5D, 0x08, 0x01}, + {0xEC5E, 0x14, 0x01}, + {0xEC5F, 0x02, 0x01}, + {0xEC60, 0x04, 0x01}, + {0xEC61, 0x04, 0x01}, + {0xEC62, 0x41, 0x01}, + {0xEC63, 0x30, 0x01}, + {0xEC64, 0x38, 0x01}, + {0xEC65, 0x04, 0x01}, + {0xEC66, 0x0C, 0x01}, + {0xEC67, 0x02, 0x01}, + {0xEC68, 0x81, 0x01}, + {0xEC69, 0x80, 0x01}, + {0xEC6A, 0x20, 0x01}, + {0xEC6B, 0x20, 0x01}, + {0xEC6C, 0x14, 0x01}, + {0xEC6D, 0x02, 0x01}, + {0xEC6E, 0x85, 0x01}, + {0xEC6F, 0x00, 0x01}, + {0xEC70, 0x01, 0x01}, + {0xEC71, 0x41, 0x01}, + {0xEC72, 0x10, 0x01}, + {0xEC73, 0x0C, 0x01}, + {0xEC74, 0x0E, 0x01}, + {0xEC75, 0x01, 0x01}, + {0xEC76, 0x83, 0x01}, + {0xEC77, 0x40, 0x01}, + {0xEC78, 0x20, 0x01}, + {0xEC79, 0x20, 0x01}, + {0xEC7A, 0x08, 0x01}, + {0xEC7B, 0x08, 0x01}, + + + {0xED02, 0x85, 0x01}, + {0xED03, 0xAA, 0x01}, + {0xED04, 0xD8, 0x01}, + {0xED05, 0x9A, 0x01}, + {0xED06, 0xE6, 0x01}, + {0xED07, 0x65, 0x01}, + {0xED08, 0x25, 0x01}, + {0xED09, 0x6C, 0x01}, + {0xED0A, 0xC9, 0x01}, + {0xED0B, 0xE8, 0x01}, + {0xED0C, 0x56, 0x01}, + {0xED0D, 0x21, 0x01}, + {0xED0E, 0xA2, 0x01}, + {0xED0F, 0x54, 0x01}, + {0xED10, 0x88, 0x01}, + {0xED11, 0x2C, 0x01}, + {0xED12, 0x45, 0x01}, + {0xED13, 0x23, 0x01}, + {0xED14, 0x5A, 0x01}, + {0xED15, 0x41, 0x01}, + {0xED16, 0xA9, 0x01}, + {0xED17, 0x59, 0x01}, + {0xED18, 0x67, 0x01}, + {0xED19, 0xCA, 0x01}, + {0xED1A, 0x96, 0x01}, + {0xED1B, 0x93, 0x01}, + {0xED1C, 0x76, 0x01}, + {0xED1D, 0x35, 0x01}, + {0xED1E, 0xA1, 0x01}, + {0xED1F, 0x38, 0x01}, + {0xED20, 0x89, 0x01}, + {0xED21, 0x67, 0x01}, + {0xED22, 0x46, 0x01}, + {0xED23, 0xC1, 0x01}, + {0xED24, 0x71, 0x01}, + {0xED25, 0x10, 0x01}, + {0xED26, 0x6C, 0x01}, + {0xED27, 0xEC, 0x01}, + {0xED28, 0x13, 0x01}, + {0xED29, 0x9B, 0x01}, + {0xED2A, 0xFC, 0x01}, + {0xED2B, 0x10, 0x01}, + {0xED2C, 0x87, 0x01}, + {0xED2D, 0x42, 0x01}, + {0xED2E, 0xE9, 0x01}, + {0xED2F, 0x29, 0x01}, + {0xED30, 0x92, 0x01}, + {0xED31, 0x86, 0x01}, + {0xED32, 0xFC, 0x01}, + {0xED33, 0x74, 0x01}, + {0xED34, 0x21, 0x01}, + {0xED35, 0x39, 0x01}, + {0xED36, 0x31, 0x01}, + {0xED37, 0xE7, 0x01}, + {0xED38, 0x41, 0x01}, + {0xED39, 0x9D, 0x01}, + {0xED3A, 0x89, 0x01}, + {0xED3B, 0xCE, 0x01}, + {0xED3C, 0x5F, 0x01}, + {0xED3D, 0x58, 0x01}, + {0xED3E, 0x03, 0x01}, + {0xED3F, 0x17, 0x01}, + {0xED40, 0xCD, 0x01}, + {0xED41, 0xCC, 0x01}, + {0xED42, 0xC5, 0x01}, + {0xED43, 0x33, 0x01}, + {0xED44, 0x85, 0x01}, + {0xED45, 0xD1, 0x01}, + {0xED46, 0x0D, 0x01}, + {0xED47, 0x69, 0x01}, + {0xED48, 0xD4, 0x01}, + {0xED49, 0x53, 0x01}, + {0xED4A, 0x1D, 0x01}, + {0xED4B, 0x18, 0x01}, + {0xED4C, 0x7D, 0x01}, + {0xED4D, 0x07, 0x01}, + {0xED4E, 0x45, 0x01}, + {0xED4F, 0x9D, 0x01}, + {0xED50, 0x69, 0x01}, + {0xED51, 0x4E, 0x01}, + {0xED52, 0x5B, 0x01}, + {0xED53, 0x16, 0x01}, + {0xED54, 0x83, 0x01}, + {0xED55, 0x94, 0x01}, + {0xED56, 0xAE, 0x01}, + {0xED57, 0xE0, 0x01}, + {0xED58, 0x24, 0x01}, + {0xED59, 0x29, 0x01}, + {0xED5A, 0x3C, 0x01}, + {0xED5B, 0x79, 0x01}, + {0xED5C, 0x8A, 0x01}, + {0xED5D, 0x54, 0x01}, + {0xED5E, 0xE0, 0x01}, + {0xED5F, 0x72, 0x01}, + {0xED60, 0x17, 0x01}, + {0xED61, 0xD3, 0x01}, + {0xED62, 0x90, 0x01}, + {0xED63, 0x06, 0x01}, + {0xED64, 0x3D, 0x01}, + {0xED65, 0xC1, 0x01}, + {0xED66, 0xD1, 0x01}, + {0xED67, 0x0F, 0x01}, + {0xED68, 0x5F, 0x01}, + {0xED69, 0x3C, 0x01}, + {0xED6A, 0x53, 0x01}, + {0xED6B, 0x14, 0x01}, + {0xED6C, 0xAB, 0x01}, + {0xED6D, 0x84, 0x01}, + {0xED6E, 0x24, 0x01}, + {0xED6F, 0x25, 0x01}, + {0xED70, 0x11, 0x01}, + {0xED71, 0xB1, 0x01}, + {0xED72, 0x08, 0x01}, + {0xED73, 0x45, 0x01}, + {0xED74, 0x34, 0x01}, + {0xED75, 0xB2, 0x01}, + {0xED76, 0x92, 0x01}, + {0xED77, 0x9C, 0x01}, + {0xED78, 0x5C, 0x01}, + {0xED79, 0x65, 0x01}, + {0xED7A, 0x2E, 0x01}, + {0xED7B, 0x8E, 0x01}, + {0xED7C, 0x09, 0x01}, + {0xED7D, 0x8E, 0x01}, + {0xED7E, 0x6C, 0x01}, + {0xED7F, 0xC6, 0x01}, + {0xED80, 0x93, 0x01}, + {0xED81, 0x96, 0x01}, + {0xED82, 0xC1, 0x01}, + {0xED83, 0xC4, 0x01}, + {0xED84, 0x64, 0x01}, + {0xED85, 0x27, 0x01}, + {0xED86, 0x0E, 0x01}, + {0xED87, 0x89, 0x01}, + {0xED88, 0x08, 0x01}, + {0xED89, 0x40, 0x01}, + {0xED8A, 0x02, 0x01}, + {0xED8B, 0x22, 0x01}, + {0xED8C, 0x10, 0x01}, + {0xED8D, 0x82, 0x01}, + {0xED8E, 0x64, 0x01}, + {0xED8F, 0x24, 0x01}, + {0xED90, 0x24, 0x01}, + {0xED91, 0x44, 0x01}, + {0xED92, 0xD1, 0x01}, + {0xED93, 0x0A, 0x01}, + {0xED94, 0x60, 0x01}, + {0xED95, 0x58, 0x01}, + {0xED96, 0x53, 0x01}, + {0xED97, 0x1B, 0x01}, + {0xED98, 0xF2, 0x01}, + {0xED99, 0xA8, 0x01}, + {0xED9A, 0x65, 0x01}, + {0xED9B, 0x30, 0x01}, + {0xED9C, 0x32, 0x01}, + {0xED9D, 0xD9, 0x01}, + {0xED9E, 0x89, 0x01}, + {0xED9F, 0x43, 0x01}, + {0xEDA0, 0x20, 0x01}, + {0xEDA1, 0x12, 0x01}, + {0xEDA2, 0x10, 0x01}, + {0xEDA3, 0x80, 0x01}, + {0xEDA4, 0x10, 0x01}, + {0xEDA5, 0x84, 0x01}, + {0xEDA6, 0x20, 0x01}, + {0xEDA7, 0x19, 0x01}, + {0xEDA8, 0x01, 0x01}, + {0xEDA9, 0x49, 0x01}, + {0xEDAA, 0x51, 0x01}, + {0xEDAB, 0xB2, 0x01}, + {0xEDAC, 0x12, 0x01}, + {0xEDAD, 0x98, 0x01}, + {0xEDAE, 0xD5, 0x01}, + {0xEDAF, 0xFC, 0x01}, + {0xEDB0, 0x46, 0x01}, + {0xEDB1, 0x3E, 0x01}, + {0xEDB2, 0x7C, 0x01}, + {0xEDB3, 0xC9, 0x01}, + {0xEDB4, 0xCC, 0x01}, + {0xEDB5, 0x51, 0x01}, + {0xEDB6, 0xAC, 0x01}, + {0xEDB7, 0x32, 0x01}, + {0xEDB8, 0x12, 0x01}, + {0xEDB9, 0x93, 0x01}, + {0xEDBA, 0x4C, 0x01}, + {0xEDBB, 0x84, 0x01}, + {0xEDBC, 0x22, 0x01}, + {0xEDBD, 0x17, 0x01}, + {0xEDBE, 0xD9, 0x01}, + {0xEDBF, 0xC8, 0x01}, + {0xEDC0, 0x4B, 0x01}, + {0xEDC1, 0x74, 0x01}, + {0xEDC2, 0xA2, 0x01}, + {0xEDC3, 0x95, 0x01}, + {0xEDC4, 0xB9, 0x01}, + {0xEDC5, 0x48, 0x01}, + {0xEDC6, 0x06, 0x01}, + {0xEDC7, 0x38, 0x01}, + {0xEDC8, 0xDC, 0x01}, + {0xEDC9, 0xC9, 0x01}, + {0xEDCA, 0xD0, 0x01}, + {0xEDCB, 0x66, 0x01}, + {0xEDCC, 0x86, 0x01}, + {0xEDCD, 0xD3, 0x01}, + {0xEDCE, 0x96, 0x01}, + {0xEDCF, 0xC3, 0x01}, + {0xEDD0, 0x28, 0x01}, + {0xEDD1, 0x45, 0x01}, + {0xEDD2, 0x2B, 0x01}, + {0xEDD3, 0x39, 0x01}, + {0xEDD4, 0x31, 0x01}, + {0xEDD5, 0xCA, 0x01}, + {0xEDD6, 0x4F, 0x01}, + {0xEDD7, 0x9C, 0x01}, + {0xEDD8, 0x62, 0x01}, + {0xEDD9, 0x15, 0x01}, + {0xEDDA, 0xB6, 0x01}, + {0xEDDB, 0xF4, 0x01}, + {0xEDDC, 0x45, 0x01}, + {0xEDDD, 0x34, 0x01}, + {0xEDDE, 0xAD, 0x01}, + {0xEDDF, 0x29, 0x01}, + {0xEDE0, 0x4F, 0x01}, + {0xEDE1, 0x84, 0x01}, + {0xEDE2, 0xC4, 0x01}, + {0xEDE3, 0x84, 0x01}, + {0xEDE4, 0x9C, 0x01}, + {0xEDE5, 0x01, 0x01}, + {0xEDE6, 0x6D, 0x01}, + {0xEDE7, 0x06, 0x01}, + {0xEDE8, 0x39, 0x01}, + {0xEDE9, 0x7F, 0x01}, + {0xEDEA, 0x11, 0x01}, + {0xEDEB, 0x0D, 0x01}, + {0xEDEC, 0x5C, 0x01}, + {0xEDED, 0x26, 0x01}, + {0xEDEE, 0x53, 0x01}, + {0xEDEF, 0x17, 0x01}, + {0xEDF0, 0xCE, 0x01}, + {0xEDF1, 0x20, 0x01}, + {0xEDF2, 0xC6, 0x01}, + {0xEDF3, 0x36, 0x01}, + {0xEDF4, 0xA8, 0x01}, + {0xEDF5, 0x11, 0x01}, + {0xEDF6, 0x0F, 0x01}, + {0xEDF7, 0x76, 0x01}, + {0xEDF8, 0x44, 0x01}, + {0xEDF9, 0x34, 0x01}, + {0xEDFA, 0x24, 0x01}, + {0xEDFB, 0x53, 0x01}, + {0xEDFC, 0x15, 0x01}, + {0xEDFD, 0x08, 0x01}, + {0xEDFE, 0x4B, 0x01}, + {0xEDFF, 0xD5, 0x01}, + {0xEE00, 0xC9, 0x01}, + {0xEE01, 0x90, 0x01}, + {0xEE02, 0x6D, 0x01}, + {0xEE03, 0xEA, 0x01}, + {0xEE04, 0x93, 0x01}, + {0xEE05, 0x1A, 0x01}, + {0xEE06, 0xF3, 0x01}, + {0xEE07, 0xB8, 0x01}, + {0xEE08, 0xC6, 0x01}, + {0xEE09, 0x3D, 0x01}, + {0xEE0A, 0xC0, 0x01}, + {0xEE0B, 0x19, 0x01}, + {0xEE0C, 0xD0, 0x01}, + {0xEE0D, 0x78, 0x01}, + {0xEE0E, 0x64, 0x01}, + {0xEE0F, 0x24, 0x01}, + {0xEE10, 0xA1, 0x01}, + {0xEE11, 0x37, 0x01}, + {0xEE12, 0xD1, 0x01}, + {0xEE13, 0x89, 0x01}, + {0xEE14, 0x5A, 0x01}, + {0xEE15, 0x51, 0x01}, + {0xEE16, 0x72, 0x01}, + {0xEE17, 0xD5, 0x01}, + {0xEE18, 0x8C, 0x01}, + {0xEE19, 0x14, 0x01}, + {0xEE1A, 0x05, 0x01}, + {0xEE1B, 0xA1, 0x01}, + {0xEE1C, 0x33, 0x01}, + {0xEE1D, 0xF9, 0x01}, + {0xEE1E, 0xE7, 0x01}, + {0xEE1F, 0x4A, 0x01}, + {0xEE20, 0x01, 0x01}, + {0xEE21, 0xCA, 0x01}, + {0xEE22, 0xD2, 0x01}, + {0xEE23, 0x86, 0x01}, + {0xEE24, 0xE4, 0x01}, + {0xEE25, 0x94, 0x01}, + {0xEE26, 0x23, 0x01}, + {0xEE27, 0x4A, 0x01}, + {0xEE28, 0x55, 0x01}, + {0xEE29, 0x29, 0x01}, + {0xEE2A, 0x57, 0x01}, + {0xEE2B, 0x74, 0x01}, + {0xEE2C, 0x6A, 0x01}, + {0xEE2D, 0x14, 0x01}, + {0xEE2E, 0x95, 0x01}, + {0xEE2F, 0xEA, 0x01}, + {0xEE30, 0x94, 0x01}, + {0xEE31, 0xA3, 0x01}, + {0xEE32, 0x2C, 0x01}, + {0xEE33, 0x75, 0x01}, + {0xEE34, 0x28, 0x01}, + {0xEE35, 0x47, 0x01}, + {0xEE36, 0x0F, 0x01}, + {0xEE37, 0x2A, 0x01}, + {0xEE38, 0xD1, 0x01}, + {0xEE39, 0x84, 0x01}, + {0xEE3A, 0x4E, 0x01}, + {0xEE3B, 0x44, 0x01}, + {0xEE3C, 0x22, 0x01}, + {0xEE3D, 0x1E, 0x01}, + {0xEE3E, 0xE1, 0x01}, + {0xEE3F, 0x28, 0x01}, + {0xEE40, 0x4B, 0x01}, + {0xEE41, 0x4D, 0x01}, + {0xEE42, 0xC2, 0x01}, + {0xEE43, 0x53, 0x01}, + {0xEE44, 0x8D, 0x01}, + {0xEE45, 0xA4, 0x01}, + {0xEE46, 0xC4, 0x01}, + {0xEE47, 0x9F, 0x01}, + {0xEE48, 0x0B, 0x01}, + {0xEE49, 0x49, 0x01}, + {0xEE4A, 0xE7, 0x01}, + {0xEE4B, 0x3C, 0x01}, + {0xEE4C, 0xB5, 0x01}, + {0xEE4D, 0x29, 0x01}, + {0xEE4E, 0x8E, 0x01}, + {0xEE4F, 0x69, 0x01}, + {0xEE50, 0x6A, 0x01}, + {0xEE51, 0x93, 0x01}, + {0xEE52, 0x1A, 0x01}, + {0xEE53, 0xDC, 0x01}, + {0xEE54, 0xE0, 0x01}, + {0xEE55, 0x66, 0x01}, + {0xEE56, 0x39, 0x01}, + {0xEE57, 0xD7, 0x01}, + {0xEE58, 0x91, 0x01}, + {0xEE59, 0x8F, 0x01}, + {0xEE5A, 0x80, 0x01}, + {0xEE5B, 0x46, 0x01}, + {0xEE5C, 0xB4, 0x01}, + {0xEE5D, 0x1F, 0x01}, + {0xEE5E, 0x0C, 0x01}, + {0xEE5F, 0xE5, 0x01}, + {0xEE60, 0xC6, 0x01}, + {0xEE61, 0x39, 0x01}, + {0xEE62, 0x92, 0x01}, + {0xEE63, 0x01, 0x01}, + {0xEE64, 0x0D, 0x01}, + {0xEE65, 0x5E, 0x01}, + {0xEE66, 0x04, 0x01}, + {0xEE67, 0xB3, 0x01}, + {0xEE68, 0x16, 0x01}, + {0xEE69, 0xBA, 0x01}, + {0xEE6A, 0xB8, 0x01}, + {0xEE6B, 0x05, 0x01}, + {0xEE6C, 0x2F, 0x01}, + {0xEE6D, 0x7D, 0x01}, + {0xEE6E, 0x51, 0x01}, + {0xEE6F, 0xCC, 0x01}, + {0xEE70, 0x65, 0x01}, + {0xEE71, 0x52, 0x01}, + {0xEE72, 0x23, 0x01}, + {0xEE73, 0x9C, 0x01}, + {0xEE74, 0xED, 0x01}, + {0xEE75, 0x14, 0x01}, + {0xEE76, 0x67, 0x01}, + {0xEE77, 0x3B, 0x01}, + {0xEE78, 0x8D, 0x01}, + {0xEE79, 0xE1, 0x01}, + {0xEE7A, 0x0C, 0x01}, + {0xEE7B, 0x59, 0x01}, + {0xEE7C, 0xDE, 0x01}, + {0xEE7D, 0x42, 0x01}, + {0xEE7E, 0x94, 0x01}, + {0xEE7F, 0xA5, 0x01}, + {0xEE80, 0xDC, 0x01}, + {0xEE81, 0x64, 0x01}, + {0xEE82, 0x27, 0x01}, + {0xEE83, 0x3A, 0x01}, + {0xEE84, 0xF9, 0x01}, + {0xEE85, 0x89, 0x01}, + {0xEE86, 0x53, 0x01}, + {0xEE87, 0xAC, 0x01}, + {0xEE88, 0xE2, 0x01}, + {0xEE89, 0x96, 0x01}, + {0xEE8A, 0xBD, 0x01}, + {0xEE8B, 0x54, 0x01}, + {0xEE8C, 0xE6, 0x01}, + {0xEE8D, 0x34, 0x01}, + {0xEE8E, 0xAA, 0x01}, + {0xEE8F, 0xE1, 0x01}, + {0xEE90, 0x0D, 0x01}, + {0xEE91, 0x5C, 0x01}, + {0xEE92, 0xF8, 0x01}, + {0xEE93, 0xF2, 0x01}, + {0xEE94, 0x93, 0x01}, + {0xEE95, 0xA3, 0x01}, + {0xEE96, 0x78, 0x01}, + {0xEE97, 0x64, 0x01}, + {0xEE98, 0x24, 0x01}, + {0xEE99, 0x12, 0x01}, + {0xEE9A, 0x99, 0x01}, + {0xEE9B, 0x88, 0x01}, + {0xEE9C, 0x45, 0x01}, + {0xEE9D, 0x2C, 0x01}, + {0xEE9E, 0xA2, 0x01}, + {0xEE9F, 0x92, 0x01}, + {0xEEA0, 0x96, 0x01}, + {0xEEA1, 0x3C, 0x01}, + {0xEEA2, 0x05, 0x01}, + {0xEEA3, 0x2B, 0x01}, + {0xEEA4, 0x7F, 0x01}, + {0xEEA5, 0x79, 0x01}, + {0xEEA6, 0x8C, 0x01}, + {0xEEA7, 0x67, 0x01}, + {0xEEA8, 0x5E, 0x01}, + {0xEEA9, 0xF3, 0x01}, + {0xEEAA, 0x95, 0x01}, + {0xEEAB, 0xB4, 0x01}, + {0xEEAC, 0xB4, 0x01}, + {0xEEAD, 0x44, 0x01}, + {0xEEAE, 0x26, 0x01}, + {0xEEAF, 0x0C, 0x01}, + {0xEEB0, 0x79, 0x01}, + {0xEEB1, 0x08, 0x01}, + {0xEEB2, 0x40, 0x01}, + {0xEEB3, 0x02, 0x01}, + {0xEEB4, 0x42, 0x01}, + {0xEEB5, 0x90, 0x01}, + {0xEEB6, 0x81, 0x01}, + {0xEEB7, 0x60, 0x01}, + {0xEEB8, 0x24, 0x01}, + {0xEEB9, 0x23, 0x01}, + {0xEEBA, 0x3E, 0x01}, + {0xEEBB, 0x21, 0x01}, + {0xEEBC, 0x4A, 0x01}, + {0xEEBD, 0x5C, 0x01}, + {0xEEBE, 0xFE, 0x01}, + {0xEEBF, 0xE2, 0x01}, + {0xEEC0, 0x99, 0x01}, + {0xEEC1, 0xD5, 0x01}, + {0xEEC2, 0x7C, 0x01}, + {0xEEC3, 0xC5, 0x01}, + {0xEEC4, 0x2C, 0x01}, + {0xEEC5, 0x2B, 0x01}, + {0xEEC6, 0x89, 0x01}, + {0xEEC7, 0x09, 0x01}, + {0xEEC8, 0x43, 0x01}, + {0xEEC9, 0x1C, 0x01}, + {0xEECA, 0x02, 0x01}, + {0xEECB, 0x10, 0x01}, + {0xEECC, 0x80, 0x01}, + {0xEECD, 0x0C, 0x01}, + {0xEECE, 0x64, 0x01}, + {0xEECF, 0x20, 0x01}, + {0xEED0, 0x16, 0x01}, + {0xEED1, 0xC9, 0x01}, + {0xEED2, 0x08, 0x01}, + {0xEED3, 0x4F, 0x01}, + {0xEED4, 0x88, 0x01}, + {0xEED5, 0xE2, 0x01}, + {0xEED6, 0x96, 0x01}, + {0xEED7, 0xBF, 0x01}, + {0xEED8, 0xAC, 0x01}, + {0xEED9, 0xC6, 0x01}, + {0xEEDA, 0x36, 0x01}, + {0xEEDB, 0x70, 0x01}, + {0xEEDC, 0xB1, 0x01}, + {0xEEDD, 0xCB, 0x01}, + {0xEEDE, 0x4F, 0x01}, + {0xEEDF, 0x86, 0x01}, + {0xEEE0, 0xD2, 0x01}, + {0xEEE1, 0x11, 0x01}, + {0xEEE2, 0x90, 0x01}, + {0xEEE3, 0x3C, 0x01}, + {0xEEE4, 0x04, 0x01}, + {0xEEE5, 0x22, 0x01}, + {0xEEE6, 0x13, 0x01}, + {0xEEE7, 0xA1, 0x01}, + {0xEEE8, 0xC8, 0x01}, + {0xEEE9, 0x49, 0x01}, + {0xEEEA, 0x58, 0x01}, + {0xEEEB, 0xC2, 0x01}, + {0xEEEC, 0x94, 0x01}, + {0xEEED, 0xAB, 0x01}, + {0xEEEE, 0xE8, 0x01}, + {0xEEEF, 0xE5, 0x01}, + {0xEEF0, 0x31, 0x01}, + {0xEEF1, 0xC5, 0x01}, + {0xEEF2, 0x89, 0x01}, + {0xEEF3, 0x0E, 0x01}, + {0xEEF4, 0x63, 0x01}, + {0xEEF5, 0x26, 0x01}, + {0xEEF6, 0x33, 0x01}, + {0xEEF7, 0x96, 0x01}, + {0xEEF8, 0xB3, 0x01}, + {0xEEF9, 0x0C, 0x01}, + {0xEEFA, 0xA5, 0x01}, + {0xEEFB, 0x28, 0x01}, + {0xEEFC, 0x33, 0x01}, + {0xEEFD, 0xB1, 0x01}, + {0xEEFE, 0xC9, 0x01}, + {0xEEFF, 0x4D, 0x01}, + {0xEF00, 0x76, 0x01}, + {0xEF01, 0x92, 0x01}, + {0xEF02, 0x94, 0x01}, + {0xEF03, 0xA9, 0x01}, + {0xEF04, 0xA8, 0x01}, + {0xEF05, 0x25, 0x01}, + {0xEF06, 0x2F, 0x01}, + {0xEF07, 0x8E, 0x01}, + {0xEF08, 0x49, 0x01}, + {0xEF09, 0xCD, 0x01}, + {0xEF0A, 0x7E, 0x01}, + {0xEF0B, 0x06, 0x01}, + {0xEF0C, 0x94, 0x01}, + {0xEF0D, 0x9B, 0x01}, + {0xEF0E, 0xDF, 0x01}, + {0xEF0F, 0x44, 0x01}, + {0xEF10, 0xA6, 0x01}, + {0xEF11, 0x32, 0x01}, + {0xEF12, 0x75, 0x01}, + {0xEF13, 0xD9, 0x01}, + {0xEF14, 0xCB, 0x01}, + {0xEF15, 0x59, 0x01}, + {0xEF16, 0xDC, 0x01}, + {0xEF17, 0x82, 0x01}, + {0xEF18, 0x96, 0x01}, + {0xEF19, 0xB9, 0x01}, + {0xEF1A, 0xD4, 0x01}, + {0xEF1B, 0xC5, 0x01}, + {0xEF1C, 0x30, 0x01}, + {0xEF1D, 0x8E, 0x01}, + {0xEF1E, 0x41, 0x01}, + {0xEF1F, 0xCD, 0x01}, + {0xEF20, 0x6C, 0x01}, + {0xEF21, 0xAE, 0x01}, + {0xEF22, 0xD3, 0x01}, + {0xEF23, 0x22, 0x01}, + {0xEF24, 0x1C, 0x01}, + {0xEF25, 0xD5, 0x01}, + {0xEF26, 0x07, 0x01}, + {0xEF27, 0x40, 0x01}, + {0xEF28, 0xC7, 0x01}, + {0xEF29, 0x99, 0x01}, + {0xEF2A, 0xCE, 0x01}, + {0xEF2B, 0x6A, 0x01}, + {0xEF2C, 0x6A, 0x01}, + {0xEF2D, 0xC3, 0x01}, + {0xEF2E, 0x19, 0x01}, + {0xEF2F, 0xD5, 0x01}, + {0xEF30, 0x6C, 0x01}, + {0xEF31, 0xC6, 0x01}, + {0xEF32, 0x35, 0x01}, + {0xEF33, 0xA9, 0x01}, + {0xEF34, 0x09, 0x01}, + {0xEF35, 0x4E, 0x01}, + {0xEF36, 0x71, 0x01}, + {0xEF37, 0xCA, 0x01}, + {0xEF38, 0xC3, 0x01}, + {0xEF39, 0x1E, 0x01}, + {0xEF3A, 0x0A, 0x01}, + {0xEF3B, 0x55, 0x01}, + {0xEF3C, 0x09, 0x01}, + {0xEF3D, 0x4D, 0x01}, + {0xEF3E, 0x39, 0x01}, + {0xEF3F, 0x8A, 0x01}, + {0xEF40, 0x52, 0x01}, + {0xEF41, 0x86, 0x01}, + {0xEF42, 0x6E, 0x01}, + {0xEF43, 0xD4, 0x01}, + {0xEF44, 0x1F, 0x01}, + {0xEF45, 0x09, 0x01}, + {0xEF46, 0xA1, 0x01}, + {0xEF47, 0x87, 0x01}, + {0xEF48, 0x40, 0x01}, + {0xEF49, 0xE5, 0x01}, + {0xEF4A, 0x39, 0x01}, + {0xEF4B, 0x10, 0x01}, + {0xEF4C, 0x7E, 0x01}, + {0xEF4D, 0x40, 0x01}, + {0xEF4E, 0x14, 0x01}, + {0xEF4F, 0x21, 0x01}, + {0xEF50, 0x1F, 0x01}, + {0xEF51, 0x81, 0x01}, + {0xEF52, 0x08, 0x01}, + {0xEF53, 0x4B, 0x01}, + + + {0xEF54, 0xC7, 0x01}, + {0xEF55, 0x82, 0x01}, + {0xEF56, 0x55, 0x01}, + {0xEF57, 0xA6, 0x01}, + {0xEF58, 0xEE, 0x01}, + {0xEF59, 0xA4, 0x01}, + {0xEF5A, 0x25, 0x01}, + {0xEF5B, 0x2F, 0x01}, + {0xEF5C, 0xD5, 0x01}, + {0xEF5D, 0x09, 0x01}, + {0xEF5E, 0x52, 0x01}, + {0xEF5F, 0x96, 0x01}, + {0xEF60, 0x02, 0x01}, + {0xEF61, 0x94, 0x01}, + {0xEF62, 0x8F, 0x01}, + {0xEF63, 0x0C, 0x01}, + {0xEF64, 0x34, 0x01}, + {0xEF65, 0x1E, 0x01}, + {0xEF66, 0xE7, 0x01}, + {0xEF67, 0x40, 0x01}, + {0xEF68, 0xE7, 0x01}, + {0xEF69, 0x3C, 0x01}, + {0xEF6A, 0x14, 0x01}, + {0xEF6B, 0x4A, 0x01}, + {0xEF6C, 0x92, 0x01}, + {0xEF6D, 0x90, 0x01}, + {0xEF6E, 0xD0, 0x01}, + {0xEF6F, 0x13, 0x01}, + {0xEF70, 0x1B, 0x01}, + {0xEF71, 0xC7, 0x01}, + {0xEF72, 0xF8, 0x01}, + {0xEF73, 0x25, 0x01}, + {0xEF74, 0x30, 0x01}, + {0xEF75, 0x98, 0x01}, + {0xEF76, 0x19, 0x01}, + {0xEF77, 0x4E, 0x01}, + {0xEF78, 0x81, 0x01}, + {0xEF79, 0x02, 0x01}, + {0xEF7A, 0xE4, 0x01}, + {0xEF7B, 0x1A, 0x01}, + {0xEF7C, 0xBA, 0x01}, + {0xEF7D, 0x30, 0x01}, + {0xEF7E, 0x45, 0x01}, + {0xEF7F, 0x27, 0x01}, + {0xEF80, 0x3F, 0x01}, + {0xEF81, 0xD1, 0x01}, + {0xEF82, 0x4A, 0x01}, + {0xEF83, 0x62, 0x01}, + {0xEF84, 0x88, 0x01}, + {0xEF85, 0xA3, 0x01}, + {0xEF86, 0x1D, 0x01}, + {0xEF87, 0xC3, 0x01}, + {0xEF88, 0x20, 0x01}, + {0xEF89, 0x25, 0x01}, + {0xEF8A, 0x24, 0x01}, + {0xEF8B, 0x10, 0x01}, + {0xEF8C, 0x99, 0x01}, + {0xEF8D, 0x48, 0x01}, + {0xEF8E, 0x4B, 0x01}, + {0xEF8F, 0xBE, 0x01}, + {0xEF90, 0x42, 0x01}, + {0xEF91, 0x1A, 0x01}, + {0xEF92, 0xE4, 0x01}, + {0xEF93, 0xC4, 0x01}, + {0xEF94, 0x45, 0x01}, + {0xEF95, 0x26, 0x01}, + {0xEF96, 0x0E, 0x01}, + {0xEF97, 0x01, 0x01}, + {0xEF98, 0x88, 0x01}, + {0xEF99, 0x40, 0x01}, + {0xEF9A, 0x34, 0x01}, + {0xEF9B, 0xB2, 0x01}, + {0xEF9C, 0x94, 0x01}, + {0xEF9D, 0xC9, 0x01}, + {0xEF9E, 0x24, 0x01}, + {0xEF9F, 0x47, 0x01}, + {0xEFA0, 0x2E, 0x01}, + {0xEFA1, 0x33, 0x01}, + {0xEFA2, 0x71, 0x01}, + {0xEFA3, 0x08, 0x01}, + {0xEFA4, 0x40, 0x01}, + {0xEFA5, 0x08, 0x01}, + {0xEFA6, 0xB2, 0x01}, + {0xEFA7, 0x11, 0x01}, + {0xEFA8, 0xA6, 0x01}, + {0xEFA9, 0x50, 0x01}, + {0xEFAA, 0x26, 0x01}, + {0xEFAB, 0x3B, 0x01}, + {0xEFAC, 0x86, 0x01}, + {0xEFAD, 0x51, 0x01}, + {0xEFAE, 0x8A, 0x01}, + {0xEFAF, 0x48, 0x01}, + {0xEFB0, 0x24, 0x01}, + {0xEFB1, 0x82, 0x01}, + {0xEFB2, 0x91, 0x01}, + {0xEFB3, 0x98, 0x01}, + {0xEFB4, 0x8C, 0x01}, + {0xEFB5, 0x25, 0x01}, + {0xEFB6, 0x35, 0x01}, + {0xEFB7, 0xFF, 0x01}, + {0xEFB8, 0x71, 0x01}, + {0xEFB9, 0x8D, 0x01}, + {0xEFBA, 0x5D, 0x01}, + {0xEFBB, 0x9E, 0x01}, + {0xEFBC, 0xE2, 0x01}, + {0xEFBD, 0x13, 0x01}, + {0xEFBE, 0xA2, 0x01}, + {0xEFBF, 0x7C, 0x01}, + {0xEFC0, 0xC5, 0x01}, + {0xEFC1, 0x31, 0x01}, + {0xEFC2, 0xCB, 0x01}, + {0xEFC3, 0x09, 0x01}, + {0xEFC4, 0x52, 0x01}, + {0xEFC5, 0x7A, 0x01}, + {0xEFC6, 0x62, 0x01}, + {0xEFC7, 0xF3, 0x01}, + {0xEFC8, 0x98, 0x01}, + {0xEFC9, 0xC0, 0x01}, + {0xEFCA, 0x24, 0x01}, + {0xEFCB, 0x06, 0x01}, + {0xEFCC, 0x34, 0x01}, + {0xEFCD, 0xCA, 0x01}, + {0xEFCE, 0x29, 0x01}, + {0xEFCF, 0x10, 0x01}, + {0xEFD0, 0xA0, 0x01}, + {0xEFD1, 0x72, 0x01}, + {0xEFD2, 0xE4, 0x01}, + {0xEFD3, 0x1F, 0x01}, + {0xEFD4, 0xEE, 0x01}, + {0xEFD5, 0x38, 0x01}, + {0xEFD6, 0xA7, 0x01}, + {0xEFD7, 0x3A, 0x01}, + {0xEFD8, 0xEA, 0x01}, + {0xEFD9, 0xB1, 0x01}, + {0xEFDA, 0xD0, 0x01}, + {0xEFDB, 0x93, 0x01}, + {0xEFDC, 0x56, 0x01}, + {0xEFDD, 0x95, 0x01}, + {0xEFDE, 0x28, 0x01}, + {0xEFDF, 0x33, 0x01}, + {0xEFE0, 0x25, 0x01}, + {0xEFE1, 0xE9, 0x01}, + {0xEFE2, 0x46, 0x01}, + {0xEFE3, 0x3A, 0x01}, + {0xEFE4, 0x8A, 0x01}, + {0xEFE5, 0x52, 0x01}, + {0xEFE6, 0x9D, 0x01}, + {0xEFE7, 0x24, 0x01}, + {0xEFE8, 0x05, 0x01}, + {0xEFE9, 0x00, 0x01}, + {0xEFEA, 0x00, 0x01}, + {0xEFEB, 0x00, 0x01}, + {0xEFEC, 0x00, 0x01}, + {0xEFED, 0x00, 0x01}, + + /*SHD3 D65+TL84 C01*/ + {0xED00, 0x9191, 0x02}, + {0xEFEE, 0x22, 0x01}, + {0xEFEF, 0xBA, 0x01}, + {0xEFF0, 0xD1, 0x01}, + {0xEFF1, 0x8C, 0x01}, + {0xEFF2, 0x50, 0x01}, + {0xEFF3, 0xA4, 0x01}, + {0xEFF4, 0x22, 0x01}, + {0xEFF5, 0x17, 0x01}, + {0xEFF6, 0xE9, 0x01}, + {0xEFF7, 0x88, 0x01}, + {0xEFF8, 0x47, 0x01}, + {0xEFF9, 0x29, 0x01}, + {0xEFFA, 0xBA, 0x01}, + {0xEFFB, 0x50, 0x01}, + {0xEFFC, 0x80, 0x01}, + {0xEFFD, 0xD0, 0x01}, + {0xEFFE, 0x73, 0x01}, + {0xEFFF, 0x1D, 0x01}, + {0xF000, 0xE9, 0x01}, + {0xF001, 0x6C, 0x01}, + {0xF002, 0x87, 0x01}, + {0xF003, 0x3D, 0x01}, + {0xF004, 0x05, 0x01}, + {0xF005, 0xE2, 0x01}, + {0xF006, 0xD0, 0x01}, + {0xF007, 0x7D, 0x01}, + {0xF008, 0xA2, 0x01}, + {0xF009, 0xF3, 0x01}, + {0xF00A, 0x9A, 0x01}, + {0xF00B, 0xC9, 0x01}, + {0xF00C, 0x2C, 0x01}, + {0xF00D, 0xA6, 0x01}, + {0xF00E, 0x32, 0x01}, + {0xF00F, 0xAF, 0x01}, + {0xF010, 0xB1, 0x01}, + {0xF011, 0x0E, 0x01}, + {0xF012, 0x82, 0x01}, + {0xF013, 0xAE, 0x01}, + {0xF014, 0x33, 0x01}, + {0xF015, 0x1A, 0x01}, + {0xF016, 0xB9, 0x01}, + {0xF017, 0x48, 0x01}, + {0xF018, 0x25, 0x01}, + {0xF019, 0x29, 0x01}, + {0xF01A, 0x54, 0x01}, + {0xF01B, 0xA9, 0x01}, + {0xF01C, 0x0B, 0x01}, + {0xF01D, 0x6B, 0x01}, + {0xF01E, 0xD0, 0x01}, + {0xF01F, 0xE3, 0x01}, + {0xF020, 0x9B, 0x01}, + {0xF021, 0xBE, 0x01}, + {0xF022, 0x18, 0x01}, + {0xF023, 0x85, 0x01}, + {0xF024, 0x24, 0x01}, + {0xF025, 0x19, 0x01}, + {0xF026, 0x29, 0x01}, + {0xF027, 0xC9, 0x01}, + {0xF028, 0x52, 0x01}, + {0xF029, 0x08, 0x01}, + {0xF02A, 0x93, 0x01}, + {0xF02B, 0x1C, 0x01}, + {0xF02C, 0xD8, 0x01}, + {0xF02D, 0xA8, 0x01}, + {0xF02E, 0x05, 0x01}, + {0xF02F, 0x26, 0x01}, + {0xF030, 0x0B, 0x01}, + {0xF031, 0x01, 0x01}, + {0xF032, 0x88, 0x01}, + {0xF033, 0x43, 0x01}, + {0xF034, 0x6C, 0x01}, + {0xF035, 0xE2, 0x01}, + {0xF036, 0x96, 0x01}, + {0xF037, 0xDB, 0x01}, + {0xF038, 0xC4, 0x01}, + {0xF039, 0x66, 0x01}, + {0xF03A, 0x2D, 0x01}, + {0xF03B, 0x31, 0x01}, + {0xF03C, 0x59, 0x01}, + {0xF03D, 0x48, 0x01}, + {0xF03E, 0x40, 0x01}, + {0xF03F, 0x20, 0x01}, + {0xF040, 0x62, 0x01}, + {0xF041, 0x13, 0x01}, + {0xF042, 0xB8, 0x01}, + {0xF043, 0xF0, 0x01}, + {0xF044, 0x86, 0x01}, + {0xF045, 0x38, 0x01}, + {0xF046, 0x82, 0x01}, + {0xF047, 0x49, 0x01}, + {0xF048, 0x0A, 0x01}, + {0xF049, 0x49, 0x01}, + {0xF04A, 0x34, 0x01}, + {0xF04B, 0x92, 0x01}, + {0xF04C, 0x12, 0x01}, + {0xF04D, 0xA7, 0x01}, + {0xF04E, 0x1C, 0x01}, + {0xF04F, 0xE6, 0x01}, + {0xF050, 0x39, 0x01}, + {0xF051, 0xE2, 0x01}, + {0xF052, 0x41, 0x01}, + {0xF053, 0x8D, 0x01}, + {0xF054, 0x5D, 0x01}, + {0xF055, 0xAA, 0x01}, + {0xF056, 0xC2, 0x01}, + {0xF057, 0x94, 0x01}, + {0xF058, 0xAC, 0x01}, + {0xF059, 0xF4, 0x01}, + {0xF05A, 0x65, 0x01}, + {0xF05B, 0x36, 0x01}, + {0xF05C, 0xF1, 0x01}, + {0xF05D, 0x31, 0x01}, + {0xF05E, 0x90, 0x01}, + {0xF05F, 0x76, 0x01}, + {0xF060, 0x62, 0x01}, + {0xF061, 0x83, 0x01}, + {0xF062, 0x19, 0x01}, + {0xF063, 0xC7, 0x01}, + {0xF064, 0x6C, 0x01}, + {0xF065, 0x26, 0x01}, + {0xF066, 0x37, 0x01}, + {0xF067, 0xE2, 0x01}, + {0xF068, 0x89, 0x01}, + {0xF069, 0xD0, 0x01}, + {0xF06A, 0x87, 0x01}, + {0xF06B, 0x0C, 0x01}, + {0xF06C, 0xC4, 0x01}, + {0xF06D, 0x1E, 0x01}, + {0xF06E, 0xEE, 0x01}, + {0xF06F, 0x58, 0x01}, + {0xF070, 0x07, 0x01}, + {0xF071, 0x3C, 0x01}, + {0xF072, 0xF4, 0x01}, + {0xF073, 0x81, 0x01}, + {0xF074, 0x90, 0x01}, + {0xF075, 0x8B, 0x01}, + {0xF076, 0x3C, 0x01}, + {0xF077, 0xA4, 0x01}, + {0xF078, 0xA2, 0x01}, + {0xF079, 0x10, 0x01}, + {0xF07A, 0x69, 0x01}, + {0xF07B, 0x48, 0x01}, + {0xF07C, 0x43, 0x01}, + {0xF07D, 0x20, 0x01}, + {0xF07E, 0x62, 0x01}, + {0xF07F, 0x51, 0x01}, + {0xF080, 0x8C, 0x01}, + {0xF081, 0x50, 0x01}, + {0xF082, 0x04, 0x01}, + {0xF083, 0x00, 0x01}, + {0xF084, 0x00, 0x01}, + {0xF085, 0x00, 0x01}, + {0xF086, 0x00, 0x01}, + {0xF087, 0x00, 0x01}, + {0xF088, 0xBB, 0x01}, + {0xF089, 0x41, 0x01}, + {0xF08A, 0x0E, 0x01}, + {0xF08B, 0x6F, 0x01}, + {0xF08C, 0x68, 0x01}, + {0xF08D, 0x23, 0x01}, + {0xF08E, 0x9B, 0x01}, + {0xF08F, 0xD9, 0x01}, + {0xF090, 0xE8, 0x01}, + {0xF091, 0x06, 0x01}, + {0xF092, 0x38, 0x01}, + {0xF093, 0xB9, 0x01}, + {0xF094, 0xB9, 0x01}, + {0xF095, 0x4D, 0x01}, + {0xF096, 0x69, 0x01}, + {0xF097, 0x24, 0x01}, + {0xF098, 0x83, 0x01}, + {0xF099, 0x98, 0x01}, + {0xF09A, 0xC1, 0x01}, + {0xF09B, 0x1C, 0x01}, + {0xF09C, 0x06, 0x01}, + {0xF09D, 0x32, 0x01}, + {0xF09E, 0xA4, 0x01}, + {0xF09F, 0xA9, 0x01}, + {0xF0A0, 0x4D, 0x01}, + {0xF0A1, 0x67, 0x01}, + {0xF0A2, 0x0C, 0x01}, + {0xF0A3, 0x13, 0x01}, + {0xF0A4, 0x97, 0x01}, + {0xF0A5, 0xB0, 0x01}, + {0xF0A6, 0x6C, 0x01}, + {0xF0A7, 0x25, 0x01}, + {0xF0A8, 0x2C, 0x01}, + {0xF0A9, 0x70, 0x01}, + {0xF0AA, 0x39, 0x01}, + {0xF0AB, 0xCC, 0x01}, + {0xF0AC, 0x68, 0x01}, + {0xF0AD, 0x10, 0x01}, + {0xF0AE, 0xA3, 0x01}, + {0xF0AF, 0x96, 0x01}, + {0xF0B0, 0xA6, 0x01}, + {0xF0B1, 0xE4, 0x01}, + {0xF0B2, 0x44, 0x01}, + {0xF0B3, 0x26, 0x01}, + {0xF0B4, 0x3A, 0x01}, + {0xF0B5, 0x79, 0x01}, + {0xF0B6, 0x4A, 0x01}, + {0xF0B7, 0x5B, 0x01}, + {0xF0B8, 0x18, 0x01}, + {0xF0B9, 0x93, 0x01}, + {0xF0BA, 0x17, 0x01}, + {0xF0BB, 0xA9, 0x01}, + {0xF0BC, 0xBC, 0x01}, + {0xF0BD, 0x24, 0x01}, + {0xF0BE, 0x23, 0x01}, + {0xF0BF, 0x12, 0x01}, + {0xF0C0, 0xE1, 0x01}, + {0xF0C1, 0xC8, 0x01}, + {0xF0C2, 0x4C, 0x01}, + {0xF0C3, 0xAA, 0x01}, + {0xF0C4, 0xA2, 0x01}, + {0xF0C5, 0x17, 0x01}, + {0xF0C6, 0xB6, 0x01}, + {0xF0C7, 0x10, 0x01}, + {0xF0C8, 0x05, 0x01}, + {0xF0C9, 0x24, 0x01}, + {0xF0CA, 0x06, 0x01}, + {0xF0CB, 0x09, 0x01}, + {0xF0CC, 0xC8, 0x01}, + {0xF0CD, 0x42, 0x01}, + {0xF0CE, 0x4A, 0x01}, + {0xF0CF, 0x82, 0x01}, + {0xF0D0, 0x94, 0x01}, + {0xF0D1, 0xB8, 0x01}, + {0xF0D2, 0xC0, 0x01}, + {0xF0D3, 0xE5, 0x01}, + {0xF0D4, 0x28, 0x01}, + {0xF0D5, 0x21, 0x01}, + {0xF0D6, 0x39, 0x01}, + {0xF0D7, 0x08, 0x01}, + {0xF0D8, 0x40, 0x01}, + {0xF0D9, 0x16, 0x01}, + {0xF0DA, 0x62, 0x01}, + {0xF0DB, 0x92, 0x01}, + {0xF0DC, 0xA4, 0x01}, + {0xF0DD, 0xC4, 0x01}, + {0xF0DE, 0xE5, 0x01}, + {0xF0DF, 0x2F, 0x01}, + {0xF0E0, 0x58, 0x01}, + {0xF0E1, 0x99, 0x01}, + {0xF0E2, 0x49, 0x01}, + {0xF0E3, 0x46, 0x01}, + {0xF0E4, 0x22, 0x01}, + {0xF0E5, 0xC2, 0x01}, + {0xF0E6, 0x91, 0x01}, + {0xF0E7, 0x9A, 0x01}, + {0xF0E8, 0x58, 0x01}, + {0xF0E9, 0xA5, 0x01}, + {0xF0EA, 0x2F, 0x01}, + {0xF0EB, 0x95, 0x01}, + {0xF0EC, 0x99, 0x01}, + {0xF0ED, 0x4B, 0x01}, + {0xF0EE, 0x54, 0x01}, + {0xF0EF, 0x74, 0x01}, + {0xF0F0, 0x32, 0x01}, + {0xF0F1, 0x93, 0x01}, + {0xF0F2, 0x9D, 0x01}, + {0xF0F3, 0x38, 0x01}, + {0xF0F4, 0xC5, 0x01}, + {0xF0F5, 0x2D, 0x01}, + {0xF0F6, 0x90, 0x01}, + {0xF0F7, 0x59, 0x01}, + {0xF0F8, 0x0D, 0x01}, + {0xF0F9, 0x64, 0x01}, + {0xF0FA, 0xEE, 0x01}, + {0xF0FB, 0x62, 0x01}, + {0xF0FC, 0x96, 0x01}, + {0xF0FD, 0xAE, 0x01}, + {0xF0FE, 0x84, 0x01}, + {0xF0FF, 0x25, 0x01}, + {0xF100, 0x2E, 0x01}, + {0xF101, 0x8A, 0x01}, + {0xF102, 0x29, 0x01}, + {0xF103, 0x8D, 0x01}, + {0xF104, 0x6F, 0x01}, + {0xF105, 0x60, 0x01}, + {0xF106, 0xD3, 0x01}, + {0xF107, 0x19, 0x01}, + {0xF108, 0xC7, 0x01}, + {0xF109, 0x18, 0x01}, + {0xF10A, 0x26, 0x01}, + {0xF10B, 0x31, 0x01}, + {0xF10C, 0x97, 0x01}, + {0xF10D, 0x41, 0x01}, + {0xF10E, 0x8D, 0x01}, + {0xF10F, 0x6D, 0x01}, + {0xF110, 0x84, 0x01}, + {0xF111, 0xE3, 0x01}, + {0xF112, 0x1C, 0x01}, + {0xF113, 0xE3, 0x01}, + {0xF114, 0xDC, 0x01}, + {0xF115, 0x26, 0x01}, + {0xF116, 0x36, 0x01}, + {0xF117, 0xB6, 0x01}, + {0xF118, 0xF1, 0x01}, + {0xF119, 0x4D, 0x01}, + {0xF11A, 0x70, 0x01}, + {0xF11B, 0x68, 0x01}, + {0xF11C, 0x03, 0x01}, + {0xF11D, 0x00, 0x01}, + {0xF11E, 0x00, 0x01}, + {0xF11F, 0x00, 0x01}, + {0xF120, 0x00, 0x01}, + {0xF121, 0x00, 0x01}, + + + /*SHD TH*/ + {0x6C32, 0x16A8, 0x02}, /* SHD_INP_TH_HB_H_R2*/ + {0x6C34, 0x1612, 0x02}, /* SHD_INP_TH_HB_L_R2*/ + {0x6C36, 0x10CC, 0x02}, /* SHD_INP_TH_LB_H_R2*/ + {0x6C38, 0x1004, 0x02}, /* SHD_INP_TH_LB_L_R2*/ + {0x6C3C, 0x10CC, 0x02}, /* SHD_INP_TH_HB_H_RB*/ + {0x6C3E, 0x1004, 0x02}, /* SHD_INP_TH_HB_L_RB*/ + {0x6C40, 0x0000, 0x02}, /* SHD_INP_TH_LB_H_RB*/ + {0x6C42, 0x0000, 0x02}, /* SHD_INP_TH_LB_L_RB*/ + + /*PreWB_offset (for SHD2)*/ + {0x6828, 0x0013, 0x02}, /* SHD_PRER_OFFSET_R2 :*/ + /*PreWB_offset (for SHD3)*/ + {0x682C, 0x000C, 0x02}, /* SHD_PRER_OFFSET_RB :*/ + {0x6830, 0xFFFF, 0x02}, /* SHD_PREB_OFFSET_RB :*/ + + /* CXC/SHD EN*/ + {0x01BC, 0x57, 0x01}, /* CXC ON SHD ON INP ON GAIN OFF*/ + + /*#36*/ + {0x6804, 0x1122, 0x02}, /* NORMR*/ + {0x6806, 0x116B, 0x02}, /* NORMB*/ + {0x6808, 0x0150, 0x02}, /* AWBPRER*/ + {0x680A, 0x0245, 0x02}, /* AWBPREB*/ + {0x6810, 0x1001, 0x02}, /* AWB_PRE_ADJ_RG*/ + {0x6812, 0x0FC9, 0x02}, /* AWB_PRE_ADJ_BG*/ + {0x6814, 0x0A73, 0x02}, /* AWB_C14_RG*/ + {0x6816, 0x17EA, 0x02}, /* AWB_C14_BG*/ +}; + +struct isx012_short_t ISX012_Shading_0[] = { + {0x01BC, 0x50, 0x01}, /* CXC OFF SHD OFF*/ + + {0xEB00, 0x8282, 0x02}, /*valid_code*/ + {0xEB02, 0xFF, 0x01}, + {0xEB03, 0xC4, 0x01}, + {0xEB04, 0x3F, 0x01}, + {0xEB05, 0xF1, 0x01}, + {0xEB06, 0x3F, 0x01}, + {0xEB07, 0x00, 0x01}, + {0xEB08, 0x12, 0x01}, + {0xEB09, 0x7E, 0x01}, + {0xEB0A, 0x83, 0x01}, + {0xEB0B, 0xFF, 0x01}, + {0xEB0C, 0xF0, 0x01}, + {0xEB0D, 0x47, 0x01}, + {0xEB0E, 0x04, 0x01}, + {0xEB0F, 0x12, 0x01}, + {0xEB10, 0x81, 0x01}, + {0xEB11, 0xC4, 0x01}, + {0xEB12, 0x3F, 0x01}, + {0xEB13, 0xF1, 0x01}, + {0xEB14, 0x4F, 0x01}, + {0xEB15, 0xFC, 0x01}, + {0xEB16, 0x0F, 0x01}, + {0xEB17, 0x80, 0x01}, + {0xEB18, 0x84, 0x01}, + {0xEB19, 0xDF, 0x01}, + {0xEB1A, 0xE0, 0x01}, + {0xEB1B, 0x3F, 0x01}, + {0xEB1C, 0xFC, 0x01}, + {0xEB1D, 0x11, 0x01}, + {0xEB1E, 0x81, 0x01}, + {0xEB1F, 0x44, 0x01}, + {0xEB20, 0x20, 0x01}, + {0xEB21, 0x11, 0x01}, + {0xEB22, 0x38, 0x01}, + {0xEB23, 0x04, 0x01}, + {0xEB24, 0x0E, 0x01}, + {0xEB25, 0x01, 0x01}, + {0xEB26, 0xC3, 0x01}, + {0xEB27, 0xBF, 0x01}, + {0xEB28, 0x00, 0x01}, + {0xEB29, 0x30, 0x01}, + {0xEB2A, 0x00, 0x01}, + {0xEB2B, 0x0C, 0x01}, + {0xEB2C, 0x82, 0x01}, + {0xEB2D, 0x43, 0x01}, + {0xEB2E, 0x40, 0x01}, + {0xEB2F, 0x11, 0x01}, + {0xEB30, 0x50, 0x01}, + {0xEB31, 0x08, 0x01}, + {0xEB32, 0x0E, 0x01}, + {0xEB33, 0x82, 0x01}, + {0xEB34, 0xC3, 0x01}, + {0xEB35, 0xA0, 0x01}, + {0xEB36, 0x00, 0x01}, + {0xEB37, 0x18, 0x01}, + {0xEB38, 0x00, 0x01}, + {0xEB39, 0x04, 0x01}, + {0xEB3A, 0x81, 0x01}, + {0xEB3B, 0x01, 0x01}, + {0xEB3C, 0xC0, 0x01}, + {0xEB3D, 0x00, 0x01}, + {0xEB3E, 0x38, 0x01}, + {0xEB3F, 0x00, 0x01}, + {0xEB40, 0x0E, 0x01}, + {0xEB41, 0x83, 0x01}, + {0xEB42, 0xC2, 0x01}, + {0xEB43, 0xA0, 0x01}, + {0xEB44, 0x10, 0x01}, + {0xEB45, 0x18, 0x01}, + {0xEB46, 0x00, 0x01}, + {0xEB47, 0x04, 0x01}, + {0xEB48, 0x01, 0x01}, + {0xEB49, 0x01, 0x01}, + {0xEB4A, 0x00, 0x01}, + {0xEB4B, 0x00, 0x01}, + {0xEB4C, 0x18, 0x01}, + {0xEB4D, 0x08, 0x01}, + {0xEB4E, 0x0A, 0x01}, + {0xEB4F, 0x82, 0x01}, + {0xEB50, 0x02, 0x01}, + {0xEB51, 0x60, 0x01}, + {0xEB52, 0x00, 0x01}, + {0xEB53, 0x18, 0x01}, + {0xEB54, 0x04, 0x01}, + {0xEB55, 0x02, 0x01}, + {0xEB56, 0x81, 0x01}, + {0xEB57, 0x40, 0x01}, + {0xEB58, 0x20, 0x01}, + {0xEB59, 0x00, 0x01}, + {0xEB5A, 0x08, 0x01}, + {0xEB5B, 0x04, 0x01}, + {0xEB5C, 0x04, 0x01}, + {0xEB5D, 0x02, 0x01}, + {0xEB5E, 0x82, 0x01}, + {0xEB5F, 0x80, 0x01}, + {0xEB60, 0x30, 0x01}, + {0xEB61, 0x18, 0x01}, + {0xEB62, 0x0C, 0x01}, + {0xEB63, 0x06, 0x01}, + {0xEB64, 0x82, 0x01}, + {0xEB65, 0xC0, 0x01}, + {0xEB66, 0xFF, 0x01}, + {0xEB67, 0x0F, 0x01}, + {0xEB68, 0x00, 0x01}, + {0xEB69, 0x04, 0x01}, + {0xEB6A, 0x00, 0x01}, + {0xEB6B, 0x80, 0x01}, + {0xEB6C, 0x00, 0x01}, + {0xEB6D, 0x40, 0x01}, + {0xEB6E, 0x00, 0x01}, + {0xEB6F, 0x10, 0x01}, + {0xEB70, 0x00, 0x01}, + {0xEB71, 0x04, 0x01}, + {0xEB72, 0x00, 0x01}, + {0xEB73, 0x81, 0x01}, + {0xEB74, 0x60, 0x01}, + {0xEB75, 0x20, 0x01}, + {0xEB76, 0x00, 0x01}, + {0xEB77, 0x04, 0x01}, + {0xEB78, 0xFE, 0x01}, + {0xEB79, 0x82, 0x01}, + {0xEB7A, 0xC0, 0x01}, + {0xEB7B, 0x40, 0x01}, + {0xEB7C, 0x30, 0x01}, + {0xEB7D, 0x18, 0x01}, + {0xEB7E, 0x0C, 0x01}, + {0xEB7F, 0x06, 0x01}, + {0xEB80, 0x80, 0x01}, + {0xEB81, 0x01, 0x01}, + {0xEB82, 0x60, 0x01}, + {0xEB83, 0x30, 0x01}, + {0xEB84, 0x18, 0x01}, + {0xEB85, 0x08, 0x01}, + {0xEB86, 0x04, 0x01}, + {0xEB87, 0x80, 0x01}, + {0xEB88, 0xC0, 0x01}, + {0xEB89, 0x40, 0x01}, + {0xEB8A, 0x20, 0x01}, + {0xEB8B, 0x10, 0x01}, + {0xEB8C, 0x0C, 0x01}, + {0xEB8D, 0x06, 0x01}, + {0xEB8E, 0x83, 0x01}, + {0xEB8F, 0x41, 0x01}, + {0xEB90, 0x80, 0x01}, + {0xEB91, 0x10, 0x01}, + {0xEB92, 0x20, 0x01}, + {0xEB93, 0x04, 0x01}, + {0xEB94, 0x06, 0x01}, + {0xEB95, 0x82, 0x01}, + {0xEB96, 0x41, 0x01}, + {0xEB97, 0x60, 0x01}, + {0xEB98, 0x30, 0x01}, + {0xEB99, 0x28, 0x01}, + {0xEB9A, 0x08, 0x01}, + {0xEB9B, 0x08, 0x01}, + {0xEB9C, 0x82, 0x01}, + {0xEB9D, 0x82, 0x01}, + {0xEB9E, 0xA0, 0x01}, + {0xEB9F, 0xE0, 0x01}, + {0xEBA0, 0x2F, 0x01}, + {0xEBA1, 0xF8, 0x01}, + {0xEBA2, 0x0B, 0x01}, + {0xEBA3, 0x02, 0x01}, + {0xEBA4, 0x42, 0x01}, + {0xEBA5, 0xA0, 0x01}, + {0xEBA6, 0x20, 0x01}, + {0xEBA7, 0x28, 0x01}, + {0xEBA8, 0x10, 0x01}, + {0xEBA9, 0x0C, 0x01}, + {0xEBAA, 0x03, 0x01}, + {0xEBAB, 0x82, 0x01}, + {0xEBAC, 0xA0, 0x01}, + {0xEBAD, 0x20, 0x01}, + {0xEBAE, 0x28, 0x01}, + {0xEBAF, 0xF8, 0x01}, + {0xEBB0, 0x0B, 0x01}, + {0xEBB1, 0xFE, 0x01}, + {0xEBB2, 0x82, 0x01}, + {0xEBB3, 0x80, 0x01}, + {0xEBB4, 0x10, 0x01}, + {0xEBB5, 0x28, 0x01}, + {0xEBB6, 0x08, 0x01}, + {0xEBB7, 0x0A, 0x01}, + {0xEBB8, 0x04, 0x01}, + {0xEBB9, 0xC3, 0x01}, + {0xEBBA, 0x80, 0x01}, + {0xEBBB, 0x20, 0x01}, + {0xEBBC, 0x28, 0x01}, + {0xEBBD, 0x08, 0x01}, + {0xEBBE, 0x0A, 0x01}, + {0xEBBF, 0x03, 0x01}, + {0xEBC0, 0xFB, 0x01}, + {0xEBC1, 0xC0, 0x01}, + {0xEBC2, 0x3E, 0x01}, + {0xEBC3, 0xC0, 0x01}, + {0xEBC4, 0x0F, 0x01}, + {0xEBC5, 0xF4, 0x01}, + {0xEBC6, 0x02, 0x01}, + {0xEBC7, 0xFC, 0x01}, + {0xEBC8, 0x20, 0x01}, + {0xEBC9, 0x2F, 0x01}, + {0xEBCA, 0xB8, 0x01}, + {0xEBCB, 0x03, 0x01}, + {0xEBCC, 0xF8, 0x01}, + {0xEBCD, 0x00, 0x01}, + {0xEBCE, 0xFE, 0x01}, + {0xEBCF, 0xC0, 0x01}, + {0xEBD0, 0x3E, 0x01}, + {0xEBD1, 0xB0, 0x01}, + {0xEBD2, 0x0F, 0x01}, + {0xEBD3, 0xF0, 0x01}, + {0xEBD4, 0x03, 0x01}, + {0xEBD5, 0xBD, 0x01}, + {0xEBD6, 0x00, 0x01}, + {0xEBD7, 0x3F, 0x01}, + {0xEBD8, 0xC8, 0x01}, + {0xEBD9, 0x0B, 0x01}, + {0xEBDA, 0xEE, 0x01}, + {0xEBDB, 0x00, 0x01}, + {0xEBDC, 0x3E, 0x01}, + {0xEBDD, 0x80, 0x01}, + {0xEBDE, 0x2F, 0x01}, + {0xEBDF, 0xC8, 0x01}, + {0xEBE0, 0x0B, 0x01}, + {0xEBE1, 0xF2, 0x01}, + {0xEBE2, 0x83, 0x01}, + {0xEBE3, 0xBC, 0x01}, + {0xEBE4, 0xA0, 0x01}, + {0xEBE5, 0x0E, 0x01}, + {0xEBE6, 0xC0, 0x01}, + {0xEBE7, 0x03, 0x01}, + {0xEBE8, 0xF4, 0x01}, + {0xEBE9, 0x81, 0x01}, + {0xEBEA, 0x3D, 0x01}, + {0xEBEB, 0x00, 0x01}, + {0xEBEC, 0x0F, 0x01}, + {0xEBED, 0xC0, 0x01}, + {0xEBEE, 0x0F, 0x01}, + {0xEBEF, 0xEE, 0x01}, + {0xEBF0, 0x83, 0x01}, + {0xEBF1, 0xBB, 0x01}, + {0xEBF2, 0x60, 0x01}, + {0xEBF3, 0x0F, 0x01}, + {0xEBF4, 0xB8, 0x01}, + {0xEBF5, 0xFF, 0x01}, + {0xEBF6, 0xF3, 0x01}, + {0xEBF7, 0xFF, 0x01}, + {0xEBF8, 0x3C, 0x01}, + {0xEBF9, 0x40, 0x01}, + {0xEBFA, 0x0F, 0x01}, + {0xEBFB, 0xC8, 0x01}, + {0xEBFC, 0x03, 0x01}, + {0xEBFD, 0xF2, 0x01}, + {0xEBFE, 0x04, 0x01}, + {0xEBFF, 0x3E, 0x01}, + {0xEC00, 0x81, 0x01}, + {0xEC01, 0x0F, 0x01}, + {0xEC02, 0xD0, 0x01}, + {0xEC03, 0x03, 0x01}, + {0xEC04, 0xF6, 0x01}, + {0xEC05, 0x00, 0x01}, + {0xEC06, 0x3D, 0x01}, + {0xEC07, 0xE0, 0x01}, + {0xEC08, 0xFE, 0x01}, + {0xEC09, 0xD7, 0x01}, + {0xEC0A, 0x03, 0x01}, + {0xEC0B, 0xF4, 0x01}, + {0xEC0C, 0x00, 0x01}, + {0xEC0D, 0x3D, 0x01}, + {0xEC0E, 0xE1, 0x01}, + {0xEC0F, 0x4F, 0x01}, + {0xEC10, 0xF8, 0x01}, + {0xEC11, 0x0F, 0x01}, + {0xEC12, 0xF4, 0x01}, + {0xEC13, 0x80, 0x01}, + {0xEC14, 0xFE, 0x01}, + {0xEC15, 0x9F, 0x01}, + {0xEC16, 0x0F, 0x01}, + {0xEC17, 0xE0, 0x01}, + {0xEC18, 0x03, 0x01}, + {0xEC19, 0xFA, 0x01}, + {0xEC1A, 0x80, 0x01}, + {0xEC1B, 0x3D, 0x01}, + {0xEC1C, 0x60, 0x01}, + {0xEC1D, 0x5F, 0x01}, + {0xEC1E, 0xF0, 0x01}, + {0xEC1F, 0x17, 0x01}, + {0xEC20, 0xFC, 0x01}, + {0xEC21, 0x02, 0x01}, + {0xEC22, 0x41, 0x01}, + {0xEC23, 0xC0, 0x01}, + {0xEC24, 0x1F, 0x01}, + {0xEC25, 0xF8, 0x01}, + {0xEC26, 0x03, 0x01}, + {0xEC27, 0x02, 0x01}, + {0xEC28, 0xFF, 0x01}, + {0xEC29, 0x3F, 0x01}, + {0xEC2A, 0xC0, 0x01}, + {0xEC2B, 0x0F, 0x01}, + {0xEC2C, 0xF0, 0x01}, + {0xEC2D, 0x1F, 0x01}, + {0xEC2E, 0x04, 0x01}, + {0xEC2F, 0x07, 0x01}, + {0xEC30, 0x41, 0x01}, + {0xEC31, 0x61, 0x01}, + {0xEC32, 0x20, 0x01}, + {0xEC33, 0x10, 0x01}, + {0xEC34, 0x04, 0x01}, + {0xEC35, 0x04, 0x01}, + {0xEC36, 0x81, 0x01}, + {0xEC37, 0x3F, 0x01}, + {0xEC38, 0x80, 0x01}, + {0xEC39, 0x20, 0x01}, + {0xEC3A, 0x10, 0x01}, + {0xEC3B, 0x08, 0x01}, + {0xEC3C, 0x04, 0x01}, + {0xEC3D, 0x05, 0x01}, + {0xEC3E, 0x41, 0x01}, + {0xEC3F, 0x41, 0x01}, + {0xEC40, 0x50, 0x01}, + {0xEC41, 0x30, 0x01}, + {0xEC42, 0x10, 0x01}, + {0xEC43, 0x02, 0x01}, + {0xEC44, 0x82, 0x01}, + {0xEC45, 0x81, 0x01}, + {0xEC46, 0xC0, 0x01}, + {0xEC47, 0x20, 0x01}, + {0xEC48, 0x18, 0x01}, + {0xEC49, 0x0C, 0x01}, + {0xEC4A, 0x04, 0x01}, + {0xEC4B, 0x03, 0x01}, + {0xEC4C, 0xC1, 0x01}, + {0xEC4D, 0x21, 0x01}, + {0xEC4E, 0x70, 0x01}, + {0xEC4F, 0x08, 0x01}, + {0xEC50, 0x20, 0x01}, + {0xEC51, 0x02, 0x01}, + {0xEC52, 0x84, 0x01}, + {0xEC53, 0x83, 0x01}, + {0xEC54, 0xC0, 0x01}, + {0xEC55, 0x20, 0x01}, + {0xEC56, 0x20, 0x01}, + {0xEC57, 0x04, 0x01}, + {0xEC58, 0x04, 0x01}, + {0xEC59, 0x02, 0x01}, + {0xEC5A, 0x82, 0x01}, + {0xEC5B, 0x80, 0x01}, + {0xEC5C, 0x50, 0x01}, + {0xEC5D, 0x08, 0x01}, + {0xEC5E, 0x14, 0x01}, + {0xEC5F, 0x02, 0x01}, + {0xEC60, 0x04, 0x01}, + {0xEC61, 0x04, 0x01}, + {0xEC62, 0x41, 0x01}, + {0xEC63, 0x30, 0x01}, + {0xEC64, 0x38, 0x01}, + {0xEC65, 0x04, 0x01}, + {0xEC66, 0x0C, 0x01}, + {0xEC67, 0x02, 0x01}, + {0xEC68, 0x81, 0x01}, + {0xEC69, 0x80, 0x01}, + {0xEC6A, 0x20, 0x01}, + {0xEC6B, 0x20, 0x01}, + {0xEC6C, 0x14, 0x01}, + {0xEC6D, 0x02, 0x01}, + {0xEC6E, 0x85, 0x01}, + {0xEC6F, 0x00, 0x01}, + {0xEC70, 0x01, 0x01}, + {0xEC71, 0x41, 0x01}, + {0xEC72, 0x10, 0x01}, + {0xEC73, 0x0C, 0x01}, + {0xEC74, 0x0E, 0x01}, + {0xEC75, 0x01, 0x01}, + {0xEC76, 0x83, 0x01}, + {0xEC77, 0x40, 0x01}, + {0xEC78, 0x20, 0x01}, + {0xEC79, 0x20, 0x01}, + {0xEC7A, 0x08, 0x01}, + {0xEC7B, 0x08, 0x01}, + + + {0xED02, 0x85, 0x01}, + {0xED03, 0xAA, 0x01}, + {0xED04, 0xD8, 0x01}, + {0xED05, 0x9A, 0x01}, + {0xED06, 0xE6, 0x01}, + {0xED07, 0x65, 0x01}, + {0xED08, 0x25, 0x01}, + {0xED09, 0x6C, 0x01}, + {0xED0A, 0xC9, 0x01}, + {0xED0B, 0xE8, 0x01}, + {0xED0C, 0x56, 0x01}, + {0xED0D, 0x21, 0x01}, + {0xED0E, 0xA2, 0x01}, + {0xED0F, 0x54, 0x01}, + {0xED10, 0x88, 0x01}, + {0xED11, 0x2C, 0x01}, + {0xED12, 0x45, 0x01}, + {0xED13, 0x23, 0x01}, + {0xED14, 0x5A, 0x01}, + {0xED15, 0x41, 0x01}, + {0xED16, 0xA9, 0x01}, + {0xED17, 0x59, 0x01}, + {0xED18, 0x67, 0x01}, + {0xED19, 0xCA, 0x01}, + {0xED1A, 0x96, 0x01}, + {0xED1B, 0x93, 0x01}, + {0xED1C, 0x76, 0x01}, + {0xED1D, 0x35, 0x01}, + {0xED1E, 0xA1, 0x01}, + {0xED1F, 0x38, 0x01}, + {0xED20, 0x89, 0x01}, + {0xED21, 0x67, 0x01}, + {0xED22, 0x46, 0x01}, + {0xED23, 0xC1, 0x01}, + {0xED24, 0x71, 0x01}, + {0xED25, 0x10, 0x01}, + {0xED26, 0x6C, 0x01}, + {0xED27, 0xEC, 0x01}, + {0xED28, 0x13, 0x01}, + {0xED29, 0x9B, 0x01}, + {0xED2A, 0xFC, 0x01}, + {0xED2B, 0x10, 0x01}, + {0xED2C, 0x87, 0x01}, + {0xED2D, 0x42, 0x01}, + {0xED2E, 0xE9, 0x01}, + {0xED2F, 0x29, 0x01}, + {0xED30, 0x92, 0x01}, + {0xED31, 0x86, 0x01}, + {0xED32, 0xFC, 0x01}, + {0xED33, 0x74, 0x01}, + {0xED34, 0x21, 0x01}, + {0xED35, 0x39, 0x01}, + {0xED36, 0x31, 0x01}, + {0xED37, 0xE7, 0x01}, + {0xED38, 0x41, 0x01}, + {0xED39, 0x9D, 0x01}, + {0xED3A, 0x89, 0x01}, + {0xED3B, 0xCE, 0x01}, + {0xED3C, 0x5F, 0x01}, + {0xED3D, 0x58, 0x01}, + {0xED3E, 0x03, 0x01}, + {0xED3F, 0x17, 0x01}, + {0xED40, 0xCD, 0x01}, + {0xED41, 0xCC, 0x01}, + {0xED42, 0xC5, 0x01}, + {0xED43, 0x33, 0x01}, + {0xED44, 0x85, 0x01}, + {0xED45, 0xD1, 0x01}, + {0xED46, 0x0D, 0x01}, + {0xED47, 0x69, 0x01}, + {0xED48, 0xD4, 0x01}, + {0xED49, 0x53, 0x01}, + {0xED4A, 0x1D, 0x01}, + {0xED4B, 0x18, 0x01}, + {0xED4C, 0x7D, 0x01}, + {0xED4D, 0x07, 0x01}, + {0xED4E, 0x45, 0x01}, + {0xED4F, 0x9D, 0x01}, + {0xED50, 0x69, 0x01}, + {0xED51, 0x4E, 0x01}, + {0xED52, 0x5B, 0x01}, + {0xED53, 0x16, 0x01}, + {0xED54, 0x83, 0x01}, + {0xED55, 0x94, 0x01}, + {0xED56, 0xAE, 0x01}, + {0xED57, 0xE0, 0x01}, + {0xED58, 0x24, 0x01}, + {0xED59, 0x29, 0x01}, + {0xED5A, 0x3C, 0x01}, + {0xED5B, 0x79, 0x01}, + {0xED5C, 0x8A, 0x01}, + {0xED5D, 0x54, 0x01}, + {0xED5E, 0xE0, 0x01}, + {0xED5F, 0x72, 0x01}, + {0xED60, 0x17, 0x01}, + {0xED61, 0xD3, 0x01}, + {0xED62, 0x90, 0x01}, + {0xED63, 0x06, 0x01}, + {0xED64, 0x3D, 0x01}, + {0xED65, 0xC1, 0x01}, + {0xED66, 0xD1, 0x01}, + {0xED67, 0x0F, 0x01}, + {0xED68, 0x5F, 0x01}, + {0xED69, 0x3C, 0x01}, + {0xED6A, 0x53, 0x01}, + {0xED6B, 0x14, 0x01}, + {0xED6C, 0xAB, 0x01}, + {0xED6D, 0x84, 0x01}, + {0xED6E, 0x24, 0x01}, + {0xED6F, 0x25, 0x01}, + {0xED70, 0x11, 0x01}, + {0xED71, 0xB1, 0x01}, + {0xED72, 0x08, 0x01}, + {0xED73, 0x45, 0x01}, + {0xED74, 0x34, 0x01}, + {0xED75, 0xB2, 0x01}, + {0xED76, 0x92, 0x01}, + {0xED77, 0x9C, 0x01}, + {0xED78, 0x5C, 0x01}, + {0xED79, 0x65, 0x01}, + {0xED7A, 0x2E, 0x01}, + {0xED7B, 0x8E, 0x01}, + {0xED7C, 0x09, 0x01}, + {0xED7D, 0x8E, 0x01}, + {0xED7E, 0x6C, 0x01}, + {0xED7F, 0xC6, 0x01}, + {0xED80, 0x93, 0x01}, + {0xED81, 0x96, 0x01}, + {0xED82, 0xC1, 0x01}, + {0xED83, 0xC4, 0x01}, + {0xED84, 0x64, 0x01}, + {0xED85, 0x27, 0x01}, + {0xED86, 0x0E, 0x01}, + {0xED87, 0x89, 0x01}, + {0xED88, 0x08, 0x01}, + {0xED89, 0x40, 0x01}, + {0xED8A, 0x02, 0x01}, + {0xED8B, 0x22, 0x01}, + {0xED8C, 0x10, 0x01}, + {0xED8D, 0x82, 0x01}, + {0xED8E, 0x64, 0x01}, + {0xED8F, 0x24, 0x01}, + {0xED90, 0x24, 0x01}, + {0xED91, 0x44, 0x01}, + {0xED92, 0xD1, 0x01}, + {0xED93, 0x0A, 0x01}, + {0xED94, 0x60, 0x01}, + {0xED95, 0x58, 0x01}, + {0xED96, 0x53, 0x01}, + {0xED97, 0x1B, 0x01}, + {0xED98, 0xF2, 0x01}, + {0xED99, 0xA8, 0x01}, + {0xED9A, 0x65, 0x01}, + {0xED9B, 0x30, 0x01}, + {0xED9C, 0x32, 0x01}, + {0xED9D, 0xD9, 0x01}, + {0xED9E, 0x89, 0x01}, + {0xED9F, 0x43, 0x01}, + {0xEDA0, 0x20, 0x01}, + {0xEDA1, 0x12, 0x01}, + {0xEDA2, 0x10, 0x01}, + {0xEDA3, 0x80, 0x01}, + {0xEDA4, 0x10, 0x01}, + {0xEDA5, 0x84, 0x01}, + {0xEDA6, 0x20, 0x01}, + {0xEDA7, 0x19, 0x01}, + {0xEDA8, 0x01, 0x01}, + {0xEDA9, 0x49, 0x01}, + {0xEDAA, 0x51, 0x01}, + {0xEDAB, 0xB2, 0x01}, + {0xEDAC, 0x12, 0x01}, + {0xEDAD, 0x98, 0x01}, + {0xEDAE, 0xD5, 0x01}, + {0xEDAF, 0xFC, 0x01}, + {0xEDB0, 0x46, 0x01}, + {0xEDB1, 0x3E, 0x01}, + {0xEDB2, 0x7C, 0x01}, + {0xEDB3, 0xC9, 0x01}, + {0xEDB4, 0xCC, 0x01}, + {0xEDB5, 0x51, 0x01}, + {0xEDB6, 0xAC, 0x01}, + {0xEDB7, 0x32, 0x01}, + {0xEDB8, 0x12, 0x01}, + {0xEDB9, 0x93, 0x01}, + {0xEDBA, 0x4C, 0x01}, + {0xEDBB, 0x84, 0x01}, + {0xEDBC, 0x22, 0x01}, + {0xEDBD, 0x17, 0x01}, + {0xEDBE, 0xD9, 0x01}, + {0xEDBF, 0xC8, 0x01}, + {0xEDC0, 0x4B, 0x01}, + {0xEDC1, 0x74, 0x01}, + {0xEDC2, 0xA2, 0x01}, + {0xEDC3, 0x95, 0x01}, + {0xEDC4, 0xB9, 0x01}, + {0xEDC5, 0x48, 0x01}, + {0xEDC6, 0x06, 0x01}, + {0xEDC7, 0x38, 0x01}, + {0xEDC8, 0xDC, 0x01}, + {0xEDC9, 0xC9, 0x01}, + {0xEDCA, 0xD0, 0x01}, + {0xEDCB, 0x66, 0x01}, + {0xEDCC, 0x86, 0x01}, + {0xEDCD, 0xD3, 0x01}, + {0xEDCE, 0x96, 0x01}, + {0xEDCF, 0xC3, 0x01}, + {0xEDD0, 0x28, 0x01}, + {0xEDD1, 0x45, 0x01}, + {0xEDD2, 0x2B, 0x01}, + {0xEDD3, 0x39, 0x01}, + {0xEDD4, 0x31, 0x01}, + {0xEDD5, 0xCA, 0x01}, + {0xEDD6, 0x4F, 0x01}, + {0xEDD7, 0x9C, 0x01}, + {0xEDD8, 0x62, 0x01}, + {0xEDD9, 0x15, 0x01}, + {0xEDDA, 0xB6, 0x01}, + {0xEDDB, 0xF4, 0x01}, + {0xEDDC, 0x45, 0x01}, + {0xEDDD, 0x34, 0x01}, + {0xEDDE, 0xAD, 0x01}, + {0xEDDF, 0x29, 0x01}, + {0xEDE0, 0x4F, 0x01}, + {0xEDE1, 0x84, 0x01}, + {0xEDE2, 0xC4, 0x01}, + {0xEDE3, 0x84, 0x01}, + {0xEDE4, 0x9C, 0x01}, + {0xEDE5, 0x01, 0x01}, + {0xEDE6, 0x6D, 0x01}, + {0xEDE7, 0x06, 0x01}, + {0xEDE8, 0x39, 0x01}, + {0xEDE9, 0x7F, 0x01}, + {0xEDEA, 0x11, 0x01}, + {0xEDEB, 0x0D, 0x01}, + {0xEDEC, 0x5C, 0x01}, + {0xEDED, 0x26, 0x01}, + {0xEDEE, 0x53, 0x01}, + {0xEDEF, 0x17, 0x01}, + {0xEDF0, 0xCE, 0x01}, + {0xEDF1, 0x20, 0x01}, + {0xEDF2, 0xC6, 0x01}, + {0xEDF3, 0x36, 0x01}, + {0xEDF4, 0xA8, 0x01}, + {0xEDF5, 0x11, 0x01}, + {0xEDF6, 0x0F, 0x01}, + {0xEDF7, 0x76, 0x01}, + {0xEDF8, 0x44, 0x01}, + {0xEDF9, 0x34, 0x01}, + {0xEDFA, 0x24, 0x01}, + {0xEDFB, 0x53, 0x01}, + {0xEDFC, 0x15, 0x01}, + {0xEDFD, 0x08, 0x01}, + {0xEDFE, 0x4B, 0x01}, + {0xEDFF, 0xD5, 0x01}, + {0xEE00, 0xC9, 0x01}, + {0xEE01, 0x90, 0x01}, + {0xEE02, 0x6D, 0x01}, + {0xEE03, 0xEA, 0x01}, + {0xEE04, 0x93, 0x01}, + {0xEE05, 0x1A, 0x01}, + {0xEE06, 0xF3, 0x01}, + {0xEE07, 0xB8, 0x01}, + {0xEE08, 0xC6, 0x01}, + {0xEE09, 0x3D, 0x01}, + {0xEE0A, 0xC0, 0x01}, + {0xEE0B, 0x19, 0x01}, + {0xEE0C, 0xD0, 0x01}, + {0xEE0D, 0x78, 0x01}, + {0xEE0E, 0x64, 0x01}, + {0xEE0F, 0x24, 0x01}, + {0xEE10, 0xA1, 0x01}, + {0xEE11, 0x37, 0x01}, + {0xEE12, 0xD1, 0x01}, + {0xEE13, 0x89, 0x01}, + {0xEE14, 0x5A, 0x01}, + {0xEE15, 0x51, 0x01}, + {0xEE16, 0x72, 0x01}, + {0xEE17, 0xD5, 0x01}, + {0xEE18, 0x8C, 0x01}, + {0xEE19, 0x14, 0x01}, + {0xEE1A, 0x05, 0x01}, + {0xEE1B, 0xA1, 0x01}, + {0xEE1C, 0x33, 0x01}, + {0xEE1D, 0xF9, 0x01}, + {0xEE1E, 0xE7, 0x01}, + {0xEE1F, 0x4A, 0x01}, + {0xEE20, 0x01, 0x01}, + {0xEE21, 0xCA, 0x01}, + {0xEE22, 0xD2, 0x01}, + {0xEE23, 0x86, 0x01}, + {0xEE24, 0xE4, 0x01}, + {0xEE25, 0x94, 0x01}, + {0xEE26, 0x23, 0x01}, + {0xEE27, 0x4A, 0x01}, + {0xEE28, 0x55, 0x01}, + {0xEE29, 0x29, 0x01}, + {0xEE2A, 0x57, 0x01}, + {0xEE2B, 0x74, 0x01}, + {0xEE2C, 0x6A, 0x01}, + {0xEE2D, 0x14, 0x01}, + {0xEE2E, 0x95, 0x01}, + {0xEE2F, 0xEA, 0x01}, + {0xEE30, 0x94, 0x01}, + {0xEE31, 0xA3, 0x01}, + {0xEE32, 0x2C, 0x01}, + {0xEE33, 0x75, 0x01}, + {0xEE34, 0x28, 0x01}, + {0xEE35, 0x47, 0x01}, + {0xEE36, 0x0F, 0x01}, + {0xEE37, 0x2A, 0x01}, + {0xEE38, 0xD1, 0x01}, + {0xEE39, 0x84, 0x01}, + {0xEE3A, 0x4E, 0x01}, + {0xEE3B, 0x44, 0x01}, + {0xEE3C, 0x22, 0x01}, + {0xEE3D, 0x1E, 0x01}, + {0xEE3E, 0xE1, 0x01}, + {0xEE3F, 0x28, 0x01}, + {0xEE40, 0x4B, 0x01}, + {0xEE41, 0x4D, 0x01}, + {0xEE42, 0xC2, 0x01}, + {0xEE43, 0x53, 0x01}, + {0xEE44, 0x8D, 0x01}, + {0xEE45, 0xA4, 0x01}, + {0xEE46, 0xC4, 0x01}, + {0xEE47, 0x9F, 0x01}, + {0xEE48, 0x0B, 0x01}, + {0xEE49, 0x49, 0x01}, + {0xEE4A, 0xE7, 0x01}, + {0xEE4B, 0x3C, 0x01}, + {0xEE4C, 0xB5, 0x01}, + {0xEE4D, 0x29, 0x01}, + {0xEE4E, 0x8E, 0x01}, + {0xEE4F, 0x69, 0x01}, + {0xEE50, 0x6A, 0x01}, + {0xEE51, 0x93, 0x01}, + {0xEE52, 0x1A, 0x01}, + {0xEE53, 0xDC, 0x01}, + {0xEE54, 0xE0, 0x01}, + {0xEE55, 0x66, 0x01}, + {0xEE56, 0x39, 0x01}, + {0xEE57, 0xD7, 0x01}, + {0xEE58, 0x91, 0x01}, + {0xEE59, 0x8F, 0x01}, + {0xEE5A, 0x80, 0x01}, + {0xEE5B, 0x46, 0x01}, + {0xEE5C, 0xB4, 0x01}, + {0xEE5D, 0x1F, 0x01}, + {0xEE5E, 0x0C, 0x01}, + {0xEE5F, 0xE5, 0x01}, + {0xEE60, 0xC6, 0x01}, + {0xEE61, 0x39, 0x01}, + {0xEE62, 0x92, 0x01}, + {0xEE63, 0x01, 0x01}, + {0xEE64, 0x0D, 0x01}, + {0xEE65, 0x5E, 0x01}, + {0xEE66, 0x04, 0x01}, + {0xEE67, 0xB3, 0x01}, + {0xEE68, 0x16, 0x01}, + {0xEE69, 0xBA, 0x01}, + {0xEE6A, 0xB8, 0x01}, + {0xEE6B, 0x05, 0x01}, + {0xEE6C, 0x2F, 0x01}, + {0xEE6D, 0x7D, 0x01}, + {0xEE6E, 0x51, 0x01}, + {0xEE6F, 0xCC, 0x01}, + {0xEE70, 0x65, 0x01}, + {0xEE71, 0x52, 0x01}, + {0xEE72, 0x23, 0x01}, + {0xEE73, 0x9C, 0x01}, + {0xEE74, 0xED, 0x01}, + {0xEE75, 0x14, 0x01}, + {0xEE76, 0x67, 0x01}, + {0xEE77, 0x3B, 0x01}, + {0xEE78, 0x8D, 0x01}, + {0xEE79, 0xE1, 0x01}, + {0xEE7A, 0x0C, 0x01}, + {0xEE7B, 0x59, 0x01}, + {0xEE7C, 0xDE, 0x01}, + {0xEE7D, 0x42, 0x01}, + {0xEE7E, 0x94, 0x01}, + {0xEE7F, 0xA5, 0x01}, + {0xEE80, 0xDC, 0x01}, + {0xEE81, 0x64, 0x01}, + {0xEE82, 0x27, 0x01}, + {0xEE83, 0x3A, 0x01}, + {0xEE84, 0xF9, 0x01}, + {0xEE85, 0x89, 0x01}, + {0xEE86, 0x53, 0x01}, + {0xEE87, 0xAC, 0x01}, + {0xEE88, 0xE2, 0x01}, + {0xEE89, 0x96, 0x01}, + {0xEE8A, 0xBD, 0x01}, + {0xEE8B, 0x54, 0x01}, + {0xEE8C, 0xE6, 0x01}, + {0xEE8D, 0x34, 0x01}, + {0xEE8E, 0xAA, 0x01}, + {0xEE8F, 0xE1, 0x01}, + {0xEE90, 0x0D, 0x01}, + {0xEE91, 0x5C, 0x01}, + {0xEE92, 0xF8, 0x01}, + {0xEE93, 0xF2, 0x01}, + {0xEE94, 0x93, 0x01}, + {0xEE95, 0xA3, 0x01}, + {0xEE96, 0x78, 0x01}, + {0xEE97, 0x64, 0x01}, + {0xEE98, 0x24, 0x01}, + {0xEE99, 0x12, 0x01}, + {0xEE9A, 0x99, 0x01}, + {0xEE9B, 0x88, 0x01}, + {0xEE9C, 0x45, 0x01}, + {0xEE9D, 0x2C, 0x01}, + {0xEE9E, 0xA2, 0x01}, + {0xEE9F, 0x92, 0x01}, + {0xEEA0, 0x96, 0x01}, + {0xEEA1, 0x3C, 0x01}, + {0xEEA2, 0x05, 0x01}, + {0xEEA3, 0x2B, 0x01}, + {0xEEA4, 0x7F, 0x01}, + {0xEEA5, 0x79, 0x01}, + {0xEEA6, 0x8C, 0x01}, + {0xEEA7, 0x67, 0x01}, + {0xEEA8, 0x5E, 0x01}, + {0xEEA9, 0xF3, 0x01}, + {0xEEAA, 0x95, 0x01}, + {0xEEAB, 0xB4, 0x01}, + {0xEEAC, 0xB4, 0x01}, + {0xEEAD, 0x44, 0x01}, + {0xEEAE, 0x26, 0x01}, + {0xEEAF, 0x0C, 0x01}, + {0xEEB0, 0x79, 0x01}, + {0xEEB1, 0x08, 0x01}, + {0xEEB2, 0x40, 0x01}, + {0xEEB3, 0x02, 0x01}, + {0xEEB4, 0x42, 0x01}, + {0xEEB5, 0x90, 0x01}, + {0xEEB6, 0x81, 0x01}, + {0xEEB7, 0x60, 0x01}, + {0xEEB8, 0x24, 0x01}, + {0xEEB9, 0x23, 0x01}, + {0xEEBA, 0x3E, 0x01}, + {0xEEBB, 0x21, 0x01}, + {0xEEBC, 0x4A, 0x01}, + {0xEEBD, 0x5C, 0x01}, + {0xEEBE, 0xFE, 0x01}, + {0xEEBF, 0xE2, 0x01}, + {0xEEC0, 0x99, 0x01}, + {0xEEC1, 0xD5, 0x01}, + {0xEEC2, 0x7C, 0x01}, + {0xEEC3, 0xC5, 0x01}, + {0xEEC4, 0x2C, 0x01}, + {0xEEC5, 0x2B, 0x01}, + {0xEEC6, 0x89, 0x01}, + {0xEEC7, 0x09, 0x01}, + {0xEEC8, 0x43, 0x01}, + {0xEEC9, 0x1C, 0x01}, + {0xEECA, 0x02, 0x01}, + {0xEECB, 0x10, 0x01}, + {0xEECC, 0x80, 0x01}, + {0xEECD, 0x0C, 0x01}, + {0xEECE, 0x64, 0x01}, + {0xEECF, 0x20, 0x01}, + {0xEED0, 0x16, 0x01}, + {0xEED1, 0xC9, 0x01}, + {0xEED2, 0x08, 0x01}, + {0xEED3, 0x4F, 0x01}, + {0xEED4, 0x88, 0x01}, + {0xEED5, 0xE2, 0x01}, + {0xEED6, 0x96, 0x01}, + {0xEED7, 0xBF, 0x01}, + {0xEED8, 0xAC, 0x01}, + {0xEED9, 0xC6, 0x01}, + {0xEEDA, 0x36, 0x01}, + {0xEEDB, 0x70, 0x01}, + {0xEEDC, 0xB1, 0x01}, + {0xEEDD, 0xCB, 0x01}, + {0xEEDE, 0x4F, 0x01}, + {0xEEDF, 0x86, 0x01}, + {0xEEE0, 0xD2, 0x01}, + {0xEEE1, 0x11, 0x01}, + {0xEEE2, 0x90, 0x01}, + {0xEEE3, 0x3C, 0x01}, + {0xEEE4, 0x04, 0x01}, + {0xEEE5, 0x22, 0x01}, + {0xEEE6, 0x13, 0x01}, + {0xEEE7, 0xA1, 0x01}, + {0xEEE8, 0xC8, 0x01}, + {0xEEE9, 0x49, 0x01}, + {0xEEEA, 0x58, 0x01}, + {0xEEEB, 0xC2, 0x01}, + {0xEEEC, 0x94, 0x01}, + {0xEEED, 0xAB, 0x01}, + {0xEEEE, 0xE8, 0x01}, + {0xEEEF, 0xE5, 0x01}, + {0xEEF0, 0x31, 0x01}, + {0xEEF1, 0xC5, 0x01}, + {0xEEF2, 0x89, 0x01}, + {0xEEF3, 0x0E, 0x01}, + {0xEEF4, 0x63, 0x01}, + {0xEEF5, 0x26, 0x01}, + {0xEEF6, 0x33, 0x01}, + {0xEEF7, 0x96, 0x01}, + {0xEEF8, 0xB3, 0x01}, + {0xEEF9, 0x0C, 0x01}, + {0xEEFA, 0xA5, 0x01}, + {0xEEFB, 0x28, 0x01}, + {0xEEFC, 0x33, 0x01}, + {0xEEFD, 0xB1, 0x01}, + {0xEEFE, 0xC9, 0x01}, + {0xEEFF, 0x4D, 0x01}, + {0xEF00, 0x76, 0x01}, + {0xEF01, 0x92, 0x01}, + {0xEF02, 0x94, 0x01}, + {0xEF03, 0xA9, 0x01}, + {0xEF04, 0xA8, 0x01}, + {0xEF05, 0x25, 0x01}, + {0xEF06, 0x2F, 0x01}, + {0xEF07, 0x8E, 0x01}, + {0xEF08, 0x49, 0x01}, + {0xEF09, 0xCD, 0x01}, + {0xEF0A, 0x7E, 0x01}, + {0xEF0B, 0x06, 0x01}, + {0xEF0C, 0x94, 0x01}, + {0xEF0D, 0x9B, 0x01}, + {0xEF0E, 0xDF, 0x01}, + {0xEF0F, 0x44, 0x01}, + {0xEF10, 0xA6, 0x01}, + {0xEF11, 0x32, 0x01}, + {0xEF12, 0x75, 0x01}, + {0xEF13, 0xD9, 0x01}, + {0xEF14, 0xCB, 0x01}, + {0xEF15, 0x59, 0x01}, + {0xEF16, 0xDC, 0x01}, + {0xEF17, 0x82, 0x01}, + {0xEF18, 0x96, 0x01}, + {0xEF19, 0xB9, 0x01}, + {0xEF1A, 0xD4, 0x01}, + {0xEF1B, 0xC5, 0x01}, + {0xEF1C, 0x30, 0x01}, + {0xEF1D, 0x8E, 0x01}, + {0xEF1E, 0x41, 0x01}, + {0xEF1F, 0xCD, 0x01}, + {0xEF20, 0x6C, 0x01}, + {0xEF21, 0xAE, 0x01}, + {0xEF22, 0xD3, 0x01}, + {0xEF23, 0x22, 0x01}, + {0xEF24, 0x1C, 0x01}, + {0xEF25, 0xD5, 0x01}, + {0xEF26, 0x07, 0x01}, + {0xEF27, 0x40, 0x01}, + {0xEF28, 0xC7, 0x01}, + {0xEF29, 0x99, 0x01}, + {0xEF2A, 0xCE, 0x01}, + {0xEF2B, 0x6A, 0x01}, + {0xEF2C, 0x6A, 0x01}, + {0xEF2D, 0xC3, 0x01}, + {0xEF2E, 0x19, 0x01}, + {0xEF2F, 0xD5, 0x01}, + {0xEF30, 0x6C, 0x01}, + {0xEF31, 0xC6, 0x01}, + {0xEF32, 0x35, 0x01}, + {0xEF33, 0xA9, 0x01}, + {0xEF34, 0x09, 0x01}, + {0xEF35, 0x4E, 0x01}, + {0xEF36, 0x71, 0x01}, + {0xEF37, 0xCA, 0x01}, + {0xEF38, 0xC3, 0x01}, + {0xEF39, 0x1E, 0x01}, + {0xEF3A, 0x0A, 0x01}, + {0xEF3B, 0x55, 0x01}, + {0xEF3C, 0x09, 0x01}, + {0xEF3D, 0x4D, 0x01}, + {0xEF3E, 0x39, 0x01}, + {0xEF3F, 0x8A, 0x01}, + {0xEF40, 0x52, 0x01}, + {0xEF41, 0x86, 0x01}, + {0xEF42, 0x6E, 0x01}, + {0xEF43, 0xD4, 0x01}, + {0xEF44, 0x1F, 0x01}, + {0xEF45, 0x09, 0x01}, + {0xEF46, 0xA1, 0x01}, + {0xEF47, 0x87, 0x01}, + {0xEF48, 0x40, 0x01}, + {0xEF49, 0xE5, 0x01}, + {0xEF4A, 0x39, 0x01}, + {0xEF4B, 0x10, 0x01}, + {0xEF4C, 0x7E, 0x01}, + {0xEF4D, 0x40, 0x01}, + {0xEF4E, 0x14, 0x01}, + {0xEF4F, 0x21, 0x01}, + {0xEF50, 0x1F, 0x01}, + {0xEF51, 0x81, 0x01}, + {0xEF52, 0x08, 0x01}, + {0xEF53, 0x4B, 0x01}, + + + {0xEF54, 0xC7, 0x01}, + {0xEF55, 0x82, 0x01}, + {0xEF56, 0x55, 0x01}, + {0xEF57, 0xA6, 0x01}, + {0xEF58, 0xEE, 0x01}, + {0xEF59, 0xA4, 0x01}, + {0xEF5A, 0x25, 0x01}, + {0xEF5B, 0x2F, 0x01}, + {0xEF5C, 0xD5, 0x01}, + {0xEF5D, 0x09, 0x01}, + {0xEF5E, 0x52, 0x01}, + {0xEF5F, 0x96, 0x01}, + {0xEF60, 0x02, 0x01}, + {0xEF61, 0x94, 0x01}, + {0xEF62, 0x8F, 0x01}, + {0xEF63, 0x0C, 0x01}, + {0xEF64, 0x34, 0x01}, + {0xEF65, 0x1E, 0x01}, + {0xEF66, 0xE7, 0x01}, + {0xEF67, 0x40, 0x01}, + {0xEF68, 0xE7, 0x01}, + {0xEF69, 0x3C, 0x01}, + {0xEF6A, 0x14, 0x01}, + {0xEF6B, 0x4A, 0x01}, + {0xEF6C, 0x92, 0x01}, + {0xEF6D, 0x90, 0x01}, + {0xEF6E, 0xD0, 0x01}, + {0xEF6F, 0x13, 0x01}, + {0xEF70, 0x1B, 0x01}, + {0xEF71, 0xC7, 0x01}, + {0xEF72, 0xF8, 0x01}, + {0xEF73, 0x25, 0x01}, + {0xEF74, 0x30, 0x01}, + {0xEF75, 0x98, 0x01}, + {0xEF76, 0x19, 0x01}, + {0xEF77, 0x4E, 0x01}, + {0xEF78, 0x81, 0x01}, + {0xEF79, 0x02, 0x01}, + {0xEF7A, 0xE4, 0x01}, + {0xEF7B, 0x1A, 0x01}, + {0xEF7C, 0xBA, 0x01}, + {0xEF7D, 0x30, 0x01}, + {0xEF7E, 0x45, 0x01}, + {0xEF7F, 0x27, 0x01}, + {0xEF80, 0x3F, 0x01}, + {0xEF81, 0xD1, 0x01}, + {0xEF82, 0x4A, 0x01}, + {0xEF83, 0x62, 0x01}, + {0xEF84, 0x88, 0x01}, + {0xEF85, 0xA3, 0x01}, + {0xEF86, 0x1D, 0x01}, + {0xEF87, 0xC3, 0x01}, + {0xEF88, 0x20, 0x01}, + {0xEF89, 0x25, 0x01}, + {0xEF8A, 0x24, 0x01}, + {0xEF8B, 0x10, 0x01}, + {0xEF8C, 0x99, 0x01}, + {0xEF8D, 0x48, 0x01}, + {0xEF8E, 0x4B, 0x01}, + {0xEF8F, 0xBE, 0x01}, + {0xEF90, 0x42, 0x01}, + {0xEF91, 0x1A, 0x01}, + {0xEF92, 0xE4, 0x01}, + {0xEF93, 0xC4, 0x01}, + {0xEF94, 0x45, 0x01}, + {0xEF95, 0x26, 0x01}, + {0xEF96, 0x0E, 0x01}, + {0xEF97, 0x01, 0x01}, + {0xEF98, 0x88, 0x01}, + {0xEF99, 0x40, 0x01}, + {0xEF9A, 0x34, 0x01}, + {0xEF9B, 0xB2, 0x01}, + {0xEF9C, 0x94, 0x01}, + {0xEF9D, 0xC9, 0x01}, + {0xEF9E, 0x24, 0x01}, + {0xEF9F, 0x47, 0x01}, + {0xEFA0, 0x2E, 0x01}, + {0xEFA1, 0x33, 0x01}, + {0xEFA2, 0x71, 0x01}, + {0xEFA3, 0x08, 0x01}, + {0xEFA4, 0x40, 0x01}, + {0xEFA5, 0x08, 0x01}, + {0xEFA6, 0xB2, 0x01}, + {0xEFA7, 0x11, 0x01}, + {0xEFA8, 0xA6, 0x01}, + {0xEFA9, 0x50, 0x01}, + {0xEFAA, 0x26, 0x01}, + {0xEFAB, 0x3B, 0x01}, + {0xEFAC, 0x86, 0x01}, + {0xEFAD, 0x51, 0x01}, + {0xEFAE, 0x8A, 0x01}, + {0xEFAF, 0x48, 0x01}, + {0xEFB0, 0x24, 0x01}, + {0xEFB1, 0x82, 0x01}, + {0xEFB2, 0x91, 0x01}, + {0xEFB3, 0x98, 0x01}, + {0xEFB4, 0x8C, 0x01}, + {0xEFB5, 0x25, 0x01}, + {0xEFB6, 0x35, 0x01}, + {0xEFB7, 0xFF, 0x01}, + {0xEFB8, 0x71, 0x01}, + {0xEFB9, 0x8D, 0x01}, + {0xEFBA, 0x5D, 0x01}, + {0xEFBB, 0x9E, 0x01}, + {0xEFBC, 0xE2, 0x01}, + {0xEFBD, 0x13, 0x01}, + {0xEFBE, 0xA2, 0x01}, + {0xEFBF, 0x7C, 0x01}, + {0xEFC0, 0xC5, 0x01}, + {0xEFC1, 0x31, 0x01}, + {0xEFC2, 0xCB, 0x01}, + {0xEFC3, 0x09, 0x01}, + {0xEFC4, 0x52, 0x01}, + {0xEFC5, 0x7A, 0x01}, + {0xEFC6, 0x62, 0x01}, + {0xEFC7, 0xF3, 0x01}, + {0xEFC8, 0x98, 0x01}, + {0xEFC9, 0xC0, 0x01}, + {0xEFCA, 0x24, 0x01}, + {0xEFCB, 0x06, 0x01}, + {0xEFCC, 0x34, 0x01}, + {0xEFCD, 0xCA, 0x01}, + {0xEFCE, 0x29, 0x01}, + {0xEFCF, 0x10, 0x01}, + {0xEFD0, 0xA0, 0x01}, + {0xEFD1, 0x72, 0x01}, + {0xEFD2, 0xE4, 0x01}, + {0xEFD3, 0x1F, 0x01}, + {0xEFD4, 0xEE, 0x01}, + {0xEFD5, 0x38, 0x01}, + {0xEFD6, 0xA7, 0x01}, + {0xEFD7, 0x3A, 0x01}, + {0xEFD8, 0xEA, 0x01}, + {0xEFD9, 0xB1, 0x01}, + {0xEFDA, 0xD0, 0x01}, + {0xEFDB, 0x93, 0x01}, + {0xEFDC, 0x56, 0x01}, + {0xEFDD, 0x95, 0x01}, + {0xEFDE, 0x28, 0x01}, + {0xEFDF, 0x33, 0x01}, + {0xEFE0, 0x25, 0x01}, + {0xEFE1, 0xE9, 0x01}, + {0xEFE2, 0x46, 0x01}, + {0xEFE3, 0x3A, 0x01}, + {0xEFE4, 0x8A, 0x01}, + {0xEFE5, 0x52, 0x01}, + {0xEFE6, 0x9D, 0x01}, + {0xEFE7, 0x24, 0x01}, + {0xEFE8, 0x05, 0x01}, + {0xEFE9, 0x00, 0x01}, + {0xEFEA, 0x00, 0x01}, + {0xEFEB, 0x00, 0x01}, + {0xEFEC, 0x00, 0x01}, + {0xEFED, 0x00, 0x01}, + + /*SHD3 D 65+TL 84 C01*/ + {0xED00, 0x9191, 0x02}, + {0xEFEE, 0x22, 0x01}, + {0xEFEF, 0xBA, 0x01}, + {0xEFF0, 0xD1, 0x01}, + {0xEFF1, 0x8C, 0x01}, + {0xEFF2, 0x50, 0x01}, + {0xEFF3, 0xA4, 0x01}, + {0xEFF4, 0x22, 0x01}, + {0xEFF5, 0x17, 0x01}, + {0xEFF6, 0xE9, 0x01}, + {0xEFF7, 0x88, 0x01}, + {0xEFF8, 0x47, 0x01}, + {0xEFF9, 0x29, 0x01}, + {0xEFFA, 0xBA, 0x01}, + {0xEFFB, 0x50, 0x01}, + {0xEFFC, 0x80, 0x01}, + {0xEFFD, 0xD0, 0x01}, + {0xEFFE, 0x73, 0x01}, + {0xEFFF, 0x1D, 0x01}, + {0xF000, 0xE9, 0x01}, + {0xF001, 0x6C, 0x01}, + {0xF002, 0x87, 0x01}, + {0xF003, 0x3D, 0x01}, + {0xF004, 0x05, 0x01}, + {0xF005, 0xE2, 0x01}, + {0xF006, 0xD0, 0x01}, + {0xF007, 0x7D, 0x01}, + {0xF008, 0xA2, 0x01}, + {0xF009, 0xF3, 0x01}, + {0xF00A, 0x9A, 0x01}, + {0xF00B, 0xC9, 0x01}, + {0xF00C, 0x2C, 0x01}, + {0xF00D, 0xA6, 0x01}, + {0xF00E, 0x32, 0x01}, + {0xF00F, 0xAF, 0x01}, + {0xF010, 0xB1, 0x01}, + {0xF011, 0x0E, 0x01}, + {0xF012, 0x82, 0x01}, + {0xF013, 0xAE, 0x01}, + {0xF014, 0x33, 0x01}, + {0xF015, 0x1A, 0x01}, + {0xF016, 0xB9, 0x01}, + {0xF017, 0x48, 0x01}, + {0xF018, 0x25, 0x01}, + {0xF019, 0x29, 0x01}, + {0xF01A, 0x54, 0x01}, + {0xF01B, 0xA9, 0x01}, + {0xF01C, 0x0B, 0x01}, + {0xF01D, 0x6B, 0x01}, + {0xF01E, 0xD0, 0x01}, + {0xF01F, 0xE3, 0x01}, + {0xF020, 0x9B, 0x01}, + {0xF021, 0xBE, 0x01}, + {0xF022, 0x18, 0x01}, + {0xF023, 0x85, 0x01}, + {0xF024, 0x24, 0x01}, + {0xF025, 0x19, 0x01}, + {0xF026, 0x29, 0x01}, + {0xF027, 0xC9, 0x01}, + {0xF028, 0x52, 0x01}, + {0xF029, 0x08, 0x01}, + {0xF02A, 0x93, 0x01}, + {0xF02B, 0x1C, 0x01}, + {0xF02C, 0xD8, 0x01}, + {0xF02D, 0xA8, 0x01}, + {0xF02E, 0x05, 0x01}, + {0xF02F, 0x26, 0x01}, + {0xF030, 0x0B, 0x01}, + {0xF031, 0x01, 0x01}, + {0xF032, 0x88, 0x01}, + {0xF033, 0x43, 0x01}, + {0xF034, 0x6C, 0x01}, + {0xF035, 0xE2, 0x01}, + {0xF036, 0x96, 0x01}, + {0xF037, 0xDB, 0x01}, + {0xF038, 0xC4, 0x01}, + {0xF039, 0x66, 0x01}, + {0xF03A, 0x2D, 0x01}, + {0xF03B, 0x31, 0x01}, + {0xF03C, 0x59, 0x01}, + {0xF03D, 0x48, 0x01}, + {0xF03E, 0x40, 0x01}, + {0xF03F, 0x20, 0x01}, + {0xF040, 0x62, 0x01}, + {0xF041, 0x13, 0x01}, + {0xF042, 0xB8, 0x01}, + {0xF043, 0xF0, 0x01}, + {0xF044, 0x86, 0x01}, + {0xF045, 0x38, 0x01}, + {0xF046, 0x82, 0x01}, + {0xF047, 0x49, 0x01}, + {0xF048, 0x0A, 0x01}, + {0xF049, 0x49, 0x01}, + {0xF04A, 0x34, 0x01}, + {0xF04B, 0x92, 0x01}, + {0xF04C, 0x12, 0x01}, + {0xF04D, 0xA7, 0x01}, + {0xF04E, 0x1C, 0x01}, + {0xF04F, 0xE6, 0x01}, + {0xF050, 0x39, 0x01}, + {0xF051, 0xE2, 0x01}, + {0xF052, 0x41, 0x01}, + {0xF053, 0x8D, 0x01}, + {0xF054, 0x5D, 0x01}, + {0xF055, 0xAA, 0x01}, + {0xF056, 0xC2, 0x01}, + {0xF057, 0x94, 0x01}, + {0xF058, 0xAC, 0x01}, + {0xF059, 0xF4, 0x01}, + {0xF05A, 0x65, 0x01}, + {0xF05B, 0x36, 0x01}, + {0xF05C, 0xF1, 0x01}, + {0xF05D, 0x31, 0x01}, + {0xF05E, 0x90, 0x01}, + {0xF05F, 0x76, 0x01}, + {0xF060, 0x62, 0x01}, + {0xF061, 0x83, 0x01}, + {0xF062, 0x19, 0x01}, + {0xF063, 0xC7, 0x01}, + {0xF064, 0x6C, 0x01}, + {0xF065, 0x26, 0x01}, + {0xF066, 0x37, 0x01}, + {0xF067, 0xE2, 0x01}, + {0xF068, 0x89, 0x01}, + {0xF069, 0xD0, 0x01}, + {0xF06A, 0x87, 0x01}, + {0xF06B, 0x0C, 0x01}, + {0xF06C, 0xC4, 0x01}, + {0xF06D, 0x1E, 0x01}, + {0xF06E, 0xEE, 0x01}, + {0xF06F, 0x58, 0x01}, + {0xF070, 0x07, 0x01}, + {0xF071, 0x3C, 0x01}, + {0xF072, 0xF4, 0x01}, + {0xF073, 0x81, 0x01}, + {0xF074, 0x90, 0x01}, + {0xF075, 0x8B, 0x01}, + {0xF076, 0x3C, 0x01}, + {0xF077, 0xA4, 0x01}, + {0xF078, 0xA2, 0x01}, + {0xF079, 0x10, 0x01}, + {0xF07A, 0x69, 0x01}, + {0xF07B, 0x48, 0x01}, + {0xF07C, 0x43, 0x01}, + {0xF07D, 0x20, 0x01}, + {0xF07E, 0x62, 0x01}, + {0xF07F, 0x51, 0x01}, + {0xF080, 0x8C, 0x01}, + {0xF081, 0x50, 0x01}, + {0xF082, 0x04, 0x01}, + {0xF083, 0x00, 0x01}, + {0xF084, 0x00, 0x01}, + {0xF085, 0x00, 0x01}, + {0xF086, 0x00, 0x01}, + {0xF087, 0x00, 0x01}, + {0xF088, 0xBB, 0x01}, + {0xF089, 0x41, 0x01}, + {0xF08A, 0x0E, 0x01}, + {0xF08B, 0x6F, 0x01}, + {0xF08C, 0x68, 0x01}, + {0xF08D, 0x23, 0x01}, + {0xF08E, 0x9B, 0x01}, + {0xF08F, 0xD9, 0x01}, + {0xF090, 0xE8, 0x01}, + {0xF091, 0x06, 0x01}, + {0xF092, 0x38, 0x01}, + {0xF093, 0xB9, 0x01}, + {0xF094, 0xB9, 0x01}, + {0xF095, 0x4D, 0x01}, + {0xF096, 0x69, 0x01}, + {0xF097, 0x24, 0x01}, + {0xF098, 0x83, 0x01}, + {0xF099, 0x98, 0x01}, + {0xF09A, 0xC1, 0x01}, + {0xF09B, 0x1C, 0x01}, + {0xF09C, 0x06, 0x01}, + {0xF09D, 0x32, 0x01}, + {0xF09E, 0xA4, 0x01}, + {0xF09F, 0xA9, 0x01}, + {0xF0A0, 0x4D, 0x01}, + {0xF0A1, 0x67, 0x01}, + {0xF0A2, 0x0C, 0x01}, + {0xF0A3, 0x13, 0x01}, + {0xF0A4, 0x97, 0x01}, + {0xF0A5, 0xB0, 0x01}, + {0xF0A6, 0x6C, 0x01}, + {0xF0A7, 0x25, 0x01}, + {0xF0A8, 0x2C, 0x01}, + {0xF0A9, 0x70, 0x01}, + {0xF0AA, 0x39, 0x01}, + {0xF0AB, 0xCC, 0x01}, + {0xF0AC, 0x68, 0x01}, + {0xF0AD, 0x10, 0x01}, + {0xF0AE, 0xA3, 0x01}, + {0xF0AF, 0x96, 0x01}, + {0xF0B0, 0xA6, 0x01}, + {0xF0B1, 0xE4, 0x01}, + {0xF0B2, 0x44, 0x01}, + {0xF0B3, 0x26, 0x01}, + {0xF0B4, 0x3A, 0x01}, + {0xF0B5, 0x79, 0x01}, + {0xF0B6, 0x4A, 0x01}, + {0xF0B7, 0x5B, 0x01}, + {0xF0B8, 0x18, 0x01}, + {0xF0B9, 0x93, 0x01}, + {0xF0BA, 0x17, 0x01}, + {0xF0BB, 0xA9, 0x01}, + {0xF0BC, 0xBC, 0x01}, + {0xF0BD, 0x24, 0x01}, + {0xF0BE, 0x23, 0x01}, + {0xF0BF, 0x12, 0x01}, + {0xF0C0, 0xE1, 0x01}, + {0xF0C1, 0xC8, 0x01}, + {0xF0C2, 0x4C, 0x01}, + {0xF0C3, 0xAA, 0x01}, + {0xF0C4, 0xA2, 0x01}, + {0xF0C5, 0x17, 0x01}, + {0xF0C6, 0xB6, 0x01}, + {0xF0C7, 0x10, 0x01}, + {0xF0C8, 0x05, 0x01}, + {0xF0C9, 0x24, 0x01}, + {0xF0CA, 0x06, 0x01}, + {0xF0CB, 0x09, 0x01}, + {0xF0CC, 0xC8, 0x01}, + {0xF0CD, 0x42, 0x01}, + {0xF0CE, 0x4A, 0x01}, + {0xF0CF, 0x82, 0x01}, + {0xF0D0, 0x94, 0x01}, + {0xF0D1, 0xB8, 0x01}, + {0xF0D2, 0xC0, 0x01}, + {0xF0D3, 0xE5, 0x01}, + {0xF0D4, 0x28, 0x01}, + {0xF0D5, 0x21, 0x01}, + {0xF0D6, 0x39, 0x01}, + {0xF0D7, 0x08, 0x01}, + {0xF0D8, 0x40, 0x01}, + {0xF0D9, 0x16, 0x01}, + {0xF0DA, 0x62, 0x01}, + {0xF0DB, 0x92, 0x01}, + {0xF0DC, 0xA4, 0x01}, + {0xF0DD, 0xC4, 0x01}, + {0xF0DE, 0xE5, 0x01}, + {0xF0DF, 0x2F, 0x01}, + {0xF0E0, 0x58, 0x01}, + {0xF0E1, 0x99, 0x01}, + {0xF0E2, 0x49, 0x01}, + {0xF0E3, 0x46, 0x01}, + {0xF0E4, 0x22, 0x01}, + {0xF0E5, 0xC2, 0x01}, + {0xF0E6, 0x91, 0x01}, + {0xF0E7, 0x9A, 0x01}, + {0xF0E8, 0x58, 0x01}, + {0xF0E9, 0xA5, 0x01}, + {0xF0EA, 0x2F, 0x01}, + {0xF0EB, 0x95, 0x01}, + {0xF0EC, 0x99, 0x01}, + {0xF0ED, 0x4B, 0x01}, + {0xF0EE, 0x54, 0x01}, + {0xF0EF, 0x74, 0x01}, + {0xF0F0, 0x32, 0x01}, + {0xF0F1, 0x93, 0x01}, + {0xF0F2, 0x9D, 0x01}, + {0xF0F3, 0x38, 0x01}, + {0xF0F4, 0xC5, 0x01}, + {0xF0F5, 0x2D, 0x01}, + {0xF0F6, 0x90, 0x01}, + {0xF0F7, 0x59, 0x01}, + {0xF0F8, 0x0D, 0x01}, + {0xF0F9, 0x64, 0x01}, + {0xF0FA, 0xEE, 0x01}, + {0xF0FB, 0x62, 0x01}, + {0xF0FC, 0x96, 0x01}, + {0xF0FD, 0xAE, 0x01}, + {0xF0FE, 0x84, 0x01}, + {0xF0FF, 0x25, 0x01}, + {0xF100, 0x2E, 0x01}, + {0xF101, 0x8A, 0x01}, + {0xF102, 0x29, 0x01}, + {0xF103, 0x8D, 0x01}, + {0xF104, 0x6F, 0x01}, + {0xF105, 0x60, 0x01}, + {0xF106, 0xD3, 0x01}, + {0xF107, 0x19, 0x01}, + {0xF108, 0xC7, 0x01}, + {0xF109, 0x18, 0x01}, + {0xF10A, 0x26, 0x01}, + {0xF10B, 0x31, 0x01}, + {0xF10C, 0x97, 0x01}, + {0xF10D, 0x41, 0x01}, + {0xF10E, 0x8D, 0x01}, + {0xF10F, 0x6D, 0x01}, + {0xF110, 0x84, 0x01}, + {0xF111, 0xE3, 0x01}, + {0xF112, 0x1C, 0x01}, + {0xF113, 0xE3, 0x01}, + {0xF114, 0xDC, 0x01}, + {0xF115, 0x26, 0x01}, + {0xF116, 0x36, 0x01}, + {0xF117, 0xB6, 0x01}, + {0xF118, 0xF1, 0x01}, + {0xF119, 0x4D, 0x01}, + {0xF11A, 0x70, 0x01}, + {0xF11B, 0x68, 0x01}, + {0xF11C, 0x03, 0x01}, + {0xF11D, 0x00, 0x01}, + {0xF11E, 0x00, 0x01}, + {0xF11F, 0x00, 0x01}, + {0xF120, 0x00, 0x01}, + {0xF121, 0x00, 0x01}, + + + /*SHD TH*/ + {0x6C32, 0x16A8, 0x02}, /* SHD_INP_TH_HB_H_R2*/ + {0x6C34, 0x1612, 0x02}, /* SHD_INP_TH_HB_L_R2*/ + {0x6C36, 0x10CC, 0x02}, /* SHD_INP_TH_LB_H_R2*/ + {0x6C38, 0x1004, 0x02}, /* SHD_INP_TH_LB_L_R2*/ + {0x6C3C, 0x10CC, 0x02}, /* SHD_INP_TH_HB_H_RB*/ + {0x6C3E, 0x1004, 0x02}, /* SHD_INP_TH_HB_L_RB*/ + {0x6C40, 0x0000, 0x02}, /* SHD_INP_TH_LB_H_RB*/ + {0x6C42, 0x0000, 0x02}, /* SHD_INP_TH_LB_L_RB*/ + + /*PreWB_offset (for SHD2)*/ + {0x6828, 0x0013, 0x02}, /* SHD_PRER_OFFSET_R2 :*/ + /*PreWB_offset (for SHD3)*/ + {0x682C, 0x000C, 0x02}, /* SHD_PRER_OFFSET_RB :*/ + {0x6830, 0xFFFF, 0x02}, /* SHD_PREB_OFFSET_RB :*/ + + /* CXC/SHD EN*/ + {0x01BC, 0x57, 0x01}, /* CXC ON SHD ON INP ON GAIN OFF*/ + + /*#36*/ + {0x6804, 0x1122, 0x02}, /* NORMR*/ + {0x6806, 0x116B, 0x02}, /* NORMB*/ + {0x6808, 0x0150, 0x02}, /* AWBPRER*/ + {0x680A, 0x0245, 0x02}, /* AWBPREB*/ + {0x6810, 0x1001, 0x02}, /* AWB_PRE_ADJ_RG*/ + {0x6812, 0x0FC9, 0x02}, /* AWB_PRE_ADJ_BG*/ + {0x6814, 0x0A73, 0x02}, /* AWB_C14_RG*/ + {0x6816, 0x17EA, 0x02}, /* AWB_C14_BG*/ +}; + +struct isx012_short_t ISX012_Shading_1[] = { + {0x01BC, 0x50, 0x01}, /* CXC OFF SHD OFF*/ + + {0xEB00, 0x8282, 0x02}, /*valid_code*/ + {0xEB02, 0xFF, 0x01}, + {0xEB03, 0xC4, 0x01}, + {0xEB04, 0x3F, 0x01}, + {0xEB05, 0xF1, 0x01}, + {0xEB06, 0x3F, 0x01}, + {0xEB07, 0x00, 0x01}, + {0xEB08, 0x12, 0x01}, + {0xEB09, 0x7E, 0x01}, + {0xEB0A, 0x83, 0x01}, + {0xEB0B, 0xFF, 0x01}, + {0xEB0C, 0xF0, 0x01}, + {0xEB0D, 0x47, 0x01}, + {0xEB0E, 0x04, 0x01}, + {0xEB0F, 0x12, 0x01}, + {0xEB10, 0x81, 0x01}, + {0xEB11, 0xC4, 0x01}, + {0xEB12, 0x3F, 0x01}, + {0xEB13, 0xF1, 0x01}, + {0xEB14, 0x4F, 0x01}, + {0xEB15, 0xFC, 0x01}, + {0xEB16, 0x0F, 0x01}, + {0xEB17, 0x80, 0x01}, + {0xEB18, 0x84, 0x01}, + {0xEB19, 0xDF, 0x01}, + {0xEB1A, 0xE0, 0x01}, + {0xEB1B, 0x3F, 0x01}, + {0xEB1C, 0xFC, 0x01}, + {0xEB1D, 0x11, 0x01}, + {0xEB1E, 0x81, 0x01}, + {0xEB1F, 0x44, 0x01}, + {0xEB20, 0x20, 0x01}, + {0xEB21, 0x11, 0x01}, + {0xEB22, 0x38, 0x01}, + {0xEB23, 0x04, 0x01}, + {0xEB24, 0x0E, 0x01}, + {0xEB25, 0x01, 0x01}, + {0xEB26, 0xC3, 0x01}, + {0xEB27, 0xBF, 0x01}, + {0xEB28, 0x00, 0x01}, + {0xEB29, 0x30, 0x01}, + {0xEB2A, 0x00, 0x01}, + {0xEB2B, 0x0C, 0x01}, + {0xEB2C, 0x82, 0x01}, + {0xEB2D, 0x43, 0x01}, + {0xEB2E, 0x40, 0x01}, + {0xEB2F, 0x11, 0x01}, + {0xEB30, 0x50, 0x01}, + {0xEB31, 0x08, 0x01}, + {0xEB32, 0x0E, 0x01}, + {0xEB33, 0x82, 0x01}, + {0xEB34, 0xC3, 0x01}, + {0xEB35, 0xA0, 0x01}, + {0xEB36, 0x00, 0x01}, + {0xEB37, 0x18, 0x01}, + {0xEB38, 0x00, 0x01}, + {0xEB39, 0x04, 0x01}, + {0xEB3A, 0x81, 0x01}, + {0xEB3B, 0x01, 0x01}, + {0xEB3C, 0xC0, 0x01}, + {0xEB3D, 0x00, 0x01}, + {0xEB3E, 0x38, 0x01}, + {0xEB3F, 0x00, 0x01}, + {0xEB40, 0x0E, 0x01}, + {0xEB41, 0x83, 0x01}, + {0xEB42, 0xC2, 0x01}, + {0xEB43, 0xA0, 0x01}, + {0xEB44, 0x10, 0x01}, + {0xEB45, 0x18, 0x01}, + {0xEB46, 0x00, 0x01}, + {0xEB47, 0x04, 0x01}, + {0xEB48, 0x01, 0x01}, + {0xEB49, 0x01, 0x01}, + {0xEB4A, 0x00, 0x01}, + {0xEB4B, 0x00, 0x01}, + {0xEB4C, 0x18, 0x01}, + {0xEB4D, 0x08, 0x01}, + {0xEB4E, 0x0A, 0x01}, + {0xEB4F, 0x82, 0x01}, + {0xEB50, 0x02, 0x01}, + {0xEB51, 0x60, 0x01}, + {0xEB52, 0x00, 0x01}, + {0xEB53, 0x18, 0x01}, + {0xEB54, 0x04, 0x01}, + {0xEB55, 0x02, 0x01}, + {0xEB56, 0x81, 0x01}, + {0xEB57, 0x40, 0x01}, + {0xEB58, 0x20, 0x01}, + {0xEB59, 0x00, 0x01}, + {0xEB5A, 0x08, 0x01}, + {0xEB5B, 0x04, 0x01}, + {0xEB5C, 0x04, 0x01}, + {0xEB5D, 0x02, 0x01}, + {0xEB5E, 0x82, 0x01}, + {0xEB5F, 0x80, 0x01}, + {0xEB60, 0x30, 0x01}, + {0xEB61, 0x18, 0x01}, + {0xEB62, 0x0C, 0x01}, + {0xEB63, 0x06, 0x01}, + {0xEB64, 0x82, 0x01}, + {0xEB65, 0xC0, 0x01}, + {0xEB66, 0xFF, 0x01}, + {0xEB67, 0x0F, 0x01}, + {0xEB68, 0x00, 0x01}, + {0xEB69, 0x04, 0x01}, + {0xEB6A, 0x00, 0x01}, + {0xEB6B, 0x80, 0x01}, + {0xEB6C, 0x00, 0x01}, + {0xEB6D, 0x40, 0x01}, + {0xEB6E, 0x00, 0x01}, + {0xEB6F, 0x10, 0x01}, + {0xEB70, 0x00, 0x01}, + {0xEB71, 0x04, 0x01}, + {0xEB72, 0x00, 0x01}, + {0xEB73, 0x81, 0x01}, + {0xEB74, 0x60, 0x01}, + {0xEB75, 0x20, 0x01}, + {0xEB76, 0x00, 0x01}, + {0xEB77, 0x04, 0x01}, + {0xEB78, 0xFE, 0x01}, + {0xEB79, 0x82, 0x01}, + {0xEB7A, 0xC0, 0x01}, + {0xEB7B, 0x40, 0x01}, + {0xEB7C, 0x30, 0x01}, + {0xEB7D, 0x18, 0x01}, + {0xEB7E, 0x0C, 0x01}, + {0xEB7F, 0x06, 0x01}, + {0xEB80, 0x80, 0x01}, + {0xEB81, 0x01, 0x01}, + {0xEB82, 0x60, 0x01}, + {0xEB83, 0x30, 0x01}, + {0xEB84, 0x18, 0x01}, + {0xEB85, 0x08, 0x01}, + {0xEB86, 0x04, 0x01}, + {0xEB87, 0x80, 0x01}, + {0xEB88, 0xC0, 0x01}, + {0xEB89, 0x40, 0x01}, + {0xEB8A, 0x20, 0x01}, + {0xEB8B, 0x10, 0x01}, + {0xEB8C, 0x0C, 0x01}, + {0xEB8D, 0x06, 0x01}, + {0xEB8E, 0x83, 0x01}, + {0xEB8F, 0x41, 0x01}, + {0xEB90, 0x80, 0x01}, + {0xEB91, 0x10, 0x01}, + {0xEB92, 0x20, 0x01}, + {0xEB93, 0x04, 0x01}, + {0xEB94, 0x06, 0x01}, + {0xEB95, 0x82, 0x01}, + {0xEB96, 0x41, 0x01}, + {0xEB97, 0x60, 0x01}, + {0xEB98, 0x30, 0x01}, + {0xEB99, 0x28, 0x01}, + {0xEB9A, 0x08, 0x01}, + {0xEB9B, 0x08, 0x01}, + {0xEB9C, 0x82, 0x01}, + {0xEB9D, 0x82, 0x01}, + {0xEB9E, 0xA0, 0x01}, + {0xEB9F, 0xE0, 0x01}, + {0xEBA0, 0x2F, 0x01}, + {0xEBA1, 0xF8, 0x01}, + {0xEBA2, 0x0B, 0x01}, + {0xEBA3, 0x02, 0x01}, + {0xEBA4, 0x42, 0x01}, + {0xEBA5, 0xA0, 0x01}, + {0xEBA6, 0x20, 0x01}, + {0xEBA7, 0x28, 0x01}, + {0xEBA8, 0x10, 0x01}, + {0xEBA9, 0x0C, 0x01}, + {0xEBAA, 0x03, 0x01}, + {0xEBAB, 0x82, 0x01}, + {0xEBAC, 0xA0, 0x01}, + {0xEBAD, 0x20, 0x01}, + {0xEBAE, 0x28, 0x01}, + {0xEBAF, 0xF8, 0x01}, + {0xEBB0, 0x0B, 0x01}, + {0xEBB1, 0xFE, 0x01}, + {0xEBB2, 0x82, 0x01}, + {0xEBB3, 0x80, 0x01}, + {0xEBB4, 0x10, 0x01}, + {0xEBB5, 0x28, 0x01}, + {0xEBB6, 0x08, 0x01}, + {0xEBB7, 0x0A, 0x01}, + {0xEBB8, 0x04, 0x01}, + {0xEBB9, 0xC3, 0x01}, + {0xEBBA, 0x80, 0x01}, + {0xEBBB, 0x20, 0x01}, + {0xEBBC, 0x28, 0x01}, + {0xEBBD, 0x08, 0x01}, + {0xEBBE, 0x0A, 0x01}, + {0xEBBF, 0x03, 0x01}, + {0xEBC0, 0xFB, 0x01}, + {0xEBC1, 0xC0, 0x01}, + {0xEBC2, 0x3E, 0x01}, + {0xEBC3, 0xC0, 0x01}, + {0xEBC4, 0x0F, 0x01}, + {0xEBC5, 0xF4, 0x01}, + {0xEBC6, 0x02, 0x01}, + {0xEBC7, 0xFC, 0x01}, + {0xEBC8, 0x20, 0x01}, + {0xEBC9, 0x2F, 0x01}, + {0xEBCA, 0xB8, 0x01}, + {0xEBCB, 0x03, 0x01}, + {0xEBCC, 0xF8, 0x01}, + {0xEBCD, 0x00, 0x01}, + {0xEBCE, 0xFE, 0x01}, + {0xEBCF, 0xC0, 0x01}, + {0xEBD0, 0x3E, 0x01}, + {0xEBD1, 0xB0, 0x01}, + {0xEBD2, 0x0F, 0x01}, + {0xEBD3, 0xF0, 0x01}, + {0xEBD4, 0x03, 0x01}, + {0xEBD5, 0xBD, 0x01}, + {0xEBD6, 0x00, 0x01}, + {0xEBD7, 0x3F, 0x01}, + {0xEBD8, 0xC8, 0x01}, + {0xEBD9, 0x0B, 0x01}, + {0xEBDA, 0xEE, 0x01}, + {0xEBDB, 0x00, 0x01}, + {0xEBDC, 0x3E, 0x01}, + {0xEBDD, 0x80, 0x01}, + {0xEBDE, 0x2F, 0x01}, + {0xEBDF, 0xC8, 0x01}, + {0xEBE0, 0x0B, 0x01}, + {0xEBE1, 0xF2, 0x01}, + {0xEBE2, 0x83, 0x01}, + {0xEBE3, 0xBC, 0x01}, + {0xEBE4, 0xA0, 0x01}, + {0xEBE5, 0x0E, 0x01}, + {0xEBE6, 0xC0, 0x01}, + {0xEBE7, 0x03, 0x01}, + {0xEBE8, 0xF4, 0x01}, + {0xEBE9, 0x81, 0x01}, + {0xEBEA, 0x3D, 0x01}, + {0xEBEB, 0x00, 0x01}, + {0xEBEC, 0x0F, 0x01}, + {0xEBED, 0xC0, 0x01}, + {0xEBEE, 0x0F, 0x01}, + {0xEBEF, 0xEE, 0x01}, + {0xEBF0, 0x83, 0x01}, + {0xEBF1, 0xBB, 0x01}, + {0xEBF2, 0x60, 0x01}, + {0xEBF3, 0x0F, 0x01}, + {0xEBF4, 0xB8, 0x01}, + {0xEBF5, 0xFF, 0x01}, + {0xEBF6, 0xF3, 0x01}, + {0xEBF7, 0xFF, 0x01}, + {0xEBF8, 0x3C, 0x01}, + {0xEBF9, 0x40, 0x01}, + {0xEBFA, 0x0F, 0x01}, + {0xEBFB, 0xC8, 0x01}, + {0xEBFC, 0x03, 0x01}, + {0xEBFD, 0xF2, 0x01}, + {0xEBFE, 0x04, 0x01}, + {0xEBFF, 0x3E, 0x01}, + {0xEC00, 0x81, 0x01}, + {0xEC01, 0x0F, 0x01}, + {0xEC02, 0xD0, 0x01}, + {0xEC03, 0x03, 0x01}, + {0xEC04, 0xF6, 0x01}, + {0xEC05, 0x00, 0x01}, + {0xEC06, 0x3D, 0x01}, + {0xEC07, 0xE0, 0x01}, + {0xEC08, 0xFE, 0x01}, + {0xEC09, 0xD7, 0x01}, + {0xEC0A, 0x03, 0x01}, + {0xEC0B, 0xF4, 0x01}, + {0xEC0C, 0x00, 0x01}, + {0xEC0D, 0x3D, 0x01}, + {0xEC0E, 0xE1, 0x01}, + {0xEC0F, 0x4F, 0x01}, + {0xEC10, 0xF8, 0x01}, + {0xEC11, 0x0F, 0x01}, + {0xEC12, 0xF4, 0x01}, + {0xEC13, 0x80, 0x01}, + {0xEC14, 0xFE, 0x01}, + {0xEC15, 0x9F, 0x01}, + {0xEC16, 0x0F, 0x01}, + {0xEC17, 0xE0, 0x01}, + {0xEC18, 0x03, 0x01}, + {0xEC19, 0xFA, 0x01}, + {0xEC1A, 0x80, 0x01}, + {0xEC1B, 0x3D, 0x01}, + {0xEC1C, 0x60, 0x01}, + {0xEC1D, 0x5F, 0x01}, + {0xEC1E, 0xF0, 0x01}, + {0xEC1F, 0x17, 0x01}, + {0xEC20, 0xFC, 0x01}, + {0xEC21, 0x02, 0x01}, + {0xEC22, 0x41, 0x01}, + {0xEC23, 0xC0, 0x01}, + {0xEC24, 0x1F, 0x01}, + {0xEC25, 0xF8, 0x01}, + {0xEC26, 0x03, 0x01}, + {0xEC27, 0x02, 0x01}, + {0xEC28, 0xFF, 0x01}, + {0xEC29, 0x3F, 0x01}, + {0xEC2A, 0xC0, 0x01}, + {0xEC2B, 0x0F, 0x01}, + {0xEC2C, 0xF0, 0x01}, + {0xEC2D, 0x1F, 0x01}, + {0xEC2E, 0x04, 0x01}, + {0xEC2F, 0x07, 0x01}, + {0xEC30, 0x41, 0x01}, + {0xEC31, 0x61, 0x01}, + {0xEC32, 0x20, 0x01}, + {0xEC33, 0x10, 0x01}, + {0xEC34, 0x04, 0x01}, + {0xEC35, 0x04, 0x01}, + {0xEC36, 0x81, 0x01}, + {0xEC37, 0x3F, 0x01}, + {0xEC38, 0x80, 0x01}, + {0xEC39, 0x20, 0x01}, + {0xEC3A, 0x10, 0x01}, + {0xEC3B, 0x08, 0x01}, + {0xEC3C, 0x04, 0x01}, + {0xEC3D, 0x05, 0x01}, + {0xEC3E, 0x41, 0x01}, + {0xEC3F, 0x41, 0x01}, + {0xEC40, 0x50, 0x01}, + {0xEC41, 0x30, 0x01}, + {0xEC42, 0x10, 0x01}, + {0xEC43, 0x02, 0x01}, + {0xEC44, 0x82, 0x01}, + {0xEC45, 0x81, 0x01}, + {0xEC46, 0xC0, 0x01}, + {0xEC47, 0x20, 0x01}, + {0xEC48, 0x18, 0x01}, + {0xEC49, 0x0C, 0x01}, + {0xEC4A, 0x04, 0x01}, + {0xEC4B, 0x03, 0x01}, + {0xEC4C, 0xC1, 0x01}, + {0xEC4D, 0x21, 0x01}, + {0xEC4E, 0x70, 0x01}, + {0xEC4F, 0x08, 0x01}, + {0xEC50, 0x20, 0x01}, + {0xEC51, 0x02, 0x01}, + {0xEC52, 0x84, 0x01}, + {0xEC53, 0x83, 0x01}, + {0xEC54, 0xC0, 0x01}, + {0xEC55, 0x20, 0x01}, + {0xEC56, 0x20, 0x01}, + {0xEC57, 0x04, 0x01}, + {0xEC58, 0x04, 0x01}, + {0xEC59, 0x02, 0x01}, + {0xEC5A, 0x82, 0x01}, + {0xEC5B, 0x80, 0x01}, + {0xEC5C, 0x50, 0x01}, + {0xEC5D, 0x08, 0x01}, + {0xEC5E, 0x14, 0x01}, + {0xEC5F, 0x02, 0x01}, + {0xEC60, 0x04, 0x01}, + {0xEC61, 0x04, 0x01}, + {0xEC62, 0x41, 0x01}, + {0xEC63, 0x30, 0x01}, + {0xEC64, 0x38, 0x01}, + {0xEC65, 0x04, 0x01}, + {0xEC66, 0x0C, 0x01}, + {0xEC67, 0x02, 0x01}, + {0xEC68, 0x81, 0x01}, + {0xEC69, 0x80, 0x01}, + {0xEC6A, 0x20, 0x01}, + {0xEC6B, 0x20, 0x01}, + {0xEC6C, 0x14, 0x01}, + {0xEC6D, 0x02, 0x01}, + {0xEC6E, 0x85, 0x01}, + {0xEC6F, 0x00, 0x01}, + {0xEC70, 0x01, 0x01}, + {0xEC71, 0x41, 0x01}, + {0xEC72, 0x10, 0x01}, + {0xEC73, 0x0C, 0x01}, + {0xEC74, 0x0E, 0x01}, + {0xEC75, 0x01, 0x01}, + {0xEC76, 0x83, 0x01}, + {0xEC77, 0x40, 0x01}, + {0xEC78, 0x20, 0x01}, + {0xEC79, 0x20, 0x01}, + {0xEC7A, 0x08, 0x01}, + {0xEC7B, 0x08, 0x01}, + + + {0xED02, 0x85, 0x01}, + {0xED03, 0xAA, 0x01}, + {0xED04, 0xD8, 0x01}, + {0xED05, 0x9A, 0x01}, + {0xED06, 0xE6, 0x01}, + {0xED07, 0x65, 0x01}, + {0xED08, 0x25, 0x01}, + {0xED09, 0x6C, 0x01}, + {0xED0A, 0xC9, 0x01}, + {0xED0B, 0xE8, 0x01}, + {0xED0C, 0x56, 0x01}, + {0xED0D, 0x21, 0x01}, + {0xED0E, 0xA2, 0x01}, + {0xED0F, 0x54, 0x01}, + {0xED10, 0x88, 0x01}, + {0xED11, 0x2C, 0x01}, + {0xED12, 0x45, 0x01}, + {0xED13, 0x23, 0x01}, + {0xED14, 0x5A, 0x01}, + {0xED15, 0x41, 0x01}, + {0xED16, 0xA9, 0x01}, + {0xED17, 0x59, 0x01}, + {0xED18, 0x67, 0x01}, + {0xED19, 0xCA, 0x01}, + {0xED1A, 0x96, 0x01}, + {0xED1B, 0x93, 0x01}, + {0xED1C, 0x76, 0x01}, + {0xED1D, 0x35, 0x01}, + {0xED1E, 0xA1, 0x01}, + {0xED1F, 0x38, 0x01}, + {0xED20, 0x89, 0x01}, + {0xED21, 0x67, 0x01}, + {0xED22, 0x46, 0x01}, + {0xED23, 0xC1, 0x01}, + {0xED24, 0x71, 0x01}, + {0xED25, 0x10, 0x01}, + {0xED26, 0x6C, 0x01}, + {0xED27, 0xEC, 0x01}, + {0xED28, 0x13, 0x01}, + {0xED29, 0x9B, 0x01}, + {0xED2A, 0xFC, 0x01}, + {0xED2B, 0x10, 0x01}, + {0xED2C, 0x87, 0x01}, + {0xED2D, 0x42, 0x01}, + {0xED2E, 0xE9, 0x01}, + {0xED2F, 0x29, 0x01}, + {0xED30, 0x92, 0x01}, + {0xED31, 0x86, 0x01}, + {0xED32, 0xFC, 0x01}, + {0xED33, 0x74, 0x01}, + {0xED34, 0x21, 0x01}, + {0xED35, 0x39, 0x01}, + {0xED36, 0x31, 0x01}, + {0xED37, 0xE7, 0x01}, + {0xED38, 0x41, 0x01}, + {0xED39, 0x9D, 0x01}, + {0xED3A, 0x89, 0x01}, + {0xED3B, 0xCE, 0x01}, + {0xED3C, 0x5F, 0x01}, + {0xED3D, 0x58, 0x01}, + {0xED3E, 0x03, 0x01}, + {0xED3F, 0x17, 0x01}, + {0xED40, 0xCD, 0x01}, + {0xED41, 0xCC, 0x01}, + {0xED42, 0xC5, 0x01}, + {0xED43, 0x33, 0x01}, + {0xED44, 0x85, 0x01}, + {0xED45, 0xD1, 0x01}, + {0xED46, 0x0D, 0x01}, + {0xED47, 0x69, 0x01}, + {0xED48, 0xD4, 0x01}, + {0xED49, 0x53, 0x01}, + {0xED4A, 0x1D, 0x01}, + {0xED4B, 0x18, 0x01}, + {0xED4C, 0x7D, 0x01}, + {0xED4D, 0x07, 0x01}, + {0xED4E, 0x45, 0x01}, + {0xED4F, 0x9D, 0x01}, + {0xED50, 0x69, 0x01}, + {0xED51, 0x4E, 0x01}, + {0xED52, 0x5B, 0x01}, + {0xED53, 0x16, 0x01}, + {0xED54, 0x83, 0x01}, + {0xED55, 0x94, 0x01}, + {0xED56, 0xAE, 0x01}, + {0xED57, 0xE0, 0x01}, + {0xED58, 0x24, 0x01}, + {0xED59, 0x29, 0x01}, + {0xED5A, 0x3C, 0x01}, + {0xED5B, 0x79, 0x01}, + {0xED5C, 0x8A, 0x01}, + {0xED5D, 0x54, 0x01}, + {0xED5E, 0xE0, 0x01}, + {0xED5F, 0x72, 0x01}, + {0xED60, 0x17, 0x01}, + {0xED61, 0xD3, 0x01}, + {0xED62, 0x90, 0x01}, + {0xED63, 0x06, 0x01}, + {0xED64, 0x3D, 0x01}, + {0xED65, 0xC1, 0x01}, + {0xED66, 0xD1, 0x01}, + {0xED67, 0x0F, 0x01}, + {0xED68, 0x5F, 0x01}, + {0xED69, 0x3C, 0x01}, + {0xED6A, 0x53, 0x01}, + {0xED6B, 0x14, 0x01}, + {0xED6C, 0xAB, 0x01}, + {0xED6D, 0x84, 0x01}, + {0xED6E, 0x24, 0x01}, + {0xED6F, 0x25, 0x01}, + {0xED70, 0x11, 0x01}, + {0xED71, 0xB1, 0x01}, + {0xED72, 0x08, 0x01}, + {0xED73, 0x45, 0x01}, + {0xED74, 0x34, 0x01}, + {0xED75, 0xB2, 0x01}, + {0xED76, 0x92, 0x01}, + {0xED77, 0x9C, 0x01}, + {0xED78, 0x5C, 0x01}, + {0xED79, 0x65, 0x01}, + {0xED7A, 0x2E, 0x01}, + {0xED7B, 0x8E, 0x01}, + {0xED7C, 0x09, 0x01}, + {0xED7D, 0x8E, 0x01}, + {0xED7E, 0x6C, 0x01}, + {0xED7F, 0xC6, 0x01}, + {0xED80, 0x93, 0x01}, + {0xED81, 0x96, 0x01}, + {0xED82, 0xC1, 0x01}, + {0xED83, 0xC4, 0x01}, + {0xED84, 0x64, 0x01}, + {0xED85, 0x27, 0x01}, + {0xED86, 0x0E, 0x01}, + {0xED87, 0x89, 0x01}, + {0xED88, 0x08, 0x01}, + {0xED89, 0x40, 0x01}, + {0xED8A, 0x02, 0x01}, + {0xED8B, 0x22, 0x01}, + {0xED8C, 0x10, 0x01}, + {0xED8D, 0x82, 0x01}, + {0xED8E, 0x64, 0x01}, + {0xED8F, 0x24, 0x01}, + {0xED90, 0x24, 0x01}, + {0xED91, 0x44, 0x01}, + {0xED92, 0xD1, 0x01}, + {0xED93, 0x0A, 0x01}, + {0xED94, 0x60, 0x01}, + {0xED95, 0x58, 0x01}, + {0xED96, 0x53, 0x01}, + {0xED97, 0x1B, 0x01}, + {0xED98, 0xF2, 0x01}, + {0xED99, 0xA8, 0x01}, + {0xED9A, 0x65, 0x01}, + {0xED9B, 0x30, 0x01}, + {0xED9C, 0x32, 0x01}, + {0xED9D, 0xD9, 0x01}, + {0xED9E, 0x89, 0x01}, + {0xED9F, 0x43, 0x01}, + {0xEDA0, 0x20, 0x01}, + {0xEDA1, 0x12, 0x01}, + {0xEDA2, 0x10, 0x01}, + {0xEDA3, 0x80, 0x01}, + {0xEDA4, 0x10, 0x01}, + {0xEDA5, 0x84, 0x01}, + {0xEDA6, 0x20, 0x01}, + {0xEDA7, 0x19, 0x01}, + {0xEDA8, 0x01, 0x01}, + {0xEDA9, 0x49, 0x01}, + {0xEDAA, 0x51, 0x01}, + {0xEDAB, 0xB2, 0x01}, + {0xEDAC, 0x12, 0x01}, + {0xEDAD, 0x98, 0x01}, + {0xEDAE, 0xD5, 0x01}, + {0xEDAF, 0xFC, 0x01}, + {0xEDB0, 0x46, 0x01}, + {0xEDB1, 0x3E, 0x01}, + {0xEDB2, 0x7C, 0x01}, + {0xEDB3, 0xC9, 0x01}, + {0xEDB4, 0xCC, 0x01}, + {0xEDB5, 0x51, 0x01}, + {0xEDB6, 0xAC, 0x01}, + {0xEDB7, 0x32, 0x01}, + {0xEDB8, 0x12, 0x01}, + {0xEDB9, 0x93, 0x01}, + {0xEDBA, 0x4C, 0x01}, + {0xEDBB, 0x84, 0x01}, + {0xEDBC, 0x22, 0x01}, + {0xEDBD, 0x17, 0x01}, + {0xEDBE, 0xD9, 0x01}, + {0xEDBF, 0xC8, 0x01}, + {0xEDC0, 0x4B, 0x01}, + {0xEDC1, 0x74, 0x01}, + {0xEDC2, 0xA2, 0x01}, + {0xEDC3, 0x95, 0x01}, + {0xEDC4, 0xB9, 0x01}, + {0xEDC5, 0x48, 0x01}, + {0xEDC6, 0x06, 0x01}, + {0xEDC7, 0x38, 0x01}, + {0xEDC8, 0xDC, 0x01}, + {0xEDC9, 0xC9, 0x01}, + {0xEDCA, 0xD0, 0x01}, + {0xEDCB, 0x66, 0x01}, + {0xEDCC, 0x86, 0x01}, + {0xEDCD, 0xD3, 0x01}, + {0xEDCE, 0x96, 0x01}, + {0xEDCF, 0xC3, 0x01}, + {0xEDD0, 0x28, 0x01}, + {0xEDD1, 0x45, 0x01}, + {0xEDD2, 0x2B, 0x01}, + {0xEDD3, 0x39, 0x01}, + {0xEDD4, 0x31, 0x01}, + {0xEDD5, 0xCA, 0x01}, + {0xEDD6, 0x4F, 0x01}, + {0xEDD7, 0x9C, 0x01}, + {0xEDD8, 0x62, 0x01}, + {0xEDD9, 0x15, 0x01}, + {0xEDDA, 0xB6, 0x01}, + {0xEDDB, 0xF4, 0x01}, + {0xEDDC, 0x45, 0x01}, + {0xEDDD, 0x34, 0x01}, + {0xEDDE, 0xAD, 0x01}, + {0xEDDF, 0x29, 0x01}, + {0xEDE0, 0x4F, 0x01}, + {0xEDE1, 0x84, 0x01}, + {0xEDE2, 0xC4, 0x01}, + {0xEDE3, 0x84, 0x01}, + {0xEDE4, 0x9C, 0x01}, + {0xEDE5, 0x01, 0x01}, + {0xEDE6, 0x6D, 0x01}, + {0xEDE7, 0x06, 0x01}, + {0xEDE8, 0x39, 0x01}, + {0xEDE9, 0x7F, 0x01}, + {0xEDEA, 0x11, 0x01}, + {0xEDEB, 0x0D, 0x01}, + {0xEDEC, 0x5C, 0x01}, + {0xEDED, 0x26, 0x01}, + {0xEDEE, 0x53, 0x01}, + {0xEDEF, 0x17, 0x01}, + {0xEDF0, 0xCE, 0x01}, + {0xEDF1, 0x20, 0x01}, + {0xEDF2, 0xC6, 0x01}, + {0xEDF3, 0x36, 0x01}, + {0xEDF4, 0xA8, 0x01}, + {0xEDF5, 0x11, 0x01}, + {0xEDF6, 0x0F, 0x01}, + {0xEDF7, 0x76, 0x01}, + {0xEDF8, 0x44, 0x01}, + {0xEDF9, 0x34, 0x01}, + {0xEDFA, 0x24, 0x01}, + {0xEDFB, 0x53, 0x01}, + {0xEDFC, 0x15, 0x01}, + {0xEDFD, 0x08, 0x01}, + {0xEDFE, 0x4B, 0x01}, + {0xEDFF, 0xD5, 0x01}, + {0xEE00, 0xC9, 0x01}, + {0xEE01, 0x90, 0x01}, + {0xEE02, 0x6D, 0x01}, + {0xEE03, 0xEA, 0x01}, + {0xEE04, 0x93, 0x01}, + {0xEE05, 0x1A, 0x01}, + {0xEE06, 0xF3, 0x01}, + {0xEE07, 0xB8, 0x01}, + {0xEE08, 0xC6, 0x01}, + {0xEE09, 0x3D, 0x01}, + {0xEE0A, 0xC0, 0x01}, + {0xEE0B, 0x19, 0x01}, + {0xEE0C, 0xD0, 0x01}, + {0xEE0D, 0x78, 0x01}, + {0xEE0E, 0x64, 0x01}, + {0xEE0F, 0x24, 0x01}, + {0xEE10, 0xA1, 0x01}, + {0xEE11, 0x37, 0x01}, + {0xEE12, 0xD1, 0x01}, + {0xEE13, 0x89, 0x01}, + {0xEE14, 0x5A, 0x01}, + {0xEE15, 0x51, 0x01}, + {0xEE16, 0x72, 0x01}, + {0xEE17, 0xD5, 0x01}, + {0xEE18, 0x8C, 0x01}, + {0xEE19, 0x14, 0x01}, + {0xEE1A, 0x05, 0x01}, + {0xEE1B, 0xA1, 0x01}, + {0xEE1C, 0x33, 0x01}, + {0xEE1D, 0xF9, 0x01}, + {0xEE1E, 0xE7, 0x01}, + {0xEE1F, 0x4A, 0x01}, + {0xEE20, 0x01, 0x01}, + {0xEE21, 0xCA, 0x01}, + {0xEE22, 0xD2, 0x01}, + {0xEE23, 0x86, 0x01}, + {0xEE24, 0xE4, 0x01}, + {0xEE25, 0x94, 0x01}, + {0xEE26, 0x23, 0x01}, + {0xEE27, 0x4A, 0x01}, + {0xEE28, 0x55, 0x01}, + {0xEE29, 0x29, 0x01}, + {0xEE2A, 0x57, 0x01}, + {0xEE2B, 0x74, 0x01}, + {0xEE2C, 0x6A, 0x01}, + {0xEE2D, 0x14, 0x01}, + {0xEE2E, 0x95, 0x01}, + {0xEE2F, 0xEA, 0x01}, + {0xEE30, 0x94, 0x01}, + {0xEE31, 0xA3, 0x01}, + {0xEE32, 0x2C, 0x01}, + {0xEE33, 0x75, 0x01}, + {0xEE34, 0x28, 0x01}, + {0xEE35, 0x47, 0x01}, + {0xEE36, 0x0F, 0x01}, + {0xEE37, 0x2A, 0x01}, + {0xEE38, 0xD1, 0x01}, + {0xEE39, 0x84, 0x01}, + {0xEE3A, 0x4E, 0x01}, + {0xEE3B, 0x44, 0x01}, + {0xEE3C, 0x22, 0x01}, + {0xEE3D, 0x1E, 0x01}, + {0xEE3E, 0xE1, 0x01}, + {0xEE3F, 0x28, 0x01}, + {0xEE40, 0x4B, 0x01}, + {0xEE41, 0x4D, 0x01}, + {0xEE42, 0xC2, 0x01}, + {0xEE43, 0x53, 0x01}, + {0xEE44, 0x8D, 0x01}, + {0xEE45, 0xA4, 0x01}, + {0xEE46, 0xC4, 0x01}, + {0xEE47, 0x9F, 0x01}, + {0xEE48, 0x0B, 0x01}, + {0xEE49, 0x49, 0x01}, + {0xEE4A, 0xE7, 0x01}, + {0xEE4B, 0x3C, 0x01}, + {0xEE4C, 0xB5, 0x01}, + {0xEE4D, 0x29, 0x01}, + {0xEE4E, 0x8E, 0x01}, + {0xEE4F, 0x69, 0x01}, + {0xEE50, 0x6A, 0x01}, + {0xEE51, 0x93, 0x01}, + {0xEE52, 0x1A, 0x01}, + {0xEE53, 0xDC, 0x01}, + {0xEE54, 0xE0, 0x01}, + {0xEE55, 0x66, 0x01}, + {0xEE56, 0x39, 0x01}, + {0xEE57, 0xD7, 0x01}, + {0xEE58, 0x91, 0x01}, + {0xEE59, 0x8F, 0x01}, + {0xEE5A, 0x80, 0x01}, + {0xEE5B, 0x46, 0x01}, + {0xEE5C, 0xB4, 0x01}, + {0xEE5D, 0x1F, 0x01}, + {0xEE5E, 0x0C, 0x01}, + {0xEE5F, 0xE5, 0x01}, + {0xEE60, 0xC6, 0x01}, + {0xEE61, 0x39, 0x01}, + {0xEE62, 0x92, 0x01}, + {0xEE63, 0x01, 0x01}, + {0xEE64, 0x0D, 0x01}, + {0xEE65, 0x5E, 0x01}, + {0xEE66, 0x04, 0x01}, + {0xEE67, 0xB3, 0x01}, + {0xEE68, 0x16, 0x01}, + {0xEE69, 0xBA, 0x01}, + {0xEE6A, 0xB8, 0x01}, + {0xEE6B, 0x05, 0x01}, + {0xEE6C, 0x2F, 0x01}, + {0xEE6D, 0x7D, 0x01}, + {0xEE6E, 0x51, 0x01}, + {0xEE6F, 0xCC, 0x01}, + {0xEE70, 0x65, 0x01}, + {0xEE71, 0x52, 0x01}, + {0xEE72, 0x23, 0x01}, + {0xEE73, 0x9C, 0x01}, + {0xEE74, 0xED, 0x01}, + {0xEE75, 0x14, 0x01}, + {0xEE76, 0x67, 0x01}, + {0xEE77, 0x3B, 0x01}, + {0xEE78, 0x8D, 0x01}, + {0xEE79, 0xE1, 0x01}, + {0xEE7A, 0x0C, 0x01}, + {0xEE7B, 0x59, 0x01}, + {0xEE7C, 0xDE, 0x01}, + {0xEE7D, 0x42, 0x01}, + {0xEE7E, 0x94, 0x01}, + {0xEE7F, 0xA5, 0x01}, + {0xEE80, 0xDC, 0x01}, + {0xEE81, 0x64, 0x01}, + {0xEE82, 0x27, 0x01}, + {0xEE83, 0x3A, 0x01}, + {0xEE84, 0xF9, 0x01}, + {0xEE85, 0x89, 0x01}, + {0xEE86, 0x53, 0x01}, + {0xEE87, 0xAC, 0x01}, + {0xEE88, 0xE2, 0x01}, + {0xEE89, 0x96, 0x01}, + {0xEE8A, 0xBD, 0x01}, + {0xEE8B, 0x54, 0x01}, + {0xEE8C, 0xE6, 0x01}, + {0xEE8D, 0x34, 0x01}, + {0xEE8E, 0xAA, 0x01}, + {0xEE8F, 0xE1, 0x01}, + {0xEE90, 0x0D, 0x01}, + {0xEE91, 0x5C, 0x01}, + {0xEE92, 0xF8, 0x01}, + {0xEE93, 0xF2, 0x01}, + {0xEE94, 0x93, 0x01}, + {0xEE95, 0xA3, 0x01}, + {0xEE96, 0x78, 0x01}, + {0xEE97, 0x64, 0x01}, + {0xEE98, 0x24, 0x01}, + {0xEE99, 0x12, 0x01}, + {0xEE9A, 0x99, 0x01}, + {0xEE9B, 0x88, 0x01}, + {0xEE9C, 0x45, 0x01}, + {0xEE9D, 0x2C, 0x01}, + {0xEE9E, 0xA2, 0x01}, + {0xEE9F, 0x92, 0x01}, + {0xEEA0, 0x96, 0x01}, + {0xEEA1, 0x3C, 0x01}, + {0xEEA2, 0x05, 0x01}, + {0xEEA3, 0x2B, 0x01}, + {0xEEA4, 0x7F, 0x01}, + {0xEEA5, 0x79, 0x01}, + {0xEEA6, 0x8C, 0x01}, + {0xEEA7, 0x67, 0x01}, + {0xEEA8, 0x5E, 0x01}, + {0xEEA9, 0xF3, 0x01}, + {0xEEAA, 0x95, 0x01}, + {0xEEAB, 0xB4, 0x01}, + {0xEEAC, 0xB4, 0x01}, + {0xEEAD, 0x44, 0x01}, + {0xEEAE, 0x26, 0x01}, + {0xEEAF, 0x0C, 0x01}, + {0xEEB0, 0x79, 0x01}, + {0xEEB1, 0x08, 0x01}, + {0xEEB2, 0x40, 0x01}, + {0xEEB3, 0x02, 0x01}, + {0xEEB4, 0x42, 0x01}, + {0xEEB5, 0x90, 0x01}, + {0xEEB6, 0x81, 0x01}, + {0xEEB7, 0x60, 0x01}, + {0xEEB8, 0x24, 0x01}, + {0xEEB9, 0x23, 0x01}, + {0xEEBA, 0x3E, 0x01}, + {0xEEBB, 0x21, 0x01}, + {0xEEBC, 0x4A, 0x01}, + {0xEEBD, 0x5C, 0x01}, + {0xEEBE, 0xFE, 0x01}, + {0xEEBF, 0xE2, 0x01}, + {0xEEC0, 0x99, 0x01}, + {0xEEC1, 0xD5, 0x01}, + {0xEEC2, 0x7C, 0x01}, + {0xEEC3, 0xC5, 0x01}, + {0xEEC4, 0x2C, 0x01}, + {0xEEC5, 0x2B, 0x01}, + {0xEEC6, 0x89, 0x01}, + {0xEEC7, 0x09, 0x01}, + {0xEEC8, 0x43, 0x01}, + {0xEEC9, 0x1C, 0x01}, + {0xEECA, 0x02, 0x01}, + {0xEECB, 0x10, 0x01}, + {0xEECC, 0x80, 0x01}, + {0xEECD, 0x0C, 0x01}, + {0xEECE, 0x64, 0x01}, + {0xEECF, 0x20, 0x01}, + {0xEED0, 0x16, 0x01}, + {0xEED1, 0xC9, 0x01}, + {0xEED2, 0x08, 0x01}, + {0xEED3, 0x4F, 0x01}, + {0xEED4, 0x88, 0x01}, + {0xEED5, 0xE2, 0x01}, + {0xEED6, 0x96, 0x01}, + {0xEED7, 0xBF, 0x01}, + {0xEED8, 0xAC, 0x01}, + {0xEED9, 0xC6, 0x01}, + {0xEEDA, 0x36, 0x01}, + {0xEEDB, 0x70, 0x01}, + {0xEEDC, 0xB1, 0x01}, + {0xEEDD, 0xCB, 0x01}, + {0xEEDE, 0x4F, 0x01}, + {0xEEDF, 0x86, 0x01}, + {0xEEE0, 0xD2, 0x01}, + {0xEEE1, 0x11, 0x01}, + {0xEEE2, 0x90, 0x01}, + {0xEEE3, 0x3C, 0x01}, + {0xEEE4, 0x04, 0x01}, + {0xEEE5, 0x22, 0x01}, + {0xEEE6, 0x13, 0x01}, + {0xEEE7, 0xA1, 0x01}, + {0xEEE8, 0xC8, 0x01}, + {0xEEE9, 0x49, 0x01}, + {0xEEEA, 0x58, 0x01}, + {0xEEEB, 0xC2, 0x01}, + {0xEEEC, 0x94, 0x01}, + {0xEEED, 0xAB, 0x01}, + {0xEEEE, 0xE8, 0x01}, + {0xEEEF, 0xE5, 0x01}, + {0xEEF0, 0x31, 0x01}, + {0xEEF1, 0xC5, 0x01}, + {0xEEF2, 0x89, 0x01}, + {0xEEF3, 0x0E, 0x01}, + {0xEEF4, 0x63, 0x01}, + {0xEEF5, 0x26, 0x01}, + {0xEEF6, 0x33, 0x01}, + {0xEEF7, 0x96, 0x01}, + {0xEEF8, 0xB3, 0x01}, + {0xEEF9, 0x0C, 0x01}, + {0xEEFA, 0xA5, 0x01}, + {0xEEFB, 0x28, 0x01}, + {0xEEFC, 0x33, 0x01}, + {0xEEFD, 0xB1, 0x01}, + {0xEEFE, 0xC9, 0x01}, + {0xEEFF, 0x4D, 0x01}, + {0xEF00, 0x76, 0x01}, + {0xEF01, 0x92, 0x01}, + {0xEF02, 0x94, 0x01}, + {0xEF03, 0xA9, 0x01}, + {0xEF04, 0xA8, 0x01}, + {0xEF05, 0x25, 0x01}, + {0xEF06, 0x2F, 0x01}, + {0xEF07, 0x8E, 0x01}, + {0xEF08, 0x49, 0x01}, + {0xEF09, 0xCD, 0x01}, + {0xEF0A, 0x7E, 0x01}, + {0xEF0B, 0x06, 0x01}, + {0xEF0C, 0x94, 0x01}, + {0xEF0D, 0x9B, 0x01}, + {0xEF0E, 0xDF, 0x01}, + {0xEF0F, 0x44, 0x01}, + {0xEF10, 0xA6, 0x01}, + {0xEF11, 0x32, 0x01}, + {0xEF12, 0x75, 0x01}, + {0xEF13, 0xD9, 0x01}, + {0xEF14, 0xCB, 0x01}, + {0xEF15, 0x59, 0x01}, + {0xEF16, 0xDC, 0x01}, + {0xEF17, 0x82, 0x01}, + {0xEF18, 0x96, 0x01}, + {0xEF19, 0xB9, 0x01}, + {0xEF1A, 0xD4, 0x01}, + {0xEF1B, 0xC5, 0x01}, + {0xEF1C, 0x30, 0x01}, + {0xEF1D, 0x8E, 0x01}, + {0xEF1E, 0x41, 0x01}, + {0xEF1F, 0xCD, 0x01}, + {0xEF20, 0x6C, 0x01}, + {0xEF21, 0xAE, 0x01}, + {0xEF22, 0xD3, 0x01}, + {0xEF23, 0x22, 0x01}, + {0xEF24, 0x1C, 0x01}, + {0xEF25, 0xD5, 0x01}, + {0xEF26, 0x07, 0x01}, + {0xEF27, 0x40, 0x01}, + {0xEF28, 0xC7, 0x01}, + {0xEF29, 0x99, 0x01}, + {0xEF2A, 0xCE, 0x01}, + {0xEF2B, 0x6A, 0x01}, + {0xEF2C, 0x6A, 0x01}, + {0xEF2D, 0xC3, 0x01}, + {0xEF2E, 0x19, 0x01}, + {0xEF2F, 0xD5, 0x01}, + {0xEF30, 0x6C, 0x01}, + {0xEF31, 0xC6, 0x01}, + {0xEF32, 0x35, 0x01}, + {0xEF33, 0xA9, 0x01}, + {0xEF34, 0x09, 0x01}, + {0xEF35, 0x4E, 0x01}, + {0xEF36, 0x71, 0x01}, + {0xEF37, 0xCA, 0x01}, + {0xEF38, 0xC3, 0x01}, + {0xEF39, 0x1E, 0x01}, + {0xEF3A, 0x0A, 0x01}, + {0xEF3B, 0x55, 0x01}, + {0xEF3C, 0x09, 0x01}, + {0xEF3D, 0x4D, 0x01}, + {0xEF3E, 0x39, 0x01}, + {0xEF3F, 0x8A, 0x01}, + {0xEF40, 0x52, 0x01}, + {0xEF41, 0x86, 0x01}, + {0xEF42, 0x6E, 0x01}, + {0xEF43, 0xD4, 0x01}, + {0xEF44, 0x1F, 0x01}, + {0xEF45, 0x09, 0x01}, + {0xEF46, 0xA1, 0x01}, + {0xEF47, 0x87, 0x01}, + {0xEF48, 0x40, 0x01}, + {0xEF49, 0xE5, 0x01}, + {0xEF4A, 0x39, 0x01}, + {0xEF4B, 0x10, 0x01}, + {0xEF4C, 0x7E, 0x01}, + {0xEF4D, 0x40, 0x01}, + {0xEF4E, 0x14, 0x01}, + {0xEF4F, 0x21, 0x01}, + {0xEF50, 0x1F, 0x01}, + {0xEF51, 0x81, 0x01}, + {0xEF52, 0x08, 0x01}, + {0xEF53, 0x4B, 0x01}, + + + {0xEF54, 0xC7, 0x01}, + {0xEF55, 0x82, 0x01}, + {0xEF56, 0x55, 0x01}, + {0xEF57, 0xA6, 0x01}, + {0xEF58, 0xEE, 0x01}, + {0xEF59, 0xA4, 0x01}, + {0xEF5A, 0x25, 0x01}, + {0xEF5B, 0x2F, 0x01}, + {0xEF5C, 0xD5, 0x01}, + {0xEF5D, 0x09, 0x01}, + {0xEF5E, 0x52, 0x01}, + {0xEF5F, 0x96, 0x01}, + {0xEF60, 0x02, 0x01}, + {0xEF61, 0x94, 0x01}, + {0xEF62, 0x8F, 0x01}, + {0xEF63, 0x0C, 0x01}, + {0xEF64, 0x34, 0x01}, + {0xEF65, 0x1E, 0x01}, + {0xEF66, 0xE7, 0x01}, + {0xEF67, 0x40, 0x01}, + {0xEF68, 0xE7, 0x01}, + {0xEF69, 0x3C, 0x01}, + {0xEF6A, 0x14, 0x01}, + {0xEF6B, 0x4A, 0x01}, + {0xEF6C, 0x92, 0x01}, + {0xEF6D, 0x90, 0x01}, + {0xEF6E, 0xD0, 0x01}, + {0xEF6F, 0x13, 0x01}, + {0xEF70, 0x1B, 0x01}, + {0xEF71, 0xC7, 0x01}, + {0xEF72, 0xF8, 0x01}, + {0xEF73, 0x25, 0x01}, + {0xEF74, 0x30, 0x01}, + {0xEF75, 0x98, 0x01}, + {0xEF76, 0x19, 0x01}, + {0xEF77, 0x4E, 0x01}, + {0xEF78, 0x81, 0x01}, + {0xEF79, 0x02, 0x01}, + {0xEF7A, 0xE4, 0x01}, + {0xEF7B, 0x1A, 0x01}, + {0xEF7C, 0xBA, 0x01}, + {0xEF7D, 0x30, 0x01}, + {0xEF7E, 0x45, 0x01}, + {0xEF7F, 0x27, 0x01}, + {0xEF80, 0x3F, 0x01}, + {0xEF81, 0xD1, 0x01}, + {0xEF82, 0x4A, 0x01}, + {0xEF83, 0x62, 0x01}, + {0xEF84, 0x88, 0x01}, + {0xEF85, 0xA3, 0x01}, + {0xEF86, 0x1D, 0x01}, + {0xEF87, 0xC3, 0x01}, + {0xEF88, 0x20, 0x01}, + {0xEF89, 0x25, 0x01}, + {0xEF8A, 0x24, 0x01}, + {0xEF8B, 0x10, 0x01}, + {0xEF8C, 0x99, 0x01}, + {0xEF8D, 0x48, 0x01}, + {0xEF8E, 0x4B, 0x01}, + {0xEF8F, 0xBE, 0x01}, + {0xEF90, 0x42, 0x01}, + {0xEF91, 0x1A, 0x01}, + {0xEF92, 0xE4, 0x01}, + {0xEF93, 0xC4, 0x01}, + {0xEF94, 0x45, 0x01}, + {0xEF95, 0x26, 0x01}, + {0xEF96, 0x0E, 0x01}, + {0xEF97, 0x01, 0x01}, + {0xEF98, 0x88, 0x01}, + {0xEF99, 0x40, 0x01}, + {0xEF9A, 0x34, 0x01}, + {0xEF9B, 0xB2, 0x01}, + {0xEF9C, 0x94, 0x01}, + {0xEF9D, 0xC9, 0x01}, + {0xEF9E, 0x24, 0x01}, + {0xEF9F, 0x47, 0x01}, + {0xEFA0, 0x2E, 0x01}, + {0xEFA1, 0x33, 0x01}, + {0xEFA2, 0x71, 0x01}, + {0xEFA3, 0x08, 0x01}, + {0xEFA4, 0x40, 0x01}, + {0xEFA5, 0x08, 0x01}, + {0xEFA6, 0xB2, 0x01}, + {0xEFA7, 0x11, 0x01}, + {0xEFA8, 0xA6, 0x01}, + {0xEFA9, 0x50, 0x01}, + {0xEFAA, 0x26, 0x01}, + {0xEFAB, 0x3B, 0x01}, + {0xEFAC, 0x86, 0x01}, + {0xEFAD, 0x51, 0x01}, + {0xEFAE, 0x8A, 0x01}, + {0xEFAF, 0x48, 0x01}, + {0xEFB0, 0x24, 0x01}, + {0xEFB1, 0x82, 0x01}, + {0xEFB2, 0x91, 0x01}, + {0xEFB3, 0x98, 0x01}, + {0xEFB4, 0x8C, 0x01}, + {0xEFB5, 0x25, 0x01}, + {0xEFB6, 0x35, 0x01}, + {0xEFB7, 0xFF, 0x01}, + {0xEFB8, 0x71, 0x01}, + {0xEFB9, 0x8D, 0x01}, + {0xEFBA, 0x5D, 0x01}, + {0xEFBB, 0x9E, 0x01}, + {0xEFBC, 0xE2, 0x01}, + {0xEFBD, 0x13, 0x01}, + {0xEFBE, 0xA2, 0x01}, + {0xEFBF, 0x7C, 0x01}, + {0xEFC0, 0xC5, 0x01}, + {0xEFC1, 0x31, 0x01}, + {0xEFC2, 0xCB, 0x01}, + {0xEFC3, 0x09, 0x01}, + {0xEFC4, 0x52, 0x01}, + {0xEFC5, 0x7A, 0x01}, + {0xEFC6, 0x62, 0x01}, + {0xEFC7, 0xF3, 0x01}, + {0xEFC8, 0x98, 0x01}, + {0xEFC9, 0xC0, 0x01}, + {0xEFCA, 0x24, 0x01}, + {0xEFCB, 0x06, 0x01}, + {0xEFCC, 0x34, 0x01}, + {0xEFCD, 0xCA, 0x01}, + {0xEFCE, 0x29, 0x01}, + {0xEFCF, 0x10, 0x01}, + {0xEFD0, 0xA0, 0x01}, + {0xEFD1, 0x72, 0x01}, + {0xEFD2, 0xE4, 0x01}, + {0xEFD3, 0x1F, 0x01}, + {0xEFD4, 0xEE, 0x01}, + {0xEFD5, 0x38, 0x01}, + {0xEFD6, 0xA7, 0x01}, + {0xEFD7, 0x3A, 0x01}, + {0xEFD8, 0xEA, 0x01}, + {0xEFD9, 0xB1, 0x01}, + {0xEFDA, 0xD0, 0x01}, + {0xEFDB, 0x93, 0x01}, + {0xEFDC, 0x56, 0x01}, + {0xEFDD, 0x95, 0x01}, + {0xEFDE, 0x28, 0x01}, + {0xEFDF, 0x33, 0x01}, + {0xEFE0, 0x25, 0x01}, + {0xEFE1, 0xE9, 0x01}, + {0xEFE2, 0x46, 0x01}, + {0xEFE3, 0x3A, 0x01}, + {0xEFE4, 0x8A, 0x01}, + {0xEFE5, 0x52, 0x01}, + {0xEFE6, 0x9D, 0x01}, + {0xEFE7, 0x24, 0x01}, + {0xEFE8, 0x05, 0x01}, + {0xEFE9, 0x00, 0x01}, + {0xEFEA, 0x00, 0x01}, + {0xEFEB, 0x00, 0x01}, + {0xEFEC, 0x00, 0x01}, + {0xEFED, 0x00, 0x01}, + + /*SHD3 D65+TL84 C01*/ + {0xED00, 0x9191, 0x02}, + {0xEFEE, 0x22, 0x01}, + {0xEFEF, 0xBA, 0x01}, + {0xEFF0, 0xD1, 0x01}, + {0xEFF1, 0x8C, 0x01}, + {0xEFF2, 0x50, 0x01}, + {0xEFF3, 0xA4, 0x01}, + {0xEFF4, 0x22, 0x01}, + {0xEFF5, 0x17, 0x01}, + {0xEFF6, 0xE9, 0x01}, + {0xEFF7, 0x88, 0x01}, + {0xEFF8, 0x47, 0x01}, + {0xEFF9, 0x29, 0x01}, + {0xEFFA, 0xBA, 0x01}, + {0xEFFB, 0x50, 0x01}, + {0xEFFC, 0x80, 0x01}, + {0xEFFD, 0xD0, 0x01}, + {0xEFFE, 0x73, 0x01}, + {0xEFFF, 0x1D, 0x01}, + {0xF000, 0xE9, 0x01}, + {0xF001, 0x6C, 0x01}, + {0xF002, 0x87, 0x01}, + {0xF003, 0x3D, 0x01}, + {0xF004, 0x05, 0x01}, + {0xF005, 0xE2, 0x01}, + {0xF006, 0xD0, 0x01}, + {0xF007, 0x7D, 0x01}, + {0xF008, 0xA2, 0x01}, + {0xF009, 0xF3, 0x01}, + {0xF00A, 0x9A, 0x01}, + {0xF00B, 0xC9, 0x01}, + {0xF00C, 0x2C, 0x01}, + {0xF00D, 0xA6, 0x01}, + {0xF00E, 0x32, 0x01}, + {0xF00F, 0xAF, 0x01}, + {0xF010, 0xB1, 0x01}, + {0xF011, 0x0E, 0x01}, + {0xF012, 0x82, 0x01}, + {0xF013, 0xAE, 0x01}, + {0xF014, 0x33, 0x01}, + {0xF015, 0x1A, 0x01}, + {0xF016, 0xB9, 0x01}, + {0xF017, 0x48, 0x01}, + {0xF018, 0x25, 0x01}, + {0xF019, 0x29, 0x01}, + {0xF01A, 0x54, 0x01}, + {0xF01B, 0xA9, 0x01}, + {0xF01C, 0x0B, 0x01}, + {0xF01D, 0x6B, 0x01}, + {0xF01E, 0xD0, 0x01}, + {0xF01F, 0xE3, 0x01}, + {0xF020, 0x9B, 0x01}, + {0xF021, 0xBE, 0x01}, + {0xF022, 0x18, 0x01}, + {0xF023, 0x85, 0x01}, + {0xF024, 0x24, 0x01}, + {0xF025, 0x19, 0x01}, + {0xF026, 0x29, 0x01}, + {0xF027, 0xC9, 0x01}, + {0xF028, 0x52, 0x01}, + {0xF029, 0x08, 0x01}, + {0xF02A, 0x93, 0x01}, + {0xF02B, 0x1C, 0x01}, + {0xF02C, 0xD8, 0x01}, + {0xF02D, 0xA8, 0x01}, + {0xF02E, 0x05, 0x01}, + {0xF02F, 0x26, 0x01}, + {0xF030, 0x0B, 0x01}, + {0xF031, 0x01, 0x01}, + {0xF032, 0x88, 0x01}, + {0xF033, 0x43, 0x01}, + {0xF034, 0x6C, 0x01}, + {0xF035, 0xE2, 0x01}, + {0xF036, 0x96, 0x01}, + {0xF037, 0xDB, 0x01}, + {0xF038, 0xC4, 0x01}, + {0xF039, 0x66, 0x01}, + {0xF03A, 0x2D, 0x01}, + {0xF03B, 0x31, 0x01}, + {0xF03C, 0x59, 0x01}, + {0xF03D, 0x48, 0x01}, + {0xF03E, 0x40, 0x01}, + {0xF03F, 0x20, 0x01}, + {0xF040, 0x62, 0x01}, + {0xF041, 0x13, 0x01}, + {0xF042, 0xB8, 0x01}, + {0xF043, 0xF0, 0x01}, + {0xF044, 0x86, 0x01}, + {0xF045, 0x38, 0x01}, + {0xF046, 0x82, 0x01}, + {0xF047, 0x49, 0x01}, + {0xF048, 0x0A, 0x01}, + {0xF049, 0x49, 0x01}, + {0xF04A, 0x34, 0x01}, + {0xF04B, 0x92, 0x01}, + {0xF04C, 0x12, 0x01}, + {0xF04D, 0xA7, 0x01}, + {0xF04E, 0x1C, 0x01}, + {0xF04F, 0xE6, 0x01}, + {0xF050, 0x39, 0x01}, + {0xF051, 0xE2, 0x01}, + {0xF052, 0x41, 0x01}, + {0xF053, 0x8D, 0x01}, + {0xF054, 0x5D, 0x01}, + {0xF055, 0xAA, 0x01}, + {0xF056, 0xC2, 0x01}, + {0xF057, 0x94, 0x01}, + {0xF058, 0xAC, 0x01}, + {0xF059, 0xF4, 0x01}, + {0xF05A, 0x65, 0x01}, + {0xF05B, 0x36, 0x01}, + {0xF05C, 0xF1, 0x01}, + {0xF05D, 0x31, 0x01}, + {0xF05E, 0x90, 0x01}, + {0xF05F, 0x76, 0x01}, + {0xF060, 0x62, 0x01}, + {0xF061, 0x83, 0x01}, + {0xF062, 0x19, 0x01}, + {0xF063, 0xC7, 0x01}, + {0xF064, 0x6C, 0x01}, + {0xF065, 0x26, 0x01}, + {0xF066, 0x37, 0x01}, + {0xF067, 0xE2, 0x01}, + {0xF068, 0x89, 0x01}, + {0xF069, 0xD0, 0x01}, + {0xF06A, 0x87, 0x01}, + {0xF06B, 0x0C, 0x01}, + {0xF06C, 0xC4, 0x01}, + {0xF06D, 0x1E, 0x01}, + {0xF06E, 0xEE, 0x01}, + {0xF06F, 0x58, 0x01}, + {0xF070, 0x07, 0x01}, + {0xF071, 0x3C, 0x01}, + {0xF072, 0xF4, 0x01}, + {0xF073, 0x81, 0x01}, + {0xF074, 0x90, 0x01}, + {0xF075, 0x8B, 0x01}, + {0xF076, 0x3C, 0x01}, + {0xF077, 0xA4, 0x01}, + {0xF078, 0xA2, 0x01}, + {0xF079, 0x10, 0x01}, + {0xF07A, 0x69, 0x01}, + {0xF07B, 0x48, 0x01}, + {0xF07C, 0x43, 0x01}, + {0xF07D, 0x20, 0x01}, + {0xF07E, 0x62, 0x01}, + {0xF07F, 0x51, 0x01}, + {0xF080, 0x8C, 0x01}, + {0xF081, 0x50, 0x01}, + {0xF082, 0x04, 0x01}, + {0xF083, 0x00, 0x01}, + {0xF084, 0x00, 0x01}, + {0xF085, 0x00, 0x01}, + {0xF086, 0x00, 0x01}, + {0xF087, 0x00, 0x01}, + {0xF088, 0xBB, 0x01}, + {0xF089, 0x41, 0x01}, + {0xF08A, 0x0E, 0x01}, + {0xF08B, 0x6F, 0x01}, + {0xF08C, 0x68, 0x01}, + {0xF08D, 0x23, 0x01}, + {0xF08E, 0x9B, 0x01}, + {0xF08F, 0xD9, 0x01}, + {0xF090, 0xE8, 0x01}, + {0xF091, 0x06, 0x01}, + {0xF092, 0x38, 0x01}, + {0xF093, 0xB9, 0x01}, + {0xF094, 0xB9, 0x01}, + {0xF095, 0x4D, 0x01}, + {0xF096, 0x69, 0x01}, + {0xF097, 0x24, 0x01}, + {0xF098, 0x83, 0x01}, + {0xF099, 0x98, 0x01}, + {0xF09A, 0xC1, 0x01}, + {0xF09B, 0x1C, 0x01}, + {0xF09C, 0x06, 0x01}, + {0xF09D, 0x32, 0x01}, + {0xF09E, 0xA4, 0x01}, + {0xF09F, 0xA9, 0x01}, + {0xF0A0, 0x4D, 0x01}, + {0xF0A1, 0x67, 0x01}, + {0xF0A2, 0x0C, 0x01}, + {0xF0A3, 0x13, 0x01}, + {0xF0A4, 0x97, 0x01}, + {0xF0A5, 0xB0, 0x01}, + {0xF0A6, 0x6C, 0x01}, + {0xF0A7, 0x25, 0x01}, + {0xF0A8, 0x2C, 0x01}, + {0xF0A9, 0x70, 0x01}, + {0xF0AA, 0x39, 0x01}, + {0xF0AB, 0xCC, 0x01}, + {0xF0AC, 0x68, 0x01}, + {0xF0AD, 0x10, 0x01}, + {0xF0AE, 0xA3, 0x01}, + {0xF0AF, 0x96, 0x01}, + {0xF0B0, 0xA6, 0x01}, + {0xF0B1, 0xE4, 0x01}, + {0xF0B2, 0x44, 0x01}, + {0xF0B3, 0x26, 0x01}, + {0xF0B4, 0x3A, 0x01}, + {0xF0B5, 0x79, 0x01}, + {0xF0B6, 0x4A, 0x01}, + {0xF0B7, 0x5B, 0x01}, + {0xF0B8, 0x18, 0x01}, + {0xF0B9, 0x93, 0x01}, + {0xF0BA, 0x17, 0x01}, + {0xF0BB, 0xA9, 0x01}, + {0xF0BC, 0xBC, 0x01}, + {0xF0BD, 0x24, 0x01}, + {0xF0BE, 0x23, 0x01}, + {0xF0BF, 0x12, 0x01}, + {0xF0C0, 0xE1, 0x01}, + {0xF0C1, 0xC8, 0x01}, + {0xF0C2, 0x4C, 0x01}, + {0xF0C3, 0xAA, 0x01}, + {0xF0C4, 0xA2, 0x01}, + {0xF0C5, 0x17, 0x01}, + {0xF0C6, 0xB6, 0x01}, + {0xF0C7, 0x10, 0x01}, + {0xF0C8, 0x05, 0x01}, + {0xF0C9, 0x24, 0x01}, + {0xF0CA, 0x06, 0x01}, + {0xF0CB, 0x09, 0x01}, + {0xF0CC, 0xC8, 0x01}, + {0xF0CD, 0x42, 0x01}, + {0xF0CE, 0x4A, 0x01}, + {0xF0CF, 0x82, 0x01}, + {0xF0D0, 0x94, 0x01}, + {0xF0D1, 0xB8, 0x01}, + {0xF0D2, 0xC0, 0x01}, + {0xF0D3, 0xE5, 0x01}, + {0xF0D4, 0x28, 0x01}, + {0xF0D5, 0x21, 0x01}, + {0xF0D6, 0x39, 0x01}, + {0xF0D7, 0x08, 0x01}, + {0xF0D8, 0x40, 0x01}, + {0xF0D9, 0x16, 0x01}, + {0xF0DA, 0x62, 0x01}, + {0xF0DB, 0x92, 0x01}, + {0xF0DC, 0xA4, 0x01}, + {0xF0DD, 0xC4, 0x01}, + {0xF0DE, 0xE5, 0x01}, + {0xF0DF, 0x2F, 0x01}, + {0xF0E0, 0x58, 0x01}, + {0xF0E1, 0x99, 0x01}, + {0xF0E2, 0x49, 0x01}, + {0xF0E3, 0x46, 0x01}, + {0xF0E4, 0x22, 0x01}, + {0xF0E5, 0xC2, 0x01}, + {0xF0E6, 0x91, 0x01}, + {0xF0E7, 0x9A, 0x01}, + {0xF0E8, 0x58, 0x01}, + {0xF0E9, 0xA5, 0x01}, + {0xF0EA, 0x2F, 0x01}, + {0xF0EB, 0x95, 0x01}, + {0xF0EC, 0x99, 0x01}, + {0xF0ED, 0x4B, 0x01}, + {0xF0EE, 0x54, 0x01}, + {0xF0EF, 0x74, 0x01}, + {0xF0F0, 0x32, 0x01}, + {0xF0F1, 0x93, 0x01}, + {0xF0F2, 0x9D, 0x01}, + {0xF0F3, 0x38, 0x01}, + {0xF0F4, 0xC5, 0x01}, + {0xF0F5, 0x2D, 0x01}, + {0xF0F6, 0x90, 0x01}, + {0xF0F7, 0x59, 0x01}, + {0xF0F8, 0x0D, 0x01}, + {0xF0F9, 0x64, 0x01}, + {0xF0FA, 0xEE, 0x01}, + {0xF0FB, 0x62, 0x01}, + {0xF0FC, 0x96, 0x01}, + {0xF0FD, 0xAE, 0x01}, + {0xF0FE, 0x84, 0x01}, + {0xF0FF, 0x25, 0x01}, + {0xF100, 0x2E, 0x01}, + {0xF101, 0x8A, 0x01}, + {0xF102, 0x29, 0x01}, + {0xF103, 0x8D, 0x01}, + {0xF104, 0x6F, 0x01}, + {0xF105, 0x60, 0x01}, + {0xF106, 0xD3, 0x01}, + {0xF107, 0x19, 0x01}, + {0xF108, 0xC7, 0x01}, + {0xF109, 0x18, 0x01}, + {0xF10A, 0x26, 0x01}, + {0xF10B, 0x31, 0x01}, + {0xF10C, 0x97, 0x01}, + {0xF10D, 0x41, 0x01}, + {0xF10E, 0x8D, 0x01}, + {0xF10F, 0x6D, 0x01}, + {0xF110, 0x84, 0x01}, + {0xF111, 0xE3, 0x01}, + {0xF112, 0x1C, 0x01}, + {0xF113, 0xE3, 0x01}, + {0xF114, 0xDC, 0x01}, + {0xF115, 0x26, 0x01}, + {0xF116, 0x36, 0x01}, + {0xF117, 0xB6, 0x01}, + {0xF118, 0xF1, 0x01}, + {0xF119, 0x4D, 0x01}, + {0xF11A, 0x70, 0x01}, + {0xF11B, 0x68, 0x01}, + {0xF11C, 0x03, 0x01}, + {0xF11D, 0x00, 0x01}, + {0xF11E, 0x00, 0x01}, + {0xF11F, 0x00, 0x01}, + {0xF120, 0x00, 0x01}, + {0xF121, 0x00, 0x01}, + + + /*SHD TH*/ + {0x6C32, 0x16A8, 0x02}, /* SHD_INP_TH_HB_H_R2*/ + {0x6C34, 0x1612, 0x02}, /* SHD_INP_TH_HB_L_R2*/ + {0x6C36, 0x10CC, 0x02}, /* SHD_INP_TH_LB_H_R2*/ + {0x6C38, 0x1004, 0x02}, /* SHD_INP_TH_LB_L_R2*/ + {0x6C3C, 0x10CC, 0x02}, /* SHD_INP_TH_HB_H_RB*/ + {0x6C3E, 0x1004, 0x02}, /* SHD_INP_TH_HB_L_RB*/ + {0x6C40, 0x0000, 0x02}, /* SHD_INP_TH_LB_H_RB*/ + {0x6C42, 0x0000, 0x02}, /* SHD_INP_TH_LB_L_RB*/ + + /*PreWB_offset (for SHD2)*/ + {0x6828, 0x0013, 0x02}, /* SHD_PRER_OFFSET_R2 :*/ + /*PreWB_offset (for SHD3)*/ + {0x682C, 0x000C, 0x02}, /* SHD_PRER_OFFSET_RB :*/ + {0x6830, 0xFFFF, 0x02}, /* SHD_PREB_OFFSET_RB :*/ + + /* CXC/SHD EN*/ + {0x01BC, 0x57, 0x01}, /* CXC ON SHD ON INP ON GAIN OFF*/ + + /*#36*/ + {0x6804, 0x1122, 0x02}, /* NORMR*/ + {0x6806, 0x116B, 0x02}, /* NORMB*/ + {0x6808, 0x0150, 0x02}, /* AWBPRER*/ + {0x680A, 0x0245, 0x02}, /* AWBPREB*/ + {0x6810, 0x1001, 0x02}, /* AWB_PRE_ADJ_RG*/ + {0x6812, 0x0FC9, 0x02}, /* AWB_PRE_ADJ_BG*/ + {0x6814, 0x0A73, 0x02}, /* AWB_C14_RG*/ + {0x6816, 0x17EA, 0x02}, /* AWB_C14_BG*/ +}; + +struct isx012_short_t ISX012_Shading_2[] = { + {0x01BC, 0x50, 0x01}, /* CXC OFF SHD OFF*/ + + {0xEB00, 0x8282, 0x02}, /*valid_code*/ + {0xEB02, 0xFF, 0x01}, + {0xEB03, 0xC4, 0x01}, + {0xEB04, 0x3F, 0x01}, + {0xEB05, 0xF1, 0x01}, + {0xEB06, 0x3F, 0x01}, + {0xEB07, 0x00, 0x01}, + {0xEB08, 0x12, 0x01}, + {0xEB09, 0x7E, 0x01}, + {0xEB0A, 0x83, 0x01}, + {0xEB0B, 0xFF, 0x01}, + {0xEB0C, 0xF0, 0x01}, + {0xEB0D, 0x47, 0x01}, + {0xEB0E, 0x04, 0x01}, + {0xEB0F, 0x12, 0x01}, + {0xEB10, 0x81, 0x01}, + {0xEB11, 0xC4, 0x01}, + {0xEB12, 0x3F, 0x01}, + {0xEB13, 0xF1, 0x01}, + {0xEB14, 0x4F, 0x01}, + {0xEB15, 0xFC, 0x01}, + {0xEB16, 0x0F, 0x01}, + {0xEB17, 0x80, 0x01}, + {0xEB18, 0x84, 0x01}, + {0xEB19, 0xDF, 0x01}, + {0xEB1A, 0xE0, 0x01}, + {0xEB1B, 0x3F, 0x01}, + {0xEB1C, 0xFC, 0x01}, + {0xEB1D, 0x11, 0x01}, + {0xEB1E, 0x81, 0x01}, + {0xEB1F, 0x44, 0x01}, + {0xEB20, 0x20, 0x01}, + {0xEB21, 0x11, 0x01}, + {0xEB22, 0x38, 0x01}, + {0xEB23, 0x04, 0x01}, + {0xEB24, 0x0E, 0x01}, + {0xEB25, 0x01, 0x01}, + {0xEB26, 0xC3, 0x01}, + {0xEB27, 0xBF, 0x01}, + {0xEB28, 0x00, 0x01}, + {0xEB29, 0x30, 0x01}, + {0xEB2A, 0x00, 0x01}, + {0xEB2B, 0x0C, 0x01}, + {0xEB2C, 0x82, 0x01}, + {0xEB2D, 0x43, 0x01}, + {0xEB2E, 0x40, 0x01}, + {0xEB2F, 0x11, 0x01}, + {0xEB30, 0x50, 0x01}, + {0xEB31, 0x08, 0x01}, + {0xEB32, 0x0E, 0x01}, + {0xEB33, 0x82, 0x01}, + {0xEB34, 0xC3, 0x01}, + {0xEB35, 0xA0, 0x01}, + {0xEB36, 0x00, 0x01}, + {0xEB37, 0x18, 0x01}, + {0xEB38, 0x00, 0x01}, + {0xEB39, 0x04, 0x01}, + {0xEB3A, 0x81, 0x01}, + {0xEB3B, 0x01, 0x01}, + {0xEB3C, 0xC0, 0x01}, + {0xEB3D, 0x00, 0x01}, + {0xEB3E, 0x38, 0x01}, + {0xEB3F, 0x00, 0x01}, + {0xEB40, 0x0E, 0x01}, + {0xEB41, 0x83, 0x01}, + {0xEB42, 0xC2, 0x01}, + {0xEB43, 0xA0, 0x01}, + {0xEB44, 0x10, 0x01}, + {0xEB45, 0x18, 0x01}, + {0xEB46, 0x00, 0x01}, + {0xEB47, 0x04, 0x01}, + {0xEB48, 0x01, 0x01}, + {0xEB49, 0x01, 0x01}, + {0xEB4A, 0x00, 0x01}, + {0xEB4B, 0x00, 0x01}, + {0xEB4C, 0x18, 0x01}, + {0xEB4D, 0x08, 0x01}, + {0xEB4E, 0x0A, 0x01}, + {0xEB4F, 0x82, 0x01}, + {0xEB50, 0x02, 0x01}, + {0xEB51, 0x60, 0x01}, + {0xEB52, 0x00, 0x01}, + {0xEB53, 0x18, 0x01}, + {0xEB54, 0x04, 0x01}, + {0xEB55, 0x02, 0x01}, + {0xEB56, 0x81, 0x01}, + {0xEB57, 0x40, 0x01}, + {0xEB58, 0x20, 0x01}, + {0xEB59, 0x00, 0x01}, + {0xEB5A, 0x08, 0x01}, + {0xEB5B, 0x04, 0x01}, + {0xEB5C, 0x04, 0x01}, + {0xEB5D, 0x02, 0x01}, + {0xEB5E, 0x82, 0x01}, + {0xEB5F, 0x80, 0x01}, + {0xEB60, 0x30, 0x01}, + {0xEB61, 0x18, 0x01}, + {0xEB62, 0x0C, 0x01}, + {0xEB63, 0x06, 0x01}, + {0xEB64, 0x82, 0x01}, + {0xEB65, 0xC0, 0x01}, + {0xEB66, 0xFF, 0x01}, + {0xEB67, 0x0F, 0x01}, + {0xEB68, 0x00, 0x01}, + {0xEB69, 0x04, 0x01}, + {0xEB6A, 0x00, 0x01}, + {0xEB6B, 0x80, 0x01}, + {0xEB6C, 0x00, 0x01}, + {0xEB6D, 0x40, 0x01}, + {0xEB6E, 0x00, 0x01}, + {0xEB6F, 0x10, 0x01}, + {0xEB70, 0x00, 0x01}, + {0xEB71, 0x04, 0x01}, + {0xEB72, 0x00, 0x01}, + {0xEB73, 0x81, 0x01}, + {0xEB74, 0x60, 0x01}, + {0xEB75, 0x20, 0x01}, + {0xEB76, 0x00, 0x01}, + {0xEB77, 0x04, 0x01}, + {0xEB78, 0xFE, 0x01}, + {0xEB79, 0x82, 0x01}, + {0xEB7A, 0xC0, 0x01}, + {0xEB7B, 0x40, 0x01}, + {0xEB7C, 0x30, 0x01}, + {0xEB7D, 0x18, 0x01}, + {0xEB7E, 0x0C, 0x01}, + {0xEB7F, 0x06, 0x01}, + {0xEB80, 0x80, 0x01}, + {0xEB81, 0x01, 0x01}, + {0xEB82, 0x60, 0x01}, + {0xEB83, 0x30, 0x01}, + {0xEB84, 0x18, 0x01}, + {0xEB85, 0x08, 0x01}, + {0xEB86, 0x04, 0x01}, + {0xEB87, 0x80, 0x01}, + {0xEB88, 0xC0, 0x01}, + {0xEB89, 0x40, 0x01}, + {0xEB8A, 0x20, 0x01}, + {0xEB8B, 0x10, 0x01}, + {0xEB8C, 0x0C, 0x01}, + {0xEB8D, 0x06, 0x01}, + {0xEB8E, 0x83, 0x01}, + {0xEB8F, 0x41, 0x01}, + {0xEB90, 0x80, 0x01}, + {0xEB91, 0x10, 0x01}, + {0xEB92, 0x20, 0x01}, + {0xEB93, 0x04, 0x01}, + {0xEB94, 0x06, 0x01}, + {0xEB95, 0x82, 0x01}, + {0xEB96, 0x41, 0x01}, + {0xEB97, 0x60, 0x01}, + {0xEB98, 0x30, 0x01}, + {0xEB99, 0x28, 0x01}, + {0xEB9A, 0x08, 0x01}, + {0xEB9B, 0x08, 0x01}, + {0xEB9C, 0x82, 0x01}, + {0xEB9D, 0x82, 0x01}, + {0xEB9E, 0xA0, 0x01}, + {0xEB9F, 0xE0, 0x01}, + {0xEBA0, 0x2F, 0x01}, + {0xEBA1, 0xF8, 0x01}, + {0xEBA2, 0x0B, 0x01}, + {0xEBA3, 0x02, 0x01}, + {0xEBA4, 0x42, 0x01}, + {0xEBA5, 0xA0, 0x01}, + {0xEBA6, 0x20, 0x01}, + {0xEBA7, 0x28, 0x01}, + {0xEBA8, 0x10, 0x01}, + {0xEBA9, 0x0C, 0x01}, + {0xEBAA, 0x03, 0x01}, + {0xEBAB, 0x82, 0x01}, + {0xEBAC, 0xA0, 0x01}, + {0xEBAD, 0x20, 0x01}, + {0xEBAE, 0x28, 0x01}, + {0xEBAF, 0xF8, 0x01}, + {0xEBB0, 0x0B, 0x01}, + {0xEBB1, 0xFE, 0x01}, + {0xEBB2, 0x82, 0x01}, + {0xEBB3, 0x80, 0x01}, + {0xEBB4, 0x10, 0x01}, + {0xEBB5, 0x28, 0x01}, + {0xEBB6, 0x08, 0x01}, + {0xEBB7, 0x0A, 0x01}, + {0xEBB8, 0x04, 0x01}, + {0xEBB9, 0xC3, 0x01}, + {0xEBBA, 0x80, 0x01}, + {0xEBBB, 0x20, 0x01}, + {0xEBBC, 0x28, 0x01}, + {0xEBBD, 0x08, 0x01}, + {0xEBBE, 0x0A, 0x01}, + {0xEBBF, 0x03, 0x01}, + {0xEBC0, 0xFB, 0x01}, + {0xEBC1, 0xC0, 0x01}, + {0xEBC2, 0x3E, 0x01}, + {0xEBC3, 0xC0, 0x01}, + {0xEBC4, 0x0F, 0x01}, + {0xEBC5, 0xF4, 0x01}, + {0xEBC6, 0x02, 0x01}, + {0xEBC7, 0xFC, 0x01}, + {0xEBC8, 0x20, 0x01}, + {0xEBC9, 0x2F, 0x01}, + {0xEBCA, 0xB8, 0x01}, + {0xEBCB, 0x03, 0x01}, + {0xEBCC, 0xF8, 0x01}, + {0xEBCD, 0x00, 0x01}, + {0xEBCE, 0xFE, 0x01}, + {0xEBCF, 0xC0, 0x01}, + {0xEBD0, 0x3E, 0x01}, + {0xEBD1, 0xB0, 0x01}, + {0xEBD2, 0x0F, 0x01}, + {0xEBD3, 0xF0, 0x01}, + {0xEBD4, 0x03, 0x01}, + {0xEBD5, 0xBD, 0x01}, + {0xEBD6, 0x00, 0x01}, + {0xEBD7, 0x3F, 0x01}, + {0xEBD8, 0xC8, 0x01}, + {0xEBD9, 0x0B, 0x01}, + {0xEBDA, 0xEE, 0x01}, + {0xEBDB, 0x00, 0x01}, + {0xEBDC, 0x3E, 0x01}, + {0xEBDD, 0x80, 0x01}, + {0xEBDE, 0x2F, 0x01}, + {0xEBDF, 0xC8, 0x01}, + {0xEBE0, 0x0B, 0x01}, + {0xEBE1, 0xF2, 0x01}, + {0xEBE2, 0x83, 0x01}, + {0xEBE3, 0xBC, 0x01}, + {0xEBE4, 0xA0, 0x01}, + {0xEBE5, 0x0E, 0x01}, + {0xEBE6, 0xC0, 0x01}, + {0xEBE7, 0x03, 0x01}, + {0xEBE8, 0xF4, 0x01}, + {0xEBE9, 0x81, 0x01}, + {0xEBEA, 0x3D, 0x01}, + {0xEBEB, 0x00, 0x01}, + {0xEBEC, 0x0F, 0x01}, + {0xEBED, 0xC0, 0x01}, + {0xEBEE, 0x0F, 0x01}, + {0xEBEF, 0xEE, 0x01}, + {0xEBF0, 0x83, 0x01}, + {0xEBF1, 0xBB, 0x01}, + {0xEBF2, 0x60, 0x01}, + {0xEBF3, 0x0F, 0x01}, + {0xEBF4, 0xB8, 0x01}, + {0xEBF5, 0xFF, 0x01}, + {0xEBF6, 0xF3, 0x01}, + {0xEBF7, 0xFF, 0x01}, + {0xEBF8, 0x3C, 0x01}, + {0xEBF9, 0x40, 0x01}, + {0xEBFA, 0x0F, 0x01}, + {0xEBFB, 0xC8, 0x01}, + {0xEBFC, 0x03, 0x01}, + {0xEBFD, 0xF2, 0x01}, + {0xEBFE, 0x04, 0x01}, + {0xEBFF, 0x3E, 0x01}, + {0xEC00, 0x81, 0x01}, + {0xEC01, 0x0F, 0x01}, + {0xEC02, 0xD0, 0x01}, + {0xEC03, 0x03, 0x01}, + {0xEC04, 0xF6, 0x01}, + {0xEC05, 0x00, 0x01}, + {0xEC06, 0x3D, 0x01}, + {0xEC07, 0xE0, 0x01}, + {0xEC08, 0xFE, 0x01}, + {0xEC09, 0xD7, 0x01}, + {0xEC0A, 0x03, 0x01}, + {0xEC0B, 0xF4, 0x01}, + {0xEC0C, 0x00, 0x01}, + {0xEC0D, 0x3D, 0x01}, + {0xEC0E, 0xE1, 0x01}, + {0xEC0F, 0x4F, 0x01}, + {0xEC10, 0xF8, 0x01}, + {0xEC11, 0x0F, 0x01}, + {0xEC12, 0xF4, 0x01}, + {0xEC13, 0x80, 0x01}, + {0xEC14, 0xFE, 0x01}, + {0xEC15, 0x9F, 0x01}, + {0xEC16, 0x0F, 0x01}, + {0xEC17, 0xE0, 0x01}, + {0xEC18, 0x03, 0x01}, + {0xEC19, 0xFA, 0x01}, + {0xEC1A, 0x80, 0x01}, + {0xEC1B, 0x3D, 0x01}, + {0xEC1C, 0x60, 0x01}, + {0xEC1D, 0x5F, 0x01}, + {0xEC1E, 0xF0, 0x01}, + {0xEC1F, 0x17, 0x01}, + {0xEC20, 0xFC, 0x01}, + {0xEC21, 0x02, 0x01}, + {0xEC22, 0x41, 0x01}, + {0xEC23, 0xC0, 0x01}, + {0xEC24, 0x1F, 0x01}, + {0xEC25, 0xF8, 0x01}, + {0xEC26, 0x03, 0x01}, + {0xEC27, 0x02, 0x01}, + {0xEC28, 0xFF, 0x01}, + {0xEC29, 0x3F, 0x01}, + {0xEC2A, 0xC0, 0x01}, + {0xEC2B, 0x0F, 0x01}, + {0xEC2C, 0xF0, 0x01}, + {0xEC2D, 0x1F, 0x01}, + {0xEC2E, 0x04, 0x01}, + {0xEC2F, 0x07, 0x01}, + {0xEC30, 0x41, 0x01}, + {0xEC31, 0x61, 0x01}, + {0xEC32, 0x20, 0x01}, + {0xEC33, 0x10, 0x01}, + {0xEC34, 0x04, 0x01}, + {0xEC35, 0x04, 0x01}, + {0xEC36, 0x81, 0x01}, + {0xEC37, 0x3F, 0x01}, + {0xEC38, 0x80, 0x01}, + {0xEC39, 0x20, 0x01}, + {0xEC3A, 0x10, 0x01}, + {0xEC3B, 0x08, 0x01}, + {0xEC3C, 0x04, 0x01}, + {0xEC3D, 0x05, 0x01}, + {0xEC3E, 0x41, 0x01}, + {0xEC3F, 0x41, 0x01}, + {0xEC40, 0x50, 0x01}, + {0xEC41, 0x30, 0x01}, + {0xEC42, 0x10, 0x01}, + {0xEC43, 0x02, 0x01}, + {0xEC44, 0x82, 0x01}, + {0xEC45, 0x81, 0x01}, + {0xEC46, 0xC0, 0x01}, + {0xEC47, 0x20, 0x01}, + {0xEC48, 0x18, 0x01}, + {0xEC49, 0x0C, 0x01}, + {0xEC4A, 0x04, 0x01}, + {0xEC4B, 0x03, 0x01}, + {0xEC4C, 0xC1, 0x01}, + {0xEC4D, 0x21, 0x01}, + {0xEC4E, 0x70, 0x01}, + {0xEC4F, 0x08, 0x01}, + {0xEC50, 0x20, 0x01}, + {0xEC51, 0x02, 0x01}, + {0xEC52, 0x84, 0x01}, + {0xEC53, 0x83, 0x01}, + {0xEC54, 0xC0, 0x01}, + {0xEC55, 0x20, 0x01}, + {0xEC56, 0x20, 0x01}, + {0xEC57, 0x04, 0x01}, + {0xEC58, 0x04, 0x01}, + {0xEC59, 0x02, 0x01}, + {0xEC5A, 0x82, 0x01}, + {0xEC5B, 0x80, 0x01}, + {0xEC5C, 0x50, 0x01}, + {0xEC5D, 0x08, 0x01}, + {0xEC5E, 0x14, 0x01}, + {0xEC5F, 0x02, 0x01}, + {0xEC60, 0x04, 0x01}, + {0xEC61, 0x04, 0x01}, + {0xEC62, 0x41, 0x01}, + {0xEC63, 0x30, 0x01}, + {0xEC64, 0x38, 0x01}, + {0xEC65, 0x04, 0x01}, + {0xEC66, 0x0C, 0x01}, + {0xEC67, 0x02, 0x01}, + {0xEC68, 0x81, 0x01}, + {0xEC69, 0x80, 0x01}, + {0xEC6A, 0x20, 0x01}, + {0xEC6B, 0x20, 0x01}, + {0xEC6C, 0x14, 0x01}, + {0xEC6D, 0x02, 0x01}, + {0xEC6E, 0x85, 0x01}, + {0xEC6F, 0x00, 0x01}, + {0xEC70, 0x01, 0x01}, + {0xEC71, 0x41, 0x01}, + {0xEC72, 0x10, 0x01}, + {0xEC73, 0x0C, 0x01}, + {0xEC74, 0x0E, 0x01}, + {0xEC75, 0x01, 0x01}, + {0xEC76, 0x83, 0x01}, + {0xEC77, 0x40, 0x01}, + {0xEC78, 0x20, 0x01}, + {0xEC79, 0x20, 0x01}, + {0xEC7A, 0x08, 0x01}, + {0xEC7B, 0x08, 0x01}, + + + {0xED02, 0x85, 0x01}, + {0xED03, 0xAA, 0x01}, + {0xED04, 0xD8, 0x01}, + {0xED05, 0x9A, 0x01}, + {0xED06, 0xE6, 0x01}, + {0xED07, 0x65, 0x01}, + {0xED08, 0x25, 0x01}, + {0xED09, 0x6C, 0x01}, + {0xED0A, 0xC9, 0x01}, + {0xED0B, 0xE8, 0x01}, + {0xED0C, 0x56, 0x01}, + {0xED0D, 0x21, 0x01}, + {0xED0E, 0xA2, 0x01}, + {0xED0F, 0x54, 0x01}, + {0xED10, 0x88, 0x01}, + {0xED11, 0x2C, 0x01}, + {0xED12, 0x45, 0x01}, + {0xED13, 0x23, 0x01}, + {0xED14, 0x5A, 0x01}, + {0xED15, 0x41, 0x01}, + {0xED16, 0xA9, 0x01}, + {0xED17, 0x59, 0x01}, + {0xED18, 0x67, 0x01}, + {0xED19, 0xCA, 0x01}, + {0xED1A, 0x96, 0x01}, + {0xED1B, 0x93, 0x01}, + {0xED1C, 0x76, 0x01}, + {0xED1D, 0x35, 0x01}, + {0xED1E, 0xA1, 0x01}, + {0xED1F, 0x38, 0x01}, + {0xED20, 0x89, 0x01}, + {0xED21, 0x67, 0x01}, + {0xED22, 0x46, 0x01}, + {0xED23, 0xC1, 0x01}, + {0xED24, 0x71, 0x01}, + {0xED25, 0x10, 0x01}, + {0xED26, 0x6C, 0x01}, + {0xED27, 0xEC, 0x01}, + {0xED28, 0x13, 0x01}, + {0xED29, 0x9B, 0x01}, + {0xED2A, 0xFC, 0x01}, + {0xED2B, 0x10, 0x01}, + {0xED2C, 0x87, 0x01}, + {0xED2D, 0x42, 0x01}, + {0xED2E, 0xE9, 0x01}, + {0xED2F, 0x29, 0x01}, + {0xED30, 0x92, 0x01}, + {0xED31, 0x86, 0x01}, + {0xED32, 0xFC, 0x01}, + {0xED33, 0x74, 0x01}, + {0xED34, 0x21, 0x01}, + {0xED35, 0x39, 0x01}, + {0xED36, 0x31, 0x01}, + {0xED37, 0xE7, 0x01}, + {0xED38, 0x41, 0x01}, + {0xED39, 0x9D, 0x01}, + {0xED3A, 0x89, 0x01}, + {0xED3B, 0xCE, 0x01}, + {0xED3C, 0x5F, 0x01}, + {0xED3D, 0x58, 0x01}, + {0xED3E, 0x03, 0x01}, + {0xED3F, 0x17, 0x01}, + {0xED40, 0xCD, 0x01}, + {0xED41, 0xCC, 0x01}, + {0xED42, 0xC5, 0x01}, + {0xED43, 0x33, 0x01}, + {0xED44, 0x85, 0x01}, + {0xED45, 0xD1, 0x01}, + {0xED46, 0x0D, 0x01}, + {0xED47, 0x69, 0x01}, + {0xED48, 0xD4, 0x01}, + {0xED49, 0x53, 0x01}, + {0xED4A, 0x1D, 0x01}, + {0xED4B, 0x18, 0x01}, + {0xED4C, 0x7D, 0x01}, + {0xED4D, 0x07, 0x01}, + {0xED4E, 0x45, 0x01}, + {0xED4F, 0x9D, 0x01}, + {0xED50, 0x69, 0x01}, + {0xED51, 0x4E, 0x01}, + {0xED52, 0x5B, 0x01}, + {0xED53, 0x16, 0x01}, + {0xED54, 0x83, 0x01}, + {0xED55, 0x94, 0x01}, + {0xED56, 0xAE, 0x01}, + {0xED57, 0xE0, 0x01}, + {0xED58, 0x24, 0x01}, + {0xED59, 0x29, 0x01}, + {0xED5A, 0x3C, 0x01}, + {0xED5B, 0x79, 0x01}, + {0xED5C, 0x8A, 0x01}, + {0xED5D, 0x54, 0x01}, + {0xED5E, 0xE0, 0x01}, + {0xED5F, 0x72, 0x01}, + {0xED60, 0x17, 0x01}, + {0xED61, 0xD3, 0x01}, + {0xED62, 0x90, 0x01}, + {0xED63, 0x06, 0x01}, + {0xED64, 0x3D, 0x01}, + {0xED65, 0xC1, 0x01}, + {0xED66, 0xD1, 0x01}, + {0xED67, 0x0F, 0x01}, + {0xED68, 0x5F, 0x01}, + {0xED69, 0x3C, 0x01}, + {0xED6A, 0x53, 0x01}, + {0xED6B, 0x14, 0x01}, + {0xED6C, 0xAB, 0x01}, + {0xED6D, 0x84, 0x01}, + {0xED6E, 0x24, 0x01}, + {0xED6F, 0x25, 0x01}, + {0xED70, 0x11, 0x01}, + {0xED71, 0xB1, 0x01}, + {0xED72, 0x08, 0x01}, + {0xED73, 0x45, 0x01}, + {0xED74, 0x34, 0x01}, + {0xED75, 0xB2, 0x01}, + {0xED76, 0x92, 0x01}, + {0xED77, 0x9C, 0x01}, + {0xED78, 0x5C, 0x01}, + {0xED79, 0x65, 0x01}, + {0xED7A, 0x2E, 0x01}, + {0xED7B, 0x8E, 0x01}, + {0xED7C, 0x09, 0x01}, + {0xED7D, 0x8E, 0x01}, + {0xED7E, 0x6C, 0x01}, + {0xED7F, 0xC6, 0x01}, + {0xED80, 0x93, 0x01}, + {0xED81, 0x96, 0x01}, + {0xED82, 0xC1, 0x01}, + {0xED83, 0xC4, 0x01}, + {0xED84, 0x64, 0x01}, + {0xED85, 0x27, 0x01}, + {0xED86, 0x0E, 0x01}, + {0xED87, 0x89, 0x01}, + {0xED88, 0x08, 0x01}, + {0xED89, 0x40, 0x01}, + {0xED8A, 0x02, 0x01}, + {0xED8B, 0x22, 0x01}, + {0xED8C, 0x10, 0x01}, + {0xED8D, 0x82, 0x01}, + {0xED8E, 0x64, 0x01}, + {0xED8F, 0x24, 0x01}, + {0xED90, 0x24, 0x01}, + {0xED91, 0x44, 0x01}, + {0xED92, 0xD1, 0x01}, + {0xED93, 0x0A, 0x01}, + {0xED94, 0x60, 0x01}, + {0xED95, 0x58, 0x01}, + {0xED96, 0x53, 0x01}, + {0xED97, 0x1B, 0x01}, + {0xED98, 0xF2, 0x01}, + {0xED99, 0xA8, 0x01}, + {0xED9A, 0x65, 0x01}, + {0xED9B, 0x30, 0x01}, + {0xED9C, 0x32, 0x01}, + {0xED9D, 0xD9, 0x01}, + {0xED9E, 0x89, 0x01}, + {0xED9F, 0x43, 0x01}, + {0xEDA0, 0x20, 0x01}, + {0xEDA1, 0x12, 0x01}, + {0xEDA2, 0x10, 0x01}, + {0xEDA3, 0x80, 0x01}, + {0xEDA4, 0x10, 0x01}, + {0xEDA5, 0x84, 0x01}, + {0xEDA6, 0x20, 0x01}, + {0xEDA7, 0x19, 0x01}, + {0xEDA8, 0x01, 0x01}, + {0xEDA9, 0x49, 0x01}, + {0xEDAA, 0x51, 0x01}, + {0xEDAB, 0xB2, 0x01}, + {0xEDAC, 0x12, 0x01}, + {0xEDAD, 0x98, 0x01}, + {0xEDAE, 0xD5, 0x01}, + {0xEDAF, 0xFC, 0x01}, + {0xEDB0, 0x46, 0x01}, + {0xEDB1, 0x3E, 0x01}, + {0xEDB2, 0x7C, 0x01}, + {0xEDB3, 0xC9, 0x01}, + {0xEDB4, 0xCC, 0x01}, + {0xEDB5, 0x51, 0x01}, + {0xEDB6, 0xAC, 0x01}, + {0xEDB7, 0x32, 0x01}, + {0xEDB8, 0x12, 0x01}, + {0xEDB9, 0x93, 0x01}, + {0xEDBA, 0x4C, 0x01}, + {0xEDBB, 0x84, 0x01}, + {0xEDBC, 0x22, 0x01}, + {0xEDBD, 0x17, 0x01}, + {0xEDBE, 0xD9, 0x01}, + {0xEDBF, 0xC8, 0x01}, + {0xEDC0, 0x4B, 0x01}, + {0xEDC1, 0x74, 0x01}, + {0xEDC2, 0xA2, 0x01}, + {0xEDC3, 0x95, 0x01}, + {0xEDC4, 0xB9, 0x01}, + {0xEDC5, 0x48, 0x01}, + {0xEDC6, 0x06, 0x01}, + {0xEDC7, 0x38, 0x01}, + {0xEDC8, 0xDC, 0x01}, + {0xEDC9, 0xC9, 0x01}, + {0xEDCA, 0xD0, 0x01}, + {0xEDCB, 0x66, 0x01}, + {0xEDCC, 0x86, 0x01}, + {0xEDCD, 0xD3, 0x01}, + {0xEDCE, 0x96, 0x01}, + {0xEDCF, 0xC3, 0x01}, + {0xEDD0, 0x28, 0x01}, + {0xEDD1, 0x45, 0x01}, + {0xEDD2, 0x2B, 0x01}, + {0xEDD3, 0x39, 0x01}, + {0xEDD4, 0x31, 0x01}, + {0xEDD5, 0xCA, 0x01}, + {0xEDD6, 0x4F, 0x01}, + {0xEDD7, 0x9C, 0x01}, + {0xEDD8, 0x62, 0x01}, + {0xEDD9, 0x15, 0x01}, + {0xEDDA, 0xB6, 0x01}, + {0xEDDB, 0xF4, 0x01}, + {0xEDDC, 0x45, 0x01}, + {0xEDDD, 0x34, 0x01}, + {0xEDDE, 0xAD, 0x01}, + {0xEDDF, 0x29, 0x01}, + {0xEDE0, 0x4F, 0x01}, + {0xEDE1, 0x84, 0x01}, + {0xEDE2, 0xC4, 0x01}, + {0xEDE3, 0x84, 0x01}, + {0xEDE4, 0x9C, 0x01}, + {0xEDE5, 0x01, 0x01}, + {0xEDE6, 0x6D, 0x01}, + {0xEDE7, 0x06, 0x01}, + {0xEDE8, 0x39, 0x01}, + {0xEDE9, 0x7F, 0x01}, + {0xEDEA, 0x11, 0x01}, + {0xEDEB, 0x0D, 0x01}, + {0xEDEC, 0x5C, 0x01}, + {0xEDED, 0x26, 0x01}, + {0xEDEE, 0x53, 0x01}, + {0xEDEF, 0x17, 0x01}, + {0xEDF0, 0xCE, 0x01}, + {0xEDF1, 0x20, 0x01}, + {0xEDF2, 0xC6, 0x01}, + {0xEDF3, 0x36, 0x01}, + {0xEDF4, 0xA8, 0x01}, + {0xEDF5, 0x11, 0x01}, + {0xEDF6, 0x0F, 0x01}, + {0xEDF7, 0x76, 0x01}, + {0xEDF8, 0x44, 0x01}, + {0xEDF9, 0x34, 0x01}, + {0xEDFA, 0x24, 0x01}, + {0xEDFB, 0x53, 0x01}, + {0xEDFC, 0x15, 0x01}, + {0xEDFD, 0x08, 0x01}, + {0xEDFE, 0x4B, 0x01}, + {0xEDFF, 0xD5, 0x01}, + {0xEE00, 0xC9, 0x01}, + {0xEE01, 0x90, 0x01}, + {0xEE02, 0x6D, 0x01}, + {0xEE03, 0xEA, 0x01}, + {0xEE04, 0x93, 0x01}, + {0xEE05, 0x1A, 0x01}, + {0xEE06, 0xF3, 0x01}, + {0xEE07, 0xB8, 0x01}, + {0xEE08, 0xC6, 0x01}, + {0xEE09, 0x3D, 0x01}, + {0xEE0A, 0xC0, 0x01}, + {0xEE0B, 0x19, 0x01}, + {0xEE0C, 0xD0, 0x01}, + {0xEE0D, 0x78, 0x01}, + {0xEE0E, 0x64, 0x01}, + {0xEE0F, 0x24, 0x01}, + {0xEE10, 0xA1, 0x01}, + {0xEE11, 0x37, 0x01}, + {0xEE12, 0xD1, 0x01}, + {0xEE13, 0x89, 0x01}, + {0xEE14, 0x5A, 0x01}, + {0xEE15, 0x51, 0x01}, + {0xEE16, 0x72, 0x01}, + {0xEE17, 0xD5, 0x01}, + {0xEE18, 0x8C, 0x01}, + {0xEE19, 0x14, 0x01}, + {0xEE1A, 0x05, 0x01}, + {0xEE1B, 0xA1, 0x01}, + {0xEE1C, 0x33, 0x01}, + {0xEE1D, 0xF9, 0x01}, + {0xEE1E, 0xE7, 0x01}, + {0xEE1F, 0x4A, 0x01}, + {0xEE20, 0x01, 0x01}, + {0xEE21, 0xCA, 0x01}, + {0xEE22, 0xD2, 0x01}, + {0xEE23, 0x86, 0x01}, + {0xEE24, 0xE4, 0x01}, + {0xEE25, 0x94, 0x01}, + {0xEE26, 0x23, 0x01}, + {0xEE27, 0x4A, 0x01}, + {0xEE28, 0x55, 0x01}, + {0xEE29, 0x29, 0x01}, + {0xEE2A, 0x57, 0x01}, + {0xEE2B, 0x74, 0x01}, + {0xEE2C, 0x6A, 0x01}, + {0xEE2D, 0x14, 0x01}, + {0xEE2E, 0x95, 0x01}, + {0xEE2F, 0xEA, 0x01}, + {0xEE30, 0x94, 0x01}, + {0xEE31, 0xA3, 0x01}, + {0xEE32, 0x2C, 0x01}, + {0xEE33, 0x75, 0x01}, + {0xEE34, 0x28, 0x01}, + {0xEE35, 0x47, 0x01}, + {0xEE36, 0x0F, 0x01}, + {0xEE37, 0x2A, 0x01}, + {0xEE38, 0xD1, 0x01}, + {0xEE39, 0x84, 0x01}, + {0xEE3A, 0x4E, 0x01}, + {0xEE3B, 0x44, 0x01}, + {0xEE3C, 0x22, 0x01}, + {0xEE3D, 0x1E, 0x01}, + {0xEE3E, 0xE1, 0x01}, + {0xEE3F, 0x28, 0x01}, + {0xEE40, 0x4B, 0x01}, + {0xEE41, 0x4D, 0x01}, + {0xEE42, 0xC2, 0x01}, + {0xEE43, 0x53, 0x01}, + {0xEE44, 0x8D, 0x01}, + {0xEE45, 0xA4, 0x01}, + {0xEE46, 0xC4, 0x01}, + {0xEE47, 0x9F, 0x01}, + {0xEE48, 0x0B, 0x01}, + {0xEE49, 0x49, 0x01}, + {0xEE4A, 0xE7, 0x01}, + {0xEE4B, 0x3C, 0x01}, + {0xEE4C, 0xB5, 0x01}, + {0xEE4D, 0x29, 0x01}, + {0xEE4E, 0x8E, 0x01}, + {0xEE4F, 0x69, 0x01}, + {0xEE50, 0x6A, 0x01}, + {0xEE51, 0x93, 0x01}, + {0xEE52, 0x1A, 0x01}, + {0xEE53, 0xDC, 0x01}, + {0xEE54, 0xE0, 0x01}, + {0xEE55, 0x66, 0x01}, + {0xEE56, 0x39, 0x01}, + {0xEE57, 0xD7, 0x01}, + {0xEE58, 0x91, 0x01}, + {0xEE59, 0x8F, 0x01}, + {0xEE5A, 0x80, 0x01}, + {0xEE5B, 0x46, 0x01}, + {0xEE5C, 0xB4, 0x01}, + {0xEE5D, 0x1F, 0x01}, + {0xEE5E, 0x0C, 0x01}, + {0xEE5F, 0xE5, 0x01}, + {0xEE60, 0xC6, 0x01}, + {0xEE61, 0x39, 0x01}, + {0xEE62, 0x92, 0x01}, + {0xEE63, 0x01, 0x01}, + {0xEE64, 0x0D, 0x01}, + {0xEE65, 0x5E, 0x01}, + {0xEE66, 0x04, 0x01}, + {0xEE67, 0xB3, 0x01}, + {0xEE68, 0x16, 0x01}, + {0xEE69, 0xBA, 0x01}, + {0xEE6A, 0xB8, 0x01}, + {0xEE6B, 0x05, 0x01}, + {0xEE6C, 0x2F, 0x01}, + {0xEE6D, 0x7D, 0x01}, + {0xEE6E, 0x51, 0x01}, + {0xEE6F, 0xCC, 0x01}, + {0xEE70, 0x65, 0x01}, + {0xEE71, 0x52, 0x01}, + {0xEE72, 0x23, 0x01}, + {0xEE73, 0x9C, 0x01}, + {0xEE74, 0xED, 0x01}, + {0xEE75, 0x14, 0x01}, + {0xEE76, 0x67, 0x01}, + {0xEE77, 0x3B, 0x01}, + {0xEE78, 0x8D, 0x01}, + {0xEE79, 0xE1, 0x01}, + {0xEE7A, 0x0C, 0x01}, + {0xEE7B, 0x59, 0x01}, + {0xEE7C, 0xDE, 0x01}, + {0xEE7D, 0x42, 0x01}, + {0xEE7E, 0x94, 0x01}, + {0xEE7F, 0xA5, 0x01}, + {0xEE80, 0xDC, 0x01}, + {0xEE81, 0x64, 0x01}, + {0xEE82, 0x27, 0x01}, + {0xEE83, 0x3A, 0x01}, + {0xEE84, 0xF9, 0x01}, + {0xEE85, 0x89, 0x01}, + {0xEE86, 0x53, 0x01}, + {0xEE87, 0xAC, 0x01}, + {0xEE88, 0xE2, 0x01}, + {0xEE89, 0x96, 0x01}, + {0xEE8A, 0xBD, 0x01}, + {0xEE8B, 0x54, 0x01}, + {0xEE8C, 0xE6, 0x01}, + {0xEE8D, 0x34, 0x01}, + {0xEE8E, 0xAA, 0x01}, + {0xEE8F, 0xE1, 0x01}, + {0xEE90, 0x0D, 0x01}, + {0xEE91, 0x5C, 0x01}, + {0xEE92, 0xF8, 0x01}, + {0xEE93, 0xF2, 0x01}, + {0xEE94, 0x93, 0x01}, + {0xEE95, 0xA3, 0x01}, + {0xEE96, 0x78, 0x01}, + {0xEE97, 0x64, 0x01}, + {0xEE98, 0x24, 0x01}, + {0xEE99, 0x12, 0x01}, + {0xEE9A, 0x99, 0x01}, + {0xEE9B, 0x88, 0x01}, + {0xEE9C, 0x45, 0x01}, + {0xEE9D, 0x2C, 0x01}, + {0xEE9E, 0xA2, 0x01}, + {0xEE9F, 0x92, 0x01}, + {0xEEA0, 0x96, 0x01}, + {0xEEA1, 0x3C, 0x01}, + {0xEEA2, 0x05, 0x01}, + {0xEEA3, 0x2B, 0x01}, + {0xEEA4, 0x7F, 0x01}, + {0xEEA5, 0x79, 0x01}, + {0xEEA6, 0x8C, 0x01}, + {0xEEA7, 0x67, 0x01}, + {0xEEA8, 0x5E, 0x01}, + {0xEEA9, 0xF3, 0x01}, + {0xEEAA, 0x95, 0x01}, + {0xEEAB, 0xB4, 0x01}, + {0xEEAC, 0xB4, 0x01}, + {0xEEAD, 0x44, 0x01}, + {0xEEAE, 0x26, 0x01}, + {0xEEAF, 0x0C, 0x01}, + {0xEEB0, 0x79, 0x01}, + {0xEEB1, 0x08, 0x01}, + {0xEEB2, 0x40, 0x01}, + {0xEEB3, 0x02, 0x01}, + {0xEEB4, 0x42, 0x01}, + {0xEEB5, 0x90, 0x01}, + {0xEEB6, 0x81, 0x01}, + {0xEEB7, 0x60, 0x01}, + {0xEEB8, 0x24, 0x01}, + {0xEEB9, 0x23, 0x01}, + {0xEEBA, 0x3E, 0x01}, + {0xEEBB, 0x21, 0x01}, + {0xEEBC, 0x4A, 0x01}, + {0xEEBD, 0x5C, 0x01}, + {0xEEBE, 0xFE, 0x01}, + {0xEEBF, 0xE2, 0x01}, + {0xEEC0, 0x99, 0x01}, + {0xEEC1, 0xD5, 0x01}, + {0xEEC2, 0x7C, 0x01}, + {0xEEC3, 0xC5, 0x01}, + {0xEEC4, 0x2C, 0x01}, + {0xEEC5, 0x2B, 0x01}, + {0xEEC6, 0x89, 0x01}, + {0xEEC7, 0x09, 0x01}, + {0xEEC8, 0x43, 0x01}, + {0xEEC9, 0x1C, 0x01}, + {0xEECA, 0x02, 0x01}, + {0xEECB, 0x10, 0x01}, + {0xEECC, 0x80, 0x01}, + {0xEECD, 0x0C, 0x01}, + {0xEECE, 0x64, 0x01}, + {0xEECF, 0x20, 0x01}, + {0xEED0, 0x16, 0x01}, + {0xEED1, 0xC9, 0x01}, + {0xEED2, 0x08, 0x01}, + {0xEED3, 0x4F, 0x01}, + {0xEED4, 0x88, 0x01}, + {0xEED5, 0xE2, 0x01}, + {0xEED6, 0x96, 0x01}, + {0xEED7, 0xBF, 0x01}, + {0xEED8, 0xAC, 0x01}, + {0xEED9, 0xC6, 0x01}, + {0xEEDA, 0x36, 0x01}, + {0xEEDB, 0x70, 0x01}, + {0xEEDC, 0xB1, 0x01}, + {0xEEDD, 0xCB, 0x01}, + {0xEEDE, 0x4F, 0x01}, + {0xEEDF, 0x86, 0x01}, + {0xEEE0, 0xD2, 0x01}, + {0xEEE1, 0x11, 0x01}, + {0xEEE2, 0x90, 0x01}, + {0xEEE3, 0x3C, 0x01}, + {0xEEE4, 0x04, 0x01}, + {0xEEE5, 0x22, 0x01}, + {0xEEE6, 0x13, 0x01}, + {0xEEE7, 0xA1, 0x01}, + {0xEEE8, 0xC8, 0x01}, + {0xEEE9, 0x49, 0x01}, + {0xEEEA, 0x58, 0x01}, + {0xEEEB, 0xC2, 0x01}, + {0xEEEC, 0x94, 0x01}, + {0xEEED, 0xAB, 0x01}, + {0xEEEE, 0xE8, 0x01}, + {0xEEEF, 0xE5, 0x01}, + {0xEEF0, 0x31, 0x01}, + {0xEEF1, 0xC5, 0x01}, + {0xEEF2, 0x89, 0x01}, + {0xEEF3, 0x0E, 0x01}, + {0xEEF4, 0x63, 0x01}, + {0xEEF5, 0x26, 0x01}, + {0xEEF6, 0x33, 0x01}, + {0xEEF7, 0x96, 0x01}, + {0xEEF8, 0xB3, 0x01}, + {0xEEF9, 0x0C, 0x01}, + {0xEEFA, 0xA5, 0x01}, + {0xEEFB, 0x28, 0x01}, + {0xEEFC, 0x33, 0x01}, + {0xEEFD, 0xB1, 0x01}, + {0xEEFE, 0xC9, 0x01}, + {0xEEFF, 0x4D, 0x01}, + {0xEF00, 0x76, 0x01}, + {0xEF01, 0x92, 0x01}, + {0xEF02, 0x94, 0x01}, + {0xEF03, 0xA9, 0x01}, + {0xEF04, 0xA8, 0x01}, + {0xEF05, 0x25, 0x01}, + {0xEF06, 0x2F, 0x01}, + {0xEF07, 0x8E, 0x01}, + {0xEF08, 0x49, 0x01}, + {0xEF09, 0xCD, 0x01}, + {0xEF0A, 0x7E, 0x01}, + {0xEF0B, 0x06, 0x01}, + {0xEF0C, 0x94, 0x01}, + {0xEF0D, 0x9B, 0x01}, + {0xEF0E, 0xDF, 0x01}, + {0xEF0F, 0x44, 0x01}, + {0xEF10, 0xA6, 0x01}, + {0xEF11, 0x32, 0x01}, + {0xEF12, 0x75, 0x01}, + {0xEF13, 0xD9, 0x01}, + {0xEF14, 0xCB, 0x01}, + {0xEF15, 0x59, 0x01}, + {0xEF16, 0xDC, 0x01}, + {0xEF17, 0x82, 0x01}, + {0xEF18, 0x96, 0x01}, + {0xEF19, 0xB9, 0x01}, + {0xEF1A, 0xD4, 0x01}, + {0xEF1B, 0xC5, 0x01}, + {0xEF1C, 0x30, 0x01}, + {0xEF1D, 0x8E, 0x01}, + {0xEF1E, 0x41, 0x01}, + {0xEF1F, 0xCD, 0x01}, + {0xEF20, 0x6C, 0x01}, + {0xEF21, 0xAE, 0x01}, + {0xEF22, 0xD3, 0x01}, + {0xEF23, 0x22, 0x01}, + {0xEF24, 0x1C, 0x01}, + {0xEF25, 0xD5, 0x01}, + {0xEF26, 0x07, 0x01}, + {0xEF27, 0x40, 0x01}, + {0xEF28, 0xC7, 0x01}, + {0xEF29, 0x99, 0x01}, + {0xEF2A, 0xCE, 0x01}, + {0xEF2B, 0x6A, 0x01}, + {0xEF2C, 0x6A, 0x01}, + {0xEF2D, 0xC3, 0x01}, + {0xEF2E, 0x19, 0x01}, + {0xEF2F, 0xD5, 0x01}, + {0xEF30, 0x6C, 0x01}, + {0xEF31, 0xC6, 0x01}, + {0xEF32, 0x35, 0x01}, + {0xEF33, 0xA9, 0x01}, + {0xEF34, 0x09, 0x01}, + {0xEF35, 0x4E, 0x01}, + {0xEF36, 0x71, 0x01}, + {0xEF37, 0xCA, 0x01}, + {0xEF38, 0xC3, 0x01}, + {0xEF39, 0x1E, 0x01}, + {0xEF3A, 0x0A, 0x01}, + {0xEF3B, 0x55, 0x01}, + {0xEF3C, 0x09, 0x01}, + {0xEF3D, 0x4D, 0x01}, + {0xEF3E, 0x39, 0x01}, + {0xEF3F, 0x8A, 0x01}, + {0xEF40, 0x52, 0x01}, + {0xEF41, 0x86, 0x01}, + {0xEF42, 0x6E, 0x01}, + {0xEF43, 0xD4, 0x01}, + {0xEF44, 0x1F, 0x01}, + {0xEF45, 0x09, 0x01}, + {0xEF46, 0xA1, 0x01}, + {0xEF47, 0x87, 0x01}, + {0xEF48, 0x40, 0x01}, + {0xEF49, 0xE5, 0x01}, + {0xEF4A, 0x39, 0x01}, + {0xEF4B, 0x10, 0x01}, + {0xEF4C, 0x7E, 0x01}, + {0xEF4D, 0x40, 0x01}, + {0xEF4E, 0x14, 0x01}, + {0xEF4F, 0x21, 0x01}, + {0xEF50, 0x1F, 0x01}, + {0xEF51, 0x81, 0x01}, + {0xEF52, 0x08, 0x01}, + {0xEF53, 0x4B, 0x01}, + + + {0xEF54, 0xC7, 0x01}, + {0xEF55, 0x82, 0x01}, + {0xEF56, 0x55, 0x01}, + {0xEF57, 0xA6, 0x01}, + {0xEF58, 0xEE, 0x01}, + {0xEF59, 0xA4, 0x01}, + {0xEF5A, 0x25, 0x01}, + {0xEF5B, 0x2F, 0x01}, + {0xEF5C, 0xD5, 0x01}, + {0xEF5D, 0x09, 0x01}, + {0xEF5E, 0x52, 0x01}, + {0xEF5F, 0x96, 0x01}, + {0xEF60, 0x02, 0x01}, + {0xEF61, 0x94, 0x01}, + {0xEF62, 0x8F, 0x01}, + {0xEF63, 0x0C, 0x01}, + {0xEF64, 0x34, 0x01}, + {0xEF65, 0x1E, 0x01}, + {0xEF66, 0xE7, 0x01}, + {0xEF67, 0x40, 0x01}, + {0xEF68, 0xE7, 0x01}, + {0xEF69, 0x3C, 0x01}, + {0xEF6A, 0x14, 0x01}, + {0xEF6B, 0x4A, 0x01}, + {0xEF6C, 0x92, 0x01}, + {0xEF6D, 0x90, 0x01}, + {0xEF6E, 0xD0, 0x01}, + {0xEF6F, 0x13, 0x01}, + {0xEF70, 0x1B, 0x01}, + {0xEF71, 0xC7, 0x01}, + {0xEF72, 0xF8, 0x01}, + {0xEF73, 0x25, 0x01}, + {0xEF74, 0x30, 0x01}, + {0xEF75, 0x98, 0x01}, + {0xEF76, 0x19, 0x01}, + {0xEF77, 0x4E, 0x01}, + {0xEF78, 0x81, 0x01}, + {0xEF79, 0x02, 0x01}, + {0xEF7A, 0xE4, 0x01}, + {0xEF7B, 0x1A, 0x01}, + {0xEF7C, 0xBA, 0x01}, + {0xEF7D, 0x30, 0x01}, + {0xEF7E, 0x45, 0x01}, + {0xEF7F, 0x27, 0x01}, + {0xEF80, 0x3F, 0x01}, + {0xEF81, 0xD1, 0x01}, + {0xEF82, 0x4A, 0x01}, + {0xEF83, 0x62, 0x01}, + {0xEF84, 0x88, 0x01}, + {0xEF85, 0xA3, 0x01}, + {0xEF86, 0x1D, 0x01}, + {0xEF87, 0xC3, 0x01}, + {0xEF88, 0x20, 0x01}, + {0xEF89, 0x25, 0x01}, + {0xEF8A, 0x24, 0x01}, + {0xEF8B, 0x10, 0x01}, + {0xEF8C, 0x99, 0x01}, + {0xEF8D, 0x48, 0x01}, + {0xEF8E, 0x4B, 0x01}, + {0xEF8F, 0xBE, 0x01}, + {0xEF90, 0x42, 0x01}, + {0xEF91, 0x1A, 0x01}, + {0xEF92, 0xE4, 0x01}, + {0xEF93, 0xC4, 0x01}, + {0xEF94, 0x45, 0x01}, + {0xEF95, 0x26, 0x01}, + {0xEF96, 0x0E, 0x01}, + {0xEF97, 0x01, 0x01}, + {0xEF98, 0x88, 0x01}, + {0xEF99, 0x40, 0x01}, + {0xEF9A, 0x34, 0x01}, + {0xEF9B, 0xB2, 0x01}, + {0xEF9C, 0x94, 0x01}, + {0xEF9D, 0xC9, 0x01}, + {0xEF9E, 0x24, 0x01}, + {0xEF9F, 0x47, 0x01}, + {0xEFA0, 0x2E, 0x01}, + {0xEFA1, 0x33, 0x01}, + {0xEFA2, 0x71, 0x01}, + {0xEFA3, 0x08, 0x01}, + {0xEFA4, 0x40, 0x01}, + {0xEFA5, 0x08, 0x01}, + {0xEFA6, 0xB2, 0x01}, + {0xEFA7, 0x11, 0x01}, + {0xEFA8, 0xA6, 0x01}, + {0xEFA9, 0x50, 0x01}, + {0xEFAA, 0x26, 0x01}, + {0xEFAB, 0x3B, 0x01}, + {0xEFAC, 0x86, 0x01}, + {0xEFAD, 0x51, 0x01}, + {0xEFAE, 0x8A, 0x01}, + {0xEFAF, 0x48, 0x01}, + {0xEFB0, 0x24, 0x01}, + {0xEFB1, 0x82, 0x01}, + {0xEFB2, 0x91, 0x01}, + {0xEFB3, 0x98, 0x01}, + {0xEFB4, 0x8C, 0x01}, + {0xEFB5, 0x25, 0x01}, + {0xEFB6, 0x35, 0x01}, + {0xEFB7, 0xFF, 0x01}, + {0xEFB8, 0x71, 0x01}, + {0xEFB9, 0x8D, 0x01}, + {0xEFBA, 0x5D, 0x01}, + {0xEFBB, 0x9E, 0x01}, + {0xEFBC, 0xE2, 0x01}, + {0xEFBD, 0x13, 0x01}, + {0xEFBE, 0xA2, 0x01}, + {0xEFBF, 0x7C, 0x01}, + {0xEFC0, 0xC5, 0x01}, + {0xEFC1, 0x31, 0x01}, + {0xEFC2, 0xCB, 0x01}, + {0xEFC3, 0x09, 0x01}, + {0xEFC4, 0x52, 0x01}, + {0xEFC5, 0x7A, 0x01}, + {0xEFC6, 0x62, 0x01}, + {0xEFC7, 0xF3, 0x01}, + {0xEFC8, 0x98, 0x01}, + {0xEFC9, 0xC0, 0x01}, + {0xEFCA, 0x24, 0x01}, + {0xEFCB, 0x06, 0x01}, + {0xEFCC, 0x34, 0x01}, + {0xEFCD, 0xCA, 0x01}, + {0xEFCE, 0x29, 0x01}, + {0xEFCF, 0x10, 0x01}, + {0xEFD0, 0xA0, 0x01}, + {0xEFD1, 0x72, 0x01}, + {0xEFD2, 0xE4, 0x01}, + {0xEFD3, 0x1F, 0x01}, + {0xEFD4, 0xEE, 0x01}, + {0xEFD5, 0x38, 0x01}, + {0xEFD6, 0xA7, 0x01}, + {0xEFD7, 0x3A, 0x01}, + {0xEFD8, 0xEA, 0x01}, + {0xEFD9, 0xB1, 0x01}, + {0xEFDA, 0xD0, 0x01}, + {0xEFDB, 0x93, 0x01}, + {0xEFDC, 0x56, 0x01}, + {0xEFDD, 0x95, 0x01}, + {0xEFDE, 0x28, 0x01}, + {0xEFDF, 0x33, 0x01}, + {0xEFE0, 0x25, 0x01}, + {0xEFE1, 0xE9, 0x01}, + {0xEFE2, 0x46, 0x01}, + {0xEFE3, 0x3A, 0x01}, + {0xEFE4, 0x8A, 0x01}, + {0xEFE5, 0x52, 0x01}, + {0xEFE6, 0x9D, 0x01}, + {0xEFE7, 0x24, 0x01}, + {0xEFE8, 0x05, 0x01}, + {0xEFE9, 0x00, 0x01}, + {0xEFEA, 0x00, 0x01}, + {0xEFEB, 0x00, 0x01}, + {0xEFEC, 0x00, 0x01}, + {0xEFED, 0x00, 0x01}, + + /*SHD3 D65+TL84 C01*/ + {0xED00, 0x9191, 0x02}, + {0xEFEE, 0x22, 0x01}, + {0xEFEF, 0xBA, 0x01}, + {0xEFF0, 0xD1, 0x01}, + {0xEFF1, 0x8C, 0x01}, + {0xEFF2, 0x50, 0x01}, + {0xEFF3, 0xA4, 0x01}, + {0xEFF4, 0x22, 0x01}, + {0xEFF5, 0x17, 0x01}, + {0xEFF6, 0xE9, 0x01}, + {0xEFF7, 0x88, 0x01}, + {0xEFF8, 0x47, 0x01}, + {0xEFF9, 0x29, 0x01}, + {0xEFFA, 0xBA, 0x01}, + {0xEFFB, 0x50, 0x01}, + {0xEFFC, 0x80, 0x01}, + {0xEFFD, 0xD0, 0x01}, + {0xEFFE, 0x73, 0x01}, + {0xEFFF, 0x1D, 0x01}, + {0xF000, 0xE9, 0x01}, + {0xF001, 0x6C, 0x01}, + {0xF002, 0x87, 0x01}, + {0xF003, 0x3D, 0x01}, + {0xF004, 0x05, 0x01}, + {0xF005, 0xE2, 0x01}, + {0xF006, 0xD0, 0x01}, + {0xF007, 0x7D, 0x01}, + {0xF008, 0xA2, 0x01}, + {0xF009, 0xF3, 0x01}, + {0xF00A, 0x9A, 0x01}, + {0xF00B, 0xC9, 0x01}, + {0xF00C, 0x2C, 0x01}, + {0xF00D, 0xA6, 0x01}, + {0xF00E, 0x32, 0x01}, + {0xF00F, 0xAF, 0x01}, + {0xF010, 0xB1, 0x01}, + {0xF011, 0x0E, 0x01}, + {0xF012, 0x82, 0x01}, + {0xF013, 0xAE, 0x01}, + {0xF014, 0x33, 0x01}, + {0xF015, 0x1A, 0x01}, + {0xF016, 0xB9, 0x01}, + {0xF017, 0x48, 0x01}, + {0xF018, 0x25, 0x01}, + {0xF019, 0x29, 0x01}, + {0xF01A, 0x54, 0x01}, + {0xF01B, 0xA9, 0x01}, + {0xF01C, 0x0B, 0x01}, + {0xF01D, 0x6B, 0x01}, + {0xF01E, 0xD0, 0x01}, + {0xF01F, 0xE3, 0x01}, + {0xF020, 0x9B, 0x01}, + {0xF021, 0xBE, 0x01}, + {0xF022, 0x18, 0x01}, + {0xF023, 0x85, 0x01}, + {0xF024, 0x24, 0x01}, + {0xF025, 0x19, 0x01}, + {0xF026, 0x29, 0x01}, + {0xF027, 0xC9, 0x01}, + {0xF028, 0x52, 0x01}, + {0xF029, 0x08, 0x01}, + {0xF02A, 0x93, 0x01}, + {0xF02B, 0x1C, 0x01}, + {0xF02C, 0xD8, 0x01}, + {0xF02D, 0xA8, 0x01}, + {0xF02E, 0x05, 0x01}, + {0xF02F, 0x26, 0x01}, + {0xF030, 0x0B, 0x01}, + {0xF031, 0x01, 0x01}, + {0xF032, 0x88, 0x01}, + {0xF033, 0x43, 0x01}, + {0xF034, 0x6C, 0x01}, + {0xF035, 0xE2, 0x01}, + {0xF036, 0x96, 0x01}, + {0xF037, 0xDB, 0x01}, + {0xF038, 0xC4, 0x01}, + {0xF039, 0x66, 0x01}, + {0xF03A, 0x2D, 0x01}, + {0xF03B, 0x31, 0x01}, + {0xF03C, 0x59, 0x01}, + {0xF03D, 0x48, 0x01}, + {0xF03E, 0x40, 0x01}, + {0xF03F, 0x20, 0x01}, + {0xF040, 0x62, 0x01}, + {0xF041, 0x13, 0x01}, + {0xF042, 0xB8, 0x01}, + {0xF043, 0xF0, 0x01}, + {0xF044, 0x86, 0x01}, + {0xF045, 0x38, 0x01}, + {0xF046, 0x82, 0x01}, + {0xF047, 0x49, 0x01}, + {0xF048, 0x0A, 0x01}, + {0xF049, 0x49, 0x01}, + {0xF04A, 0x34, 0x01}, + {0xF04B, 0x92, 0x01}, + {0xF04C, 0x12, 0x01}, + {0xF04D, 0xA7, 0x01}, + {0xF04E, 0x1C, 0x01}, + {0xF04F, 0xE6, 0x01}, + {0xF050, 0x39, 0x01}, + {0xF051, 0xE2, 0x01}, + {0xF052, 0x41, 0x01}, + {0xF053, 0x8D, 0x01}, + {0xF054, 0x5D, 0x01}, + {0xF055, 0xAA, 0x01}, + {0xF056, 0xC2, 0x01}, + {0xF057, 0x94, 0x01}, + {0xF058, 0xAC, 0x01}, + {0xF059, 0xF4, 0x01}, + {0xF05A, 0x65, 0x01}, + {0xF05B, 0x36, 0x01}, + {0xF05C, 0xF1, 0x01}, + {0xF05D, 0x31, 0x01}, + {0xF05E, 0x90, 0x01}, + {0xF05F, 0x76, 0x01}, + {0xF060, 0x62, 0x01}, + {0xF061, 0x83, 0x01}, + {0xF062, 0x19, 0x01}, + {0xF063, 0xC7, 0x01}, + {0xF064, 0x6C, 0x01}, + {0xF065, 0x26, 0x01}, + {0xF066, 0x37, 0x01}, + {0xF067, 0xE2, 0x01}, + {0xF068, 0x89, 0x01}, + {0xF069, 0xD0, 0x01}, + {0xF06A, 0x87, 0x01}, + {0xF06B, 0x0C, 0x01}, + {0xF06C, 0xC4, 0x01}, + {0xF06D, 0x1E, 0x01}, + {0xF06E, 0xEE, 0x01}, + {0xF06F, 0x58, 0x01}, + {0xF070, 0x07, 0x01}, + {0xF071, 0x3C, 0x01}, + {0xF072, 0xF4, 0x01}, + {0xF073, 0x81, 0x01}, + {0xF074, 0x90, 0x01}, + {0xF075, 0x8B, 0x01}, + {0xF076, 0x3C, 0x01}, + {0xF077, 0xA4, 0x01}, + {0xF078, 0xA2, 0x01}, + {0xF079, 0x10, 0x01}, + {0xF07A, 0x69, 0x01}, + {0xF07B, 0x48, 0x01}, + {0xF07C, 0x43, 0x01}, + {0xF07D, 0x20, 0x01}, + {0xF07E, 0x62, 0x01}, + {0xF07F, 0x51, 0x01}, + {0xF080, 0x8C, 0x01}, + {0xF081, 0x50, 0x01}, + {0xF082, 0x04, 0x01}, + {0xF083, 0x00, 0x01}, + {0xF084, 0x00, 0x01}, + {0xF085, 0x00, 0x01}, + {0xF086, 0x00, 0x01}, + {0xF087, 0x00, 0x01}, + {0xF088, 0xBB, 0x01}, + {0xF089, 0x41, 0x01}, + {0xF08A, 0x0E, 0x01}, + {0xF08B, 0x6F, 0x01}, + {0xF08C, 0x68, 0x01}, + {0xF08D, 0x23, 0x01}, + {0xF08E, 0x9B, 0x01}, + {0xF08F, 0xD9, 0x01}, + {0xF090, 0xE8, 0x01}, + {0xF091, 0x06, 0x01}, + {0xF092, 0x38, 0x01}, + {0xF093, 0xB9, 0x01}, + {0xF094, 0xB9, 0x01}, + {0xF095, 0x4D, 0x01}, + {0xF096, 0x69, 0x01}, + {0xF097, 0x24, 0x01}, + {0xF098, 0x83, 0x01}, + {0xF099, 0x98, 0x01}, + {0xF09A, 0xC1, 0x01}, + {0xF09B, 0x1C, 0x01}, + {0xF09C, 0x06, 0x01}, + {0xF09D, 0x32, 0x01}, + {0xF09E, 0xA4, 0x01}, + {0xF09F, 0xA9, 0x01}, + {0xF0A0, 0x4D, 0x01}, + {0xF0A1, 0x67, 0x01}, + {0xF0A2, 0x0C, 0x01}, + {0xF0A3, 0x13, 0x01}, + {0xF0A4, 0x97, 0x01}, + {0xF0A5, 0xB0, 0x01}, + {0xF0A6, 0x6C, 0x01}, + {0xF0A7, 0x25, 0x01}, + {0xF0A8, 0x2C, 0x01}, + {0xF0A9, 0x70, 0x01}, + {0xF0AA, 0x39, 0x01}, + {0xF0AB, 0xCC, 0x01}, + {0xF0AC, 0x68, 0x01}, + {0xF0AD, 0x10, 0x01}, + {0xF0AE, 0xA3, 0x01}, + {0xF0AF, 0x96, 0x01}, + {0xF0B0, 0xA6, 0x01}, + {0xF0B1, 0xE4, 0x01}, + {0xF0B2, 0x44, 0x01}, + {0xF0B3, 0x26, 0x01}, + {0xF0B4, 0x3A, 0x01}, + {0xF0B5, 0x79, 0x01}, + {0xF0B6, 0x4A, 0x01}, + {0xF0B7, 0x5B, 0x01}, + {0xF0B8, 0x18, 0x01}, + {0xF0B9, 0x93, 0x01}, + {0xF0BA, 0x17, 0x01}, + {0xF0BB, 0xA9, 0x01}, + {0xF0BC, 0xBC, 0x01}, + {0xF0BD, 0x24, 0x01}, + {0xF0BE, 0x23, 0x01}, + {0xF0BF, 0x12, 0x01}, + {0xF0C0, 0xE1, 0x01}, + {0xF0C1, 0xC8, 0x01}, + {0xF0C2, 0x4C, 0x01}, + {0xF0C3, 0xAA, 0x01}, + {0xF0C4, 0xA2, 0x01}, + {0xF0C5, 0x17, 0x01}, + {0xF0C6, 0xB6, 0x01}, + {0xF0C7, 0x10, 0x01}, + {0xF0C8, 0x05, 0x01}, + {0xF0C9, 0x24, 0x01}, + {0xF0CA, 0x06, 0x01}, + {0xF0CB, 0x09, 0x01}, + {0xF0CC, 0xC8, 0x01}, + {0xF0CD, 0x42, 0x01}, + {0xF0CE, 0x4A, 0x01}, + {0xF0CF, 0x82, 0x01}, + {0xF0D0, 0x94, 0x01}, + {0xF0D1, 0xB8, 0x01}, + {0xF0D2, 0xC0, 0x01}, + {0xF0D3, 0xE5, 0x01}, + {0xF0D4, 0x28, 0x01}, + {0xF0D5, 0x21, 0x01}, + {0xF0D6, 0x39, 0x01}, + {0xF0D7, 0x08, 0x01}, + {0xF0D8, 0x40, 0x01}, + {0xF0D9, 0x16, 0x01}, + {0xF0DA, 0x62, 0x01}, + {0xF0DB, 0x92, 0x01}, + {0xF0DC, 0xA4, 0x01}, + {0xF0DD, 0xC4, 0x01}, + {0xF0DE, 0xE5, 0x01}, + {0xF0DF, 0x2F, 0x01}, + {0xF0E0, 0x58, 0x01}, + {0xF0E1, 0x99, 0x01}, + {0xF0E2, 0x49, 0x01}, + {0xF0E3, 0x46, 0x01}, + {0xF0E4, 0x22, 0x01}, + {0xF0E5, 0xC2, 0x01}, + {0xF0E6, 0x91, 0x01}, + {0xF0E7, 0x9A, 0x01}, + {0xF0E8, 0x58, 0x01}, + {0xF0E9, 0xA5, 0x01}, + {0xF0EA, 0x2F, 0x01}, + {0xF0EB, 0x95, 0x01}, + {0xF0EC, 0x99, 0x01}, + {0xF0ED, 0x4B, 0x01}, + {0xF0EE, 0x54, 0x01}, + {0xF0EF, 0x74, 0x01}, + {0xF0F0, 0x32, 0x01}, + {0xF0F1, 0x93, 0x01}, + {0xF0F2, 0x9D, 0x01}, + {0xF0F3, 0x38, 0x01}, + {0xF0F4, 0xC5, 0x01}, + {0xF0F5, 0x2D, 0x01}, + {0xF0F6, 0x90, 0x01}, + {0xF0F7, 0x59, 0x01}, + {0xF0F8, 0x0D, 0x01}, + {0xF0F9, 0x64, 0x01}, + {0xF0FA, 0xEE, 0x01}, + {0xF0FB, 0x62, 0x01}, + {0xF0FC, 0x96, 0x01}, + {0xF0FD, 0xAE, 0x01}, + {0xF0FE, 0x84, 0x01}, + {0xF0FF, 0x25, 0x01}, + {0xF100, 0x2E, 0x01}, + {0xF101, 0x8A, 0x01}, + {0xF102, 0x29, 0x01}, + {0xF103, 0x8D, 0x01}, + {0xF104, 0x6F, 0x01}, + {0xF105, 0x60, 0x01}, + {0xF106, 0xD3, 0x01}, + {0xF107, 0x19, 0x01}, + {0xF108, 0xC7, 0x01}, + {0xF109, 0x18, 0x01}, + {0xF10A, 0x26, 0x01}, + {0xF10B, 0x31, 0x01}, + {0xF10C, 0x97, 0x01}, + {0xF10D, 0x41, 0x01}, + {0xF10E, 0x8D, 0x01}, + {0xF10F, 0x6D, 0x01}, + {0xF110, 0x84, 0x01}, + {0xF111, 0xE3, 0x01}, + {0xF112, 0x1C, 0x01}, + {0xF113, 0xE3, 0x01}, + {0xF114, 0xDC, 0x01}, + {0xF115, 0x26, 0x01}, + {0xF116, 0x36, 0x01}, + {0xF117, 0xB6, 0x01}, + {0xF118, 0xF1, 0x01}, + {0xF119, 0x4D, 0x01}, + {0xF11A, 0x70, 0x01}, + {0xF11B, 0x68, 0x01}, + {0xF11C, 0x03, 0x01}, + {0xF11D, 0x00, 0x01}, + {0xF11E, 0x00, 0x01}, + {0xF11F, 0x00, 0x01}, + {0xF120, 0x00, 0x01}, + {0xF121, 0x00, 0x01}, + + + /*SHD TH*/ + {0x6C32, 0x16A8, 0x02}, /* SHD_INP_TH_HB_H_R2*/ + {0x6C34, 0x1612, 0x02}, /* SHD_INP_TH_HB_L_R2*/ + {0x6C36, 0x10CC, 0x02}, /* SHD_INP_TH_LB_H_R2*/ + {0x6C38, 0x1004, 0x02}, /* SHD_INP_TH_LB_L_R2*/ + {0x6C3C, 0x10CC, 0x02}, /* SHD_INP_TH_HB_H_RB*/ + {0x6C3E, 0x1004, 0x02}, /* SHD_INP_TH_HB_L_RB*/ + {0x6C40, 0x0000, 0x02}, /* SHD_INP_TH_LB_H_RB*/ + {0x6C42, 0x0000, 0x02}, /* SHD_INP_TH_LB_L_RB*/ + + /*PreWB_offset (for SHD2)*/ + {0x6828, 0x0013, 0x02}, /* SHD_PRER_OFFSET_R2 :*/ + /*PreWB_offset (for SHD3)*/ + {0x682C, 0x000C, 0x02}, /* SHD_PRER_OFFSET_RB :*/ + {0x6830, 0xFFFF, 0x02}, /* SHD_PREB_OFFSET_RB :*/ + + /* CXC/SHD EN*/ + {0x01BC, 0x57, 0x01}, /* CXC ON SHD ON INP ON GAIN OFF*/ + + /*#36*/ + {0x6804, 0x1122, 0x02}, /* NORMR*/ + {0x6806, 0x116B, 0x02}, /* NORMB*/ + {0x6808, 0x0150, 0x02}, /* AWBPRER*/ + {0x680A, 0x0245, 0x02}, /* AWBPREB*/ + {0x6810, 0x1001, 0x02}, /* AWB_PRE_ADJ_RG*/ + {0x6812, 0x0FC9, 0x02}, /* AWB_PRE_ADJ_BG*/ + {0x6814, 0x0A73, 0x02}, /* AWB_C14_RG*/ + {0x6816, 0x17EA, 0x02}, /* AWB_C14_BG*/ +}; + +struct isx012_short_t ISX012_Pll_Setting_4[] = { + {0x0007, 0x00, 0x01}, /* PLL_CKSEL : PLL 432MHz */ + {0x0008, 0x00, 0x01}, /* SRCCK_DIV : 1/5 frequency*/ + + {0x0004, 0x03, 0x01}, /* I2C_ADR_SEL 2: 0x3C MIPI */ + /*selected, 3: 0x3D MIPI selected*/ + {0x5008, 0x00, 0x01}, /* ENDIAN_SEL : 0:Little Endian*/ + {0x6DA8, 0x01, 0x01}, /* SHD_CoEF (OTP shading ON flag)*/ + + {0x00C4, 0x11, 0x01}, /* VIF_CLKCONFIG1 : VIFSEL and VIFDIV*/ + /*setting value with full frame pixel setting for other then JPG*/ + {0x00C5, 0x11, 0x01}, /* VIF_CLKCONFIG2 : VIFSEL and VIFDIV setting*/ + /* value with 1/2 sub-sampling setting for other then JPG*/ + {0x00C6, 0x11, 0x01}, /* VIF_CLKCONFIG3 : VIFSEL and VIFDIV */ + /*setting value with 1/4 sub-sampling setting for other then JPG*/ + {0x00C7, 0x11, 0x01}, /* VIF_CLKCONFIG4 : VIFSEL and VIFDIV setting*/ + /* value with 1/8 sub-sampling setting for other then JPG*/ + {0x00C8, 0x11, 0x01}, /* VIF_CLKCONFIG5 : VIFSEL and VIFDIV setting*/ + /*value with full frame pixel setting for JPG mode*/ + {0x00C9, 0x11, 0x01},/* VIF_CLKCONFIG6 : VIFSEL and VIFDIV setting */ + /* value with 1/2 sub-sampling setting for JPG mode*/ + {0x00CA, 0x11, 0x01},/* VIF_CLKCONFIG7 : VIFSEL and VIFDIV setting */ + /*value with 1/4 sub-sampling setting for JPG mode*/ + {0x00CC, 0x11, 0x01},/* VIF_CLKCONFIG9 : VIFSEL and VIFDIV setting */ + /*value with full frame pixel setting for JPG and interleave mode*/ + {0x00CD, 0x11, 0x01},/* VIF_CLKCONFIG10 : VIFSEL and VIFDIV setting*/ + /* value with 1/2 sub-sampling setting for JPG and interleave mode*/ + {0x6A12, 0x11, 0x01},/* VIF_CLKCONFIG13 for RAW8 : VIFSEL and VIFDIV*/ + /* setting value with full frame pixel setting for RAW mode*/ + {0x6A13, 0x11, 0x01},/* VIF_CLKCONFIG14 for RAW8 : VIFSEL and VIFDIV*/ + /* setting value with 1/2 sub-sampling setting for RAW mode*/ + {0x6A14, 0x11, 0x01},/* VIF_CLKCONFIG15 for RAW8 : VIFSEL and VIFDIV*/ + /* setting value with 1/4 sub-sampling setting for RAW mode*/ + {0x6A15, 0x11, 0x01},/* VIF_CLKCONFIG16 for RAW8 : VIFSEL and VIFDIV*/ + /* setting value with 1/8 sub-sampling setting for RAW mode*/ + {0x018C, 0x0026, 0x02}, /* VADJ_SENS_1_1 : VMAX adjustment value for */ + /*full frame pixel*/ + {0x018E, 0x0012, 0x02}, /* VADJ_SENS_1_2 : VMAX adjustment value for */ + /*1/2 sub-sampling*/ + {0x0190, 0x0000, 0x02}, /* VADJ_SENS_1_4 : VMAX adjustment value for */ + /* 1/4 sub-sampling*/ + {0x0192, 0x0000, 0x02}, /* VADJ_SENS_1_8 : VMAX adjustment value for */ + /*1/8 sub-sampling*/ + {0x0194, 0x0027, 0x02}, /* VADJ_SENS_HD_1_1 : VMAX adjustment value */ + /*for HD full frame pixel*/ + {0x0196, 0x0015, 0x02}, /* VADJ_SENS_HD_1_2 : VMAX adjustment value */ + /*for HD 1/2 sub-sampling*/ + {0x6A16, 0x0440, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_1 : Detection*/ + /* window vertical size with all 32 windows for FLC full frame pixel*/ + {0x6A18, 0x03C0, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_2 : Detection */ + /*window vertical size with all 32 windows for FLC 1/2 sub-sampling*/ + {0x6A1A, 0x01E0, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_4 : Detection*/ + /* window vertical size with all 32 windows for FLC 1/4 sub-sampling*/ + {0x6A1C, 0x00E0, 0x02}, /* FLC_OPD_HEIGHT_NORMAL_1_8 : Detection */ + /*window vertical size with all 32 windows for FLC 1/8 sub-sampling*/ + {0x6A1E, 0x0420, 0x02}, /* FLC_OPD_HEIGHT_HD_1_1 : Detection window */ + /*vertical size with all 32 windows for FLC HD full frame pixel*/ + {0x6A20, 0x02C0, 0x02}, /* FLC_OPD_HEIGHT_HD_1_2 : Detection window */ + /*vertical size with all 32 windows for FLC HD 1/2 sub-sampling*/ + {0x0016, 0x0010, 0x02}, /* GPIO_FUNCSEL : GPIO setting*/ + {0x5C01, 0x00, 0x01}, /* RGLANESEL : */ + {0x5C04, 0x04, 0x01}, /* RGTLPX : */ + {0x5C05, 0x03, 0x01}, /* RGTCLKPREPARE : */ + {0x5C06, 0x0E, 0x01}, /* RGTCLKZERO : */ + {0x5C07, 0x02, 0x01}, /* RGTCLKPRE: */ + {0x5C08, 0x0B, 0x01}, /* RGTCLKPOST : */ + {0x5C09, 0x05, 0x01}, /* RGTCLKTRAIL : */ + {0x5C0A, 0x07, 0x01}, /* RGTHSEXIT : */ + {0x5C0B, 0x03, 0x01}, /* RGTHSPREPARE : */ + {0x5C0C, 0x07, 0x01},/* RGTHSZERO: */ + {0x5C0D, 0x05, 0x01},/*RGTHSTRAIL: */ + + {0x6A9E, 0x15C0, 0x02},/* HMAX_1_1(0x6A9E)=0x15C0 */ + + /* init Preview setting */ + {0x0089, 0x00, 0x01},/* OUTFMT_MONI */ + {0x0090, 0x0280, 0x02},/* HSIZE_MONI : 640 */ + {0x0096, 0x01E0, 0x02},/* VSIZE_MONI : 480 */ + {0x0083, 0x01, 0x01},/* SENSMODE_MONI */ + {0x0086, 0x02, 0x01},/* FPSTYPE_MONI */ + {0x0081, 0x00, 0x01},/* MODESEL */ + {0x0082, 0x01, 0x01},/* MONI_REFRESH */ + + /* jpeg setting */ + /* Apex40 is not Jpeg Capture*/ + + /* Fast mode setting*/ + {0x500A, 0x00, 0x01}, /* FAST_MODECHG_EN*/ + {0x500B, 0x01, 0x01}, /* FAST_SHT_MODE_SEL*/ + {0x500C, 0x00FA, 0x02}, /* FAST_SHT_LIMIT_COUNT*/ + + /* Select sensor inversion link control*/ + {0x501A, 0x01, 0x01}, /* SENS_REVERSE_CTRL*/ + + /* additional code*/ + {0xF200, 0xB9B9, 0x02}, + {0xF202, 0x4E12, 0x02}, + {0xF204, 0x6055, 0x02}, + {0xF206, 0x008B, 0x02}, + {0xF208, 0xF177, 0x02}, + {0xF20A, 0xFA70, 0x02}, + {0xF20C, 0x0000, 0x02}, + {0xF20E, 0x0000, 0x02}, + {0xF210, 0x0000, 0x02}, + {0xF212, 0x0000, 0x02}, + {0xF214, 0x0000, 0x02}, + {0xF216, 0x0000, 0x02}, + {0xF218, 0x0000, 0x02}, + {0xF21A, 0x0000, 0x02}, + {0xF21C, 0x0000, 0x02}, + {0xF21E, 0x0000, 0x02}, + {0xF220, 0x0000, 0x02}, + {0xF222, 0x0000, 0x02}, + {0xF224, 0x0000, 0x02}, + {0xF226, 0x0000, 0x02}, + {0xF228, 0x0000, 0x02}, + {0xF22A, 0x0000, 0x02}, + {0xF22C, 0x0000, 0x02}, + {0xF22E, 0x0000, 0x02}, + {0xF230, 0x0000, 0x02}, + {0xF232, 0x0000, 0x02}, + {0xF234, 0x0000, 0x02}, + {0xF236, 0x0000, 0x02}, + {0xF238, 0x0000, 0x02}, + {0xF23A, 0x0000, 0x02}, + {0xF23C, 0x0000, 0x02}, + {0xF23E, 0x0000, 0x02}, + {0xF240, 0x0000, 0x02}, + {0xF242, 0x0000, 0x02}, + {0xF244, 0xB47E, 0x02}, + {0xF246, 0x4808, 0x02}, + {0xF248, 0x7800, 0x02}, + {0xF24A, 0x07C0, 0x02}, + {0xF24C, 0x0FC0, 0x02}, + {0xF24E, 0xF687, 0x02}, + {0xF250, 0xF8ED, 0x02}, + {0xF252, 0xF68E, 0x02}, + {0xF254, 0xFE2B, 0x02}, + {0xF256, 0xF688, 0x02}, + {0xF258, 0xFF6B, 0x02}, + {0xF25A, 0xF693, 0x02}, + {0xF25C, 0xFB6B, 0x02}, + {0xF25E, 0xF687, 0x02}, + {0xF260, 0xF947, 0x02}, + {0xF262, 0xBC7E, 0x02}, + {0xF264, 0xF688, 0x02}, + {0xF266, 0xFD8F, 0x02}, + {0xF268, 0x239C, 0x02}, + {0xF26A, 0x0018, 0x02}, + + {0x0006, 0x16, 0x01}, /* INCK_SET : 24MHz*/ +}; +#endif diff --git a/drivers/media/video/msm_zsl/isx012_regs_old.h b/drivers/media/video/msm_zsl/isx012_regs_old.h new file mode 100644 index 00000000000..0ef15a8ad79 --- /dev/null +++ b/drivers/media/video/msm_zsl/isx012_regs_old.h @@ -0,0 +1,4630 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __ISX012_REGS_H__ +#define __ISX012_REGS_H__ + + + +typedef struct isx012_reg { + unsigned short subaddr; + unsigned int value; + unsigned int len; +}isx012_short_t; + +isx012_short_t isx012_init_reg[] = +{ +///////////////////////////////////// +//AF driver setting// AF driver// +///////////////////////////////////// +{0x66C2,0x0C,0x01},//AF_INTERNAL_LENSDRV_ADRS +{0x66C3,0x02,0x01},//AF_INTERNAL_LENSDRV_SIZE +{0x66C5,0x14,0x01},//AF_INTERNAL_LENSDRV_SHIFT +{0x66C8,0x000F0000,0x04},//AF_INTERNAL_LENSDRV_FIXEDPTN +{0x000B,0x01,0x01},//AF_EXT : AF driver start + + +// AE window add V02 +{0x6000,0x06,0x01}, // CENTER_FIXWEIGHT_00_TYPE1 : +{0x6001,0x08,0x01}, // CENTER_FIXWEIGHT_01_TYPE1 : +{0x6002,0x0A,0x01}, // CENTER_FIXWEIGHT_02_TYPE1 : +{0x6003,0x0B,0x01}, // CENTER_FIXWEIGHT_03_TYPE1 : +{0x6004,0x0C,0x01}, // CENTER_FIXWEIGHT_04_TYPE1 : +{0x6005,0x0B,0x01}, // CENTER_FIXWEIGHT_05_TYPE1 : +{0x6006,0x0A,0x01}, // CENTER_FIXWEIGHT_06_TYPE1 : +{0x6007,0x08,0x01}, // CENTER_FIXWEIGHT_07_TYPE1 : +{0x6008,0x06,0x01}, // CENTER_FIXWEIGHT_08_TYPE1 : +{0x6009,0x08,0x01}, // CENTER_FIXWEIGHT_09_TYPE1 : +{0x600A,0x0C,0x01}, // CENTER_FIXWEIGHT_10_TYPE1 : +{0x600B,0x12,0x01}, // CENTER_FIXWEIGHT_11_TYPE1 : +{0x600C,0x16,0x01}, // CENTER_FIXWEIGHT_12_TYPE1 : +{0x600D,0x18,0x01}, // CENTER_FIXWEIGHT_13_TYPE1 : +{0x600E,0x16,0x01}, // CENTER_FIXWEIGHT_14_TYPE1 : +{0x600F,0x12,0x01}, // CENTER_FIXWEIGHT_15_TYPE1 : +{0x6010,0x0C,0x01}, // CENTER_FIXWEIGHT_16_TYPE1 : +{0x6011,0x08,0x01}, // CENTER_FIXWEIGHT_17_TYPE1 : +{0x6012,0x0C,0x01}, // CENTER_FIXWEIGHT_18_TYPE1 : +{0x6013,0x14,0x01}, // CENTER_FIXWEIGHT_19_TYPE1 : +{0x6014,0x32,0x01}, // CENTER_FIXWEIGHT_20_TYPE1 : +{0x6015,0x34,0x01}, // CENTER_FIXWEIGHT_21_TYPE1 : +{0x6016,0x41,0x01}, // CENTER_FIXWEIGHT_22_TYPE1 : +{0x6017,0x34,0x01}, // CENTER_FIXWEIGHT_23_TYPE1 : +{0x6018,0x32,0x01}, // CENTER_FIXWEIGHT_24_TYPE1 : +{0x6019,0x15,0x01}, // CENTER_FIXWEIGHT_25_TYPE1 : +{0x601A,0x0C,0x01}, // CENTER_FIXWEIGHT_26_TYPE1 : +{0x601B,0x10,0x01}, // CENTER_FIXWEIGHT_27_TYPE1 : +{0x601C,0x1C,0x01}, // CENTER_FIXWEIGHT_28_TYPE1 : +{0x601D,0x32,0x01}, // CENTER_FIXWEIGHT_29_TYPE1 : +{0x601E,0x55,0x01}, // CENTER_FIXWEIGHT_30_TYPE1 : +{0x601F,0x64,0x01}, // CENTER_FIXWEIGHT_31_TYPE1 : +{0x6020,0x55,0x01}, // CENTER_FIXWEIGHT_32_TYPE1 : +{0x6021,0x32,0x01}, // CENTER_FIXWEIGHT_33_TYPE1 : +{0x6022,0x1C,0x01}, // CENTER_FIXWEIGHT_34_TYPE1 : +{0x6023,0x10,0x01}, // CENTER_FIXWEIGHT_35_TYPE1 : +{0x6024,0x0C,0x01}, // CENTER_FIXWEIGHT_36_TYPE1 : +{0x6025,0x14,0x01}, // CENTER_FIXWEIGHT_37_TYPE1 : +{0x6026,0x32,0x01}, // CENTER_FIXWEIGHT_38_TYPE1 : +{0x6027,0x3C,0x01}, // CENTER_FIXWEIGHT_39_TYPE1 : +{0x6028,0x4B,0x01}, // CENTER_FIXWEIGHT_40_TYPE1 : +{0x6029,0x3C,0x01}, // CENTER_FIXWEIGHT_41_TYPE1 : +{0x602A,0x32,0x01}, // CENTER_FIXWEIGHT_42_TYPE1 : +{0x602B,0x14,0x01}, // CENTER_FIXWEIGHT_43_TYPE1 : +{0x602C,0x0C,0x01}, // CENTER_FIXWEIGHT_44_TYPE1 : +{0x602D,0x08,0x01}, // CENTER_FIXWEIGHT_45_TYPE1 : +{0x602E,0x0C,0x01}, // CENTER_FIXWEIGHT_46_TYPE1 : +{0x602F,0x14,0x01}, // CENTER_FIXWEIGHT_47_TYPE1 : +{0x6030,0x1A,0x01}, // CENTER_FIXWEIGHT_48_TYPE1 : +{0x6031,0x20,0x01}, // CENTER_FIXWEIGHT_49_TYPE1 : +{0x6032,0x1A,0x01}, // CENTER_FIXWEIGHT_50_TYPE1 : +{0x6033,0x14,0x01}, // CENTER_FIXWEIGHT_51_TYPE1 : +{0x6034,0x0C,0x01}, // CENTER_FIXWEIGHT_52_TYPE1 : +{0x6035,0x08,0x01}, // CENTER_FIXWEIGHT_53_TYPE1 : +{0x6036,0x06,0x01}, // CENTER_FIXWEIGHT_54_TYPE1 : +{0x6037,0x08,0x01}, // CENTER_FIXWEIGHT_55_TYPE1 : +{0x6038,0x0A,0x01}, // CENTER_FIXWEIGHT_56_TYPE1 : +{0x6039,0x0B,0x01}, // CENTER_FIXWEIGHT_57_TYPE1 : +{0x603A,0x0C,0x01}, // CENTER_FIXWEIGHT_58_TYPE1 : +{0x603B,0x0B,0x01}, // CENTER_FIXWEIGHT_59_TYPE1 : +{0x603C,0x0A,0x01}, // CENTER_FIXWEIGHT_60_TYPE1 : +{0x603D,0x08,0x01}, // CENTER_FIXWEIGHT_61_TYPE1 : +{0x603E,0x06,0x01}, // CENTER_FIXWEIGHT_62_TYPE1 : + + +//AF filter +{0x66EE,0x01F4,0x02}, // AF_LVD_HBPF_VAL1_1STOPD +{0x66F0,0x2710,0x02}, // AF_LVD_HBPF_VAL2_1ST +{0x66F2,0x004C,0x02}, // AF_LVD_HBPF_RATE1_1ST + +{0x6D14,0x0001,0x02}, // HPF_HBPF_CORSL_Y1 : +{0x6D16,0x0001,0x02}, // HPF_HBPF_CORSL_Y2 : +{0x6D18,0x0002,0x02}, // HPF_HBPF_CORSL_Y3 : +{0x6D1A,0x0005,0x02}, // HPF_HBPF_CORSL_Y4 : + +{0x6D20,0x0004,0x02}, // HPF_HBPF_CORL_Y1 : +{0x6D22,0x0004,0x02}, // HPF_HBPF_CORL_Y2 : +{0x6D24,0x000F,0x02}, // HPF_HBPF_CORL_Y3 : +{0x6D26,0x001E,0x02}, // HPF_HBPF_CORL_Y4 : + +{0x6D2C,0x000E,0x02}, // HPF_HBPF_CORH_Y1 : +{0x6D2E,0x000F,0x02}, // HPF_HBPF_CORH_Y2 : +{0x6D30,0x0022,0x02}, // HPF_HBPF_CORH_Y3 : +{0x6D32,0x004D,0x02}, // HPF_HBPF_CORH_Y4 : + +{0x6D44,0x0001,0x02}, // HPF_LBPF_CORSL_Y1 : +{0x6D46,0x0001,0x02}, // HPF_LBPF_CORSL_Y2 : +{0x6D48,0x0002,0x02}, // HPF_LBPF_CORSL_Y3 : +{0x6D4A,0x0004,0x02}, // HPF_LBPF_CORSL_Y4 : + +{0x6D50,0x03FF,0x02}, // HPF_LBPF_CORL_Y1 : +{0x6D52,0x03FF,0x02}, // HPF_LBPF_CORL_Y2 : +{0x6D54,0x03FF,0x02}, // HPF_LBPF_CORL_Y3 : +{0x6D56,0x03FF,0x02}, // HPF_LBPF_CORL_Y4 : + +{0x6D5C,0x03FF,0x02}, // HPF_LBPF_CORH_Y1 : +{0x6D5E,0x03FF,0x02}, // HPF_LBPF_CORH_Y2 : +{0x6D60,0x03FF,0x02}, // HPF_LBPF_CORH_Y3 : +{0x6D62,0x03FF,0x02}, // HPF_LBPF_CORH_Y4 : + +{0x6D74,0x0001,0x02}, // HPF_VHBPF_CORSL_Y1 : +{0x6D76,0x0001,0x02}, // HPF_VHBPF_CORSL_Y2 : +{0x6D78,0x0002,0x02}, // HPF_VHBPF_CORSL_Y3 : +{0x6D7A,0x0005,0x02}, // HPF_VHBPF_CORSL_Y4 : + +{0x6D80,0x0004,0x02}, // HPF_VHBPF_CORL_Y1 : +{0x6D82,0x0005,0x02}, // HPF_VHBPF_CORL_Y2 : +{0x6D84,0x000C,0x02}, // HPF_VHBPF_CORL_Y3 : +{0x6D86,0x001C,0x02}, // HPF_VHBPF_CORL_Y4 : + +{0x6D8C,0x000D,0x02}, // HPF_VHBPF_CORH_Y1 : +{0x6D8E,0x0010,0x02}, // HPF_VHBPF_CORH_Y2 : +{0x6D90,0x0026,0x02}, // HPF_VHBPF_CORH_Y3 : +{0x6D92,0x004D,0x02}, // HPF_VHBPF_CORH_Y4 : + +// CAF ߰κ +{0x6622,0x0004,0x02}, // AF_CAF_PARAM_WOBBLE_STEP : +{0x6624,0x0008,0x02}, // AF_CAF_CLIMB_STEP : +{0x6687,0x01,0x01}, // AF_CAF_CLIMB_PEAK_BACK_STEP_ENABLE : +{0x6696,0x32,0x01}, // AF_CAF_WOBBLE_START_INTERVAL_COUNTER : +{0x6698,0x00,0x01}, // AF_CAF_WOBBLE_FILTER_ENABLE : +{0x66A4,0x06,0x01}, // AF_CAF_OPD_FLAT_MOVE_ENABLE : +{0x66B0,0x0002,0x02}, // AF_CAF_WAIT_FOR_AF_STABLE_TH : +//S, 672E, 0046, 16, // CAF_LVD_CLMP_HBPF_RATE1 : +//S, 6730, 0046, 16, // CAF_LVD_CLMP_HBPF_RATE2 : +//S, 6764, 0004, 8, // AF_SENDNUM_ALL4 + +{0x5003,0x04,0x01}, // Z1_HOLD = 1 + +//߰úκ SAFκ +{0x028E,0x00,0x01}, // AF_SN1_2 : +{0x028F,0x00,0x01}, // AF_SN3_4 : +{0x0290,0x00,0x01}, // AF_SN5_6 : +{0x0291,0x00,0x01}, // AF_SN7_8 : +{0x0292,0x00,0x01}, // AF_SN9_10 : +{0x0293,0x00,0x01}, // AF_SN11_12 : +{0x6604,0x00,0x01}, // AF_SEARCH_DIR : +{0x6616,0x00,0x01}, // AF_DIRECTBACK_F : +{0x661B,0x03,0x01}, // AF_OPDDATA_SAVE : +{0x661C,0x01,0x01}, // AF_MONOTONY_POS : +{0x663E,0x01,0x01}, // AF_SEARCH_SECOND_DIR : +{0x663F,0x01,0x01}, // AF_DIRECTBACK_SECOND_F : +{0x6674,0x01,0x01}, // AF_MONICHG_MOVE_F : +{0x6675,0x00,0x01}, // CAP_AF_CANCEL_F : +{0x6676,0x02,0x01}, // AF_SAxF_MODE : +{0x669E,0x02,0x01}, // AF_SECOND_WND_CHK : +{0x6600,0x0100,0x02}, // AF_SEARCH_AREA_LOW : +{0x6602,0x0400,0x02}, // AF_SEARCH_AREA_HIGH : +{0x6640,0x02,0x01}, // AF_DROPN_ON_PEAK_DETECT_SECOND : +{0x6641,0x02,0x01}, // AF_UPN_ON_PEAK_DETECT_SECOND : +{0x6644,0x14,0x01}, // AF_UPRATE_ON_PEAK_DETECT_HBPF_SECOND : +{0x6646,0x08,0x01}, // AF_OPD_WEIGHT_TH : +{0x664A,0x02,0x01}, // AF_DROPN_ON_PEAK_DETECT : +{0x664B,0x02,0x01}, // AF_UPN_ON_PEAK_DETECT : +{0x664C,0xFF,0x01}, // AF_UPRATE_ON_PEAK_DETECT_HBPF : +{0x665A,0x0190,0x02}, // AF_LENSPOS_ON_AFNG : +{0x665C,0x0014,0x02}, // AF_DRV_AMOUNT_TONEAR_F : +{0x665E,0x0008,0x02}, // AF_DRV_AMOUNT_TONEAR_S : +{0x6660,0x0014,0x02}, // AF_DRV_AMOUNT_TOFAR_F : +{0x6662,0x0008,0x02}, // AF_DRV_AMOUNT_TOFAR_S : +{0x6666,0x0100,0x02}, // AF_AREA_LOW_TYPE1 : +{0x6668,0x0400,0x02}, // AF_AREA_HIGH_TYPE1 : +{0x669A,0x01F4,0x02}, // AF_OPD_MONOTONYUP_HBPF_TH : +{0x66E4,0x50,0x01}, // AF_TH_1STDEPEND_HBPF_RATE : +{0x66EE,0x01F4,0x02}, // AF_LVD_HBPF_VAL1_1ST : +{0x66F0,0x2710,0x02}, // AF_LVD_HBPF_VAL2_1ST : +{0x66F2,0x004C,0x02}, // AF_LVD_HBPF_RATE1_1ST : +{0x66F4,0x0019,0x02}, // AF_LVD_HBPF_RATE2_1ST : +{0x66F6,0x00,0x01}, // AF_LVD_HBPF_SHIFT_1ST : +{0x6702,0x03E8,0x02}, // AF_LVD_HBPF_VAL1_2ND : +{0x6704,0x4E20,0x02}, // AF_LVD_HBPF_VAL2_2ND : +{0x6706,0x0003,0x02}, // AF_LVD_HBPF_RATE1_2ND : +{0x6708,0x0003,0x02}, // AF_LVD_HBPF_RATE2_2ND : +{0x670A,0x00,0x01}, // AF_LVD_HBPF_SHIFT_2ND : +{0x6742,0x0080,0x02}, // AF_SEARCH_OFFSET_FAR : +{0x6744,0x0080,0x02}, // AF_SEARCH_OFFSET_NEAR : + +//߰ κ +{0x00F7,0x4F,0x01}, // INIT_QLTY0 : Standard 79 +{0x00F8,0x56,0x01}, // INIT_QLTY1 : Fine 86 +{0x00F9,0x5C,0x01}, // INIT_QLTY2 : SuperFine 92 + +// Normal AE +{0x0326,0x22,0x01}, // SHTCTRLTIME1_TYPE1 : +{0x0327,0x15,0x01}, // AGCGAIN1_TYPE1 : 5.4->6.3dB +{0x0328,0x53,0x01}, // SHTCTRLTIME2_TYPE1 : +{0x0329,0x1E,0x01}, // AGCGAIN2_TYPE1 : 8.7->9.0dB +{0x032A,0x3E,0x01}, // SHTCTRLTIME3_TYPE1 : +{0x032B,0x3D,0x01}, // AGCGAIN3_TYPE1 : 17.7-> 18.3dB + +//half release max 20 fps AE +{0x032C,0x64,0x01}, // SHTCTRLTIME1_TYPE2 +{0x032D,0x40,0x01}, // AGCGAIN1_TYPE2 +{0x032E,0x64,0x01}, // SHTCTRLTIME2_TYPE2 +{0x032F,0x40,0x01}, // AGCGAIN2_TYPE2 +{0x0330,0x32,0x01}, // SHTCTRLTIME3_TYPE2 +{0x0331,0x40,0x01}, // AGCGAIN3_TYPE2 + +//AE ref tunning +{0x5E8A,0x00,0x01}, // EVREF_GAIN_A : +{0x5E8B,0x00,0x01}, // EVREF_GAIN_B : +{0x5E8C,0x00,0x01}, // EVREF_GAIN_C : +{0x5E8D,0x03,0x01}, // EVREF_GAIN_D : +{0x5E8E,0x04,0x01}, // EVREF_GAIN_E : +{0x5E8F,0x90,0x01}, // EVREF_TH_A : +{0x5E90,0x94,0x01}, // EVREF_TH_B : +{0x5E91,0xA5,0x01}, // EVREF_TH_C : +{0x5E92,0xC0,0x01}, // EVREF_TH_D : +{0x5E93,0xD5,0x01}, // EVREF_TH_E : + + +//gamma Ilumi +{0x9211,0x58,0x01}, // GAIN_TH_A_TYPE3 : +{0x9212,0x63,0x01}, // GAIN_TH_B_TYPE3 : +{0x9213,0x9F,0x01}, // GAIN_TH_C_TYPE3 : + +{0x984E,0x0A,0x01}, // GAMMA0_0CLIP_A : +{0x984F,0x0A,0x01}, // GAMMA0_0CLIP_B : +{0x9850,0x0F,0x01}, // GAMMA0_0CLIP_C : +{0x9851,0x1E,0x01}, // GAMMA0_SLOPE_A : +{0x9852,0x1E,0x01}, // GAMMA0_SLOPE_B : +{0x9853,0x1E,0x01}, // GAMMA0_SLOPE_C : + +//low gamma +{0x7046,0x67,0x01}, // G0_KNOT_GAINCTRL_TH_L : +{0x7047,0x6C,0x01}, // G0_KNOT_GAINCTRL_TH_H : +{0x7048,0x0000,0x02}, // G0_KNOT_L_G0 : +{0x704A,0x0007,0x02}, // G0_KNOT_L_G1 : +{0x704C,0x001D,0x02}, // G0_KNOT_L_G2 : +{0x704E,0x002F,0x02}, // G0_KNOT_L_G3 : +{0x7050,0x003D,0x02}, // G0_KNOT_L_G4 : +{0x7052,0x004A,0x02}, // G0_KNOT_L_G5 : +{0x7054,0x0051,0x02}, // G0_KNOT_L_G6 : +{0x7056,0x005A,0x02}, // G0_KNOT_L_G7 : +{0x7058,0x0061,0x02}, // G0_KNOT_L_G8 : +{0x705A,0x006A,0x02}, // G0_KNOT_L_G9 : +{0x705C,0x0049,0x02}, // G0_KNOT_L_G10 : +{0x705E,0x0082,0x02}, // G0_KNOT_L_G11 : +{0x7060,0x00AD,0x02}, // G0_KNOT_L_G12 : +{0x7062,0x00CC,0x02}, // G0_KNOT_L_G13 : +{0x7064,0x00E1,0x02}, // G0_KNOT_L_G14 : +{0x7066,0x00ED,0x02}, // G0_KNOT_L_G15 : +{0x7068,0x00F6,0x02}, // G0_KNOT_L_G16 : +{0x706A,0x0106,0x02}, // G0_KNOT_L_G17 : +{0x706C,0x010C,0x02}, // G0_KNOT_L_G18 : + + + +//AWB tuning +{0x64A4,0xFF,0x01}, // OUTFRM_LEFT00 : +{0x64A5,0xFF,0x01}, // OUTFRM_LEFT01 : +{0x64A6,0xFF,0x01}, // OUTFRM_LEFT02 : +{0x64A7,0xFF,0x01}, // OUTFRM_LEFT03 : +{0x64A8,0xFF,0x01}, // OUTFRM_LEFT04 : +{0x64A9,0xFF,0x01}, // OUTFRM_LEFT05 : +{0x64AA,0xFF,0x01}, // OUTFRM_LEFT06 : +{0x64AB,0xFF,0x01}, // OUTFRM_LEFT07 : +{0x64AC,0xFF,0x01}, // OUTFRM_LEFT08 : +{0x64AD,0xFD,0x01}, // OUTFRM_LEFT09 : +{0x64AE,0xCB,0x01}, // OUTFRM_LEFT10 : +{0x64AF,0xA9,0x01}, // OUTFRM_LEFT11 : +{0x64B0,0x90,0x01}, // OUTFRM_LEFT12 : +{0x64B1,0x7D,0x01}, // OUTFRM_LEFT13 : +{0x64B2,0x70,0x01}, // OUTFRM_LEFT14 : +{0x64B3,0x65,0x01}, // OUTFRM_LEFT15 : +{0x64B4,0x5C,0x01}, // OUTFRM_LEFT16 : +{0x64B5,0x55,0x01}, // OUTFRM_LEFT17 : +{0x64B6,0x4F,0x01}, // OUTFRM_LEFT18 : +{0x64B7,0x32,0x01}, // OUTFRM_LEFT19 : +{0x64B8,0x4D,0x01}, // OUTFRM_LEFT20 : +{0x64B9,0x40,0x01}, // OUTFRM_LEFT21 : +{0x64BA,0x2D,0x01}, // OUTFRM_LEFT22 : +{0x64BB,0x2B,0x01}, // OUTFRM_LEFT23 : +{0x64BC,0x29,0x01}, // OUTFRM_LEFT24 : +{0x64BD,0x27,0x01}, // OUTFRM_LEFT25 : +{0x64BE,0x25,0x01}, // OUTFRM_LEFT26 : +{0x64BF,0x23,0x01}, // OUTFRM_LEFT27 : +{0x64C0,0x21,0x01}, // OUTFRM_LEFT28 : +{0x64C1,0x1F,0x01}, // OUTFRM_LEFT29 : +{0x64C2,0x1D,0x01}, // OUTFRM_LEFT30 : +{0x64C3,0x1B,0x01}, // OUTFRM_LEFT31 : +{0x64C4,0x1A,0x01}, // OUTFRM_LEFT32 : +{0x64C5,0x1A,0x01}, // OUTFRM_LEFT33 : +{0x64C6,0x1A,0x01}, // OUTFRM_LEFT34 : +{0x64C7,0x28,0x01}, // OUTFRM_LEFT35 : +{0x64C8,0x27,0x01}, // OUTFRM_LEFT36 : +{0x64C9,0x26,0x01}, // OUTFRM_LEFT37 : +{0x64CA,0xFF,0x01}, // OUTFRM_RIGHT00 : +{0x64CB,0xFF,0x01}, // OUTFRM_RIGHT01 : +{0x64CC,0xFF,0x01}, // OUTFRM_RIGHT02 : +{0x64CD,0xFF,0x01}, // OUTFRM_RIGHT03 : +{0x64CE,0xFF,0x01}, // OUTFRM_RIGHT04 : +{0x64CF,0xFF,0x01}, // OUTFRM_RIGHT05 : +{0x64D0,0xFF,0x01}, // OUTFRM_RIGHT06 : +{0x64D1,0xFF,0x01}, // OUTFRM_RIGHT07 : +{0x64D2,0xFF,0x01}, // OUTFRM_RIGHT08 : +{0x64D3,0xFF,0x01}, // OUTFRM_RIGHT09 : +{0x64D4,0xD3,0x01}, // OUTFRM_RIGHT10 : +{0x64D5,0xB1,0x01}, // OUTFRM_RIGHT11 : +{0x64D6,0x98,0x01}, // OUTFRM_RIGHT12 : +{0x64D7,0x85,0x01}, // OUTFRM_RIGHT13 : +{0x64D8,0x78,0x01}, // OUTFRM_RIGHT14 : +{0x64D9,0x6D,0x01}, // OUTFRM_RIGHT15 : +{0x64DA,0x64,0x01}, // OUTFRM_RIGHT16 : +{0x64DB,0x5D,0x01}, // OUTFRM_RIGHT17 : +{0x64DC,0x57,0x01}, // OUTFRM_RIGHT18 : +{0x64DD,0x63,0x01}, // OUTFRM_RIGHT19 : +{0x64DE,0x5E,0x01}, // OUTFRM_RIGHT20 : +{0x64DF,0x5A,0x01}, // OUTFRM_RIGHT21 : +{0x64E0,0x56,0x01}, // OUTFRM_RIGHT22 : +{0x64E1,0x52,0x01}, // OUTFRM_RIGHT23 : +{0x64E2,0x50,0x01}, // OUTFRM_RIGHT24 : +{0x64E3,0x4E,0x01}, // OUTFRM_RIGHT25 : +{0x64E4,0x4C,0x01}, // OUTFRM_RIGHT26 : +{0x64E5,0x4A,0x01}, // OUTFRM_RIGHT27 : +{0x64E6,0x48,0x01}, // OUTFRM_RIGHT28 : +{0x64E7,0x46,0x01}, // OUTFRM_RIGHT29 : +{0x64E8,0x44,0x01}, // OUTFRM_RIGHT30 : +{0x64E9,0x43,0x01}, // OUTFRM_RIGHT31 : +{0x64EA,0x42,0x01}, // OUTFRM_RIGHT32 : +{0x64EB,0x42,0x01}, // OUTFRM_RIGHT33 : +{0x64EC,0x42,0x01}, // OUTFRM_RIGHT34 : +{0x64ED,0x30,0x01}, // OUTFRM_RIGHT35 : +{0x64EE,0x2F,0x01}, // OUTFRM_RIGHT36 : +{0x64EF,0x2E,0x01}, // OUTFRM_RIGHT37 : +{0x64F0,0x1D92,0x02}, // OUTFRM_TOP : +{0x64F2,0x1400,0x02}, // OUTFRM_BOTM : +{0x64F4,0x19,0x01}, // OUTFRM_FLTOP : +{0x64F5,0x14,0x01}, // OUTFRM_FLBOTM : +{0x64F6,0xFF,0x01}, // OUTAIM_LEFT00 : +{0x64F7,0xFF,0x01}, // OUTAIM_LEFT01 : +{0x64F8,0xFF,0x01}, // OUTAIM_LEFT02 : +{0x64F9,0xFF,0x01}, // OUTAIM_LEFT03 : +{0x64FA,0xFF,0x01}, // OUTAIM_LEFT04 : +{0x64FB,0xFF,0x01}, // OUTAIM_LEFT05 : +{0x64FC,0xFF,0x01}, // OUTAIM_LEFT06 : +{0x64FD,0xFF,0x01}, // OUTAIM_LEFT07 : +{0x64FE,0xFF,0x01}, // OUTAIM_LEFT08 : +{0x64FF,0xFF,0x01}, // OUTAIM_LEFT09 : +{0x6500,0x91,0x01}, // OUTAIM_LEFT10 : +{0x6501,0x91,0x01}, // OUTAIM_LEFT11 : +{0x6502,0x91,0x01}, // OUTAIM_LEFT12 : +{0x6503,0x66,0x01}, // OUTAIM_LEFT13 : +{0x6504,0x5D,0x01}, // OUTAIM_LEFT14 : +{0x6505,0x3C,0x01}, // OUTAIM_LEFT15 : +{0x6506,0x3C,0x01}, // OUTAIM_LEFT16 : +{0x6507,0x3C,0x01}, // OUTAIM_LEFT17 : +{0x6508,0x3A,0x01}, // OUTAIM_LEFT18 : +{0x6509,0x39,0x01}, // OUTAIM_LEFT19 : +{0x650A,0x40,0x01}, // OUTAIM_LEFT20 : +{0x650B,0x46,0x01}, // OUTAIM_LEFT21 : +{0x650C,0x42,0x01}, // OUTAIM_LEFT22 : +{0x650D,0x40,0x01}, // OUTAIM_LEFT23 : +{0x650E,0x3C,0x01}, // OUTAIM_LEFT24 : +{0x650F,0x37,0x01}, // OUTAIM_LEFT25 : +{0x6510,0x34,0x01}, // OUTAIM_LEFT26 : +{0x6511,0x32,0x01}, // OUTAIM_LEFT27 : +{0x6512,0x2F,0x01}, // OUTAIM_LEFT28 : +{0x6513,0x2E,0x01}, // OUTAIM_LEFT29 : +{0x6514,0x2C,0x01}, // OUTAIM_LEFT30 : +{0x6515,0x2A,0x01}, // OUTAIM_LEFT31 : +{0x6516,0x2D,0x01}, // OUTAIM_LEFT32 : +{0x6517,0x2C,0x01}, // OUTAIM_LEFT33 : +{0x6518,0x2B,0x01}, // OUTAIM_LEFT34 : +{0x6519,0x2A,0x01}, // OUTAIM_LEFT35 : +{0x651A,0x29,0x01}, // OUTAIM_LEFT36 : +{0x651B,0x28,0x01}, // OUTAIM_LEFT37 : +{0x651C,0xFF,0x01}, // OUTAIM_RIGHT00 : +{0x651D,0xFF,0x01}, // OUTAIM_RIGHT01 : +{0x651E,0xFF,0x01}, // OUTAIM_RIGHT02 : +{0x651F,0xFF,0x01}, // OUTAIM_RIGHT03 : +{0x6520,0xFF,0x01}, // OUTAIM_RIGHT04 : +{0x6521,0xFF,0x01}, // OUTAIM_RIGHT05 : +{0x6522,0xFF,0x01}, // OUTAIM_RIGHT06 : +{0x6523,0xFF,0x01}, // OUTAIM_RIGHT07 : +{0x6524,0xFF,0x01}, // OUTAIM_RIGHT08 : +{0x6525,0xFF,0x01}, // OUTAIM_RIGHT09 : +{0x6526,0xD9,0x01}, // OUTAIM_RIGHT10 : +{0x6527,0xB7,0x01}, // OUTAIM_RIGHT11 : +{0x6528,0x96,0x01}, // OUTAIM_RIGHT12 : +{0x6529,0x6C,0x01}, // OUTAIM_RIGHT13 : +{0x652A,0x64,0x01}, // OUTAIM_RIGHT14 : +{0x652B,0x62,0x01}, // OUTAIM_RIGHT15 : +{0x652C,0x62,0x01}, // OUTAIM_RIGHT16 : +{0x652D,0x61,0x01}, // OUTAIM_RIGHT17 : +{0x652E,0x60,0x01}, // OUTAIM_RIGHT18 : +{0x652F,0x5E,0x01}, // OUTAIM_RIGHT19 : +{0x6530,0x5B,0x01}, // OUTAIM_RIGHT20 : +{0x6531,0x4F,0x01}, // OUTAIM_RIGHT21 : +{0x6532,0x4B,0x01}, // OUTAIM_RIGHT22 : +{0x6533,0x49,0x01}, // OUTAIM_RIGHT23 : +{0x6534,0x44,0x01}, // OUTAIM_RIGHT24 : +{0x6535,0x3F,0x01}, // OUTAIM_RIGHT25 : +{0x6536,0x3D,0x01}, // OUTAIM_RIGHT26 : +{0x6537,0x3B,0x01}, // OUTAIM_RIGHT27 : +{0x6538,0x3B,0x01}, // OUTAIM_RIGHT28 : +{0x6539,0x3A,0x01}, // OUTAIM_RIGHT29 : +{0x653A,0x38,0x01}, // OUTAIM_RIGHT30 : +{0x653B,0x38,0x01}, // OUTAIM_RIGHT31 : +{0x653C,0x33,0x01}, // OUTAIM_RIGHT32 : +{0x653D,0x32,0x01}, // OUTAIM_RIGHT33 : +{0x653E,0x31,0x01}, // OUTAIM_RIGHT34 : +{0x653F,0x30,0x01}, // OUTAIM_RIGHT35 : +{0x6540,0x2F,0x01}, // OUTAIM_RIGHT36 : +{0x6541,0x2E,0x01}, // OUTAIM_RIGHT37 : +{0x6542,0x1B3E,0x02}, // OUTAIM_TOP : +{0x6544,0x1716,0x02}, // OUTAIM_BOTM : +{0x6546,0x19,0x01}, // OUTAIM_FLTOP : +{0x6547,0x17,0x01}, // OUTAIM_FLBOTM : +{0x65AA,0x78,0x01}, // OUT_CTMP_FRM_BG0 : +{0x65AB,0x74,0x01}, // OUT_CTMP_FRM_BG1 : +{0x65AC,0x70,0x01}, // OUT_CTMP_FRM_BG2 : +{0x65AD,0x6D,0x01}, // OUT_CTMP_FRM_BG3 : +{0x65AE,0x67,0x01}, // OUT_CTMP_FRM_BG4 : +{0x65AF,0x65,0x01}, // OUT_CTMP_FRM_BG5 : +{0x65B0,0x61,0x01}, // OUT_CTMP_FRM_BG6 : +{0x65B1,0x5D,0x01}, // OUT_CTMP_FRM_BG7 : +{0x65B2,0x58,0x01}, // OUT_CTMP_FRM_BG8 : +{0x65B3,0x54,0x01}, // OUT_CTMP_FRM_BG9 : +{0x65B4,0x50,0x01}, // OUT_CTMP_FRM_BG10 : +{0x65B5,0x19,0x01}, // OUT_CTMP_FRM_RG0 : +{0x65B6,0x27,0x01}, // OUT_CTMP_FRM_RG1 : +{0x65B7,0x32,0x01}, // OUT_CTMP_FRM_RG2 : +{0x65B8,0x3E,0x01}, // OUT_CTMP_FRM_RG3 : +{0x65B9,0x49,0x01}, // OUT_CTMP_FRM_RG4 : +{0x65BA,0x54,0x01}, // OUT_CTMP_FRM_RG5 : +{0x65BB,0x5E,0x01}, // OUT_CTMP_FRM_RG6 : +{0x65BC,0x20,0x01}, // OUT_CTMP_WEIGHT00_01 : +{0x65BD,0x22,0x01}, // OUT_CTMP_WEIGHT02_03 : +{0x65BE,0x02,0x01}, // OUT_CTMP_WEIGHT04_05 : +{0x65BF,0x20,0x01}, // OUT_CTMP_WEIGHT06_07 : +{0x65C0,0x22,0x01}, // OUT_CTMP_WEIGHT08_09 : +{0x65C1,0x02,0x01}, // OUT_CTMP_WEIGHT10_11 : +{0x65C2,0x20,0x01}, // OUT_CTMP_WEIGHT12_13 : +{0x65C3,0x22,0x01}, // OUT_CTMP_WEIGHT14_15 : +{0x65C4,0x02,0x01}, // OUT_CTMP_WEIGHT16_17 : +{0x65C5,0x20,0x01}, // OUT_CTMP_WEIGHT18_19 : +{0x65C6,0x22,0x01}, // OUT_CTMP_WEIGHT20_21 : +{0x65C7,0x02,0x01}, // OUT_CTMP_WEIGHT22_23 : +{0x65C8,0x10,0x01}, // OUT_CTMP_WEIGHT24_25 : +{0x65C9,0x11,0x01}, // OUT_CTMP_WEIGHT26_27 : +{0x65CA,0x01,0x01}, // OUT_CTMP_WEIGHT28_29 : +{0x65CB,0x10,0x01}, // OUT_CTMP_WEIGHT30_31 : +{0x65CC,0x11,0x01}, // OUT_CTMP_WEIGHT32_33 : +{0x65CD,0x01,0x01}, // OUT_CTMP_WEIGHT34_35 : +{0x65CE,0x10,0x01}, // OUT_CTMP_WEIGHT36_37 : +{0x65CF,0x11,0x01}, // OUT_CTMP_WEIGHT38_39 : +{0x65D0,0x01,0x01}, // OUT_CTMP_WEIGHT40_41 : +{0x65D1,0x00,0x01}, // OUT_CTMP_WEIGHT42_43 : +{0x65D2,0x00,0x01}, // OUT_CTMP_WEIGHT44_45 : +{0x65D3,0x00,0x01}, // OUT_CTMP_WEIGHT46_47 : +{0x65D4,0x00,0x01}, // OUT_CTMP_WEIGHT48_49 : +{0x65D5,0x00,0x01}, // OUT_CTMP_WEIGHT50_51 : +{0x65D6,0x00,0x01}, // OUT_CTMP_WEIGHT52_53 : +{0x65D7,0x00,0x01}, // OUT_CTMP_WEIGHT54_55 : +{0x65D8,0x00,0x01}, // OUT_CTMP_WEIGHT56_57 : +{0x65D9,0x00,0x01}, // OUT_CTMP_WEIGHT58_59 : + + +//AWB_outdoor_ġ on +{0x629B,0x41,0x01}, // CAT_AWB_3 : + +//Bluesky threshold +{0x6548,0x1926,0x02}, // OUTAIM_TOP_BLUESKY : + + +//Hue,Gain outdoor setting +{0x6EF6,0x0000,0x02}, // +{0x6EF8,0xFFF2,0x02}, // +{0x6EFA,0xFFF8,0x02}, // +{0x6EFC,0xFFF3,0x02}, // +{0x6EFE,0xFFF8,0x02}, // +{0x6F00,0xFFEF,0x02}, // +{0x6F02,0x0000,0x02}, // +{0x6F04,0xFFED,0x02}, // +{0x6F5E,0x55,0x01}, // +{0x6F5F,0x55,0x01}, // +{0x6F60,0x55,0x01}, // +{0x6F61,0x5F,0x01}, // +{0x6F62,0x55,0x01}, // +{0x6F63,0x5F,0x01}, // +{0x6F64,0x55,0x01}, // +{0x6F65,0x55,0x01}, // + +//LMT outdoor setting +{0x6E54,0xFFA6,0x02}, // LM_GRG_OUT : +{0x6E56,0xFFEF,0x02}, // LM_GRB_OUT : +{0x6E58,0xFFF6,0x02}, // LM_GGR_OUT : +{0x6E5A,0xFFE6,0x02}, // LM_GGB_OUT : +{0x6E5C,0xFFFA,0x02}, // LM_GBR_OUT : +{0x6E5E,0xFFE6,0x02}, // LM_GBG_OUT : + +//MC3 OFF +{0x6C49,0xE5,0x01}, // MAIN_CONFIG4 : + + +//////////////////////////////////////////////////////////////// + +{0x941F,0x00,0x01}, // AP_N_GC_POS_CORE_A : < Ϲ̻ //// 0x18 => OUTFMT_CAPϻ +{0x0084,0x00,0x01},//SENSMODE_CAP +{0x0087,0x03,0x01},//FPSTYPE_CAP +}; + +isx012_short_t isx012_shading_setting[] = +{ +// CXC/SHD EN +{0x01BC,0x57,0x01}, // CXC OFF SHD OFF + +//CXC +{0xEB00,0x8282,0x02}, // valid_code +{0xEB02,0x00,0x01}, // +{0xEB03,0x03,0x01}, // +{0xEB04,0xC0,0x01}, // +{0xEB05,0x30,0x01}, // +{0xEB06,0x48,0x01}, // +{0xEB07,0x04,0x01}, // +{0xEB08,0x0C,0x01}, // +{0xEB09,0x02,0x01}, // +{0xEB0A,0x44,0x01}, // +{0xEB0B,0xE0,0x01}, // +{0xEB0C,0x30,0x01}, // +{0xEB0D,0x40,0x01}, // +{0xEB0E,0x0C,0x01}, // +{0xEB0F,0x12,0x01}, // +{0xEB10,0x83,0x01}, // +{0xEB11,0x04,0x01}, // +{0xEB12,0xC0,0x01}, // +{0xEB13,0x00,0x01}, // +{0xEB14,0x30,0x01}, // +{0xEB15,0x0C,0x01}, // +{0xEB16,0x12,0x01}, // +{0xEB17,0x01,0x01}, // +{0xEB18,0x83,0x01}, // +{0xEB19,0x00,0x01}, // +{0xEB1A,0x11,0x01}, // +{0xEB1B,0x38,0x01}, // +{0xEB1C,0x0C,0x01}, // +{0xEB1D,0x10,0x01}, // +{0xEB1E,0x83,0x01}, // +{0xEB1F,0xC4,0x01}, // +{0xEB20,0x20,0x01}, // +{0xEB21,0x21,0x01}, // +{0xEB22,0x28,0x01}, // +{0xEB23,0x08,0x01}, // +{0xEB24,0x0A,0x01}, // +{0xEB25,0x83,0x01}, // +{0xEB26,0xC3,0x01}, // +{0xEB27,0xC0,0x01}, // +{0xEB28,0x10,0x01}, // +{0xEB29,0x28,0x01}, // +{0xEB2A,0x08,0x01}, // +{0xEB2B,0x0A,0x01}, // +{0xEB2C,0x03,0x01}, // +{0xEB2D,0x04,0x01}, // +{0xEB2E,0x01,0x01}, // +{0xEB2F,0x41,0x01}, // +{0xEB30,0x40,0x01}, // +{0xEB31,0x08,0x01}, // +{0xEB32,0x0A,0x01}, // +{0xEB33,0x82,0x01}, // +{0xEB34,0x42,0x01}, // +{0xEB35,0x80,0x01}, // +{0xEB36,0x10,0x01}, // +{0xEB37,0x18,0x01}, // +{0xEB38,0x04,0x01}, // +{0xEB39,0x08,0x01}, // +{0xEB3A,0x81,0x01}, // +{0xEB3B,0x81,0x01}, // +{0xEB3C,0xA0,0x01}, // +{0xEB3D,0x10,0x01}, // +{0xEB3E,0x40,0x01}, // +{0xEB3F,0x04,0x01}, // +{0xEB40,0x10,0x01}, // +{0xEB41,0x82,0x01}, // +{0xEB42,0x82,0x01}, // +{0xEB43,0xA0,0x01}, // +{0xEB44,0x10,0x01}, // +{0xEB45,0x10,0x01}, // +{0xEB46,0x08,0x01}, // +{0xEB47,0x02,0x01}, // +{0xEB48,0x01,0x01}, // +{0xEB49,0x80,0x01}, // +{0xEB4A,0x40,0x01}, // +{0xEB4B,0x20,0x01}, // +{0xEB4C,0x10,0x01}, // +{0xEB4D,0x08,0x01}, // +{0xEB4E,0x0C,0x01}, // +{0xEB4F,0x02,0x01}, // +{0xEB50,0xC3,0x01}, // +{0xEB51,0x40,0x01}, // +{0xEB52,0x30,0x01}, // +{0xEB53,0x10,0x01}, // +{0xEB54,0x08,0x01}, // +{0xEB55,0x02,0x01}, // +{0xEB56,0x01,0x01}, // +{0xEB57,0x80,0x01}, // +{0xEB58,0xE0,0x01}, // +{0xEB59,0x1F,0x01}, // +{0xEB5A,0x00,0x01}, // +{0xEB5B,0x04,0x01}, // +{0xEB5C,0x02,0x01}, // +{0xEB5D,0x00,0x01}, // +{0xEB5E,0x02,0x01}, // +{0xEB5F,0x80,0x01}, // +{0xEB60,0x10,0x01}, // +{0xEB61,0x18,0x01}, // +{0xEB62,0x04,0x01}, // +{0xEB63,0x06,0x01}, // +{0xEB64,0x81,0x01}, // +{0xEB65,0x80,0x01}, // +{0xEB66,0x00,0x01}, // +{0xEB67,0x20,0x01}, // +{0xEB68,0x00,0x01}, // +{0xEB69,0x0C,0x01}, // +{0xEB6A,0x02,0x01}, // +{0xEB6B,0x01,0x01}, // +{0xEB6C,0x81,0x01}, // +{0xEB6D,0x60,0x01}, // +{0xEB6E,0x20,0x01}, // +{0xEB6F,0x18,0x01}, // +{0xEB70,0x08,0x01}, // +{0xEB71,0x06,0x01}, // +{0xEB72,0x82,0x01}, // +{0xEB73,0x81,0x01}, // +{0xEB74,0x40,0x01}, // +{0xEB75,0x30,0x01}, // +{0xEB76,0x00,0x01}, // +{0xEB77,0x0C,0x01}, // +{0xEB78,0x00,0x01}, // +{0xEB79,0x84,0x01}, // +{0xEB7A,0x40,0x01}, // +{0xEB7B,0x40,0x01}, // +{0xEB7C,0x00,0x01}, // +{0xEB7D,0x20,0x01}, // +{0xEB7E,0x00,0x01}, // +{0xEB7F,0x08,0x01}, // +{0xEB80,0x80,0x01}, // +{0xEB81,0x02,0x01}, // +{0xEB82,0xA0,0x01}, // +{0xEB83,0x10,0x01}, // +{0xEB84,0x18,0x01}, // +{0xEB85,0x08,0x01}, // +{0xEB86,0x04,0x01}, // +{0xEB87,0x03,0x01}, // +{0xEB88,0xC1,0x01}, // +{0xEB89,0x60,0x01}, // +{0xEB8A,0x10,0x01}, // +{0xEB8B,0x20,0x01}, // +{0xEB8C,0x08,0x01}, // +{0xEB8D,0x08,0x01}, // +{0xEB8E,0x02,0x01}, // +{0xEB8F,0x02,0x01}, // +{0xEB90,0x81,0x01}, // +{0xEB91,0x40,0x01}, // +{0xEB92,0x20,0x01}, // +{0xEB93,0x10,0x01}, // +{0xEB94,0x0A,0x01}, // +{0xEB95,0x01,0x01}, // +{0xEB96,0x42,0x01}, // +{0xEB97,0x60,0x01}, // +{0xEB98,0x40,0x01}, // +{0xEB99,0x20,0x01}, // +{0xEB9A,0x10,0x01}, // +{0xEB9B,0x0C,0x01}, // +{0xEB9C,0x02,0x01}, // +{0xEB9D,0x82,0x01}, // +{0xEB9E,0x80,0x01}, // +{0xEB9F,0x20,0x01}, // +{0xEBA0,0x28,0x01}, // +{0xEBA1,0x08,0x01}, // +{0xEBA2,0x0A,0x01}, // +{0xEBA3,0x04,0x01}, // +{0xEBA4,0x02,0x01}, // +{0xEBA5,0xC1,0x01}, // +{0xEBA6,0x30,0x01}, // +{0xEBA7,0x30,0x01}, // +{0xEBA8,0x10,0x01}, // +{0xEBA9,0x0C,0x01}, // +{0xEBAA,0x02,0x01}, // +{0xEBAB,0x03,0x01}, // +{0xEBAC,0xC1,0x01}, // +{0xEBAD,0x40,0x01}, // +{0xEBAE,0x30,0x01}, // +{0xEBAF,0x08,0x01}, // +{0xEBB0,0x0A,0x01}, // +{0xEBB1,0x82,0x01}, // +{0xEBB2,0x02,0x01}, // +{0xEBB3,0x81,0x01}, // +{0xEBB4,0x40,0x01}, // +{0xEBB5,0x30,0x01}, // +{0xEBB6,0x0C,0x01}, // +{0xEBB7,0x0C,0x01}, // +{0xEBB8,0x04,0x01}, // +{0xEBB9,0x83,0x01}, // +{0xEBBA,0xC0,0x01}, // +{0xEBBB,0x40,0x01}, // +{0xEBBC,0x30,0x01}, // +{0xEBBD,0x10,0x01}, // +{0xEBBE,0x0C,0x01}, // +{0xEBBF,0x81,0x01}, // +{0xEBC0,0x7C,0x01}, // +{0xEBC1,0x20,0x01}, // +{0xEBC2,0x0F,0x01}, // +{0xEBC3,0xC8,0x01}, // +{0xEBC4,0xFF,0x01}, // +{0xEBC5,0xF7,0x01}, // +{0xEBC6,0x80,0x01}, // +{0xEBC7,0x3D,0x01}, // +{0xEBC8,0x40,0x01}, // +{0xEBC9,0xEF,0x01}, // +{0xEBCA,0xDF,0x01}, // +{0xEBCB,0xFB,0x01}, // +{0xEBCC,0xF3,0x01}, // +{0xEBCD,0xFE,0x01}, // +{0xEBCE,0x7C,0x01}, // +{0xEBCF,0x20,0x01}, // +{0xEBD0,0x1F,0x01}, // +{0xEBD1,0xC8,0x01}, // +{0xEBD2,0x03,0x01}, // +{0xEBD3,0xF2,0x01}, // +{0xEBD4,0xFF,0x01}, // +{0xEBD5,0x3D,0x01}, // +{0xEBD6,0x60,0x01}, // +{0xEBD7,0x0F,0x01}, // +{0xEBD8,0xD0,0x01}, // +{0xEBD9,0xFB,0x01}, // +{0xEBDA,0xF7,0x01}, // +{0xEBDB,0xFE,0x01}, // +{0xEBDC,0xBC,0x01}, // +{0xEBDD,0x3F,0x01}, // +{0xEBDE,0x1F,0x01}, // +{0xEBDF,0xC0,0x01}, // +{0xEBE0,0x07,0x01}, // +{0xEBE1,0xF0,0x01}, // +{0xEBE2,0x01,0x01}, // +{0xEBE3,0xBD,0x01}, // +{0xEBE4,0x3F,0x01}, // +{0xEBE5,0xFF,0x01}, // +{0xEBE6,0xD7,0x01}, // +{0xEBE7,0xF7,0x01}, // +{0xEBE8,0xF3,0x01}, // +{0xEBE9,0xFF,0x01}, // +{0xEBEA,0xFD,0x01}, // +{0xEBEB,0x5F,0x01}, // +{0xEBEC,0xFF,0x01}, // +{0xEBED,0xD7,0x01}, // +{0xEBEE,0x0B,0x01}, // +{0xEBEF,0xF8,0x01}, // +{0xEBF0,0x02,0x01}, // +{0xEBF1,0xBE,0x01}, // +{0xEBF2,0xFF,0x01}, // +{0xEBF3,0xEE,0x01}, // +{0xEBF4,0xCF,0x01}, // +{0xEBF5,0xFB,0x01}, // +{0xEBF6,0xF3,0x01}, // +{0xEBF7,0xFE,0x01}, // +{0xEBF8,0xFC,0x01}, // +{0xEBF9,0x5F,0x01}, // +{0xEBFA,0xEF,0x01}, // +{0xEBFB,0xC7,0x01}, // +{0xEBFC,0xFB,0x01}, // +{0xEBFD,0xF1,0x01}, // +{0xEBFE,0x81,0x01}, // +{0xEBFF,0x7C,0x01}, // +{0xEC00,0x20,0x01}, // +{0xEC01,0x0F,0x01}, // +{0xEC02,0xE0,0x01}, // +{0xEC03,0xFF,0x01}, // +{0xEC04,0xF7,0x01}, // +{0xEC05,0xFD,0x01}, // +{0xEC06,0xFE,0x01}, // +{0xEC07,0x5F,0x01}, // +{0xEC08,0xDF,0x01}, // +{0xEC09,0xEF,0x01}, // +{0xEC0A,0xF7,0x01}, // +{0xEC0B,0xF7,0x01}, // +{0xEC0C,0xFD,0x01}, // +{0xEC0D,0x3D,0x01}, // +{0xEC0E,0xC1,0x01}, // +{0xEC0F,0x4F,0x01}, // +{0xEC10,0xF0,0x01}, // +{0xEC11,0x07,0x01}, // +{0xEC12,0xF8,0x01}, // +{0xEC13,0xFF,0x01}, // +{0xEC14,0xBE,0x01}, // +{0xEC15,0xFF,0x01}, // +{0xEC16,0xFF,0x01}, // +{0xEC17,0xEF,0x01}, // +{0xEC18,0xFF,0x01}, // +{0xEC19,0xFB,0x01}, // +{0xEC1A,0xFE,0x01}, // +{0xEC1B,0xBD,0x01}, // +{0xEC1C,0x7F,0x01}, // +{0xEC1D,0x4F,0x01}, // +{0xEC1E,0x00,0x01}, // +{0xEC1F,0x10,0x01}, // +{0xEC20,0x00,0x01}, // +{0xEC21,0x82,0x01}, // +{0xEC22,0x40,0x01}, // +{0xEC23,0x00,0x01}, // +{0xEC24,0x00,0x01}, // +{0xEC25,0xF8,0x01}, // +{0xEC26,0xFF,0x01}, // +{0xEC27,0x05,0x01}, // +{0xEC28,0x7F,0x01}, // +{0xEC29,0xFF,0x01}, // +{0xEC2A,0xBF,0x01}, // +{0xEC2B,0xFF,0x01}, // +{0xEC2C,0xEF,0x01}, // +{0xEC2D,0x17,0x01}, // +{0xEC2E,0x02,0x01}, // +{0xEC2F,0x85,0x01}, // +{0xEC30,0xC0,0x01}, // +{0xEC31,0x00,0x01}, // +{0xEC32,0x20,0x01}, // +{0xEC33,0xF8,0x01}, // +{0xEC34,0x07,0x01}, // +{0xEC35,0x08,0x01}, // +{0xEC36,0x00,0x01}, // +{0xEC37,0x41,0x01}, // +{0xEC38,0x20,0x01}, // +{0xEC39,0x20,0x01}, // +{0xEC3A,0x10,0x01}, // +{0xEC3B,0x08,0x01}, // +{0xEC3C,0x04,0x01}, // +{0xEC3D,0x07,0x01}, // +{0xEC3E,0xC1,0x01}, // +{0xEC3F,0x41,0x01}, // +{0xEC40,0x60,0x01}, // +{0xEC41,0x00,0x01}, // +{0xEC42,0x0C,0x01}, // +{0xEC43,0x0A,0x01}, // +{0xEC44,0x83,0x01}, // +{0xEC45,0x82,0x01}, // +{0xEC46,0x80,0x01}, // +{0xEC47,0x10,0x01}, // +{0xEC48,0x18,0x01}, // +{0xEC49,0x08,0x01}, // +{0xEC4A,0x04,0x01}, // +{0xEC4B,0x02,0x01}, // +{0xEC4C,0x81,0x01}, // +{0xEC4D,0x61,0x01}, // +{0xEC4E,0x60,0x01}, // +{0xEC4F,0x18,0x01}, // +{0xEC50,0x14,0x01}, // +{0xEC51,0x06,0x01}, // +{0xEC52,0x05,0x01}, // +{0xEC53,0x04,0x01}, // +{0xEC54,0x61,0x01}, // +{0xEC55,0x30,0x01}, // +{0xEC56,0x38,0x01}, // +{0xEC57,0x08,0x01}, // +{0xEC58,0x0A,0x01}, // +{0xEC59,0x03,0x01}, // +{0xEC5A,0xC2,0x01}, // +{0xEC5B,0x80,0x01}, // +{0xEC5C,0x60,0x01}, // +{0xEC5D,0x28,0x01}, // +{0xEC5E,0x18,0x01}, // +{0xEC5F,0x0A,0x01}, // +{0xEC60,0x84,0x01}, // +{0xEC61,0x03,0x01}, // +{0xEC62,0xC1,0x01}, // +{0xEC63,0x30,0x01}, // +{0xEC64,0x30,0x01}, // +{0xEC65,0x08,0x01}, // +{0xEC66,0x0C,0x01}, // +{0xEC67,0x03,0x01}, // +{0xEC68,0x02,0x01}, // +{0xEC69,0x21,0x01}, // +{0xEC6A,0x41,0x01}, // +{0xEC6B,0x48,0x01}, // +{0xEC6C,0x18,0x01}, // +{0xEC6D,0x0A,0x01}, // +{0xEC6E,0x86,0x01}, // +{0xEC6F,0x02,0x01}, // +{0xEC70,0xE1,0x01}, // +{0xEC71,0x40,0x01}, // +{0xEC72,0x30,0x01}, // +{0xEC73,0x0C,0x01}, // +{0xEC74,0x0C,0x01}, // +{0xEC75,0x02,0x01}, // +{0xEC76,0xC3,0x01}, // +{0xEC77,0x80,0x01}, // +{0xEC78,0x40,0x01}, // +{0xEC79,0x48,0x01}, // +{0xEC7A,0x10,0x01}, // +{0xEC7B,0x12,0x01}, // +{0xED00,0x9191,0x02}, // +{0xED02,0x24,0x01}, // +{0xED03,0xC2,0x01}, // +{0xED04,0x13,0x01}, // +{0xED05,0x86,0x01}, // +{0xED06,0xD6,0x01}, // +{0xED07,0x24,0x01}, // +{0xED08,0x9F,0x01}, // +{0xED09,0x22,0x01}, // +{0xED0A,0x61,0x01}, // +{0xED0B,0x07,0x01}, // +{0xED0C,0x44,0x01}, // +{0xED0D,0xC8,0x01}, // +{0xED0E,0x89,0x01}, // +{0xED0F,0x50,0x01}, // +{0xED10,0x74,0x01}, // +{0xED11,0x34,0x01}, // +{0xED12,0x84,0x01}, // +{0xED13,0x1E,0x01}, // +{0xED14,0x1C,0x01}, // +{0xED15,0x31,0x01}, // +{0xED16,0xC8,0x01}, // +{0xED17,0x4C,0x01}, // +{0xED18,0x1B,0x01}, // +{0xED19,0xAA,0x01}, // +{0xED1A,0xD3,0x01}, // +{0xED1B,0x87,0x01}, // +{0xED1C,0xE8,0x01}, // +{0xED1D,0x34,0x01}, // +{0xED1E,0xA0,0x01}, // +{0xED1F,0x2A,0x01}, // +{0xED20,0x65,0x01}, // +{0xED21,0x87,0x01}, // +{0xED22,0x44,0x01}, // +{0xED23,0xBE,0x01}, // +{0xED24,0xF9,0x01}, // +{0xED25,0x0F,0x01}, // +{0xED26,0x6C,0x01}, // +{0xED27,0xE2,0x01}, // +{0xED28,0x83,0x01}, // +{0xED29,0x1B,0x01}, // +{0xED2A,0xFD,0x01}, // +{0xED2B,0x38,0x01}, // +{0xED2C,0x47,0x01}, // +{0xED2D,0x43,0x01}, // +{0xED2E,0xF4,0x01}, // +{0xED2F,0x79,0x01}, // +{0xED30,0x92,0x01}, // +{0xED31,0x83,0x01}, // +{0xED32,0xDA,0x01}, // +{0xED33,0x64,0x01}, // +{0xED34,0x9E,0x01}, // +{0xED35,0x15,0x01}, // +{0xED36,0x1D,0x01}, // +{0xED37,0x87,0x01}, // +{0xED38,0x40,0x01}, // +{0xED39,0x99,0x01}, // +{0xED3A,0x69,0x01}, // +{0xED3B,0x4E,0x01}, // +{0xED3C,0x5F,0x01}, // +{0xED3D,0x4C,0x01}, // +{0xED3E,0x13,0x01}, // +{0xED3F,0x17,0x01}, // +{0xED40,0xCC,0x01}, // +{0xED41,0xDC,0x01}, // +{0xED42,0xE5,0x01}, // +{0xED43,0x33,0x01}, // +{0xED44,0x90,0x01}, // +{0xED45,0x29,0x01}, // +{0xED46,0xCE,0x01}, // +{0xED47,0x6E,0x01}, // +{0xED48,0x02,0x01}, // +{0xED49,0x34,0x01}, // +{0xED4A,0x9D,0x01}, // +{0xED4B,0x11,0x01}, // +{0xED4C,0xDD,0x01}, // +{0xED4D,0xC6,0x01}, // +{0xED4E,0x3D,0x01}, // +{0xED4F,0x97,0x01}, // +{0xED50,0x29,0x01}, // +{0xED51,0x8E,0x01}, // +{0xED52,0x59,0x01}, // +{0xED53,0x08,0x01}, // +{0xED54,0x13,0x01}, // +{0xED55,0x94,0x01}, // +{0xED56,0xAA,0x01}, // +{0xED57,0xD8,0x01}, // +{0xED58,0xE4,0x01}, // +{0xED59,0x28,0x01}, // +{0xED5A,0x3D,0x01}, // +{0xED5B,0x81,0x01}, // +{0xED5C,0x8A,0x01}, // +{0xED5D,0x57,0x01}, // +{0xED5E,0xFA,0x01}, // +{0xED5F,0xA2,0x01}, // +{0xED60,0x98,0x01}, // +{0xED61,0xDF,0x01}, // +{0xED62,0x94,0x01}, // +{0xED63,0x06,0x01}, // +{0xED64,0x3D,0x01}, // +{0xED65,0x99,0x01}, // +{0xED66,0x39,0x01}, // +{0xED67,0x0E,0x01}, // +{0xED68,0x5D,0x01}, // +{0xED69,0x2C,0x01}, // +{0xED6A,0xE3,0x01}, // +{0xED6B,0x13,0x01}, // +{0xED6C,0xA7,0x01}, // +{0xED6D,0x70,0x01}, // +{0xED6E,0x84,0x01}, // +{0xED6F,0x24,0x01}, // +{0xED70,0x0F,0x01}, // +{0xED71,0x99,0x01}, // +{0xED72,0x48,0x01}, // +{0xED73,0x46,0x01}, // +{0xED74,0x40,0x01}, // +{0xED75,0x72,0x01}, // +{0xED76,0x93,0x01}, // +{0xED77,0xA3,0x01}, // +{0xED78,0xA0,0x01}, // +{0xED79,0xA5,0x01}, // +{0xED7A,0x31,0x01}, // +{0xED7B,0x88,0x01}, // +{0xED7C,0xE1,0x01}, // +{0xED7D,0x0D,0x01}, // +{0xED7E,0x63,0x01}, // +{0xED7F,0x64,0x01}, // +{0xED80,0x53,0x01}, // +{0xED81,0x16,0x01}, // +{0xED82,0xBF,0x01}, // +{0xED83,0xB0,0x01}, // +{0xED84,0xC4,0x01}, // +{0xED85,0x26,0x01}, // +{0xED86,0x0B,0x01}, // +{0xED87,0x71,0x01}, // +{0xED88,0x08,0x01}, // +{0xED89,0x40,0x01}, // +{0xED8A,0x00,0x01}, // +{0xED8B,0x92,0x01}, // +{0xED8C,0x90,0x01}, // +{0xED8D,0x85,0x01}, // +{0xED8E,0x90,0x01}, // +{0xED8F,0xE4,0x01}, // +{0xED90,0x25,0x01}, // +{0xED91,0x56,0x01}, // +{0xED92,0xA1,0x01}, // +{0xED93,0x4B,0x01}, // +{0xED94,0x5E,0x01}, // +{0xED95,0x4A,0x01}, // +{0xED96,0xF3,0x01}, // +{0xED97,0x18,0x01}, // +{0xED98,0xDC,0x01}, // +{0xED99,0xA0,0x01}, // +{0xED9A,0x65,0x01}, // +{0xED9B,0x30,0x01}, // +{0xED9C,0x30,0x01}, // +{0xED9D,0xE1,0x01}, // +{0xED9E,0x09,0x01}, // +{0xED9F,0x44,0x01}, // +{0xEDA0,0x24,0x01}, // +{0xEDA1,0x32,0x01}, // +{0xEDA2,0x10,0x01}, // +{0xEDA3,0x82,0x01}, // +{0xEDA4,0x34,0x01}, // +{0xEDA5,0x04,0x01}, // +{0xEDA6,0x22,0x01}, // +{0xEDA7,0x28,0x01}, // +{0xEDA8,0xA9,0x01}, // +{0xEDA9,0x89,0x01}, // +{0xEDAA,0x56,0x01}, // +{0xEDAB,0xEE,0x01}, // +{0xEDAC,0xE2,0x01}, // +{0xEDAD,0x97,0x01}, // +{0xEDAE,0xD3,0x01}, // +{0xEDAF,0x94,0x01}, // +{0xEDB0,0x86,0x01}, // +{0xEDB1,0x3A,0x01}, // +{0xEDB2,0x81,0x01}, // +{0xEDB3,0x21,0x01}, // +{0xEDB4,0xCD,0x01}, // +{0xEDB5,0x52,0x01}, // +{0xEDB6,0xBA,0x01}, // +{0xEDB7,0x92,0x01}, // +{0xEDB8,0x12,0x01}, // +{0xEDB9,0x98,0x01}, // +{0xEDBA,0x70,0x01}, // +{0xEDBB,0x04,0x01}, // +{0xEDBC,0x24,0x01}, // +{0xEDBD,0x26,0x01}, // +{0xEDBE,0x71,0x01}, // +{0xEDBF,0x89,0x01}, // +{0xEDC0,0x50,0x01}, // +{0xEDC1,0xAC,0x01}, // +{0xEDC2,0x22,0x01}, // +{0xEDC3,0x97,0x01}, // +{0xEDC4,0xCC,0x01}, // +{0xEDC5,0x48,0x01}, // +{0xEDC6,0x86,0x01}, // +{0xEDC7,0x38,0x01}, // +{0xEDC8,0xC7,0x01}, // +{0xEDC9,0x31,0x01}, // +{0xEDCA,0x10,0x01}, // +{0xEDCB,0x6A,0x01}, // +{0xEDCC,0xBA,0x01}, // +{0xEDCD,0x83,0x01}, // +{0xEDCE,0x97,0x01}, // +{0xEDCF,0xCD,0x01}, // +{0xEDD0,0x54,0x01}, // +{0xEDD1,0x65,0x01}, // +{0xEDD2,0x2D,0x01}, // +{0xEDD3,0x4A,0x01}, // +{0xEDD4,0xE1,0x01}, // +{0xEDD5,0x4A,0x01}, // +{0xEDD6,0x54,0x01}, // +{0xEDD7,0xD0,0x01}, // +{0xEDD8,0xF2,0x01}, // +{0xEDD9,0x16,0x01}, // +{0xEDDA,0xCA,0x01}, // +{0xEDDB,0x68,0x01}, // +{0xEDDC,0xE6,0x01}, // +{0xEDDD,0x39,0x01}, // +{0xEDDE,0xB5,0x01}, // +{0xEDDF,0x91,0x01}, // +{0xEDE0,0x8F,0x01}, // +{0xEDE1,0x7F,0x01}, // +{0xEDE2,0x96,0x01}, // +{0xEDE3,0xD4,0x01}, // +{0xEDE4,0x9D,0x01}, // +{0xEDE5,0x10,0x01}, // +{0xEDE6,0xB9,0x01}, // +{0xEDE7,0xC6,0x01}, // +{0xEDE8,0x3C,0x01}, // +{0xEDE9,0x92,0x01}, // +{0xEDEA,0x11,0x01}, // +{0xEDEB,0x0E,0x01}, // +{0xEDEC,0x62,0x01}, // +{0xEDED,0x68,0x01}, // +{0xEDEE,0xD3,0x01}, // +{0xEDEF,0x18,0x01}, // +{0xEDF0,0xDF,0x01}, // +{0xEDF1,0x90,0x01}, // +{0xEDF2,0x46,0x01}, // +{0xEDF3,0x3C,0x01}, // +{0xEDF4,0xCD,0x01}, // +{0xEDF5,0xA9,0x01}, // +{0xEDF6,0x10,0x01}, // +{0xEDF7,0x7A,0x01}, // +{0xEDF8,0x70,0x01}, // +{0xEDF9,0xA4,0x01}, // +{0xEDFA,0xA3,0x01}, // +{0xEDFB,0x4B,0x01}, // +{0xEDFC,0x81,0x01}, // +{0xEDFD,0x48,0x01}, // +{0xEDFE,0x4F,0x01}, // +{0xEDFF,0xF5,0x01}, // +{0xEE00,0x21,0x01}, // +{0xEE01,0x52,0x01}, // +{0xEE02,0x76,0x01}, // +{0xEE03,0x4C,0x01}, // +{0xEE04,0xA4,0x01}, // +{0xEE05,0x1C,0x01}, // +{0xEE06,0x0B,0x01}, // +{0xEE07,0x4D,0x01}, // +{0xEE08,0x27,0x01}, // +{0xEE09,0x44,0x01}, // +{0xEE0A,0xE8,0x01}, // +{0xEE0B,0x01,0x01}, // +{0xEE0C,0x12,0x01}, // +{0xEE0D,0x84,0x01}, // +{0xEE0E,0xE2,0x01}, // +{0xEE0F,0x64,0x01}, // +{0xEE10,0x22,0x01}, // +{0xEE11,0x43,0x01}, // +{0xEE12,0xE5,0x01}, // +{0xEE13,0xC8,0x01}, // +{0xEE14,0x52,0x01}, // +{0xEE15,0x36,0x01}, // +{0xEE16,0xA2,0x01}, // +{0xEE17,0x94,0x01}, // +{0xEE18,0x85,0x01}, // +{0xEE19,0xE0,0x01}, // +{0xEE1A,0xA4,0x01}, // +{0xEE1B,0x9F,0x01}, // +{0xEE1C,0x2A,0x01}, // +{0xEE1D,0xA1,0x01}, // +{0xEE1E,0x67,0x01}, // +{0xEE1F,0x48,0x01}, // +{0xEE20,0xF1,0x01}, // +{0xEE21,0x69,0x01}, // +{0xEE22,0x12,0x01}, // +{0xEE23,0x82,0x01}, // +{0xEE24,0xD8,0x01}, // +{0xEE25,0x74,0x01}, // +{0xEE26,0x22,0x01}, // +{0xEE27,0x47,0x01}, // +{0xEE28,0xB5,0x01}, // +{0xEE29,0xE8,0x01}, // +{0xEE2A,0x51,0x01}, // +{0xEE2B,0x0B,0x01}, // +{0xEE2C,0xDA,0x01}, // +{0xEE2D,0x50,0x01}, // +{0xEE2E,0x80,0x01}, // +{0xEE2F,0x2A,0x01}, // +{0xEE30,0xB4,0x01}, // +{0xEE31,0x1D,0x01}, // +{0xEE32,0xF7,0x01}, // +{0xEE33,0x14,0x01}, // +{0xEE34,0xE7,0x01}, // +{0xEE35,0x3A,0x01}, // +{0xEE36,0xBA,0x01}, // +{0xEE37,0x49,0x01}, // +{0xEE38,0xCE,0x01}, // +{0xEE39,0x70,0x01}, // +{0xEE3A,0xA2,0x01}, // +{0xEE3B,0x43,0x01}, // +{0xEE3C,0x1D,0x01}, // +{0xEE3D,0xF4,0x01}, // +{0xEE3E,0xD4,0x01}, // +{0xEE3F,0x47,0x01}, // +{0xEE40,0x41,0x01}, // +{0xEE41,0xFE,0x01}, // +{0xEE42,0x89,0x01}, // +{0xEE43,0x10,0x01}, // +{0xEE44,0x83,0x01}, // +{0xEE45,0x38,0x01}, // +{0xEE46,0xF4,0x01}, // +{0xEE47,0x1E,0x01}, // +{0xEE48,0x00,0x01}, // +{0xEE49,0x1D,0x01}, // +{0xEE4A,0xA7,0x01}, // +{0xEE4B,0x3A,0x01}, // +{0xEE4C,0xB1,0x01}, // +{0xEE4D,0xE9,0x01}, // +{0xEE4E,0xCD,0x01}, // +{0xEE4F,0x69,0x01}, // +{0xEE50,0x60,0x01}, // +{0xEE51,0x03,0x01}, // +{0xEE52,0x9B,0x01}, // +{0xEE53,0xDC,0x01}, // +{0xEE54,0x04,0x01}, // +{0xEE55,0xC7,0x01}, // +{0xEE56,0x39,0x01}, // +{0xEE57,0xE5,0x01}, // +{0xEE58,0x99,0x01}, // +{0xEE59,0x4F,0x01}, // +{0xEE5A,0x7F,0x01}, // +{0xEE5B,0x16,0x01}, // +{0xEE5C,0xB4,0x01}, // +{0xEE5D,0x1C,0x01}, // +{0xEE5E,0xED,0x01}, // +{0xEE5F,0xD0,0x01}, // +{0xEE60,0x66,0x01}, // +{0xEE61,0x38,0x01}, // +{0xEE62,0x90,0x01}, // +{0xEE63,0xD9,0x01}, // +{0xEE64,0xCC,0x01}, // +{0xEE65,0x5C,0x01}, // +{0xEE66,0xF6,0x01}, // +{0xEE67,0xC2,0x01}, // +{0xEE68,0x96,0x01}, // +{0xEE69,0xB8,0x01}, // +{0xEE6A,0xC4,0x01}, // +{0xEE6B,0xE5,0x01}, // +{0xEE6C,0x2E,0x01}, // +{0xEE6D,0x8C,0x01}, // +{0xEE6E,0xA1,0x01}, // +{0xEE6F,0xCC,0x01}, // +{0xEE70,0x6B,0x01}, // +{0xEE71,0x72,0x01}, // +{0xEE72,0x03,0x01}, // +{0xEE73,0x9C,0x01}, // +{0xEE74,0xE5,0x01}, // +{0xEE75,0x90,0x01}, // +{0xEE76,0x26,0x01}, // +{0xEE77,0x36,0x01}, // +{0xEE78,0x87,0x01}, // +{0xEE79,0x99,0x01}, // +{0xEE7A,0x0C,0x01}, // +{0xEE7B,0x57,0x01}, // +{0xEE7C,0xC8,0x01}, // +{0xEE7D,0x02,0x01}, // +{0xEE7E,0x14,0x01}, // +{0xEE7F,0xA2,0x01}, // +{0xEE80,0xDC,0x01}, // +{0xEE81,0x24,0x01}, // +{0xEE82,0x27,0x01}, // +{0xEE83,0x3F,0x01}, // +{0xEE84,0x01,0x01}, // +{0xEE85,0x8A,0x01}, // +{0xEE86,0x56,0x01}, // +{0xEE87,0xBC,0x01}, // +{0xEE88,0x12,0x01}, // +{0xEE89,0x18,0x01}, // +{0xEE8A,0xC4,0x01}, // +{0xEE8B,0x5C,0x01}, // +{0xEE8C,0x26,0x01}, // +{0xEE8D,0x34,0x01}, // +{0xEE8E,0x87,0x01}, // +{0xEE8F,0x91,0x01}, // +{0xEE90,0xCC,0x01}, // +{0xEE91,0x5A,0x01}, // +{0xEE92,0xE8,0x01}, // +{0xEE93,0xA2,0x01}, // +{0xEE94,0x13,0x01}, // +{0xEE95,0xA0,0x01}, // +{0xEE96,0x70,0x01}, // +{0xEE97,0xC4,0x01}, // +{0xEE98,0x23,0x01}, // +{0xEE99,0x10,0x01}, // +{0xEE9A,0x89,0x01}, // +{0xEE9B,0x08,0x01}, // +{0xEE9C,0x47,0x01}, // +{0xEE9D,0x34,0x01}, // +{0xEE9E,0x72,0x01}, // +{0xEE9F,0x93,0x01}, // +{0xEEA0,0x9C,0x01}, // +{0xEEA1,0x8C,0x01}, // +{0xEEA2,0x25,0x01}, // +{0xEEA3,0x2D,0x01}, // +{0xEEA4,0x7B,0x01}, // +{0xEEA5,0x29,0x01}, // +{0xEEA6,0x4C,0x01}, // +{0xEEA7,0x60,0x01}, // +{0xEEA8,0x12,0x01}, // +{0xEEA9,0xE3,0x01}, // +{0xEEAA,0x95,0x01}, // +{0xEEAB,0xB1,0x01}, // +{0xEEAC,0xA4,0x01}, // +{0xEEAD,0x84,0x01}, // +{0xEEAE,0x25,0x01}, // +{0xEEAF,0x0A,0x01}, // +{0xEEB0,0x61,0x01}, // +{0xEEB1,0x08,0x01}, // +{0xEEB2,0x40,0x01}, // +{0xEEB3,0x00,0x01}, // +{0xEEB4,0xB2,0x01}, // +{0xEEB5,0x90,0x01}, // +{0xEEB6,0x84,0x01}, // +{0xEEB7,0x94,0x01}, // +{0xEEB8,0x84,0x01}, // +{0xEEB9,0x24,0x01}, // +{0xEEBA,0x53,0x01}, // +{0xEEBB,0xB1,0x01}, // +{0xEEBC,0x0A,0x01}, // +{0xEEBD,0x5C,0x01}, // +{0xEEBE,0xF0,0x01}, // +{0xEEBF,0x52,0x01}, // +{0xEEC0,0x98,0x01}, // +{0xEEC1,0xC5,0x01}, // +{0xEEC2,0x84,0x01}, // +{0xEEC3,0xC5,0x01}, // +{0xEEC4,0x2C,0x01}, // +{0xEEC5,0x2D,0x01}, // +{0xEEC6,0x79,0x01}, // +{0xEEC7,0x89,0x01}, // +{0xEEC8,0x43,0x01}, // +{0xEEC9,0x1C,0x01}, // +{0xEECA,0x32,0x01}, // +{0xEECB,0x10,0x01}, // +{0xEECC,0x81,0x01}, // +{0xEECD,0x30,0x01}, // +{0xEECE,0x64,0x01}, // +{0xEECF,0x21,0x01}, // +{0xEED0,0x27,0x01}, // +{0xEED1,0x31,0x01}, // +{0xEED2,0x09,0x01}, // +{0xEED3,0x55,0x01}, // +{0xEED4,0xAE,0x01}, // +{0xEED5,0x22,0x01}, // +{0xEED6,0x17,0x01}, // +{0xEED7,0xBD,0x01}, // +{0xEED8,0x50,0x01}, // +{0xEED9,0x26,0x01}, // +{0xEEDA,0x33,0x01}, // +{0xEEDB,0x78,0x01}, // +{0xEEDC,0xD9,0x01}, // +{0xEEDD,0x8B,0x01}, // +{0xEEDE,0x51,0x01}, // +{0xEEDF,0x8E,0x01}, // +{0xEEE0,0x62,0x01}, // +{0xEEE1,0x12,0x01}, // +{0xEEE2,0x93,0x01}, // +{0xEEE3,0x64,0x01}, // +{0xEEE4,0x24,0x01}, // +{0xEEE5,0x23,0x01}, // +{0xEEE6,0x22,0x01}, // +{0xEEE7,0x11,0x01}, // +{0xEEE8,0x89,0x01}, // +{0xEEE9,0x4F,0x01}, // +{0xEEEA,0x7E,0x01}, // +{0xEEEB,0x92,0x01}, // +{0xEEEC,0x96,0x01}, // +{0xEEED,0xB7,0x01}, // +{0xEEEE,0x00,0x01}, // +{0xEEEF,0x46,0x01}, // +{0xEEF0,0x31,0x01}, // +{0xEEF1,0xB8,0x01}, // +{0xEEF2,0xC9,0x01}, // +{0xEEF3,0x0D,0x01}, // +{0xEEF4,0x67,0x01}, // +{0xEEF5,0x38,0x01}, // +{0xEEF6,0x13,0x01}, // +{0xEEF7,0x97,0x01}, // +{0xEEF8,0xB7,0x01}, // +{0xEEF9,0x48,0x01}, // +{0xEEFA,0x25,0x01}, // +{0xEEFB,0x2A,0x01}, // +{0xEEFC,0x47,0x01}, // +{0xEEFD,0x31,0x01}, // +{0xEEFE,0x0A,0x01}, // +{0xEEFF,0x53,0x01}, // +{0xEF00,0x9A,0x01}, // +{0xEF01,0x22,0x01}, // +{0xEF02,0x16,0x01}, // +{0xEF03,0xB4,0x01}, // +{0xEF04,0x1C,0x01}, // +{0xEF05,0x26,0x01}, // +{0xEF06,0x32,0x01}, // +{0xEF07,0x9D,0x01}, // +{0xEF08,0x61,0x01}, // +{0xEF09,0xCD,0x01}, // +{0xEF0A,0x79,0x01}, // +{0xEF0B,0xCE,0x01}, // +{0xEF0C,0xE3,0x01}, // +{0xEF0D,0x9C,0x01}, // +{0xEF0E,0xE7,0x01}, // +{0xEF0F,0x9C,0x01}, // +{0xEF10,0x06,0x01}, // +{0xEF11,0x35,0x01}, // +{0xEF12,0x8B,0x01}, // +{0xEF13,0x61,0x01}, // +{0xEF14,0x4C,0x01}, // +{0xEF15,0x60,0x01}, // +{0xEF16,0x04,0x01}, // +{0xEF17,0x23,0x01}, // +{0xEF18,0x18,0x01}, // +{0xEF19,0xC4,0x01}, // +{0xEF1A,0x5C,0x01}, // +{0xEF1B,0x46,0x01}, // +{0xEF1C,0x34,0x01}, // +{0xEF1D,0xB7,0x01}, // +{0xEF1E,0x31,0x01}, // +{0xEF1F,0x0E,0x01}, // +{0xEF20,0x72,0x01}, // +{0xEF21,0xB4,0x01}, // +{0xEF22,0x73,0x01}, // +{0xEF23,0xA2,0x01}, // +{0xEF24,0x15,0x01}, // +{0xEF25,0x41,0x01}, // +{0xEF26,0x88,0x01}, // +{0xEF27,0x42,0x01}, // +{0xEF28,0xE6,0x01}, // +{0xEF29,0x59,0x01}, // +{0xEF2A,0x0F,0x01}, // +{0xEF2B,0x73,0x01}, // +{0xEF2C,0xA4,0x01}, // +{0xEF2D,0xD3,0x01}, // +{0xEF2E,0x9B,0x01}, // +{0xEF2F,0xE2,0x01}, // +{0xEF30,0x08,0x01}, // +{0xEF31,0xC7,0x01}, // +{0xEF32,0x39,0x01}, // +{0xEF33,0xD4,0x01}, // +{0xEF34,0x19,0x01}, // +{0xEF35,0x0F,0x01}, // +{0xEF36,0x7E,0x01}, // +{0xEF37,0x18,0x01}, // +{0xEF38,0xA4,0x01}, // +{0xEF39,0x20,0x01}, // +{0xEF3A,0x10,0x01}, // +{0xEF3B,0x89,0x01}, // +{0xEF3C,0xA8,0x01}, // +{0xEF3D,0x44,0x01}, // +{0xEF3E,0x25,0x01}, // +{0xEF3F,0x52,0x01}, // +{0xEF40,0x11,0x01}, // +{0xEF41,0x81,0x01}, // +{0xEF42,0x16,0x01}, // +{0xEF43,0xB4,0x01}, // +{0xEF44,0x9E,0x01}, // +{0xEF45,0xF8,0x01}, // +{0xEF46,0x64,0x01}, // +{0xEF47,0x67,0x01}, // +{0xEF48,0x3C,0x01}, // +{0xEF49,0xDF,0x01}, // +{0xEF4A,0x61,0x01}, // +{0xEF4B,0x8F,0x01}, // +{0xEF4C,0x7C,0x01}, // +{0xEF4D,0x04,0x01}, // +{0xEF4E,0xF4,0x01}, // +{0xEF4F,0x20,0x01}, // +{0xEF50,0x11,0x01}, // +{0xEF51,0x35,0x01}, // +{0xEF52,0x88,0x01}, // +{0xEF53,0x43,0x01}, // +{0xEF54,0x2E,0x01}, // +{0xEF55,0x5A,0x01}, // +{0xEF56,0x11,0x01}, // +{0xEF57,0x82,0x01}, // +{0xEF58,0xCE,0x01}, // +{0xEF59,0x93,0x01}, // +{0xEF5A,0x9D,0x01}, // +{0xEF5B,0xF1,0x01}, // +{0xEF5C,0xF0,0x01}, // +{0xEF5D,0x47,0x01}, // +{0xEF5E,0x44,0x01}, // +{0xEF5F,0x28,0x01}, // +{0xEF60,0xAA,0x01}, // +{0xEF61,0x51,0x01}, // +{0xEF62,0x86,0x01}, // +{0xEF63,0xDA,0x01}, // +{0xEF64,0xD3,0x01}, // +{0xEF65,0x1C,0x01}, // +{0xEF66,0xE0,0x01}, // +{0xEF67,0x24,0x01}, // +{0xEF68,0x87,0x01}, // +{0xEF69,0x3C,0x01}, // +{0xEF6A,0x11,0x01}, // +{0xEF6B,0x52,0x01}, // +{0xEF6C,0xD1,0x01}, // +{0xEF6D,0x7B,0x01}, // +{0xEF6E,0xA6,0x01}, // +{0xEF6F,0x63,0x01}, // +{0xEF70,0x9A,0x01}, // +{0xEF71,0xC0,0x01}, // +{0xEF72,0xD4,0x01}, // +{0xEF73,0x65,0x01}, // +{0xEF74,0x2F,0x01}, // +{0xEF75,0x9F,0x01}, // +{0xEF76,0x69,0x01}, // +{0xEF77,0x0E,0x01}, // +{0xEF78,0x79,0x01}, // +{0xEF79,0x82,0x01}, // +{0xEF7A,0xC3,0x01}, // +{0xEF7B,0x99,0x01}, // +{0xEF7C,0xB3,0x01}, // +{0xEF7D,0x0C,0x01}, // +{0xEF7E,0xE5,0x01}, // +{0xEF7F,0x26,0x01}, // +{0xEF80,0x3E,0x01}, // +{0xEF81,0xF9,0x01}, // +{0xEF82,0x0A,0x01}, // +{0xEF83,0x65,0x01}, // +{0xEF84,0x6C,0x01}, // +{0xEF85,0xE3,0x01}, // +{0xEF86,0x19,0x01}, // +{0xEF87,0xBD,0x01}, // +{0xEF88,0xFC,0x01}, // +{0xEF89,0x84,0x01}, // +{0xEF8A,0x23,0x01}, // +{0xEF8B,0x0E,0x01}, // +{0xEF8C,0xC9,0x01}, // +{0xEF8D,0x08,0x01}, // +{0xEF8E,0x4E,0x01}, // +{0xEF8F,0xE0,0x01}, // +{0xEF90,0x12,0x01}, // +{0xEF91,0x99,0x01}, // +{0xEF92,0xC9,0x01}, // +{0xEF93,0x9C,0x01}, // +{0xEF94,0x85,0x01}, // +{0xEF95,0x25,0x01}, // +{0xEF96,0x0C,0x01}, // +{0xEF97,0x01,0x01}, // +{0xEF98,0x48,0x01}, // +{0xEF99,0x42,0x01}, // +{0xEF9A,0x4C,0x01}, // +{0xEF9B,0xD2,0x01}, // +{0xEF9C,0x15,0x01}, // +{0xEF9D,0xC2,0x01}, // +{0xEF9E,0x5C,0x01}, // +{0xEF9F,0x86,0x01}, // +{0xEFA0,0x2D,0x01}, // +{0xEFA1,0x31,0x01}, // +{0xEFA2,0x79,0x01}, // +{0xEFA3,0xC8,0x01}, // +{0xEFA4,0x40,0x01}, // +{0xEFA5,0x1A,0x01}, // +{0xEFA6,0xA2,0x01}, // +{0xEFA7,0x12,0x01}, // +{0xEFA8,0xB0,0x01}, // +{0xEFA9,0x1C,0x01}, // +{0xEFAA,0x86,0x01}, // +{0xEFAB,0x35,0x01}, // +{0xEFAC,0x87,0x01}, // +{0xEFAD,0x61,0x01}, // +{0xEFAE,0x0A,0x01}, // +{0xEFAF,0x4A,0x01}, // +{0xEFB0,0x36,0x01}, // +{0xEFB1,0x52,0x01}, // +{0xEFB2,0x92,0x01}, // +{0xEFB3,0xA2,0x01}, // +{0xEFB4,0xF0,0x01}, // +{0xEFB5,0x85,0x01}, // +{0xEFB6,0x33,0x01}, // +{0xEFB7,0xD7,0x01}, // +{0xEFB8,0x91,0x01}, // +{0xEFB9,0x0D,0x01}, // +{0xEFBA,0x5F,0x01}, // +{0xEFBB,0xB2,0x01}, // +{0xEFBC,0xD2,0x01}, // +{0xEFBD,0x94,0x01}, // +{0xEFBE,0xAA,0x01}, // +{0xEFBF,0xD4,0x01}, // +{0xEFC0,0xC5,0x01}, // +{0xEFC1,0x34,0x01}, // +{0xEFC2,0xC5,0x01}, // +{0xEFC3,0x71,0x01}, // +{0xEFC4,0xD0,0x01}, // +{0xEFC5,0x7B,0x01}, // +{0xEFC6,0x80,0x01}, // +{0xEFC7,0xD3,0x01}, // +{0xEFC8,0x19,0x01}, // +{0xEFC9,0xC9,0x01}, // +{0xEFCA,0x60,0x01}, // +{0xEFCB,0x46,0x01}, // +{0xEFCC,0x37,0x01}, // +{0xEFCD,0xE4,0x01}, // +{0xEFCE,0xD9,0x01}, // +{0xEFCF,0x4F,0x01}, // +{0xEFD0,0x95,0x01}, // +{0xEFD1,0x7A,0x01}, // +{0xEFD2,0xE4,0x01}, // +{0xEFD3,0xA0,0x01}, // +{0xEFD4,0xF9,0x01}, // +{0xEFD5,0x90,0x01}, // +{0xEFD6,0xA7,0x01}, // +{0xEFD7,0x3D,0x01}, // +{0xEFD8,0x07,0x01}, // +{0xEFD9,0x92,0x01}, // +{0xEFDA,0x11,0x01}, // +{0xEFDB,0x91,0x01}, // +{0xEFDC,0x92,0x01}, // +{0xEFDD,0x04,0x01}, // +{0xEFDE,0xA5,0x01}, // +{0xEFDF,0x19,0x01}, // +{0xEFE0,0x69,0x01}, // +{0xEFE1,0x28,0x01}, // +{0xEFE2,0x41,0x01}, // +{0xEFE3,0x11,0x01}, // +{0xEFE4,0x5A,0x01}, // +{0xEFE5,0xD1,0x01}, // +{0xEFE6,0x91,0x01}, // +{0xEFE7,0x80,0x01}, // +{0xEFE8,0x04,0x01}, // +{0xEFE9,0x69,0x01}, // +{0xEFEA,0x00,0x01}, // +{0xEFEB,0x00,0x01}, // +{0xEFEC,0x19,0x01}, // +{0xEFED,0x26,0x01}, // +{0x6C32,0x1478,0x02}, // SHD_INP_TH_HB_H_R2 +{0x6C34,0x13B0,0x02}, // SHD_INP_TH_HB_L_R2 +{0x6C36,0x10CC,0x02}, // SHD_INP_TH_LB_H_R2 +{0x6C38,0x1004,0x02}, // SHD_INP_TH_LB_L_R2 +{0x6C3C,0x0000,0x02}, // SHD_INP_TH_HB_H_RB +{0x6C3E,0x0000,0x02}, // SHD_INP_TH_HB_L_RB +{0x6C40,0x0000,0x02}, // SHD_INP_TH_LB_H_RB +{0x6C42,0x0000,0x02}, // SHD_INP_TH_LB_L_RB + +{0x6804,0x11DA,0x02}, // NORMR +{0x6806,0x10AB,0x02}, // NORMB +{0x6808,0x0147,0x02}, // AWBPRER +{0x680A,0x0226,0x02}, // AWBPREB +{0x6810,0x10A8,0x02}, // AWB_PRE_ADJ_RG +{0x6812,0x0F8F,0x02}, // AWB_PRE_ADJ_BG +{0x6814,0x0AD9,0x02}, // AWB_C14_RG +{0x6816,0x1701,0x02}, // AWB_C14_BG + +//PreWB_offset +{0x6828,0x0013,0x02}, // SHD_PRER_OFFSET_R2 : + +// CXC/SHD EN +{0x01BC,0x57,0x01}, // CXC ON SHD ON INP ON GAIN OFF +}; + +isx012_short_t isx012_movie_mode_off[] = +{ + +//SN +{0x0308,0x00,0x01}, // AELINE_MONI_SN1_2 : +{0x0320,0x22,0x01}, // AELINE_MONI_SN1_2 : +{0x00B2,0x03,0x01}, // AFMODE_MONI : + +//AE speed +{0x02AC,0x01,0x01}, // AE_SUB_SN1 : +{0x5E2D,0x08,0x01}, // AEMOVECNT : +{0x5E2E,0x1A,0x01}, // AEINDEADBAND : +{0x5E2F,0x04,0x01}, // AEOUTDEADBAND : +{0x5E30,0x20,0x01}, // AESPEED : + +{0x5E31,0x0F,0x01}, // AESPEED_INIT : +{0x5E32,0x0F,0x01}, // AESPEED_FAST : + +{0x621E,0x20,0x01}, // AIM_NR_TH_UP : +{0x621F,0x20,0x01}, // AIM_NR_TH_DOWN : +{0x6220,0x20,0x01}, // AIM_NR_TH_RIGHT : +{0x6221,0x20,0x01}, // AIM_NR_TH_LEFT : + +//AWB κ +{0x6222,0x00,0x01}, // INIT_AIMW : +{0x6223,0x04,0x01}, // INIT_GAINS : +{0x6224,0x10,0x01}, // ATW_DELAY : +{0x6225,0x00,0x01}, // ATW_AIMW : + +{0x6226,0x02,0x01}, // ATW_GAINS_IN_NR : +{0x6227,0x02,0x01}, // ATW_GAINS_IN : +{0x6228,0x02,0x01}, // ATW_GAINS_OUT_NR : +{0x6229,0x02,0x01}, // ATW_GAINS_OUT : +{0x622A,0x02,0x01}, // ALLWB_GAINS : + +{0x6400,0xAA,0x01}, // INFRM_LEFT00 : +{0x6401,0xAA,0x01}, // INFRM_LEFT01 : +{0x6402,0xAA,0x01}, // INFRM_LEFT02 : +{0x6403,0xAA,0x01}, // INFRM_LEFT03 : +{0x6404,0xAA,0x01}, // INFRM_LEFT04 : +{0x6405,0xAA,0x01}, // INFRM_LEFT05 : +{0x6406,0xAA,0x01}, // INFRM_LEFT06 : +{0x6407,0xAA,0x01}, // INFRM_LEFT07 : +{0x6408,0xAA,0x01}, // INFRM_LEFT08 : +{0x6409,0xAE,0x01}, // INFRM_LEFT09 : +{0x640A,0xA0,0x01}, // INFRM_LEFT10 : +{0x640B,0x8C,0x01}, // INFRM_LEFT11 : +{0x640C,0x72,0x01}, // INFRM_LEFT12 : +{0x640D,0x64,0x01}, // INFRM_LEFT13 : +{0x640E,0x5A,0x01}, // INFRM_LEFT14 : +{0x640F,0x52,0x01}, // INFRM_LEFT15 : +{0x6410,0x4B,0x01}, // INFRM_LEFT16 : +{0x6411,0x46,0x01}, // INFRM_LEFT17 : +{0x6412,0x40,0x01}, // INFRM_LEFT18 : +{0x6413,0x3A,0x01}, // INFRM_LEFT19 : +{0x6414,0x36,0x01}, // INFRM_LEFT20 : +{0x6415,0x34,0x01}, // INFRM_LEFT21 : +{0x6416,0x33,0x01}, // INFRM_LEFT22 : +{0x6417,0x32,0x01}, // INFRM_LEFT23 : +{0x6418,0x31,0x01}, // INFRM_LEFT24 : +{0x6419,0x2F,0x01}, // INFRM_LEFT25 : +{0x641A,0x2D,0x01}, // INFRM_LEFT26 : +{0x641B,0x2A,0x01}, // INFRM_LEFT27 : +{0x641C,0x28,0x01}, // INFRM_LEFT28 : +{0x641D,0x26,0x01}, // INFRM_LEFT29 : +{0x641E,0x23,0x01}, // INFRM_LEFT30 : +{0x641F,0x20,0x01}, // INFRM_LEFT31 : +{0x6420,0x1D,0x01}, // INFRM_LEFT32 : +{0x6421,0x1A,0x01}, // INFRM_LEFT33 : +{0x6422,0x18,0x01}, // INFRM_LEFT34 : +{0x6423,0x17,0x01}, // INFRM_LEFT35 : +{0x6424,0x16,0x01}, // INFRM_LEFT36 : +{0x6425,0x17,0x01}, // INFRM_LEFT37 : +{0x6426,0xAF,0x01}, // INFRM_RIGHT00 : +{0x6427,0xAF,0x01}, // INFRM_RIGHT01 : +{0x6428,0xAF,0x01}, // INFRM_RIGHT02 : +{0x6429,0xAF,0x01}, // INFRM_RIGHT03 : +{0x642A,0xAF,0x01}, // INFRM_RIGHT04 : +{0x642B,0xAF,0x01}, // INFRM_RIGHT05 : +{0x642C,0xAF,0x01}, // INFRM_RIGHT06 : +{0x642D,0xAF,0x01}, // INFRM_RIGHT07 : +{0x642E,0xAF,0x01}, // INFRM_RIGHT08 : +{0x642F,0xAA,0x01}, // INFRM_RIGHT09 : +{0x6430,0xB2,0x01}, // INFRM_RIGHT10 : +{0x6431,0xB4,0x01}, // INFRM_RIGHT11 : +{0x6432,0xB6,0x01}, // INFRM_RIGHT12 : +{0x6433,0xB4,0x01}, // INFRM_RIGHT13 : +{0x6434,0x9B,0x01}, // INFRM_RIGHT14 : +{0x6435,0x82,0x01}, // INFRM_RIGHT15 : +{0x6436,0x78,0x01}, // INFRM_RIGHT16 : +{0x6437,0x72,0x01}, // INFRM_RIGHT17 : +{0x6438,0x6C,0x01}, // INFRM_RIGHT18 : +{0x6439,0x67,0x01}, // INFRM_RIGHT19 : +{0x643A,0x63,0x01}, // INFRM_RIGHT20 : +{0x643B,0x5E,0x01}, // INFRM_RIGHT21 : +{0x643C,0x58,0x01}, // INFRM_RIGHT22 : +{0x643D,0x53,0x01}, // INFRM_RIGHT23 : +{0x643E,0x4E,0x01}, // INFRM_RIGHT24 : +{0x643F,0x4A,0x01}, // INFRM_RIGHT25 : +{0x6440,0x46,0x01}, // INFRM_RIGHT26 : +{0x6441,0x42,0x01}, // INFRM_RIGHT27 : +{0x6442,0x3F,0x01}, // INFRM_RIGHT28 : +{0x6443,0x3C,0x01}, // INFRM_RIGHT29 : +{0x6444,0x3A,0x01}, // INFRM_RIGHT30 : +{0x6445,0x38,0x01}, // INFRM_RIGHT31 : +{0x6446,0x37,0x01}, // INFRM_RIGHT32 : +{0x6447,0x2E,0x01}, // INFRM_RIGHT33 : +{0x6448,0x2D,0x01}, // INFRM_RIGHT34 : +{0x6449,0x2C,0x01}, // INFRM_RIGHT35 : +{0x644A,0x2C,0x01}, // INFRM_RIGHT36 : +{0x644B,0x36,0x01}, // INFRM_RIGHT37 : +{0x644C,0x232F,0x02}, // INFRM_TOP : +{0x644E,0x0940,0x02}, // INFRM_BOTM : +{0x6450,0x19,0x01}, // INFRM_FLTOP : +{0x6451,0x10,0x01}, // INFRM_FLBOTM : +{0x6452,0x91,0x01}, // INAIM_LEFT00 : +{0x6453,0x91,0x01}, // INAIM_LEFT01 : +{0x6454,0x91,0x01}, // INAIM_LEFT02 : +{0x6455,0x91,0x01}, // INAIM_LEFT03 : +{0x6456,0x91,0x01}, // INAIM_LEFT04 : +{0x6457,0x91,0x01}, // INAIM_LEFT05 : +{0x6458,0x91,0x01}, // INAIM_LEFT06 : +{0x6459,0x91,0x01}, // INAIM_LEFT07 : +{0x645A,0x91,0x01}, // INAIM_LEFT08 : +{0x645B,0x91,0x01}, // INAIM_LEFT09 : +{0x645C,0x91,0x01}, // INAIM_LEFT10 : +{0x645D,0x91,0x01}, // INAIM_LEFT11 : +{0x645E,0x91,0x01}, // INAIM_LEFT12 : +{0x645F,0x66,0x01}, // INAIM_LEFT13 : +{0x6460,0x5D,0x01}, // INAIM_LEFT14 : +{0x6461,0x55,0x01}, // INAIM_LEFT15 : +{0x6462,0x4E,0x01}, // INAIM_LEFT16 : +{0x6463,0x47,0x01}, // INAIM_LEFT17 : +{0x6464,0x42,0x01}, // INAIM_LEFT18 : +{0x6465,0x3C,0x01}, // INAIM_LEFT19 : +{0x6466,0x38,0x01}, // INAIM_LEFT20 : +{0x6467,0x36,0x01}, // INAIM_LEFT21 : +{0x6468,0x35,0x01}, // INAIM_LEFT22 : +{0x6469,0x33,0x01}, // INAIM_LEFT23 : +{0x646A,0x32,0x01}, // INAIM_LEFT24 : +{0x646B,0x30,0x01}, // INAIM_LEFT25 : +{0x646C,0x2F,0x01}, // INAIM_LEFT26 : +{0x646D,0x2D,0x01}, // INAIM_LEFT27 : +{0x646E,0x2C,0x01}, // INAIM_LEFT28 : +{0x646F,0x2B,0x01}, // INAIM_LEFT29 : +{0x6470,0x2A,0x01}, // INAIM_LEFT30 : +{0x6471,0x28,0x01}, // INAIM_LEFT31 : +{0x6472,0x26,0x01}, // INAIM_LEFT32 : +{0x6473,0x24,0x01}, // INAIM_LEFT33 : +{0x6474,0x29,0x01}, // INAIM_LEFT34 : +{0x6475,0x28,0x01}, // INAIM_LEFT35 : +{0x6476,0x29,0x01}, // INAIM_LEFT36 : +{0x6477,0x26,0x01}, // INAIM_LEFT37 : +{0x6478,0xFF,0x01}, // INAIM_RIGHT00 : +{0x6479,0xFF,0x01}, // INAIM_RIGHT01 : +{0x647A,0xFF,0x01}, // INAIM_RIGHT02 : +{0x647B,0xFF,0x01}, // INAIM_RIGHT03 : +{0x647C,0xFF,0x01}, // INAIM_RIGHT04 : +{0x647D,0xFF,0x01}, // INAIM_RIGHT05 : +{0x647E,0xFF,0x01}, // INAIM_RIGHT06 : +{0x647F,0xFF,0x01}, // INAIM_RIGHT07 : +{0x6480,0xFF,0x01}, // INAIM_RIGHT08 : +{0x6481,0xFF,0x01}, // INAIM_RIGHT09 : +{0x6482,0xD9,0x01}, // INAIM_RIGHT10 : +{0x6483,0xB7,0x01}, // INAIM_RIGHT11 : +{0x6484,0x96,0x01}, // INAIM_RIGHT12 : +{0x6485,0x68,0x01}, // INAIM_RIGHT13 : +{0x6486,0x70,0x01}, // INAIM_RIGHT14 : +{0x6487,0x72,0x01}, // INAIM_RIGHT15 : +{0x6488,0x71,0x01}, // INAIM_RIGHT16 : +{0x6489,0x6B,0x01}, // INAIM_RIGHT17 : +{0x648A,0x65,0x01}, // INAIM_RIGHT18 : +{0x648B,0x60,0x01}, // INAIM_RIGHT19 : +{0x648C,0x5B,0x01}, // INAIM_RIGHT20 : +{0x648D,0x56,0x01}, // INAIM_RIGHT21 : +{0x648E,0x51,0x01}, // INAIM_RIGHT22 : +{0x648F,0x4C,0x01}, // INAIM_RIGHT23 : +{0x6490,0x47,0x01}, // INAIM_RIGHT24 : +{0x6491,0x44,0x01}, // INAIM_RIGHT25 : +{0x6492,0x41,0x01}, // INAIM_RIGHT26 : +{0x6493,0x3E,0x01}, // INAIM_RIGHT27 : +{0x6494,0x3B,0x01}, // INAIM_RIGHT28 : +{0x6495,0x39,0x01}, // INAIM_RIGHT29 : +{0x6496,0x37,0x01}, // INAIM_RIGHT30 : +{0x6497,0x34,0x01}, // INAIM_RIGHT31 : +{0x6498,0x33,0x01}, // INAIM_RIGHT32 : +{0x6499,0x32,0x01}, // INAIM_RIGHT33 : +{0x649A,0x31,0x01}, // INAIM_RIGHT34 : +{0x649B,0x30,0x01}, // INAIM_RIGHT35 : +{0x649C,0x2F,0x01}, // INAIM_RIGHT36 : +{0x649D,0x2E,0x01}, // INAIM_RIGHT37 : +{0x649E,0x1E00,0x02}, // INAIM_TOP : +{0x64A0,0x0D90,0x02}, // INAIM_BOTM : +{0x64A2,0x18,0x01}, // INAIM_FLTOP : +{0x64A3,0x10,0x01}, // INAIM_FLBOTM : +{0x64A4,0xFF,0x01}, // OUTFRM_LEFT00 : +{0x64A5,0xFF,0x01}, // OUTFRM_LEFT01 : +{0x64A6,0xFF,0x01}, // OUTFRM_LEFT02 : +{0x64A7,0xFF,0x01}, // OUTFRM_LEFT03 : +{0x64A8,0xFF,0x01}, // OUTFRM_LEFT04 : +{0x64A9,0xFF,0x01}, // OUTFRM_LEFT05 : +{0x64AA,0xFF,0x01}, // OUTFRM_LEFT06 : +{0x64AB,0xFF,0x01}, // OUTFRM_LEFT07 : +{0x64AC,0xFF,0x01}, // OUTFRM_LEFT08 : +{0x64AD,0xFD,0x01}, // OUTFRM_LEFT09 : +{0x64AE,0xCB,0x01}, // OUTFRM_LEFT10 : +{0x64AF,0xA9,0x01}, // OUTFRM_LEFT11 : +{0x64B0,0x90,0x01}, // OUTFRM_LEFT12 : +{0x64B1,0x7D,0x01}, // OUTFRM_LEFT13 : +{0x64B2,0x70,0x01}, // OUTFRM_LEFT14 : +{0x64B3,0x65,0x01}, // OUTFRM_LEFT15 : +{0x64B4,0x5C,0x01}, // OUTFRM_LEFT16 : +{0x64B5,0x55,0x01}, // OUTFRM_LEFT17 : +{0x64B6,0x4F,0x01}, // OUTFRM_LEFT18 : +{0x64B7,0x32,0x01}, // OUTFRM_LEFT19 : +{0x64B8,0x4D,0x01}, // OUTFRM_LEFT20 : +{0x64B9,0x40,0x01}, // OUTFRM_LEFT21 : +{0x64BA,0x2D,0x01}, // OUTFRM_LEFT22 : +{0x64BB,0x2B,0x01}, // OUTFRM_LEFT23 : +{0x64BC,0x29,0x01}, // OUTFRM_LEFT24 : +{0x64BD,0x27,0x01}, // OUTFRM_LEFT25 : +{0x64BE,0x25,0x01}, // OUTFRM_LEFT26 : +{0x64BF,0x23,0x01}, // OUTFRM_LEFT27 : +{0x64C0,0x21,0x01}, // OUTFRM_LEFT28 : +{0x64C1,0x1F,0x01}, // OUTFRM_LEFT29 : +{0x64C2,0x1D,0x01}, // OUTFRM_LEFT30 : +{0x64C3,0x1B,0x01}, // OUTFRM_LEFT31 : +{0x64C4,0x1A,0x01}, // OUTFRM_LEFT32 : +{0x64C5,0x1A,0x01}, // OUTFRM_LEFT33 : +{0x64C6,0x1A,0x01}, // OUTFRM_LEFT34 : +{0x64C7,0x28,0x01}, // OUTFRM_LEFT35 : +{0x64C8,0x27,0x01}, // OUTFRM_LEFT36 : +{0x64C9,0x26,0x01}, // OUTFRM_LEFT37 : +{0x64CA,0xFF,0x01}, // OUTFRM_RIGHT00 : +{0x64CB,0xFF,0x01}, // OUTFRM_RIGHT01 : +{0x64CC,0xFF,0x01}, // OUTFRM_RIGHT02 : +{0x64CD,0xFF,0x01}, // OUTFRM_RIGHT03 : +{0x64CE,0xFF,0x01}, // OUTFRM_RIGHT04 : +{0x64CF,0xFF,0x01}, // OUTFRM_RIGHT05 : +{0x64D0,0xFF,0x01}, // OUTFRM_RIGHT06 : +{0x64D1,0xFF,0x01}, // OUTFRM_RIGHT07 : +{0x64D2,0xFF,0x01}, // OUTFRM_RIGHT08 : +{0x64D3,0xFF,0x01}, // OUTFRM_RIGHT09 : +{0x64D4,0xD3,0x01}, // OUTFRM_RIGHT10 : +{0x64D5,0xB1,0x01}, // OUTFRM_RIGHT11 : +{0x64D6,0x98,0x01}, // OUTFRM_RIGHT12 : +{0x64D7,0x85,0x01}, // OUTFRM_RIGHT13 : +{0x64D8,0x78,0x01}, // OUTFRM_RIGHT14 : +{0x64D9,0x6D,0x01}, // OUTFRM_RIGHT15 : +{0x64DA,0x64,0x01}, // OUTFRM_RIGHT16 : +{0x64DB,0x5D,0x01}, // OUTFRM_RIGHT17 : +{0x64DC,0x57,0x01}, // OUTFRM_RIGHT18 : +{0x64DD,0x63,0x01}, // OUTFRM_RIGHT19 : +{0x64DE,0x5E,0x01}, // OUTFRM_RIGHT20 : +{0x64DF,0x5A,0x01}, // OUTFRM_RIGHT21 : +{0x64E0,0x56,0x01}, // OUTFRM_RIGHT22 : +{0x64E1,0x52,0x01}, // OUTFRM_RIGHT23 : +{0x64E2,0x50,0x01}, // OUTFRM_RIGHT24 : +{0x64E3,0x4E,0x01}, // OUTFRM_RIGHT25 : +{0x64E4,0x4C,0x01}, // OUTFRM_RIGHT26 : +{0x64E5,0x4A,0x01}, // OUTFRM_RIGHT27 : +{0x64E6,0x48,0x01}, // OUTFRM_RIGHT28 : +{0x64E7,0x46,0x01}, // OUTFRM_RIGHT29 : +{0x64E8,0x44,0x01}, // OUTFRM_RIGHT30 : +{0x64E9,0x43,0x01}, // OUTFRM_RIGHT31 : +{0x64EA,0x42,0x01}, // OUTFRM_RIGHT32 : +{0x64EB,0x42,0x01}, // OUTFRM_RIGHT33 : +{0x64EC,0x42,0x01}, // OUTFRM_RIGHT34 : +{0x64ED,0x30,0x01}, // OUTFRM_RIGHT35 : +{0x64EE,0x2F,0x01}, // OUTFRM_RIGHT36 : +{0x64EF,0x2E,0x01}, // OUTFRM_RIGHT37 : +{0x64F0,0x1D92,0x02}, // OUTFRM_TOP : +{0x64F2,0x1400,0x02}, // OUTFRM_BOTM : +{0x64F4,0x19,0x01}, // OUTFRM_FLTOP : +{0x64F5,0x14,0x01}, // OUTFRM_FLBOTM : + + +//CAF +{0x6696,0x32,0x01}, // AF_CAF_WOBBLE_START_INTERVAL_COUNTER +{0x6668,0x0400,0x02}, // AF_AREA_HIGH_TYPE1 : + +{0x6716,0x0000,0x02}, // CAF_LVD_WOB_HBPF_VAL1 : +{0x6718,0x0000,0x02}, // CAF_LVD_WOB_HBPF_VAL2 : +{0x671A,0x0014,0x02}, // CAF_LVD_WOB_HBPF_RATE1 : +{0x671C,0x0014,0x02}, // CAF_LVD_WOB_HBPF_RATE2 : +{0x671E,0x00,0x01}, // CAF_LVD_WOB_HBPF_SHIFT : +{0x6720,0x0000,0x02}, // CAF_LVD_WOB_LBPF_VAL1 : +{0x6722,0x0000,0x02}, // CAF_LVD_WOB_LBPF_VAL2 : +{0x6724,0x0014,0x02}, // CAF_LVD_WOB_LBPF_RATE1 : +{0x6726,0x0014,0x02}, // CAF_LVD_WOB_LBPF_RATE2 : +{0x6728,0x00,0x01}, // CAF_LVD_WOB_LBPF_SHIFT : +{0x672A,0x0000,0x02}, // CAF_LVD_CLMP_HBPF_VAL1 : +{0x672C,0x0000,0x02}, // CAF_LVD_CLMP_HBPF_VAL2 : +{0x672E,0x0046,0x02}, // CAF_LVD_CLMP_HBPF_RATE1 : +{0x6730,0x0046,0x02}, // CAF_LVD_CLMP_HBPF_RATE2 : +{0x6732,0x00,0x01}, // CAF_LVD_CLMP_HBPF_SHIFT : +{0x6734,0x0000,0x02}, // CAF_LVD_CLMP_LBPF_VAL1 : +{0x6736,0x0000,0x02}, // CAF_LVD_CLMP_LBPF_VAL2 : +{0x6738,0x0046,0x02}, // CAF_LVD_CLMP_LBPF_RATE1 : +{0x673A,0x0046,0x02}, // CAF_LVD_CLMP_LBPF_RATE2 : +{0x673C,0x00,0x01}, // CAF_LVD_CLMP_LBPF_SHIFT : + +//AWB +{0x6232,0xFF,0x01}, // ATW_SFTLMT_OUT_NR +{0x6234,0xFF,0x01}, // ATW_SFTLMT_OUT + + +//preview setting +{0x0090,0x0280,0x02},//HSIZE_MONI : 640 +{0x0096,0x01E0,0x02},//VSIZE_MONI : 480 + +{0x018E,0x0000,0x02}, //VADJ_SENS_1_2 : normal + +{0x0089,0x00,0x01},//OUTFMT_MONI +{0x0083,0x01,0x01},//SENSMODE_MONI +{0x0086,0x02,0x01},//FPSTYPE_MONI + +{0x0081,0x00,0x01},//MODESEL +{0x0082,0x01,0x01},//MONI_REFRESH +}; + +isx012_short_t isx012_movie_mode_on[] = +{ +//SN +{0x0308,0x02,0x01}, // AELINE_MONI_SN1_2 : +{0x0320,0x02,0x01}, // AELINE_MONI_SN1_2 : +{0x00B2,0x01,0x01}, // AFMODE_MONI : + +//AE speed +{0x02AC,0x00,0x01}, // AE_SUB_SN1 : +{0x5E2D,0x0C,0x01}, // AEMOVECNT : +{0x5E2E,0x20,0x01}, // AEINDEADBAND : +{0x5E2F,0x08,0x01}, // AEOUTDEADBAND : +{0x5E30,0xA0,0x01}, // AESPEED : + +{0x5E31,0x0F,0x01}, // AESPEED_INIT : +{0x5E32,0x0F,0x01}, // AESPEED_FAST : + +{0x621E,0x18,0x01}, // AIM_NR_TH_UP : +{0x621F,0x18,0x01}, // AIM_NR_TH_DOWN : +{0x6220,0x18,0x01}, // AIM_NR_TH_RIGHT : +{0x6221,0x18,0x01}, // AIM_NR_TH_LEFT : + +//AWB κ +{0x6222,0x00,0x01}, // INIT_AIMW : +{0x6223,0x04,0x01}, // INIT_GAINS : +{0x6224,0x10,0x01}, // ATW_DELAY : +{0x6225,0x00,0x01}, // ATW_AIMW : + +{0x6226,0x20,0x01}, // ATW_GAINS_IN_NR : +{0x6227,0x30,0x01}, // ATW_GAINS_IN : +{0x6228,0x20,0x01}, // ATW_GAINS_OUT_NR : +{0x6229,0x30,0x01}, // ATW_GAINS_OUT : +{0x622A,0x0D,0x01}, // ALLWB_GAINS : + +{0x6400,0x00,0x01}, // INFRM_LEFT00 : +{0x6401,0x00,0x01}, // INFRM_LEFT01 : +{0x6402,0x00,0x01}, // INFRM_LEFT02 : +{0x6403,0x00,0x01}, // INFRM_LEFT03 : +{0x6404,0x00,0x01}, // INFRM_LEFT04 : +{0x6405,0x00,0x01}, // INFRM_LEFT05 : +{0x6406,0x00,0x01}, // INFRM_LEFT06 : +{0x6407,0x00,0x01}, // INFRM_LEFT07 : +{0x6408,0x00,0x01}, // INFRM_LEFT08 : +{0x6409,0x00,0x01}, // INFRM_LEFT09 : +{0x640A,0x00,0x01}, // INFRM_LEFT10 : +{0x640B,0x00,0x01}, // INFRM_LEFT11 : +{0x640C,0x00,0x01}, // INFRM_LEFT12 : +{0x640D,0x00,0x01}, // INFRM_LEFT13 : +{0x640E,0x00,0x01}, // INFRM_LEFT14 : +{0x640F,0x00,0x01}, // INFRM_LEFT15 : +{0x6410,0x00,0x01}, // INFRM_LEFT16 : +{0x6411,0x00,0x01}, // INFRM_LEFT17 : +{0x6412,0x00,0x01}, // INFRM_LEFT18 : +{0x6413,0x00,0x01}, // INFRM_LEFT19 : +{0x6414,0x00,0x01}, // INFRM_LEFT20 : +{0x6415,0x00,0x01}, // INFRM_LEFT21 : +{0x6416,0x00,0x01}, // INFRM_LEFT22 : +{0x6417,0x00,0x01}, // INFRM_LEFT23 : +{0x6418,0x00,0x01}, // INFRM_LEFT24 : +{0x6419,0x00,0x01}, // INFRM_LEFT25 : +{0x641A,0x00,0x01}, // INFRM_LEFT26 : +{0x641B,0x00,0x01}, // INFRM_LEFT27 : +{0x641C,0x00,0x01}, // INFRM_LEFT28 : +{0x641D,0x00,0x01}, // INFRM_LEFT29 : +{0x641E,0x00,0x01}, // INFRM_LEFT30 : +{0x641F,0x00,0x01}, // INFRM_LEFT31 : +{0x6420,0x00,0x01}, // INFRM_LEFT32 : +{0x6421,0x00,0x01}, // INFRM_LEFT33 : +{0x6422,0x00,0x01}, // INFRM_LEFT34 : +{0x6423,0x00,0x01}, // INFRM_LEFT35 : +{0x6424,0x00,0x01}, // INFRM_LEFT36 : +{0x6425,0x00,0x01}, // INFRM_LEFT37 : +{0x6426,0xFF,0x01}, // INFRM_RIGHT00 : +{0x6427,0xFF,0x01}, // INFRM_RIGHT01 : +{0x6428,0xFF,0x01}, // INFRM_RIGHT02 : +{0x6429,0xFF,0x01}, // INFRM_RIGHT03 : +{0x642A,0xFF,0x01}, // INFRM_RIGHT04 : +{0x642B,0xFF,0x01}, // INFRM_RIGHT05 : +{0x642C,0xFF,0x01}, // INFRM_RIGHT06 : +{0x642D,0xFF,0x01}, // INFRM_RIGHT07 : +{0x642E,0xFF,0x01}, // INFRM_RIGHT08 : +{0x642F,0xFF,0x01}, // INFRM_RIGHT09 : +{0x6430,0xFF,0x01}, // INFRM_RIGHT10 : +{0x6431,0xFF,0x01}, // INFRM_RIGHT11 : +{0x6432,0xFF,0x01}, // INFRM_RIGHT12 : +{0x6433,0xFF,0x01}, // INFRM_RIGHT13 : +{0x6434,0xFF,0x01}, // INFRM_RIGHT14 : +{0x6435,0xFF,0x01}, // INFRM_RIGHT15 : +{0x6436,0xFF,0x01}, // INFRM_RIGHT16 : +{0x6437,0xFF,0x01}, // INFRM_RIGHT17 : +{0x6438,0xFF,0x01}, // INFRM_RIGHT18 : +{0x6439,0xFF,0x01}, // INFRM_RIGHT19 : +{0x643A,0xFF,0x01}, // INFRM_RIGHT20 : +{0x643B,0xFF,0x01}, // INFRM_RIGHT21 : +{0x643C,0xFF,0x01}, // INFRM_RIGHT22 : +{0x643D,0xFF,0x01}, // INFRM_RIGHT23 : +{0x643E,0xFF,0x01}, // INFRM_RIGHT24 : +{0x643F,0xFF,0x01}, // INFRM_RIGHT25 : +{0x6440,0xFF,0x01}, // INFRM_RIGHT26 : +{0x6441,0xFF,0x01}, // INFRM_RIGHT27 : +{0x6442,0xFF,0x01}, // INFRM_RIGHT28 : +{0x6443,0xFF,0x01}, // INFRM_RIGHT29 : +{0x6444,0xFF,0x01}, // INFRM_RIGHT30 : +{0x6445,0xFF,0x01}, // INFRM_RIGHT31 : +{0x6446,0xFF,0x01}, // INFRM_RIGHT32 : +{0x6447,0xFF,0x01}, // INFRM_RIGHT33 : +{0x6448,0xFF,0x01}, // INFRM_RIGHT34 : +{0x6449,0xFF,0x01}, // INFRM_RIGHT35 : +{0x644A,0xFF,0x01}, // INFRM_RIGHT36 : +{0x644B,0xFF,0x01}, // INFRM_RIGHT37 : +{0x644C,0xFFFF,0x02}, // INFRM_TOP : +{0x644E,0x0000,0x02}, // INFRM_BOTM : +{0x6450,0x25,0x01}, // INFRM_FLTOP : +{0x6451,0x00,0x01}, // INFRM_FLBOTM : +{0x6452,0x91,0x01}, // INAIM_LEFT00 : +{0x6453,0x91,0x01}, // INAIM_LEFT01 : +{0x6454,0x91,0x01}, // INAIM_LEFT02 : +{0x6455,0x91,0x01}, // INAIM_LEFT03 : +{0x6456,0x91,0x01}, // INAIM_LEFT04 : +{0x6457,0x91,0x01}, // INAIM_LEFT05 : +{0x6458,0x91,0x01}, // INAIM_LEFT06 : +{0x6459,0x91,0x01}, // INAIM_LEFT07 : +{0x645A,0x91,0x01}, // INAIM_LEFT08 : +{0x645B,0x91,0x01}, // INAIM_LEFT09 : +{0x645C,0x91,0x01}, // INAIM_LEFT10 : +{0x645D,0x91,0x01}, // INAIM_LEFT11 : +{0x645E,0x91,0x01}, // INAIM_LEFT12 : +{0x645F,0x66,0x01}, // INAIM_LEFT13 : +{0x6460,0x5D,0x01}, // INAIM_LEFT14 : +{0x6461,0x69,0x01}, // INAIM_LEFT15 : +{0x6462,0x54,0x01}, // INAIM_LEFT16 : +{0x6463,0x4B,0x01}, // INAIM_LEFT17 : +{0x6464,0x42,0x01}, // INAIM_LEFT18 : +{0x6465,0x3C,0x01}, // INAIM_LEFT19 : +{0x6466,0x38,0x01}, // INAIM_LEFT20 : +{0x6467,0x36,0x01}, // INAIM_LEFT21 : +{0x6468,0x35,0x01}, // INAIM_LEFT22 : +{0x6469,0x33,0x01}, // INAIM_LEFT23 : +{0x646A,0x32,0x01}, // INAIM_LEFT24 : +{0x646B,0x30,0x01}, // INAIM_LEFT25 : +{0x646C,0x2F,0x01}, // INAIM_LEFT26 : +{0x646D,0x2D,0x01}, // INAIM_LEFT27 : +{0x646E,0x2C,0x01}, // INAIM_LEFT28 : +{0x646F,0x2B,0x01}, // INAIM_LEFT29 : +{0x6470,0x2A,0x01}, // INAIM_LEFT30 : +{0x6471,0x28,0x01}, // INAIM_LEFT31 : +{0x6472,0x26,0x01}, // INAIM_LEFT32 : +{0x6473,0x24,0x01}, // INAIM_LEFT33 : +{0x6474,0x29,0x01}, // INAIM_LEFT34 : +{0x6475,0x28,0x01}, // INAIM_LEFT35 : +{0x6476,0x29,0x01}, // INAIM_LEFT36 : +{0x6477,0x26,0x01}, // INAIM_LEFT37 : +{0x6478,0xFF,0x01}, // INAIM_RIGHT00 : +{0x6479,0xFF,0x01}, // INAIM_RIGHT01 : +{0x647A,0xFF,0x01}, // INAIM_RIGHT02 : +{0x647B,0xFF,0x01}, // INAIM_RIGHT03 : +{0x647C,0xFF,0x01}, // INAIM_RIGHT04 : +{0x647D,0xFF,0x01}, // INAIM_RIGHT05 : +{0x647E,0xFF,0x01}, // INAIM_RIGHT06 : +{0x647F,0xFF,0x01}, // INAIM_RIGHT07 : +{0x6480,0xFF,0x01}, // INAIM_RIGHT08 : +{0x6481,0xFF,0x01}, // INAIM_RIGHT09 : +{0x6482,0xD9,0x01}, // INAIM_RIGHT10 : +{0x6483,0xB7,0x01}, // INAIM_RIGHT11 : +{0x6484,0x96,0x01}, // INAIM_RIGHT12 : +{0x6485,0x68,0x01}, // INAIM_RIGHT13 : +{0x6486,0x70,0x01}, // INAIM_RIGHT14 : +{0x6487,0x72,0x01}, // INAIM_RIGHT15 : +{0x6488,0x71,0x01}, // INAIM_RIGHT16 : +{0x6489,0x6B,0x01}, // INAIM_RIGHT17 : +{0x648A,0x65,0x01}, // INAIM_RIGHT18 : +{0x648B,0x60,0x01}, // INAIM_RIGHT19 : +{0x648C,0x5B,0x01}, // INAIM_RIGHT20 : +{0x648D,0x56,0x01}, // INAIM_RIGHT21 : +{0x648E,0x51,0x01}, // INAIM_RIGHT22 : +{0x648F,0x4C,0x01}, // INAIM_RIGHT23 : +{0x6490,0x47,0x01}, // INAIM_RIGHT24 : +{0x6491,0x44,0x01}, // INAIM_RIGHT25 : +{0x6492,0x41,0x01}, // INAIM_RIGHT26 : +{0x6493,0x3E,0x01}, // INAIM_RIGHT27 : +{0x6494,0x3B,0x01}, // INAIM_RIGHT28 : +{0x6495,0x39,0x01}, // INAIM_RIGHT29 : +{0x6496,0x37,0x01}, // INAIM_RIGHT30 : +{0x6497,0x34,0x01}, // INAIM_RIGHT31 : +{0x6498,0x33,0x01}, // INAIM_RIGHT32 : +{0x6499,0x32,0x01}, // INAIM_RIGHT33 : +{0x649A,0x31,0x01}, // INAIM_RIGHT34 : +{0x649B,0x30,0x01}, // INAIM_RIGHT35 : +{0x649C,0x2F,0x01}, // INAIM_RIGHT36 : +{0x649D,0x2E,0x01}, // INAIM_RIGHT37 : +{0x649E,0x1E00,0x02}, // INAIM_TOP : +{0x64A0,0x0F48,0x02}, // INAIM_BOTM : +{0x64A2,0x18,0x01}, // INAIM_FLTOP : +{0x64A3,0x11,0x01}, // INAIM_FLBOTM : +{0x64A4,0x00,0x01}, // OUTFRM_LEFT00 : +{0x64A5,0x00,0x01}, // OUTFRM_LEFT01 : +{0x64A6,0x00,0x01}, // OUTFRM_LEFT02 : +{0x64A7,0x00,0x01}, // OUTFRM_LEFT03 : +{0x64A8,0x00,0x01}, // OUTFRM_LEFT04 : +{0x64A9,0x00,0x01}, // OUTFRM_LEFT05 : +{0x64AA,0x00,0x01}, // OUTFRM_LEFT06 : +{0x64AB,0x00,0x01}, // OUTFRM_LEFT07 : +{0x64AC,0x00,0x01}, // OUTFRM_LEFT08 : +{0x64AD,0x00,0x01}, // OUTFRM_LEFT09 : +{0x64AE,0x00,0x01}, // OUTFRM_LEFT10 : +{0x64AF,0x00,0x01}, // OUTFRM_LEFT11 : +{0x64B0,0x00,0x01}, // OUTFRM_LEFT12 : +{0x64B1,0x00,0x01}, // OUTFRM_LEFT13 : +{0x64B2,0x00,0x01}, // OUTFRM_LEFT14 : +{0x64B3,0x00,0x01}, // OUTFRM_LEFT15 : +{0x64B4,0x00,0x01}, // OUTFRM_LEFT16 : +{0x64B5,0x00,0x01}, // OUTFRM_LEFT17 : +{0x64B6,0x00,0x01}, // OUTFRM_LEFT18 : +{0x64B7,0x00,0x01}, // OUTFRM_LEFT19 : +{0x64B8,0x00,0x01}, // OUTFRM_LEFT20 : +{0x64B9,0x00,0x01}, // OUTFRM_LEFT21 : +{0x64BA,0x00,0x01}, // OUTFRM_LEFT22 : +{0x64BB,0x00,0x01}, // OUTFRM_LEFT23 : +{0x64BC,0x00,0x01}, // OUTFRM_LEFT24 : +{0x64BD,0x00,0x01}, // OUTFRM_LEFT25 : +{0x64BE,0x00,0x01}, // OUTFRM_LEFT26 : +{0x64BF,0x00,0x01}, // OUTFRM_LEFT27 : +{0x64C0,0x00,0x01}, // OUTFRM_LEFT28 : +{0x64C1,0x00,0x01}, // OUTFRM_LEFT29 : +{0x64C2,0x00,0x01}, // OUTFRM_LEFT30 : +{0x64C3,0x00,0x01}, // OUTFRM_LEFT31 : +{0x64C4,0x00,0x01}, // OUTFRM_LEFT32 : +{0x64C5,0x00,0x01}, // OUTFRM_LEFT33 : +{0x64C6,0x00,0x01}, // OUTFRM_LEFT34 : +{0x64C7,0x00,0x01}, // OUTFRM_LEFT35 : +{0x64C8,0x00,0x01}, // OUTFRM_LEFT36 : +{0x64C9,0x00,0x01}, // OUTFRM_LEFT37 : +{0x64CA,0xFF,0x01}, // OUTFRM_RIGHT00 : +{0x64CB,0xFF,0x01}, // OUTFRM_RIGHT01 : +{0x64CC,0xFF,0x01}, // OUTFRM_RIGHT02 : +{0x64CD,0xFF,0x01}, // OUTFRM_RIGHT03 : +{0x64CE,0xFF,0x01}, // OUTFRM_RIGHT04 : +{0x64CF,0xFF,0x01}, // OUTFRM_RIGHT05 : +{0x64D0,0xFF,0x01}, // OUTFRM_RIGHT06 : +{0x64D1,0xFF,0x01}, // OUTFRM_RIGHT07 : +{0x64D2,0xFF,0x01}, // OUTFRM_RIGHT08 : +{0x64D3,0xFF,0x01}, // OUTFRM_RIGHT09 : +{0x64D4,0xFF,0x01}, // OUTFRM_RIGHT10 : +{0x64D5,0xFF,0x01}, // OUTFRM_RIGHT11 : +{0x64D6,0xFF,0x01}, // OUTFRM_RIGHT12 : +{0x64D7,0xFF,0x01}, // OUTFRM_RIGHT13 : +{0x64D8,0xFF,0x01}, // OUTFRM_RIGHT14 : +{0x64D9,0xFF,0x01}, // OUTFRM_RIGHT15 : +{0x64DA,0xFF,0x01}, // OUTFRM_RIGHT16 : +{0x64DB,0xFF,0x01}, // OUTFRM_RIGHT17 : +{0x64DC,0xFF,0x01}, // OUTFRM_RIGHT18 : +{0x64DD,0xFF,0x01}, // OUTFRM_RIGHT19 : +{0x64DE,0xFF,0x01}, // OUTFRM_RIGHT20 : +{0x64DF,0xFF,0x01}, // OUTFRM_RIGHT21 : +{0x64E0,0xFF,0x01}, // OUTFRM_RIGHT22 : +{0x64E1,0xFF,0x01}, // OUTFRM_RIGHT23 : +{0x64E2,0xFF,0x01}, // OUTFRM_RIGHT24 : +{0x64E3,0xFF,0x01}, // OUTFRM_RIGHT25 : +{0x64E4,0xFF,0x01}, // OUTFRM_RIGHT26 : +{0x64E5,0xFF,0x01}, // OUTFRM_RIGHT27 : +{0x64E6,0xFF,0x01}, // OUTFRM_RIGHT28 : +{0x64E7,0xFF,0x01}, // OUTFRM_RIGHT29 : +{0x64E8,0xFF,0x01}, // OUTFRM_RIGHT30 : +{0x64E9,0xFF,0x01}, // OUTFRM_RIGHT31 : +{0x64EA,0xFF,0x01}, // OUTFRM_RIGHT32 : +{0x64EB,0xFF,0x01}, // OUTFRM_RIGHT33 : +{0x64EC,0xFF,0x01}, // OUTFRM_RIGHT34 : +{0x64ED,0xFF,0x01}, // OUTFRM_RIGHT35 : +{0x64EE,0xFF,0x01}, // OUTFRM_RIGHT36 : +{0x64EF,0xFF,0x01}, // OUTFRM_RIGHT37 : +{0x64F0,0x24F0,0x02}, // OUTFRM_TOP : +{0x64F2,0x1400,0x02}, // OUTFRM_BOTM : +{0x64F4,0x37,0x01}, // OUTFRM_FLTOP : +{0x64F5,0x00,0x01}, // OUTFRM_FLBOTM : + + +//CAF +{0x6696,0x16,0x01}, //AF_CAF_WOBBLE_START_INTERVAL_COUNTER +{0x6668,0x03FF,0x02}, // AF_AREA_HIGH_TYPE1 : + +{0x6716,0x0000,0x02}, // CAF_LVD_WOB_HBPF_VAL1 : +{0x6718,0x0000,0x02}, // CAF_LVD_WOB_HBPF_VAL2 : +{0x671A,0x00C8,0x02}, // CAF_LVD_WOB_HBPF_RATE1 : +{0x671C,0x00C8,0x02}, // CAF_LVD_WOB_HBPF_RATE2 : +{0x671E,0x00,0x01}, // CAF_LVD_WOB_HBPF_SHIFT : +{0x6720,0x0000,0x02}, // CAF_LVD_WOB_LBPF_VAL1 : +{0x6722,0x0000,0x02}, // CAF_LVD_WOB_LBPF_VAL2 : +{0x6724,0x0014,0x02}, // CAF_LVD_WOB_LBPF_RATE1 : +{0x6726,0x0014,0x02}, // CAF_LVD_WOB_LBPF_RATE2 : +{0x6728,0x00,0x01}, // CAF_LVD_WOB_LBPF_SHIFT : +{0x672A,0x0000,0x02}, // CAF_LVD_CLMP_HBPF_VAL1 : +{0x672C,0x0000,0x02}, // CAF_LVD_CLMP_HBPF_VAL2 : +{0x672E,0x012C,0x02}, // CAF_LVD_CLMP_HBPF_RATE1 : +{0x6730,0x012C,0x02}, // CAF_LVD_CLMP_HBPF_RATE2 : +{0x6732,0x00,0x01}, // CAF_LVD_CLMP_HBPF_SHIFT : +{0x6734,0x0000,0x02}, // CAF_LVD_CLMP_LBPF_VAL1 : +{0x6736,0x0000,0x02}, // CAF_LVD_CLMP_LBPF_VAL2 : +{0x6738,0x0046,0x02}, // CAF_LVD_CLMP_LBPF_RATE1 : +{0x673A,0x0046,0x02}, // CAF_LVD_CLMP_LBPF_RATE2 : +{0x673C,0x00,0x01}, // CAF_LVD_CLMP_LBPF_SHIFT : + +//AWB +{0x6232,0x07,0x01},//ATW_SFTLMT_OUT_NR +{0x6234,0x05,0x01},//ATW_SFTLMT_OUT + + +//movie setting +{0x0094,0x0500,0x02},//HSIZE_MOVIE : 1280 +{0x009A,0x02D0,0x02},//VSIZE_MOVIE : 720 + +{0x018E,0x0012,0x02}, //VADJ_SENS_1_2 : 30 fps fix + +{0x008B,0x00,0x01},//OUTFMT_MOVIE +{0x0085,0x01,0x01},//SENSMODE_MOVIE +{0x0088,0x02,0x01},//FPSTYPE_MOVIE + +{0x0081,0x03,0x01},//MODESEL +{0x0082,0x01,0x01},//MONI_REFRESH +}; + +isx012_short_t isx012_pll_setting[] = +{ +// ISX012-0 +// MIPI 2LANE 432/LANE +// PLL 432MHz +// DCK 54 +// inifile +// size address data +// + +{0x0006,0x07,0x01}, //INCK_SET : 26MHz + +{0x0007,0x00,0x01}, // PLL_CKSEL : PLL 432MHz +{0x0008,0x00,0x01}, // SRCCK_DIV : 1/5 frequency +{0x00C4,0x11,0x01}, // VIF_CLKCONFIG1 : VIFSEL and VIFDIV setting value with full frame pixel setting for other then JPG +{0x00C5,0x11,0x01}, // VIF_CLKCONFIG2 : VIFSEL and VIFDIV setting value with 1/2 sub-sampling setting for other then JPG +{0x00C6,0x11,0x01}, // VIF_CLKCONFIG3 : VIFSEL and VIFDIV setting value with 1/4 sub-sampling setting for other then JPG +{0x00C7,0x11,0x01}, // VIF_CLKCONFIG4 : VIFSEL and VIFDIV setting value with 1/8 sub-sampling setting for other then JPG +{0x00C8,0x11,0x01}, // VIF_CLKCONFIG5 : VIFSEL and VIFDIV setting value with full frame pixel setting for JPG mode +{0x00C9,0x11,0x01}, // VIF_CLKCONFIG6 : VIFSEL and VIFDIV setting value with 1/2 sub-sampling setting for JPG mode +{0x00CA,0x11,0x01}, // VIF_CLKCONFIG7 : VIFSEL and VIFDIV setting value with 1/4 sub-sampling setting for JPG mode +{0x00CC,0x11,0x01}, // VIF_CLKCONFIG9 : VIFSEL and VIFDIV setting value with full frame pixel setting for JPG and interleave mode +{0x00CD,0x11,0x01}, // VIF_CLKCONFIG10 : VIFSEL and VIFDIV setting value with 1/2 sub-sampling setting for JPG and interleave mode +{0x6A12,0x11,0x01}, // VIF_CLKCONFIG13 for RAW8 : VIFSEL and VIFDIV setting value with full frame pixel setting for RAW mode +{0x6A13,0x11,0x01}, // VIF_CLKCONFIG14 for RAW8 : VIFSEL and VIFDIV setting value with 1/2 sub-sampling setting for RAW mode +{0x6A14,0x11,0x01}, // VIF_CLKCONFIG15 for RAW8 : VIFSEL and VIFDIV setting value with 1/4 sub-sampling setting for RAW mode +{0x6A15,0x11,0x01}, // VIF_CLKCONFIG16 for RAW8 : VIFSEL and VIFDIV setting value with 1/8 sub-sampling setting for RAW mode +{0x018C,0x0000,0x02}, // VADJ_SENS_1_1 : VMAX adjustment value for full frame pixel +{0x018E,0x0000,0x02}, // VADJ_SENS_1_2 : VMAX adjustment value for 1/2 sub-sampling +{0x0190,0x0000,0x02}, // VADJ_SENS_1_4 : VMAX adjustment value for 1/4 sub-sampling +{0x0192,0x0000,0x02}, // VADJ_SENS_1_8 : VMAX adjustment value for 1/8 sub-sampling +{0x0194,0x0027,0x02}, // VADJ_SENS_HD_1_1 : VMAX adjustment value for HD full frame pixel +{0x0196,0x0015,0x02}, // VADJ_SENS_HD_1_2 : VMAX adjustment value for HD 1/2 sub-sampling +{0x6A16,0x0440,0x02}, // FLC_OPD_HEIGHT_NORMAL_1_1 : Detection window vertical size with all 32 windows for FLC full frame pixel +{0x6A18,0x03C0,0x02}, // FLC_OPD_HEIGHT_NORMAL_1_2 : Detection window vertical size with all 32 windows for FLC 1/2 sub-sampling +{0x6A1A,0x01E0,0x02}, // FLC_OPD_HEIGHT_NORMAL_1_4 : Detection window vertical size with all 32 windows for FLC 1/4 sub-sampling +{0x6A1C,0x00E0,0x02}, // FLC_OPD_HEIGHT_NORMAL_1_8 : Detection window vertical size with all 32 windows for FLC 1/8 sub-sampling +{0x6A1E,0x0420,0x02}, // FLC_OPD_HEIGHT_HD_1_1 : Detection window vertical size with all 32 windows for FLC HD full frame pixel +{0x6A20,0x02C0,0x02}, // FLC_OPD_HEIGHT_HD_1_2 : Detection window vertical size with all 32 windows for FLC HD 1/2 sub-sampling +{0x0016,0x0010,0x02}, // GPIO_FUNCSEL : GPIO setting +{0x5C01,0x00,0x01}, // RGLANESEL : +{0x5C04,0x04,0x01}, // RGTLPX : +{0x5C05,0x03,0x01}, // RGTCLKPREPARE : +{0x5C06,0x14,0x01}, // RGTCLKZERO : +{0x5C07,0x02,0x01}, // RGTCLKPRE : +{0x5C08,0x11,0x01}, // RGTCLKPOST : +{0x5C09,0x05,0x01}, // RGTCLKTRAIL : +{0x5C0A,0x07,0x01}, // RGTHSEXIT : +{0x5C0B,0x03,0x01}, // RGTHSPREPARE : +{0x5C0C,0x07,0x01}, // RGTHSZERO : +{0x5C0D,0x05,0x01}, // RGTHSTRAIL : + +{0x0004,0x02,0x01}, //I2C_ADR_SEL 2: 0x3C MIPI selected +{0x5008,0x00,0x01}, //ENDIAN_SEL : 0:Little Endian + + +{0x0089,0x00,0x01},//OUTFMT_MONI +{0x0090,0x0280,0x02},//HSIZE_MONI : 640 +{0x0096,0x01E0,0x02},//VSIZE_MONI : 480 +{0x0083,0x01,0x01},//SENSMODE_MONI +{0x0086,0x02,0x01},//FPSTYPE_MONI +{0x0081,0x00,0x01},//MODESEL +{0x0082,0x01,0x01},//MONI_REFRESH + +{0x0006,0x17,0x01}, //INCK_SET : 26MHz + +}; + +isx012_short_t isx012_shading_cal_setting[] = +{ +// CXC/SHD EN +{0x01BC,0x57,0x01}, // CXC OFF SHD OFF + +//CXC +{0xEB00,0x8282,0x02}, // valid_code +{0xEB02,0x00,0x01}, // +{0xEB03,0x03,0x01}, // +{0xEB04,0xC0,0x01}, // +{0xEB05,0x30,0x01}, // +{0xEB06,0x48,0x01}, // +{0xEB07,0x04,0x01}, // +{0xEB08,0x0C,0x01}, // +{0xEB09,0x02,0x01}, // +{0xEB0A,0x44,0x01}, // +{0xEB0B,0xE0,0x01}, // +{0xEB0C,0x30,0x01}, // +{0xEB0D,0x40,0x01}, // +{0xEB0E,0x0C,0x01}, // +{0xEB0F,0x12,0x01}, // +{0xEB10,0x83,0x01}, // +{0xEB11,0x04,0x01}, // +{0xEB12,0xC0,0x01}, // +{0xEB13,0x00,0x01}, // +{0xEB14,0x30,0x01}, // +{0xEB15,0x0C,0x01}, // +{0xEB16,0x12,0x01}, // +{0xEB17,0x01,0x01}, // +{0xEB18,0x83,0x01}, // +{0xEB19,0x00,0x01}, // +{0xEB1A,0x11,0x01}, // +{0xEB1B,0x38,0x01}, // +{0xEB1C,0x0C,0x01}, // +{0xEB1D,0x10,0x01}, // +{0xEB1E,0x83,0x01}, // +{0xEB1F,0xC4,0x01}, // +{0xEB20,0x20,0x01}, // +{0xEB21,0x21,0x01}, // +{0xEB22,0x28,0x01}, // +{0xEB23,0x08,0x01}, // +{0xEB24,0x0A,0x01}, // +{0xEB25,0x83,0x01}, // +{0xEB26,0xC3,0x01}, // +{0xEB27,0xC0,0x01}, // +{0xEB28,0x10,0x01}, // +{0xEB29,0x28,0x01}, // +{0xEB2A,0x08,0x01}, // +{0xEB2B,0x0A,0x01}, // +{0xEB2C,0x03,0x01}, // +{0xEB2D,0x04,0x01}, // +{0xEB2E,0x01,0x01}, // +{0xEB2F,0x41,0x01}, // +{0xEB30,0x40,0x01}, // +{0xEB31,0x08,0x01}, // +{0xEB32,0x0A,0x01}, // +{0xEB33,0x82,0x01}, // +{0xEB34,0x42,0x01}, // +{0xEB35,0x80,0x01}, // +{0xEB36,0x10,0x01}, // +{0xEB37,0x18,0x01}, // +{0xEB38,0x04,0x01}, // +{0xEB39,0x08,0x01}, // +{0xEB3A,0x81,0x01}, // +{0xEB3B,0x81,0x01}, // +{0xEB3C,0xA0,0x01}, // +{0xEB3D,0x10,0x01}, // +{0xEB3E,0x40,0x01}, // +{0xEB3F,0x04,0x01}, // +{0xEB40,0x10,0x01}, // +{0xEB41,0x82,0x01}, // +{0xEB42,0x82,0x01}, // +{0xEB43,0xA0,0x01}, // +{0xEB44,0x10,0x01}, // +{0xEB45,0x10,0x01}, // +{0xEB46,0x08,0x01}, // +{0xEB47,0x02,0x01}, // +{0xEB48,0x01,0x01}, // +{0xEB49,0x80,0x01}, // +{0xEB4A,0x40,0x01}, // +{0xEB4B,0x20,0x01}, // +{0xEB4C,0x10,0x01}, // +{0xEB4D,0x08,0x01}, // +{0xEB4E,0x0C,0x01}, // +{0xEB4F,0x02,0x01}, // +{0xEB50,0xC3,0x01}, // +{0xEB51,0x40,0x01}, // +{0xEB52,0x30,0x01}, // +{0xEB53,0x10,0x01}, // +{0xEB54,0x08,0x01}, // +{0xEB55,0x02,0x01}, // +{0xEB56,0x01,0x01}, // +{0xEB57,0x80,0x01}, // +{0xEB58,0xE0,0x01}, // +{0xEB59,0x1F,0x01}, // +{0xEB5A,0x00,0x01}, // +{0xEB5B,0x04,0x01}, // +{0xEB5C,0x02,0x01}, // +{0xEB5D,0x00,0x01}, // +{0xEB5E,0x02,0x01}, // +{0xEB5F,0x80,0x01}, // +{0xEB60,0x10,0x01}, // +{0xEB61,0x18,0x01}, // +{0xEB62,0x04,0x01}, // +{0xEB63,0x06,0x01}, // +{0xEB64,0x81,0x01}, // +{0xEB65,0x80,0x01}, // +{0xEB66,0x00,0x01}, // +{0xEB67,0x20,0x01}, // +{0xEB68,0x00,0x01}, // +{0xEB69,0x0C,0x01}, // +{0xEB6A,0x02,0x01}, // +{0xEB6B,0x01,0x01}, // +{0xEB6C,0x81,0x01}, // +{0xEB6D,0x60,0x01}, // +{0xEB6E,0x20,0x01}, // +{0xEB6F,0x18,0x01}, // +{0xEB70,0x08,0x01}, // +{0xEB71,0x06,0x01}, // +{0xEB72,0x82,0x01}, // +{0xEB73,0x81,0x01}, // +{0xEB74,0x40,0x01}, // +{0xEB75,0x30,0x01}, // +{0xEB76,0x00,0x01}, // +{0xEB77,0x0C,0x01}, // +{0xEB78,0x00,0x01}, // +{0xEB79,0x84,0x01}, // +{0xEB7A,0x40,0x01}, // +{0xEB7B,0x40,0x01}, // +{0xEB7C,0x00,0x01}, // +{0xEB7D,0x20,0x01}, // +{0xEB7E,0x00,0x01}, // +{0xEB7F,0x08,0x01}, // +{0xEB80,0x80,0x01}, // +{0xEB81,0x02,0x01}, // +{0xEB82,0xA0,0x01}, // +{0xEB83,0x10,0x01}, // +{0xEB84,0x18,0x01}, // +{0xEB85,0x08,0x01}, // +{0xEB86,0x04,0x01}, // +{0xEB87,0x03,0x01}, // +{0xEB88,0xC1,0x01}, // +{0xEB89,0x60,0x01}, // +{0xEB8A,0x10,0x01}, // +{0xEB8B,0x20,0x01}, // +{0xEB8C,0x08,0x01}, // +{0xEB8D,0x08,0x01}, // +{0xEB8E,0x02,0x01}, // +{0xEB8F,0x02,0x01}, // +{0xEB90,0x81,0x01}, // +{0xEB91,0x40,0x01}, // +{0xEB92,0x20,0x01}, // +{0xEB93,0x10,0x01}, // +{0xEB94,0x0A,0x01}, // +{0xEB95,0x01,0x01}, // +{0xEB96,0x42,0x01}, // +{0xEB97,0x60,0x01}, // +{0xEB98,0x40,0x01}, // +{0xEB99,0x20,0x01}, // +{0xEB9A,0x10,0x01}, // +{0xEB9B,0x0C,0x01}, // +{0xEB9C,0x02,0x01}, // +{0xEB9D,0x82,0x01}, // +{0xEB9E,0x80,0x01}, // +{0xEB9F,0x20,0x01}, // +{0xEBA0,0x28,0x01}, // +{0xEBA1,0x08,0x01}, // +{0xEBA2,0x0A,0x01}, // +{0xEBA3,0x04,0x01}, // +{0xEBA4,0x02,0x01}, // +{0xEBA5,0xC1,0x01}, // +{0xEBA6,0x30,0x01}, // +{0xEBA7,0x30,0x01}, // +{0xEBA8,0x10,0x01}, // +{0xEBA9,0x0C,0x01}, // +{0xEBAA,0x02,0x01}, // +{0xEBAB,0x03,0x01}, // +{0xEBAC,0xC1,0x01}, // +{0xEBAD,0x40,0x01}, // +{0xEBAE,0x30,0x01}, // +{0xEBAF,0x08,0x01}, // +{0xEBB0,0x0A,0x01}, // +{0xEBB1,0x82,0x01}, // +{0xEBB2,0x02,0x01}, // +{0xEBB3,0x81,0x01}, // +{0xEBB4,0x40,0x01}, // +{0xEBB5,0x30,0x01}, // +{0xEBB6,0x0C,0x01}, // +{0xEBB7,0x0C,0x01}, // +{0xEBB8,0x04,0x01}, // +{0xEBB9,0x83,0x01}, // +{0xEBBA,0xC0,0x01}, // +{0xEBBB,0x40,0x01}, // +{0xEBBC,0x30,0x01}, // +{0xEBBD,0x10,0x01}, // +{0xEBBE,0x0C,0x01}, // +{0xEBBF,0x81,0x01}, // +{0xEBC0,0x7C,0x01}, // +{0xEBC1,0x20,0x01}, // +{0xEBC2,0x0F,0x01}, // +{0xEBC3,0xC8,0x01}, // +{0xEBC4,0xFF,0x01}, // +{0xEBC5,0xF7,0x01}, // +{0xEBC6,0x80,0x01}, // +{0xEBC7,0x3D,0x01}, // +{0xEBC8,0x40,0x01}, // +{0xEBC9,0xEF,0x01}, // +{0xEBCA,0xDF,0x01}, // +{0xEBCB,0xFB,0x01}, // +{0xEBCC,0xF3,0x01}, // +{0xEBCD,0xFE,0x01}, // +{0xEBCE,0x7C,0x01}, // +{0xEBCF,0x20,0x01}, // +{0xEBD0,0x1F,0x01}, // +{0xEBD1,0xC8,0x01}, // +{0xEBD2,0x03,0x01}, // +{0xEBD3,0xF2,0x01}, // +{0xEBD4,0xFF,0x01}, // +{0xEBD5,0x3D,0x01}, // +{0xEBD6,0x60,0x01}, // +{0xEBD7,0x0F,0x01}, // +{0xEBD8,0xD0,0x01}, // +{0xEBD9,0xFB,0x01}, // +{0xEBDA,0xF7,0x01}, // +{0xEBDB,0xFE,0x01}, // +{0xEBDC,0xBC,0x01}, // +{0xEBDD,0x3F,0x01}, // +{0xEBDE,0x1F,0x01}, // +{0xEBDF,0xC0,0x01}, // +{0xEBE0,0x07,0x01}, // +{0xEBE1,0xF0,0x01}, // +{0xEBE2,0x01,0x01}, // +{0xEBE3,0xBD,0x01}, // +{0xEBE4,0x3F,0x01}, // +{0xEBE5,0xFF,0x01}, // +{0xEBE6,0xD7,0x01}, // +{0xEBE7,0xF7,0x01}, // +{0xEBE8,0xF3,0x01}, // +{0xEBE9,0xFF,0x01}, // +{0xEBEA,0xFD,0x01}, // +{0xEBEB,0x5F,0x01}, // +{0xEBEC,0xFF,0x01}, // +{0xEBED,0xD7,0x01}, // +{0xEBEE,0x0B,0x01}, // +{0xEBEF,0xF8,0x01}, // +{0xEBF0,0x02,0x01}, // +{0xEBF1,0xBE,0x01}, // +{0xEBF2,0xFF,0x01}, // +{0xEBF3,0xEE,0x01}, // +{0xEBF4,0xCF,0x01}, // +{0xEBF5,0xFB,0x01}, // +{0xEBF6,0xF3,0x01}, // +{0xEBF7,0xFE,0x01}, // +{0xEBF8,0xFC,0x01}, // +{0xEBF9,0x5F,0x01}, // +{0xEBFA,0xEF,0x01}, // +{0xEBFB,0xC7,0x01}, // +{0xEBFC,0xFB,0x01}, // +{0xEBFD,0xF1,0x01}, // +{0xEBFE,0x81,0x01}, // +{0xEBFF,0x7C,0x01}, // +{0xEC00,0x20,0x01}, // +{0xEC01,0x0F,0x01}, // +{0xEC02,0xE0,0x01}, // +{0xEC03,0xFF,0x01}, // +{0xEC04,0xF7,0x01}, // +{0xEC05,0xFD,0x01}, // +{0xEC06,0xFE,0x01}, // +{0xEC07,0x5F,0x01}, // +{0xEC08,0xDF,0x01}, // +{0xEC09,0xEF,0x01}, // +{0xEC0A,0xF7,0x01}, // +{0xEC0B,0xF7,0x01}, // +{0xEC0C,0xFD,0x01}, // +{0xEC0D,0x3D,0x01}, // +{0xEC0E,0xC1,0x01}, // +{0xEC0F,0x4F,0x01}, // +{0xEC10,0xF0,0x01}, // +{0xEC11,0x07,0x01}, // +{0xEC12,0xF8,0x01}, // +{0xEC13,0xFF,0x01}, // +{0xEC14,0xBE,0x01}, // +{0xEC15,0xFF,0x01}, // +{0xEC16,0xFF,0x01}, // +{0xEC17,0xEF,0x01}, // +{0xEC18,0xFF,0x01}, // +{0xEC19,0xFB,0x01}, // +{0xEC1A,0xFE,0x01}, // +{0xEC1B,0xBD,0x01}, // +{0xEC1C,0x7F,0x01}, // +{0xEC1D,0x4F,0x01}, // +{0xEC1E,0x00,0x01}, // +{0xEC1F,0x10,0x01}, // +{0xEC20,0x00,0x01}, // +{0xEC21,0x82,0x01}, // +{0xEC22,0x40,0x01}, // +{0xEC23,0x00,0x01}, // +{0xEC24,0x00,0x01}, // +{0xEC25,0xF8,0x01}, // +{0xEC26,0xFF,0x01}, // +{0xEC27,0x05,0x01}, // +{0xEC28,0x7F,0x01}, // +{0xEC29,0xFF,0x01}, // +{0xEC2A,0xBF,0x01}, // +{0xEC2B,0xFF,0x01}, // +{0xEC2C,0xEF,0x01}, // +{0xEC2D,0x17,0x01}, // +{0xEC2E,0x02,0x01}, // +{0xEC2F,0x85,0x01}, // +{0xEC30,0xC0,0x01}, // +{0xEC31,0x00,0x01}, // +{0xEC32,0x20,0x01}, // +{0xEC33,0xF8,0x01}, // +{0xEC34,0x07,0x01}, // +{0xEC35,0x08,0x01}, // +{0xEC36,0x00,0x01}, // +{0xEC37,0x41,0x01}, // +{0xEC38,0x20,0x01}, // +{0xEC39,0x20,0x01}, // +{0xEC3A,0x10,0x01}, // +{0xEC3B,0x08,0x01}, // +{0xEC3C,0x04,0x01}, // +{0xEC3D,0x07,0x01}, // +{0xEC3E,0xC1,0x01}, // +{0xEC3F,0x41,0x01}, // +{0xEC40,0x60,0x01}, // +{0xEC41,0x00,0x01}, // +{0xEC42,0x0C,0x01}, // +{0xEC43,0x0A,0x01}, // +{0xEC44,0x83,0x01}, // +{0xEC45,0x82,0x01}, // +{0xEC46,0x80,0x01}, // +{0xEC47,0x10,0x01}, // +{0xEC48,0x18,0x01}, // +{0xEC49,0x08,0x01}, // +{0xEC4A,0x04,0x01}, // +{0xEC4B,0x02,0x01}, // +{0xEC4C,0x81,0x01}, // +{0xEC4D,0x61,0x01}, // +{0xEC4E,0x60,0x01}, // +{0xEC4F,0x18,0x01}, // +{0xEC50,0x14,0x01}, // +{0xEC51,0x06,0x01}, // +{0xEC52,0x05,0x01}, // +{0xEC53,0x04,0x01}, // +{0xEC54,0x61,0x01}, // +{0xEC55,0x30,0x01}, // +{0xEC56,0x38,0x01}, // +{0xEC57,0x08,0x01}, // +{0xEC58,0x0A,0x01}, // +{0xEC59,0x03,0x01}, // +{0xEC5A,0xC2,0x01}, // +{0xEC5B,0x80,0x01}, // +{0xEC5C,0x60,0x01}, // +{0xEC5D,0x28,0x01}, // +{0xEC5E,0x18,0x01}, // +{0xEC5F,0x0A,0x01}, // +{0xEC60,0x84,0x01}, // +{0xEC61,0x03,0x01}, // +{0xEC62,0xC1,0x01}, // +{0xEC63,0x30,0x01}, // +{0xEC64,0x30,0x01}, // +{0xEC65,0x08,0x01}, // +{0xEC66,0x0C,0x01}, // +{0xEC67,0x03,0x01}, // +{0xEC68,0x02,0x01}, // +{0xEC69,0x21,0x01}, // +{0xEC6A,0x41,0x01}, // +{0xEC6B,0x48,0x01}, // +{0xEC6C,0x18,0x01}, // +{0xEC6D,0x0A,0x01}, // +{0xEC6E,0x86,0x01}, // +{0xEC6F,0x02,0x01}, // +{0xEC70,0xE1,0x01}, // +{0xEC71,0x40,0x01}, // +{0xEC72,0x30,0x01}, // +{0xEC73,0x0C,0x01}, // +{0xEC74,0x0C,0x01}, // +{0xEC75,0x02,0x01}, // +{0xEC76,0xC3,0x01}, // +{0xEC77,0x80,0x01}, // +{0xEC78,0x40,0x01}, // +{0xEC79,0x48,0x01}, // +{0xEC7A,0x10,0x01}, // +{0xEC7B,0x12,0x01}, // +{0xED00,0x9191,0x02}, // +{0xED02,0x24,0x01}, // +{0xED03,0xC2,0x01}, // +{0xED04,0x13,0x01}, // +{0xED05,0x86,0x01}, // +{0xED06,0xD6,0x01}, // +{0xED07,0x24,0x01}, // +{0xED08,0x9F,0x01}, // +{0xED09,0x22,0x01}, // +{0xED0A,0x61,0x01}, // +{0xED0B,0x07,0x01}, // +{0xED0C,0x44,0x01}, // +{0xED0D,0xC8,0x01}, // +{0xED0E,0x89,0x01}, // +{0xED0F,0x50,0x01}, // +{0xED10,0x74,0x01}, // +{0xED11,0x34,0x01}, // +{0xED12,0x84,0x01}, // +{0xED13,0x1E,0x01}, // +{0xED14,0x1C,0x01}, // +{0xED15,0x31,0x01}, // +{0xED16,0xC8,0x01}, // +{0xED17,0x4C,0x01}, // +{0xED18,0x1B,0x01}, // +{0xED19,0xAA,0x01}, // +{0xED1A,0xD3,0x01}, // +{0xED1B,0x87,0x01}, // +{0xED1C,0xE8,0x01}, // +{0xED1D,0x34,0x01}, // +{0xED1E,0xA0,0x01}, // +{0xED1F,0x2A,0x01}, // +{0xED20,0x65,0x01}, // +{0xED21,0x87,0x01}, // +{0xED22,0x44,0x01}, // +{0xED23,0xBE,0x01}, // +{0xED24,0xF9,0x01}, // +{0xED25,0x0F,0x01}, // +{0xED26,0x6C,0x01}, // +{0xED27,0xE2,0x01}, // +{0xED28,0x83,0x01}, // +{0xED29,0x1B,0x01}, // +{0xED2A,0xFD,0x01}, // +{0xED2B,0x38,0x01}, // +{0xED2C,0x47,0x01}, // +{0xED2D,0x43,0x01}, // +{0xED2E,0xF4,0x01}, // +{0xED2F,0x79,0x01}, // +{0xED30,0x92,0x01}, // +{0xED31,0x83,0x01}, // +{0xED32,0xDA,0x01}, // +{0xED33,0x64,0x01}, // +{0xED34,0x9E,0x01}, // +{0xED35,0x15,0x01}, // +{0xED36,0x1D,0x01}, // +{0xED37,0x87,0x01}, // +{0xED38,0x40,0x01}, // +{0xED39,0x99,0x01}, // +{0xED3A,0x69,0x01}, // +{0xED3B,0x4E,0x01}, // +{0xED3C,0x5F,0x01}, // +{0xED3D,0x4C,0x01}, // +{0xED3E,0x13,0x01}, // +{0xED3F,0x17,0x01}, // +{0xED40,0xCC,0x01}, // +{0xED41,0xDC,0x01}, // +{0xED42,0xE5,0x01}, // +{0xED43,0x33,0x01}, // +{0xED44,0x90,0x01}, // +{0xED45,0x29,0x01}, // +{0xED46,0xCE,0x01}, // +{0xED47,0x6E,0x01}, // +{0xED48,0x02,0x01}, // +{0xED49,0x34,0x01}, // +{0xED4A,0x9D,0x01}, // +{0xED4B,0x11,0x01}, // +{0xED4C,0xDD,0x01}, // +{0xED4D,0xC6,0x01}, // +{0xED4E,0x3D,0x01}, // +{0xED4F,0x97,0x01}, // +{0xED50,0x29,0x01}, // +{0xED51,0x8E,0x01}, // +{0xED52,0x59,0x01}, // +{0xED53,0x08,0x01}, // +{0xED54,0x13,0x01}, // +{0xED55,0x94,0x01}, // +{0xED56,0xAA,0x01}, // +{0xED57,0xD8,0x01}, // +{0xED58,0xE4,0x01}, // +{0xED59,0x28,0x01}, // +{0xED5A,0x3D,0x01}, // +{0xED5B,0x81,0x01}, // +{0xED5C,0x8A,0x01}, // +{0xED5D,0x57,0x01}, // +{0xED5E,0xFA,0x01}, // +{0xED5F,0xA2,0x01}, // +{0xED60,0x98,0x01}, // +{0xED61,0xDF,0x01}, // +{0xED62,0x94,0x01}, // +{0xED63,0x06,0x01}, // +{0xED64,0x3D,0x01}, // +{0xED65,0x99,0x01}, // +{0xED66,0x39,0x01}, // +{0xED67,0x0E,0x01}, // +{0xED68,0x5D,0x01}, // +{0xED69,0x2C,0x01}, // +{0xED6A,0xE3,0x01}, // +{0xED6B,0x13,0x01}, // +{0xED6C,0xA7,0x01}, // +{0xED6D,0x70,0x01}, // +{0xED6E,0x84,0x01}, // +{0xED6F,0x24,0x01}, // +{0xED70,0x0F,0x01}, // +{0xED71,0x99,0x01}, // +{0xED72,0x48,0x01}, // +{0xED73,0x46,0x01}, // +{0xED74,0x40,0x01}, // +{0xED75,0x72,0x01}, // +{0xED76,0x93,0x01}, // +{0xED77,0xA3,0x01}, // +{0xED78,0xA0,0x01}, // +{0xED79,0xA5,0x01}, // +{0xED7A,0x31,0x01}, // +{0xED7B,0x88,0x01}, // +{0xED7C,0xE1,0x01}, // +{0xED7D,0x0D,0x01}, // +{0xED7E,0x63,0x01}, // +{0xED7F,0x64,0x01}, // +{0xED80,0x53,0x01}, // +{0xED81,0x16,0x01}, // +{0xED82,0xBF,0x01}, // +{0xED83,0xB0,0x01}, // +{0xED84,0xC4,0x01}, // +{0xED85,0x26,0x01}, // +{0xED86,0x0B,0x01}, // +{0xED87,0x71,0x01}, // +{0xED88,0x08,0x01}, // +{0xED89,0x40,0x01}, // +{0xED8A,0x00,0x01}, // +{0xED8B,0x92,0x01}, // +{0xED8C,0x90,0x01}, // +{0xED8D,0x85,0x01}, // +{0xED8E,0x90,0x01}, // +{0xED8F,0xE4,0x01}, // +{0xED90,0x25,0x01}, // +{0xED91,0x56,0x01}, // +{0xED92,0xA1,0x01}, // +{0xED93,0x4B,0x01}, // +{0xED94,0x5E,0x01}, // +{0xED95,0x4A,0x01}, // +{0xED96,0xF3,0x01}, // +{0xED97,0x18,0x01}, // +{0xED98,0xDC,0x01}, // +{0xED99,0xA0,0x01}, // +{0xED9A,0x65,0x01}, // +{0xED9B,0x30,0x01}, // +{0xED9C,0x30,0x01}, // +{0xED9D,0xE1,0x01}, // +{0xED9E,0x09,0x01}, // +{0xED9F,0x44,0x01}, // +{0xEDA0,0x24,0x01}, // +{0xEDA1,0x32,0x01}, // +{0xEDA2,0x10,0x01}, // +{0xEDA3,0x82,0x01}, // +{0xEDA4,0x34,0x01}, // +{0xEDA5,0x04,0x01}, // +{0xEDA6,0x22,0x01}, // +{0xEDA7,0x28,0x01}, // +{0xEDA8,0xA9,0x01}, // +{0xEDA9,0x89,0x01}, // +{0xEDAA,0x56,0x01}, // +{0xEDAB,0xEE,0x01}, // +{0xEDAC,0xE2,0x01}, // +{0xEDAD,0x97,0x01}, // +{0xEDAE,0xD3,0x01}, // +{0xEDAF,0x94,0x01}, // +{0xEDB0,0x86,0x01}, // +{0xEDB1,0x3A,0x01}, // +{0xEDB2,0x81,0x01}, // +{0xEDB3,0x21,0x01}, // +{0xEDB4,0xCD,0x01}, // +{0xEDB5,0x52,0x01}, // +{0xEDB6,0xBA,0x01}, // +{0xEDB7,0x92,0x01}, // +{0xEDB8,0x12,0x01}, // +{0xEDB9,0x98,0x01}, // +{0xEDBA,0x70,0x01}, // +{0xEDBB,0x04,0x01}, // +{0xEDBC,0x24,0x01}, // +{0xEDBD,0x26,0x01}, // +{0xEDBE,0x71,0x01}, // +{0xEDBF,0x89,0x01}, // +{0xEDC0,0x50,0x01}, // +{0xEDC1,0xAC,0x01}, // +{0xEDC2,0x22,0x01}, // +{0xEDC3,0x97,0x01}, // +{0xEDC4,0xCC,0x01}, // +{0xEDC5,0x48,0x01}, // +{0xEDC6,0x86,0x01}, // +{0xEDC7,0x38,0x01}, // +{0xEDC8,0xC7,0x01}, // +{0xEDC9,0x31,0x01}, // +{0xEDCA,0x10,0x01}, // +{0xEDCB,0x6A,0x01}, // +{0xEDCC,0xBA,0x01}, // +{0xEDCD,0x83,0x01}, // +{0xEDCE,0x97,0x01}, // +{0xEDCF,0xCD,0x01}, // +{0xEDD0,0x54,0x01}, // +{0xEDD1,0x65,0x01}, // +{0xEDD2,0x2D,0x01}, // +{0xEDD3,0x4A,0x01}, // +{0xEDD4,0xE1,0x01}, // +{0xEDD5,0x4A,0x01}, // +{0xEDD6,0x54,0x01}, // +{0xEDD7,0xD0,0x01}, // +{0xEDD8,0xF2,0x01}, // +{0xEDD9,0x16,0x01}, // +{0xEDDA,0xCA,0x01}, // +{0xEDDB,0x68,0x01}, // +{0xEDDC,0xE6,0x01}, // +{0xEDDD,0x39,0x01}, // +{0xEDDE,0xB5,0x01}, // +{0xEDDF,0x91,0x01}, // +{0xEDE0,0x8F,0x01}, // +{0xEDE1,0x7F,0x01}, // +{0xEDE2,0x96,0x01}, // +{0xEDE3,0xD4,0x01}, // +{0xEDE4,0x9D,0x01}, // +{0xEDE5,0x10,0x01}, // +{0xEDE6,0xB9,0x01}, // +{0xEDE7,0xC6,0x01}, // +{0xEDE8,0x3C,0x01}, // +{0xEDE9,0x92,0x01}, // +{0xEDEA,0x11,0x01}, // +{0xEDEB,0x0E,0x01}, // +{0xEDEC,0x62,0x01}, // +{0xEDED,0x68,0x01}, // +{0xEDEE,0xD3,0x01}, // +{0xEDEF,0x18,0x01}, // +{0xEDF0,0xDF,0x01}, // +{0xEDF1,0x90,0x01}, // +{0xEDF2,0x46,0x01}, // +{0xEDF3,0x3C,0x01}, // +{0xEDF4,0xCD,0x01}, // +{0xEDF5,0xA9,0x01}, // +{0xEDF6,0x10,0x01}, // +{0xEDF7,0x7A,0x01}, // +{0xEDF8,0x70,0x01}, // +{0xEDF9,0xA4,0x01}, // +{0xEDFA,0xA3,0x01}, // +{0xEDFB,0x4B,0x01}, // +{0xEDFC,0x81,0x01}, // +{0xEDFD,0x48,0x01}, // +{0xEDFE,0x4F,0x01}, // +{0xEDFF,0xF5,0x01}, // +{0xEE00,0x21,0x01}, // +{0xEE01,0x52,0x01}, // +{0xEE02,0x76,0x01}, // +{0xEE03,0x4C,0x01}, // +{0xEE04,0xA4,0x01}, // +{0xEE05,0x1C,0x01}, // +{0xEE06,0x0B,0x01}, // +{0xEE07,0x4D,0x01}, // +{0xEE08,0x27,0x01}, // +{0xEE09,0x44,0x01}, // +{0xEE0A,0xE8,0x01}, // +{0xEE0B,0x01,0x01}, // +{0xEE0C,0x12,0x01}, // +{0xEE0D,0x84,0x01}, // +{0xEE0E,0xE2,0x01}, // +{0xEE0F,0x64,0x01}, // +{0xEE10,0x22,0x01}, // +{0xEE11,0x43,0x01}, // +{0xEE12,0xE5,0x01}, // +{0xEE13,0xC8,0x01}, // +{0xEE14,0x52,0x01}, // +{0xEE15,0x36,0x01}, // +{0xEE16,0xA2,0x01}, // +{0xEE17,0x94,0x01}, // +{0xEE18,0x85,0x01}, // +{0xEE19,0xE0,0x01}, // +{0xEE1A,0xA4,0x01}, // +{0xEE1B,0x9F,0x01}, // +{0xEE1C,0x2A,0x01}, // +{0xEE1D,0xA1,0x01}, // +{0xEE1E,0x67,0x01}, // +{0xEE1F,0x48,0x01}, // +{0xEE20,0xF1,0x01}, // +{0xEE21,0x69,0x01}, // +{0xEE22,0x12,0x01}, // +{0xEE23,0x82,0x01}, // +{0xEE24,0xD8,0x01}, // +{0xEE25,0x74,0x01}, // +{0xEE26,0x22,0x01}, // +{0xEE27,0x47,0x01}, // +{0xEE28,0xB5,0x01}, // +{0xEE29,0xE8,0x01}, // +{0xEE2A,0x51,0x01}, // +{0xEE2B,0x0B,0x01}, // +{0xEE2C,0xDA,0x01}, // +{0xEE2D,0x50,0x01}, // +{0xEE2E,0x80,0x01}, // +{0xEE2F,0x2A,0x01}, // +{0xEE30,0xB4,0x01}, // +{0xEE31,0x1D,0x01}, // +{0xEE32,0xF7,0x01}, // +{0xEE33,0x14,0x01}, // +{0xEE34,0xE7,0x01}, // +{0xEE35,0x3A,0x01}, // +{0xEE36,0xBA,0x01}, // +{0xEE37,0x49,0x01}, // +{0xEE38,0xCE,0x01}, // +{0xEE39,0x70,0x01}, // +{0xEE3A,0xA2,0x01}, // +{0xEE3B,0x43,0x01}, // +{0xEE3C,0x1D,0x01}, // +{0xEE3D,0xF4,0x01}, // +{0xEE3E,0xD4,0x01}, // +{0xEE3F,0x47,0x01}, // +{0xEE40,0x41,0x01}, // +{0xEE41,0xFE,0x01}, // +{0xEE42,0x89,0x01}, // +{0xEE43,0x10,0x01}, // +{0xEE44,0x83,0x01}, // +{0xEE45,0x38,0x01}, // +{0xEE46,0xF4,0x01}, // +{0xEE47,0x1E,0x01}, // +{0xEE48,0x00,0x01}, // +{0xEE49,0x1D,0x01}, // +{0xEE4A,0xA7,0x01}, // +{0xEE4B,0x3A,0x01}, // +{0xEE4C,0xB1,0x01}, // +{0xEE4D,0xE9,0x01}, // +{0xEE4E,0xCD,0x01}, // +{0xEE4F,0x69,0x01}, // +{0xEE50,0x60,0x01}, // +{0xEE51,0x03,0x01}, // +{0xEE52,0x9B,0x01}, // +{0xEE53,0xDC,0x01}, // +{0xEE54,0x04,0x01}, // +{0xEE55,0xC7,0x01}, // +{0xEE56,0x39,0x01}, // +{0xEE57,0xE5,0x01}, // +{0xEE58,0x99,0x01}, // +{0xEE59,0x4F,0x01}, // +{0xEE5A,0x7F,0x01}, // +{0xEE5B,0x16,0x01}, // +{0xEE5C,0xB4,0x01}, // +{0xEE5D,0x1C,0x01}, // +{0xEE5E,0xED,0x01}, // +{0xEE5F,0xD0,0x01}, // +{0xEE60,0x66,0x01}, // +{0xEE61,0x38,0x01}, // +{0xEE62,0x90,0x01}, // +{0xEE63,0xD9,0x01}, // +{0xEE64,0xCC,0x01}, // +{0xEE65,0x5C,0x01}, // +{0xEE66,0xF6,0x01}, // +{0xEE67,0xC2,0x01}, // +{0xEE68,0x96,0x01}, // +{0xEE69,0xB8,0x01}, // +{0xEE6A,0xC4,0x01}, // +{0xEE6B,0xE5,0x01}, // +{0xEE6C,0x2E,0x01}, // +{0xEE6D,0x8C,0x01}, // +{0xEE6E,0xA1,0x01}, // +{0xEE6F,0xCC,0x01}, // +{0xEE70,0x6B,0x01}, // +{0xEE71,0x72,0x01}, // +{0xEE72,0x03,0x01}, // +{0xEE73,0x9C,0x01}, // +{0xEE74,0xE5,0x01}, // +{0xEE75,0x90,0x01}, // +{0xEE76,0x26,0x01}, // +{0xEE77,0x36,0x01}, // +{0xEE78,0x87,0x01}, // +{0xEE79,0x99,0x01}, // +{0xEE7A,0x0C,0x01}, // +{0xEE7B,0x57,0x01}, // +{0xEE7C,0xC8,0x01}, // +{0xEE7D,0x02,0x01}, // +{0xEE7E,0x14,0x01}, // +{0xEE7F,0xA2,0x01}, // +{0xEE80,0xDC,0x01}, // +{0xEE81,0x24,0x01}, // +{0xEE82,0x27,0x01}, // +{0xEE83,0x3F,0x01}, // +{0xEE84,0x01,0x01}, // +{0xEE85,0x8A,0x01}, // +{0xEE86,0x56,0x01}, // +{0xEE87,0xBC,0x01}, // +{0xEE88,0x12,0x01}, // +{0xEE89,0x18,0x01}, // +{0xEE8A,0xC4,0x01}, // +{0xEE8B,0x5C,0x01}, // +{0xEE8C,0x26,0x01}, // +{0xEE8D,0x34,0x01}, // +{0xEE8E,0x87,0x01}, // +{0xEE8F,0x91,0x01}, // +{0xEE90,0xCC,0x01}, // +{0xEE91,0x5A,0x01}, // +{0xEE92,0xE8,0x01}, // +{0xEE93,0xA2,0x01}, // +{0xEE94,0x13,0x01}, // +{0xEE95,0xA0,0x01}, // +{0xEE96,0x70,0x01}, // +{0xEE97,0xC4,0x01}, // +{0xEE98,0x23,0x01}, // +{0xEE99,0x10,0x01}, // +{0xEE9A,0x89,0x01}, // +{0xEE9B,0x08,0x01}, // +{0xEE9C,0x47,0x01}, // +{0xEE9D,0x34,0x01}, // +{0xEE9E,0x72,0x01}, // +{0xEE9F,0x93,0x01}, // +{0xEEA0,0x9C,0x01}, // +{0xEEA1,0x8C,0x01}, // +{0xEEA2,0x25,0x01}, // +{0xEEA3,0x2D,0x01}, // +{0xEEA4,0x7B,0x01}, // +{0xEEA5,0x29,0x01}, // +{0xEEA6,0x4C,0x01}, // +{0xEEA7,0x60,0x01}, // +{0xEEA8,0x12,0x01}, // +{0xEEA9,0xE3,0x01}, // +{0xEEAA,0x95,0x01}, // +{0xEEAB,0xB1,0x01}, // +{0xEEAC,0xA4,0x01}, // +{0xEEAD,0x84,0x01}, // +{0xEEAE,0x25,0x01}, // +{0xEEAF,0x0A,0x01}, // +{0xEEB0,0x61,0x01}, // +{0xEEB1,0x08,0x01}, // +{0xEEB2,0x40,0x01}, // +{0xEEB3,0x00,0x01}, // +{0xEEB4,0xB2,0x01}, // +{0xEEB5,0x90,0x01}, // +{0xEEB6,0x84,0x01}, // +{0xEEB7,0x94,0x01}, // +{0xEEB8,0x84,0x01}, // +{0xEEB9,0x24,0x01}, // +{0xEEBA,0x53,0x01}, // +{0xEEBB,0xB1,0x01}, // +{0xEEBC,0x0A,0x01}, // +{0xEEBD,0x5C,0x01}, // +{0xEEBE,0xF0,0x01}, // +{0xEEBF,0x52,0x01}, // +{0xEEC0,0x98,0x01}, // +{0xEEC1,0xC5,0x01}, // +{0xEEC2,0x84,0x01}, // +{0xEEC3,0xC5,0x01}, // +{0xEEC4,0x2C,0x01}, // +{0xEEC5,0x2D,0x01}, // +{0xEEC6,0x79,0x01}, // +{0xEEC7,0x89,0x01}, // +{0xEEC8,0x43,0x01}, // +{0xEEC9,0x1C,0x01}, // +{0xEECA,0x32,0x01}, // +{0xEECB,0x10,0x01}, // +{0xEECC,0x81,0x01}, // +{0xEECD,0x30,0x01}, // +{0xEECE,0x64,0x01}, // +{0xEECF,0x21,0x01}, // +{0xEED0,0x27,0x01}, // +{0xEED1,0x31,0x01}, // +{0xEED2,0x09,0x01}, // +{0xEED3,0x55,0x01}, // +{0xEED4,0xAE,0x01}, // +{0xEED5,0x22,0x01}, // +{0xEED6,0x17,0x01}, // +{0xEED7,0xBD,0x01}, // +{0xEED8,0x50,0x01}, // +{0xEED9,0x26,0x01}, // +{0xEEDA,0x33,0x01}, // +{0xEEDB,0x78,0x01}, // +{0xEEDC,0xD9,0x01}, // +{0xEEDD,0x8B,0x01}, // +{0xEEDE,0x51,0x01}, // +{0xEEDF,0x8E,0x01}, // +{0xEEE0,0x62,0x01}, // +{0xEEE1,0x12,0x01}, // +{0xEEE2,0x93,0x01}, // +{0xEEE3,0x64,0x01}, // +{0xEEE4,0x24,0x01}, // +{0xEEE5,0x23,0x01}, // +{0xEEE6,0x22,0x01}, // +{0xEEE7,0x11,0x01}, // +{0xEEE8,0x89,0x01}, // +{0xEEE9,0x4F,0x01}, // +{0xEEEA,0x7E,0x01}, // +{0xEEEB,0x92,0x01}, // +{0xEEEC,0x96,0x01}, // +{0xEEED,0xB7,0x01}, // +{0xEEEE,0x00,0x01}, // +{0xEEEF,0x46,0x01}, // +{0xEEF0,0x31,0x01}, // +{0xEEF1,0xB8,0x01}, // +{0xEEF2,0xC9,0x01}, // +{0xEEF3,0x0D,0x01}, // +{0xEEF4,0x67,0x01}, // +{0xEEF5,0x38,0x01}, // +{0xEEF6,0x13,0x01}, // +{0xEEF7,0x97,0x01}, // +{0xEEF8,0xB7,0x01}, // +{0xEEF9,0x48,0x01}, // +{0xEEFA,0x25,0x01}, // +{0xEEFB,0x2A,0x01}, // +{0xEEFC,0x47,0x01}, // +{0xEEFD,0x31,0x01}, // +{0xEEFE,0x0A,0x01}, // +{0xEEFF,0x53,0x01}, // +{0xEF00,0x9A,0x01}, // +{0xEF01,0x22,0x01}, // +{0xEF02,0x16,0x01}, // +{0xEF03,0xB4,0x01}, // +{0xEF04,0x1C,0x01}, // +{0xEF05,0x26,0x01}, // +{0xEF06,0x32,0x01}, // +{0xEF07,0x9D,0x01}, // +{0xEF08,0x61,0x01}, // +{0xEF09,0xCD,0x01}, // +{0xEF0A,0x79,0x01}, // +{0xEF0B,0xCE,0x01}, // +{0xEF0C,0xE3,0x01}, // +{0xEF0D,0x9C,0x01}, // +{0xEF0E,0xE7,0x01}, // +{0xEF0F,0x9C,0x01}, // +{0xEF10,0x06,0x01}, // +{0xEF11,0x35,0x01}, // +{0xEF12,0x8B,0x01}, // +{0xEF13,0x61,0x01}, // +{0xEF14,0x4C,0x01}, // +{0xEF15,0x60,0x01}, // +{0xEF16,0x04,0x01}, // +{0xEF17,0x23,0x01}, // +{0xEF18,0x18,0x01}, // +{0xEF19,0xC4,0x01}, // +{0xEF1A,0x5C,0x01}, // +{0xEF1B,0x46,0x01}, // +{0xEF1C,0x34,0x01}, // +{0xEF1D,0xB7,0x01}, // +{0xEF1E,0x31,0x01}, // +{0xEF1F,0x0E,0x01}, // +{0xEF20,0x72,0x01}, // +{0xEF21,0xB4,0x01}, // +{0xEF22,0x73,0x01}, // +{0xEF23,0xA2,0x01}, // +{0xEF24,0x15,0x01}, // +{0xEF25,0x41,0x01}, // +{0xEF26,0x88,0x01}, // +{0xEF27,0x42,0x01}, // +{0xEF28,0xE6,0x01}, // +{0xEF29,0x59,0x01}, // +{0xEF2A,0x0F,0x01}, // +{0xEF2B,0x73,0x01}, // +{0xEF2C,0xA4,0x01}, // +{0xEF2D,0xD3,0x01}, // +{0xEF2E,0x9B,0x01}, // +{0xEF2F,0xE2,0x01}, // +{0xEF30,0x08,0x01}, // +{0xEF31,0xC7,0x01}, // +{0xEF32,0x39,0x01}, // +{0xEF33,0xD4,0x01}, // +{0xEF34,0x19,0x01}, // +{0xEF35,0x0F,0x01}, // +{0xEF36,0x7E,0x01}, // +{0xEF37,0x18,0x01}, // +{0xEF38,0xA4,0x01}, // +{0xEF39,0x20,0x01}, // +{0xEF3A,0x10,0x01}, // +{0xEF3B,0x89,0x01}, // +{0xEF3C,0xA8,0x01}, // +{0xEF3D,0x44,0x01}, // +{0xEF3E,0x25,0x01}, // +{0xEF3F,0x52,0x01}, // +{0xEF40,0x11,0x01}, // +{0xEF41,0x81,0x01}, // +{0xEF42,0x16,0x01}, // +{0xEF43,0xB4,0x01}, // +{0xEF44,0x9E,0x01}, // +{0xEF45,0xF8,0x01}, // +{0xEF46,0x64,0x01}, // +{0xEF47,0x67,0x01}, // +{0xEF48,0x3C,0x01}, // +{0xEF49,0xDF,0x01}, // +{0xEF4A,0x61,0x01}, // +{0xEF4B,0x8F,0x01}, // +{0xEF4C,0x7C,0x01}, // +{0xEF4D,0x04,0x01}, // +{0xEF4E,0xF4,0x01}, // +{0xEF4F,0x20,0x01}, // +{0xEF50,0x11,0x01}, // +{0xEF51,0x35,0x01}, // +{0xEF52,0x88,0x01}, // +{0xEF53,0x43,0x01}, // +{0xEF54,0x2E,0x01}, // +{0xEF55,0x5A,0x01}, // +{0xEF56,0x11,0x01}, // +{0xEF57,0x82,0x01}, // +{0xEF58,0xCE,0x01}, // +{0xEF59,0x93,0x01}, // +{0xEF5A,0x9D,0x01}, // +{0xEF5B,0xF1,0x01}, // +{0xEF5C,0xF0,0x01}, // +{0xEF5D,0x47,0x01}, // +{0xEF5E,0x44,0x01}, // +{0xEF5F,0x28,0x01}, // +{0xEF60,0xAA,0x01}, // +{0xEF61,0x51,0x01}, // +{0xEF62,0x86,0x01}, // +{0xEF63,0xDA,0x01}, // +{0xEF64,0xD3,0x01}, // +{0xEF65,0x1C,0x01}, // +{0xEF66,0xE0,0x01}, // +{0xEF67,0x24,0x01}, // +{0xEF68,0x87,0x01}, // +{0xEF69,0x3C,0x01}, // +{0xEF6A,0x11,0x01}, // +{0xEF6B,0x52,0x01}, // +{0xEF6C,0xD1,0x01}, // +{0xEF6D,0x7B,0x01}, // +{0xEF6E,0xA6,0x01}, // +{0xEF6F,0x63,0x01}, // +{0xEF70,0x9A,0x01}, // +{0xEF71,0xC0,0x01}, // +{0xEF72,0xD4,0x01}, // +{0xEF73,0x65,0x01}, // +{0xEF74,0x2F,0x01}, // +{0xEF75,0x9F,0x01}, // +{0xEF76,0x69,0x01}, // +{0xEF77,0x0E,0x01}, // +{0xEF78,0x79,0x01}, // +{0xEF79,0x82,0x01}, // +{0xEF7A,0xC3,0x01}, // +{0xEF7B,0x99,0x01}, // +{0xEF7C,0xB3,0x01}, // +{0xEF7D,0x0C,0x01}, // +{0xEF7E,0xE5,0x01}, // +{0xEF7F,0x26,0x01}, // +{0xEF80,0x3E,0x01}, // +{0xEF81,0xF9,0x01}, // +{0xEF82,0x0A,0x01}, // +{0xEF83,0x65,0x01}, // +{0xEF84,0x6C,0x01}, // +{0xEF85,0xE3,0x01}, // +{0xEF86,0x19,0x01}, // +{0xEF87,0xBD,0x01}, // +{0xEF88,0xFC,0x01}, // +{0xEF89,0x84,0x01}, // +{0xEF8A,0x23,0x01}, // +{0xEF8B,0x0E,0x01}, // +{0xEF8C,0xC9,0x01}, // +{0xEF8D,0x08,0x01}, // +{0xEF8E,0x4E,0x01}, // +{0xEF8F,0xE0,0x01}, // +{0xEF90,0x12,0x01}, // +{0xEF91,0x99,0x01}, // +{0xEF92,0xC9,0x01}, // +{0xEF93,0x9C,0x01}, // +{0xEF94,0x85,0x01}, // +{0xEF95,0x25,0x01}, // +{0xEF96,0x0C,0x01}, // +{0xEF97,0x01,0x01}, // +{0xEF98,0x48,0x01}, // +{0xEF99,0x42,0x01}, // +{0xEF9A,0x4C,0x01}, // +{0xEF9B,0xD2,0x01}, // +{0xEF9C,0x15,0x01}, // +{0xEF9D,0xC2,0x01}, // +{0xEF9E,0x5C,0x01}, // +{0xEF9F,0x86,0x01}, // +{0xEFA0,0x2D,0x01}, // +{0xEFA1,0x31,0x01}, // +{0xEFA2,0x79,0x01}, // +{0xEFA3,0xC8,0x01}, // +{0xEFA4,0x40,0x01}, // +{0xEFA5,0x1A,0x01}, // +{0xEFA6,0xA2,0x01}, // +{0xEFA7,0x12,0x01}, // +{0xEFA8,0xB0,0x01}, // +{0xEFA9,0x1C,0x01}, // +{0xEFAA,0x86,0x01}, // +{0xEFAB,0x35,0x01}, // +{0xEFAC,0x87,0x01}, // +{0xEFAD,0x61,0x01}, // +{0xEFAE,0x0A,0x01}, // +{0xEFAF,0x4A,0x01}, // +{0xEFB0,0x36,0x01}, // +{0xEFB1,0x52,0x01}, // +{0xEFB2,0x92,0x01}, // +{0xEFB3,0xA2,0x01}, // +{0xEFB4,0xF0,0x01}, // +{0xEFB5,0x85,0x01}, // +{0xEFB6,0x33,0x01}, // +{0xEFB7,0xD7,0x01}, // +{0xEFB8,0x91,0x01}, // +{0xEFB9,0x0D,0x01}, // +{0xEFBA,0x5F,0x01}, // +{0xEFBB,0xB2,0x01}, // +{0xEFBC,0xD2,0x01}, // +{0xEFBD,0x94,0x01}, // +{0xEFBE,0xAA,0x01}, // +{0xEFBF,0xD4,0x01}, // +{0xEFC0,0xC5,0x01}, // +{0xEFC1,0x34,0x01}, // +{0xEFC2,0xC5,0x01}, // +{0xEFC3,0x71,0x01}, // +{0xEFC4,0xD0,0x01}, // +{0xEFC5,0x7B,0x01}, // +{0xEFC6,0x80,0x01}, // +{0xEFC7,0xD3,0x01}, // +{0xEFC8,0x19,0x01}, // +{0xEFC9,0xC9,0x01}, // +{0xEFCA,0x60,0x01}, // +{0xEFCB,0x46,0x01}, // +{0xEFCC,0x37,0x01}, // +{0xEFCD,0xE4,0x01}, // +{0xEFCE,0xD9,0x01}, // +{0xEFCF,0x4F,0x01}, // +{0xEFD0,0x95,0x01}, // +{0xEFD1,0x7A,0x01}, // +{0xEFD2,0xE4,0x01}, // +{0xEFD3,0xA0,0x01}, // +{0xEFD4,0xF9,0x01}, // +{0xEFD5,0x90,0x01}, // +{0xEFD6,0xA7,0x01}, // +{0xEFD7,0x3D,0x01}, // +{0xEFD8,0x07,0x01}, // +{0xEFD9,0x92,0x01}, // +{0xEFDA,0x11,0x01}, // +{0xEFDB,0x91,0x01}, // +{0xEFDC,0x92,0x01}, // +{0xEFDD,0x04,0x01}, // +{0xEFDE,0xA5,0x01}, // +{0xEFDF,0x19,0x01}, // +{0xEFE0,0x69,0x01}, // +{0xEFE1,0x28,0x01}, // +{0xEFE2,0x41,0x01}, // +{0xEFE3,0x11,0x01}, // +{0xEFE4,0x5A,0x01}, // +{0xEFE5,0xD1,0x01}, // +{0xEFE6,0x91,0x01}, // +{0xEFE7,0x80,0x01}, // +{0xEFE8,0x04,0x01}, // +{0xEFE9,0x69,0x01}, // +{0xEFEA,0x00,0x01}, // +{0xEFEB,0x00,0x01}, // +{0xEFEC,0x19,0x01}, // +{0xEFED,0x26,0x01}, // +{0x6C32,0x1478,0x02}, // SHD_INP_TH_HB_H_R2 +{0x6C34,0x13B0,0x02}, // SHD_INP_TH_HB_L_R2 +{0x6C36,0x10CC,0x02}, // SHD_INP_TH_LB_H_R2 +{0x6C38,0x1004,0x02}, // SHD_INP_TH_LB_L_R2 +{0x6C3C,0x0000,0x02}, // SHD_INP_TH_HB_H_RB +{0x6C3E,0x0000,0x02}, // SHD_INP_TH_HB_L_RB +{0x6C40,0x0000,0x02}, // SHD_INP_TH_LB_H_RB +{0x6C42,0x0000,0x02}, // SHD_INP_TH_LB_L_RB + +{0x6804,0x11DA,0x02}, // NORMR +{0x6806,0x10AB,0x02}, // NORMB +{0x6808,0x0147,0x02}, // AWBPRER +{0x680A,0x0226,0x02}, // AWBPREB +{0x6810,0x10A8,0x02}, // AWB_PRE_ADJ_RG +{0x6812,0x0F8F,0x02}, // AWB_PRE_ADJ_BG +{0x6814,0x0AD9,0x02}, // AWB_C14_RG +{0x6816,0x1701,0x02}, // AWB_C14_BG + +//PreWB_offset +{0x6828,0x0013,0x02}, // SHD_PRER_OFFSET_R2 : + +// CXC/SHD EN +{0x01BC,0x57,0x01}, // CXC ON SHD ON INP ON GAIN OFF +}; + +/* + auto focus +*/ +isx012_short_t isx012_af_cancel[] = +{ +{0x00B2,0x03,0x01}, //AFMODE_MONI : AF OFF +}; + +isx012_short_t isx012_af_macro_off[] = +{ +{0x0081,0x00,0x01}, //MODESEL : Monitoring mode +{0x6648,0x0100,0x02}, //AF_MANUAL_POS : MANUA AF search start position +{0x028E,0x00,0x01}, //AF_SEARCH_DIR : NEAR->FAR +{0x00B1,0x01,0x01}, //AF_RESTART_F +}; + +isx012_short_t isx012_af_macro_on[] = +{ +{0x0081,0x00,0x01}, //MODESEL : Monitoring mode +{0x6648,0x03DE,0x02}, //AF_MANUAL_POS : MANUA AF search start position +{0x028E,0x01,0x01}, //AF_SEARCH_DIR : NEAR->FAR +{0x00B1,0x01,0x01}, //AF_RESTART_F +}; + +isx012_short_t isx012_af_saf[] = +{ +{0x00B2,0x00,0x01}, //AFMODE_MONI : Single AF mode +}; + +isx012_short_t isx012_af_saf_off[] = +{ +{0x0081,0x00,0x01}, //MODESEL : Monitoring mode +{0x00B2,0x02,0x01}, //AFMODE_MONI : Manual AF mode +}; + +/* + brightness +*/ +isx012_short_t isx012_brightness_m1[] = +{ +{0x01C6,0xFF,0x01}, +}; + +isx012_short_t isx012_brightness_m2[] = +{ +{0x01C6,0xFD,0x01}, +}; + +isx012_short_t isx012_brightness_m3[] = +{ +{0x01C6,0xFC,0x01}, +}; + +isx012_short_t isx012_brightness_m4[] = +{ +{0x01C6,0xFA,0x01}, +}; + +isx012_short_t isx012_brightness_0[] = +{ +{0x01C6,0x00,0x01},//UIBRIGHTNESS +}; + +isx012_short_t isx012_brightness_p1[] = +{ +{0x01C6,0x01,0x01}, +}; + +isx012_short_t isx012_brightness_p2[] = +{ +{0x01C6,0x03,0x01}, +}; + +isx012_short_t isx012_brightness_p3[] = +{ +{0x01C6,0x04,0x01}, +}; + +isx012_short_t isx012_brightness_p4[] = +{ +{0x01C6,0x06,0x01}, +}; + +isx012_short_t isx012_contrast_n1[] = +{ +{0x01C7,0x6C,0x01} +}; + +isx012_short_t isx012_contrast_n2[] = +{ +{0x01C7,0x58,0x01} +}; + +isx012_short_t isx012_contrast_0[] = +{ +{0x01C7,0x80,0x01},//UICONTRAST +}; + +isx012_short_t isx012_contrast_p1[] = +{ +{0x01C7,0x94,0x01}, +}; + +isx012_short_t isx012_contrast_p2[] = +{ +{0x01C7,0xA8,0x01}, +}; + + + +/* + Effect +*/ +isx012_short_t isx012_effect_pastel[] = +{ +{0x01C5,0x05,0x01}, +}; + +isx012_short_t isx012_effect_monotone[] = +{ +{0x01C5,0x04,0x01}, +}; + +isx012_short_t isx012_effect_negative[] = +{ +{0x01C5,0x02,0x01}, +}; + +isx012_short_t isx012_effect_normal[] = +{ +{0x01C5,0x00,0x01}, +}; + +isx012_short_t isx012_effect_sepia[] = +{ +{0x01C5,0x03,0x01}, +}; + + + + + +isx012_short_t isx012_photometry_center[] = +{ +{0x02AC,0x01,0x01}, +}; + +isx012_short_t isx012_photometry_average[] = +{ +{0x02AC,0x00,0x01}, +}; + +isx012_short_t isx012_photometry_spot[] = +{ +{0x02AC,0x02,0x01}, +}; + + +/* + Exposure Value +*/ +isx012_short_t isx012_ev_m1[] = +{ +{0x0180,0xFF,0x01}, +}; + +isx012_short_t isx012_ev_m2[] = +{ +{0x0180,0xFE,0x01}, +}; + +isx012_short_t isx012_ev_m3[] = +{ +{0x0180,0xFD,0x01}, +}; + +isx012_short_t isx012_ev_m4[] = +{ +{0x0180,0xFC,0x01}, +}; + +isx012_short_t isx012_ev_0[] = +{ +{0x0180,0x00,0x01}, +}; + +isx012_short_t isx012_ev_p1[] = +{ +{0x0180,0x01,0x01}, +}; + +isx012_short_t isx012_ev_p2[] = +{ +{0x0180,0x02,0x01}, +}; + +isx012_short_t isx012_ev_p3[] = +{ +{0x0180,0x03,0x01}, +}; + +isx012_short_t isx012_ev_p4[] = +{ +{0x0180,0x04,0x01}, +}; + +/* + iso +*/ +isx012_short_t isx012_iso_50[] = +{ +{0x02A8,0x04,0x01}, +}; + +isx012_short_t isx012_iso_100[] = +{ +{0x02A8,0x07,0x01}, +}; + +isx012_short_t isx012_iso_200[] = +{ +{0x02A8,0x0A,0x01}, +}; + +isx012_short_t isx012_iso_400[] = +{ +{0x02A8,0x0D,0x01}, +}; + +isx012_short_t isx012_iso_800[] = +{ +{0x02A8,0x10,0x01}, +}; + +isx012_short_t isx012_iso_auto[] = +{ +{0x02A8,0x00,0x01}, +}; + +/* + Saturation +*/ +isx012_short_t isx012_saturation_n1[] = +{ +{0x039E,0x62,0x01}, +}; + +isx012_short_t isx012_saturation_n2[] = +{ +{0x039E,0x44,0x01}, +}; + +isx012_short_t isx012_saturation_0[] = +{ +{0x039E,0x80,0x01}, +}; + +isx012_short_t isx012_saturation_p1[] = +{ +{0x039E,0x9E,0x01}, +}; + +isx012_short_t isx012_saturation_p2[] = +{ +{0x039E,0xBC,0x01}, +}; + +/* + Sharpness +*/ +isx012_short_t isx012_sharpness_n1[] = +{ +{0x00A1,0x14,0x01},//UISHARPNESS_POS_TYPE1 +{0x00A4,0x14,0x01},//UISHARPNESS_NEG_TYPE1 +}; + +isx012_short_t isx012_sharpness_n2[] = +{ +{0x00A1,0x08,0x01},//UISHARPNESS_POS_TYPE1 +{0x00A4,0x08,0x01},//UISHARPNESS_NEG_TYPE1 +}; + +isx012_short_t isx012_sharpness_0[] = +{ +{0x00A1,0x20,0x01},//UISHARPNESS_POS_TYPE1 +{0x00A4,0x20,0x01},//UISHARPNESS_NEG_TYPE1 +}; + +isx012_short_t isx012_sharpness_p1[] = +{ +{0x00A1,0x2C,0x01},//UISHARPNESS_POS_TYPE1 +{0x00A4,0x2C,0x01},//UISHARPNESS_NEG_TYPE1 +}; + +isx012_short_t isx012_sharpness_p2[] = +{ +{0x00A1,0x38,0x01},//UISHARPNESS_POS_TYPE1 +{0x00A4,0x38,0x01},//UISHARPNESS_NEG_TYPE1 +}; + +/* + Scene +*/ +isx012_short_t isx012_scene_auto[] = +{ +{0x0280,0x00,0x01}, +}; + +isx012_short_t isx012_scene_landscape[] = +{ +{0x0280,0x01,0x01}, +}; + +isx012_short_t isx012_scene_sports[] = +{ +{0x0280,0x02,0x01}, +}; + + +isx012_short_t isx012_scene_indoor[] = +{ +{0x0280,0x03,0x01}, +}; + +isx012_short_t isx012_scene_beachsnow[] = +{ +{0x0280,0x04,0x01}, +}; + +isx012_short_t isx012_scene_sunset[] = +{ +{0x0280,0x05,0x01}, +}; + +isx012_short_t isx012_scene_portrait[] = +{ +{0x0280,0x06,0x01}, +}; + +isx012_short_t isx012_scene_nightmode[] = +{ +{0x0280,0x07,0x01}, +}; + +isx012_short_t isx012_scene_firework[] = +{ +{0x0280,0x08,0x01}, +}; + +isx012_short_t isx012_scene_document[] = +{ +{0x0280,0x09,0x01}, +}; + +isx012_short_t isx012_scene_backlight[] = +{ +{0x0280,0x10,0x01}, +}; + +isx012_short_t isx012_scene_movie[] = +{ +{0x0280,0x11,0x01}, +}; + +/* + Whitebalance +*/ +isx012_short_t isx012_wb_auto[] = +{ +{0x625F,0x75,0x01},//CAT_AWB_1 +{0x0282,0x20,0x01},//AWB_SN1 +}; + +isx012_short_t isx012_wb_clody[] = +{ +{0x625F,0x35,0x01},//CAT_AWB_1 +{0x0282,0x26,0x01},//AWB_SN1 +}; + +isx012_short_t isx012_wb_daylight[] = +{ +{0x625F,0x35,0x01},//CAT_AWB_1 +{0x0282,0x25,0x01},//AWB_SN1 +}; + +isx012_short_t isx012_wb_fluorescent[] = +{ +{0x625F,0x35,0x01},//CAT_AWB_1 +{0x0282,0x27,0x01},//AWB_SN1 +}; + +isx012_short_t isx012_wb_incandescent[] = +{ +{0x625F,0x35,0x01},//CAT_AWB_1 +{0x0282,0x28,0x01},//AWB_SN1 +}; + + +/* + JPEG quality +*/ +isx012_short_t isx012_jpeg_standard[] = +{ +{0x00F6,0x00,0x01},//JPG_QLTY +}; + +isx012_short_t isx012_jpeg_fine[] = +{ +{0x00F6,0x01,0x01},//JPG_QLTY +}; + +isx012_short_t isx012_jpeg_superfine[] = +{ +{0x00F6,0x02,0x01},//JPG_QLTY +}; + +isx012_short_t isx012_quality_table[] = +{ +{0x00F7,0x4F,0x01}, // INIT_QLTY0 +{0x00F8,0x56,0x01}, // INIT_QLTY1 +{0x00F9,0x5C,0x01}, // INIT_QLTY2 +}; + +/* + capture size +*/ +isx012_short_t isx012_capture_mode[] = +{ +{0x0081,0x02,0x01},//MODESEL +{0x0082,0x01,0x01},//MONI_REFRESH +}; + +isx012_short_t isx012_capture_size_5M[] = // 2592x1944 +{ +{0x0081,0x02,0x01},//MODESEL +{0x0082,0x01,0x01},//MONI_REFRESH +}; + +/* + preview size +*/ +isx012_short_t isx012_preview_mode[] = +{ +{0x0089,0x00,0x01},//OUTFMT_MONI +{0x0083,0x01,0x01},//SENSMODE_MONI +{0x0086,0x02,0x01},//FPSTYPE_MONI +{0x0081,0x00,0x01},//MODESEL +{0x0082,0x01,0x01},//MONI_REFRESH +}; + +isx012_short_t isx012_preview_size_VGA[] = +{ +{0x0090,0x0280,0x02},//HSIZE_MONI : 640 +{0x0096,0x01E0,0x02},//VSIZE_MONI : 480 +}; + + +#endif diff --git a/drivers/media/video/msm_zsl/isx012_v4l2.c b/drivers/media/video/msm_zsl/isx012_v4l2.c new file mode 100644 index 00000000000..7296d962872 --- /dev/null +++ b/drivers/media/video/msm_zsl/isx012_v4l2.c @@ -0,0 +1,1687 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "msm.h" +#include "isx012.h" +#include "isx012_regs.h" +#include "msm.h" +#include "msm_ispif.h" + + +#undef CONFIG_LOAD_FILE + +#ifdef CONFIG_LOAD_FILE + +#include +#include +#include +#include +#include + +static char *isx012_regs_table; +static int isx012_regs_table_size; +static int isx012_write_regs_from_sd(char *name); +#endif + +#define ISX012_WRITE_LIST(A) \ + isx012_i2c_write_list(A, (sizeof(A) / sizeof(A[0])), #A); + +#define MOVIEMODE_FLASH 17 +#define FLASHMODE_FLASH 18 + +#define ERROR 1 + +#define IN_AUTO_MODE 1 +#define IN_MACRO_MODE 2 + +struct isx012_work { + struct work_struct work; +}; + +static struct isx012_work *isx012_sensorw; +static struct i2c_client *isx012_client; + +struct isx012_ctrl { + const struct msm_camera_sensor_info *sensordata; + struct isx012_userset settings; + + struct v4l2_subdev *sensor_dev; + + int op_mode; + int dtp_mode; + int app_mode; + int cam_mode; + int vtcall_mode; + int started; + int isCapture; + int flash_mode; + int lowLight; + int dtpTest; +}; + +static unsigned int config_csi2; +static struct isx012_ctrl *isx012_ctrl; + +struct isx012_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; +static int32_t isx012_sensor_setting(int update_type, int rt); +static DECLARE_WAIT_QUEUE_HEAD(isx012_wait_queue); + +/** + * isx012_i2c_read_multi: Read (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * @r_data: buffer where data is read + * @r_len: number of bytes to read + * + * Returns 0 on success, <0 on error + */ + +static int isx012_i2c_read_multi(unsigned short subaddr, unsigned long *data) +{ + unsigned char buf[4]; + struct i2c_msg msg = {isx012_client->addr, 0, 2, buf}; + + int err = 0; + + if (!isx012_client->adapter) + return -EIO; + + buf[0] = subaddr >> 8; + buf[1] = subaddr & 0xff; + + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (unlikely(err < 0)) + return -EIO; + + msg.flags = I2C_M_RD; + msg.len = 4; + + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (unlikely(err < 0)) + return -EIO; + + /* + * Data comes in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + *data = *(unsigned long *)(&buf); + + return err; +} + + +/** + * isx012_i2c_read: Read (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @data: data to be read + * + * Returns 0 on success, <0 on error + */ +static int isx012_i2c_read(unsigned short subaddr, unsigned short *data) +{ + unsigned char buf[2]; + struct i2c_msg msg = {isx012_client->addr, 0, 2, buf}; + + int err = 0; + + if (!isx012_client->adapter) + return -EIO; + + buf[0] = subaddr >> 8; + buf[1] = subaddr & 0xff; + + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (unlikely(err < 0)) + return -EIO; + + msg.flags = I2C_M_RD; + + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (unlikely(err < 0)) + return -EIO; + + /* + * Data comes in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + *data = *(unsigned short *)(&buf); + + return err; +} + +/** + * isx012_i2c_write_multi: Write (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * + * Returns 0 on success, <0 on error + */ +static int isx012_i2c_write_multi(unsigned short addr, +unsigned int w_data, unsigned int w_len) +{ + unsigned char buf[w_len+2]; + struct i2c_msg msg = {isx012_client->addr, 0, w_len+2, buf}; + + int retry_count = 5; + int err = 0; + + if (!isx012_client->adapter) + return -EIO; + + buf[0] = addr >> 8; + buf[1] = addr & 0xff; + + /* + * Data should be written in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + if (w_len == 1) + buf[2] = (unsigned char)w_data; + else if (w_len == 2) + *((unsigned short *)&buf[2]) = (unsigned short)w_data; + else + *((unsigned int *)&buf[2]) = w_data; + + while (retry_count--) { + err = i2c_transfer(isx012_client->adapter, &msg, 1); + if (likely(err == 1)) + break; + } + + return (err == 1) ? 0 : -EIO; +} + +static int isx012_i2c_write_list(struct isx012_short_t regs[], int size, + char *name) +{ +#ifdef CONFIG_LOAD_FILE + isx012_write_regs_from_sd(name); +#else + int err = 0; + int i = 0; + +/* printk(KERN_DEBUG "[isx012] %s, %d\n", __func__, __LINE__);*/ + + if (!isx012_client->adapter) { + printk(KERN_ERR "%s: %d can't search i2c client adapter\n", + __func__, __LINE__); + return -EIO; + } + + for (i = 0; i < size; i++) { + if (regs[i].subaddr == 0xFFFF) { + msleep(regs[i].value); + printk(KERN_DEBUG "delay 0x%04x, value 0x%04x\n", + regs[i].subaddr, regs[i].value); + } else { + err = isx012_i2c_write_multi(regs[i].subaddr, + regs[i].value, regs[i].len); + + if (unlikely(err < 0)) { + printk(KERN_ERR "%s: register set failed\n", + __func__); + return -EIO; + } + } + } +#endif + + return 0; +} + +#ifdef CONFIG_LOAD_FILE +void isx012_regs_table_init(void) +{ + struct file *filp; + char *dp; + long l; + loff_t pos; + int ret; + mm_segment_t fs = get_fs(); + + printk(KERN_DEBUG "%s %d\n", __func__, __LINE__); + + set_fs(get_ds()); + + filp = filp_open("/mnt/sdcard/isx012_regs.h", O_RDONLY, 0); + + if (IS_ERR_OR_NULL(filp)) { + printk(KERN_DEBUG "file open error\n"); + return PTR_ERR(filp); + } + + l = filp->f_path.dentry->d_inode->i_size; + printk(KERN_DEBUG "l = %ld\n", l); + dp = vmalloc(l); + if (dp == NULL) { + printk(KERN_DEBUG "Out of Memory\n"); + filp_close(filp, current->files); + } + + pos = 0; + memset(dp, 0, l); + ret = vfs_read(filp, (char __user *)dp, l, &pos); + + if (ret != l) { + printk(KERN_DEBUG "Failed to read file ret = %d\n", ret); + /*kfree(dp);*/ + vfree(dp); + filp_close(filp, current->files); + return -EINVAL; + } + + filp_close(filp, current->files); + + set_fs(fs); + + isx012_regs_table = dp; + + isx012_regs_table_size = l; + + *((isx012_regs_table + isx012_regs_table_size) - 1) = '\0'; + + printk(KERN_DEBUG "isx012_reg_table_init\n"); + return 0; +} + + +void isx012_regs_table_exit(void) +{ + printk(KERN_DEBUG "%s %d\n", __func__, __LINE__); + + if (isx012_regs_table) { + vfree(isx012_regs_table); + isx012_regs_table = NULL; + } +} + +static int isx012_write_regs_from_sd(char *name) +{ + char *start, *end, *reg, *size; + unsigned short addr; + unsigned int len, value; + char reg_buf[7], data_buf1[5], data_buf2[7], len_buf[5]; + + *(reg_buf + 6) = '\0'; + *(data_buf1 + 4) = '\0'; + *(data_buf2 + 6) = '\0'; + *(len_buf + 4) = '\0'; + + printk(KERN_DEBUG "isx012_regs_table_write start!\n"); + printk(KERN_DEBUG "E string = %s\n", name); + + start = strstr(isx012_regs_table, name); + end = strstr(start, "};"); + + while (1) { + /* Find Address */ + reg = strstr(start, "{0x"); + + if ((reg == NULL) || (reg > end)) + break; + + /* Write Value to Address */ + if (reg != NULL) { + memcpy(reg_buf, (reg + 1), 6); + memcpy(data_buf2, (reg + 9), 6); + size = strstr(data_buf2, ","); + if (size) { /* 1 byte write */ + memcpy(data_buf1, (reg + 9), 4); + memcpy(len_buf, (reg + 15), 4); + kstrtoint(reg_buf, 16, &addr); + kstrtoint(data_buf1, 16, &value); + kstrtoint(len_buf, 16, &len); + if (reg) + start = (reg + 22); + } else {/* 2 byte write */ + memcpy(len_buf, (reg + 17), 4); + kstrtoint(reg_buf, 16, &addr); + kstrtoint(data_buf2, 16, &value); + kstrtoint(len_buf, 16, &len); + if (reg) + start = (reg + 24); + } + size = NULL; + printk(KERN_DEBUG "delay 0x%04x, value 0x%04x, , len 0x%02x\n", + addr, value, len); + if (addr == 0xFFFF) + msleep(value); + else + isx012_i2c_write_multi(addr, value, len); + } + } + + printk(KERN_DEBUG "isx005_regs_table_write end!\n"); + + return 0; +} +#endif + + +static int isx012_get_LowLightCondition() +{ + int err = -1; + short unsigned int r_data2[2] = {0, 0}; + unsigned char l_data[2] = {0, 0}, h_data[2] = {0, 0}; + unsigned int LowLight_value = 0; + unsigned int ldata_temp = 0, hdata_temp = 0; + + unsigned short read_val = 0; + int read_val2; + err = isx012_i2c_read(0x01A5, &read_val); + LowLight_value = 0x00FF & read_val; + + if (err < 0) + pr_err("%s: isx012_get_LowLightCondition() returned error, %d\n" + , __func__, err); + + CAM_DEBUG("auto iso %d, read_val = 0x%x LowLight_value = 0x%x\n", + isx012_ctrl->settings.iso, read_val, LowLight_value); + if (isx012_ctrl->settings.iso == CAMERA_ISO_MODE_AUTO) { /*auto iso*/ + if (LowLight_value >= LOWLIGHT_DEFAULT) + isx012_ctrl->lowLight = 1; + else + isx012_ctrl->lowLight = 0; + } else { /*manual iso*/ + err = isx012_i2c_read_multi(0x019C, l_data); /*SHT_TIME_OUT_L*/ + ldata_temp = (l_data[1] << 8 | l_data[0]); + + err = isx012_i2c_read(0x019E, h_data); /*SHT_TIME_OUT_H*/ + hdata_temp = (h_data[1] << 8 | h_data[0]); + CAM_DEBUG("ldata_temp = 0x%x, hdata_temp = 0x%x", + ldata_temp, hdata_temp); + LowLight_value = (h_data[1] << 24 | h_data[0] << 16 | + l_data[1] << 8 | l_data[0]); + + switch (isx012_ctrl->settings.iso) { + case CAMERA_ISO_MODE_100: + if (LowLight_value >= LOWLIGHT_ISO100) + isx012_ctrl->lowLight = 1; + else + isx012_ctrl->lowLight = 0; + break; + + case CAMERA_ISO_MODE_200: + if (LowLight_value >= LOWLIGHT_ISO200) + isx012_ctrl->lowLight = 1; + else + isx012_ctrl->lowLight = 0; + break; + + case CAMERA_ISO_MODE_400: + if (LowLight_value >= LOWLIGHT_ISO400) + isx012_ctrl->lowLight = 1; + else + isx012_ctrl->lowLight = 0; + break; + + default: + printk(KERN_DEBUG "[ISX012][%s:%d] invalid iso[%d]\n", + __func__, __LINE__, isx012_ctrl->settings.iso); + break; + + } + } + CAM_DEBUG("lowLight : %d\n", isx012_ctrl->lowLight); + + return err; +} + + +void isx012_mode_transtion_OM(void) +{ + int count = 0; + int status = 0; + + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + for (count = 0; count < 100 ; count++) { + isx012_i2c_read(0x000E, (unsigned short *)&status); + printk(KERN_DEBUG "[isx012] 0x000E (1) read : %x\n", status); + + if ((status & 0x1) == 0x1) + break; + + usleep(1*1000); + } + isx012_i2c_write_multi(0x0012, 0x01, 0x01); + + for (count = 0; count < 100 ; count++) { + isx012_i2c_read(0x000E, (unsigned short *)&status); + + printk(KERN_DEBUG "[isx012] 0x000E (2) read : %x\n", status); + + if ((status & 0x1) == 0x0) + break; + + usleep(1*1000); + } +} + + +void isx012_mode_transtion_CM(void) +{ + int count = 0; + int status = 0; + + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + for (count = 0; count < 100 ; count++) { + isx012_i2c_read(0x000E, (unsigned short *)&status); + + printk(KERN_DEBUG "[isx012] 0x000E (1) read : %x\n", status); + + if ((status & 0x2) == 0x2) + break; + + usleep(1*1000); + } + isx012_i2c_write_multi(0x0012, 0x02, 0x01); + + for (count = 0; count < 100 ; count++) { + isx012_i2c_read(0x000E, (unsigned short *)&status); + + printk(KERN_DEBUG "[isx012] 0x000E (2) read : %x\n", status); + + if ((status & 0x2) == 0x0) + break; + + usleep(1*1000); + } +} + +void isx012_Sensor_Calibration(void) +{ + int count = 0; + int status = 0; + int temp = 0; + + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + +/* Read OTP1 */ + isx012_i2c_read(0x004F, (unsigned short *)&status); + printk(KERN_DEBUG "0x004F read : %x\n", status); + + if ((status & 0x1) == 0x1) { + /* Read ShadingTable */ + isx012_i2c_read(0x005C, (unsigned short *)&status); + temp = (status&0x03C0)>>6; + printk(KERN_DEBUG "Read ShadingTable read : %x\n", temp); + + /* Write Shading Table */ + if (temp == 0x0) { + printk(KERN_DEBUG "ISX012_Shading_0\n"); + ISX012_WRITE_LIST(ISX012_Shading_0); + } else if (temp == 0x1) { + printk(KERN_DEBUG "ISX012_Shading_1\n"); + ISX012_WRITE_LIST(ISX012_Shading_1); + } else if (temp == 0x2) { + printk(KERN_DEBUG "ISX012_Shading_2\n"); + ISX012_WRITE_LIST(ISX012_Shading_2); + } + + /* Write NorR */ + isx012_i2c_read(0x0054, (unsigned short *)&status); + temp = status&0x3FFF; + printk(KERN_DEBUG "NorR read : %x\n", temp); + isx012_i2c_write_multi(0x6804, temp, 0x02); + + /* Write NorB */ + isx012_i2c_read(0x0056, (unsigned short *)&status); + temp = status&0x3FFF; + printk(KERN_DEBUG "NorB read : %x\n", temp); + isx012_i2c_write_multi(0x6806, temp, 0x02); + + /* Write PreR */ + isx012_i2c_read(0x005A, (unsigned short *)&status); + temp = (status&0x0FFC)>>2; + printk(KERN_DEBUG "PreR read : %x\n", temp); + isx012_i2c_write_multi(0x6808, temp, 0x02); + + /* Write PreB */ + isx012_i2c_read(0x005B, (unsigned short *)&status); + temp = (status&0x3FF0)>>4; + printk(KERN_DEBUG "PreB read : %x\n", temp); + isx012_i2c_write_multi(0x680A, temp, 0x02); + } else { + /* Read OTP0 */ + isx012_i2c_read(0x0040, (unsigned short *)&status); + printk(KERN_DEBUG "0x0040 read : %x\n", status); + + if ((status & 0x1) == 0x1) { + /* Read ShadingTable */ + isx012_i2c_read(0x004D, (unsigned short *)&status); + temp = (status&0x03C0)>>6; + printk(KERN_DEBUG "Read ShadingTable read : %x\n", + temp); + + /* Write Shading Table */ + if (temp == 0x0) { + printk(KERN_DEBUG "ISX012_Shading_0\n"); + ISX012_WRITE_LIST(ISX012_Shading_0); + } else if (temp == 0x1) { + printk(KERN_DEBUG "ISX012_Shading_1\n"); + ISX012_WRITE_LIST(ISX012_Shading_1); + } else if (temp == 0x2) { + printk(KERN_DEBUG "ISX012_Shading_2\n"); + ISX012_WRITE_LIST(ISX012_Shading_2); + } + + /* Write NorR */ + isx012_i2c_read(0x0045, (unsigned short *)&status); + temp = status&0x3FFF; + printk(KERN_DEBUG "NorR read : %x\n", temp); + isx012_i2c_write_multi(0x6804, temp, 0x02); + + /* Write NorB */ + isx012_i2c_read(0x0047, (unsigned short *)&status); + temp = status&0x3FFF; + printk(KERN_DEBUG "NorB read : %x\n", temp); + isx012_i2c_write_multi(0x6806, temp, 0x02); + + /* Write PreR */ + isx012_i2c_read(0x004B, (unsigned short *)&status); + temp = (status&0x0FFC)>>2; + printk(KERN_DEBUG "PreR read : %x\n", temp); + isx012_i2c_write_multi(0x6808, temp, 0x02); + + /* Write PreB */ + isx012_i2c_read(0x004C, (unsigned short *)&status); + temp = (status&0x3FF0)>>4; + printk(KERN_DEBUG "PreB read : %x\n", temp); + isx012_i2c_write_multi(0x680A, temp, 0x02); + } else + ISX012_WRITE_LIST(ISX012_Shading_Nocal); + } +} + +void isx012_jpeg_update(void) +{ + int count = 0; + int status = 0; + + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + for (count = 0; count < 100 ; count++) { + isx012_i2c_read(0x000E, (unsigned short *)&status); + printk(KERN_DEBUG "[isx012] 0x000E (1) %d read : %x\n", + count, status); + + if ((status & 0x4) == 0x4) + break; + + usleep(1*1000); + } + isx012_i2c_write_multi(0x0012, 0x04, 0x01); + for (count = 0; count < 100 ; count++) { + isx012_i2c_read(0x000E, (unsigned short *)&status); + printk(KERN_DEBUG "[isx012] 0x000E (2) read : %x\n", status); + + if ((status & 0x4) == 0x0) + break; + + usleep(1*1000); + } +} + +static int isx012_sensor_af_status(void) +{ + int ret = 0; + int status = 0; + + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + isx012_i2c_read(0x8B8A, (unsigned short *)&status); + if ((status & 0x8) == 0x8) { + ret = 1; + printk(KERN_DEBUG "[isx012] success\n"); + } + + return ret; +} + +static int isx012_sensor_af_result(void) +{ + int ret = 0; + int status = 0; + + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + isx012_i2c_read(0x8B8B, (unsigned short *)&status); + if ((status & 0x1) == 0x1) { + printk(KERN_DEBUG "[isx012] AF success\n"); + ret = 1; + } else if ((status & 0x1) == 0x0) { + printk(KERN_DEBUG "[isx012] AF fail\n"); + ret = 2; + } + return ret; +} + +static void isx012_set_flash(int lux_val) +{ + int i = 0; + printk(KERN_DEBUG "%s, flash set is %d, %d\n", + __func__, lux_val, isx012_ctrl->flash_mode); + + if (isx012_ctrl->flash_mode == 0) + return; + + if (lux_val == MOVIEMODE_FLASH) { + printk(KERN_DEBUG "[ASWOOGI] FLASH MOVIE MODE\n"); + gpio_set_value_cansleep( + isx012_ctrl->sensordata + ->sensor_platform_info->flash_en, 0); + + for (i = 5; i > 1; i--) { + gpio_set_value_cansleep( + isx012_ctrl->sensordata + ->sensor_platform_info->flash_set, 1); + udelay(1); + gpio_set_value_cansleep( + isx012_ctrl->sensordata + ->sensor_platform_info->flash_set, 0); + udelay(1); + } + gpio_set_value_cansleep( + isx012_ctrl->sensordata + ->sensor_platform_info->flash_set, 1); + usleep(2*1000); + } else if (lux_val == FLASHMODE_FLASH) { + printk(KERN_DEBUG "[ASWOOGI] FLASH ON : %d\n", lux_val); + gpio_set_value_cansleep( + isx012_ctrl->sensordata + ->sensor_platform_info->flash_en, 1); + gpio_set_value_cansleep( + isx012_ctrl->sensordata + ->sensor_platform_info->flash_set, 0); + } else { + printk(KERN_DEBUG "[ASWOOGI] FLASH OFF\n"); + gpio_set_value_cansleep( + isx012_ctrl->sensordata + ->sensor_platform_info->flash_en, 0); + gpio_set_value_cansleep( + isx012_ctrl->sensordata + ->sensor_platform_info->flash_set, 0); + } +} + +void isx012_set_preview(void) +{ + /*printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__);*/ + CAM_DEBUG("cam_mode = %d", isx012_ctrl->cam_mode); + + if (isx012_ctrl->cam_mode == MOVIE_MODE) { + ISX012_WRITE_LIST(ISX012_Camcorder_Mode); + } else { + ISX012_WRITE_LIST(ISX012_Preview_Mode); + } + isx012_mode_transtion_CM(); +} + +void isx012_set_capture(void) +{ + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + ISX012_WRITE_LIST(ISX012_Capture_SizeSetting); + + isx012_get_LowLightCondition(); + + if ((isx012_ctrl->flash_mode == CAMERA_FLASH_AUTO && + isx012_ctrl->lowLight) || + isx012_ctrl->flash_mode == CAMERA_FLASH_ON) { + isx012_set_flash(FLASHMODE_FLASH); + } + + ISX012_WRITE_LIST(ISX012_Capture_Mode); + + isx012_mode_transtion_CM(); + +/*frame capture*/ + isx012_ctrl->isCapture = 1; +} + +static int32_t isx012_sensor_setting(int update_type, int rt) +{ + int32_t rc = 0; + struct msm_camera_csid_params isx012_csid_params; + struct msm_camera_csiphy_params isx012_csiphy_params; + + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + switch (update_type) { + case REG_INIT: + break; + + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + printk(KERN_DEBUG "[isx012] UPDATE_PERIODIC\n"); + + v4l2_subdev_notify(isx012_ctrl->sensor_dev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_OFF_IMMEDIATELY)); + + /* stop streaming */ + printk(KERN_DEBUG "[isx012] change standby state\n"); + isx012_i2c_write_multi(0x0005, 0x01, 0x01); + + msleep(100); + + if (config_csi2 == 0) { + struct msm_camera_csid_vc_cfg isx012_vccfg[] = { + {0, 0x1E, CSI_DECODE_8BIT}, + {1, CSI_EMBED_DATA, CSI_DECODE_8BIT}, + }; + isx012_csid_params.lane_cnt = 2; + isx012_csid_params.lane_assign = 0xe4; + isx012_csid_params.lut_params.num_cid = + ARRAY_SIZE(isx012_vccfg); + isx012_csid_params.lut_params.vc_cfg = + &isx012_vccfg[0]; + isx012_csiphy_params.lane_cnt = 2; + isx012_csiphy_params.settle_cnt = 0x5; + v4l2_subdev_notify(isx012_ctrl->sensor_dev, + NOTIFY_CSID_CFG, + &isx012_csid_params); + v4l2_subdev_notify(isx012_ctrl->sensor_dev, + NOTIFY_CID_CHANGE, NULL); + mb(); + v4l2_subdev_notify(isx012_ctrl->sensor_dev, + NOTIFY_CSIPHY_CFG, + &isx012_csiphy_params); + mb(); + /*isx012_delay_msecs_stdby*/ + msleep(100); + config_csi2 = 1; + } + + if (rc < 0) + return rc; + + v4l2_subdev_notify(isx012_ctrl->sensor_dev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_ON_FRAME_BOUNDARY)); + + /*start stream*/ + printk(KERN_DEBUG "[isx012] change stream state\n"); + isx012_i2c_write_multi(0x0005, 0x00, 0x01); + + msleep(100); + + } + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static int32_t isx012_video_config(int mode) +{ + int32_t rc = 0; + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + if (isx012_sensor_setting(UPDATE_PERIODIC, RES_PREVIEW) < 0) + return rc; + return rc; +} + +static long isx012_set_sensor_mode(int mode) +{ + printk(KERN_DEBUG "[isx012] %s : %d /%d\n", __func__, mode, __LINE__); + + switch (mode) { + case SENSOR_PREVIEW_MODE: + case SENSOR_VIDEO_MODE: + isx012_set_flash(0); + + if (isx012_ctrl->isCapture == 1) { + isx012_ctrl->isCapture = 0; + isx012_set_preview(); + } + + isx012_video_config(mode); + break; + + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + isx012_set_flash(FLASHMODE_FLASH); + isx012_set_capture(); + break; + + default: + return 0; + } + return 0; +} + +static int isx012_set_effect(int effect) +{ + switch (effect) { + case CAMERA_EFFECT_OFF: + ISX012_WRITE_LIST(ISX012_Effect_Normal); + break; + + case CAMERA_EFFECT_MONO: + ISX012_WRITE_LIST(ISX012_Effect_Monotone); + break; + + case CAMERA_EFFECT_NEGATIVE: + ISX012_WRITE_LIST(ISX012_Effect_Negative); + break; + + case CAMERA_EFFECT_SEPIA: + ISX012_WRITE_LIST(ISX012_Effect_Sepia); + break; + + case CAMERA_EFFECT_WHITEBOARD: + ISX012_WRITE_LIST(ISX012_Effect_Pastel); + break; + + default: + printk(KERN_DEBUG "[isx012] default effect\n"); + ISX012_WRITE_LIST(ISX012_Effect_Normal); + return 0; + } + + return 0; +} + +static int isx012_set_whitebalance(int wb) +{ + switch (wb) { + case CAMERA_WHITE_BALANCE_AUTO: + ISX012_WRITE_LIST(ISX012_WB_Auto); + break; + + case CAMERA_WHITE_BALANCE_INCANDESCENT: + ISX012_WRITE_LIST(ISX012_WB_Incandescent); + break; + + case CAMERA_WHITE_BALANCE_FLUORESCENT: + ISX012_WRITE_LIST(ISX012_WB_Fluorescent); + break; + + case CAMERA_WHITE_BALANCE_DAYLIGHT: + ISX012_WRITE_LIST(ISX012_WB_Daylight); + break; + + case CAMERA_WHITE_BALANCE_CLOUDY_DAYLIGHT: + ISX012_WRITE_LIST(ISX012_WB_Cloudy); + break; + + default: + printk(KERN_DEBUG "[isx012] unexpected WB mode %s/%d\n", + __func__, __LINE__); + return 0; + } + return 0; +} +static void isx012_check_dataline(int val) +{ + if (val) { + printk(KERN_DEBUG "DTP ON\n"); + ISX012_WRITE_LIST(ISX012_DTP_Init); + isx012_ctrl->dtpTest = 1; + + } else { + printk(KERN_DEBUG "DTP OFF\n"); + ISX012_WRITE_LIST(ISX012_DTP_Stop); + isx012_ctrl->dtpTest = 0; + } +} + +static void isx012_set_ev(int ev) +{ + printk(KERN_DEBUG "[isx012] %s : %d\n", __func__, ev); + + switch (ev) { + case CAMERA_EV_M2: + ISX012_WRITE_LIST(ISX012_ExpSetting_M4Step); + break; + + case CAMERA_EV_M1: + ISX012_WRITE_LIST(ISX012_ExpSetting_M2Step); + break; + + case CAMERA_EV_DEFAULT: + ISX012_WRITE_LIST(ISX012_ExpSetting_Default); + break; + + case CAMERA_EV_P1: + ISX012_WRITE_LIST(ISX012_ExpSetting_P2Step); + break; + + case CAMERA_EV_P2: + ISX012_WRITE_LIST(ISX012_ExpSetting_P4Step); + break; + + default: + printk(KERN_DEBUG "[isx012] unexpected ev mode %s/%d\n", + __func__, __LINE__); + break; + } +} + +static void isx012_set_scene_mode(int mode) +{ + printk(KERN_DEBUG "[isx012] %s : %d\n", __func__, mode); + + switch (mode) { + case CAMERA_SCENE_AUTO: + ISX012_WRITE_LIST(ISX012_Scene_Auto); + break; + + case CAMERA_SCENE_LANDSCAPE: + ISX012_WRITE_LIST(ISX012_Scene_Landscape); + break; + + case CAMERA_SCENE_DAWN: + ISX012_WRITE_LIST(ISX012_Scene_Dawn); + break; + + case CAMERA_SCENE_BEACH: + ISX012_WRITE_LIST(ISX012_Scene_Beach_Snow); + break; + + case CAMERA_SCENE_SUNSET: + ISX012_WRITE_LIST(ISX012_Scene_Sunset); + break; + + case CAMERA_SCENE_NIGHT: + ISX012_WRITE_LIST(ISX012_Scene_Nightmode); + break; + + case CAMERA_SCENE_PORTRAIT: + ISX012_WRITE_LIST(ISX012_Scene_Portrait); + break; + + case CAMERA_SCENE_AGAINST_LIGHT: + ISX012_WRITE_LIST(ISX012_Scene_Backlight); + break; + + case CAMERA_SCENE_SPORT: + ISX012_WRITE_LIST(ISX012_Scene_Sports); + break; + + case CAMERA_SCENE_FALL: + ISX012_WRITE_LIST(ISX012_Scene_Fallcolor); + break; + + case CAMERA_SCENE_TEXT: + ISX012_WRITE_LIST(ISX012_Scene_Document); + break; + + case CAMERA_SCENE_CANDLE: + ISX012_WRITE_LIST(ISX012_Scene_CandleLight); + break; + + case CAMERA_SCENE_FIRE: + ISX012_WRITE_LIST(ISX012_Scene_Firework); + break; + + case CAMERA_SCENE_PARTY: + ISX012_WRITE_LIST(ISX012_Scene_Indoor); + break; + + default: + printk(KERN_DEBUG "[isx012] unexpected scene mode %s/%d\n", + __func__, __LINE__); + break; + } +} + +static void isx012_set_iso(int iso) +{ + printk(KERN_DEBUG "[isx012] %s : %d\n", __func__, iso); + + switch (iso) { + case CAMERA_ISO_MODE_AUTO: + ISX012_WRITE_LIST(ISX012_ISO_AUTO); + break; + + case CAMERA_ISO_MODE_100: + ISX012_WRITE_LIST(ISX012_ISO_100); + break; + + case CAMERA_ISO_MODE_200: + ISX012_WRITE_LIST(ISX012_ISO_200); + break; + + case CAMERA_ISO_MODE_400: + ISX012_WRITE_LIST(ISX012_ISO_400); + break; + + case CAMERA_ISO_MODE_800: + ISX012_WRITE_LIST(ISX012_ISO_800); + break; + + default: + printk(KERN_DEBUG "[isx012] unexpected iso mode %s/%d\n", + __func__, __LINE__); + break; + } + + isx012_ctrl->settings.iso = iso; +} + +static void isx012_set_metering(int mode) +{ + printk(KERN_DEBUG "[isx012] %s : %d\n", __func__, mode); + + switch (mode) { + case CAMERA_CENTER_WEIGHT: + ISX012_WRITE_LIST(ISX012_Potometry_CenterWeight); + break; + + case CAMERA_AVERAGE: + ISX012_WRITE_LIST(ISX012_Potometry_Average); + break; + + case CAMERA_SPOT: + ISX012_WRITE_LIST(ISX012_Potometry_Spot); + break; + + default: + printk(KERN_DEBUG "[isx012] unexpected metering mode %s/%d\n", + __func__, __LINE__); + break; + } +} + + +static int isx012_set_movie_mode(int mode) +{ + CAM_DEBUG("E"); + + if (mode == MOVIE_MODE) { + printk(KERN_DEBUG "isx012_set_movie_mode Camcorder_Mode_ON\n"); +/* ISX012_WRITE_LIST(ISX012_Camcorder_Mode_ON); + isx012_ctrl->status.camera_status = 1;*/ + } else { + /*isx012_ctrl->status.camera_status = 0;*/ + } +/* + if ((mode != SENSOR_CAMERA) && (mode != SENSOR_MOVIE)) { + return -EINVAL; + } +*/ + return 0; +} + + +static void isx012_set_focus(int mode) +{ + printk(KERN_DEBUG "[isx012] %s : %d\n", __func__, mode); + + switch (mode) { + case CAMERA_AF_AUTO: + ISX012_WRITE_LIST(ISX012_AF_Macro_OFF); + if (isx012_ctrl->settings.focus_mode == IN_MACRO_MODE) + ISX012_WRITE_LIST(ISX012_AF_ReStart); + isx012_ctrl->settings.focus_mode = IN_AUTO_MODE; + break; + + case CAMERA_AF_MACRO: + ISX012_WRITE_LIST(ISX012_AF_Macro_ON); + if (isx012_ctrl->settings.focus_mode == IN_AUTO_MODE) + ISX012_WRITE_LIST(ISX012_AF_ReStart); + isx012_ctrl->settings.focus_mode = IN_MACRO_MODE; + break; + + default: + printk(KERN_DEBUG "[isx012] unexpected focus mode %s/%d\n", + __func__, __LINE__); + break; + } +} + +static void isx012_set_preview_size(int32_t width) +{ + printk(KERN_DEBUG "width %d\n", width); + + if (width == 1920) { + printk(KERN_DEBUG "1920*1080\n"); + ISX012_WRITE_LIST(ISX012_1920_Preview_SizeSetting); + } else if (width == 1280) { + printk(KERN_DEBUG "1280*720\n"); + ISX012_WRITE_LIST(ISX012_1280_Preview_SizeSetting); + } else if (width == 800) { + printk(KERN_DEBUG "800*480\n"); + ISX012_WRITE_LIST(ISX012_800_Preview_SizeSetting); + } else if (width == 720) { + printk(KERN_DEBUG "720*480\n"); + ISX012_WRITE_LIST(ISX012_720_Preview_SizeSetting); + } else { + printk(KERN_DEBUG "640*480\n"); + ISX012_WRITE_LIST(ISX012_640_Preview_SizeSetting); + } + + ISX012_WRITE_LIST(ISX012_Preview_Mode); + isx012_mode_transtion_CM(); +} + +static int isx012_sensor_init_probe(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + int temp = 0; + + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + gpio_set_value_cansleep( + data->sensor_platform_info->vt_sensor_stby, 0); + temp = gpio_get_value(data->sensor_platform_info->vt_sensor_stby); + printk(KERN_DEBUG "[isx012] check VT standby : %d\n", temp); + usleep(10*1000); + + gpio_set_value_cansleep(data->sensor_platform_info->vt_sensor_reset, 0); + temp = gpio_get_value(data->sensor_platform_info->vt_sensor_reset); + printk(KERN_DEBUG "[isx012] check VT reset : %d\n", temp); + usleep(10*1000); + + gpio_set_value_cansleep(data->sensor_platform_info->sensor_reset, 0); + temp = gpio_get_value(data->sensor_platform_info->sensor_reset); + printk(KERN_DEBUG "[isx012] CAM_5M_RST : %d\n", temp); + + gpio_set_value_cansleep(data->sensor_platform_info->sensor_stby, 0); + temp = gpio_get_value(data->sensor_platform_info->sensor_stby); + printk(KERN_DEBUG "[isx012] CAM_5M_ISP_INIT : %d\n", temp); + + /*Power on the LDOs*/ + data->sensor_platform_info->sensor_power_on(0); + usleep(5*1000); + + /*standy VT*/ + gpio_set_value_cansleep( + data->sensor_platform_info->vt_sensor_stby, 1); + temp = gpio_get_value(data->sensor_platform_info->vt_sensor_stby); + printk(KERN_DEBUG "[isx012] check VT standby : %d\n", temp); + usleep(10*1000); + + + /*Set Main clock*/ + gpio_tlmm_config(GPIO_CFG( + data->sensor_platform_info->mclk, 1, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), GPIO_CFG_ENABLE); + msm_camio_clk_rate_set(24000000); + usleep(10*1000); + + + /*reset VT*/ + gpio_set_value_cansleep(data->sensor_platform_info->vt_sensor_reset, 1); + temp = gpio_get_value(data->sensor_platform_info->vt_sensor_reset); + printk(KERN_DEBUG "[isx012] check VT reset : %d\n", temp); + usleep(10*1000); + + /*off standy VT*/ + gpio_set_value_cansleep( + data->sensor_platform_info->vt_sensor_stby, 0); + temp = gpio_get_value(data->sensor_platform_info->vt_sensor_stby); + printk(KERN_DEBUG "[isx012] check VT standby : %d\n", temp); + usleep(10*1000); + + /*reset Main cam*/ + gpio_set_value_cansleep(data->sensor_platform_info->sensor_reset, 1); + temp = gpio_get_value(data->sensor_platform_info->sensor_reset); + printk(KERN_DEBUG "[isx012] CAM_5M_RST : %d\n", temp); + usleep(5*1000); + + /*I2C*/ + printk(KERN_DEBUG "[isx012] Mode Trandition 1\n"); + + isx012_mode_transtion_OM(); + + usleep(10*1000); + ISX012_WRITE_LIST(ISX012_Pll_Setting_3); + printk(KERN_DEBUG "[isx012] Mode Trandition 2\n"); + + usleep(10*1000); + + ISX012_WRITE_LIST(ISX012_Pll_Setting_4); + printk(KERN_DEBUG "[isx012] Mode Trandition 2\n"); + + usleep(10*1000); + + isx012_mode_transtion_OM(); + + printk(KERN_DEBUG "[isx012] MIPI write\n"); + + isx012_i2c_write_multi(0x5008, 0x00, 0x01); + isx012_Sensor_Calibration(); + ISX012_WRITE_LIST(ISX012_Init_Reg); + ISX012_WRITE_LIST(ISX012_Preview_SizeSetting); + ISX012_WRITE_LIST(ISX012_Preview_Mode); + + /*standby Main cam*/ + gpio_set_value_cansleep(data->sensor_platform_info->sensor_stby, 1); + temp = gpio_get_value(data->sensor_platform_info->sensor_stby); + printk(KERN_DEBUG "[isx012] CAM_5M_ISP_INIT : %d\n", temp); + msleep(20); + + isx012_mode_transtion_OM(); + + isx012_mode_transtion_CM(); + + msleep(50); + + return rc; +} + + +int isx012_sensor_init(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + if (!isx012_ctrl) { + printk(KERN_DEBUG "isx012_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + if (data) + isx012_ctrl->sensordata = data; + + isx012_ctrl->settings.iso = CAMERA_ISO_MODE_AUTO; + config_csi2 = 0; +#ifdef CONFIG_LOAD_FILE + isx012_regs_table_init(); +#endif + rc = isx012_sensor_init_probe(data); + if (rc < 0) { + printk(KERN_DEBUG "isx012_sensor_init failed!\n"); + goto init_fail; + } +init_done: + return rc; + +init_fail: + kfree(isx012_ctrl); + return rc; +} + +static int isx012_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&isx012_wait_queue); + return 0; +} + + +void sensor_native_control(void __user *arg) +{ + struct ioctl_native_cmd ctrl_info; + + /*printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__);*/ + + if (copy_from_user((void *)&ctrl_info, + (const void *)arg, sizeof(ctrl_info))) + printk(KERN_DEBUG + "[isx012] %s fail copy_from_user!\n", __func__); + + /*printk(KERN_DEBUG "[isx012] %d %d %d %d %d\n", + ctrl_info.mode, ctrl_info.address, ctrl_info.value_1, + ctrl_info.value_2, ctrl_info.value_3);*/ + + switch (ctrl_info.mode) { + case EXT_CAM_AF: + if (ctrl_info.address == 0) { + isx012_get_LowLightCondition(); + if ((isx012_ctrl->flash_mode == + CAMERA_FLASH_AUTO && isx012_ctrl->lowLight) || + isx012_ctrl->flash_mode == CAMERA_FLASH_ON) { + /*Flash On set*/ + ISX012_WRITE_LIST(ISX012_Flash_ON); + mdelay(40); + isx012_set_flash(MOVIEMODE_FLASH); + } + ISX012_WRITE_LIST(ISX012_Halfrelease_Mode); + } else if (ctrl_info.address == 1) { + ctrl_info.value_1 = isx012_sensor_af_status(); + if (ctrl_info.value_1 == 1) + isx012_i2c_write_multi(0x0012, 0x10, 0x01); + } else if (ctrl_info.address == 2) { + ctrl_info.value_1 = isx012_sensor_af_result(); + } + break; + + case EXT_CAM_FLASH: + if (ctrl_info.value_1 == 0) {/*off*/ + isx012_set_flash(0); + } else if (ctrl_info.value_1 == 1) {/*MOVIEMODE_FLASH*/ + isx012_set_flash(MOVIEMODE_FLASH); + } else if (ctrl_info.value_1 == 2) {/*FLASHMODE_FLASH*/ + isx012_set_flash(FLASHMODE_FLASH); + } + break; + + case EXT_CAM_FLASH_MODE: + isx012_ctrl->flash_mode = ctrl_info.value_1; + printk(KERN_DEBUG "[isx012] Flash mode : %d\n", + isx012_ctrl->flash_mode); + break; + + case EXT_CAM_EV: + isx012_set_ev(ctrl_info.value_1); + break; + + case EXT_CAM_EFFECT: + isx012_set_effect(ctrl_info.value_1); + break; + + case EXT_CAM_SCENE_MODE: + isx012_set_scene_mode(ctrl_info.value_1); + break; + + case EXT_CAM_ISO: + isx012_set_iso(ctrl_info.value_1); + break; + + case EXT_CAM_METERING: + isx012_set_metering(ctrl_info.value_1); + break; + + case EXT_CAM_WB: + isx012_set_whitebalance(ctrl_info.value_1); + break; + + case EXT_CAM_FOCUS: + isx012_set_focus(ctrl_info.value_1); + break; + + case EXT_CAM_PREVIEW_SIZE: + isx012_set_preview_size(ctrl_info.value_1); + break; + + case EXT_CAM_MOVIE_MODE: + CAM_DEBUG("MOVIE mode : %d", ctrl_info.value_1); + isx012_ctrl->cam_mode = ctrl_info.value_1; + + /* test code for movie mode*/ + ISX012_WRITE_LIST(ISX012_Camcorder_Mode); + break; + + case EXT_CAM_DTP_TEST: + isx012_check_dataline(ctrl_info.value_1); + break; + + default: + printk(KERN_DEBUG "[isx012] default mode\n"); + break; + } + + if (copy_to_user((void *)arg, + (const void *)&ctrl_info, sizeof(ctrl_info))) + printk(KERN_DEBUG "[isx012] %s fail copy_to_user!\n", __func__); +} + + +int isx012_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cfg_data; + long rc = 0; + + if (copy_from_user(&cfg_data, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + printk(KERN_DEBUG "[isx012] isx012_ioctl, cfgtype = %d, mode = %d\n", + cfg_data.cfgtype, cfg_data.mode); + + switch (cfg_data.cfgtype) { + case CFG_SET_MODE: + rc = isx012_set_sensor_mode( + cfg_data.mode); + break; + + case CFG_GET_AF_MAX_STEPS: + default: + rc = 0; + printk(KERN_DEBUG "isx012_sensor_config : Invalid cfgtype ! %d\n", + cfg_data.cfgtype); + break; + } + + return rc; +} + +int isx012_sensor_release(void) +{ + int rc = 0; + int temp = 0; + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + /*power off the LDOs*/ + isx012_ctrl->sensordata->sensor_platform_info->sensor_power_off(0); + + /*reset VT*/ + gpio_set_value_cansleep( + isx012_ctrl->sensordata->sensor_platform_info->vt_sensor_reset, + 0); + temp = gpio_get_value( + isx012_ctrl->sensordata->sensor_platform_info->vt_sensor_reset); + printk(KERN_DEBUG "[isx012] check VT reset : %d\n", temp); + usleep(10*1000); + + /*standy VT*/ + gpio_set_value_cansleep( + isx012_ctrl->sensordata->sensor_platform_info->vt_sensor_stby, + 0); + temp = gpio_get_value( + isx012_ctrl->sensordata->sensor_platform_info->vt_sensor_stby); + printk(KERN_DEBUG "[isx012] check VT standby : %d\n", temp); + usleep(10*1000); + + /*reset Main cam*/ + gpio_set_value_cansleep( + isx012_ctrl->sensordata->sensor_platform_info->sensor_reset, 0); + temp = gpio_get_value( + isx012_ctrl->sensordata->sensor_platform_info->sensor_reset); + printk(KERN_DEBUG "[isx012] CAM_5M_RST : %d\n", temp); + + /*standby Main cam*/ + gpio_set_value_cansleep( + isx012_ctrl->sensordata->sensor_platform_info->sensor_stby, 0); + temp = gpio_get_value( + isx012_ctrl->sensordata->sensor_platform_info->sensor_stby); + printk(KERN_DEBUG "[isx012] CAM_5M_ISP_INIT : %d\n", temp); + + /*I2C*/ + +#ifdef CONFIG_LOAD_FILE + isx012_regs_table_exit(); +#endif + return rc; +} + +static int isx012_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + rc = -ENOTSUPP; + goto probe_failure; + } + + isx012_sensorw = + kzalloc(sizeof(struct isx012_work), GFP_KERNEL); + + if (!isx012_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, isx012_sensorw); + isx012_init_client(client); + isx012_client = client; + + + printk(KERN_DEBUG "isx012_probe succeeded!\n"); + + return 0; + +probe_failure: + kfree(isx012_sensorw); + isx012_sensorw = NULL; + printk(KERN_DEBUG "isx012_probe failed!\n"); + return rc; +} + +static const struct i2c_device_id isx012_i2c_id[] = { + { "isx012", 0}, + { }, +}; + +static struct i2c_driver isx012_i2c_driver = { + .id_table = isx012_i2c_id, + .probe = isx012_i2c_probe, + .remove = __exit_p(isx012_i2c_remove), + .driver = { + .name = "isx012", + }, +}; + + +static int isx012_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = i2c_add_driver(&isx012_i2c_driver); + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + if (rc < 0 || isx012_client == NULL) { + rc = -ENOTSUPP; + goto probe_done; + } + + msm_camio_clk_rate_set(24000000); + + s->s_init = isx012_sensor_init; + s->s_release = isx012_sensor_release; + s->s_config = isx012_sensor_config; + s->s_camera_type = BACK_CAMERA_2D; + s->s_mount_angle = 90; + + +probe_done: + printk(KERN_DEBUG "%s %s:%d\n", __FILE__, __func__, __LINE__); + return rc; +} + + +static struct isx012_format isx012_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static int isx012_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + printk(KERN_DEBUG "Index is %d\n", index); + if ((unsigned int)index >= ARRAY_SIZE(isx012_subdev_info)) + return -EINVAL; + + *code = isx012_subdev_info[index].code; + return 0; +} + +static struct v4l2_subdev_core_ops isx012_subdev_core_ops; +static struct v4l2_subdev_video_ops isx012_subdev_video_ops = { + .enum_mbus_fmt = isx012_enum_fmt, +}; + +static struct v4l2_subdev_ops isx012_subdev_ops = { + .core = &isx012_subdev_core_ops, + .video = &isx012_subdev_video_ops, +}; + +static int isx012_sensor_probe_cb(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + int rc = 0; + printk(KERN_DEBUG "[isx012] %s/%d\n", __func__, __LINE__); + + rc = isx012_sensor_probe(info, s); + if (rc < 0) + return rc; + + isx012_ctrl = kzalloc(sizeof(struct isx012_ctrl), GFP_KERNEL); + if (!isx012_ctrl) { + printk(KERN_DEBUG "isx012_sensor_probe failed!\n"); + return -ENOMEM; + } + + /* probe is successful, init a v4l2 subdevice */ + if (sdev) { + v4l2_i2c_subdev_init(sdev, isx012_client, + &isx012_subdev_ops); + isx012_ctrl->sensor_dev = sdev; + } else { + printk(KERN_DEBUG "[isx012] sdev is null in probe_cb\n"); + } + return rc; +} + +static int __isx012_probe(struct platform_device *pdev) +{ + printk(KERN_DEBUG "############# ISX012 probe ##############\n"); + + return msm_sensor_register(pdev, isx012_sensor_probe_cb); +} + +static struct platform_driver msm_camera_driver = { + .probe = __isx012_probe, + .driver = { + .name = "msm_camera_isx012", + .owner = THIS_MODULE, + }, +}; + +static int __init isx012_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(isx012_init); diff --git a/drivers/media/video/msm_zsl/msm.c b/drivers/media/video/msm_zsl/msm.c new file mode 100755 index 00000000000..76bf93119b3 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm.c @@ -0,0 +1,2855 @@ +/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm.h" + +/* extern void sensor_native_control_front(void __user *arg);aswoogi_zsl */ + +#define MSM_MAX_CAMERA_SENSORS 5 + +#ifdef CONFIG_MSM_CAMERA_DEBUG +#define D(fmt, args...) pr_debug("msm: " fmt, ##args) +#else +#define D(fmt, args...) do {} while (0) +#endif + +static unsigned msm_camera_v4l2_nr = -1; +static struct msm_cam_server_dev g_server_dev; +static struct class *msm_class; +static dev_t msm_devno; +static int vnode_count; + +module_param(msm_camera_v4l2_nr, uint, 0644); +MODULE_PARM_DESC(msm_camera_v4l2_nr, "videoX start number, -1 is autodetect"); + +static int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle, + struct video_device *pvdev); + +static void msm_queue_init(struct msm_device_queue *queue, const char *name) +{ + D("%s\n", __func__); + spin_lock_init(&queue->lock); + queue->len = 0; + queue->max = 0; + queue->name = name; + INIT_LIST_HEAD(&queue->list); + init_waitqueue_head(&queue->wait); +} + +static void msm_enqueue(struct msm_device_queue *queue, + struct list_head *entry) +{ + unsigned long flags; + spin_lock_irqsave(&queue->lock, flags); + queue->len++; + if (queue->len > queue->max) { + queue->max = queue->len; + pr_info("%s: queue %s new max is %d\n", __func__, + queue->name, queue->max); + } + list_add_tail(entry, &queue->list); + wake_up(&queue->wait); + D("%s: woke up %s\n", __func__, queue->name); + spin_unlock_irqrestore(&queue->lock, flags); +} + +/* callback function from all subdevices of a msm_cam_v4l2_device */ +static void msm_cam_v4l2_subdev_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + struct msm_cam_v4l2_device *pcam; + + if (sd == NULL) + return; + + pcam = to_pcam(sd->v4l2_dev); + + if (pcam == NULL) + return; + + /* forward to media controller for any changes*/ + if (pcam->mctl.mctl_notify) + pcam->mctl.mctl_notify(&pcam->mctl, notification, arg); +} + +static int msm_ctrl_cmd_done(void __user *arg) +{ + void __user *uptr; + struct msm_queue_cmd *qcmd; + struct msm_ctrl_cmd *command = &g_server_dev.ctrl; + + D("%s\n", __func__); + + if (copy_from_user(command, arg, + sizeof(struct msm_ctrl_cmd))) + return -EINVAL; + + qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); + atomic_set(&qcmd->on_heap, 1); + uptr = command->value; + qcmd->command = command; + + if (command->length > 0) { + command->value = g_server_dev.ctrl_data; + if (command->length > sizeof(g_server_dev.ctrl_data)) { + pr_err("%s: user data %d is too big (max %d)\n", + __func__, command->length, + sizeof(g_server_dev.ctrl_data)); + free_qcmd(qcmd); + return -EINVAL; + } + if (copy_from_user(command->value, uptr, command->length)) { + free_qcmd(qcmd); + return -EINVAL; + } + } + + msm_enqueue(&g_server_dev.ctrl_q, &qcmd->list_control); + return 0; +} + +/* send control command to config and wait for results*/ +static int msm_server_control(struct msm_cam_server_dev *server_dev, + struct msm_ctrl_cmd *out) +{ + int rc = 0; + void *value; + struct msm_queue_cmd *rcmd; + struct msm_ctrl_cmd *ctrlcmd; + struct msm_device_queue *queue = &server_dev->ctrl_q; + void *ctrlcmd_data; + + struct v4l2_event v4l2_evt; + struct msm_isp_event_ctrl *isp_event; + isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL); + if (!isp_event) { + pr_err("%s Insufficient memory. return", __func__); + return -ENOMEM; + } + + D("%s\n", __func__); + + g_server_dev.server_evt_id++; + if (g_server_dev.server_evt_id == 0) + g_server_dev.server_evt_id++; + isp_event->evt_id = g_server_dev.server_evt_id; + + v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2; + v4l2_evt.id = 0; + /* setup event object to transfer the command; */ + *((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event; + isp_event->resptype = MSM_CAM_RESP_V4L2; + isp_event->isp_data.ctrl = *out; + + if (out->length > 0 && out->value != NULL) { + ctrlcmd_data = kzalloc(out->length, GFP_KERNEL); + if (!ctrlcmd_data) { + kfree(isp_event); + pr_err("%s Insufficient memory. return", __func__); + return -ENOMEM; + } + memcpy(ctrlcmd_data, out->value, out->length); + isp_event->isp_data.ctrl.value = ctrlcmd_data; + } + /* now send command to config thread in userspace, + * and wait for results */ + v4l2_event_queue(server_dev->server_command_queue.pvdev, + &v4l2_evt); + + D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type); + + /* wait for config return status */ + D("Waiting for config status\n"); + rc = wait_event_interruptible_timeout(queue->wait, + !list_empty_careful(&queue->list), + msecs_to_jiffies(out->timeout_ms)); + D("Waiting is over for config status\n"); + if (list_empty_careful(&queue->list)) { + if (!rc) + rc = -ETIMEDOUT; + if (rc < 0) { + if (g_server_dev.server_evt_id == 0) + g_server_dev.server_evt_id++; + pr_err("%s: wait_event error %d\n", __func__, rc); + return rc; + } + } + + rcmd = msm_dequeue(queue, list_control); + BUG_ON(!rcmd); + D("%s Finished servicing ioctl\n", __func__); + + ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command); + value = out->value; + if (ctrlcmd->length > 0) + memcpy(value, ctrlcmd->value, ctrlcmd->length); + + memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd)); + out->value = value; + + if (rcmd) { + free_qcmd(rcmd); + rcmd = NULL; + } + D("%s: rc %d\n", __func__, rc); + /* rc is the time elapsed. */ + if (rc >= 0) { + /* TODO: Refactor msm_ctrl_cmd::status field */ + if (out->status == 0) + rc = -1; + else if (out->status == 1 || out->status == 4) + rc = 0; + else + rc = -EINVAL; + } + return rc; +} + +/*send open command to server*/ +static int msm_send_open_server(int vnode_id) +{ + int rc = 0; + struct msm_ctrl_cmd ctrlcmd; + + D("%s\n", __func__); + ctrlcmd.type = MSM_V4L2_OPEN; + ctrlcmd.timeout_ms = 5000; + ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0], + MAX_DEV_NAME_LEN)+1; + ctrlcmd.value = (char *)g_server_dev.config_info.config_dev_name[0]; + ctrlcmd.vnode_id = vnode_id; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + + /* send command to config thread in usersspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + + return rc; +} + +static int msm_send_close_server(int vnode_id) +{ + int rc = 0; + struct msm_ctrl_cmd ctrlcmd; + D("%s\n", __func__); + ctrlcmd.type = MSM_V4L2_CLOSE; + ctrlcmd.timeout_ms = 10000; + ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0], + MAX_DEV_NAME_LEN)+1; + ctrlcmd.value = (char *)g_server_dev.config_info.config_dev_name[0]; + ctrlcmd.vnode_id = vnode_id; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + + /* send command to config thread in usersspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + + return rc; +} + +static int msm_server_set_fmt(struct msm_cam_v4l2_device *pcam, int idx, + struct v4l2_format *pfmt) +{ + int rc = 0; + int i = 0; + struct v4l2_pix_format *pix = &pfmt->fmt.pix; + struct msm_ctrl_cmd ctrlcmd; + struct img_plane_info plane_info; + + plane_info.width = pix->width; + plane_info.height = pix->height; + plane_info.pixelformat = pix->pixelformat; + plane_info.buffer_type = pfmt->type; + plane_info.ext_mode = pcam->dev_inst[idx]->image_mode; + plane_info.num_planes = 1; + D("%s: %d, %d, 0x%x\n", __func__, + pfmt->fmt.pix.width, pfmt->fmt.pix.height, + pfmt->fmt.pix.pixelformat); + + if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + D("%s, Attention! Wrong buf-type %d\n", __func__, pfmt->type); + + for (i = 0; i < pcam->num_fmts; i++) + if (pcam->usr_fmts[i].fourcc == pix->pixelformat) + break; + if (i == pcam->num_fmts) { + pr_err("%s: User requested pixelformat %x not supported\n", + __func__, pix->pixelformat); + return -EINVAL; + } + + ctrlcmd.type = MSM_V4L2_VID_CAP_TYPE; + ctrlcmd.length = sizeof(struct img_plane_info); + ctrlcmd.value = (void *)&plane_info; + ctrlcmd.timeout_ms = 10000; + ctrlcmd.vnode_id = pcam->vnode_id; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + + /* send command to config thread in usersspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + + if (rc >= 0) { + pcam->dev_inst[idx]->vid_fmt = *pfmt; + pcam->dev_inst[idx]->sensor_pxlcode + = pcam->usr_fmts[i].pxlcode; + D("%s:inst=0x%x,idx=%d,width=%d,heigth=%d\n", + __func__, (u32)pcam->dev_inst[idx], idx, + pcam->dev_inst[idx]->vid_fmt.fmt.pix.width, + pcam->dev_inst[idx]->vid_fmt.fmt.pix.height); + pcam->dev_inst[idx]->plane_info = plane_info; + } + + return rc; +} + +static int msm_server_set_fmt_mplane(struct msm_cam_v4l2_device *pcam, int idx, + struct v4l2_format *pfmt) +{ + int rc = 0; + int i = 0; + struct v4l2_pix_format_mplane *pix_mp = &pfmt->fmt.pix_mp; + struct msm_ctrl_cmd ctrlcmd; + struct img_plane_info plane_info; + + plane_info.width = pix_mp->width; + plane_info.height = pix_mp->height; + plane_info.pixelformat = pix_mp->pixelformat; + plane_info.buffer_type = pfmt->type; + plane_info.ext_mode = pcam->dev_inst[idx]->image_mode; + plane_info.num_planes = pix_mp->num_planes; + if (plane_info.num_planes <= 0 || + plane_info.num_planes > VIDEO_MAX_PLANES) { + pr_err("%s Invalid number of planes set %d", __func__, + plane_info.num_planes); + return -EINVAL; + } + D("%s: %d, %d, 0x%x\n", __func__, + pfmt->fmt.pix_mp.width, pfmt->fmt.pix_mp.height, + pfmt->fmt.pix_mp.pixelformat); + + if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + pr_err("%s, Attention! Wrong buf-type %d\n", + __func__, pfmt->type); + return -EINVAL; + } + + for (i = 0; i < pcam->num_fmts; i++) + if (pcam->usr_fmts[i].fourcc == pix_mp->pixelformat) + break; + if (i == pcam->num_fmts) { + pr_err("%s: User requested pixelformat %x not supported\n", + __func__, pix_mp->pixelformat); + return -EINVAL; + } + + ctrlcmd.type = MSM_V4L2_VID_CAP_TYPE; + ctrlcmd.length = sizeof(struct img_plane_info); + ctrlcmd.value = (void *)&plane_info; + ctrlcmd.timeout_ms = 10000; + ctrlcmd.vnode_id = pcam->vnode_id; + + /* send command to config thread in usersspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + if (rc >= 0) { + pcam->dev_inst[idx]->vid_fmt = *pfmt; + pcam->dev_inst[idx]->sensor_pxlcode + = pcam->usr_fmts[i].pxlcode; + D("%s:inst=0x%x,idx=%d,width=%d,heigth=%d\n", + __func__, (u32)pcam->dev_inst[idx], idx, + pcam->dev_inst[idx]->vid_fmt.fmt.pix_mp.width, + pcam->dev_inst[idx]->vid_fmt.fmt.pix_mp.height); + pcam->dev_inst[idx]->plane_info = plane_info; + } + + return rc; +} + +static int msm_server_streamon(struct msm_cam_v4l2_device *pcam, int idx) +{ + int rc = 0; + struct msm_ctrl_cmd ctrlcmd; + D("%s\n", __func__); + ctrlcmd.type = MSM_V4L2_STREAM_ON; + ctrlcmd.timeout_ms = 3000; + ctrlcmd.length = 0; + ctrlcmd.value = NULL; + ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode; + ctrlcmd.vnode_id = pcam->vnode_id; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + + + /* send command to config thread in usersspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + + return rc; +} + +static int msm_server_streamoff(struct msm_cam_v4l2_device *pcam, int idx) +{ + int rc = 0; + struct msm_ctrl_cmd ctrlcmd; + + D("%s, pcam = 0x%x\n", __func__, (u32)pcam); + ctrlcmd.type = MSM_V4L2_STREAM_OFF; + ctrlcmd.timeout_ms = 3000; + ctrlcmd.length = 0; + ctrlcmd.value = NULL; + ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode; + ctrlcmd.vnode_id = pcam->vnode_id; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + + /* send command to config thread in usersspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + + return rc; +} + +static int msm_server_proc_ctrl_cmd(struct msm_cam_v4l2_device *pcam, + struct v4l2_control *ctrl, int is_set_cmd) +{ + int rc = 0; + struct msm_ctrl_cmd ctrlcmd, *tmp_cmd; + uint8_t *ctrl_data = NULL; + void __user *uptr_cmd; + void __user *uptr_value; + uint32_t cmd_len = sizeof(struct msm_ctrl_cmd); + uint32_t value_len; + + tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value; + uptr_cmd = (void __user *)ctrl->value; + uptr_value = (void __user *)tmp_cmd->value; + value_len = tmp_cmd->length; + + D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n", + __func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len, + (uint32_t)uptr_value, tmp_cmd->length); + + ctrl_data = kzalloc(value_len+cmd_len, GFP_KERNEL); + if (ctrl_data == 0) { + pr_err("%s could not allocate memory\n", __func__); + rc = -ENOMEM; + goto end; + } + tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data; + if (copy_from_user((void *)ctrl_data, uptr_cmd, + cmd_len)) { + pr_err("%s: copy_from_user failed.\n", __func__); + rc = -EINVAL; + goto end; + } + tmp_cmd->value = (void *)(ctrl_data+cmd_len); + if (uptr_value && tmp_cmd->length > 0) { + if (copy_from_user((void *)tmp_cmd->value, uptr_value, + value_len)) { + pr_err("%s: copy_from_user failed, size=%d\n", + __func__, value_len); + rc = -EINVAL; + goto end; + } + } else + tmp_cmd->value = NULL; + + ctrlcmd.type = MSM_V4L2_SET_CTRL_CMD; + ctrlcmd.length = cmd_len + value_len; + ctrlcmd.value = (void *)ctrl_data; + ctrlcmd.timeout_ms = 1000; + ctrlcmd.vnode_id = pcam->vnode_id; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + /* send command to config thread in usersspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + D("%s: msm_server_control rc=%d\n", __func__, rc); + if (rc == 0) { + if (uptr_value && tmp_cmd->length > 0 && + copy_to_user((void __user *)uptr_value, + (void *)(ctrl_data+cmd_len), tmp_cmd->length)) { + pr_err("%s: copy_to_user failed, size=%d\n", + __func__, tmp_cmd->length); + rc = -EINVAL; + goto end; + } + tmp_cmd->value = uptr_value; + if (copy_to_user((void __user *)uptr_cmd, + (void *)tmp_cmd, cmd_len)) { + pr_err("%s: copy_to_user failed in cpy, size=%d\n", + __func__, cmd_len); + rc = -EINVAL; + goto end; + } + } +end: + D("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n", + __func__, tmp_cmd->type, (uint32_t)tmp_cmd->value, + tmp_cmd->length, tmp_cmd->status, rc); + kfree(ctrl_data); + ctrl_data = NULL; + return rc; +} + +static int msm_server_s_ctrl(struct msm_cam_v4l2_device *pcam, + struct v4l2_control *ctrl) +{ + int rc = 0; + struct msm_ctrl_cmd ctrlcmd; + uint8_t ctrl_data[max_control_command_size]; + + WARN_ON(ctrl == NULL); + + if (ctrl && ctrl->id == MSM_V4L2_PID_CTRL_CMD) + return msm_server_proc_ctrl_cmd(pcam, ctrl, 1); + + memset(ctrl_data, 0, sizeof(ctrl_data)); + + ctrlcmd.type = MSM_V4L2_SET_CTRL; + ctrlcmd.length = sizeof(struct v4l2_control); + ctrlcmd.value = (void *)ctrl_data; + memcpy(ctrlcmd.value, ctrl, ctrlcmd.length); + ctrlcmd.timeout_ms = 1000; + ctrlcmd.vnode_id = pcam->vnode_id; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + + /* send command to config thread in usersspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + + return rc; +} + +static int msm_server_g_ctrl(struct msm_cam_v4l2_device *pcam, + struct v4l2_control *ctrl) +{ + int rc = 0; + struct msm_ctrl_cmd ctrlcmd; + uint8_t ctrl_data[max_control_command_size]; + + WARN_ON(ctrl == NULL); + if (ctrl && ctrl->id == MSM_V4L2_PID_CTRL_CMD) + return msm_server_proc_ctrl_cmd(pcam, ctrl, 0); + + memset(ctrl_data, 0, sizeof(ctrl_data)); + + ctrlcmd.type = MSM_V4L2_GET_CTRL; + ctrlcmd.length = sizeof(struct v4l2_control); + ctrlcmd.value = (void *)ctrl_data; + memcpy(ctrlcmd.value, ctrl, ctrlcmd.length); + ctrlcmd.timeout_ms = 1000; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + + /* send command to config thread in usersspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + + ctrl->value = ((struct v4l2_control *)ctrlcmd.value)->value; + + return rc; +} + +static int msm_server_q_ctrl(struct msm_cam_v4l2_device *pcam, + struct v4l2_queryctrl *queryctrl) +{ + int rc = 0; + struct msm_ctrl_cmd ctrlcmd; + uint8_t ctrl_data[max_control_command_size]; + + WARN_ON(queryctrl == NULL); + memset(ctrl_data, 0, sizeof(ctrl_data)); + + ctrlcmd.type = MSM_V4L2_QUERY_CTRL; + ctrlcmd.length = sizeof(struct v4l2_queryctrl); + ctrlcmd.value = (void *)ctrl_data; + memcpy(ctrlcmd.value, queryctrl, ctrlcmd.length); + ctrlcmd.timeout_ms = 1000; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + + /* send command to config thread in userspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + D("%s: rc = %d\n", __func__, rc); + + if (rc >= 0) + memcpy(queryctrl, ctrlcmd.value, sizeof(struct v4l2_queryctrl)); + + return rc; +} + +static int msm_server_get_fmt(struct msm_cam_v4l2_device *pcam, + int idx, struct v4l2_format *pfmt) +{ + struct v4l2_pix_format *pix = &pfmt->fmt.pix; + + pix->width = pcam->dev_inst[idx]->vid_fmt.fmt.pix.width; + pix->height = pcam->dev_inst[idx]->vid_fmt.fmt.pix.height; + pix->field = pcam->dev_inst[idx]->vid_fmt.fmt.pix.field; + pix->pixelformat = pcam->dev_inst[idx]->vid_fmt.fmt.pix.pixelformat; + pix->bytesperline = pcam->dev_inst[idx]->vid_fmt.fmt.pix.bytesperline; + pix->colorspace = pcam->dev_inst[idx]->vid_fmt.fmt.pix.colorspace; + /* if (pix->bytesperline < 0) + return pix->bytesperline; */ + + pix->sizeimage = pix->height * pix->bytesperline; + + return 0; +} + +static int msm_server_get_fmt_mplane(struct msm_cam_v4l2_device *pcam, + int idx, struct v4l2_format *pfmt) +{ + *pfmt = pcam->dev_inst[idx]->vid_fmt; + return 0; +} + +static int msm_server_try_fmt(struct msm_cam_v4l2_device *pcam, + struct v4l2_format *pfmt) +{ + int rc = 0; + int i = 0; + struct v4l2_pix_format *pix = &pfmt->fmt.pix; + + D("%s: 0x%x\n", __func__, pix->pixelformat); + if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + pr_err("%s: pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE!\n", + __func__); + return -EINVAL; + } + + /* check if the format is supported by this host-sensor combo */ + for (i = 0; i < pcam->num_fmts; i++) { + D("%s: usr_fmts.fourcc: 0x%x\n", __func__, + pcam->usr_fmts[i].fourcc); + if (pcam->usr_fmts[i].fourcc == pix->pixelformat) + break; + } + + if (i == pcam->num_fmts) { + pr_err("%s: Format %x not found\n", __func__, pix->pixelformat); + return -EINVAL; + } + return rc; +} + +static int msm_server_try_fmt_mplane(struct msm_cam_v4l2_device *pcam, + struct v4l2_format *pfmt) +{ + int rc = 0; + int i = 0; + struct v4l2_pix_format_mplane *pix_mp = &pfmt->fmt.pix_mp; + + D("%s: 0x%x\n", __func__, pix_mp->pixelformat); + if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + pr_err("%s: Incorrect format type %d ", + __func__, pfmt->type); + return -EINVAL; + } + + /* check if the format is supported by this host-sensor combo */ + for (i = 0; i < pcam->num_fmts; i++) { + D("%s: usr_fmts.fourcc: 0x%x\n", __func__, + pcam->usr_fmts[i].fourcc); + if (pcam->usr_fmts[i].fourcc == pix_mp->pixelformat) + break; + } + + if (i == pcam->num_fmts) { + pr_err("%s: Format %x not found\n", + __func__, pix_mp->pixelformat); + return -EINVAL; + } + return rc; +} + +static int msm_camera_get_crop(struct msm_cam_v4l2_device *pcam, + int idx, struct v4l2_crop *crop) +{ + int rc = 0; + struct msm_ctrl_cmd ctrlcmd; + + BUG_ON(crop == NULL); + + ctrlcmd.type = MSM_V4L2_GET_CROP; + ctrlcmd.length = sizeof(struct v4l2_crop); + ctrlcmd.value = (void *)crop; + ctrlcmd.timeout_ms = 1000; + ctrlcmd.vnode_id = pcam->vnode_id; + ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode; + ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0]; + + /* send command to config thread in userspace, and get return value */ + rc = msm_server_control(&g_server_dev, &ctrlcmd); + D("%s: rc = %d\n", __func__, rc); + + return rc; +} + +/* + * + * implementation of v4l2_ioctl_ops + * + */ +static int msm_camera_v4l2_querycap(struct file *f, void *pctx, + struct v4l2_capability *pcaps) +{ + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + /* some other day, some other time */ + /*cap->version = LINUX_VERSION_CODE; */ + pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + return 0; +} + +static int msm_camera_v4l2_queryctrl(struct file *f, void *pctx, + struct v4l2_queryctrl *pqctrl) +{ + int rc = 0; + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + mutex_lock(&pcam->vid_lock); + rc = msm_server_q_ctrl(pcam, pqctrl); + mutex_unlock(&pcam->vid_lock); + return rc; +} + +static int msm_camera_v4l2_g_ctrl(struct file *f, void *pctx, + struct v4l2_control *c) +{ + int rc = 0; + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + mutex_lock(&pcam->vid_lock); + rc = msm_server_g_ctrl(pcam, c); + mutex_unlock(&pcam->vid_lock); + + return rc; +} + +static int msm_camera_v4l2_s_ctrl(struct file *f, void *pctx, + struct v4l2_control *ctrl) +{ + int rc = 0; + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s\n", __func__); + + WARN_ON(pctx != f->private_data); + mutex_lock(&pcam->vid_lock); + switch (ctrl->id) { + case MSM_V4L2_PID_MMAP_INST: + D("%s: mmap_inst=(0x%p, %d)\n", + __func__, pcam_inst, pcam_inst->my_index); + pcam_inst->is_mem_map_inst = 1; + break; + case MSM_V4L2_PID_MMAP_ENTRY: + if (copy_from_user(&pcam_inst->mem_map, + (void *)ctrl->value, + sizeof(struct msm_mem_map_info))) { + rc = -EFAULT; + } else + D("%s:mmap entry:cookie=0x%x,mem_type=%d,len=%d\n", + __func__, pcam_inst->mem_map.cookie, + pcam_inst->mem_map.mem_type, + pcam_inst->mem_map.length); + break; + default: + if (ctrl->id == MSM_V4L2_PID_CAM_MODE) + pcam->op_mode = ctrl->value; + rc = msm_server_s_ctrl(pcam, ctrl); + break; + } + mutex_unlock(&pcam->vid_lock); + + return rc; +} + +static int msm_camera_v4l2_reqbufs(struct file *f, void *pctx, + struct v4l2_requestbuffers *pb) +{ + int rc = 0, i, j; + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + mutex_lock(&pcam_inst->inst_lock); + rc = vb2_reqbufs(&pcam_inst->vid_bufq, pb); + if (rc < 0) { + pr_err("%s reqbufs failed %d ", __func__, rc); + mutex_unlock(&pcam_inst->inst_lock); + return rc; + } + if (!pb->count) { + /* Deallocation. free buf_offset array */ + D("%s Inst %p freeing buffer offsets array", + __func__, pcam_inst); + for (j = 0 ; j < pcam_inst->buf_count ; j++) { + kfree(pcam_inst->buf_offset[j]); + pcam_inst->buf_offset[j] = NULL; + } + kfree(pcam_inst->buf_offset); + pcam_inst->buf_offset = NULL; + /* If the userspace has deallocated all the + * buffers, then release the vb2 queue */ + if (pcam_inst->vbqueue_initialized) { + vb2_queue_release(&pcam_inst->vid_bufq); + pcam_inst->vbqueue_initialized = 0; + } + } else { + D("%s Inst %p Allocating buf_offset array", + __func__, pcam_inst); + /* Allocation. allocate buf_offset array */ + pcam_inst->buf_offset = (struct msm_cam_buf_offset **) + kzalloc(pb->count * sizeof(struct msm_cam_buf_offset *), + GFP_KERNEL); + if (!pcam_inst->buf_offset) { + pr_err("%s out of memory ", __func__); + mutex_unlock(&pcam_inst->inst_lock); + return -ENOMEM; + } + for (i = 0; i < pb->count; i++) { + pcam_inst->buf_offset[i] = + kzalloc(sizeof(struct msm_cam_buf_offset) * + pcam_inst->plane_info.num_planes, GFP_KERNEL); + if (!pcam_inst->buf_offset[i]) { + pr_err("%s out of memory ", __func__); + for (j = i-1 ; j >= 0; j--) { + kfree(pcam_inst->buf_offset[j]); + pcam_inst->buf_offset[j] = NULL; + } + kfree(pcam_inst->buf_offset); + pcam_inst->buf_offset = NULL; + mutex_unlock(&pcam_inst->inst_lock); + return -ENOMEM; + } + } + } + pcam_inst->buf_count = pb->count; + mutex_unlock(&pcam_inst->inst_lock); + return rc; +} + +static int msm_camera_v4l2_querybuf(struct file *f, void *pctx, + struct v4l2_buffer *pb) +{ + /* get the video device */ + int rc = 0; + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + mutex_lock(&pcam_inst->inst_lock); + rc = vb2_querybuf(&pcam_inst->vid_bufq, pb); + mutex_unlock(&pcam_inst->inst_lock); + return rc; +} + +static int msm_camera_v4l2_qbuf(struct file *f, void *pctx, + struct v4l2_buffer *pb) +{ + int rc = 0, i = 0; + /* get the camera device */ + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s Inst = %p\n", __func__, pcam_inst); + WARN_ON(pctx != f->private_data); + + mutex_lock(&pcam_inst->inst_lock); + if (!pcam_inst->buf_offset) { + pr_err("%s Buffer is already released. Returning. ", __func__); + mutex_unlock(&pcam_inst->inst_lock); + return -EINVAL; + } + + if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + /* Reject the buffer if planes array was not allocated */ + if (pb->m.planes == NULL) { + pr_err("%s Planes array is null ", __func__); + mutex_unlock(&pcam_inst->inst_lock); + return -EINVAL; + } + for (i = 0; i < pcam_inst->plane_info.num_planes; i++) { + D("%s stored offsets for plane %d as" + "addr offset %d, data offset %d", + __func__, i, pb->m.planes[i].reserved[0], + pb->m.planes[i].data_offset); + pcam_inst->buf_offset[pb->index][i].data_offset = + pb->m.planes[i].data_offset; + pcam_inst->buf_offset[pb->index][i].addr_offset = + pb->m.planes[i].reserved[0]; + } + } else { + D("%s stored reserved info %d", __func__, pb->reserved); + pcam_inst->buf_offset[pb->index][0].addr_offset = pb->reserved; + } + + rc = vb2_qbuf(&pcam_inst->vid_bufq, pb); + D("%s, videobuf_qbuf returns %d\n", __func__, rc); + + mutex_unlock(&pcam_inst->inst_lock); + return rc; +} + +static int msm_camera_v4l2_dqbuf(struct file *f, void *pctx, + struct v4l2_buffer *pb) +{ + int rc = 0; + /* get the camera device */ + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + mutex_lock(&pcam_inst->inst_lock); + if (0 == pcam_inst->streamon) { + mutex_unlock(&pcam_inst->inst_lock); + return -EACCES; + } + + rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb, f->f_flags & O_NONBLOCK); + D("%s, videobuf_dqbuf returns %d\n", __func__, rc); + mutex_unlock(&pcam_inst->inst_lock); + return rc; +} + +static int msm_camera_v4l2_streamon(struct file *f, void *pctx, + enum v4l2_buf_type buf_type) +{ + int rc = 0; + /* get the camera device */ + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s Inst %p\n", __func__, pcam_inst); + WARN_ON(pctx != f->private_data); + + mutex_lock(&pcam->vid_lock); + mutex_lock(&pcam_inst->inst_lock); + if ((buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && + (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) { + pr_err("%s Invalid buffer type ", __func__); + mutex_unlock(&pcam_inst->inst_lock); + mutex_unlock(&pcam->vid_lock); + return -EINVAL; + } + + D("%s Calling videobuf_streamon", __func__); + /* if HW streaming on is successful, start buffer streaming */ + rc = vb2_streamon(&pcam_inst->vid_bufq, buf_type); + D("%s, videobuf_streamon returns %d\n", __func__, rc); + + /* turn HW (VFE/sensor) streaming */ + pcam_inst->streamon = 1; + rc = msm_server_streamon(pcam, pcam_inst->my_index); + mutex_unlock(&pcam_inst->inst_lock); + mutex_unlock(&pcam->vid_lock); + D("%s rc = %d\n", __func__, rc); + return rc; +} + +static int msm_camera_v4l2_streamoff(struct file *f, void *pctx, + enum v4l2_buf_type buf_type) +{ + int rc = 0; + /* get the camera device */ + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s Inst %p\n", __func__, pcam_inst); + WARN_ON(pctx != f->private_data); + + if ((buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && + (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) { + pr_err("%s Invalid buffer type ", __func__); + return -EINVAL; + } + + /* first turn of HW (VFE/sensor) streaming so that buffers are + not in use when we free the buffers */ + mutex_lock(&pcam->vid_lock); + mutex_lock(&pcam_inst->inst_lock); + pcam_inst->streamon = 0; + if (g_server_dev.use_count > 0) + rc = msm_server_streamoff(pcam, pcam_inst->my_index); + if (rc < 0) + pr_err("%s: hw failed to stop streaming\n", __func__); + + /* stop buffer streaming */ + rc = vb2_streamoff(&pcam_inst->vid_bufq, buf_type); + D("%s, videobuf_streamoff returns %d\n", __func__, rc); + mutex_unlock(&pcam_inst->inst_lock); + mutex_unlock(&pcam->vid_lock); + return rc; +} + +static int msm_camera_v4l2_enum_fmt_cap(struct file *f, void *pctx, + struct v4l2_fmtdesc *pfmtdesc) +{ + /* get the video device */ + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + const struct msm_isp_color_fmt *isp_fmt; + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + if ((pfmtdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && + (pfmtdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + + if (pfmtdesc->index >= pcam->num_fmts) + return -EINVAL; + + isp_fmt = &pcam->usr_fmts[pfmtdesc->index]; + + if (isp_fmt->name) + strlcpy(pfmtdesc->description, isp_fmt->name, + sizeof(pfmtdesc->description)); + + pfmtdesc->pixelformat = isp_fmt->fourcc; + + D("%s: [%d] 0x%x, %s\n", __func__, pfmtdesc->index, + isp_fmt->fourcc, isp_fmt->name); + return 0; +} + +static int msm_camera_v4l2_g_fmt_cap(struct file *f, + void *pctx, struct v4l2_format *pfmt) +{ + int rc = 0; + /* get the video device */ + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + rc = msm_server_get_fmt(pcam, pcam_inst->my_index, pfmt); + D("%s: current_fmt->fourcc: 0x%08x, rc = %d\n", __func__, + pfmt->fmt.pix.pixelformat, rc); + return rc; +} + +static int msm_camera_v4l2_g_fmt_cap_mplane(struct file *f, + void *pctx, struct v4l2_format *pfmt) +{ + int rc = 0; + /* get the video device */ + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + rc = msm_server_get_fmt_mplane(pcam, pcam_inst->my_index, pfmt); + D("%s: current_fmt->fourcc: 0x%08x, rc = %d\n", __func__, + pfmt->fmt.pix_mp.pixelformat, rc); + return rc; +} + +/* This function will readjust the format parameters based in HW + capabilities. Called by s_fmt_cap +*/ +static int msm_camera_v4l2_try_fmt_cap(struct file *f, void *pctx, + struct v4l2_format *pfmt) +{ + int rc = 0; + /* get the video device */ + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + mutex_lock(&pcam->vid_lock); + rc = msm_server_try_fmt(pcam, pfmt); + if (rc) + pr_err("Format %x not found, rc = %d\n", + pfmt->fmt.pix.pixelformat, rc); + mutex_unlock(&pcam->vid_lock); + return rc; +} + +static int msm_camera_v4l2_try_fmt_cap_mplane(struct file *f, void *pctx, + struct v4l2_format *pfmt) +{ + int rc = 0; + /* get the video device */ + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + mutex_lock(&pcam->vid_lock); + rc = msm_server_try_fmt_mplane(pcam, pfmt); + if (rc) + pr_err("Format %x not found, rc = %d\n", + pfmt->fmt.pix_mp.pixelformat, rc); + + mutex_unlock(&pcam->vid_lock); + return rc; +} + +/* This function will reconfig the v4l2 driver and HW device, it should be + called after the streaming is stopped. +*/ +static int msm_camera_v4l2_s_fmt_cap(struct file *f, void *pctx, + struct v4l2_format *pfmt) +{ + int rc; + /* get the video device */ + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s\n", __func__); + D("%s, inst=0x%x,idx=%d,priv = 0x%p\n", + __func__, (u32)pcam_inst, pcam_inst->my_index, + (void *)pfmt->fmt.pix.priv); + WARN_ON(pctx != f->private_data); + + if (!pcam_inst->vbqueue_initialized) { + pcam->mctl.mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + pcam_inst->vbqueue_initialized = 1; + } + + mutex_lock(&pcam->vid_lock); + + rc = msm_server_set_fmt(pcam, pcam_inst->my_index, pfmt); + if (rc < 0) { + pr_err("%s: msm_server_set_fmt Error: %d\n", + __func__, rc); + } + mutex_unlock(&pcam->vid_lock); + + return rc; +} + +static int msm_camera_v4l2_s_fmt_cap_mplane(struct file *f, void *pctx, + struct v4l2_format *pfmt) +{ + int rc; + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s Inst %p\n", __func__, pcam_inst); + WARN_ON(pctx != f->private_data); + + if (!pcam_inst->vbqueue_initialized) { + pcam->mctl.mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + pcam_inst->vbqueue_initialized = 1; + } + + mutex_lock(&pcam->vid_lock); + rc = msm_server_set_fmt_mplane(pcam, pcam_inst->my_index, pfmt); + mutex_unlock(&pcam->vid_lock); + + return rc; +} +static int msm_camera_v4l2_g_jpegcomp(struct file *f, void *pctx, + struct v4l2_jpegcompression *pcomp) +{ + int rc = -EINVAL; + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + return rc; +} + +static int msm_camera_v4l2_s_jpegcomp(struct file *f, void *pctx, + struct v4l2_jpegcompression *pcomp) +{ + int rc = -EINVAL; + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + return rc; +} + + +static int msm_camera_v4l2_g_crop(struct file *f, void *pctx, + struct v4l2_crop *crop) +{ + int rc = -EINVAL; + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + struct msm_cam_v4l2_dev_inst *pcam_inst; + + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + mutex_lock(&pcam->vid_lock); + rc = msm_camera_get_crop(pcam, pcam_inst->my_index, crop); + mutex_unlock(&pcam->vid_lock); + return rc; +} + +static int msm_camera_v4l2_s_crop(struct file *f, void *pctx, + struct v4l2_crop *a) +{ + int rc = -EINVAL; + + D("%s\n", __func__); + WARN_ON(pctx != f->private_data); + + return rc; +} + +/* Stream type-dependent parameter ioctls */ +static int msm_camera_v4l2_g_parm(struct file *f, void *pctx, + struct v4l2_streamparm *a) +{ + int rc = -EINVAL; + return rc; +} +static int msm_vidbuf_get_path(u32 extendedmode) +{ + switch (extendedmode) { + case MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL: + return OUTPUT_TYPE_T; + case MSM_V4L2_EXT_CAPTURE_MODE_MAIN: + return OUTPUT_TYPE_S; + case MSM_V4L2_EXT_CAPTURE_MODE_VIDEO: + return OUTPUT_TYPE_V; + case MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT: + case MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW: + default: + return OUTPUT_TYPE_P; + } +} + +static int msm_camera_v4l2_s_parm(struct file *f, void *pctx, + struct v4l2_streamparm *a) +{ + int rc = 0; + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + pcam_inst->image_mode = a->parm.capture.extendedmode; + pcam_inst->pcam->dev_inst_map[pcam_inst->image_mode] = pcam_inst; + pcam_inst->path = msm_vidbuf_get_path(pcam_inst->image_mode); + D("%spath=%d,rc=%d\n", __func__, + pcam_inst->path, rc); + return rc; +} + +static int msm_camera_v4l2_subscribe_event(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + int rc = 0; + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = + (struct msm_cam_v4l2_dev_inst *)container_of(fh, + struct msm_cam_v4l2_dev_inst, eventHandle); + + sub->id = 0; + + D("%s:fh = 0x%x, type = 0x%x, id=%d\n", __func__, (u32)fh, sub->type, sub->id); + if (pcam_inst->my_index != 0) + return -EINVAL; + if (sub->type == V4L2_EVENT_ALL) + sub->type = V4L2_EVENT_PRIVATE_START+MSM_CAM_APP_NOTIFY_EVENT; + rc = v4l2_event_subscribe(fh, sub, 30); + if (rc < 0) + D("%s: failed for evtType = 0x%x, rc = %d\n", + __func__, sub->type, rc); + return rc; +} + +static int msm_camera_v4l2_unsubscribe_event(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + int rc = 0; + struct msm_cam_v4l2_dev_inst *pcam_inst; + + sub->id=0; + pcam_inst = + (struct msm_cam_v4l2_dev_inst *)container_of(fh, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("%s: fh = 0x%x\n", __func__, (u32)fh); + if (pcam_inst->my_index != 0) + return -EINVAL; + + rc = v4l2_event_unsubscribe(fh, sub); + D("%s: rc = %d\n", __func__, rc); + return rc; +} + +static int msm_server_v4l2_subscribe_event(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + int rc = 0; + + sub->id = 0; + D("%s: fh = 0x%x, type = 0x%x", __func__, (u32)fh, sub->type); + if (sub->type == V4L2_EVENT_ALL) { + /*sub->type = MSM_ISP_EVENT_START;*/ + sub->type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_CTRL; + D("sub->type start = 0x%x\n", sub->type); + do { + rc = v4l2_event_subscribe(fh, sub, 30); + if (rc < 0) { + D("%s: failed for evtType = 0x%x, rc = %d\n", + __func__, sub->type, rc); + /* unsubscribe all events here and return */ + sub->type = V4L2_EVENT_ALL; + v4l2_event_unsubscribe(fh, sub); + return rc; + } else + D("%s: subscribed evtType = 0x%x, rc = %d\n", + __func__, sub->type, rc); + sub->type++; + D("sub->type while = 0x%x\n", sub->type); + } while (sub->type != + V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MAX); + } else { + D("sub->type not V4L2_EVENT_ALL = 0x%x\n", sub->type); + rc = v4l2_event_subscribe(fh, sub, 30); + if (rc < 0) + D("%s: failed for evtType = 0x%x, rc = %d\n", + __func__, sub->type, rc); + } + + D("%s: rc = %d\n", __func__, rc); + return rc; +} + +static int msm_server_v4l2_unsubscribe_event(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + int rc = 0; + sub->id = 0; + D("%s: fh = 0x%x\n", __func__, (u32)fh); + rc = v4l2_event_unsubscribe(fh, sub); + D("%s: rc = %d\n", __func__, rc); + return rc; +} + +/* v4l2_ioctl_ops */ +static const struct v4l2_ioctl_ops g_msm_ioctl_ops = { + .vidioc_querycap = msm_camera_v4l2_querycap, + + .vidioc_s_crop = msm_camera_v4l2_s_crop, + .vidioc_g_crop = msm_camera_v4l2_g_crop, + + .vidioc_queryctrl = msm_camera_v4l2_queryctrl, + .vidioc_g_ctrl = msm_camera_v4l2_g_ctrl, + .vidioc_s_ctrl = msm_camera_v4l2_s_ctrl, + + .vidioc_reqbufs = msm_camera_v4l2_reqbufs, + .vidioc_querybuf = msm_camera_v4l2_querybuf, + .vidioc_qbuf = msm_camera_v4l2_qbuf, + .vidioc_dqbuf = msm_camera_v4l2_dqbuf, + + .vidioc_streamon = msm_camera_v4l2_streamon, + .vidioc_streamoff = msm_camera_v4l2_streamoff, + + /* format ioctls */ + .vidioc_enum_fmt_vid_cap = msm_camera_v4l2_enum_fmt_cap, + .vidioc_enum_fmt_vid_cap_mplane = msm_camera_v4l2_enum_fmt_cap, + .vidioc_try_fmt_vid_cap = msm_camera_v4l2_try_fmt_cap, + .vidioc_try_fmt_vid_cap_mplane = msm_camera_v4l2_try_fmt_cap_mplane, + .vidioc_g_fmt_vid_cap = msm_camera_v4l2_g_fmt_cap, + .vidioc_g_fmt_vid_cap_mplane = msm_camera_v4l2_g_fmt_cap_mplane, + .vidioc_s_fmt_vid_cap = msm_camera_v4l2_s_fmt_cap, + .vidioc_s_fmt_vid_cap_mplane = msm_camera_v4l2_s_fmt_cap_mplane, + + .vidioc_g_jpegcomp = msm_camera_v4l2_g_jpegcomp, + .vidioc_s_jpegcomp = msm_camera_v4l2_s_jpegcomp, + + /* Stream type-dependent parameter ioctls */ + .vidioc_g_parm = msm_camera_v4l2_g_parm, + .vidioc_s_parm = msm_camera_v4l2_s_parm, + + /* event subscribe/unsubscribe */ + .vidioc_subscribe_event = msm_camera_v4l2_subscribe_event, + .vidioc_unsubscribe_event = msm_camera_v4l2_unsubscribe_event, +}; + +/* open an active camera session to manage the streaming logic */ +static int msm_cam_server_open_session(struct msm_cam_server_dev *ps, + struct msm_cam_v4l2_device *pcam) +{ + int rc = 0; + D("%s\n", __func__); + + if (!ps || !pcam) { + pr_err("%s NULL pointer passed in!\n", __func__); + return rc; + } + + /* book keeping this camera session*/ + ps->pcam_active = pcam; + atomic_inc(&ps->number_pcam_active); + + D("config pcam = 0x%p\n", ps->pcam_active); + + /* initialization the media controller module*/ + msm_mctl_init_module(pcam); + + /*yyan: for single VFE msms (8660, 8960v1), just populate the session + with our VFE devices that registered*/ + pcam->mctl.isp_sdev = ps->isp_subdev[0]; + + + /*yyan: 8960 bring up - no VPE and flash; populate later*/ + pcam->mctl.vpe_sdev = NULL; + pcam->mctl.flash_sdev = NULL; + + return rc; + +} + +/* close an active camera session to server */ +static int msm_cam_server_close_session(struct msm_cam_server_dev *ps, + struct msm_cam_v4l2_device *pcam) +{ + int rc = 0; + D("%s\n", __func__); + + if (!ps || !pcam) { + D("%s NULL pointer passed in!\n", __func__); + return rc; + } + + + atomic_dec(&ps->number_pcam_active); + ps->pcam_active = NULL; + + return rc; +} + +static int msm_open_init(struct msm_cam_v4l2_device *pcam, + struct msm_cam_v4l2_dev_inst *pcam_inst) +{ + int rc; + + rc = msm_cam_server_open_session(&g_server_dev, pcam); + if (rc < 0) { + pr_err("%s: cam_server_open_session failed %d\n", + __func__, rc); + goto end; + } + /* Should be set to sensor ops if any but right now its OK!! */ + if (!pcam->mctl.mctl_open) { + pr_err("%s: media contoller is not inited\n", + __func__); + rc = -ENODEV; + goto fail; + } +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + pcam->mctl.client = msm_ion_client_create(-1, "camera"); + kref_init(&pcam->mctl.refcount); +#endif + + /* Now we really have to activate the camera */ + D("%s: call mctl_open\n", __func__); + rc = pcam->mctl.mctl_open(&(pcam->mctl), MSM_APPS_ID_V4L2); + if (rc < 0) { + pr_err("%s: HW open failed rc = 0x%x\n", __func__, rc); + goto fail1; + } + pcam->mctl.sync.pcam_sync = pcam; + + /* Register isp subdev */ + rc = v4l2_device_register_subdev(&pcam->v4l2_dev, + pcam->mctl.isp_sdev->sd); + if (rc < 0) { + pr_err("%s: v4l2_device_register_subdev failed rc = %d\n", + __func__, rc); + goto fail2; + } + rc = v4l2_device_register_subdev(&pcam->v4l2_dev, + pcam->mctl.isp_sdev->sd_vpe); + if (rc < 0) { + pr_err("%s: vpe v4l2_device_register_subdev failed rc = %d\n", + __func__, rc); + goto fail3; + } + + rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle, + pcam->pvdev); + if (rc < 0) + goto fail4; + + rc = msm_send_open_server(pcam->vnode_id); + if (rc < 0) { + pr_err("%s failed\n", __func__); + goto fail5; + } + goto end; + +fail5: + v4l2_fh_del(&pcam_inst->eventHandle); + v4l2_fh_exit(&pcam_inst->eventHandle); +fail4: + v4l2_device_unregister_subdev(pcam->mctl.isp_sdev->sd_vpe); +fail3: + v4l2_device_unregister_subdev(pcam->mctl.isp_sdev->sd); +fail2: + if (pcam->mctl.mctl_release) + pcam->mctl.mctl_release(&(pcam->mctl)); +fail1: +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_client_destroy(pcam->mctl.client); +#endif +fail: + msm_cam_server_close_session(&g_server_dev, pcam); +end: + return rc; +} + +/* v4l2_file_operations */ +static int msm_open(struct file *f) +{ + int i; + int rc = -EINVAL; + /*struct msm_isp_ops *p_isp = 0;*/ + /* get the video device */ + struct msm_cam_v4l2_device *pcam = video_drvdata(f); + struct msm_cam_v4l2_dev_inst *pcam_inst; + + D("%s\n", __func__); + + if (!pcam) { + pr_err("%s NULL pointer passed in!\n", __func__); + return rc; + } + mutex_lock(&pcam->vid_lock); + for (i = 0; i < MSM_DEV_INST_MAX; i++) { + if (pcam->dev_inst[i] == NULL) + break; + } + /* if no instance is available, return error */ + if (i == MSM_DEV_INST_MAX) + goto end; + + pcam_inst = kzalloc(sizeof(struct msm_cam_v4l2_dev_inst), GFP_KERNEL); + if (!pcam_inst) { + mutex_unlock(&pcam->vid_lock); + return rc; + } + mutex_init(&pcam_inst->inst_lock); + pcam_inst->sensor_pxlcode = pcam->usr_fmts[0].pxlcode; + pcam_inst->my_index = i; + pcam_inst->pcam = pcam; + pcam_inst->vbqueue_initialized = 0; + pcam->dev_inst[i] = pcam_inst; + + D("%s for %s\n", __func__, pcam->pdev->name); + pcam->use_count++; + if (pcam->use_count == 1) { + rc = msm_open_init(pcam, pcam_inst); + if (rc < 0) + goto fail; + } + f->private_data = &pcam_inst->eventHandle; + rc = 0; + + goto end; + +fail: + pcam->use_count--; + pcam->dev_inst[pcam_inst->my_index] = NULL; + kfree(pcam_inst); + f->private_data = NULL; +end: + mutex_unlock(&pcam->vid_lock); + D("%s: end", __func__); + /* rc = msm_cam_server_open_session(g_server_dev, pcam);*/ + return rc; +} + +static int msm_addr_remap(struct msm_cam_v4l2_dev_inst *pcam_inst, + struct vm_area_struct *vma) +{ + int phyaddr; + int retval; + unsigned long size; + struct msm_sync *sync = &pcam_inst->pcam->mctl.sync; + int rc = 0; + + rc = msm_pmem_region_get_phy_addr(&sync->pmem_stats, + &pcam_inst->mem_map, + &phyaddr); + if (rc) { + pr_err("%s: cannot map vaddr", __func__); + return -EFAULT; + } + size = vma->vm_end - vma->vm_start; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + retval = remap_pfn_range(vma, vma->vm_start, + phyaddr >> PAGE_SHIFT, + size, vma->vm_page_prot); + if (retval) { + pr_err("%s:mmap: remap failed with error %d. ", + __func__, retval); + memset(&pcam_inst->mem_map, 0, sizeof(pcam_inst->mem_map)); + return -ENOMEM; + } + D("%s:mmap: phy_addr=0x%x: %08lx-%08lx, pgoff %08lx\n", + __func__, (uint32_t)phyaddr, + vma->vm_start, vma->vm_end, vma->vm_pgoff); + memset(&pcam_inst->mem_map, 0, sizeof(pcam_inst->mem_map)); + return 0; +} + +static int msm_mmap(struct file *f, struct vm_area_struct *vma) +{ + int rc = 0; + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + + D("mmap called, vma=0x%08lx\n", (unsigned long)vma); + + if (pcam_inst->is_mem_map_inst && + pcam_inst->mem_map.cookie) { + rc = msm_addr_remap(pcam_inst, vma); + D("%s: msm_addr_remap ret=%d\n", __func__, rc); + return rc; + } else + rc = vb2_mmap(&pcam_inst->vid_bufq, vma); + D("vma start=0x%08lx, size=%ld, ret=%d\n", + (unsigned long)vma->vm_start, + (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, + rc); + + return rc; +} + +void msm_release_ion_client(struct kref *ref) +{ + struct msm_cam_media_controller *mctl = container_of(ref, + struct msm_cam_media_controller, refcount); + pr_err("%s Calling ion_client_destroy ", __func__); + ion_client_destroy(mctl->client); +} + +static int msm_close(struct file *f) +{ + int rc = 0; + struct msm_cam_v4l2_device *pcam; + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + pcam = pcam_inst->pcam; + if (!pcam) { + pr_err("%s NULL pointer of camera device!\n", __func__); + return -EINVAL; + } + + mutex_lock(&pcam->vid_lock); +#if defined(CONFIG_MSM_IOMMU) + mutex_lock(&pcam_inst->inst_lock); + + if (pcam_inst->streamon) { + /*something went wrong since instance + is closing without streamoff*/ + if (pcam->mctl.mctl_release) { + rc = pcam->mctl.mctl_release(&(pcam->mctl)); + if (rc < 0) + pr_err("mctl_release fails %d\n", rc); + } + pcam->mctl.mctl_release = NULL;/*so that it isn't closed again*/ + } +#endif + + pcam_inst->streamon = 0; + pcam->use_count--; + pcam->dev_inst_map[pcam_inst->image_mode] = NULL; + if (pcam_inst->vbqueue_initialized) + vb2_queue_release(&pcam_inst->vid_bufq); + D("%s Closing down instance %p ", __func__, pcam_inst); + pcam->dev_inst[pcam_inst->my_index] = NULL; + if (pcam_inst->my_index == 0) { + v4l2_fh_del(&pcam_inst->eventHandle); + v4l2_fh_exit(&pcam_inst->eventHandle); + } + + mutex_unlock(&pcam_inst->inst_lock); + mutex_destroy(&pcam_inst->inst_lock); + kfree(pcam_inst); + f->private_data = NULL; + + if (pcam->use_count == 0) { + v4l2_device_unregister_subdev(pcam->mctl.isp_sdev->sd); + v4l2_device_unregister_subdev(pcam->mctl.isp_sdev->sd_vpe); + rc = msm_send_close_server(pcam->vnode_id); + if (rc < 0) + pr_err("msm_send_close_server failed %d\n", rc); + + rc = msm_cam_server_close_session(&g_server_dev, pcam); + if (rc < 0) + pr_err("msm_cam_server_close_session fails %d\n", rc); + + if (pcam->mctl.mctl_release) { + rc = pcam->mctl.mctl_release(&(pcam->mctl)); + if (rc < 0) + pr_err("mctl_release fails %d\n", rc); + } +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + kref_put(&pcam->mctl.refcount, msm_release_ion_client); +#endif + if (g_server_dev.use_count == 0) + mutex_unlock(&g_server_dev.server_lock); + } + mutex_unlock(&pcam->vid_lock); + return rc; +} + +static unsigned int msm_poll(struct file *f, struct poll_table_struct *wait) +{ + int rc = 0; + struct msm_cam_v4l2_device *pcam; + struct msm_cam_v4l2_dev_inst *pcam_inst; + pcam_inst = container_of(f->private_data, + struct msm_cam_v4l2_dev_inst, eventHandle); + pcam = pcam_inst->pcam; + D("%s\n", __func__); + if (!pcam) { + pr_err("%s NULL pointer of camera device!\n", __func__); + return -EINVAL; + } + if (pcam_inst->my_index == 0) { + poll_wait(f, &(pcam_inst->eventHandle.wait), wait); + if (v4l2_event_pending(&pcam_inst->eventHandle)) + rc |= POLLPRI; + } else { + if (!pcam_inst->vid_bufq.streaming) { + D("%s vid_bufq.streaming is off, inst=0x%x\n", + __func__, (u32)pcam_inst); + return -EINVAL; + } + rc |= vb2_poll(&pcam_inst->vid_bufq, f, wait); + } + D("%s returns, rc = 0x%x\n", __func__, rc); + return rc; +} + +static unsigned int msm_poll_server(struct file *fp, + struct poll_table_struct *wait) +{ + int rc = 0; + + D("%s\n", __func__); + poll_wait(fp, + &g_server_dev.server_command_queue.eventHandle.wait, + wait); + if (v4l2_event_pending(&g_server_dev.server_command_queue.eventHandle)) + rc |= POLLPRI; + + return rc; +} + +static long msm_ioctl_server(struct file *fp, unsigned int cmd, + unsigned long arg) +{ + int rc = -EINVAL; + struct v4l2_event ev; + struct msm_camera_info temp_cam_info; + struct msm_cam_config_dev_info temp_config_info; + struct v4l2_event_subscription temp_sub; + int i; + + D("%s: cmd %d\n", __func__, _IOC_NR(cmd)); + switch (cmd) { + case MSM_CAM_IOCTL_GET_CAMERA_INFO: + if (copy_from_user(&temp_cam_info, (void __user *)arg, + sizeof(struct msm_camera_info))) { + rc = -EINVAL; + return rc; + } + for (i = 0; i < g_server_dev.camera_info.num_cameras; i++) { + if (copy_to_user((void __user *) + temp_cam_info.video_dev_name[i], + g_server_dev.camera_info.video_dev_name[i], + strlen(g_server_dev.camera_info.video_dev_name[i]))) { + rc = -EINVAL; + return rc; + } + temp_cam_info.has_3d_support[i] = + g_server_dev.camera_info.has_3d_support[i]; + temp_cam_info.is_internal_cam[i] = + g_server_dev.camera_info.is_internal_cam[i]; + temp_cam_info.s_mount_angle[i] = + g_server_dev.camera_info.s_mount_angle[i]; + temp_cam_info.sensor_type[i] = + g_server_dev.camera_info.sensor_type[i]; + + } + temp_cam_info.num_cameras = + g_server_dev.camera_info.num_cameras; + if (copy_to_user((void __user *)arg, + &temp_cam_info, + sizeof(struct msm_camera_info))) { + rc = -EINVAL; + return rc; + } + rc = 0; + break; + + case MSM_CAM_IOCTL_GET_CONFIG_INFO: + if (copy_from_user(&temp_config_info, (void __user *)arg, + sizeof(struct msm_cam_config_dev_info))) { + rc = -EINVAL; + return rc; + } + for (i = 0; + i < g_server_dev.config_info.num_config_nodes; i++) { + if (copy_to_user( + (void __user *)temp_config_info.config_dev_name[i], + g_server_dev.config_info.config_dev_name[i], + strlen(g_server_dev.config_info.config_dev_name[i]))) { + rc = -EINVAL; + return rc; + } + } + temp_config_info.num_config_nodes = + g_server_dev.config_info.num_config_nodes; + if (copy_to_user((void __user *)arg, + &temp_config_info, + sizeof(struct msm_cam_config_dev_info))) { + rc = -EINVAL; + return rc; + } + rc = 0; + break; + + case VIDIOC_SUBSCRIBE_EVENT: + if (copy_from_user(&temp_sub, (void __user *)arg, + sizeof(struct v4l2_event_subscription))) { + rc = -EINVAL; + return rc; + } + rc = msm_server_v4l2_subscribe_event + (&g_server_dev.server_command_queue.eventHandle, + &temp_sub); + if (rc < 0) + return rc; + + break; + + case VIDIOC_DQEVENT: { + void __user *u_ctrl_value = NULL, *user_ptr = NULL; + struct msm_isp_event_ctrl u_isp_event; + struct msm_isp_event_ctrl *k_isp_event; + /* First, copy the event structure from userspace */ + D("%s: VIDIOC_DQEVENT\n", __func__); + if (copy_from_user(&ev, (void __user *)arg, + sizeof(struct v4l2_event))) { + break; + } + /* Next, get the pointer to event_ctrl structure + * embedded inside the v4l2_event.u.data array. */ + user_ptr = (void __user *)(*((uint32_t *)ev.u.data)); + + /* Next, copy the userspace event ctrl structure */ + if (copy_from_user((void *)&u_isp_event, user_ptr, + sizeof(struct msm_isp_event_ctrl))) { + rc = -EFAULT; + break; + } + + /* Save the pointer of the user allocated command buffer*/ + u_ctrl_value = u_isp_event.isp_data.ctrl.value; + /* Dequeue the event queued into the v4l2 queue*/ + ev.id = 0; + rc = v4l2_event_dequeue( + &g_server_dev.server_command_queue.eventHandle, + &ev, fp->f_flags & O_NONBLOCK); + + if (rc < 0) { + pr_err("no pending events?"); + rc = -EFAULT; + break; + } + /* Use k_isp_event to point to the event_ctrl structure + * embedded inside v4l2_event.u.data */ + k_isp_event = (struct msm_isp_event_ctrl *) + (*((uint32_t *)ev.u.data)); + if (!k_isp_event) { + pr_err("%s Invalid event ctrl structure. ", __func__); + rc = -EFAULT; + break; + } + if (k_isp_event->evt_id != g_server_dev.server_evt_id) { + pr_err("%s: isp_event->evt_id (0x%x) neq cur_server_evt_id (0x%x)", + __func__, k_isp_event->evt_id, g_server_dev.server_evt_id); + kfree(k_isp_event->isp_data.ctrl.value); + k_isp_event->isp_data.ctrl.value = NULL; + kfree(k_isp_event); + k_isp_event = NULL; + rc = -EFAULT; + break; + } + /* Copy the event structure into user struct*/ + u_isp_event = *k_isp_event; + + /* Restore the saved pointer of the user + * allocated command buffer. */ + u_isp_event.isp_data.ctrl.value = u_ctrl_value; + if (ev.type == V4L2_EVENT_PRIVATE_START+MSM_CAM_RESP_V4L2) { + /* Copy the ctrl cmd, if present*/ + if (k_isp_event->isp_data.ctrl.length > 0 && + k_isp_event->isp_data.ctrl.value != NULL) { + void *k_ctrl_value = + k_isp_event->isp_data.ctrl.value; + if (copy_to_user(u_ctrl_value, k_ctrl_value, + k_isp_event->isp_data.ctrl.length)) { + kfree(k_isp_event->isp_data.ctrl.value); + k_isp_event->isp_data.ctrl.value = NULL; + kfree(k_isp_event); + k_isp_event = NULL; + rc = -EINVAL; + break; + } + kfree(k_isp_event->isp_data.ctrl.value); + k_isp_event->isp_data.ctrl.value = NULL; + } + /* Copy the event ctrl structure back into + * user's structure. */ + if (copy_to_user(user_ptr, (void *)&u_isp_event, + sizeof(struct msm_isp_event_ctrl))) { + kfree(k_isp_event); + k_isp_event = NULL; + rc = -EINVAL; + break; + } + } + + /* Copy the v4l2_event structure back to the user*/ + if (copy_to_user((void __user *)arg, &ev, + sizeof(struct v4l2_event))) { + kfree(k_isp_event); + k_isp_event = NULL; + rc = -EINVAL; + break; + } + kfree(k_isp_event); + k_isp_event = NULL; + break; + } + case MSM_CAM_IOCTL_CTRL_CMD_DONE: + D("%s: MSM_CAM_IOCTL_CTRL_CMD_DONE\n", __func__); + rc = msm_ctrl_cmd_done((void __user *)arg); + break; + + case MSM_CAM_IOCTL_V4L2_EVT_NATIVE_CMD: + sensor_native_control((void __user *)arg); + rc = 0; + break; + + case MSM_CAM_IOCTL_V4L2_EVT_NATIVE_FRONT_CMD: + /*sensor_native_control_front((void __user *)arg);aswoogi_zsl*/ + rc = 0; + break; + + default: + pr_info("%s: trouble recognizing ioctl, break", __func__); + break; + } + return rc; +} + +static int msm_open_server(struct inode *inode, struct file *fp) +{ + int rc; + D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name); + mutex_lock(&g_server_dev.server_lock); + rc = nonseekable_open(inode, fp); + if (rc < 0) { + pr_err("%s: nonseekable_open error %d\n", __func__, rc); + mutex_unlock(&g_server_dev.server_lock); + return rc; + } + g_server_dev.use_count++; + if (g_server_dev.use_count == 1) + msm_queue_init(&g_server_dev.ctrl_q, "control"); + mutex_unlock(&g_server_dev.server_lock); + return rc; +} + +static unsigned int msm_poll_config(struct file *fp, + struct poll_table_struct *wait) +{ + int rc = 0; + struct msm_cam_config_dev *config = fp->private_data; + if (config == NULL) + return -EINVAL; + + D("%s\n", __func__); + + poll_wait(fp, + &config->config_stat_event_queue.eventHandle.wait, wait); + if (v4l2_event_pending(&config->config_stat_event_queue.eventHandle)) + rc |= POLLPRI; + + return rc; +} + +static int msm_close_server(struct inode *inode, struct file *fp) +{ + struct v4l2_event_subscription sub; + D("%s\n", __func__); + mutex_lock(&g_server_dev.server_lock); + if (g_server_dev.use_count > 0) + g_server_dev.use_count--; + mutex_unlock(&g_server_dev.server_lock); + if (g_server_dev.use_count == 0) { + if (g_server_dev.pcam_active) { + struct v4l2_event v4l2_ev; + mutex_lock(&g_server_dev.server_lock); + + v4l2_ev.type = V4L2_EVENT_PRIVATE_START + + MSM_CAM_APP_NOTIFY_ERROR_EVENT; + ktime_get_ts(&v4l2_ev.timestamp); + v4l2_event_queue( + g_server_dev.pcam_active->pvdev, &v4l2_ev); + } + sub.type = V4L2_EVENT_ALL; + sub.id = 0; + msm_server_v4l2_unsubscribe_event( + &g_server_dev.server_command_queue.eventHandle, &sub); + } + return 0; +} + +static long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl, + unsigned int cmd, unsigned long evt) +{ + struct v4l2_event v4l2_ev; + struct msm_cam_v4l2_device *pcam = NULL; + + if (!mctl) { + pr_err("%s: mctl is NULL\n", __func__); + return -EINVAL; + } + + if (copy_from_user(&v4l2_ev, (void __user *)evt, + sizeof(struct v4l2_event))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + pcam = mctl->sync.pcam_sync; + ktime_get_ts(&v4l2_ev.timestamp); + v4l2_event_queue(pcam->pvdev, &v4l2_ev); + return 0; +} + +static long msm_ioctl_config(struct file *fp, unsigned int cmd, + unsigned long arg) +{ + + int rc = 0; + struct v4l2_event ev; + struct msm_cam_config_dev *config_cam = fp->private_data; + struct v4l2_event_subscription temp_sub; + + D("%s: cmd %d\n", __func__, _IOC_NR(cmd)); + if (!g_server_dev.pcam_active) { + pr_err("%s: no active pcam instance.", __func__); + return -EINVAL; + } + + switch (cmd) { + /* memory management shall be handeld here*/ + case MSM_CAM_IOCTL_REGISTER_PMEM: + return msm_register_pmem( + &config_cam->p_mctl->sync.pmem_stats, + (void __user *)arg, config_cam->p_mctl->client); + break; + + case MSM_CAM_IOCTL_UNREGISTER_PMEM: + return msm_pmem_table_del( + &config_cam->p_mctl->sync.pmem_stats, + (void __user *)arg, config_cam->p_mctl->client); + break; + case VIDIOC_SUBSCRIBE_EVENT: + if (copy_from_user(&temp_sub, + (void __user *)arg, + sizeof(struct v4l2_event_subscription))) { + rc = -EINVAL; + return rc; + } + rc = msm_server_v4l2_subscribe_event + (&config_cam->config_stat_event_queue.eventHandle, + &temp_sub); + if (rc < 0) + return rc; + break; + + case VIDIOC_UNSUBSCRIBE_EVENT: + if (copy_from_user(&temp_sub, (void __user *)arg, + sizeof(struct v4l2_event_subscription))) { + rc = -EINVAL; + return rc; + } + rc = msm_server_v4l2_unsubscribe_event + (&config_cam->config_stat_event_queue.eventHandle, + &temp_sub); + if (rc < 0) + return rc; + break; + + case VIDIOC_DQEVENT: { + void __user *u_msg_value = NULL, *user_ptr = NULL; + struct msm_isp_event_ctrl u_isp_event; + struct msm_isp_event_ctrl *k_isp_event; + /* First, copy the v4l2 event structure from userspace */ + D("%s: VIDIOC_DQEVENT\n", __func__); + if (copy_from_user(&ev, (void __user *)arg, + sizeof(struct v4l2_event))) + break; + /* Next, get the pointer to event_ctrl structure + * embedded inside the v4l2_event.u.data array. */ + user_ptr = (void __user *)(*((uint32_t *)ev.u.data)); + + /* Next, copy the userspace event ctrl structure */ + if (copy_from_user((void *)&u_isp_event, user_ptr, + sizeof(struct msm_isp_event_ctrl))) { + break; + } + /* Save the pointer of the user allocated command buffer*/ + u_msg_value = u_isp_event.isp_data.isp_msg.data; + /* Dequeue the event queued into the v4l2 queue*/ + ev.id = 0; + rc = v4l2_event_dequeue( + &config_cam->config_stat_event_queue.eventHandle, + &ev, fp->f_flags & O_NONBLOCK); + if (rc < 0) { + pr_err("no pending events?"); + break; + } + /* Use k_isp_event to point to the event_ctrl structure + * embedded inside v4l2_event.u.data */ + k_isp_event = (struct msm_isp_event_ctrl *) + (*((uint32_t *)ev.u.data)); + /* Copy the event structure into user struct. */ + u_isp_event = *k_isp_event; + if (ev.type != (V4L2_EVENT_PRIVATE_START + + MSM_CAM_RESP_DIV_FRAME_EVT_MSG) && + ev.type != (V4L2_EVENT_PRIVATE_START + + MSM_CAM_RESP_MCTL_PP_EVENT)) { + + /* Restore the saved pointer of the + * user allocated command buffer. */ + u_isp_event.isp_data.isp_msg.data = u_msg_value; + + if (ev.type == (V4L2_EVENT_PRIVATE_START + + MSM_CAM_RESP_STAT_EVT_MSG)) { + if (k_isp_event->isp_data.isp_msg.len > 0) { + void *k_msg_value = + k_isp_event->isp_data.isp_msg.data; + if (copy_to_user(u_msg_value, + k_msg_value, + k_isp_event->isp_data.isp_msg.len)) { + rc = -EINVAL; + break; + } + kfree(k_msg_value); + k_msg_value = NULL; + } + } + } + /* Copy the event ctrl structure back + * into user's structure. */ + if (copy_to_user(user_ptr, + (void *)&u_isp_event, sizeof( + struct msm_isp_event_ctrl))) { + rc = -EINVAL; + break; + } + kfree(k_isp_event); + k_isp_event = NULL; + /* Copy the v4l2_event structure back to the user*/ + if (copy_to_user((void __user *)arg, &ev, + sizeof(struct v4l2_event))) { + rc = -EINVAL; + break; + } + } + + break; + + case MSM_CAM_IOCTL_V4L2_EVT_NOTIFY: + rc = msm_v4l2_evt_notify(config_cam->p_mctl, cmd, arg); + break; + + case MSM_CAM_IOCTL_SET_MEM_MAP_INFO: + if (copy_from_user(&config_cam->mem_map, (void __user *)arg, + sizeof(struct msm_mem_map_info))) + rc = -EINVAL; + break; + + default:{ + /* For the rest of config command, forward to media controller*/ + struct msm_cam_media_controller *p_mctl = config_cam->p_mctl; + if (p_mctl && p_mctl->mctl_cmd) { + rc = config_cam->p_mctl->mctl_cmd(p_mctl, cmd, arg); + } else { + rc = -EINVAL; + pr_err("%s: media controller is null\n", __func__); + } + + break; + } /* end of default*/ + } /* end of switch*/ + return rc; +} + +static int msm_mmap_config(struct file *fp, struct vm_area_struct *vma) +{ + struct msm_cam_config_dev *config_cam = fp->private_data; + int rc = 0; + int phyaddr; + int retval; + unsigned long size; + + D("%s: phy_addr=0x%x", __func__, config_cam->mem_map.cookie); + phyaddr = (int)config_cam->mem_map.cookie; + if (!phyaddr) { + pr_err("%s: no physical memory to map", __func__); + return -EFAULT; + } + memset(&config_cam->mem_map, 0, + sizeof(struct msm_mem_map_info)); + size = vma->vm_end - vma->vm_start; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + retval = remap_pfn_range(vma, vma->vm_start, + phyaddr >> PAGE_SHIFT, + size, vma->vm_page_prot); + if (retval) { + pr_err("%s: remap failed, rc = %d", + __func__, retval); + rc = -ENOMEM; + goto end; + } + D("%s: phy_addr=0x%x: %08lx-%08lx, pgoff %08lx\n", + __func__, (uint32_t)phyaddr, + vma->vm_start, vma->vm_end, vma->vm_pgoff); +end: + return rc; +} + +static int msm_open_config(struct inode *inode, struct file *fp) +{ + int rc; + + struct msm_cam_config_dev *config_cam = + container_of(inode->i_cdev, struct msm_cam_config_dev, config_cdev); + + D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name); + + if (!g_server_dev.pcam_active) { + pr_err("%s: no active pcam instance.", __func__); + return -EINVAL; + } + + rc = nonseekable_open(inode, fp); + if (rc < 0) { + pr_err("%s: nonseekable_open error %d\n", __func__, rc); + return rc; + } + config_cam->use_count++; + + /*config_cam->isp_subdev = g_server_dev.pcam_active->mctl.isp_sdev;*/ + /* assume there is only one active camera possible*/ + config_cam->p_mctl = &g_server_dev.pcam_active->mctl; + + INIT_HLIST_HEAD(&config_cam->p_mctl->sync.pmem_stats); + spin_lock_init(&config_cam->p_mctl->sync.pmem_stats_spinlock); + + config_cam->p_mctl->config_device = config_cam; + kref_get(&config_cam->p_mctl->refcount); + fp->private_data = config_cam; + return rc; +} + +static int msm_close_config(struct inode *node, struct file *f) +{ + struct msm_cam_config_dev *config_cam = f->private_data; + D("%s Decrementing ref count of config node ", __func__); + kref_put(&config_cam->p_mctl->refcount, msm_release_ion_client); + return 0; +} + +static struct v4l2_file_operations g_msm_fops = { + .owner = THIS_MODULE, + .open = msm_open, + .poll = msm_poll, + .mmap = msm_mmap, + .release = msm_close, + .ioctl = video_ioctl2, +}; + +/* Init a config node for ISP control, + * which will create a config device (/dev/config0/ and plug in + * ISP's operation "v4l2_ioctl_ops*" + */ +static const struct file_operations msm_fops_server = { + .owner = THIS_MODULE, + .open = msm_open_server, + .poll = msm_poll_server, + .unlocked_ioctl = msm_ioctl_server, + .release = msm_close_server, +}; + +static const struct file_operations msm_fops_config = { + .owner = THIS_MODULE, + .open = msm_open_config, + .poll = msm_poll_config, + .unlocked_ioctl = msm_ioctl_config, + .mmap = msm_mmap_config, + .release = msm_close_config, +}; + +static int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle, + struct video_device *pvdev) +{ + int rc = 0; + /* v4l2_fh support */ + spin_lock_init(&pvdev->fh_lock); + INIT_LIST_HEAD(&pvdev->fh_list); + + v4l2_fh_init(eventHandle, pvdev); +// if (rc < 0) +// return rc; +// if (eventHandle->events == NULL) { +// rc = v4l2_event_init(eventHandle); +// if (rc < 0) +// return rc; +// } + + /* queue of max size 30 */ +// rc = v4l2_event_alloc(eventHandle, 30); +// if (rc < 0) +// return rc; + + v4l2_fh_add(eventHandle); + return rc; + +} + +static int msm_setup_config_dev(int node, char *device_name) +{ + int rc = -ENODEV; + struct device *device_config; + int dev_num = node; + dev_t devno; + struct msm_cam_config_dev *config_cam; + + config_cam = kzalloc(sizeof(*config_cam), GFP_KERNEL); + if (!config_cam) { + pr_err("%s: could not allocate memory for msm_cam_config_device\n", + __func__); + return -ENOMEM; + } + + D("%s\n", __func__); + + devno = MKDEV(MAJOR(msm_devno), dev_num+1); + device_config = device_create(msm_class, NULL, devno, NULL, + "%s%d", device_name, dev_num); + + if (IS_ERR(device_config)) { + rc = PTR_ERR(device_config); + pr_err("%s: error creating device: %d\n", __func__, rc); + kfree(config_cam); + return rc; + } + + cdev_init(&config_cam->config_cdev, + &msm_fops_config); + config_cam->config_cdev.owner = THIS_MODULE; + + rc = cdev_add(&config_cam->config_cdev, devno, 1); + if (rc < 0) { + pr_err("%s: error adding cdev: %d\n", __func__, rc); + kfree(config_cam); + device_destroy(msm_class, devno); + return rc; + } + g_server_dev.config_info.config_dev_name[dev_num] + = dev_name(device_config); + D("%s Connected config device %s\n", __func__, + g_server_dev.config_info.config_dev_name[dev_num]); + g_server_dev.config_info.config_dev_id[dev_num] + = dev_num; + + config_cam->config_stat_event_queue.pvdev = video_device_alloc(); + if (config_cam->config_stat_event_queue.pvdev == NULL) { + pr_err("%s: video_device_alloc failed\n", __func__); + kfree(config_cam); + return -ENOMEM; + } + + rc = msm_setup_v4l2_event_queue( + &config_cam->config_stat_event_queue.eventHandle, + config_cam->config_stat_event_queue.pvdev); + if (rc < 0) + pr_err("%s failed to initialize event queue\n", __func__); + + return rc; +} + +static int msm_setup_server_dev(int node, char *device_name) +{ + int rc = -ENODEV; + struct device *device_server; + int dev_num = node; + dev_t devno; + + D("%s\n", __func__); + + devno = MKDEV(MAJOR(msm_devno), dev_num); + device_server = device_create(msm_class, NULL, + devno, NULL, "%s", device_name); + + if (IS_ERR(device_server)) { + rc = PTR_ERR(device_server); + pr_err("%s: error creating device: %d\n", __func__, rc); + return rc; + } + + cdev_init(&g_server_dev.server_cdev, &msm_fops_server); + g_server_dev.server_cdev.owner = THIS_MODULE; + + rc = cdev_add(&g_server_dev.server_cdev, devno, 1); + if (rc < 0) { + pr_err("%s: error adding cdev: %d\n", __func__, rc); + device_destroy(msm_class, devno); + return rc; + } + + mutex_init(&g_server_dev.server_lock); + g_server_dev.pcam_active = NULL; + g_server_dev.camera_info.num_cameras = 0; + atomic_set(&g_server_dev.number_pcam_active, 0); + + /*initialize fake video device and event queue*/ + + g_server_dev.server_command_queue.pvdev = video_device_alloc(); + if (g_server_dev.server_command_queue.pvdev == NULL) { + pr_err("%s: video_device_alloc failed\n", __func__); + return -ENOMEM; + } + rc = msm_setup_v4l2_event_queue( + &g_server_dev.server_command_queue.eventHandle, + g_server_dev.server_command_queue.pvdev); + if (rc < 0) + pr_err("%s failed to initialize event queue\n", __func__); + + return rc; +} + +static int msm_cam_dev_init(struct msm_cam_v4l2_device *pcam) +{ + int rc = -ENOMEM; + struct video_device *pvdev = NULL; + D("%s\n", __func__); + + /* first register the v4l2 device */ + pcam->v4l2_dev.dev = &pcam->pdev->dev; + rc = v4l2_device_register(pcam->v4l2_dev.dev, &pcam->v4l2_dev); + if (rc < 0) + return -EINVAL; + else + pcam->v4l2_dev.notify = msm_cam_v4l2_subdev_notify; + + + /* now setup video device */ + pvdev = video_device_alloc(); + if (pvdev == NULL) { + pr_err("%s: video_device_alloc failed\n", __func__); + return rc; + } + + /* init video device's driver interface */ + D("sensor name = %s, sizeof(pvdev->name)=%d\n", + pcam->pdev->name, sizeof(pvdev->name)); + + /* device info - strlcpy is safer than strncpy but + only if architecture supports*/ + strlcpy(pvdev->name, pcam->pdev->name, sizeof(pvdev->name)); + + pvdev->release = video_device_release; + pvdev->fops = &g_msm_fops; + pvdev->ioctl_ops = &g_msm_ioctl_ops; + pvdev->minor = -1; + pvdev->vfl_type = 1; + + /* register v4l2 video device to kernel as /dev/videoXX */ + D("video_register_device\n"); + rc = video_register_device(pvdev, + VFL_TYPE_GRABBER, + msm_camera_v4l2_nr); + if (rc) { + pr_err("%s: video_register_device failed\n", __func__); + goto reg_fail; + } + D("%s: video device registered as /dev/video%d\n", + __func__, pvdev->num); + + /* connect pcam and video dev to each other */ + pcam->pvdev = pvdev; + video_set_drvdata(pcam->pvdev, pcam); + + /* If isp HW registeration is successful, + * then create event queue to + * receievent event froms HW + */ + /* yyan: no global - each sensor will + * create a new vidoe node! */ + /* g_pmsm_camera_v4l2_dev = pmsm_camera_v4l2_dev; */ + /* g_pmsm_camera_v4l2_dev->pvdev = pvdev; */ + + return rc ; + +reg_fail: + video_device_release(pvdev); + v4l2_device_unregister(&pcam->v4l2_dev); + pcam->v4l2_dev.dev = NULL; + return rc; +} + +static int msm_sync_destroy(struct msm_sync *sync) +{ + if (sync) { + mutex_destroy(&sync->lock); + wake_lock_destroy(&sync->wake_lock); + } + return 0; +} + +static int msm_actuator_probe(struct msm_actuator_info *actuator_info, + struct v4l2_subdev *act_sdev, + struct msm_actuator_ctrl *actctrl) +{ + int rc = 0; + struct i2c_adapter *adapter = NULL; + void *act_client = NULL; + struct msm_actuator_ctrl *a_ext_ctrl = NULL; + + D("%s called\n", __func__); + + if (!actuator_info) + goto probe_fail; + + adapter = i2c_get_adapter(actuator_info->bus_id); + if (!adapter) + goto probe_fail; + + act_client = i2c_new_device(adapter, actuator_info->board_info); + if (!act_client) + goto device_fail; + + a_ext_ctrl = (struct msm_actuator_ctrl *)i2c_get_clientdata(act_client); + if (!a_ext_ctrl) + goto client_fail; + + *actctrl = *a_ext_ctrl; + a_ext_ctrl->a_create_subdevice((void *)actuator_info->board_info, + (void *)act_sdev); + return rc; + +client_fail: + i2c_unregister_device(act_client); +device_fail: + i2c_put_adapter(adapter); + adapter = NULL; +probe_fail: + actctrl->a_init_table = NULL; + actctrl->a_power_up = NULL; + actctrl->a_power_down = NULL; + actctrl->a_config = NULL; + actctrl->a_create_subdevice = NULL; + return rc; +} + +static int msm_sync_init(struct msm_sync *sync, + struct platform_device *pdev) +{ + int rc = 0; + + sync->sdata = pdev->dev.platform_data; + + wake_lock_init(&sync->wake_lock, WAKE_LOCK_SUSPEND, "msm_camera"); + + sync->pdev = pdev; + sync->opencnt = 0; + + mutex_init(&sync->lock); + D("%s: initialized %s\n", __func__, sync->sdata->sensor_name); + return rc; +} + +/* register a msm sensor into the msm device, which will probe the + * sensor HW. if the HW exist then create a video device (/dev/videoX/) + * to represent this sensor */ +int msm_sensor_register(struct platform_device *pdev, + int (*sensor_probe)(const struct msm_camera_sensor_info *, + struct v4l2_subdev *, struct msm_sensor_ctrl *)) +{ + + int rc = -EINVAL; + struct msm_camera_sensor_info *sdata = pdev->dev.platform_data; + struct msm_cam_v4l2_device *pcam; + struct v4l2_subdev *sdev = NULL; + struct msm_sensor_ctrl *sctrl = NULL; + struct v4l2_subdev *act_sdev = NULL; + struct msm_actuator_ctrl *actctrl = NULL; + + D("%s for %s\n", __func__, pdev->name); + + /* allocate the memory for the camera device first */ + pcam = kzalloc(sizeof(*pcam), GFP_KERNEL); + if (!pcam) { + pr_err("%s: could not allocate mem for msm_cam_v4l2_device\n", + __func__); + return -ENOMEM; + } + + pcam->mctl.sensor_sdev = kzalloc(sizeof(struct v4l2_subdev), + GFP_KERNEL); + if (!pcam->mctl.sensor_sdev) { + pr_err("%s: could not allocate mem for sensor v4l2_subdev\n", + __func__); + kfree(pcam); + return -ENOMEM; + } + + sdev = pcam->mctl.sensor_sdev; + snprintf(sdev->name, sizeof(sdev->name), "%s", pdev->name); + sctrl = &pcam->mctl.sync.sctrl; + +#if !defined(CONFIG_S5C73M3) && !defined(CONFIG_S5K6A3YX) + /* come sensor probe logic */ + rc = msm_camio_probe_on(pdev); + if (rc < 0) { + kzfree(pcam); + return rc; + } +#endif + + rc = sensor_probe(sdata, sdev, sctrl); + if (rc < 0) { + pr_err("%s: failed to detect %s\n", + __func__, + sdata->sensor_name); + msm_camio_probe_off(pdev); + kzfree(sdev); + kzfree(pcam); + return rc; + } + + pcam->mctl.act_sdev = kzalloc(sizeof(struct v4l2_subdev), + GFP_KERNEL); + if (!pcam->mctl.act_sdev) { + pr_err("%s: could not allocate mem for actuator v4l2_subdev\n", + __func__); + msm_camio_probe_off(pdev); + kzfree(sdev); + kfree(pcam); + return -ENOMEM; + } + + act_sdev = pcam->mctl.act_sdev; + actctrl = &pcam->mctl.sync.actctrl; + + msm_actuator_probe(sdata->actuator_info, + act_sdev, actctrl); + +#if !defined(CONFIG_S5C73M3) && !defined(CONFIG_S5K6A3YX) + msm_camio_probe_off(pdev); +#endif + + /* setup a manager object*/ + rc = msm_sync_init(&pcam->mctl.sync, pdev); + if (rc < 0) + goto failure; + D("%s: pcam =0x%p\n", __func__, pcam); + D("%s: &pcam->mctl.sync =0x%p\n", __func__, &pcam->mctl.sync); + + pcam->mctl.sync.pcam_sync = pcam; + /* bind the driver device to the sensor device */ + pcam->pdev = pdev; + + /* init the user count and lock*/ + pcam->use_count = 0; + mutex_init(&pcam->vid_lock); + + /* Initialize the formats supported */ + rc = msm_mctl_init_user_formats(pcam); + if (rc < 0) + goto failure; + + /* now initialize the camera device object */ + rc = msm_cam_dev_init(pcam); + if (rc < 0) + goto failure; + + g_server_dev.camera_info.video_dev_name + [g_server_dev.camera_info.num_cameras] + = video_device_node_name(pcam->pvdev); + D("%s Connected video device %s\n", __func__, + g_server_dev.camera_info.video_dev_name + [g_server_dev.camera_info.num_cameras]); + + g_server_dev.camera_info.s_mount_angle + [g_server_dev.camera_info.num_cameras] + = sctrl->s_mount_angle; + + g_server_dev.camera_info.is_internal_cam + [g_server_dev.camera_info.num_cameras] + = sctrl->s_camera_type; + + g_server_dev.camera_info.num_cameras++; + + D("%s done, rc = %d\n", __func__, rc); + D("%s number of sensors connected is %d\n", __func__, + g_server_dev.camera_info.num_cameras); +/* + if (g_server_dev.camera_info.num_cameras == 1) { + rc = add_axi_qos(); + if (rc < 0) + goto failure; + } +*/ + /* register the subdevice, must be done for callbacks */ + rc = v4l2_device_register_subdev(&pcam->v4l2_dev, sdev); + if (rc < 0) { + D("%s sensor sub device register failed\n", + __func__); + goto failure; + } + if (sdata->actuator_info) { + rc = v4l2_device_register_subdev(&pcam->v4l2_dev, act_sdev); + if (rc < 0) { + D("%s actuator sub device register failed\n", + __func__); + goto failure; + } + } + pcam->vnode_id = vnode_count++; + return rc; + +failure: + /* mutex_destroy not needed at this moment as the associated + implemenation of mutex_init is not consuming resources */ + msm_sync_destroy(&pcam->mctl.sync); + pcam->pdev = NULL; + kfree(act_sdev); + kfree(sdev); + kzfree(pcam); + return rc; +} +EXPORT_SYMBOL(msm_sensor_register); + +static int __init msm_camera_init(void) +{ + int rc = 0, i; + /*for now just create a config 0 node + put logic here later to know how many configs to create*/ + g_server_dev.config_info.num_config_nodes = 1; + rc = msm_isp_init_module(g_server_dev.config_info.num_config_nodes); + if (rc < 0) { + pr_err("Failed to initialize isp\n"); + return rc; + } + + if (!msm_class) { + rc = alloc_chrdev_region(&msm_devno, 0, + g_server_dev.config_info.num_config_nodes+1, "msm_camera"); + if (rc < 0) { + pr_err("%s: failed to allocate chrdev: %d\n", __func__, + rc); + return rc; + } + + msm_class = class_create(THIS_MODULE, "msm_camera"); + if (IS_ERR(msm_class)) { + rc = PTR_ERR(msm_class); + pr_err("%s: create device class failed: %d\n", + __func__, rc); + return rc; + } + } + + D("creating server and config nodes\n"); + rc = msm_setup_server_dev(0, "video_msm"); + if (rc < 0) { + pr_err("%s: failed to create server dev: %d\n", __func__, + rc); + return rc; + } + + for (i = 0; i < g_server_dev.config_info.num_config_nodes; i++) { + rc = msm_setup_config_dev(i, "config"); + if (rc < 0) { + pr_err("%s:failed to create config dev: %d\n", + __func__, rc); + return rc; + } + } + + msm_isp_register(&g_server_dev); + return rc; +} + +static void __exit msm_camera_exit(void) +{ + msm_isp_unregister(&g_server_dev); +} + +module_init(msm_camera_init); +module_exit(msm_camera_exit); diff --git a/drivers/media/video/msm_zsl/msm.h b/drivers/media/video/msm_zsl/msm.h new file mode 100755 index 00000000000..8c4fce9821e --- /dev/null +++ b/drivers/media/video/msm_zsl/msm.h @@ -0,0 +1,502 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef _MSM_H +#define _MSM_H + +#ifdef __KERNEL__ + +/* Header files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSM_V4L2_DIMENSION_SIZE 96 +#define MAX_DEV_NAME_LEN 50 + +#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \ + __func__, __LINE__, ((to) ? "to" : "from")) +#define ERR_COPY_FROM_USER() ERR_USER_COPY(0) +#define ERR_COPY_TO_USER() ERR_USER_COPY(1) + +#define MSM_CSIPHY_DRV_NAME "msm_csiphy" +#define MSM_CSID_DRV_NAME "msm_csid" +#define MSM_ISPIF_DRV_NAME "msm_ispif" +#define MSM_VFE_DRV_NAME "msm_vfe" +#define MSM_VPE_DRV_NAME "msm_vpe" + +/* msm queue management APIs*/ + +#define msm_dequeue(queue, member) ({ \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + __q->len--; \ + qcmd = list_first_entry(&__q->list, \ + struct msm_queue_cmd, member); \ + list_del_init(&qcmd->member); \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + qcmd; \ +}) + +#define msm_queue_drain(queue, member) do { \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd; \ + spin_lock_irqsave(&__q->lock, flags); \ + while (!list_empty(&__q->list)) { \ + qcmd = list_first_entry(&__q->list, \ + struct msm_queue_cmd, member); \ + list_del_init(&qcmd->member); \ + free_qcmd(qcmd); \ + }; \ + spin_unlock_irqrestore(&__q->lock, flags); \ +} while (0) + +static inline void free_qcmd(struct msm_queue_cmd *qcmd) +{ + if (!qcmd || !atomic_read(&qcmd->on_heap)) + return; + if (!atomic_sub_return(1, &qcmd->on_heap)) + kfree(qcmd); +} + +struct isp_msg_stats { + uint32_t id; + uint32_t buffer; + uint32_t frameCounter; +}; + +struct msm_free_buf { + uint8_t num_planes; + uint32_t ch_paddr[VIDEO_MAX_PLANES]; + uint32_t vb; +}; + +struct isp_msg_event { + uint32_t msg_id; + uint32_t sof_count; +}; + +struct isp_msg_output { + uint8_t output_id; + struct msm_free_buf buf; + uint32_t frameCounter; +}; + +/* message id for v4l2_subdev_notify*/ +enum msm_camera_v4l2_subdev_notify { + NOTIFY_CID_CHANGE, /* arg = msm_camera_csid_params */ + NOTIFY_ISP_MSG_EVT, /* arg = enum ISP_MESSAGE_ID */ + NOTIFY_VFE_MSG_OUT, /* arg = struct isp_msg_output */ + NOTIFY_VFE_MSG_STATS, /* arg = struct isp_msg_stats */ + NOTIFY_VFE_BUF_EVT, /* arg = struct msm_vfe_resp */ + NOTIFY_ISPIF_STREAM, /* arg = enable parameter for s_stream */ + NOTIFY_VPE_MSG_EVT, + NOTIFY_PCLK_CHANGE, /* arg = pclk */ + NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */ + NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */ + NOTIFY_INVALID +}; + +enum isp_vfe_cmd_id { + /* + *Important! Command_ID are arranged in order. + *Don't change!*/ + ISP_VFE_CMD_ID_STREAM_ON, + ISP_VFE_CMD_ID_STREAM_OFF, + ISP_VFE_CMD_ID_FRAME_BUF_RELEASE +}; + +struct msm_cam_v4l2_device; +struct msm_cam_v4l2_dev_inst; +#define MSM_MAX_IMG_MODE 8 + +enum msm_buffer_state { + MSM_BUFFER_STATE_UNUSED, + MSM_BUFFER_STATE_INITIALIZED, + MSM_BUFFER_STATE_PREPARED, + MSM_BUFFER_STATE_QUEUED, + MSM_BUFFER_STATE_RESERVED, + MSM_BUFFER_STATE_DEQUEUED +}; + +/* buffer for one video frame */ +struct msm_frame_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_buffer vidbuf; + struct list_head list; + enum v4l2_mbus_pixelcode pxlcode; + enum msm_buffer_state state; + int active; +}; + +struct msm_isp_color_fmt { + char *name; + int depth; + int bitsperpxl; + u32 fourcc; + enum v4l2_mbus_pixelcode pxlcode; + enum v4l2_colorspace colorspace; +}; + +struct msm_mctl_pp_frame_info { + int user_cmd; + struct msm_pp_frame src_frame; + struct msm_pp_frame dest_frame; + struct msm_mctl_pp_frame_cmd pp_frame_cmd; +}; + +struct msm_mctl_pp_ctrl { + int pp_msg_type; + struct msm_mctl_pp_frame_info *pp_frame_info; + +}; +struct msm_mctl_pp_info { + spinlock_t lock; + uint32_t cnt; + uint32_t pp_key; + uint32_t cur_frame_id[MSM_MAX_IMG_MODE]; + struct msm_free_buf div_frame[MSM_MAX_IMG_MODE]; + struct msm_mctl_pp_ctrl pp_ctrl; + +}; +/* "Media Controller" represents a camera steaming session, + * which consists of a "sensor" device and an "isp" device + * (such as VFE, if needed), connected via an "IO" device, + * (such as IPIF on 8960, or none on 8660) plus other extra + * sub devices such as VPE and flash. + */ + +struct msm_cam_media_controller { + + int (*mctl_open)(struct msm_cam_media_controller *p_mctl, + const char *const apps_id); + int (*mctl_cb)(void); + int (*mctl_notify)(struct msm_cam_media_controller *p_mctl, + unsigned int notification, void *arg); + int (*mctl_cmd)(struct msm_cam_media_controller *p_mctl, + unsigned int cmd, unsigned long arg); + int (*mctl_release)(struct msm_cam_media_controller *p_mctl); + int (*mctl_buf_init)(struct msm_cam_v4l2_dev_inst *pcam); + int (*mctl_vbqueue_init)(struct msm_cam_v4l2_dev_inst *pcam, + struct vb2_queue *q, enum v4l2_buf_type type); + int (*mctl_ufmt_init)(struct msm_cam_media_controller *p_mctl); + + struct v4l2_fh eventHandle; /* event queue to export events */ + /* most-frequently accessed manager object*/ + struct msm_sync sync; + + + /* the following reflect the HW topology information*/ + /*mandatory*/ + struct v4l2_subdev *sensor_sdev; /* sensor sub device */ + struct v4l2_subdev mctl_sdev; /* media control sub device */ + struct platform_device *plat_dev; + /*optional*/ + struct msm_isp_ops *isp_sdev; /* isp sub device : camif/VFE */ + struct v4l2_subdev *vpe_sdev; /* vpe sub device : VPE */ + struct v4l2_subdev *flash_sdev; /* vpe sub device : VPE */ + struct msm_cam_config_dev *config_device; + struct v4l2_subdev *csiphy_sdev; /*csiphy sub device*/ + struct v4l2_subdev *csid_sdev; /*csid sub device*/ + struct v4l2_subdev *ispif_sdev; /* ispif sub device */ + struct v4l2_subdev *act_sdev; /* actuator sub device */ + + struct pm_qos_request *pm_qos_req_list; + struct msm_mctl_pp_info pp_info; + struct ion_client *client; + struct kref refcount; +}; + +/* abstract camera device represents a VFE and connected sensor */ +struct msm_isp_ops { + char *config_dev_name; + + /*int (*isp_init)(struct msm_cam_v4l2_device *pcam);*/ + int (*isp_open)(struct v4l2_subdev *sd, struct v4l2_subdev *sd_vpe, + struct msm_sync *sync); + int (*isp_config)(struct msm_cam_media_controller *pmctl, + unsigned int cmd, unsigned long arg); + int (*isp_notify)(struct v4l2_subdev *sd, + unsigned int notification, void *arg); + void (*isp_release)(struct msm_sync *psync); + int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl, + struct msm_mctl_pp_cmd, void *data); + + /* vfe subdevice */ + struct v4l2_subdev *sd; + struct v4l2_subdev *sd_vpe; +}; + +struct msm_isp_buf_info { + int type; + unsigned long buffer; + int fd; +}; +struct msm_cam_buf_offset { + uint32_t addr_offset; + uint32_t data_offset; +}; + +#define MSM_DEV_INST_MAX 16 +struct msm_cam_v4l2_dev_inst { + struct v4l2_fh eventHandle; + struct vb2_queue vid_bufq; + spinlock_t vq_irqlock; + struct list_head free_vq; + struct v4l2_format vid_fmt; + /* sensor pixel code*/ + enum v4l2_mbus_pixelcode sensor_pxlcode; + struct msm_cam_v4l2_device *pcam; + int my_index; + int image_mode; + int path; + int buf_count; + /* buffer offsets, if any */ + struct msm_cam_buf_offset **buf_offset; + struct v4l2_crop crop; + int streamon; + struct msm_mem_map_info mem_map; + int is_mem_map_inst; + struct img_plane_info plane_info; + int vbqueue_initialized; + struct mutex inst_lock; +}; +/* abstract camera device for each sensor successfully probed*/ +struct msm_cam_v4l2_device { + /* standard device interfaces */ + /* parent of video device to trace back */ + struct device dev; + /* sensor's platform device*/ + struct platform_device *pdev; + /* V4l2 device */ + struct v4l2_device v4l2_dev; + /* will be registered as /dev/video*/ + struct video_device *pvdev; + int use_count; + /* will be used to init/release HW */ + struct msm_cam_media_controller mctl; + + /* parent device */ + struct device *parent_dev; + + struct mutex vid_lock; + /* v4l2 format support */ + struct msm_isp_color_fmt *usr_fmts; + int num_fmts; + /* preview or snapshot */ + u32 mode; + u32 memsize; + + int op_mode; + int vnode_id; + struct msm_cam_v4l2_dev_inst *dev_inst[MSM_DEV_INST_MAX]; + struct msm_cam_v4l2_dev_inst *dev_inst_map[MSM_MAX_IMG_MODE]; + /* native config device */ + struct cdev cdev; + + /* The message queue is used by the control thread to send commands + * to the config thread, and also by the HW to send messages to the + * config thread. Thus it is the only queue that is accessed from + * both interrupt and process context. + */ + /* struct msm_device_queue event_q; */ + + /* This queue used by the config thread to send responses back to the + * control thread. It is accessed only from a process context. + * TO BE REMOVED + */ + struct msm_device_queue ctrl_q; + + struct mutex lock; + uint8_t ctrl_data[max_control_command_size]; + struct msm_ctrl_cmd ctrl; + uint32_t event_mask; +}; +static inline struct msm_cam_v4l2_device *to_pcam( + struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct msm_cam_v4l2_device, v4l2_dev); +} + +/*pseudo v4l2 device and v4l2 event queue + for server and config cdevs*/ +struct v4l2_queue_util { + struct video_device *pvdev; + struct v4l2_fh eventHandle; +}; + +/* abstract config device for all sensor successfully probed*/ +struct msm_cam_config_dev { + struct cdev config_cdev; + struct v4l2_queue_util config_stat_event_queue; + int use_count; + /*struct msm_isp_ops* isp_subdev;*/ + struct msm_cam_media_controller *p_mctl; + struct msm_mem_map_info mem_map; +}; + +/* abstract camera server device for all sensor successfully probed*/ +struct msm_cam_server_dev { + + /* config node device*/ + struct cdev server_cdev; + /* info of sensors successfully probed*/ + struct msm_camera_info camera_info; + /* info of configs successfully created*/ + struct msm_cam_config_dev_info config_info; + /* active working camera device - only one allowed at this time*/ + struct msm_cam_v4l2_device *pcam_active; + /* number of camera devices opened*/ + atomic_t number_pcam_active; + struct v4l2_queue_util server_command_queue; + /* This queue used by the config thread to send responses back to the + * control thread. It is accessed only from a process context. + */ + struct msm_device_queue ctrl_q; + uint8_t ctrl_data[max_control_command_size]; + struct msm_ctrl_cmd ctrl; + int use_count; + /* all the registered ISP subdevice*/ + struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS]; + struct mutex server_lock; + uint32_t server_evt_id; +}; + +/* camera server related functions */ + + +/* ISP related functions */ +void msm_isp_vfe_dev_init(struct v4l2_subdev *vd); +/* +int msm_isp_register(struct msm_cam_v4l2_device *pcam); +*/ +int msm_isp_register(struct msm_cam_server_dev *psvr); +void msm_isp_unregister(struct msm_cam_server_dev *psvr); +int msm_sensor_register(struct platform_device *pdev, + int (*sensor_probe)(const struct msm_camera_sensor_info *, + struct v4l2_subdev *, struct msm_sensor_ctrl *)); +int msm_isp_init_module(int g_num_config_nodes); + +int msm_mctl_init_module(struct msm_cam_v4l2_device *pcam); +int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam); +int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam); +int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl, + int msg_type, struct msm_free_buf *buf, + uint32_t frame_id); +int msm_mctl_buf_done_pp(struct msm_cam_media_controller *pmctl, + int msg_type, struct msm_free_buf *frame, int dirty); +int msm_mctl_reserve_free_buf(struct msm_cam_media_controller *pmctl, + int path, struct msm_free_buf *free_buf); +int msm_mctl_check_free_buf(struct msm_cam_media_controller *pmctl, + int path); +int msm_mctl_release_free_buf(struct msm_cam_media_controller *pmctl, + int path, struct msm_free_buf *free_buf); +/*Memory(PMEM) functions*/ +int msm_register_pmem(struct hlist_head *ptype, void __user *arg, + struct ion_client *client); +int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg, + struct ion_client *client); +int msm_pmem_region_get_phy_addr(struct hlist_head *ptype, + struct msm_mem_map_info *mem_map, int32_t *phyaddr); +uint8_t msm_pmem_region_lookup(struct hlist_head *ptype, + int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount); +uint8_t msm_pmem_region_lookup_2(struct hlist_head *ptype, + int pmem_type, + struct msm_pmem_region *reg, + uint8_t maxcount); +unsigned long msm_pmem_stats_vtop_lookup( + struct msm_sync *sync, + unsigned long buffer, + int fd); +unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync, + unsigned long addr, int *fd); + +int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data, + struct platform_device *pdev); +void msm_vfe_subdev_release(struct platform_device *pdev); + +int msm_isp_subdev_ioctl(struct v4l2_subdev *sd, + struct msm_vfe_cfg_cmd *cfgcmd, void *data); +int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data, + struct platform_device *pdev); +void msm_vpe_subdev_release(struct platform_device *pdev); +int msm_isp_subdev_ioctl_vpe(struct v4l2_subdev *isp_subdev, + struct msm_mctl_pp_cmd *cmd, void *data); +int msm_mctl_is_pp_msg_type(struct msm_cam_media_controller *p_mctl, + int msg_type); +int msm_mctl_do_pp(struct msm_cam_media_controller *p_mctl, + int msg_type, uint32_t y_phy, uint32_t frame_id); +int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl, + unsigned int cmd, unsigned long arg); +int msm_mctl_pp_notify(struct msm_cam_media_controller *pmctl, + struct msm_mctl_pp_frame_info *pp_frame_info); +int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam, + int out_type); +struct msm_frame_buffer *msm_mctl_buf_find( + struct msm_cam_media_controller *pmctl, + struct msm_cam_v4l2_dev_inst *pcam_inst, int del_buf, + int msg_type, struct msm_free_buf *fbuf); +void msm_mctl_gettimeofday(struct timeval *tv); +struct msm_frame_buffer *msm_mctl_get_free_buf( + struct msm_cam_media_controller *pmctl, + int msg_type); +int msm_mctl_put_free_buf( + struct msm_cam_media_controller *pmctl, + int msg_type, struct msm_frame_buffer *buf); +int msm_mctl_check_pp(struct msm_cam_media_controller *p_mctl, + int msg_type, int *pp_divert_type, int *pp_type); +int msm_mctl_do_pp_divert( + struct msm_cam_media_controller *p_mctl, + int msg_type, struct msm_free_buf *fbuf, + uint32_t frame_id, int pp_type); +int msm_mctl_buf_del(struct msm_cam_media_controller *pmctl, + int msg_type, + struct msm_frame_buffer *my_buf); +int msm_mctl_pp_release_free_frame( + struct msm_cam_media_controller *p_mctl, + void __user *arg); +int msm_mctl_pp_reserve_free_frame( + struct msm_cam_media_controller *p_mctl, + void __user *arg); +int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl, + void __user *arg); +int msm_mctl_pp_done( + struct msm_cam_media_controller *p_mctl, + void __user *arg); +int msm_mctl_pp_divert_done( + struct msm_cam_media_controller *p_mctl, + void __user *arg); + +extern void sensor_native_control(void __user *arg); + +void msm_release_ion_client(struct kref *ref); +#endif /* __KERNEL__ */ + +#endif /* _MSM_H */ diff --git a/drivers/media/video/msm_zsl/msm_axi_qos.c b/drivers/media/video/msm_zsl/msm_axi_qos.c new file mode 100644 index 00000000000..3969547cd17 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_axi_qos.c @@ -0,0 +1,47 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#define MSM_AXI_QOS_NAME "msm_camera" + +static struct clk *ebi1_clk; + +int add_axi_qos(void) +{ + ebi1_clk = clk_get(NULL, "ebi1_vfe_clk"); + if (IS_ERR(ebi1_clk)) + ebi1_clk = NULL; + else + clk_enable(ebi1_clk); + + return 0; +} + +int update_axi_qos(uint32_t rate) +{ + if (!ebi1_clk) + return 0; + + return clk_set_rate(ebi1_clk, rate * 1000); +} + +void release_axi_qos(void) +{ + if (!ebi1_clk) + return; + + clk_disable(ebi1_clk); + clk_put(ebi1_clk); + ebi1_clk = NULL; +} diff --git a/drivers/media/video/msm_zsl/msm_camera.c b/drivers/media/video/msm_zsl/msm_camera.c new file mode 100644 index 00000000000..65b33c25bf1 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_camera.c @@ -0,0 +1,4104 @@ +/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +//FIXME: most allocations need not be GFP_ATOMIC +/* FIXME: management of mutexes */ +/* FIXME: msm_pmem_region_lookup return values */ +/* FIXME: way too many copy to/from user */ +/* FIXME: does region->active mean free */ +/* FIXME: check limits on command lenghts passed from userspace */ +/* FIXME: __msm_release: which queues should we flush when opencnt != 0 */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +DEFINE_MUTEX(ctrl_cmd_lock); + +#define CAMERA_STOP_VIDEO 58 +spinlock_t pp_prev_spinlock; +spinlock_t pp_stereocam_spinlock; +spinlock_t st_frame_spinlock; + +#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \ + __func__, __LINE__, ((to) ? "to" : "from")) +#define ERR_COPY_FROM_USER() ERR_USER_COPY(0) +#define ERR_COPY_TO_USER() ERR_USER_COPY(1) +#define MAX_PMEM_CFG_BUFFERS 10 + +static struct class *msm_class; +static dev_t msm_devno; +static LIST_HEAD(msm_sensors); +struct msm_control_device *g_v4l2_control_device; +int g_v4l2_opencnt; +static int camera_node; +static enum msm_camera_type camera_type[MSM_MAX_CAMERA_SENSORS]; +static uint32_t sensor_mount_angle[MSM_MAX_CAMERA_SENSORS]; + +struct ion_client *client_for_ion; + +static const char *vfe_config_cmd[] = { + "CMD_GENERAL", /* 0 */ + "CMD_AXI_CFG_OUT1", + "CMD_AXI_CFG_SNAP_O1_AND_O2", + "CMD_AXI_CFG_OUT2", + "CMD_PICT_T_AXI_CFG", + "CMD_PICT_M_AXI_CFG", /* 5 */ + "CMD_RAW_PICT_AXI_CFG", + "CMD_FRAME_BUF_RELEASE", + "CMD_PREV_BUF_CFG", + "CMD_SNAP_BUF_RELEASE", + "CMD_SNAP_BUF_CFG", /* 10 */ + "CMD_STATS_DISABLE", + "CMD_STATS_AEC_AWB_ENABLE", + "CMD_STATS_AF_ENABLE", + "CMD_STATS_AEC_ENABLE", + "CMD_STATS_AWB_ENABLE", /* 15 */ + "CMD_STATS_ENABLE", + "CMD_STATS_AXI_CFG", + "CMD_STATS_AEC_AXI_CFG", + "CMD_STATS_AF_AXI_CFG", + "CMD_STATS_AWB_AXI_CFG", /* 20 */ + "CMD_STATS_RS_AXI_CFG", + "CMD_STATS_CS_AXI_CFG", + "CMD_STATS_IHIST_AXI_CFG", + "CMD_STATS_SKIN_AXI_CFG", + "CMD_STATS_BUF_RELEASE", /* 25 */ + "CMD_STATS_AEC_BUF_RELEASE", + "CMD_STATS_AF_BUF_RELEASE", + "CMD_STATS_AWB_BUF_RELEASE", + "CMD_STATS_RS_BUF_RELEASE", + "CMD_STATS_CS_BUF_RELEASE", /* 30 */ + "CMD_STATS_IHIST_BUF_RELEASE", + "CMD_STATS_SKIN_BUF_RELEASE", + "UPDATE_STATS_INVALID", + "CMD_AXI_CFG_SNAP_GEMINI", + "CMD_AXI_CFG_SNAP", /* 35 */ + "CMD_AXI_CFG_PREVIEW", + "CMD_AXI_CFG_VIDEO", + "CMD_STATS_IHIST_ENABLE", + "CMD_STATS_RS_ENABLE", + "CMD_STATS_CS_ENABLE", /* 40 */ + "CMD_VPE", + "CMD_AXI_CFG_VPE", + "CMD_AXI_CFG_SNAP_VPE", + "CMD_AXI_CFG_SNAP_THUMB_VPE", +}; +#define __CONTAINS(r, v, l, field) ({ \ + typeof(r) __r = r; \ + typeof(v) __v = v; \ + typeof(v) __e = __v + l; \ + int res = __v >= __r->field && \ + __e <= __r->field + __r->len; \ + res; \ +}) + +#define CONTAINS(r1, r2, field) ({ \ + typeof(r2) __r2 = r2; \ + __CONTAINS(r1, __r2->field, __r2->len, field); \ +}) + +#define IN_RANGE(r, v, field) ({ \ + typeof(r) __r = r; \ + typeof(v) __vv = v; \ + int res = ((__vv >= __r->field) && \ + (__vv < (__r->field + __r->len))); \ + res; \ +}) + +#define OVERLAPS(r1, r2, field) ({ \ + typeof(r1) __r1 = r1; \ + typeof(r2) __r2 = r2; \ + typeof(__r2->field) __v = __r2->field; \ + typeof(__v) __e = __v + __r2->len - 1; \ + int res = (IN_RANGE(__r1, __v, field) || \ + IN_RANGE(__r1, __e, field)); \ + res; \ +}) + +static inline void free_qcmd(struct msm_queue_cmd *qcmd) +{ + if (!qcmd || !atomic_read(&qcmd->on_heap)) + return; + if (!atomic_sub_return(1, &qcmd->on_heap)) + kfree(qcmd); +} + +static void msm_region_init(struct msm_sync *sync) +{ + INIT_HLIST_HEAD(&sync->pmem_frames); + INIT_HLIST_HEAD(&sync->pmem_stats); + spin_lock_init(&sync->pmem_frame_spinlock); + spin_lock_init(&sync->pmem_stats_spinlock); +} + +static void msm_queue_init(struct msm_device_queue *queue, const char *name) +{ + spin_lock_init(&queue->lock); + queue->len = 0; + queue->max = 0; + queue->name = name; + INIT_LIST_HEAD(&queue->list); + init_waitqueue_head(&queue->wait); +} + +static void msm_enqueue(struct msm_device_queue *queue, + struct list_head *entry) +{ + unsigned long flags; + spin_lock_irqsave(&queue->lock, flags); + queue->len++; + if (queue->len > queue->max) { + queue->max = queue->len; + CDBG("%s: queue %s new max is %d\n", __func__, + queue->name, queue->max); + } + list_add_tail(entry, &queue->list); + wake_up(&queue->wait); + CDBG("%s: woke up %s\n", __func__, queue->name); + spin_unlock_irqrestore(&queue->lock, flags); +} + +static void msm_enqueue_vpe(struct msm_device_queue *queue, + struct list_head *entry) +{ + unsigned long flags; + spin_lock_irqsave(&queue->lock, flags); + queue->len++; + if (queue->len > queue->max) { + queue->max = queue->len; + CDBG("%s: queue %s new max is %d\n", __func__, + queue->name, queue->max); + } + list_add_tail(entry, &queue->list); + CDBG("%s: woke up %s\n", __func__, queue->name); + spin_unlock_irqrestore(&queue->lock, flags); +} + +#define msm_dequeue(queue, member) ({ \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + __q->len--; \ + qcmd = list_first_entry(&__q->list, \ + struct msm_queue_cmd, member); \ + if ((qcmd) && (&qcmd->member) && (&qcmd->member.next)) \ + list_del_init(&qcmd->member); \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + qcmd; \ +}) + +#define msm_delete_entry(queue, member, q_cmd) ({ \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + list_for_each_entry(qcmd, &__q->list, member) \ + if (qcmd == q_cmd) { \ + __q->len--; \ + list_del_init(&qcmd->member); \ + CDBG("msm_delete_entry, match found\n");\ + kfree(q_cmd); \ + q_cmd = NULL; \ + break; \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + q_cmd; \ +}) + +#define msm_queue_drain(queue, member) do { \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd; \ + spin_lock_irqsave(&__q->lock, flags); \ + while (!list_empty(&__q->list)) { \ + __q->len--; \ + qcmd = list_first_entry(&__q->list, \ + struct msm_queue_cmd, member); \ + if (qcmd) { \ + if (&qcmd->member) \ + list_del_init(&qcmd->member); \ + free_qcmd(qcmd); \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ +} while (0) + +static int check_overlap(struct hlist_head *ptype, + unsigned long paddr, + unsigned long len) +{ + struct msm_pmem_region *region; + struct msm_pmem_region t = { .paddr = paddr, .len = len }; + struct hlist_node *node; + + hlist_for_each_entry(region, node, ptype, list) { + if (CONTAINS(region, &t, paddr) || + CONTAINS(&t, region, paddr) || + OVERLAPS(region, &t, paddr)) { + CDBG(" region (PHYS %p len %ld)" + " clashes with registered region" + " (paddr %p len %ld)\n", + (void *)t.paddr, t.len, + (void *)region->paddr, region->len); + return -1; + } + } + + return 0; +} + +static int check_pmem_info(struct msm_pmem_info *info, int len) +{ + if (info->offset < len && + info->offset + info->len <= len && + info->y_off < len && + info->cbcr_off < len) + return 0; + + pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n", + __func__, + info->offset, + info->len, + info->y_off, + info->cbcr_off, + len); + return -EINVAL; +} +static int msm_pmem_table_add(struct hlist_head *ptype, + struct msm_pmem_info *info, spinlock_t* pmem_spinlock, + struct msm_sync *sync) +{ + unsigned long paddr; +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + struct file *file; + unsigned long kvstart; +#endif + unsigned long len; + int rc = -ENOMEM; + struct msm_pmem_region *region; + unsigned long flags; + + region = kmalloc(sizeof(struct msm_pmem_region), GFP_KERNEL); + if (!region) + goto out; +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + region->handle = ion_import_fd(client_for_ion, info->fd); + if (IS_ERR_OR_NULL(region->handle)) + goto out1; + ion_phys(client_for_ion, region->handle, + &paddr, (size_t *)&len); +#else + rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file); + if (rc < 0) { + pr_err("%s: get_pmem_file fd %d error %d\n", + __func__, + info->fd, rc); + goto out1; + } + region->file = file; +#endif + if (!info->len) + info->len = len; + + rc = check_pmem_info(info, len); + if (rc < 0) + goto out2; + + paddr += info->offset; + len = info->len; + + spin_lock_irqsave(pmem_spinlock, flags); + if (check_overlap(ptype, paddr, len) < 0) { + spin_unlock_irqrestore(pmem_spinlock, flags); + rc = -EINVAL; + goto out2; + } + spin_unlock_irqrestore(pmem_spinlock, flags); + + spin_lock_irqsave(pmem_spinlock, flags); + INIT_HLIST_NODE(®ion->list); + + region->paddr = paddr; + region->len = len; + memcpy(®ion->info, info, sizeof(region->info)); + + hlist_add_head(&(region->list), ptype); + spin_unlock_irqrestore(pmem_spinlock, flags); + CDBG("%s: type %d, paddr 0x%lx, vaddr 0x%lx\n", + __func__, info->type, paddr, (unsigned long)info->vaddr); + return 0; +out2: +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_free(client_for_ion, region->handle); +#else + put_pmem_file(region->file); +#endif +out1: + kfree(region); +out: + return rc; +} + +/* return of 0 means failure */ +static uint8_t msm_pmem_region_lookup(struct hlist_head *ptype, + int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount, + spinlock_t *pmem_spinlock) +{ + struct msm_pmem_region *region; + struct msm_pmem_region *regptr; + struct hlist_node *node, *n; + unsigned long flags = 0; + + uint8_t rc = 0; + + regptr = reg; + spin_lock_irqsave(pmem_spinlock, flags); + hlist_for_each_entry_safe(region, node, n, ptype, list) { + if (region->info.type == pmem_type && region->info.active) { + *regptr = *region; + rc += 1; + if (rc >= maxcount) + break; + regptr++; + } + } + spin_unlock_irqrestore(pmem_spinlock, flags); + /* After lookup failure, dump all the list entries...*/ + if (rc == 0) { + pr_err("%s: pmem_type = %d\n", __func__, pmem_type); + hlist_for_each_entry_safe(region, node, n, ptype, list) { + pr_err("listed region->info.type = %d, active = %d", + region->info.type, region->info.active); + } + + } + return rc; +} + +static uint8_t msm_pmem_region_lookup_2(struct hlist_head *ptype, + int pmem_type, + struct msm_pmem_region *reg, + uint8_t maxcount, + spinlock_t *pmem_spinlock) +{ + struct msm_pmem_region *region; + struct msm_pmem_region *regptr; + struct hlist_node *node, *n; + uint8_t rc = 0; + unsigned long flags = 0; + regptr = reg; + spin_lock_irqsave(pmem_spinlock, flags); + hlist_for_each_entry_safe(region, node, n, ptype, list) { + CDBG("%s:info.type=%d, pmem_type = %d," + "info.active = %d\n", + __func__, region->info.type, pmem_type, region->info.active); + + if (region->info.type == pmem_type && region->info.active) { + CDBG("%s:info.type=%d, pmem_type = %d," + "info.active = %d,\n", + __func__, region->info.type, pmem_type, + region->info.active); + *regptr = *region; + region->info.type = MSM_PMEM_VIDEO; + rc += 1; + if (rc >= maxcount) + break; + regptr++; + } + } + spin_unlock_irqrestore(pmem_spinlock, flags); + return rc; +} + +static int msm_pmem_frame_ptov_lookup(struct msm_sync *sync, + unsigned long pyaddr, + unsigned long pcbcraddr, + struct msm_pmem_info *pmem_info, + int clear_active) +{ + struct msm_pmem_region *region; + struct hlist_node *node, *n; + unsigned long flags = 0; + + spin_lock_irqsave(&sync->pmem_frame_spinlock, flags); + hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) { + if (pyaddr == (region->paddr + region->info.y_off) && + pcbcraddr == (region->paddr + + region->info.cbcr_off) && + region->info.active) { + /* offset since we could pass vaddr inside + * a registerd pmem buffer + */ + memcpy(pmem_info, ®ion->info, sizeof(*pmem_info)); + if (clear_active) + region->info.active = 0; + spin_unlock_irqrestore(&sync->pmem_frame_spinlock, + flags); + return 0; + } + } + /* After lookup failure, dump all the list entries... */ + pr_err("%s, for pyaddr 0x%lx, pcbcraddr 0x%lx\n", + __func__, pyaddr, pcbcraddr); + hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) { + pr_err("listed pyaddr 0x%lx, pcbcraddr 0x%lx, active = %d", + (region->paddr + region->info.y_off), + (region->paddr + region->info.cbcr_off), + region->info.active); + } + + spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags); + return -EINVAL; +} + +static int msm_pmem_frame_ptov_lookup2(struct msm_sync *sync, + unsigned long pyaddr, + struct msm_pmem_info *pmem_info, + int clear_active) +{ + struct msm_pmem_region *region; + struct hlist_node *node, *n; + unsigned long flags = 0; + + spin_lock_irqsave(&sync->pmem_frame_spinlock, flags); + hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) { + if (pyaddr == (region->paddr + region->info.y_off) && + region->info.active) { + /* offset since we could pass vaddr inside + * a registerd pmem buffer + */ + memcpy(pmem_info, ®ion->info, sizeof(*pmem_info)); + if (clear_active) + region->info.active = 0; + spin_unlock_irqrestore(&sync->pmem_frame_spinlock, + flags); + return 0; + } + } + + spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags); + return -EINVAL; +} + +static unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync, + unsigned long addr, int *fd) +{ + struct msm_pmem_region *region; + struct hlist_node *node, *n; + unsigned long flags = 0; + + spin_lock_irqsave(&sync->pmem_stats_spinlock, flags); + hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) { + if (addr == region->paddr && region->info.active) { + /* offset since we could pass vaddr inside a + * registered pmem buffer */ + *fd = region->info.fd; + region->info.active = 0; + spin_unlock_irqrestore(&sync->pmem_stats_spinlock, + flags); + return (unsigned long)(region->info.vaddr); + } + } + /* After lookup failure, dump all the list entries... */ + pr_err("%s, lookup failure, for paddr 0x%lx\n", + __func__, addr); + hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) { + pr_err("listed paddr 0x%lx, active = %d", + region->paddr, + region->info.active); + } + spin_unlock_irqrestore(&sync->pmem_stats_spinlock, flags); + + return 0; +} + +static unsigned long msm_pmem_frame_vtop_lookup(struct msm_sync *sync, + unsigned long buffer, + uint32_t yoff, uint32_t cbcroff, int fd, int change_flag) +{ + struct msm_pmem_region *region; + struct hlist_node *node, *n; + unsigned long flags = 0; + + spin_lock_irqsave(&sync->pmem_frame_spinlock, flags); + hlist_for_each_entry_safe(region, + node, n, &sync->pmem_frames, list) { + if (((unsigned long)(region->info.vaddr) == buffer) && + (region->info.y_off == yoff) && + (region->info.cbcr_off == cbcroff) && + (region->info.fd == fd) && + (region->info.active == 0)) { + if (change_flag) + region->info.active = 1; + spin_unlock_irqrestore(&sync->pmem_frame_spinlock, + flags); + return region->paddr; + } + } + /* After lookup failure, dump all the list entries... */ + pr_err("%s, failed for vaddr 0x%lx, yoff %d cbcroff %d\n", + __func__, buffer, yoff, cbcroff); + hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) { + pr_err("listed vaddr 0x%p, cbcroff %d, active = %d", + (region->info.vaddr), + (region->info.cbcr_off), + region->info.active); + } + + spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags); + + return 0; +} + +static unsigned long msm_pmem_stats_vtop_lookup( + struct msm_sync *sync, + unsigned long buffer, + int fd) +{ + struct msm_pmem_region *region; + struct hlist_node *node, *n; + unsigned long flags = 0; + + spin_lock_irqsave(&sync->pmem_stats_spinlock, flags); + hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) { + if (((unsigned long)(region->info.vaddr) == buffer) && + (region->info.fd == fd) && + region->info.active == 0) { + region->info.active = 1; + spin_unlock_irqrestore(&sync->pmem_stats_spinlock, + flags); + return region->paddr; + } + } + /* After lookup failure, dump all the list entries... */ + pr_err("%s,look up error for vaddr %ld\n", + __func__, buffer); + hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) { + pr_err("listed vaddr 0x%p, active = %d", + region->info.vaddr, + region->info.active); + } + spin_unlock_irqrestore(&sync->pmem_stats_spinlock, flags); + + return 0; +} + +static int __msm_pmem_table_del(struct msm_sync *sync, + struct msm_pmem_info *pinfo) +{ + int rc = 0; + struct msm_pmem_region *region; + struct hlist_node *node, *n; + unsigned long flags = 0; + + switch (pinfo->type) { + case MSM_PMEM_PREVIEW: + case MSM_PMEM_THUMBNAIL: + case MSM_PMEM_MAINIMG: + case MSM_PMEM_RAW_MAINIMG: + case MSM_PMEM_C2D: + case MSM_PMEM_MAINIMG_VPE: + case MSM_PMEM_THUMBNAIL_VPE: + spin_lock_irqsave(&sync->pmem_frame_spinlock, flags); + hlist_for_each_entry_safe(region, node, n, + &sync->pmem_frames, list) { + + if (pinfo->type == region->info.type && + pinfo->vaddr == region->info.vaddr && + pinfo->fd == region->info.fd) { + hlist_del(node); +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_free(client_for_ion, region->handle); +#else + put_pmem_file(region->file); +#endif + kfree(region); + CDBG("%s: type %d, vaddr 0x%p\n", + __func__, pinfo->type, pinfo->vaddr); + } + } + spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags); + break; + + case MSM_PMEM_VIDEO: + case MSM_PMEM_VIDEO_VPE: + spin_lock_irqsave(&sync->pmem_frame_spinlock, flags); + hlist_for_each_entry_safe(region, node, n, + &sync->pmem_frames, list) { + + if (((region->info.type == MSM_PMEM_VIDEO) || + (region->info.type == MSM_PMEM_VIDEO_VPE)) && + pinfo->vaddr == region->info.vaddr && + pinfo->fd == region->info.fd) { + hlist_del(node); +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_free(client_for_ion, region->handle); +#else + put_pmem_file(region->file); +#endif + kfree(region); + CDBG("%s: type %d, vaddr 0x%p\n", + __func__, pinfo->type, pinfo->vaddr); + } + } + spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags); + break; + + case MSM_PMEM_AEC_AWB: + case MSM_PMEM_AF: + spin_lock_irqsave(&sync->pmem_stats_spinlock, flags); + hlist_for_each_entry_safe(region, node, n, + &sync->pmem_stats, list) { + + if (pinfo->type == region->info.type && + pinfo->vaddr == region->info.vaddr && + pinfo->fd == region->info.fd) { + hlist_del(node); +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_free(client_for_ion, region->handle); +#else + put_pmem_file(region->file); +#endif + kfree(region); + CDBG("%s: type %d, vaddr 0x%p\n", + __func__, pinfo->type, pinfo->vaddr); + } + } + spin_unlock_irqrestore(&sync->pmem_stats_spinlock, flags); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static int msm_pmem_table_del(struct msm_sync *sync, void __user *arg) +{ + struct msm_pmem_info info; + + if (copy_from_user(&info, arg, sizeof(info))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + return __msm_pmem_table_del(sync, &info); +} + +static int __msm_get_frame(struct msm_sync *sync, + struct msm_frame *frame) +{ + int rc = 0; + + struct msm_pmem_info pmem_info; + struct msm_queue_cmd *qcmd = NULL; + struct msm_vfe_resp *vdata; + struct msm_vfe_phy_info *pphy; + + qcmd = msm_dequeue(&sync->frame_q, list_frame); + + if (!qcmd) { + pr_err("%s: no preview frame.\n", __func__); + return -EAGAIN; + } + + if ((!qcmd->command) && (qcmd->error_code & MSM_CAMERA_ERR_MASK)) { + frame->error_code = qcmd->error_code; + pr_err("%s: fake frame with camera error code = %d\n", + __func__, frame->error_code); + goto err; + } + + vdata = (struct msm_vfe_resp *)(qcmd->command); + pphy = &vdata->phy; + + rc = msm_pmem_frame_ptov_lookup(sync, + pphy->y_phy, + pphy->cbcr_phy, + &pmem_info, + 1); /* Clear the active flag */ + + if (rc < 0) { + pr_err("%s: cannot get frame, invalid lookup address " + "y %x cbcr %x\n", + __func__, + pphy->y_phy, + pphy->cbcr_phy); + goto err; + } + + frame->ts = qcmd->ts; + frame->buffer = (unsigned long)pmem_info.vaddr; + frame->y_off = pmem_info.y_off; + frame->cbcr_off = pmem_info.cbcr_off; + frame->fd = pmem_info.fd; + frame->path = vdata->phy.output_id; + frame->frame_id = vdata->phy.frame_id; + + CDBG("%s: y %x, cbcr %x, qcmd %x, virt_addr %x\n", + __func__, + pphy->y_phy, pphy->cbcr_phy, (int) qcmd, (int) frame->buffer); + +err: + free_qcmd(qcmd); + return rc; +} + +static int msm_get_frame(struct msm_sync *sync, void __user *arg) +{ + int rc = 0; + struct msm_frame frame; + + if (copy_from_user(&frame, + arg, + sizeof(struct msm_frame))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + rc = __msm_get_frame(sync, &frame); + if (rc < 0) + return rc; + + mutex_lock(&sync->lock); + if (sync->croplen && (!sync->stereocam_enabled)) { + if (frame.croplen != sync->croplen) { + pr_err("%s: invalid frame croplen %d," + "expecting %d\n", + __func__, + frame.croplen, + sync->croplen); + mutex_unlock(&sync->lock); + return -EINVAL; + } + + if (copy_to_user((void *)frame.cropinfo, + sync->cropinfo, + sync->croplen)) { + ERR_COPY_TO_USER(); + mutex_unlock(&sync->lock); + return -EFAULT; + } + } + + if (sync->fdroiinfo.info) { + if (copy_to_user((void *)frame.roi_info.info, + sync->fdroiinfo.info, + sync->fdroiinfo.info_len)) { + ERR_COPY_TO_USER(); + mutex_unlock(&sync->lock); + return -EFAULT; + } + } + + if (sync->stereocam_enabled) { + frame.stcam_conv_value = sync->stcam_conv_value; + frame.stcam_quality_ind = sync->stcam_quality_ind; + } + + if (copy_to_user((void *)arg, + &frame, sizeof(struct msm_frame))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + } + + mutex_unlock(&sync->lock); + CDBG("%s: got frame\n", __func__); + + return rc; +} + +static int msm_enable_vfe(struct msm_sync *sync, void __user *arg) +{ + int rc = -EIO; + struct camera_enable_cmd cfg; + + if (copy_from_user(&cfg, + arg, + sizeof(struct camera_enable_cmd))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + if (sync->vfefn.vfe_enable) + rc = sync->vfefn.vfe_enable(&cfg); + + return rc; +} + +static int msm_disable_vfe(struct msm_sync *sync, void __user *arg) +{ + int rc = -EIO; + struct camera_enable_cmd cfg; + + if (copy_from_user(&cfg, + arg, + sizeof(struct camera_enable_cmd))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + if (sync->vfefn.vfe_disable) + rc = sync->vfefn.vfe_disable(&cfg, NULL); + + return rc; +} + +static struct msm_queue_cmd *__msm_control(struct msm_sync *sync, + struct msm_device_queue *queue, + struct msm_queue_cmd *qcmd, + int timeout) +{ + int rc; + + CDBG("Inside __msm_control\n"); + if (sync->event_q.len <= 100 && sync->frame_q.len <= 100) { + /* wake up config thread */ + msm_enqueue(&sync->event_q, &qcmd->list_config); + } else { + pr_err("%s, Error Queue limit exceeded e_q = %d, f_q = %d\n", + __func__, sync->event_q.len, sync->frame_q.len); + free_qcmd(qcmd); + return NULL; + } + if (!queue) + return NULL; + + /* wait for config status */ + CDBG("Waiting for config status \n"); + rc = wait_event_interruptible_timeout( + queue->wait, + !list_empty_careful(&queue->list), + timeout); + CDBG("Waiting over for config status\n"); + if (list_empty_careful(&queue->list)) { + if (!rc) { + rc = -ETIMEDOUT; + pr_err("%s: wait_event error %d\n", __func__, rc); + return ERR_PTR(rc); + } else if (rc < 0) { + pr_err("%s: wait_event error %d\n", __func__, rc); + if (msm_delete_entry(&sync->event_q, + list_config, qcmd)) { + sync->ignore_qcmd = true; + sync->ignore_qcmd_type = + (int16_t)((struct msm_ctrl_cmd *) + (qcmd->command))->type; + } + return ERR_PTR(rc); + } + } + qcmd = msm_dequeue(queue, list_control); + BUG_ON(!qcmd); + CDBG("__msm_control done \n"); + return qcmd; +} + +static struct msm_queue_cmd *__msm_control_nb(struct msm_sync *sync, + struct msm_queue_cmd *qcmd_to_copy) +{ + /* Since this is a non-blocking command, we cannot use qcmd_to_copy and + * its data, since they are on the stack. We replicate them on the heap + * and mark them on_heap so that they get freed when the config thread + * dequeues them. + */ + + struct msm_ctrl_cmd *udata; + struct msm_ctrl_cmd *udata_to_copy = qcmd_to_copy->command; + + struct msm_queue_cmd *qcmd = + kmalloc(sizeof(*qcmd_to_copy) + + sizeof(*udata_to_copy) + + udata_to_copy->length, + GFP_KERNEL); + if (!qcmd) { + pr_err("%s: out of memory\n", __func__); + return ERR_PTR(-ENOMEM); + } + *qcmd = *qcmd_to_copy; + udata = qcmd->command = qcmd + 1; + memcpy(udata, udata_to_copy, sizeof(*udata)); + udata->value = udata + 1; + memcpy(udata->value, udata_to_copy->value, udata_to_copy->length); + + atomic_set(&qcmd->on_heap, 1); + + /* qcmd_resp will be set to NULL */ + return __msm_control(sync, NULL, qcmd, 0); +} + +static int msm_control(struct msm_control_device *ctrl_pmsm, + int block, + void __user *arg) +{ + int rc = 0; + + struct msm_sync *sync = ctrl_pmsm->pmsm->sync; + void __user *uptr; + struct msm_ctrl_cmd udata_resp; + struct msm_queue_cmd *qcmd_resp = NULL; + uint8_t data[max_control_command_size]; + struct msm_ctrl_cmd *udata; + struct msm_queue_cmd *qcmd = + kmalloc(sizeof(struct msm_queue_cmd) + + sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); + if (!qcmd) { + pr_err("%s: out of memory\n", __func__); + return -ENOMEM; + } + udata = (struct msm_ctrl_cmd *)(qcmd + 1); + atomic_set(&(qcmd->on_heap), 1); + CDBG("Inside msm_control\n"); + if (copy_from_user(udata, arg, sizeof(struct msm_ctrl_cmd))) { + ERR_COPY_FROM_USER(); + rc = -EFAULT; + goto end; + } + + uptr = udata->value; + udata->value = data; + qcmd->type = MSM_CAM_Q_CTRL; + qcmd->command = udata; + + if (udata->length) { + if (udata->length > sizeof(data)) { + pr_err("%s: user data too large (%d, max is %d)\n", + __func__, + udata->length, + sizeof(data)); + rc = -EIO; + goto end; + } + if (copy_from_user(udata->value, uptr, udata->length)) { + ERR_COPY_FROM_USER(); + rc = -EFAULT; + goto end; + } + } + + if (unlikely(!block)) { + qcmd_resp = __msm_control_nb(sync, qcmd); + goto end; + } + msm_queue_drain(&ctrl_pmsm->ctrl_q, list_control); + qcmd_resp = __msm_control(sync, + &ctrl_pmsm->ctrl_q, + qcmd, msecs_to_jiffies(10000)); + + /* ownership of qcmd will be transfered to event queue */ + qcmd = NULL; + + if (!qcmd_resp || IS_ERR(qcmd_resp)) { + /* Do not free qcmd_resp here. If the config thread read it, + * then it has already been freed, and we timed out because + * we did not receive a MSM_CAM_IOCTL_CTRL_CMD_DONE. If the + * config thread itself is blocked and not dequeueing commands, + * then it will either eventually unblock and process them, + * or when it is killed, qcmd will be freed in + * msm_release_config. + */ + rc = PTR_ERR(qcmd_resp); + qcmd_resp = NULL; + goto end; + } + + if (qcmd_resp->command) { + udata_resp = *(struct msm_ctrl_cmd *)qcmd_resp->command; + if (udata_resp.length > 0) { + if (copy_to_user(uptr, + udata_resp.value, + udata_resp.length)) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + goto end; + } + } + udata_resp.value = uptr; + + if (copy_to_user((void *)arg, &udata_resp, + sizeof(struct msm_ctrl_cmd))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + goto end; + } + } + +end: + free_qcmd(qcmd); + CDBG("%s: done rc = %d\n", __func__, rc); + return rc; +} + +/* Divert frames for post-processing by delivering them to the config thread; + * when post-processing is done, it will return the frame to the frame thread. + */ +static int msm_divert_frame(struct msm_sync *sync, + struct msm_vfe_resp *data, + struct msm_stats_event_ctrl *se) +{ + struct msm_pmem_info pinfo; + struct msm_postproc buf; + int rc; + + CDBG("%s: Frame PP sync->pp_mask %d\n", __func__, sync->pp_mask); + + if (!(sync->pp_mask & PP_PREV) && !(sync->pp_mask & PP_SNAP)) { + pr_err("%s: diverting frame, not in PP_PREV or PP_SNAP!\n", + __func__); + return -EINVAL; + } + + rc = msm_pmem_frame_ptov_lookup(sync, data->phy.y_phy, + data->phy.cbcr_phy, &pinfo, + 0); /* do not clear the active flag */ + + if (rc < 0) { + pr_err("%s: msm_pmem_frame_ptov_lookup failed\n", __func__); + return rc; + } + + buf.fmain.buffer = (unsigned long)pinfo.vaddr; + buf.fmain.y_off = pinfo.y_off; + buf.fmain.cbcr_off = pinfo.cbcr_off; + buf.fmain.fd = pinfo.fd; + + CDBG("%s: buf 0x%x fd %d\n", __func__, (unsigned int)buf.fmain.buffer, + buf.fmain.fd); + if (copy_to_user((void *)(se->stats_event.data), + &(buf.fmain), sizeof(struct msm_frame))) { + ERR_COPY_TO_USER(); + return -EFAULT; + } + return 0; +} + +/* Divert stereo frames for post-processing by delivering + * them to the config thread. + */ +static int msm_divert_st_frame(struct msm_sync *sync, + struct msm_vfe_resp *data, struct msm_stats_event_ctrl *se, int path) +{ + struct msm_pmem_info pinfo; + struct msm_st_frame buf; + struct video_crop_t *crop = NULL; + int rc = 0; + + if (se->stats_event.msg_id == OUTPUT_TYPE_ST_L) { + buf.type = OUTPUT_TYPE_ST_L; + } else if (se->stats_event.msg_id == OUTPUT_TYPE_ST_R) { + buf.type = OUTPUT_TYPE_ST_R; + } else { + if (se->resptype == MSM_CAM_RESP_STEREO_OP_1) { + rc = msm_pmem_frame_ptov_lookup(sync, data->phy.y_phy, + data->phy.cbcr_phy, &pinfo, + 1); /* do clear the active flag */ + buf.buf_info.path = path; + } else if (se->resptype == MSM_CAM_RESP_STEREO_OP_2) { + rc = msm_pmem_frame_ptov_lookup(sync, data->phy.y_phy, + data->phy.cbcr_phy, &pinfo, + 0); /* do not clear the active flag */ + buf.buf_info.path = path; + } else + CDBG("%s: Invalid resptype = %d\n", __func__, + se->resptype); + + if (rc < 0) { + CDBG("%s: msm_pmem_frame_ptov_lookup failed\n", + __func__); + return rc; + } + + buf.type = OUTPUT_TYPE_ST_D; + + if (sync->cropinfo != NULL) { + crop = sync->cropinfo; + switch (path) { + case OUTPUT_TYPE_P: + case OUTPUT_TYPE_T: { + buf.L.stCropInfo.in_w = crop->in1_w; + buf.L.stCropInfo.in_h = crop->in1_h; + buf.L.stCropInfo.out_w = crop->out1_w; + buf.L.stCropInfo.out_h = crop->out1_h; + buf.R.stCropInfo = buf.L.stCropInfo; + break; + } + + case OUTPUT_TYPE_V: + case OUTPUT_TYPE_S: { + buf.L.stCropInfo.in_w = crop->in2_w; + buf.L.stCropInfo.in_h = crop->in2_h; + buf.L.stCropInfo.out_w = crop->out2_w; + buf.L.stCropInfo.out_h = crop->out2_h; + buf.R.stCropInfo = buf.L.stCropInfo; + break; + } + default: { + pr_warning("%s: invalid frame path %d\n", + __func__, path); + break; + } + } + } else { + buf.L.stCropInfo.in_w = 0; + buf.L.stCropInfo.in_h = 0; + buf.L.stCropInfo.out_w = 0; + buf.L.stCropInfo.out_h = 0; + buf.R.stCropInfo = buf.L.stCropInfo; + } + + /* hardcode for now. */ + if ((path == OUTPUT_TYPE_S) || (path == OUTPUT_TYPE_T)) + buf.packing = sync->sctrl.s_snap_packing; + else + buf.packing = sync->sctrl.s_video_packing; + + buf.buf_info.buffer = (unsigned long)pinfo.vaddr; + buf.buf_info.phy_offset = pinfo.offset; + buf.buf_info.y_off = pinfo.y_off; + buf.buf_info.cbcr_off = pinfo.cbcr_off; + buf.buf_info.fd = pinfo.fd; + + CDBG("%s: buf 0x%x fd %d\n", __func__, + (unsigned int)buf.buf_info.buffer, buf.buf_info.fd); + } + + if (copy_to_user((void *)(se->stats_event.data), + &buf, sizeof(struct msm_st_frame))) { + ERR_COPY_TO_USER(); + return -EFAULT; + } + return 0; +} + +static int msm_get_stats(struct msm_sync *sync, void __user *arg) +{ + int rc = 0; + + struct msm_stats_event_ctrl se; + + struct msm_queue_cmd *qcmd = NULL; + struct msm_ctrl_cmd *ctrl = NULL; + struct msm_vfe_resp *data = NULL; + struct msm_vpe_resp *vpe_data = NULL; + struct msm_stats_buf stats; + + if (copy_from_user(&se, arg, + sizeof(struct msm_stats_event_ctrl))) { + ERR_COPY_FROM_USER(); + pr_err("%s, ERR_COPY_FROM_USER\n", __func__); + return -EFAULT; + } + + rc = 0; + + qcmd = msm_dequeue(&sync->event_q, list_config); + if (!qcmd) { + /* Should be associated with wait_event + error -512 from __msm_control*/ + pr_err("%s, qcmd is Null\n", __func__); + rc = -ETIMEDOUT; + return rc; + } + + CDBG("%s: received from DSP %d\n", __func__, qcmd->type); + + switch (qcmd->type) { + case MSM_CAM_Q_VPE_MSG: + /* Complete VPE response. */ + vpe_data = (struct msm_vpe_resp *)(qcmd->command); + se.resptype = MSM_CAM_RESP_STEREO_OP_2; + se.stats_event.type = vpe_data->evt_msg.type; + se.stats_event.msg_id = vpe_data->evt_msg.msg_id; + se.stats_event.len = vpe_data->evt_msg.len; + + if (vpe_data->type == VPE_MSG_OUTPUT_ST_L) { + CDBG("%s: Change msg_id to OUTPUT_TYPE_ST_L\n", + __func__); + se.stats_event.msg_id = OUTPUT_TYPE_ST_L; + rc = msm_divert_st_frame(sync, data, &se, + OUTPUT_TYPE_V); + } else if (vpe_data->type == VPE_MSG_OUTPUT_ST_R) { + CDBG("%s: Change msg_id to OUTPUT_TYPE_ST_R\n", + __func__); + se.stats_event.msg_id = OUTPUT_TYPE_ST_R; + rc = msm_divert_st_frame(sync, data, &se, + OUTPUT_TYPE_V); + } else { + pr_warning("%s: invalid vpe_data->type = %d\n", + __func__, vpe_data->type); + } + break; + + case MSM_CAM_Q_VFE_EVT: + case MSM_CAM_Q_VFE_MSG: + data = (struct msm_vfe_resp *)(qcmd->command); + + /* adsp event and message */ + se.resptype = MSM_CAM_RESP_STAT_EVT_MSG; + + /* 0 - msg from aDSP, 1 - event from mARM */ + se.stats_event.type = data->evt_msg.type; + se.stats_event.msg_id = data->evt_msg.msg_id; + se.stats_event.len = data->evt_msg.len; + se.stats_event.frame_id = data->evt_msg.frame_id; + + CDBG("%s: qcmd->type %d length %d msd_id %d\n", __func__, + qcmd->type, + se.stats_event.len, + se.stats_event.msg_id); + + if (data->type == VFE_MSG_COMMON) { + stats.status_bits = data->stats_msg.status_bits; + stats.awb_ymin = data->stats_msg.awb_ymin; + + if (data->stats_msg.aec_buff) { + stats.aec.buff = + msm_pmem_stats_ptov_lookup(sync, + data->stats_msg.aec_buff, + &(stats.aec.fd)); + if (!stats.aec.buff) { + pr_err("%s: msm_pmem_stats_ptov_lookup error\n", + __func__); + rc = -EINVAL; + goto failure; + } + + } else { + stats.aec.buff = 0; + } + if (data->stats_msg.awb_buff) { + stats.awb.buff = + msm_pmem_stats_ptov_lookup(sync, + data->stats_msg.awb_buff, + &(stats.awb.fd)); + if (!stats.awb.buff) { + pr_err("%s: msm_pmem_stats_ptov_lookup error\n", + __func__); + rc = -EINVAL; + goto failure; + } + + } else { + stats.awb.buff = 0; + } + if (data->stats_msg.af_buff) { + stats.af.buff = + msm_pmem_stats_ptov_lookup(sync, + data->stats_msg.af_buff, + &(stats.af.fd)); + if (!stats.af.buff) { + pr_err("%s: msm_pmem_stats_ptov_lookup error\n", + __func__); + rc = -EINVAL; + goto failure; + } + + } else { + stats.af.buff = 0; + } + if (data->stats_msg.ihist_buff) { + stats.ihist.buff = + msm_pmem_stats_ptov_lookup(sync, + data->stats_msg.ihist_buff, + &(stats.ihist.fd)); + if (!stats.ihist.buff) { + pr_err("%s: msm_pmem_stats_ptov_lookup error\n", + __func__); + rc = -EINVAL; + goto failure; + } + + } else { + stats.ihist.buff = 0; + } + + if (data->stats_msg.rs_buff) { + stats.rs.buff = + msm_pmem_stats_ptov_lookup(sync, + data->stats_msg.rs_buff, + &(stats.rs.fd)); + if (!stats.rs.buff) { + pr_err("%s: msm_pmem_stats_ptov_lookup error\n", + __func__); + rc = -EINVAL; + goto failure; + } + + } else { + stats.rs.buff = 0; + } + + if (data->stats_msg.cs_buff) { + stats.cs.buff = + msm_pmem_stats_ptov_lookup(sync, + data->stats_msg.cs_buff, + &(stats.cs.fd)); + if (!stats.cs.buff) { + pr_err("%s: msm_pmem_stats_ptov_lookup error\n", + __func__); + rc = -EINVAL; + goto failure; + } + } else { + stats.cs.buff = 0; + } + + se.stats_event.frame_id = data->phy.frame_id; + if (copy_to_user((void *)(se.stats_event.data), + &stats, + sizeof(struct msm_stats_buf))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + goto failure; + } + } else if ((data->type >= VFE_MSG_STATS_AEC) && + (data->type <= VFE_MSG_STATS_WE)) { + /* the check above includes all stats type. */ + stats.awb_ymin = data->stats_msg.awb_ymin; + stats.buffer = + msm_pmem_stats_ptov_lookup(sync, + data->phy.sbuf_phy, + &(stats.fd)); + if (!stats.buffer) { + pr_err("%s: msm_pmem_stats_ptov_lookup error\n", + __func__); + rc = -EINVAL; + goto failure; + } + se.stats_event.frame_id = data->phy.frame_id; + if (copy_to_user((void *)(se.stats_event.data), + &stats, + sizeof(struct msm_stats_buf))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + goto failure; + } + } else if ((data->evt_msg.len > 0) && + (data->type == VFE_MSG_GENERAL)) { + if (copy_to_user((void *)(se.stats_event.data), + data->evt_msg.data, + data->evt_msg.len)) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + goto failure; + } + } else { + if (sync->stereocam_enabled) { + if (data->type == VFE_MSG_OUTPUT_P) { + CDBG("%s: Preview mark as st op 1\n", + __func__); + se.resptype = MSM_CAM_RESP_STEREO_OP_1; + rc = msm_divert_st_frame(sync, data, + &se, OUTPUT_TYPE_P); + break; + } else if (data->type == VFE_MSG_OUTPUT_V) { + CDBG("%s: Video mark as st op 2\n", + __func__); + se.resptype = MSM_CAM_RESP_STEREO_OP_2; + rc = msm_divert_st_frame(sync, data, + &se, OUTPUT_TYPE_V); + break; + } else if (data->type == VFE_MSG_OUTPUT_S) { + CDBG("%s: Main img mark as st op 2\n", + __func__); + se.resptype = MSM_CAM_RESP_STEREO_OP_2; + rc = msm_divert_st_frame(sync, data, + &se, OUTPUT_TYPE_S); + break; + } else if (data->type == VFE_MSG_OUTPUT_T) { + CDBG("%s: Thumb img mark as st op 2\n", + __func__); + se.resptype = MSM_CAM_RESP_STEREO_OP_2; + rc = msm_divert_st_frame(sync, data, + &se, OUTPUT_TYPE_T); + break; + } else + CDBG("%s: VFE_MSG Fall Through\n", + __func__); + } + if ((sync->pp_frame_avail == 1) && + (sync->pp_mask & PP_PREV) && + (data->type == VFE_MSG_OUTPUT_P)) { + CDBG("%s:%d:preiew PP\n", + __func__, __LINE__); + se.stats_event.frame_id = + data->phy.frame_id; + rc = msm_divert_frame(sync, data, &se); + sync->pp_frame_avail = 0; + } else { + if ((sync->pp_mask & PP_PREV) && + (data->type == VFE_MSG_OUTPUT_P)) { + se.stats_event.frame_id = + data->phy.frame_id; + free_qcmd(qcmd); + return 0; + } else + CDBG("%s:indication type is %d\n", + __func__, data->type); + } + if (sync->pp_mask & PP_SNAP) + if (data->type == VFE_MSG_OUTPUT_S || + data->type == VFE_MSG_OUTPUT_T) + rc = msm_divert_frame(sync, data, &se); + } + break; + + case MSM_CAM_Q_CTRL: + /* control command from control thread */ + ctrl = (struct msm_ctrl_cmd *)(qcmd->command); + + CDBG("%s: qcmd->type %d length %d\n", __func__, + qcmd->type, ctrl->length); + + if (ctrl->length > 0) { + if (copy_to_user((void *)(se.ctrl_cmd.value), + ctrl->value, + ctrl->length)) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + goto failure; + } + } + + se.resptype = MSM_CAM_RESP_CTRL; + + /* what to control */ + se.ctrl_cmd.type = ctrl->type; + se.ctrl_cmd.length = ctrl->length; + se.ctrl_cmd.resp_fd = ctrl->resp_fd; + break; + + case MSM_CAM_Q_V4L2_REQ: + /* control command from v4l2 client */ + ctrl = (struct msm_ctrl_cmd *)(qcmd->command); + if (ctrl->length > 0) { + if (copy_to_user((void *)(se.ctrl_cmd.value), + ctrl->value, ctrl->length)) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + goto failure; + } + } + + /* 2 tells config thread this is v4l2 request */ + se.resptype = MSM_CAM_RESP_V4L2; + + /* what to control */ + se.ctrl_cmd.type = ctrl->type; + se.ctrl_cmd.length = ctrl->length; + break; + + default: + rc = -EFAULT; + goto failure; + } /* switch qcmd->type */ + if (copy_to_user((void *)arg, &se, sizeof(se))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + goto failure; + } + +failure: + free_qcmd(qcmd); + + CDBG("%s: %d\n", __func__, rc); + return rc; +} + +static int msm_ctrl_cmd_done(struct msm_control_device *ctrl_pmsm, + void __user *arg) +{ + void __user *uptr; + struct msm_queue_cmd *qcmd = &ctrl_pmsm->qcmd; + struct msm_ctrl_cmd *command = &ctrl_pmsm->ctrl; + + if (copy_from_user(command, arg, sizeof(*command))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + atomic_set(&qcmd->on_heap, 0); + qcmd->command = command; + uptr = command->value; + + if (command->length > 0) { + command->value = ctrl_pmsm->ctrl_data; + if (command->length > sizeof(ctrl_pmsm->ctrl_data)) { + pr_err("%s: user data %d is too big (max %d)\n", + __func__, command->length, + sizeof(ctrl_pmsm->ctrl_data)); + return -EINVAL; + } + + if (copy_from_user(command->value, + uptr, + command->length)) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + } else + command->value = NULL; + + /* Ignore the command if the ctrl cmd has + return back due to signaling */ + /* Should be associated with wait_event + error -512 from __msm_control*/ + if (ctrl_pmsm->pmsm->sync->ignore_qcmd == true && + ctrl_pmsm->pmsm->sync->ignore_qcmd_type == (int16_t)command->type) { + ctrl_pmsm->pmsm->sync->ignore_qcmd = false; + ctrl_pmsm->pmsm->sync->ignore_qcmd_type = -1; + } else /* wake up control thread */ + msm_enqueue(&ctrl_pmsm->ctrl_q, &qcmd->list_control); + + return 0; +} + +static int msm_config_vpe(struct msm_sync *sync, void __user *arg) +{ + struct msm_vpe_cfg_cmd cfgcmd; + if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + CDBG("%s: cmd_type %s\n", __func__, vfe_config_cmd[cfgcmd.cmd_type]); + switch (cfgcmd.cmd_type) { + case CMD_VPE: + return sync->vpefn.vpe_config(&cfgcmd, NULL); + default: + pr_err("%s: unknown command type %d\n", + __func__, cfgcmd.cmd_type); + } + return -EINVAL; +} + +static int msm_config_vfe(struct msm_sync *sync, void __user *arg) +{ + struct msm_vfe_cfg_cmd cfgcmd; + struct msm_pmem_region region[8]; + struct axidata axi_data; + + if (!sync->vfefn.vfe_config) { + pr_err("%s: no vfe_config!\n", __func__); + return -EIO; + } + + if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + memset(&axi_data, 0, sizeof(axi_data)); + CDBG("%s: cmd_type %s\n", __func__, vfe_config_cmd[cfgcmd.cmd_type]); + switch (cfgcmd.cmd_type) { + case CMD_STATS_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_AEC_AWB, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + axi_data.bufnum2 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_AF, ®ion[axi_data.bufnum1], + NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + if (!axi_data.bufnum1 || !axi_data.bufnum2) { + pr_err("%s: pmem region lookup error\n", __func__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return sync->vfefn.vfe_config(&cfgcmd, &axi_data); + case CMD_STATS_AF_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_AF, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return sync->vfefn.vfe_config(&cfgcmd, &axi_data); + case CMD_STATS_AEC_AWB_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_AEC_AWB, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return sync->vfefn.vfe_config(&cfgcmd, &axi_data); + case CMD_STATS_AEC_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_AEC, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return sync->vfefn.vfe_config(&cfgcmd, &axi_data); + case CMD_STATS_AWB_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_AWB, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return sync->vfefn.vfe_config(&cfgcmd, &axi_data); + + + case CMD_STATS_IHIST_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_IHIST, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return sync->vfefn.vfe_config(&cfgcmd, &axi_data); + + case CMD_STATS_RS_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_RS, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return sync->vfefn.vfe_config(&cfgcmd, &axi_data); + + case CMD_STATS_CS_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_CS, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return sync->vfefn.vfe_config(&cfgcmd, &axi_data); + + case CMD_GENERAL: + case CMD_STATS_DISABLE: + return sync->vfefn.vfe_config(&cfgcmd, NULL); + default: + pr_err("%s: unknown command type %d\n", + __func__, cfgcmd.cmd_type); + } + + return -EINVAL; +} +static int msm_vpe_frame_cfg(struct msm_sync *sync, + void *cfgcmdin) +{ + int rc = -EIO; + struct axidata axi_data; + void *data = &axi_data; + struct msm_pmem_region region[8]; + int pmem_type; + + struct msm_vpe_cfg_cmd *cfgcmd; + cfgcmd = (struct msm_vpe_cfg_cmd *)cfgcmdin; + + memset(&axi_data, 0, sizeof(axi_data)); + CDBG("In vpe_frame_cfg cfgcmd->cmd_type = %s\n", + vfe_config_cmd[cfgcmd->cmd_type]); + switch (cfgcmd->cmd_type) { + case CMD_AXI_CFG_VPE: + pmem_type = MSM_PMEM_VIDEO_VPE; + axi_data.bufnum1 = + msm_pmem_region_lookup_2(&sync->pmem_frames, pmem_type, + ®ion[0], 8, &sync->pmem_frame_spinlock); + CDBG("axi_data.bufnum1 = %d\n", axi_data.bufnum1); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + pmem_type = MSM_PMEM_VIDEO; + break; + case CMD_AXI_CFG_SNAP_THUMB_VPE: + CDBG("%s: CMD_AXI_CFG_SNAP_THUMB_VPE", __func__); + pmem_type = MSM_PMEM_THUMBNAIL_VPE; + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[0], 8, &sync->pmem_frame_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s: THUMBNAIL_VPE pmem region lookup error\n", + __func__); + return -EINVAL; + } + break; + case CMD_AXI_CFG_SNAP_VPE: + CDBG("%s: CMD_AXI_CFG_SNAP_VPE", __func__); + pmem_type = MSM_PMEM_MAINIMG_VPE; + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[0], 8, &sync->pmem_frame_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s: MAINIMG_VPE pmem region lookup error\n", + __func__); + return -EINVAL; + } + break; + default: + pr_err("%s: unknown command type %d\n", + __func__, cfgcmd->cmd_type); + break; + } + axi_data.region = ®ion[0]; + CDBG("out vpe_frame_cfg cfgcmd->cmd_type = %s\n", + vfe_config_cmd[cfgcmd->cmd_type]); + /* send the AXI configuration command to driver */ + if (sync->vpefn.vpe_config) + rc = sync->vpefn.vpe_config(cfgcmd, data); + return rc; +} + +static int msm_frame_axi_cfg(struct msm_sync *sync, + struct msm_vfe_cfg_cmd *cfgcmd) +{ + int rc = -EIO; + struct axidata axi_data; + void *data = &axi_data; + struct msm_pmem_region region[MAX_PMEM_CFG_BUFFERS]; + int pmem_type; + + memset(&axi_data, 0, sizeof(axi_data)); + + switch (cfgcmd->cmd_type) { + + case CMD_AXI_CFG_PREVIEW: + pmem_type = MSM_PMEM_PREVIEW; + axi_data.bufnum2 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[0], MAX_PMEM_CFG_BUFFERS, + &sync->pmem_frame_spinlock); + if (!axi_data.bufnum2) { + pr_err("%s %d: pmem region lookup error (empty %d)\n", + __func__, __LINE__, + hlist_empty(&sync->pmem_frames)); + return -EINVAL; + } + break; + + case CMD_AXI_CFG_VIDEO: + pmem_type = MSM_PMEM_PREVIEW; + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[0], MAX_PMEM_CFG_BUFFERS, + &sync->pmem_frame_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + + pmem_type = MSM_PMEM_VIDEO; + axi_data.bufnum2 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[axi_data.bufnum1], + (MAX_PMEM_CFG_BUFFERS-(axi_data.bufnum1)), + &sync->pmem_frame_spinlock); + if (!axi_data.bufnum2) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + break; + + case CMD_AXI_CFG_SNAP: + CDBG("%s, CMD_AXI_CFG_SNAP, type=%d\n", __func__, + cfgcmd->cmd_type); + pmem_type = MSM_PMEM_THUMBNAIL; + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[0], MAX_PMEM_CFG_BUFFERS, + &sync->pmem_frame_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + + pmem_type = MSM_PMEM_MAINIMG; + axi_data.bufnum2 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[axi_data.bufnum1], + (MAX_PMEM_CFG_BUFFERS-(axi_data.bufnum1)), + &sync->pmem_frame_spinlock); + if (!axi_data.bufnum2) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + break; + + case CMD_AXI_CFG_ZSL: + CDBG("%s, CMD_AXI_CFG_ZSL, type = %d\n", __func__, + cfgcmd->cmd_type); + pmem_type = MSM_PMEM_PREVIEW; + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[0], MAX_PMEM_CFG_BUFFERS, + &sync->pmem_frame_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + + pmem_type = MSM_PMEM_THUMBNAIL; + axi_data.bufnum2 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[axi_data.bufnum1], + (MAX_PMEM_CFG_BUFFERS-(axi_data.bufnum1)), + &sync->pmem_frame_spinlock); + if (!axi_data.bufnum2) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + + pmem_type = MSM_PMEM_MAINIMG; + axi_data.bufnum3 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[axi_data.bufnum1 + axi_data.bufnum2], + (MAX_PMEM_CFG_BUFFERS - axi_data.bufnum1 - + axi_data.bufnum2), &sync->pmem_frame_spinlock); + if (!axi_data.bufnum3) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + break; + + case CMD_RAW_PICT_AXI_CFG: + pmem_type = MSM_PMEM_RAW_MAINIMG; + axi_data.bufnum2 = + msm_pmem_region_lookup(&sync->pmem_frames, pmem_type, + ®ion[0], MAX_PMEM_CFG_BUFFERS, + &sync->pmem_frame_spinlock); + if (!axi_data.bufnum2) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + break; + + case CMD_GENERAL: + data = NULL; + break; + + default: + pr_err("%s: unknown command type %d\n", + __func__, cfgcmd->cmd_type); + return -EINVAL; + } + + axi_data.region = ®ion[0]; + + /* send the AXI configuration command to driver */ + if (sync->vfefn.vfe_config) + rc = sync->vfefn.vfe_config(cfgcmd, data); + + return rc; +} + +static int msm_get_sensor_info(struct msm_sync *sync, void __user *arg) +{ + int rc = 0; + struct msm_camsensor_info info; + struct msm_camera_sensor_info *sdata; + + if (copy_from_user(&info, + arg, + sizeof(struct msm_camsensor_info))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + sdata = sync->pdev->dev.platform_data; + if (sync->sctrl.s_camera_type == BACK_CAMERA_3D) + info.support_3d = true; + else + info.support_3d = false; + memcpy(&info.name[0], + sdata->sensor_name, + MAX_SENSOR_NAME); + info.flash_enabled = sdata->flash_data->flash_type != + MSM_CAMERA_FLASH_NONE; + + /* copy back to user space */ + if (copy_to_user((void *)arg, + &info, + sizeof(struct msm_camsensor_info))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + } + + return rc; +} + +static int msm_get_camera_info(void __user *arg) +{ + int rc = 0; + int i = 0; + struct msm_camera_info info; + + if (copy_from_user(&info, arg, sizeof(struct msm_camera_info))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + CDBG("%s: camera_node %d\n", __func__, camera_node); + info.num_cameras = camera_node; + + for (i = 0; i < camera_node; i++) { + info.has_3d_support[i] = 0; + info.is_internal_cam[i] = 0; + info.s_mount_angle[i] = sensor_mount_angle[i]; + switch (camera_type[i]) { + case FRONT_CAMERA_2D: + info.is_internal_cam[i] = 1; + break; + case BACK_CAMERA_3D: + info.has_3d_support[i] = 1; + break; + case BACK_CAMERA_2D: + default: + break; + } + } + /* copy back to user space */ + if (copy_to_user((void *)arg, &info, sizeof(struct msm_camera_info))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + } + return rc; +} + +static int __msm_put_frame_buf(struct msm_sync *sync, + struct msm_frame *pb) +{ + unsigned long pphy; + struct msm_vfe_cfg_cmd cfgcmd; + + int rc = -EIO; + + /* Change the active flag. */ + pphy = msm_pmem_frame_vtop_lookup(sync, + pb->buffer, + pb->y_off, pb->cbcr_off, pb->fd, 1); + + if (pphy != 0) { + CDBG("%s: rel: vaddr %lx, paddr %lx\n", + __func__, + pb->buffer, pphy); + cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE; + cfgcmd.value = (void *)pb; + if (sync->vfefn.vfe_config) + rc = sync->vfefn.vfe_config(&cfgcmd, &pphy); + } else { + pr_err("%s: msm_pmem_frame_vtop_lookup failed\n", + __func__); + rc = -EINVAL; + } + + return rc; +} +static int __msm_put_pic_buf(struct msm_sync *sync, + struct msm_frame *pb) +{ + unsigned long pphy; + struct msm_vfe_cfg_cmd cfgcmd; + + int rc = -EIO; + + pphy = msm_pmem_frame_vtop_lookup(sync, + pb->buffer, + pb->y_off, pb->cbcr_off, pb->fd, 1); + + if (pphy != 0) { + CDBG("%s: rel: vaddr %lx, paddr %lx\n", + __func__, + pb->buffer, pphy); + cfgcmd.cmd_type = CMD_SNAP_BUF_RELEASE; + cfgcmd.value = (void *)pb; + if (sync->vfefn.vfe_config) + rc = sync->vfefn.vfe_config(&cfgcmd, &pphy); + } else { + pr_err("%s: msm_pmem_frame_vtop_lookup failed\n", + __func__); + rc = -EINVAL; + } + + return rc; +} + + +static int msm_put_frame_buffer(struct msm_sync *sync, void __user *arg) +{ + struct msm_frame buf_t; + + if (copy_from_user(&buf_t, + arg, + sizeof(struct msm_frame))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + return __msm_put_frame_buf(sync, &buf_t); +} + + +static int msm_put_pic_buffer(struct msm_sync *sync, void __user *arg) +{ + struct msm_frame buf_t; + + if (copy_from_user(&buf_t, + arg, + sizeof(struct msm_frame))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + return __msm_put_pic_buf(sync, &buf_t); +} + +static int __msm_register_pmem(struct msm_sync *sync, + struct msm_pmem_info *pinfo) +{ + int rc = 0; + + switch (pinfo->type) { + case MSM_PMEM_VIDEO: + case MSM_PMEM_PREVIEW: + case MSM_PMEM_THUMBNAIL: + case MSM_PMEM_MAINIMG: + case MSM_PMEM_RAW_MAINIMG: + case MSM_PMEM_VIDEO_VPE: + case MSM_PMEM_C2D: + case MSM_PMEM_MAINIMG_VPE: + case MSM_PMEM_THUMBNAIL_VPE: + rc = msm_pmem_table_add(&sync->pmem_frames, pinfo, + &sync->pmem_frame_spinlock, sync); + break; + + case MSM_PMEM_AEC_AWB: + case MSM_PMEM_AF: + case MSM_PMEM_AEC: + case MSM_PMEM_AWB: + case MSM_PMEM_RS: + case MSM_PMEM_CS: + case MSM_PMEM_IHIST: + case MSM_PMEM_SKIN: + + rc = msm_pmem_table_add(&sync->pmem_stats, pinfo, + &sync->pmem_stats_spinlock, sync); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static int msm_register_pmem(struct msm_sync *sync, void __user *arg) +{ + struct msm_pmem_info info; + + if (copy_from_user(&info, arg, sizeof(info))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + return __msm_register_pmem(sync, &info); +} + +static int msm_stats_axi_cfg(struct msm_sync *sync, + struct msm_vfe_cfg_cmd *cfgcmd) +{ + int rc = -EIO; + struct axidata axi_data; + void *data = &axi_data; + + struct msm_pmem_region region[3]; + int pmem_type = MSM_PMEM_MAX; + + memset(&axi_data, 0, sizeof(axi_data)); + + switch (cfgcmd->cmd_type) { + case CMD_STATS_AXI_CFG: + pmem_type = MSM_PMEM_AEC_AWB; + break; + case CMD_STATS_AF_AXI_CFG: + pmem_type = MSM_PMEM_AF; + break; + case CMD_GENERAL: + data = NULL; + break; + default: + pr_err("%s: unknown command type %d\n", + __func__, cfgcmd->cmd_type); + return -EINVAL; + } + + if (cfgcmd->cmd_type != CMD_GENERAL) { + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, pmem_type, + ®ion[0], NUM_STAT_OUTPUT_BUFFERS, + &sync->pmem_stats_spinlock); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + } + + /* send the AEC/AWB STATS configuration command to driver */ + if (sync->vfefn.vfe_config) + rc = sync->vfefn.vfe_config(cfgcmd, &axi_data); + + return rc; +} + +static int msm_put_stats_buffer(struct msm_sync *sync, void __user *arg) +{ + int rc = -EIO; + + struct msm_stats_buf buf; + unsigned long pphy; + struct msm_vfe_cfg_cmd cfgcmd; + + if (copy_from_user(&buf, arg, + sizeof(struct msm_stats_buf))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + CDBG("%s\n", __func__); + pphy = msm_pmem_stats_vtop_lookup(sync, buf.buffer, buf.fd); + + if (pphy != 0) { + if (buf.type == STAT_AEAW) + cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE; + else if (buf.type == STAT_AF) + cfgcmd.cmd_type = CMD_STATS_AF_BUF_RELEASE; + else if (buf.type == STAT_AEC) + cfgcmd.cmd_type = CMD_STATS_AEC_BUF_RELEASE; + else if (buf.type == STAT_AWB) + cfgcmd.cmd_type = CMD_STATS_AWB_BUF_RELEASE; + else if (buf.type == STAT_IHIST) + cfgcmd.cmd_type = CMD_STATS_IHIST_BUF_RELEASE; + else if (buf.type == STAT_RS) + cfgcmd.cmd_type = CMD_STATS_RS_BUF_RELEASE; + else if (buf.type == STAT_CS) + cfgcmd.cmd_type = CMD_STATS_CS_BUF_RELEASE; + + else { + pr_err("%s: invalid buf type %d\n", + __func__, + buf.type); + rc = -EINVAL; + goto put_done; + } + + cfgcmd.value = (void *)&buf; + + if (sync->vfefn.vfe_config) { + rc = sync->vfefn.vfe_config(&cfgcmd, &pphy); + if (rc < 0) + pr_err("%s: vfe_config error %d\n", + __func__, rc); + } else + pr_err("%s: vfe_config is NULL\n", __func__); + } else { + pr_err("%s: NULL physical address\n", __func__); + rc = -EINVAL; + } + +put_done: + return rc; +} + +static int msm_axi_config(struct msm_sync *sync, void __user *arg) +{ + struct msm_vfe_cfg_cmd cfgcmd; + + if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + switch (cfgcmd.cmd_type) { + case CMD_AXI_CFG_VIDEO: + case CMD_AXI_CFG_PREVIEW: + case CMD_AXI_CFG_SNAP: + case CMD_RAW_PICT_AXI_CFG: + case CMD_AXI_CFG_ZSL: + CDBG("%s, cfgcmd.cmd_type = %d\n", __func__, cfgcmd.cmd_type); + return msm_frame_axi_cfg(sync, &cfgcmd); + + case CMD_AXI_CFG_VPE: + case CMD_AXI_CFG_SNAP_VPE: + case CMD_AXI_CFG_SNAP_THUMB_VPE: + return msm_vpe_frame_cfg(sync, (void *)&cfgcmd); + + case CMD_STATS_AXI_CFG: + case CMD_STATS_AF_AXI_CFG: + return msm_stats_axi_cfg(sync, &cfgcmd); + + default: + pr_err("%s: unknown command type %d\n", + __func__, + cfgcmd.cmd_type); + return -EINVAL; + } + + return 0; +} + +static int __msm_get_pic(struct msm_sync *sync, + struct msm_frame *frame) +{ + + int rc = 0; + struct msm_queue_cmd *qcmd = NULL; + struct msm_vfe_resp *vdata; + struct msm_vfe_phy_info *pphy; + struct msm_pmem_info pmem_info; + struct msm_frame *pframe; + + qcmd = msm_dequeue(&sync->pict_q, list_pict); + + if (!qcmd) { + pr_err("%s: no pic frame.\n", __func__); + return -EAGAIN; + } + + if (MSM_CAM_Q_PP_MSG != qcmd->type) { + vdata = (struct msm_vfe_resp *)(qcmd->command); + pphy = &vdata->phy; + + rc = msm_pmem_frame_ptov_lookup2(sync, + pphy->y_phy, + &pmem_info, + 1); /* mark pic frame in use */ + + if (rc < 0) { + pr_err("%s: cannot get pic frame, invalid lookup" + " address y %x cbcr %x\n", + __func__, pphy->y_phy, pphy->cbcr_phy); + goto err; + } + + frame->ts = qcmd->ts; + frame->buffer = (unsigned long)pmem_info.vaddr; + frame->y_off = pmem_info.y_off; + frame->cbcr_off = pmem_info.cbcr_off; + frame->fd = pmem_info.fd; + if (sync->stereocam_enabled && + sync->stereo_state != STEREO_RAW_SNAP_STARTED) { + if (pmem_info.type == MSM_PMEM_THUMBNAIL_VPE) + frame->path = OUTPUT_TYPE_T; + else + frame->path = OUTPUT_TYPE_S; + } else + frame->path = vdata->phy.output_id; + + CDBG("%s: y %x, cbcr %x, qcmd %x, virt_addr %x\n", + __func__, pphy->y_phy, + pphy->cbcr_phy, (int) qcmd, (int) frame->buffer); + } else { /* PP */ + pframe = (struct msm_frame *)(qcmd->command); + frame->ts = qcmd->ts; + frame->buffer = pframe->buffer; + frame->y_off = pframe->y_off; + frame->cbcr_off = pframe->cbcr_off; + frame->fd = pframe->fd; + frame->path = pframe->path; + CDBG("%s: PP y_off %x, cbcr_off %x, path %d vaddr 0x%x\n", + __func__, frame->y_off, frame->cbcr_off, frame->path, + (int) frame->buffer); + } + +err: + free_qcmd(qcmd); + + return rc; +} + +static int msm_get_pic(struct msm_sync *sync, void __user *arg) +{ + int rc = 0; + struct msm_frame frame; + + if (copy_from_user(&frame, + arg, + sizeof(struct msm_frame))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + rc = __msm_get_pic(sync, &frame); + if (rc < 0) + return rc; + + if (sync->croplen && (!sync->stereocam_enabled)) { + if (frame.croplen != sync->croplen) { + pr_err("%s: invalid frame croplen %d," + "expecting %d\n", + __func__, + frame.croplen, + sync->croplen); + return -EINVAL; + } + + if (copy_to_user((void *)frame.cropinfo, + sync->cropinfo, + sync->croplen)) { + ERR_COPY_TO_USER(); + return -EFAULT; + } + } + CDBG("%s: copy snapshot frame to user\n", __func__); + if (copy_to_user((void *)arg, + &frame, sizeof(struct msm_frame))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + } + + CDBG("%s: got pic frame\n", __func__); + + return rc; +} + +static int msm_set_crop(struct msm_sync *sync, void __user *arg) +{ + struct crop_info crop; + + mutex_lock(&sync->lock); + if (copy_from_user(&crop, + arg, + sizeof(struct crop_info))) { + ERR_COPY_FROM_USER(); + mutex_unlock(&sync->lock); + return -EFAULT; + } + + if (crop.len != CROP_LEN) { + mutex_unlock(&sync->lock); + return -EINVAL; + } + + if (!sync->croplen) { + sync->cropinfo = kmalloc(crop.len, GFP_KERNEL); + if (!sync->cropinfo) { + mutex_unlock(&sync->lock); + return -ENOMEM; + } + } + + if (copy_from_user(sync->cropinfo, + crop.info, + crop.len)) { + ERR_COPY_FROM_USER(); + sync->croplen = 0; + kfree(sync->cropinfo); + mutex_unlock(&sync->lock); + return -EFAULT; + } + + sync->croplen = crop.len; + + mutex_unlock(&sync->lock); + return 0; +} + +static int msm_error_config(struct msm_sync *sync, void __user *arg) +{ + struct msm_queue_cmd *qcmd = + kmalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); + + qcmd->command = NULL; + + if (qcmd) + atomic_set(&(qcmd->on_heap), 1); + + if (copy_from_user(&(qcmd->error_code), arg, sizeof(uint32_t))) { + ERR_COPY_FROM_USER(); + free_qcmd(qcmd); + return -EFAULT; + } + + pr_err("%s: Enqueue Fake Frame with error code = %d\n", __func__, + qcmd->error_code); + msm_enqueue(&sync->frame_q, &qcmd->list_frame); + return 0; +} + +static int msm_set_fd_roi(struct msm_sync *sync, void __user *arg) +{ + struct fd_roi_info fd_roi; + + mutex_lock(&sync->lock); + if (copy_from_user(&fd_roi, + arg, + sizeof(struct fd_roi_info))) { + ERR_COPY_FROM_USER(); + mutex_unlock(&sync->lock); + return -EFAULT; + } + if (fd_roi.info_len <= 0) { + mutex_unlock(&sync->lock); + return -EFAULT; + } + + if (!sync->fdroiinfo.info) { + sync->fdroiinfo.info = kmalloc(fd_roi.info_len, GFP_KERNEL); + if (!sync->fdroiinfo.info) { + mutex_unlock(&sync->lock); + return -ENOMEM; + } + sync->fdroiinfo.info_len = fd_roi.info_len; + } else if (sync->fdroiinfo.info_len < fd_roi.info_len) { + mutex_unlock(&sync->lock); + return -EINVAL; + } + + if (copy_from_user(sync->fdroiinfo.info, + fd_roi.info, + fd_roi.info_len)) { + ERR_COPY_FROM_USER(); + kfree(sync->fdroiinfo.info); + sync->fdroiinfo.info = NULL; + mutex_unlock(&sync->lock); + return -EFAULT; + } + mutex_unlock(&sync->lock); + return 0; +} + +static int msm_pp_grab(struct msm_sync *sync, void __user *arg) +{ + uint32_t enable; + if (copy_from_user(&enable, arg, sizeof(enable))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } else { + enable &= PP_MASK; + if (enable & (enable - 1)) { + CDBG("%s: more than one PP request!\n", + __func__); + } + if (sync->pp_mask) { + if (enable) { + CDBG("%s: postproc %x is already enabled\n", + __func__, sync->pp_mask & enable); + } else { + sync->pp_mask &= enable; + CDBG("%s: sync->pp_mask %d enable %d\n", + __func__, sync->pp_mask, enable); + } + } + + CDBG("%s: sync->pp_mask %d enable %d\n", __func__, + sync->pp_mask, enable); + sync->pp_mask |= enable; + } + + return 0; +} + +static int msm_put_st_frame(struct msm_sync *sync, void __user *arg) +{ + unsigned long flags; + unsigned long st_pphy; + if (sync->stereocam_enabled) { + /* Make stereo frame ready for VPE. */ + struct msm_st_frame stereo_frame_half; + + if (copy_from_user(&stereo_frame_half, arg, + sizeof(stereo_frame_half))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + if (stereo_frame_half.type == OUTPUT_TYPE_ST_L) { + struct msm_vfe_resp *vfe_rp; + struct msm_queue_cmd *qcmd; + + spin_lock_irqsave(&pp_stereocam_spinlock, flags); + if (!sync->pp_stereocam) { + pr_warning("%s: no stereo frame to deliver!\n", + __func__); + spin_unlock_irqrestore(&pp_stereocam_spinlock, + flags); + return -EINVAL; + } + CDBG("%s: delivering left frame to VPE\n", __func__); + + qcmd = sync->pp_stereocam; + sync->pp_stereocam = NULL; + spin_unlock_irqrestore(&pp_stereocam_spinlock, flags); + + vfe_rp = (struct msm_vfe_resp *)qcmd->command; + + CDBG("%s: Left Py = 0x%x y_off = %d cbcr_off = %d\n", + __func__, vfe_rp->phy.y_phy, + stereo_frame_half.L.buf_y_off, + stereo_frame_half.L.buf_cbcr_off); + + sync->vpefn.vpe_cfg_offset(stereo_frame_half.packing, + vfe_rp->phy.y_phy + stereo_frame_half.L.buf_y_off, + vfe_rp->phy.y_phy + stereo_frame_half.L.buf_cbcr_off, + &(qcmd->ts), OUTPUT_TYPE_ST_L, stereo_frame_half.L, + stereo_frame_half.frame_id); + + free_qcmd(qcmd); + } else if (stereo_frame_half.type == OUTPUT_TYPE_ST_R) { + CDBG("%s: delivering right frame to VPE\n", __func__); + spin_lock_irqsave(&st_frame_spinlock, flags); + + sync->stcam_conv_value = + stereo_frame_half.buf_info.stcam_conv_value; + sync->stcam_quality_ind = + stereo_frame_half.buf_info.stcam_quality_ind; + + st_pphy = msm_pmem_frame_vtop_lookup(sync, + stereo_frame_half.buf_info.buffer, + stereo_frame_half.buf_info.y_off, + stereo_frame_half.buf_info.cbcr_off, + stereo_frame_half.buf_info.fd, + 0); /* Do not change the active flag. */ + + sync->vpefn.vpe_cfg_offset(stereo_frame_half.packing, + st_pphy + stereo_frame_half.R.buf_y_off, + st_pphy + stereo_frame_half.R.buf_cbcr_off, + NULL, OUTPUT_TYPE_ST_R, stereo_frame_half.R, + stereo_frame_half.frame_id); + + spin_unlock_irqrestore(&st_frame_spinlock, flags); + } else { + CDBG("%s: Invalid Msg\n", __func__); + } + } + + return 0; +} + +static struct msm_queue_cmd *msm_get_pp_qcmd(struct msm_frame* frame) +{ + struct msm_queue_cmd *qcmd = + kmalloc(sizeof(struct msm_queue_cmd) + + sizeof(struct msm_frame), GFP_ATOMIC); + qcmd->command = (struct msm_frame *)(qcmd + 1); + + qcmd->type = MSM_CAM_Q_PP_MSG; + + ktime_get_ts(&(qcmd->ts)); + memcpy(qcmd->command, frame, sizeof(struct msm_frame)); + atomic_set(&(qcmd->on_heap), 1); + return qcmd; +} + +static int msm_pp_release(struct msm_sync *sync, void __user *arg) +{ + unsigned long flags; + + if (!sync->pp_mask) { + pr_warning("%s: pp not in progress for\n", __func__); + return -EINVAL; + } + if (sync->pp_mask & PP_PREV) { + + + spin_lock_irqsave(&pp_prev_spinlock, flags); + if (!sync->pp_prev) { + pr_err("%s: no preview frame to deliver!\n", + __func__); + spin_unlock_irqrestore(&pp_prev_spinlock, + flags); + return -EINVAL; + } + CDBG("%s: delivering pp_prev\n", __func__); + + if (sync->frame_q.len <= 100 && + sync->event_q.len <= 100) { + msm_enqueue(&sync->frame_q, + &sync->pp_prev->list_frame); + } else { + pr_err("%s, Error Queue limit exceeded f_q=%d,\ + e_q = %d\n", + __func__, sync->frame_q.len, + sync->event_q.len); + free_qcmd(sync->pp_prev); + goto done; + } + + sync->pp_prev = NULL; + spin_unlock_irqrestore(&pp_prev_spinlock, flags); + goto done; + } + + if ((sync->pp_mask & PP_SNAP) || + (sync->pp_mask & PP_RAW_SNAP)) { + struct msm_frame frame; + struct msm_queue_cmd *qcmd; + + if (copy_from_user(&frame, + arg, + sizeof(struct msm_frame))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + qcmd = msm_get_pp_qcmd(&frame); + if (!qcmd) { + pr_err("%s: no snapshot to deliver!\n", __func__); + return -EINVAL; + } + CDBG("%s: delivering pp snap\n", __func__); + msm_enqueue(&sync->pict_q, &qcmd->list_pict); + } + +done: + return 0; +} + +static long msm_ioctl_common(struct msm_cam_device *pmsm, + unsigned int cmd, + void __user *argp) +{ + switch (cmd) { + case MSM_CAM_IOCTL_REGISTER_PMEM: + CDBG("%s cmd = MSM_CAM_IOCTL_REGISTER_PMEM\n", __func__); + return msm_register_pmem(pmsm->sync, argp); + case MSM_CAM_IOCTL_UNREGISTER_PMEM: + CDBG("%s cmd = MSM_CAM_IOCTL_UNREGISTER_PMEM\n", __func__); + return msm_pmem_table_del(pmsm->sync, argp); + case MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER: + CDBG("%s cmd = MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER\n", __func__); + return msm_put_frame_buffer(pmsm->sync, argp); + break; + default: + CDBG("%s cmd invalid\n", __func__); + return -EINVAL; + } +} + +static long msm_ioctl_config(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int rc = -EINVAL; + void __user *argp = (void __user *)arg; + struct msm_cam_device *pmsm = filep->private_data; + + CDBG("%s: cmd %d\n", __func__, _IOC_NR(cmd)); + + switch (cmd) { + case MSM_CAM_IOCTL_GET_SENSOR_INFO: + rc = msm_get_sensor_info(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_CONFIG_VFE: + /* Coming from config thread for update */ + rc = msm_config_vfe(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_CONFIG_VPE: + /* Coming from config thread for update */ + rc = msm_config_vpe(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_GET_STATS: + /* Coming from config thread wait + * for vfe statistics and control requests */ + rc = msm_get_stats(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_ENABLE_VFE: + /* This request comes from control thread: + * enable either QCAMTASK or VFETASK */ + rc = msm_enable_vfe(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_DISABLE_VFE: + /* This request comes from control thread: + * disable either QCAMTASK or VFETASK */ + rc = msm_disable_vfe(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_VFE_APPS_RESET: + msm_camio_vfe_blk_reset(); + rc = 0; + break; + + case MSM_CAM_IOCTL_RELEASE_STATS_BUFFER: + rc = msm_put_stats_buffer(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_AXI_CONFIG: + case MSM_CAM_IOCTL_AXI_VPE_CONFIG: + rc = msm_axi_config(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_SET_CROP: + rc = msm_set_crop(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_SET_FD_ROI: + rc = msm_set_fd_roi(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_PICT_PP: + /* Grab one preview frame or one snapshot + * frame. + */ + rc = msm_pp_grab(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_PICT_PP_DONE: + /* Release the preview of snapshot frame + * that was grabbed. + */ + rc = msm_pp_release(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_PUT_ST_FRAME: + /* Release the left or right frame + * that was sent for stereo processing. + */ + rc = msm_put_st_frame(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_SENSOR_IO_CFG: + rc = pmsm->sync->sctrl.s_config(argp); + break; + + case MSM_CAM_IOCTL_FLASH_LED_CFG: { + uint32_t led_state; + if (copy_from_user(&led_state, argp, sizeof(led_state))) { + ERR_COPY_FROM_USER(); + rc = -EFAULT; + } else + rc = msm_camera_flash_set_led_state(pmsm->sync-> + sdata->flash_data, led_state); + break; + } + + case MSM_CAM_IOCTL_STROBE_FLASH_CFG: { + uint32_t flash_type; + if (copy_from_user(&flash_type, argp, sizeof(flash_type))) { + pr_err("msm_strobe_flash_init failed"); + ERR_COPY_FROM_USER(); + rc = -EFAULT; + } else { + CDBG("msm_strobe_flash_init enter"); + rc = msm_strobe_flash_init(pmsm->sync, flash_type); + } + break; + } + + case MSM_CAM_IOCTL_STROBE_FLASH_RELEASE: + if (pmsm->sync->sdata->strobe_flash_data) { + rc = pmsm->sync->sfctrl.strobe_flash_release( + pmsm->sync->sdata->strobe_flash_data, 0); + } + break; + + case MSM_CAM_IOCTL_STROBE_FLASH_CHARGE: { + uint32_t charge_en; + if (copy_from_user(&charge_en, argp, sizeof(charge_en))) { + ERR_COPY_FROM_USER(); + rc = -EFAULT; + } else + rc = pmsm->sync->sfctrl.strobe_flash_charge( + pmsm->sync->sdata->strobe_flash_data->flash_charge, + charge_en, pmsm->sync->sdata->strobe_flash_data-> + flash_recharge_duration); + break; + } + + case MSM_CAM_IOCTL_FLASH_CTRL: { + struct flash_ctrl_data flash_info; + if (copy_from_user(&flash_info, argp, sizeof(flash_info))) { + ERR_COPY_FROM_USER(); + rc = -EFAULT; + } else + rc = msm_flash_ctrl(pmsm->sync->sdata, &flash_info); + + break; + } + + case MSM_CAM_IOCTL_ERROR_CONFIG: + rc = msm_error_config(pmsm->sync, argp); + break; + + case MSM_CAM_IOCTL_ABORT_CAPTURE: { + unsigned long flags = 0; + CDBG("get_pic:MSM_CAM_IOCTL_ABORT_CAPTURE\n"); + spin_lock_irqsave(&pmsm->sync->abort_pict_lock, flags); + pmsm->sync->get_pic_abort = 1; + spin_unlock_irqrestore(&pmsm->sync->abort_pict_lock, flags); + wake_up(&(pmsm->sync->pict_q.wait)); + rc = 0; + break; + } + + default: + rc = msm_ioctl_common(pmsm, cmd, argp); + break; + } + + CDBG("%s: cmd %d DONE\n", __func__, _IOC_NR(cmd)); + return rc; +} + +static int msm_unblock_poll_frame(struct msm_sync *); + +static long msm_ioctl_frame(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int rc = -EINVAL; + void __user *argp = (void __user *)arg; + struct msm_cam_device *pmsm = filep->private_data; + + + switch (cmd) { + case MSM_CAM_IOCTL_GETFRAME: + /* Coming from frame thread to get frame + * after SELECT is done */ + rc = msm_get_frame(pmsm->sync, argp); + break; + case MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER: + rc = msm_put_frame_buffer(pmsm->sync, argp); + break; + case MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME: + rc = msm_unblock_poll_frame(pmsm->sync); + break; + default: + break; + } + + return rc; +} + +static int msm_unblock_poll_pic(struct msm_sync *sync); +static long msm_ioctl_pic(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int rc = -EINVAL; + void __user *argp = (void __user *)arg; + struct msm_cam_device *pmsm = filep->private_data; + + + switch (cmd) { + case MSM_CAM_IOCTL_GET_PICTURE: + rc = msm_get_pic(pmsm->sync, argp); + break; + case MSM_CAM_IOCTL_RELEASE_PIC_BUFFER: + rc = msm_put_pic_buffer(pmsm->sync, argp); + break; + case MSM_CAM_IOCTL_UNBLOCK_POLL_PIC_FRAME: + rc = msm_unblock_poll_pic(pmsm->sync); + break; + default: + break; + } + + return rc; +} + + +static long msm_ioctl_control(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int rc = -EINVAL; + void __user *argp = (void __user *)arg; + struct msm_control_device *ctrl_pmsm = filep->private_data; + struct msm_cam_device *pmsm = ctrl_pmsm->pmsm; + + switch (cmd) { + case MSM_CAM_IOCTL_CTRL_COMMAND: + /* Coming from control thread, may need to wait for + * command status */ + CDBG("calling msm_control kernel msm_ioctl_control\n"); + mutex_lock(&ctrl_cmd_lock); + rc = msm_control(ctrl_pmsm, 1, argp); + mutex_unlock(&ctrl_cmd_lock); + break; + case MSM_CAM_IOCTL_CTRL_COMMAND_2: + /* Sends a message, returns immediately */ + rc = msm_control(ctrl_pmsm, 0, argp); + break; + case MSM_CAM_IOCTL_CTRL_CMD_DONE: + /* Config thread calls the control thread to notify it + * of the result of a MSM_CAM_IOCTL_CTRL_COMMAND. + */ + rc = msm_ctrl_cmd_done(ctrl_pmsm, argp); + break; + case MSM_CAM_IOCTL_GET_SENSOR_INFO: + rc = msm_get_sensor_info(pmsm->sync, argp); + break; + case MSM_CAM_IOCTL_GET_CAMERA_INFO: + rc = msm_get_camera_info(argp); + break; + default: + rc = msm_ioctl_common(pmsm, cmd, argp); + break; + } + + return rc; +} + +static int __msm_release(struct msm_sync *sync) +{ + struct msm_pmem_region *region; + struct hlist_node *hnode; + struct hlist_node *n; + + mutex_lock(&sync->lock); + if (sync->opencnt) + sync->opencnt--; + pr_info("%s, open count =%d\n", __func__, sync->opencnt); + if (!sync->opencnt) { + /* need to clean up system resource */ + pr_info("%s, release VFE\n", __func__); + if (sync->core_powered_on) { + if (sync->vfefn.vfe_release) + sync->vfefn.vfe_release(sync->pdev); + /*sensor release */ + pr_info("%s, release Sensor\n", __func__); + sync->sctrl.s_release(); + CDBG("%s, msm_camio_sensor_clk_off\n", __func__); + msm_camio_sensor_clk_off(sync->pdev); + if (sync->sfctrl.strobe_flash_release) { + CDBG("%s, strobe_flash_release\n", __func__); + sync->sfctrl.strobe_flash_release( + sync->sdata->strobe_flash_data, 1); + } + } + kfree(sync->cropinfo); + sync->cropinfo = NULL; + sync->croplen = 0; + CDBG("%s, free frame pmem region\n", __func__); + hlist_for_each_entry_safe(region, hnode, n, + &sync->pmem_frames, list) { + hlist_del(hnode); +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_free(client_for_ion, region->handle); +#else + put_pmem_file(region->file); +#endif + kfree(region); + } + CDBG("%s, free stats pmem region\n", __func__); + hlist_for_each_entry_safe(region, hnode, n, + &sync->pmem_stats, list) { + hlist_del(hnode); +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_free(client_for_ion, region->handle); +#else + put_pmem_file(region->file); +#endif + kfree(region); + } + msm_queue_drain(&sync->pict_q, list_pict); + msm_queue_drain(&sync->event_q, list_config); + + wake_unlock(&sync->wake_lock); + sync->apps_id = NULL; + sync->core_powered_on = 0; + } + mutex_unlock(&sync->lock); + ion_client_destroy(client_for_ion); + + return 0; +} + +static int msm_release_config(struct inode *node, struct file *filep) +{ + int rc; + struct msm_cam_device *pmsm = filep->private_data; + pr_info("%s: %s\n", __func__, filep->f_path.dentry->d_name.name); + rc = __msm_release(pmsm->sync); + if (!rc) { + msm_queue_drain(&pmsm->sync->event_q, list_config); + atomic_set(&pmsm->opened, 0); + } + return rc; +} + +static int msm_release_control(struct inode *node, struct file *filep) +{ + int rc; + struct msm_control_device *ctrl_pmsm = filep->private_data; + struct msm_cam_device *pmsm = ctrl_pmsm->pmsm; + pr_info("%s: %s\n", __func__, filep->f_path.dentry->d_name.name); + g_v4l2_opencnt--; + mutex_lock(&pmsm->sync->lock); + if (pmsm->sync->core_powered_on && pmsm->sync->vfefn.vfe_stop) { + pr_info("%s, stop vfe if active\n", __func__); + pmsm->sync->vfefn.vfe_stop(); + } + mutex_unlock(&pmsm->sync->lock); + rc = __msm_release(pmsm->sync); + if (!rc) { + msm_queue_drain(&ctrl_pmsm->ctrl_q, list_control); + kfree(ctrl_pmsm); + } + return rc; +} + +static int msm_release_frame(struct inode *node, struct file *filep) +{ + int rc; + struct msm_cam_device *pmsm = filep->private_data; + pr_info("%s: %s\n", __func__, filep->f_path.dentry->d_name.name); + rc = __msm_release(pmsm->sync); + if (!rc) { + msm_queue_drain(&pmsm->sync->frame_q, list_frame); + atomic_set(&pmsm->opened, 0); + } + return rc; +} + + +static int msm_release_pic(struct inode *node, struct file *filep) +{ + int rc; + struct msm_cam_device *pmsm = filep->private_data; + CDBG("%s: %s\n", __func__, filep->f_path.dentry->d_name.name); + rc = __msm_release(pmsm->sync); + if (!rc) { + msm_queue_drain(&pmsm->sync->pict_q, list_pict); + atomic_set(&pmsm->opened, 0); + } + return rc; +} + +static int msm_unblock_poll_pic(struct msm_sync *sync) +{ + unsigned long flags; + CDBG("%s\n", __func__); + spin_lock_irqsave(&sync->pict_q.lock, flags); + sync->unblock_poll_pic_frame = 1; + wake_up(&sync->pict_q.wait); + spin_unlock_irqrestore(&sync->pict_q.lock, flags); + return 0; +} + +static int msm_unblock_poll_frame(struct msm_sync *sync) +{ + unsigned long flags; + CDBG("%s\n", __func__); + spin_lock_irqsave(&sync->frame_q.lock, flags); + sync->unblock_poll_frame = 1; + wake_up(&sync->frame_q.wait); + spin_unlock_irqrestore(&sync->frame_q.lock, flags); + return 0; +} + +static unsigned int __msm_poll_frame(struct msm_sync *sync, + struct file *filep, + struct poll_table_struct *pll_table) +{ + int rc = 0; + unsigned long flags; + + poll_wait(filep, &sync->frame_q.wait, pll_table); + + spin_lock_irqsave(&sync->frame_q.lock, flags); + if (!list_empty_careful(&sync->frame_q.list)) + /* frame ready */ + rc = POLLIN | POLLRDNORM; + if (sync->unblock_poll_frame) { + CDBG("%s: sync->unblock_poll_frame is true\n", __func__); + rc |= POLLPRI; + sync->unblock_poll_frame = 0; + } + spin_unlock_irqrestore(&sync->frame_q.lock, flags); + + return rc; +} + +static unsigned int __msm_poll_pic(struct msm_sync *sync, + struct file *filep, + struct poll_table_struct *pll_table) +{ + int rc = 0; + unsigned long flags; + + poll_wait(filep, &sync->pict_q.wait , pll_table); + spin_lock_irqsave(&sync->abort_pict_lock, flags); + if (sync->get_pic_abort == 1) { + /* TODO: need to pass an error case */ + sync->get_pic_abort = 0; + } + spin_unlock_irqrestore(&sync->abort_pict_lock, flags); + + spin_lock_irqsave(&sync->pict_q.lock, flags); + if (!list_empty_careful(&sync->pict_q.list)) + /* frame ready */ + rc = POLLIN | POLLRDNORM; + if (sync->unblock_poll_pic_frame) { + CDBG("%s: sync->unblock_poll_pic_frame is true\n", __func__); + rc |= POLLPRI; + sync->unblock_poll_pic_frame = 0; + } + spin_unlock_irqrestore(&sync->pict_q.lock, flags); + + return rc; +} + +static unsigned int msm_poll_frame(struct file *filep, + struct poll_table_struct *pll_table) +{ + struct msm_cam_device *pmsm = filep->private_data; + return __msm_poll_frame(pmsm->sync, filep, pll_table); +} + +static unsigned int msm_poll_pic(struct file *filep, + struct poll_table_struct *pll_table) +{ + struct msm_cam_device *pmsm = filep->private_data; + return __msm_poll_pic(pmsm->sync, filep, pll_table); +} + +static unsigned int __msm_poll_config(struct msm_sync *sync, + struct file *filep, + struct poll_table_struct *pll_table) +{ + int rc = 0; + unsigned long flags; + + poll_wait(filep, &sync->event_q.wait, pll_table); + + spin_lock_irqsave(&sync->event_q.lock, flags); + if (!list_empty_careful(&sync->event_q.list)) + /* event ready */ + rc = POLLIN | POLLRDNORM; + spin_unlock_irqrestore(&sync->event_q.lock, flags); + + return rc; +} + +static unsigned int msm_poll_config(struct file *filep, + struct poll_table_struct *pll_table) +{ + struct msm_cam_device *pmsm = filep->private_data; + return __msm_poll_config(pmsm->sync, filep, pll_table); +} + +/* + * This function executes in interrupt context. + */ + +static void *msm_vfe_sync_alloc(int size, + void *syncdata __attribute__((unused)), + gfp_t gfp) +{ + struct msm_queue_cmd *qcmd = + kzalloc(sizeof(struct msm_queue_cmd) + size, gfp); + if (qcmd) { + atomic_set(&qcmd->on_heap, 1); + return qcmd + 1; + } + return NULL; +} + +static void *msm_vpe_sync_alloc(int size, + void *syncdata __attribute__((unused)), + gfp_t gfp) +{ + struct msm_queue_cmd *qcmd = + kzalloc(sizeof(struct msm_queue_cmd) + size, gfp); + if (qcmd) { + atomic_set(&qcmd->on_heap, 1); + return qcmd + 1; + } + return NULL; +} + +static void msm_vfe_sync_free(void *ptr) +{ + if (ptr) { + struct msm_queue_cmd *qcmd = + (struct msm_queue_cmd *)ptr; + qcmd--; + if (atomic_read(&qcmd->on_heap)) + kfree(qcmd); + } +} + +static void msm_vpe_sync_free(void *ptr) +{ + if (ptr) { + struct msm_queue_cmd *qcmd = + (struct msm_queue_cmd *)ptr; + qcmd--; + if (atomic_read(&qcmd->on_heap)) + kfree(qcmd); + } +} + +/* + * This function executes in interrupt context. + */ + +static void msm_vfe_sync(struct msm_vfe_resp *vdata, + enum msm_queue qtype, void *syncdata, + gfp_t gfp) +{ + struct msm_queue_cmd *qcmd = NULL; + struct msm_sync *sync = (struct msm_sync *)syncdata; + unsigned long flags; + + if (!sync) { + pr_err("%s: no context in dsp callback.\n", __func__); + return; + } + + qcmd = ((struct msm_queue_cmd *)vdata) - 1; + qcmd->type = qtype; + qcmd->command = vdata; + + ktime_get_ts(&(qcmd->ts)); + + if (qtype != MSM_CAM_Q_VFE_MSG) + goto vfe_for_config; + + CDBG("%s: vdata->type %d\n", __func__, vdata->type); + + switch (vdata->type) { + case VFE_MSG_OUTPUT_P: + if (sync->pp_mask & PP_PREV) { + CDBG("%s: PP_PREV in progress: phy_y %x phy_cbcr %x\n", + __func__, + vdata->phy.y_phy, + vdata->phy.cbcr_phy); + spin_lock_irqsave(&pp_prev_spinlock, flags); + if (sync->pp_prev) + CDBG("%s: overwriting pp_prev!\n", + __func__); + CDBG("%s: sending preview to config\n", __func__); + sync->pp_prev = qcmd; + spin_unlock_irqrestore(&pp_prev_spinlock, flags); + sync->pp_frame_avail = 1; + if (atomic_read(&qcmd->on_heap)) + atomic_add(1, &qcmd->on_heap); + break; + } + CDBG("%s: msm_enqueue frame_q\n", __func__); + if (sync->stereocam_enabled) + CDBG("%s: Enqueue VFE_MSG_OUTPUT_P to event_q for " + "stereo processing\n", __func__); + else { + if (sync->frame_q.len <= 100 && + sync->event_q.len <= 100) { + if (atomic_read(&qcmd->on_heap)) + atomic_add(1, &qcmd->on_heap); + msm_enqueue(&sync->frame_q, &qcmd->list_frame); + } else { + pr_err("%s, Error Queue limit exceeded " + "f_q = %d, e_q = %d\n", __func__, + sync->frame_q.len, sync->event_q.len); + free_qcmd(qcmd); + return; + } + } + break; + + case VFE_MSG_OUTPUT_T: + if (sync->stereocam_enabled) { + spin_lock_irqsave(&pp_stereocam_spinlock, flags); + + /* if out1/2 is currently in progress, save the qcmd + and issue only ionce the 1st one completes the 3D + pipeline */ + if (STEREO_SNAP_BUFFER1_PROCESSING == + sync->stereo_state) { + sync->pp_stereocam2 = qcmd; + spin_unlock_irqrestore(&pp_stereocam_spinlock, + flags); + if (atomic_read(&qcmd->on_heap)) + atomic_add(1, &qcmd->on_heap); + CDBG("%s: snapshot stereo in progress\n", + __func__); + return; + } + + if (sync->pp_stereocam) + CDBG("%s: overwriting pp_stereocam!\n", + __func__); + + CDBG("%s: sending stereo frame to config\n", __func__); + sync->pp_stereocam = qcmd; + sync->stereo_state = + STEREO_SNAP_BUFFER1_PROCESSING; + + spin_unlock_irqrestore(&pp_stereocam_spinlock, flags); + + /* Increament on_heap by one because the same qcmd will + be used for VPE in msm_pp_release. */ + if (atomic_read(&qcmd->on_heap)) + atomic_add(1, &qcmd->on_heap); + CDBG("%s: Enqueue VFE_MSG_OUTPUT_T to event_q for " + "stereo processing.\n", __func__); + break; + } + if (sync->pp_mask & PP_SNAP) { + CDBG("%s: pp sending thumbnail to config\n", + __func__); + } else { + msm_enqueue(&sync->pict_q, &qcmd->list_pict); + return; + } + + case VFE_MSG_OUTPUT_S: + if (sync->stereocam_enabled && + sync->stereo_state != STEREO_RAW_SNAP_STARTED) { + spin_lock_irqsave(&pp_stereocam_spinlock, flags); + + /* if out1/2 is currently in progress, save the qcmd + and issue only once the 1st one completes the 3D + pipeline */ + if (STEREO_SNAP_BUFFER1_PROCESSING == + sync->stereo_state) { + sync->pp_stereocam2 = qcmd; + spin_unlock_irqrestore(&pp_stereocam_spinlock, + flags); + if (atomic_read(&qcmd->on_heap)) + atomic_add(1, &qcmd->on_heap); + CDBG("%s: snapshot stereo in progress\n", + __func__); + return; + } + if (sync->pp_stereocam) + CDBG("%s: overwriting pp_stereocam!\n", + __func__); + + CDBG("%s: sending stereo frame to config\n", __func__); + sync->pp_stereocam = qcmd; + sync->stereo_state = + STEREO_SNAP_BUFFER1_PROCESSING; + + spin_unlock_irqrestore(&pp_stereocam_spinlock, flags); + + /* Increament on_heap by one because the same qcmd will + be used for VPE in msm_pp_release. */ + if (atomic_read(&qcmd->on_heap)) + atomic_add(1, &qcmd->on_heap); + CDBG("%s: Enqueue VFE_MSG_OUTPUT_S to event_q for " + "stereo processing.\n", __func__); + break; + } + if (sync->pp_mask & PP_SNAP) { + CDBG("%s: pp sending main image to config\n", + __func__); + } else { + CDBG("%s: enqueue to picture queue\n", __func__); + msm_enqueue(&sync->pict_q, &qcmd->list_pict); + return; + } + break; + + case VFE_MSG_OUTPUT_V: + if (sync->stereocam_enabled) { + spin_lock_irqsave(&pp_stereocam_spinlock, flags); + + if (sync->pp_stereocam) + CDBG("%s: overwriting pp_stereocam!\n", + __func__); + + CDBG("%s: sending stereo frame to config\n", __func__); + sync->pp_stereocam = qcmd; + + spin_unlock_irqrestore(&pp_stereocam_spinlock, flags); + + /* Increament on_heap by one because the same qcmd will + be used for VPE in msm_pp_release. */ + if (atomic_read(&qcmd->on_heap)) + atomic_add(1, &qcmd->on_heap); + CDBG("%s: Enqueue VFE_MSG_OUTPUT_V to event_q for " + "stereo processing.\n", __func__); + break; + } + if (sync->vpefn.vpe_cfg_update) { + CDBG("dis_en = %d\n", *sync->vpefn.dis); + if (*(sync->vpefn.dis)) { + memset(&(vdata->vpe_bf), 0, + sizeof(vdata->vpe_bf)); + + if (sync->cropinfo != NULL) + vdata->vpe_bf.vpe_crop = + *(struct video_crop_t *)(sync->cropinfo); + + vdata->vpe_bf.y_phy = vdata->phy.y_phy; + vdata->vpe_bf.cbcr_phy = vdata->phy.cbcr_phy; + vdata->vpe_bf.ts = (qcmd->ts); + vdata->vpe_bf.frame_id = vdata->phy.frame_id; + qcmd->command = vdata; + msm_enqueue_vpe(&sync->vpe_q, + &qcmd->list_vpe_frame); + return; + } else if (sync->vpefn.vpe_cfg_update(sync->cropinfo)) { + CDBG("%s: msm_enqueue video frame to vpe time " + "= %ld\n", __func__, qcmd->ts.tv_nsec); + + sync->vpefn.send_frame_to_vpe( + vdata->phy.y_phy, + vdata->phy.cbcr_phy, + &(qcmd->ts), OUTPUT_TYPE_V); + + free_qcmd(qcmd); + return; + } else { + CDBG("%s: msm_enqueue video frame_q\n", + __func__); + if (sync->liveshot_enabled) { + CDBG("%s: msm_enqueue liveshot\n", + __func__); + vdata->phy.output_id |= OUTPUT_TYPE_L; + sync->liveshot_enabled = false; + } + if (sync->frame_q.len <= 100 && + sync->event_q.len <= 100) { + msm_enqueue(&sync->frame_q, + &qcmd->list_frame); + } else { + pr_err("%s, Error Queue limit exceeded\ + f_q = %d, e_q = %d\n", + __func__, sync->frame_q.len, + sync->event_q.len); + free_qcmd(qcmd); + } + + return; + } + } else { + CDBG("%s: msm_enqueue video frame_q\n", __func__); + if (sync->frame_q.len <= 100 && + sync->event_q.len <= 100) { + msm_enqueue(&sync->frame_q, &qcmd->list_frame); + } else { + pr_err("%s, Error Queue limit exceeded\ + f_q = %d, e_q = %d\n", + __func__, sync->frame_q.len, + sync->event_q.len); + free_qcmd(qcmd); + } + + return; + } + + case VFE_MSG_SNAPSHOT: + if (sync->pp_mask & (PP_SNAP | PP_RAW_SNAP)) { + CDBG("%s: PP_SNAP in progress: pp_mask %x\n", + __func__, sync->pp_mask); + } else { + if (atomic_read(&qcmd->on_heap)) + atomic_add(1, &qcmd->on_heap); + CDBG("%s: VFE_MSG_SNAPSHOT store\n", + __func__); + if (sync->stereocam_enabled && + sync->stereo_state != STEREO_RAW_SNAP_STARTED) { + sync->pp_stereosnap = qcmd; + return; + } + } + break; + + case VFE_MSG_COMMON: + CDBG("%s: qtype %d, comp stats, enqueue event_q.\n", + __func__, vdata->type); + break; + + case VFE_MSG_GENERAL: + CDBG("%s: qtype %d, general msg, enqueue event_q.\n", + __func__, vdata->type); + break; + + default: + CDBG("%s: qtype %d not handled\n", __func__, vdata->type); + /* fall through, send to config. */ + } + +vfe_for_config: + CDBG("%s: msm_enqueue event_q\n", __func__); + if (sync->frame_q.len <= 100 && sync->event_q.len <= 100) { + msm_enqueue(&sync->event_q, &qcmd->list_config); + } else if (sync->event_q.len > 100) { + pr_err("%s, Error Event Queue limit exceeded f_q = %d, e_q = %d\n", + __func__, sync->frame_q.len, sync->event_q.len); + qcmd->error_code = 0xffffffff; + qcmd->command = NULL; + msm_enqueue(&sync->frame_q, &qcmd->list_frame); + } else { + pr_err("%s, Error Queue limit exceeded f_q = %d, e_q = %d\n", + __func__, sync->frame_q.len, sync->event_q.len); + free_qcmd(qcmd); + } + +} + +static void msm_vpe_sync(struct msm_vpe_resp *vdata, + enum msm_queue qtype, void *syncdata, void *ts, gfp_t gfp) +{ + struct msm_queue_cmd *qcmd = NULL; + unsigned long flags; + + struct msm_sync *sync = (struct msm_sync *)syncdata; + if (!sync) { + pr_err("%s: no context in dsp callback.\n", __func__); + return; + } + + qcmd = ((struct msm_queue_cmd *)vdata) - 1; + qcmd->type = qtype; + qcmd->command = vdata; + qcmd->ts = *((struct timespec *)ts); + + if (qtype != MSM_CAM_Q_VPE_MSG) { + pr_err("%s: Invalid qcmd type = %d.\n", __func__, qcmd->type); + free_qcmd(qcmd); + return; + } + + CDBG("%s: vdata->type %d\n", __func__, vdata->type); + switch (vdata->type) { + case VPE_MSG_OUTPUT_V: + if (sync->liveshot_enabled) { + CDBG("%s: msm_enqueue liveshot %d\n", __func__, + sync->liveshot_enabled); + vdata->phy.output_id |= OUTPUT_TYPE_L; + sync->liveshot_enabled = false; + } + if (sync->frame_q.len <= 100 && sync->event_q.len <= 100) { + CDBG("%s: enqueue to frame_q from VPE\n", __func__); + msm_enqueue(&sync->frame_q, &qcmd->list_frame); + } else { + pr_err("%s, Error Queue limit exceeded f_q = %d, " + "e_q = %d\n", __func__, sync->frame_q.len, + sync->event_q.len); + free_qcmd(qcmd); + } + return; + + case VPE_MSG_OUTPUT_ST_L: + CDBG("%s: enqueue left frame done msg to event_q from VPE\n", + __func__); + msm_enqueue(&sync->event_q, &qcmd->list_config); + return; + + case VPE_MSG_OUTPUT_ST_R: + spin_lock_irqsave(&pp_stereocam_spinlock, flags); + CDBG("%s: received VPE_MSG_OUTPUT_ST_R state %d\n", __func__, + sync->stereo_state); + + if (STEREO_SNAP_BUFFER1_PROCESSING == sync->stereo_state) { + msm_enqueue(&sync->pict_q, &qcmd->list_pict); + qcmd = sync->pp_stereocam2; + sync->pp_stereocam = sync->pp_stereocam2; + sync->pp_stereocam2 = NULL; + msm_enqueue(&sync->event_q, &qcmd->list_config); + sync->stereo_state = + STEREO_SNAP_BUFFER2_PROCESSING; + } else if (STEREO_SNAP_BUFFER2_PROCESSING == + sync->stereo_state) { + sync->stereo_state = STEREO_SNAP_IDLE; + /* Send snapshot DONE */ + msm_enqueue(&sync->pict_q, &qcmd->list_pict); + qcmd = sync->pp_stereosnap; + sync->pp_stereosnap = NULL; + CDBG("%s: send SNAPSHOT_DONE message\n", __func__); + msm_enqueue(&sync->event_q, &qcmd->list_config); + } else { + if (atomic_read(&qcmd->on_heap)) + atomic_add(1, &qcmd->on_heap); + msm_enqueue(&sync->event_q, &qcmd->list_config); + if (sync->stereo_state == STEREO_VIDEO_ACTIVE) { + CDBG("%s: st frame to frame_q from VPE\n", + __func__); + msm_enqueue(&sync->frame_q, &qcmd->list_frame); + } + } + spin_unlock_irqrestore(&pp_stereocam_spinlock, flags); + return; + + default: + pr_err("%s: qtype %d not handled\n", __func__, vdata->type); + } + pr_err("%s: Should not come here. Error.\n", __func__); +} + +static struct msm_vpe_callback msm_vpe_s = { + .vpe_resp = msm_vpe_sync, + .vpe_alloc = msm_vpe_sync_alloc, + .vpe_free = msm_vpe_sync_free, +}; + +static struct msm_vfe_callback msm_vfe_s = { + .vfe_resp = msm_vfe_sync, + .vfe_alloc = msm_vfe_sync_alloc, + .vfe_free = msm_vfe_sync_free, +}; + +static int __msm_open(struct msm_cam_device *pmsm, const char *const apps_id, + int is_controlnode) +{ + int rc = 0; + struct msm_sync *sync = pmsm->sync; + + mutex_lock(&sync->lock); + if (sync->apps_id && strcmp(sync->apps_id, apps_id) + && (!strcmp(MSM_APPS_ID_V4L2, apps_id))) { + pr_err("%s(%s): sensor %s is already opened for %s\n", + __func__, + apps_id, + sync->sdata->sensor_name, + sync->apps_id); + rc = -EBUSY; + goto msm_open_done; + } + + sync->apps_id = apps_id; + + if (!sync->core_powered_on && !is_controlnode) { + wake_lock(&sync->wake_lock); + + msm_camvfe_fn_init(&sync->vfefn, sync); + if (sync->vfefn.vfe_init) { + sync->pp_frame_avail = 0; + sync->get_pic_abort = 0; + rc = msm_camio_sensor_clk_on(sync->pdev); + if (rc < 0) { + pr_err("%s: setting sensor clocks failed: %d\n", + __func__, rc); + goto msm_open_err; + } + rc = sync->sctrl.s_init(sync->sdata); + if (rc < 0) { + pr_err("%s: sensor init failed: %d\n", + __func__, rc); + msm_camio_sensor_clk_off(sync->pdev); + goto msm_open_err; + } + rc = sync->vfefn.vfe_init(&msm_vfe_s, + sync->pdev); + if (rc < 0) { + pr_err("%s: vfe_init failed at %d\n", + __func__, rc); + sync->sctrl.s_release(); + msm_camio_sensor_clk_off(sync->pdev); + goto msm_open_err; + } + } else { + pr_err("%s: no sensor init func\n", __func__); + rc = -ENODEV; + goto msm_open_err; + } + msm_camvpe_fn_init(&sync->vpefn, sync); + + spin_lock_init(&sync->abort_pict_lock); + spin_lock_init(&pp_prev_spinlock); + spin_lock_init(&pp_stereocam_spinlock); + spin_lock_init(&st_frame_spinlock); + if (rc >= 0) { + msm_region_init(sync); + if (sync->vpefn.vpe_reg) + sync->vpefn.vpe_reg(&msm_vpe_s); + sync->unblock_poll_frame = 0; + sync->unblock_poll_pic_frame = 0; + } + sync->core_powered_on = 1; + } + sync->opencnt++; + client_for_ion = msm_ion_client_create(-1, "camera"); + +msm_open_done: + mutex_unlock(&sync->lock); + return rc; + +msm_open_err: + atomic_set(&pmsm->opened, 0); + mutex_unlock(&sync->lock); + return rc; +} + +static int msm_open_common(struct inode *inode, struct file *filep, + int once, int is_controlnode) +{ + int rc; + struct msm_cam_device *pmsm = + container_of(inode->i_cdev, struct msm_cam_device, cdev); + + CDBG("%s: open %s\n", __func__, filep->f_path.dentry->d_name.name); + + if (atomic_cmpxchg(&pmsm->opened, 0, 1) && once) { + pr_err("%s: %s is already opened.\n", + __func__, + filep->f_path.dentry->d_name.name); + return -EBUSY; + } + + rc = nonseekable_open(inode, filep); + if (rc < 0) { + pr_err("%s: nonseekable_open error %d\n", __func__, rc); + return rc; + } + + rc = __msm_open(pmsm, MSM_APPS_ID_PROP, is_controlnode); + if (rc < 0) + return rc; + filep->private_data = pmsm; + CDBG("%s: rc %d\n", __func__, rc); + return rc; +} + +static int msm_open_frame(struct inode *inode, struct file *filep) +{ + struct msm_cam_device *pmsm = + container_of(inode->i_cdev, struct msm_cam_device, cdev); + msm_queue_drain(&pmsm->sync->frame_q, list_frame); + return msm_open_common(inode, filep, 1, 0); +} + +static int msm_open(struct inode *inode, struct file *filep) +{ + return msm_open_common(inode, filep, 1, 0); +} + +static int msm_open_control(struct inode *inode, struct file *filep) +{ + int rc; + + struct msm_control_device *ctrl_pmsm = + kmalloc(sizeof(struct msm_control_device), GFP_KERNEL); + if (!ctrl_pmsm) + return -ENOMEM; + + rc = msm_open_common(inode, filep, 0, 1); + if (rc < 0) { + kfree(ctrl_pmsm); + return rc; + } + ctrl_pmsm->pmsm = filep->private_data; + filep->private_data = ctrl_pmsm; + + msm_queue_init(&ctrl_pmsm->ctrl_q, "control"); + + if (!g_v4l2_opencnt) + g_v4l2_control_device = ctrl_pmsm; + g_v4l2_opencnt++; + CDBG("%s: rc %d\n", __func__, rc); + return rc; +} + +static const struct file_operations msm_fops_config = { + .owner = THIS_MODULE, + .open = msm_open, + .unlocked_ioctl = msm_ioctl_config, + .release = msm_release_config, + .poll = msm_poll_config, +}; + +static const struct file_operations msm_fops_control = { + .owner = THIS_MODULE, + .open = msm_open_control, + .unlocked_ioctl = msm_ioctl_control, + .release = msm_release_control, +}; + +static const struct file_operations msm_fops_frame = { + .owner = THIS_MODULE, + .open = msm_open_frame, + .unlocked_ioctl = msm_ioctl_frame, + .release = msm_release_frame, + .poll = msm_poll_frame, +}; + +static const struct file_operations msm_fops_pic = { + .owner = THIS_MODULE, + .open = msm_open, + .unlocked_ioctl = msm_ioctl_pic, + .release = msm_release_pic, + .poll = msm_poll_pic, +}; + +static int msm_setup_cdev(struct msm_cam_device *msm, + int node, + dev_t devno, + const char *suffix, + const struct file_operations *fops) +{ + int rc = -ENODEV; + + struct device *device = + device_create(msm_class, NULL, + devno, NULL, + "%s%d", suffix, node); + + if (IS_ERR(device)) { + rc = PTR_ERR(device); + pr_err("%s: error creating device: %d\n", __func__, rc); + return rc; + } + + cdev_init(&msm->cdev, fops); + msm->cdev.owner = THIS_MODULE; + + rc = cdev_add(&msm->cdev, devno, 1); + if (rc < 0) { + pr_err("%s: error adding cdev: %d\n", __func__, rc); + device_destroy(msm_class, devno); + return rc; + } + + return rc; +} + +static int msm_tear_down_cdev(struct msm_cam_device *msm, dev_t devno) +{ + cdev_del(&msm->cdev); + device_destroy(msm_class, devno); + return 0; +} + +static int msm_sync_init(struct msm_sync *sync, + struct platform_device *pdev, + int (*sensor_probe)(const struct msm_camera_sensor_info *, + struct msm_sensor_ctrl *)) +{ + int rc = 0; + struct msm_sensor_ctrl sctrl; + sync->sdata = pdev->dev.platform_data; + + msm_queue_init(&sync->event_q, "event"); + msm_queue_init(&sync->frame_q, "frame"); + msm_queue_init(&sync->pict_q, "pict"); + msm_queue_init(&sync->vpe_q, "vpe"); + + wake_lock_init(&sync->wake_lock, WAKE_LOCK_IDLE, "msm_camera"); + + rc = msm_camio_probe_on(pdev); + if (rc < 0) { + wake_lock_destroy(&sync->wake_lock); + return rc; + } + rc = sensor_probe(sync->sdata, &sctrl); + if (rc >= 0) { + sync->pdev = pdev; + sync->sctrl = sctrl; + } + msm_camio_probe_off(pdev); + if (rc < 0) { + pr_err("%s: failed to initialize %s\n", + __func__, + sync->sdata->sensor_name); + wake_lock_destroy(&sync->wake_lock); + return rc; + } + + sync->opencnt = 0; + sync->core_powered_on = 0; + sync->ignore_qcmd = false; + sync->ignore_qcmd_type = -1; + mutex_init(&sync->lock); + if (sync->sdata->strobe_flash_data) { + sync->sdata->strobe_flash_data->state = 0; + spin_lock_init(&sync->sdata->strobe_flash_data->spin_lock); + } + CDBG("%s: initialized %s\n", __func__, sync->sdata->sensor_name); + return rc; +} + +static int msm_sync_destroy(struct msm_sync *sync) +{ + wake_lock_destroy(&sync->wake_lock); + return 0; +} + +static int msm_device_init(struct msm_cam_device *pmsm, + struct msm_sync *sync, + int node) +{ + int dev_num = 4 * node; + int rc = msm_setup_cdev(pmsm, node, + MKDEV(MAJOR(msm_devno), dev_num), + "control", &msm_fops_control); + if (rc < 0) { + pr_err("%s: error creating control node: %d\n", __func__, rc); + return rc; + } + + rc = msm_setup_cdev(pmsm + 1, node, + MKDEV(MAJOR(msm_devno), dev_num + 1), + "config", &msm_fops_config); + if (rc < 0) { + pr_err("%s: error creating config node: %d\n", __func__, rc); + msm_tear_down_cdev(pmsm, MKDEV(MAJOR(msm_devno), + dev_num)); + return rc; + } + + rc = msm_setup_cdev(pmsm + 2, node, + MKDEV(MAJOR(msm_devno), dev_num + 2), + "frame", &msm_fops_frame); + if (rc < 0) { + pr_err("%s: error creating frame node: %d\n", __func__, rc); + msm_tear_down_cdev(pmsm, + MKDEV(MAJOR(msm_devno), dev_num)); + msm_tear_down_cdev(pmsm + 1, + MKDEV(MAJOR(msm_devno), dev_num + 1)); + return rc; + } + + rc = msm_setup_cdev(pmsm + 3, node, + MKDEV(MAJOR(msm_devno), dev_num + 3), + "pic", &msm_fops_pic); + if (rc < 0) { + pr_err("%s: error creating pic node: %d\n", __func__, rc); + msm_tear_down_cdev(pmsm, + MKDEV(MAJOR(msm_devno), dev_num)); + msm_tear_down_cdev(pmsm + 1, + MKDEV(MAJOR(msm_devno), dev_num + 1)); + msm_tear_down_cdev(pmsm + 2, + MKDEV(MAJOR(msm_devno), dev_num + 2)); + return rc; + } + + + atomic_set(&pmsm[0].opened, 0); + atomic_set(&pmsm[1].opened, 0); + atomic_set(&pmsm[2].opened, 0); + atomic_set(&pmsm[3].opened, 0); + + pmsm[0].sync = sync; + pmsm[1].sync = sync; + pmsm[2].sync = sync; + pmsm[3].sync = sync; + + return rc; +} + +int msm_camera_drv_start(struct platform_device *dev, + int (*sensor_probe)(const struct msm_camera_sensor_info *, + struct msm_sensor_ctrl *)) +{ + struct msm_cam_device *pmsm = NULL; + struct msm_sync *sync; + int rc = -ENODEV; + + if (camera_node >= MSM_MAX_CAMERA_SENSORS) { + pr_err("%s: too many camera sensors\n", __func__); + return rc; + } + + if (!msm_class) { + /* There are three device nodes per sensor */ + rc = alloc_chrdev_region(&msm_devno, 0, + 4 * MSM_MAX_CAMERA_SENSORS, + "msm_camera"); + if (rc < 0) { + pr_err("%s: failed to allocate chrdev: %d\n", __func__, + rc); + return rc; + } + + msm_class = class_create(THIS_MODULE, "msm_camera"); + if (IS_ERR(msm_class)) { + rc = PTR_ERR(msm_class); + pr_err("%s: create device class failed: %d\n", + __func__, rc); + return rc; + } + } + + pmsm = kzalloc(sizeof(struct msm_cam_device) * 4 + + sizeof(struct msm_sync), GFP_ATOMIC); + if (!pmsm) + return -ENOMEM; + sync = (struct msm_sync *)(pmsm + 4); + + rc = msm_sync_init(sync, dev, sensor_probe); + if (rc < 0) { + kfree(pmsm); + return rc; + } + + CDBG("%s: setting camera node %d\n", __func__, camera_node); + rc = msm_device_init(pmsm, sync, camera_node); + if (rc < 0) { + msm_sync_destroy(sync); + kfree(pmsm); + return rc; + } + + camera_type[camera_node] = sync->sctrl.s_camera_type; + sensor_mount_angle[camera_node] = sync->sctrl.s_mount_angle; + camera_node++; + + list_add(&sync->list, &msm_sensors); + return rc; +} +EXPORT_SYMBOL(msm_camera_drv_start); diff --git a/drivers/media/video/msm_zsl/msm_io7x.c b/drivers/media/video/msm_zsl/msm_io7x.c new file mode 100644 index 00000000000..1befec693cb --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_io7x.c @@ -0,0 +1,318 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define CAMIF_CFG_RMSK 0x1fffff +#define CAM_SEL_BMSK 0x2 +#define CAM_PCLK_SRC_SEL_BMSK 0x60000 +#define CAM_PCLK_INVERT_BMSK 0x80000 +#define CAM_PAD_REG_SW_RESET_BMSK 0x100000 + +#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000 +#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000 +#define MDDI_CLK_CHICKEN_BIT_BMSK 0x80 + +#define CAM_SEL_SHFT 0x1 +#define CAM_PCLK_SRC_SEL_SHFT 0x11 +#define CAM_PCLK_INVERT_SHFT 0x13 +#define CAM_PAD_REG_SW_RESET_SHFT 0x14 + +#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10 +#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF +#define MDDI_CLK_CHICKEN_BIT_SHFT 0x7 +#define APPS_RESET_OFFSET 0x00000210 + +static struct clk *camio_vfe_mdc_clk; +static struct clk *camio_mdc_clk; +static struct clk *camio_vfe_clk; + +static struct msm_camera_io_ext camio_ext; +static struct resource *appio, *mdcio; +void __iomem *appbase, *mdcbase; + +static struct resource *appio, *mdcio; +void __iomem *appbase, *mdcbase; + +int msm_camio_clk_enable(enum msm_camio_clk_type clktype) +{ + int rc = -1; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_VFE_MDC_CLK: + clk = camio_vfe_mdc_clk = clk_get(NULL, "vfe_mdc_clk"); + break; + + case CAMIO_MDC_CLK: + clk = camio_mdc_clk = clk_get(NULL, "mdc_clk"); + break; + + case CAMIO_VFE_CLK: + clk = camio_vfe_clk = clk_get(NULL, "vfe_clk"); + break; + + default: + break; + } + + if (!IS_ERR(clk)) { + clk_enable(clk); + rc = 0; + } + + return rc; +} + +int msm_camio_clk_disable(enum msm_camio_clk_type clktype) +{ + int rc = -1; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_VFE_MDC_CLK: + clk = camio_vfe_mdc_clk; + break; + + case CAMIO_MDC_CLK: + clk = camio_mdc_clk; + break; + + case CAMIO_VFE_CLK: + clk = camio_vfe_clk; + break; + + default: + break; + } + + if (!IS_ERR(clk)) { + clk_disable(clk); + clk_put(clk); + rc = 0; + } + + return rc; +} + +void msm_camio_clk_rate_set(int rate) +{ + struct clk *clk = camio_vfe_clk; + + if (clk != ERR_PTR(-ENOENT)) + clk_set_rate(clk, rate); +} + +int msm_camio_enable(struct platform_device *pdev) +{ + int rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + + camio_ext = camdev->ioext; + + appio = request_mem_region(camio_ext.appphy, + camio_ext.appsz, pdev->name); + if (!appio) { + rc = -EBUSY; + goto enable_fail; + } + + appbase = ioremap(camio_ext.appphy, + camio_ext.appsz); + if (!appbase) { + rc = -ENOMEM; + goto apps_no_mem; + } + + msm_camio_clk_enable(CAMIO_VFE_CLK); + msm_camio_clk_enable(CAMIO_MDC_CLK); + return 0; +apps_no_mem: + release_mem_region(camio_ext.appphy, camio_ext.appsz); +enable_fail: + return rc; +} + +int msm_camio_sensor_clk_on(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + int32_t rc = 0; + camio_ext = camdev->ioext; + mdcio = request_mem_region(camio_ext.mdcphy, + camio_ext.mdcsz, pdev->name); + if (!mdcio) + rc = -EBUSY; + mdcbase = ioremap(camio_ext.mdcphy, + camio_ext.mdcsz); + if (!mdcbase) { + rc = -EINVAL; + goto mdc_no_mem; + } + camdev->camera_gpio_on(); + return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK); + +mdc_no_mem: + release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); + return rc; +} + +int msm_camio_sensor_clk_off(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camdev->camera_gpio_off(); + iounmap(mdcbase); + release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); + return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK); +} + +void msm_camio_disable(struct platform_device *pdev) +{ + iounmap(appbase); + release_mem_region(camio_ext.appphy, camio_ext.appsz); + msm_camio_clk_disable(CAMIO_VFE_CLK); + msm_camio_clk_disable(CAMIO_MDC_CLK); +} + +void msm_disable_io_gpio_clk(struct platform_device *pdev) +{ + return; +} + +void msm_camio_camif_pad_reg_reset(void) +{ + uint32_t reg; + uint32_t mask, value; + + /* select CLKRGM_VFE_SRC_CAM_VFE_SRC: internal source */ + msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL); + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + + mask = CAM_SEL_BMSK | + CAM_PCLK_SRC_SEL_BMSK | + CAM_PCLK_INVERT_BMSK; + + value = 1 << CAM_SEL_SHFT | + 3 << CAM_PCLK_SRC_SEL_SHFT | + 0 << CAM_PCLK_INVERT_SHFT; + + writel((reg & (~mask)) | (value & mask), mdcbase); + msleep(10); + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + mask = CAM_PAD_REG_SW_RESET_BMSK; + value = 1 << CAM_PAD_REG_SW_RESET_SHFT; + writel((reg & (~mask)) | (value & mask), mdcbase); + msleep(10); + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + mask = CAM_PAD_REG_SW_RESET_BMSK; + value = 0 << CAM_PAD_REG_SW_RESET_SHFT; + writel((reg & (~mask)) | (value & mask), mdcbase); + msleep(10); + + msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL); + msleep(10); +} + +void msm_camio_vfe_blk_reset(void) +{ + uint32_t val; + + /* do apps reset */ + val = readl(appbase + 0x00000210); + val |= 0x1; + writel(val, appbase + 0x00000210); + mdelay(10); + + val = readl(appbase + 0x00000210); + val &= ~0x1; + writel(val, appbase + 0x00000210); + mdelay(10); + + /* do axi reset */ + val = readl(appbase + 0x00000208); + val |= 0x1; + writel(val, appbase + 0x00000208); + mdelay(10); + + val = readl(appbase + 0x00000208); + val &= ~0x1; + writel(val, appbase + 0x00000208); + mdelay(10); +} + +void msm_camio_camif_pad_reg_reset_2(void) +{ + uint32_t reg; + uint32_t mask, value; + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + mask = CAM_PAD_REG_SW_RESET_BMSK; + value = 1 << CAM_PAD_REG_SW_RESET_SHFT; + writel((reg & (~mask)) | (value & mask), mdcbase); + mdelay(10); + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + mask = CAM_PAD_REG_SW_RESET_BMSK; + value = 0 << CAM_PAD_REG_SW_RESET_SHFT; + writel((reg & (~mask)) | (value & mask), mdcbase); + mdelay(10); +} + +void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype) +{ + struct clk *clk = NULL; + + clk = camio_vfe_clk; + + if (clk != NULL && clk != ERR_PTR(-ENOENT)) { + switch (srctype) { + case MSM_CAMIO_CLK_SRC_INTERNAL: + clk_set_flags(clk, 0x00000100 << 1); + break; + + case MSM_CAMIO_CLK_SRC_EXTERNAL: + clk_set_flags(clk, 0x00000100); + break; + + default: + break; + } + } +} + +int msm_camio_probe_on(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camdev->camera_gpio_on(); + return msm_camio_clk_enable(CAMIO_VFE_CLK); +} + +int msm_camio_probe_off(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camdev->camera_gpio_off(); + return msm_camio_clk_disable(CAMIO_VFE_CLK); +} diff --git a/drivers/media/video/msm_zsl/msm_io8x.c b/drivers/media/video/msm_zsl/msm_io8x.c new file mode 100644 index 00000000000..6bc92b0d7dd --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_io8x.c @@ -0,0 +1,331 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define CAMIF_CFG_RMSK 0x1fffff +#define CAM_SEL_BMSK 0x2 +#define CAM_PCLK_SRC_SEL_BMSK 0x60000 +#define CAM_PCLK_INVERT_BMSK 0x80000 +#define CAM_PAD_REG_SW_RESET_BMSK 0x100000 + +#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000 +#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000 +#define MDDI_CLK_CHICKEN_BIT_BMSK 0x80 + +#define CAM_SEL_SHFT 0x1 +#define CAM_PCLK_SRC_SEL_SHFT 0x11 +#define CAM_PCLK_INVERT_SHFT 0x13 +#define CAM_PAD_REG_SW_RESET_SHFT 0x14 + +#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10 +#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF +#define MDDI_CLK_CHICKEN_BIT_SHFT 0x7 +#define APPS_RESET_OFFSET 0x00000214 + +static struct clk *camio_vfe_mdc_clk; +static struct clk *camio_mdc_clk; +static struct clk *camio_vfe_clk; +static struct clk *camio_vfe_axi_clk; +static struct msm_camera_io_ext camio_ext; +static struct resource *appio, *mdcio; + +void __iomem *appbase, *mdcbase; + + +int msm_camio_clk_enable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_VFE_MDC_CLK: + camio_vfe_mdc_clk = clk = clk_get(NULL, "vfe_mdc_clk"); + break; + + case CAMIO_MDC_CLK: + camio_mdc_clk = clk = clk_get(NULL, "mdc_clk"); + break; + + case CAMIO_VFE_CLK: + camio_vfe_clk = clk = clk_get(NULL, "vfe_clk"); + break; + + case CAMIO_VFE_AXI_CLK: + camio_vfe_axi_clk = clk = clk_get(NULL, "vfe_axi_clk"); + break; + + default: + break; + } + + if (!IS_ERR(clk)) + clk_enable(clk); + else + rc = -1; + + return rc; +} + +int msm_camio_clk_disable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_VFE_MDC_CLK: + clk = camio_vfe_mdc_clk; + break; + + case CAMIO_MDC_CLK: + clk = camio_mdc_clk; + break; + + case CAMIO_VFE_CLK: + clk = camio_vfe_clk; + break; + + case CAMIO_VFE_AXI_CLK: + clk = camio_vfe_axi_clk; + break; + + default: + break; + } + + if (!IS_ERR(clk)) { + clk_disable(clk); + clk_put(clk); + } else + rc = -1; + + return rc; +} + +void msm_camio_clk_rate_set(int rate) +{ + struct clk *clk = camio_vfe_mdc_clk; + + /* TODO: check return */ + clk_set_rate(clk, rate); +} + +int msm_camio_enable(struct platform_device *pdev) +{ + int rc = 0; + + appio = request_mem_region(camio_ext.appphy, + camio_ext.appsz, pdev->name); + if (!appio) { + rc = -EBUSY; + goto enable_fail; + } + + appbase = ioremap(camio_ext.appphy, camio_ext.appsz); + if (!appbase) { + rc = -ENOMEM; + goto apps_no_mem; + } + msm_camio_clk_enable(CAMIO_MDC_CLK); + msm_camio_clk_enable(CAMIO_VFE_AXI_CLK); + return 0; + +apps_no_mem: + release_mem_region(camio_ext.appphy, camio_ext.appsz); +enable_fail: + return rc; +} + +void msm_camio_disable(struct platform_device *pdev) +{ + iounmap(appbase); + release_mem_region(camio_ext.appphy, camio_ext.appsz); + msm_camio_clk_disable(CAMIO_MDC_CLK); + msm_camio_clk_disable(CAMIO_VFE_AXI_CLK); +} + +int msm_camio_sensor_clk_on(struct platform_device *pdev) +{ + + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + int32_t rc = 0; + camio_ext = camdev->ioext; + + mdcio = request_mem_region(camio_ext.mdcphy, + camio_ext.mdcsz, pdev->name); + if (!mdcio) + rc = -EBUSY; + mdcbase = ioremap(camio_ext.mdcphy, + camio_ext.mdcsz); + if (!mdcbase) + goto mdc_no_mem; + camdev->camera_gpio_on(); + + msm_camio_clk_enable(CAMIO_VFE_CLK); + msm_camio_clk_enable(CAMIO_VFE_MDC_CLK); + return rc; + + +mdc_no_mem: + release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); + return -EINVAL; +} + +int msm_camio_sensor_clk_off(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camdev->camera_gpio_off(); + iounmap(mdcbase); + release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); + msm_camio_clk_disable(CAMIO_VFE_CLK); + return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK); + +} + +void msm_disable_io_gpio_clk(struct platform_device *pdev) +{ + return; +} + +void msm_camio_camif_pad_reg_reset(void) +{ + uint32_t reg; + uint32_t mask, value; + + /* select CLKRGM_VFE_SRC_CAM_VFE_SRC: internal source */ + msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL); + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + + mask = CAM_SEL_BMSK | + CAM_PCLK_SRC_SEL_BMSK | + CAM_PCLK_INVERT_BMSK | + EXT_CAM_HSYNC_POL_SEL_BMSK | + EXT_CAM_VSYNC_POL_SEL_BMSK | MDDI_CLK_CHICKEN_BIT_BMSK; + + value = 1 << CAM_SEL_SHFT | + 3 << CAM_PCLK_SRC_SEL_SHFT | + 0 << CAM_PCLK_INVERT_SHFT | + 0 << EXT_CAM_HSYNC_POL_SEL_SHFT | + 0 << EXT_CAM_VSYNC_POL_SEL_SHFT | 0 << MDDI_CLK_CHICKEN_BIT_SHFT; + writel((reg & (~mask)) | (value & mask), mdcbase); + msleep(10); + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + mask = CAM_PAD_REG_SW_RESET_BMSK; + value = 1 << CAM_PAD_REG_SW_RESET_SHFT; + writel((reg & (~mask)) | (value & mask), mdcbase); + msleep(10); + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + mask = CAM_PAD_REG_SW_RESET_BMSK; + value = 0 << CAM_PAD_REG_SW_RESET_SHFT; + writel((reg & (~mask)) | (value & mask), mdcbase); + msleep(10); + + msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL); + + msleep(10); + + /* todo: check return */ + if (camio_vfe_clk) + clk_set_rate(camio_vfe_clk, 96000000); +} + +void msm_camio_vfe_blk_reset(void) +{ + uint32_t val; + + val = readl(appbase + APPS_RESET_OFFSET); + val |= 0x1; + writel(val, appbase + APPS_RESET_OFFSET); + mdelay(10); + + val = readl(appbase + APPS_RESET_OFFSET); + val &= ~0x1; + writel(val, appbase + APPS_RESET_OFFSET); + mdelay(10); +} + +void msm_camio_camif_pad_reg_reset_2(void) +{ + uint32_t reg; + uint32_t mask, value; + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + mask = CAM_PAD_REG_SW_RESET_BMSK; + value = 1 << CAM_PAD_REG_SW_RESET_SHFT; + writel((reg & (~mask)) | (value & mask), mdcbase); + mdelay(10); + + reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; + mask = CAM_PAD_REG_SW_RESET_BMSK; + value = 0 << CAM_PAD_REG_SW_RESET_SHFT; + writel((reg & (~mask)) | (value & mask), mdcbase); + mdelay(10); +} + +void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype) +{ + struct clk *clk = NULL; + + clk = camio_vfe_clk; + + if (clk != NULL) { + switch (srctype) { + case MSM_CAMIO_CLK_SRC_INTERNAL: + clk_set_flags(clk, 0x00000100 << 1); + break; + + case MSM_CAMIO_CLK_SRC_EXTERNAL: + clk_set_flags(clk, 0x00000100); + break; + + default: + break; + } + } +} + +void msm_camio_clk_axi_rate_set(int rate) +{ + struct clk *clk = camio_vfe_axi_clk; + /* todo: check return */ + clk_set_rate(clk, rate); +} + +int msm_camio_probe_on(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + + camdev->camera_gpio_on(); + return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK); +} + +int msm_camio_probe_off(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + + camdev->camera_gpio_off(); + return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK); +} diff --git a/drivers/media/video/msm_zsl/msm_io_7x27a.c b/drivers/media/video/msm_zsl/msm_io_7x27a.c new file mode 100644 index 00000000000..7a83721ea58 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_io_7x27a.c @@ -0,0 +1,609 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* MIPI CSI controller registers */ +#define MIPI_PHY_CONTROL 0x00000000 +#define MIPI_PROTOCOL_CONTROL 0x00000004 +#define MIPI_INTERRUPT_STATUS 0x00000008 +#define MIPI_INTERRUPT_MASK 0x0000000C +#define MIPI_CAMERA_CNTL 0x00000024 +#define MIPI_CALIBRATION_CONTROL 0x00000018 +#define MIPI_PHY_D0_CONTROL2 0x00000038 +#define MIPI_PHY_D1_CONTROL2 0x0000003C +#define MIPI_PHY_D2_CONTROL2 0x00000040 +#define MIPI_PHY_D3_CONTROL2 0x00000044 +#define MIPI_PHY_CL_CONTROL 0x00000048 +#define MIPI_PHY_D0_CONTROL 0x00000034 +#define MIPI_PHY_D1_CONTROL 0x00000020 +#define MIPI_PHY_D2_CONTROL 0x0000002C +#define MIPI_PHY_D3_CONTROL 0x00000030 +#define MIPI_PWR_CNTL 0x00000054 + +/* + * MIPI_PROTOCOL_CONTROL register bits to enable/disable the features of + * CSI Rx Block + */ + +/* DPCM scheme */ +#define MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT 0x1e +/* SW_RST to issue a SW reset to the CSI core */ +#define MIPI_PROTOCOL_CONTROL_SW_RST_BMSK 0x8000000 +/* To Capture Long packet Header Info in MIPI_PROTOCOL_STATUS register */ +#define MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK 0x200000 +/* Data format for unpacking purpose */ +#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT 0x13 +/* Enable decoding of payload based on data type filed of packet hdr */ +#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x00000 +/* Enable error correction on packet headers */ +#define MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK 0x20000 + +/* + * MIPI_CALIBRATION_CONTROL register contains control info for + * calibration impledence controller +*/ + +/* Enable bit for calibration pad */ +#define MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT 0x16 +/* With SWCAL_STRENGTH_OVERRIDE_EN, SW_CAL_EN and MANUAL_OVERRIDE_EN + * the hardware calibration circuitry associated with CAL_SW_HW_MODE + * is bypassed +*/ +#define MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT 0x15 +/* To indicate the Calibration process is in the control of HW/SW */ +#define MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT 0x14 +/* When this is set the strength value of the data and clk lane impedence + * termination is updated with MANUAL_STRENGTH settings and calibration + * sensing logic is idle. +*/ +#define MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT 0x7 + +/* Data lane0 control */ +/* T-hs Settle count value for Rx */ +#define MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT 0x18 +/* Rx termination control */ +#define MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT 0x10 +/* LP Rx enable */ +#define MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT 0x4 +/* + * Enable for error in sync sequence + * 1 - one bit error in sync seq + * 0 - requires all 8 bit correct seq +*/ +#define MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 + +/* Comments are same as D0 */ +#define MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 + +/* Comments are same as D0 */ +#define MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 + +/* Comments are same as D0 */ +#define MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 + +/* PHY_CL_CTRL programs the parameters of clk lane of CSIRXPHY */ +/* HS Rx termination control */ +#define MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT 0x18 +/* Start signal for T-hs delay */ +#define MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT 0x2 + +/* PHY DATA lane 0 control */ +/* + * HS RX equalizer strength control + * 00 - 0db 01 - 3db 10 - 5db 11 - 7db +*/ +#define MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT 0x1c + +/* PHY DATA lane 1 control */ +/* Shutdown signal for MIPI clk phy line */ +#define MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT 0x9 +/* Shutdown signal for MIPI data phy line */ +#define MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT 0x8 + +#define MSM_AXI_QOS_PREVIEW 200000 +#define MSM_AXI_QOS_SNAPSHOT 200000 +#define MSM_AXI_QOS_RECORDING 200000 + +#define MIPI_PWR_CNTL_ENA 0x07 +#define MIPI_PWR_CNTL_DIS 0x0 + +static struct clk *camio_cam_clk; +static struct clk *camio_vfe_clk; +static struct clk *camio_csi_src_clk; +static struct clk *camio_csi0_vfe_clk; +static struct clk *camio_csi1_vfe_clk; +static struct clk *camio_csi0_clk; +static struct clk *camio_csi1_clk; +static struct clk *camio_csi0_pclk; +static struct clk *camio_csi1_pclk; + +static struct msm_camera_io_ext camio_ext; +static struct msm_camera_io_clk camio_clk; +static struct platform_device *camio_dev; +void __iomem *csibase; +void __iomem *appbase; + + + +void msm_io_w(u32 data, void __iomem *addr) +{ + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + writel((data), (addr)); +} + +u32 msm_io_r(void __iomem *addr) +{ + uint32_t data = readl(addr); + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + return data; +} + +int msm_camio_vfe_clk_rate_set(int rate) +{ + int rc = 0; + struct clk *clk = camio_vfe_clk; + if (rate > clk_get_rate(clk)) + rc = clk_set_rate(clk, rate); + return rc; +} + +int msm_camio_clk_enable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_CAM_MCLK_CLK: + clk = clk_get(NULL, "cam_m_clk"); + camio_cam_clk = clk; + msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate); + break; + case CAMIO_VFE_CLK: + clk = clk_get(NULL, "vfe_clk"); + camio_vfe_clk = clk; + msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate); + break; + case CAMIO_CSI0_VFE_CLK: + clk = clk_get(&camio_dev->dev, "csi_vfe_clk"); + camio_csi0_vfe_clk = clk; + break; + case CAMIO_CSI1_VFE_CLK: + clk = clk_get(NULL, "csi_vfe_clk"); + camio_csi1_vfe_clk = clk; + break; + case CAMIO_CSI_SRC_CLK: + clk = clk_get(NULL, "csi_src_clk"); + camio_csi_src_clk = clk; + break; + case CAMIO_CSI0_CLK: + clk = clk_get(&camio_dev->dev, "csi_clk"); + camio_csi0_clk = clk; + msm_camio_clk_rate_set_2(clk, 400000000); + break; + case CAMIO_CSI1_CLK: + clk = clk_get(NULL, "csi_clk"); + camio_csi1_clk = clk; + break; + case CAMIO_CSI0_PCLK: + clk = clk_get(&camio_dev->dev, "csi_pclk"); + camio_csi0_pclk = clk; + break; + case CAMIO_CSI1_PCLK: + clk = clk_get(NULL, "csi_pclk"); + camio_csi1_pclk = clk; + break; + default: + break; + } + + if (!IS_ERR(clk)) + clk_enable(clk); + else + rc = -1; + return rc; +} + +int msm_camio_clk_disable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_CAM_MCLK_CLK: + clk = camio_cam_clk; + break; + case CAMIO_VFE_CLK: + clk = camio_vfe_clk; + break; + case CAMIO_CSI_SRC_CLK: + clk = camio_csi_src_clk; + break; + case CAMIO_CSI0_VFE_CLK: + clk = camio_csi0_vfe_clk; + break; + case CAMIO_CSI1_VFE_CLK: + clk = camio_csi1_vfe_clk; + break; + case CAMIO_CSI0_CLK: + clk = camio_csi0_clk; + break; + case CAMIO_CSI1_CLK: + clk = camio_csi1_clk; + break; + case CAMIO_CSI0_PCLK: + clk = camio_csi0_pclk; + break; + case CAMIO_CSI1_PCLK: + clk = camio_csi1_pclk; + break; + default: + break; + } + + if (!IS_ERR(clk)) { + clk_disable(clk); + clk_put(clk); + } else + rc = -1; + return rc; +} + +void msm_camio_clk_rate_set(int rate) +{ + struct clk *clk = camio_cam_clk; + clk_set_rate(clk, rate); +} + +void msm_camio_clk_rate_set_2(struct clk *clk, int rate) +{ + clk_set_rate(clk, rate); +} + +static irqreturn_t msm_io_csi_irq(int irq_num, void *data) +{ + uint32_t irq; + + irq = msm_io_r(csibase + MIPI_INTERRUPT_STATUS); + CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq); + msm_io_w(irq, csibase + MIPI_INTERRUPT_STATUS); + + /* TODO: Needs to send this info to upper layers */ + if ((irq >> 19) & 0x1) + pr_info("Unsupported packet format is received\n"); + return IRQ_HANDLED; +} + +int msm_camio_enable(struct platform_device *pdev) +{ + int rc = 0; + const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + uint32_t val; + + camio_dev = pdev; + camio_ext = camdev->ioext; + camio_clk = camdev->ioclk; + + msm_camio_clk_enable(CAMIO_VFE_CLK); + msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK); + msm_camio_clk_enable(CAMIO_CSI1_VFE_CLK); + msm_camio_clk_enable(CAMIO_CSI0_CLK); + msm_camio_clk_enable(CAMIO_CSI1_CLK); + msm_camio_clk_enable(CAMIO_CSI0_PCLK); + msm_camio_clk_enable(CAMIO_CSI1_PCLK); + + csibase = ioremap(camio_ext.csiphy, camio_ext.csisz); + if (!csibase) { + rc = -ENOMEM; + goto csi_busy; + } + rc = request_irq(camio_ext.csiirq, msm_io_csi_irq, + IRQF_TRIGGER_RISING, "csi", 0); + if (rc < 0) + goto csi_irq_fail; + + msleep(20); + val = (20 << + MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) | + (0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) | + (0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) | + (0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT); + CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2); + + val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) | + (0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT); + CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL); + + appbase = ioremap(camio_ext.appphy, + camio_ext.appsz); + if (!appbase) { + rc = -ENOMEM; + goto csi_irq_fail; + } + return 0; + +csi_irq_fail: + iounmap(csibase); +csi_busy: + msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); + msm_camio_clk_disable(CAMIO_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI0_CLK); + msm_camio_clk_disable(CAMIO_CSI1_CLK); + msm_camio_clk_disable(CAMIO_CSI0_PCLK); + msm_camio_clk_disable(CAMIO_CSI1_PCLK); + camdev->camera_gpio_off(); + return rc; +} + +void msm_camio_disable(struct platform_device *pdev) +{ + uint32_t val; + + val = (20 << + MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) | + (0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) | + (0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) | + (0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT); + CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2); + + val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) | + (0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT); + CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL); + msleep(20); + + free_irq(camio_ext.csiirq, 0); + iounmap(csibase); + iounmap(appbase); + CDBG("disable clocks\n"); + + msm_camio_clk_disable(CAMIO_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI0_CLK); + msm_camio_clk_disable(CAMIO_CSI1_CLK); + msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI0_PCLK); + msm_camio_clk_disable(CAMIO_CSI1_PCLK); +} + +int msm_camio_sensor_clk_on(struct platform_device *pdev) +{ + int rc = 0; + const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camio_dev = pdev; + camio_ext = camdev->ioext; + camio_clk = camdev->ioclk; + + rc = camdev->camera_gpio_on(); + if (rc < 0) + return rc; + return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK); +} + +int msm_camio_sensor_clk_off(struct platform_device *pdev) +{ + const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camdev->camera_gpio_off(); + return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); + +} + +void msm_camio_vfe_blk_reset(void) +{ + uint32_t val; + + /* do apps reset */ + val = readl_relaxed(appbase + 0x00000210); + val |= 0x1; + writel_relaxed(val, appbase + 0x00000210); + usleep_range(10000, 11000); + + val = readl_relaxed(appbase + 0x00000210); + val &= ~0x1; + writel_relaxed(val, appbase + 0x00000210); + usleep_range(10000, 11000); + + /* do axi reset */ + val = readl_relaxed(appbase + 0x00000208); + val |= 0x1; + writel_relaxed(val, appbase + 0x00000208); + usleep_range(10000, 11000); + + val = readl_relaxed(appbase + 0x00000208); + val &= ~0x1; + writel_relaxed(val, appbase + 0x00000208); + mb(); + usleep_range(10000, 11000); + return; +} + +int msm_camio_probe_on(struct platform_device *pdev) +{ + int rc = 0; + const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camio_dev = pdev; + camio_ext = camdev->ioext; + camio_clk = camdev->ioclk; + + msm_camio_clk_enable(CAMIO_CSI0_PCLK); + msm_camio_clk_enable(CAMIO_CSI1_PCLK); + + rc = camdev->camera_gpio_on(); + if (rc < 0) + return rc; + return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK); +} + +int msm_camio_probe_off(struct platform_device *pdev) +{ + const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camdev->camera_gpio_off(); + + csibase = ioremap(camdev->ioext.csiphy, camdev->ioext.csisz); + if (!csibase) { + pr_err("ioremap failed for CSIBASE\n"); + goto ioremap_fail; + } + msm_io_w(MIPI_PWR_CNTL_DIS, csibase + MIPI_PWR_CNTL); + iounmap(csibase); +ioremap_fail: + msm_camio_clk_disable(CAMIO_CSI0_PCLK); + msm_camio_clk_disable(CAMIO_CSI1_PCLK); + return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); +} + +int msm_camio_csi_config(struct msm_camera_csi_params *csi_params) +{ + int rc = 0; + uint32_t val = 0; + + CDBG("msm_camio_csi_config\n"); + + /* Enable error correction for DATA lane. Applies to all data lanes */ + msm_io_w(0x4, csibase + MIPI_PHY_CONTROL); + + msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK, + csibase + MIPI_PROTOCOL_CONTROL); + + val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK | + MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK | + MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK; + val |= (uint32_t)(csi_params->data_format) << + MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT; + val |= csi_params->dpcm_scheme << + MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT; + CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PROTOCOL_CONTROL); + + val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) | + (0x1 << + MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) | + (0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) | + (0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT); + CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_CALIBRATION_CONTROL); + + val = (csi_params->settle_cnt << + MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) | + (0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) | + (0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) | + (0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT); + CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2); + + + val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) | + (0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT); + CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL); + + val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT; + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL); + + val = (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) | + (0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT); + CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL); + + msm_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL); + msm_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL); + + /* program number of lanes and lane mapping */ + switch (csi_params->lane_cnt) { + case 1: + msm_io_w(csi_params->lane_assign << 8 | 0x4, + csibase + MIPI_CAMERA_CNTL); + break; + case 2: + msm_io_w(csi_params->lane_assign << 8 | 0x5, + csibase + MIPI_CAMERA_CNTL); + break; + case 3: + msm_io_w(csi_params->lane_assign << 8 | 0x6, + csibase + MIPI_CAMERA_CNTL); + break; + case 4: + msm_io_w(csi_params->lane_assign << 8 | 0x7, + csibase + MIPI_CAMERA_CNTL); + break; + } + + msm_io_w(0xFFFFF3FF, csibase + MIPI_INTERRUPT_MASK); + /*clear IRQ bits - write 1 clears the status*/ + msm_io_w(0xFFFFF3FF, csibase + MIPI_INTERRUPT_STATUS); + + return rc; +} + +void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting) +{ + switch (perf_setting) { + case S_INIT: + add_axi_qos(); + break; + case S_PREVIEW: + update_axi_qos(MSM_AXI_QOS_PREVIEW); + break; + case S_VIDEO: + update_axi_qos(MSM_AXI_QOS_RECORDING); + break; + case S_CAPTURE: + update_axi_qos(MSM_AXI_QOS_SNAPSHOT); + break; + case S_DEFAULT: + update_axi_qos(PM_QOS_DEFAULT_VALUE); + break; + case S_EXIT: + release_axi_qos(); + break; + default: + CDBG("%s: INVALID CASE\n", __func__); + } +} diff --git a/drivers/media/video/msm_zsl/msm_io_8960.c b/drivers/media/video/msm_zsl/msm_io_8960.c new file mode 100644 index 00000000000..2f9648c43b2 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_io_8960.c @@ -0,0 +1,871 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFF_SIZE_128 128 + +#define CAM_VAF_MINUV 2800000 +#define CAM_VAF_MAXUV 2800000 +#define CAM_VDIG_MINUV 1200000 +#define CAM_VDIG_MAXUV 1200000 +#define CAM_VANA_MINUV 2800000 +#define CAM_VANA_MAXUV 2850000 +#define CAM_CSI_VDD_MINUV 1200000 +#define CAM_CSI_VDD_MAXUV 1200000 + +#define CAM_VAF_LOAD_UA 300000 +#define CAM_VDIG_LOAD_UA 105000 +#define CAM_VANA_LOAD_UA 85600 +#define CAM_CSI_LOAD_UA 20000 + +static struct clk *camio_cam_clk; + +static struct clk *camio_jpeg_clk; +static struct clk *camio_jpeg_pclk; +static struct regulator *fs_ijpeg; +#ifndef CONFIG_S5C73M3 +static struct regulator *cam_vana; +static struct regulator *cam_vio; +static struct regulator *cam_vdig; +static struct regulator *cam_vaf; +static struct regulator *mipi_csi_vdd; +#endif +static struct msm_camera_io_clk camio_clk; +static struct platform_device *camio_dev; +static struct resource *s3drw_io, *s3dctl_io; +static struct resource *s3drw_mem, *s3dctl_mem; +void __iomem *s3d_rw, *s3d_ctl; +struct msm_bus_scale_pdata *cam_bus_scale_table; + +void msm_io_setBits(void __iomem *addr, int offset, int bitmask) +{ + uint32_t value = 0; + value = msm_io_r(addr + offset); +// CDBG("%s: Writing %x at (%x + %x), New value = %x\n", +// __func__, bitmask, addr, offset, value | bitmask); + msm_io_w(value | bitmask , addr + offset); +} + +void msm_io_w(u32 data, void __iomem *addr) +{ + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + writel_relaxed((data), (addr)); +} + +void msm_io_w_mb(u32 data, void __iomem *addr) +{ + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + wmb(); + writel_relaxed((data), (addr)); + wmb(); +} + +u32 msm_io_r(void __iomem *addr) +{ + uint32_t data = readl_relaxed(addr); + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + return data; +} + +u32 msm_io_r_mb(void __iomem *addr) +{ + uint32_t data; + rmb(); + data = readl_relaxed(addr); + rmb(); + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + return data; +} + +void msm_io_memcpy_toio(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + int i; + u32 *d = (u32 *) dest_addr; + u32 *s = (u32 *) src_addr; + /* memcpy_toio does not work. Use writel_relaxed for now */ + for (i = 0; i < len; i++) + writel_relaxed(*s++, d++); +} + +void msm_io_dump1(void __iomem *addr, int size) +{ + char line_str[BUFF_SIZE_128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + CDBG("%s: %p %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "%08x: ", (u32) p); + p_str += 10; + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + CDBG("nishu %s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CDBG("nishu %s\n", line_str); +} + +void msm_io_dump(void __iomem *addr, int size) +{ + char line_str[BUFF_SIZE_128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + CDBG("%s: %p %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "%08x: ", (u32) p); + p_str += 10; + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + CDBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CDBG("%s\n", line_str); +} + +void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len) +{ + CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len); + msm_io_memcpy_toio(dest_addr, src_addr, len / 4); + msm_io_dump(dest_addr, len); +} +#ifndef CONFIG_S5C73M3 +static int msm_camera_vreg_enable(struct platform_device *pdev) +{ + if (mipi_csi_vdd == NULL) { + mipi_csi_vdd = regulator_get(&pdev->dev, "mipi_csi_vdd"); + if (IS_ERR(mipi_csi_vdd)) { + CDBG("%s: VREG MIPI CSI VDD get failed\n", __func__); + mipi_csi_vdd = NULL; + return -ENODEV; + } + if (regulator_set_voltage(mipi_csi_vdd, CAM_CSI_VDD_MINUV, + CAM_CSI_VDD_MAXUV)) { + CDBG("%s: VREG MIPI CSI VDD set voltage failed\n", + __func__); + goto mipi_csi_vdd_put; + } + if (regulator_set_optimum_mode(mipi_csi_vdd, + CAM_CSI_LOAD_UA) < 0) { + CDBG("%s: VREG MIPI CSI set optimum mode failed\n", + __func__); + goto mipi_csi_vdd_release; + } + if (regulator_enable(mipi_csi_vdd)) { + CDBG("%s: VREG MIPI CSI VDD enable failed\n", + __func__); + goto mipi_csi_vdd_disable; + } + } +#ifndef CONFIG_S5C73M3 + CDBG("%s : XXX\n", __func__); + + if (cam_vana == NULL) { + cam_vana = regulator_get(&pdev->dev, "cam_vana"); + if (IS_ERR(cam_vana)) { + CDBG("%s: VREG CAM VANA get failed\n", __func__); + cam_vana = NULL; + goto mipi_csi_vdd_disable; + } + if (regulator_set_voltage(cam_vana, CAM_VANA_MINUV, + CAM_VANA_MAXUV)) { + CDBG("%s: VREG CAM VANA set voltage failed\n", + __func__); + goto cam_vana_put; + } + if (regulator_set_optimum_mode(cam_vana, + CAM_VANA_LOAD_UA) < 0) { + CDBG("%s: VREG CAM VANA set optimum mode failed\n", + __func__); + goto cam_vana_release; + } + if (regulator_enable(cam_vana)) { + CDBG("%s: VREG CAM VANA enable failed\n", __func__); + goto cam_vana_disable; + } + } + if (system_rev <= 1) { + if (cam_vio == NULL) { + cam_vio = regulator_get(&pdev->dev, "cam_vio"); + if (IS_ERR(cam_vio)) { + CDBG("%s: VREG VIO get failed\n", __func__); + cam_vio = NULL; + goto mipi_csi_vdd_disable; + } + if (regulator_set_voltage(cam_vio, 1800000, + 1800000)) { + CDBG("%s: VREG VIO set voltage failed\n", + __func__); + goto cam_vio_put; + } + if (regulator_enable(cam_vio)) { + CDBG("%s: VREG VIO enable failed\n", __func__); + goto cam_vio_put; + } + } + if (cam_vdig == NULL) { + cam_vdig = regulator_get(&pdev->dev, "cam_vdig"); + if (IS_ERR(cam_vdig)) { + CDBG("CAM VDIG get failed\n"); + cam_vdig = NULL; + goto cam_vio_disable; + } + if (regulator_set_voltage(cam_vdig, CAM_VDIG_MINUV, + CAM_VDIG_MAXUV)) { + CDBG("CAM VDIG set voltage failed\n"); + goto cam_vdig_put; + } + if (regulator_set_optimum_mode(cam_vdig, + CAM_VDIG_LOAD_UA) < 0) { + CDBG("CAM VDIG set optimum mode failed\n"); + goto cam_vdig_release; + } + if (regulator_enable(cam_vdig)) { + CDBG("CAM VDIG enable failed\n"); + goto cam_vdig_disable; + } + } + } else { + if (cam_vdig == NULL) { + cam_vdig = regulator_get(&pdev->dev, "cam_vdig"); + if (IS_ERR(cam_vdig)) { + CDBG("CAM VDIG get failed\n"); + cam_vdig = NULL; + goto mipi_csi_vdd_disable; + } + if (regulator_set_voltage(cam_vdig, CAM_VDIG_MINUV, + CAM_VDIG_MAXUV)) { + CDBG("CAM VDIG set voltage failed\n"); + goto cam_vdig_put; + } + if (regulator_set_optimum_mode(cam_vdig, + CAM_VDIG_LOAD_UA) < 0) { + CDBG("%s: VREG CAM VDIG set optimum" + " mode failed\n", + __func__); + goto cam_vdig_release; + } + if (regulator_enable(cam_vdig)) { + CDBG("%s: VREG CAM VDIG enable failed\n", + __func__); + goto cam_vdig_disable; + } + } + } + if (cam_vaf == NULL) { + cam_vaf = regulator_get(&pdev->dev, "cam_vaf"); + if (IS_ERR(cam_vaf)) { + CDBG("%s: VREG CAM VAF get failed\n", __func__); + cam_vaf = NULL; + goto cam_vdig_disable; + } + if (regulator_set_voltage(cam_vaf, CAM_VAF_MINUV, + CAM_VAF_MAXUV)) { + CDBG("%s: VREG CAM VAF set voltage failed\n", + __func__); + goto cam_vaf_put; + } + if (regulator_set_optimum_mode(cam_vaf, + CAM_VAF_LOAD_UA) < 0) { + CDBG("%s: VREG CAM VAF set optimum mode failed\n", + __func__); + goto cam_vaf_release; + } + if (regulator_enable(cam_vaf)) { + CDBG("%s: VREG CAM VAF enable failed\n", __func__); + goto cam_vaf_disable; + } + } +#endif + return 0; + +#ifndef CONFIG_S5C73M3 +cam_vaf_disable: + regulator_set_optimum_mode(cam_vaf, 0); +cam_vaf_release: + regulator_set_voltage(cam_vaf, 0, CAM_VAF_MAXUV); + regulator_disable(cam_vaf); + +cam_vaf_put: + regulator_put(cam_vaf); + cam_vaf = NULL; +cam_vdig_disable: + regulator_set_optimum_mode(cam_vdig, 0); +cam_vdig_release: + regulator_set_voltage(cam_vdig, 0, CAM_VDIG_MAXUV); + regulator_disable(cam_vdig); +cam_vdig_put: +#endif + regulator_put(cam_vdig); + cam_vdig = NULL; +#ifndef CONFIG_S5C73M3 +cam_vio_disable: +#endif + regulator_disable(cam_vio); +#ifndef CONFIG_S5C73M3 +cam_vio_put: +#endif + regulator_put(cam_vio); + cam_vio = NULL; +#ifndef CONFIG_S5C73M3 +cam_vana_disable: +#endif + regulator_set_optimum_mode(cam_vana, 0); +#ifndef CONFIG_S5C73M3 +cam_vana_release: +#endif + regulator_set_voltage(cam_vana, 0, CAM_VANA_MAXUV); + regulator_disable(cam_vana); +#ifndef CONFIG_S5C73M3 +cam_vana_put: +#endif + regulator_put(cam_vana); + cam_vana = NULL; +mipi_csi_vdd_disable: + regulator_set_optimum_mode(mipi_csi_vdd, 0); +mipi_csi_vdd_release: + regulator_set_voltage(mipi_csi_vdd, 0, CAM_CSI_VDD_MAXUV); + regulator_disable(mipi_csi_vdd); + +mipi_csi_vdd_put: + regulator_put(mipi_csi_vdd); + mipi_csi_vdd = NULL; + return -ENODEV; +} +#endif +#ifndef CONFIG_S5C73M3 +static void msm_camera_vreg_disable(void) +{ + if (mipi_csi_vdd) { + regulator_set_voltage(mipi_csi_vdd, 0, CAM_CSI_VDD_MAXUV); + regulator_set_optimum_mode(mipi_csi_vdd, 0); + regulator_disable(mipi_csi_vdd); + regulator_put(mipi_csi_vdd); + mipi_csi_vdd = NULL; + } + + if (cam_vana) { + regulator_set_voltage(cam_vana, 0, CAM_VANA_MAXUV); + regulator_set_optimum_mode(cam_vana, 0); + regulator_disable(cam_vana); + regulator_put(cam_vana); + cam_vana = NULL; + } + + if (cam_vio) { + regulator_set_voltage(cam_vio, 0, 1800000); + regulator_disable(cam_vio); + regulator_put(cam_vio); + cam_vio = NULL; + } + + if (cam_vdig) { + regulator_set_voltage(cam_vdig, 0, CAM_VDIG_MAXUV); + regulator_set_optimum_mode(cam_vdig, 0); + regulator_disable(cam_vdig); + regulator_put(cam_vdig); + cam_vdig = NULL; + } + + if (cam_vaf) { + regulator_set_voltage(cam_vaf, 0, CAM_VAF_MAXUV); + regulator_set_optimum_mode(cam_vaf, 0); + regulator_disable(cam_vaf); + regulator_put(cam_vaf); + cam_vaf = NULL; + } +} +#endif +int msm_camio_clk_enable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_CAM_MCLK_CLK: + camio_cam_clk = + clk = clk_get(&camio_dev->dev, "cam_clk"); + msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate); + break; + + case CAMIO_JPEG_CLK: + camio_jpeg_clk = + clk = clk_get(NULL, "ijpeg_clk"); + clk_set_rate(clk, 153600000); + break; + + case CAMIO_JPEG_PCLK: + camio_jpeg_pclk = + clk = clk_get(NULL, "ijpeg_pclk"); + break; + + default: + break; + } + + if (!IS_ERR(clk)) + rc = clk_prepare_enable(clk); + else + rc = PTR_ERR(clk); + + if (rc < 0) + pr_err("%s(%d) failed %d\n", __func__, clktype, rc); + + return rc; +} + +int msm_camio_clk_disable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_CAM_MCLK_CLK: + clk = camio_cam_clk; + break; + + case CAMIO_JPEG_CLK: + clk = camio_jpeg_clk; + break; + + case CAMIO_JPEG_PCLK: + clk = camio_jpeg_pclk; + break; + + default: + break; + } + + if (!IS_ERR(clk)) { + clk_disable_unprepare(clk); + clk_put(clk); + } else + rc = PTR_ERR(clk); + + if (rc < 0) + pr_err("%s(%d) failed %d\n", __func__, clktype, rc); + + return rc; +} + +void msm_camio_clk_rate_set(int rate) +{ + struct clk *clk = camio_cam_clk; + clk_set_rate(clk, rate); +} + +void msm_camio_clk_rate_set_2(struct clk *clk, int rate) +{ + clk_set_rate(clk, rate); +} + +int msm_camio_jpeg_clk_disable(void) +{ + int rc = 0; + if (fs_ijpeg) { + rc = regulator_disable(fs_ijpeg); + if (rc < 0) { + pr_err("%s: Regulator disable failed %d\n", + __func__, rc); + return rc; + } + regulator_put(fs_ijpeg); + } + rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK); + if (rc < 0) + return rc; + rc = msm_camio_clk_disable(CAMIO_JPEG_CLK); + CDBG("%s: exit %d\n", __func__, rc); + return rc; +} + +int msm_camio_jpeg_clk_enable(void) +{ + int rc = 0; + rc = msm_camio_clk_enable(CAMIO_JPEG_CLK); + if (rc < 0) + return rc; + rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK); + if (rc < 0) + return rc; + fs_ijpeg = regulator_get(NULL, "fs_ijpeg"); + if (IS_ERR(fs_ijpeg)) { + pr_err("%s: Regulator FS_IJPEG get failed %ld\n", + __func__, PTR_ERR(fs_ijpeg)); + fs_ijpeg = NULL; + } else if (regulator_enable(fs_ijpeg)) { + pr_err("%s: Regulator FS_IJPEG enable failed\n", __func__); + regulator_put(fs_ijpeg); + } + CDBG("%s: exit %d\n", __func__, rc); + return rc; +} + +static int config_gpio_table(int gpio_en) +{ + struct msm_camera_sensor_info *sinfo = camio_dev->dev.platform_data; + struct msm_camera_gpio_conf *gpio_conf = sinfo->gpio_conf; + int rc = 0, i = 0; + + if (gpio_conf->cam_gpio_tbl == NULL || gpio_conf->cam_gpiomux_conf_tbl + == NULL) { + pr_err("%s: Invalid NULL cam gpio config table\n", __func__); + return -EFAULT; + } + + if (gpio_en) { + msm_gpiomux_install((struct msm_gpiomux_config *)gpio_conf-> + cam_gpiomux_conf_tbl, + gpio_conf->cam_gpiomux_conf_tbl_size); + for (i = 0; i < gpio_conf->cam_gpio_tbl_size; i++) { + rc = gpio_request(gpio_conf->cam_gpio_tbl[i], + "CAM_GPIO"); + if (rc < 0) { + pr_err("%s not able to get gpio\n", __func__); + for (i--; i >= 0; i--) + gpio_free(gpio_conf->cam_gpio_tbl[i]); + break; + } + } + } else { + for (i = 0; i < gpio_conf->cam_gpio_tbl_size; i++) + gpio_free(gpio_conf->cam_gpio_tbl[i]); + } + return rc; +} + +int32_t msm_camio_3d_enable(const struct msm_camera_sensor_info *s_info) +{ + int32_t val = 0, rc = 0; + char s3drw[] = "s3d_rw"; + char s3dctl[] = "s3d_ctl"; + struct platform_device *pdev = camio_dev; + pdev->resource = s_info->resource; + pdev->num_resources = s_info->num_resources; + + s3drw_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, s3drw); + if (!s3drw_mem) { + pr_err("%s: no mem resource?\n", __func__); + return -ENODEV; + } + s3dctl_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, s3dctl); + if (!s3dctl_mem) { + pr_err("%s: no mem resource?\n", __func__); + return -ENODEV; + } + s3drw_io = request_mem_region(s3drw_mem->start, + resource_size(s3drw_mem), pdev->name); + if (!s3drw_io) + return -EBUSY; + + s3d_rw = ioremap(s3drw_mem->start, + resource_size(s3drw_mem)); + if (!s3d_rw) { + rc = -ENOMEM; + goto s3drw_nomem; + } + s3dctl_io = request_mem_region(s3dctl_mem->start, + resource_size(s3dctl_mem), pdev->name); + if (!s3dctl_io) { + rc = -EBUSY; + goto s3dctl_busy; + } + s3d_ctl = ioremap(s3dctl_mem->start, + resource_size(s3dctl_mem)); + if (!s3d_ctl) { + rc = -ENOMEM; + goto s3dctl_nomem; + } + + val = msm_io_r(s3d_rw); + msm_io_w((val | 0x200), s3d_rw); + return rc; + +s3dctl_nomem: + release_mem_region(s3dctl_mem->start, resource_size(s3dctl_mem)); +s3dctl_busy: + iounmap(s3d_rw); +s3drw_nomem: + release_mem_region(s3drw_mem->start, resource_size(s3drw_mem)); +return rc; +} + +void msm_camio_3d_disable(void) +{ + int32_t val = 0; + msm_io_w((val & ~0x200), s3d_rw); + iounmap(s3d_ctl); + release_mem_region(s3dctl_mem->start, resource_size(s3dctl_mem)); + iounmap(s3d_rw); + release_mem_region(s3drw_mem->start, resource_size(s3drw_mem)); +} +#if 0 +static struct pm8xxx_mpp_config_data privacy_light_on_config = { + .type = PM8XXX_MPP_TYPE_SINK, + .level = PM8XXX_MPP_CS_OUT_5MA, + .control = PM8XXX_MPP_CS_CTRL_MPP_LOW_EN, +}; + +static struct pm8xxx_mpp_config_data privacy_light_off_config = { + .type = PM8XXX_MPP_TYPE_SINK, + .level = PM8XXX_MPP_CS_OUT_5MA, + .control = PM8XXX_MPP_CS_CTRL_DISABLE, +}; +#endif +int msm_camio_sensor_clk_on(struct platform_device *pdev) +{ + int rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) + char *front_cam = "s5k6a3yx"; +#endif + camio_dev = pdev; + camio_clk = camdev->ioclk; + rc = config_gpio_table(1); + if (rc < 0) { + pr_err("%s : retry gpio setting\n", __func__); + rc = config_gpio_table(1); + if (rc < 0) { + pr_err("%s : error gpio setting\n", __func__); + return rc; + } + } + +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) + if (!strcmp(sinfo->sensor_name, front_cam)) + sinfo->sensor_platform_info->sensor_power_on(1, 0); + else + sinfo->sensor_platform_info->sensor_power_on(0, 0); +#endif + + msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK); + usleep(1*1000); + +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) + if (!strcmp(sinfo->sensor_name, front_cam)) + sinfo->sensor_platform_info->sensor_power_on(1, 1); + else + sinfo->sensor_platform_info->sensor_power_on(0, 1); +#else + msm_camera_vreg_enable(pdev); +#endif + if (sinfo->sensor_platform_info->privacy_light) { +// struct msm8960_privacy_light_cfg *privacy_light_config = +// sinfo->sensor_platform_info->privacy_light_info; + /* UPDATE1031_CAM_TEMP */ + /*pm8xxx_mpp_config(privacy_light_config->mpp, + &privacy_light_on_config);*/ + } + msleep(20); + return 0; +} + +int msm_camio_sensor_clk_off(struct platform_device *pdev) +{ + int rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) + char *front_cam = "s5k6a3yx"; +#endif + +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) + if (!strcmp(sinfo->sensor_name, front_cam)) + sinfo->sensor_platform_info->sensor_power_off(1); + else + sinfo->sensor_platform_info->sensor_power_off(0); +#else + msm_camera_vreg_disable(); +#endif + if (sinfo->sensor_platform_info->privacy_light) { +// struct msm8960_privacy_light_cfg *privacy_light_config = +// sinfo->sensor_platform_info->privacy_light_info; + /* UPDATE1031_CAM_TEMP */ + /*pm8xxx_mpp_config(privacy_light_config->mpp, + &privacy_light_off_config);*/ + } + rc = config_gpio_table(0); + if (rc < 0) + return rc; + return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); +} + +void msm_camio_vfe_blk_reset(void) +{ + return; +} + +int msm_camio_probe_on(struct platform_device *pdev) +{ + int rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) + char *front_cam = "s5k6a3yx"; +#endif + camio_dev = pdev; + camio_clk = camdev->ioclk; + + rc = config_gpio_table(1); + if (rc < 0) + return rc; +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) + if (!strcmp(sinfo->sensor_name, front_cam)) { + sinfo->sensor_platform_info->sensor_power_on(1, 0); + sinfo->sensor_platform_info->sensor_power_on(1, 1); + } else { + sinfo->sensor_platform_info->sensor_power_on(0, 0); + sinfo->sensor_platform_info->sensor_power_on(0, 1); + } +#else + msm_camera_vreg_enable(pdev); +#endif + + return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK); +} + +int msm_camio_probe_off(struct platform_device *pdev) +{ + int rc = 0; +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + char *front_cam = "s5k6a3yx"; +#endif + +#if defined(CONFIG_S5C73M3) || defined(CONFIG_S5K6A3YX) + if (!strcmp(sinfo->sensor_name, front_cam)) + sinfo->sensor_platform_info->sensor_power_off(1); + else + sinfo->sensor_platform_info->sensor_power_off(0); +#else + msm_camera_vreg_disable(); +#endif + rc = config_gpio_table(0); + if (rc < 0) + return rc; + return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); +} + +void msm_camio_mode_config(enum msm_cam_mode mode) +{ + uint32_t val; + val = msm_io_r(s3d_ctl); + if (mode == MODE_DUAL) { + msm_io_w(val | 0x3, s3d_ctl); + } else if (mode == MODE_L) { + msm_io_w(((val | 0x2) & ~(0x1)), s3d_ctl); + val = msm_io_r(s3d_ctl); + CDBG("the camio mode config left value is %d\n", val); + } else { + msm_io_w(((val | 0x1) & ~(0x2)), s3d_ctl); + val = msm_io_r(s3d_ctl); + CDBG("the camio mode config right value is %d\n", val); + } +} + +void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting) +{ + static uint32_t bus_perf_client; + struct msm_camera_sensor_info *sinfo = camio_dev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + + int rc = 0; + switch (perf_setting) { + case S_INIT: + cam_bus_scale_table = camdev->cam_bus_scale_table; + bus_perf_client = + msm_bus_scale_register_client(cam_bus_scale_table); + if (!bus_perf_client) { + CDBG("%s: Registration Failed!!!\n", __func__); + bus_perf_client = 0; + return; + } + CDBG("%s: S_INIT rc = %u\n", __func__, bus_perf_client); + break; + case S_EXIT: + if (bus_perf_client) { + CDBG("%s: S_EXIT\n", __func__); + msm_bus_scale_unregister_client(bus_perf_client); + } else + CDBG("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_PREVIEW: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 1); + CDBG("%s: S_PREVIEW rc = %d\n", __func__, rc); + } else + CDBG("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_VIDEO: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 2); + CDBG("%s: S_VIDEO rc = %d\n", __func__, rc); + } else + CDBG("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_CAPTURE: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 3); + CDBG("%s: S_CAPTURE rc = %d\n", __func__, rc); + } else + CDBG("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_ZSL: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 4); + CDBG("%s: S_ZSL rc = %d\n", __func__, rc); + } else + CDBG("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_DEFAULT: + break; + default: + pr_warning("%s: INVALID CASE\n", __func__); + } +} diff --git a/drivers/media/video/msm_zsl/msm_io_8x60.c b/drivers/media/video/msm_zsl/msm_io_8x60.c new file mode 100644 index 00000000000..ec43c4ed238 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_io_8x60.c @@ -0,0 +1,891 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* MIPI CSI controller registers */ +#define MIPI_PHY_CONTROL 0x00000000 +#define MIPI_PROTOCOL_CONTROL 0x00000004 +#define MIPI_INTERRUPT_STATUS 0x00000008 +#define MIPI_INTERRUPT_MASK 0x0000000C +#define MIPI_CAMERA_CNTL 0x00000024 +#define MIPI_CALIBRATION_CONTROL 0x00000018 +#define MIPI_PHY_D0_CONTROL2 0x00000038 +#define MIPI_PHY_D1_CONTROL2 0x0000003C +#define MIPI_PHY_D2_CONTROL2 0x00000040 +#define MIPI_PHY_D3_CONTROL2 0x00000044 +#define MIPI_PHY_CL_CONTROL 0x00000048 +#define MIPI_PHY_D0_CONTROL 0x00000034 +#define MIPI_PHY_D1_CONTROL 0x00000020 +#define MIPI_PHY_D2_CONTROL 0x0000002C +#define MIPI_PHY_D3_CONTROL 0x00000030 +#define MIPI_PROTOCOL_CONTROL_SW_RST_BMSK 0x8000000 +#define MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK 0x200000 +#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_BMSK 0x180000 +#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x40000 +#define MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK 0x20000 +#define MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT 0x16 +#define MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT 0x15 +#define MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT 0x14 +#define MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT 0x7 +#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT 0x13 +#define MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT 0x1e +#define MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 +#define MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 +#define MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 +#define MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 +#define MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT 0x18 +#define MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT 0x2 +#define MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT 0x1c +#define MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT 0x9 +#define MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT 0x8 +#define DBG_CSI 0 + +static struct clk *camio_cam_clk; +static struct clk *camio_vfe_clk; +static struct clk *camio_csi_src_clk; +static struct clk *camio_csi0_vfe_clk; +static struct clk *camio_csi1_vfe_clk; +static struct clk *camio_csi0_clk; +static struct clk *camio_csi1_clk; +static struct clk *camio_csi0_pclk; +static struct clk *camio_csi1_pclk; +static struct clk *camio_vfe_pclk; +static struct clk *camio_jpeg_clk; +static struct clk *camio_jpeg_pclk; +static struct clk *camio_vpe_clk; +static struct clk *camio_vpe_pclk; +static struct regulator *fs_vfe; +static struct regulator *fs_ijpeg; +static struct regulator *fs_vpe; +static struct regulator *ldo15; +static struct regulator *lvs0; +static struct regulator *ldo25; + +static struct msm_camera_io_ext camio_ext; +static struct msm_camera_io_clk camio_clk; +static struct platform_device *camio_dev; +static struct resource *csiio; +void __iomem *csibase; +static int vpe_clk_rate; +struct msm_bus_scale_pdata *cam_bus_scale_table; + +void msm_io_w(u32 data, void __iomem *addr) +{ + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + writel_relaxed((data), (addr)); +} + +void msm_io_w_mb(u32 data, void __iomem *addr) +{ + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + wmb(); + writel_relaxed((data), (addr)); + wmb(); +} + +u32 msm_io_r(void __iomem *addr) +{ + uint32_t data = readl_relaxed(addr); + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + return data; +} + +u32 msm_io_r_mb(void __iomem *addr) +{ + uint32_t data; + rmb(); + data = readl_relaxed(addr); + rmb(); + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + return data; +} + +void msm_io_memcpy_toio(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + int i; + u32 *d = (u32 *) dest_addr; + u32 *s = (u32 *) src_addr; + /* memcpy_toio does not work. Use writel for now */ + for (i = 0; i < len; i++) + writel_relaxed(*s++, d++); +} + +void msm_io_dump(void __iomem *addr, int size) +{ + char line_str[128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + CDBG("%s: %p %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + sprintf(p_str, "%08x: ", (u32) p); + p_str += 10; + } + data = readl_relaxed(p++); + sprintf(p_str, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + CDBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CDBG("%s\n", line_str); +} + +void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len) +{ + CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len); + msm_io_memcpy_toio(dest_addr, src_addr, len / 4); + msm_io_dump(dest_addr, len); +} + +static void msm_camera_vreg_enable(void) +{ + ldo15 = regulator_get(NULL, "8058_l15"); + if (IS_ERR(ldo15)) { + pr_err("%s: VREG LDO15 get failed\n", __func__); + ldo15 = NULL; + return; + } + if (regulator_set_voltage(ldo15, 2850000, 2850000)) { + pr_err("%s: VREG LDO15 set voltage failed\n", __func__); + goto ldo15_disable; + } + if (regulator_enable(ldo15)) { + pr_err("%s: VREG LDO15 enable failed\n", __func__); + goto ldo15_put; + } + + lvs0 = regulator_get(NULL, "8058_lvs0"); + if (IS_ERR(lvs0)) { + pr_err("%s: VREG LVS0 get failed\n", __func__); + lvs0 = NULL; + goto ldo15_disable; + } + if (regulator_enable(lvs0)) { + pr_err("%s: VREG LVS0 enable failed\n", __func__); + goto lvs0_put; + } + + ldo25 = regulator_get(NULL, "8058_l25"); + if (IS_ERR(ldo25)) { + pr_err("%s: VREG LDO25 get failed\n", __func__); + ldo25 = NULL; + goto lvs0_disable; + } + if (regulator_set_voltage(ldo25, 1200000, 1200000)) { + pr_err("%s: VREG LDO25 set voltage failed\n", __func__); + goto ldo25_disable; + } + if (regulator_enable(ldo25)) { + pr_err("%s: VREG LDO25 enable failed\n", __func__); + goto ldo25_put; + } + + fs_vfe = regulator_get(NULL, "fs_vfe"); + if (IS_ERR(fs_vfe)) { + CDBG("%s: Regulator FS_VFE get failed %ld\n", __func__, + PTR_ERR(fs_vfe)); + fs_vfe = NULL; + } else if (regulator_enable(fs_vfe)) { + CDBG("%s: Regulator FS_VFE enable failed\n", __func__); + regulator_put(fs_vfe); + } + return; + +ldo25_disable: + regulator_disable(ldo25); +ldo25_put: + regulator_put(ldo25); +lvs0_disable: + regulator_disable(lvs0); +lvs0_put: + regulator_put(lvs0); +ldo15_disable: + regulator_disable(ldo15); +ldo15_put: + regulator_put(ldo15); +} + +static void msm_camera_vreg_disable(void) +{ + if (ldo15) { + regulator_disable(ldo15); + regulator_put(ldo15); + } + + if (lvs0) { + regulator_disable(lvs0); + regulator_put(lvs0); + } + + if (ldo25) { + regulator_disable(ldo25); + regulator_put(ldo25); + } + + if (fs_vfe) { + regulator_disable(fs_vfe); + regulator_put(fs_vfe); + } +} + +int msm_camio_clk_enable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_CAM_MCLK_CLK: + camio_cam_clk = + clk = clk_get(NULL, "cam_clk"); + msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate); + break; + + case CAMIO_VFE_CLK: + camio_vfe_clk = + clk = clk_get(NULL, "vfe_clk"); + msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate); + break; + + case CAMIO_CSI0_VFE_CLK: + camio_csi0_vfe_clk = + clk = clk_get(NULL, "csi_vfe_clk"); + break; + + case CAMIO_CSI1_VFE_CLK: + camio_csi1_vfe_clk = + clk = clk_get(&camio_dev->dev, "csi_vfe_clk"); + break; + + case CAMIO_CSI_SRC_CLK: + camio_csi_src_clk = + clk = clk_get(NULL, "csi_src_clk"); + msm_camio_clk_rate_set_2(clk, 384000000); + break; + + case CAMIO_CSI0_CLK: + camio_csi0_clk = + clk = clk_get(NULL, "csi_clk"); + break; + + case CAMIO_CSI1_CLK: + camio_csi1_clk = + clk = clk_get(&camio_dev->dev, "csi_clk"); + break; + + case CAMIO_VFE_PCLK: + camio_vfe_pclk = + clk = clk_get(NULL, "vfe_pclk"); + break; + + case CAMIO_CSI0_PCLK: + camio_csi0_pclk = + clk = clk_get(NULL, "csi_pclk"); + break; + + case CAMIO_CSI1_PCLK: + camio_csi1_pclk = + clk = clk_get(&camio_dev->dev, "csi_pclk"); + break; + + case CAMIO_JPEG_CLK: + camio_jpeg_clk = + clk = clk_get(NULL, "ijpeg_clk"); + msm_camio_clk_rate_set_2(clk, 228571000); + break; + + case CAMIO_JPEG_PCLK: + camio_jpeg_pclk = + clk = clk_get(NULL, "ijpeg_pclk"); + break; + + case CAMIO_VPE_CLK: + camio_vpe_clk = + clk = clk_get(NULL, "vpe_clk"); + vpe_clk_rate = clk_round_rate(camio_vpe_clk, vpe_clk_rate); + clk_set_rate(camio_vpe_clk, vpe_clk_rate); + break; + + case CAMIO_VPE_PCLK: + camio_vpe_pclk = + clk = clk_get(NULL, "vpe_pclk"); + break; + + default: + break; + } + + if (!IS_ERR(clk)) + clk_prepare_enable(clk); + else + rc = -1; + return rc; +} + +int msm_camio_clk_disable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_CAM_MCLK_CLK: + clk = camio_cam_clk; + break; + + case CAMIO_VFE_CLK: + clk = camio_vfe_clk; + break; + + case CAMIO_CSI_SRC_CLK: + clk = camio_csi_src_clk; + break; + + case CAMIO_CSI0_VFE_CLK: + clk = camio_csi0_vfe_clk; + break; + + case CAMIO_CSI1_VFE_CLK: + clk = camio_csi1_vfe_clk; + break; + + case CAMIO_CSI0_CLK: + clk = camio_csi0_clk; + break; + + case CAMIO_CSI1_CLK: + clk = camio_csi1_clk; + break; + + case CAMIO_VFE_PCLK: + clk = camio_vfe_pclk; + break; + + case CAMIO_CSI0_PCLK: + clk = camio_csi0_pclk; + break; + + case CAMIO_CSI1_PCLK: + clk = camio_csi1_pclk; + break; + + case CAMIO_JPEG_CLK: + clk = camio_jpeg_clk; + break; + + case CAMIO_JPEG_PCLK: + clk = camio_jpeg_pclk; + break; + + case CAMIO_VPE_CLK: + clk = camio_vpe_clk; + break; + + case CAMIO_VPE_PCLK: + clk = camio_vpe_pclk; + break; + + default: + break; + } + + if (!IS_ERR(clk)) { + clk_disable_unprepare(clk); + clk_put(clk); + } else + rc = -1; + return rc; +} + +int msm_camio_vfe_clk_rate_set(int rate) +{ + int rc = 0; + struct clk *clk = camio_vfe_clk; + if (rate > clk_get_rate(clk)) + rc = clk_set_rate(clk, rate); + return rc; +} + +void msm_camio_clk_rate_set(int rate) +{ + struct clk *clk = camio_cam_clk; + clk_set_rate(clk, rate); +} + +void msm_camio_clk_rate_set_2(struct clk *clk, int rate) +{ + clk_set_rate(clk, rate); +} + +static irqreturn_t msm_io_csi_irq(int irq_num, void *data) +{ + uint32_t irq = 0; + if (csibase != NULL) + irq = msm_io_r(csibase + MIPI_INTERRUPT_STATUS); + CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq); + if (csibase != NULL) + msm_io_w(irq, csibase + MIPI_INTERRUPT_STATUS); + return IRQ_HANDLED; +} + +int msm_camio_jpeg_clk_disable(void) +{ + int rc = 0; + if (fs_ijpeg) { + rc = regulator_disable(fs_ijpeg); + if (rc < 0) { + CDBG("%s: Regulator disable failed %d\n", __func__, rc); + return rc; + } + regulator_put(fs_ijpeg); + } + rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK); + if (rc < 0) + return rc; + rc = msm_camio_clk_disable(CAMIO_JPEG_CLK); + CDBG("%s: exit %d\n", __func__, rc); + return rc; +} + +int msm_camio_jpeg_clk_enable(void) +{ + int rc = 0; + rc = msm_camio_clk_enable(CAMIO_JPEG_CLK); + if (rc < 0) + return rc; + rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK); + if (rc < 0) + return rc; + fs_ijpeg = regulator_get(NULL, "fs_ijpeg"); + if (IS_ERR(fs_ijpeg)) { + CDBG("%s: Regulator FS_IJPEG get failed %ld\n", __func__, + PTR_ERR(fs_ijpeg)); + fs_ijpeg = NULL; + } else if (regulator_enable(fs_ijpeg)) { + CDBG("%s: Regulator FS_IJPEG enable failed\n", __func__); + regulator_put(fs_ijpeg); + } + CDBG("%s: exit %d\n", __func__, rc); + return rc; +} + +int msm_camio_vpe_clk_disable(void) +{ + int rc = 0; + if (fs_vpe) { + regulator_disable(fs_vpe); + regulator_put(fs_vpe); + } + + rc = msm_camio_clk_disable(CAMIO_VPE_CLK); + if (rc < 0) + return rc; + rc = msm_camio_clk_disable(CAMIO_VPE_PCLK); + return rc; +} + +int msm_camio_vpe_clk_enable(uint32_t clk_rate) +{ + int rc = 0; + fs_vpe = regulator_get(NULL, "fs_vpe"); + if (IS_ERR(fs_vpe)) { + CDBG("%s: Regulator FS_VPE get failed %ld\n", __func__, + PTR_ERR(fs_vpe)); + fs_vpe = NULL; + } else if (regulator_enable(fs_vpe)) { + CDBG("%s: Regulator FS_VPE enable failed\n", __func__); + regulator_put(fs_vpe); + } + + vpe_clk_rate = clk_rate; + rc = msm_camio_clk_enable(CAMIO_VPE_CLK); + if (rc < 0) + return rc; + + rc = msm_camio_clk_enable(CAMIO_VPE_PCLK); + return rc; +} + +#ifdef DBG_CSI +static int csi_request_irq(void) +{ + return request_irq(camio_ext.csiirq, msm_io_csi_irq, + IRQF_TRIGGER_HIGH, "csi", 0); +} +#else +static int csi_request_irq(void) { return 0; } +#endif + +#ifdef DBG_CSI +static void csi_free_irq(void) +{ + free_irq(camio_ext.csiirq, 0); +} +#else +static void csi_free_irq(void) { return 0; } +#endif + +int msm_camio_enable(struct platform_device *pdev) +{ + int rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camio_dev = pdev; + camio_ext = camdev->ioext; + camio_clk = camdev->ioclk; + cam_bus_scale_table = camdev->cam_bus_scale_table; + + msm_camio_clk_enable(CAMIO_VFE_CLK); + msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK); + msm_camio_clk_enable(CAMIO_CSI1_VFE_CLK); + msm_camio_clk_enable(CAMIO_CSI_SRC_CLK); + msm_camio_clk_enable(CAMIO_CSI0_CLK); + msm_camio_clk_enable(CAMIO_CSI1_CLK); + msm_camio_clk_enable(CAMIO_VFE_PCLK); + msm_camio_clk_enable(CAMIO_CSI0_PCLK); + msm_camio_clk_enable(CAMIO_CSI1_PCLK); + + csiio = request_mem_region(camio_ext.csiphy, + camio_ext.csisz, pdev->name); + if (!csiio) { + rc = -EBUSY; + goto common_fail; + } + csibase = ioremap(camio_ext.csiphy, + camio_ext.csisz); + if (!csibase) { + rc = -ENOMEM; + goto csi_busy; + } + rc = csi_request_irq(); + if (rc < 0) + goto csi_irq_fail; + + return 0; + +csi_irq_fail: + iounmap(csibase); + csibase = NULL; +csi_busy: + release_mem_region(camio_ext.csiphy, camio_ext.csisz); + csibase = NULL; +common_fail: + msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); + msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI0_CLK); + msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI1_CLK); + msm_camio_clk_disable(CAMIO_VFE_PCLK); + msm_camio_clk_disable(CAMIO_CSI0_PCLK); + msm_camio_clk_disable(CAMIO_CSI1_PCLK); + msm_camera_vreg_disable(); + camdev->camera_gpio_off(); + return rc; +} + +static void msm_camio_csi_disable(void) +{ + uint32_t val; + + val = 0x0; + if (csibase != NULL) { + CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2); + CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL); + msleep(20); + val = msm_io_r(csibase + MIPI_PHY_D1_CONTROL); + val &= + ~((0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) + |(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT)); + CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL); + usleep_range(5000, 6000); + msm_io_w(0x0, csibase + MIPI_INTERRUPT_MASK); + msm_io_w(0x0, csibase + MIPI_INTERRUPT_STATUS); + csi_free_irq(); + iounmap(csibase); + csibase = NULL; + release_mem_region(camio_ext.csiphy, camio_ext.csisz); + } +} +void msm_camio_disable(struct platform_device *pdev) +{ + CDBG("disable mipi\n"); + msm_camio_csi_disable(); + CDBG("disable clocks\n"); + msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI0_CLK); + msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK); + msm_camio_clk_disable(CAMIO_CSI1_CLK); + msm_camio_clk_disable(CAMIO_VFE_PCLK); + msm_camio_clk_disable(CAMIO_CSI0_PCLK); + msm_camio_clk_disable(CAMIO_CSI1_PCLK); + msm_camio_clk_disable(CAMIO_CSI_SRC_CLK); + msm_camio_clk_disable(CAMIO_VFE_CLK); +} + +int msm_camio_sensor_clk_on(struct platform_device *pdev) +{ + int rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camio_dev = pdev; + camio_ext = camdev->ioext; + camio_clk = camdev->ioclk; + + msm_camera_vreg_enable(); + msleep(10); + rc = camdev->camera_gpio_on(); + if (rc < 0) + return rc; + return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK); +} + +int msm_camio_sensor_clk_off(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + msm_camera_vreg_disable(); + camdev->camera_gpio_off(); + return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); + +} + +void msm_camio_vfe_blk_reset(void) +{ + return; +} + +int msm_camio_probe_on(struct platform_device *pdev) +{ + int rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camio_dev = pdev; + camio_ext = camdev->ioext; + camio_clk = camdev->ioclk; + + rc = camdev->camera_gpio_on(); + if (rc < 0) + return rc; + msm_camera_vreg_enable(); + return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK); +} + +int msm_camio_probe_off(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + msm_camera_vreg_disable(); + camdev->camera_gpio_off(); + return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); +} + +int msm_camio_csi_config(struct msm_camera_csi_params *csi_params) +{ + int rc = 0; + uint32_t val = 0; + int i; + + CDBG("msm_camio_csi_config\n"); + if (csibase != NULL) { + /* SOT_ECC_EN enable error correction for SYNC (data-lane) */ + msm_io_w(0x4, csibase + MIPI_PHY_CONTROL); + + /* SW_RST to the CSI core */ + msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK, + csibase + MIPI_PROTOCOL_CONTROL); + + /* PROTOCOL CONTROL */ + val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK | + MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK | + MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK; + val |= (uint32_t)(csi_params->data_format) << + MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT; + val |= csi_params->dpcm_scheme << + MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT; + CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PROTOCOL_CONTROL); + + /* settle_cnt is very sensitive to speed! + increase this value to run at higher speeds */ + val = (csi_params->settle_cnt << + MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) | + (0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) | + (0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) | + (0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT); + CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val); + for (i = 0; i < csi_params->lane_cnt; i++) + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2 + i * 4); + + val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) | + (0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT); + CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL); + + val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT; + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL); + + val = + (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) + |(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT); + CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL); + + msm_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL); + msm_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL); + + /* halcyon only supports 1 or 2 lane */ + switch (csi_params->lane_cnt) { + case 1: + msm_io_w(csi_params->lane_assign << 8 | 0x4, + csibase + MIPI_CAMERA_CNTL); + break; + case 2: + msm_io_w(csi_params->lane_assign << 8 | 0x5, + csibase + MIPI_CAMERA_CNTL); + break; + case 3: + msm_io_w(csi_params->lane_assign << 8 | 0x6, + csibase + MIPI_CAMERA_CNTL); + break; + case 4: + msm_io_w(csi_params->lane_assign << 8 | 0x7, + csibase + MIPI_CAMERA_CNTL); + break; + } + + /* mask out ID_ERROR[19], DATA_CMM_ERR[11] + and CLK_CMM_ERR[10] - de-featured */ + msm_io_w(0xF017F3C0, csibase + MIPI_INTERRUPT_MASK); + /*clear IRQ bits*/ + msm_io_w(0xF017F3C0, csibase + MIPI_INTERRUPT_STATUS); + } else { + pr_info("CSIBASE is NULL"); + } + + return rc; +} + +void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting) +{ + static uint32_t bus_perf_client; + int rc = 0; + switch (perf_setting) { + case S_INIT: + bus_perf_client = + msm_bus_scale_register_client(cam_bus_scale_table); + if (!bus_perf_client) { + pr_err("%s: Registration Failed!!!\n", __func__); + bus_perf_client = 0; + return; + } + CDBG("%s: S_INIT rc = %u\n", __func__, bus_perf_client); + break; + case S_EXIT: + if (bus_perf_client) { + CDBG("%s: S_EXIT\n", __func__); + msm_bus_scale_unregister_client(bus_perf_client); + } else + pr_err("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_PREVIEW: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 1); + CDBG("%s: S_PREVIEW rc = %d\n", __func__, rc); + } else + pr_err("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_VIDEO: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 2); + CDBG("%s: S_VIDEO rc = %d\n", __func__, rc); + } else + pr_err("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_CAPTURE: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 3); + CDBG("%s: S_CAPTURE rc = %d\n", __func__, rc); + } else + pr_err("%s: Bus Client NOT Registered!!!\n", __func__); + break; + + case S_ZSL: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 4); + CDBG("%s: S_ZSL rc = %d\n", __func__, rc); + } else + pr_err("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_STEREO_VIDEO: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 5); + CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc); + } else + pr_err("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_STEREO_CAPTURE: + if (bus_perf_client) { + rc = msm_bus_scale_client_update_request( + bus_perf_client, 6); + CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc); + } else + pr_err("%s: Bus Client NOT Registered!!!\n", __func__); + break; + case S_DEFAULT: + break; + default: + pr_warning("%s: INVALID CASE\n", __func__); + } +} diff --git a/drivers/media/video/msm_zsl/msm_io_vfe31.c b/drivers/media/video/msm_zsl/msm_io_vfe31.c new file mode 100644 index 00000000000..91dbc8f49d0 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_io_vfe31.c @@ -0,0 +1,840 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CAMIF_CFG_RMSK 0x1fffff +#define CAM_SEL_BMSK 0x2 +#define CAM_PCLK_SRC_SEL_BMSK 0x60000 +#define CAM_PCLK_INVERT_BMSK 0x80000 +#define CAM_PAD_REG_SW_RESET_BMSK 0x100000 + +#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000 +#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000 +#define MDDI_CLK_CHICKEN_BIT_BMSK 0x80 + +#define CAM_SEL_SHFT 0x1 +#define CAM_PCLK_SRC_SEL_SHFT 0x11 +#define CAM_PCLK_INVERT_SHFT 0x13 +#define CAM_PAD_REG_SW_RESET_SHFT 0x14 + +#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10 +#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF +#define MDDI_CLK_CHICKEN_BIT_SHFT 0x7 + +/* MIPI CSI controller registers */ +#define MIPI_PHY_CONTROL 0x00000000 +#define MIPI_PROTOCOL_CONTROL 0x00000004 +#define MIPI_INTERRUPT_STATUS 0x00000008 +#define MIPI_INTERRUPT_MASK 0x0000000C +#define MIPI_CAMERA_CNTL 0x00000024 +#define MIPI_CALIBRATION_CONTROL 0x00000018 +#define MIPI_PHY_D0_CONTROL2 0x00000038 +#define MIPI_PHY_D1_CONTROL2 0x0000003C +#define MIPI_PHY_D2_CONTROL2 0x00000040 +#define MIPI_PHY_D3_CONTROL2 0x00000044 +#define MIPI_PHY_CL_CONTROL 0x00000048 +#define MIPI_PHY_D0_CONTROL 0x00000034 +#define MIPI_PHY_D1_CONTROL 0x00000020 +#define MIPI_PHY_D2_CONTROL 0x0000002C +#define MIPI_PHY_D3_CONTROL 0x00000030 +#define MIPI_PROTOCOL_CONTROL_SW_RST_BMSK 0x8000000 +#define MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK 0x200000 +#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_BMSK 0x180000 +#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x40000 +#define MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK 0x20000 +#define MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT 0x16 +#define MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT 0x15 +#define MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT 0x14 +#define MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT 0x7 +#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT 0x13 +#define MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT 0x1e +#define MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 +#define MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 +#define MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 +#define MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT 0x18 +#define MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT 0x10 +#define MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT 0x4 +#define MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3 +#define MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT 0x18 +#define MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT 0x2 +#define MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT 0x1c +#define MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT 0x9 +#define MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT 0x8 + +#define CAMIO_VFE_CLK_SNAP 122880000 +#define CAMIO_VFE_CLK_PREV 122880000 + +/* AXI rates in KHz */ +#define MSM_AXI_QOS_PREVIEW 192000 +#define MSM_AXI_QOS_SNAPSHOT 192000 +#define MSM_AXI_QOS_RECORDING 192000 + +static struct clk *camio_vfe_mdc_clk; +static struct clk *camio_mdc_clk; +static struct clk *camio_vfe_clk; +static struct clk *camio_vfe_camif_clk; +static struct clk *camio_vfe_pbdg_clk; +static struct clk *camio_cam_m_clk; +static struct clk *camio_camif_pad_pbdg_clk; +static struct clk *camio_csi_clk; +static struct clk *camio_csi_pclk; +static struct clk *camio_csi_vfe_clk; +static struct clk *camio_jpeg_clk; +static struct clk *camio_jpeg_pclk; +static struct clk *camio_vpe_clk; +static struct regulator *fs_vpe; +static struct msm_camera_io_ext camio_ext; +static struct msm_camera_io_clk camio_clk; +static struct resource *camifpadio, *csiio; +void __iomem *camifpadbase, *csibase; +static uint32_t vpe_clk_rate; +static uint32_t jpeg_clk_rate; + +static struct regulator_bulk_data regs[] = { + { .supply = "gp2", .min_uV = 2600000, .max_uV = 2600000 }, + { .supply = "lvsw1" }, + { .supply = "fs_vfe" }, + /* sn12m0pz regulators */ + { .supply = "gp6", .min_uV = 3050000, .max_uV = 3100000 }, + { .supply = "gp16", .min_uV = 1200000, .max_uV = 1200000 }, +}; + +static int reg_count; + +void msm_io_w(u32 data, void __iomem *addr) +{ + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + writel_relaxed((data), (addr)); +} + +void msm_io_w_mb(u32 data, void __iomem *addr) +{ + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + wmb(); + writel_relaxed((data), (addr)); + wmb(); +} + +u32 msm_io_r(void __iomem *addr) +{ + uint32_t data = readl_relaxed(addr); + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + return data; +} + +u32 msm_io_r_mb(void __iomem *addr) +{ + uint32_t data; + rmb(); + data = readl_relaxed(addr); + rmb(); + CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data)); + return data; +} + +void msm_io_memcpy_toio(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + int i; + u32 *d = (u32 *) dest_addr; + u32 *s = (u32 *) src_addr; + /* memcpy_toio does not work. Use writel for now */ + for (i = 0; i < len; i++) + writel_relaxed(*s++, d++); +} + +void msm_io_dump(void __iomem *addr, int size) +{ + char line_str[128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + CDBG("%s: %p %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + sprintf(p_str, "%08x: ", (u32) p); + p_str += 10; + } + data = readl_relaxed(p++); + sprintf(p_str, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + CDBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CDBG("%s\n", line_str); +} + +void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len) +{ + CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len); + msm_io_memcpy_toio(dest_addr, src_addr, len / 4); + msm_io_dump(dest_addr, len); +} + +static void msm_camera_vreg_enable(struct platform_device *pdev) +{ + int count, rc; + + struct device *dev = &pdev->dev; + + /* Use gp6 and gp16 if and only if dev name matches. */ + if (!strncmp(pdev->name, "msm_camera_sn12m0pz", 20)) + count = ARRAY_SIZE(regs); + else + count = ARRAY_SIZE(regs) - 2; + + rc = regulator_bulk_get(dev, count, regs); + + if (rc) { + dev_err(dev, "%s: could not get regulators: %d\n", + __func__, rc); + return; + } + + rc = regulator_bulk_set_voltage(count, regs); + + if (rc) { + dev_err(dev, "%s: could not set voltages: %d\n", + __func__, rc); + goto reg_free; + } + + rc = regulator_bulk_enable(count, regs); + + if (rc) { + dev_err(dev, "%s: could not enable regulators: %d\n", + __func__, rc); + goto reg_free; + } + + reg_count = count; + return; + +reg_free: + regulator_bulk_free(count, regs); + return; +} + + +static void msm_camera_vreg_disable(void) +{ + regulator_bulk_disable(reg_count, regs); + regulator_bulk_free(reg_count, regs); + reg_count = 0; +} + +int msm_camio_clk_enable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_VFE_MDC_CLK: + camio_vfe_mdc_clk = + clk = clk_get(NULL, "vfe_mdc_clk"); + break; + + case CAMIO_MDC_CLK: + camio_mdc_clk = + clk = clk_get(NULL, "mdc_clk"); + break; + + case CAMIO_VFE_CLK: + camio_vfe_clk = + clk = clk_get(NULL, "vfe_clk"); + msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate); + break; + + case CAMIO_VFE_CAMIF_CLK: + camio_vfe_camif_clk = + clk = clk_get(NULL, "vfe_camif_clk"); + break; + + case CAMIO_VFE_PBDG_CLK: + camio_vfe_pbdg_clk = + clk = clk_get(NULL, "vfe_pclk"); + break; + + case CAMIO_CAM_MCLK_CLK: + camio_cam_m_clk = + clk = clk_get(NULL, "cam_m_clk"); + msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate); + break; + + case CAMIO_CAMIF_PAD_PBDG_CLK: + camio_camif_pad_pbdg_clk = + clk = clk_get(NULL, "camif_pad_pclk"); + break; + + case CAMIO_CSI0_CLK: + camio_csi_clk = + clk = clk_get(NULL, "csi_clk"); + msm_camio_clk_rate_set_2(clk, 153600000); + break; + case CAMIO_CSI0_VFE_CLK: + camio_csi_vfe_clk = + clk = clk_get(NULL, "csi_vfe_clk"); + break; + case CAMIO_CSI0_PCLK: + camio_csi_pclk = + clk = clk_get(NULL, "csi_pclk"); + break; + + case CAMIO_JPEG_CLK: + camio_jpeg_clk = + clk = clk_get(NULL, "jpeg_clk"); + jpeg_clk_rate = clk_round_rate(clk, 144000000); + clk_set_rate(clk, jpeg_clk_rate); + break; + case CAMIO_JPEG_PCLK: + camio_jpeg_pclk = + clk = clk_get(NULL, "jpeg_pclk"); + break; + case CAMIO_VPE_CLK: + camio_vpe_clk = + clk = clk_get(NULL, "vpe_clk"); + vpe_clk_rate = clk_round_rate(clk, vpe_clk_rate); + clk_set_rate(clk, vpe_clk_rate); + break; + default: + break; + } + + if (!IS_ERR(clk)) + clk_enable(clk); + else + rc = -1; + return rc; +} + +int msm_camio_clk_disable(enum msm_camio_clk_type clktype) +{ + int rc = 0; + struct clk *clk = NULL; + + switch (clktype) { + case CAMIO_VFE_MDC_CLK: + clk = camio_vfe_mdc_clk; + break; + + case CAMIO_MDC_CLK: + clk = camio_mdc_clk; + break; + + case CAMIO_VFE_CLK: + clk = camio_vfe_clk; + break; + + case CAMIO_VFE_CAMIF_CLK: + clk = camio_vfe_camif_clk; + break; + + case CAMIO_VFE_PBDG_CLK: + clk = camio_vfe_pbdg_clk; + break; + + case CAMIO_CAM_MCLK_CLK: + clk = camio_cam_m_clk; + break; + + case CAMIO_CAMIF_PAD_PBDG_CLK: + clk = camio_camif_pad_pbdg_clk; + break; + case CAMIO_CSI0_CLK: + clk = camio_csi_clk; + break; + case CAMIO_CSI0_VFE_CLK: + clk = camio_csi_vfe_clk; + break; + case CAMIO_CSI0_PCLK: + clk = camio_csi_pclk; + break; + case CAMIO_JPEG_CLK: + clk = camio_jpeg_clk; + break; + case CAMIO_JPEG_PCLK: + clk = camio_jpeg_pclk; + break; + case CAMIO_VPE_CLK: + clk = camio_vpe_clk; + break; + default: + break; + } + + if (!IS_ERR(clk)) { + clk_disable(clk); + clk_put(clk); + } else + rc = -1; + + return rc; +} + +void msm_camio_clk_rate_set(int rate) +{ + struct clk *clk = camio_cam_m_clk; + clk_set_rate(clk, rate); +} + +int msm_camio_vfe_clk_rate_set(int rate) +{ + struct clk *clk = camio_vfe_clk; + return clk_set_rate(clk, rate); +} + +void msm_camio_clk_rate_set_2(struct clk *clk, int rate) +{ + clk_set_rate(clk, rate); +} + +static irqreturn_t msm_io_csi_irq(int irq_num, void *data) +{ + uint32_t irq; + irq = msm_io_r(csibase + MIPI_INTERRUPT_STATUS); + CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq); + msm_io_w(irq, csibase + MIPI_INTERRUPT_STATUS); + return IRQ_HANDLED; +} + +int msm_camio_jpeg_clk_disable(void) +{ + msm_camio_clk_disable(CAMIO_JPEG_CLK); + msm_camio_clk_disable(CAMIO_JPEG_PCLK); + /* Need to add the code for remove PM QOS requirement */ + return 0; +} + + +int msm_camio_jpeg_clk_enable(void) +{ + msm_camio_clk_enable(CAMIO_JPEG_CLK); + msm_camio_clk_enable(CAMIO_JPEG_PCLK); + return 0; +} + +int msm_camio_vpe_clk_disable(void) +{ + msm_camio_clk_disable(CAMIO_VPE_CLK); + + if (fs_vpe) { + regulator_disable(fs_vpe); + regulator_put(fs_vpe); + } + + return 0; +} + +int msm_camio_vpe_clk_enable(uint32_t clk_rate) +{ + fs_vpe = regulator_get(NULL, "fs_vpe"); + if (IS_ERR(fs_vpe)) { + pr_err("%s: Regulator FS_VPE get failed %ld\n", __func__, + PTR_ERR(fs_vpe)); + fs_vpe = NULL; + } else if (regulator_enable(fs_vpe)) { + pr_err("%s: Regulator FS_VPE enable failed\n", __func__); + regulator_put(fs_vpe); + } + + vpe_clk_rate = clk_rate; + msm_camio_clk_enable(CAMIO_VPE_CLK); + return 0; +} + +int msm_camio_enable(struct platform_device *pdev) +{ + int rc = 0; + uint32_t val; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + msm_camio_clk_enable(CAMIO_VFE_PBDG_CLK); + if (!sinfo->csi_if) + msm_camio_clk_enable(CAMIO_VFE_CAMIF_CLK); + else { + msm_camio_clk_enable(CAMIO_VFE_CLK); + csiio = request_mem_region(camio_ext.csiphy, + camio_ext.csisz, pdev->name); + if (!csiio) { + rc = -EBUSY; + goto common_fail; + } + csibase = ioremap(camio_ext.csiphy, + camio_ext.csisz); + if (!csibase) { + rc = -ENOMEM; + goto csi_busy; + } + rc = request_irq(camio_ext.csiirq, msm_io_csi_irq, + IRQF_TRIGGER_RISING, "csi", 0); + if (rc < 0) + goto csi_irq_fail; + /* enable required clocks for CSI */ + msm_camio_clk_enable(CAMIO_CSI0_PCLK); + msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK); + msm_camio_clk_enable(CAMIO_CSI0_CLK); + + msleep(10); + val = (20 << + MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) | + (0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) | + (0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) | + (0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT); + CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2); + + val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) | + (0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT); + CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL); + } + return 0; +csi_irq_fail: + iounmap(csibase); +csi_busy: + release_mem_region(camio_ext.csiphy, camio_ext.csisz); +common_fail: + msm_camio_clk_disable(CAMIO_VFE_PBDG_CLK); + msm_camio_clk_disable(CAMIO_VFE_CLK); + return rc; +} + +void msm_camio_disable(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + uint32_t val; + if (!sinfo->csi_if) { + msm_camio_clk_disable(CAMIO_VFE_CAMIF_CLK); + } else { + val = (0x0 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) | + (0x0<dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camio_clk = camdev->ioclk; + camio_ext = camdev->ioext; + camdev->camera_gpio_on(); + msm_camera_vreg_enable(pdev); + return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK); +} + +int msm_camio_probe_off(struct platform_device *pdev) +{ + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + msm_camera_vreg_disable(); + camdev->camera_gpio_off(); + return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); +} + +int msm_camio_sensor_clk_on(struct platform_device *pdev) +{ + int rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camio_clk = camdev->ioclk; + camio_ext = camdev->ioext; + camdev->camera_gpio_on(); + msm_camera_vreg_enable(pdev); + msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK); + msm_camio_clk_enable(CAMIO_CAMIF_PAD_PBDG_CLK); + if (!sinfo->csi_if) { + camifpadio = request_mem_region(camio_ext.camifpadphy, + camio_ext.camifpadsz, pdev->name); + msm_camio_clk_enable(CAMIO_VFE_CLK); + if (!camifpadio) { + rc = -EBUSY; + goto common_fail; + } + camifpadbase = ioremap(camio_ext.camifpadphy, + camio_ext.camifpadsz); + if (!camifpadbase) { + CDBG("msm_camio_sensor_clk_on fail\n"); + rc = -ENOMEM; + goto parallel_busy; + } + } + return rc; +parallel_busy: + release_mem_region(camio_ext.camifpadphy, camio_ext.camifpadsz); + goto common_fail; +common_fail: + msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); + msm_camio_clk_disable(CAMIO_VFE_CLK); + msm_camio_clk_disable(CAMIO_CAMIF_PAD_PBDG_CLK); + msm_camera_vreg_disable(); + camdev->camera_gpio_off(); + return rc; +} + +int msm_camio_sensor_clk_off(struct platform_device *pdev) +{ + uint32_t rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + camdev->camera_gpio_off(); + msm_camera_vreg_disable(); + rc = msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK); + rc = msm_camio_clk_disable(CAMIO_CAMIF_PAD_PBDG_CLK); + if (!sinfo->csi_if) { + iounmap(camifpadbase); + release_mem_region(camio_ext.camifpadphy, camio_ext.camifpadsz); + rc = msm_camio_clk_disable(CAMIO_VFE_CLK); + } + return rc; +} + +int msm_camio_csi_config(struct msm_camera_csi_params *csi_params) +{ + int rc = 0; + uint32_t val = 0; + + CDBG("msm_camio_csi_config \n"); + + /* SOT_ECC_EN enable error correction for SYNC (data-lane) */ + msm_io_w(0x4, csibase + MIPI_PHY_CONTROL); + + /* SW_RST to the CSI core */ + msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK, + csibase + MIPI_PROTOCOL_CONTROL); + + /* PROTOCOL CONTROL */ + val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK | + MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK | + MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK; + val |= (uint32_t)(csi_params->data_format) << + MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT; + val |= csi_params->dpcm_scheme << + MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT; + CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PROTOCOL_CONTROL); + + /* SW CAL EN */ + val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) | + (0x1 << + MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) | + (0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) | + (0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT); + CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_CALIBRATION_CONTROL); + + /* settle_cnt is very sensitive to speed! + increase this value to run at higher speeds */ + val = (csi_params->settle_cnt << + MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) | + (0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) | + (0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) | + (0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT); + CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2); + msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2); + + + val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) | + (0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT); + CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL); + + val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT; + msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL); + + val = (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) | + (0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT); + CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val); + msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL); + + msm_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL); + msm_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL); + + /* halcyon only supports 1 or 2 lane */ + switch (csi_params->lane_cnt) { + case 1: + msm_io_w(csi_params->lane_assign << 8 | 0x4, + csibase + MIPI_CAMERA_CNTL); + break; + case 2: + msm_io_w(csi_params->lane_assign << 8 | 0x5, + csibase + MIPI_CAMERA_CNTL); + break; + case 3: + msm_io_w(csi_params->lane_assign << 8 | 0x6, + csibase + MIPI_CAMERA_CNTL); + break; + case 4: + msm_io_w(csi_params->lane_assign << 8 | 0x7, + csibase + MIPI_CAMERA_CNTL); + break; + } + + /* mask out ID_ERROR[19], DATA_CMM_ERR[11] + and CLK_CMM_ERR[10] - de-featured */ + msm_io_w(0xFFF7F3FF, csibase + MIPI_INTERRUPT_MASK); + /*clear IRQ bits*/ + msm_io_w(0xFFF7F3FF, csibase + MIPI_INTERRUPT_STATUS); + + return rc; +} +void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting) +{ + switch (perf_setting) { + case S_INIT: + add_axi_qos(); + break; + case S_PREVIEW: + update_axi_qos(MSM_AXI_QOS_PREVIEW); + break; + case S_VIDEO: + update_axi_qos(MSM_AXI_QOS_RECORDING); + break; + case S_CAPTURE: + update_axi_qos(MSM_AXI_QOS_SNAPSHOT); + break; + case S_DEFAULT: + update_axi_qos(PM_QOS_DEFAULT_VALUE); + break; + case S_EXIT: + release_axi_qos(); + break; + default: + CDBG("%s: INVALID CASE\n", __func__); + } +} diff --git a/drivers/media/video/msm_zsl/msm_isp.c b/drivers/media/video/msm_zsl/msm_isp.c new file mode 100644 index 00000000000..546a0fc57a6 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_isp.c @@ -0,0 +1,783 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "msm.h" + +#ifdef CONFIG_MSM_CAMERA_DEBUG +#define D(fmt, args...) pr_debug("msm_isp: " fmt, ##args) +#else +#define D(fmt, args...) do {} while (0) +#endif +#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \ + __func__, __LINE__, ((to) ? "to" : "from")) +#define ERR_COPY_FROM_USER() ERR_USER_COPY(0) +#define ERR_COPY_TO_USER() ERR_USER_COPY(1) + +#define MSM_FRAME_AXI_MAX_BUF 32 + +/* + * This function executes in interrupt context. + */ + +void *msm_isp_sync_alloc(int size, + gfp_t gfp) +{ + struct msm_queue_cmd *qcmd = + kmalloc(sizeof(struct msm_queue_cmd) + size, gfp); + + if (qcmd) { + atomic_set(&qcmd->on_heap, 1); + return qcmd + 1; + } + return NULL; +} + +void msm_isp_sync_free(void *ptr) +{ + if (ptr) { + struct msm_queue_cmd *qcmd = + (struct msm_queue_cmd *)ptr; + qcmd--; + if (atomic_read(&qcmd->on_heap)) + kfree(qcmd); + } +} + +static int msm_isp_notify_VFE_BUF_EVT(struct v4l2_subdev *sd, void *arg) +{ + int rc = -EINVAL; + struct msm_vfe_resp *vdata = (struct msm_vfe_resp *)arg; + struct msm_free_buf free_buf; + struct msm_camvfe_params vfe_params; + struct msm_vfe_cfg_cmd cfgcmd; + struct msm_sync *sync = + (struct msm_sync *)v4l2_get_subdev_hostdata(sd); + struct msm_cam_v4l2_device *pcam = sync->pcam_sync; + + int vfe_id = vdata->evt_msg.msg_id; + if (!pcam) { + pr_err("%s pcam is null. return\n", __func__); + msm_isp_sync_free(vdata); + return rc; + } + switch (vdata->type) { + case VFE_MSG_V32_START: + case VFE_MSG_V32_START_RECORDING: + D("%s Got V32_START_*: Getting ping addr id = %d", + __func__, vfe_id); + msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf); + cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf); + cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + break; + case VFE_MSG_V32_CAPTURE: + pr_err("%s Got V32_CAPTURE: getting buffer for id = %d", + __func__, vfe_id); + msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf); + cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + /* Write the same buffer into PONG */ + cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + break; + case VFE_MSG_OUTPUT_IRQ: + D("%s Got OUTPUT_IRQ: Getting free buf id = %d", + __func__, vfe_id); + msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf); + cfgcmd.cmd_type = CMD_CONFIG_FREE_BUF_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + break; + default: + pr_err("%s: Invalid vdata type: %d\n", __func__, vdata->type); + break; + } + return rc; +} + +/* + * This function executes in interrupt context. + */ +static int msm_isp_notify_vfe(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + int rc = 0; + struct v4l2_event v4l2_evt; + struct msm_isp_event_ctrl *isp_event; + struct msm_sync *sync = + (struct msm_sync *)v4l2_get_subdev_hostdata(sd); + struct msm_cam_media_controller *pmctl = NULL; + struct msm_free_buf buf; + + v4l2_evt.id = 0; + if (!sync) { + pr_err("%s: no context in dsp callback.\n", __func__); + rc = -EINVAL; + return rc; + } + + pmctl = &sync->pcam_sync->mctl; + + if (notification == NOTIFY_VFE_BUF_EVT) + return msm_isp_notify_VFE_BUF_EVT(sd, arg); + + isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_ATOMIC); + if (!isp_event) { + pr_err("%s Insufficient memory. return", __func__); + return -ENOMEM; + } + + v4l2_evt.type = V4L2_EVENT_PRIVATE_START + + MSM_CAM_RESP_STAT_EVT_MSG; + *((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event; + + isp_event->resptype = MSM_CAM_RESP_STAT_EVT_MSG; + isp_event->isp_data.isp_msg.type = MSM_CAMERA_MSG; + isp_event->isp_data.isp_msg.len = 0; + + switch (notification) { + case NOTIFY_ISP_MSG_EVT: { + struct isp_msg_event *isp_msg = (struct isp_msg_event *)arg; + + isp_event->isp_data.isp_msg.msg_id = isp_msg->msg_id; + isp_event->isp_data.isp_msg.frame_id = isp_msg->sof_count; + break; + } + case NOTIFY_VFE_MSG_OUT: { + uint8_t msgid; + struct isp_msg_output *isp_output = + (struct isp_msg_output *)arg; + switch (isp_output->output_id) { + case MSG_ID_OUTPUT_P: + msgid = VFE_MSG_OUTPUT_P; + break; + case MSG_ID_OUTPUT_V: + msgid = VFE_MSG_OUTPUT_V; + break; + case MSG_ID_OUTPUT_T: + msgid = VFE_MSG_OUTPUT_T; + break; + case MSG_ID_OUTPUT_S: + msgid = VFE_MSG_OUTPUT_S; + break; + default: + pr_err("%s: Invalid VFE output id: %d\n", + __func__, isp_output->output_id); + rc = -EINVAL; + break; + } + + if (!rc) { + isp_event->isp_data.isp_msg.msg_id = + isp_output->output_id; + isp_event->isp_data.isp_msg.frame_id = + isp_output->frameCounter; + buf = isp_output->buf; + msm_mctl_buf_done(pmctl, msgid, + &buf, isp_output->frameCounter); + } + } + break; + case NOTIFY_VFE_MSG_STATS: { + struct msm_stats_buf stats; + struct isp_msg_stats *isp_stats = (struct isp_msg_stats *)arg; + + isp_event->isp_data.isp_msg.msg_id = isp_stats->id; + isp_event->isp_data.isp_msg.frame_id = + isp_stats->frameCounter; + stats.buffer = msm_pmem_stats_ptov_lookup(&pmctl->sync, + isp_stats->buffer, + &(stats.fd)); + switch (isp_stats->id) { + case MSG_ID_STATS_AEC: + stats.aec.buff = stats.buffer; + stats.aec.fd = stats.fd; + break; + case MSG_ID_STATS_AF: + stats.af.buff = stats.buffer; + stats.af.fd = stats.fd; + break; + case MSG_ID_STATS_AWB: + stats.awb.buff = stats.buffer; + stats.awb.fd = stats.fd; + break; + case MSG_ID_STATS_IHIST: + stats.ihist.buff = stats.buffer; + stats.ihist.fd = stats.fd; + break; + case MSG_ID_STATS_RS: + stats.rs.buff = stats.buffer; + stats.rs.fd = stats.fd; + break; + case MSG_ID_STATS_CS: + stats.cs.buff = stats.buffer; + stats.cs.fd = stats.fd; + break; + default: + pr_err("%s: Invalid msg type", __func__); + break; + } + if (!stats.buffer) { + pr_err("%s: msm_pmem_stats_ptov_lookup error\n", + __func__); + isp_event->isp_data.isp_msg.len = 0; + rc = -EFAULT; + } else { + struct msm_stats_buf *stats_buf = + kmalloc(sizeof(struct msm_stats_buf), + GFP_ATOMIC); + if (!stats_buf) { + pr_err("%s: out of memory.\n", + __func__); + rc = -ENOMEM; + } else { + *stats_buf = stats; + isp_event->isp_data.isp_msg.len = + sizeof(struct msm_stats_buf); + isp_event->isp_data.isp_msg.data = stats_buf; + } + } + } + break; + default: + pr_err("%s: Unsupport isp notification %d\n", + __func__, notification); + rc = -EINVAL; + break; + } + + v4l2_event_queue(pmctl->config_device->config_stat_event_queue.pvdev, + &v4l2_evt); + + return rc; +} + +static int msm_isp_notify_vpe(struct v4l2_subdev *sd, void *arg) +{ + struct msm_sync *sync = + (struct msm_sync *)v4l2_get_subdev_hostdata(sd); + struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg; + if (sync == NULL) { + pr_err("%s: VPE subdev hostdata not set\n", __func__); + return -EINVAL; + } + + msm_mctl_pp_notify(&sync->pcam_sync->mctl, + (struct msm_mctl_pp_frame_info *)vdata->extdata); + return 0; +} + +static int msm_isp_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + if (notification == NOTIFY_VPE_MSG_EVT) + return msm_isp_notify_vpe(sd, arg); + else + return msm_isp_notify_vfe(sd, notification, arg); +} + +/* This function is called by open() function, so we need to init HW*/ +static int msm_isp_open(struct v4l2_subdev *sd, + struct v4l2_subdev *sd_vpe, + struct msm_sync *sync) +{ + /* init vfe and senor, register sync callbacks for init*/ + int rc = 0; + D("%s\n", __func__); + if (!sync) { + pr_err("%s: param is NULL", __func__); + return -EINVAL; + } + + + rc = msm_vfe_subdev_init(sd, sync, sync->pdev); + if (rc < 0) { + pr_err("%s: vfe_init failed at %d\n", + __func__, rc); + } + D("%s: init vpe subdev", __func__); + rc = msm_vpe_subdev_init(sd_vpe, sync, sync->pdev); + if (rc < 0) { + pr_err("%s: vpe_init failed at %d\n", + __func__, rc); + } + return rc; +} + +static void msm_isp_release(struct msm_sync *psync) +{ + D("%s\n", __func__); + msm_vfe_subdev_release(psync->pdev); + msm_vpe_subdev_release(psync->pdev); +} + +static int msm_config_vfe(struct v4l2_subdev *sd, + struct msm_sync *sync, void __user *arg) +{ + struct msm_vfe_cfg_cmd cfgcmd; + struct msm_pmem_region region[8]; + struct axidata axi_data; + + if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + memset(&axi_data, 0, sizeof(axi_data)); + CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type); + switch (cfgcmd.cmd_type) { + case CMD_STATS_AF_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_AF, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return msm_isp_subdev_ioctl(sd, &cfgcmd, + &axi_data); + case CMD_STATS_AEC_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_AEC, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return msm_isp_subdev_ioctl(sd, &cfgcmd, + &axi_data); + case CMD_STATS_AWB_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_AWB, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return msm_isp_subdev_ioctl(sd, &cfgcmd, + &axi_data); + case CMD_STATS_IHIST_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_IHIST, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return msm_isp_subdev_ioctl(sd, &cfgcmd, + &axi_data); + case CMD_STATS_RS_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_RS, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return msm_isp_subdev_ioctl(sd, &cfgcmd, + &axi_data); + case CMD_STATS_CS_ENABLE: + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, + MSM_PMEM_CS, ®ion[0], + NUM_STAT_OUTPUT_BUFFERS); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + return msm_isp_subdev_ioctl(sd, &cfgcmd, + &axi_data); + case CMD_GENERAL: + case CMD_STATS_DISABLE: + return msm_isp_subdev_ioctl(sd, &cfgcmd, + &axi_data); + default: + pr_err("%s: unknown command type %d\n", + __func__, cfgcmd.cmd_type); + } + + return -EINVAL; +} +#if 0 +static int msm_vpe_frame_cfg(struct msm_sync *sync, + void *cfgcmdin) +{ + int rc = -EIO; + struct axidata axi_data; + void *data = &axi_data; + struct msm_pmem_region region[8]; + int pmem_type; + + struct msm_vpe_cfg_cmd *cfgcmd; + cfgcmd = (struct msm_vpe_cfg_cmd *)cfgcmdin; + + memset(&axi_data, 0, sizeof(axi_data)); + CDBG("In vpe_frame_cfg cfgcmd->cmd_type = %d\n", + cfgcmd->cmd_type); + switch (cfgcmd->cmd_type) { + case CMD_AXI_CFG_VPE: + pmem_type = MSM_PMEM_VIDEO_VPE; + axi_data.bufnum1 = + msm_pmem_region_lookup_2(&sync->pmem_frames, pmem_type, + ®ion[0], 8); + CDBG("axi_data.bufnum1 = %d\n", axi_data.bufnum1); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + pmem_type = MSM_PMEM_VIDEO; + break; + default: + pr_err("%s: unknown command type %d\n", + __func__, cfgcmd->cmd_type); + break; + } + axi_data.region = ®ion[0]; + CDBG("out vpe_frame_cfg cfgcmd->cmd_type = %d\n", + cfgcmd->cmd_type); + /* send the AXI configuration command to driver */ + if (sync->vpefn.vpe_config) + rc = sync->vpefn.vpe_config(cfgcmd, data); + return rc; +} +#endif +static int msm_stats_axi_cfg(struct v4l2_subdev *sd, + struct msm_sync *sync, struct msm_vfe_cfg_cmd *cfgcmd) +{ + int rc = -EIO; + struct axidata axi_data; + void *data = &axi_data; + struct msm_pmem_region region[3]; + int pmem_type = MSM_PMEM_MAX; + + memset(&axi_data, 0, sizeof(axi_data)); + + switch (cfgcmd->cmd_type) { + case CMD_STATS_AF_AXI_CFG: + pmem_type = MSM_PMEM_AF; + break; + case CMD_GENERAL: + data = NULL; + break; + default: + pr_err("%s: unknown command type %d\n", + __func__, cfgcmd->cmd_type); + return -EINVAL; + } + + if (cfgcmd->cmd_type != CMD_GENERAL) { + axi_data.bufnum1 = + msm_pmem_region_lookup(&sync->pmem_stats, pmem_type, + ®ion[0], NUM_STAT_OUTPUT_BUFFERS); + if (!axi_data.bufnum1) { + pr_err("%s %d: pmem region lookup error\n", + __func__, __LINE__); + return -EINVAL; + } + axi_data.region = ®ion[0]; + } + + /* send the AEC/AWB STATS configuration command to driver */ + rc = msm_isp_subdev_ioctl(sd, cfgcmd, data); + return rc; +} + +static int msm_axi_config(struct v4l2_subdev *sd, + struct msm_sync *sync, void __user *arg) +{ + struct msm_vfe_cfg_cmd cfgcmd; + + if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + switch (cfgcmd.cmd_type) { + case CMD_AXI_CFG_VIDEO: + case CMD_AXI_CFG_PREVIEW: + case CMD_AXI_CFG_SNAP: + case CMD_AXI_CFG_ZSL: + case CMD_AXI_CFG_VIDEO_ALL_CHNLS: + case CMD_AXI_CFG_ZSL_ALL_CHNLS: + case CMD_RAW_PICT_AXI_CFG: + /* Dont need to pass buffer information. + * subdev will get the buffer from media + * controller free queue. + */ + return msm_isp_subdev_ioctl(sd, &cfgcmd, NULL); + case CMD_AXI_CFG_VPE: + return 0; + /* return msm_vpe_frame_cfg(sync, (void *)&cfgcmd); */ + + case CMD_STATS_AXI_CFG: + case CMD_STATS_AF_AXI_CFG: + return msm_stats_axi_cfg(sd, sync, &cfgcmd); + + default: + pr_err("%s: unknown command type %d\n", + __func__, + cfgcmd.cmd_type); + return -EINVAL; + } + + return 0; +} + +static int msm_set_crop(struct msm_sync *sync, void __user *arg) +{ + struct crop_info crop; + + if (copy_from_user(&crop, + arg, + sizeof(struct crop_info))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + if (!sync->croplen) { + sync->cropinfo = kmalloc(crop.len, GFP_KERNEL); + if (!sync->cropinfo) + return -ENOMEM; + } else if (sync->croplen < crop.len) + return -EINVAL; + + if (copy_from_user(sync->cropinfo, + crop.info, + crop.len)) { + ERR_COPY_FROM_USER(); + kfree(sync->cropinfo); + return -EFAULT; + } + + sync->croplen = crop.len; + + return 0; +} + +static int msm_put_stats_buffer(struct v4l2_subdev *sd, + struct msm_sync *sync, void __user *arg) +{ + int rc = -EIO; + + struct msm_stats_buf buf; + unsigned long pphy; + struct msm_vfe_cfg_cmd cfgcmd; + + if (copy_from_user(&buf, arg, + sizeof(struct msm_stats_buf))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + CDBG("%s\n", __func__); + pphy = msm_pmem_stats_vtop_lookup(sync, buf.buffer, buf.fd); + + if (pphy != 0) { + if (buf.type == STAT_AF) + cfgcmd.cmd_type = CMD_STATS_AF_BUF_RELEASE; + else if (buf.type == STAT_AEC) + cfgcmd.cmd_type = CMD_STATS_AEC_BUF_RELEASE; + else if (buf.type == STAT_AWB) + cfgcmd.cmd_type = CMD_STATS_AWB_BUF_RELEASE; + else if (buf.type == STAT_IHIST) + cfgcmd.cmd_type = CMD_STATS_IHIST_BUF_RELEASE; + else if (buf.type == STAT_RS) + cfgcmd.cmd_type = CMD_STATS_RS_BUF_RELEASE; + else if (buf.type == STAT_CS) + cfgcmd.cmd_type = CMD_STATS_CS_BUF_RELEASE; + + else { + pr_err("%s: invalid buf type %d\n", + __func__, + buf.type); + rc = -EINVAL; + goto put_done; + } + + cfgcmd.value = (void *)&buf; + + rc = msm_isp_subdev_ioctl(sd, &cfgcmd, &pphy); + } else { + pr_err("%s: NULL physical address\n", __func__); + rc = -EINVAL; + } + +put_done: + return rc; +} + +/* config function simliar to origanl msm_ioctl_config*/ +static int msm_isp_config(struct msm_cam_media_controller *pmctl, + unsigned int cmd, unsigned long arg) +{ + + int rc = -EINVAL; + void __user *argp = (void __user *)arg; + struct v4l2_subdev *sd = pmctl->isp_sdev->sd; + + D("%s: cmd %d\n", __func__, _IOC_NR(cmd)); + switch (cmd) { + case MSM_CAM_IOCTL_PICT_PP_DONE: + /* Release the preview of snapshot frame + * that was grabbed. + */ + /*rc = msm_pp_release(pmsm->sync, arg);*/ + break; + + case MSM_CAM_IOCTL_CONFIG_VFE: + /* Coming from config thread for update */ + rc = msm_config_vfe(sd, &pmctl->sync, argp); + break; + + case MSM_CAM_IOCTL_CONFIG_VPE: + /* Coming from config thread for update */ + /*rc = msm_config_vpe(pmsm->sync, argp);*/ + rc = 0; + break; + + case MSM_CAM_IOCTL_AXI_CONFIG: + case MSM_CAM_IOCTL_AXI_VPE_CONFIG: + D("Received MSM_CAM_IOCTL_AXI_CONFIG\n"); + rc = msm_axi_config(sd, &pmctl->sync, argp); + break; + + case MSM_CAM_IOCTL_SET_CROP: + rc = msm_set_crop(&pmctl->sync, argp); + break; + + case MSM_CAM_IOCTL_RELEASE_STATS_BUFFER: + rc = msm_put_stats_buffer(sd, &pmctl->sync, argp); + break; + + default: + break; + } + + D("%s: cmd %d DONE\n", __func__, _IOC_NR(cmd)); + + return rc; +} + +static struct msm_isp_ops isp_subdev[MSM_MAX_CAMERA_CONFIGS]; + +/**/ +int msm_isp_init_module(int g_num_config_nodes) +{ + int i = 0; + + for (i = 0; i < g_num_config_nodes; i++) { + isp_subdev[i].isp_open = msm_isp_open; + isp_subdev[i].isp_config = msm_isp_config; + isp_subdev[i].isp_release = msm_isp_release; + isp_subdev[i].isp_notify = msm_isp_notify; + } + return 0; +} +EXPORT_SYMBOL(msm_isp_init_module); + +/* +*/ +int msm_isp_register(struct msm_cam_server_dev *psvr) +{ + int i = 0; + + D("%s\n", __func__); + + BUG_ON(!psvr); + + /* Initialize notify function for v4l2_dev */ + for (i = 0; i < psvr->config_info.num_config_nodes; i++) + psvr->isp_subdev[i] = &(isp_subdev[i]); + + return 0; +} +EXPORT_SYMBOL(msm_isp_register); + +/**/ +void msm_isp_unregister(struct msm_cam_server_dev *psvr) +{ + int i = 0; + for (i = 0; i < psvr->config_info.num_config_nodes; i++) + psvr->isp_subdev[i] = NULL; +} + +int msm_isp_subdev_ioctl(struct v4l2_subdev *isp_subdev, + struct msm_vfe_cfg_cmd *cfgcmd, void *data) +{ + struct msm_camvfe_params vfe_params; + vfe_params.vfe_cfg = cfgcmd; + vfe_params.data = data; + return v4l2_subdev_call(isp_subdev, core, ioctl, 0, &vfe_params); +} + +int msm_isp_subdev_ioctl_vpe(struct v4l2_subdev *isp_subdev, + struct msm_mctl_pp_cmd *cmd, void *data) +{ + int rc = 0; + struct msm_mctl_pp_params parm; + parm.cmd = cmd; + parm.data = data; + rc = v4l2_subdev_call(isp_subdev, core, ioctl, 0, &parm); + return rc; +} diff --git a/drivers/media/video/msm_zsl/msm_ispif.c b/drivers/media/video/msm_zsl/msm_ispif.c new file mode 100644 index 00000000000..9ddb2f57c3e --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_ispif.c @@ -0,0 +1,959 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +/*[[ aswoogi_zsl*/ +#include +#include +/*]]*/ +#include +#include +#include "msm_ispif.h" +#include "msm.h" + +#define QC_TEST +#define V4L2_IDENT_ISPIF 50001 +#define CSID_VERSION_V2 0x2000011 + +/* ISPIF registers */ + +#define ISPIF_RST_CMD_ADDR 0X00 +#define ISPIF_INTF_CMD_ADDR 0X04 +#define ISPIF_CTRL_ADDR 0X08 +#define ISPIF_INPUT_SEL_ADDR 0X0C +#define ISPIF_PIX_INTF_CID_MASK_ADDR 0X10 +#define ISPIF_RDI_INTF_CID_MASK_ADDR 0X14 +#define ISPIF_PIX_1_INTF_CID_MASK_ADDR 0X38 +#define ISPIF_RDI_1_INTF_CID_MASK_ADDR 0X3C +#define ISPIF_PIX_STATUS_ADDR 0X24 +#define ISPIF_RDI_STATUS_ADDR 0X28 +#define ISPIF_RDI_1_STATUS_ADDR 0X64 +#define ISPIF_IRQ_MASK_ADDR 0X0100 +#define ISPIF_IRQ_CLEAR_ADDR 0X0104 +#define ISPIF_IRQ_STATUS_ADDR 0X0108 +#define ISPIF_IRQ_MASK_1_ADDR 0X010C +#define ISPIF_IRQ_CLEAR_1_ADDR 0X0110 +#define ISPIF_IRQ_STATUS_1_ADDR 0X0114 +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x0124 + +/*ISPIF RESET BITS*/ + +#define VFE_CLK_DOMAIN_RST 31 +#define RDI_CLK_DOMAIN_RST 30 +#define PIX_CLK_DOMAIN_RST 29 +#define AHB_CLK_DOMAIN_RST 28 +#define RDI_1_CLK_DOMAIN_RST 27 +#define RDI_1_VFE_RST_STB 13 +#define RDI_1_CSID_RST_STB 12 +#define RDI_VFE_RST_STB 7 +#define RDI_CSID_RST_STB 6 +#define PIX_VFE_RST_STB 4 +#define PIX_CSID_RST_STB 3 +#define SW_REG_RST_STB 2 +#define MISC_LOGIC_RST_STB 1 +#define STROBED_RST_EN 0 + +#define PIX_INTF_0_OVERFLOW_IRQ 12 +#define RAW_INTF_0_OVERFLOW_IRQ 25 +#define RAW_INTF_1_OVERFLOW_IRQ 25 +#define RESET_DONE_IRQ 27 + +#ifdef QC_TEST /*aswoogi_zsl */ +#define ISPIF_IRQ_STATUS_MASK 0xA497000 +#else +#define ISPIF_IRQ_STATUS_MASK 0xA493000 +#endif +#define ISPIF_IRQ_1_STATUS_MASK 0xA493000 +#define ISPIF_IRQ_STATUS_RDI_SOF_MASK 0x492000 +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1 + +#define MAX_CID 15 + +static struct ispif_device *ispif; + +static uint32_t global_intf_cmd_mask = 0xFFFFFFFF; + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_intf_reset(uint8_t intfmask) +{ + int rc = 0; + uint32_t data = 0x1; + uint8_t intfnum = 0, mask = intfmask; + while (mask != 0) { /*nsync */ + if (!(intfmask & (0x1 << intfnum))) { + mask >>= 1; + intfnum++; + continue; + } + switch (intfnum) { + case PIX0: + data = (0x1 << STROBED_RST_EN) + + (0x1 << PIX_VFE_RST_STB) + + (0x1 << PIX_CSID_RST_STB); + /*msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); */ + break; + + case RDI0: + data = (0x1 << STROBED_RST_EN) + + (0x1 << RDI_VFE_RST_STB) + + (0x1 << RDI_CSID_RST_STB); + /*msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); */ + break; + + case RDI1: + data = (0x1 << STROBED_RST_EN) + + (0x1 << RDI_1_VFE_RST_STB) + + (0x1 << RDI_1_CSID_RST_STB); + /*msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); */ + break; + + default: + rc = -EINVAL; + break; + } + mask >>= 1; + intfnum++; + } /*end while */ + if (rc >= 0) { + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + rc = wait_for_completion_interruptible(&ispif->reset_complete); + } + return rc; +} +#else +static int msm_ispif_intf_reset(uint8_t intftype) +{ + int rc = 0; + uint32_t data; + + switch (intftype) { + case PIX0: + data = (0x1 << STROBED_RST_EN) + + (0x1 << PIX_VFE_RST_STB) + (0x1 << PIX_CSID_RST_STB); + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + break; + + case RDI0: + data = (0x1 << STROBED_RST_EN) + + (0x1 << RDI_VFE_RST_STB) + (0x1 << RDI_CSID_RST_STB); + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + break; + + case RDI1: + data = (0x1 << STROBED_RST_EN) + + (0x1 << RDI_1_VFE_RST_STB) + (0x1 << RDI_1_CSID_RST_STB); + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + break; + + default: + rc = -EINVAL; + break; + } + if (rc >= 0) + rc = wait_for_completion_interruptible(&ispif->reset_complete); + + return rc; +} +#endif + +static int msm_ispif_reset(void) +{ + uint32_t data = (0x1 << STROBED_RST_EN) + + (0x1 << SW_REG_RST_STB) + + (0x1 << MISC_LOGIC_RST_STB) + + (0x1 << PIX_VFE_RST_STB) + + (0x1 << PIX_CSID_RST_STB) + + (0x1 << RDI_VFE_RST_STB) + + (0x1 << RDI_CSID_RST_STB) + + (0x1 << RDI_1_VFE_RST_STB) + (0x1 << RDI_1_CSID_RST_STB); + msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR); + return wait_for_completion_interruptible(&ispif->reset_complete); +} + +static int msm_ispif_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_ISPIF; + chip->revision = 0; + return 0; +} + +static void msm_ispif_sel_csid_core(uint8_t intftype, uint8_t csid) +{ + int rc = 0; + uint32_t data; + if (ispif->ispif_clk[intftype] == NULL) { + pr_err("%s: ispif NULL clk\n", __func__); + return; + } + + rc = clk_set_rate(ispif->ispif_clk[intftype], csid); + if (rc < 0) + pr_err("%s: clk_set_rate failed %d\n", __func__, rc); + + data = msm_io_r(ispif->base + ISPIF_INPUT_SEL_ADDR); + data |= csid << (intftype * 4); + msm_io_w(data, ispif->base + ISPIF_INPUT_SEL_ADDR); +} + +static void msm_ispif_enable_intf_cids(uint8_t intftype, uint16_t cid_mask) +{ + uint32_t data; + mutex_lock(&ispif->mutex); + switch (intftype) { + case PIX0: + data = msm_io_r(ispif->base + ISPIF_PIX_INTF_CID_MASK_ADDR); + data |= cid_mask; + msm_io_w(data, ispif->base + ISPIF_PIX_INTF_CID_MASK_ADDR); + break; + + case RDI0: + data = msm_io_r(ispif->base + ISPIF_RDI_INTF_CID_MASK_ADDR); + data |= cid_mask; + msm_io_w(data, ispif->base + ISPIF_RDI_INTF_CID_MASK_ADDR); + break; + + case RDI1: + data = msm_io_r(ispif->base + ISPIF_RDI_1_INTF_CID_MASK_ADDR); + data |= cid_mask; + msm_io_w(data, ispif->base + ISPIF_RDI_1_INTF_CID_MASK_ADDR); + break; + } + mutex_unlock(&ispif->mutex); +} + +static int msm_ispif_config(struct msm_ispif_params_list *params_list) +{ + uint32_t params_len; + struct msm_ispif_params *ispif_params; + uint32_t data, data1; + int rc = 0, i = 0; + params_len = params_list->len; + ispif_params = params_list->params; + CDBG("Enable interface\n"); + data = msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR); + data1 = msm_io_r(ispif->base + ISPIF_RDI_STATUS_ADDR); + if (((data & 0xf) != 0xf) || ((data1 & 0xf) != 0xf)) + return -EBUSY; + msm_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_ADDR); + for (i = 0; i < params_len; i++) { + msm_ispif_sel_csid_core(ispif_params[i].intftype, + ispif_params[i].csid); + msm_ispif_enable_intf_cids(ispif_params[i].intftype, + ispif_params[i].cid_mask); + } + + msm_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + ISPIF_IRQ_MASK_ADDR); + msm_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + ISPIF_IRQ_CLEAR_ADDR); + msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + /* test: Qualcomm */ +#ifndef QC_TEST /*aswoogi_zsl*/ + CDBG("Dumping ISPIF registers\n"); +/* + msm_io_w(ISPIF_IRQ_STATUS_MASK | 0x18, ispif->base + + ISPIF_IRQ_MASK_ADDR); + msm_io_w(ISPIF_IRQ_STATUS_MASK | 0x18, ispif->base + + ISPIF_IRQ_CLEAR_ADDR); + msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); +*/ + msm_io_dump(ispif->base, 500); + CDBG("Hardcoding some other ISPIF registers\n"); + /*msm_io_w(0x00000000, ispif->base + 0x0004);*/ + msm_io_w(0x0001, ispif->base + 0x0010); + /* msm_io_w(0x0004, ispif->base + 0x0014); */ + +#endif + + return rc; +} + +static uint32_t msm_ispif_get_cid_mask(uint8_t intftype) +{ + uint32_t mask = 0; + switch (intftype) { + case PIX0: + mask = msm_io_r(ispif->base + ISPIF_PIX_INTF_CID_MASK_ADDR); + break; + + case RDI0: + mask = msm_io_r(ispif->base + ISPIF_RDI_INTF_CID_MASK_ADDR); + break; + + case RDI1: + mask = msm_io_r(ispif->base + ISPIF_RDI_1_INTF_CID_MASK_ADDR); + break; + + default: + break; + } + return mask; +} + +#ifdef QC_TEST /*aswoogi_zsl */ +static void msm_ispif_intf_cmd(uint8_t intfmask, uint8_t intf_cmd_mask) +{ + uint8_t vc = 0, val = 0; + uint8_t mask = intfmask, intfnum = 0; + uint32_t cid_mask = 0; + while (mask != 0) { + if (!(intfmask & (0x1 << intfnum))) { /*nsync */ + mask >>= 1; + intfnum++; + continue; + } + + cid_mask = msm_ispif_get_cid_mask(intfnum); + vc = 0; + + while (cid_mask != 0) { + if ((cid_mask & 0xf) != 0x0) { + val = (intf_cmd_mask >> (vc * 2)) & 0x3; + global_intf_cmd_mask |= + (0x3 << ((vc * 2) + (intfnum * 8))); + global_intf_cmd_mask &= ~((0x3 & ~val) + << ((vc * 2) + + (intfnum * 8))); + CDBG("nishu intf cmd 0x%x\n", + global_intf_cmd_mask); + } + vc++; + cid_mask >>= 4; + } + mask >>= 1; + intfnum++; + } + msm_io_w(global_intf_cmd_mask, ispif->base + ISPIF_INTF_CMD_ADDR); +} +#else +static void msm_ispif_intf_cmd(uint8_t intftype, uint8_t intf_cmd_mask) +{ + uint8_t vc = 0, val = 0; + uint32_t cid_mask = msm_ispif_get_cid_mask(intftype); + + while (cid_mask != 0) { + if ((cid_mask & 0xf) != 0x0) { + val = (intf_cmd_mask >> (vc * 2)) & 0x3; + global_intf_cmd_mask &= ~((0x3 & ~val) + << ((vc * 2) + + (intftype * 8))); + CDBG("intf cmd 0x%x\n", global_intf_cmd_mask); + msm_io_w(global_intf_cmd_mask, + ispif->base + ISPIF_INTF_CMD_ADDR); + } + vc++; + cid_mask >>= 4; + } +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_abort_intf_transfer(uint8_t intfmask) +{ + int rc = 0; + uint8_t intf_cmd_mask = 0xAA; + uint8_t intfnum = 0, mask = intfmask; + + pr_err("abort stream request %d\n", intfmask); + /*mutex_lock(&ispif->mutex); */ + msm_ispif_intf_cmd(intfmask, intf_cmd_mask); + /*rc = msm_ispif_intf_reset(intf); */ + while (mask != 0) { + if (mask & (0x1 << intfnum)) + global_intf_cmd_mask |= 0xFF << (intfnum * 8); + mask >>= 1; + intfnum++; + } + /*mutex_unlock(&ispif->mutex); */ + return rc; +} +#else +static int msm_ispif_abort_intf_transfer(uint8_t intf) +{ + int rc = 0; + uint8_t intf_cmd_mask = 0xAA; + + CDBG("abort stream request\n"); + mutex_lock(&ispif->mutex); + msm_ispif_intf_cmd(intf, intf_cmd_mask); + rc = msm_ispif_intf_reset(intf); + global_intf_cmd_mask |= 0xFF << (intf * 8); + mutex_unlock(&ispif->mutex); + return rc; +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_start_intf_transfer(uint8_t intfmask) +{ + uint32_t data; + uint8_t intf_cmd_mask = 0x55; + int rc = 0; + + CDBG("start stream request %d\n", intfmask); + mutex_lock(&ispif->mutex); + rc = msm_ispif_intf_reset(intfmask); /*nishu */ + /*switch (intfmask) {//nsync + case PIX0: + data = msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR); + break; + + case RDI0: + data = msm_io_r(ispif->base + ISPIF_RDI_STATUS_ADDR); + ispif->start_ack_pending = 1; + break; + + case RDI1: + data = msm_io_r(ispif->base + ISPIF_RDI_1_STATUS_ADDR); + ispif->start_ack_pending = 1; + break; + } */ + msm_ispif_intf_cmd(intfmask, intf_cmd_mask); + if (intfmask & 0xb) { + CDBG("pix 0-rdi0-rdi1 interface\n"); + msm_io_dump1(ispif->base, 0x150); + } + mutex_unlock(&ispif->mutex); + return rc; +} +#else +static int msm_ispif_start_intf_transfer(uint8_t intf) +{ + uint32_t data; + uint8_t intf_cmd_mask = 0x55; + int rc = 0; + + CDBG("start stream request\n"); + mutex_lock(&ispif->mutex); + switch (intf) { + case PIX0: + data = msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR); + if ((data & 0xf) != 0xf) { + CDBG("interface is busy\n"); + mutex_unlock(&ispif->mutex); + return -EBUSY; + } + break; + + case RDI0: + data = msm_io_r(ispif->base + ISPIF_RDI_STATUS_ADDR); + ispif->start_ack_pending = 1; + break; + + case RDI1: + data = msm_io_r(ispif->base + ISPIF_RDI_1_STATUS_ADDR); + ispif->start_ack_pending = 1; + break; + } + msm_ispif_intf_cmd(intf, intf_cmd_mask); + mutex_unlock(&ispif->mutex); + return rc; +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_stop_intf_transfer(uint8_t intfmask) +{ + int rc = 0; + uint8_t intf_cmd_mask = 0x00; + uint8_t intfnum = 0, mask = intfmask; + CDBG("stop stream request %d\n", intfmask); + /*mutex_lock(&ispif->mutex); */ /*nishu*/ + msm_ispif_intf_cmd(intfmask, intf_cmd_mask); + switch (intfnum) { /*nsync change later*/ + case PIX0: +/* while ((msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR) //nsync + & 0xf) != 0xf) { + CDBG("Wait for Idle\n"); + } + break; +*/ + case RDI0: + case RDI1: + break; + default: + break; + } + while (mask != 0) { /*nsyncs */ + if (mask & (0x1 << intfnum)) + global_intf_cmd_mask |= 0xFF << (intfnum * 8); + mask >>= 1; + intfnum++; + } + /*mutex_unlock(&ispif->mutex); */ + return rc; +} +#else +static int msm_ispif_stop_intf_transfer(uint8_t intf) +{ + int rc = 0; + uint8_t intf_cmd_mask = 0x00; + CDBG("stop stream request\n"); + mutex_lock(&ispif->mutex); + msm_ispif_intf_cmd(intf, intf_cmd_mask); + switch (intf) { + case PIX0: + while ((msm_io_r(ispif->base + ISPIF_PIX_STATUS_ADDR) + & 0xf) != 0xf) { + CDBG("Wait for Idle\n"); + } + break; + + case RDI0: + while ((msm_io_r(ispif->base + ISPIF_RDI_STATUS_ADDR) + & 0xf) != 0xf) { + CDBG("Wait for Idle\n"); + } + break; + default: + break; + } + global_intf_cmd_mask |= 0xFF << (intf * 8); + mutex_unlock(&ispif->mutex); + return rc; +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_subdev_video_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + int32_t cmd = enable & ((1 << ISPIF_S_STREAM_SHIFT) - 1); + uint8_t intfmask = enable >> ISPIF_S_STREAM_SHIFT; + int rc = -EINVAL; + + BUG_ON(!ispif); + switch (cmd) { + case ISPIF_ON_FRAME_BOUNDARY: + +/*Qualcomm: Front camera hack*/ + intfmask = 11; + rc = msm_ispif_start_intf_transfer(intfmask); + break; + case ISPIF_OFF_FRAME_BOUNDARY: + rc = msm_ispif_stop_intf_transfer(intfmask); + break; + case ISPIF_OFF_IMMEDIATELY: + rc = msm_ispif_abort_intf_transfer(intfmask); + break; + default: + break; + } + return rc; +} +#else +static int msm_ispif_subdev_video_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + int32_t cmd = enable & ((1 << ISPIF_S_STREAM_SHIFT) - 1); + enum msm_ispif_intftype intf = enable >> ISPIF_S_STREAM_SHIFT; + int rc = -EINVAL; + + BUG_ON(!ispif); + switch (cmd) { + case ISPIF_ON_FRAME_BOUNDARY: + rc = msm_ispif_start_intf_transfer(intf); + break; + case ISPIF_OFF_FRAME_BOUNDARY: + rc = msm_ispif_stop_intf_transfer(intf); + break; + case ISPIF_OFF_IMMEDIATELY: + rc = msm_ispif_abort_intf_transfer(intf); + break; + default: + break; + } + return rc; +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +atomic_t ispif_irq_cnt; +spinlock_t ispif_tasklet_lock; +struct list_head ispif_tasklet_q; + +struct ispif_isr_queue_cmd { + struct list_head list; + uint32_t ispifInterruptStatus0; + uint32_t ispifInterruptStatus1; +}; + +static void ispif_do_tasklet(unsigned long data) +{ + unsigned long flags; + + struct ispif_isr_queue_cmd *qcmd = NULL; + + CDBG("=== ispif_do_tasklet start ===\n"); + + while (atomic_read(&ispif_irq_cnt)) { + spin_lock_irqsave(&ispif_tasklet_lock, flags); + qcmd = list_first_entry(&ispif_tasklet_q, + struct ispif_isr_queue_cmd, list); + atomic_sub(1, &ispif_irq_cnt); + + if (!qcmd) { + spin_unlock_irqrestore(&ispif_tasklet_lock, flags); + return; + } + + list_del(&qcmd->list); + spin_unlock_irqrestore(&ispif_tasklet_lock, flags); + + if (qcmd->ispifInterruptStatus0 & + ISPIF_IRQ_STATUS_RDI_SOF_MASK) { + CDBG("ispif rdi irq status\n"); + vfe32_process_ispif_sof_irq(); + } + if (qcmd->ispifInterruptStatus1 & + ISPIF_IRQ_STATUS_RDI_SOF_MASK) + CDBG("ispif rdi1 irq status\n"); + + kfree(qcmd); + } + CDBG("=== ispif_do_tasklet end ===\n"); +} + +DECLARE_TASKLET(ispif_tasklet, ispif_do_tasklet, 0); + +static void ispif_process_irq(struct ispif_irq_status *out) +{ + unsigned long flags; + struct ispif_isr_queue_cmd *qcmd; + + CDBG("ispif_process_irq\n"); + + qcmd = kzalloc(sizeof(struct ispif_isr_queue_cmd), GFP_ATOMIC); + if (!qcmd) { + pr_err("ispif_process_irq: qcmd malloc failed!\n"); + return; + } + qcmd->ispifInterruptStatus0 = out->ispifIrqStatus0; + qcmd->ispifInterruptStatus1 = out->ispifIrqStatus1; + + spin_lock_irqsave(&ispif_tasklet_lock, flags); + list_add_tail(&qcmd->list, &ispif_tasklet_q); + + atomic_add(1, &ispif_irq_cnt); + spin_unlock_irqrestore(&ispif_tasklet_lock, flags); + tasklet_schedule(&ispif_tasklet); + return; +} +#endif + +#ifdef QC_TEST /*aswoogi_zsl */ +static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out) +{ + out->ispifIrqStatus0 = msm_io_r(ispif->base + ISPIF_IRQ_STATUS_ADDR); + out->ispifIrqStatus1 = msm_io_r(ispif->base + ISPIF_IRQ_STATUS_1_ADDR); + CDBG("nishu ispif->irq: Irq_status0 = 0x%x\n", + out->ispifIrqStatus0);/*nishu */ + msm_io_w(out->ispifIrqStatus0, ispif->base + ISPIF_IRQ_CLEAR_ADDR); + msm_io_w(out->ispifIrqStatus1, ispif->base + ISPIF_IRQ_CLEAR_1_ADDR); + + if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) { + if (out->ispifIrqStatus0 & (0x1 << RESET_DONE_IRQ)) + complete(&ispif->reset_complete); + if (out->ispifIrqStatus0 & (0x1 << PIX_INTF_0_OVERFLOW_IRQ)) + pr_err("%s: pix intf 0 overflow.\n", __func__); + if (out->ispifIrqStatus0 & (0x1 << RAW_INTF_0_OVERFLOW_IRQ)) + pr_err("%s: rdi intf 0 overflow.\n", __func__); + if ((out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_RDI_SOF_MASK) || + (out->ispifIrqStatus1 & ISPIF_IRQ_STATUS_RDI_SOF_MASK)) { + ispif_process_irq(out); + } + } + /*msm_io_w(out->ispifIrqStatus0,nishu */ + /*ispif->base + ISPIF_IRQ_CLEAR_ADDR); */ + msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); +} +#else +static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out) +{ + out->ispifIrqStatus0 = msm_io_r(ispif->base + ISPIF_IRQ_STATUS_ADDR); + CDBG("ispif->irq: Irq_status0 = 0x%x\n", out->ispifIrqStatus0); + if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) { + if (out->ispifIrqStatus0 & (0x1 << RESET_DONE_IRQ)) + complete(&ispif->reset_complete); + if (out->ispifIrqStatus0 & (0x1 << PIX_INTF_0_OVERFLOW_IRQ)) + pr_err("%s: pix intf 0 overflow.\n", __func__); + if (out->ispifIrqStatus0 & (0x1 << RAW_INTF_0_OVERFLOW_IRQ)) + pr_err("%s: rdi intf 0 overflow.\n", __func__); + if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_RDI_SOF_MASK) { + if (ispif->start_ack_pending) { + v4l2_subdev_notify(&ispif->subdev, + NOTIFY_ISP_MSG_EVT, + (void *)MSG_ID_START_ACK); + ispif->start_ack_pending = 0; + /* stop stream at frame boundary */ + msm_ispif_stop_intf_transfer(RDI0); + } + v4l2_subdev_notify(&ispif->subdev, NOTIFY_ISP_MSG_EVT, + (void *)MSG_ID_SOF_ACK); + } + } + msm_io_w(out->ispifIrqStatus0, ispif->base + ISPIF_IRQ_CLEAR_ADDR); + msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); +} +#endif + +static irqreturn_t msm_io_ispif_irq(int irq_num, void *data) +{ + struct ispif_irq_status irq; + msm_ispif_read_irq_status(&irq); + return IRQ_HANDLED; +} + +static struct msm_cam_clk_info ispif_clk_info[] = { + {"csi_pix_clk", 0}, + {"csi_rdi_clk", 0}, + {"csi_pix1_clk", 0}, + {"csi_rdi1_clk", 0}, + {"csi_rdi2_clk", 0}, +}; + +#ifdef QC_TEST /*aswoogi_zsl */ +static int msm_ispif_init(const uint32_t *csid_version) +{ + int rc = 0; + spin_lock_init(&ispif_tasklet_lock); /*nishu */ + INIT_LIST_HEAD(&ispif_tasklet_q); + rc = request_irq(ispif->irq->start, msm_io_ispif_irq, + IRQF_TRIGGER_RISING, "ispif", 0); + + global_intf_cmd_mask = 0xFFFFFFFF; + init_completion(&ispif->reset_complete); + + ispif->csid_version = *csid_version; + if (ispif->csid_version == CSID_VERSION_V2) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, + ARRAY_SIZE(ispif_clk_info), 1); + if (rc < 0) + return rc; + } else { + rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, 2, 1); + if (rc < 0) + return rc; + } + + rc = msm_ispif_reset(); + return rc; +} + +static void msm_ispif_release(struct v4l2_subdev *sd) +{ + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + + if (ispif->csid_version == CSID_VERSION_V2) + msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, ARRAY_SIZE(ispif_clk_info), + 0); + else + msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, 2, 0); + + CDBG("%s, free_irq\n", __func__); + free_irq(ispif->irq->start, 0); + tasklet_kill(&ispif_tasklet); /*nishu */ +} +#else +static int msm_ispif_init(const uint32_t *csid_version) +{ + int rc = 0; + rc = request_irq(ispif->irq->start, msm_io_ispif_irq, + IRQF_TRIGGER_RISING, "ispif", 0); + + global_intf_cmd_mask = 0xFFFFFFFF; + init_completion(&ispif->reset_complete); + + ispif->csid_version = *csid_version; + if (ispif->csid_version == CSID_VERSION_V2) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, + ARRAY_SIZE(ispif_clk_info), 1); + if (rc < 0) + return rc; + } else { + rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, 2, 1); + if (rc < 0) + return rc; + } + + rc = msm_ispif_reset(); + return rc; +} + +static void msm_ispif_release(struct v4l2_subdev *sd) +{ + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + + if (ispif->csid_version == CSID_VERSION_V2) + msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, ARRAY_SIZE(ispif_clk_info), + 0); + else + msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info, + ispif->ispif_clk, 2, 0); + + CDBG("%s, free_irq\n", __func__); + free_irq(ispif->irq->start, 0); +} +#endif + +void msm_ispif_vfe_get_cid(uint8_t intftype, char *cids, int *num) +{ + uint32_t data = 0; + int i = 0, j = 0; + switch (intftype) { + case PIX0: + data = msm_io_r(ispif->base + ISPIF_PIX_INTF_CID_MASK_ADDR); + break; + + case RDI0: + data = msm_io_r(ispif->base + ISPIF_RDI_INTF_CID_MASK_ADDR); + break; + + case RDI1: + data = msm_io_r(ispif->base + ISPIF_RDI_1_INTF_CID_MASK_ADDR); + break; + + default: + break; + } + for (i = 0; i <= MAX_CID; i++) { + if ((data & 0x1) == 0x1) { + cids[j++] = i; + (*num)++; + } + data >>= 1; + } +} + +static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, + void *arg) +{ + switch (cmd) { + case VIDIOC_MSM_ISPIF_CFG: + return msm_ispif_config((struct msm_ispif_params_list *)arg); + case VIDIOC_MSM_ISPIF_INIT: + return msm_ispif_init((uint32_t *) arg); + case VIDIOC_MSM_ISPIF_RELEASE: + msm_ispif_release(sd); + default: + return -ENOIOCTLCMD; + } +} + +static struct v4l2_subdev_core_ops msm_ispif_subdev_core_ops = { + .g_chip_ident = &msm_ispif_subdev_g_chip_ident, + .ioctl = &msm_ispif_subdev_ioctl, +}; + +static struct v4l2_subdev_video_ops msm_ispif_subdev_video_ops = { + .s_stream = &msm_ispif_subdev_video_s_stream, +}; + +static const struct v4l2_subdev_ops msm_ispif_subdev_ops = { + .core = &msm_ispif_subdev_core_ops, + .video = &msm_ispif_subdev_video_ops, +}; + +static int __devinit ispif_probe(struct platform_device *pdev) +{ + int rc = 0; + CDBG("%s\n", __func__); + ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL); + if (!ispif) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + v4l2_subdev_init(&ispif->subdev, &msm_ispif_subdev_ops); + v4l2_set_subdevdata(&ispif->subdev, ispif); + platform_set_drvdata(pdev, &ispif->subdev); + snprintf(ispif->subdev.name, sizeof(ispif->subdev.name), "ispif"); + mutex_init(&ispif->mutex); + + ispif->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "ispif"); + if (!ispif->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto ispif_no_resource; + } + ispif->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "ispif"); + if (!ispif->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto ispif_no_resource; + } + ispif->io = request_mem_region(ispif->mem->start, + resource_size(ispif->mem), pdev->name); + if (!ispif->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto ispif_no_resource; + } + ispif->base = ioremap(ispif->mem->start, resource_size(ispif->mem)); + if (!ispif->base) { + rc = -ENOMEM; + goto ispif_no_mem; + } + + ispif->pdev = pdev; + return 0; + +ispif_no_mem: + release_mem_region(ispif->mem->start, resource_size(ispif->mem)); +ispif_no_resource: + mutex_destroy(&ispif->mutex); + kfree(ispif); + return rc; +} + +static struct platform_driver ispif_driver = { + .probe = ispif_probe, + .driver = { + .name = MSM_ISPIF_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_ispif_init_module(void) +{ + return platform_driver_register(&ispif_driver); +} + +static void __exit msm_ispif_exit_module(void) +{ + platform_driver_unregister(&ispif_driver); +} + +module_init(msm_ispif_init_module); +module_exit(msm_ispif_exit_module); +MODULE_DESCRIPTION("MSM ISP Interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/msm_mctl.c b/drivers/media/video/msm_zsl/msm_mctl.c new file mode 100644 index 00000000000..3d459ebbc9d --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_mctl.c @@ -0,0 +1,772 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "msm.h" +#include "msm_csid.h" +#include "msm_csiphy.h" +#include "msm_ispif.h" + +#ifdef CONFIG_MSM_CAMERA_DEBUG +#define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args) +#else +#define D(fmt, args...) do {} while (0) +#endif + +#define MSM_V4L2_SWFI_LATENCY 3 + +/* VFE required buffer number for streaming */ +static struct msm_isp_color_fmt msm_isp_formats[] = { + { + .name = "NV12YUV", + .depth = 12, + .bitsperpxl = 8, + .fourcc = V4L2_PIX_FMT_NV12, + .pxlcode = V4L2_MBUS_FMT_YUYV8_2X8, /* YUV sensor */ + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + .name = "NV21YUV", + .depth = 12, + .bitsperpxl = 8, + .fourcc = V4L2_PIX_FMT_NV21, + .pxlcode = V4L2_MBUS_FMT_YUYV8_2X8, /* YUV sensor */ + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + .name = "NV12BAYER", + .depth = 8, + .bitsperpxl = 8, + .fourcc = V4L2_PIX_FMT_NV12, + .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */ + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + .name = "NV21BAYER", + .depth = 8, + .bitsperpxl = 8, + .fourcc = V4L2_PIX_FMT_NV21, + .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */ + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + .name = "YU12BAYER", + .depth = 8, + .bitsperpxl = 8, + .fourcc = V4L2_PIX_FMT_YUV420M, + .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */ + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + .name = "RAWBAYER", + .depth = 10, + .bitsperpxl = 10, + .fourcc = V4L2_PIX_FMT_SBGGR10, + .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */ + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + .name = "NV16BAYER", + .depth = 8, + .bitsperpxl = 8, + .fourcc = V4L2_PIX_FMT_NV16, + .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */ + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + .name = "NV61BAYER", + .depth = 8, + .bitsperpxl = 8, + .fourcc = V4L2_PIX_FMT_NV61, + .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */ + .colorspace = V4L2_COLORSPACE_JPEG, + }, +}; + +/* + * V4l2 subdevice operations + */ +static int mctl_subdev_log_status(struct v4l2_subdev *sd) +{ + return -EINVAL; +} + +static long mctl_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_cam_media_controller *pmctl = NULL; + if (!sd) { + pr_err("%s: param is NULL", __func__); + return -EINVAL; + } else + pmctl = (struct msm_cam_media_controller *) + v4l2_get_subdevdata(sd); + + + return -EINVAL; +} + + +static int mctl_subdev_g_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + return -EINVAL; +} + +static struct v4l2_subdev_core_ops mctl_subdev_core_ops = { + .log_status = mctl_subdev_log_status, + .ioctl = mctl_subdev_ioctl, +}; + +static struct v4l2_subdev_video_ops mctl_subdev_video_ops = { + .g_mbus_fmt = mctl_subdev_g_mbus_fmt, +}; + +static struct v4l2_subdev_ops mctl_subdev_ops = { + .core = &mctl_subdev_core_ops, + .video = &mctl_subdev_video_ops, +}; + +static int msm_get_sensor_info(struct msm_sync *sync, + void __user *arg) +{ + int rc = 0; + struct msm_camsensor_info info; + struct msm_camera_sensor_info *sdata; + + if (copy_from_user(&info, + arg, + sizeof(struct msm_camsensor_info))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + sdata = sync->pdev->dev.platform_data; + D("%s: sensor_name %s\n", __func__, sdata->sensor_name); + + memcpy(&info.name[0], sdata->sensor_name, MAX_SENSOR_NAME); + info.flash_enabled = sdata->flash_data->flash_type != + MSM_CAMERA_FLASH_NONE; + + /* copy back to user space */ + if (copy_to_user((void *)arg, + &info, + sizeof(struct msm_camsensor_info))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + } + + return rc; +} + +/* called by other subdev to notify any changes*/ + +static int msm_mctl_notify(struct msm_cam_media_controller *p_mctl, + unsigned int notification, void *arg) +{ + int rc = -EINVAL; + struct msm_camera_sensor_info *sinfo = + p_mctl->plat_dev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + uint8_t csid_core = camdev->csid_core; + switch (notification) { + case NOTIFY_CID_CHANGE: +#if defined(REMOVE_TEMP) /*aswoogi_zsl*/ + /* reconfig the ISPIF*/ + if (p_mctl->ispif_sdev) { + struct msm_ispif_params_list ispif_params; + ispif_params.len = 1; + ispif_params.params[0].intftype = PIX0; + ispif_params.params[0].cid_mask = 0x0001; + ispif_params.params[0].csid = csid_core; + + rc = v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl, + VIDIOC_MSM_ISPIF_CFG, &ispif_params); + if (rc < 0) + return rc; + } +#else + /* reconfig the ISPIF*/ + if (p_mctl->ispif_sdev) { + struct msm_ispif_params_list ispif_params; + ispif_params.len = 3; + ispif_params.params[0].intftype = PIX0; + ispif_params.params[0].cid_mask = 0x0001; + ispif_params.params[0].csid = csid_core; + + ispif_params.params[1].intftype = RDI0;/*nishu*/ + ispif_params.params[1].cid_mask = 0x0004; + ispif_params.params[1].csid = csid_core; + + ispif_params.params[2].intftype = RDI1;/*nishu*/ + ispif_params.params[2].cid_mask = 0x0002;/*metadata*/ + ispif_params.params[2].csid = csid_core; + + rc = v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl, + VIDIOC_MSM_ISPIF_CFG, &ispif_params); + if (rc < 0) + return rc; + } +#endif + break; + case NOTIFY_ISPIF_STREAM: + /* call ISPIF stream on/off */ + rc = v4l2_subdev_call(p_mctl->ispif_sdev, video, + s_stream, (int)arg); + if (rc < 0) + return rc; + + break; + case NOTIFY_ISP_MSG_EVT: + case NOTIFY_VFE_MSG_OUT: + case NOTIFY_VFE_MSG_STATS: + case NOTIFY_VFE_BUF_EVT: + if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) { + rc = p_mctl->isp_sdev->isp_notify( + p_mctl->isp_sdev->sd, notification, arg); + } + break; + case NOTIFY_VPE_MSG_EVT: + if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) { + rc = p_mctl->isp_sdev->isp_notify( + p_mctl->isp_sdev->sd_vpe, notification, arg); + } + break; + case NOTIFY_PCLK_CHANGE: + rc = v4l2_subdev_call(p_mctl->isp_sdev->sd, video, + s_crystal_freq, *(uint32_t *)arg, 0); + break; + case NOTIFY_CSIPHY_CFG: + rc = v4l2_subdev_call(p_mctl->csiphy_sdev, + core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg); + break; + case NOTIFY_CSID_CFG: + rc = v4l2_subdev_call(p_mctl->csid_sdev, + core, ioctl, VIDIOC_MSM_CSID_CFG, arg); + break; + default: + break; + } + + return rc; +} + +/* called by the server or the config nodes to handle user space + commands*/ +static int msm_mctl_cmd(struct msm_cam_media_controller *p_mctl, + unsigned int cmd, unsigned long arg) +{ + int rc = -EINVAL; + void __user *argp = (void __user *)arg; + if (!p_mctl) { + pr_err("%s: param is NULL", __func__); + return -EINVAL; + } + D("%s cmd = %d\n", __func__, _IOC_NR(cmd)); + + /* ... call sensor, ISPIF or VEF subdev*/ + switch (cmd) { + /* sensor config*/ + case MSM_CAM_IOCTL_GET_SENSOR_INFO: + rc = msm_get_sensor_info(&p_mctl->sync, argp); + break; + + case MSM_CAM_IOCTL_SENSOR_IO_CFG: + rc = p_mctl->sync.sctrl.s_config(argp); + break; + + case MSM_CAM_IOCTL_SENSOR_V4l2_S_CTRL: { + struct v4l2_control v4l2_ctrl; + CDBG("subdev call\n"); + if (copy_from_user(&v4l2_ctrl, + (void *)argp, + sizeof(struct v4l2_control))) { + CDBG("copy fail\n"); + return -EFAULT; + } + CDBG("subdev call ok\n"); + rc = v4l2_subdev_call(p_mctl->sensor_sdev, + core, s_ctrl, &v4l2_ctrl); + break; + } + + case MSM_CAM_IOCTL_SENSOR_V4l2_QUERY_CTRL: { + struct v4l2_queryctrl v4l2_qctrl; + CDBG("query called\n"); + if (copy_from_user(&v4l2_qctrl, + (void *)argp, + sizeof(struct v4l2_queryctrl))) { + CDBG("copy fail\n"); + rc = -EFAULT; + break; + } + rc = v4l2_subdev_call(p_mctl->sensor_sdev, + core, queryctrl, &v4l2_qctrl); + if (rc < 0) { + rc = -EFAULT; + break; + } + if (copy_to_user((void *)argp, + &v4l2_qctrl, + sizeof(struct v4l2_queryctrl))) { + rc = -EFAULT; + } + break; + } + + case MSM_CAM_IOCTL_ACTUATOR_IO_CFG: { + struct msm_actuator_cfg_data act_data; + if (p_mctl->sync.actctrl.a_config) { + rc = p_mctl->sync.actctrl.a_config(argp); + } else { + rc = copy_from_user( + &act_data, + (void *)argp, + sizeof(struct msm_actuator_cfg_data)); + if (rc != 0) { + rc = -EFAULT; + break; + } + act_data.is_af_supported = 0; + rc = copy_to_user((void *)argp, + &act_data, + sizeof(struct msm_actuator_cfg_data)); + if (rc != 0) { + rc = -EFAULT; + break; + } + } + break; + } + + case MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME: { + struct timeval timestamp; + if (copy_from_user(×tamp, argp, sizeof(timestamp))) { + ERR_COPY_FROM_USER(); + rc = -EFAULT; + } else { + msm_mctl_gettimeofday(×tamp); + rc = copy_to_user((void *)argp, + ×tamp, sizeof(timestamp)); + } + break; + } + + case MSM_CAM_IOCTL_FLASH_CTRL: { + struct flash_ctrl_data flash_info; + if (copy_from_user(&flash_info, argp, sizeof(flash_info))) { + ERR_COPY_FROM_USER(); + rc = -EFAULT; + } else { + rc = msm_flash_ctrl(p_mctl->sync.sdata, &flash_info); + } + break; + } + case MSM_CAM_IOCTL_PICT_PP: + rc = msm_mctl_set_pp_key(p_mctl, (void __user *)arg); + break; + case MSM_CAM_IOCTL_PICT_PP_DIVERT_DONE: + rc = msm_mctl_pp_divert_done(p_mctl, (void __user *)arg); + break; + case MSM_CAM_IOCTL_PICT_PP_DONE: + rc = msm_mctl_pp_done(p_mctl, (void __user *)arg); + break; + case MSM_CAM_IOCTL_MCTL_POST_PROC: + rc = msm_mctl_pp_ioctl(p_mctl, cmd, arg); + break; + case MSM_CAM_IOCTL_RESERVE_FREE_FRAME: + rc = msm_mctl_pp_reserve_free_frame(p_mctl, + (void __user *)arg); + break; + case MSM_CAM_IOCTL_RELEASE_FREE_FRAME: + rc = msm_mctl_pp_release_free_frame(p_mctl, + (void __user *)arg); + break; + /* ISFIF config*/ + default: + /* ISP config*/ + rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg); + break; + } + D("%s: !!! cmd = %d, rc = %d\n", + __func__, _IOC_NR(cmd), rc); + return rc; +} + +static int msm_mctl_subdev_match_core(struct device *dev, void *data) +{ + int core_index = (int)data; + struct platform_device *pdev = to_platform_device(dev); + + if (pdev->id == core_index) + return 1; + else + return 0; +} + +static int msm_mctl_register_subdevs(struct msm_cam_media_controller *p_mctl, + int core_index) +{ + struct device_driver *driver; + struct device *dev; + int rc = -ENODEV; + + /* register csiphy subdev */ + driver = driver_find(MSM_CSIPHY_DRV_NAME, &platform_bus_type); + if (!driver) + goto out; + + dev = driver_find_device(driver, NULL, (void *)core_index, + msm_mctl_subdev_match_core); + if (!dev) + goto out_put_driver; + + p_mctl->csiphy_sdev = dev_get_drvdata(dev); +// put_driver(driver); + + /* register csid subdev */ + driver = driver_find(MSM_CSID_DRV_NAME, &platform_bus_type); + if (!driver) + goto out; + + dev = driver_find_device(driver, NULL, (void *)core_index, + msm_mctl_subdev_match_core); + if (!dev) + goto out_put_driver; + + p_mctl->csid_sdev = dev_get_drvdata(dev); +// put_driver(driver); + + /* register ispif subdev */ + driver = driver_find(MSM_ISPIF_DRV_NAME, &platform_bus_type); + if (!driver) + goto out; + + dev = driver_find_device(driver, NULL, 0, + msm_mctl_subdev_match_core); + if (!dev) + goto out_put_driver; + + p_mctl->ispif_sdev = dev_get_drvdata(dev); +// put_driver(driver); + + /* register vfe subdev */ + driver = driver_find(MSM_VFE_DRV_NAME, &platform_bus_type); + if (!driver) + goto out; + + dev = driver_find_device(driver, NULL, 0, + msm_mctl_subdev_match_core); + if (!dev) + goto out_put_driver; + + p_mctl->isp_sdev->sd = dev_get_drvdata(dev); +// put_driver(driver); + + /* register vfe subdev */ + driver = driver_find(MSM_VPE_DRV_NAME, &platform_bus_type); + if (!driver) + goto out; + + dev = driver_find_device(driver, NULL, 0, + msm_mctl_subdev_match_core); + if (!dev) + goto out_put_driver; + + p_mctl->isp_sdev->sd_vpe = dev_get_drvdata(dev); +// put_driver(driver); + + rc = 0; + return rc; +out_put_driver: +// put_driver(driver); +out: + return rc; +} + +static int msm_mctl_open_init(struct msm_cam_media_controller *p_mctl, + const char *const apps_id, + struct msm_sync *sync) +{ + int rc; + struct msm_camera_sensor_info *sinfo; + struct msm_camera_device_platform_data *camdev; + uint8_t csid_core; + uint32_t csid_version; + + wake_lock(&sync->wake_lock); + + sinfo = sync->pdev->dev.platform_data; + sync->pdev->resource = sinfo->resource; + sync->pdev->num_resources = sinfo->num_resources; + camdev = sinfo->pdata; + csid_core = camdev->csid_core; + rc = msm_mctl_register_subdevs(p_mctl, csid_core); + if (rc < 0) { + pr_err("%s: msm_mctl_register_subdevs failed:%d\n", + __func__, rc); + goto fail1; + } + + /* turn on clock */ + rc = msm_camio_sensor_clk_on(sync->pdev); + if (rc < 0) { + pr_err("%s: msm_camio_sensor_clk_on failed:%d\n", + __func__, rc); + goto fail1; + } + + rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl, + VIDIOC_MSM_CSIPHY_INIT, NULL); + if (rc < 0) { + pr_err("%s: csiphy initialization failed %d\n", + __func__, rc); + goto fail2; + } + + rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl, + VIDIOC_MSM_CSID_INIT, &csid_version); + if (rc < 0) { + pr_err("%s: csid initialization failed %d\n", + __func__, rc); + goto fail3; + } + + /* ISP first*/ + if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_open) + rc = p_mctl->isp_sdev->isp_open( + p_mctl->isp_sdev->sd, + p_mctl->isp_sdev->sd_vpe, sync); + if (rc < 0) { + pr_err("%s: isp init failed: %d\n", __func__, rc); + goto fail4; + } + + rc = v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl, + VIDIOC_MSM_ISPIF_INIT, &csid_version); + if (rc < 0) { + pr_err("%s: ispif initialization failed %d\n", + __func__, rc); + goto fail5; + } + + /* then sensor - move sub dev later*/ + if (sync->sctrl.s_init) + rc = sync->sctrl.s_init(sync->sdata); + if (rc < 0) { + pr_err("%s: isp init failed: %d\n", __func__, rc); + goto fail6; + } + + if (sync->actctrl.a_power_up) + rc = sync->actctrl.a_power_up( + sync->sdata->actuator_info); + if (rc < 0) { + pr_err("%s: act power failed:%d\n", __func__, rc); + goto fail7; + } + + pm_qos_add_request(p_mctl->pm_qos_req_list, + PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + pm_qos_update_request(p_mctl->pm_qos_req_list, + MSM_V4L2_SWFI_LATENCY); + + sync->apps_id = apps_id; + sync->opencnt++; + return rc; + +fail7: + if (sync->sctrl.s_release) + sync->sctrl.s_release(); +fail6: + v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl, + VIDIOC_MSM_ISPIF_RELEASE, &csid_version); +fail5: + if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release) + p_mctl->isp_sdev->isp_release(sync); +fail4: + v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl, + VIDIOC_MSM_CSID_RELEASE, &csid_version); +fail3: + v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl, + VIDIOC_MSM_CSIPHY_RELEASE, NULL); +fail2: + msm_camio_sensor_clk_off(sync->pdev); +fail1: + wake_unlock(&sync->wake_lock); + return rc; +} + +static int msm_mctl_open(struct msm_cam_media_controller *p_mctl, + const char *const apps_id) +{ + int rc = 0; + struct msm_sync *sync = NULL; + D("%s\n", __func__); + if (!p_mctl) { + pr_err("%s: param is NULL", __func__); + return -EINVAL; + } + + /* msm_sync_init() muct be called before*/ + sync = &(p_mctl->sync); + + mutex_lock(&sync->lock); + /* open sub devices - once only*/ + if (!sync->opencnt) + rc = msm_mctl_open_init(p_mctl, apps_id, sync); + + mutex_unlock(&sync->lock); + return rc; +} + +static int msm_mctl_release(struct msm_cam_media_controller *p_mctl) +{ + int rc = 0; + struct msm_sync *sync = &(p_mctl->sync); + + v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl, + VIDIOC_MSM_ISPIF_RELEASE, NULL); + + if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release) + p_mctl->isp_sdev->isp_release(&p_mctl->sync); + + v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl, + VIDIOC_MSM_CSID_RELEASE, NULL); + + v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl, + VIDIOC_MSM_CSIPHY_RELEASE, NULL); + + if (p_mctl->sync.actctrl.a_power_down) + p_mctl->sync.actctrl.a_power_down(sync->sdata->actuator_info); + + if (p_mctl->sync.sctrl.s_release) + p_mctl->sync.sctrl.s_release(); + + rc = msm_camio_sensor_clk_off(sync->pdev); + if (rc < 0) + pr_err("%s: msm_camio_sensor_clk_off failed:%d\n", + __func__, rc); + + pm_qos_update_request(p_mctl->pm_qos_req_list, + PM_QOS_DEFAULT_VALUE); + pm_qos_remove_request(p_mctl->pm_qos_req_list); + wake_unlock(&p_mctl->sync.wake_lock); + + return rc; +} + +int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam) +{ + struct v4l2_subdev *sd = pcam->mctl.sensor_sdev; + enum v4l2_mbus_pixelcode pxlcode; + int numfmt_sensor = 0; + int numfmt = 0; + int rc = 0; + int i, j; + + D("%s\n", __func__); + while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, numfmt_sensor, + &pxlcode)) + numfmt_sensor++; + + D("%s, numfmt_sensor = %d\n", __func__, numfmt_sensor); + if (!numfmt_sensor) + return -ENXIO; + + pcam->usr_fmts = vmalloc(numfmt_sensor * ARRAY_SIZE(msm_isp_formats) * + sizeof(struct msm_isp_color_fmt)); + if (!pcam->usr_fmts) + return -ENOMEM; + + /* from sensor to ISP.. fill the data structure */ + for (i = 0; i < numfmt_sensor; i++) { + rc = v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &pxlcode); + D("rc is %d\n", rc); + if (rc < 0) { + vfree(pcam->usr_fmts); + return rc; + } + + for (j = 0; j < ARRAY_SIZE(msm_isp_formats); j++) { + /* find the corresponding format */ + if (pxlcode == msm_isp_formats[j].pxlcode) { + pcam->usr_fmts[numfmt] = msm_isp_formats[j]; + D("pcam->usr_fmts=0x%x\n", (u32)pcam->usr_fmts); + D("format pxlcode 0x%x (0x%x) found\n", + pcam->usr_fmts[numfmt].pxlcode, + pcam->usr_fmts[numfmt].fourcc); + numfmt++; + } + } + } + + pcam->num_fmts = numfmt; + + if (numfmt == 0) { + pr_err("%s: No supported formats.\n", __func__); + vfree(pcam->usr_fmts); + return -EINVAL; + } + + D("Found %d supported formats.\n", pcam->num_fmts); + /* set the default pxlcode, in any case, it will be set through + * setfmt */ + return 0; +} + +/* this function plug in the implementation of a v4l2_subdev */ +int msm_mctl_init_module(struct msm_cam_v4l2_device *pcam) +{ + struct msm_cam_media_controller *pmctl = NULL; + D("%s\n", __func__); + if (!pcam) { + pr_err("%s: param is NULL", __func__); + return -EINVAL; + } else + pmctl = &pcam->mctl; + + pmctl->sync.opencnt = 0; + + /* init module operations*/ + pmctl->mctl_open = msm_mctl_open; + pmctl->mctl_cmd = msm_mctl_cmd; + pmctl->mctl_notify = msm_mctl_notify; + pmctl->mctl_release = msm_mctl_release; + pmctl->plat_dev = pcam->pdev; + /* init mctl buf */ + msm_mctl_buf_init(pcam); + memset(&pmctl->pp_info, 0, sizeof(pmctl->pp_info)); + spin_lock_init(&pmctl->pp_info.lock); + /* init sub device*/ + v4l2_subdev_init(&(pmctl->mctl_sdev), &mctl_subdev_ops); + v4l2_set_subdevdata(&(pmctl->mctl_sdev), pmctl); + + return 0; +} diff --git a/drivers/media/video/msm_zsl/msm_mctl_buf.c b/drivers/media/video/msm_zsl/msm_mctl_buf.c new file mode 100644 index 00000000000..b7a4b81ab36 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_mctl_buf.c @@ -0,0 +1,764 @@ +/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "msm.h" +#include "msm_ispif.h" + +#ifdef CONFIG_MSM_CAMERA_DEBUG +#define D(fmt, args...) pr_debug("msm_mctl_buf: " fmt, ##args) +#else +#define D(fmt, args...) do {} while (0) +#endif + +static int msm_vb2_ops_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + void *alloc_ctxs[]) +{ + /* get the video device */ + struct msm_cam_v4l2_dev_inst *pcam_inst = vb2_get_drv_priv(vq); + struct msm_cam_v4l2_device *pcam = pcam_inst->pcam; + int i; + + D("%s\n", __func__); + if (!pcam || !(*num_buffers)) { + pr_err("%s error : invalid input\n", __func__); + return -EINVAL; + } + + *num_planes = pcam_inst->plane_info.num_planes; + for (i = 0; i < pcam_inst->vid_fmt.fmt.pix_mp.num_planes; i++) { + sizes[i] = PAGE_ALIGN(pcam_inst->plane_info.plane[i].size); + D("%s Inst %p : Plane %d Offset = %d Size = %ld" + "Aligned Size = %u", __func__, pcam_inst, i, + pcam_inst->plane_info.plane[i].offset, + pcam_inst->plane_info.plane[i].size, sizes[i]); + } + return 0; +} + +static void msm_vb2_ops_wait_prepare(struct vb2_queue *q) +{ + /* we use polling so do not use this fn now */ +} +static void msm_vb2_ops_wait_finish(struct vb2_queue *q) +{ + /* we use polling so do not use this fn now */ +} + +static int msm_vb2_ops_buf_init(struct vb2_buffer *vb) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + struct msm_cam_v4l2_device *pcam; + struct videobuf2_contig_pmem *mem; + struct vb2_queue *vq; + uint32_t buf_idx; + struct msm_frame_buffer *buf; + int rc = 0, i; + enum videobuf2_buffer_type buf_type; + struct videobuf2_msm_offset offset; + vq = vb->vb2_queue; + pcam_inst = vb2_get_drv_priv(vq); + pcam = pcam_inst->pcam; + D("%s\n", __func__); + D("%s, inst=0x%x,idx=%d, width = %d\n", __func__, + (u32)pcam_inst, pcam_inst->my_index, + pcam_inst->vid_fmt.fmt.pix.width); + D("%s, inst=0x%x,idx=%d, height = %d\n", __func__, + (u32)pcam_inst, pcam_inst->my_index, + pcam_inst->vid_fmt.fmt.pix.height); + + buf = container_of(vb, struct msm_frame_buffer, vidbuf); + if (buf->state == MSM_BUFFER_STATE_INITIALIZED) + return rc; + + if (pcam_inst->plane_info.buffer_type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + buf_type = VIDEOBUF2_MULTIPLE_PLANES; + else if (pcam_inst->plane_info.buffer_type == + V4L2_BUF_TYPE_VIDEO_CAPTURE) + buf_type = VIDEOBUF2_SINGLE_PLANE; + else + return -EINVAL; + + if (buf_type == VIDEOBUF2_SINGLE_PLANE) { + offset.sp_off.y_off = pcam_inst->plane_info.sp_y_offset; + offset.sp_off.cbcr_off = + pcam_inst->plane_info.plane[0].offset; + } + buf_idx = vb->v4l2_buf.index; + for (i = 0; i < vb->num_planes; i++) { + mem = vb2_plane_cookie(vb, i); + if (buf_type == VIDEOBUF2_MULTIPLE_PLANES) + offset.data_offset = + pcam_inst->plane_info.plane[i].offset; + + if (vb->v4l2_buf.memory == V4L2_MEMORY_USERPTR) + rc = videobuf2_pmem_contig_user_get(mem, &offset, + buf_type, + pcam_inst->buf_offset[buf_idx][i].addr_offset, + pcam_inst->path, pcam->mctl.client + /*HACK:WILL BREAK THINGS*/,0); + else + rc = videobuf2_pmem_contig_mmap_get(mem, &offset, + buf_type, pcam_inst->path); + if (rc < 0) { + pr_err("%s error initializing buffer ", + __func__); + return rc; + } + } + buf->state = MSM_BUFFER_STATE_INITIALIZED; + return rc; +} + +static int msm_vb2_ops_buf_prepare(struct vb2_buffer *vb) +{ + int i, rc = 0; + uint32_t len; + struct msm_cam_v4l2_dev_inst *pcam_inst; + struct msm_cam_v4l2_device *pcam; + struct msm_frame_buffer *buf; + struct vb2_queue *vq = NULL; + + D("%s\n", __func__); + if (!vb) { + pr_err("%s error : input is NULL\n", __func__); + return -EINVAL; + } + vq = vb->vb2_queue; + pcam_inst = vb2_get_drv_priv(vq); + pcam = pcam_inst->pcam; + buf = container_of(vb, struct msm_frame_buffer, vidbuf); + + if (!pcam || !buf) { + pr_err("%s error : pointer is NULL\n", __func__); + return -EINVAL; + } + /* by this time vid_fmt should be already set. + * return error if it is not. */ + if ((pcam_inst->vid_fmt.fmt.pix.width == 0) || + (pcam_inst->vid_fmt.fmt.pix.height == 0)) { + pr_err("%s error : pcam vid_fmt is not set\n", __func__); + return -EINVAL; + } + /* prefill in the byteused field */ + for (i = 0; i < vb->num_planes; i++) { + len = vb2_plane_size(vb, i); + vb2_set_plane_payload(vb, i, len); + } + buf->state = MSM_BUFFER_STATE_PREPARED; + return rc; +} + +static int msm_vb2_ops_buf_finish(struct vb2_buffer *vb) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + struct msm_cam_v4l2_device *pcam; + struct msm_frame_buffer *buf; + + pcam_inst = vb2_get_drv_priv(vb->vb2_queue); + pcam = pcam_inst->pcam; + buf = container_of(vb, struct msm_frame_buffer, vidbuf); + buf->state = MSM_BUFFER_STATE_DEQUEUED; + D("%s: inst=0x%x, buf=0x, %x, idx=%d\n", __func__, + (uint32_t)pcam_inst, (uint32_t)buf, vb->v4l2_buf.index); + return 0; +} + +static void msm_vb2_ops_buf_cleanup(struct vb2_buffer *vb) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + struct msm_cam_v4l2_device *pcam; + struct videobuf2_contig_pmem *mem; + struct msm_frame_buffer *buf, *tmp; + uint32_t i, vb_phyaddr = 0, buf_phyaddr = 0; + unsigned long flags = 0; + + pcam_inst = vb2_get_drv_priv(vb->vb2_queue); + pcam = pcam_inst->pcam; + buf = container_of(vb, struct msm_frame_buffer, vidbuf); + + if (pcam_inst->vid_fmt.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + for (i = 0; i < vb->num_planes; i++) { + mem = vb2_plane_cookie(vb, i); + if (!mem) { + D("%s Inst %p memory already freed up. return", + __func__, pcam_inst); + return; + } + D("%s: inst=%p, buf=0x%x, idx=%d plane id = %d\n", + __func__, pcam_inst, + (uint32_t)buf, vb->v4l2_buf.index, i); + + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + list_for_each_entry_safe(buf, tmp, + &pcam_inst->free_vq, list) { + if (&buf->vidbuf == vb) { + list_del_init(&buf->list); + break; + } + } + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + } + } else { + mem = vb2_plane_cookie(vb, 0); + if (!mem) + return; + D("%s: inst=0x%x, buf=0x%x, idx=%d\n", __func__, + (uint32_t)pcam_inst, (uint32_t)buf, vb->v4l2_buf.index); + vb_phyaddr = (unsigned long) videobuf2_to_pmem_contig(vb, 0); + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + list_for_each_entry_safe(buf, tmp, + &pcam_inst->free_vq, list) { + buf_phyaddr = (unsigned long) + videobuf2_to_pmem_contig(&buf->vidbuf, 0); + D("%s vb_idx=%d,vb_paddr=0x%x,phyaddr=0x%x\n", + __func__, buf->vidbuf.v4l2_buf.index, + buf_phyaddr, vb_phyaddr); + if (vb_phyaddr == buf_phyaddr) { + list_del_init(&buf->list); + break; + } + } + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + } + for (i = 0; i < vb->num_planes; i++) { + mem = vb2_plane_cookie(vb, i); + videobuf2_pmem_contig_user_put(mem, pcam->mctl.client/*HACK WILL BREAK THINGS*/, 0); + } + buf->state = MSM_BUFFER_STATE_UNUSED; +} + +static int msm_vb2_ops_start_streaming(struct vb2_queue *q, unsigned int count) +{ + return 0; +} + +static int msm_vb2_ops_stop_streaming(struct vb2_queue *q) +{ + int rc = 0; + struct msm_free_buf *free_buf = NULL; + struct msm_cam_v4l2_dev_inst *pcam_inst = vb2_get_drv_priv(q); + if (rc != 0) + msm_mctl_release_free_buf(&pcam_inst->pcam->mctl, + pcam_inst->path, free_buf); + return 0; +} + +static void msm_vb2_ops_buf_queue(struct vb2_buffer *vb) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst = NULL; + struct msm_cam_v4l2_device *pcam = NULL; + unsigned long flags = 0; + struct vb2_queue *vq = NULL; + struct msm_frame_buffer *buf; + + D("%s\n", __func__); + if (!vb) { + pr_err("%s error : input is NULL\n", __func__); + return ; + } + vq = vb->vb2_queue; + pcam_inst = vb2_get_drv_priv(vq); + pcam = pcam_inst->pcam; + D("%s pcam_inst=%p,(vb=0x%p),idx=%d,len=%d\n", + __func__, pcam_inst, + vb, vb->v4l2_buf.index, vb->v4l2_buf.length); + buf = container_of(vb, struct msm_frame_buffer, vidbuf); + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + /* we are returning a buffer to the queue */ + list_add_tail(&buf->list, &pcam_inst->free_vq); + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + buf->state = MSM_BUFFER_STATE_QUEUED; +} + +static struct vb2_ops msm_vb2_ops = { + .queue_setup = msm_vb2_ops_queue_setup, + .wait_prepare = msm_vb2_ops_wait_prepare, + .wait_finish = msm_vb2_ops_wait_finish, + .buf_init = msm_vb2_ops_buf_init, + .buf_prepare = msm_vb2_ops_buf_prepare, + .buf_finish = msm_vb2_ops_buf_finish, + .buf_cleanup = msm_vb2_ops_buf_cleanup, + .start_streaming = msm_vb2_ops_start_streaming, + .stop_streaming = msm_vb2_ops_stop_streaming, + .buf_queue = msm_vb2_ops_buf_queue, +}; + + +/* prepare a video buffer queue for a vl42 device*/ +static int msm_vbqueue_init(struct msm_cam_v4l2_dev_inst *pcam_inst, + struct vb2_queue *q, enum v4l2_buf_type type) +{ + if (!q) { + pr_err("%s error : input is NULL\n", __func__); + return -EINVAL; + } + + spin_lock_init(&pcam_inst->vq_irqlock); + INIT_LIST_HEAD(&pcam_inst->free_vq); + videobuf2_queue_pmem_contig_init(q, type, + &msm_vb2_ops, + sizeof(struct msm_frame_buffer), + (void *)pcam_inst); + return 0; +} + +int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam, + int out_type) +{ + int image_mode; + switch (out_type) { + case VFE_MSG_OUTPUT_P: + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW; + break; + case VFE_MSG_OUTPUT_V: + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO; + break; + case VFE_MSG_OUTPUT_S: + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN; + break; + case VFE_MSG_OUTPUT_T: + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL; + break; + default: + image_mode = -1; + break; + } + if ((image_mode >= 0) && pcam->dev_inst_map[image_mode]) + return pcam->dev_inst_map[image_mode]->my_index; + else + return -EINVAL; +} + +void msm_mctl_gettimeofday(struct timeval *tv) +{ + struct timespec ts; + + BUG_ON(!tv); + + ktime_get_ts(&ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec/1000; +} + +struct msm_frame_buffer *msm_mctl_buf_find( + struct msm_cam_media_controller *pmctl, + struct msm_cam_v4l2_dev_inst *pcam_inst, int del_buf, + int msg_type, struct msm_free_buf *fbuf) +{ + struct msm_frame_buffer *buf = NULL, *tmp; + uint32_t buf_phyaddr = 0; + unsigned long flags = 0; + uint32_t buf_idx, offset = 0; + struct videobuf2_contig_pmem *mem; + + /* we actually need a list, not a queue */ + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + list_for_each_entry_safe(buf, tmp, + &pcam_inst->free_vq, list) { + buf_idx = buf->vidbuf.v4l2_buf.index; + mem = vb2_plane_cookie(&buf->vidbuf, 0); + if (mem->buffer_type == VIDEOBUF2_MULTIPLE_PLANES) + offset = mem->offset.data_offset + + pcam_inst->buf_offset[buf_idx][0].data_offset; + else + offset = mem->offset.sp_off.y_off; + buf_phyaddr = (unsigned long) + videobuf2_to_pmem_contig(&buf->vidbuf, 0) + + offset; + D("%s vb_idx=%d,vb_paddr=0x%x ch0=0x%x\n", + __func__, buf->vidbuf.v4l2_buf.index, + buf_phyaddr, fbuf->ch_paddr[0]); + if (fbuf->ch_paddr[0] == buf_phyaddr) { + if (del_buf) + list_del_init(&buf->list); + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, + flags); + buf->state = MSM_BUFFER_STATE_RESERVED; + return buf; + } + } + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + return NULL; +} + +int msm_mctl_buf_done_proc( + struct msm_cam_media_controller *pmctl, + struct msm_cam_v4l2_dev_inst *pcam_inst, + int msg_type, struct msm_free_buf *fbuf, + uint32_t *frame_id, int gen_timestamp) +{ + struct msm_frame_buffer *buf = NULL; + int del_buf = 1; + + buf = msm_mctl_buf_find(pmctl, pcam_inst, del_buf, + msg_type, fbuf); + if (!buf) { + pr_err("%s: buf=0x%x not found\n", + __func__, fbuf->ch_paddr[0]); + return -EINVAL; + } + if (gen_timestamp) { + if (frame_id) + buf->vidbuf.v4l2_buf.sequence = *frame_id; + msm_mctl_gettimeofday( + &buf->vidbuf.v4l2_buf.timestamp); + } + vb2_buffer_done(&buf->vidbuf, VB2_BUF_STATE_DONE); + return 0; +} + + +int msm_mctl_buf_done(struct msm_cam_media_controller *p_mctl, + int msg_type, struct msm_free_buf *fbuf, + uint32_t frame_id) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + int idx, rc; + int pp_divert_type = 0, pp_type = 0; + + msm_mctl_check_pp(p_mctl, msg_type, &pp_divert_type, &pp_type); + D("%s: pp_type=%d, pp_divert_type = %d", + __func__, pp_type, pp_divert_type); + if (pp_type || pp_divert_type) + rc = msm_mctl_do_pp_divert(p_mctl, + msg_type, fbuf, frame_id, pp_type); + else { + idx = msm_mctl_out_type_to_inst_index( + p_mctl->sync.pcam_sync, msg_type); + if (idx < 0) { + pr_err("%s Invalid instance, dropping buffer\n", + __func__); + return idx; + } + pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx]; + rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst, + msg_type, fbuf, + &frame_id, 1); + } + return rc; +} + +int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam) +{ + pcam->mctl.mctl_vbqueue_init = msm_vbqueue_init; + return 0; +} + +int msm_mctl_check_free_buf( + struct msm_cam_media_controller *pmctl, + int msg_type) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + unsigned long flags = 0; + /* CACHABLE_MEMORY */ + struct msm_frame_buffer *buf = NULL; + int rc = -EINVAL, idx; + + if (!pmctl) { + pr_err("%s: pmctl is null\n", __func__); + return rc; + } + idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, + msg_type); + if (idx < 0) { + pr_err("%s Invalid instance, returning\n", __func__); + return idx; + } + pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx]; + if (!pcam_inst || !pcam_inst->streamon) { + pr_err("%s: stream is turned off\n", __func__); + return rc; + } + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + list_for_each_entry(buf, &pcam_inst->free_vq, list) { + if (buf->state != MSM_BUFFER_STATE_QUEUED) + continue; + + rc = 0; + break; + } + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + return rc; +} + +int msm_mctl_reserve_free_buf( + struct msm_cam_media_controller *pmctl, + int msg_type, struct msm_free_buf *free_buf) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + unsigned long flags = 0; + /* CACHABLE_MEMORY */ + struct videobuf2_contig_pmem *mem = NULL; + struct msm_frame_buffer *buf = NULL; + int rc = -EINVAL, idx, i; + uint32_t buf_idx, plane_offset = 0; + + if (!free_buf || !pmctl) { + pr_err("%s: free_buf/pmctl is null\n", __func__); + return rc; + } + memset(free_buf, 0, sizeof(struct msm_free_buf)); + idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, + msg_type); + if (idx < 0) { + pr_err("%s Invalid instance, returning\n", __func__); + return idx; + } + pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx]; + if (!pcam_inst || !pcam_inst->streamon) { + pr_err("%s: stream is turned off\n", __func__); + return rc; + } + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + list_for_each_entry(buf, &pcam_inst->free_vq, list) { + if (buf->state != MSM_BUFFER_STATE_QUEUED) + continue; + + buf_idx = buf->vidbuf.v4l2_buf.index; + if (pcam_inst->vid_fmt.type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + free_buf->num_planes = + pcam_inst->plane_info.num_planes; + for (i = 0; i < free_buf->num_planes; i++) { + mem = vb2_plane_cookie(&buf->vidbuf, i); + if (mem->buffer_type == + VIDEOBUF2_MULTIPLE_PLANES) + plane_offset = + mem->offset.data_offset; + else + plane_offset = + mem->offset.sp_off.cbcr_off; + + free_buf->ch_paddr[i] = (uint32_t) + videobuf2_to_pmem_contig(&buf->vidbuf, i) + + pcam_inst->buf_offset[buf_idx][i].data_offset + + plane_offset; + } + } else { + mem = vb2_plane_cookie(&buf->vidbuf, 0); + free_buf->ch_paddr[0] = (uint32_t) + videobuf2_to_pmem_contig(&buf->vidbuf, 0) + + mem->offset.sp_off.y_off; + free_buf->ch_paddr[1] = free_buf->ch_paddr[0] + + mem->offset.sp_off.cbcr_off; + } + free_buf->vb = (uint32_t)buf; + buf->state = MSM_BUFFER_STATE_RESERVED; + D("%s idx=%d,inst=0x%p,idx=%d,paddr=0x%x, " + "ch1 addr=0x%x\n", __func__, + idx, pcam_inst, buf->vidbuf.v4l2_buf.index, + free_buf->ch_paddr[0], free_buf->ch_paddr[1]); + + /* CACHABLE_MEMORY */ + /*invalidate cache if required*/ +#if defined(CACHABLE_MEMORY) + if (mem && (ION_IS_CACHED(mem->ion_flags) == CACHED)) + invalidate_caches((unsigned long)mem->kernel_vaddr, + mem->size, (unsigned long)mem->phyaddr); +#endif + rc = 0; + break; + } + if (rc != 0) + D("%s:No free buffer available: inst = 0x%p ", + __func__, pcam_inst); + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + return rc; +} + +int msm_mctl_release_free_buf(struct msm_cam_media_controller *pmctl, + int msg_type, struct msm_free_buf *free_buf) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + unsigned long flags = 0; + struct msm_frame_buffer *buf = NULL; + uint32_t buf_phyaddr = 0; + int rc = -EINVAL, idx; + + if (!free_buf) + return rc; + + idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, msg_type); + if (idx < 0) { + pr_err("%s Invalid instance, buffer not released\n", __func__); + return idx; + } + pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx]; + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + list_for_each_entry(buf, &pcam_inst->free_vq, list) { + buf_phyaddr = + (uint32_t) videobuf2_to_pmem_contig(&buf->vidbuf, 0); + if (free_buf->ch_paddr[0] == buf_phyaddr) { + D("%s buf = 0x%x ", __func__, free_buf->ch_paddr[0]); + buf->state = MSM_BUFFER_STATE_UNUSED; + rc = 0; + break; + } + } + + if (rc != 0) + pr_err("%s invalid buffer address ", __func__); + + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + return rc; +} + +int msm_mctl_buf_done_pp( + struct msm_cam_media_controller *pmctl, + int msg_type, struct msm_free_buf *frame, int dirty) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + int idx, rc = 0; + + idx = msm_mctl_out_type_to_inst_index( + pmctl->sync.pcam_sync, msg_type); + if (idx < 0) { + pr_err("%s Invalid instance, buffer dropped\n", __func__); + return idx; + } + pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx]; + D("%s:inst=0x%p, paddr=0x%x, dirty=%d", + __func__, pcam_inst, frame->ch_paddr[0], dirty); + if (dirty) + /* the frame is dirty, not going to disptach to app */ + rc = msm_mctl_release_free_buf(pmctl, msg_type, frame); + else + rc = msm_mctl_buf_done_proc(pmctl, pcam_inst, + msg_type, frame, NULL, 0); + return rc; +} + +struct msm_frame_buffer *msm_mctl_get_free_buf( + struct msm_cam_media_controller *pmctl, + int msg_type) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + unsigned long flags = 0; + struct msm_frame_buffer *buf = NULL; + int rc = -EINVAL, idx; + + idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, + msg_type); + if (idx < 0) { + pr_err("%s Invalid instance, cant get buffer\n", __func__); + return NULL; + } + pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx]; + if (!pcam_inst->streamon) { + D("%s: stream 0x%p is off\n", __func__, pcam_inst); + return NULL; + } + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + if (!list_empty(&pcam_inst->free_vq)) { + list_for_each_entry(buf, &pcam_inst->free_vq, list) { + if (buf->state == MSM_BUFFER_STATE_QUEUED) { + buf->state = MSM_BUFFER_STATE_RESERVED; + rc = 0; + break; + } + } + } + if (rc != 0) { + D("%s:No free buffer available: inst = 0x%p ", + __func__, pcam_inst); + buf = NULL; + } + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + return buf; +} + +int msm_mctl_put_free_buf( + struct msm_cam_media_controller *pmctl, + int msg_type, struct msm_frame_buffer *my_buf) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + unsigned long flags = 0; + int rc = 0, idx; + struct msm_frame_buffer *buf = NULL; + + idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, + msg_type); + if (idx < 0) { + pr_err("%s Invalid instance, cant put buffer\n", __func__); + return idx; + } + pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx]; + if (!pcam_inst->streamon) { + D("%s: stream 0x%p is off\n", __func__, pcam_inst); + return rc; + } + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + if (!list_empty(&pcam_inst->free_vq)) { + list_for_each_entry(buf, &pcam_inst->free_vq, list) { + if (my_buf == buf) { + buf->state = MSM_BUFFER_STATE_QUEUED; + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, + flags); + return 0; + } + } + } + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + return rc; +} + +int msm_mctl_buf_del(struct msm_cam_media_controller *pmctl, + int msg_type, + struct msm_frame_buffer *my_buf) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + struct msm_frame_buffer *buf = NULL; + unsigned long flags = 0; + int idx; + + idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, + msg_type); + if (idx < 0) { + pr_err("%s Invalid instance, cant delete buffer\n", __func__); + return idx; + } + pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx]; + D("%s: idx = %d, pinst=0x%p", __func__, idx, pcam_inst); + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + if (!list_empty(&pcam_inst->free_vq)) { + list_for_each_entry(buf, &pcam_inst->free_vq, list) { + if (my_buf == buf) { + list_del_init(&buf->list); + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, + flags); + return 0; + } + } + } + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + pr_err("%s: buf 0x%p not found", __func__, my_buf); + return -EINVAL; +} diff --git a/drivers/media/video/msm_zsl/msm_mctl_pp.c b/drivers/media/video/msm_zsl/msm_mctl_pp.c new file mode 100644 index 00000000000..a0afbd1d2fb --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_mctl_pp.c @@ -0,0 +1,925 @@ +/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "msm.h" + +#ifdef CONFIG_MSM_CAMERA_DEBUG +#define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args) +#else +#define D(fmt, args...) do {} while (0) +#endif + +static int msm_mctl_pp_buf_divert( + struct msm_cam_media_controller *pmctl, + struct msm_cam_v4l2_dev_inst *pcam_inst, + struct msm_cam_evt_divert_frame *div) +{ + struct v4l2_event v4l2_evt; + struct msm_isp_event_ctrl *isp_event; + isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), + GFP_ATOMIC); + v4l2_evt.id = 0; + if (!isp_event) { + pr_err("%s Insufficient memory. return", __func__); + return -ENOMEM; + } + D("%s: msm_cam_evt_divert_frame=%d", + __func__, sizeof(struct msm_cam_evt_divert_frame)); + memset(&v4l2_evt, 0, sizeof(v4l2_evt)); + v4l2_evt.type = V4L2_EVENT_PRIVATE_START + + MSM_CAM_RESP_DIV_FRAME_EVT_MSG; + *((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event; + /* Copy the divert frame struct into event ctrl struct. */ + isp_event->isp_data.div_frame = *div; + + D("%s inst=%p, img_mode=%d, frame_id=%d\n", __func__, + pcam_inst, pcam_inst->image_mode, div->frame.frame_id); + v4l2_event_queue( + pmctl->config_device->config_stat_event_queue.pvdev, + &v4l2_evt); + return 0; +} + +int msm_mctl_check_pp(struct msm_cam_media_controller *p_mctl, + int msg_type, int *pp_divert_type, int *pp_type) +{ + int rc = 0; + unsigned long flags; + uint32_t pp_key = 0; + int image_mode = MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT; + + *pp_type = 0; + *pp_divert_type = 0; + spin_lock_irqsave(&p_mctl->pp_info.lock, flags); + switch (msg_type) { + case VFE_MSG_OUTPUT_P: + pp_key = PP_PREV; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW; + if (p_mctl->pp_info.pp_key & pp_key) + *pp_divert_type = OUTPUT_TYPE_P; + if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_P) + *pp_type = OUTPUT_TYPE_P; + break; + case VFE_MSG_OUTPUT_S: + pp_key = PP_SNAP; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN; + if (p_mctl->pp_info.pp_key & pp_key) + *pp_divert_type = OUTPUT_TYPE_S; + if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_S) + *pp_type = OUTPUT_TYPE_P; + break; + case VFE_MSG_OUTPUT_V: + if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_V) + *pp_type = OUTPUT_TYPE_V; + break; + case VFE_MSG_OUTPUT_T: + if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_T) + *pp_type = OUTPUT_TYPE_T; + break; + default: + break; + } + if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) + *pp_divert_type = 0; + spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); + D("%s: pp_type=%d, pp_divert_type = %d", + __func__, *pp_type, *pp_divert_type); + return rc; +} + +int msm_mctl_do_pp_divert( + struct msm_cam_media_controller *p_mctl, + int msg_type, struct msm_free_buf *fbuf, + uint32_t frame_id, int pp_type) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + int idx, rc = 0, i, buf_idx; + int del_buf = 0; /* delete from free queue */ + struct msm_cam_evt_divert_frame div; + struct msm_frame_buffer *vb = NULL; + struct videobuf2_contig_pmem *mem; + + idx = msm_mctl_out_type_to_inst_index( + p_mctl->sync.pcam_sync, msg_type); + if (idx < 0) { + pr_err("%s Invalid instance. returning\n", __func__); + return -EINVAL; + } + pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx]; + vb = msm_mctl_buf_find(p_mctl, pcam_inst, + del_buf, msg_type, fbuf); + if (!vb) + return -EINVAL; + + vb->vidbuf.v4l2_buf.sequence = frame_id; + buf_idx = vb->vidbuf.v4l2_buf.index; + div.image_mode = pcam_inst->image_mode; + div.op_mode = pcam_inst->pcam->op_mode; + div.inst_idx = pcam_inst->my_index; + div.node_idx = pcam_inst->pcam->vnode_id; + p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode] = frame_id; + div.frame.frame_id = + p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]; +#if defined(CONFIG_MSM_IOMMU) + div.frame.buf_idx = buf_idx; +#endif + + div.frame.handle = (uint32_t)vb; + msm_mctl_gettimeofday(&div.frame.timestamp); + vb->vidbuf.v4l2_buf.timestamp = div.frame.timestamp; + div.do_pp = pp_type; + D("%s Diverting frame %x id %d to userspace ", __func__, + (int)div.frame.handle, div.frame.frame_id); + /* Get the cookie for 1st plane and store the path. + * Also use this to check the number of planes in + * this buffer.*/ + mem = vb2_plane_cookie(&vb->vidbuf, 0); + div.frame.path = mem->path; +#if defined(CONFIG_MSM_IOMMU) + div.frame.node_type = VIDEO_NODE; +#endif + + if (mem->buffer_type == VIDEOBUF2_SINGLE_PLANE) { + /* This buffer contains only 1 plane. Use the + * single planar structure to store the info.*/ + div.frame.num_planes = 1; + div.frame.sp.phy_addr = + videobuf2_to_pmem_contig(&vb->vidbuf, 0); + div.frame.sp.addr_offset = mem->addr_offset; + div.frame.sp.y_off = 0; + div.frame.sp.cbcr_off = mem->offset.sp_off.cbcr_off; + div.frame.sp.fd = (int)mem->vaddr; + div.frame.sp.length = mem->size; + if (!pp_type) + p_mctl->pp_info.div_frame[pcam_inst->image_mode]. + ch_paddr[0] = div.frame.sp.phy_addr; + } else { + /* This buffer contains multiple planes. Use the mutliplanar + * structure to store the info. */ + div.frame.num_planes = pcam_inst->plane_info.num_planes; + /* Now traverse through all the planes of the buffer to + * fill out the plane info. */ + for (i = 0; i < div.frame.num_planes; i++) { + mem = vb2_plane_cookie(&vb->vidbuf, i); + div.frame.mp[i].phy_addr = + videobuf2_to_pmem_contig(&vb->vidbuf, i); + div.frame.mp[i].data_offset = + pcam_inst->buf_offset[buf_idx][i].data_offset; + div.frame.mp[i].addr_offset = + mem->addr_offset; + div.frame.mp[i].fd = (int)mem->vaddr; + div.frame.mp[i].length = mem->size; + } + if (!pp_type) + p_mctl->pp_info.div_frame[pcam_inst->image_mode]. + ch_paddr[0] = div.frame.mp[0].phy_addr + + div.frame.mp[0].data_offset; + } + rc = msm_mctl_pp_buf_divert(p_mctl, pcam_inst, &div); + return rc; +} + +static int msm_mctl_pp_get_phy_addr( + struct msm_cam_v4l2_dev_inst *pcam_inst, + uint32_t frame_handle, + struct msm_pp_frame *pp_frame) +{ + struct msm_frame_buffer *vb = NULL; + struct videobuf2_contig_pmem *mem; + int i, buf_idx = 0; + + vb = (struct msm_frame_buffer *)frame_handle; + buf_idx = vb->vidbuf.v4l2_buf.index; + memset(pp_frame, 0, sizeof(struct msm_pp_frame)); + pp_frame->handle = (uint32_t)vb; + pp_frame->frame_id = vb->vidbuf.v4l2_buf.sequence; + pp_frame->timestamp = vb->vidbuf.v4l2_buf.timestamp; + /* Get the cookie for 1st plane and store the path. + * Also use this to check the number of planes in + * this buffer.*/ + mem = vb2_plane_cookie(&vb->vidbuf, 0); + pp_frame->image_type = (unsigned short)mem->path; + if (mem->buffer_type == VIDEOBUF2_SINGLE_PLANE) { + pp_frame->num_planes = 1; + pp_frame->sp.addr_offset = mem->addr_offset; + pp_frame->sp.phy_addr = + videobuf2_to_pmem_contig(&vb->vidbuf, 0); + pp_frame->sp.y_off = 0; + pp_frame->sp.cbcr_off = mem->offset.sp_off.cbcr_off; + pp_frame->sp.length = mem->size; + pp_frame->sp.fd = (int)mem->vaddr; + } else { + pp_frame->num_planes = pcam_inst->plane_info.num_planes; + for (i = 0; i < pp_frame->num_planes; i++) { + mem = vb2_plane_cookie(&vb->vidbuf, i); + pp_frame->mp[i].addr_offset = mem->addr_offset; + pp_frame->mp[i].phy_addr = + videobuf2_to_pmem_contig(&vb->vidbuf, i); + pp_frame->mp[i].data_offset = + pcam_inst->buf_offset[buf_idx][i].data_offset; + pp_frame->mp[i].fd = (int)mem->vaddr; + pp_frame->mp[i].length = mem->size; + D("%s frame id %d buffer %d plane %d phy addr 0x%x" + " fd %d length %d\n", __func__, + pp_frame->frame_id, buf_idx, i, + (uint32_t)pp_frame->mp[i].phy_addr, + pp_frame->mp[i].fd, pp_frame->mp[i].length); + } + } + return 0; +} + +static int msm_mctl_pp_copy_timestamp_and_frame_id( + uint32_t src_handle, uint32_t dest_handle) +{ + struct msm_frame_buffer *src_vb; + struct msm_frame_buffer *dest_vb; + + src_vb = (struct msm_frame_buffer *)src_handle; + dest_vb = (struct msm_frame_buffer *)dest_handle; + dest_vb->vidbuf.v4l2_buf.timestamp = + src_vb->vidbuf.v4l2_buf.timestamp; + dest_vb->vidbuf.v4l2_buf.sequence = + src_vb->vidbuf.v4l2_buf.sequence; + D("%s: timestamp=%ld:%ld,frame_id=0x%x", __func__, + dest_vb->vidbuf.v4l2_buf.timestamp.tv_sec, + dest_vb->vidbuf.v4l2_buf.timestamp.tv_usec, + dest_vb->vidbuf.v4l2_buf.sequence); + return 0; +} + +static int msm_mctl_pp_path_to_inst_index(struct msm_cam_v4l2_device *pcam, + int out_type) +{ + int image_mode; + switch (out_type) { + case OUTPUT_TYPE_P: + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW; + break; + case OUTPUT_TYPE_V: + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO; + break; + case OUTPUT_TYPE_S: + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN; + break; + default: + image_mode = -1; + break; + } + if ((image_mode >= 0) && pcam->dev_inst_map[image_mode]) + return pcam->dev_inst_map[image_mode]->my_index; + else + return -EINVAL; +} + +int msm_mctl_pp_proc_vpe_cmd( + struct msm_cam_media_controller *p_mctl, + struct msm_mctl_pp_cmd *pp_cmd) +{ + int rc = 0, idx; + void __user *argp = (void __user *)pp_cmd->value; + struct msm_cam_v4l2_dev_inst *pcam_inst; + + switch (pp_cmd->id) { + case VPE_CMD_INIT: + case VPE_CMD_DEINIT: + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL); + break; + case VPE_CMD_DISABLE: + case VPE_CMD_RESET: + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL); + break; + case VPE_CMD_ENABLE: { + struct msm_vpe_clock_rate clk_rate; + if (sizeof(struct msm_vpe_clock_rate) != + pp_cmd->length) { + D("%s: vpe cmd size mismatch " + "(id=%d, length = %d, expect size = %d", + __func__, pp_cmd->id, pp_cmd->length, + sizeof(struct msm_vpe_clock_rate)); + rc = -EINVAL; + break; + } + if (copy_from_user(&clk_rate, pp_cmd->value, + sizeof(struct msm_vpe_clock_rate))) { + D("%s:clk_rate copy failed", __func__); + return -EFAULT; + } + pp_cmd->value = (void *)&clk_rate; + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL); + pp_cmd->value = argp; + break; + } + case VPE_CMD_FLUSH: { + struct msm_vpe_flush_frame_buffer flush_buf; + if (sizeof(struct msm_vpe_flush_frame_buffer) != + pp_cmd->length) { + D("%s: size mismatch(id=%d, len = %d, expected = %d", + __func__, pp_cmd->id, pp_cmd->length, + sizeof(struct msm_vpe_flush_frame_buffer)); + rc = -EINVAL; + break; + } + if (copy_from_user( + &flush_buf, pp_cmd->value, sizeof(flush_buf))) + return -EFAULT; + pp_cmd->value = (void *)&flush_buf; + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL); + if (rc == 0) { + if (copy_to_user((void *)argp, + &flush_buf, + sizeof(flush_buf))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + } + pp_cmd->value = argp; + } + } + break; + case VPE_CMD_OPERATION_MODE_CFG: { + struct msm_vpe_op_mode_cfg_zsl op_mode_cfg; + if (sizeof(struct msm_vpe_op_mode_cfg_zsl) != + pp_cmd->length) { + D("%s: size mismatch(id=%d, len = %d, expected = %d", + __func__, pp_cmd->id, pp_cmd->length, + sizeof(struct msm_vpe_op_mode_cfg_zsl)); + rc = -EINVAL; + break; + } + if (copy_from_user(&op_mode_cfg, + pp_cmd->value, + sizeof(op_mode_cfg))) + return -EFAULT; + pp_cmd->value = (void *)&op_mode_cfg; + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL); + break; + } + case VPE_CMD_INPUT_PLANE_CFG: { + struct msm_vpe_input_plane_cfg input_cfg; + if (sizeof(struct msm_vpe_input_plane_cfg) != + pp_cmd->length) { + D("%s: mismatch(id=%d, len = %d, expected = %d", + __func__, pp_cmd->id, pp_cmd->length, + sizeof(struct msm_vpe_input_plane_cfg)); + rc = -EINVAL; + break; + } + if (copy_from_user( + &input_cfg, pp_cmd->value, sizeof(input_cfg))) + return -EFAULT; + pp_cmd->value = (void *)&input_cfg; + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL); + break; + } + case VPE_CMD_OUTPUT_PLANE_CFG: { + struct msm_vpe_output_plane_cfg_zsl output_cfg; + if (sizeof(struct msm_vpe_output_plane_cfg_zsl) != + pp_cmd->length) { + D("%s: size mismatch(id=%d, len = %d, expected = %d", + __func__, pp_cmd->id, pp_cmd->length, + sizeof(struct msm_vpe_output_plane_cfg_zsl)); + rc = -EINVAL; + break; + } + if (copy_from_user(&output_cfg, pp_cmd->value, + sizeof(output_cfg))) { + D("%s: cannot copy pp_cmd->value, size=%d", + __func__, pp_cmd->length); + return -EFAULT; + } + pp_cmd->value = (void *)&output_cfg; + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL); + break; + } + case VPE_CMD_INPUT_PLANE_UPDATE: { + struct msm_vpe_input_plane_update_cfg input_update_cfg; + if (sizeof(struct msm_vpe_input_plane_update_cfg) != + pp_cmd->length) { + D("%s: size mismatch(id=%d, len = %d, expected = %d", + __func__, pp_cmd->id, pp_cmd->length, + sizeof(struct msm_vpe_input_plane_update_cfg)); + rc = -EINVAL; + break; + } + if (copy_from_user(&input_update_cfg, pp_cmd->value, + sizeof(input_update_cfg))) + return -EFAULT; + pp_cmd->value = (void *)&input_update_cfg; + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL); + break; + } + case VPE_CMD_SCALE_CFG_TYPE: { + struct msm_vpe_scaler_cfg scaler_cfg; + if (sizeof(struct msm_vpe_scaler_cfg) != + pp_cmd->length) { + D("%s: size mismatch(id=%d, len = %d, expected = %d", + __func__, pp_cmd->id, pp_cmd->length, + sizeof(struct msm_vpe_scaler_cfg)); + rc = -EINVAL; + break; + } + if (copy_from_user(&scaler_cfg, pp_cmd->value, + sizeof(scaler_cfg))) + return -EFAULT; + pp_cmd->value = (void *)&scaler_cfg; + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL); + break; + } + case VPE_CMD_ZOOM: { + struct msm_mctl_pp_frame_info *zoom; + zoom = kmalloc(sizeof(struct msm_mctl_pp_frame_info), + GFP_ATOMIC); + if (!zoom) { + rc = -ENOMEM; + break; + } + if (sizeof(zoom->pp_frame_cmd) != pp_cmd->length) { + D("%s: size mismatch(id=%d, len = %d, expected = %d", + __func__, pp_cmd->id, pp_cmd->length, + sizeof(zoom->pp_frame_cmd)); + rc = -EINVAL; + kfree(zoom); + break; + } + if (copy_from_user(&zoom->pp_frame_cmd, pp_cmd->value, + sizeof(zoom->pp_frame_cmd))) { + kfree(zoom); + return -EFAULT; + } + D("%s: src=0x%x, dest=0x%x,cookie=0x%x,action=0x%x,path=0x%x", + __func__, zoom->pp_frame_cmd.src_buf_handle, + zoom->pp_frame_cmd.dest_buf_handle, + zoom->pp_frame_cmd.cookie, + zoom->pp_frame_cmd.vpe_output_action, + zoom->pp_frame_cmd.path); + idx = msm_mctl_pp_path_to_inst_index(p_mctl->sync.pcam_sync, + zoom->pp_frame_cmd.path); + if (idx < 0) { + pr_err("%s Invalid path, returning\n", __func__); + kfree(zoom); + return idx; + } + pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx]; + if (!pcam_inst) { + pr_err("%s Invalid instance, returning\n", __func__); + kfree(zoom); + return -EINVAL; + } + zoom->user_cmd = pp_cmd->id; + rc = msm_mctl_pp_get_phy_addr(pcam_inst, + zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame); + if (rc) { + kfree(zoom); + break; + } + rc = msm_mctl_pp_get_phy_addr(pcam_inst, + zoom->pp_frame_cmd.dest_buf_handle, &zoom->dest_frame); + if (rc) { + kfree(zoom); + break; + } + rc = msm_mctl_pp_copy_timestamp_and_frame_id( + zoom->pp_frame_cmd.src_buf_handle, + + zoom->pp_frame_cmd.dest_buf_handle); + if (rc) { + kfree(zoom); + break; + } + rc = msm_isp_subdev_ioctl_vpe( + p_mctl->isp_sdev->sd_vpe, pp_cmd, (void *)zoom); + if (rc) { + kfree(zoom); + break; + } + break; + } + default: + rc = -1; + break; + } + return rc; +} + +static int msm_mctl_pp_path_to_msg_type(int path) +{ + switch (path) { + case OUTPUT_TYPE_P: + return VFE_MSG_OUTPUT_P; + case OUTPUT_TYPE_V: + return VFE_MSG_OUTPUT_V; + case OUTPUT_TYPE_S: + return VFE_MSG_OUTPUT_S; + case OUTPUT_TYPE_T: + default: + return VFE_MSG_OUTPUT_T; + } +} + +int msm_mctl_pp_proc_cmd(struct msm_cam_media_controller *p_mctl, + struct msm_mctl_pp_cmd *pp_cmd) +{ + int rc = 0; + struct msm_mctl_pp_frame_buffer pp_buffer; + struct msm_frame_buffer *buf = NULL; + void __user *argp = (void __user *)pp_cmd->value; + int msg_type = VFE_MSG_OUTPUT_V; + unsigned long flags; + + switch (pp_cmd->id) { + case MCTL_CMD_GET_FRAME_BUFFER: { + if (copy_from_user(&pp_buffer, pp_cmd->value, + sizeof(pp_buffer))) + return -EFAULT; + msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path); + buf = msm_mctl_get_free_buf(p_mctl, msg_type); + pp_buffer.buf_handle = (uint32_t)buf; + if (copy_to_user((void *)argp, + &pp_buffer, + sizeof(struct msm_mctl_pp_frame_buffer))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + } + break; + } + case MCTL_CMD_PUT_FRAME_BUFFER: { + if (copy_from_user(&pp_buffer, pp_cmd->value, + sizeof(pp_buffer))) + return -EFAULT; + msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path); + buf = (struct msm_frame_buffer *)pp_buffer.buf_handle; + msm_mctl_put_free_buf(p_mctl, msg_type, buf); + break; + } + case MCTL_CMD_DIVERT_FRAME_PP_PATH: { + struct msm_mctl_pp_divert_pp divert_pp; + if (copy_from_user(&divert_pp, pp_cmd->value, + sizeof(divert_pp))) + return -EFAULT; + D("%s: PP_PATH, path=%d", + __func__, divert_pp.path); + spin_lock_irqsave(&p_mctl->pp_info.lock, flags); + if (divert_pp.enable) + p_mctl->pp_info.pp_ctrl.pp_msg_type |= divert_pp.path; + else + p_mctl->pp_info.pp_ctrl.pp_msg_type &= ~divert_pp.path; + spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); + D("%s: pp path = 0x%x", __func__, + p_mctl->pp_info.pp_ctrl.pp_msg_type); + break; + } + default: + rc = -EPERM; + break; + } + return rc; +} + + +int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl, + unsigned int cmd, unsigned long arg) +{ + int rc = -EINVAL; + struct msm_mctl_post_proc_cmd pp_cmd; + void __user *argp = (void __user *)arg; + + if (copy_from_user(&pp_cmd, argp, sizeof(pp_cmd))) + return -EFAULT; + + switch (pp_cmd.type) { + case MSM_PP_CMD_TYPE_VPE: + rc = msm_mctl_pp_proc_vpe_cmd(p_mctl, &pp_cmd.cmd); + break; + case MSM_PP_CMD_TYPE_MCTL: + rc = msm_mctl_pp_proc_cmd(p_mctl, &pp_cmd.cmd); + break; + default: + rc = -EPERM; + break; + } + if (!rc) { + /* deep copy back the return value */ + if (copy_to_user((void *)arg, + &pp_cmd, + sizeof(struct msm_mctl_post_proc_cmd))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + } + } + return rc; +} + +int msm_mctl_pp_notify(struct msm_cam_media_controller *p_mctl, + struct msm_mctl_pp_frame_info *pp_frame_info) +{ + struct msm_mctl_pp_frame_cmd *pp_frame_cmd; + pp_frame_cmd = &pp_frame_info->pp_frame_cmd; + + D("%s: msm_cam_evt_divert_frame=%d", + __func__, sizeof(struct msm_mctl_pp_event_info)); + if ((MSM_MCTL_PP_VPE_FRAME_TO_APP & + pp_frame_cmd->vpe_output_action)) { + struct msm_free_buf done_frame; + int msg_type = + msm_mctl_pp_path_to_msg_type( + pp_frame_cmd->path); + + done_frame.ch_paddr[0] = + pp_frame_info->dest_frame.sp.phy_addr; + done_frame.vb = + pp_frame_info->dest_frame.handle; + msm_mctl_buf_done_pp( + p_mctl, msg_type, &done_frame, 0); + pr_info("%s: vpe done to app, vb=0x%x, path=%d, phy=0x%x", + __func__, done_frame.vb, + pp_frame_cmd->path, done_frame.ch_paddr[0]); + } + if ((MSM_MCTL_PP_VPE_FRAME_ACK & + pp_frame_cmd->vpe_output_action)) { + struct v4l2_event v4l2_evt; + struct msm_mctl_pp_event_info *pp_event_info; + struct msm_isp_event_ctrl *isp_event; + isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), + GFP_ATOMIC); + if (!isp_event) { + pr_err("%s Insufficient memory.", __func__); + return -ENOMEM; + } + memset(&v4l2_evt, 0, sizeof(v4l2_evt)); + *((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event; + + /* Get hold of pp event info struct inside event ctrl.*/ + pp_event_info = &(isp_event->isp_data.pp_event_info); + + pp_event_info->event = MCTL_PP_EVENT_CMD_ACK; + pp_event_info->ack.cmd = pp_frame_info->user_cmd; + pp_event_info->ack.status = 0; + pp_event_info->ack.cookie = pp_frame_cmd->cookie; + v4l2_evt.type = V4L2_EVENT_PRIVATE_START + + MSM_CAM_RESP_MCTL_PP_EVENT; + + v4l2_event_queue( + p_mctl->config_device-> + config_stat_event_queue.pvdev, + &v4l2_evt); + D("%s: ack to daemon, cookie=0x%x, event = 0x%x", + __func__, pp_frame_info->pp_frame_cmd.cookie, + v4l2_evt.type); + } + kfree(pp_frame_info); /* free mem */ + return 0; +} + +int msm_mctl_pp_reserve_free_frame( + struct msm_cam_media_controller *p_mctl, + void __user *arg) +{ + struct msm_cam_evt_divert_frame frame; + int msg_type, image_mode, rc = 0; + struct msm_free_buf free_buf; + int idx; + struct msm_cam_v4l2_dev_inst *pcam_inst; + + memset(&free_buf, 0, sizeof(struct msm_free_buf)); + if (copy_from_user(&frame, arg, + sizeof(struct msm_cam_evt_divert_frame))) + return -EFAULT; + switch (frame.frame.path) { + case OUTPUT_TYPE_P: + msg_type = VFE_MSG_OUTPUT_P; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW; + break; + case OUTPUT_TYPE_S: + msg_type = VFE_MSG_OUTPUT_S; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN; + break; + case OUTPUT_TYPE_V: + msg_type = VFE_MSG_OUTPUT_V; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO; + break; + case OUTPUT_TYPE_T: + default: + rc = -EFAULT; + return rc; + } + + idx = msm_mctl_out_type_to_inst_index( + p_mctl->sync.pcam_sync, msg_type); + if (idx < 0) { + pr_err("%s Invalid instance. returning\n", __func__); + return -EINVAL; + } + pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx]; + + rc = msm_mctl_reserve_free_buf(p_mctl, msg_type, &free_buf); + if (rc == 0) { + msm_mctl_pp_get_phy_addr(pcam_inst, free_buf.vb, &frame.frame); + if (copy_to_user((void *)arg, + &frame, + sizeof(frame))) { + ERR_COPY_TO_USER(); + rc = -EFAULT; + } + } + D("%s: reserve free buf, rc = %d, phy = 0x%x", + __func__, rc, free_buf.ch_paddr[0]); + return rc; +} + +int msm_mctl_pp_release_free_frame( + struct msm_cam_media_controller *p_mctl, + void __user *arg) +{ + struct msm_cam_evt_divert_frame frame; + int msg_type, image_mode, rc = 0; + struct msm_free_buf free_buf; + + if (copy_from_user(&frame, arg, + sizeof(struct msm_cam_evt_divert_frame))) + return -EFAULT; + switch (frame.frame.path) { + case OUTPUT_TYPE_P: + msg_type = VFE_MSG_OUTPUT_P; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW; + break; + case OUTPUT_TYPE_S: + msg_type = VFE_MSG_OUTPUT_S; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN; + break; + case OUTPUT_TYPE_V: + msg_type = VFE_MSG_OUTPUT_V; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO; + break; + case OUTPUT_TYPE_T: + default: + rc = -EFAULT; + return rc; + } + free_buf.ch_paddr[0] = frame.frame.sp.phy_addr; + rc = msm_mctl_release_free_buf(p_mctl, msg_type, &free_buf); + D("%s: release free buf, rc = %d, phy = 0x%x", + __func__, rc, free_buf.ch_paddr[0]); + + return rc; +} + +int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl, + void __user *arg) +{ + int rc = 0; + unsigned long flags; + spin_lock_irqsave(&p_mctl->pp_info.lock, flags); + if (copy_from_user(&p_mctl->pp_info.pp_key, + arg, sizeof(p_mctl->pp_info.pp_key))) + rc = -EFAULT; + else + D("%s: mctl=0x%p, pp_key_setting=0x%x", + __func__, p_mctl, p_mctl->pp_info.pp_key); + spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); + return rc; +} + +int msm_mctl_pp_done( + struct msm_cam_media_controller *p_mctl, + void __user *arg) +{ + struct msm_pp_frame frame; + int msg_type, image_mode, rc = 0; + int dirty = 0; + struct msm_free_buf buf; + unsigned long flags; + + if (copy_from_user(&frame, arg, sizeof(frame))) + return -EFAULT; + + spin_lock_irqsave(&p_mctl->pp_info.lock, flags); + switch (frame.path) { + case OUTPUT_TYPE_P: + msg_type = VFE_MSG_OUTPUT_P; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW; + break; + case OUTPUT_TYPE_S: + msg_type = VFE_MSG_OUTPUT_S; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN; + break; + case OUTPUT_TYPE_V: + msg_type = VFE_MSG_OUTPUT_V; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO; + break; + case OUTPUT_TYPE_T: + default: + rc = -EFAULT; + goto err; + } + D("%s Returning frame %x id %d to kernel ", __func__, + (int)frame.handle, frame.frame_id); + if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) { + memcpy(&buf, + &p_mctl->pp_info.div_frame[image_mode], + sizeof(buf)); + memset(&p_mctl->pp_info.div_frame[image_mode], + 0, sizeof(buf)); + if (p_mctl->pp_info.cur_frame_id[image_mode] != + frame.frame_id) { + /* dirty frame. should not pass to app */ + dirty = 1; + } + } else { + if (frame.num_planes > 1) + buf.ch_paddr[0] = frame.mp[0].phy_addr + + frame.mp[0].data_offset; + else + buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off; + } + spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); + /* here buf.addr is phy_addr */ + rc = msm_mctl_buf_done_pp(p_mctl, msg_type, &buf, dirty); + return rc; +err: + spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); + return rc; +} + +int msm_mctl_pp_divert_done( + struct msm_cam_media_controller *p_mctl, + void __user *arg) +{ + struct msm_pp_frame frame; + int msg_type, image_mode, rc = 0; + int dirty = 0; + struct msm_free_buf buf; + unsigned long flags; + D("%s enter\n", __func__); + + if (copy_from_user(&frame, arg, sizeof(frame))) + return -EFAULT; + + spin_lock_irqsave(&p_mctl->pp_info.lock, flags); + D("%s Frame path: %d\n", __func__, frame.path); + switch (frame.path) { + case OUTPUT_TYPE_P: + msg_type = VFE_MSG_OUTPUT_P; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW; + break; + case OUTPUT_TYPE_S: + msg_type = VFE_MSG_OUTPUT_S; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN; + break; + case OUTPUT_TYPE_V: + msg_type = VFE_MSG_OUTPUT_V; + image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO; + break; + case OUTPUT_TYPE_T: + default: + rc = -EFAULT; + goto err; + } + + if (frame.num_planes > 1) + buf.ch_paddr[0] = frame.mp[0].phy_addr; + else + buf.ch_paddr[0] = frame.sp.phy_addr; + + spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); + D("%s Frame done id: %d\n", __func__, frame.frame_id); + rc = msm_mctl_buf_done_pp(p_mctl, msg_type, &buf, dirty); + return rc; +err: + spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); + return rc; +} diff --git a/drivers/media/video/msm_zsl/msm_mem.c b/drivers/media/video/msm_zsl/msm_mem.c new file mode 100644 index 00000000000..3d00d878acf --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_mem.c @@ -0,0 +1,414 @@ +/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "msm.h" +#define UNCACHED 0 +#ifdef CONFIG_MSM_CAMERA_DEBUG +#define D(fmt, args...) pr_debug("msm_isp: " fmt, ##args) +#else +#define D(fmt, args...) do {} while (0) +#endif + +#define PAD_TO_WORD(a) (((a) + 3) & ~3) + +#define __CONTAINS(r, v, l, field) ({ \ + typeof(r) __r = r; \ + typeof(v) __v = v; \ + typeof(v) __e = __v + l; \ + int res = __v >= __r->field && \ + __e <= __r->field + __r->len; \ + res; \ +}) + +#define CONTAINS(r1, r2, field) ({ \ + typeof(r2) __r2 = r2; \ + __CONTAINS(r1, __r2->field, __r2->len, field); \ +}) + +#define IN_RANGE(r, v, field) ({ \ + typeof(r) __r = r; \ + typeof(v) __vv = v; \ + int res = ((__vv >= __r->field) && \ + (__vv < (__r->field + __r->len))); \ + res; \ +}) + +#define OVERLAPS(r1, r2, field) ({ \ + typeof(r1) __r1 = r1; \ + typeof(r2) __r2 = r2; \ + typeof(__r2->field) __v = __r2->field; \ + typeof(__v) __e = __v + __r2->len - 1; \ + int res = (IN_RANGE(__r1, __v, field) || \ + IN_RANGE(__r1, __e, field)); \ + res; \ +}) + +static DEFINE_MUTEX(hlist_mut); + +#ifdef CONFIG_ANDROID_PMEM +static int check_pmem_info(struct msm_pmem_info *info, int len) +{ + if (info->offset < len && + info->offset + info->len <= len && + info->planar0_off < len && + info->planar1_off < len) + return 0; + + pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n", + __func__, + info->offset, + info->len, + info->planar0_off, + info->planar1_off, + len); + return -EINVAL; +} +#endif + +static int check_overlap(struct hlist_head *ptype, + unsigned long paddr, + unsigned long len) +{ + struct msm_pmem_region *region; + struct msm_pmem_region t = { .paddr = paddr, .len = len }; + struct hlist_node *node; + + hlist_for_each_entry(region, node, ptype, list) { + if (CONTAINS(region, &t, paddr) || + CONTAINS(&t, region, paddr) || + OVERLAPS(region, &t, paddr)) { + CDBG(" region (PHYS %p len %ld)" + " clashes with registered region" + " (paddr %p len %ld)\n", + (void *)t.paddr, t.len, + (void *)region->paddr, region->len); + return -EINVAL; + } + } + + return 0; +} + +static int msm_pmem_table_add(struct hlist_head *ptype, + struct msm_pmem_info *info, struct ion_client *client) +{ + unsigned long paddr; +#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION + unsigned long kvstart; + struct file *file; +#endif + int rc = -ENOMEM; + + unsigned long len; + struct msm_pmem_region *region; + + region = kmalloc(sizeof(struct msm_pmem_region), GFP_KERNEL); + if (!region) + goto out; +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + region->handle = ion_import_dma_buf(client, info->fd); + if (IS_ERR_OR_NULL(region->handle)) + goto out1; + if (ion_map_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL, + SZ_4K, 0, &paddr, &len, UNCACHED, 0) < 0) + goto out2; +#elif CONFIG_ANDROID_PMEM + rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file); + if (rc < 0) { + pr_err("%s: get_pmem_file fd %d error %d\n", + __func__, info->fd, rc); + goto out1; + } + region->file = file; +#else + paddr = 0; + file = NULL; + kvstart = 0; +#endif + if (!info->len) + info->len = len; + rc = check_pmem_info(info, len); + if (rc < 0) + goto out3; + paddr += info->offset; + len = info->len; + + if (check_overlap(ptype, paddr, len) < 0) { + rc = -EINVAL; + goto out3; + } + + CDBG("%s: type %d, active flag %d, paddr 0x%lx, vaddr 0x%lx\n", + __func__, info->type, info->active, paddr, + (unsigned long)info->vaddr); + + INIT_HLIST_NODE(®ion->list); + region->paddr = paddr; + region->len = len; + memcpy(®ion->info, info, sizeof(region->info)); + D("%s Adding region to list with type %d\n", __func__, + region->info.type); + D("%s pmem_stats address is 0x%p\n", __func__, ptype); + hlist_add_head(&(region->list), ptype); + + return 0; +out3: +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_unmap_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL); +#endif +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +out2: + ion_free(client, region->handle); +#elif CONFIG_ANDROID_PMEM + put_pmem_file(region->file); +#endif +out1: + kfree(region); +out: + return rc; +} + +static int __msm_register_pmem(struct hlist_head *ptype, + struct msm_pmem_info *pinfo, struct ion_client *client) +{ + int rc = 0; + + switch (pinfo->type) { + case MSM_PMEM_AF: + case MSM_PMEM_AEC: + case MSM_PMEM_AWB: + case MSM_PMEM_RS: + case MSM_PMEM_CS: + case MSM_PMEM_IHIST: + case MSM_PMEM_SKIN: + case MSM_PMEM_AEC_AWB: + rc = msm_pmem_table_add(ptype, pinfo, client); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static int __msm_pmem_table_del(struct hlist_head *ptype, + struct msm_pmem_info *pinfo, struct ion_client *client) +{ + int rc = 0; + struct msm_pmem_region *region; + struct hlist_node *node, *n; + + switch (pinfo->type) { + case MSM_PMEM_AF: + case MSM_PMEM_AEC: + case MSM_PMEM_AWB: + case MSM_PMEM_RS: + case MSM_PMEM_CS: + case MSM_PMEM_IHIST: + case MSM_PMEM_SKIN: + case MSM_PMEM_AEC_AWB: + hlist_for_each_entry_safe(region, node, n, + ptype, list) { + + if (pinfo->type == region->info.type && + pinfo->vaddr == region->info.vaddr && + pinfo->fd == region->info.fd) { + hlist_del(node); +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_unmap_iommu(client, region->handle, + CAMERA_DOMAIN, GEN_POOL); + ion_free(client, region->handle); +#else + put_pmem_file(region->file); +#endif + kfree(region); + } + } + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +/* return of 0 means failure */ +uint8_t msm_pmem_region_lookup(struct hlist_head *ptype, + int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount) +{ + struct msm_pmem_region *region; + struct msm_pmem_region *regptr; + struct hlist_node *node, *n; + + uint8_t rc = 0; + D("%s\n", __func__); + regptr = reg; + mutex_lock(&hlist_mut); + hlist_for_each_entry_safe(region, node, n, ptype, list) { + if (region->info.type == pmem_type && region->info.active) { + *regptr = *region; + rc += 1; + if (rc >= maxcount) + break; + regptr++; + } + } + D("%s finished, rc=%d\n", __func__, rc); + mutex_unlock(&hlist_mut); + return rc; +} + +int msm_pmem_region_get_phy_addr(struct hlist_head *ptype, + struct msm_mem_map_info *mem_map, int32_t *phyaddr) +{ + struct msm_pmem_region *region; + struct hlist_node *node, *n; + int pmem_type = mem_map->mem_type; + int rc = -EFAULT; + + D("%s\n", __func__); + *phyaddr = 0; + mutex_lock(&hlist_mut); + hlist_for_each_entry_safe(region, node, n, ptype, list) { + if (region->info.type == pmem_type && + (uint32_t)region->info.vaddr == mem_map->cookie) { + *phyaddr = (int32_t)region->paddr; + rc = 0; + break; + } + } + D("%s finished, phy_addr = 0x%x, rc=%d\n", __func__, *phyaddr, rc); + mutex_unlock(&hlist_mut); + return rc; +} + +uint8_t msm_pmem_region_lookup_2(struct hlist_head *ptype, + int pmem_type, + struct msm_pmem_region *reg, + uint8_t maxcount) +{ + struct msm_pmem_region *region; + struct msm_pmem_region *regptr; + struct hlist_node *node, *n; + uint8_t rc = 0; + regptr = reg; + mutex_lock(&hlist_mut); + hlist_for_each_entry_safe(region, node, n, ptype, list) { + D("Mio: info.type=%d, pmem_type = %d," + "info.active = %d\n", + region->info.type, pmem_type, region->info.active); + + if (region->info.type == pmem_type && region->info.active) { + D("info.type=%d, pmem_type = %d," + "info.active = %d,\n", + region->info.type, pmem_type, + region->info.active); + *regptr = *region; + region->info.type = MSM_PMEM_VIDEO; + rc += 1; + if (rc >= maxcount) + break; + regptr++; + } + } + mutex_unlock(&hlist_mut); + return rc; +} + +unsigned long msm_pmem_stats_vtop_lookup( + struct msm_sync *sync, + unsigned long buffer, + int fd) +{ + struct msm_pmem_region *region; + struct hlist_node *node, *n; + + hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) { + if (((unsigned long)(region->info.vaddr) == buffer) && + (region->info.fd == fd) && + region->info.active == 0) { + region->info.active = 1; + return region->paddr; + } + } + + return 0; +} + +unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync, + unsigned long addr, int *fd) +{ + struct msm_pmem_region *region; + struct hlist_node *node, *n; + + hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) { + if (addr == region->paddr && region->info.active) { + /* offset since we could pass vaddr inside a + * registered pmem buffer */ + *fd = region->info.fd; + region->info.active = 0; + return (unsigned long)(region->info.vaddr); + } + } + + return 0; +} + +int msm_register_pmem(struct hlist_head *ptype, void __user *arg, + struct ion_client *client) +{ + struct msm_pmem_info info; + + if (copy_from_user(&info, arg, sizeof(info))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + return __msm_register_pmem(ptype, &info, client); +} +EXPORT_SYMBOL(msm_register_pmem); + +int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg, + struct ion_client *client) +{ + struct msm_pmem_info info; + + if (copy_from_user(&info, arg, sizeof(info))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + + return __msm_pmem_table_del(ptype, &info, client); +} +EXPORT_SYMBOL(msm_pmem_table_del); diff --git a/drivers/media/video/msm_zsl/msm_vfe31.c b/drivers/media/video/msm_zsl/msm_vfe31.c new file mode 100644 index 00000000000..b22b6c54a5b --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe31.c @@ -0,0 +1,3736 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "msm_vfe31.h" +#include "msm_vpe1.h" + +atomic_t irq_cnt; + +#define CHECKED_COPY_FROM_USER(in) { \ + if (copy_from_user((in), (void __user *)cmd->value, \ + cmd->length)) { \ + rc = -EFAULT; \ + break; \ + } \ +} + +static struct vfe31_ctrl_type *vfe31_ctrl; +static struct msm_camera_io_clk camio_clk; +static void *vfe_syncdata; +static void vfe31_send_msg_no_payload(enum VFE31_MESSAGE_ID id); +static void vfe31_reset_hist_cfg(void); + +struct vfe31_isr_queue_cmd { + struct list_head list; + uint32_t vfeInterruptStatus0; + uint32_t vfeInterruptStatus1; + uint32_t vfePingPongStatus; + struct vfe_frame_asf_info vfeAsfFrameInfo; + struct vfe_frame_bpc_info vfeBpcFrameInfo; + struct vfe_msg_camif_status vfeCamifStatusLocal; +}; + +static struct vfe31_cmd_type vfe31_cmd[] = { +/* 0*/ {V31_DUMMY_0}, + {V31_SET_CLK}, + {V31_RESET}, + {V31_START}, + {V31_TEST_GEN_START}, +/* 5*/ {V31_OPERATION_CFG, V31_OPERATION_CFG_LEN}, + {V31_AXI_OUT_CFG, V31_AXI_OUT_LEN, V31_AXI_OUT_OFF, 0xFF}, + {V31_CAMIF_CFG, V31_CAMIF_LEN, V31_CAMIF_OFF, 0xFF}, + {V31_AXI_INPUT_CFG}, + {V31_BLACK_LEVEL_CFG, V31_BLACK_LEVEL_LEN, V31_BLACK_LEVEL_OFF, + 0xFF}, +/*10*/ {V31_ROLL_OFF_CFG, V31_ROLL_OFF_CFG_LEN, V31_ROLL_OFF_CFG_OFF, + 0xFF}, + {V31_DEMUX_CFG, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF}, + {V31_DEMOSAIC_0_CFG, V31_DEMOSAIC_0_LEN, V31_DEMOSAIC_0_OFF, + 0xFF}, + {V31_DEMOSAIC_1_CFG, V31_DEMOSAIC_1_LEN, V31_DEMOSAIC_1_OFF, + 0xFF}, + {V31_DEMOSAIC_2_CFG, V31_DEMOSAIC_2_LEN, V31_DEMOSAIC_2_OFF, + 0xFF}, +/*15*/ {V31_FOV_CFG, V31_FOV_LEN, V31_FOV_OFF, 0xFF}, + {V31_MAIN_SCALER_CFG, V31_MAIN_SCALER_LEN, V31_MAIN_SCALER_OFF, + 0xFF}, + {V31_WB_CFG, V31_WB_LEN, V31_WB_OFF, 0xFF}, + {V31_COLOR_COR_CFG, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF, 0xFF}, + {V31_RGB_G_CFG, V31_RGB_G_LEN, V31_RGB_G_OFF, 0xFF}, +/*20*/ {V31_LA_CFG, V31_LA_LEN, V31_LA_OFF, 0xFF }, + {V31_CHROMA_EN_CFG, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF, 0xFF}, + {V31_CHROMA_SUP_CFG, V31_CHROMA_SUP_LEN, V31_CHROMA_SUP_OFF, + 0xFF}, + {V31_MCE_CFG, V31_MCE_LEN, V31_MCE_OFF, 0xFF}, + {V31_SK_ENHAN_CFG, V31_SCE_LEN, V31_SCE_OFF, 0xFF}, +/*25*/ {V31_ASF_CFG, V31_ASF_LEN, V31_ASF_OFF, 0xFF}, + {V31_S2Y_CFG, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF}, + {V31_S2CbCr_CFG, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF}, + {V31_CHROMA_SUBS_CFG, V31_CHROMA_SUBS_LEN, V31_CHROMA_SUBS_OFF, + 0xFF}, + {V31_OUT_CLAMP_CFG, V31_OUT_CLAMP_LEN, V31_OUT_CLAMP_OFF, + 0xFF}, +/*30*/ {V31_FRAME_SKIP_CFG, V31_FRAME_SKIP_LEN, V31_FRAME_SKIP_OFF, + 0xFF}, + {V31_DUMMY_1}, + {V31_DUMMY_2}, + {V31_DUMMY_3}, + {V31_UPDATE}, +/*35*/ {V31_BL_LVL_UPDATE, V31_BLACK_LEVEL_LEN, V31_BLACK_LEVEL_OFF, + 0xFF}, + {V31_DEMUX_UPDATE, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF}, + {V31_DEMOSAIC_1_UPDATE, V31_DEMOSAIC_1_LEN, V31_DEMOSAIC_1_OFF, + 0xFF}, + {V31_DEMOSAIC_2_UPDATE, V31_DEMOSAIC_2_LEN, V31_DEMOSAIC_2_OFF, + 0xFF}, + {V31_FOV_UPDATE, V31_FOV_LEN, V31_FOV_OFF, 0xFF}, +/*40*/ {V31_MAIN_SCALER_UPDATE, V31_MAIN_SCALER_LEN, V31_MAIN_SCALER_OFF, + 0xFF}, + {V31_WB_UPDATE, V31_WB_LEN, V31_WB_OFF, 0xFF}, + {V31_COLOR_COR_UPDATE, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF, + 0xFF}, + {V31_RGB_G_UPDATE, V31_RGB_G_LEN, V31_CHROMA_EN_OFF, 0xFF}, + {V31_LA_UPDATE, V31_LA_LEN, V31_LA_OFF, 0xFF }, +/*45*/ {V31_CHROMA_EN_UPDATE, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF, + 0xFF}, + {V31_CHROMA_SUP_UPDATE, V31_CHROMA_SUP_LEN, V31_CHROMA_SUP_OFF, + 0xFF}, + {V31_MCE_UPDATE, V31_MCE_LEN, V31_MCE_OFF, 0xFF}, + {V31_SK_ENHAN_UPDATE, V31_SCE_LEN, V31_SCE_OFF, 0xFF}, + {V31_S2CbCr_UPDATE, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF}, +/*50*/ {V31_S2Y_UPDATE, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF}, + {V31_ASF_UPDATE, V31_ASF_UPDATE_LEN, V31_ASF_OFF, 0xFF}, + {V31_FRAME_SKIP_UPDATE}, + {V31_CAMIF_FRAME_UPDATE}, + {V31_STATS_AF_UPDATE, V31_STATS_AF_LEN, V31_STATS_AF_OFF}, +/*55*/ {V31_STATS_AE_UPDATE, V31_STATS_AE_LEN, V31_STATS_AE_OFF}, + {V31_STATS_AWB_UPDATE, V31_STATS_AWB_LEN, V31_STATS_AWB_OFF}, + {V31_STATS_RS_UPDATE, V31_STATS_RS_LEN, V31_STATS_RS_OFF}, + {V31_STATS_CS_UPDATE, V31_STATS_CS_LEN, V31_STATS_CS_OFF}, + {V31_STATS_SKIN_UPDATE}, +/*60*/ {V31_STATS_IHIST_UPDATE, V31_STATS_IHIST_LEN, V31_STATS_IHIST_OFF}, + {V31_DUMMY_4}, + {V31_EPOCH1_ACK}, + {V31_EPOCH2_ACK}, + {V31_START_RECORDING}, +/*65*/ {V31_STOP_RECORDING}, + {V31_DUMMY_5}, + {V31_DUMMY_6}, + {V31_CAPTURE, V31_CAPTURE_LEN, 0xFF}, + {V31_DUMMY_7}, +/*70*/ {V31_STOP}, + {V31_GET_HW_VERSION}, + {V31_GET_FRAME_SKIP_COUNTS}, + {V31_OUTPUT1_BUFFER_ENQ}, + {V31_OUTPUT2_BUFFER_ENQ}, +/*75*/ {V31_OUTPUT3_BUFFER_ENQ}, + {V31_JPEG_OUT_BUF_ENQ}, + {V31_RAW_OUT_BUF_ENQ}, + {V31_RAW_IN_BUF_ENQ}, + {V31_STATS_AF_ENQ}, +/*80*/ {V31_STATS_AE_ENQ}, + {V31_STATS_AWB_ENQ}, + {V31_STATS_RS_ENQ}, + {V31_STATS_CS_ENQ}, + {V31_STATS_SKIN_ENQ}, +/*85*/ {V31_STATS_IHIST_ENQ}, + {V31_DUMMY_8}, + {V31_JPEG_ENC_CFG}, + {V31_DUMMY_9}, + {V31_STATS_AF_START, V31_STATS_AF_LEN, V31_STATS_AF_OFF}, +/*90*/ {V31_STATS_AF_STOP}, + {V31_STATS_AE_START, V31_STATS_AE_LEN, V31_STATS_AE_OFF}, + {V31_STATS_AE_STOP}, + {V31_STATS_AWB_START, V31_STATS_AWB_LEN, V31_STATS_AWB_OFF}, + {V31_STATS_AWB_STOP}, +/*95*/ {V31_STATS_RS_START, V31_STATS_RS_LEN, V31_STATS_RS_OFF}, + {V31_STATS_RS_STOP}, + {V31_STATS_CS_START, V31_STATS_CS_LEN, V31_STATS_CS_OFF}, + {V31_STATS_CS_STOP}, + {V31_STATS_SKIN_START}, +/*100*/ {V31_STATS_SKIN_STOP}, + {V31_STATS_IHIST_START, + V31_STATS_IHIST_LEN, V31_STATS_IHIST_OFF}, + {V31_STATS_IHIST_STOP}, + {V31_DUMMY_10}, + {V31_SYNC_TIMER_SETTING, V31_SYNC_TIMER_LEN, + V31_SYNC_TIMER_OFF}, +/*105*/ {V31_ASYNC_TIMER_SETTING, V31_ASYNC_TIMER_LEN, V31_ASYNC_TIMER_OFF}, + {V31_LIVESHOT}, + {V31_ZSL, V31_CAPTURE_LEN, 0xFF}, + {V31_STEREOCAM}, + {V31_LA_SETUP}, +/*110*/ {V31_XBAR_CFG, V31_XBAR_CFG_LEN, V31_XBAR_CFG_OFF}, +/*111*/ {V31_EZTUNE_CFG, V31_EZTUNE_CFG_LEN, V31_EZTUNE_CFG_OFF}, +}; + +uint32_t vfe31_AXI_WM_CFG[] = { + 0x0000004C, + 0x00000064, + 0x0000007C, + 0x00000094, + 0x000000AC, + 0x000000C4, + 0x000000DC, +}; + +static const char *vfe31_general_cmd[] = { + "DUMMY_0", /* 0 */ + "SET_CLK", + "RESET", + "START", + "TEST_GEN_START", + "OPERATION_CFG", /* 5 */ + "AXI_OUT_CFG", + "CAMIF_CFG", + "AXI_INPUT_CFG", + "BLACK_LEVEL_CFG", + "ROLL_OFF_CFG", /* 10 */ + "DEMUX_CFG", + "DEMOSAIC_0_CFG", /* general */ + "DEMOSAIC_1_CFG", /* ABF */ + "DEMOSAIC_2_CFG", /* BPC */ + "FOV_CFG", /* 15 */ + "MAIN_SCALER_CFG", + "WB_CFG", + "COLOR_COR_CFG", + "RGB_G_CFG", + "LA_CFG", /* 20 */ + "CHROMA_EN_CFG", + "CHROMA_SUP_CFG", + "MCE_CFG", + "SK_ENHAN_CFG", + "ASF_CFG", /* 25 */ + "S2Y_CFG", + "S2CbCr_CFG", + "CHROMA_SUBS_CFG", + "OUT_CLAMP_CFG", + "FRAME_SKIP_CFG", /* 30 */ + "DUMMY_1", + "DUMMY_2", + "DUMMY_3", + "UPDATE", + "BL_LVL_UPDATE", /* 35 */ + "DEMUX_UPDATE", + "DEMOSAIC_1_UPDATE", /* BPC */ + "DEMOSAIC_2_UPDATE", /* ABF */ + "FOV_UPDATE", + "MAIN_SCALER_UPDATE", /* 40 */ + "WB_UPDATE", + "COLOR_COR_UPDATE", + "RGB_G_UPDATE", + "LA_UPDATE", + "CHROMA_EN_UPDATE", /* 45 */ + "CHROMA_SUP_UPDATE", + "MCE_UPDATE", + "SK_ENHAN_UPDATE", + "S2CbCr_UPDATE", + "S2Y_UPDATE", /* 50 */ + "ASF_UPDATE", + "FRAME_SKIP_UPDATE", + "CAMIF_FRAME_UPDATE", + "STATS_AF_UPDATE", + "STATS_AE_UPDATE", /* 55 */ + "STATS_AWB_UPDATE", + "STATS_RS_UPDATE", + "STATS_CS_UPDATE", + "STATS_SKIN_UPDATE", + "STATS_IHIST_UPDATE", /* 60 */ + "DUMMY_4", + "EPOCH1_ACK", + "EPOCH2_ACK", + "START_RECORDING", + "STOP_RECORDING", /* 65 */ + "DUMMY_5", + "DUMMY_6", + "CAPTURE", + "DUMMY_7", + "STOP", /* 70 */ + "GET_HW_VERSION", + "GET_FRAME_SKIP_COUNTS", + "OUTPUT1_BUFFER_ENQ", + "OUTPUT2_BUFFER_ENQ", + "OUTPUT3_BUFFER_ENQ", /* 75 */ + "JPEG_OUT_BUF_ENQ", + "RAW_OUT_BUF_ENQ", + "RAW_IN_BUF_ENQ", + "STATS_AF_ENQ", + "STATS_AE_ENQ", /* 80 */ + "STATS_AWB_ENQ", + "STATS_RS_ENQ", + "STATS_CS_ENQ", + "STATS_SKIN_ENQ", + "STATS_IHIST_ENQ", /* 85 */ + "DUMMY_8", + "JPEG_ENC_CFG", + "DUMMY_9", + "STATS_AF_START", + "STATS_AF_STOP", /* 90 */ + "STATS_AE_START", + "STATS_AE_STOP", + "STATS_AWB_START", + "STATS_AWB_STOP", + "STATS_RS_START", /* 95 */ + "STATS_RS_STOP", + "STATS_CS_START", + "STATS_CS_STOP", + "STATS_SKIN_START", + "STATS_SKIN_STOP", /* 100 */ + "STATS_IHIST_START", + "STATS_IHIST_STOP", + "DUMMY_10", + "SYNC_TIMER_SETTING", + "ASYNC_TIMER_SETTING", /* 105 */ + "V31_LIVESHOT", + "V31_ZSL", + "V31_STEREOCAM", + "V31_LA_SETUP", + "V31_XBAR_CFG", +}; + +static void vfe_addr_convert(struct msm_vfe_phy_info *pinfo, + enum vfe_resp_msg type, void *data, void **ext, int32_t *elen) +{ + uint8_t outid; + switch (type) { + case VFE_MSG_OUTPUT_T: + case VFE_MSG_OUTPUT_P: + case VFE_MSG_OUTPUT_S: + case VFE_MSG_OUTPUT_V: + { + pinfo->output_id = + ((struct vfe_message *)data)->_u.msgOut.output_id; + + switch (type) { + case VFE_MSG_OUTPUT_P: + outid = OUTPUT_TYPE_P; + break; + case VFE_MSG_OUTPUT_V: + outid = OUTPUT_TYPE_V; + break; + case VFE_MSG_OUTPUT_T: + outid = OUTPUT_TYPE_T; + break; + case VFE_MSG_OUTPUT_S: + outid = OUTPUT_TYPE_S; + break; + default: + outid = 0xff; + break; + } + pinfo->output_id = outid; + pinfo->y_phy = + ((struct vfe_message *)data)->_u.msgOut.yBuffer; + pinfo->cbcr_phy = + ((struct vfe_message *)data)->_u.msgOut.cbcrBuffer; + + pinfo->frame_id = + ((struct vfe_message *)data)->_u.msgOut.frameCounter; + + ((struct vfe_msg_output *)(vfe31_ctrl->extdata))->bpcInfo = + ((struct vfe_message *)data)->_u.msgOut.bpcInfo; + ((struct vfe_msg_output *)(vfe31_ctrl->extdata))->asfInfo = + ((struct vfe_message *)data)->_u.msgOut.asfInfo; + ((struct vfe_msg_output *)(vfe31_ctrl->extdata))->frameCounter = + ((struct vfe_message *)data)->_u.msgOut.frameCounter; + *ext = vfe31_ctrl->extdata; + *elen = vfe31_ctrl->extlen; + } + break; + + default: + break; + } /* switch */ +} + + +static void vfe31_proc_ops(enum VFE31_MESSAGE_ID id, void *msg, size_t len) +{ + struct msm_vfe_resp *rp; + + rp = vfe31_ctrl->resp->vfe_alloc(sizeof(struct msm_vfe_resp), + vfe31_ctrl->syncdata, GFP_ATOMIC); + if (!rp) { + CDBG("rp: cannot allocate buffer\n"); + return; + } + CDBG("vfe31_proc_ops, msgId = %d\n", id); + rp->evt_msg.type = MSM_CAMERA_MSG; + rp->evt_msg.msg_id = id; + rp->evt_msg.len = len; + rp->evt_msg.data = msg; + + switch (rp->evt_msg.msg_id) { + case MSG_ID_SNAPSHOT_DONE: + rp->type = VFE_MSG_SNAPSHOT; + break; + + case MSG_ID_OUTPUT_P: + rp->type = VFE_MSG_OUTPUT_P; + vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_P, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + + case MSG_ID_OUTPUT_T: + rp->type = VFE_MSG_OUTPUT_T; + vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_T, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + + case MSG_ID_OUTPUT_S: + rp->type = VFE_MSG_OUTPUT_S; + vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_S, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + + case MSG_ID_OUTPUT_V: + rp->type = VFE_MSG_OUTPUT_V; + vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_V, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + + case MSG_ID_COMMON: + rp->type = VFE_MSG_COMMON; + rp->stats_msg.status_bits = ((struct vfe_message *) + rp->evt_msg.data)->_u.msgStats.status_bits; + rp->stats_msg.frame_id = ((struct vfe_message *) + rp->evt_msg.data)->_u.msgStats.frameCounter; + + rp->stats_msg.aec_buff = ((struct vfe_message *) + rp->evt_msg.data)->_u.msgStats.buff.aec; + rp->stats_msg.awb_buff = ((struct vfe_message *) + rp->evt_msg.data)->_u.msgStats.buff.awb; + rp->stats_msg.af_buff = ((struct vfe_message *) + rp->evt_msg.data)->_u.msgStats.buff.af; + rp->stats_msg.ihist_buff = ((struct vfe_message *) + rp->evt_msg.data)->_u.msgStats.buff.ihist; + rp->stats_msg.rs_buff = ((struct vfe_message *) + rp->evt_msg.data)->_u.msgStats.buff.rs; + rp->stats_msg.cs_buff = ((struct vfe_message *) + rp->evt_msg.data)->_u.msgStats.buff.cs; + rp->stats_msg.awb_ymin = ((struct vfe_message *) + rp->evt_msg.data)->_u.msgStats.buff.awb_ymin; + break; + + case MSG_ID_SYNC_TIMER0_DONE: + rp->type = VFE_MSG_SYNC_TIMER0; + break; + + case MSG_ID_SYNC_TIMER1_DONE: + rp->type = VFE_MSG_SYNC_TIMER1; + break; + + case MSG_ID_SYNC_TIMER2_DONE: + rp->type = VFE_MSG_SYNC_TIMER2; + break; + + default: + rp->type = VFE_MSG_GENERAL; + break; + } + + /* save the frame id.*/ + rp->evt_msg.frame_id = rp->phy.frame_id; + + vfe31_ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe31_ctrl->syncdata, + GFP_ATOMIC); +} + +static void vfe_send_outmsg(uint8_t msgid, uint32_t pyaddr, + uint32_t pcbcraddr) +{ + struct vfe_message msg; + uint8_t outid; + + msg._d = msgid; /* now the output mode is redundnat. */ + msg._u.msgOut.frameCounter = vfe31_ctrl->vfeFrameId; + + switch (msgid) { + case MSG_ID_OUTPUT_P: + outid = OUTPUT_TYPE_P; + break; + case MSG_ID_OUTPUT_V: + outid = OUTPUT_TYPE_V; + break; + case MSG_ID_OUTPUT_T: + outid = OUTPUT_TYPE_T; + break; + case MSG_ID_OUTPUT_S: + outid = OUTPUT_TYPE_S; + break; + default: + outid = 0xff; /* -1 for error condition.*/ + break; + } + msg._u.msgOut.output_id = msgid; + msg._u.msgOut.yBuffer = pyaddr; + msg._u.msgOut.cbcrBuffer = pcbcraddr; + + vfe31_proc_ops(msgid, &msg, sizeof(struct vfe_message)); + return; +} +static int vfe31_enable(struct camera_enable_cmd *enable) +{ + return 0; +} + +static void vfe31_stop(void) +{ + atomic_set(&vfe31_ctrl->vstate, 0); + atomic_set(&vfe31_ctrl->stop_ack_pending, 1); + + /* in either continuous or snapshot mode, stop command can be issued + * at any time. stop camif immediately. */ + msm_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY, + vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND); + + /* disable all interrupts. */ + msm_io_w(VFE_DISABLE_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_io_w(VFE_DISABLE_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* clear all pending interrupts*/ + msm_io_w(VFE_CLEAR_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_io_w(VFE_CLEAR_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1); + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, + vfe31_ctrl->vfebase + VFE_IRQ_CMD); + + /* now enable only halt_irq & reset_irq */ + msm_io_w(0xf0000000, /* this is for async timer. */ + vfe31_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_io_w(VFE_IMASK_AXI_HALT, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* then apply axi halt command. */ + msm_io_w_mb(AXI_HALT, + vfe31_ctrl->vfebase + VFE_AXI_CMD); +} + +static int vfe31_disable(struct camera_enable_cmd *enable, + struct platform_device *dev) +{ + msm_camio_set_perf_lvl(S_EXIT); + msm_camio_disable(dev); + return 0; +} + +static int vfe31_add_free_buf2(struct vfe31_output_ch *outch, + uint32_t paddr, uint32_t y_off, uint32_t cbcr_off) +{ + struct vfe31_free_buf *free_buf = NULL; + unsigned long flags = 0; + free_buf = kmalloc(sizeof(struct vfe31_free_buf), GFP_KERNEL); + if (!free_buf) + return -ENOMEM; + + spin_lock_irqsave(&outch->free_buf_lock, flags); + free_buf->paddr = paddr; + free_buf->y_off = y_off; + free_buf->cbcr_off = cbcr_off; + list_add_tail(&free_buf->node, &outch->free_buf_head); + + CDBG("%s: free_buf paddr = 0x%x, y_off = %d, cbcr_off = %d\n", + __func__, free_buf->paddr, free_buf->y_off, + free_buf->cbcr_off); + spin_unlock_irqrestore(&outch->free_buf_lock, flags); + return 0; +} + +#define vfe31_add_free_buf(outch, regptr) \ + vfe31_add_free_buf2(outch, regptr->paddr, regptr->info.y_off, \ + regptr->info.cbcr_off) + +#define vfe31_free_buf_available(outch) \ + (!list_empty(&outch.free_buf_head)) + +static inline struct vfe31_free_buf *vfe31_get_free_buf( + struct vfe31_output_ch *outch) +{ + unsigned long flags = 0; + struct vfe31_free_buf *free_buf = NULL; + spin_lock_irqsave(&outch->free_buf_lock, flags); + if (!list_empty(&outch->free_buf_head)) { + free_buf = list_first_entry(&outch->free_buf_head, + struct vfe31_free_buf, node); + if (free_buf) + list_del_init(&free_buf->node); + } + spin_unlock_irqrestore(&outch->free_buf_lock, flags); + return free_buf; +} + +static inline void vfe31_reset_free_buf_queue( + struct vfe31_output_ch *outch) +{ + unsigned long flags = 0; + struct vfe31_free_buf *free_buf = NULL; + spin_lock_irqsave(&outch->free_buf_lock, flags); + while (!list_empty(&outch->free_buf_head)) { + free_buf = list_first_entry(&outch->free_buf_head, + struct vfe31_free_buf, node); + if (free_buf) { + list_del_init(&free_buf->node); + kfree(free_buf); + } + } + spin_unlock_irqrestore(&outch->free_buf_lock, flags); +} + +#define vfe31_init_free_buf_queue() do { \ + INIT_LIST_HEAD(&vfe31_ctrl->outpath.out0.free_buf_head); \ + INIT_LIST_HEAD(&vfe31_ctrl->outpath.out1.free_buf_head); \ + INIT_LIST_HEAD(&vfe31_ctrl->outpath.out2.free_buf_head); \ + spin_lock_init(&vfe31_ctrl->outpath.out0.free_buf_lock); \ + spin_lock_init(&vfe31_ctrl->outpath.out1.free_buf_lock); \ + spin_lock_init(&vfe31_ctrl->outpath.out2.free_buf_lock); \ +} while (0) + +#define vfe31_reset_free_buf_queue_all() do { \ + vfe31_reset_free_buf_queue(&vfe31_ctrl->outpath.out0); \ + vfe31_reset_free_buf_queue(&vfe31_ctrl->outpath.out1); \ + vfe31_reset_free_buf_queue(&vfe31_ctrl->outpath.out2); \ +} while (0) + +static int vfe31_config_axi(int mode, struct axidata *ad, uint32_t *ao) +{ + int i; + uint32_t *p, *p1, *p2, *p3; + int32_t *ch_info; + struct vfe31_output_ch *outp1, *outp2, *outp3; + struct msm_pmem_region *regp1 = NULL; + struct msm_pmem_region *regp2 = NULL; + struct msm_pmem_region *regp3 = NULL; + int ret; + struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata; + + outp1 = NULL; + outp2 = NULL; + outp3 = NULL; + + p = ao + 2; + + /* Update the corresponding write masters for each output*/ + ch_info = ao + V31_AXI_CFG_LEN; + vfe31_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info; + vfe31_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16); + vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++; + vfe31_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info; + vfe31_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16); + vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++; + vfe31_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info; + vfe31_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16); + vfe31_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++; + + CDBG("vfe31_config_axi: mode = %d, bufnum1 = %d, bufnum2 = %d" + "bufnum3 = %d", mode, ad->bufnum1, ad->bufnum2, ad->bufnum3); + + switch (mode) { + + case OUTPUT_2: { + if (ad->bufnum2 != 3) + return -EINVAL; + regp1 = &(ad->region[ad->bufnum1]); + outp1 = &(vfe31_ctrl->outpath.out0); + vfe31_ctrl->outpath.output_mode |= VFE31_OUTPUT_MODE_PT; + + for (i = 0; i < 2; i++) { + p1 = ao + 6 + i; /* wm0 for y */ + *p1 = (regp1->paddr + regp1->info.y_off); + + p1 = ao + 12 + i; /* wm1 for cbcr */ + *p1 = (regp1->paddr + regp1->info.cbcr_off); + regp1++; + } + ret = vfe31_add_free_buf(outp1, regp1); + if (ret < 0) + return ret; + } + break; + + case OUTPUT_1_AND_2: + /* use wm0& 4 for thumbnail, wm1&5 for main image.*/ + if ((ad->bufnum1 < 1) || (ad->bufnum2 < 1)) + return -EINVAL; + vfe31_ctrl->outpath.output_mode |= + VFE31_OUTPUT_MODE_S; /* main image.*/ + vfe31_ctrl->outpath.output_mode |= + VFE31_OUTPUT_MODE_PT; /* thumbnail. */ + + /* this is thumbnail buffer. */ + regp1 = &(ad->region[ad->bufnum1-1]); + /* this is main image buffer. */ + regp2 = &(ad->region[ad->bufnum1+ad->bufnum2-1]); + + outp1 = &(vfe31_ctrl->outpath.out0); + outp2 = &(vfe31_ctrl->outpath.out1); /* snapshot */ + + /* Parse the buffers!!! */ + if (ad->bufnum2 == 1) { /* assuming bufnum1 = bufnum2 */ + p1 = ao + 6; /* wm0 ping */ + *p1++ = (regp1->paddr + regp1->info.y_off); + + /* this is to duplicate ping address to pong.*/ + *p1 = (regp1->paddr + regp1->info.y_off); + + p1 = ao + 30; /* wm4 ping */ + *p1++ = (regp1->paddr + regp1->info.cbcr_off); + CDBG("%s: regp1->info.cbcr_off = 0x%x\n", __func__, + regp1->info.cbcr_off); + + /* this is to duplicate ping address to pong.*/ + *p1 = (regp1->paddr + regp1->info.cbcr_off); + + p1 = ao + 12; /* wm1 ping */ + *p1++ = (regp2->paddr + regp2->info.y_off); + + /* pong = ping,*/ + *p1 = (regp2->paddr + regp2->info.y_off); + + p1 = ao + 36; /* wm5 */ + *p1++ = (regp2->paddr + regp2->info.cbcr_off); + CDBG("%s: regp2->info.cbcr_off = 0x%x\n", __func__, + regp2->info.cbcr_off); + + /* pong = ping,*/ + *p1 = (regp2->paddr + regp2->info.cbcr_off); + } else { /* more than one snapshot */ + /* first fill ping & pong */ + for (i = 0; i < 2; i++) { + p1 = ao + 6 + i; /* wm0 for y */ + *p1 = (regp1->paddr + regp1->info.y_off); + p1 = ao + 30 + i; /* wm4 for cbcr */ + *p1 = (regp1->paddr + regp1->info.cbcr_off); + regp1--; + } + + for (i = 0; i < 2; i++) { + p2 = ao + 12 + i; /* wm1 for y */ + *p2 = (regp2->paddr + regp2->info.y_off); + p2 = ao + 36 + i; /* wm5 for cbcr */ + *p2 = (regp2->paddr + regp2->info.cbcr_off); + regp2--; + } + + for (i = 2; i < ad->bufnum1; i++) { + ret = vfe31_add_free_buf(outp1, regp1); + if (ret < 0) + return ret; + regp1--; + } + + for (i = 2; i < ad->bufnum2; i++) { + ret = vfe31_add_free_buf(outp2, regp2); + if (ret < 0) + return ret; + regp2--; + } + } + break; + + case OUTPUT_1_2_AND_3: + CDBG("%s: OUTPUT_1_2_AND_3", __func__); + CDBG("%s: %d %d %d", __func__, ad->bufnum1, ad->bufnum2, + ad->bufnum3); + /* use wm0& 4 for postview, wm1&5 for preview.*/ + /* use wm2& 6 for main img */ + if ((ad->bufnum1 < 1) || (ad->bufnum2 < 1) || (ad->bufnum3 < 1)) + return -EINVAL; + vfe31_ctrl->outpath.output_mode |= + VFE31_OUTPUT_MODE_S; /* main image.*/ + vfe31_ctrl->outpath.output_mode |= + VFE31_OUTPUT_MODE_P; /* preview. */ + vfe31_ctrl->outpath.output_mode |= + VFE31_OUTPUT_MODE_T; /* thumbnail. */ + + /* this is preview buffer. */ + regp1 = &(ad->region[0]); + /* this is thumbnail buffer. */ + regp2 = &(ad->region[ad->bufnum1]); + /* this is main image buffer. */ + regp3 = &(ad->region[ad->bufnum1+ad->bufnum2]); + outp1 = &(vfe31_ctrl->outpath.out0); + outp2 = &(vfe31_ctrl->outpath.out1); + outp3 = &(vfe31_ctrl->outpath.out2); + + /* Parse the buffers!!! */ + /* first fill ping & pong */ + for (i = 0; i < 2; i++) { + p1 = ao + 6 + i; /* wm0 for y */ + *p1 = (regp1->paddr + regp1->info.y_off); + p1 = ao + 30 + i; /* wm4 for cbcr */ + *p1 = (regp1->paddr + regp1->info.cbcr_off); + regp1++; + } + + for (i = 0; i < 2; i++) { + p2 = ao + 12 + i; /* wm1 for y */ + *p2 = (regp2->paddr + regp2->info.y_off); + p2 = ao + 36 + i; /* wm5 for cbcr */ + *p2 = (regp2->paddr + regp2->info.cbcr_off); + regp2++; + } + + for (i = 0; i < 2; i++) { + p3 = ao + 18 + i; /* wm2 for y */ + *p3 = (regp3->paddr + regp3->info.y_off); + p3 = ao + 42 + i; /* wm6 for cbcr */ + *p3 = (regp3->paddr + regp3->info.cbcr_off); + regp3++; + } + + for (i = 2; i < ad->bufnum1; i++) { + ret = vfe31_add_free_buf(outp1, regp1); + if (ret < 0) + return ret; + regp1++; + } + + for (i = 2; i < ad->bufnum2; i++) { + ret = vfe31_add_free_buf(outp2, regp2); + if (ret < 0) + return ret; + regp2++; + } + + for (i = 2; i < ad->bufnum3; i++) { + ret = vfe31_add_free_buf(outp3, regp3); + if (ret < 0) + return ret; + regp3++; + } + break; + + case OUTPUT_1_AND_3: { + /* use wm0&4 for preview, wm1&5 for video.*/ + if ((ad->bufnum1 < 2) || (ad->bufnum2 < 2)) + return -EINVAL; + +#ifdef CONFIG_MSM_CAMERA_V4L2 + *p++ = 0x1; /* xbar cfg0 */ + *p = 0x1a03; /* xbar cfg1 */ +#endif + vfe31_ctrl->outpath.output_mode |= + VFE31_OUTPUT_MODE_V; /* video*/ + vfe31_ctrl->outpath.output_mode |= + VFE31_OUTPUT_MODE_PT; /* preview */ + + regp1 = &(ad->region[0]); /* this is preview buffer. */ + regp2 = &(ad->region[ad->bufnum1]);/* this is video buffer. */ + outp1 = &(vfe31_ctrl->outpath.out0); /* preview */ + outp2 = &(vfe31_ctrl->outpath.out2); /* video */ + + + for (i = 0; i < 2; i++) { + p1 = ao + 6 + i; /* wm0 for y */ + *p1 = (regp1->paddr + regp1->info.y_off); + + p1 = ao + 30 + i; /* wm4 for cbcr */ + *p1 = (regp1->paddr + regp1->info.cbcr_off); + regp1++; + } + + for (i = 0; i < 2; i++) { + p2 = ao + 12 + i; /* wm1 for y */ + *p2 = (regp2->paddr + regp2->info.y_off); + + p2 = ao + 36 + i; /* wm5 for cbcr */ + *p2 = (regp2->paddr + regp2->info.cbcr_off); + regp2++; + } + for (i = 2; i < ad->bufnum1; i++) { + ret = vfe31_add_free_buf(outp1, regp1); + if (ret < 0) + return ret; + regp1++; + } + + for (i = 2; i < ad->bufnum2; i++) { + ret = vfe31_add_free_buf(outp2, regp2); + if (ret < 0) + return ret; + regp2++; + } + } + break; + case CAMIF_TO_AXI_VIA_OUTPUT_2: { /* use wm0 only */ + if (ad->bufnum2 < 1) + return -EINVAL; + CDBG("config axi for raw snapshot.\n"); + vfe31_ctrl->outpath.out1.ch0 = 0; /* raw */ + regp1 = &(ad->region[ad->bufnum1]); + vfe31_ctrl->outpath.output_mode |= VFE31_OUTPUT_MODE_S; + p1 = ao + 6; /* wm0 for y */ + *p1 = (regp1->paddr + regp1->info.y_off); + if (p_sync->stereocam_enabled) + p_sync->stereo_state = STEREO_RAW_SNAP_IDLE; + } + break; + default: + break; + } + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[V31_AXI_OUT_CFG].offset, + ao, vfe31_cmd[V31_AXI_OUT_CFG].length - V31_AXI_CH_INF_LEN); + + return 0; +} + +static void vfe31_reset_internal_variables(void) +{ + unsigned long flags; + vfe31_ctrl->vfeImaskCompositePacked = 0; + /* state control variables */ + vfe31_ctrl->start_ack_pending = FALSE; + atomic_set(&irq_cnt, 0); + + spin_lock_irqsave(&vfe31_ctrl->xbar_lock, flags); + vfe31_ctrl->xbar_update_pending = 0; + spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags); + + atomic_set(&vfe31_ctrl->stop_ack_pending, 0); + atomic_set(&vfe31_ctrl->vstate, 0); + + vfe31_ctrl->aec_ack_pending = FALSE; + vfe31_ctrl->af_ack_pending = FALSE; + vfe31_ctrl->awb_ack_pending = FALSE; + vfe31_ctrl->ihist_ack_pending = FALSE; + vfe31_ctrl->rs_ack_pending = FALSE; + vfe31_ctrl->cs_ack_pending = FALSE; + + vfe31_ctrl->reset_ack_pending = FALSE; + + spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags); + vfe31_ctrl->update_ack_pending = FALSE; + spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags); + + vfe31_ctrl->recording_state = VFE_REC_STATE_IDLE; + + /* 0 for continuous mode, 1 for snapshot mode */ + vfe31_ctrl->operation_mode = VFE_MODE_OF_OPERATION_CONTINUOUS; + vfe31_ctrl->outpath.output_mode = 0; + vfe31_ctrl->vfe_capture_count = 0; + + /* this is unsigned 32 bit integer. */ + vfe31_ctrl->vfeFrameId = 0; + + vfe31_ctrl->output1Pattern = 0xffffffff; + vfe31_ctrl->output1Period = 31; + vfe31_ctrl->output2Pattern = 0xffffffff; + vfe31_ctrl->output2Period = 31; + vfe31_ctrl->vfeFrameSkipCount = 0; + vfe31_ctrl->vfeFrameSkipPeriod = 31; + + /* Stats control variables. */ + memset(&(vfe31_ctrl->afStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe31_ctrl->awbStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe31_ctrl->aecStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe31_ctrl->ihistStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe31_ctrl->rsStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe31_ctrl->csStatsControl), 0, + sizeof(struct vfe_stats_control)); +} + +static void vfe31_reset(void) +{ + uint32_t vfe_version; + vfe31_reset_free_buf_queue_all(); + vfe31_reset_internal_variables(); + + vfe31_reset_hist_cfg(); + vfe_version = msm_io_r(vfe31_ctrl->vfebase); + CDBG("vfe_version = 0x%x\n", vfe_version); + /* disable all interrupts. vfeImaskLocal is also reset to 0 + * to begin with. */ + msm_io_w(VFE_DISABLE_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_0); + + msm_io_w(VFE_DISABLE_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* clear all pending interrupts*/ + msm_io_w(VFE_CLEAR_ALL_IRQS, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_io_w(VFE_CLEAR_ALL_IRQS, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_IRQ_CMD); + + /* enable reset_ack interrupt. */ + msm_io_w(VFE_IMASK_RESET, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset + * is done, hardware interrupt will be generated. VFE ist processes + * the interrupt to complete the function call. Note that the reset + * function is synchronous. */ + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(VFE_RESET_UPON_RESET_CMD, + vfe31_ctrl->vfebase + VFE_GLOBAL_RESET); +} + +static int vfe31_operation_config(uint32_t *cmd) +{ + uint32_t *p = cmd; + + vfe31_ctrl->operation_mode = *p; + vpe_ctrl->pad_2k_bool = (vfe31_ctrl->operation_mode & 1) ? + FALSE : TRUE; + + vfe31_ctrl->stats_comp = *(++p); + vfe31_ctrl->hfr_mode = *(++p); + + msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_CFG_OFF); + msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_REALIGN_BUF); + msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_CHROMA_UP); + msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_STATS_CFG); + wmb(); + return 0; +} +static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); + vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + + +static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR); + + vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); + + vfe31_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR); + + vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR); + + vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} +static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR); + + vfe31_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +static void vfe31_start_common(void) +{ + uint32_t irq_mask = 0x00E00021; + vfe31_ctrl->start_ack_pending = TRUE; + CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n", + vfe31_ctrl->operation_mode, vfe31_ctrl->outpath.output_mode); + /* Enable IRQ for comp stats, Image master, SOF & Reg Update*/ + if (vfe31_ctrl->stats_comp) + irq_mask |= 0x01000000; + else /* Enable IRQ for Image masters, AF stats, SOF & Reg Update */ + irq_mask |= 0x00004000; + + /* Enable EOF for video mode */ + if (VFE_MODE_OF_OPERATION_VIDEO == vfe31_ctrl->operation_mode) + irq_mask |= 0x4; + + msm_io_w(irq_mask, vfe31_ctrl->vfebase + VFE_IRQ_MASK_0); + + msm_io_w(VFE_IMASK_RESET, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_1); + /* enable out of order option */ + msm_io_w(0x80000000, vfe31_ctrl->vfebase + VFE_AXI_CFG); + /* enable performance monitor */ + msm_io_w(1, vfe31_ctrl->vfebase + VFE_BUS_PM_CFG); + msm_io_w(1, vfe31_ctrl->vfebase + VFE_BUS_PM_CMD); + + + msm_io_dump(vfe31_ctrl->vfebase, 0x600); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD); + msm_io_w(1, vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND); + wmb(); + + atomic_set(&vfe31_ctrl->vstate, 1); +} + +static int vfe31_start_recording(void) +{ + msm_camio_set_perf_lvl(S_VIDEO); + usleep(1000); + vfe31_ctrl->recording_state = VFE_REC_STATE_START_REQUESTED; + msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD); + return 0; +} + +static int vfe31_stop_recording(void) +{ + vfe31_ctrl->recording_state = VFE_REC_STATE_STOP_REQUESTED; + msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD); + msm_camio_set_perf_lvl(S_PREVIEW); + return 0; +} + +static void vfe31_liveshot(void) +{ + struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata; + if (p_sync) + p_sync->liveshot_enabled = true; +} + +static void vfe31_stereocam(uint32_t enable) +{ + struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata; + if (p_sync) { + CDBG("%s: Enable StereoCam %d!!!\n", __func__, enable); + p_sync->stereocam_enabled = enable; + } +} + +static int vfe31_zsl(void) +{ + uint32_t irq_comp_mask = 0; + /* capture command is valid for both idle and active state. */ + irq_comp_mask = + msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + CDBG("%s:op mode %d O/P Mode %d\n", __func__, + vfe31_ctrl->operation_mode, vfe31_ctrl->outpath.output_mode); + if ((vfe31_ctrl->operation_mode == VFE_MODE_OF_OPERATION_ZSL)) { + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_P) { + irq_comp_mask |= + ((0x1 << (vfe31_ctrl->outpath.out0.ch0)) | + (0x1 << (vfe31_ctrl->outpath.out0.ch1))); + } + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_T) { + irq_comp_mask |= + ((0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8)) | + (0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8))); + } + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) { + irq_comp_mask |= + ((0x1 << (vfe31_ctrl->outpath.out2.ch0 + 8)) | + (0x1 << (vfe31_ctrl->outpath.out2.ch1 + 8))); + } + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_P) { + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]); + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]); + } + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_T) { + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]); + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]); + } + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) { + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch0]); + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch1]); + } + } + msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK); + vfe31_start_common(); + msm_camio_set_perf_lvl(S_ZSL); + usleep(1000); + /* for debug */ + msm_io_w(1, vfe31_ctrl->vfebase + 0x18C); + msm_io_w(1, vfe31_ctrl->vfebase + 0x188); + return 0; +} + +static int vfe31_capture(uint32_t num_frames_capture) +{ + uint32_t irq_comp_mask = 0; + struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata; + + /* capture command is valid for both idle and active state. */ + vfe31_ctrl->vfe_capture_count = num_frames_capture; + if (p_sync) { + p_sync->snap_count = num_frames_capture; + p_sync->thumb_count = num_frames_capture; + } + + irq_comp_mask = + msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + if ((vfe31_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_SNAPSHOT) || + (vfe31_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_ZSL)){ + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) { + irq_comp_mask |= + ((0x1 << (vfe31_ctrl->outpath.out0.ch0 + 8)) | + (0x1 << (vfe31_ctrl->outpath.out0.ch1 + 8))); + } + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) { + irq_comp_mask |= + ((0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8)) | + (0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8))); + } + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) { + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]); + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]); + } + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) { + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]); + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]); + } + } else { /* this is raw snapshot mode. */ + CDBG("config the comp imask for raw snapshot mode.\n"); + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) { + irq_comp_mask |= + (0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8)); + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]); + } + } + msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK); + if (p_sync->stereocam_enabled) + msm_camio_set_perf_lvl(S_STEREO_CAPTURE); + else + msm_camio_set_perf_lvl(S_CAPTURE); + + usleep(1000); + vfe31_start_common(); + return 0; +} + +static int vfe31_start(void) +{ + uint32_t irq_comp_mask = 0; + struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata; + /* start command now is only good for continuous mode. */ + if ((vfe31_ctrl->operation_mode != VFE_MODE_OF_OPERATION_CONTINUOUS) && + (vfe31_ctrl->operation_mode != VFE_MODE_OF_OPERATION_VIDEO)) + return 0; + irq_comp_mask = + msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) { + irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 | + 0x1 << vfe31_ctrl->outpath.out0.ch1); + } + + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) { + irq_comp_mask |= (0x1 << (vfe31_ctrl->outpath.out2.ch0 + 16)| + 0x1 << (vfe31_ctrl->outpath.out2.ch1 + 16)); + } + + msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) { + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]); + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]); + } + if (p_sync->stereocam_enabled) + msm_camio_set_perf_lvl(S_STEREO_VIDEO); + else + msm_camio_set_perf_lvl(S_PREVIEW); + + usleep(1000); + vfe31_start_common(); + return 0; +} + +static void vfe31_update(void) +{ + unsigned long flags; + CDBG("vfe31_update\n"); + + if (vfe31_ctrl->update_gamma) { + if (!msm_io_r(vfe31_ctrl->vfebase + V31_GAMMA_CFG_OFF)) + msm_io_w(7, vfe31_ctrl->vfebase+V31_GAMMA_CFG_OFF); + else + msm_io_w(0, vfe31_ctrl->vfebase+V31_GAMMA_CFG_OFF); + vfe31_ctrl->update_gamma = false; + } + if (vfe31_ctrl->update_luma) { + if (!msm_io_r(vfe31_ctrl->vfebase + V31_LUMA_CFG_OFF)) + msm_io_w(1, vfe31_ctrl->vfebase + V31_LUMA_CFG_OFF); + else + msm_io_w(0, vfe31_ctrl->vfebase + V31_LUMA_CFG_OFF); + vfe31_ctrl->update_luma = false; + } + spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags); + vfe31_ctrl->update_ack_pending = TRUE; + spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags); + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD); + return; +} + +static void vfe31_sync_timer_stop(void) +{ + uint32_t value = 0; + vfe31_ctrl->sync_timer_state = 0; + if (vfe31_ctrl->sync_timer_number == 0) + value = 0x10000; + else if (vfe31_ctrl->sync_timer_number == 1) + value = 0x20000; + else if (vfe31_ctrl->sync_timer_number == 2) + value = 0x40000; + + /* Timer Stop */ + msm_io_w_mb(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF); +} + +static void vfe31_sync_timer_start(const uint32_t *tbl) +{ + /* set bit 8 for auto increment. */ + uint32_t value = 1; + uint32_t val; + + vfe31_ctrl->sync_timer_state = *tbl++; + vfe31_ctrl->sync_timer_repeat_count = *tbl++; + vfe31_ctrl->sync_timer_number = *tbl++; + CDBG("%s timer_state %d, repeat_cnt %d timer number %d\n", + __func__, vfe31_ctrl->sync_timer_state, + vfe31_ctrl->sync_timer_repeat_count, + vfe31_ctrl->sync_timer_number); + + if (vfe31_ctrl->sync_timer_state) { /* Start Timer */ + value = value << vfe31_ctrl->sync_timer_number; + } else { /* Stop Timer */ + CDBG("Failed to Start timer\n"); + return; + } + + /* Timer Start */ + msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF); + /* Sync Timer Line Start */ + value = *tbl++; + msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF + + 4 + ((vfe31_ctrl->sync_timer_number) * 12)); + /* Sync Timer Pixel Start */ + value = *tbl++; + msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF + + 8 + ((vfe31_ctrl->sync_timer_number) * 12)); + /* Sync Timer Pixel Duration */ + value = *tbl++; + val = camio_clk.vfe_clk_rate / 10000; + val = 10000000 / val; + val = value * 10000 / val; + CDBG("%s: Pixel Clk Cycles!!! %d \n", __func__, val); + msm_io_w(val, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF + + 12 + ((vfe31_ctrl->sync_timer_number) * 12)); + /* Timer0 Active High/LOW */ + value = *tbl++; + msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_POLARITY_OFF); + /* Selects sync timer 0 output to drive onto timer1 port */ + value = 0; + msm_io_w(value, vfe31_ctrl->vfebase + V31_TIMER_SELECT_OFF); + wmb(); +} + +static void vfe31_program_dmi_cfg(enum VFE31_DMI_RAM_SEL bankSel) +{ + /* set bit 8 for auto increment. */ + uint32_t value = VFE_DMI_CFG_DEFAULT; + value += (uint32_t)bankSel; + + msm_io_w_mb(value, vfe31_ctrl->vfebase + VFE_DMI_CFG); + /* by default, always starts with offset 0.*/ + msm_io_w(0, vfe31_ctrl->vfebase + VFE_DMI_ADDR); + wmb(); +} +static void vfe31_write_gamma_cfg(enum VFE31_DMI_RAM_SEL channel_sel, + const uint32_t *tbl) +{ + int i; + uint32_t value, value1, value2; + vfe31_program_dmi_cfg(channel_sel); + /* for loop for extracting init table. */ + for (i = 0 ; i < (VFE31_GAMMA_NUM_ENTRIES/2) ; i++) { + value = *tbl++; + value1 = value & 0x0000FFFF; + value2 = (value & 0xFFFF0000)>>16; + msm_io_w((value1), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO); + msm_io_w((value2), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO); + } + vfe31_program_dmi_cfg(NO_MEM_SELECTED); +} + +static void vfe31_reset_hist_cfg() +{ + uint32_t i; + uint32_t value = 0; + + vfe31_program_dmi_cfg(STATS_HIST_RAM); + for (i = 0 ; i < VFE31_HIST_TABLE_LENGTH ; i++) + msm_io_w(value, vfe31_ctrl->vfebase + VFE_DMI_DATA_LO); + vfe31_program_dmi_cfg(NO_MEM_SELECTED); +} + +static void vfe31_write_la_cfg(enum VFE31_DMI_RAM_SEL channel_sel, + const uint32_t *tbl) +{ + uint32_t i; + uint32_t value, value1, value2; + + vfe31_program_dmi_cfg(channel_sel); + /* for loop for extracting init table. */ + for (i = 0 ; i < (VFE31_LA_TABLE_LENGTH/2) ; i++) { + value = *tbl++; + value1 = value & 0x0000FFFF; + value2 = (value & 0xFFFF0000)>>16; + msm_io_w((value1), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO); + msm_io_w((value2), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO); + } + vfe31_program_dmi_cfg(NO_MEM_SELECTED); +} + +static int vfe31_proc_general(struct msm_vfe31_cmd *cmd) +{ + int i , rc = 0; + uint32_t old_val = 0 , new_val = 0; + uint32_t *cmdp = NULL; + uint32_t *cmdp_local = NULL; + uint32_t snapshot_cnt = 0; + uint32_t stereo_cam_enable = 0; + struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata; + + CDBG("vfe31_proc_general: cmdID = %s, length = %d\n", + vfe31_general_cmd[cmd->id], cmd->length); + switch (cmd->id) { + case V31_RESET: + pr_info("vfe31_proc_general: cmdID = %s\n", + vfe31_general_cmd[cmd->id]); + vfe31_reset(); + break; + case V31_START: + pr_info("vfe31_proc_general: cmdID = %s\n", + vfe31_general_cmd[cmd->id]); + rc = vfe31_start(); + break; + case V31_UPDATE: + vfe31_update(); + break; + case V31_ZSL: + pr_info("vfe31_proc_general: cmdID = %s\n", + vfe31_general_cmd[cmd->id]); + vfe31_zsl(); + break; + case V31_CAPTURE: + pr_info("vfe31_proc_general: cmdID = %s\n", + vfe31_general_cmd[cmd->id]); + if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value), + sizeof(uint32_t))) { + rc = -EFAULT; + goto proc_general_done; + } + rc = vfe31_capture(snapshot_cnt); + break; + case V31_START_RECORDING: + pr_info("vfe31_proc_general: cmdID = %s\n", + vfe31_general_cmd[cmd->id]); + rc = vfe31_start_recording(); + if (p_sync->stereocam_enabled) + p_sync->stereo_state = STEREO_VIDEO_ACTIVE; + break; + case V31_STOP_RECORDING: + pr_info("vfe31_proc_general: cmdID = %s\n", + vfe31_general_cmd[cmd->id]); + rc = vfe31_stop_recording(); + if (p_sync->stereocam_enabled) + p_sync->stereo_state = STEREO_VIDEO_IDLE; + break; + case V31_OPERATION_CFG: { + if (cmd->length != V31_OPERATION_CFG_LEN) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kmalloc(V31_OPERATION_CFG_LEN, GFP_ATOMIC); + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + V31_OPERATION_CFG_LEN)) { + rc = -EFAULT; + goto proc_general_done; + } + rc = vfe31_operation_config(cmdp); + } + break; + + case V31_STATS_AE_START: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= AE_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp, (vfe31_cmd[cmd->id].length)); + } + break; + case V31_STATS_AF_START: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= AF_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp, (vfe31_cmd[cmd->id].length)); + } + break; + case V31_STATS_AWB_START: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= AWB_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp, (vfe31_cmd[cmd->id].length)); + } + break; + + case V31_STATS_IHIST_START: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= IHIST_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp, (vfe31_cmd[cmd->id].length)); + } + break; + + case V31_XBAR_CFG: { + unsigned long flags = 0; + spin_lock_irqsave(&vfe31_ctrl->xbar_lock, flags); + if ((cmd->length != V31_XBAR_CFG_LEN) + || vfe31_ctrl->xbar_update_pending) { + rc = -EINVAL; + spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags); + goto proc_general_done; + } + spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags); + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + spin_lock_irqsave(&vfe31_ctrl->xbar_lock, flags); + vfe31_ctrl->xbar_cfg[0] = *cmdp; + vfe31_ctrl->xbar_cfg[1] = *(cmdp+1); + vfe31_ctrl->xbar_update_pending = 1; + spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags); + CDBG("%s: xbar0 0x%x xbar1 0x%x", __func__, + vfe31_ctrl->xbar_cfg[0], + vfe31_ctrl->xbar_cfg[1]); + } + break; + + case V31_STATS_RS_START: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + /* + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= RS_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + */ + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp, (vfe31_cmd[cmd->id].length)); + } + break; + + case V31_STATS_CS_START: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + /* + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= CS_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + */ + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp, (vfe31_cmd[cmd->id].length)); + } + break; + + case V31_MCE_UPDATE: + case V31_MCE_CFG:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + /* Incrementing with 4 so as to point to the 2nd Register as + the 2nd register has the mce_enable bit */ + old_val = msm_io_r(vfe31_ctrl->vfebase + + V31_CHROMA_SUP_OFF + 4); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + old_val &= MCE_EN_MASK; + new_val = new_val | old_val; + msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 4, + &new_val, 4); + cmdp_local += 1; + + old_val = msm_io_r(vfe31_ctrl->vfebase + + V31_CHROMA_SUP_OFF + 8); + new_val = *cmdp_local; + old_val &= MCE_Q_K_MASK; + new_val = new_val | old_val; + msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 8, + &new_val, 4); + cmdp_local += 1; + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp_local, (vfe31_cmd[cmd->id].length)); + } + break; + case V31_DEMOSAIC_2_UPDATE: /* 38 BPC update */ + case V31_DEMOSAIC_2_CFG: { /* 14 BPC config */ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF); + old_val &= BPC_MASK; + + new_val = new_val | old_val; + *cmdp_local = new_val; + msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF, + cmdp_local, 4); + cmdp_local += 1; + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp_local, (vfe31_cmd[cmd->id].length)); + } + break; + case V31_DEMOSAIC_1_UPDATE:/* 37 ABF update */ + case V31_DEMOSAIC_1_CFG: { /* 13 ABF config */ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF); + old_val &= ABF_MASK; + new_val = new_val | old_val; + *cmdp_local = new_val; + + msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF, + cmdp_local, 4); + + cmdp_local += 1; + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp_local, (vfe31_cmd[cmd->id].length)); + } + break; + case V31_ROLL_OFF_CFG: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value) , cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp_local, 16); + cmdp_local += 4; + vfe31_program_dmi_cfg(ROLLOFF_RAM); + /* for loop for extrcting init table. */ + for (i = 0 ; i < (VFE31_ROLL_OFF_INIT_TABLE_SIZE * 2) ; i++) { + msm_io_w(*cmdp_local , + vfe31_ctrl->vfebase + VFE_DMI_DATA_LO); + cmdp_local++; + } + CDBG("done writing init table \n"); + /* by default, always starts with offset 0. */ + msm_io_w(LENS_ROLL_OFF_DELTA_TABLE_OFFSET, + vfe31_ctrl->vfebase + VFE_DMI_ADDR); + /* for loop for extracting delta table. */ + for (i = 0 ; i < (VFE31_ROLL_OFF_DELTA_TABLE_SIZE * 2) ; i++) { + msm_io_w(*cmdp_local, + vfe31_ctrl->vfebase + VFE_DMI_DATA_LO); + cmdp_local++; + } + vfe31_program_dmi_cfg(NO_MEM_SELECTED); + } + break; + + case V31_LA_CFG:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + + rc = -EFAULT; + goto proc_general_done; + } + /* Select Bank 0*/ + *cmdp = 0; + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp, (vfe31_cmd[cmd->id].length)); + cmdp += 1; + vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0 , cmdp); + cmdp -= 1; + } + break; + + case V31_LA_UPDATE: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_io_r(vfe31_ctrl->vfebase + V31_LUMA_CFG_OFF); + cmdp += 1; + if (old_val != 0x0) + vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0 , cmdp); + else + vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1 , cmdp); + vfe31_ctrl->update_luma = true; + cmdp -= 1; + } + break; + + case V31_SK_ENHAN_CFG: + case V31_SK_ENHAN_UPDATE:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_io_memcpy(vfe31_ctrl->vfebase + V31_SCE_OFF, + cmdp, V31_SCE_LEN); + } + break; + + case V31_LIVESHOT: + vfe31_liveshot(); + break; + + case V31_STEREOCAM: + if (copy_from_user(&stereo_cam_enable, + (void __user *)(cmd->value), sizeof(uint32_t))) { + rc = -EFAULT; + goto proc_general_done; + } + vfe31_stereocam(stereo_cam_enable); + break; + + case V31_RGB_G_CFG: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + /* Select Bank 0*/ + *cmdp = 0; + msm_io_memcpy(vfe31_ctrl->vfebase + V31_RGB_G_OFF, + cmdp, 4); + cmdp += 1; + vfe31_write_gamma_cfg(RGBLUT_CHX_BANK0, cmdp); + cmdp -= 1; + } + break; + + case V31_RGB_G_UPDATE: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_io_r(vfe31_ctrl->vfebase + V31_GAMMA_CFG_OFF); + cmdp += 1; + + if (!old_val) { + vfe31_write_gamma_cfg(RGBLUT_CHX_BANK1, cmdp); + } else { + vfe31_write_gamma_cfg(RGBLUT_CHX_BANK0, cmdp); + } + vfe31_ctrl->update_gamma = true; + cmdp -= 1; + } + break; + + case V31_STATS_AWB_STOP: { + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~AWB_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + case V31_STATS_AE_STOP: { + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~AE_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + case V31_STATS_AF_STOP: { + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~AF_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + + case V31_STATS_IHIST_STOP: { + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~IHIST_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + + case V31_STATS_RS_STOP: { + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~RS_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + + case V31_STATS_CS_STOP: { + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~CS_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + case V31_STOP: + pr_info("vfe31_proc_general: cmdID = %s\n", + vfe31_general_cmd[cmd->id]); + vfe31_stop(); + break; + + case V31_SYNC_TIMER_SETTING: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + vfe31_sync_timer_start(cmdp); + break; + + case V31_EZTUNE_CFG: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + *cmdp &= ~STATS_ENABLE_MASK; + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= STATS_ENABLE_MASK; + *cmdp |= old_val; + + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp, (vfe31_cmd[cmd->id].length)); + } + break; + + default: { + if (cmd->length != vfe31_cmd[cmd->id].length) + return -EINVAL; + + cmdp = kmalloc(vfe31_cmd[cmd->id].length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + + CHECKED_COPY_FROM_USER(cmdp); + msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset, + cmdp, (vfe31_cmd[cmd->id].length)); + } + break; + + } + +proc_general_done: + kfree(cmdp); + + return rc; +} + +static void vfe31_stats_af_ack(struct vfe_cmd_stats_ack *pAck) +{ + vfe31_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe31_ctrl->af_ack_pending = FALSE; +} + +static void vfe31_stats_awb_ack(struct vfe_cmd_stats_ack *pAck) +{ + vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe31_ctrl->awb_ack_pending = FALSE; +} + +static void vfe31_stats_aec_ack(struct vfe_cmd_stats_ack *pAck) +{ + vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe31_ctrl->aec_ack_pending = FALSE; +} + +static void vfe31_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck) +{ + vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe31_ctrl->ihist_ack_pending = FALSE; +} + +static void vfe31_stats_rs_ack(struct vfe_cmd_stats_ack *pAck) +{ + vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe31_ctrl->rs_ack_pending = FALSE; +} + +static void vfe31_stats_cs_ack(struct vfe_cmd_stats_ack *pAck) +{ + vfe31_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe31_ctrl->cs_ack_pending = FALSE; +} + +static int vfe31_config(struct msm_vfe_cfg_cmd *cmd, void *data) +{ + struct msm_vfe31_cmd vfecmd; + + long rc = 0; + uint32_t i = 0; + struct vfe_cmd_stats_buf *scfg = NULL; + struct msm_pmem_region *regptr = NULL; + struct vfe_cmd_stats_ack *sack = NULL; + + if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE && + cmd->cmd_type != CMD_SNAP_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) { + if (copy_from_user(&vfecmd, + (void __user *)(cmd->value), + sizeof(vfecmd))) { + pr_err("%s %d: copy_from_user failed\n", __func__, + __LINE__); + return -EFAULT; + } + } else { + /* here eith stats release or frame release. */ + if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE && + cmd->cmd_type != CMD_SNAP_BUF_RELEASE) { + /* then must be stats release. */ + if (!data) + return -EFAULT; + sack = kmalloc(sizeof(struct vfe_cmd_stats_ack), + GFP_ATOMIC); + if (!sack) + return -ENOMEM; + + sack->nextStatsBuf = *(uint32_t *)data; + } + } + + CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type); + + if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) || + (cmd->cmd_type == CMD_STATS_AWB_ENABLE) || + (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) || + (cmd->cmd_type == CMD_STATS_RS_ENABLE) || + (cmd->cmd_type == CMD_STATS_CS_ENABLE) || + (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) { + struct axidata *axid; + axid = data; + if (!axid) { + rc = -EFAULT; + goto vfe31_config_done; + } + + scfg = + kmalloc(sizeof(struct vfe_cmd_stats_buf), + GFP_ATOMIC); + if (!scfg) { + rc = -ENOMEM; + goto vfe31_config_done; + } + regptr = axid->region; + if (axid->bufnum1 > 0) { + for (i = 0; i < axid->bufnum1; i++) { + scfg->statsBuf[i] = + (uint32_t)(regptr->paddr); + regptr++; + } + } + /* individual */ + switch (cmd->cmd_type) { + case CMD_STATS_AEC_ENABLE: + rc = vfe_stats_aec_buf_init(scfg); + break; + case CMD_STATS_AF_ENABLE: + rc = vfe_stats_af_buf_init(scfg); + break; + case CMD_STATS_AWB_ENABLE: + rc = vfe_stats_awb_buf_init(scfg); + break; + case CMD_STATS_IHIST_ENABLE: + rc = vfe_stats_ihist_buf_init(scfg); + break; + case CMD_STATS_RS_ENABLE: + rc = vfe_stats_rs_buf_init(scfg); + break; + case CMD_STATS_CS_ENABLE: + rc = vfe_stats_cs_buf_init(scfg); + break; + } + } + + switch (cmd->cmd_type) { + case CMD_GENERAL: + rc = vfe31_proc_general(&vfecmd); + break; + + case CMD_FRAME_BUF_RELEASE: { + struct msm_frame *b; + unsigned long p; + int ret; + struct vfe31_output_ch *outch = NULL; + if (!data) { + rc = -EFAULT; + break; + } + + b = (struct msm_frame *)(cmd->value); + p = *(unsigned long *)data; + + CDBG("CMD_FRAME_BUF_RELEASE b->path = %d\n", b->path); + + if (b->path & OUTPUT_TYPE_P) { + CDBG("CMD_FRAME_BUF_RELEASE got free buffer\n"); + outch = &vfe31_ctrl->outpath.out0; + } else if (b->path & OUTPUT_TYPE_S) { + outch = &vfe31_ctrl->outpath.out1; + } else if (b->path & OUTPUT_TYPE_V) { + outch = &vfe31_ctrl->outpath.out2; + } else { + rc = -EFAULT; + break; + } + + ret = vfe31_add_free_buf2(outch, p, b->y_off, b->cbcr_off); + if (ret < 0) + return ret; + break; + } + + case CMD_SNAP_BUF_RELEASE: { + struct msm_frame *b; + unsigned long p; + int ret; + struct vfe31_output_ch *outch = NULL; + if (!data) + return -EFAULT; + + b = (struct msm_frame *)(cmd->value); + p = *(unsigned long *)data; + + CDBG("CMD_PIC_BUF_RELEASE b->path = %d\n", b->path); + + if (b->path & OUTPUT_TYPE_T) { + CDBG("CMD_FRAME_BUF_RELEASE got free buffer\n"); + outch = &vfe31_ctrl->outpath.out1; + } else if (b->path & OUTPUT_TYPE_S) { + outch = &vfe31_ctrl->outpath.out2; + } else + return -EFAULT; + + ret = vfe31_add_free_buf2(outch, p, b->y_off, b->cbcr_off); + if (ret < 0) + return ret; + break; + } + + case CMD_STATS_AEC_BUF_RELEASE: + vfe31_stats_aec_ack(sack); + break; + + case CMD_STATS_AF_BUF_RELEASE: + vfe31_stats_af_ack(sack); + break; + + case CMD_STATS_AWB_BUF_RELEASE: + vfe31_stats_awb_ack(sack); + break; + + case CMD_STATS_IHIST_BUF_RELEASE: + vfe31_stats_ihist_ack(sack); + break; + + case CMD_STATS_RS_BUF_RELEASE: + vfe31_stats_rs_ack(sack); + break; + + case CMD_STATS_CS_BUF_RELEASE: + vfe31_stats_cs_ack(sack); + break; + + case CMD_AXI_CFG_PREVIEW: { + struct axidata *axid; + uint32_t *axio = NULL; + axid = data; + if (!axid) { + rc = -EFAULT; + break; + } + axio = + kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe31_cmd[V31_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe31_config_axi(OUTPUT_2, axid, axio); + kfree(axio); + break; + } + + case CMD_RAW_PICT_AXI_CFG: { + struct axidata *axid; + uint32_t *axio = NULL; + axid = data; + if (!axid) { + rc = -EFAULT; + break; + } + axio = + kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe31_cmd[V31_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe31_config_axi(CAMIF_TO_AXI_VIA_OUTPUT_2, axid, axio); + kfree(axio); + break; + } + + case CMD_AXI_CFG_SNAP: { + struct axidata *axid; + uint32_t *axio = NULL; + CDBG("%s, CMD_AXI_CFG_SNAP\n", __func__); + axid = data; + if (!axid) + return -EFAULT; + axio = + kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe31_cmd[V31_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe31_config_axi(OUTPUT_1_AND_2, axid, axio); + kfree(axio); + break; + } + + case CMD_AXI_CFG_ZSL: { + struct axidata *axid; + uint32_t *axio = NULL; + CDBG("%s, CMD_AXI_CFG_ZSL\n", __func__); + axid = data; + if (!axid) + return -EFAULT; + axio = + kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe31_cmd[V31_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe31_config_axi(OUTPUT_1_2_AND_3, axid, axio); + kfree(axio); + } + break; + + case CMD_AXI_CFG_VIDEO: { + struct axidata *axid; + uint32_t *axio = NULL; + axid = data; + if (!axid) { + rc = -EFAULT; + break; + } + + axio = + kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe31_cmd[V31_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe31_config_axi(OUTPUT_1_AND_3, axid, axio); + kfree(axio); + break; + } + + default: + break; + } +vfe31_config_done: + kfree(scfg); + kfree(sack); + CDBG("%s done: rc = %d\n", __func__, (int) rc); + return rc; +} + +static void vfe31_send_msg_no_payload(enum VFE31_MESSAGE_ID id) +{ + struct vfe_message msg; + + CDBG("vfe31_send_msg_no_payload\n"); + msg._d = id; + vfe31_proc_ops(id, &msg, 0); +} + +static void vfe31_process_reg_update_irq(void) +{ + uint32_t temp, old_val; + unsigned long flags; + if (vfe31_ctrl->recording_state == VFE_REC_STATE_START_REQUESTED) { + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) { + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch0]); + msm_io_w(1, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch1]); + } + vfe31_ctrl->recording_state = VFE_REC_STATE_STARTED; + if (vpe_ctrl->dis_en) { + old_val = msm_io_r( + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= RS_CS_ENABLE_MASK; + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + } + msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD); + CDBG("start video triggered .\n"); + } else if (vfe31_ctrl->recording_state + == VFE_REC_STATE_STOP_REQUESTED) { + if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) { + msm_io_w(0, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch0]); + msm_io_w(0, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch1]); + } + + /*disable rs& cs when stop recording. */ + old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= (~RS_CS_ENABLE_MASK); + msm_io_w(old_val, + vfe31_ctrl->vfebase + VFE_MODULE_CFG); + CDBG("stop video triggered\n"); + } + if (vfe31_ctrl->start_ack_pending == TRUE) { + vfe31_send_msg_no_payload(MSG_ID_START_ACK); + vfe31_ctrl->start_ack_pending = FALSE; + } else { + if (vfe31_ctrl->recording_state == + VFE_REC_STATE_STOP_REQUESTED) { + vfe31_ctrl->recording_state = VFE_REC_STATE_STOPPED; + msm_io_w_mb(1, vfe31_ctrl->vfebase + + VFE_REG_UPDATE_CMD); + } else if (vfe31_ctrl->recording_state == + VFE_REC_STATE_STOPPED) { + CDBG("sent stop video rec ACK"); + vfe31_send_msg_no_payload(MSG_ID_STOP_REC_ACK); + vfe31_ctrl->recording_state = VFE_REC_STATE_IDLE; + } + spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags); + if (vfe31_ctrl->update_ack_pending == TRUE) { + vfe31_ctrl->update_ack_pending = FALSE; + spin_unlock_irqrestore( + &vfe31_ctrl->update_ack_lock, flags); + vfe31_send_msg_no_payload(MSG_ID_UPDATE_ACK); + } else { + spin_unlock_irqrestore( + &vfe31_ctrl->update_ack_lock, flags); + } + } + /* in snapshot mode */ + if (vfe31_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_SNAPSHOT) { + /* later we need to add check for live snapshot mode. */ + + if (vfe31_ctrl->vfe_capture_count) + vfe31_ctrl->vfe_capture_count--; + /* if last frame to be captured: */ + if (vfe31_ctrl->vfe_capture_count == 0) { + /* stop the bus output: write master enable = 0*/ + if (vfe31_ctrl->outpath.output_mode & + VFE31_OUTPUT_MODE_PT) { + msm_io_w(0, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[ + vfe31_ctrl->outpath.out0.ch0]); + msm_io_w(0, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl-> + outpath.out0.ch1]); + } + if (vfe31_ctrl->outpath.output_mode & + VFE31_OUTPUT_MODE_S) { + msm_io_w(0, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl-> + outpath.out1.ch0]); + msm_io_w(0, vfe31_ctrl->vfebase + + vfe31_AXI_WM_CFG[vfe31_ctrl-> + outpath.out1.ch1]); + } + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY, + vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND); + + /* Ensure the read order while reading + to the command register using the barrier */ + temp = msm_io_r_mb(vfe31_ctrl->vfebase + + VFE_CAMIF_COMMAND); + } + /* then do reg_update. */ + msm_io_w_mb(1, vfe31_ctrl->vfebase + + VFE_REG_UPDATE_CMD); + } /* if snapshot mode. */ +} + +static void vfe31_set_default_reg_values(void) +{ + msm_io_w(0x800080, vfe31_ctrl->vfebase + VFE_DEMUX_GAIN_0); + msm_io_w(0x800080, vfe31_ctrl->vfebase + VFE_DEMUX_GAIN_1); + msm_io_w(0xFFFFF, vfe31_ctrl->vfebase + VFE_CGC_OVERRIDE); + + /* default frame drop period and pattern */ + msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG); + msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG); + msm_io_w(0xFFFFFFFF, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN); + msm_io_w(0xFFFFFFFF, + vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN); + msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y); + msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR); + msm_io_w(0xFFFFFFFF, + vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN); + msm_io_w(0xFFFFFFFF, + vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN); + msm_io_w(0, vfe31_ctrl->vfebase + VFE_CLAMP_MIN); + msm_io_w(0xFFFFFF, vfe31_ctrl->vfebase + VFE_CLAMP_MAX); + + /* stats UB config */ + msm_io_w(0x3980007, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG); + msm_io_w(0x3A00007, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG); + msm_io_w(0x3A8000F, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG); + msm_io_w(0x3B80007, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG); + msm_io_w(0x3C0001F, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG); + msm_io_w(0x3E0001F, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG); +} + +static void vfe31_process_reset_irq(void) +{ + atomic_set(&vfe31_ctrl->vstate, 0); + vfe31_ctrl->while_stopping_mask = VFE_IMASK_WHILE_STOPPING_1; + if (atomic_read(&vfe31_ctrl->stop_ack_pending)) { + /* this is from the stop command. */ + atomic_set(&vfe31_ctrl->stop_ack_pending, 0); + vfe31_send_msg_no_payload(MSG_ID_STOP_ACK); + } else { + /* this is from reset command. */ + vfe31_set_default_reg_values(); + + /* reload all write masters. (frame & line)*/ + msm_io_w_mb(0x7FFF, vfe31_ctrl->vfebase + VFE_BUS_CMD); + vfe31_send_msg_no_payload(MSG_ID_RESET_ACK); + } +} + + +static void vfe31_process_axi_halt_irq(void) +{ + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(AXI_HALT_CLEAR, + vfe31_ctrl->vfebase + VFE_AXI_CMD); + vfe31_ctrl->while_stopping_mask = VFE_IMASK_RESET; + + /* disable all interrupts. */ + msm_io_w(VFE_DISABLE_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_io_w(VFE_DISABLE_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* clear all pending interrupts*/ + msm_io_w(VFE_CLEAR_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_io_w(VFE_CLEAR_ALL_IRQS, + vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1); + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, + vfe31_ctrl->vfebase + VFE_IRQ_CMD); + + /* now enable only halt_irq & reset_irq */ + msm_io_w(0xf0000000, /* this is for async timer. */ + vfe31_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_io_w(VFE_IMASK_RESET, + vfe31_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + CDBG("%s: about to reset vfe...\n", __func__); + msm_io_w_mb(VFE_RESET_UPON_STOP_CMD, + vfe31_ctrl->vfebase + VFE_GLOBAL_RESET); + +} + +static void vfe31_process_camif_sof_irq(void) +{ + uint32_t temp; + + /* in raw snapshot mode */ + if (vfe31_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) { + if (vfe31_ctrl->start_ack_pending) { + vfe31_send_msg_no_payload(MSG_ID_START_ACK); + vfe31_ctrl->start_ack_pending = FALSE; + } + if (vfe31_ctrl->vfe_capture_count) + vfe31_ctrl->vfe_capture_count--; + /* if last frame to be captured: */ + if (vfe31_ctrl->vfe_capture_count == 0) { + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY, + vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND); + temp = msm_io_r_mb(vfe31_ctrl->vfebase + + VFE_CAMIF_COMMAND); + } + } /* if raw snapshot mode. */ + + if ((vfe31_ctrl->hfr_mode != HFR_MODE_OFF) && + (vfe31_ctrl->operation_mode == VFE_MODE_OF_OPERATION_VIDEO) && + (vfe31_ctrl->vfeFrameId % vfe31_ctrl->hfr_mode != 0)) { + vfe31_ctrl->vfeFrameId++; + CDBG("Skip the SOF notification when HFR enabled\n"); + return; + } + vfe31_send_msg_no_payload(MSG_ID_SOF_ACK); + vfe31_ctrl->vfeFrameId++; + CDBG("camif_sof_irq, frameId = %d\n", vfe31_ctrl->vfeFrameId); + + if (vfe31_ctrl->sync_timer_state) { + if (vfe31_ctrl->sync_timer_repeat_count == 0) + vfe31_sync_timer_stop(); + else + vfe31_ctrl->sync_timer_repeat_count--; + } +} + +static void vfe31_process_error_irq(uint32_t errStatus) +{ + uint32_t camifStatus, read_val; + uint32_t *temp; + + if (errStatus & VFE31_IMASK_CAMIF_ERROR) { + pr_err("vfe31_irq: camif errors\n"); + temp = (uint32_t *)(vfe31_ctrl->vfebase + VFE_CAMIF_STATUS); + camifStatus = msm_io_r(temp); + pr_err("camifStatus = 0x%x\n", camifStatus); + vfe31_send_msg_no_payload(MSG_ID_CAMIF_ERROR); + } + + if (errStatus & VFE31_IMASK_STATS_CS_OVWR) + pr_err("vfe31_irq: stats cs overwrite\n"); + + if (errStatus & VFE31_IMASK_STATS_IHIST_OVWR) + pr_err("vfe31_irq: stats ihist overwrite\n"); + + if (errStatus & VFE31_IMASK_REALIGN_BUF_Y_OVFL) + pr_err("vfe31_irq: realign bug Y overflow\n"); + + if (errStatus & VFE31_IMASK_REALIGN_BUF_CB_OVFL) + pr_err("vfe31_irq: realign bug CB overflow\n"); + + if (errStatus & VFE31_IMASK_REALIGN_BUF_CR_OVFL) + pr_err("vfe31_irq: realign bug CR overflow\n"); + + if (errStatus & VFE31_IMASK_VIOLATION) + pr_err("vfe31_irq: violation interrupt\n"); + + if (errStatus & VFE31_IMASK_IMG_MAST_0_BUS_OVFL) + pr_err("vfe31_irq: image master 0 bus overflow\n"); + + if (errStatus & VFE31_IMASK_IMG_MAST_1_BUS_OVFL) + pr_err("vfe31_irq: image master 1 bus overflow\n"); + + if (errStatus & VFE31_IMASK_IMG_MAST_2_BUS_OVFL) + pr_err("vfe31_irq: image master 2 bus overflow\n"); + + if (errStatus & VFE31_IMASK_IMG_MAST_3_BUS_OVFL) + pr_err("vfe31_irq: image master 3 bus overflow\n"); + + if (errStatus & VFE31_IMASK_IMG_MAST_4_BUS_OVFL) + pr_err("vfe31_irq: image master 4 bus overflow\n"); + + if (errStatus & VFE31_IMASK_IMG_MAST_5_BUS_OVFL) + pr_err("vfe31_irq: image master 5 bus overflow\n"); + + if (errStatus & VFE31_IMASK_IMG_MAST_6_BUS_OVFL) + pr_err("vfe31_irq: image master 6 bus overflow\n"); + + if (errStatus & VFE31_IMASK_STATS_AE_BUS_OVFL) + pr_err("vfe31_irq: ae stats bus overflow\n"); + + if (errStatus & VFE31_IMASK_STATS_AF_BUS_OVFL) + pr_err("vfe31_irq: af stats bus overflow\n"); + + if (errStatus & VFE31_IMASK_STATS_AWB_BUS_OVFL) + pr_err("vfe31_irq: awb stats bus overflow\n"); + + if (errStatus & VFE31_IMASK_STATS_RS_BUS_OVFL) + pr_err("vfe31_irq: rs stats bus overflow\n"); + + if (errStatus & VFE31_IMASK_STATS_CS_BUS_OVFL) + pr_err("vfe31_irq: cs stats bus overflow\n"); + + if (errStatus & VFE31_IMASK_STATS_IHIST_BUS_OVFL) + pr_err("vfe31_irq: ihist stats bus overflow\n"); + + if (errStatus & VFE31_IMASK_STATS_SKIN_BUS_OVFL) + pr_err("vfe31_irq: skin stats bus overflow\n"); + + if (errStatus & VFE31_IMASK_AXI_ERROR) { + pr_err("vfe31_irq: axi error\n"); + /* read status too when overflow happens.*/ + read_val = msm_io_r(vfe31_ctrl->vfebase + + VFE_BUS_PING_PONG_STATUS); + pr_debug("VFE_BUS_PING_PONG_STATUS = 0x%x\n", read_val); + read_val = msm_io_r(vfe31_ctrl->vfebase + + VFE_BUS_OPERATION_STATUS); + pr_debug("VFE_BUS_OPERATION_STATUS = 0x%x\n", read_val); + read_val = msm_io_r(vfe31_ctrl->vfebase + + VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0); + pr_debug("VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0 = 0x%x\n", + read_val); + read_val = msm_io_r(vfe31_ctrl->vfebase + + VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1); + pr_debug("VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1 = 0x%x\n", + read_val); + read_val = msm_io_r(vfe31_ctrl->vfebase + + VFE_AXI_STATUS); + pr_debug("VFE_AXI_STATUS = 0x%x\n", read_val); + } +} + +#define VFE31_AXI_OFFSET 0x0050 +#define vfe31_get_ch_ping_addr(chn) \ + (msm_io_r(vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn))) +#define vfe31_get_ch_pong_addr(chn) \ + (msm_io_r(vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4)) +#define vfe31_get_ch_addr(ping_pong, chn) \ + (((ping_pong) & (1 << (chn))) == 0 ? \ + vfe31_get_ch_pong_addr(chn) : vfe31_get_ch_ping_addr(chn)) + +#define vfe31_put_ch_ping_addr(chn, addr) \ + (msm_io_w((addr), vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn))) +#define vfe31_put_ch_pong_addr(chn, addr) \ + (msm_io_w((addr), vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4)) +#define vfe31_put_ch_addr(ping_pong, chn, addr) \ + (((ping_pong) & (1 << (chn))) == 0 ? \ + vfe31_put_ch_pong_addr((chn), (addr)) : \ + vfe31_put_ch_ping_addr((chn), (addr))) + +static void vfe31_process_output_path_irq_0(uint32_t ping_pong) +{ + uint32_t pyaddr, pcbcraddr; +#ifdef CONFIG_MSM_CAMERA_V4L2 + uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong; +#endif + struct vfe31_free_buf *free_buf = NULL; + /* we render frames in the following conditions: + 1. Continuous mode and the free buffer is avaialable. + */ + free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out0); + + if (free_buf) { + /* Y channel */ + pyaddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out0.ch0); + /* Chroma channel */ + pcbcraddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out0.ch1); + + CDBG("output path 0, pyaddr = 0x%x, pcbcraddr = 0x%x\n", + pyaddr, pcbcraddr); + /* Y channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out0.ch0, + free_buf->paddr + free_buf->y_off); + /* Chroma channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out0.ch1, + free_buf->paddr + free_buf->cbcr_off); + + kfree(free_buf); + /* if continuous mode, for display. (preview) */ + vfe_send_outmsg(MSG_ID_OUTPUT_P, pyaddr, pcbcraddr); + } else { + vfe31_ctrl->outpath.out0.frame_drop_cnt++; + pr_warning("path_irq_0 - no free buffer!\n"); +#ifdef CONFIG_MSM_CAMERA_V4L2 + pr_info("Swapping ping and pong\n"); + + /*get addresses*/ + /* Y channel */ + pyaddr_ping = vfe31_get_ch_ping_addr( + vfe31_ctrl->outpath.out0.ch0); + /* Chroma channel */ + pcbcraddr_ping = vfe31_get_ch_ping_addr( + vfe31_ctrl->outpath.out0.ch1); + /* Y channel */ + pyaddr_pong = vfe31_get_ch_pong_addr( + vfe31_ctrl->outpath.out0.ch0); + /* Chroma channel */ + pcbcraddr_pong = vfe31_get_ch_pong_addr( + vfe31_ctrl->outpath.out0.ch1); + + CDBG("ping = 0x%p, pong = 0x%p\n", (void *)pyaddr_ping, + (void *)pyaddr_pong); + CDBG("ping_cbcr = 0x%p, pong_cbcr = 0x%p\n", + (void *)pcbcraddr_ping, (void *)pcbcraddr_pong); + + /*put addresses*/ + /* SWAP y channel*/ + vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out0.ch0, + pyaddr_pong); + vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out0.ch0, + pyaddr_ping); + /* SWAP chroma channel*/ + vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out0.ch1, + pcbcraddr_pong); + vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out0.ch1, + pcbcraddr_ping); + CDBG("after swap: ping = 0x%p, pong = 0x%p\n", + (void *)pyaddr_pong, (void *)pyaddr_ping); +#endif + } +} + +static void vfe31_process_snapshot_frame(uint32_t ping_pong) +{ + uint32_t pyaddr, pcbcraddr; + struct vfe31_free_buf *free_buf = NULL; + /* Y channel- Main Image */ + pyaddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch0); + /* Chroma channel - TN Image */ + pcbcraddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch1); + + free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out1); + CDBG("%s: snapshot main, pyaddr = 0x%x, pcbcraddr = 0x%x\n", + __func__, pyaddr, pcbcraddr); + if (free_buf) { + /* Y channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch0, + free_buf->paddr + free_buf->y_off); + /* Chroma channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch1, + free_buf->paddr + free_buf->cbcr_off); + kfree(free_buf); + } + vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr); + + /* Y channel- TN Image */ + pyaddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out0.ch0); + /* Chroma channel - TN Image */ + pcbcraddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out0.ch1); + + free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out0); + CDBG("%s: snapshot TN, pyaddr = 0x%x, pcbcraddr = 0x%x\n", + __func__, pyaddr, pcbcraddr); + if (free_buf) { + /* Y channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out0.ch0, + free_buf->paddr + free_buf->y_off); + /* Chroma channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out0.ch1, + free_buf->paddr + free_buf->cbcr_off); + kfree(free_buf); + } + + vfe_send_outmsg(MSG_ID_OUTPUT_T, pyaddr, pcbcraddr); + + /* in snapshot mode if done then send + snapshot done message */ + if (vfe31_ctrl->vfe_capture_count == 0) { + vfe31_send_msg_no_payload(MSG_ID_SNAPSHOT_DONE); + /* Ensure the write order while writing + to the cmd register using barrier */ + msm_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY, + vfe31_ctrl->vfebase + + VFE_CAMIF_COMMAND); + } +} + +static void vfe31_process_raw_snapshot_frame(uint32_t ping_pong) +{ + uint32_t pyaddr, pcbcraddr; + struct vfe31_free_buf *free_buf = NULL; + struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata; + + if (p_sync->stereocam_enabled) + p_sync->stereo_state = STEREO_RAW_SNAP_STARTED; + + /* Y channel- Main Image */ + pyaddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch0); + /* Chroma channel - Main Image */ + pcbcraddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch1); + + free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out1); + CDBG("%s: snapshot raw, pyaddr = 0x%x, pcbcraddr = 0x%x\n", + __func__, pyaddr, pcbcraddr); + if (free_buf) { + /* Y channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch0, + free_buf->paddr + free_buf->y_off); + /* Chroma channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch1, + free_buf->paddr + free_buf->cbcr_off); + kfree(free_buf); + } + vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr); + + /* in snapshot mode if done then send + snapshot done message */ + if (vfe31_ctrl->vfe_capture_count == 0) { + vfe31_send_msg_no_payload(MSG_ID_SNAPSHOT_DONE); + /* Ensure the write order while writing + to the cmd register using barrier */ + msm_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY, + vfe31_ctrl->vfebase + + VFE_CAMIF_COMMAND); + } +} +static void vfe31_process_zsl_frame(uint32_t ping_pong) +{ + uint32_t pyaddr, pcbcraddr; + struct vfe31_free_buf *free_buf = NULL; + /* Y channel- Main Image */ + pyaddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out2.ch0); + /* Chroma channel - Main Image */ + pcbcraddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out2.ch1); + + free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out2); + CDBG("%s: snapshot main, pyaddr = 0x%x, pcbcraddr = 0x%x\n", + __func__, pyaddr, pcbcraddr); + if (free_buf) { + /* Y channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out2.ch0, + free_buf->paddr + free_buf->y_off); + /* Chroma channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out2.ch1, + free_buf->paddr + free_buf->cbcr_off); + kfree(free_buf); + } + vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr); + + /* Y channel- TN Image */ + pyaddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch0); + /* Chroma channel - TN Image */ + pcbcraddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch1); + + free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out1); + CDBG("%s: snapshot TN, pyaddr = 0x%x, pcbcraddr = 0x%x\n", + __func__, pyaddr, pcbcraddr); + if (free_buf) { + /* Y channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch0, + free_buf->paddr + free_buf->y_off); + /* Chroma channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out1.ch1, + free_buf->paddr + free_buf->cbcr_off); + kfree(free_buf); + } + + vfe_send_outmsg(MSG_ID_OUTPUT_T, pyaddr, pcbcraddr); +} + +static void vfe31_process_output_path_irq_1(uint32_t ping_pong) +{ + +#ifdef CONFIG_MSM_CAMERA_V4L2 + uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong; +#endif + CDBG("%s, operation_mode = %d, cap_cnt = %d\n", __func__, + vfe31_ctrl->operation_mode, vfe31_ctrl->vfe_capture_count); + + /* In Snapshot mode */ + if ((VFE_MODE_OF_OPERATION_SNAPSHOT == vfe31_ctrl->operation_mode) + && ((vfe31_ctrl->vfe_capture_count <= 1) + || (vfe31_free_buf_available(vfe31_ctrl->outpath.out0) && + vfe31_free_buf_available(vfe31_ctrl->outpath.out1)))) { + vfe31_process_snapshot_frame(ping_pong); + } else if ((VFE_MODE_OF_OPERATION_RAW_SNAPSHOT == + vfe31_ctrl->operation_mode) && + ((vfe31_ctrl->vfe_capture_count <= 1) || + vfe31_free_buf_available(vfe31_ctrl->outpath.out1))) { + vfe31_process_raw_snapshot_frame(ping_pong); + } else if ((VFE_MODE_OF_OPERATION_ZSL == vfe31_ctrl->operation_mode) + && (vfe31_free_buf_available(vfe31_ctrl->outpath.out1) + && vfe31_free_buf_available(vfe31_ctrl->outpath.out2))) { + vfe31_process_zsl_frame(ping_pong); + } else { + vfe31_ctrl->outpath.out1.frame_drop_cnt++; + pr_info("path_irq_1 - no free buffer!\n"); +#ifdef CONFIG_MSM_CAMERA_V4L2 + pr_info("Swapping ping and pong\n"); + + /*get addresses*/ + /* Y channel */ + pyaddr_ping = vfe31_get_ch_ping_addr( + vfe31_ctrl->outpath.out1.ch0); + /* Chroma channel */ + pcbcraddr_ping = vfe31_get_ch_ping_addr( + vfe31_ctrl->outpath.out1.ch1); + /* Y channel */ + pyaddr_pong = vfe31_get_ch_pong_addr( + vfe31_ctrl->outpath.out1.ch0); + /* Chroma channel */ + pcbcraddr_pong = vfe31_get_ch_pong_addr( + vfe31_ctrl->outpath.out1.ch1); + + CDBG("ping = 0x%p, pong = 0x%p\n", (void *)pyaddr_ping, + (void *)pyaddr_pong); + CDBG("ping_cbcr = 0x%p, pong_cbcr = 0x%p\n", + (void *)pcbcraddr_ping, (void *)pcbcraddr_pong); + + /*put addresses*/ + /* SWAP y channel*/ + vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out1.ch0, + pyaddr_pong); + vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out1.ch0, + pyaddr_ping); + /* SWAP chroma channel*/ + vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out1.ch1, + pcbcraddr_pong); + vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out1.ch1, + pcbcraddr_ping); + CDBG("after swap: ping = 0x%p, pong = 0x%p\n", + (void *)pyaddr_pong, (void *)pyaddr_ping); +#endif + } + +} + +static void vfe31_process_output_path_irq_2(uint32_t ping_pong) +{ + uint32_t pyaddr, pcbcraddr; + struct vfe31_free_buf *free_buf = NULL; + +#ifdef CONFIG_MSM_CAMERA_V4L2 + uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong; +#endif + /* we render frames in the following conditions: + 1. Continuous mode and the free buffer is avaialable. + */ + CDBG("%s, operation_mode = %d, state %d\n", __func__, + vfe31_ctrl->operation_mode, + vfe31_ctrl->recording_state); + /* Ensure that both wm1 and wm5 ping and pong buffers are active*/ + if (!(((ping_pong & 0x22) == 0x22) || + ((ping_pong & 0x22) == 0x0))) { + pr_err(" Irq_2 - skip the frame pp_status is not proper" + "PP_status = 0x%x\n", ping_pong); + return; + } + if ((vfe31_ctrl->recording_state == VFE_REC_STATE_STOP_REQUESTED) + || (vfe31_ctrl->recording_state == VFE_REC_STATE_STOPPED)) { + vfe31_ctrl->outpath.out2.frame_drop_cnt++; + pr_warning("path_irq_2 - recording stopped\n"); + return; + } + + free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out2); + + if (free_buf) { + /* Y channel */ + pyaddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out2.ch0); + /* Chroma channel */ + pcbcraddr = vfe31_get_ch_addr(ping_pong, + vfe31_ctrl->outpath.out2.ch1); + + CDBG("video output, pyaddr = 0x%x, pcbcraddr = 0x%x\n", + pyaddr, pcbcraddr); + + /* Y channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out2.ch0, + free_buf->paddr + free_buf->y_off); + /* Chroma channel */ + vfe31_put_ch_addr(ping_pong, + vfe31_ctrl->outpath.out2.ch1, + free_buf->paddr + free_buf->cbcr_off); + kfree(free_buf); + vfe_send_outmsg(MSG_ID_OUTPUT_V, pyaddr, pcbcraddr); + } else { + vfe31_ctrl->outpath.out2.frame_drop_cnt++; + pr_warning("path_irq_2 - no free buffer!\n"); + +#ifdef CONFIG_MSM_CAMERA_V4L2 + pr_info("Swapping ping and pong\n"); + + /*get addresses*/ + /* Y channel */ + pyaddr_ping = vfe31_get_ch_ping_addr( + vfe31_ctrl->outpath.out2.ch0); + /* Chroma channel */ + pcbcraddr_ping = vfe31_get_ch_ping_addr( + vfe31_ctrl->outpath.out2.ch1); + /* Y channel */ + pyaddr_pong = vfe31_get_ch_pong_addr( + vfe31_ctrl->outpath.out2.ch0); + /* Chroma channel */ + pcbcraddr_pong = vfe31_get_ch_pong_addr( + vfe31_ctrl->outpath.out2.ch1); + + CDBG("ping = 0x%p, pong = 0x%p\n", (void *)pyaddr_ping, + (void *)pyaddr_pong); + CDBG("ping_cbcr = 0x%p, pong_cbcr = 0x%p\n", + (void *)pcbcraddr_ping, (void *)pcbcraddr_pong); + + /*put addresses*/ + /* SWAP y channel*/ + vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out2.ch0, + pyaddr_pong); + vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out2.ch0, + pyaddr_ping); + /* SWAP chroma channel*/ + vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out2.ch1, + pcbcraddr_pong); + vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out2.ch1, + pcbcraddr_ping); + CDBG("after swap: ping = 0x%p, pong = 0x%p\n", + (void *)pyaddr_pong, (void *)pyaddr_ping); +#endif + } +} + + +static uint32_t vfe31_process_stats_irq_common(uint32_t statsNum, + uint32_t newAddr) { + + uint32_t pingpongStatus; + uint32_t returnAddr; + uint32_t pingpongAddr; + + /* must be 0=ping, 1=pong */ + pingpongStatus = + ((msm_io_r(vfe31_ctrl->vfebase + + VFE_BUS_PING_PONG_STATUS)) + & ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7); + /* stats bits starts at 7 */ + CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus); + pingpongAddr = + ((uint32_t)(vfe31_ctrl->vfebase + + VFE_BUS_STATS_PING_PONG_BASE)) + + (3*statsNum)*4 + (1-pingpongStatus)*4; + returnAddr = msm_io_r((uint32_t *)pingpongAddr); + msm_io_w(newAddr, (uint32_t *)pingpongAddr); + return returnAddr; +} + +static void vfe_send_stats_msg(void) +{ + struct vfe_message msg; + uint32_t temp; + + /* fill message with right content. */ + msg._u.msgStats.frameCounter = vfe31_ctrl->vfeFrameId; + msg._u.msgStats.status_bits = vfe31_ctrl->status_bits; + msg._d = MSG_ID_COMMON; + + msg._u.msgStats.buff.aec = vfe31_ctrl->aecStatsControl.bufToRender; + msg._u.msgStats.buff.awb = vfe31_ctrl->awbStatsControl.bufToRender; + msg._u.msgStats.buff.af = vfe31_ctrl->afStatsControl.bufToRender; + + msg._u.msgStats.buff.ihist = vfe31_ctrl->ihistStatsControl.bufToRender; + msg._u.msgStats.buff.rs = vfe31_ctrl->rsStatsControl.bufToRender; + msg._u.msgStats.buff.cs = vfe31_ctrl->csStatsControl.bufToRender; + + temp = msm_io_r(vfe31_ctrl->vfebase + VFE_STATS_AWB_SGW_CFG); + msg._u.msgStats.buff.awb_ymin = (0xFF00 & temp) >> 8; + + vfe31_proc_ops(msg._d, + &msg, sizeof(struct vfe_message)); + return; +} + +static void vfe31_process_stats(void) +{ + int32_t process_stats = false; + + CDBG("%s, stats = 0x%x\n", __func__, vfe31_ctrl->status_bits); + + if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_AEC) { + if (!vfe31_ctrl->aec_ack_pending) { + vfe31_ctrl->aec_ack_pending = TRUE; + vfe31_ctrl->aecStatsControl.bufToRender = + vfe31_process_stats_irq_common(statsAeNum, + vfe31_ctrl->aecStatsControl.nextFrameAddrBuf); + process_stats = true; + } else{ + vfe31_ctrl->aecStatsControl.bufToRender = 0; + vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++; + } + } else { + vfe31_ctrl->aecStatsControl.bufToRender = 0; + } + + if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_AWB) { + if (!vfe31_ctrl->awb_ack_pending) { + vfe31_ctrl->awb_ack_pending = TRUE; + vfe31_ctrl->awbStatsControl.bufToRender = + vfe31_process_stats_irq_common(statsAwbNum, + vfe31_ctrl->awbStatsControl.nextFrameAddrBuf); + process_stats = true; + } else{ + vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++; + vfe31_ctrl->awbStatsControl.bufToRender = 0; + } + } else { + vfe31_ctrl->awbStatsControl.bufToRender = 0; + } + + + if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_AF) { + if (!vfe31_ctrl->af_ack_pending) { + vfe31_ctrl->af_ack_pending = TRUE; + vfe31_ctrl->afStatsControl.bufToRender = + vfe31_process_stats_irq_common(statsAfNum, + vfe31_ctrl->afStatsControl.nextFrameAddrBuf); + process_stats = true; + } else { + vfe31_ctrl->afStatsControl.bufToRender = 0; + vfe31_ctrl->afStatsControl.droppedStatsFrameCount++; + } + } else { + vfe31_ctrl->afStatsControl.bufToRender = 0; + } + + if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_IHIST) { + if (!vfe31_ctrl->ihist_ack_pending) { + vfe31_ctrl->ihist_ack_pending = TRUE; + vfe31_ctrl->ihistStatsControl.bufToRender = + vfe31_process_stats_irq_common(statsIhistNum, + vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf); + process_stats = true; + } else { + vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++; + vfe31_ctrl->ihistStatsControl.bufToRender = 0; + } + } else { + vfe31_ctrl->ihistStatsControl.bufToRender = 0; + } + + if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_RS) { + if (!vfe31_ctrl->rs_ack_pending) { + vfe31_ctrl->rs_ack_pending = TRUE; + vfe31_ctrl->rsStatsControl.bufToRender = + vfe31_process_stats_irq_common(statsRsNum, + vfe31_ctrl->rsStatsControl.nextFrameAddrBuf); + process_stats = true; + } else { + vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++; + vfe31_ctrl->rsStatsControl.bufToRender = 0; + } + } else { + vfe31_ctrl->rsStatsControl.bufToRender = 0; + } + + + if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_CS) { + if (!vfe31_ctrl->cs_ack_pending) { + vfe31_ctrl->cs_ack_pending = TRUE; + vfe31_ctrl->csStatsControl.bufToRender = + vfe31_process_stats_irq_common(statsCsNum, + vfe31_ctrl->csStatsControl.nextFrameAddrBuf); + process_stats = true; + } else { + vfe31_ctrl->csStatsControl.droppedStatsFrameCount++; + vfe31_ctrl->csStatsControl.bufToRender = 0; + } + } else { + vfe31_ctrl->csStatsControl.bufToRender = 0; + } + + if (process_stats) + vfe_send_stats_msg(); + + return; +} + +static void vfe31_process_stats_irq(uint32_t *irqstatus) +{ + /* Subsample the stats according to the hfr speed*/ + if ((vfe31_ctrl->hfr_mode != HFR_MODE_OFF) && + (vfe31_ctrl->vfeFrameId % vfe31_ctrl->hfr_mode != 0)) { + CDBG("Skip the stats when HFR enabled\n"); + return; + } + + vfe31_ctrl->status_bits = VFE_COM_STATUS & *irqstatus; + vfe31_process_stats(); + return; +} + +static void vfe31_do_tasklet(unsigned long data) +{ + unsigned long flags; + + struct vfe31_isr_queue_cmd *qcmd = NULL; + + CDBG("=== vfe31_do_tasklet start === \n"); + + while (atomic_read(&irq_cnt)) { + spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags); + qcmd = list_first_entry(&vfe31_ctrl->tasklet_q, + struct vfe31_isr_queue_cmd, list); + atomic_sub(1, &irq_cnt); + + if (!qcmd) { + spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock, + flags); + return; + } + + list_del(&qcmd->list); + spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock, + flags); + + /* interrupt to be processed, *qcmd has the payload. */ + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_REG_UPDATE_MASK) { + CDBG("irq regUpdateIrq\n"); + vfe31_process_reg_update_irq(); + } + + if (qcmd->vfeInterruptStatus1 & + VFE_IMASK_RESET) { + CDBG("irq resetAckIrq\n"); + vfe31_process_reset_irq(); + } + + + if (qcmd->vfeInterruptStatus1 & + VFE_IMASK_AXI_HALT) { + CDBG("irq axi halt irq\n"); + vfe31_process_axi_halt_irq(); + } + + if (atomic_read(&vfe31_ctrl->vstate)) { + if (qcmd->vfeInterruptStatus1 & + VFE31_IMASK_ERROR_ONLY_1) { + pr_err("irq errorIrq\n"); + vfe31_process_error_irq( + qcmd->vfeInterruptStatus1 & + VFE31_IMASK_ERROR_ONLY_1); + } + + /* irqs below are only valid when in active state. */ + /* next, check output path related interrupts. */ + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) { + CDBG("Image composite done 0 irq occured.\n"); + vfe31_process_output_path_irq_0( + qcmd->vfePingPongStatus); + } + + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) { + CDBG("Image composite done 1 irq occured.\n"); + vfe31_process_output_path_irq_1( + qcmd->vfePingPongStatus); + } + + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK) { + CDBG("Image composite done 2 irq occured.\n"); + vfe31_process_output_path_irq_2( + qcmd->vfePingPongStatus); + } + + /* then process stats irq. */ + if (vfe31_ctrl->stats_comp) { + /* process stats comb interrupt. */ + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) { + CDBG("Stats composite irq occured.\n"); + vfe31_process_stats_irq( + &qcmd->vfeInterruptStatus0); + } + } else { + /* process individual stats interrupt. */ + if (qcmd->vfeInterruptStatus0 & + VFE_COM_STATUS) { + CDBG("VFE stats occured.\n"); + vfe31_process_stats_irq( + &qcmd->vfeInterruptStatus0); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_SYNC_TIMER0) { + CDBG("SYNC_TIMER 0 irq occured.\n"); + vfe31_send_msg_no_payload( + MSG_ID_SYNC_TIMER0_DONE); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_SYNC_TIMER1) { + CDBG("SYNC_TIMER 1 irq occured.\n"); + vfe31_send_msg_no_payload( + MSG_ID_SYNC_TIMER1_DONE); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_SYNC_TIMER2) { + CDBG("SYNC_TIMER 2 irq occured.\n"); + vfe31_send_msg_no_payload( + MSG_ID_SYNC_TIMER2_DONE); + } + } + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_CAMIF_SOF_MASK) { + CDBG("irq camifSofIrq\n"); + vfe31_process_camif_sof_irq(); + } + kfree(qcmd); + } + CDBG("=== vfe31_do_tasklet end === \n"); +} + +DECLARE_TASKLET(vfe31_tasklet, vfe31_do_tasklet, 0); + +static irqreturn_t vfe31_parse_irq(int irq_num, void *data) +{ + unsigned long flags; + struct vfe31_irq_status irq; + struct vfe31_isr_queue_cmd *qcmd; + uint32_t *val; + CDBG("vfe_parse_irq\n"); + memset(&irq, 0, sizeof(struct vfe31_irq_status)); + + val = (uint32_t *)(vfe31_ctrl->vfebase + VFE_IRQ_STATUS_0); + irq.vfeIrqStatus0 = msm_io_r(val); + + val = (uint32_t *)(vfe31_ctrl->vfebase + VFE_IRQ_STATUS_1); + irq.vfeIrqStatus1 = msm_io_r(val); + + if (irq.vfeIrqStatus1 & VFE_IMASK_AXI_HALT) { + msm_io_w(VFE_IMASK_RESET, vfe31_ctrl->vfebase + VFE_IRQ_MASK_1); + + msm_io_w_mb(AXI_HALT_CLEAR, + vfe31_ctrl->vfebase + VFE_AXI_CMD); + } + + val = (uint32_t *)(vfe31_ctrl->vfebase + VFE_CAMIF_STATUS); + irq.camifStatus = msm_io_r(val); + CDBG("camifStatus = 0x%x\n", irq.camifStatus); + + val = (uint32_t *)(vfe31_ctrl->vfebase + VFE_BUS_PING_PONG_STATUS); + irq.vfePingPongStatus = msm_io_r(val); + + /* clear the pending interrupt of the same kind.*/ + msm_io_w(irq.vfeIrqStatus0, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_io_w(irq.vfeIrqStatus1, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_IRQ_CMD); + + if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) { + CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n"); + return IRQ_HANDLED; + } + + qcmd = kzalloc(sizeof(struct vfe31_isr_queue_cmd), + GFP_ATOMIC); + if (!qcmd) { + pr_err("vfe_parse_irq: qcmd malloc failed!\n"); + return IRQ_HANDLED; + } + + if (atomic_read(&vfe31_ctrl->stop_ack_pending)) { + irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0; + irq.vfeIrqStatus1 &= vfe31_ctrl->while_stopping_mask; + } + + spin_lock_irqsave(&vfe31_ctrl->xbar_lock, flags); + if ((irq.vfeIrqStatus0 & + VFE_IRQ_STATUS0_CAMIF_EOF_MASK) && + vfe31_ctrl->xbar_update_pending) { + CDBG("irq camifEofIrq\n"); + msm_io_memcpy(vfe31_ctrl->vfebase + V31_XBAR_CFG_OFF, + (void *)vfe31_ctrl->xbar_cfg, V31_XBAR_CFG_LEN); + vfe31_ctrl->xbar_update_pending = 0; + } + spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags); + CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n", + irq.vfeIrqStatus0, irq.vfeIrqStatus1); + + qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0; + qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1; + qcmd->vfePingPongStatus = irq.vfePingPongStatus; + + spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags); + list_add_tail(&qcmd->list, &vfe31_ctrl->tasklet_q); + + atomic_add(1, &irq_cnt); + spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock, flags); + tasklet_schedule(&vfe31_tasklet); + return IRQ_HANDLED; +} + +static void vfe31_release(struct platform_device *pdev) +{ + struct resource *vfemem, *vfeio; + + vfe31_reset_free_buf_queue_all(); + CDBG("%s, free_irq\n", __func__); + free_irq(vfe31_ctrl->vfeirq, 0); + tasklet_kill(&vfe31_tasklet); + + if (atomic_read(&irq_cnt)) + pr_warning("%s, Warning IRQ Count not ZERO\n", __func__); + + vfemem = vfe31_ctrl->vfemem; + vfeio = vfe31_ctrl->vfeio; + + msm_vpe_release(); + + kfree(vfe31_ctrl->extdata); + iounmap(vfe31_ctrl->vfebase); + kfree(vfe31_ctrl); + vfe31_ctrl = NULL; + release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1); + CDBG("%s, msm_camio_disable\n", __func__); + msm_camio_disable(pdev); + msm_camio_set_perf_lvl(S_EXIT); + + vfe_syncdata = NULL; +} + +static int vfe31_resource_init(struct msm_vfe_callback *presp, + struct platform_device *pdev, void *sdata) +{ + struct resource *vfemem, *vfeirq, *vfeio; + int rc; + struct msm_camera_sensor_info *s_info; + s_info = pdev->dev.platform_data; + + pdev->resource = s_info->resource; + pdev->num_resources = s_info->num_resources; + + vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!vfemem) { + pr_err("%s: no mem resource?\n", __func__); + return -ENODEV; + } + + vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!vfeirq) { + pr_err("%s: no irq resource?\n", __func__); + return -ENODEV; + } + + vfeio = request_mem_region(vfemem->start, + resource_size(vfemem), pdev->name); + if (!vfeio) { + pr_err("%s: VFE region already claimed\n", __func__); + return -EBUSY; + } + + vfe31_ctrl = kzalloc(sizeof(struct vfe31_ctrl_type), GFP_KERNEL); + if (!vfe31_ctrl) { + rc = -ENOMEM; + goto cmd_init_failed1; + } + + vfe31_ctrl->vfeirq = vfeirq->start; + + vfe31_ctrl->vfebase = + ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1); + if (!vfe31_ctrl->vfebase) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto cmd_init_failed2; + } + + if (presp && presp->vfe_resp) + vfe31_ctrl->resp = presp; + else { + rc = -EINVAL; + goto cmd_init_failed3; + } + + vfe31_ctrl->extdata = + kmalloc(sizeof(struct vfe31_frame_extra), GFP_KERNEL); + if (!vfe31_ctrl->extdata) { + rc = -ENOMEM; + goto cmd_init_failed3; + } + + vfe31_ctrl->extlen = sizeof(struct vfe31_frame_extra); + + spin_lock_init(&vfe31_ctrl->io_lock); + spin_lock_init(&vfe31_ctrl->update_ack_lock); + spin_lock_init(&vfe31_ctrl->tasklet_lock); + + INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q); + vfe31_init_free_buf_queue(); + + vfe31_ctrl->syncdata = sdata; + vfe31_ctrl->vfemem = vfemem; + vfe31_ctrl->vfeio = vfeio; + vfe31_ctrl->update_gamma = false; + vfe31_ctrl->update_luma = false; + vfe31_ctrl->s_info = s_info; + vfe31_ctrl->stats_comp = 0; + vfe31_ctrl->hfr_mode = HFR_MODE_OFF; + return 0; + +cmd_init_failed3: + free_irq(vfe31_ctrl->vfeirq, 0); + iounmap(vfe31_ctrl->vfebase); +cmd_init_failed2: + kfree(vfe31_ctrl); +cmd_init_failed1: + release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1); + return rc; +} + +static int vfe31_init(struct msm_vfe_callback *presp, + struct platform_device *pdev) +{ + int rc = 0; + struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; + struct msm_camera_device_platform_data *camdev = sinfo->pdata; + + camio_clk = camdev->ioclk; + + rc = vfe31_resource_init(presp, pdev, vfe_syncdata); + if (rc < 0) + return rc; + /* Bring up all the required GPIOs and Clocks */ + rc = msm_camio_enable(pdev); + msm_camio_set_perf_lvl(S_INIT); + if (msm_vpe_open() < 0) + CDBG("%s: vpe_open failed\n", __func__); + + /* TO DO: Need to release the VFE resources */ + rc = request_irq(vfe31_ctrl->vfeirq, vfe31_parse_irq, + IRQF_TRIGGER_RISING, "vfe", 0); + + return rc; +} + +void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data) +{ + fptr->vfe_init = vfe31_init; + fptr->vfe_enable = vfe31_enable; + fptr->vfe_config = vfe31_config; + fptr->vfe_disable = vfe31_disable; + fptr->vfe_release = vfe31_release; + fptr->vfe_stop = vfe31_stop; + vfe_syncdata = data; +} + +void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data) +{ + fptr->vpe_reg = msm_vpe_reg; + fptr->send_frame_to_vpe = msm_send_frame_to_vpe; + fptr->vpe_config = msm_vpe_config; + fptr->vpe_cfg_update = msm_vpe_cfg_update; + fptr->dis = &(vpe_ctrl->dis_en); + fptr->vpe_cfg_offset = msm_vpe_offset_update; + vpe_ctrl->syncdata = data; +} diff --git a/drivers/media/video/msm_zsl/msm_vfe31.h b/drivers/media/video/msm_zsl/msm_vfe31.h new file mode 100644 index 00000000000..c47c7de3bee --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe31.h @@ -0,0 +1,1115 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __MSM_VFE31_H__ +#define __MSM_VFE31_H__ + +#define TRUE 1 +#define FALSE 0 + +/* at start of camif, bit 1:0 = 0x01:enable + * image data capture at frame boundary. */ +#define CAMIF_COMMAND_START 0x00000005 + +/* bit 2= 0x1:clear the CAMIF_STATUS register + * value. */ +#define CAMIF_COMMAND_CLEAR 0x00000004 + +/* at stop of vfe pipeline, for now it is assumed + * that camif will stop at any time. Bit 1:0 = 0x10: + * disable image data capture immediately. */ +#define CAMIF_COMMAND_STOP_IMMEDIATELY 0x00000002 + +/* at stop of vfe pipeline, for now it is assumed + * that camif will stop at any time. Bit 1:0 = 0x00: + * disable image data capture at frame boundary */ +#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY 0x00000000 + +/* to halt axi bridge */ +#define AXI_HALT 0x00000001 + +/* clear the halt bit. */ +#define AXI_HALT_CLEAR 0x00000000 + +/* clear axi_halt_irq */ +#define MASK_AXI_HALT_IRQ 0xFF7FFFFF + +/* reset the pipeline when stop command is issued. + * (without reset the register.) bit 26-31 = 0, + * domain reset, bit 0-9 = 1 for module reset, except + * register module. */ +#define VFE_RESET_UPON_STOP_CMD 0x000003ef + +/* reset the pipeline when reset command. + * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */ +#define VFE_RESET_UPON_RESET_CMD 0x000003ff + +/* bit 5 is for axi status idle or busy. + * 1 = halted, 0 = busy */ +#define AXI_STATUS_BUSY_MASK 0x00000020 + +/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present + * for frame done interrupt */ +#define VFE_COMP_IRQ_BOTH_Y_CBCR 3 + +/* bit 1 = 1, only cbcr irq triggers frame done interrupt */ +#define VFE_COMP_IRQ_CBCR_ONLY 2 + +/* bit 0 = 1, only y irq triggers frame done interrupt */ +#define VFE_COMP_IRQ_Y_ONLY 1 + +/* bit 0 = 1, PM go; bit1 = 1, PM stop */ +#define VFE_PERFORMANCE_MONITOR_GO 0x00000001 +#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002 + +/* bit 0 = 1, test gen go; bit1 = 1, test gen stop */ +#define VFE_TEST_GEN_GO 0x00000001 +#define VFE_TEST_GEN_STOP 0x00000002 + +/* the chroma is assumed to be interpolated between + * the luma samples. JPEG 4:2:2 */ +#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0 + +/* constants for irq registers */ +#define VFE_DISABLE_ALL_IRQS 0 +/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS. */ +#define VFE_CLEAR_ALL_IRQS 0xffffffff + +#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK 0x00000001 +#define VFE_IRQ_STATUS0_CAMIF_EOF_MASK 0x00000004 +#define VFE_IRQ_STATUS0_REG_UPDATE_MASK 0x00000020 +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK 0x00200000 +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK 0x00400000 +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK 0x00800000 +#define VFE_IRQ_STATUS1_RESET_AXI_HALT_ACK_MASK 0x00800000 +#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK 0x01000000 + +#define VFE_IRQ_STATUS0_STATS_AEC 0x2000 /* bit 13 */ +#define VFE_IRQ_STATUS0_STATS_AF 0x4000 /* bit 14 */ +#define VFE_IRQ_STATUS0_STATS_AWB 0x8000 /* bit 15 */ +#define VFE_IRQ_STATUS0_STATS_RS 0x10000 /* bit 16 */ +#define VFE_IRQ_STATUS0_STATS_CS 0x20000 /* bit 17 */ +#define VFE_IRQ_STATUS0_STATS_IHIST 0x40000 /* bit 18 */ + +#define VFE_IRQ_STATUS0_SYNC_TIMER0 0x2000000 /* bit 25 */ +#define VFE_IRQ_STATUS0_SYNC_TIMER1 0x4000000 /* bit 26 */ +#define VFE_IRQ_STATUS0_SYNC_TIMER2 0x8000000 /* bit 27 */ +#define VFE_IRQ_STATUS0_ASYNC_TIMER0 0x10000000 /* bit 28 */ +#define VFE_IRQ_STATUS0_ASYNC_TIMER1 0x20000000 /* bit 29 */ +#define VFE_IRQ_STATUS0_ASYNC_TIMER2 0x40000000 /* bit 30 */ +#define VFE_IRQ_STATUS0_ASYNC_TIMER3 0x80000000 /* bit 31 */ + +/* imask for while waiting for stop ack, driver has already + * requested stop, waiting for reset irq, and async timer irq. + * For irq_status_0, bit 28-31 are for async timer. For + * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack + irq */ +#define VFE_IMASK_WHILE_STOPPING_0 0xF0000000 +#define VFE_IMASK_WHILE_STOPPING_1 0x00C00000 +#define VFE_IMASK_RESET 0x00400000 +#define VFE_IMASK_AXI_HALT 0x00800000 + + +/* no error irq in mask 0 */ +#define VFE_IMASK_ERROR_ONLY_0 0x0 +/* when normal case, don't want to block error status. */ +/* bit 0-21 are error irq bits */ +#define VFE_IMASK_ERROR_ONLY_1 0x003fffff + +/* For BPC bit 0,bit 12-17 and bit 26 -20 are set to zero and other's 1 */ +#define BPC_MASK 0xF80C0FFE + +/* For BPC bit 1 and 2 are set to zero and other's 1 */ +#define ABF_MASK 0xFFFFFFF9 + +/* For MCE enable bit 28 set to zero and other's 1 */ +#define MCE_EN_MASK 0xEFFFFFFF + +/* For MCE Q_K bit 28 to 31 set to zero and other's 1 */ +#define MCE_Q_K_MASK 0x0FFFFFFF + +#define AWB_ENABLE_MASK 0x00000080 /* bit 7 */ +#define AF_ENABLE_MASK 0x00000040 /* bit 6 */ +#define AE_ENABLE_MASK 0x00000020 /* bit 5 */ +#define IHIST_ENABLE_MASK 0x00008000 /* bit 15 */ +#define RS_ENABLE_MASK 0x00000100 /* bit 8 */ +#define CS_ENABLE_MASK 0x00000200 /* bit 9 */ +#define RS_CS_ENABLE_MASK 0x00000300 /* bit 8,9 */ +#define STATS_ENABLE_MASK 0x000483E0 /* bit 18,15,9,8,7,6,5*/ + +#define VFE_REG_UPDATE_TRIGGER 1 +#define VFE_PM_BUF_MAX_CNT_MASK 0xFF +#define VFE_DMI_CFG_DEFAULT 0x00000100 +#define LENS_ROLL_OFF_DELTA_TABLE_OFFSET 32 +#define VFE_AE_PINGPONG_STATUS_BIT 0x80 +#define VFE_AF_PINGPONG_STATUS_BIT 0x100 +#define VFE_AWB_PINGPONG_STATUS_BIT 0x200 + +#define HFR_MODE_OFF 1 + +enum VFE31_DMI_RAM_SEL { + NO_MEM_SELECTED = 0, + ROLLOFF_RAM = 0x1, + RGBLUT_RAM_CH0_BANK0 = 0x2, + RGBLUT_RAM_CH0_BANK1 = 0x3, + RGBLUT_RAM_CH1_BANK0 = 0x4, + RGBLUT_RAM_CH1_BANK1 = 0x5, + RGBLUT_RAM_CH2_BANK0 = 0x6, + RGBLUT_RAM_CH2_BANK1 = 0x7, + STATS_HIST_RAM = 0x8, + RGBLUT_CHX_BANK0 = 0x9, + RGBLUT_CHX_BANK1 = 0xa, + LUMA_ADAPT_LUT_RAM_BANK0 = 0xb, + LUMA_ADAPT_LUT_RAM_BANK1 = 0xc +}; + +enum VFE_STATE { + VFE_STATE_IDLE, + VFE_STATE_ACTIVE +}; + +enum vfe_recording_state { + VFE_REC_STATE_IDLE, + VFE_REC_STATE_START_REQUESTED, + VFE_REC_STATE_STARTED, + VFE_REC_STATE_STOP_REQUESTED, + VFE_REC_STATE_STOPPED, +}; + +#define V31_DUMMY_0 0 +#define V31_SET_CLK 1 +#define V31_RESET 2 +#define V31_START 3 +#define V31_TEST_GEN_START 4 +#define V31_OPERATION_CFG 5 +#define V31_AXI_OUT_CFG 6 +#define V31_CAMIF_CFG 7 +#define V31_AXI_INPUT_CFG 8 +#define V31_BLACK_LEVEL_CFG 9 +#define V31_ROLL_OFF_CFG 10 +#define V31_DEMUX_CFG 11 +#define V31_DEMOSAIC_0_CFG 12 /* general */ +#define V31_DEMOSAIC_1_CFG 13 /* ABF */ +#define V31_DEMOSAIC_2_CFG 14 /* BPC */ +#define V31_FOV_CFG 15 +#define V31_MAIN_SCALER_CFG 16 +#define V31_WB_CFG 17 +#define V31_COLOR_COR_CFG 18 +#define V31_RGB_G_CFG 19 +#define V31_LA_CFG 20 +#define V31_CHROMA_EN_CFG 21 +#define V31_CHROMA_SUP_CFG 22 +#define V31_MCE_CFG 23 +#define V31_SK_ENHAN_CFG 24 +#define V31_ASF_CFG 25 +#define V31_S2Y_CFG 26 +#define V31_S2CbCr_CFG 27 +#define V31_CHROMA_SUBS_CFG 28 +#define V31_OUT_CLAMP_CFG 29 +#define V31_FRAME_SKIP_CFG 30 +#define V31_DUMMY_1 31 +#define V31_DUMMY_2 32 +#define V31_DUMMY_3 33 +#define V31_UPDATE 34 +#define V31_BL_LVL_UPDATE 35 +#define V31_DEMUX_UPDATE 36 +#define V31_DEMOSAIC_1_UPDATE 37 /* BPC */ +#define V31_DEMOSAIC_2_UPDATE 38 /* ABF */ +#define V31_FOV_UPDATE 39 +#define V31_MAIN_SCALER_UPDATE 40 +#define V31_WB_UPDATE 41 +#define V31_COLOR_COR_UPDATE 42 +#define V31_RGB_G_UPDATE 43 +#define V31_LA_UPDATE 44 +#define V31_CHROMA_EN_UPDATE 45 +#define V31_CHROMA_SUP_UPDATE 46 +#define V31_MCE_UPDATE 47 +#define V31_SK_ENHAN_UPDATE 48 +#define V31_S2CbCr_UPDATE 49 +#define V31_S2Y_UPDATE 50 +#define V31_ASF_UPDATE 51 +#define V31_FRAME_SKIP_UPDATE 52 +#define V31_CAMIF_FRAME_UPDATE 53 +#define V31_STATS_AF_UPDATE 54 +#define V31_STATS_AE_UPDATE 55 +#define V31_STATS_AWB_UPDATE 56 +#define V31_STATS_RS_UPDATE 57 +#define V31_STATS_CS_UPDATE 58 +#define V31_STATS_SKIN_UPDATE 59 +#define V31_STATS_IHIST_UPDATE 60 +#define V31_DUMMY_4 61 +#define V31_EPOCH1_ACK 62 +#define V31_EPOCH2_ACK 63 +#define V31_START_RECORDING 64 +#define V31_STOP_RECORDING 65 +#define V31_DUMMY_5 66 +#define V31_DUMMY_6 67 +#define V31_CAPTURE 68 +#define V31_DUMMY_7 69 +#define V31_STOP 70 +#define V31_GET_HW_VERSION 71 +#define V31_GET_FRAME_SKIP_COUNTS 72 +#define V31_OUTPUT1_BUFFER_ENQ 73 +#define V31_OUTPUT2_BUFFER_ENQ 74 +#define V31_OUTPUT3_BUFFER_ENQ 75 +#define V31_JPEG_OUT_BUF_ENQ 76 +#define V31_RAW_OUT_BUF_ENQ 77 +#define V31_RAW_IN_BUF_ENQ 78 +#define V31_STATS_AF_ENQ 79 +#define V31_STATS_AE_ENQ 80 +#define V31_STATS_AWB_ENQ 81 +#define V31_STATS_RS_ENQ 82 +#define V31_STATS_CS_ENQ 83 +#define V31_STATS_SKIN_ENQ 84 +#define V31_STATS_IHIST_ENQ 85 +#define V31_DUMMY_8 86 +#define V31_JPEG_ENC_CFG 87 +#define V31_DUMMY_9 88 +#define V31_STATS_AF_START 89 +#define V31_STATS_AF_STOP 90 +#define V31_STATS_AE_START 91 +#define V31_STATS_AE_STOP 92 +#define V31_STATS_AWB_START 93 +#define V31_STATS_AWB_STOP 94 +#define V31_STATS_RS_START 95 +#define V31_STATS_RS_STOP 96 +#define V31_STATS_CS_START 97 +#define V31_STATS_CS_STOP 98 +#define V31_STATS_SKIN_START 99 +#define V31_STATS_SKIN_STOP 100 +#define V31_STATS_IHIST_START 101 +#define V31_STATS_IHIST_STOP 102 +#define V31_DUMMY_10 103 +#define V31_SYNC_TIMER_SETTING 104 +#define V31_ASYNC_TIMER_SETTING 105 +#define V31_LIVESHOT 106 +#define V31_ZSL 107 +#define V31_STEREOCAM 108 +#define V31_LA_SETUP 109 +#define V31_XBAR_CFG 110 +#define V31_EZTUNE_CFG 111 + +#define V31_CAMIF_OFF 0x000001E4 +#define V31_CAMIF_LEN 32 + +#define V31_DEMUX_OFF 0x00000284 +#define V31_DEMUX_LEN 20 + +#define V31_DEMOSAIC_0_OFF 0x00000298 +#define V31_DEMOSAIC_0_LEN 4 +/* ABF */ +#define V31_DEMOSAIC_1_OFF 0x000002A4 +#define V31_DEMOSAIC_1_LEN 180 +/* BPC */ +#define V31_DEMOSAIC_2_OFF 0x0000029C +#define V31_DEMOSAIC_2_LEN 8 + +/* gamma VFE_LUT_BANK_SEL*/ +#define V31_GAMMA_CFG_OFF 0x000003BC +#define V31_LUMA_CFG_OFF 0x000003C0 + +#define V31_OUT_CLAMP_OFF 0x00000524 +#define V31_OUT_CLAMP_LEN 8 + +#define V31_OPERATION_CFG_LEN 32 + +#define V31_AXI_OUT_OFF 0x00000038 +#define V31_AXI_OUT_LEN 212 +#define V31_AXI_CH_INF_LEN 24 +#define V31_AXI_CFG_LEN 47 + +#define V31_FRAME_SKIP_OFF 0x00000504 +#define V31_FRAME_SKIP_LEN 32 + +#define V31_CHROMA_SUBS_OFF 0x000004F8 +#define V31_CHROMA_SUBS_LEN 12 + +#define V31_FOV_OFF 0x00000360 +#define V31_FOV_LEN 8 + +#define V31_MAIN_SCALER_OFF 0x00000368 +#define V31_MAIN_SCALER_LEN 28 + +#define V31_S2Y_OFF 0x000004D0 +#define V31_S2Y_LEN 20 + +#define V31_S2CbCr_OFF 0x000004E4 +#define V31_S2CbCr_LEN 20 + +#define V31_CHROMA_EN_OFF 0x000003C4 +#define V31_CHROMA_EN_LEN 36 + +#define V31_SYNC_TIMER_OFF 0x0000020C +#define V31_SYNC_TIMER_POLARITY_OFF 0x00000234 +#define V31_TIMER_SELECT_OFF 0x0000025C +#define V31_SYNC_TIMER_LEN 28 + +#define V31_ASYNC_TIMER_OFF 0x00000238 +#define V31_ASYNC_TIMER_LEN 28 + +#define V31_BLACK_LEVEL_OFF 0x00000264 +#define V31_BLACK_LEVEL_LEN 16 + +#define V31_ROLL_OFF_CFG_OFF 0x00000274 +#define V31_ROLL_OFF_CFG_LEN 16 + +#define V31_COLOR_COR_OFF 0x00000388 +#define V31_COLOR_COR_LEN 52 + +#define V31_WB_OFF 0x00000384 +#define V31_WB_LEN 4 + +#define V31_RGB_G_OFF 0x000003BC +#define V31_RGB_G_LEN 4 + +#define V31_LA_OFF 0x000003C0 +#define V31_LA_LEN 4 + +#define V31_SCE_OFF 0x00000418 +#define V31_SCE_LEN 136 + +#define V31_CHROMA_SUP_OFF 0x000003E8 +#define V31_CHROMA_SUP_LEN 12 + +#define V31_MCE_OFF 0x000003F4 +#define V31_MCE_LEN 36 +#define V31_STATS_AF_OFF 0x0000053c +#define V31_STATS_AF_LEN 16 + +#define V31_STATS_AE_OFF 0x00000534 +#define V31_STATS_AE_LEN 8 + +#define V31_STATS_AWB_OFF 0x0000054c +#define V31_STATS_AWB_LEN 32 + +#define V31_STATS_IHIST_OFF 0x0000057c +#define V31_STATS_IHIST_LEN 8 + +#define V31_STATS_RS_OFF 0x0000056c +#define V31_STATS_RS_LEN 8 + +#define V31_STATS_CS_OFF 0x00000574 +#define V31_STATS_CS_LEN 8 + +#define V31_XBAR_CFG_OFF 0x00000040 +#define V31_XBAR_CFG_LEN 8 + +#define V31_EZTUNE_CFG_OFF 0x00000010 +#define V31_EZTUNE_CFG_LEN 4 + +#define V31_ASF_OFF 0x000004A0 +#define V31_ASF_LEN 48 +#define V31_ASF_UPDATE_LEN 36 + +#define V31_CAPTURE_LEN 4 + +struct vfe_cmd_hw_version { + uint32_t minorVersion; + uint32_t majorVersion; + uint32_t coreVersion; +}; + +enum VFE_AXI_OUTPUT_MODE { + VFE_AXI_OUTPUT_MODE_Output1, + VFE_AXI_OUTPUT_MODE_Output2, + VFE_AXI_OUTPUT_MODE_Output1AndOutput2, + VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2, + VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1, + VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2, + VFE_AXI_LAST_OUTPUT_MODE_ENUM +}; + +enum VFE_RAW_WR_PATH_SEL { + VFE_RAW_OUTPUT_DISABLED, + VFE_RAW_OUTPUT_ENC_CBCR_PATH, + VFE_RAW_OUTPUT_VIEW_CBCR_PATH, + VFE_RAW_OUTPUT_PATH_INVALID +}; + + +#define VFE_AXI_OUTPUT_BURST_LENGTH 4 +#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4 +#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT 3 + +struct vfe_cmds_per_write_master { + uint16_t imageWidth; + uint16_t imageHeight; + uint16_t outRowCount; + uint16_t outRowIncrement; + uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT] + [VFE_MAX_NUM_FRAGMENTS_PER_FRAME]; +}; + +struct vfe_cmds_axi_per_output_path { + uint8_t fragmentCount; + struct vfe_cmds_per_write_master firstWM; + struct vfe_cmds_per_write_master secondWM; +}; + +enum VFE_AXI_BURST_LENGTH { + VFE_AXI_BURST_LENGTH_IS_2 = 2, + VFE_AXI_BURST_LENGTH_IS_4 = 4, + VFE_AXI_BURST_LENGTH_IS_8 = 8, + VFE_AXI_BURST_LENGTH_IS_16 = 16 +}; + + +struct vfe_cmd_fov_crop_config { + uint8_t enable; + uint16_t firstPixel; + uint16_t lastPixel; + uint16_t firstLine; + uint16_t lastLine; +}; + +struct vfe_cmds_main_scaler_stripe_init { + uint16_t MNCounterInit; + uint16_t phaseInit; +}; + +struct vfe_cmds_scaler_one_dimension { + uint8_t enable; + uint16_t inputSize; + uint16_t outputSize; + uint32_t phaseMultiplicationFactor; + uint8_t interpolationResolution; +}; + +struct vfe_cmd_main_scaler_config { + uint8_t enable; + struct vfe_cmds_scaler_one_dimension hconfig; + struct vfe_cmds_scaler_one_dimension vconfig; + struct vfe_cmds_main_scaler_stripe_init MNInitH; + struct vfe_cmds_main_scaler_stripe_init MNInitV; +}; + +struct vfe_cmd_scaler2_config { + uint8_t enable; + struct vfe_cmds_scaler_one_dimension hconfig; + struct vfe_cmds_scaler_one_dimension vconfig; +}; + + +struct vfe_cmd_frame_skip_update { + uint32_t output1Pattern; + uint32_t output2Pattern; +}; + +struct vfe_cmd_output_clamp_config { + uint8_t minCh0; + uint8_t minCh1; + uint8_t minCh2; + uint8_t maxCh0; + uint8_t maxCh1; + uint8_t maxCh2; +}; + +struct vfe_cmd_chroma_subsample_config { + uint8_t enable; + uint8_t cropEnable; + uint8_t vsubSampleEnable; + uint8_t hsubSampleEnable; + uint8_t vCosited; + uint8_t hCosited; + uint8_t vCositedPhase; + uint8_t hCositedPhase; + uint16_t cropWidthFirstPixel; + uint16_t cropWidthLastPixel; + uint16_t cropHeightFirstLine; + uint16_t cropHeightLastLine; +}; + +enum VFE_START_INPUT_SOURCE { + VFE_START_INPUT_SOURCE_CAMIF, + VFE_START_INPUT_SOURCE_TESTGEN, + VFE_START_INPUT_SOURCE_AXI, + VFE_START_INPUT_SOURCE_INVALID +}; + +enum VFE_START_PIXEL_PATTERN { + VFE_BAYER_RGRGRG, + VFE_BAYER_GRGRGR, + VFE_BAYER_BGBGBG, + VFE_BAYER_GBGBGB, + VFE_YUV_YCbYCr, + VFE_YUV_YCrYCb, + VFE_YUV_CbYCrY, + VFE_YUV_CrYCbY +}; + +enum VFE_BUS_RD_INPUT_PIXEL_PATTERN { + VFE_BAYER_RAW, + VFE_YUV_INTERLEAVED, + VFE_YUV_PSEUDO_PLANAR_Y, + VFE_YUV_PSEUDO_PLANAR_CBCR +}; + +enum VFE_YUV_INPUT_COSITING_MODE { + VFE_YUV_COSITED, + VFE_YUV_INTERPOLATED +}; + + +/* 13*1 */ +#define VFE31_ROLL_OFF_INIT_TABLE_SIZE 13 +/* 13*16 */ +#define VFE31_ROLL_OFF_DELTA_TABLE_SIZE 208 + +#define VFE31_GAMMA_NUM_ENTRIES 64 + +#define VFE31_LA_TABLE_LENGTH 64 + +#define VFE31_HIST_TABLE_LENGTH 256 + +struct vfe_cmds_demosaic_abf { + uint8_t enable; + uint8_t forceOn; + uint8_t shift; + uint16_t lpThreshold; + uint16_t max; + uint16_t min; + uint8_t ratio; +}; + +struct vfe_cmds_demosaic_bpc { + uint8_t enable; + uint16_t fmaxThreshold; + uint16_t fminThreshold; + uint16_t redDiffThreshold; + uint16_t blueDiffThreshold; + uint16_t greenDiffThreshold; +}; + +struct vfe_cmd_demosaic_config { + uint8_t enable; + uint8_t slopeShift; + struct vfe_cmds_demosaic_abf abfConfig; + struct vfe_cmds_demosaic_bpc bpcConfig; +}; + +struct vfe_cmd_demosaic_bpc_update { + struct vfe_cmds_demosaic_bpc bpcUpdate; +}; + +struct vfe_cmd_demosaic_abf_update { + struct vfe_cmds_demosaic_abf abfUpdate; +}; + +struct vfe_cmd_white_balance_config { + uint8_t enable; + uint16_t ch2Gain; + uint16_t ch1Gain; + uint16_t ch0Gain; +}; + +enum VFE_COLOR_CORRECTION_COEF_QFACTOR { + COEF_IS_Q7_SIGNED, + COEF_IS_Q8_SIGNED, + COEF_IS_Q9_SIGNED, + COEF_IS_Q10_SIGNED +}; + +struct vfe_cmd_color_correction_config { + uint8_t enable; + enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor; + int16_t C0; + int16_t C1; + int16_t C2; + int16_t C3; + int16_t C4; + int16_t C5; + int16_t C6; + int16_t C7; + int16_t C8; + int16_t K0; + int16_t K1; + int16_t K2; +}; + +#define VFE_LA_TABLE_LENGTH 64 + +struct vfe_cmd_la_config { + uint8_t enable; + int16_t table[VFE_LA_TABLE_LENGTH]; +}; + +#define VFE_GAMMA_TABLE_LENGTH 256 +enum VFE_RGB_GAMMA_TABLE_SELECT { + RGB_GAMMA_CH0_SELECTED, + RGB_GAMMA_CH1_SELECTED, + RGB_GAMMA_CH2_SELECTED, + RGB_GAMMA_CH0_CH1_SELECTED, + RGB_GAMMA_CH0_CH2_SELECTED, + RGB_GAMMA_CH1_CH2_SELECTED, + RGB_GAMMA_CH0_CH1_CH2_SELECTED +}; + +struct vfe_cmd_rgb_gamma_config { + uint8_t enable; + enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect; + int16_t table[VFE_GAMMA_TABLE_LENGTH]; +}; + +struct vfe_cmd_chroma_enhan_config { + uint8_t enable; + int16_t am; + int16_t ap; + int16_t bm; + int16_t bp; + int16_t cm; + int16_t cp; + int16_t dm; + int16_t dp; + int16_t kcr; + int16_t kcb; + int16_t RGBtoYConversionV0; + int16_t RGBtoYConversionV1; + int16_t RGBtoYConversionV2; + uint8_t RGBtoYConversionOffset; +}; + +struct vfe_cmd_chroma_suppression_config { + uint8_t enable; + uint8_t m1; + uint8_t m3; + uint8_t n1; + uint8_t n3; + uint8_t nn1; + uint8_t mm1; +}; + +struct vfe_cmd_asf_config { + uint8_t enable; + uint8_t smoothFilterEnabled; + uint8_t sharpMode; + uint8_t smoothCoefCenter; + uint8_t smoothCoefSurr; + uint8_t normalizeFactor; + uint8_t sharpK1; + uint8_t sharpK2; + uint8_t sharpThreshE1; + int8_t sharpThreshE2; + int8_t sharpThreshE3; + int8_t sharpThreshE4; + int8_t sharpThreshE5; + int8_t filter1Coefficients[9]; + int8_t filter2Coefficients[9]; + uint8_t cropEnable; + uint16_t cropFirstPixel; + uint16_t cropLastPixel; + uint16_t cropFirstLine; + uint16_t cropLastLine; +}; + +struct vfe_cmd_asf_update { + uint8_t enable; + uint8_t smoothFilterEnabled; + uint8_t sharpMode; + uint8_t smoothCoefCenter; + uint8_t smoothCoefSurr; + uint8_t normalizeFactor; + uint8_t sharpK1; + uint8_t sharpK2; + uint8_t sharpThreshE1; + int8_t sharpThreshE2; + int8_t sharpThreshE3; + int8_t sharpThreshE4; + int8_t sharpThreshE5; + int8_t filter1Coefficients[9]; + int8_t filter2Coefficients[9]; + uint8_t cropEnable; +}; + +enum VFE_TEST_GEN_SYNC_EDGE { + VFE_TEST_GEN_SYNC_EDGE_ActiveHigh, + VFE_TEST_GEN_SYNC_EDGE_ActiveLow +}; + + +struct vfe_cmd_bus_pm_start { + uint8_t output2YWrPmEnable; + uint8_t output2CbcrWrPmEnable; + uint8_t output1YWrPmEnable; + uint8_t output1CbcrWrPmEnable; +}; + +struct vfe_frame_skip_counts { + uint32_t totalFrameCount; + uint32_t output1Count; + uint32_t output2Count; +}; + +enum VFE_AXI_RD_UNPACK_HBI_SEL { + VFE_AXI_RD_HBI_32_CLOCK_CYCLES, + VFE_AXI_RD_HBI_64_CLOCK_CYCLES, + VFE_AXI_RD_HBI_128_CLOCK_CYCLES, + VFE_AXI_RD_HBI_256_CLOCK_CYCLES, + VFE_AXI_RD_HBI_512_CLOCK_CYCLES, + VFE_AXI_RD_HBI_1024_CLOCK_CYCLES, + VFE_AXI_RD_HBI_2048_CLOCK_CYCLES, + VFE_AXI_RD_HBI_4096_CLOCK_CYCLES +}; + +enum VFE31_MESSAGE_ID { + MSG_ID_RESET_ACK, /* 0 */ + MSG_ID_START_ACK, + MSG_ID_STOP_ACK, + MSG_ID_UPDATE_ACK, + MSG_ID_OUTPUT_P, + MSG_ID_OUTPUT_T, + MSG_ID_OUTPUT_S, + MSG_ID_OUTPUT_V, + MSG_ID_SNAPSHOT_DONE, + MSG_ID_COMMON, + MSG_ID_EPOCH1, /* 10 */ + MSG_ID_EPOCH2, + MSG_ID_SYNC_TIMER0_DONE, + MSG_ID_SYNC_TIMER1_DONE, + MSG_ID_SYNC_TIMER2_DONE, + MSG_ID_ASYNC_TIMER0_DONE, + MSG_ID_ASYNC_TIMER1_DONE, + MSG_ID_ASYNC_TIMER2_DONE, + MSG_ID_ASYNC_TIMER3_DONE, + MSG_ID_AE_OVERFLOW, + MSG_ID_AF_OVERFLOW, /* 20 */ + MSG_ID_AWB_OVERFLOW, + MSG_ID_RS_OVERFLOW, + MSG_ID_CS_OVERFLOW, + MSG_ID_IHIST_OVERFLOW, + MSG_ID_SKIN_OVERFLOW, + MSG_ID_AXI_ERROR, + MSG_ID_CAMIF_OVERFLOW, + MSG_ID_VIOLATION, + MSG_ID_CAMIF_ERROR, + MSG_ID_BUS_OVERFLOW, /* 30 */ + MSG_ID_SOF_ACK, + MSG_ID_STOP_REC_ACK, +}; + +struct stats_buffer { + uint8_t awb_ymin; + uint32_t aec; + uint32_t awb; + uint32_t af; + uint32_t ihist; + uint32_t rs; + uint32_t cs; + uint32_t skin; +}; + +struct vfe_msg_stats { + struct stats_buffer buff; + uint32_t frameCounter; + uint32_t status_bits; +}; + + +struct vfe_frame_bpc_info { + uint32_t greenDefectPixelCount; + uint32_t redBlueDefectPixelCount; +}; + +struct vfe_frame_asf_info { + uint32_t asfMaxEdge; + uint32_t asfHbiCount; +}; + +struct vfe_msg_camif_status { + uint8_t camifState; + uint32_t pixelCount; + uint32_t lineCount; +}; + + +struct vfe31_irq_status { + uint32_t vfeIrqStatus0; + uint32_t vfeIrqStatus1; + uint32_t camifStatus; + uint32_t demosaicStatus; + uint32_t asfMaxEdge; + uint32_t vfePingPongStatus; +}; + +struct vfe_msg_output { + uint8_t output_id; + uint32_t yBuffer; + uint32_t cbcrBuffer; + struct vfe_frame_bpc_info bpcInfo; + struct vfe_frame_asf_info asfInfo; + uint32_t frameCounter; +}; + +struct vfe_message { + enum VFE31_MESSAGE_ID _d; + union { + struct vfe_msg_output msgOut; + struct vfe_msg_stats msgStats; + struct vfe_msg_camif_status msgCamifError; + } _u; +}; + +/* New one for 7x30 */ +struct msm_vfe31_cmd { + int32_t id; + uint16_t length; + void *value; +}; + +#define V31_PREVIEW_AXI_FLAG 0x00000001 +#define V31_SNAPSHOT_AXI_FLAG (0x00000001<<1) + +struct vfe31_cmd_type { + uint16_t id; + uint32_t length; + uint32_t offset; + uint32_t flag; +}; + +struct vfe31_free_buf { + struct list_head node; + uint32_t paddr; + uint32_t y_off; + uint32_t cbcr_off; +}; + +struct vfe31_output_ch { + struct list_head free_buf_head; + spinlock_t free_buf_lock; + uint16_t output_fmt; + int8_t ch0; + int8_t ch1; + int8_t ch2; + uint32_t frame_drop_cnt; +}; + +/* no error irq in mask 0 */ +#define VFE31_IMASK_ERROR_ONLY_0 0x0 +/* when normal case, don't want to block error status. */ +/* bit 0-21 are error irq bits */ +#define VFE31_IMASK_ERROR_ONLY_1 0x003FFFFF +#define VFE31_IMASK_CAMIF_ERROR (0x00000001<<0) +#define VFE31_IMASK_STATS_CS_OVWR (0x00000001<<1) +#define VFE31_IMASK_STATS_IHIST_OVWR (0x00000001<<2) +#define VFE31_IMASK_REALIGN_BUF_Y_OVFL (0x00000001<<3) +#define VFE31_IMASK_REALIGN_BUF_CB_OVFL (0x00000001<<4) +#define VFE31_IMASK_REALIGN_BUF_CR_OVFL (0x00000001<<5) +#define VFE31_IMASK_VIOLATION (0x00000001<<6) +#define VFE31_IMASK_IMG_MAST_0_BUS_OVFL (0x00000001<<7) +#define VFE31_IMASK_IMG_MAST_1_BUS_OVFL (0x00000001<<8) +#define VFE31_IMASK_IMG_MAST_2_BUS_OVFL (0x00000001<<9) +#define VFE31_IMASK_IMG_MAST_3_BUS_OVFL (0x00000001<<10) +#define VFE31_IMASK_IMG_MAST_4_BUS_OVFL (0x00000001<<11) +#define VFE31_IMASK_IMG_MAST_5_BUS_OVFL (0x00000001<<12) +#define VFE31_IMASK_IMG_MAST_6_BUS_OVFL (0x00000001<<13) +#define VFE31_IMASK_STATS_AE_BUS_OVFL (0x00000001<<14) +#define VFE31_IMASK_STATS_AF_BUS_OVFL (0x00000001<<15) +#define VFE31_IMASK_STATS_AWB_BUS_OVFL (0x00000001<<16) +#define VFE31_IMASK_STATS_RS_BUS_OVFL (0x00000001<<17) +#define VFE31_IMASK_STATS_CS_BUS_OVFL (0x00000001<<18) +#define VFE31_IMASK_STATS_IHIST_BUS_OVFL (0x00000001<<19) +#define VFE31_IMASK_STATS_SKIN_BUS_OVFL (0x00000001<<20) +#define VFE31_IMASK_AXI_ERROR (0x00000001<<21) + +#define VFE_COM_STATUS 0x000FE000 + +struct vfe31_output_path { + uint16_t output_mode; /* bitmask */ + + struct vfe31_output_ch out0; /* preview and thumbnail */ + struct vfe31_output_ch out1; /* snapshot */ + struct vfe31_output_ch out2; /* video */ +}; + +struct vfe31_frame_extra { + uint32_t greenDefectPixelCount; + uint32_t redBlueDefectPixelCount; + + uint32_t asfMaxEdge; + uint32_t asfHbiCount; + + uint32_t yWrPmStats0; + uint32_t yWrPmStats1; + uint32_t cbcrWrPmStats0; + uint32_t cbcrWrPmStats1; + + uint32_t frameCounter; +}; + +#define VFE_DISABLE_ALL_IRQS 0 +#define VFE_CLEAR_ALL_IRQS 0xffffffff + +#define VFE_GLOBAL_RESET 0x00000004 +#define VFE_CGC_OVERRIDE 0x0000000C +#define VFE_MODULE_CFG 0x00000010 +#define VFE_CFG_OFF 0x00000014 +#define VFE_IRQ_CMD 0x00000018 +#define VFE_IRQ_MASK_0 0x0000001C +#define VFE_IRQ_MASK_1 0x00000020 +#define VFE_IRQ_CLEAR_0 0x00000024 +#define VFE_IRQ_CLEAR_1 0x00000028 +#define VFE_IRQ_STATUS_0 0x0000002C +#define VFE_IRQ_STATUS_1 0x00000030 +#define VFE_IRQ_COMP_MASK 0x00000034 +#define VFE_BUS_CMD 0x00000038 +#define VFE_BUS_PING_PONG_STATUS 0x00000180 +#define VFE_BUS_OPERATION_STATUS 0x00000184 + +#define VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0 0x00000190 +#define VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1 0x00000194 + +#define VFE_AXI_CMD 0x000001D8 +#define VFE_AXI_STATUS 0x000001DC +#define VFE_BUS_STATS_PING_PONG_BASE 0x000000F4 + +#define VFE_BUS_STATS_AEC_WR_PING_ADDR 0x000000F4 +#define VFE_BUS_STATS_AEC_WR_PONG_ADDR 0x000000F8 +#define VFE_BUS_STATS_AEC_UB_CFG 0x000000FC +#define VFE_BUS_STATS_AF_WR_PING_ADDR 0x00000100 +#define VFE_BUS_STATS_AF_WR_PONG_ADDR 0x00000104 +#define VFE_BUS_STATS_AF_UB_CFG 0x00000108 +#define VFE_BUS_STATS_AWB_WR_PING_ADDR 0x0000010C +#define VFE_BUS_STATS_AWB_WR_PONG_ADDR 0x00000110 +#define VFE_BUS_STATS_AWB_UB_CFG 0x00000114 +#define VFE_BUS_STATS_RS_WR_PING_ADDR 0x00000118 +#define VFE_BUS_STATS_RS_WR_PONG_ADDR 0x0000011C +#define VFE_BUS_STATS_RS_UB_CFG 0x00000120 + +#define VFE_BUS_STATS_CS_WR_PING_ADDR 0x00000124 +#define VFE_BUS_STATS_CS_WR_PONG_ADDR 0x00000128 +#define VFE_BUS_STATS_CS_UB_CFG 0x0000012C +#define VFE_BUS_STATS_HIST_WR_PING_ADDR 0x00000130 +#define VFE_BUS_STATS_HIST_WR_PONG_ADDR 0x00000134 +#define VFE_BUS_STATS_HIST_UB_CFG 0x00000138 +#define VFE_BUS_STATS_SKIN_WR_PING_ADDR 0x0000013C +#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR 0x00000140 +#define VFE_BUS_STATS_SKIN_UB_CFG 0x00000144 +#define VFE_BUS_PM_CMD 0x00000188 +#define VFE_BUS_PM_CFG 0x0000018C +#define VFE_CAMIF_COMMAND 0x000001E0 +#define VFE_CAMIF_STATUS 0x00000204 +#define VFE_REG_UPDATE_CMD 0x00000260 +#define VFE_DEMUX_GAIN_0 0x00000288 +#define VFE_DEMUX_GAIN_1 0x0000028C +#define VFE_CHROMA_UP 0x0000035C +#define VFE_FRAMEDROP_ENC_Y_CFG 0x00000504 +#define VFE_FRAMEDROP_ENC_CBCR_CFG 0x00000508 +#define VFE_FRAMEDROP_ENC_Y_PATTERN 0x0000050C +#define VFE_FRAMEDROP_ENC_CBCR_PATTERN 0x00000510 +#define VFE_FRAMEDROP_VIEW_Y 0x00000514 +#define VFE_FRAMEDROP_VIEW_CBCR 0x00000518 +#define VFE_FRAMEDROP_VIEW_Y_PATTERN 0x0000051C +#define VFE_FRAMEDROP_VIEW_CBCR_PATTERN 0x00000520 +#define VFE_CLAMP_MAX 0x00000524 +#define VFE_CLAMP_MIN 0x00000528 +#define VFE_REALIGN_BUF 0x0000052C +#define VFE_STATS_CFG 0x00000530 +#define VFE_STATS_AWB_SGW_CFG 0x00000554 +#define VFE_DMI_CFG 0x00000598 +#define VFE_DMI_ADDR 0x0000059C +#define VFE_DMI_DATA_LO 0x000005A4 +#define VFE_AXI_CFG 0x00000600 + +struct vfe_stats_control { + uint8_t ackPending; + uint32_t nextFrameAddrBuf; + uint32_t droppedStatsFrameCount; + uint32_t bufToRender; +}; + +struct vfe31_ctrl_type { + uint16_t operation_mode; /* streaming or snapshot */ + struct vfe31_output_path outpath; + + uint32_t vfeImaskCompositePacked; + + spinlock_t update_ack_lock; + spinlock_t io_lock; + + int8_t aec_ack_pending; + int8_t awb_ack_pending; + int8_t af_ack_pending; + int8_t ihist_ack_pending; + int8_t rs_ack_pending; + int8_t cs_ack_pending; + + struct msm_vfe_callback *resp; + uint32_t extlen; + void *extdata; + + int8_t start_ack_pending; + atomic_t stop_ack_pending; + int8_t reset_ack_pending; + int8_t update_ack_pending; + enum vfe_recording_state recording_state; + int8_t output0_available; + int8_t output1_available; + int8_t update_gamma; + int8_t update_luma; + spinlock_t tasklet_lock; + struct list_head tasklet_q; + int vfeirq; + void __iomem *vfebase; + void *syncdata; + + struct resource *vfemem; + struct resource *vfeio; + + uint32_t stats_comp; + uint32_t hfr_mode; + atomic_t vstate; + uint32_t vfe_capture_count; + uint32_t sync_timer_repeat_count; + uint32_t sync_timer_state; + uint32_t sync_timer_number; + + uint32_t vfeFrameId; + uint32_t output1Pattern; + uint32_t output1Period; + uint32_t output2Pattern; + uint32_t output2Period; + uint32_t vfeFrameSkipCount; + uint32_t vfeFrameSkipPeriod; + uint32_t status_bits; + struct vfe_stats_control afStatsControl; + struct vfe_stats_control awbStatsControl; + struct vfe_stats_control aecStatsControl; + struct vfe_stats_control ihistStatsControl; + struct vfe_stats_control rsStatsControl; + struct vfe_stats_control csStatsControl; + struct msm_camera_sensor_info *s_info; + struct vfe_message vMsgHold_Snap; + struct vfe_message vMsgHold_Thumb; + int8_t xbar_update_pending; + uint32_t xbar_cfg[2]; + spinlock_t xbar_lock; + uint32_t while_stopping_mask; +}; + +#define statsAeNum 0 +#define statsAfNum 1 +#define statsAwbNum 2 +#define statsRsNum 3 +#define statsCsNum 4 +#define statsIhistNum 5 +#define statsSkinNum 6 + +struct vfe_cmd_stats_ack{ + uint32_t nextStatsBuf; +}; + +#define VFE_STATS_BUFFER_COUNT 3 + +struct vfe_cmd_stats_buf{ + uint32_t statsBuf[VFE_STATS_BUFFER_COUNT]; +}; +#endif /* __MSM_VFE31_H__ */ diff --git a/drivers/media/video/msm_zsl/msm_vfe32.c b/drivers/media/video/msm_zsl/msm_vfe32.c new file mode 100755 index 00000000000..15525f5f8ab --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe32.c @@ -0,0 +1,4277 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "msm.h" +#include "msm_vfe32.h" +#include "msm_ispif.h" /*aswoogi_zsl */ + +atomic_t irq_cnt; + +#define QC_TEST + +#define CHECKED_COPY_FROM_USER(in) { \ + if (copy_from_user((in), (void __user *)cmd->value, \ + cmd->length)) { \ + rc = -EFAULT; \ + break; \ + } \ +} + +#define VFE32_AXI_OFFSET 0x0050 +#define vfe32_get_ch_ping_addr(chn) \ + (msm_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn))) +#define vfe32_get_ch_pong_addr(chn) \ + (msm_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4)) +#define vfe32_get_ch_addr(ping_pong, chn) \ + (((ping_pong) & (1 << (chn))) == 0 ? \ + vfe32_get_ch_pong_addr(chn) : vfe32_get_ch_ping_addr(chn)) + +#define vfe32_put_ch_ping_addr(chn, addr) \ + (msm_io_w((addr), vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn))) +#define vfe32_put_ch_pong_addr(chn, addr) \ + (msm_io_w((addr), vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4)) +#define vfe32_put_ch_addr(ping_pong, chn, addr) \ + (((ping_pong) & (1 << (chn))) == 0 ? \ + vfe32_put_ch_pong_addr((chn), (addr)) : \ + vfe32_put_ch_ping_addr((chn), (addr))) + +static struct vfe32_ctrl_type *vfe32_ctrl; +static void *vfe_syncdata; +static uint32_t vfe_clk_rate; + +struct vfe32_isr_queue_cmd { + struct list_head list; + uint32_t vfeInterruptStatus0; + uint32_t vfeInterruptStatus1; +}; + +static struct vfe32_cmd_type vfe32_cmd[] = { +/* 0*/ {VFE_CMD_DUMMY_0}, + {VFE_CMD_SET_CLK}, + {VFE_CMD_RESET}, + {VFE_CMD_START}, + {VFE_CMD_TEST_GEN_START}, +/* 5*/ {VFE_CMD_OPERATION_CFG, V32_OPERATION_CFG_LEN}, + {VFE_CMD_AXI_OUT_CFG, V32_AXI_OUT_LEN, V32_AXI_OUT_OFF, 0xFF}, + {VFE_CMD_CAMIF_CFG, V32_CAMIF_LEN, V32_CAMIF_OFF, 0xFF}, + {VFE_CMD_AXI_INPUT_CFG}, + {VFE_CMD_BLACK_LEVEL_CFG, V32_BLACK_LEVEL_LEN, + V32_BLACK_LEVEL_OFF, + 0xFF}, +/*10*/ {VFE_CMD_MESH_ROLL_OFF_CFG, V32_MESH_ROLL_OFF_CFG_LEN, + V32_MESH_ROLL_OFF_CFG_OFF, 0xFF}, + {VFE_CMD_DEMUX_CFG, V32_DEMUX_LEN, V32_DEMUX_OFF, 0xFF}, + {VFE_CMD_FOV_CFG, V32_FOV_LEN, V32_FOV_OFF, 0xFF}, + {VFE_CMD_MAIN_SCALER_CFG, V32_MAIN_SCALER_LEN, + V32_MAIN_SCALER_OFF, 0xFF}, + {VFE_CMD_WB_CFG, V32_WB_LEN, V32_WB_OFF, 0xFF}, +/*15*/ {VFE_CMD_COLOR_COR_CFG, V32_COLOR_COR_LEN, V32_COLOR_COR_OFF, + 0xFF}, + {VFE_CMD_RGB_G_CFG, V32_RGB_G_LEN, V32_RGB_G_OFF, 0xFF}, + {VFE_CMD_LA_CFG, V32_LA_LEN, V32_LA_OFF, 0xFF}, + {VFE_CMD_CHROMA_EN_CFG, V32_CHROMA_EN_LEN, V32_CHROMA_EN_OFF, + 0xFF}, + {VFE_CMD_CHROMA_SUP_CFG, V32_CHROMA_SUP_LEN, V32_CHROMA_SUP_OFF, + 0xFF}, +/*20*/ {VFE_CMD_MCE_CFG, V32_MCE_LEN, V32_MCE_OFF, 0xFF}, + {VFE_CMD_SK_ENHAN_CFG, V32_SCE_LEN, V32_SCE_OFF, 0xFF}, + {VFE_CMD_ASF_CFG, V32_ASF_LEN, V32_ASF_OFF, 0xFF}, + {VFE_CMD_S2Y_CFG, V32_S2Y_LEN, V32_S2Y_OFF, 0xFF}, + {VFE_CMD_S2CbCr_CFG, V32_S2CbCr_LEN, V32_S2CbCr_OFF, 0xFF}, +/*25*/ {VFE_CMD_CHROMA_SUBS_CFG, V32_CHROMA_SUBS_LEN, + V32_CHROMA_SUBS_OFF, + 0xFF}, + {VFE_CMD_OUT_CLAMP_CFG, V32_OUT_CLAMP_LEN, V32_OUT_CLAMP_OFF, + 0xFF}, + {VFE_CMD_FRAME_SKIP_CFG, V32_FRAME_SKIP_LEN, V32_FRAME_SKIP_OFF, + 0xFF}, + {VFE_CMD_DUMMY_1}, + {VFE_CMD_DUMMY_2}, +/*30*/ {VFE_CMD_DUMMY_3}, + {VFE_CMD_UPDATE}, + {VFE_CMD_BL_LVL_UPDATE, V32_BLACK_LEVEL_LEN, + V32_BLACK_LEVEL_OFF, 0xFF}, + {VFE_CMD_DEMUX_UPDATE, V32_DEMUX_LEN, V32_DEMUX_OFF, 0xFF}, + {VFE_CMD_FOV_UPDATE, V32_FOV_LEN, V32_FOV_OFF, 0xFF}, +/*35*/ {VFE_CMD_MAIN_SCALER_UPDATE, V32_MAIN_SCALER_LEN, + V32_MAIN_SCALER_OFF, + 0xFF}, + {VFE_CMD_WB_UPDATE, V32_WB_LEN, V32_WB_OFF, 0xFF}, + {VFE_CMD_COLOR_COR_UPDATE, V32_COLOR_COR_LEN, V32_COLOR_COR_OFF, + 0xFF}, + {VFE_CMD_RGB_G_UPDATE, V32_RGB_G_LEN, V32_CHROMA_EN_OFF, 0xFF}, + {VFE_CMD_LA_UPDATE, V32_LA_LEN, V32_LA_OFF, 0xFF}, +/*40*/ {VFE_CMD_CHROMA_EN_UPDATE, V32_CHROMA_EN_LEN, V32_CHROMA_EN_OFF, + 0xFF}, + {VFE_CMD_CHROMA_SUP_UPDATE, V32_CHROMA_SUP_LEN, + V32_CHROMA_SUP_OFF, 0xFF}, + {VFE_CMD_MCE_UPDATE, V32_MCE_LEN, V32_MCE_OFF, 0xFF}, + {VFE_CMD_SK_ENHAN_UPDATE, V32_SCE_LEN, V32_SCE_OFF, 0xFF}, + {VFE_CMD_S2CbCr_UPDATE, V32_S2CbCr_LEN, V32_S2CbCr_OFF, 0xFF}, +/*45*/ {VFE_CMD_S2Y_UPDATE, V32_S2Y_LEN, V32_S2Y_OFF, 0xFF}, + {VFE_CMD_ASF_UPDATE, V32_ASF_UPDATE_LEN, V32_ASF_OFF, 0xFF}, + {VFE_CMD_FRAME_SKIP_UPDATE}, + {VFE_CMD_CAMIF_FRAME_UPDATE}, + {VFE_CMD_STATS_AF_UPDATE, V32_STATS_AF_LEN, V32_STATS_AF_OFF}, +/*50*/ {VFE_CMD_STATS_AE_UPDATE, V32_STATS_AE_LEN, V32_STATS_AE_OFF}, + {VFE_CMD_STATS_AWB_UPDATE, V32_STATS_AWB_LEN, + V32_STATS_AWB_OFF}, + {VFE_CMD_STATS_RS_UPDATE, V32_STATS_RS_LEN, V32_STATS_RS_OFF}, + {VFE_CMD_STATS_CS_UPDATE, V32_STATS_CS_LEN, V32_STATS_CS_OFF}, + {VFE_CMD_STATS_SKIN_UPDATE}, +/*55*/ {VFE_CMD_STATS_IHIST_UPDATE, V32_STATS_IHIST_LEN, + V32_STATS_IHIST_OFF}, + {VFE_CMD_DUMMY_4}, + {VFE_CMD_EPOCH1_ACK}, + {VFE_CMD_EPOCH2_ACK}, + {VFE_CMD_START_RECORDING}, +/*60*/ {VFE_CMD_STOP_RECORDING}, + {VFE_CMD_DUMMY_5}, + {VFE_CMD_DUMMY_6}, + {VFE_CMD_CAPTURE, V32_CAPTURE_LEN, 0xFF}, + {VFE_CMD_DUMMY_7}, +/*65*/ {VFE_CMD_STOP}, + {VFE_CMD_GET_HW_VERSION, V32_GET_HW_VERSION_LEN, + V32_GET_HW_VERSION_OFF}, + {VFE_CMD_GET_FRAME_SKIP_COUNTS}, + {VFE_CMD_OUTPUT1_BUFFER_ENQ}, + {VFE_CMD_OUTPUT2_BUFFER_ENQ}, +/*70*/ {VFE_CMD_OUTPUT3_BUFFER_ENQ}, + {VFE_CMD_JPEG_OUT_BUF_ENQ}, + {VFE_CMD_RAW_OUT_BUF_ENQ}, + {VFE_CMD_RAW_IN_BUF_ENQ}, + {VFE_CMD_STATS_AF_ENQ}, +/*75*/ {VFE_CMD_STATS_AE_ENQ}, + {VFE_CMD_STATS_AWB_ENQ}, + {VFE_CMD_STATS_RS_ENQ}, + {VFE_CMD_STATS_CS_ENQ}, + {VFE_CMD_STATS_SKIN_ENQ}, +/*80*/ {VFE_CMD_STATS_IHIST_ENQ}, + {VFE_CMD_DUMMY_8}, + {VFE_CMD_JPEG_ENC_CFG}, + {VFE_CMD_DUMMY_9}, + {VFE_CMD_STATS_AF_START, V32_STATS_AF_LEN, V32_STATS_AF_OFF}, +/*85*/ {VFE_CMD_STATS_AF_STOP}, + {VFE_CMD_STATS_AE_START, V32_STATS_AE_LEN, V32_STATS_AE_OFF}, + {VFE_CMD_STATS_AE_STOP}, + {VFE_CMD_STATS_AWB_START, V32_STATS_AWB_LEN, V32_STATS_AWB_OFF}, + {VFE_CMD_STATS_AWB_STOP}, +/*90*/ {VFE_CMD_STATS_RS_START, V32_STATS_RS_LEN, V32_STATS_RS_OFF}, + {VFE_CMD_STATS_RS_STOP}, + {VFE_CMD_STATS_CS_START, V32_STATS_CS_LEN, V32_STATS_CS_OFF}, + {VFE_CMD_STATS_CS_STOP}, + {VFE_CMD_STATS_SKIN_START}, +/*95*/ {VFE_CMD_STATS_SKIN_STOP}, + {VFE_CMD_STATS_IHIST_START, + V32_STATS_IHIST_LEN, V32_STATS_IHIST_OFF}, + {VFE_CMD_STATS_IHIST_STOP}, + {VFE_CMD_DUMMY_10}, + {VFE_CMD_SYNC_TIMER_SETTING, V32_SYNC_TIMER_LEN, + V32_SYNC_TIMER_OFF}, +/*100*/ {VFE_CMD_ASYNC_TIMER_SETTING, V32_ASYNC_TIMER_LEN, + V32_ASYNC_TIMER_OFF}, + {VFE_CMD_LIVESHOT}, + {VFE_CMD_LA_SETUP}, + {VFE_CMD_LINEARIZATION_CFG, V32_LINEARIZATION_LEN1, + V32_LINEARIZATION_OFF1}, + {VFE_CMD_DEMOSAICV3}, +/*105*/ {VFE_CMD_DEMOSAICV3_ABCC_CFG}, + {VFE_CMD_DEMOSAICV3_DBCC_CFG, V32_DEMOSAICV3_DBCC_LEN, + V32_DEMOSAICV3_DBCC_OFF}, + {VFE_CMD_DEMOSAICV3_DBPC_CFG}, + {VFE_CMD_DEMOSAICV3_ABF_CFG, V32_DEMOSAICV3_ABF_LEN, + V32_DEMOSAICV3_ABF_OFF}, + {VFE_CMD_DEMOSAICV3_ABCC_UPDATE}, +/*110*/ {VFE_CMD_DEMOSAICV3_DBCC_UPDATE, V32_DEMOSAICV3_DBCC_LEN, + V32_DEMOSAICV3_DBCC_OFF}, + {VFE_CMD_DEMOSAICV3_DBPC_UPDATE}, + {VFE_CMD_XBAR_CFG}, + {VFE_CMD_MODULE_CFG, V32_MODULE_CFG_LEN, V32_MODULE_CFG_OFF}, + {VFE_CMD_ZSL}, +/*115*/ {VFE_CMD_LINEARIZATION_UPDATE, V32_LINEARIZATION_LEN1, + V32_LINEARIZATION_OFF1}, + {VFE_CMD_DEMOSAICV3_ABF_UPDATE, V32_DEMOSAICV3_ABF_LEN, + V32_DEMOSAICV3_ABF_OFF}, + {VFE_CMD_CLF_CFG, V32_CLF_CFG_LEN, V32_CLF_CFG_OFF}, + {VFE_CMD_CLF_LUMA_UPDATE, V32_CLF_LUMA_UPDATE_LEN, + V32_CLF_LUMA_UPDATE_OFF}, + {VFE_CMD_CLF_CHROMA_UPDATE, V32_CLF_CHROMA_UPDATE_LEN, + V32_CLF_CHROMA_UPDATE_OFF}, +/*120*/ {VFE_CMD_PCA_ROLL_OFF_CFG}, + {VFE_CMD_PCA_ROLL_OFF_UPDATE}, + {VFE_CMD_GET_REG_DUMP}, + {VFE_CMD_GET_LINEARIZATON_TABLE}, + {VFE_CMD_GET_MESH_ROLLOFF_TABLE}, +/*125*/ {VFE_CMD_GET_PCA_ROLLOFF_TABLE}, + {VFE_CMD_GET_RGB_G_TABLE}, + {VFE_CMD_GET_LA_TABLE}, + {VFE_CMD_DEMOSAICV3_UPDATE}, +}; + +uint32_t vfe32_AXI_WM_CFG[] = { + 0x0000004C, + 0x00000064, + 0x0000007C, + 0x00000094, + 0x000000AC, + 0x000000C4, + 0x000000DC, +}; + +static const char *const vfe32_general_cmd[] = { + "DUMMY_0", /* 0 */ + "SET_CLK", + "RESET", + "START", + "TEST_GEN_START", + "OPERATION_CFG", /* 5 */ + "AXI_OUT_CFG", + "CAMIF_CFG", + "AXI_INPUT_CFG", + "BLACK_LEVEL_CFG", + "ROLL_OFF_CFG", /* 10 */ + "DEMUX_CFG", + "FOV_CFG", + "MAIN_SCALER_CFG", + "WB_CFG", + "COLOR_COR_CFG", /* 15 */ + "RGB_G_CFG", + "LA_CFG", + "CHROMA_EN_CFG", + "CHROMA_SUP_CFG", + "MCE_CFG", /* 20 */ + "SK_ENHAN_CFG", + "ASF_CFG", + "S2Y_CFG", + "S2CbCr_CFG", + "CHROMA_SUBS_CFG", /* 25 */ + "OUT_CLAMP_CFG", + "FRAME_SKIP_CFG", + "DUMMY_1", + "DUMMY_2", + "DUMMY_3", /* 30 */ + "UPDATE", + "BL_LVL_UPDATE", + "DEMUX_UPDATE", + "FOV_UPDATE", + "MAIN_SCALER_UPDATE", /* 35 */ + "WB_UPDATE", + "COLOR_COR_UPDATE", + "RGB_G_UPDATE", + "LA_UPDATE", + "CHROMA_EN_UPDATE", /* 40 */ + "CHROMA_SUP_UPDATE", + "MCE_UPDATE", + "SK_ENHAN_UPDATE", + "S2CbCr_UPDATE", + "S2Y_UPDATE", /* 45 */ + "ASF_UPDATE", + "FRAME_SKIP_UPDATE", + "CAMIF_FRAME_UPDATE", + "STATS_AF_UPDATE", + "STATS_AE_UPDATE", /* 50 */ + "STATS_AWB_UPDATE", + "STATS_RS_UPDATE", + "STATS_CS_UPDATE", + "STATS_SKIN_UPDATE", + "STATS_IHIST_UPDATE", /* 55 */ + "DUMMY_4", + "EPOCH1_ACK", + "EPOCH2_ACK", + "START_RECORDING", + "STOP_RECORDING", /* 60 */ + "DUMMY_5", + "DUMMY_6", + "CAPTURE", + "DUMMY_7", + "STOP", /* 65 */ + "GET_HW_VERSION", + "GET_FRAME_SKIP_COUNTS", + "OUTPUT1_BUFFER_ENQ", + "OUTPUT2_BUFFER_ENQ", + "OUTPUT3_BUFFER_ENQ", /* 70 */ + "JPEG_OUT_BUF_ENQ", + "RAW_OUT_BUF_ENQ", + "RAW_IN_BUF_ENQ", + "STATS_AF_ENQ", + "STATS_AE_ENQ", /* 75 */ + "STATS_AWB_ENQ", + "STATS_RS_ENQ", + "STATS_CS_ENQ", + "STATS_SKIN_ENQ", + "STATS_IHIST_ENQ", /* 80 */ + "DUMMY_8", + "JPEG_ENC_CFG", + "DUMMY_9", + "STATS_AF_START", + "STATS_AF_STOP", /* 85 */ + "STATS_AE_START", + "STATS_AE_STOP", + "STATS_AWB_START", + "STATS_AWB_STOP", + "STATS_RS_START", /* 90 */ + "STATS_RS_STOP", + "STATS_CS_START", + "STATS_CS_STOP", + "STATS_SKIN_START", + "STATS_SKIN_STOP", /* 95 */ + "STATS_IHIST_START", + "STATS_IHIST_STOP", + "DUMMY_10", + "SYNC_TIMER_SETTING", + "ASYNC_TIMER_SETTING", /* 100 */ + "LIVESHOT", + "LA_SETUP", + "LINEARIZATION_CFG", + "DEMOSAICV3", + "DEMOSAICV3_ABCC_CFG", /* 105 */ + "DEMOSAICV3_DBCC_CFG", + "DEMOSAICV3_DBPC_CFG", + "DEMOSAICV3_ABF_CFG", + "DEMOSAICV3_ABCC_UPDATE", + "DEMOSAICV3_DBCC_UPDATE", /* 110 */ + "DEMOSAICV3_DBPC_UPDATE", + "XBAR_CFG", + "EZTUNE_CFG", + "V32_ZSL", + "LINEARIZATION_UPDATE", /*115 */ + "DEMOSAICV3_ABF_UPDATE", + "CLF_CFG", + "CLF_LUMA_UPDATE", + "CLF_CHROMA_UPDATE", + "PCA_ROLL_OFF_CFG", /*120 */ + "PCA_ROLL_OFF_UPDATE", + "GET_REG_DUMP", + "GET_LINEARIZATON_TABLE", + "GET_MESH_ROLLOFF_TABLE", + "GET_PCA_ROLLOFF_TABLE", /*125 */ + "GET_RGB_G_TABLE", + "GET_LA_TABLE", + "DEMOSAICV3_UPDATE", +}; + +static void vfe32_stop(void) +{ + uint8_t axiBusyFlag = true; + unsigned long flags; + + atomic_set(&vfe32_ctrl->vstate, 0); + + /* for reset hw modules, and send msg when reset_irq comes. */ + spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags); + vfe32_ctrl->stop_ack_pending = TRUE; + spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags); + + /* disable all interrupts. */ + msm_io_w(VFE_DISABLE_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_io_w(VFE_DISABLE_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* clear all pending interrupts */ + msm_io_w(VFE_CLEAR_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_io_w(VFE_CLEAR_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_1); + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_IRQ_CMD); + + /* in either continuous or snapshot mode, stop command can be issued + * at any time. stop camif immediately. */ + msm_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY, + vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND); +/*[[ aswoogi_zsl*/ + v4l2_subdev_notify(&vfe32_ctrl->subdev, + NOTIFY_ISPIF_STREAM, + (void *)ISPIF_STREAM(RDI_0 | RDI_1 | PIX_0, + ISPIF_OFF_IMMEDIATELY)); + /*v4l2_subdev_notify(&vfe32_ctrl->subdev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + RDI_1, ISPIF_OFF_IMMEDIATELY)); + v4l2_subdev_notify(&vfe32_ctrl->subdev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX_0, ISPIF_OFF_IMMEDIATELY)); */ +/*]]*/ + /* axi halt command. */ + msm_io_w(AXI_HALT, vfe32_ctrl->vfebase + VFE_AXI_CMD); + wmb(); + while (axiBusyFlag) { + if (msm_io_r(vfe32_ctrl->vfebase + VFE_AXI_STATUS) & 0x1) + axiBusyFlag = false; + } + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(AXI_HALT_CLEAR, vfe32_ctrl->vfebase + VFE_AXI_CMD); + + /* after axi halt, then ok to apply global reset. */ + /* enable reset_ack and async timer interrupt only while + stopping the pipeline. */ + msm_io_w(0xf0000000, vfe32_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_io_w(VFE_IMASK_WHILE_STOPPING_1, + vfe32_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(VFE_RESET_UPON_STOP_CMD, + vfe32_ctrl->vfebase + VFE_GLOBAL_RESET); +} + +static void vfe32_subdev_notify(int id, int path) +{ + struct msm_vfe_resp rp; + unsigned long flags = 0; + spin_lock_irqsave(&vfe32_ctrl->sd_notify_lock, flags); + CDBG("vfe32_subdev_notify : msgId = %d\n", id); + memset(&rp, 0, sizeof(struct msm_vfe_resp)); + rp.evt_msg.type = MSM_CAMERA_MSG; + rp.evt_msg.msg_id = path; + rp.type = id; + v4l2_subdev_notify(&vfe32_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp); + spin_unlock_irqrestore(&vfe32_ctrl->sd_notify_lock, flags); +} + +static int vfe32_config_axi(int mode, uint32_t *ao) +{ + int32_t *ch_info; + + /* Update the corresponding write masters for each output */ + ch_info = ao + V32_AXI_CFG_LEN; + vfe32_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info; + vfe32_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16); + vfe32_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++; + vfe32_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info; + vfe32_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16); + vfe32_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++; + vfe32_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info; + vfe32_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16); + vfe32_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++; + vfe32_ctrl->outpath.out3.ch0 = 0x0000FFFF & *ch_info; + vfe32_ctrl->outpath.out3.ch1 = 0x0000FFFF & (*ch_info++ >> 16); + vfe32_ctrl->outpath.out3.ch2 = 0x0000FFFF & *ch_info++; + + switch (mode) { + + case OUTPUT_2: + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_PT; + break; + + case OUTPUT_1_AND_2: + /* use wm0& 4 for thumbnail, wm1&5 for main image. */ + /* main image. */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_S; + /* thumbnail. */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_PT; + break; + + case OUTPUT_1_2_AND_3: + CDBG("%s: OUTPUT_ZSL", __func__); + /* use wm0& 4 for postview, wm1&5 for preview. */ + /* use wm2& 6 for main img */ + /* main image. */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_S; + /* preview. */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_P; + /* thumbnail. */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_T; + break; + + case OUTPUT_1_AND_3: + /* use wm0& 4 for preview, wm1&5 for video. */ + /* video */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_V; + /* preview */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_PT; + break; + case CAMIF_TO_AXI_VIA_OUTPUT_2: + /* use wm0 only */ + CDBG("config axi for raw snapshot.\n"); + vfe32_ctrl->outpath.out1.ch0 = 0; /* raw */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_S; + break; + case OUTPUT_ALL_CHNLS: + /* YV12 preview */ + vfe32_ctrl->outpath.output_mode |= + VFE32_OUTPUT_MODE_P_ALL_CHNLS; + /* video */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_V; + break; + case OUTPUT_ZSL_ALL_CHNLS: + CDBG("%s: OUTPUT_ZSL_ALL_CHNLS", __func__); + /* main image. */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_S; + /* preview. */ + vfe32_ctrl->outpath.output_mode |= + VFE32_OUTPUT_MODE_P_ALL_CHNLS; + /* thumbnail. */ + vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_T; + break; + default: + break; + } + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[VFE_CMD_AXI_OUT_CFG].offset, ao, + vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length - + V32_AXI_CH_INF_LEN); + return 0; +} + +static void vfe32_reset_internal_variables(void) +{ + unsigned long flags; + vfe32_ctrl->vfeImaskCompositePacked = 0; + /* state control variables */ + vfe32_ctrl->start_ack_pending = FALSE; + atomic_set(&irq_cnt, 0); + + spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags); + vfe32_ctrl->stop_ack_pending = FALSE; + spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags); + + vfe32_ctrl->reset_ack_pending = FALSE; + + spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags); + vfe32_ctrl->update_ack_pending = FALSE; + spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags); + + vfe32_ctrl->recording_state = VFE_REC_STATE_IDLE; + + atomic_set(&vfe32_ctrl->vstate, 0); + + /* 0 for continuous mode, 1 for snapshot mode */ + vfe32_ctrl->operation_mode = 0; + vfe32_ctrl->outpath.output_mode = 0; + vfe32_ctrl->vfe_capture_count = 0; + + /* this is unsigned 32 bit integer. */ + vfe32_ctrl->vfeFrameId = 0; + vfe32_ctrl->rdi0FrameId = 0; + vfe32_ctrl->rdi1FrameId = 0; + /* Stats control variables. */ + memset(&(vfe32_ctrl->afStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe32_ctrl->awbStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe32_ctrl->aecStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe32_ctrl->ihistStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe32_ctrl->rsStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe32_ctrl->csStatsControl), 0, + sizeof(struct vfe_stats_control)); + /* jpeg_soc flag */ + vfe32_ctrl->jpeg_soc = 0; +} + +static void vfe32_reset(void) +{ + vfe32_reset_internal_variables(); + /* disable all interrupts. vfeImaskLocal is also reset to 0 + * to begin with. */ + msm_io_w(VFE_DISABLE_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_MASK_0); + + msm_io_w(VFE_DISABLE_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* clear all pending interrupts */ + msm_io_w(VFE_CLEAR_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_io_w(VFE_CLEAR_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_IRQ_CMD); + + /* enable reset_ack interrupt. */ + msm_io_w(VFE_IMASK_WHILE_STOPPING_1, + vfe32_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset + * is done, hardware interrupt will be generated. VFE ist processes + * the interrupt to complete the function call. Note that the reset + * function is synchronous. */ + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(VFE_RESET_UPON_RESET_CMD, + vfe32_ctrl->vfebase + VFE_GLOBAL_RESET); +} + +/*[[ aswoogi_zsl*/ +void msm_io_dump2(void __iomem *addr, int size) +{ + char line_str[128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + CDBG("%s: %p %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size / 4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "%08x: ", (u32) p); + p_str += 10; + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + CDBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CDBG("%s\n", line_str); +} + +/*]]*/ +static int vfe32_operation_config(uint32_t *cmd) +{ + uint32_t *p = cmd; + + vfe32_ctrl->operation_mode = *p; + vfe32_ctrl->stats_comp = *(++p); + + msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_CFG); + msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_PIXEL_IF_CFG); + /*metadata aswoogi_zsl */ + msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_RDI_CFG0); + msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_REALIGN_BUF); + msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_CHROMA_UP); + msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_STATS_CFG); +/*[[ aswoogi_zsl*/ + CDBG("nishu operation config done\n"); + msm_io_dump2(vfe32_ctrl->vfebase + 0x6fc, 0x4); + msm_io_dump2(vfe32_ctrl->vfebase + 0x004c, 0x4); +/*]]*/ + return 0; +} + +static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); + vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR); + + vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); + + vfe32_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR); + + vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR); + + vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in) +{ + uint32_t *ptr = in->statsBuf; + uint32_t addr; + + addr = ptr[0]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR); + addr = ptr[1]; + msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR); + + vfe32_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2]; + return 0; +} + +#ifdef QC_TEST /*aswoogi_zsl */ +static void vfe32_start_common(uint16_t operation_mode) +{ + vfe32_ctrl->start_ack_pending = TRUE; + CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n", + vfe32_ctrl->operation_mode, vfe32_ctrl->outpath.output_mode); + msm_io_w(0x00EFE021, vfe32_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_io_w(VFE_IMASK_WHILE_STOPPING_1, + vfe32_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* test: Qualcomm */ +#ifndef QC_TEST + CDBG("Hardcoding some VFE registers\n"); + /*msm_io_w(0x02D20788, vfe32_ctrl->vfebase + 0x01EC); */ + + msm_io_setBits(vfe32_ctrl->vfebase, 0x004C, 0x2); + msm_io_setBits(vfe32_ctrl->vfebase, 0x00AC, 0x2); +#endif + + /* Ensure the write order while writing + to the command register using the barrier */ + CDBG("nishu vfe start coommon\n"); + msm_io_dump2(vfe32_ctrl->vfebase, vfe32_ctrl->register_total * 4); + if (operation_mode == VFE_MODE_OF_OPERATION_ZSL) { /*metadata */ + msm_io_dump2(vfe32_ctrl->vfebase, + vfe32_ctrl->register_total * 4); + msm_io_w_mb(7, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD); + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND); + v4l2_subdev_notify(&vfe32_ctrl->subdev, + NOTIFY_ISPIF_STREAM, + (void *)ISPIF_STREAM(PIX_0 | RDI_0 | RDI_1, + ISPIF_ON_FRAME_BOUNDARY)); + } else { + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD); + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND); + v4l2_subdev_notify(&vfe32_ctrl->subdev, + NOTIFY_ISPIF_STREAM, + (void *)ISPIF_STREAM(PIX_0, + ISPIF_ON_FRAME_BOUNDARY)); + } + atomic_set(&vfe32_ctrl->vstate, 1); +} +#else +static void vfe32_start_common(void) +{ + vfe32_ctrl->start_ack_pending = TRUE; + CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n", + vfe32_ctrl->operation_mode, vfe32_ctrl->outpath.output_mode); + msm_io_w(0x00EFE021, vfe32_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_io_w(VFE_IMASK_WHILE_STOPPING_1, + vfe32_ctrl->vfebase + VFE_IRQ_MASK_1); + + msm_io_dump(vfe32_ctrl->vfebase, vfe32_ctrl->register_total * 4); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD); + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND); + + atomic_set(&vfe32_ctrl->vstate, 1); +} +#endif + +static int vfe32_start_recording(void) +{ + msm_camio_set_perf_lvl(S_VIDEO); + vfe32_ctrl->recording_state = VFE_REC_STATE_START_REQUESTED; + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD); + return 0; +} + +static int vfe32_stop_recording(void) +{ + vfe32_ctrl->recording_state = VFE_REC_STATE_STOP_REQUESTED; + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD); + msm_camio_set_perf_lvl(S_PREVIEW); + return 0; +} + +static void vfe32_liveshot(void) +{ + struct msm_sync *p_sync = (struct msm_sync *)vfe_syncdata; + if (p_sync) + p_sync->liveshot_enabled = true; +} + +static int vfe32_zsl(void) +{ + uint32_t irq_comp_mask = 0; + /* capture command is valid for both idle and active state. */ + irq_comp_mask = msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + CDBG("%s:op mode %d O/P Mode %d\n", __func__, + vfe32_ctrl->operation_mode, vfe32_ctrl->outpath.output_mode); + if ((vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_ZSL)) { + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_P) { + irq_comp_mask |= + ((0x1 << vfe32_ctrl->outpath.out0.ch0) | + (0x1 << vfe32_ctrl->outpath.out0.ch1)); + } else if (vfe32_ctrl->outpath.output_mode & + VFE32_OUTPUT_MODE_P_ALL_CHNLS) { + pr_debug("%s Enabling all channels ", __func__); + irq_comp_mask |= (0x1 << vfe32_ctrl->outpath.out0.ch0 | + 0x1 << vfe32_ctrl->outpath.out0.ch1 | + 0x1 << vfe32_ctrl->outpath.out0.ch2); + } + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_V) { + irq_comp_mask |= + ((0x1 << (vfe32_ctrl->outpath.out3.ch0 + 16)) | + (0x1 << (vfe32_ctrl->outpath.out3.ch1 + 16))); + } +/*metadata*/ + if (vfe32_ctrl->jpeg_soc) { + if (vfe32_ctrl-> + outpath.output_mode & VFE32_OUTPUT_MODE_T) { + irq_comp_mask |= + (0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8)); + } + if (vfe32_ctrl-> + outpath.output_mode & VFE32_OUTPUT_MODE_S) { + irq_comp_mask |= + (0x1 << (vfe32_ctrl->outpath.out2.ch0 + 8)); + } + } else { + if (vfe32_ctrl-> + outpath.output_mode & VFE32_OUTPUT_MODE_T) { + irq_comp_mask |= + ((0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8)) + | (0x1 << + (vfe32_ctrl->outpath.out1.ch1 + 8))); + } + if (vfe32_ctrl-> + outpath.output_mode & VFE32_OUTPUT_MODE_S) { + irq_comp_mask |= + ((0x1 << (vfe32_ctrl->outpath.out2.ch0 + 8)) + | (0x1 << + (vfe32_ctrl->outpath.out2.ch1 + 8))); + } + } + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_P) { + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out0.ch0]); + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out0.ch1]); + } else if (vfe32_ctrl-> + outpath.output_mode & + VFE32_OUTPUT_MODE_P_ALL_CHNLS) { + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out0.ch0]); + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out0.ch1]); + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out0.ch2]); + } + /*concurrent metadata */ + if (vfe32_ctrl->jpeg_soc) { + if (vfe32_ctrl-> + outpath.output_mode & VFE32_OUTPUT_MODE_T) { + msm_io_w(3, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out1.ch0]); + + } + if (vfe32_ctrl-> + outpath.output_mode & VFE32_OUTPUT_MODE_S) { + msm_io_w(3, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out2.ch0]); + } + } else { + + if (vfe32_ctrl-> + outpath.output_mode & VFE32_OUTPUT_MODE_T) { + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out1.ch0]); + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out1.ch1]); + } + if (vfe32_ctrl-> + outpath.output_mode & VFE32_OUTPUT_MODE_S) { + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out2.ch0]); + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out2.ch1]); + } + } + + } + CDBG("nishu zsl composite irq mask = %x\n", irq_comp_mask); + /*irq_comp_mask &= 0x1FFFF4FF; *//* nishu good hack */ + /*irq_comp_mask &= 0x1FFFF3FF; */ + /* nishu hack : see how often thumbnail IRQs show up */ + + msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + +/* Test +msm_camio_set_perf_lvl(S_ZSL); +msleep(100); +*/ + +#ifdef QC_TEST /*aswoogi_zsl */ + vfe32_start_common(vfe32_ctrl->operation_mode); +#else + vfe32_start_common(); +#endif + + msm_camio_set_perf_lvl(S_ZSL); + CDBG("vfe32 zsl end\n"); + + msm_io_w(1, vfe32_ctrl->vfebase + 0x18C); + msm_io_w(1, vfe32_ctrl->vfebase + 0x188); + return 0; +} + +static int vfe32_capture(uint32_t num_frames_capture) +{ + uint32_t irq_comp_mask = 0; + struct msm_sync *p_sync = (struct msm_sync *)vfe_syncdata; + if (p_sync) { + p_sync->snap_count = num_frames_capture; + p_sync->thumb_count = num_frames_capture; + } + /* capture command is valid for both idle and active state. */ + vfe32_ctrl->outpath.out1.capture_cnt = num_frames_capture; + if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_SNAPSHOT) + vfe32_ctrl->outpath.out0.capture_cnt = num_frames_capture; + + vfe32_ctrl->vfe_capture_count = num_frames_capture; + irq_comp_mask = msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_SNAPSHOT) { + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PT) { + irq_comp_mask |= (0x1 << vfe32_ctrl->outpath.out0.ch0 | + 0x1 << vfe32_ctrl->outpath.out0.ch1); + } + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_S) { + irq_comp_mask |= + (0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8) | + 0x1 << (vfe32_ctrl->outpath.out1.ch1 + 8)); + } + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PT) { + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out0.ch0]); + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out0.ch1]); + } + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_S) { + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out1.ch0]); + msm_io_w(1, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out1.ch1]); + } + } else { /* this is raw snapshot mode. */ + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_S) { + irq_comp_mask |= + (0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8)); + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath. + out1.ch0]); +#ifdef QC_TEST /*aswoogi_zsl */ + msm_io_w(0x0000, vfe32_ctrl->vfebase + + VFE_BUS_IO_FORMAT_CFG);/*npandit */ +#else + msm_io_w(0x1000, vfe32_ctrl->vfebase + + VFE_BUS_IO_FORMAT_CFG); +#endif + } + } + msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK); + msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK); + msm_camio_set_perf_lvl(S_CAPTURE); +#ifdef QC_TEST /*aswoogi_zsl */ + vfe32_start_common(vfe32_ctrl->operation_mode); +#else + vfe32_start_common(); +#endif + msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK); + /* for debug */ + msm_io_w(1, vfe32_ctrl->vfebase + 0x18C); + msm_io_w(1, vfe32_ctrl->vfebase + 0x188); + return 0; +} + +static int vfe32_start(void) +{ + uint32_t irq_comp_mask = 0; + /* start command now is only good for continuous mode. */ + if ((vfe32_ctrl->operation_mode != VFE_MODE_OF_OPERATION_CONTINUOUS) && + (vfe32_ctrl->operation_mode != VFE_MODE_OF_OPERATION_VIDEO)) + return 0; + irq_comp_mask = msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PT) { + irq_comp_mask |= (0x1 << vfe32_ctrl->outpath.out0.ch0 | + 0x1 << vfe32_ctrl->outpath.out0.ch1); + } else if (vfe32_ctrl->outpath.output_mode & + VFE32_OUTPUT_MODE_P_ALL_CHNLS) { + pr_debug("%s Enabling all channels ", __func__); + irq_comp_mask |= (0x1 << vfe32_ctrl->outpath.out0.ch0 | + 0x1 << vfe32_ctrl->outpath.out0.ch1 | + 0x1 << vfe32_ctrl->outpath.out0.ch2); + } + + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_V) { + irq_comp_mask |= (0x1 << (vfe32_ctrl->outpath.out2.ch0 + 16) | + 0x1 << (vfe32_ctrl->outpath.out2.ch1 + 16)); + } + + msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PT) { + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]); + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]); + } else if (vfe32_ctrl->outpath.output_mode & + VFE32_OUTPUT_MODE_P_ALL_CHNLS) { + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]); + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]); + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch2]); + } + msm_camio_set_perf_lvl(S_PREVIEW); +#ifdef QC_TEST /*aswoogi_zsl */ + vfe32_start_common(vfe32_ctrl->operation_mode); +#else + vfe32_start_common(); +#endif + return 0; +} + +static void vfe32_update(void) +{ + unsigned long flags; + uint32_t value = 0; + if (vfe32_ctrl->update_linear) { + if (!msm_io_r(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1)) + msm_io_w(1, + vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1); + else + msm_io_w(0, + vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1); + vfe32_ctrl->update_linear = false; + } + + if (vfe32_ctrl->update_rolloff) { + value = msm_io_r(vfe32_ctrl->vfebase + + V33_PCA_ROLL_OFF_CFG_OFF1); + value ^= V33_PCA_ROLL_OFF_LUT_BANK_SEL_MASK; + msm_io_w(value, vfe32_ctrl->vfebase + + V33_PCA_ROLL_OFF_CFG_OFF1); + vfe32_ctrl->update_rolloff = false; + } + + if (vfe32_ctrl->update_la) { + if (!msm_io_r(vfe32_ctrl->vfebase + V32_LA_OFF)) + msm_io_w(1, vfe32_ctrl->vfebase + V32_LA_OFF); + else + msm_io_w(0, vfe32_ctrl->vfebase + V32_LA_OFF); + vfe32_ctrl->update_la = false; + } + + if (vfe32_ctrl->update_gamma) { + value = msm_io_r(vfe32_ctrl->vfebase + V32_RGB_G_OFF); + value ^= V32_GAMMA_LUT_BANK_SEL_MASK; + msm_io_w(value, vfe32_ctrl->vfebase + V32_RGB_G_OFF); + vfe32_ctrl->update_gamma = false; + } + + spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags); + vfe32_ctrl->update_ack_pending = TRUE; + spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags); + /* Ensure the write order while writing + to the command register using the barrier */ +#ifdef QC_TEST /*aswoogi_zsl */ + msm_io_w_mb(7, vfe32_ctrl->vfebase + + VFE_REG_UPDATE_CMD);/*nishu enabled for all 3 interfaces */ +#else + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD); +#endif + return; +} + +static void vfe32_sync_timer_stop(void) +{ + uint32_t value = 0; + vfe32_ctrl->sync_timer_state = 0; + if (vfe32_ctrl->sync_timer_number == 0) + value = 0x10000; + else if (vfe32_ctrl->sync_timer_number == 1) + value = 0x20000; + else if (vfe32_ctrl->sync_timer_number == 2) + value = 0x40000; + + /* Timer Stop */ + msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF); +} + +static void vfe32_sync_timer_start(const uint32_t *tbl) +{ + /* set bit 8 for auto increment. */ + uint32_t value = 1; + uint32_t val; + + vfe32_ctrl->sync_timer_state = *tbl++; + vfe32_ctrl->sync_timer_repeat_count = *tbl++; + vfe32_ctrl->sync_timer_number = *tbl++; + CDBG("%s timer_state %d, repeat_cnt %d timer number %d\n", + __func__, vfe32_ctrl->sync_timer_state, + vfe32_ctrl->sync_timer_repeat_count, + vfe32_ctrl->sync_timer_number); + + if (vfe32_ctrl->sync_timer_state) { /* Start Timer */ + value = value << vfe32_ctrl->sync_timer_number; + } else { /* Stop Timer */ + CDBG("Failed to Start timer\n"); + return; + } + + /* Timer Start */ + msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF); + /* Sync Timer Line Start */ + value = *tbl++; + msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF + + 4 + ((vfe32_ctrl->sync_timer_number) * 12)); + /* Sync Timer Pixel Start */ + value = *tbl++; + msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF + + 8 + ((vfe32_ctrl->sync_timer_number) * 12)); + /* + * temp code for capture: assigning hardcode value for + * 'vfe_clk_rate' to remove the error logs 'divide by zero + * in kernel' during image capture. vfe_clk_rate gets set + * inside msm_vfe_subdev_s_crystal_freq() which is not called + * anywhere as of now, and hence vfe_clk_rate contains value + * '0' causing "division by zero" error here + */ + /* Sync Timer Pixel Duration */ + value = *tbl++; + vfe_clk_rate = 228570000; + if (vfe_clk_rate == 0) + CDBG("nishu clock null\n"); + else + CDBG("nishu clock not null\n"); + val = vfe_clk_rate / 10000; + val = 10000000 / val; + val = value * 10000 / val; + CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val); + msm_io_w(val, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF + + 12 + ((vfe32_ctrl->sync_timer_number) * 12)); + /* Timer0 Active High/LOW */ + value = *tbl++; + msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_POLARITY_OFF); + /* Selects sync timer 0 output to drive onto timer1 port */ + value = 0; + msm_io_w(value, vfe32_ctrl->vfebase + V32_TIMER_SELECT_OFF); +} + +static void vfe32_program_dmi_cfg(enum VFE32_DMI_RAM_SEL bankSel) +{ + /* set bit 8 for auto increment. */ + uint32_t value = VFE_DMI_CFG_DEFAULT; + value += (uint32_t) bankSel; + CDBG("%s: banksel = %d\n", __func__, bankSel); + + msm_io_w(value, vfe32_ctrl->vfebase + VFE_DMI_CFG); + /* by default, always starts with offset 0. */ + msm_io_w(0, vfe32_ctrl->vfebase + VFE_DMI_ADDR); +} + +static void vfe32_write_gamma_cfg(enum VFE32_DMI_RAM_SEL channel_sel, + const uint32_t *tbl) +{ + int i; + uint32_t value, value1, value2; + vfe32_program_dmi_cfg(channel_sel); + for (i = 0; i < (VFE32_GAMMA_NUM_ENTRIES / 2); i++) { + value = *tbl++; + value1 = value & 0x0000FFFF; + value2 = (value & 0xFFFF0000) >> 16; + msm_io_w((value1), vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + msm_io_w((value2), vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + } + vfe32_program_dmi_cfg(NO_MEM_SELECTED); +} + +static void vfe32_read_gamma_cfg(enum VFE32_DMI_RAM_SEL channel_sel, + uint32_t *tbl) +{ + int i; + vfe32_program_dmi_cfg(channel_sel); + CDBG("%s: Gamma table channel: %d\n", __func__, channel_sel); + for (i = 0; i < VFE32_GAMMA_NUM_ENTRIES; i++) { + *tbl = msm_io_r(vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + CDBG("%s: %08x\n", __func__, *tbl); + tbl++; + } + vfe32_program_dmi_cfg(NO_MEM_SELECTED); +} + +static void vfe32_write_la_cfg(enum VFE32_DMI_RAM_SEL channel_sel, + const uint32_t *tbl) +{ + uint32_t i; + uint32_t value, value1, value2; + + vfe32_program_dmi_cfg(channel_sel); + for (i = 0; i < (VFE32_LA_TABLE_LENGTH / 2); i++) { + value = *tbl++; + value1 = value & 0x0000FFFF; + value2 = (value & 0xFFFF0000) >> 16; + msm_io_w((value1), vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + msm_io_w((value2), vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + } + vfe32_program_dmi_cfg(NO_MEM_SELECTED); +} + +static struct vfe32_output_ch *vfe32_get_ch(int path) +{ + struct vfe32_output_ch *ch = NULL; + + switch (vfe32_ctrl->operation_mode) { + case VFE_MODE_OF_OPERATION_CONTINUOUS: + if (path == VFE_MSG_OUTPUT_P) + ch = &vfe32_ctrl->outpath.out0; + break; + case VFE_MODE_OF_OPERATION_SNAPSHOT: + if (path == VFE_MSG_OUTPUT_T) + ch = &vfe32_ctrl->outpath.out0; + else if (path == VFE_MSG_OUTPUT_S) + ch = &vfe32_ctrl->outpath.out1; + break; + case VFE_MODE_OF_OPERATION_VIDEO: + if (path == VFE_MSG_OUTPUT_P) + ch = &vfe32_ctrl->outpath.out0; + else if (path == VFE_MSG_OUTPUT_V) + ch = &vfe32_ctrl->outpath.out2; + break; + case VFE_MODE_OF_OPERATION_RAW_SNAPSHOT: + if (path == VFE_MSG_OUTPUT_S) + ch = &vfe32_ctrl->outpath.out0; + break; + case VFE_MODE_OF_OPERATION_ZSL: + if (path == VFE_MSG_OUTPUT_P) + ch = &vfe32_ctrl->outpath.out0; + else if (path == VFE_MSG_OUTPUT_T) + ch = &vfe32_ctrl->outpath.out1; + else if (path == VFE_MSG_OUTPUT_S) + ch = &vfe32_ctrl->outpath.out2; + else if (path == VFE_MSG_OUTPUT_V) + ch = &vfe32_ctrl->outpath.out3; + break; + default: + pr_err("%s: Unsupported operation mode %d\n", __func__, + vfe32_ctrl->operation_mode); + } + + BUG_ON(ch == NULL); + return ch; +} + +static struct msm_free_buf *vfe32_check_free_buffer(int id, int path) +{ + struct vfe32_output_ch *outch = NULL; + struct msm_free_buf *b = NULL; + vfe32_subdev_notify(id, path); + outch = vfe32_get_ch(path); + if (outch->free_buf.ch_paddr[0]) + b = &outch->free_buf; + return b; +} + +static int vfe32_configure_pingpong_buffers(int id, int path) +{ + struct vfe32_output_ch *outch = NULL; + int rc = 0; + vfe32_subdev_notify(id, path); + outch = vfe32_get_ch(path); + if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) { + /* Configure Preview Ping Pong */ + CDBG("%s Configure ping/pong address for %d", + __func__, path); + vfe32_put_ch_ping_addr(outch->ch0, outch->ping.ch_paddr[0]); + vfe32_put_ch_pong_addr(outch->ch0, outch->pong.ch_paddr[0]); +#ifdef QC_TEST /*concurrent aswoogi_zsl */ + if (outch->ping.num_planes > 1) + vfe32_put_ch_ping_addr(outch->ch1, + outch->ping.ch_paddr[1]); + if (outch->pong.num_planes > 1) + vfe32_put_ch_pong_addr(outch->ch1, + outch->pong.ch_paddr[1]); +#else + + if (vfe32_ctrl->operation_mode != + VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) { + vfe32_put_ch_ping_addr(outch->ch1, + outch->ping.ch_paddr[1]); + vfe32_put_ch_pong_addr(outch->ch1, + outch->pong.ch_paddr[1]); + } +#endif + + if (outch->ping.num_planes > 2) + vfe32_put_ch_ping_addr(outch->ch2, + outch->ping.ch_paddr[2]); + if (outch->pong.num_planes > 2) + vfe32_put_ch_pong_addr(outch->ch2, + outch->pong.ch_paddr[2]); + + /* avoid stale info */ + memset(&outch->ping, 0, sizeof(struct msm_free_buf)); + memset(&outch->pong, 0, sizeof(struct msm_free_buf)); + } else { + pr_err("%s ping/pong addr is null!!", __func__); + rc = -EINVAL; + } + return rc; +} + +static void vfe32_write_linear_cfg(enum VFE32_DMI_RAM_SEL channel_sel, + const uint32_t *tbl) +{ + uint32_t i; + + vfe32_program_dmi_cfg(channel_sel); + /* for loop for configuring LUT. */ + for (i = 0; i < VFE32_LINEARIZATON_TABLE_LENGTH; i++) { + msm_io_w(*tbl, vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + tbl++; + } + CDBG("done writing to linearization table\n"); + vfe32_program_dmi_cfg(NO_MEM_SELECTED); +} + +static void vfe32_send_isp_msg(struct vfe32_ctrl_type *vctrl, + uint32_t isp_msg_id) +{ + struct isp_msg_event isp_msg_evt; + + isp_msg_evt.msg_id = isp_msg_id; + isp_msg_evt.sof_count = vfe32_ctrl->vfeFrameId; + v4l2_subdev_notify(&vctrl->subdev, + NOTIFY_ISP_MSG_EVT, (void *)&isp_msg_evt); +} + +static int vfe32_proc_general(struct msm_isp_cmd *cmd) +{ + int i, rc = 0; + uint32_t old_val = 0, new_val = 0; + uint32_t *cmdp = NULL; + uint32_t *cmdp_local = NULL; + uint32_t snapshot_cnt = 0; + uint32_t temp1 = 0, temp2 = 0; + + CDBG("vfe32_proc_general: cmdID = %s, length = %d\n", + vfe32_general_cmd[cmd->id], cmd->length); + + if (vfe32_ctrl->vfebase == NULL) { + pr_err("Error : vfe32_ctrl->vfebase is NULL!!\n"); + pr_err("vfe32_proc_general: cmdID = %s, length = %d\n", + vfe32_general_cmd[cmd->id], cmd->length); + rc = -EINVAL; + goto proc_general_done; + } + + switch (cmd->id) { + case VFE_CMD_RESET: + CDBG("vfe32_proc_general: cmdID = %s\n", + vfe32_general_cmd[cmd->id]); + vfe32_reset(); + break; + case VFE_CMD_START: + CDBG("vfe32_proc_general: cmdID = %s\n", + vfe32_general_cmd[cmd->id]); + rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_START, + VFE_MSG_OUTPUT_P); + if (rc < 0) { + pr_err("%s error configuring pingpong buffers" + " for preview", __func__); + rc = -EINVAL; + goto proc_general_done; + } + rc = vfe32_start(); + break; + case VFE_CMD_UPDATE: + vfe32_update(); + break; + case VFE_CMD_CAPTURE: + CDBG("vfe32_proc_general: cmdID = %s\n", + vfe32_general_cmd[cmd->id]); + if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value), + sizeof(uint32_t))) { + rc = -EFAULT; + goto proc_general_done; + } + rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_CAPTURE, + VFE_MSG_OUTPUT_S); + if (rc < 0) { + pr_err("%s error configuring pingpong buffers" + " for snapshot", __func__); + rc = -EINVAL; + goto proc_general_done; + } + if (vfe32_ctrl->operation_mode != + VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) { + rc = vfe32_configure_pingpong_buffers + (VFE_MSG_V32_CAPTURE, VFE_MSG_OUTPUT_T); + if (rc < 0) { + pr_err("%s error configuring pingpong buffers" + " for thumbnail", __func__); + rc = -EINVAL; + goto proc_general_done; + } + } + rc = vfe32_capture(snapshot_cnt); + break; + case VFE_CMD_START_RECORDING: + CDBG("vfe32_proc_general: cmdID = %s\n", + vfe32_general_cmd[cmd->id]); + rc = vfe32_configure_pingpong_buffers + (VFE_MSG_V32_START_RECORDING, VFE_MSG_OUTPUT_V); + if (rc < 0) { + pr_err("%s error configuring pingpong buffers" + " for video", __func__); + rc = -EINVAL; + goto proc_general_done; + } + rc = vfe32_start_recording(); + break; + case VFE_CMD_STOP_RECORDING: + CDBG("vfe32_proc_general: cmdID = %s\n", + vfe32_general_cmd[cmd->id]); + rc = vfe32_stop_recording(); + break; + case VFE_CMD_OPERATION_CFG:{ + if (cmd->length != V32_OPERATION_CFG_LEN) { + rc = -EINVAL; + /*aswoogi_zsl */ + pr_err("nishu operation config invalid command\n"); + goto proc_general_done; + } + cmdp = kmalloc(V32_OPERATION_CFG_LEN, GFP_ATOMIC); + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + V32_OPERATION_CFG_LEN)) { + rc = -EFAULT; + /*aswoogi_zsl */ + pr_err("nishu operation config fault\n"); + goto proc_general_done; + } + rc = vfe32_operation_config(cmdp); + } + break; + + case VFE_CMD_STATS_AE_START:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= AE_BG_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp, + (vfe32_cmd[cmd->id].length)); + } + break; + case VFE_CMD_STATS_AF_START:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= AF_BF_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp, + (vfe32_cmd[cmd->id].length)); + } + break; + case VFE_CMD_STATS_AWB_START:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= AWB_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp, + (vfe32_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_STATS_IHIST_START:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= IHIST_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp, + (vfe32_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_STATS_RS_START:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp, + (vfe32_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_STATS_CS_START:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp, + (vfe32_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_MCE_UPDATE: + case VFE_CMD_MCE_CFG:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + /* Incrementing with 4 so as to point to + the 2nd Register as + the 2nd register has the mce_enable bit */ + old_val = msm_io_r(vfe32_ctrl->vfebase + + V32_CHROMA_SUP_OFF + 4); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + old_val &= MCE_EN_MASK; + new_val = new_val | old_val; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + + 4, &new_val, 4); + cmdp_local += 1; + + old_val = msm_io_r(vfe32_ctrl->vfebase + + V32_CHROMA_SUP_OFF + 8); + new_val = *cmdp_local; + old_val &= MCE_Q_K_MASK; + new_val = new_val | old_val; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + + 8, &new_val, 4); + cmdp_local += 1; + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp_local, + (vfe32_cmd[cmd->id].length)); + } + break; + case VFE_CMD_CHROMA_SUP_UPDATE: + case VFE_CMD_CHROMA_SUP_CFG:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF, + cmdp_local, 4); + + cmdp_local += 1; + new_val = *cmdp_local; + /* Incrementing with 4 so as to point to + the 2nd Register as + * the 2nd register has the mce_enable bit + */ + old_val = msm_io_r(vfe32_ctrl->vfebase + + V32_CHROMA_SUP_OFF + 4); + old_val &= ~MCE_EN_MASK; + new_val = new_val | old_val; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + + 4, &new_val, 4); + cmdp_local += 1; + + old_val = msm_io_r(vfe32_ctrl->vfebase + + V32_CHROMA_SUP_OFF + 8); + new_val = *cmdp_local; + old_val &= ~MCE_Q_K_MASK; + new_val = new_val | old_val; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + + 8, &new_val, 4); + } + break; + case VFE_CMD_BLACK_LEVEL_CFG: + rc = -EFAULT; + goto proc_general_done; + + case VFE_CMD_MESH_ROLL_OFF_CFG:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp_local, + 16); + cmdp_local += 4; + vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0); + /* for loop for extrcting init table. */ + for (i = 0; i < (V32_MESH_ROLL_OFF_INIT_TABLE_SIZE * 2); + i++) { + msm_io_w(*cmdp_local, + vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + cmdp_local++; + } + CDBG("done writing init table\n"); + /* by default, always starts with offset 0. */ + msm_io_w(V32_MESH_ROLL_OFF_DELTA_TABLE_OFFSET, + vfe32_ctrl->vfebase + VFE_DMI_ADDR); + /* for loop for extracting delta table. */ + for (i = 0; + i < (V32_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2); + i++) { + msm_io_w(*cmdp_local, + vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + cmdp_local++; + } + vfe32_program_dmi_cfg(NO_MEM_SELECTED); + } + break; + + case VFE_CMD_GET_MESH_ROLLOFF_TABLE: + temp1 = sizeof(uint32_t) * ((V32_MESH_ROLL_OFF_INIT_TABLE_SIZE * + 2) + + (V32_MESH_ROLL_OFF_DELTA_TABLE_SIZE + * 2)); + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kzalloc(temp1, GFP_KERNEL); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + cmdp_local = cmdp; + vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0); + CDBG("%s: Mesh Rolloff init Table\n", __func__); + for (i = 0; i < (V32_MESH_ROLL_OFF_INIT_TABLE_SIZE * 2); i++) { + *cmdp_local = + msm_io_r(vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + CDBG("%s: %08x\n", __func__, *cmdp_local); + cmdp_local++; + } + msm_io_w(V32_MESH_ROLL_OFF_DELTA_TABLE_OFFSET, + vfe32_ctrl->vfebase + VFE_DMI_ADDR); + CDBG("%s: Mesh Rolloff Delta Table\n", __func__); + for (i = 0; i < (V32_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2); i++) { + *cmdp_local = + msm_io_r(vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + CDBG("%s: %08x\n", __func__, *cmdp_local); + cmdp_local++; + } + CDBG("done reading delta table\n"); + vfe32_program_dmi_cfg(NO_MEM_SELECTED); + if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + case VFE_CMD_LA_CFG: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), cmd->length)) { + + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset, + cmdp_local, (vfe32_cmd[cmd->id].length)); + + cmdp_local += 1; + vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0, cmdp_local); + break; + + case VFE_CMD_LA_UPDATE:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + + rc = -EFAULT; + goto proc_general_done; + } + + cmdp_local = cmdp + 1; + old_val = msm_io_r(vfe32_ctrl->vfebase + V32_LA_OFF); + if (old_val != 0x0) + vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0, + cmdp_local); + else + vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1, + cmdp_local); + } + vfe32_ctrl->update_la = true; + break; + + case VFE_CMD_GET_LA_TABLE: + temp1 = sizeof(uint32_t) * VFE32_LA_TABLE_LENGTH / 2; + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kzalloc(temp1, GFP_KERNEL); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + cmdp_local = cmdp; + if (msm_io_r(vfe32_ctrl->vfebase + V32_LA_OFF)) + vfe32_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK1); + else + vfe32_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK0); + for (i = 0; i < (VFE32_LA_TABLE_LENGTH / 2); i++) { + *cmdp_local = + msm_io_r(vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + *cmdp_local |= (msm_io_r(vfe32_ctrl->vfebase + + VFE_DMI_DATA_LO)) << 16; + cmdp_local++; + } + vfe32_program_dmi_cfg(NO_MEM_SELECTED); + if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + case VFE_CMD_SK_ENHAN_CFG: + case VFE_CMD_SK_ENHAN_UPDATE:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_io_memcpy(vfe32_ctrl->vfebase + V32_SCE_OFF, + cmdp, V32_SCE_LEN); + } + break; + + case VFE_CMD_LIVESHOT: + vfe32_liveshot(); + break; + + case VFE_CMD_LINEARIZATION_CFG: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1, + cmdp_local, V32_LINEARIZATION_LEN1); + cmdp_local += 4; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF2, + cmdp_local, V32_LINEARIZATION_LEN2); + + cmdp_local = cmdp + 17; + vfe32_write_linear_cfg(BLACK_LUT_RAM_BANK0, cmdp_local); + break; + + case VFE_CMD_LINEARIZATION_UPDATE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + cmdp_local++; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1 + 4, + cmdp_local, (V32_LINEARIZATION_LEN1 - 4)); + cmdp_local += 3; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF2, + cmdp_local, V32_LINEARIZATION_LEN2); + cmdp_local = cmdp + 17; + /*extracting the bank select */ + old_val = + msm_io_r(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1); + + if (old_val != 0x0) + vfe32_write_linear_cfg(BLACK_LUT_RAM_BANK0, cmdp_local); + else + vfe32_write_linear_cfg(BLACK_LUT_RAM_BANK1, cmdp_local); + vfe32_ctrl->update_linear = true; + break; + + case VFE_CMD_GET_LINEARIZATON_TABLE: + temp1 = sizeof(uint32_t) * VFE32_LINEARIZATON_TABLE_LENGTH; + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kzalloc(temp1, GFP_KERNEL); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + cmdp_local = cmdp; + if (msm_io_r(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1)) + vfe32_program_dmi_cfg(BLACK_LUT_RAM_BANK1); + else + vfe32_program_dmi_cfg(BLACK_LUT_RAM_BANK0); + CDBG("%s: Linearization Table\n", __func__); + for (i = 0; i < VFE32_LINEARIZATON_TABLE_LENGTH; i++) { + *cmdp_local = + msm_io_r(vfe32_ctrl->vfebase + VFE_DMI_DATA_LO); + CDBG("%s: %08x\n", __func__, *cmdp_local); + cmdp_local++; + } + vfe32_program_dmi_cfg(NO_MEM_SELECTED); + if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + case VFE_CMD_DEMOSAICV3: + if (cmd->length != V32_DEMOSAICV3_0_LEN + + V32_DEMOSAICV3_1_LEN) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_io_r(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF); + old_val &= DEMOSAIC_MASK; + new_val = new_val | old_val; + *cmdp_local = new_val; + + msm_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF, + cmdp_local, V32_DEMOSAICV3_0_LEN); + cmdp_local += 1; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_1_OFF, + cmdp_local, V32_DEMOSAICV3_1_LEN); + break; + + case VFE_CMD_DEMOSAICV3_UPDATE: + if (cmd->length != + V32_DEMOSAICV3_0_LEN * V32_DEMOSAICV3_UP_REG_CNT) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_io_r(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF); + old_val &= DEMOSAIC_MASK; + new_val = new_val | old_val; + *cmdp_local = new_val; + + msm_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF, + cmdp_local, V32_DEMOSAICV3_0_LEN); + /* As the address space is not contiguous increment by 2 + * before copying to next address space */ + cmdp_local += 1; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_1_OFF, + cmdp_local, 2 * V32_DEMOSAICV3_0_LEN); + /* As the address space is not contiguous increment by 2 + * before copying to next address space */ + cmdp_local += 2; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_2_OFF, + cmdp_local, 2 * V32_DEMOSAICV3_0_LEN); + break; + + case VFE_CMD_DEMOSAICV3_ABCC_CFG: + rc = -EFAULT; + break; + + case VFE_CMD_DEMOSAICV3_ABF_UPDATE: /* 116 ABF update */ + case VFE_CMD_DEMOSAICV3_ABF_CFG:{ + /* 108 ABF config */ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = + msm_io_r(vfe32_ctrl->vfebase + + V32_DEMOSAICV3_0_OFF); + old_val &= ABF_MASK; + new_val = new_val | old_val; + *cmdp_local = new_val; + + msm_io_memcpy(vfe32_ctrl->vfebase + + V32_DEMOSAICV3_0_OFF, cmdp_local, 4); + + cmdp_local += 1; + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp_local, + (vfe32_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_DEMOSAICV3_DBCC_CFG: + case VFE_CMD_DEMOSAICV3_DBCC_UPDATE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_io_r(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF); + old_val &= DBCC_MASK; + + new_val = new_val | old_val; + *cmdp_local = new_val; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF, + cmdp_local, 4); + cmdp_local += 1; + msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset, + cmdp_local, (vfe32_cmd[cmd->id].length)); + break; + + case VFE_CMD_DEMOSAICV3_DBPC_CFG: + case VFE_CMD_DEMOSAICV3_DBPC_UPDATE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_io_r(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF); + old_val &= DBPC_MASK; + + new_val = new_val | old_val; + *cmdp_local = new_val; + msm_io_memcpy(vfe32_ctrl->vfebase + + V32_DEMOSAICV3_0_OFF, + cmdp_local, V32_DEMOSAICV3_LEN); + cmdp_local += 1; + msm_io_memcpy(vfe32_ctrl->vfebase + + V32_DEMOSAICV3_DBPC_CFG_OFF, + cmdp_local, V32_DEMOSAICV3_DBPC_LEN); + cmdp_local += 1; + msm_io_memcpy(vfe32_ctrl->vfebase + + V32_DEMOSAICV3_DBPC_CFG_OFF0, + cmdp_local, V32_DEMOSAICV3_DBPC_LEN); + cmdp_local += 1; + msm_io_memcpy(vfe32_ctrl->vfebase + + V32_DEMOSAICV3_DBPC_CFG_OFF1, + cmdp_local, V32_DEMOSAICV3_DBPC_LEN); + cmdp_local += 1; + msm_io_memcpy(vfe32_ctrl->vfebase + + V32_DEMOSAICV3_DBPC_CFG_OFF2, + cmdp_local, V32_DEMOSAICV3_DBPC_LEN); + break; + + case VFE_CMD_RGB_G_CFG:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_io_memcpy(vfe32_ctrl->vfebase + V32_RGB_G_OFF, + cmdp, 4); + cmdp += 1; + + vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp); + } + cmdp -= 1; + break; + + case VFE_CMD_RGB_G_UPDATE:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + + old_val = msm_io_r(vfe32_ctrl->vfebase + V32_RGB_G_OFF); + cmdp += 1; + if (old_val != 0x0) { + vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, + cmdp); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, + cmdp); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, + cmdp); + } else { + vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK1, + cmdp); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK1, + cmdp); + vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK1, + cmdp); + } + } + vfe32_ctrl->update_gamma = TRUE; + cmdp -= 1; + break; + + case VFE_CMD_GET_RGB_G_TABLE: + temp1 = sizeof(uint32_t) * VFE32_GAMMA_NUM_ENTRIES * 3; + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kzalloc(temp1, GFP_KERNEL); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + cmdp_local = cmdp; + + old_val = msm_io_r(vfe32_ctrl->vfebase + V32_RGB_G_OFF); + temp2 = old_val ? RGBLUT_RAM_CH0_BANK1 : RGBLUT_RAM_CH0_BANK0; + for (i = 0; i < 3; i++) { + vfe32_read_gamma_cfg(temp2, + cmdp_local + + (VFE32_GAMMA_NUM_ENTRIES * i)); + temp2 += 2; + } + if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + + case VFE_CMD_STATS_AWB_STOP:{ + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~AWB_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + case VFE_CMD_STATS_AE_STOP:{ + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~AE_BG_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + case VFE_CMD_STATS_AF_STOP:{ + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~AF_BF_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + + case VFE_CMD_STATS_IHIST_STOP:{ + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~IHIST_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + + case VFE_CMD_STATS_RS_STOP:{ + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~RS_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + + case VFE_CMD_STATS_CS_STOP:{ + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~CS_ENABLE_MASK; + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + case VFE_CMD_STOP: + CDBG("vfe32_proc_general: cmdID = %s\n", + vfe32_general_cmd[cmd->id]); + vfe32_stop(); + break; + + case VFE_CMD_SYNC_TIMER_SETTING: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + vfe32_sync_timer_start(cmdp); + break; + + case VFE_CMD_MODULE_CFG:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + *cmdp &= ~STATS_ENABLE_MASK; + old_val = + msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= STATS_ENABLE_MASK; + *cmdp |= old_val; + + msm_io_memcpy(vfe32_ctrl->vfebase + + vfe32_cmd[cmd->id].offset, cmdp, + (vfe32_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_ZSL: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + vfe32_ctrl->jpeg_soc = *cmdp; + + rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_START, + VFE_MSG_OUTPUT_P); + if (rc < 0) + goto proc_general_done; + if (vfe32_ctrl->jpeg_soc) { + /* YUV Soc ZSL */ + vfe32_ctrl->outpath.output_mode |= + VFE32_OUTPUT_MODE_V;/* video */ + } + rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_START, + VFE_MSG_OUTPUT_T); + if (rc < 0) + goto proc_general_done; + rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_START, + VFE_MSG_OUTPUT_S); + if (rc < 0) + goto proc_general_done; + + rc = vfe32_zsl(); + break; + + case VFE_CMD_ASF_CFG: + case VFE_CMD_ASF_UPDATE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset, + cmdp, (vfe32_cmd[cmd->id].length)); + cmdp_local = cmdp + V32_ASF_LEN / 4; + msm_io_memcpy(vfe32_ctrl->vfebase + V32_ASF_SPECIAL_EFX_CFG_OFF, + cmdp_local, V32_ASF_SPECIAL_EFX_CFG_LEN); + break; + + case VFE_CMD_PCA_ROLL_OFF_CFG: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + + cmdp_local = cmdp; + + temp1 = *cmdp_local; + cmdp_local++; + + msm_io_memcpy(vfe32_ctrl->vfebase + V33_PCA_ROLL_OFF_CFG_OFF1, + cmdp_local, V33_PCA_ROLL_OFF_CFG_LEN1); + cmdp_local += 4; + msm_io_memcpy(vfe32_ctrl->vfebase + V33_PCA_ROLL_OFF_CFG_OFF2, + cmdp_local, V33_PCA_ROLL_OFF_CFG_LEN2); + + cmdp_local += 3; + CDBG("%s: start writing RollOff Ram0 table\n", __func__); + vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0); + msm_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR); + for (i = 0; i < V33_PCA_ROLL_OFF_TABLE_SIZE; i++) { + msm_io_w(*(cmdp_local + 1), + vfe32_ctrl->vfebase + VFE33_DMI_DATA_HI); + msm_io_w(*cmdp_local, + vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO); + cmdp_local += 2; + } + CDBG("%s: end writing RollOff Ram0 table\n", __func__); + + CDBG("%s: start writing RollOff Ram1 table\n", __func__); + vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0); + msm_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR); + for (i = 0; i < V33_PCA_ROLL_OFF_TABLE_SIZE; i++) { + msm_io_w(*cmdp_local, + vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO); + cmdp_local += 2; + } + CDBG("%s: end writing RollOff Ram1 table\n", __func__); + + vfe32_program_dmi_cfg(NO_MEM_SELECTED); + break; + + case VFE_CMD_PCA_ROLL_OFF_UPDATE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + + cmdp_local = cmdp; + + temp1 = *cmdp_local; + cmdp_local += 8; + + temp2 = msm_io_r(vfe32_ctrl->vfebase + + V33_PCA_ROLL_OFF_CFG_OFF1) + & V33_PCA_ROLL_OFF_LUT_BANK_SEL_MASK; + + CDBG("%s: start writing RollOff Ram0 table\n", __func__); + if (temp2) + vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0); + else + vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK1); + + msm_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR); + for (i = 0; i < V33_PCA_ROLL_OFF_TABLE_SIZE; i++) { + msm_io_w(*(cmdp_local + 1), + vfe32_ctrl->vfebase + VFE33_DMI_DATA_HI); + msm_io_w(*cmdp_local, + vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO); + cmdp_local += 2; + } + CDBG("%s: end writing RollOff Ram0 table\n", __func__); + + CDBG("%s: start writing RollOff Ram1 table\n", __func__); + if (temp2) + vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0); + else + vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK1); + + msm_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR); + for (i = 0; i < V33_PCA_ROLL_OFF_TABLE_SIZE; i++) { + msm_io_w(*cmdp_local, + vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO); + cmdp_local += 2; + } + CDBG("%s: end writing RollOff Ram1 table\n", __func__); + + vfe32_program_dmi_cfg(NO_MEM_SELECTED); + vfe32_ctrl->update_rolloff = true; + break; + case VFE_CMD_GET_PCA_ROLLOFF_TABLE: + temp1 = sizeof(uint64_t) * V33_PCA_ROLL_OFF_TABLE_SIZE * 2; + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kzalloc(temp1, GFP_KERNEL); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + cmdp_local = cmdp; + old_val = msm_io_r(vfe32_ctrl->vfebase + + V33_PCA_ROLL_OFF_CFG_OFF1) & + V33_PCA_ROLL_OFF_LUT_BANK_SEL_MASK; + + if (old_val) + vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK1); + else + vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0); + + CDBG("%s: PCA Rolloff Ram0\n", __func__); + for (i = 0; i < V33_PCA_ROLL_OFF_TABLE_SIZE * 2; i++) { +#ifdef QC_TEST /*aswoogi_zsl*/ + temp2 = (i == (V33_PCA_ROLL_OFF_TABLE_SIZE - 1)); +#else + temp2 = (i == (V33_PCA_ROLL_OFF_TABLE_SIZE)); +#endif + if (old_val && temp2) + vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK1); + else if (!old_val && temp2) + vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0); + +#ifdef QC_TEST /*aswoogi_zsl*/ + *(cmdp_local + 1) = + msm_io_r(vfe32_ctrl->vfebase + VFE33_DMI_DATA_HI); + *cmdp_local = msm_io_r(vfe32_ctrl->vfebase + + VFE33_DMI_DATA_LO); +#else + *cmdp_local = msm_io_r(vfe32_ctrl->vfebase + + VFE33_DMI_DATA_LO); + *(cmdp_local + 1) = + msm_io_r(vfe32_ctrl->vfebase + VFE33_DMI_DATA_HI); +#endif + CDBG("%s: %08x%08x\n", __func__, + *(cmdp_local + 1), *cmdp_local); + cmdp_local += 2; + } + vfe32_program_dmi_cfg(NO_MEM_SELECTED); + if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + case VFE_CMD_GET_HW_VERSION: + if (cmd->length != V32_GET_HW_VERSION_LEN) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kmalloc(V32_GET_HW_VERSION_LEN, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + *cmdp = msm_io_r(vfe32_ctrl->vfebase + V32_GET_HW_VERSION_OFF); + if (copy_to_user((void __user *)(cmd->value), cmdp, + V32_GET_HW_VERSION_LEN)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + case VFE_CMD_GET_REG_DUMP: + temp1 = sizeof(uint32_t) * vfe32_ctrl->register_total; + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kmalloc(temp1, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + msm_io_dump(vfe32_ctrl->vfebase, + vfe32_ctrl->register_total * 4); + CDBG("%s: %p %p %d\n", __func__, (void *)cmdp, + vfe32_ctrl->vfebase, temp1); + memcpy_fromio((void *)cmdp, vfe32_ctrl->vfebase, temp1); + if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + default: + if (cmd->length != vfe32_cmd[cmd->id].length) + return -EINVAL; + + cmdp = kmalloc(vfe32_cmd[cmd->id].length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + + CHECKED_COPY_FROM_USER(cmdp); + msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset, + cmdp, (vfe32_cmd[cmd->id].length)); + break; + + } + +proc_general_done: + kfree(cmdp); + + return rc; +} + +static void vfe32_stats_af_ack(struct vfe_cmd_stats_ack *pAck) +{ + unsigned long flags; + spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags); + vfe32_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe32_ctrl->afStatsControl.ackPending = FALSE; + spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags); +} + +static void vfe32_stats_awb_ack(struct vfe_cmd_stats_ack *pAck) +{ + unsigned long flags; + spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags); + vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe32_ctrl->awbStatsControl.ackPending = FALSE; + spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags); +} + +static void vfe32_stats_aec_ack(struct vfe_cmd_stats_ack *pAck) +{ + unsigned long flags; + spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags); + vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe32_ctrl->aecStatsControl.ackPending = FALSE; + spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags); +} + +static void vfe32_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck) +{ + vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe32_ctrl->ihistStatsControl.ackPending = FALSE; +} + +static void vfe32_stats_rs_ack(struct vfe_cmd_stats_ack *pAck) +{ + vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe32_ctrl->rsStatsControl.ackPending = FALSE; +} + +static void vfe32_stats_cs_ack(struct vfe_cmd_stats_ack *pAck) +{ + vfe32_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf; + vfe32_ctrl->csStatsControl.ackPending = FALSE; +} + +static inline void vfe32_read_irq_status(struct vfe32_irq_status *out) +{ + uint32_t *temp; + memset(out, 0, sizeof(struct vfe32_irq_status)); + temp = (uint32_t *) (vfe32_ctrl->vfebase + VFE_IRQ_STATUS_0); + out->vfeIrqStatus0 = msm_io_r(temp); + + temp = (uint32_t *) (vfe32_ctrl->vfebase + VFE_IRQ_STATUS_1); + out->vfeIrqStatus1 = msm_io_r(temp); + + temp = (uint32_t *) (vfe32_ctrl->vfebase + VFE_CAMIF_STATUS); + out->camifStatus = msm_io_r(temp); + CDBG("camifStatus = 0x%x\n", out->camifStatus); + + /* clear the pending interrupt of the same kind. */ + msm_io_w(out->vfeIrqStatus0, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_io_w(out->vfeIrqStatus1, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_IRQ_CMD); + +} + +static void vfe32_process_reg_update_irq(void) +{ + uint32_t old_val; + unsigned long flags; + struct vfe32_output_ch *video_ch; + + CDBG("%s: jpeg_soc = %d\n", __func__, vfe32_ctrl->jpeg_soc); + if (vfe32_ctrl->jpeg_soc) + video_ch = &vfe32_ctrl->outpath.out3; + else + video_ch = &vfe32_ctrl->outpath.out2; + + if (vfe32_ctrl->recording_state == + VFE_REC_STATE_START_REQUESTED) { + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_V) { + CDBG("%s: %d\n", __func__, __LINE__); + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[video_ch->ch0]); + msm_io_w(1, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[video_ch->ch1]); + } + vfe32_ctrl->recording_state = VFE_REC_STATE_STARTED; + msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD); + CDBG("start video triggered .\n"); + } else if (vfe32_ctrl->recording_state == + VFE_REC_STATE_STOP_REQUESTED) { + if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_V) { + msm_io_w_mb(0, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[video_ch->ch0]); + msm_io_w_mb(0, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[video_ch->ch1]); + } + + /*disable rs& cs when stop recording. */ + old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= (~RS_CS_ENABLE_MASK); + msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG); + + CDBG("stop video triggered .\n"); + } + if (vfe32_ctrl->start_ack_pending == TRUE) { + vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_START_ACK); + vfe32_ctrl->start_ack_pending = FALSE; + } else { + if (vfe32_ctrl->recording_state == + VFE_REC_STATE_STOP_REQUESTED) { + vfe32_ctrl->recording_state = VFE_REC_STATE_STOPPED; + /* request a reg update and send STOP_REC_ACK + * when we process the next reg update irq. + */ + msm_io_w_mb(1, + vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD); + } else if (vfe32_ctrl->recording_state == + VFE_REC_STATE_STOPPED) { + vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_STOP_REC_ACK); + vfe32_ctrl->recording_state = VFE_REC_STATE_IDLE; + } + spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags); + if (vfe32_ctrl->update_ack_pending == TRUE) { + vfe32_ctrl->update_ack_pending = FALSE; + spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, + flags); + vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_UPDATE_ACK); + } else { + spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, + flags); + } + } + /* in snapshot mode */ + if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_SNAPSHOT) { + /* later we need to add check for live snapshot mode. */ + vfe32_ctrl->vfe_capture_count--; + /* if last frame to be captured: */ + if (vfe32_ctrl->vfe_capture_count == 0) { + /* stop the bus output: write master enable = 0 */ + if (vfe32_ctrl->outpath.output_mode & + VFE32_OUTPUT_MODE_PT) { + msm_io_w(0, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out0.ch0]); + msm_io_w(0, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out0.ch1]); + } + if (vfe32_ctrl->outpath.output_mode & + VFE32_OUTPUT_MODE_S) { + msm_io_w(0, vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out1.ch0]); + msm_io_w(0, + vfe32_ctrl->vfebase + + vfe32_AXI_WM_CFG[vfe32_ctrl-> + outpath.out1.ch1]); + } + msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY, + vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND); +/*[[ aswoogi_zsl*/ + v4l2_subdev_notify(&vfe32_ctrl->subdev, + NOTIFY_ISPIF_STREAM, + (void *)ISPIF_STREAM(PIX_0, + ISPIF_OFF_FRAME_BOUNDARY)); +/*]]*/ + /* then do reg_update. */ + msm_io_w(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD); + } + } /* if snapshot mode. */ +} + +static void vfe32_set_default_reg_values(void) +{ + msm_io_w(0x800080, vfe32_ctrl->vfebase + VFE_DEMUX_GAIN_0); + msm_io_w(0x800080, vfe32_ctrl->vfebase + VFE_DEMUX_GAIN_1); + /* What value should we program CGC_OVERRIDE to? */ + msm_io_w(0xFFFFF, vfe32_ctrl->vfebase + VFE_CGC_OVERRIDE); + + /* default frame drop period and pattern */ + msm_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG); + msm_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG); + msm_io_w(0xFFFFFFFF, vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN); + msm_io_w(0xFFFFFFFF, + vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN); + msm_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y); + msm_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR); + msm_io_w(0xFFFFFFFF, + vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN); + msm_io_w(0xFFFFFFFF, + vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN); + msm_io_w(0, vfe32_ctrl->vfebase + VFE_CLAMP_MIN); + msm_io_w(0xFFFFFF, vfe32_ctrl->vfebase + VFE_CLAMP_MAX); + + /* stats UB config */ + msm_io_w(0x3980007, vfe32_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG); + msm_io_w(0x3A00007, vfe32_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG); + msm_io_w(0x3A8000F, vfe32_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG); + msm_io_w(0x3B80007, vfe32_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG); + msm_io_w(0x3C0001F, vfe32_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG); + msm_io_w(0x3E0001F, vfe32_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG); +} + +static void vfe32_process_reset_irq(void) +{ + unsigned long flags; + + atomic_set(&vfe32_ctrl->vstate, 0); + + spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags); + if (vfe32_ctrl->stop_ack_pending) { + vfe32_ctrl->stop_ack_pending = FALSE; + spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags); + vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_STOP_ACK); + } else { + spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags); + /* this is from reset command. */ + vfe32_set_default_reg_values(); + + /* reload all write masters. (frame & line) */ + msm_io_w(0x7FFF, vfe32_ctrl->vfebase + VFE_BUS_CMD); + vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_RESET_ACK); + } +} + +/*[[ aswoogi_zsl*/ +void vfe32_process_ispif_sof_irq(int rdi) +{ + if (rdi == RDI_0) { + vfe32_ctrl->rdi0FrameId++; + if (vfe32_ctrl->rdi0FrameId == 0) + vfe32_ctrl->rdi0FrameId = 1; + } else if (rdi == RDI_1) { + vfe32_ctrl->rdi1FrameId++; + if (vfe32_ctrl->rdi1FrameId == 0) + vfe32_ctrl->rdi1FrameId = 1; + } + CDBG("nishu is ispif vfe sof exit\n"); +} + +/*]]*/ +static void vfe32_process_camif_sof_irq(void) +{ + /* in raw snapshot mode */ + if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) { + if (vfe32_ctrl->start_ack_pending) { + vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_START_ACK); + vfe32_ctrl->start_ack_pending = FALSE; + } + vfe32_ctrl->vfe_capture_count--; + /* if last frame to be captured: */ + if (vfe32_ctrl->vfe_capture_count == 0) { + /* Ensure the write order while writing + to the command register using the barrier */ + msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY, + vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND); +/*[[ aswoogi_zsl*/ + v4l2_subdev_notify(&vfe32_ctrl->subdev, + NOTIFY_ISPIF_STREAM, + (void *)ISPIF_STREAM(PIX_0, + ISPIF_OFF_FRAME_BOUNDARY)); +/*]]*/ + } + } /* if raw snapshot mode. */ + vfe32_ctrl->vfeFrameId++; + if (vfe32_ctrl->vfeFrameId == 0) + vfe32_ctrl->vfeFrameId = 1; /* wrapped back */ + vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_SOF_ACK); + CDBG("camif_sof_irq, frameId = %d\n", vfe32_ctrl->vfeFrameId); + + if (vfe32_ctrl->sync_timer_state) { + if (vfe32_ctrl->sync_timer_repeat_count == 0) + vfe32_sync_timer_stop(); + else + vfe32_ctrl->sync_timer_repeat_count--; + } +} + +static void vfe32_process_error_irq(uint32_t errStatus) +{ + uint32_t camifStatus; + uint32_t *temp; + + if (errStatus & VFE32_IMASK_CAMIF_ERROR) { + pr_err("vfe32_irq: camif errors\n"); + temp = (uint32_t *) (vfe32_ctrl->vfebase + VFE_CAMIF_STATUS); + camifStatus = msm_io_r(temp); + pr_err("camifStatus = 0x%x\n", camifStatus); + vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_CAMIF_ERROR); + } + + if (errStatus & VFE32_IMASK_BHIST_OVWR) + pr_err("vfe32_irq: stats bhist overwrite\n"); + + if (errStatus & VFE32_IMASK_STATS_CS_OVWR) + pr_err("vfe32_irq: stats cs overwrite\n"); + + if (errStatus & VFE32_IMASK_STATS_IHIST_OVWR) + pr_err("vfe32_irq: stats ihist overwrite\n"); + + if (errStatus & VFE32_IMASK_REALIGN_BUF_Y_OVFL) + pr_err("vfe32_irq: realign bug Y overflow\n"); + + if (errStatus & VFE32_IMASK_REALIGN_BUF_CB_OVFL) + pr_err("vfe32_irq: realign bug CB overflow\n"); + + if (errStatus & VFE32_IMASK_REALIGN_BUF_CR_OVFL) + pr_err("vfe32_irq: realign bug CR overflow\n"); + + if (errStatus & VFE32_IMASK_VIOLATION) { + pr_err("vfe32_irq: violation interrupt," + " value = %x\n", + msm_io_r(vfe32_ctrl->vfebase + 0x7B4)); + } + + if (errStatus & VFE32_IMASK_IMG_MAST_0_BUS_OVFL) + pr_err("vfe32_irq: image master 0 bus overflow\n"); + + if (errStatus & VFE32_IMASK_IMG_MAST_1_BUS_OVFL) + pr_err("vfe32_irq: image master 1 bus overflow\n"); + + if (errStatus & VFE32_IMASK_IMG_MAST_2_BUS_OVFL) + pr_err("vfe32_irq: image master 2 bus overflow\n"); + + if (errStatus & VFE32_IMASK_IMG_MAST_3_BUS_OVFL) + pr_err("vfe32_irq: image master 3 bus overflow\n"); + + if (errStatus & VFE32_IMASK_IMG_MAST_4_BUS_OVFL) + pr_err("vfe32_irq: image master 4 bus overflow\n"); + + if (errStatus & VFE32_IMASK_IMG_MAST_5_BUS_OVFL) + pr_err("vfe32_irq: image master 5 bus overflow\n"); + + if (errStatus & VFE32_IMASK_IMG_MAST_6_BUS_OVFL) + pr_err("vfe32_irq: image master 6 bus overflow\n"); + + if (errStatus & VFE32_IMASK_STATS_AE_BG_BUS_OVFL) + pr_err("vfe32_irq: ae/bg stats bus overflow\n"); + + if (errStatus & VFE32_IMASK_STATS_AF_BF_BUS_OVFL) + pr_err("vfe32_irq: af/bf stats bus overflow\n"); + + if (errStatus & VFE32_IMASK_STATS_AWB_BUS_OVFL) + pr_err("vfe32_irq: awb stats bus overflow\n"); + + if (errStatus & VFE32_IMASK_STATS_RS_BUS_OVFL) + pr_err("vfe32_irq: rs stats bus overflow\n"); + + if (errStatus & VFE32_IMASK_STATS_CS_BUS_OVFL) + pr_err("vfe32_irq: cs stats bus overflow\n"); + + if (errStatus & VFE32_IMASK_STATS_IHIST_BUS_OVFL) + pr_err("vfe32_irq: ihist stats bus overflow\n"); + + if (errStatus & VFE32_IMASK_STATS_SKIN_BHIST_BUS_OVFL) + pr_err("vfe32_irq: skin/bhist stats bus overflow\n"); + + if (errStatus & VFE32_IMASK_AXI_ERROR) + pr_err("vfe32_irq: axi error\n"); +} + +static void vfe_send_outmsg(struct v4l2_subdev *sd, uint8_t msgid, + uint32_t ch0_paddr, uint32_t ch1_paddr, + uint32_t ch2_paddr, uint32_t frame_id) +{ + struct isp_msg_output msg; + + msg.output_id = msgid; + msg.buf.ch_paddr[0] = ch0_paddr; + msg.buf.ch_paddr[1] = ch1_paddr; + msg.buf.ch_paddr[2] = ch2_paddr; + msg.frameCounter = frame_id; + + v4l2_subdev_notify(&vfe32_ctrl->subdev, NOTIFY_VFE_MSG_OUT, &msg); + return; +} + +static void vfe32_process_output_path_irq_0(void) +{ + uint32_t ping_pong; + uint32_t ch0_paddr, ch1_paddr, ch2_paddr; + uint8_t out_bool = 0; + struct msm_free_buf *free_buf = NULL; + CDBG("nishu output 0\n"); /*aswoogi_zsl*/ + if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_SNAPSHOT) + free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_T); + else + free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_P); + /* we render frames in the following conditions: + 1. Continuous mode and the free buffer is avaialable. + 2. In snapshot shot mode, free buffer is not always available. + when pending snapshot count is <=1, then no need to use + free buffer. + */ + out_bool = + ((vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_SNAPSHOT || + vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) && + (vfe32_ctrl->vfe_capture_count <= 1)) || free_buf; + if (out_bool) { + ping_pong = msm_io_r(vfe32_ctrl->vfebase + + VFE_BUS_PING_PONG_STATUS); + + /* Channel 0 */ + ch0_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out0.ch0); + /* Channel 1 */ + ch1_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out0.ch1); + /* Channel 2 */ + ch2_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out0.ch2); + + CDBG("output path 0, ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n", + ch0_paddr, ch1_paddr, ch2_paddr); + if (free_buf) { + /* Y channel */ + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out0.ch0, + free_buf->ch_paddr[0]); + /* Chroma channel */ + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out0.ch1, + free_buf->ch_paddr[1]); + if (free_buf->num_planes > 2) + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out0.ch2, + free_buf->ch_paddr[2]); + } + if (vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_SNAPSHOT) { + /* will add message for multi-shot. */ + vfe32_ctrl->outpath.out0.capture_cnt--; + vfe_send_outmsg(&vfe32_ctrl->subdev, + MSG_ID_OUTPUT_T, ch0_paddr, + ch1_paddr, ch2_paddr, + vfe32_ctrl->vfeFrameId); + } else { + /* always send message for continous mode. */ + /* if continuous mode, for display. (preview) */ + vfe_send_outmsg(&vfe32_ctrl->subdev, + MSG_ID_OUTPUT_P, ch0_paddr, + ch1_paddr, ch2_paddr, + vfe32_ctrl->vfeFrameId); + } + } else { + vfe32_ctrl->outpath.out0.frame_drop_cnt++; + CDBG("path_irq_0 - no free buffer!\n"); + if (no_free_buffer_flag == 0) + pr_warn("Waiting output 0 buffer." + " but it doesn't matter.\n"); + } +} + +static bool vfe32_is_free_buf_avail(int path) +{ + struct msm_sync *p_sync = (struct msm_sync *)vfe_syncdata; + struct msm_cam_v4l2_device *pcam = p_sync->pcam_sync; + return (msm_mctl_check_free_buf(&pcam->mctl, path) >= 0); +} + +static void vfe32_process_zsl_frame(void) +{ + uint32_t ping_pong; + uint32_t ch0_paddr, ch1_paddr, ch2_paddr; + bool t_avail = false; + bool s_avail = false; + struct msm_free_buf *free_buf_t = NULL; + struct msm_free_buf *free_buf_s = NULL; + struct timespec tv; + unsigned int time_diff = 0; + + CDBG("nishu process zsl handled\n"); /*aswoogi_zsl */ + + getnstimeofday(&tv); + CDBG("[%s:%d] sec %ld, nsec %ld\n", __func__, __LINE__, tv.tv_sec, tv.tv_nsec); + + t_avail = vfe32_is_free_buf_avail(VFE_MSG_OUTPUT_T); + s_avail = vfe32_is_free_buf_avail(VFE_MSG_OUTPUT_S); + if (!(t_avail && s_avail)) { + if (pre_frame_sec != 0 && pre_frame_msec != 0) { + if (pre_frame_sec == tv.tv_sec) + time_diff = TV_MSEC(tv.tv_nsec) - pre_frame_msec; + else + time_diff = (TV_MSEC(tv.tv_nsec) + 1000) - pre_frame_msec; + + if (time_diff <= 70) /* 70msec is a frame when fps is 15*/ + no_free_buffer_count++; + else + no_free_buffer_count = 0; + CDBG("count %x\n", no_free_buffer_count); + CDBG("time_diff %x, tv_msec %ld, pre_frame_msec %ld\n", + time_diff, TV_MSEC(tv.tv_nsec), pre_frame_msec); + /* max 66msec * 60 = 3960msec */ + /* min 33msec * 60 = 1980msec */ + if (no_free_buffer_count > 60) + no_free_buffer_flag = 1; + else + no_free_buffer_flag = 0; + } + + if (no_free_buffer_flag) { + if (!s_avail) + pr_err("%d : nishu zsl no free snapshot buffer\n", __LINE__); + if (!t_avail) + pr_err("%d : nishu zsl no free thumbnail buffer\n", __LINE__); + } else { + if (!s_avail) + CDBG("nishu zsl no free snapshot buffer\n"); + if (!t_avail) + CDBG("nishu zsl no free thumbnail buffer\n"); + } + pre_frame_sec = tv.tv_sec; + pre_frame_msec = TV_MSEC(tv.tv_nsec); + + return; + } + pre_frame_sec = 0; + pre_frame_msec = 0; + no_free_buffer_count = 0; + no_free_buffer_flag = 0; + + ping_pong = msm_io_r(vfe32_ctrl->vfebase + VFE_BUS_PING_PONG_STATUS); + CDBG("%s: ping_pong = %d\n", __func__, ping_pong); + + /* Thumbnail - RDI1 */ + free_buf_t = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_T); + if (free_buf_t) { + ch0_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch0); + ch1_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch1); + ch2_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch2); + CDBG("thumbnail get ch0_paddr = 0x%x", ch0_paddr); + CDBG("thumbnail get ch1_paddr = 0x%x", ch1_paddr); + CDBG("thumbnail get ch2_paddr = 0x%x", ch2_paddr); + + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch0, + free_buf_t->ch_paddr[0]); + if (free_buf_t->num_planes > 1) + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch1, + free_buf_t->ch_paddr[1]); + if (free_buf_t->num_planes > 2) + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch2, + free_buf_t->ch_paddr[2]); + CDBG("thumbnail put ch0_paddr = 0x%x", free_buf_t->ch_paddr[0]); + CDBG("thumbnail put ch1_paddr = 0x%x", free_buf_t->ch_paddr[1]); + CDBG("thumbnail put ch2_paddr = 0x%x", free_buf_t->ch_paddr[2]); + + vfe_send_outmsg(&vfe32_ctrl->subdev, + MSG_ID_OUTPUT_T, ch0_paddr, + ch1_paddr, ch2_paddr, vfe32_ctrl->rdi1FrameId); + } else + pr_info("%s: nishu zsl no free thumbnail buffer\n", __func__); + + /* Mainimg - RDI0 */ + free_buf_s = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_S); + if (free_buf_s) { + ch0_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out2.ch0); + ch1_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out2.ch1); + ch2_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out2.ch2); + CDBG("mainimg get ch0_paddr = 0x%x", ch0_paddr); + CDBG("mainimg get ch1_paddr = 0x%x", ch1_paddr); + CDBG("mainimg get ch2_paddr = 0x%x", ch2_paddr); + + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out2.ch0, + free_buf_s->ch_paddr[0]); + if (free_buf_s->num_planes > 1) + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out2.ch1, + free_buf_s->ch_paddr[1]); + if (free_buf_s->num_planes > 2) + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out2.ch2, + free_buf_s->ch_paddr[2]); + CDBG("mainimg put ch0_paddr = 0x%x", free_buf_t->ch_paddr[0]); + CDBG("mainimg put ch1_paddr = 0x%x", free_buf_t->ch_paddr[1]); + CDBG("mainimg put ch2_paddr = 0x%x", free_buf_t->ch_paddr[2]); + + vfe_send_outmsg(&vfe32_ctrl->subdev, + MSG_ID_OUTPUT_S, ch0_paddr, + ch1_paddr, ch2_paddr, vfe32_ctrl->rdi0FrameId); + } else + pr_info("%s: nishu zsl no free main image buffer\n", __func__); +} + +static void vfe32_process_output_path_irq_1(void) +{ + uint32_t ping_pong; + uint32_t ch0_paddr, ch1_paddr, ch2_paddr; + /* this must be snapshot main image output. */ + uint8_t out_bool = 0; + struct msm_free_buf *free_buf = NULL; + CDBG("nishu output 1\n"); /*aswoogi_zsl*/ + if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_ZSL) { + vfe32_process_zsl_frame(); + return; + } + + free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_S); + + /* we render frames in the following conditions: + 1. Continuous mode and the free buffer is avaialable. + 2. In snapshot shot mode, free buffer is not always available. + -- when pending snapshot count is <=1, then no need to use + free buffer. + */ + out_bool = + ((vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_SNAPSHOT || + vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) && + (vfe32_ctrl->vfe_capture_count <= 1)) || free_buf; + if (out_bool) { + ping_pong = msm_io_r(vfe32_ctrl->vfebase + + VFE_BUS_PING_PONG_STATUS); + + /* Y channel */ + ch0_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch0); + /* Chroma channel */ + ch1_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch1); + ch2_paddr = vfe32_get_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch2); + + CDBG("snapshot main, ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n", + ch0_paddr, ch1_paddr, ch2_paddr); + if (free_buf) { + /* Y channel */ + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch0, + free_buf->ch_paddr[0]); + /* Chroma channel */ + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch1, + free_buf->ch_paddr[1]); + if (free_buf->num_planes > 2) + vfe32_put_ch_addr(ping_pong, + vfe32_ctrl->outpath.out1.ch2, + free_buf->ch_paddr[2]); + } + + if (vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_SNAPSHOT || + vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) { + vfe32_ctrl->outpath.out1.capture_cnt--; + vfe_send_outmsg(&vfe32_ctrl->subdev, + MSG_ID_OUTPUT_S, ch0_paddr, + ch1_paddr, ch2_paddr, + vfe32_ctrl->vfeFrameId); + } + } else { + vfe32_ctrl->outpath.out1.frame_drop_cnt++; + CDBG("path_irq_1 - no free buffer!\n"); + pr_warn("Waiting output 1 buffer.\n"); + } +} + +static void vfe32_process_output_path_irq_2(void) +{ + uint32_t ping_pong; + uint32_t ch0_paddr, ch1_paddr, ch2_paddr; + struct msm_free_buf *free_buf = NULL; + struct vfe32_output_ch *video_ch; + + if (vfe32_ctrl->jpeg_soc) + video_ch = &vfe32_ctrl->outpath.out3; + else + video_ch = &vfe32_ctrl->outpath.out2; + + CDBG("nishu record buffer interrupt !\n"); + if (vfe32_ctrl->recording_state == VFE_REC_STATE_STOP_REQUESTED) { + vfe32_ctrl->outpath.out2.frame_drop_cnt++; + pr_err("%s: path_irq_2 - recording stop requested ", __func__); + return; + } + + free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_V); + /* we render frames in the following conditions: + 1. Continuous mode and the free buffer is avaialable. + 2. In snapshot shot mode, free buffer is not always available. + -- when pending snapshot count is <=1, then no need to use + free buffer. + */ + + CDBG("nishu %s: op mode = %d, capture_cnt = %d\n", __func__, + vfe32_ctrl->operation_mode, vfe32_ctrl->vfe_capture_count); + + if (free_buf) { + ping_pong = msm_io_r(vfe32_ctrl->vfebase + + VFE_BUS_PING_PONG_STATUS); + + /* Y channel */ + ch0_paddr = vfe32_get_ch_addr(ping_pong, video_ch->ch0); + /* Chroma channel */ + ch1_paddr = vfe32_get_ch_addr(ping_pong, video_ch->ch1); + ch2_paddr = vfe32_get_ch_addr(ping_pong, video_ch->ch2); + + /* Y channel */ + vfe32_put_ch_addr(ping_pong, + video_ch->ch0, free_buf->ch_paddr[0]); + /* Chroma channel */ + vfe32_put_ch_addr(ping_pong, + video_ch->ch1, free_buf->ch_paddr[1]); + if (free_buf->num_planes > 2) + vfe32_put_ch_addr(ping_pong, + video_ch->ch2, free_buf->ch_paddr[2]); + + vfe_send_outmsg(&vfe32_ctrl->subdev, + MSG_ID_OUTPUT_V, ch0_paddr, + ch1_paddr, ch2_paddr, vfe32_ctrl->vfeFrameId); + + } else { + vfe32_ctrl->outpath.out2.frame_drop_cnt++; + pr_err("nishu path_irq_2 - no free buffer!\n"); + } +} + +static void vfe32_process_stats_comb_irq(uint32_t *irqstatus) +{ + return; +} + +static uint32_t vfe32_process_stats_irq_common(uint32_t statsNum, + uint32_t newAddr) +{ + + uint32_t pingpongStatus; + uint32_t returnAddr; + uint32_t pingpongAddr; + + /* must be 0=ping, 1=pong */ + pingpongStatus = + ((msm_io_r(vfe32_ctrl->vfebase + VFE_BUS_PING_PONG_STATUS)) + & ((uint32_t) (1 << (statsNum + 7)))) >> (statsNum + 7); + /* stats bits starts at 7 */ + CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus); + pingpongAddr = + ((uint32_t) (vfe32_ctrl->vfebase + + VFE_BUS_STATS_PING_PONG_BASE)) + + (3 * statsNum) * 4 + (1 - pingpongStatus) * 4; + returnAddr = msm_io_r((uint32_t *) pingpongAddr); + msm_io_w(newAddr, (uint32_t *) pingpongAddr); + return returnAddr; +} + +static void vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum) +{ + unsigned long flags; + /* fill message with right content. */ + /* @todo This is causing issues, need further investigate */ + /* spin_lock_irqsave(&ctrl->state_lock, flags); */ + struct isp_msg_stats msgStats; + msgStats.frameCounter = vfe32_ctrl->vfeFrameId; + msgStats.buffer = bufAddress; + + switch (statsNum) { + case statsAeNum:{ + msgStats.id = MSG_ID_STATS_AEC; + spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags); + vfe32_ctrl->aecStatsControl.ackPending = TRUE; + spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, + flags); + } + break; + case statsAfNum:{ + msgStats.id = MSG_ID_STATS_AF; + spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags); + vfe32_ctrl->afStatsControl.ackPending = TRUE; + spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags); + } + break; + case statsAwbNum:{ + msgStats.id = MSG_ID_STATS_AWB; + spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags); + vfe32_ctrl->awbStatsControl.ackPending = TRUE; + spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, + flags); + } + break; + + case statsIhistNum:{ + msgStats.id = MSG_ID_STATS_IHIST; + vfe32_ctrl->ihistStatsControl.ackPending = TRUE; + } + break; + case statsRsNum:{ + msgStats.id = MSG_ID_STATS_RS; + vfe32_ctrl->rsStatsControl.ackPending = TRUE; + } + break; + case statsCsNum:{ + msgStats.id = MSG_ID_STATS_CS; + vfe32_ctrl->csStatsControl.ackPending = TRUE; + } + break; + + default: + goto stats_done; + } + + v4l2_subdev_notify(&vfe32_ctrl->subdev, + NOTIFY_VFE_MSG_STATS, &msgStats); +stats_done: + /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ + return; +} + +static void vfe32_process_stats_ae_irq(void) +{ + unsigned long flags; + spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags); + if (!(vfe32_ctrl->aecStatsControl.ackPending)) { + spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags); + vfe32_ctrl->aecStatsControl.bufToRender = + vfe32_process_stats_irq_common(statsAeNum, + vfe32_ctrl->aecStatsControl.nextFrameAddrBuf); + + vfe_send_stats_msg(vfe32_ctrl->aecStatsControl.bufToRender, + statsAeNum); + } else { + spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags); + vfe32_ctrl->aecStatsControl.droppedStatsFrameCount++; + } +} + +static void vfe32_process_stats_awb_irq(void) +{ + unsigned long flags; + spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags); + if (!(vfe32_ctrl->awbStatsControl.ackPending)) { + spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags); + vfe32_ctrl->awbStatsControl.bufToRender = + vfe32_process_stats_irq_common(statsAwbNum, + vfe32_ctrl->awbStatsControl.nextFrameAddrBuf); + + vfe_send_stats_msg(vfe32_ctrl->awbStatsControl.bufToRender, + statsAwbNum); + } else { + spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags); + vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++; + } +} + +static void vfe32_process_stats_af_irq(void) +{ + unsigned long flags; + spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags); + if (!(vfe32_ctrl->afStatsControl.ackPending)) { + spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags); + vfe32_ctrl->afStatsControl.bufToRender = + vfe32_process_stats_irq_common(statsAfNum, + vfe32_ctrl->afStatsControl.nextFrameAddrBuf); + + vfe_send_stats_msg(vfe32_ctrl->afStatsControl.bufToRender, + statsAfNum); + } else { + spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags); + vfe32_ctrl->afStatsControl.droppedStatsFrameCount++; + } +} + +static void vfe32_process_stats_ihist_irq(void) +{ + if (!(vfe32_ctrl->ihistStatsControl.ackPending)) { + vfe32_ctrl->ihistStatsControl.bufToRender = + vfe32_process_stats_irq_common(statsIhistNum, + vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf); + + vfe_send_stats_msg(vfe32_ctrl->ihistStatsControl.bufToRender, + statsIhistNum); + } else + vfe32_ctrl->ihistStatsControl.droppedStatsFrameCount++; +} + +static void vfe32_process_stats_rs_irq(void) +{ + if (!(vfe32_ctrl->rsStatsControl.ackPending)) { + vfe32_ctrl->rsStatsControl.bufToRender = + vfe32_process_stats_irq_common(statsRsNum, + vfe32_ctrl->rsStatsControl.nextFrameAddrBuf); + + vfe_send_stats_msg(vfe32_ctrl->rsStatsControl.bufToRender, + statsRsNum); + } else + vfe32_ctrl->rsStatsControl.droppedStatsFrameCount++; +} + +static void vfe32_process_stats_cs_irq(void) +{ + if (!(vfe32_ctrl->csStatsControl.ackPending)) { + vfe32_ctrl->csStatsControl.bufToRender = + vfe32_process_stats_irq_common(statsCsNum, + vfe32_ctrl->csStatsControl.nextFrameAddrBuf); + + vfe_send_stats_msg(vfe32_ctrl->csStatsControl.bufToRender, + statsCsNum); + } else + vfe32_ctrl->csStatsControl.droppedStatsFrameCount++; +} + +static void vfe32_do_tasklet(unsigned long data) +{ + unsigned long flags; + + struct vfe32_isr_queue_cmd *qcmd = NULL; + + CDBG("=== vfe32_do_tasklet start ===\n"); + + while (atomic_read(&irq_cnt)) { + spin_lock_irqsave(&vfe32_ctrl->tasklet_lock, flags); + qcmd = list_first_entry(&vfe32_ctrl->tasklet_q, + struct vfe32_isr_queue_cmd, list); + atomic_sub(1, &irq_cnt); + + if (!qcmd) { + spin_unlock_irqrestore(&vfe32_ctrl->tasklet_lock, + flags); + return; + } + + list_del_init(&qcmd->list); + spin_unlock_irqrestore(&vfe32_ctrl->tasklet_lock, + flags); + + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_CAMIF_SOF_MASK) { + CDBG("irq camifSofIrq\n"); + vfe32_process_camif_sof_irq(); + } + /* interrupt to be processed, *qcmd has the payload. */ + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_REG_UPDATE_MASK) { + CDBG("irq regUpdateIrq\n"); + vfe32_process_reg_update_irq(); + } + + if (qcmd->vfeInterruptStatus1 & + VFE_IMASK_WHILE_STOPPING_1) { + CDBG("irq resetAckIrq\n"); + vfe32_process_reset_irq(); + } + + if (atomic_read(&vfe32_ctrl->vstate)) { + if (qcmd->vfeInterruptStatus1 & + VFE32_IMASK_ERROR_ONLY_1) { + pr_err("irq errorIrq\n"); + vfe32_process_error_irq + (qcmd->vfeInterruptStatus1 & + VFE32_IMASK_ERROR_ONLY_1); + } + /* next, check output path related interrupts. */ + if (!vfe32_ctrl->start_ack_pending) { + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) { + CDBG("Image done 0 irq occured.\n"); + vfe32_process_output_path_irq_0(); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) { + CDBG("Image done 1 irq occured.\n"); + vfe32_process_output_path_irq_1(); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK) { + CDBG("Image done 2 irq occured.\n"); + vfe32_process_output_path_irq_2(); + } + } + /* in snapshot mode if done then send + snapshot done message */ + if (vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_SNAPSHOT || + vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) { + if ((vfe32_ctrl->outpath.out0.capture_cnt == 0) + && (vfe32_ctrl->outpath.out1.capture_cnt == + 0)) { + msm_io_w_mb + (CAMIF_COMMAND_STOP_IMMEDIATELY, + vfe32_ctrl->vfebase + + VFE_CAMIF_COMMAND); +/*[[ aswoogi_zsl*/ + v4l2_subdev_notify(&vfe32_ctrl->subdev, + NOTIFY_ISPIF_STREAM, + (void *) + ISPIF_STREAM(PIX_0, + ISPIF_OFF_IMMEDIATELY)); +/*]]*/ + vfe32_send_isp_msg(vfe32_ctrl, + MSG_ID_SNAPSHOT_DONE); + } + } + /* then process stats irq. */ + if (vfe32_ctrl->stats_comp) { + /* process stats comb interrupt. */ + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) { + CDBG("Stats composite irq occured.\n"); + vfe32_process_stats_comb_irq + (&qcmd->vfeInterruptStatus0); + } + } else { + /* process individual stats interrupt. */ + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_AEC) { + CDBG("Stats AEC irq occured.\n"); + vfe32_process_stats_ae_irq(); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_AWB) { + CDBG("Stats AWB irq occured.\n"); + vfe32_process_stats_awb_irq(); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_AF) { + CDBG("Stats AF irq occured.\n"); + vfe32_process_stats_af_irq(); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_IHIST) { + CDBG("Stats IHIST irq occured.\n"); + vfe32_process_stats_ihist_irq(); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_RS) { + CDBG("Stats RS irq occured.\n"); + vfe32_process_stats_rs_irq(); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_CS) { + CDBG("Stats CS irq occured.\n"); + vfe32_process_stats_cs_irq(); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_SYNC_TIMER0) { + CDBG("SYNC_TIMER 0 irq occured.\n"); + vfe32_send_isp_msg(vfe32_ctrl, + MSG_ID_SYNC_TIMER0_DONE); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_SYNC_TIMER1) { + CDBG("SYNC_TIMER 1 irq occured.\n"); + vfe32_send_isp_msg(vfe32_ctrl, + MSG_ID_SYNC_TIMER1_DONE); + } + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_SYNC_TIMER2) { + CDBG("SYNC_TIMER 2 irq occured.\n"); + vfe32_send_isp_msg(vfe32_ctrl, + MSG_ID_SYNC_TIMER2_DONE); + } + } + } + kfree(qcmd); + } + CDBG("=== vfe32_do_tasklet end ===\n"); +} + +static irqreturn_t vfe32_parse_irq(int irq_num, void *data) +{ + unsigned long flags; + struct vfe32_irq_status irq; + struct vfe32_isr_queue_cmd *qcmd; + + CDBG("vfe_parse_irq\n"); + + vfe32_read_irq_status(&irq); + + if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) { + CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n"); + return IRQ_HANDLED; + } + + qcmd = kzalloc(sizeof(struct vfe32_isr_queue_cmd), GFP_ATOMIC); + if (!qcmd) { + pr_err("vfe_parse_irq: qcmd malloc failed!\n"); + return IRQ_HANDLED; + } + + spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags); + if (vfe32_ctrl->stop_ack_pending) { + irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0; + irq.vfeIrqStatus1 &= VFE_IMASK_WHILE_STOPPING_1; + } + spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags); + + CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n", + irq.vfeIrqStatus0, irq.vfeIrqStatus1); + + qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0; + qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1; + + spin_lock_irqsave(&vfe32_ctrl->tasklet_lock, flags); + list_add_tail(&qcmd->list, &vfe32_ctrl->tasklet_q); + + atomic_add(1, &irq_cnt); + spin_unlock_irqrestore(&vfe32_ctrl->tasklet_lock, flags); + tasklet_schedule(&vfe32_ctrl->vfe32_tasklet); + return IRQ_HANDLED; +} + +static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int subdev_cmd, void *arg) +{ + struct msm_isp_cmd vfecmd; + struct msm_camvfe_params *vfe_params = (struct msm_camvfe_params *)arg; + struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg; + void *data = vfe_params->data; + + long rc = 0; + uint32_t i = 0; + struct vfe_cmd_stats_buf *scfg = NULL; + struct msm_pmem_region *regptr = NULL; + struct vfe_cmd_stats_ack *sack = NULL; + if (cmd->cmd_type != CMD_CONFIG_PING_ADDR && + cmd->cmd_type != CMD_CONFIG_PONG_ADDR && + cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR && + cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) { + if (copy_from_user(&vfecmd, + (void __user *)(cmd->value), + sizeof(vfecmd))) { + pr_err("%s %d: copy_from_user failed\n", __func__, + __LINE__); + return -EFAULT; + } + } else { + /* here eith stats release or frame release. */ + if (cmd->cmd_type != CMD_CONFIG_PING_ADDR && + cmd->cmd_type != CMD_CONFIG_PONG_ADDR && + cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) { + /* then must be stats release. */ + if (!data) + return -EFAULT; + sack = kmalloc(sizeof(struct vfe_cmd_stats_ack), + GFP_ATOMIC); + if (!sack) + return -ENOMEM; + + sack->nextStatsBuf = *(uint32_t *) data; + } + } + + CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type); + + if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) || + (cmd->cmd_type == CMD_STATS_AWB_ENABLE) || + (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) || + (cmd->cmd_type == CMD_STATS_RS_ENABLE) || + (cmd->cmd_type == CMD_STATS_CS_ENABLE) || + (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) { + struct axidata *axid; + axid = data; + if (!axid) { + rc = -EFAULT; + goto vfe32_config_done; + } + + scfg = kmalloc(sizeof(struct vfe_cmd_stats_buf), GFP_ATOMIC); + if (!scfg) { + rc = -ENOMEM; + goto vfe32_config_done; + } + regptr = axid->region; + if (axid->bufnum1 > 0) { + for (i = 0; i < axid->bufnum1; i++) { + scfg->statsBuf[i] = (uint32_t) (regptr->paddr); + regptr++; + } + } + /* individual */ + switch (cmd->cmd_type) { + case CMD_STATS_AEC_ENABLE: + rc = vfe_stats_aec_buf_init(scfg); + break; + case CMD_STATS_AF_ENABLE: + rc = vfe_stats_af_buf_init(scfg); + break; + case CMD_STATS_AWB_ENABLE: + rc = vfe_stats_awb_buf_init(scfg); + break; + case CMD_STATS_IHIST_ENABLE: + rc = vfe_stats_ihist_buf_init(scfg); + break; + case CMD_STATS_RS_ENABLE: + rc = vfe_stats_rs_buf_init(scfg); + break; + case CMD_STATS_CS_ENABLE: + rc = vfe_stats_cs_buf_init(scfg); + break; + } + } + switch (cmd->cmd_type) { + case CMD_GENERAL: + rc = vfe32_proc_general(&vfecmd); + break; + + case CMD_CONFIG_PING_ADDR:{ + int path = *((int *)cmd->value); + struct vfe32_output_ch *outch = vfe32_get_ch(path); + outch->ping = *((struct msm_free_buf *)data); + } + break; + + case CMD_CONFIG_PONG_ADDR:{ + int path = *((int *)cmd->value); + struct vfe32_output_ch *outch = vfe32_get_ch(path); + outch->pong = *((struct msm_free_buf *)data); + } + break; + + case CMD_CONFIG_FREE_BUF_ADDR:{ + int path = *((int *)cmd->value); + struct vfe32_output_ch *outch = vfe32_get_ch(path); + outch->free_buf = *((struct msm_free_buf *)data); + } + break; + + case CMD_SNAP_BUF_RELEASE: + break; + case CMD_STATS_AEC_BUF_RELEASE: + vfe32_stats_aec_ack(sack); + break; + case CMD_STATS_AF_BUF_RELEASE: + vfe32_stats_af_ack(sack); + break; + case CMD_STATS_AWB_BUF_RELEASE: + vfe32_stats_awb_ack(sack); + break; + + case CMD_STATS_IHIST_BUF_RELEASE: + vfe32_stats_ihist_ack(sack); + break; + case CMD_STATS_RS_BUF_RELEASE: + vfe32_stats_rs_ack(sack); + break; + case CMD_STATS_CS_BUF_RELEASE: + vfe32_stats_cs_ack(sack); + break; + + case CMD_AXI_CFG_PREVIEW:{ + uint32_t *axio = NULL; + axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe32_cmd + [VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe32_config_axi(OUTPUT_2, axio); + kfree(axio); + } + break; + + case CMD_RAW_PICT_AXI_CFG:{ + uint32_t *axio = NULL; + axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe32_cmd + [VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe32_config_axi(CAMIF_TO_AXI_VIA_OUTPUT_2, axio); + kfree(axio); + } + break; + + case CMD_AXI_CFG_SNAP:{ + uint32_t *axio = NULL; + axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe32_cmd + [VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe32_config_axi(OUTPUT_1_AND_2, axio); + kfree(axio); + } + break; + + case CMD_AXI_CFG_ZSL:{ + uint32_t *axio = NULL; + CDBG("%s, CMD_AXI_CFG_ZSL\n", __func__); + axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe32_cmd + [VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe32_config_axi(OUTPUT_1_2_AND_3, axio); + kfree(axio); + } + break; + + case CMD_AXI_CFG_ZSL_ALL_CHNLS:{ + uint32_t *axio = NULL; + CDBG("%s, CMD_AXI_CFG_ZSL\n", __func__); + axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe32_cmd + [VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe32_config_axi(OUTPUT_ZSL_ALL_CHNLS, axio); + kfree(axio); + } + break; + + case CMD_AXI_CFG_VIDEO:{ + uint32_t *axio = NULL; + axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe32_cmd + [VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe32_config_axi(OUTPUT_1_AND_3, axio); + kfree(axio); + } + break; + + case CMD_AXI_CFG_VIDEO_ALL_CHNLS:{ + uint32_t *axio = NULL; + axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe32_cmd + [VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe32_config_axi(OUTPUT_ALL_CHNLS, axio); + kfree(axio); + } + break; + default: + break; + } +vfe32_config_done: + kfree(scfg); + kfree(sack); + CDBG("%s done: rc = %d\n", __func__, (int)rc); + return rc; +} + +static struct msm_cam_clk_info vfe32_clk_info[] = { + {"vfe_clk", 228570000}, + {"vfe_pclk", -1}, + {"csi_vfe_clk", -1}, +}; + +static int msm_vfe_subdev_s_crystal_freq(struct v4l2_subdev *sd, + u32 freq, u32 flags) +{ + int rc = 0; + int round_rate; + + round_rate = clk_round_rate(vfe32_ctrl->vfe_clk[0], freq); + if (rc < 0) { + pr_err("%s: clk_round_rate failed %d\n", __func__, rc); + return rc; + } + + vfe_clk_rate = round_rate; + rc = clk_set_rate(vfe32_ctrl->vfe_clk[0], round_rate); + if (rc < 0) + pr_err("%s: clk_set_rate failed %d\n", __func__, rc); + + pr_info("%s: vfe clock set to %d\n", __func__, round_rate); + return rc; +} + +static const struct v4l2_subdev_video_ops msm_vfe_subdev_video_ops = { + .s_crystal_freq = msm_vfe_subdev_s_crystal_freq, +}; + +static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = { + .ioctl = msm_vfe_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_vfe_subdev_ops = { + .core = &msm_vfe_subdev_core_ops, + .video = &msm_vfe_subdev_video_ops, +}; + +int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data, + struct platform_device *pdev) +{ + int rc = 0; + v4l2_set_subdev_hostdata(sd, data); + vfe_syncdata = data; + + spin_lock_init(&vfe32_ctrl->stop_flag_lock); + spin_lock_init(&vfe32_ctrl->state_lock); + spin_lock_init(&vfe32_ctrl->io_lock); + spin_lock_init(&vfe32_ctrl->update_ack_lock); + spin_lock_init(&vfe32_ctrl->tasklet_lock); + + spin_lock_init(&vfe32_ctrl->aec_ack_lock); + spin_lock_init(&vfe32_ctrl->awb_ack_lock); + spin_lock_init(&vfe32_ctrl->af_ack_lock); + spin_lock_init(&vfe32_ctrl->sd_notify_lock); + INIT_LIST_HEAD(&vfe32_ctrl->tasklet_q); + + vfe32_ctrl->update_linear = false; + vfe32_ctrl->update_rolloff = false; + vfe32_ctrl->update_la = false; + vfe32_ctrl->update_gamma = false; + + vfe32_ctrl->vfebase = ioremap(vfe32_ctrl->vfemem->start, + resource_size(vfe32_ctrl->vfemem)); + if (!vfe32_ctrl->vfebase) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vfe_remap_failed; + } + + if (vfe32_ctrl->fs_vfe == NULL) { + vfe32_ctrl->fs_vfe = + regulator_get(&vfe32_ctrl->pdev->dev, "vdd"); + if (IS_ERR(vfe32_ctrl->fs_vfe)) { + pr_err("%s: Regulator FS_VFE get failed %ld\n", + __func__, PTR_ERR(vfe32_ctrl->fs_vfe)); + vfe32_ctrl->fs_vfe = NULL; + goto vfe_fs_failed; + } else if (regulator_enable(vfe32_ctrl->fs_vfe)) { + pr_err("%s: Regulator FS_VFE enable failed\n", + __func__); + regulator_put(vfe32_ctrl->fs_vfe); + vfe32_ctrl->fs_vfe = NULL; + goto vfe_fs_failed; + } + } + + rc = msm_cam_clk_enable(&vfe32_ctrl->pdev->dev, vfe32_clk_info, + vfe32_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), + 1); + if (rc < 0) + goto vfe_clk_enable_failed; + + msm_camio_set_perf_lvl(S_INIT); + msm_camio_set_perf_lvl(S_PREVIEW); + + if (msm_io_r(vfe32_ctrl->vfebase + V32_GET_HW_VERSION_OFF) == + VFE32_HW_NUMBER) + vfe32_ctrl->register_total = VFE32_REGISTER_TOTAL; + else + vfe32_ctrl->register_total = VFE33_REGISTER_TOTAL; + + enable_irq(vfe32_ctrl->vfeirq->start); + + return rc; + +vfe_clk_enable_failed: + regulator_disable(vfe32_ctrl->fs_vfe); + regulator_put(vfe32_ctrl->fs_vfe); + vfe32_ctrl->fs_vfe = NULL; +vfe_fs_failed: + iounmap(vfe32_ctrl->vfebase); + vfe32_ctrl->vfebase = NULL; +vfe_remap_failed: + disable_irq(vfe32_ctrl->vfeirq->start); + return rc; +} + +void msm_vfe_subdev_release(struct platform_device *pdev) +{ + CDBG("%s, free_irq\n", __func__); + disable_irq(vfe32_ctrl->vfeirq->start); + tasklet_kill(&vfe32_ctrl->vfe32_tasklet); + msm_cam_clk_enable(&vfe32_ctrl->pdev->dev, vfe32_clk_info, + vfe32_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0); + if (vfe32_ctrl->fs_vfe) { + regulator_disable(vfe32_ctrl->fs_vfe); + regulator_put(vfe32_ctrl->fs_vfe); + vfe32_ctrl->fs_vfe = NULL; + } + iounmap(vfe32_ctrl->vfebase); + vfe32_ctrl->vfebase = NULL; + + if (atomic_read(&irq_cnt)) + pr_warning("%s, Warning IRQ Count not ZERO\n", __func__); + + msm_camio_set_perf_lvl(S_EXIT); + vfe_syncdata = NULL; +} + +static int __devinit vfe32_probe(struct platform_device *pdev) +{ + int rc = 0; + CDBG("%s: device id = %d\n", __func__, pdev->id); + vfe32_ctrl = kzalloc(sizeof(struct vfe32_ctrl_type), GFP_KERNEL); + if (!vfe32_ctrl) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + v4l2_subdev_init(&vfe32_ctrl->subdev, &msm_vfe_subdev_ops); + snprintf(vfe32_ctrl->subdev.name, + sizeof(vfe32_ctrl->subdev.name), "vfe3.2"); + v4l2_set_subdevdata(&vfe32_ctrl->subdev, vfe32_ctrl); + platform_set_drvdata(pdev, &vfe32_ctrl->subdev); + + vfe32_ctrl->vfemem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, + "vfe32"); + if (!vfe32_ctrl->vfemem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe32_no_resource; + } + vfe32_ctrl->vfeirq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, + "vfe32"); + if (!vfe32_ctrl->vfeirq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto vfe32_no_resource; + } + + vfe32_ctrl->vfeio = request_mem_region(vfe32_ctrl->vfemem->start, + resource_size + (vfe32_ctrl->vfemem), + pdev->name); + if (!vfe32_ctrl->vfeio) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto vfe32_no_resource; + } + + rc = request_irq(vfe32_ctrl->vfeirq->start, vfe32_parse_irq, + IRQF_TRIGGER_RISING, "vfe", 0); + if (rc < 0) { + pr_err("%s: irq request fail\n", __func__); + rc = -EBUSY; + goto vfe32_no_resource; + } + + disable_irq(vfe32_ctrl->vfeirq->start); + + tasklet_init(&vfe32_ctrl->vfe32_tasklet, + vfe32_do_tasklet, (unsigned long)vfe32_ctrl); + + vfe32_ctrl->pdev = pdev; + return 0; + +vfe32_no_resource: + kfree(vfe32_ctrl); + return 0; +} + +static struct platform_driver vfe32_driver = { + .probe = vfe32_probe, + .driver = { + .name = MSM_VFE_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_vfe32_init_module(void) +{ + return platform_driver_register(&vfe32_driver); +} + +static void __exit msm_vfe32_exit_module(void) +{ + platform_driver_unregister(&vfe32_driver); +} + +module_init(msm_vfe32_init_module); +module_exit(msm_vfe32_exit_module); +MODULE_DESCRIPTION("VFE 3.2 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/msm_vfe32.h b/drivers/media/video/msm_zsl/msm_vfe32.h new file mode 100644 index 00000000000..6b3f2f29908 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe32.h @@ -0,0 +1,995 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __MSM_VFE32_H__ +#define __MSM_VFE32_H__ + +#define TRUE 1 +#define FALSE 0 + +#define QC_TEST + + +#define VFE32_HW_NUMBER 0x3030B +#define VFE33_HW_NUMBER 0x30408 + +/* This defines total number registers in VFE. + * Each register is 4 bytes so to get the range, + * multiply this number with 4. */ +#define VFE32_REGISTER_TOTAL 0x000001CD +#define VFE33_REGISTER_TOTAL 0x000001EE + +/* at start of camif, bit 1:0 = 0x01:enable + * image data capture at frame boundary. */ +#define CAMIF_COMMAND_START 0x00000005 + +/* bit 2= 0x1:clear the CAMIF_STATUS register + * value. */ +#define CAMIF_COMMAND_CLEAR 0x00000004 + +/* at stop of vfe pipeline, for now it is assumed + * that camif will stop at any time. Bit 1:0 = 0x10: + * disable image data capture immediately. */ +#define CAMIF_COMMAND_STOP_IMMEDIATELY 0x00000002 + +/* at stop of vfe pipeline, for now it is assumed + * that camif will stop at any time. Bit 1:0 = 0x00: + * disable image data capture at frame boundary */ +#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY 0x00000000 + +/* to halt axi bridge */ +#define AXI_HALT 0x00000001 + +/* clear the halt bit. */ +#define AXI_HALT_CLEAR 0x00000000 + +/* reset the pipeline when stop command is issued. + * (without reset the register.) bit 26-32 = 0, + * domain reset, bit 0-9 = 1 for module reset, except + * register module. */ +#define VFE_RESET_UPON_STOP_CMD 0x000003ef + +/* reset the pipeline when reset command. + * bit 26-32 = 0, domain reset, bit 0-9 = 1 for module reset. */ +#define VFE_RESET_UPON_RESET_CMD 0x000003ff + +/* bit 5 is for axi status idle or busy. + * 1 = halted, 0 = busy */ +#define AXI_STATUS_BUSY_MASK 0x00000020 + +/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present + * for frame done interrupt */ +#define VFE_COMP_IRQ_BOTH_Y_CBCR 3 + +/* bit 1 = 1, only cbcr irq triggers frame done interrupt */ +#define VFE_COMP_IRQ_CBCR_ONLY 2 + +/* bit 0 = 1, only y irq triggers frame done interrupt */ +#define VFE_COMP_IRQ_Y_ONLY 1 + +/* bit 0 = 1, PM go; bit1 = 1, PM stop */ +#define VFE_PERFORMANCE_MONITOR_GO 0x00000001 +#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002 + +/* bit 0 = 1, test gen go; bit1 = 1, test gen stop */ +#define VFE_TEST_GEN_GO 0x00000001 +#define VFE_TEST_GEN_STOP 0x00000002 + +/* the chroma is assumed to be interpolated between + * the luma samples. JPEG 4:2:2 */ +#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0 + +/* constants for irq registers */ +#define VFE_DISABLE_ALL_IRQS 0 +/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS. */ +#define VFE_CLEAR_ALL_IRQS 0xffffffff + +#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK 0x00000001 +#define VFE_IRQ_STATUS0_REG_UPDATE_MASK 0x00000020 +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK 0x00200000 +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK 0x00400000 +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK 0x00800000 +#define VFE_IRQ_STATUS1_RESET_AXI_HALT_ACK_MASK 0x00800000 +#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK 0x01000000 + +#define VFE_IRQ_STATUS0_STATS_AEC 0x2000 /* bit 13 */ +#define VFE_IRQ_STATUS0_STATS_AF 0x4000 /* bit 14 */ +#define VFE_IRQ_STATUS0_STATS_AWB 0x8000 /* bit 15 */ +#define VFE_IRQ_STATUS0_STATS_RS 0x10000 /* bit 16 */ +#define VFE_IRQ_STATUS0_STATS_CS 0x20000 /* bit 17 */ +#define VFE_IRQ_STATUS0_STATS_IHIST 0x40000 /* bit 18 */ + +#define VFE_IRQ_STATUS0_SYNC_TIMER0 0x2000000 /* bit 25 */ +#define VFE_IRQ_STATUS0_SYNC_TIMER1 0x4000000 /* bit 26 */ +#define VFE_IRQ_STATUS0_SYNC_TIMER2 0x8000000 /* bit 27 */ +#define VFE_IRQ_STATUS0_ASYNC_TIMER0 0x10000000 /* bit 28 */ +#define VFE_IRQ_STATUS0_ASYNC_TIMER1 0x20000000 /* bit 29 */ +#define VFE_IRQ_STATUS0_ASYNC_TIMER2 0x40000000 /* bit 30 */ +#define VFE_IRQ_STATUS0_ASYNC_TIMER3 0x80000000 /* bit 32 */ + +/* imask for while waiting for stop ack, driver has already + * requested stop, waiting for reset irq, and async timer irq. + * For irq_status_0, bit 28-32 are for async timer. For + * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack + irq */ +#define VFE_IMASK_WHILE_STOPPING_0 0xF0000000 +#define VFE_IMASK_WHILE_STOPPING_1 0x00800000 + +/* no error irq in mask 0 */ +#define VFE_IMASK_ERROR_ONLY_0 0x0 +/* when normal case, don't want to block error status. */ +/* bit 0-21 are error irq bits */ +#define VFE_IMASK_ERROR_ONLY_1 0x003fffff + +/* For BPC bit 0,bit 12-17 and bit 26 -20 are set to zero and other's 1 */ +#define BPC_MASK 0xF80C0FFE + +/* For ABF bit 4 is set to zero and other's 1 */ +#define ABF_MASK 0xFFFFFFF7 + + +/* For DBPC bit 0 is set to zero and other's 1 */ +#define DBPC_MASK 0xFFFFFFFE + +/* For DBPC bit 1 is set to zero and other's 1 */ +#define DBCC_MASK 0xFFFFFFFD + +/* For DBPC/ABF/DBCC/ABCC bits are set to 1 all others 0 */ +#define DEMOSAIC_MASK 0xF + +/* For MCE enable bit 28 set to zero and other's 1 */ +#define MCE_EN_MASK 0xEFFFFFFF + +/* For MCE Q_K bit 28 to 32 set to zero and other's 1 */ +#define MCE_Q_K_MASK 0x0FFFFFFF + +#define AE_BG_ENABLE_MASK 0x00000020 /* bit 5 */ +#define AF_BF_ENABLE_MASK 0x00000040 /* bit 6 */ +#define AWB_ENABLE_MASK 0x00000080 /* bit 7 */ +#define RS_ENABLE_MASK 0x00000100 /* bit 8 */ +#define CS_ENABLE_MASK 0x00000200 /* bit 9 */ +#define RS_CS_ENABLE_MASK 0x00000300 /* bit 8,9 */ +#define CLF_ENABLE_MASK 0x00002000 /* bit 13 */ +#define IHIST_ENABLE_MASK 0x00010000 /* bit 16 */ +#define STATS_ENABLE_MASK 0x000903E0 /* bit 19,16,9,8,7,6,5*/ + +#define VFE_REG_UPDATE_TRIGGER 1 +#define VFE_PM_BUF_MAX_CNT_MASK 0xFF +#define VFE_DMI_CFG_DEFAULT 0x00000100 +#define VFE_AE_PINGPONG_STATUS_BIT 0x80 +#define VFE_AF_PINGPONG_STATUS_BIT 0x100 +#define VFE_AWB_PINGPONG_STATUS_BIT 0x200 + +enum VFE32_DMI_RAM_SEL { + NO_MEM_SELECTED = 0, + BLACK_LUT_RAM_BANK0 = 0x1, + BLACK_LUT_RAM_BANK1 = 0x2, + ROLLOFF_RAM0_BANK0 = 0x3, + DEMOSAIC_LUT_RAM_BANK0 = 0x4, + DEMOSAIC_LUT_RAM_BANK1 = 0x5, + STATS_BHIST_RAM0 = 0x6, + STATS_BHIST_RAM1 = 0x7, + RGBLUT_RAM_CH0_BANK0 = 0x8, + RGBLUT_RAM_CH0_BANK1 = 0x9, + RGBLUT_RAM_CH1_BANK0 = 0xa, + RGBLUT_RAM_CH1_BANK1 = 0xb, + RGBLUT_RAM_CH2_BANK0 = 0xc, + RGBLUT_RAM_CH2_BANK1 = 0xd, + RGBLUT_CHX_BANK0 = 0xe, + RGBLUT_CHX_BANK1 = 0xf, + STATS_IHIST_RAM = 0x10, + LUMA_ADAPT_LUT_RAM_BANK0 = 0x11, + LUMA_ADAPT_LUT_RAM_BANK1 = 0x12, + ROLLOFF_RAM1_BANK0 = 0x13, + ROLLOFF_RAM0_BANK1 = 0x14, + ROLLOFF_RAM1_BANK1 = 0x15, +}; + +enum VFE_STATE { + VFE_STATE_IDLE, + VFE_STATE_ACTIVE +}; + +enum vfe_recording_state { + VFE_REC_STATE_IDLE, + VFE_REC_STATE_START_REQUESTED, + VFE_REC_STATE_STARTED, + VFE_REC_STATE_STOP_REQUESTED, + VFE_REC_STATE_STOPPED, +}; + +#define V32_CAMIF_OFF 0x000001E4 +#define V32_CAMIF_LEN 32 + +#define V32_DEMUX_OFF 0x00000284 +#define V32_DEMUX_LEN 20 + +#define V32_DEMOSAICV3_0_OFF 0x00000298 +#define V32_DEMOSAICV3_0_LEN 4 +#define V32_DEMOSAICV3_1_OFF 0x0000061C +#define V32_DEMOSAICV3_1_LEN 88 +#define V32_DEMOSAICV3_2_OFF 0x0000066C +#define V32_DEMOSAICV3_UP_REG_CNT 5 +/* BPC */ +#define V32_DEMOSAIC_2_OFF 0x0000029C +#define V32_DEMOSAIC_2_LEN 8 + +#define V32_OUT_CLAMP_OFF 0x00000524 +#define V32_OUT_CLAMP_LEN 8 + +#ifdef QC_TEST /*aswoogi_zsl*/ +#define V32_OPERATION_CFG_LEN 36 /*metadata*/ +#else +#define V32_OPERATION_CFG_LEN 32 +#endif + +#define V32_AXI_OUT_OFF 0x00000038 +#define V32_AXI_OUT_LEN 220 +#define V32_AXI_CH_INF_LEN 32 +#define V32_AXI_CFG_LEN 47 + +#define V32_FRAME_SKIP_OFF 0x00000504 +#define V32_FRAME_SKIP_LEN 32 + +#define V32_CHROMA_SUBS_OFF 0x000004F8 +#define V32_CHROMA_SUBS_LEN 12 + +#define V32_FOV_OFF 0x00000360 +#define V32_FOV_LEN 8 + +#define V32_MAIN_SCALER_OFF 0x00000368 +#define V32_MAIN_SCALER_LEN 28 + +#define V32_S2Y_OFF 0x000004D0 +#define V32_S2Y_LEN 20 + +#define V32_S2CbCr_OFF 0x000004E4 +#define V32_S2CbCr_LEN 20 + +#define V32_CHROMA_EN_OFF 0x000003C4 +#define V32_CHROMA_EN_LEN 36 + +#define V32_SYNC_TIMER_OFF 0x0000020C +#define V32_SYNC_TIMER_POLARITY_OFF 0x00000234 +#define V32_TIMER_SELECT_OFF 0x0000025C +#define V32_SYNC_TIMER_LEN 28 + +#define V32_ASYNC_TIMER_OFF 0x00000238 +#define V32_ASYNC_TIMER_LEN 28 + +#define V32_BLACK_LEVEL_OFF 0x00000264 +#define V32_BLACK_LEVEL_LEN 16 + +#define V32_MESH_ROLL_OFF_CFG_OFF 0x00000274 +#define V32_MESH_ROLL_OFF_CFG_LEN 16 +#define V32_MESH_ROLL_OFF_INIT_TABLE_SIZE 13 +#define V32_MESH_ROLL_OFF_DELTA_TABLE_SIZE 208 +#define V32_MESH_ROLL_OFF_DELTA_TABLE_OFFSET 32 +#define V32_GAMMA_LUT_BANK_SEL_MASK 0x00000007 + +#define V33_PCA_ROLL_OFF_CFG_LEN1 16 +#define V33_PCA_ROLL_OFF_CFG_OFF1 0x00000274 +#define V33_PCA_ROLL_OFF_CFG_LEN2 12 +#define V33_PCA_ROLL_OFF_CFG_OFF2 0x000007A8 +#define V33_PCA_ROLL_OFF_TABLE_SIZE (17 + (13*4)) +#define V33_PCA_ROLL_OFF_LUT_BANK_SEL_MASK 0x00010000 + +#define V32_COLOR_COR_OFF 0x00000388 +#define V32_COLOR_COR_LEN 52 + +#define V32_WB_OFF 0x00000384 +#define V32_WB_LEN 4 + +#define V32_RGB_G_OFF 0x000003BC +#define V32_RGB_G_LEN 4 + +#define V32_LA_OFF 0x000003C0 +#define V32_LA_LEN 4 + +#define V32_SCE_OFF 0x00000418 +#define V32_SCE_LEN 136 + +#define V32_CHROMA_SUP_OFF 0x000003E8 +#define V32_CHROMA_SUP_LEN 12 + +#define V32_MCE_OFF 0x000003F4 +#define V32_MCE_LEN 36 +#define V32_STATS_AF_OFF 0x0000053c +#define V32_STATS_AF_LEN 16 + +#define V32_STATS_AE_OFF 0x00000534 +#define V32_STATS_AE_LEN 8 + +#define V32_STATS_AWB_OFF 0x0000054c +#define V32_STATS_AWB_LEN 32 + +#define V32_STATS_IHIST_OFF 0x0000057c +#define V32_STATS_IHIST_LEN 8 + +#define V32_STATS_RS_OFF 0x0000056c +#define V32_STATS_RS_LEN 8 + +#define V32_STATS_CS_OFF 0x00000574 +#define V32_STATS_CS_LEN 8 + + +#define V32_ASF_OFF 0x000004A0 +#define V32_ASF_LEN 48 +#define V32_ASF_UPDATE_LEN 36 + +#define V32_CAPTURE_LEN 4 + +#define V32_GET_HW_VERSION_OFF 0 +#define V32_GET_HW_VERSION_LEN 4 + +#define V32_LINEARIZATION_OFF1 0x00000264 +#define V32_LINEARIZATION_LEN1 16 + +#define V32_LINEARIZATION_OFF2 0x0000067C +#define V32_LINEARIZATION_LEN2 52 + +#define V32_DEMOSAICV3_OFF 0x00000298 +#define V32_DEMOSAICV3_LEN 4 + +#define V32_DEMOSAICV3_DBPC_CFG_OFF 0x0000029C +#define V32_DEMOSAICV3_DBPC_LEN 4 + +#define V32_DEMOSAICV3_DBPC_CFG_OFF0 0x000002a0 +#define V32_DEMOSAICV3_DBPC_CFG_OFF1 0x00000604 +#define V32_DEMOSAICV3_DBPC_CFG_OFF2 0x00000608 + +#define V32_DEMOSAICV3_DBCC_OFF 0x0000060C +#define V32_DEMOSAICV3_DBCC_LEN 16 + +#define V32_DEMOSAICV3_ABF_OFF 0x000002A4 +#define V32_DEMOSAICV3_ABF_LEN 180 + +#define V32_MODULE_CFG_OFF 0x00000010 +#define V32_MODULE_CFG_LEN 4 + +#define V32_ASF_SPECIAL_EFX_CFG_OFF 0x000005FC +#define V32_ASF_SPECIAL_EFX_CFG_LEN 4 + +#define V32_CLF_CFG_OFF 0x000006B0 +#define V32_CLF_CFG_LEN 72 + +#define V32_CLF_LUMA_UPDATE_OFF 0x000006B4 +#define V32_CLF_LUMA_UPDATE_LEN 60 + +#define V32_CLF_CHROMA_UPDATE_OFF 0x000006F0 +#define V32_CLF_CHROMA_UPDATE_LEN 8 + +struct vfe_cmd_hw_version { + uint32_t minorVersion; + uint32_t majorVersion; + uint32_t coreVersion; +}; + +enum VFE_AXI_OUTPUT_MODE { + VFE_AXI_OUTPUT_MODE_Output1, + VFE_AXI_OUTPUT_MODE_Output2, + VFE_AXI_OUTPUT_MODE_Output1AndOutput2, + VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2, + VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1, + VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2, + VFE_AXI_LAST_OUTPUT_MODE_ENUM +}; + +enum VFE_RAW_WR_PATH_SEL { + VFE_RAW_OUTPUT_DISABLED, + VFE_RAW_OUTPUT_ENC_CBCR_PATH, + VFE_RAW_OUTPUT_VIEW_CBCR_PATH, + VFE_RAW_OUTPUT_PATH_INVALID +}; + + +#define VFE_AXI_OUTPUT_BURST_LENGTH 4 +#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4 +#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT 3 + +struct vfe_cmds_per_write_master { + uint16_t imageWidth; + uint16_t imageHeight; + uint16_t outRowCount; + uint16_t outRowIncrement; + uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT] + [VFE_MAX_NUM_FRAGMENTS_PER_FRAME]; +}; + +struct vfe_cmds_axi_per_output_path { + uint8_t fragmentCount; + struct vfe_cmds_per_write_master firstWM; + struct vfe_cmds_per_write_master secondWM; +}; + +enum VFE_AXI_BURST_LENGTH { + VFE_AXI_BURST_LENGTH_IS_2 = 2, + VFE_AXI_BURST_LENGTH_IS_4 = 4, + VFE_AXI_BURST_LENGTH_IS_8 = 8, + VFE_AXI_BURST_LENGTH_IS_16 = 16 +}; + + +struct vfe_cmd_fov_crop_config { + uint8_t enable; + uint16_t firstPixel; + uint16_t lastPixel; + uint16_t firstLine; + uint16_t lastLine; +}; + +struct vfe_cmds_main_scaler_stripe_init { + uint16_t MNCounterInit; + uint16_t phaseInit; +}; + +struct vfe_cmds_scaler_one_dimension { + uint8_t enable; + uint16_t inputSize; + uint16_t outputSize; + uint32_t phaseMultiplicationFactor; + uint8_t interpolationResolution; +}; + +struct vfe_cmd_main_scaler_config { + uint8_t enable; + struct vfe_cmds_scaler_one_dimension hconfig; + struct vfe_cmds_scaler_one_dimension vconfig; + struct vfe_cmds_main_scaler_stripe_init MNInitH; + struct vfe_cmds_main_scaler_stripe_init MNInitV; +}; + +struct vfe_cmd_scaler2_config { + uint8_t enable; + struct vfe_cmds_scaler_one_dimension hconfig; + struct vfe_cmds_scaler_one_dimension vconfig; +}; + + +struct vfe_cmd_frame_skip_update { + uint32_t output1Pattern; + uint32_t output2Pattern; +}; + +struct vfe_cmd_output_clamp_config { + uint8_t minCh0; + uint8_t minCh1; + uint8_t minCh2; + uint8_t maxCh0; + uint8_t maxCh1; + uint8_t maxCh2; +}; + +struct vfe_cmd_chroma_subsample_config { + uint8_t enable; + uint8_t cropEnable; + uint8_t vsubSampleEnable; + uint8_t hsubSampleEnable; + uint8_t vCosited; + uint8_t hCosited; + uint8_t vCositedPhase; + uint8_t hCositedPhase; + uint16_t cropWidthFirstPixel; + uint16_t cropWidthLastPixel; + uint16_t cropHeightFirstLine; + uint16_t cropHeightLastLine; +}; + +enum VFE_START_PIXEL_PATTERN { + VFE_BAYER_RGRGRG, + VFE_BAYER_GRGRGR, + VFE_BAYER_BGBGBG, + VFE_BAYER_GBGBGB, + VFE_YUV_YCbYCr, + VFE_YUV_YCrYCb, + VFE_YUV_CbYCrY, + VFE_YUV_CrYCbY +}; + +enum VFE_BUS_RD_INPUT_PIXEL_PATTERN { + VFE_BAYER_RAW, + VFE_YUV_INTERLEAVED, + VFE_YUV_PSEUDO_PLANAR_Y, + VFE_YUV_PSEUDO_PLANAR_CBCR +}; + +enum VFE_YUV_INPUT_COSITING_MODE { + VFE_YUV_COSITED, + VFE_YUV_INTERPOLATED +}; + +#define VFE32_GAMMA_NUM_ENTRIES 64 + +#define VFE32_LA_TABLE_LENGTH 64 + +#define VFE32_LINEARIZATON_TABLE_LENGTH 36 + +struct vfe_cmds_demosaic_abf { + uint8_t enable; + uint8_t forceOn; + uint8_t shift; + uint16_t lpThreshold; + uint16_t max; + uint16_t min; + uint8_t ratio; +}; + +struct vfe_cmds_demosaic_bpc { + uint8_t enable; + uint16_t fmaxThreshold; + uint16_t fminThreshold; + uint16_t redDiffThreshold; + uint16_t blueDiffThreshold; + uint16_t greenDiffThreshold; +}; + +struct vfe_cmd_demosaic_config { + uint8_t enable; + uint8_t slopeShift; + struct vfe_cmds_demosaic_abf abfConfig; + struct vfe_cmds_demosaic_bpc bpcConfig; +}; + +struct vfe_cmd_demosaic_bpc_update { + struct vfe_cmds_demosaic_bpc bpcUpdate; +}; + +struct vfe_cmd_demosaic_abf_update { + struct vfe_cmds_demosaic_abf abfUpdate; +}; + +struct vfe_cmd_white_balance_config { + uint8_t enable; + uint16_t ch2Gain; + uint16_t ch1Gain; + uint16_t ch0Gain; +}; + +enum VFE_COLOR_CORRECTION_COEF_QFACTOR { + COEF_IS_Q7_SIGNED, + COEF_IS_Q8_SIGNED, + COEF_IS_Q9_SIGNED, + COEF_IS_Q10_SIGNED +}; + +struct vfe_cmd_color_correction_config { + uint8_t enable; + enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor; + int16_t C0; + int16_t C1; + int16_t C2; + int16_t C3; + int16_t C4; + int16_t C5; + int16_t C6; + int16_t C7; + int16_t C8; + int16_t K0; + int16_t K1; + int16_t K2; +}; + +#define VFE_LA_TABLE_LENGTH 64 + +struct vfe_cmd_la_config { + uint8_t enable; + int16_t table[VFE_LA_TABLE_LENGTH]; +}; + +#define VFE_GAMMA_TABLE_LENGTH 256 +enum VFE_RGB_GAMMA_TABLE_SELECT { + RGB_GAMMA_CH0_SELECTED, + RGB_GAMMA_CH1_SELECTED, + RGB_GAMMA_CH2_SELECTED, + RGB_GAMMA_CH0_CH1_SELECTED, + RGB_GAMMA_CH0_CH2_SELECTED, + RGB_GAMMA_CH1_CH2_SELECTED, + RGB_GAMMA_CH0_CH1_CH2_SELECTED +}; + +struct vfe_cmd_rgb_gamma_config { + uint8_t enable; + enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect; + int16_t table[VFE_GAMMA_TABLE_LENGTH]; +}; + +struct vfe_cmd_chroma_enhan_config { + uint8_t enable; + int16_t am; + int16_t ap; + int16_t bm; + int16_t bp; + int16_t cm; + int16_t cp; + int16_t dm; + int16_t dp; + int16_t kcr; + int16_t kcb; + int16_t RGBtoYConversionV0; + int16_t RGBtoYConversionV1; + int16_t RGBtoYConversionV2; + uint8_t RGBtoYConversionOffset; +}; + +struct vfe_cmd_chroma_suppression_config { + uint8_t enable; + uint8_t m1; + uint8_t m3; + uint8_t n1; + uint8_t n3; + uint8_t nn1; + uint8_t mm1; +}; + +struct vfe_cmd_asf_config { + uint8_t enable; + uint8_t smoothFilterEnabled; + uint8_t sharpMode; + uint8_t smoothCoefCenter; + uint8_t smoothCoefSurr; + uint8_t normalizeFactor; + uint8_t sharpK1; + uint8_t sharpK2; + uint8_t sharpThreshE1; + int8_t sharpThreshE2; + int8_t sharpThreshE3; + int8_t sharpThreshE4; + int8_t sharpThreshE5; + int8_t filter1Coefficients[9]; + int8_t filter2Coefficients[9]; + uint8_t cropEnable; + uint16_t cropFirstPixel; + uint16_t cropLastPixel; + uint16_t cropFirstLine; + uint16_t cropLastLine; +}; + +struct vfe_cmd_asf_update { + uint8_t enable; + uint8_t smoothFilterEnabled; + uint8_t sharpMode; + uint8_t smoothCoefCenter; + uint8_t smoothCoefSurr; + uint8_t normalizeFactor; + uint8_t sharpK1; + uint8_t sharpK2; + uint8_t sharpThreshE1; + int8_t sharpThreshE2; + int8_t sharpThreshE3; + int8_t sharpThreshE4; + int8_t sharpThreshE5; + int8_t filter1Coefficients[9]; + int8_t filter2Coefficients[9]; + uint8_t cropEnable; +}; + +enum VFE_TEST_GEN_SYNC_EDGE { + VFE_TEST_GEN_SYNC_EDGE_ActiveHigh, + VFE_TEST_GEN_SYNC_EDGE_ActiveLow +}; + + +struct vfe_cmd_bus_pm_start { + uint8_t output2YWrPmEnable; + uint8_t output2CbcrWrPmEnable; + uint8_t output1YWrPmEnable; + uint8_t output1CbcrWrPmEnable; +}; + +struct vfe_frame_skip_counts { + uint32_t totalFrameCount; + uint32_t output1Count; + uint32_t output2Count; +}; + +enum VFE_AXI_RD_UNPACK_HBI_SEL { + VFE_AXI_RD_HBI_32_CLOCK_CYCLES, + VFE_AXI_RD_HBI_64_CLOCK_CYCLES, + VFE_AXI_RD_HBI_128_CLOCK_CYCLES, + VFE_AXI_RD_HBI_256_CLOCK_CYCLES, + VFE_AXI_RD_HBI_512_CLOCK_CYCLES, + VFE_AXI_RD_HBI_1024_CLOCK_CYCLES, + VFE_AXI_RD_HBI_2048_CLOCK_CYCLES, + VFE_AXI_RD_HBI_4096_CLOCK_CYCLES +}; + +struct vfe_frame_bpc_info { + uint32_t greenDefectPixelCount; + uint32_t redBlueDefectPixelCount; +}; + +struct vfe_frame_asf_info { + uint32_t asfMaxEdge; + uint32_t asfHbiCount; +}; + +struct vfe_msg_camif_status { + uint8_t camifState; + uint32_t pixelCount; + uint32_t lineCount; +}; + +struct vfe32_irq_status { + uint32_t vfeIrqStatus0; + uint32_t vfeIrqStatus1; + uint32_t camifStatus; + uint32_t demosaicStatus; + uint32_t asfMaxEdge; +}; + +#define V32_PREVIEW_AXI_FLAG 0x00000001 +#define V32_SNAPSHOT_AXI_FLAG (0x00000001<<1) + +struct vfe32_cmd_type { + uint16_t id; + uint32_t length; + uint32_t offset; + uint32_t flag; +}; + +struct vfe32_free_buf { + struct list_head node; + uint32_t paddr; + uint32_t y_off; + uint32_t cbcr_off; +}; + +struct vfe32_output_ch { + struct list_head free_buf_queue; + spinlock_t free_buf_lock; + uint16_t output_fmt; + int8_t ch0; + int8_t ch1; + int8_t ch2; + uint32_t capture_cnt; + uint32_t frame_drop_cnt; + struct msm_free_buf ping; + struct msm_free_buf pong; + struct msm_free_buf free_buf; +}; + +/* no error irq in mask 0 */ +#define VFE32_IMASK_ERROR_ONLY_0 0x0 +/* when normal case, don't want to block error status. */ +/* bit 0-21 are error irq bits */ +#define VFE32_IMASK_ERROR_ONLY_1 0x005FFFFF +#define VFE32_IMASK_CAMIF_ERROR (0x00000001<<0) +#define VFE32_IMASK_BHIST_OVWR (0x00000001<<1) +#define VFE32_IMASK_STATS_CS_OVWR (0x00000001<<2) +#define VFE32_IMASK_STATS_IHIST_OVWR (0x00000001<<3) +#define VFE32_IMASK_REALIGN_BUF_Y_OVFL (0x00000001<<4) +#define VFE32_IMASK_REALIGN_BUF_CB_OVFL (0x00000001<<5) +#define VFE32_IMASK_REALIGN_BUF_CR_OVFL (0x00000001<<6) +#define VFE32_IMASK_VIOLATION (0x00000001<<7) +#define VFE32_IMASK_IMG_MAST_0_BUS_OVFL (0x00000001<<8) +#define VFE32_IMASK_IMG_MAST_1_BUS_OVFL (0x00000001<<9) +#define VFE32_IMASK_IMG_MAST_2_BUS_OVFL (0x00000001<<10) +#define VFE32_IMASK_IMG_MAST_3_BUS_OVFL (0x00000001<<11) +#define VFE32_IMASK_IMG_MAST_4_BUS_OVFL (0x00000001<<12) +#define VFE32_IMASK_IMG_MAST_5_BUS_OVFL (0x00000001<<13) +#define VFE32_IMASK_IMG_MAST_6_BUS_OVFL (0x00000001<<14) +#define VFE32_IMASK_STATS_AE_BG_BUS_OVFL (0x00000001<<15) +#define VFE32_IMASK_STATS_AF_BF_BUS_OVFL (0x00000001<<16) +#define VFE32_IMASK_STATS_AWB_BUS_OVFL (0x00000001<<17) +#define VFE32_IMASK_STATS_RS_BUS_OVFL (0x00000001<<18) +#define VFE32_IMASK_STATS_CS_BUS_OVFL (0x00000001<<19) +#define VFE32_IMASK_STATS_IHIST_BUS_OVFL (0x00000001<<20) +#define VFE32_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<21) +#define VFE32_IMASK_AXI_ERROR (0x00000001<<22) + +struct vfe32_output_path { + uint16_t output_mode; /* bitmask */ + + struct vfe32_output_ch out0; /* preview and thumbnail */ + struct vfe32_output_ch out1; /* snapshot */ + struct vfe32_output_ch out2; /* video */ + struct vfe32_output_ch out3; /* jpeg soc */ +}; + +struct vfe32_frame_extra { + uint32_t greenDefectPixelCount; + uint32_t redBlueDefectPixelCount; + + uint32_t asfMaxEdge; + uint32_t asfHbiCount; + + uint32_t yWrPmStats0; + uint32_t yWrPmStats1; + uint32_t cbcrWrPmStats0; + uint32_t cbcrWrPmStats1; + + uint32_t frameCounter; +}; + +#define VFE_DISABLE_ALL_IRQS 0 +#define VFE_CLEAR_ALL_IRQS 0xffffffff + +#define VFE_HW_VERSION 0x00000000 +#define VFE_GLOBAL_RESET 0x00000004 +#define VFE_MODULE_RESET 0x00000008 +#define VFE_CGC_OVERRIDE 0x0000000C +#define VFE_MODULE_CFG 0x00000010 +#define VFE_CFG 0x00000014 +#define VFE_IRQ_CMD 0x00000018 +#define VFE_IRQ_MASK_0 0x0000001C +#define VFE_IRQ_MASK_1 0x00000020 +#define VFE_IRQ_CLEAR_0 0x00000024 +#define VFE_IRQ_CLEAR_1 0x00000028 +#define VFE_IRQ_STATUS_0 0x0000002C +#define VFE_IRQ_STATUS_1 0x00000030 +#define VFE_IRQ_COMP_MASK 0x00000034 +#define VFE_BUS_CMD 0x00000038 +#define VFE_BUS_PING_PONG_STATUS 0x00000180 +#define VFE_AXI_CMD 0x000001D8 +#define VFE_AXI_STATUS 0x000001DC +#define VFE_BUS_STATS_PING_PONG_BASE 0x000000F4 + +#define VFE_BUS_STATS_AEC_WR_PING_ADDR 0x000000F4 +#define VFE_BUS_STATS_AEC_WR_PONG_ADDR 0x000000F8 +#define VFE_BUS_STATS_AEC_UB_CFG 0x000000FC +#define VFE_BUS_STATS_AF_WR_PING_ADDR 0x00000100 +#define VFE_BUS_STATS_AF_WR_PONG_ADDR 0x00000104 +#define VFE_BUS_STATS_AF_UB_CFG 0x00000108 +#define VFE_BUS_STATS_AWB_WR_PING_ADDR 0x0000010C +#define VFE_BUS_STATS_AWB_WR_PONG_ADDR 0x00000110 +#define VFE_BUS_STATS_AWB_UB_CFG 0x00000114 +#define VFE_BUS_STATS_RS_WR_PING_ADDR 0x00000118 +#define VFE_BUS_STATS_RS_WR_PONG_ADDR 0x0000011C +#define VFE_BUS_STATS_RS_UB_CFG 0x00000120 + +#define VFE_BUS_STATS_CS_WR_PING_ADDR 0x00000124 +#define VFE_BUS_STATS_CS_WR_PONG_ADDR 0x00000128 +#define VFE_BUS_STATS_CS_UB_CFG 0x0000012C +#define VFE_BUS_STATS_HIST_WR_PING_ADDR 0x00000130 +#define VFE_BUS_STATS_HIST_WR_PONG_ADDR 0x00000134 +#define VFE_BUS_STATS_HIST_UB_CFG 0x00000138 +#define VFE_BUS_STATS_SKIN_WR_PING_ADDR 0x0000013C +#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR 0x00000140 +#define VFE_BUS_STATS_SKIN_UB_CFG 0x00000144 +#define VFE_CAMIF_COMMAND 0x000001E0 +#define VFE_CAMIF_STATUS 0x00000204 +#define VFE_REG_UPDATE_CMD 0x00000260 +#define VFE_DEMUX_GAIN_0 0x00000288 +#define VFE_DEMUX_GAIN_1 0x0000028C +#define VFE_CHROMA_UP 0x0000035C +#define VFE_FRAMEDROP_ENC_Y_CFG 0x00000504 +#define VFE_FRAMEDROP_ENC_CBCR_CFG 0x00000508 +#define VFE_FRAMEDROP_ENC_Y_PATTERN 0x0000050C +#define VFE_FRAMEDROP_ENC_CBCR_PATTERN 0x00000510 +#define VFE_FRAMEDROP_VIEW_Y 0x00000514 +#define VFE_FRAMEDROP_VIEW_CBCR 0x00000518 +#define VFE_FRAMEDROP_VIEW_Y_PATTERN 0x0000051C +#define VFE_FRAMEDROP_VIEW_CBCR_PATTERN 0x00000520 +#define VFE_CLAMP_MAX 0x00000524 +#define VFE_CLAMP_MIN 0x00000528 +#define VFE_REALIGN_BUF 0x0000052C +#define VFE_STATS_CFG 0x00000530 +#define VFE_DMI_CFG 0x00000598 +#define VFE_DMI_ADDR 0x0000059C +#define VFE_DMI_DATA_LO 0x000005A4 +#define VFE_BUS_IO_FORMAT_CFG 0x000006F8 +#define VFE_PIXEL_IF_CFG 0x000006FC +#define VFE_RDI_CFG0 0x00000734 /*aswoogi_zsl*/ + + +#define VFE33_DMI_DATA_HI 0x000005A0 +#define VFE33_DMI_DATA_LO 0x000005A4 + +#define VFE32_OUTPUT_MODE_PT (0x1 << 0) +#define VFE32_OUTPUT_MODE_S (0x1 << 1) +#define VFE32_OUTPUT_MODE_V (0x1 << 2) +#define VFE32_OUTPUT_MODE_P (0x1 << 3) +#define VFE32_OUTPUT_MODE_T (0x1 << 4) +#define VFE32_OUTPUT_MODE_P_ALL_CHNLS (0x1 << 5) + +struct vfe_stats_control { + uint8_t ackPending; + uint32_t nextFrameAddrBuf; + uint32_t droppedStatsFrameCount; + uint32_t bufToRender; +}; + +struct vfe32_ctrl_type { + uint16_t operation_mode; /* streaming or snapshot */ + struct vfe32_output_path outpath; + + uint32_t vfeImaskCompositePacked; + + spinlock_t stop_flag_lock; + spinlock_t update_ack_lock; + spinlock_t state_lock; + spinlock_t io_lock; + + spinlock_t aec_ack_lock; + spinlock_t awb_ack_lock; + spinlock_t af_ack_lock; + + uint32_t extlen; + void *extdata; + + int8_t start_ack_pending; + int8_t stop_ack_pending; + int8_t reset_ack_pending; + int8_t update_ack_pending; + enum vfe_recording_state recording_state; + int8_t update_linear; + int8_t update_rolloff; + int8_t update_la; + int8_t update_gamma; + + spinlock_t tasklet_lock; + struct list_head tasklet_q; + void __iomem *vfebase; + void *syncdata; + uint32_t register_total; + + struct resource *vfemem; + struct resource *vfeio; + struct resource *vfeirq; + struct regulator *fs_vfe; + + uint32_t stats_comp; + atomic_t vstate; + uint32_t vfe_capture_count; + uint32_t sync_timer_repeat_count; + uint32_t sync_timer_state; + uint32_t sync_timer_number; + + uint32_t vfeFrameId; + uint32_t rdi0FrameId; + uint32_t rdi1FrameId; + uint32_t output1Pattern; + uint32_t output1Period; + uint32_t output2Pattern; + uint32_t output2Period; + uint32_t vfeFrameSkipCount; + uint32_t vfeFrameSkipPeriod; + struct vfe_stats_control afStatsControl; + struct vfe_stats_control awbStatsControl; + struct vfe_stats_control aecStatsControl; + struct vfe_stats_control ihistStatsControl; + struct vfe_stats_control rsStatsControl; + struct vfe_stats_control csStatsControl; + uint32_t jpeg_soc; + /* v4l2 subdev */ + struct v4l2_subdev subdev; + struct platform_device *pdev; + struct clk *vfe_clk[3]; + spinlock_t sd_notify_lock; + struct tasklet_struct vfe32_tasklet; +}; + +#define statsAeNum 0 +#define statsAfNum 1 +#define statsAwbNum 2 +#define statsRsNum 3 +#define statsCsNum 4 +#define statsIhistNum 5 +#define statsSkinNum 6 + +struct vfe_cmd_stats_ack { + uint32_t nextStatsBuf; +}; + +#define VFE_STATS_BUFFER_COUNT 3 + +struct vfe_cmd_stats_buf { + uint32_t statsBuf[VFE_STATS_BUFFER_COUNT]; +}; + +static unsigned long pre_frame_sec = 0; +static unsigned long pre_frame_msec = 0; +static unsigned int no_free_buffer_count = 0; +static bool no_free_buffer_flag = 0; +#define TV_MSEC(x) x / 1000000 + +#endif /* __MSM_VFE32_H__ */ diff --git a/drivers/media/video/msm_zsl/msm_vfe7x.c b/drivers/media/video/msm_zsl/msm_vfe7x.c new file mode 100644 index 00000000000..316aacfc361 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe7x.c @@ -0,0 +1,783 @@ +/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_vfe7x.h" +#include + +#define QDSP_CMDQUEUE 25 + +#define VFE_RESET_CMD 0 +#define VFE_START_CMD 1 +#define VFE_STOP_CMD 2 +#define VFE_FRAME_ACK 20 +#define STATS_AF_ACK 21 +#define STATS_WE_ACK 22 + +#define MSG_STOP_ACK 1 +#define MSG_SNAPSHOT 2 +#define MSG_OUTPUT1 6 +#define MSG_OUTPUT2 7 +#define MSG_STATS_AF 8 +#define MSG_STATS_WE 9 +#define MSG_OUTPUT_S 10 +#define MSG_OUTPUT_T 11 + +#define VFE_ADSP_EVENT 0xFFFF +#define SNAPSHOT_MASK_MODE 0x00000002 +#define MSM_AXI_QOS_PREVIEW 192000 +#define MSM_AXI_QOS_SNAPSHOT 192000 + + +static struct msm_adsp_module *qcam_mod; +static struct msm_adsp_module *vfe_mod; +static struct msm_vfe_callback *resp; +static void *extdata; +static uint32_t extlen; + +struct mutex vfe_lock; +static void *vfe_syncdata; +static uint8_t vfestopped; +static uint32_t vfetask_state; +static int cnt; + +static struct stop_event stopevent; + +unsigned long paddr_s_y; +unsigned long paddr_s_cbcr; +unsigned long paddr_t_y; +unsigned long paddr_t_cbcr; + +static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo, + enum vfe_resp_msg type, + void *data, void **ext, int32_t *elen) +{ + switch (type) { + case VFE_MSG_OUTPUT_P: { + pinfo->y_phy = ((struct vfe_endframe *)data)->y_address; + pinfo->cbcr_phy = + ((struct vfe_endframe *)data)->cbcr_address; + + pinfo->output_id = OUTPUT_TYPE_P; + + CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n", + pinfo->y_phy, pinfo->cbcr_phy); + + ((struct vfe_frame_extra *)extdata)->bl_evencol = + ((struct vfe_endframe *)data)->blacklevelevencolumn; + + ((struct vfe_frame_extra *)extdata)->bl_oddcol = + ((struct vfe_endframe *)data)->blackleveloddcolumn; + + ((struct vfe_frame_extra *)extdata)->g_def_p_cnt = + ((struct vfe_endframe *)data)->greendefectpixelcount; + + ((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt = + ((struct vfe_endframe *)data)->redbluedefectpixelcount; + + *ext = extdata; + *elen = extlen; + } + break; + + case VFE_MSG_OUTPUT_S: { + pinfo->y_phy = paddr_s_y; + pinfo->cbcr_phy = paddr_s_cbcr; + pinfo->output_id = OUTPUT_TYPE_S; + CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n", + pinfo->y_phy, pinfo->cbcr_phy); + } + break; + + case VFE_MSG_OUTPUT_T: { + pinfo->y_phy = paddr_t_y; + pinfo->cbcr_phy = paddr_t_cbcr; + pinfo->output_id = OUTPUT_TYPE_T; + CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n", + pinfo->y_phy, pinfo->cbcr_phy); + } + break; + + case VFE_MSG_STATS_AF: + case VFE_MSG_STATS_WE: + pinfo->sbuf_phy = *(uint32_t *)data; + break; + + default: + break; + } /* switch */ +} + +static void vfe_7x_ops(void *driver_data, unsigned id, size_t len, + void (*getevent)(void *ptr, size_t len)) +{ + uint32_t evt_buf[3]; + struct msm_vfe_resp *rp; + void *data; + CDBG("%s:id=%d\n", __func__, id); + + len = (id == VFE_ADSP_EVENT) ? 0 : len; + data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, + vfe_syncdata, GFP_ATOMIC); + + if (!data) { + pr_err("%s: rp: cannot allocate buffer\n", __func__); + return; + } + rp = (struct msm_vfe_resp *)data; + rp->evt_msg.len = len; + + if (id == VFE_ADSP_EVENT) { + /* event */ + rp->type = VFE_EVENT; + rp->evt_msg.type = MSM_CAMERA_EVT; + getevent(evt_buf, sizeof(evt_buf)); + rp->evt_msg.msg_id = evt_buf[0]; + CDBG("%s:event:msg_id=%d\n", __func__, rp->evt_msg.msg_id); + resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT, vfe_syncdata, + GFP_ATOMIC); + } else { + /* messages */ + rp->evt_msg.type = MSM_CAMERA_MSG; + rp->evt_msg.msg_id = id; + rp->evt_msg.data = rp + 1; + getevent(rp->evt_msg.data, len); + CDBG("%s:messages:msg_id=%d\n", __func__, rp->evt_msg.msg_id); + + switch (rp->evt_msg.msg_id) { + case MSG_SNAPSHOT: + update_axi_qos(MSM_AXI_QOS_PREVIEW); + vfe_7x_ops(driver_data, MSG_OUTPUT_S, len, getevent); + vfe_7x_ops(driver_data, MSG_OUTPUT_T, len, getevent); + rp->type = VFE_MSG_SNAPSHOT; + break; + + case MSG_OUTPUT_S: + rp->type = VFE_MSG_OUTPUT_S; + vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_S, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + + case MSG_OUTPUT_T: + rp->type = VFE_MSG_OUTPUT_T; + vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_T, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + + case MSG_OUTPUT1: + case MSG_OUTPUT2: + rp->type = VFE_MSG_OUTPUT_P; + vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_P, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + + case MSG_STATS_AF: + rp->type = VFE_MSG_STATS_AF; + vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF, + rp->evt_msg.data, NULL, NULL); + break; + + case MSG_STATS_WE: + rp->type = VFE_MSG_STATS_WE; + vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE, + rp->evt_msg.data, NULL, NULL); + + CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy); + break; + + case MSG_STOP_ACK: + rp->type = VFE_MSG_GENERAL; + stopevent.state = 1; + wake_up(&stopevent.wait); + break; + + + default: + rp->type = VFE_MSG_GENERAL; + break; + } + resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata, GFP_ATOMIC); + } +} + +static struct msm_adsp_ops vfe_7x_sync = { + .event = vfe_7x_ops, +}; + +static int vfe_7x_enable(struct camera_enable_cmd *enable) +{ + int rc = -EFAULT; + + if (!strcmp(enable->name, "QCAMTASK")) + rc = msm_adsp_enable(qcam_mod); + else if (!strcmp(enable->name, "VFETASK")) { + rc = msm_adsp_enable(vfe_mod); + vfetask_state = 1; + } + + if (!cnt) { + add_axi_qos(); + cnt++; + } + return rc; +} + +static int vfe_7x_disable(struct camera_enable_cmd *enable, + struct platform_device *dev __attribute__((unused))) +{ + int rc = -EFAULT; + + if (!strcmp(enable->name, "QCAMTASK")) + rc = msm_adsp_disable(qcam_mod); + else if (!strcmp(enable->name, "VFETASK")) { + rc = msm_adsp_disable(vfe_mod); + vfetask_state = 0; + } + + return rc; +} + +static int vfe_7x_stop(void) +{ + int rc = 0; + uint32_t stopcmd = VFE_STOP_CMD; + rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE, + &stopcmd, sizeof(uint32_t)); + if (rc < 0) { + CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc); + return rc; + } + + stopevent.state = 0; + rc = wait_event_timeout(stopevent.wait, + stopevent.state != 0, + msecs_to_jiffies(stopevent.timeout)); + + return rc; +} + +static void vfe_7x_release(struct platform_device *pdev) +{ + mutex_lock(&vfe_lock); + vfe_syncdata = NULL; + mutex_unlock(&vfe_lock); + + if (!vfestopped) { + CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__); + vfe_7x_stop(); + } else + vfestopped = 0; + + msm_adsp_disable(qcam_mod); + msm_adsp_disable(vfe_mod); + vfetask_state = 0; + + msm_adsp_put(qcam_mod); + msm_adsp_put(vfe_mod); + + msm_camio_disable(pdev); + + kfree(extdata); + extlen = 0; + + /* Release AXI */ + release_axi_qos(); + cnt = 0; +} + +static int vfe_7x_init(struct msm_vfe_callback *presp, + struct platform_device *dev) +{ + int rc = 0; + + init_waitqueue_head(&stopevent.wait); + stopevent.timeout = 200; + stopevent.state = 0; + + if (presp && presp->vfe_resp) + resp = presp; + else + return -EFAULT; + + /* Bring up all the required GPIOs and Clocks */ + rc = msm_camio_enable(dev); + if (rc < 0) + return rc; + msm_camio_camif_pad_reg_reset(); + + extlen = sizeof(struct vfe_frame_extra); + + extdata = + kmalloc(extlen, GFP_ATOMIC); + if (!extdata) { + rc = -ENOMEM; + goto init_fail; + } + + rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL); + if (rc) { + rc = -EBUSY; + goto get_qcam_fail; + } + + rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL); + if (rc) { + rc = -EBUSY; + goto get_vfe_fail; + } + + return 0; + +get_vfe_fail: + msm_adsp_put(qcam_mod); +get_qcam_fail: + kfree(extdata); +init_fail: + extlen = 0; + return rc; +} + +static int vfe_7x_config_axi(int mode, + struct axidata *ad, struct axiout *ao) +{ + struct msm_pmem_region *regptr; + unsigned long *bptr; + int cnt; + + int rc = 0; + + if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) { + regptr = ad->region; + + CDBG("bufnum1 = %d\n", ad->bufnum1); + if (mode == OUTPUT_1_AND_2) { + paddr_t_y = regptr->paddr + regptr->info.y_off; + paddr_t_cbcr = regptr->paddr + regptr->info.cbcr_off; + } + + CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n", + regptr->paddr, regptr->info.y_off, + regptr->info.cbcr_off); + + bptr = &ao->output1buffer1_y_phy; + for (cnt = 0; cnt < ad->bufnum1; cnt++) { + *bptr = regptr->paddr + regptr->info.y_off; + bptr++; + *bptr = regptr->paddr + regptr->info.cbcr_off; + + bptr++; + regptr++; + } + + regptr--; + for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) { + *bptr = regptr->paddr + regptr->info.y_off; + bptr++; + *bptr = regptr->paddr + regptr->info.cbcr_off; + bptr++; + } + } /* if OUTPUT1 or Both */ + + if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) { + regptr = &(ad->region[ad->bufnum1]); + + CDBG("bufnum2 = %d\n", ad->bufnum2); + paddr_s_y = regptr->paddr + regptr->info.y_off; + paddr_s_cbcr = regptr->paddr + regptr->info.cbcr_off; + CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n", + regptr->paddr, regptr->info.y_off, regptr->info.cbcr_off); + + bptr = &ao->output2buffer1_y_phy; + for (cnt = 0; cnt < ad->bufnum2; cnt++) { + *bptr = regptr->paddr + regptr->info.y_off; + bptr++; + *bptr = regptr->paddr + regptr->info.cbcr_off; + + bptr++; + regptr++; + } + + regptr--; + for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) { + *bptr = regptr->paddr + regptr->info.y_off; + bptr++; + *bptr = regptr->paddr + regptr->info.cbcr_off; + bptr++; + } + } + + return rc; +} + +static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data) +{ + struct msm_pmem_region *regptr; + unsigned char buf[256]; + + struct vfe_stats_ack sack; + struct axidata *axid; + uint32_t i, op_mode; + uint32_t *_mode; + + struct vfe_stats_we_cfg *scfg = NULL; + struct vfe_stats_af_cfg *sfcfg = NULL; + + struct axiout *axio = NULL; + void *cmd_data = NULL; + void *cmd_data_alloc = NULL; + long rc = 0; + struct msm_vfe_command_7k *vfecmd; + + vfecmd = + kmalloc(sizeof(struct msm_vfe_command_7k), + GFP_ATOMIC); + if (!vfecmd) { + pr_err("vfecmd alloc failed!\n"); + return -ENOMEM; + } + + if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) { + if (copy_from_user(vfecmd, + (void __user *)(cmd->value), + sizeof(struct msm_vfe_command_7k))) { + rc = -EFAULT; + goto config_failure; + } + } + + switch (cmd->cmd_type) { + case CMD_STATS_AEC_AWB_ENABLE: + case CMD_STATS_AXI_CFG: { + axid = data; + if (!axid) { + rc = -EFAULT; + goto config_failure; + } + + scfg = + kmalloc(sizeof(struct vfe_stats_we_cfg), + GFP_ATOMIC); + if (!scfg) { + rc = -ENOMEM; + goto config_failure; + } + + if (copy_from_user(scfg, + (void __user *)(vfecmd->value), + vfecmd->length)) { + + rc = -EFAULT; + goto config_done; + } + + CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n", + axid->bufnum1, scfg->wb_expstatsenable); + + if (axid->bufnum1 > 0) { + regptr = axid->region; + + for (i = 0; i < axid->bufnum1; i++) { + + CDBG("STATS_ENABLE, phy = 0x%lx\n", + regptr->paddr); + + scfg->wb_expstatoutputbuffer[i] = + (void *)regptr->paddr; + regptr++; + } + + cmd_data = scfg; + + } else { + rc = -EINVAL; + goto config_done; + } + } + break; + + case CMD_STATS_AF_ENABLE: + case CMD_STATS_AF_AXI_CFG: { + axid = data; + if (!axid) { + rc = -EFAULT; + goto config_failure; + } + + sfcfg = + kmalloc(sizeof(struct vfe_stats_af_cfg), + GFP_ATOMIC); + + if (!sfcfg) { + rc = -ENOMEM; + goto config_failure; + } + + if (copy_from_user(sfcfg, + (void __user *)(vfecmd->value), + vfecmd->length)) { + + rc = -EFAULT; + goto config_done; + } + + CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n", + axid->bufnum1, sfcfg->af_enable); + + if (axid->bufnum1 > 0) { + regptr = &axid->region[0]; + + for (i = 0; i < axid->bufnum1; i++) { + + CDBG("STATS_ENABLE, phy = 0x%lx\n", + regptr->paddr); + + sfcfg->af_outbuf[i] = + (void *)regptr->paddr; + + regptr++; + } + + cmd_data = sfcfg; + + } else { + rc = -EINVAL; + goto config_done; + } + } + break; + + case CMD_FRAME_BUF_RELEASE: { + struct msm_frame *b; + unsigned long p; + struct vfe_outputack fack; + if (!data) { + rc = -EFAULT; + goto config_failure; + } + + b = (struct msm_frame *)(cmd->value); + p = *(unsigned long *)data; + + fack.header = VFE_FRAME_ACK; + + fack.output2newybufferaddress = + (void *)(p + b->y_off); + + fack.output2newcbcrbufferaddress = + (void *)(p + b->cbcr_off); + + vfecmd->queue = QDSP_CMDQUEUE; + vfecmd->length = sizeof(struct vfe_outputack); + cmd_data = &fack; + } + break; + + case CMD_SNAP_BUF_RELEASE: + break; + + case CMD_STATS_BUF_RELEASE: { + CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n"); + if (!data) { + rc = -EFAULT; + goto config_failure; + } + + sack.header = STATS_WE_ACK; + sack.bufaddr = (void *)*(uint32_t *)data; + + vfecmd->queue = QDSP_CMDQUEUE; + vfecmd->length = sizeof(struct vfe_stats_ack); + cmd_data = &sack; + } + break; + + case CMD_STATS_AF_BUF_RELEASE: { + CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n"); + if (!data) { + rc = -EFAULT; + goto config_failure; + } + + sack.header = STATS_AF_ACK; + sack.bufaddr = (void *)*(uint32_t *)data; + + vfecmd->queue = QDSP_CMDQUEUE; + vfecmd->length = sizeof(struct vfe_stats_ack); + cmd_data = &sack; + } + break; + + case CMD_GENERAL: + case CMD_STATS_DISABLE: { + if (vfecmd->length > 256) { + cmd_data_alloc = + cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC); + if (!cmd_data) { + rc = -ENOMEM; + goto config_failure; + } + } else + cmd_data = buf; + + if (copy_from_user(cmd_data, + (void __user *)(vfecmd->value), + vfecmd->length)) { + + rc = -EFAULT; + goto config_done; + } + + if (vfecmd->queue == QDSP_CMDQUEUE) { + switch (*(uint32_t *)cmd_data) { + case VFE_RESET_CMD: + msm_camio_vfe_blk_reset(); + vfestopped = 0; + break; + + case VFE_START_CMD: + _mode = (uint32_t *)cmd_data; + op_mode = *(++_mode); + if (op_mode & SNAPSHOT_MASK_MODE) { + /* request AXI bus for snapshot */ + if (update_axi_qos(MSM_AXI_QOS_SNAPSHOT) + < 0) { + rc = -EFAULT; + goto config_failure; + } + } else { + /* request AXI bus for snapshot */ + if (update_axi_qos(MSM_AXI_QOS_PREVIEW) + < 0) { + rc = -EFAULT; + goto config_failure; + } + } + msm_camio_camif_pad_reg_reset_2(); + vfestopped = 0; + break; + + case VFE_STOP_CMD: + vfestopped = 1; + goto config_send; + + default: + break; + } + } /* QDSP_CMDQUEUE */ + } + break; + case CMD_AXI_CFG_PREVIEW: + case CMD_RAW_PICT_AXI_CFG: { + axid = data; + if (!axid) { + rc = -EFAULT; + goto config_failure; + } + + axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + goto config_failure; + } + + if (copy_from_user(axio, (void __user *)(vfecmd->value), + sizeof(struct axiout))) { + rc = -EFAULT; + goto config_done; + } + + vfe_7x_config_axi(OUTPUT_2, axid, axio); + cmd_data = axio; + } + break; + + case CMD_AXI_CFG_SNAP: { + axid = data; + if (!axid) { + rc = -EFAULT; + goto config_failure; + } + + axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + goto config_failure; + } + + if (copy_from_user(axio, (void __user *)(vfecmd->value), + sizeof(struct axiout))) { + rc = -EFAULT; + goto config_done; + } + + vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio); + + cmd_data = axio; + } + break; + + default: + break; + } /* switch */ + + if (vfestopped) + goto config_done; + +config_send: + CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data); + if (vfetask_state) + rc = msm_adsp_write(vfe_mod, vfecmd->queue, + cmd_data, vfecmd->length); +config_done: + if (cmd_data_alloc != NULL) + kfree(cmd_data_alloc); + +config_failure: + kfree(scfg); + kfree(axio); + kfree(vfecmd); + return rc; +} + +void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data) +{ + mutex_init(&vfe_lock); + fptr->vfe_init = vfe_7x_init; + fptr->vfe_enable = vfe_7x_enable; + fptr->vfe_config = vfe_7x_config; + fptr->vfe_disable = vfe_7x_disable; + fptr->vfe_release = vfe_7x_release; + vfe_syncdata = data; +} + +void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data) +{ + fptr->vpe_reg = NULL; + fptr->send_frame_to_vpe = NULL; + fptr->vpe_config = NULL; + fptr->vpe_cfg_update = NULL; + fptr->dis = NULL; +} diff --git a/drivers/media/video/msm_zsl/msm_vfe7x.h b/drivers/media/video/msm_zsl/msm_vfe7x.h new file mode 100644 index 00000000000..51a480d1fda --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe7x.h @@ -0,0 +1,265 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __MSM_VFE7X_H__ +#define __MSM_VFE7X_H__ +#include +#include + +struct vfe_frame_extra { + uint32_t bl_evencol; + uint32_t bl_oddcol; + uint16_t g_def_p_cnt; + uint16_t r_b_def_p_cnt; +}; + +struct vfe_endframe { + uint32_t y_address; + uint32_t cbcr_address; + + unsigned int blacklevelevencolumn:23; + uint16_t reserved1:9; + unsigned int blackleveloddcolumn:23; + uint16_t reserved2:9; + + uint16_t greendefectpixelcount:8; + uint16_t reserved3:8; + uint16_t redbluedefectpixelcount:8; + uint16_t reserved4:8; +} __attribute__((packed, aligned(4))); + +struct vfe_outputack { + uint32_t header; + void *output2newybufferaddress; + void *output2newcbcrbufferaddress; +} __attribute__((packed, aligned(4))); + +struct vfe_stats_ack { + uint32_t header; + /* MUST BE 64 bit ALIGNED */ + void *bufaddr; +} __attribute__((packed, aligned(4))); + +/* AXI Output Config Command sent to DSP */ +struct axiout { + uint32_t cmdheader:32; + int outputmode:3; + uint8_t format:2; + uint32_t /* reserved */ : 27; + + /* AXI Output 1 Y Configuration, Part 1 */ + uint32_t out1yimageheight:12; + uint32_t /* reserved */ : 4; + uint32_t out1yimagewidthin64bitwords:10; + uint32_t /* reserved */ : 6; + + /* AXI Output 1 Y Configuration, Part 2 */ + uint8_t out1yburstlen:2; + uint32_t out1ynumrows:12; + uint32_t out1yrowincin64bitincs:12; + uint32_t /* reserved */ : 6; + + /* AXI Output 1 CbCr Configuration, Part 1 */ + uint32_t out1cbcrimageheight:12; + uint32_t /* reserved */ : 4; + uint32_t out1cbcrimagewidthin64bitwords:10; + uint32_t /* reserved */ : 6; + + /* AXI Output 1 CbCr Configuration, Part 2 */ + uint8_t out1cbcrburstlen:2; + uint32_t out1cbcrnumrows:12; + uint32_t out1cbcrrowincin64bitincs:12; + uint32_t /* reserved */ : 6; + + /* AXI Output 2 Y Configuration, Part 1 */ + uint32_t out2yimageheight:12; + uint32_t /* reserved */ : 4; + uint32_t out2yimagewidthin64bitwords:10; + uint32_t /* reserved */ : 6; + + /* AXI Output 2 Y Configuration, Part 2 */ + uint8_t out2yburstlen:2; + uint32_t out2ynumrows:12; + uint32_t out2yrowincin64bitincs:12; + uint32_t /* reserved */ : 6; + + /* AXI Output 2 CbCr Configuration, Part 1 */ + uint32_t out2cbcrimageheight:12; + uint32_t /* reserved */ : 4; + uint32_t out2cbcrimagewidtein64bitwords:10; + uint32_t /* reserved */ : 6; + + /* AXI Output 2 CbCr Configuration, Part 2 */ + uint8_t out2cbcrburstlen:2; + uint32_t out2cbcrnumrows:12; + uint32_t out2cbcrrowincin64bitincs:12; + uint32_t /* reserved */ : 6; + + /* Address configuration: + * output1 phisycal address */ + unsigned long output1buffer1_y_phy; + unsigned long output1buffer1_cbcr_phy; + unsigned long output1buffer2_y_phy; + unsigned long output1buffer2_cbcr_phy; + unsigned long output1buffer3_y_phy; + unsigned long output1buffer3_cbcr_phy; + unsigned long output1buffer4_y_phy; + unsigned long output1buffer4_cbcr_phy; + unsigned long output1buffer5_y_phy; + unsigned long output1buffer5_cbcr_phy; + unsigned long output1buffer6_y_phy; + unsigned long output1buffer6_cbcr_phy; + unsigned long output1buffer7_y_phy; + unsigned long output1buffer7_cbcr_phy; + unsigned long output1buffer8_y_phy; + unsigned long output1buffer8_cbcr_phy; + + /* output2 phisycal address */ + unsigned long output2buffer1_y_phy; + unsigned long output2buffer1_cbcr_phy; + unsigned long output2buffer2_y_phy; + unsigned long output2buffer2_cbcr_phy; + unsigned long output2buffer3_y_phy; + unsigned long output2buffer3_cbcr_phy; + unsigned long output2buffer4_y_phy; + unsigned long output2buffer4_cbcr_phy; + unsigned long output2buffer5_y_phy; + unsigned long output2buffer5_cbcr_phy; + unsigned long output2buffer6_y_phy; + unsigned long output2buffer6_cbcr_phy; + unsigned long output2buffer7_y_phy; + unsigned long output2buffer7_cbcr_phy; + unsigned long output2buffer8_y_phy; + unsigned long output2buffer8_cbcr_phy; +} __attribute__((packed, aligned(4))); + +struct vfe_stats_we_cfg { + uint32_t header; + + /* White Balance/Exposure Statistic Selection */ + uint8_t wb_expstatsenable:1; + uint8_t wb_expstatbuspriorityselection:1; + unsigned int wb_expstatbuspriorityvalue:4; + unsigned int /* reserved */ : 26; + + /* White Balance/Exposure Statistic Configuration, Part 1 */ + uint8_t exposurestatregions:1; + uint8_t exposurestatsubregions:1; + unsigned int /* reserved */ : 14; + + unsigned int whitebalanceminimumy:8; + unsigned int whitebalancemaximumy:8; + + /* White Balance/Exposure Statistic Configuration, Part 2 */ + uint8_t wb_expstatslopeofneutralregionline[ + NUM_WB_EXP_NEUTRAL_REGION_LINES]; + + /* White Balance/Exposure Statistic Configuration, Part 3 */ + unsigned int wb_expstatcrinterceptofneutralregionline2:12; + unsigned int /* reserved */ : 4; + unsigned int wb_expstatcbinterceptofneutralreginnline1:12; + unsigned int /* reserved */ : 4; + + /* White Balance/Exposure Statistic Configuration, Part 4 */ + unsigned int wb_expstatcrinterceptofneutralregionline4:12; + unsigned int /* reserved */ : 4; + unsigned int wb_expstatcbinterceptofneutralregionline3:12; + unsigned int /* reserved */ : 4; + + /* White Balance/Exposure Statistic Output Buffer Header */ + unsigned int wb_expmetricheaderpattern:8; + unsigned int /* reserved */ : 24; + + /* White Balance/Exposure Statistic Output Buffers-MUST + * BE 64 bit ALIGNED */ + void *wb_expstatoutputbuffer[NUM_WB_EXP_STAT_OUTPUT_BUFFERS]; +} __attribute__((packed, aligned(4))); + +struct vfe_stats_af_cfg { + uint32_t header; + + /* Autofocus Statistic Selection */ + uint8_t af_enable:1; + uint8_t af_busprioritysel:1; + unsigned int af_buspriorityval:4; + unsigned int /* reserved */ : 26; + + /* Autofocus Statistic Configuration, Part 1 */ + unsigned int af_singlewinvoffset:12; + unsigned int /* reserved */ : 4; + unsigned int af_singlewinhoffset:12; + unsigned int /* reserved */ : 3; + uint8_t af_winmode:1; + + /* Autofocus Statistic Configuration, Part 2 */ + unsigned int af_singglewinvh:11; + unsigned int /* reserved */ : 5; + unsigned int af_singlewinhw:11; + unsigned int /* reserved */ : 5; + + /* Autofocus Statistic Configuration, Parts 3-6 */ + uint8_t af_multiwingrid[NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS]; + + /* Autofocus Statistic Configuration, Part 7 */ + signed int af_metrichpfcoefa00:5; + signed int af_metrichpfcoefa04:5; + unsigned int af_metricmaxval:11; + uint8_t af_metricsel:1; + unsigned int /* reserved */ : 10; + + /* Autofocus Statistic Configuration, Part 8 */ + signed int af_metrichpfcoefa20:5; + signed int af_metrichpfcoefa21:5; + signed int af_metrichpfcoefa22:5; + signed int af_metrichpfcoefa23:5; + signed int af_metrichpfcoefa24:5; + unsigned int /* reserved */ : 7; + + /* Autofocus Statistic Output Buffer Header */ + unsigned int af_metrichp:8; + unsigned int /* reserved */ : 24; + + /* Autofocus Statistic Output Buffers - MUST BE 64 bit ALIGNED!!! */ + void *af_outbuf[NUM_AF_STAT_OUTPUT_BUFFERS]; +} __attribute__((packed, aligned(4))); /* VFE_StatsAutofocusConfigCmdType */ + +struct msm_camera_frame_msg { + unsigned long output_y_address; + unsigned long output_cbcr_address; + + unsigned int blacklevelevenColumn:23; + uint16_t reserved1:9; + unsigned int blackleveloddColumn:23; + uint16_t reserved2:9; + + uint16_t greendefectpixelcount:8; + uint16_t reserved3:8; + uint16_t redbluedefectpixelcount:8; + uint16_t reserved4:8; +} __attribute__((packed, aligned(4))); + +/* New one for 7k */ +struct msm_vfe_command_7k { + uint16_t queue; + uint16_t length; + void *value; +}; + +struct stop_event { + wait_queue_head_t wait; + int state; + int timeout; +}; + + +#endif /* __MSM_VFE7X_H__ */ diff --git a/drivers/media/video/msm_zsl/msm_vfe7x27a.c b/drivers/media/video/msm_zsl/msm_vfe7x27a.c new file mode 100644 index 00000000000..9f7dff71a68 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe7x27a.c @@ -0,0 +1,741 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_vfe7x27a.h" + +#define QDSP_CMDQUEUE 25 + +#define VFE_RESET_CMD 0 +#define VFE_START_CMD 1 +#define VFE_STOP_CMD 2 +#define VFE_FRAME_ACK 20 +#define STATS_AF_ACK 21 +#define STATS_WE_ACK 22 + +#define MSG_STOP_ACK 1 +#define MSG_SNAPSHOT 2 +#define MSG_OUTPUT1 6 +#define MSG_OUTPUT2 7 +#define MSG_STATS_AF 8 +#define MSG_STATS_WE 9 +#define MSG_OUTPUT_S 23 +#define MSG_OUTPUT_T 22 +#define MSG_SOF 15 + +#define VFE_ADSP_EVENT 0xFFFF +#define SNAPSHOT_MASK_MODE 0x00000002 +#define MSM_AXI_QOS_PREVIEW 122000 +#define MSM_AXI_QOS_SNAPSHOT 192000 + + +static struct msm_adsp_module *qcam_mod; +static struct msm_adsp_module *vfe_mod; +static struct msm_vfe_callback *resp; +static void *extdata; +static uint32_t extlen; + +struct mutex vfe_lock; +static void *vfe_syncdata; +static uint8_t vfestopped; + +static struct stop_event stopevent; + +unsigned long paddr_s_y; +unsigned long paddr_s_cbcr; +unsigned long paddr_t_y; +unsigned long paddr_t_cbcr; +static uint32_t op_mode; + +static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo, + enum vfe_resp_msg type, + void *data, void **ext, int32_t *elen) +{ + switch (type) { + case VFE_MSG_OUTPUT_P: { + pinfo->y_phy = ((struct vfe_endframe *)data)->y_address; + pinfo->cbcr_phy = + ((struct vfe_endframe *)data)->cbcr_address; + + pinfo->output_id = OUTPUT_TYPE_P; + + CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n", + pinfo->y_phy, pinfo->cbcr_phy); + + memcpy(((struct vfe_frame_extra *)extdata), + &((struct vfe_endframe *)data)->extra, + sizeof(struct vfe_frame_extra)); + + *ext = extdata; + *elen = extlen; + pinfo->frame_id = + ((struct vfe_frame_extra *)extdata)->frame_id; + } + break; + case VFE_MSG_OUTPUT_S: { + pinfo->y_phy = paddr_s_y; + pinfo->cbcr_phy = paddr_s_cbcr; + pinfo->output_id = OUTPUT_TYPE_S; + CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n", + pinfo->y_phy, pinfo->cbcr_phy); + } + break; + case VFE_MSG_OUTPUT_T: { + pinfo->y_phy = paddr_t_y; + pinfo->cbcr_phy = paddr_t_cbcr; + pinfo->output_id = OUTPUT_TYPE_T; + CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n", + pinfo->y_phy, pinfo->cbcr_phy); + } + break; + case VFE_MSG_STATS_AF: + case VFE_MSG_STATS_WE: + pinfo->sbuf_phy = *(uint32_t *)data; + pinfo->frame_id = *(((uint32_t *)data) + 1); + CDBG("frame id = %d\n", pinfo->frame_id); + break; + default: + break; + } +} + +static void vfe_7x_ops(void *driver_data, unsigned id, size_t len, + void (*getevent)(void *ptr, size_t len)) +{ + uint32_t evt_buf[3]; + struct msm_vfe_resp *rp; + void *data; + CDBG("%s:id=%d\n", __func__, id); + + len = (id == VFE_ADSP_EVENT) ? 0 : len; + data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, + vfe_syncdata, GFP_ATOMIC); + + if (!data) { + pr_err("%s: rp: cannot allocate buffer\n", __func__); + return; + } + rp = data; + rp->evt_msg.len = len; + + if (id == VFE_ADSP_EVENT) { + /* event */ + rp->type = VFE_EVENT; + rp->evt_msg.type = MSM_CAMERA_EVT; + getevent(evt_buf, sizeof(evt_buf)); + rp->evt_msg.msg_id = evt_buf[0]; + CDBG("%s:event:msg_id=%d\n", __func__, rp->evt_msg.msg_id); + resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT, vfe_syncdata, + GFP_ATOMIC); + } else { + /* messages */ + rp->evt_msg.type = MSM_CAMERA_MSG; + rp->evt_msg.msg_id = id; + rp->evt_msg.data = rp + 1; + getevent(rp->evt_msg.data, len); + CDBG("%s:messages:msg_id=%d\n", __func__, rp->evt_msg.msg_id); + + switch (rp->evt_msg.msg_id) { + case MSG_SNAPSHOT: + msm_camio_set_perf_lvl(S_PREVIEW); + vfe_7x_ops(driver_data, MSG_OUTPUT_S, len, getevent); + vfe_7x_ops(driver_data, MSG_OUTPUT_T, len, getevent); + rp->type = VFE_MSG_SNAPSHOT; + break; + case MSG_OUTPUT_S: + rp->type = VFE_MSG_OUTPUT_S; + vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_S, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + case MSG_OUTPUT_T: + rp->type = VFE_MSG_OUTPUT_T; + vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_T, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + case MSG_OUTPUT1: + case MSG_OUTPUT2: + if (op_mode & SNAPSHOT_MASK_MODE) { + resp->vfe_free(data); + return; + } + rp->type = VFE_MSG_OUTPUT_P; + vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_P, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + case MSG_STATS_AF: + rp->type = VFE_MSG_STATS_AF; + vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF, + rp->evt_msg.data, NULL, NULL); + break; + case MSG_STATS_WE: + rp->type = VFE_MSG_STATS_WE; + vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE, + rp->evt_msg.data, NULL, NULL); + + CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy); + break; + case MSG_STOP_ACK: + rp->type = VFE_MSG_GENERAL; + stopevent.state = 1; + wake_up(&stopevent.wait); + break; + default: + rp->type = VFE_MSG_GENERAL; + break; + } + if (id != MSG_SOF) + resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, + vfe_syncdata, GFP_ATOMIC); + } +} + +static struct msm_adsp_ops vfe_7x_sync = { + .event = vfe_7x_ops, +}; + +static int vfe_7x_enable(struct camera_enable_cmd *enable) +{ + int rc = -EFAULT; + static int cnt; + + if (!strcmp(enable->name, "QCAMTASK")) + rc = msm_adsp_enable(qcam_mod); + else if (!strcmp(enable->name, "VFETASK")) + rc = msm_adsp_enable(vfe_mod); + + if (!cnt) { + msm_camio_set_perf_lvl(S_INIT); + cnt++; + } + return rc; +} + +static int vfe_7x_disable(struct camera_enable_cmd *enable, + struct platform_device *dev __attribute__((unused))) +{ + int rc = -EFAULT; + + if (!strcmp(enable->name, "QCAMTASK")) + rc = msm_adsp_disable(qcam_mod); + else if (!strcmp(enable->name, "VFETASK")) + rc = msm_adsp_disable(vfe_mod); + + return rc; +} + +static int vfe_7x_stop(void) +{ + int rc = 0; + uint32_t stopcmd = VFE_STOP_CMD; + rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE, + &stopcmd, sizeof(uint32_t)); + if (rc < 0) { + CDBG("%s:%d: failed rc = %d\n", __func__, __LINE__, rc); + return rc; + } + + stopevent.state = 0; + rc = wait_event_timeout(stopevent.wait, + stopevent.state != 0, + msecs_to_jiffies(stopevent.timeout)); + + return rc; +} + +static void vfe_7x_release(struct platform_device *pdev) +{ + mutex_lock(&vfe_lock); + vfe_syncdata = NULL; + mutex_unlock(&vfe_lock); + + if (!vfestopped) { + CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__); + vfe_7x_stop(); + } else + vfestopped = 0; + + msm_adsp_disable(qcam_mod); + msm_adsp_disable(vfe_mod); + + msm_adsp_put(qcam_mod); + msm_adsp_put(vfe_mod); + + msm_camio_disable(pdev); + + kfree(extdata); + extlen = 0; + + msm_camio_set_perf_lvl(S_EXIT); +} + +static int vfe_7x_init(struct msm_vfe_callback *presp, + struct platform_device *dev) +{ + int rc = 0; + + init_waitqueue_head(&stopevent.wait); + stopevent.timeout = 200; + stopevent.state = 0; + + if (presp && presp->vfe_resp) + resp = presp; + else + return -EFAULT; + + /* Bring up all the required GPIOs and Clocks */ + rc = msm_camio_enable(dev); + if (rc < 0) + return rc; + + extlen = sizeof(struct vfe_frame_extra); + + extdata = kmalloc(extlen, GFP_ATOMIC); + if (!extdata) { + rc = -ENOMEM; + goto init_fail; + } + + rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL); + if (rc) { + rc = -EBUSY; + goto get_qcam_fail; + } + + rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL); + if (rc) { + rc = -EBUSY; + goto get_vfe_fail; + } + + return 0; + +get_vfe_fail: + msm_adsp_put(qcam_mod); +get_qcam_fail: + kfree(extdata); +init_fail: + extlen = 0; + return rc; +} + +static int vfe_7x_config_axi(int mode, + struct axidata *ad, struct axiout *ao) +{ + struct msm_pmem_region *regptr; + unsigned long *bptr; + int cnt; + + int rc = 0; + + if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) { + regptr = ad->region; + + CDBG("bufnum1 = %d\n", ad->bufnum1); + if (mode == OUTPUT_1_AND_2) { + paddr_t_y = regptr->paddr + regptr->info.y_off; + paddr_t_cbcr = regptr->paddr + regptr->info.cbcr_off; + } + + CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n", + regptr->paddr, regptr->info.y_off, + regptr->info.cbcr_off); + + bptr = &ao->output1buffer1_y_phy; + for (cnt = 0; cnt < ad->bufnum1; cnt++) { + *bptr = regptr->paddr + regptr->info.y_off; + bptr++; + *bptr = regptr->paddr + regptr->info.cbcr_off; + + bptr++; + regptr++; + } + + regptr--; + for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) { + *bptr = regptr->paddr + regptr->info.y_off; + bptr++; + *bptr = regptr->paddr + regptr->info.cbcr_off; + bptr++; + } + } + + if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) { + regptr = &(ad->region[ad->bufnum1]); + + CDBG("bufnum2 = %d\n", ad->bufnum2); + paddr_s_y = regptr->paddr + regptr->info.y_off; + paddr_s_cbcr = regptr->paddr + regptr->info.cbcr_off; + + CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n", + regptr->paddr, regptr->info.y_off, regptr->info.cbcr_off); + + bptr = &ao->output2buffer1_y_phy; + for (cnt = 0; cnt < ad->bufnum2; cnt++) { + *bptr = regptr->paddr + regptr->info.y_off; + bptr++; + *bptr = regptr->paddr + regptr->info.cbcr_off; + + bptr++; + regptr++; + } + + regptr--; + for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) { + *bptr = regptr->paddr + regptr->info.y_off; + bptr++; + *bptr = regptr->paddr + regptr->info.cbcr_off; + bptr++; + } + } + + return rc; +} + +static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data) +{ + struct msm_pmem_region *regptr; + unsigned char buf[256]; + + struct vfe_stats_ack sack; + struct axidata *axid; + uint32_t i; + uint32_t *_mode; + + struct vfe_stats_we_cfg *scfg = NULL; + struct vfe_stats_af_cfg *sfcfg = NULL; + + struct axiout *axio = NULL; + void *cmd_data = NULL; + void *cmd_data_alloc = NULL; + long rc = 0; + struct msm_vfe_command_7k *vfecmd; + + vfecmd = kmalloc(sizeof(struct msm_vfe_command_7k), GFP_ATOMIC); + if (!vfecmd) { + pr_err("vfecmd alloc failed!\n"); + return -ENOMEM; + } + + if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) { + if (copy_from_user(vfecmd, + (void __user *)(cmd->value), + sizeof(struct msm_vfe_command_7k))) { + rc = -EFAULT; + goto config_failure; + } + } + + switch (cmd->cmd_type) { + case CMD_STATS_AEC_AWB_ENABLE: + case CMD_STATS_AXI_CFG: { + axid = data; + if (!axid) { + rc = -EFAULT; + goto config_failure; + } + + scfg = + kmalloc(sizeof(struct vfe_stats_we_cfg), + GFP_ATOMIC); + if (!scfg) { + rc = -ENOMEM; + goto config_failure; + } + + if (copy_from_user(scfg, + (void __user *)(vfecmd->value), + vfecmd->length)) { + + rc = -EFAULT; + goto config_done; + } + + CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n", + axid->bufnum1, scfg->wb_expstatsenable); + + if (axid->bufnum1 > 0) { + regptr = axid->region; + + for (i = 0; i < axid->bufnum1; i++) { + + CDBG("STATS_ENABLE, phy = 0x%lx\n", + regptr->paddr); + + scfg->wb_expstatoutputbuffer[i] = + (void *)regptr->paddr; + regptr++; + } + + cmd_data = scfg; + + } else { + rc = -EINVAL; + goto config_done; + } + } + break; + case CMD_STATS_AF_ENABLE: + case CMD_STATS_AF_AXI_CFG: { + axid = data; + if (!axid) { + rc = -EFAULT; + goto config_failure; + } + + sfcfg = + kmalloc(sizeof(struct vfe_stats_af_cfg), + GFP_ATOMIC); + + if (!sfcfg) { + rc = -ENOMEM; + goto config_failure; + } + + if (copy_from_user(sfcfg, + (void __user *)(vfecmd->value), + vfecmd->length)) { + + rc = -EFAULT; + goto config_done; + } + + CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n", + axid->bufnum1, sfcfg->af_enable); + + if (axid->bufnum1 > 0) { + regptr = &axid->region[0]; + + for (i = 0; i < axid->bufnum1; i++) { + + CDBG("STATS_ENABLE, phy = 0x%lx\n", + regptr->paddr); + + sfcfg->af_outbuf[i] = + (void *)regptr->paddr; + + regptr++; + } + + cmd_data = sfcfg; + + } else { + rc = -EINVAL; + goto config_done; + } + } + break; + case CMD_FRAME_BUF_RELEASE: { + struct msm_frame *b; + unsigned long p; + struct vfe_outputack fack; + if (!data) { + rc = -EFAULT; + goto config_failure; + } + + b = (struct msm_frame *)(cmd->value); + p = *(unsigned long *)data; + + fack.header = VFE_FRAME_ACK; + + fack.output2newybufferaddress = + (void *)(p + b->y_off); + + fack.output2newcbcrbufferaddress = + (void *)(p + b->cbcr_off); + + vfecmd->queue = QDSP_CMDQUEUE; + vfecmd->length = sizeof(struct vfe_outputack); + cmd_data = &fack; + } + break; + case CMD_SNAP_BUF_RELEASE: + break; + case CMD_STATS_BUF_RELEASE: { + CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n"); + if (!data) { + rc = -EFAULT; + goto config_failure; + } + + sack.header = STATS_WE_ACK; + sack.bufaddr = (void *)*(uint32_t *)data; + + vfecmd->queue = QDSP_CMDQUEUE; + vfecmd->length = sizeof(struct vfe_stats_ack); + cmd_data = &sack; + } + break; + case CMD_STATS_AF_BUF_RELEASE: { + CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n"); + if (!data) { + rc = -EFAULT; + goto config_failure; + } + + sack.header = STATS_AF_ACK; + sack.bufaddr = (void *)*(uint32_t *)data; + + vfecmd->queue = QDSP_CMDQUEUE; + vfecmd->length = sizeof(struct vfe_stats_ack); + cmd_data = &sack; + } + break; + case CMD_GENERAL: + case CMD_STATS_DISABLE: { + if (vfecmd->length > 256) { + cmd_data_alloc = + cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC); + if (!cmd_data) { + rc = -ENOMEM; + goto config_failure; + } + } else + cmd_data = buf; + + if (copy_from_user(cmd_data, + (void __user *)(vfecmd->value), + vfecmd->length)) { + + rc = -EFAULT; + goto config_done; + } + + if (vfecmd->queue == QDSP_CMDQUEUE) { + switch (*(uint32_t *)cmd_data) { + case VFE_RESET_CMD: + msm_camio_vfe_blk_reset(); + vfestopped = 0; + break; + case VFE_START_CMD: + _mode = (uint32_t *)cmd_data; + op_mode = *(++_mode); + if (op_mode & SNAPSHOT_MASK_MODE) + msm_camio_set_perf_lvl(S_CAPTURE); + else + msm_camio_set_perf_lvl(S_PREVIEW); + vfestopped = 0; + break; + case VFE_STOP_CMD: + vfestopped = 1; + goto config_send; + + default: + break; + } + } /* QDSP_CMDQUEUE */ + } + break; + case CMD_AXI_CFG_PREVIEW: + case CMD_RAW_PICT_AXI_CFG: { + axid = data; + if (!axid) { + rc = -EFAULT; + goto config_failure; + } + + axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + goto config_failure; + } + + if (copy_from_user(axio, (void __user *)(vfecmd->value), + sizeof(struct axiout))) { + rc = -EFAULT; + goto config_done; + } + + vfe_7x_config_axi(OUTPUT_2, axid, axio); + cmd_data = axio; + } + break; + case CMD_AXI_CFG_SNAP: { + axid = data; + if (!axid) { + rc = -EFAULT; + goto config_failure; + } + + axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + goto config_failure; + } + + if (copy_from_user(axio, (void __user *)(vfecmd->value), + sizeof(struct axiout))) { + rc = -EFAULT; + goto config_done; + } + + vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio); + + cmd_data = axio; + } + break; + default: + break; + } + + if (vfestopped) + goto config_done; + +config_send: + CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data); + rc = msm_adsp_write(vfe_mod, vfecmd->queue, + cmd_data, vfecmd->length); + +config_done: + kfree(cmd_data_alloc); + +config_failure: + kfree(scfg); + kfree(axio); + kfree(vfecmd); + return rc; +} + +void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data) +{ + mutex_init(&vfe_lock); + fptr->vfe_init = vfe_7x_init; + fptr->vfe_enable = vfe_7x_enable; + fptr->vfe_config = vfe_7x_config; + fptr->vfe_disable = vfe_7x_disable; + fptr->vfe_release = vfe_7x_release; + vfe_syncdata = data; +} + +void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data) +{ + fptr->vpe_reg = NULL; + fptr->send_frame_to_vpe = NULL; + fptr->vpe_config = NULL; + fptr->vpe_cfg_update = NULL; + fptr->dis = NULL; +} diff --git a/drivers/media/video/msm_zsl/msm_vfe7x27a.h b/drivers/media/video/msm_zsl/msm_vfe7x27a.h new file mode 100644 index 00000000000..a4882060efc --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe7x27a.h @@ -0,0 +1,300 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __MSM_VFE7X_H__ +#define __MSM_VFE7X_H__ +#include +#include + +struct vfe_frame_extra { + uint32_t bl_evencol:23; + uint32_t rvd1:9; + uint32_t bl_oddcol:23; + uint32_t rvd2:9; + + uint32_t d_dbpc_stats_hot:16; + uint32_t d_dbpc_stats_cold:16; + + uint32_t d_dbpc_stats_0_hot:10; + uint32_t rvd3:6; + uint32_t d_dbpc_stats_0_cold:10; + uint32_t rvd4:6; + uint32_t d_dbpc_stats_1_hot:10; + uint32_t rvd5:6; + uint32_t d_dbpc_stats_1_cold:10; + uint32_t rvd6:6; + + uint32_t asf_max_edge; + + uint32_t e_y_wm_pm_stats_0:21; + uint32_t rvd7:11; + uint32_t e_y_wm_pm_stats_1_bl:8; + uint32_t rvd8:8; + uint32_t e_y_wm_pm_stats_1_nl:12; + uint32_t rvd9:4; + + uint32_t e_cbcr_wm_pm_stats_0:21; + uint32_t rvd10:11; + uint32_t e_cbcr_wm_pm_stats_1_bl:8; + uint32_t rvd11:8; + uint32_t e_cbcr_wm_pm_stats_1_nl:12; + uint32_t rvd12:4; + + uint32_t v_y_wm_pm_stats_0:21; + uint32_t rvd13:11; + uint32_t v_y_wm_pm_stats_1_bl:8; + uint32_t rvd14:8; + uint32_t v_y_wm_pm_stats_1_nl:12; + uint32_t rvd15:4; + + uint32_t v_cbcr_wm_pm_stats_0:21; + uint32_t rvd16:11; + uint32_t v_cbcr_wm_pm_stats_1_bl:8; + uint32_t rvd17:8; + uint32_t v_cbcr_wm_pm_stats_1_nl:12; + uint32_t rvd18:4; + + uint32_t frame_id; +}; + +struct vfe_endframe { + uint32_t y_address; + uint32_t cbcr_address; + + struct vfe_frame_extra extra; +} __packed; + +struct vfe_outputack { + uint32_t header; + void *output2newybufferaddress; + void *output2newcbcrbufferaddress; +} __packed; + +struct vfe_stats_ack { + uint32_t header; + /* MUST BE 64 bit ALIGNED */ + void *bufaddr; +} __packed; + +/* AXI Output Config Command sent to DSP */ +struct axiout { + uint32_t cmdheader:32; + int outputmode:3; + uint8_t format:2; + uint32_t /* reserved */ : 27; + + /* AXI Output 1 Y Configuration, Part 1 */ + uint32_t out1yimageheight:12; + uint32_t /* reserved */ : 4; + uint32_t out1yimagewidthin64bitwords:10; + uint32_t /* reserved */ : 6; + + /* AXI Output 1 Y Configuration, Part 2 */ + uint8_t out1yburstlen:2; + uint32_t out1ynumrows:12; + uint32_t out1yrowincin64bitincs:12; + uint32_t /* reserved */ : 6; + + /* AXI Output 1 CbCr Configuration, Part 1 */ + uint32_t out1cbcrimageheight:12; + uint32_t /* reserved */ : 4; + uint32_t out1cbcrimagewidthin64bitwords:10; + uint32_t /* reserved */ : 6; + + /* AXI Output 1 CbCr Configuration, Part 2 */ + uint8_t out1cbcrburstlen:2; + uint32_t out1cbcrnumrows:12; + uint32_t out1cbcrrowincin64bitincs:12; + uint32_t /* reserved */ : 6; + + /* AXI Output 2 Y Configuration, Part 1 */ + uint32_t out2yimageheight:12; + uint32_t /* reserved */ : 4; + uint32_t out2yimagewidthin64bitwords:10; + uint32_t /* reserved */ : 6; + + /* AXI Output 2 Y Configuration, Part 2 */ + uint8_t out2yburstlen:2; + uint32_t out2ynumrows:12; + uint32_t out2yrowincin64bitincs:12; + uint32_t /* reserved */ : 6; + + /* AXI Output 2 CbCr Configuration, Part 1 */ + uint32_t out2cbcrimageheight:12; + uint32_t /* reserved */ : 4; + uint32_t out2cbcrimagewidtein64bitwords:10; + uint32_t /* reserved */ : 6; + + /* AXI Output 2 CbCr Configuration, Part 2 */ + uint8_t out2cbcrburstlen:2; + uint32_t out2cbcrnumrows:12; + uint32_t out2cbcrrowincin64bitincs:12; + uint32_t /* reserved */ : 6; + + /* Address configuration: + * output1 phisycal address */ + unsigned long output1buffer1_y_phy; + unsigned long output1buffer1_cbcr_phy; + unsigned long output1buffer2_y_phy; + unsigned long output1buffer2_cbcr_phy; + unsigned long output1buffer3_y_phy; + unsigned long output1buffer3_cbcr_phy; + unsigned long output1buffer4_y_phy; + unsigned long output1buffer4_cbcr_phy; + unsigned long output1buffer5_y_phy; + unsigned long output1buffer5_cbcr_phy; + unsigned long output1buffer6_y_phy; + unsigned long output1buffer6_cbcr_phy; + unsigned long output1buffer7_y_phy; + unsigned long output1buffer7_cbcr_phy; + unsigned long output1buffer8_y_phy; + unsigned long output1buffer8_cbcr_phy; + + /* output2 phisycal address */ + unsigned long output2buffer1_y_phy; + unsigned long output2buffer1_cbcr_phy; + unsigned long output2buffer2_y_phy; + unsigned long output2buffer2_cbcr_phy; + unsigned long output2buffer3_y_phy; + unsigned long output2buffer3_cbcr_phy; + unsigned long output2buffer4_y_phy; + unsigned long output2buffer4_cbcr_phy; + unsigned long output2buffer5_y_phy; + unsigned long output2buffer5_cbcr_phy; + unsigned long output2buffer6_y_phy; + unsigned long output2buffer6_cbcr_phy; + unsigned long output2buffer7_y_phy; + unsigned long output2buffer7_cbcr_phy; + unsigned long output2buffer8_y_phy; + unsigned long output2buffer8_cbcr_phy; +} __packed; + +struct vfe_stats_we_cfg { + uint32_t header; + + /* White Balance/Exposure Statistic Selection */ + uint8_t wb_expstatsenable:1; + uint8_t wb_expstatbuspriorityselection:1; + unsigned int wb_expstatbuspriorityvalue:4; + unsigned int /* reserved */ : 26; + + /* White Balance/Exposure Statistic Configuration, Part 1 */ + uint8_t exposurestatregions:1; + uint8_t exposurestatsubregions:1; + unsigned int /* reserved */ : 14; + + unsigned int whitebalanceminimumy:8; + unsigned int whitebalancemaximumy:8; + + /* White Balance/Exposure Statistic Configuration, Part 2 */ + uint8_t wb_expstatslopeofneutralregionline[ + NUM_WB_EXP_NEUTRAL_REGION_LINES]; + + /* White Balance/Exposure Statistic Configuration, Part 3 */ + unsigned int wb_expstatcrinterceptofneutralregionline2:12; + unsigned int /* reserved */ : 4; + unsigned int wb_expstatcbinterceptofneutralreginnline1:12; + unsigned int /* reserved */ : 4; + + /* White Balance/Exposure Statistic Configuration, Part 4 */ + unsigned int wb_expstatcrinterceptofneutralregionline4:12; + unsigned int /* reserved */ : 4; + unsigned int wb_expstatcbinterceptofneutralregionline3:12; + unsigned int /* reserved */ : 4; + + /* White Balance/Exposure Statistic Output Buffer Header */ + unsigned int wb_expmetricheaderpattern:8; + unsigned int /* reserved */ : 24; + + /* White Balance/Exposure Statistic Output Buffers-MUST + * BE 64 bit ALIGNED */ + void *wb_expstatoutputbuffer[NUM_WB_EXP_STAT_OUTPUT_BUFFERS]; +} __packed; + +struct vfe_stats_af_cfg { + uint32_t header; + + /* Autofocus Statistic Selection */ + uint8_t af_enable:1; + uint8_t af_busprioritysel:1; + unsigned int af_buspriorityval:4; + unsigned int /* reserved */ : 26; + + /* Autofocus Statistic Configuration, Part 1 */ + unsigned int af_singlewinvoffset:12; + unsigned int /* reserved */ : 4; + unsigned int af_singlewinhoffset:12; + unsigned int /* reserved */ : 3; + uint8_t af_winmode:1; + + /* Autofocus Statistic Configuration, Part 2 */ + unsigned int af_singglewinvh:11; + unsigned int /* reserved */ : 5; + unsigned int af_singlewinhw:11; + unsigned int /* reserved */ : 5; + + /* Autofocus Statistic Configuration, Parts 3-6 */ + uint8_t af_multiwingrid[NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS]; + + /* Autofocus Statistic Configuration, Part 7 */ + signed int af_metrichpfcoefa00:5; + signed int af_metrichpfcoefa04:5; + unsigned int af_metricmaxval:11; + uint8_t af_metricsel:1; + unsigned int /* reserved */ : 10; + + /* Autofocus Statistic Configuration, Part 8 */ + signed int af_metrichpfcoefa20:5; + signed int af_metrichpfcoefa21:5; + signed int af_metrichpfcoefa22:5; + signed int af_metrichpfcoefa23:5; + signed int af_metrichpfcoefa24:5; + unsigned int /* reserved */ : 7; + + /* Autofocus Statistic Output Buffer Header */ + unsigned int af_metrichp:8; + unsigned int /* reserved */ : 24; + + /* Autofocus Statistic Output Buffers - MUST BE 64 bit ALIGNED!!! */ + void *af_outbuf[NUM_AF_STAT_OUTPUT_BUFFERS]; +} __packed; /* VFE_StatsAutofocusConfigCmdType */ + +struct msm_camera_frame_msg { + unsigned long output_y_address; + unsigned long output_cbcr_address; + + unsigned int blacklevelevenColumn:23; + uint16_t reserved1:9; + unsigned int blackleveloddColumn:23; + uint16_t reserved2:9; + + uint16_t greendefectpixelcount:8; + uint16_t reserved3:8; + uint16_t redbluedefectpixelcount:8; + uint16_t reserved4:8; +} __packed; + +/* New one for 7k */ +struct msm_vfe_command_7k { + uint16_t queue; + uint16_t length; + void *value; +}; + +struct stop_event { + wait_queue_head_t wait; + int state; + int timeout; +}; + + +#endif /* __MSM_VFE7X_H__ */ diff --git a/drivers/media/video/msm_zsl/msm_vfe8x.c b/drivers/media/video/msm_zsl/msm_vfe8x.c new file mode 100644 index 00000000000..0bf1785a86c --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe8x.c @@ -0,0 +1,842 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include "msm_vfe8x_proc.h" +#include + +#define ON 1 +#define OFF 0 + +static const char *vfe_general_cmd[] = { + "START", /* 0 */ + "RESET", + "AXI_INPUT_CONFIG", + "CAMIF_CONFIG", + "AXI_OUTPUT_CONFIG", + "BLACK_LEVEL_CONFIG", /* 5 */ + "ROLL_OFF_CONFIG", + "DEMUX_CHANNEL_GAIN_CONFIG", + "DEMOSAIC_CONFIG", + "FOV_CROP_CONFIG", + "MAIN_SCALER_CONFIG", /* 10 */ + "WHITE_BALANCE_CONFIG", + "COLOR_CORRECTION_CONFIG", + "LA_CONFIG", + "RGB_GAMMA_CONFIG", + "CHROMA_ENHAN_CONFIG", /* 15 */ + "CHROMA_SUPPRESSION_CONFIG", + "ASF_CONFIG", + "SCALER2Y_CONFIG", + "SCALER2CbCr_CONFIG", + "CHROMA_SUBSAMPLE_CONFIG", /* 20 */ + "FRAME_SKIP_CONFIG", + "OUTPUT_CLAMP_CONFIG", + "TEST_GEN_START", + "UPDATE", + "OUTPUT1_ACK", /* 25 */ + "OUTPUT2_ACK", + "EPOCH1_ACK", + "EPOCH2_ACK", + "STATS_AUTOFOCUS_ACK", + "STATS_WB_EXP_ACK", /* 30 */ + "BLACK_LEVEL_UPDATE", + "DEMUX_CHANNEL_GAIN_UPDATE", + "DEMOSAIC_BPC_UPDATE", + "DEMOSAIC_ABF_UPDATE", + "FOV_CROP_UPDATE", /* 35 */ + "WHITE_BALANCE_UPDATE", + "COLOR_CORRECTION_UPDATE", + "LA_UPDATE", + "RGB_GAMMA_UPDATE", + "CHROMA_ENHAN_UPDATE", /* 40 */ + "CHROMA_SUPPRESSION_UPDATE", + "MAIN_SCALER_UPDATE", + "SCALER2CbCr_UPDATE", + "SCALER2Y_UPDATE", + "ASF_UPDATE", /* 45 */ + "FRAME_SKIP_UPDATE", + "CAMIF_FRAME_UPDATE", + "STATS_AUTOFOCUS_UPDATE", + "STATS_WB_EXP_UPDATE", + "STOP", /* 50 */ + "GET_HW_VERSION", + "STATS_SETTING", + "STATS_AUTOFOCUS_START", + "STATS_AUTOFOCUS_STOP", + "STATS_WB_EXP_START", /* 55 */ + "STATS_WB_EXP_STOP", + "ASYNC_TIMER_SETTING", +}; + +static void *vfe_syncdata; + +static int vfe_enable(struct camera_enable_cmd *enable) +{ + return 0; +} + +static int vfe_disable(struct camera_enable_cmd *enable, + struct platform_device *dev) +{ + vfe_stop(); + msm_camio_disable(dev); + return 0; +} + +static void vfe_release(struct platform_device *dev) +{ + msm_camio_disable(dev); + vfe_cmd_release(dev); + update_axi_qos(PM_QOS_DEFAULT_VALUE); + vfe_syncdata = NULL; +} + +static void vfe_config_axi(int mode, + struct axidata *ad, + struct vfe_cmd_axi_output_config *ao) +{ + struct msm_pmem_region *regptr, *regptr1; + int i, j; + uint32_t *p1, *p2; + + if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) { + regptr = ad->region; + for (i = 0; i < ad->bufnum1; i++) { + + p1 = &(ao->output1.outputY.outFragments[i][0]); + p2 = &(ao->output1.outputCbcr.outFragments[i][0]); + + for (j = 0; j < ao->output1.fragmentCount; j++) { + + *p1 = regptr->paddr + regptr->info.y_off; + p1++; + + *p2 = regptr->paddr + regptr->info.cbcr_off; + p2++; + } + regptr++; + } + } /* if OUTPUT1 or Both */ + + if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) { + + regptr = &(ad->region[ad->bufnum1]); + CDBG("bufnum2 = %d\n", ad->bufnum2); + + for (i = 0; i < ad->bufnum2; i++) { + + p1 = &(ao->output2.outputY.outFragments[i][0]); + p2 = &(ao->output2.outputCbcr.outFragments[i][0]); + + CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, "\ + "cbcr_off = %d\n", regptr->paddr, + regptr->info.y_off, regptr->info.cbcr_off); + + for (j = 0; j < ao->output2.fragmentCount; j++) { + + *p1 = regptr->paddr + regptr->info.y_off; + CDBG("vfe_config_axi: p1 = 0x%x\n", *p1); + p1++; + + *p2 = regptr->paddr + regptr->info.cbcr_off; + CDBG("vfe_config_axi: p2 = 0x%x\n", *p2); + p2++; + } + regptr++; + } + } + /* For video configuration */ + if (mode == OUTPUT_1_AND_3) { + /* this is preview buffer. */ + regptr = &(ad->region[0]); + /* this is video buffer. */ + regptr1 = &(ad->region[ad->bufnum1]); + CDBG("bufnum1 = %d\n", ad->bufnum1); + CDBG("bufnum2 = %d\n", ad->bufnum2); + + for (i = 0; i < ad->bufnum1; i++) { + p1 = &(ao->output1.outputY.outFragments[i][0]); + p2 = &(ao->output1.outputCbcr.outFragments[i][0]); + + CDBG("config_axi: O1, phy = 0x%lx, y_off = %d, "\ + "cbcr_off = %d\n", regptr->paddr, + regptr->info.y_off, regptr->info.cbcr_off); + + for (j = 0; j < ao->output1.fragmentCount; j++) { + + *p1 = regptr->paddr + regptr->info.y_off; + CDBG("vfe_config_axi: p1 = 0x%x\n", *p1); + p1++; + + *p2 = regptr->paddr + regptr->info.cbcr_off; + CDBG("vfe_config_axi: p2 = 0x%x\n", *p2); + p2++; + } + regptr++; + } + for (i = 0; i < ad->bufnum2; i++) { + p1 = &(ao->output2.outputY.outFragments[i][0]); + p2 = &(ao->output2.outputCbcr.outFragments[i][0]); + + CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, "\ + "cbcr_off = %d\n", regptr1->paddr, + regptr1->info.y_off, regptr1->info.cbcr_off); + + for (j = 0; j < ao->output2.fragmentCount; j++) { + + *p1 = regptr1->paddr + regptr1->info.y_off; + CDBG("vfe_config_axi: p1 = 0x%x\n", *p1); + p1++; + + *p2 = regptr1->paddr + regptr1->info.cbcr_off; + CDBG("vfe_config_axi: p2 = 0x%x\n", *p2); + p2++; + } + regptr1++; + } + } + +} + +#define CHECKED_COPY_FROM_USER(in) { \ + if (cmd->length != sizeof(*(in))) { \ + pr_err("msm_camera: %s:%d cmd %d: user data size %d " \ + "!= kernel data size %d\n", \ + __func__, __LINE__, \ + cmd->id, cmd->length, sizeof(*(in))); \ + rc = -EIO; \ + break; \ + } \ + if (copy_from_user((in), (void __user *)cmd->value, \ + sizeof(*(in)))) { \ + rc = -EFAULT; \ + break; \ + } \ +} + +static int vfe_proc_general(struct msm_vfe_command_8k *cmd) +{ + int rc = 0; + + CDBG("%s: cmdID = %s\n", __func__, vfe_general_cmd[cmd->id]); + + switch (cmd->id) { + case VFE_CMD_ID_RESET: + msm_camio_vfe_blk_reset(); + msm_camio_camif_pad_reg_reset_2(); + vfe_reset(); + break; + + case VFE_CMD_ID_START: { + struct vfe_cmd_start start; + CHECKED_COPY_FROM_USER(&start); + + /* msm_camio_camif_pad_reg_reset_2(); */ + msm_camio_camif_pad_reg_reset(); + vfe_start(&start); + } + break; + + case VFE_CMD_ID_CAMIF_CONFIG: { + struct vfe_cmd_camif_config camif; + CHECKED_COPY_FROM_USER(&camif); + + vfe_camif_config(&camif); + } + break; + + case VFE_CMD_ID_BLACK_LEVEL_CONFIG: { + struct vfe_cmd_black_level_config bl; + CHECKED_COPY_FROM_USER(&bl); + + vfe_black_level_config(&bl); + } + break; + + case VFE_CMD_ID_ROLL_OFF_CONFIG:{ + /* rolloff is too big to be on the stack */ + struct vfe_cmd_roll_off_config *rolloff = + kmalloc(sizeof(struct vfe_cmd_roll_off_config), + GFP_KERNEL); + if (!rolloff) { + pr_err("%s: out of memory\n", __func__); + rc = -ENOMEM; + break; + } + /* Wrap CHECKED_COPY_FROM_USER() in a do-while(0) loop + * to make sure we free rolloff when copy_from_user() + * fails. + */ + do { + CHECKED_COPY_FROM_USER(rolloff); + vfe_roll_off_config(rolloff); + } while (0); + kfree(rolloff); + } + break; + + case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG: { + struct vfe_cmd_demux_channel_gain_config demuxc; + CHECKED_COPY_FROM_USER(&demuxc); + + /* demux is always enabled. */ + vfe_demux_channel_gain_config(&demuxc); + } + break; + + case VFE_CMD_ID_DEMOSAIC_CONFIG: { + struct vfe_cmd_demosaic_config demosaic; + CHECKED_COPY_FROM_USER(&demosaic); + + vfe_demosaic_config(&demosaic); + } + break; + + case VFE_CMD_ID_FOV_CROP_CONFIG: + case VFE_CMD_ID_FOV_CROP_UPDATE: { + struct vfe_cmd_fov_crop_config fov; + CHECKED_COPY_FROM_USER(&fov); + + vfe_fov_crop_config(&fov); + } + break; + + case VFE_CMD_ID_MAIN_SCALER_CONFIG: + case VFE_CMD_ID_MAIN_SCALER_UPDATE: { + struct vfe_cmd_main_scaler_config mainds; + CHECKED_COPY_FROM_USER(&mainds); + + vfe_main_scaler_config(&mainds); + } + break; + + case VFE_CMD_ID_WHITE_BALANCE_CONFIG: + case VFE_CMD_ID_WHITE_BALANCE_UPDATE: { + struct vfe_cmd_white_balance_config wb; + CHECKED_COPY_FROM_USER(&wb); + + vfe_white_balance_config(&wb); + } + break; + + case VFE_CMD_ID_COLOR_CORRECTION_CONFIG: + case VFE_CMD_ID_COLOR_CORRECTION_UPDATE: { + struct vfe_cmd_color_correction_config cc; + CHECKED_COPY_FROM_USER(&cc); + + vfe_color_correction_config(&cc); + } + break; + + case VFE_CMD_ID_LA_CONFIG: { + struct vfe_cmd_la_config la; + CHECKED_COPY_FROM_USER(&la); + + vfe_la_config(&la); + } + break; + + case VFE_CMD_ID_RGB_GAMMA_CONFIG: { + struct vfe_cmd_rgb_gamma_config rgb; + CHECKED_COPY_FROM_USER(&rgb); + + rc = vfe_rgb_gamma_config(&rgb); + } + break; + + case VFE_CMD_ID_CHROMA_ENHAN_CONFIG: + case VFE_CMD_ID_CHROMA_ENHAN_UPDATE: { + struct vfe_cmd_chroma_enhan_config chrom; + CHECKED_COPY_FROM_USER(&chrom); + + vfe_chroma_enhan_config(&chrom); + } + break; + + case VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG: + case VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE: { + struct vfe_cmd_chroma_suppression_config chromsup; + CHECKED_COPY_FROM_USER(&chromsup); + + vfe_chroma_sup_config(&chromsup); + } + break; + + case VFE_CMD_ID_ASF_CONFIG: { + struct vfe_cmd_asf_config asf; + CHECKED_COPY_FROM_USER(&asf); + + vfe_asf_config(&asf); + } + break; + + case VFE_CMD_ID_SCALER2Y_CONFIG: + case VFE_CMD_ID_SCALER2Y_UPDATE: { + struct vfe_cmd_scaler2_config ds2y; + CHECKED_COPY_FROM_USER(&ds2y); + + vfe_scaler2y_config(&ds2y); + } + break; + + case VFE_CMD_ID_SCALER2CbCr_CONFIG: + case VFE_CMD_ID_SCALER2CbCr_UPDATE: { + struct vfe_cmd_scaler2_config ds2cbcr; + CHECKED_COPY_FROM_USER(&ds2cbcr); + + vfe_scaler2cbcr_config(&ds2cbcr); + } + break; + + case VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG: { + struct vfe_cmd_chroma_subsample_config sub; + CHECKED_COPY_FROM_USER(&sub); + + vfe_chroma_subsample_config(&sub); + } + break; + + case VFE_CMD_ID_FRAME_SKIP_CONFIG: { + struct vfe_cmd_frame_skip_config fskip; + CHECKED_COPY_FROM_USER(&fskip); + + vfe_frame_skip_config(&fskip); + } + break; + + case VFE_CMD_ID_OUTPUT_CLAMP_CONFIG: { + struct vfe_cmd_output_clamp_config clamp; + CHECKED_COPY_FROM_USER(&clamp); + + vfe_output_clamp_config(&clamp); + } + break; + + /* module update commands */ + case VFE_CMD_ID_BLACK_LEVEL_UPDATE: { + struct vfe_cmd_black_level_config blk; + CHECKED_COPY_FROM_USER(&blk); + + vfe_black_level_update(&blk); + } + break; + + case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE: { + struct vfe_cmd_demux_channel_gain_config dmu; + CHECKED_COPY_FROM_USER(&dmu); + + vfe_demux_channel_gain_update(&dmu); + } + break; + + case VFE_CMD_ID_DEMOSAIC_BPC_UPDATE: { + struct vfe_cmd_demosaic_bpc_update demo_bpc; + CHECKED_COPY_FROM_USER(&demo_bpc); + + vfe_demosaic_bpc_update(&demo_bpc); + } + break; + + case VFE_CMD_ID_DEMOSAIC_ABF_UPDATE: { + struct vfe_cmd_demosaic_abf_update demo_abf; + CHECKED_COPY_FROM_USER(&demo_abf); + + vfe_demosaic_abf_update(&demo_abf); + } + break; + + case VFE_CMD_ID_LA_UPDATE: { + struct vfe_cmd_la_config la; + CHECKED_COPY_FROM_USER(&la); + + vfe_la_update(&la); + } + break; + + case VFE_CMD_ID_RGB_GAMMA_UPDATE: { + struct vfe_cmd_rgb_gamma_config rgb; + CHECKED_COPY_FROM_USER(&rgb); + + rc = vfe_rgb_gamma_update(&rgb); + } + break; + + case VFE_CMD_ID_ASF_UPDATE: { + struct vfe_cmd_asf_update asf; + CHECKED_COPY_FROM_USER(&asf); + + vfe_asf_update(&asf); + } + break; + + case VFE_CMD_ID_FRAME_SKIP_UPDATE: { + struct vfe_cmd_frame_skip_update fskip; + CHECKED_COPY_FROM_USER(&fskip); + /* Start recording */ + if (fskip.output2Pattern == 0xffffffff) + update_axi_qos(MSM_AXI_QOS_RECORDING); + else if (fskip.output2Pattern == 0) + update_axi_qos(MSM_AXI_QOS_PREVIEW); + + vfe_frame_skip_update(&fskip); + } + break; + + case VFE_CMD_ID_CAMIF_FRAME_UPDATE: { + struct vfe_cmds_camif_frame fup; + CHECKED_COPY_FROM_USER(&fup); + + vfe_camif_frame_update(&fup); + } + break; + + /* stats update commands */ + case VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE: { + struct vfe_cmd_stats_af_update afup; + CHECKED_COPY_FROM_USER(&afup); + + vfe_stats_update_af(&afup); + } + break; + + case VFE_CMD_ID_STATS_WB_EXP_UPDATE: { + struct vfe_cmd_stats_wb_exp_update wbexp; + CHECKED_COPY_FROM_USER(&wbexp); + + vfe_stats_update_wb_exp(&wbexp); + } + break; + + /* control of start, stop, update, etc... */ + case VFE_CMD_ID_STOP: + vfe_stop(); + break; + + case VFE_CMD_ID_GET_HW_VERSION: + break; + + /* stats */ + case VFE_CMD_ID_STATS_SETTING: { + struct vfe_cmd_stats_setting stats; + CHECKED_COPY_FROM_USER(&stats); + + vfe_stats_setting(&stats); + } + break; + + case VFE_CMD_ID_STATS_AUTOFOCUS_START: { + struct vfe_cmd_stats_af_start af; + CHECKED_COPY_FROM_USER(&af); + + vfe_stats_start_af(&af); + } + break; + + case VFE_CMD_ID_STATS_AUTOFOCUS_STOP: + vfe_stats_af_stop(); + break; + + case VFE_CMD_ID_STATS_WB_EXP_START: { + struct vfe_cmd_stats_wb_exp_start awexp; + CHECKED_COPY_FROM_USER(&awexp); + + vfe_stats_start_wb_exp(&awexp); + } + break; + + case VFE_CMD_ID_STATS_WB_EXP_STOP: + vfe_stats_wb_exp_stop(); + break; + + case VFE_CMD_ID_ASYNC_TIMER_SETTING: + break; + + case VFE_CMD_ID_UPDATE: + vfe_update(); + break; + + /* test gen */ + case VFE_CMD_ID_TEST_GEN_START: + break; + +/* + acknowledge from upper layer + these are not in general command. + + case VFE_CMD_ID_OUTPUT1_ACK: + break; + case VFE_CMD_ID_OUTPUT2_ACK: + break; + case VFE_CMD_ID_EPOCH1_ACK: + break; + case VFE_CMD_ID_EPOCH2_ACK: + break; + case VFE_CMD_ID_STATS_AUTOFOCUS_ACK: + break; + case VFE_CMD_ID_STATS_WB_EXP_ACK: + break; +*/ + + default: + pr_err("%s: invalid cmd id %d\n", __func__, cmd->id); + rc = -EINVAL; + break; + } /* switch */ + + return rc; +} + +static int vfe_config(struct msm_vfe_cfg_cmd *cmd, void *data) +{ + struct msm_pmem_region *regptr; + struct msm_vfe_command_8k vfecmd; + struct vfe_cmd_axi_output_config axio; + struct axidata *axid = data; + + int rc = 0; + + + if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_BUF_RELEASE && + cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) { + + if (copy_from_user(&vfecmd, + (void __user *)(cmd->value), sizeof(vfecmd))) { + pr_err("%s %d: copy_from_user failed\n", + __func__, __LINE__); + return -EFAULT; + } + } + + CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type); + + switch (cmd->cmd_type) { + case CMD_GENERAL: + rc = vfe_proc_general(&vfecmd); + break; + + case CMD_STATS_ENABLE: + case CMD_STATS_AXI_CFG: { + int i; + struct vfe_cmd_stats_setting scfg; + + BUG_ON(!axid); + + if (vfecmd.length != sizeof(scfg)) { + pr_err + ("msm_camera: %s: cmd %d: user-space "\ + "data size %d != kernel data size %d\n", + __func__, + cmd->cmd_type, vfecmd.length, + sizeof(scfg)); + return -EIO; + } + + if (copy_from_user(&scfg, + (void __user *)(vfecmd.value), + sizeof(scfg))) { + pr_err("%s %d: copy_from_user failed\n", + __func__, __LINE__); + return -EFAULT; + } + + regptr = axid->region; + if (axid->bufnum1 > 0) { + for (i = 0; i < axid->bufnum1; i++) { + scfg.awbBuffer[i] = + (uint32_t)(regptr->paddr); + regptr++; + } + } + + if (axid->bufnum2 > 0) { + for (i = 0; i < axid->bufnum2; i++) { + scfg.afBuffer[i] = + (uint32_t)(regptr->paddr); + regptr++; + } + } + + vfe_stats_setting(&scfg); + } + break; + + case CMD_STATS_AF_AXI_CFG: + break; + + case CMD_FRAME_BUF_RELEASE: { + /* preview buffer release */ + struct msm_frame *b; + unsigned long p; + struct vfe_cmd_output_ack fack; + + BUG_ON(!data); + + b = (struct msm_frame *)(cmd->value); + p = *(unsigned long *)data; + + fack.ybufaddr[0] = (uint32_t) (p + b->y_off); + + fack.chromabufaddr[0] = (uint32_t) (p + b->cbcr_off); + + if (b->path == OUTPUT_TYPE_P) + vfe_output_p_ack(&fack); + + if ((b->path == OUTPUT_TYPE_V) + || (b->path == OUTPUT_TYPE_S)) + vfe_output_v_ack(&fack); + } + break; + + case CMD_SNAP_BUF_RELEASE: + break; + + case CMD_STATS_BUF_RELEASE: { + struct vfe_cmd_stats_wb_exp_ack sack; + + BUG_ON(!data); + + sack.nextWbExpOutputBufferAddr = *(uint32_t *)data; + vfe_stats_wb_exp_ack(&sack); + } + break; + + case CMD_STATS_AF_BUF_RELEASE: { + struct vfe_cmd_stats_af_ack ack; + + BUG_ON(!data); + + ack.nextAFOutputBufferAddr = *(uint32_t *)data; + vfe_stats_af_ack(&ack); + } + break; + + case CMD_AXI_CFG_PREVIEW: + case CMD_RAW_PICT_AXI_CFG: { + + BUG_ON(!axid); + + if (copy_from_user(&axio, (void __user *)(vfecmd.value), + sizeof(axio))) { + pr_err("%s %d: copy_from_user failed\n", + __func__, __LINE__); + return -EFAULT; + } + /* Validate the data from user space */ + if (axio.output2.fragmentCount < + VFE_MIN_NUM_FRAGMENTS_PER_FRAME || + axio.output2.fragmentCount > + VFE_MAX_NUM_FRAGMENTS_PER_FRAME) + return -EINVAL; + + vfe_config_axi(OUTPUT_2, axid, &axio); + axio.outputDataSize = 0; + vfe_axi_output_config(&axio); + } + break; + + case CMD_AXI_CFG_SNAP: { + + BUG_ON(!axid); + + if (copy_from_user(&axio, (void __user *)(vfecmd.value), + sizeof(axio))) { + pr_err("%s %d: copy_from_user failed\n", + __func__, __LINE__); + return -EFAULT; + } + /* Validate the data from user space */ + if (axio.output1.fragmentCount < + VFE_MIN_NUM_FRAGMENTS_PER_FRAME || + axio.output1.fragmentCount > + VFE_MAX_NUM_FRAGMENTS_PER_FRAME || + axio.output2.fragmentCount < + VFE_MIN_NUM_FRAGMENTS_PER_FRAME || + axio.output2.fragmentCount > + VFE_MAX_NUM_FRAGMENTS_PER_FRAME) + return -EINVAL; + + vfe_config_axi(OUTPUT_1_AND_2, axid, &axio); + vfe_axi_output_config(&axio); + } + break; + + case CMD_AXI_CFG_VIDEO: { + BUG_ON(!axid); + + if (copy_from_user(&axio, (void __user *)(vfecmd.value), + sizeof(axio))) { + pr_err("%s %d: copy_from_user failed\n", + __func__, __LINE__); + return -EFAULT; + } + /* Validate the data from user space */ + if (axio.output1.fragmentCount < + VFE_MIN_NUM_FRAGMENTS_PER_FRAME || + axio.output1.fragmentCount > + VFE_MAX_NUM_FRAGMENTS_PER_FRAME || + axio.output2.fragmentCount < + VFE_MIN_NUM_FRAGMENTS_PER_FRAME || + axio.output2.fragmentCount > + VFE_MAX_NUM_FRAGMENTS_PER_FRAME) + return -EINVAL; + + vfe_config_axi(OUTPUT_1_AND_3, axid, &axio); + axio.outputDataSize = 0; + vfe_axi_output_config(&axio); + } + break; + + default: + break; + } /* switch */ + + return rc; +} + +static int vfe_init(struct msm_vfe_callback *presp, struct platform_device *dev) +{ + int rc = 0; + + rc = vfe_cmd_init(presp, dev, vfe_syncdata); + if (rc < 0) + return rc; + + /* Bring up all the required GPIOs and Clocks */ + rc = msm_camio_enable(dev); + + return rc; +} + +void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data) +{ + fptr->vfe_init = vfe_init; + fptr->vfe_enable = vfe_enable; + fptr->vfe_config = vfe_config; + fptr->vfe_disable = vfe_disable; + fptr->vfe_release = vfe_release; + vfe_syncdata = data; +} + +void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data) +{ + fptr->vpe_reg = NULL; + fptr->send_frame_to_vpe = NULL; + fptr->vpe_config = NULL; + fptr->vpe_cfg_update = NULL; + fptr->dis = NULL; +} diff --git a/drivers/media/video/msm_zsl/msm_vfe8x.h b/drivers/media/video/msm_zsl/msm_vfe8x.h new file mode 100644 index 00000000000..1b3148f0e84 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe8x.h @@ -0,0 +1,909 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __MSM_VFE8X_H__ +#define __MSM_VFE8X_H__ + +#define TRUE 1 +#define FALSE 0 +#define boolean uint8_t + +enum VFE_STATE { + VFE_STATE_IDLE, + VFE_STATE_ACTIVE +}; + +enum vfe_cmd_id { + /* + *Important! Command_ID are arranged in order. + *Don't change!*/ + VFE_CMD_ID_START, + VFE_CMD_ID_RESET, + + /* bus and camif config */ + VFE_CMD_ID_AXI_INPUT_CONFIG, + VFE_CMD_ID_CAMIF_CONFIG, + VFE_CMD_ID_AXI_OUTPUT_CONFIG, + + /* module config */ + VFE_CMD_ID_BLACK_LEVEL_CONFIG, + VFE_CMD_ID_ROLL_OFF_CONFIG, + VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG, + VFE_CMD_ID_DEMOSAIC_CONFIG, + VFE_CMD_ID_FOV_CROP_CONFIG, + VFE_CMD_ID_MAIN_SCALER_CONFIG, + VFE_CMD_ID_WHITE_BALANCE_CONFIG, + VFE_CMD_ID_COLOR_CORRECTION_CONFIG, + VFE_CMD_ID_LA_CONFIG, + VFE_CMD_ID_RGB_GAMMA_CONFIG, + VFE_CMD_ID_CHROMA_ENHAN_CONFIG, + VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG, + VFE_CMD_ID_ASF_CONFIG, + VFE_CMD_ID_SCALER2Y_CONFIG, + VFE_CMD_ID_SCALER2CbCr_CONFIG, + VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG, + VFE_CMD_ID_FRAME_SKIP_CONFIG, + VFE_CMD_ID_OUTPUT_CLAMP_CONFIG, + + /* test gen */ + VFE_CMD_ID_TEST_GEN_START, + + VFE_CMD_ID_UPDATE, + + /* ackownledge from upper layer */ + VFE_CMD_ID_OUTPUT1_ACK, + VFE_CMD_ID_OUTPUT2_ACK, + VFE_CMD_ID_EPOCH1_ACK, + VFE_CMD_ID_EPOCH2_ACK, + VFE_CMD_ID_STATS_AUTOFOCUS_ACK, + VFE_CMD_ID_STATS_WB_EXP_ACK, + + /* module update commands */ + VFE_CMD_ID_BLACK_LEVEL_UPDATE, + VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE, + VFE_CMD_ID_DEMOSAIC_BPC_UPDATE, + VFE_CMD_ID_DEMOSAIC_ABF_UPDATE, + VFE_CMD_ID_FOV_CROP_UPDATE, + VFE_CMD_ID_WHITE_BALANCE_UPDATE, + VFE_CMD_ID_COLOR_CORRECTION_UPDATE, + VFE_CMD_ID_LA_UPDATE, + VFE_CMD_ID_RGB_GAMMA_UPDATE, + VFE_CMD_ID_CHROMA_ENHAN_UPDATE, + VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE, + VFE_CMD_ID_MAIN_SCALER_UPDATE, + VFE_CMD_ID_SCALER2CbCr_UPDATE, + VFE_CMD_ID_SCALER2Y_UPDATE, + VFE_CMD_ID_ASF_UPDATE, + VFE_CMD_ID_FRAME_SKIP_UPDATE, + VFE_CMD_ID_CAMIF_FRAME_UPDATE, + + /* stats update commands */ + VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE, + VFE_CMD_ID_STATS_WB_EXP_UPDATE, + + /* control of start, stop, update, etc... */ + VFE_CMD_ID_STOP, + VFE_CMD_ID_GET_HW_VERSION, + + /* stats */ + VFE_CMD_ID_STATS_SETTING, + VFE_CMD_ID_STATS_AUTOFOCUS_START, + VFE_CMD_ID_STATS_AUTOFOCUS_STOP, + VFE_CMD_ID_STATS_WB_EXP_START, + VFE_CMD_ID_STATS_WB_EXP_STOP, + + VFE_CMD_ID_ASYNC_TIMER_SETTING, + + /* max id */ + VFE_CMD_ID_MAX +}; + +struct vfe_cmd_hw_version { + uint32_t minorVersion; + uint32_t majorVersion; + uint32_t coreVersion; +}; + +enum VFE_CAMIF_SYNC_EDGE { + VFE_CAMIF_SYNC_EDGE_ActiveHigh, + VFE_CAMIF_SYNC_EDGE_ActiveLow +}; + +enum VFE_CAMIF_SYNC_MODE { + VFE_CAMIF_SYNC_MODE_APS, + VFE_CAMIF_SYNC_MODE_EFS, + VFE_CAMIF_SYNC_MODE_ELS, + VFE_CAMIF_SYNC_MODE_ILLEGAL +}; + +struct vfe_cmds_camif_efs { + uint8_t efsendofline; + uint8_t efsstartofline; + uint8_t efsendofframe; + uint8_t efsstartofframe; +}; + +struct vfe_cmds_camif_frame { + uint16_t pixelsPerLine; + uint16_t linesPerFrame; +}; + +struct vfe_cmds_camif_window { + uint16_t firstpixel; + uint16_t lastpixel; + uint16_t firstline; + uint16_t lastline; +}; + +enum CAMIF_SUBSAMPLE_FRAME_SKIP { + CAMIF_SUBSAMPLE_FRAME_SKIP_0, + CAMIF_SUBSAMPLE_FRAME_SKIP_AllFrames, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_2Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_3Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_4Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_5Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_6Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_7Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_8Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_9Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_10Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_11Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_12Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_13Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_14Frame, + CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_15Frame +}; + +struct vfe_cmds_camif_subsample { + uint16_t pixelskipmask; + uint16_t lineskipmask; + enum CAMIF_SUBSAMPLE_FRAME_SKIP frameskip; + uint8_t frameskipmode; + uint8_t pixelskipwrap; +}; + +struct vfe_cmds_camif_epoch { + uint8_t enable; + uint16_t lineindex; +}; + +struct vfe_cmds_camif_cfg { + enum VFE_CAMIF_SYNC_EDGE vSyncEdge; + enum VFE_CAMIF_SYNC_EDGE hSyncEdge; + enum VFE_CAMIF_SYNC_MODE syncMode; + uint8_t vfeSubSampleEnable; + uint8_t busSubSampleEnable; + uint8_t irqSubSampleEnable; + uint8_t binningEnable; + uint8_t misrEnable; +}; + +struct vfe_cmd_camif_config { + struct vfe_cmds_camif_cfg camifConfig; + struct vfe_cmds_camif_efs EFS; + struct vfe_cmds_camif_frame frame; + struct vfe_cmds_camif_window window; + struct vfe_cmds_camif_subsample subsample; + struct vfe_cmds_camif_epoch epoch1; + struct vfe_cmds_camif_epoch epoch2; +}; + +enum VFE_AXI_OUTPUT_MODE { + VFE_AXI_OUTPUT_MODE_Output1, + VFE_AXI_OUTPUT_MODE_Output2, + VFE_AXI_OUTPUT_MODE_Output1AndOutput2, + VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2, + VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1, + VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2, + VFE_AXI_LAST_OUTPUT_MODE_ENUM +}; + +enum VFE_RAW_WR_PATH_SEL { + VFE_RAW_OUTPUT_DISABLED, + VFE_RAW_OUTPUT_ENC_CBCR_PATH, + VFE_RAW_OUTPUT_VIEW_CBCR_PATH, + VFE_RAW_OUTPUT_PATH_INVALID +}; + +enum VFE_RAW_PIXEL_DATA_SIZE { + VFE_RAW_PIXEL_DATA_SIZE_8BIT, + VFE_RAW_PIXEL_DATA_SIZE_10BIT, + VFE_RAW_PIXEL_DATA_SIZE_12BIT, +}; + +#define VFE_AXI_OUTPUT_BURST_LENGTH 4 +#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4 +#define VFE_MIN_NUM_FRAGMENTS_PER_FRAME 1 +#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT 3 + +struct vfe_cmds_axi_out_per_component { + uint16_t imageWidth; + uint16_t imageHeight; + uint16_t outRowCount; + uint16_t outRowIncrement; + uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT] + [VFE_MAX_NUM_FRAGMENTS_PER_FRAME]; +}; + +struct vfe_cmds_axi_per_output_path { + uint8_t fragmentCount; + struct vfe_cmds_axi_out_per_component outputY; + struct vfe_cmds_axi_out_per_component outputCbcr; +}; + +enum VFE_AXI_BURST_LENGTH { + VFE_AXI_BURST_LENGTH_IS_2 = 2, + VFE_AXI_BURST_LENGTH_IS_4 = 4, + VFE_AXI_BURST_LENGTH_IS_8 = 8, + VFE_AXI_BURST_LENGTH_IS_16 = 16 +}; + +struct vfe_cmd_axi_output_config { + enum VFE_AXI_BURST_LENGTH burstLength; + enum VFE_AXI_OUTPUT_MODE outputMode; + enum VFE_RAW_PIXEL_DATA_SIZE outputDataSize; + struct vfe_cmds_axi_per_output_path output1; + struct vfe_cmds_axi_per_output_path output2; +}; + +struct vfe_cmd_fov_crop_config { + uint8_t enable; + uint16_t firstPixel; + uint16_t lastPixel; + uint16_t firstLine; + uint16_t lastLine; +}; + +struct vfe_cmds_main_scaler_stripe_init { + uint16_t MNCounterInit; + uint16_t phaseInit; +}; + +struct vfe_cmds_scaler_one_dimension { + uint8_t enable; + uint16_t inputSize; + uint16_t outputSize; + uint32_t phaseMultiplicationFactor; + uint8_t interpolationResolution; +}; + +struct vfe_cmd_main_scaler_config { + uint8_t enable; + struct vfe_cmds_scaler_one_dimension hconfig; + struct vfe_cmds_scaler_one_dimension vconfig; + struct vfe_cmds_main_scaler_stripe_init MNInitH; + struct vfe_cmds_main_scaler_stripe_init MNInitV; +}; + +struct vfe_cmd_scaler2_config { + uint8_t enable; + struct vfe_cmds_scaler_one_dimension hconfig; + struct vfe_cmds_scaler_one_dimension vconfig; +}; + +struct vfe_cmd_frame_skip_config { + uint8_t output1Period; + uint32_t output1Pattern; + uint8_t output2Period; + uint32_t output2Pattern; +}; + +struct vfe_cmd_frame_skip_update { + uint32_t output1Pattern; + uint32_t output2Pattern; +}; + +struct vfe_cmd_output_clamp_config { + uint8_t minCh0; + uint8_t minCh1; + uint8_t minCh2; + uint8_t maxCh0; + uint8_t maxCh1; + uint8_t maxCh2; +}; + +struct vfe_cmd_chroma_subsample_config { + uint8_t enable; + uint8_t cropEnable; + uint8_t vsubSampleEnable; + uint8_t hsubSampleEnable; + uint8_t vCosited; + uint8_t hCosited; + uint8_t vCositedPhase; + uint8_t hCositedPhase; + uint16_t cropWidthFirstPixel; + uint16_t cropWidthLastPixel; + uint16_t cropHeightFirstLine; + uint16_t cropHeightLastLine; +}; + +enum VFE_START_INPUT_SOURCE { + VFE_START_INPUT_SOURCE_CAMIF, + VFE_START_INPUT_SOURCE_TESTGEN, + VFE_START_INPUT_SOURCE_AXI, + VFE_START_INPUT_SOURCE_INVALID +}; + +enum VFE_START_OPERATION_MODE { + VFE_START_OPERATION_MODE_CONTINUOUS, + VFE_START_OPERATION_MODE_SNAPSHOT +}; + +enum VFE_START_PIXEL_PATTERN { + VFE_BAYER_RGRGRG, + VFE_BAYER_GRGRGR, + VFE_BAYER_BGBGBG, + VFE_BAYER_GBGBGB, + VFE_YUV_YCbYCr, + VFE_YUV_YCrYCb, + VFE_YUV_CbYCrY, + VFE_YUV_CrYCbY +}; + +enum VFE_BUS_RD_INPUT_PIXEL_PATTERN { + VFE_BAYER_RAW, + VFE_YUV_INTERLEAVED, + VFE_YUV_PSEUDO_PLANAR_Y, + VFE_YUV_PSEUDO_PLANAR_CBCR +}; + +enum VFE_YUV_INPUT_COSITING_MODE { + VFE_YUV_COSITED, + VFE_YUV_INTERPOLATED +}; + +struct vfe_cmd_start { + enum VFE_START_INPUT_SOURCE inputSource; + enum VFE_START_OPERATION_MODE operationMode; + uint8_t snapshotCount; + enum VFE_START_PIXEL_PATTERN pixel; + enum VFE_YUV_INPUT_COSITING_MODE yuvInputCositingMode; +}; + +struct vfe_cmd_output_ack { + uint32_t ybufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME]; + uint32_t chromabufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME]; +}; + +#define VFE_STATS_BUFFER_COUNT 3 + +struct vfe_cmd_stats_setting { + uint16_t frameHDimension; + uint16_t frameVDimension; + uint8_t afBusPrioritySelection; + uint8_t afBusPriority; + uint8_t awbBusPrioritySelection; + uint8_t awbBusPriority; + uint8_t histBusPrioritySelection; + uint8_t histBusPriority; + uint32_t afBuffer[VFE_STATS_BUFFER_COUNT]; + uint32_t awbBuffer[VFE_STATS_BUFFER_COUNT]; + uint32_t histBuffer[VFE_STATS_BUFFER_COUNT]; +}; + +struct vfe_cmd_stats_af_start { + uint8_t enable; + uint8_t windowMode; + uint16_t windowHOffset; + uint16_t windowVOffset; + uint16_t windowWidth; + uint16_t windowHeight; + uint8_t gridForMultiWindows[16]; + uint8_t metricSelection; + int16_t metricMax; + int8_t highPassCoef[7]; + int8_t bufferHeader; +}; + +struct vfe_cmd_stats_af_update { + uint8_t windowMode; + uint16_t windowHOffset; + uint16_t windowVOffset; + uint16_t windowWidth; + uint16_t windowHeight; +}; + +struct vfe_cmd_stats_wb_exp_start { + uint8_t enable; + uint8_t wbExpRegions; + uint8_t wbExpSubRegion; + uint8_t awbYMin; + uint8_t awbYMax; + int8_t awbMCFG[4]; + int16_t awbCCFG[4]; + int8_t axwHeader; +}; + +struct vfe_cmd_stats_wb_exp_update { + uint8_t wbExpRegions; + uint8_t wbExpSubRegion; + int8_t awbYMin; + int8_t awbYMax; + int8_t awbMCFG[4]; + int16_t awbCCFG[4]; +}; + +struct vfe_cmd_stats_af_ack { + uint32_t nextAFOutputBufferAddr; +}; + +struct vfe_cmd_stats_wb_exp_ack { + uint32_t nextWbExpOutputBufferAddr; +}; + +struct vfe_cmd_black_level_config { + uint8_t enable; + uint16_t evenEvenAdjustment; + uint16_t evenOddAdjustment; + uint16_t oddEvenAdjustment; + uint16_t oddOddAdjustment; +}; + +/* 13*1 */ +#define VFE_ROLL_OFF_INIT_TABLE_SIZE 13 +/* 13*16 */ +#define VFE_ROLL_OFF_DELTA_TABLE_SIZE 208 + +struct vfe_cmd_roll_off_config { + uint8_t enable; + uint16_t gridWidth; + uint16_t gridHeight; + uint16_t yDelta; + uint8_t gridXIndex; + uint8_t gridYIndex; + uint16_t gridPixelXIndex; + uint16_t gridPixelYIndex; + uint16_t yDeltaAccum; + uint16_t initTableR[VFE_ROLL_OFF_INIT_TABLE_SIZE]; + uint16_t initTableGr[VFE_ROLL_OFF_INIT_TABLE_SIZE]; + uint16_t initTableB[VFE_ROLL_OFF_INIT_TABLE_SIZE]; + uint16_t initTableGb[VFE_ROLL_OFF_INIT_TABLE_SIZE]; + int16_t deltaTableR[VFE_ROLL_OFF_DELTA_TABLE_SIZE]; + int16_t deltaTableGr[VFE_ROLL_OFF_DELTA_TABLE_SIZE]; + int16_t deltaTableB[VFE_ROLL_OFF_DELTA_TABLE_SIZE]; + int16_t deltaTableGb[VFE_ROLL_OFF_DELTA_TABLE_SIZE]; +}; + +struct vfe_cmd_demux_channel_gain_config { + uint16_t ch0EvenGain; + uint16_t ch0OddGain; + uint16_t ch1Gain; + uint16_t ch2Gain; +}; + +struct vfe_cmds_demosaic_abf { + uint8_t enable; + uint8_t forceOn; + uint8_t shift; + uint16_t lpThreshold; + uint16_t max; + uint16_t min; + uint8_t ratio; +}; + +struct vfe_cmds_demosaic_bpc { + uint8_t enable; + uint16_t fmaxThreshold; + uint16_t fminThreshold; + uint16_t redDiffThreshold; + uint16_t blueDiffThreshold; + uint16_t greenDiffThreshold; +}; + +struct vfe_cmd_demosaic_config { + uint8_t enable; + uint8_t slopeShift; + struct vfe_cmds_demosaic_abf abfConfig; + struct vfe_cmds_demosaic_bpc bpcConfig; +}; + +struct vfe_cmd_demosaic_bpc_update { + struct vfe_cmds_demosaic_bpc bpcUpdate; +}; + +struct vfe_cmd_demosaic_abf_update { + struct vfe_cmds_demosaic_abf abfUpdate; +}; + +struct vfe_cmd_white_balance_config { + uint8_t enable; + uint16_t ch2Gain; + uint16_t ch1Gain; + uint16_t ch0Gain; +}; + +enum VFE_COLOR_CORRECTION_COEF_QFACTOR { + COEF_IS_Q7_SIGNED, + COEF_IS_Q8_SIGNED, + COEF_IS_Q9_SIGNED, + COEF_IS_Q10_SIGNED +}; + +struct vfe_cmd_color_correction_config { + uint8_t enable; + enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor; + int16_t C0; + int16_t C1; + int16_t C2; + int16_t C3; + int16_t C4; + int16_t C5; + int16_t C6; + int16_t C7; + int16_t C8; + int16_t K0; + int16_t K1; + int16_t K2; +}; + +#define VFE_LA_TABLE_LENGTH 256 +struct vfe_cmd_la_config { + uint8_t enable; + int16_t table[VFE_LA_TABLE_LENGTH]; +}; + +#define VFE_GAMMA_TABLE_LENGTH 256 +enum VFE_RGB_GAMMA_TABLE_SELECT { + RGB_GAMMA_CH0_SELECTED, + RGB_GAMMA_CH1_SELECTED, + RGB_GAMMA_CH2_SELECTED, + RGB_GAMMA_CH0_CH1_SELECTED, + RGB_GAMMA_CH0_CH2_SELECTED, + RGB_GAMMA_CH1_CH2_SELECTED, + RGB_GAMMA_CH0_CH1_CH2_SELECTED +}; + +struct vfe_cmd_rgb_gamma_config { + uint8_t enable; + enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect; + int16_t table[VFE_GAMMA_TABLE_LENGTH]; +}; + +struct vfe_cmd_chroma_enhan_config { + uint8_t enable; + int16_t am; + int16_t ap; + int16_t bm; + int16_t bp; + int16_t cm; + int16_t cp; + int16_t dm; + int16_t dp; + int16_t kcr; + int16_t kcb; + int16_t RGBtoYConversionV0; + int16_t RGBtoYConversionV1; + int16_t RGBtoYConversionV2; + uint8_t RGBtoYConversionOffset; +}; + +struct vfe_cmd_chroma_suppression_config { + uint8_t enable; + uint8_t m1; + uint8_t m3; + uint8_t n1; + uint8_t n3; + uint8_t nn1; + uint8_t mm1; +}; + +struct vfe_cmd_asf_config { + uint8_t enable; + uint8_t smoothFilterEnabled; + uint8_t sharpMode; + uint8_t smoothCoefCenter; + uint8_t smoothCoefSurr; + uint8_t normalizeFactor; + uint8_t sharpK1; + uint8_t sharpK2; + uint8_t sharpThreshE1; + int8_t sharpThreshE2; + int8_t sharpThreshE3; + int8_t sharpThreshE4; + int8_t sharpThreshE5; + int8_t filter1Coefficients[9]; + int8_t filter2Coefficients[9]; + uint8_t cropEnable; + uint16_t cropFirstPixel; + uint16_t cropLastPixel; + uint16_t cropFirstLine; + uint16_t cropLastLine; +}; + +struct vfe_cmd_asf_update { + uint8_t enable; + uint8_t smoothFilterEnabled; + uint8_t sharpMode; + uint8_t smoothCoefCenter; + uint8_t smoothCoefSurr; + uint8_t normalizeFactor; + uint8_t sharpK1; + uint8_t sharpK2; + uint8_t sharpThreshE1; + int8_t sharpThreshE2; + int8_t sharpThreshE3; + int8_t sharpThreshE4; + int8_t sharpThreshE5; + int8_t filter1Coefficients[9]; + int8_t filter2Coefficients[9]; + uint8_t cropEnable; +}; + +enum VFE_TEST_GEN_SYNC_EDGE { + VFE_TEST_GEN_SYNC_EDGE_ActiveHigh, + VFE_TEST_GEN_SYNC_EDGE_ActiveLow +}; + +struct vfe_cmd_test_gen_start { + uint8_t pixelDataSelect; + uint8_t systematicDataSelect; + enum VFE_TEST_GEN_SYNC_EDGE hsyncEdge; + enum VFE_TEST_GEN_SYNC_EDGE vsyncEdge; + uint16_t numFrame; + enum VFE_RAW_PIXEL_DATA_SIZE pixelDataSize; + uint16_t imageWidth; + uint16_t imageHeight; + uint32_t startOfFrameOffset; + uint32_t endOfFrameNOffset; + uint16_t startOfLineOffset; + uint16_t endOfLineNOffset; + uint16_t hbi; + uint8_t vblEnable; + uint16_t vbl; + uint8_t startOfFrameDummyLine; + uint8_t endOfFrameDummyLine; + uint8_t unicolorBarEnable; + uint8_t colorBarsSplitEnable; + uint8_t unicolorBarSelect; + enum VFE_START_PIXEL_PATTERN colorBarsPixelPattern; + uint8_t colorBarsRotatePeriod; + uint16_t testGenRandomSeed; +}; + +struct vfe_cmd_bus_pm_start { + uint8_t output2YWrPmEnable; + uint8_t output2CbcrWrPmEnable; + uint8_t output1YWrPmEnable; + uint8_t output1CbcrWrPmEnable; +}; + +struct vfe_cmd_camif_frame_update { + struct vfe_cmds_camif_frame camifFrame; +}; + +struct vfe_cmd_sync_timer_setting { + uint8_t whichSyncTimer; + uint8_t operation; + uint8_t polarity; + uint16_t repeatCount; + uint16_t hsyncCount; + uint32_t pclkCount; + uint32_t outputDuration; +}; + +struct vfe_cmd_async_timer_setting { + uint8_t whichAsyncTimer; + uint8_t operation; + uint8_t polarity; + uint16_t repeatCount; + uint16_t inactiveCount; + uint32_t activeCount; +}; + +struct vfe_frame_skip_counts { + uint32_t totalFrameCount; + uint32_t output1Count; + uint32_t output2Count; +}; + +enum VFE_AXI_RD_UNPACK_HBI_SEL { + VFE_AXI_RD_HBI_32_CLOCK_CYCLES, + VFE_AXI_RD_HBI_64_CLOCK_CYCLES, + VFE_AXI_RD_HBI_128_CLOCK_CYCLES, + VFE_AXI_RD_HBI_256_CLOCK_CYCLES, + VFE_AXI_RD_HBI_512_CLOCK_CYCLES, + VFE_AXI_RD_HBI_1024_CLOCK_CYCLES, + VFE_AXI_RD_HBI_2048_CLOCK_CYCLES, + VFE_AXI_RD_HBI_4096_CLOCK_CYCLES +}; + +struct vfe_cmd_axi_input_config { + uint32_t fragAddr[4]; + uint8_t totalFragmentCount; + uint16_t ySize; + uint16_t xOffset; + uint16_t xSize; + uint16_t rowIncrement; + uint16_t numOfRows; + enum VFE_AXI_BURST_LENGTH burstLength; + uint8_t unpackPhase; + enum VFE_AXI_RD_UNPACK_HBI_SEL unpackHbi; + enum VFE_RAW_PIXEL_DATA_SIZE pixelSize; + uint8_t padRepeatCountLeft; + uint8_t padRepeatCountRight; + uint8_t padRepeatCountTop; + uint8_t padRepeatCountBottom; + uint8_t padLeftComponentSelectCycle0; + uint8_t padLeftComponentSelectCycle1; + uint8_t padLeftComponentSelectCycle2; + uint8_t padLeftComponentSelectCycle3; + uint8_t padLeftStopCycle0; + uint8_t padLeftStopCycle1; + uint8_t padLeftStopCycle2; + uint8_t padLeftStopCycle3; + uint8_t padRightComponentSelectCycle0; + uint8_t padRightComponentSelectCycle1; + uint8_t padRightComponentSelectCycle2; + uint8_t padRightComponentSelectCycle3; + uint8_t padRightStopCycle0; + uint8_t padRightStopCycle1; + uint8_t padRightStopCycle2; + uint8_t padRightStopCycle3; + uint8_t padTopLineCount; + uint8_t padBottomLineCount; +}; + +struct vfe_interrupt_status { + uint8_t camifErrorIrq; + uint8_t camifSofIrq; + uint8_t camifEolIrq; + uint8_t camifEofIrq; + uint8_t camifEpoch1Irq; + uint8_t camifEpoch2Irq; + uint8_t camifOverflowIrq; + uint8_t ceIrq; + uint8_t regUpdateIrq; + uint8_t resetAckIrq; + uint8_t encYPingpongIrq; + uint8_t encCbcrPingpongIrq; + uint8_t viewYPingpongIrq; + uint8_t viewCbcrPingpongIrq; + uint8_t rdPingpongIrq; + uint8_t afPingpongIrq; + uint8_t awbPingpongIrq; + uint8_t histPingpongIrq; + uint8_t encIrq; + uint8_t viewIrq; + uint8_t busOverflowIrq; + uint8_t afOverflowIrq; + uint8_t awbOverflowIrq; + uint8_t syncTimer0Irq; + uint8_t syncTimer1Irq; + uint8_t syncTimer2Irq; + uint8_t asyncTimer0Irq; + uint8_t asyncTimer1Irq; + uint8_t asyncTimer2Irq; + uint8_t asyncTimer3Irq; + uint8_t axiErrorIrq; + uint8_t violationIrq; + uint8_t anyErrorIrqs; + uint8_t anyOutput1PathIrqs; + uint8_t anyOutput2PathIrqs; + uint8_t anyOutputPathIrqs; + uint8_t anyAsyncTimerIrqs; + uint8_t anySyncTimerIrqs; + uint8_t anyIrqForActiveStatesOnly; +}; + +enum VFE_MESSAGE_ID { + VFE_MSG_ID_RESET_ACK, + VFE_MSG_ID_START_ACK, + VFE_MSG_ID_STOP_ACK, + VFE_MSG_ID_UPDATE_ACK, + VFE_MSG_ID_OUTPUT_P, + VFE_MSG_ID_OUTPUT_V, + VFE_MSG_ID_OUTPUT_S, + VFE_MSG_ID_OUTPUT_T, + VFE_MSG_ID_SNAPSHOT_DONE, + VFE_MSG_ID_STATS_AUTOFOCUS, + VFE_MSG_ID_STATS_WB_EXP, + VFE_MSG_ID_EPOCH1, + VFE_MSG_ID_EPOCH2, + VFE_MSG_ID_SYNC_TIMER0_DONE, + VFE_MSG_ID_SYNC_TIMER1_DONE, + VFE_MSG_ID_SYNC_TIMER2_DONE, + VFE_MSG_ID_ASYNC_TIMER0_DONE, + VFE_MSG_ID_ASYNC_TIMER1_DONE, + VFE_MSG_ID_ASYNC_TIMER2_DONE, + VFE_MSG_ID_ASYNC_TIMER3_DONE, + VFE_MSG_ID_AF_OVERFLOW, + VFE_MSG_ID_AWB_OVERFLOW, + VFE_MSG_ID_AXI_ERROR, + VFE_MSG_ID_CAMIF_OVERFLOW, + VFE_MSG_ID_VIOLATION, + VFE_MSG_ID_CAMIF_ERROR, + VFE_MSG_ID_BUS_OVERFLOW, + VFE_MSG_ID_SOF_ACK, +}; + +struct vfe_msg_stats_autofocus { + uint32_t afBuffer; + uint32_t frameCounter; +}; + +struct vfe_msg_stats_wb_exp { + uint32_t awbBuffer; + uint32_t frameCounter; +}; + +struct vfe_frame_bpc_info { + uint32_t greenDefectPixelCount; + uint32_t redBlueDefectPixelCount; +}; + +struct vfe_frame_asf_info { + uint32_t asfMaxEdge; + uint32_t asfHbiCount; +}; + +struct vfe_msg_camif_status { + uint8_t camifState; + uint32_t pixelCount; + uint32_t lineCount; +}; + +struct vfe_bus_pm_per_path { + uint32_t yWrPmStats0; + uint32_t yWrPmStats1; + uint32_t cbcrWrPmStats0; + uint32_t cbcrWrPmStats1; +}; + +struct vfe_bus_performance_monitor { + struct vfe_bus_pm_per_path encPathPmInfo; + struct vfe_bus_pm_per_path viewPathPmInfo; +}; + +struct vfe_irq_thread_msg { + uint32_t vfeIrqStatus; + uint32_t camifStatus; + uint32_t demosaicStatus; + uint32_t asfMaxEdge; + struct vfe_bus_performance_monitor pmInfo; +}; + +struct vfe_msg_output { + uint32_t yBuffer; + uint32_t cbcrBuffer; + struct vfe_frame_bpc_info bpcInfo; + struct vfe_frame_asf_info asfInfo; + uint32_t frameCounter; + struct vfe_bus_pm_per_path pmData; +}; + +struct vfe_message { + enum VFE_MESSAGE_ID _d; + union { + struct vfe_msg_output msgOutput1; + struct vfe_msg_output msgOutput2; + struct vfe_msg_stats_autofocus msgStatsAf; + struct vfe_msg_stats_wb_exp msgStatsWbExp; + struct vfe_msg_camif_status msgCamifError; + struct vfe_bus_performance_monitor msgBusOverflow; + } _u; +}; + +/* New one for 8k */ +struct msm_vfe_command_8k { + int id; + uint16_t length; + void *value; +}; + +struct vfe_frame_extra { + struct vfe_frame_bpc_info bpcInfo; + struct vfe_frame_asf_info asfInfo; + uint32_t frameCounter; + struct vfe_bus_pm_per_path pmData; +}; +#endif /* __MSM_VFE8X_H__ */ diff --git a/drivers/media/video/msm_zsl/msm_vfe8x_proc.c b/drivers/media/video/msm_zsl/msm_vfe8x_proc.c new file mode 100644 index 00000000000..97645575054 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe8x_proc.c @@ -0,0 +1,3888 @@ +/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "msm_vfe8x_proc.h" +#include +#include + +struct isr_queue_cmd { + struct list_head list; + struct vfe_interrupt_status vfeInterruptStatus; + struct vfe_frame_asf_info vfeAsfFrameInfo; + struct vfe_frame_bpc_info vfeBpcFrameInfo; + struct vfe_msg_camif_status vfeCamifStatusLocal; + struct vfe_bus_performance_monitor vfePmData; +}; + +struct msm_vfe8x_ctrl { + /* bit 1:0 ENC_IRQ_MASK = 0x11: + * generate IRQ when both y and cbcr frame is ready. */ + + /* bit 1:0 VIEW_IRQ_MASK= 0x11: + * generate IRQ when both y and cbcr frame is ready. */ + struct vfe_irq_composite_mask_config vfeIrqCompositeMaskLocal; + struct vfe_module_enable vfeModuleEnableLocal; + struct vfe_camif_cfg_data vfeCamifConfigLocal; + struct vfe_interrupt_mask vfeImaskLocal; + struct vfe_stats_cmd_data vfeStatsCmdLocal; + struct vfe_bus_cfg_data vfeBusConfigLocal; + struct vfe_cmd_bus_pm_start vfeBusPmConfigLocal; + struct vfe_bus_cmd_data vfeBusCmdLocal; + enum vfe_interrupt_name vfeInterruptNameLocal; + uint32_t vfeLaBankSel; + struct vfe_gamma_lut_sel vfeGammaLutSel; + + boolean vfeStartAckPendingFlag; + boolean vfeStopAckPending; + boolean vfeResetAckPending; + boolean vfeUpdateAckPending; + + enum VFE_AXI_OUTPUT_MODE axiOutputMode; + enum VFE_START_OPERATION_MODE vfeOperationMode; + + atomic_t vfe_serv_interrupt; + + uint32_t vfeSnapShotCount; + uint32_t vfeRequestedSnapShotCount; + boolean vfeStatsPingPongReloadFlag; + uint32_t vfeFrameId; + + struct vfe_cmd_frame_skip_config vfeFrameSkip; + uint32_t vfeFrameSkipPattern; + uint8_t vfeFrameSkipCount; + uint8_t vfeFrameSkipPeriod; + + boolean vfeTestGenStartFlag; + uint32_t vfeImaskPacked; + uint32_t vfeImaskCompositePacked; + enum VFE_RAW_PIXEL_DATA_SIZE axiInputDataSize; + struct vfe_irq_thread_msg vfeIrqThreadMsgLocal; + + struct vfe_output_path_combo viewPath; + struct vfe_output_path_combo encPath; + struct vfe_frame_skip_counts vfeDroppedFrameCounts; + struct vfe_stats_control afStatsControl; + struct vfe_stats_control awbStatsControl; + + enum VFE_STATE vstate; + + struct msm_vfe_callback *resp; + struct vfe_frame_extra extdata; + + struct isr_queue_cmd irqs[10]; + spinlock_t irqs_lock; + int irq_get; + int irq_put; + + int vfeirq; + void __iomem *vfebase; + + void *syncdata; +}; + +static struct msm_vfe8x_ctrl *ctrl; +static spinlock_t msm_vfe_ctrl_lock; + +static void vfe_prog_hw(uint8_t *hwreg, uint32_t *inptr, uint32_t regcnt) +{ + /* unsigned long flags; */ + uint32_t i; + uint32_t *p; + + /* @todo This is causing issues, need further investigate */ + /* spin_lock_irqsave(&ctrl->io_lock, flags); */ + + p = (uint32_t *)(hwreg); + for (i = 0; i < (regcnt >> 2); i++) + writel(*inptr++, p++); + /* *p++ = *inptr++; */ + + /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */ +} + +static void +vfe_set_bus_pipo_addr(struct vfe_output_path_combo *vpath, + struct vfe_output_path_combo *epath) +{ + vpath->yPath.hwRegPingAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PING_ADDR); + vpath->yPath.hwRegPongAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PONG_ADDR); + vpath->cbcrPath.hwRegPingAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PING_ADDR); + vpath->cbcrPath.hwRegPongAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PONG_ADDR); + + epath->yPath.hwRegPingAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR); + epath->yPath.hwRegPongAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PONG_ADDR); + epath->cbcrPath.hwRegPingAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PING_ADDR); + epath->cbcrPath.hwRegPongAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PONG_ADDR); +} + +static void vfe_axi_output(struct vfe_cmd_axi_output_config *in, + struct vfe_output_path_combo *out1, + struct vfe_output_path_combo *out2, uint16_t out) +{ + struct vfe_axi_out_cfg cmd; + + uint16_t temp; + uint32_t burstLength; + + memset(&cmd, 0, sizeof(cmd)); + /* force it to burst length 4, hardware does not support it. */ + burstLength = 1; + + /* AXI Output 2 Y Configuration*/ + /* VFE_BUS_ENC_Y_WR_PING_ADDR */ + cmd.out2YPingAddr = out2->yPath.addressBuffer[0]; + + /* VFE_BUS_ENC_Y_WR_PONG_ADDR */ + cmd.out2YPongAddr = out2->yPath.addressBuffer[1]; + + /* VFE_BUS_ENC_Y_WR_IMAGE_SIZE */ + cmd.out2YImageHeight = in->output2.outputY.imageHeight; + /* convert the image width and row increment to be in + * unit of 64bit (8 bytes) */ + temp = (in->output2.outputY.imageWidth + (out - 1)) / out; + cmd.out2YImageWidthin64bit = temp; + + /* VFE_BUS_ENC_Y_WR_BUFFER_CFG */ + cmd.out2YBurstLength = burstLength; + cmd.out2YNumRows = in->output2.outputY.outRowCount; + temp = (in->output2.outputY.outRowIncrement + (out - 1)) / out; + cmd.out2YRowIncrementIn64bit = temp; + + /* AXI Output 2 Cbcr Configuration*/ + /* VFE_BUS_ENC_Cbcr_WR_PING_ADDR */ + cmd.out2CbcrPingAddr = out2->cbcrPath.addressBuffer[0]; + + /* VFE_BUS_ENC_Cbcr_WR_PONG_ADDR */ + cmd.out2CbcrPongAddr = out2->cbcrPath.addressBuffer[1]; + + /* VFE_BUS_ENC_Cbcr_WR_IMAGE_SIZE */ + cmd.out2CbcrImageHeight = in->output2.outputCbcr.imageHeight; + temp = (in->output2.outputCbcr.imageWidth + (out - 1)) / out; + cmd.out2CbcrImageWidthIn64bit = temp; + + /* VFE_BUS_ENC_Cbcr_WR_BUFFER_CFG */ + cmd.out2CbcrBurstLength = burstLength; + cmd.out2CbcrNumRows = in->output2.outputCbcr.outRowCount; + temp = (in->output2.outputCbcr.outRowIncrement + (out - 1)) / out; + cmd.out2CbcrRowIncrementIn64bit = temp; + + /* AXI Output 1 Y Configuration */ + /* VFE_BUS_VIEW_Y_WR_PING_ADDR */ + cmd.out1YPingAddr = out1->yPath.addressBuffer[0]; + + /* VFE_BUS_VIEW_Y_WR_PONG_ADDR */ + cmd.out1YPongAddr = out1->yPath.addressBuffer[1]; + + /* VFE_BUS_VIEW_Y_WR_IMAGE_SIZE */ + cmd.out1YImageHeight = in->output1.outputY.imageHeight; + temp = (in->output1.outputY.imageWidth + (out - 1)) / out; + cmd.out1YImageWidthin64bit = temp; + + /* VFE_BUS_VIEW_Y_WR_BUFFER_CFG */ + cmd.out1YBurstLength = burstLength; + cmd.out1YNumRows = in->output1.outputY.outRowCount; + + temp = (in->output1.outputY.outRowIncrement + (out - 1)) / out; + cmd.out1YRowIncrementIn64bit = temp; + + /* AXI Output 1 Cbcr Configuration*/ + cmd.out1CbcrPingAddr = out1->cbcrPath.addressBuffer[0]; + + /* VFE_BUS_VIEW_Cbcr_WR_PONG_ADDR */ + cmd.out1CbcrPongAddr = out1->cbcrPath.addressBuffer[1]; + + /* VFE_BUS_VIEW_Cbcr_WR_IMAGE_SIZE */ + cmd.out1CbcrImageHeight = in->output1.outputCbcr.imageHeight; + temp = (in->output1.outputCbcr.imageWidth + (out - 1)) / out; + cmd.out1CbcrImageWidthIn64bit = temp; + + cmd.out1CbcrBurstLength = burstLength; + cmd.out1CbcrNumRows = in->output1.outputCbcr.outRowCount; + temp = (in->output1.outputCbcr.outRowIncrement + (out - 1)) / out; + + cmd.out1CbcrRowIncrementIn64bit = temp; + + vfe_prog_hw(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR, + (uint32_t *)&cmd, sizeof(cmd)); +} + +static void vfe_reg_bus_cfg(struct vfe_bus_cfg_data *in) +{ + struct vfe_axi_bus_cfg cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.stripeRdPathEn = in->stripeRdPathEn; + cmd.encYWrPathEn = in->encYWrPathEn; + cmd.encCbcrWrPathEn = in->encCbcrWrPathEn; + cmd.viewYWrPathEn = in->viewYWrPathEn; + cmd.viewCbcrWrPathEn = in->viewCbcrWrPathEn; + cmd.rawPixelDataSize = (uint32_t)in->rawPixelDataSize; + cmd.rawWritePathSelect = (uint32_t)in->rawWritePathSelect; + + /* program vfe_bus_cfg */ + writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CFG); +} + +static void vfe_reg_camif_config(struct vfe_camif_cfg_data *in) +{ + struct VFE_CAMIFConfigType cfg; + + memset(&cfg, 0, sizeof(cfg)); + + cfg.VSyncEdge = in->camifCfgFromCmd.vSyncEdge; + + cfg.HSyncEdge = in->camifCfgFromCmd.hSyncEdge; + + cfg.syncMode = in->camifCfgFromCmd.syncMode; + + cfg.vfeSubsampleEnable = in->camifCfgFromCmd.vfeSubSampleEnable; + + cfg.busSubsampleEnable = in->camifCfgFromCmd.busSubSampleEnable; + + cfg.camif2vfeEnable = in->camif2OutputEnable; + + cfg.camif2busEnable = in->camif2BusEnable; + + cfg.irqSubsampleEnable = in->camifCfgFromCmd.irqSubSampleEnable; + + cfg.binningEnable = in->camifCfgFromCmd.binningEnable; + + cfg.misrEnable = in->camifCfgFromCmd.misrEnable; + + /* program camif_config */ + writel(*((uint32_t *)&cfg), ctrl->vfebase + CAMIF_CONFIG); +} + +static void vfe_reg_bus_cmd(struct vfe_bus_cmd_data *in) +{ + struct vfe_buscmd cmd; + memset(&cmd, 0, sizeof(cmd)); + + cmd.stripeReload = in->stripeReload; + cmd.busPingpongReload = in->busPingpongReload; + cmd.statsPingpongReload = in->statsPingpongReload; + + writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CMD); + + CDBG("bus command = 0x%x\n", (*((uint32_t *)&cmd))); + + /* this is needed, as the control bits are pulse based. + * Don't want to reload bus pingpong again. */ + in->busPingpongReload = 0; + in->statsPingpongReload = 0; + in->stripeReload = 0; +} + +static void vfe_reg_module_cfg(struct vfe_module_enable *in) +{ + struct vfe_mod_enable ena; + + memset(&ena, 0, sizeof(ena)); + + ena.blackLevelCorrectionEnable = in->blackLevelCorrectionEnable; + ena.lensRollOffEnable = in->lensRollOffEnable; + ena.demuxEnable = in->demuxEnable; + ena.chromaUpsampleEnable = in->chromaUpsampleEnable; + ena.demosaicEnable = in->demosaicEnable; + ena.statsEnable = in->statsEnable; + ena.cropEnable = in->cropEnable; + ena.mainScalerEnable = in->mainScalerEnable; + ena.whiteBalanceEnable = in->whiteBalanceEnable; + ena.colorCorrectionEnable = in->colorCorrectionEnable; + ena.yHistEnable = in->yHistEnable; + ena.skinToneEnable = in->skinToneEnable; + ena.lumaAdaptationEnable = in->lumaAdaptationEnable; + ena.rgbLUTEnable = in->rgbLUTEnable; + ena.chromaEnhanEnable = in->chromaEnhanEnable; + ena.asfEnable = in->asfEnable; + ena.chromaSuppressionEnable = in->chromaSuppressionEnable; + ena.chromaSubsampleEnable = in->chromaSubsampleEnable; + ena.scaler2YEnable = in->scaler2YEnable; + ena.scaler2CbcrEnable = in->scaler2CbcrEnable; + + writel(*((uint32_t *)&ena), ctrl->vfebase + VFE_MODULE_CFG); +} + +static void vfe_program_dmi_cfg(enum VFE_DMI_RAM_SEL bankSel) +{ + /* set bit 8 for auto increment. */ + uint32_t value = (uint32_t) ctrl->vfebase + VFE_DMI_CFG_DEFAULT; + + value += (uint32_t)bankSel; + /* CDBG("dmi cfg input bank is 0x%x\n", bankSel); */ + + writel(value, ctrl->vfebase + VFE_DMI_CFG); + writel(0, ctrl->vfebase + VFE_DMI_ADDR); +} + +static void vfe_write_lens_roll_off_table(struct vfe_cmd_roll_off_config *in) +{ + uint16_t i; + uint32_t data; + + uint16_t *initGr = in->initTableGr; + uint16_t *initGb = in->initTableGb; + uint16_t *initB = in->initTableB; + uint16_t *initR = in->initTableR; + + int16_t *pDeltaGr = in->deltaTableGr; + int16_t *pDeltaGb = in->deltaTableGb; + int16_t *pDeltaB = in->deltaTableB; + int16_t *pDeltaR = in->deltaTableR; + + vfe_program_dmi_cfg(ROLLOFF_RAM); + + /* first pack and write init table */ + for (i = 0; i < VFE_ROLL_OFF_INIT_TABLE_SIZE; i++) { + data = (((uint32_t)(*initR)) & 0x0000FFFF) | + (((uint32_t)(*initGr)) << 16); + initR++; + initGr++; + + writel(data, ctrl->vfebase + VFE_DMI_DATA_LO); + + data = (((uint32_t)(*initB)) & 0x0000FFFF) | + (((uint32_t)(*initGb))<<16); + initB++; + initGb++; + + writel(data, ctrl->vfebase + VFE_DMI_DATA_LO); + } + + /* there are gaps between the init table and delta table, + * set the offset for delta table. */ + writel(LENS_ROLL_OFF_DELTA_TABLE_OFFSET, ctrl->vfebase + VFE_DMI_ADDR); + + /* pack and write delta table */ + for (i = 0; i < VFE_ROLL_OFF_DELTA_TABLE_SIZE; i++) { + data = (((int)(*pDeltaR)) & 0x0000FFFF) | + (((int)(*pDeltaGr))<<16); + pDeltaR++; + pDeltaGr++; + + writel(data, ctrl->vfebase + VFE_DMI_DATA_LO); + + data = (((int)(*pDeltaB)) & 0x0000FFFF) | + (((int)(*pDeltaGb))<<16); + pDeltaB++; + pDeltaGb++; + + writel(data, ctrl->vfebase + VFE_DMI_DATA_LO); + } + + /* After DMI transfer, to make it safe, need to set the + * DMI_CFG to unselect any SRAM + */ + /* unselect the SRAM Bank. */ + writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG); +} + +static void vfe_set_default_reg_values(void) +{ + writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_0); + writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_1); + writel(0xFFFFF, ctrl->vfebase + VFE_CGC_OVERRIDE); + + /* default frame drop period and pattern */ + writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG); + writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG); + writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN); + writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN); + writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_CFG); + writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_CFG); + writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN); + writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN); + writel(0, ctrl->vfebase + VFE_CLAMP_MIN_CFG); + writel(0xFFFFFF, ctrl->vfebase + VFE_CLAMP_MAX_CFG); +} + +static void vfe_config_demux(uint32_t period, uint32_t even, uint32_t odd) +{ + writel(period, ctrl->vfebase + VFE_DEMUX_CFG); + writel(even, ctrl->vfebase + VFE_DEMUX_EVEN_CFG); + writel(odd, ctrl->vfebase + VFE_DEMUX_ODD_CFG); +} + +static void vfe_pm_stop(void) +{ + writel(VFE_PERFORMANCE_MONITOR_STOP, ctrl->vfebase + VFE_BUS_PM_CMD); +} + +static void vfe_camif_stop_immediately(void) +{ + writel(CAMIF_COMMAND_STOP_IMMEDIATELY, ctrl->vfebase + CAMIF_COMMAND); + writel(0, ctrl->vfebase + VFE_CGC_OVERRIDE); +} + +static void vfe_program_reg_update_cmd(uint32_t value) +{ + writel(value, ctrl->vfebase + VFE_REG_UPDATE_CMD); +} + +static void vfe_program_global_reset_cmd(uint32_t value) +{ + writel(value, ctrl->vfebase + VFE_GLOBAL_RESET_CMD); +} + +static void vfe_program_axi_cmd(uint32_t value) +{ + writel(value, ctrl->vfebase + VFE_AXI_CMD); +} + +static void vfe_program_irq_composite_mask(uint32_t value) +{ + writel(value, ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK); +} + +static inline void vfe_program_irq_mask(uint32_t value) +{ + writel(value, ctrl->vfebase + VFE_IRQ_MASK); +} + +static uint32_t vfe_read_axi_status(void) +{ + return readl(ctrl->vfebase + VFE_AXI_STATUS); +} + +static void +vfe_set_stats_pingpong_address(struct vfe_stats_control *afControl, + struct vfe_stats_control *awbControl) +{ + afControl->hwRegPingAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); + afControl->hwRegPongAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); + + awbControl->hwRegPingAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); + awbControl->hwRegPongAddress = (uint8_t *) + (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); +} + +static void vfe_program_lut_bank_sel(struct vfe_gamma_lut_sel *in) +{ + struct VFE_GammaLutSelect_ConfigCmdType cmd; + + memset(&cmd, 0, sizeof(cmd)); + + cmd.ch0BankSelect = in->ch0BankSelect; + cmd.ch1BankSelect = in->ch1BankSelect; + cmd.ch2BankSelect = in->ch2BankSelect; + CDBG("VFE gamma lut bank selection is 0x%x\n", *((uint32_t *)&cmd)); + vfe_prog_hw(ctrl->vfebase + VFE_LUT_BANK_SEL, + (uint32_t *)&cmd, sizeof(cmd)); +} + +static void vfe_program_stats_cmd(struct vfe_stats_cmd_data *in) +{ + struct VFE_StatsCmdType stats; + memset(&stats, 0, sizeof(stats)); + + stats.autoFocusEnable = in->autoFocusEnable; + stats.axwEnable = in->axwEnable; + stats.histEnable = in->histEnable; + stats.clearHistEnable = in->clearHistEnable; + stats.histAutoClearEnable = in->histAutoClearEnable; + stats.colorConversionEnable = in->colorConversionEnable; + + writel(*((uint32_t *)&stats), ctrl->vfebase + VFE_STATS_CMD); +} + +static void vfe_pm_start(struct vfe_cmd_bus_pm_start *in) +{ + struct VFE_Bus_Pm_ConfigCmdType cmd; + memset(&cmd, 0, sizeof(struct VFE_Bus_Pm_ConfigCmdType)); + + cmd.output2YWrPmEnable = in->output2YWrPmEnable; + cmd.output2CbcrWrPmEnable = in->output2CbcrWrPmEnable; + cmd.output1YWrPmEnable = in->output1YWrPmEnable; + cmd.output1CbcrWrPmEnable = in->output1CbcrWrPmEnable; + + vfe_prog_hw(ctrl->vfebase + VFE_BUS_PM_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +static void vfe_8k_pm_start(struct vfe_cmd_bus_pm_start *in) +{ + in->output1CbcrWrPmEnable = ctrl->vfeBusConfigLocal.viewCbcrWrPathEn; + in->output1YWrPmEnable = ctrl->vfeBusConfigLocal.viewYWrPathEn; + in->output2CbcrWrPmEnable = ctrl->vfeBusConfigLocal.encCbcrWrPathEn; + in->output2YWrPmEnable = ctrl->vfeBusConfigLocal.encYWrPathEn; + + if (in->output1CbcrWrPmEnable || in->output1YWrPmEnable) + ctrl->viewPath.pmEnabled = TRUE; + + if (in->output2CbcrWrPmEnable || in->output2YWrPmEnable) + ctrl->encPath.pmEnabled = TRUE; + + vfe_pm_start(in); + + writel(VFE_PERFORMANCE_MONITOR_GO, ctrl->vfebase + VFE_BUS_PM_CMD); +} + +static uint32_t vfe_irq_pack(struct vfe_interrupt_mask data) +{ + struct vfe_irqenable packedData; + + memset(&packedData, 0, sizeof(packedData)); + + packedData.camifErrorIrq = data.camifErrorIrq; + packedData.camifSofIrq = data.camifSofIrq; + packedData.camifEolIrq = data.camifEolIrq; + packedData.camifEofIrq = data.camifEofIrq; + packedData.camifEpoch1Irq = data.camifEpoch1Irq; + packedData.camifEpoch2Irq = data.camifEpoch2Irq; + packedData.camifOverflowIrq = data.camifOverflowIrq; + packedData.ceIrq = data.ceIrq; + packedData.regUpdateIrq = data.regUpdateIrq; + packedData.resetAckIrq = data.resetAckIrq; + packedData.encYPingpongIrq = data.encYPingpongIrq; + packedData.encCbcrPingpongIrq = data.encCbcrPingpongIrq; + packedData.viewYPingpongIrq = data.viewYPingpongIrq; + packedData.viewCbcrPingpongIrq = data.viewCbcrPingpongIrq; + packedData.rdPingpongIrq = data.rdPingpongIrq; + packedData.afPingpongIrq = data.afPingpongIrq; + packedData.awbPingpongIrq = data.awbPingpongIrq; + packedData.histPingpongIrq = data.histPingpongIrq; + packedData.encIrq = data.encIrq; + packedData.viewIrq = data.viewIrq; + packedData.busOverflowIrq = data.busOverflowIrq; + packedData.afOverflowIrq = data.afOverflowIrq; + packedData.awbOverflowIrq = data.awbOverflowIrq; + packedData.syncTimer0Irq = data.syncTimer0Irq; + packedData.syncTimer1Irq = data.syncTimer1Irq; + packedData.syncTimer2Irq = data.syncTimer2Irq; + packedData.asyncTimer0Irq = data.asyncTimer0Irq; + packedData.asyncTimer1Irq = data.asyncTimer1Irq; + packedData.asyncTimer2Irq = data.asyncTimer2Irq; + packedData.asyncTimer3Irq = data.asyncTimer3Irq; + packedData.axiErrorIrq = data.axiErrorIrq; + packedData.violationIrq = data.violationIrq; + + return *((uint32_t *)&packedData); +} + +static uint32_t +vfe_irq_composite_pack(struct vfe_irq_composite_mask_config data) +{ + struct VFE_Irq_Composite_MaskType packedData; + + memset(&packedData, 0, sizeof(packedData)); + + packedData.encIrqComMaskBits = data.encIrqComMask; + packedData.viewIrqComMaskBits = data.viewIrqComMask; + packedData.ceDoneSelBits = data.ceDoneSel; + + return *((uint32_t *)&packedData); +} + +static void vfe_addr_convert(struct msm_vfe_phy_info *pinfo, + enum vfe_resp_msg type, void *data, void **ext, + int *elen) +{ + switch (type) { + case VFE_MSG_OUTPUT_P: + case VFE_MSG_OUTPUT_V:{ + pinfo->y_phy = + ((struct vfe_message *)data)->_u.msgOutput2.yBuffer; + pinfo->cbcr_phy = + ((struct vfe_message *)data)->_u.msgOutput2. + cbcrBuffer; + ctrl->extdata.bpcInfo = + ((struct vfe_message *)data)->_u.msgOutput2.bpcInfo; + ctrl->extdata.asfInfo = + ((struct vfe_message *)data)->_u.msgOutput2.asfInfo; + ctrl->extdata.frameCounter = + ((struct vfe_message *)data)->_u.msgOutput2. + frameCounter; + ctrl->extdata.pmData = + ((struct vfe_message *)data)->_u.msgOutput2.pmData; + *ext = &ctrl->extdata; + *elen = sizeof(ctrl->extdata); + } + break; + + case VFE_MSG_STATS_AF: + pinfo->sbuf_phy = + ((struct vfe_message *)data)->_u.msgStatsAf.afBuffer; + break; + + case VFE_MSG_STATS_WE: + pinfo->sbuf_phy = + ((struct vfe_message *)data)->_u.msgStatsWbExp.awbBuffer; + break; + + default: + break; + } /* switch */ +} + +static boolean vfe_send_preview_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data); +static boolean vfe_send_video_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data); +static boolean vfe_send_mainimage_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data); +static boolean vfe_send_thumbnail_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data); +static boolean vfe_send_af_stats_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data); +static boolean vfe_send_awb_stats_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data); +static boolean vfe_send_camif_error_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data); +static boolean vfe_send_bus_overflow_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data); +static boolean vfe_send_sof_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data); + +static boolean invalid(struct msm_vfe_resp *rp, + struct vfe_message *_m, void *_d) +{ + BUG_ON(1); /* this function should not be called. */ + return FALSE; +} + +static struct { + boolean (*fn)(struct msm_vfe_resp *rp, struct vfe_message *msg, + void *data); + enum vfe_resp_msg rt; /* reponse type */ +} vfe_funcs[] = { + [VFE_MSG_ID_RESET_ACK] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_START_ACK] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_STOP_ACK] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_UPDATE_ACK] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_OUTPUT_P] = { vfe_send_preview_msg, VFE_MSG_OUTPUT_P }, + [VFE_MSG_ID_OUTPUT_V] = { vfe_send_video_msg, VFE_MSG_OUTPUT_V }, + [VFE_MSG_ID_OUTPUT_S] = { vfe_send_mainimage_msg, VFE_MSG_OUTPUT_S }, + [VFE_MSG_ID_OUTPUT_T] = { vfe_send_thumbnail_msg, VFE_MSG_OUTPUT_T }, + [VFE_MSG_ID_SNAPSHOT_DONE] = { NULL, VFE_MSG_SNAPSHOT }, + [VFE_MSG_ID_STATS_AUTOFOCUS] = { vfe_send_af_stats_msg, + VFE_MSG_STATS_AF }, + [VFE_MSG_ID_STATS_WB_EXP] = { vfe_send_awb_stats_msg, + VFE_MSG_STATS_WE }, + [VFE_MSG_ID_EPOCH1] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_EPOCH2] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_SYNC_TIMER0_DONE] = { invalid }, + [VFE_MSG_ID_SYNC_TIMER1_DONE] = { invalid }, + [VFE_MSG_ID_SYNC_TIMER2_DONE] = { invalid }, + [VFE_MSG_ID_ASYNC_TIMER0_DONE] = { invalid }, + [VFE_MSG_ID_ASYNC_TIMER1_DONE] = { invalid }, + [VFE_MSG_ID_ASYNC_TIMER2_DONE] = { invalid }, + [VFE_MSG_ID_ASYNC_TIMER3_DONE] = { invalid }, + [VFE_MSG_ID_AF_OVERFLOW] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_AWB_OVERFLOW] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_AXI_ERROR] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_CAMIF_OVERFLOW] = { NULL, VFE_MSG_GENERAL }, + [VFE_MSG_ID_VIOLATION] = { invalid }, + [VFE_MSG_ID_CAMIF_ERROR] = { vfe_send_camif_error_msg, + VFE_MSG_GENERAL }, + [VFE_MSG_ID_BUS_OVERFLOW] = { vfe_send_bus_overflow_msg, + VFE_MSG_GENERAL }, + [VFE_MSG_ID_SOF_ACK] = { vfe_send_sof_msg, + VFE_MSG_GENERAL }, +}; + +static void vfe_proc_ops(enum VFE_MESSAGE_ID id, void *data) +{ + struct msm_vfe_resp *rp; + struct vfe_message *msg; + + if (id >= ARRAY_SIZE(vfe_funcs) || vfe_funcs[id].fn == invalid) { + pr_err("%s: invalid VFE message id %d\n", __func__, id); + return; + } + + /* In 8k, OUTPUT1 & OUTPUT2 messages arrive before SNAPSHOT_DONE. + * We don't send such messages to the user. Note that we can do + * this in the vfe_func[] callback, but that would cause us to + * allocate and then immediately free the msm_vfe_resp structure, + * which is wasteful. + */ + if ((ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) && + (id == VFE_MSG_ID_OUTPUT_T || + id == VFE_MSG_ID_OUTPUT_S)) + return; + + rp = ctrl->resp->vfe_alloc(sizeof(*rp) + + (vfe_funcs[id].fn ? sizeof(*msg) : 0), + ctrl->syncdata, + GFP_ATOMIC); + if (!rp) { + pr_err("%s: out of memory\n", __func__); + return; + } + + rp->type = vfe_funcs[id].rt; + rp->evt_msg.type = MSM_CAMERA_MSG; + rp->evt_msg.msg_id = id; + + if (!vfe_funcs[id].fn) { + rp->evt_msg.len = 0; + rp->evt_msg.data = 0; + } else { + /* populate the message accordingly */ + if (vfe_funcs[id].fn) + rp->evt_msg.data = msg = + (struct vfe_message *)(rp + 1); + else + rp->evt_msg.data = msg = 0; + rp->evt_msg.len = sizeof(*msg); + msg->_d = id; + if (vfe_funcs[id].fn(rp, msg, data) == FALSE) { + pr_warning("%s: freeing memory: handler for %d " + "returned false\n", __func__, id); + ctrl->resp->vfe_free(rp); + return; + } +} + + ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, ctrl->syncdata, GFP_KERNEL); +} + +static boolean vfe_send_bus_overflow_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, + void *data) +{ +#if 0 + memcpy(&(msg->_u.msgBusOverflow), + &ctrl->vfePmData, sizeof(ctrl->vfePmData)); +#endif + return TRUE; +} + +static boolean vfe_send_sof_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, + void *data) +{ + return TRUE; +} +static boolean vfe_send_camif_error_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, + void *data) +{ +#if 0 + memcpy(&(msg->_u.msgCamifError), + &ctrl->vfeCamifStatusLocal, sizeof(ctrl->vfeCamifStatusLocal)); +#endif + return TRUE; +} + +static void vfe_process_error_irq(struct vfe_interrupt_status *irqstatus) +{ + /* all possible error irq. Note error irqs are not enabled, it is + * checked only when other interrupts are present. */ + if (irqstatus->afOverflowIrq) + vfe_proc_ops(VFE_MSG_ID_AF_OVERFLOW, NULL); + + if (irqstatus->awbOverflowIrq) + vfe_proc_ops(VFE_MSG_ID_AWB_OVERFLOW, NULL); + + if (irqstatus->axiErrorIrq) + vfe_proc_ops(VFE_MSG_ID_AXI_ERROR, NULL); + + if (irqstatus->busOverflowIrq) + vfe_proc_ops(VFE_MSG_ID_BUS_OVERFLOW, NULL); + + if (irqstatus->camifErrorIrq) { + CDBG("vfe_irq: camif errors\n"); + vfe_proc_ops(VFE_MSG_ID_CAMIF_ERROR, NULL); + } + + if (irqstatus->camifOverflowIrq) + vfe_proc_ops(VFE_MSG_ID_CAMIF_OVERFLOW, NULL); + + if (irqstatus->violationIrq) + pr_err("%s: violation irq\n", __func__); +} + +static void vfe_process_camif_sof_irq(void) +{ + /* increment the frame id number. */ + ctrl->vfeFrameId++; + + CDBG("camif_sof_irq, frameId = %d\n", ctrl->vfeFrameId); + + /* In snapshot mode, if frame skip is programmed, + * need to check it accordingly to stop camif at + * correct frame boundary. For the dropped frames, + * there won't be any output path irqs, but there is + * still SOF irq, which can help us determine when + * to stop the camif. + */ + if (ctrl->vfeOperationMode) { + if ((1 << ctrl->vfeFrameSkipCount)&ctrl->vfeFrameSkipPattern) { + + ctrl->vfeSnapShotCount--; + if (ctrl->vfeSnapShotCount == 0) + /* terminate vfe pipeline at frame boundary. */ + writel(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY, + ctrl->vfebase + CAMIF_COMMAND); + } + + /* update frame skip counter for bit checking. */ + ctrl->vfeFrameSkipCount++; + if (ctrl->vfeFrameSkipCount == (ctrl->vfeFrameSkipPeriod + 1)) + ctrl->vfeFrameSkipCount = 0; + } + vfe_proc_ops(VFE_MSG_ID_SOF_ACK, NULL); +} + +static boolean vfe_get_af_pingpong_status(void) +{ + uint32_t busPingPongStatus = + readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS); + return !!(busPingPongStatus & VFE_AF_PINGPONG_STATUS_BIT); +} + +static uint32_t vfe_read_af_buf_addr(boolean pipo) +{ + if (pipo == FALSE) + return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); + else + return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); +} + +static void vfe_update_af_buf_addr(boolean pipo, uint32_t addr) +{ + if (pipo == FALSE) + writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); + else + writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); +} + +static boolean vfe_send_af_stats_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data) +{ + uint32_t afBufAddress = (uint32_t)data; + + /* fill message with right content. */ + /* @todo This is causing issues, need further investigate */ + /* spin_lock_irqsave(&ctrl->state_lock, flags); */ + if (ctrl->vstate != VFE_STATE_ACTIVE) + return FALSE; + + msg->_u.msgStatsAf.afBuffer = afBufAddress; + msg->_u.msgStatsAf.frameCounter = ctrl->vfeFrameId; + + ctrl->afStatsControl.ackPending = TRUE; + + vfe_addr_convert(&(rp->phy), rp->type, msg, NULL, NULL); + /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ + return TRUE; +} + +static void vfe_process_stats_af_irq(void) +{ + boolean bufferAvailable; + + if (!(ctrl->afStatsControl.ackPending)) { + + /* read hardware status. */ + ctrl->afStatsControl.pingPongStatus = + vfe_get_af_pingpong_status(); + + bufferAvailable = (ctrl->afStatsControl.pingPongStatus) ^ 1; + + ctrl->afStatsControl.bufToRender = + vfe_read_af_buf_addr(bufferAvailable); + + /* update the same buffer address (ping or pong) */ + vfe_update_af_buf_addr(bufferAvailable, + ctrl->afStatsControl.nextFrameAddrBuf); + + vfe_proc_ops(VFE_MSG_ID_STATS_AUTOFOCUS, + (void *)ctrl->afStatsControl.bufToRender); + } else + ctrl->afStatsControl.droppedStatsFrameCount++; +} + +static boolean vfe_get_awb_pingpong_status(void) +{ + uint32_t busPingPongStatus = + + readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS); + + return !!(busPingPongStatus & VFE_AWB_PINGPONG_STATUS_BIT); + +} + +static uint32_t vfe_read_awb_buf_addr(boolean pingpong) +{ + if (pingpong == FALSE) + return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); + else + return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); +} + +static void vfe_update_awb_buf_addr(boolean pingpong, uint32_t addr) +{ + if (pingpong == FALSE) + writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); + else + writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); +} + +static boolean vfe_send_awb_stats_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data) +{ + uint32_t awbBufAddress = (uint32_t)data; + + /* fill message with right content. */ + /* @todo This is causing issues, need further investigate */ + /* spin_lock_irqsave(&ctrl->state_lock, flags); */ + if (ctrl->vstate != VFE_STATE_ACTIVE) + return FALSE; + + msg->_u.msgStatsWbExp.awbBuffer = awbBufAddress; + msg->_u.msgStatsWbExp.frameCounter = ctrl->vfeFrameId; + + + ctrl->awbStatsControl.ackPending = TRUE; + + vfe_addr_convert(&(rp->phy), + rp->type, msg, + NULL, NULL); + + return TRUE; +} + +static void vfe_process_stats_awb_irq(void) +{ + boolean bufferAvailable; + + if (!(ctrl->awbStatsControl.ackPending)) { + + ctrl->awbStatsControl.pingPongStatus = + vfe_get_awb_pingpong_status(); + + bufferAvailable = (ctrl->awbStatsControl.pingPongStatus) ^ 1; + + ctrl->awbStatsControl.bufToRender = + vfe_read_awb_buf_addr(bufferAvailable); + + vfe_update_awb_buf_addr(bufferAvailable, + ctrl->awbStatsControl.nextFrameAddrBuf); + + vfe_proc_ops(VFE_MSG_ID_STATS_WB_EXP, + (void *)ctrl->awbStatsControl.bufToRender); + + } else + ctrl->awbStatsControl.droppedStatsFrameCount++; +} + +static void vfe_write_gamma_table(uint8_t channel, + boolean bank, int16_t *pTable) +{ + uint16_t i; + + enum VFE_DMI_RAM_SEL dmiRamSel = NO_MEM_SELECTED; + + switch (channel) { + case 0: + if (bank == 0) + dmiRamSel = RGBLUT_RAM_CH0_BANK0; + else + dmiRamSel = RGBLUT_RAM_CH0_BANK1; + break; + + case 1: + if (bank == 0) + dmiRamSel = RGBLUT_RAM_CH1_BANK0; + else + dmiRamSel = RGBLUT_RAM_CH1_BANK1; + break; + + case 2: + if (bank == 0) + dmiRamSel = RGBLUT_RAM_CH2_BANK0; + else + dmiRamSel = RGBLUT_RAM_CH2_BANK1; + break; + + default: + break; + } + + vfe_program_dmi_cfg(dmiRamSel); + + for (i = 0; i < VFE_GAMMA_TABLE_LENGTH; i++) { + writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO); + pTable++; + } + + /* After DMI transfer, need to set the DMI_CFG to unselect any SRAM + unselect the SRAM Bank. */ + writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG); +} + +static void vfe_prog_hw_testgen_cmd(uint32_t value) +{ + writel(value, ctrl->vfebase + VFE_HW_TESTGEN_CMD); +} + +static inline void vfe_read_irq_status(struct vfe_irq_thread_msg *out) +{ + uint32_t *temp; + + memset(out, 0, sizeof(struct vfe_irq_thread_msg)); + + temp = (uint32_t *)(ctrl->vfebase + VFE_IRQ_STATUS); + out->vfeIrqStatus = readl(temp); + + temp = (uint32_t *)(ctrl->vfebase + CAMIF_STATUS); + out->camifStatus = readl(temp); + +/* this for YUV performance tuning + writel(0x7, ctrl->vfebase + CAMIF_COMMAND); + writel(0x3, ctrl->vfebase + CAMIF_COMMAND); + CDBG("camifStatus = 0x%x\n", out->camifStatus); +*/ +/* + temp = (uint32_t *)(ctrl->vfebase + VFE_DEMOSAIC_STATUS); + out->demosaicStatus = readl(temp); + + temp = (uint32_t *)(ctrl->vfebase + VFE_ASF_MAX_EDGE); + out->asfMaxEdge = readl(temp); + + temp = (uint32_t *)(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PM_STATS_0); +*/ + +#if 0 + out->pmInfo.encPathPmInfo.yWrPmStats0 = readl(temp++); + out->pmInfo.encPathPmInfo.yWrPmStats1 = readl(temp++); + out->pmInfo.encPathPmInfo.cbcrWrPmStats0 = readl(temp++); + out->pmInfo.encPathPmInfo.cbcrWrPmStats1 = readl(temp++); + out->pmInfo.viewPathPmInfo.yWrPmStats0 = readl(temp++); + out->pmInfo.viewPathPmInfo.yWrPmStats1 = readl(temp++); + out->pmInfo.viewPathPmInfo.cbcrWrPmStats0 = readl(temp++); + out->pmInfo.viewPathPmInfo.cbcrWrPmStats1 = readl(temp); +#endif /* if 0 Jeff */ +} + +static void +vfe_parse_interrupt_status(struct vfe_interrupt_status *ret, +uint32_t irqStatusIn) +{ + struct vfe_irqenable hwstat; + boolean temp; + + memset(&hwstat, 0, sizeof(hwstat)); + memset(ret, 0, sizeof(*ret)); + + hwstat = *((struct vfe_irqenable *)(&irqStatusIn)); + + ret->camifErrorIrq = hwstat.camifErrorIrq; + ret->camifSofIrq = hwstat.camifSofIrq; + ret->camifEolIrq = hwstat.camifEolIrq; + ret->camifEofIrq = hwstat.camifEofIrq; + ret->camifEpoch1Irq = hwstat.camifEpoch1Irq; + ret->camifEpoch2Irq = hwstat.camifEpoch2Irq; + ret->camifOverflowIrq = hwstat.camifOverflowIrq; + ret->ceIrq = hwstat.ceIrq; + ret->regUpdateIrq = hwstat.regUpdateIrq; + ret->resetAckIrq = hwstat.resetAckIrq; + ret->encYPingpongIrq = hwstat.encYPingpongIrq; + ret->encCbcrPingpongIrq = hwstat.encCbcrPingpongIrq; + ret->viewYPingpongIrq = hwstat.viewYPingpongIrq; + ret->viewCbcrPingpongIrq = hwstat.viewCbcrPingpongIrq; + ret->rdPingpongIrq = hwstat.rdPingpongIrq; + ret->afPingpongIrq = hwstat.afPingpongIrq; + ret->awbPingpongIrq = hwstat.awbPingpongIrq; + ret->histPingpongIrq = hwstat.histPingpongIrq; + ret->encIrq = hwstat.encIrq; + ret->viewIrq = hwstat.viewIrq; + ret->busOverflowIrq = hwstat.busOverflowIrq; + ret->afOverflowIrq = hwstat.afOverflowIrq; + ret->awbOverflowIrq = hwstat.awbOverflowIrq; + ret->syncTimer0Irq = hwstat.syncTimer0Irq; + ret->syncTimer1Irq = hwstat.syncTimer1Irq; + ret->syncTimer2Irq = hwstat.syncTimer2Irq; + ret->asyncTimer0Irq = hwstat.asyncTimer0Irq; + ret->asyncTimer1Irq = hwstat.asyncTimer1Irq; + ret->asyncTimer2Irq = hwstat.asyncTimer2Irq; + ret->asyncTimer3Irq = hwstat.asyncTimer3Irq; + ret->axiErrorIrq = hwstat.axiErrorIrq; + ret->violationIrq = hwstat.violationIrq; + + /* logic OR of any error bits + * although each irq corresponds to a bit, the data type here is a + * boolean already. hence use logic operation. + */ + temp = + ret->camifErrorIrq || + ret->camifOverflowIrq || + ret->afOverflowIrq || + ret->awbOverflowIrq || + ret->awbPingpongIrq || + ret->afPingpongIrq || + ret->busOverflowIrq || ret->axiErrorIrq || ret->violationIrq; + + ret->anyErrorIrqs = temp; + + /* logic OR of any output path bits*/ + temp = ret->encYPingpongIrq || ret->encCbcrPingpongIrq || ret->encIrq; + + ret->anyOutput2PathIrqs = temp; + + temp = ret->viewYPingpongIrq || ret->viewCbcrPingpongIrq || + ret->viewIrq; + + ret->anyOutput1PathIrqs = temp; + + ret->anyOutputPathIrqs = + ret->anyOutput1PathIrqs || ret->anyOutput2PathIrqs; + + /* logic OR of any sync timer bits*/ + temp = ret->syncTimer0Irq || ret->syncTimer1Irq || ret->syncTimer2Irq; + + ret->anySyncTimerIrqs = temp; + + /* logic OR of any async timer bits*/ + temp = + ret->asyncTimer0Irq || + ret->asyncTimer1Irq || ret->asyncTimer2Irq || ret->asyncTimer3Irq; + + ret->anyAsyncTimerIrqs = temp; + + /* bool for all interrupts that are not allowed in idle state */ + temp = + ret->anyErrorIrqs || + ret->anyOutputPathIrqs || + ret->anySyncTimerIrqs || + ret->regUpdateIrq || + ret->awbPingpongIrq || + ret->afPingpongIrq || + ret->camifSofIrq || ret->camifEpoch2Irq || ret->camifEpoch1Irq; + + ret->anyIrqForActiveStatesOnly = temp; +} + +static void +vfe_get_asf_frame_info(struct vfe_frame_asf_info *rc, +struct vfe_irq_thread_msg *in) +{ + struct vfe_asf_info asfInfoTemp; + + memset(rc, 0, sizeof(*rc)); + memset(&asfInfoTemp, 0, sizeof(asfInfoTemp)); + + asfInfoTemp = *((struct vfe_asf_info *)(&(in->asfMaxEdge))); + + rc->asfHbiCount = asfInfoTemp.HBICount; + rc->asfMaxEdge = asfInfoTemp.maxEdge; +} + +static void +vfe_get_demosaic_frame_info(struct vfe_frame_bpc_info *rc, +struct vfe_irq_thread_msg *in) +{ + struct vfe_bps_info bpcInfoTemp; + + memset(rc, 0, sizeof(*rc)); + memset(&bpcInfoTemp, 0, sizeof(bpcInfoTemp)); + + bpcInfoTemp = *((struct vfe_bps_info *)(&(in->demosaicStatus))); + + rc->greenDefectPixelCount = bpcInfoTemp.greenBadPixelCount; + + rc->redBlueDefectPixelCount = bpcInfoTemp.RedBlueBadPixelCount; +} + +static void +vfe_get_camif_status(struct vfe_msg_camif_status *rc, +struct vfe_irq_thread_msg *in) +{ + struct vfe_camif_stats camifStatusTemp; + + memset(rc, 0, sizeof(*rc)); + memset(&camifStatusTemp, 0, sizeof(camifStatusTemp)); + + camifStatusTemp = *((struct vfe_camif_stats *)(&(in->camifStatus))); + + rc->camifState = (boolean) camifStatusTemp.camifHalt; + rc->lineCount = camifStatusTemp.lineCount; + rc->pixelCount = camifStatusTemp.pixelCount; +} + +static void +vfe_get_performance_monitor_data(struct vfe_bus_performance_monitor *rc, + struct vfe_irq_thread_msg *in) +{ + memset(rc, 0, sizeof(*rc)); + + rc->encPathPmInfo.yWrPmStats0 = in->pmInfo.encPathPmInfo.yWrPmStats0; + rc->encPathPmInfo.yWrPmStats1 = in->pmInfo.encPathPmInfo.yWrPmStats1; + rc->encPathPmInfo.cbcrWrPmStats0 = + in->pmInfo.encPathPmInfo.cbcrWrPmStats0; + rc->encPathPmInfo.cbcrWrPmStats1 = + in->pmInfo.encPathPmInfo.cbcrWrPmStats1; + rc->viewPathPmInfo.yWrPmStats0 = in->pmInfo.viewPathPmInfo.yWrPmStats0; + rc->viewPathPmInfo.yWrPmStats1 = in->pmInfo.viewPathPmInfo.yWrPmStats1; + rc->viewPathPmInfo.cbcrWrPmStats0 = + in->pmInfo.viewPathPmInfo.cbcrWrPmStats0; + rc->viewPathPmInfo.cbcrWrPmStats1 = + in->pmInfo.viewPathPmInfo.cbcrWrPmStats1; +} + +static void vfe_process_reg_update_irq(void) +{ + CDBG("vfe_process_reg_update_irq: ackPendingFlag is %d\n", + ctrl->vfeStartAckPendingFlag); + if (ctrl->vfeStartAckPendingFlag == TRUE) { + vfe_proc_ops(VFE_MSG_ID_START_ACK, NULL); + ctrl->vfeStartAckPendingFlag = FALSE; + } else + vfe_proc_ops(VFE_MSG_ID_UPDATE_ACK, NULL); +} + +static void vfe_process_reset_irq(void) +{ + /* unsigned long flags; */ + + /* @todo This is causing issues, need further investigate */ + /* spin_lock_irqsave(&ctrl->state_lock, flags); */ + ctrl->vstate = VFE_STATE_IDLE; + /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ + + if (ctrl->vfeStopAckPending == TRUE) { + ctrl->vfeStopAckPending = FALSE; + vfe_proc_ops(VFE_MSG_ID_STOP_ACK, NULL); + } else { + vfe_set_default_reg_values(); + vfe_proc_ops(VFE_MSG_ID_RESET_ACK, NULL); + } +} + +static void vfe_process_pingpong_irq(struct vfe_output_path *in, + uint8_t fragmentCount) +{ + uint16_t circularIndex; + uint32_t nextFragmentAddr; + + /* get next fragment address from circular buffer */ + circularIndex = (in->fragIndex) % (2 * fragmentCount); + nextFragmentAddr = in->addressBuffer[circularIndex]; + + in->fragIndex = circularIndex + 1; + + /* use next fragment to program hardware ping/pong address. */ + if (in->hwCurrentFlag == ping) { + writel(nextFragmentAddr, in->hwRegPingAddress); + in->hwCurrentFlag = pong; + + } else { + writel(nextFragmentAddr, in->hwRegPongAddress); + in->hwCurrentFlag = ping; + } +} + +static boolean vfe_send_video_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data) +{ + struct vfe_msg_output *pPayload = data; + + if (ctrl->vstate != VFE_STATE_ACTIVE) + return FALSE; + memcpy(&(msg->_u), + (void *)pPayload, sizeof(struct vfe_msg_output)); + + rp->phy.output_id = OUTPUT_TYPE_V; + CDBG("vfe_send_video_msg rp->type= %d\n", rp->type); + + vfe_addr_convert(&(rp->phy), + rp->type, msg, + &(rp->extdata), &(rp->extlen)); + return TRUE; +} + +static boolean vfe_send_preview_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data) +{ + struct vfe_msg_output *pPayload = data; + + if (ctrl->vstate != VFE_STATE_ACTIVE) + return FALSE; + + memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output)); + + rp->phy.output_id = OUTPUT_TYPE_P; + CDBG("vfe_send_preview_msg rp->type= %d\n", rp->type); + + vfe_addr_convert(&(rp->phy), + rp->type, msg, + &(rp->extdata), &(rp->extlen)); + + return TRUE; +} + + +static boolean vfe_send_thumbnail_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data) +{ + struct vfe_msg_output *pPayload = data; + + if (ctrl->vstate != VFE_STATE_ACTIVE) + return FALSE; + + memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output)); + + rp->phy.output_id = OUTPUT_TYPE_T; + CDBG("vfe_send_thumbnail_msg rp->type= %d\n", rp->type); + + if (ctrl->viewPath.snapshotPendingCount <= 1) + ctrl->viewPath.ackPending = FALSE; + + vfe_addr_convert(&(rp->phy), + rp->type, msg, + &(rp->extdata), &(rp->extlen)); + return TRUE; +} + +static boolean vfe_send_mainimage_msg(struct msm_vfe_resp *rp, + struct vfe_message *msg, void *data) +{ + struct vfe_msg_output *pPayload = data; + + if (ctrl->vstate != VFE_STATE_ACTIVE) + return FALSE; + + memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output)); + + rp->phy.output_id = OUTPUT_TYPE_S; + CDBG("vfe_send_mainimage_msg rp->type= %d\n", rp->type); + + if (ctrl->encPath.snapshotPendingCount <= 1) { + ctrl->encPath.ackPending = FALSE; + } + + vfe_addr_convert(&(rp->phy), + rp->type, msg, + &(rp->extdata), &(rp->extlen)); + + return TRUE; +} + +static void vfe_send_output_msg(boolean whichOutputPath, + uint32_t yPathAddr, uint32_t cbcrPathAddr) +{ + struct vfe_msg_output msgPayload; + + msgPayload.yBuffer = yPathAddr; + msgPayload.cbcrBuffer = cbcrPathAddr; + + /* asf info is common for both output1 and output2 */ +#if 0 + msgPayload.asfInfo.asfHbiCount = ctrl->vfeAsfFrameInfo.asfHbiCount; + msgPayload.asfInfo.asfMaxEdge = ctrl->vfeAsfFrameInfo.asfMaxEdge; + + /* demosaic info is common for both output1 and output2 */ + msgPayload.bpcInfo.greenDefectPixelCount = + ctrl->vfeBpcFrameInfo.greenDefectPixelCount; + msgPayload.bpcInfo.redBlueDefectPixelCount = + ctrl->vfeBpcFrameInfo.redBlueDefectPixelCount; +#endif /* if 0 */ + + /* frame ID is common for both paths. */ + msgPayload.frameCounter = ctrl->vfeFrameId; + + if (whichOutputPath) { + /* msgPayload.pmData = ctrl->vfePmData.encPathPmInfo; */ + ctrl->encPath.ackPending = TRUE; + + if (ctrl->vfeOperationMode == 0) { + if (ctrl->axiOutputMode == + VFE_AXI_OUTPUT_MODE_Output1AndOutput2) { + /* video mode */ + vfe_proc_ops(VFE_MSG_ID_OUTPUT_V, &msgPayload); + } else{ + /* preview mode */ + vfe_proc_ops(VFE_MSG_ID_OUTPUT_P, &msgPayload); + } + } else { + vfe_proc_ops(VFE_MSG_ID_OUTPUT_S, &msgPayload); + } + + } else { + /* physical output1 path from vfe */ + ctrl->viewPath.ackPending = TRUE; + + if (ctrl->vfeOperationMode == 0) { + vfe_proc_ops(VFE_MSG_ID_OUTPUT_P, &msgPayload); + CDBG(" video mode display output.\n"); + + } else{ + vfe_proc_ops(VFE_MSG_ID_OUTPUT_T, &msgPayload); + CDBG(" snapshot mode thumbnail output.\n"); + } + } +} + +static void vfe_process_frame_done_irq_multi_frag(struct vfe_output_path_combo + *in) +{ + uint32_t yAddress, cbcrAddress; + uint16_t idx; + uint32_t *ptrY; + uint32_t *ptrCbcr; + const uint32_t *ptrSrc; + uint8_t i; + + if (!in->ackPending) { + + idx = (in->currentFrame) * (in->fragCount); + + /* Send output message. */ + yAddress = in->yPath.addressBuffer[idx]; + cbcrAddress = in->cbcrPath.addressBuffer[idx]; + + /* copy next frame to current frame. */ + ptrSrc = in->nextFrameAddrBuf; + ptrY = (uint32_t *)&in->yPath.addressBuffer[idx]; + ptrCbcr = (uint32_t *)&in->cbcrPath.addressBuffer[idx]; + + /* Copy Y address */ + for (i = 0; i < in->fragCount; i++) + *ptrY++ = *ptrSrc++; + + /* Copy Cbcr address */ + for (i = 0; i < in->fragCount; i++) + *ptrCbcr++ = *ptrSrc++; + + vfe_send_output_msg(in->whichOutputPath, yAddress, cbcrAddress); + + } else { + if (in->whichOutputPath == 0) + ctrl->vfeDroppedFrameCounts.output1Count++; + + if (in->whichOutputPath == 1) + ctrl->vfeDroppedFrameCounts.output2Count++; + } + + /* toggle current frame. */ + in->currentFrame = in->currentFrame^1; + + if (ctrl->vfeOperationMode) + in->snapshotPendingCount--; +} + +static void vfe_process_frame_done_irq_no_frag_io( + struct vfe_output_path_combo *in, + uint32_t *pNextAddr, + uint32_t *pdestRenderAddr) +{ + uint32_t busPingPongStatus; + uint32_t tempAddress; + + /* 1. read hw status register. */ + busPingPongStatus = readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS); + + CDBG("hardware status is 0x%x\n", busPingPongStatus); + + /* 2. determine ping or pong */ + /* use cbcr status */ + busPingPongStatus = busPingPongStatus & (1<<(in->cbcrStatusBit)); + + /* 3. read out address and update address */ + if (busPingPongStatus == 0) { + /* hw is working on ping, render pong buffer */ + /* a. read out pong address */ + /* read out y address. */ + tempAddress = readl(in->yPath.hwRegPongAddress); + + CDBG("pong 1 addr = 0x%x\n", tempAddress); + *pdestRenderAddr++ = tempAddress; + /* read out cbcr address. */ + tempAddress = readl(in->cbcrPath.hwRegPongAddress); + + CDBG("pong 2 addr = 0x%x\n", tempAddress); + *pdestRenderAddr = tempAddress; + + /* b. update pong address */ + writel(*pNextAddr++, in->yPath.hwRegPongAddress); + writel(*pNextAddr, in->cbcrPath.hwRegPongAddress); + } else { + /* hw is working on pong, render ping buffer */ + + /* a. read out ping address */ + tempAddress = readl(in->yPath.hwRegPingAddress); + CDBG("ping 1 addr = 0x%x\n", tempAddress); + *pdestRenderAddr++ = tempAddress; + tempAddress = readl(in->cbcrPath.hwRegPingAddress); + + CDBG("ping 2 addr = 0x%x\n", tempAddress); + *pdestRenderAddr = tempAddress; + + /* b. update ping address */ + writel(*pNextAddr++, in->yPath.hwRegPingAddress); + CDBG("NextAddress = 0x%x\n", *pNextAddr); + writel(*pNextAddr, in->cbcrPath.hwRegPingAddress); + } +} + +static void vfe_process_frame_done_irq_no_frag(struct vfe_output_path_combo *in) +{ + uint32_t addressToRender[2]; + + if (!in->ackPending) { + vfe_process_frame_done_irq_no_frag_io(in, + in->nextFrameAddrBuf, + addressToRender); + + /* use addressToRender to send out message. */ + vfe_send_output_msg(in->whichOutputPath, + addressToRender[0], addressToRender[1]); + + } else { + /* ackPending is still there, accumulate dropped frame count. + * These count can be read through ioctrl command. */ + CDBG("waiting frame ACK\n"); + + if (in->whichOutputPath == 0) + ctrl->vfeDroppedFrameCounts.output1Count++; + + if (in->whichOutputPath == 1) + ctrl->vfeDroppedFrameCounts.output2Count++; + } + + /* in case of multishot when upper layer did not ack, there will still + * be a snapshot done msg sent out, even though the number of frames + * sent out may be less than the desired number of frames. snapshot + * done msg would be helpful to indicate that vfe pipeline has stop, + * and in good known state. + */ + if (ctrl->vfeOperationMode) + in->snapshotPendingCount--; +} + +static void vfe_process_output_path_irq(struct vfe_interrupt_status *irqstatus) +{ + /* unsigned long flags; */ + + /* process the view path interrupts */ + if (irqstatus->anyOutput1PathIrqs) { + if (ctrl->viewPath.multiFrag) { + + if (irqstatus->viewCbcrPingpongIrq) + vfe_process_pingpong_irq(& + (ctrl->viewPath. + cbcrPath), + ctrl->viewPath. + fragCount); + + if (irqstatus->viewYPingpongIrq) + vfe_process_pingpong_irq(& + (ctrl->viewPath.yPath), + ctrl->viewPath. + fragCount); + + if (irqstatus->viewIrq) + vfe_process_frame_done_irq_multi_frag(&ctrl-> + viewPath); + + } else { + /* typical case for no fragment, + only frame done irq is enabled. */ + if (irqstatus->viewIrq) + vfe_process_frame_done_irq_no_frag(&ctrl-> + viewPath); + } + } + + /* process the encoder path interrupts */ + if (irqstatus->anyOutput2PathIrqs) { + if (ctrl->encPath.multiFrag) { + if (irqstatus->encCbcrPingpongIrq) + vfe_process_pingpong_irq(& + (ctrl->encPath. + cbcrPath), + ctrl->encPath. + fragCount); + + if (irqstatus->encYPingpongIrq) + vfe_process_pingpong_irq(&(ctrl->encPath.yPath), + ctrl->encPath. + fragCount); + + if (irqstatus->encIrq) + vfe_process_frame_done_irq_multi_frag(&ctrl-> + encPath); + + } else { + if (irqstatus->encIrq) + vfe_process_frame_done_irq_no_frag(&ctrl-> + encPath); + } + } + + if (ctrl->vfeOperationMode) { + if ((ctrl->encPath.snapshotPendingCount == 0) && + (ctrl->viewPath.snapshotPendingCount == 0)) { + + /* @todo This is causing issues, further investigate */ + /* spin_lock_irqsave(&ctrl->state_lock, flags); */ + ctrl->vstate = VFE_STATE_IDLE; + /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ + + vfe_proc_ops(VFE_MSG_ID_SNAPSHOT_DONE, NULL); + vfe_camif_stop_immediately(); + vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP); + vfe_pm_stop(); + } + } +} + +static void __vfe_do_tasklet(struct isr_queue_cmd *qcmd) +{ + if (qcmd->vfeInterruptStatus.regUpdateIrq) { + CDBG("irq regUpdateIrq\n"); + vfe_process_reg_update_irq(); + } + + if (qcmd->vfeInterruptStatus.resetAckIrq) { + CDBG("%s: process resetAckIrq\n", __func__); + vfe_process_reset_irq(); + } + + if (ctrl->vstate != VFE_STATE_ACTIVE) + return; + +#if 0 + if (qcmd->vfeInterruptStatus.camifEpoch1Irq) + vfe_proc_ops(VFE_MSG_ID_EPOCH1); + + if (qcmd->vfeInterruptStatus.camifEpoch2Irq) + vfe_proc_ops(VFE_MSG_ID_EPOCH2); +#endif /* Jeff */ + + /* next, check output path related interrupts. */ + if (qcmd->vfeInterruptStatus.anyOutputPathIrqs) { + CDBG("irq: anyOutputPathIrqs\n"); + vfe_process_output_path_irq(&qcmd->vfeInterruptStatus); + } + + if (qcmd->vfeInterruptStatus.afPingpongIrq) + vfe_process_stats_af_irq(); + + if (qcmd->vfeInterruptStatus.awbPingpongIrq) + vfe_process_stats_awb_irq(); + + /* any error irqs*/ + if (qcmd->vfeInterruptStatus.anyErrorIrqs) + vfe_process_error_irq(&qcmd->vfeInterruptStatus); + +#if 0 + if (qcmd->vfeInterruptStatus.anySyncTimerIrqs) + vfe_process_sync_timer_irq(); + + if (qcmd->vfeInterruptStatus.anyAsyncTimerIrqs) + vfe_process_async_timer_irq(); +#endif /* Jeff */ + + if (qcmd->vfeInterruptStatus.camifSofIrq) { + CDBG("irq: camifSofIrq\n"); + vfe_process_camif_sof_irq(); + } +} + +static struct isr_queue_cmd *get_irq_cmd_nosync(void) +{ + int old_get = ctrl->irq_get++; + ctrl->irq_get = ctrl->irq_get % ARRAY_SIZE(ctrl->irqs); + if (ctrl->irq_get == ctrl->irq_put) { + pr_err("%s: out of irq command packets\n", __func__); + ctrl->irq_get = old_get; + return NULL; + } + + return ctrl->irqs + old_get; +} + +static struct isr_queue_cmd *next_irq_cmd(void) +{ + unsigned long flags; + struct isr_queue_cmd *cmd; + spin_lock_irqsave(&ctrl->irqs_lock, flags); + if (ctrl->irq_get == ctrl->irq_put) { + spin_unlock_irqrestore(&ctrl->irqs_lock, flags); + return NULL; /* already empty */ + } + cmd = ctrl->irqs + ctrl->irq_put; + spin_unlock_irqrestore(&ctrl->irqs_lock, flags); + return cmd; +} + +static void put_irq_cmd(void) +{ + unsigned long flags; + spin_lock_irqsave(&ctrl->irqs_lock, flags); + if (ctrl->irq_get == ctrl->irq_put) { + spin_unlock_irqrestore(&ctrl->irqs_lock, flags); + return; /* already empty */ + } + ctrl->irq_put++; + ctrl->irq_put %= ARRAY_SIZE(ctrl->irqs); + spin_unlock_irqrestore(&ctrl->irqs_lock, flags); +} + +static void vfe_do_tasklet(unsigned long data) +{ + int cnt = 0; + unsigned long flags; + struct isr_queue_cmd *qcmd = NULL; + + spin_lock_irqsave(&msm_vfe_ctrl_lock, flags); + if (!ctrl) { + spin_unlock_irqrestore(&msm_vfe_ctrl_lock, flags); + return; + } + + CDBG("%s\n", __func__); + + while ((qcmd = next_irq_cmd())) { + __vfe_do_tasklet(qcmd); + put_irq_cmd(); + cnt++; + } + + if (cnt > ARRAY_SIZE(ctrl->irqs)/2) + CDBG("%s: serviced %d vfe interrupts\n", __func__, cnt); + + spin_unlock_irqrestore(&msm_vfe_ctrl_lock, flags); +} + +DECLARE_TASKLET(vfe_tasklet, vfe_do_tasklet, 0); + +static irqreturn_t vfe_parse_irq(int irq_num, void *data) +{ + unsigned long flags; + uint32_t irqStatusLocal; + struct vfe_irq_thread_msg irq; + struct isr_queue_cmd *qcmd; + + CDBG("vfe_parse_irq\n"); + + if (!atomic_read(&ctrl->vfe_serv_interrupt)) + return IRQ_HANDLED; + + vfe_read_irq_status(&irq); + + if (irq.vfeIrqStatus == 0) { + CDBG("vfe_parse_irq: irq.vfeIrqStatus is 0\n"); + return IRQ_HANDLED; + } + + if (ctrl->vfeStopAckPending) + irqStatusLocal = (VFE_IMASK_WHILE_STOPPING & irq.vfeIrqStatus); + else + irqStatusLocal = + ((ctrl->vfeImaskPacked | VFE_IMASK_ERROR_ONLY) & + irq.vfeIrqStatus); + + spin_lock_irqsave(&ctrl->irqs_lock, flags); + qcmd = get_irq_cmd_nosync(); + if (!qcmd) { + spin_unlock_irqrestore(&ctrl->irqs_lock, flags); + goto done; + } + /* first parse the interrupt status to local data structures. */ + vfe_parse_interrupt_status(&qcmd->vfeInterruptStatus, irqStatusLocal); + vfe_get_asf_frame_info(&qcmd->vfeAsfFrameInfo, &irq); + vfe_get_demosaic_frame_info(&qcmd->vfeBpcFrameInfo, &irq); + vfe_get_camif_status(&qcmd->vfeCamifStatusLocal, &irq); + vfe_get_performance_monitor_data(&qcmd->vfePmData, &irq); + spin_unlock_irqrestore(&ctrl->irqs_lock, flags); + tasklet_schedule(&vfe_tasklet); + +done: + /* clear the pending interrupt of the same kind.*/ + writel(irq.vfeIrqStatus, ctrl->vfebase + VFE_IRQ_CLEAR); + + return IRQ_HANDLED; +} + +int vfe_cmd_init(struct msm_vfe_callback *presp, + struct platform_device *pdev, void *sdata) +{ + struct resource *vfemem, *vfeirq, *vfeio; + int rc; + struct msm_camera_sensor_info *s_info; + s_info = pdev->dev.platform_data; + + pdev->resource = s_info->resource; + pdev->num_resources = s_info->num_resources; + + vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!vfemem) { + pr_err("%s: no mem resource\n", __func__); + return -ENODEV; + } + + vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!vfeirq) { + pr_err("%s: no irq resource\n", __func__); + return -ENODEV; + } + + vfeio = request_mem_region(vfemem->start, + resource_size(vfemem), pdev->name); + if (!vfeio) { + pr_err("%s: VFE region already claimed\n", __func__); + return -EBUSY; + } + + ctrl = kzalloc(sizeof(struct msm_vfe8x_ctrl), GFP_KERNEL); + if (!ctrl) { + pr_err("%s: out of memory\n", __func__); + rc = -ENOMEM; + goto cmd_init_failed1; + } + atomic_set(&ctrl->vfe_serv_interrupt, 0); + ctrl->vfeirq = vfeirq->start; + + ctrl->vfebase = + ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1); + if (!ctrl->vfebase) { + pr_err("%s: ioremap failed\n", __func__); + rc = -ENOMEM; + goto cmd_init_failed2; + } + + rc = request_irq(ctrl->vfeirq, vfe_parse_irq, + IRQF_TRIGGER_RISING, "vfe", 0); + if (rc < 0) { + pr_err("%s: request_irq(%d) failed\n", __func__, ctrl->vfeirq); + goto cmd_init_failed2; + } + + if (presp && presp->vfe_resp) + ctrl->resp = presp; + else { + pr_err("%s: no vfe_resp function\n", __func__); + + rc = -EIO; + goto cmd_init_failed3; + } + + ctrl->syncdata = sdata; + return 0; + +cmd_init_failed3: + disable_irq(ctrl->vfeirq); + free_irq(ctrl->vfeirq, 0); + iounmap(ctrl->vfebase); +cmd_init_failed2: + kfree(ctrl); +cmd_init_failed1: + release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1); + return rc; +} + +void vfe_cmd_release(struct platform_device *dev) +{ + struct resource *mem; + unsigned long flags; + atomic_set(&ctrl->vfe_serv_interrupt, 0); + disable_irq(ctrl->vfeirq); + free_irq(ctrl->vfeirq, 0); + + iounmap(ctrl->vfebase); + mem = platform_get_resource(dev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, (mem->end - mem->start) + 1); + + spin_lock_irqsave(&msm_vfe_ctrl_lock, flags); + kfree(ctrl); + ctrl = 0; + spin_unlock_irqrestore(&msm_vfe_ctrl_lock, flags); +} + +void vfe_stats_af_stop(void) +{ + ctrl->vfeStatsCmdLocal.autoFocusEnable = FALSE; + ctrl->vfeImaskLocal.afPingpongIrq = FALSE; +} + +void vfe_stop(void) +{ + int spin_cnt = 0; + uint32_t vfeAxiStauts; + + /* for reset hw modules, and send msg when reset_irq comes.*/ + ctrl->vfeStopAckPending = TRUE; + + ctrl->vfeStatsPingPongReloadFlag = FALSE; + vfe_pm_stop(); + + /* disable all interrupts. */ + vfe_program_irq_mask(VFE_DISABLE_ALL_IRQS); + + /* in either continuous or snapshot mode, stop command can be issued + * at any time. + */ + vfe_camif_stop_immediately(); + vfe_program_axi_cmd(AXI_HALT); + vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP); + + do { + vfeAxiStauts = vfe_read_axi_status(); + spin_cnt++; + } while (!(vfeAxiStauts & AXI_STATUS_BUSY_MASK)); + if (spin_cnt > 1) + pr_warning("%s: spin_cnt %d\n", __func__, spin_cnt); + + vfe_program_axi_cmd(AXI_HALT_CLEAR); + + /* clear all pending interrupts */ + writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR); + + /* enable reset_ack and async timer interrupt only while stopping + * the pipeline. + */ + vfe_program_irq_mask(VFE_IMASK_WHILE_STOPPING); + + vfe_program_global_reset_cmd(VFE_RESET_UPON_STOP_CMD); +} + +void vfe_update(void) +{ + ctrl->vfeModuleEnableLocal.statsEnable = + ctrl->vfeStatsCmdLocal.autoFocusEnable | + ctrl->vfeStatsCmdLocal.axwEnable; + + vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal); + + vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal); + + ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal); + vfe_program_irq_mask(ctrl->vfeImaskPacked); + + if ((ctrl->vfeModuleEnableLocal.statsEnable == TRUE) && + (ctrl->vfeStatsPingPongReloadFlag == FALSE)) { + ctrl->vfeStatsPingPongReloadFlag = TRUE; + + ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE; + vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal); + } + + vfe_program_reg_update_cmd(VFE_REG_UPDATE_TRIGGER); +} + +int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *in) +{ + int rc = 0; + + ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable; + + switch (in->channelSelect) { + case RGB_GAMMA_CH0_SELECTED: + ctrl->vfeGammaLutSel.ch0BankSelect ^= 1; + vfe_write_gamma_table(0, + ctrl->vfeGammaLutSel.ch0BankSelect, + in->table); + break; + + case RGB_GAMMA_CH1_SELECTED: + ctrl->vfeGammaLutSel.ch1BankSelect ^= 1; + vfe_write_gamma_table(1, + ctrl->vfeGammaLutSel.ch1BankSelect, + in->table); + break; + + case RGB_GAMMA_CH2_SELECTED: + ctrl->vfeGammaLutSel.ch2BankSelect ^= 1; + vfe_write_gamma_table(2, + ctrl->vfeGammaLutSel.ch2BankSelect, + in->table); + break; + + case RGB_GAMMA_CH0_CH1_SELECTED: + ctrl->vfeGammaLutSel.ch0BankSelect ^= 1; + ctrl->vfeGammaLutSel.ch1BankSelect ^= 1; + vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect, + in->table); + vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect, + in->table); + break; + + case RGB_GAMMA_CH0_CH2_SELECTED: + ctrl->vfeGammaLutSel.ch0BankSelect ^= 1; + ctrl->vfeGammaLutSel.ch2BankSelect ^= 1; + vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect, + in->table); + vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect, + in->table); + break; + + case RGB_GAMMA_CH1_CH2_SELECTED: + ctrl->vfeGammaLutSel.ch1BankSelect ^= 1; + ctrl->vfeGammaLutSel.ch2BankSelect ^= 1; + vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect, + in->table); + vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect, + in->table); + break; + + case RGB_GAMMA_CH0_CH1_CH2_SELECTED: + ctrl->vfeGammaLutSel.ch0BankSelect ^= 1; + ctrl->vfeGammaLutSel.ch1BankSelect ^= 1; + ctrl->vfeGammaLutSel.ch2BankSelect ^= 1; + vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect, + in->table); + vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect, + in->table); + vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect, + in->table); + break; + + default: + pr_err("%s: invalid gamma channel %d\n", __func__, + in->channelSelect); + return -EINVAL; + } /* switch */ + + /* update the gammaLutSel register. */ + vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel); + + return rc; +} + +int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *in) +{ + int rc = 0; + + ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable; + + switch (in->channelSelect) { + case RGB_GAMMA_CH0_SELECTED: +vfe_write_gamma_table(0, 0, in->table); +break; + + case RGB_GAMMA_CH1_SELECTED: + vfe_write_gamma_table(1, 0, in->table); + break; + + case RGB_GAMMA_CH2_SELECTED: + vfe_write_gamma_table(2, 0, in->table); + break; + + case RGB_GAMMA_CH0_CH1_SELECTED: + vfe_write_gamma_table(0, 0, in->table); + vfe_write_gamma_table(1, 0, in->table); + break; + + case RGB_GAMMA_CH0_CH2_SELECTED: + vfe_write_gamma_table(0, 0, in->table); + vfe_write_gamma_table(2, 0, in->table); + break; + + case RGB_GAMMA_CH1_CH2_SELECTED: + vfe_write_gamma_table(1, 0, in->table); + vfe_write_gamma_table(2, 0, in->table); + break; + + case RGB_GAMMA_CH0_CH1_CH2_SELECTED: + vfe_write_gamma_table(0, 0, in->table); + vfe_write_gamma_table(1, 0, in->table); + vfe_write_gamma_table(2, 0, in->table); + break; + + default: + pr_err("%s: invalid gamma channel %d\n", __func__, + in->channelSelect); + rc = -EINVAL; + break; + } /* switch */ + + return rc; +} + +void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *in) +{ + ctrl->afStatsControl.nextFrameAddrBuf = in->nextAFOutputBufferAddr; + ctrl->afStatsControl.ackPending = FALSE; +} + +void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *in) +{ + ctrl->awbStatsControl.nextFrameAddrBuf = in->nextWbExpOutputBufferAddr; + ctrl->awbStatsControl.ackPending = FALSE; +} + + +void vfe_output_v_ack(struct vfe_cmd_output_ack *in) +{ + const uint32_t *psrc; + uint32_t *pdest; + uint8_t i; + + pdest = ctrl->encPath.nextFrameAddrBuf; + + CDBG("video_frame_ack: ack addr = 0x%x\n", in->ybufaddr[0]); + + psrc = in->ybufaddr; + for (i = 0; i < ctrl->encPath.fragCount; i++) + *pdest++ = *psrc++; + + psrc = in->chromabufaddr; + for (i = 0; i < ctrl->encPath.fragCount; i++) + *pdest++ = *psrc++; + + ctrl->encPath.ackPending = FALSE; +} + +void vfe_output_p_ack(struct vfe_cmd_output_ack *in) +{ + const uint32_t *psrc; + uint32_t *pdest; + uint8_t i; + + if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_Output1AndOutput2) { + /* video mode, preview comes from output1 path */ + + pdest = ctrl->viewPath.nextFrameAddrBuf; + + psrc = in->ybufaddr; + for (i = 0; i < ctrl->viewPath.fragCount; i++) + *pdest++ = *psrc++; + + psrc = in->chromabufaddr; + for (i = 0; i < ctrl->viewPath.fragCount; i++) + *pdest++ = *psrc++; + + ctrl->viewPath.ackPending = FALSE; + + } else { /* preview mode, preview comes from output2 path. */ + pdest = ctrl->encPath.nextFrameAddrBuf; + + psrc = in->ybufaddr; + for (i = 0; i < ctrl->encPath.fragCount; i++) + *pdest++ = *psrc++; + + psrc = in->chromabufaddr; + for (i = 0; i < ctrl->encPath.fragCount; i++) + *pdest++ = *psrc++; + + ctrl->encPath.ackPending = FALSE; + + } +} + +void vfe_start(struct vfe_cmd_start *in) +{ + uint32_t pmstatus = 0; + boolean rawmode; + uint32_t demperiod = 0; + uint32_t demeven = 0; + uint32_t demodd = 0; + + /* derived from other commands. (camif config, axi output config, + * etc) + */ + struct vfe_cfg hwcfg; + struct vfe_upsample_cfg chromupcfg; + + CDBG("vfe_start operationMode = %d\n", in->operationMode); + + memset(&hwcfg, 0, sizeof(hwcfg)); + memset(&chromupcfg, 0, sizeof(chromupcfg)); + + switch (in->pixel) { + case VFE_BAYER_RGRGRG: + demperiod = 1; + demeven = 0xC9; + demodd = 0xAC; + break; + + case VFE_BAYER_GRGRGR: + demperiod = 1; + demeven = 0x9C; + demodd = 0xCA; + break; + + case VFE_BAYER_BGBGBG: + demperiod = 1; + demeven = 0xCA; + demodd = 0x9C; + break; + + case VFE_BAYER_GBGBGB: + demperiod = 1; + demeven = 0xAC; + demodd = 0xC9; + break; + + case VFE_YUV_YCbYCr: + demperiod = 3; + demeven = 0x9CAC; + demodd = 0x9CAC; + break; + + case VFE_YUV_YCrYCb: + demperiod = 3; + demeven = 0xAC9C; + demodd = 0xAC9C; + break; + + case VFE_YUV_CbYCrY: + demperiod = 3; + demeven = 0xC9CA; + demodd = 0xC9CA; + break; + + case VFE_YUV_CrYCbY: + demperiod = 3; + demeven = 0xCAC9; + demodd = 0xCAC9; + break; + + default: + return; + } + + vfe_config_demux(demperiod, demeven, demodd); + + vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel); + + /* save variables to local. */ + ctrl->vfeOperationMode = in->operationMode; + if (ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) { + + update_axi_qos(MSM_AXI_QOS_SNAPSHOT); + /* in snapshot mode, initialize snapshot count*/ + ctrl->vfeSnapShotCount = in->snapshotCount; + + /* save the requested count, this is temporarily done, to + help with HJR / multishot. */ + ctrl->vfeRequestedSnapShotCount = ctrl->vfeSnapShotCount; + + CDBG("requested snapshot count = %d\n", ctrl->vfeSnapShotCount); + + /* Assumption is to have the same pattern and period for both + paths, if both paths are used. */ + if (ctrl->viewPath.pathEnabled) { + ctrl->viewPath.snapshotPendingCount = in->snapshotCount; + + ctrl->vfeFrameSkipPattern = + ctrl->vfeFrameSkip.output1Pattern; + ctrl->vfeFrameSkipPeriod = + ctrl->vfeFrameSkip.output1Period; + } + + if (ctrl->encPath.pathEnabled) { + ctrl->encPath.snapshotPendingCount = in->snapshotCount; + + ctrl->vfeFrameSkipPattern = + ctrl->vfeFrameSkip.output2Pattern; + ctrl->vfeFrameSkipPeriod = + ctrl->vfeFrameSkip.output2Period; + } + } else + update_axi_qos(MSM_AXI_QOS_PREVIEW); + + /* enable color conversion for bayer sensor + if stats enabled, need to do color conversion. */ + if (in->pixel <= VFE_BAYER_GBGBGB) + ctrl->vfeStatsCmdLocal.colorConversionEnable = TRUE; + + vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal); + + if (in->pixel >= VFE_YUV_YCbYCr) + ctrl->vfeModuleEnableLocal.chromaUpsampleEnable = TRUE; + + ctrl->vfeModuleEnableLocal.demuxEnable = TRUE; + + /* if any stats module is enabled, the main bit is enabled. */ + ctrl->vfeModuleEnableLocal.statsEnable = + ctrl->vfeStatsCmdLocal.autoFocusEnable | + ctrl->vfeStatsCmdLocal.axwEnable; + + vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal); + + /* in case of offline processing, do not need to config camif. Having + * bus output enabled in camif_config register might confuse the + * hardware? + */ + if (in->inputSource != VFE_START_INPUT_SOURCE_AXI) { + vfe_reg_camif_config(&ctrl->vfeCamifConfigLocal); + } else { + /* offline processing, enable axi read */ + ctrl->vfeBusConfigLocal.stripeRdPathEn = TRUE; + ctrl->vfeBusCmdLocal.stripeReload = TRUE; + ctrl->vfeBusConfigLocal.rawPixelDataSize = + ctrl->axiInputDataSize; + } + + vfe_reg_bus_cfg(&ctrl->vfeBusConfigLocal); + + /* directly from start command */ + hwcfg.pixelPattern = in->pixel; + hwcfg.inputSource = in->inputSource; + writel(*(uint32_t *)&hwcfg, ctrl->vfebase + VFE_CFG); + + /* regardless module enabled or not, it does not hurt + * to program the cositing mode. */ + chromupcfg.chromaCositingForYCbCrInputs = in->yuvInputCositingMode; + + writel(*(uint32_t *)&chromupcfg, + ctrl->vfebase + VFE_CHROMA_UPSAMPLE_CFG); + + /* MISR to monitor the axi read. */ + writel(0xd8, ctrl->vfebase + VFE_BUS_MISR_MAST_CFG_0); + + /* clear all pending interrupts. */ + writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR); + + /* define how composite interrupt work. */ + ctrl->vfeImaskCompositePacked = + vfe_irq_composite_pack(ctrl->vfeIrqCompositeMaskLocal); + + vfe_program_irq_composite_mask(ctrl->vfeImaskCompositePacked); + + /* enable all necessary interrupts. */ + ctrl->vfeImaskLocal.camifSofIrq = TRUE; + ctrl->vfeImaskLocal.regUpdateIrq = TRUE; + ctrl->vfeImaskLocal.resetAckIrq = TRUE; + + ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal); + vfe_program_irq_mask(ctrl->vfeImaskPacked); + + /* enable bus performance monitor */ + vfe_8k_pm_start(&ctrl->vfeBusPmConfigLocal); + + /* trigger vfe reg update */ + ctrl->vfeStartAckPendingFlag = TRUE; + + /* write bus command to trigger reload of ping pong buffer. */ + ctrl->vfeBusCmdLocal.busPingpongReload = TRUE; + + if (ctrl->vfeModuleEnableLocal.statsEnable == TRUE) { + ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE; + ctrl->vfeStatsPingPongReloadFlag = TRUE; + } + + writel(VFE_REG_UPDATE_TRIGGER, ctrl->vfebase + VFE_REG_UPDATE_CMD); + + /* program later than the reg update. */ + vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal); + + if ((in->inputSource == + VFE_START_INPUT_SOURCE_CAMIF) || + (in->inputSource == VFE_START_INPUT_SOURCE_TESTGEN)) + writel(CAMIF_COMMAND_START, ctrl->vfebase + CAMIF_COMMAND); + + /* start test gen if it is enabled */ + if (ctrl->vfeTestGenStartFlag == TRUE) { + ctrl->vfeTestGenStartFlag = FALSE; + vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_GO); + } + + CDBG("ctrl->axiOutputMode = %d\n", ctrl->axiOutputMode); + if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2) { + /* raw dump mode */ + rawmode = TRUE; + + while (rawmode) { + pmstatus = + readl(ctrl->vfebase + + VFE_BUS_ENC_CBCR_WR_PM_STATS_1); + + if ((pmstatus & VFE_PM_BUF_MAX_CNT_MASK) != 0) + rawmode = FALSE; + } + + vfe_proc_ops(VFE_MSG_ID_START_ACK, NULL); + ctrl->vfeStartAckPendingFlag = FALSE; + } + + ctrl->vstate = VFE_STATE_ACTIVE; +} + +void vfe_la_update(struct vfe_cmd_la_config *in) +{ + int16_t *pTable; + enum VFE_DMI_RAM_SEL dmiRamSel; + int i; + + pTable = in->table; + ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable; + + /* toggle the bank to be used. */ + ctrl->vfeLaBankSel ^= 1; + + if (ctrl->vfeLaBankSel == 0) + dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0; + else + dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1; + + /* configure the DMI_CFG to select right sram */ + vfe_program_dmi_cfg(dmiRamSel); + + for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) { + writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO); + pTable++; + } + + /* After DMI transfer, to make it safe, need to set + * the DMI_CFG to unselect any SRAM */ + writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG); + writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG); +} + +void vfe_la_config(struct vfe_cmd_la_config *in) +{ + uint16_t i; + int16_t *pTable; + enum VFE_DMI_RAM_SEL dmiRamSel; + + pTable = in->table; + ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable; + + if (ctrl->vfeLaBankSel == 0) + dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0; + else + dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1; + + /* configure the DMI_CFG to select right sram */ + vfe_program_dmi_cfg(dmiRamSel); + + for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) { + writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO); + pTable++; + } + + /* After DMI transfer, to make it safe, need to set the + * DMI_CFG to unselect any SRAM */ + writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG); + + /* can only be bank 0 or bank 1 for now. */ + writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG); + CDBG("VFE Luma adaptation bank selection is 0x%x\n", + *(uint32_t *)&ctrl->vfeLaBankSel); +} + +void vfe_test_gen_start(struct vfe_cmd_test_gen_start *in) +{ + struct VFE_TestGen_ConfigCmdType cmd; + + memset(&cmd, 0, sizeof(cmd)); + + cmd.numFrame = in->numFrame; + cmd.pixelDataSelect = in->pixelDataSelect; + cmd.systematicDataSelect = in->systematicDataSelect; + cmd.pixelDataSize = (uint32_t)in->pixelDataSize; + cmd.hsyncEdge = (uint32_t)in->hsyncEdge; + cmd.vsyncEdge = (uint32_t)in->vsyncEdge; + cmd.imageWidth = in->imageWidth; + cmd.imageHeight = in->imageHeight; + cmd.sofOffset = in->startOfFrameOffset; + cmd.eofNOffset = in->endOfFrameNOffset; + cmd.solOffset = in->startOfLineOffset; + cmd.eolNOffset = in->endOfLineNOffset; + cmd.hBlankInterval = in->hbi; + cmd.vBlankInterval = in->vbl; + cmd.vBlankIntervalEnable = in->vblEnable; + cmd.sofDummy = in->startOfFrameDummyLine; + cmd.eofDummy = in->endOfFrameDummyLine; + cmd.unicolorBarSelect = in->unicolorBarSelect; + cmd.unicolorBarEnable = in->unicolorBarEnable; + cmd.splitEnable = in->colorBarsSplitEnable; + cmd.pixelPattern = (uint32_t)in->colorBarsPixelPattern; + cmd.rotatePeriod = in->colorBarsRotatePeriod; + cmd.randomSeed = in->testGenRandomSeed; + + vfe_prog_hw(ctrl->vfebase + VFE_HW_TESTGEN_CFG, + (uint32_t *) &cmd, sizeof(cmd)); +} + +void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *in) +{ + struct VFE_FRAME_SKIP_UpdateCmdType cmd; + + cmd.yPattern = in->output1Pattern; + cmd.cbcrPattern = in->output1Pattern; + vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN, + (uint32_t *)&cmd, sizeof(cmd)); + + cmd.yPattern = in->output2Pattern; + cmd.cbcrPattern = in->output2Pattern; + vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *in) +{ + struct vfe_frame_skip_cfg cmd; + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeFrameSkip = *in; + + cmd.output2YPeriod = in->output2Period; + cmd.output2CbCrPeriod = in->output2Period; + cmd.output2YPattern = in->output2Pattern; + cmd.output2CbCrPattern = in->output2Pattern; + cmd.output1YPeriod = in->output1Period; + cmd.output1CbCrPeriod = in->output1Period; + cmd.output1YPattern = in->output1Pattern; + cmd.output1CbCrPattern = in->output1Pattern; + + vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *in) +{ + struct vfe_output_clamp_cfg cmd; + memset(&cmd, 0, sizeof(cmd)); + + cmd.yChanMax = in->maxCh0; + cmd.cbChanMax = in->maxCh1; + cmd.crChanMax = in->maxCh2; + + cmd.yChanMin = in->minCh0; + cmd.cbChanMin = in->minCh1; + cmd.crChanMin = in->minCh2; + + vfe_prog_hw(ctrl->vfebase + VFE_CLAMP_MAX_CFG, (uint32_t *)&cmd, + sizeof(cmd)); +} + +void vfe_camif_frame_update(struct vfe_cmds_camif_frame *in) +{ + struct vfe_camifframe_update cmd; + + memset(&cmd, 0, sizeof(cmd)); + + cmd.pixelsPerLine = in->pixelsPerLine; + cmd.linesPerFrame = in->linesPerFrame; + + vfe_prog_hw(ctrl->vfebase + CAMIF_FRAME_CONFIG, (uint32_t *)&cmd, + sizeof(cmd)); +} + +void vfe_color_correction_config(struct vfe_cmd_color_correction_config *in) +{ + struct vfe_color_correction_cfg cmd; + + memset(&cmd, 0, sizeof(cmd)); + ctrl->vfeModuleEnableLocal.colorCorrectionEnable = in->enable; + + cmd.c0 = in->C0; + cmd.c1 = in->C1; + cmd.c2 = in->C2; + cmd.c3 = in->C3; + cmd.c4 = in->C4; + cmd.c5 = in->C5; + cmd.c6 = in->C6; + cmd.c7 = in->C7; + cmd.c8 = in->C8; + + cmd.k0 = in->K0; + cmd.k1 = in->K1; + cmd.k2 = in->K2; + + cmd.coefQFactor = in->coefQFactor; + + vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CORRECT_COEFF_0, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *in) +{ +struct vfe_demosaic_cfg cmd; + struct vfe_demosaic_abf_cfg cmdabf; + uint32_t temp; + + memset(&cmd, 0, sizeof(cmd)); + temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG); + + cmd = *((struct vfe_demosaic_cfg *)(&temp)); + cmd.abfEnable = in->abfUpdate.enable; + cmd.forceAbfOn = in->abfUpdate.forceOn; + cmd.abfShift = in->abfUpdate.shift; + vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG, + (uint32_t *)&cmd, sizeof(cmd)); + + cmdabf.lpThreshold = in->abfUpdate.lpThreshold; + cmdabf.ratio = in->abfUpdate.ratio; + cmdabf.minValue = in->abfUpdate.min; + cmdabf.maxValue = in->abfUpdate.max; + vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0, + (uint32_t *)&cmdabf, sizeof(cmdabf)); +} + +void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *in) +{ + struct vfe_demosaic_cfg cmd; + struct vfe_demosaic_bpc_cfg cmdbpc; + uint32_t temp; + + memset(&cmd, 0, sizeof(cmd)); + + temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG); + + cmd = *((struct vfe_demosaic_cfg *)(&temp)); + cmd.badPixelCorrEnable = in->bpcUpdate.enable; + cmd.fminThreshold = in->bpcUpdate.fminThreshold; + cmd.fmaxThreshold = in->bpcUpdate.fmaxThreshold; + + vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG, + (uint32_t *)&cmd, sizeof(cmd)); + + cmdbpc.blueDiffThreshold = in->bpcUpdate.blueDiffThreshold; + cmdbpc.redDiffThreshold = in->bpcUpdate.redDiffThreshold; + cmdbpc.greenDiffThreshold = in->bpcUpdate.greenDiffThreshold; + + vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0, + (uint32_t *)&cmdbpc, sizeof(cmdbpc)); +} + +void vfe_demosaic_config(struct vfe_cmd_demosaic_config *in) +{ + struct vfe_demosaic_cfg cmd; + struct vfe_demosaic_bpc_cfg cmd_bpc; + struct vfe_demosaic_abf_cfg cmd_abf; + + memset(&cmd, 0, sizeof(cmd)); + memset(&cmd_bpc, 0, sizeof(cmd_bpc)); + memset(&cmd_abf, 0, sizeof(cmd_abf)); + + ctrl->vfeModuleEnableLocal.demosaicEnable = in->enable; + + cmd.abfEnable = in->abfConfig.enable; + cmd.badPixelCorrEnable = in->bpcConfig.enable; + cmd.forceAbfOn = in->abfConfig.forceOn; + cmd.abfShift = in->abfConfig.shift; + cmd.fminThreshold = in->bpcConfig.fminThreshold; + cmd.fmaxThreshold = in->bpcConfig.fmaxThreshold; + cmd.slopeShift = in->slopeShift; + + vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG, + (uint32_t *)&cmd, sizeof(cmd)); + + cmd_abf.lpThreshold = in->abfConfig.lpThreshold; + cmd_abf.ratio = in->abfConfig.ratio; + cmd_abf.minValue = in->abfConfig.min; + cmd_abf.maxValue = in->abfConfig.max; + + vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0, + (uint32_t *)&cmd_abf, sizeof(cmd_abf)); + + cmd_bpc.blueDiffThreshold = in->bpcConfig.blueDiffThreshold; + cmd_bpc.redDiffThreshold = in->bpcConfig.redDiffThreshold; + cmd_bpc.greenDiffThreshold = in->bpcConfig.greenDiffThreshold; + + vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0, + (uint32_t *)&cmd_bpc, sizeof(cmd_bpc)); +} + +void vfe_demux_channel_gain_update(struct vfe_cmd_demux_channel_gain_config *in) +{ + struct vfe_demux_cfg cmd; + + memset(&cmd, 0, sizeof(cmd)); + + cmd.ch0EvenGain = in->ch0EvenGain; + cmd.ch0OddGain = in->ch0OddGain; + cmd.ch1Gain = in->ch1Gain; + cmd.ch2Gain = in->ch2Gain; + + vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_demux_channel_gain_config(struct vfe_cmd_demux_channel_gain_config *in) +{ + struct vfe_demux_cfg cmd; + + memset(&cmd, 0, sizeof(cmd)); + + cmd.ch0EvenGain = in->ch0EvenGain; + cmd.ch0OddGain = in->ch0OddGain; + cmd.ch1Gain = in->ch1Gain; + cmd.ch2Gain = in->ch2Gain; + + vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_black_level_update(struct vfe_cmd_black_level_config *in) +{ + struct vfe_blacklevel_cfg cmd; + + memset(&cmd, 0, sizeof(cmd)); + ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable; + + cmd.evenEvenAdjustment = in->evenEvenAdjustment; + cmd.evenOddAdjustment = in->evenOddAdjustment; + cmd.oddEvenAdjustment = in->oddEvenAdjustment; + cmd.oddOddAdjustment = in->oddOddAdjustment; + + vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_black_level_config(struct vfe_cmd_black_level_config *in) +{ + struct vfe_blacklevel_cfg cmd; + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable; + + cmd.evenEvenAdjustment = in->evenEvenAdjustment; + cmd.evenOddAdjustment = in->evenOddAdjustment; + cmd.oddEvenAdjustment = in->oddEvenAdjustment; + cmd.oddOddAdjustment = in->oddOddAdjustment; + + vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_asf_update(struct vfe_cmd_asf_update *in) +{ + struct vfe_asf_update cmd; + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.asfEnable = in->enable; + + cmd.smoothEnable = in->smoothFilterEnabled; + cmd.sharpMode = in->sharpMode; + cmd.smoothCoeff0 = in->smoothCoefCenter; + cmd.smoothCoeff1 = in->smoothCoefSurr; + cmd.cropEnable = in->cropEnable; + cmd.sharpThresholdE1 = in->sharpThreshE1; + cmd.sharpDegreeK1 = in->sharpK1; + cmd.sharpDegreeK2 = in->sharpK2; + cmd.normalizeFactor = in->normalizeFactor; + cmd.sharpThresholdE2 = in->sharpThreshE2; + cmd.sharpThresholdE3 = in->sharpThreshE3; + cmd.sharpThresholdE4 = in->sharpThreshE4; + cmd.sharpThresholdE5 = in->sharpThreshE5; + cmd.F1Coeff0 = in->filter1Coefficients[0]; + cmd.F1Coeff1 = in->filter1Coefficients[1]; + cmd.F1Coeff2 = in->filter1Coefficients[2]; + cmd.F1Coeff3 = in->filter1Coefficients[3]; + cmd.F1Coeff4 = in->filter1Coefficients[4]; + cmd.F1Coeff5 = in->filter1Coefficients[5]; + cmd.F1Coeff6 = in->filter1Coefficients[6]; + cmd.F1Coeff7 = in->filter1Coefficients[7]; + cmd.F1Coeff8 = in->filter1Coefficients[8]; + cmd.F2Coeff0 = in->filter2Coefficients[0]; + cmd.F2Coeff1 = in->filter2Coefficients[1]; + cmd.F2Coeff2 = in->filter2Coefficients[2]; + cmd.F2Coeff3 = in->filter2Coefficients[3]; + cmd.F2Coeff4 = in->filter2Coefficients[4]; + cmd.F2Coeff5 = in->filter2Coefficients[5]; + cmd.F2Coeff6 = in->filter2Coefficients[6]; + cmd.F2Coeff7 = in->filter2Coefficients[7]; + cmd.F2Coeff8 = in->filter2Coefficients[8]; + + vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_asf_config(struct vfe_cmd_asf_config *in) +{ + struct vfe_asf_update cmd; + struct vfe_asfcrop_cfg cmd2; + + memset(&cmd, 0, sizeof(cmd)); + memset(&cmd2, 0, sizeof(cmd2)); + + ctrl->vfeModuleEnableLocal.asfEnable = in->enable; + + cmd.smoothEnable = in->smoothFilterEnabled; + cmd.sharpMode = in->sharpMode; + cmd.smoothCoeff0 = in->smoothCoefCenter; + cmd.smoothCoeff1 = in->smoothCoefSurr; + cmd.cropEnable = in->cropEnable; + cmd.sharpThresholdE1 = in->sharpThreshE1; + cmd.sharpDegreeK1 = in->sharpK1; + cmd.sharpDegreeK2 = in->sharpK2; + cmd.normalizeFactor = in->normalizeFactor; + cmd.sharpThresholdE2 = in->sharpThreshE2; + cmd.sharpThresholdE3 = in->sharpThreshE3; + cmd.sharpThresholdE4 = in->sharpThreshE4; + cmd.sharpThresholdE5 = in->sharpThreshE5; + cmd.F1Coeff0 = in->filter1Coefficients[0]; + cmd.F1Coeff1 = in->filter1Coefficients[1]; + cmd.F1Coeff2 = in->filter1Coefficients[2]; + cmd.F1Coeff3 = in->filter1Coefficients[3]; + cmd.F1Coeff4 = in->filter1Coefficients[4]; + cmd.F1Coeff5 = in->filter1Coefficients[5]; + cmd.F1Coeff6 = in->filter1Coefficients[6]; + cmd.F1Coeff7 = in->filter1Coefficients[7]; + cmd.F1Coeff8 = in->filter1Coefficients[8]; + cmd.F2Coeff0 = in->filter2Coefficients[0]; + cmd.F2Coeff1 = in->filter2Coefficients[1]; + cmd.F2Coeff2 = in->filter2Coefficients[2]; + cmd.F2Coeff3 = in->filter2Coefficients[3]; + cmd.F2Coeff4 = in->filter2Coefficients[4]; + cmd.F2Coeff5 = in->filter2Coefficients[5]; + cmd.F2Coeff6 = in->filter2Coefficients[6]; + cmd.F2Coeff7 = in->filter2Coefficients[7]; + cmd.F2Coeff8 = in->filter2Coefficients[8]; + + vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG, + (uint32_t *)&cmd, sizeof(cmd)); + + cmd2.firstLine = in->cropFirstLine; + cmd2.lastLine = in->cropLastLine; + cmd2.firstPixel = in->cropFirstPixel; + cmd2.lastPixel = in->cropLastPixel; + + vfe_prog_hw(ctrl->vfebase + VFE_ASF_CROP_WIDTH_CFG, + (uint32_t *)&cmd2, sizeof(cmd2)); +} + +void vfe_white_balance_config(struct vfe_cmd_white_balance_config *in) +{ + struct vfe_wb_cfg cmd; + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.whiteBalanceEnable = in->enable; + + cmd.ch0Gain = in->ch0Gain; + cmd.ch1Gain = in->ch1Gain; + cmd.ch2Gain = in->ch2Gain; + + vfe_prog_hw(ctrl->vfebase + VFE_WB_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *in) +{ + struct vfe_chroma_suppress_cfg cmd; + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.chromaSuppressionEnable = in->enable; + + cmd.m1 = in->m1; + cmd.m3 = in->m3; + cmd.n1 = in->n1; + cmd.n3 = in->n3; + cmd.mm1 = in->mm1; + cmd.nn1 = in->nn1; + + vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUPPRESS_CFG_0, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_roll_off_config(struct vfe_cmd_roll_off_config *in) +{ + struct vfe_rolloff_cfg cmd; + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.lensRollOffEnable = in->enable; + + cmd.gridWidth = in->gridWidth; + cmd.gridHeight = in->gridHeight; + cmd.yDelta = in->yDelta; + cmd.gridX = in->gridXIndex; + cmd.gridY = in->gridYIndex; + cmd.pixelX = in->gridPixelXIndex; + cmd.pixelY = in->gridPixelYIndex; + cmd.yDeltaAccum = in->yDeltaAccum; + + vfe_prog_hw(ctrl->vfebase + VFE_ROLLOFF_CFG_0, + (uint32_t *)&cmd, sizeof(cmd)); + + vfe_write_lens_roll_off_table(in); +} + +void vfe_chroma_subsample_config(struct vfe_cmd_chroma_subsample_config *in) +{ + struct vfe_chromasubsample_cfg cmd; + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.chromaSubsampleEnable = in->enable; + + cmd.hCositedPhase = in->hCositedPhase; + cmd.vCositedPhase = in->vCositedPhase; + cmd.hCosited = in->hCosited; + cmd.vCosited = in->vCosited; + cmd.hsubSampleEnable = in->hsubSampleEnable; + cmd.vsubSampleEnable = in->vsubSampleEnable; + cmd.cropEnable = in->cropEnable; + cmd.cropWidthLastPixel = in->cropWidthLastPixel; + cmd.cropWidthFirstPixel = in->cropWidthFirstPixel; + cmd.cropHeightLastLine = in->cropHeightLastLine; + cmd.cropHeightFirstLine = in->cropHeightFirstLine; + + vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUBSAMPLE_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *in) +{ + struct vfe_chroma_enhance_cfg cmd; + struct vfe_color_convert_cfg cmd2; + + memset(&cmd, 0, sizeof(cmd)); + memset(&cmd2, 0, sizeof(cmd2)); + + ctrl->vfeModuleEnableLocal.chromaEnhanEnable = in->enable; + + cmd.ap = in->ap; + cmd.am = in->am; + cmd.bp = in->bp; + cmd.bm = in->bm; + cmd.cp = in->cp; + cmd.cm = in->cm; + cmd.dp = in->dp; + cmd.dm = in->dm; + cmd.kcb = in->kcb; + cmd.kcr = in->kcr; + + cmd2.v0 = in->RGBtoYConversionV0; + cmd2.v1 = in->RGBtoYConversionV1; + cmd2.v2 = in->RGBtoYConversionV2; + cmd2.ConvertOffset = in->RGBtoYConversionOffset; + + vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_ENHAN_A, + (uint32_t *)&cmd, sizeof(cmd)); + + vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CONVERT_COEFF_0, + (uint32_t *)&cmd2, sizeof(cmd2)); +} + +void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *in) +{ + struct vfe_scaler2_cfg cmd; + + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.scaler2CbcrEnable = in->enable; + + cmd.hEnable = in->hconfig.enable; + cmd.vEnable = in->vconfig.enable; + cmd.inWidth = in->hconfig.inputSize; + cmd.outWidth = in->hconfig.outputSize; + cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor; + cmd.horizInterResolution = in->hconfig.interpolationResolution; + cmd.inHeight = in->vconfig.inputSize; + cmd.outHeight = in->vconfig.outputSize; + cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor; + cmd.vertInterResolution = in->vconfig.interpolationResolution; + + vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CBCR_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *in) +{ + struct vfe_scaler2_cfg cmd; + + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.scaler2YEnable = in->enable; + + cmd.hEnable = in->hconfig.enable; + cmd.vEnable = in->vconfig.enable; + cmd.inWidth = in->hconfig.inputSize; + cmd.outWidth = in->hconfig.outputSize; + cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor; + cmd.horizInterResolution = in->hconfig.interpolationResolution; + cmd.inHeight = in->vconfig.inputSize; + cmd.outHeight = in->vconfig.outputSize; + cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor; + cmd.vertInterResolution = in->vconfig.interpolationResolution; + + vfe_prog_hw(ctrl->vfebase + VFE_SCALE_Y_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *in) +{ + struct vfe_main_scaler_cfg cmd; + + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.mainScalerEnable = in->enable; + + cmd.hEnable = in->hconfig.enable; + cmd.vEnable = in->vconfig.enable; + cmd.inWidth = in->hconfig.inputSize; + cmd.outWidth = in->hconfig.outputSize; + cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor; + cmd.horizInterResolution = in->hconfig.interpolationResolution; + cmd.horizMNInit = in->MNInitH.MNCounterInit; + cmd.horizPhaseInit = in->MNInitH.phaseInit; + cmd.inHeight = in->vconfig.inputSize; + cmd.outHeight = in->vconfig.outputSize; + cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor; + cmd.vertInterResolution = in->vconfig.interpolationResolution; + cmd.vertMNInit = in->MNInitV.MNCounterInit; + cmd.vertPhaseInit = in->MNInitV.phaseInit; + + vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_stats_wb_exp_stop(void) +{ + ctrl->vfeStatsCmdLocal.axwEnable = FALSE; + ctrl->vfeImaskLocal.awbPingpongIrq = FALSE; +} + +void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *in) +{ + struct vfe_statsawb_update cmd; + struct vfe_statsawbae_update cmd2; + + memset(&cmd, 0, sizeof(cmd)); + memset(&cmd2, 0, sizeof(cmd2)); + + cmd.m1 = in->awbMCFG[0]; + cmd.m2 = in->awbMCFG[1]; + cmd.m3 = in->awbMCFG[2]; + cmd.m4 = in->awbMCFG[3]; + cmd.c1 = in->awbCCFG[0]; + cmd.c2 = in->awbCCFG[1]; + cmd.c3 = in->awbCCFG[2]; + cmd.c4 = in->awbCCFG[3]; + vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG, + (uint32_t *)&cmd, sizeof(cmd)); + + cmd2.aeRegionCfg = in->wbExpRegions; + cmd2.aeSubregionCfg = in->wbExpSubRegion; + cmd2.awbYMin = in->awbYMin; + cmd2.awbYMax = in->awbYMax; + vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG, + (uint32_t *)&cmd2, sizeof(cmd2)); +} + +void vfe_stats_update_af(struct vfe_cmd_stats_af_update *in) +{ + struct vfe_statsaf_update cmd; + memset(&cmd, 0, sizeof(cmd)); + + cmd.windowVOffset = in->windowVOffset; + cmd.windowHOffset = in->windowHOffset; + cmd.windowMode = in->windowMode; + cmd.windowHeight = in->windowHeight; + cmd.windowWidth = in->windowWidth; + + vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *in) +{ + struct vfe_statsawb_update cmd; + struct vfe_statsawbae_update cmd2; + struct vfe_statsaxw_hdr_cfg cmd3; + + ctrl->vfeStatsCmdLocal.axwEnable = in->enable; + ctrl->vfeImaskLocal.awbPingpongIrq = TRUE; + + memset(&cmd, 0, sizeof(cmd)); + memset(&cmd2, 0, sizeof(cmd2)); + memset(&cmd3, 0, sizeof(cmd3)); + + cmd.m1 = in->awbMCFG[0]; + cmd.m2 = in->awbMCFG[1]; + cmd.m3 = in->awbMCFG[2]; + cmd.m4 = in->awbMCFG[3]; + cmd.c1 = in->awbCCFG[0]; + cmd.c2 = in->awbCCFG[1]; + cmd.c3 = in->awbCCFG[2]; + cmd.c4 = in->awbCCFG[3]; + vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG, + (uint32_t *)&cmd, sizeof(cmd)); + + cmd2.aeRegionCfg = in->wbExpRegions; + cmd2.aeSubregionCfg = in->wbExpSubRegion; + cmd2.awbYMin = in->awbYMin; + cmd2.awbYMax = in->awbYMax; + vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG, + (uint32_t *)&cmd2, sizeof(cmd2)); + + cmd3.axwHeader = in->axwHeader; + vfe_prog_hw(ctrl->vfebase + VFE_STATS_AXW_HEADER, + (uint32_t *)&cmd3, sizeof(cmd3)); +} + +void vfe_stats_start_af(struct vfe_cmd_stats_af_start *in) +{ + struct vfe_statsaf_update cmd; + struct vfe_statsaf_cfg cmd2; + + memset(&cmd, 0, sizeof(cmd)); + memset(&cmd2, 0, sizeof(cmd2)); + + ctrl->vfeStatsCmdLocal.autoFocusEnable = in->enable; + ctrl->vfeImaskLocal.afPingpongIrq = TRUE; + + cmd.windowVOffset = in->windowVOffset; + cmd.windowHOffset = in->windowHOffset; + cmd.windowMode = in->windowMode; + cmd.windowHeight = in->windowHeight; + cmd.windowWidth = in->windowWidth; + + vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG, + (uint32_t *)&cmd, sizeof(cmd)); + + cmd2.a00 = in->highPassCoef[0]; + cmd2.a04 = in->highPassCoef[1]; + cmd2.a20 = in->highPassCoef[2]; + cmd2.a21 = in->highPassCoef[3]; + cmd2.a22 = in->highPassCoef[4]; + cmd2.a23 = in->highPassCoef[5]; + cmd2.a24 = in->highPassCoef[6]; + cmd2.fvMax = in->metricMax; + cmd2.fvMetric = in->metricSelection; + cmd2.afHeader = in->bufferHeader; + cmd2.entry00 = in->gridForMultiWindows[0]; + cmd2.entry01 = in->gridForMultiWindows[1]; + cmd2.entry02 = in->gridForMultiWindows[2]; + cmd2.entry03 = in->gridForMultiWindows[3]; + cmd2.entry10 = in->gridForMultiWindows[4]; + cmd2.entry11 = in->gridForMultiWindows[5]; + cmd2.entry12 = in->gridForMultiWindows[6]; + cmd2.entry13 = in->gridForMultiWindows[7]; + cmd2.entry20 = in->gridForMultiWindows[8]; + cmd2.entry21 = in->gridForMultiWindows[9]; + cmd2.entry22 = in->gridForMultiWindows[10]; + cmd2.entry23 = in->gridForMultiWindows[11]; + cmd2.entry30 = in->gridForMultiWindows[12]; + cmd2.entry31 = in->gridForMultiWindows[13]; + cmd2.entry32 = in->gridForMultiWindows[14]; + cmd2.entry33 = in->gridForMultiWindows[15]; + + vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_GRID_0, + (uint32_t *)&cmd2, sizeof(cmd2)); +} + +void vfe_stats_setting(struct vfe_cmd_stats_setting *in) +{ + struct vfe_statsframe cmd1; + struct vfe_busstats_wrprio cmd2; + + memset(&cmd1, 0, sizeof(cmd1)); + memset(&cmd2, 0, sizeof(cmd2)); + + ctrl->afStatsControl.addressBuffer[0] = in->afBuffer[0]; + ctrl->afStatsControl.addressBuffer[1] = in->afBuffer[1]; + ctrl->afStatsControl.nextFrameAddrBuf = in->afBuffer[2]; + + ctrl->awbStatsControl.addressBuffer[0] = in->awbBuffer[0]; + ctrl->awbStatsControl.addressBuffer[1] = in->awbBuffer[1]; + ctrl->awbStatsControl.nextFrameAddrBuf = in->awbBuffer[2]; + + cmd1.lastPixel = in->frameHDimension; + cmd1.lastLine = in->frameVDimension; + vfe_prog_hw(ctrl->vfebase + VFE_STATS_FRAME_SIZE, + (uint32_t *)&cmd1, sizeof(cmd1)); + + cmd2.afBusPriority = in->afBusPriority; + cmd2.awbBusPriority = in->awbBusPriority; + cmd2.histBusPriority = in->histBusPriority; + cmd2.afBusPriorityEn = in->afBusPrioritySelection; + cmd2.awbBusPriorityEn = in->awbBusPrioritySelection; + cmd2.histBusPriorityEn = in->histBusPrioritySelection; + + vfe_prog_hw(ctrl->vfebase + VFE_BUS_STATS_WR_PRIORITY, + (uint32_t *)&cmd2, sizeof(cmd2)); + + /* Program the bus ping pong address for statistics modules. */ + writel(in->afBuffer[0], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); + writel(in->afBuffer[1], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); + writel(in->awbBuffer[0], + ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); + writel(in->awbBuffer[1], + ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); + writel(in->histBuffer[0], + ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR); + writel(in->histBuffer[1], + ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR); +} + +void vfe_axi_input_config(struct vfe_cmd_axi_input_config *in) +{ + struct VFE_AxiInputCmdType cmd; + uint32_t xSizeWord, axiRdUnpackPattern; + uint8_t axiInputPpw; + uint32_t busPingpongRdIrqEnable; + + ctrl->vfeImaskLocal.rdPingpongIrq = TRUE; + + switch (in->pixelSize) { + case VFE_RAW_PIXEL_DATA_SIZE_10BIT: + ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_10BIT; + break; + + case VFE_RAW_PIXEL_DATA_SIZE_12BIT: + ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_12BIT; + break; + + case VFE_RAW_PIXEL_DATA_SIZE_8BIT: + default: + ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_8BIT; + break; + } + + memset(&cmd, 0, sizeof(cmd)); + + switch (in->pixelSize) { + case VFE_RAW_PIXEL_DATA_SIZE_10BIT: + axiInputPpw = 6; + axiRdUnpackPattern = 0xD43210; + break; + + case VFE_RAW_PIXEL_DATA_SIZE_12BIT: + axiInputPpw = 5; + axiRdUnpackPattern = 0xC3210; + break; + + case VFE_RAW_PIXEL_DATA_SIZE_8BIT: + default: + axiInputPpw = 8; + axiRdUnpackPattern = 0xF6543210; + break; + } + + xSizeWord = + ((((in->xOffset % axiInputPpw) + in->xSize) + + (axiInputPpw-1)) / axiInputPpw) - 1; + + cmd.stripeStartAddr0 = in->fragAddr[0]; + cmd.stripeStartAddr1 = in->fragAddr[1]; + cmd.stripeStartAddr2 = in->fragAddr[2]; + cmd.stripeStartAddr3 = in->fragAddr[3]; + cmd.ySize = in->ySize; + cmd.yOffsetDelta = 0; + cmd.xSizeWord = xSizeWord; + cmd.burstLength = 1; + cmd.NumOfRows = in->numOfRows; + cmd.RowIncrement = (in->rowIncrement + (axiInputPpw - 1)) / axiInputPpw; + cmd.mainUnpackHeight = in->ySize; + cmd.mainUnpackWidth = in->xSize - 1; + cmd.mainUnpackHbiSel = (uint32_t)in->unpackHbi; + cmd.mainUnpackPhase = in->unpackPhase; + cmd.unpackPattern = axiRdUnpackPattern; + cmd.padLeft = in->padRepeatCountLeft; + cmd.padRight = in->padRepeatCountRight; + cmd.padTop = in->padRepeatCountTop; + cmd.padBottom = in->padRepeatCountBottom; + cmd.leftUnpackPattern0 = in->padLeftComponentSelectCycle0; + cmd.leftUnpackPattern1 = in->padLeftComponentSelectCycle1; + cmd.leftUnpackPattern2 = in->padLeftComponentSelectCycle2; + cmd.leftUnpackPattern3 = in->padLeftComponentSelectCycle3; + cmd.leftUnpackStop0 = in->padLeftStopCycle0; + cmd.leftUnpackStop1 = in->padLeftStopCycle1; + cmd.leftUnpackStop2 = in->padLeftStopCycle2; + cmd.leftUnpackStop3 = in->padLeftStopCycle3; + cmd.rightUnpackPattern0 = in->padRightComponentSelectCycle0; + cmd.rightUnpackPattern1 = in->padRightComponentSelectCycle1; + cmd.rightUnpackPattern2 = in->padRightComponentSelectCycle2; + cmd.rightUnpackPattern3 = in->padRightComponentSelectCycle3; + cmd.rightUnpackStop0 = in->padRightStopCycle0; + cmd.rightUnpackStop1 = in->padRightStopCycle1; + cmd.rightUnpackStop2 = in->padRightStopCycle2; + cmd.rightUnpackStop3 = in->padRightStopCycle3; + cmd.topUnapckPattern = in->padTopLineCount; + cmd.bottomUnapckPattern = in->padBottomLineCount; + + /* program vfe_bus_cfg */ + vfe_prog_hw(ctrl->vfebase + VFE_BUS_STRIPE_RD_ADDR_0, + (uint32_t *)&cmd, sizeof(cmd)); + + /* hacking code, put it to default value */ + busPingpongRdIrqEnable = 0xf; + + writel(busPingpongRdIrqEnable, ctrl->vfebase + VFE_BUS_PINGPONG_IRQ_EN); +} + +void vfe_axi_output_config(struct vfe_cmd_axi_output_config *in) +{ + /* local variable */ + uint32_t *pcircle; + uint32_t *pdest; + uint32_t *psrc; + uint8_t i; + uint8_t fcnt; + uint16_t axioutpw = 8; + + /* parameters check, condition and usage mode check */ + ctrl->encPath.fragCount = in->output2.fragmentCount; + if (ctrl->encPath.fragCount > 1) + ctrl->encPath.multiFrag = TRUE; + + ctrl->viewPath.fragCount = in->output1.fragmentCount; + if (ctrl->viewPath.fragCount > 1) + ctrl->viewPath.multiFrag = TRUE; + + /* VFE_BUS_CFG. raw data size */ + ctrl->vfeBusConfigLocal.rawPixelDataSize = in->outputDataSize; + + switch (in->outputDataSize) { + case VFE_RAW_PIXEL_DATA_SIZE_8BIT: + axioutpw = 8; + break; + + case VFE_RAW_PIXEL_DATA_SIZE_10BIT: + axioutpw = 6; + break; + + case VFE_RAW_PIXEL_DATA_SIZE_12BIT: + axioutpw = 5; + break; + } + + ctrl->axiOutputMode = in->outputMode; + + CDBG("axiOutputMode = %d\n", ctrl->axiOutputMode); + + switch (ctrl->axiOutputMode) { + case VFE_AXI_OUTPUT_MODE_Output1: { + ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE; + ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; + ctrl->vfeBusConfigLocal.rawWritePathSelect = + VFE_RAW_OUTPUT_DISABLED; + + ctrl->encPath.pathEnabled = FALSE; + ctrl->vfeImaskLocal.encIrq = FALSE; + ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE; + ctrl->vfeBusConfigLocal.encCbcrWrPathEn = FALSE; + ctrl->viewPath.pathEnabled = TRUE; + ctrl->vfeImaskLocal.viewIrq = TRUE; + ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE; + ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE; + + if (ctrl->vfeBusConfigLocal.encYWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewYWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; + } /* VFE_AXI_OUTPUT_MODE_Output1 */ + break; + + case VFE_AXI_OUTPUT_MODE_Output2: { + ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE; + ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; + ctrl->vfeBusConfigLocal.rawWritePathSelect = + VFE_RAW_OUTPUT_DISABLED; + + ctrl->encPath.pathEnabled = TRUE; + ctrl->vfeImaskLocal.encIrq = TRUE; + ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE; + ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; + + ctrl->viewPath.pathEnabled = FALSE; + ctrl->vfeImaskLocal.viewIrq = FALSE; + ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE; + ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = FALSE; + + if (ctrl->vfeBusConfigLocal.encYWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewYWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; + } /* VFE_AXI_OUTPUT_MODE_Output2 */ + break; + + case VFE_AXI_OUTPUT_MODE_Output1AndOutput2: { + ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE; + ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; + ctrl->vfeBusConfigLocal.rawWritePathSelect = + VFE_RAW_OUTPUT_DISABLED; + + ctrl->encPath.pathEnabled = TRUE; + ctrl->vfeImaskLocal.encIrq = TRUE; + ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE; + ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; + ctrl->viewPath.pathEnabled = TRUE; + ctrl->vfeImaskLocal.viewIrq = TRUE; + ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE; + ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE; + + if (ctrl->vfeBusConfigLocal.encYWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewYWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; + } /* VFE_AXI_OUTPUT_MODE_Output1AndOutput2 */ + break; + + case VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2: { + /* For raw snapshot, we need both ping and pong buffer + * initialized to the same address. Otherwise, if we + * leave the pong buffer to NULL, there will be axi_error. + * Note that ideally we should deal with this at upper layer, + * which is in msm_vfe8x.c */ + if (!in->output2.outputCbcr.outFragments[1][0]) { + in->output2.outputCbcr.outFragments[1][0] = + in->output2.outputCbcr.outFragments[0][0]; + } + + ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE; + ctrl->vfeCamifConfigLocal.camif2OutputEnable = FALSE; + ctrl->vfeBusConfigLocal.rawWritePathSelect = + VFE_RAW_OUTPUT_ENC_CBCR_PATH; + + ctrl->encPath.pathEnabled = TRUE; + ctrl->vfeImaskLocal.encIrq = TRUE; + ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = + VFE_COMP_IRQ_CBCR_ONLY; + + ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE; + ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; + + ctrl->viewPath.pathEnabled = FALSE; + ctrl->vfeImaskLocal.viewIrq = FALSE; + ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE; + ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = FALSE; + + if (ctrl->vfeBusConfigLocal.encYWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewYWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; + } /* VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2 */ + break; + + case VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1: { + ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE; + ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; + ctrl->vfeBusConfigLocal.rawWritePathSelect = + VFE_RAW_OUTPUT_VIEW_CBCR_PATH; + + ctrl->encPath.pathEnabled = TRUE; + ctrl->vfeImaskLocal.encIrq = TRUE; + ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE; + ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; + + ctrl->viewPath.pathEnabled = TRUE; + ctrl->vfeImaskLocal.viewIrq = TRUE; + ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = + VFE_COMP_IRQ_CBCR_ONLY; + + ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE; + ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE; + + if (ctrl->vfeBusConfigLocal.encYWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewYWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; + } /* VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1 */ + break; + + case VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2: { + ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE; + ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; + ctrl->vfeBusConfigLocal.rawWritePathSelect = + VFE_RAW_OUTPUT_ENC_CBCR_PATH; + + ctrl->encPath.pathEnabled = TRUE; + ctrl->vfeImaskLocal.encIrq = TRUE; + ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = + VFE_COMP_IRQ_CBCR_ONLY; + + ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE; + ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; + + ctrl->viewPath.pathEnabled = TRUE; + ctrl->vfeImaskLocal.viewIrq = TRUE; + + ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE; + ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE; + + if (ctrl->vfeBusConfigLocal.encYWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && + ctrl->encPath.multiFrag) + ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewYWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; + + if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && + ctrl->viewPath.multiFrag) + ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; + } /* VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2 */ + break; + + case VFE_AXI_LAST_OUTPUT_MODE_ENUM: + break; + } /* switch */ + + /* Save the addresses for each path. */ + /* output2 path */ + fcnt = ctrl->encPath.fragCount; + + pcircle = ctrl->encPath.yPath.addressBuffer; + pdest = ctrl->encPath.nextFrameAddrBuf; + + psrc = &(in->output2.outputY.outFragments[0][0]); + for (i = 0; i < fcnt; i++) + *pcircle++ = *psrc++; + + psrc = &(in->output2.outputY.outFragments[1][0]); + for (i = 0; i < fcnt; i++) + *pcircle++ = *psrc++; + + psrc = &(in->output2.outputY.outFragments[2][0]); + for (i = 0; i < fcnt; i++) + *pdest++ = *psrc++; + + pcircle = ctrl->encPath.cbcrPath.addressBuffer; + + psrc = &(in->output2.outputCbcr.outFragments[0][0]); + for (i = 0; i < fcnt; i++) + *pcircle++ = *psrc++; + + psrc = &(in->output2.outputCbcr.outFragments[1][0]); + for (i = 0; i < fcnt; i++) + *pcircle++ = *psrc++; + + psrc = &(in->output2.outputCbcr.outFragments[2][0]); + for (i = 0; i < fcnt; i++) + *pdest++ = *psrc++; + + vfe_set_bus_pipo_addr(&ctrl->viewPath, &ctrl->encPath); + + ctrl->encPath.ackPending = FALSE; + ctrl->encPath.currentFrame = ping; + ctrl->encPath.whichOutputPath = 1; + ctrl->encPath.yPath.fragIndex = 2; + ctrl->encPath.cbcrPath.fragIndex = 2; + ctrl->encPath.yPath.hwCurrentFlag = ping; + ctrl->encPath.cbcrPath.hwCurrentFlag = ping; + + /* output1 path */ + pcircle = ctrl->viewPath.yPath.addressBuffer; + pdest = ctrl->viewPath.nextFrameAddrBuf; + fcnt = ctrl->viewPath.fragCount; + + psrc = &(in->output1.outputY.outFragments[0][0]); + for (i = 0; i < fcnt; i++) + *pcircle++ = *psrc++; + + psrc = &(in->output1.outputY.outFragments[1][0]); + for (i = 0; i < fcnt; i++) + *pcircle++ = *psrc++; + + psrc = &(in->output1.outputY.outFragments[2][0]); + for (i = 0; i < fcnt; i++) + *pdest++ = *psrc++; + + pcircle = ctrl->viewPath.cbcrPath.addressBuffer; + + psrc = &(in->output1.outputCbcr.outFragments[0][0]); + for (i = 0; i < fcnt; i++) + *pcircle++ = *psrc++; + + psrc = &(in->output1.outputCbcr.outFragments[1][0]); + for (i = 0; i < fcnt; i++) + *pcircle++ = *psrc++; + + psrc = &(in->output1.outputCbcr.outFragments[2][0]); + for (i = 0; i < fcnt; i++) + *pdest++ = *psrc++; + + ctrl->viewPath.ackPending = FALSE; + ctrl->viewPath.currentFrame = ping; + ctrl->viewPath.whichOutputPath = 0; + ctrl->viewPath.yPath.fragIndex = 2; + ctrl->viewPath.cbcrPath.fragIndex = 2; + ctrl->viewPath.yPath.hwCurrentFlag = ping; + ctrl->viewPath.cbcrPath.hwCurrentFlag = ping; + + /* call to program the registers. */ + vfe_axi_output(in, &ctrl->viewPath, &ctrl->encPath, axioutpw); +} + +void vfe_camif_config(struct vfe_cmd_camif_config *in) +{ + struct vfe_camifcfg cmd; + memset(&cmd, 0, sizeof(cmd)); + + CDBG("camif.frame pixelsPerLine = %d\n", in->frame.pixelsPerLine); + CDBG("camif.frame linesPerFrame = %d\n", in->frame.linesPerFrame); + CDBG("camif.window firstpixel = %d\n", in->window.firstpixel); + CDBG("camif.window lastpixel = %d\n", in->window.lastpixel); + CDBG("camif.window firstline = %d\n", in->window.firstline); + CDBG("camif.window lastline = %d\n", in->window.lastline); + + /* determine if epoch interrupt needs to be enabled. */ + if ((in->epoch1.enable == TRUE) && + (in->epoch1.lineindex <= in->frame.linesPerFrame)) + ctrl->vfeImaskLocal.camifEpoch1Irq = 1; + + if ((in->epoch2.enable == TRUE) && + (in->epoch2.lineindex <= in->frame.linesPerFrame)) { + ctrl->vfeImaskLocal.camifEpoch2Irq = 1; + } + + /* save the content to program CAMIF_CONFIG seperately. */ + ctrl->vfeCamifConfigLocal.camifCfgFromCmd = in->camifConfig; + + /* EFS_Config */ + cmd.efsEndOfLine = in->EFS.efsendofline; + cmd.efsStartOfLine = in->EFS.efsstartofline; + cmd.efsEndOfFrame = in->EFS.efsendofframe; + cmd.efsStartOfFrame = in->EFS.efsstartofframe; + + /* Frame Config */ + cmd.frameConfigPixelsPerLine = in->frame.pixelsPerLine; + cmd.frameConfigLinesPerFrame = in->frame.linesPerFrame; + + /* Window Width Config */ + cmd.windowWidthCfgLastPixel = in->window.lastpixel; + cmd.windowWidthCfgFirstPixel = in->window.firstpixel; + + /* Window Height Config */ + cmd.windowHeightCfglastLine = in->window.lastline; + cmd.windowHeightCfgfirstLine = in->window.firstline; + + /* Subsample 1 Config */ + cmd.subsample1CfgPixelSkip = in->subsample.pixelskipmask; + cmd.subsample1CfgLineSkip = in->subsample.lineskipmask; + + /* Subsample 2 Config */ + cmd.subsample2CfgFrameSkip = in->subsample.frameskip; + cmd.subsample2CfgFrameSkipMode = in->subsample.frameskipmode; + cmd.subsample2CfgPixelSkipWrap = in->subsample.pixelskipwrap; + + /* Epoch Interrupt */ + cmd.epoch1Line = in->epoch1.lineindex; + cmd.epoch2Line = in->epoch2.lineindex; + + vfe_prog_hw(ctrl->vfebase + CAMIF_EFS_CONFIG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *in) +{ + struct vfe_fov_crop_cfg cmd; + memset(&cmd, 0, sizeof(cmd)); + + ctrl->vfeModuleEnableLocal.cropEnable = in->enable; + + /* FOV Corp, Part 1 */ + cmd.lastPixel = in->lastPixel; + cmd.firstPixel = in->firstPixel; + + /* FOV Corp, Part 2 */ + cmd.lastLine = in->lastLine; + cmd.firstLine = in->firstLine; + + vfe_prog_hw(ctrl->vfebase + VFE_CROP_WIDTH_CFG, + (uint32_t *)&cmd, sizeof(cmd)); +} + +void vfe_get_hw_version(struct vfe_cmd_hw_version *out) +{ + uint32_t vfeHwVersionPacked; + struct vfe_hw_ver ver; + + vfeHwVersionPacked = readl(ctrl->vfebase + VFE_HW_VERSION); + + ver = *((struct vfe_hw_ver *)&vfeHwVersionPacked); + + out->coreVersion = ver.coreVersion; + out->minorVersion = ver.minorVersion; + out->majorVersion = ver.majorVersion; +} + +static void vfe_reset_internal_variables(void) +{ + /* local variables to program the hardware. */ + ctrl->vfeImaskPacked = 0; + ctrl->vfeImaskCompositePacked = 0; + + /* FALSE = disable, 1 = enable. */ + memset(&ctrl->vfeModuleEnableLocal, 0, + sizeof(ctrl->vfeModuleEnableLocal)); + + /* 0 = disable, 1 = enable */ + memset(&ctrl->vfeCamifConfigLocal, 0, + sizeof(ctrl->vfeCamifConfigLocal)); + /* 0 = disable, 1 = enable */ + memset(&ctrl->vfeImaskLocal, 0, sizeof(ctrl->vfeImaskLocal)); + memset(&ctrl->vfeStatsCmdLocal, 0, sizeof(ctrl->vfeStatsCmdLocal)); + memset(&ctrl->vfeBusConfigLocal, 0, sizeof(ctrl->vfeBusConfigLocal)); + memset(&ctrl->vfeBusPmConfigLocal, 0, + sizeof(ctrl->vfeBusPmConfigLocal)); + memset(&ctrl->vfeBusCmdLocal, 0, sizeof(ctrl->vfeBusCmdLocal)); + memset(&ctrl->vfeInterruptNameLocal, 0, + sizeof(ctrl->vfeInterruptNameLocal)); + memset(&ctrl->vfeDroppedFrameCounts, 0, + sizeof(ctrl->vfeDroppedFrameCounts)); + memset(&ctrl->vfeIrqThreadMsgLocal, 0, + sizeof(ctrl->vfeIrqThreadMsgLocal)); + + /* state control variables */ + ctrl->vfeStartAckPendingFlag = FALSE; + ctrl->vfeStopAckPending = FALSE; + ctrl->vfeIrqCompositeMaskLocal.ceDoneSel = 0; + ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = VFE_COMP_IRQ_BOTH_Y_CBCR; + ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = + VFE_COMP_IRQ_BOTH_Y_CBCR; + + ctrl->vstate = VFE_STATE_IDLE; + + ctrl->axiOutputMode = VFE_AXI_LAST_OUTPUT_MODE_ENUM; + /* 0 for continuous mode, 1 for snapshot mode */ + ctrl->vfeOperationMode = VFE_START_OPERATION_MODE_CONTINUOUS; + ctrl->vfeSnapShotCount = 0; + ctrl->vfeStatsPingPongReloadFlag = FALSE; + /* this is unsigned 32 bit integer. */ + ctrl->vfeFrameId = 0; + ctrl->vfeFrameSkip.output1Pattern = 0xffffffff; + ctrl->vfeFrameSkip.output1Period = 31; + ctrl->vfeFrameSkip.output2Pattern = 0xffffffff; + ctrl->vfeFrameSkip.output2Period = 31; + ctrl->vfeFrameSkipPattern = 0xffffffff; + ctrl->vfeFrameSkipCount = 0; + ctrl->vfeFrameSkipPeriod = 31; + + memset((void *)&ctrl->encPath, 0, sizeof(ctrl->encPath)); + memset((void *)&ctrl->viewPath, 0, sizeof(ctrl->viewPath)); + + ctrl->encPath.whichOutputPath = 1; + ctrl->encPath.cbcrStatusBit = 5; + ctrl->viewPath.whichOutputPath = 0; + ctrl->viewPath.cbcrStatusBit = 7; + + ctrl->vfeTestGenStartFlag = FALSE; + + /* default to bank 0. */ + ctrl->vfeLaBankSel = 0; + + /* default to bank 0 for all channels. */ + memset(&ctrl->vfeGammaLutSel, 0, sizeof(ctrl->vfeGammaLutSel)); + + /* Stats control variables. */ + memset(&ctrl->afStatsControl, 0, sizeof(ctrl->afStatsControl)); + memset(&ctrl->awbStatsControl, 0, sizeof(ctrl->awbStatsControl)); + vfe_set_stats_pingpong_address(&ctrl->afStatsControl, + &ctrl->awbStatsControl); +} + +void vfe_reset(void) +{ + spin_lock_init(&msm_vfe_ctrl_lock); + vfe_reset_internal_variables(); + + atomic_set(&ctrl->vfe_serv_interrupt, 1); + ctrl->vfeImaskLocal.resetAckIrq = TRUE; + ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal); + + /* disable all interrupts. */ + writel(VFE_DISABLE_ALL_IRQS, ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK); + + /* clear all pending interrupts*/ + writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR); + + /* enable reset_ack interrupt. */ + writel(ctrl->vfeImaskPacked, ctrl->vfebase + VFE_IRQ_MASK); + + writel(VFE_RESET_UPON_RESET_CMD, ctrl->vfebase + VFE_GLOBAL_RESET_CMD); +} diff --git a/drivers/media/video/msm_zsl/msm_vfe8x_proc.h b/drivers/media/video/msm_zsl/msm_vfe8x_proc.h new file mode 100644 index 00000000000..da00e8fb17f --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vfe8x_proc.h @@ -0,0 +1,1563 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __MSM_VFE8X_REG_H__ +#define __MSM_VFE8X_REG_H__ + +#include +#include +#include "msm_vfe8x.h" + + +#define MSM_AXI_QOS_PREVIEW 128000 +#define MSM_AXI_QOS_SNAPSHOT 128000 +#define MSM_AXI_QOS_RECORDING 128000 + + +/* at start of camif, bit 1:0 = 0x01:enable + * image data capture at frame boundary. */ +#define CAMIF_COMMAND_START 0x00000005 + +/* bit 2= 0x1:clear the CAMIF_STATUS register + * value. */ +#define CAMIF_COMMAND_CLEAR 0x00000004 + +/* at stop of vfe pipeline, for now it is assumed + * that camif will stop at any time. Bit 1:0 = 0x10: + * disable image data capture immediately. */ +#define CAMIF_COMMAND_STOP_IMMEDIATELY 0x00000002 + +/* at stop of vfe pipeline, for now it is assumed + * that camif will stop at any time. Bit 1:0 = 0x00: + * disable image data capture at frame boundary */ +#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY 0x00000000 + +/* to halt axi bridge */ +#define AXI_HALT 0x00000001 + +/* clear the halt bit. */ +#define AXI_HALT_CLEAR 0x00000000 + +/* reset the pipeline when stop command is issued. + * (without reset the register.) bit 26-31 = 0, + * domain reset, bit 0-9 = 1 for module reset, except + * register module. */ +#define VFE_RESET_UPON_STOP_CMD 0x000003ef + +/* reset the pipeline when reset command. + * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */ +#define VFE_RESET_UPON_RESET_CMD 0x000003ff + +/* bit 5 is for axi status idle or busy. + * 1 = halted, 0 = busy */ +#define AXI_STATUS_BUSY_MASK 0x00000020 + +/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present + * for frame done interrupt */ +#define VFE_COMP_IRQ_BOTH_Y_CBCR 3 + +/* bit 1 = 1, only cbcr irq triggers frame done interrupt */ +#define VFE_COMP_IRQ_CBCR_ONLY 2 + +/* bit 0 = 1, only y irq triggers frame done interrupt */ +#define VFE_COMP_IRQ_Y_ONLY 1 + +/* bit 0 = 1, PM go; bit1 = 1, PM stop */ +#define VFE_PERFORMANCE_MONITOR_GO 0x00000001 +#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002 + +/* bit 0 = 1, test gen go; bit1 = 1, test gen stop */ +#define VFE_TEST_GEN_GO 0x00000001 +#define VFE_TEST_GEN_STOP 0x00000002 + +/* the chroma is assumed to be interpolated between + * the luma samples. JPEG 4:2:2 */ +#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0 + +/* constants for irq registers */ +#define VFE_DISABLE_ALL_IRQS 0 +/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS. */ +#define VFE_CLEAR_ALL_IRQS 0xffffffff +/* imask for while waiting for stop ack, driver has already + * requested stop, waiting for reset irq, + * bit 29,28,27,26 for async timer, bit 9 for reset */ +#define VFE_IMASK_WHILE_STOPPING 0x3c000200 + +/* when normal case, don't want to block error status. + * bit 0,6,20,21,22,30,31 */ +#define VFE_IMASK_ERROR_ONLY 0xC0700041 +#define VFE_REG_UPDATE_TRIGGER 1 +#define VFE_PM_BUF_MAX_CNT_MASK 0xFF +#define VFE_DMI_CFG_DEFAULT 0x00000100 +#define LENS_ROLL_OFF_DELTA_TABLE_OFFSET 32 +#define VFE_AF_PINGPONG_STATUS_BIT 0x100 +#define VFE_AWB_PINGPONG_STATUS_BIT 0x200 + +/* VFE I/O registers */ +enum { + VFE_HW_VERSION = 0x00000000, + VFE_GLOBAL_RESET_CMD = 0x00000004, + VFE_MODULE_RESET = 0x00000008, + VFE_CGC_OVERRIDE = 0x0000000C, + VFE_MODULE_CFG = 0x00000010, + VFE_CFG = 0x00000014, + VFE_IRQ_MASK = 0x00000018, + VFE_IRQ_CLEAR = 0x0000001C, +VFE_IRQ_STATUS = 0x00000020, +VFE_IRQ_COMPOSITE_MASK = 0x00000024, +VFE_BUS_CMD = 0x00000028, +VFE_BUS_CFG = 0x0000002C, +VFE_BUS_ENC_Y_WR_PING_ADDR = 0x00000030, +VFE_BUS_ENC_Y_WR_PONG_ADDR = 0x00000034, +VFE_BUS_ENC_Y_WR_IMAGE_SIZE = 0x00000038, +VFE_BUS_ENC_Y_WR_BUFFER_CFG = 0x0000003C, +VFE_BUS_ENC_CBCR_WR_PING_ADDR = 0x00000040, +VFE_BUS_ENC_CBCR_WR_PONG_ADDR = 0x00000044, +VFE_BUS_ENC_CBCR_WR_IMAGE_SIZE = 0x00000048, +VFE_BUS_ENC_CBCR_WR_BUFFER_CFG = 0x0000004C, +VFE_BUS_VIEW_Y_WR_PING_ADDR = 0x00000050, +VFE_BUS_VIEW_Y_WR_PONG_ADDR = 0x00000054, +VFE_BUS_VIEW_Y_WR_IMAGE_SIZE = 0x00000058, +VFE_BUS_VIEW_Y_WR_BUFFER_CFG = 0x0000005C, +VFE_BUS_VIEW_CBCR_WR_PING_ADDR = 0x00000060, +VFE_BUS_VIEW_CBCR_WR_PONG_ADDR = 0x00000064, +VFE_BUS_VIEW_CBCR_WR_IMAGE_SIZE = 0x00000068, +VFE_BUS_VIEW_CBCR_WR_BUFFER_CFG = 0x0000006C, +VFE_BUS_STATS_AF_WR_PING_ADDR = 0x00000070, +VFE_BUS_STATS_AF_WR_PONG_ADDR = 0x00000074, +VFE_BUS_STATS_AWB_WR_PING_ADDR = 0x00000078, +VFE_BUS_STATS_AWB_WR_PONG_ADDR = 0x0000007C, +VFE_BUS_STATS_HIST_WR_PING_ADDR = 0x00000080, +VFE_BUS_STATS_HIST_WR_PONG_ADDR = 0x00000084, +VFE_BUS_STATS_WR_PRIORITY = 0x00000088, +VFE_BUS_STRIPE_RD_ADDR_0 = 0x0000008C, +VFE_BUS_STRIPE_RD_ADDR_1 = 0x00000090, +VFE_BUS_STRIPE_RD_ADDR_2 = 0x00000094, +VFE_BUS_STRIPE_RD_ADDR_3 = 0x00000098, +VFE_BUS_STRIPE_RD_VSIZE = 0x0000009C, +VFE_BUS_STRIPE_RD_HSIZE = 0x000000A0, +VFE_BUS_STRIPE_RD_BUFFER_CFG = 0x000000A4, +VFE_BUS_STRIPE_RD_UNPACK_CFG = 0x000000A8, +VFE_BUS_STRIPE_RD_UNPACK = 0x000000AC, +VFE_BUS_STRIPE_RD_PAD_SIZE = 0x000000B0, +VFE_BUS_STRIPE_RD_PAD_L_UNPACK = 0x000000B4, +VFE_BUS_STRIPE_RD_PAD_R_UNPACK = 0x000000B8, +VFE_BUS_STRIPE_RD_PAD_TB_UNPACK = 0x000000BC, +VFE_BUS_PINGPONG_IRQ_EN = 0x000000C0, +VFE_BUS_PINGPONG_STATUS = 0x000000C4, +VFE_BUS_PM_CMD = 0x000000C8, +VFE_BUS_PM_CFG = 0x000000CC, +VFE_BUS_ENC_Y_WR_PM_STATS_0 = 0x000000D0, +VFE_BUS_ENC_Y_WR_PM_STATS_1 = 0x000000D4, +VFE_BUS_ENC_CBCR_WR_PM_STATS_0 = 0x000000D8, +VFE_BUS_ENC_CBCR_WR_PM_STATS_1 = 0x000000DC, +VFE_BUS_VIEW_Y_WR_PM_STATS_0 = 0x000000E0, +VFE_BUS_VIEW_Y_WR_PM_STATS_1 = 0x000000E4, +VFE_BUS_VIEW_CBCR_WR_PM_STATS_0 = 0x000000E8, +VFE_BUS_VIEW_CBCR_WR_PM_STATS_1 = 0x000000EC, +VFE_BUS_MISR_CFG = 0x000000F4, +VFE_BUS_MISR_MAST_CFG_0 = 0x000000F8, +VFE_BUS_MISR_MAST_CFG_1 = 0x000000FC, +VFE_BUS_MISR_RD_VAL = 0x00000100, +VFE_AXI_CMD = 0x00000104, +VFE_AXI_CFG = 0x00000108, +VFE_AXI_STATUS = 0x0000010C, +CAMIF_COMMAND = 0x00000110, +CAMIF_CONFIG = 0x00000114, +CAMIF_EFS_CONFIG = 0x00000118, +CAMIF_FRAME_CONFIG = 0x0000011C, +CAMIF_WINDOW_WIDTH_CONFIG = 0x00000120, +CAMIF_WINDOW_HEIGHT_CONFIG = 0x00000124, +CAMIF_SUBSAMPLE1_CONFIG = 0x00000128, +CAMIF_SUBSAMPLE2_CONFIG = 0x0000012C, +CAMIF_EPOCH_IRQ = 0x00000130, +CAMIF_STATUS = 0x00000134, +CAMIF_MISR = 0x00000138, +VFE_SYNC_TIMER_CMD = 0x0000013C, +VFE_SYNC_TIMER0_LINE_START = 0x00000140, +VFE_SYNC_TIMER0_PIXEL_START = 0x00000144, +VFE_SYNC_TIMER0_PIXEL_DURATION = 0x00000148, +VFE_SYNC_TIMER1_LINE_START = 0x0000014C, +VFE_SYNC_TIMER1_PIXEL_START = 0x00000150, +VFE_SYNC_TIMER1_PIXEL_DURATION = 0x00000154, +VFE_SYNC_TIMER2_LINE_START = 0x00000158, +VFE_SYNC_TIMER2_PIXEL_START = 0x0000015C, +VFE_SYNC_TIMER2_PIXEL_DURATION = 0x00000160, +VFE_SYNC_TIMER_POLARITY = 0x00000164, +VFE_ASYNC_TIMER_CMD = 0x00000168, +VFE_ASYNC_TIMER0_CFG_0 = 0x0000016C, +VFE_ASYNC_TIMER0_CFG_1 = 0x00000170, +VFE_ASYNC_TIMER1_CFG_0 = 0x00000174, +VFE_ASYNC_TIMER1_CFG_1 = 0x00000178, +VFE_ASYNC_TIMER2_CFG_0 = 0x0000017C, +VFE_ASYNC_TIMER2_CFG_1 = 0x00000180, +VFE_ASYNC_TIMER3_CFG_0 = 0x00000184, +VFE_ASYNC_TIMER3_CFG_1 = 0x00000188, +VFE_TIMER_SEL = 0x0000018C, +VFE_REG_UPDATE_CMD = 0x00000190, +VFE_BLACK_EVEN_EVEN_VALUE = 0x00000194, +VFE_BLACK_EVEN_ODD_VALUE = 0x00000198, +VFE_BLACK_ODD_EVEN_VALUE = 0x0000019C, +VFE_BLACK_ODD_ODD_VALUE = 0x000001A0, +VFE_ROLLOFF_CFG_0 = 0x000001A4, +VFE_ROLLOFF_CFG_1 = 0x000001A8, +VFE_ROLLOFF_CFG_2 = 0x000001AC, +VFE_DEMUX_CFG = 0x000001B0, +VFE_DEMUX_GAIN_0 = 0x000001B4, +VFE_DEMUX_GAIN_1 = 0x000001B8, +VFE_DEMUX_EVEN_CFG = 0x000001BC, +VFE_DEMUX_ODD_CFG = 0x000001C0, +VFE_DEMOSAIC_CFG = 0x000001C4, +VFE_DEMOSAIC_ABF_CFG_0 = 0x000001C8, +VFE_DEMOSAIC_ABF_CFG_1 = 0x000001CC, +VFE_DEMOSAIC_BPC_CFG_0 = 0x000001D0, +VFE_DEMOSAIC_BPC_CFG_1 = 0x000001D4, +VFE_DEMOSAIC_STATUS = 0x000001D8, +VFE_CHROMA_UPSAMPLE_CFG = 0x000001DC, +VFE_CROP_WIDTH_CFG = 0x000001E0, +VFE_CROP_HEIGHT_CFG = 0x000001E4, +VFE_COLOR_CORRECT_COEFF_0 = 0x000001E8, +VFE_COLOR_CORRECT_COEFF_1 = 0x000001EC, +VFE_COLOR_CORRECT_COEFF_2 = 0x000001F0, +VFE_COLOR_CORRECT_COEFF_3 = 0x000001F4, +VFE_COLOR_CORRECT_COEFF_4 = 0x000001F8, +VFE_COLOR_CORRECT_COEFF_5 = 0x000001FC, +VFE_COLOR_CORRECT_COEFF_6 = 0x00000200, +VFE_COLOR_CORRECT_COEFF_7 = 0x00000204, +VFE_COLOR_CORRECT_COEFF_8 = 0x00000208, +VFE_COLOR_CORRECT_OFFSET_0 = 0x0000020C, +VFE_COLOR_CORRECT_OFFSET_1 = 0x00000210, +VFE_COLOR_CORRECT_OFFSET_2 = 0x00000214, +VFE_COLOR_CORRECT_COEFF_Q = 0x00000218, +VFE_LA_CFG = 0x0000021C, +VFE_LUT_BANK_SEL = 0x00000220, +VFE_CHROMA_ENHAN_A = 0x00000224, +VFE_CHROMA_ENHAN_B = 0x00000228, +VFE_CHROMA_ENHAN_C = 0x0000022C, +VFE_CHROMA_ENHAN_D = 0x00000230, +VFE_CHROMA_ENHAN_K = 0x00000234, +VFE_COLOR_CONVERT_COEFF_0 = 0x00000238, +VFE_COLOR_CONVERT_COEFF_1 = 0x0000023C, +VFE_COLOR_CONVERT_COEFF_2 = 0x00000240, +VFE_COLOR_CONVERT_OFFSET = 0x00000244, +VFE_ASF_CFG = 0x00000248, +VFE_ASF_SHARP_CFG_0 = 0x0000024C, +VFE_ASF_SHARP_CFG_1 = 0x00000250, +VFE_ASF_SHARP_COEFF_0 = 0x00000254, +VFE_ASF_SHARP_COEFF_1 = 0x00000258, +VFE_ASF_SHARP_COEFF_2 = 0x0000025C, +VFE_ASF_SHARP_COEFF_3 = 0x00000260, +VFE_ASF_MAX_EDGE = 0x00000264, +VFE_ASF_CROP_WIDTH_CFG = 0x00000268, +VFE_ASF_CROP_HEIGHT_CFG = 0x0000026C, +VFE_SCALE_CFG = 0x00000270, +VFE_SCALE_H_IMAGE_SIZE_CFG = 0x00000274, +VFE_SCALE_H_PHASE_CFG = 0x00000278, +VFE_SCALE_H_STRIPE_CFG = 0x0000027C, +VFE_SCALE_V_IMAGE_SIZE_CFG = 0x00000280, +VFE_SCALE_V_PHASE_CFG = 0x00000284, +VFE_SCALE_V_STRIPE_CFG = 0x00000288, +VFE_SCALE_Y_CFG = 0x0000028C, +VFE_SCALE_Y_H_IMAGE_SIZE_CFG = 0x00000290, +VFE_SCALE_Y_H_PHASE_CFG = 0x00000294, +VFE_SCALE_Y_V_IMAGE_SIZE_CFG = 0x00000298, +VFE_SCALE_Y_V_PHASE_CFG = 0x0000029C, +VFE_SCALE_CBCR_CFG = 0x000002A0, +VFE_SCALE_CBCR_H_IMAGE_SIZE_CFG = 0x000002A4, +VFE_SCALE_CBCR_H_PHASE_CFG = 0x000002A8, +VFE_SCALE_CBCR_V_IMAGE_SIZE_CFG = 0x000002AC, +VFE_SCALE_CBCR_V_PHASE_CFG = 0x000002B0, +VFE_WB_CFG = 0x000002B4, +VFE_CHROMA_SUPPRESS_CFG_0 = 0x000002B8, +VFE_CHROMA_SUPPRESS_CFG_1 = 0x000002BC, +VFE_CHROMA_SUBSAMPLE_CFG = 0x000002C0, +VFE_CHROMA_SUB_CROP_WIDTH_CFG = 0x000002C4, +VFE_CHROMA_SUB_CROP_HEIGHT_CFG = 0x000002C8, +VFE_FRAMEDROP_ENC_Y_CFG = 0x000002CC, +VFE_FRAMEDROP_ENC_CBCR_CFG = 0x000002D0, +VFE_FRAMEDROP_ENC_Y_PATTERN = 0x000002D4, +VFE_FRAMEDROP_ENC_CBCR_PATTERN = 0x000002D8, +VFE_FRAMEDROP_VIEW_Y_CFG = 0x000002DC, +VFE_FRAMEDROP_VIEW_CBCR_CFG = 0x000002E0, +VFE_FRAMEDROP_VIEW_Y_PATTERN = 0x000002E4, +VFE_FRAMEDROP_VIEW_CBCR_PATTERN = 0x000002E8, +VFE_CLAMP_MAX_CFG = 0x000002EC, +VFE_CLAMP_MIN_CFG = 0x000002F0, +VFE_STATS_CMD = 0x000002F4, +VFE_STATS_AF_CFG = 0x000002F8, +VFE_STATS_AF_DIM = 0x000002FC, +VFE_STATS_AF_GRID_0 = 0x00000300, +VFE_STATS_AF_GRID_1 = 0x00000304, +VFE_STATS_AF_GRID_2 = 0x00000308, +VFE_STATS_AF_GRID_3 = 0x0000030C, +VFE_STATS_AF_HEADER = 0x00000310, +VFE_STATS_AF_COEF0 = 0x00000314, +VFE_STATS_AF_COEF1 = 0x00000318, +VFE_STATS_AWBAE_CFG = 0x0000031C, +VFE_STATS_AXW_HEADER = 0x00000320, +VFE_STATS_AWB_MCFG = 0x00000324, +VFE_STATS_AWB_CCFG1 = 0x00000328, +VFE_STATS_AWB_CCFG2 = 0x0000032C, +VFE_STATS_HIST_HEADER = 0x00000330, +VFE_STATS_HIST_INNER_OFFSET = 0x00000334, +VFE_STATS_HIST_INNER_DIM = 0x00000338, +VFE_STATS_FRAME_SIZE = 0x0000033C, +VFE_DMI_CFG = 0x00000340, +VFE_DMI_ADDR = 0x00000344, +VFE_DMI_DATA_HI = 0x00000348, +VFE_DMI_DATA_LO = 0x0000034C, +VFE_DMI_RAM_AUTO_LOAD_CMD = 0x00000350, +VFE_DMI_RAM_AUTO_LOAD_STATUS = 0x00000354, +VFE_DMI_RAM_AUTO_LOAD_CFG = 0x00000358, +VFE_DMI_RAM_AUTO_LOAD_SEED = 0x0000035C, +VFE_TESTBUS_SEL = 0x00000360, +VFE_TESTGEN_CFG = 0x00000364, +VFE_SW_TESTGEN_CMD = 0x00000368, +VFE_HW_TESTGEN_CMD = 0x0000036C, +VFE_HW_TESTGEN_CFG = 0x00000370, +VFE_HW_TESTGEN_IMAGE_CFG = 0x00000374, +VFE_HW_TESTGEN_SOF_OFFSET_CFG = 0x00000378, +VFE_HW_TESTGEN_EOF_NOFFSET_CFG = 0x0000037C, +VFE_HW_TESTGEN_SOL_OFFSET_CFG = 0x00000380, +VFE_HW_TESTGEN_EOL_NOFFSET_CFG = 0x00000384, +VFE_HW_TESTGEN_HBI_CFG = 0x00000388, +VFE_HW_TESTGEN_VBL_CFG = 0x0000038C, +VFE_HW_TESTGEN_SOF_DUMMY_LINE_CFG2 = 0x00000390, +VFE_HW_TESTGEN_EOF_DUMMY_LINE_CFG2 = 0x00000394, +VFE_HW_TESTGEN_COLOR_BARS_CFG = 0x00000398, +VFE_HW_TESTGEN_RANDOM_CFG = 0x0000039C, +VFE_SPARE = 0x000003A0, +}; + +#define ping 0x0 +#define pong 0x1 + +struct vfe_bus_cfg_data { + boolean stripeRdPathEn; + boolean encYWrPathEn; + boolean encCbcrWrPathEn; + boolean viewYWrPathEn; + boolean viewCbcrWrPathEn; + enum VFE_RAW_PIXEL_DATA_SIZE rawPixelDataSize; + enum VFE_RAW_WR_PATH_SEL rawWritePathSelect; +}; + +struct vfe_camif_cfg_data { + boolean camif2OutputEnable; + boolean camif2BusEnable; + struct vfe_cmds_camif_cfg camifCfgFromCmd; +}; + +struct vfe_irq_composite_mask_config { + uint8_t encIrqComMask; + uint8_t viewIrqComMask; + uint8_t ceDoneSel; +}; + +/* define a structure for each output path.*/ +struct vfe_output_path { + uint32_t addressBuffer[8]; + uint16_t fragIndex; + boolean hwCurrentFlag; + uint8_t *hwRegPingAddress; + uint8_t *hwRegPongAddress; +}; + +struct vfe_output_path_combo { + boolean whichOutputPath; + boolean pathEnabled; + boolean multiFrag; + uint8_t fragCount; + boolean ackPending; + uint8_t currentFrame; + uint32_t nextFrameAddrBuf[8]; + struct vfe_output_path yPath; + struct vfe_output_path cbcrPath; + uint8_t snapshotPendingCount; + boolean pmEnabled; + uint8_t cbcrStatusBit; +}; + +struct vfe_stats_control { + boolean ackPending; + uint32_t addressBuffer[2]; + uint32_t nextFrameAddrBuf; + boolean pingPongStatus; + uint8_t *hwRegPingAddress; + uint8_t *hwRegPongAddress; + uint32_t droppedStatsFrameCount; + uint32_t bufToRender; +}; + +struct vfe_gamma_lut_sel { + boolean ch0BankSelect; + boolean ch1BankSelect; + boolean ch2BankSelect; +}; + +struct vfe_interrupt_mask { + boolean camifErrorIrq; + boolean camifSofIrq; + boolean camifEolIrq; + boolean camifEofIrq; + boolean camifEpoch1Irq; + boolean camifEpoch2Irq; + boolean camifOverflowIrq; + boolean ceIrq; + boolean regUpdateIrq; + boolean resetAckIrq; + boolean encYPingpongIrq; + boolean encCbcrPingpongIrq; + boolean viewYPingpongIrq; + boolean viewCbcrPingpongIrq; + boolean rdPingpongIrq; + boolean afPingpongIrq; + boolean awbPingpongIrq; + boolean histPingpongIrq; + boolean encIrq; + boolean viewIrq; + boolean busOverflowIrq; + boolean afOverflowIrq; + boolean awbOverflowIrq; + boolean syncTimer0Irq; + boolean syncTimer1Irq; + boolean syncTimer2Irq; + boolean asyncTimer0Irq; + boolean asyncTimer1Irq; + boolean asyncTimer2Irq; + boolean asyncTimer3Irq; + boolean axiErrorIrq; + boolean violationIrq; +}; + +enum vfe_interrupt_name { + CAMIF_ERROR_IRQ, + CAMIF_SOF_IRQ, + CAMIF_EOL_IRQ, + CAMIF_EOF_IRQ, + CAMIF_EPOCH1_IRQ, + CAMIF_EPOCH2_IRQ, + CAMIF_OVERFLOW_IRQ, + CE_IRQ, + REG_UPDATE_IRQ, + RESET_ACK_IRQ, + ENC_Y_PINGPONG_IRQ, + ENC_CBCR_PINGPONG_IRQ, + VIEW_Y_PINGPONG_IRQ, + VIEW_CBCR_PINGPONG_IRQ, + RD_PINGPONG_IRQ, + AF_PINGPONG_IRQ, + AWB_PINGPONG_IRQ, + HIST_PINGPONG_IRQ, + ENC_IRQ, + VIEW_IRQ, + BUS_OVERFLOW_IRQ, + AF_OVERFLOW_IRQ, + AWB_OVERFLOW_IRQ, + SYNC_TIMER0_IRQ, + SYNC_TIMER1_IRQ, + SYNC_TIMER2_IRQ, + ASYNC_TIMER0_IRQ, + ASYNC_TIMER1_IRQ, + ASYNC_TIMER2_IRQ, + ASYNC_TIMER3_IRQ, + AXI_ERROR_IRQ, + VIOLATION_IRQ +}; + +enum VFE_DMI_RAM_SEL { + NO_MEM_SELECTED = 0, + ROLLOFF_RAM = 0x1, + RGBLUT_RAM_CH0_BANK0 = 0x2, + RGBLUT_RAM_CH0_BANK1 = 0x3, + RGBLUT_RAM_CH1_BANK0 = 0x4, + RGBLUT_RAM_CH1_BANK1 = 0x5, + RGBLUT_RAM_CH2_BANK0 = 0x6, + RGBLUT_RAM_CH2_BANK1 = 0x7, + STATS_HIST_CB_EVEN_RAM = 0x8, + STATS_HIST_CB_ODD_RAM = 0x9, + STATS_HIST_CR_EVEN_RAM = 0xa, + STATS_HIST_CR_ODD_RAM = 0xb, + RGBLUT_CHX_BANK0 = 0xc, + RGBLUT_CHX_BANK1 = 0xd, + LUMA_ADAPT_LUT_RAM_BANK0 = 0xe, + LUMA_ADAPT_LUT_RAM_BANK1 = 0xf +}; + +struct vfe_module_enable { + boolean blackLevelCorrectionEnable; + boolean lensRollOffEnable; + boolean demuxEnable; + boolean chromaUpsampleEnable; + boolean demosaicEnable; + boolean statsEnable; + boolean cropEnable; + boolean mainScalerEnable; + boolean whiteBalanceEnable; + boolean colorCorrectionEnable; + boolean yHistEnable; + boolean skinToneEnable; + boolean lumaAdaptationEnable; + boolean rgbLUTEnable; + boolean chromaEnhanEnable; + boolean asfEnable; + boolean chromaSuppressionEnable; + boolean chromaSubsampleEnable; + boolean scaler2YEnable; + boolean scaler2CbcrEnable; +}; + +struct vfe_bus_cmd_data { + boolean stripeReload; + boolean busPingpongReload; + boolean statsPingpongReload; +}; + +struct vfe_stats_cmd_data { + boolean autoFocusEnable; + boolean axwEnable; + boolean histEnable; + boolean clearHistEnable; + boolean histAutoClearEnable; + boolean colorConversionEnable; +}; + +struct vfe_hw_ver { + uint32_t minorVersion:8; + uint32_t majorVersion:8; + uint32_t coreVersion:4; + uint32_t /* reserved */ : 12; +} __attribute__((packed, aligned(4))); + +struct vfe_cfg { + uint32_t pixelPattern:3; + uint32_t /* reserved */ : 13; + uint32_t inputSource:2; + uint32_t /* reserved */ : 14; +} __attribute__((packed, aligned(4))); + +struct vfe_buscmd { + uint32_t stripeReload:1; + uint32_t /* reserved */ : 3; + uint32_t busPingpongReload:1; + uint32_t statsPingpongReload:1; + uint32_t /* reserved */ : 26; +} __attribute__((packed, aligned(4))); + +struct VFE_Irq_Composite_MaskType { + uint32_t encIrqComMaskBits:2; + uint32_t viewIrqComMaskBits:2; + uint32_t ceDoneSelBits:5; + uint32_t /* reserved */ : 23; +} __attribute__((packed, aligned(4))); + +struct vfe_mod_enable { + uint32_t blackLevelCorrectionEnable:1; + uint32_t lensRollOffEnable:1; + uint32_t demuxEnable:1; + uint32_t chromaUpsampleEnable:1; + uint32_t demosaicEnable:1; + uint32_t statsEnable:1; + uint32_t cropEnable:1; + uint32_t mainScalerEnable:1; + uint32_t whiteBalanceEnable:1; + uint32_t colorCorrectionEnable:1; + uint32_t yHistEnable:1; + uint32_t skinToneEnable:1; + uint32_t lumaAdaptationEnable:1; + uint32_t rgbLUTEnable:1; + uint32_t chromaEnhanEnable:1; + uint32_t asfEnable:1; + uint32_t chromaSuppressionEnable:1; + uint32_t chromaSubsampleEnable:1; + uint32_t scaler2YEnable:1; + uint32_t scaler2CbcrEnable:1; + uint32_t /* reserved */ : 14; +} __attribute__((packed, aligned(4))); + +struct vfe_irqenable { + uint32_t camifErrorIrq:1; + uint32_t camifSofIrq:1; + uint32_t camifEolIrq:1; + uint32_t camifEofIrq:1; + uint32_t camifEpoch1Irq:1; + uint32_t camifEpoch2Irq:1; + uint32_t camifOverflowIrq:1; + uint32_t ceIrq:1; + uint32_t regUpdateIrq:1; + uint32_t resetAckIrq:1; + uint32_t encYPingpongIrq:1; + uint32_t encCbcrPingpongIrq:1; + uint32_t viewYPingpongIrq:1; + uint32_t viewCbcrPingpongIrq:1; + uint32_t rdPingpongIrq:1; + uint32_t afPingpongIrq:1; + uint32_t awbPingpongIrq:1; + uint32_t histPingpongIrq:1; + uint32_t encIrq:1; + uint32_t viewIrq:1; + uint32_t busOverflowIrq:1; + uint32_t afOverflowIrq:1; + uint32_t awbOverflowIrq:1; + uint32_t syncTimer0Irq:1; + uint32_t syncTimer1Irq:1; + uint32_t syncTimer2Irq:1; + uint32_t asyncTimer0Irq:1; + uint32_t asyncTimer1Irq:1; + uint32_t asyncTimer2Irq:1; + uint32_t asyncTimer3Irq:1; + uint32_t axiErrorIrq:1; + uint32_t violationIrq:1; +} __attribute__((packed, aligned(4))); + +struct vfe_upsample_cfg { + uint32_t chromaCositingForYCbCrInputs:1; + uint32_t /* reserved */ : 31; +} __attribute__((packed, aligned(4))); + +struct VFE_CAMIFConfigType { + /* CAMIF Config */ + uint32_t /* reserved */ : 1; + uint32_t VSyncEdge:1; + uint32_t HSyncEdge:1; + uint32_t syncMode:2; + uint32_t vfeSubsampleEnable:1; + uint32_t /* reserved */ : 1; + uint32_t busSubsampleEnable:1; + uint32_t camif2vfeEnable:1; + uint32_t /* reserved */ : 1; + uint32_t camif2busEnable:1; + uint32_t irqSubsampleEnable:1; + uint32_t binningEnable:1; + uint32_t /* reserved */ : 18; + uint32_t misrEnable:1; +} __attribute__((packed, aligned(4))); + +struct vfe_camifcfg { + /* EFS_Config */ + uint32_t efsEndOfLine:8; + uint32_t efsStartOfLine:8; + uint32_t efsEndOfFrame:8; + uint32_t efsStartOfFrame:8; + /* Frame Config */ + uint32_t frameConfigPixelsPerLine:14; + uint32_t /* reserved */ : 2; + uint32_t frameConfigLinesPerFrame:14; + uint32_t /* reserved */ : 2; + /* Window Width Config */ + uint32_t windowWidthCfgLastPixel:14; + uint32_t /* reserved */ : 2; + uint32_t windowWidthCfgFirstPixel:14; + uint32_t /* reserved */ : 2; + /* Window Height Config */ + uint32_t windowHeightCfglastLine:14; + uint32_t /* reserved */ : 2; + uint32_t windowHeightCfgfirstLine:14; + uint32_t /* reserved */ : 2; + /* Subsample 1 Config */ + uint32_t subsample1CfgPixelSkip:16; + uint32_t subsample1CfgLineSkip:16; + /* Subsample 2 Config */ + uint32_t subsample2CfgFrameSkip:4; + uint32_t subsample2CfgFrameSkipMode:1; + uint32_t subsample2CfgPixelSkipWrap:1; + uint32_t /* reserved */ : 26; + /* Epoch Interrupt */ + uint32_t epoch1Line:14; + uint32_t /* reserved */ : 2; + uint32_t epoch2Line:14; + uint32_t /* reserved */ : 2; +} __attribute__((packed, aligned(4))); + +struct vfe_camifframe_update { + uint32_t pixelsPerLine:14; + uint32_t /* reserved */ : 2; + uint32_t linesPerFrame:14; + uint32_t /* reserved */ : 2; +} __attribute__((packed, aligned(4))); + +struct vfe_axi_bus_cfg { + uint32_t stripeRdPathEn:1; + uint32_t /* reserved */ : 3; + uint32_t encYWrPathEn:1; + uint32_t encCbcrWrPathEn:1; + uint32_t viewYWrPathEn:1; + uint32_t viewCbcrWrPathEn:1; + uint32_t rawPixelDataSize:2; + uint32_t rawWritePathSelect:2; + uint32_t /* reserved */ : 20; +} __attribute__((packed, aligned(4))); + +struct vfe_axi_out_cfg { + uint32_t out2YPingAddr:32; + uint32_t out2YPongAddr:32; + uint32_t out2YImageHeight:12; + uint32_t /* reserved */ : 4; + uint32_t out2YImageWidthin64bit:10; + uint32_t /* reserved */ : 6; + uint32_t out2YBurstLength:2; + uint32_t /* reserved */ : 2; + uint32_t out2YNumRows:12; + uint32_t out2YRowIncrementIn64bit:12; + uint32_t /* reserved */ : 4; + uint32_t out2CbcrPingAddr:32; + uint32_t out2CbcrPongAddr:32; + uint32_t out2CbcrImageHeight:12; + uint32_t /* reserved */ : 4; + uint32_t out2CbcrImageWidthIn64bit:10; + uint32_t /* reserved */ : 6; + uint32_t out2CbcrBurstLength:2; + uint32_t /* reserved */ : 2; + uint32_t out2CbcrNumRows:12; + uint32_t out2CbcrRowIncrementIn64bit:12; + uint32_t /* reserved */ : 4; + uint32_t out1YPingAddr:32; + uint32_t out1YPongAddr:32; + uint32_t out1YImageHeight:12; + uint32_t /* reserved */ : 4; + uint32_t out1YImageWidthin64bit:10; + uint32_t /* reserved */ : 6; + uint32_t out1YBurstLength:2; + uint32_t /* reserved */ : 2; + uint32_t out1YNumRows:12; + uint32_t out1YRowIncrementIn64bit:12; + uint32_t /* reserved */ : 4; + uint32_t out1CbcrPingAddr:32; + uint32_t out1CbcrPongAddr:32; + uint32_t out1CbcrImageHeight:12; + uint32_t /* reserved */ : 4; + uint32_t out1CbcrImageWidthIn64bit:10; + uint32_t /* reserved */ : 6; + uint32_t out1CbcrBurstLength:2; + uint32_t /* reserved */ : 2; + uint32_t out1CbcrNumRows:12; + uint32_t out1CbcrRowIncrementIn64bit:12; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct vfe_output_clamp_cfg { + /* Output Clamp Maximums */ + uint32_t yChanMax:8; + uint32_t cbChanMax:8; + uint32_t crChanMax:8; + uint32_t /* reserved */ : 8; + /* Output Clamp Minimums */ + uint32_t yChanMin:8; + uint32_t cbChanMin:8; + uint32_t crChanMin:8; + uint32_t /* reserved */ : 8; +} __attribute__((packed, aligned(4))); + +struct vfe_fov_crop_cfg { + uint32_t lastPixel:12; + uint32_t /* reserved */ : 4; + uint32_t firstPixel:12; + uint32_t /* reserved */ : 4; + + /* FOV Corp, Part 2 */ + uint32_t lastLine:12; + uint32_t /* reserved */ : 4; + uint32_t firstLine:12; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct VFE_FRAME_SKIP_UpdateCmdType { + uint32_t yPattern:32; + uint32_t cbcrPattern:32; +} __attribute__((packed, aligned(4))); + +struct vfe_frame_skip_cfg { + /* Frame Drop Enc (output2) */ + uint32_t output2YPeriod:5; + uint32_t /* reserved */ : 27; + uint32_t output2CbCrPeriod:5; + uint32_t /* reserved */ : 27; + uint32_t output2YPattern:32; + uint32_t output2CbCrPattern:32; + /* Frame Drop View (output1) */ + uint32_t output1YPeriod:5; + uint32_t /* reserved */ : 27; + uint32_t output1CbCrPeriod:5; + uint32_t /* reserved */ : 27; + uint32_t output1YPattern:32; + uint32_t output1CbCrPattern:32; +} __attribute__((packed, aligned(4))); + +struct vfe_main_scaler_cfg { + /* Scaler Enable Config */ + uint32_t hEnable:1; + uint32_t vEnable:1; + uint32_t /* reserved */ : 30; + /* Scale H Image Size Config */ + uint32_t inWidth:12; + uint32_t /* reserved */ : 4; + uint32_t outWidth:12; + uint32_t /* reserved */ : 4; + /* Scale H Phase Config */ + uint32_t horizPhaseMult:18; + uint32_t /* reserved */ : 2; + uint32_t horizInterResolution:2; + uint32_t /* reserved */ : 10; + /* Scale H Stripe Config */ + uint32_t horizMNInit:12; + uint32_t /* reserved */ : 4; + uint32_t horizPhaseInit:15; + uint32_t /* reserved */ : 1; + /* Scale V Image Size Config */ + uint32_t inHeight:12; + uint32_t /* reserved */ : 4; + uint32_t outHeight:12; + uint32_t /* reserved */ : 4; + /* Scale V Phase Config */ + uint32_t vertPhaseMult:18; + uint32_t /* reserved */ : 2; + uint32_t vertInterResolution:2; + uint32_t /* reserved */ : 10; + /* Scale V Stripe Config */ + uint32_t vertMNInit:12; + uint32_t /* reserved */ : 4; + uint32_t vertPhaseInit:15; + uint32_t /* reserved */ : 1; +} __attribute__((packed, aligned(4))); + +struct vfe_scaler2_cfg { + /* Scaler Enable Config */ + uint32_t hEnable:1; + uint32_t vEnable:1; + uint32_t /* reserved */ : 30; + /* Scaler H Image Size Config */ + uint32_t inWidth:12; + uint32_t /* reserved */ : 4; + uint32_t outWidth:12; + uint32_t /* reserved */ : 4; + /* Scaler H Phase Config */ + uint32_t horizPhaseMult:18; + uint32_t /* reserved */ : 2; + uint32_t horizInterResolution:2; + uint32_t /* reserved */ : 10; + /* Scaler V Image Size Config */ + uint32_t inHeight:12; + uint32_t /* reserved */ : 4; + uint32_t outHeight:12; + uint32_t /* reserved */ : 4; + /* Scaler V Phase Config */ + uint32_t vertPhaseMult:18; + uint32_t /* reserved */ : 2; + uint32_t vertInterResolution:2; + uint32_t /* reserved */ : 10; +} __attribute__((packed, aligned(4))); + +struct vfe_rolloff_cfg { + /* Rolloff 0 Config */ + uint32_t gridWidth:9; + uint32_t gridHeight:9; + uint32_t yDelta:9; + uint32_t /* reserved */ : 5; + /* Rolloff 1 Config*/ + uint32_t gridX:4; + uint32_t gridY:4; + uint32_t pixelX:9; + uint32_t /* reserved */ : 3; + uint32_t pixelY:9; + uint32_t /* reserved */ : 3; + /* Rolloff 2 Config */ + uint32_t yDeltaAccum:12; + uint32_t /* reserved */ : 20; +} __attribute__((packed, aligned(4))); + +struct vfe_asf_update { + /* ASF Config Command */ + uint32_t smoothEnable:1; + uint32_t sharpMode:2; + uint32_t /* reserved */ : 1; + uint32_t smoothCoeff1:4; + uint32_t smoothCoeff0:8; + uint32_t pipeFlushCount:12; + uint32_t pipeFlushOvd:1; + uint32_t flushHaltOvd:1; + uint32_t cropEnable:1; + uint32_t /* reserved */ : 1; + /* Sharpening Config 0 */ + uint32_t sharpThresholdE1:7; + uint32_t /* reserved */ : 1; + uint32_t sharpDegreeK1:5; + uint32_t /* reserved */ : 3; + uint32_t sharpDegreeK2:5; + uint32_t /* reserved */ : 3; + uint32_t normalizeFactor:7; + uint32_t /* reserved */ : 1; + /* Sharpening Config 1 */ + uint32_t sharpThresholdE2:8; + uint32_t sharpThresholdE3:8; + uint32_t sharpThresholdE4:8; + uint32_t sharpThresholdE5:8; + /* Sharpening Coefficients 0 */ + uint32_t F1Coeff0:6; + uint32_t F1Coeff1:6; + uint32_t F1Coeff2:6; + uint32_t F1Coeff3:6; + uint32_t F1Coeff4:6; + uint32_t /* reserved */ : 2; + /* Sharpening Coefficients 1 */ + uint32_t F1Coeff5:6; + uint32_t F1Coeff6:6; + uint32_t F1Coeff7:6; + uint32_t F1Coeff8:7; + uint32_t /* reserved */ : 7; + /* Sharpening Coefficients 2 */ + uint32_t F2Coeff0:6; + uint32_t F2Coeff1:6; + uint32_t F2Coeff2:6; + uint32_t F2Coeff3:6; + uint32_t F2Coeff4:6; + uint32_t /* reserved */ : 2; + /* Sharpening Coefficients 3 */ + uint32_t F2Coeff5:6; + uint32_t F2Coeff6:6; + uint32_t F2Coeff7:6; + uint32_t F2Coeff8:7; + uint32_t /* reserved */ : 7; +} __attribute__((packed, aligned(4))); + +struct vfe_asfcrop_cfg { + /* ASF Crop Width Config */ + uint32_t lastPixel:12; + uint32_t /* reserved */ : 4; + uint32_t firstPixel:12; + uint32_t /* reserved */ : 4; + /* ASP Crop Height Config */ + uint32_t lastLine:12; + uint32_t /* reserved */ : 4; + uint32_t firstLine:12; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct vfe_chroma_suppress_cfg { + /* Chroma Suppress 0 Config */ + uint32_t m1:8; + uint32_t m3:8; + uint32_t n1:3; + uint32_t /* reserved */ : 1; + uint32_t n3:3; + uint32_t /* reserved */ : 9; + /* Chroma Suppress 1 Config */ + uint32_t mm1:8; + uint32_t nn1:3; + uint32_t /* reserved */ : 21; +} __attribute__((packed, aligned(4))); + +struct vfe_chromasubsample_cfg { + /* Chroma Subsample Selection */ + uint32_t hCositedPhase:1; + uint32_t vCositedPhase:1; + uint32_t hCosited:1; + uint32_t vCosited:1; + uint32_t hsubSampleEnable:1; + uint32_t vsubSampleEnable:1; + uint32_t cropEnable:1; + uint32_t /* reserved */ : 25; + uint32_t cropWidthLastPixel:12; + uint32_t /* reserved */ : 4; + uint32_t cropWidthFirstPixel:12; + uint32_t /* reserved */ : 4; + uint32_t cropHeightLastLine:12; + uint32_t /* reserved */ : 4; + uint32_t cropHeightFirstLine:12; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct vfe_blacklevel_cfg { + /* Black Even-Even Value Config */ + uint32_t evenEvenAdjustment:9; + uint32_t /* reserved */ : 23; + /* Black Even-Odd Value Config */ + uint32_t evenOddAdjustment:9; + uint32_t /* reserved */ : 23; + /* Black Odd-Even Value Config */ + uint32_t oddEvenAdjustment:9; + uint32_t /* reserved */ : 23; + /* Black Odd-Odd Value Config */ + uint32_t oddOddAdjustment:9; + uint32_t /* reserved */ : 23; +} __attribute__((packed, aligned(4))); + +struct vfe_demux_cfg { + /* Demux Gain 0 Config */ + uint32_t ch0EvenGain:10; + uint32_t /* reserved */ : 6; + uint32_t ch0OddGain:10; + uint32_t /* reserved */ : 6; + /* Demux Gain 1 Config */ + uint32_t ch1Gain:10; + uint32_t /* reserved */ : 6; + uint32_t ch2Gain:10; + uint32_t /* reserved */ : 6; +} __attribute__((packed, aligned(4))); + +struct vfe_bps_info { + uint32_t greenBadPixelCount:8; + uint32_t /* reserved */ : 8; + uint32_t RedBlueBadPixelCount:8; + uint32_t /* reserved */ : 8; +} __attribute__((packed, aligned(4))); + +struct vfe_demosaic_cfg { + /* Demosaic Config */ + uint32_t abfEnable:1; + uint32_t badPixelCorrEnable:1; + uint32_t forceAbfOn:1; + uint32_t /* reserved */ : 1; + uint32_t abfShift:4; + uint32_t fminThreshold:7; + uint32_t /* reserved */ : 1; + uint32_t fmaxThreshold:7; + uint32_t /* reserved */ : 5; + uint32_t slopeShift:3; + uint32_t /* reserved */ : 1; +} __attribute__((packed, aligned(4))); + +struct vfe_demosaic_bpc_cfg { + /* Demosaic BPC Config 0 */ + uint32_t blueDiffThreshold:12; + uint32_t redDiffThreshold:12; + uint32_t /* reserved */ : 8; + /* Demosaic BPC Config 1 */ + uint32_t greenDiffThreshold:12; + uint32_t /* reserved */ : 20; +} __attribute__((packed, aligned(4))); + +struct vfe_demosaic_abf_cfg { + /* Demosaic ABF Config 0 */ + uint32_t lpThreshold:10; + uint32_t /* reserved */ : 22; + /* Demosaic ABF Config 1 */ + uint32_t ratio:4; + uint32_t minValue:10; + uint32_t /* reserved */ : 2; + uint32_t maxValue:10; + uint32_t /* reserved */ : 6; +} __attribute__((packed, aligned(4))); + +struct vfe_color_correction_cfg { + /* Color Corr. Coefficient 0 Config */ + uint32_t c0:12; + uint32_t /* reserved */ : 20; + /* Color Corr. Coefficient 1 Config */ + uint32_t c1:12; + uint32_t /* reserved */ : 20; + /* Color Corr. Coefficient 2 Config */ + uint32_t c2:12; + uint32_t /* reserved */ : 20; + /* Color Corr. Coefficient 3 Config */ + uint32_t c3:12; + uint32_t /* reserved */ : 20; + /* Color Corr. Coefficient 4 Config */ + uint32_t c4:12; + uint32_t /* reserved */ : 20; + /* Color Corr. Coefficient 5 Config */ + uint32_t c5:12; + uint32_t /* reserved */ : 20; + /* Color Corr. Coefficient 6 Config */ + uint32_t c6:12; + uint32_t /* reserved */ : 20; + /* Color Corr. Coefficient 7 Config */ + uint32_t c7:12; + uint32_t /* reserved */ : 20; + /* Color Corr. Coefficient 8 Config */ + uint32_t c8:12; + uint32_t /* reserved */ : 20; + /* Color Corr. Offset 0 Config */ + uint32_t k0:11; + uint32_t /* reserved */ : 21; + /* Color Corr. Offset 1 Config */ + uint32_t k1:11; + uint32_t /* reserved */ : 21; + /* Color Corr. Offset 2 Config */ + uint32_t k2:11; + uint32_t /* reserved */ : 21; + /* Color Corr. Coefficient Q Config */ + uint32_t coefQFactor:2; + uint32_t /* reserved */ : 30; +} __attribute__((packed, aligned(4))); + +struct VFE_LumaAdaptation_ConfigCmdType { + /* LA Config */ + uint32_t lutBankSelect:1; + uint32_t /* reserved */ : 31; +} __attribute__((packed, aligned(4))); + +struct vfe_wb_cfg { + /* WB Config */ + uint32_t ch0Gain:9; + uint32_t ch1Gain:9; + uint32_t ch2Gain:9; + uint32_t /* reserved */ : 5; +} __attribute__((packed, aligned(4))); + +struct VFE_GammaLutSelect_ConfigCmdType { + /* LUT Bank Select Config */ + uint32_t ch0BankSelect:1; + uint32_t ch1BankSelect:1; + uint32_t ch2BankSelect:1; + uint32_t /* reserved */ : 29; +} __attribute__((packed, aligned(4))); + +struct vfe_chroma_enhance_cfg { + /* Chroma Enhance A Config */ + uint32_t ap:11; + uint32_t /* reserved */ : 5; + uint32_t am:11; + uint32_t /* reserved */ : 5; + /* Chroma Enhance B Config */ + uint32_t bp:11; + uint32_t /* reserved */ : 5; + uint32_t bm:11; + uint32_t /* reserved */ : 5; + /* Chroma Enhance C Config */ + uint32_t cp:11; + uint32_t /* reserved */ : 5; + uint32_t cm:11; + uint32_t /* reserved */ : 5; + /* Chroma Enhance D Config */ + uint32_t dp:11; + uint32_t /* reserved */ : 5; + uint32_t dm:11; + uint32_t /* reserved */ : 5; + /* Chroma Enhance K Config */ + uint32_t kcb:11; + uint32_t /* reserved */ : 5; + uint32_t kcr:11; + uint32_t /* reserved */ : 5; +} __attribute__((packed, aligned(4))); + +struct vfe_color_convert_cfg { + /* Conversion Coefficient 0 */ + uint32_t v0:12; + uint32_t /* reserved */ : 20; + /* Conversion Coefficient 1 */ + uint32_t v1:12; + uint32_t /* reserved */ : 20; + /* Conversion Coefficient 2 */ + uint32_t v2:12; + uint32_t /* reserved */ : 20; + /* Conversion Offset */ + uint32_t ConvertOffset:8; + uint32_t /* reserved */ : 24; +} __attribute__((packed, aligned(4))); + +struct VFE_SyncTimer_ConfigCmdType { + /* Timer Line Start Config */ + uint32_t timerLineStart:12; + uint32_t /* reserved */ : 20; + /* Timer Pixel Start Config */ + uint32_t timerPixelStart:18; + uint32_t /* reserved */ : 14; + /* Timer Pixel Duration Config */ + uint32_t timerPixelDuration:28; + uint32_t /* reserved */ : 4; + /* Sync Timer Polarity Config */ + uint32_t timer0Polarity:1; + uint32_t timer1Polarity:1; + uint32_t timer2Polarity:1; + uint32_t /* reserved */ : 29; +} __attribute__((packed, aligned(4))); + +struct VFE_AsyncTimer_ConfigCmdType { + /* Async Timer Config 0 */ + uint32_t inactiveLength:20; + uint32_t numRepetition:10; + uint32_t /* reserved */ : 1; + uint32_t polarity:1; + /* Async Timer Config 1 */ + uint32_t activeLength:20; + uint32_t /* reserved */ : 12; +} __attribute__((packed, aligned(4))); + +struct VFE_AWBAEStatistics_ConfigCmdType { + /* AWB autoexposure Config */ + uint32_t aeRegionConfig:1; + uint32_t aeSubregionConfig:1; + uint32_t /* reserved */ : 14; + uint32_t awbYMin:8; + uint32_t awbYMax:8; + /* AXW Header */ + uint32_t axwHeader:8; + uint32_t /* reserved */ : 24; + /* AWB Mconfig */ + uint32_t m4:8; + uint32_t m3:8; + uint32_t m2:8; + uint32_t m1:8; + /* AWB Cconfig */ + uint32_t c2:12; + uint32_t /* reserved */ : 4; + uint32_t c1:12; + uint32_t /* reserved */ : 4; + /* AWB Cconfig 2 */ + uint32_t c4:12; + uint32_t /* reserved */ : 4; + uint32_t c3:12; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct VFE_TestGen_ConfigCmdType { + /* HW Test Gen Config */ + uint32_t numFrame:10; + uint32_t /* reserved */ : 2; + uint32_t pixelDataSelect:1; + uint32_t systematicDataSelect:1; + uint32_t /* reserved */ : 2; + uint32_t pixelDataSize:2; + uint32_t hsyncEdge:1; + uint32_t vsyncEdge:1; + uint32_t /* reserved */ : 12; + /* HW Test Gen Image Config */ + uint32_t imageWidth:14; + uint32_t /* reserved */ : 2; + uint32_t imageHeight:14; + uint32_t /* reserved */ : 2; + /* SOF Offset Config */ + uint32_t sofOffset:24; + uint32_t /* reserved */ : 8; + /* EOF NOffset Config */ + uint32_t eofNOffset:24; + uint32_t /* reserved */ : 8; + /* SOL Offset Config */ + uint32_t solOffset:9; + uint32_t /* reserved */ : 23; + /* EOL NOffset Config */ + uint32_t eolNOffset:9; + uint32_t /* reserved */ : 23; + /* HBI Config */ + uint32_t hBlankInterval:14; + uint32_t /* reserved */ : 18; + /* VBL Config */ + uint32_t vBlankInterval:14; + uint32_t /* reserved */ : 2; + uint32_t vBlankIntervalEnable:1; + uint32_t /* reserved */ : 15; + /* SOF Dummy Line Config */ + uint32_t sofDummy:8; + uint32_t /* reserved */ : 24; + /* EOF Dummy Line Config */ + uint32_t eofDummy:8; + uint32_t /* reserved */ : 24; + /* Color Bars Config */ + uint32_t unicolorBarSelect:3; + uint32_t /* reserved */ : 1; + uint32_t unicolorBarEnable:1; + uint32_t splitEnable:1; + uint32_t pixelPattern:2; + uint32_t rotatePeriod:6; + uint32_t /* reserved */ : 18; + /* Random Config */ + uint32_t randomSeed:16; + uint32_t /* reserved */ : 16; +} __attribute__((packed, aligned(4))); + +struct VFE_Bus_Pm_ConfigCmdType { + /* VFE Bus Performance Monitor Config */ + uint32_t output2YWrPmEnable:1; + uint32_t output2CbcrWrPmEnable:1; + uint32_t output1YWrPmEnable:1; + uint32_t output1CbcrWrPmEnable:1; + uint32_t /* reserved */ : 28; +} __attribute__((packed, aligned(4))); + +struct vfe_asf_info { + /* asf max edge */ + uint32_t maxEdge:13; + uint32_t /* reserved */ : 3; + /* HBi count */ + uint32_t HBICount:12; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct vfe_camif_stats { + uint32_t pixelCount:14; + uint32_t /* reserved */ : 2; + uint32_t lineCount:14; + uint32_t /* reserved */ : 1; + uint32_t camifHalt:1; +} __attribute__((packed, aligned(4))); + +struct VFE_StatsCmdType { + uint32_t autoFocusEnable:1; + uint32_t axwEnable:1; + uint32_t histEnable:1; + uint32_t clearHistEnable:1; + uint32_t histAutoClearEnable:1; + uint32_t colorConversionEnable:1; + uint32_t /* reserved */ : 26; +} __attribute__((packed, aligned(4))); + + +struct vfe_statsframe { + uint32_t lastPixel:12; + uint32_t /* reserved */ : 4; + uint32_t lastLine:12; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct vfe_busstats_wrprio { + uint32_t afBusPriority:4; + uint32_t awbBusPriority:4; + uint32_t histBusPriority:4; + uint32_t afBusPriorityEn:1; + uint32_t awbBusPriorityEn:1; + uint32_t histBusPriorityEn:1; + uint32_t /* reserved */ : 17; +} __attribute__((packed, aligned(4))); + +struct vfe_statsaf_update { + /* VFE_STATS_AF_CFG */ + uint32_t windowVOffset:12; + uint32_t /* reserved */ : 4; + uint32_t windowHOffset:12; + uint32_t /* reserved */ : 3; + uint32_t windowMode:1; + + /* VFE_STATS_AF_DIM */ + uint32_t windowHeight:12; + uint32_t /* reserved */ : 4; + uint32_t windowWidth:12; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct vfe_statsaf_cfg { + /* VFE_STATS_AF_GRID_0 */ + uint32_t entry00:8; + uint32_t entry01:8; + uint32_t entry02:8; + uint32_t entry03:8; + + /* VFE_STATS_AF_GRID_1 */ + uint32_t entry10:8; + uint32_t entry11:8; + uint32_t entry12:8; + uint32_t entry13:8; + + /* VFE_STATS_AF_GRID_2 */ + uint32_t entry20:8; + uint32_t entry21:8; + uint32_t entry22:8; + uint32_t entry23:8; + + /* VFE_STATS_AF_GRID_3 */ + uint32_t entry30:8; + uint32_t entry31:8; + uint32_t entry32:8; + uint32_t entry33:8; + + /* VFE_STATS_AF_HEADER */ + uint32_t afHeader:8; + uint32_t /* reserved */ : 24; + /* VFE_STATS_AF_COEF0 */ + uint32_t a00:5; + uint32_t a04:5; + uint32_t fvMax:11; + uint32_t fvMetric:1; + uint32_t /* reserved */ : 10; + + /* VFE_STATS_AF_COEF1 */ + uint32_t a20:5; + uint32_t a21:5; + uint32_t a22:5; + uint32_t a23:5; + uint32_t a24:5; + uint32_t /* reserved */ : 7; +} __attribute__((packed, aligned(4))); + +struct vfe_statsawbae_update { + uint32_t aeRegionCfg:1; + uint32_t aeSubregionCfg:1; + uint32_t /* reserved */ : 14; + uint32_t awbYMin:8; + uint32_t awbYMax:8; +} __attribute__((packed, aligned(4))); + +struct vfe_statsaxw_hdr_cfg { + /* Stats AXW Header Config */ + uint32_t axwHeader:8; + uint32_t /* reserved */ : 24; +} __attribute__((packed, aligned(4))); + +struct vfe_statsawb_update { + /* AWB MConfig */ + uint32_t m4:8; + uint32_t m3:8; + uint32_t m2:8; + uint32_t m1:8; + + /* AWB CConfig1 */ + uint32_t c2:12; + uint32_t /* reserved */ : 4; + uint32_t c1:12; + uint32_t /* reserved */ : 4; + + /* AWB CConfig2 */ + uint32_t c4:12; + uint32_t /* reserved */ : 4; + uint32_t c3:12; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct VFE_SyncTimerCmdType { + uint32_t hsyncCount:12; + uint32_t /* reserved */ : 20; + uint32_t pclkCount:18; + uint32_t /* reserved */ : 14; + uint32_t outputDuration:28; + uint32_t /* reserved */ : 4; +} __attribute__((packed, aligned(4))); + +struct VFE_AsyncTimerCmdType { + /* config 0 */ + uint32_t inactiveCount:20; + uint32_t repeatCount:10; + uint32_t /* reserved */ : 1; + uint32_t polarity:1; + /* config 1 */ + uint32_t activeCount:20; + uint32_t /* reserved */ : 12; +} __attribute__((packed, aligned(4))); + +struct VFE_AxiInputCmdType { + uint32_t stripeStartAddr0:32; + uint32_t stripeStartAddr1:32; + uint32_t stripeStartAddr2:32; + uint32_t stripeStartAddr3:32; + + uint32_t ySize:12; + uint32_t yOffsetDelta:12; + uint32_t /* reserved */ : 8; + + /* bus_stripe_rd_hSize */ + uint32_t /* reserved */ : 16; + uint32_t xSizeWord:10; + uint32_t /* reserved */ : 6; + + /* bus_stripe_rd_buffer_cfg */ + uint32_t burstLength:2; + uint32_t /* reserved */ : 2; + uint32_t NumOfRows:12; + uint32_t RowIncrement:12; + uint32_t /* reserved */ : 4; + + /* bus_stripe_rd_unpack_cfg */ + uint32_t mainUnpackHeight:12; + uint32_t mainUnpackWidth:13; + uint32_t mainUnpackHbiSel:3; + uint32_t mainUnpackPhase:3; + uint32_t /* reserved */ : 1; + + /* bus_stripe_rd_unpack */ + uint32_t unpackPattern:32; + + /* bus_stripe_rd_pad_size */ + uint32_t padLeft:7; + uint32_t /* reserved */ : 1; + uint32_t padRight:7; + uint32_t /* reserved */ : 1; + uint32_t padTop:7; + uint32_t /* reserved */ : 1; + uint32_t padBottom:7; + uint32_t /* reserved */ : 1; + + /* bus_stripe_rd_pad_L_unpack */ + uint32_t leftUnpackPattern0:4; + uint32_t leftUnpackPattern1:4; + uint32_t leftUnpackPattern2:4; + uint32_t leftUnpackPattern3:4; + uint32_t leftUnpackStop0:1; + uint32_t leftUnpackStop1:1; + uint32_t leftUnpackStop2:1; + uint32_t leftUnpackStop3:1; + uint32_t /* reserved */ : 12; + + /* bus_stripe_rd_pad_R_unpack */ + uint32_t rightUnpackPattern0:4; + uint32_t rightUnpackPattern1:4; + uint32_t rightUnpackPattern2:4; + uint32_t rightUnpackPattern3:4; + uint32_t rightUnpackStop0:1; + uint32_t rightUnpackStop1:1; + uint32_t rightUnpackStop2:1; + uint32_t rightUnpackStop3:1; + uint32_t /* reserved */ : 12; + + /* bus_stripe_rd_pad_tb_unpack */ + uint32_t topUnapckPattern:4; + uint32_t /* reserved */ : 12; + uint32_t bottomUnapckPattern:4; + uint32_t /* reserved */ : 12; +} __attribute__((packed, aligned(4))); + +struct VFE_AxiRdFragIrqEnable { + uint32_t stripeRdFragirq0Enable:1; + uint32_t stripeRdFragirq1Enable:1; + uint32_t stripeRdFragirq2Enable:1; + uint32_t stripeRdFragirq3Enable:1; + uint32_t /* reserved */ : 28; +} __attribute__((packed, aligned(4))); + +int vfe_cmd_init(struct msm_vfe_callback *, struct platform_device *, void *); +void vfe_stats_af_stop(void); +void vfe_stop(void); +void vfe_update(void); +int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *); +int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *); +void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *); +void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *); +void vfe_start(struct vfe_cmd_start *); +void vfe_la_update(struct vfe_cmd_la_config *); +void vfe_la_config(struct vfe_cmd_la_config *); +void vfe_test_gen_start(struct vfe_cmd_test_gen_start *); +void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *); +void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *); +void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *); +void vfe_camif_frame_update(struct vfe_cmds_camif_frame *); +void vfe_color_correction_config(struct vfe_cmd_color_correction_config *); +void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *); +void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *); +void vfe_demosaic_config(struct vfe_cmd_demosaic_config *); +void vfe_demux_channel_gain_update(struct vfe_cmd_demux_channel_gain_config *); +void vfe_demux_channel_gain_config(struct vfe_cmd_demux_channel_gain_config *); +void vfe_black_level_update(struct vfe_cmd_black_level_config *); +void vfe_black_level_config(struct vfe_cmd_black_level_config *); +void vfe_asf_update(struct vfe_cmd_asf_update *); +void vfe_asf_config(struct vfe_cmd_asf_config *); +void vfe_white_balance_config(struct vfe_cmd_white_balance_config *); +void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *); +void vfe_roll_off_config(struct vfe_cmd_roll_off_config *); +void vfe_chroma_subsample_config(struct vfe_cmd_chroma_subsample_config *); +void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *); +void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *); +void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *); +void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *); +void vfe_stats_wb_exp_stop(void); +void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *); +void vfe_stats_update_af(struct vfe_cmd_stats_af_update *); +void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *); +void vfe_stats_start_af(struct vfe_cmd_stats_af_start *); +void vfe_stats_setting(struct vfe_cmd_stats_setting *); +void vfe_axi_input_config(struct vfe_cmd_axi_input_config *); +void vfe_axi_output_config(struct vfe_cmd_axi_output_config *); +void vfe_camif_config(struct vfe_cmd_camif_config *); +void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *); +void vfe_get_hw_version(struct vfe_cmd_hw_version *); +void vfe_reset(void); +void vfe_cmd_release(struct platform_device *); +void vfe_output_p_ack(struct vfe_cmd_output_ack *); +void vfe_output_v_ack(struct vfe_cmd_output_ack *); +#endif /* __MSM_VFE8X_REG_H__ */ diff --git a/drivers/media/video/msm_zsl/msm_vpe.c b/drivers/media/video/msm_zsl/msm_vpe.c new file mode 100644 index 00000000000..2a214ac4961 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vpe.c @@ -0,0 +1,793 @@ +/* Copyright (c) 2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm.h" +#include "msm_vpe.h" + +static int vpe_enable(uint32_t); +static int vpe_disable(void); +static int vpe_update_scaler(struct msm_pp_crop *pcrop); +struct vpe_ctrl_type *vpe_ctrl; +static atomic_t vpe_init_done = ATOMIC_INIT(0); + +static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd, + struct msm_mctl_pp_frame_info *pp_frame_info); + +static long long vpe_do_div(long long num, long long den) +{ + do_div(num, den); + return num; +} + +static int vpe_start(void) +{ + /* enable the frame irq, bit 0 = Display list 0 ROI done */ + msm_io_w_mb(1, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET); + msm_io_dump(vpe_ctrl->vpebase, 0x120); + msm_io_dump(vpe_ctrl->vpebase + 0x10000, 0x250); + msm_io_dump(vpe_ctrl->vpebase + 0x30000, 0x20); + msm_io_dump(vpe_ctrl->vpebase + 0x50000, 0x30); + msm_io_dump(vpe_ctrl->vpebase + 0x50400, 0x10); + /* this triggers the operation. */ + msm_io_w(1, vpe_ctrl->vpebase + VPE_DL0_START_OFFSET); + wmb(); + return 0; +} + +void vpe_reset_state_variables(void) +{ + /* initialize local variables for state control, etc.*/ + vpe_ctrl->op_mode = 0; + vpe_ctrl->state = VPE_STATE_INIT; +} + +static void vpe_config_axi_default(void) +{ + msm_io_w(0x25, vpe_ctrl->vpebase + VPE_AXI_ARB_2_OFFSET); + CDBG("%s: yaddr %ld cbcraddr %ld", __func__, + vpe_ctrl->out_y_addr, vpe_ctrl->out_cbcr_addr); + if (!vpe_ctrl->out_y_addr || !vpe_ctrl->out_cbcr_addr) + return; + msm_io_w(vpe_ctrl->out_y_addr, + vpe_ctrl->vpebase + VPE_OUTP0_ADDR_OFFSET); + /* for video CbCr address */ + msm_io_w(vpe_ctrl->out_cbcr_addr, + vpe_ctrl->vpebase + VPE_OUTP1_ADDR_OFFSET); + +} + +static int vpe_reset(void) +{ + uint32_t vpe_version; + uint32_t rc = 0; + + vpe_reset_state_variables(); + vpe_version = msm_io_r(vpe_ctrl->vpebase + VPE_HW_VERSION_OFFSET); + CDBG("vpe_version = 0x%x\n", vpe_version); + /* disable all interrupts.*/ + msm_io_w(0, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET); + /* clear all pending interrupts*/ + msm_io_w(0x1fffff, vpe_ctrl->vpebase + VPE_INTR_CLEAR_OFFSET); + /* write sw_reset to reset the core. */ + msm_io_w(0x10, vpe_ctrl->vpebase + VPE_SW_RESET_OFFSET); + /* then poll the reset bit, it should be self-cleared. */ + while (1) { + rc = + msm_io_r(vpe_ctrl->vpebase + VPE_SW_RESET_OFFSET) & 0x10; + if (rc == 0) + break; + } + /* at this point, hardware is reset. Then pogram to default + values. */ + msm_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE, + vpe_ctrl->vpebase + VPE_AXI_RD_ARB_CONFIG_OFFSET); + + msm_io_w(VPE_CGC_ENABLE_VALUE, + vpe_ctrl->vpebase + VPE_CGC_EN_OFFSET); + msm_io_w(1, vpe_ctrl->vpebase + VPE_CMD_MODE_OFFSET); + msm_io_w(VPE_DEFAULT_OP_MODE_VALUE, + vpe_ctrl->vpebase + VPE_OP_MODE_OFFSET); + msm_io_w(VPE_DEFAULT_SCALE_CONFIG, + vpe_ctrl->vpebase + VPE_SCALE_CONFIG_OFFSET); + vpe_config_axi_default(); + return rc; +} + +static int msm_vpe_cfg_update(void *pinfo) +{ + uint32_t rot_flag, rc = 0; + struct msm_pp_crop *pcrop = (struct msm_pp_crop *)pinfo; + + rot_flag = msm_io_r(vpe_ctrl->vpebase + + VPE_OP_MODE_OFFSET) & 0xE00; + if (pinfo != NULL) { + CDBG("%s: Crop info in2_w = %d, in2_h = %d " + "out2_w = %d out2_h = %d\n", + __func__, pcrop->src_w, pcrop->src_h, + pcrop->dst_w, pcrop->dst_h); + rc = vpe_update_scaler(pcrop); + } + CDBG("return rc = %d rot_flag = %d\n", rc, rot_flag); + rc |= rot_flag; + + return rc; +} + +void vpe_update_scale_coef(uint32_t *p) +{ + uint32_t i, offset; + offset = *p; + for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) { + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_SCALE_COEFF_LSBn(i)); + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_SCALE_COEFF_MSBn(i)); + } +} + +void vpe_input_plane_config(uint32_t *p) +{ + msm_io_w(*p, vpe_ctrl->vpebase + VPE_SRC_FORMAT_OFFSET); + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_SRC_UNPACK_PATTERN1_OFFSET); + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_SRC_IMAGE_SIZE_OFFSET); + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_SRC_YSTRIDE1_OFFSET); + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_SRC_SIZE_OFFSET); + vpe_ctrl->in_h_w = *p; + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_SRC_XY_OFFSET); + CDBG("%s: in_h_w=0x%x", __func__, vpe_ctrl->in_h_w); +} + +void vpe_output_plane_config(uint32_t *p) +{ + msm_io_w(*p, vpe_ctrl->vpebase + VPE_OUT_FORMAT_OFFSET); + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_OUT_PACK_PATTERN1_OFFSET); + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_OUT_YSTRIDE1_OFFSET); + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_OUT_SIZE_OFFSET); + msm_io_w(*(++p), vpe_ctrl->vpebase + VPE_OUT_XY_OFFSET); + vpe_ctrl->pcbcr_dis_offset = *(++p); +} + +static int vpe_operation_config(uint32_t *p) +{ + uint32_t w, h, temp; + msm_io_w(*p, vpe_ctrl->vpebase + VPE_OP_MODE_OFFSET); + + temp = msm_io_r(vpe_ctrl->vpebase + VPE_OUT_SIZE_OFFSET); + w = temp & 0xFFF; + h = (temp & 0xFFF0000) >> 16; + if (*p++ & 0xE00) { + /* rotation enabled. */ + vpe_ctrl->out_w = h; + vpe_ctrl->out_h = w; + } else { + vpe_ctrl->out_w = w; + vpe_ctrl->out_h = h; + } + vpe_ctrl->dis_en = *p; + CDBG("%s: out_w=%d, out_h=%d, dis_en=%d", + __func__, vpe_ctrl->out_w, vpe_ctrl->out_h, vpe_ctrl->dis_en); + return 0; +} + +/* Later we can separate the rotation and scaler calc. If +* rotation is enabled, simply swap the destination dimension. +* And then pass the already swapped output size to this +* function. */ +static int vpe_update_scaler(struct msm_pp_crop *pcrop) +{ + uint32_t out_ROI_width, out_ROI_height; + uint32_t src_ROI_width, src_ROI_height; + + uint32_t rc = 0; /* default to no zoom. */ + /* + * phase_step_x, phase_step_y, phase_init_x and phase_init_y + * are represented in fixed-point, unsigned 3.29 format + */ + uint32_t phase_step_x = 0; + uint32_t phase_step_y = 0; + uint32_t phase_init_x = 0; + uint32_t phase_init_y = 0; + + uint32_t src_roi, src_x, src_y, src_xy, temp; + uint32_t yscale_filter_sel, xscale_filter_sel; + uint32_t scale_unit_sel_x, scale_unit_sel_y; + uint64_t numerator, denominator; + if ((pcrop->src_w >= pcrop->dst_w) && + (pcrop->src_h >= pcrop->dst_h)) { + CDBG(" =======VPE no zoom needed.\n"); + + temp = msm_io_r(vpe_ctrl->vpebase + VPE_OP_MODE_OFFSET) + & 0xfffffffc; + msm_io_w(temp, vpe_ctrl->vpebase + VPE_OP_MODE_OFFSET); + + + msm_io_w(0, vpe_ctrl->vpebase + VPE_SRC_XY_OFFSET); + + CDBG("vpe_ctrl->in_h_w = %d\n", vpe_ctrl->in_h_w); + msm_io_w(vpe_ctrl->in_h_w , vpe_ctrl->vpebase + + VPE_SRC_SIZE_OFFSET); + + return rc; + } + /* If fall through then scaler is needed.*/ + + CDBG("========VPE zoom needed.\n"); + /* assumption is both direction need zoom. this can be + improved. */ + temp = + msm_io_r(vpe_ctrl->vpebase + VPE_OP_MODE_OFFSET) | 0x3; + msm_io_w(temp, vpe_ctrl->vpebase + VPE_OP_MODE_OFFSET); + + src_ROI_width = pcrop->src_w; + src_ROI_height = pcrop->src_h; + out_ROI_width = pcrop->dst_w; + out_ROI_height = pcrop->dst_h; + + CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n", + src_ROI_width, src_ROI_height, out_ROI_width, + out_ROI_height); + src_roi = (src_ROI_height << 16) + src_ROI_width; + + msm_io_w(src_roi, vpe_ctrl->vpebase + VPE_SRC_SIZE_OFFSET); + + src_x = pcrop->src_x; + src_y = pcrop->src_y; + + CDBG("src_x = %d, src_y=%d.\n", src_x, src_y); + + src_xy = src_y*(1<<16) + src_x; + msm_io_w(src_xy, vpe_ctrl->vpebase + + VPE_SRC_XY_OFFSET); + CDBG("src_xy = %d, src_roi=%d.\n", src_xy, src_roi); + + /* decide whether to use FIR or M/N for scaling */ + if ((out_ROI_width == 1 && src_ROI_width < 4) || + (src_ROI_width < 4 * out_ROI_width - 3)) + scale_unit_sel_x = 0;/* use FIR scalar */ + else + scale_unit_sel_x = 1;/* use M/N scalar */ + + if ((out_ROI_height == 1 && src_ROI_height < 4) || + (src_ROI_height < 4 * out_ROI_height - 3)) + scale_unit_sel_y = 0;/* use FIR scalar */ + else + scale_unit_sel_y = 1;/* use M/N scalar */ + + /* calculate phase step for the x direction */ + + /* if destination is only 1 pixel wide, + the value of phase_step_x + is unimportant. Assigning phase_step_x to + src ROI width as an arbitrary value. */ + if (out_ROI_width == 1) + phase_step_x = (uint32_t) ((src_ROI_width) << + SCALER_PHASE_BITS); + + /* if using FIR scalar */ + else if (scale_unit_sel_x == 0) { + + /* Calculate the quotient ( src_ROI_width - 1 ) + ( out_ROI_width - 1) + with u3.29 precision. Quotient is rounded up to + the larger 29th decimal point*/ + numerator = (uint64_t)(src_ROI_width - 1) << + SCALER_PHASE_BITS; + /* never equals to 0 because of the + "(out_ROI_width == 1 )"*/ + denominator = (uint64_t)(out_ROI_width - 1); + /* divide and round up to the larger 29th + decimal point.*/ + phase_step_x = (uint32_t) vpe_do_div((numerator + + denominator - 1), denominator); + } else if (scale_unit_sel_x == 1) { /* if M/N scalar */ + /* Calculate the quotient ( src_ROI_width ) / + ( out_ROI_width) + with u3.29 precision. Quotient is rounded down to the + smaller 29th decimal point.*/ + numerator = (uint64_t)(src_ROI_width) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_width); + phase_step_x = + (uint32_t) vpe_do_div(numerator, denominator); + } + /* calculate phase step for the y direction */ + + /* if destination is only 1 pixel wide, the value of + phase_step_x is unimportant. Assigning phase_step_x + to src ROI width as an arbitrary value. */ + if (out_ROI_height == 1) + phase_step_y = + (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); + + /* if FIR scalar */ + else if (scale_unit_sel_y == 0) { + /* Calculate the quotient ( src_ROI_height - 1 ) / + ( out_ROI_height - 1) + with u3.29 precision. Quotient is rounded up to the + larger 29th decimal point. */ + numerator = (uint64_t)(src_ROI_height - 1) << + SCALER_PHASE_BITS; + /* never equals to 0 because of the " + ( out_ROI_height == 1 )" case */ + denominator = (uint64_t)(out_ROI_height - 1); + /* Quotient is rounded up to the larger + 29th decimal point. */ + phase_step_y = + (uint32_t) vpe_do_div( + (numerator + denominator - 1), denominator); + } else if (scale_unit_sel_y == 1) { /* if M/N scalar */ + /* Calculate the quotient ( src_ROI_height ) + ( out_ROI_height) + with u3.29 precision. Quotient is rounded down + to the smaller 29th decimal point. */ + numerator = (uint64_t)(src_ROI_height) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_height); + phase_step_y = (uint32_t) vpe_do_div( + numerator, denominator); + } + + /* decide which set of FIR coefficients to use */ + if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) + xscale_filter_sel = 0; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) + xscale_filter_sel = 1; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) + xscale_filter_sel = 2; + else + xscale_filter_sel = 3; + + if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) + yscale_filter_sel = 0; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) + yscale_filter_sel = 1; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) + yscale_filter_sel = 2; + else + yscale_filter_sel = 3; + + /* calculate phase init for the x direction */ + + /* if using FIR scalar */ + if (scale_unit_sel_x == 0) { + if (out_ROI_width == 1) + phase_init_x = + (uint32_t) ((src_ROI_width - 1) << + SCALER_PHASE_BITS); + else + phase_init_x = 0; + } else if (scale_unit_sel_x == 1) /* M over N scalar */ + phase_init_x = 0; + + /* calculate phase init for the y direction + if using FIR scalar */ + if (scale_unit_sel_y == 0) { + if (out_ROI_height == 1) + phase_init_y = + (uint32_t) ((src_ROI_height - + 1) << SCALER_PHASE_BITS); + else + phase_init_y = 0; + } else if (scale_unit_sel_y == 1) /* M over N scalar */ + phase_init_y = 0; + + CDBG("phase step x = %d, step y = %d.\n", + phase_step_x, phase_step_y); + CDBG("phase init x = %d, init y = %d.\n", + phase_init_x, phase_init_y); + + msm_io_w(phase_step_x, vpe_ctrl->vpebase + + VPE_SCALE_PHASEX_STEP_OFFSET); + msm_io_w(phase_step_y, vpe_ctrl->vpebase + + VPE_SCALE_PHASEY_STEP_OFFSET); + + msm_io_w(phase_init_x, vpe_ctrl->vpebase + + VPE_SCALE_PHASEX_INIT_OFFSET); + + msm_io_w(phase_init_y, vpe_ctrl->vpebase + + VPE_SCALE_PHASEY_INIT_OFFSET); + + return 1; +} + +static inline void vpe_get_zoom_dis_xy( + struct dis_offset_type *dis_offset, + struct msm_pp_crop *pcrop, + int32_t *zoom_dis_x, + int32_t *zoom_dis_y) +{ + *zoom_dis_x = dis_offset->dis_offset_x * + pcrop->src_w / pcrop->dst_w; + *zoom_dis_y = dis_offset->dis_offset_y * + pcrop->src_h / pcrop->dst_h; +} + +int msm_vpe_is_busy(void) +{ + int busy = 0; + unsigned long flags; + spin_lock_irqsave(&vpe_ctrl->lock, flags); + if (vpe_ctrl->state == VPE_STATE_ACTIVE) + busy = 1; + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + return busy; +} +static int msm_send_frame_to_vpe(void) +{ + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&vpe_ctrl->lock, flags); + msm_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr + + vpe_ctrl->pp_frame_info->src_frame.sp.y_off), + vpe_ctrl->vpebase + VPE_SRCP0_ADDR_OFFSET); + msm_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr + + vpe_ctrl->pp_frame_info->src_frame.sp.cbcr_off), + vpe_ctrl->vpebase + VPE_SRCP1_ADDR_OFFSET); + msm_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr + + vpe_ctrl->pp_frame_info->dest_frame.sp.y_off), + vpe_ctrl->vpebase + VPE_OUTP0_ADDR_OFFSET); + msm_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr + + vpe_ctrl->pp_frame_info->dest_frame.sp.cbcr_off), + vpe_ctrl->vpebase + VPE_OUTP1_ADDR_OFFSET); + vpe_ctrl->state = VPE_STATE_ACTIVE; + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + vpe_start(); + return rc; +} + +static void vpe_send_outmsg(void) +{ + unsigned long flags; + struct msm_vpe_resp rp; + memset(&rp, 0, sizeof(rp)); + spin_lock_irqsave(&vpe_ctrl->lock, flags); + if (vpe_ctrl->state == VPE_STATE_IDLE) { + pr_err("%s VPE is in IDLE state. Ignore the ack msg", __func__); + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + return; + } + rp.type = vpe_ctrl->pp_frame_info->pp_frame_cmd.path; + rp.extdata = (void *)vpe_ctrl->pp_frame_info; + rp.extlen = sizeof(*vpe_ctrl->pp_frame_info); + vpe_ctrl->state = VPE_STATE_INIT; /* put it back to idle. */ + vpe_ctrl->pp_frame_info = NULL; + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + v4l2_subdev_notify(&vpe_ctrl->subdev, + NOTIFY_VPE_MSG_EVT, (void *)&rp); +} + +static void vpe_do_tasklet(unsigned long data) +{ + CDBG("%s: irq_status = 0x%x", + __func__, vpe_ctrl->irq_status); + if (vpe_ctrl->irq_status & 0x1) + vpe_send_outmsg(); + +} +DECLARE_TASKLET(vpe_tasklet, vpe_do_tasklet, 0); + +static irqreturn_t vpe_parse_irq(int irq_num, void *data) +{ + vpe_ctrl->irq_status = msm_io_r_mb(vpe_ctrl->vpebase + + VPE_INTR_STATUS_OFFSET); + msm_io_w_mb(vpe_ctrl->irq_status, vpe_ctrl->vpebase + + VPE_INTR_CLEAR_OFFSET); + msm_io_w(0, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET); + CDBG("%s: vpe_parse_irq =0x%x.\n", __func__, vpe_ctrl->irq_status); + tasklet_schedule(&vpe_tasklet); + return IRQ_HANDLED; +} + +static struct msm_cam_clk_info vpe_clk_info[] = { + {"vpe_clk", 160000000}, + {"vpe_pclk", -1}, +}; + +int vpe_enable(uint32_t clk_rate) +{ + int rc = 0; + unsigned long flags = 0; + CDBG("%s", __func__); + /* don't change the order of clock and irq.*/ + spin_lock_irqsave(&vpe_ctrl->lock, flags); + if (vpe_ctrl->state != VPE_STATE_IDLE) { + pr_err("%s: VPE already enabled", __func__); + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + return 0; + } + vpe_ctrl->state = VPE_STATE_INIT; + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + + rc = request_irq(vpe_ctrl->vpeirq->start, vpe_parse_irq, + IRQF_TRIGGER_RISING, "vpe", 0); + if (rc < 0) { + pr_err("%s: irq request fail\n", __func__); + return -EBUSY; + } + + vpe_ctrl->fs_vpe = regulator_get(NULL, "fs_vpe"); + if (IS_ERR(vpe_ctrl->fs_vpe)) { + pr_err("%s: Regulator FS_VPE get failed %ld\n", __func__, + PTR_ERR(vpe_ctrl->fs_vpe)); + vpe_ctrl->fs_vpe = NULL; + goto vpe_fs_failed; + } else if (regulator_enable(vpe_ctrl->fs_vpe)) { + pr_err("%s: Regulator FS_VPE enable failed\n", __func__); + regulator_put(vpe_ctrl->fs_vpe); + goto vpe_fs_failed; + } + + rc = msm_cam_clk_enable(&vpe_ctrl->pdev->dev, vpe_clk_info, + vpe_ctrl->vpe_clk, ARRAY_SIZE(vpe_clk_info), 1); + if (rc < 0) + goto vpe_clk_failed; + + return rc; + +vpe_clk_failed: + regulator_disable(vpe_ctrl->fs_vpe); + regulator_put(vpe_ctrl->fs_vpe); + vpe_ctrl->fs_vpe = NULL; +vpe_fs_failed: + free_irq(vpe_ctrl->vpeirq->start, 0); + vpe_ctrl->state = VPE_STATE_IDLE; + return rc; +} + +int vpe_disable(void) +{ + int rc = 0; + unsigned long flags = 0; + CDBG("%s", __func__); + spin_lock_irqsave(&vpe_ctrl->lock, flags); + if (vpe_ctrl->state == VPE_STATE_IDLE) { + CDBG("%s: VPE already disabled", __func__); + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + return rc; + } + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + + disable_irq(vpe_ctrl->vpeirq->start); + tasklet_kill(&vpe_tasklet); + msm_cam_clk_enable(&vpe_ctrl->pdev->dev, vpe_clk_info, + vpe_ctrl->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0); + + regulator_disable(vpe_ctrl->fs_vpe); + regulator_put(vpe_ctrl->fs_vpe); + vpe_ctrl->fs_vpe = NULL; + spin_lock_irqsave(&vpe_ctrl->lock, flags); + vpe_ctrl->state = VPE_STATE_IDLE; + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + return rc; +} + +static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd, + struct msm_mctl_pp_frame_info *pp_frame_info) +{ + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&vpe_ctrl->lock, flags); + if (vpe_ctrl->state == VPE_STATE_ACTIVE || + vpe_ctrl->state == VPE_STATE_IDLE) { + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + pr_err(" =====VPE in wrong state:%d!!! Wrong!========\n", + vpe_ctrl->state); + return -EBUSY; + } + spin_unlock_irqrestore(&vpe_ctrl->lock, flags); + vpe_ctrl->pp_frame_info = pp_frame_info; + msm_vpe_cfg_update( + &vpe_ctrl->pp_frame_info->pp_frame_cmd.crop); + rc = msm_send_frame_to_vpe(); + return rc; +} + +static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int subdev_cmd, void *arg) +{ + struct msm_mctl_pp_params *vpe_params = + (struct msm_mctl_pp_params *)arg; + struct msm_mctl_pp_cmd *cmd = vpe_params->cmd; + int rc = 0; + switch (cmd->id) { + case VPE_CMD_INIT: + case VPE_CMD_DEINIT: + break; + case VPE_CMD_RESET: + rc = vpe_reset(); + break; + case VPE_CMD_OPERATION_MODE_CFG: + rc = vpe_operation_config(cmd->value); + break; + case VPE_CMD_INPUT_PLANE_CFG: + vpe_input_plane_config(cmd->value); + break; + case VPE_CMD_OUTPUT_PLANE_CFG: + vpe_output_plane_config(cmd->value); + break; + case VPE_CMD_SCALE_CFG_TYPE: + vpe_update_scale_coef(cmd->value); + break; + case VPE_CMD_ZOOM: { + rc = msm_vpe_do_pp(cmd, + (struct msm_mctl_pp_frame_info *)vpe_params->data); + break; + } + case VPE_CMD_ENABLE: { + struct msm_vpe_clock_rate *clk_rate = cmd->value; + int turbo_mode = (int)clk_rate->rate; + rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) : + vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE); + break; + } + case VPE_CMD_DISABLE: + rc = vpe_disable(); + break; + case VPE_CMD_INPUT_PLANE_UPDATE: + case VPE_CMD_FLUSH: + /*case VPE_CMD_DIS_OFFSET_CFG:*//* UPDATE1031_CAM_TEMP */ + default: + break; + } + CDBG("%s: end, id = %d, rc = %d", __func__, cmd->id, rc); + return rc; +} + +static const struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = { + .ioctl = msm_vpe_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_vpe_subdev_ops = { + .core = &msm_vpe_subdev_core_ops, +}; + +static int msm_vpe_resource_init(struct platform_device *pdev); + +int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data, + struct platform_device *pdev) +{ + int rc = 0; + CDBG("%s:begin", __func__); + if (atomic_read(&vpe_init_done)) { + pr_err("%s: VPE has been initialized", __func__); + return -EBUSY; + } + atomic_set(&vpe_init_done, 1); + + rc = msm_vpe_resource_init(pdev); + if (rc < 0) { + atomic_set(&vpe_init_done, 0); + return rc; + } + + disable_irq(vpe_ctrl->vpeirq->start); + + v4l2_set_subdev_hostdata(sd, data); + spin_lock_init(&vpe_ctrl->lock); + CDBG("%s:end", __func__); + return rc; +} +EXPORT_SYMBOL(msm_vpe_subdev_init); + +static int msm_vpe_resource_init(struct platform_device *pdev) +{ + int rc = 0; + + vpe_ctrl->vpebase = ioremap(vpe_ctrl->vpemem->start, + resource_size(vpe_ctrl->vpemem)); + + if (!vpe_ctrl->vpebase) { + rc = -ENOMEM; + pr_err("%s: vpe ioremap failed\n", __func__); + goto vpe_unmap_mem_region; + } + + return rc; +/* from this part it is error handling. */ +vpe_unmap_mem_region: + iounmap(vpe_ctrl->vpebase); + return rc; /* this rc should have error code. */ +} + +void msm_vpe_subdev_release(struct platform_device *pdev) +{ + if (!atomic_read(&vpe_init_done)) { + /* no VPE object created */ + pr_err("%s: no VPE object to release", __func__); + return; + } + + iounmap(vpe_ctrl->vpebase); + atomic_set(&vpe_init_done, 0); +} +EXPORT_SYMBOL(msm_vpe_subdev_release); + +static int __devinit vpe_probe(struct platform_device *pdev) +{ + int rc = 0; + CDBG("%s: device id = %d\n", __func__, pdev->id); + vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL); + if (!vpe_ctrl) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + v4l2_subdev_init(&vpe_ctrl->subdev, &msm_vpe_subdev_ops); + v4l2_set_subdevdata(&vpe_ctrl->subdev, vpe_ctrl); + snprintf(vpe_ctrl->subdev.name, sizeof(vpe_ctrl->subdev.name), "vpe"); + platform_set_drvdata(pdev, &vpe_ctrl->subdev); + + vpe_ctrl->vpemem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "vpe"); + if (!vpe_ctrl->vpemem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vpe_no_resource; + } + vpe_ctrl->vpeirq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "vpe"); + if (!vpe_ctrl->vpeirq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto vpe_no_resource; + } + + vpe_ctrl->vpeio = request_mem_region(vpe_ctrl->vpemem->start, + resource_size(vpe_ctrl->vpemem), pdev->name); + if (!vpe_ctrl->vpeio) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto vpe_no_resource; + } + + vpe_ctrl->pdev = pdev; + return 0; + +vpe_no_resource: + kfree(vpe_ctrl); + return 0; +} + +struct platform_driver vpe_driver = { + .probe = vpe_probe, + .driver = { + .name = MSM_VPE_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_vpe_init_module(void) +{ + return platform_driver_register(&vpe_driver); +} + +module_init(msm_vpe_init_module); +MODULE_DESCRIPTION("VPE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/msm_vpe.h b/drivers/media/video/msm_zsl/msm_vpe.h new file mode 100644 index 00000000000..d355c449180 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vpe.h @@ -0,0 +1,192 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef _MSM_VPE_H_ +#define _MSM_VPE_H_ + +#include + +/*********** start of register offset *********************/ +#define VPE_INTR_ENABLE_OFFSET 0x0020 +#define VPE_INTR_STATUS_OFFSET 0x0024 +#define VPE_INTR_CLEAR_OFFSET 0x0028 +#define VPE_DL0_START_OFFSET 0x0030 +#define VPE_HW_VERSION_OFFSET 0x0070 +#define VPE_SW_RESET_OFFSET 0x0074 +#define VPE_AXI_RD_ARB_CONFIG_OFFSET 0x0078 +#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET 0x007C +#define VPE_CGC_EN_OFFSET 0x0100 +#define VPE_CMD_STATUS_OFFSET 0x10008 +#define VPE_PROFILE_EN_OFFSET 0x10010 +#define VPE_PROFILE_COUNT_OFFSET 0x10014 +#define VPE_CMD_MODE_OFFSET 0x10060 +#define VPE_SRC_SIZE_OFFSET 0x10108 +#define VPE_SRCP0_ADDR_OFFSET 0x1010C +#define VPE_SRCP1_ADDR_OFFSET 0x10110 +#define VPE_SRC_YSTRIDE1_OFFSET 0x1011C +#define VPE_SRC_FORMAT_OFFSET 0x10124 +#define VPE_SRC_UNPACK_PATTERN1_OFFSET 0x10128 +#define VPE_OP_MODE_OFFSET 0x10138 +#define VPE_SCALE_PHASEX_INIT_OFFSET 0x1013C +#define VPE_SCALE_PHASEY_INIT_OFFSET 0x10140 +#define VPE_SCALE_PHASEX_STEP_OFFSET 0x10144 +#define VPE_SCALE_PHASEY_STEP_OFFSET 0x10148 +#define VPE_OUT_FORMAT_OFFSET 0x10150 +#define VPE_OUT_PACK_PATTERN1_OFFSET 0x10154 +#define VPE_OUT_SIZE_OFFSET 0x10164 +#define VPE_OUTP0_ADDR_OFFSET 0x10168 +#define VPE_OUTP1_ADDR_OFFSET 0x1016C +#define VPE_OUT_YSTRIDE1_OFFSET 0x10178 +#define VPE_OUT_XY_OFFSET 0x1019C +#define VPE_SRC_XY_OFFSET 0x10200 +#define VPE_SRC_IMAGE_SIZE_OFFSET 0x10208 +#define VPE_SCALE_CONFIG_OFFSET 0x10230 +#define VPE_DEINT_STATUS_OFFSET 0x30000 +#define VPE_DEINT_DECISION_OFFSET 0x30004 +#define VPE_DEINT_COEFF0_OFFSET 0x30010 +#define VPE_SCALE_STATUS_OFFSET 0x50000 +#define VPE_SCALE_SVI_PARAM_OFFSET 0x50010 +#define VPE_SCALE_SHARPEN_CFG_OFFSET 0x50020 +#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400 +#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404 + +#define VPE_AXI_ARB_2_OFFSET 0x004C + +#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n)) +#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n)) +#define VPE_SCALE_COEFF_NUM 32 + +/*********** end of register offset ********************/ + + +#define VPE_HARDWARE_VERSION 0x00080308 +#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/ +#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924 +#define VPE_CMD_MODE_VALUE 0x1 +#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004 +#define VPE_CGC_ENABLE_VALUE 0xffff +#define VPE_DEFAULT_SCALE_CONFIG 0x3c + +#define VPE_NORMAL_MODE_CLOCK_RATE 150000000 +#define VPE_TURBO_MODE_CLOCK_RATE 200000000 + + +/**************************************************/ +/*********** End of command id ********************/ +/**************************************************/ + +enum vpe_state { + VPE_STATE_IDLE, + VPE_STATE_INIT, + VPE_STATE_ACTIVE, +}; + +struct dis_offset_type { + int32_t dis_offset_x; + int32_t dis_offset_y; + uint32_t frame_id; +}; + +struct vpe_ctrl_type { + spinlock_t lock; + uint32_t irq_status; + void *syncdata; + uint16_t op_mode; + void *extdata; + uint32_t extlen; + struct msm_vpe_callback *resp; + uint32_t in_h_w; + uint32_t out_h; /* this is BEFORE rotation. */ + uint32_t out_w; /* this is BEFORE rotation. */ + uint32_t dis_en; + struct timespec ts; + struct dis_offset_type dis_offset; + uint32_t pcbcr_before_dis; + uint32_t pcbcr_dis_offset; + int output_type; + int frame_pack; + uint8_t pad_2k_bool; + enum vpe_state state; + unsigned long out_y_addr; + unsigned long out_cbcr_addr; + struct v4l2_subdev subdev; + struct platform_device *pdev; + struct resource *vpeirq; + void __iomem *vpebase; + struct resource *vpemem; + struct resource *vpeio; + void *device_extdata; + struct regulator *fs_vpe; + struct clk *vpe_clk[2]; + struct msm_mctl_pp_frame_info *pp_frame_info; +}; + +/* +* vpe_input_update +* +* Define the parameters for output plane +*/ +/* this is the dimension of ROI. width / height. */ +struct vpe_src_size_packed { + uint32_t src_w; + uint32_t src_h; +}; + +struct vpe_src_xy_packed { + uint32_t src_x; + uint32_t src_y; +}; + +struct vpe_input_plane_update_type { + struct vpe_src_size_packed src_roi_size; + /* DIS updates this set. */ + struct vpe_src_xy_packed src_roi_offset; + /* input address*/ + uint8_t *src_p0_addr; + uint8_t *src_p1_addr; +}; + +struct vpe_msg_stats { + uint32_t buffer; + uint32_t frameCounter; +}; + +struct vpe_msg_output { + uint8_t output_id; + uint32_t yBuffer; + uint32_t cbcrBuffer; + uint32_t frameCounter; +}; + +struct vpe_message { + uint8_t _d; + union { + struct vpe_msg_output msgOut; + struct vpe_msg_stats msgStats; + } _u; +}; + +#define SCALER_PHASE_BITS 29 +#define HAL_MDP_PHASE_STEP_2P50 0x50000000 +#define HAL_MDP_PHASE_STEP_1P66 0x35555555 +#define HAL_MDP_PHASE_STEP_1P25 0x28000000 + +struct phase_val_t { + int32_t phase_init_x; + int32_t phase_init_y; + int32_t phase_step_x; + int32_t phase_step_y; +}; + + +#endif /*_MSM_VPE_H_*/ diff --git a/drivers/media/video/msm_zsl/msm_vpe1.c b/drivers/media/video/msm_zsl/msm_vpe1.c new file mode 100644 index 00000000000..f8d71cb7b29 --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vpe1.c @@ -0,0 +1,1446 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include "msm_vpe1.h" +#include +#include +#include +#include + +static int vpe_enable(uint32_t); +static int vpe_disable(void); +static int vpe_update_scaler(struct video_crop_t *pcrop); +static struct vpe_device_type vpe_device_data; +static struct vpe_device_type *vpe_device; +struct vpe_ctrl_type *vpe_ctrl; +char *vpe_general_cmd[] = { + "VPE_DUMMY_0", /* 0 */ + "VPE_SET_CLK", + "VPE_RESET", + "VPE_START", + "VPE_ABORT", + "VPE_OPERATION_MODE_CFG", /* 5 */ + "VPE_INPUT_PLANE_CFG", + "VPE_OUTPUT_PLANE_CFG", + "VPE_INPUT_PLANE_UPDATE", + "VPE_SCALE_CFG_TYPE", + "VPE_ROTATION_CFG_TYPE", /* 10 */ + "VPE_AXI_OUT_CFG", + "VPE_CMD_DIS_OFFSET_CFG", + "VPE_ENABLE", + "VPE_DISABLE", +}; +static uint32_t orig_src_y, orig_src_cbcr; + +#define CHECKED_COPY_FROM_USER(in) { \ + if (copy_from_user((in), (void __user *)cmd->value, \ + cmd->length)) { \ + rc = -EFAULT; \ + break; \ + } \ +} + +#define msm_dequeue_vpe(queue, member) ({ \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + __q->len--; \ + qcmd = list_first_entry(&__q->list, \ + struct msm_queue_cmd, member); \ + list_del_init(&qcmd->member); \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + qcmd; \ +}) + +/* +static struct vpe_cmd_type vpe_cmd[] = { + {VPE_DUMMY_0, 0}, + {VPE_SET_CLK, 0}, + {VPE_RESET, 0}, + {VPE_START, 0}, + {VPE_ABORT, 0}, + {VPE_OPERATION_MODE_CFG, VPE_OPERATION_MODE_CFG_LEN}, + {VPE_INPUT_PLANE_CFG, VPE_INPUT_PLANE_CFG_LEN}, + {VPE_OUTPUT_PLANE_CFG, VPE_OUTPUT_PLANE_CFG_LEN}, + {VPE_INPUT_PLANE_UPDATE, VPE_INPUT_PLANE_UPDATE_LEN}, + {VPE_SCALE_CFG_TYPE, VPE_SCALER_CONFIG_LEN}, + {VPE_ROTATION_CFG_TYPE, 0}, + {VPE_AXI_OUT_CFG, 0}, + {VPE_CMD_DIS_OFFSET_CFG, VPE_DIS_OFFSET_CFG_LEN}, +}; +*/ + +static long long vpe_do_div(long long num, long long den) +{ + do_div(num, den); + return num; +} + +static int vpe_start(void) +{ + /* enable the frame irq, bit 0 = Display list 0 ROI done */ + msm_io_w(1, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET); + msm_io_dump(vpe_device->vpebase + 0x10000, 0x250); + /* this triggers the operation. */ + msm_io_w(1, vpe_device->vpebase + VPE_DL0_START_OFFSET); + + return 0; +} + +void vpe_reset_state_variables(void) +{ + /* initialize local variables for state control, etc.*/ + vpe_ctrl->op_mode = 0; + vpe_ctrl->state = VPE_STATE_INIT; + spin_lock_init(&vpe_ctrl->tasklet_lock); + spin_lock_init(&vpe_ctrl->state_lock); + INIT_LIST_HEAD(&vpe_ctrl->tasklet_q); +} + +static void vpe_config_axi_default(void) +{ + msm_io_w(0x25, vpe_device->vpebase + VPE_AXI_ARB_2_OFFSET); + + CDBG("%s: yaddr %ld cbcraddr %ld", __func__, + vpe_ctrl->out_y_addr, vpe_ctrl->out_cbcr_addr); + + if (!vpe_ctrl->out_y_addr || !vpe_ctrl->out_cbcr_addr) + return; + + msm_io_w(vpe_ctrl->out_y_addr, + vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET); + /* for video CbCr address */ + msm_io_w(vpe_ctrl->out_cbcr_addr, + vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET); + +} + +static int vpe_reset(void) +{ + uint32_t vpe_version; + uint32_t rc; + + vpe_reset_state_variables(); + vpe_version = msm_io_r(vpe_device->vpebase + VPE_HW_VERSION_OFFSET); + CDBG("vpe_version = 0x%x\n", vpe_version); + + /* disable all interrupts.*/ + msm_io_w(0, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET); + /* clear all pending interrupts*/ + msm_io_w(0x1fffff, vpe_device->vpebase + VPE_INTR_CLEAR_OFFSET); + + /* write sw_reset to reset the core. */ + msm_io_w(0x10, vpe_device->vpebase + VPE_SW_RESET_OFFSET); + + /* then poll the reset bit, it should be self-cleared. */ + while (1) { + rc = + msm_io_r(vpe_device->vpebase + VPE_SW_RESET_OFFSET) & 0x10; + if (rc == 0) + break; + } + + /* at this point, hardware is reset. Then pogram to default + values. */ + msm_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE, + vpe_device->vpebase + VPE_AXI_RD_ARB_CONFIG_OFFSET); + + msm_io_w(VPE_CGC_ENABLE_VALUE, + vpe_device->vpebase + VPE_CGC_EN_OFFSET); + + msm_io_w(1, vpe_device->vpebase + VPE_CMD_MODE_OFFSET); + + msm_io_w(VPE_DEFAULT_OP_MODE_VALUE, + vpe_device->vpebase + VPE_OP_MODE_OFFSET); + + msm_io_w(VPE_DEFAULT_SCALE_CONFIG, + vpe_device->vpebase + VPE_SCALE_CONFIG_OFFSET); + + vpe_config_axi_default(); + return 0; +} + +int msm_vpe_cfg_update(void *pinfo) +{ + uint32_t rot_flag, rc = 0; + struct video_crop_t *pcrop = (struct video_crop_t *)pinfo; + + rot_flag = msm_io_r(vpe_device->vpebase + + VPE_OP_MODE_OFFSET) & 0xE00; + if (pinfo != NULL) { + CDBG("Crop info in2_w = %d, in2_h = %d " + "out2_h = %d out2_w = %d \n", pcrop->in2_w, + pcrop->in2_h, + pcrop->out2_h, pcrop->out2_w); + rc = vpe_update_scaler(pcrop); + } + CDBG("return rc = %d rot_flag = %d\n", rc, rot_flag); + rc |= rot_flag; + + return rc; +} + +void vpe_update_scale_coef(uint32_t *p) +{ + uint32_t i, offset; + offset = *p; + for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) { + msm_io_w(*(++p), vpe_device->vpebase + VPE_SCALE_COEFF_LSBn(i)); + msm_io_w(*(++p), vpe_device->vpebase + VPE_SCALE_COEFF_MSBn(i)); + } +} + +void vpe_input_plane_config(uint32_t *p) +{ + msm_io_w(*p, vpe_device->vpebase + VPE_SRC_FORMAT_OFFSET); + msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_UNPACK_PATTERN1_OFFSET); + msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_IMAGE_SIZE_OFFSET); + msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_YSTRIDE1_OFFSET); + msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_SIZE_OFFSET); + vpe_ctrl->in_h_w = *p; + msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_XY_OFFSET); +} + +void vpe_output_plane_config(uint32_t *p) +{ + msm_io_w(*p, vpe_device->vpebase + VPE_OUT_FORMAT_OFFSET); + msm_io_w(*(++p), vpe_device->vpebase + VPE_OUT_PACK_PATTERN1_OFFSET); + msm_io_w(*(++p), vpe_device->vpebase + VPE_OUT_YSTRIDE1_OFFSET); + msm_io_w(*(++p), vpe_device->vpebase + VPE_OUT_SIZE_OFFSET); + msm_io_w(*(++p), vpe_device->vpebase + VPE_OUT_XY_OFFSET); + vpe_ctrl->pcbcr_dis_offset = *(++p); +} + +static int vpe_operation_config(uint32_t *p) +{ + uint32_t outw, outh, temp; + msm_io_w(*p, vpe_device->vpebase + VPE_OP_MODE_OFFSET); + + temp = msm_io_r(vpe_device->vpebase + VPE_OUT_SIZE_OFFSET); + outw = temp & 0xFFF; + outh = (temp & 0xFFF0000) >> 16; + + if (*p++ & 0xE00) { + /* rotation enabled. */ + vpe_ctrl->out_w = outh; + vpe_ctrl->out_h = outw; + } else { + vpe_ctrl->out_w = outw; + vpe_ctrl->out_h = outh; + } + vpe_ctrl->dis_en = *p; + return 0; +} + +/* Later we can separate the rotation and scaler calc. If +* rotation is enabled, simply swap the destination dimension. +* And then pass the already swapped output size to this +* function. */ +static int vpe_update_scaler(struct video_crop_t *pcrop) +{ + uint32_t out_ROI_width, out_ROI_height; + uint32_t src_ROI_width, src_ROI_height; + + uint32_t rc = 0; /* default to no zoom. */ + /* + * phase_step_x, phase_step_y, phase_init_x and phase_init_y + * are represented in fixed-point, unsigned 3.29 format + */ + uint32_t phase_step_x = 0; + uint32_t phase_step_y = 0; + uint32_t phase_init_x = 0; + uint32_t phase_init_y = 0; + + uint32_t src_roi, src_x, src_y, src_xy, temp; + uint32_t yscale_filter_sel, xscale_filter_sel; + uint32_t scale_unit_sel_x, scale_unit_sel_y; + uint64_t numerator, denominator; + + if ((pcrop->in2_w >= pcrop->out2_w) && + (pcrop->in2_h >= pcrop->out2_h)) { + CDBG(" =======VPE no zoom needed.\n"); + + temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) + & 0xfffffffc; + msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET); + + + msm_io_w(0, vpe_device->vpebase + VPE_SRC_XY_OFFSET); + + CDBG("vpe_ctrl->in_h_w = %d \n", vpe_ctrl->in_h_w); + msm_io_w(vpe_ctrl->in_h_w , vpe_device->vpebase + + VPE_SRC_SIZE_OFFSET); + + return rc; + } + /* If fall through then scaler is needed.*/ + + CDBG("========VPE zoom needed.\n"); + /* assumption is both direction need zoom. this can be + improved. */ + temp = + msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) | 0x3; + msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET); + + src_ROI_width = pcrop->in2_w; + src_ROI_height = pcrop->in2_h; + out_ROI_width = pcrop->out2_w; + out_ROI_height = pcrop->out2_h; + + CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n", + src_ROI_width, src_ROI_height, out_ROI_width, + out_ROI_height); + src_roi = (src_ROI_height << 16) + src_ROI_width; + + msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET); + + src_x = (out_ROI_width - src_ROI_width)/2; + src_y = (out_ROI_height - src_ROI_height)/2; + + CDBG("src_x = %d, src_y=%d.\n", src_x, src_y); + + src_xy = src_y*(1<<16) + src_x; + msm_io_w(src_xy, vpe_device->vpebase + + VPE_SRC_XY_OFFSET); + CDBG("src_xy = %d, src_roi=%d.\n", src_xy, src_roi); + + /* decide whether to use FIR or M/N for scaling */ + if ((out_ROI_width == 1 && src_ROI_width < 4) || + (src_ROI_width < 4 * out_ROI_width - 3)) + scale_unit_sel_x = 0;/* use FIR scalar */ + else + scale_unit_sel_x = 1;/* use M/N scalar */ + + if ((out_ROI_height == 1 && src_ROI_height < 4) || + (src_ROI_height < 4 * out_ROI_height - 3)) + scale_unit_sel_y = 0;/* use FIR scalar */ + else + scale_unit_sel_y = 1;/* use M/N scalar */ + + /* calculate phase step for the x direction */ + + /* if destination is only 1 pixel wide, + the value of phase_step_x + is unimportant. Assigning phase_step_x to + src ROI width as an arbitrary value. */ + if (out_ROI_width == 1) + phase_step_x = (uint32_t) ((src_ROI_width) << + SCALER_PHASE_BITS); + + /* if using FIR scalar */ + else if (scale_unit_sel_x == 0) { + + /* Calculate the quotient ( src_ROI_width - 1 ) + / ( out_ROI_width - 1) + with u3.29 precision. Quotient is rounded up to + the larger 29th decimal point. */ + numerator = (uint64_t)(src_ROI_width - 1) << + SCALER_PHASE_BITS; + /* never equals to 0 because of the + "(out_ROI_width == 1 )"*/ + denominator = (uint64_t)(out_ROI_width - 1); + /* divide and round up to the larger 29th + decimal point. */ + phase_step_x = (uint32_t) vpe_do_div((numerator + + denominator - 1), denominator); + } else if (scale_unit_sel_x == 1) { /* if M/N scalar */ + /* Calculate the quotient ( src_ROI_width ) / + ( out_ROI_width) + with u3.29 precision. Quotient is rounded down to the + smaller 29th decimal point. */ + numerator = (uint64_t)(src_ROI_width) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_width); + phase_step_x = + (uint32_t) vpe_do_div(numerator, denominator); + } + /* calculate phase step for the y direction */ + + /* if destination is only 1 pixel wide, the value of + phase_step_x is unimportant. Assigning phase_step_x + to src ROI width as an arbitrary value. */ + if (out_ROI_height == 1) + phase_step_y = + (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); + + /* if FIR scalar */ + else if (scale_unit_sel_y == 0) { + /* Calculate the quotient ( src_ROI_height - 1 ) / + ( out_ROI_height - 1) + with u3.29 precision. Quotient is rounded up to the + larger 29th decimal point. */ + numerator = (uint64_t)(src_ROI_height - 1) << + SCALER_PHASE_BITS; + /* never equals to 0 because of the " + ( out_ROI_height == 1 )" case */ + denominator = (uint64_t)(out_ROI_height - 1); + /* Quotient is rounded up to the larger + 29th decimal point. */ + phase_step_y = + (uint32_t) vpe_do_div( + (numerator + denominator - 1), denominator); + } else if (scale_unit_sel_y == 1) { /* if M/N scalar */ + /* Calculate the quotient ( src_ROI_height ) + / ( out_ROI_height) + with u3.29 precision. Quotient is rounded down + to the smaller 29th decimal point. */ + numerator = (uint64_t)(src_ROI_height) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_height); + phase_step_y = (uint32_t) vpe_do_div( + numerator, denominator); + } + + /* decide which set of FIR coefficients to use */ + if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) + xscale_filter_sel = 0; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) + xscale_filter_sel = 1; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) + xscale_filter_sel = 2; + else + xscale_filter_sel = 3; + + if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) + yscale_filter_sel = 0; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) + yscale_filter_sel = 1; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) + yscale_filter_sel = 2; + else + yscale_filter_sel = 3; + + /* calculate phase init for the x direction */ + + /* if using FIR scalar */ + if (scale_unit_sel_x == 0) { + if (out_ROI_width == 1) + phase_init_x = + (uint32_t) ((src_ROI_width - 1) << + SCALER_PHASE_BITS); + else + phase_init_x = 0; + } else if (scale_unit_sel_x == 1) /* M over N scalar */ + phase_init_x = 0; + + /* calculate phase init for the y direction + if using FIR scalar */ + if (scale_unit_sel_y == 0) { + if (out_ROI_height == 1) + phase_init_y = + (uint32_t) ((src_ROI_height - + 1) << SCALER_PHASE_BITS); + else + phase_init_y = 0; + } else if (scale_unit_sel_y == 1) /* M over N scalar */ + phase_init_y = 0; + + CDBG("phase step x = %d, step y = %d.\n", + phase_step_x, phase_step_y); + CDBG("phase init x = %d, init y = %d.\n", + phase_init_x, phase_init_y); + + msm_io_w(phase_step_x, vpe_device->vpebase + + VPE_SCALE_PHASEX_STEP_OFFSET); + msm_io_w(phase_step_y, vpe_device->vpebase + + VPE_SCALE_PHASEY_STEP_OFFSET); + + msm_io_w(phase_init_x, vpe_device->vpebase + + VPE_SCALE_PHASEX_INIT_OFFSET); + + msm_io_w(phase_init_y, vpe_device->vpebase + + VPE_SCALE_PHASEY_INIT_OFFSET); + + return 1; +} + +static int vpe_update_scaler_with_dis(struct video_crop_t *pcrop, + struct dis_offset_type *dis_offset) +{ + uint32_t out_ROI_width, out_ROI_height; + uint32_t src_ROI_width, src_ROI_height; + + uint32_t rc = 0; /* default to no zoom. */ + /* + * phase_step_x, phase_step_y, phase_init_x and phase_init_y + * are represented in fixed-point, unsigned 3.29 format + */ + uint32_t phase_step_x = 0; + uint32_t phase_step_y = 0; + uint32_t phase_init_x = 0; + uint32_t phase_init_y = 0; + + uint32_t src_roi, temp; + int32_t src_x, src_y, src_xy; + uint32_t yscale_filter_sel, xscale_filter_sel; + uint32_t scale_unit_sel_x, scale_unit_sel_y; + uint64_t numerator, denominator; + int32_t zoom_dis_x, zoom_dis_y; + + CDBG("%s: pcrop->in2_w = %d, pcrop->in2_h = %d\n", __func__, + pcrop->in2_w, pcrop->in2_h); + CDBG("%s: pcrop->out2_w = %d, pcrop->out2_h = %d\n", __func__, + pcrop->out2_w, pcrop->out2_h); + + if ((pcrop->in2_w >= pcrop->out2_w) && + (pcrop->in2_h >= pcrop->out2_h)) { + CDBG(" =======VPE no zoom needed, DIS is still enabled. \n"); + + temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) + & 0xfffffffc; + msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET); + + /* no zoom, use dis offset directly. */ + src_xy = dis_offset->dis_offset_y * (1<<16) + + dis_offset->dis_offset_x; + + msm_io_w(src_xy, vpe_device->vpebase + VPE_SRC_XY_OFFSET); + + CDBG("vpe_ctrl->in_h_w = 0x%x \n", vpe_ctrl->in_h_w); + msm_io_w(vpe_ctrl->in_h_w, vpe_device->vpebase + + VPE_SRC_SIZE_OFFSET); + return rc; + } + /* If fall through then scaler is needed.*/ + + CDBG("========VPE zoom needed + DIS enabled.\n"); + /* assumption is both direction need zoom. this can be + improved. */ + temp = msm_io_r(vpe_device->vpebase + + VPE_OP_MODE_OFFSET) | 0x3; + msm_io_w(temp, vpe_device->vpebase + + VPE_OP_MODE_OFFSET); + zoom_dis_x = dis_offset->dis_offset_x * + pcrop->in2_w / pcrop->out2_w; + zoom_dis_y = dis_offset->dis_offset_y * + pcrop->in2_h / pcrop->out2_h; + + src_x = zoom_dis_x + (pcrop->out2_w-pcrop->in2_w)/2; + src_y = zoom_dis_y + (pcrop->out2_h-pcrop->in2_h)/2; + + out_ROI_width = vpe_ctrl->out_w; + out_ROI_height = vpe_ctrl->out_h; + + src_ROI_width = out_ROI_width * pcrop->in2_w / pcrop->out2_w; + src_ROI_height = out_ROI_height * pcrop->in2_h / pcrop->out2_h; + + /* clamp to output size. This is because along + processing, we mostly do truncation, therefore + dis_offset tends to be + smaller values. The intention was to make sure that the + offset does not exceed margin. But in the case it could + result src_roi bigger, due to subtract a smaller value. */ + CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n", + src_ROI_width, src_ROI_height, out_ROI_width, + out_ROI_height); + + src_roi = (src_ROI_height << 16) + src_ROI_width; + + msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET); + + CDBG("src_x = %d, src_y=%d.\n", src_x, src_y); + + src_xy = src_y*(1<<16) + src_x; + msm_io_w(src_xy, vpe_device->vpebase + + VPE_SRC_XY_OFFSET); + CDBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi); + + /* decide whether to use FIR or M/N for scaling */ + if ((out_ROI_width == 1 && src_ROI_width < 4) || + (src_ROI_width < 4 * out_ROI_width - 3)) + scale_unit_sel_x = 0;/* use FIR scalar */ + else + scale_unit_sel_x = 1;/* use M/N scalar */ + + if ((out_ROI_height == 1 && src_ROI_height < 4) || + (src_ROI_height < 4 * out_ROI_height - 3)) + scale_unit_sel_y = 0;/* use FIR scalar */ + else + scale_unit_sel_y = 1;/* use M/N scalar */ + /* calculate phase step for the x direction */ + + /* if destination is only 1 pixel wide, the value of + phase_step_x is unimportant. Assigning phase_step_x + to src ROI width as an arbitrary value. */ + if (out_ROI_width == 1) + phase_step_x = (uint32_t) ((src_ROI_width) << + SCALER_PHASE_BITS); + else if (scale_unit_sel_x == 0) { /* if using FIR scalar */ + /* Calculate the quotient ( src_ROI_width - 1 ) + / ( out_ROI_width - 1)with u3.29 precision. + Quotient is rounded up to the larger + 29th decimal point. */ + numerator = + (uint64_t)(src_ROI_width - 1) << + SCALER_PHASE_BITS; + /* never equals to 0 because of the " + (out_ROI_width == 1 )"*/ + denominator = (uint64_t)(out_ROI_width - 1); + /* divide and round up to the larger 29th + decimal point. */ + phase_step_x = (uint32_t) vpe_do_div( + (numerator + denominator - 1), denominator); + } else if (scale_unit_sel_x == 1) { /* if M/N scalar */ + /* Calculate the quotient + ( src_ROI_width ) / ( out_ROI_width) + with u3.29 precision. Quotient is rounded + down to the smaller 29th decimal point. */ + numerator = (uint64_t)(src_ROI_width) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_width); + phase_step_x = + (uint32_t) vpe_do_div(numerator, denominator); + } + /* calculate phase step for the y direction */ + + /* if destination is only 1 pixel wide, the value of + phase_step_x is unimportant. Assigning phase_step_x + to src ROI width as an arbitrary value. */ + if (out_ROI_height == 1) + phase_step_y = + (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); + else if (scale_unit_sel_y == 0) { /* if FIR scalar */ + /* Calculate the quotient + ( src_ROI_height - 1 ) / ( out_ROI_height - 1) + with u3.29 precision. Quotient is rounded up to the + larger 29th decimal point. */ + numerator = (uint64_t)(src_ROI_height - 1) << + SCALER_PHASE_BITS; + /* never equals to 0 because of the + "( out_ROI_height == 1 )" case */ + denominator = (uint64_t)(out_ROI_height - 1); + /* Quotient is rounded up to the larger 29th + decimal point. */ + phase_step_y = + (uint32_t) vpe_do_div( + (numerator + denominator - 1), denominator); + } else if (scale_unit_sel_y == 1) { /* if M/N scalar */ + /* Calculate the quotient ( src_ROI_height ) / ( out_ROI_height) + with u3.29 precision. Quotient is rounded down to the smaller + 29th decimal point. */ + numerator = (uint64_t)(src_ROI_height) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_height); + phase_step_y = (uint32_t) vpe_do_div( + numerator, denominator); + } + + /* decide which set of FIR coefficients to use */ + if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) + xscale_filter_sel = 0; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) + xscale_filter_sel = 1; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) + xscale_filter_sel = 2; + else + xscale_filter_sel = 3; + + if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) + yscale_filter_sel = 0; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) + yscale_filter_sel = 1; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) + yscale_filter_sel = 2; + else + yscale_filter_sel = 3; + + /* calculate phase init for the x direction */ + + /* if using FIR scalar */ + if (scale_unit_sel_x == 0) { + if (out_ROI_width == 1) + phase_init_x = + (uint32_t) ((src_ROI_width - 1) << + SCALER_PHASE_BITS); + else + phase_init_x = 0; + + } else if (scale_unit_sel_x == 1) /* M over N scalar */ + phase_init_x = 0; + + /* calculate phase init for the y direction + if using FIR scalar */ + if (scale_unit_sel_y == 0) { + if (out_ROI_height == 1) + phase_init_y = + (uint32_t) ((src_ROI_height - + 1) << SCALER_PHASE_BITS); + else + phase_init_y = 0; + + } else if (scale_unit_sel_y == 1) /* M over N scalar */ + phase_init_y = 0; + + CDBG("phase step x = %d, step y = %d.\n", + phase_step_x, phase_step_y); + CDBG("phase init x = %d, init y = %d.\n", + phase_init_x, phase_init_y); + + msm_io_w(phase_step_x, vpe_device->vpebase + + VPE_SCALE_PHASEX_STEP_OFFSET); + + msm_io_w(phase_step_y, vpe_device->vpebase + + VPE_SCALE_PHASEY_STEP_OFFSET); + + msm_io_w(phase_init_x, vpe_device->vpebase + + VPE_SCALE_PHASEX_INIT_OFFSET); + + msm_io_w(phase_init_y, vpe_device->vpebase + + VPE_SCALE_PHASEY_INIT_OFFSET); + + return 1; +} + +void msm_send_frame_to_vpe(uint32_t pyaddr, uint32_t pcbcraddr, + struct timespec *ts, int output_type) +{ + uint32_t temp_pyaddr = 0, temp_pcbcraddr = 0; + + CDBG("vpe input, pyaddr = 0x%x, pcbcraddr = 0x%x\n", + pyaddr, pcbcraddr); + msm_io_w(pyaddr, vpe_device->vpebase + VPE_SRCP0_ADDR_OFFSET); + msm_io_w(pcbcraddr, vpe_device->vpebase + VPE_SRCP1_ADDR_OFFSET); + + if (vpe_ctrl->state == VPE_STATE_ACTIVE) + CDBG(" =====VPE is busy!!! Wrong!========\n"); + + if (output_type != OUTPUT_TYPE_ST_R) + vpe_ctrl->ts = *ts; + + if (output_type == OUTPUT_TYPE_ST_L) { + vpe_ctrl->pcbcr_before_dis = msm_io_r(vpe_device->vpebase + + VPE_OUTP1_ADDR_OFFSET); + temp_pyaddr = msm_io_r(vpe_device->vpebase + + VPE_OUTP0_ADDR_OFFSET); + temp_pcbcraddr = temp_pyaddr + PAD_TO_2K(vpe_ctrl->out_w * + vpe_ctrl->out_h * 2, vpe_ctrl->pad_2k_bool); + msm_io_w(temp_pcbcraddr, vpe_device->vpebase + + VPE_OUTP1_ADDR_OFFSET); + } + + if (vpe_ctrl->dis_en) { + /* Changing the VPE output CBCR address, + to make Y/CBCR continuous */ + vpe_ctrl->pcbcr_before_dis = msm_io_r(vpe_device->vpebase + + VPE_OUTP1_ADDR_OFFSET); + temp_pyaddr = msm_io_r(vpe_device->vpebase + + VPE_OUTP0_ADDR_OFFSET); + temp_pcbcraddr = temp_pyaddr + vpe_ctrl->pcbcr_dis_offset; + msm_io_w(temp_pcbcraddr, vpe_device->vpebase + + VPE_OUTP1_ADDR_OFFSET); + } + + vpe_ctrl->output_type = output_type; + vpe_ctrl->state = VPE_STATE_ACTIVE; + vpe_start(); +} + +static int vpe_proc_general(struct msm_vpe_cmd *cmd) +{ + int rc = 0; + uint32_t *cmdp = NULL; + struct msm_queue_cmd *qcmd = NULL; + struct msm_vpe_buf_info *vpe_buf; + int turbo_mode = 0; + struct msm_sync *sync = (struct msm_sync *)vpe_ctrl->syncdata; + CDBG("vpe_proc_general: cmdID = %s, length = %d\n", + vpe_general_cmd[cmd->id], cmd->length); + switch (cmd->id) { + case VPE_ENABLE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto vpe_proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto vpe_proc_general_done; + } + turbo_mode = *((int *)(cmd->value)); + rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) + : vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE); + break; + case VPE_DISABLE: + rc = vpe_disable(); + break; + case VPE_RESET: + case VPE_ABORT: + rc = vpe_reset(); + break; + case VPE_START: + rc = vpe_start(); + break; + + case VPE_INPUT_PLANE_CFG: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto vpe_proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto vpe_proc_general_done; + } + vpe_input_plane_config(cmdp); + break; + + case VPE_OPERATION_MODE_CFG: + CDBG("cmd->length = %d\n", cmd->length); + if (cmd->length != VPE_OPERATION_MODE_CFG_LEN_ZSL) { + rc = -EINVAL; + goto vpe_proc_general_done; + } + cmdp = kmalloc(VPE_OPERATION_MODE_CFG_LEN_ZSL, + GFP_ATOMIC); + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + VPE_OPERATION_MODE_CFG_LEN_ZSL)) { + rc = -EFAULT; + goto vpe_proc_general_done; + } + rc = vpe_operation_config(cmdp); + CDBG("rc = %d \n", rc); + break; + + case VPE_OUTPUT_PLANE_CFG: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto vpe_proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto vpe_proc_general_done; + } + vpe_output_plane_config(cmdp); + break; + + case VPE_SCALE_CFG_TYPE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto vpe_proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto vpe_proc_general_done; + } + vpe_update_scale_coef(cmdp); + break; + + case VPE_CMD_DIS_OFFSET_CFG: { + struct msm_vfe_resp *vdata; + /* first get the dis offset and frame id. */ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto vpe_proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto vpe_proc_general_done; + } + /* get the offset. */ + vpe_ctrl->dis_offset = *(struct dis_offset_type *)cmdp; + qcmd = msm_dequeue_vpe(&sync->vpe_q, list_vpe_frame); + if (!qcmd) { + pr_err("%s: no video frame.\n", __func__); + kfree(cmdp); + return -EAGAIN; + } + vdata = (struct msm_vfe_resp *)(qcmd->command); + vpe_buf = &vdata->vpe_bf; + vpe_update_scaler_with_dis(&(vpe_buf->vpe_crop), + &(vpe_ctrl->dis_offset)); + + msm_send_frame_to_vpe(vpe_buf->y_phy, vpe_buf->cbcr_phy, + &(vpe_buf->ts), OUTPUT_TYPE_V); + + if (!qcmd || !atomic_read(&qcmd->on_heap)) { + kfree(cmdp); + return -EAGAIN; + } + if (!atomic_sub_return(1, &qcmd->on_heap)) + kfree(qcmd); + break; + } + + default: + break; + } +vpe_proc_general_done: + kfree(cmdp); + return rc; +} + +static void vpe_addr_convert(struct msm_vpe_phy_info *pinfo, + enum vpe_resp_msg type, void *data, void **ext, int32_t *elen) +{ + CDBG("In vpe_addr_convert type = %d\n", type); + switch (type) { + case VPE_MSG_OUTPUT_V: + pinfo->output_id = OUTPUT_TYPE_V; + break; + case VPE_MSG_OUTPUT_ST_R: + /* output_id will be used by user space only. */ + pinfo->output_id = OUTPUT_TYPE_V; + break; + default: + break; + } /* switch */ + + CDBG("In vpe_addr_convert output_id = %d\n", pinfo->output_id); + + pinfo->y_phy = + ((struct vpe_message *)data)->_u.msgOut.yBuffer; + pinfo->cbcr_phy = + ((struct vpe_message *)data)->_u.msgOut.cbcrBuffer; + *ext = vpe_ctrl->extdata; + *elen = vpe_ctrl->extlen; +} + +void vpe_proc_ops(uint8_t id, void *msg, size_t len) +{ + struct msm_vpe_resp *rp; + + rp = vpe_ctrl->resp->vpe_alloc(sizeof(struct msm_vpe_resp), + vpe_ctrl->syncdata, GFP_ATOMIC); + if (!rp) { + CDBG("rp: cannot allocate buffer\n"); + return; + } + + CDBG("vpe_proc_ops, msgId = %d rp->evt_msg.msg_id = %d\n", + id, rp->evt_msg.msg_id); + rp->evt_msg.type = MSM_CAMERA_MSG; + rp->evt_msg.msg_id = id; + rp->evt_msg.len = len; + rp->evt_msg.data = msg; + + switch (rp->evt_msg.msg_id) { + case MSG_ID_VPE_OUTPUT_V: + rp->type = VPE_MSG_OUTPUT_V; + vpe_addr_convert(&(rp->phy), VPE_MSG_OUTPUT_V, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + + case MSG_ID_VPE_OUTPUT_ST_R: + rp->type = VPE_MSG_OUTPUT_ST_R; + vpe_addr_convert(&(rp->phy), VPE_MSG_OUTPUT_ST_R, + rp->evt_msg.data, &(rp->extdata), + &(rp->extlen)); + break; + + case MSG_ID_VPE_OUTPUT_ST_L: + rp->type = VPE_MSG_OUTPUT_ST_L; + break; + + default: + rp->type = VPE_MSG_GENERAL; + break; + } + CDBG("%s: time = %ld\n", + __func__, vpe_ctrl->ts.tv_nsec); + + vpe_ctrl->resp->vpe_resp(rp, MSM_CAM_Q_VPE_MSG, + vpe_ctrl->syncdata, + &(vpe_ctrl->ts), GFP_ATOMIC); +} + +int vpe_config_axi(struct axidata *ad) +{ + uint32_t p1; + struct msm_pmem_region *regp1 = NULL; + CDBG("vpe_config_axi:bufnum1 = %d.\n", ad->bufnum1); + + if (ad->bufnum1 != 1) + return -EINVAL; + + regp1 = &(ad->region[0]); + /* for video Y address */ + p1 = (regp1->paddr + regp1->info.y_off); + msm_io_w(p1, vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET); + /* for video CbCr address */ + p1 = (regp1->paddr + regp1->info.cbcr_off); + msm_io_w(p1, vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET); + + return 0; +} + +int msm_vpe_config(struct msm_vpe_cfg_cmd *cmd, void *data) +{ + struct msm_vpe_cmd vpecmd; + int rc = 0; + if (copy_from_user(&vpecmd, + (void __user *)(cmd->value), + sizeof(vpecmd))) { + pr_err("%s %d: copy_from_user failed\n", __func__, + __LINE__); + return -EFAULT; + } + CDBG("%s: cmd_type %d\n", __func__, cmd->cmd_type); + switch (cmd->cmd_type) { + case CMD_VPE: + rc = vpe_proc_general(&vpecmd); + CDBG(" rc = %d\n", rc); + break; + + case CMD_AXI_CFG_VPE: + case CMD_AXI_CFG_SNAP_VPE: + case CMD_AXI_CFG_SNAP_THUMB_VPE: { + struct axidata *axid; + axid = data; + if (!axid) + return -EFAULT; + vpe_config_axi(axid); + break; + } + default: + break; + } + CDBG("%s: rc = %d\n", __func__, rc); + return rc; +} + +void msm_vpe_offset_update(int frame_pack, uint32_t pyaddr, uint32_t pcbcraddr, + struct timespec *ts, int output_id, struct msm_st_half st_half, + int frameid) +{ + struct msm_vpe_buf_info vpe_buf; + uint32_t input_stride; + + vpe_buf.vpe_crop.in2_w = st_half.stCropInfo.in_w; + vpe_buf.vpe_crop.in2_h = st_half.stCropInfo.in_h; + vpe_buf.vpe_crop.out2_w = st_half.stCropInfo.out_w; + vpe_buf.vpe_crop.out2_h = st_half.stCropInfo.out_h; + vpe_ctrl->dis_offset.dis_offset_x = st_half.pix_x_off; + vpe_ctrl->dis_offset.dis_offset_y = st_half.pix_y_off; + vpe_ctrl->dis_offset.frame_id = frameid; + vpe_ctrl->frame_pack = frame_pack; + vpe_ctrl->output_type = output_id; + + input_stride = (st_half.buf_cbcr_stride * (1<<16)) + + st_half.buf_y_stride; + + msm_io_w(input_stride, vpe_device->vpebase + VPE_SRC_YSTRIDE1_OFFSET); + + vpe_update_scaler_with_dis(&(vpe_buf.vpe_crop), + &(vpe_ctrl->dis_offset)); + + msm_send_frame_to_vpe(pyaddr, pcbcraddr, ts, output_id); +} + +static void vpe_send_outmsg(uint8_t msgid, uint32_t pyaddr, + uint32_t pcbcraddr) +{ + struct vpe_message msg; + uint8_t outid; + msg._d = outid = msgid; + msg._u.msgOut.output_id = msgid; + msg._u.msgOut.yBuffer = pyaddr; + msg._u.msgOut.cbcrBuffer = pcbcraddr; + vpe_proc_ops(outid, &msg, sizeof(struct vpe_message)); + return; +} + +int msm_vpe_reg(struct msm_vpe_callback *presp) +{ + if (presp && presp->vpe_resp) + vpe_ctrl->resp = presp; + + return 0; +} + +static void vpe_send_msg_no_payload(enum VPE_MESSAGE_ID id) +{ + struct vpe_message msg; + + CDBG("vfe31_send_msg_no_payload\n"); + msg._d = id; + vpe_proc_ops(id, &msg, 0); +} + +static void vpe_do_tasklet(unsigned long data) +{ + unsigned long flags; + uint32_t pyaddr = 0, pcbcraddr = 0; + uint32_t src_y, src_cbcr, temp; + + struct vpe_isr_queue_cmd_type *qcmd = NULL; + + CDBG("=== vpe_do_tasklet start === \n"); + + spin_lock_irqsave(&vpe_ctrl->tasklet_lock, flags); + qcmd = list_first_entry(&vpe_ctrl->tasklet_q, + struct vpe_isr_queue_cmd_type, list); + + if (!qcmd) { + spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags); + return; + } + + list_del(&qcmd->list); + spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags); + + /* interrupt to be processed, *qcmd has the payload. */ + if (qcmd->irq_status & 0x1) { + if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_L) { + CDBG("vpe left frame done.\n"); + vpe_ctrl->output_type = 0; + CDBG("vpe send out msg.\n"); + orig_src_y = msm_io_r(vpe_device->vpebase + + VPE_SRCP0_ADDR_OFFSET); + orig_src_cbcr = msm_io_r(vpe_device->vpebase + + VPE_SRCP1_ADDR_OFFSET); + + pyaddr = msm_io_r(vpe_device->vpebase + + VPE_OUTP0_ADDR_OFFSET); + pcbcraddr = msm_io_r(vpe_device->vpebase + + VPE_OUTP1_ADDR_OFFSET); + CDBG("%s: out_w = %d, out_h = %d\n", __func__, + vpe_ctrl->out_w, vpe_ctrl->out_h); + + if ((vpe_ctrl->frame_pack == TOP_DOWN_FULL) || + (vpe_ctrl->frame_pack == TOP_DOWN_HALF)) { + msm_io_w(pyaddr + (vpe_ctrl->out_w * + vpe_ctrl->out_h), vpe_device->vpebase + + VPE_OUTP0_ADDR_OFFSET); + msm_io_w(pcbcraddr + (vpe_ctrl->out_w * + vpe_ctrl->out_h/2), + vpe_device->vpebase + + VPE_OUTP1_ADDR_OFFSET); + } else if ((vpe_ctrl->frame_pack == + SIDE_BY_SIDE_HALF) || (vpe_ctrl->frame_pack == + SIDE_BY_SIDE_FULL)) { + msm_io_w(pyaddr + vpe_ctrl->out_w, + vpe_device->vpebase + + VPE_OUTP0_ADDR_OFFSET); + msm_io_w(pcbcraddr + vpe_ctrl->out_w, + vpe_device->vpebase + + VPE_OUTP1_ADDR_OFFSET); + } else + CDBG("%s: Invalid packing = %d\n", __func__, + vpe_ctrl->frame_pack); + + vpe_send_msg_no_payload(MSG_ID_VPE_OUTPUT_ST_L); + vpe_ctrl->state = VPE_STATE_INIT; + kfree(qcmd); + return; + } else if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_R) { + src_y = orig_src_y; + src_cbcr = orig_src_cbcr; + CDBG("%s: out_w = %d, out_h = %d\n", __func__, + vpe_ctrl->out_w, vpe_ctrl->out_h); + + if ((vpe_ctrl->frame_pack == TOP_DOWN_FULL) || + (vpe_ctrl->frame_pack == TOP_DOWN_HALF)) { + pyaddr = msm_io_r(vpe_device->vpebase + + VPE_OUTP0_ADDR_OFFSET) - + (vpe_ctrl->out_w * vpe_ctrl->out_h); + } else if ((vpe_ctrl->frame_pack == + SIDE_BY_SIDE_HALF) || (vpe_ctrl->frame_pack == + SIDE_BY_SIDE_FULL)) { + pyaddr = msm_io_r(vpe_device->vpebase + + VPE_OUTP0_ADDR_OFFSET) - vpe_ctrl->out_w; + } else + CDBG("%s: Invalid packing = %d\n", __func__, + vpe_ctrl->frame_pack); + + pcbcraddr = vpe_ctrl->pcbcr_before_dis; + } else { + src_y = msm_io_r(vpe_device->vpebase + + VPE_SRCP0_ADDR_OFFSET); + src_cbcr = msm_io_r(vpe_device->vpebase + + VPE_SRCP1_ADDR_OFFSET); + pyaddr = msm_io_r(vpe_device->vpebase + + VPE_OUTP0_ADDR_OFFSET); + pcbcraddr = msm_io_r(vpe_device->vpebase + + VPE_OUTP1_ADDR_OFFSET); + } + + if (vpe_ctrl->dis_en) + pcbcraddr = vpe_ctrl->pcbcr_before_dis; + + msm_io_w(src_y, + vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET); + msm_io_w(src_cbcr, + vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET); + + temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) & + 0xFFFFFFFC; + msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET); + + /* now pass this frame to msm_camera.c. */ + if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_R) { + CDBG("vpe send out R msg.\n"); + vpe_send_outmsg(MSG_ID_VPE_OUTPUT_ST_R, pyaddr, + pcbcraddr); + } else if (vpe_ctrl->output_type == OUTPUT_TYPE_V) { + CDBG("vpe send out V msg.\n"); + vpe_send_outmsg(MSG_ID_VPE_OUTPUT_V, pyaddr, pcbcraddr); + } + + vpe_ctrl->output_type = 0; + vpe_ctrl->state = VPE_STATE_INIT; /* put it back to idle. */ + + } + kfree(qcmd); +} +DECLARE_TASKLET(vpe_tasklet, vpe_do_tasklet, 0); + +static irqreturn_t vpe_parse_irq(int irq_num, void *data) +{ + unsigned long flags; + uint32_t irq_status = 0; + struct vpe_isr_queue_cmd_type *qcmd; + + CDBG("vpe_parse_irq.\n"); + /* read and clear back-to-back. */ + irq_status = msm_io_r_mb(vpe_device->vpebase + + VPE_INTR_STATUS_OFFSET); + msm_io_w_mb(irq_status, vpe_device->vpebase + + VPE_INTR_CLEAR_OFFSET); + + msm_io_w(0, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET); + + if (irq_status == 0) { + pr_err("%s: irq_status = 0,Something is wrong!\n", __func__); + return IRQ_HANDLED; + } + irq_status &= 0x1; + /* apply mask. only interested in bit 0. */ + if (irq_status) { + qcmd = kzalloc(sizeof(struct vpe_isr_queue_cmd_type), + GFP_ATOMIC); + if (!qcmd) { + pr_err("%s: qcmd malloc failed!\n", __func__); + return IRQ_HANDLED; + } + /* must be 0x1 now. so in bottom half we don't really + need to check. */ + qcmd->irq_status = irq_status & 0x1; + spin_lock_irqsave(&vpe_ctrl->tasklet_lock, flags); + list_add_tail(&qcmd->list, &vpe_ctrl->tasklet_q); + spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags); + tasklet_schedule(&vpe_tasklet); + } + return IRQ_HANDLED; +} + +static int vpe_enable_irq(void) +{ + uint32_t rc = 0; + rc = request_irq(vpe_device->vpeirq, + vpe_parse_irq, + IRQF_TRIGGER_HIGH, "vpe", 0); + return rc; +} + +int msm_vpe_open(void) +{ + int rc = 0; + + CDBG("%s: In \n", __func__); + + vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL); + if (!vpe_ctrl) { + pr_err("%s: no memory!\n", __func__); + return -ENOMEM; + } + + spin_lock_init(&vpe_ctrl->ops_lock); + CDBG("%s: Out\n", __func__); + + return rc; +} + +int msm_vpe_release(void) +{ + /* clean up....*/ + int rc = 0; + CDBG("%s: state %d\n", __func__, vpe_ctrl->state); + if (vpe_ctrl->state != VPE_STATE_IDLE) + rc = vpe_disable(); + + kfree(vpe_ctrl); + return rc; +} + + +int vpe_enable(uint32_t clk_rate) +{ + int rc = 0; + unsigned long flags = 0; + /* don't change the order of clock and irq.*/ + CDBG("%s: enable_clock rate %u\n", __func__, clk_rate); + spin_lock_irqsave(&vpe_ctrl->ops_lock, flags); + if (vpe_ctrl->state != VPE_STATE_IDLE) { + CDBG("%s: VPE already enabled", __func__); + spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags); + return 0; + } + vpe_ctrl->state = VPE_STATE_INIT; + spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags); + + rc = msm_camio_vpe_clk_enable(clk_rate); + if (rc < 0) { + pr_err("%s: msm_camio_vpe_clk_enable failed", __func__); + vpe_ctrl->state = VPE_STATE_IDLE; + return rc; + } + + CDBG("%s: enable_irq\n", __func__); + vpe_enable_irq(); + + /* initialize the data structure - lock, queue etc. */ + spin_lock_init(&vpe_ctrl->tasklet_lock); + INIT_LIST_HEAD(&vpe_ctrl->tasklet_q); + + return rc; +} + +int vpe_disable(void) +{ + int rc = 0; + unsigned long flags = 0; + CDBG("%s: called", __func__); + spin_lock_irqsave(&vpe_ctrl->ops_lock, flags); + if (vpe_ctrl->state == VPE_STATE_IDLE) { + CDBG("%s: VPE already disabled", __func__); + spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags); + return 0; + } + vpe_ctrl->state = VPE_STATE_IDLE; + spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags); + vpe_ctrl->out_y_addr = msm_io_r(vpe_device->vpebase + + VPE_OUTP0_ADDR_OFFSET); + vpe_ctrl->out_cbcr_addr = msm_io_r(vpe_device->vpebase + + VPE_OUTP1_ADDR_OFFSET); + free_irq(vpe_device->vpeirq, 0); + tasklet_kill(&vpe_tasklet); + rc = msm_camio_vpe_clk_disable(); + return rc; +} + +static int __msm_vpe_probe(struct platform_device *pdev) +{ + int rc = 0; + struct resource *vpemem, *vpeirq, *vpeio; + void __iomem *vpebase; + + /* first allocate */ + + vpe_device = &vpe_device_data; + memset(vpe_device, 0, sizeof(struct vpe_device_type)); + + /* does the device exist? */ + vpeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!vpeirq) { + pr_err("%s: no vpe irq resource.\n", __func__); + rc = -ENODEV; + goto vpe_free_device; + } + vpemem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!vpemem) { + pr_err("%s: no vpe mem resource!\n", __func__); + rc = -ENODEV; + goto vpe_free_device; + } + vpeio = request_mem_region(vpemem->start, + resource_size(vpemem), pdev->name); + if (!vpeio) { + pr_err("%s: VPE region already claimed.\n", __func__); + rc = -EBUSY; + goto vpe_free_device; + } + + vpebase = + ioremap(vpemem->start, + (vpemem->end - vpemem->start) + 1); + if (!vpebase) { + pr_err("%s: vpe ioremap failed.\n", __func__); + rc = -ENOMEM; + goto vpe_release_mem_region; + } + + /* Fall through, _probe is successful. */ + vpe_device->vpeirq = vpeirq->start; + vpe_device->vpemem = vpemem; + vpe_device->vpeio = vpeio; + vpe_device->vpebase = vpebase; + return rc; /* this rc should be zero.*/ + + iounmap(vpe_device->vpebase); /* this path should never occur */ + vpe_device->vpebase = NULL; +/* from this part it is error handling. */ +vpe_release_mem_region: + release_mem_region(vpemem->start, (vpemem->end - vpemem->start) + 1); +vpe_free_device: + return rc; /* this rc should have error code. */ +} + +static int __msm_vpe_remove(struct platform_device *pdev) +{ + struct resource *vpemem; + vpemem = vpe_device->vpemem; + + iounmap(vpe_device->vpebase); + vpe_device->vpebase = NULL; + release_mem_region(vpemem->start, + (vpemem->end - vpemem->start) + 1); + return 0; +} + +static struct platform_driver msm_vpe_driver = { + .probe = __msm_vpe_probe, + .remove = __msm_vpe_remove, + .driver = { + .name = "msm_vpe", + .owner = THIS_MODULE, + }, +}; + +static int __init msm_vpe_init(void) +{ + return platform_driver_register(&msm_vpe_driver); +} +module_init(msm_vpe_init); + +static void __exit msm_vpe_exit(void) +{ + platform_driver_unregister(&msm_vpe_driver); +} +module_exit(msm_vpe_exit); + +MODULE_DESCRIPTION("msm vpe 1.0 driver"); +MODULE_VERSION("msm vpe driver 1.0"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/msm_vpe1.h b/drivers/media/video/msm_zsl/msm_vpe1.h new file mode 100644 index 00000000000..1110b056e9c --- /dev/null +++ b/drivers/media/video/msm_zsl/msm_vpe1.h @@ -0,0 +1,252 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _msm_vpe1_h_ +#define _msm_vpe1_h_ + +#include + +/*********** start of register offset *********************/ +#define VPE_INTR_ENABLE_OFFSET 0x0020 +#define VPE_INTR_STATUS_OFFSET 0x0024 +#define VPE_INTR_CLEAR_OFFSET 0x0028 +#define VPE_DL0_START_OFFSET 0x0030 +#define VPE_HW_VERSION_OFFSET 0x0070 +#define VPE_SW_RESET_OFFSET 0x0074 +#define VPE_AXI_RD_ARB_CONFIG_OFFSET 0x0078 +#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET 0x007C +#define VPE_CGC_EN_OFFSET 0x0100 +#define VPE_CMD_STATUS_OFFSET 0x10008 +#define VPE_PROFILE_EN_OFFSET 0x10010 +#define VPE_PROFILE_COUNT_OFFSET 0x10014 +#define VPE_CMD_MODE_OFFSET 0x10060 +#define VPE_SRC_SIZE_OFFSET 0x10108 +#define VPE_SRCP0_ADDR_OFFSET 0x1010C +#define VPE_SRCP1_ADDR_OFFSET 0x10110 +#define VPE_SRC_YSTRIDE1_OFFSET 0x1011C +#define VPE_SRC_FORMAT_OFFSET 0x10124 +#define VPE_SRC_UNPACK_PATTERN1_OFFSET 0x10128 +#define VPE_OP_MODE_OFFSET 0x10138 +#define VPE_SCALE_PHASEX_INIT_OFFSET 0x1013C +#define VPE_SCALE_PHASEY_INIT_OFFSET 0x10140 +#define VPE_SCALE_PHASEX_STEP_OFFSET 0x10144 +#define VPE_SCALE_PHASEY_STEP_OFFSET 0x10148 +#define VPE_OUT_FORMAT_OFFSET 0x10150 +#define VPE_OUT_PACK_PATTERN1_OFFSET 0x10154 +#define VPE_OUT_SIZE_OFFSET 0x10164 +#define VPE_OUTP0_ADDR_OFFSET 0x10168 +#define VPE_OUTP1_ADDR_OFFSET 0x1016C +#define VPE_OUT_YSTRIDE1_OFFSET 0x10178 +#define VPE_OUT_XY_OFFSET 0x1019C +#define VPE_SRC_XY_OFFSET 0x10200 +#define VPE_SRC_IMAGE_SIZE_OFFSET 0x10208 +#define VPE_SCALE_CONFIG_OFFSET 0x10230 +#define VPE_DEINT_STATUS_OFFSET 0x30000 +#define VPE_DEINT_DECISION_OFFSET 0x30004 +#define VPE_DEINT_COEFF0_OFFSET 0x30010 +#define VPE_SCALE_STATUS_OFFSET 0x50000 +#define VPE_SCALE_SVI_PARAM_OFFSET 0x50010 +#define VPE_SCALE_SHARPEN_CFG_OFFSET 0x50020 +#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400 +#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404 + +#define VPE_AXI_ARB_2_OFFSET 0x004C + +#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n)) +#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n)) +#define VPE_SCALE_COEFF_NUM 32 + +/*********** end of register offset ********************/ + + +#define VPE_HARDWARE_VERSION 0x00080308 +#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/ +#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924 +#define VPE_CMD_MODE_VALUE 0x1 +#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004 +#define VPE_CGC_ENABLE_VALUE 0xffff +#define VPE_DEFAULT_SCALE_CONFIG 0x3c + +#define VPE_NORMAL_MODE_CLOCK_RATE 150000000 +#define VPE_TURBO_MODE_CLOCK_RATE 200000000 +/**************************************************/ +/*********** Start of command id ******************/ +/**************************************************/ +enum VPE_CMD_ID_ENUM { + VPE_DUMMY_0 = 0, + VPE_SET_CLK, + VPE_RESET, + VPE_START, + VPE_ABORT, + VPE_OPERATION_MODE_CFG, /* 5 */ + VPE_INPUT_PLANE_CFG, + VPE_OUTPUT_PLANE_CFG, + VPE_INPUT_PLANE_UPDATE, + VPE_SCALE_CFG_TYPE, + VPE_ROTATION_CFG_TYPE, /* 10 */ + VPE_AXI_OUT_CFG, + VPE_CMD_DIS_OFFSET_CFG, + VPE_ENABLE, + VPE_DISABLE, +}; + +/* Length of each command. In bytes. (payload only) */ +#define VPE_OPERATION_MODE_CFG_LEN_ZSL 8 +#define VPE_INPUT_PLANE_CFG_LEN 24 +#define VPE_OUTPUT_PLANE_CFG_LEN_ZSL 20 +#define VPE_INPUT_PLANE_UPDATE_LEN 12 +#define VPE_SCALER_CONFIG_LEN 260 +#define VPE_DIS_OFFSET_CFG_LEN 12 +/**************************************************/ +/*********** End of command id ********************/ +/**************************************************/ + +struct msm_vpe_cmd { + int32_t id; + uint16_t length; + void *value; +}; + +struct vpe_cmd_type { + uint16_t id; + uint32_t length; +}; + +struct vpe_isr_queue_cmd_type { + struct list_head list; + uint32_t irq_status; +}; + +enum VPE_MESSAGE_ID { + MSG_ID_VPE_OUTPUT_V = 7, /* To match with that of VFE */ + MSG_ID_VPE_OUTPUT_ST_L, + MSG_ID_VPE_OUTPUT_ST_R, +}; + +enum vpe_state { + VPE_STATE_IDLE, + VPE_STATE_INIT, + VPE_STATE_ACTIVE, +}; + +struct vpe_device_type { + /* device related. */ + int vpeirq; + void __iomem *vpebase; + struct resource *vpemem; + struct resource *vpeio; + void *device_extdata; +}; + +struct dis_offset_type { + int32_t dis_offset_x; + int32_t dis_offset_y; + uint32_t frame_id; +}; + +struct vpe_ctrl_type { + spinlock_t tasklet_lock; + spinlock_t state_lock; + spinlock_t ops_lock; + + struct list_head tasklet_q; + void *syncdata; + uint16_t op_mode; + void *extdata; + uint32_t extlen; + struct msm_vpe_callback *resp; + uint32_t in_h_w; + uint32_t out_h; /* this is BEFORE rotation. */ + uint32_t out_w; /* this is BEFORE rotation. */ + uint32_t dis_en; + struct timespec ts; + struct dis_offset_type dis_offset; + uint32_t pcbcr_before_dis; + uint32_t pcbcr_dis_offset; + int output_type; + int frame_pack; + uint8_t pad_2k_bool; + enum vpe_state state; + unsigned long out_y_addr; + unsigned long out_cbcr_addr; +}; + +/* +* vpe_input_update +* +* Define the parameters for output plane +*/ +/* this is the dimension of ROI. width / height. */ +struct vpe_src_size_packed { + uint32_t src_w; + uint32_t src_h; +}; + +struct vpe_src_xy_packed { + uint32_t src_x; + uint32_t src_y; +}; + +struct vpe_input_plane_update_type { + struct vpe_src_size_packed src_roi_size; + /* DIS updates this set. */ + struct vpe_src_xy_packed src_roi_offset; + /* input address*/ + uint8_t *src_p0_addr; + uint8_t *src_p1_addr; +}; + +struct vpe_msg_stats{ + uint32_t buffer; + uint32_t frameCounter; +}; + +struct vpe_msg_output { + uint8_t output_id; + uint32_t yBuffer; + uint32_t cbcrBuffer; + uint32_t frameCounter; +}; + +struct vpe_message { + uint8_t _d; + union { + struct vpe_msg_output msgOut; + struct vpe_msg_stats msgStats; + } _u; +}; + +#define SCALER_PHASE_BITS 29 +#define HAL_MDP_PHASE_STEP_2P50 0x50000000 +#define HAL_MDP_PHASE_STEP_1P66 0x35555555 +#define HAL_MDP_PHASE_STEP_1P25 0x28000000 + +struct phase_val_t { + int32_t phase_init_x; + int32_t phase_init_y; + int32_t phase_step_x; + int32_t phase_step_y; +}; + +extern struct vpe_ctrl_type *vpe_ctrl; + +int msm_vpe_open(void); +int msm_vpe_release(void); +int msm_vpe_reg(struct msm_vpe_callback *presp); +void msm_send_frame_to_vpe(uint32_t pyaddr, uint32_t pcbcraddr, + struct timespec *ts, int output_id); +int msm_vpe_config(struct msm_vpe_cfg_cmd *cmd, void *data); +int msm_vpe_cfg_update(void *pinfo); +void msm_vpe_offset_update(int frame_pack, uint32_t pyaddr, uint32_t pcbcraddr, + struct timespec *ts, int output_id, struct msm_st_half st_half, + int frameid); +#endif /*_msm_vpe1_h_*/ diff --git a/drivers/media/video/msm_zsl/mt9d112.c b/drivers/media/video/msm_zsl/mt9d112.c new file mode 100644 index 00000000000..a7b5156c1ec --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9d112.c @@ -0,0 +1,845 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mt9d112.h" + +/* Micron MT9D112 Registers and their values */ +/* Sensor Core Registers */ +#define REG_MT9D112_MODEL_ID 0x3000 +#define MT9D112_MODEL_ID 0x1580 + +/* SOC Registers Page 1 */ +#define REG_MT9D112_SENSOR_RESET 0x301A +#define REG_MT9D112_STANDBY_CONTROL 0x3202 +#define REG_MT9D112_MCU_BOOT 0x3386 + +#define SENSOR_DEBUG 0 + +struct mt9d112_work { + struct work_struct work; +}; + +static struct mt9d112_work *mt9d112_sensorw; +static struct i2c_client *mt9d112_client; + +struct mt9d112_ctrl { + const struct msm_camera_sensor_info *sensordata; +}; + + +static struct mt9d112_ctrl *mt9d112_ctrl; + +static DECLARE_WAIT_QUEUE_HEAD(mt9d112_wait_queue); +DEFINE_SEMAPHORE(mt9d112_sem); +static int16_t mt9d112_effect = CAMERA_EFFECT_OFF; + +/*============================================================= + EXTERNAL DECLARATIONS +==============================================================*/ +extern struct mt9d112_reg mt9d112_regs; + + +/*=============================================================*/ + +static int mt9d112_reset(const struct msm_camera_sensor_info *dev) +{ + int rc = 0; + + rc = gpio_request(dev->sensor_reset, "mt9d112"); + + if (!rc) { + rc = gpio_direction_output(dev->sensor_reset, 0); + msleep(20); + gpio_set_value_cansleep(dev->sensor_reset, 1); + msleep(20); + } + + return rc; +} + +static int32_t mt9d112_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + +#if SENSOR_DEBUG + if (length == 2) + CDBG("msm_io_i2c_w: 0x%04x 0x%04x\n", + *(u16 *) txdata, *(u16 *) (txdata + 2)); + else if (length == 4) + CDBG("msm_io_i2c_w: 0x%04x\n", *(u16 *) txdata); + else + CDBG("msm_io_i2c_w: length = %d\n", length); +#endif + if (i2c_transfer(mt9d112_client->adapter, msg, 1) < 0) { + CDBG("mt9d112_i2c_txdata failed\n"); + return -EIO; + } + + return 0; +} + +static int32_t mt9d112_i2c_write(unsigned short saddr, + unsigned short waddr, unsigned short wdata, enum mt9d112_width width) +{ + int32_t rc = -EIO; + unsigned char buf[4]; + + memset(buf, 0, sizeof(buf)); + switch (width) { + case WORD_LEN: { + buf[0] = (waddr & 0xFF00)>>8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00)>>8; + buf[3] = (wdata & 0x00FF); + + rc = mt9d112_i2c_txdata(saddr, buf, 4); + } + break; + + case BYTE_LEN: { + buf[0] = waddr; + buf[1] = wdata; + rc = mt9d112_i2c_txdata(saddr, buf, 2); + } + break; + + default: + break; + } + + if (rc < 0) + CDBG( + "i2c_write failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + + return rc; +} + +static int32_t mt9d112_i2c_write_table( + struct mt9d112_i2c_reg_conf const *reg_conf_tbl, + int num_of_items_in_table) +{ + int i; + int32_t rc = -EIO; + + for (i = 0; i < num_of_items_in_table; i++) { + rc = mt9d112_i2c_write(mt9d112_client->addr, + reg_conf_tbl->waddr, reg_conf_tbl->wdata, + reg_conf_tbl->width); + if (rc < 0) + break; + if (reg_conf_tbl->mdelay_time != 0) + mdelay(reg_conf_tbl->mdelay_time); + reg_conf_tbl++; + } + + return rc; +} + +static int mt9d112_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + +#if SENSOR_DEBUG + if (length == 2) + CDBG("msm_io_i2c_r: 0x%04x 0x%04x\n", + *(u16 *) rxdata, *(u16 *) (rxdata + 2)); + else if (length == 4) + CDBG("msm_io_i2c_r: 0x%04x\n", *(u16 *) rxdata); + else + CDBG("msm_io_i2c_r: length = %d\n", length); +#endif + + if (i2c_transfer(mt9d112_client->adapter, msgs, 2) < 0) { + CDBG("mt9d112_i2c_rxdata failed!\n"); + return -EIO; + } + + return 0; +} + +static int32_t mt9d112_i2c_read(unsigned short saddr, + unsigned short raddr, unsigned short *rdata, enum mt9d112_width width) +{ + int32_t rc = 0; + unsigned char buf[4]; + + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + + switch (width) { + case WORD_LEN: { + buf[0] = (raddr & 0xFF00)>>8; + buf[1] = (raddr & 0x00FF); + + rc = mt9d112_i2c_rxdata(saddr, buf, 2); + if (rc < 0) + return rc; + + *rdata = buf[0] << 8 | buf[1]; + } + break; + + default: + break; + } + + if (rc < 0) + CDBG("mt9d112_i2c_read failed!\n"); + + return rc; +} + +static int32_t mt9d112_set_lens_roll_off(void) +{ + int32_t rc = 0; + rc = mt9d112_i2c_write_table(&mt9d112_regs.rftbl[0], + mt9d112_regs.rftbl_size); + return rc; +} + +static long mt9d112_reg_init(void) +{ + int32_t array_length; + int32_t i; + long rc; + + /* PLL Setup Start */ + rc = mt9d112_i2c_write_table(&mt9d112_regs.plltbl[0], + mt9d112_regs.plltbl_size); + + if (rc < 0) + return rc; + /* PLL Setup End */ + + array_length = mt9d112_regs.prev_snap_reg_settings_size; + + /* Configure sensor for Preview mode and Snapshot mode */ + for (i = 0; i < array_length; i++) { + rc = mt9d112_i2c_write(mt9d112_client->addr, + mt9d112_regs.prev_snap_reg_settings[i].register_address, + mt9d112_regs.prev_snap_reg_settings[i].register_value, + WORD_LEN); + + if (rc < 0) + return rc; + } + + /* Configure for Noise Reduction, Saturation and Aperture Correction */ + array_length = mt9d112_regs.noise_reduction_reg_settings_size; + + for (i = 0; i < array_length; i++) { + rc = mt9d112_i2c_write(mt9d112_client->addr, + mt9d112_regs.noise_reduction_reg_settings[i].register_address, + mt9d112_regs.noise_reduction_reg_settings[i].register_value, + WORD_LEN); + + if (rc < 0) + return rc; + } + + /* Set Color Kill Saturation point to optimum value */ + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x35A4, + 0x0593, + WORD_LEN); + if (rc < 0) + return rc; + + rc = mt9d112_i2c_write_table(&mt9d112_regs.stbl[0], + mt9d112_regs.stbl_size); + if (rc < 0) + return rc; + + rc = mt9d112_set_lens_roll_off(); + if (rc < 0) + return rc; + + return 0; +} + +static long mt9d112_set_effect(int mode, int effect) +{ + uint16_t reg_addr; + uint16_t reg_val; + long rc = 0; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + /* Context A Special Effects */ + reg_addr = 0x2799; + break; + + case SENSOR_RAW_SNAPSHOT_MODE: + case SENSOR_SNAPSHOT_MODE: + /* Context B Special Effects */ + reg_addr = 0x279B; + break; + + default: + reg_addr = 0x2799; + break; + } + + switch (effect) { + case CAMERA_EFFECT_OFF: { + reg_val = 0x6440; + + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, reg_addr, WORD_LEN); + if (rc < 0) + return rc; + + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, reg_val, WORD_LEN); + if (rc < 0) + return rc; + } + break; + + case CAMERA_EFFECT_MONO: { + reg_val = 0x6441; + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, reg_addr, WORD_LEN); + if (rc < 0) + return rc; + + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, reg_val, WORD_LEN); + if (rc < 0) + return rc; + } + break; + + case CAMERA_EFFECT_NEGATIVE: { + reg_val = 0x6443; + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, reg_addr, WORD_LEN); + if (rc < 0) + return rc; + + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, reg_val, WORD_LEN); + if (rc < 0) + return rc; + } + break; + + case CAMERA_EFFECT_SOLARIZE: { + reg_val = 0x6445; + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, reg_addr, WORD_LEN); + if (rc < 0) + return rc; + + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, reg_val, WORD_LEN); + if (rc < 0) + return rc; + } + break; + + case CAMERA_EFFECT_SEPIA: { + reg_val = 0x6442; + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, reg_addr, WORD_LEN); + if (rc < 0) + return rc; + + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, reg_val, WORD_LEN); + if (rc < 0) + return rc; + } + break; + + default: { + reg_val = 0x6440; + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, reg_addr, WORD_LEN); + if (rc < 0) + return rc; + + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, reg_val, WORD_LEN); + if (rc < 0) + return rc; + + return -EINVAL; + } + } + mt9d112_effect = effect; + /* Refresh Sequencer */ + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0xA103, WORD_LEN); + if (rc < 0) + return rc; + + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x0005, WORD_LEN); + + return rc; +} + +static long mt9d112_set_sensor_mode(int mode) +{ + uint16_t clock; + long rc = 0; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0xA20C, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x0004, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0xA215, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x0004, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0xA20B, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x0000, WORD_LEN); + if (rc < 0) + return rc; + + clock = 0x23C; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x341C, clock, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0xA103, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x0001, WORD_LEN); + if (rc < 0) + return rc; + mdelay(5); + + break; + + case SENSOR_SNAPSHOT_MODE: + /* Switch to lower fps for Snapshot */ + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x341C, 0x0120, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0xA120, WORD_LEN); + if (rc < 0) + return rc; + + msleep(40);/*waiting for the delay of one frame*/ + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x0002, WORD_LEN); + if (rc < 0) + return rc; + + msleep(80);/*waiting for the delay of two frames*/ + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0xA103, WORD_LEN); + if (rc < 0) + return rc; + + msleep(40);/*waiting for the delay of one frame*/ + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x0002, WORD_LEN); + if (rc < 0) + return rc; + break; + + case SENSOR_RAW_SNAPSHOT_MODE: + /* Setting the effect to CAMERA_EFFECT_OFF */ + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0x279B, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x6440, WORD_LEN); + if (rc < 0) + return rc; + msleep(40);/*waiting for the delay of one frame*/ + /* Switch to lower fps for Snapshot */ + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x341C, 0x0120, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0xA120, WORD_LEN); + if (rc < 0) + return rc; + + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x0002, WORD_LEN); + if (rc < 0) + return rc; + msleep(80);/*waiting for the delay of two frames frame*/ + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x338C, 0xA103, WORD_LEN); + if (rc < 0) + return rc; + msleep(40);/*waiting for the delay of one frame*/ + rc = + mt9d112_i2c_write(mt9d112_client->addr, + 0x3390, 0x0002, WORD_LEN); + if (rc < 0) + return rc; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int mt9d112_sensor_init_probe(const struct msm_camera_sensor_info *data) +{ + uint16_t model_id = 0; + int rc = 0; + + CDBG("init entry \n"); + rc = mt9d112_reset(data); + if (rc < 0) { + CDBG("reset failed!\n"); + goto init_probe_fail; + } + + msm_camio_clk_rate_set(24000000); + msleep(20); + + /* Micron suggested Power up block Start: + * Put MCU into Reset - Stop MCU */ + rc = mt9d112_i2c_write(mt9d112_client->addr, + REG_MT9D112_MCU_BOOT, 0x0501, WORD_LEN); + if (rc < 0) + goto init_probe_fail; + + /* Pull MCU from Reset - Start MCU */ + rc = mt9d112_i2c_write(mt9d112_client->addr, + REG_MT9D112_MCU_BOOT, 0x0500, WORD_LEN); + if (rc < 0) + goto init_probe_fail; + + mdelay(5); + + /* Micron Suggested - Power up block */ + rc = mt9d112_i2c_write(mt9d112_client->addr, + REG_MT9D112_SENSOR_RESET, 0x0ACC, WORD_LEN); + if (rc < 0) + goto init_probe_fail; + + rc = mt9d112_i2c_write(mt9d112_client->addr, + REG_MT9D112_STANDBY_CONTROL, 0x0008, WORD_LEN); + if (rc < 0) + goto init_probe_fail; + + /* FUSED_DEFECT_CORRECTION */ + rc = mt9d112_i2c_write(mt9d112_client->addr, + 0x33F4, 0x031D, WORD_LEN); + if (rc < 0) + goto init_probe_fail; + + mdelay(5); + + /* Micron suggested Power up block End */ + /* Read the Model ID of the sensor */ + rc = mt9d112_i2c_read(mt9d112_client->addr, + REG_MT9D112_MODEL_ID, &model_id, WORD_LEN); + if (rc < 0) + goto init_probe_fail; + + CDBG("mt9d112 model_id = 0x%x\n", model_id); + + /* Check if it matches it with the value in Datasheet */ + if (model_id != MT9D112_MODEL_ID) { + rc = -EINVAL; + goto init_probe_fail; + } + + rc = mt9d112_reg_init(); + if (rc < 0) + goto init_probe_fail; + + return rc; + +init_probe_fail: + return rc; +} + +int mt9d112_sensor_init(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + + mt9d112_ctrl = kzalloc(sizeof(struct mt9d112_ctrl), GFP_KERNEL); + if (!mt9d112_ctrl) { + CDBG("mt9d112_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + if (data) + mt9d112_ctrl->sensordata = data; + + /* Input MCLK = 24MHz */ + msm_camio_clk_rate_set(24000000); + mdelay(5); + + msm_camio_camif_pad_reg_reset(); + + rc = mt9d112_sensor_init_probe(data); + if (rc < 0) { + CDBG("mt9d112_sensor_init failed!\n"); + goto init_fail; + } + +init_done: + return rc; + +init_fail: + kfree(mt9d112_ctrl); + return rc; +} + +static int mt9d112_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&mt9d112_wait_queue); + return 0; +} + +int mt9d112_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cfg_data; + long rc = 0; + + if (copy_from_user(&cfg_data, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + /* down(&mt9d112_sem); */ + + CDBG("mt9d112_ioctl, cfgtype = %d, mode = %d\n", + cfg_data.cfgtype, cfg_data.mode); + + switch (cfg_data.cfgtype) { + case CFG_SET_MODE: + rc = mt9d112_set_sensor_mode( + cfg_data.mode); + break; + + case CFG_SET_EFFECT: + rc = mt9d112_set_effect(cfg_data.mode, + cfg_data.cfg.effect); + break; + + case CFG_GET_AF_MAX_STEPS: + default: + rc = -EINVAL; + break; + } + + /* up(&mt9d112_sem); */ + + return rc; +} + +int mt9d112_sensor_release(void) +{ + int rc = 0; + + /* down(&mt9d112_sem); */ + gpio_set_value_cansleep(mt9d112_ctrl->sensordata->sensor_reset, 0); + msleep(20); + gpio_free(mt9d112_ctrl->sensordata->sensor_reset); + kfree(mt9d112_ctrl); + /* up(&mt9d112_sem); */ + + return rc; +} + +static int mt9d112_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + rc = -ENOTSUPP; + goto probe_failure; + } + + mt9d112_sensorw = + kzalloc(sizeof(struct mt9d112_work), GFP_KERNEL); + + if (!mt9d112_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, mt9d112_sensorw); + mt9d112_init_client(client); + mt9d112_client = client; + + CDBG("mt9d112_probe succeeded!\n"); + + return 0; + +probe_failure: + kfree(mt9d112_sensorw); + mt9d112_sensorw = NULL; + CDBG("mt9d112_probe failed!\n"); + return rc; +} + +static const struct i2c_device_id mt9d112_i2c_id[] = { + { "mt9d112", 0}, + { }, +}; + +static struct i2c_driver mt9d112_i2c_driver = { + .id_table = mt9d112_i2c_id, + .probe = mt9d112_i2c_probe, + .remove = __exit_p(mt9d112_i2c_remove), + .driver = { + .name = "mt9d112", + }, +}; + +static int mt9d112_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = i2c_add_driver(&mt9d112_i2c_driver); + if (rc < 0 || mt9d112_client == NULL) { + rc = -ENOTSUPP; + goto probe_done; + } + + /* Input MCLK = 24MHz */ + msm_camio_clk_rate_set(24000000); + mdelay(5); + + rc = mt9d112_sensor_init_probe(info); + if (rc < 0) { + gpio_free(info->sensor_reset); + goto probe_done; + } + s->s_init = mt9d112_sensor_init; + s->s_release = mt9d112_sensor_release; + s->s_config = mt9d112_sensor_config; + s->s_camera_type = FRONT_CAMERA_2D; + s->s_mount_angle = 0; + gpio_set_value_cansleep(info->sensor_reset, 0); + msleep(20); + gpio_free(info->sensor_reset); + +probe_done: + CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__); + return rc; +} + +static int __mt9d112_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, mt9d112_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __mt9d112_probe, + .driver = { + .name = "msm_camera_mt9d112", + .owner = THIS_MODULE, + }, +}; + +static int __init mt9d112_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(mt9d112_init); diff --git a/drivers/media/video/msm_zsl/mt9d112.h b/drivers/media/video/msm_zsl/mt9d112.h new file mode 100644 index 00000000000..309fcec05b4 --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9d112.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef MT9D112_H +#define MT9D112_H + +#include +#include + +extern struct mt9d112_reg mt9d112_regs; + +enum mt9d112_width { + WORD_LEN, + BYTE_LEN +}; + +struct mt9d112_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; + enum mt9d112_width width; + unsigned short mdelay_time; +}; + +struct mt9d112_reg { + const struct register_address_value_pair *prev_snap_reg_settings; + uint16_t prev_snap_reg_settings_size; + const struct register_address_value_pair *noise_reduction_reg_settings; + uint16_t noise_reduction_reg_settings_size; + const struct mt9d112_i2c_reg_conf *plltbl; + uint16_t plltbl_size; + const struct mt9d112_i2c_reg_conf *stbl; + uint16_t stbl_size; + const struct mt9d112_i2c_reg_conf *rftbl; + uint16_t rftbl_size; +}; + +#endif /* MT9D112_H */ diff --git a/drivers/media/video/msm_zsl/mt9d112_reg.c b/drivers/media/video/msm_zsl/mt9d112_reg.c new file mode 100644 index 00000000000..ba279cf85df --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9d112_reg.c @@ -0,0 +1,316 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "mt9d112.h" + + +struct register_address_value_pair const +preview_snapshot_mode_reg_settings_array[] = { + {0x338C, 0x2703}, + {0x3390, 800}, /* Output Width (P) = 640 */ + {0x338C, 0x2705}, + {0x3390, 600}, /* Output Height (P) = 480 */ + {0x338C, 0x2707}, + {0x3390, 0x0640}, /* Output Width (S) = 1600 */ + {0x338C, 0x2709}, + {0x3390, 0x04B0}, /* Output Height (S) = 1200 */ + {0x338C, 0x270D}, + {0x3390, 0x0000}, /* Row Start (P) = 0 */ + {0x338C, 0x270F}, + {0x3390, 0x0000}, /* Column Start (P) = 0 */ + {0x338C, 0x2711}, + {0x3390, 0x04BD}, /* Row End (P) = 1213 */ + {0x338C, 0x2713}, + {0x3390, 0x064D}, /* Column End (P) = 1613 */ + {0x338C, 0x2715}, + {0x3390, 0x0000}, /* Extra Delay (P) = 0 */ + {0x338C, 0x2717}, + {0x3390, 0x2111}, /* Row Speed (P) = 8465 */ + {0x338C, 0x2719}, + {0x3390, 0x046C}, /* Read Mode (P) = 1132 */ + {0x338C, 0x271B}, + {0x3390, 0x024F}, /* Sensor_Sample_Time_pck(P) = 591 */ + {0x338C, 0x271D}, + {0x3390, 0x0102}, /* Sensor_Fine_Correction(P) = 258 */ + {0x338C, 0x271F}, + {0x3390, 0x0279}, /* Sensor_Fine_IT_min(P) = 633 */ + {0x338C, 0x2721}, + {0x3390, 0x0155}, /* Sensor_Fine_IT_max_margin(P) = 341 */ + {0x338C, 0x2723}, + {0x3390, 659}, /* Frame Lines (P) = 679 */ + {0x338C, 0x2725}, + {0x3390, 0x061B}, /* Line Length (P) = 1563 */ + {0x338C, 0x2727}, + {0x3390, 0x2020}, + {0x338C, 0x2729}, + {0x3390, 0x2020}, + {0x338C, 0x272B}, + {0x3390, 0x1020}, + {0x338C, 0x272D}, + {0x3390, 0x2007}, + {0x338C, 0x272F}, + {0x3390, 0x0004}, /* Row Start(S) = 4 */ + {0x338C, 0x2731}, + {0x3390, 0x0004}, /* Column Start(S) = 4 */ + {0x338C, 0x2733}, + {0x3390, 0x04BB}, /* Row End(S) = 1211 */ + {0x338C, 0x2735}, + {0x3390, 0x064B}, /* Column End(S) = 1611 */ + {0x338C, 0x2737}, + {0x3390, 0x04CE}, /* Extra Delay(S) = 1230 */ + {0x338C, 0x2739}, + {0x3390, 0x2111}, /* Row Speed(S) = 8465 */ + {0x338C, 0x273B}, + {0x3390, 0x0024}, /* Read Mode(S) = 36 */ + {0x338C, 0x273D}, + {0x3390, 0x0120}, /* Sensor sample time pck(S) = 288 */ + {0x338C, 0x2741}, + {0x3390, 0x0169}, /* Sensor_Fine_IT_min(P) = 361 */ + {0x338C, 0x2745}, + {0x3390, 0x04FF}, /* Frame Lines(S) = 1279 */ + {0x338C, 0x2747}, + {0x3390, 0x0824}, /* Line Length(S) = 2084 */ + {0x338C, 0x2751}, + {0x3390, 0x0000}, /* Crop_X0(P) = 0 */ + {0x338C, 0x2753}, + {0x3390, 0x0320}, /* Crop_X1(P) = 800 */ + {0x338C, 0x2755}, + {0x3390, 0x0000}, /* Crop_Y0(P) = 0 */ + {0x338C, 0x2757}, + {0x3390, 0x0258}, /* Crop_Y1(P) = 600 */ + {0x338C, 0x275F}, + {0x3390, 0x0000}, /* Crop_X0(S) = 0 */ + {0x338C, 0x2761}, + {0x3390, 0x0640}, /* Crop_X1(S) = 1600 */ + {0x338C, 0x2763}, + {0x3390, 0x0000}, /* Crop_Y0(S) = 0 */ + {0x338C, 0x2765}, + {0x3390, 0x04B0}, /* Crop_Y1(S) = 1200 */ + {0x338C, 0x222E}, + {0x3390, 0x00A0}, /* R9 Step = 160 */ + {0x338C, 0xA408}, + {0x3390, 0x001F}, + {0x338C, 0xA409}, + {0x3390, 0x0021}, + {0x338C, 0xA40A}, + {0x3390, 0x0025}, + {0x338C, 0xA40B}, + {0x3390, 0x0027}, + {0x338C, 0x2411}, + {0x3390, 0x00A0}, + {0x338C, 0x2413}, + {0x3390, 0x00C0}, + {0x338C, 0x2415}, + {0x3390, 0x00A0}, + {0x338C, 0x2417}, + {0x3390, 0x00C0}, + {0x338C, 0x2799}, + {0x3390, 0x6408}, /* MODE_SPEC_EFFECTS(P) */ + {0x338C, 0x279B}, + {0x3390, 0x6408}, /* MODE_SPEC_EFFECTS(S) */ +}; + +static struct register_address_value_pair const +noise_reduction_reg_settings_array[] = { + {0x338C, 0xA76D}, + {0x3390, 0x0003}, + {0x338C, 0xA76E}, + {0x3390, 0x0003}, + {0x338C, 0xA76F}, + {0x3390, 0}, + {0x338C, 0xA770}, + {0x3390, 21}, + {0x338C, 0xA771}, + {0x3390, 37}, + {0x338C, 0xA772}, + {0x3390, 63}, + {0x338C, 0xA773}, + {0x3390, 100}, + {0x338C, 0xA774}, + {0x3390, 128}, + {0x338C, 0xA775}, + {0x3390, 151}, + {0x338C, 0xA776}, + {0x3390, 169}, + {0x338C, 0xA777}, + {0x3390, 186}, + {0x338C, 0xA778}, + {0x3390, 199}, + {0x338C, 0xA779}, + {0x3390, 210}, + {0x338C, 0xA77A}, + {0x3390, 220}, + {0x338C, 0xA77B}, + {0x3390, 228}, + {0x338C, 0xA77C}, + {0x3390, 234}, + {0x338C, 0xA77D}, + {0x3390, 240}, + {0x338C, 0xA77E}, + {0x3390, 244}, + {0x338C, 0xA77F}, + {0x3390, 248}, + {0x338C, 0xA780}, + {0x3390, 252}, + {0x338C, 0xA781}, + {0x3390, 255}, + {0x338C, 0xA782}, + {0x3390, 0}, + {0x338C, 0xA783}, + {0x3390, 21}, + {0x338C, 0xA784}, + {0x3390, 37}, + {0x338C, 0xA785}, + {0x3390, 63}, + {0x338C, 0xA786}, + {0x3390, 100}, + {0x338C, 0xA787}, + {0x3390, 128}, + {0x338C, 0xA788}, + {0x3390, 151}, + {0x338C, 0xA789}, + {0x3390, 169}, + {0x338C, 0xA78A}, + {0x3390, 186}, + {0x338C, 0xA78B}, + {0x3390, 199}, + {0x338C, 0xA78C}, + {0x3390, 210}, + {0x338C, 0xA78D}, + {0x3390, 220}, + {0x338C, 0xA78E}, + {0x3390, 228}, + {0x338C, 0xA78F}, + {0x3390, 234}, + {0x338C, 0xA790}, + {0x3390, 240}, + {0x338C, 0xA791}, + {0x3390, 244}, + {0x338C, 0xA793}, + {0x3390, 252}, + {0x338C, 0xA794}, + {0x3390, 255}, + {0x338C, 0xA103}, + {0x3390, 6}, +}; + +static const struct mt9d112_i2c_reg_conf const lens_roll_off_tbl[] = { + { 0x34CE, 0x81A0, WORD_LEN, 0 }, + { 0x34D0, 0x6331, WORD_LEN, 0 }, + { 0x34D2, 0x3394, WORD_LEN, 0 }, + { 0x34D4, 0x9966, WORD_LEN, 0 }, + { 0x34D6, 0x4B25, WORD_LEN, 0 }, + { 0x34D8, 0x2670, WORD_LEN, 0 }, + { 0x34DA, 0x724C, WORD_LEN, 0 }, + { 0x34DC, 0xFFFD, WORD_LEN, 0 }, + { 0x34DE, 0x00CA, WORD_LEN, 0 }, + { 0x34E6, 0x00AC, WORD_LEN, 0 }, + { 0x34EE, 0x0EE1, WORD_LEN, 0 }, + { 0x34F6, 0x0D87, WORD_LEN, 0 }, + { 0x3500, 0xE1F7, WORD_LEN, 0 }, + { 0x3508, 0x1CF4, WORD_LEN, 0 }, + { 0x3510, 0x1D28, WORD_LEN, 0 }, + { 0x3518, 0x1F26, WORD_LEN, 0 }, + { 0x3520, 0x2220, WORD_LEN, 0 }, + { 0x3528, 0x333D, WORD_LEN, 0 }, + { 0x3530, 0x15D9, WORD_LEN, 0 }, + { 0x3538, 0xCFB8, WORD_LEN, 0 }, + { 0x354C, 0x05FE, WORD_LEN, 0 }, + { 0x3544, 0x05F8, WORD_LEN, 0 }, + { 0x355C, 0x0596, WORD_LEN, 0 }, + { 0x3554, 0x0611, WORD_LEN, 0 }, + { 0x34E0, 0x00F2, WORD_LEN, 0 }, + { 0x34E8, 0x00A8, WORD_LEN, 0 }, + { 0x34F0, 0x0F7B, WORD_LEN, 0 }, + { 0x34F8, 0x0CD7, WORD_LEN, 0 }, + { 0x3502, 0xFEDB, WORD_LEN, 0 }, + { 0x350A, 0x13E4, WORD_LEN, 0 }, + { 0x3512, 0x1F2C, WORD_LEN, 0 }, + { 0x351A, 0x1D20, WORD_LEN, 0 }, + { 0x3522, 0x2422, WORD_LEN, 0 }, + { 0x352A, 0x2925, WORD_LEN, 0 }, + { 0x3532, 0x1D04, WORD_LEN, 0 }, + { 0x353A, 0xFBF2, WORD_LEN, 0 }, + { 0x354E, 0x0616, WORD_LEN, 0 }, + { 0x3546, 0x0597, WORD_LEN, 0 }, + { 0x355E, 0x05CD, WORD_LEN, 0 }, + { 0x3556, 0x0529, WORD_LEN, 0 }, + { 0x34E4, 0x00B2, WORD_LEN, 0 }, + { 0x34EC, 0x005E, WORD_LEN, 0 }, + { 0x34F4, 0x0F43, WORD_LEN, 0 }, + { 0x34FC, 0x0E2F, WORD_LEN, 0 }, + { 0x3506, 0xF9FC, WORD_LEN, 0 }, + { 0x350E, 0x0CE4, WORD_LEN, 0 }, + { 0x3516, 0x1E1E, WORD_LEN, 0 }, + { 0x351E, 0x1B19, WORD_LEN, 0 }, + { 0x3526, 0x151B, WORD_LEN, 0 }, + { 0x352E, 0x1416, WORD_LEN, 0 }, + { 0x3536, 0x10FC, WORD_LEN, 0 }, + { 0x353E, 0xC018, WORD_LEN, 0 }, + { 0x3552, 0x06B4, WORD_LEN, 0 }, + { 0x354A, 0x0506, WORD_LEN, 0 }, + { 0x3562, 0x06AB, WORD_LEN, 0 }, + { 0x355A, 0x063A, WORD_LEN, 0 }, + { 0x34E2, 0x00E5, WORD_LEN, 0 }, + { 0x34EA, 0x008B, WORD_LEN, 0 }, + { 0x34F2, 0x0E4C, WORD_LEN, 0 }, + { 0x34FA, 0x0CA3, WORD_LEN, 0 }, + { 0x3504, 0x0907, WORD_LEN, 0 }, + { 0x350C, 0x1DFD, WORD_LEN, 0 }, + { 0x3514, 0x1E24, WORD_LEN, 0 }, + { 0x351C, 0x2529, WORD_LEN, 0 }, + { 0x3524, 0x1D20, WORD_LEN, 0 }, + { 0x352C, 0x2332, WORD_LEN, 0 }, + { 0x3534, 0x10E9, WORD_LEN, 0 }, + { 0x353C, 0x0BCB, WORD_LEN, 0 }, + { 0x3550, 0x04EF, WORD_LEN, 0 }, + { 0x3548, 0x0609, WORD_LEN, 0 }, + { 0x3560, 0x0580, WORD_LEN, 0 }, + { 0x3558, 0x05DD, WORD_LEN, 0 }, + { 0x3540, 0x0000, WORD_LEN, 0 }, + { 0x3542, 0x0000, WORD_LEN, 0 } +}; + +static const struct mt9d112_i2c_reg_conf const pll_setup_tbl[] = { + { 0x341E, 0x8F09, WORD_LEN, 0 }, + { 0x341C, 0x0250, WORD_LEN, 0 }, + { 0x341E, 0x8F09, WORD_LEN, 5 }, + { 0x341E, 0x8F08, WORD_LEN, 0 } +}; + +/* Refresh Sequencer */ +static const struct mt9d112_i2c_reg_conf const sequencer_tbl[] = { + { 0x338C, 0x2799, WORD_LEN, 0}, + { 0x3390, 0x6440, WORD_LEN, 5}, + { 0x338C, 0x279B, WORD_LEN, 0}, + { 0x3390, 0x6440, WORD_LEN, 5}, + { 0x338C, 0xA103, WORD_LEN, 0}, + { 0x3390, 0x0005, WORD_LEN, 5}, + { 0x338C, 0xA103, WORD_LEN, 0}, + { 0x3390, 0x0006, WORD_LEN, 5} +}; + +struct mt9d112_reg mt9d112_regs = { + .prev_snap_reg_settings = &preview_snapshot_mode_reg_settings_array[0], + .prev_snap_reg_settings_size = ARRAY_SIZE( + preview_snapshot_mode_reg_settings_array), + .noise_reduction_reg_settings = &noise_reduction_reg_settings_array[0], + .noise_reduction_reg_settings_size = ARRAY_SIZE( + noise_reduction_reg_settings_array), + .plltbl = pll_setup_tbl, + .plltbl_size = ARRAY_SIZE(pll_setup_tbl), + .stbl = sequencer_tbl, + .stbl_size = ARRAY_SIZE(sequencer_tbl), + .rftbl = lens_roll_off_tbl, + .rftbl_size = ARRAY_SIZE(lens_roll_off_tbl) +}; diff --git a/drivers/media/video/msm_zsl/mt9d113.c b/drivers/media/video/msm_zsl/mt9d113.c new file mode 100644 index 00000000000..8e81bda5949 --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9d113.c @@ -0,0 +1,656 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mt9d113.h" + +/* Micron MT9D113 Registers and their values */ +#define REG_MT9D113_MODEL_ID 0x0000 +#define MT9D113_MODEL_ID 0x2580 +#define Q8 0x00000100 + +struct mt9d113_work { + struct work_struct work; +}; + +static struct mt9d113_work *mt9d113_sensorw; +static struct i2c_client *mt9d113_client; + +struct mt9d113_ctrl { + const struct msm_camera_sensor_info *sensordata; + uint32_t sensormode; + uint32_t fps_divider;/* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */ + uint16_t fps; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + uint16_t config_csi; + enum mt9d113_resolution_t prev_res; + enum mt9d113_resolution_t pict_res; + enum mt9d113_resolution_t curr_res; + enum mt9d113_test_mode_t set_test; +}; + +static struct mt9d113_ctrl *mt9d113_ctrl; + +static DECLARE_WAIT_QUEUE_HEAD(mt9d113_wait_queue); +DEFINE_MUTEX(mt9d113_mut); + +static int mt9d113_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + if (i2c_transfer(mt9d113_client->adapter, msgs, 2) < 0) { + CDBG("mt9d113_i2c_rxdata failed!\n"); + return -EIO; + } + return 0; +} + +static int32_t mt9d113_i2c_read(unsigned short saddr, + unsigned short raddr, + unsigned short *rdata, + enum mt9d113_width width) +{ + int32_t rc = 0; + unsigned char buf[4]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + switch (width) { + case WORD_LEN: { + buf[0] = (raddr & 0xFF00)>>8; + buf[1] = (raddr & 0x00FF); + rc = mt9d113_i2c_rxdata(saddr, buf, 2); + if (rc < 0) + return rc; + *rdata = buf[0] << 8 | buf[1]; + } + break; + default: + break; + } + if (rc < 0) + CDBG("mt9d113_i2c_read failed !\n"); + return rc; +} + +static int32_t mt9d113_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(mt9d113_client->adapter, msg, 1) < 0) { + CDBG("mt9d113_i2c_txdata failed\n"); + return -EIO; + } + return 0; +} + +static int32_t mt9d113_i2c_write(unsigned short saddr, + unsigned short waddr, + unsigned short wdata, + enum mt9d113_width width) +{ + int32_t rc = -EIO; + unsigned char buf[4]; + memset(buf, 0, sizeof(buf)); + switch (width) { + case WORD_LEN: { + buf[0] = (waddr & 0xFF00)>>8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00)>>8; + buf[3] = (wdata & 0x00FF); + rc = mt9d113_i2c_txdata(saddr, buf, 4); + } + break; + case BYTE_LEN: { + buf[0] = waddr; + buf[1] = wdata; + rc = mt9d113_i2c_txdata(saddr, buf, 2); + } + break; + default: + break; + } + if (rc < 0) + printk(KERN_ERR + "i2c_write failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + return rc; +} + +static int32_t mt9d113_i2c_write_table( + struct mt9d113_i2c_reg_conf + const *reg_conf_tbl, + int num_of_items_in_table) +{ + int i; + int32_t rc = -EIO; + for (i = 0; i < num_of_items_in_table; i++) { + rc = mt9d113_i2c_write(mt9d113_client->addr, + reg_conf_tbl->waddr, reg_conf_tbl->wdata, + WORD_LEN); + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +static long mt9d113_reg_init(void) +{ + uint16_t data = 0; + int32_t rc = 0; + int count = 0; + struct msm_camera_csi_params mt9d113_csi_params; + if (!mt9d113_ctrl->config_csi) { + mt9d113_csi_params.lane_cnt = 1; + mt9d113_csi_params.data_format = CSI_8BIT; + mt9d113_csi_params.lane_assign = 0xe4; + mt9d113_csi_params.dpcm_scheme = 0; + mt9d113_csi_params.settle_cnt = 0x14; + rc = msm_camio_csi_config(&mt9d113_csi_params); + mt9d113_ctrl->config_csi = 1; + msleep(50); + } + /* Disable parallel and enable mipi*/ + rc = mt9d113_i2c_write(mt9d113_client->addr, + 0x001A, + 0x0051, WORD_LEN); + rc = mt9d113_i2c_write(mt9d113_client->addr, + 0x001A, + 0x0050, + WORD_LEN); + msleep(20); + rc = mt9d113_i2c_write(mt9d113_client->addr, + 0x001A, + 0x0058, + WORD_LEN); + + /* Preset pll settings begin*/ + rc = mt9d113_i2c_write_table(&mt9d113_regs.pll_tbl[0], + mt9d113_regs.pll_tbl_size); + if (rc < 0) + return rc; + rc = mt9d113_i2c_read(mt9d113_client->addr, + 0x0014, &data, WORD_LEN); + data = data&0x8000; + /* Poll*/ + while (data == 0x0000) { + data = 0; + rc = mt9d113_i2c_read(mt9d113_client->addr, + 0x0014, &data, WORD_LEN); + data = data & 0x8000; + usleep_range(11000, 12000); + count++; + if (count == 100) { + CDBG(" Timeout:1\n"); + break; + } + } + rc = mt9d113_i2c_write(mt9d113_client->addr, + 0x0014, + 0x20FA, + WORD_LEN); + + /*Preset pll Ends*/ + mt9d113_i2c_write(mt9d113_client->addr, + 0x0018, + 0x402D, + WORD_LEN); + + mt9d113_i2c_write(mt9d113_client->addr, + 0x0018, + 0x402C, + WORD_LEN); + /*POLL_REG=0x0018,0x4000,!=0x0000,DELAY=10,TIMEOUT=100*/ + data = 0; + rc = mt9d113_i2c_read(mt9d113_client->addr, + 0x0018, &data, WORD_LEN); + data = data & 0x4000; + count = 0; + while (data != 0x0000) { + rc = mt9d113_i2c_read(mt9d113_client->addr, + 0x0018, &data, WORD_LEN); + data = data & 0x4000; + CDBG(" data is %d\n" , data); + usleep_range(11000, 12000); + count++; + if (count == 100) { + CDBG(" Loop2 timeout: MT9D113\n"); + break; + } + CDBG(" Not streaming\n"); + } + CDBG("MT9D113: Start stream\n"); + /*Preset Register Wizard Conf*/ + rc = mt9d113_i2c_write_table(&mt9d113_regs.register_tbl[0], + mt9d113_regs.register_tbl_size); + if (rc < 0) + return rc; + rc = mt9d113_i2c_write_table(&mt9d113_regs.err_tbl[0], + mt9d113_regs.err_tbl_size); + if (rc < 0) + return rc; + rc = mt9d113_i2c_write_table(&mt9d113_regs.eeprom_tbl[0], + mt9d113_regs.eeprom_tbl_size); + if (rc < 0) + return rc; + + rc = mt9d113_i2c_write_table(&mt9d113_regs.low_light_tbl[0], + mt9d113_regs.low_light_tbl_size); + if (rc < 0) + return rc; + + rc = mt9d113_i2c_write_table(&mt9d113_regs.awb_tbl[0], + mt9d113_regs.awb_tbl_size); + if (rc < 0) + return rc; + + rc = mt9d113_i2c_write_table(&mt9d113_regs.patch_tbl[0], + mt9d113_regs.patch_tbl_size); + if (rc < 0) + return rc; + + /*check patch load*/ + mt9d113_i2c_write(mt9d113_client->addr, + 0x098C, + 0xA024, + WORD_LEN); + count = 0; + /*To check if patch is loaded properly + poll the register 0x990 till the condition is + met or till the timeout*/ + data = 0; + rc = mt9d113_i2c_read(mt9d113_client->addr, + 0x0990, &data, WORD_LEN); + while (data == 0) { + data = 0; + rc = mt9d113_i2c_read(mt9d113_client->addr, + 0x0990, &data, WORD_LEN); + usleep_range(11000, 12000); + count++; + if (count == 100) { + CDBG("Timeout in patch loading\n"); + break; + } + } + /*BITFIELD=0x0018, 0x0004, 0*/ + /*Preset continue begin */ + rc = mt9d113_i2c_write(mt9d113_client->addr, 0x0018, 0x0028, + WORD_LEN); + CDBG(" mt9d113 wait for seq done\n"); + /* syncronize the FW with the sensor + MCU_ADDRESS [SEQ_CMD]*/ + rc = mt9d113_i2c_write(mt9d113_client->addr, + 0x098C, 0xA103, WORD_LEN); + rc = mt9d113_i2c_write(mt9d113_client->addr, + 0x0990, 0x0006, WORD_LEN); + /*mt9d113 wait for seq done + syncronize the FW with the sensor */ + msleep(20); + /*Preset continue end */ + CDBG(" MT9D113: Preset continue end\n"); + rc = mt9d113_i2c_write(mt9d113_client->addr, + 0x0012, + 0x00F5, + WORD_LEN); + /*continue begin */ + CDBG(" MT9D113: Preset continue begin\n"); + rc = mt9d113_i2c_write(mt9d113_client->addr, 0x0018, 0x0028 , + WORD_LEN); + /*mt9d113 wait for seq done + syncronize the FW with the sensor + MCU_ADDRESS [SEQ_CMD]*/ + msleep(20); + rc = mt9d113_i2c_write(mt9d113_client->addr, + 0x098C, 0xA103, WORD_LEN); + /* MCU DATA */ + rc = mt9d113_i2c_write(mt9d113_client->addr, 0x0990, + 0x0006, WORD_LEN); + /*mt9d113 wait for seq done + syncronize the FW with the sensor */ + /* MCU_ADDRESS [SEQ_CMD]*/ + msleep(20); + /*Preset continue end*/ + return rc; + +} + +static long mt9d113_set_sensor_mode(int mode) +{ + long rc = 0; + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = mt9d113_reg_init(); + CDBG("MT9D113: configure to preview begin\n"); + rc = + mt9d113_i2c_write(mt9d113_client->addr, + 0x098C, 0xA115, WORD_LEN); + if (rc < 0) + return rc; + rc = + mt9d113_i2c_write(mt9d113_client->addr, + 0x0990, 0x0000, WORD_LEN); + if (rc < 0) + return rc; + rc = + mt9d113_i2c_write(mt9d113_client->addr, + 0x098C, 0xA103, WORD_LEN); + if (rc < 0) + return rc; + rc = + mt9d113_i2c_write(mt9d113_client->addr, + 0x0990, 0x0001, WORD_LEN); + if (rc < 0) + return rc; + break; + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + rc = + mt9d113_i2c_write(mt9d113_client->addr, + 0x098C, 0xA115, WORD_LEN); + rc = + mt9d113_i2c_write(mt9d113_client->addr, + 0x0990, 0x0002, WORD_LEN); + rc = + mt9d113_i2c_write(mt9d113_client->addr, + 0x098C, 0xA103, WORD_LEN); + rc = + mt9d113_i2c_write(mt9d113_client->addr, + 0x0990, 0x0002, WORD_LEN); + break; + default: + return -EINVAL; + } + return 0; +} + +static int mt9d113_sensor_init_probe(const struct + msm_camera_sensor_info * data) +{ + uint16_t model_id = 0; + int rc = 0; + /* Read the Model ID of the sensor */ + rc = mt9d113_i2c_read(mt9d113_client->addr, + REG_MT9D113_MODEL_ID, + &model_id, WORD_LEN); + if (rc < 0) + goto init_probe_fail; + /* Check if it matches it with the value in Datasheet */ + if (model_id != MT9D113_MODEL_ID) + printk(KERN_INFO "mt9d113 model_id = 0x%x\n", model_id); + if (rc < 0) + goto init_probe_fail; + return rc; +init_probe_fail: + printk(KERN_INFO "probe fail\n"); + return rc; +} + +static int mt9d113_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&mt9d113_wait_queue); + return 0; +} + +int mt9d113_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cfg_data; + long rc = 0; + + if (copy_from_user(&cfg_data, + (void *)argp, + (sizeof(struct sensor_cfg_data)))) + return -EFAULT; + mutex_lock(&mt9d113_mut); + CDBG("mt9d113_ioctl, cfgtype = %d, mode = %d\n", + cfg_data.cfgtype, cfg_data.mode); + switch (cfg_data.cfgtype) { + case CFG_SET_MODE: + rc = mt9d113_set_sensor_mode( + cfg_data.mode); + break; + case CFG_SET_EFFECT: + return rc; + case CFG_GET_AF_MAX_STEPS: + default: + rc = -EINVAL; + break; + } + mutex_unlock(&mt9d113_mut); + return rc; +} + +int mt9d113_sensor_release(void) +{ + int rc = 0; + + mutex_lock(&mt9d113_mut); + gpio_set_value_cansleep(mt9d113_ctrl->sensordata->sensor_reset, 0); + msleep(20); + gpio_free(mt9d113_ctrl->sensordata->sensor_reset); + kfree(mt9d113_ctrl); + mutex_unlock(&mt9d113_mut); + + return rc; +} + +static int mt9d113_probe_init_done(const struct msm_camera_sensor_info + *data) +{ + gpio_free(data->sensor_reset); + return 0; +} + +static int mt9d113_probe_init_sensor(const struct msm_camera_sensor_info + *data) +{ + int32_t rc = 0; + uint16_t chipid = 0; + + rc = gpio_request(data->sensor_reset, "mt9d113"); + printk(KERN_INFO " mt9d113_probe_init_sensor\n"); + if (!rc) { + printk(KERN_INFO "sensor_reset = %d\n", rc); + gpio_direction_output(data->sensor_reset, 0); + usleep_range(11000, 12000); + gpio_set_value_cansleep(data->sensor_reset, 1); + usleep_range(11000, 12000); + } else + goto init_probe_done; + printk(KERN_INFO " mt9d113_probe_init_sensor called\n"); + rc = mt9d113_i2c_read(mt9d113_client->addr, REG_MT9D113_MODEL_ID, + &chipid, WORD_LEN); + if (rc < 0) + goto init_probe_fail; + /*Compare sensor ID to MT9D113 ID: */ + if (chipid != MT9D113_MODEL_ID) { + printk(KERN_INFO "mt9d113_probe_init_sensor chip id is%d\n", + chipid); + } + CDBG("mt9d113_probe_init_sensor Success\n"); + goto init_probe_done; +init_probe_fail: + CDBG(" ov2720_probe_init_sensor fails\n"); + gpio_set_value_cansleep(data->sensor_reset, 0); + mt9d113_probe_init_done(data); +init_probe_done: + printk(KERN_INFO " mt9d113_probe_init_sensor finishes\n"); + return rc; +} + +static int mt9d113_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + rc = -ENOTSUPP; + goto probe_failure; + } + mt9d113_sensorw = + kzalloc(sizeof(struct mt9d113_work), GFP_KERNEL); + if (!mt9d113_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + i2c_set_clientdata(client, mt9d113_sensorw); + mt9d113_init_client(client); + mt9d113_client = client; + CDBG("mt9d113_probe succeeded!\n"); + return 0; +probe_failure: + kfree(mt9d113_sensorw); + mt9d113_sensorw = NULL; + CDBG("mt9d113_probe failed!\n"); + return rc; +} + +static const struct i2c_device_id mt9d113_i2c_id[] = { + { "mt9d113", 0}, + {}, +}; + +static struct i2c_driver mt9d113_i2c_driver = { + .id_table = mt9d113_i2c_id, + .probe = mt9d113_i2c_probe, + .remove = __exit_p(mt9d113_i2c_remove), + .driver = { + .name = "mt9d113", + }, +}; + +int mt9d113_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + mt9d113_ctrl = kzalloc(sizeof(struct mt9d113_ctrl), GFP_KERNEL); + if (!mt9d113_ctrl) { + printk(KERN_INFO "mt9d113_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + mt9d113_ctrl->fps_divider = 1 * 0x00000400; + mt9d113_ctrl->pict_fps_divider = 1 * 0x00000400; + mt9d113_ctrl->set_test = TEST_OFF; + mt9d113_ctrl->config_csi = 0; + mt9d113_ctrl->prev_res = QTR_SIZE; + mt9d113_ctrl->pict_res = FULL_SIZE; + mt9d113_ctrl->curr_res = INVALID_SIZE; + if (data) + mt9d113_ctrl->sensordata = data; + if (rc < 0) { + printk(KERN_INFO "mt9d113_sensor_open_init fail\n"); + return rc; + } + /* enable mclk first */ + msm_camio_clk_rate_set(24000000); + msleep(20); + rc = mt9d113_probe_init_sensor(data); + if (rc < 0) + goto init_fail; + mt9d113_ctrl->fps = 30*Q8; + rc = mt9d113_sensor_init_probe(data); + if (rc < 0) { + gpio_set_value_cansleep(data->sensor_reset, 0); + goto init_fail; + } else + printk(KERN_ERR "%s: %d\n", __func__, __LINE__); + goto init_done; +init_fail: + printk(KERN_INFO "init_fail\n"); + mt9d113_probe_init_done(data); +init_done: + CDBG("init_done\n"); + return rc; +} + +static int mt9d113_sensor_probe(const struct msm_camera_sensor_info + *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(&mt9d113_i2c_driver); + if (rc < 0 || mt9d113_client == NULL) { + rc = -ENOTSUPP; + goto probe_fail; + } + msm_camio_clk_rate_set(24000000); + usleep_range(5000, 6000); + rc = mt9d113_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + s->s_init = mt9d113_sensor_open_init; + s->s_release = mt9d113_sensor_release; + s->s_config = mt9d113_sensor_config; + s->s_camera_type = FRONT_CAMERA_2D; + s->s_mount_angle = 0; + gpio_set_value_cansleep(info->sensor_reset, 0); + mt9d113_probe_init_done(info); + return rc; +probe_fail: + printk(KERN_INFO "mt9d113_sensor_probe: SENSOR PROBE FAILS!\n"); + return rc; +} + +static int __mt9d113_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, mt9d113_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __mt9d113_probe, + .driver = { + .name = "msm_cam_mt9d113", + .owner = THIS_MODULE, + }, +}; + +static int __init mt9d113_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(mt9d113_init); + +MODULE_DESCRIPTION("Micron 2MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/mt9d113.h b/drivers/media/video/msm_zsl/mt9d113.h new file mode 100644 index 00000000000..f22f16c542c --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9d113.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef MT9D113_H +#define MT9D113_H + +#include +#include + +extern struct mt9d113_reg mt9d113_regs; + +enum mt9d113_width { + WORD_LEN, + BYTE_LEN +}; + +struct mt9d113_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +struct mt9d113_reg { + const struct mt9d113_i2c_reg_conf *pll_tbl; + uint16_t pll_tbl_size; + const struct mt9d113_i2c_reg_conf *register_tbl; + uint16_t register_tbl_size; + const struct mt9d113_i2c_reg_conf *err_tbl; + uint16_t err_tbl_size; + const struct mt9d113_i2c_reg_conf *low_light_tbl; + uint16_t low_light_tbl_size; + const struct mt9d113_i2c_reg_conf *awb_tbl; + uint16_t awb_tbl_size; + const struct mt9d113_i2c_reg_conf *patch_tbl; + uint16_t patch_tbl_size; + const struct mt9d113_i2c_reg_conf *eeprom_tbl ; + uint16_t eeprom_tbl_size ; +}; + +enum mt9d113_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum mt9d113_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; + +enum mt9d113_setting { + RES_PREVIEW, + RES_CAPTURE +}; +#endif /* MT9D113_H */ diff --git a/drivers/media/video/msm_zsl/mt9d113_reg.c b/drivers/media/video/msm_zsl/mt9d113_reg.c new file mode 100644 index 00000000000..6c37c5c937b --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9d113_reg.c @@ -0,0 +1,452 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "mt9d113.h" + +struct mt9d113_i2c_reg_conf const + pll_tbl_settings[] = { + {0x0014, 0x21F9 }, /*PLL control: BYPASS PLL = 8697*/ + {0x0010, 0x0115 }, /*PLL Dividers = 277*/ + {0x0012, 0x0F5 }, /*PLL P Dividers = 245*/ + {0x0014, 0x21FB }, /*PLL control: PLL_ENABLE on = 8699*/ + {0x0014, 0x20FB }, /*PLL control: SEL_LOCK_DET on = 8443*/ +}; + +struct mt9d113_i2c_reg_conf const + register_wizard_settings[] = { + {0x098C, 0x2719}, + {0x0990, 0x005A}, + {0x098C, 0x271B}, + {0x0990, 0x01BE}, + {0x098C, 0x271D}, + {0x0990, 0x0131}, + {0x098C, 0x271F}, + {0x0990, 0x02BB}, + {0x098C, 0x2721}, + {0x0990, 0x0888}, + {0x098C, 0x272F}, + {0x0990, 0x003A}, + {0x098C, 0x2731}, + {0x0990, 0x00F6}, + {0x098C, 0x2733}, + {0x0990, 0x008B}, + {0x098C, 0x2735}, + {0x0990, 0x0521}, + {0x098C, 0x2737}, + {0x0990, 0x0888}, + {0x098C, 0x275F}, + {0x0990, 0x0194}, + {0x098C, 0x2761}, + {0x0990, 0x0014}, + {0x098C, 0xA765}, + {0x0990, 0x0044}, + {0x098C, 0xA24F}, + {0x0990, 0x0028}, + {0x098C, 0xA20E}, + {0x0990, 0x00A0}, + {0x098C, 0xA20C}, + {0x0990, 0x000E}, + {0x098C, 0x2222}, + {0x0990, 0x00A0}, + {0x098C, 0x2212}, + {0x0990, 0x01EE}, + {0x098C, 0xA408}, + {0x0990, 0x0026}, + {0x098C, 0xA409}, + {0x0990, 0x0029}, + {0x098C, 0xA40A}, + {0x0990, 0x002E}, + {0x098C, 0xA40B}, + {0x0990, 0x0031}, + {0x098C, 0x2411}, + {0x0990, 0x00A0}, + {0x098C, 0x2413}, + {0x0990, 0x00C0}, + {0x098C, 0x2415}, + {0x0990, 0x00A0}, + {0x098C, 0x2417}, + {0x0990, 0x00C0}, +}; + +struct mt9d113_i2c_reg_conf const + err_settings[] = { + {0x3084, 0x240C}, + {0x3092, 0x0A4C}, + {0x3094, 0x4C4C}, + {0x3096, 0x4C54}, +}; + +struct mt9d113_i2c_reg_conf const + patch_settings[] = { + {0x098C, 0x0415}, /* MCU_ADDRESS*/ + {0x0990, 0xF601}, + {0x0992, 0x42C1}, + {0x0994, 0x0326}, + {0x0996, 0x11F6}, + {0x0998, 0x0143}, + {0x099A, 0xC104}, + {0x099C, 0x260A}, + {0x099E, 0xCC04}, + {0x098C, 0x0425}, + {0x0990, 0x33BD}, + {0x0992, 0xA362}, + {0x0994, 0xBD04}, + {0x0996, 0x3339}, + {0x0998, 0xC6FF}, + {0x099A, 0xF701}, + {0x099C, 0x6439}, + {0x099E, 0xFE01}, + {0x098C, 0x0435}, + {0x0990, 0x6918}, + {0x0992, 0xCE03}, + {0x0994, 0x25CC}, + {0x0996, 0x0013}, + {0x0998, 0xBDC2}, + {0x099A, 0xB8CC}, + {0x099C, 0x0489}, + {0x099E, 0xFD03}, + {0x098C, 0x0445}, + {0x0990, 0x27CC}, + {0x0992, 0x0325}, + {0x0994, 0xFD01}, + {0x0996, 0x69FE}, + {0x0998, 0x02BD}, + {0x099A, 0x18CE}, + {0x099C, 0x0339}, + {0x099E, 0xCC00}, + {0x098C, 0x0455}, + {0x0990, 0x11BD}, + {0x0992, 0xC2B8}, + {0x0994, 0xCC04}, + {0x0996, 0xC8FD}, + {0x0998, 0x0347}, + {0x099A, 0xCC03}, + {0x099C, 0x39FD}, + {0x099E, 0x02BD}, + {0x098C, 0x0465}, + {0x0990, 0xDE00}, + {0x0992, 0x18CE}, + {0x0994, 0x00C2}, + {0x0996, 0xCC00}, + {0x0998, 0x37BD}, + {0x099A, 0xC2B8}, + {0x099C, 0xCC04}, + {0x099E, 0xEFDD}, + {0x098C, 0x0475}, + {0x0990, 0xE6CC}, + {0x0992, 0x00C2}, + {0x0994, 0xDD00}, + {0x0996, 0xC601}, + {0x0998, 0xF701}, + {0x099A, 0x64C6}, + {0x099C, 0x03F7}, + {0x099E, 0x0165}, + {0x098C, 0x0485}, + {0x0990, 0x7F01}, + {0x0992, 0x6639}, + {0x0994, 0x3C3C}, + {0x0996, 0x3C34}, + {0x0998, 0xCC32}, + {0x099A, 0x3EBD}, + {0x099C, 0xA558}, + {0x099E, 0x30ED}, + {0x098C, 0x0495}, + {0x0990, 0x04BD}, + {0x0992, 0xB2D7}, + {0x0994, 0x30E7}, + {0x0996, 0x06CC}, + {0x0998, 0x323E}, + {0x099A, 0xED00}, + {0x099C, 0xEC04}, + {0x099E, 0xBDA5}, + {0x098C, 0x04A5}, + {0x0990, 0x44CC}, + {0x0992, 0x3244}, + {0x0994, 0xBDA5}, + {0x0996, 0x585F}, + {0x0998, 0x30ED}, + {0x099A, 0x02CC}, + {0x099C, 0x3244}, + {0x099E, 0xED00}, + {0x098C, 0x04B5}, + {0x0990, 0xF601}, + {0x0992, 0xD54F}, + {0x0994, 0xEA03}, + {0x0996, 0xAA02}, + {0x0998, 0xBDA5}, + {0x099A, 0x4430}, + {0x099C, 0xE606}, + {0x099E, 0x3838}, + {0x098C, 0x04C5}, + {0x0990, 0x3831}, + {0x0992, 0x39BD}, + {0x0994, 0xD661}, + {0x0996, 0xF602}, + {0x0998, 0xF4C1}, + {0x099A, 0x0126}, + {0x099C, 0x0BFE}, + {0x099E, 0x02BD}, + {0x098C, 0x04D5}, + {0x0990, 0xEE10}, + {0x0992, 0xFC02}, + {0x0994, 0xF5AD}, + {0x0996, 0x0039}, + {0x0998, 0xF602}, + {0x099A, 0xF4C1}, + {0x099C, 0x0226}, + {0x099E, 0x0AFE}, + {0x098C, 0x04E5}, + {0x0990, 0x02BD}, + {0x0992, 0xEE10}, + {0x0994, 0xFC02}, + {0x0996, 0xF7AD}, + {0x0998, 0x0039}, + {0x099A, 0x3CBD}, + {0x099C, 0xB059}, + {0x099E, 0xCC00}, + {0x098C, 0x04F5}, + {0x0990, 0x28BD}, + {0x0992, 0xA558}, + {0x0994, 0x8300}, + {0x0996, 0x0027}, + {0x0998, 0x0BCC}, + {0x099A, 0x0026}, + {0x099C, 0x30ED}, + {0x099E, 0x00C6}, + {0x098C, 0x0505}, + {0x0990, 0x03BD}, + {0x0992, 0xA544}, + {0x0994, 0x3839}, + {0x098C, 0x2006}, + {0x0990, 0x0415}, + {0x098C, 0xA005}, + {0x0990, 0x0001}, +}; + +struct mt9d113_i2c_reg_conf const + eeprom_settings[] = { + {0x3658, 0x0110}, + {0x365A, 0x1B6D}, + {0x365C, 0x01F2}, + {0x365E, 0xFBCD}, + {0x3660, 0x8C91}, + {0x3680, 0xB9ED}, + {0x3682, 0x0EE}, + {0x3684, 0x256F}, + {0x3686, 0x824F}, + {0x3688, 0xD293}, + {0x36A8, 0x5BF2}, + {0x36AA, 0x1711}, + {0x36AC, 0xA095}, + {0x36AE, 0x642C}, + {0x36B0, 0x0E38}, + {0x36D0, 0x88B0}, + {0x36D2, 0x2EB2}, + {0x36D4, 0x4C74}, + {0x36D6, 0x9F96}, + {0x36D8, 0x9557}, + {0x36F8, 0xCE51}, + {0x36FA, 0xB354}, + {0x36FC, 0x2817}, + {0x36FE, 0x14B8}, + {0x3700, 0xB019}, + {0x364E, 0x0710}, + {0x3650, 0x30ED}, + {0x3652, 0x03F2}, + {0x3654, 0xF12E}, + {0x3656, 0x8492}, + {0x3676, 0xD9AD}, + {0x3678, 0x88D0}, + {0x367A, 0x7DED}, + {0x367C, 0x3E31}, + {0x367E, 0x91B3}, + {0x369E, 0x7032}, + {0x36A0, 0x2791}, + {0x36A2, 0xBB55}, + {0x36A4, 0xAB32}, + {0x36A6, 0x1A58}, + {0x36C6, 0xB50F}, + {0x36C8, 0x0011}, + {0x36CA, 0x6DB4}, + {0x36CC, 0x96F5}, + {0x36CE, 0x9BB7}, + {0x36EE, 0x9353}, + {0x36F0, 0xDF74}, + {0x36F2, 0x04F8}, + {0x36F4, 0x0FD8}, + {0x36F6, 0xA87A}, + {0x3662, 0x0170}, + {0x3664, 0x6F0C}, + {0x3666, 0x0112}, + {0x3668, 0xCBAB}, + {0x366A, 0x9111}, + {0x368A, 0xB38D}, + {0x368C, 0xE96F}, + {0x368E, 0xCC0F}, + {0x3690, 0x5851}, + {0x3692, 0xFDD2}, + {0x36B2, 0x5F92}, + {0x36B4, 0x33B2}, + {0x36B6, 0x9815}, + {0x36B8, 0x86F5}, + {0x36BA, 0x0578}, + {0x36DA, 0xCD90}, + {0x36DC, 0x1131}, + {0x36DE, 0x5275}, + {0x36E0, 0xE855}, + {0x36E2, 0xD037}, + {0x3702, 0xAAD1}, + {0x3704, 0xEB75}, + {0x3706, 0x0CD7}, + {0x3708, 0x2C79}, + {0x370A, 0xE0B9}, + {0x366C, 0x0190}, + {0x366E, 0x1C8D}, + {0x3670, 0x0052}, + {0x3672, 0xD66E}, + {0x3674, 0xF511}, + {0x3694, 0xB54D}, + {0x3696, 0x6E4E}, + {0x3698, 0x142E}, + {0x369A, 0xC190}, + {0x369C, 0xA753}, + {0x36BC, 0x70F2}, + {0x36BE, 0x04F1}, + {0x36C0, 0xBD95}, + {0x36C2, 0x0CEE}, + {0x36C4, 0x1BF8}, + {0x36E4, 0x806F}, + {0x36E6, 0x1672}, + {0x36E8, 0x2DF4}, + {0x36EA, 0x8F16}, + {0x36EC, 0xF776}, + {0x370C, 0xAD73}, + {0x370E, 0xB534}, + {0x3710, 0x0D18}, + {0x3712, 0x6057}, + {0x3714, 0xBD1A}, + {0x3644, 0x0354}, + {0x3642, 0x0234}, + {0x3210, 0x01B8}, +}; + +struct mt9d113_i2c_reg_conf const + awb_settings[] = { + {0x098C, 0x2306}, + {0x0990, 0x0180}, + {0x098C, 0x2308}, + {0x0990, 0xFF00}, + {0x098C, 0x230A}, + {0x0990, 0x0080}, + {0x098C, 0x230C}, + {0x0990, 0xFF66}, + {0x098C, 0x230E}, + {0x0990, 0x0180}, + {0x098C, 0x2310}, + {0x0990, 0xFFEE}, + {0x098C, 0x2312}, + {0x0990, 0xFFCD}, + {0x098C, 0x2314}, + {0x0990, 0xFECD}, + {0x098C, 0x2316}, + {0x0990, 0x019A}, + {0x098C, 0x2318}, + {0x0990, 0x0020}, + {0x098C, 0x231A}, + {0x0990, 0x0033}, + {0x098C, 0x231C}, + {0x0990, 0x0100}, + {0x098C, 0x231E}, + {0x0990, 0xFF9A}, + {0x098C, 0x2320}, + {0x0990, 0x0000}, + {0x098C, 0x2322}, + {0x0990, 0x004D}, + {0x098C, 0x2324}, + {0x0990, 0xFFCD}, + {0x098C, 0x2326}, + {0x0990, 0xFFB8}, + {0x098C, 0x2328}, + {0x0990, 0x004D}, + {0x098C, 0x232A}, + {0x0990, 0x0080}, + {0x098C, 0x232C}, + {0x0990, 0xFF66}, + {0x098C, 0x232E}, + {0x0990, 0x0008}, + {0x098C, 0x2330}, + {0x0990, 0xFFF7}, + {0x098C, 0xA363}, + {0x0990, 0x00D2}, + {0x098C, 0xA364}, + {0x0990, 0x00EE}, + {0x3244, 0x0328}, + {0x323E, 0xC22C}, +}; + +struct mt9d113_i2c_reg_conf const + low_light_setting[] = { + {0x098C, 0x2B28}, + {0x0990, 0x35E8}, + {0x098C, 0x2B2A}, + {0x0990, 0xB3B0}, + {0x098C, 0xAB20}, + {0x0990, 0x004B}, + {0x098C, 0xAB24}, + {0x0990, 0x0000}, + {0x098C, 0xAB25}, + {0x0990, 0x00FF}, + {0x098C, 0xAB30}, + {0x0990, 0x00FF}, + {0x098C, 0xAB31}, + {0x0990, 0x00FF}, + {0x098C, 0xAB32}, + {0x0990, 0x00FF}, + {0x098C, 0xAB33}, + {0x0990, 0x0057}, + {0x098C, 0xAB34}, + {0x0990, 0x0080}, + {0x098C, 0xAB35}, + {0x0990, 0x00FF}, + {0x098C, 0xAB36}, + {0x0990, 0x0014}, + {0x098C, 0xAB37}, + {0x0990, 0x0003}, + {0x098C, 0x2B38}, + {0x0990, 0x32C8}, + {0x098C, 0x2B3A}, + {0x0990, 0x7918}, + {0x098C, 0x2B62}, + {0x0990, 0xFFFE}, + {0x098C, 0x2B64}, + {0x0990, 0xFFFF}, +}; + +struct mt9d113_reg mt9d113_regs = { + .pll_tbl = pll_tbl_settings, + .pll_tbl_size = ARRAY_SIZE( + pll_tbl_settings), + .register_tbl = register_wizard_settings, + .register_tbl_size = ARRAY_SIZE( + register_wizard_settings), + .err_tbl = err_settings, + .err_tbl_size = ARRAY_SIZE(err_settings), + .low_light_tbl = low_light_setting, + .low_light_tbl_size = ARRAY_SIZE(low_light_setting), + .awb_tbl = awb_settings, + .awb_tbl_size = ARRAY_SIZE(awb_settings), + .patch_tbl = patch_settings, + .patch_tbl_size = ARRAY_SIZE(patch_settings), + .eeprom_tbl = eeprom_settings, + .eeprom_tbl_size = ARRAY_SIZE(eeprom_settings), +}; diff --git a/drivers/media/video/msm_zsl/mt9e013.c b/drivers/media/video/msm_zsl/mt9e013.c new file mode 100644 index 00000000000..b57d763c1dd --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9e013.c @@ -0,0 +1,1137 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mt9e013.h" +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD_OFF 0x00 +#define GROUPED_PARAMETER_HOLD 0x01 +/* Integration Time */ +#define REG_COARSE_INTEGRATION_TIME 0x3012 +/* Gain */ +#define REG_GLOBAL_GAIN 0x305E +/* PLL registers */ +#define REG_FRAME_LENGTH_LINES 0x0340 +/* Test Pattern */ +#define REG_TEST_PATTERN_MODE 0x0601 +#define REG_VCM_NEW_CODE 0x30F2 + +/*============================================================================ + TYPE DECLARATIONS +============================================================================*/ + +/* 16bit address - 8 bit context register structure */ +#define Q8 0x00000100 +#define Q10 0x00000400 +#define MT9E013_MASTER_CLK_RATE 24000000 + +/* AF Total steps parameters */ +#define MT9E013_TOTAL_STEPS_NEAR_TO_FAR 32 + +uint16_t mt9e013_step_position_table[MT9E013_TOTAL_STEPS_NEAR_TO_FAR+1]; +uint16_t mt9e013_nl_region_boundary1; +uint16_t mt9e013_nl_region_code_per_step1; +uint16_t mt9e013_l_region_code_per_step = 4; +uint16_t mt9e013_damping_threshold = 10; +uint16_t mt9e013_sw_damping_time_wait = 1; + +struct mt9e013_work_t { + struct work_struct work; +}; + +static struct mt9e013_work_t *mt9e013_sensorw; +static struct i2c_client *mt9e013_client; + +struct mt9e013_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + + uint32_t sensormode; + uint32_t fps_divider;/* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */ + uint16_t fps; + + uint16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + + enum mt9e013_resolution_t prev_res; + enum mt9e013_resolution_t pict_res; + enum mt9e013_resolution_t curr_res; + enum mt9e013_test_mode_t set_test; +}; + + +static bool CSI_CONFIG; +static struct mt9e013_ctrl_t *mt9e013_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(mt9e013_wait_queue); +DEFINE_MUTEX(mt9e013_mut); + +static int cam_debug_init(void); +static struct dentry *debugfs_base; +/*=============================================================*/ + +static int mt9e013_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 2, + .buf = rxdata, + }, + }; + if (i2c_transfer(mt9e013_client->adapter, msgs, 2) < 0) { + CDBG("mt9e013_i2c_rxdata faild 0x%x\n", saddr); + return -EIO; + } + return 0; +} + +static int32_t mt9e013_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(mt9e013_client->adapter, msg, 1) < 0) { + CDBG("mt9e013_i2c_txdata faild 0x%x\n", saddr); + return -EIO; + } + + return 0; +} + +static int32_t mt9e013_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + rc = mt9e013_i2c_rxdata(mt9e013_client->addr<<1, buf, rlen); + if (rc < 0) { + CDBG("mt9e013_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + CDBG("mt9e013_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata); + return rc; +} + +static int32_t mt9e013_i2c_write_w_sensor(unsigned short waddr, uint16_t wdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[4]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00) >> 8; + buf[3] = (wdata & 0x00FF); + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata); + rc = mt9e013_i2c_txdata(mt9e013_client->addr<<1, buf, 4); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + } + return rc; +} + +static int32_t mt9e013_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[3]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata); + rc = mt9e013_i2c_txdata(mt9e013_client->addr<<1, buf, 3); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + return rc; +} + +static int32_t mt9e013_i2c_write_w_table(struct mt9e013_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + for (i = 0; i < num; i++) { + rc = mt9e013_i2c_write_w_sensor(reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +static void mt9e013_group_hold_on(void) +{ + mt9e013_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); +} + +static void mt9e013_group_hold_off(void) +{ + mt9e013_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF); +} + +static void mt9e013_start_stream(void) +{ + mt9e013_i2c_write_w_sensor(0x301A, 0x8250); + mt9e013_i2c_write_w_sensor(0x301A, 0x8650); + mt9e013_i2c_write_w_sensor(0x301A, 0x8658); + mt9e013_i2c_write_b_sensor(0x0104, 0x00); + mt9e013_i2c_write_w_sensor(0x301A, 0x065C); +} + +static void mt9e013_stop_stream(void) +{ + mt9e013_i2c_write_w_sensor(0x301A, 0x0058); + mt9e013_i2c_write_w_sensor(0x301A, 0x0050); + mt9e013_i2c_write_b_sensor(0x0104, 0x01); +} + +static void mt9e013_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint32_t divider, d1, d2; + + d1 = mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata + * 0x00000400/ + mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata; + d2 = mt9e013_regs.reg_prev[E013_LINE_LENGTH_PCK].wdata + * 0x00000400/ + mt9e013_regs.reg_snap[E013_LINE_LENGTH_PCK].wdata; + divider = d1 * d2 / 0x400; + + /*Verify PCLK settings and frame sizes.*/ + *pfps = (uint16_t) (fps * divider / 0x400); + /* 2 is the ratio of no.of snapshot channels + to number of preview channels */ +} + +static uint16_t mt9e013_get_prev_lines_pf(void) +{ + if (mt9e013_ctrl->prev_res == QTR_SIZE) + return mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata; + else if (mt9e013_ctrl->prev_res == FULL_SIZE) + return mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata; + else if (mt9e013_ctrl->prev_res == HFR_60FPS) + return mt9e013_regs.reg_60fps[E013_FRAME_LENGTH_LINES].wdata; + else if (mt9e013_ctrl->prev_res == HFR_90FPS) + return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata; + else + return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata; +} + +static uint16_t mt9e013_get_prev_pixels_pl(void) +{ + if (mt9e013_ctrl->prev_res == QTR_SIZE) + return mt9e013_regs.reg_prev[E013_LINE_LENGTH_PCK].wdata; + else if (mt9e013_ctrl->prev_res == FULL_SIZE) + return mt9e013_regs.reg_snap[E013_LINE_LENGTH_PCK].wdata; + else if (mt9e013_ctrl->prev_res == HFR_60FPS) + return mt9e013_regs.reg_60fps[E013_LINE_LENGTH_PCK].wdata; + else if (mt9e013_ctrl->prev_res == HFR_90FPS) + return mt9e013_regs.reg_120fps[E013_LINE_LENGTH_PCK].wdata; + else + return mt9e013_regs.reg_120fps[E013_LINE_LENGTH_PCK].wdata; +} + +static uint16_t mt9e013_get_pict_lines_pf(void) +{ + if (mt9e013_ctrl->pict_res == QTR_SIZE) + return mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata; + else if (mt9e013_ctrl->pict_res == FULL_SIZE) + return mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata; + else if (mt9e013_ctrl->pict_res == HFR_60FPS) + return mt9e013_regs.reg_60fps[E013_FRAME_LENGTH_LINES].wdata; + else if (mt9e013_ctrl->pict_res == HFR_90FPS) + return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata; + else + return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata; +} + +static uint16_t mt9e013_get_pict_pixels_pl(void) +{ + if (mt9e013_ctrl->pict_res == QTR_SIZE) + return mt9e013_regs.reg_prev[E013_LINE_LENGTH_PCK].wdata; + else if (mt9e013_ctrl->pict_res == FULL_SIZE) + return mt9e013_regs.reg_snap[E013_LINE_LENGTH_PCK].wdata; + else if (mt9e013_ctrl->pict_res == HFR_60FPS) + return mt9e013_regs.reg_60fps[E013_LINE_LENGTH_PCK].wdata; + else if (mt9e013_ctrl->pict_res == HFR_90FPS) + return mt9e013_regs.reg_120fps[E013_LINE_LENGTH_PCK].wdata; + else + return mt9e013_regs.reg_120fps[E013_LINE_LENGTH_PCK].wdata; +} + +static uint32_t mt9e013_get_pict_max_exp_lc(void) +{ + if (mt9e013_ctrl->pict_res == QTR_SIZE) + return mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata + * 24; + else if (mt9e013_ctrl->pict_res == FULL_SIZE) + return mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata + * 24; + else if (mt9e013_ctrl->pict_res == HFR_60FPS) + return mt9e013_regs.reg_60fps[E013_FRAME_LENGTH_LINES].wdata + * 24; + else if (mt9e013_ctrl->pict_res == HFR_90FPS) + return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata + * 24; + else + return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata + * 24; +} + +static int32_t mt9e013_set_fps(struct fps_cfg *fps) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + if (mt9e013_ctrl->curr_res == QTR_SIZE) + total_lines_per_frame = + mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata; + else if (mt9e013_ctrl->curr_res == FULL_SIZE) + total_lines_per_frame = + mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata; + else if (mt9e013_ctrl->curr_res == HFR_60FPS) + total_lines_per_frame = + mt9e013_regs.reg_60fps[E013_FRAME_LENGTH_LINES].wdata; + else if (mt9e013_ctrl->curr_res == HFR_90FPS) + total_lines_per_frame = + mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata; + else + total_lines_per_frame = + mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata; + + mt9e013_ctrl->fps_divider = fps->fps_div; + mt9e013_ctrl->pict_fps_divider = fps->pict_fps_div; + + if (mt9e013_ctrl->curr_res == FULL_SIZE) { + total_lines_per_frame = (uint16_t) + (total_lines_per_frame * mt9e013_ctrl->pict_fps_divider/0x400); + } else { + total_lines_per_frame = (uint16_t) + (total_lines_per_frame * mt9e013_ctrl->fps_divider/0x400); + } + + mt9e013_group_hold_on(); + rc = mt9e013_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES, + total_lines_per_frame); + mt9e013_group_hold_off(); + return rc; +} + +static int32_t mt9e013_write_exp_gain(uint16_t gain, uint32_t line) +{ + uint16_t max_legal_gain = 0xE7F; + int32_t rc = 0; + if (gain > max_legal_gain) { + CDBG("Max legal gain Line:%d\n", __LINE__); + gain = max_legal_gain; + } + + if (mt9e013_ctrl->curr_res != FULL_SIZE) { + mt9e013_ctrl->my_reg_gain = gain; + mt9e013_ctrl->my_reg_line_count = (uint16_t) line; + line = (uint32_t) (line * mt9e013_ctrl->fps_divider / + 0x00000400); + } else { + line = (uint32_t) (line * mt9e013_ctrl->pict_fps_divider / + 0x00000400); + } + + gain |= 0x1000; + + mt9e013_group_hold_on(); + rc = mt9e013_i2c_write_w_sensor(REG_GLOBAL_GAIN, gain); + rc = mt9e013_i2c_write_w_sensor(REG_COARSE_INTEGRATION_TIME, line); + mt9e013_group_hold_off(); + return rc; +} + +static int32_t mt9e013_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + rc = mt9e013_write_exp_gain(gain, line); + mt9e013_i2c_write_w_sensor(0x301A, 0x065C|0x2); + return rc; +} + +#define DIV_CEIL(x, y) (x/y + (x%y) ? 1 : 0) + +static int32_t mt9e013_move_focus(int direction, + int32_t num_steps) +{ + int16_t step_direction, dest_lens_position, dest_step_position; + int16_t target_dist, small_step, next_lens_position; + if (direction == MOVE_NEAR) + step_direction = 1; + else + step_direction = -1; + + dest_step_position = mt9e013_ctrl->curr_step_pos + + (step_direction * num_steps); + + if (dest_step_position < 0) + dest_step_position = 0; + else if (dest_step_position > MT9E013_TOTAL_STEPS_NEAR_TO_FAR) + dest_step_position = MT9E013_TOTAL_STEPS_NEAR_TO_FAR; + + if (dest_step_position == mt9e013_ctrl->curr_step_pos) + return 0; + + dest_lens_position = mt9e013_step_position_table[dest_step_position]; + target_dist = step_direction * + (dest_lens_position - mt9e013_ctrl->curr_lens_pos); + + if (step_direction < 0 && (target_dist >= + mt9e013_step_position_table[mt9e013_damping_threshold])) { + small_step = DIV_CEIL(target_dist, 10); + mt9e013_sw_damping_time_wait = 10; + } else { + small_step = DIV_CEIL(target_dist, 4); + mt9e013_sw_damping_time_wait = 4; + } + + for (next_lens_position = mt9e013_ctrl->curr_lens_pos + + (step_direction * small_step); + (step_direction * next_lens_position) <= + (step_direction * dest_lens_position); + next_lens_position += (step_direction * small_step)) { + mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE, + next_lens_position); + mt9e013_ctrl->curr_lens_pos = next_lens_position; + usleep(mt9e013_sw_damping_time_wait*50); + } + + if (mt9e013_ctrl->curr_lens_pos != dest_lens_position) { + mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE, + dest_lens_position); + usleep(mt9e013_sw_damping_time_wait*50); + } + mt9e013_ctrl->curr_lens_pos = dest_lens_position; + mt9e013_ctrl->curr_step_pos = dest_step_position; + return 0; +} + +static int32_t mt9e013_set_default_focus(uint8_t af_step) +{ + int32_t rc = 0; + if (mt9e013_ctrl->curr_step_pos != 0) { + rc = mt9e013_move_focus(MOVE_FAR, + mt9e013_ctrl->curr_step_pos); + } else { + mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE, 0x00); + } + + mt9e013_ctrl->curr_lens_pos = 0; + mt9e013_ctrl->curr_step_pos = 0; + + return rc; +} + +static void mt9e013_init_focus(void) +{ + uint8_t i; + mt9e013_step_position_table[0] = 0; + for (i = 1; i <= MT9E013_TOTAL_STEPS_NEAR_TO_FAR; i++) { + if (i <= mt9e013_nl_region_boundary1) { + mt9e013_step_position_table[i] = + mt9e013_step_position_table[i-1] + + mt9e013_nl_region_code_per_step1; + } else { + mt9e013_step_position_table[i] = + mt9e013_step_position_table[i-1] + + mt9e013_l_region_code_per_step; + } + + if (mt9e013_step_position_table[i] > 255) + mt9e013_step_position_table[i] = 255; + } +} + +static int32_t mt9e013_test(enum mt9e013_test_mode_t mo) +{ + int32_t rc = 0; + if (mo == TEST_OFF) + return rc; + else { + /* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation, + 1: Bypass Signal Processing + REG_0x30D8[5] is EBDMASK: 0: + Output Embedded data, 1: No output embedded data */ + if (mt9e013_i2c_write_b_sensor(REG_TEST_PATTERN_MODE, + (uint8_t) mo) < 0) { + return rc; + } + } + return rc; +} + +static int32_t mt9e013_sensor_setting(int update_type, int rt) +{ + + int32_t rc = 0; + struct msm_camera_csi_params mt9e013_csi_params; + uint8_t stored_af_step = 0; + CDBG("sensor_settings\n"); + stored_af_step = mt9e013_ctrl->curr_step_pos; + mt9e013_set_default_focus(0); + mt9e013_stop_stream(); + msleep(15); + if (update_type == REG_INIT) { + mt9e013_i2c_write_w_table(mt9e013_regs.reg_mipi, + mt9e013_regs.reg_mipi_size); + mt9e013_i2c_write_w_table(mt9e013_regs.rec_settings, + mt9e013_regs.rec_size); + cam_debug_init(); + CSI_CONFIG = 0; + } else if (update_type == UPDATE_PERIODIC) { + if (rt == QTR_SIZE) { + mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll, + mt9e013_regs.reg_pll_size); + mt9e013_i2c_write_w_table(mt9e013_regs.reg_prev, + mt9e013_regs.reg_prev_size); + } else if (rt == FULL_SIZE) { + mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll, + mt9e013_regs.reg_pll_size); + mt9e013_i2c_write_w_table(mt9e013_regs.reg_snap, + mt9e013_regs.reg_snap_size); + } else if (rt == HFR_60FPS) { + mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll_120fps, + mt9e013_regs.reg_pll_120fps_size); + mt9e013_i2c_write_w_sensor(0x0306, 0x0029); + mt9e013_i2c_write_w_table(mt9e013_regs.reg_120fps, + mt9e013_regs.reg_120fps_size); + } else if (rt == HFR_90FPS) { + mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll_120fps, + mt9e013_regs.reg_pll_120fps_size); + mt9e013_i2c_write_w_sensor(0x0306, 0x003D); + mt9e013_i2c_write_w_table(mt9e013_regs.reg_120fps, + mt9e013_regs.reg_120fps_size); + } else if (rt == HFR_120FPS) { + msm_camio_vfe_clk_rate_set(266667000); + mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll_120fps, + mt9e013_regs.reg_pll_120fps_size); + mt9e013_i2c_write_w_table(mt9e013_regs.reg_120fps, + mt9e013_regs.reg_120fps_size); + } + if (!CSI_CONFIG) { + msm_camio_vfe_clk_rate_set(192000000); + mt9e013_csi_params.data_format = CSI_10BIT; + mt9e013_csi_params.lane_cnt = 2; + mt9e013_csi_params.lane_assign = 0xe4; + mt9e013_csi_params.dpcm_scheme = 0; + mt9e013_csi_params.settle_cnt = 0x18; + rc = msm_camio_csi_config(&mt9e013_csi_params); + msleep(10); + CSI_CONFIG = 1; + } + mt9e013_move_focus(MOVE_NEAR, stored_af_step); + mt9e013_start_stream(); + } + return rc; +} + +static int32_t mt9e013_video_config(int mode) +{ + + int32_t rc = 0; + + CDBG("video config\n"); + /* change sensor resolution if needed */ + if (mt9e013_sensor_setting(UPDATE_PERIODIC, + mt9e013_ctrl->prev_res) < 0) + return rc; + if (mt9e013_ctrl->set_test) { + if (mt9e013_test(mt9e013_ctrl->set_test) < 0) + return rc; + } + + mt9e013_ctrl->curr_res = mt9e013_ctrl->prev_res; + mt9e013_ctrl->sensormode = mode; + return rc; +} + +static int32_t mt9e013_snapshot_config(int mode) +{ + int32_t rc = 0; + /*change sensor resolution if needed */ + if (mt9e013_ctrl->curr_res != mt9e013_ctrl->pict_res) { + if (mt9e013_sensor_setting(UPDATE_PERIODIC, + mt9e013_ctrl->pict_res) < 0) + return rc; + } + + mt9e013_ctrl->curr_res = mt9e013_ctrl->pict_res; + mt9e013_ctrl->sensormode = mode; + return rc; +} /*end of mt9e013_snapshot_config*/ + +static int32_t mt9e013_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + /* change sensor resolution if needed */ + if (mt9e013_ctrl->curr_res != mt9e013_ctrl->pict_res) { + if (mt9e013_sensor_setting(UPDATE_PERIODIC, + mt9e013_ctrl->pict_res) < 0) + return rc; + } + + mt9e013_ctrl->curr_res = mt9e013_ctrl->pict_res; + mt9e013_ctrl->sensormode = mode; + return rc; +} /*end of mt9e013_raw_snapshot_config*/ + +static int32_t mt9e013_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + switch (mode) { + case SENSOR_PREVIEW_MODE: + case SENSOR_HFR_60FPS_MODE: + case SENSOR_HFR_90FPS_MODE: + case SENSOR_HFR_120FPS_MODE: + mt9e013_ctrl->prev_res = res; + rc = mt9e013_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + mt9e013_ctrl->pict_res = res; + rc = mt9e013_snapshot_config(mode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + mt9e013_ctrl->pict_res = res; + rc = mt9e013_raw_snapshot_config(mode); + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +static int32_t mt9e013_power_down(void) +{ + return 0; +} + +static int mt9e013_probe_init_done(const struct msm_camera_sensor_info *data) +{ + CDBG("probe done\n"); + gpio_free(data->sensor_reset); + return 0; +} + +static int mt9e013_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + uint16_t chipid = 0; + CDBG("%s: %d\n", __func__, __LINE__); + rc = gpio_request(data->sensor_reset, "mt9e013"); + CDBG(" mt9e013_probe_init_sensor\n"); + if (!rc) { + CDBG("sensor_reset = %d\n", rc); + gpio_direction_output(data->sensor_reset, 0); + msleep(10); + gpio_set_value_cansleep(data->sensor_reset, 1); + msleep(10); + } else { + goto init_probe_done; + } + + CDBG(" mt9e013_probe_init_sensor is called\n"); + rc = mt9e013_i2c_read(0x0000, &chipid, 2); + CDBG("ID: %d\n", chipid); + /* 4. Compare sensor ID to MT9E013 ID: */ + if (chipid != 0x4B00) { + rc = -ENODEV; + CDBG("mt9e013_probe_init_sensor fail chip id doesnot match\n"); + goto init_probe_fail; + } + + mt9e013_ctrl = kzalloc(sizeof(struct mt9e013_ctrl_t), GFP_KERNEL); + if (!mt9e013_ctrl) { + CDBG("mt9e013_init failed!\n"); + rc = -ENOMEM; + } + mt9e013_ctrl->fps_divider = 1 * 0x00000400; + mt9e013_ctrl->pict_fps_divider = 1 * 0x00000400; + mt9e013_ctrl->set_test = TEST_OFF; + mt9e013_ctrl->prev_res = QTR_SIZE; + mt9e013_ctrl->pict_res = FULL_SIZE; + + if (data) + mt9e013_ctrl->sensordata = data; + + goto init_probe_done; +init_probe_fail: + CDBG(" mt9e013_probe_init_sensor fails\n"); + gpio_set_value_cansleep(data->sensor_reset, 0); + mt9e013_probe_init_done(data); +init_probe_done: + CDBG(" mt9e013_probe_init_sensor finishes\n"); + return rc; +} +/* camsensor_mt9e013_reset */ + +int mt9e013_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + + CDBG("%s: %d\n", __func__, __LINE__); + CDBG("Calling mt9e013_sensor_open_init\n"); + + mt9e013_ctrl = kzalloc(sizeof(struct mt9e013_ctrl_t), GFP_KERNEL); + if (!mt9e013_ctrl) { + CDBG("mt9e013_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + mt9e013_ctrl->fps_divider = 1 * 0x00000400; + mt9e013_ctrl->pict_fps_divider = 1 * 0x00000400; + mt9e013_ctrl->set_test = TEST_OFF; + mt9e013_ctrl->prev_res = QTR_SIZE; + mt9e013_ctrl->pict_res = FULL_SIZE; + + if (data) + mt9e013_ctrl->sensordata = data; + if (rc < 0) { + CDBG("Calling mt9e013_sensor_open_init fail1\n"); + return rc; + } + CDBG("%s: %d\n", __func__, __LINE__); + /* enable mclk first */ + msm_camio_clk_rate_set(MT9E013_MASTER_CLK_RATE); + rc = mt9e013_probe_init_sensor(data); + if (rc < 0) + goto init_fail; + + CDBG("init settings\n"); + rc = mt9e013_sensor_setting(REG_INIT, mt9e013_ctrl->prev_res); + mt9e013_ctrl->fps = 30*Q8; + mt9e013_init_focus(); + if (rc < 0) { + gpio_set_value_cansleep(data->sensor_reset, 0); + goto init_fail; + } else + goto init_done; +init_fail: + CDBG("init_fail\n"); + mt9e013_probe_init_done(data); +init_done: + CDBG("init_done\n"); + return rc; +} /*endof mt9e013_sensor_open_init*/ + +static int mt9e013_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&mt9e013_wait_queue); + return 0; +} + +static const struct i2c_device_id mt9e013_i2c_id[] = { + {"mt9e013", 0}, + { } +}; + +static int mt9e013_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("mt9e013_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + mt9e013_sensorw = kzalloc(sizeof(struct mt9e013_work_t), GFP_KERNEL); + if (!mt9e013_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, mt9e013_sensorw); + mt9e013_init_client(client); + mt9e013_client = client; + + + CDBG("mt9e013_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("mt9e013_probe failed! rc = %d\n", rc); + return rc; +} + +static int mt9e013_send_wb_info(struct wb_info_cfg *wb) +{ + return 0; + +} /*end of mt9e013_snapshot_config*/ + +static int __exit mt9e013_remove(struct i2c_client *client) +{ + struct mt9e013_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + mt9e013_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver mt9e013_i2c_driver = { + .id_table = mt9e013_i2c_id, + .probe = mt9e013_i2c_probe, + .remove = __exit_p(mt9e013_i2c_remove), + .driver = { + .name = "mt9e013", + }, +}; + +int mt9e013_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&mt9e013_mut); + CDBG("mt9e013_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + mt9e013_get_pict_fps( + cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = + mt9e013_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = + mt9e013_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = + mt9e013_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + mt9e013_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + mt9e013_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = mt9e013_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = + mt9e013_write_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + rc = + mt9e013_set_pict_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = mt9e013_set_sensor_mode(cdata.mode, + cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = mt9e013_power_down(); + break; + + case CFG_MOVE_FOCUS: + rc = + mt9e013_move_focus( + cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = + mt9e013_set_default_focus( + cdata.cfg.focus.steps); + break; + + case CFG_GET_AF_MAX_STEPS: + cdata.max_steps = MT9E013_TOTAL_STEPS_NEAR_TO_FAR; + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_EFFECT: + rc = mt9e013_set_default_focus( + cdata.cfg.effect); + break; + + + case CFG_SEND_WB_INFO: + rc = mt9e013_send_wb_info( + &(cdata.cfg.wb_info)); + break; + + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&mt9e013_mut); + + return rc; +} + +static int mt9e013_sensor_release(void) +{ + int rc = -EBADF; + mutex_lock(&mt9e013_mut); + mt9e013_power_down(); + gpio_set_value_cansleep(mt9e013_ctrl->sensordata->sensor_reset, 0); + msleep(5); + gpio_free(mt9e013_ctrl->sensordata->sensor_reset); + kfree(mt9e013_ctrl); + mt9e013_ctrl = NULL; + CDBG("mt9e013_release completed\n"); + mutex_unlock(&mt9e013_mut); + + return rc; +} + +static int mt9e013_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(&mt9e013_i2c_driver); + if (rc < 0 || mt9e013_client == NULL) { + rc = -ENOTSUPP; + CDBG("I2C add driver failed"); + goto probe_fail; + } + msm_camio_clk_rate_set(MT9E013_MASTER_CLK_RATE); + rc = mt9e013_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + s->s_init = mt9e013_sensor_open_init; + s->s_release = mt9e013_sensor_release; + s->s_config = mt9e013_sensor_config; + s->s_mount_angle = info->sensor_platform_info->mount_angle; + gpio_set_value_cansleep(info->sensor_reset, 0); + mt9e013_probe_init_done(info); + return rc; + +probe_fail: + CDBG("mt9e013_sensor_probe: SENSOR PROBE FAILS!\n"); + return rc; +} + +static int __mt9e013_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, mt9e013_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __mt9e013_probe, + .driver = { + .name = "msm_camera_mt9e013", + .owner = THIS_MODULE, + }, +}; + +static int __init mt9e013_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(mt9e013_init); +void mt9e013_exit(void) +{ + i2c_del_driver(&mt9e013_i2c_driver); +} +MODULE_DESCRIPTION("Aptina 8 MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); + +static bool streaming = 1; + +static int mt9e013_focus_test(void *data, u64 *val) +{ + int i = 0; + mt9e013_set_default_focus(0); + + for (i = 90; i < 256; i++) { + mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE, i); + msleep(5000); + } + msleep(5000); + for (i = 255; i > 90; i--) { + mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE, i); + msleep(5000); + } + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_focus, mt9e013_focus_test, + NULL, "%lld\n"); + +static int mt9e013_step_test(void *data, u64 *val) +{ + int i = 0; + mt9e013_set_default_focus(0); + + for (i = 0; i < MT9E013_TOTAL_STEPS_NEAR_TO_FAR; i++) { + mt9e013_move_focus(MOVE_NEAR, 1); + msleep(5000); + } + + mt9e013_move_focus(MOVE_FAR, MT9E013_TOTAL_STEPS_NEAR_TO_FAR); + msleep(5000); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_step, mt9e013_step_test, + NULL, "%lld\n"); + +static int cam_debug_stream_set(void *data, u64 val) +{ + int rc = 0; + + if (val) { + mt9e013_start_stream(); + streaming = 1; + } else { + mt9e013_stop_stream(); + streaming = 0; + } + + return rc; +} + +static int cam_debug_stream_get(void *data, u64 *val) +{ + *val = streaming; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(cam_stream, cam_debug_stream_get, + cam_debug_stream_set, "%llu\n"); + + +static int cam_debug_init(void) +{ + struct dentry *cam_dir; + debugfs_base = debugfs_create_dir("sensor", NULL); + if (!debugfs_base) + return -ENOMEM; + + cam_dir = debugfs_create_dir("mt9e013", debugfs_base); + if (!cam_dir) + return -ENOMEM; + + if (!debugfs_create_file("focus", S_IRUGO | S_IWUSR, cam_dir, + NULL, &cam_focus)) + return -ENOMEM; + if (!debugfs_create_file("step", S_IRUGO | S_IWUSR, cam_dir, + NULL, &cam_step)) + return -ENOMEM; + if (!debugfs_create_file("stream", S_IRUGO | S_IWUSR, cam_dir, + NULL, &cam_stream)) + return -ENOMEM; + + return 0; +} diff --git a/drivers/media/video/msm_zsl/mt9e013.h b/drivers/media/video/msm_zsl/mt9e013.h new file mode 100644 index 00000000000..9052a354453 --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9e013.h @@ -0,0 +1,174 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef MT9E013_H +#define MT9E013_H +#include +#include +extern struct mt9e013_reg mt9e013_regs; +struct reg_struct_init { + uint8_t reg_0x0112; /* 0x0112*/ + uint8_t reg_0x0113; /* 0x0113*/ + uint8_t vt_pix_clk_div; /* 0x0301*/ + uint8_t pre_pll_clk_div; /* 0x0305*/ + uint8_t pll_multiplier; /* 0x0307*/ + uint8_t op_pix_clk_div; /* 0x0309*/ + uint8_t reg_0x3030; /*0x3030*/ + uint8_t reg_0x0111; /*0x0111*/ + uint8_t reg_0x0b00; /*0x0b00*/ + uint8_t reg_0x3001; /*0x3001*/ + uint8_t reg_0x3004; /*0x3004*/ + uint8_t reg_0x3007; /*0x3007*/ + uint8_t reg_0x3016; /*0x3016*/ + uint8_t reg_0x301d; /*0x301d*/ + uint8_t reg_0x317e; /*0x317E*/ + uint8_t reg_0x317f; /*0x317F*/ + uint8_t reg_0x3400; /*0x3400*/ + uint8_t reg_0x0b06; /*0x0b06*/ + uint8_t reg_0x0b07; /*0x0b07*/ + uint8_t reg_0x0b08; /*0x0b08*/ + uint8_t reg_0x0b09; /*0x0b09*/ + uint8_t reg_0x0136; + uint8_t reg_0x0137; + /* Edof */ + uint8_t reg_0x0b83; /*0x0b83*/ + uint8_t reg_0x0b84; /*0x0b84*/ + uint8_t reg_0x0b85; /*0x0b85*/ + uint8_t reg_0x0b88; /*0x0b88*/ + uint8_t reg_0x0b89; /*0x0b89*/ + uint8_t reg_0x0b8a; /*0x0b8a*/ + }; +struct reg_struct { + uint8_t coarse_integration_time_hi; /*REG_COARSE_INTEGRATION_TIME_HI*/ + uint8_t coarse_integration_time_lo; /*REG_COARSE_INTEGRATION_TIME_LO*/ + uint8_t analogue_gain_code_global; + uint8_t frame_length_lines_hi; /* 0x0340*/ + uint8_t frame_length_lines_lo; /* 0x0341*/ + uint8_t line_length_pck_hi; /* 0x0342*/ + uint8_t line_length_pck_lo; /* 0x0343*/ + uint8_t reg_0x3005; /* 0x3005*/ + uint8_t reg_0x3010; /* 0x3010*/ + uint8_t reg_0x3011; /* 0x3011*/ + uint8_t reg_0x301a; /* 0x301a*/ + uint8_t reg_0x3035; /* 0x3035*/ + uint8_t reg_0x3036; /* 0x3036*/ + uint8_t reg_0x3041; /*0x3041*/ + uint8_t reg_0x3042; /*0x3042*/ + uint8_t reg_0x3045; /*0x3045*/ + uint8_t reg_0x0b80; /* 0x0b80*/ + uint8_t reg_0x0900; /*0x0900*/ + uint8_t reg_0x0901; /* 0x0901*/ + uint8_t reg_0x0902; /*0x0902*/ + uint8_t reg_0x0383; /*0x0383*/ + uint8_t reg_0x0387; /* 0x0387*/ + uint8_t reg_0x034c; /* 0x034c*/ + uint8_t reg_0x034d; /*0x034d*/ + uint8_t reg_0x034e; /* 0x034e*/ + uint8_t reg_0x034f; /* 0x034f*/ + uint8_t reg_0x1716; /*0x1716*/ + uint8_t reg_0x1717; /*0x1717*/ + uint8_t reg_0x1718; /*0x1718*/ + uint8_t reg_0x1719; /*0x1719*/ + uint8_t reg_0x3210;/*0x3210*/ + uint8_t reg_0x111; /*0x111*/ + uint8_t reg_0x3410; /*0x3410*/ + uint8_t reg_0x3098; + uint8_t reg_0x309D; + uint8_t reg_0x0200; + uint8_t reg_0x0201; + }; +struct mt9e013_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum mt9e013_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum mt9e013_resolution_t { + QTR_SIZE, + FULL_SIZE, + HFR_60FPS, + HFR_90FPS, + HFR_120FPS, + INVALID_SIZE +}; +enum mt9e013_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum mt9e013_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum mt9e013_reg_pll { + E013_VT_PIX_CLK_DIV, + E013_VT_SYS_CLK_DIV, + E013_PRE_PLL_CLK_DIV, + E013_PLL_MULTIPLIER, + E013_OP_PIX_CLK_DIV, + E013_OP_SYS_CLK_DIV +}; + +enum mt9e013_reg_mode { + E013_X_ADDR_START, + E013_X_ADDR_END, + E013_Y_ADDR_START, + E013_Y_ADDR_END, + E013_X_OUTPUT_SIZE, + E013_Y_OUTPUT_SIZE, + E013_DATAPATH_SELECT, + E013_READ_MODE, + E013_ANALOG_CONTROL5, + E013_DAC_LD_4_5, + E013_SCALING_MODE, + E013_SCALE_M, + E013_LINE_LENGTH_PCK, + E013_FRAME_LENGTH_LINES, + E013_COARSE_INTEGRATION_TIME, + E013_FINE_INTEGRATION_TIME, + E013_FINE_CORRECTION +}; + +struct mt9e013_reg { + const struct mt9e013_i2c_reg_conf *reg_mipi; + const unsigned short reg_mipi_size; + const struct mt9e013_i2c_reg_conf *rec_settings; + const unsigned short rec_size; + const struct mt9e013_i2c_reg_conf *reg_pll; + const unsigned short reg_pll_size; + const struct mt9e013_i2c_reg_conf *reg_pll_60fps; + const unsigned short reg_pll_60fps_size; + const struct mt9e013_i2c_reg_conf *reg_pll_120fps; + const unsigned short reg_pll_120fps_size; + const struct mt9e013_i2c_reg_conf *reg_prev; + const unsigned short reg_prev_size; + const struct mt9e013_i2c_reg_conf *reg_snap; + const unsigned short reg_snap_size; + const struct mt9e013_i2c_reg_conf *reg_60fps; + const unsigned short reg_60fps_size; + const struct mt9e013_i2c_reg_conf *reg_120fps; + const unsigned short reg_120fps_size; +}; +#endif /* MT9E013_H */ diff --git a/drivers/media/video/msm_zsl/mt9e013_reg.c b/drivers/media/video/msm_zsl/mt9e013_reg.c new file mode 100644 index 00000000000..9a4bd7eefa9 --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9e013_reg.c @@ -0,0 +1,234 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + + +#include "mt9e013.h" + +static struct mt9e013_i2c_reg_conf mipi_settings[] = { + /*Disable embedded data*/ + {0x3064, 0x7800},/*SMIA_TEST*/ + /*configure 2-lane MIPI*/ + {0x31AE, 0x0202},/*SERIAL_FORMAT*/ + {0x31B8, 0x0E3F},/*MIPI_TIMING_2*/ + /*set data to RAW10 format*/ + {0x0112, 0x0A0A},/*CCP_DATA_FORMAT*/ + {0x30F0, 0x8000},/*VCM CONTROL*/ +}; + +/*PLL Configuration +(Ext=24MHz, vt_pix_clk=174MHz, op_pix_clk=69.6MHz)*/ +static struct mt9e013_i2c_reg_conf pll_settings[] = { + {0x0300, 0x0004},/*VT_PIX_CLK_DIV*/ + {0x0302, 0x0001},/*VT_SYS_CLK_DIV*/ + {0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/ + {0x0306, 0x003A},/*PLL_MULTIPLIER*/ + {0x0308, 0x000A},/*OP_PIX_CLK_DIV*/ + {0x030A, 0x0001},/*OP_SYS_CLK_DIV*/ +}; + +static struct mt9e013_i2c_reg_conf prev_settings[] = { + /*Output Size (1632x1224)*/ + {0x0344, 0x0008},/*X_ADDR_START*/ + {0x0348, 0x0CC9},/*X_ADDR_END*/ + {0x0346, 0x0008},/*Y_ADDR_START*/ + {0x034A, 0x0999},/*Y_ADDR_END*/ + {0x034C, 0x0660},/*X_OUTPUT_SIZE*/ + {0x034E, 0x04C8},/*Y_OUTPUT_SIZE*/ + {0x306E, 0xFCB0},/*DATAPATH_SELECT*/ + {0x3040, 0x04C3},/*READ_MODE*/ + {0x3178, 0x0000},/*ANALOG_CONTROL5*/ + {0x3ED0, 0x1E24},/*DAC_LD_4_5*/ + {0x0400, 0x0002},/*SCALING_MODE*/ + {0x0404, 0x0010},/*SCALE_M*/ + /*Timing configuration*/ + {0x0342, 0x1018},/*LINE_LENGTH_PCK*/ + {0x0340, 0x055B},/*FRAME_LENGTH_LINES*/ + {0x0202, 0x0557},/*COARSE_INTEGRATION_TIME*/ + {0x3014, 0x0846},/*FINE_INTEGRATION_TIME_*/ + {0x3010, 0x0130},/*FINE_CORRECTION*/ +}; + +static struct mt9e013_i2c_reg_conf snap_settings[] = { + /*Output Size (3264x2448)*/ + {0x0344, 0x0008},/*X_ADDR_START */ + {0x0348, 0x0CD7},/*X_ADDR_END*/ + {0x0346, 0x0008},/*Y_ADDR_START */ + {0x034A, 0x09A7},/*Y_ADDR_END*/ + {0x034C, 0x0CD0},/*X_OUTPUT_SIZE*/ + {0x034E, 0x09A0},/*Y_OUTPUT_SIZE*/ + {0x306E, 0xFC80},/*DATAPATH_SELECT*/ + {0x3040, 0x0041},/*READ_MODE*/ + {0x3178, 0x0000},/*ANALOG_CONTROL5*/ + {0x3ED0, 0x1E24},/*DAC_LD_4_5*/ + {0x0400, 0x0000},/*SCALING_MODE*/ + {0x0404, 0x0010},/*SCALE_M*/ + /*Timing configuration*/ + {0x0342, 0x13F8},/*LINE_LENGTH_PCK*/ + {0x0340, 0x0A2F},/*FRAME_LENGTH_LINES*/ + {0x0202, 0x0A1F},/*COARSE_INTEGRATION_TIME*/ + {0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_ */ + {0x3010, 0x0078},/*FINE_CORRECTION*/ +}; + +static struct mt9e013_i2c_reg_conf pll_settings_60fps[] = { + {0x0300, 0x0004},/*VT_PIX_CLK_DIV*/ + {0x0302, 0x0001},/*VT_SYS_CLK_DIV*/ + {0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/ + {0x0306, 0x0042},/*PLL_MULTIPLIER*/ + {0x0308, 0x000A},/*OP_PIX_CLK_DIV*/ + {0x030A, 0x0001},/*OP_SYS_CLK_DIV*/ +}; + +static struct mt9e013_i2c_reg_conf prev_settings_60fps[] = { + /*Output Size (1632x1224)*/ + {0x0344, 0x0008},/*X_ADDR_START*/ + {0x0348, 0x0CC5},/*X_ADDR_END*/ + {0x0346, 0x013a},/*Y_ADDR_START*/ + {0x034A, 0x0863},/*Y_ADDR_END*/ + {0x034C, 0x0660},/*X_OUTPUT_SIZE*/ + {0x034E, 0x0396},/*Y_OUTPUT_SIZE*/ + {0x306E, 0xFC80},/*DATAPATH_SELECT*/ + {0x3040, 0x00C3},/*READ_MODE*/ + {0x3178, 0x0000},/*ANALOG_CONTROL5*/ + {0x3ED0, 0x1E24},/*DAC_LD_4_5*/ + {0x0400, 0x0000},/*SCALING_MODE*/ + {0x0404, 0x0010},/*SCALE_M*/ + /*Timing configuration*/ + {0x0342, 0x0BE8},/*LINE_LENGTH_PCK*/ + {0x0340, 0x0425},/*FRAME_LENGTH_LINES*/ + {0x0202, 0x0425},/*COARSE_INTEGRATION_TIME*/ + {0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/ + {0x3010, 0x0078},/*FINE_CORRECTION*/ +}; + +static struct mt9e013_i2c_reg_conf pll_settings_120fps[] = { + {0x0300, 0x0005},/*VT_PIX_CLK_DIV*/ + {0x0302, 0x0001},/*VT_SYS_CLK_DIV*/ + {0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/ + {0x0306, 0x0052},/*PLL_MULTIPLIER*/ + {0x0308, 0x000A},/*OP_PIX_CLK_DIV*/ + {0x030A, 0x0001},/*OP_SYS_CLK_DIV*/ +}; + +static struct mt9e013_i2c_reg_conf prev_settings_120fps[] = { + {0x0344, 0x0008},/*X_ADDR_START*/ + {0x0348, 0x0685},/*X_ADDR_END*/ + {0x0346, 0x013a},/*Y_ADDR_START*/ + {0x034A, 0x055B},/*Y_ADDR_END*/ + {0x034C, 0x0340},/*X_OUTPUT_SIZE*/ + {0x034E, 0x0212},/*Y_OUTPUT_SIZE*/ + {0x306E, 0xFC80},/*DATAPATH_SELECT*/ + {0x3040, 0x00C3},/*READ_MODE*/ + {0x3178, 0x0000},/*ANALOG_CONTROL5*/ + {0x3ED0, 0x1E24},/*DAC_LD_4_5*/ + {0x0400, 0x0000},/*SCALING_MODE*/ + {0x0404, 0x0010},/*SCALE_M*/ + /*Timing configuration*/ + {0x0342, 0x0970},/*LINE_LENGTH_PCK*/ + {0x0340, 0x02A1},/*FRAME_LENGTH_LINES*/ + {0x0202, 0x02A1},/*COARSE_INTEGRATION_TIME*/ + {0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/ + {0x3010, 0x0078},/*FINE_CORRECTION*/ +}; + +static struct mt9e013_i2c_reg_conf recommend_settings[] = { + {0x3044, 0x0590}, + {0x306E, 0xFC80}, + {0x30B2, 0xC000}, + {0x30D6, 0x0800}, + {0x316C, 0xB42F}, + {0x316E, 0x869C}, + {0x3170, 0x210E}, + {0x317A, 0x010E}, + {0x31E0, 0x1FB9}, + {0x31E6, 0x07FC}, + {0x37C0, 0x0000}, + {0x37C2, 0x0000}, + {0x37C4, 0x0000}, + {0x37C6, 0x0000}, + {0x3E02, 0x8801}, + {0x3E04, 0x2301}, + {0x3E06, 0x8449}, + {0x3E08, 0x6841}, + {0x3E0A, 0x400C}, + {0x3E0C, 0x1001}, + {0x3E0E, 0x2103}, + {0x3E10, 0x4B41}, + {0x3E12, 0x4B26}, + {0x3E16, 0x8802}, + {0x3E18, 0x84FF}, + {0x3E1A, 0x8601}, + {0x3E1C, 0x8401}, + {0x3E1E, 0x840A}, + {0x3E20, 0xFF00}, + {0x3E22, 0x8401}, + {0x3E24, 0x00FF}, + {0x3E26, 0x0088}, + {0x3E28, 0x2E8A}, + {0x3E32, 0x8801}, + {0x3E34, 0x4024}, + {0x3E38, 0x8469}, + {0x3E3C, 0x2301}, + {0x3E3E, 0x3E25}, + {0x3E40, 0x1C01}, + {0x3E42, 0x8486}, + {0x3E44, 0x8401}, + {0x3E46, 0x00FF}, + {0x3E48, 0x8401}, + {0x3E4A, 0x8601}, + {0x3E4C, 0x8402}, + {0x3E4E, 0x00FF}, + {0x3E50, 0x6623}, + {0x3E52, 0x8340}, + {0x3E54, 0x00FF}, + {0x3E56, 0x4A42}, + {0x3E58, 0x2203}, + {0x3E5A, 0x674D}, + {0x3E5C, 0x3F25}, + {0x3E5E, 0x846A}, + {0x3E60, 0x4C01}, + {0x3E62, 0x8401}, + {0x3E66, 0x3901}, + {0x3ECC, 0x00EB}, + {0x3ED0, 0x1E24}, + {0x3ED4, 0xAFC4}, + {0x3ED6, 0x909B}, + {0x3ED8, 0x0006}, + {0x3EDA, 0xCFC6}, + {0x3EDC, 0x4FE4}, + {0x3EE0, 0x2424}, + {0x3EE2, 0x9797}, + {0x3EE4, 0xC100}, + {0x3EE6, 0x0540} +}; + +struct mt9e013_reg mt9e013_regs = { + .reg_mipi = &mipi_settings[0], + .reg_mipi_size = ARRAY_SIZE(mipi_settings), + .rec_settings = &recommend_settings[0], + .rec_size = ARRAY_SIZE(recommend_settings), + .reg_pll = &pll_settings[0], + .reg_pll_size = ARRAY_SIZE(pll_settings), + .reg_prev = &prev_settings[0], + .reg_pll_60fps = &pll_settings_60fps[0], + .reg_pll_60fps_size = ARRAY_SIZE(pll_settings_60fps), + .reg_pll_120fps = &pll_settings_120fps[0], + .reg_pll_120fps_size = ARRAY_SIZE(pll_settings_120fps), + .reg_prev_size = ARRAY_SIZE(prev_settings), + .reg_snap = &snap_settings[0], + .reg_snap_size = ARRAY_SIZE(snap_settings), + .reg_60fps = &prev_settings_60fps[0], + .reg_60fps_size = ARRAY_SIZE(prev_settings_60fps), + .reg_120fps = &prev_settings_120fps[0], + .reg_120fps_size = ARRAY_SIZE(prev_settings_120fps), +}; diff --git a/drivers/media/video/msm_zsl/mt9p012.h b/drivers/media/video/msm_zsl/mt9p012.h new file mode 100644 index 00000000000..05798130bbf --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9p012.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef MT9T012_H +#define MT9T012_H + +#include + +extern struct mt9p012_reg mt9p012_regs; /* from mt9p012_reg.c */ + +struct reg_struct { + uint16_t vt_pix_clk_div; /* 0x0300 */ + uint16_t vt_sys_clk_div; /* 0x0302 */ + uint16_t pre_pll_clk_div; /* 0x0304 */ + uint16_t pll_multiplier; /* 0x0306 */ + uint16_t op_pix_clk_div; /* 0x0308 */ + uint16_t op_sys_clk_div; /* 0x030A */ + uint16_t scale_m; /* 0x0404 */ + uint16_t row_speed; /* 0x3016 */ + uint16_t x_addr_start; /* 0x3004 */ + uint16_t x_addr_end; /* 0x3008 */ + uint16_t y_addr_start; /* 0x3002 */ + uint16_t y_addr_end; /* 0x3006 */ + uint16_t read_mode; /* 0x3040 */ + uint16_t x_output_size ; /* 0x034C */ + uint16_t y_output_size; /* 0x034E */ + uint16_t line_length_pck; /* 0x300C */ + uint16_t frame_length_lines; /* 0x300A */ + uint16_t coarse_int_time; /* 0x3012 */ + uint16_t fine_int_time; /* 0x3014 */ +}; + + +struct mt9p012_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + + +struct mt9p012_reg { + struct reg_struct const *reg_pat; + uint16_t reg_pat_size; + struct mt9p012_i2c_reg_conf const *ttbl; + uint16_t ttbl_size; + struct mt9p012_i2c_reg_conf const *rftbl; + uint16_t rftbl_size; +}; + +#endif /* MT9T012_H */ diff --git a/drivers/media/video/msm_zsl/mt9p012_bam.c b/drivers/media/video/msm_zsl/mt9p012_bam.c new file mode 100644 index 00000000000..919738099f3 --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9p012_bam.c @@ -0,0 +1,1426 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mt9p012.h" + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ +#define MT9P012_REG_MODEL_ID 0x0000 +#define MT9P012_MODEL_ID 0x2801 +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD 0x0100 +#define GROUPED_PARAMETER_UPDATE 0x0000 +#define REG_COARSE_INT_TIME 0x3012 +#define REG_VT_PIX_CLK_DIV 0x0300 +#define REG_VT_SYS_CLK_DIV 0x0302 +#define REG_PRE_PLL_CLK_DIV 0x0304 +#define REG_PLL_MULTIPLIER 0x0306 +#define REG_OP_PIX_CLK_DIV 0x0308 +#define REG_OP_SYS_CLK_DIV 0x030A +#define REG_SCALE_M 0x0404 +#define REG_FRAME_LENGTH_LINES 0x300A +#define REG_LINE_LENGTH_PCK 0x300C +#define REG_X_ADDR_START 0x3004 +#define REG_Y_ADDR_START 0x3002 +#define REG_X_ADDR_END 0x3008 +#define REG_Y_ADDR_END 0x3006 +#define REG_X_OUTPUT_SIZE 0x034C +#define REG_Y_OUTPUT_SIZE 0x034E +#define REG_FINE_INTEGRATION_TIME 0x3014 +#define REG_ROW_SPEED 0x3016 +#define MT9P012_REG_RESET_REGISTER 0x301A +#define MT9P012_RESET_REGISTER_PWON 0x10CC +#define MT9P012_RESET_REGISTER_PWOFF 0x10C8 +#define REG_READ_MODE 0x3040 +#define REG_GLOBAL_GAIN 0x305E +#define REG_TEST_PATTERN_MODE 0x3070 + +#define MT9P012_REV_7 + +enum mt9p012_test_mode { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum mt9p012_resolution { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; + +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum mt9p012_setting { + RES_PREVIEW, + RES_CAPTURE +}; + +/* actuator's Slave Address */ +#define MT9P012_AF_I2C_ADDR 0x0A + +/* AF Total steps parameters */ +#define MT9P012_STEPS_NEAR_TO_CLOSEST_INF 20 +#define MT9P012_TOTAL_STEPS_NEAR_TO_FAR 20 + +#define MT9P012_MU5M0_PREVIEW_DUMMY_PIXELS 0 +#define MT9P012_MU5M0_PREVIEW_DUMMY_LINES 0 + +/* Time in milisecs for waiting for the sensor to reset.*/ +#define MT9P012_RESET_DELAY_MSECS 66 + +/* for 20 fps preview */ +#define MT9P012_DEFAULT_CLOCK_RATE 24000000 +#define MT9P012_DEFAULT_MAX_FPS 26 /* ???? */ + +struct mt9p012_work { + struct work_struct work; +}; +static struct mt9p012_work *mt9p012_sensorw; +static struct i2c_client *mt9p012_client; + +struct mt9p012_ctrl { + const struct msm_camera_sensor_info *sensordata; + + int sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + + uint16_t curr_lens_pos; + uint16_t init_curr_lens_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + + enum mt9p012_resolution prev_res; + enum mt9p012_resolution pict_res; + enum mt9p012_resolution curr_res; + enum mt9p012_test_mode set_test; +}; + +static uint16_t bam_macro, bam_infinite; +static uint16_t bam_step_lookup_table[MT9P012_TOTAL_STEPS_NEAR_TO_FAR + 1]; +static uint16_t update_type = UPDATE_PERIODIC; +static struct mt9p012_ctrl *mt9p012_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(mt9p012_wait_queue); +DEFINE_MUTEX(mt9p012_mut); + +/*=============================================================*/ + +static int mt9p012_i2c_rxdata(unsigned short saddr, int slength, + unsigned char *rxdata, int rxlength) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = slength, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = rxlength, + .buf = rxdata, + }, + }; + + if (i2c_transfer(mt9p012_client->adapter, msgs, 2) < 0) { + CDBG("mt9p012_i2c_rxdata failed!\n"); + return -EIO; + } + + return 0; +} +static int32_t mt9p012_i2c_read_b(unsigned short saddr, unsigned char raddr, + unsigned short *rdata) +{ + int32_t rc = 0; + if (!rdata) + return -EIO; + rc = mt9p012_i2c_rxdata(saddr, 1, &raddr, 1); + if (rc < 0) + return rc; + *rdata = raddr; + if (rc < 0) + CDBG("mt9p012_i2c_read_b failed!\n"); + return rc; +} + +static int32_t mt9p012_i2c_read_w(unsigned short saddr, unsigned short raddr, + unsigned short *rdata) +{ + int32_t rc = 0; + unsigned char buf[4]; + + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + + rc = mt9p012_i2c_rxdata(saddr, 2, buf, 2); + if (rc < 0) + return rc; + + *rdata = buf[0] << 8 | buf[1]; + + if (rc < 0) + CDBG("mt9p012_i2c_read failed!\n"); + + return rc; +} + +static int32_t mt9p012_i2c_txdata(unsigned short saddr, unsigned char *txdata, + int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + if (i2c_transfer(mt9p012_client->adapter, msg, 1) < 0) { + CDBG("mt9p012_i2c_txdata failed\n"); + return -EIO; + } + + return 0; +} + +static int32_t mt9p012_i2c_write_b(unsigned short saddr, unsigned short baddr, + unsigned short bdata) +{ + int32_t rc = -EIO; + unsigned char buf[2]; + + memset(buf, 0, sizeof(buf)); + buf[0] = baddr; + buf[1] = bdata; + rc = mt9p012_i2c_txdata(saddr, buf, 2); + + if (rc < 0) + CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!\n", + saddr, baddr, bdata); + + return rc; +} + +static int32_t mt9p012_i2c_write_w(unsigned short saddr, unsigned short waddr, + unsigned short wdata) +{ + int32_t rc = -EIO; + unsigned char buf[4]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00) >> 8; + buf[3] = (wdata & 0x00FF); + + rc = mt9p012_i2c_txdata(saddr, buf, 4); + + if (rc < 0) + CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + + return rc; +} + +static int32_t mt9p012_i2c_write_w_table(struct mt9p012_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + + for (i = 0; i < num; i++) { + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + + return rc; +} + +static int32_t mt9p012_test(enum mt9p012_test_mode mo) +{ + int32_t rc = 0; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + if (mo == TEST_OFF) + return 0; + else { + rc = mt9p012_i2c_write_w_table(mt9p012_regs.ttbl, + mt9p012_regs.ttbl_size); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_TEST_PATTERN_MODE, (uint16_t) mo); + if (rc < 0) + return rc; + } + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t mt9p012_lens_shading_enable(uint8_t is_enable) +{ + int32_t rc = 0; + + CDBG("%s: entered. enable = %d\n", __func__, is_enable); + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3780, + ((uint16_t) is_enable) << 15); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + + CDBG("%s: exiting. rc = %d\n", __func__, rc); + return rc; +} + +static int32_t mt9p012_set_lc(void) +{ + int32_t rc; + + rc = mt9p012_i2c_write_w_table(mt9p012_regs.rftbl, + mt9p012_regs.rftbl_size); + + return rc; +} + +static void mt9p012_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint32_t divider; /*Q10 */ + uint32_t pclk_mult; /*Q10 */ + + if (mt9p012_ctrl->prev_res == QTR_SIZE) { + divider = (uint32_t) + (((mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines * + mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck) * + 0x00000400) / + (mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines * + mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck)); + + pclk_mult = + (uint32_t) ((mt9p012_regs.reg_pat[RES_CAPTURE]. + pll_multiplier * 0x00000400) / + (mt9p012_regs.reg_pat[RES_PREVIEW]. + pll_multiplier)); + } else { + /* full size resolution used for preview. */ + divider = 0x00000400; /*1.0 */ + pclk_mult = 0x00000400; /*1.0 */ + } + + /* Verify PCLK settings and frame sizes. */ + *pfps = (uint16_t) (fps * divider * pclk_mult / 0x00000400 / + 0x00000400); +} + +static uint16_t mt9p012_get_prev_lines_pf(void) +{ + if (mt9p012_ctrl->prev_res == QTR_SIZE) + return mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines; + else + return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines; +} + +static uint16_t mt9p012_get_prev_pixels_pl(void) +{ + if (mt9p012_ctrl->prev_res == QTR_SIZE) + return mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck; + else + return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck; +} + +static uint16_t mt9p012_get_pict_lines_pf(void) +{ + return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines; +} + +static uint16_t mt9p012_get_pict_pixels_pl(void) +{ + return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck; +} + +static uint32_t mt9p012_get_pict_max_exp_lc(void) +{ + uint16_t snapshot_lines_per_frame; + + if (mt9p012_ctrl->pict_res == QTR_SIZE) + snapshot_lines_per_frame = + mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1; + else + snapshot_lines_per_frame = + mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1; + + return snapshot_lines_per_frame * 24; +} + +static int32_t mt9p012_set_fps(struct fps_cfg *fps) +{ + /* input is new fps in Q10 format */ + int32_t rc = 0; + enum mt9p012_setting setting; + + mt9p012_ctrl->fps_divider = fps->fps_div; + mt9p012_ctrl->pict_fps_divider = fps->pict_fps_div; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return -EBUSY; + + if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) + setting = RES_PREVIEW; + else + setting = RES_CAPTURE; + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_FRAME_LENGTH_LINES, + (mt9p012_regs.reg_pat[setting].frame_length_lines * + fps->fps_div / 0x00000400)); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + + return rc; +} + +static int32_t mt9p012_write_exp_gain(uint16_t gain, uint32_t line) +{ + uint16_t max_legal_gain = 0x01FF; + uint32_t line_length_ratio = 0x00000400; + enum mt9p012_setting setting; + int32_t rc = 0; + + CDBG("Line:%d mt9p012_write_exp_gain \n", __LINE__); + + if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + mt9p012_ctrl->my_reg_gain = gain; + mt9p012_ctrl->my_reg_line_count = (uint16_t) line; + } + + if (gain > max_legal_gain) { + CDBG("Max legal gain Line:%d \n", __LINE__); + gain = max_legal_gain; + } + + /* Verify no overflow */ + if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + line = (uint32_t) (line * mt9p012_ctrl->fps_divider / + 0x00000400); + setting = RES_PREVIEW; + } else { + line = (uint32_t) (line * mt9p012_ctrl->pict_fps_divider / + 0x00000400); + setting = RES_CAPTURE; + } + + /* Set digital gain to 1 */ +#ifdef MT9P012_REV_7 + gain |= 0x1000; +#else + gain |= 0x0200; +#endif + + if ((mt9p012_regs.reg_pat[setting].frame_length_lines - 1) < line) { + line_length_ratio = (uint32_t) (line * 0x00000400) / + (mt9p012_regs.reg_pat[setting].frame_length_lines - 1); + } else + line_length_ratio = 0x00000400; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, REG_GLOBAL_GAIN, gain); + if (rc < 0) { + CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_COARSE_INT_TIME, line); + if (rc < 0) { + CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + CDBG("mt9p012_write_exp_gain: gain = %d, line = %d\n", gain, line); + + return rc; +} + +static int32_t mt9p012_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + + CDBG("Line:%d mt9p012_set_pict_exp_gain \n", __LINE__); + + rc = mt9p012_write_exp_gain(gain, line); + if (rc < 0) { + CDBG("Line:%d mt9p012_set_pict_exp_gain failed... \n", + __LINE__); + return rc; + } + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0002); + if (rc < 0) { + CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + mdelay(5); + + /* camera_timed_wait(snapshot_wait*exposure_ratio); */ + return rc; +} + +static int32_t mt9p012_setting(enum mt9p012_reg_update rupdate, + enum mt9p012_setting rt) +{ + int32_t rc = 0; + + switch (rupdate) { + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct mt9p012_i2c_reg_conf ppc_tbl[] = { + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD}, + {REG_ROW_SPEED, + mt9p012_regs.reg_pat[rt].row_speed}, + {REG_X_ADDR_START, + mt9p012_regs.reg_pat[rt].x_addr_start}, + {REG_X_ADDR_END, + mt9p012_regs.reg_pat[rt].x_addr_end}, + {REG_Y_ADDR_START, + mt9p012_regs.reg_pat[rt].y_addr_start}, + {REG_Y_ADDR_END, + mt9p012_regs.reg_pat[rt].y_addr_end}, + {REG_READ_MODE, + mt9p012_regs.reg_pat[rt].read_mode}, + {REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m}, + {REG_X_OUTPUT_SIZE, + mt9p012_regs.reg_pat[rt].x_output_size}, + {REG_Y_OUTPUT_SIZE, + mt9p012_regs.reg_pat[rt].y_output_size}, + + {REG_LINE_LENGTH_PCK, + mt9p012_regs.reg_pat[rt].line_length_pck}, + {REG_FRAME_LENGTH_LINES, + (mt9p012_regs.reg_pat[rt].frame_length_lines * + mt9p012_ctrl->fps_divider / 0x00000400)}, + {REG_COARSE_INT_TIME, + mt9p012_regs.reg_pat[rt].coarse_int_time}, + {REG_FINE_INTEGRATION_TIME, + mt9p012_regs.reg_pat[rt].fine_int_time}, + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE}, + }; + if (update_type == REG_INIT) { + update_type = rupdate; + return rc; + } + rc = mt9p012_i2c_write_w_table(&ppc_tbl[0], + ARRAY_SIZE(ppc_tbl)); + if (rc < 0) + return rc; + + rc = mt9p012_test(mt9p012_ctrl->set_test); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWON | + 0x0002); + if (rc < 0) + return rc; + + mdelay(5); /* 15? wait for sensor to transition */ + + return rc; + } + break; /* UPDATE_PERIODIC */ + + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct mt9p012_i2c_reg_conf ipc_tbl1[] = { + {MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWOFF}, + {REG_VT_PIX_CLK_DIV, + mt9p012_regs.reg_pat[rt].vt_pix_clk_div}, + {REG_VT_SYS_CLK_DIV, + mt9p012_regs.reg_pat[rt].vt_sys_clk_div}, + {REG_PRE_PLL_CLK_DIV, + mt9p012_regs.reg_pat[rt].pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + mt9p012_regs.reg_pat[rt].pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + mt9p012_regs.reg_pat[rt].op_pix_clk_div}, + {REG_OP_SYS_CLK_DIV, + mt9p012_regs.reg_pat[rt].op_sys_clk_div}, +#ifdef MT9P012_REV_7 + {0x30B0, 0x0001}, + {0x308E, 0xE060}, + {0x3092, 0x0A52}, + {0x3094, 0x4656}, + {0x3096, 0x5652}, + {0x30CA, 0x8006}, + {0x312A, 0xDD02}, + {0x312C, 0x00E4}, + {0x3170, 0x299A}, +#endif + /* optimized settings for noise */ + {0x3088, 0x6FF6}, + {0x3154, 0x0282}, + {0x3156, 0x0381}, + {0x3162, 0x04CE}, + {0x0204, 0x0010}, + {0x0206, 0x0010}, + {0x0208, 0x0010}, + {0x020A, 0x0010}, + {0x020C, 0x0010}, + {MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWON}, + }; + + struct mt9p012_i2c_reg_conf ipc_tbl2[] = { + {MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWOFF}, + {REG_VT_PIX_CLK_DIV, + mt9p012_regs.reg_pat[rt].vt_pix_clk_div}, + {REG_VT_SYS_CLK_DIV, + mt9p012_regs.reg_pat[rt].vt_sys_clk_div}, + {REG_PRE_PLL_CLK_DIV, + mt9p012_regs.reg_pat[rt].pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + mt9p012_regs.reg_pat[rt].pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + mt9p012_regs.reg_pat[rt].op_pix_clk_div}, + {REG_OP_SYS_CLK_DIV, + mt9p012_regs.reg_pat[rt].op_sys_clk_div}, +#ifdef MT9P012_REV_7 + {0x30B0, 0x0001}, + {0x308E, 0xE060}, + {0x3092, 0x0A52}, + {0x3094, 0x4656}, + {0x3096, 0x5652}, + {0x30CA, 0x8006}, + {0x312A, 0xDD02}, + {0x312C, 0x00E4}, + {0x3170, 0x299A}, +#endif + /* optimized settings for noise */ + {0x3088, 0x6FF6}, + {0x3154, 0x0282}, + {0x3156, 0x0381}, + {0x3162, 0x04CE}, + {0x0204, 0x0010}, + {0x0206, 0x0010}, + {0x0208, 0x0010}, + {0x020A, 0x0010}, + {0x020C, 0x0010}, + {MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWON}, + }; + + struct mt9p012_i2c_reg_conf ipc_tbl3[] = { + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD}, + /* Set preview or snapshot mode */ + {REG_ROW_SPEED, + mt9p012_regs.reg_pat[rt].row_speed}, + {REG_X_ADDR_START, + mt9p012_regs.reg_pat[rt].x_addr_start}, + {REG_X_ADDR_END, + mt9p012_regs.reg_pat[rt].x_addr_end}, + {REG_Y_ADDR_START, + mt9p012_regs.reg_pat[rt].y_addr_start}, + {REG_Y_ADDR_END, + mt9p012_regs.reg_pat[rt].y_addr_end}, + {REG_READ_MODE, + mt9p012_regs.reg_pat[rt].read_mode}, + {REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m}, + {REG_X_OUTPUT_SIZE, + mt9p012_regs.reg_pat[rt].x_output_size}, + {REG_Y_OUTPUT_SIZE, + mt9p012_regs.reg_pat[rt].y_output_size}, + {REG_LINE_LENGTH_PCK, + mt9p012_regs.reg_pat[rt].line_length_pck}, + {REG_FRAME_LENGTH_LINES, + mt9p012_regs.reg_pat[rt].frame_length_lines}, + {REG_COARSE_INT_TIME, + mt9p012_regs.reg_pat[rt].coarse_int_time}, + {REG_FINE_INTEGRATION_TIME, + mt9p012_regs.reg_pat[rt].fine_int_time}, + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE}, + }; + + /* reset fps_divider */ + mt9p012_ctrl->fps_divider = 1 * 0x0400; + + rc = mt9p012_i2c_write_w_table(&ipc_tbl1[0], + ARRAY_SIZE(ipc_tbl1)); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w_table(&ipc_tbl2[0], + ARRAY_SIZE(ipc_tbl2)); + if (rc < 0) + return rc; + + mdelay(5); + + rc = mt9p012_i2c_write_w_table(&ipc_tbl3[0], + ARRAY_SIZE(ipc_tbl3)); + if (rc < 0) + return rc; + + /* load lens shading */ + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + rc = mt9p012_set_lc(); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + + if (rc < 0) + return rc; + } + update_type = rupdate; + break; /* case REG_INIT: */ + + default: + rc = -EINVAL; + break; + } /* switch (rupdate) */ + + return rc; +} + +static int32_t mt9p012_video_config(int mode, int res) +{ + int32_t rc; + + switch (res) { + case QTR_SIZE: + rc = mt9p012_setting(UPDATE_PERIODIC, RES_PREVIEW); + if (rc < 0) + return rc; + + CDBG("mt9p012 sensor configuration done!\n"); + break; + + case FULL_SIZE: + rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + break; + + default: + return 0; + } /* switch */ + + mt9p012_ctrl->prev_res = res; + mt9p012_ctrl->curr_res = res; + mt9p012_ctrl->sensormode = mode; + + rc = mt9p012_write_exp_gain(mt9p012_ctrl->my_reg_gain, + mt9p012_ctrl->my_reg_line_count); + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, 0x10cc | 0x0002); + + return rc; +} + +static int32_t mt9p012_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res; + + mt9p012_ctrl->sensormode = mode; + + return rc; +} + +static int32_t mt9p012_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res; + + mt9p012_ctrl->sensormode = mode; + + return rc; +} + +static int32_t mt9p012_power_down(void) +{ + int32_t rc = 0; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWOFF); + + mdelay(5); + return rc; +} + +static int32_t mt9p012_move_focus(int direction, int32_t num_steps) +{ + int32_t rc; + int16_t step_direction; + int16_t actual_step; + int16_t next_position; + uint8_t code_val; + uint8_t time_out; + uint8_t temp_pos; + + uint16_t actual_position_target; + if (num_steps > MT9P012_TOTAL_STEPS_NEAR_TO_FAR) + num_steps = MT9P012_TOTAL_STEPS_NEAR_TO_FAR; + else if (num_steps == 0) { + CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__); + return -EINVAL; + } + + if (direction == MOVE_NEAR) + step_direction = -1; + else if (direction == MOVE_FAR) + step_direction = 1; + else { + CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__); + return -EINVAL; + } + + if (mt9p012_ctrl->curr_lens_pos < mt9p012_ctrl->init_curr_lens_pos) + mt9p012_ctrl->curr_lens_pos = mt9p012_ctrl->init_curr_lens_pos; + + actual_step = (int16_t) (step_direction * (int16_t) num_steps); + next_position = (int16_t) (mt9p012_ctrl->curr_lens_pos + actual_step); + + if (next_position > MT9P012_TOTAL_STEPS_NEAR_TO_FAR) + next_position = MT9P012_TOTAL_STEPS_NEAR_TO_FAR; + else if (next_position < 0) + next_position = 0; + + if (num_steps >= 10) + time_out = 100; + else + time_out = 30; + code_val = next_position; + actual_position_target = bam_step_lookup_table[code_val]; + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x29); + if (rc < 0) + return rc; + temp_pos = (uint8_t) (actual_position_target >> 8); + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x05, temp_pos); + if (rc < 0) + return rc; + temp_pos = (uint8_t) (actual_position_target & 0x00FF); + /* code_val_lsb |= mode_mask; */ + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x06, temp_pos); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0B, time_out); + if (rc < 0) + return rc; + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x27); + if (rc < 0) + return rc; + + mdelay(time_out); + + /* Storing the current lens Position */ + mt9p012_ctrl->curr_lens_pos = next_position; + + return rc; +} + +static int32_t mt9p012_set_default_focus(void) +{ + int32_t rc = 0; + + uint8_t temp_pos; + + /* Write the digital code for current to the actuator */ + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x29); + if (rc < 0) + return rc; + temp_pos = (uint8_t) (bam_infinite >> 8); + + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x05, temp_pos); + if (rc < 0) + return rc; + temp_pos = (uint8_t) (bam_infinite & 0x00FF); + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x06, temp_pos); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0B, 0x64); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x27); + if (rc < 0) + return rc; + + mdelay(140); + + mt9p012_ctrl->curr_lens_pos = MT9P012_TOTAL_STEPS_NEAR_TO_FAR; + + return rc; +} + +static int mt9p012_probe_init_done(const struct msm_camera_sensor_info *data) +{ + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + return 0; +} + +static int mt9p012_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + uint16_t chipid; + + rc = gpio_request(data->sensor_reset, "mt9p012"); + if (!rc) + gpio_direction_output(data->sensor_reset, 1); + else + goto init_probe_done; + + msleep(20); + + /* RESET the sensor image part via I2C command */ + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0001); + if (rc < 0) { + CDBG("sensor reset failed. rc = %d\n", rc); + goto init_probe_fail; + } + + msleep(MT9P012_RESET_DELAY_MSECS); + + /* 3. Read sensor Model ID: */ + rc = mt9p012_i2c_read_w(mt9p012_client->addr, + MT9P012_REG_MODEL_ID, &chipid); + if (rc < 0) + goto init_probe_fail; + + /* 4. Compare sensor ID to MT9T012VC ID: */ + if (chipid != MT9P012_MODEL_ID) { + rc = -ENODEV; + goto init_probe_fail; + } + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x306E, 0x9000); + if (rc < 0) { + CDBG("REV_7 write failed. rc = %d\n", rc); + goto init_probe_fail; + } + + /* RESET_REGISTER, enable parallel interface and disable serialiser */ + rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x301A, 0x10CC); + if (rc < 0) { + CDBG("enable parallel interface failed. rc = %d\n", rc); + goto init_probe_fail; + } + + /* To disable the 2 extra lines */ + rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3064, 0x0805); + + if (rc < 0) { + CDBG("disable the 2 extra lines failed. rc = %d\n", rc); + goto init_probe_fail; + } + + goto init_probe_done; + +init_probe_fail: + mt9p012_probe_init_done(data); +init_probe_done: + return rc; +} + +static int mt9p012_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + unsigned short temp_pos; + uint8_t i; + uint16_t temp; + + mt9p012_ctrl = kzalloc(sizeof(struct mt9p012_ctrl), GFP_KERNEL); + if (!mt9p012_ctrl) { + CDBG("mt9p012_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + mt9p012_ctrl->fps_divider = 1 * 0x00000400; + mt9p012_ctrl->pict_fps_divider = 1 * 0x00000400; + mt9p012_ctrl->set_test = TEST_OFF; + mt9p012_ctrl->prev_res = QTR_SIZE; + mt9p012_ctrl->pict_res = FULL_SIZE; + + if (data) + mt9p012_ctrl->sensordata = data; + + msm_camio_camif_pad_reg_reset(); + mdelay(20); + + rc = mt9p012_probe_init_sensor(data); + if (rc < 0) + goto init_fail1; + + if (mt9p012_ctrl->prev_res == QTR_SIZE) + rc = mt9p012_setting(REG_INIT, RES_PREVIEW); + else + rc = mt9p012_setting(REG_INIT, RES_CAPTURE); + + if (rc < 0) { + CDBG("mt9p012_setting failed. rc = %d\n", rc); + goto init_fail1; + } + + /* sensor : output enable */ + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWON); + if (rc < 0) { + CDBG("sensor output enable failed. rc = %d\n", rc); + goto init_fail1; + } + + /* enable AF actuator */ + rc = gpio_request(mt9p012_ctrl->sensordata->vcm_pwd, "mt9p012"); + if (!rc) + gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 1); + else { + CDBG("mt9p012_ctrl gpio request failed!\n"); + goto init_fail1; + } + + mdelay(20); + + bam_infinite = 0; + bam_macro = 0; + /*initialize AF actuator */ + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x09); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x2E); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0A, 0x01); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x17, 0x06); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x16, 0x0A); + + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x29); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x05, 0x00); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x06, 0x00); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0B, 0x64); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x27); + mdelay(140); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x29); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x05, 0x03); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x06, 0xFF); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0B, 0x64); + mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x27); + mdelay(140); + + if (mt9p012_i2c_read_b(MT9P012_AF_I2C_ADDR >> 1, 0x12, &temp_pos) + >= 0) { + bam_infinite = (uint16_t) temp_pos; + if (mt9p012_i2c_read_b + (MT9P012_AF_I2C_ADDR >> 1, 0x13, &temp_pos) >= 0) + bam_infinite = + (bam_infinite << 8) | ((uint16_t) temp_pos); + } else { + bam_infinite = 100; + } + + if (mt9p012_i2c_read_b(MT9P012_AF_I2C_ADDR >> 1, 0x14, &temp_pos) + >= 0) { + bam_macro = (uint16_t) temp_pos; + if (mt9p012_i2c_read_b + (MT9P012_AF_I2C_ADDR >> 1, 0x15, &temp_pos) >= 0) + bam_macro = (bam_macro << 8) | ((uint16_t) temp_pos); + } + temp = (bam_infinite - bam_macro) / MT9P012_TOTAL_STEPS_NEAR_TO_FAR; + for (i = 0; i < MT9P012_TOTAL_STEPS_NEAR_TO_FAR; i++) + bam_step_lookup_table[i] = bam_macro + temp * i; + + bam_step_lookup_table[MT9P012_TOTAL_STEPS_NEAR_TO_FAR] = bam_infinite; + + rc = mt9p012_set_default_focus(); + if (rc >= 0) + goto init_done; + +init_fail1: + mt9p012_probe_init_done(data); + kfree(mt9p012_ctrl); +init_done: + return rc; +} + +static int mt9p012_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&mt9p012_wait_queue); + return 0; +} + +static int32_t mt9p012_set_sensor_mode(int mode, int res) +{ + int32_t rc = 0; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = mt9p012_video_config(mode, res); + break; + + case SENSOR_SNAPSHOT_MODE: + rc = mt9p012_snapshot_config(mode); + break; + + case SENSOR_RAW_SNAPSHOT_MODE: + rc = mt9p012_raw_snapshot_config(mode); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +int mt9p012_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + int rc = 0; + + if (copy_from_user(&cdata, + (void *)argp, sizeof(struct sensor_cfg_data))) + return -EFAULT; + + mutex_lock(&mt9p012_mut); + + CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + mt9p012_get_pict_fps(cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = mt9p012_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = mt9p012_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = mt9p012_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = mt9p012_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = mt9p012_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = mt9p012_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = mt9p012_write_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__); + rc = mt9p012_set_pict_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = mt9p012_set_sensor_mode(cdata.mode, cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = mt9p012_power_down(); + break; + + case CFG_MOVE_FOCUS: + CDBG("mt9p012_ioctl: CFG_MOVE_FOCUS: dir=%d steps=%d\n", + cdata.cfg.focus.dir, cdata.cfg.focus.steps); + rc = mt9p012_move_focus(cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = mt9p012_set_default_focus(); + + break; + + case CFG_SET_EFFECT: + rc = mt9p012_set_default_focus(); + break; + + case CFG_SET_LENS_SHADING: + CDBG("%s: CFG_SET_LENS_SHADING\n", __func__); + rc = mt9p012_lens_shading_enable(cdata.cfg.lens_shading); + break; + + case CFG_GET_AF_MAX_STEPS: + cdata.max_steps = MT9P012_STEPS_NEAR_TO_CLOSEST_INF; + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + default: + rc = -EINVAL; + break; + } + + mutex_unlock(&mt9p012_mut); + return rc; +} + +int mt9p012_sensor_release(void) +{ + int rc = -EBADF; + + mutex_lock(&mt9p012_mut); + + mt9p012_power_down(); + + gpio_direction_output(mt9p012_ctrl->sensordata->sensor_reset, 0); + gpio_free(mt9p012_ctrl->sensordata->sensor_reset); + + gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0); + gpio_free(mt9p012_ctrl->sensordata->vcm_pwd); + + kfree(mt9p012_ctrl); + mt9p012_ctrl = NULL; + + CDBG("mt9p012_release completed\n"); + + mutex_unlock(&mt9p012_mut); + return rc; +} + +static int mt9p012_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("mt9p012_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + mt9p012_sensorw = kzalloc(sizeof(struct mt9p012_work), GFP_KERNEL); + if (!mt9p012_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, mt9p012_sensorw); + mt9p012_init_client(client); + mt9p012_client = client; + + mdelay(50); + + CDBG("mt9p012_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("mt9p012_probe failed! rc = %d\n", rc); + return rc; +} + +static int __exit mt9p012_remove(struct i2c_client *client) +{ + struct mt9p012_work_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + mt9p012_client = NULL; + kfree(sensorw); + return 0; +} + +static const struct i2c_device_id mt9p012_i2c_id[] = { + {"mt9p012", 0} +}; + +static struct i2c_driver mt9p012_i2c_driver = { + .id_table = mt9p012_i2c_id, + .probe = mt9p012_i2c_probe, + .remove = __exit_p(mt9p012_i2c_remove), + .driver = { + .name = "mt9p012", + }, +}; + +static int mt9p012_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = i2c_add_driver(&mt9p012_i2c_driver); + if (rc < 0 || mt9p012_client == NULL) { + rc = -ENOTSUPP; + goto probe_done; + } + + msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE); + mdelay(20); + + rc = mt9p012_probe_init_sensor(info); + if (rc < 0) + goto probe_done; + + s->s_init = mt9p012_sensor_open_init; + s->s_release = mt9p012_sensor_release; + s->s_config = mt9p012_sensor_config; + s->s_mount_angle = 0; + mt9p012_probe_init_done(info); + +probe_done: + CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__); + return rc; +} + +static int __mt9p012_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, mt9p012_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __mt9p012_probe, + .driver = { + .name = "msm_camera_mt9p012", + .owner = THIS_MODULE, + }, +}; + +static int __init mt9p012_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(mt9p012_init); +void mt9p012_exit(void) +{ + i2c_del_driver(&mt9p012_i2c_driver); +} diff --git a/drivers/media/video/msm_zsl/mt9p012_fox.c b/drivers/media/video/msm_zsl/mt9p012_fox.c new file mode 100644 index 00000000000..4a732f3098e --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9p012_fox.c @@ -0,0 +1,1345 @@ +/* Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mt9p012.h" + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ +#define MT9P012_REG_MODEL_ID 0x0000 +#define MT9P012_MODEL_ID 0x2801 +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD 0x0100 +#define GROUPED_PARAMETER_UPDATE 0x0000 +#define REG_COARSE_INT_TIME 0x3012 +#define REG_VT_PIX_CLK_DIV 0x0300 +#define REG_VT_SYS_CLK_DIV 0x0302 +#define REG_PRE_PLL_CLK_DIV 0x0304 +#define REG_PLL_MULTIPLIER 0x0306 +#define REG_OP_PIX_CLK_DIV 0x0308 +#define REG_OP_SYS_CLK_DIV 0x030A +#define REG_SCALE_M 0x0404 +#define REG_FRAME_LENGTH_LINES 0x300A +#define REG_LINE_LENGTH_PCK 0x300C +#define REG_X_ADDR_START 0x3004 +#define REG_Y_ADDR_START 0x3002 +#define REG_X_ADDR_END 0x3008 +#define REG_Y_ADDR_END 0x3006 +#define REG_X_OUTPUT_SIZE 0x034C +#define REG_Y_OUTPUT_SIZE 0x034E +#define REG_FINE_INTEGRATION_TIME 0x3014 +#define REG_ROW_SPEED 0x3016 +#define MT9P012_REG_RESET_REGISTER 0x301A +#define MT9P012_RESET_REGISTER_PWON 0x10CC +#define MT9P012_RESET_REGISTER_PWOFF 0x10C8 +#define REG_READ_MODE 0x3040 +#define REG_GLOBAL_GAIN 0x305E +#define REG_TEST_PATTERN_MODE 0x3070 + +#define MT9P012_REV_7 + +enum mt9p012_test_mode { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum mt9p012_resolution { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; + +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum mt9p012_setting { + RES_PREVIEW, + RES_CAPTURE +}; + +/* actuator's Slave Address */ +#define MT9P012_AF_I2C_ADDR 0x18 + +/* AF Total steps parameters */ +#define MT9P012_STEPS_NEAR_TO_CLOSEST_INF 32 +#define MT9P012_TOTAL_STEPS_NEAR_TO_FAR 32 + +#define MT9P012_MU5M0_PREVIEW_DUMMY_PIXELS 0 +#define MT9P012_MU5M0_PREVIEW_DUMMY_LINES 0 + +/* Time in milisecs for waiting for the sensor to reset.*/ +#define MT9P012_RESET_DELAY_MSECS 66 + +/* for 20 fps preview */ +#define MT9P012_DEFAULT_CLOCK_RATE 24000000 +#define MT9P012_DEFAULT_MAX_FPS 26 /* ???? */ + +struct mt9p012_work { + struct work_struct work; +}; +static struct mt9p012_work *mt9p012_sensorw; +static struct i2c_client *mt9p012_client; + +struct mt9p012_ctrl { + const struct msm_camera_sensor_info *sensordata; + + int sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + + uint16_t curr_lens_pos; + uint16_t init_curr_lens_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + + enum mt9p012_resolution prev_res; + enum mt9p012_resolution pict_res; + enum mt9p012_resolution curr_res; + enum mt9p012_test_mode set_test; +}; +static uint16_t update_type = UPDATE_PERIODIC; +static struct mt9p012_ctrl *mt9p012_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(mt9p012_wait_queue); +DEFINE_MUTEX(mt9p012_mut); + + +/*=============================================================*/ + +static int mt9p012_i2c_rxdata(unsigned short saddr, unsigned char *rxdata, + int length) +{ + int retry_cnt = 0; + int rc; + + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + + do { + rc = i2c_transfer(mt9p012_client->adapter, msgs, 2); + if (rc > 0) + break; + retry_cnt++; + } while (retry_cnt < 3); + + if (rc < 0) { + pr_err("mt9p012_i2c_rxdata failed!:%d %d\n", rc, retry_cnt); + return -EIO; + } + + return 0; +} + +static int32_t mt9p012_i2c_read_w(unsigned short saddr, unsigned short raddr, + unsigned short *rdata) +{ + int32_t rc = 0; + unsigned char buf[4]; + + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + + rc = mt9p012_i2c_rxdata(saddr, buf, 2); + if (rc < 0) + return rc; + + *rdata = buf[0] << 8 | buf[1]; + + if (rc < 0) + CDBG("mt9p012_i2c_read failed!\n"); + + return rc; +} + +static int32_t mt9p012_i2c_txdata(unsigned short saddr, unsigned char *txdata, + int length) +{ + int retry_cnt = 0; + int rc; + + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + do { + rc = i2c_transfer(mt9p012_client->adapter, msg, 1); + if (rc > 0) + break; + retry_cnt++; + } while (retry_cnt < 3); + + if (rc < 0) { + pr_err("mt9p012_i2c_txdata failed: %d %d\n", rc, retry_cnt); + return -EIO; + } + + return 0; +} + +static int32_t mt9p012_i2c_write_b(unsigned short saddr, unsigned short baddr, + unsigned short bdata) +{ + int32_t rc = -EIO; + unsigned char buf[2]; + + memset(buf, 0, sizeof(buf)); + buf[0] = baddr; + buf[1] = bdata; + rc = mt9p012_i2c_txdata(saddr, buf, 2); + + if (rc < 0) + CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!\n", + saddr, baddr, bdata); + + return rc; +} + +static int32_t mt9p012_i2c_write_w(unsigned short saddr, unsigned short waddr, + unsigned short wdata) +{ + int32_t rc = -EIO; + unsigned char buf[4]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00) >> 8; + buf[3] = (wdata & 0x00FF); + + rc = mt9p012_i2c_txdata(saddr, buf, 4); + + if (rc < 0) + CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + + return rc; +} + +static int32_t mt9p012_i2c_write_w_table(struct mt9p012_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + + for (i = 0; i < num; i++) { + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + + return rc; +} + +static int32_t mt9p012_test(enum mt9p012_test_mode mo) +{ + int32_t rc = 0; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + if (mo == TEST_OFF) + return 0; + else { + rc = mt9p012_i2c_write_w_table(mt9p012_regs.ttbl, + mt9p012_regs.ttbl_size); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_TEST_PATTERN_MODE, (uint16_t) mo); + if (rc < 0) + return rc; + } + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t mt9p012_lens_shading_enable(uint8_t is_enable) +{ + int32_t rc = 0; + + CDBG("%s: entered. enable = %d\n", __func__, is_enable); + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3780, + ((uint16_t) is_enable) << 15); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + + CDBG("%s: exiting. rc = %d\n", __func__, rc); + return rc; +} + +static int32_t mt9p012_set_lc(void) +{ + int32_t rc; + + rc = mt9p012_i2c_write_w_table(mt9p012_regs.rftbl, + mt9p012_regs.rftbl_size); + + return rc; +} + +static void mt9p012_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint32_t divider; /*Q10 */ + uint32_t pclk_mult; /*Q10 */ + uint32_t d1; + uint32_t d2; + + d1 = + (uint32_t)( + (mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines * + 0x00000400) / + mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines); + + d2 = + (uint32_t)( + (mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck * + 0x00000400) / + mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck); + + divider = (uint32_t) (d1 * d2) / 0x00000400; + + pclk_mult = + (uint32_t) ((mt9p012_regs.reg_pat[RES_CAPTURE].pll_multiplier * + 0x00000400) / + (mt9p012_regs.reg_pat[RES_PREVIEW].pll_multiplier)); + + /* Verify PCLK settings and frame sizes. */ + *pfps = (uint16_t) (fps * divider * pclk_mult / 0x00000400 / + 0x00000400); +} + +static uint16_t mt9p012_get_prev_lines_pf(void) +{ + if (mt9p012_ctrl->prev_res == QTR_SIZE) + return mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines; + else + return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines; +} + +static uint16_t mt9p012_get_prev_pixels_pl(void) +{ + if (mt9p012_ctrl->prev_res == QTR_SIZE) + return mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck; + else + return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck; +} + +static uint16_t mt9p012_get_pict_lines_pf(void) +{ + return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines; +} + +static uint16_t mt9p012_get_pict_pixels_pl(void) +{ + return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck; +} + +static uint32_t mt9p012_get_pict_max_exp_lc(void) +{ + uint16_t snapshot_lines_per_frame; + + if (mt9p012_ctrl->pict_res == QTR_SIZE) + snapshot_lines_per_frame = + mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1; + else + snapshot_lines_per_frame = + mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1; + + return snapshot_lines_per_frame * 24; +} + +static int32_t mt9p012_set_fps(struct fps_cfg *fps) +{ + /* input is new fps in Q10 format */ + int32_t rc = 0; + enum mt9p012_setting setting; + + mt9p012_ctrl->fps_divider = fps->fps_div; + mt9p012_ctrl->pict_fps_divider = fps->pict_fps_div; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return -EBUSY; + + if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) + setting = RES_PREVIEW; + else + setting = RES_CAPTURE; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_FRAME_LENGTH_LINES, + (mt9p012_regs.reg_pat[setting].frame_length_lines * + fps->fps_div / 0x00000400)); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + + return rc; +} + +static int32_t mt9p012_write_exp_gain(uint16_t gain, uint32_t line) +{ + uint16_t max_legal_gain = 0x01FF; + uint32_t line_length_ratio = 0x00000400; + enum mt9p012_setting setting; + int32_t rc = 0; + + CDBG("Line:%d mt9p012_write_exp_gain \n", __LINE__); + + if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + mt9p012_ctrl->my_reg_gain = gain; + mt9p012_ctrl->my_reg_line_count = (uint16_t) line; + } + + if (gain > max_legal_gain) { + CDBG("Max legal gain Line:%d \n", __LINE__); + gain = max_legal_gain; + } + + /* Verify no overflow */ + if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + line = (uint32_t) (line * mt9p012_ctrl->fps_divider / + 0x00000400); + setting = RES_PREVIEW; + } else { + line = (uint32_t) (line * mt9p012_ctrl->pict_fps_divider / + 0x00000400); + setting = RES_CAPTURE; + } + + /* Set digital gain to 1 */ +#ifdef MT9P012_REV_7 + gain |= 0x1000; +#else + gain |= 0x0200; +#endif + + if ((mt9p012_regs.reg_pat[setting].frame_length_lines - 1) < line) { + line_length_ratio = (uint32_t) (line * 0x00000400) / + (mt9p012_regs.reg_pat[setting].frame_length_lines - 1); + } else + line_length_ratio = 0x00000400; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, REG_GLOBAL_GAIN, gain); + if (rc < 0) { + CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_COARSE_INT_TIME, line); + if (rc < 0) { + CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + CDBG("mt9p012_write_exp_gain: gain = %d, line = %d\n", gain, line); + + return rc; +} + +static int32_t mt9p012_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + + CDBG("Line:%d mt9p012_set_pict_exp_gain \n", __LINE__); + + rc = mt9p012_write_exp_gain(gain, line); + if (rc < 0) { + CDBG("Line:%d mt9p012_set_pict_exp_gain failed... \n", + __LINE__); + return rc; + } + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0002); + if (rc < 0) { + CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + mdelay(5); + + /* camera_timed_wait(snapshot_wait*exposure_ratio); */ + return rc; +} + +static int32_t mt9p012_setting(enum mt9p012_reg_update rupdate, + enum mt9p012_setting rt) +{ + int32_t rc = 0; + switch (rupdate) { + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct mt9p012_i2c_reg_conf ppc_tbl[] = { + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD}, + {REG_ROW_SPEED, + mt9p012_regs.reg_pat[rt].row_speed}, + {REG_X_ADDR_START, + mt9p012_regs.reg_pat[rt].x_addr_start}, + {REG_X_ADDR_END, + mt9p012_regs.reg_pat[rt].x_addr_end}, + {REG_Y_ADDR_START, + mt9p012_regs.reg_pat[rt].y_addr_start}, + {REG_Y_ADDR_END, + mt9p012_regs.reg_pat[rt].y_addr_end}, + {REG_READ_MODE, + mt9p012_regs.reg_pat[rt].read_mode}, + {REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m}, + {REG_X_OUTPUT_SIZE, + mt9p012_regs.reg_pat[rt].x_output_size}, + {REG_Y_OUTPUT_SIZE, + mt9p012_regs.reg_pat[rt].y_output_size}, + + {REG_LINE_LENGTH_PCK, + mt9p012_regs.reg_pat[rt].line_length_pck}, + {REG_FRAME_LENGTH_LINES, + (mt9p012_regs.reg_pat[rt].frame_length_lines * + mt9p012_ctrl->fps_divider / 0x00000400)}, + {REG_COARSE_INT_TIME, + mt9p012_regs.reg_pat[rt].coarse_int_time}, + {REG_FINE_INTEGRATION_TIME, + mt9p012_regs.reg_pat[rt].fine_int_time}, + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE}, + }; + if (update_type == REG_INIT) { + update_type = rupdate; + return rc; + } + rc = mt9p012_i2c_write_w_table(&ppc_tbl[0], + ARRAY_SIZE(ppc_tbl)); + if (rc < 0) + return rc; + + rc = mt9p012_test(mt9p012_ctrl->set_test); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWON | + 0x0002); + if (rc < 0) + return rc; + + mdelay(5); /* 15? wait for sensor to transition */ + + return rc; + } + break; /* UPDATE_PERIODIC */ + + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct mt9p012_i2c_reg_conf ipc_tbl1[] = { + {MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWOFF}, + {REG_VT_PIX_CLK_DIV, + mt9p012_regs.reg_pat[rt].vt_pix_clk_div}, + {REG_VT_SYS_CLK_DIV, + mt9p012_regs.reg_pat[rt].vt_sys_clk_div}, + {REG_PRE_PLL_CLK_DIV, + mt9p012_regs.reg_pat[rt].pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + mt9p012_regs.reg_pat[rt].pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + mt9p012_regs.reg_pat[rt].op_pix_clk_div}, + {REG_OP_SYS_CLK_DIV, + mt9p012_regs.reg_pat[rt].op_sys_clk_div}, +#ifdef MT9P012_REV_7 + {0x30B0, 0x0001}, + {0x308E, 0xE060}, + {0x3092, 0x0A52}, + {0x3094, 0x4656}, + {0x3096, 0x5652}, + {0x30CA, 0x8006}, + {0x312A, 0xDD02}, + {0x312C, 0x00E4}, + {0x3170, 0x299A}, +#endif + /* optimized settings for noise */ + {0x3088, 0x6FF6}, + {0x3154, 0x0282}, + {0x3156, 0x0381}, + {0x3162, 0x04CE}, + {0x0204, 0x0010}, + {0x0206, 0x0010}, + {0x0208, 0x0010}, + {0x020A, 0x0010}, + {0x020C, 0x0010}, + {MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWON}, + }; + + struct mt9p012_i2c_reg_conf ipc_tbl2[] = { + {MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWOFF}, + {REG_VT_PIX_CLK_DIV, + mt9p012_regs.reg_pat[rt].vt_pix_clk_div}, + {REG_VT_SYS_CLK_DIV, + mt9p012_regs.reg_pat[rt].vt_sys_clk_div}, + {REG_PRE_PLL_CLK_DIV, + mt9p012_regs.reg_pat[rt].pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + mt9p012_regs.reg_pat[rt].pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + mt9p012_regs.reg_pat[rt].op_pix_clk_div}, + {REG_OP_SYS_CLK_DIV, + mt9p012_regs.reg_pat[rt].op_sys_clk_div}, +#ifdef MT9P012_REV_7 + {0x30B0, 0x0001}, + {0x308E, 0xE060}, + {0x3092, 0x0A52}, + {0x3094, 0x4656}, + {0x3096, 0x5652}, + {0x30CA, 0x8006}, + {0x312A, 0xDD02}, + {0x312C, 0x00E4}, + {0x3170, 0x299A}, +#endif + /* optimized settings for noise */ + {0x3088, 0x6FF6}, + {0x3154, 0x0282}, + {0x3156, 0x0381}, + {0x3162, 0x04CE}, + {0x0204, 0x0010}, + {0x0206, 0x0010}, + {0x0208, 0x0010}, + {0x020A, 0x0010}, + {0x020C, 0x0010}, + {MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWON}, + }; + + struct mt9p012_i2c_reg_conf ipc_tbl3[] = { + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD}, + /* Set preview or snapshot mode */ + {REG_ROW_SPEED, + mt9p012_regs.reg_pat[rt].row_speed}, + {REG_X_ADDR_START, + mt9p012_regs.reg_pat[rt].x_addr_start}, + {REG_X_ADDR_END, + mt9p012_regs.reg_pat[rt].x_addr_end}, + {REG_Y_ADDR_START, + mt9p012_regs.reg_pat[rt].y_addr_start}, + {REG_Y_ADDR_END, + mt9p012_regs.reg_pat[rt].y_addr_end}, + {REG_READ_MODE, + mt9p012_regs.reg_pat[rt].read_mode}, + {REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m}, + {REG_X_OUTPUT_SIZE, + mt9p012_regs.reg_pat[rt].x_output_size}, + {REG_Y_OUTPUT_SIZE, + mt9p012_regs.reg_pat[rt].y_output_size}, + {REG_LINE_LENGTH_PCK, + mt9p012_regs.reg_pat[rt].line_length_pck}, + {REG_FRAME_LENGTH_LINES, + mt9p012_regs.reg_pat[rt].frame_length_lines}, + {REG_COARSE_INT_TIME, + mt9p012_regs.reg_pat[rt].coarse_int_time}, + {REG_FINE_INTEGRATION_TIME, + mt9p012_regs.reg_pat[rt].fine_int_time}, + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE}, + }; + + /* reset fps_divider */ + mt9p012_ctrl->fps_divider = 1 * 0x0400; + + rc = mt9p012_i2c_write_w_table(&ipc_tbl1[0], + ARRAY_SIZE(ipc_tbl1)); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w_table(&ipc_tbl2[0], + ARRAY_SIZE(ipc_tbl2)); + if (rc < 0) + return rc; + + mdelay(5); + + rc = mt9p012_i2c_write_w_table(&ipc_tbl3[0], + ARRAY_SIZE(ipc_tbl3)); + if (rc < 0) + return rc; + + /* load lens shading */ + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + rc = mt9p012_set_lc(); + if (rc < 0) + return rc; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + + if (rc < 0) + return rc; + } + update_type = rupdate; + break; /* case REG_INIT: */ + + default: + rc = -EINVAL; + break; + } /* switch (rupdate) */ + + return rc; +} + +static int32_t mt9p012_video_config(int mode, int res) +{ + int32_t rc; + + switch (res) { + case QTR_SIZE: + rc = mt9p012_setting(UPDATE_PERIODIC, RES_PREVIEW); + if (rc < 0) + return rc; + + CDBG("mt9p012 sensor configuration done!\n"); + break; + + case FULL_SIZE: + rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + break; + + default: + return 0; + } /* switch */ + + mt9p012_ctrl->prev_res = res; + mt9p012_ctrl->curr_res = res; + mt9p012_ctrl->sensormode = mode; + + rc = mt9p012_write_exp_gain(mt9p012_ctrl->my_reg_gain, + mt9p012_ctrl->my_reg_line_count); + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, 0x10cc | 0x0002); + + return rc; +} + +static int32_t mt9p012_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res; + + mt9p012_ctrl->sensormode = mode; + + return rc; +} + +static int32_t mt9p012_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res; + + mt9p012_ctrl->sensormode = mode; + + return rc; +} + +static int32_t mt9p012_power_down(void) +{ + int32_t rc = 0; + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWOFF); + + mdelay(5); + return rc; +} + +static int32_t mt9p012_move_focus(int direction, int32_t num_steps) +{ + int16_t step_direction; + int16_t actual_step; + int16_t next_position; + uint8_t code_val_msb, code_val_lsb; + + if (num_steps > MT9P012_TOTAL_STEPS_NEAR_TO_FAR) + num_steps = MT9P012_TOTAL_STEPS_NEAR_TO_FAR; + else if (num_steps == 0) { + CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__); + return -EINVAL; + } + + if (direction == MOVE_NEAR) + step_direction = 16; /* 10bit */ + else if (direction == MOVE_FAR) + step_direction = -16; /* 10 bit */ + else { + CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__); + return -EINVAL; + } + + if (mt9p012_ctrl->curr_lens_pos < mt9p012_ctrl->init_curr_lens_pos) + mt9p012_ctrl->curr_lens_pos = mt9p012_ctrl->init_curr_lens_pos; + + actual_step = (int16_t) (step_direction * (int16_t) num_steps); + next_position = (int16_t) (mt9p012_ctrl->curr_lens_pos + actual_step); + + if (next_position > 1023) + next_position = 1023; + else if (next_position < 0) + next_position = 0; + + code_val_msb = next_position >> 4; + code_val_lsb = (next_position & 0x000F) << 4; + /* code_val_lsb |= mode_mask; */ + + /* Writing the digital code for current to the actuator */ + if (mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, + code_val_msb, code_val_lsb) < 0) { + CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__); + return -EBUSY; + } + + /* Storing the current lens Position */ + mt9p012_ctrl->curr_lens_pos = next_position; + + return 0; +} + +static int32_t mt9p012_set_default_focus(void) +{ + int32_t rc = 0; + uint8_t code_val_msb, code_val_lsb; + + code_val_msb = 0x00; + code_val_lsb = 0x00; + + /* Write the digital code for current to the actuator */ + rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, + code_val_msb, code_val_lsb); + + mt9p012_ctrl->curr_lens_pos = 0; + mt9p012_ctrl->init_curr_lens_pos = 0; + + return rc; +} + +static int mt9p012_probe_init_done(const struct msm_camera_sensor_info *data) +{ + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + return 0; +} + +static int mt9p012_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + uint16_t chipid; + + rc = gpio_request(data->sensor_reset, "mt9p012"); + if (!rc) + gpio_direction_output(data->sensor_reset, 1); + else + goto init_probe_done; + + msleep(20); + + /* RESET the sensor image part via I2C command */ + CDBG("mt9p012_sensor_init(): reseting sensor.\n"); + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0001); + if (rc < 0) { + CDBG("sensor reset failed. rc = %d\n", rc); + goto init_probe_fail; + } + + msleep(MT9P012_RESET_DELAY_MSECS); + + /* 3. Read sensor Model ID: */ + rc = mt9p012_i2c_read_w(mt9p012_client->addr, + MT9P012_REG_MODEL_ID, &chipid); + if (rc < 0) + goto init_probe_fail; + + /* 4. Compare sensor ID to MT9T012VC ID: */ + if (chipid != MT9P012_MODEL_ID) { + CDBG("mt9p012 wrong model_id = 0x%x\n", chipid); + rc = -ENODEV; + goto init_probe_fail; + } + + rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x306E, 0x9000); + if (rc < 0) { + CDBG("REV_7 write failed. rc = %d\n", rc); + goto init_probe_fail; + } + + /* RESET_REGISTER, enable parallel interface and disable serialiser */ + CDBG("mt9p012_sensor_init(): enabling parallel interface.\n"); + rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x301A, 0x10CC); + if (rc < 0) { + CDBG("enable parallel interface failed. rc = %d\n", rc); + goto init_probe_fail; + } + + /* To disable the 2 extra lines */ + rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3064, 0x0805); + + if (rc < 0) { + CDBG("disable the 2 extra lines failed. rc = %d\n", rc); + goto init_probe_fail; + } + goto init_probe_done; + +init_probe_fail: + mt9p012_probe_init_done(data); +init_probe_done: + return rc; +} + +static int mt9p012_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + + mt9p012_ctrl = kzalloc(sizeof(struct mt9p012_ctrl), GFP_KERNEL); + if (!mt9p012_ctrl) { + CDBG("mt9p012_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + mt9p012_ctrl->fps_divider = 1 * 0x00000400; + mt9p012_ctrl->pict_fps_divider = 1 * 0x00000400; + mt9p012_ctrl->set_test = TEST_OFF; + mt9p012_ctrl->prev_res = QTR_SIZE; + mt9p012_ctrl->pict_res = FULL_SIZE; + + if (data) + mt9p012_ctrl->sensordata = data; + + msm_camio_camif_pad_reg_reset(); + mdelay(20); + + rc = mt9p012_probe_init_sensor(data); + if (rc < 0) + goto init_fail1; + + if (mt9p012_ctrl->prev_res == QTR_SIZE) + rc = mt9p012_setting(REG_INIT, RES_PREVIEW); + else + rc = mt9p012_setting(REG_INIT, RES_CAPTURE); + + if (rc < 0) { + CDBG("mt9p012_setting failed. rc = %d\n", rc); + goto init_fail1; + } + + /* sensor : output enable */ + CDBG("mt9p012_sensor_open_init(): enabling output.\n"); + rc = mt9p012_i2c_write_w(mt9p012_client->addr, + MT9P012_REG_RESET_REGISTER, + MT9P012_RESET_REGISTER_PWON); + if (rc < 0) { + CDBG("sensor output enable failed. rc = %d\n", rc); + goto init_fail1; + } + + /* enable AF actuator */ + if (mt9p012_ctrl->sensordata->vcm_enable) { + CDBG("enable AF actuator, gpio = %d\n", + mt9p012_ctrl->sensordata->vcm_pwd); + rc = gpio_request(mt9p012_ctrl->sensordata->vcm_pwd, + "mt9p012"); + if (!rc) + gpio_direction_output( + mt9p012_ctrl->sensordata->vcm_pwd, + 1); + else { + CDBG("mt9p012_ctrl gpio request failed!\n"); + goto init_fail1; + } + msleep(20); + rc = mt9p012_set_default_focus(); + if (rc < 0) { + gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, + 0); + gpio_free(mt9p012_ctrl->sensordata->vcm_pwd); + } + } + if (rc >= 0) + goto init_done; +init_fail1: + mt9p012_probe_init_done(data); + kfree(mt9p012_ctrl); +init_done: + return rc; +} + +static int mt9p012_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&mt9p012_wait_queue); + return 0; +} + +static int32_t mt9p012_set_sensor_mode(int mode, int res) +{ + int32_t rc = 0; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = mt9p012_video_config(mode, res); + break; + + case SENSOR_SNAPSHOT_MODE: + rc = mt9p012_snapshot_config(mode); + break; + + case SENSOR_RAW_SNAPSHOT_MODE: + rc = mt9p012_raw_snapshot_config(mode); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +int mt9p012_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + int rc = 0; + + if (copy_from_user(&cdata, + (void *)argp, sizeof(struct sensor_cfg_data))) + return -EFAULT; + + mutex_lock(&mt9p012_mut); + + CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + mt9p012_get_pict_fps(cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = mt9p012_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = mt9p012_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = mt9p012_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = mt9p012_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = mt9p012_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = mt9p012_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = mt9p012_write_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__); + rc = mt9p012_set_pict_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = mt9p012_set_sensor_mode(cdata.mode, cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = mt9p012_power_down(); + break; + + case CFG_MOVE_FOCUS: + CDBG("mt9p012_ioctl: CFG_MOVE_FOCUS: cdata.cfg.focus.dir=%d \ + cdata.cfg.focus.steps=%d\n", + cdata.cfg.focus.dir, cdata.cfg.focus.steps); + rc = mt9p012_move_focus(cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = mt9p012_set_default_focus(); + break; + + case CFG_SET_LENS_SHADING: + CDBG("%s: CFG_SET_LENS_SHADING\n", __func__); + rc = mt9p012_lens_shading_enable(cdata.cfg.lens_shading); + break; + + case CFG_GET_AF_MAX_STEPS: + cdata.max_steps = MT9P012_STEPS_NEAR_TO_CLOSEST_INF; + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_EFFECT: + default: + rc = -EINVAL; + break; + } + + mutex_unlock(&mt9p012_mut); + return rc; +} + +int mt9p012_sensor_release(void) +{ + int rc = -EBADF; + + mutex_lock(&mt9p012_mut); + + mt9p012_power_down(); + + gpio_direction_output(mt9p012_ctrl->sensordata->sensor_reset, 0); + gpio_free(mt9p012_ctrl->sensordata->sensor_reset); + + if (mt9p012_ctrl->sensordata->vcm_enable) { + gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0); + gpio_free(mt9p012_ctrl->sensordata->vcm_pwd); + } + + kfree(mt9p012_ctrl); + mt9p012_ctrl = NULL; + + CDBG("mt9p012_release completed\n"); + + mutex_unlock(&mt9p012_mut); + return rc; +} + +static int mt9p012_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("mt9p012_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + mt9p012_sensorw = kzalloc(sizeof(struct mt9p012_work), GFP_KERNEL); + if (!mt9p012_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, mt9p012_sensorw); + mt9p012_init_client(client); + mt9p012_client = client; + + mdelay(50); + + CDBG("mt9p012_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("mt9p012_probe failed! rc = %d\n", rc); + return rc; +} + +static const struct i2c_device_id mt9p012_i2c_id[] = { + {"mt9p012", 0}, + {} +}; + +static struct i2c_driver mt9p012_i2c_driver = { + .id_table = mt9p012_i2c_id, + .probe = mt9p012_i2c_probe, + .remove = __exit_p(mt9p012_i2c_remove), + .driver = { + .name = "mt9p012", + }, +}; + +static int mt9p012_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = i2c_add_driver(&mt9p012_i2c_driver); + if (rc < 0 || mt9p012_client == NULL) { + rc = -ENOTSUPP; + goto probe_done; + } + + msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE); + mdelay(20); + + rc = mt9p012_probe_init_sensor(info); + if (rc < 0) + goto probe_done; + + s->s_init = mt9p012_sensor_open_init; + s->s_release = mt9p012_sensor_release; + s->s_config = mt9p012_sensor_config; + s->s_mount_angle = 0; + mt9p012_probe_init_done(info); + +probe_done: + CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__); + return rc; +} + +static int __mt9p012_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, mt9p012_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __mt9p012_probe, + .driver = { + .name = "msm_camera_mt9p012", + .owner = THIS_MODULE, + }, +}; + +static int __init mt9p012_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(mt9p012_init); diff --git a/drivers/media/video/msm_zsl/mt9p012_km.c b/drivers/media/video/msm_zsl/mt9p012_km.c new file mode 100644 index 00000000000..c20064c0401 --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9p012_km.c @@ -0,0 +1,1295 @@ +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mt9p012_km.h" + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ + +#define MT9P012_KM_REG_MODEL_ID 0x0000 +#define MT9P012_KM_MODEL_ID 0x2800 +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD 0x0100 +#define GROUPED_PARAMETER_UPDATE 0x0000 +#define REG_COARSE_INT_TIME 0x3012 +#define REG_VT_PIX_CLK_DIV 0x0300 +#define REG_VT_SYS_CLK_DIV 0x0302 +#define REG_PRE_PLL_CLK_DIV 0x0304 +#define REG_PLL_MULTIPLIER 0x0306 +#define REG_OP_PIX_CLK_DIV 0x0308 +#define REG_OP_SYS_CLK_DIV 0x030A +#define REG_SCALE_M 0x0404 +#define REG_FRAME_LENGTH_LINES 0x300A +#define REG_LINE_LENGTH_PCK 0x300C +#define REG_X_ADDR_START 0x3004 +#define REG_Y_ADDR_START 0x3002 +#define REG_X_ADDR_END 0x3008 +#define REG_Y_ADDR_END 0x3006 +#define REG_X_OUTPUT_SIZE 0x034C +#define REG_Y_OUTPUT_SIZE 0x034E +#define REG_FINE_INTEGRATION_TIME 0x3014 +#define REG_ROW_SPEED 0x3016 +#define MT9P012_KM_REG_RESET_REGISTER 0x301A +#define MT9P012_KM_RESET_REGISTER_PWON 0x10CC +#define MT9P012_KM_RESET_REGISTER_PWOFF 0x10C8 +#define REG_READ_MODE 0x3040 +#define REG_GLOBAL_GAIN 0x305E +#define REG_TEST_PATTERN_MODE 0x3070 + +enum mt9p012_km_test_mode { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum mt9p012_km_resolution { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; + +enum mt9p012_km_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum mt9p012_km_setting { + RES_PREVIEW, + RES_CAPTURE +}; + +uint8_t mode_mask = 0x04; + +/* actuator's Slave Address */ +#define MT9P012_KM_AF_I2C_ADDR (0x18 >> 1) + +/* AF Total steps parameters */ +#define MT9P012_KM_STEPS_NEAR_TO_CLOSEST_INF 30 +#define MT9P012_KM_TOTAL_STEPS_NEAR_TO_FAR 30 + +/* Time in milisecs for waiting for the sensor to reset.*/ +#define MT9P012_KM_RESET_DELAY_MSECS 66 + +/* for 20 fps preview */ +#define MT9P012_KM_DEFAULT_CLOCK_RATE 24000000 + +struct mt9p012_km_work { + struct work_struct work; +}; +static struct mt9p012_km_work *mt9p012_km_sensorw; +static struct i2c_client *mt9p012_km_client; + +struct mt9p012_km_ctrl { + const struct msm_camera_sensor_info *sensordata; + + int sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + + uint16_t curr_lens_pos; + uint16_t init_curr_lens_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + + enum mt9p012_km_resolution prev_res; + enum mt9p012_km_resolution pict_res; + enum mt9p012_km_resolution curr_res; + enum mt9p012_km_test_mode set_test; +}; +static uint16_t update_type = UPDATE_PERIODIC; +static struct mt9p012_km_ctrl *mt9p012_km_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(mt9p012_km_wait_queue); +DEFINE_MUTEX(mt9p012_km_mut); + +/*=============================================================*/ + +static int mt9p012_km_i2c_rxdata(unsigned short saddr, unsigned char *rxdata, + int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr << 1, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr << 1, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + + if (i2c_transfer(mt9p012_km_client->adapter, msgs, 2) < 0) { + CDBG("mt9p012_km_i2c_rxdata failed!\n"); + return -EIO; + } + + return 0; +} + +static int32_t mt9p012_km_i2c_read_w(unsigned short saddr, unsigned short raddr, + unsigned short *rdata) +{ + int32_t rc = 0; + unsigned char buf[4]; + + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + + rc = mt9p012_km_i2c_rxdata(saddr, buf, 2); + if (rc < 0) + return rc; + + *rdata = buf[0] << 8 | buf[1]; + + if (rc < 0) + CDBG("mt9p012_km_i2c_read failed!\n"); + + return rc; +} + +static int32_t mt9p012_km_i2c_txdata(unsigned short saddr, + unsigned char *txdata, + int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr << 1, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + if (i2c_transfer(mt9p012_km_client->adapter, msg, 1) < 0) { + CDBG("mt9p012_km_i2c_txdata failed\n"); + return -EIO; + } + + return 0; +} + +static int32_t mt9p012_km_i2c_write_b(unsigned short saddr, + unsigned short baddr, + unsigned short bdata) +{ + int32_t rc = -EIO; + unsigned char buf[2]; + + memset(buf, 0, sizeof(buf)); + buf[0] = baddr; + buf[1] = bdata; + rc = mt9p012_km_i2c_txdata(saddr, buf, 2); + + if (rc < 0) + CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!\n", + saddr, baddr, bdata); + + return rc; +} + +static int32_t mt9p012_km_i2c_write_w(unsigned short saddr, + unsigned short waddr, + unsigned short wdata) +{ + int32_t rc = -EIO; + unsigned char buf[4]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00) >> 8; + buf[3] = (wdata & 0x00FF); + + rc = mt9p012_km_i2c_txdata(saddr, buf, 4); + + if (rc < 0) + CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + + return rc; +} + +static int32_t mt9p012_km_i2c_write_w_table(struct mt9p012_km_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + + for (i = 0; i < num; i++) { + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + + return rc; +} + +static int32_t mt9p012_km_test(enum mt9p012_km_test_mode mo) +{ + int32_t rc = 0; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + if (mo == TEST_OFF) + return 0; + else { + rc = mt9p012_km_i2c_write_w_table(mt9p012_km_regs.ttbl, + mt9p012_km_regs.ttbl_size); + if (rc < 0) + return rc; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_TEST_PATTERN_MODE, (uint16_t) mo); + if (rc < 0) + return rc; + } + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t mt9p012_km_lens_shading_enable(uint8_t is_enable) +{ + int32_t rc = 0; + + CDBG("%s: entered. enable = %d\n", __func__, is_enable); + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, 0x3780, + ((uint16_t) is_enable) << 15); + if (rc < 0) + return rc; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + + CDBG("%s: exiting. rc = %d\n", __func__, rc); + return rc; +} + +static int32_t mt9p012_km_set_lc(void) +{ + int32_t rc; + + rc = mt9p012_km_i2c_write_w_table(mt9p012_km_regs.lctbl, + mt9p012_km_regs.lctbl_size); + + return rc; +} + +static void mt9p012_km_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + + /* input fps is preview fps in Q8 format */ + uint32_t divider; /*Q10 */ + uint32_t pclk_mult; /*Q10 */ + uint32_t d1; + uint32_t d2; + + d1 = + (uint32_t)( + (mt9p012_km_regs.reg_pat[RES_PREVIEW].frame_length_lines * + 0x00000400) / + mt9p012_km_regs.reg_pat[RES_CAPTURE].frame_length_lines); + + d2 = + (uint32_t)( + (mt9p012_km_regs.reg_pat[RES_PREVIEW].line_length_pck * + 0x00000400) / + mt9p012_km_regs.reg_pat[RES_CAPTURE].line_length_pck); + + divider = (uint32_t) (d1 * d2) / 0x00000400; + + pclk_mult = + (uint32_t) ((mt9p012_km_regs.reg_pat[RES_CAPTURE]. + pll_multiplier * 0x00000400) / + (mt9p012_km_regs.reg_pat[RES_PREVIEW].pll_multiplier)); + + + /* Verify PCLK settings and frame sizes. */ + *pfps = (uint16_t)((((fps * pclk_mult) / 0x00000400) * divider)/ + 0x00000400); +} + +static uint16_t mt9p012_km_get_prev_lines_pf(void) +{ + if (mt9p012_km_ctrl->prev_res == QTR_SIZE) + return mt9p012_km_regs.reg_pat[RES_PREVIEW].frame_length_lines; + else + return mt9p012_km_regs.reg_pat[RES_CAPTURE].frame_length_lines; +} + +static uint16_t mt9p012_km_get_prev_pixels_pl(void) +{ + if (mt9p012_km_ctrl->prev_res == QTR_SIZE) + return mt9p012_km_regs.reg_pat[RES_PREVIEW].line_length_pck; + else + return mt9p012_km_regs.reg_pat[RES_CAPTURE].line_length_pck; +} + +static uint16_t mt9p012_km_get_pict_lines_pf(void) +{ + return mt9p012_km_regs.reg_pat[RES_CAPTURE].frame_length_lines; +} + +static uint16_t mt9p012_km_get_pict_pixels_pl(void) +{ + return mt9p012_km_regs.reg_pat[RES_CAPTURE].line_length_pck; +} + +static uint32_t mt9p012_km_get_pict_max_exp_lc(void) +{ + uint16_t snapshot_lines_per_frame; + + if (mt9p012_km_ctrl->pict_res == QTR_SIZE) + snapshot_lines_per_frame = + mt9p012_km_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1; + else + snapshot_lines_per_frame = + mt9p012_km_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1; + + return snapshot_lines_per_frame * 24; +} + +static int32_t mt9p012_km_set_fps(struct fps_cfg *fps) +{ + int32_t rc = 0; + + mt9p012_km_ctrl->fps_divider = fps->fps_div; + mt9p012_km_ctrl->pict_fps_divider = fps->pict_fps_div; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return -EBUSY; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_FRAME_LENGTH_LINES, + mt9p012_km_regs.reg_pat[mt9p012_km_ctrl->sensormode]. + frame_length_lines * + mt9p012_km_ctrl->fps_divider / 0x00000400); + if (rc < 0) + return rc; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + + return rc; +} + + +static int32_t mt9p012_km_write_exp_gain(uint16_t gain, uint32_t line) +{ + uint16_t max_legal_gain = 0x01FF; + uint32_t line_length_ratio = 0x00000400; + enum mt9p012_km_setting setting; + int32_t rc = 0; + + CDBG("Line:%d mt9p012_km_write_exp_gain \n", __LINE__); + + if (mt9p012_km_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + mt9p012_km_ctrl->my_reg_gain = gain; + mt9p012_km_ctrl->my_reg_line_count = (uint16_t) line; + } + + if (gain > max_legal_gain) { + CDBG("Max legal gain Line:%d \n", __LINE__); + gain = max_legal_gain; + } + + /* Verify no overflow */ + if (mt9p012_km_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + line = (uint32_t) (line * mt9p012_km_ctrl->fps_divider / + 0x00000400); + setting = RES_PREVIEW; + } else { + line = (uint32_t) (line * mt9p012_km_ctrl->pict_fps_divider / + 0x00000400); + setting = RES_CAPTURE; + } + + gain |= 0x0200; + + if ((mt9p012_km_regs.reg_pat[setting].frame_length_lines - 1) < line) { + line_length_ratio = (uint32_t) (line * 0x00000400) / + (mt9p012_km_regs.reg_pat[setting].frame_length_lines - 1); + } else + line_length_ratio = 0x00000400; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) { + CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GLOBAL_GAIN, gain); + if (rc < 0) { + CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_LINE_LENGTH_PCK, + (uint16_t) (mt9p012_km_regs.reg_pat[setting]. + line_length_pck * line_length_ratio / 0x00000400)); + if (rc < 0) + return rc; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_COARSE_INT_TIME, + (uint16_t) ((line * 0x00000400)/ + line_length_ratio)); + if (rc < 0) { + CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + if (rc < 0) { + CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + CDBG("mt9p012_km_write_exp_gain: gain = %d, line = %d\n", gain, line); + + return rc; +} + +static int32_t mt9p012_km_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + + CDBG("Line:%d mt9p012_km_set_pict_exp_gain \n", __LINE__); + + rc = mt9p012_km_write_exp_gain(gain, line); + if (rc < 0) { + CDBG("Line:%d mt9p012_km_set_pict_exp_gain failed... \n", + __LINE__); + return rc; + } + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + MT9P012_KM_REG_RESET_REGISTER, + 0x10CC | 0x0002); + if (rc < 0) { + CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__); + return rc; + } + + mdelay(5); + + /* camera_timed_wait(snapshot_wait*exposure_ratio); */ + return rc; +} + +static int32_t mt9p012_km_setting(enum mt9p012_km_reg_update rupdate, + enum mt9p012_km_setting rt) +{ + int32_t rc = 0; + + switch (rupdate) { + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + + struct mt9p012_km_i2c_reg_conf ppc_tbl[] = { + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD}, + {REG_ROW_SPEED, + mt9p012_km_regs.reg_pat[rt].row_speed}, + {REG_X_ADDR_START, + mt9p012_km_regs.reg_pat[rt].x_addr_start}, + {REG_X_ADDR_END, + mt9p012_km_regs.reg_pat[rt].x_addr_end}, + {REG_Y_ADDR_START, + mt9p012_km_regs.reg_pat[rt].y_addr_start}, + {REG_Y_ADDR_END, + mt9p012_km_regs.reg_pat[rt].y_addr_end}, + {REG_READ_MODE, + mt9p012_km_regs.reg_pat[rt].read_mode}, + {REG_SCALE_M, + mt9p012_km_regs.reg_pat[rt].scale_m}, + {REG_X_OUTPUT_SIZE, + mt9p012_km_regs.reg_pat[rt].x_output_size}, + {REG_Y_OUTPUT_SIZE, + mt9p012_km_regs.reg_pat[rt].y_output_size}, + {REG_LINE_LENGTH_PCK, + mt9p012_km_regs.reg_pat[rt].line_length_pck}, + {REG_FRAME_LENGTH_LINES, + (mt9p012_km_regs.reg_pat[rt].frame_length_lines * + mt9p012_km_ctrl->fps_divider / 0x00000400)}, + {REG_COARSE_INT_TIME, + mt9p012_km_regs.reg_pat[rt].coarse_int_time}, + {REG_FINE_INTEGRATION_TIME, + mt9p012_km_regs.reg_pat[rt].fine_int_time}, + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE}, + }; + + if (update_type == REG_INIT) { + update_type = rupdate; + return rc; + } + + rc = mt9p012_km_i2c_write_w_table(&ppc_tbl[0], + ARRAY_SIZE(ppc_tbl)); + if (rc < 0) + return rc; + + rc = mt9p012_km_test(mt9p012_km_ctrl->set_test); + if (rc < 0) + return rc; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + MT9P012_KM_REG_RESET_REGISTER, + 0x10cc | + 0x0002); + if (rc < 0) + return rc; + + mdelay(15); /* 15? wait for sensor to transition */ + + return rc; + } + break; /* UPDATE_PERIODIC */ + + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct mt9p012_km_i2c_reg_conf ipc_tbl1[] = { + {MT9P012_KM_REG_RESET_REGISTER, + MT9P012_KM_RESET_REGISTER_PWOFF}, + {REG_VT_PIX_CLK_DIV, + mt9p012_km_regs.reg_pat[rt].vt_pix_clk_div}, + {REG_VT_SYS_CLK_DIV, + mt9p012_km_regs.reg_pat[rt].vt_sys_clk_div}, + {REG_PRE_PLL_CLK_DIV, + mt9p012_km_regs.reg_pat[rt].pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + mt9p012_km_regs.reg_pat[rt].pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + mt9p012_km_regs.reg_pat[rt].op_pix_clk_div}, + {REG_OP_SYS_CLK_DIV, + mt9p012_km_regs.reg_pat[rt].op_sys_clk_div}, + {MT9P012_KM_REG_RESET_REGISTER, + MT9P012_KM_RESET_REGISTER_PWON}, + }; + + struct mt9p012_km_i2c_reg_conf ipc_tbl2[] = { + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD}, + /* Optimized register settings for + Rev3 Silicon */ + {0x308A, 0x6424}, + {0x3092, 0x0A52}, + {0x3094, 0x4656}, + {0x3096, 0x5652}, + {0x0204, 0x0010}, + {0x0206, 0x0010}, + {0x0208, 0x0010}, + {0x020A, 0x0010}, + {0x020C, 0x0010}, + {0x3088, 0x6FF6}, + {0x3154, 0x0282}, + {0x3156, 0x0381}, + {0x3162, 0x04CE}, + }; + + struct mt9p012_km_i2c_reg_conf ipc_tbl3[] = { + /* Set preview or snapshot mode */ + {REG_ROW_SPEED, + mt9p012_km_regs.reg_pat[rt].row_speed}, + {REG_X_ADDR_START, + mt9p012_km_regs.reg_pat[rt].x_addr_start}, + {REG_X_ADDR_END, + mt9p012_km_regs.reg_pat[rt].x_addr_end}, + {REG_Y_ADDR_START, + mt9p012_km_regs.reg_pat[rt].y_addr_start}, + {REG_Y_ADDR_END, + mt9p012_km_regs.reg_pat[rt].y_addr_end}, + {REG_READ_MODE, + mt9p012_km_regs.reg_pat[rt].read_mode}, + {REG_SCALE_M, + mt9p012_km_regs.reg_pat[rt].scale_m}, + {REG_X_OUTPUT_SIZE, + mt9p012_km_regs.reg_pat[rt].x_output_size}, + {REG_Y_OUTPUT_SIZE, + mt9p012_km_regs.reg_pat[rt].y_output_size}, + {REG_LINE_LENGTH_PCK, + mt9p012_km_regs.reg_pat[rt].line_length_pck}, + {REG_FRAME_LENGTH_LINES, + mt9p012_km_regs.reg_pat[rt]. + frame_length_lines}, + {REG_COARSE_INT_TIME, + mt9p012_km_regs.reg_pat[rt].coarse_int_time}, + {REG_FINE_INTEGRATION_TIME, + mt9p012_km_regs.reg_pat[rt].fine_int_time}, + {REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE}, + }; + + /* reset fps_divider */ + mt9p012_km_ctrl->fps_divider = 1 * 0x0400; + + rc = mt9p012_km_i2c_write_w_table(&ipc_tbl1[0], + ARRAY_SIZE(ipc_tbl1)); + if (rc < 0) + return rc; + + mdelay(15); + + rc = mt9p012_km_i2c_write_w_table(&ipc_tbl2[0], + ARRAY_SIZE(ipc_tbl2)); + if (rc < 0) + return rc; + + mdelay(5); + + rc = mt9p012_km_i2c_write_w_table(&ipc_tbl3[0], + ARRAY_SIZE(ipc_tbl3)); + if (rc < 0) + return rc; + + /* load lens shading */ + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + rc = mt9p012_km_set_lc(); + if (rc < 0) + return rc; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + + if (rc < 0) + return rc; + } + update_type = rupdate; + break; /* case REG_INIT: */ + + default: + rc = -EINVAL; + break; + } /* switch (rupdate) */ + + return rc; +} + +static int32_t mt9p012_km_video_config(int mode, int res) +{ + int32_t rc; + + switch (res) { + case QTR_SIZE: + rc = mt9p012_km_setting(UPDATE_PERIODIC, RES_PREVIEW); + if (rc < 0) + return rc; + + CDBG("mt9p012_km sensor configuration done!\n"); + break; + + case FULL_SIZE: + rc = mt9p012_km_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + break; + + default: + return 0; + } /* switch */ + + mt9p012_km_ctrl->prev_res = res; + mt9p012_km_ctrl->curr_res = res; + mt9p012_km_ctrl->sensormode = mode; + + rc = mt9p012_km_write_exp_gain(mt9p012_km_ctrl->my_reg_gain, + mt9p012_km_ctrl->my_reg_line_count); + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + MT9P012_KM_REG_RESET_REGISTER, + 0x10cc | 0x0002); + + mdelay(15); + return rc; +} + +static int32_t mt9p012_km_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = mt9p012_km_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + mt9p012_km_ctrl->curr_res = mt9p012_km_ctrl->pict_res; + + mt9p012_km_ctrl->sensormode = mode; + + return rc; +} + +static int32_t mt9p012_km_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = mt9p012_km_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + mt9p012_km_ctrl->curr_res = mt9p012_km_ctrl->pict_res; + + mt9p012_km_ctrl->sensormode = mode; + + return rc; +} + +static int32_t mt9p012_km_power_down(void) +{ + int32_t rc = 0; + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + MT9P012_KM_REG_RESET_REGISTER, + MT9P012_KM_RESET_REGISTER_PWOFF); + + mdelay(5); + return rc; +} + +static int32_t mt9p012_km_move_focus(int direction, int32_t num_steps) +{ + int16_t step_direction; + int16_t actual_step; + int16_t next_position; + uint8_t code_val_msb, code_val_lsb; + + if (num_steps > MT9P012_KM_TOTAL_STEPS_NEAR_TO_FAR) + num_steps = MT9P012_KM_TOTAL_STEPS_NEAR_TO_FAR; + else if (num_steps == 0) { + CDBG("mt9p012_km_move_focus failed at line %d ...\n", __LINE__); + return -EINVAL; + } + + if (direction == MOVE_NEAR) + step_direction = 16; /* 10bit */ + else if (direction == MOVE_FAR) + step_direction = -16; /* 10 bit */ + else { + CDBG("mt9p012_km_move_focus failed at line %d ...\n", __LINE__); + return -EINVAL; + } + + if (mt9p012_km_ctrl->curr_lens_pos < + mt9p012_km_ctrl->init_curr_lens_pos) + mt9p012_km_ctrl->curr_lens_pos = + mt9p012_km_ctrl->init_curr_lens_pos; + + actual_step = (int16_t) (step_direction * (int16_t) num_steps); + next_position = (int16_t) (mt9p012_km_ctrl->curr_lens_pos + + actual_step); + + if (next_position > 1023) + next_position = 1023; + else if (next_position < 0) + next_position = 0; + + code_val_msb = next_position >> 4; + code_val_lsb = (next_position & 0x000F) << 4; + code_val_lsb |= mode_mask; + + /* Writing the digital code for current to the actuator */ + if (mt9p012_km_i2c_write_b(MT9P012_KM_AF_I2C_ADDR >> 1, + code_val_msb, code_val_lsb) < 0) { + CDBG("mt9p012_km_move_focus failed at line %d ...\n", __LINE__); + return -EBUSY; + } + + /* Storing the current lens Position */ + mt9p012_km_ctrl->curr_lens_pos = next_position; + + return 0; +} + +static int32_t mt9p012_km_set_default_focus(void) +{ + int32_t rc = 0; + uint8_t code_val_msb, code_val_lsb; + + code_val_msb = 0x00; + code_val_lsb = 0x04; + + /* Write the digital code for current to the actuator */ + rc = mt9p012_km_i2c_write_b(MT9P012_KM_AF_I2C_ADDR >> 1, + code_val_msb, code_val_lsb); + + mt9p012_km_ctrl->curr_lens_pos = 0; + mt9p012_km_ctrl->init_curr_lens_pos = 0; + + return rc; +} + +static int mt9p012_km_probe_init_done(const struct msm_camera_sensor_info *data) +{ + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + return 0; +} + +static int + mt9p012_km_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + uint16_t chipid; + + rc = gpio_request(data->sensor_reset, "mt9p012_km"); + if (!rc) + gpio_direction_output(data->sensor_reset, 1); + else + goto init_probe_done; + + msleep(20); + + /* RESET the sensor image part via I2C command */ + CDBG("mt9p012_km_sensor_init(): reseting sensor.\n"); + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + MT9P012_KM_REG_RESET_REGISTER, + 0x10CC | 0x0001); + if (rc < 0) { + CDBG("sensor reset failed. rc = %d\n", rc); + goto init_probe_fail; + } + + msleep(MT9P012_KM_RESET_DELAY_MSECS); + + /* 3. Read sensor Model ID: */ + rc = mt9p012_km_i2c_read_w(mt9p012_km_client->addr, + MT9P012_KM_REG_MODEL_ID, &chipid); + if (rc < 0) + goto init_probe_fail; + + /* 4. Compare sensor ID to MT9T012VC ID: */ + if (chipid != MT9P012_KM_MODEL_ID) { + CDBG("mt9p012_km wrong model_id = 0x%x\n", chipid); + rc = -ENODEV; + goto init_probe_fail; + } + + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, 0x306E, 0x9080); + if (rc < 0) { + CDBG("REV_7 write failed. rc = %d\n", rc); + goto init_probe_fail; + } + + /* RESET_REGISTER, enable parallel interface and disable serialiser */ + CDBG("mt9p012_km_sensor_init(): enabling parallel interface.\n"); + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, 0x301A, 0x10CC); + if (rc < 0) { + CDBG("enable parallel interface failed. rc = %d\n", rc); + goto init_probe_fail; + } + + /* To disable the 2 extra lines */ + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, 0x3064, 0x0805); + + if (rc < 0) { + CDBG("disable the 2 extra lines failed. rc = %d\n", rc); + goto init_probe_fail; + } + + goto init_probe_done; + +init_probe_fail: + mt9p012_km_probe_init_done(data); +init_probe_done: + return rc; +} + +static int + mt9p012_km_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + + mt9p012_km_ctrl = kzalloc(sizeof(struct mt9p012_km_ctrl), GFP_KERNEL); + if (!mt9p012_km_ctrl) { + CDBG("mt9p012_km_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + mt9p012_km_ctrl->fps_divider = 1 * 0x00000400; + mt9p012_km_ctrl->pict_fps_divider = 1 * 0x00000400; + mt9p012_km_ctrl->set_test = TEST_OFF; + mt9p012_km_ctrl->prev_res = QTR_SIZE; + mt9p012_km_ctrl->pict_res = FULL_SIZE; + + if (data) + mt9p012_km_ctrl->sensordata = data; + + msm_camio_camif_pad_reg_reset(); + mdelay(20); + + rc = mt9p012_km_probe_init_sensor(data); + if (rc < 0) + goto init_fail1; + + if (mt9p012_km_ctrl->prev_res == QTR_SIZE) + rc = mt9p012_km_setting(REG_INIT, RES_PREVIEW); + else + rc = mt9p012_km_setting(REG_INIT, RES_CAPTURE); + + if (rc < 0) { + CDBG("mt9p012_km_setting failed. rc = %d\n", rc); + goto init_fail1; + } + + /* sensor : output enable */ + CDBG("mt9p012_km_sensor_open_init(): enabling output.\n"); + rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, + MT9P012_KM_REG_RESET_REGISTER, + MT9P012_KM_RESET_REGISTER_PWON); + if (rc < 0) { + CDBG("sensor output enable failed. rc = %d\n", rc); + goto init_fail1; + } + + if (rc >= 0) + goto init_done; + +init_fail1: + mt9p012_km_probe_init_done(data); + kfree(mt9p012_km_ctrl); +init_done: + return rc; +} + +static int mt9p012_km_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&mt9p012_km_wait_queue); + return 0; +} + +static int32_t mt9p012_km_set_sensor_mode(int mode, int res) +{ + int32_t rc = 0; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = mt9p012_km_video_config(mode, res); + break; + + case SENSOR_SNAPSHOT_MODE: + rc = mt9p012_km_snapshot_config(mode); + break; + + case SENSOR_RAW_SNAPSHOT_MODE: + rc = mt9p012_km_raw_snapshot_config(mode); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +int mt9p012_km_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + int rc = 0; + + if (copy_from_user(&cdata, + (void *)argp, sizeof(struct sensor_cfg_data))) + return -EFAULT; + + mutex_lock(&mt9p012_km_mut); + + CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + mt9p012_km_get_pict_fps(cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = mt9p012_km_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = mt9p012_km_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = mt9p012_km_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = mt9p012_km_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = mt9p012_km_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = mt9p012_km_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = mt9p012_km_write_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__); + rc = mt9p012_km_set_pict_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = mt9p012_km_set_sensor_mode(cdata.mode, cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = mt9p012_km_power_down(); + break; + + case CFG_MOVE_FOCUS: + CDBG("mt9p012_km_ioctl: CFG_MOVE_FOCUS: cdata.cfg.focus.dir=%d \ + cdata.cfg.focus.steps=%d\n", + cdata.cfg.focus.dir, cdata.cfg.focus.steps); + rc = mt9p012_km_move_focus(cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = mt9p012_km_set_default_focus(); + break; + + case CFG_SET_LENS_SHADING: + CDBG("%s: CFG_SET_LENS_SHADING\n", __func__); + rc = mt9p012_km_lens_shading_enable(cdata.cfg.lens_shading); + break; + + case CFG_GET_AF_MAX_STEPS: + cdata.max_steps = MT9P012_KM_STEPS_NEAR_TO_CLOSEST_INF; + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_EFFECT: + default: + rc = -EINVAL; + break; + } + + mutex_unlock(&mt9p012_km_mut); + return rc; +} + +int mt9p012_km_sensor_release(void) +{ + int rc = -EBADF; + + mutex_lock(&mt9p012_km_mut); + + mt9p012_km_power_down(); + + gpio_direction_output(mt9p012_km_ctrl->sensordata->sensor_reset, 0); + gpio_free(mt9p012_km_ctrl->sensordata->sensor_reset); + + gpio_direction_output(mt9p012_km_ctrl->sensordata->vcm_pwd, 0); + gpio_free(mt9p012_km_ctrl->sensordata->vcm_pwd); + + kfree(mt9p012_km_ctrl); + mt9p012_km_ctrl = NULL; + + CDBG("mt9p012_km_release completed\n"); + + mutex_unlock(&mt9p012_km_mut); + return rc; +} + +static int mt9p012_km_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("mt9p012_km_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + mt9p012_km_sensorw = kzalloc(sizeof(struct mt9p012_km_work), + GFP_KERNEL); + if (!mt9p012_km_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, mt9p012_km_sensorw); + mt9p012_km_init_client(client); + mt9p012_km_client = client; + + mdelay(50); + + CDBG("mt9p012_km_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("mt9p012_km_probe failed! rc = %d\n", rc); + return rc; +} + +static const struct i2c_device_id mt9p012_km_i2c_id[] = { + {"mt9p012_km", 0}, + {} +}; + +static struct i2c_driver mt9p012_km_i2c_driver = { + .id_table = mt9p012_km_i2c_id, + .probe = mt9p012_km_i2c_probe, + .remove = __exit_p(mt9p012_km_i2c_remove), + .driver = { + .name = "mt9p012_km", + }, +}; + +static int mt9p012_km_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = i2c_add_driver(&mt9p012_km_i2c_driver); + if (rc < 0 || mt9p012_km_client == NULL) { + rc = -ENOTSUPP; + goto probe_done; + } + + msm_camio_clk_rate_set(MT9P012_KM_DEFAULT_CLOCK_RATE); + mdelay(20); + + rc = mt9p012_km_probe_init_sensor(info); + if (rc < 0) + goto probe_done; + + s->s_init = mt9p012_km_sensor_open_init; + s->s_release = mt9p012_km_sensor_release; + s->s_config = mt9p012_km_sensor_config; + s->s_mount_angle = 0; + mt9p012_km_probe_init_done(info); + +probe_done: + CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__); + return rc; +} + +static int __mt9p012_km_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, mt9p012_km_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __mt9p012_km_probe, + .driver = { + .name = "msm_camera_mt9p012_km", + .owner = THIS_MODULE, + }, +}; + +static int __init mt9p012_km_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(mt9p012_km_init); diff --git a/drivers/media/video/msm_zsl/mt9p012_km.h b/drivers/media/video/msm_zsl/mt9p012_km.h new file mode 100644 index 00000000000..aefabd4122c --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9p012_km.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef MT9P012_KM_H +#define MT9P012_KM_H + +#include + +extern struct mt9p012_km_reg mt9p012_km_regs; /* from mt9p012_km_reg.c */ + +struct reg_struct { + uint16_t vt_pix_clk_div; /* 0x0300 */ + uint16_t vt_sys_clk_div; /* 0x0302 */ + uint16_t pre_pll_clk_div; /* 0x0304 */ + uint16_t pll_multiplier; /* 0x0306 */ + uint16_t op_pix_clk_div; /* 0x0308 */ + uint16_t op_sys_clk_div; /* 0x030A */ + uint16_t scale_m; /* 0x0404 */ + uint16_t row_speed; /* 0x3016 */ + uint16_t x_addr_start; /* 0x3004 */ + uint16_t x_addr_end; /* 0x3008 */ + uint16_t y_addr_start; /* 0x3002 */ + uint16_t y_addr_end; /* 0x3006 */ + uint16_t read_mode; /* 0x3040 */ + uint16_t x_output_size ; /* 0x034C */ + uint16_t y_output_size; /* 0x034E */ + uint16_t line_length_pck; /* 0x300C */ + uint16_t frame_length_lines; /* 0x300A */ + uint16_t coarse_int_time; /* 0x3012 */ + uint16_t fine_int_time; /* 0x3014 */ +}; + + +struct mt9p012_km_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + + +struct mt9p012_km_reg { + struct reg_struct const *reg_pat; + uint16_t reg_pat_size; + struct mt9p012_km_i2c_reg_conf const *ttbl; + uint16_t ttbl_size; + struct mt9p012_km_i2c_reg_conf const *lctbl; + uint16_t lctbl_size; + struct mt9p012_km_i2c_reg_conf const *rftbl; + uint16_t rftbl_size; +}; + +#endif /* MT9P012_KM_H */ diff --git a/drivers/media/video/msm_zsl/mt9p012_km_reg.c b/drivers/media/video/msm_zsl/mt9p012_km_reg.c new file mode 100644 index 00000000000..81221fb1e0c --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9p012_km_reg.c @@ -0,0 +1,373 @@ +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "mt9p012_km.h" +#include + +/*Micron settings from Applications for lower power consumption.*/ +struct reg_struct const mt9p012_km_reg_pat[2] = { + { /* Preview */ + /* vt_pix_clk_div REG=0x0300 */ + 6, /* 5 */ + + /* vt_sys_clk_div REG=0x0302 */ + 1, + + /* pre_pll_clk_div REG=0x0304 */ + 2, + + /* pll_multiplier REG=0x0306 */ + 60, + + /* op_pix_clk_div REG=0x0308 */ + 8, /* 10 */ + + /* op_sys_clk_div REG=0x030A */ + 1, + + /* scale_m REG=0x0404 */ + 16, + + /* row_speed REG=0x3016 */ + 0x0111, + + /* x_addr_start REG=0x3004 */ + 8, + + /* x_addr_end REG=0x3008 */ + 2597, + + /* y_addr_start REG=0x3002 */ + 8, + + /* y_addr_end REG=0x3006 */ + 1949, + + /* read_mode REG=0x3040 + * Preview 2x2 skipping */ + 0x006C, + + /* x_output_size REG=0x034C */ + 1296, + + /* y_output_size REG=0x034E */ + 972, + + /* line_length_pck REG=0x300C */ + 3783, + + /* frame_length_lines REG=0x300A */ + 1074, + + /* coarse_integration_time REG=0x3012 */ + 16, + + /* fine_integration_time REG=0x3014 */ + 1764 + }, + { /* Snapshot */ + /* vt_pix_clk_div REG=0x0300 */ + 6, + + /* vt_sys_clk_div REG=0x0302 */ + 1, + + /* pre_pll_clk_div REG=0x0304 */ + 2, + + /* pll_multiplier REG=0x0306 + * 39 for 10fps snapshot */ + 39, + + /* op_pix_clk_div REG=0x0308 */ + 8, + + /* op_sys_clk_div REG=0x030A */ + 1, + + /* scale_m REG=0x0404 */ + 16, + + /* row_speed REG=0x3016 */ + 0x0111, + + /* x_addr_start REG=0x3004 */ + 8, + + /* x_addr_end REG=0x3008 */ + 2615, + + /* y_addr_start REG=0x3002 */ + 8, + + /* y_addr_end REG=0x3006 */ + 1967, + + /* read_mode REG=0x3040 */ + 0x0024, + + /* x_output_size REG=0x034C */ + 2608, + + /* y_output_size REG=0x034E */ + 1960, + + /* line_length_pck REG=0x300C */ + 3788, + + /* frame_length_lines REG=0x300A 10 fps snapshot */ + 2045, + + /* coarse_integration_time REG=0x3012 */ + 16, + + /* fine_integration_time REG=0x3014 */ + 882 + } +}; + +struct mt9p012_km_i2c_reg_conf const mt9p012_km_test_tbl[] = { + {0x3044, 0x0544 & 0xFBFF}, + {0x30CA, 0x0004 | 0x0001}, + {0x30D4, 0x9020 & 0x7FFF}, + {0x31E0, 0x0003 & 0xFFFE}, + {0x3180, 0x91FF & 0x7FFF}, + {0x301A, (0x10CC | 0x8000) & 0xFFF7}, + {0x301E, 0x0000}, + {0x3780, 0x0000}, +}; + + +struct mt9p012_km_i2c_reg_conf const mt9p012_km_lc_tbl[] = { + {0x360A, 0x00F0}, + {0x360C, 0x0B29}, + {0x360E, 0x5ED1}, + {0x3610, 0x890D}, + {0x3612, 0x9871}, + {0x364A, 0xAD2C}, + {0x364C, 0x0A8C}, + {0x364E, 0x91EC}, + {0x3650, 0x94EC}, + {0x3652, 0xC76B}, + {0x368A, 0x5931}, + {0x368C, 0x4FED}, + {0x368E, 0x8A50}, + {0x3690, 0x5C0F}, + {0x3692, 0x8393}, + {0x36CA, 0xDB8E}, + {0x36CC, 0xCA4D}, + {0x36CE, 0x146F}, + {0x36D0, 0x618F}, + {0x36D2, 0x014F}, + {0x370A, 0x1FEE}, + {0x370C, 0xDD50}, + {0x370E, 0xDB54}, + {0x3710, 0xCA92}, + {0x3712, 0x1896}, + {0x3600, 0x00F0}, + {0x3602, 0xA04C}, + {0x3604, 0x5711}, + {0x3606, 0x5E6D}, + {0x3608, 0xA971}, + {0x3640, 0xDCCC}, + {0x3642, 0x0529}, + {0x3644, 0x96ED}, + {0x3646, 0xF447}, + {0x3648, 0x4AEE}, + {0x3680, 0x2171}, + {0x3682, 0x634F}, + {0x3684, 0xCC91}, + {0x3686, 0xA9CE}, + {0x3688, 0x8751}, + {0x36C0, 0x8B6D}, + {0x36C2, 0xE20E}, + {0x36C4, 0x750F}, + {0x36C6, 0x0090}, + {0x36C8, 0x9E91}, + {0x3700, 0xEAAF}, + {0x3702, 0xB8AF}, + {0x3704, 0xE293}, + {0x3706, 0xAB33}, + {0x3708, 0x4595}, + {0x3614, 0x00D0}, + {0x3616, 0x8AAB}, + {0x3618, 0x18B1}, + {0x361A, 0x54AD}, + {0x361C, 0x9DB0}, + {0x3654, 0x11EB}, + {0x3656, 0x332C}, + {0x3658, 0x316D}, + {0x365A, 0xF0EB}, + {0x365C, 0xB4ED}, + {0x3694, 0x0F31}, + {0x3696, 0x08D0}, + {0x3698, 0xA52F}, + {0x369A, 0xE64F}, + {0x369C, 0xC9D2}, + {0x36D4, 0x8C2D}, + {0x36D6, 0xAD6E}, + {0x36D8, 0xE1CE}, + {0x36DA, 0x1750}, + {0x36DC, 0x8CAD}, + {0x3714, 0x8CAF}, + {0x3716, 0x8C11}, + {0x3718, 0xE453}, + {0x371A, 0x9693}, + {0x371C, 0x38B5}, + {0x361E, 0x00D0}, + {0x3620, 0xB6CB}, + {0x3622, 0x4811}, + {0x3624, 0xB70C}, + {0x3626, 0xA771}, + {0x365E, 0xB5A9}, + {0x3660, 0x05AA}, + {0x3662, 0x00CF}, + {0x3664, 0xB86B}, + {0x3666, 0xA4AF}, + {0x369E, 0x3E31}, + {0x36A0, 0x902B}, + {0x36A2, 0xD251}, + {0x36A4, 0x5C2F}, + {0x36A6, 0x8471}, + {0x36DE, 0x2C6D}, + {0x36E0, 0xECEE}, + {0x36E2, 0xB650}, + {0x36E4, 0x0210}, + {0x36E6, 0xACAE}, + {0x371E, 0xAC30}, + {0x3720, 0x394E}, + {0x3722, 0xFDD3}, + {0x3724, 0xBCB2}, + {0x3726, 0x5AD5}, + {0x3782, 0x0508}, + {0x3784, 0x03B4}, + {0x3780, 0x8000}, +}; + +struct mt9p012_km_i2c_reg_conf const mt9p012_km_rolloff_tbl[] = { + {0x360A, 0x00F0}, + {0x360C, 0x0B29}, + {0x360E, 0x5ED1}, + {0x3610, 0x890D}, + {0x3612, 0x9871}, + {0x364A, 0xAD2C}, + {0x364C, 0x0A8C}, + {0x364E, 0x91EC}, + {0x3650, 0x94EC}, + {0x3652, 0xC76B}, + {0x368A, 0x5931}, + {0x368C, 0x4FED}, + {0x368E, 0x8A50}, + {0x3690, 0x5C0F}, + {0x3692, 0x8393}, + {0x36CA, 0xDB8E}, + {0x36CC, 0xCA4D}, + {0x36CE, 0x146F}, + {0x36D0, 0x618F}, + {0x36D2, 0x014F}, + {0x370A, 0x1FEE}, + {0x370C, 0xDD50}, + {0x370E, 0xDB54}, + {0x3710, 0xCA92}, + {0x3712, 0x1896}, + {0x3600, 0x00F0}, + {0x3602, 0xA04C}, + {0x3604, 0x5711}, + {0x3606, 0x5E6D}, + {0x3608, 0xA971}, + {0x3640, 0xDCCC}, + {0x3642, 0x0529}, + {0x3644, 0x96ED}, + {0x3646, 0xF447}, + {0x3648, 0x4AEE}, + {0x3680, 0x2171}, + {0x3682, 0x634F}, + {0x3684, 0xCC91}, + {0x3686, 0xA9CE}, + {0x3688, 0x8751}, + {0x36C0, 0x8B6D}, + {0x36C2, 0xE20E}, + {0x36C4, 0x750F}, + {0x36C6, 0x0090}, + {0x36C8, 0x9E91}, + {0x3700, 0xEAAF}, + {0x3702, 0xB8AF}, + {0x3704, 0xE293}, + {0x3706, 0xAB33}, + {0x3708, 0x4595}, + {0x3614, 0x00D0}, + {0x3616, 0x8AAB}, + {0x3618, 0x18B1}, + {0x361A, 0x54AD}, + {0x361C, 0x9DB0}, + {0x3654, 0x11EB}, + {0x3656, 0x332C}, + {0x3658, 0x316D}, + {0x365A, 0xF0EB}, + {0x365C, 0xB4ED}, + {0x3694, 0x0F31}, + {0x3696, 0x08D0}, + {0x3698, 0xA52F}, + {0x369A, 0xE64F}, + {0x369C, 0xC9D2}, + {0x36D4, 0x8C2D}, + {0x36D6, 0xAD6E}, + {0x36D8, 0xE1CE}, + {0x36DA, 0x1750}, + {0x36DC, 0x8CAD}, + {0x3714, 0x8CAF}, + {0x3716, 0x8C11}, + {0x3718, 0xE453}, + {0x371A, 0x9693}, + {0x371C, 0x38B5}, + {0x361E, 0x00D0}, + {0x3620, 0xB6CB}, + {0x3622, 0x4811}, + {0x3624, 0xB70C}, + {0x3626, 0xA771}, + {0x365E, 0xB5A9}, + {0x3660, 0x05AA}, + {0x3662, 0x00CF}, + {0x3664, 0xB86B}, + {0x3666, 0xA4AF}, + {0x369E, 0x3E31}, + {0x36A0, 0x902B}, + {0x36A2, 0xD251}, + {0x36A4, 0x5C2F}, + {0x36A6, 0x8471}, + {0x36DE, 0x2C6D}, + {0x36E0, 0xECEE}, + {0x36E2, 0xB650}, + {0x36E4, 0x0210}, + {0x36E6, 0xACAE}, + {0x371E, 0xAC30}, + {0x3720, 0x394E}, + {0x3722, 0xFDD3}, + {0x3724, 0xBCB2}, + {0x3726, 0x5AD5}, + {0x3782, 0x0508}, + {0x3784, 0x03B4}, + {0x3780, 0x8000}, +}; + + +struct mt9p012_km_reg mt9p012_km_regs = { + .reg_pat = &mt9p012_km_reg_pat[0], + .reg_pat_size = ARRAY_SIZE(mt9p012_km_reg_pat), + .ttbl = &mt9p012_km_test_tbl[0], + .ttbl_size = ARRAY_SIZE(mt9p012_km_test_tbl), + .lctbl = &mt9p012_km_lc_tbl[0], + .lctbl_size = ARRAY_SIZE(mt9p012_km_lc_tbl), + .rftbl = &mt9p012_km_rolloff_tbl[0], + .rftbl_size = ARRAY_SIZE(mt9p012_km_rolloff_tbl) +}; diff --git a/drivers/media/video/msm_zsl/mt9p012_reg.c b/drivers/media/video/msm_zsl/mt9p012_reg.c new file mode 100644 index 00000000000..a624c420905 --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9p012_reg.c @@ -0,0 +1,261 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "mt9p012.h" +#include + +/*Micron settings from Applications for lower power consumption.*/ +struct reg_struct const mt9p012_reg_pat[2] = { + { /* Preview */ + /* vt_pix_clk_div REG=0x0300 */ + 6, /* 5 */ + + /* vt_sys_clk_div REG=0x0302 */ + 1, + /* pre_pll_clk_div REG=0x0304 */ + 2, + /* pll_multiplier REG=0x0306 */ + 60, + + /* op_pix_clk_div REG=0x0308 */ + 8, /* 10 */ + + /* op_sys_clk_div REG=0x030A */ + 1, + + /* scale_m REG=0x0404 */ + 16, + + /* row_speed REG=0x3016 */ + 0x0111, + + /* x_addr_start REG=0x3004 */ + 8, + + /* x_addr_end REG=0x3008 */ + 2597, + + /* y_addr_start REG=0x3002 */ + 8, + + /* y_addr_end REG=0x3006 */ + 1949, + + /* read_mode REG=0x3040 + * Preview 2x2 skipping */ + 0x00C3, + + /* x_output_size REG=0x034C */ + 1296, + + /* y_output_size REG=0x034E */ + 972, + + /* line_length_pck REG=0x300C */ + 3659, + + /* frame_length_lines REG=0x300A */ + 1074, + + /* coarse_integration_time REG=0x3012 */ + 16, + + /* fine_integration_time REG=0x3014 */ + 1764 + }, + { /* Snapshot */ + /* vt_pix_clk_div REG=0x0300 */ + 6, + + /* vt_sys_clk_div REG=0x0302 */ + 1, + + /* pre_pll_clk_div REG=0x0304 */ + 2, + + /* pll_multiplier REG=0x0306 + * 60 for 10fps snapshot */ + 60, + + /* op_pix_clk_div REG=0x0308 */ + 8, + + /* op_sys_clk_div REG=0x030A */ + 1, + + /* scale_m REG=0x0404 */ + 16, + + /* row_speed REG=0x3016 */ + 0x0111, + + /* x_addr_start REG=0x3004 */ + 8, + + /* x_addr_end REG=0x3008 */ + 2615, + + /* y_addr_start REG=0x3002 */ + 8, + + /* y_addr_end REG=0x3006 */ + 1967, + + /* read_mode REG=0x3040 */ + 0x0041, + + /* x_output_size REG=0x034C */ + 2608, + + /* y_output_size REG=0x034E */ + 1960, + + /* line_length_pck REG=0x300C */ + 3911, + + /* frame_length_lines REG=0x300A 10 fps snapshot */ + 2045, + + /* coarse_integration_time REG=0x3012 */ + 16, + + /* fine_integration_time REG=0x3014 */ + 882 + } +}; + + +struct mt9p012_i2c_reg_conf const mt9p012_test_tbl[] = { + {0x3044, 0x0544 & 0xFBFF}, + {0x30CA, 0x0004 | 0x0001}, + {0x30D4, 0x9020 & 0x7FFF}, + {0x31E0, 0x0003 & 0xFFFE}, + {0x3180, 0x91FF & 0x7FFF}, + {0x301A, (0x10CC | 0x8000) & 0xFFF7}, + {0x301E, 0x0000}, + {0x3780, 0x0000}, +}; +struct mt9p012_i2c_reg_conf const mt9p012_rolloff_tbl[] = { + {0x360A, 0x0110}, + {0x360C, 0x270D}, + {0x360E, 0x0071}, + {0x3610, 0xA38D}, + {0x3612, 0xA610}, + {0x364A, 0x8F49}, + {0x364C, 0x696A}, + {0x364E, 0x0FCD}, + {0x3650, 0x20ED}, + {0x3652, 0x81ED}, + {0x368A, 0x1031}, + {0x368C, 0xBCAD}, + {0x368E, 0x77AA}, + {0x3690, 0xD10E}, + {0x3692, 0xC133}, + {0x36CA, 0x4F8D}, + {0x36CC, 0xAC4D}, + {0x36CE, 0xC8CE}, + {0x36D0, 0x73AD}, + {0x36D2, 0xC150}, + {0x370A, 0xB590}, + {0x370C, 0x9010}, + {0x370E, 0xAC52}, + {0x3710, 0x4D51}, + {0x3712, 0x5670}, + {0x3600, 0x00F0}, + {0x3602, 0xCE4B}, + {0x3604, 0x4270}, + {0x3606, 0x8BC9}, + {0x3608, 0xFA2F}, + {0x3640, 0x9A09}, + {0x3642, 0xB40C}, + {0x3644, 0x4ECD}, + {0x3646, 0x1BCC}, + {0x3648, 0xD68E}, + {0x3680, 0x1BF0}, + {0x3682, 0xC94D}, + {0x3684, 0x714F}, + {0x3686, 0x1491}, + {0x3688, 0xB8D3}, + {0x36C0, 0x3E49}, + {0x36C2, 0x7A6C}, + {0x36C4, 0xEF2E}, + {0x36C6, 0xE0EE}, + {0x36C8, 0x570F}, + {0x3700, 0xD6AF}, + {0x3702, 0x2251}, + {0x3704, 0x8A33}, + {0x3706, 0xEFB3}, + {0x3708, 0x1174}, + {0x3614, 0x0150}, + {0x3616, 0xA9AB}, + {0x3618, 0x1770}, + {0x361A, 0x8809}, + {0x361C, 0xE3AE}, + {0x3654, 0x5ACC}, + {0x3656, 0x35EA}, + {0x3658, 0x2DEC}, + {0x365A, 0xB90B}, + {0x365C, 0x250C}, + {0x3694, 0x1630}, + {0x3696, 0xD88C}, + {0x3698, 0xBD0E}, + {0x369A, 0x16D1}, + {0x369C, 0xE492}, + {0x36D4, 0x5D6D}, + {0x36D6, 0x906E}, + {0x36D8, 0x10AE}, + {0x36DA, 0x7A8E}, + {0x36DC, 0x9672}, + {0x3714, 0x8D90}, + {0x3716, 0x04F1}, + {0x3718, 0x23F1}, + {0x371A, 0xF313}, + {0x371C, 0xE833}, + {0x361E, 0x0490}, + {0x3620, 0x14CD}, + {0x3622, 0x38F0}, + {0x3624, 0xBAED}, + {0x3626, 0xFF6F}, + {0x365E, 0x358C}, + {0x3660, 0xA9E9}, + {0x3662, 0x4A4E}, + {0x3664, 0x398D}, + {0x3666, 0x890F}, + {0x369E, 0x2DF0}, + {0x36A0, 0xF7CE}, + {0x36A2, 0xB3CC}, + {0x36A4, 0x118D}, + {0x36A6, 0x9CB3}, + {0x36DE, 0x462D}, + {0x36E0, 0x74AA}, + {0x36E2, 0xC8CF}, + {0x36E4, 0x8DEF}, + {0x36E6, 0xF130}, + {0x371E, 0x9250}, + {0x3720, 0x19CC}, + {0x3722, 0xDFD1}, + {0x3724, 0x5B70}, + {0x3726, 0x34D2}, + {0x3782, 0x0530}, + {0x3784, 0x03C8}, + {0x3780, 0x8000}, +}; + +struct mt9p012_reg mt9p012_regs = { + .reg_pat = &mt9p012_reg_pat[0], + .reg_pat_size = ARRAY_SIZE(mt9p012_reg_pat), + .ttbl = &mt9p012_test_tbl[0], + .ttbl_size = ARRAY_SIZE(mt9p012_test_tbl), + .rftbl = &mt9p012_rolloff_tbl[0], + .rftbl_size = ARRAY_SIZE(mt9p012_rolloff_tbl) +}; diff --git a/drivers/media/video/msm_zsl/mt9t013.c b/drivers/media/video/msm_zsl/mt9t013.c new file mode 100644 index 00000000000..1ca6e5e1764 --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9t013.c @@ -0,0 +1,1503 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mt9t013.h" + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ +#define MT9T013_REG_MODEL_ID 0x0000 +#define MT9T013_MODEL_ID 0x2600 +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD 0x0100 +#define GROUPED_PARAMETER_UPDATE 0x0000 +#define REG_COARSE_INT_TIME 0x3012 +#define REG_VT_PIX_CLK_DIV 0x0300 +#define REG_VT_SYS_CLK_DIV 0x0302 +#define REG_PRE_PLL_CLK_DIV 0x0304 +#define REG_PLL_MULTIPLIER 0x0306 +#define REG_OP_PIX_CLK_DIV 0x0308 +#define REG_OP_SYS_CLK_DIV 0x030A +#define REG_SCALE_M 0x0404 +#define REG_FRAME_LENGTH_LINES 0x300A +#define REG_LINE_LENGTH_PCK 0x300C +#define REG_X_ADDR_START 0x3004 +#define REG_Y_ADDR_START 0x3002 +#define REG_X_ADDR_END 0x3008 +#define REG_Y_ADDR_END 0x3006 +#define REG_X_OUTPUT_SIZE 0x034C +#define REG_Y_OUTPUT_SIZE 0x034E +#define REG_FINE_INT_TIME 0x3014 +#define REG_ROW_SPEED 0x3016 +#define MT9T013_REG_RESET_REGISTER 0x301A +#define MT9T013_RESET_REGISTER_PWON 0x10CC +#define MT9T013_RESET_REGISTER_PWOFF 0x1008 /* 0x10C8 stop streaming*/ +#define MT9T013_RESET_FAST_TRANSITION 0x0002 +#define REG_READ_MODE 0x3040 +#define REG_GLOBAL_GAIN 0x305E +#define REG_TEST_PATTERN_MODE 0x3070 + + +enum mt9t013_test_mode { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum mt9t013_resolution { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; + +enum mt9t013_reg_update { + REG_INIT, /* registers that need to be updated during initialization */ + UPDATE_PERIODIC, /* registers that needs periodic I2C writes */ + UPDATE_ALL, /* all registers will be updated */ + UPDATE_INVALID +}; + +enum mt9t013_setting { + RES_PREVIEW, + RES_CAPTURE +}; + +/* actuator's Slave Address */ +#define MT9T013_AF_I2C_ADDR 0x18 + +/* +* AF Total steps parameters +*/ +#define MT9T013_TOTAL_STEPS_NEAR_TO_FAR 30 + +/* + * Time in milisecs for waiting for the sensor to reset. + */ +#define MT9T013_RESET_DELAY_MSECS 66 + +/* for 30 fps preview */ +#define MT9T013_DEFAULT_CLOCK_RATE 24000000 +#define MT9T013_DEFAULT_MAX_FPS 26 + + +/* FIXME: Changes from here */ +struct mt9t013_work { + struct work_struct work; +}; + +static struct mt9t013_work *mt9t013_sensorw; +static struct i2c_client *mt9t013_client; + +struct mt9t013_ctrl { + const struct msm_camera_sensor_info *sensordata; + + int sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + + uint16_t curr_lens_pos; + uint16_t init_curr_lens_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + + enum mt9t013_resolution prev_res; + enum mt9t013_resolution pict_res; + enum mt9t013_resolution curr_res; + enum mt9t013_test_mode set_test; + + unsigned short imgaddr; +}; + + +static struct mt9t013_ctrl *mt9t013_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(mt9t013_wait_queue); +DEFINE_SEMAPHORE(mt9t013_sem); + +static int mt9t013_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + + if (i2c_transfer(mt9t013_client->adapter, msgs, 2) < 0) { + pr_err("mt9t013_i2c_rxdata failed!\n"); + return -EIO; + } + + return 0; +} + +static int32_t mt9t013_i2c_read_w(unsigned short saddr, + unsigned short raddr, unsigned short *rdata) +{ + int32_t rc = 0; + unsigned char buf[4]; + + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + + buf[0] = (raddr & 0xFF00)>>8; + buf[1] = (raddr & 0x00FF); + + rc = mt9t013_i2c_rxdata(saddr, buf, 2); + if (rc < 0) + return rc; + + *rdata = buf[0] << 8 | buf[1]; + + if (rc < 0) + pr_err("mt9t013_i2c_read failed!\n"); + + return rc; +} + +static int32_t mt9t013_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + if (i2c_transfer(mt9t013_client->adapter, msg, 1) < 0) { + pr_err("mt9t013_i2c_txdata failed\n"); + return -EIO; + } + + return 0; +} + +static int32_t mt9t013_i2c_write_b(unsigned short saddr, + unsigned short waddr, unsigned short wdata) +{ + int32_t rc = -EIO; + unsigned char buf[2]; + + memset(buf, 0, sizeof(buf)); + buf[0] = waddr; + buf[1] = wdata; + rc = mt9t013_i2c_txdata(saddr, buf, 2); + + if (rc < 0) + pr_err("i2c_write failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + + return rc; +} + +static int32_t mt9t013_i2c_write_w(unsigned short saddr, + unsigned short waddr, unsigned short wdata) +{ + int32_t rc = -EIO; + unsigned char buf[4]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00)>>8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00)>>8; + buf[3] = (wdata & 0x00FF); + + rc = mt9t013_i2c_txdata(saddr, buf, 4); + + if (rc < 0) + pr_err("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + + return rc; +} + +static int32_t mt9t013_i2c_write_w_table( + struct mt9t013_i2c_reg_conf const *reg_conf_tbl, + int num_of_items_in_table) +{ + int i; + int32_t rc = -EIO; + + for (i = 0; i < num_of_items_in_table; i++) { + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + reg_conf_tbl->waddr, reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + + return rc; +} + +static int32_t mt9t013_test(enum mt9t013_test_mode mo) +{ + int32_t rc = 0; + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + if (mo == TEST_OFF) + return 0; + else { + rc = mt9t013_i2c_write_w_table(mt9t013_regs.ttbl, + mt9t013_regs.ttbl_size); + if (rc < 0) + return rc; + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_TEST_PATTERN_MODE, (uint16_t)mo); + if (rc < 0) + return rc; + } + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t mt9t013_set_lc(void) +{ + int32_t rc; + + rc = mt9t013_i2c_write_w_table(mt9t013_regs.lctbl, + mt9t013_regs.lctbl_size); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t mt9t013_set_default_focus(uint8_t af_step) +{ + int32_t rc = 0; + uint8_t code_val_msb, code_val_lsb; + code_val_msb = 0x01; + code_val_lsb = af_step; + + /* Write the digital code for current to the actuator */ + rc = mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1, + code_val_msb, code_val_lsb); + + mt9t013_ctrl->curr_lens_pos = 0; + mt9t013_ctrl->init_curr_lens_pos = 0; + return rc; +} + +static void mt9t013_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint32_t divider; /*Q10 */ + uint32_t pclk_mult; /*Q10 */ + uint32_t d1; + uint32_t d2; + + d1 = + (uint32_t)( + (mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines * + 0x00000400) / + mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines); + + d2 = + (uint32_t)( + (mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck * + 0x00000400) / + mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck); + + divider = (uint32_t) (d1 * d2) / 0x00000400; + + pclk_mult = + (uint32_t) ((mt9t013_regs.reg_pat[RES_CAPTURE].pll_multiplier * + 0x00000400) / + (mt9t013_regs.reg_pat[RES_PREVIEW].pll_multiplier)); + + + /* Verify PCLK settings and frame sizes. */ + *pfps = + (uint16_t) (fps * divider * pclk_mult / + 0x00000400 / 0x00000400); +} + +static uint16_t mt9t013_get_prev_lines_pf(void) +{ + if (mt9t013_ctrl->prev_res == QTR_SIZE) + return mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines; + else + return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines; +} + +static uint16_t mt9t013_get_prev_pixels_pl(void) +{ + if (mt9t013_ctrl->prev_res == QTR_SIZE) + return mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck; + else + return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck; +} + +static uint16_t mt9t013_get_pict_lines_pf(void) +{ + return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines; +} + +static uint16_t mt9t013_get_pict_pixels_pl(void) +{ + return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck; +} + +static uint32_t mt9t013_get_pict_max_exp_lc(void) +{ + uint16_t snapshot_lines_per_frame; + + if (mt9t013_ctrl->pict_res == QTR_SIZE) { + snapshot_lines_per_frame = + mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1; + } else { + snapshot_lines_per_frame = + mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1; + } + + return snapshot_lines_per_frame * 24; +} + +static int32_t mt9t013_set_fps(struct fps_cfg *fps) +{ + /* input is new fps in Q8 format */ + int32_t rc = 0; + enum mt9t013_setting setting; + + mt9t013_ctrl->fps_divider = fps->fps_div; + mt9t013_ctrl->pict_fps_divider = fps->pict_fps_div; + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return -EBUSY; + + CDBG("mt9t013_set_fps: fps_div is %d, f_mult is %d\n", + fps->fps_div, fps->f_mult); + + if (mt9t013_ctrl->sensormode == SENSOR_PREVIEW_MODE) + setting = RES_PREVIEW; + else + setting = RES_CAPTURE; + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_FRAME_LENGTH_LINES, + (uint16_t) ( + mt9t013_regs.reg_pat[setting].frame_length_lines * + fps->fps_div / 0x00000400)); + + if (rc < 0) + return rc; + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t mt9t013_write_exp_gain(uint16_t gain, uint32_t line) +{ + uint16_t max_legal_gain = 0x01FF; + int32_t rc = 0; + + if (mt9t013_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + mt9t013_ctrl->my_reg_gain = gain; + mt9t013_ctrl->my_reg_line_count = (uint16_t) line; + } + + if (gain > max_legal_gain) + gain = max_legal_gain; + + if (mt9t013_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) + line = (uint32_t) (line * mt9t013_ctrl->fps_divider / + 0x00000400); + else + line = (uint32_t) (line * mt9t013_ctrl->pict_fps_divider / + 0x00000400); + + /*Set digital gain to 1 */ + gain |= 0x0200; + + /* There used to be PARAMETER_HOLD register write before and + * after REG_GLOBAL_GAIN & REG_COARSE_INIT_TIME. This causes + * aec oscillation. Hence removed. */ + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, REG_GLOBAL_GAIN, gain); + if (rc < 0) + return rc; + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_COARSE_INT_TIME, line); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t mt9t013_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + + rc = mt9t013_write_exp_gain(gain, line); + if (rc < 0) + return rc; + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + MT9T013_REG_RESET_REGISTER, + 0x10CC | 0x0002); + + mdelay(5); + + return rc; +} + +static int32_t mt9t013_setting(enum mt9t013_reg_update rupdate, + enum mt9t013_setting rt) +{ + int32_t rc = 0; + + switch (rupdate) { + case UPDATE_PERIODIC: { + + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { +#if 0 + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + MT9T013_REG_RESET_REGISTER, + MT9T013_RESET_REGISTER_PWOFF); + if (rc < 0) + return rc; +#endif + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_VT_PIX_CLK_DIV, + mt9t013_regs.reg_pat[rt].vt_pix_clk_div); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_VT_SYS_CLK_DIV, + mt9t013_regs.reg_pat[rt].vt_sys_clk_div); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_PRE_PLL_CLK_DIV, + mt9t013_regs.reg_pat[rt].pre_pll_clk_div); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_PLL_MULTIPLIER, + mt9t013_regs.reg_pat[rt].pll_multiplier); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_OP_PIX_CLK_DIV, + mt9t013_regs.reg_pat[rt].op_pix_clk_div); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_OP_SYS_CLK_DIV, + mt9t013_regs.reg_pat[rt].op_sys_clk_div); + if (rc < 0) + return rc; + + mdelay(5); + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_ROW_SPEED, + mt9t013_regs.reg_pat[rt].row_speed); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_X_ADDR_START, + mt9t013_regs.reg_pat[rt].x_addr_start); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_X_ADDR_END, + mt9t013_regs.reg_pat[rt].x_addr_end); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_Y_ADDR_START, + mt9t013_regs.reg_pat[rt].y_addr_start); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_Y_ADDR_END, + mt9t013_regs.reg_pat[rt].y_addr_end); + if (rc < 0) + return rc; + + if (machine_is_sapphire()) { + if (rt == 0) + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_READ_MODE, + 0x046F); + else + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_READ_MODE, + 0x0027); + } else + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_READ_MODE, + mt9t013_regs.reg_pat[rt].read_mode); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_SCALE_M, + mt9t013_regs.reg_pat[rt].scale_m); + if (rc < 0) + return rc; + + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_X_OUTPUT_SIZE, + mt9t013_regs.reg_pat[rt].x_output_size); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_Y_OUTPUT_SIZE, + mt9t013_regs.reg_pat[rt].y_output_size); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_LINE_LENGTH_PCK, + mt9t013_regs.reg_pat[rt].line_length_pck); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_FRAME_LENGTH_LINES, + (mt9t013_regs.reg_pat[rt].frame_length_lines * + mt9t013_ctrl->fps_divider / 0x00000400)); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_COARSE_INT_TIME, + mt9t013_regs.reg_pat[rt].coarse_int_time); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_FINE_INT_TIME, + mt9t013_regs.reg_pat[rt].fine_int_time); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + if (rc < 0) + return rc; + + rc = mt9t013_test(mt9t013_ctrl->set_test); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + MT9T013_REG_RESET_REGISTER, + MT9T013_RESET_REGISTER_PWON| + MT9T013_RESET_FAST_TRANSITION); + if (rc < 0) + return rc; + + mdelay(5); + + return rc; + } + } + break; + + /*CAMSENSOR_REG_UPDATE_PERIODIC */ + case REG_INIT: { + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + MT9T013_REG_RESET_REGISTER, + MT9T013_RESET_REGISTER_PWOFF); + if (rc < 0) + /* MODE_SELECT, stop streaming */ + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_VT_PIX_CLK_DIV, + mt9t013_regs.reg_pat[rt].vt_pix_clk_div); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_VT_SYS_CLK_DIV, + mt9t013_regs.reg_pat[rt].vt_sys_clk_div); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_PRE_PLL_CLK_DIV, + mt9t013_regs.reg_pat[rt].pre_pll_clk_div); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_PLL_MULTIPLIER, + mt9t013_regs.reg_pat[rt].pll_multiplier); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_OP_PIX_CLK_DIV, + mt9t013_regs.reg_pat[rt].op_pix_clk_div); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_OP_SYS_CLK_DIV, + mt9t013_regs.reg_pat[rt].op_sys_clk_div); + if (rc < 0) + return rc; + + mdelay(5); + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + /* additional power saving mode ok around 38.2MHz */ + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + 0x3084, 0x2409); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + 0x3092, 0x0A49); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + 0x3094, 0x4949); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + 0x3096, 0x4949); + if (rc < 0) + return rc; + + /* Set preview or snapshot mode */ + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_ROW_SPEED, + mt9t013_regs.reg_pat[rt].row_speed); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_X_ADDR_START, + mt9t013_regs.reg_pat[rt].x_addr_start); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_X_ADDR_END, + mt9t013_regs.reg_pat[rt].x_addr_end); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_Y_ADDR_START, + mt9t013_regs.reg_pat[rt].y_addr_start); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_Y_ADDR_END, + mt9t013_regs.reg_pat[rt].y_addr_end); + if (rc < 0) + return rc; + + if (machine_is_sapphire()) { + if (rt == 0) + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_READ_MODE, + 0x046F); + else + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_READ_MODE, + 0x0027); + } else + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_READ_MODE, + mt9t013_regs.reg_pat[rt].read_mode); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_SCALE_M, + mt9t013_regs.reg_pat[rt].scale_m); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_X_OUTPUT_SIZE, + mt9t013_regs.reg_pat[rt].x_output_size); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_Y_OUTPUT_SIZE, + mt9t013_regs.reg_pat[rt].y_output_size); + if (rc < 0) + return 0; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_LINE_LENGTH_PCK, + mt9t013_regs.reg_pat[rt].line_length_pck); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_FRAME_LENGTH_LINES, + mt9t013_regs.reg_pat[rt].frame_length_lines); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_COARSE_INT_TIME, + mt9t013_regs.reg_pat[rt].coarse_int_time); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_FINE_INT_TIME, + mt9t013_regs.reg_pat[rt].fine_int_time); + if (rc < 0) + return rc; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + if (rc < 0) + return rc; + + /* load lens shading */ + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + /* most likely needs to be written only once. */ + rc = mt9t013_set_lc(); + if (rc < 0) + return -EBUSY; + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + if (rc < 0) + return rc; + + rc = mt9t013_test(mt9t013_ctrl->set_test); + if (rc < 0) + return rc; + + mdelay(5); + + rc = + mt9t013_i2c_write_w(mt9t013_client->addr, + MT9T013_REG_RESET_REGISTER, + MT9T013_RESET_REGISTER_PWON); + if (rc < 0) + /* MODE_SELECT, stop streaming */ + return rc; + + CDBG("!!! mt9t013 !!! PowerOn is done!\n"); + mdelay(5); + return rc; + } + } /* case CAMSENSOR_REG_INIT: */ + break; + + /*CAMSENSOR_REG_INIT */ + default: + rc = -EINVAL; + break; + } /* switch (rupdate) */ + + return rc; +} + +static int32_t mt9t013_video_config(int mode, int res) +{ + int32_t rc; + + switch (res) { + case QTR_SIZE: + rc = mt9t013_setting(UPDATE_PERIODIC, RES_PREVIEW); + if (rc < 0) + return rc; + CDBG("sensor configuration done!\n"); + break; + + case FULL_SIZE: + rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + break; + + default: + return -EINVAL; + } /* switch */ + + mt9t013_ctrl->prev_res = res; + mt9t013_ctrl->curr_res = res; + mt9t013_ctrl->sensormode = mode; + + rc = mt9t013_write_exp_gain(mt9t013_ctrl->my_reg_gain, + mt9t013_ctrl->my_reg_line_count); + if (rc < 0) + return rc; + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + MT9T013_REG_RESET_REGISTER, + MT9T013_RESET_REGISTER_PWON|MT9T013_RESET_FAST_TRANSITION); + if (rc < 0) + return rc; + + msleep(5); + return rc; +} + +static int32_t mt9t013_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res; + mt9t013_ctrl->sensormode = mode; + return rc; +} + +static int32_t mt9t013_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE); + if (rc < 0) + return rc; + + mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res; + mt9t013_ctrl->sensormode = mode; + return rc; +} + +static int32_t mt9t013_power_down(void) +{ + int32_t rc = 0; + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + MT9T013_REG_RESET_REGISTER, + MT9T013_RESET_REGISTER_PWOFF); + if (rc >= 0) + mdelay(5); + return rc; +} + +static int32_t mt9t013_move_focus(int direction, int32_t num_steps) +{ + int16_t step_direction; + int16_t actual_step; + int16_t next_position; + int16_t break_steps[4]; + uint8_t code_val_msb, code_val_lsb; + int16_t i; + + if (num_steps > MT9T013_TOTAL_STEPS_NEAR_TO_FAR) + num_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR; + else if (num_steps == 0) + return -EINVAL; + + if (direction == MOVE_NEAR) + step_direction = 4; + else if (direction == MOVE_FAR) + step_direction = -4; + else + return -EINVAL; + + if (mt9t013_ctrl->curr_lens_pos < mt9t013_ctrl->init_curr_lens_pos) + mt9t013_ctrl->curr_lens_pos = mt9t013_ctrl->init_curr_lens_pos; + + actual_step = + (int16_t) (step_direction * + (int16_t) num_steps); + + for (i = 0; i < 4; i++) + break_steps[i] = + actual_step / 4 * (i + 1) - actual_step / 4 * i; + + for (i = 0; i < 4; i++) { + next_position = + (int16_t) + (mt9t013_ctrl->curr_lens_pos + break_steps[i]); + + if (next_position > 255) + next_position = 255; + else if (next_position < 0) + next_position = 0; + + code_val_msb = + ((next_position >> 4) << 2) | + ((next_position << 4) >> 6); + + code_val_lsb = + ((next_position & 0x03) << 6); + + /* Writing the digital code for current to the actuator */ + if (mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1, + code_val_msb, code_val_lsb) < 0) + return -EBUSY; + + /* Storing the current lens Position */ + mt9t013_ctrl->curr_lens_pos = next_position; + + if (i < 3) + mdelay(1); + } /* for */ + + return 0; +} + +static int mt9t013_sensor_init_done(const struct msm_camera_sensor_info *data) +{ + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + return 0; +} + +static int mt9t013_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int rc; + uint16_t chipid; + + rc = gpio_request(data->sensor_reset, "mt9t013"); + if (!rc) + gpio_direction_output(data->sensor_reset, 1); + else + goto init_probe_done; + + mdelay(20); + + /* RESET the sensor image part via I2C command */ + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + MT9T013_REG_RESET_REGISTER, 0x1009); + if (rc < 0) + goto init_probe_fail; + + msleep(10); + + /* 3. Read sensor Model ID: */ + rc = mt9t013_i2c_read_w(mt9t013_client->addr, + MT9T013_REG_MODEL_ID, &chipid); + + if (rc < 0) + goto init_probe_fail; + + CDBG("mt9t013 model_id = 0x%x\n", chipid); + + /* 4. Compare sensor ID to MT9T012VC ID: */ + if (chipid != MT9T013_MODEL_ID) { + rc = -ENODEV; + goto init_probe_fail; + } + + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + 0x3064, 0x0805); + if (rc < 0) + goto init_probe_fail; + + mdelay(MT9T013_RESET_DELAY_MSECS); + + goto init_probe_done; + + /* sensor: output enable */ +#if 0 + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + MT9T013_REG_RESET_REGISTER, + MT9T013_RESET_REGISTER_PWON); + + /* if this fails, the sensor is not the MT9T013 */ + rc = mt9t013_set_default_focus(0); +#endif + +init_probe_fail: + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); +init_probe_done: + return rc; +} + +static int32_t mt9t013_poweron_af(void) +{ + int32_t rc = 0; + + /* enable AF actuator */ + CDBG("enable AF actuator, gpio = %d\n", + mt9t013_ctrl->sensordata->vcm_pwd); + rc = gpio_request(mt9t013_ctrl->sensordata->vcm_pwd, "mt9t013"); + if (!rc) { + gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 0); + mdelay(20); + rc = mt9t013_set_default_focus(0); + } else + pr_err("%s, gpio_request failed (%d)!\n", __func__, rc); + return rc; +} + +static void mt9t013_poweroff_af(void) +{ + gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 1); + gpio_free(mt9t013_ctrl->sensordata->vcm_pwd); +} + +int mt9t013_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + + mt9t013_ctrl = kzalloc(sizeof(struct mt9t013_ctrl), GFP_KERNEL); + if (!mt9t013_ctrl) { + pr_err("mt9t013_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + mt9t013_ctrl->fps_divider = 1 * 0x00000400; + mt9t013_ctrl->pict_fps_divider = 1 * 0x00000400; + mt9t013_ctrl->set_test = TEST_OFF; + mt9t013_ctrl->prev_res = QTR_SIZE; + mt9t013_ctrl->pict_res = FULL_SIZE; + + if (data) + mt9t013_ctrl->sensordata = data; + + /* enable mclk first */ + msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE); + mdelay(20); + + msm_camio_camif_pad_reg_reset(); + mdelay(20); + + rc = mt9t013_probe_init_sensor(data); + if (rc < 0) + goto init_fail; + + if (mt9t013_ctrl->prev_res == QTR_SIZE) + rc = mt9t013_setting(REG_INIT, RES_PREVIEW); + else + rc = mt9t013_setting(REG_INIT, RES_CAPTURE); + + if (rc >= 0) + if (machine_is_sapphire()) + rc = mt9t013_poweron_af(); + + if (rc < 0) + goto init_fail; + else + goto init_done; + +init_fail: + kfree(mt9t013_ctrl); +init_done: + return rc; +} + +static int mt9t013_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&mt9t013_wait_queue); + return 0; +} + + +static int32_t mt9t013_set_sensor_mode(int mode, int res) +{ + int32_t rc = 0; + rc = mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (rc < 0) + return rc; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = mt9t013_video_config(mode, res); + break; + + case SENSOR_SNAPSHOT_MODE: + rc = mt9t013_snapshot_config(mode); + break; + + case SENSOR_RAW_SNAPSHOT_MODE: + rc = mt9t013_raw_snapshot_config(mode); + break; + + default: + return -EINVAL; + } + + /* FIXME: what should we do if rc < 0? */ + if (rc >= 0) + return mt9t013_i2c_write_w(mt9t013_client->addr, + REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_UPDATE); + return rc; +} + +int mt9t013_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + + if (copy_from_user(&cdata, (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + down(&mt9t013_sem); + + CDBG("mt9t013_sensor_config: cfgtype = %d\n", cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + mt9t013_get_pict_fps(cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = mt9t013_get_prev_lines_pf(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = mt9t013_get_prev_pixels_pl(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = mt9t013_get_pict_lines_pf(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + mt9t013_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + mt9t013_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = mt9t013_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = mt9t013_write_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + rc = mt9t013_set_pict_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = mt9t013_set_sensor_mode(cdata.mode, cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = mt9t013_power_down(); + break; + + case CFG_MOVE_FOCUS: + rc = mt9t013_move_focus(cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = mt9t013_set_default_focus(cdata.cfg.focus.steps); + break; + + case CFG_GET_AF_MAX_STEPS: + cdata.max_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR; + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_EFFECT: + default: + rc = -EINVAL; + break; + } + + up(&mt9t013_sem); + return rc; +} + +int mt9t013_sensor_release(void) +{ + int rc = -EBADF; + + down(&mt9t013_sem); + + if (machine_is_sapphire()) + mt9t013_poweroff_af(); + mt9t013_power_down(); + + gpio_direction_output(mt9t013_ctrl->sensordata->sensor_reset, + 0); + gpio_free(mt9t013_ctrl->sensordata->sensor_reset); + + kfree(mt9t013_ctrl); + + up(&mt9t013_sem); + CDBG("mt9t013_release completed!\n"); + return rc; +} + +static int mt9t013_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + rc = -ENOTSUPP; + goto probe_failure; + } + + mt9t013_sensorw = + kzalloc(sizeof(struct mt9t013_work), GFP_KERNEL); + + if (!mt9t013_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, mt9t013_sensorw); + mt9t013_init_client(client); + mt9t013_client = client; + mt9t013_client->addr = mt9t013_client->addr >> 1; + mdelay(50); + + CDBG("i2c probe ok\n"); + return 0; + +probe_failure: + kfree(mt9t013_sensorw); + mt9t013_sensorw = NULL; + pr_err("i2c probe failure %d\n", rc); + return rc; +} + +static const struct i2c_device_id mt9t013_i2c_id[] = { + { "mt9t013", 0}, + { } +}; + +static struct i2c_driver mt9t013_i2c_driver = { + .id_table = mt9t013_i2c_id, + .probe = mt9t013_i2c_probe, + .remove = __exit_p(mt9t013_i2c_remove), + .driver = { + .name = "mt9t013", + }, +}; + +static int mt9t013_sensor_probe( + const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + /* We expect this driver to match with the i2c device registered + * in the board file immediately. */ + int rc = i2c_add_driver(&mt9t013_i2c_driver); + if (rc < 0 || mt9t013_client == NULL) { + rc = -ENOTSUPP; + goto probe_done; + } + + /* enable mclk first */ + msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE); + mdelay(20); + + rc = mt9t013_probe_init_sensor(info); + if (rc < 0) { + i2c_del_driver(&mt9t013_i2c_driver); + goto probe_done; + } + + s->s_init = mt9t013_sensor_open_init; + s->s_release = mt9t013_sensor_release; + s->s_config = mt9t013_sensor_config; + s->s_mount_angle = 0; + mt9t013_sensor_init_done(info); + +probe_done: + return rc; +} + +static int __mt9t013_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, mt9t013_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __mt9t013_probe, + .driver = { + .name = "msm_camera_mt9t013", + .owner = THIS_MODULE, + }, +}; + +static int __init mt9t013_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(mt9t013_init); diff --git a/drivers/media/video/msm_zsl/mt9t013.h b/drivers/media/video/msm_zsl/mt9t013.h new file mode 100644 index 00000000000..804a90ce268 --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9t013.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef MT9T013_H +#define MT9T013_H + +#include + +extern struct mt9t013_reg mt9t013_regs; /* from mt9t013_reg.c */ + +struct reg_struct { + uint16_t vt_pix_clk_div; /* 0x0300 */ + uint16_t vt_sys_clk_div; /* 0x0302 */ + uint16_t pre_pll_clk_div; /* 0x0304 */ + uint16_t pll_multiplier; /* 0x0306 */ + uint16_t op_pix_clk_div; /* 0x0308 */ + uint16_t op_sys_clk_div; /* 0x030A */ + uint16_t scale_m; /* 0x0404 */ + uint16_t row_speed; /* 0x3016 */ + uint16_t x_addr_start; /* 0x3004 */ + uint16_t x_addr_end; /* 0x3008 */ + uint16_t y_addr_start; /* 0x3002 */ + uint16_t y_addr_end; /* 0x3006 */ + uint16_t read_mode; /* 0x3040 */ + uint16_t x_output_size; /* 0x034C */ + uint16_t y_output_size; /* 0x034E */ + uint16_t line_length_pck; /* 0x300C */ + uint16_t frame_length_lines; /* 0x300A */ + uint16_t coarse_int_time; /* 0x3012 */ + uint16_t fine_int_time; /* 0x3014 */ +}; + +struct mt9t013_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +struct mt9t013_reg { + struct reg_struct const *reg_pat; + uint16_t reg_pat_size; + struct mt9t013_i2c_reg_conf const *ttbl; + uint16_t ttbl_size; + struct mt9t013_i2c_reg_conf const *lctbl; + uint16_t lctbl_size; + struct mt9t013_i2c_reg_conf const *rftbl; + uint16_t rftbl_size; +}; + +#endif /* #define MT9T013_H */ diff --git a/drivers/media/video/msm_zsl/mt9t013_reg.c b/drivers/media/video/msm_zsl/mt9t013_reg.c new file mode 100644 index 00000000000..cb389a53d7b --- /dev/null +++ b/drivers/media/video/msm_zsl/mt9t013_reg.c @@ -0,0 +1,273 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "mt9t013.h" +#include + +struct reg_struct const mt9t013_reg_pat[2] = { + { /* Preview 2x2 binning 20fps, pclk MHz, MCLK 24MHz */ + /* vt_pix_clk_div:REG=0x0300 update get_snapshot_fps + * if this change */ + 8, + + /* vt_sys_clk_div: REG=0x0302 update get_snapshot_fps + * if this change */ + 1, + + /* pre_pll_clk_div REG=0x0304 update get_snapshot_fps + * if this change */ + 2, + + /* pll_multiplier REG=0x0306 60 for 30fps preview, 40 + * for 20fps preview + * 46 for 30fps preview, try 47/48 to increase further */ + 46, + + /* op_pix_clk_div REG=0x0308 */ + 8, + + /* op_sys_clk_div REG=0x030A */ + 1, + + /* scale_m REG=0x0404 */ + 16, + + /* row_speed REG=0x3016 */ + 0x0111, + + /* x_addr_start REG=0x3004 */ + 8, + + /* x_addr_end REG=0x3008 */ + 2053, + + /* y_addr_start REG=0x3002 */ + 8, + + /* y_addr_end REG=0x3006 */ + 1541, + + /* read_mode REG=0x3040 */ + 0x046C, + + /* x_output_size REG=0x034C */ + 1024, + + /* y_output_size REG=0x034E */ + 768, + + /* line_length_pck REG=0x300C */ + 2616, + + /* frame_length_lines REG=0x300A */ + 916, + + /* coarse_int_time REG=0x3012 */ + 16, + + /* fine_int_time REG=0x3014 */ + 1461 + }, + { /*Snapshot */ + /* vt_pix_clk_div REG=0x0300 update get_snapshot_fps + * if this change */ + 8, + + /* vt_sys_clk_div REG=0x0302 update get_snapshot_fps + * if this change */ + 1, + + /* pre_pll_clk_div REG=0x0304 update get_snapshot_fps + * if this change */ + 2, + + /* pll_multiplier REG=0x0306 50 for 15fps snapshot, + * 40 for 10fps snapshot + * 46 for 30fps snapshot, try 47/48 to increase further */ + 46, + + /* op_pix_clk_div REG=0x0308 */ + 8, + + /* op_sys_clk_div REG=0x030A */ + 1, + + /* scale_m REG=0x0404 */ + 16, + + /* row_speed REG=0x3016 */ + 0x0111, + + /* x_addr_start REG=0x3004 */ + 8, + + /* x_addr_end REG=0x3008 */ + 2071, + + /* y_addr_start REG=0x3002 */ + 8, + + /* y_addr_end REG=0x3006 */ + 1551, + + /* read_mode REG=0x3040 */ + 0x0024, + + /* x_output_size REG=0x034C */ + 2064, + + /* y_output_size REG=0x034E */ + 1544, + + /* line_length_pck REG=0x300C */ + 2952, + + /* frame_length_lines REG=0x300A */ + 1629, + + /* coarse_int_time REG=0x3012 */ + 16, + + /* fine_int_time REG=0x3014 */ + 733 + } +}; + +struct mt9t013_i2c_reg_conf const mt9t013_test_tbl[] = { + { 0x3044, 0x0544 & 0xFBFF }, + { 0x30CA, 0x0004 | 0x0001 }, + { 0x30D4, 0x9020 & 0x7FFF }, + { 0x31E0, 0x0003 & 0xFFFE }, + { 0x3180, 0x91FF & 0x7FFF }, + { 0x301A, (0x10CC | 0x8000) & 0xFFF7 }, + { 0x301E, 0x0000 }, + { 0x3780, 0x0000 }, +}; + +/* [Lens shading 85 Percent TL84] */ +struct mt9t013_i2c_reg_conf const mt9t013_lc_tbl[] = { + { 0x360A, 0x0290 }, /* P_RD_P0Q0 */ + { 0x360C, 0xC92D }, /* P_RD_P0Q1 */ + { 0x360E, 0x0771 }, /* P_RD_P0Q2 */ + { 0x3610, 0xE38C }, /* P_RD_P0Q3 */ + { 0x3612, 0xD74F }, /* P_RD_P0Q4 */ + { 0x364A, 0x168C }, /* P_RD_P1Q0 */ + { 0x364C, 0xCACB }, /* P_RD_P1Q1 */ + { 0x364E, 0x8C4C }, /* P_RD_P1Q2 */ + { 0x3650, 0x0BEA }, /* P_RD_P1Q3 */ + { 0x3652, 0xDC0F }, /* P_RD_P1Q4 */ + { 0x368A, 0x70B0 }, /* P_RD_P2Q0 */ + { 0x368C, 0x200B }, /* P_RD_P2Q1 */ + { 0x368E, 0x30B2 }, /* P_RD_P2Q2 */ + { 0x3690, 0xD04F }, /* P_RD_P2Q3 */ + { 0x3692, 0xACF5 }, /* P_RD_P2Q4 */ + { 0x36CA, 0xF7C9 }, /* P_RD_P3Q0 */ + { 0x36CC, 0x2AED }, /* P_RD_P3Q1 */ + { 0x36CE, 0xA652 }, /* P_RD_P3Q2 */ + { 0x36D0, 0x8192 }, /* P_RD_P3Q3 */ + { 0x36D2, 0x3A15 }, /* P_RD_P3Q4 */ + { 0x370A, 0xDA30 }, /* P_RD_P4Q0 */ + { 0x370C, 0x2E2F }, /* P_RD_P4Q1 */ + { 0x370E, 0xBB56 }, /* P_RD_P4Q2 */ + { 0x3710, 0x8195 }, /* P_RD_P4Q3 */ + { 0x3712, 0x02F9 }, /* P_RD_P4Q4 */ + { 0x3600, 0x0230 }, /* P_GR_P0Q0 */ + { 0x3602, 0x58AD }, /* P_GR_P0Q1 */ + { 0x3604, 0x18D1 }, /* P_GR_P0Q2 */ + { 0x3606, 0x260D }, /* P_GR_P0Q3 */ + { 0x3608, 0xF530 }, /* P_GR_P0Q4 */ + { 0x3640, 0x17EB }, /* P_GR_P1Q0 */ + { 0x3642, 0x3CAB }, /* P_GR_P1Q1 */ + { 0x3644, 0x87CE }, /* P_GR_P1Q2 */ + { 0x3646, 0xC02E }, /* P_GR_P1Q3 */ + { 0x3648, 0xF48F }, /* P_GR_P1Q4 */ + { 0x3680, 0x5350 }, /* P_GR_P2Q0 */ + { 0x3682, 0x7EAF }, /* P_GR_P2Q1 */ + { 0x3684, 0x4312 }, /* P_GR_P2Q2 */ + { 0x3686, 0xC652 }, /* P_GR_P2Q3 */ + { 0x3688, 0xBC15 }, /* P_GR_P2Q4 */ + { 0x36C0, 0xB8AD }, /* P_GR_P3Q0 */ + { 0x36C2, 0xBDCD }, /* P_GR_P3Q1 */ + { 0x36C4, 0xE4B2 }, /* P_GR_P3Q2 */ + { 0x36C6, 0xB50F }, /* P_GR_P3Q3 */ + { 0x36C8, 0x5B95 }, /* P_GR_P3Q4 */ + { 0x3700, 0xFC90 }, /* P_GR_P4Q0 */ + { 0x3702, 0x8C51 }, /* P_GR_P4Q1 */ + { 0x3704, 0xCED6 }, /* P_GR_P4Q2 */ + { 0x3706, 0xB594 }, /* P_GR_P4Q3 */ + { 0x3708, 0x0A39 }, /* P_GR_P4Q4 */ + { 0x3614, 0x0230 }, /* P_BL_P0Q0 */ + { 0x3616, 0x160D }, /* P_BL_P0Q1 */ + { 0x3618, 0x08D1 }, /* P_BL_P0Q2 */ + { 0x361A, 0x98AB }, /* P_BL_P0Q3 */ + { 0x361C, 0xEA50 }, /* P_BL_P0Q4 */ + { 0x3654, 0xB4EA }, /* P_BL_P1Q0 */ + { 0x3656, 0xEA6C }, /* P_BL_P1Q1 */ + { 0x3658, 0xFE08 }, /* P_BL_P1Q2 */ + { 0x365A, 0x2C6E }, /* P_BL_P1Q3 */ + { 0x365C, 0xEB0E }, /* P_BL_P1Q4 */ + { 0x3694, 0x6DF0 }, /* P_BL_P2Q0 */ + { 0x3696, 0x3ACF }, /* P_BL_P2Q1 */ + { 0x3698, 0x3E0F }, /* P_BL_P2Q2 */ + { 0x369A, 0xB2B1 }, /* P_BL_P2Q3 */ + { 0x369C, 0xC374 }, /* P_BL_P2Q4 */ + { 0x36D4, 0xF2AA }, /* P_BL_P3Q0 */ + { 0x36D6, 0x8CCC }, /* P_BL_P3Q1 */ + { 0x36D8, 0xDEF2 }, /* P_BL_P3Q2 */ + { 0x36DA, 0xFA11 }, /* P_BL_P3Q3 */ + { 0x36DC, 0x42F5 }, /* P_BL_P3Q4 */ + { 0x3714, 0xF4F1 }, /* P_BL_P4Q0 */ + { 0x3716, 0xF6F0 }, /* P_BL_P4Q1 */ + { 0x3718, 0x8FD6 }, /* P_BL_P4Q2 */ + { 0x371A, 0xEA14 }, /* P_BL_P4Q3 */ + { 0x371C, 0x6338 }, /* P_BL_P4Q4 */ + { 0x361E, 0x0350 }, /* P_GB_P0Q0 */ + { 0x3620, 0x91AE }, /* P_GB_P0Q1 */ + { 0x3622, 0x0571 }, /* P_GB_P0Q2 */ + { 0x3624, 0x100D }, /* P_GB_P0Q3 */ + { 0x3626, 0xCA70 }, /* P_GB_P0Q4 */ + { 0x365E, 0xE6CB }, /* P_GB_P1Q0 */ + { 0x3660, 0x50ED }, /* P_GB_P1Q1 */ + { 0x3662, 0x3DAE }, /* P_GB_P1Q2 */ + { 0x3664, 0xAA4F }, /* P_GB_P1Q3 */ + { 0x3666, 0xDC50 }, /* P_GB_P1Q4 */ + { 0x369E, 0x5470 }, /* P_GB_P2Q0 */ + { 0x36A0, 0x1F6E }, /* P_GB_P2Q1 */ + { 0x36A2, 0x6671 }, /* P_GB_P2Q2 */ + { 0x36A4, 0xC010 }, /* P_GB_P2Q3 */ + { 0x36A6, 0x8DF5 }, /* P_GB_P2Q4 */ + { 0x36DE, 0x0B0C }, /* P_GB_P3Q0 */ + { 0x36E0, 0x84CE }, /* P_GB_P3Q1 */ + { 0x36E2, 0x8493 }, /* P_GB_P3Q2 */ + { 0x36E4, 0xA610 }, /* P_GB_P3Q3 */ + { 0x36E6, 0x50B5 }, /* P_GB_P3Q4 */ + { 0x371E, 0x9651 }, /* P_GB_P4Q0 */ + { 0x3720, 0x1EAB }, /* P_GB_P4Q1 */ + { 0x3722, 0xAF76 }, /* P_GB_P4Q2 */ + { 0x3724, 0xE4F4 }, /* P_GB_P4Q3 */ + { 0x3726, 0x79F8 }, /* P_GB_P4Q4 */ + { 0x3782, 0x0410 }, /* POLY_ORIGIN_C */ + { 0x3784, 0x0320 }, /* POLY_ORIGIN_R */ + { 0x3780, 0x8000 } /* POLY_SC_ENABLE */ +}; + +struct mt9t013_reg mt9t013_regs = { + .reg_pat = &mt9t013_reg_pat[0], + .reg_pat_size = ARRAY_SIZE(mt9t013_reg_pat), + .ttbl = &mt9t013_test_tbl[0], + .ttbl_size = ARRAY_SIZE(mt9t013_test_tbl), + .lctbl = &mt9t013_lc_tbl[0], + .lctbl_size = ARRAY_SIZE(mt9t013_lc_tbl), + .rftbl = &mt9t013_lc_tbl[0], /* &mt9t013_rolloff_tbl[0], */ + .rftbl_size = ARRAY_SIZE(mt9t013_lc_tbl) +}; diff --git a/drivers/media/video/msm_zsl/ov5640.c b/drivers/media/video/msm_zsl/ov5640.c new file mode 100644 index 00000000000..1380bcf642a --- /dev/null +++ b/drivers/media/video/msm_zsl/ov5640.c @@ -0,0 +1,1477 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +/* #define DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ov5640.h" + +#define FALSE 0 +#define TRUE 1 + +struct ov5640_work { + struct work_struct work; +}; + +struct __ov5640_ctrl { + const struct msm_camera_sensor_info *sensordata; + int sensormode; + uint fps_divider; /* init to 1 * 0x00000400 */ + uint pict_fps_divider; /* init to 1 * 0x00000400 */ + u16 curr_step_pos; + u16 curr_lens_pos; + u16 init_curr_lens_pos; + u16 my_reg_gain; + u16 my_reg_line_count; + enum msm_s_resolution prev_res; + enum msm_s_resolution pict_res; + enum msm_s_resolution curr_res; + enum msm_s_test_mode set_test; +}; + +static DECLARE_WAIT_QUEUE_HEAD(ov5640_wait_queue); +DEFINE_MUTEX(ov5640_mutex); + +static int ov5640_pwdn_gpio; +static int ov5640_reset_gpio; +static int ov5640_driver_pwdn_gpio; +static int OV5640_CSI_CONFIG; +static struct ov5640_work *ov5640_sensorw; +static struct i2c_client *ov5640_client; +static u8 ov5640_i2c_buf[4]; +static u8 ov5640_counter; +static int16_t ov5640_effect; +static int is_autoflash; +static int effect_value; +unsigned int ov5640_SAT_U = 0x40; +unsigned int ov5640_SAT_V = 0x40; + +static struct __ov5640_ctrl *ov5640_ctrl; +static int ov5640_afinit = 1; + +struct rw_semaphore ov_leds_list_lock; +struct list_head ov_leds_list; + +static int ov5640_i2c_remove(struct i2c_client *client); +static int ov5640_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id); + +static int ov5640_i2c_txdata(u16 saddr, u8 *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + if (i2c_transfer(ov5640_client->adapter, msg, 1) < 0) + return -EIO; + else + return 0; +} + +static int ov5640_i2c_write(unsigned short saddr, unsigned int waddr, + unsigned short bdata, u8 trytimes) +{ + int rc = -EIO; + + ov5640_counter = 0; + ov5640_i2c_buf[0] = (waddr & 0xFF00) >> 8; + ov5640_i2c_buf[1] = (waddr & 0x00FF); + ov5640_i2c_buf[2] = (bdata & 0x00FF); + + while ((ov5640_counter < trytimes) && (rc != 0)) { + rc = ov5640_i2c_txdata(saddr, ov5640_i2c_buf, 3); + + if (rc < 0) { + ov5640_counter++; + CDBG("***--CAMERA i2c_write_w failed,i2c addr=0x%x," + "command addr = 0x%x, val = 0x%x,s=%d," + "rc=%d!\n", saddr, waddr, bdata, + ov5640_counter, rc); + msleep(20); + } + } + return rc; +} + +static int ov5640_i2c_rxdata(unsigned short saddr, unsigned char *rxdata, + int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + + if (i2c_transfer(ov5640_client->adapter, msgs, 2) < 0) { + CDBG("ov5640_i2c_rxdata failed!\n"); + return -EIO; + } + + return 0; +} + +static int32_t ov5640_i2c_read_byte(unsigned short saddr, + unsigned int raddr, unsigned int *rdata) +{ + int rc = 0; + unsigned char buf[2]; + + memset(buf, 0, sizeof(buf)); + + buf[0] = (raddr & 0xFF00)>>8; + buf[1] = (raddr & 0x00FF); + + rc = ov5640_i2c_rxdata(saddr, buf, 1); + if (rc < 0) { + CDBG("ov5640_i2c_read_byte failed!\n"); + return rc; + } + + *rdata = buf[0]; + + return rc; +} + +static int32_t ov5640_writepregs(struct ov5640_sensor *ptb, int32_t len) +{ + int32_t i, ret = 0; + uint32_t regv; + + for (i = 0; i < len; i++) { + if (0 == ptb[i].mask) { + ov5640_i2c_write(ov5640_client->addr, ptb[i].addr, + ptb[i].data, 10); + } else { + ov5640_i2c_read_byte(ov5640_client->addr, ptb[i].addr, + ®v); + regv &= ptb[i].mask; + regv |= (ptb[i].data & (~ptb[i].mask)); + ov5640_i2c_write(ov5640_client->addr, ptb[i].addr, + regv, 10); + } + } + return ret; +} + +static void camera_sw_power_onoff(int v) +{ + if (v == 0) { + CDBG("camera_sw_power_onoff: down\n"); + ov5640_i2c_write(ov5640_client->addr, 0x3008, 0x42, 10); + } else { + CDBG("camera_sw_power_onoff: on\n"); + ov5640_i2c_write(ov5640_client->addr, 0x3008, 0x02, 10); + } +} + +static void ov5640_power_off(void) +{ + CDBG("--CAMERA-- %s ... (Start...)\n", __func__); + gpio_set_value(ov5640_pwdn_gpio, 1); + CDBG("--CAMERA-- %s ... (End...)\n", __func__); +} + +static void ov5640_power_on(void) +{ + CDBG("--CAMERA-- %s ... (Start...)\n", __func__); + gpio_set_value(ov5640_pwdn_gpio, 0); + CDBG("--CAMERA-- %s ... (End...)\n", __func__); +} + +static void ov5640_power_reset(void) +{ + CDBG("--CAMERA-- %s ... (Start...)\n", __func__); + gpio_set_value(ov5640_reset_gpio, 1); /* reset camera reset pin */ + msleep(20); + gpio_set_value(ov5640_reset_gpio, 0); + msleep(20); + gpio_set_value(ov5640_reset_gpio, 1); + msleep(20); + + CDBG("--CAMERA-- %s ... (End...)\n", __func__); +} + +static int ov5640_probe_readID(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + u32 device_id_high = 0; + u32 device_id_low = 0; + + CDBG("--CAMERA-- %s (Start...)\n", __func__); + CDBG("--CAMERA-- %s sensor poweron,begin to read ID!\n", __func__); + + /* 0x300A ,sensor ID register */ + rc = ov5640_i2c_read_byte(ov5640_client->addr, 0x300A, + &device_id_high); + + if (rc < 0) { + CDBG("--CAMERA-- %s ok , readI2C failed, rc = 0x%x\r\n", + __func__, rc); + return rc; + } + CDBG("--CAMERA-- %s readID high byte, data = 0x%x\r\n", + __func__, device_id_high); + + /* 0x300B ,sensor ID register */ + rc = ov5640_i2c_read_byte(ov5640_client->addr, 0x300B, + &device_id_low); + if (rc < 0) { + CDBG("--CAMERA-- %s ok , readI2C failed,rc = 0x%x\r\n", + __func__, rc); + return rc; + } + + CDBG("--CAMERA-- %s readID low byte, data = 0x%x\r\n", + __func__, device_id_low); + CDBG("--CAMERA-- %s return ID :0x%x\n", __func__, + (device_id_high << 8) + device_id_low); + + /* 0x5640, ov5640 chip id */ + if ((device_id_high << 8) + device_id_low != OV5640_SENSOR_ID) { + CDBG("--CAMERA-- %s ok , device id error, should be 0x%x\r\n", + __func__, OV5640_SENSOR_ID); + return -EINVAL; + } else { + CDBG("--CAMERA-- %s ok , device id=0x%x\n", __func__, + OV5640_SENSOR_ID); + return 0; + } +} + +static int ov5640_af_setting(void) +{ + int rc = 0; + int lens = sizeof(ov5640_afinit_tbl) / sizeof(ov5640_afinit_tbl[0]); + + CDBG("--CAMERA-- ov5640_af_setting\n"); + + ov5640_i2c_write(ov5640_client->addr, 0x3000, 0x20, 10); + + rc = ov5640_i2c_txdata(ov5640_client->addr, ov5640_afinit_tbl, lens); + if (rc < 0) { + CDBG("--CAMERA-- AF_init failed\n"); + return rc; + } + + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_MAIN, 0x00, 10); + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_ACK, 0x00, 10); + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_PARA0, 0x00, 10); + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_PARA1, 0x00, 10); + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_PARA2, 0x00, 10); + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_PARA3, 0x00, 10); + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_PARA4, 0x00, 10); + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_FW_STATUS, 0x7f, 10); + ov5640_i2c_write(ov5640_client->addr, 0x3000, 0x00, 10); + + return rc; +} + +static int ov5640_set_flash_light(enum led_brightness brightness) +{ + struct led_classdev *led_cdev; + + CDBG("ov5640_set_flash_light brightness = %d\n", brightness); + + down_read(&ov_leds_list_lock); + list_for_each_entry(led_cdev, &ov_leds_list, node) { + if (!strncmp(led_cdev->name, "flashlight", 10)) + break; + } + up_read(&ov_leds_list_lock); + + if (led_cdev) { + led_brightness_set(led_cdev, brightness); + } else { + CDBG("get flashlight device failed\n"); + return -EINVAL; + } + + return 0; +} + +static int ov5640_video_config(void) +{ + int rc = 0; + + CDBG("--CAMERA-- ov5640_video_config\n"); + CDBG("--CAMERA-- preview in, is_autoflash - 0x%x\n", is_autoflash); + + /* autoflash setting */ + if (is_autoflash == 1) + ov5640_set_flash_light(LED_OFF); + + /* preview setting */ + rc = OV5640CORE_WRITEPREG(ov5640_preview_tbl); + return rc; +} + +static int ov5640_snapshot_config(void) +{ + int rc = 0; + unsigned int tmp; + + CDBG("--CAMERA-- SENSOR_SNAPSHOT_MODE\n"); + CDBG("--CAMERA-- %s, snapshot in, is_autoflash - 0x%x\n", __func__, + is_autoflash); + + if (is_autoflash == 1) { + ov5640_i2c_read_byte(ov5640_client->addr, 0x350b, &tmp); + CDBG("--CAMERA-- GAIN VALUE : %x\n", tmp); + if ((tmp & 0x80) == 0) + ov5640_set_flash_light(LED_OFF); + else + ov5640_set_flash_light(LED_FULL); + } + + rc = OV5640CORE_WRITEPREG(ov5640_capture_tbl); + + return rc; +} + +static int ov5640_setting(enum msm_s_reg_update rupdate, + enum msm_s_setting rt) +{ + int rc = -EINVAL, tmp; + struct msm_camera_csi_params ov5640_csi_params; + + CDBG("--CAMERA-- %s (Start...), rupdate=%d\n", __func__, rupdate); + + switch (rupdate) { + case S_UPDATE_PERIODIC: + if (!OV5640_CSI_CONFIG) { + camera_sw_power_onoff(0); /* standby */ + msleep(20); + + ov5640_csi_params.lane_cnt = 2; + ov5640_csi_params.data_format = CSI_8BIT; + ov5640_csi_params.lane_assign = 0xe4; + ov5640_csi_params.dpcm_scheme = 0; + ov5640_csi_params.settle_cnt = 0x6; + + CDBG("%s: msm_camio_csi_config\n", __func__); + + rc = msm_camio_csi_config(&ov5640_csi_params); + msleep(20); + camera_sw_power_onoff(1); /* on */ + msleep(20); + + OV5640_CSI_CONFIG = 1; + + } else { + rc = 0; + } + + if (S_RES_PREVIEW == rt) + rc = ov5640_video_config(); + else if (S_RES_CAPTURE == rt) + rc = ov5640_snapshot_config(); + + break; /* UPDATE_PERIODIC */ + + case S_REG_INIT: + CDBG("--CAMERA-- S_REG_INIT (Start)\n"); + + rc = ov5640_i2c_write(ov5640_client->addr, 0x3103, 0x11, 10); + rc = ov5640_i2c_write(ov5640_client->addr, 0x3008, 0x82, 10); + msleep(20); + + /* set sensor init setting */ + CDBG("set sensor init setting\n"); + rc = OV5640CORE_WRITEPREG(ov5640_init_tbl); + if (rc < 0) { + CDBG("sensor init setting failed\n"); + break; + } + + /* set image quality setting */ + rc = OV5640CORE_WRITEPREG(ov5640_init_iq_tbl); + rc = ov5640_i2c_read_byte(ov5640_client->addr, 0x4740, &tmp); + CDBG("--CAMERA-- init 0x4740 value=0x%x\n", tmp); + + if (tmp != 0x21) { + rc = ov5640_i2c_write(ov5640_client->addr, 0x4740, + 0x21, 10); + msleep(20); + rc = ov5640_i2c_read_byte(ov5640_client->addr, + 0x4740, &tmp); + CDBG("--CAMERA-- WG 0x4740 value=0x%x\n", tmp); + } + + CDBG("--CAMERA-- AF_init: ov5640_afinit = %d\n", + ov5640_afinit); + if (ov5640_afinit == 1) { + rc = ov5640_af_setting(); + if (rc < 0) { + CDBG("--CAMERA-- ov5640_af_setting failed\n"); + break; + } + ov5640_afinit = 0; + } + + /* reset fps_divider */ + ov5640_ctrl->fps_divider = 1 * 0x0400; + CDBG("--CAMERA-- S_REG_INIT (End)\n"); + break; /* case REG_INIT: */ + + default: + break; + } /* switch (rupdate) */ + + CDBG("--CAMERA-- %s (End), rupdate=%d\n", __func__, rupdate); + + return rc; +} + +static int ov5640_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int rc = -ENOMEM; + + CDBG("--CAMERA-- %s\n", __func__); + ov5640_ctrl = kzalloc(sizeof(struct __ov5640_ctrl), GFP_KERNEL); + if (!ov5640_ctrl) { + CDBG("--CAMERA-- kzalloc ov5640_ctrl error !!\n"); + kfree(ov5640_ctrl); + return rc; + } + + ov5640_ctrl->fps_divider = 1 * 0x00000400; + ov5640_ctrl->pict_fps_divider = 1 * 0x00000400; + ov5640_ctrl->set_test = S_TEST_OFF; + ov5640_ctrl->prev_res = S_QTR_SIZE; + ov5640_ctrl->pict_res = S_FULL_SIZE; + + if (data) + ov5640_ctrl->sensordata = data; + + ov5640_power_off(); + + CDBG("%s: msm_camio_clk_rate_set\n", __func__); + + msm_camio_clk_rate_set(24000000); + msleep(20); + + ov5640_power_on(); + ov5640_power_reset(); + + CDBG("%s: init sequence\n", __func__); + + if (ov5640_ctrl->prev_res == S_QTR_SIZE) + rc = ov5640_setting(S_REG_INIT, S_RES_PREVIEW); + else + rc = ov5640_setting(S_REG_INIT, S_RES_CAPTURE); + + if (rc < 0) { + CDBG("--CAMERA-- %s : ov5640_setting failed. rc = %d\n", + __func__, rc); + kfree(ov5640_ctrl); + return rc; + } + + OV5640_CSI_CONFIG = 0; + + CDBG("--CAMERA--re_init_sensor ok!!\n"); + return rc; +} + +static int ov5640_sensor_release(void) +{ + CDBG("--CAMERA--ov5640_sensor_release!!\n"); + + mutex_lock(&ov5640_mutex); + + ov5640_power_off(); + + kfree(ov5640_ctrl); + ov5640_ctrl = NULL; + + OV5640_CSI_CONFIG = 0; + + mutex_unlock(&ov5640_mutex); + return 0; +} + +static const struct i2c_device_id ov5640_i2c_id[] = { + {"ov5640", 0}, {} +}; + +static int ov5640_i2c_remove(struct i2c_client *client) +{ + return 0; +} + +static int ov5640_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&ov5640_wait_queue); + return 0; +} + +static long ov5640_set_effect(int mode, int effect) +{ + int rc = 0; + + CDBG("--CAMERA-- %s ...(Start)\n", __func__); + + switch (mode) { + case SENSOR_PREVIEW_MODE: + /* Context A Special Effects */ + CDBG("--CAMERA-- %s ...SENSOR_PREVIEW_MODE\n", __func__); + break; + + case SENSOR_SNAPSHOT_MODE: + /* Context B Special Effects */ + CDBG("--CAMERA-- %s ...SENSOR_SNAPSHOT_MODE\n", __func__); + break; + + default: + break; + } + + effect_value = effect; + + switch (effect) { + case CAMERA_EFFECT_OFF: + CDBG("--CAMERA-- %s ...CAMERA_EFFECT_OFF\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_effect_normal_tbl); + /* for recover saturation level when change special effect */ + ov5640_i2c_write(ov5640_client->addr, 0x5583, ov5640_SAT_U, + 10); + /* for recover saturation level when change special effect */ + ov5640_i2c_write(ov5640_client->addr, 0x5584, ov5640_SAT_V, + 10); + break; + + case CAMERA_EFFECT_MONO: + CDBG("--CAMERA-- %s ...CAMERA_EFFECT_MONO\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_effect_mono_tbl); + break; + + case CAMERA_EFFECT_BW: + CDBG("--CAMERA-- %s ...CAMERA_EFFECT_BW\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_effect_bw_tbl); + break; + + case CAMERA_EFFECT_BLUISH: + CDBG("--CAMERA-- %s ...CAMERA_EFFECT_BLUISH\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_effect_bluish_tbl); + break; + + case CAMERA_EFFECT_SOLARIZE: + CDBG("--CAMERA-- %s ...CAMERA_EFFECT_NEGATIVE\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_effect_solarize_tbl); + break; + + case CAMERA_EFFECT_SEPIA: + CDBG("--CAMERA-- %s ...CAMERA_EFFECT_SEPIA\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_effect_sepia_tbl); + break; + + case CAMERA_EFFECT_REDDISH: + CDBG("--CAMERA-- %s ...CAMERA_EFFECT_REDDISH\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_effect_reddish_tbl); + break; + + case CAMERA_EFFECT_GREENISH: + CDBG("--CAMERA-- %s ...CAMERA_EFFECT_GREENISH\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_effect_greenish_tbl); + break; + + case CAMERA_EFFECT_NEGATIVE: + CDBG("--CAMERA-- %s ...CAMERA_EFFECT_NEGATIVE\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_effect_negative_tbl); + break; + + default: + CDBG("--CAMERA-- %s ...Default(Not Support)\n", __func__); + } + + ov5640_effect = effect; + /* Refresh Sequencer */ + CDBG("--CAMERA-- %s ...(End)\n", __func__); + return rc; +} + +static int ov5640_set_brightness(int8_t brightness) +{ + int rc = 0; + + CDBG("--CAMERA-- %s ...(Start)\n", __func__); + CDBG("--CAMERA-- %s ...brightness = %d\n", __func__ , brightness); + + switch (brightness) { + case CAMERA_BRIGHTNESS_LV0: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_LV0\n"); + rc = OV5640CORE_WRITEPREG(ov5640_brightness_lv0_tbl); + break; + + case CAMERA_BRIGHTNESS_LV1: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_LV1\n"); + rc = OV5640CORE_WRITEPREG(ov5640_brightness_lv1_tbl); + break; + + case CAMERA_BRIGHTNESS_LV2: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_LV2\n"); + rc = OV5640CORE_WRITEPREG(ov5640_brightness_lv2_tbl); + break; + + case CAMERA_BRIGHTNESS_LV3: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_LV3\n"); + rc = OV5640CORE_WRITEPREG(ov5640_brightness_lv3_tbl); + break; + + case CAMERA_BRIGHTNESS_LV4: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_LV4\n"); + rc = OV5640CORE_WRITEPREG(ov5640_brightness_default_lv4_tbl); + break; + + case CAMERA_BRIGHTNESS_LV5: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_LV5\n"); + rc = OV5640CORE_WRITEPREG(ov5640_brightness_lv5_tbl); + break; + + case CAMERA_BRIGHTNESS_LV6: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_LV6\n"); + rc = OV5640CORE_WRITEPREG(ov5640_brightness_lv6_tbl); + break; + + case CAMERA_BRIGHTNESS_LV7: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_LV7\n"); + rc = OV5640CORE_WRITEPREG(ov5640_brightness_lv7_tbl); + break; + + case CAMERA_BRIGHTNESS_LV8: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_LV8\n"); + rc = OV5640CORE_WRITEPREG(ov5640_brightness_lv8_tbl); + break; + + default: + CDBG("--CAMERA--CAMERA_BRIGHTNESS_ERROR COMMAND\n"); + break; + } + + CDBG("--CAMERA-- %s ...(End)\n", __func__); + return rc; +} + +static int ov5640_set_contrast(int contrast) +{ + int rc = 0; + + CDBG("--CAMERA-- %s ...(Start)\n", __func__); + CDBG("--CAMERA-- %s ...contrast = %d\n", __func__ , contrast); + + if (effect_value == CAMERA_EFFECT_OFF) { + switch (contrast) { + case CAMERA_CONTRAST_LV0: + CDBG("--CAMERA--CAMERA_CONTRAST_LV0\n"); + rc = OV5640CORE_WRITEPREG(ov5640_contrast_lv0_tbl); + break; + + case CAMERA_CONTRAST_LV1: + CDBG("--CAMERA--CAMERA_CONTRAST_LV1\n"); + rc = OV5640CORE_WRITEPREG(ov5640_contrast_lv1_tbl); + break; + + case CAMERA_CONTRAST_LV2: + CDBG("--CAMERA--CAMERA_CONTRAST_LV2\n"); + rc = OV5640CORE_WRITEPREG(ov5640_contrast_lv2_tbl); + break; + + case CAMERA_CONTRAST_LV3: + CDBG("--CAMERA--CAMERA_CONTRAST_LV3\n"); + rc = OV5640CORE_WRITEPREG(ov5640_contrast_lv3_tbl); + break; + + case CAMERA_CONTRAST_LV4: + CDBG("--CAMERA--CAMERA_CONTRAST_LV4\n"); + rc = OV5640CORE_WRITEPREG( + ov5640_contrast_default_lv4_tbl); + break; + + case CAMERA_CONTRAST_LV5: + CDBG("--CAMERA--CAMERA_CONTRAST_LV5\n"); + rc = OV5640CORE_WRITEPREG(ov5640_contrast_lv5_tbl); + break; + + case CAMERA_CONTRAST_LV6: + CDBG("--CAMERA--CAMERA_CONTRAST_LV6\n"); + rc = OV5640CORE_WRITEPREG(ov5640_contrast_lv6_tbl); + break; + + case CAMERA_CONTRAST_LV7: + CDBG("--CAMERA--CAMERA_CONTRAST_LV7\n"); + rc = OV5640CORE_WRITEPREG(ov5640_contrast_lv7_tbl); + break; + + case CAMERA_CONTRAST_LV8: + CDBG("--CAMERA--CAMERA_CONTRAST_LV8\n"); + rc = OV5640CORE_WRITEPREG(ov5640_contrast_lv8_tbl); + break; + + default: + CDBG("--CAMERA--CAMERA_CONTRAST_ERROR COMMAND\n"); + break; + } + } + + CDBG("--CAMERA-- %s ...(End)\n", __func__); + return rc; +} + +static int ov5640_set_sharpness(int sharpness) +{ + int rc = 0; + + CDBG("--CAMERA-- %s ...(Start)\n", __func__); + CDBG("--CAMERA-- %s ...sharpness = %d\n", __func__ , sharpness); + + if (effect_value == CAMERA_EFFECT_OFF) { + switch (sharpness) { + case CAMERA_SHARPNESS_LV0: + CDBG("--CAMERA--CAMERA_SHARPNESS_LV0\n"); + rc = OV5640CORE_WRITEPREG(ov5640_sharpness_lv0_tbl); + break; + + case CAMERA_SHARPNESS_LV1: + CDBG("--CAMERA--CAMERA_SHARPNESS_LV1\n"); + rc = OV5640CORE_WRITEPREG(ov5640_sharpness_lv1_tbl); + break; + + case CAMERA_SHARPNESS_LV2: + CDBG("--CAMERA--CAMERA_SHARPNESS_LV2\n"); + rc = OV5640CORE_WRITEPREG( + ov5640_sharpness_default_lv2_tbl); + break; + + case CAMERA_SHARPNESS_LV3: + CDBG("--CAMERA--CAMERA_SHARPNESS_LV3\n"); + rc = OV5640CORE_WRITEPREG(ov5640_sharpness_lv3_tbl); + break; + + case CAMERA_SHARPNESS_LV4: + CDBG("--CAMERA--CAMERA_SHARPNESS_LV4\n"); + rc = OV5640CORE_WRITEPREG(ov5640_sharpness_lv4_tbl); + break; + + case CAMERA_SHARPNESS_LV5: + CDBG("--CAMERA--CAMERA_SHARPNESS_LV5\n"); + rc = OV5640CORE_WRITEPREG(ov5640_sharpness_lv5_tbl); + break; + + case CAMERA_SHARPNESS_LV6: + CDBG("--CAMERA--CAMERA_SHARPNESS_LV6\n"); + rc = OV5640CORE_WRITEPREG(ov5640_sharpness_lv6_tbl); + break; + + case CAMERA_SHARPNESS_LV7: + CDBG("--CAMERA--CAMERA_SHARPNESS_LV7\n"); + rc = OV5640CORE_WRITEPREG(ov5640_sharpness_lv7_tbl); + break; + + case CAMERA_SHARPNESS_LV8: + CDBG("--CAMERA--CAMERA_SHARPNESS_LV8\n"); + rc = OV5640CORE_WRITEPREG(ov5640_sharpness_lv8_tbl); + break; + + default: + CDBG("--CAMERA--CAMERA_SHARPNESS_ERROR COMMAND\n"); + break; + } + } + + CDBG("--CAMERA-- %s ...(End)\n", __func__); + return rc; +} + +static int ov5640_set_saturation(int saturation) +{ + long rc = 0; + + CDBG("--CAMERA-- %s ...(Start)\n", __func__); + CDBG("--CAMERA-- %s ...saturation = %d\n", __func__ , saturation); + + if (effect_value == CAMERA_EFFECT_OFF) { + switch (saturation) { + case CAMERA_SATURATION_LV0: + CDBG("--CAMERA--CAMERA_SATURATION_LV0\n"); + rc = OV5640CORE_WRITEPREG(ov5640_saturation_lv0_tbl); + break; + + case CAMERA_SATURATION_LV1: + CDBG("--CAMERA--CAMERA_SATURATION_LV1\n"); + rc = OV5640CORE_WRITEPREG(ov5640_saturation_lv1_tbl); + break; + + case CAMERA_SATURATION_LV2: + CDBG("--CAMERA--CAMERA_SATURATION_LV2\n"); + rc = OV5640CORE_WRITEPREG(ov5640_saturation_lv2_tbl); + break; + + case CAMERA_SATURATION_LV3: + CDBG("--CAMERA--CAMERA_SATURATION_LV3\n"); + rc = OV5640CORE_WRITEPREG(ov5640_saturation_lv3_tbl); + break; + + case CAMERA_SATURATION_LV4: + CDBG("--CAMERA--CAMERA_SATURATION_LV4\n"); + rc = OV5640CORE_WRITEPREG( + ov5640_saturation_default_lv4_tbl); + break; + + case CAMERA_SATURATION_LV5: + CDBG("--CAMERA--CAMERA_SATURATION_LV5\n"); + rc = OV5640CORE_WRITEPREG(ov5640_saturation_lv5_tbl); + break; + + case CAMERA_SATURATION_LV6: + CDBG("--CAMERA--CAMERA_SATURATION_LV6\n"); + rc = OV5640CORE_WRITEPREG(ov5640_saturation_lv6_tbl); + break; + + case CAMERA_SATURATION_LV7: + CDBG("--CAMERA--CAMERA_SATURATION_LV7\n"); + rc = OV5640CORE_WRITEPREG(ov5640_saturation_lv7_tbl); + break; + + case CAMERA_SATURATION_LV8: + CDBG("--CAMERA--CAMERA_SATURATION_LV8\n"); + rc = OV5640CORE_WRITEPREG(ov5640_saturation_lv8_tbl); + break; + + default: + CDBG("--CAMERA--CAMERA_SATURATION_ERROR COMMAND\n"); + break; + } + } + + /* for recover saturation level when change special effect */ + switch (saturation) { + case CAMERA_SATURATION_LV0: + CDBG("--CAMERA--CAMERA_SATURATION_LV0\n"); + ov5640_SAT_U = 0x00; + ov5640_SAT_V = 0x00; + break; + case CAMERA_SATURATION_LV1: + CDBG("--CAMERA--CAMERA_SATURATION_LV1\n"); + ov5640_SAT_U = 0x10; + ov5640_SAT_V = 0x10; + break; + case CAMERA_SATURATION_LV2: + CDBG("--CAMERA--CAMERA_SATURATION_LV2\n"); + ov5640_SAT_U = 0x20; + ov5640_SAT_V = 0x20; + break; + case CAMERA_SATURATION_LV3: + CDBG("--CAMERA--CAMERA_SATURATION_LV3\n"); + ov5640_SAT_U = 0x30; + ov5640_SAT_V = 0x30; + break; + case CAMERA_SATURATION_LV4: + CDBG("--CAMERA--CAMERA_SATURATION_LV4\n"); + ov5640_SAT_U = 0x40; + ov5640_SAT_V = 0x40; break; + case CAMERA_SATURATION_LV5: + CDBG("--CAMERA--CAMERA_SATURATION_LV5\n"); + ov5640_SAT_U = 0x50; + ov5640_SAT_V = 0x50; break; + case CAMERA_SATURATION_LV6: + CDBG("--CAMERA--CAMERA_SATURATION_LV6\n"); + ov5640_SAT_U = 0x60; + ov5640_SAT_V = 0x60; + break; + case CAMERA_SATURATION_LV7: + CDBG("--CAMERA--CAMERA_SATURATION_LV7\n"); + ov5640_SAT_U = 0x70; + ov5640_SAT_V = 0x70; break; + case CAMERA_SATURATION_LV8: + CDBG("--CAMERA--CAMERA_SATURATION_LV8\n"); + ov5640_SAT_U = 0x80; + ov5640_SAT_V = 0x80; + break; + default: + CDBG("--CAMERA--CAMERA_SATURATION_ERROR COMMAND\n"); + break; + } + + CDBG("--CAMERA-- %s ...(End)\n", __func__); + return rc; +} + +static long ov5640_set_antibanding(int antibanding) +{ + long rc = 0; + + CDBG("--CAMERA-- %s ...(Start)\n", __func__); + CDBG("--CAMERA-- %s ...antibanding = %d\n", __func__, antibanding); + + switch (antibanding) { + case CAMERA_ANTIBANDING_OFF: + CDBG("--CAMERA--CAMERA_ANTIBANDING_OFF\n"); + break; + + case CAMERA_ANTIBANDING_60HZ: + CDBG("--CAMERA--CAMERA_ANTIBANDING_60HZ\n"); + rc = OV5640CORE_WRITEPREG(ov5640_antibanding_60z_tbl); + break; + + case CAMERA_ANTIBANDING_50HZ: + CDBG("--CAMERA--CAMERA_ANTIBANDING_50HZ\n"); + rc = OV5640CORE_WRITEPREG(ov5640_antibanding_50z_tbl); + break; + + case CAMERA_ANTIBANDING_AUTO: + CDBG("--CAMERA--CAMERA_ANTIBANDING_AUTO\n"); + rc = OV5640CORE_WRITEPREG(ov5640_antibanding_auto_tbl); + break; + + default: + CDBG("--CAMERA--CAMERA_ANTIBANDING_ERROR COMMAND\n"); + break; + } + + CDBG("--CAMERA-- %s ...(End)\n", __func__); + return rc; +} + +static long ov5640_set_exposure_mode(int mode) +{ + long rc = 0; + CDBG("--CAMERA-- %s ...(Start)\n", __func__); + CDBG("--CAMERA-- %s ...mode = %d\n", __func__ , mode); + CDBG("--CAMERA-- %s ...(End)\n", __func__); + return rc; +} + +static int32_t ov5640_lens_shading_enable(uint8_t is_enable) +{ + int32_t rc = 0; + CDBG("--CAMERA--%s: ...(Start). enable = %d\n", __func__, is_enable); + + if (is_enable) { + CDBG("%s: enable~!!\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_lens_shading_on_tbl); + } else { + CDBG("%s: disable~!!\n", __func__); + rc = OV5640CORE_WRITEPREG(ov5640_lens_shading_off_tbl); + } + CDBG("--CAMERA--%s: ...(End). rc = %d\n", __func__, rc); + return rc; +} + +static int ov5640_set_sensor_mode(int mode, int res) +{ + int rc = 0; + + CDBG("--CAMERA-- ov5640_set_sensor_mode mode = %d, res = %d\n", + mode, res); + + switch (mode) { + case SENSOR_PREVIEW_MODE: + CDBG("--CAMERA-- SENSOR_PREVIEW_MODE\n"); + rc = ov5640_setting(S_UPDATE_PERIODIC, S_RES_PREVIEW); + break; + + case SENSOR_SNAPSHOT_MODE: + CDBG("--CAMERA-- SENSOR_SNAPSHOT_MODE\n"); + rc = ov5640_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); + break; + + case SENSOR_RAW_SNAPSHOT_MODE: + CDBG("--CAMERA-- SENSOR_RAW_SNAPSHOT_MODE\n"); + rc = ov5640_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); + break; + + default: + CDBG("--CAMERA--ov5640_set_sensor_mode no support\n"); + rc = -EINVAL; + break; + } + + return rc; +} + +static int ov5640_set_wb_oem(uint8_t param) +{ + int rc = 0; + unsigned int tmp2; + + CDBG("[kylin] %s \r\n", __func__); + + ov5640_i2c_read_byte(ov5640_client->addr, 0x350b, &tmp2); + CDBG("--CAMERA-- GAIN VALUE : %x\n", tmp2); + + switch (param) { + case CAMERA_WB_AUTO: + + CDBG("--CAMERA--CAMERA_WB_AUTO\n"); + rc = OV5640CORE_WRITEPREG(ov5640_wb_def); + break; + + case CAMERA_WB_CUSTOM: + CDBG("--CAMERA--CAMERA_WB_CUSTOM\n"); + rc = OV5640CORE_WRITEPREG(ov5640_wb_custom); + break; + case CAMERA_WB_INCANDESCENT: + CDBG("--CAMERA--CAMERA_WB_INCANDESCENT\n"); + rc = OV5640CORE_WRITEPREG(ov5640_wb_inc); + break; + case CAMERA_WB_DAYLIGHT: + CDBG("--CAMERA--CAMERA_WB_DAYLIGHT\n"); + rc = OV5640CORE_WRITEPREG(ov5640_wb_daylight); + break; + case CAMERA_WB_CLOUDY_DAYLIGHT: + CDBG("--CAMERA--CAMERA_WB_CLOUDY_DAYLIGHT\n"); + rc = OV5640CORE_WRITEPREG(ov5640_wb_cloudy); + break; + default: + break; + } + return rc; +} + +static int ov5640_set_touchaec(uint32_t x, uint32_t y) +{ + uint8_t aec_arr[8] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}; + int idx = 0; + int i; + + CDBG("[kylin] %s x: %d ,y: %d\r\n", __func__ , x, y); + idx = x / 2 + y * 2; + CDBG("[kylin] idx: %d\r\n", idx); + + if (x % 2 == 0) + aec_arr[idx] = 0x10 | 0x0a; + else + aec_arr[idx] = 0x01 | 0xa0; + + for (i = 0; i < 8; i++) { + CDBG("write : %x val : %x ", 0x5688 + i, aec_arr[i]); + ov5640_i2c_write(ov5640_client->addr, 0x5688 + i, + aec_arr[i], 10); + } + + return 1; +} + +static int ov5640_set_exposure_compensation(int compensation) +{ + long rc = 0; + + CDBG("--CAMERA-- %s ...(Start)\n", __func__); + + CDBG("--CAMERA-- %s ...exposure_compensation = %d\n", __func__ , + compensation); + + switch (compensation) { + case CAMERA_EXPOSURE_COMPENSATION_LV0: + CDBG("--CAMERA--CAMERA_EXPOSURE_COMPENSATION_LV0\n"); + rc = OV5640CORE_WRITEPREG( + ov5640_exposure_compensation_lv0_tbl); + break; + + case CAMERA_EXPOSURE_COMPENSATION_LV1: + CDBG("--CAMERA--CAMERA_EXPOSURE_COMPENSATION_LV1\n"); + rc = OV5640CORE_WRITEPREG( + ov5640_exposure_compensation_lv1_tbl); + break; + + case CAMERA_EXPOSURE_COMPENSATION_LV2: + CDBG("--CAMERA--CAMERA_EXPOSURE_COMPENSATION_LV2\n"); + rc = OV5640CORE_WRITEPREG( + ov5640_exposure_compensation_lv2_default_tbl); + break; + + case CAMERA_EXPOSURE_COMPENSATION_LV3: + CDBG("--CAMERA--CAMERA_EXPOSURE_COMPENSATION_LV3\n"); + rc = OV5640CORE_WRITEPREG( + ov5640_exposure_compensation_lv3_tbl); + break; + + case CAMERA_EXPOSURE_COMPENSATION_LV4: + CDBG("--CAMERA--CAMERA_EXPOSURE_COMPENSATION_LV3\n"); + rc = OV5640CORE_WRITEPREG( + ov5640_exposure_compensation_lv4_tbl); + break; + + default: + CDBG("--CAMERA--ERROR CAMERA_EXPOSURE_COMPENSATION\n"); + break; + } + + CDBG("--CAMERA-- %s ...(End)\n", __func__); + + return rc; +} + +static int ov5640_sensor_start_af(void) +{ + int i; + unsigned int af_st = 0; + unsigned int af_ack = 0; + unsigned int tmp = 0; + int rc = 0; + + CDBG("--CAMERA-- %s (Start...)\n", __func__); + + ov5640_i2c_read_byte(ov5640_client->addr, + OV5640_CMD_FW_STATUS, &af_st); + CDBG("--CAMERA-- %s af_st = %d\n", __func__, af_st); + + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_ACK, 0x01, 10); + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_MAIN, 0x03, 10); + + for (i = 0; i < 50; i++) { + ov5640_i2c_read_byte(ov5640_client->addr, + OV5640_CMD_ACK, &af_ack); + if (af_ack == 0) + break; + msleep(50); + } + CDBG("--CAMERA-- %s af_ack = 0x%x\n", __func__, af_ack); + + ov5640_i2c_read_byte(ov5640_client->addr, OV5640_CMD_FW_STATUS, + &af_st); + CDBG("--CAMERA-- %s af_st = %d\n", __func__, af_st); + + if (af_st == 0x10) { + CDBG("--CAMERA-- %s AF ok and release AF setting~!!\n", + __func__); + } else { + CDBG("--CAMERA-- %s AF not ready!!\n", __func__); + } + + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_ACK, 0x01, 10); + ov5640_i2c_write(ov5640_client->addr, OV5640_CMD_MAIN, 0x07, 10); + + for (i = 0; i < 70; i++) { + ov5640_i2c_read_byte(ov5640_client->addr, OV5640_CMD_ACK, + &af_ack); + if (af_ack == 0) + break; + msleep(25); + } + + ov5640_i2c_read_byte(ov5640_client->addr, OV5640_CMD_PARA0, &tmp); + CDBG("0x3024 = %x\n", tmp); + rc = ((tmp == 0) ? 1 : 0); + + ov5640_i2c_read_byte(ov5640_client->addr, OV5640_CMD_PARA1, &tmp); + CDBG("0x3025 = %x\n", tmp); + rc = ((tmp == 0) ? 1 : 0); + + ov5640_i2c_read_byte(ov5640_client->addr, OV5640_CMD_PARA2, &tmp); + CDBG("0x3026 = %x\n", tmp); + rc = ((tmp == 0) ? 1 : 0); + + ov5640_i2c_read_byte(ov5640_client->addr, OV5640_CMD_PARA3, &tmp); + CDBG("0x3027 = %x\n", tmp); + rc = ((tmp == 0) ? 1 : 0) ; + + ov5640_i2c_read_byte(ov5640_client->addr, OV5640_CMD_PARA4, &tmp); + CDBG("0x3028 = %x\n", tmp); + rc = ((tmp == 0) ? 1 : 0) ; + + CDBG("--CAMERA-- %s rc = %d(End...)\n", __func__, rc); + return rc; +} + +static int ov5640_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + + if (copy_from_user(&cdata, (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + CDBG("--CAMERA-- %s %d\n", __func__, cdata.cfgtype); + + mutex_lock(&ov5640_mutex); + + switch (cdata.cfgtype) { + case CFG_SET_MODE: + rc = ov5640_set_sensor_mode(cdata.mode, cdata.rs); + break; + + case CFG_SET_EFFECT: + CDBG("--CAMERA-- CFG_SET_EFFECT mode=%d," + "effect = %d !!\n", cdata.mode, + cdata.cfg.effect); + rc = ov5640_set_effect(cdata.mode, cdata.cfg.effect); + break; + + case CFG_START: + CDBG("--CAMERA-- CFG_START (Not Support) !!\n"); + /* Not Support */ + break; + + case CFG_PWR_UP: + CDBG("--CAMERA-- CFG_PWR_UP (Not Support) !!\n"); + /* Not Support */ + break; + + case CFG_PWR_DOWN: + CDBG("--CAMERA-- CFG_PWR_DOWN (Not Support)\n"); + ov5640_power_off(); + break; + + case CFG_SET_DEFAULT_FOCUS: + CDBG("--CAMERA-- CFG_SET_DEFAULT_FOCUS (Not Implement) !!\n"); + break; + + case CFG_MOVE_FOCUS: + CDBG("--CAMERA-- CFG_MOVE_FOCUS (Not Implement) !!\n"); + break; + + case CFG_SET_BRIGHTNESS: + CDBG("--CAMERA-- CFG_SET_BRIGHTNESS !!\n"); + rc = ov5640_set_brightness(cdata.cfg.brightness); + break; + + case CFG_SET_CONTRAST: + CDBG("--CAMERA-- CFG_SET_CONTRAST !!\n"); + rc = ov5640_set_contrast(cdata.cfg.contrast); + break; + + case CFG_SET_EXPOSURE_MODE: + CDBG("--CAMERA-- CFG_SET_EXPOSURE_MODE !!\n"); + rc = ov5640_set_exposure_mode(cdata.cfg.ae_mode); + break; + + case CFG_SET_ANTIBANDING: + CDBG("--CAMERA-- CFG_SET_ANTIBANDING antibanding = %d!!\n", + cdata.cfg.antibanding); + rc = ov5640_set_antibanding(cdata.cfg.antibanding); + break; + + case CFG_SET_LENS_SHADING: + CDBG("--CAMERA-- CFG_SET_LENS_SHADING !!\n"); + rc = ov5640_lens_shading_enable( + cdata.cfg.lens_shading); + break; + + case CFG_SET_SATURATION: + CDBG("--CAMERA-- CFG_SET_SATURATION !!\n"); + rc = ov5640_set_saturation(cdata.cfg.saturation); + break; + + case CFG_SET_SHARPNESS: + CDBG("--CAMERA-- CFG_SET_SHARPNESS !!\n"); + rc = ov5640_set_sharpness(cdata.cfg.sharpness); + break; + + case CFG_SET_WB: + CDBG("--CAMERA-- CFG_SET_WB!!\n"); + ov5640_set_wb_oem(cdata.cfg.wb_val); + rc = 0 ; + break; + + case CFG_SET_TOUCHAEC: + CDBG("--CAMERA-- CFG_SET_TOUCHAEC!!\n"); + ov5640_set_touchaec(cdata.cfg.aec_cord.x, + cdata.cfg.aec_cord.y); + rc = 0 ; + break; + + case CFG_SET_AUTO_FOCUS: + CDBG("--CAMERA-- CFG_SET_AUTO_FOCUS !\n"); + rc = ov5640_sensor_start_af(); + break; + + case CFG_SET_AUTOFLASH: + CDBG("--CAMERA-- CFG_SET_AUTOFLASH !\n"); + is_autoflash = cdata.cfg.is_autoflash; + CDBG("[kylin] is autoflash %d\r\n", is_autoflash); + rc = 0; + break; + + case CFG_SET_EXPOSURE_COMPENSATION: + CDBG("--CAMERA-- CFG_SET_EXPOSURE_COMPENSATION !\n"); + rc = ov5640_set_exposure_compensation( + cdata.cfg.exp_compensation); + break; + + default: + CDBG("%s: Command=%d (Not Implement)!!\n", __func__, + cdata.cfgtype); + rc = -EINVAL; + break; + } + + mutex_unlock(&ov5640_mutex); + return rc; +} + +static struct i2c_driver ov5640_i2c_driver = { + .id_table = ov5640_i2c_id, + .probe = ov5640_i2c_probe, + .remove = ov5640_i2c_remove, + .driver = { + .name = "ov5640", + }, +}; + +static int ov5640_probe_init_gpio(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + + CDBG("--CAMERA-- %s\n", __func__); + + ov5640_pwdn_gpio = data->sensor_pwd; + ov5640_reset_gpio = data->sensor_reset; + ov5640_driver_pwdn_gpio = data->vcm_pwd ; + + if (data->vcm_enable) + gpio_direction_output(data->vcm_pwd, 1); + + gpio_direction_output(data->sensor_reset, 1); + gpio_direction_output(data->sensor_pwd, 1); + + return rc; + +} + +static void ov5640_probe_free_gpio(const struct msm_camera_sensor_info *data) +{ + gpio_free(ov5640_pwdn_gpio); + gpio_free(ov5640_reset_gpio); + + if (data->vcm_enable) { + gpio_free(ov5640_driver_pwdn_gpio); + ov5640_driver_pwdn_gpio = 0xFF ; + } + + ov5640_pwdn_gpio = 0xFF; + ov5640_reset_gpio = 0xFF; +} + +static int ov5640_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = -ENOTSUPP; + + CDBG("--CAMERA-- %s (Start...)\n", __func__); + rc = i2c_add_driver(&ov5640_i2c_driver); + CDBG("--CAMERA-- i2c_add_driver ret:0x%x,ov5640_client=0x%x\n", + rc, (unsigned int)ov5640_client); + if ((rc < 0) || (ov5640_client == NULL)) { + CDBG("--CAMERA-- i2c_add_driver FAILS!!\n"); + return rc; + } + + rc = ov5640_probe_init_gpio(info); + if (rc < 0) + return rc; + + ov5640_power_off(); + + /* SENSOR NEED MCLK TO DO I2C COMMUNICTION, OPEN CLK FIRST*/ + msm_camio_clk_rate_set(24000000); + + msleep(20); + + ov5640_power_on(); + ov5640_power_reset(); + + rc = ov5640_probe_readID(info); + + if (rc < 0) { + CDBG("--CAMERA--ov5640_probe_readID Fail !!~~~~!!\n"); + CDBG("--CAMERA-- %s, unregister\n", __func__); + i2c_del_driver(&ov5640_i2c_driver); + ov5640_power_off(); + ov5640_probe_free_gpio(info); + return rc; + } + + s->s_init = ov5640_sensor_open_init; + s->s_release = ov5640_sensor_release; + s->s_config = ov5640_sensor_config; + s->s_camera_type = BACK_CAMERA_2D; + s->s_mount_angle = info->sensor_platform_info->mount_angle; + + ov5640_power_off(); + + CDBG("--CAMERA-- %s (End...)\n", __func__); + return rc; +} + +static int ov5640_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + CDBG("--CAMERA-- %s ... (Start...)\n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("--CAMERA--i2c_check_functionality failed\n"); + return -ENOMEM; + } + + ov5640_sensorw = kzalloc(sizeof(struct ov5640_work), GFP_KERNEL); + if (!ov5640_sensorw) { + CDBG("--CAMERA--kzalloc failed\n"); + return -ENOMEM; + } + + i2c_set_clientdata(client, ov5640_sensorw); + ov5640_init_client(client); + ov5640_client = client; + + CDBG("--CAMERA-- %s ... (End...)\n", __func__); + return 0; +} + +static int __ov5640_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, ov5640_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __ov5640_probe, + .driver = { + .name = "msm_camera_ov5640", + .owner = THIS_MODULE, + }, +}; + +static int __init ov5640_init(void) +{ + ov5640_i2c_buf[0] = 0x5A; + return platform_driver_register(&msm_camera_driver); +} + +module_init(ov5640_init); + +MODULE_DESCRIPTION("OV5640 YUV MIPI sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/ov5640.h b/drivers/media/video/msm_zsl/ov5640.h new file mode 100644 index 00000000000..0e65329ce63 --- /dev/null +++ b/drivers/media/video/msm_zsl/ov5640.h @@ -0,0 +1,2993 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + + +/* +[SENSOR] +Sensor Model: OV5640 +Camera Module: +Lens Model: +Driver IC: +PV Size = 640 x 480 +Cap Size = 2592 x 1944 +Output Format = YUYV +MCLK Speed = 24M +PV DVP_PCLK = 28M +Cap DVP_PCLK = 56M +PV Frame Rate = 30fps +Cap Frame Rate = 7.5fps +I2C Slave ID = 0x78 +I2C Mode = 16Addr, 8Data +*/ + +#ifndef CAMSENSOR_OV5640 +#define CAMSENSOR_OV5640 + +#define INVMASK(v) (0xff-v) +#define OV5640CORE_WRITEPREG(PTBL) ov5640_writepregs(PTBL,\ + sizeof(PTBL)/sizeof(PTBL[0])) + +/* OV SENSOR SCCB */ +struct ov5640_sensor { + uint16_t addr; + uint8_t data; + uint8_t mask; +}; + +/* Auto Focus Command */ +#define OV5640_CMD_MAIN 0x3022 +#define OV5640_CMD_ACK 0x3023 +#define OV5640_CMD_PARA0 0x3024 +#define OV5640_CMD_PARA1 0x3025 +#define OV5640_CMD_PARA2 0x3026 +#define OV5640_CMD_PARA3 0x3027 +#define OV5640_CMD_PARA4 0x3028 +#define OV5640_CMD_FW_STATUS 0x3029 + +/* Sensor ID */ +#define OV5640_SENSOR_ID 0x5640 + +#define capture_framerate 750 /* 7.5fps capture frame rate */ +#define g_preview_frameRate 3000 /* 30fps preview frame rate */ + +struct ov5640_sensor ov5640_init_tbl[] = { + {0x3008, 0x42}, + {0x3103, 0x03}, + {0x3017, 0x00}, + {0x3018, 0x00}, + {0x3034, 0x18}, + {0x3035, 0x14}, + {0x3036, 0x38}, + {0x3037, 0x13}, + {0x3108, 0x01}, + {0x3630, 0x36}, + {0x3631, 0x0e}, + {0x3632, 0xe2}, + {0x3633, 0x12}, + {0x3621, 0xe0}, + {0x3704, 0xa0}, + {0x3703, 0x5a}, + {0x3715, 0x78}, + {0x3717, 0x01}, + {0x370b, 0x60}, + {0x3705, 0x1a}, + {0x3905, 0x02}, + {0x3906, 0x10}, + {0x3901, 0x0a}, + {0x3731, 0x12}, + {0x3600, 0x08}, + {0x3601, 0x33}, + {0x302d, 0x60}, + {0x3620, 0x52}, + {0x371b, 0x20}, + {0x471c, 0x50}, + {0x3a13, 0x43}, + {0x3a18, 0x00}, + {0x3a19, 0xf8}, + {0x3635, 0x13}, + {0x3636, 0x03}, + {0x3634, 0x40}, + {0x3622, 0x01}, + {0x3c01, 0x34}, + {0x3c04, 0x28}, + {0x3c05, 0x98}, + {0x3c06, 0x00}, + {0x3c07, 0x08}, + {0x3c08, 0x00}, + {0x3c09, 0x1c}, + {0x3c0a, 0x9c}, + {0x3c0b, 0x40}, + {0x3820, 0x41}, + {0x3821, 0x07}, + {0x3814, 0x31}, + {0x3815, 0x31}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0x9b}, + {0x3808, 0x02}, + {0x3809, 0x80}, + {0x380a, 0x01}, + {0x380b, 0xe0}, + {0x380c, 0x07}, + {0x380d, 0x68}, + {0x380e, 0x03}, + {0x380f, 0xd8}, + {0x3810, 0x00}, + {0x3811, 0x10}, + {0x3812, 0x00}, + {0x3813, 0x06}, + {0x3618, 0x00}, + {0x3612, 0x29}, + {0x3708, 0x64}, + {0x3709, 0x52}, + {0x370c, 0x03}, + {0x3a02, 0x03}, + {0x3a03, 0xd8}, + {0x3a08, 0x01}, + {0x3a09, 0x27}, + {0x3a0a, 0x00}, + {0x3a0b, 0xf6}, + {0x3a0e, 0x03}, + {0x3a0d, 0x04}, + {0x3a14, 0x03}, + {0x3a15, 0xd8}, + {0x4001, 0x02}, + {0x4004, 0x02}, + {0x3000, 0x00}, + {0x3002, 0x1c}, + {0x3004, 0xff}, + {0x3006, 0xc3}, + {0x300e, 0x45}, + {0x302e, 0x08}, + {0x4300, 0x30}, + {0x501f, 0x00}, + {0x4713, 0x03}, + {0x4407, 0x04}, + {0x440e, 0x00}, + {0x460b, 0x35}, + {0x460c, 0x22}, + {0x4837, 0x44}, + {0x3824, 0x02}, + {0x5000, 0xa7}, + {0x5001, 0xa3}, + {0x5180, 0xff}, + {0x5181, 0xf2}, + {0x5182, 0x00}, + {0x5183, 0x14}, + {0x5184, 0x25}, + {0x5185, 0x24}, + {0x5186, 0x09}, + {0x5187, 0x09}, + {0x5188, 0x09}, + {0x5189, 0x75}, + {0x518a, 0x54}, + {0x518b, 0xe0}, + {0x518c, 0xb2}, + {0x518d, 0x42}, + {0x518e, 0x3d}, + {0x518f, 0x56}, + {0x5190, 0x46}, + {0x5191, 0xf8}, + {0x5192, 0x04}, + {0x5193, 0x70}, + {0x5194, 0xf0}, + {0x5195, 0xf0}, + {0x5196, 0x03}, + {0x5197, 0x01}, + {0x5198, 0x04}, + {0x5199, 0x12}, + {0x519a, 0x04}, + {0x519b, 0x00}, + {0x519c, 0x06}, + {0x519d, 0x82}, + {0x519e, 0x38}, + {0x5381, 0x1e}, + {0x5382, 0x5b}, + {0x5383, 0x08}, + {0x5384, 0x0a}, + {0x5385, 0x7e}, + {0x5386, 0x88}, + {0x5387, 0x7c}, + {0x5388, 0x6c}, + {0x5389, 0x10}, + {0x538a, 0x01}, + {0x538b, 0x98}, + {0x5300, 0x08}, + {0x5301, 0x30}, + {0x5302, 0x10}, + {0x5303, 0x00}, + {0x5304, 0x08}, + {0x5305, 0x30}, + {0x5306, 0x08}, + {0x5307, 0x16}, + {0x5309, 0x08}, + {0x530a, 0x30}, + {0x530b, 0x04}, + {0x530c, 0x06}, + {0x5480, 0x01}, + {0x5481, 0x08}, + {0x5482, 0x14}, + {0x5483, 0x28}, + {0x5484, 0x51}, + {0x5485, 0x65}, + {0x5486, 0x71}, + {0x5487, 0x7d}, + {0x5488, 0x87}, + {0x5489, 0x91}, + {0x548a, 0x9a}, + {0x548b, 0xaa}, + {0x548c, 0xb8}, + {0x548d, 0xcd}, + {0x548e, 0xdd}, + {0x548f, 0xea}, + {0x5490, 0x1d}, + {0x5580, 0x02}, + {0x5583, 0x40}, + {0x5584, 0x10}, + {0x5589, 0x10}, + {0x558a, 0x00}, + {0x558b, 0xf8}, + {0x5800, 0x23}, + {0x5801, 0x14}, + {0x5802, 0x0f}, + {0x5803, 0x0f}, + {0x5804, 0x12}, + {0x5805, 0x26}, + {0x5806, 0x0c}, + {0x5807, 0x08}, + {0x5808, 0x05}, + {0x5809, 0x05}, + {0x580a, 0x08}, + {0x580b, 0x0d}, + {0x580c, 0x08}, + {0x580d, 0x03}, + {0x580e, 0x00}, + {0x580f, 0x00}, + {0x5810, 0x03}, + {0x5811, 0x09}, + {0x5812, 0x07}, + {0x5813, 0x03}, + {0x5814, 0x00}, + {0x5815, 0x01}, + {0x5816, 0x03}, + {0x5817, 0x08}, + {0x5818, 0x0d}, + {0x5819, 0x08}, + {0x581a, 0x05}, + {0x581b, 0x06}, + {0x581c, 0x08}, + {0x581d, 0x0e}, + {0x581e, 0x29}, + {0x581f, 0x17}, + {0x5820, 0x11}, + {0x5821, 0x11}, + {0x5822, 0x15}, + {0x5823, 0x28}, + {0x5824, 0x46}, + {0x5825, 0x26}, + {0x5826, 0x08}, + {0x5827, 0x26}, + {0x5828, 0x64}, + {0x5829, 0x26}, + {0x582a, 0x24}, + {0x582b, 0x22}, + {0x582c, 0x24}, + {0x582d, 0x24}, + {0x582e, 0x06}, + {0x582f, 0x22}, + {0x5830, 0x40}, + {0x5831, 0x42}, + {0x5832, 0x24}, + {0x5833, 0x26}, + {0x5834, 0x24}, + {0x5835, 0x22}, + {0x5836, 0x22}, + {0x5837, 0x26}, + {0x5838, 0x44}, + {0x5839, 0x24}, + {0x583a, 0x26}, + {0x583b, 0x28}, + {0x583c, 0x42}, + {0x583d, 0xce}, + {0x5025, 0x00}, + {0x3a0f, 0x30}, + {0x3a10, 0x28}, + {0x3a1b, 0x30}, + {0x3a1e, 0x26}, + {0x3a11, 0x60}, + {0x3a1f, 0x14}, + {0x3008, 0x02}, +}; + +struct ov5640_sensor ov5640_init_iq_tbl[] = { +/* Lens correction */ +/* OV5640 LENC setting */ + {0x5800, 0x3f}, + {0x5801, 0x20}, + {0x5802, 0x1a}, + {0x5803, 0x1a}, + {0x5804, 0x23}, + {0x5805, 0x3f}, + {0x5806, 0x11}, + {0x5807, 0x0c}, + {0x5808, 0x09}, + {0x5809, 0x08}, + {0x580a, 0x0d}, + {0x580b, 0x12}, + {0x580c, 0x0d}, + {0x580d, 0x04}, + {0x580e, 0x00}, + {0x580f, 0x00}, + {0x5810, 0x05}, + {0x5811, 0x0d}, + {0x5812, 0x0d}, + {0x5813, 0x04}, + {0x5814, 0x00}, + {0x5815, 0x00}, + {0x5816, 0x04}, + {0x5817, 0x0d}, + {0x5818, 0x13}, + {0x5819, 0x0d}, + {0x581a, 0x08}, + {0x581b, 0x08}, + {0x581c, 0x0c}, + {0x581d, 0x13}, + {0x581e, 0x3f}, + {0x581f, 0x1f}, + {0x5820, 0x1b}, + {0x5821, 0x1c}, + {0x5822, 0x23}, + {0x5823, 0x3f}, + {0x5824, 0x6a}, + {0x5825, 0x06}, + {0x5826, 0x08}, + {0x5827, 0x06}, + {0x5828, 0x2a}, + {0x5829, 0x08}, + {0x582a, 0x24}, + {0x582b, 0x24}, + {0x582c, 0x24}, + {0x582d, 0x08}, + {0x582e, 0x08}, + {0x582f, 0x22}, + {0x5830, 0x40}, + {0x5831, 0x22}, + {0x5832, 0x06}, + {0x5833, 0x08}, + {0x5834, 0x24}, + {0x5835, 0x24}, + {0x5836, 0x04}, + {0x5837, 0x0a}, + {0x5838, 0x86}, + {0x5839, 0x08}, + {0x583a, 0x28}, + {0x583b, 0x28}, + {0x583c, 0x66}, + {0x583d, 0xce}, +/* AEC */ + {0x3a0f, 0x38}, + {0x3a10, 0x30}, + {0x3a11, 0x61}, + {0x3a1b, 0x38}, + {0x3a1e, 0x30}, + {0x3a1f, 0x10}, + /* AWB */ + {0x5180, 0xff}, + {0x5181, 0xf2}, + {0x5182, 0x00}, + {0x5183, 0x14}, + {0x5184, 0x25}, + {0x5185, 0x24}, + {0x5186, 0x09}, + {0x5187, 0x09}, + {0x5188, 0x09}, + {0x5189, 0x88}, + {0x518a, 0x54}, + {0x518b, 0xee}, + {0x518c, 0xb2}, + {0x518d, 0x50}, + {0x518e, 0x34}, + {0x518f, 0x6b}, + {0x5190, 0x46}, + {0x5191, 0xf8}, + {0x5192, 0x04}, + {0x5193, 0x70}, + {0x5194, 0xf0}, + {0x5195, 0xf0}, + {0x5196, 0x03}, + {0x5197, 0x01}, + {0x5198, 0x04}, + {0x5199, 0x6c}, + {0x519a, 0x04}, + {0x519b, 0x00}, + {0x519c, 0x09}, + {0x519d, 0x2b}, + {0x519e, 0x38}, + +/* UV Adjust Auto Mode */ + {0x5580, 0x02}, /* 02 ;Sat enable */ + {0x5588, 0x01}, /*40 ;enable UV adj */ + {0x5583, 0x40}, /* ;offset high */ + {0x5584, 0x18}, /* ;offset low */ + {0x5589, 0x18}, /* ;gth1 */ + {0x558a, 0x00}, + {0x358b, 0xf8}, /* ;gth2 */ +}; + +struct ov5640_sensor ov5640_preview_tbl[] = { +/* @@ MIPI_2lane_5M to vga(YUV) 30fps 99 640 480 98 0 0 */ + {0x3503, 0x00}, /* enable AE back from capture to preview */ + {0x3035, 0x14}, + {0x3036, 0x38}, + {0x3820, 0x41}, + {0x3821, 0x07}, + {0x3814, 0x31}, + {0x3815, 0x31}, + {0x3803, 0x04}, + {0x3807, 0x9b}, + {0x3808, 0x02}, + {0x3809, 0x80}, + {0x380a, 0x01}, + {0x380b, 0xe0}, + {0x380c, 0x07}, + {0x380d, 0x68}, + {0x380e, 0x03}, + {0x380f, 0xd8}, + {0x3813, 0x06}, + {0x3618, 0x00}, + {0x3612, 0x29}, + {0x3708, 0x64}, + {0x3709, 0x52}, + {0x370c, 0x03}, + {0x5001, 0xa3}, + {0x4004, 0x02}, + {0x4005, 0x18}, + {0x4837, 0x44}, + {0x4713, 0x03}, + {0x4407, 0x04}, + {0x460b, 0x35}, + {0x460c, 0x22}, + {0x3824, 0x02}, +}; + +struct ov5640_sensor ov5640_capture_tbl[] = { +/* @@ MIPI_2lane_5M(YUV) 7.5/15fps 99 2592 1944 98 0 0 */ + {0x3035, 0x21}, /* 11 */ + {0x3036, 0x54}, + {0x3820, 0x40}, + {0x3821, 0x06}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3803, 0x00}, + {0x3807, 0x9f}, + {0x3808, 0x0a}, + {0x3809, 0x20}, + {0x380a, 0x07}, + {0x380b, 0x98}, + {0x380c, 0x0b}, + {0x380d, 0x1c}, + {0x380e, 0x07}, + {0x380f, 0xb0}, + {0x3813, 0x04}, + {0x3618, 0x04}, + {0x3612, 0x2b}, + {0x3708, 0x21}, + {0x3709, 0x12}, + {0x370c, 0x00}, + {0x5001, 0x83}, + {0x4004, 0x06}, + {0x4005, 0x1a}, + {0x4837, 0x15}, /* 0a */ + {0x4713, 0x02}, + {0x4407, 0x0c}, + {0x460b, 0x37}, + {0x460c, 0x20}, + {0x3824, 0x01}, +}; + +/* Contrast */ + +struct ov5640_sensor ov5640_contrast_lv0_tbl[] = { +/* Contrast -4 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x04, INVMASK(0x04)}, /* Enable BIT2 for contrast/brightness + control*/ + {0x5586, 0x10}, /* Gain */ + {0x5585, 0x10}, /* Offset */ + {0x5588, 0x00, INVMASK(0x04)}, /* Offset sign */ +}; + +struct ov5640_sensor ov5640_contrast_lv1_tbl[] = { +/* Contrast -3 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x04, INVMASK(0x04)}, /* Enable BIT2 for contrast/brightness + control */ + {0x5586, 0x14}, /* Gain */ + {0x5585, 0x14}, /* Offset */ + {0x5588, 0x00, INVMASK(0x04)}, /* Offset sign */ +}; + +struct ov5640_sensor ov5640_contrast_lv2_tbl[] = { +/* Contrast -2 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x04, INVMASK(0x04)}, /* Enable BIT2 for contrast/brightness + control */ + {0x5586, 0x18}, /* Gain */ + {0x5585, 0x18}, /* Offset */ + {0x5588, 0x00, INVMASK(0x04)}, /* Offset sign */ +}; + +struct ov5640_sensor ov5640_contrast_lv3_tbl[] = { +/* Contrast -1 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5586, 0x1c}, + {0x5585, 0x1c}, + {0x5588, 0x00, INVMASK(0x04)}, +}; + +struct ov5640_sensor ov5640_contrast_default_lv4_tbl[] = { +/* Contrast (Default) */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5586, 0x20}, + {0x5585, 0x00}, + {0x5588, 0x00, INVMASK(0x04)}, +}; + +struct ov5640_sensor ov5640_contrast_lv5_tbl[] = { +/* Contrast +1 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5586, 0x24}, + {0x5585, 0x10}, + {0x5588, 0x00, INVMASK(0x04)}, +}; + +struct ov5640_sensor ov5640_contrast_lv6_tbl[] = { +/* Contrast +2 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5586, 0x28}, + {0x5585, 0x18}, + {0x5588, 0x00, INVMASK(0x04)}, +}; + +struct ov5640_sensor ov5640_contrast_lv7_tbl[] = { +/* Contrast +3 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5586, 0x2c}, + {0x5585, 0x1c}, + {0x5588, 0x00, INVMASK(0x04)}, +}; + +struct ov5640_sensor ov5640_contrast_lv8_tbl[] = { +/* Contrast +4 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5586, 0x30}, + {0x5585, 0x20}, + {0x5588, 0x00, INVMASK(0x04)}, +}; + +/* Sharpness */ + +struct ov5640_sensor ov5640_sharpness_lv0_tbl[] = { +/* Sharpness 0 */ + {0x5308, 0x40, INVMASK(0x40)}, + {0x5302, 0x00}, +}; + +struct ov5640_sensor ov5640_sharpness_lv1_tbl[] = { +/* Sharpness 1 */ + {0x5308, 0x40, INVMASK(0x40)}, + {0x5302, 0x02}, +}; + +struct ov5640_sensor ov5640_sharpness_default_lv2_tbl[] = { +/* Sharpness_Auto (Default) */ + {0x5308, 0x00, INVMASK(0x40)}, + {0x5300, 0x08}, + {0x5301, 0x30}, + {0x5302, 0x10}, + {0x5303, 0x00}, + {0x5309, 0x08}, + {0x530a, 0x30}, + {0x530b, 0x04}, + {0x530c, 0x06}, +}; + +struct ov5640_sensor ov5640_sharpness_lv3_tbl[] = { +/* Sharpness 3 */ + {0x5308, 0x40, INVMASK(0x40)}, + {0x5302, 0x08}, +}; + +struct ov5640_sensor ov5640_sharpness_lv4_tbl[] = { +/* Sharpness 4 */ + {0x5308, 0x40, INVMASK(0x40)}, + {0x5302, 0x0c}, +}; + +struct ov5640_sensor ov5640_sharpness_lv5_tbl[] = { +/* Sharpness 5 */ + {0x5308, 0x40, INVMASK(0x40)}, + {0x5302, 0x10}, +}; + +struct ov5640_sensor ov5640_sharpness_lv6_tbl[] = { +/* Sharpness 6 */ + {0x5308, 0x40, INVMASK(0x40)}, + {0x5302, 0x14}, +}; + +struct ov5640_sensor ov5640_sharpness_lv7_tbl[] = { +/* Sharpness 7 */ + {0x5308, 0x40, INVMASK(0x40)}, + {0x5302, 0x18}, +}; + +struct ov5640_sensor ov5640_sharpness_lv8_tbl[] = { +/* Sharpness 8 */ + {0x5308, 0x40, INVMASK(0x40)}, + {0x5302, 0x20}, +}; + +/* Saturation */ + +struct ov5640_sensor ov5640_saturation_lv0_tbl[] = { +/* Saturation x0.25 */ + {0x5001, 0x83, INVMASK(0x80)}, /* SDE_En */ + {0x5583, 0x00}, /* Saturaion gain in U */ + {0x5584, 0x00}, /* Saturation gain in V */ + {0x5580, 0x02, INVMASK(0x02)}, /* Saturation enable */ + {0x5588, 0x40, INVMASK(0x40)}, +}; + +struct ov5640_sensor ov5640_saturation_lv1_tbl[] = { +/* Saturation x0.5 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5583, 0x10}, + {0x5584, 0x10}, + {0x5580, 0x02, INVMASK(0x02)}, + {0x5588, 0x40, INVMASK(0x40)}, +}; + +struct ov5640_sensor ov5640_saturation_lv2_tbl[] = { +/* Saturation x0.75 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5583, 0x20}, + {0x5584, 0x20}, + {0x5580, 0x02, INVMASK(0x02)}, + {0x5588, 0x40, INVMASK(0x40)}, +}; + +struct ov5640_sensor ov5640_saturation_lv3_tbl[] = { +/* Saturation x0.75 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5583, 0x30}, + {0x5584, 0x30}, + {0x5580, 0x02, INVMASK(0x02)}, + {0x5588, 0x40, INVMASK(0x40)}, +}; + +struct ov5640_sensor ov5640_saturation_default_lv4_tbl[] = { +/* Saturation x1 (Default) */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5583, 0x40}, + {0x5584, 0x40}, + {0x5580, 0x02, INVMASK(0x02)}, + {0x5588, 0x40, INVMASK(0x40)}, +}; + +struct ov5640_sensor ov5640_saturation_lv5_tbl[] = { +/* Saturation x1.25 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5583, 0x50}, + {0x5584, 0x50}, + {0x5580, 0x02, INVMASK(0x02)}, + {0x5588, 0x40, INVMASK(0x40)}, +}; + +struct ov5640_sensor ov5640_saturation_lv6_tbl[] = { +/* Saturation x1.5 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5583, 0x60}, + {0x5584, 0x60}, + {0x5580, 0x02, INVMASK(0x02)}, + {0x5588, 0x40, INVMASK(0x40)}, +}; + +struct ov5640_sensor ov5640_saturation_lv7_tbl[] = { +/* Saturation x1.25 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5583, 0x70}, + {0x5584, 0x70}, + {0x5580, 0x02, INVMASK(0x02)}, + {0x5588, 0x40, INVMASK(0x40)}, +}; + +struct ov5640_sensor ov5640_saturation_lv8_tbl[] = { +/* Saturation x1.5 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5583, 0x80}, + {0x5584, 0x80}, + {0x5580, 0x02, INVMASK(0x02)}, + {0x5588, 0x40, INVMASK(0x40)}, +}; + +/* Brightness */ + +struct ov5640_sensor ov5640_brightness_lv0_tbl[] = { +/* Brightness -4 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5587, 0x40}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5588, 0x08, INVMASK(0x08)}, +}; + +struct ov5640_sensor ov5640_brightness_lv1_tbl[] = { +/* Brightness -3 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5587, 0x30}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5588, 0x08, INVMASK(0x08)}, +}; + +struct ov5640_sensor ov5640_brightness_lv2_tbl[] = { +/* Brightness -2 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5587, 0x20}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5588, 0x08, INVMASK(0x08)}, +}; + +struct ov5640_sensor ov5640_brightness_lv3_tbl[] = { +/* Brightness -1 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5587, 0x10}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5588, 0x08, INVMASK(0x08)}, +}; + +struct ov5640_sensor ov5640_brightness_default_lv4_tbl[] = { +/* Brightness 0 (Default) */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5587, 0x00}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5588, 0x00, INVMASK(0x08)}, +}; + +struct ov5640_sensor ov5640_brightness_lv5_tbl[] = { +/* Brightness +1 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5587, 0x10}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5588, 0x00, INVMASK(0x08)}, +}; + +struct ov5640_sensor ov5640_brightness_lv6_tbl[] = { +/* Brightness +2 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5587, 0x20}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5588, 0x00, INVMASK(0x08)}, +}; + +struct ov5640_sensor ov5640_brightness_lv7_tbl[] = { +/* Brightness +3 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5587, 0x30}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5588, 0x00, INVMASK(0x08)}, +}; + +struct ov5640_sensor ov5640_brightness_lv8_tbl[] = { +/* Brightness +4 */ + {0x5001, 0x83, INVMASK(0x80)}, + {0x5587, 0x40}, + {0x5580, 0x04, INVMASK(0x04)}, + {0x5588, 0x00, INVMASK(0x08)}, +}; + +/* Exposure Compensation */ +struct ov5640_sensor ov5640_exposure_compensation_lv0_tbl[] = { + /* @@ +1.7EV */ + {0x3a0f, 0x60}, + {0x3a10, 0x58}, + {0x3a11, 0xa0}, + {0x3a1b, 0x60}, + {0x3a1e, 0x58}, + {0x3a1f, 0x20}, +}; + +struct ov5640_sensor ov5640_exposure_compensation_lv1_tbl[] = { + /* @@ +1.0EV */ + {0x3a0f, 0x50}, + {0x3a10, 0x48}, + {0x3a11, 0x90}, + {0x3a1b, 0x50}, + {0x3a1e, 0x48}, + {0x3a1f, 0x20}, +}; + +struct ov5640_sensor ov5640_exposure_compensation_lv2_default_tbl[] = { + /* @@ default */ + {0x3a0f, 0x38}, + {0x3a10, 0x30}, + {0x3a11, 0x61}, + {0x3a1b, 0x38}, + {0x3a1e, 0x30}, + {0x3a1f, 0x10}, +}; + +struct ov5640_sensor ov5640_exposure_compensation_lv3_tbl[] = { + /* @@ -1.0EV */ + {0x3a0f, 0x20}, + {0x3a10, 0x18}, + {0x3a11, 0x41}, + {0x3a1b, 0x20}, + {0x3a1e, 0x18}, + {0x3a1f, 0x10}, +}; + +struct ov5640_sensor ov5640_exposure_compensation_lv4_tbl[] = { + /* @@ -1.7EV */ + {0x3a0f, 0x10}, + {0x3a10, 0x08}, + {0x3a11, 0x10}, + {0x3a1b, 0x08}, + {0x3a1e, 0x20}, + {0x3a1f, 0x10}, +}; + +/* Auto Expourse Weight */ + +struct ov5640_sensor ov5640_ae_average_tbl[] = { + /* Whole Image Average */ + {0x5688, 0x11}, /* Zone 1/Zone 0 weight */ + {0x5689, 0x11}, /* Zone 3/Zone 2 weight */ + {0x569a, 0x11}, /* Zone 5/Zone 4 weight */ + {0x569b, 0x11}, /* Zone 7/Zone 6 weight */ + {0x569c, 0x11}, /* Zone 9/Zone 8 weight */ + {0x569d, 0x11}, /* Zone b/Zone a weight */ + {0x569e, 0x11}, /* Zone d/Zone c weight */ + {0x569f, 0x11}, /* Zone f/Zone e weight */ +}; + +struct ov5640_sensor ov5640_ae_centerweight_tbl[] = { + /* Whole Image Center More weight */ + {0x5688, 0x62}, + {0x5689, 0x26}, + {0x568a, 0xe6}, + {0x568b, 0x6e}, + {0x568c, 0xea}, + {0x568d, 0xae}, + {0x568e, 0xa6}, + {0x568f, 0x6a}, +}; + +/* Light Mode */ +struct ov5640_sensor ov5640_wb_def[] = { + {0x3406, 0x00, INVMASK(0x01)}, +}; + +struct ov5640_sensor ov5640_wb_custom[] = { + {0x3406, 0x01, INVMASK(0x01)}, + {0x3400, 0x04}, + {0x3401, 0x58}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x08}, + {0x3405, 0x40}, +}; + +struct ov5640_sensor ov5640_wb_inc[] = { + {0x3406, 0x01, INVMASK(0x01)}, + {0x3400, 0x04}, + {0x3401, 0x88}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x08}, + {0x3405, 0xb6}, +}; + +struct ov5640_sensor ov5640_wb_daylight[] = { + {0x3406, 0x01, INVMASK(0x01)}, + {0x3400, 0x07}, + {0x3401, 0x02}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x05}, + {0x3405, 0x15}, +}; + +struct ov5640_sensor ov5640_wb_cloudy[] = { + {0x3406, 0x01, INVMASK(0x01)}, + {0x3400, 0x07}, + {0x3401, 0x88}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x05}, + {0x3405, 0x00}, +}; + +/* EFFECT */ +struct ov5640_sensor ov5640_effect_normal_tbl[] = { + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x00, INVMASK(0x78)}, + {0x5003, 0x08}, + {0x5583, 0x40}, + {0x5584, 0x40}, +}; + +struct ov5640_sensor ov5640_effect_mono_tbl[] = { + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x20, INVMASK(0x78)}, + {0x5003, 0x08}, + {0x5583, 0x40}, + {0x5584, 0x40}, +}; + +struct ov5640_sensor ov5640_effect_bw_tbl[] = { + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x18, INVMASK(0x78)}, + {0x5003, 0x08}, + {0x5583, 0x80}, + {0x5584, 0x80}, +}; + +struct ov5640_sensor ov5640_effect_bluish_tbl[] = { + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x18, INVMASK(0x78)}, + {0x5003, 0x08}, + {0x5583, 0xa0}, + {0x5584, 0x40}, +}; + +struct ov5640_sensor ov5640_effect_solarize_tbl[] = { + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x00, INVMASK(0x78)}, + {0x5003, 0x09}, +}; + + +struct ov5640_sensor ov5640_effect_sepia_tbl[] = { + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x18, INVMASK(0x78)}, + {0x5003, 0x08}, + {0x5583, 0x40}, + {0x5584, 0xa0}, +}; + +struct ov5640_sensor ov5640_effect_reddish_tbl[] = { + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x18, INVMASK(0x78)}, + {0x5003, 0x08}, + {0x5583, 0x80}, + {0x5584, 0xc0}, +}; + +struct ov5640_sensor ov5640_effect_greenish_tbl[] = { + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x18, INVMASK(0x78)}, + {0x5003, 0x08}, + {0x5583, 0x60}, + {0x5584, 0x60}, +}; + +struct ov5640_sensor ov5640_effect_negative_tbl[] = { + {0x5001, 0x83, INVMASK(0x80)}, + {0x5580, 0x40, INVMASK(0x78)}, + {0x5003, 0x08}, +}; + +/* AntiBanding */ +struct ov5640_sensor ov5640_antibanding_auto_tbl[] = { + /* Auto-XCLK24MHz */ + {0x3622, 0x01}, /* PD-sel */ + {0x3635, 0x1c}, /* VMREF 3635[2:0] */ + {0x3634, 0x40}, /* I_5060 3643[2:0] */ + {0x3c01, 0x34}, + {0x3c00, 0x00}, + {0x3c04, 0x28}, + {0x3c05, 0x98}, + {0x3c06, 0x00}, + {0x3c07, 0x08}, + {0x3c08, 0x00}, + {0x3c09, 0x1c}, + {0x300c, 0x22}, /* 50/60div 300c[2:0] */ + {0x3c0a, 0x9c}, + {0x3c0b, 0x40}, +}; + +struct ov5640_sensor ov5640_antibanding_50z_tbl[] = { + /* Band 50Hz */ + {0x3c01, 0x80, INVMASK(0x80)}, + {0x3c00, 0x04}, +}; + +struct ov5640_sensor ov5640_antibanding_60z_tbl[] = { + /* Band 60Hz */ + {0x3c01, 0x80, INVMASK(0x80)}, + {0x3c00, 0x00}, +}; + + +/* Lens_shading */ + +struct ov5640_sensor ov5640_lens_shading_on_tbl[] = { + /* @@ Lenc On(C) */ + {0x5000, 0x80, INVMASK(0x80)}, +}; + +struct ov5640_sensor ov5640_lens_shading_off_tbl[] = { + /* Lenc Off */ + {0x5000, 0x00, INVMASK(0x80)}, +}; + +/* Auto Focus Firmware-use 2011-08-24 firmware settings */ +u8 ov5640_afinit_tbl[] = { + 0x80, 0x00, 0x02, 0x0b, 0x7b, 0x02, 0x07, 0xbd, 0xc2, + 0x01, 0x22, 0x22, 0x00, 0x02, 0x0b, 0x57, 0xe5, 0x1f, + 0x70, 0x72, 0xf5, 0x1e, 0xd2, 0x35, 0xff, 0xef, 0x25, + 0xe0, 0x24, 0x4b, 0xf8, 0xe4, 0xf6, 0x08, 0xf6, 0x0f, + 0xbf, 0x34, 0xf2, 0x90, 0x0e, 0x88, 0xe4, 0x93, 0xff, + 0xe5, 0x49, 0xc3, 0x9f, 0x50, 0x04, 0x7f, 0x05, 0x80, + 0x02, 0x7f, 0xfb, 0x78, 0xba, 0xa6, 0x07, 0x12, 0x0a, + 0xb4, 0x40, 0x04, 0x7f, 0x03, 0x80, 0x02, 0x7f, 0x30, + 0x78, 0xb9, 0xa6, 0x07, 0xe6, 0x18, 0xf6, 0x08, 0xe6, + 0x78, 0xb6, 0xf6, 0x78, 0xb9, 0xe6, 0x78, 0xb7, 0xf6, + 0x78, 0xbc, 0x76, 0x33, 0xe4, 0x08, 0xf6, 0x78, 0xb5, + 0x76, 0x01, 0x75, 0x48, 0x02, 0x78, 0xb3, 0xf6, 0x08, + 0xf6, 0x74, 0xff, 0x78, 0xbe, 0xf6, 0x08, 0xf6, 0x75, + 0x1f, 0x01, 0x78, 0xb9, 0xe6, 0x75, 0xf0, 0x05, 0xa4, + 0xf5, 0x49, 0x12, 0x08, 0x5b, 0xc2, 0x37, 0x22, 0x78, + 0xb5, 0xe6, 0xd3, 0x94, 0x00, 0x40, 0x02, 0x16, 0x22, + 0xe5, 0x1f, 0x64, 0x05, 0x70, 0x28, 0xf5, 0x1f, 0xc2, + 0x01, 0x78, 0xb6, 0xe6, 0x25, 0xe0, 0x24, 0x4b, 0xf8, + 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x78, 0x4b, 0xa6, 0x06, + 0x08, 0xa6, 0x07, 0xa2, 0x37, 0xe4, 0x33, 0xf5, 0x3c, + 0x90, 0x30, 0x28, 0xf0, 0x75, 0x1e, 0x10, 0xd2, 0x35, + 0x22, 0xe5, 0x49, 0x75, 0xf0, 0x05, 0x84, 0x78, 0xb9, + 0xf6, 0x90, 0x0e, 0x85, 0xe4, 0x93, 0xff, 0x25, 0xe0, + 0x24, 0x0a, 0xf8, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x78, + 0xb9, 0xe6, 0x25, 0xe0, 0x24, 0x4b, 0xf8, 0xa6, 0x04, + 0x08, 0xa6, 0x05, 0xef, 0x12, 0x0a, 0xbb, 0xd3, 0x78, + 0xb4, 0x96, 0xee, 0x18, 0x96, 0x40, 0x0d, 0x78, 0xb9, + 0xe6, 0x78, 0xb6, 0xf6, 0x78, 0xb3, 0xa6, 0x06, 0x08, + 0xa6, 0x07, 0x90, 0x0e, 0x85, 0xe4, 0x93, 0x12, 0x0a, + 0xbb, 0xc3, 0x78, 0xbf, 0x96, 0xee, 0x18, 0x96, 0x50, + 0x0d, 0x78, 0xb9, 0xe6, 0x78, 0xb7, 0xf6, 0x78, 0xbe, + 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x78, 0xb3, 0xe6, 0xfe, + 0x08, 0xe6, 0xc3, 0x78, 0xbf, 0x96, 0xff, 0xee, 0x18, + 0x96, 0x78, 0xc0, 0xf6, 0x08, 0xa6, 0x07, 0x90, 0x0e, + 0x8a, 0xe4, 0x18, 0x12, 0x0a, 0x99, 0xc3, 0x33, 0xce, + 0x33, 0xce, 0xd8, 0xf9, 0xff, 0xd3, 0xed, 0x9f, 0xec, + 0x9e, 0x40, 0x02, 0xd2, 0x37, 0x78, 0xb9, 0xe6, 0x08, + 0x26, 0x08, 0xf6, 0xe5, 0x1f, 0x64, 0x01, 0x70, 0x55, + 0xe6, 0xc3, 0x78, 0xbd, 0x12, 0x0a, 0x8f, 0x40, 0x10, + 0x12, 0x0a, 0x8a, 0x50, 0x0b, 0x30, 0x37, 0x41, 0x78, + 0xb9, 0xe6, 0x78, 0xb6, 0x66, 0x60, 0x39, 0x12, 0x0a, + 0xb2, 0x40, 0x04, 0x7f, 0xfe, 0x80, 0x02, 0x7f, 0x02, + 0x78, 0xba, 0xa6, 0x07, 0x78, 0xb6, 0xe6, 0x24, 0x03, + 0x78, 0xbc, 0xf6, 0x78, 0xb6, 0xe6, 0x24, 0xfd, 0x78, + 0xbd, 0xf6, 0x12, 0x0a, 0xb2, 0x40, 0x06, 0x78, 0xbd, + 0xe6, 0xff, 0x80, 0x04, 0x78, 0xbc, 0xe6, 0xff, 0x78, + 0xbb, 0xa6, 0x07, 0x75, 0x1f, 0x02, 0x78, 0xb5, 0x76, + 0x01, 0x02, 0x02, 0x68, 0xe5, 0x1f, 0x64, 0x02, 0x60, + 0x03, 0x02, 0x02, 0x48, 0x78, 0xbb, 0xe6, 0xff, 0xc3, + 0x78, 0xbd, 0x12, 0x0a, 0x90, 0x40, 0x08, 0x12, 0x0a, + 0x8a, 0x50, 0x03, 0x02, 0x02, 0x46, 0x12, 0x0a, 0xb2, + 0x40, 0x04, 0x7f, 0xff, 0x80, 0x02, 0x7f, 0x01, 0x78, + 0xba, 0xa6, 0x07, 0x78, 0xb6, 0xe6, 0x04, 0x78, 0xbc, + 0xf6, 0x78, 0xb6, 0xe6, 0x14, 0x78, 0xbd, 0xf6, 0x18, + 0x12, 0x0a, 0xb4, 0x40, 0x04, 0xe6, 0xff, 0x80, 0x02, + 0x7f, 0x00, 0x78, 0xbc, 0xa6, 0x07, 0xd3, 0x08, 0xe6, + 0x64, 0x80, 0x94, 0x80, 0x40, 0x04, 0xe6, 0xff, 0x80, + 0x02, 0x7f, 0x00, 0x78, 0xbd, 0xa6, 0x07, 0xc3, 0x18, + 0xe6, 0x64, 0x80, 0x94, 0xb3, 0x50, 0x04, 0xe6, 0xff, + 0x80, 0x02, 0x7f, 0x33, 0x78, 0xbc, 0xa6, 0x07, 0xc3, + 0x08, 0xe6, 0x64, 0x80, 0x94, 0xb3, 0x50, 0x04, 0xe6, + 0xff, 0x80, 0x02, 0x7f, 0x33, 0x78, 0xbd, 0xa6, 0x07, + 0x12, 0x0a, 0xb2, 0x40, 0x06, 0x78, 0xbd, 0xe6, 0xff, + 0x80, 0x04, 0x78, 0xbc, 0xe6, 0xff, 0x78, 0xbb, 0xa6, + 0x07, 0x75, 0x1f, 0x03, 0x78, 0xb5, 0x76, 0x01, 0x80, + 0x20, 0xe5, 0x1f, 0x64, 0x03, 0x70, 0x26, 0x78, 0xbb, + 0xe6, 0xff, 0xc3, 0x78, 0xbd, 0x12, 0x0a, 0x90, 0x40, + 0x05, 0x12, 0x0a, 0x8a, 0x40, 0x09, 0x78, 0xb6, 0xe6, + 0x78, 0xbb, 0xf6, 0x75, 0x1f, 0x04, 0x78, 0xbb, 0xe6, + 0x75, 0xf0, 0x05, 0xa4, 0xf5, 0x49, 0x02, 0x08, 0x5b, + 0xe5, 0x1f, 0xb4, 0x04, 0x1d, 0x90, 0x0e, 0x89, 0xe4, + 0x78, 0xc0, 0x12, 0x0a, 0x99, 0xc3, 0x33, 0xce, 0x33, + 0xce, 0xd8, 0xf9, 0xff, 0xd3, 0xed, 0x9f, 0xec, 0x9e, + 0x40, 0x02, 0xd2, 0x37, 0x75, 0x1f, 0x05, 0x22, 0xef, + 0x8d, 0xf0, 0xa4, 0xa8, 0xf0, 0xcf, 0x8c, 0xf0, 0xa4, + 0x28, 0xce, 0x8d, 0xf0, 0xa4, 0x2e, 0xfe, 0x22, 0xbc, + 0x00, 0x0b, 0xbe, 0x00, 0x29, 0xef, 0x8d, 0xf0, 0x84, + 0xff, 0xad, 0xf0, 0x22, 0xe4, 0xcc, 0xf8, 0x75, 0xf0, + 0x08, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xec, 0x33, + 0xfc, 0xee, 0x9d, 0xec, 0x98, 0x40, 0x05, 0xfc, 0xee, + 0x9d, 0xfe, 0x0f, 0xd5, 0xf0, 0xe9, 0xe4, 0xce, 0xfd, + 0x22, 0xed, 0xf8, 0xf5, 0xf0, 0xee, 0x84, 0x20, 0xd2, + 0x1c, 0xfe, 0xad, 0xf0, 0x75, 0xf0, 0x08, 0xef, 0x2f, + 0xff, 0xed, 0x33, 0xfd, 0x40, 0x07, 0x98, 0x50, 0x06, + 0xd5, 0xf0, 0xf2, 0x22, 0xc3, 0x98, 0xfd, 0x0f, 0xd5, + 0xf0, 0xea, 0x22, 0xe8, 0x8f, 0xf0, 0xa4, 0xcc, 0x8b, + 0xf0, 0xa4, 0x2c, 0xfc, 0xe9, 0x8e, 0xf0, 0xa4, 0x2c, + 0xfc, 0x8a, 0xf0, 0xed, 0xa4, 0x2c, 0xfc, 0xea, 0x8e, + 0xf0, 0xa4, 0xcd, 0xa8, 0xf0, 0x8b, 0xf0, 0xa4, 0x2d, + 0xcc, 0x38, 0x25, 0xf0, 0xfd, 0xe9, 0x8f, 0xf0, 0xa4, + 0x2c, 0xcd, 0x35, 0xf0, 0xfc, 0xeb, 0x8e, 0xf0, 0xa4, + 0xfe, 0xa9, 0xf0, 0xeb, 0x8f, 0xf0, 0xa4, 0xcf, 0xc5, + 0xf0, 0x2e, 0xcd, 0x39, 0xfe, 0xe4, 0x3c, 0xfc, 0xea, + 0xa4, 0x2d, 0xce, 0x35, 0xf0, 0xfd, 0xe4, 0x3c, 0xfc, + 0x22, 0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, + 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc, 0x33, + 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, + 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40, 0x0c, 0xf5, 0x82, + 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, + 0x0f, 0xd5, 0xf0, 0xd6, 0xe4, 0xce, 0xfb, 0xe4, 0xcd, + 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, + 0xc1, 0xb9, 0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, + 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb, + 0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, + 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb, 0x33, 0xfb, + 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, + 0x0f, 0xd8, 0xe5, 0xe4, 0xf9, 0xfa, 0x22, 0x78, 0x18, + 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, + 0xec, 0x33, 0xfc, 0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, + 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, + 0x9a, 0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, + 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f, 0xff, + 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, + 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07, 0x9b, 0xec, 0x9a, + 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, + 0xfc, 0xe8, 0x99, 0xf8, 0x0f, 0xd5, 0xf0, 0xda, 0xe4, + 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22, + 0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, + 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0, 0x22, 0xe8, + 0x60, 0x0f, 0xef, 0xc3, 0x33, 0xff, 0xee, 0x33, 0xfe, + 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xd8, 0xf1, 0x22, + 0xe4, 0x93, 0xfc, 0x74, 0x01, 0x93, 0xfd, 0x74, 0x02, + 0x93, 0xfe, 0x74, 0x03, 0x93, 0xff, 0x22, 0xe6, 0xfb, + 0x08, 0xe6, 0xf9, 0x08, 0xe6, 0xfa, 0x08, 0xe6, 0xcb, + 0xf8, 0x22, 0xec, 0xf6, 0x08, 0xed, 0xf6, 0x08, 0xee, + 0xf6, 0x08, 0xef, 0xf6, 0x22, 0xa4, 0x25, 0x82, 0xf5, + 0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xd0, + 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, + 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, + 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, + 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, + 0xdf, 0x90, 0x38, 0x04, 0x78, 0x4f, 0x12, 0x09, 0x50, + 0x90, 0x38, 0x00, 0xe0, 0xfe, 0xa3, 0xe0, 0xfd, 0xed, + 0xff, 0xc3, 0x12, 0x09, 0x09, 0x90, 0x38, 0x10, 0x12, + 0x08, 0xfd, 0x90, 0x38, 0x06, 0x78, 0x51, 0x12, 0x09, + 0x50, 0x90, 0x38, 0x02, 0xe0, 0xfe, 0xa3, 0xe0, 0xfd, + 0xed, 0xff, 0xc3, 0x12, 0x09, 0x09, 0x90, 0x38, 0x12, + 0x12, 0x08, 0xfd, 0xa3, 0xe0, 0xb4, 0x31, 0x07, 0x78, + 0x4f, 0x79, 0x4f, 0x12, 0x09, 0x66, 0x90, 0x38, 0x14, + 0xe0, 0xb4, 0x71, 0x15, 0x78, 0x4f, 0xe6, 0xfe, 0x08, + 0xe6, 0x78, 0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, + 0xf9, 0x79, 0x50, 0xf7, 0xee, 0x19, 0xf7, 0x90, 0x38, + 0x15, 0xe0, 0xb4, 0x31, 0x07, 0x78, 0x51, 0x79, 0x51, + 0x12, 0x09, 0x66, 0x90, 0x38, 0x15, 0xe0, 0xb4, 0x71, + 0x15, 0x78, 0x51, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x02, + 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x79, 0x52, + 0xf7, 0xee, 0x19, 0xf7, 0x79, 0x4f, 0x12, 0x09, 0x38, + 0x09, 0x12, 0x09, 0x38, 0xaf, 0x45, 0x12, 0x08, 0xee, + 0x7d, 0x50, 0x12, 0x02, 0xa9, 0x78, 0x57, 0xa6, 0x06, + 0x08, 0xa6, 0x07, 0xaf, 0x43, 0x12, 0x08, 0xee, 0x7d, + 0x50, 0x12, 0x02, 0xa9, 0x78, 0x53, 0xa6, 0x06, 0x08, + 0xa6, 0x07, 0xaf, 0x46, 0x78, 0x51, 0x12, 0x08, 0xf0, + 0x7d, 0x3c, 0x12, 0x02, 0xa9, 0x78, 0x59, 0xa6, 0x06, + 0x08, 0xa6, 0x07, 0xaf, 0x44, 0x7e, 0x00, 0x78, 0x51, + 0x12, 0x08, 0xf2, 0x7d, 0x3c, 0x12, 0x02, 0xa9, 0x78, + 0x55, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0xc3, 0x78, 0x58, + 0xe6, 0x94, 0x08, 0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, + 0x76, 0x00, 0x08, 0x76, 0x08, 0xc3, 0x78, 0x5a, 0xe6, + 0x94, 0x08, 0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, 0x76, + 0x00, 0x08, 0x76, 0x08, 0x78, 0x57, 0x12, 0x09, 0x25, + 0xff, 0xd3, 0x78, 0x54, 0xe6, 0x9f, 0x18, 0xe6, 0x9e, + 0x40, 0x0e, 0x78, 0x57, 0xe6, 0x13, 0xfe, 0x08, 0xe6, + 0x78, 0x54, 0x12, 0x09, 0x5b, 0x80, 0x04, 0x7e, 0x00, + 0x7f, 0x00, 0x78, 0x5b, 0x12, 0x09, 0x1d, 0xff, 0xd3, + 0x78, 0x56, 0xe6, 0x9f, 0x18, 0xe6, 0x9e, 0x40, 0x0e, + 0x78, 0x59, 0xe6, 0x13, 0xfe, 0x08, 0xe6, 0x78, 0x56, + 0x12, 0x09, 0x5b, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, + 0xe4, 0xfc, 0xfd, 0x78, 0x5f, 0x12, 0x04, 0x5c, 0x78, + 0x57, 0x12, 0x09, 0x25, 0x78, 0x54, 0x26, 0xff, 0xee, + 0x18, 0x36, 0xfe, 0x78, 0x63, 0x12, 0x09, 0x1d, 0x78, + 0x56, 0x26, 0xff, 0xee, 0x18, 0x36, 0xfe, 0xe4, 0xfc, + 0xfd, 0x78, 0x67, 0x12, 0x04, 0x5c, 0x12, 0x09, 0x2d, + 0x78, 0x63, 0x12, 0x04, 0x4f, 0xd3, 0x12, 0x04, 0x1b, + 0x40, 0x08, 0x12, 0x09, 0x2d, 0x78, 0x63, 0x12, 0x04, + 0x5c, 0x78, 0x51, 0x12, 0x09, 0x2f, 0x78, 0x67, 0x12, + 0x04, 0x4f, 0xd3, 0x12, 0x04, 0x1b, 0x40, 0x0a, 0x78, + 0x51, 0x12, 0x09, 0x2f, 0x78, 0x67, 0x12, 0x04, 0x5c, + 0xe4, 0xfd, 0x78, 0x5e, 0x12, 0x09, 0x48, 0x24, 0x01, + 0x12, 0x09, 0x11, 0x78, 0x62, 0x12, 0x09, 0x48, 0x24, + 0x02, 0x12, 0x09, 0x11, 0x78, 0x66, 0x12, 0x09, 0x48, + 0x24, 0x03, 0x12, 0x09, 0x11, 0x78, 0x6a, 0x12, 0x09, + 0x48, 0x24, 0x04, 0x12, 0x09, 0x11, 0x0d, 0xbd, 0x05, + 0xd4, 0xc2, 0x0e, 0xc2, 0x06, 0x22, 0x85, 0x08, 0x41, + 0x90, 0x30, 0x24, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0, 0xf5, + 0x3e, 0xa3, 0xe0, 0xf5, 0x3f, 0xa3, 0xe0, 0xf5, 0x40, + 0xa3, 0xe0, 0xf5, 0x3c, 0xd2, 0x34, 0xe5, 0x41, 0x12, + 0x04, 0x74, 0x06, 0xc7, 0x03, 0x06, 0xcb, 0x04, 0x06, + 0xd1, 0x07, 0x06, 0xda, 0x08, 0x06, 0xeb, 0x12, 0x07, + 0x03, 0x18, 0x07, 0x19, 0x19, 0x06, 0xee, 0x1a, 0x06, + 0xfa, 0x1b, 0x07, 0x3e, 0x80, 0x07, 0x43, 0x81, 0x07, + 0xa1, 0x8f, 0x07, 0x90, 0x90, 0x07, 0xa1, 0x91, 0x07, + 0xa1, 0x92, 0x07, 0xa1, 0x93, 0x07, 0xa1, 0x94, 0x07, + 0xa1, 0x98, 0x07, 0x9e, 0x9f, 0x00, 0x00, 0x07, 0xbc, + 0x12, 0x0a, 0xf4, 0x22, 0x12, 0x0a, 0xf4, 0xd2, 0x03, + 0x22, 0xa2, 0x37, 0xe4, 0x33, 0xf5, 0x3c, 0x02, 0x07, + 0xa1, 0xc2, 0x01, 0xc2, 0x02, 0xc2, 0x03, 0x12, 0x09, + 0x70, 0x75, 0x1e, 0x70, 0xd2, 0x35, 0x02, 0x07, 0xa1, + 0x02, 0x07, 0x8b, 0x85, 0x40, 0x48, 0x85, 0x3c, 0x49, + 0x12, 0x08, 0x5b, 0x02, 0x07, 0xa1, 0x85, 0x48, 0x40, + 0x85, 0x49, 0x3c, 0x02, 0x07, 0xa1, 0xe4, 0xf5, 0x22, + 0xf5, 0x23, 0x85, 0x40, 0x31, 0x85, 0x3f, 0x30, 0x85, + 0x3e, 0x2f, 0x85, 0x3d, 0x2e, 0x12, 0x0a, 0xc6, 0x80, + 0x1f, 0x75, 0x22, 0x00, 0x75, 0x23, 0x01, 0x74, 0xff, + 0xf5, 0x2d, 0xf5, 0x2c, 0xf5, 0x2b, 0xf5, 0x2a, 0x12, + 0x0a, 0xc6, 0x85, 0x2d, 0x40, 0x85, 0x2c, 0x3f, 0x85, + 0x2b, 0x3e, 0x85, 0x2a, 0x3d, 0xe4, 0xf5, 0x3c, 0x02, + 0x07, 0xa1, 0x12, 0x0b, 0x3d, 0x80, 0x5e, 0x85, 0x3d, + 0x43, 0x85, 0x3e, 0x44, 0xe5, 0x45, 0xc3, 0x13, 0xff, + 0xe5, 0x43, 0xc3, 0x9f, 0x50, 0x02, 0x8f, 0x43, 0xe5, + 0x46, 0xc3, 0x13, 0xff, 0xe5, 0x44, 0xc3, 0x9f, 0x50, + 0x02, 0x8f, 0x44, 0xe5, 0x45, 0xc3, 0x13, 0xff, 0xfd, + 0xe5, 0x43, 0x90, 0x0e, 0x7f, 0x12, 0x0b, 0x10, 0x40, + 0x04, 0xee, 0x9f, 0xf5, 0x43, 0xe5, 0x46, 0xc3, 0x13, + 0xff, 0xfd, 0xe5, 0x44, 0x90, 0x0e, 0x80, 0x12, 0x0b, + 0x10, 0x40, 0x04, 0xee, 0x9f, 0xf5, 0x44, 0x12, 0x04, + 0x9a, 0x80, 0x11, 0x85, 0x40, 0x46, 0x85, 0x3f, 0x45, + 0x85, 0x3e, 0x44, 0x85, 0x3d, 0x43, 0x80, 0x03, 0x02, + 0x04, 0x9a, 0x90, 0x30, 0x24, 0xe5, 0x3d, 0xf0, 0xa3, + 0xe5, 0x3e, 0xf0, 0xa3, 0xe5, 0x3f, 0xf0, 0xa3, 0xe5, + 0x40, 0xf0, 0xa3, 0xe5, 0x3c, 0xf0, 0x90, 0x30, 0x23, + 0xe4, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, + 0xc0, 0xd0, 0x90, 0x3f, 0x0c, 0xe0, 0xf5, 0x32, 0xe5, + 0x32, 0x30, 0xe3, 0x4c, 0x30, 0x36, 0x3e, 0x90, 0x60, + 0x19, + 0xe0, + 0xf5, + 0x0a, + 0xa3, + 0xe0, + 0xf5, + 0x0b, + 0x90, + 0x60, + 0x1d, + 0xe0, + 0xf5, + 0x14, + 0xa3, + 0xe0, + 0xf5, + 0x15, + 0x30, + 0x01, + 0x06, + 0x30, + 0x33, + 0x03, + 0xd3, + 0x80, + 0x01, + 0xc3, + 0x92, + 0x09, + 0x30, + 0x02, + 0x06, + 0x30, + 0x33, + 0x03, + 0xd3, + 0x80, + 0x01, + 0xc3, + 0x92, + 0x0a, + 0x30, + 0x33, + 0x0c, + 0x30, + 0x03, + 0x09, + 0x20, + 0x02, + 0x06, + 0x20, + 0x01, + 0x03, + 0xd3, + 0x80, + 0x01, + 0xc3, + 0x92, + 0x0b, + 0x90, + 0x30, + 0x01, + 0xe0, + 0x44, + 0x40, + 0xf0, + 0xe0, + 0x54, + 0xbf, + 0xf0, + 0xe5, + 0x32, + 0x30, + 0xe1, + 0x14, + 0x30, + 0x34, + 0x11, + 0x90, + 0x30, + 0x22, + 0xe0, + 0xf5, + 0x08, + 0xe4, + 0xf0, + 0x30, + 0x00, + 0x03, + 0xd3, + 0x80, + 0x01, + 0xc3, + 0x92, + 0x08, + 0xe5, + 0x32, + 0x30, + 0xe5, + 0x12, + 0x90, + 0x56, + 0xa1, + 0xe0, + 0xf5, + 0x09, + 0x30, + 0x31, + 0x09, + 0x30, + 0x05, + 0x03, + 0xd3, + 0x80, + 0x01, + 0xc3, + 0x92, + 0x0d, + 0x90, + 0x3f, + 0x0c, + 0xe5, + 0x32, + 0xf0, + 0xd0, + 0xd0, + 0xd0, + 0x82, + 0xd0, + 0x83, + 0xd0, + 0xe0, + 0x32, + 0x90, + 0x0e, + 0x7d, + 0xe4, + 0x93, + 0xfe, + 0x74, + 0x01, + 0x93, + 0xff, + 0xc3, + 0x90, + 0x0e, + 0x7b, + 0x74, + 0x01, + 0x93, + 0x9f, + 0xff, + 0xe4, + 0x93, + 0x9e, + 0xfe, + 0xe4, + 0x8f, + 0x3b, + 0x8e, + 0x3a, + 0xf5, + 0x39, + 0xf5, + 0x38, + 0xab, + 0x3b, + 0xaa, + 0x3a, + 0xa9, + 0x39, + 0xa8, + 0x38, + 0xaf, + 0x49, + 0xfc, + 0xfd, + 0xfe, + 0x12, + 0x02, + 0xfe, + 0x12, + 0x0b, + 0x22, + 0xe4, + 0x7b, + 0xff, + 0xfa, + 0xf9, + 0xf8, + 0x12, + 0x03, + 0x89, + 0x12, + 0x0b, + 0x22, + 0x90, + 0x0e, + 0x69, + 0xe4, + 0x12, + 0x0b, + 0x37, + 0x12, + 0x0b, + 0x22, + 0xe4, + 0x85, + 0x48, + 0x37, + 0xf5, + 0x36, + 0xf5, + 0x35, + 0xf5, + 0x34, + 0xaf, + 0x37, + 0xae, + 0x36, + 0xad, + 0x35, + 0xac, + 0x34, + 0xa3, + 0x12, + 0x0b, + 0x37, + 0x8f, + 0x37, + 0x8e, + 0x36, + 0x8d, + 0x35, + 0x8c, + 0x34, + 0xe5, + 0x3b, + 0x45, + 0x37, + 0xf5, + 0x3b, + 0xe5, + 0x3a, + 0x45, + 0x36, + 0xf5, + 0x3a, + 0xe5, + 0x39, + 0x45, + 0x35, + 0xf5, + 0x39, + 0xe5, + 0x38, + 0x45, + 0x34, + 0xf5, + 0x38, + 0xe4, + 0xf5, + 0x22, + 0xf5, + 0x23, + 0x85, + 0x3b, + 0x31, + 0x85, + 0x3a, + 0x30, + 0x85, + 0x39, + 0x2f, + 0x85, + 0x38, + 0x2e, + 0x02, + 0x0a, + 0xc6, + 0x78, + 0x4f, + 0x7e, + 0x00, + 0xe6, + 0xfc, + 0x08, + 0xe6, + 0xfd, + 0x12, + 0x02, + 0x97, + 0x7c, + 0x00, + 0x22, + 0xe0, + 0xa3, + 0xe0, + 0x75, + 0xf0, + 0x02, + 0xa4, + 0xff, + 0xae, + 0xf0, + 0xc3, + 0x08, + 0xe6, + 0x9f, + 0xf6, + 0x18, + 0xe6, + 0x9e, + 0xf6, + 0x22, + 0xff, + 0xe5, + 0xf0, + 0x34, + 0x60, + 0x8f, + 0x82, + 0xf5, + 0x83, + 0xec, + 0xf0, + 0x22, + 0xe4, + 0xfc, + 0xfd, + 0x12, + 0x04, + 0x5c, + 0x78, + 0x59, + 0xe6, + 0xc3, + 0x13, + 0xfe, + 0x08, + 0xe6, + 0x13, + 0x22, + 0x78, + 0x4f, + 0xe6, + 0xfe, + 0x08, + 0xe6, + 0xff, + 0xe4, + 0xfc, + 0xfd, + 0x22, + 0xe7, + 0xc4, + 0xf8, + 0x54, + 0xf0, + 0xc8, + 0x68, + 0xf7, + 0x09, + 0xe7, + 0xc4, + 0x54, + 0x0f, + 0x48, + 0xf7, + 0x22, + 0xe6, + 0xfc, + 0xed, + 0x75, + 0xf0, + 0x04, + 0xa4, + 0x22, + 0xe0, + 0xfe, + 0xa3, + 0xe0, + 0xfd, + 0xee, + 0xf6, + 0xed, + 0x08, + 0xf6, + 0x22, + 0x13, + 0xff, + 0xc3, + 0xe6, + 0x9f, + 0xff, + 0x18, + 0xe6, + 0x9e, + 0xfe, + 0x22, + 0xe6, + 0xc3, + 0x13, + 0xf7, + 0x08, + 0xe6, + 0x13, + 0x09, + 0xf7, + 0x22, + 0xe4, + 0xf5, + 0x49, + 0x90, + 0x0e, + 0x77, + 0x93, + 0xff, + 0xe4, + 0x8f, + 0x37, + 0xf5, + 0x36, + 0xf5, + 0x35, + 0xf5, + 0x34, + 0xaf, + 0x37, + 0xae, + 0x36, + 0xad, + 0x35, + 0xac, + 0x34, + 0x90, + 0x0e, + 0x6a, + 0x12, + 0x0b, + 0x37, + 0x8f, + 0x37, + 0x8e, + 0x36, + 0x8d, + 0x35, + 0x8c, + 0x34, + 0x90, + 0x0e, + 0x72, + 0x12, + 0x04, + 0x3f, + 0xef, + 0x45, + 0x37, + 0xf5, + 0x37, + 0xee, + 0x45, + 0x36, + 0xf5, + 0x36, + 0xed, + 0x45, + 0x35, + 0xf5, + 0x35, + 0xec, + 0x45, + 0x34, + 0xf5, + 0x34, + 0xe4, + 0xf5, + 0x22, + 0xf5, + 0x23, + 0x85, + 0x37, + 0x31, + 0x85, + 0x36, + 0x30, + 0x85, + 0x35, + 0x2f, + 0x85, + 0x34, + 0x2e, + 0x12, + 0x0a, + 0xc6, + 0xe4, + 0xf5, + 0x22, + 0xf5, + 0x23, + 0x90, + 0x0e, + 0x72, + 0x12, + 0x0b, + 0x2b, + 0x12, + 0x0a, + 0xc6, + 0xe4, + 0xf5, + 0x22, + 0xf5, + 0x23, + 0x90, + 0x0e, + 0x6e, + 0x12, + 0x0b, + 0x2b, + 0x02, + 0x0a, + 0xc6, + 0x75, + 0x89, + 0x03, + 0x75, + 0xa8, + 0x01, + 0x75, + 0xb8, + 0x04, + 0x75, + 0x34, + 0xff, + 0x75, + 0x35, + 0x0e, + 0x75, + 0x36, + 0x15, + 0x75, + 0x37, + 0x0d, + 0x12, + 0x0a, + 0x4a, + 0x12, + 0x00, + 0x09, + 0x12, + 0x0b, + 0x3d, + 0x12, + 0x00, + 0x06, + 0xd2, + 0x00, + 0xd2, + 0x34, + 0xd2, + 0xaf, + 0x75, + 0x34, + 0xff, + 0x75, + 0x35, + 0x0e, + 0x75, + 0x36, + 0x49, + 0x75, + 0x37, + 0x03, + 0x12, + 0x0a, + 0x4a, + 0x30, + 0x08, + 0x09, + 0xc2, + 0x34, + 0x12, + 0x06, + 0x6a, + 0xc2, + 0x08, + 0xd2, + 0x34, + 0x30, + 0x09, + 0x09, + 0xc2, + 0x36, + 0x12, + 0x00, + 0x0e, + 0xc2, + 0x09, + 0xd2, + 0x36, + 0x30, + 0x0e, + 0x03, + 0x12, + 0x04, + 0x9a, + 0x30, + 0x35, + 0xdf, + 0x90, + 0x30, + 0x29, + 0xe5, + 0x1e, + 0xf0, + 0xb4, + 0x10, + 0x05, + 0x90, + 0x30, + 0x23, + 0xe4, + 0xf0, + 0xc2, + 0x35, + 0x80, + 0xcd, + 0xae, + 0x35, + 0xaf, + 0x36, + 0xe4, + 0xfd, + 0xed, + 0xc3, + 0x95, + 0x37, + 0x50, + 0x33, + 0x12, + 0x0b, + 0x87, + 0xe4, + 0x93, + 0xf5, + 0x38, + 0x74, + 0x01, + 0x93, + 0xf5, + 0x39, + 0x45, + 0x38, + 0x60, + 0x23, + 0x85, + 0x39, + 0x82, + 0x85, + 0x38, + 0x83, + 0xe0, + 0xfc, + 0x12, + 0x0b, + 0x87, + 0x74, + 0x03, + 0x93, + 0x52, + 0x04, + 0x12, + 0x0b, + 0x87, + 0x74, + 0x02, + 0x93, + 0x42, + 0x04, + 0x85, + 0x39, + 0x82, + 0x85, + 0x38, + 0x83, + 0xec, + 0xf0, + 0x0d, + 0x80, + 0xc7, + 0x22, + 0x78, + 0xbb, + 0xe6, + 0xd3, + 0x08, + 0xff, + 0xe6, + 0x64, + 0x80, + 0xf8, + 0xef, + 0x64, + 0x80, + 0x98, + 0x22, + 0x93, + 0xff, + 0x7e, + 0x00, + 0xe6, + 0xfc, + 0x08, + 0xe6, + 0xfd, + 0x12, + 0x02, + 0x97, + 0xac, + 0x06, + 0xad, + 0x07, + 0x78, + 0xb3, + 0xe6, + 0xfe, + 0x08, + 0xe6, + 0x78, + 0x03, + 0x22, + 0x78, + 0xba, + 0xd3, + 0xe6, + 0x64, + 0x80, + 0x94, + 0x80, + 0x22, + 0x25, + 0xe0, + 0x24, + 0x0a, + 0xf8, + 0xe6, + 0xfe, + 0x08, + 0xe6, + 0xff, + 0x22, + 0xa2, + 0xaf, + 0x92, + 0x32, + 0xc2, + 0xaf, + 0xe5, + 0x23, + 0x45, + 0x22, + 0x90, + 0x0e, + 0x5d, + 0x60, + 0x0e, + 0x12, + 0x0b, + 0x70, + 0xe0, + 0xf5, + 0x2c, + 0x12, + 0x0b, + 0x6d, + 0xe0, + 0xf5, + 0x2d, + 0x80, + 0x0c, + 0x12, + 0x0b, + 0x70, + 0xe5, + 0x30, + 0xf0, + 0x12, + 0x0b, + 0x6d, + 0xe5, + 0x31, + 0xf0, + 0xa2, + 0x32, + 0x92, + 0xaf, + 0x22, + 0xd2, + 0x01, + 0xc2, + 0x02, + 0xe4, + 0xf5, + 0x1f, + 0xf5, + 0x1e, + 0xd2, + 0x35, + 0xd2, + 0x33, + 0xd2, + 0x36, + 0xd2, + 0x01, + 0xc2, + 0x02, + 0xf5, + 0x1f, + 0xf5, + 0x1e, + 0xd2, + 0x35, + 0xd2, + 0x33, + 0x22, + 0x2d, + 0xfd, + 0xe4, + 0x33, + 0xfc, + 0xe4, + 0x93, + 0xfe, + 0xfb, + 0xd3, + 0xed, + 0x9b, + 0x74, + 0x80, + 0xf8, + 0x6c, + 0x98, + 0x22, + 0x8f, + 0x3b, + 0x8e, + 0x3a, + 0x8d, + 0x39, + 0x8c, + 0x38, + 0x22, + 0x12, + 0x04, + 0x3f, + 0x8f, + 0x31, + 0x8e, + 0x30, + 0x8d, + 0x2f, + 0x8c, + 0x2e, + 0x22, + 0x93, + 0xf9, + 0xf8, + 0x02, + 0x04, + 0x2c, + 0x90, + 0x0e, + 0x81, + 0x12, + 0x04, + 0x3f, + 0x8f, + 0x46, + 0x8e, + 0x45, + 0x8d, + 0x44, + 0x8c, + 0x43, + 0xd2, + 0x06, + 0x30, + 0x06, + 0x03, + 0xd3, + 0x80, + 0x01, + 0xc3, + 0x92, + 0x0e, + 0x22, + 0xc0, + 0xe0, + 0xc0, + 0x83, + 0xc0, + 0x82, + 0x90, + 0x3f, + 0x0d, + 0xe0, + 0xf5, + 0x33, + 0xe5, + 0x33, + 0xf0, + 0xd0, + 0x82, + 0xd0, + 0x83, + 0xd0, + 0xe0, + 0x32, + 0x90, + 0x0e, + 0x5f, + 0xe4, + 0x93, + 0xfe, + 0x74, + 0x01, + 0x93, + 0xf5, + 0x82, + 0x8e, + 0x83, + 0x22, + 0x78, + 0x7f, + 0xe4, + 0xf6, + 0xd8, + 0xfd, + 0x75, + 0x81, + 0xca, + 0x02, + 0x09, + 0xe1, + 0x8f, + 0x82, + 0x8e, + 0x83, + 0x75, + 0xf0, + 0x04, + 0xed, + 0x02, + 0x04, + 0x68, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x11, + 0x07, + 0x21, + 0x15, + 0x29, + 0x13, + 0x4f, + 0x56, + 0x54, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x01, + 0x10, + 0x00, + 0x56, + 0x40, + 0x1a, + 0x30, + 0x29, + 0x7e, + 0x00, + 0x30, + 0x04, + 0x20, + 0xdf, + 0x30, + 0x05, + 0x40, + 0xbf, + 0x50, + 0x03, + 0x00, + 0xfd, + 0x50, + 0x27, + 0x01, + 0xfe, + 0x60, + 0x00, + 0x11, + 0x00, + 0x3f, + 0x05, + 0x30, + 0x00, + 0x3f, + 0x06, + 0x22, + 0x00, + 0x3f, + 0x01, + 0x2a, + 0x00, + 0x3f, + 0x02, + 0x00, + 0x00, + 0x36, + 0x06, + 0x07, + 0x00, + 0x3f, + 0x0b, + 0x0f, + 0xf0, + 0x00, + 0x00, + 0x00, + 0x00, + 0x30, + 0x01, + 0x40, + 0xbf, + 0x30, + 0x01, + 0x00, + 0xbf, + 0x30, + 0x29, + 0x70, + 0x00, + 0x3a, + 0x00, + 0x00, + 0xff, + 0x3a, + 0x00, + 0x00, + 0xff, + 0x36, + 0x03, + 0x36, + 0x02, + 0x41, + 0x44, + 0x58, + 0x20, + 0x18, + 0x10, + 0x0a, + 0x04, + 0x04, + 0x00, + 0x03, + 0xff, + 0x64, + 0x00, + 0x00, + 0x80, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x02, + 0x04, + 0x06, + 0x00, + 0x03, + 0x98, + 0x00, + 0xcc, + 0x50, + 0x3c, + 0x28, + 0x1e, + 0x10, + 0x10, + 0x00, + 0x00, + 0x00, + 0x6e, + 0x30, + 0x28, + 0x00, + 0xa5, + 0x5a, + 0x00, +}; + +#endif /* CAMSENSOR_OV5640 */ diff --git a/drivers/media/video/msm_zsl/ov7692.c b/drivers/media/video/msm_zsl/ov7692.c new file mode 100644 index 00000000000..7372156fcd3 --- /dev/null +++ b/drivers/media/video/msm_zsl/ov7692.c @@ -0,0 +1,595 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ov7692.h" + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ +#define Q8 0x00000100 + +/* Omnivision8810 product ID register address */ +#define REG_OV7692_MODEL_ID_MSB 0x0A +#define REG_OV7692_MODEL_ID_LSB 0x0B + +#define OV7692_MODEL_ID 0x7692 +/* Omnivision8810 product ID */ + +/* Time in milisecs for waiting for the sensor to reset */ +#define OV7692_RESET_DELAY_MSECS 66 +#define OV7692_DEFAULT_CLOCK_RATE 24000000 +/* Registers*/ + +/* Color bar pattern selection */ +#define OV7692_COLOR_BAR_PATTERN_SEL_REG 0x82 +/* Color bar enabling control */ +#define OV7692_COLOR_BAR_ENABLE_REG 0x601 +/* Time in milisecs for waiting for the sensor to reset*/ +#define OV7692_RESET_DELAY_MSECS 66 + +/*============================================================================ + DATA DECLARATIONS +============================================================================*/ +/* 96MHz PCLK @ 24MHz MCLK */ +struct reg_addr_val_pair_struct ov7692_init_settings_array[] = { + {0x12, 0x80}, + {0x0e, 0x08}, + {0x69, 0x52}, + {0x1e, 0xb3}, + {0x48, 0x42}, + {0xff, 0x01}, + {0xae, 0xa0}, + {0xa8, 0x26}, + {0xb4, 0xc0}, + {0xb5, 0x40}, + {0xff, 0x00}, + {0x0c, 0x00}, + {0x62, 0x10}, + {0x12, 0x00}, + {0x17, 0x65}, + {0x18, 0xa4}, + {0x19, 0x0a}, + {0x1a, 0xf6}, + {0x3e, 0x30}, + {0x64, 0x0a}, + {0xff, 0x01}, + {0xb4, 0xc0}, + {0xff, 0x00}, + {0x67, 0x20}, + {0x81, 0x3f}, + {0xcc, 0x02}, + {0xcd, 0x80}, + {0xce, 0x01}, + {0xcf, 0xe0}, + {0xc8, 0x02}, + {0xc9, 0x80}, + {0xca, 0x01}, + {0xcb, 0xe0}, + {0xd0, 0x48}, + {0x82, 0x03}, + {0x0e, 0x00}, + {0x70, 0x00}, + {0x71, 0x34}, + {0x74, 0x28}, + {0x75, 0x98}, + {0x76, 0x00}, + {0x77, 0x64}, + {0x78, 0x01}, + {0x79, 0xc2}, + {0x7a, 0x4e}, + {0x7b, 0x1f}, + {0x7c, 0x00}, + {0x11, 0x00}, + {0x20, 0x00}, + {0x21, 0x23}, + {0x50, 0x9a}, + {0x51, 0x80}, + {0x4c, 0x7d}, + {0x0e, 0x00}, + {0x80, 0x7f}, + {0x85, 0x10}, + {0x86, 0x00}, + {0x87, 0x00}, + {0x88, 0x00}, + {0x89, 0x2a}, + {0x8a, 0x26}, + {0x8b, 0x22}, + {0xbb, 0x7a}, + {0xbc, 0x69}, + {0xbd, 0x11}, + {0xbe, 0x13}, + {0xbf, 0x81}, + {0xc0, 0x96}, + {0xc1, 0x1e}, + {0xb7, 0x05}, + {0xb8, 0x09}, + {0xb9, 0x00}, + {0xba, 0x18}, + {0x5a, 0x1f}, + {0x5b, 0x9f}, + {0x5c, 0x6a}, + {0x5d, 0x42}, + {0x24, 0x78}, + {0x25, 0x68}, + {0x26, 0xb3}, + {0xa3, 0x0b}, + {0xa4, 0x15}, + {0xa5, 0x2a}, + {0xa6, 0x51}, + {0xa7, 0x63}, + {0xa8, 0x74}, + {0xa9, 0x83}, + {0xaa, 0x91}, + {0xab, 0x9e}, + {0xac, 0xaa}, + {0xad, 0xbe}, + {0xae, 0xce}, + {0xaf, 0xe5}, + {0xb0, 0xf3}, + {0xb1, 0xfb}, + {0xb2, 0x06}, + {0x8c, 0x5c}, + {0x8d, 0x11}, + {0x8e, 0x12}, + {0x8f, 0x19}, + {0x90, 0x50}, + {0x91, 0x20}, + {0x92, 0x96}, + {0x93, 0x80}, + {0x94, 0x13}, + {0x95, 0x1b}, + {0x96, 0xff}, + {0x97, 0x00}, + {0x98, 0x3d}, + {0x99, 0x36}, + {0x9a, 0x51}, + {0x9b, 0x43}, + {0x9c, 0xf0}, + {0x9d, 0xf0}, + {0x9e, 0xf0}, + {0x9f, 0xff}, + {0xa0, 0x68}, + {0xa1, 0x62}, + {0xa2, 0x0e}, +}; + +static bool OV7692_CSI_CONFIG; +/* 816x612, 24MHz MCLK 96MHz PCLK */ +uint32_t OV7692_FULL_SIZE_WIDTH = 640; +uint32_t OV7692_FULL_SIZE_HEIGHT = 480; + +uint32_t OV7692_QTR_SIZE_WIDTH = 640; +uint32_t OV7692_QTR_SIZE_HEIGHT = 480; + +uint32_t OV7692_HRZ_FULL_BLK_PIXELS = 16; +uint32_t OV7692_VER_FULL_BLK_LINES = 12; +uint32_t OV7692_HRZ_QTR_BLK_PIXELS = 16; +uint32_t OV7692_VER_QTR_BLK_LINES = 12; + +struct ov7692_work_t { + struct work_struct work; +}; +static struct ov7692_work_t *ov7692_sensorw; +static struct i2c_client *ov7692_client; +struct ov7692_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + uint32_t sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + uint32_t fps; + int32_t curr_lens_pos; + uint32_t curr_step_pos; + uint32_t my_reg_gain; + uint32_t my_reg_line_count; + uint32_t total_lines_per_frame; + enum ov7692_resolution_t prev_res; + enum ov7692_resolution_t pict_res; + enum ov7692_resolution_t curr_res; + enum ov7692_test_mode_t set_test; + unsigned short imgaddr; +}; +static struct ov7692_ctrl_t *ov7692_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(ov7692_wait_queue); +DEFINE_MUTEX(ov7692_mut); + +/*=============================================================*/ + +static int ov7692_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 1, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 1, + .buf = rxdata, + }, + }; + if (i2c_transfer(ov7692_client->adapter, msgs, 2) < 0) { + CDBG("ov7692_i2c_rxdata failed!\n"); + return -EIO; + } + return 0; +} +static int32_t ov7692_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = txdata, + }, + }; + if (i2c_transfer(ov7692_client->adapter, msg, 1) < 0) { + CDBG("ov7692_i2c_txdata faild 0x%x\n", ov7692_client->addr); + return -EIO; + } + + return 0; +} + +static int32_t ov7692_i2c_read(uint8_t raddr, + uint8_t *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[1]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + buf[0] = raddr; + rc = ov7692_i2c_rxdata(ov7692_client->addr >> 1, buf, rlen); + if (rc < 0) { + CDBG("ov7692_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = buf[0]; + return rc; +} +static int32_t ov7692_i2c_write_b_sensor(uint8_t waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[2]; + memset(buf, 0, sizeof(buf)); + buf[0] = waddr; + buf[1] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata); + rc = ov7692_i2c_txdata(ov7692_client->addr >> 1, buf, 2); + if (rc < 0) + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + return rc; +} + +static int32_t ov7692_sensor_setting(int update_type, int rt) +{ + int32_t i, array_length; + int32_t rc = 0; + struct msm_camera_csi_params ov7692_csi_params; + switch (update_type) { + case REG_INIT: + OV7692_CSI_CONFIG = 0; + ov7692_i2c_write_b_sensor(0x0e, 0x08); + return rc; + break; + case UPDATE_PERIODIC: + if (!OV7692_CSI_CONFIG) { + ov7692_csi_params.lane_cnt = 1; + ov7692_csi_params.data_format = CSI_8BIT; + ov7692_csi_params.lane_assign = 0xe4; + ov7692_csi_params.dpcm_scheme = 0; + ov7692_csi_params.settle_cnt = 0x14; + + rc = msm_camio_csi_config(&ov7692_csi_params); + msleep(10); + array_length = sizeof(ov7692_init_settings_array) / + sizeof(ov7692_init_settings_array[0]); + for (i = 0; i < array_length; i++) { + rc = ov7692_i2c_write_b_sensor( + ov7692_init_settings_array[i].reg_addr, + ov7692_init_settings_array[i].reg_val); + if (rc < 0) + return rc; + } + OV7692_CSI_CONFIG = 1; + msleep(20); + return rc; + } + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +static int32_t ov7692_video_config(int mode) +{ + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + rt = RES_PREVIEW; + + if (ov7692_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + ov7692_ctrl->curr_res = ov7692_ctrl->prev_res; + ov7692_ctrl->sensormode = mode; + return rc; +} + +static int32_t ov7692_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = ov7692_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + break; + default: + rc = -EINVAL; + break; + } + return rc; +} +static int32_t ov7692_power_down(void) +{ + return 0; +} + +static int ov7692_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + uint8_t model_id_msb, model_id_lsb = 0; + uint16_t model_id; + int32_t rc = 0; + /*The reset pin is not physically connected to the sensor. + The standby pin will do the reset hence there is no need + to request the gpio reset*/ + + /* Read sensor Model ID: */ + rc = ov7692_i2c_read(REG_OV7692_MODEL_ID_MSB, &model_id_msb, 1); + if (rc < 0) + goto init_probe_fail; + rc = ov7692_i2c_read(REG_OV7692_MODEL_ID_LSB, &model_id_lsb, 1); + if (rc < 0) + goto init_probe_fail; + model_id = (model_id_msb << 8) | ((model_id_lsb & 0x00FF)) ; + CDBG("ov7692 model_id = 0x%x, 0x%x, 0x%x\n", + model_id, model_id_msb, model_id_lsb); + /* 4. Compare sensor ID to OV7692 ID: */ + if (model_id != OV7692_MODEL_ID) { + rc = -ENODEV; + goto init_probe_fail; + } + goto init_probe_done; +init_probe_fail: + pr_warning(" ov7692_probe_init_sensor fails\n"); +init_probe_done: + CDBG(" ov7692_probe_init_sensor finishes\n"); + return rc; +} + +int ov7692_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + + CDBG("%s: %d\n", __func__, __LINE__); + CDBG("Calling ov7692_sensor_open_init\n"); + ov7692_ctrl = kzalloc(sizeof(struct ov7692_ctrl_t), GFP_KERNEL); + if (!ov7692_ctrl) { + CDBG("ov7692_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + ov7692_ctrl->fps_divider = 1 * 0x00000400; + ov7692_ctrl->pict_fps_divider = 1 * 0x00000400; + ov7692_ctrl->fps = 30 * Q8; + ov7692_ctrl->set_test = TEST_OFF; + ov7692_ctrl->prev_res = QTR_SIZE; + ov7692_ctrl->pict_res = FULL_SIZE; + ov7692_ctrl->curr_res = INVALID_SIZE; + + if (data) + ov7692_ctrl->sensordata = data; + + /* enable mclk first */ + + msm_camio_clk_rate_set(24000000); + msleep(20); + + rc = ov7692_probe_init_sensor(data); + if (rc < 0) { + CDBG("Calling ov7692_sensor_open_init fail\n"); + goto init_fail; + } + + rc = ov7692_sensor_setting(REG_INIT, RES_PREVIEW); + if (rc < 0) + goto init_fail; + else + goto init_done; + +init_fail: + CDBG(" ov7692_sensor_open_init fail\n"); + kfree(ov7692_ctrl); +init_done: + CDBG("ov7692_sensor_open_init done\n"); + return rc; +} + +static int ov7692_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&ov7692_wait_queue); + return 0; +} + +static const struct i2c_device_id ov7692_i2c_id[] = { + {"ov7692", 0}, + { } +}; + +static int ov7692_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("ov7692_i2c_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + ov7692_sensorw = kzalloc(sizeof(struct ov7692_work_t), GFP_KERNEL); + if (!ov7692_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, ov7692_sensorw); + ov7692_init_client(client); + ov7692_client = client; + + CDBG("ov7692_i2c_probe success! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("ov7692_i2c_probe failed! rc = %d\n", rc); + return rc; +} + +static int __exit ov7692_remove(struct i2c_client *client) +{ + struct ov7692_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + ov7692_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver ov7692_i2c_driver = { + .id_table = ov7692_i2c_id, + .probe = ov7692_i2c_probe, + .remove = __exit_p(ov7692_i2c_remove), + .driver = { + .name = "ov7692", + }, +}; + +int ov7692_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&ov7692_mut); + CDBG("ov7692_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_SET_MODE: + rc = ov7692_set_sensor_mode(cdata.mode, + cdata.rs); + break; + case CFG_PWR_DOWN: + rc = ov7692_power_down(); + break; + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&ov7692_mut); + + return rc; +} +static int ov7692_sensor_release(void) +{ + int rc = -EBADF; + mutex_lock(&ov7692_mut); + ov7692_power_down(); + kfree(ov7692_ctrl); + ov7692_ctrl = NULL; + CDBG("ov7692_release completed\n"); + mutex_unlock(&ov7692_mut); + + return rc; +} + +static int ov7692_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(&ov7692_i2c_driver); + if (rc < 0 || ov7692_client == NULL) { + rc = -ENOTSUPP; + goto probe_fail; + } + msm_camio_clk_rate_set(24000000); + rc = ov7692_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + s->s_init = ov7692_sensor_open_init; + s->s_release = ov7692_sensor_release; + s->s_config = ov7692_sensor_config; + s->s_camera_type = FRONT_CAMERA_2D; + s->s_mount_angle = 0; + return rc; + +probe_fail: + CDBG("ov7692_sensor_probe: SENSOR PROBE FAILS!\n"); + i2c_del_driver(&ov7692_i2c_driver); + return rc; +} + +static int __ov7692_probe(struct platform_device *pdev) +{ + + return msm_camera_drv_start(pdev, ov7692_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __ov7692_probe, + .driver = { + .name = "msm_camera_ov7692", + .owner = THIS_MODULE, + }, +}; + +static int __init ov7692_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(ov7692_init); + +MODULE_DESCRIPTION("OMNI VGA YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/ov7692.h b/drivers/media/video/msm_zsl/ov7692.h new file mode 100644 index 00000000000..d8f7114199c --- /dev/null +++ b/drivers/media/video/msm_zsl/ov7692.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ +#ifndef OV7692_H +#define OV7692_H +#include +#include + +struct reg_addr_val_pair_struct { + uint8_t reg_addr; + uint8_t reg_val; +}; + +enum ov7692_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum ov7692_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; + +enum ov7692_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum ov7692_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; +#endif diff --git a/drivers/media/video/msm_zsl/ov7692_qrd.c b/drivers/media/video/msm_zsl/ov7692_qrd.c new file mode 100644 index 00000000000..e558e575c1d --- /dev/null +++ b/drivers/media/video/msm_zsl/ov7692_qrd.c @@ -0,0 +1,679 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +/* #define DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ov7692.h" + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ +#define Q8 0x00000100 + +/* Omnivision8810 product ID register address */ +#define REG_OV7692_MODEL_ID_MSB 0x0A +#define REG_OV7692_MODEL_ID_LSB 0x0B + +#define OV7692_MODEL_ID 0x7692 +/* Omnivision8810 product ID */ + +/* Time in milisecs for waiting for the sensor to reset */ +#define OV7692_RESET_DELAY_MSECS 66 +#define OV7692_DEFAULT_CLOCK_RATE 24000000 +/* Registers*/ + +/* Color bar pattern selection */ +#define OV7692_COLOR_BAR_PATTERN_SEL_REG 0x82 +/* Color bar enabling control */ +#define OV7692_COLOR_BAR_ENABLE_REG 0x601 +/* Time in milisecs for waiting for the sensor to reset*/ +#define OV7692_RESET_DELAY_MSECS 66 + +static int ov7692_pwdn_gpio; +static int ov7692_reset_gpio; + + +/*============================================================================ + DATA DECLARATIONS + ============================================================================*/ +/* 96MHz PCLK @ 24MHz MCLK */ +struct reg_addr_val_pair_struct ov7692_init_settings_array[] = { + {0x12, 0x80}, + {0x0e, 0x08}, + {0x69, 0x52}, + {0x1e, 0xb3}, + {0x48, 0x42}, + {0xff, 0x01}, + {0xae, 0xa0}, + {0xa8, 0x26}, + {0xb4, 0xc0}, + {0xb5, 0x40}, + {0xff, 0x00}, + {0x0c, 0x00}, + {0x62, 0x10}, + {0x12, 0x00}, + {0x17, 0x65}, + {0x18, 0xa4}, + {0x19, 0x0a}, + {0x1a, 0xf6}, + {0x3e, 0x30}, + {0x64, 0x0a}, + {0xff, 0x01}, + {0xb4, 0xc0}, + {0xff, 0x00}, + {0x67, 0x20}, + {0x81, 0x3f}, + {0xcc, 0x02}, + {0xcd, 0x80}, + {0xce, 0x01}, + {0xcf, 0xe0}, + {0xc8, 0x02}, + {0xc9, 0x80}, + {0xca, 0x01}, + {0xcb, 0xe0}, + {0xd0, 0x48}, + {0x82, 0x03}, + {0x0e, 0x00}, + {0x70, 0x00}, + {0x71, 0x34}, + {0x74, 0x28}, + {0x75, 0x98}, + {0x76, 0x00}, + {0x77, 0x64}, + {0x78, 0x01}, + {0x79, 0xc2}, + {0x7a, 0x4e}, + {0x7b, 0x1f}, + {0x7c, 0x00}, + {0x11, 0x00}, + {0x20, 0x00}, + {0x21, 0x23}, + {0x50, 0x9a}, + {0x51, 0x80}, + {0x4c, 0x7d}, + {0x0e, 0x00}, + {0x85, 0x10}, + {0x86, 0x00}, + {0x87, 0x00}, + {0x88, 0x00}, + {0x89, 0x2a}, + {0x8a, 0x26}, + {0x8b, 0x22}, + {0xbb, 0x7a}, + {0xbc, 0x69}, + {0xbd, 0x11}, + {0xbe, 0x13}, + {0xbf, 0x81}, + {0xc0, 0x96}, + {0xc1, 0x1e}, + {0xb7, 0x05}, + {0xb8, 0x09}, + {0xb9, 0x00}, + {0xba, 0x18}, + {0x5a, 0x1f}, + {0x5b, 0x9f}, + {0x5c, 0x6a}, + {0x5d, 0x42}, + {0x24, 0x78}, + {0x25, 0x68}, + {0x26, 0xb3}, + {0xa3, 0x0b}, + {0xa4, 0x15}, + {0xa5, 0x2a}, + {0xa6, 0x51}, + {0xa7, 0x63}, + {0xa8, 0x74}, + {0xa9, 0x83}, + {0xaa, 0x91}, + {0xab, 0x9e}, + {0xac, 0xaa}, + {0xad, 0xbe}, + {0xae, 0xce}, + {0xaf, 0xe5}, + {0xb0, 0xf3}, + {0xb1, 0xfb}, + {0xb2, 0x06}, + {0x8c, 0x5c}, + {0x8d, 0x11}, + {0x8e, 0x12}, + {0x8f, 0x19}, + {0x90, 0x50}, + {0x91, 0x20}, + {0x92, 0x96}, + {0x93, 0x80}, + {0x94, 0x13}, + {0x95, 0x1b}, + {0x96, 0xff}, + {0x97, 0x00}, + {0x98, 0x3d}, + {0x99, 0x36}, + {0x9a, 0x51}, + {0x9b, 0x43}, + {0x9c, 0xf0}, + {0x9d, 0xf0}, + {0x9e, 0xf0}, + {0x9f, 0xff}, + {0xa0, 0x68}, + {0xa1, 0x62}, + {0xa2, 0x0e}, +}; + +static bool OV7692_CSI_CONFIG; +/* 816x612, 24MHz MCLK 96MHz PCLK */ +uint32_t OV7692_FULL_SIZE_WIDTH = 640; +uint32_t OV7692_FULL_SIZE_HEIGHT = 480; + +uint32_t OV7692_QTR_SIZE_WIDTH = 640; +uint32_t OV7692_QTR_SIZE_HEIGHT = 480; + +uint32_t OV7692_HRZ_FULL_BLK_PIXELS = 16; +uint32_t OV7692_VER_FULL_BLK_LINES = 12; +uint32_t OV7692_HRZ_QTR_BLK_PIXELS = 16; +uint32_t OV7692_VER_QTR_BLK_LINES = 12; + +struct ov7692_work_t { + struct work_struct work; +}; +static struct ov7692_work_t *ov7692_sensorw; +static struct i2c_client *ov7692_client; +struct ov7692_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + uint32_t sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + uint32_t fps; + int32_t curr_lens_pos; + uint32_t curr_step_pos; + uint32_t my_reg_gain; + uint32_t my_reg_line_count; + uint32_t total_lines_per_frame; + enum ov7692_resolution_t prev_res; + enum ov7692_resolution_t pict_res; + enum ov7692_resolution_t curr_res; + enum ov7692_test_mode_t set_test; + unsigned short imgaddr; +}; +static struct ov7692_ctrl_t *ov7692_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(ov7692_wait_queue); +DEFINE_MUTEX(ov7692_mut); + +/*=============================================================*/ + +static int ov7692_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 1, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 1, + .buf = rxdata, + }, + }; + if (i2c_transfer(ov7692_client->adapter, msgs, 2) < 0) { + CDBG("ov7692_i2c_rxdata failed!\n"); + return -EIO; + } + return 0; +} +static int32_t ov7692_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = txdata, + }, + }; + if (i2c_transfer(ov7692_client->adapter, msg, 1) < 0) { + CDBG("ov7692_i2c_txdata faild 0x%x\n", ov7692_client->addr); + return -EIO; + } + + return 0; +} + +static int32_t ov7692_i2c_read(uint8_t raddr, + uint8_t *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[1]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + buf[0] = raddr; + rc = ov7692_i2c_rxdata(ov7692_client->addr >> 1, buf, rlen); + if (rc < 0) { + CDBG("ov7692_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = buf[0]; + return rc; +} +static int32_t ov7692_i2c_write_b_sensor(uint8_t waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[2]; + + memset(buf, 0, sizeof(buf)); + buf[0] = waddr; + buf[1] = bdata; + + rc = ov7692_i2c_txdata(ov7692_client->addr >> 1, buf, 2); + if (rc < 0) + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + return rc; +} + +static int32_t ov7692_sensor_setting(int update_type, int rt) +{ + int32_t i, array_length; + int32_t rc = 0; + struct msm_camera_csi_params ov7692_csi_params; + + CDBG("%s: rt = %d\n", __func__, rt); + + switch (update_type) { + case REG_INIT: + OV7692_CSI_CONFIG = 0; + ov7692_i2c_write_b_sensor(0x0e, 0x08); + return rc; + break; + case UPDATE_PERIODIC: + if (!OV7692_CSI_CONFIG) { + ov7692_csi_params.lane_cnt = 1; + ov7692_csi_params.data_format = CSI_8BIT; + ov7692_csi_params.lane_assign = 0xe4; + ov7692_csi_params.dpcm_scheme = 0; + ov7692_csi_params.settle_cnt = 0x14; + + rc = msm_camio_csi_config(&ov7692_csi_params); + msleep(20); + array_length = sizeof(ov7692_init_settings_array) / + sizeof(ov7692_init_settings_array[0]); + for (i = 0; i < array_length; i++) { + rc = ov7692_i2c_write_b_sensor( + ov7692_init_settings_array[i].reg_addr, + ov7692_init_settings_array[i].reg_val); + if (rc < 0) + return rc; + } + OV7692_CSI_CONFIG = 1; + msleep(20); + return rc; + } + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +static int32_t ov7692_video_config(int mode) +{ + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + rt = RES_PREVIEW; + + CDBG("%s\n", __func__); + + if (ov7692_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + ov7692_ctrl->curr_res = ov7692_ctrl->prev_res; + ov7692_ctrl->sensormode = mode; + return rc; +} + +static int32_t ov7692_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = ov7692_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +static void ov7692_power_on(void) +{ + CDBG("%s\n", __func__); + gpio_set_value(ov7692_pwdn_gpio, 0); +} + +static void ov7692_power_down(void) +{ + CDBG("%s\n", __func__); + gpio_set_value(ov7692_pwdn_gpio, 1); +} + +static void ov7692_sw_reset(void) +{ + CDBG("%s\n", __func__); + ov7692_i2c_write_b_sensor(0x12, 0x80); +} + +static void ov7692_hw_reset(void) +{ + CDBG("--CAMERA-- %s ... (Start...)\n", __func__); + gpio_set_value(ov7692_reset_gpio, 1); /* reset camera reset pin */ + msleep(20); + gpio_set_value(ov7692_reset_gpio, 0); + msleep(20); + gpio_set_value(ov7692_reset_gpio, 1); + msleep(20); + + CDBG("--CAMERA-- %s ... (End...)\n", __func__); +} + + + +static int ov7692_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + uint8_t model_id_msb, model_id_lsb = 0; + uint16_t model_id = 0; + int32_t rc = 0; + /*The reset pin is not physically connected to the sensor. + The standby pin will do the reset hence there is no need + to request the gpio reset*/ + + /* Read sensor Model ID: */ + rc = ov7692_i2c_read(REG_OV7692_MODEL_ID_MSB, &model_id_msb, 1); + if (rc < 0) + goto init_probe_fail; + rc = ov7692_i2c_read(REG_OV7692_MODEL_ID_LSB, &model_id_lsb, 1); + if (rc < 0) + goto init_probe_fail; + model_id = (model_id_msb << 8) | ((model_id_lsb & 0x00FF)) ; + CDBG("ov7692 model_id = 0x%x, 0x%x, 0x%x\n", + model_id, model_id_msb, model_id_lsb); + /* 4. Compare sensor ID to OV7692 ID: */ + if (model_id != OV7692_MODEL_ID) { + rc = -ENODEV; + goto init_probe_fail; + } + goto init_probe_done; +init_probe_fail: + pr_warning(" ov7692_probe_init_sensor fails\n"); +init_probe_done: + CDBG(" ov7692_probe_init_sensor finishes\n"); + return rc; +} + +int ov7692_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + + CDBG("%s: %d\n", __func__, __LINE__); + CDBG("Calling ov7692_sensor_open_init\n"); + ov7692_ctrl = kzalloc(sizeof(struct ov7692_ctrl_t), GFP_KERNEL); + if (!ov7692_ctrl) { + CDBG("ov7692_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + ov7692_ctrl->fps_divider = 1 * 0x00000400; + ov7692_ctrl->pict_fps_divider = 1 * 0x00000400; + ov7692_ctrl->fps = 30 * Q8; + ov7692_ctrl->set_test = TEST_OFF; + ov7692_ctrl->prev_res = QTR_SIZE; + ov7692_ctrl->pict_res = FULL_SIZE; + ov7692_ctrl->curr_res = INVALID_SIZE; + + if (data) + ov7692_ctrl->sensordata = data; + + /* enable mclk first */ + + msm_camio_clk_rate_set(24000000); + msleep(20); + + ov7692_power_on(); + msleep(20); + + rc = ov7692_probe_init_sensor(data); + if (rc < 0) { + CDBG("Calling ov7692_sensor_open_init fail\n"); + goto init_fail; + } + + rc = ov7692_sensor_setting(REG_INIT, RES_PREVIEW); + if (rc < 0) + goto init_fail; + else + goto init_done; + +init_fail: + CDBG(" ov7692_sensor_open_init fail\n"); + kfree(ov7692_ctrl); +init_done: + CDBG("ov7692_sensor_open_init done\n"); + return rc; +} + +static int ov7692_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&ov7692_wait_queue); + return 0; +} + +static const struct i2c_device_id ov7692_i2c_id[] = { + {"ov7692", 0}, + { } +}; + +static int ov7692_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("ov7692_i2c_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + ov7692_sensorw = kzalloc(sizeof(struct ov7692_work_t), GFP_KERNEL); + if (!ov7692_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, ov7692_sensorw); + ov7692_init_client(client); + ov7692_client = client; + + CDBG("ov7692_i2c_probe success! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("ov7692_i2c_probe failed! rc = %d\n", rc); + return rc; +} + +static int __exit ov7692_remove(struct i2c_client *client) +{ + struct ov7692_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + ov7692_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver ov7692_i2c_driver = { + .id_table = ov7692_i2c_id, + .probe = ov7692_i2c_probe, + .remove = __exit_p(ov7692_i2c_remove), + .driver = { + .name = "ov7692", + }, +}; + +int ov7692_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&ov7692_mut); + CDBG("ov7692_sensor_config: cfgtype = %d\n", cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_SET_MODE: + rc = ov7692_set_sensor_mode(cdata.mode, + cdata.rs); + break; + case CFG_PWR_DOWN: + ov7692_power_down(); + break; + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&ov7692_mut); + + return rc; +} +static int ov7692_sensor_release(void) +{ + int rc = -EBADF; + mutex_lock(&ov7692_mut); + ov7692_sw_reset(); + ov7692_power_down(); + kfree(ov7692_ctrl); + ov7692_ctrl = NULL; + CDBG("ov7692_release completed\n"); + mutex_unlock(&ov7692_mut); + + return rc; +} + +static int ov7692_probe_init_gpio(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + + ov7692_pwdn_gpio = data->sensor_pwd; + ov7692_reset_gpio = data->sensor_reset ; + + if (data->sensor_reset_enable) + gpio_direction_output(data->sensor_reset, 1); + + gpio_direction_output(data->sensor_pwd, 1); + + return rc; + +} + + +static int ov7692_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(&ov7692_i2c_driver); + if (rc < 0 || ov7692_client == NULL) { + rc = -ENOTSUPP; + goto probe_fail; + } + + rc = ov7692_probe_init_gpio(info); + if (rc < 0) { + CDBG("%s: gpio init failed\n", __func__); + goto probe_fail; + } + + ov7692_power_down(); + + msm_camio_clk_rate_set(24000000); + msleep(20); + + ov7692_power_on(); + msleep(20); + + if (info->sensor_reset_enable) + ov7692_hw_reset(); + else + ov7692_sw_reset(); + + rc = ov7692_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + + + s->s_init = ov7692_sensor_open_init; + s->s_release = ov7692_sensor_release; + s->s_config = ov7692_sensor_config; + s->s_camera_type = FRONT_CAMERA_2D; + s->s_mount_angle = info->sensor_platform_info->mount_angle; + + ov7692_power_down(); + + return rc; + +probe_fail: + CDBG("ov7692_sensor_probe: SENSOR PROBE FAILS!\n"); + i2c_del_driver(&ov7692_i2c_driver); + return rc; +} + +static int __ov7692_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, ov7692_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __ov7692_probe, + .driver = { + .name = "msm_camera_ov7692", + .owner = THIS_MODULE, + }, +}; + +static int __init ov7692_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(ov7692_init); + +MODULE_DESCRIPTION("OMNI VGA YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/ov9726.c b/drivers/media/video/msm_zsl/ov9726.c new file mode 100644 index 00000000000..12def80f9eb --- /dev/null +++ b/drivers/media/video/msm_zsl/ov9726.c @@ -0,0 +1,793 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ov9726.h" + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ +#define OV9726_Q8 0x00000100 +#define OV9726_Q8Shift 8 +#define OV9726_Q10 0x00000400 +#define OV9726_Q10Shift 10 + +/* Omnivision8810 product ID register address */ +#define OV9726_PIDH_REG 0x0000 +#define OV9726_PIDL_REG 0x0001 +/* Omnivision8810 product ID */ +#define OV9726_PID 0x97 +/* Omnivision8810 version */ +#define OV9726_VER 0x26 +/* Time in milisecs for waiting for the sensor to reset */ +#define OV9726_RESET_DELAY_MSECS 66 +#define OV9726_DEFAULT_CLOCK_RATE 24000000 +/* Registers*/ +#define OV9726_GAIN 0x3000 +#define OV9726_AEC_MSB 0x3002 +#define OV9726_AEC_LSB 0x3003 + +/* Color bar pattern selection */ +#define OV9726_COLOR_BAR_PATTERN_SEL_REG 0x600 +/* Color bar enabling control */ +#define OV9726_COLOR_BAR_ENABLE_REG 0x601 +/* Time in milisecs for waiting for the sensor to reset*/ +#define OV9726_RESET_DELAY_MSECS 66 +/* I2C Address of the Sensor */ +/*============================================================================ + DATA DECLARATIONS +============================================================================*/ +#define OV9726_FULL_SIZE_DUMMY_PIXELS 0 +#define OV9726_FULL_SIZE_DUMMY_LINES 0 +#define OV9726_QTR_SIZE_DUMMY_PIXELS 0 +#define OV9726_QTR_SIZE_DUMMY_LINES 0 + +#define OV9726_FULL_SIZE_WIDTH 1296 +#define OV9726_FULL_SIZE_HEIGHT 808 + +#define OV9726_QTR_SIZE_WIDTH 1296 +#define OV9726_QTR_SIZE_HEIGHT 808 + +#define OV9726_HRZ_FULL_BLK_PIXELS 368 +#define OV9726_VER_FULL_BLK_LINES 32 +#define OV9726_HRZ_QTR_BLK_PIXELS 368 +#define OV9726_VER_QTR_BLK_LINES 32 + +#define OV9726_MSB_MASK 0xFF00 +#define OV9726_LSB_MASK 0x00FF + +struct ov9726_work_t { + struct work_struct work; +}; +static struct ov9726_work_t *ov9726_sensorw; +static struct i2c_client *ov9726_client; +struct ov9726_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + uint32_t sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + uint16_t fps; + int16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + enum ov9726_resolution_t prev_res; + enum ov9726_resolution_t pict_res; + enum ov9726_resolution_t curr_res; + enum ov9726_test_mode_t set_test; + unsigned short imgaddr; +}; +static struct ov9726_ctrl_t *ov9726_ctrl; +static int8_t config_not_set = 1; +static DECLARE_WAIT_QUEUE_HEAD(ov9726_wait_queue); +DEFINE_MUTEX(ov9726_mut); + +/*=============================================================*/ +static int ov9726_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + + if (i2c_transfer(ov9726_client->adapter, msgs, 2) < 0) { + CDBG("ov9726_i2c_rxdata failed!\n"); + return -EIO; + } + + return 0; +} + +static int32_t ov9726_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr , + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + if (i2c_transfer(ov9726_client->adapter, msg, 1) < 0) { + CDBG("ov9726_i2c_txdata faild 0x%x\n", ov9726_client->addr); + return -EIO; + } + + return 0; +} + +static int32_t ov9726_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + + if (!rdata) + return -EIO; + + buf[0] = (raddr & OV9726_MSB_MASK) >> 8; + buf[1] = (raddr & OV9726_LSB_MASK); + + rc = ov9726_i2c_rxdata(ov9726_client->addr, buf, rlen); + + if (rc < 0) { + CDBG("ov9726_i2c_read 0x%x failed!\n", raddr); + return rc; + } + + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + return rc; +} + +static int32_t ov9726_i2c_write_b(unsigned short saddr, + unsigned short waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[3]; + + buf[0] = (waddr & OV9726_MSB_MASK) >> 8; + buf[1] = (waddr & OV9726_LSB_MASK); + buf[2] = bdata; + + CDBG("i2c_write_b addr = 0x%x, val = 0x%xd\n", waddr, bdata); + rc = ov9726_i2c_txdata(saddr, buf, 3); + + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + + return rc; +} + +static void ov9726_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + uint32_t divider; /*Q10 */ + uint32_t d1; + uint32_t d2; + uint16_t snapshot_height, preview_height, preview_width, snapshot_width; + if (ov9726_ctrl->prev_res == QTR_SIZE) { + preview_width = OV9726_QTR_SIZE_WIDTH + + OV9726_HRZ_QTR_BLK_PIXELS ; + preview_height = OV9726_QTR_SIZE_HEIGHT + + OV9726_VER_QTR_BLK_LINES ; + } else { + /* full size resolution used for preview. */ + preview_width = OV9726_FULL_SIZE_WIDTH + + OV9726_HRZ_FULL_BLK_PIXELS ; + preview_height = OV9726_FULL_SIZE_HEIGHT + + OV9726_VER_FULL_BLK_LINES ; + } + if (ov9726_ctrl->pict_res == QTR_SIZE) { + snapshot_width = OV9726_QTR_SIZE_WIDTH + + OV9726_HRZ_QTR_BLK_PIXELS ; + snapshot_height = OV9726_QTR_SIZE_HEIGHT + + OV9726_VER_QTR_BLK_LINES ; + } else { + snapshot_width = OV9726_FULL_SIZE_WIDTH + + OV9726_HRZ_FULL_BLK_PIXELS; + snapshot_height = OV9726_FULL_SIZE_HEIGHT + + OV9726_VER_FULL_BLK_LINES; + } + + d1 = (uint32_t)(((uint32_t)preview_height << + OV9726_Q10Shift) / + snapshot_height); + + d2 = (uint32_t)(((uint32_t)preview_width << + OV9726_Q10Shift) / + snapshot_width); + + divider = (uint32_t) (d1 * d2) >> OV9726_Q10Shift; + *pfps = (uint16_t)((uint32_t)(fps * divider) >> OV9726_Q10Shift); +} + +static uint16_t ov9726_get_prev_lines_pf(void) +{ + if (ov9726_ctrl->prev_res == QTR_SIZE) + return OV9726_QTR_SIZE_HEIGHT + OV9726_VER_QTR_BLK_LINES; + else + return OV9726_FULL_SIZE_HEIGHT + OV9726_VER_FULL_BLK_LINES; +} + +static uint16_t ov9726_get_prev_pixels_pl(void) +{ + if (ov9726_ctrl->prev_res == QTR_SIZE) + return OV9726_QTR_SIZE_WIDTH + OV9726_HRZ_QTR_BLK_PIXELS; + else + return OV9726_FULL_SIZE_WIDTH + OV9726_HRZ_FULL_BLK_PIXELS; +} + +static uint16_t ov9726_get_pict_lines_pf(void) +{ + if (ov9726_ctrl->pict_res == QTR_SIZE) + return OV9726_QTR_SIZE_HEIGHT + OV9726_VER_QTR_BLK_LINES; + else + return OV9726_FULL_SIZE_HEIGHT + OV9726_VER_FULL_BLK_LINES; +} + +static uint16_t ov9726_get_pict_pixels_pl(void) +{ + if (ov9726_ctrl->pict_res == QTR_SIZE) + return OV9726_QTR_SIZE_WIDTH + OV9726_HRZ_QTR_BLK_PIXELS; + else + return OV9726_FULL_SIZE_WIDTH + OV9726_HRZ_FULL_BLK_PIXELS; +} + +static uint32_t ov9726_get_pict_max_exp_lc(void) +{ + if (ov9726_ctrl->pict_res == QTR_SIZE) + return (OV9726_QTR_SIZE_HEIGHT + OV9726_VER_QTR_BLK_LINES)*24; + else + return (OV9726_FULL_SIZE_HEIGHT + OV9726_VER_FULL_BLK_LINES)*24; +} + +static int32_t ov9726_set_fps(struct fps_cfg *fps) +{ + int32_t rc = 0; + CDBG("%s: fps->fps_div = %d\n", __func__, fps->fps_div); + /* TODO: Passing of fps_divider from user space has issues. */ + /* ov9726_ctrl->fps_divider = fps->fps_div; */ + ov9726_ctrl->fps_divider = 1 * 0x400; + CDBG("%s: ov9726_ctrl->fps_divider = %d\n", __func__, + ov9726_ctrl->fps_divider); + ov9726_ctrl->pict_fps_divider = fps->pict_fps_div; + ov9726_ctrl->fps = fps->f_mult; + return rc; +} + +static int32_t ov9726_write_exp_gain(uint16_t gain, uint32_t line) +{ + static uint16_t max_legal_gain = 0x00FF; + uint8_t gain_msb, gain_lsb; + uint8_t intg_time_msb, intg_time_lsb; + uint8_t ov9726_offset = 6; + uint8_t line_length_pck_msb, line_length_pck_lsb; + uint16_t line_length_pck, frame_length_lines; + uint32_t line_length_ratio = 1 << OV9726_Q8Shift; + int32_t rc = -1; + CDBG("%s: gain = %d line = %d", __func__, gain, line); + + if (ov9726_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) { + if (ov9726_ctrl->curr_res == QTR_SIZE) { + frame_length_lines = OV9726_QTR_SIZE_HEIGHT + + OV9726_VER_QTR_BLK_LINES; + line_length_pck = OV9726_QTR_SIZE_WIDTH + + OV9726_HRZ_QTR_BLK_PIXELS; + } else { + frame_length_lines = OV9726_FULL_SIZE_HEIGHT + + OV9726_VER_FULL_BLK_LINES; + line_length_pck = OV9726_FULL_SIZE_WIDTH + + OV9726_HRZ_FULL_BLK_PIXELS; + } + if (line > (frame_length_lines - ov9726_offset)) + ov9726_ctrl->fps = (uint16_t) (((uint32_t)30 << + OV9726_Q8Shift) * + (frame_length_lines - ov9726_offset) / line); + else + ov9726_ctrl->fps = (uint16_t) ((uint32_t)30 << + OV9726_Q8Shift); + } else { + frame_length_lines = OV9726_FULL_SIZE_HEIGHT + + OV9726_VER_FULL_BLK_LINES; + line_length_pck = OV9726_FULL_SIZE_WIDTH + + OV9726_HRZ_FULL_BLK_PIXELS; + } + + if (ov9726_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) { + line = (uint32_t) (line * ov9726_ctrl->fps_divider) >> + OV9726_Q10Shift; + } else { + line = (uint32_t) (line * ov9726_ctrl->pict_fps_divider) >> + OV9726_Q10Shift; + } + + /* calculate line_length_ratio */ + if (line > (frame_length_lines - ov9726_offset)) { + line_length_ratio = (line << OV9726_Q8Shift) / + (frame_length_lines - ov9726_offset); + line = frame_length_lines - ov9726_offset; + } else + line_length_ratio = (uint32_t)1 << OV9726_Q8Shift; + + if (gain > max_legal_gain) { + /* range: 0 to 224 */ + gain = max_legal_gain; + } + /* update gain registers */ + gain_msb = (uint8_t) ((gain & 0xFF00) >> 8); + gain_lsb = (uint8_t) (gain & 0x00FF); + /* linear AFR horizontal stretch */ + line_length_pck = (uint16_t) ((line_length_pck * + line_length_ratio) >> OV9726_Q8Shift); + line_length_pck_msb = (uint8_t) ((line_length_pck & 0xFF00) >> 8); + line_length_pck_lsb = (uint8_t) (line_length_pck & 0x00FF); + /* update line count registers */ + intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8); + intg_time_lsb = (uint8_t) (line & 0x00FF); + + rc = ov9726_i2c_write_b(ov9726_client->addr, 0x104, 0x1); + if (rc < 0) + return rc; + + rc = ov9726_i2c_write_b(ov9726_client->addr, 0x204, gain_msb); + if (rc < 0) + return rc; + + rc = ov9726_i2c_write_b(ov9726_client->addr, 0x205, gain_lsb); + if (rc < 0) + return rc; + + rc = ov9726_i2c_write_b(ov9726_client->addr, 0x342, + line_length_pck_msb); + if (rc < 0) + return rc; + + rc = ov9726_i2c_write_b(ov9726_client->addr, 0x343, + line_length_pck_lsb); + if (rc < 0) + return rc; + + rc = ov9726_i2c_write_b(ov9726_client->addr, 0x0202, intg_time_msb); + if (rc < 0) + return rc; + + rc = ov9726_i2c_write_b(ov9726_client->addr, 0x0203, intg_time_lsb); + if (rc < 0) + return rc; + + rc = ov9726_i2c_write_b(ov9726_client->addr, 0x104, 0x0); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t ov9726_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + rc = ov9726_write_exp_gain(gain, line); + return rc; +} + +static int32_t initialize_ov9726_registers(void) +{ + int32_t i; + int32_t rc = 0; + ov9726_ctrl->sensormode = SENSOR_PREVIEW_MODE ; + /* Configure sensor for Preview mode and Snapshot mode */ + CDBG("Initialize_ov9726_registers\n"); + for (i = 0; i < ov9726_array_length; i++) { + rc = ov9726_i2c_write_b(ov9726_client->addr, + ov9726_init_settings_array[i].reg_addr, + ov9726_init_settings_array[i].reg_val); + if (rc < 0) + return rc; + } + return rc; +} + +static int32_t ov9726_video_config(int mode) +{ + int32_t rc = 0; + + ov9726_ctrl->sensormode = mode; + + if (config_not_set) { + struct msm_camera_csi_params ov9726_csi_params; + + /* sensor in standby */ + ov9726_i2c_write_b(ov9726_client->addr, 0x100, 0); + msleep(5); + /* Initialize Sensor registers */ + ov9726_csi_params.data_format = CSI_10BIT; + ov9726_csi_params.lane_cnt = 1; + ov9726_csi_params.lane_assign = 0xe4; + ov9726_csi_params.dpcm_scheme = 0; + ov9726_csi_params.settle_cnt = 7; + + rc = msm_camio_csi_config(&ov9726_csi_params); + rc = initialize_ov9726_registers(); + config_not_set = 0; + } + return rc; +} + +static int32_t ov9726_snapshot_config(int mode) +{ + int32_t rc = 0; + ov9726_ctrl->sensormode = mode; + return rc; +} + +static int32_t ov9726_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + ov9726_ctrl->sensormode = mode; + return rc; +} + +static int32_t ov9726_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = ov9726_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + rc = ov9726_snapshot_config(mode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + rc = ov9726_raw_snapshot_config(mode); + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +static int ov9726_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + uint16_t chipidl, chipidh; + + if (data->sensor_reset_enable) { + rc = gpio_request(data->sensor_reset, "ov9726"); + if (!rc) { + gpio_direction_output(data->sensor_reset, 0); + gpio_set_value_cansleep(data->sensor_reset, 1); + msleep(20); + } else + goto init_probe_done; + } + /* 3. Read sensor Model ID: */ + rc = ov9726_i2c_read(OV9726_PIDH_REG, &chipidh, 1); + if (rc < 0) + goto init_probe_fail; + rc = ov9726_i2c_read(OV9726_PIDL_REG, &chipidl, 1); + if (rc < 0) + goto init_probe_fail; + CDBG("kov9726 model_id = 0x%x 0x%x\n", chipidh, chipidl); + /* 4. Compare sensor ID to OV9726 ID: */ + if (chipidh != OV9726_PID) { + rc = -ENODEV; + printk(KERN_INFO "Probeinit fail\n"); + goto init_probe_fail; + } + CDBG("chipidh == OV9726_PID\n"); + msleep(OV9726_RESET_DELAY_MSECS); + CDBG("after delay\n"); + goto init_probe_done; + +init_probe_fail: + if (data->sensor_reset_enable) { + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + } +init_probe_done: + printk(KERN_INFO " ov9726_probe_init_sensor finishes\n"); + return rc; +} + +int ov9726_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + + CDBG("Calling ov9726_sensor_open_init\n"); + ov9726_ctrl = kzalloc(sizeof(struct ov9726_ctrl_t), GFP_KERNEL); + if (!ov9726_ctrl) { + CDBG("ov9726_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + ov9726_ctrl->curr_lens_pos = -1; + ov9726_ctrl->fps_divider = 1 << OV9726_Q10Shift; + ov9726_ctrl->pict_fps_divider = 1 << OV9726_Q10Shift; + ov9726_ctrl->set_test = TEST_OFF; + ov9726_ctrl->prev_res = FULL_SIZE; + ov9726_ctrl->pict_res = FULL_SIZE; + ov9726_ctrl->curr_res = INVALID_SIZE; + config_not_set = 1; + if (data) + ov9726_ctrl->sensordata = data; + /* enable mclk first */ + msm_camio_clk_rate_set(OV9726_DEFAULT_CLOCK_RATE); + msleep(20); + rc = ov9726_probe_init_sensor(data); + if (rc < 0) + goto init_fail; + + ov9726_ctrl->fps = (uint16_t)(30 << OV9726_Q8Shift); + /* generate test pattern */ + if (rc < 0) + goto init_fail; + else + goto init_done; + /* reset the driver state */ +init_fail: + CDBG(" init_fail\n"); + kfree(ov9726_ctrl); +init_done: + CDBG("init_done\n"); + return rc; +} + +static int ov9726_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&ov9726_wait_queue); + return 0; +} + +static const struct i2c_device_id ov9726_i2c_id[] = { + { "ov9726", 0}, + { } +}; + +static int ov9726_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("ov9726_probe called!\n"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + ov9726_sensorw = kzalloc(sizeof(struct ov9726_work_t), GFP_KERNEL); + if (!ov9726_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + i2c_set_clientdata(client, ov9726_sensorw); + ov9726_init_client(client); + ov9726_client = client; + msleep(50); + CDBG("ov9726_probe successed! rc = %d\n", rc); + return 0; +probe_failure: + CDBG("ov9726_probe failed! rc = %d\n", rc); + return rc; +} + +static int __exit ov9726_remove(struct i2c_client *client) +{ + struct ov9726_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + ov9726_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver ov9726_i2c_driver = { + .id_table = ov9726_i2c_id, + .probe = ov9726_i2c_probe, + .remove = __exit_p(ov9726_i2c_remove), + .driver = { + .name = "ov9726", + }, +}; + +int ov9726_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&ov9726_mut); + CDBG("ov9726_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + ov9726_get_pict_fps(cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = ov9726_get_prev_lines_pf(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = ov9726_get_prev_pixels_pl(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = ov9726_get_pict_lines_pf(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + ov9726_get_pict_pixels_pl(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = ov9726_get_pict_max_exp_lc(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = ov9726_set_fps(&(cdata.cfg.fps)); + break; + case CFG_SET_EXP_GAIN: + rc = ov9726_write_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + case CFG_SET_PICT_EXP_GAIN: + rc = ov9726_set_pict_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + case CFG_SET_MODE: + rc = ov9726_set_sensor_mode(cdata.mode, + cdata.rs); + break; + case CFG_PWR_DOWN: + case CFG_MOVE_FOCUS: + case CFG_SET_DEFAULT_FOCUS: + rc = 0; + break; + case CFG_SET_EFFECT: + default: + rc = -EFAULT; + break; + } + mutex_unlock(&ov9726_mut); + return rc; +} + +static int ov9726_probe_init_done(const struct msm_camera_sensor_info *data) +{ + if (data->sensor_reset_enable) { + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + } + return 0; +} + +static int ov9726_sensor_release(void) +{ + int rc = -EBADF; + mutex_lock(&ov9726_mut); + if (ov9726_ctrl->sensordata->sensor_reset_enable) { + gpio_direction_output( + ov9726_ctrl->sensordata->sensor_reset, 0); + gpio_free(ov9726_ctrl->sensordata->sensor_reset); + } + kfree(ov9726_ctrl); + ov9726_ctrl = NULL; + CDBG("ov9726_release completed\n"); + mutex_unlock(&ov9726_mut); + return rc; +} + +static int ov9726_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + + rc = i2c_add_driver(&ov9726_i2c_driver); + if (rc < 0 || ov9726_client == NULL) { + rc = -ENOTSUPP; + goto probe_fail; + } + msm_camio_clk_rate_set(24000000); + msleep(20); + rc = ov9726_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + + s->s_init = ov9726_sensor_open_init; + s->s_release = ov9726_sensor_release; + s->s_config = ov9726_sensor_config; + s->s_camera_type = FRONT_CAMERA_2D; + s->s_mount_angle = info->sensor_platform_info->mount_angle; + ov9726_probe_init_done(info); + + return rc; + +probe_fail: + CDBG("SENSOR PROBE FAILS!\n"); + return rc; +} + +static int __ov9726_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, ov9726_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __ov9726_probe, + .driver = { + .name = "msm_camera_ov9726", + .owner = THIS_MODULE, + }, +}; + +static int __init ov9726_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(ov9726_init); +void ov9726_exit(void) +{ + i2c_del_driver(&ov9726_i2c_driver); +} + +MODULE_DESCRIPTION("OMNI VGA Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/ov9726.h b/drivers/media/video/msm_zsl/ov9726.h new file mode 100644 index 00000000000..22360f008a9 --- /dev/null +++ b/drivers/media/video/msm_zsl/ov9726.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef OV9726_H +#define OV9726_H +#include +#include + +/* 16bit address - 8 bit context register structure */ +struct reg_struct_type { + uint16_t reg_addr; + unsigned char reg_val; +}; + +enum ov9726_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum ov9726_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +extern struct reg_struct_type ov9726_init_settings_array[]; +extern int32_t ov9726_array_length; +#endif diff --git a/drivers/media/video/msm_zsl/ov9726_reg.c b/drivers/media/video/msm_zsl/ov9726_reg.c new file mode 100644 index 00000000000..1ba7c043231 --- /dev/null +++ b/drivers/media/video/msm_zsl/ov9726_reg.c @@ -0,0 +1,100 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "ov9726.h" +struct reg_struct_type ov9726_init_settings_array[] = { + {0x0103, 0x01}, /* SOFTWARE_RESET */ + {0x3026, 0x00}, /* OUTPUT_SELECT01 */ + {0x3027, 0x00}, /* OUTPUT_SELECT02 */ + {0x3002, 0xe8}, /* IO_CTRL00 */ + {0x3004, 0x03}, /* IO_CTRL01 */ + {0x3005, 0xff}, /* IO_CTRL02 */ + {0x3703, 0x42}, + {0x3704, 0x10}, + {0x3705, 0x45}, + {0x3603, 0xaa}, + {0x3632, 0x2f}, + {0x3620, 0x66}, + {0x3621, 0xc0}, + {0x0340, 0x03}, /* FRAME_LENGTH_LINES_HI */ + {0x0341, 0xC1}, /* FRAME_LENGTH_LINES_LO */ + {0x0342, 0x06}, /* LINE_LENGTH_PCK_HI */ + {0x0343, 0x80}, /* LINE_LENGTH_PCK_LO */ + {0x0202, 0x03}, /* COARSE_INTEGRATION_TIME_HI */ + {0x0203, 0x43}, /* COARSE_INTEGRATION_TIME_LO */ + {0x3833, 0x04}, + {0x3835, 0x02}, + {0x4702, 0x04}, + {0x4704, 0x00}, /* DVP_CTRL01 */ + {0x4706, 0x08}, + {0x5052, 0x01}, + {0x3819, 0x6e}, + {0x3817, 0x94}, + {0x3a18, 0x00}, /* AEC_GAIN_CEILING_HI */ + {0x3a19, 0x7f}, /* AEC_GAIN_CEILING_LO */ + {0x404e, 0x7e}, + {0x3631, 0x52}, + {0x3633, 0x50}, + {0x3630, 0xd2}, + {0x3604, 0x08}, + {0x3601, 0x40}, + {0x3602, 0x14}, + {0x3610, 0xa0}, + {0x3612, 0x20}, + {0x034c, 0x05}, /* X_OUTPUT_SIZE_HI */ + {0x034d, 0x10}, /* X_OUTPUT_SIZE_LO */ + {0x034e, 0x03}, /* Y_OUTPUT_SIZE_HI */ + {0x034f, 0x28}, /* Y_OUTPUT_SIZE_LO */ + {0x0340, 0x03}, /* FRAME_LENGTH_LINES_HI */ + {0x0341, 0xC1}, /* FRAME_LENGTH_LINES_LO */ + {0x0342, 0x06}, /* LINE_LENGTH_PCK_HI */ + {0x0343, 0x80}, /* LINE_LENGTH_PCK_LO */ + {0x0202, 0x03}, /* COARSE_INTEGRATION_TIME_HI */ + {0x0203, 0x43}, /* COARSE_INTEGRATION_TIME_LO */ + {0x0303, 0x01}, /* VT_SYS_CLK_DIV_LO */ + {0x3002, 0x00}, /* IO_CTRL00 */ + {0x3004, 0x00}, /* IO_CTRL01 */ + {0x3005, 0x00}, /* IO_CTRL02 */ + {0x4801, 0x0f}, /* MIPI_CTRL01 */ + {0x4803, 0x05}, /* MIPI_CTRL03 */ + {0x4601, 0x16}, /* VFIFO_READ_CONTROL */ + {0x3014, 0x05}, /* SC_CMMN_MIPI / SC_CTRL00 */ + {0x3104, 0x80}, + {0x0305, 0x04}, /* PRE_PLL_CLK_DIV_LO */ + {0x0307, 0x64}, /* PLL_MULTIPLIER_LO */ + {0x300c, 0x02}, + {0x300d, 0x20}, + {0x300e, 0x01}, + {0x3010, 0x01}, + {0x460e, 0x81}, /* VFIFO_CONTROL00 */ + {0x0101, 0x01}, /* IMAGE_ORIENTATION */ + {0x3707, 0x14}, + {0x3622, 0x9f}, + {0x5047, 0x3D}, /* ISP_CTRL47 */ + {0x4002, 0x45}, /* BLC_CTRL02 */ + {0x5000, 0x06}, /* ISP_CTRL0 */ + {0x5001, 0x00}, /* ISP_CTRL1 */ + {0x3406, 0x00}, /* AWB_MANUAL_CTRL */ + {0x3503, 0x13}, /* AEC_ENABLE */ + {0x4005, 0x18}, /* BLC_CTRL05 */ + {0x4837, 0x21}, + {0x0100, 0x01}, /* MODE_SELECT */ + {0x3a0f, 0x64}, /* AEC_CTRL0F */ + {0x3a10, 0x54}, /* AEC_CTRL10 */ + {0x3a11, 0xc2}, /* AEC_CTRL11 */ + {0x3a1b, 0x64}, /* AEC_CTRL1B */ + {0x3a1e, 0x54}, /* AEC_CTRL1E */ + {0x3a1a, 0x05}, /* AEC_DIFF_MAX */ +}; +int32_t ov9726_array_length = sizeof(ov9726_init_settings_array) / + sizeof(ov9726_init_settings_array[0]); diff --git a/drivers/media/video/msm_zsl/pm_qos_params.h b/drivers/media/video/msm_zsl/pm_qos_params.h new file mode 100644 index 00000000000..a7d87f911ca --- /dev/null +++ b/drivers/media/video/msm_zsl/pm_qos_params.h @@ -0,0 +1,38 @@ +#ifndef _LINUX_PM_QOS_PARAMS_H +#define _LINUX_PM_QOS_PARAMS_H +/* interface for the pm_qos_power infrastructure of the linux kernel. + * + * Mark Gross + */ +#include +#include +#include + +#define PM_QOS_RESERVED 0 +#define PM_QOS_CPU_DMA_LATENCY 1 +#define PM_QOS_NETWORK_LATENCY 2 +#define PM_QOS_NETWORK_THROUGHPUT 3 + +#define PM_QOS_NUM_CLASSES 4 +#define PM_QOS_DEFAULT_VALUE -1 + +#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) +#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) +#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 + +struct pm_qos_request_list { + struct plist_node list; + int pm_qos_class; +}; + +void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value); +void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req, + s32 new_value); +void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req); + +int pm_qos_request(int pm_qos_class); +int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier); +int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier); +int pm_qos_request_active(struct pm_qos_request_list *req); + +#endif diff --git a/drivers/media/video/msm_zsl/qs_s5k4e1.c b/drivers/media/video/msm_zsl/qs_s5k4e1.c new file mode 100644 index 00000000000..64db015d63b --- /dev/null +++ b/drivers/media/video/msm_zsl/qs_s5k4e1.c @@ -0,0 +1,1822 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qs_s5k4e1.h" +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD_OFF 0x00 +#define GROUPED_PARAMETER_HOLD 0x01 +/* Integration Time */ +#define REG_COARSE_INTEGRATION_TIME 0x0202 +/* Gain */ +#define REG_GLOBAL_GAIN 0x0204 +#define REG_GR_GAIN 0x020E +#define REG_R_GAIN 0x0210 +#define REG_B_GAIN 0x0212 +#define REG_GB_GAIN 0x0214 +/* PLL registers */ +#define REG_FRAME_LENGTH_LINES 0x0340 +#define REG_LINE_LENGTH_PCK 0x0342 +/* Test Pattern */ +#define REG_TEST_PATTERN_MODE 0x0601 +#define REG_VCM_NEW_CODE 0x30F2 +#define AF_ADDR 0x18 +#define BRIDGE_ADDR 0x80 +/*============================================================================ + TYPE DECLARATIONS +============================================================================*/ + +/* 16bit address - 8 bit context register structure */ +#define Q8 0x00000100 +#define Q10 0x00000400 +#define QS_S5K4E1_MASTER_CLK_RATE 24000000 +#define QS_S5K4E1_OFFSET 8 + +/* AF Total steps parameters */ +#define QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR 32 +#define QS_S5K4E1_TOTAL_STEPS_3D 32 + +uint16_t qs_s5k4e1_step_position_table[QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR+1]; +uint16_t qs_s5k4e1_step_position_table_left[QS_S5K4E1_TOTAL_STEPS_3D+1]; +uint16_t qs_s5k4e1_step_position_table_right[QS_S5K4E1_TOTAL_STEPS_3D+1]; +uint16_t qs_s5k4e1_nl_region_boundary1; +uint16_t qs_s5k4e1_nl_region_code_per_step1 = 190; +uint16_t qs_s5k4e1_l_region_code_per_step = 8; +uint16_t qs_s5k4e1_damping_threshold = 10; +uint16_t qs_s5k4e1_sw_damping_time_wait = 8; +uint16_t qs_s5k4e1_af_mode = 4; +int16_t qs_s5k4e1_af_initial_code = 190; +int16_t qs_s5k4e1_af_right_adjust; + +struct qs_s5k4e1_work_t { + struct work_struct work; +}; + +static struct qs_s5k4e1_work_t *qs_s5k4e1_sensorw; +static struct i2c_client *qs_s5k4e1_client; +static char lens_eeprom_data[864]; +static bool cali_data_status; +struct qs_s5k4e1_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + + uint32_t sensormode; + uint32_t fps_divider;/* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */ + uint16_t fps; + + uint16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + + enum qs_s5k4e1_resolution_t prev_res; + enum qs_s5k4e1_resolution_t pict_res; + enum qs_s5k4e1_resolution_t curr_res; + enum qs_s5k4e1_test_mode_t set_test; + enum qs_s5k4e1_cam_mode_t cam_mode; +}; + +static uint16_t prev_line_length_pck; +static uint16_t prev_frame_length_lines; +static uint16_t snap_line_length_pck; +static uint16_t snap_frame_length_lines; + +static bool CSI_CONFIG, LENS_SHADE_CONFIG, default_lens_shade; +static struct qs_s5k4e1_ctrl_t *qs_s5k4e1_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(qs_s5k4e1_wait_queue); +DEFINE_MUTEX(qs_s5k4e1_mut); + +static int cam_debug_init(void); +static struct dentry *debugfs_base; +/*=============================================================*/ + +static int qs_s5k4e1_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + if (i2c_transfer(qs_s5k4e1_client->adapter, msgs, 2) < 0) { + CDBG("qs_s5k4e1_i2c_rxdata faild 0x%x\n", saddr); + return -EIO; + } + return 0; +} + +static int32_t qs_s5k4e1_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(qs_s5k4e1_client->adapter, msg, 1) < 0) { + CDBG("qs_s5k4e1_i2c_txdata faild 0x%x\n", saddr); + return -EIO; + } + + return 0; +} + +static int32_t qs_s5k4e1_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + rc = qs_s5k4e1_i2c_rxdata(qs_s5k4e1_client->addr>>1, buf, rlen); + if (rc < 0) { + CDBG("qs_s5k4e1_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + CDBG("qs_s5k4e1_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata); + return rc; +} + +static int32_t qs_s5k4e1_i2c_write_w_sensor(unsigned short waddr, + uint16_t wdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[4]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00) >> 8; + buf[3] = (wdata & 0x00FF); + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata); + rc = qs_s5k4e1_i2c_txdata(qs_s5k4e1_client->addr>>1, buf, 4); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + } + return rc; +} + +static int32_t qs_s5k4e1_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[3]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata); + rc = qs_s5k4e1_i2c_txdata(qs_s5k4e1_client->addr>>1, buf, 3); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + return rc; +} + +static int32_t qs_s5k4e1_i2c_write_b_table(struct qs_s5k4e1_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + for (i = 0; i < num; i++) { + rc = qs_s5k4e1_i2c_write_b_sensor(reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +static int32_t qs_s5k4e1_i2c_write_seq_sensor(unsigned short waddr, + unsigned char *seq_data, int len) +{ + int32_t rc = -EFAULT; + unsigned char buf[len+2]; + int i = 0; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + for (i = 0; i < len; i++) + buf[i+2] = seq_data[i]; + rc = qs_s5k4e1_i2c_txdata(qs_s5k4e1_client->addr>>1, buf, len+2); + return rc; +} + +static int32_t af_i2c_write_b_sensor(unsigned short baddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[2]; + memset(buf, 0, sizeof(buf)); + buf[0] = baddr; + buf[1] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", baddr, bdata); + rc = qs_s5k4e1_i2c_txdata(AF_ADDR>>1, buf, 2); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + baddr, bdata); + } + return rc; +} + +static int32_t bridge_i2c_write_w(unsigned short waddr, uint16_t wdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[4]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00) >> 8; + buf[3] = (wdata & 0x00FF); + CDBG("bridge_i2c_write_w addr = 0x%x, val = 0x%x\n", waddr, wdata); + rc = qs_s5k4e1_i2c_txdata(BRIDGE_ADDR>>1, buf, 4); + if (rc < 0) { + CDBG("bridge_i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + } + return rc; +} + +static int32_t bridge_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + rc = qs_s5k4e1_i2c_rxdata(BRIDGE_ADDR>>1, buf, rlen); + if (rc < 0) { + CDBG("bridge_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + CDBG("bridge_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata); + return rc; +} + +static int32_t qs_s5k4e1_eeprom_i2c_read(unsigned short raddr, + unsigned char *rdata, int rlen) +{ + int32_t rc = 0; + unsigned short i2caddr = 0xA0 >> 1; + unsigned char buf[rlen]; + int i = 0; + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + rc = qs_s5k4e1_i2c_rxdata(i2caddr, buf, rlen); + if (rc < 0) { + CDBG("qs_s5k4e1_eeprom_i2c_read 0x%x failed!\n", raddr); + return rc; + } + for (i = 0; i < rlen; i++) { + rdata[i] = buf[i]; + CDBG("qs_s5k4e1_eeprom_i2c_read 0x%x index: %d val = 0x%x!\n", + raddr, i, buf[i]); + } + return rc; +} + +static int32_t qs_s5k4e1_eeprom_i2c_read_b(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + rc = qs_s5k4e1_eeprom_i2c_read(raddr, &buf[0], rlen); + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + CDBG("qs_s5k4e1_eeprom_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata); + return rc; +} + +static int32_t qs_s5k4e1_get_calibration_data( + struct sensor_3d_cali_data_t *cdata) +{ + int32_t rc = 0; + cali_data_status = 1; + rc = qs_s5k4e1_eeprom_i2c_read(0x0, + &(cdata->left_p_matrix[0][0][0]), 96); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read(0x60, + &(cdata->right_p_matrix[0][0][0]), 96); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read(0xC0, &(cdata->square_len[0]), 8); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read(0xC8, &(cdata->focal_len[0]), 8); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read(0xD0, &(cdata->pixel_pitch[0]), 8); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x100, &(cdata->left_r), 1); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x101, &(cdata->right_r), 1); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x102, &(cdata->left_b), 1); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x103, &(cdata->right_b), 1); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x104, &(cdata->left_gb), 1); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x105, &(cdata->right_gb), 1); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x110, &(cdata->left_af_far), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x112, &(cdata->right_af_far), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x114, &(cdata->left_af_mid), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x116, &(cdata->right_af_mid), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x118, &(cdata->left_af_short), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x11A, &(cdata->right_af_short), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x11C, &(cdata->left_af_5um), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x11E, &(cdata->right_af_5um), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x120, &(cdata->left_af_50up), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x122, &(cdata->right_af_50up), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x124, &(cdata->left_af_50down), 2); + if (rc < 0) + goto fail; + rc = qs_s5k4e1_eeprom_i2c_read_b(0x126, &(cdata->right_af_50down), 2); + if (rc < 0) + goto fail; + + return 0; + +fail: + cali_data_status = 0; + return -EIO; + +} +static int32_t qs_s5k4e1_write_left_lsc(char *left_lsc, int rt) +{ + struct qs_s5k4e1_i2c_reg_conf *ptr = (struct qs_s5k4e1_i2c_reg_conf *) + (qs_s5k4e1_regs.reg_lens + rt); + bridge_i2c_write_w(0x06, 0x02); + if (!LENS_SHADE_CONFIG) { + qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x40); + qs_s5k4e1_i2c_write_b_table(ptr, qs_s5k4e1_regs.reg_lens_size); + if (default_lens_shade) + qs_s5k4e1_i2c_write_b_table(qs_s5k4e1_regs. + reg_default_lens, qs_s5k4e1_regs.reg_default_lens_size); + else { + qs_s5k4e1_i2c_write_seq_sensor(0x3200, + &left_lsc[0], 216); + qs_s5k4e1_i2c_write_seq_sensor(0x32D8, + &left_lsc[216], 216); + } + qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x60); + qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x40); + } else + qs_s5k4e1_i2c_write_b_table(ptr, qs_s5k4e1_regs.reg_lens_size); + return 0; +} + +static int32_t qs_s5k4e1_write_right_lsc(char *right_lsc, int rt) +{ + struct qs_s5k4e1_i2c_reg_conf *ptr = (struct qs_s5k4e1_i2c_reg_conf *) + (qs_s5k4e1_regs.reg_lens + rt); + bridge_i2c_write_w(0x06, 0x01); + if (!LENS_SHADE_CONFIG) { + qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x40); + qs_s5k4e1_i2c_write_b_table(ptr, qs_s5k4e1_regs.reg_lens_size); + if (default_lens_shade) + qs_s5k4e1_i2c_write_b_table(qs_s5k4e1_regs. + reg_default_lens, qs_s5k4e1_regs.reg_default_lens_size); + else { + qs_s5k4e1_i2c_write_seq_sensor(0x3200, + &right_lsc[0], 216); + qs_s5k4e1_i2c_write_seq_sensor(0x32D8, + &right_lsc[216], 216); + } + qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x60); + qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x40); + } else + qs_s5k4e1_i2c_write_b_table(ptr, qs_s5k4e1_regs.reg_lens_size); + return 0; +} + +static int32_t qs_s5k4e1_write_lsc(char *lsc, int rt) +{ + if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) { + qs_s5k4e1_write_left_lsc(&lsc[0], rt); + qs_s5k4e1_write_right_lsc(&lsc[432], rt); + bridge_i2c_write_w(0x06, 0x03); + } else if (qs_s5k4e1_ctrl->cam_mode == MODE_2D_LEFT) + qs_s5k4e1_write_left_lsc(&lsc[0], rt); + else if (qs_s5k4e1_ctrl->cam_mode == MODE_2D_RIGHT) + qs_s5k4e1_write_right_lsc(&lsc[432], rt); + return 0; +} + +static int32_t qs_s5k4e1_read_left_lsc(char *left_lsc) +{ + qs_s5k4e1_eeprom_i2c_read(0x200, &left_lsc[0], 216); + qs_s5k4e1_eeprom_i2c_read(0x2D8, &left_lsc[216], 216); + return 0; +} + +static int32_t qs_s5k4e1_read_right_lsc(char *right_lsc) +{ + qs_s5k4e1_eeprom_i2c_read(0x3B0, &right_lsc[0], 216); + qs_s5k4e1_eeprom_i2c_read(0x488, &right_lsc[216], 216); + return 0; +} + +static int32_t qs_s5k4e1_read_lsc(char *lsc) +{ + qs_s5k4e1_read_left_lsc(&lsc[0]); + qs_s5k4e1_read_right_lsc(&lsc[432]); + return 0; +} + +static int32_t qs_s5k4e1_bridge_reset(void){ + unsigned short RegData = 0, GPIOInState = 0; + int32_t rc = 0; + rc = bridge_i2c_write_w(0x50, 0x00); + if (rc < 0) + goto bridge_fail; + rc = bridge_i2c_write_w(0x53, 0x00); + if (rc < 0) + goto bridge_fail; + msleep(30); + rc = bridge_i2c_write_w(0x53, 0x01); + if (rc < 0) + goto bridge_fail; + msleep(30); + rc = bridge_i2c_write_w(0x0E, 0xFFFF); + if (rc < 0) + goto err; + rc = bridge_i2c_read(0x54, &RegData, 2); + if (rc < 0) + goto err; + rc = bridge_i2c_write_w(0x54, (RegData | 0x1)); + if (rc < 0) + goto err; + msleep(30); + rc = bridge_i2c_read(0x54, &RegData, 2); + if (rc < 0) + goto err; + rc = bridge_i2c_write_w(0x54, (RegData | 0x4)); + if (rc < 0) + goto err; + rc = bridge_i2c_read(0x55, &GPIOInState, 2); + if (rc < 0) + goto err; + rc = bridge_i2c_write_w(0x55, (GPIOInState | 0x1)); + if (rc < 0) + goto err; + msleep(30); + rc = bridge_i2c_read(0x55, &GPIOInState, 2); + if (rc < 0) + goto err; + rc = bridge_i2c_write_w(0x55, (GPIOInState | 0x4)); + if (rc < 0) + goto err; + msleep(30); + rc = bridge_i2c_read(0x55, &GPIOInState, 2); + if (rc < 0) + goto err; + GPIOInState = ((GPIOInState >> 4) & 0x1); + + rc = bridge_i2c_read(0x08, &GPIOInState, 2); + if (rc < 0) + goto err; + rc = bridge_i2c_write_w(0x08, GPIOInState | 0x4000); + if (rc < 0) + goto err; + return rc; + +err: + bridge_i2c_write_w(0x53, 0x00); + msleep(30); + +bridge_fail: + return rc; + +} + +static void qs_s5k4e1_bridge_config(int mode, int rt) +{ + unsigned short RegData = 0; + if (mode == MODE_3D) { + bridge_i2c_read(0x54, &RegData, 2); + bridge_i2c_write_w(0x54, (RegData | 0x2)); + bridge_i2c_write_w(0x54, (RegData | 0xa)); + bridge_i2c_read(0x55, &RegData, 2); + bridge_i2c_write_w(0x55, (RegData | 0x2)); + bridge_i2c_write_w(0x55, (RegData | 0xa)); + bridge_i2c_write_w(0x14, 0x0C); + msleep(20); + bridge_i2c_write_w(0x16, 0x00); + bridge_i2c_write_w(0x51, 0x3); + bridge_i2c_write_w(0x52, 0x1); + bridge_i2c_write_w(0x06, 0x03); + bridge_i2c_write_w(0x04, 0x2018); + bridge_i2c_write_w(0x50, 0x00); + } else if (mode == MODE_2D_RIGHT) { + bridge_i2c_read(0x54, &RegData, 2); + RegData |= 0x2; + bridge_i2c_write_w(0x54, RegData); + bridge_i2c_write_w(0x54, (RegData & ~(0x8))); + bridge_i2c_read(0x55, &RegData, 2); + RegData |= 0x2; + bridge_i2c_write_w(0x55, RegData); + bridge_i2c_write_w(0x55, (RegData & ~(0x8))); + bridge_i2c_write_w(0x14, 0x04); + msleep(20); + bridge_i2c_write_w(0x51, 0x3); + bridge_i2c_write_w(0x06, 0x01); + bridge_i2c_write_w(0x04, 0x2018); + bridge_i2c_write_w(0x50, 0x01); + } else if (mode == MODE_2D_LEFT) { + bridge_i2c_read(0x54, &RegData, 2); + RegData |= 0x8; + bridge_i2c_write_w(0x54, RegData); + bridge_i2c_write_w(0x54, (RegData & ~(0x2))); + bridge_i2c_read(0x55, &RegData, 2); + RegData |= 0x8; + bridge_i2c_write_w(0x55, RegData); + bridge_i2c_write_w(0x55, (RegData & ~(0x2))); + bridge_i2c_write_w(0x14, 0x08); + msleep(20); + bridge_i2c_write_w(0x51, 0x3); + bridge_i2c_write_w(0x06, 0x02); + bridge_i2c_write_w(0x04, 0x2018); + bridge_i2c_write_w(0x50, 0x02); + } +} + +static void qs_s5k4e1_group_hold_on(void) +{ + qs_s5k4e1_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); +} + +static void qs_s5k4e1_group_hold_off(void) +{ + qs_s5k4e1_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF); +} + +static void qs_s5k4e1_start_stream(void) +{ + qs_s5k4e1_i2c_write_b_sensor(0x0100, 0x01); +} + +static void qs_s5k4e1_stop_stream(void) +{ + qs_s5k4e1_i2c_write_b_sensor(0x0100, 0x00); +} + +static void qs_s5k4e1_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint32_t divider, d1, d2; + + d1 = prev_frame_length_lines * 0x00000400 / snap_frame_length_lines; + d2 = prev_line_length_pck * 0x00000400 / snap_line_length_pck; + divider = d1 * d2 / 0x400; + + /*Verify PCLK settings and frame sizes.*/ + *pfps = (uint16_t) (fps * divider / 0x400); + /* 2 is the ratio of no.of snapshot channels + to number of preview channels */ +} + +static uint16_t qs_s5k4e1_get_prev_lines_pf(void) +{ + + return prev_frame_length_lines; + +} + +static uint16_t qs_s5k4e1_get_prev_pixels_pl(void) +{ + return prev_line_length_pck; + +} + +static uint16_t qs_s5k4e1_get_pict_lines_pf(void) +{ + return snap_frame_length_lines; +} + +static uint16_t qs_s5k4e1_get_pict_pixels_pl(void) +{ + return snap_line_length_pck; +} + + +static uint32_t qs_s5k4e1_get_pict_max_exp_lc(void) +{ + return snap_frame_length_lines * 24; +} + +static int32_t qs_s5k4e1_set_fps(struct fps_cfg *fps) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + qs_s5k4e1_ctrl->fps_divider = fps->fps_div; + qs_s5k4e1_ctrl->pict_fps_divider = fps->pict_fps_div; + if (qs_s5k4e1_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + total_lines_per_frame = (uint16_t) + ((prev_frame_length_lines) * qs_s5k4e1_ctrl->fps_divider/0x400); + } else { + total_lines_per_frame = (uint16_t) + ((snap_frame_length_lines) * + qs_s5k4e1_ctrl->pict_fps_divider/0x400); + } + qs_s5k4e1_group_hold_on(); + rc = qs_s5k4e1_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES, + total_lines_per_frame); + qs_s5k4e1_group_hold_off(); + return rc; +} + +static int32_t qs_s5k4e1_write_exp_gain(struct sensor_3d_exp_cfg exp_cfg) +{ + uint16_t max_legal_gain = 0x0200; + uint32_t ll_pck, fl_lines; + uint16_t gain = exp_cfg.gain; + uint32_t line = exp_cfg.line; + int32_t rc = 0; + if (gain > max_legal_gain) { + CDBG("Max legal gain Line:%d\n", __LINE__); + gain = max_legal_gain; + } + CDBG("qs_s5k4e1_write_exp_gain : gain = %d line = %d\n", gain, line); + + if (qs_s5k4e1_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + qs_s5k4e1_ctrl->my_reg_gain = gain; + qs_s5k4e1_ctrl->my_reg_line_count = (uint16_t) line; + fl_lines = prev_frame_length_lines * + qs_s5k4e1_ctrl->fps_divider / 0x400; + ll_pck = prev_line_length_pck; + } else { + fl_lines = snap_frame_length_lines * + qs_s5k4e1_ctrl->pict_fps_divider / 0x400; + ll_pck = snap_line_length_pck; + } + if (line > (fl_lines - QS_S5K4E1_OFFSET)) + fl_lines = line + QS_S5K4E1_OFFSET; + qs_s5k4e1_group_hold_on(); + rc = qs_s5k4e1_i2c_write_w_sensor(REG_GLOBAL_GAIN, gain); + rc = qs_s5k4e1_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES, fl_lines); + rc = qs_s5k4e1_i2c_write_w_sensor(REG_COARSE_INTEGRATION_TIME, line); + if ((qs_s5k4e1_ctrl->cam_mode == MODE_3D) && (cali_data_status == 1)) { + bridge_i2c_write_w(0x06, 0x01); + rc = qs_s5k4e1_i2c_write_w_sensor(REG_GLOBAL_GAIN, + exp_cfg.gain_adjust); + rc = qs_s5k4e1_i2c_write_w_sensor(REG_GR_GAIN, exp_cfg.gr_gain); + rc = qs_s5k4e1_i2c_write_w_sensor(REG_R_GAIN, + exp_cfg.r_gain); + rc = qs_s5k4e1_i2c_write_w_sensor(REG_B_GAIN, + exp_cfg.b_gain); + rc = qs_s5k4e1_i2c_write_w_sensor(REG_GB_GAIN, + exp_cfg.gb_gain); + bridge_i2c_write_w(0x06, 0x03); + } + qs_s5k4e1_group_hold_off(); + return rc; +} + +static int32_t qs_s5k4e1_set_pict_exp_gain(struct sensor_3d_exp_cfg exp_cfg) +{ + int32_t rc = 0; + rc = qs_s5k4e1_write_exp_gain(exp_cfg); + return rc; +} + +static int32_t qs_s5k4e1_write_focus_value(uint16_t code_value) +{ + uint8_t code_val_msb, code_val_lsb; + if ((qs_s5k4e1_ctrl->cam_mode == MODE_2D_LEFT) || + (qs_s5k4e1_ctrl->cam_mode == MODE_3D)) { + /* Left */ + bridge_i2c_write_w(0x06, 0x02); + CDBG("%s: Left Lens Position: %d\n", __func__, + code_value); + code_val_msb = code_value >> 4; + code_val_lsb = (code_value & 0x000F) << 4; + code_val_lsb |= qs_s5k4e1_af_mode; + if (af_i2c_write_b_sensor(code_val_msb, code_val_lsb) < 0) { + CDBG("move_focus failed at line %d ...\n", __LINE__); + return -EBUSY; + } + } + + if ((qs_s5k4e1_ctrl->cam_mode == MODE_2D_RIGHT) || + (qs_s5k4e1_ctrl->cam_mode == MODE_3D)) { + /* Right */ + bridge_i2c_write_w(0x06, 0x01); + code_value += qs_s5k4e1_af_right_adjust; + CDBG("%s: Right Lens Position: %d\n", __func__, + code_value); + code_val_msb = code_value >> 4; + code_val_lsb = (code_value & 0x000F) << 4; + code_val_lsb |= qs_s5k4e1_af_mode; + if (af_i2c_write_b_sensor(code_val_msb, code_val_lsb) < 0) { + CDBG("move_focus failed at line %d ...\n", __LINE__); + return -EBUSY; + } + } + + if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) { + /* 3D Mode */ + bridge_i2c_write_w(0x06, 0x03); + } + usleep(qs_s5k4e1_sw_damping_time_wait*50); + return 0; +} + +static int32_t qs_s5k4e1_write_1D_focus_value(uint16_t code_value) +{ + uint8_t code_val_msb, code_val_lsb; + CDBG("%s: Lens Position: %d\n", __func__, code_value); + code_val_msb = code_value >> 4; + code_val_lsb = (code_value & 0x000F) << 4; + code_val_lsb |= qs_s5k4e1_af_mode; + if (af_i2c_write_b_sensor(code_val_msb, code_val_lsb) < 0) { + CDBG("move_focus failed at line %d ...\n", __LINE__); + return -EBUSY; + } + + usleep(qs_s5k4e1_sw_damping_time_wait*50); + return 0; +} + +static int32_t qs_s5k4e1_move_focus(int direction, + int32_t num_steps) +{ + int16_t step_direction, actual_step, dest_lens_position, + dest_step_position; + int16_t max_step_postion = QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR; + CDBG("Inside %s\n", __func__); + if (direction == MOVE_NEAR) + step_direction = 1; + else + step_direction = -1; + + actual_step = (int16_t) (step_direction * (int16_t) num_steps); + dest_step_position = (int16_t) (qs_s5k4e1_ctrl->curr_step_pos + + actual_step); + + if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) + max_step_postion = QS_S5K4E1_TOTAL_STEPS_3D; + + if (dest_step_position > max_step_postion) + dest_step_position = max_step_postion; + else if (dest_step_position < 0) + dest_step_position = 0; + + if (dest_step_position == qs_s5k4e1_ctrl->curr_step_pos) { + CDBG("%s cur and dest pos are same\n", __func__); + CDBG("%s cur_step_pos:%d\n", __func__, + qs_s5k4e1_ctrl->curr_step_pos); + return 0; + } + + if (step_direction < 0) { + if (num_steps >= 20) { + /* sweeping towards all the way in infinity direction */ + qs_s5k4e1_af_mode = 2; + qs_s5k4e1_sw_damping_time_wait = 8; + } else if (num_steps <= 4) { + /* reverse search during macro mode */ + qs_s5k4e1_af_mode = 4; + qs_s5k4e1_sw_damping_time_wait = 16; + } else { + qs_s5k4e1_af_mode = 3; + qs_s5k4e1_sw_damping_time_wait = 12; + } + } else { + /* coarse search towards macro direction */ + qs_s5k4e1_af_mode = 4; + qs_s5k4e1_sw_damping_time_wait = 16; + } + + if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) { + /* Left */ + bridge_i2c_write_w(0x06, 0x02); + dest_lens_position = + qs_s5k4e1_step_position_table_left[dest_step_position]; + if (qs_s5k4e1_write_1D_focus_value(dest_lens_position) < 0) { + CDBG("move_focus failed at line %d ...\n", __LINE__); + bridge_i2c_write_w(0x06, 0x03); + return -EBUSY; + } + /* Keep left sensor as reference as AF stats is from left */ + qs_s5k4e1_ctrl->curr_step_pos = dest_step_position; + qs_s5k4e1_ctrl->curr_lens_pos = dest_lens_position; + + /* Right */ + bridge_i2c_write_w(0x06, 0x01); + dest_lens_position = + qs_s5k4e1_step_position_table_right[dest_step_position]; + if (qs_s5k4e1_write_1D_focus_value(dest_lens_position) < 0) { + CDBG("move_focus failed at line %d ...\n", __LINE__); + bridge_i2c_write_w(0x06, 0x03); + return -EBUSY; + } + + /* 3D Mode */ + bridge_i2c_write_w(0x06, 0x03); + return 0; + } + + dest_lens_position = qs_s5k4e1_step_position_table[dest_step_position]; + CDBG("%s: Step Position: %d\n", __func__, dest_step_position); + if (qs_s5k4e1_ctrl->curr_lens_pos != dest_lens_position) { + if (qs_s5k4e1_write_focus_value(dest_lens_position) < 0) { + CDBG("move_focus failed at line %d ...\n", __LINE__); + return -EBUSY; + } + } + + qs_s5k4e1_ctrl->curr_step_pos = dest_step_position; + qs_s5k4e1_ctrl->curr_lens_pos = dest_lens_position; + return 0; +} + +static int32_t qs_s5k4e1_set_default_focus(uint8_t af_step) +{ + int32_t rc = 0; + if (qs_s5k4e1_ctrl->curr_step_pos) { + rc = qs_s5k4e1_move_focus(MOVE_FAR, + qs_s5k4e1_ctrl->curr_step_pos); + if (rc < 0) + return rc; + } else { + if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) { + /* Left */ + bridge_i2c_write_w(0x06, 0x02); + rc = qs_s5k4e1_write_1D_focus_value( + qs_s5k4e1_step_position_table_left[0]); + if (rc < 0) { + bridge_i2c_write_w(0x06, 0x03); + return rc; + } + + /* Right */ + bridge_i2c_write_w(0x06, 0x01); + rc = qs_s5k4e1_write_1D_focus_value( + qs_s5k4e1_step_position_table_right[0]); + if (rc < 0) { + bridge_i2c_write_w(0x06, 0x03); + return rc; + } + + /* Left sensor is the reference sensor for AF stats */ + qs_s5k4e1_ctrl->curr_lens_pos = + qs_s5k4e1_step_position_table_left[0]; + + /* 3D Mode */ + bridge_i2c_write_w(0x06, 0x03); + } else { + rc = qs_s5k4e1_write_focus_value( + qs_s5k4e1_step_position_table[0]); + if (rc < 0) + return rc; + qs_s5k4e1_ctrl->curr_lens_pos = + qs_s5k4e1_step_position_table[0]; + } + } + CDBG("%s\n", __func__); + return 0; +} + +static void qs_s5k4e1_3d_table_init(void) +{ + int16_t af_data = 0; + uint16_t step = 8, step_q2 = 8, anchor_point_q2; + int32_t rc = 0, i, j; + uint16_t eeprom_read_addr[2][3] = {{0x110, 0x114, 0x118}, + {0x112, 0x116, 0x11A} }; + uint16_t *step_position_table; + + step_position_table = qs_s5k4e1_step_position_table_left; + for (j = 0; j < 2; j++) { + rc = qs_s5k4e1_eeprom_i2c_read_b(eeprom_read_addr[j][0], + &af_data, 2); + if (rc == 0) { + CDBG("%s: Far data - %d\n", __func__, af_data); + step_position_table[0] = af_data; + } else { + CDBG("%s: EEPROM data read error\n", __func__); + return; + } + + rc = qs_s5k4e1_eeprom_i2c_read_b(eeprom_read_addr[j][1], + &af_data, 2); + if (rc == 0) { + CDBG("%s: Medium data - %d\n", __func__, af_data); + step_position_table[2] = af_data; + } else { + CDBG("%s: EEPROM data read error\n", __func__); + return; + } + + /* + * Using the 150cm and 100cm calibration values + * as per the Lens characteristics derive intermediate step + */ + step_position_table[1] = step_position_table[0] + + (step_position_table[2] - step_position_table[0])/2; + CDBG("%s: Step between 150cm:100cm is %d\n", __func__, + step_position_table[1]); + + rc = qs_s5k4e1_eeprom_i2c_read_b(eeprom_read_addr[j][2], + &af_data, 2); + if (rc == 0) { + CDBG("%s: Short data - %d\n", __func__, af_data); + step_position_table[6] = af_data; + } else { + CDBG("%s: EEPROM data read error\n", __func__); + return; + } + + /* + * Using the 100cm and 50cm calibration values + * as per the Lens characteristics derive + * intermediate steps + */ + step = (step_position_table[6] - step_position_table[2])/4; + + /* + * Interpolate the intermediate steps between 100cm + * to 50cm based on COC1.5 + */ + step_position_table[3] = step_position_table[2] + step; + step_position_table[4] = step_position_table[3] + step; + step_position_table[5] = step_position_table[4] + step; + + /* + * Extrapolate the steps within 50cm based on + * OC2 to converge faster. This range is beyond the 3D + * specification of 50cm + */ + anchor_point_q2 = step_position_table[6] << 1; + step_q2 = (step_position_table[6] - step_position_table[2]); + + for (i = 7; i < QS_S5K4E1_TOTAL_STEPS_3D; i++) { + anchor_point_q2 += step_q2; + step_position_table[i] = anchor_point_q2 >> 1; + } + step_position_table = qs_s5k4e1_step_position_table_right; + } +} + +static void qs_s5k4e1_init_focus(void) +{ + uint8_t i; + int32_t rc = 0; + int16_t af_far_data = 0; + qs_s5k4e1_af_initial_code = 190; + /* Read the calibration data from left and right sensors if available */ + rc = qs_s5k4e1_eeprom_i2c_read_b(0x110, &af_far_data, 2); + if (rc == 0) { + CDBG("%s: Left Far data - %d\n", __func__, af_far_data); + qs_s5k4e1_af_initial_code = af_far_data; + } + + rc = qs_s5k4e1_eeprom_i2c_read_b(0x112, &af_far_data, 2); + if (rc == 0) { + CDBG("%s: Right Far data - %d\n", __func__, af_far_data); + qs_s5k4e1_af_right_adjust = af_far_data - + qs_s5k4e1_af_initial_code; + } + + qs_s5k4e1_3d_table_init(); + + qs_s5k4e1_step_position_table[0] = qs_s5k4e1_af_initial_code; + for (i = 1; i <= QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR; i++) { + if (i <= qs_s5k4e1_nl_region_boundary1) { + qs_s5k4e1_step_position_table[i] = + qs_s5k4e1_step_position_table[i-1] + + qs_s5k4e1_nl_region_code_per_step1; + } else { + qs_s5k4e1_step_position_table[i] = + qs_s5k4e1_step_position_table[i-1] + + qs_s5k4e1_l_region_code_per_step; + } + + if (qs_s5k4e1_step_position_table[i] > 1023) + qs_s5k4e1_step_position_table[i] = 1023; + } + qs_s5k4e1_ctrl->curr_step_pos = 0; +} + +static int32_t qs_s5k4e1_test(enum qs_s5k4e1_test_mode_t mo) +{ + int32_t rc = 0; + if (mo == TEST_OFF) + return rc; + else { + /* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation, + 1: Bypass Signal Processing + REG_0x30D8[5] is EBDMASK: 0: + Output Embedded data, 1: No output embedded data */ + if (qs_s5k4e1_i2c_write_b_sensor(REG_TEST_PATTERN_MODE, + (uint8_t) mo) < 0) { + return rc; + } + } + return rc; +} + +static int32_t qs_s5k4e1_sensor_setting(int update_type, int rt) +{ + + int32_t rc = 0; + struct msm_camera_csi_params qs_s5k4e1_csi_params; + + qs_s5k4e1_stop_stream(); + msleep(80); + bridge_i2c_write_w(0x53, 0x00); + msleep(80); + if (update_type == REG_INIT) { + CSI_CONFIG = 0; + LENS_SHADE_CONFIG = 0; + default_lens_shade = 0; + bridge_i2c_write_w(0x53, 0x01); + msleep(30); + qs_s5k4e1_bridge_config(qs_s5k4e1_ctrl->cam_mode, rt); + msleep(30); + qs_s5k4e1_i2c_write_b_table(qs_s5k4e1_regs.rec_settings, + qs_s5k4e1_regs.rec_size); + msleep(30); + } else if (update_type == UPDATE_PERIODIC) { + qs_s5k4e1_write_lsc(lens_eeprom_data, rt); + msleep(100); + if (!CSI_CONFIG) { + if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) { + qs_s5k4e1_csi_params.lane_cnt = 4; + qs_s5k4e1_csi_params.data_format = CSI_8BIT; + } else { + qs_s5k4e1_csi_params.lane_cnt = 1; + qs_s5k4e1_csi_params.data_format = CSI_10BIT; + } + qs_s5k4e1_csi_params.lane_assign = 0xe4; + qs_s5k4e1_csi_params.dpcm_scheme = 0; + qs_s5k4e1_csi_params.settle_cnt = 28; + rc = msm_camio_csi_config(&qs_s5k4e1_csi_params); + msleep(10); + cam_debug_init(); + CSI_CONFIG = 1; + } + bridge_i2c_write_w(0x53, 0x01); + msleep(50); + qs_s5k4e1_i2c_write_b_table(qs_s5k4e1_regs.conf_array[rt].conf, + qs_s5k4e1_regs.conf_array[rt].size); + msleep(50); + qs_s5k4e1_start_stream(); + msleep(80); + } + return rc; +} + +static int32_t qs_s5k4e1_video_config(int mode) +{ + + int32_t rc = 0; + /* change sensor resolution if needed */ + if (qs_s5k4e1_sensor_setting(UPDATE_PERIODIC, + qs_s5k4e1_ctrl->prev_res) < 0) + return rc; + if (qs_s5k4e1_ctrl->set_test) { + if (qs_s5k4e1_test(qs_s5k4e1_ctrl->set_test) < 0) + return rc; + } + + qs_s5k4e1_ctrl->curr_res = qs_s5k4e1_ctrl->prev_res; + qs_s5k4e1_ctrl->sensormode = mode; + return rc; +} + +static int32_t qs_s5k4e1_snapshot_config(int mode) +{ + int32_t rc = 0; + /*change sensor resolution if needed */ + if (qs_s5k4e1_ctrl->curr_res != qs_s5k4e1_ctrl->pict_res) { + if (qs_s5k4e1_sensor_setting(UPDATE_PERIODIC, + qs_s5k4e1_ctrl->pict_res) < 0) + return rc; + } + + qs_s5k4e1_ctrl->curr_res = qs_s5k4e1_ctrl->pict_res; + qs_s5k4e1_ctrl->sensormode = mode; + return rc; +} /*end of qs_s5k4e1_snapshot_config*/ + +static int32_t qs_s5k4e1_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + /* change sensor resolution if needed */ + if (qs_s5k4e1_ctrl->curr_res != qs_s5k4e1_ctrl->pict_res) { + if (qs_s5k4e1_sensor_setting(UPDATE_PERIODIC, + qs_s5k4e1_ctrl->pict_res) < 0) + return rc; + } + + qs_s5k4e1_ctrl->curr_res = qs_s5k4e1_ctrl->pict_res; + qs_s5k4e1_ctrl->sensormode = mode; + return rc; +} /*end of qs_s5k4e1_raw_snapshot_config*/ + +static int32_t qs_s5k4e1_mode_init(int mode, struct sensor_init_cfg init_info) +{ + int32_t rc = 0; + if (mode != qs_s5k4e1_ctrl->cam_mode) { + qs_s5k4e1_ctrl->prev_res = init_info.prev_res; + qs_s5k4e1_ctrl->pict_res = init_info.pict_res; + qs_s5k4e1_ctrl->cam_mode = mode; + + prev_frame_length_lines = + ((qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->prev_res]\ + .conf[QS_S5K4E1_FRAME_LENGTH_LINES_H].wdata << 8) + | qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->prev_res]\ + .conf[QS_S5K4E1_FRAME_LENGTH_LINES_L].wdata); + prev_line_length_pck = + (qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->prev_res]\ + .conf[QS_S5K4E1_LINE_LENGTH_PCK_H].wdata << 8) + | qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->prev_res]\ + .conf[QS_S5K4E1_LINE_LENGTH_PCK_L].wdata; + snap_frame_length_lines = + (qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->pict_res]\ + .conf[QS_S5K4E1_FRAME_LENGTH_LINES_H].wdata << 8) + | qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->pict_res]\ + .conf[QS_S5K4E1_FRAME_LENGTH_LINES_L].wdata; + snap_line_length_pck = + (qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->pict_res]\ + .conf[QS_S5K4E1_LINE_LENGTH_PCK_H].wdata << 8) + | qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->pict_res]\ + .conf[QS_S5K4E1_LINE_LENGTH_PCK_L].wdata; + + rc = qs_s5k4e1_sensor_setting(REG_INIT, + qs_s5k4e1_ctrl->prev_res); + } + return rc; +} +static int32_t qs_s5k4e1_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + switch (mode) { + case SENSOR_PREVIEW_MODE: + qs_s5k4e1_ctrl->prev_res = res; + rc = qs_s5k4e1_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + qs_s5k4e1_ctrl->pict_res = res; + rc = qs_s5k4e1_snapshot_config(mode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + qs_s5k4e1_ctrl->pict_res = res; + rc = qs_s5k4e1_raw_snapshot_config(mode); + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +static int32_t qs_s5k4e1_power_down(void) +{ + qs_s5k4e1_stop_stream(); + msleep(30); + qs_s5k4e1_af_mode = 2; + qs_s5k4e1_af_right_adjust = 0; + qs_s5k4e1_write_focus_value(0); + msleep(100); + /* Set AF actutator to PowerDown */ + af_i2c_write_b_sensor(0x80, 00); + return 0; +} + +static int qs_s5k4e1_probe_init_done(const struct msm_camera_sensor_info *data) +{ + CDBG("probe done\n"); + gpio_free(data->sensor_reset); + return 0; +} + +static int + qs_s5k4e1_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + uint16_t chipid = 0; + CDBG("%s: %d\n", __func__, __LINE__); + rc = gpio_request(data->sensor_reset, "qs_s5k4e1"); + CDBG(" qs_s5k4e1_probe_init_sensor\n"); + if (!rc) { + CDBG("sensor_reset = %d\n", rc); + gpio_direction_output(data->sensor_reset, 0); + msleep(50); + gpio_set_value_cansleep(data->sensor_reset, 1); + msleep(13); + } else { + goto init_probe_done; + } + msleep(70); + rc = qs_s5k4e1_bridge_reset(); + if (rc < 0) + goto init_probe_fail; + qs_s5k4e1_bridge_config(MODE_3D, RES_PREVIEW); + msleep(30); + + CDBG(" qs_s5k4e1_probe_init_sensor is called\n"); + rc = qs_s5k4e1_i2c_read(0x0000, &chipid, 2); + CDBG("ID: %d\n", chipid); + /* 4. Compare sensor ID to QS_S5K4E1 ID: */ + if (chipid != 0x4e10) { + rc = -ENODEV; + CDBG("qs_s5k4e1_probe_init_sensor fail chip id mismatch\n"); + goto init_probe_fail; + } + goto init_probe_done; +init_probe_fail: + CDBG(" qs_s5k4e1_probe_init_sensor fails\n"); + gpio_set_value_cansleep(data->sensor_reset, 0); + qs_s5k4e1_probe_init_done(data); +init_probe_done: + CDBG(" qs_s5k4e1_probe_init_sensor finishes\n"); + return rc; +} +/* camsensor_qs_s5k4e1_reset */ + +int qs_s5k4e1_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + CDBG("%s: %d\n", __func__, __LINE__); + CDBG("Calling qs_s5k4e1_sensor_open_init\n"); + + qs_s5k4e1_ctrl = kzalloc(sizeof(struct qs_s5k4e1_ctrl_t), GFP_KERNEL); + if (!qs_s5k4e1_ctrl) { + CDBG("qs_s5k4e1_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + qs_s5k4e1_ctrl->fps_divider = 1 * 0x00000400; + qs_s5k4e1_ctrl->pict_fps_divider = 1 * 0x00000400; + qs_s5k4e1_ctrl->set_test = TEST_OFF; + qs_s5k4e1_ctrl->cam_mode = MODE_INVALID; + + if (data) + qs_s5k4e1_ctrl->sensordata = data; + if (rc < 0) { + CDBG("Calling qs_s5k4e1_sensor_open_init fail1\n"); + return rc; + } + CDBG("%s: %d\n", __func__, __LINE__); + /* enable mclk first */ + msm_camio_clk_rate_set(QS_S5K4E1_MASTER_CLK_RATE); + rc = qs_s5k4e1_probe_init_sensor(data); + if (rc < 0) + goto init_fail; +/*Default mode is 3D*/ + memcpy(lens_eeprom_data, data->eeprom_data, 864); + qs_s5k4e1_ctrl->fps = 30*Q8; + qs_s5k4e1_init_focus(); + if (rc < 0) { + gpio_set_value_cansleep(data->sensor_reset, 0); + goto init_fail; + } else + goto init_done; +init_fail: + CDBG("init_fail\n"); + qs_s5k4e1_probe_init_done(data); +init_done: + CDBG("init_done\n"); + return rc; +} /*endof qs_s5k4e1_sensor_open_init*/ + +static int qs_s5k4e1_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&qs_s5k4e1_wait_queue); + return 0; +} + +static const struct i2c_device_id qs_s5k4e1_i2c_id[] = { + {"qs_s5k4e1", 0}, + { } +}; + +static int qs_s5k4e1_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("qs_s5k4e1_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + qs_s5k4e1_sensorw = kzalloc(sizeof(struct qs_s5k4e1_work_t), + GFP_KERNEL); + if (!qs_s5k4e1_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, qs_s5k4e1_sensorw); + qs_s5k4e1_init_client(client); + qs_s5k4e1_client = client; + + msleep(50); + + CDBG("qs_s5k4e1_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("qs_s5k4e1_probe failed! rc = %d\n", rc); + return rc; +} + +static int qs_s5k4e1_send_wb_info(struct wb_info_cfg *wb) +{ + return 0; + +} /*end of qs_s5k4e1_snapshot_config*/ + +static int __exit qs_s5k4e1_remove(struct i2c_client *client) +{ + struct qs_s5k4e1_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + qs_s5k4e1_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver qs_s5k4e1_i2c_driver = { + .id_table = qs_s5k4e1_i2c_id, + .probe = qs_s5k4e1_i2c_probe, + .remove = __exit_p(qs_s5k4e1_i2c_remove), + .driver = { + .name = "qs_s5k4e1", + }, +}; + +int qs_s5k4e1_3D_sensor_config(void __user *argp) +{ + struct sensor_large_data cdata; + long rc; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_large_data))) + return -EFAULT; + mutex_lock(&qs_s5k4e1_mut); + rc = qs_s5k4e1_get_calibration_data + (&cdata.data.sensor_3d_cali_data); + if (rc < 0) + goto fail; + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_large_data))) + rc = -EFAULT; +fail: + mutex_unlock(&qs_s5k4e1_mut); + return rc; +} + +int qs_s5k4e1_2D_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&qs_s5k4e1_mut); + CDBG("qs_s5k4e1_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + qs_s5k4e1_get_pict_fps( + cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = + qs_s5k4e1_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = + qs_s5k4e1_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = + qs_s5k4e1_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + qs_s5k4e1_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + qs_s5k4e1_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = qs_s5k4e1_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = + qs_s5k4e1_write_exp_gain( + cdata.cfg.sensor_3d_exp); + break; + + case CFG_SET_PICT_EXP_GAIN: + rc = + qs_s5k4e1_set_pict_exp_gain( + cdata.cfg.sensor_3d_exp); + break; + + case CFG_SET_MODE: + rc = qs_s5k4e1_set_sensor_mode(cdata.mode, + cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = qs_s5k4e1_power_down(); + break; + + case CFG_MOVE_FOCUS: + rc = + qs_s5k4e1_move_focus( + cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = + qs_s5k4e1_set_default_focus( + cdata.cfg.focus.steps); + break; + + case CFG_GET_AF_MAX_STEPS: + if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) + cdata.max_steps = QS_S5K4E1_TOTAL_STEPS_3D; + else + cdata.max_steps = + QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR; + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_EFFECT: + rc = qs_s5k4e1_set_default_focus( + cdata.cfg.effect); + break; + + + case CFG_SEND_WB_INFO: + rc = qs_s5k4e1_send_wb_info( + &(cdata.cfg.wb_info)); + break; + + case CFG_SENSOR_INIT: + rc = qs_s5k4e1_mode_init(cdata.mode, + cdata.cfg.init_info); + break; + + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&qs_s5k4e1_mut); + + return rc; +} + +int qs_s5k4e1_sensor_config(void __user *argp) +{ + int cfgtype; + long rc; + if (copy_from_user(&cfgtype, + (void *)argp, + sizeof(int))) + return -EFAULT; + if (cfgtype != CFG_GET_3D_CALI_DATA) + rc = qs_s5k4e1_2D_sensor_config(argp); + else + rc = qs_s5k4e1_3D_sensor_config(argp); + return rc; +} + +static int qs_s5k4e1_sensor_release(void) +{ + int rc = -EBADF; + mutex_lock(&qs_s5k4e1_mut); + qs_s5k4e1_power_down(); + bridge_i2c_write_w(0x53, 0x00); + msleep(20); + gpio_set_value_cansleep(qs_s5k4e1_ctrl->sensordata->sensor_reset, 0); + msleep(5); + gpio_free(qs_s5k4e1_ctrl->sensordata->sensor_reset); + kfree(qs_s5k4e1_ctrl); + qs_s5k4e1_ctrl = NULL; + CDBG("qs_s5k4e1_release completed\n"); + mutex_unlock(&qs_s5k4e1_mut); + + return rc; +} + +static int qs_s5k4e1_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(&qs_s5k4e1_i2c_driver); + if (rc < 0 || qs_s5k4e1_client == NULL) { + rc = -ENOTSUPP; + CDBG("I2C add driver failed"); + goto probe_fail; + } + msm_camio_clk_rate_set(QS_S5K4E1_MASTER_CLK_RATE); + rc = qs_s5k4e1_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + qs_s5k4e1_read_lsc(info->eeprom_data); /*Default mode is 3D*/ + s->s_init = qs_s5k4e1_sensor_open_init; + s->s_release = qs_s5k4e1_sensor_release; + s->s_config = qs_s5k4e1_sensor_config; + s->s_mount_angle = info->sensor_platform_info->mount_angle; + s->s_camera_type = BACK_CAMERA_3D; + s->s_video_packing = SIDE_BY_SIDE_HALF; + s->s_snap_packing = SIDE_BY_SIDE_FULL; + bridge_i2c_write_w(0x53, 0x00); + msleep(20); + gpio_set_value_cansleep(info->sensor_reset, 0); + qs_s5k4e1_probe_init_done(info); + return rc; + +probe_fail: + CDBG("qs_s5k4e1_sensor_probe: SENSOR PROBE FAILS!\n"); + return rc; +} + +static bool streaming = 1; + +static int qs_s5k4e1_focus_test(void *data, u64 *val) +{ + int i = 0; + qs_s5k4e1_set_default_focus(0); + + for (i = 0; i < QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR; i++) { + qs_s5k4e1_move_focus(MOVE_NEAR, 1); + msleep(2000); + } + msleep(5000); + for ( ; i > 0; i--) { + qs_s5k4e1_move_focus(MOVE_FAR, 1); + msleep(2000); + } + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_focus, qs_s5k4e1_focus_test, + NULL, "%lld\n"); + +static int qs_s5k4e1_step_test(void *data, u64 *val) +{ + int rc = 0; + struct sensor_large_data cdata; + rc = qs_s5k4e1_get_calibration_data + (&cdata.data.sensor_3d_cali_data); + if (rc < 0) + CDBG("%s: Calibration data read fail.\n", __func__); + + return 0; +} + +static int qs_s5k4e1_set_step(void *data, u64 val) +{ + qs_s5k4e1_l_region_code_per_step = val & 0xFF; + qs_s5k4e1_af_mode = (val >> 8) & 0xFF; + qs_s5k4e1_nl_region_code_per_step1 = (val >> 16) & 0xFFFF; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_step, qs_s5k4e1_step_test, + qs_s5k4e1_set_step, "%lld\n"); + +static int cam_debug_stream_set(void *data, u64 val) +{ + int rc = 0; + + if (val) { + qs_s5k4e1_start_stream(); + streaming = 1; + } else { + qs_s5k4e1_stop_stream(); + streaming = 0; + } + + return rc; +} + +static int cam_debug_stream_get(void *data, u64 *val) +{ + *val = streaming; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(cam_stream, cam_debug_stream_get, + cam_debug_stream_set, "%llu\n"); + +static uint16_t qs_s5k4e1_step_val = QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR; +static uint8_t qs_s5k4e1_step_dir = MOVE_NEAR; +static int qs_s5k4e1_af_step_config(void *data, u64 val) +{ + qs_s5k4e1_step_val = val & 0xFFFF; + qs_s5k4e1_step_dir = (val >> 16) & 0x1; + CDBG("%s\n", __func__); + return 0; +} + +static int qs_s5k4e1_af_step(void *data, u64 *val) +{ + int i = 0; + int dir = MOVE_NEAR; + CDBG("%s\n", __func__); + qs_s5k4e1_set_default_focus(0); + msleep(5000); + if (qs_s5k4e1_step_dir == 1) + dir = MOVE_FAR; + + for (i = 0; i < qs_s5k4e1_step_val; i += 4) { + qs_s5k4e1_move_focus(dir, 4); + msleep(1000); + } + qs_s5k4e1_set_default_focus(0); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(af_step, qs_s5k4e1_af_step, + qs_s5k4e1_af_step_config, "%llu\n"); + +static int cam_debug_init(void) +{ + struct dentry *cam_dir; + debugfs_base = debugfs_create_dir("sensor", NULL); + if (!debugfs_base) + return -ENOMEM; + + cam_dir = debugfs_create_dir("qs_s5k4e1", debugfs_base); + if (!cam_dir) + return -ENOMEM; + + if (!debugfs_create_file("focus", S_IRUGO | S_IWUSR, cam_dir, + NULL, &cam_focus)) + return -ENOMEM; + if (!debugfs_create_file("step", S_IRUGO | S_IWUSR, cam_dir, + NULL, &cam_step)) + return -ENOMEM; + if (!debugfs_create_file("stream", S_IRUGO | S_IWUSR, cam_dir, + NULL, &cam_stream)) + return -ENOMEM; + if (!debugfs_create_file("af_step", S_IRUGO | S_IWUSR, cam_dir, + NULL, &af_step)) + return -ENOMEM; + return 0; +} + +static int __qs_s5k4e1_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, qs_s5k4e1_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __qs_s5k4e1_probe, + .driver = { + .name = "msm_camera_qs_s5k4e1", + .owner = THIS_MODULE, + }, +}; + +static int __init qs_s5k4e1_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(qs_s5k4e1_init); +void qs_s5k4e1_exit(void) +{ + i2c_del_driver(&qs_s5k4e1_i2c_driver); +} +MODULE_DESCRIPTION("Samsung 5MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/qs_s5k4e1.h b/drivers/media/video/msm_zsl/qs_s5k4e1.h new file mode 100644 index 00000000000..f9c4c3f492b --- /dev/null +++ b/drivers/media/video/msm_zsl/qs_s5k4e1.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef QS_S5K4E1_H +#define QS_S5K4E1_H +#include +#include +extern struct qs_s5k4e1_reg qs_s5k4e1_regs; + +#define LENS_SHADE_TABLE 16 + +struct qs_s5k4e1_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +struct qs_s5k4e1_i2c_conf_array { + struct qs_s5k4e1_i2c_reg_conf *conf; + unsigned short size; +}; + +enum qs_s5k4e1_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum qs_s5k4e1_resolution_t { + QTR_2D_SIZE, + FULL_2D_SIZE, + QTR_3D_SIZE, + FULL_3D_SIZE, + INVALID_SIZE +}; +enum qs_s5k4e1_setting { + RES_PREVIEW, + RES_CAPTURE, + RES_3D_PREVIEW, + RES_3D_CAPTURE +}; +enum qs_s5k4e1_cam_mode_t { + MODE_2D_RIGHT, + MODE_2D_LEFT, + MODE_3D, + MODE_INVALID +}; +enum qs_s5k4e1_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum qs_s5k4e1_reg_mode { + QS_S5K4E1_FRAME_LENGTH_LINES_H = 1, + QS_S5K4E1_FRAME_LENGTH_LINES_L, + QS_S5K4E1_LINE_LENGTH_PCK_H, + QS_S5K4E1_LINE_LENGTH_PCK_L, +}; + +struct qs_s5k4e1_reg { + const struct qs_s5k4e1_i2c_reg_conf *rec_settings; + const unsigned short rec_size; + const struct qs_s5k4e1_i2c_reg_conf *reg_prev; + const unsigned short reg_prev_size; + const struct qs_s5k4e1_i2c_reg_conf *reg_snap; + const unsigned short reg_snap_size; + const struct qs_s5k4e1_i2c_reg_conf (*reg_lens)[LENS_SHADE_TABLE]; + const unsigned short reg_lens_size; + const struct qs_s5k4e1_i2c_reg_conf *reg_default_lens; + const unsigned short reg_default_lens_size; + const struct qs_s5k4e1_i2c_conf_array *conf_array; +}; +#endif /* QS_S5K4E1_H */ diff --git a/drivers/media/video/msm_zsl/qs_s5k4e1_reg.c b/drivers/media/video/msm_zsl/qs_s5k4e1_reg.c new file mode 100644 index 00000000000..39c3f29a48e --- /dev/null +++ b/drivers/media/video/msm_zsl/qs_s5k4e1_reg.c @@ -0,0 +1,804 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + + +#include "qs_s5k4e1.h" + +struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_prev_settings_3d[] = { + {0x0100, 0x00}, + /*Frame Length*/ + {0x0340, 0x04}, + {0x0341, 0x90}, + /*Line Length*/ + {0x0342, 0x0A}, + {0x0343, 0xB2}, + {0x3030, 0x06}, + {0x3017, 0xA4}, + {0x301B, 0x88}, + {0x30BC, 0x90}, + {0x301C, 0x04}, + {0x0202, 0x04}, + {0x0203, 0x12}, + {0x0204, 0x00}, + {0x0205, 0x80}, + {0x0306, 0x00}, + {0x0307, 0x60}, + {0x30B5, 0x01}, + {0x30E2, 0x02},/*num lanes[1:0] = 1*/ + {0x30F1, 0x60}, +/*MIPI Size Setting*/ + {0x30A9, 0x02}, + {0x300E, 0xE8}, + {0x0387, 0x01}, + {0x0344, 0x01}, + {0x0345, 0x18}, + {0x0348, 0x09}, + {0x0349, 0x17}, + {0x0346, 0x01}, + {0x0347, 0x94}, + {0x034A, 0x06}, + {0x034B, 0x13}, + {0x0380, 0x00}, + {0x0381, 0x01}, + {0x0382, 0x00}, + {0x0383, 0x01}, + {0x0384, 0x00}, + {0x0385, 0x01}, + {0x0386, 0x00}, + {0x0387, 0x01}, + {0x034C, 0x04}, + {0x034D, 0x00}, + {0x034E, 0x04}, + {0x034F, 0x80}, + {0x30BF, 0xAA}, + {0x30C0, 0x40}, + {0x30C8, 0x04}, + {0x30C9, 0x00}, +}; + +struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_prev_settings_2d[] = { + {0x0100, 0x00}, + {0x0340, 0x03}, + {0x0341, 0xe0}, + {0x0342, 0x0A}, + {0x0343, 0xB2}, + {0x3030, 0x06}, + {0x301B, 0x83}, + {0x30BC, 0x98}, + {0x301C, 0x04}, + {0x0202, 0x01}, + {0x0203, 0xFD}, + {0x0204, 0x00}, + {0x0205, 0x80}, + {0x0306, 0x00}, + {0x0307, 0x64}, + {0x30B5, 0x00}, + {0x30E2, 0x01},/*num lanes[1:0] = 1*/ + {0x30F1, 0xd0}, + {0x30A9, 0x02}, + {0x300E, 0xEB}, + {0x0387, 0x03}, + {0x0344, 0x00}, + {0x0345, 0x00}, + {0x0348, 0x0A}, + {0x0349, 0x2F}, + {0x0346, 0x00}, + {0x0347, 0x00}, + {0x034A, 0x07}, + {0x034B, 0xA7}, + {0x0380, 0x00}, + {0x0381, 0x01}, + {0x0382, 0x00}, + {0x0383, 0x01}, + {0x0384, 0x00}, + {0x0385, 0x01}, + {0x0386, 0x00}, + {0x0387, 0x03}, + {0x034C, 0x05}, + {0x034D, 0x10}, + {0x034E, 0x03}, + {0x034F, 0xd4}, + {0x30BF, 0xAB}, + {0x30C0, 0xc0}, + {0x30C8, 0x06}, + {0x30C9, 0x54}, +}; + +struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_snap_settings_2d[] = { + {0x0100, 0x00}, + {0x0340, 0x07}, + {0x0341, 0xb4}, + {0x0342, 0x0A}, + {0x0343, 0xB2}, + {0x3030, 0x06}, /*shut streaming off*/ + {0x300E, 0xE8}, + {0x301B, 0x75}, + {0x301C, 0x04}, + {0x30BC, 0x98}, + {0x0202, 0x04}, + {0x0203, 0x12}, + {0x0204, 0x00}, + {0x0205, 0x80}, + {0x0306, 0x00}, + {0x0307, 0x64}, + {0x30B5, 0x00}, + {0x30E2, 0x01},/*num lanes[1:0] = 1*/ + {0x30F1, 0xd0}, + {0x30A9, 0x03},/*Horizontal Binning Off*/ + {0x300E, 0xE8},/*Vertical Binning Off*/ + {0x0387, 0x01},/*y_odd_inc*/ + {0x034C, 0x0A},/*x_output size*/ + {0x034D, 0x30}, + {0x034E, 0x07},/*y_output size*/ + {0x034F, 0xA8}, + {0x30BF, 0xAB},/*outif_enable[7], data_type[5:0](2Bh = bayer 10bit)*/ + {0x30C0, 0x86},/*video_offset[7:4] 3260%12*/ + {0x30C8, 0x0C},/*video_data_length 3260 = 2608 * 1.25*/ + {0x30C9, 0xBC}, + +}; + +struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_snap_settings_3d[] = { + {0x0100, 0x00}, + +/* Frame Length*/ + {0x0340, 0x09}, + {0x0341, 0x20}, +/* Line Length*/ + {0x0342, 0x0A}, + {0x0343, 0xB2}, + {0x3030, 0x06},/*shut streaming off*/ +/*Analog Setting*/ + {0x3017, 0xA4}, + {0x301B, 0x88}, + {0x30BC, 0x90}, + {0x301C, 0x04}, +/*Integration setting ... */ + {0x0202, 0x04}, + {0x0203, 0x12}, + {0x0204, 0x00}, + {0x0205, 0x80}, +/*PLL setting ...*/ + {0x0306, 0x00}, + {0x0307, 0x60}, + {0x30B5, 0x01}, + {0x30E2, 0x02},/*num lanes[1:0] = 1*/ + {0x30F1, 0x60}, +/*MIPI Size Setting*/ + {0x30A9, 0x01}, + {0x300E, 0xE8}, + {0x0387, 0x01}, + {0x0344, 0x01},/*x_addr_start*/ + {0x0345, 0x14}, + {0x0348, 0x09},/*x_addr_end*/ + {0x0349, 0x17}, + {0x0346, 0x01},/*y_addr_start*/ + {0x0347, 0x94}, + {0x034A, 0x06},/*y_addr_end*/ + {0x034B, 0x13}, + {0x0380, 0x00},/*x_even_inc 1*/ + {0x0381, 0x01}, + {0x0382, 0x00},/*x_odd_inc 1*/ + {0x0383, 0x01}, + {0x0384, 0x00},/*y_even_inc 1*/ + {0x0385, 0x01}, + {0x0386, 0x00},/*y_odd_inc 1*/ + {0x0387, 0x01}, + {0x034C, 0x08},/*x_output size*/ + {0x034D, 0x00}, + {0x034E, 0x04},/*y_output size*/ + {0x034F, 0x80}, + {0x30BF, 0xAA},/*outif_enable[7], data_type[5:0](2Bh = bayer 8bit)*/ + {0x30C0, 0x80},/*video_offset[7:4]*/ + {0x30C8, 0x08},/*video_data_length*/ + {0x30C9, 0x00}, + +}; + +struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_recommend_settings[] = { + {0x0100, 0x00}, + + {0x3030, 0x06},/*shut streaming*/ +/*Analog Setting*/ + {0x3000, 0x05}, + {0x3001, 0x03}, + {0x3002, 0x08}, + {0x3003, 0x09}, + {0x3004, 0x2E}, + {0x3005, 0x06}, + {0x3006, 0x34}, + {0x3007, 0x00}, + {0x3008, 0x3C}, + {0x3009, 0x3C}, + {0x300A, 0x28}, + {0x300B, 0x04}, + {0x300C, 0x0A}, + {0x300D, 0x02}, + {0x300F, 0x82}, + {0x3010, 0x00}, + {0x3011, 0x4C}, + {0x3012, 0x30}, + {0x3013, 0xC0}, + {0x3014, 0x00}, + {0x3015, 0x00}, + {0x3016, 0x2C}, + {0x3017, 0x94}, + {0x3018, 0x78}, + {0x301D, 0xD4}, + {0x3021, 0x02}, + {0x3022, 0x24}, + {0x3024, 0x40}, + {0x3027, 0x08}, + {0x3029, 0xC6}, + {0x302B, 0x01}, + {0x30D8, 0x3F}, +/* ADLC setting ...*/ + {0x3070, 0x5F}, + {0x3071, 0x00}, + {0x3080, 0x04}, + {0x3081, 0x38}, + +/*MIPI setting*/ + {0x30BD, 0x00},/*SEL_CCP[0]*/ + {0x3084, 0x15},/*SYNC Mode*/ + {0x30BE, 0x1A},/*M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0]*/ + {0x30C1, 0x01},/*pack video enable [0]*/ + {0x30EE, 0x02},/*DPHY enable [1]*/ + {0x3111, 0x86},/*Embedded data off [5]*/ +/*For MIPI T8 T9*/ + {0x30E3, 0x38}, + {0x30E4, 0x40}, + {0x3113, 0x70}, + {0x3114, 0x80}, + {0x3115, 0x7B}, + {0x3116, 0xC0}, + {0x30EE, 0x12}, + +/*PLL setting ...*/ + {0x0305, 0x06}, +}; +static struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_default_lenshading_settings[] = { + + {0x3200, 0x00}, + {0x3201, 0x9a}, + {0x3202, 0x56}, + {0x3203, 0xf }, + {0x3204, 0xd8}, + {0x3205, 0x94}, + {0x3206, 0x0 }, + {0x3207, 0x10}, + {0x3208, 0x71}, + {0x3209, 0x0 }, + {0x320a, 0x9 }, + {0x320b, 0xc1}, + {0x320c, 0xf }, + {0x320d, 0xf1}, + {0x320e, 0x3d}, + {0x320f, 0x0 }, + {0x3210, 0xa }, + {0x3211, 0x93}, + {0x3212, 0xf }, + {0x3213, 0xc9}, + {0x3214, 0xa1}, + {0x3215, 0x0 }, + {0x3216, 0x10}, + {0x3217, 0x89}, + {0x3218, 0xf }, + {0x3219, 0xfb}, + {0x321a, 0xf3}, + {0x321b, 0xf }, + {0x321c, 0xf8}, + {0x321d, 0xfc}, + {0x321e, 0x0 }, + {0x321f, 0x4 }, + {0x3220, 0xe3}, + {0x3221, 0xf }, + {0x3222, 0xfe}, + {0x3223, 0x94}, + {0x3224, 0x0 }, + {0x3225, 0x24}, + {0x3226, 0x59}, + {0x3227, 0xf }, + {0x3228, 0xe9}, + {0x3229, 0x68}, + {0x322a, 0xf }, + {0x322b, 0xfa}, + {0x322c, 0x7f}, + {0x322d, 0x0 }, + {0x322e, 0x13}, + {0x322f, 0xe1}, + {0x3230, 0x0 }, + {0x3231, 0x3 }, + {0x3232, 0xbc}, + {0x3233, 0xf }, + {0x3234, 0xf0}, + {0x3235, 0xa1}, + {0x3236, 0xf }, + {0x3237, 0xf4}, + {0x3238, 0xc9}, + {0x3239, 0x0 }, + {0x323a, 0x11}, + {0x323b, 0x4b}, + {0x323c, 0x0 }, + {0x323d, 0x12}, + {0x323e, 0xc5}, + {0x323f, 0xf }, + {0x3240, 0xe3}, + {0x3241, 0xb }, + {0x3242, 0xf }, + {0x3243, 0xf8}, + {0x3244, 0x4f}, + {0x3245, 0x0 }, + {0x3246, 0x13}, + {0x3247, 0xac}, + {0x3248, 0x0 }, + {0x3249, 0x0 }, + {0x324a, 0x7c}, + {0x324b, 0xf }, + {0x324c, 0xfe}, + {0x324d, 0xdd}, + {0x324e, 0xf }, + {0x324f, 0xf2}, + {0x3250, 0x96}, + {0x3251, 0x0 }, + {0x3252, 0x8 }, + {0x3253, 0xef}, + {0x3254, 0x0 }, + {0x3255, 0x6 }, + {0x3256, 0xa4}, + {0x3257, 0x0 }, + {0x3258, 0x2 }, + {0x3259, 0x4b}, + {0x325a, 0x0 }, + {0x325b, 0x6 }, + {0x325c, 0x85}, + {0x325d, 0xf }, + {0x325e, 0xf8}, + {0x325f, 0x6a}, + {0x3260, 0xf }, + {0x3261, 0xfd}, + {0x3262, 0x70}, + {0x3263, 0x0 }, + {0x3264, 0xd }, + {0x3265, 0xa9}, + {0x3266, 0xf }, + {0x3267, 0xfd}, + {0x3268, 0xf8}, + {0x3269, 0xf }, + {0x326a, 0xec}, + {0x326b, 0xfc}, + {0x326c, 0x0 }, + {0x326d, 0xa7}, + {0x326e, 0x5 }, + {0x326f, 0xf }, + {0x3270, 0xd6}, + {0x3271, 0x19}, + {0x3272, 0x0 }, + {0x3273, 0xa }, + {0x3274, 0xe8}, + {0x3275, 0x0 }, + {0x3276, 0x17}, + {0x3277, 0x1 }, + {0x3278, 0xf }, + {0x3279, 0xe7}, + {0x327a, 0xa0}, + {0x327b, 0x0 }, + {0x327c, 0xb }, + {0x327d, 0xc3}, + {0x327e, 0xf }, + {0x327f, 0xc0}, + {0x3280, 0xe3}, + {0x3281, 0x0 }, + {0x3282, 0x15}, + {0x3283, 0x5a}, + {0x3284, 0xf }, + {0x3285, 0xf9}, + {0x3286, 0xa0}, + {0x3287, 0xf }, + {0x3288, 0xf4}, + {0x3289, 0xce}, + {0x328a, 0x0 }, + {0x328b, 0xb }, + {0x328c, 0x72}, + {0x328d, 0xf }, + {0x328e, 0xfb}, + {0x328f, 0xb5}, + {0x3290, 0x0 }, + {0x3291, 0x2f}, + {0x3292, 0xb }, + {0x3293, 0xf }, + {0x3294, 0xde}, + {0x3295, 0xc0}, + {0x3296, 0x0 }, + {0x3297, 0x0 }, + {0x3298, 0x58}, + {0x3299, 0x0 }, + {0x329a, 0x1b}, + {0x329b, 0x5 }, + {0x329c, 0xf }, + {0x329d, 0xf9}, + {0x329e, 0x23}, + {0x329f, 0xf }, + {0x32a0, 0xf3}, + {0x32a1, 0x94}, + {0x32a2, 0xf }, + {0x32a3, 0xe7}, + {0x32a4, 0xc2}, + {0x32a5, 0x0 }, + {0x32a6, 0x1d}, + {0x32a7, 0xe5}, + {0x32a8, 0x0 }, + {0x32a9, 0x5 }, + {0x32aa, 0xaf}, + {0x32ab, 0xf }, + {0x32ac, 0xe3}, + {0x32ad, 0xb7}, + {0x32ae, 0xf }, + {0x32af, 0xf8}, + {0x32b0, 0x34}, + {0x32b1, 0x0 }, + {0x32b2, 0x1c}, + {0x32b3, 0x3d}, + {0x32b4, 0x0 }, + {0x32b5, 0x10}, + {0x32b6, 0x4a}, + {0x32b7, 0xf }, + {0x32b8, 0xfa}, + {0x32b9, 0x7 }, + {0x32ba, 0xf }, + {0x32bb, 0xff}, + {0x32bc, 0x16}, + {0x32bd, 0x0 }, + {0x32be, 0x5 }, + {0x32bf, 0x4e}, + {0x32c0, 0x0 }, + {0x32c1, 0xc }, + {0x32c2, 0x1b}, + {0x32c3, 0xf }, + {0x32c4, 0xf1}, + {0x32c5, 0xdb}, + {0x32c6, 0xf }, + {0x32c7, 0xfc}, + {0x32c8, 0xf8}, + {0x32c9, 0xf }, + {0x32ca, 0xf4}, + {0x32cb, 0xad}, + {0x32cc, 0xf }, + {0x32cd, 0xfb}, + {0x32ce, 0x59}, + {0x32cf, 0x0 }, + {0x32d0, 0x9 }, + {0x32d1, 0xf7}, + {0x32d2, 0x0 }, + {0x32d3, 0x0 }, + {0x32d4, 0xc1}, + {0x32d5, 0xf }, + {0x32d6, 0xf5}, + {0x32d7, 0x30}, + {0x32d8, 0x0 }, + {0x32d9, 0x83}, + {0x32da, 0x1d}, + {0x32db, 0xf }, + {0x32dc, 0xe3}, + {0x32dd, 0x3c}, + {0x32de, 0x0 }, + {0x32df, 0xa }, + {0x32e0, 0x10}, + {0x32e1, 0x0 }, + {0x32e2, 0x7 }, + {0x32e3, 0x65}, + {0x32e4, 0xf }, + {0x32e5, 0xfe}, + {0x32e6, 0x79}, + {0x32e7, 0xf }, + {0x32e8, 0xfd}, + {0x32e9, 0x57}, + {0x32ea, 0xf }, + {0x32eb, 0xd6}, + {0x32ec, 0x8f}, + {0x32ed, 0x0 }, + {0x32ee, 0x3 }, + {0x32ef, 0x93}, + {0x32f0, 0x0 }, + {0x32f1, 0x6 }, + {0x32f2, 0xa }, + {0x32f3, 0xf }, + {0x32f4, 0xfa}, + {0x32f5, 0x6c}, + {0x32f6, 0xf }, + {0x32f7, 0xf1}, + {0x32f8, 0x1e}, + {0x32f9, 0x0 }, + {0x32fa, 0x14}, + {0x32fb, 0xe7}, + {0x32fc, 0x0 }, + {0x32fd, 0x1f}, + {0x32fe, 0x2d}, + {0x32ff, 0x0 }, + {0x3300, 0x7 }, + {0x3301, 0x5e}, + {0x3302, 0xf }, + {0x3303, 0xe0}, + {0x3304, 0x55}, + {0x3305, 0x0 }, + {0x3306, 0x20}, + {0x3307, 0x93}, + {0x3308, 0x0 }, + {0x3309, 0xf }, + {0x330a, 0x20}, + {0x330b, 0xf }, + {0x330c, 0xd7}, + {0x330d, 0xf5}, + {0x330e, 0xf }, + {0x330f, 0xef}, + {0x3310, 0xb8}, + {0x3311, 0xf }, + {0x3312, 0xf0}, + {0x3313, 0x29}, + {0x3314, 0x0 }, + {0x3315, 0x27}, + {0x3316, 0x5e}, + {0x3317, 0xf }, + {0x3318, 0xda}, + {0x3319, 0x14}, + {0x331a, 0xf }, + {0x331b, 0xef}, + {0x331c, 0x93}, + {0x331d, 0x0 }, + {0x331e, 0x2c}, + {0x331f, 0xdc}, + {0x3320, 0x0 }, + {0x3321, 0xe }, + {0x3322, 0x2d}, + {0x3323, 0x0 }, + {0x3324, 0x6 }, + {0x3325, 0xcf}, + {0x3326, 0xf }, + {0x3327, 0xfb}, + {0x3328, 0x26}, + {0x3329, 0x0 }, + {0x332a, 0x3 }, + {0x332b, 0x5 }, + {0x332c, 0x0 }, + {0x332d, 0x6 }, + {0x332e, 0xa6}, + {0x332f, 0xf }, + {0x3330, 0xf7}, + {0x3331, 0x7b}, + {0x3332, 0xf }, + {0x3333, 0xf9}, + {0x3334, 0xb }, + {0x3335, 0x0 }, + {0x3336, 0x7 }, + {0x3337, 0x5a}, + {0x3338, 0xf }, + {0x3339, 0xe4}, + {0x333a, 0x7a}, + {0x333b, 0x0 }, + {0x333c, 0x1b}, + {0x333d, 0xb0}, + {0x333e, 0x0 }, + {0x333f, 0x2 }, + {0x3340, 0xa7}, + {0x3341, 0xf }, + {0x3342, 0xe9}, + {0x3343, 0x3a}, + {0x3344, 0x0 }, + {0x3345, 0x95}, + {0x3346, 0x42}, + {0x3347, 0xf }, + {0x3348, 0xda}, + {0x3349, 0x45}, + {0x334a, 0x0 }, + {0x334b, 0x16}, + {0x334c, 0x7a}, + {0x334d, 0xf }, + {0x334e, 0xfb}, + {0x334f, 0x32}, + {0x3350, 0x0 }, + {0x3351, 0x6 }, + {0x3352, 0x35}, + {0x3353, 0xf }, + {0x3354, 0xfc}, + {0x3355, 0x8f}, + {0x3356, 0xf }, + {0x3357, 0xca}, + {0x3358, 0xd5}, + {0x3359, 0x0 }, + {0x335a, 0x11}, + {0x335b, 0x59}, + {0x335c, 0xf }, + {0x335d, 0xfa}, + {0x335e, 0xaa}, + {0x335f, 0xf }, + {0x3360, 0xfe}, + {0x3361, 0x84}, + {0x3362, 0xf }, + {0x3363, 0xf6}, + {0x3364, 0x8f}, + {0x3365, 0x0 }, + {0x3366, 0xb }, + {0x3367, 0x70}, + {0x3368, 0x0 }, + {0x3369, 0x25}, + {0x336a, 0x83}, + {0x336b, 0xf }, + {0x336c, 0xe7}, + {0x336d, 0x27}, + {0x336e, 0xf }, + {0x336f, 0xf1}, + {0x3370, 0x72}, + {0x3371, 0x0 }, + {0x3372, 0x21}, + {0x3373, 0x6d}, + {0x3374, 0x0 }, + {0x3375, 0x2 }, + {0x3376, 0xc3}, + {0x3377, 0xf }, + {0x3378, 0xe8}, + {0x3379, 0x5a}, + {0x337a, 0xf }, + {0x337b, 0xf2}, + {0x337c, 0x73}, + {0x337d, 0x0 }, + {0x337e, 0x19}, + {0x337f, 0xa5}, + {0x3380, 0x0 }, + {0x3381, 0x1a}, + {0x3382, 0x81}, + {0x3383, 0xf }, + {0x3384, 0xd0}, + {0x3385, 0x31}, + {0x3386, 0xf }, + {0x3387, 0xfb}, + {0x3388, 0xff}, + {0x3389, 0x0 }, + {0x338a, 0x1e}, + {0x338b, 0xe1}, + {0x338c, 0x0 }, + {0x338d, 0x5 }, + {0x338e, 0xe1}, + {0x338f, 0xf }, + {0x3390, 0xee}, + {0x3391, 0xe2}, + {0x3392, 0xf }, + {0x3393, 0xf6}, + {0x3394, 0xcf}, + {0x3395, 0x0 }, + {0x3396, 0x13}, + {0x3397, 0x8f}, + {0x3398, 0x0 }, + {0x3399, 0x3 }, + {0x339a, 0x61}, + {0x339b, 0xf }, + {0x339c, 0xf8}, + {0x339d, 0xf7}, + {0x339e, 0x0 }, + {0x339f, 0x0 }, + {0x33a0, 0xb5}, + {0x33a1, 0x0 }, + {0x33a2, 0x5 }, + {0x33a3, 0x78}, + {0x33a4, 0xf }, + {0x33a5, 0xf4}, + {0x33a6, 0x5 }, + {0x33a7, 0x0 }, + {0x33a8, 0xc }, + {0x33a9, 0xe }, + {0x33aa, 0x0 }, + {0x33ab, 0x3 }, + {0x33ac, 0x53}, + {0x33ad, 0xf }, + {0x33ae, 0xec}, + {0x33af, 0xbd}, +}; + +const struct +qs_s5k4e1_i2c_reg_conf qs_s5k4e1_lenshading_settings[4][LENS_SHADE_TABLE] = { + {/*2D Preview*/ + {0x3097, 0x52},/*sh4ch_blk_width = 82*/ + {0x3098, 0x3e},/*sh4ch_blk_height = 62*/ + {0x3099, 0x03},/*sh4ch_step_x msb (sh4ch_step_x = 799)*/ + {0x309a, 0x1f},/*sh4ch_step_x lsb*/ + {0x309b, 0x04},/*sh4ch_step_y msb (sh4ch_step_y = 1057)*/ + {0x309c, 0x21},/*sh4ch_step_y lsb*/ + {0x309d, 0x00},/*sh4ch_start_blk_cnt_x = 0*/ + {0x309e, 0x00},/*sh4ch_start_int_cnt_x = 0*/ + {0x309f, 0x00},/*sh4ch_start_frac_cnt_x msb (0)*/ + {0x30a0, 0x00},/*sh4ch_start_frac_cnt_x lsb*/ + {0x30a1, 0x00},/*sh4ch_start_blk_cnt_y = 0*/ + {0x30a2, 0x00},/*sh4ch_start_int_cnt_y = 0*/ + {0x30a3, 0x00},/*sh4ch_start_frac_cnt_y msb (0)*/ + {0x30a4, 0x00},/*sh4ch_start_frac_cnt_y lsb*/ + {0x30a5, 0x01}, + {0x30a6, 0x00},/*gs_pedestal = 64*/ + }, + {/*2D Snapshot*/ + {0x3097, 0x52},/*sh4ch_blk_width = 82*/ + {0x3098, 0x7b},/*sh4ch_blk_height = 123*/ + {0x3099, 0x03},/*sh4ch_step_x msb (sh4ch_step_x = 799)*/ + {0x309a, 0x1f},/*sh4ch_step_x lsb*/ + {0x309b, 0x02},/*sh4ch_step_y msb (sh4ch_step_y = 533)*/ + {0x309c, 0x15},/*sh4ch_step_y lsb*/ + {0x309d, 0x00},/*sh4ch_start_blk_cnt_x = 0*/ + {0x309e, 0x00},/*sh4ch_start_int_cnt_x = 0*/ + {0x309f, 0x00},/*sh4ch_start_frac_cnt_x msb (0)*/ + {0x30a0, 0x00},/*sh4ch_start_frac_cnt_x lsb*/ + {0x30a1, 0x00},/*sh4ch_start_blk_cnt_y = 0*/ + {0x30a2, 0x00},/*sh4ch_start_int_cnt_y = 0*/ + {0x30a3, 0x00},/*sh4ch_start_frac_cnt_y msb (0)*/ + {0x30a4, 0x00},/*sh4ch_start_frac_cnt_y lsb*/ + {0x30a5, 0x01}, + {0x30a6, 0x00},/*gs_pedestal = 64*/ + }, + + {/*3D Preview*/ + {0x3097, 0x52},/*sh4ch_blk_width = 82*/ + {0x3098, 0x7b},/*sh4ch_blk_height = 123*/ + {0x3099, 0x03},/*sh4ch_step_x msb (sh4ch_step_x = 799)*/ + {0x309a, 0x1f},/*sh4ch_step_x lsb*/ + {0x309b, 0x02},/*sh4ch_step_y msb (sh4ch_step_y = 533)*/ + {0x309c, 0x15},/*sh4ch_step_y lsb*/ + {0x309d, 0x3a},/*sh4ch_start_blk_cnt_x = 58*/ + {0x309e, 0x01},/*sh4ch_start_int_cnt_x = 1*/ + {0x309f, 0xb5},/*sh4ch_start_frac_cnt_x msb (46342)*/ + {0x30a0, 0x06},/*sh4ch_start_frac_cnt_x lsb*/ + {0x30a1, 0x23},/*sh4ch_start_blk_cnt_y = 35*/ + {0x30a2, 0x03},/*sh4ch_start_int_cnt_y = 3*/ + {0x30a3, 0x48},/*sh4ch_start_frac_cnt_y msb (46342)*/ + {0x30a4, 0xdf},/*sh4ch_start_frac_cnt_y lsb*/ + {0x30a5, 0x01}, + {0x30a6, 0x00},/*gs_pedestal = 64*/ + }, + + {/*3D Snapshot*/ + {0x3097, 0x52},/*sh4ch_blk_width = 82*/ + {0x3098, 0x7b},/*sh4ch_blk_height = 123*/ + {0x3099, 0x03},/*sh4ch_step_x msb (sh4ch_step_x = 799)*/ + {0x309a, 0x1f},/*sh4ch_step_x lsb*/ + {0x309b, 0x02},/*sh4ch_step_y msb (sh4ch_step_y = 533)*/ + {0x309c, 0x15},/*sh4ch_step_y lsb*/ + {0x309d, 0x38},/*sh4ch_start_blk_cnt_x = 56*/ + {0x309e, 0x01},/*sh4ch_start_int_cnt_x = 1*/ + {0x309f, 0xae},/*sh4ch_start_frac_cnt_x msb (44744)*/ + {0x30a0, 0xc8},/*sh4ch_start_frac_cnt_x lsb*/ + {0x30a1, 0x23},/*sh4ch_start_blk_cnt_y = 35*/ + {0x30a2, 0x03},/*sh4ch_start_int_cnt_y = 3*/ + {0x30a3, 0x48},/*sh4ch_start_frac_cnt_y msb (44744)*/ + {0x30a4, 0xdf},/*sh4ch_start_frac_cnt_y lsb*/ + {0x30a5, 0x01}, + {0x30a6, 0x00},/*gs_pedestal = 64*/ + }, + +}; + +struct qs_s5k4e1_i2c_conf_array qs_s5k4e1_confs[] = { + {&qs_s5k4e1_prev_settings_2d[0], \ + ARRAY_SIZE(qs_s5k4e1_prev_settings_2d)}, + {&qs_s5k4e1_snap_settings_2d[0], \ + ARRAY_SIZE(qs_s5k4e1_snap_settings_2d)}, + {&qs_s5k4e1_prev_settings_3d[0], \ + ARRAY_SIZE(qs_s5k4e1_prev_settings_3d)}, + {&qs_s5k4e1_snap_settings_3d[0], \ + ARRAY_SIZE(qs_s5k4e1_snap_settings_3d)}, +}; +struct qs_s5k4e1_reg qs_s5k4e1_regs = { + .rec_settings = &qs_s5k4e1_recommend_settings[0], + .rec_size = ARRAY_SIZE(qs_s5k4e1_recommend_settings), + .reg_lens = &qs_s5k4e1_lenshading_settings[0], + .reg_lens_size = ARRAY_SIZE(qs_s5k4e1_lenshading_settings[0]), + .reg_default_lens = &qs_s5k4e1_default_lenshading_settings[0], + .reg_default_lens_size = + ARRAY_SIZE(qs_s5k4e1_default_lenshading_settings), + .conf_array = &qs_s5k4e1_confs[0], +}; diff --git a/drivers/media/video/msm_zsl/s5k3e2fx.c b/drivers/media/video/msm_zsl/s5k3e2fx.c new file mode 100644 index 00000000000..75766fc1b94 --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k3e2fx.c @@ -0,0 +1,1385 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "s5k3e2fx.h" + +#define S5K3E2FX_REG_MODEL_ID 0x0000 +#define S5K3E2FX_MODEL_ID 0x3E2F + +/* PLL Registers */ +#define REG_PRE_PLL_CLK_DIV 0x0305 +#define REG_PLL_MULTIPLIER_MSB 0x0306 +#define REG_PLL_MULTIPLIER_LSB 0x0307 +#define REG_VT_PIX_CLK_DIV 0x0301 +#define REG_VT_SYS_CLK_DIV 0x0303 +#define REG_OP_PIX_CLK_DIV 0x0309 +#define REG_OP_SYS_CLK_DIV 0x030B + +/* Data Format Registers */ +#define REG_CCP_DATA_FORMAT_MSB 0x0112 +#define REG_CCP_DATA_FORMAT_LSB 0x0113 + +/* Output Size */ +#define REG_X_OUTPUT_SIZE_MSB 0x034C +#define REG_X_OUTPUT_SIZE_LSB 0x034D +#define REG_Y_OUTPUT_SIZE_MSB 0x034E +#define REG_Y_OUTPUT_SIZE_LSB 0x034F + +/* Binning */ +#define REG_X_EVEN_INC 0x0381 +#define REG_X_ODD_INC 0x0383 +#define REG_Y_EVEN_INC 0x0385 +#define REG_Y_ODD_INC 0x0387 +/*Reserved register */ +#define REG_BINNING_ENABLE 0x3014 + +/* Frame Fotmat */ +#define REG_FRAME_LENGTH_LINES_MSB 0x0340 +#define REG_FRAME_LENGTH_LINES_LSB 0x0341 +#define REG_LINE_LENGTH_PCK_MSB 0x0342 +#define REG_LINE_LENGTH_PCK_LSB 0x0343 + +/* MSR setting */ +/* Reserved registers */ +#define REG_SHADE_CLK_ENABLE 0x30AC +#define REG_SEL_CCP 0x30C4 +#define REG_VPIX 0x3024 +#define REG_CLAMP_ON 0x3015 +#define REG_OFFSET 0x307E + +/* CDS timing settings */ +/* Reserved registers */ +#define REG_LD_START 0x3000 +#define REG_LD_END 0x3001 +#define REG_SL_START 0x3002 +#define REG_SL_END 0x3003 +#define REG_RX_START 0x3004 +#define REG_S1_START 0x3005 +#define REG_S1_END 0x3006 +#define REG_S1S_START 0x3007 +#define REG_S1S_END 0x3008 +#define REG_S3_START 0x3009 +#define REG_S3_END 0x300A +#define REG_CMP_EN_START 0x300B +#define REG_CLP_SL_START 0x300C +#define REG_CLP_SL_END 0x300D +#define REG_OFF_START 0x300E +#define REG_RMP_EN_START 0x300F +#define REG_TX_START 0x3010 +#define REG_TX_END 0x3011 +#define REG_STX_WIDTH 0x3012 +#define REG_TYPE1_AF_ENABLE 0x3130 +#define DRIVER_ENABLED 0x0001 +#define AUTO_START_ENABLED 0x0010 +#define REG_NEW_POSITION 0x3131 +#define REG_3152_RESERVED 0x3152 +#define REG_315A_RESERVED 0x315A +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204 +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205 +#define REG_FINE_INTEGRATION_TIME 0x0200 +#define REG_COARSE_INTEGRATION_TIME 0x0202 +#define REG_COARSE_INTEGRATION_TIME_LSB 0x0203 + +/* Mode select register */ +#define S5K3E2FX_REG_MODE_SELECT 0x0100 +#define S5K3E2FX_MODE_SELECT_STREAM 0x01 /* start streaming */ +#define S5K3E2FX_MODE_SELECT_SW_STANDBY 0x00 /* software standby */ +#define S5K3E2FX_REG_SOFTWARE_RESET 0x0103 +#define S5K3E2FX_SOFTWARE_RESET 0x01 +#define REG_TEST_PATTERN_MODE 0x0601 + +struct reg_struct { + uint8_t pre_pll_clk_div; /* 0x0305 */ + uint8_t pll_multiplier_msb; /* 0x0306 */ + uint8_t pll_multiplier_lsb; /* 0x0307 */ + uint8_t vt_pix_clk_div; /* 0x0301 */ + uint8_t vt_sys_clk_div; /* 0x0303 */ + uint8_t op_pix_clk_div; /* 0x0309 */ + uint8_t op_sys_clk_div; /* 0x030B */ + uint8_t ccp_data_format_msb; /* 0x0112 */ + uint8_t ccp_data_format_lsb; /* 0x0113 */ + uint8_t x_output_size_msb; /* 0x034C */ + uint8_t x_output_size_lsb; /* 0x034D */ + uint8_t y_output_size_msb; /* 0x034E */ + uint8_t y_output_size_lsb; /* 0x034F */ + uint8_t x_even_inc; /* 0x0381 */ + uint8_t x_odd_inc; /* 0x0383 */ + uint8_t y_even_inc; /* 0x0385 */ + uint8_t y_odd_inc; /* 0x0387 */ + uint8_t binning_enable; /* 0x3014 */ + uint8_t frame_length_lines_msb; /* 0x0340 */ + uint8_t frame_length_lines_lsb; /* 0x0341 */ + uint8_t line_length_pck_msb; /* 0x0342 */ + uint8_t line_length_pck_lsb; /* 0x0343 */ + uint8_t shade_clk_enable ; /* 0x30AC */ + uint8_t sel_ccp; /* 0x30C4 */ + uint8_t vpix; /* 0x3024 */ + uint8_t clamp_on; /* 0x3015 */ + uint8_t offset; /* 0x307E */ + uint8_t ld_start; /* 0x3000 */ + uint8_t ld_end; /* 0x3001 */ + uint8_t sl_start; /* 0x3002 */ + uint8_t sl_end; /* 0x3003 */ + uint8_t rx_start; /* 0x3004 */ + uint8_t s1_start; /* 0x3005 */ + uint8_t s1_end; /* 0x3006 */ + uint8_t s1s_start; /* 0x3007 */ + uint8_t s1s_end; /* 0x3008 */ + uint8_t s3_start; /* 0x3009 */ + uint8_t s3_end; /* 0x300A */ + uint8_t cmp_en_start; /* 0x300B */ + uint8_t clp_sl_start; /* 0x300C */ + uint8_t clp_sl_end; /* 0x300D */ + uint8_t off_start; /* 0x300E */ + uint8_t rmp_en_start; /* 0x300F */ + uint8_t tx_start; /* 0x3010 */ + uint8_t tx_end; /* 0x3011 */ + uint8_t stx_width; /* 0x3012 */ + uint8_t reg_3152_reserved; /* 0x3152 */ + uint8_t reg_315A_reserved; /* 0x315A */ + uint8_t analogue_gain_code_global_msb; /* 0x0204 */ + uint8_t analogue_gain_code_global_lsb; /* 0x0205 */ + uint8_t fine_integration_time; /* 0x0200 */ + uint8_t coarse_integration_time; /* 0x0202 */ + uint32_t size_h; + uint32_t blk_l; + uint32_t size_w; + uint32_t blk_p; +}; + +struct reg_struct s5k3e2fx_reg_pat[2] = { + { /* Preview */ + 0x06, /* pre_pll_clk_div REG=0x0305 */ + 0x00, /* pll_multiplier_msb REG=0x0306 */ + 0x88, /* pll_multiplier_lsb REG=0x0307 */ + 0x0a, /* vt_pix_clk_div REG=0x0301 */ + 0x01, /* vt_sys_clk_div REG=0x0303 */ + 0x0a, /* op_pix_clk_div REG=0x0309 */ + 0x01, /* op_sys_clk_div REG=0x030B */ + 0x0a, /* ccp_data_format_msb REG=0x0112 */ + 0x0a, /* ccp_data_format_lsb REG=0x0113 */ + 0x05, /* x_output_size_msb REG=0x034C */ + 0x10, /* x_output_size_lsb REG=0x034D */ + 0x03, /* y_output_size_msb REG=0x034E */ + 0xcc, /* y_output_size_lsb REG=0x034F */ + + /* enable binning for preview */ + 0x01, /* x_even_inc REG=0x0381 */ + 0x01, /* x_odd_inc REG=0x0383 */ + 0x01, /* y_even_inc REG=0x0385 */ + 0x03, /* y_odd_inc REG=0x0387 */ + 0x06, /* binning_enable REG=0x3014 */ + + 0x03, /* frame_length_lines_msb REG=0x0340 */ + 0xde, /* frame_length_lines_lsb REG=0x0341 */ + 0x0a, /* line_length_pck_msb REG=0x0342 */ + 0xac, /* line_length_pck_lsb REG=0x0343 */ + 0x81, /* shade_clk_enable REG=0x30AC */ + 0x01, /* sel_ccp REG=0x30C4 */ + 0x04, /* vpix REG=0x3024 */ + 0x00, /* clamp_on REG=0x3015 */ + 0x02, /* offset REG=0x307E */ + 0x03, /* ld_start REG=0x3000 */ + 0x9c, /* ld_end REG=0x3001 */ + 0x02, /* sl_start REG=0x3002 */ + 0x9e, /* sl_end REG=0x3003 */ + 0x05, /* rx_start REG=0x3004 */ + 0x0f, /* s1_start REG=0x3005 */ + 0x24, /* s1_end REG=0x3006 */ + 0x7c, /* s1s_start REG=0x3007 */ + 0x9a, /* s1s_end REG=0x3008 */ + 0x10, /* s3_start REG=0x3009 */ + 0x14, /* s3_end REG=0x300A */ + 0x10, /* cmp_en_start REG=0x300B */ + 0x04, /* clp_sl_start REG=0x300C */ + 0x26, /* clp_sl_end REG=0x300D */ + 0x02, /* off_start REG=0x300E */ + 0x0e, /* rmp_en_start REG=0x300F */ + 0x30, /* tx_start REG=0x3010 */ + 0x4e, /* tx_end REG=0x3011 */ + 0x1E, /* stx_width REG=0x3012 */ + 0x08, /* reg_3152_reserved REG=0x3152 */ + 0x10, /* reg_315A_reserved REG=0x315A */ + 0x00, /* analogue_gain_code_global_msb REG=0x0204 */ + 0x80, /* analogue_gain_code_global_lsb REG=0x0205 */ + 0x02, /* fine_integration_time REG=0x0200 */ + 0x03, /* coarse_integration_time REG=0x0202 */ + 972, + 18, + 1296, + 1436 + }, + { /* Snapshot */ + 0x06, /* pre_pll_clk_div REG=0x0305 */ + 0x00, /* pll_multiplier_msb REG=0x0306 */ + 0x88, /* pll_multiplier_lsb REG=0x0307 */ + 0x0a, /* vt_pix_clk_div REG=0x0301 */ + 0x01, /* vt_sys_clk_div REG=0x0303 */ + 0x0a, /* op_pix_clk_div REG=0x0309 */ + 0x01, /* op_sys_clk_div REG=0x030B */ + 0x0a, /* ccp_data_format_msb REG=0x0112 */ + 0x0a, /* ccp_data_format_lsb REG=0x0113 */ + 0x0a, /* x_output_size_msb REG=0x034C */ + 0x30, /* x_output_size_lsb REG=0x034D */ + 0x07, /* y_output_size_msb REG=0x034E */ + 0xa8, /* y_output_size_lsb REG=0x034F */ + + /* disable binning for snapshot */ + 0x01, /* x_even_inc REG=0x0381 */ + 0x01, /* x_odd_inc REG=0x0383 */ + 0x01, /* y_even_inc REG=0x0385 */ + 0x01, /* y_odd_inc REG=0x0387 */ + 0x00, /* binning_enable REG=0x3014 */ + + 0x07, /* frame_length_lines_msb REG=0x0340 */ + 0xb6, /* frame_length_lines_lsb REG=0x0341 */ + 0x0a, /* line_length_pck_msb REG=0x0342 */ + 0xac, /* line_length_pck_lsb REG=0x0343 */ + 0x81, /* shade_clk_enable REG=0x30AC */ + 0x01, /* sel_ccp REG=0x30C4 */ + 0x04, /* vpix REG=0x3024 */ + 0x00, /* clamp_on REG=0x3015 */ + 0x02, /* offset REG=0x307E */ + 0x03, /* ld_start REG=0x3000 */ + 0x9c, /* ld_end REG=0x3001 */ + 0x02, /* sl_start REG=0x3002 */ + 0x9e, /* sl_end REG=0x3003 */ + 0x05, /* rx_start REG=0x3004 */ + 0x0f, /* s1_start REG=0x3005 */ + 0x24, /* s1_end REG=0x3006 */ + 0x7c, /* s1s_start REG=0x3007 */ + 0x9a, /* s1s_end REG=0x3008 */ + 0x10, /* s3_start REG=0x3009 */ + 0x14, /* s3_end REG=0x300A */ + 0x10, /* cmp_en_start REG=0x300B */ + 0x04, /* clp_sl_start REG=0x300C */ + 0x26, /* clp_sl_end REG=0x300D */ + 0x02, /* off_start REG=0x300E */ + 0x0e, /* rmp_en_start REG=0x300F */ + 0x30, /* tx_start REG=0x3010 */ + 0x4e, /* tx_end REG=0x3011 */ + 0x1E, /* stx_width REG=0x3012 */ + 0x08, /* reg_3152_reserved REG=0x3152 */ + 0x10, /* reg_315A_reserved REG=0x315A */ + 0x00, /* analogue_gain_code_global_msb REG=0x0204 */ + 0x80, /* analogue_gain_code_global_lsb REG=0x0205 */ + 0x02, /* fine_integration_time REG=0x0200 */ + 0x03, /* coarse_integration_time REG=0x0202 */ + 1960, + 14, + 2608, + 124 + } +}; + +struct s5k3e2fx_work { + struct work_struct work; +}; +static struct s5k3e2fx_work *s5k3e2fx_sensorw; +static struct i2c_client *s5k3e2fx_client; + +struct s5k3e2fx_ctrl { + const struct msm_camera_sensor_info *sensordata; + + int sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + + uint16_t curr_lens_pos; + uint16_t init_curr_lens_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + + enum msm_s_resolution prev_res; + enum msm_s_resolution pict_res; + enum msm_s_resolution curr_res; + enum msm_s_test_mode set_test; +}; + +struct s5k3e2fx_i2c_reg_conf { + unsigned short waddr; + unsigned char bdata; +}; + +static struct s5k3e2fx_ctrl *s5k3e2fx_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(s5k3e2fx_wait_queue); +DEFINE_MUTEX(s5k3e2fx_mutex); + +static int s5k3e2fx_i2c_rxdata(unsigned short saddr, unsigned char *rxdata, + int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, + }, + }; + + if (i2c_transfer(s5k3e2fx_client->adapter, msgs, 2) < 0) { + CDBG("s5k3e2fx_i2c_rxdata failed!\n"); + return -EIO; + } + + return 0; +} + +static int32_t s5k3e2fx_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + if (i2c_transfer(s5k3e2fx_client->adapter, msg, 1) < 0) { + CDBG("s5k3e2fx_i2c_txdata failed\n"); + return -EIO; + } + + return 0; +} + +static int32_t s5k3e2fx_i2c_write_b(unsigned short saddr, unsigned short waddr, + unsigned char bdata) +{ + int32_t rc = -EIO; + unsigned char buf[4]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00)>>8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + + rc = s5k3e2fx_i2c_txdata(saddr, buf, 3); + + if (rc < 0) + CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + + return rc; +} + +static int32_t s5k3e2fx_i2c_write_table( + struct s5k3e2fx_i2c_reg_conf *reg_cfg_tbl, int num) +{ + int i; + int32_t rc = -EIO; + for (i = 0; i < num; i++) { + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + reg_cfg_tbl->waddr, reg_cfg_tbl->bdata); + if (rc < 0) + break; + reg_cfg_tbl++; + } + + return rc; +} + +static int32_t s5k3e2fx_i2c_read_w(unsigned short saddr, unsigned short raddr, + unsigned short *rdata) +{ + int32_t rc = 0; + unsigned char buf[4]; + + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + + buf[0] = (raddr & 0xFF00)>>8; + buf[1] = (raddr & 0x00FF); + + rc = s5k3e2fx_i2c_rxdata(saddr, buf, 2); + if (rc < 0) + return rc; + + *rdata = buf[0] << 8 | buf[1]; + + if (rc < 0) + CDBG("s5k3e2fx_i2c_read failed!\n"); + + return rc; +} + +static int s5k3e2fx_probe_init_done(const struct msm_camera_sensor_info *data) +{ + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + return 0; +} + +static int s5k3e2fx_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + uint16_t chipid = 0; + + rc = gpio_request(data->sensor_reset, "s5k3e2fx"); + if (!rc) + gpio_direction_output(data->sensor_reset, 1); + else + goto init_probe_done; + + mdelay(20); + + CDBG("s5k3e2fx_sensor_init(): reseting sensor.\n"); + + rc = s5k3e2fx_i2c_read_w(s5k3e2fx_client->addr, + S5K3E2FX_REG_MODEL_ID, &chipid); + if (rc < 0) + goto init_probe_fail; + + if (chipid != S5K3E2FX_MODEL_ID) { + CDBG("S5K3E2FX wrong model_id = 0x%x\n", chipid); + rc = -ENODEV; + goto init_probe_fail; + } + + goto init_probe_done; + +init_probe_fail: + s5k3e2fx_probe_init_done(data); +init_probe_done: + return rc; +} + +static int s5k3e2fx_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&s5k3e2fx_wait_queue); + return 0; +} + +static const struct i2c_device_id s5k3e2fx_i2c_id[] = { + { "s5k3e2fx", 0}, + { } +}; + +static int s5k3e2fx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("s5k3e2fx_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + s5k3e2fx_sensorw = kzalloc(sizeof(struct s5k3e2fx_work), GFP_KERNEL); + if (!s5k3e2fx_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, s5k3e2fx_sensorw); + s5k3e2fx_init_client(client); + s5k3e2fx_client = client; + + mdelay(50); + + CDBG("s5k3e2fx_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("s5k3e2fx_probe failed! rc = %d\n", rc); + return rc; +} + +static struct i2c_driver s5k3e2fx_i2c_driver = { + .id_table = s5k3e2fx_i2c_id, + .probe = s5k3e2fx_i2c_probe, + .remove = __exit_p(s5k3e2fx_i2c_remove), + .driver = { + .name = "s5k3e2fx", + }, +}; + +static int32_t s5k3e2fx_test(enum msm_s_test_mode mo) +{ + int32_t rc = 0; + + if (mo == S_TEST_OFF) + rc = 0; + else + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + REG_TEST_PATTERN_MODE, (uint16_t)mo); + + return rc; +} + +static int32_t s5k3e2fx_setting(enum msm_s_reg_update rupdate, + enum msm_s_setting rt) +{ + int32_t rc = 0; + uint16_t num_lperf; + + switch (rupdate) { + case S_UPDATE_PERIODIC: + if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) { + + struct s5k3e2fx_i2c_reg_conf tbl_1[] = { + {REG_CCP_DATA_FORMAT_MSB, + s5k3e2fx_reg_pat[rt].ccp_data_format_msb}, + {REG_CCP_DATA_FORMAT_LSB, + s5k3e2fx_reg_pat[rt].ccp_data_format_lsb}, + {REG_X_OUTPUT_SIZE_MSB, + s5k3e2fx_reg_pat[rt].x_output_size_msb}, + {REG_X_OUTPUT_SIZE_LSB, + s5k3e2fx_reg_pat[rt].x_output_size_lsb}, + {REG_Y_OUTPUT_SIZE_MSB, + s5k3e2fx_reg_pat[rt].y_output_size_msb}, + {REG_Y_OUTPUT_SIZE_LSB, + s5k3e2fx_reg_pat[rt].y_output_size_lsb}, + {REG_X_EVEN_INC, + s5k3e2fx_reg_pat[rt].x_even_inc}, + {REG_X_ODD_INC, + s5k3e2fx_reg_pat[rt].x_odd_inc}, + {REG_Y_EVEN_INC, + s5k3e2fx_reg_pat[rt].y_even_inc}, + {REG_Y_ODD_INC, + s5k3e2fx_reg_pat[rt].y_odd_inc}, + {REG_BINNING_ENABLE, + s5k3e2fx_reg_pat[rt].binning_enable}, + }; + + struct s5k3e2fx_i2c_reg_conf tbl_2[] = { + {REG_FRAME_LENGTH_LINES_MSB, 0}, + {REG_FRAME_LENGTH_LINES_LSB, 0}, + {REG_LINE_LENGTH_PCK_MSB, + s5k3e2fx_reg_pat[rt].line_length_pck_msb}, + {REG_LINE_LENGTH_PCK_LSB, + s5k3e2fx_reg_pat[rt].line_length_pck_lsb}, + {REG_SHADE_CLK_ENABLE, + s5k3e2fx_reg_pat[rt].shade_clk_enable}, + {REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp}, + {REG_VPIX, s5k3e2fx_reg_pat[rt].vpix}, + {REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on}, + {REG_OFFSET, s5k3e2fx_reg_pat[rt].offset}, + {REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start}, + {REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end}, + {REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start}, + {REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end}, + {REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start}, + {REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start}, + {REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end}, + {REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start}, + {REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end}, + {REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start}, + {REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end}, + {REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start}, + {REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start}, + {REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end}, + {REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start}, + {REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start}, + {REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start}, + {REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end}, + {REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width}, + {REG_3152_RESERVED, + s5k3e2fx_reg_pat[rt].reg_3152_reserved}, + {REG_315A_RESERVED, + s5k3e2fx_reg_pat[rt].reg_315A_reserved}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, + s5k3e2fx_reg_pat[rt]. + analogue_gain_code_global_msb}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, + s5k3e2fx_reg_pat[rt]. + analogue_gain_code_global_lsb}, + {REG_FINE_INTEGRATION_TIME, + s5k3e2fx_reg_pat[rt].fine_integration_time}, + {REG_COARSE_INTEGRATION_TIME, + s5k3e2fx_reg_pat[rt].coarse_integration_time}, + {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM}, + }; + + rc = s5k3e2fx_i2c_write_table(&tbl_1[0], + ARRAY_SIZE(tbl_1)); + if (rc < 0) + return rc; + + num_lperf = (uint16_t) + ((s5k3e2fx_reg_pat[rt].frame_length_lines_msb << 8) + & 0xFF00) + + s5k3e2fx_reg_pat[rt].frame_length_lines_lsb; + + num_lperf = num_lperf * s5k3e2fx_ctrl->fps_divider / 0x0400; + + tbl_2[0] = (struct s5k3e2fx_i2c_reg_conf) + {REG_FRAME_LENGTH_LINES_MSB, (num_lperf & 0xFF00) >> 8}; + tbl_2[1] = (struct s5k3e2fx_i2c_reg_conf) + {REG_FRAME_LENGTH_LINES_LSB, (num_lperf & 0x00FF)}; + + rc = s5k3e2fx_i2c_write_table(&tbl_2[0], + ARRAY_SIZE(tbl_2)); + if (rc < 0) + return rc; + + mdelay(5); + + rc = s5k3e2fx_test(s5k3e2fx_ctrl->set_test); + if (rc < 0) + return rc; + } + break; /* UPDATE_PERIODIC */ + + case S_REG_INIT: + if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) { + + struct s5k3e2fx_i2c_reg_conf tbl_3[] = { + {S5K3E2FX_REG_SOFTWARE_RESET, S5K3E2FX_SOFTWARE_RESET}, + {S5K3E2FX_REG_MODE_SELECT, + S5K3E2FX_MODE_SELECT_SW_STANDBY}, + /* PLL setting */ + {REG_PRE_PLL_CLK_DIV, + s5k3e2fx_reg_pat[rt].pre_pll_clk_div}, + {REG_PLL_MULTIPLIER_MSB, + s5k3e2fx_reg_pat[rt].pll_multiplier_msb}, + {REG_PLL_MULTIPLIER_LSB, + s5k3e2fx_reg_pat[rt].pll_multiplier_lsb}, + {REG_VT_PIX_CLK_DIV, + s5k3e2fx_reg_pat[rt].vt_pix_clk_div}, + {REG_VT_SYS_CLK_DIV, + s5k3e2fx_reg_pat[rt].vt_sys_clk_div}, + {REG_OP_PIX_CLK_DIV, + s5k3e2fx_reg_pat[rt].op_pix_clk_div}, + {REG_OP_SYS_CLK_DIV, + s5k3e2fx_reg_pat[rt].op_sys_clk_div}, + /*Data Format */ + {REG_CCP_DATA_FORMAT_MSB, + s5k3e2fx_reg_pat[rt].ccp_data_format_msb}, + {REG_CCP_DATA_FORMAT_LSB, + s5k3e2fx_reg_pat[rt].ccp_data_format_lsb}, + /*Output Size */ + {REG_X_OUTPUT_SIZE_MSB, + s5k3e2fx_reg_pat[rt].x_output_size_msb}, + {REG_X_OUTPUT_SIZE_LSB, + s5k3e2fx_reg_pat[rt].x_output_size_lsb}, + {REG_Y_OUTPUT_SIZE_MSB, + s5k3e2fx_reg_pat[rt].y_output_size_msb}, + {REG_Y_OUTPUT_SIZE_LSB, + s5k3e2fx_reg_pat[rt].y_output_size_lsb}, + /* Binning */ + {REG_X_EVEN_INC, s5k3e2fx_reg_pat[rt].x_even_inc}, + {REG_X_ODD_INC, s5k3e2fx_reg_pat[rt].x_odd_inc }, + {REG_Y_EVEN_INC, s5k3e2fx_reg_pat[rt].y_even_inc}, + {REG_Y_ODD_INC, s5k3e2fx_reg_pat[rt].y_odd_inc}, + {REG_BINNING_ENABLE, + s5k3e2fx_reg_pat[rt].binning_enable}, + /* Frame format */ + {REG_FRAME_LENGTH_LINES_MSB, + s5k3e2fx_reg_pat[rt].frame_length_lines_msb}, + {REG_FRAME_LENGTH_LINES_LSB, + s5k3e2fx_reg_pat[rt].frame_length_lines_lsb}, + {REG_LINE_LENGTH_PCK_MSB, + s5k3e2fx_reg_pat[rt].line_length_pck_msb}, + {REG_LINE_LENGTH_PCK_LSB, + s5k3e2fx_reg_pat[rt].line_length_pck_lsb}, + /* MSR setting */ + {REG_SHADE_CLK_ENABLE, + s5k3e2fx_reg_pat[rt].shade_clk_enable}, + {REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp}, + {REG_VPIX, s5k3e2fx_reg_pat[rt].vpix}, + {REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on}, + {REG_OFFSET, s5k3e2fx_reg_pat[rt].offset}, + /* CDS timing setting */ + {REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start}, + {REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end}, + {REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start}, + {REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end}, + {REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start}, + {REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start}, + {REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end}, + {REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start}, + {REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end}, + {REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start}, + {REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end}, + {REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start}, + {REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start}, + {REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end}, + {REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start}, + {REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start}, + {REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start}, + {REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end}, + {REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width}, + {REG_3152_RESERVED, + s5k3e2fx_reg_pat[rt].reg_3152_reserved}, + {REG_315A_RESERVED, + s5k3e2fx_reg_pat[rt].reg_315A_reserved}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, + s5k3e2fx_reg_pat[rt]. + analogue_gain_code_global_msb}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, + s5k3e2fx_reg_pat[rt]. + analogue_gain_code_global_lsb}, + {REG_FINE_INTEGRATION_TIME, + s5k3e2fx_reg_pat[rt].fine_integration_time}, + {REG_COARSE_INTEGRATION_TIME, + s5k3e2fx_reg_pat[rt].coarse_integration_time}, + {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM}, + }; + + /* reset fps_divider */ + s5k3e2fx_ctrl->fps_divider = 1 * 0x0400; + rc = s5k3e2fx_i2c_write_table(&tbl_3[0], + ARRAY_SIZE(tbl_3)); + if (rc < 0) + return rc; + } + break; /* case REG_INIT: */ + + default: + rc = -EINVAL; + break; + } /* switch (rupdate) */ + + return rc; +} + +static int s5k3e2fx_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + + s5k3e2fx_ctrl = kzalloc(sizeof(struct s5k3e2fx_ctrl), GFP_KERNEL); + if (!s5k3e2fx_ctrl) { + CDBG("s5k3e2fx_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + s5k3e2fx_ctrl->fps_divider = 1 * 0x00000400; + s5k3e2fx_ctrl->pict_fps_divider = 1 * 0x00000400; + s5k3e2fx_ctrl->set_test = S_TEST_OFF; + s5k3e2fx_ctrl->prev_res = S_QTR_SIZE; + s5k3e2fx_ctrl->pict_res = S_FULL_SIZE; + + if (data) + s5k3e2fx_ctrl->sensordata = data; + + /* enable mclk first */ + msm_camio_clk_rate_set(24000000); + mdelay(20); + + msm_camio_camif_pad_reg_reset(); + mdelay(20); + + rc = s5k3e2fx_probe_init_sensor(data); + if (rc < 0) + goto init_fail1; + + if (s5k3e2fx_ctrl->prev_res == S_QTR_SIZE) + rc = s5k3e2fx_setting(S_REG_INIT, S_RES_PREVIEW); + else + rc = s5k3e2fx_setting(S_REG_INIT, S_RES_CAPTURE); + + if (rc < 0) { + CDBG("s5k3e2fx_setting failed. rc = %d\n", rc); + goto init_fail1; + } + + /* initialize AF */ + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + 0x3146, 0x3A); + if (rc < 0) + goto init_fail1; + + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + 0x3130, 0x03); + if (rc < 0) + goto init_fail1; + + goto init_done; + +init_fail1: + s5k3e2fx_probe_init_done(data); + kfree(s5k3e2fx_ctrl); +init_done: + return rc; +} + +static int32_t s5k3e2fx_power_down(void) +{ + int32_t rc = 0; + return rc; +} + +static int s5k3e2fx_sensor_release(void) +{ + int rc = -EBADF; + + mutex_lock(&s5k3e2fx_mutex); + + s5k3e2fx_power_down(); + + gpio_direction_output(s5k3e2fx_ctrl->sensordata->sensor_reset, + 0); + gpio_free(s5k3e2fx_ctrl->sensordata->sensor_reset); + + kfree(s5k3e2fx_ctrl); + s5k3e2fx_ctrl = NULL; + + CDBG("s5k3e2fx_release completed\n"); + + mutex_unlock(&s5k3e2fx_mutex); + return rc; +} + +static void s5k3e2fx_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint32_t divider; /* Q10 */ + + divider = (uint32_t) + ((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + + s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) * + (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w + + s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p)) * 0x00000400 / + ((s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h + + s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l) * + (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w + + s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p)); + + /* Verify PCLK settings and frame sizes. */ + *pfps = (uint16_t)(fps * divider / 0x00000400); +} + +static uint16_t s5k3e2fx_get_prev_lines_pf(void) +{ + return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + + s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l; +} + +static uint16_t s5k3e2fx_get_prev_pixels_pl(void) +{ + return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w + + s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p; +} + +static uint16_t s5k3e2fx_get_pict_lines_pf(void) +{ + return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h + + s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l; +} + +static uint16_t s5k3e2fx_get_pict_pixels_pl(void) +{ + return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w + + s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p; +} + +static uint32_t s5k3e2fx_get_pict_max_exp_lc(void) +{ + uint32_t snapshot_lines_per_frame; + + if (s5k3e2fx_ctrl->pict_res == S_QTR_SIZE) + snapshot_lines_per_frame = + s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + + s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l; + else + snapshot_lines_per_frame = 3961 * 3; + + return snapshot_lines_per_frame; +} + +static int32_t s5k3e2fx_set_fps(struct fps_cfg *fps) +{ + /* input is new fps in Q10 format */ + int32_t rc = 0; + enum msm_s_setting setting; + + s5k3e2fx_ctrl->fps_divider = fps->fps_div; + + if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) + setting = S_RES_PREVIEW; + else + setting = S_RES_CAPTURE; + + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + REG_FRAME_LENGTH_LINES_MSB, + (((s5k3e2fx_reg_pat[setting].size_h + + s5k3e2fx_reg_pat[setting].blk_l) * + s5k3e2fx_ctrl->fps_divider / 0x400) & 0xFF00) >> 8); + if (rc < 0) + goto set_fps_done; + + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + REG_FRAME_LENGTH_LINES_LSB, + (((s5k3e2fx_reg_pat[setting].size_h + + s5k3e2fx_reg_pat[setting].blk_l) * + s5k3e2fx_ctrl->fps_divider / 0x400) & 0x00FF)); + +set_fps_done: + return rc; +} + +static int32_t s5k3e2fx_write_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + + uint16_t max_legal_gain = 0x0200; + uint32_t ll_ratio; /* Q10 */ + uint32_t ll_pck, fl_lines; + uint16_t offset = 4; + uint32_t gain_msb, gain_lsb; + uint32_t intg_t_msb, intg_t_lsb; + uint32_t ll_pck_msb, ll_pck_lsb; + + struct s5k3e2fx_i2c_reg_conf tbl[2]; + + CDBG("Line:%d s5k3e2fx_write_exp_gain \n", __LINE__); + + if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + + s5k3e2fx_ctrl->my_reg_gain = gain; + s5k3e2fx_ctrl->my_reg_line_count = (uint16_t)line; + + fl_lines = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + + s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l; + + ll_pck = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w + + s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p; + + } else { + + fl_lines = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h + + s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l; + + ll_pck = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w + + s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p; + } + + if (gain > max_legal_gain) + gain = max_legal_gain; + + /* in Q10 */ + line = (line * s5k3e2fx_ctrl->fps_divider); + + if (fl_lines < (line / 0x400)) + ll_ratio = (line / (fl_lines - offset)); + else + ll_ratio = 0x400; + + /* update gain registers */ + gain_msb = (gain & 0xFF00) >> 8; + gain_lsb = gain & 0x00FF; + tbl[0].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB; + tbl[0].bdata = gain_msb; + tbl[1].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB; + tbl[1].bdata = gain_lsb; + rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl)); + if (rc < 0) + goto write_gain_done; + + ll_pck = ll_pck * ll_ratio; + ll_pck_msb = ((ll_pck / 0x400) & 0xFF00) >> 8; + ll_pck_lsb = (ll_pck / 0x400) & 0x00FF; + tbl[0].waddr = REG_LINE_LENGTH_PCK_MSB; + tbl[0].bdata = ll_pck_msb; + tbl[1].waddr = REG_LINE_LENGTH_PCK_LSB; + tbl[1].bdata = ll_pck_lsb; + rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl)); + if (rc < 0) + goto write_gain_done; + + line = line / ll_ratio; + intg_t_msb = (line & 0xFF00) >> 8; + intg_t_lsb = (line & 0x00FF); + tbl[0].waddr = REG_COARSE_INTEGRATION_TIME; + tbl[0].bdata = intg_t_msb; + tbl[1].waddr = REG_COARSE_INTEGRATION_TIME_LSB; + tbl[1].bdata = intg_t_lsb; + rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl)); + +write_gain_done: + return rc; +} + +static int32_t s5k3e2fx_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + + CDBG("Line:%d s5k3e2fx_set_pict_exp_gain \n", __LINE__); + + rc = + s5k3e2fx_write_exp_gain(gain, line); + + return rc; +} + +static int32_t s5k3e2fx_video_config(int mode, int res) +{ + int32_t rc; + + switch (res) { + case S_QTR_SIZE: + rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_PREVIEW); + if (rc < 0) + return rc; + + CDBG("s5k3e2fx sensor configuration done!\n"); + break; + + case S_FULL_SIZE: + rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); + if (rc < 0) + return rc; + + break; + + default: + return 0; + } /* switch */ + + s5k3e2fx_ctrl->prev_res = res; + s5k3e2fx_ctrl->curr_res = res; + s5k3e2fx_ctrl->sensormode = mode; + + rc = + s5k3e2fx_write_exp_gain(s5k3e2fx_ctrl->my_reg_gain, + s5k3e2fx_ctrl->my_reg_line_count); + + return rc; +} + +static int32_t s5k3e2fx_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); + if (rc < 0) + return rc; + + s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res; + s5k3e2fx_ctrl->sensormode = mode; + + return rc; +} + +static int32_t s5k3e2fx_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + + rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); + if (rc < 0) + return rc; + + s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res; + s5k3e2fx_ctrl->sensormode = mode; + + return rc; +} + +static int32_t s5k3e2fx_set_sensor_mode(int mode, int res) +{ + int32_t rc = 0; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = s5k3e2fx_video_config(mode, res); + break; + + case SENSOR_SNAPSHOT_MODE: + rc = s5k3e2fx_snapshot_config(mode); + break; + + case SENSOR_RAW_SNAPSHOT_MODE: + rc = s5k3e2fx_raw_snapshot_config(mode); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static int32_t s5k3e2fx_set_default_focus(void) +{ + int32_t rc = 0; + + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + 0x3131, 0); + if (rc < 0) + return rc; + + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + 0x3132, 0); + if (rc < 0) + return rc; + + s5k3e2fx_ctrl->curr_lens_pos = 0; + + return rc; +} + +static int32_t s5k3e2fx_move_focus(int direction, int32_t num_steps) +{ + int32_t rc = 0; + int32_t i; + int16_t step_direction; + int16_t actual_step; + int16_t next_pos, pos_offset; + int16_t init_code = 50; + uint8_t next_pos_msb, next_pos_lsb; + int16_t s_move[5]; + uint32_t gain; /* Q10 format */ + + if (direction == MOVE_NEAR) + step_direction = 20; + else if (direction == MOVE_FAR) + step_direction = -20; + else { + CDBG("s5k3e2fx_move_focus failed at line %d ...\n", __LINE__); + return -EINVAL; + } + + actual_step = step_direction * (int16_t)num_steps; + pos_offset = init_code + s5k3e2fx_ctrl->curr_lens_pos; + gain = actual_step * 0x400 / 5; + + for (i = 0; i <= 4; i++) { + if (actual_step >= 0) + s_move[i] = (((i+1)*gain+0x200)-(i*gain+0x200))/0x400; + else + s_move[i] = (((i+1)*gain-0x200)-(i*gain-0x200))/0x400; + } + + /* Ring Damping Code */ + for (i = 0; i <= 4; i++) { + next_pos = (int16_t)(pos_offset + s_move[i]); + + if (next_pos > (738 + init_code)) + next_pos = 738 + init_code; + else if (next_pos < 0) + next_pos = 0; + + CDBG("next_position in damping mode = %d\n", next_pos); + /* Writing the Values to the actuator */ + if (next_pos == init_code) + next_pos = 0x00; + + next_pos_msb = next_pos >> 8; + next_pos_lsb = next_pos & 0x00FF; + + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + 0x3131, next_pos_msb); + if (rc < 0) + break; + + rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, + 0x3132, next_pos_lsb); + if (rc < 0) + break; + + pos_offset = next_pos; + s5k3e2fx_ctrl->curr_lens_pos = pos_offset - init_code; + if (i < 4) + mdelay(3); + } + + return rc; +} + +static int s5k3e2fx_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + mutex_lock(&s5k3e2fx_mutex); + + CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + s5k3e2fx_get_pict_fps(cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = s5k3e2fx_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = s5k3e2fx_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = s5k3e2fx_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = s5k3e2fx_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + s5k3e2fx_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = s5k3e2fx_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = + s5k3e2fx_write_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__); + rc = + s5k3e2fx_set_pict_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = + s5k3e2fx_set_sensor_mode( + cdata.mode, cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = s5k3e2fx_power_down(); + break; + + case CFG_MOVE_FOCUS: + rc = + s5k3e2fx_move_focus( + cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = + s5k3e2fx_set_default_focus(); + break; + + case CFG_GET_AF_MAX_STEPS: + case CFG_SET_EFFECT: + case CFG_SET_LENS_SHADING: + default: + rc = -EINVAL; + break; + } + + mutex_unlock(&s5k3e2fx_mutex); + return rc; +} + +static int s5k3e2fx_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + + rc = i2c_add_driver(&s5k3e2fx_i2c_driver); + if (rc < 0 || s5k3e2fx_client == NULL) { + rc = -ENOTSUPP; + goto probe_fail; + } + + msm_camio_clk_rate_set(24000000); + mdelay(20); + + rc = s5k3e2fx_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + + s->s_init = s5k3e2fx_sensor_open_init; + s->s_release = s5k3e2fx_sensor_release; + s->s_config = s5k3e2fx_sensor_config; + s->s_mount_angle = 0; + s5k3e2fx_probe_init_done(info); + + return rc; + +probe_fail: + CDBG("SENSOR PROBE FAILS!\n"); + return rc; +} + +static int __s5k3e2fx_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, s5k3e2fx_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __s5k3e2fx_probe, + .driver = { + .name = "msm_camera_s5k3e2fx", + .owner = THIS_MODULE, + }, +}; + +static int __init s5k3e2fx_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(s5k3e2fx_init); diff --git a/drivers/media/video/msm_zsl/s5k3e2fx.h b/drivers/media/video/msm_zsl/s5k3e2fx.h new file mode 100644 index 00000000000..cf3f88140c4 --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k3e2fx.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef CAMSENSOR_S5K3E2FX +#define CAMSENSOR_S5K3E2FX + +#include +#endif /* CAMSENSOR_S5K3E2FX */ diff --git a/drivers/media/video/msm_zsl/s5k4e1.c b/drivers/media/video/msm_zsl/s5k4e1.c new file mode 100644 index 00000000000..30572d839d9 --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k4e1.c @@ -0,0 +1,1103 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "s5k4e1.h" + +/* 16bit address - 8 bit context register structure */ +#define Q8 0x00000100 +#define Q10 0x00000400 + +/* MCLK */ +#define S5K4E1_MASTER_CLK_RATE 24000000 + +/* AF Total steps parameters */ +#define S5K4E1_TOTAL_STEPS_NEAR_TO_FAR 32 + +#define S5K4E1_REG_PREV_FRAME_LEN_1 31 +#define S5K4E1_REG_PREV_FRAME_LEN_2 32 +#define S5K4E1_REG_PREV_LINE_LEN_1 33 +#define S5K4E1_REG_PREV_LINE_LEN_2 34 + +#define S5K4E1_REG_SNAP_FRAME_LEN_1 15 +#define S5K4E1_REG_SNAP_FRAME_LEN_2 16 +#define S5K4E1_REG_SNAP_LINE_LEN_1 17 +#define S5K4E1_REG_SNAP_LINE_LEN_2 18 +#define MSB 1 +#define LSB 0 + +struct s5k4e1_work_t { + struct work_struct work; +}; + +static struct s5k4e1_work_t *s5k4e1_sensorw; +static struct s5k4e1_work_t *s5k4e1_af_sensorw; +static struct i2c_client *s5k4e1_af_client; +static struct i2c_client *s5k4e1_client; + +struct s5k4e1_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + + uint32_t sensormode; + uint32_t fps_divider;/* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */ + uint16_t fps; + + uint16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + + enum s5k4e1_resolution_t prev_res; + enum s5k4e1_resolution_t pict_res; + enum s5k4e1_resolution_t curr_res; + enum s5k4e1_test_mode_t set_test; +}; + +static bool CSI_CONFIG; +static struct s5k4e1_ctrl_t *s5k4e1_ctrl; + +static DECLARE_WAIT_QUEUE_HEAD(s5k4e1_wait_queue); +static DECLARE_WAIT_QUEUE_HEAD(s5k4e1_af_wait_queue); +DEFINE_MUTEX(s5k4e1_mut); + +static uint16_t prev_line_length_pck; +static uint16_t prev_frame_length_lines; +static uint16_t snap_line_length_pck; +static uint16_t snap_frame_length_lines; + +static int s5k4e1_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 1, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 1, + .buf = rxdata, + }, + }; + if (i2c_transfer(s5k4e1_client->adapter, msgs, 2) < 0) { + CDBG("s5k4e1_i2c_rxdata faild 0x%x\n", saddr); + return -EIO; + } + return 0; +} + +static int32_t s5k4e1_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(s5k4e1_client->adapter, msg, 1) < 0) { + CDBG("s5k4e1_i2c_txdata faild 0x%x\n", saddr); + return -EIO; + } + + return 0; +} + +static int32_t s5k4e1_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + rc = s5k4e1_i2c_rxdata(s5k4e1_client->addr, buf, rlen); + if (rc < 0) { + CDBG("s5k4e1_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + CDBG("s5k4e1_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata); + + return rc; +} + +static int32_t s5k4e1_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[3]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata); + rc = s5k4e1_i2c_txdata(s5k4e1_client->addr, buf, 3); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + return rc; +} + +static int32_t s5k4e1_i2c_write_b_table(struct s5k4e1_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + + for (i = 0; i < num; i++) { + rc = s5k4e1_i2c_write_b_sensor(reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +static int32_t s5k4e1_af_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(s5k4e1_af_client->adapter, msg, 1) < 0) { + pr_err("s5k4e1_af_i2c_txdata faild 0x%x\n", saddr); + return -EIO; + } + + return 0; +} + +static int32_t s5k4e1_af_i2c_write_b_sensor(uint8_t waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[2]; + + memset(buf, 0, sizeof(buf)); + buf[0] = waddr; + buf[1] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata); + rc = s5k4e1_af_i2c_txdata(s5k4e1_af_client->addr << 1, buf, 2); + if (rc < 0) { + pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + return rc; +} + +static void s5k4e1_start_stream(void) +{ + s5k4e1_i2c_write_b_sensor(0x0100, 0x01);/* streaming on */ +} + +static void s5k4e1_stop_stream(void) +{ + s5k4e1_i2c_write_b_sensor(0x0100, 0x00);/* streaming off */ +} + +static void s5k4e1_group_hold_on(void) +{ + s5k4e1_i2c_write_b_sensor(0x0104, 0x01); +} + +static void s5k4e1_group_hold_off(void) +{ + s5k4e1_i2c_write_b_sensor(0x0104, 0x0); +} + +static void s5k4e1_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint32_t divider, d1, d2; + + d1 = (prev_frame_length_lines * 0x00000400) / snap_frame_length_lines; + d2 = (prev_line_length_pck * 0x00000400) / snap_line_length_pck; + divider = (d1 * d2) / 0x400; + + /*Verify PCLK settings and frame sizes.*/ + *pfps = (uint16_t) (fps * divider / 0x400); +} + +static uint16_t s5k4e1_get_prev_lines_pf(void) +{ + if (s5k4e1_ctrl->prev_res == QTR_SIZE) + return prev_frame_length_lines; + else + return snap_frame_length_lines; +} + +static uint16_t s5k4e1_get_prev_pixels_pl(void) +{ + if (s5k4e1_ctrl->prev_res == QTR_SIZE) + return prev_line_length_pck; + else + return snap_line_length_pck; +} + +static uint16_t s5k4e1_get_pict_lines_pf(void) +{ + if (s5k4e1_ctrl->pict_res == QTR_SIZE) + return prev_frame_length_lines; + else + return snap_frame_length_lines; +} + +static uint16_t s5k4e1_get_pict_pixels_pl(void) +{ + if (s5k4e1_ctrl->pict_res == QTR_SIZE) + return prev_line_length_pck; + else + return snap_line_length_pck; +} + +static uint32_t s5k4e1_get_pict_max_exp_lc(void) +{ + return snap_frame_length_lines * 24; +} + +static int32_t s5k4e1_set_fps(struct fps_cfg *fps) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + + s5k4e1_ctrl->fps_divider = fps->fps_div; + s5k4e1_ctrl->pict_fps_divider = fps->pict_fps_div; + + if (s5k4e1_ctrl->sensormode == SENSOR_PREVIEW_MODE) { + total_lines_per_frame = (uint16_t) + ((prev_frame_length_lines * s5k4e1_ctrl->fps_divider) / 0x400); + } else { + total_lines_per_frame = (uint16_t) + ((snap_frame_length_lines * s5k4e1_ctrl->fps_divider) / 0x400); + } + + s5k4e1_group_hold_on(); + rc = s5k4e1_i2c_write_b_sensor(0x0340, + ((total_lines_per_frame & 0xFF00) >> 8)); + rc = s5k4e1_i2c_write_b_sensor(0x0341, + (total_lines_per_frame & 0x00FF)); + s5k4e1_group_hold_off(); + + return rc; +} + +static inline uint8_t s5k4e1_byte(uint16_t word, uint8_t offset) +{ + return word >> (offset * BITS_PER_BYTE); +} + +static int32_t s5k4e1_write_exp_gain(uint16_t gain, uint32_t line) +{ + uint16_t max_legal_gain = 0x0200; + int32_t rc = 0; + static uint32_t fl_lines; + + if (gain > max_legal_gain) { + pr_debug("Max legal gain Line:%d\n", __LINE__); + gain = max_legal_gain; + } + /* Analogue Gain */ + s5k4e1_i2c_write_b_sensor(0x0204, s5k4e1_byte(gain, MSB)); + s5k4e1_i2c_write_b_sensor(0x0205, s5k4e1_byte(gain, LSB)); + + if (line > (prev_frame_length_lines - 4)) { + fl_lines = line+4; + s5k4e1_group_hold_on(); + s5k4e1_i2c_write_b_sensor(0x0340, s5k4e1_byte(fl_lines, MSB)); + s5k4e1_i2c_write_b_sensor(0x0341, s5k4e1_byte(fl_lines, LSB)); + /* Coarse Integration Time */ + s5k4e1_i2c_write_b_sensor(0x0202, s5k4e1_byte(line, MSB)); + s5k4e1_i2c_write_b_sensor(0x0203, s5k4e1_byte(line, LSB)); + s5k4e1_group_hold_off(); + } else if (line < (fl_lines - 4)) { + fl_lines = line+4; + if (fl_lines < prev_frame_length_lines) + fl_lines = prev_frame_length_lines; + + s5k4e1_group_hold_on(); + /* Coarse Integration Time */ + s5k4e1_i2c_write_b_sensor(0x0202, s5k4e1_byte(line, MSB)); + s5k4e1_i2c_write_b_sensor(0x0203, s5k4e1_byte(line, LSB)); + s5k4e1_i2c_write_b_sensor(0x0340, s5k4e1_byte(fl_lines, MSB)); + s5k4e1_i2c_write_b_sensor(0x0341, s5k4e1_byte(fl_lines, LSB)); + s5k4e1_group_hold_off(); + } else { + fl_lines = line+4; + s5k4e1_group_hold_on(); + /* Coarse Integration Time */ + s5k4e1_i2c_write_b_sensor(0x0202, s5k4e1_byte(line, MSB)); + s5k4e1_i2c_write_b_sensor(0x0203, s5k4e1_byte(line, LSB)); + s5k4e1_group_hold_off(); + } + return rc; +} + +static int32_t s5k4e1_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + uint16_t max_legal_gain = 0x0200; + uint16_t min_ll_pck = 0x0AB2; + uint32_t ll_pck, fl_lines; + uint32_t ll_ratio; + int32_t rc = 0; + uint8_t gain_msb, gain_lsb; + uint8_t intg_time_msb, intg_time_lsb; + uint8_t ll_pck_msb, ll_pck_lsb; + + if (gain > max_legal_gain) { + pr_debug("Max legal gain Line:%d\n", __LINE__); + gain = max_legal_gain; + } + + pr_debug("s5k4e1_write_exp_gain : gain = %d line = %d\n", gain, line); + line = (uint32_t) (line * s5k4e1_ctrl->pict_fps_divider); + fl_lines = snap_frame_length_lines; + ll_pck = snap_line_length_pck; + + if (fl_lines < (line / 0x400)) + ll_ratio = (line / (fl_lines - 4)); + else + ll_ratio = 0x400; + + ll_pck = ll_pck * ll_ratio / 0x400; + line = line / ll_ratio; + if (ll_pck < min_ll_pck) + ll_pck = min_ll_pck; + + gain_msb = (uint8_t) ((gain & 0xFF00) >> 8); + gain_lsb = (uint8_t) (gain & 0x00FF); + + intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8); + intg_time_lsb = (uint8_t) (line & 0x00FF); + + ll_pck_msb = (uint8_t) ((ll_pck & 0xFF00) >> 8); + ll_pck_lsb = (uint8_t) (ll_pck & 0x00FF); + + s5k4e1_group_hold_on(); + s5k4e1_i2c_write_b_sensor(0x0204, gain_msb); /* Analogue Gain */ + s5k4e1_i2c_write_b_sensor(0x0205, gain_lsb); + + s5k4e1_i2c_write_b_sensor(0x0342, ll_pck_msb); + s5k4e1_i2c_write_b_sensor(0x0343, ll_pck_lsb); + + /* Coarse Integration Time */ + s5k4e1_i2c_write_b_sensor(0x0202, intg_time_msb); + s5k4e1_i2c_write_b_sensor(0x0203, intg_time_lsb); + s5k4e1_group_hold_off(); + + return rc; +} + +static int32_t s5k4e1_move_focus(int direction, + int32_t num_steps) +{ + int16_t step_direction, actual_step, next_position; + uint8_t code_val_msb, code_val_lsb; + + if (direction == MOVE_NEAR) + step_direction = 16; + else + step_direction = -16; + + actual_step = (int16_t) (step_direction * num_steps); + next_position = (int16_t) (s5k4e1_ctrl->curr_lens_pos + actual_step); + + if (next_position > 1023) + next_position = 1023; + else if (next_position < 0) + next_position = 0; + + code_val_msb = next_position >> 4; + code_val_lsb = (next_position & 0x000F) << 4; + + if (s5k4e1_af_i2c_write_b_sensor(code_val_msb, code_val_lsb) < 0) { + pr_err("move_focus failed at line %d ...\n", __LINE__); + return -EBUSY; + } + + s5k4e1_ctrl->curr_lens_pos = next_position; + return 0; +} + +static int32_t s5k4e1_set_default_focus(uint8_t af_step) +{ + int32_t rc = 0; + + if (s5k4e1_ctrl->curr_step_pos != 0) { + rc = s5k4e1_move_focus(MOVE_FAR, + s5k4e1_ctrl->curr_step_pos); + } else { + s5k4e1_af_i2c_write_b_sensor(0x00, 0x00); + } + + s5k4e1_ctrl->curr_lens_pos = 0; + s5k4e1_ctrl->curr_step_pos = 0; + + return rc; +} + +static int32_t s5k4e1_test(enum s5k4e1_test_mode_t mo) +{ + int32_t rc = 0; + + if (mo != TEST_OFF) + rc = s5k4e1_i2c_write_b_sensor(0x0601, (uint8_t) mo); + + return rc; +} + +static void s5k4e1_reset_sensor(void) +{ + s5k4e1_i2c_write_b_sensor(0x103, 0x1); +} + +static int32_t s5k4e1_sensor_setting(int update_type, int rt) +{ + + int32_t rc = 0; + struct msm_camera_csi_params s5k4e1_csi_params; + + s5k4e1_stop_stream(); + msleep(30); + + if (update_type == REG_INIT) { + s5k4e1_reset_sensor(); + s5k4e1_i2c_write_b_table(s5k4e1_regs.reg_mipi, + s5k4e1_regs.reg_mipi_size); + s5k4e1_i2c_write_b_table(s5k4e1_regs.rec_settings, + s5k4e1_regs.rec_size); + s5k4e1_i2c_write_b_table(s5k4e1_regs.reg_pll_p, + s5k4e1_regs.reg_pll_p_size); + CSI_CONFIG = 0; + } else if (update_type == UPDATE_PERIODIC) { + if (rt == RES_PREVIEW) + s5k4e1_i2c_write_b_table(s5k4e1_regs.reg_prev, + s5k4e1_regs.reg_prev_size); + else + s5k4e1_i2c_write_b_table(s5k4e1_regs.reg_snap, + s5k4e1_regs.reg_snap_size); + msleep(20); + if (!CSI_CONFIG) { + msm_camio_vfe_clk_rate_set(192000000); + s5k4e1_csi_params.data_format = CSI_10BIT; + s5k4e1_csi_params.lane_cnt = 1; + s5k4e1_csi_params.lane_assign = 0xe4; + s5k4e1_csi_params.dpcm_scheme = 0; + s5k4e1_csi_params.settle_cnt = 24; + rc = msm_camio_csi_config(&s5k4e1_csi_params); + msleep(20); + CSI_CONFIG = 1; + } + s5k4e1_start_stream(); + msleep(30); + } + return rc; +} + +static int32_t s5k4e1_video_config(int mode) +{ + + int32_t rc = 0; + int rt; + CDBG("video config\n"); + /* change sensor resolution if needed */ + if (s5k4e1_ctrl->prev_res == QTR_SIZE) + rt = RES_PREVIEW; + else + rt = RES_CAPTURE; + if (s5k4e1_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + if (s5k4e1_ctrl->set_test) { + if (s5k4e1_test(s5k4e1_ctrl->set_test) < 0) + return rc; + } + + s5k4e1_ctrl->curr_res = s5k4e1_ctrl->prev_res; + s5k4e1_ctrl->sensormode = mode; + return rc; +} + +static int32_t s5k4e1_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt; + + /*change sensor resolution if needed */ + if (s5k4e1_ctrl->curr_res != s5k4e1_ctrl->pict_res) { + if (s5k4e1_ctrl->pict_res == QTR_SIZE) + rt = RES_PREVIEW; + else + rt = RES_CAPTURE; + if (s5k4e1_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + + s5k4e1_ctrl->curr_res = s5k4e1_ctrl->pict_res; + s5k4e1_ctrl->sensormode = mode; + return rc; +} + +static int32_t s5k4e1_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt; + + /* change sensor resolution if needed */ + if (s5k4e1_ctrl->curr_res != s5k4e1_ctrl->pict_res) { + if (s5k4e1_ctrl->pict_res == QTR_SIZE) + rt = RES_PREVIEW; + else + rt = RES_CAPTURE; + if (s5k4e1_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + + s5k4e1_ctrl->curr_res = s5k4e1_ctrl->pict_res; + s5k4e1_ctrl->sensormode = mode; + return rc; +} + +static int32_t s5k4e1_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = s5k4e1_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + rc = s5k4e1_snapshot_config(mode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + rc = s5k4e1_raw_snapshot_config(mode); + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +static int32_t s5k4e1_power_down(void) +{ + s5k4e1_stop_stream(); + return 0; +} + +static int s5k4e1_probe_init_done(const struct msm_camera_sensor_info *data) +{ + CDBG("probe done\n"); + gpio_free(data->sensor_reset); + return 0; +} + +static int s5k4e1_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + uint16_t regaddress1 = 0x0000; + uint16_t regaddress2 = 0x0001; + uint16_t chipid1 = 0; + uint16_t chipid2 = 0; + + CDBG("%s: %d\n", __func__, __LINE__); + CDBG(" s5k4e1_probe_init_sensor is called\n"); + + rc = gpio_request(data->sensor_reset, "s5k4e1"); + CDBG(" s5k4e1_probe_init_sensor\n"); + if (!rc) { + CDBG("sensor_reset = %d\n", rc); + gpio_direction_output(data->sensor_reset, 0); + msleep(50); + gpio_set_value_cansleep(data->sensor_reset, 1); + msleep(20); + } else + goto gpio_req_fail; + + msleep(20); + + s5k4e1_i2c_read(regaddress1, &chipid1, 1); + if (chipid1 != 0x4E) { + rc = -ENODEV; + CDBG("s5k4e1_probe_init_sensor fail chip id doesnot match\n"); + goto init_probe_fail; + } + + s5k4e1_i2c_read(regaddress2, &chipid2 , 1); + if (chipid2 != 0x10) { + rc = -ENODEV; + CDBG("s5k4e1_probe_init_sensor fail chip id doesnot match\n"); + goto init_probe_fail; + } + + CDBG("ID: %d\n", chipid1); + CDBG("ID: %d\n", chipid1); + + return rc; + +init_probe_fail: + CDBG(" s5k4e1_probe_init_sensor fails\n"); + gpio_set_value_cansleep(data->sensor_reset, 0); + s5k4e1_probe_init_done(data); + if (data->vcm_enable) { + int ret = gpio_request(data->vcm_pwd, "s5k4e1_af"); + if (!ret) { + gpio_direction_output(data->vcm_pwd, 0); + msleep(20); + gpio_free(data->vcm_pwd); + } + } +gpio_req_fail: + return rc; +} + +int s5k4e1_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + + CDBG("%s: %d\n", __func__, __LINE__); + CDBG("Calling s5k4e1_sensor_open_init\n"); + + s5k4e1_ctrl = kzalloc(sizeof(struct s5k4e1_ctrl_t), GFP_KERNEL); + if (!s5k4e1_ctrl) { + CDBG("s5k4e1_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + s5k4e1_ctrl->fps_divider = 1 * 0x00000400; + s5k4e1_ctrl->pict_fps_divider = 1 * 0x00000400; + s5k4e1_ctrl->set_test = TEST_OFF; + s5k4e1_ctrl->prev_res = QTR_SIZE; + s5k4e1_ctrl->pict_res = FULL_SIZE; + + if (data) + s5k4e1_ctrl->sensordata = data; + + prev_frame_length_lines = + ((s5k4e1_regs.reg_prev[S5K4E1_REG_PREV_FRAME_LEN_1].wdata << 8) | + s5k4e1_regs.reg_prev[S5K4E1_REG_PREV_FRAME_LEN_2].wdata); + + prev_line_length_pck = + (s5k4e1_regs.reg_prev[S5K4E1_REG_PREV_LINE_LEN_1].wdata << 8) | + s5k4e1_regs.reg_prev[S5K4E1_REG_PREV_LINE_LEN_2].wdata; + + snap_frame_length_lines = + (s5k4e1_regs.reg_snap[S5K4E1_REG_SNAP_FRAME_LEN_1].wdata << 8) | + s5k4e1_regs.reg_snap[S5K4E1_REG_SNAP_FRAME_LEN_2].wdata; + + snap_line_length_pck = + (s5k4e1_regs.reg_snap[S5K4E1_REG_SNAP_LINE_LEN_1].wdata << 8) | + s5k4e1_regs.reg_snap[S5K4E1_REG_SNAP_LINE_LEN_1].wdata; + + /* enable mclk first */ + msm_camio_clk_rate_set(S5K4E1_MASTER_CLK_RATE); + rc = s5k4e1_probe_init_sensor(data); + if (rc < 0) + goto init_fail; + + CDBG("init settings\n"); + if (s5k4e1_ctrl->prev_res == QTR_SIZE) + rc = s5k4e1_sensor_setting(REG_INIT, RES_PREVIEW); + else + rc = s5k4e1_sensor_setting(REG_INIT, RES_CAPTURE); + s5k4e1_ctrl->fps = 30 * Q8; + + /* enable AF actuator */ + if (s5k4e1_ctrl->sensordata->vcm_enable) { + CDBG("enable AF actuator, gpio = %d\n", + s5k4e1_ctrl->sensordata->vcm_pwd); + rc = gpio_request(s5k4e1_ctrl->sensordata->vcm_pwd, + "s5k4e1_af"); + if (!rc) + gpio_direction_output( + s5k4e1_ctrl->sensordata->vcm_pwd, + 1); + else { + pr_err("s5k4e1_ctrl gpio request failed!\n"); + goto init_fail; + } + msleep(20); + rc = s5k4e1_set_default_focus(0); + if (rc < 0) { + gpio_direction_output(s5k4e1_ctrl->sensordata->vcm_pwd, + 0); + gpio_free(s5k4e1_ctrl->sensordata->vcm_pwd); + } + } + if (rc < 0) + goto init_fail; + else + goto init_done; +init_fail: + CDBG("init_fail\n"); + s5k4e1_probe_init_done(data); +init_done: + CDBG("init_done\n"); + return rc; +} + +static int s5k4e1_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&s5k4e1_wait_queue); + return 0; +} + +static int s5k4e1_af_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&s5k4e1_af_wait_queue); + return 0; +} + +static const struct i2c_device_id s5k4e1_af_i2c_id[] = { + {"s5k4e1_af", 0}, + { } +}; + +static int s5k4e1_af_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("s5k4e1_af_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + s5k4e1_af_sensorw = kzalloc(sizeof(struct s5k4e1_work_t), GFP_KERNEL); + if (!s5k4e1_af_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, s5k4e1_af_sensorw); + s5k4e1_af_init_client(client); + s5k4e1_af_client = client; + + msleep(50); + + CDBG("s5k4e1_af_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("s5k4e1_af_probe failed! rc = %d\n", rc); + return rc; +} + +static const struct i2c_device_id s5k4e1_i2c_id[] = { + {"s5k4e1", 0}, + { } +}; + +static int s5k4e1_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("s5k4e1_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + s5k4e1_sensorw = kzalloc(sizeof(struct s5k4e1_work_t), GFP_KERNEL); + if (!s5k4e1_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, s5k4e1_sensorw); + s5k4e1_init_client(client); + s5k4e1_client = client; + + msleep(50); + + CDBG("s5k4e1_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("s5k4e1_probe failed! rc = %d\n", rc); + return rc; +} + +static int __devexit s5k4e1_remove(struct i2c_client *client) +{ + struct s5k4e1_work_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + s5k4e1_client = NULL; + kfree(sensorw); + return 0; +} + +static int __devexit s5k4e1_af_remove(struct i2c_client *client) +{ + struct s5k4e1_work_t *s5k4e1_af = i2c_get_clientdata(client); + free_irq(client->irq, s5k4e1_af); + s5k4e1_af_client = NULL; + kfree(s5k4e1_af); + return 0; +} + +static struct i2c_driver s5k4e1_i2c_driver = { + .id_table = s5k4e1_i2c_id, + .probe = s5k4e1_i2c_probe, + .remove = __exit_p(s5k4e1_i2c_remove), + .driver = { + .name = "s5k4e1", + }, +}; + +static struct i2c_driver s5k4e1_af_i2c_driver = { + .id_table = s5k4e1_af_i2c_id, + .probe = s5k4e1_af_i2c_probe, + .remove = __exit_p(s5k4e1_af_i2c_remove), + .driver = { + .name = "s5k4e1_af", + }, +}; + +int s5k4e1_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&s5k4e1_mut); + CDBG("s5k4e1_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + s5k4e1_get_pict_fps( + cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = + s5k4e1_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = + s5k4e1_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = + s5k4e1_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + s5k4e1_get_pict_pixels_pl(); + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + s5k4e1_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = s5k4e1_set_fps(&(cdata.cfg.fps)); + break; + case CFG_SET_EXP_GAIN: + rc = s5k4e1_write_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + case CFG_SET_PICT_EXP_GAIN: + rc = s5k4e1_set_pict_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + case CFG_SET_MODE: + rc = s5k4e1_set_sensor_mode(cdata.mode, cdata.rs); + break; + case CFG_PWR_DOWN: + rc = s5k4e1_power_down(); + break; + case CFG_MOVE_FOCUS: + rc = s5k4e1_move_focus(cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + case CFG_SET_DEFAULT_FOCUS: + rc = s5k4e1_set_default_focus(cdata.cfg.focus.steps); + break; + case CFG_GET_AF_MAX_STEPS: + cdata.max_steps = S5K4E1_TOTAL_STEPS_NEAR_TO_FAR; + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + case CFG_SET_EFFECT: + rc = s5k4e1_set_default_focus(cdata.cfg.effect); + break; + default: + rc = -EFAULT; + break; + } + mutex_unlock(&s5k4e1_mut); + + return rc; +} + +static int s5k4e1_sensor_release(void) +{ + int rc = -EBADF; + + mutex_lock(&s5k4e1_mut); + s5k4e1_power_down(); + msleep(20); + gpio_set_value_cansleep(s5k4e1_ctrl->sensordata->sensor_reset, 0); + usleep_range(5000, 5100); + gpio_free(s5k4e1_ctrl->sensordata->sensor_reset); + if (s5k4e1_ctrl->sensordata->vcm_enable) { + gpio_set_value_cansleep(s5k4e1_ctrl->sensordata->vcm_pwd, 0); + gpio_free(s5k4e1_ctrl->sensordata->vcm_pwd); + } + kfree(s5k4e1_ctrl); + s5k4e1_ctrl = NULL; + CDBG("s5k4e1_release completed\n"); + mutex_unlock(&s5k4e1_mut); + + return rc; +} + +static int s5k4e1_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + + rc = i2c_add_driver(&s5k4e1_i2c_driver); + if (rc < 0 || s5k4e1_client == NULL) { + rc = -ENOTSUPP; + CDBG("I2C add driver failed"); + goto probe_fail_1; + } + + rc = i2c_add_driver(&s5k4e1_af_i2c_driver); + if (rc < 0 || s5k4e1_af_client == NULL) { + rc = -ENOTSUPP; + CDBG("I2C add driver failed"); + goto probe_fail_2; + } + + msm_camio_clk_rate_set(S5K4E1_MASTER_CLK_RATE); + + rc = s5k4e1_probe_init_sensor(info); + if (rc < 0) + goto probe_fail_3; + + s->s_init = s5k4e1_sensor_open_init; + s->s_release = s5k4e1_sensor_release; + s->s_config = s5k4e1_sensor_config; + s->s_mount_angle = info->sensor_platform_info->mount_angle; + gpio_set_value_cansleep(info->sensor_reset, 0); + s5k4e1_probe_init_done(info); + /* Keep vcm_pwd to OUT Low */ + if (info->vcm_enable) { + rc = gpio_request(info->vcm_pwd, "s5k4e1_af"); + if (!rc) { + gpio_direction_output(info->vcm_pwd, 0); + msleep(20); + gpio_free(info->vcm_pwd); + } else + return rc; + } + return rc; + +probe_fail_3: + i2c_del_driver(&s5k4e1_af_i2c_driver); +probe_fail_2: + i2c_del_driver(&s5k4e1_i2c_driver); +probe_fail_1: + CDBG("s5k4e1_sensor_probe: SENSOR PROBE FAILS!\n"); + return rc; +} + +static int __devinit s5k4e1_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, s5k4e1_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = s5k4e1_probe, + .driver = { + .name = "msm_camera_s5k4e1", + .owner = THIS_MODULE, + }, +}; + +static int __init s5k4e1_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(s5k4e1_init); +MODULE_DESCRIPTION("Samsung 5 MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/s5k4e1.h b/drivers/media/video/msm_zsl/s5k4e1.h new file mode 100644 index 00000000000..7f603322a3c --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k4e1.h @@ -0,0 +1,94 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef S5K4E1_H +#define S5K4E1_H +#include +#include +extern struct s5k4e1_reg s5k4e1_regs; + +struct s5k4e1_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum s5k4e1_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum s5k4e1_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +enum s5k4e1_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum s5k4e1_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum s5k4e1_reg_pll { + E013_VT_PIX_CLK_DIV, + E013_VT_SYS_CLK_DIV, + E013_PRE_PLL_CLK_DIV, + E013_PLL_MULTIPLIER, + E013_OP_PIX_CLK_DIV, + E013_OP_SYS_CLK_DIV +}; + +enum s5k4e1_reg_mode { + E013_X_ADDR_START, + E013_X_ADDR_END, + E013_Y_ADDR_START, + E013_Y_ADDR_END, + E013_X_OUTPUT_SIZE, + E013_Y_OUTPUT_SIZE, + E013_DATAPATH_SELECT, + E013_READ_MODE, + E013_ANALOG_CONTROL5, + E013_DAC_LD_4_5, + E013_SCALING_MODE, + E013_SCALE_M, + E013_LINE_LENGTH_PCK, + E013_FRAME_LENGTH_LINES, + E013_COARSE_INTEGRATION_TIME, + E013_FINE_INTEGRATION_TIME, + E013_FINE_CORRECTION +}; + +struct s5k4e1_reg { + const struct s5k4e1_i2c_reg_conf *reg_mipi; + const unsigned short reg_mipi_size; + const struct s5k4e1_i2c_reg_conf *rec_settings; + const unsigned short rec_size; + const struct s5k4e1_i2c_reg_conf *reg_pll_p; + const unsigned short reg_pll_p_size; + const struct s5k4e1_i2c_reg_conf *reg_pll_s; + const unsigned short reg_pll_s_size; + const struct s5k4e1_i2c_reg_conf *reg_prev; + const unsigned short reg_prev_size; + const struct s5k4e1_i2c_reg_conf *reg_snap; + const unsigned short reg_snap_size; +}; +#endif /* S5K4E1_H */ diff --git a/drivers/media/video/msm_zsl/s5k4e1_reg.c b/drivers/media/video/msm_zsl/s5k4e1_reg.c new file mode 100644 index 00000000000..59bb1c85295 --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k4e1_reg.c @@ -0,0 +1,169 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + + +#include "s5k4e1.h" + +struct s5k4e1_i2c_reg_conf s5k4e1_mipi_settings[] = { + {0x30BD, 0x00},/* SEL_CCP[0] */ + {0x3084, 0x15},/* SYNC Mode */ + {0x30BE, 0x1A},/* M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0] */ + {0x30C1, 0x01},/* pack video enable [0] */ + {0x30EE, 0x02},/* DPHY enable [ 1] */ + {0x3111, 0x86},/* Embedded data off [5] */ +}; + +/* PLL Configuration */ +struct s5k4e1_i2c_reg_conf s5k4e1_pll_preview_settings[] = { + {0x0305, 0x04}, + {0x0306, 0x00}, + {0x0307, 0x44}, + {0x30B5, 0x00}, + {0x30E2, 0x01},/* num lanes[1:0] = 2 */ + {0x30F1, 0xB0}, +}; + +struct s5k4e1_i2c_reg_conf s5k4e1_pll_snap_settings[] = { + {0x0305, 0x04}, + {0x0306, 0x00}, + {0x0307, 0x44}, + {0x30B5, 0x00}, + {0x30E2, 0x01},/* num lanes[1:0] = 2 */ + {0x30F1, 0xB0}, +}; + +struct s5k4e1_i2c_reg_conf s5k4e1_prev_settings[] = { + /* output size (1304 x 980) */ + {0x30A9, 0x02},/* Horizontal Binning On */ + {0x300E, 0xEB},/* Vertical Binning On */ + {0x0387, 0x03},/* y_odd_inc 03(10b AVG) */ + {0x0344, 0x00},/* x_addr_start 0 */ + {0x0345, 0x00}, + {0x0348, 0x0A},/* x_addr_end 2607 */ + {0x0349, 0x2F}, + {0x0346, 0x00},/* y_addr_start 0 */ + {0x0347, 0x00}, + {0x034A, 0x07},/* y_addr_end 1959 */ + {0x034B, 0xA7}, + {0x0380, 0x00},/* x_even_inc 1 */ + {0x0381, 0x01}, + {0x0382, 0x00},/* x_odd_inc 1 */ + {0x0383, 0x01}, + {0x0384, 0x00},/* y_even_inc 1 */ + {0x0385, 0x01}, + {0x0386, 0x00},/* y_odd_inc 3 */ + {0x0387, 0x03}, + {0x034C, 0x05},/* x_output_size 1304 */ + {0x034D, 0x18}, + {0x034E, 0x03},/* y_output_size 980 */ + {0x034F, 0xd4}, + {0x30BF, 0xAB},/* outif_enable[7], data_type[5:0](2Bh = bayer 10bit} */ + {0x30C0, 0xA0},/* video_offset[7:4] 3260%12 */ + {0x30C8, 0x06},/* video_data_length 1600 = 1304 * 1.25 */ + {0x30C9, 0x5E}, + /* Timing Configuration */ + {0x0202, 0x03}, + {0x0203, 0x14}, + {0x0204, 0x00}, + {0x0205, 0x80}, + {0x0340, 0x03},/* Frame Length */ + {0x0341, 0xE0}, + {0x0342, 0x0A},/* 2738 Line Length */ + {0x0343, 0xB2}, +}; + +struct s5k4e1_i2c_reg_conf s5k4e1_snap_settings[] = { + /*Output Size (2608x1960)*/ + {0x30A9, 0x03},/* Horizontal Binning Off */ + {0x300E, 0xE8},/* Vertical Binning Off */ + {0x0387, 0x01},/* y_odd_inc */ + {0x034C, 0x0A},/* x_output size */ + {0x034D, 0x30}, + {0x034E, 0x07},/* y_output size */ + {0x034F, 0xA8}, + {0x30BF, 0xAB},/* outif_enable[7], data_type[5:0](2Bh = bayer 10bit} */ + {0x30C0, 0x80},/* video_offset[7:4] 3260%12 */ + {0x30C8, 0x0C},/* video_data_length 3260 = 2608 * 1.25 */ + {0x30C9, 0xBC}, + /*Timing configuration*/ + {0x0202, 0x06}, + {0x0203, 0x28}, + {0x0204, 0x00}, + {0x0205, 0x80}, + {0x0340, 0x07},/* Frame Length */ + {0x0341, 0xB4}, + {0x0342, 0x0A},/* 2738 Line Length */ + {0x0343, 0xB2}, +}; + +struct s5k4e1_i2c_reg_conf s5k4e1_recommend_settings[] = { + /*CDS timing setting ... */ + {0x3000, 0x05}, + {0x3001, 0x03}, + {0x3002, 0x08}, + {0x3003, 0x0A}, + {0x3004, 0x50}, + {0x3005, 0x0E}, + {0x3006, 0x5E}, + {0x3007, 0x00}, + {0x3008, 0x78}, + {0x3009, 0x78}, + {0x300A, 0x50}, + {0x300B, 0x08}, + {0x300C, 0x14}, + {0x300D, 0x00}, + {0x300E, 0xE8}, + {0x300F, 0x82}, + {0x301B, 0x77}, + + /* CDS option setting ... */ + {0x3010, 0x00}, + {0x3011, 0x3A}, + {0x3029, 0x04}, + {0x3012, 0x30}, + {0x3013, 0xA0}, + {0x3014, 0x00}, + {0x3015, 0x00}, + {0x3016, 0x30}, + {0x3017, 0x94}, + {0x3018, 0x70}, + {0x301D, 0xD4}, + {0x3021, 0x02}, + {0x3022, 0x24}, + {0x3024, 0x40}, + {0x3027, 0x08}, + + /* Pixel option setting ... */ + {0x301C, 0x04}, + {0x30D8, 0x3F}, + {0x302B, 0x01}, + + {0x3070, 0x5F}, + {0x3071, 0x00}, + {0x3080, 0x04}, + {0x3081, 0x38}, +}; + +struct s5k4e1_reg s5k4e1_regs = { + .reg_mipi = &s5k4e1_mipi_settings[0], + .reg_mipi_size = ARRAY_SIZE(s5k4e1_mipi_settings), + .rec_settings = &s5k4e1_recommend_settings[0], + .rec_size = ARRAY_SIZE(s5k4e1_recommend_settings), + .reg_pll_p = &s5k4e1_pll_preview_settings[0], + .reg_pll_p_size = ARRAY_SIZE(s5k4e1_pll_preview_settings), + .reg_pll_s = &s5k4e1_pll_snap_settings[0], + .reg_pll_s_size = ARRAY_SIZE(s5k4e1_pll_snap_settings), + .reg_prev = &s5k4e1_prev_settings[0], + .reg_prev_size = ARRAY_SIZE(s5k4e1_prev_settings), + .reg_snap = &s5k4e1_snap_settings[0], + .reg_snap_size = ARRAY_SIZE(s5k4e1_snap_settings), +}; diff --git a/drivers/media/video/msm_zsl/s5k6aa.h b/drivers/media/video/msm_zsl/s5k6aa.h new file mode 100644 index 00000000000..7cc45ec38f7 --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k6aa.h @@ -0,0 +1,196 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __S5K6AA_H__ +#define __S5K6AA_H__ + +#include +#include + +#define S5K6AA_DEBUG +#ifdef S5K6AA_DEBUG +#define CAM_DEBUG(fmt, arg...) \ + do {\ + printk("\033[[S5K6AA] %s:%d: " fmt "\033[0m\n", __FUNCTION__, __LINE__, ##arg);}\ + while(0) + +#define cam_info(fmt, arg...) \ + do {\ + printk(KERN_INFO "[S5K6AA]" fmt "\n",##arg);}\ + while(0) + +#define cam_err(fmt, arg...) \ + do {\ + printk(KERN_ERR "[S5K6AA] %s:%d:" fmt "\n",__FUNCTION__, __LINE__, ##arg);}\ + while(0) + +#else +#define CAM_DEBUG(fmt, arg...) +#define cam_info(fmt, arg...) +#define cam_err(fmt, arg...) +#endif + + +#define CAPTURE_FLASH 1 +#define MOVIE_FLASH 0 + +/* level at or below which we need to enable flash when in auto mode */ +#define LOW_LIGHT_LEVEL 0x20 + + +/* DTP */ +#define DTP_OFF 0 +#define DTP_ON 1 +#define DTP_OFF_ACK 2 +#define DTP_ON_ACK 3 + +struct s5k6aa_userset { + unsigned int focus_mode; + unsigned int focus_status; + unsigned int continuous_af; + + unsigned int metering; + unsigned int exposure; + unsigned int wb; + unsigned int iso; + int contrast; + int saturation; + int sharpness; + int brightness; + int scene; + unsigned int zoom; + unsigned int effect; /* Color FX (AKA Color tone) */ + unsigned int scenemode; + unsigned int detectmode; + unsigned int antishake; + unsigned int fps; + unsigned int flash_mode; + unsigned int flash_state; + + unsigned int stabilize; /* IS */ + + unsigned int strobe; + unsigned int jpeg_quality; + //unsigned int preview_size; +// struct m5mo_preview_size preview_size; + unsigned int preview_size_idx; + unsigned int capture_size; + unsigned int thumbnail_size; + + +}; + + +//extern struct s5k6aa_reg s5k6aa_regs; +struct reg_struct_init { + /* PLL setting */ + uint8_t pre_pll_clk_div; /* 0x0305 */ + uint8_t plstatim; /* 0x302b */ + uint8_t reg_3024; /*ox3024*/ + uint8_t image_orientation; /* 0x0101*/ + uint8_t vndmy_ablmgshlmt; /*0x300a*/ + uint8_t y_opbaddr_start_di; /*0x3014*/ + uint8_t reg_0x3015; /*0x3015*/ + uint8_t reg_0x301c; /*0x301c*/ + uint8_t reg_0x302c; /*0x302c*/ + uint8_t reg_0x3031; /*0x3031*/ + uint8_t reg_0x3041; /* 0x3041 */ + uint8_t reg_0x3051; /* 0x3051 */ + uint8_t reg_0x3053; /* 0x3053 */ + uint8_t reg_0x3057; /* 0x3057 */ + uint8_t reg_0x305c; /* 0x305c */ + uint8_t reg_0x305d; /* 0x305d */ + uint8_t reg_0x3060; /* 0x3060 */ + uint8_t reg_0x3065; /* 0x3065 */ + uint8_t reg_0x30aa; /* 0x30aa */ + uint8_t reg_0x30ab; + uint8_t reg_0x30b0; + uint8_t reg_0x30b2; + uint8_t reg_0x30d3; + uint8_t reg_0x3106; + uint8_t reg_0x310c; + uint8_t reg_0x3304; + uint8_t reg_0x3305; + uint8_t reg_0x3306; + uint8_t reg_0x3307; + uint8_t reg_0x3308; + uint8_t reg_0x3309; + uint8_t reg_0x330a; + uint8_t reg_0x330b; + uint8_t reg_0x330c; + uint8_t reg_0x330d; + uint8_t reg_0x330f; + uint8_t reg_0x3381; +}; + +struct reg_struct { + uint8_t pll_multiplier; /* 0x0307 */ + uint8_t frame_length_lines_hi; /* 0x0340*/ + uint8_t frame_length_lines_lo; /* 0x0341*/ + uint8_t y_addr_start; /* 0x347 */ + uint8_t y_add_end; /* 0x034b */ + uint8_t x_output_size_msb; /* 0x034c */ + uint8_t x_output_size_lsb; /* 0x034d */ + uint8_t y_output_size_msb; /* 0x034e */ + uint8_t y_output_size_lsb; /* 0x034f */ + uint8_t x_even_inc; /* 0x0381 */ + uint8_t x_odd_inc; /* 0x0383 */ + uint8_t y_even_inc; /* 0x0385 */ + uint8_t y_odd_inc; /* 0x0387 */ + uint8_t hmodeadd; /* 0x3001 */ + uint8_t vmodeadd; /* 0x3016 */ + uint8_t vapplinepos_start;/*ox3069*/ + uint8_t vapplinepos_end;/*306b*/ + uint8_t shutter; /* 0x3086 */ + uint8_t haddave; /* 0x30e8 */ + uint8_t lanesel; /* 0x3301 */ +}; + +struct s5k6aa_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum s5k6aa_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum s5k6aa_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +enum s5k6aa_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; +/* +struct s5k6aa_reg { + const struct reg_struct_init *reg_pat_init; + const struct reg_struct *reg_pat; +}; + */ +#endif /* __S5K6AA_H__ */ diff --git a/drivers/media/video/msm_zsl/s5k6aa_regs.h b/drivers/media/video/msm_zsl/s5k6aa_regs.h new file mode 100644 index 00000000000..f2cb06752aa --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k6aa_regs.h @@ -0,0 +1,2840 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifdef __S5K6AA_H__ +#define __S5K6AA_H__ + + +typedef struct s5k6aa_reg { + unsigned short subaddr; + unsigned int value; +}s5k6aa_short_t; + +s5k6aa_short_t s5k6aa_init_reg[] = +{ +//================================================================ +// Device : S5K6AAFX +// MIPI Interface for Noncontious Clock +//================================================================ + +//================================================================ +// History +// 20101214 Hyungseok.Yoon T&P Update from SIRC(ISP06AA00C00000.ASIC.TNP) +//================================================================ + +//================================================================ +// ARM GO and Delay +//================================================================ +{0xFCFC, 0xD000}, +{0x0010, 0x0001}, // Reset +{0x0004, 0x0000}, // Disable Auto Address Increment : 0 Chunghwan Park +{0x1030, 0x0000}, // Clear host interrupt so main will wait +{0x0014, 0x0001}, // ARM Go +{0xFFFE, 0x0064}, // Wait100ms + +//================================================================ +// Trap and Patch +//================================================================ +// svn://transrdsrv/svn/svnroot/System/Software/tcevb/SDK+FW/ISP_Oscar/Firmware +// Rev: 33110-33110 +// Signature: +// md5 f0ba942df15b96de5c09e6cf13fed9c9 .btp +// md5 8bc59f72129cb36e6f6db4be5ddca1f6 .htp +// md5 954ec97efcabad291d89f63e29f32490 .RegsMap.h +// md5 5c29fe50b51e7e860313f5b3b6452bfd .RegsMap.bin +// md5 6211407baaa234b753431cde4ba32402 .base.RegsMap.h +// md5 90cc21d42cc5f02eb80b2586e5c46d9b .base.RegsMap.bin +{0xFCFC, 0xD000}, +{0x0004, 0x0001}, // ensable Auto Address Increment : 1 +{0x0028, 0x7000}, +{0x002A, 0x1D60}, +{0x0F12, 0xB570}, +{0x0F12, 0x4936}, +{0x0F12, 0x4836}, +{0x0F12, 0x2205}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA4E}, +{0x0F12, 0x4935}, +{0x0F12, 0x2002}, +{0x0F12, 0x83C8}, +{0x0F12, 0x2001}, +{0x0F12, 0x3120}, +{0x0F12, 0x8088}, +{0x0F12, 0x4933}, +{0x0F12, 0x0200}, +{0x0F12, 0x8008}, +{0x0F12, 0x4933}, +{0x0F12, 0x8048}, +{0x0F12, 0x4933}, +{0x0F12, 0x4833}, +{0x0F12, 0x2204}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA3E}, +{0x0F12, 0x4932}, +{0x0F12, 0x4833}, +{0x0F12, 0x2206}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA39}, +{0x0F12, 0x4932}, +{0x0F12, 0x4832}, +{0x0F12, 0x2207}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA34}, +{0x0F12, 0x4931}, +{0x0F12, 0x4832}, +{0x0F12, 0x2208}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA2F}, +{0x0F12, 0x4931}, +{0x0F12, 0x4831}, +{0x0F12, 0x2209}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA2A}, +{0x0F12, 0x4930}, +{0x0F12, 0x4831}, +{0x0F12, 0x220A}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA25}, +{0x0F12, 0x4930}, +{0x0F12, 0x4830}, +{0x0F12, 0x220B}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA20}, +{0x0F12, 0x482F}, +{0x0F12, 0x4930}, +{0x0F12, 0x6108}, +{0x0F12, 0x4830}, +{0x0F12, 0x39FF}, +{0x0F12, 0x3901}, +{0x0F12, 0x6748}, +{0x0F12, 0x482F}, +{0x0F12, 0x1C0A}, +{0x0F12, 0x32C0}, +{0x0F12, 0x6390}, +{0x0F12, 0x482E}, +{0x0F12, 0x6708}, +{0x0F12, 0x491A}, +{0x0F12, 0x482D}, +{0x0F12, 0x3108}, +{0x0F12, 0x60C1}, +{0x0F12, 0x6882}, +{0x0F12, 0x1A51}, +{0x0F12, 0x8201}, +{0x0F12, 0x4C2B}, +{0x0F12, 0x2607}, +{0x0F12, 0x6821}, +{0x0F12, 0x0736}, +{0x0F12, 0x42B1}, +{0x0F12, 0xDA05}, +{0x0F12, 0x4829}, +{0x0F12, 0x22D8}, +{0x0F12, 0x1C05}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA09}, +{0x0F12, 0x6025}, +{0x0F12, 0x68A1}, +{0x0F12, 0x42B1}, +{0x0F12, 0xDA07}, +{0x0F12, 0x4825}, +{0x0F12, 0x2224}, +{0x0F12, 0x3824}, +{0x0F12, 0xF000}, +{0x0F12, 0xFA00}, +{0x0F12, 0x4822}, +{0x0F12, 0x3824}, +{0x0F12, 0x60A0}, +{0x0F12, 0x4D22}, +{0x0F12, 0x6D29}, +{0x0F12, 0x42B1}, +{0x0F12, 0xDA07}, +{0x0F12, 0x481F}, +{0x0F12, 0x228F}, +{0x0F12, 0x00D2}, +{0x0F12, 0x30D8}, +{0x0F12, 0x1C04}, +{0x0F12, 0xF000}, +{0x0F12, 0xF9F2}, +{0x0F12, 0x652C}, +{0x0F12, 0xBC70}, +{0x0F12, 0xBC08}, +{0x0F12, 0x4718}, +{0x0F12, 0x218B}, +{0x0F12, 0x7000}, +{0x0F12, 0x127B}, +{0x0F12, 0x0000}, +{0x0F12, 0x0398}, +{0x0F12, 0x7000}, +{0x0F12, 0x1376}, +{0x0F12, 0x7000}, +{0x0F12, 0x2370}, +{0x0F12, 0x7000}, +{0x0F12, 0x1F0D}, +{0x0F12, 0x7000}, +{0x0F12, 0x890D}, +{0x0F12, 0x0000}, +{0x0F12, 0x1F2F}, +{0x0F12, 0x7000}, +{0x0F12, 0x27A9}, +{0x0F12, 0x0000}, +{0x0F12, 0x1FE1}, +{0x0F12, 0x7000}, +{0x0F12, 0x27C5}, +{0x0F12, 0x0000}, +{0x0F12, 0x2043}, +{0x0F12, 0x7000}, +{0x0F12, 0x285F}, +{0x0F12, 0x0000}, +{0x0F12, 0x2003}, +{0x0F12, 0x7000}, +{0x0F12, 0x28FF}, +{0x0F12, 0x0000}, +{0x0F12, 0x20CD}, +{0x0F12, 0x7000}, +{0x0F12, 0x6181}, +{0x0F12, 0x0000}, +{0x0F12, 0x20EF}, +{0x0F12, 0x7000}, +{0x0F12, 0x6663}, +{0x0F12, 0x0000}, +{0x0F12, 0x2123}, +{0x0F12, 0x7000}, +{0x0F12, 0x0100}, +{0x0F12, 0x7000}, +{0x0F12, 0x1EC1}, +{0x0F12, 0x7000}, +{0x0F12, 0x1EAD}, +{0x0F12, 0x7000}, +{0x0F12, 0x1F79}, +{0x0F12, 0x7000}, +{0x0F12, 0x04AC}, +{0x0F12, 0x7000}, +{0x0F12, 0x06CC}, +{0x0F12, 0x7000}, +{0x0F12, 0x23A4}, +{0x0F12, 0x7000}, +{0x0F12, 0x0704}, +{0x0F12, 0x7000}, +{0x0F12, 0xB510}, +{0x0F12, 0xF000}, +{0x0F12, 0xF9B9}, +{0x0F12, 0x48C3}, +{0x0F12, 0x49C3}, +{0x0F12, 0x8800}, +{0x0F12, 0x8048}, +{0x0F12, 0xBC10}, +{0x0F12, 0xBC08}, +{0x0F12, 0x4718}, +{0x0F12, 0xB5F8}, +{0x0F12, 0x1C06}, +{0x0F12, 0x4DC0}, +{0x0F12, 0x68AC}, +{0x0F12, 0x1C30}, +{0x0F12, 0xF000}, +{0x0F12, 0xF9B3}, +{0x0F12, 0x68A9}, +{0x0F12, 0x4ABC}, +{0x0F12, 0x42A1}, +{0x0F12, 0xD003}, +{0x0F12, 0x4BBD}, +{0x0F12, 0x8A1B}, +{0x0F12, 0x3301}, +{0x0F12, 0x8013}, +{0x0F12, 0x8813}, +{0x0F12, 0x1C14}, +{0x0F12, 0x2B00}, +{0x0F12, 0xD00F}, +{0x0F12, 0x2201}, +{0x0F12, 0x4281}, +{0x0F12, 0xD003}, +{0x0F12, 0x8C2F}, +{0x0F12, 0x42B9}, +{0x0F12, 0xD300}, +{0x0F12, 0x2200}, +{0x0F12, 0x60AE}, +{0x0F12, 0x2A00}, +{0x0F12, 0xD003}, +{0x0F12, 0x8C28}, +{0x0F12, 0x42B0}, +{0x0F12, 0xD800}, +{0x0F12, 0x1C30}, +{0x0F12, 0x1E59}, +{0x0F12, 0x8021}, +{0x0F12, 0xBCF8}, +{0x0F12, 0xBC08}, +{0x0F12, 0x4718}, +{0x0F12, 0xB510}, +{0x0F12, 0x1C04}, +{0x0F12, 0x48AF}, +{0x0F12, 0xF000}, +{0x0F12, 0xF997}, +{0x0F12, 0x4AAD}, +{0x0F12, 0x4BAE}, +{0x0F12, 0x8811}, +{0x0F12, 0x885B}, +{0x0F12, 0x8852}, +{0x0F12, 0x4359}, +{0x0F12, 0x1889}, +{0x0F12, 0x4288}, +{0x0F12, 0xD800}, +{0x0F12, 0x1C08}, +{0x0F12, 0x6020}, +{0x0F12, 0xE7C5}, +{0x0F12, 0xB570}, +{0x0F12, 0x1C05}, +{0x0F12, 0xF000}, +{0x0F12, 0xF98F}, +{0x0F12, 0x49A5}, +{0x0F12, 0x8989}, +{0x0F12, 0x4348}, +{0x0F12, 0x0200}, +{0x0F12, 0x0C00}, +{0x0F12, 0x2101}, +{0x0F12, 0x0349}, +{0x0F12, 0xF000}, +{0x0F12, 0xF98E}, +{0x0F12, 0x1C04}, +{0x0F12, 0x489F}, +{0x0F12, 0x8F80}, +{0x0F12, 0xF000}, +{0x0F12, 0xF991}, +{0x0F12, 0x1C01}, +{0x0F12, 0x20FF}, +{0x0F12, 0x43C0}, +{0x0F12, 0xF000}, +{0x0F12, 0xF994}, +{0x0F12, 0xF000}, +{0x0F12, 0xF998}, +{0x0F12, 0x1C01}, +{0x0F12, 0x4898}, +{0x0F12, 0x8840}, +{0x0F12, 0x4360}, +{0x0F12, 0x0200}, +{0x0F12, 0x0C00}, +{0x0F12, 0xF000}, +{0x0F12, 0xF97A}, +{0x0F12, 0x6028}, +{0x0F12, 0xBC70}, +{0x0F12, 0xBC08}, +{0x0F12, 0x4718}, +{0x0F12, 0xB5F1}, +{0x0F12, 0xB082}, +{0x0F12, 0x4D96}, +{0x0F12, 0x4E91}, +{0x0F12, 0x88A8}, +{0x0F12, 0x1C2C}, +{0x0F12, 0x3420}, +{0x0F12, 0x4F90}, +{0x0F12, 0x2800}, +{0x0F12, 0xD018}, +{0x0F12, 0xF000}, +{0x0F12, 0xF988}, +{0x0F12, 0x9001}, +{0x0F12, 0x9802}, +{0x0F12, 0x6B39}, +{0x0F12, 0x0200}, +{0x0F12, 0xF000}, +{0x0F12, 0xF974}, +{0x0F12, 0xF000}, +{0x0F12, 0xF978}, +{0x0F12, 0x9901}, +{0x0F12, 0xF000}, +{0x0F12, 0xF95F}, +{0x0F12, 0x8020}, +{0x0F12, 0x8871}, +{0x0F12, 0x0200}, +{0x0F12, 0xF000}, +{0x0F12, 0xF96A}, +{0x0F12, 0x0400}, +{0x0F12, 0x0C00}, +{0x0F12, 0x21FF}, +{0x0F12, 0x3101}, +{0x0F12, 0xF000}, +{0x0F12, 0xF97A}, +{0x0F12, 0x8020}, +{0x0F12, 0x88E8}, +{0x0F12, 0x2800}, +{0x0F12, 0xD00A}, +{0x0F12, 0x4980}, +{0x0F12, 0x8820}, +{0x0F12, 0x3128}, +{0x0F12, 0xF000}, +{0x0F12, 0xF979}, +{0x0F12, 0x8D38}, +{0x0F12, 0x8871}, +{0x0F12, 0x4348}, +{0x0F12, 0x0200}, +{0x0F12, 0x0C00}, +{0x0F12, 0x8538}, +{0x0F12, 0xBCFE}, +{0x0F12, 0xBC08}, +{0x0F12, 0x4718}, +{0x0F12, 0xB510}, +{0x0F12, 0x1C04}, +{0x0F12, 0xF000}, +{0x0F12, 0xF974}, +{0x0F12, 0x6821}, +{0x0F12, 0x0409}, +{0x0F12, 0x0C09}, +{0x0F12, 0x1A40}, +{0x0F12, 0x4976}, +{0x0F12, 0x6849}, +{0x0F12, 0x4281}, +{0x0F12, 0xD800}, +{0x0F12, 0x1C08}, +{0x0F12, 0xF000}, +{0x0F12, 0xF971}, +{0x0F12, 0x6020}, +{0x0F12, 0xE75B}, +{0x0F12, 0xB570}, +{0x0F12, 0x6801}, +{0x0F12, 0x040D}, +{0x0F12, 0x0C2D}, +{0x0F12, 0x6844}, +{0x0F12, 0x486F}, +{0x0F12, 0x8981}, +{0x0F12, 0x1C28}, +{0x0F12, 0xF000}, +{0x0F12, 0xF927}, +{0x0F12, 0x8060}, +{0x0F12, 0x4970}, +{0x0F12, 0x69C9}, +{0x0F12, 0xF000}, +{0x0F12, 0xF968}, +{0x0F12, 0x1C01}, +{0x0F12, 0x80A0}, +{0x0F12, 0x0228}, +{0x0F12, 0xF000}, +{0x0F12, 0xF92D}, +{0x0F12, 0x0400}, +{0x0F12, 0x0C00}, +{0x0F12, 0x8020}, +{0x0F12, 0x496B}, +{0x0F12, 0x2300}, +{0x0F12, 0x5EC9}, +{0x0F12, 0x4288}, +{0x0F12, 0xDA02}, +{0x0F12, 0x20FF}, +{0x0F12, 0x3001}, +{0x0F12, 0x8020}, +{0x0F12, 0xE797}, +{0x0F12, 0xB5F8}, +{0x0F12, 0x1C04}, +{0x0F12, 0x4867}, +{0x0F12, 0x4E65}, +{0x0F12, 0x7800}, +{0x0F12, 0x6AB7}, +{0x0F12, 0x2800}, +{0x0F12, 0xD100}, +{0x0F12, 0x6A37}, +{0x0F12, 0x495D}, +{0x0F12, 0x2800}, +{0x0F12, 0x688D}, +{0x0F12, 0xD100}, +{0x0F12, 0x684D}, +{0x0F12, 0x4859}, +{0x0F12, 0x8841}, +{0x0F12, 0x6820}, +{0x0F12, 0x0200}, +{0x0F12, 0xF000}, +{0x0F12, 0xF94B}, +{0x0F12, 0x8DF1}, +{0x0F12, 0x434F}, +{0x0F12, 0x0A3A}, +{0x0F12, 0x4282}, +{0x0F12, 0xD30C}, +{0x0F12, 0x4D5C}, +{0x0F12, 0x26FF}, +{0x0F12, 0x8829}, +{0x0F12, 0x3601}, +{0x0F12, 0x43B1}, +{0x0F12, 0x8029}, +{0x0F12, 0xF000}, +{0x0F12, 0xF944}, +{0x0F12, 0x6020}, +{0x0F12, 0x8828}, +{0x0F12, 0x4330}, +{0x0F12, 0x8028}, +{0x0F12, 0xE73B}, +{0x0F12, 0x1C0A}, +{0x0F12, 0x436A}, +{0x0F12, 0x0A12}, +{0x0F12, 0x4282}, +{0x0F12, 0xD304}, +{0x0F12, 0x0200}, +{0x0F12, 0xF000}, +{0x0F12, 0xF8F3}, +{0x0F12, 0x6020}, +{0x0F12, 0xE7F4}, +{0x0F12, 0x6025}, +{0x0F12, 0xE7F2}, +{0x0F12, 0xB410}, +{0x0F12, 0x4848}, +{0x0F12, 0x4950}, +{0x0F12, 0x89C0}, +{0x0F12, 0x2316}, +{0x0F12, 0x5ECC}, +{0x0F12, 0x1C02}, +{0x0F12, 0x42A0}, +{0x0F12, 0xDC00}, +{0x0F12, 0x1C22}, +{0x0F12, 0x82CA}, +{0x0F12, 0x2318}, +{0x0F12, 0x5ECA}, +{0x0F12, 0x4290}, +{0x0F12, 0xDC00}, +{0x0F12, 0x1C10}, +{0x0F12, 0x8308}, +{0x0F12, 0xBC10}, +{0x0F12, 0x4770}, +{0x0F12, 0xB570}, +{0x0F12, 0x1C06}, +{0x0F12, 0x4C45}, +{0x0F12, 0x2501}, +{0x0F12, 0x8820}, +{0x0F12, 0x02AD}, +{0x0F12, 0x43A8}, +{0x0F12, 0x8020}, +{0x0F12, 0xF000}, +{0x0F12, 0xF91E}, +{0x0F12, 0x6030}, +{0x0F12, 0xF7FF}, +{0x0F12, 0xFFE0}, +{0x0F12, 0x8820}, +{0x0F12, 0x4328}, +{0x0F12, 0x8020}, +{0x0F12, 0xE741}, +{0x0F12, 0xB570}, +{0x0F12, 0x4C3D}, +{0x0F12, 0x2501}, +{0x0F12, 0x8820}, +{0x0F12, 0x02ED}, +{0x0F12, 0x43A8}, +{0x0F12, 0x8020}, +{0x0F12, 0xF000}, +{0x0F12, 0xF916}, +{0x0F12, 0xF7FF}, +{0x0F12, 0xFFD1}, +{0x0F12, 0x8820}, +{0x0F12, 0x4328}, +{0x0F12, 0x8020}, +{0x0F12, 0xE732}, +{0x0F12, 0x230D}, +{0x0F12, 0x071B}, +{0x0F12, 0x18C3}, +{0x0F12, 0x8818}, +{0x0F12, 0x2A00}, +{0x0F12, 0xD001}, +{0x0F12, 0x4308}, +{0x0F12, 0xE000}, +{0x0F12, 0x4388}, +{0x0F12, 0x8018}, +{0x0F12, 0x4770}, +{0x0F12, 0xB570}, +{0x0F12, 0x2402}, +{0x0F12, 0x4932}, +{0x0F12, 0x8809}, +{0x0F12, 0x078A}, +{0x0F12, 0xD500}, +{0x0F12, 0x2406}, +{0x0F12, 0x2900}, +{0x0F12, 0xD01F}, +{0x0F12, 0x1C02}, +{0x0F12, 0x207D}, +{0x0F12, 0x00C0}, +{0x0F12, 0x2600}, +{0x0F12, 0x4D2D}, +{0x0F12, 0x2A00}, +{0x0F12, 0xD019}, +{0x0F12, 0x2101}, +{0x0F12, 0x8229}, +{0x0F12, 0xF000}, +{0x0F12, 0xF8F9}, +{0x0F12, 0x2200}, +{0x0F12, 0x2101}, +{0x0F12, 0x482A}, +{0x0F12, 0x0309}, +{0x0F12, 0xF7FF}, +{0x0F12, 0xFFDB}, +{0x0F12, 0x2008}, +{0x0F12, 0x4304}, +{0x0F12, 0x1C21}, +{0x0F12, 0x4C26}, +{0x0F12, 0x2200}, +{0x0F12, 0x3C14}, +{0x0F12, 0x1C20}, +{0x0F12, 0xF7FF}, +{0x0F12, 0xFFD2}, +{0x0F12, 0x2200}, +{0x0F12, 0x2121}, +{0x0F12, 0x1C20}, +{0x0F12, 0xF7FF}, +{0x0F12, 0xFFCD}, +{0x0F12, 0x802E}, +{0x0F12, 0xE6FD}, +{0x0F12, 0x822E}, +{0x0F12, 0x0789}, +{0x0F12, 0x0FC9}, +{0x0F12, 0x0089}, +{0x0F12, 0x223B}, +{0x0F12, 0x4311}, +{0x0F12, 0x8029}, +{0x0F12, 0xF000}, +{0x0F12, 0xF8DA}, +{0x0F12, 0xE7F4}, +{0x0F12, 0xB510}, +{0x0F12, 0x491B}, +{0x0F12, 0x8FC8}, +{0x0F12, 0x2800}, +{0x0F12, 0xD007}, +{0x0F12, 0x2000}, +{0x0F12, 0x87C8}, +{0x0F12, 0x8F88}, +{0x0F12, 0x4C19}, +{0x0F12, 0x2800}, +{0x0F12, 0xD002}, +{0x0F12, 0x2008}, +{0x0F12, 0x8020}, +{0x0F12, 0xE689}, +{0x0F12, 0x4815}, +{0x0F12, 0x3060}, +{0x0F12, 0x8900}, +{0x0F12, 0x2800}, +{0x0F12, 0xD103}, +{0x0F12, 0x4814}, +{0x0F12, 0x2101}, +{0x0F12, 0xF000}, +{0x0F12, 0xF8CA}, +{0x0F12, 0x2010}, +{0x0F12, 0x8020}, +{0x0F12, 0xE7F2}, +{0x0F12, 0x0000}, +{0x0F12, 0x1376}, +{0x0F12, 0x7000}, +{0x0F12, 0x2370}, +{0x0F12, 0x7000}, +{0x0F12, 0x14D8}, +{0x0F12, 0x7000}, +{0x0F12, 0x235C}, +{0x0F12, 0x7000}, +{0x0F12, 0xF4B0}, +{0x0F12, 0x0000}, +{0x0F12, 0x1554}, +{0x0F12, 0x7000}, +{0x0F12, 0x1AB8}, +{0x0F12, 0x7000}, +{0x0F12, 0x0080}, +{0x0F12, 0x7000}, +{0x0F12, 0x046C}, +{0x0F12, 0x7000}, +{0x0F12, 0x0468}, +{0x0F12, 0x7000}, +{0x0F12, 0x1100}, +{0x0F12, 0xD000}, +{0x0F12, 0x198C}, +{0x0F12, 0x7000}, +{0x0F12, 0x0AC4}, +{0x0F12, 0x7000}, +{0x0F12, 0xB0A0}, +{0x0F12, 0xD000}, +{0x0F12, 0xB0B4}, +{0x0F12, 0x0000}, +{0x0F12, 0x01B8}, +{0x0F12, 0x7000}, +{0x0F12, 0x044E}, +{0x0F12, 0x7000}, +{0x0F12, 0x0450}, +{0x0F12, 0x7000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x9CE7}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xF004}, +{0x0F12, 0xE51F}, +{0x0F12, 0x9FB8}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x14C1}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x27E1}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x88DF}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x275D}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x1ED3}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x27C5}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xF004}, +{0x0F12, 0xE51F}, +{0x0F12, 0xA144}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x1F87}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x27A9}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x1ECB}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x28FF}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x26F9}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x4027}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x9F03}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xF004}, +{0x0F12, 0xE51F}, +{0x0F12, 0x9D9C}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x285F}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x6181}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x6663}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x85D9}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x2001}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0xE848}, +{0x0F12, 0x0001}, +{0x0F12, 0xE848}, +{0x0F12, 0x0001}, +{0x0F12, 0x0500}, +{0x0F12, 0x0064}, +{0x0F12, 0x0002}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +//Parameters Defined in T&P: +//REG_SF_USER_IsoVal 2 700003EE SHORT +//REG_SF_USER_IsoChanged 2 700003F0 SHORT +//AWBBTune_EVT4 20 7000235C STRUCT +//AWBBTune_EVT4_uMinCoarse 2 7000235C SHORT +//AWBBTune_EVT4_uMinFine 2 7000235E SHORT +//AWBBTune_EVT4_uMaxExp3 4 70002360 LONG +//AWBBTune_EVT4_uCapMaxExp3 4 70002364 LONG +//AWBBTune_EVT4_uMaxAnGain3 2 70002368 SHORT +//AWBBTune_EVT4_uMinFinalPt 2 7000236A SHORT +//AWBBTune_EVT4_uInitPostToleranceCnt 2 7000236C SHORT +//AWBB_Mon_EVT3 4 70002370 STRUCT +//AWBB_Mon_EVT3_uPostToleranceCnt 2 70002370 SHORT +//AWBB_Mon_EVT3_usIsoFixedDigitalGain88 2 70002372 SHORT +//End T&P part + + +//================================================================ +// Analog Setting +//================================================================ +{0x0004, 0x0000}, //Disable Auto Address Increment : 0 +{0xF454, 0x0001}, //ADC sat = 750mV(50h), NTG = -0.8V(10h), Saturation margin low limit = 732LSB +{0xF418, 0x0050}, //aig_adc_sat[7:4] +{0xF43E, 0x0010}, //aig_reg_tune_ntg[7:0] +{0x0004, 0x0001}, //Disable Auto Address Increment : 1 +{0x002A, 0x112A}, //senHal_SenRegsModes3_pSenModesRegsArray3[8] +{0x0F12, 0x0000}, +{0x002A, 0x1132}, //senHal_SenRegsModes3_pSenModesRegsArray3[12] +{0x0F12, 0x0000}, +{0x002A, 0x113E}, //senHal_SenRegsModes3_pSenModesRegsArray3[18] +{0x0F12, 0x0000}, +{0x002A, 0x115C}, //senHal_SenRegsModes3_pSenModesRegsArray3[33] +{0x0F12, 0x0000}, +{0x002A, 0x1164}, //senHal_SenRegsModes3_pSenModesRegsArray3[37] +{0x0F12, 0x0000}, +{0x002A, 0x1174}, //senHal_SenRegsModes3_pSenModesRegsArray3[45] +{0x0F12, 0x0000}, +{0x002A, 0x1178}, //senHal_SenRegsModes3_pSenModesRegsArray3[47] +{0x0F12, 0x0000}, +{0x002A, 0x077A}, //msm_uOffsetNoBin +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x07A2}, //msm_sAnalogOffset +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x07B6}, //msm_NonLinearOfsOutput +{0x0F12, 0x0000}, //msm_NonLinearOfsOutput[0] +{0x0F12, 0x0002}, //msm_NonLinearOfsOutput[1] +{0x0F12, 0x0004}, //msm_NonLinearOfsOutput[2] +{0x0F12, 0x0004}, //msm_NonLinearOfsOutput[3] +{0x0F12, 0x0005}, //msm_NonLinearOfsOutput[4] +{0x0F12, 0x0005}, //msm_NonLinearOfsOutput[5] + + +//================================================================ +// ESD Check Code add_100505 +//================================================================ +{0x0028, 0x7000}, +{0x002A, 0x0132}, +{0x0F12, 0xAAAA}, //REG_FWpid + + +//================================================================ +// AE & AE Weight +//================================================================ +{0x002A, 0x1000}, //TVAR_ae_BrAve +{0x0F12, 0x0034}, //35 + +{0x002A, 0x0474}, +{0x0F12, 0x0112}, //lt_uLimitHigh //010F //0114 +{0x0F12, 0x00EF}, //lt_uLimitLow //00F1 //00F9 + +{0x002A, 0x1006}, +{0x0F12, 0x001F}, //ae_StatMode + +{0x002A, 0x108E}, //SARR_IllumType +{0x0F12, 0x00C7}, +{0x0F12, 0x00F7}, +{0x0F12, 0x0107}, +{0x0F12, 0x0142}, +{0x0F12, 0x017A}, +{0x0F12, 0x01A0}, +{0x0F12, 0x01B6}, + +{0x0F12, 0x0100}, //SARR_IllumTypeF // 0112 +{0x0F12, 0x0100}, //0122 +{0x0F12, 0x0100}, //0136 +{0x0F12, 0x0100}, //00F6 +{0x0F12, 0x0100}, //0100 +{0x0F12, 0x0100}, //00FE +{0x0F12, 0x0100}, //0100 +{0x002A, 0x0488}, + +{0x0F12, 0x410A}, //416E //33.3m //lt_uMaxExp1 +{0x0F12, 0x0000}, +{0x0F12, 0xA316}, //lt_uMaxExp2 +{0x0F12, 0x0000}, +{0x002A, 0x2360}, //AWBBTune_EVT4_uMaxExp3 +{0x0F12, 0xF424}, +{0x0F12, 0x0000}, + +{0x002A, 0x0490}, //lt_uCapMaxExp1 +{0x0F12, 0x410A}, //416E // 33.3m +{0x0F12, 0x0000}, +{0x0F12, 0xA316}, //lt_uCapMaxExp2 +{0x0F12, 0x0000}, +{0x002A, 0x2364}, //AWBBTune_EVT4_uCapMaxExp3 +{0x0F12, 0xF424}, +{0x0F12, 0x0000}, + +{0x002A, 0x0498}, +{0x0F12, 0x0210}, //01E8 //lt_uMaxAnGain1 700luxshutter +{0x0F12, 0x0330}, //lt_uMaxAnGain2 +{0x002A, 0x2368}, +{0x0F12, 0x06d0}, //700//800//900//990//A00 //AWBBTune_EVT4_uMaxAnGain3 +{0x002A, 0x049C}, +{0x0F12, 0x0100}, //lt_uMaxDigGain + +{0x002A, 0x235C}, +{0x0F12, 0x0002}, //0001 //AWBBTune_EVT4_uMinCoarse +{0x0F12, 0x0090}, //AWBBTune_EVT4_uMinFine + + +//================================================================ +// AE WeightTable +//================================================================ +{0x002A, 0x1C72}, //ae_WeightTbl_16 +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0302}, +{0x0F12, 0x0203}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0403}, +{0x0F12, 0x0304}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0403}, +{0x0F12, 0x0304}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0302}, +{0x0F12, 0x0203}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, + +{0x002A, 0x0F4C}, //brightness +{0x0F12, 0x02B0}, //180 +{0x002A, 0x0F52}, +{0x0F12, 0x02F0}, //180 + + +//================================================================ +// GAS (Shading) +//================================================================ +{0x002A, 0x0754}, //TVAR_ash_pGAS +{0x0F12, 0x247C}, +{0x0F12, 0x7000}, +{0x002A, 0x247C}, +{0x0F12, 0x01D2}, //TVAR_ash_pGAS[0] +{0x0F12, 0x0186}, //TVAR_ash_pGAS[1] +{0x0F12, 0x012A}, //TVAR_ash_pGAS[2] +{0x0F12, 0x00E6}, //TVAR_ash_pGAS[3] +{0x0F12, 0x00BC}, //TVAR_ash_pGAS[4] +{0x0F12, 0x00A2}, //TVAR_ash_pGAS[5] +{0x0F12, 0x009B}, //TVAR_ash_pGAS[6] +{0x0F12, 0x00A1}, //TVAR_ash_pGAS[7] +{0x0F12, 0x00B7}, //TVAR_ash_pGAS[8] +{0x0F12, 0x00E2}, //TVAR_ash_pGAS[9] +{0x0F12, 0x0122}, //TVAR_ash_pGAS[10] +{0x0F12, 0x017E}, //TVAR_ash_pGAS[11] +{0x0F12, 0x01BF}, //TVAR_ash_pGAS[12] +{0x0F12, 0x019C}, //TVAR_ash_pGAS[13] +{0x0F12, 0x013C}, //TVAR_ash_pGAS[14] +{0x0F12, 0x00E1}, //TVAR_ash_pGAS[15] +{0x0F12, 0x00A7}, //TVAR_ash_pGAS[16] +{0x0F12, 0x0082}, //TVAR_ash_pGAS[17] +{0x0F12, 0x006D}, //TVAR_ash_pGAS[18] +{0x0F12, 0x0065}, //TVAR_ash_pGAS[19] +{0x0F12, 0x006B}, //TVAR_ash_pGAS[20] +{0x0F12, 0x007E}, //TVAR_ash_pGAS[21] +{0x0F12, 0x00A1}, //TVAR_ash_pGAS[22] +{0x0F12, 0x00DB}, //TVAR_ash_pGAS[23] +{0x0F12, 0x0133}, //TVAR_ash_pGAS[24] +{0x0F12, 0x018B}, //TVAR_ash_pGAS[25] +{0x0F12, 0x015A}, //TVAR_ash_pGAS[26] +{0x0F12, 0x00FA}, //TVAR_ash_pGAS[27] +{0x0F12, 0x00A7}, //TVAR_ash_pGAS[28] +{0x0F12, 0x0075}, //TVAR_ash_pGAS[29] +{0x0F12, 0x0053}, //TVAR_ash_pGAS[30] +{0x0F12, 0x0040}, //TVAR_ash_pGAS[31] +{0x0F12, 0x0038}, //TVAR_ash_pGAS[32] +{0x0F12, 0x003D}, //TVAR_ash_pGAS[33] +{0x0F12, 0x004F}, //TVAR_ash_pGAS[34] +{0x0F12, 0x006D}, //TVAR_ash_pGAS[35] +{0x0F12, 0x009F}, //TVAR_ash_pGAS[36] +{0x0F12, 0x00EE}, //TVAR_ash_pGAS[37] +{0x0F12, 0x0147}, //TVAR_ash_pGAS[38] +{0x0F12, 0x0129}, //TVAR_ash_pGAS[39] +{0x0F12, 0x00CE}, //TVAR_ash_pGAS[40] +{0x0F12, 0x0085}, //TVAR_ash_pGAS[41] +{0x0F12, 0x0055}, //TVAR_ash_pGAS[42] +{0x0F12, 0x0035}, //TVAR_ash_pGAS[43] +{0x0F12, 0x0020}, //TVAR_ash_pGAS[44] +{0x0F12, 0x0018}, //TVAR_ash_pGAS[45] +{0x0F12, 0x001E}, //TVAR_ash_pGAS[46] +{0x0F12, 0x0030}, //TVAR_ash_pGAS[47] +{0x0F12, 0x004F}, //TVAR_ash_pGAS[48] +{0x0F12, 0x007B}, //TVAR_ash_pGAS[49] +{0x0F12, 0x00C3}, //TVAR_ash_pGAS[50] +{0x0F12, 0x0119}, //TVAR_ash_pGAS[51] +{0x0F12, 0x010E}, //TVAR_ash_pGAS[52] +{0x0F12, 0x00B8}, //TVAR_ash_pGAS[53] +{0x0F12, 0x0072}, //TVAR_ash_pGAS[54] +{0x0F12, 0x0044}, //TVAR_ash_pGAS[55] +{0x0F12, 0x0023}, //TVAR_ash_pGAS[56] +{0x0F12, 0x000E}, //TVAR_ash_pGAS[57] +{0x0F12, 0x0005}, //TVAR_ash_pGAS[58] +{0x0F12, 0x000C}, //TVAR_ash_pGAS[59] +{0x0F12, 0x001F}, //TVAR_ash_pGAS[60] +{0x0F12, 0x003E}, //TVAR_ash_pGAS[61] +{0x0F12, 0x0069}, //TVAR_ash_pGAS[62] +{0x0F12, 0x00AC}, //TVAR_ash_pGAS[63] +{0x0F12, 0x0101}, //TVAR_ash_pGAS[64] +{0x0F12, 0x0107}, //TVAR_ash_pGAS[65] +{0x0F12, 0x00B2}, //TVAR_ash_pGAS[66] +{0x0F12, 0x006F}, //TVAR_ash_pGAS[67] +{0x0F12, 0x0040}, //TVAR_ash_pGAS[68] +{0x0F12, 0x001E}, //TVAR_ash_pGAS[69] +{0x0F12, 0x0008}, //TVAR_ash_pGAS[70] +{0x0F12, 0x0000}, //TVAR_ash_pGAS[71] +{0x0F12, 0x0007}, //TVAR_ash_pGAS[72] +{0x0F12, 0x001B}, //TVAR_ash_pGAS[73] +{0x0F12, 0x003A}, //TVAR_ash_pGAS[74] +{0x0F12, 0x0065}, //TVAR_ash_pGAS[75] +{0x0F12, 0x00A8}, //TVAR_ash_pGAS[76] +{0x0F12, 0x00FB}, //TVAR_ash_pGAS[77] +{0x0F12, 0x0115}, //TVAR_ash_pGAS[78] +{0x0F12, 0x00BC}, //TVAR_ash_pGAS[79] +{0x0F12, 0x0077}, //TVAR_ash_pGAS[80] +{0x0F12, 0x0048}, //TVAR_ash_pGAS[81] +{0x0F12, 0x0027}, //TVAR_ash_pGAS[82] +{0x0F12, 0x0011}, //TVAR_ash_pGAS[83] +{0x0F12, 0x0009}, //TVAR_ash_pGAS[84] +{0x0F12, 0x000F}, //TVAR_ash_pGAS[85] +{0x0F12, 0x0023}, //TVAR_ash_pGAS[86] +{0x0F12, 0x0043}, //TVAR_ash_pGAS[87] +{0x0F12, 0x0070}, //TVAR_ash_pGAS[88] +{0x0F12, 0x00B5}, //TVAR_ash_pGAS[89] +{0x0F12, 0x010A}, //TVAR_ash_pGAS[90] +{0x0F12, 0x0138}, //TVAR_ash_pGAS[91] +{0x0F12, 0x00D9}, //TVAR_ash_pGAS[92] +{0x0F12, 0x008E}, //TVAR_ash_pGAS[93] +{0x0F12, 0x005E}, //TVAR_ash_pGAS[94] +{0x0F12, 0x003C}, //TVAR_ash_pGAS[95] +{0x0F12, 0x0027}, //TVAR_ash_pGAS[96] +{0x0F12, 0x001F}, //TVAR_ash_pGAS[97] +{0x0F12, 0x0024}, //TVAR_ash_pGAS[98] +{0x0F12, 0x0038}, //TVAR_ash_pGAS[99] +{0x0F12, 0x0058}, //TVAR_ash_pGAS[100] +{0x0F12, 0x0088}, //TVAR_ash_pGAS[101] +{0x0F12, 0x00D3}, //TVAR_ash_pGAS[102] +{0x0F12, 0x012D}, //TVAR_ash_pGAS[103] +{0x0F12, 0x0171}, //TVAR_ash_pGAS[104] +{0x0F12, 0x010C}, //TVAR_ash_pGAS[105] +{0x0F12, 0x00B5}, //TVAR_ash_pGAS[106] +{0x0F12, 0x007F}, //TVAR_ash_pGAS[107] +{0x0F12, 0x005D}, //TVAR_ash_pGAS[108] +{0x0F12, 0x0048}, //TVAR_ash_pGAS[109] +{0x0F12, 0x0040}, //TVAR_ash_pGAS[110] +{0x0F12, 0x0045}, //TVAR_ash_pGAS[111] +{0x0F12, 0x0059}, //TVAR_ash_pGAS[112] +{0x0F12, 0x007B}, //TVAR_ash_pGAS[113] +{0x0F12, 0x00B1}, //TVAR_ash_pGAS[114] +{0x0F12, 0x0104}, //TVAR_ash_pGAS[115] +{0x0F12, 0x0166}, //TVAR_ash_pGAS[116] +{0x0F12, 0x01B9}, //TVAR_ash_pGAS[117] +{0x0F12, 0x0152}, //TVAR_ash_pGAS[118] +{0x0F12, 0x00F3}, //TVAR_ash_pGAS[119] +{0x0F12, 0x00B5}, //TVAR_ash_pGAS[120] +{0x0F12, 0x008C}, //TVAR_ash_pGAS[121] +{0x0F12, 0x0075}, //TVAR_ash_pGAS[122] +{0x0F12, 0x006E}, //TVAR_ash_pGAS[123] +{0x0F12, 0x0073}, //TVAR_ash_pGAS[124] +{0x0F12, 0x0089}, //TVAR_ash_pGAS[125] +{0x0F12, 0x00B2}, //TVAR_ash_pGAS[126] +{0x0F12, 0x00F1}, //TVAR_ash_pGAS[127] +{0x0F12, 0x014E}, //TVAR_ash_pGAS[128] +{0x0F12, 0x01A8}, //TVAR_ash_pGAS[129] +{0x0F12, 0x01E4}, //TVAR_ash_pGAS[130] +{0x0F12, 0x019F}, //TVAR_ash_pGAS[131] +{0x0F12, 0x013E}, //TVAR_ash_pGAS[132] +{0x0F12, 0x00F5}, //TVAR_ash_pGAS[133] +{0x0F12, 0x00C6}, //TVAR_ash_pGAS[134] +{0x0F12, 0x00AC}, //TVAR_ash_pGAS[135] +{0x0F12, 0x00A2}, //TVAR_ash_pGAS[136] +{0x0F12, 0x00AA}, //TVAR_ash_pGAS[137] +{0x0F12, 0x00C3}, //TVAR_ash_pGAS[138] +{0x0F12, 0x00F3}, //TVAR_ash_pGAS[139] +{0x0F12, 0x0138}, //TVAR_ash_pGAS[140] +{0x0F12, 0x0193}, //TVAR_ash_pGAS[141] +{0x0F12, 0x01DE}, //TVAR_ash_pGAS[142] +{0x0F12, 0x017C}, //TVAR_ash_pGAS[143] +{0x0F12, 0x0139}, //TVAR_ash_pGAS[144] +{0x0F12, 0x00EC}, //TVAR_ash_pGAS[145] +{0x0F12, 0x00B5}, //TVAR_ash_pGAS[146] +{0x0F12, 0x0092}, //TVAR_ash_pGAS[147] +{0x0F12, 0x007E}, //TVAR_ash_pGAS[148] +{0x0F12, 0x0077}, //TVAR_ash_pGAS[149] +{0x0F12, 0x007B}, //TVAR_ash_pGAS[150] +{0x0F12, 0x008A}, //TVAR_ash_pGAS[151] +{0x0F12, 0x00A7}, //TVAR_ash_pGAS[152] +{0x0F12, 0x00D8}, //TVAR_ash_pGAS[153] +{0x0F12, 0x011F}, //TVAR_ash_pGAS[154] +{0x0F12, 0x015A}, //TVAR_ash_pGAS[155] +{0x0F12, 0x014B}, //TVAR_ash_pGAS[156] +{0x0F12, 0x00F9}, //TVAR_ash_pGAS[157] +{0x0F12, 0x00AF}, //TVAR_ash_pGAS[158] +{0x0F12, 0x0081}, //TVAR_ash_pGAS[159] +{0x0F12, 0x0064}, //TVAR_ash_pGAS[160] +{0x0F12, 0x0054}, //TVAR_ash_pGAS[161] +{0x0F12, 0x004E}, //TVAR_ash_pGAS[162] +{0x0F12, 0x0050}, //TVAR_ash_pGAS[163] +{0x0F12, 0x005D}, //TVAR_ash_pGAS[164] +{0x0F12, 0x0075}, //TVAR_ash_pGAS[165] +{0x0F12, 0x009F}, //TVAR_ash_pGAS[166] +{0x0F12, 0x00E1}, //TVAR_ash_pGAS[167] +{0x0F12, 0x012C}, //TVAR_ash_pGAS[168] +{0x0F12, 0x0116}, //TVAR_ash_pGAS[169] +{0x0F12, 0x00C4}, //TVAR_ash_pGAS[170] +{0x0F12, 0x0084}, //TVAR_ash_pGAS[171] +{0x0F12, 0x005B}, //TVAR_ash_pGAS[172] +{0x0F12, 0x0042}, //TVAR_ash_pGAS[173] +{0x0F12, 0x0032}, //TVAR_ash_pGAS[174] +{0x0F12, 0x002B}, //TVAR_ash_pGAS[175] +{0x0F12, 0x002E}, //TVAR_ash_pGAS[176] +{0x0F12, 0x003A}, //TVAR_ash_pGAS[177] +{0x0F12, 0x004F}, //TVAR_ash_pGAS[178] +{0x0F12, 0x0072}, //TVAR_ash_pGAS[179] +{0x0F12, 0x00AD}, //TVAR_ash_pGAS[180] +{0x0F12, 0x00F8}, //TVAR_ash_pGAS[181] +{0x0F12, 0x00EC}, //TVAR_ash_pGAS[182] +{0x0F12, 0x00A2}, //TVAR_ash_pGAS[183] +{0x0F12, 0x0069}, //TVAR_ash_pGAS[184] +{0x0F12, 0x0044}, //TVAR_ash_pGAS[185] +{0x0F12, 0x002A}, //TVAR_ash_pGAS[186] +{0x0F12, 0x0019}, //TVAR_ash_pGAS[187] +{0x0F12, 0x0012}, //TVAR_ash_pGAS[188] +{0x0F12, 0x0015}, //TVAR_ash_pGAS[189] +{0x0F12, 0x0022}, //TVAR_ash_pGAS[190] +{0x0F12, 0x0037}, //TVAR_ash_pGAS[191] +{0x0F12, 0x0057}, //TVAR_ash_pGAS[192] +{0x0F12, 0x008C}, //TVAR_ash_pGAS[193] +{0x0F12, 0x00D2}, //TVAR_ash_pGAS[194] +{0x0F12, 0x00D6}, //TVAR_ash_pGAS[195] +{0x0F12, 0x0090}, //TVAR_ash_pGAS[196] +{0x0F12, 0x005A}, //TVAR_ash_pGAS[197] +{0x0F12, 0x0036}, //TVAR_ash_pGAS[198] +{0x0F12, 0x001C}, //TVAR_ash_pGAS[199] +{0x0F12, 0x000A}, //TVAR_ash_pGAS[200] +{0x0F12, 0x0003}, //TVAR_ash_pGAS[201] +{0x0F12, 0x0007}, //TVAR_ash_pGAS[202] +{0x0F12, 0x0015}, //TVAR_ash_pGAS[203] +{0x0F12, 0x002B}, //TVAR_ash_pGAS[204] +{0x0F12, 0x004A}, //TVAR_ash_pGAS[205] +{0x0F12, 0x007C}, //TVAR_ash_pGAS[206] +{0x0F12, 0x00BF}, //TVAR_ash_pGAS[207] +{0x0F12, 0x00CF}, //TVAR_ash_pGAS[208] +{0x0F12, 0x008C}, //TVAR_ash_pGAS[209] +{0x0F12, 0x0057}, //TVAR_ash_pGAS[210] +{0x0F12, 0x0033}, //TVAR_ash_pGAS[211] +{0x0F12, 0x0019}, //TVAR_ash_pGAS[212] +{0x0F12, 0x0007}, //TVAR_ash_pGAS[213] +{0x0F12, 0x0000}, //TVAR_ash_pGAS[214] +{0x0F12, 0x0004}, //TVAR_ash_pGAS[215] +{0x0F12, 0x0012}, //TVAR_ash_pGAS[216] +{0x0F12, 0x0029}, //TVAR_ash_pGAS[217] +{0x0F12, 0x0048}, //TVAR_ash_pGAS[218] +{0x0F12, 0x007A}, //TVAR_ash_pGAS[219] +{0x0F12, 0x00BC}, //TVAR_ash_pGAS[220] +{0x0F12, 0x00DB}, //TVAR_ash_pGAS[221] +{0x0F12, 0x0093}, //TVAR_ash_pGAS[222] +{0x0F12, 0x005E}, //TVAR_ash_pGAS[223] +{0x0F12, 0x003B}, //TVAR_ash_pGAS[224] +{0x0F12, 0x0021}, //TVAR_ash_pGAS[225] +{0x0F12, 0x000F}, //TVAR_ash_pGAS[226] +{0x0F12, 0x0008}, //TVAR_ash_pGAS[227] +{0x0F12, 0x000C}, //TVAR_ash_pGAS[228] +{0x0F12, 0x001B}, //TVAR_ash_pGAS[229] +{0x0F12, 0x0031}, //TVAR_ash_pGAS[230] +{0x0F12, 0x0052}, //TVAR_ash_pGAS[231] +{0x0F12, 0x0084}, //TVAR_ash_pGAS[232] +{0x0F12, 0x00C8}, //TVAR_ash_pGAS[233] +{0x0F12, 0x00F8}, //TVAR_ash_pGAS[234] +{0x0F12, 0x00AB}, //TVAR_ash_pGAS[235] +{0x0F12, 0x0071}, //TVAR_ash_pGAS[236] +{0x0F12, 0x004D}, //TVAR_ash_pGAS[237] +{0x0F12, 0x0034}, //TVAR_ash_pGAS[238] +{0x0F12, 0x0023}, //TVAR_ash_pGAS[239] +{0x0F12, 0x001C}, //TVAR_ash_pGAS[240] +{0x0F12, 0x0020}, //TVAR_ash_pGAS[241] +{0x0F12, 0x002E}, //TVAR_ash_pGAS[242] +{0x0F12, 0x0044}, //TVAR_ash_pGAS[243] +{0x0F12, 0x0066}, //TVAR_ash_pGAS[244] +{0x0F12, 0x009D}, //TVAR_ash_pGAS[245] +{0x0F12, 0x00E7}, //TVAR_ash_pGAS[246] +{0x0F12, 0x0125}, //TVAR_ash_pGAS[247] +{0x0F12, 0x00D2}, //TVAR_ash_pGAS[248] +{0x0F12, 0x0090}, //TVAR_ash_pGAS[249] +{0x0F12, 0x0069}, //TVAR_ash_pGAS[250] +{0x0F12, 0x004F}, //TVAR_ash_pGAS[251] +{0x0F12, 0x003F}, //TVAR_ash_pGAS[252] +{0x0F12, 0x0038}, //TVAR_ash_pGAS[253] +{0x0F12, 0x003C}, //TVAR_ash_pGAS[254] +{0x0F12, 0x0049}, //TVAR_ash_pGAS[255] +{0x0F12, 0x0061}, //TVAR_ash_pGAS[256] +{0x0F12, 0x0087}, //TVAR_ash_pGAS[257] +{0x0F12, 0x00C4}, //TVAR_ash_pGAS[258] +{0x0F12, 0x0114}, //TVAR_ash_pGAS[259] +{0x0F12, 0x0162}, //TVAR_ash_pGAS[260] +{0x0F12, 0x010C}, //TVAR_ash_pGAS[261] +{0x0F12, 0x00C3}, //TVAR_ash_pGAS[262] +{0x0F12, 0x0093}, //TVAR_ash_pGAS[263] +{0x0F12, 0x0074}, //TVAR_ash_pGAS[264] +{0x0F12, 0x0064}, //TVAR_ash_pGAS[265] +{0x0F12, 0x005D}, //TVAR_ash_pGAS[266] +{0x0F12, 0x0061}, //TVAR_ash_pGAS[267] +{0x0F12, 0x0071}, //TVAR_ash_pGAS[268] +{0x0F12, 0x008C}, //TVAR_ash_pGAS[269] +{0x0F12, 0x00BB}, //TVAR_ash_pGAS[270] +{0x0F12, 0x0102}, //TVAR_ash_pGAS[271] +{0x0F12, 0x014D}, //TVAR_ash_pGAS[272] +{0x0F12, 0x018A}, //TVAR_ash_pGAS[273] +{0x0F12, 0x014F}, //TVAR_ash_pGAS[274] +{0x0F12, 0x00FE}, //TVAR_ash_pGAS[275] +{0x0F12, 0x00C5}, //TVAR_ash_pGAS[276] +{0x0F12, 0x00A2}, //TVAR_ash_pGAS[277] +{0x0F12, 0x008E}, //TVAR_ash_pGAS[278] +{0x0F12, 0x0087}, //TVAR_ash_pGAS[279] +{0x0F12, 0x008C}, //TVAR_ash_pGAS[280] +{0x0F12, 0x009E}, //TVAR_ash_pGAS[281] +{0x0F12, 0x00C0}, //TVAR_ash_pGAS[282] +{0x0F12, 0x00F5}, //TVAR_ash_pGAS[283] +{0x0F12, 0x013E}, //TVAR_ash_pGAS[284] +{0x0F12, 0x017D}, //TVAR_ash_pGAS[285] +{0x0F12, 0x0192}, //TVAR_ash_pGAS[286] +{0x0F12, 0x0148}, //TVAR_ash_pGAS[287] +{0x0F12, 0x00F5}, //TVAR_ash_pGAS[288] +{0x0F12, 0x00BA}, //TVAR_ash_pGAS[289] +{0x0F12, 0x0095}, //TVAR_ash_pGAS[290] +{0x0F12, 0x007F}, //TVAR_ash_pGAS[291] +{0x0F12, 0x0078}, //TVAR_ash_pGAS[292] +{0x0F12, 0x007C}, //TVAR_ash_pGAS[293] +{0x0F12, 0x008F}, //TVAR_ash_pGAS[294] +{0x0F12, 0x00B3}, //TVAR_ash_pGAS[295] +{0x0F12, 0x00E9}, //TVAR_ash_pGAS[296] +{0x0F12, 0x013B}, //TVAR_ash_pGAS[297] +{0x0F12, 0x017E}, //TVAR_ash_pGAS[298] +{0x0F12, 0x015F}, //TVAR_ash_pGAS[299] +{0x0F12, 0x0108}, //TVAR_ash_pGAS[300] +{0x0F12, 0x00B9}, //TVAR_ash_pGAS[301] +{0x0F12, 0x0087}, //TVAR_ash_pGAS[302] +{0x0F12, 0x0069}, //TVAR_ash_pGAS[303] +{0x0F12, 0x0056}, //TVAR_ash_pGAS[304] +{0x0F12, 0x004F}, //TVAR_ash_pGAS[305] +{0x0F12, 0x0053}, //TVAR_ash_pGAS[306] +{0x0F12, 0x0062}, //TVAR_ash_pGAS[307] +{0x0F12, 0x007F}, //TVAR_ash_pGAS[308] +{0x0F12, 0x00AE}, //TVAR_ash_pGAS[309] +{0x0F12, 0x00F8}, //TVAR_ash_pGAS[310] +{0x0F12, 0x014C}, //TVAR_ash_pGAS[311] +{0x0F12, 0x0129}, //TVAR_ash_pGAS[312] +{0x0F12, 0x00D4}, //TVAR_ash_pGAS[313] +{0x0F12, 0x008F}, //TVAR_ash_pGAS[314] +{0x0F12, 0x0063}, //TVAR_ash_pGAS[315] +{0x0F12, 0x0047}, //TVAR_ash_pGAS[316] +{0x0F12, 0x0034}, //TVAR_ash_pGAS[317] +{0x0F12, 0x002D}, //TVAR_ash_pGAS[318] +{0x0F12, 0x0030}, //TVAR_ash_pGAS[319] +{0x0F12, 0x003E}, //TVAR_ash_pGAS[320] +{0x0F12, 0x0057}, //TVAR_ash_pGAS[321] +{0x0F12, 0x007F}, //TVAR_ash_pGAS[322] +{0x0F12, 0x00BF}, //TVAR_ash_pGAS[323] +{0x0F12, 0x0111}, //TVAR_ash_pGAS[324] +{0x0F12, 0x0100}, //TVAR_ash_pGAS[325] +{0x0F12, 0x00B1}, //TVAR_ash_pGAS[326] +{0x0F12, 0x0074}, //TVAR_ash_pGAS[327] +{0x0F12, 0x004C}, //TVAR_ash_pGAS[328] +{0x0F12, 0x002F}, //TVAR_ash_pGAS[329] +{0x0F12, 0x001C}, //TVAR_ash_pGAS[330] +{0x0F12, 0x0013}, //TVAR_ash_pGAS[331] +{0x0F12, 0x0017}, //TVAR_ash_pGAS[332] +{0x0F12, 0x0026}, //TVAR_ash_pGAS[333] +{0x0F12, 0x003E}, //TVAR_ash_pGAS[334] +{0x0F12, 0x0062}, //TVAR_ash_pGAS[335] +{0x0F12, 0x0099}, //TVAR_ash_pGAS[336] +{0x0F12, 0x00E5}, //TVAR_ash_pGAS[337] +{0x0F12, 0x00E6}, //TVAR_ash_pGAS[338] +{0x0F12, 0x009F}, //TVAR_ash_pGAS[339] +{0x0F12, 0x0066}, //TVAR_ash_pGAS[340] +{0x0F12, 0x003F}, //TVAR_ash_pGAS[341] +{0x0F12, 0x0021}, //TVAR_ash_pGAS[342] +{0x0F12, 0x000D}, //TVAR_ash_pGAS[343] +{0x0F12, 0x0004}, //TVAR_ash_pGAS[344] +{0x0F12, 0x0008}, //TVAR_ash_pGAS[345] +{0x0F12, 0x0016}, //TVAR_ash_pGAS[346] +{0x0F12, 0x002F}, //TVAR_ash_pGAS[347] +{0x0F12, 0x0050}, //TVAR_ash_pGAS[348] +{0x0F12, 0x0085}, //TVAR_ash_pGAS[349] +{0x0F12, 0x00CA}, //TVAR_ash_pGAS[350] +{0x0F12, 0x00E2}, //TVAR_ash_pGAS[351] +{0x0F12, 0x009A}, //TVAR_ash_pGAS[352] +{0x0F12, 0x0062}, //TVAR_ash_pGAS[353] +{0x0F12, 0x003B}, //TVAR_ash_pGAS[354] +{0x0F12, 0x001D}, //TVAR_ash_pGAS[355] +{0x0F12, 0x0009}, //TVAR_ash_pGAS[356] +{0x0F12, 0x0000}, //TVAR_ash_pGAS[357] +{0x0F12, 0x0003}, //TVAR_ash_pGAS[358] +{0x0F12, 0x0011}, //TVAR_ash_pGAS[359] +{0x0F12, 0x0029}, //TVAR_ash_pGAS[360] +{0x0F12, 0x0049}, //TVAR_ash_pGAS[361] +{0x0F12, 0x007D}, //TVAR_ash_pGAS[362] +{0x0F12, 0x00C0}, //TVAR_ash_pGAS[363] +{0x0F12, 0x00EE}, //TVAR_ash_pGAS[364] +{0x0F12, 0x00A1}, //TVAR_ash_pGAS[365] +{0x0F12, 0x0069}, //TVAR_ash_pGAS[366] +{0x0F12, 0x0043}, //TVAR_ash_pGAS[367] +{0x0F12, 0x0025}, //TVAR_ash_pGAS[368] +{0x0F12, 0x0010}, //TVAR_ash_pGAS[369] +{0x0F12, 0x0007}, //TVAR_ash_pGAS[370] +{0x0F12, 0x000A}, //TVAR_ash_pGAS[371] +{0x0F12, 0x0017}, //TVAR_ash_pGAS[372] +{0x0F12, 0x002E}, //TVAR_ash_pGAS[373] +{0x0F12, 0x004F}, //TVAR_ash_pGAS[374] +{0x0F12, 0x0083}, //TVAR_ash_pGAS[375] +{0x0F12, 0x00C7}, //TVAR_ash_pGAS[376] +{0x0F12, 0x010B}, //TVAR_ash_pGAS[377] +{0x0F12, 0x00BA}, //TVAR_ash_pGAS[378] +{0x0F12, 0x007B}, //TVAR_ash_pGAS[379] +{0x0F12, 0x0054}, //TVAR_ash_pGAS[380] +{0x0F12, 0x0037}, //TVAR_ash_pGAS[381] +{0x0F12, 0x0023}, //TVAR_ash_pGAS[382] +{0x0F12, 0x001A}, //TVAR_ash_pGAS[383] +{0x0F12, 0x001B}, //TVAR_ash_pGAS[384] +{0x0F12, 0x0027}, //TVAR_ash_pGAS[385] +{0x0F12, 0x003D}, //TVAR_ash_pGAS[386] +{0x0F12, 0x005F}, //TVAR_ash_pGAS[387] +{0x0F12, 0x0095}, //TVAR_ash_pGAS[388] +{0x0F12, 0x00DE}, //TVAR_ash_pGAS[389] +{0x0F12, 0x013A}, //TVAR_ash_pGAS[390] +{0x0F12, 0x00E1}, //TVAR_ash_pGAS[391] +{0x0F12, 0x009C}, //TVAR_ash_pGAS[392] +{0x0F12, 0x006F}, //TVAR_ash_pGAS[393] +{0x0F12, 0x0053}, //TVAR_ash_pGAS[394] +{0x0F12, 0x003F}, //TVAR_ash_pGAS[395] +{0x0F12, 0x0035}, //TVAR_ash_pGAS[396] +{0x0F12, 0x0036}, //TVAR_ash_pGAS[397] +{0x0F12, 0x0042}, //TVAR_ash_pGAS[398] +{0x0F12, 0x0058}, //TVAR_ash_pGAS[399] +{0x0F12, 0x007D}, //TVAR_ash_pGAS[400] +{0x0F12, 0x00B9}, //TVAR_ash_pGAS[401] +{0x0F12, 0x0105}, //TVAR_ash_pGAS[402] +{0x0F12, 0x0177}, //TVAR_ash_pGAS[403] +{0x0F12, 0x011D}, //TVAR_ash_pGAS[404] +{0x0F12, 0x00CE}, //TVAR_ash_pGAS[405] +{0x0F12, 0x009A}, //TVAR_ash_pGAS[406] +{0x0F12, 0x0078}, //TVAR_ash_pGAS[407] +{0x0F12, 0x0064}, //TVAR_ash_pGAS[408] +{0x0F12, 0x005B}, //TVAR_ash_pGAS[409] +{0x0F12, 0x005C}, //TVAR_ash_pGAS[410] +{0x0F12, 0x0068}, //TVAR_ash_pGAS[411] +{0x0F12, 0x0082}, //TVAR_ash_pGAS[412] +{0x0F12, 0x00AD}, //TVAR_ash_pGAS[413] +{0x0F12, 0x00F1}, //TVAR_ash_pGAS[414] +{0x0F12, 0x0137}, //TVAR_ash_pGAS[415] +{0x0F12, 0x019F}, //TVAR_ash_pGAS[416] +{0x0F12, 0x0160}, //TVAR_ash_pGAS[417] +{0x0F12, 0x010D}, //TVAR_ash_pGAS[418] +{0x0F12, 0x00CF}, //TVAR_ash_pGAS[419] +{0x0F12, 0x00A7}, //TVAR_ash_pGAS[420] +{0x0F12, 0x0090}, //TVAR_ash_pGAS[421] +{0x0F12, 0x0085}, //TVAR_ash_pGAS[422] +{0x0F12, 0x0087}, //TVAR_ash_pGAS[423] +{0x0F12, 0x0097}, //TVAR_ash_pGAS[424] +{0x0F12, 0x00B6}, //TVAR_ash_pGAS[425] +{0x0F12, 0x00E7}, //TVAR_ash_pGAS[426] +{0x0F12, 0x0129}, //TVAR_ash_pGAS[427] +{0x0F12, 0x0166}, //TVAR_ash_pGAS[428] +{0x0F12, 0x013A}, //TVAR_ash_pGAS[429] +{0x0F12, 0x0102}, //TVAR_ash_pGAS[430] +{0x0F12, 0x00C1}, //TVAR_ash_pGAS[431] +{0x0F12, 0x0092}, //TVAR_ash_pGAS[432] +{0x0F12, 0x0075}, //TVAR_ash_pGAS[433] +{0x0F12, 0x0065}, //TVAR_ash_pGAS[434] +{0x0F12, 0x0061}, //TVAR_ash_pGAS[435] +{0x0F12, 0x0068}, //TVAR_ash_pGAS[436] +{0x0F12, 0x007A}, //TVAR_ash_pGAS[437] +{0x0F12, 0x009C}, //TVAR_ash_pGAS[438] +{0x0F12, 0x00CD}, //TVAR_ash_pGAS[439] +{0x0F12, 0x0116}, //TVAR_ash_pGAS[440] +{0x0F12, 0x014D}, //TVAR_ash_pGAS[441] +{0x0F12, 0x0116}, //TVAR_ash_pGAS[442] +{0x0F12, 0x00CE}, //TVAR_ash_pGAS[443] +{0x0F12, 0x008E}, //TVAR_ash_pGAS[444] +{0x0F12, 0x0068}, //TVAR_ash_pGAS[445] +{0x0F12, 0x0050}, //TVAR_ash_pGAS[446] +{0x0F12, 0x0044}, //TVAR_ash_pGAS[447] +{0x0F12, 0x0040}, //TVAR_ash_pGAS[448] +{0x0F12, 0x0045}, //TVAR_ash_pGAS[449] +{0x0F12, 0x0054}, //TVAR_ash_pGAS[450] +{0x0F12, 0x006F}, //TVAR_ash_pGAS[451] +{0x0F12, 0x009A}, //TVAR_ash_pGAS[452] +{0x0F12, 0x00DC}, //TVAR_ash_pGAS[453] +{0x0F12, 0x0127}, //TVAR_ash_pGAS[454] +{0x0F12, 0x00E5}, //TVAR_ash_pGAS[455] +{0x0F12, 0x00A0}, //TVAR_ash_pGAS[456] +{0x0F12, 0x0068}, //TVAR_ash_pGAS[457] +{0x0F12, 0x0047}, //TVAR_ash_pGAS[458] +{0x0F12, 0x0033}, //TVAR_ash_pGAS[459] +{0x0F12, 0x0027}, //TVAR_ash_pGAS[460] +{0x0F12, 0x0023}, //TVAR_ash_pGAS[461] +{0x0F12, 0x0028}, //TVAR_ash_pGAS[462] +{0x0F12, 0x0036}, //TVAR_ash_pGAS[463] +{0x0F12, 0x004B}, //TVAR_ash_pGAS[464] +{0x0F12, 0x006E}, //TVAR_ash_pGAS[465] +{0x0F12, 0x00A7}, //TVAR_ash_pGAS[466] +{0x0F12, 0x00EE}, //TVAR_ash_pGAS[467] +{0x0F12, 0x00C0}, //TVAR_ash_pGAS[468] +{0x0F12, 0x0081}, //TVAR_ash_pGAS[469] +{0x0F12, 0x0051}, //TVAR_ash_pGAS[470] +{0x0F12, 0x0034}, //TVAR_ash_pGAS[471] +{0x0F12, 0x0020}, //TVAR_ash_pGAS[472] +{0x0F12, 0x0014}, //TVAR_ash_pGAS[473] +{0x0F12, 0x000F}, //TVAR_ash_pGAS[474] +{0x0F12, 0x0014}, //TVAR_ash_pGAS[475] +{0x0F12, 0x0020}, //TVAR_ash_pGAS[476] +{0x0F12, 0x0034}, //TVAR_ash_pGAS[477] +{0x0F12, 0x0052}, //TVAR_ash_pGAS[478] +{0x0F12, 0x0083}, //TVAR_ash_pGAS[479] +{0x0F12, 0x00C3}, //TVAR_ash_pGAS[480] +{0x0F12, 0x00AD}, //TVAR_ash_pGAS[481] +{0x0F12, 0x0073}, //TVAR_ash_pGAS[482] +{0x0F12, 0x0046}, //TVAR_ash_pGAS[483] +{0x0F12, 0x002A}, //TVAR_ash_pGAS[484] +{0x0F12, 0x0016}, //TVAR_ash_pGAS[485] +{0x0F12, 0x0008}, //TVAR_ash_pGAS[486] +{0x0F12, 0x0004}, //TVAR_ash_pGAS[487] +{0x0F12, 0x0008}, //TVAR_ash_pGAS[488] +{0x0F12, 0x0014}, //TVAR_ash_pGAS[489] +{0x0F12, 0x0026}, //TVAR_ash_pGAS[490] +{0x0F12, 0x0040}, //TVAR_ash_pGAS[491] +{0x0F12, 0x006D}, //TVAR_ash_pGAS[492] +{0x0F12, 0x00AA}, //TVAR_ash_pGAS[493] +{0x0F12, 0x00A8}, //TVAR_ash_pGAS[494] +{0x0F12, 0x006F}, //TVAR_ash_pGAS[495] +{0x0F12, 0x0044}, //TVAR_ash_pGAS[496] +{0x0F12, 0x0027}, //TVAR_ash_pGAS[497] +{0x0F12, 0x0013}, //TVAR_ash_pGAS[498] +{0x0F12, 0x0005}, //TVAR_ash_pGAS[499] +{0x0F12, 0x0000}, //TVAR_ash_pGAS[500] +{0x0F12, 0x0004}, //TVAR_ash_pGAS[501] +{0x0F12, 0x000F}, //TVAR_ash_pGAS[502] +{0x0F12, 0x0020}, //TVAR_ash_pGAS[503] +{0x0F12, 0x003A}, //TVAR_ash_pGAS[504] +{0x0F12, 0x0065}, //TVAR_ash_pGAS[505] +{0x0F12, 0x009F}, //TVAR_ash_pGAS[506] +{0x0F12, 0x00B4}, //TVAR_ash_pGAS[507] +{0x0F12, 0x0076}, //TVAR_ash_pGAS[508] +{0x0F12, 0x004B}, //TVAR_ash_pGAS[509] +{0x0F12, 0x002E}, //TVAR_ash_pGAS[510] +{0x0F12, 0x001A}, //TVAR_ash_pGAS[511] +{0x0F12, 0x000D}, //TVAR_ash_pGAS[512] +{0x0F12, 0x0006}, //TVAR_ash_pGAS[513] +{0x0F12, 0x000A}, //TVAR_ash_pGAS[514] +{0x0F12, 0x0014}, //TVAR_ash_pGAS[515] +{0x0F12, 0x0024}, //TVAR_ash_pGAS[516] +{0x0F12, 0x003E}, //TVAR_ash_pGAS[517] +{0x0F12, 0x0069}, //TVAR_ash_pGAS[518] +{0x0F12, 0x00A3}, //TVAR_ash_pGAS[519] +{0x0F12, 0x00CE}, //TVAR_ash_pGAS[520] +{0x0F12, 0x008D}, //TVAR_ash_pGAS[521] +{0x0F12, 0x005D}, //TVAR_ash_pGAS[522] +{0x0F12, 0x003E}, //TVAR_ash_pGAS[523] +{0x0F12, 0x002C}, //TVAR_ash_pGAS[524] +{0x0F12, 0x001D}, //TVAR_ash_pGAS[525] +{0x0F12, 0x0017}, //TVAR_ash_pGAS[526] +{0x0F12, 0x0019}, //TVAR_ash_pGAS[527] +{0x0F12, 0x0022}, //TVAR_ash_pGAS[528] +{0x0F12, 0x0031}, //TVAR_ash_pGAS[529] +{0x0F12, 0x004C}, //TVAR_ash_pGAS[530] +{0x0F12, 0x007B}, //TVAR_ash_pGAS[531] +{0x0F12, 0x00B8}, //TVAR_ash_pGAS[532] +{0x0F12, 0x00F9}, //TVAR_ash_pGAS[533] +{0x0F12, 0x00B2}, //TVAR_ash_pGAS[534] +{0x0F12, 0x0079}, //TVAR_ash_pGAS[535] +{0x0F12, 0x0059}, //TVAR_ash_pGAS[536] +{0x0F12, 0x0044}, //TVAR_ash_pGAS[537] +{0x0F12, 0x0036}, //TVAR_ash_pGAS[538] +{0x0F12, 0x0030}, //TVAR_ash_pGAS[539] +{0x0F12, 0x0031}, //TVAR_ash_pGAS[540] +{0x0F12, 0x0039}, //TVAR_ash_pGAS[541] +{0x0F12, 0x004A}, //TVAR_ash_pGAS[542] +{0x0F12, 0x0068}, //TVAR_ash_pGAS[543] +{0x0F12, 0x009D}, //TVAR_ash_pGAS[544] +{0x0F12, 0x00DD}, //TVAR_ash_pGAS[545] +{0x0F12, 0x0131}, //TVAR_ash_pGAS[546] +{0x0F12, 0x00E9}, //TVAR_ash_pGAS[547] +{0x0F12, 0x00A9}, //TVAR_ash_pGAS[548] +{0x0F12, 0x0080}, //TVAR_ash_pGAS[549] +{0x0F12, 0x0066}, //TVAR_ash_pGAS[550] +{0x0F12, 0x0058}, //TVAR_ash_pGAS[551] +{0x0F12, 0x0052}, //TVAR_ash_pGAS[552] +{0x0F12, 0x0053}, //TVAR_ash_pGAS[553] +{0x0F12, 0x005E}, //TVAR_ash_pGAS[554] +{0x0F12, 0x0073}, //TVAR_ash_pGAS[555] +{0x0F12, 0x0097}, //TVAR_ash_pGAS[556] +{0x0F12, 0x00D2}, //TVAR_ash_pGAS[557] +{0x0F12, 0x0110}, //TVAR_ash_pGAS[558] +{0x0F12, 0x0150}, //TVAR_ash_pGAS[559] +{0x0F12, 0x0124}, //TVAR_ash_pGAS[560] +{0x0F12, 0x00E0}, //TVAR_ash_pGAS[561] +{0x0F12, 0x00B0}, //TVAR_ash_pGAS[562] +{0x0F12, 0x0090}, //TVAR_ash_pGAS[563] +{0x0F12, 0x007E}, //TVAR_ash_pGAS[564] +{0x0F12, 0x0077}, //TVAR_ash_pGAS[565] +{0x0F12, 0x0079}, //TVAR_ash_pGAS[566] +{0x0F12, 0x0087}, //TVAR_ash_pGAS[567] +{0x0F12, 0x00A2}, //TVAR_ash_pGAS[568] +{0x0F12, 0x00CD}, //TVAR_ash_pGAS[569] +{0x0F12, 0x0106}, //TVAR_ash_pGAS[570] +{0x0F12, 0x0137}, //TVAR_ash_pGAS[571] + + +//================================================================ +// Shading Alpha +//================================================================ +{0x002A, 0x0704}, +{0x0F12, 0x00ED}, //TVAR_ash_AwbAshCord[0] +{0x0F12, 0x0124}, //TVAR_ash_AwbAshCord[1] +{0x0F12, 0x012B}, //TVAR_ash_AwbAshCord[2] +{0x0F12, 0x014A}, //TVAR_ash_AwbAshCord[3] +{0x0F12, 0x0190}, //TVAR_ash_AwbAshCord[4] +{0x0F12, 0x01B2}, //TVAR_ash_AwbAshCord[5] +{0x0F12, 0x01C4}, //TVAR_ash_AwbAshCord[6] + +{0x0F12, 0x012B}, //TVAR_ash_GASAlpha[0] +{0x0F12, 0x0106}, //TVAR_ash_GASAlpha[1] +{0x0F12, 0x010A}, //TVAR_ash_GASAlpha[2] +{0x0F12, 0x00EE}, //TVAR_ash_GASAlpha[3] +{0x0F12, 0x00C8}, //TVAR_ash_GASAlpha[4] +{0x0F12, 0x00FC}, //TVAR_ash_GASAlpha[5] +{0x0F12, 0x00FE}, //TVAR_ash_GASAlpha[6] +{0x0F12, 0x00A0}, //TVAR_ash_GASAlpha[7] +{0x0F12, 0x011B}, //TVAR_ash_GASAlpha[8] +{0x0F12, 0x0107}, //TVAR_ash_GASAlpha[9] +{0x0F12, 0x0109}, //TVAR_ash_GASAlpha[10] +{0x0F12, 0x00FF}, //TVAR_ash_GASAlpha[11] +{0x0F12, 0x00DB}, //TVAR_ash_GASAlpha[12] +{0x0F12, 0x00FF}, //TVAR_ash_GASAlpha[13] +{0x0F12, 0x0100}, //TVAR_ash_GASAlpha[14] +{0x0F12, 0x00FB}, //TVAR_ash_GASAlpha[15] +{0x0F12, 0x0100}, //TVAR_ash_GASAlpha[16] +{0x0F12, 0x0103}, //TVAR_ash_GASAlpha[17] +{0x0F12, 0x0101}, //TVAR_ash_GASAlpha[18] +{0x0F12, 0x0100}, //TVAR_ash_GASAlpha[19] +{0x0F12, 0x0110}, //TVAR_ash_GASAlpha[20] +{0x0F12, 0x00FD}, //TVAR_ash_GASAlpha[21] +{0x0F12, 0x00FD}, //TVAR_ash_GASAlpha[22] +{0x0F12, 0x0100}, //TVAR_ash_GASAlpha[23] +{0x0F12, 0x00D4}, //TVAR_ash_GASAlpha[24] +{0x0F12, 0x00FB}, //TVAR_ash_GASAlpha[25] +{0x0F12, 0x00F8}, //TVAR_ash_GASAlpha[26] +{0x0F12, 0x0100}, //TVAR_ash_GASAlpha[27] + +{0x0F12, 0x00F5}, //TVAR_ash_GASOutdoorAlpha[0] +{0x0F12, 0x0103}, //TVAR_ash_GAsOutdoorAlpha[1] +{0x0F12, 0x0101}, //TVAR_ash_GAsOutdoorAlpha[2] +{0x0F12, 0x00E4}, //TVAR_ash_GAsOutdoorAlpha[3] + +{0x002A, 0x075A}, +{0x0F12, 0x0000}, //ash_bParabolicEstimation +{0x0F12, 0x0280}, //ash_uParabolicCenterX +{0x0F12, 0x0200}, //ash_uParabolicCenterY +{0x0F12, 0x000E}, //ash_uParabolicscalingA +{0x0F12, 0x000F}, //ash_uParabolicscalingB + +{0x002A, 0x04C8}, +{0x0F12, 0x0000}, //0000 ////0000 ////0000 ////0000 ////0000 // //0000 //0000 //0000 //SARR_usGammaLutRGBIndoor_0__0_ +{0x0F12, 0x0007}, //0007 ////0007 ////05 ////0005 ////0005 ////000a ////0D // //0005 //0002 //0001 //SARR_usGammaLutRGBIndoor_0__1_ +{0x0F12, 0x000D}, //000D ////000D ////0c ////000c ////000c ////10 ////0016 ////1B // //000C //0004 //0002 //SARR_usGammaLutRGBIndoor_0__2_ +{0x0F12, 0x0013}, //0013 ////0012 ////0010 ////1f ////001f ////30 ////0035 ////3C // //001F //0009 //0004 //SARR_usGammaLutRGBIndoor_0__3_ +{0x0F12, 0x0079}, //0079 ////0079 ////0079 ////75 ////81 ////0081 ////0081 // //0056 //0020 //0070 //SARR_usGammaLutRGBIndoor_0__4_ +{0x0F12, 0x00FE}, //00FE ////00FE ////00FE ////00FE ////00FE // //00CD //00B8 //00df //SARR_usGammaLutRGBIndoor_0__5_ +{0x0F12, 0x0159}, //0159 ////0159 ////0159 ////0159 ////0159 // //013A //0139 //0139 //SARR_usGammaLutRGBIndoor_0__6_ +{0x0F12, 0x01A1}, //01A1 ////01A1 ////01A1 ////01A1 ////01A1 // //018C //0188 //017b //SARR_usGammaLutRGBIndoor_0__7_ +{0x0F12, 0x0210}, //0210 ////0210 ////0210 ////0210 ////0210 // //01FE //01DF //01DF //SARR_usGammaLutRGBIndoor_0__8_ +{0x0F12, 0x0263}, //0263 ////0263 ////0263 ////0263 ////0263 // //0255 //022D //022D //SARR_usGammaLutRGBIndoor_0__9_ +{0x0F12, 0x02D5}, //02D5 ////02D5 ////02D5 ////02D8 ////02D8 // //02D1 //02B5 //02a2 //SARR_usGammaLutRGBIndoor_0__10_ +{0x0F12, 0x0330}, //0330 ////0330 ////0330 ////0338 ////0338 // //0338 //0326 //0300 //SARR_usGammaLutRGBIndoor_0__11_ +{0x0F12, 0x0377}, //0377 ////0378 ////7A ////80 ////0380 ////0384 ////0384 // //0384 //0376 //034c //SARR_usGammaLutRGBIndoor_0__12_ +{0x0F12, 0x03BE}, //00C0 ////03B9 ////03B4 ////03B5 ////03BD ////C0 ////3BC ////03BC // //03BC //03AC //038c //SARR_usGammaLutRGBIndoor_0__13_ +{0x0F12, 0x03F0}, //03ED ////03EC ////EB ////03EA ////E8 ////03EF ////3E8 ////03E8 // //03E8 //03CA //03bc //SARR_usGammaLutRGBIndoor_0__14_ +{0x0F12, 0x0400}, //0400 ////0400 ////0400 ////0400 ////0400 // //0400 //03DE //03e7 //SARR_usGammaLutRGBIndoor_0__15_ + +{0x0F12, 0x0000}, //0000 ////0000 ////0000 ////0000 ////0000 ////0000 ////0000 ////0000 // //0000 // //0000 //0000 //0000 //SARR_usGammaLutRGBIndoor_1__0_ +{0x0F12, 0x0007}, //0007 ////0007 ////0005 ////0005 ////0005 ////0005 ////0005 ////000a ////000D // //0005 //0004 //0001 //SARR_usGammaLutRGBIndoor_1__1_ +{0x0F12, 0x000D}, //000D ////000D ////000c ////000c ////000c ////000c ////0010 ////0016 ////001B // //000C //0008 //0002 //SARR_usGammaLutRGBIndoor_1__2_ +{0x0F12, 0x0013}, //0013 ////0012 ////0012 ////0010 ////0010 ////1f ////001f ////0030 ////0035 ////003C // //001F //0010 //000a //SARR_usGammaLutRGBIndoor_1__3_ +{0x0F12, 0x0079}, //0079 ////0079 ////0079 ////0079 ////0075 ////81 ////0081 ////0081 // //0056 //0035 //0085 //SARR_usGammaLutRGBIndoor_1__4_ +{0x0F12, 0x00FE}, //00FE ////00FE ////00FE ////00FE ////00FE ////00FE ////00FE // //00CD //00C8 //00e1 //SARR_usGammaLutRGBIndoor_1__5_ +{0x0F12, 0x0159}, //0159 ////0159 ////0159 ////0159 ////0159 ////0159 ////0159 // //013A //0139 //0139 //SARR_usGammaLutRGBIndoor_1__6_ +{0x0F12, 0x01A1}, //01A1 ////01A1 ////01A1 ////01A1 ////01A1 ////01A1 ////01A1 // //018C //0188 //017b //SARR_usGammaLutRGBIndoor_1__7_ +{0x0F12, 0x0210}, //0210 ////0210 ////0210 ////0210 ////0210 ////0210 ////0210 // //01FE //01DF //01DF //SARR_usGammaLutRGBIndoor_1__8_ +{0x0F12, 0x0263}, //0263 ////0263 ////0263 ////0263 ////0263 ////0263 ////0263 // //0255 //022D //022D //SARR_usGammaLutRGBIndoor_1__9_ +{0x0F12, 0x02D5}, //02D5 ////02D5 ////02D5 ////02D5 ////02D5 ////02D8 ////02D8 // //02D1 //02B5 //02a2 //SARR_usGammaLutRGBIndoor_1__10_ +{0x0F12, 0x0330}, //0330 ////0330 ////0330 ////0330 ////0330 ////0338 ////0338 // //0338 //0326 //0300 //SARR_usGammaLutRGBIndoor_1__11_ +{0x0F12, 0x0377}, //0377 ////0378 ////037A ////80 ////0380 ////0380 ////0384 ////0384 // //0384 //0376 //034c //SARR_usGammaLutRGBIndoor_1__12_ +{0x0F12, 0x03BE}, //00C0 ////03B9 ////03B4 ////03B4 ////03B5 ////03BD ////C0 ////3BC ////03BC // //03BC //03AC //038c //SARR_usGammaLutRGBIndoor_1__13_ +{0x0F12, 0x03F0}, //03ED ////03EC ////03EB ////03EA ////03E8 ////03EF ////3E8 ////03E8 // //03E8 //03CA //03bc //SARR_usGammaLutRGBIndoor_1__14_ +{0x0F12, 0x0400}, //0400 ////0400 ////0400 ////0400 ////0400 ////0400 ////0400 // //0400 //03DE //03e7 //SARR_usGammaLutRGBIndoor_1__15_ + +{0x0F12, 0x0000}, //0000 ////0000 ////0000 ////0000 ////0000 ////0000 ////0000 ////0000 // //0000 // //0000 //0000 //0000 //SARR_usGammaLutRGBIndoor_2__0_ +{0x0F12, 0x0007}, //0007 ////0007 ////0005 ////0005 ////0005 ////0005 ////0005 ////000a ////000D // //0005 //0004 //0001 //SARR_usGammaLutRGBIndoor_2__1_ +{0x0F12, 0x000D}, //000D ////000D ////000c ////000c ////000c ////000c ////0010 ////0016 ////001B // //000C //0008 //0002 //SARR_usGammaLutRGBIndoor_2__2_ +{0x0F12, 0x0013}, //0013 ////0012 ////0012 ////0010 ////0010 ////1f ////001f ////0030 ////0035 ////003C // //001F //0010 //000a //SARR_usGammaLutRGBIndoor_2__3_ +{0x0F12, 0x0079}, //0079 ////0079 ////0079 ////0079 ////0075 ////81 ////0081 ////0081 // //0056 //0035 //0085 //SARR_usGammaLutRGBIndoor_2__4_ +{0x0F12, 0x00FE}, //00FE ////00FE ////00FE ////00FE ////00FE ////00FE ////00FE // //00CD //00C8 //00e1 //SARR_usGammaLutRGBIndoor_2__5_ +{0x0F12, 0x0159}, //0159 ////0159 ////0159 ////0159 ////0159 ////0159 ////0159 // //013A //0139 //0139 //SARR_usGammaLutRGBIndoor_2__6_ +{0x0F12, 0x01A1}, //01A1 ////01A1 ////01A1 ////01A1 ////01A1 ////01A1 ////01A1 // //018C //0188 //017b //SARR_usGammaLutRGBIndoor_2__7_ +{0x0F12, 0x0210}, //0210 ////0210 ////0210 ////0210 ////0210 ////0210 ////0210 // //01FE //01DF //01DF //SARR_usGammaLutRGBIndoor_2__8_ +{0x0F12, 0x0263}, //0263 ////0263 ////0263 ////0263 ////0263 ////0263 ////0263 // //0255 //022D //022D //SARR_usGammaLutRGBIndoor_2__9_ +{0x0F12, 0x02D5}, //02D5 ////02D5 ////02D5 ////02D5 ////02D5 ////02D8 ////02D8 // //02D1 //02B5 //02a2 //SARR_usGammaLutRGBIndoor_2__10_ +{0x0F12, 0x0330}, //0330 ////0330 ////0330 ////0330 ////0330 ////0338 ////0338 // //0338 //0326 //0300 //SARR_usGammaLutRGBIndoor_2__11_ +{0x0F12, 0x0377}, //0377 ////0378 ////037A ////80 ////0380 ////0380 ////0384 ////0384 // //0384 //0376 //034c //SARR_usGammaLutRGBIndoor_2__12_ +{0x0F12, 0x03BE}, //00C0 ////03B9 ////03B4 ////03B4 ////03B5 ////03BD ////C0 ////3BC ////03BC // //03BC //03AC //038c //SARR_usGammaLutRGBIndoor_2__13_ +{0x0F12, 0x03F0}, //03ED ////03EC ////03EB ////03EA ////03E8 ////03EF ////3E8 ////03E8 // //03E8 //03CA //03bc //SARR_usGammaLutRGBIndoor_2__14_ +{0x0F12, 0x0400}, //0400 ////0400 ////0400 ////0400 ////0400 ////0400 ////0400 // //0400 //03DE //03e7 //SARR_usGammaLutRGBIndoor_2__15_ + + +//================================================================ +// AWB +//================================================================ +{0x002A, 0x0C50}, //awbb_IndoorGrZones_m_BGrid +{0x0F12, 0x03B8}, //03B8 //awbb_IndoorGrZones_m_Bgrid[0] 70000C50 +{0x0F12, 0x03C8}, //03C8 //awbb_IndoorGrZones_m_Bgrid[0] +{0x0F12, 0x0384}, //0384 //awbb_IndoorGrZones_m_Bgrid[1] +{0x0F12, 0x03D0}, //03D0 //awbb_IndoorGrZones_m_Bgrid[1] +{0x0F12, 0x035E}, //035E //awbb_IndoorGrZones_m_Bgrid[2] +{0x0F12, 0x03CC}, //03CC //awbb_IndoorGrZones_m_Bgrid[2] +{0x0F12, 0x033E}, //033E //awbb_IndoorGrZones_m_Bgrid[3] +{0x0F12, 0x03B2}, //03B2 //awbb_IndoorGrZones_m_Bgrid[3] +{0x0F12, 0x0322}, //0322 //awbb_IndoorGrZones_m_Bgrid[4] +{0x0F12, 0x0396}, //0396 //awbb_IndoorGrZones_m_Bgrid[4] +{0x0F12, 0x030C}, //030C //awbb_IndoorGrZones_m_Bgrid[5] +{0x0F12, 0x0380}, //0380 //awbb_IndoorGrZones_m_Bgrid[5] +{0x0F12, 0x02F8}, //02F8 //awbb_IndoorGrZones_m_Bgrid[6] +{0x0F12, 0x0368}, //0368 //awbb_IndoorGrZones_m_Bgrid[6] +{0x0F12, 0x02DC}, //02DC //awbb_IndoorGrZones_m_Bgrid[7] +{0x0F12, 0x0352}, //034A //awbb_IndoorGrZones_m_Bgrid[7] +{0x0F12, 0x02C2}, //02C2 //awbb_IndoorGrZones_m_Bgrid[8] +{0x0F12, 0x033C}, //0336 //awbb_IndoorGrZones_m_Bgrid[8] +{0x0F12, 0x02AE}, //02AE //awbb_IndoorGrZones_m_Bgrid[9] +{0x0F12, 0x032A}, //031E //awbb_IndoorGrZones_m_Bgrid[9] +{0x0F12, 0x029A}, //029A //awbb_IndoorGrZones_m_Bgrid[10] +{0x0F12, 0x031C}, //0306 //awbb_IndoorGrZones_m_Bgrid[10] +{0x0F12, 0x028C}, //028C //awbb_IndoorGrZones_m_Bgrid[11] +{0x0F12, 0x030A}, //02F4 //awbb_IndoorGrZones_m_Bgrid[11] +{0x0F12, 0x027C}, //027C //awbb_IndoorGrZones_m_Bgrid[12] +{0x0F12, 0x02FC}, //02DC //awbb_IndoorGrZones_m_Bgrid[12] +{0x0F12, 0x0264}, //0264 //awbb_IndoorGrZones_m_Bgrid[13] +{0x0F12, 0x02EC}, //02C2 //awbb_IndoorGrZones_m_Bgrid[13] +{0x0F12, 0x0252}, //0252 //awbb_IndoorGrZones_m_Bgrid[14] +{0x0F12, 0x02DE}, //02AE //awbb_IndoorGrZones_m_Bgrid[14] +{0x0F12, 0x0246}, //0246 //awbb_IndoorGrZones_m_Bgrid[15] +{0x0F12, 0x02CC}, //029C //awbb_IndoorGrZones_m_Bgrid[15] +{0x0F12, 0x023C}, //023C //awbb_IndoorGrZones_m_Bgrid[16] +{0x0F12, 0x02C2}, //028A //awbb_IndoorGrZones_m_Bgrid[16] +{0x0F12, 0x022E}, //022E //awbb_IndoorGrZones_m_Bgrid[17] +{0x0F12, 0x02B4}, //027E //awbb_IndoorGrZones_m_Bgrid[17] +{0x0F12, 0x0222}, //0222 //awbb_IndoorGrZones_m_Bgrid[18] +{0x0F12, 0x02A8}, //0272 //awbb_IndoorGrZones_m_Bgrid[18] +{0x0F12, 0x0212}, //0212 //awbb_IndoorGrZones_m_Bgrid[19] +{0x0F12, 0x029C}, //0266 //awbb_IndoorGrZones_m_Bgrid[19] +{0x0F12, 0x0202}, //0202 //awbb_IndoorGrZones_m_Bgrid[20] +{0x0F12, 0x0292}, //025A //awbb_IndoorGrZones_m_Bgrid[20] +{0x0F12, 0x01FA}, //01FA //awbb_IndoorGrZones_m_Bgrid[21] +{0x0F12, 0x0288}, //0250 //awbb_IndoorGrZones_m_Bgrid[21] +{0x0F12, 0x01EC}, //01EC //awbb_IndoorGrZones_m_Bgrid[22] +{0x0F12, 0x027E}, //0246 //awbb_IndoorGrZones_m_Bgrid[22] +{0x0F12, 0x01E6}, //01E6 //awbb_IndoorGrZones_m_Bgrid[23] +{0x0F12, 0x0272}, //023C //awbb_IndoorGrZones_m_Bgrid[23] +{0x0F12, 0x01DC}, //01DC //awbb_IndoorGrZones_m_Bgrid[24] +{0x0F12, 0x0264}, //0234 //awbb_IndoorGrZones_m_Bgrid[24] +{0x0F12, 0x01D4}, //01D4 //awbb_IndoorGrZones_m_Bgrid[25] +{0x0F12, 0x0256}, //0228 //awbb_IndoorGrZones_m_Bgrid[25] +{0x0F12, 0x01CE}, //01CE //awbb_IndoorGrZones_m_Bgrid[26] +{0x0F12, 0x0248}, //0220 //awbb_IndoorGrZones_m_Bgrid[26] +{0x0F12, 0x01C6}, //01C6 //awbb_IndoorGrZones_m_Bgrid[27] +{0x0F12, 0x023E}, //0216 //awbb_IndoorGrZones_m_Bgrid[27] +{0x0F12, 0x01C0}, //01C0 //awbb_IndoorGrZones_m_Bgrid[28] +{0x0F12, 0x022E}, //020C //awbb_IndoorGrZones_m_Bgrid[28] +{0x0F12, 0x01BE}, //01BE //awbb_IndoorGrZones_m_Bgrid[29] +{0x0F12, 0x0222}, //01FC //awbb_IndoorGrZones_m_Bgrid[29] +{0x0F12, 0x01C4}, //01C4 //awbb_IndoorGrZones_m_Bgrid[30] +{0x0F12, 0x020E}, //01EE //awbb_IndoorGrZones_m_Bgrid[30] +{0x0F12, 0x01D0}, //01D0 //awbb_IndoorGrZones_m_Bgrid[31] +{0x0F12, 0x01E0}, //01E0 //awbb_IndoorGrZones_m_Bgrid[31] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[32] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[32] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[33] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[33] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[34] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[34] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[35] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[35] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[36] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[36] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[37] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[37] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[38] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[38] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[39] +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Bgrid[39] + +{0x0F12, 0x0004}, //awbb_IndoorGrZones_m_GridStep +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_GridSz + +{0x002A, 0x0CF8}, +{0x0F12, 0x010F}, //awbb_IndoorGrZones_m_Boffs +{0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Boffs + +{0x002A, 0x0D84}, //awbb_LowBrGrZones_m_BGrid +{0x0F12, 0x0406}, //awbb_LowBrGrZones_m_BGrid[0] +{0x0F12, 0x0467}, //awbb_LowBrGrZones_m_BGrid[0] +{0x0F12, 0x0371}, //awbb_LowBrGrZones_m_BGrid[1] +{0x0F12, 0x04B0}, //awbb_LowBrGrZones_m_BGrid[1] +{0x0F12, 0x02E5}, //awbb_LowBrGrZones_m_BGrid[2] +{0x0F12, 0x0481}, //awbb_LowBrGrZones_m_BGrid[2] +{0x0F12, 0x0298}, //awbb_LowBrGrZones_m_BGrid[3] +{0x0F12, 0x042E}, //awbb_LowBrGrZones_m_BGrid[3] +{0x0F12, 0x0260}, //awbb_LowBrGrZones_m_BGrid[4] +{0x0F12, 0x03DE}, //awbb_LowBrGrZones_m_BGrid[4] +{0x0F12, 0x022F}, //awbb_LowBrGrZones_m_BGrid[5] +{0x0F12, 0x0391}, //awbb_LowBrGrZones_m_BGrid[5] +{0x0F12, 0x0201}, //awbb_LowBrGrZones_m_BGrid[6] +{0x0F12, 0x034D}, //awbb_LowBrGrZones_m_BGrid[6] +{0x0F12, 0x01DA}, //awbb_LowBrGrZones_m_BGrid[7] +{0x0F12, 0x0310}, //awbb_LowBrGrZones_m_BGrid[7] +{0x0F12, 0x01B3}, //awbb_LowBrGrZones_m_BGrid[8] +{0x0F12, 0x02D4}, //awbb_LowBrGrZones_m_BGrid[8] +{0x0F12, 0x018F}, //awbb_LowBrGrZones_m_BGrid[9] +{0x0F12, 0x0297}, //awbb_LowBrGrZones_m_BGrid[9] +{0x0F12, 0x0181}, //awbb_LowBrGrZones_m_BGrid[10] +{0x0F12, 0x0271}, //awbb_LowBrGrZones_m_BGrid[10] +{0x0F12, 0x0181}, //awbb_LowBrGrZones_m_BGrid[11] +{0x0F12, 0x022A}, //awbb_LowBrGrZones_m_BGrid[11] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[12] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[12] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[13] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[13] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[14] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[14] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[15] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[15] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[16] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[16] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[17] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[17] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[18] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[18] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[19] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[19] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[20] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[20] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[21] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[21] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[22] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[22] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[23] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[23] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[24] +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[24] + +{0x0F12, 0x0006}, //awbb_LowBrGrZones_m_GridStep +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_GridSz + +{0x002A, 0x0DF0}, +{0x0F12, 0x0081}, //awbb_LowBrGrZones_m_Boffs +{0x0F12, 0x0000}, //awbb_LowBrGrZones_m_Boffs + +{0x002A, 0x0D08}, +{0x0F12, 0x026A}, //0264 //0250 //awbb_OutdoorGrZones_m_BGrid[0] +{0x0F12, 0x0280}, //0274 //0260 //awbb_OutdoorGrZones_m_BGrid[1] +{0x0F12, 0x025E}, //0259 //0245 //awbb_OutdoorGrZones_m_BGrid[2] +{0x0F12, 0x028C}, //027F //026B //awbb_OutdoorGrZones_m_BGrid[3] +{0x0F12, 0x0250}, //024E //023A //awbb_OutdoorGrZones_m_BGrid[4] +{0x0F12, 0x0290}, //0281 //026D //awbb_OutdoorGrZones_m_BGrid[5] +{0x0F12, 0x0246}, //0244 //0230 //awbb_OutdoorGrZones_m_BGrid[6] +{0x0F12, 0x0290}, //0283 //026F //awbb_OutdoorGrZones_m_BGrid[7] +{0x0F12, 0x023C}, //023A //0226 //awbb_OutdoorGrZones_m_BGrid[8] +{0x0F12, 0x0290}, //0283 //026F //awbb_OutdoorGrZones_m_BGrid[9] +{0x0F12, 0x0234}, //0235 //0221 //awbb_OutdoorGrZones_m_BGrid[10] +{0x0F12, 0x028E}, //027E //026A //awbb_OutdoorGrZones_m_BGrid[11] +{0x0F12, 0x022A}, //0231 //021D //awbb_OutdoorGrZones_m_BGrid[12] +{0x0F12, 0x028C}, //0278 //0264 //awbb_OutdoorGrZones_m_BGrid[13] +{0x0F12, 0x021E}, //022B //0217 //awbb_OutdoorGrZones_m_BGrid[14] +{0x0F12, 0x0286}, //0274 //0260 //awbb_OutdoorGrZones_m_BGrid[15] +{0x0F12, 0x0214}, //0224 //0210 //awbb_OutdoorGrZones_m_BGrid[16] +{0x0F12, 0x0280}, //026D //0259 //awbb_OutdoorGrZones_m_BGrid[17] +{0x0F12, 0x020E}, //021E //020A //awbb_OutdoorGrZones_m_BGrid[18] +{0x0F12, 0x0278}, //0265 //0251 //awbb_OutdoorGrZones_m_BGrid[19] +{0x0F12, 0x020A}, //0218 //0204 //awbb_OutdoorGrZones_m_BGrid[20] +{0x0F12, 0x0272}, //025F //024B //awbb_OutdoorGrZones_m_BGrid[21] +{0x0F12, 0x0204}, //0211 //01FD //awbb_OutdoorGrZones_m_BGrid[22] +{0x0F12, 0x026C}, //0259 //0245 //awbb_OutdoorGrZones_m_BGrid[23] +{0x0F12, 0x0200}, //020A //01F6 //awbb_OutdoorGrZones_m_BGrid[24] +{0x0F12, 0x0264}, //0252 //023E //awbb_OutdoorGrZones_m_BGrid[25] +{0x0F12, 0x01FE}, //0207 //01F1 //awbb_OutdoorGrZones_m_BGrid[26] +{0x0F12, 0x025E}, //0239 //0238 //awbb_OutdoorGrZones_m_BGrid[27] +{0x0F12, 0x01FE}, //0204 //01EC //awbb_OutdoorGrZones_m_BGrid[28] +{0x0F12, 0x0258}, //0224 //022F //awbb_OutdoorGrZones_m_BGrid[29] +{0x0F12, 0x01FE}, //0000 //01E9 //awbb_OutdoorGrZones_m_BGrid[30] +{0x0F12, 0x0252}, //0000 //0219 //awbb_OutdoorGrZones_m_BGrid[31] +{0x0F12, 0x0200}, //0000 //01EF //awbb_OutdoorGrZones_m_BGrid[32] +{0x0F12, 0x0238}, //0000 //01F8 //awbb_OutdoorGrZones_m_BGrid[33] +{0x0F12, 0x0204}, //0000 //awbb_OutdoorGrZones_m_BGrid[34] +{0x0F12, 0x0224}, //0000 //awbb_OutdoorGrZones_m_BGrid[35] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[36] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[37] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[38] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[39] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[40] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[41] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[42] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[43] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[44] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[45] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[46] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[47] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[48] +{0x0F12, 0x0000}, //0000 //awbb_OutdoorGrZones_m_BGrid[49] +{0x0F12, 0x0003}, //0003 /awbb_OutdoorGrZones_m_Gridstep +{0x0F12, 0x0000}, //0000 + +{0x002A, 0x0D70}, +{0x0F12, 0x0011}, //awbb_OutdoorGrZones_m_GridSz +{0x0F12, 0x0000}, + +{0x002A, 0x0D74}, +{0x0F12, 0x020E}, //021F //2F //awbb_OutdoorGrZones_m_Boffs Don't modify +{0x0F12, 0x0000}, +{0x002A, 0x0E00}, +{0x0F12, 0x034A}, //awbb_CrclLowT_R_c +{0x0F12, 0x0000}, +{0x0F12, 0x0176}, //awbb_CrclLowT_B_c +{0x0F12, 0x0000}, +{0x0F12, 0x71B8}, //awbb_CrclLowT_Rad_c +{0x0F12, 0x0000}, +{0x002A, 0x0E1A}, +{0x0F12, 0x012F}, +{0x0F12, 0x0120}, +{0x002A, 0x0E68}, +{0x0F12, 0x04F2}, // awbb_LowTempRB +{0x002A, 0x0D78}, +{0x0F12, 0x0020}, //AWB min. +{0x002A, 0x0D80}, +{0x0F12, 0x00E0}, //AWB Max. +{0x002A, 0x0E40}, //awbb_Use_Filters +{0x0F12, 0x0061}, //AWB option +{0x002A, 0x0EE4}, +{0x0F12, 0x0003}, //awbb_OutdoorFltrsz +{0x002A, 0x0E3C}, +{0x0F12, 0x0001}, //awbb_Use_InvalidOutDoor +{0x002A, 0x0F3A}, +{0x0F12, 0x024C}, //awbb_OutdoorWP_r //0240 //0218 // 0226 +{0x0F12, 0x0290}, //awbb_OutdoorWP_b //2B2 // 0280 + +{0x002A, 0x0E46}, +{0x0F12, 0x0BB7}, //FA0 //awbb_sunnyBr +{0x0F12, 0x0096}, //awbb_sunny_NBzone +{0x0F12, 0x0BB8}, //awbb_CloudyBr + +{0x002A, 0x0E5E}, +{0x0F12, 0x071A}, //awbb_GamutWidthThr1 +{0x0F12, 0x03A4}, + +{0x002A, 0x0E50}, +{0x0F12, 0x001B}, //awbb_MacbethGamut_WidthZone +{0x0F12, 0x000E}, +{0x0F12, 0x0008}, +{0x0F12, 0x0004}, + +{0x002A, 0x0E36}, +{0x0F12, 0x0001}, //awbb_ByPass_LowTempMode + +{0x002A, 0x0E18}, +{0x0F12, 0x0000}, // 32 awbb_dark + +{0x002A, 0x0E3A}, +{0x0F12, 0x02C2}, //awbb_Alpha_Comp_Mode +{0x002A, 0x0F12}, +{0x0F12, 0x02C9}, //awbb_GLocusR +{0x0F12, 0x033F}, //awbb_GLocusB +{0x002A, 0x0E1A}, +{0x0F12, 0x0138}, //awbb_IntcR + +{0x002A, 0x236C}, +{0x0F12, 0x0000}, //AWBBTune_EVT4_uInitPostToleranceCnt + + +{0x002A, 0x0C48}, //awbb_GainsInit +{0x0F12, 0x053C}, //R Gain +{0x0F12, 0x03B0}, //400 +{0x0F12, 0x055C}, //B Gain + + +//================================================================ +// Grid Correction +//================================================================ +{0x002A, 0x0E42}, +{0x0F12, 0x0002}, +{0x002A, 0x0EE0}, +{0x0F12, 0x00B5}, //awbb_GridCoeff_R_2 +{0x0F12, 0x00B5}, //awbb_GridCoeff_B_2 +{0x002A, 0x0ED0}, +{0x0F12, 0x0EC8}, //awbb_GridConst_2[0] +{0x0F12, 0x1022}, //awbb_GridConst_2[1] +{0x0F12, 0x10BB}, //awbb_GridConst_2[2] +{0x0F12, 0x10C9}, //awbb_GridConst_2[3] +{0x0F12, 0x1149}, //awbb_GridConst_2[4] +{0x0F12, 0x11FD}, //awbb_GridConst_2[5] +{0x0F12, 0x00B8}, //awbb_GridCoeff_R_1 +{0x0F12, 0x00B2}, //awbb_GridCoeff_B_1 +{0x002A, 0x0ECA}, +{0x0F12, 0x029A}, //awbb_GridConst_1[0] +{0x0F12, 0x0344}, //awbb_GridConst_1[1] +{0x0F12, 0x03FB}, //awbb_GridConst_1[2] +{0x002A, 0x0E82}, +{0x0F12, 0xFFE0}, //awbb_GridCorr_R[0][0] //d65 +{0x0F12, 0x0000}, //awbb_GridCorr_R[0][1] //d50 +{0x0F12, 0x0004}, //awbb_GridCorr_R[0][2] //cw +{0x0F12, 0x0004}, //awbb_GridCorr_R[0][3] //ww +{0x0F12, 0x0010}, //awbb_GridCorr_R[0][4] //a +{0x0F12, 0x007D}, //awbb_GridCorr_R[0][5] //h +{0x0F12, 0xFFE0}, //awbb_GridCorr_R[1][0] //d65 +{0x0F12, 0x0000}, //awbb_GridCorr_R[1][1] //d50 +{0x0F12, 0x0004}, //awbb_GridCorr_R[1][2] //cw +{0x0F12, 0x0004}, //awbb_GridCorr_R[1][3] //ww +{0x0F12, 0x0010}, //awbb_GridCorr_R[1][4] //a +{0x0F12, 0x007D}, //awbb_GridCorr_R[1][5] //h +{0x0F12, 0xFFE0}, //awbb_GridCorr_R[2][0] //d65 +{0x0F12, 0x0000}, //awbb_GridCorr_R[2][1] //d50 +{0x0F12, 0x0004}, //awbb_GridCorr_R[2][2] //cw +{0x0F12, 0x0004}, //awbb_GridCorr_R[2][3] //ww +{0x0F12, 0x0010}, //awbb_GridCorr_R[2][4] //a +{0x0F12, 0x007D}, //awbb_GridCorr_R[2][5] //h + +{0x0F12, 0x0010}, //awbb_GridCorr_B[0][0] //d65 +{0x0F12, 0x0010}, //awbb_GridCorr_B[0][1] //d50 +{0x0F12, 0x0010}, //awbb_GridCorr_B[0][2] //cw +{0x0F12, 0x0000}, //awbb_GridCorr_B[0][3] //ww +{0x0F12, 0xFF7D}, //awbb_GridCorr_B[0][4] //a +{0x0F12, 0xFDE7}, //awbb_GridCorr_B[0][5] //h +{0x0F12, 0x0010}, //awbb_GridCorr_B[1][0] //d65 +{0x0F12, 0x0010}, //awbb_GridCorr_B[1][1] //d50 +{0x0F12, 0x0010}, //awbb_GridCorr_B[1][2] //cw +{0x0F12, 0x0000}, //awbb_GridCorr_B[1][3] //ww +{0x0F12, 0xFF7D}, //awbb_GridCorr_B[1][4] //a +{0x0F12, 0xFDE7}, //awbb_GridCorr_B[0][5] //h +{0x0F12, 0x0010}, //awbb_GridCorr_B[2][0] //d65 +{0x0F12, 0x0010}, //awbb_GridCorr_B[2][1] //d50 +{0x0F12, 0x0010}, //awbb_GridCorr_B[2][2] //cw +{0x0F12, 0x0000}, //awbb_GridCorr_B[2][3] //ww +{0x0F12, 0xFF7D}, //awbb_GridCorr_B[2][4] //a +{0x0F12, 0xFDE7}, //awbb_GridCorr_B[0][5] //h + + +//================================================================ +// CCM +//================================================================ +{0x002A, 0x06D4}, +{0x0F12, 0x2380}, //TVAR_wbt_pOutdoorCcm +{0x0F12, 0x7000}, +{0x002A, 0x06CC}, +{0x0F12, 0x23A4}, //TVAR_wbt_pBaseCcms +{0x0F12, 0x7000}, +{0x002A, 0x06E8}, +{0x0F12, 0x23A4}, +{0x0F12, 0x7000}, +{0x0F12, 0x23C8}, +{0x0F12, 0x7000}, +{0x0F12, 0x23EC}, +{0x0F12, 0x7000}, +{0x0F12, 0x2410}, +{0x0F12, 0x7000}, +{0x0F12, 0x2434}, +{0x0F12, 0x7000}, +{0x0F12, 0x2458}, +{0x0F12, 0x7000}, +{0x002A, 0x06DA}, +{0x0F12, 0x00BF}, //SARR_AwbCcmCord[0] 2 700006DA +{0x0F12, 0x00E6}, //SARR_AwbCcmCord[1] 2 700006DC +{0x0F12, 0x00F2}, //SARR_AwbCcmCord[2] 2 700006DE +{0x0F12, 0x0143}, //SARR_AwbCcmCord[3] 2 700006E0 +{0x0F12, 0x0178}, //SARR_AwbCcmCord[4] 2 700006E2 +{0x0F12, 0x01A3}, //SARR_AwbCcmCord[5] +{0x002A, 0x23A4}, +{0x0F12, 0x01FA}, //01FA //H//23A4 +{0x0F12, 0xFFB9}, //FFB9 +{0x0F12, 0xFFF8}, //FFF8 +{0x0F12, 0x0116}, //00EC +{0x0F12, 0x00BD}, //00EB +{0x0F12, 0xFF38}, //FF33 +{0x0F12, 0xFF23}, //FF23 +{0x0F12, 0x01AB}, //01AB +{0x0F12, 0xFF81}, //FF81 +{0x0F12, 0xFF0D}, //FF0D +{0x0F12, 0x0169}, //0169 +{0x0F12, 0x00DE}, //00DE +{0x0F12, 0xFFEF}, //FFEF +{0x0F12, 0xFFCA}, //FFCA +{0x0F12, 0x014D}, //014D +{0x0F12, 0x01C3}, //01C3 +{0x0F12, 0xFF7E}, //FF7E +{0x0F12, 0x016F}, //016F + +{0x0F12, 0x01FA}, //01FA //A//23C8 +{0x0F12, 0xFFB9}, //FFB9 +{0x0F12, 0xFFF8}, //FFF8 +{0x0F12, 0x0116}, //00EC +{0x0F12, 0x00BD}, //00EB +{0x0F12, 0xFF38}, //FF33 +{0x0F12, 0xFF23}, //FF23 +{0x0F12, 0x01AB}, //01AB +{0x0F12, 0xFF81}, //FF81 +{0x0F12, 0xFF0D}, //FF0D +{0x0F12, 0x0169}, //0169 +{0x0F12, 0x00DE}, //00DE +{0x0F12, 0xFFEF}, //FFEF +{0x0F12, 0xFFCA}, //FFCA +{0x0F12, 0x014D}, //014D +{0x0F12, 0x01C3}, //01C3 +{0x0F12, 0xFF7E}, //FF7E +{0x0F12, 0x016F}, //016F + +{0x0F12, 0x01FA}, //01FA //WW//23EC +{0x0F12, 0xFFB9}, //FFB9 +{0x0F12, 0xFFF8}, //FFF8 +{0x0F12, 0x0116}, //00EC +{0x0F12, 0x00BD}, //00EB +{0x0F12, 0xFF38}, //FF33 +{0x0F12, 0xFF23}, //FF23 +{0x0F12, 0x01AB}, //01AB +{0x0F12, 0xFF81}, //FF81 +{0x0F12, 0xFF0D}, //FF0D +{0x0F12, 0x0169}, //0169 +{0x0F12, 0x00DE}, //00DE +{0x0F12, 0xFFEF}, //FFEF +{0x0F12, 0xFFCA}, //FFCA +{0x0F12, 0x014D}, //014D +{0x0F12, 0x01C3}, //01C3 +{0x0F12, 0xFF7E}, //FF7E +{0x0F12, 0x016F}, //016F + +{0x0F12, 0x01B1}, //01B6 ////0198 ////01D6 ////01E0 ////01B7 //CW//2410 +{0x0F12, 0xFFCD}, //FFDE ////FFF1 ////FFBD ////FFB9 ////FFD0 +{0x0F12, 0x0016}, //0003 ////0012 ////000D ////000C ////0019 +{0x0F12, 0x00E6}, //00C5 +{0x0F12, 0x00D6}, //00E3 +{0x0F12, 0xFF4A}, //FF5D +{0x0F12, 0xFF33}, //FF3E +{0x0F12, 0x019C}, //0186 +{0x0F12, 0xFF85}, //FF8C +{0x0F12, 0xFF0E}, //FF0E +{0x0F12, 0x016A}, //016A +{0x0F12, 0x00DF}, //00DF +{0x0F12, 0xFFEE}, //FFEE +{0x0F12, 0xFFC9}, //FFC9 +{0x0F12, 0x014C}, //014C +{0x0F12, 0x01C1}, //01C1 +{0x0F12, 0xFF7C}, //FF7C +{0x0F12, 0x016D}, //016D + +{0x0F12, 0x01B4}, //01B6 ////01AC ////0198 ////01D6 ////01E2 ////01E0 ////01B7 //D50//2434 +{0x0F12, 0xFFD4}, //FFDE ////FFE4 ////FFF1 ////FFBD ////FFB8 ////FFB9 ////FFD0 +{0x0F12, 0x000C}, //0003 ////0008 ////0012 ////000D ////000B ////000C ////0019 +{0x0F12, 0x00CB}, //00CB ////00C5 +{0x0F12, 0x00F3}, //00F3 ////00E3 +{0x0F12, 0xFF4C}, //FF4C ////FF5D +{0x0F12, 0xFF66}, //ff20 ////FF33 ////FF3E +{0x0F12, 0x01AB}, //01bb ////019C ////0186 +{0x0F12, 0xFF43}, //ff79 ////FF85 ////FF8C +{0x0F12, 0xFF0E}, //FF0E ////FF0E +{0x0F12, 0x016A}, //016A ////016A +{0x0F12, 0x00DF}, //00DF ////00DF +{0x0F12, 0xFFE8}, //FFEE ////FFEE +{0x0F12, 0xFFC1}, //FFC9 ////FFC9 +{0x0F12, 0x015A}, //014C ////014C +{0x0F12, 0x01C1}, //01C1 ////01C1 +{0x0F12, 0xFF7C}, //FF7C ////FF7C +{0x0F12, 0x016D}, //016D ////016D + +{0x0F12, 0x01E6}, //01E6 +{0x0F12, 0xFFB7}, //FFB7 +{0x0F12, 0xFFE2}, //FFE2 + +{0x0F12, 0x00CC}, //00CC +{0x0F12, 0x00F4}, //00F4 +{0x0F12, 0xFF4D}, //FF4D + +{0x0F12, 0xFF1E}, //FF46 +{0x0F12, 0x01E6}, //01D2 +{0x0F12, 0xFF2C}, //FF1C + +{0x0F12, 0xFF09}, //FF09 +{0x0F12, 0x0164}, //0164 +{0x0F12, 0x00DA}, //00DA + +{0x0F12, 0xFFD8}, //FFD8 +{0x0F12, 0xFFB2}, //FFB2 +{0x0F12, 0x014B}, //014B + +{0x0F12, 0x01B4}, //01B4 +{0x0F12, 0xFF6E}, //FF6E +{0x0F12, 0x0160}, //0160 + +{0x002A, 0x2380}, //TVAR_wbt_pOutdoorCcm +{0x0F12, 0x01AE}, //01AA //01B9 //01DD //TVAR_wbt_pOutdoorCcm[0] ߿ܾ󱼻 ϴ +{0x0F12, 0xFFB9}, //FFB9 //FFBC //FFA8 //TVAR_wbt_pOutdoorCcm[1] +{0x0F12, 0x0017}, //001E //0012 //0008 //TVAR_wbt_pOutdoorCcm[2] +{0x0F12, 0x00FC}, //00FB //00FD //TVAR_wbt_pOutdoorCcm[3] +{0x0F12, 0x013B}, //013B //0141 //TVAR_wbt_pOutdoorCcm[4] +{0x0F12, 0xFF84}, //FF82 //FF74 //TVAR_wbt_pOutdoorCcm[5] +{0x0F12, 0xFED9}, //FED6 //FEC6 //TVAR_wbt_pOutdoorCcm[6] +{0x0F12, 0x01E6}, //01E6 //01F6 //TVAR_wbt_pOutdoorCcm[7] +{0x0F12, 0xFF16}, //FF13 //FF05 //TVAR_wbt_pOutdoorCcm[8] +{0x0F12, 0xFF4A}, //FF48 //FF38 //TVAR_wbt_pOutdoorCcm[9] +{0x0F12, 0x0179}, //0179 //017F //TVAR_wbt_pOutdoorCcm[10] +{0x0F12, 0x014F}, //014F //0153 //TVAR_wbt_pOutdoorCcm[11] +{0x0F12, 0xFFC2}, //FFCB //FFCC //TVAR_wbt_pOutdoorCcm[12] +{0x0F12, 0xFF99}, //FFA4 //FFA6 //TVAR_wbt_pOutdoorCcm[13] +{0x0F12, 0x0219}, //0207 //020A //TVAR_wbt_pOutdoorCcm[14] +{0x0F12, 0x0172}, //0174 //017E //TVAR_wbt_pOutdoorCcm[15] +{0x0F12, 0xFF51}, //FF51 //FF45 //TVAR_wbt_pOutdoorCcm[16] +{0x0F12, 0x019B}, //019E //01AA //TVAR_wbt_pOutdoorCcm[17] + +//================================================================ +// AFIT +//================================================================ +{0x002A, 0x07E8}, //SARR_uNormBrInDoor +{0x0F12, 0x0016}, //000A //SARR_uNormBrInDoor[0] +{0x0F12, 0x0028}, //0019 //SARR_uNormBrInDoor[1] +{0x0F12, 0x0096}, //0096 //SARR_uNormBrInDoor[2] +{0x0F12, 0x01F4}, //01F4 //SARR_uNormBrInDoor[3] +{0x0F12, 0x07D0}, //07D0 //SARR_uNormBrInDoor[4] +{0x002A, 0x07D0}, //afit_uNoiseIndInDoor +{0x0F12, 0x0030}, //afit_uNoiseIndInDoor[0] +{0x0F12, 0x0046}, //afit_uNoiseIndInDoor[1] +{0x0F12, 0x0088}, //afit_uNoiseIndInDoor[2] +{0x0F12, 0x0205}, //afit_uNoiseIndInDoor[3] +{0x0F12, 0x02BC}, //afit_uNoiseIndInDoor[4] +{0x002A, 0x07E6}, +{0x0F12, 0x0000}, //afit_bUseNoiseInd +{0x002A, 0x0828}, +{0x0F12, 0x0008}, //10 //TVAR_afit_pBaseVals[0] 70000828 //BRIGHTNESS +{0x0F12, 0x0014}, //TVAR_afit_pBaseVals[1] 7000082A //CONTRAST +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[2] 7000082C //SATURATION +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[3] 7000082E //SHARP_BLUR +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[4] 70000830 //GLAMOUR +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[5] 70000832 //Disparity_iSatSat +{0x0F12, 0x0021}, //TVAR_afit_pBaseVals[6] 70000834 //Denoise1_iYDenThreshLow +{0x0F12, 0x0028}, //TVAR_afit_pBaseVals[7] 70000836 //Denoise1_iYDenThreshLow_Bin +{0x0F12, 0x0050}, //TVAR_afit_pBaseVals[8] 70000838 //Denoise1_iYDenThreshHigh +{0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[9] 7000083A //Denoise1_iYDenThreshHigh_Bin +{0x0F12, 0x0129}, //TVAR_afit_pBaseVals[10] 7000083C //Denoise1_iLowWWideThresh +{0x0F12, 0x000A}, //TVAR_afit_pBaseVals[11] 7000083E //Denoise1_iHighWWideThresh +{0x0F12, 0x0028}, //TVAR_afit_pBaseVals[12] 70000840 //Denoise1_iLowWideThresh +{0x0F12, 0x0028}, //TVAR_afit_pBaseVals[13] 70000842 //Denoise1_iHighWideThresh +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[14] 70000844 //Denoise1_iSatSat +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[15] 70000846 //Demosaic4_iHystGrayLow +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[16] 70000848 //Demosaic4_iHystGrayHigh +{0x0F12, 0x0344}, //TVAR_afit_pBaseVals[17] 7000084A //UVDenoise_iYLowThresh +{0x0F12, 0x033A}, //TVAR_afit_pBaseVals[18] 7000084C //UVDenoise_iYHighThresh +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[19] 7000084E //UVDenoise_iUVLowThresh +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[20] 70000850 //UVDenoise_iUVHighThresh +{0x0F12, 0x000A}, //TVAR_afit_pBaseVals[21] 70000852 //DSMix1_iLowLimit_Wide +{0x0F12, 0x0032}, //TVAR_afit_pBaseVals[22] 70000854 //DSMix1_iLowLimit_Wide_Bin +{0x0F12, 0x001E}, //TVAR_afit_pBaseVals[23] 70000856 //DSMix1_iHighLimit_Wide +{0x0F12, 0x0032}, //TVAR_afit_pBaseVals[24] 70000858 //DSMix1_iHighLimit_Wide_Bin +{0x0F12, 0x0032}, //TVAR_afit_pBaseVals[25] 7000085A //DSMix1_iLowLimit_Fine +{0x0F12, 0x0032}, //TVAR_afit_pBaseVals[26] 7000085C //DSMix1_iLowLimit_Fine_Bin +{0x0F12, 0x0010}, //TVAR_afit_pBaseVals[27] 7000085E //DSMix1_iHighLimit_Fine +{0x0F12, 0x0032}, //TVAR_afit_pBaseVals[28] 70000860 //DSMix1_iHighLimit_Fine_Bin +{0x0F12, 0x0106}, //TVAR_afit_pBaseVals[29] 70000862 //DSMix1_iRGBOffset +{0x0F12, 0x006F}, //TVAR_afit_pBaseVals[30] 70000864 //DSMix1_iDemClamp +{0x0F12, 0x0C0F}, //TVAR_afit_pBaseVals[31] 70000866 //"Disparity_iDispTH_LowDisparity_iDispTH_Low_Bin" +{0x0F12, 0x0C0F}, //TVAR_afit_pBaseVals[32] 70000868 //"Disparity_iDispTH_High Disparity_iDispTH_High_Bin" +{0x0F12, 0x0303}, //TVAR_afit_pBaseVals[33] 7000086A //"Despeckle_iCorrectionLevelColdDespeckle_iCorrectionLevelCold_Bin" +{0x0F12, 0x0303}, //TVAR_afit_pBaseVals[34] 7000086C //Despeckle_iCorrectionLevelHotDespeckle_iCorrectionLevelHot_Bin +{0x0F12, 0x140A}, //TVAR_afit_pBaseVals[35] 7000086E //"Despeckle_iColdThreshLowDespeckle_iColdThreshHigh" +{0x0F12, 0x140A}, //TVAR_afit_pBaseVals[36] 70000870 //"Despeckle_iHotThreshLowDespeckle_iHotThreshHigh" +{0x0F12, 0x2828}, //TVAR_afit_pBaseVals[37] 70000872 //"Denoise1_iLowMaxSlopeAllowedDenoise1_iHighMaxSlopeAllowed" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[38] 70000874 //"Denoise1_iLowSlopeThreshDenoise1_iHighSlopeThresh" +{0x0F12, 0x020A}, //TVAR_afit_pBaseVals[39] 70000876 //"Denoise1_iRadialPowerDenoise1_iRadialDivideShift" +{0x0F12, 0x0480}, //TVAR_afit_pBaseVals[40] 70000878 //"Denoise1_iRadialLimitDenoise1_iLWBNoise" +{0x0F12, 0x0E08}, //TVAR_afit_pBaseVals[41] 7000087A //"Denoise1_iWideDenoise1_iWideWide" +{0x0F12, 0x030A}, //TVAR_afit_pBaseVals[42] 7000087C //"Demosaic4_iHystGrayRangeUVDenoise_iYSupport" +{0x0F12, 0x0A03}, //TVAR_afit_pBaseVals[43] 7000087E //"UVDenoise_iUVSupportDSMix1_iLowPower_Wide" +{0x0F12, 0x0A11}, //TVAR_afit_pBaseVals[44] 70000880 //"DSMix1_iLowPower_Wide_BinDSMix1_iHighPower_Wide" +{0x0F12, 0x000F}, //TVAR_afit_pBaseVals[45] 70000882 //"DSMix1_iHighPower_Wide_BinDSMix1_iLowThresh_Wide" +{0x0F12, 0x0500}, //TVAR_afit_pBaseVals[46] 70000884 //"DSMix1_iHighThresh_WideDSMix1_iReduceNegativeWide" +{0x0F12, 0x0914}, //TVAR_afit_pBaseVals[47] 70000886 //"DSMix1_iLowPower_FineDSMix1_iLowPower_Fine_Bin" +{0x0F12, 0x0012}, //TVAR_afit_pBaseVals[48] 70000888 //"DSMix1_iHighPower_FineDSMix1_iHighPower_Fine_Bin" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[49] 7000088A //"DSMix1_iLowThresh_FineDSMix1_iHighThresh_Fine" +{0x0F12, 0x0005}, //TVAR_afit_pBaseVals[50] 7000088C //"DSMix1_iReduceNegativeFineDSMix1_iRGBMultiplier" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[51] 7000088E //"Mixer1_iNLowNoisePowerMixer1_iNLowNoisePower_Bin" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[52] 70000890 //"Mixer1_iNVeryLowNoisePowerMixer1_iNVeryLowNoisePower_Bin" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[53] 70000892 //"Mixer1_iNHighNoisePowerMixer1_iNHighNoisePower_Bin" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[54] 70000894 //"Mixer1_iWLowNoisePowerMixer1_iWVeryLowNoisePower" +{0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[55] 70000896 //"Mixer1_iWHighNoisePowerMixer1_iWLowNoiseCeilGain" +{0x0F12, 0x000A}, //TVAR_afit_pBaseVals[56] 70000898 //"Mixer1_iWHighNoiseCeilGainMixer1_iWNoiseCeilGain" +{0x0F12, 0x0180}, //014C //TVAR_afit_pBaseVals[57] 7000089A //"CCM_Oscar_iSaturationCCM_Oscar_bSaturation" +{0x0F12, 0x014D}, //TVAR_afit_pBaseVals[58] 7000089C //"RGBGamma2_iLinearityRGBGamma2_bLinearity" +{0x0F12, 0x0100}, //TVAR_afit_pBaseVals[59] 7000089E //"RGBGamma2_iDarkReduceRGBGamma2_bDarkReduce" +{0x0F12, 0x8020}, //TVAR_afit_pBaseVals[60] 700008A0 //"byr_gas2_iShadingPowerRGB2YUV_iRGBGain" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[61] 700008A2 //"RGB2YUV_iSaturationRGB2YUV_bGainOffset" +{0x0F12, 0x0013}, //15 //18 //001a //05 //A //TVAR_afit_pBaseVals[62] 700008A4 //RGB2YUV_iYOffset +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[63] 700008A6 //BRIGHTNESS +{0x0F12, 0x0028}, //TVAR_afit_pBaseVals[64] 700008A8 //CONTRAST +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[65] 700008AA //SATURATION +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[66] 700008AC //SHARP_BLUR +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[67] 700008AE //GLAMOUR +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[68] 700008B0 //Disparity_iSatSat +{0x0F12, 0x000C}, //0E //0C //0020 //TVAR_afit_pBaseVals[69] 700008B2 //Denoise1_iYDenThreshLow +{0x0F12, 0x000E}, //000E //TVAR_afit_pBaseVals[70] 700008B4 //Denoise1_iYDenThreshLow_Bin +{0x0F12, 0x0050}, //0080 //TVAR_afit_pBaseVals[71] 700008B6 //Denoise1_iYDenThreshHigh +{0x0F12, 0x00FF}, //00FF //TVAR_afit_pBaseVals[72] 700008B8 //Denoise1_iYDenThreshHigh_Bin +{0x0F12, 0x0129}, //0129 //TVAR_afit_pBaseVals[73] 700008BA //Denoise1_iLowWWideThresh +{0x0F12, 0x000A}, //000A //TVAR_afit_pBaseVals[74] 700008BC //Denoise1_iHighWWideThresh +{0x0F12, 0x0028}, //0028 //TVAR_afit_pBaseVals[75] 700008BE //Denoise1_iLowWideThresh +{0x0F12, 0x0028}, //0028 //TVAR_afit_pBaseVals[76] 700008C0 //Denoise1_iHighWideThresh +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[77] 700008C2 //Denoise1_iSatSat +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[78] 700008C4 //Demosaic4_iHystGrayLow +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[79] 700008C6 //Demosaic4_iHystGrayHigh +{0x0F12, 0x0114}, //0014 //TVAR_afit_pBaseVals[80] 700008C8 //UVDenoise_iYLowThresh +{0x0F12, 0x020A}, //000A //TVAR_afit_pBaseVals[81] 700008CA //UVDenoise_iYHighThresh +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[82] 700008CC //UVDenoise_iUVLowThresh +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[83] 700008CE //UVDenoise_iUVHighThresh +{0x0F12, 0x0018}, //000a //TVAR_afit_pBaseVals[84] 700008D0 //DSMix1_iLowLimit_Wide +{0x0F12, 0x0032}, //0000 //TVAR_afit_pBaseVals[85] 700008D2 //DSMix1_iLowLimit_Wide_Bin +{0x0F12, 0x000A}, //0014 //TVAR_afit_pBaseVals[86] 700008D4 //DSMix1_iHighLimit_Wide +{0x0F12, 0x0032}, //0032 //TVAR_afit_pBaseVals[87] 700008D6 //DSMix1_iHighLimit_Wide_Bin +{0x0F12, 0x0028}, //0000 //TVAR_afit_pBaseVals[88] 700008D8 //DSMix1_iLowLimit_Fine +{0x0F12, 0x0032}, //0000 //TVAR_afit_pBaseVals[89] 700008DA //DSMix1_iLowLimit_Fine_Bin +{0x0F12, 0x0010}, //00A0 //TVAR_afit_pBaseVals[90] 700008DC //DSMix1_iHighLimit_Fine +{0x0F12, 0x0032}, //0000 //TVAR_afit_pBaseVals[91] 700008DE //DSMix1_iHighLimit_Fine_Bin +{0x0F12, 0x0106}, //0106 //TVAR_afit_pBaseVals[92] 700008E0 //DSMix1_iRGBOffset +{0x0F12, 0x006F}, //006F //TVAR_afit_pBaseVals[93] 700008E2 //DSMix1_iDemClamp +{0x0F12, 0x050F}, //050F //TVAR_afit_pBaseVals[94] 700008E4 //"Disparity_iDispTH_LowDisparity_iDispTH_Low_Bin" +{0x0F12, 0x0A0F}, //0A0F //TVAR_afit_pBaseVals[95] 700008E6 //"Disparity_iDispTH_High Disparity_iDispTH_High_Bin" +{0x0F12, 0x0203}, //0203 //TVAR_afit_pBaseVals[96] 700008E8 //"Despeckle_iCorrectionLevelColdDespeckle_iCorrectionLevelCold_Bin" +{0x0F12, 0x0303}, //0203 //TVAR_afit_pBaseVals[97] 700008EA //Despeckle_iCorrectionLevelHotDespeckle_iCorrectionLevelHot_Bin +{0x0F12, 0x140A}, //140A //TVAR_afit_pBaseVals[98] 700008EC //"Despeckle_iColdThreshLowDespeckle_iColdThreshHigh" +{0x0F12, 0x140A}, //140A //TVAR_afit_pBaseVals[99] 700008EE //"Despeckle_iHotThreshLowDespeckle_iHotThreshHigh" +{0x0F12, 0x2828}, //2828 //TVAR_afit_pBaseVals[100] 700008F0 //"Denoise1_iLowMaxSlopeAllowedDenoise1_iHighMaxSlopeAllowed" +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[101] 700008F2 //"Denoise1_iLowSlopeThreshDenoise1_iHighSlopeThresh" +{0x0F12, 0x020A}, //020A //TVAR_afit_pBaseVals[102] 700008F4 //"Denoise1_iRadialPowerDenoise1_iRadialDivideShift" +{0x0F12, 0x0480}, //0480 //TVAR_afit_pBaseVals[103] 700008F6 //"Denoise1_iRadialLimitDenoise1_iLWBNoise" +{0x0F12, 0x0E08}, //0E08 //TVAR_afit_pBaseVals[104] 700008F8 //"Denoise1_iWideDenoise1_iWideWide" +{0x0F12, 0x030A}, //020A //TVAR_afit_pBaseVals[105] 700008FA //"Demosaic4_iHystGrayRangeUVDenoise_iYSupport" +{0x0F12, 0x1403}, //0A03 //TVAR_afit_pBaseVals[106] 700008FC //"UVDenoise_iUVSupportDSMix1_iLowPower_Wide" +{0x0F12, 0x0A11}, //0A11 //TVAR_afit_pBaseVals[107] 700008FE //"DSMix1_iLowPower_Wide_BinDSMix1_iHighPower_Wide" +{0x0F12, 0x0A0F}, //0A0F //TVAR_afit_pBaseVals[108] 70000900 //"DSMix1_iHighPower_Wide_BinDSMix1_iLowThresh_Wide" +{0x0F12, 0x050A}, //050A //TVAR_afit_pBaseVals[109] 70000902 //"DSMix1_iHighThresh_WideDSMix1_iReduceNegativeWide" +{0x0F12, 0x101E}, //14 //1E //101E //TVAR_afit_pBaseVals[110] 70000904 //"DSMix1_iLowPower_FineDSMix1_iLowPower_Fine_Bin" +{0x0F12, 0x101E}, //101E //TVAR_afit_pBaseVals[111] 70000906 //"DSMix1_iHighPower_FineDSMix1_iHighPower_Fine_Bin" +{0x0F12, 0x0A08}, //3030 //TVAR_afit_pBaseVals[112] 70000908 //"DSMix1_iLowThresh_FineDSMix1_iHighThresh_Fine" +{0x0F12, 0x0005}, //0005 //TVAR_afit_pBaseVals[113] 7000090A //"DSMix1_iReduceNegativeFineDSMix1_iRGBMultiplier" +{0x0F12, 0x0400}, //0400 //TVAR_afit_pBaseVals[114] 7000090C //"Mixer1_iNLowNoisePowerMixer1_iNLowNoisePower_Bin" +{0x0F12, 0x0400}, //0400 //TVAR_afit_pBaseVals[115] 7000090E //"Mixer1_iNVeryLowNoisePowerMixer1_iNVeryLowNoisePower_Bin" +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[116] 70000910 //"Mixer1_iNHighNoisePowerMixer1_iNHighNoisePower_Bin" +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[117] 70000912 //"Mixer1_iWLowNoisePowerMixer1_iWVeryLowNoisePower" +{0x0F12, 0x0A00}, //0A00 //TVAR_afit_pBaseVals[118] 70000914 //"Mixer1_iWHighNoisePowerMixer1_iWLowNoiseCeilGain" +{0x0F12, 0x000A}, //100A //TVAR_afit_pBaseVals[119] 70000916 //"Mixer1_iWHighNoiseCeilGainMixer1_iWNoiseCeilGain" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[120] 70000918 //"CCM_Oscar_iSaturationCCM_Oscar_bSaturation" +{0x0F12, 0x0154}, //TVAR_afit_pBaseVals[121] 7000091A //"RGBGamma2_iLinearityRGBGamma2_bLinearity" +{0x0F12, 0x0100}, //TVAR_afit_pBaseVals[122] 7000091C //"RGBGamma2_iDarkReduceRGBGamma2_bDarkReduce" +{0x0F12, 0x8020}, //TVAR_afit_pBaseVals[123] 7000091E //"byr_gas2_iShadingPowerRGB2YUV_iRGBGain" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[124] 70000920 //"RGB2YUV_iSaturationRGB2YUV_bGainOffset" +{0x0F12, 0x000A}, //07 //0 //TVAR_afit_pBaseVals[125] 70000922 //RGB2YUV_iYOffset +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[126] 70000924 //BRIGHTNESS +{0x0F12, 0x0024}, //TVAR_afit_pBaseVals[127] 70000926 //CONTRAST +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[128] 70000928 //SATURATION +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[129] 7000092A //SHARP_BLUR +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[130] 7000092C //GLAMOUR +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[131] 7000092E //Disparity_iSatSat +{0x0F12, 0x000A}, //0e //08 //000E //TVAR_afit_pBaseVals[132] 70000930 //Denoise1_iYDenThreshLow +{0x0F12, 0x0006}, //0006 //TVAR_afit_pBaseVals[133] 70000932 //Denoise1_iYDenThreshLow_Bin +{0x0F12, 0x0040}, //50 //0064 //TVAR_afit_pBaseVals[134] 70000934 //Denoise1_iYDenThreshHigh +{0x0F12, 0x0050}, //0050 //TVAR_afit_pBaseVals[135] 70000936 //Denoise1_iYDenThreshHigh_Bin +{0x0F12, 0x0002}, //0002 //TVAR_afit_pBaseVals[136] 70000938 //Denoise1_iLowWWideThresh +{0x0F12, 0x000A}, //000A //TVAR_afit_pBaseVals[137] 7000093A //Denoise1_iHighWWideThresh +{0x0F12, 0x000A}, //000A //TVAR_afit_pBaseVals[138] 7000093C //Denoise1_iLowWideThresh +{0x0F12, 0x000A}, //000A //TVAR_afit_pBaseVals[139] 7000093E //Denoise1_iHighWideThresh +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[140] 70000940 //Denoise1_iSatSat +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[141] 70000942 //Demosaic4_iHystGrayLow +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[142] 70000944 //Demosaic4_iHystGrayHigh +{0x0F12, 0x0014}, //0014 //TVAR_afit_pBaseVals[143] 70000946 //UVDenoise_iYLowThresh +{0x0F12, 0x000A}, //000A //TVAR_afit_pBaseVals[144] 70000948 //UVDenoise_iYHighThresh +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[145] 7000094A //UVDenoise_iUVLowThresh +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[146] 7000094C //UVDenoise_iUVHighThresh +{0x0F12, 0x001C}, //000a //TVAR_afit_pBaseVals[147] 7000094E //DSMix1_iLowLimit_Wide +{0x0F12, 0x0032}, //0032 //TVAR_afit_pBaseVals[148] 70000950 //DSMix1_iLowLimit_Wide_Bin +{0x0F12, 0x000A}, //0014 //TVAR_afit_pBaseVals[149] 70000952 //DSMix1_iHighLimit_Wide +{0x0F12, 0x0032}, //0032 //TVAR_afit_pBaseVals[150] 70000954 //DSMix1_iHighLimit_Wide_Bin +{0x0F12, 0x0028}, //0050 //TVAR_afit_pBaseVals[151] 70000956 //DSMix1_iLowLimit_Fine +{0x0F12, 0x0032}, //0032 //TVAR_afit_pBaseVals[152] 70000958 //DSMix1_iLowLimit_Fine_Bin +{0x0F12, 0x0010}, //0010 //TVAR_afit_pBaseVals[153] 7000095A //DSMix1_iHighLimit_Fine +{0x0F12, 0x0032}, //0032 //TVAR_afit_pBaseVals[154] 7000095C //DSMix1_iHighLimit_Fine_Bin +{0x0F12, 0x0106}, //0106 //TVAR_afit_pBaseVals[155] 7000095E //DSMix1_iRGBOffset +{0x0F12, 0x006F}, //006F //TVAR_afit_pBaseVals[156] 70000960 //DSMix1_iDemClamp +{0x0F12, 0x0205}, //020A //TVAR_afit_pBaseVals[157] 70000962 //"Disparity_iDispTH_LowDisparity_iDispTH_Low_Bin" +{0x0F12, 0x0505}, //050A //TVAR_afit_pBaseVals[158] 70000964 //"Disparity_iDispTH_High Disparity_iDispTH_High_Bin" +{0x0F12, 0x0101}, //0101 //TVAR_afit_pBaseVals[159] 70000966 //"Despeckle_iCorrectionLevelColdDespeckle_iCorrectionLevelCold_Bin" +{0x0F12, 0x0202}, //0102 //TVAR_afit_pBaseVals[160] 70000968 //Despeckle_iCorrectionLevelHotDespeckle_iCorrectionLevelHot_Bin +{0x0F12, 0x140A}, //140A //TVAR_afit_pBaseVals[161] 7000096A //"Despeckle_iColdThreshLowDespeckle_iColdThreshHigh" +{0x0F12, 0x140A}, //140A //TVAR_afit_pBaseVals[162] 7000096C //"Despeckle_iHotThreshLowDespeckle_iHotThreshHigh" +{0x0F12, 0x2828}, //2828 //TVAR_afit_pBaseVals[163] 7000096E //"Denoise1_iLowMaxSlopeAllowedDenoise1_iHighMaxSlopeAllowed" +{0x0F12, 0x0606}, //0606 //TVAR_afit_pBaseVals[164] 70000970 //"Denoise1_iLowSlopeThreshDenoise1_iHighSlopeThresh" +{0x0F12, 0x0205}, //0205 //TVAR_afit_pBaseVals[165] 70000972 //"Denoise1_iRadialPowerDenoise1_iRadialDivideShift" +{0x0F12, 0x0480}, //0480 //TVAR_afit_pBaseVals[166] 70000974 //"Denoise1_iRadialLimitDenoise1_iLWBNoise" +{0x0F12, 0x000A}, //000F //TVAR_afit_pBaseVals[167] 70000976 //"Denoise1_iWideDenoise1_iWideWide" +{0x0F12, 0x0005}, //0005 //TVAR_afit_pBaseVals[168] 70000978 //"Demosaic4_iHystGrayRangeUVDenoise_iYSupport" +{0x0F12, 0x1903}, //1903 //TVAR_afit_pBaseVals[169] 7000097A //"UVDenoise_iUVSupportDSMix1_iLowPower_Wide" +{0x0F12, 0x1611}, //0f11 //1911 //1911 //TVAR_afit_pBaseVals[170] 7000097C //"DSMix1_iLowPower_Wide_BinDSMix1_iHighPower_Wide" +{0x0F12, 0x0A0F}, //0A0F //TVAR_afit_pBaseVals[171] 7000097E //"DSMix1_iHighPower_Wide_BinDSMix1_iLowThresh_Wide" +{0x0F12, 0x050A}, //050A //TVAR_afit_pBaseVals[172] 70000980 //"DSMix1_iHighThresh_WideDSMix1_iReduceNegativeWide" +{0x0F12, 0x2025}, //14 //28 //2028 //TVAR_afit_pBaseVals[173] 70000982 //"DSMix1_iLowPower_FineDSMix1_iLowPower_Fine_Bin" +{0x0F12, 0x2025}, //1e //28 //2028 //TVAR_afit_pBaseVals[174] 70000984 //"DSMix1_iHighPower_FineDSMix1_iHighPower_Fine_Bin" +{0x0F12, 0x0A08}, //2000 //TVAR_afit_pBaseVals[175] 70000986 //"DSMix1_iLowThresh_FineDSMix1_iHighThresh_Fine" +{0x0F12, 0x0007}, //0007 //TVAR_afit_pBaseVals[176] 70000988 //"DSMix1_iReduceNegativeFineDSMix1_iRGBMultiplier" +{0x0F12, 0x0403}, //0403 //TVAR_afit_pBaseVals[177] 7000098A //"Mixer1_iNLowNoisePowerMixer1_iNLowNoisePower_Bin" +{0x0F12, 0x0402}, //0402 //TVAR_afit_pBaseVals[178] 7000098C //"Mixer1_iNVeryLowNoisePowerMixer1_iNVeryLowNoisePower_Bin" +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[179] 7000098E //"Mixer1_iNHighNoisePowerMixer1_iNHighNoisePower_Bin" +{0x0F12, 0x0203}, //0203 //TVAR_afit_pBaseVals[180] 70000990 //"Mixer1_iWLowNoisePowerMixer1_iWVeryLowNoisePower" +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[181] 70000992 //"Mixer1_iWHighNoisePowerMixer1_iWLowNoiseCeilGain" +{0x0F12, 0x0006}, //1006 //TVAR_afit_pBaseVals[182] 70000994 //"Mixer1_iWHighNoiseCeilGainMixer1_iWNoiseCeilGain" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[183] 70000996 //"CCM_Oscar_iSaturationCCM_Oscar_bSaturation" +{0x0F12, 0x0173}, //TVAR_afit_pBaseVals[184] 70000998 //"RGBGamma2_iLinearityRGBGamma2_bLinearity" +{0x0F12, 0x0100}, //TVAR_afit_pBaseVals[185] 7000099A //"RGBGamma2_iDarkReduceRGBGamma2_bDarkReduce" +{0x0F12, 0x8032}, //TVAR_afit_pBaseVals[186] 7000099C //"byr_gas2_iShadingPowerRGB2YUV_iRGBGain" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[187] 7000099E //"RGB2YUV_iSaturationRGB2YUV_bGainOffset" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[188] 700009A0 //RGB2YUV_iYOffset +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[189] 700009A2 //BRIGHTNESS +{0x0F12, 0x0014}, //TVAR_afit_pBaseVals[190] 700009A4 //CONTRAST +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[191] 700009A6 //SATURATION +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[192] 700009A8 //SHARP_BLUR +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[193] 700009AA //GLAMOUR +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[194] 700009AC //Disparity_iSatSat +{0x0F12, 0x000A}, //0e //08 //000E //TVAR_afit_pBaseVals[195] 700009AE //Denoise1_iYDenThreshLow +{0x0F12, 0x0006}, //0006 //TVAR_afit_pBaseVals[196] 700009B0 //Denoise1_iYDenThreshLow_Bin +{0x0F12, 0x0040}, //50 //0064 //TVAR_afit_pBaseVals[197] 700009B2 //Denoise1_iYDenThreshHigh +{0x0F12, 0x0050}, //0050 //TVAR_afit_pBaseVals[198] 700009B4 //Denoise1_iYDenThreshHigh_Bin +{0x0F12, 0x0002}, //0002 //TVAR_afit_pBaseVals[199] 700009B6 //Denoise1_iLowWWideThresh +{0x0F12, 0x000A}, //000A //TVAR_afit_pBaseVals[200] 700009B8 //Denoise1_iHighWWideThresh +{0x0F12, 0x000A}, //000A //TVAR_afit_pBaseVals[201] 700009BA //Denoise1_iLowWideThresh +{0x0F12, 0x000A}, //000A //TVAR_afit_pBaseVals[202] 700009BC //Denoise1_iHighWideThresh +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[203] 700009BE //Denoise1_iSatSat +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[204] 700009C0 //Demosaic4_iHystGrayLow +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[205] 700009C2 //Demosaic4_iHystGrayHigh +{0x0F12, 0x0014}, //0014 //TVAR_afit_pBaseVals[206] 700009C4 //UVDenoise_iYLowThresh +{0x0F12, 0x0032}, //000A //TVAR_afit_pBaseVals[207] 700009C6 //UVDenoise_iYHighThresh +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[208] 700009C8 //UVDenoise_iUVLowThresh +{0x0F12, 0x03FF}, //03FF //TVAR_afit_pBaseVals[209] 700009CA //UVDenoise_iUVHighThresh +{0x0F12, 0x001C}, //000a //TVAR_afit_pBaseVals[210] 700009CC //DSMix1_iLowLimit_Wide +{0x0F12, 0x0032}, //0032 //TVAR_afit_pBaseVals[211] 700009CE //DSMix1_iLowLimit_Wide_Bin +{0x0F12, 0x000A}, //0014 //TVAR_afit_pBaseVals[212] 700009D0 //DSMix1_iHighLimit_Wide +{0x0F12, 0x0032}, //0032 //TVAR_afit_pBaseVals[213] 700009D2 //DSMix1_iHighLimit_Wide_Bin +{0x0F12, 0x0028}, //0050 //TVAR_afit_pBaseVals[214] 700009D4 //DSMix1_iLowLimit_Fine +{0x0F12, 0x0032}, //0032 //TVAR_afit_pBaseVals[215] 700009D6 //DSMix1_iLowLimit_Fine_Bin +{0x0F12, 0x0010}, //0010 //TVAR_afit_pBaseVals[216] 700009D8 //DSMix1_iHighLimit_Fine +{0x0F12, 0x0032}, //0032 //TVAR_afit_pBaseVals[217] 700009DA //DSMix1_iHighLimit_Fine_Bin +{0x0F12, 0x0106}, //0106 //TVAR_afit_pBaseVals[218] 700009DC //DSMix1_iRGBOffset +{0x0F12, 0x006F}, //006F //TVAR_afit_pBaseVals[219] 700009DE //DSMix1_iDemClamp +{0x0F12, 0x0205}, //0205 //TVAR_afit_pBaseVals[220] 700009E0 //"Disparity_iDispTH_LowDisparity_iDispTH_Low_Bin" +{0x0F12, 0x0505}, //0505 //TVAR_afit_pBaseVals[221] 700009E2 //"Disparity_iDispTH_High Disparity_iDispTH_High_Bin" +{0x0F12, 0x0101}, //0101 //TVAR_afit_pBaseVals[222] 700009E4 //"Despeckle_iCorrectionLevelColdDespeckle_iCorrectionLevelCold_Bin" +{0x0F12, 0x0202}, //0102 //TVAR_afit_pBaseVals[223] 700009E6 //Despeckle_iCorrectionLevelHotDespeckle_iCorrectionLevelHot_Bin +{0x0F12, 0x140A}, //140A //TVAR_afit_pBaseVals[224] 700009E8 //"Despeckle_iColdThreshLowDespeckle_iColdThreshHigh" +{0x0F12, 0x140A}, //140A //TVAR_afit_pBaseVals[225] 700009EA //"Despeckle_iHotThreshLowDespeckle_iHotThreshHigh" +{0x0F12, 0x2828}, //2828 //TVAR_afit_pBaseVals[226] 700009EC //"Denoise1_iLowMaxSlopeAllowedDenoise1_iHighMaxSlopeAllowed" +{0x0F12, 0x0606}, //0606 //TVAR_afit_pBaseVals[227] 700009EE //"Denoise1_iLowSlopeThreshDenoise1_iHighSlopeThresh" +{0x0F12, 0x0205}, //0205 //TVAR_afit_pBaseVals[228] 700009F0 //"Denoise1_iRadialPowerDenoise1_iRadialDivideShift" +{0x0F12, 0x0480}, //0480 //TVAR_afit_pBaseVals[229] 700009F2 //"Denoise1_iRadialLimitDenoise1_iLWBNoise" +{0x0F12, 0x000A}, //000F //TVAR_afit_pBaseVals[230] 700009F4 //"Denoise1_iWideDenoise1_iWideWide" +{0x0F12, 0x0005}, //0005 //TVAR_afit_pBaseVals[231] 700009F6 //"Demosaic4_iHystGrayRangeUVDenoise_iYSupport" +{0x0F12, 0x1903}, //1903 //TVAR_afit_pBaseVals[232] 700009F8 //"UVDenoise_iUVSupportDSMix1_iLowPower_Wide" +{0x0F12, 0x1611}, //0f11 //1911 //1911 //TVAR_afit_pBaseVals[233] 700009FA //"DSMix1_iLowPower_Wide_BinDSMix1_iHighPower_Wide" +{0x0F12, 0x0A0F}, //0A0F //TVAR_afit_pBaseVals[234] 700009FC //"DSMix1_iHighPower_Wide_BinDSMix1_iLowThresh_Wide" +{0x0F12, 0x050A}, //050A //TVAR_afit_pBaseVals[235] 700009FE //"DSMix1_iHighThresh_WideDSMix1_iReduceNegativeWide" +{0x0F12, 0x2025}, //14 //28 //2028 //TVAR_afit_pBaseVals[236] 70000A00 //"DSMix1_iLowPower_FineDSMix1_iLowPower_Fine_Bin" +{0x0F12, 0x2025}, //1E //28 //2028 //TVAR_afit_pBaseVals[237] 70000A02 //"DSMix1_iHighPower_FineDSMix1_iHighPower_Fine_Bin" +{0x0F12, 0x0A08}, //2000 //TVAR_afit_pBaseVals[238] 70000A04 //"DSMix1_iLowThresh_FineDSMix1_iHighThresh_Fine" +{0x0F12, 0x0007}, //0007 //TVAR_afit_pBaseVals[239] 70000A06 //"DSMix1_iReduceNegativeFineDSMix1_iRGBMultiplier" +{0x0F12, 0x0403}, //0403 //TVAR_afit_pBaseVals[240] 70000A08 //"Mixer1_iNLowNoisePowerMixer1_iNLowNoisePower_Bin" +{0x0F12, 0x0402}, //0402 //TVAR_afit_pBaseVals[241] 70000A0A //"Mixer1_iNVeryLowNoisePowerMixer1_iNVeryLowNoisePower_Bin" +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[242] 70000A0C //"Mixer1_iNHighNoisePowerMixer1_iNHighNoisePower_Bin" +{0x0F12, 0x0203}, //0203 //TVAR_afit_pBaseVals[243] 70000A0E //"Mixer1_iWLowNoisePowerMixer1_iWVeryLowNoisePower" +{0x0F12, 0x0000}, //0000 //TVAR_afit_pBaseVals[244] 70000A10 //"Mixer1_iWHighNoisePowerMixer1_iWLowNoiseCeilGain" +{0x0F12, 0x0006}, //1006 //TVAR_afit_pBaseVals[245] 70000A12 //"Mixer1_iWHighNoiseCeilGainMixer1_iWNoiseCeilGain" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[246] 70000A14 //"CCM_Oscar_iSaturationCCM_Oscar_bSaturation" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[247] 70000A16 //"RGBGamma2_iLinearityRGBGamma2_bLinearity" +{0x0F12, 0x0100}, //TVAR_afit_pBaseVals[248] 70000A18 //"RGBGamma2_iDarkReduceRGBGamma2_bDarkReduce" +{0x0F12, 0x803C}, //TVAR_afit_pBaseVals[249] 70000A1A //"byr_gas2_iShadingPowerRGB2YUV_iRGBGain" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[250] 70000A1C //"RGB2YUV_iSaturationRGB2YUV_bGainOffset" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[251] 70000A1E //RGB2YUV_iYOffset +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[252] 70000A20 //BRIGHTNESS +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[253] 70000A22 //CONTRAST +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[254] 70000A24 //SATURATION +{0x0F12, 0x0014}, //TVAR_afit_pBaseVals[255] 70000A26 //SHARP_BLUR +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[256] 70000A28 //GLAMOUR +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[257] 70000A2A //Disparity_iSatSat +{0x0F12, 0x000E}, //TVAR_afit_pBaseVals[258] 70000A2C //Denoise1_iYDenThreshLow +{0x0F12, 0x0006}, //TVAR_afit_pBaseVals[259] 70000A2E //Denoise1_iYDenThreshLow_Bin +{0x0F12, 0x0020}, //TVAR_afit_pBaseVals[260] 70000A30 //Denoise1_iYDenThreshHigh +{0x0F12, 0x0050}, //TVAR_afit_pBaseVals[261] 70000A32 //Denoise1_iYDenThreshHigh_Bin +{0x0F12, 0x0002}, //TVAR_afit_pBaseVals[262] 70000A34 //Denoise1_iLowWWideThresh +{0x0F12, 0x000A}, //TVAR_afit_pBaseVals[263] 70000A36 //Denoise1_iHighWWideThresh +{0x0F12, 0x000A}, //TVAR_afit_pBaseVals[264] 70000A38 //Denoise1_iLowWideThresh +{0x0F12, 0x000A}, //TVAR_afit_pBaseVals[265] 70000A3A //Denoise1_iHighWideThresh +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[266] 70000A3C //Denoise1_iSatSat +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[267] 70000A3E //Demosaic4_iHystGrayLow +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[268] 70000A40 //Demosaic4_iHystGrayHigh +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[269] 70000A42 //UVDenoise_iYLowThresh +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[270] 70000A44 //UVDenoise_iYHighThresh +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[271] 70000A46 //UVDenoise_iUVLowThresh +{0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[272] 70000A48 //UVDenoise_iUVHighThresh +{0x0F12, 0x0014}, //TVAR_afit_pBaseVals[273] 70000A4A //DSMix1_iLowLimit_Wide +{0x0F12, 0x0032}, //TVAR_afit_pBaseVals[274] 70000A4C //DSMix1_iLowLimit_Wide_Bin +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[275] 70000A4E //DSMix1_iHighLimit_Wide +{0x0F12, 0x0032}, //TVAR_afit_pBaseVals[276] 70000A50 //DSMix1_iHighLimit_Wide_Bin +{0x0F12, 0x0020}, //TVAR_afit_pBaseVals[277] 70000A52 //DSMix1_iLowLimit_Fine +{0x0F12, 0x0032}, //TVAR_afit_pBaseVals[278] 70000A54 //DSMix1_iLowLimit_Fine_Bin +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[279] 70000A56 //DSMix1_iHighLimit_Fine +{0x0F12, 0x0032}, //TVAR_afit_pBaseVals[280] 70000A58 //DSMix1_iHighLimit_Fine_Bin +{0x0F12, 0x0106}, //TVAR_afit_pBaseVals[281] 70000A5A //DSMix1_iRGBOffset +{0x0F12, 0x006F}, //TVAR_afit_pBaseVals[282] 70000A5C //DSMix1_iDemClamp +{0x0F12, 0x0202}, //TVAR_afit_pBaseVals[283] 70000A5E //"Disparity_iDispTH_LowDisparity_iDispTH_Low_Bin" +{0x0F12, 0x0502}, //TVAR_afit_pBaseVals[284] 70000A60 //"Disparity_iDispTH_High Disparity_iDispTH_High_Bin" +{0x0F12, 0x0101}, //TVAR_afit_pBaseVals[285] 70000A62 //"Despeckle_iCorrectionLevelColdDespeckle_iCorrectionLevelCold_Bin" +{0x0F12, 0x0202}, //TVAR_afit_pBaseVals[286] 70000A64 //Despeckle_iCorrectionLevelHotDespeckle_iCorrectionLevelHot_Bin +{0x0F12, 0x140A}, //TVAR_afit_pBaseVals[287] 70000A66 //"Despeckle_iColdThreshLowDespeckle_iColdThreshHigh" +{0x0F12, 0x140A}, //TVAR_afit_pBaseVals[288] 70000A68 //"Despeckle_iHotThreshLowDespeckle_iHotThreshHigh" +{0x0F12, 0x2828}, //TVAR_afit_pBaseVals[289] 70000A6A //"Denoise1_iLowMaxSlopeAllowedDenoise1_iHighMaxSlopeAllowed" +{0x0F12, 0x0606}, //TVAR_afit_pBaseVals[290] 70000A6C //"Denoise1_iLowSlopeThreshDenoise1_iHighSlopeThresh" +{0x0F12, 0x0205}, //TVAR_afit_pBaseVals[291] 70000A6E //"Denoise1_iRadialPowerDenoise1_iRadialDivideShift" +{0x0F12, 0x0880}, //TVAR_afit_pBaseVals[292] 70000A70 //"Denoise1_iRadialLimitDenoise1_iLWBNoise" +{0x0F12, 0x000F}, //TVAR_afit_pBaseVals[293] 70000A72 //"Denoise1_iWideDenoise1_iWideWide" +{0x0F12, 0x0005}, //TVAR_afit_pBaseVals[294] 70000A74 //"Demosaic4_iHystGrayRangeUVDenoise_iYSupport" +{0x0F12, 0x1903}, //TVAR_afit_pBaseVals[295] 70000A76 //"UVDenoise_iUVSupportDSMix1_iLowPower_Wide" +{0x0F12, 0x1611}, //0f11 //1911 //TVAR_afit_pBaseVals[296] 70000A78 //"DSMix1_iLowPower_Wide_BinDSMix1_iHighPower_Wide" +{0x0F12, 0x0A0F}, //TVAR_afit_pBaseVals[297] 70000A7A //"DSMix1_iHighPower_Wide_BinDSMix1_iLowThresh_Wide" +{0x0F12, 0x050A}, //TVAR_afit_pBaseVals[298] 70000A7C //"DSMix1_iHighThresh_WideDSMix1_iReduceNegativeWide" +{0x0F12, 0x2020}, //14 //20 //TVAR_afit_pBaseVals[299] 70000A7E //"DSMix1_iLowPower_FineDSMix1_iLowPower_Fine_Bin" +{0x0F12, 0x2020}, //1e //20 //TVAR_afit_pBaseVals[300] 70000A80 //"DSMix1_iHighPower_FineDSMix1_iHighPower_Fine_Bin" +{0x0F12, 0x0A08}, //TVAR_afit_pBaseVals[301] 70000A82 //"DSMix1_iLowThresh_FineDSMix1_iHighThresh_Fine" +{0x0F12, 0x0007}, //TVAR_afit_pBaseVals[302] 70000A84 //"DSMix1_iReduceNegativeFineDSMix1_iRGBMultiplier" +{0x0F12, 0x0408}, //TVAR_afit_pBaseVals[303] 70000A86 //"Mixer1_iNLowNoisePowerMixer1_iNLowNoisePower_Bin" +{0x0F12, 0x0406}, //TVAR_afit_pBaseVals[304] 70000A88 //"Mixer1_iNVeryLowNoisePowerMixer1_iNVeryLowNoisePower_Bin" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[305] 70000A8A //"Mixer1_iNHighNoisePowerMixer1_iNHighNoisePower_Bin" +{0x0F12, 0x0608}, //TVAR_afit_pBaseVals[306] 70000A8C //"Mixer1_iWLowNoisePowerMixer1_iWVeryLowNoisePower" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[307] 70000A8E //"Mixer1_iWHighNoisePowerMixer1_iWLowNoiseCeilGain" +{0x0F12, 0x0006}, //TVAR_afit_pBaseVals[308] 70000A90 //"Mixer1_iWHighNoiseCeilGainMixer1_iWNoiseCeilGain" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[309] 70000A92 //180 173 164 //"CCM_Oscar_iSaturationCCM_Oscar_bSaturation" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[310] 70000A94 //Linearity //"RGBGamma2_iLinearityRGBGamma2_bLinearity" +{0x0F12, 0x0100}, //TVAR_afit_pBaseVals[311] 70000A96 //"RGBGamma2_iDarkReduceRGBGamma2_bDarkReduce" +{0x0F12, 0x804A}, //TVAR_afit_pBaseVals[312] 70000A98 //"byr_gas2_iShadingPowerRGB2YUV_iRGBGain" +{0x0F12, 0x0180}, //TVAR_afit_pBaseVals[313] 70000A9A //"RGB2YUV_iSaturationRGB2YUV_bGainOffset" +{0x0F12, 0x0000}, //TVAR_afit_pBaseVals[314] 70000A9C //RGB2YUV_iYOffset +{0x0F12, 0x00FF}, //afit_pConstBaseVals[0] //Denoise1_iUVDenThreshLow +{0x0F12, 0x00FF}, //afit_pConstBaseVals[1] //Denoise1_iUVDenThreshHigh +{0x0F12, 0x0800}, //afit_pConstBaseVals[2] //Denoise1_sensor_width +{0x0F12, 0x0600}, //afit_pConstBaseVals[3] //Denoise1_sensor_height +{0x0F12, 0x0000}, //afit_pConstBaseVals[4] //Denoise1_start_x +{0x0F12, 0x0000}, //afit_pConstBaseVals[5] //Denoise1_start_y +{0x0F12, 0x0000}, //afit_pConstBaseVals[6] //"Denoise1_iYDenSmoothDenoise1_iWSharp " +{0x0F12, 0x0300}, //afit_pConstBaseVals[7] //"Denoise1_iWWSharp Denoise1_iRadialTune " +{0x0F12, 0x0002}, //afit_pConstBaseVals[8] //"Denoise1_iOutputBrightnessDenoise1_binning_x " +{0x0F12, 0x0400}, //afit_pConstBaseVals[9] //"Denoise1_binning_yDemosaic4_iFDeriv " +{0x0F12, 0x0106}, //afit_pConstBaseVals[10] //"Demosaic4_iFDerivNeiDemosaic4_iSDeriv " +{0x0F12, 0x0005}, //afit_pConstBaseVals[11] //"Demosaic4_iSDerivNeiDemosaic4_iEnhancerG " +{0x0F12, 0x0000}, //afit_pConstBaseVals[12] //"Demosaic4_iEnhancerRBDemosaic4_iEnhancerV " +{0x0F12, 0x0703}, //afit_pConstBaseVals[13] //"Demosaic4_iDecisionThreshDemosaic4_iDesatThresh" +{0x0F12, 0x0000}, //afit_pConstBaseVals[14] //Demosaic4_iBypassSelect +{0x0F12, 0xFFD6}, //afit_pConstBaseVals[15] +{0x0F12, 0x53C1}, //afit_pConstBaseVals[16]//hys off : 4341 +{0x0F12, 0xE1FE}, //afit_pConstBaseVals[17]//mixer on :E0FA +{0x0F12, 0x0001}, //afit_pConstBaseVals[18] + + +//================================================================ +// Flicker +//================================================================ +{0x1000, 0x0001}, //Set host interrupt so main start run +{0xFFFE, 0x000a}, //Wait 10mSec + +{0x002A, 0x0400}, +{0x0F12, 0x005F}, //REG_TC_DBG_AutoAlgEnBits +{0x002A, 0x03DC}, +{0x0F12, 0x0001}, //REG_SF_USER_FlickerQuant 1:50hz, 2:60hz +{0x0F12, 0x0001}, //REG_SF_USER_FlickerQuantChanged + + +//================================================================ +// Clock Settings +//================================================================ +// External Clock : 24Mhz +{0x002A, 0x01B8}, +{0x0F12, 0x5DC0}, //REG_TC_IPRM_InClockLSBs //700001B8 //5DC0:24Mhz +{0x0F12, 0x0000}, //REG_TC_IPRM_InClockMSBs //700001BA + +// Pararrel & MIPI Clock Setting +{0x002A, 0x01C6}, +{0x0F12, 0x0001}, //REG_TC_IPRM_UseNPviClocks //700001C6 //1 Parallel Configurations +{0x0F12, 0x0001}, //REG_TC_IPRM_UseNMipiClocks //700001C8 //1 MIPI Configurations + +// System Clock0 : 28Mhz, PCLK : 48Mhz +{0x002A, 0x01CC}, +{0x0F12, 0x1B58}, //REG_TC_IPRM_OpClk4KHz_0 //700001CC +{0x0F12, 0x2EE0}, //REG_TC_IPRM_MinOutRate4KHz_0 //700001CE +{0x0F12, 0x2EE0}, //REG_TC_IPRM_MaxOutRate4KHz_0 //700001D0 + + //System clock1 : 28Mhz, PCLK : 48Mhz +{0x002A, 0x01D2}, +{0x0F12, 0x1B58}, //REG_TC_IPRM_OpClk4KHz_1 //700001D2 +{0x0F12, 0x2EE0}, //REG_TC_IPRM_MinOutRate4KHz_1 //700001D4 +{0x0F12, 0x2EE0}, //REG_TC_IPRM_MaxOutRate4KHz_1 //700001D6 + +// System clock2 : 24Mhz, PCLK : 24Mhz +//s002A01D8 +//s0F121770 //REG_TC_IPRM_OpClk4KHz_2 //700001D8 //1770:24Mhz +//s0F121770 //REG_TC_IPRM_MinOutRate4KHz_2 //700001DA //1770:24Mhz +//s0F121770 //REG_TC_IPRM_MaxOutRate4KHz_2 //700001DC //1770:24Mhz + +{0x002A, 0x01E0}, +{0x0F12, 0x0001}, //REG_TC_IPRM_InitParamsUpdated //700001E0 +{0xFFFE, 0x0064}, //Delay 100ms + + +//================================================================ +// Preview Configuration +//================================================================ +// Preview 0 for 640x480, 8-15fps +{0x002A, 0x0242}, +{0x0F12, 0x0280}, //REG_0TC_PCFG_usWidth +{0x0F12, 0x01E0}, //REG_0TC_PCFG_usHeight +{0x0F12, 0x0005}, //REG_0TC_PCFG_Format +{0x002A, 0x024E}, +{0x0F12, 0x0001}, //REG_0TC_PCFG_uClockInd +{0x002A, 0x0248}, +{0x0F12, 0x2EE0}, //REG_0TC_PCFG_usMaxOut4KHzRate +{0x0F12, 0x2EE0}, //REG_0TC_PCFG_usMinOut4KHzRate +{0x0F12, 0x0052}, //REG_0TC_PCFG_PVIMask +{0x002A, 0x0252}, +{0x0F12, 0x0001}, //REG_0TC_PCFG_FrRateQualityType +{0x002A, 0x0250}, +{0x0F12, 0x0000}, //REG_0TC_PCFG_usFrTimeType +{0x002A, 0x0262}, +{0x0F12, 0x0000}, //REG_0TC_PCFG_uPrevMirror [0]x [1]y [2]xy +{0x0F12, 0x0000}, //REG_0TC_PCFG_uCaptureMirror +{0x002A, 0x0254}, +{0x0F12, 0x0535}, //REG_0TC_PCFG_usMaxFrTimeMsecMult10 +{0x0F12, 0x029A}, //REG_0TC_PCFG_usMinFrTimeMsecMult10 + +// Preview 1 Not USE.. But Don't Delete this configure +{0x002A, 0x0268}, +{0x0F12, 0x0210}, //REG_1TC_PCFG_usWidth +{0x0F12, 0x01B0}, //REG_1TC_PCFG_usHeight +{0x0F12, 0x0005}, //REG_1TC_PCFG_Format +{0x002A, 0x0274}, +{0x0F12, 0x0001}, //REG_1TC_PCFG_uClockInd +{0x002A, 0x026E}, +{0x0F12, 0x2EE0}, //REG_1TC_PCFG_usMaxOut4KHzRate +{0x0F12, 0x2EE0}, //REG_1TC_PCFG_usMinOut4KHzRate +{0x0F12, 0x0052}, //REG_1TC_PCFG_PVIMask +{0x002A, 0x0278}, +{0x0F12, 0x0001}, //REG_1TC_PCFG_FrRateQualityType +{0x002A, 0x0276}, +{0x0F12, 0x0002}, //REG_1TC_PCFG_usFrTimeType +{0x002A, 0x0288}, +{0x0F12, 0x0000}, //REG_1TC_PCFG_uPrevMirror +{0x0F12, 0x0000}, //REG_1TC_PCFG_uCaptureMirror +{0x002A, 0x027A}, +{0x0F12, 0x0535}, //REG_1TC_PCFG_usMaxFrTimeMsecMult10 +{0x0F12, 0x029A}, //REG_1TC_PCFG_usMinFrTimeMsecMult10 + + +//================================================================ +// Capture Configuration +//================================================================ +// Capture 0 for 1280x960 +//s002A030C +//s0F120001 //AE ON +{0x002A, 0x030E}, +{0x0F12, 0x0500}, //REG_0TC_CCFG_usWidth +{0x0F12, 0x03C0}, //REG_0TC_CCFG_usHeight +{0x0F12, 0x0005}, //REG_0TC_CCFG_Format +{0x002A, 0x031A}, +{0x0F12, 0x0001}, //REG_0TC_CCFG_uClockInd +{0x002A, 0x0314}, +{0x0F12, 0x2EE0}, //REG_0TC_CCFG_usMaxOut4KHzRate +{0x0F12, 0x2EE0}, //REG_0TC_CCFG_usMinOut4KHzRate +{0x0F12, 0x0052}, //REG_0TC_CCFG_PVIMask +{0x002A, 0x031E}, +{0x0F12, 0x0002}, //REG_0TC_CCFG_FrRateQualityType +{0x002A, 0x031C}, +{0x0F12, 0x0002}, //REG_0TC_CCFG_usFrTimeType +{0x002A, 0x0320}, +{0x0F12, 0x0535}, //REG_0TC_CCFG_usMaxFrTimeMsecMult10 +{0x0F12, 0x0000}, //REG_0TC_CCFG_usMinFrTimeMsecMult10 + +{0x002A, 0x0226}, +{0x0F12, 0x0001}, //REG_TC_GP_CapConfigChanged + + +//================================================================ +// Factory Only No Delete +//================================================================ +{0x002A, 0x10EE}, +{0x0F12, 0x097A}, // senHal_uMinColsNoBin *FACTORY ONLY *No Delete// + + +//================================================================ +// REG TC FLS +//================================================================ +{0x002A, 0x03B6}, +{0x0F12, 0x0000}, //REG_TC_FLS + + +//================================================================ +// MIPI Lane +//================================================================ +{0x002A, 0x03FA}, +{0x0F12, 0x0001}, //REG_TC_OIF_EnMipiLanes //700003FA +{0x0F12, 0x00C3}, //REG_TC_OIF_EnPackets //700003FC +{0x0F12, 0x0001}, //REG_TC_OIF_CfgChanged //700003FE + + +//================================================================ +//PREVIEW Command +//================================================================ +{0x002A, 0x021C}, +{0x0F12, 0x0000}, //REG_TC_GP_ActivePrevConfig //7000021C +{0x002A, 0x0220}, +{0x0F12, 0x0001}, //REG_TC_GP_PrevOpenAfterChange //70000220 +{0x002A, 0x01F8}, +{0x0F12, 0x0001}, //REG_TC_GP_NewConfigSync //700001F8 +{0x002A, 0x021E}, +{0x0F12, 0x0001}, //REG_TC_GP_PrevConfigChanged //7000021E +{0x002A, 0x01F0}, +{0x0F12, 0x0001}, //REG_TC_GP_EnablePreview //700001F0 +{0x0F12, 0x0001}, //REG_TC_GP_EnablePreviewChanged //700001F2 +{0xFFFE, 0x0096}, // Wait150ms// + + +//================================================================ +//Input size Change (CROP) +//================================================================ +{0x002A, 0x020A}, +{0x0F12, 0x0500}, // REG_TC_GP_PrevZoomReqInputWidth +{0x0F12, 0x03C0}, // REG_TC_GP_PrevZoomReqInputHeight +{0x0F12, 0x0000}, // REG_TC_GP_PrevZoomReqInputWidthOfs +{0x0F12, 0x0020}, // REG_TC_GP_PrevZoomReqInputHeightOfs + +{0x0F12, 0x0500}, // REG_TC_GP_CapZoomReqInputWidth +{0x0F12, 0x03C0}, // REG_TC_GP_CapZoomReqInputHeight +{0x0F12, 0x0000}, // REG_TC_GP_CapZoomReqInputWidthOfs +{0x0F12, 0x0020}, // REG_TC_GP_CapZoomReqInputHeightOfs +{0x0F12, 0x0001}, // REG_TC_GP_InputsChangeRequest// + +{0xFFFE, 0x0064}, // Wait100ms// + +//================================================================ +// Non Continuous Mode +//================================================================ +{0x0028, 0xD000}, +{0x002A, 0xB0CC}, +{0x0F12, 0x000B}, //Non Continuous mode +}; + +s5k6aa_short_t mode_preview_640x480[] = +{ +{0xFCFC, 0xD000}, +{0x0028, 0x7000}, + +{0x002A, 0x10EE}, +{0x0F12, 0x097A}, // senHal_uMinColsNoBin *FACTORY ONLY *No Delete// + +{0x002A, 0x021C}, +{0x0F12, 0x0000}, // REG_TC_GP_ActivePrevConfig + +{0x002A, 0x0220}, +{0x0F12, 0x0001}, // REG_TC_GP_PrevOpenAfterChange + +{0x002A, 0x01F8}, +{0x0F12, 0x0001}, // REG_TC_GP_NewConfigSync + +{0x002A, 0x021E}, +{0x0F12, 0x0001}, // REG_TC_GP_PrevConfigChanged +{0x002A, 0x01F0}, +{0x0F12, 0x0001}, // REG_TC_GP_EnablePreview +{0x0F12, 0x0001}, // REG_TC_GP_EnablePreviewChanged +{0xFFFE, 0x0096}, // Wait150ms// + + +{0x0028, 0xD000}, // MIPI +{0x002A, 0xB0CC}, +{0x0F12, 0x000B}, +}; + +s5k6aa_short_t mode_capture_1280x960[] = +{ +{0xFCFC, 0xD000}, +{0x0028, 0x7000}, + +{0x002A, 0x10EE}, +{0x0F12, 0x0D7A}, // senHal_uMinColsNoBin *FACTORY ONLY *No Delete// + +{0x002A, 0x0224}, +{0x0F12, 0x0000}, // REG_TC_GP_ActiveCapConfig + +{0x002A, 0x01F8}, +{0x0F12, 0x0001}, // REG_TC_GP_NewConfigSync + +{0x002A, 0x0226}, +{0x0F12, 0x0001}, // REG_TC_GP_CapConfigChanged + +{0x002A, 0x01F4}, +{0x0F12, 0x0001}, // REG_TC_GP_EnableCapture +{0x0F12, 0x0001}, // REG_TC_GP_EnableCaptureChanged +{0xFFFE, 0x0096}, // Wait150ms// + + +{0x0028, 0xD000}, // MIPI +{0x002A, 0xB0CC}, +{0x0F12, 0x000B}, +}; + +s5k6aa_short_t mode_recording_640x480[] = +{ +{0xFCFC, 0xD000}, +{0x0028, 0x7000}, + +{0x002A, 0x10EE}, +{0x0F12, 0x03CE}, //097A //senHal_uMinColsNoBin *FACTORY ONLY *No Delete + +{0x002A, 0x021C}, +{0x0F12, 0x0000}, // REG_TC_GP_ActivePrevConfig + +{0x002A, 0x0220}, +{0x0F12, 0x0001}, // REG_TC_GP_PrevOpenAfterChange + +{0x002A, 0x01F8}, +{0x0F12, 0x0001}, // REG_TC_GP_NewConfigSync + +{0x002A, 0x021E}, +{0x0F12, 0x0001}, // REG_TC_GP_PrevConfigChanged +{0x002A, 0x01F0}, +{0x0F12, 0x0001}, // REG_TC_GP_EnablePreview +{0x0F12, 0x0001}, // REG_TC_GP_EnablePreviewChanged +{0xFFFE, 0x0096}, // Wait150ms// + +{0x0028, 0xD000}, // MIPI +{0x002A, 0xB0CC}, +{0x0F12, 0x000B}, +}; + +#endif diff --git a/drivers/media/video/msm_zsl/s5k6aa_v4l2.c b/drivers/media/video/msm_zsl/s5k6aa_v4l2.c new file mode 100644 index 00000000000..97ba99528dc --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k6aa_v4l2.c @@ -0,0 +1,818 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "msm.h" +#include "s5k6aa.h" +#include "s5k6aa_regs.h" + +#include "cam_pmic_s5k6aa.h" + + +//#define CONFIG_LOAD_FILE + + +#define S5K6AA_WRITE_LIST(A) s5k6aa_i2c_write_list(A,(sizeof(A) / sizeof(A[0])),#A); + +#define CAM_5M_RST 107 +#define CAM_5M_ISP_INIT 4 +#define CAM_1_3M_RST 76 +#define CAM_1_3M_EN 18 +#define CAM_MCLK 5 +#define CAM_I2C_SDA 20 +#define CAM_I2C_SCL 21 + + +struct s5k6aa_work { + struct work_struct work; +}; + +static struct s5k6aa_work *s5k6aa_sensorw; +static struct i2c_client *s5k6aa_client; +#if 1 +struct s5k6aa_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + uint32_t sensormode; + uint32_t fps_divider;/* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */ + uint16_t fps; + int16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + enum s5k6aa_resolution_t prev_res; + enum s5k6aa_resolution_t pict_res; + enum s5k6aa_resolution_t curr_res; + enum s5k6aa_test_mode_t set_test; + unsigned short imgaddr; + + struct v4l2_subdev *sensor_dev; + struct s5k6aa_format *fmt; +}; +#endif + +struct s5k6aa_ctrl { + const struct msm_camera_sensor_info *sensordata; + struct s5k6aa_userset settings; + + struct v4l2_subdev *sensor_dev; + + int op_mode; + int dtp_mode; + int app_mode; // camera or camcorder + int vtcall_mode; + int started; +}; + +static unsigned int config_csi2; +static struct s5k6aa_ctrl *s5k6aa_ctrl; + +struct s5k6aa_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; + +static DECLARE_WAIT_QUEUE_HEAD(s5k6aa_wait_queue); + +/** + * s5k6aa_i2c_read_multi: Read (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * @r_data: buffer where data is read + * @r_len: number of bytes to read + * + * Returns 0 on success, <0 on error + */ + +#if 1 +static int s5k6aa_i2c_read_multi(unsigned short subaddr, unsigned long *data) +{ + unsigned char buf[4]; + struct i2c_msg msg = {s5k6aa_client->addr, 0, 2, buf}; + + int err = 0; + + if (!s5k6aa_client->adapter) { + //dev_err(&s5k6aa_client->dev, "%s: %d can't search i2c client adapter\n", __func__, __LINE__); + return -EIO; + } + + buf[0] = subaddr>> 8; + buf[1] = subaddr & 0xff; + + err = i2c_transfer(s5k6aa_client->adapter, &msg, 1); + if (unlikely(err < 0)) { + //dev_err(&s5k6aa_client->dev, "%s: %d register read fail\n", __func__, __LINE__); + return -EIO; + } + + msg.flags = I2C_M_RD; + msg.len = 4; + + err = i2c_transfer(s5k6aa_client->adapter, &msg, 1); + if (unlikely(err < 0)) { + //dev_err(&s5k6aa_client->dev, "%s: %d register read fail\n", __func__, __LINE__); + return -EIO; + } + + /* + * Data comes in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + *data = *(unsigned long *)(&buf); + + return err; +} + + +/** + * s5k6aa_i2c_read: Read (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @data: data to be read + * + * Returns 0 on success, <0 on error + */ +static int s5k6aa_i2c_read(unsigned short subaddr, unsigned short *data) +{ + unsigned char buf[2]; + struct i2c_msg msg = {s5k6aa_client->addr, 0, 2, buf}; + + int err = 0; + + if (!s5k6aa_client->adapter) { + //dev_err(&s5k6aa_client->dev, "%s: %d can't search i2c client adapter\n", __func__, __LINE__); + return -EIO; + } + + buf[0] = subaddr>> 8; + buf[1] = subaddr & 0xff; + + err = i2c_transfer(s5k6aa_client->adapter, &msg, 1); + if (unlikely(err < 0)) { + //dev_err(&s5k6aa_client->dev, "%s: %d register read fail\n", __func__, __LINE__); + return -EIO; + } + + msg.flags = I2C_M_RD; + + err = i2c_transfer(s5k6aa_client->adapter, &msg, 1); + if (unlikely(err < 0)) { + //dev_err(&s5k6aa_client->dev, "%s: %d register read fail\n", __func__, __LINE__); + return -EIO; + } + + /* + * Data comes in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + *data = *(unsigned short *)(&buf); + + return err; +} + +#endif +/** + * s5k6aa_i2c_write_multi: Write (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * + * Returns 0 on success, <0 on error + */ +static int s5k6aa_i2c_write_multi(unsigned short addr, unsigned int w_data) +{ + unsigned char buf[4]; + struct i2c_msg msg = {s5k6aa_client->addr, 0, 4, buf}; + + int retry_count = 5; + int err = 0; + + if (!s5k6aa_client->adapter) { + //dev_err(&s5k6aa_client->dev, "%s: %d can't search i2c client adapter\n", __func__, __LINE__); + return -EIO; + } + + buf[0] = addr >> 8; + buf[1] = addr & 0xff; + buf[2] = w_data >> 8; + buf[3] = w_data & 0xff; + /* + * Data should be written in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + + while(retry_count--) { + err = i2c_transfer(s5k6aa_client->adapter, &msg, 1); + if (likely(err == 1)) + break; +// msleep(POLL_TIME_MS); + } + + return (err == 1) ? 0 : -EIO; +} + +static int s5k6aa_i2c_write_list(s5k6aa_short_t regs[], int size, char *name) +{ +#ifdef CONFIG_LOAD_FILE + s5k6aa_regs_table_write(client, name); +#else + int err = 0; + int i = 0; + + if (!s5k6aa_client->adapter) { + printk(KERN_ERR "%s: %d can't search i2c client adapter\n", __func__, __LINE__); + return -EIO; + } + + for (i = 0; i < size; i++) { + if(regs[i].subaddr == 0xFFFE) + { + msleep(regs[i].value); + printk("delay 0x%04x, value 0x%04x\n", regs[i].subaddr, regs[i].value); + } + else + { + err = s5k6aa_i2c_write_multi(regs[i].subaddr, regs[i].value); + + if (unlikely(err < 0)) { + printk(KERN_ERR "%s: register set failed\n", __func__); + return -EIO; + } + } + } +#endif + + return 0; +} + + +////////////////////////////////////////////////////////////// +#ifdef FACTORY_TEST +extern struct class *sec_class; +struct device *s5k6aa_dev; + +static ssize_t cameratype_file_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char sensor_info[30] = "s5k6aa"; + return sprintf(buf, "%s\n", sensor_info); +} + +static ssize_t cameratype_file_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + /*Reserved*/ + return size; +} + +//static DEVICE_ATTR(cameratype, 0666, cameratype_file_cmd_show, cameratype_file_cmd_store); +static struct device_attribute s5k6aa_camtype_attr = { + .attr = { + .name = "camtype", + .mode = (S_IRUGO | S_IWUGO)}, + .show = cameratype_file_cmd_show, + .store = cameratype_file_cmd_store +}; + +static ssize_t cameraflash_file_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /*Reserved*/ + return 0; +} + +static ssize_t cameraflash_file_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int value; + + sscanf(buf, "%d", &value); + + if (value == 0) { + printk(KERN_INFO "[Factory flash]OFF\n"); + s5k6aa_set_flash(MOVIE_FLASH,0); + } else { + printk(KERN_INFO "[Factory flash]ON\n"); + s5k6aa_set_flash(MOVIE_FLASH,1); + } + + return size; +} + +//static DEVICE_ATTR(cameraflash, 0666, cameraflash_file_cmd_show, cameraflash_file_cmd_store); +static struct device_attribute s5k6aa_cameraflash_attr = { + .attr = { + .name = "cameraflash", + .mode = (S_IRUGO | S_IWUGO)}, + .show = cameraflash_file_cmd_show, + .store = cameraflash_file_cmd_store +}; +#endif +////////////////////////////////////////////////////////////// + +void s5k6aa_set_preview(void) +{ + +} + +void s5k6aa_set_capture(void) +{ + S5K6AA_WRITE_LIST(mode_capture_1280x960); +} + +static int32_t s5k6aa_sensor_setting(int update_type, int rt) +{ + printk("[s5k6aa] %s/%d\n", __func__, __LINE__); + + int32_t rc = 0; + int temp = 0; + int32_t Cnt = 0; //Kelly's Test + struct msm_camera_csid_params s5k6aa_csid_params; + struct msm_camera_csiphy_params s5k6aa_csiphy_params; + switch (update_type) { + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) + { + } + break; + + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + printk("[s5k6aa] UPDATE_PERIODIC\n"); + + /* stop streaming */ + gpio_set_value_cansleep(CAM_1_3M_EN, 0); + temp = gpio_get_value(CAM_1_3M_EN); + printk("[s5k6aa] CAM_1_3M_EN : %d\n", temp); + msleep(100); + +#if 0//For Test + //Start polling CSIPHY interrupt status register here + do + { + printk("[s5k6aa] Kelly Test %d\n", Cnt); + + msm_io_read_interrupt(); + }while(Cnt++<5); +#endif + if (config_csi2 == 0) { + struct msm_camera_csid_vc_cfg s5k6aa_vccfg[] = { + {0, 0x1E, CSI_DECODE_8BIT}, +// {0, CSI_RAW10, CSI_DECODE_10BIT}, + {1, CSI_EMBED_DATA, CSI_DECODE_8BIT}, + }; + s5k6aa_csid_params.lane_cnt = 1; + s5k6aa_csid_params.lane_assign = 0xe4; + s5k6aa_csid_params.lut_params.num_cid = + ARRAY_SIZE(s5k6aa_vccfg); + s5k6aa_csid_params.lut_params.vc_cfg = + &s5k6aa_vccfg[0]; + s5k6aa_csiphy_params.lane_cnt = 1; + s5k6aa_csiphy_params.settle_cnt = 0x07;//0x1B; + rc = msm_camio_csid_config(&s5k6aa_csid_params); + v4l2_subdev_notify(s5k6aa_ctrl->sensor_dev, + NOTIFY_CID_CHANGE, NULL); + mb(); + rc = msm_camio_csiphy_config + (&s5k6aa_csiphy_params); + mb(); + /*s5k6aa_delay_msecs_stdby*/ + msleep(350); + config_csi2 = 1; + } + if (rc < 0) + return rc; + /*start stream*/ + gpio_set_value_cansleep(CAM_1_3M_EN, 1); + temp = gpio_get_value(CAM_1_3M_EN); + printk("[s5k6aa] CAM_1_3M_EN : %d\n", temp); + msleep(100); +#if 0//For Test + //Start polling CSIPHY interrupt status register here + do + { + printk("[s5k6aa] Kelly Test %d\n", Cnt); + + msm_io_read_interrupt(); + }while(Cnt++<10); +#endif + } + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static int32_t s5k6aa_video_config(int mode) +{ + printk("[s5k6aa] %s/%d\n", __func__, __LINE__); + + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ +// if (s5k6aa_ctrl->prev_res == QTR_SIZE) + rt = RES_PREVIEW; +// else +// rt = RES_CAPTURE; + + if (s5k6aa_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; +// s5k6aa_ctrl->curr_res = s5k6aa_ctrl->prev_res; +// s5k6aa_ctrl->sensormode = mode; + return rc; +} + +static long s5k6aa_set_sensor_mode(int mode) +{ + printk("[s5k6aa] %s : %d /%d\n", __func__, mode, __LINE__); + + switch (mode) { + case SENSOR_PREVIEW_MODE: + s5k6aa_video_config(mode); + break; + + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + s5k6aa_set_capture(); + break; + default: + return 0;//-EINVAL; + } + return 0; +} + + +static int s5k6aa_sensor_pre_init(const struct msm_camera_sensor_info *data) +{ + printk("[s5k6aa] %s/%d\n", __func__, __LINE__); + + int rc = 0; + +#ifndef CONFIG_LOAD_FILE + rc = S5K6AA_WRITE_LIST(s5k6aa_init_reg); + if(rc < 0) + printk("Error in s5k6aa_sensor_pre_init !"); +#endif + mdelay(10); + + return rc; +} + + +static int s5k6aa_sensor_init_probe(const struct msm_camera_sensor_info *data) +{ + printk("[s5k6aa] %s/%d\n", __func__, __LINE__); + + int rc = 0; + int temp = 0; + int status = 0; + int count = 0; + gpio_tlmm_config(GPIO_CFG(CAM_1_3M_RST, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(CAM_1_3M_EN, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); +// gpio_tlmm_config(GPIO_CFG(CAM_I2C_SDA, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA), GPIO_CFG_ENABLE); +// gpio_tlmm_config(GPIO_CFG(CAM_I2C_SCL, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA), GPIO_CFG_ENABLE); + + gpio_set_value_cansleep(CAM_1_3M_RST, 0); + temp = gpio_get_value(CAM_1_3M_RST); + printk("[s5k6aa] CAM_1_3M_RST : %d\n", temp); + + gpio_set_value_cansleep(CAM_1_3M_EN, 0); + temp = gpio_get_value(CAM_1_3M_EN); + printk("[s5k6aa] CAM_1_3M_EN : %d\n", temp); + + cam_ldo_power_on_s5k6aa(); // move to msm_camera.c (Jeonhk 20110622) + mdelay(1); + gpio_set_value_cansleep(CAM_1_3M_EN, 1); + temp = gpio_get_value(CAM_1_3M_EN); + printk("[s5k6aa] CAM_1_3M_EN : %d\n", temp); + mdelay(1); + gpio_tlmm_config(GPIO_CFG(CAM_MCLK, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + msm_camio_clk_rate_set(24000000); + mdelay(10); + gpio_set_value_cansleep(CAM_1_3M_RST, 1); + temp = gpio_get_value(CAM_1_3M_RST); + printk("[s5k6aa] CAM_1_3M_RST : %d\n", temp); + + mdelay(100); + + S5K6AA_WRITE_LIST(s5k6aa_init_reg); + S5K6AA_WRITE_LIST(mode_preview_640x480); + + return rc; +} + + +int s5k6aa_sensor_init(const struct msm_camera_sensor_info *data) +{ + printk("[s5k6aa] %s/%d\n", __func__, __LINE__); + + int rc = 0; +// int i = 0; + +// s5k6aa_ctrl = kzalloc(sizeof(struct s5k6aa_ctrl), GFP_KERNEL); + if (!s5k6aa_ctrl) { + printk("s5k6aa_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + if (data) + s5k6aa_ctrl->sensordata = data; + + config_csi2 = 0; +#ifdef CONFIG_LOAD_FILE + s5k6aa_regs_table_init(); +#endif + + rc = s5k6aa_sensor_init_probe(data); + if (rc < 0) { + printk("s5k6aa_sensor_init failed!\n"); + goto init_fail; + } + +init_done: + return rc; + +init_fail: + kfree(s5k6aa_ctrl); + return rc; +} + +static int s5k6aa_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&s5k6aa_wait_queue); + return 0; +} + +int s5k6aa_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cfg_data; + long rc = 0; + + if (copy_from_user(&cfg_data, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + /* down(&s5k6aa_sem); */ + + printk("s5k6aa_ioctl, cfgtype = %d, mode = %d\n", + cfg_data.cfgtype, cfg_data.mode); + + switch (cfg_data.cfgtype) { + case CFG_SET_MODE: + rc = s5k6aa_set_sensor_mode( + cfg_data.mode); + break; + + case CFG_SET_EFFECT: + //rc = s5k6aa_set_effect(cfg_data.mode, cfg_data.cfg.effect); + break; + + case CFG_GET_AF_MAX_STEPS: + default: + rc = 0;//-EINVAL; + printk("s5k6aa_sensor_config : Invalid cfgtype ! %d\n",cfg_data.cfgtype); + break; + } + + /* up(&s5k6aa_sem); */ + + return rc; +} + +int s5k6aa_sensor_release(void) +{ + int rc = 0; + + printk("[s5k6aa] s5k6aa_sensor_release\n"); + + kfree(s5k6aa_ctrl); + /* up(&s5k6aa_sem); */ + +#ifdef CONFIG_LOAD_FILE + s5k6aa_regs_table_exit(); +#endif +/* gpio_set_value_cansleep(CAM_3M_RST, LOW); + mdelay(1); + gpio_set_value_cansleep(CAM_3M_STBY, LOW); + mdelay(1); +*/ +// gpio_set_value(CAM_IO_EN, 0); + cam_ldo_power_off_s5k6aa(); + return rc; +} + +static int s5k6aa_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + printk("111111111111111\n"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + printk("222222222222222\n"); + rc = -ENOTSUPP; + goto probe_failure; + } + + s5k6aa_sensorw = + kzalloc(sizeof(struct s5k6aa_work), GFP_KERNEL); + + if (!s5k6aa_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, s5k6aa_sensorw); + s5k6aa_init_client(client); + s5k6aa_client = client; + + + printk("s5k6aa_probe succeeded!\n"); + + return 0; + +probe_failure: + kfree(s5k6aa_sensorw); + s5k6aa_sensorw = NULL; + printk("s5k6aa_probe failed!\n"); + return rc; +} + +static const struct i2c_device_id s5k6aa_i2c_id[] = { + { "s5k6aa", 0}, + { }, +}; + +static struct i2c_driver s5k6aa_i2c_driver = { + .id_table = s5k6aa_i2c_id, + .probe = s5k6aa_i2c_probe, + .remove = __exit_p(s5k6aa_i2c_remove), + .driver = { + .name = "s5k6aa", + }, +}; + + +static int s5k6aa_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + printk("[s5k6aa] %s/%d\n", __func__, __LINE__); + int rc = i2c_add_driver(&s5k6aa_i2c_driver); + if (rc < 0 || s5k6aa_client == NULL) { + printk("[s5k6aa] %d/%d\n", rc, s5k6aa_client); + + rc = -ENOTSUPP; + goto probe_done; + } + + msm_camio_clk_rate_set(24000000); + +// rc = s5k6aa_sensor_init_probe(info); +// if (rc < 0) +// goto probe_done; + + s->s_init = s5k6aa_sensor_init; + s->s_release = s5k6aa_sensor_release; + s->s_config = s5k6aa_sensor_config; + s->s_camera_type = FRONT_CAMERA_2D; + s->s_mount_angle = 90; // HC - 0/180, GB - 90/270 + + +probe_done: + printk("%s %s:%d\n", __FILE__, __func__, __LINE__); + return rc; +} + + +static struct s5k6aa_format s5k6aa_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static int s5k6aa_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + printk(KERN_DEBUG "Index is %d\n", index); + if ((unsigned int)index >= ARRAY_SIZE(s5k6aa_subdev_info)) + return -EINVAL; + + *code = s5k6aa_subdev_info[index].code; + return 0; +} + +static struct v4l2_subdev_core_ops s5k6aa_subdev_core_ops; +static struct v4l2_subdev_video_ops s5k6aa_subdev_video_ops = { + .enum_mbus_fmt = s5k6aa_enum_fmt, +}; + +static struct v4l2_subdev_ops s5k6aa_subdev_ops = { + .core = &s5k6aa_subdev_core_ops, + .video = &s5k6aa_subdev_video_ops, +}; + +static int s5k6aa_sensor_probe_cb(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + printk("[s5k6aa] %s/%d\n", __func__, __LINE__); + int rc = 0; + rc = s5k6aa_sensor_probe(info, s); + if (rc < 0) + return rc; + + s5k6aa_ctrl = kzalloc(sizeof(struct s5k6aa_ctrl_t), GFP_KERNEL); + if (!s5k6aa_ctrl) { + printk("s5k6aa_sensor_probe failed!\n"); + return -ENOMEM; + } + + /* probe is successful, init a v4l2 subdevice */ + printk(KERN_DEBUG "going into v4l2_i2c_subdev_init\n"); + if (sdev) { + v4l2_i2c_subdev_init(sdev, s5k6aa_client, + &s5k6aa_subdev_ops); + s5k6aa_ctrl->sensor_dev = sdev; + } + else printk(KERN_DEBUG "[s5k6aa] sdev is null in probe_cb\n"); + + return rc; +} + +static int __s5k6aa_probe(struct platform_device *pdev) +{ + printk("############# S5K6AA probe ##############\n"); +#if 0 // sysfs for factory test + s5k6aa_dev = device_create(sec_class, NULL, 0, NULL, "sec_s5k6aa"); + + if (IS_ERR(s5k6aa_dev)) { + printk("Failed to create device!"); + return -1; + } + + if (device_create_file(s5k6aa_dev, &s5k6aa_cameraflash_attr) < 0) { + printk("Failed to create device file!(%s)!\n", s5k6aa_cameraflash_attr.attr.name); + return -1; + } + + if (device_create_file(s5k6aa_dev, &s5k6aa_camtype_attr) < 0) { + printk("Failed to create device file!(%s)!\n", s5k6aa_camtype_attr.attr.name); + return -1; + } +#endif + return msm_sensor_register(pdev, s5k6aa_sensor_probe_cb); +} + +static struct platform_driver msm_camera_driver = { + .probe = __s5k6aa_probe, + .driver = { + .name = "msm_camera_s5k6aa", + .owner = THIS_MODULE, + }, +}; + +static int __init s5k6aa_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(s5k6aa_init); diff --git a/drivers/media/video/msm_zsl/s5k8aay.h b/drivers/media/video/msm_zsl/s5k8aay.h new file mode 100644 index 00000000000..16bda6b3d3f --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k8aay.h @@ -0,0 +1,181 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __S5K8AAY_H__ +#define __S5K8AAY_H__ + +#include +#include + +#define S5K8AAY_DEBUG +#ifdef S5K8AAY_DEBUG +#define CAM_DEBUG(fmt, arg...) \ + do { printk(KERN_DEBUG "[%s:%d] " fmt "\033[0m\n",\ + __func__, __LINE__, ##arg); } \ + while (0) + +#define cam_info(fmt, arg...) \ + do { printk(KERN_INFO "[s5k8aay]" fmt "\n", ##arg); } \ + while (0) + +#define cam_err(fmt, arg...) \ + do { printk(KERN_ERR "[s5k8aay] %s:%d:" fmt "\n",\ + __func__, __LINE__, ##arg); } \ + while (0) + +#else +#define CAM_DEBUG(fmt, arg...) +#define cam_info(fmt, arg...) +#define cam_err(fmt, arg...) +#endif + +#define CAPTURE_FLASH 1 +#define MOVIE_FLASH 0 + +/* level at or below which we need to enable flash when in auto mode */ +#define LOW_LIGHT_LEVEL 0x20 + +/* DTP */ +#define DTP_OFF 0 +#define DTP_ON 1 +#define DTP_OFF_ACK 2 +#define DTP_ON_ACK 3 + +struct s5k8aay_userset { + unsigned int focus_mode; + unsigned int focus_status; + unsigned int continuous_af; + + unsigned int metering; + unsigned int exposure; + unsigned int wb; + unsigned int iso; + int contrast; + int saturation; + int sharpness; + int brightness; + int scene; + unsigned int zoom; + unsigned int effect; /* Color FX (AKA Color tone) */ + unsigned int scenemode; + unsigned int detectmode; + unsigned int antishake; + unsigned int fps; + unsigned int flash_mode; + unsigned int flash_state; + unsigned int stabilize; /* IS */ + unsigned int strobe; + unsigned int jpeg_quality; +/*unsigned int preview_size;*/ +/*struct m5mo_preview_size preview_size;*/ + unsigned int preview_size_idx; + unsigned int capture_size; + unsigned int thumbnail_size; +}; + +struct reg_struct_init { +/* --------PLL setting-------- */ + uint8_t pre_pll_clk_div; /* 0x0305 */ + uint8_t plstatim; /* 0x302b */ + uint8_t reg_3024; /*ox3024*/ + uint8_t image_orientation; /* 0x0101*/ + uint8_t vndmy_ablmgshlmt; /*0x300a*/ + uint8_t y_opbaddr_start_di; /*0x3014*/ + uint8_t reg_0x3015; /*0x3015*/ + uint8_t reg_0x301c; /*0x301c*/ + uint8_t reg_0x302c; /*0x302c*/ + uint8_t reg_0x3031; /*0x3031*/ + uint8_t reg_0x3041; /* 0x3041 */ + uint8_t reg_0x3051; /* 0x3051 */ + uint8_t reg_0x3053; /* 0x3053 */ + uint8_t reg_0x3057; /* 0x3057 */ + uint8_t reg_0x305c; /* 0x305c */ + uint8_t reg_0x305d; /* 0x305d */ + uint8_t reg_0x3060; /* 0x3060 */ + uint8_t reg_0x3065; /* 0x3065 */ + uint8_t reg_0x30aa; /* 0x30aa */ + uint8_t reg_0x30ab; + uint8_t reg_0x30b0; + uint8_t reg_0x30b2; + uint8_t reg_0x30d3; + uint8_t reg_0x3106; + uint8_t reg_0x310c; + uint8_t reg_0x3304; + uint8_t reg_0x3305; + uint8_t reg_0x3306; + uint8_t reg_0x3307; + uint8_t reg_0x3308; + uint8_t reg_0x3309; + uint8_t reg_0x330a; + uint8_t reg_0x330b; + uint8_t reg_0x330c; + uint8_t reg_0x330d; + uint8_t reg_0x330f; + uint8_t reg_0x3381; +}; + +struct reg_struct { + uint8_t pll_multiplier; /* 0x0307 */ + uint8_t frame_length_lines_hi; /* 0x0340*/ + uint8_t frame_length_lines_lo; /* 0x0341*/ + uint8_t y_addr_start; /* 0x347 */ + uint8_t y_add_end; /* 0x034b */ + uint8_t x_output_size_msb; /* 0x034c */ + uint8_t x_output_size_lsb; /* 0x034d */ + uint8_t y_output_size_msb; /* 0x034e */ + uint8_t y_output_size_lsb; /* 0x034f */ + uint8_t x_even_inc; /* 0x0381 */ + uint8_t x_odd_inc; /* 0x0383 */ + uint8_t y_even_inc; /* 0x0385 */ + uint8_t y_odd_inc; /* 0x0387 */ + uint8_t hmodeadd; /* 0x3001 */ + uint8_t vmodeadd; /* 0x3016 */ + uint8_t vapplinepos_start; /*ox3069*/ + uint8_t vapplinepos_end; /*306b*/ + uint8_t shutter; /* 0x3086 */ + uint8_t haddave; /* 0x30e8 */ + uint8_t lanesel; /* 0x3301 */ +}; + +struct s5k8aay_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum s5k8aay_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum s5k8aay_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +enum s5k8aay_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; +#endif /* __S5K8AAY_H__ */ diff --git a/drivers/media/video/msm_zsl/s5k8aay_regs.h b/drivers/media/video/msm_zsl/s5k8aay_regs.h new file mode 100644 index 00000000000..283092a2c8c --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k8aay_regs.h @@ -0,0 +1,3537 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifdef __S5K8AAY_H__ +#define __S5K8AAY_H__ + +struct s5k8aay_short_t { + unsigned short subaddr; + unsigned int value; +}; + +/*====================================== +* 8AA M0 Capture mode final setfile +* 1280x960, 7.5fps, no binning, YUV422 +* Includes LT, FE, AS, WB, Outdoor detector, +* Pre/Post Gamma, CCM, Gamma and AFIT +========================================*/ + +struct s5k8aay_short_t s5k8aay_common[] = { +{0x0028, 0xD000}, +{0x002A, 0x0010}, +{0x0F12, 0x0001}, +{0x0028, 0x0000}, +{0x002A, 0x0000}, +{0x0F12, 0x0000}, +{0x0028, 0xD000}, +{0x002A, 0x1030}, +{0x0F12, 0x0000}, +{0x002A, 0x0014}, +{0x0F12, 0x0001}, +{0xffff, 0x0001}, +{0x0028, 0x7000}, +{0x002A, 0x2460}, +{0x0F12, 0xB510}, +{0x0F12, 0x490C}, +{0x0F12, 0x480C}, +{0x0F12, 0xF000}, +{0x0F12, 0xFB71}, +{0x0F12, 0x490C}, +{0x0F12, 0x480C}, +{0x0F12, 0xF000}, +{0x0F12, 0xFB6D}, +{0x0F12, 0x490C}, +{0x0F12, 0x480C}, +{0x0F12, 0xF000}, +{0x0F12, 0xFB69}, +{0x0F12, 0x490C}, +{0x0F12, 0x480C}, +{0x0F12, 0xF000}, +{0x0F12, 0xFB65}, +{0x0F12, 0x490C}, +{0x0F12, 0x480C}, +{0x0F12, 0x6241}, +{0x0F12, 0x490C}, +{0x0F12, 0x6341}, +{0x0F12, 0xBC10}, +{0x0F12, 0xBC08}, +{0x0F12, 0x4718}, +{0x0F12, 0x0000}, +{0x0F12, 0x2998}, +{0x0F12, 0x7000}, +{0x0F12, 0x27B7}, +{0x0F12, 0x0000}, +{0x0F12, 0x2690}, +{0x0F12, 0x7000}, +{0x0F12, 0x25DD}, +{0x0F12, 0x0000}, +{0x0F12, 0x2650}, +{0x0F12, 0x7000}, +{0x0F12, 0x9DC7}, +{0x0F12, 0x0000}, +{0x0F12, 0x24C0}, +{0x0F12, 0x7000}, +{0x0F12, 0x49CD}, +{0x0F12, 0x0000}, +{0x0F12, 0x2A65}, +{0x0F12, 0x7000}, +{0x0F12, 0x0080}, +{0x0F12, 0x7000}, +{0x0F12, 0x2A8F}, +{0x0F12, 0x7000}, +{0x0F12, 0x4070}, +{0x0F12, 0xE92D}, +{0x0F12, 0x0000}, +{0x0F12, 0xE590}, +{0x0F12, 0x10B6}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x200D}, +{0x0F12, 0xE5D0}, +{0x0F12, 0x1002}, +{0x0F12, 0xE081}, +{0x0F12, 0x0008}, +{0x0F12, 0xE351}, +{0x0F12, 0x0003}, +{0x0F12, 0x3A00}, +{0x0F12, 0x20B2}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x1002}, +{0x0F12, 0xE081}, +{0x0F12, 0x0B01}, +{0x0F12, 0xE351}, +{0x0F12, 0x0001}, +{0x0F12, 0x9A00}, +{0x0F12, 0x1001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0000}, +{0x0F12, 0xEA00}, +{0x0F12, 0x1000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x44F0}, +{0x0F12, 0xE59F}, +{0x0F12, 0x10FB}, +{0x0F12, 0xE5C4}, +{0x0F12, 0xC4EC}, +{0x0F12, 0xE59F}, +{0x0F12, 0x10B2}, +{0x0F12, 0xE1DC}, +{0x0F12, 0x0C02}, +{0x0F12, 0xE311}, +{0x0F12, 0x0009}, +{0x0F12, 0x0A00}, +{0x0F12, 0x10B4}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x200C}, +{0x0F12, 0xE5D0}, +{0x0F12, 0x1002}, +{0x0F12, 0xE081}, +{0x0F12, 0x20B0}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x1002}, +{0x0F12, 0xE081}, +{0x0F12, 0x24CC}, +{0x0F12, 0xE59F}, +{0x0F12, 0x0002}, +{0x0F12, 0xE151}, +{0x0F12, 0x0001}, +{0x0F12, 0x9A00}, +{0x0F12, 0x1001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0000}, +{0x0F12, 0xEA00}, +{0x0F12, 0x1000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x10FA}, +{0x0F12, 0xE5C4}, +{0x0F12, 0x14B4}, +{0x0F12, 0xE59F}, +{0x0F12, 0xE4B4}, +{0x0F12, 0xE59F}, +{0x0F12, 0x200C}, +{0x0F12, 0xE5D0}, +{0x0F12, 0x11B6}, +{0x0F12, 0xE1D1}, +{0x0F12, 0x35B2}, +{0x0F12, 0xE1DE}, +{0x0F12, 0x5001}, +{0x0F12, 0xE082}, +{0x0F12, 0x0003}, +{0x0F12, 0xE155}, +{0x0F12, 0x0014}, +{0x0F12, 0x3A00}, +{0x0F12, 0x50B4}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x3001}, +{0x0F12, 0xE083}, +{0x0F12, 0x3C05}, +{0x0F12, 0xE283}, +{0x0F12, 0x2005}, +{0x0F12, 0xE082}, +{0x0F12, 0x50B0}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x2005}, +{0x0F12, 0xE082}, +{0x0F12, 0x0003}, +{0x0F12, 0xE152}, +{0x0F12, 0x000C}, +{0x0F12, 0x8A00}, +{0x0F12, 0x200D}, +{0x0F12, 0xE5D0}, +{0x0F12, 0x35B4}, +{0x0F12, 0xE1DE}, +{0x0F12, 0x5001}, +{0x0F12, 0xE082}, +{0x0F12, 0x0003}, +{0x0F12, 0xE155}, +{0x0F12, 0x0007}, +{0x0F12, 0x3A00}, +{0x0F12, 0xE0B6}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x1003}, +{0x0F12, 0xE081}, +{0x0F12, 0x1D0F}, +{0x0F12, 0xE281}, +{0x0F12, 0x200E}, +{0x0F12, 0xE082}, +{0x0F12, 0xE0B2}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x200E}, +{0x0F12, 0xE082}, +{0x0F12, 0x0001}, +{0x0F12, 0xE152}, +{0x0F12, 0x0001}, +{0x0F12, 0x9A00}, +{0x0F12, 0x1001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0000}, +{0x0F12, 0xEA00}, +{0x0F12, 0x1000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x10FC}, +{0x0F12, 0xE5C4}, +{0x0F12, 0x0022}, +{0x0F12, 0xE5D0}, +{0x0F12, 0x10F9}, +{0x0F12, 0xE5D4}, +{0x0F12, 0x0001}, +{0x0F12, 0xE150}, +{0x0F12, 0x001C}, +{0x0F12, 0x0A00}, +{0x0F12, 0x00F9}, +{0x0F12, 0xE5C4}, +{0x0F12, 0x20F9}, +{0x0F12, 0xE5D4}, +{0x0F12, 0x1004}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0018}, +{0x0F12, 0xE28C}, +{0x0F12, 0x015C}, +{0x0F12, 0xEB00}, +{0x0F12, 0x00F9}, +{0x0F12, 0xE5D4}, +{0x0F12, 0x0000}, +{0x0F12, 0xE350}, +{0x0F12, 0x0001}, +{0x0F12, 0x1A00}, +{0x0F12, 0x0001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0000}, +{0x0F12, 0xEA00}, +{0x0F12, 0x0000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x13FC}, +{0x0F12, 0xE59F}, +{0x0F12, 0x08B8}, +{0x0F12, 0xE1C1}, +{0x0F12, 0x08BA}, +{0x0F12, 0xE1C1}, +{0x0F12, 0x0007}, +{0x0F12, 0x0A00}, +{0x0F12, 0x13F0}, +{0x0F12, 0xE59F}, +{0x0F12, 0x0001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x00B0}, +{0x0F12, 0xE1C1}, +{0x0F12, 0x000A}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0150}, +{0x0F12, 0xEB00}, +{0x0F12, 0x4070}, +{0x0F12, 0xE8BD}, +{0x0F12, 0x000B}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x014D}, +{0x0F12, 0xEA00}, +{0x0F12, 0x014F}, +{0x0F12, 0xEB00}, +{0x0F12, 0x000A}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0150}, +{0x0F12, 0xEB00}, +{0x0F12, 0x4070}, +{0x0F12, 0xE8BD}, +{0x0F12, 0x000B}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x014D}, +{0x0F12, 0xEA00}, +{0x0F12, 0x4070}, +{0x0F12, 0xE8BD}, +{0x0F12, 0xFF1E}, +{0x0F12, 0xE12F}, +{0x0F12, 0x4010}, +{0x0F12, 0xE92D}, +{0x0F12, 0x0000}, +{0x0F12, 0xE590}, +{0x0F12, 0x40FF}, +{0x0F12, 0xE200}, +{0x0F12, 0x2004}, +{0x0F12, 0xE1A0}, +{0x0F12, 0x1001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0CC1}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0147}, +{0x0F12, 0xEB00}, +{0x0F12, 0x0000}, +{0x0F12, 0xE354}, +{0x0F12, 0x0002}, +{0x0F12, 0x1A00}, +{0x0F12, 0x1390}, +{0x0F12, 0xE59F}, +{0x0F12, 0x0C01}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x00B2}, +{0x0F12, 0xE1C1}, +{0x0F12, 0x0388}, +{0x0F12, 0xE59F}, +{0x0F12, 0x4000}, +{0x0F12, 0xE5C0}, +{0x0F12, 0x4010}, +{0x0F12, 0xE8BD}, +{0x0F12, 0xFF1E}, +{0x0F12, 0xE12F}, +{0x0F12, 0x4FF8}, +{0x0F12, 0xE92D}, +{0x0F12, 0x0000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x013E}, +{0x0F12, 0xEB00}, +{0x0F12, 0x5000}, +{0x0F12, 0xE1A0}, +{0x0F12, 0xB36C}, +{0x0F12, 0xE59F}, +{0x0F12, 0x8001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x80B0}, +{0x0F12, 0xE1CB}, +{0x0F12, 0x7340}, +{0x0F12, 0xE59F}, +{0x0F12, 0xA000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0xA0B2}, +{0x0F12, 0xE1C7}, +{0x0F12, 0x0000}, +{0x0F12, 0xE355}, +{0x0F12, 0x004A}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0137}, +{0x0F12, 0xEB00}, +{0x0F12, 0x0015}, +{0x0F12, 0xE355}, +{0x0F12, 0x0004}, +{0x0F12, 0x1A00}, +{0x0F12, 0x1344}, +{0x0F12, 0xE59F}, +{0x0F12, 0x0344}, +{0x0F12, 0xE59F}, +{0x0F12, 0x18BE}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x1340}, +{0x0F12, 0xE59F}, +{0x0F12, 0x19B0}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x133C}, +{0x0F12, 0xE59F}, +{0x0F12, 0x933C}, +{0x0F12, 0xE59F}, +{0x0F12, 0x0001}, +{0x0F12, 0xE155}, +{0x0F12, 0x0001}, +{0x0F12, 0xE045}, +{0x0F12, 0x4C02}, +{0x0F12, 0xE289}, +{0x0F12, 0x6C01}, +{0x0F12, 0xE289}, +{0x0F12, 0x0019}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0006}, +{0x0F12, 0xCA00}, +{0x0F12, 0x0015}, +{0x0F12, 0xE355}, +{0x0F12, 0x0010}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0016}, +{0x0F12, 0xE355}, +{0x0F12, 0x0014}, +{0x0F12, 0x0A00}, +{0x0F12, 0x001D}, +{0x0F12, 0xE355}, +{0x0F12, 0x0034}, +{0x0F12, 0x1A00}, +{0x0F12, 0x0006}, +{0x0F12, 0xEA00}, +{0x0F12, 0x0007}, +{0x0F12, 0xE350}, +{0x0F12, 0x0004}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0C02}, +{0x0F12, 0xE240}, +{0x0F12, 0x0007}, +{0x0F12, 0xE250}, +{0x0F12, 0x0001}, +{0x0F12, 0x0A00}, +{0x0F12, 0x00F8}, +{0x0F12, 0xE350}, +{0x0F12, 0x002C}, +{0x0F12, 0x1A00}, +{0x0F12, 0xB2EC}, +{0x0F12, 0xE59F}, +{0x0F12, 0x001D}, +{0x0F12, 0xE355}, +{0x0F12, 0x002B}, +{0x0F12, 0x1A00}, +{0x0F12, 0x0002}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x002A}, +{0x0F12, 0xEA00}, +{0x0F12, 0x02DC}, +{0x0F12, 0xE59F}, +{0x0F12, 0x82B4}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x22D8}, +{0x0F12, 0xE59F}, +{0x0F12, 0x20BE}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x0002}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x00B2}, +{0x0F12, 0xE1C7}, +{0x0F12, 0x00B2}, +{0x0F12, 0xE1D7}, +{0x0F12, 0x0015}, +{0x0F12, 0xE380}, +{0x0F12, 0x00B2}, +{0x0F12, 0xE1C7}, +{0x0F12, 0x0005}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x08B6}, +{0x0F12, 0xE1C6}, +{0x0F12, 0x08BA}, +{0x0F12, 0xE1D6}, +{0x0F12, 0x0040}, +{0x0F12, 0xE380}, +{0x0F12, 0x08BA}, +{0x0F12, 0xE1C6}, +{0x0F12, 0x87B6}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x87B4}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x83B6}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x000C}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x00B0}, +{0x0F12, 0xE1CB}, +{0x0F12, 0x0016}, +{0x0F12, 0xE355}, +{0x0F12, 0x0001}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0001}, +{0x0F12, 0xE155}, +{0x0F12, 0x0001}, +{0x0F12, 0x1A00}, +{0x0F12, 0x1001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0000}, +{0x0F12, 0xEA00}, +{0x0F12, 0x1000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0016}, +{0x0F12, 0xE355}, +{0x0F12, 0x0001}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0000}, +{0x0F12, 0xEA00}, +{0x0F12, 0x0001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x00F8}, +{0x0F12, 0xEB00}, +{0x0F12, 0x0DBA}, +{0x0F12, 0xE1D4}, +{0x0F12, 0x0006}, +{0x0F12, 0xE3C0}, +{0x0F12, 0x0DBA}, +{0x0F12, 0xE1C4}, +{0x0F12, 0xA9BC}, +{0x0F12, 0xE1C4}, +{0x0F12, 0xA9BA}, +{0x0F12, 0xE1C4}, +{0x0F12, 0x89BE}, +{0x0F12, 0xE1C4}, +{0x0F12, 0x024C}, +{0x0F12, 0xE59F}, +{0x0F12, 0xA4B0}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x4FF8}, +{0x0F12, 0xE8BD}, +{0x0F12, 0xFF1E}, +{0x0F12, 0xE12F}, +{0x0F12, 0x0003}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0000}, +{0x0F12, 0xE58D}, +{0x0F12, 0x00EE}, +{0x0F12, 0xEB00}, +{0x0F12, 0x0FFA}, +{0x0F12, 0xE350}, +{0x0F12, 0x0001}, +{0x0F12, 0x9A00}, +{0x0F12, 0x00EB}, +{0x0F12, 0xEB00}, +{0x0F12, 0xB100}, +{0x0F12, 0xE1A0}, +{0x0F12, 0xB0B0}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x082B}, +{0x0F12, 0xE1A0}, +{0x0F12, 0x00B2}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x0000}, +{0x0F12, 0xE59D}, +{0x0F12, 0x003B}, +{0x0F12, 0xE1A0}, +{0x0F12, 0x02B0}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x01BE}, +{0x0F12, 0xE1C9}, +{0x0F12, 0xA2B2}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x0007}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x08B6}, +{0x0F12, 0xE1C6}, +{0x0F12, 0x09B4}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x87B2}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x87B0}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x85BC}, +{0x0F12, 0xE1C4}, +{0x0F12, 0x83B6}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x01E4}, +{0x0F12, 0xE59F}, +{0x0F12, 0xA4B0}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x11E0}, +{0x0F12, 0xE59F}, +{0x0F12, 0x0001}, +{0x0F12, 0xE155}, +{0x0F12, 0x00F8}, +{0x0F12, 0xE281}, +{0x0F12, 0x0001}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0000}, +{0x0F12, 0xE155}, +{0x0F12, 0x000B}, +{0x0F12, 0x1A00}, +{0x0F12, 0xA6B2}, +{0x0F12, 0xE1C4}, +{0x0F12, 0xA6B4}, +{0x0F12, 0xE1C4}, +{0x0F12, 0x2D16}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x25BE}, +{0x0F12, 0xE1C4}, +{0x0F12, 0x202A}, +{0x0F12, 0xE242}, +{0x0F12, 0x26B0}, +{0x0F12, 0xE1C4}, +{0x0F12, 0x2003}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x2AB4}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x21AC}, +{0x0F12, 0xE59F}, +{0x0F12, 0x2ABC}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x2F96}, +{0x0F12, 0xE242}, +{0x0F12, 0x2ABE}, +{0x0F12, 0xE1C9}, +{0x0F12, 0x2DBA}, +{0x0F12, 0xE1D4}, +{0x0F12, 0x2006}, +{0x0F12, 0xE3C2}, +{0x0F12, 0x2DBA}, +{0x0F12, 0xE1C4}, +{0x0F12, 0xA9BC}, +{0x0F12, 0xE1C4}, +{0x0F12, 0xA9BA}, +{0x0F12, 0xE1C4}, +{0x0F12, 0x89BE}, +{0x0F12, 0xE1C4}, +{0x0F12, 0x0001}, +{0x0F12, 0xE155}, +{0x0F12, 0xE006}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x0003}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0000}, +{0x0F12, 0xE155}, +{0x0F12, 0x0001}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0174}, +{0x0F12, 0xE59F}, +{0x0F12, 0xE0B0}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x001D}, +{0x0F12, 0xE355}, +{0x0F12, 0x002C}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0F47}, +{0x0F12, 0xE3E0}, +{0x0F12, 0x0005}, +{0x0F12, 0xE090}, +{0x0F12, 0x0026}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0FBE}, +{0x0F12, 0xE350}, +{0x0F12, 0x0002}, +{0x0F12, 0x1A00}, +{0x0F12, 0x1154}, +{0x0F12, 0xE59F}, +{0x0F12, 0x0010}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x05B4}, +{0x0F12, 0xE1C1}, +{0x0F12, 0x014C}, +{0x0F12, 0xE59F}, +{0x0F12, 0x00B2}, +{0x0F12, 0xE1C7}, +{0x0F12, 0x0148}, +{0x0F12, 0xE59F}, +{0x0F12, 0x1CBA}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x2CBE}, +{0x0F12, 0xE1D0}, +{0x0F12, 0x3DB2}, +{0x0F12, 0xE1D0}, +{0x0F12, 0xC001}, +{0x0F12, 0xE042}, +{0x0F12, 0xC003}, +{0x0F12, 0xE08C}, +{0x0F12, 0x4C05}, +{0x0F12, 0xE28C}, +{0x0F12, 0x4055}, +{0x0F12, 0xE284}, +{0x0F12, 0x4DB6}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x1EBA}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x2EBE}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x3FB2}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x1C02}, +{0x0F12, 0xE28C}, +{0x0F12, 0x10AA}, +{0x0F12, 0xE281}, +{0x0F12, 0x1FB6}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x1110}, +{0x0F12, 0xE59F}, +{0x0F12, 0x0110}, +{0x0F12, 0xE59F}, +{0x0F12, 0x1BBA}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x10C1}, +{0x0F12, 0xE1A0}, +{0x0F12, 0x1BBC}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x0104}, +{0x0F12, 0xE59F}, +{0x0F12, 0x100C}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x19BE}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x1008}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x1AB2}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x0C01}, +{0x0F12, 0xE280}, +{0x0F12, 0xABBA}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x0C03}, +{0x0F12, 0xE240}, +{0x0F12, 0x81BC}, +{0x0F12, 0xE1C0}, +{0x0F12, 0x82BC}, +{0x0F12, 0xE1C0}, +{0x0F12, 0xE1BE}, +{0x0F12, 0xE1C0}, +{0x0F12, 0xFF9A}, +{0x0F12, 0xEAFF}, +{0x0F12, 0x0081}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x00B2}, +{0x0F12, 0xE1C7}, +{0x0F12, 0xFF97}, +{0x0F12, 0xEAFF}, +{0x0F12, 0x00CC}, +{0x0F12, 0xE59F}, +{0x0F12, 0x00B2}, +{0x0F12, 0xE1C7}, +{0x0F12, 0xFF94}, +{0x0F12, 0xEAFF}, +{0x0F12, 0x1000}, +{0x0F12, 0xE590}, +{0x0F12, 0x001D}, +{0x0F12, 0xE351}, +{0x0F12, 0x000A}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0004}, +{0x0F12, 0xCA00}, +{0x0F12, 0x0015}, +{0x0F12, 0xE351}, +{0x0F12, 0x0007}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0016}, +{0x0F12, 0xE351}, +{0x0F12, 0x0009}, +{0x0F12, 0x1A00}, +{0x0F12, 0x0004}, +{0x0F12, 0xEA00}, +{0x0F12, 0x2F47}, +{0x0F12, 0xE3E0}, +{0x0F12, 0x1002}, +{0x0F12, 0xE091}, +{0x0F12, 0x0001}, +{0x0F12, 0x0A00}, +{0x0F12, 0x0C02}, +{0x0F12, 0xE351}, +{0x0F12, 0x0003}, +{0x0F12, 0x1A00}, +{0x0F12, 0x1001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x1000}, +{0x0F12, 0xE580}, +{0x0F12, 0x0001}, +{0x0F12, 0xE3A0}, +{0x0F12, 0xFF1E}, +{0x0F12, 0xE12F}, +{0x0F12, 0x1000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0x1000}, +{0x0F12, 0xE580}, +{0x0F12, 0x0000}, +{0x0F12, 0xE3A0}, +{0x0F12, 0xFFFA}, +{0x0F12, 0xEAFF}, +{0x0F12, 0x1760}, +{0x0F12, 0x7000}, +{0x0F12, 0x1718}, +{0x0F12, 0x7000}, +{0x0F12, 0x057C}, +{0x0F12, 0x0000}, +{0x0F12, 0x0A86}, +{0x0F12, 0x7000}, +{0x0F12, 0x0E2C}, +{0x0F12, 0x7000}, +{0x0F12, 0x20C4}, +{0x0F12, 0x7000}, +{0x0F12, 0x187C}, +{0x0F12, 0x7000}, +{0x0F12, 0xC100}, +{0x0F12, 0xD000}, +{0x0F12, 0x232C}, +{0x0F12, 0x7000}, +{0x0F12, 0x3600}, +{0x0F12, 0xD000}, +{0x0F12, 0x3333}, +{0x0F12, 0x0000}, +{0x0F12, 0x1200}, +{0x0F12, 0xD000}, +{0x0F12, 0x2107}, +{0x0F12, 0x0000}, +{0x0F12, 0x0116}, +{0x0F12, 0x0000}, +{0x0F12, 0x012E}, +{0x0F12, 0x7000}, +{0x0F12, 0xC350}, +{0x0F12, 0x0000}, +{0x0F12, 0x0200}, +{0x0F12, 0xD000}, +{0x0F12, 0x0F88}, +{0x0F12, 0x0000}, +{0x0F12, 0x042C}, +{0x0F12, 0x7000}, +{0x0F12, 0x031D}, +{0x0F12, 0x0000}, +{0x0F12, 0x0834}, +{0x0F12, 0x0000}, +{0x0F12, 0x3000}, +{0x0F12, 0xD000}, +{0x0F12, 0xB000}, +{0x0F12, 0xD000}, +{0x0F12, 0x0203}, +{0x0F12, 0x0000}, +{0x0F12, 0x0F2C}, +{0x0F12, 0x7000}, +{0x0F12, 0x0555}, +{0x0F12, 0x0000}, +{0x0F12, 0xF500}, +{0x0F12, 0xD000}, +{0x0F12, 0x102C}, +{0x0F12, 0x7000}, +{0x0F12, 0x0101}, +{0x0F12, 0x0000}, +{0x0F12, 0xB510}, +{0x0F12, 0xF000}, +{0x0F12, 0xF8AF}, +{0x0F12, 0x482C}, +{0x0F12, 0x7F00}, +{0x0F12, 0x2801}, +{0x0F12, 0xD00A}, +{0x0F12, 0x482B}, +{0x0F12, 0x8940}, +{0x0F12, 0x07C0}, +{0x0F12, 0xD006}, +{0x0F12, 0x4828}, +{0x0F12, 0x2180}, +{0x0F12, 0x3820}, +{0x0F12, 0x8B02}, +{0x0F12, 0x4828}, +{0x0F12, 0xF000}, +{0x0F12, 0xF8A8}, +{0x0F12, 0xBC10}, +{0x0F12, 0xBC08}, +{0x0F12, 0x4718}, +{0x0F12, 0xB5F8}, +{0x0F12, 0xF000}, +{0x0F12, 0xF8AA}, +{0x0F12, 0x4821}, +{0x0F12, 0x7F00}, +{0x0F12, 0x2801}, +{0x0F12, 0xD03C}, +{0x0F12, 0x4820}, +{0x0F12, 0x8940}, +{0x0F12, 0x07C0}, +{0x0F12, 0xD038}, +{0x0F12, 0x481D}, +{0x0F12, 0x2218}, +{0x0F12, 0x3020}, +{0x0F12, 0x2512}, +{0x0F12, 0x5E82}, +{0x0F12, 0x5F45}, +{0x0F12, 0x1B51}, +{0x0F12, 0x17CB}, +{0x0F12, 0x0F9B}, +{0x0F12, 0x1859}, +{0x0F12, 0x108B}, +{0x0F12, 0x261E}, +{0x0F12, 0x5F86}, +{0x0F12, 0x1AB1}, +{0x0F12, 0x17CC}, +{0x0F12, 0x0FA4}, +{0x0F12, 0x1861}, +{0x0F12, 0x108C}, +{0x0F12, 0x4917}, +{0x0F12, 0x8849}, +{0x0F12, 0x1949}, +{0x0F12, 0x18CD}, +{0x0F12, 0x4916}, +{0x0F12, 0x810D}, +{0x0F12, 0x4D16}, +{0x0F12, 0x886F}, +{0x0F12, 0x8AC5}, +{0x0F12, 0x197F}, +{0x0F12, 0x814F}, +{0x0F12, 0x4F15}, +{0x0F12, 0x887F}, +{0x0F12, 0x197D}, +{0x0F12, 0x18EB}, +{0x0F12, 0x818B}, +{0x0F12, 0x4B13}, +{0x0F12, 0x885B}, +{0x0F12, 0x189B}, +{0x0F12, 0x81CB}, +{0x0F12, 0x4B12}, +{0x0F12, 0x885B}, +{0x0F12, 0x189A}, +{0x0F12, 0x1912}, +{0x0F12, 0x820A}, +{0x0F12, 0x4A11}, +{0x0F12, 0x8B80}, +{0x0F12, 0x8852}, +{0x0F12, 0x1812}, +{0x0F12, 0x824A}, +{0x0F12, 0x4A0F}, +{0x0F12, 0x8852}, +{0x0F12, 0x1810}, +{0x0F12, 0x1900}, +{0x0F12, 0x8288}, +{0x0F12, 0x480E}, +{0x0F12, 0x8840}, +{0x0F12, 0x1980}, +{0x0F12, 0x82C8}, +{0x0F12, 0xBCF8}, +{0x0F12, 0xBC08}, +{0x0F12, 0x4718}, +{0x0F12, 0x2350}, +{0x0F12, 0x7000}, +{0x0F12, 0x112C}, +{0x0F12, 0x7000}, +{0x0F12, 0xF402}, +{0x0F12, 0x0000}, +{0x0F12, 0x0F94}, +{0x0F12, 0x7000}, +{0x0F12, 0xF4A0}, +{0x0F12, 0xD000}, +{0x0F12, 0x0F98}, +{0x0F12, 0x7000}, +{0x0F12, 0x0F9C}, +{0x0F12, 0x7000}, +{0x0F12, 0x0FA0}, +{0x0F12, 0x7000}, +{0x0F12, 0x0FA4}, +{0x0F12, 0x7000}, +{0x0F12, 0x0FA8}, +{0x0F12, 0x7000}, +{0x0F12, 0x0FAC}, +{0x0F12, 0x7000}, +{0x0F12, 0x0FB0}, +{0x0F12, 0x7000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0xBF01}, +{0x0F12, 0x0000}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x2E89}, +{0x0F12, 0x0000}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x1DEF}, +{0x0F12, 0x0000}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x5137}, +{0x0F12, 0x0000}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x1E0F}, +{0x0F12, 0x0000}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x2EA7}, +{0x0F12, 0x0000}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x25AD}, +{0x0F12, 0x0000}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x055F}, +{0x0F12, 0x0000}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x256B}, +{0x0F12, 0x0000}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x2D27}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0xA5ED}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x2EA7}, +{0x0F12, 0x0000}, +{0x0F12, 0x4778}, +{0x0F12, 0x46C0}, +{0x0F12, 0xC000}, +{0x0F12, 0xE59F}, +{0x0F12, 0xFF1C}, +{0x0F12, 0xE12F}, +{0x0F12, 0x2AF5}, +{0x0F12, 0x0000}, +{0x0F12, 0x8E66}, +{0x0F12, 0x0000}, +{0x002A, 0x0E8E}, +{0x0F12, 0x0005}, +{0x002A, 0x0E92}, +{0x0F12, 0x0693}, +{0x002A, 0x0E96}, +{0x0F12, 0x0001}, +{0x002A, 0x0E9A}, +{0x0F12, 0x0693}, +{0x002A, 0x0E9E}, +{0x0F12, 0x0001}, +{0x002A, 0x0EA2}, +{0x0F12, 0x0693}, +{0x002A, 0x0EA6}, +{0x0F12, 0x0009}, +{0x002A, 0x0EAA}, +{0x0F12, 0x0690}, +{0x002A, 0x0EAE}, +{0x0F12, 0x0009}, +{0x002A, 0x0EB2}, +{0x0F12, 0x0690}, +{0x002A, 0x0EB6}, +{0x0F12, 0x020B}, +{0x002A, 0x0EBA}, +{0x0F12, 0x025C}, +{0x002A, 0x0EBE}, +{0x0F12, 0x020B}, +{0x002A, 0x0EC2}, +{0x0F12, 0x025C}, +{0x002A, 0x0EC6}, +{0x0F12, 0x0007}, +{0x002A, 0x0ECA}, +{0x0F12, 0x0698}, +{0x002A, 0x0ECE}, +{0x0F12, 0x0007}, +{0x002A, 0x0ED2}, +{0x0F12, 0x0698}, +{0x002A, 0x0ED6}, +{0x0F12, 0x002D}, +{0x002A, 0x0EDA}, +{0x0F12, 0x0003}, +{0x002A, 0x0EDE}, +{0x0F12, 0x002D}, +{0x002A, 0x0EE2}, +{0x0F12, 0x0003}, +{0x002A, 0x0EE6}, +{0x0F12, 0x007A}, +{0x002A, 0x0EEA}, +{0x0F12, 0x0052}, +{0x002A, 0x0EEE}, +{0x0F12, 0x002A}, +{0x002A, 0x0EF2}, +{0x0F12, 0x0006}, +{0x002A, 0x0EF6}, +{0x0F12, 0x007A}, +{0x002A, 0x0EFA}, +{0x0F12, 0x0052}, +{0x002A, 0x0EFE}, +{0x0F12, 0x002A}, +{0x002A, 0x0F02}, +{0x0F12, 0x0006}, +{0x002A, 0x0F06}, +{0x0F12, 0x007D}, +{0x002A, 0x0F0A}, +{0x0F12, 0x004F}, +{0x002A, 0x0F0E}, +{0x0F12, 0x007D}, +{0x002A, 0x0F12}, +{0x0F12, 0x004F}, +{0x002A, 0x0F16}, +{0x0F12, 0x002E}, +{0x002A, 0x0F1A}, +{0x0F12, 0x0002}, +{0x002A, 0x0F1E}, +{0x0F12, 0x002E}, +{0x002A, 0x0F22}, +{0x0F12, 0x0002}, +{0x002A, 0x0F26}, +{0x0F12, 0x000C}, +{0x002A, 0x0F2A}, +{0x0F12, 0x0205}, +{0x002A, 0x0F2E}, +{0x0F12, 0x0268}, +{0x002A, 0x0F32}, +{0x0F12, 0x068E}, +{0x002A, 0x0F36}, +{0x0F12, 0x0000}, +{0x002A, 0x0F3A}, +{0x0F12, 0x0000}, +{0x002A, 0x0F3E}, +{0x0F12, 0x0000}, +{0x002A, 0x0F42}, +{0x0F12, 0x0000}, +{0x002A, 0x0F46}, +{0x0F12, 0x000C}, +{0x002A, 0x0F4A}, +{0x0F12, 0x0052}, +{0x002A, 0x0F4E}, +{0x0F12, 0x0000}, +{0x002A, 0x0F52}, +{0x0F12, 0x0000}, +{0x002A, 0x0F56}, +{0x0F12, 0x000C}, +{0x002A, 0x0F5A}, +{0x0F12, 0x0055}, +{0x002A, 0x0F5E}, +{0x0F12, 0x0000}, +{0x002A, 0x0F62}, +{0x0F12, 0x0000}, +{0x002A, 0x0F66}, +{0x0F12, 0x0001}, +{0x002A, 0x0F6A}, +{0x0F12, 0x0208}, +{0x002A, 0x0F6E}, +{0x0F12, 0x0000}, +{0x002A, 0x0F72}, +{0x0F12, 0x0000}, +{0x002A, 0x0F76}, +{0x0F12, 0x007F}, +{0x002A, 0x0F7A}, +{0x0F12, 0x0205}, +{0x002A, 0x0F7E}, +{0x0F12, 0x02C8}, +{0x002A, 0x0F82}, +{0x0F12, 0x068E}, +{0x002A, 0x0F86}, +{0x0F12, 0x0000}, +{0x002A, 0x0F8A}, +{0x0F12, 0x0000}, +{0x002A, 0x0F8E}, +{0x0F12, 0x0000}, +{0x002A, 0x0F92}, +{0x0F12, 0x0000}, +{0x002A, 0x0F96}, +{0x0F12, 0x00E2}, +{0x002A, 0x0F9A}, +{0x0F12, 0x0142}, +{0x002A, 0x0F9E}, +{0x0F12, 0x01A2}, +{0x002A, 0x0FA2}, +{0x0F12, 0x0208}, +{0x002A, 0x0FA6}, +{0x0F12, 0x03BB}, +{0x002A, 0x0FAA}, +{0x0F12, 0x04AB}, +{0x002A, 0x0FAE}, +{0x0F12, 0x059B}, +{0x002A, 0x0FB2}, +{0x0F12, 0x0691}, +{0x002A, 0x0FB6}, +{0x0F12, 0x020D}, +{0x002A, 0x0FBA}, +{0x0F12, 0x0262}, +{0x002A, 0x0FBE}, +{0x0F12, 0x0000}, +{0x002A, 0x0FC2}, +{0x0F12, 0x0000}, +{0x002A, 0x0FC6}, +{0x0F12, 0x0000}, +{0x002A, 0x0FCA}, +{0x0F12, 0x0000}, +{0x002A, 0x0FCE}, +{0x0F12, 0x0000}, +{0x002A, 0x0FD2}, +{0x0F12, 0x0000}, +{0x002A, 0x0FD6}, +{0x0F12, 0x0062}, +{0x002A, 0x0FDA}, +{0x0F12, 0x0691}, +{0x002A, 0x0FDE}, +{0x0F12, 0x0000}, +{0x002A, 0x0FE2}, +{0x0F12, 0x0000}, +{0x002A, 0x0FE6}, +{0x0F12, 0x029E}, +{0x002A, 0x0FEA}, +{0x0F12, 0x0691}, +{0x002A, 0x0FEE}, +{0x0F12, 0x0000}, +{0x002A, 0x0FF2}, +{0x0F12, 0x0000}, +{0x002A, 0x0FF6}, +{0x0F12, 0x0081}, +{0x002A, 0x0FFA}, +{0x0F12, 0x0202}, +{0x002A, 0x0FFE}, +{0x0F12, 0x02CA}, +{0x002A, 0x1002}, +{0x0F12, 0x068B}, +{0x002A, 0x1006}, +{0x0F12, 0x0000}, +{0x002A, 0x100A}, +{0x0F12, 0x0000}, +{0x002A, 0x100E}, +{0x0F12, 0x0000}, +{0x002A, 0x1012}, +{0x0F12, 0x0000}, +{0x002A, 0x1016}, +{0x0F12, 0x0081}, +{0x002A, 0x101A}, +{0x0F12, 0x01D3}, +{0x002A, 0x101E}, +{0x0F12, 0x02CA}, +{0x002A, 0x1022}, +{0x0F12, 0x065C}, +{0x002A, 0x1026}, +{0x0F12, 0x0000}, +{0x002A, 0x102A}, +{0x0F12, 0x0000}, +{0x002A, 0x102E}, +{0x0F12, 0x0000}, +{0x002A, 0x1032}, +{0x0F12, 0x0000}, +{0x002A, 0x1036}, +{0x0F12, 0x007F}, +{0x002A, 0x103A}, +{0x0F12, 0x0205}, +{0x002A, 0x103E}, +{0x0F12, 0x0000}, +{0x002A, 0x1042}, +{0x0F12, 0x0000}, +{0x002A, 0x1046}, +{0x0F12, 0x02C8}, +{0x002A, 0x104A}, +{0x0F12, 0x068E}, +{0x002A, 0x104E}, +{0x0F12, 0x0000}, +{0x002A, 0x1052}, +{0x0F12, 0x0000}, +{0x002A, 0x1056}, +{0x0F12, 0x0000}, +{0x002A, 0x105A}, +{0x0F12, 0x0000}, +{0x002A, 0x105E}, +{0x0F12, 0x0205}, +{0x002A, 0x1062}, +{0x0F12, 0x02B8}, +{0x002A, 0x1066}, +{0x0F12, 0x068E}, +{0x002A, 0x106A}, +{0x0F12, 0x0000}, +{0x002A, 0x106E}, +{0x0F12, 0x0000}, +{0x002A, 0x1072}, +{0x0F12, 0x0208}, +{0x002A, 0x1076}, +{0x0F12, 0x0210}, +{0x002A, 0x107A}, +{0x0F12, 0x0000}, +{0x002A, 0x107E}, +{0x0F12, 0x0000}, +{0x002A, 0x1082}, +{0x0F12, 0x0000}, +{0x002A, 0x1086}, +{0x0F12, 0x0000}, +{0x002A, 0x108A}, +{0x0F12, 0x020C}, +{0x002A, 0x108E}, +{0x0F12, 0x0214}, +{0x002A, 0x1092}, +{0x0F12, 0x0000}, +{0x002A, 0x1096}, +{0x0F12, 0x0000}, +{0x002A, 0x109A}, +{0x0F12, 0x0000}, +{0x002A, 0x109E}, +{0x0F12, 0x0000}, +{0x002A, 0x10A2}, +{0x0F12, 0x0002}, +{0x002A, 0x10A6}, +{0x0F12, 0x0010}, +{0x002A, 0x10AA}, +{0x0F12, 0x01D6}, +{0x002A, 0x10AE}, +{0x0F12, 0x0208}, +{0x002A, 0x10B2}, +{0x0F12, 0x065F}, +{0x002A, 0x10B6}, +{0x0F12, 0x0691}, +{0x002A, 0x10BA}, +{0x0F12, 0x0000}, +{0x002A, 0x10BE}, +{0x0F12, 0x0000}, +{0x002A, 0x10C2}, +{0x0F12, 0x0000}, +{0x002A, 0x10C6}, +{0x0F12, 0x0000}, +{0x002A, 0x10CA}, +{0x0F12, 0x0008}, +{0x002A, 0x10CE}, +{0x0F12, 0x0004}, +{0x002A, 0x10D2}, +{0x0F12, 0x0000}, +{0x002A, 0x10D6}, +{0x0F12, 0x0000}, +{0x002A, 0x10DA}, +{0x0F12, 0x0000}, +{0x002A, 0x10DE}, +{0x0F12, 0x0000}, +{0x002A, 0x10E2}, +{0x0F12, 0x0000}, +{0x002A, 0x10E6}, +{0x0F12, 0x0000}, +{0x002A, 0x10EA}, +{0x0F12, 0x0000}, +{0x002A, 0x10EE}, +{0x0F12, 0x0000}, +{0x002A, 0x10F2}, +{0x0F12, 0x0000}, +{0x002A, 0x10F6}, +{0x0F12, 0x0000}, +{0x002A, 0x10FA}, +{0x0F12, 0x0000}, +{0x002A, 0x10FE}, +{0x0F12, 0x0000}, +{0x002A, 0x1102}, +{0x0F12, 0x0000}, +{0x002A, 0x1106}, +{0x0F12, 0x0000}, +{0x002A, 0x110A}, +{0x0F12, 0x0000}, +{0x002A, 0x110E}, +{0x0F12, 0x0000}, +{0x002A, 0x1112}, +{0x0F12, 0x069E}, +{0x002A, 0x1116}, +{0x0F12, 0x0708}, +{0x002A, 0x111A}, +{0x0F12, 0x0000}, +{0x002A, 0x111E}, +{0x0F12, 0x0000}, +{0x002A, 0x1122}, +{0x0F12, 0x0000}, +{0x002A, 0x1126}, +{0x0F12, 0x027D}, +{0x002A, 0x112A}, +{0x0F12, 0x02C8}, +{0x002A, 0x112E}, +{0x0F12, 0x0708}, +{0x002A, 0x1132}, +{0x0F12, 0x0000}, +{0x002A, 0x0E90}, +{0x0F12, 0x0005}, +{0x002A, 0x0E94}, +{0x0F12, 0x0663}, +{0x002A, 0x0E98}, +{0x0F12, 0x0001}, +{0x002A, 0x0E9C}, +{0x0F12, 0x0332}, +{0x002A, 0x0EA0}, +{0x0F12, 0x0335}, +{0x002A, 0x0EA4}, +{0x0F12, 0x0663}, +{0x002A, 0x0EA8}, +{0x0F12, 0x0009}, +{0x002A, 0x0EAC}, +{0x0F12, 0x032C}, +{0x002A, 0x0EB0}, +{0x0F12, 0x033D}, +{0x002A, 0x0EB4}, +{0x0F12, 0x0660}, +{0x002A, 0x0EB8}, +{0x0F12, 0x0102}, +{0x002A, 0x0EBC}, +{0x0F12, 0x0153}, +{0x002A, 0x0EC0}, +{0x0F12, 0x0436}, +{0x002A, 0x0EC4}, +{0x0F12, 0x0487}, +{0x002A, 0x0EC8}, +{0x0F12, 0x0007}, +{0x002A, 0x0ECC}, +{0x0F12, 0x0334}, +{0x002A, 0x0ED0}, +{0x0F12, 0x033B}, +{0x002A, 0x0ED4}, +{0x0F12, 0x0668}, +{0x002A, 0x0ED8}, +{0x0F12, 0x0368}, +{0x002A, 0x0EDC}, +{0x0F12, 0x0337}, +{0x002A, 0x0EE0}, +{0x0F12, 0x0034}, +{0x002A, 0x0EE4}, +{0x0F12, 0x0003}, +{0x002A, 0x0EE8}, +{0x0F12, 0x03B5}, +{0x002A, 0x0EEC}, +{0x0F12, 0x038D}, +{0x002A, 0x0EF0}, +{0x0F12, 0x0365}, +{0x002A, 0x0EF4}, +{0x0F12, 0x033A}, +{0x002A, 0x0EF8}, +{0x0F12, 0x0081}, +{0x002A, 0x0EFC}, +{0x0F12, 0x0059}, +{0x002A, 0x0F00}, +{0x0F12, 0x0031}, +{0x002A, 0x0F04}, +{0x0F12, 0x0006}, +{0x002A, 0x0F08}, +{0x0F12, 0x03B2}, +{0x002A, 0x0F0C}, +{0x0F12, 0x0390}, +{0x002A, 0x0F10}, +{0x0F12, 0x0084}, +{0x002A, 0x0F14}, +{0x0F12, 0x0056}, +{0x002A, 0x0F18}, +{0x0F12, 0x0369}, +{0x002A, 0x0F1C}, +{0x0F12, 0x0336}, +{0x002A, 0x0F20}, +{0x0F12, 0x0035}, +{0x002A, 0x0F24}, +{0x0F12, 0x0002}, +{0x002A, 0x0F28}, +{0x0F12, 0x000C}, +{0x002A, 0x0F2C}, +{0x0F12, 0x00FC}, +{0x002A, 0x0F30}, +{0x0F12, 0x015F}, +{0x002A, 0x0F34}, +{0x0F12, 0x0430}, +{0x002A, 0x0F38}, +{0x0F12, 0x0493}, +{0x002A, 0x0F3C}, +{0x0F12, 0x065E}, +{0x002A, 0x0F40}, +{0x0F12, 0x0000}, +{0x002A, 0x0F44}, +{0x0F12, 0x0000}, +{0x002A, 0x0F48}, +{0x0F12, 0x000C}, +{0x002A, 0x0F4C}, +{0x0F12, 0x0052}, +{0x002A, 0x0F50}, +{0x0F12, 0x0340}, +{0x002A, 0x0F54}, +{0x0F12, 0x0386}, +{0x002A, 0x0F58}, +{0x0F12, 0x000C}, +{0x002A, 0x0F5C}, +{0x0F12, 0x0055}, +{0x002A, 0x0F60}, +{0x0F12, 0x0340}, +{0x002A, 0x0F64}, +{0x0F12, 0x0389}, +{0x002A, 0x0F68}, +{0x0F12, 0x0001}, +{0x002A, 0x0F6C}, +{0x0F12, 0x00FF}, +{0x002A, 0x0F70}, +{0x0F12, 0x032D}, +{0x002A, 0x0F74}, +{0x0F12, 0x0433}, +{0x002A, 0x0F78}, +{0x0F12, 0x007F}, +{0x002A, 0x0F7C}, +{0x0F12, 0x00FC}, +{0x002A, 0x0F80}, +{0x0F12, 0x018D}, +{0x002A, 0x0F84}, +{0x0F12, 0x032A}, +{0x002A, 0x0F88}, +{0x0F12, 0x03B3}, +{0x002A, 0x0F8C}, +{0x0F12, 0x0430}, +{0x002A, 0x0F90}, +{0x0F12, 0x04C1}, +{0x002A, 0x0F94}, +{0x0F12, 0x065E}, +{0x002A, 0x0F98}, +{0x0F12, 0x00BD}, +{0x002A, 0x0F9C}, +{0x0F12, 0x00FF}, +{0x002A, 0x0FA0}, +{0x0F12, 0x025B}, +{0x002A, 0x0FA4}, +{0x0F12, 0x032D}, +{0x002A, 0x0FA8}, +{0x0F12, 0x03F1}, +{0x002A, 0x0FAC}, +{0x0F12, 0x0433}, +{0x002A, 0x0FB0}, +{0x0F12, 0x058F}, +{0x002A, 0x0FB4}, +{0x0F12, 0x0661}, +{0x002A, 0x0FB8}, +{0x0F12, 0x0104}, +{0x002A, 0x0FBC}, +{0x0F12, 0x0159}, +{0x002A, 0x0FC0}, +{0x0F12, 0x0438}, +{0x002A, 0x0FC4}, +{0x0F12, 0x043E}, +{0x002A, 0x0FC8}, +{0x0F12, 0x0000}, +{0x002A, 0x0FCC}, +{0x0F12, 0x0000}, +{0x002A, 0x0FD0}, +{0x0F12, 0x0000}, +{0x002A, 0x0FD4}, +{0x0F12, 0x0000}, +{0x002A, 0x0FD8}, +{0x0F12, 0x0062}, +{0x002A, 0x0FDC}, +{0x0F12, 0x032D}, +{0x002A, 0x0FE0}, +{0x0F12, 0x0396}, +{0x002A, 0x0FE4}, +{0x0F12, 0x0661}, +{0x002A, 0x0FE8}, +{0x0F12, 0x0139}, +{0x002A, 0x0FEC}, +{0x0F12, 0x032D}, +{0x002A, 0x0FF0}, +{0x0F12, 0x046D}, +{0x002A, 0x0FF4}, +{0x0F12, 0x0661}, +{0x002A, 0x0FF8}, +{0x0F12, 0x0081}, +{0x002A, 0x0FFC}, +{0x0F12, 0x00F9}, +{0x002A, 0x1000}, +{0x0F12, 0x018F}, +{0x002A, 0x1004}, +{0x0F12, 0x0327}, +{0x002A, 0x1008}, +{0x0F12, 0x03B5}, +{0x002A, 0x100C}, +{0x0F12, 0x042D}, +{0x002A, 0x1010}, +{0x0F12, 0x04C3}, +{0x002A, 0x1014}, +{0x0F12, 0x065B}, +{0x002A, 0x1018}, +{0x0F12, 0x0081}, +{0x002A, 0x101C}, +{0x0F12, 0x00CA}, +{0x002A, 0x1020}, +{0x0F12, 0x018F}, +{0x002A, 0x1024}, +{0x0F12, 0x02F8}, +{0x002A, 0x1028}, +{0x0F12, 0x03B5}, +{0x002A, 0x102C}, +{0x0F12, 0x03FE}, +{0x002A, 0x1030}, +{0x0F12, 0x04C3}, +{0x002A, 0x1034}, +{0x0F12, 0x062C}, +{0x002A, 0x1038}, +{0x0F12, 0x007F}, +{0x002A, 0x103C}, +{0x0F12, 0x00FC}, +{0x002A, 0x1040}, +{0x0F12, 0x0000}, +{0x002A, 0x1044}, +{0x0F12, 0x0000}, +{0x002A, 0x1048}, +{0x0F12, 0x018D}, +{0x002A, 0x104C}, +{0x0F12, 0x032A}, +{0x002A, 0x1050}, +{0x0F12, 0x03B3}, +{0x002A, 0x1054}, +{0x0F12, 0x0430}, +{0x002A, 0x1058}, +{0x0F12, 0x04C1}, +{0x002A, 0x105C}, +{0x0F12, 0x065E}, +{0x002A, 0x1060}, +{0x0F12, 0x00FC}, +{0x002A, 0x1064}, +{0x0F12, 0x016D}, +{0x002A, 0x1068}, +{0x0F12, 0x0430}, +{0x002A, 0x106C}, +{0x0F12, 0x04A1}, +{0x002A, 0x1070}, +{0x0F12, 0x065E}, +{0x002A, 0x1074}, +{0x0F12, 0x00FF}, +{0x002A, 0x1078}, +{0x0F12, 0x010F}, +{0x002A, 0x107C}, +{0x0F12, 0x032D}, +{0x002A, 0x1080}, +{0x0F12, 0x033D}, +{0x002A, 0x1084}, +{0x0F12, 0x0433}, +{0x002A, 0x1088}, +{0x0F12, 0x0443}, +{0x002A, 0x108C}, +{0x0F12, 0x0107}, +{0x002A, 0x1090}, +{0x0F12, 0x0117}, +{0x002A, 0x1094}, +{0x0F12, 0x0335}, +{0x002A, 0x1098}, +{0x0F12, 0x0345}, +{0x002A, 0x109C}, +{0x0F12, 0x043B}, +{0x002A, 0x10A0}, +{0x0F12, 0x044B}, +{0x002A, 0x10A4}, +{0x0F12, 0x0002}, +{0x002A, 0x10A8}, +{0x0F12, 0x0010}, +{0x002A, 0x10AC}, +{0x0F12, 0x00CD}, +{0x002A, 0x10B0}, +{0x0F12, 0x00FF}, +{0x002A, 0x10B4}, +{0x0F12, 0x02FB}, +{0x002A, 0x10B8}, +{0x0F12, 0x032D}, +{0x002A, 0x10BC}, +{0x0F12, 0x0401}, +{0x002A, 0x10C0}, +{0x0F12, 0x0433}, +{0x002A, 0x10C4}, +{0x0F12, 0x062F}, +{0x002A, 0x10C8}, +{0x0F12, 0x0661}, +{0x002A, 0x10CC}, +{0x0F12, 0x000C}, +{0x002A, 0x10D0}, +{0x0F12, 0x0008}, +{0x002A, 0x10D4}, +{0x0F12, 0x0000}, +{0x002A, 0x10D8}, +{0x0F12, 0x0000}, +{0x002A, 0x10DC}, +{0x0F12, 0x0000}, +{0x002A, 0x10E0}, +{0x0F12, 0x0000}, +{0x002A, 0x10E4}, +{0x0F12, 0x0000}, +{0x002A, 0x10E8}, +{0x0F12, 0x0000}, +{0x002A, 0x10EC}, +{0x0F12, 0x0000}, +{0x002A, 0x10F0}, +{0x0F12, 0x0000}, +{0x002A, 0x10F4}, +{0x0F12, 0x0000}, +{0x002A, 0x10F8}, +{0x0F12, 0x0000}, +{0x002A, 0x10FC}, +{0x0F12, 0x0000}, +{0x002A, 0x1100}, +{0x0F12, 0x0000}, +{0x002A, 0x1104}, +{0x0F12, 0x0000}, +{0x002A, 0x1108}, +{0x0F12, 0x0000}, +{0x002A, 0x110C}, +{0x0F12, 0x0000}, +{0x002A, 0x1110}, +{0x0F12, 0x0000}, +{0x002A, 0x1114}, +{0x0F12, 0x066C}, +{0x002A, 0x1118}, +{0x0F12, 0x06DF}, +{0x002A, 0x111C}, +{0x0F12, 0x0000}, +{0x002A, 0x1120}, +{0x0F12, 0x0000}, +{0x002A, 0x1124}, +{0x0F12, 0x0000}, +{0x002A, 0x1128}, +{0x0F12, 0x04AF}, +{0x002A, 0x112C}, +{0x0F12, 0x04C1}, +{0x002A, 0x1130}, +{0x0F12, 0x06DF}, +{0x002A, 0x1134}, +{0x0F12, 0x0000}, +{0x002A, 0x1186}, +{0x0F12, 0x0404}, +{0x0F12, 0x0C0C}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x11F0}, +{0x0F12, 0x026C}, +{0x002A, 0x1136}, +{0x0F12, 0x02FF}, +{0x0F12, 0x05FF}, +{0x002A, 0x1224}, +{0x0F12, 0x0001}, +{0x0F12, 0x0008}, +{0x002A, 0x1230}, +{0x0F12, 0x0000}, +{0x002A, 0x1234}, +{0x0F12, 0x0090}, +{0x002A, 0x122A}, +{0x0F12, 0x0001}, +{0x0F12, 0x0008}, +{0x002A, 0x1236}, +{0x0F12, 0x0000}, +{0x002A, 0x123A}, +{0x0F12, 0x0090}, +{0x002A, 0x0E4C}, +{0x0F12, 0x1110}, +{0x002A, 0x0E5C}, +{0x0F12, 0x00F4}, +{0x002A, 0x0E6C}, +{0x0F12, 0x000F}, +{0x0F12, 0x000F}, +{0x002A, 0x0E34}, +{0x0F12, 0x0013}, +{0x0F12, 0x0013}, +{0x0F12, 0x0474}, +{0x0F12, 0x0474}, +{0x002A, 0x0E5E}, +{0x0F12, 0x0001}, +{0x002A, 0x1208}, +{0x0F12, 0x0276}, +{0x002A, 0x0E52}, +{0x0F12, 0x8999}, +{0x0F12, 0x0779}, +{0x002A, 0x1202}, +{0x0F12, 0x0008}, +{0x002A, 0x11FE}, +{0x0F12, 0x0000}, +{0x002A, 0x1204}, +{0x0F12, 0x0000}, +{0x002A, 0x0AA0}, +{0x0F12, 0x0001}, +{0x002A, 0x0E2C}, +{0x0F12, 0x0001}, +{0x002A, 0x1358}, +{0x0F12, 0x006C}, +{0x002A, 0x0E66}, +{0x0F12, 0x0001}, +{0x0F12, 0x0001}, +{0x0F12, 0x0001}, +{0x002A, 0x1250}, +{0x0F12, 0x00FF}, +{0x002A, 0x0D46}, +{0x0F12, 0x000F}, +{0x002A, 0x0440}, +{0x0F12, 0x3410}, +{0x002A, 0x0444}, +{0x0F12, 0x6820}, +{0x002A, 0x0448}, +{0x0F12, 0x8227}, +{0x002A, 0x044C}, +{0x0F12, 0xC350}, +{0x002A, 0x0450}, +{0x0F12, 0x3410}, +{0x002A, 0x0454}, +{0x0F12, 0x6820}, +{0x002A, 0x0458}, +{0x0F12, 0x8227}, +{0x002A, 0x045C}, +{0x0F12, 0xC350}, +{0x002A, 0x0460}, +{0x0F12, 0x01B0}, +{0x0F12, 0x01B0}, +{0x0F12, 0x0280}, +{0x0F12, 0x0A80}, +{0x0F12, 0x0100}, +{0x0F12, 0x3000}, +{0x002A, 0x042E}, +{0x0F12, 0x010E}, +{0x0F12, 0x00F5}, +{0x002A, 0x0DE0}, +{0x0F12, 0x0002}, +{0x002A, 0x0D4E}, +{0x0F12, 0x0000}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0000}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0101}, +{0x0F12, 0x0201}, +{0x0F12, 0x0303}, +{0x0F12, 0x0303}, +{0x0F12, 0x0102}, +{0x0F12, 0x0201}, +{0x0F12, 0x0403}, +{0x0F12, 0x0304}, +{0x0F12, 0x0102}, +{0x0F12, 0x0201}, +{0x0F12, 0x0403}, +{0x0F12, 0x0304}, +{0x0F12, 0x0102}, +{0x0F12, 0x0201}, +{0x0F12, 0x0403}, +{0x0F12, 0x0304}, +{0x0F12, 0x0102}, +{0x0F12, 0x0201}, +{0x0F12, 0x0303}, +{0x0F12, 0x0303}, +{0x0F12, 0x0102}, +{0x0F12, 0x0201}, +{0x0F12, 0x0202}, +{0x0F12, 0x0202}, +{0x0F12, 0x0102}, +{0x002A, 0x1326}, +{0x0F12, 0x0000}, +{0x002A, 0x063A}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x00E8}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x00E8}, +{0x0F12, 0x00F8}, +{0x0F12, 0x00F8}, +{0x0F12, 0x0100}, +{0x0F12, 0x00F0}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x00F0}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x002A, 0x067A}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x06BA}, +{0x0F12, 0x0001}, +{0x002A, 0x0632}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x002A, 0x0672}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x0F12, 0x0100}, +{0x002A, 0x06B2}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x06D0}, +{0x0F12, 0x000D}, +{0x0F12, 0x000F}, +{0x002A, 0x06CC}, +{0x0F12, 0x0280}, +{0x0F12, 0x01E0}, +{0x002A, 0x06C6}, +{0x0F12, 0x0001}, +{0x002A, 0x0624}, +{0x0F12, 0x009D}, +{0x0F12, 0x00D5}, +{0x0F12, 0x0103}, +{0x0F12, 0x0128}, +{0x0F12, 0x0166}, +{0x0F12, 0x0193}, +{0x0F12, 0x01A0}, +{0x002A, 0x347C}, +{0x0F12, 0x012F}, +{0x0F12, 0x0111}, +{0x0F12, 0x00D6}, +{0x0F12, 0x009E}, +{0x0F12, 0x007A}, +{0x0F12, 0x0064}, +{0x0F12, 0x005D}, +{0x0F12, 0x0063}, +{0x0F12, 0x007B}, +{0x0F12, 0x00A3}, +{0x0F12, 0x00E3}, +{0x0F12, 0x013B}, +{0x0F12, 0x018B}, +{0x0F12, 0x012B}, +{0x0F12, 0x00F6}, +{0x0F12, 0x00B2}, +{0x0F12, 0x007B}, +{0x0F12, 0x0057}, +{0x0F12, 0x0042}, +{0x0F12, 0x0039}, +{0x0F12, 0x003F}, +{0x0F12, 0x0053}, +{0x0F12, 0x007A}, +{0x0F12, 0x00B6}, +{0x0F12, 0x0110}, +{0x0F12, 0x016A}, +{0x0F12, 0x0114}, +{0x0F12, 0x00D4}, +{0x0F12, 0x008F}, +{0x0F12, 0x005A}, +{0x0F12, 0x0035}, +{0x0F12, 0x0020}, +{0x0F12, 0x0019}, +{0x0F12, 0x001F}, +{0x0F12, 0x0032}, +{0x0F12, 0x0056}, +{0x0F12, 0x008E}, +{0x0F12, 0x00E6}, +{0x0F12, 0x0142}, +{0x0F12, 0x0102}, +{0x0F12, 0x00BE}, +{0x0F12, 0x0077}, +{0x0F12, 0x0045}, +{0x0F12, 0x0022}, +{0x0F12, 0x000D}, +{0x0F12, 0x0006}, +{0x0F12, 0x000A}, +{0x0F12, 0x001D}, +{0x0F12, 0x003F}, +{0x0F12, 0x0075}, +{0x0F12, 0x00CC}, +{0x0F12, 0x0126}, +{0x0F12, 0x00FB}, +{0x0F12, 0x00B7}, +{0x0F12, 0x0070}, +{0x0F12, 0x003D}, +{0x0F12, 0x001B}, +{0x0F12, 0x0007}, +{0x0F12, 0x0000}, +{0x0F12, 0x0004}, +{0x0F12, 0x0015}, +{0x0F12, 0x0034}, +{0x0F12, 0x006A}, +{0x0F12, 0x00C0}, +{0x0F12, 0x011B}, +{0x0F12, 0x0102}, +{0x0F12, 0x00BA}, +{0x0F12, 0x0073}, +{0x0F12, 0x0040}, +{0x0F12, 0x001D}, +{0x0F12, 0x0009}, +{0x0F12, 0x0001}, +{0x0F12, 0x0006}, +{0x0F12, 0x0017}, +{0x0F12, 0x0039}, +{0x0F12, 0x006F}, +{0x0F12, 0x00C8}, +{0x0F12, 0x011E}, +{0x0F12, 0x0111}, +{0x0F12, 0x00C8}, +{0x0F12, 0x0081}, +{0x0F12, 0x004D}, +{0x0F12, 0x0028}, +{0x0F12, 0x0014}, +{0x0F12, 0x000B}, +{0x0F12, 0x0010}, +{0x0F12, 0x0022}, +{0x0F12, 0x0047}, +{0x0F12, 0x007E}, +{0x0F12, 0x00D8}, +{0x0F12, 0x0131}, +{0x0F12, 0x0129}, +{0x0F12, 0x00E4}, +{0x0F12, 0x009E}, +{0x0F12, 0x0068}, +{0x0F12, 0x0041}, +{0x0F12, 0x002B}, +{0x0F12, 0x0023}, +{0x0F12, 0x0028}, +{0x0F12, 0x003B}, +{0x0F12, 0x0063}, +{0x0F12, 0x00A0}, +{0x0F12, 0x00FD}, +{0x0F12, 0x015A}, +{0x0F12, 0x014A}, +{0x0F12, 0x010D}, +{0x0F12, 0x00CA}, +{0x0F12, 0x008F}, +{0x0F12, 0x0066}, +{0x0F12, 0x004F}, +{0x0F12, 0x0048}, +{0x0F12, 0x004E}, +{0x0F12, 0x0067}, +{0x0F12, 0x008F}, +{0x0F12, 0x00D1}, +{0x0F12, 0x0132}, +{0x0F12, 0x018D}, +{0x0F12, 0x0159}, +{0x0F12, 0x0141}, +{0x0F12, 0x0103}, +{0x0F12, 0x00C9}, +{0x0F12, 0x009E}, +{0x0F12, 0x0087}, +{0x0F12, 0x007D}, +{0x0F12, 0x0087}, +{0x0F12, 0x00A2}, +{0x0F12, 0x00D4}, +{0x0F12, 0x011A}, +{0x0F12, 0x017D}, +{0x0F12, 0x01CF}, +{0x0F12, 0x0181}, +{0x0F12, 0x0169}, +{0x0F12, 0x0140}, +{0x0F12, 0x0106}, +{0x0F12, 0x00DD}, +{0x0F12, 0x00C5}, +{0x0F12, 0x00BE}, +{0x0F12, 0x00C8}, +{0x0F12, 0x00E6}, +{0x0F12, 0x011B}, +{0x0F12, 0x015F}, +{0x0F12, 0x01BC}, +{0x0F12, 0x0206}, +{0x0F12, 0x00A8}, +{0x0F12, 0x008F}, +{0x0F12, 0x006F}, +{0x0F12, 0x0054}, +{0x0F12, 0x0041}, +{0x0F12, 0x0036}, +{0x0F12, 0x0033}, +{0x0F12, 0x0037}, +{0x0F12, 0x0045}, +{0x0F12, 0x005A}, +{0x0F12, 0x007A}, +{0x0F12, 0x00AA}, +{0x0F12, 0x00E2}, +{0x0F12, 0x009E}, +{0x0F12, 0x007D}, +{0x0F12, 0x005A}, +{0x0F12, 0x0041}, +{0x0F12, 0x002E}, +{0x0F12, 0x0022}, +{0x0F12, 0x001F}, +{0x0F12, 0x0022}, +{0x0F12, 0x0030}, +{0x0F12, 0x0044}, +{0x0F12, 0x0063}, +{0x0F12, 0x0091}, +{0x0F12, 0x00CB}, +{0x0F12, 0x0093}, +{0x0F12, 0x006D}, +{0x0F12, 0x004A}, +{0x0F12, 0x0031}, +{0x0F12, 0x001E}, +{0x0F12, 0x0013}, +{0x0F12, 0x000F}, +{0x0F12, 0x0013}, +{0x0F12, 0x001F}, +{0x0F12, 0x0034}, +{0x0F12, 0x0051}, +{0x0F12, 0x007C}, +{0x0F12, 0x00B7}, +{0x0F12, 0x008A}, +{0x0F12, 0x0061}, +{0x0F12, 0x003E}, +{0x0F12, 0x0026}, +{0x0F12, 0x0013}, +{0x0F12, 0x0008}, +{0x0F12, 0x0004}, +{0x0F12, 0x0007}, +{0x0F12, 0x0013}, +{0x0F12, 0x0027}, +{0x0F12, 0x0045}, +{0x0F12, 0x0070}, +{0x0F12, 0x00A7}, +{0x0F12, 0x0085}, +{0x0F12, 0x005D}, +{0x0F12, 0x003A}, +{0x0F12, 0x0021}, +{0x0F12, 0x0010}, +{0x0F12, 0x0004}, +{0x0F12, 0x0000}, +{0x0F12, 0x0003}, +{0x0F12, 0x000E}, +{0x0F12, 0x0021}, +{0x0F12, 0x003F}, +{0x0F12, 0x006B}, +{0x0F12, 0x00A1}, +{0x0F12, 0x0089}, +{0x0F12, 0x0060}, +{0x0F12, 0x003D}, +{0x0F12, 0x0023}, +{0x0F12, 0x0012}, +{0x0F12, 0x0006}, +{0x0F12, 0x0002}, +{0x0F12, 0x0005}, +{0x0F12, 0x0011}, +{0x0F12, 0x0025}, +{0x0F12, 0x0043}, +{0x0F12, 0x0070}, +{0x0F12, 0x00A4}, +{0x0F12, 0x0091}, +{0x0F12, 0x0067}, +{0x0F12, 0x0044}, +{0x0F12, 0x002B}, +{0x0F12, 0x0019}, +{0x0F12, 0x000D}, +{0x0F12, 0x0009}, +{0x0F12, 0x000C}, +{0x0F12, 0x0018}, +{0x0F12, 0x002D}, +{0x0F12, 0x004B}, +{0x0F12, 0x007B}, +{0x0F12, 0x00B0}, +{0x0F12, 0x00A1}, +{0x0F12, 0x0077}, +{0x0F12, 0x0054}, +{0x0F12, 0x003B}, +{0x0F12, 0x0029}, +{0x0F12, 0x001C}, +{0x0F12, 0x0018}, +{0x0F12, 0x001B}, +{0x0F12, 0x0029}, +{0x0F12, 0x003F}, +{0x0F12, 0x005F}, +{0x0F12, 0x008F}, +{0x0F12, 0x00C6}, +{0x0F12, 0x00B1}, +{0x0F12, 0x008E}, +{0x0F12, 0x006D}, +{0x0F12, 0x0050}, +{0x0F12, 0x003D}, +{0x0F12, 0x0031}, +{0x0F12, 0x002F}, +{0x0F12, 0x0032}, +{0x0F12, 0x0042}, +{0x0F12, 0x0058}, +{0x0F12, 0x007A}, +{0x0F12, 0x00AC}, +{0x0F12, 0x00E5}, +{0x0F12, 0x00BD}, +{0x0F12, 0x00AA}, +{0x0F12, 0x008B}, +{0x0F12, 0x006E}, +{0x0F12, 0x005A}, +{0x0F12, 0x004F}, +{0x0F12, 0x004B}, +{0x0F12, 0x0052}, +{0x0F12, 0x0062}, +{0x0F12, 0x007D}, +{0x0F12, 0x00A2}, +{0x0F12, 0x00D6}, +{0x0F12, 0x010C}, +{0x0F12, 0x00E5}, +{0x0F12, 0x00C7}, +{0x0F12, 0x00B1}, +{0x0F12, 0x0093}, +{0x0F12, 0x007F}, +{0x0F12, 0x0074}, +{0x0F12, 0x0071}, +{0x0F12, 0x0077}, +{0x0F12, 0x0089}, +{0x0F12, 0x00A7}, +{0x0F12, 0x00CC}, +{0x0F12, 0x00FE}, +{0x0F12, 0x0132}, +{0x0F12, 0x00A8}, +{0x0F12, 0x008D}, +{0x0F12, 0x006C}, +{0x0F12, 0x004E}, +{0x0F12, 0x003C}, +{0x0F12, 0x0032}, +{0x0F12, 0x002D}, +{0x0F12, 0x0032}, +{0x0F12, 0x0040}, +{0x0F12, 0x0056}, +{0x0F12, 0x0076}, +{0x0F12, 0x00A8}, +{0x0F12, 0x00E6}, +{0x0F12, 0x00A2}, +{0x0F12, 0x007C}, +{0x0F12, 0x0059}, +{0x0F12, 0x003E}, +{0x0F12, 0x002A}, +{0x0F12, 0x0020}, +{0x0F12, 0x001B}, +{0x0F12, 0x0020}, +{0x0F12, 0x002D}, +{0x0F12, 0x0042}, +{0x0F12, 0x0061}, +{0x0F12, 0x0092}, +{0x0F12, 0x00CE}, +{0x0F12, 0x0094}, +{0x0F12, 0x006F}, +{0x0F12, 0x004B}, +{0x0F12, 0x002F}, +{0x0F12, 0x001D}, +{0x0F12, 0x0011}, +{0x0F12, 0x000D}, +{0x0F12, 0x0012}, +{0x0F12, 0x001D}, +{0x0F12, 0x0033}, +{0x0F12, 0x0051}, +{0x0F12, 0x007F}, +{0x0F12, 0x00BA}, +{0x0F12, 0x008B}, +{0x0F12, 0x0064}, +{0x0F12, 0x0040}, +{0x0F12, 0x0025}, +{0x0F12, 0x0013}, +{0x0F12, 0x0007}, +{0x0F12, 0x0003}, +{0x0F12, 0x0006}, +{0x0F12, 0x0012}, +{0x0F12, 0x0027}, +{0x0F12, 0x0046}, +{0x0F12, 0x0073}, +{0x0F12, 0x00AB}, +{0x0F12, 0x008B}, +{0x0F12, 0x0062}, +{0x0F12, 0x003F}, +{0x0F12, 0x0023}, +{0x0F12, 0x0010}, +{0x0F12, 0x0004}, +{0x0F12, 0x0000}, +{0x0F12, 0x0003}, +{0x0F12, 0x000E}, +{0x0F12, 0x0022}, +{0x0F12, 0x0041}, +{0x0F12, 0x006E}, +{0x0F12, 0x00A4}, +{0x0F12, 0x008E}, +{0x0F12, 0x0065}, +{0x0F12, 0x0040}, +{0x0F12, 0x0025}, +{0x0F12, 0x0013}, +{0x0F12, 0x0006}, +{0x0F12, 0x0001}, +{0x0F12, 0x0005}, +{0x0F12, 0x0010}, +{0x0F12, 0x0025}, +{0x0F12, 0x0044}, +{0x0F12, 0x0074}, +{0x0F12, 0x00AA}, +{0x0F12, 0x0097}, +{0x0F12, 0x006D}, +{0x0F12, 0x0048}, +{0x0F12, 0x002D}, +{0x0F12, 0x0019}, +{0x0F12, 0x000E}, +{0x0F12, 0x0009}, +{0x0F12, 0x000C}, +{0x0F12, 0x0018}, +{0x0F12, 0x002E}, +{0x0F12, 0x004E}, +{0x0F12, 0x007D}, +{0x0F12, 0x00B5}, +{0x0F12, 0x00A6}, +{0x0F12, 0x007C}, +{0x0F12, 0x0058}, +{0x0F12, 0x003E}, +{0x0F12, 0x0029}, +{0x0F12, 0x001D}, +{0x0F12, 0x0018}, +{0x0F12, 0x001B}, +{0x0F12, 0x0028}, +{0x0F12, 0x003F}, +{0x0F12, 0x0062}, +{0x0F12, 0x0093}, +{0x0F12, 0x00CC}, +{0x0F12, 0x00B9}, +{0x0F12, 0x0094}, +{0x0F12, 0x0071}, +{0x0F12, 0x0052}, +{0x0F12, 0x003D}, +{0x0F12, 0x0031}, +{0x0F12, 0x002D}, +{0x0F12, 0x0031}, +{0x0F12, 0x0040}, +{0x0F12, 0x0058}, +{0x0F12, 0x007B}, +{0x0F12, 0x00AE}, +{0x0F12, 0x00EA}, +{0x0F12, 0x00C2}, +{0x0F12, 0x00AE}, +{0x0F12, 0x008E}, +{0x0F12, 0x006F}, +{0x0F12, 0x0059}, +{0x0F12, 0x004E}, +{0x0F12, 0x0049}, +{0x0F12, 0x004F}, +{0x0F12, 0x005E}, +{0x0F12, 0x007A}, +{0x0F12, 0x009F}, +{0x0F12, 0x00D5}, +{0x0F12, 0x010C}, +{0x0F12, 0x00E5}, +{0x0F12, 0x00C8}, +{0x0F12, 0x00B0}, +{0x0F12, 0x0091}, +{0x0F12, 0x007D}, +{0x0F12, 0x0070}, +{0x0F12, 0x006D}, +{0x0F12, 0x0074}, +{0x0F12, 0x0086}, +{0x0F12, 0x00A4}, +{0x0F12, 0x00CA}, +{0x0F12, 0x00FE}, +{0x0F12, 0x0134}, +{0x0F12, 0x009F}, +{0x0F12, 0x0089}, +{0x0F12, 0x0067}, +{0x0F12, 0x004E}, +{0x0F12, 0x003E}, +{0x0F12, 0x0033}, +{0x0F12, 0x0031}, +{0x0F12, 0x0036}, +{0x0F12, 0x0045}, +{0x0F12, 0x0058}, +{0x0F12, 0x0074}, +{0x0F12, 0x00A0}, +{0x0F12, 0x00C9}, +{0x0F12, 0x0098}, +{0x0F12, 0x0077}, +{0x0F12, 0x0055}, +{0x0F12, 0x003C}, +{0x0F12, 0x002A}, +{0x0F12, 0x0022}, +{0x0F12, 0x001F}, +{0x0F12, 0x0024}, +{0x0F12, 0x0030}, +{0x0F12, 0x0044}, +{0x0F12, 0x0060}, +{0x0F12, 0x008B}, +{0x0F12, 0x00B2}, +{0x0F12, 0x0088}, +{0x0F12, 0x0065}, +{0x0F12, 0x0044}, +{0x0F12, 0x002C}, +{0x0F12, 0x001B}, +{0x0F12, 0x0012}, +{0x0F12, 0x000F}, +{0x0F12, 0x0013}, +{0x0F12, 0x001E}, +{0x0F12, 0x0032}, +{0x0F12, 0x004E}, +{0x0F12, 0x0078}, +{0x0F12, 0x00A2}, +{0x0F12, 0x007F}, +{0x0F12, 0x005B}, +{0x0F12, 0x0039}, +{0x0F12, 0x0021}, +{0x0F12, 0x0012}, +{0x0F12, 0x0007}, +{0x0F12, 0x0004}, +{0x0F12, 0x0006}, +{0x0F12, 0x0012}, +{0x0F12, 0x0024}, +{0x0F12, 0x0041}, +{0x0F12, 0x006A}, +{0x0F12, 0x0092}, +{0x0F12, 0x007B}, +{0x0F12, 0x0057}, +{0x0F12, 0x0036}, +{0x0F12, 0x001E}, +{0x0F12, 0x000F}, +{0x0F12, 0x0003}, +{0x0F12, 0x0000}, +{0x0F12, 0x0002}, +{0x0F12, 0x000D}, +{0x0F12, 0x0020}, +{0x0F12, 0x003C}, +{0x0F12, 0x0067}, +{0x0F12, 0x008D}, +{0x0F12, 0x007E}, +{0x0F12, 0x005A}, +{0x0F12, 0x0038}, +{0x0F12, 0x0022}, +{0x0F12, 0x0013}, +{0x0F12, 0x0006}, +{0x0F12, 0x0001}, +{0x0F12, 0x0004}, +{0x0F12, 0x000F}, +{0x0F12, 0x0023}, +{0x0F12, 0x003E}, +{0x0F12, 0x006A}, +{0x0F12, 0x0091}, +{0x0F12, 0x0085}, +{0x0F12, 0x0060}, +{0x0F12, 0x0041}, +{0x0F12, 0x002A}, +{0x0F12, 0x0019}, +{0x0F12, 0x000D}, +{0x0F12, 0x0008}, +{0x0F12, 0x000A}, +{0x0F12, 0x0016}, +{0x0F12, 0x002A}, +{0x0F12, 0x0047}, +{0x0F12, 0x0074}, +{0x0F12, 0x009A}, +{0x0F12, 0x0097}, +{0x0F12, 0x0070}, +{0x0F12, 0x0052}, +{0x0F12, 0x003C}, +{0x0F12, 0x0028}, +{0x0F12, 0x001D}, +{0x0F12, 0x0019}, +{0x0F12, 0x001A}, +{0x0F12, 0x0026}, +{0x0F12, 0x003B}, +{0x0F12, 0x005A}, +{0x0F12, 0x0089}, +{0x0F12, 0x00AF}, +{0x0F12, 0x00A7}, +{0x0F12, 0x0088}, +{0x0F12, 0x006B}, +{0x0F12, 0x0050}, +{0x0F12, 0x003D}, +{0x0F12, 0x0032}, +{0x0F12, 0x002E}, +{0x0F12, 0x0030}, +{0x0F12, 0x003E}, +{0x0F12, 0x0052}, +{0x0F12, 0x0073}, +{0x0F12, 0x00A1}, +{0x0F12, 0x00C7}, +{0x0F12, 0x00AE}, +{0x0F12, 0x00A4}, +{0x0F12, 0x0088}, +{0x0F12, 0x006D}, +{0x0F12, 0x0059}, +{0x0F12, 0x004D}, +{0x0F12, 0x0049}, +{0x0F12, 0x004E}, +{0x0F12, 0x005B}, +{0x0F12, 0x0073}, +{0x0F12, 0x0095}, +{0x0F12, 0x00C4}, +{0x0F12, 0x00E9}, +{0x0F12, 0x00D5}, +{0x0F12, 0x00C1}, +{0x0F12, 0x00AB}, +{0x0F12, 0x008D}, +{0x0F12, 0x0079}, +{0x0F12, 0x0070}, +{0x0F12, 0x006A}, +{0x0F12, 0x006F}, +{0x0F12, 0x0080}, +{0x0F12, 0x0096}, +{0x0F12, 0x00B9}, +{0x0F12, 0x00E2}, +{0x0F12, 0x010F}, +{0x002A, 0x1348}, +{0x0F12, 0x0001}, +{0x002A, 0x0B36}, +{0x0F12, 0x0005}, +{0x002A, 0x0B3A}, +{0x0F12, 0x00EC}, +{0x0F12, 0x02C1}, +{0x002A, 0x0B38}, +{0x0F12, 0x0010}, +{0x002A, 0x0AE6}, +{0x0F12, 0x03E1}, +{0x0F12, 0x0413}, +{0x0F12, 0x039E}, +{0x0F12, 0x0416}, +{0x0F12, 0x0367}, +{0x0F12, 0x03F3}, +{0x0F12, 0x032D}, +{0x0F12, 0x03C5}, +{0x0F12, 0x02FD}, +{0x0F12, 0x038F}, +{0x0F12, 0x02D3}, +{0x0F12, 0x0365}, +{0x0F12, 0x02AA}, +{0x0F12, 0x033E}, +{0x0F12, 0x028D}, +{0x0F12, 0x0310}, +{0x0F12, 0x0271}, +{0x0F12, 0x02F1}, +{0x0F12, 0x025A}, +{0x0F12, 0x02D2}, +{0x0F12, 0x0249}, +{0x0F12, 0x02B9}, +{0x0F12, 0x0238}, +{0x0F12, 0x02A2}, +{0x0F12, 0x021B}, +{0x0F12, 0x0289}, +{0x0F12, 0x0200}, +{0x0F12, 0x026C}, +{0x0F12, 0x01FC}, +{0x0F12, 0x024F}, +{0x0F12, 0x021E}, +{0x0F12, 0x022C}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x0BAA}, +{0x0F12, 0x0006}, +{0x002A, 0x0BAE}, +{0x0F12, 0x010E}, +{0x0F12, 0x02E9}, +{0x002A, 0x0BAC}, +{0x0F12, 0x0009}, +{0x002A, 0x0B7A}, +{0x0F12, 0x038C}, +{0x0F12, 0x03DA}, +{0x0F12, 0x030E}, +{0x0F12, 0x03E9}, +{0x0F12, 0x02A2}, +{0x0F12, 0x03C2}, +{0x0F12, 0x0259}, +{0x0F12, 0x038A}, +{0x0F12, 0x0218}, +{0x0F12, 0x0352}, +{0x0F12, 0x01F4}, +{0x0F12, 0x02E1}, +{0x0F12, 0x01D7}, +{0x0F12, 0x028E}, +{0x0F12, 0x01CB}, +{0x0F12, 0x0258}, +{0x0F12, 0x022B}, +{0x0F12, 0x01CC}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x0B70}, +{0x0F12, 0x0005}, +{0x002A, 0x0B74}, +{0x0F12, 0x01F8}, +{0x0F12, 0x02A8}, +{0x002A, 0x0B72}, +{0x0F12, 0x0007}, +{0x002A, 0x0B40}, +{0x0F12, 0x029E}, +{0x0F12, 0x02C8}, +{0x0F12, 0x0281}, +{0x0F12, 0x02C8}, +{0x0F12, 0x0266}, +{0x0F12, 0x02AC}, +{0x0F12, 0x0251}, +{0x0F12, 0x028E}, +{0x0F12, 0x023D}, +{0x0F12, 0x0275}, +{0x0F12, 0x0228}, +{0x0F12, 0x025D}, +{0x0F12, 0x0228}, +{0x0F12, 0x0243}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x0BC8}, +{0x0F12, 0x0005}, +{0x002A, 0x0BCC}, +{0x0F12, 0x010F}, +{0x0F12, 0x018F}, +{0x002A, 0x0BCA}, +{0x0F12, 0x0005}, +{0x002A, 0x0BB4}, +{0x0F12, 0x03E7}, +{0x0F12, 0x03F8}, +{0x0F12, 0x03A7}, +{0x0F12, 0x03FC}, +{0x0F12, 0x0352}, +{0x0F12, 0x03D0}, +{0x0F12, 0x0322}, +{0x0F12, 0x039E}, +{0x0F12, 0x032B}, +{0x0F12, 0x034D}, +{0x002A, 0x0BE6}, +{0x0F12, 0x0006}, +{0x002A, 0x0BEA}, +{0x0F12, 0x019E}, +{0x0F12, 0x0257}, +{0x002A, 0x0BE8}, +{0x0F12, 0x0004}, +{0x002A, 0x0BD2}, +{0x0F12, 0x030B}, +{0x0F12, 0x0323}, +{0x0F12, 0x02C3}, +{0x0F12, 0x030F}, +{0x0F12, 0x0288}, +{0x0F12, 0x02E5}, +{0x0F12, 0x026A}, +{0x0F12, 0x02A2}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x0C2C}, +{0x0F12, 0x0139}, +{0x0F12, 0x0122}, +{0x002A, 0x0BFC}, +{0x0F12, 0x03AD}, +{0x0F12, 0x013F}, +{0x0F12, 0x0341}, +{0x0F12, 0x017B}, +{0x0F12, 0x038D}, +{0x0F12, 0x014B}, +{0x0F12, 0x02C3}, +{0x0F12, 0x01CC}, +{0x0F12, 0x0241}, +{0x0F12, 0x027F}, +{0x0F12, 0x0241}, +{0x0F12, 0x027F}, +{0x0F12, 0x0214}, +{0x0F12, 0x02A8}, +{0x0F12, 0x0255}, +{0x0F12, 0x025B}, +{0x002A, 0x0C4C}, +{0x0F12, 0x0452}, +{0x002A, 0x0C58}, +{0x0F12, 0x059C}, +{0x002A, 0x0BF8}, +{0x0F12, 0x01AE}, +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, +{0x002A, 0x0CAC}, +{0x0F12, 0x0F00}, +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, +{0x002A, 0x0D0E}, +{0x0F12, 0x00B8}, +{0x0F12, 0x00B2}, +{0x002A, 0x0CFE}, +{0x0F12, 0x0FAB}, +{0x0F12, 0x0FF5}, +{0x0F12, 0x10BB}, +{0x0F12, 0x1153}, +{0x0F12, 0x11C5}, +{0x0F12, 0x122A}, +{0x0F12, 0x00A9}, +{0x0F12, 0x00C0}, +{0x002A, 0x0CF8}, +{0x0F12, 0x030E}, +{0x0F12, 0x034C}, +{0x0F12, 0x0388}, +{0x002A, 0x0CB0}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0028}, +{0x0F12, 0x0028}, +{0x0F12, 0x003C}, +{0x0F12, 0x0050}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0028}, +{0x0F12, 0x0028}, +{0x0F12, 0x003C}, +{0x0F12, 0x0050}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0028}, +{0x0F12, 0x0028}, +{0x0F12, 0x003C}, +{0x0F12, 0x0050}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0xFFB0}, +{0x0F12, 0xFF06}, +{0x0F12, 0xFF06}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0xFFB0}, +{0x0F12, 0xFF06}, +{0x0F12, 0xFF06}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0xFFB0}, +{0x0F12, 0xFF06}, +{0x0F12, 0xFF06}, +{0x002A, 0x0D30}, +{0x0F12, 0x0002}, +{0x002A, 0x0C86}, +{0x0F12, 0x0005}, +{0x002A, 0x0C70}, +{0x0F12, 0xFF7B}, +{0x0F12, 0x00CE}, +{0x0F12, 0xFF23}, +{0x0F12, 0x010D}, +{0x0F12, 0xFEF3}, +{0x0F12, 0x012C}, +{0x0F12, 0xFED7}, +{0x0F12, 0x014E}, +{0x0F12, 0xFEBB}, +{0x0F12, 0x0162}, +{0x0F12, 0x1388}, +{0x002A, 0x0C8A}, +{0x0F12, 0x4ACB}, +{0x002A, 0x0C88}, +{0x0F12, 0x0A7C}, +{0x002A, 0x0538}, +{0x0F12, 0x0000}, +{0x0F12, 0x001F}, +{0x0F12, 0x0035}, +{0x0F12, 0x005A}, +{0x0F12, 0x0095}, +{0x0F12, 0x00E6}, +{0x0F12, 0x0121}, +{0x0F12, 0x0139}, +{0x0F12, 0x0150}, +{0x0F12, 0x0177}, +{0x0F12, 0x019A}, +{0x0F12, 0x01BB}, +{0x0F12, 0x01DC}, +{0x0F12, 0x0219}, +{0x0F12, 0x0251}, +{0x0F12, 0x02B3}, +{0x0F12, 0x030A}, +{0x0F12, 0x035F}, +{0x0F12, 0x03B1}, +{0x0F12, 0x03FF}, +{0x0F12, 0x0000}, +{0x0F12, 0x0001}, +{0x0F12, 0x0001}, +{0x0F12, 0x0002}, +{0x0F12, 0x0004}, +{0x0F12, 0x000A}, +{0x0F12, 0x0012}, +{0x0F12, 0x0016}, +{0x0F12, 0x001A}, +{0x0F12, 0x0024}, +{0x0F12, 0x0031}, +{0x0F12, 0x003E}, +{0x0F12, 0x004E}, +{0x0F12, 0x0075}, +{0x0F12, 0x00A8}, +{0x0F12, 0x0126}, +{0x0F12, 0x01BE}, +{0x0F12, 0x0272}, +{0x0F12, 0x0334}, +{0x0F12, 0x03FF}, +{0x002A, 0x33A4}, +{0x0F12, 0x01D0}, +{0x0F12, 0xFFA1}, +{0x0F12, 0xFFFA}, +{0x0F12, 0xFF6F}, +{0x0F12, 0x0140}, +{0x0F12, 0xFF49}, +{0x0F12, 0xFFC1}, +{0x0F12, 0x001F}, +{0x0F12, 0x01BD}, +{0x0F12, 0x013F}, +{0x0F12, 0x00E1}, +{0x0F12, 0xFF43}, +{0x0F12, 0x0191}, +{0x0F12, 0xFFC0}, +{0x0F12, 0x01B7}, +{0x0F12, 0xFF30}, +{0x0F12, 0x015F}, +{0x0F12, 0x0106}, +{0x0F12, 0x01D0}, +{0x0F12, 0xFFA1}, +{0x0F12, 0xFFFA}, +{0x0F12, 0xFF6F}, +{0x0F12, 0x0140}, +{0x0F12, 0xFF49}, +{0x0F12, 0xFFC1}, +{0x0F12, 0x001F}, +{0x0F12, 0x01BD}, +{0x0F12, 0x013F}, +{0x0F12, 0x00E1}, +{0x0F12, 0xFF43}, +{0x0F12, 0x0191}, +{0x0F12, 0xFFC0}, +{0x0F12, 0x01B7}, +{0x0F12, 0xFF30}, +{0x0F12, 0x015F}, +{0x0F12, 0x0106}, +{0x0F12, 0x01D0}, +{0x0F12, 0xFFA1}, +{0x0F12, 0xFFFA}, +{0x0F12, 0xFF6F}, +{0x0F12, 0x0140}, +{0x0F12, 0xFF49}, +{0x0F12, 0xFFC1}, +{0x0F12, 0x001F}, +{0x0F12, 0x01BD}, +{0x0F12, 0x013F}, +{0x0F12, 0x00E1}, +{0x0F12, 0xFF43}, +{0x0F12, 0x0191}, +{0x0F12, 0xFFC0}, +{0x0F12, 0x01B7}, +{0x0F12, 0xFF30}, +{0x0F12, 0x015F}, +{0x0F12, 0x0106}, +{0x0F12, 0x01D0}, +{0x0F12, 0xFFA1}, +{0x0F12, 0xFFFA}, +{0x0F12, 0xFF6F}, +{0x0F12, 0x0140}, +{0x0F12, 0xFF49}, +{0x0F12, 0xFFC1}, +{0x0F12, 0x001F}, +{0x0F12, 0x01BD}, +{0x0F12, 0x013F}, +{0x0F12, 0x00E1}, +{0x0F12, 0xFF43}, +{0x0F12, 0x0191}, +{0x0F12, 0xFFC0}, +{0x0F12, 0x01B7}, +{0x0F12, 0xFF30}, +{0x0F12, 0x015F}, +{0x0F12, 0x0106}, +{0x0F12, 0x01BF}, +{0x0F12, 0xFFBF}, +{0x0F12, 0xFFFE}, +{0x0F12, 0xFF6D}, +{0x0F12, 0x01B4}, +{0x0F12, 0xFF66}, +{0x0F12, 0xFFCA}, +{0x0F12, 0xFFCE}, +{0x0F12, 0x017B}, +{0x0F12, 0x0136}, +{0x0F12, 0x0132}, +{0x0F12, 0xFF85}, +{0x0F12, 0x018B}, +{0x0F12, 0xFF73}, +{0x0F12, 0x0191}, +{0x0F12, 0xFF3F}, +{0x0F12, 0x015B}, +{0x0F12, 0x00D0}, +{0x0F12, 0x01BF}, +{0x0F12, 0xFFBF}, +{0x0F12, 0xFFFE}, +{0x0F12, 0xFF6D}, +{0x0F12, 0x01B4}, +{0x0F12, 0xFF66}, +{0x0F12, 0xFFCA}, +{0x0F12, 0xFFCE}, +{0x0F12, 0x017B}, +{0x0F12, 0x0136}, +{0x0F12, 0x0132}, +{0x0F12, 0xFF85}, +{0x0F12, 0x018B}, +{0x0F12, 0xFF73}, +{0x0F12, 0x0191}, +{0x0F12, 0xFF3F}, +{0x0F12, 0x015B}, +{0x0F12, 0x00D0}, +{0x002A, 0x3380}, +{0x0F12, 0x01AC}, +{0x0F12, 0xFFD7}, +{0x0F12, 0x0019}, +{0x0F12, 0xFF49}, +{0x0F12, 0x01D9}, +{0x0F12, 0xFF63}, +{0x0F12, 0xFFCA}, +{0x0F12, 0xFFCE}, +{0x0F12, 0x017B}, +{0x0F12, 0x0132}, +{0x0F12, 0x012E}, +{0x0F12, 0xFF8D}, +{0x0F12, 0x018B}, +{0x0F12, 0xFF73}, +{0x0F12, 0x0191}, +{0x0F12, 0xFF3F}, +{0x0F12, 0x015B}, +{0x0F12, 0x00D0}, +{0x002A, 0x0612}, +{0x0F12, 0x009D}, +{0x0F12, 0x00D5}, +{0x0F12, 0x0103}, +{0x0F12, 0x0128}, +{0x0F12, 0x0166}, +{0x0F12, 0x0193}, +{0x002A, 0x0D40}, +{0x0F12, 0x003E}, +{0x002A, 0x0498}, +{0x0F12, 0x0000}, +{0x0F12, 0x0002}, +{0x0F12, 0x0007}, +{0x0F12, 0x001D}, +{0x0F12, 0x006E}, +{0x0F12, 0x00D3}, +{0x0F12, 0x0127}, +{0x0F12, 0x014C}, +{0x0F12, 0x016E}, +{0x0F12, 0x01A5}, +{0x0F12, 0x01D3}, +{0x0F12, 0x01FB}, +{0x0F12, 0x021F}, +{0x0F12, 0x0260}, +{0x0F12, 0x029A}, +{0x0F12, 0x02F7}, +{0x0F12, 0x034D}, +{0x0F12, 0x0395}, +{0x0F12, 0x03CE}, +{0x0F12, 0x03FF}, +{0x0F12, 0x0000}, +{0x0F12, 0x0004}, +{0x0F12, 0x000C}, +{0x0F12, 0x0024}, +{0x0F12, 0x006E}, +{0x0F12, 0x00D1}, +{0x0F12, 0x0119}, +{0x0F12, 0x0139}, +{0x0F12, 0x0157}, +{0x0F12, 0x018E}, +{0x0F12, 0x01C3}, +{0x0F12, 0x01F3}, +{0x0F12, 0x021F}, +{0x0F12, 0x0269}, +{0x0F12, 0x02A6}, +{0x0F12, 0x02FF}, +{0x0F12, 0x0351}, +{0x0F12, 0x0395}, +{0x0F12, 0x03CE}, +{0x0F12, 0x03FF}, +{0x002A, 0x06D4}, +{0x0F12, 0x0032}, +{0x0F12, 0x0078}, +{0x0F12, 0x00C8}, +{0x0F12, 0x0190}, +{0x0F12, 0x028C}, +{0x002A, 0x0734}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0078}, +{0x0F12, 0x012C}, +{0x0F12, 0x03FF}, +{0x0F12, 0x0014}, +{0x0F12, 0x0064}, +{0x0F12, 0x000C}, +{0x0F12, 0x0010}, +{0x0F12, 0x01E6}, +{0x0F12, 0x0000}, +{0x0F12, 0x0070}, +{0x0F12, 0x01FF}, +{0x0F12, 0x0144}, +{0x0F12, 0x000F}, +{0x0F12, 0x000A}, +{0x0F12, 0x0073}, +{0x0F12, 0x0087}, +{0x0F12, 0x0014}, +{0x0F12, 0x000A}, +{0x0F12, 0x0023}, +{0x0F12, 0x001E}, +{0x0F12, 0x0014}, +{0x0F12, 0x000A}, +{0x0F12, 0x0023}, +{0x0F12, 0x0046}, +{0x0F12, 0x2B32}, +{0x0F12, 0x0601}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x00FF}, +{0x0F12, 0x07FF}, +{0x0F12, 0xFFFF}, +{0x0F12, 0x0000}, +{0x0F12, 0x050D}, +{0x0F12, 0x1E80}, +{0x0F12, 0x0000}, +{0x0F12, 0x1408}, +{0x0F12, 0x0214}, +{0x0F12, 0xFF01}, +{0x0F12, 0x180F}, +{0x0F12, 0x0001}, +{0x0F12, 0x0000}, +{0x0F12, 0x8003}, +{0x0F12, 0x0094}, +{0x0F12, 0x0580}, +{0x0F12, 0x0180}, +{0x0F12, 0x0308}, +{0x0F12, 0x3186}, +{0x0F12, 0x5260}, +{0x0F12, 0x0A02}, +{0x0F12, 0x080A}, +{0x0F12, 0x0500}, +{0x0F12, 0x032D}, +{0x0F12, 0x324E}, +{0x0F12, 0x001E}, +{0x0F12, 0x0200}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x9696}, +{0x0F12, 0x4646}, +{0x0F12, 0x0802}, +{0x0F12, 0x0802}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3202}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x9696}, +{0x0F12, 0x4646}, +{0x0F12, 0x0802}, +{0x0F12, 0x0802}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3202}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0003}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x006A}, +{0x0F12, 0x012C}, +{0x0F12, 0x03FF}, +{0x0F12, 0x0014}, +{0x0F12, 0x0064}, +{0x0F12, 0x000C}, +{0x0F12, 0x0010}, +{0x0F12, 0x01E6}, +{0x0F12, 0x03FF}, +{0x0F12, 0x0070}, +{0x0F12, 0x007D}, +{0x0F12, 0x0064}, +{0x0F12, 0x0014}, +{0x0F12, 0x000A}, +{0x0F12, 0x0073}, +{0x0F12, 0x0087}, +{0x0F12, 0x0014}, +{0x0F12, 0x000A}, +{0x0F12, 0x0023}, +{0x0F12, 0x001E}, +{0x0F12, 0x0014}, +{0x0F12, 0x000A}, +{0x0F12, 0x0023}, +{0x0F12, 0x001E}, +{0x0F12, 0x2B32}, +{0x0F12, 0x0601}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x00FF}, +{0x0F12, 0x07FF}, +{0x0F12, 0xFFFF}, +{0x0F12, 0x0000}, +{0x0F12, 0x050D}, +{0x0F12, 0x1E80}, +{0x0F12, 0x0000}, +{0x0F12, 0x1408}, +{0x0F12, 0x0214}, +{0x0F12, 0xFF01}, +{0x0F12, 0x180F}, +{0x0F12, 0x0002}, +{0x0F12, 0x0000}, +{0x0F12, 0x8003}, +{0x0F12, 0x0080}, +{0x0F12, 0x0080}, +{0x0F12, 0x0180}, +{0x0F12, 0x0308}, +{0x0F12, 0x1E65}, +{0x0F12, 0x1A24}, +{0x0F12, 0x0A03}, +{0x0F12, 0x080A}, +{0x0F12, 0x0500}, +{0x0F12, 0x032D}, +{0x0F12, 0x324D}, +{0x0F12, 0x001E}, +{0x0F12, 0x0200}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x9696}, +{0x0F12, 0x2F34}, +{0x0F12, 0x0504}, +{0x0F12, 0x080F}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3208}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x9696}, +{0x0F12, 0x1414}, +{0x0F12, 0x0504}, +{0x0F12, 0x080F}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3208}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0003}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0064}, +{0x0F12, 0x012C}, +{0x0F12, 0x03FF}, +{0x0F12, 0x0014}, +{0x0F12, 0x0064}, +{0x0F12, 0x000C}, +{0x0F12, 0x0010}, +{0x0F12, 0x01E6}, +{0x0F12, 0x03FF}, +{0x0F12, 0x0070}, +{0x0F12, 0x007D}, +{0x0F12, 0x0064}, +{0x0F12, 0x0014}, +{0x0F12, 0x0023}, +{0x0F12, 0x0073}, +{0x0F12, 0x0087}, +{0x0F12, 0x0014}, +{0x0F12, 0x0019}, +{0x0F12, 0x0023}, +{0x0F12, 0x001E}, +{0x0F12, 0x0014}, +{0x0F12, 0x0019}, +{0x0F12, 0x0023}, +{0x0F12, 0x001E}, +{0x0F12, 0x2B32}, +{0x0F12, 0x0601}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x00FF}, +{0x0F12, 0x07FF}, +{0x0F12, 0xFFFF}, +{0x0F12, 0x0000}, +{0x0F12, 0x050D}, +{0x0F12, 0x1E80}, +{0x0F12, 0x0000}, +{0x0F12, 0x0A08}, +{0x0F12, 0x0200}, +{0x0F12, 0xFF01}, +{0x0F12, 0x180F}, +{0x0F12, 0x0002}, +{0x0F12, 0x0000}, +{0x0F12, 0x8003}, +{0x0F12, 0x0080}, +{0x0F12, 0x0080}, +{0x0F12, 0x0180}, +{0x0F12, 0x0208}, +{0x0F12, 0x1E4B}, +{0x0F12, 0x1A24}, +{0x0F12, 0x0A05}, +{0x0F12, 0x080A}, +{0x0F12, 0x0500}, +{0x0F12, 0x032D}, +{0x0F12, 0x324D}, +{0x0F12, 0x001E}, +{0x0F12, 0x0200}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x9696}, +{0x0F12, 0x1E23}, +{0x0F12, 0x0505}, +{0x0F12, 0x080F}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3208}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x9696}, +{0x0F12, 0x1E23}, +{0x0F12, 0x0505}, +{0x0F12, 0x080F}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3208}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0003}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0064}, +{0x0F12, 0x012C}, +{0x0F12, 0x03FF}, +{0x0F12, 0x0014}, +{0x0F12, 0x0064}, +{0x0F12, 0x000C}, +{0x0F12, 0x0010}, +{0x0F12, 0x01E6}, +{0x0F12, 0x0000}, +{0x0F12, 0x0070}, +{0x0F12, 0x007D}, +{0x0F12, 0x0064}, +{0x0F12, 0x0028}, +{0x0F12, 0x0023}, +{0x0F12, 0x0073}, +{0x0F12, 0x009F}, +{0x0F12, 0x0028}, +{0x0F12, 0x0028}, +{0x0F12, 0x0023}, +{0x0F12, 0x0037}, +{0x0F12, 0x0028}, +{0x0F12, 0x0028}, +{0x0F12, 0x0023}, +{0x0F12, 0x0037}, +{0x0F12, 0x2B32}, +{0x0F12, 0x0601}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x00FF}, +{0x0F12, 0x07A0}, +{0x0F12, 0xFFFF}, +{0x0F12, 0x0000}, +{0x0F12, 0x050D}, +{0x0F12, 0x1E80}, +{0x0F12, 0x0000}, +{0x0F12, 0x0A08}, +{0x0F12, 0x0200}, +{0x0F12, 0xFF01}, +{0x0F12, 0x180F}, +{0x0F12, 0x0001}, +{0x0F12, 0x0000}, +{0x0F12, 0x8003}, +{0x0F12, 0x0080}, +{0x0F12, 0x0080}, +{0x0F12, 0x0180}, +{0x0F12, 0x0108}, +{0x0F12, 0x1E32}, +{0x0F12, 0x1A24}, +{0x0F12, 0x0A05}, +{0x0F12, 0x080A}, +{0x0F12, 0x0000}, +{0x0F12, 0x0328}, +{0x0F12, 0x324C}, +{0x0F12, 0x001E}, +{0x0F12, 0x0200}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x9696}, +{0x0F12, 0x0F0F}, +{0x0F12, 0x0307}, +{0x0F12, 0x080F}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3208}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x9696}, +{0x0F12, 0x0F0F}, +{0x0F12, 0x0307}, +{0x0F12, 0x080F}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3208}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0003}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0028}, +{0x0F12, 0x012C}, +{0x0F12, 0x03FF}, +{0x0F12, 0x0014}, +{0x0F12, 0x0064}, +{0x0F12, 0x000C}, +{0x0F12, 0x0010}, +{0x0F12, 0x01E6}, +{0x0F12, 0x0000}, +{0x0F12, 0x0070}, +{0x0F12, 0x0087}, +{0x0F12, 0x0073}, +{0x0F12, 0x0028}, +{0x0F12, 0x0023}, +{0x0F12, 0x0073}, +{0x0F12, 0x00B4}, +{0x0F12, 0x0028}, +{0x0F12, 0x0028}, +{0x0F12, 0x0023}, +{0x0F12, 0x0046}, +{0x0F12, 0x0028}, +{0x0F12, 0x0028}, +{0x0F12, 0x0023}, +{0x0F12, 0x0046}, +{0x0F12, 0x2B23}, +{0x0F12, 0x0601}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x0F12, 0x00FF}, +{0x0F12, 0x0B84}, +{0x0F12, 0xFFFF}, +{0x0F12, 0x0000}, +{0x0F12, 0x050D}, +{0x0F12, 0x1E80}, +{0x0F12, 0x0000}, +{0x0F12, 0x0A08}, +{0x0F12, 0x0200}, +{0x0F12, 0xFF01}, +{0x0F12, 0x180F}, +{0x0F12, 0x0001}, +{0x0F12, 0x0000}, +{0x0F12, 0x8003}, +{0x0F12, 0x0080}, +{0x0F12, 0x0080}, +{0x0F12, 0x0180}, +{0x0F12, 0x0108}, +{0x0F12, 0x1E1E}, +{0x0F12, 0x1419}, +{0x0F12, 0x0A0A}, +{0x0F12, 0x0800}, +{0x0F12, 0x0000}, +{0x0F12, 0x0328}, +{0x0F12, 0x324C}, +{0x0F12, 0x001E}, +{0x0F12, 0x0200}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x6464}, +{0x0F12, 0x0F0F}, +{0x0F12, 0x0307}, +{0x0F12, 0x080F}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3208}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0103}, +{0x0F12, 0x010C}, +{0x0F12, 0x6464}, +{0x0F12, 0x0F0F}, +{0x0F12, 0x0307}, +{0x0F12, 0x080F}, +{0x0F12, 0x0000}, +{0x0F12, 0x030F}, +{0x0F12, 0x3208}, +{0x0F12, 0x0F1E}, +{0x0F12, 0x020F}, +{0x0F12, 0x0003}, +{0x0F12, 0x7F5E}, +{0x0F12, 0xFEEE}, +{0x0F12, 0xD9B7}, +{0x0F12, 0x0472}, +{0x0F12, 0x0001}, +{0x002A, 0x01BE}, +{0x0F12, 0x0280}, +{0x0F12, 0x01e0}, +{0x0F12, 0x0005}, +{0x002A, 0x01C8}, +{0x0F12, 0x0000}, +{0x002A, 0x01C4}, +{0x0F12, 0x0052}, +{0x002A, 0x01D4}, +{0x0F12, 0x0002}, +{0x002A, 0x01D2}, +{0x0F12, 0x0000}, +{0x002A, 0x01D8}, +{0x0F12, 0x0535}, +{0x002A, 0x01D6}, +{0x0F12, 0x029A}, +{0x002A, 0x01E8}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x01EE}, +{0x0F12, 0x0500}, +{0x0F12, 0x03C0}, +{0x0F12, 0x0005}, +{0x002A, 0x01F8}, +{0x0F12, 0x0000}, +{0x002A, 0x01F4}, +{0x0F12, 0x0052}, +{0x002A, 0x0204}, +{0x0F12, 0x0002}, +{0x002A, 0x0202}, +{0x0F12, 0x0001}, +{0x002A, 0x0208}, +{0x0F12, 0x0535}, +{0x002A, 0x0206}, +{0x0F12, 0x0000}, +{0x002A, 0x0218}, +{0x0F12, 0x0000}, +{0x0F12, 0x0000}, +{0x002A, 0x02B0}, +{0x0F12, 0x0500}, +{0x0F12, 0x03C0}, +{0x0F12, 0x0005}, +{0x002A, 0x02BA}, +{0x0F12, 0x0000}, +{0x002A, 0x02B6}, +{0x0F12, 0x0052}, +{0x002A, 0x02C6}, +{0x0F12, 0x0002}, +{0x002A, 0x02C4}, +{0x0F12, 0x0002}, +{0x002A, 0x02CA}, +{0x0F12, 0x0535}, +{0x002A, 0x02C8}, +{0x0F12, 0x0000}, +{0x002A, 0x01A8}, +{0x0F12, 0x0000}, +{0x002A, 0x01B0}, +{0x0F12, 0x0000}, +{0x002A, 0x1278}, +{0x0F12, 0xAAF0}, +{0x002A, 0x0408}, +{0x0F12, 0x067F}, +{0x002A, 0x03F4}, +{0x0F12, 0x0002}, +{0x0F12, 0x0001}, +{0x002A, 0x012E}, +{0x0F12, 0x5DC0}, +{0x0F12, 0x0000}, +{0x002A, 0x0146}, +{0x0F12, 0x0000}, +{0x0F12, 0x0001}, +{0x002A, 0x014C}, +{0x0F12, 0x34BC}, +{0x002A, 0x0152}, +{0x0F12, 0x6977}, +{0x002A, 0x014E}, +{0x0F12, 0x6978}, +{0x002A, 0x019E}, +{0x0F12, 0x0001}, +{0x0F12, 0x0001}, +{0x002A, 0x0164}, +{0x0F12, 0x0001}, +{0x0028, 0xD000}, +{0x002A, 0x1000}, +{0x0F12, 0x0001}, +{0xffff, 0x000A}, +{0x0028, 0x7000}, +{0x002A, 0x0C86}, +{0x0F12, 0x0005}, +{0x002A, 0x0C70}, +{0x0F12, 0xFF70}, +{0x0F12, 0x00C3}, +{0x0F12, 0xFF18}, +{0x0F12, 0x0102}, +{0x0F12, 0xFEE8}, +{0x0F12, 0x0121}, +{0x0F12, 0xFECC}, +{0x0F12, 0x0143}, +{0x0F12, 0xFEB0}, +{0x0F12, 0x0157}, +{0x0F12, 0x1388}, +{0x002A, 0x0C8A}, +{0x0F12, 0x4DFC}, +{0x002A, 0x0C88}, +{0x0F12, 0x5A10}, +}; + + + +struct s5k8aay_short_t s5k8aay_preview[] = { + +{0xFCFC, 0xD000}, +{0x0028, 0x7000}, +{0x002A, 0x01A8}, +{0x0F12, 0x0000}, +{0x002A, 0x01A6}, +{0x0F12, 0x0001}, +{0x002A, 0x01AA}, +{0x0F12, 0x0001}, +{0x002A, 0x019E}, +{0x0F12, 0x0001}, +{0x0F12, 0x0001}, +{0xffff, 0x0096}, +}; + + + +struct s5k8aay_short_t s5k8aay_capture[] = { + +{0xFCFC, 0xD000}, +{0x0028, 0x7000}, +{0x002A, 0x01B0}, +{0x0F12, 0x0000}, +{0x002A, 0x01A6}, +{0x0F12, 0x0001}, +{0x002A, 0x01B2}, +{0x0F12, 0x0001}, +{0x002A, 0x01A2}, +{0x0F12, 0x0001}, +{0x0F12, 0x0001}, +{0xffff, 0x0096}, + +}; +#endif diff --git a/drivers/media/video/msm_zsl/s5k8aay_regs_v2.h b/drivers/media/video/msm_zsl/s5k8aay_regs_v2.h new file mode 100644 index 00000000000..1cf9da6f655 --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k8aay_regs_v2.h @@ -0,0 +1,9631 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + * ============================================================ + * 00.History + * ============================================================ + * 2011 : EVT1 + * 20111109 : LSI CSE Standard + * 20111110 : Shading, AWB, Contrast Tuning + * 20111114 : AE Weight Tuning + * ============================================================ + */ + +#ifdef __S5K8AAY_H__ +#define __S5K8AAY_H__ + +struct s5k8aay_short_t { + unsigned short subaddr; + unsigned int value; +}; + +/*====================================== + * 8AA M0 Capture mode final setfile + * 1280x960, 7.5fps, no binning, YUV422 + * Includes LT, FE, AS, WB, Outdoor detector, + * Pre/Post Gamma, CCM, Gamma and AFIT + *====================================== + */ + +struct s5k8aay_short_t s5k8aay_common[] = { +/* Start of Self-Cam init */ + +/**************************************/ +/* 01.Start Setting */ +/**************************************/ +{0xFCFC, 0xD000}, +{0x0010, 0x0001}, /* S/W Reset */ +{0xFCFC, 0x0000}, +{0x0000, 0x0000}, /* Simmian bug workaround */ + +{0xFCFC, 0xD000}, +{0x1030, 0x0000}, /* contint_host_int */ +{0x0014, 0x0001}, + +{0xffff, 0x0001}, /* Delay 1ms */ + +/**************************************/ +/*02.ETC Setting */ +/**************************************/ +{0x002A, 0x1278}, +{0x0F12, 0xAAF0}, /* gisp_dadlc_config Ladlc mode average*/ + +/************************************** + * 03.Analog Setting & ASP Control + ************************************** + * This register is for FACTORY ONLY. + * If you change it without prior notification + * YOU are RESPONSIBLE for the FAILURE + * that will happen in the future + * For CDS Timing + ************************************** + */ +{0x002A, 0x0EC6}, +{0x0F12, 0x000B}, /* 11d aig_fdba_ptr0 */ +{0x002A, 0x0ECE}, +{0x0F12, 0x000B}, /* 11d aig_fdbb_ptr0 */ +{0x002A, 0x0F16}, +{0x0F12, 0x002B}, /* 43d aig_sfdba_reg0 */ +{0x002A, 0x0F1E}, +{0x0F12, 0x002B}, /* 43d aig_sfdbb_reg0 */ +{0x002A, 0x0EC8}, +{0x0F12, 0x000B}, /* 11d aig_fdba_ptr0 */ +{0x002A, 0x0ED0}, +{0x0F12, 0x033F}, /* 831d aig_fdbb_ptr0 */ +{0x002A, 0x0F18}, +{0x0F12, 0x0366}, /* 870d aig_sfdba_reg0 */ +{0x002A, 0x0F20}, +{0x0F12, 0x0032}, /* 50d aig_sfdbb_reg0 */ + +/* For Other Analog Settings */ +{0x002A, 0x0E38}, +{0x0F12, 0x0476}, /* senHal_RegCompBiasNormSf CDS bias */ +{0x0F12, 0x0476}, /* senHal_RegCompBiasYAv CDS bias */ +{0x002A, 0x0AA0}, +{0x0F12, 0x0001}, /* setot_bUseDigitalHbin 1-Digital, 0-Analog */ +{0x002A, 0x0E2C}, +{0x0F12, 0x0001}, +{0x002A, 0x1250}, +{0x0F12, 0xFFFF}, /* senHal_Bls_nSpExpLines */ +{0x002A, 0x1202}, +{0x0F12, 0x0010}, /* senHal_Dblr_VcoFreqMHZ */ + +/**************************************/ +/* 04.Trap and Patch */ +/**************************************/ +/* Start of Patch data */ +{0x0028, 0x7000}, +{0x002A, 0x2470}, +{0x0F12, 0xB510}, /* 70002470 */ +{0x0F12, 0x490D}, /* 70002472 */ +{0x0F12, 0x480D}, /* 70002474 */ +{0x0F12, 0xF000}, /* 70002476 */ +{0x0F12, 0xF96D}, /* 70002478 */ +{0x0F12, 0x490D}, /* 7000247A */ +{0x0F12, 0x480D}, /* 7000247C */ +{0x0F12, 0xF000}, /* 7000247E */ +{0x0F12, 0xF969}, /* 70002480 */ +{0x0F12, 0x490D}, /* 70002482 */ +{0x0F12, 0x480D}, /* 70002484 */ +{0x0F12, 0x6341}, /* 70002486 */ +{0x0F12, 0x490D}, /* 70002488 */ +{0x0F12, 0x480E}, /* 7000248A */ +{0x0F12, 0xF000}, /* 7000248C */ +{0x0F12, 0xF962}, /* 7000248E */ +{0x0F12, 0x490D}, /* 70002490 */ +{0x0F12, 0x480E}, /* 70002492 */ +{0x0F12, 0xF000}, /* 70002494 */ +{0x0F12, 0xF95E}, /* 70002496 */ +{0x0F12, 0x490D}, /* 70002498 */ +{0x0F12, 0x480E}, /* 7000249A */ +{0x0F12, 0xF000}, /* 7000249C */ +{0x0F12, 0xF95A}, /* 7000249E */ +{0x0F12, 0xBC10}, /* 700024A0 */ +{0x0F12, 0xBC08}, /* 700024A2 */ +{0x0F12, 0x4718}, /* 700024A4 */ +{0x0F12, 0x0000}, /* 700024A6 */ +{0x0F12, 0x26D4}, /* 700024A8 */ +{0x0F12, 0x7000}, /* 700024AA */ +{0x0F12, 0x8EDD}, /* 700024AC */ +{0x0F12, 0x0000}, /* 700024AE */ +{0x0F12, 0x264C}, /* 700024B0 */ +{0x0F12, 0x7000}, /* 700024B2 */ +{0x0F12, 0x8725}, /* 700024B4 */ +{0x0F12, 0x0000}, /* 700024B6 */ +{0x0F12, 0x25EC}, /* 700024B8 */ +{0x0F12, 0x7000}, /* 700024BA */ +{0x0F12, 0x0080}, /* 700024BC */ +{0x0F12, 0x7000}, /* 700024BE */ +{0x0F12, 0x2540}, /* 700024C0 */ +{0x0F12, 0x7000}, /* 700024C2 */ +{0x0F12, 0xA6EF}, /* 700024C4 */ +{0x0F12, 0x0000}, /* 700024C6 */ +{0x0F12, 0x250C}, /* 700024C8 */ +{0x0F12, 0x7000}, /* 700024CA */ +{0x0F12, 0xA0F1}, /* 700024CC */ +{0x0F12, 0x0000}, /* 700024CE */ +{0x0F12, 0x24D8}, /* 700024D0 */ +{0x0F12, 0x7000}, /* 700024D2 */ +{0x0F12, 0x058F}, /* 700024D4 */ +{0x0F12, 0x0000}, /* 700024D6 */ +{0x0F12, 0x4010}, /* 700024D8 */ +{0x0F12, 0xE92D}, /* 700024DA */ +{0x0F12, 0x00A0}, /* 700024DC */ +{0x0F12, 0xEB00}, /* 700024DE */ +{0x0F12, 0x023C}, /* 700024E0 */ +{0x0F12, 0xE59F}, /* 700024E2 */ +{0x0F12, 0x00B2}, /* 700024E4 */ +{0x0F12, 0xE1D0}, /* 700024E6 */ +{0x0F12, 0x0000}, /* 700024E8 */ +{0x0F12, 0xE350}, /* 700024EA */ +{0x0F12, 0x0004}, /* 700024EC */ +{0x0F12, 0x0A00}, /* 700024EE */ +{0x0F12, 0x0080}, /* 700024F0 */ +{0x0F12, 0xE310}, /* 700024F2 */ +{0x0F12, 0x0002}, /* 700024F4 */ +{0x0F12, 0x1A00}, /* 700024F6 */ +{0x0F12, 0x1228}, /* 700024F8 */ +{0x0F12, 0xE59F}, /* 700024FA */ +{0x0F12, 0x0001}, /* 700024FC */ +{0x0F12, 0xE3A0}, /* 700024FE */ +{0x0F12, 0x0DB2}, /* 70002500 */ +{0x0F12, 0xE1C1}, /* 70002502 */ +{0x0F12, 0x4010}, /* 70002504 */ +{0x0F12, 0xE8BD}, /* 70002506 */ +{0x0F12, 0xFF1E}, /* 70002508 */ +{0x0F12, 0xE12F}, /* 7000250A */ +{0x0F12, 0x4010}, /* 7000250C */ +{0x0F12, 0xE92D}, /* 7000250E */ +{0x0F12, 0x4000}, /* 70002510 */ +{0x0F12, 0xE590}, /* 70002512 */ +{0x0F12, 0x0004}, /* 70002514 */ +{0x0F12, 0xE1A0}, /* 70002516 */ +{0x0F12, 0x0094}, /* 70002518 */ +{0x0F12, 0xEB00}, /* 7000251A */ +{0x0F12, 0x0208}, /* 7000251C */ +{0x0F12, 0xE59F}, /* 7000251E */ +{0x0F12, 0x0000}, /* 70002520 */ +{0x0F12, 0xE5D0}, /* 70002522 */ +{0x0F12, 0x0000}, /* 70002524 */ +{0x0F12, 0xE350}, /* 70002526 */ +{0x0F12, 0x0002}, /* 70002528 */ +{0x0F12, 0x0A00}, /* 7000252A */ +{0x0F12, 0x0004}, /* 7000252C */ +{0x0F12, 0xE594}, /* 7000252E */ +{0x0F12, 0x00A0}, /* 70002530 */ +{0x0F12, 0xE1A0}, /* 70002532 */ +{0x0F12, 0x0004}, /* 70002534 */ +{0x0F12, 0xE584}, /* 70002536 */ +{0x0F12, 0x4010}, /* 70002538 */ +{0x0F12, 0xE8BD}, /* 7000253A */ +{0x0F12, 0xFF1E}, /* 7000253C */ +{0x0F12, 0xE12F}, /* 7000253E */ +{0x0F12, 0x4070}, /* 70002540 */ +{0x0F12, 0xE92D}, /* 70002542 */ +{0x0F12, 0x0000}, /* 70002544 */ +{0x0F12, 0xE590}, /* 70002546 */ +{0x0F12, 0x0800}, /* 70002548 */ +{0x0F12, 0xE1A0}, /* 7000254A */ +{0x0F12, 0x0820}, /* 7000254C */ +{0x0F12, 0xE1A0}, /* 7000254E */ +{0x0F12, 0x4041}, /* 70002550 */ +{0x0F12, 0xE280}, /* 70002552 */ +{0x0F12, 0x01D4}, /* 70002554 */ +{0x0F12, 0xE59F}, /* 70002556 */ +{0x0F12, 0x11B8}, /* 70002558 */ +{0x0F12, 0xE1D0}, /* 7000255A */ +{0x0F12, 0x51B6}, /* 7000255C */ +{0x0F12, 0xE1D0}, /* 7000255E */ +{0x0F12, 0x0005}, /* 70002560 */ +{0x0F12, 0xE041}, /* 70002562 */ +{0x0F12, 0x0094}, /* 70002564 */ +{0x0F12, 0xE000}, /* 70002566 */ +{0x0F12, 0x1D11}, /* 70002568 */ +{0x0F12, 0xE3A0}, /* 7000256A */ +{0x0F12, 0x0082}, /* 7000256C */ +{0x0F12, 0xEB00}, /* 7000256E */ +{0x0F12, 0x11B4}, /* 70002570 */ +{0x0F12, 0xE59F}, /* 70002572 */ +{0x0F12, 0x1000}, /* 70002574 */ +{0x0F12, 0xE5D1}, /* 70002576 */ +{0x0F12, 0x0000}, /* 70002578 */ +{0x0F12, 0xE351}, /* 7000257A */ +{0x0F12, 0x0000}, /* 7000257C */ +{0x0F12, 0x0A00}, /* 7000257E */ +{0x0F12, 0x00A0}, /* 70002580 */ +{0x0F12, 0xE1A0}, /* 70002582 */ +{0x0F12, 0x219C}, /* 70002584 */ +{0x0F12, 0xE59F}, /* 70002586 */ +{0x0F12, 0x3FB0}, /* 70002588 */ +{0x0F12, 0xE1D2}, /* 7000258A */ +{0x0F12, 0x0000}, /* 7000258C */ +{0x0F12, 0xE353}, /* 7000258E */ +{0x0F12, 0x0003}, /* 70002590 */ +{0x0F12, 0x0A00}, /* 70002592 */ +{0x0F12, 0x3198}, /* 70002594 */ +{0x0F12, 0xE59F}, /* 70002596 */ +{0x0F12, 0x5BB2}, /* 70002598 */ +{0x0F12, 0xE1C3}, /* 7000259A */ +{0x0F12, 0xC000}, /* 7000259C */ +{0x0F12, 0xE085}, /* 7000259E */ +{0x0F12, 0xCBB4}, /* 700025A0 */ +{0x0F12, 0xE1C3}, /* 700025A2 */ +{0x0F12, 0x0000}, /* 700025A4 */ +{0x0F12, 0xE351}, /* 700025A6 */ +{0x0F12, 0x0000}, /* 700025A8 */ +{0x0F12, 0x0A00}, /* 700025AA */ +{0x0F12, 0x0080}, /* 700025AC */ +{0x0F12, 0xE1A0}, /* 700025AE */ +{0x0F12, 0x1DBC}, /* 700025B0 */ +{0x0F12, 0xE1D2}, /* 700025B2 */ +{0x0F12, 0x3EB4}, /* 700025B4 */ +{0x0F12, 0xE1D2}, /* 700025B6 */ +{0x0F12, 0x2EB2}, /* 700025B8 */ +{0x0F12, 0xE1D2}, /* 700025BA */ +{0x0F12, 0x0193}, /* 700025BC */ +{0x0F12, 0xE001}, /* 700025BE */ +{0x0F12, 0x0092}, /* 700025C0 */ +{0x0F12, 0xE000}, /* 700025C2 */ +{0x0F12, 0x2811}, /* 700025C4 */ +{0x0F12, 0xE3A0}, /* 700025C6 */ +{0x0F12, 0x0194}, /* 700025C8 */ +{0x0F12, 0xE001}, /* 700025CA */ +{0x0F12, 0x0092}, /* 700025CC */ +{0x0F12, 0xE000}, /* 700025CE */ +{0x0F12, 0x11A1}, /* 700025D0 */ +{0x0F12, 0xE1A0}, /* 700025D2 */ +{0x0F12, 0x01A0}, /* 700025D4 */ +{0x0F12, 0xE1A0}, /* 700025D6 */ +{0x0F12, 0x0067}, /* 700025D8 */ +{0x0F12, 0xEB00}, /* 700025DA */ +{0x0F12, 0x1154}, /* 700025DC */ +{0x0F12, 0xE59F}, /* 700025DE */ +{0x0F12, 0x02B4}, /* 700025E0 */ +{0x0F12, 0xE1C1}, /* 700025E2 */ +{0x0F12, 0x4070}, /* 700025E4 */ +{0x0F12, 0xE8BD}, /* 700025E6 */ +{0x0F12, 0xFF1E}, /* 700025E8 */ +{0x0F12, 0xE12F}, /* 700025EA */ +{0x0F12, 0x4010}, /* 700025EC */ +{0x0F12, 0xE92D}, /* 700025EE */ +{0x0F12, 0x0063}, /* 700025F0 */ +{0x0F12, 0xEB00}, /* 700025F2 */ +{0x0F12, 0x213C}, /* 700025F4 */ +{0x0F12, 0xE59F}, /* 700025F6 */ +{0x0F12, 0x14B0}, /* 700025F8 */ +{0x0F12, 0xE1D2}, /* 700025FA */ +{0x0F12, 0x0080}, /* 700025FC */ +{0x0F12, 0xE311}, /* 700025FE */ +{0x0F12, 0x0005}, /* 70002600 */ +{0x0F12, 0x0A00}, /* 70002602 */ +{0x0F12, 0x0130}, /* 70002604 */ +{0x0F12, 0xE59F}, /* 70002606 */ +{0x0F12, 0x00B0}, /* 70002608 */ +{0x0F12, 0xE1D0}, /* 7000260A */ +{0x0F12, 0x0001}, /* 7000260C */ +{0x0F12, 0xE350}, /* 7000260E */ +{0x0F12, 0x0001}, /* 70002610 */ +{0x0F12, 0x9A00}, /* 70002612 */ +{0x0F12, 0x0001}, /* 70002614 */ +{0x0F12, 0xE3A0}, /* 70002616 */ +{0x0F12, 0x0000}, /* 70002618 */ +{0x0F12, 0xEA00}, /* 7000261A */ +{0x0F12, 0x0000}, /* 7000261C */ +{0x0F12, 0xE3A0}, /* 7000261E */ +{0x0F12, 0x3104}, /* 70002620 */ +{0x0F12, 0xE59F}, /* 70002622 */ +{0x0F12, 0x0000}, /* 70002624 */ +{0x0F12, 0xE5C3}, /* 70002626 */ +{0x0F12, 0x0000}, /* 70002628 */ +{0x0F12, 0xE5D3}, /* 7000262A */ +{0x0F12, 0x0000}, /* 7000262C */ +{0x0F12, 0xE350}, /* 7000262E */ +{0x0F12, 0x0003}, /* 70002630 */ +{0x0F12, 0x0A00}, /* 70002632 */ +{0x0F12, 0x0080}, /* 70002634 */ +{0x0F12, 0xE3C1}, /* 70002636 */ +{0x0F12, 0x1100}, /* 70002638 */ +{0x0F12, 0xE59F}, /* 7000263A */ +{0x0F12, 0x04B0}, /* 7000263C */ +{0x0F12, 0xE1C2}, /* 7000263E */ +{0x0F12, 0x00B2}, /* 70002640 */ +{0x0F12, 0xE1C1}, /* 70002642 */ +{0x0F12, 0x4010}, /* 70002644 */ +{0x0F12, 0xE8BD}, /* 70002646 */ +{0x0F12, 0xFF1E}, /* 70002648 */ +{0x0F12, 0xE12F}, /* 7000264A */ +{0x0F12, 0x41F0}, /* 7000264C */ +{0x0F12, 0xE92D}, /* 7000264E */ +{0x0F12, 0x1000}, /* 70002650 */ +{0x0F12, 0xE590}, /* 70002652 */ +{0x0F12, 0xC801}, /* 70002654 */ +{0x0F12, 0xE1A0}, /* 70002656 */ +{0x0F12, 0xC82C}, /* 70002658 */ +{0x0F12, 0xE1A0}, /* 7000265A */ +{0x0F12, 0x1004}, /* 7000265C */ +{0x0F12, 0xE590}, /* 7000265E */ +{0x0F12, 0x1801}, /* 70002660 */ +{0x0F12, 0xE1A0}, /* 70002662 */ +{0x0F12, 0x1821}, /* 70002664 */ +{0x0F12, 0xE1A0}, /* 70002666 */ +{0x0F12, 0x4008}, /* 70002668 */ +{0x0F12, 0xE590}, /* 7000266A */ +{0x0F12, 0x500C}, /* 7000266C */ +{0x0F12, 0xE590}, /* 7000266E */ +{0x0F12, 0x2004}, /* 70002670 */ +{0x0F12, 0xE1A0}, /* 70002672 */ +{0x0F12, 0x3005}, /* 70002674 */ +{0x0F12, 0xE1A0}, /* 70002676 */ +{0x0F12, 0x000C}, /* 70002678 */ +{0x0F12, 0xE1A0}, /* 7000267A */ +{0x0F12, 0x0043}, /* 7000267C */ +{0x0F12, 0xEB00}, /* 7000267E */ +{0x0F12, 0x60BC}, /* 70002680 */ +{0x0F12, 0xE59F}, /* 70002682 */ +{0x0F12, 0x00B2}, /* 70002684 */ +{0x0F12, 0xE1D6}, /* 70002686 */ +{0x0F12, 0x0000}, /* 70002688 */ +{0x0F12, 0xE350}, /* 7000268A */ +{0x0F12, 0x000E}, /* 7000268C */ +{0x0F12, 0x0A00}, /* 7000268E */ +{0x0F12, 0x00B0}, /* 70002690 */ +{0x0F12, 0xE59F}, /* 70002692 */ +{0x0F12, 0x05B4}, /* 70002694 */ +{0x0F12, 0xE1D0}, /* 70002696 */ +{0x0F12, 0x0002}, /* 70002698 */ +{0x0F12, 0xE350}, /* 7000269A */ +{0x0F12, 0x000A}, /* 7000269C */ +{0x0F12, 0x1A00}, /* 7000269E */ +{0x0F12, 0x70A4}, /* 700026A0 */ +{0x0F12, 0xE59F}, /* 700026A2 */ +{0x0F12, 0x10F4}, /* 700026A4 */ +{0x0F12, 0xE1D6}, /* 700026A6 */ +{0x0F12, 0x26B0}, /* 700026A8 */ +{0x0F12, 0xE1D7}, /* 700026AA */ +{0x0F12, 0x00F0}, /* 700026AC */ +{0x0F12, 0xE1D4}, /* 700026AE */ +{0x0F12, 0x0039}, /* 700026B0 */ +{0x0F12, 0xEB00}, /* 700026B2 */ +{0x0F12, 0x00B0}, /* 700026B4 */ +{0x0F12, 0xE1C4}, /* 700026B6 */ +{0x0F12, 0x26B0}, /* 700026B8 */ +{0x0F12, 0xE1D7}, /* 700026BA */ +{0x0F12, 0x10F6}, /* 700026BC */ +{0x0F12, 0xE1D6}, /* 700026BE */ +{0x0F12, 0x00F0}, /* 700026C0 */ +{0x0F12, 0xE1D5}, /* 700026C2 */ +{0x0F12, 0x0034}, /* 700026C4 */ +{0x0F12, 0xEB00}, /* 700026C6 */ +{0x0F12, 0x00B0}, /* 700026C8 */ +{0x0F12, 0xE1C5}, /* 700026CA */ +{0x0F12, 0x41F0}, /* 700026CC */ +{0x0F12, 0xE8BD}, /* 700026CE */ +{0x0F12, 0xFF1E}, /* 700026D0 */ +{0x0F12, 0xE12F}, /* 700026D2 */ +{0x0F12, 0x4010}, /* 700026D4 */ +{0x0F12, 0xE92D}, /* 700026D6 */ +{0x0F12, 0x4000}, /* 700026D8 */ +{0x0F12, 0xE1A0}, /* 700026DA */ +{0x0F12, 0x1004}, /* 700026DC */ +{0x0F12, 0xE594}, /* 700026DE */ +{0x0F12, 0x005C}, /* 700026E0 */ +{0x0F12, 0xE59F}, /* 700026E2 */ +{0x0F12, 0x00B0}, /* 700026E4 */ +{0x0F12, 0xE1D0}, /* 700026E6 */ +{0x0F12, 0x0000}, /* 700026E8 */ +{0x0F12, 0xE350}, /* 700026EA */ +{0x0F12, 0x0008}, /* 700026EC */ +{0x0F12, 0x0A00}, /* 700026EE */ +{0x0F12, 0x0054}, /* 700026F0 */ +{0x0F12, 0xE59F}, /* 700026F2 */ +{0x0F12, 0x3001}, /* 700026F4 */ +{0x0F12, 0xE1A0}, /* 700026F6 */ +{0x0F12, 0x2068}, /* 700026F8 */ +{0x0F12, 0xE590}, /* 700026FA */ +{0x0F12, 0x004C}, /* 700026FC */ +{0x0F12, 0xE59F}, /* 700026FE */ +{0x0F12, 0x1005}, /* 70002700 */ +{0x0F12, 0xE3A0}, /* 70002702 */ +{0x0F12, 0x0027}, /* 70002704 */ +{0x0F12, 0xEB00}, /* 70002706 */ +{0x0F12, 0x0000}, /* 70002708 */ +{0x0F12, 0xE584}, /* 7000270A */ +{0x0F12, 0x4010}, /* 7000270C */ +{0x0F12, 0xE8BD}, /* 7000270E */ +{0x0F12, 0xFF1E}, /* 70002710 */ +{0x0F12, 0xE12F}, /* 70002712 */ +{0x0F12, 0x0000}, /* 70002714 */ +{0x0F12, 0xE594}, /* 70002716 */ +{0x0F12, 0x0025}, /* 70002718 */ +{0x0F12, 0xEB00}, /* 7000271A */ +{0x0F12, 0x0000}, /* 7000271C */ +{0x0F12, 0xE584}, /* 7000271E */ +{0x0F12, 0xFFF9}, /* 70002720 */ +{0x0F12, 0xEAFF}, /* 70002722 */ +{0x0F12, 0x1728}, /* 70002724 */ +{0x0F12, 0x7000}, /* 70002726 */ +{0x0F12, 0x112C}, /* 70002728 */ +{0x0F12, 0x7000}, /* 7000272A */ +{0x0F12, 0x27C4}, /* 7000272C */ +{0x0F12, 0x7000}, /* 7000272E */ +{0x0F12, 0x122C}, /* 70002730 */ +{0x0F12, 0x7000}, /* 70002732 */ +{0x0F12, 0xF200}, /* 70002734 */ +{0x0F12, 0xD000}, /* 70002736 */ +{0x0F12, 0x2340}, /* 70002738 */ +{0x0F12, 0x7000}, /* 7000273A */ +{0x0F12, 0x0E2C}, /* 7000273C */ +{0x0F12, 0x7000}, /* 7000273E */ +{0x0F12, 0xF400}, /* 70002740 */ +{0x0F12, 0xD000}, /* 70002742 */ +{0x0F12, 0x3370}, /* 70002744 */ +{0x0F12, 0x7000}, /* 70002746 */ +{0x0F12, 0x0CDC}, /* 70002748 */ +{0x0F12, 0x7000}, /* 7000274A */ +{0x0F12, 0x20D4}, /* 7000274C */ +{0x0F12, 0x7000}, /* 7000274E */ +{0x0F12, 0x06D4}, /* 70002750 */ +{0x0F12, 0x7000}, /* 70002752 */ +{0x0F12, 0x4778}, /* 70002754 */ +{0x0F12, 0x46C0}, /* 70002756 */ +{0x0F12, 0xC000}, /* 70002758 */ +{0x0F12, 0xE59F}, /* 7000275A */ +{0x0F12, 0xFF1C}, /* 7000275C */ +{0x0F12, 0xE12F}, /* 7000275E */ +{0x0F12, 0xC091}, /* 70002760 */ +{0x0F12, 0x0000}, /* 70002762 */ +{0x0F12, 0xC000}, /* 70002764 */ +{0x0F12, 0xE59F}, /* 70002766 */ +{0x0F12, 0xFF1C}, /* 70002768 */ +{0x0F12, 0xE12F}, /* 7000276A */ +{0x0F12, 0x058F}, /* 7000276C */ +{0x0F12, 0x0000}, /* 7000276E */ +{0x0F12, 0xC000}, /* 70002770 */ +{0x0F12, 0xE59F}, /* 70002772 */ +{0x0F12, 0xFF1C}, /* 70002774 */ +{0x0F12, 0xE12F}, /* 70002776 */ +{0x0F12, 0xA0F1}, /* 70002778 */ +{0x0F12, 0x0000}, /* 7000277A */ +{0x0F12, 0xF004}, /* 7000277C */ +{0x0F12, 0xE51F}, /* 7000277E */ +{0x0F12, 0xD14C}, /* 70002780 */ +{0x0F12, 0x0000}, /* 70002782 */ +{0x0F12, 0xC000}, /* 70002784 */ +{0x0F12, 0xE59F}, /* 70002786 */ +{0x0F12, 0xFF1C}, /* 70002788 */ +{0x0F12, 0xE12F}, /* 7000278A */ +{0x0F12, 0x2B43}, /* 7000278C */ +{0x0F12, 0x0000}, /* 7000278E */ +{0x0F12, 0xC000}, /* 70002790 */ +{0x0F12, 0xE59F}, /* 70002792 */ +{0x0F12, 0xFF1C}, /* 70002794 */ +{0x0F12, 0xE12F}, /* 70002796 */ +{0x0F12, 0x8725}, /* 70002798 */ +{0x0F12, 0x0000}, /* 7000279A */ +{0x0F12, 0xC000}, /* 7000279C */ +{0x0F12, 0xE59F}, /* 7000279E */ +{0x0F12, 0xFF1C}, /* 700027A0 */ +{0x0F12, 0xE12F}, /* 700027A2 */ +{0x0F12, 0x6777}, /* 700027A4 */ +{0x0F12, 0x0000}, /* 700027A6 */ +{0x0F12, 0xC000}, /* 700027A8 */ +{0x0F12, 0xE59F}, /* 700027AA */ +{0x0F12, 0xFF1C}, /* 700027AC */ +{0x0F12, 0xE12F}, /* 700027AE */ +{0x0F12, 0x8E49}, /* 700027B0 */ +{0x0F12, 0x0000}, /* 700027B2 */ +{0x0F12, 0xC000}, /* 700027B4 */ +{0x0F12, 0xE59F}, /* 700027B6 */ +{0x0F12, 0xFF1C}, /* 700027B8 */ +{0x0F12, 0xE12F}, /* 700027BA */ +{0x0F12, 0x8EDD}, /* 700027BC */ +{0x0F12, 0x0000}, /* 700027BE */ +{0x0F12, 0x90C8}, /* 700027C0 */ +{0x0F12, 0x0000}, /* 700027C2 */ +/* End of Patch Data(Last : 700027C2h) */ +/* Total Size 852 (0x0354) */ +/* Addr : 2470 , Size : 850(352h) */ + +/**************************************/ +/* 05.OTP Control */ +/**************************************/ + +/**************************************/ +/* 06.GAS (Grid Anti-Shading) */ +/**************************************/ +{0x002A, 0x1326}, +{0x0F12, 0x0000}, /* gisp_gos_Enable */ +{0x002A, 0x063A}, +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__0_ Horizon */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__3_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__0_ IncandA */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__3_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__0_ WW */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__3_ */ +{0x0F12, 0x00E8}, /* TVAR_ash_GASAlpha_3__0_ CW */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__3_ */ +{0x0F12, 0x00E8}, /* TVAR_ash_GASAlpha_4__0_ D50 */ +{0x0F12, 0x00F8}, /* TVAR_ash_GASAlpha_4__1_ */ +{0x0F12, 0x00F8}, /* TVAR_ash_GASAlpha_4__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_4__3_ */ +{0x0F12, 0x00F0}, /* TVAR_ash_GASAlpha_5__0_ D65 */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__3_ */ +{0x0F12, 0x00F0}, /* TVAR_ash_GASAlpha_6__0_ D75 */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__3_ */ +{0x002A, 0x067A}, +{0x0F12, 0x0000}, /* ash_GASBeta_0__0_ Horizon */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__0_ IncandA */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__0_ WW */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__0_ CW */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__0_ D50 */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__0_ D65 */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__0_ D75 */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__3_ */ +{0x002A, 0x06BA}, +{0x0F12, 0x0001}, /*ash_bLumaMode */ +{0x002A, 0x0632}, +{0x0F12, 0x0100}, /* ash_CGrasAlphas_0_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_1_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_2_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_3_ */ +{0x002A, 0x0672}, +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_0_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_3_ */ +{0x002A, 0x06B2}, +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_0_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_1_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_2_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_3_ */ +{0x002A, 0x06D0}, +{0x0F12, 0x000D}, /* ash_uParabolicScalingA */ +{0x0F12, 0x000F}, /* ash_uParabolicScalingB */ +{0x002A, 0x06CC}, +{0x0F12, 0x0280}, /* ash_uParabolicCenterX */ +{0x0F12, 0x01E0}, /* ash_uParabolicCenterY */ +{0x002A, 0x06C6}, +{0x0F12, 0x0001}, /* ash_bParabolicEstimation */ +{0x002A, 0x0624}, +{0x0F12, 0x009D}, /* TVAR_ash_AwbAshCord_0_ Horizon */ +{0x0F12, 0x00D5}, /* TVAR_ash_AwbAshCord_1_ IncandA */ +{0x0F12, 0x0103}, /* TVAR_ash_AwbAshCord_2_ WW */ +{0x0F12, 0x0128}, /* TVAR_ash_AwbAshCord_3_ CW */ +{0x0F12, 0x0166}, /* TVAR_ash_AwbAshCord_4_ D50 */ +{0x0F12, 0x0193}, /* TVAR_ash_AwbAshCord_5_ D65 */ +{0x0F12, 0x01A0}, /* TVAR_ash_AwbAshCord_6_ D75 */ +{0x002A, 0x347C}, +{0x0F12, 0x013B}, /* 011A 012F Tune_wbt_GAS_0_ */ +{0x0F12, 0x0116}, /* 011A 0111 Tune_wbt_GAS_1_ */ +{0x0F12, 0x00D9}, /* 00EE 00D6 Tune_wbt_GAS_2_ */ +{0x0F12, 0x00A6}, /* 00C1 009E Tune_wbt_GAS_3_ */ +{0x0F12, 0x0082}, /* 009E 007A Tune_wbt_GAS_4_ */ +{0x0F12, 0x006C}, /* 008A 0064 Tune_wbt_GAS_5_ */ +{0x0F12, 0x0065}, /* 0083 005D Tune_wbt_GAS_6_ */ +{0x0F12, 0x006C}, /* 008A 0063 Tune_wbt_GAS_7_ */ +{0x0F12, 0x0080}, /* 009E 007B Tune_wbt_GAS_8_ */ +{0x0F12, 0x00A3}, /* 00BF 00A3 Tune_wbt_GAS_9_ */ +{0x0F12, 0x00D4}, /* 00E5 00E3 Tune_wbt_GAS_10_ */ +{0x0F12, 0x010D}, /* 00F9 013B Tune_wbt_GAS_11_ */ +{0x0F12, 0x012E}, /* 0124 018B Tune_wbt_GAS_12_ */ +{0x0F12, 0x0138}, /* 0126 012B Tune_wbt_GAS_13_ */ +{0x0F12, 0x0104}, /* 010E 00F6 Tune_wbt_GAS_14_ */ +{0x0F12, 0x00BE}, /* 00D3 00B2 Tune_wbt_GAS_15_ */ +{0x0F12, 0x0088}, /* 009F 007B Tune_wbt_GAS_16_ */ +{0x0F12, 0x0062}, /* 007C 0057 Tune_wbt_GAS_17_ */ +{0x0F12, 0x004D}, /* 0068 0042 Tune_wbt_GAS_18_ */ +{0x0F12, 0x0046}, /* 0061 0039 Tune_wbt_GAS_19_ */ +{0x0F12, 0x004C}, /* 0068 003F Tune_wbt_GAS_20_ */ +{0x0F12, 0x0060}, /* 007E 0053 Tune_wbt_GAS_21_ */ +{0x0F12, 0x0084}, /* 00A3 007A Tune_wbt_GAS_22_ */ +{0x0F12, 0x00B8}, /* 00C9 00B6 Tune_wbt_GAS_23_ */ +{0x0F12, 0x00F9}, /* 00F0 0110 Tune_wbt_GAS_24_ */ +{0x0F12, 0x012C}, /* 0131 016A Tune_wbt_GAS_25_ */ +{0x0F12, 0x011A}, /* 011C 0114 Tune_wbt_GAS_26_ */ +{0x0F12, 0x00DB}, /* 00EB 00D4 Tune_wbt_GAS_27_ */ +{0x0F12, 0x0093}, /* 00AA 008F Tune_wbt_GAS_28_ */ +{0x0F12, 0x005F}, /* 0075 005A Tune_wbt_GAS_29_ */ +{0x0F12, 0x003C}, /* 0053 0035 Tune_wbt_GAS_30_ */ +{0x0F12, 0x0027}, /* 003F 0020 Tune_wbt_GAS_31_ */ +{0x0F12, 0x0020}, /* 0038 0019 Tune_wbt_GAS_32_ */ +{0x0F12, 0x0026}, /* 0040 001F Tune_wbt_GAS_33_ */ +{0x0F12, 0x003A}, /* 0055 0032 Tune_wbt_GAS_34_ */ +{0x0F12, 0x005C}, /* 007A 0056 Tune_wbt_GAS_35_ */ +{0x0F12, 0x008E}, /* 00A6 008E Tune_wbt_GAS_36_ */ +{0x0F12, 0x00D2}, /* 00D5 00E6 Tune_wbt_GAS_37_ */ +{0x0F12, 0x010E}, /* 0126 0142 Tune_wbt_GAS_38_ */ +{0x0F12, 0x0101}, /* 00F6 0102 Tune_wbt_GAS_39_ */ +{0x0F12, 0x00BF}, /* 00C0 00BE Tune_wbt_GAS_40_ */ +{0x0F12, 0x0077}, /* 007D 0077 Tune_wbt_GAS_41_ */ +{0x0F12, 0x0044}, /* 004D 0045 Tune_wbt_GAS_42_ */ +{0x0F12, 0x0023}, /* 002C 0022 Tune_wbt_GAS_43_ */ +{0x0F12, 0x0011}, /* 001B 000D Tune_wbt_GAS_44_ */ +{0x0F12, 0x000C}, /* 0017 0006 Tune_wbt_GAS_45_ */ +{0x0F12, 0x0010}, /* 001B 000A Tune_wbt_GAS_46_ */ +{0x0F12, 0x0022}, /* 002D 001D Tune_wbt_GAS_47_ */ +{0x0F12, 0x0043}, /* 004E 003F Tune_wbt_GAS_48_ */ +{0x0F12, 0x0074}, /* 0080 0075 Tune_wbt_GAS_49_ */ +{0x0F12, 0x00B7}, /* 00C1 00CC Tune_wbt_GAS_50_ */ +{0x0F12, 0x00F7}, /* 00FF 0126 Tune_wbt_GAS_51_ */ +{0x0F12, 0x00FC}, /* 00EA 00FB Tune_wbt_GAS_52_ */ +{0x0F12, 0x00B7}, /* 00B0 00B7 Tune_wbt_GAS_53_ */ +{0x0F12, 0x006F}, /* 006D 0070 Tune_wbt_GAS_54_ */ +{0x0F12, 0x003C}, /* 003D 003D Tune_wbt_GAS_55_ */ +{0x0F12, 0x001C}, /* 001E 001B Tune_wbt_GAS_56_ */ +{0x0F12, 0x000A}, /* 000F 0007 Tune_wbt_GAS_57_ */ +{0x0F12, 0x0004}, /* 000A 0000 Tune_wbt_GAS_58_ */ +{0x0F12, 0x000A}, /* 0010 0004 Tune_wbt_GAS_59_ */ +{0x0F12, 0x001B}, /* 001E 0015 Tune_wbt_GAS_60_ */ +{0x0F12, 0x003B}, /* 003E 0034 Tune_wbt_GAS_61_ */ +{0x0F12, 0x006C}, /* 006F 006A Tune_wbt_GAS_62_ */ +{0x0F12, 0x00B0}, /* 00B2 00C0 Tune_wbt_GAS_63_ */ +{0x0F12, 0x00F2}, /* 00F1 011B Tune_wbt_GAS_64_ */ +{0x0F12, 0x00EF}, /* 00E0 0102 Tune_wbt_GAS_65_ */ +{0x0F12, 0x00AB}, /* 00A6 00BA Tune_wbt_GAS_66_ */ +{0x0F12, 0x0065}, /* 0063 0073 Tune_wbt_GAS_67_ */ +{0x0F12, 0x0034}, /* 0033 0040 Tune_wbt_GAS_68_ */ +{0x0F12, 0x0015}, /* 0016 001D Tune_wbt_GAS_69_ */ +{0x0F12, 0x0004}, /* 0008 0009 Tune_wbt_GAS_70_ */ +{0x0F12, 0x0000}, /* 0003 0001 Tune_wbt_GAS_71_ */ +{0x0F12, 0x0004}, /* 0009 0006 Tune_wbt_GAS_72_ */ +{0x0F12, 0x0013}, /* 0016 0017 Tune_wbt_GAS_73_ */ +{0x0F12, 0x0033}, /* 0035 0039 Tune_wbt_GAS_74_ */ +{0x0F12, 0x0063}, /* 0066 006F Tune_wbt_GAS_75_ */ +{0x0F12, 0x00A5}, /* 00A7 00C8 Tune_wbt_GAS_76_ */ +{0x0F12, 0x00E5}, /* 00E9 011E Tune_wbt_GAS_77_ */ +{0x0F12, 0x00F7}, /* 00D5 0111 Tune_wbt_GAS_78_ */ +{0x0F12, 0x00B4}, /* 009D 00C8 Tune_wbt_GAS_79_ */ +{0x0F12, 0x006D}, /* 005D 0081 Tune_wbt_GAS_80_ */ +{0x0F12, 0x003C}, /* 002F 004D Tune_wbt_GAS_81_ */ +{0x0F12, 0x001C}, /* 0010 0028 Tune_wbt_GAS_82_ */ +{0x0F12, 0x000B}, /* 0004 0014 Tune_wbt_GAS_83_ */ +{0x0F12, 0x0005}, /* 0001 000B Tune_wbt_GAS_84_ */ +{0x0F12, 0x000A}, /* 0005 0010 Tune_wbt_GAS_85_ */ +{0x0F12, 0x001B}, /* 0013 0022 Tune_wbt_GAS_86_ */ +{0x0F12, 0x003B}, /* 0031 0047 Tune_wbt_GAS_87_ */ +{0x0F12, 0x006B}, /* 005F 007E Tune_wbt_GAS_88_ */ +{0x0F12, 0x00AD}, /* 00A1 00D8 Tune_wbt_GAS_89_ */ +{0x0F12, 0x00ED}, /* 00DF 0131 Tune_wbt_GAS_90_ */ +{0x0F12, 0x010B}, /* 00E9 0129 Tune_wbt_GAS_91_ */ +{0x0F12, 0x00CB}, /* 00B2 00E4 Tune_wbt_GAS_92_ */ +{0x0F12, 0x0085}, /* 006F 009E Tune_wbt_GAS_93_ */ +{0x0F12, 0x0051}, /* 003F 0068 Tune_wbt_GAS_94_ */ +{0x0F12, 0x002F}, /* 0020 0041 Tune_wbt_GAS_95_ */ +{0x0F12, 0x001C}, /* 000F 002B Tune_wbt_GAS_96_ */ +{0x0F12, 0x0016}, /* 000B 0023 Tune_wbt_GAS_97_ */ +{0x0F12, 0x001C}, /* 0010 0028 Tune_wbt_GAS_98_ */ +{0x0F12, 0x002E}, /* 0021 003B Tune_wbt_GAS_99_ */ +{0x0F12, 0x004F}, /* 0041 0063 Tune_wbt_GAS_100_ */ +{0x0F12, 0x0081}, /* 0071 00A0 Tune_wbt_GAS_101_ */ +{0x0F12, 0x00C4}, /* 00B4 00FD Tune_wbt_GAS_102_ */ +{0x0F12, 0x0102}, /* 00F6 015A Tune_wbt_GAS_103_ */ +{0x0F12, 0x0119}, /* 00F9 014A Tune_wbt_GAS_104_ */ +{0x0F12, 0x00DF}, /* 00C2 010D Tune_wbt_GAS_105_ */ +{0x0F12, 0x009B}, /* 0082 00CA Tune_wbt_GAS_106_ */ +{0x0F12, 0x0067}, /* 0053 008F Tune_wbt_GAS_107_ */ +{0x0F12, 0x0045}, /* 0033 0066 Tune_wbt_GAS_108_ */ +{0x0F12, 0x0030}, /* 0021 004F Tune_wbt_GAS_109_ */ +{0x0F12, 0x0029}, /* 001C 0048 Tune_wbt_GAS_110_ */ +{0x0F12, 0x002F}, /* 0022 004E Tune_wbt_GAS_111_ */ +{0x0F12, 0x0043}, /* 0035 0067 Tune_wbt_GAS_112_ */ +{0x0F12, 0x0066}, /* 0056 008F Tune_wbt_GAS_113_ */ +{0x0F12, 0x0098}, /* 0087 00D1 Tune_wbt_GAS_114_ */ +{0x0F12, 0x00D9}, /* 00CA 0132 Tune_wbt_GAS_115_ */ +{0x0F12, 0x010F}, /* 0107 018D Tune_wbt_GAS_116_ */ +{0x0F12, 0x0138}, /* 0108 0159 Tune_wbt_GAS_117_ */ +{0x0F12, 0x010C}, /* 00E0 0141 Tune_wbt_GAS_118_ */ +{0x0F12, 0x00CB}, /* 00A2 0103 Tune_wbt_GAS_119_ */ +{0x0F12, 0x0097}, /* 0072 00C9 Tune_wbt_GAS_120_ */ +{0x0F12, 0x0073}, /* 0052 009E Tune_wbt_GAS_121_ */ +{0x0F12, 0x005C}, /* 0040 0087 Tune_wbt_GAS_122_ */ +{0x0F12, 0x0054}, /* 003A 007D Tune_wbt_GAS_123_ */ +{0x0F12, 0x005B}, /* 0041 0087 Tune_wbt_GAS_124_ */ +{0x0F12, 0x0070}, /* 0055 00A2 Tune_wbt_GAS_125_ */ +{0x0F12, 0x0096}, /* 0077 00D4 Tune_wbt_GAS_126_ */ +{0x0F12, 0x00C9}, /* 00A8 011A Tune_wbt_GAS_127_ */ +{0x0F12, 0x0106}, /* 00E7 017D Tune_wbt_GAS_128_ */ +{0x0F12, 0x012D}, /* 011E 01CF Tune_wbt_GAS_129_ */ +{0x0F12, 0x0147}, /* 0123 0181 Tune_wbt_GAS_130_ */ +{0x0F12, 0x012F}, /* 0100 0169 Tune_wbt_GAS_131_ */ +{0x0F12, 0x00F8}, /* 00CB 0140 Tune_wbt_GAS_132_ */ +{0x0F12, 0x00C5}, /* 009A 0106 Tune_wbt_GAS_133_ */ +{0x0F12, 0x00A1}, /* 0079 00DD Tune_wbt_GAS_134_ */ +{0x0F12, 0x008B}, /* 0067 00C5 Tune_wbt_GAS_135_ */ +{0x0F12, 0x0083}, /* 0060 00BE Tune_wbt_GAS_136_ */ +{0x0F12, 0x008B}, /* 0068 00C8 Tune_wbt_GAS_137_ */ +{0x0F12, 0x00A0}, /* 007B 00E6 Tune_wbt_GAS_138_ */ +{0x0F12, 0x00C2}, /* 009D 011B Tune_wbt_GAS_139_ */ +{0x0F12, 0x00F3}, /* 00CD 015F Tune_wbt_GAS_140_ */ +{0x0F12, 0x0124}, /* 0108 01BC Tune_wbt_GAS_141_ */ +{0x0F12, 0x0139}, /* 0131 0206 Tune_wbt_GAS_142_ */ +{0x0F12, 0x0093}, /* 006C 00A8 Tune_wbt_GAS_143_ */ +{0x0F12, 0x007E}, /* 006E 008F Tune_wbt_GAS_144_ */ +{0x0F12, 0x0062}, /* 005D 006F Tune_wbt_GAS_145_ */ +{0x0F12, 0x004D}, /* 004C 0054 Tune_wbt_GAS_146_ */ +{0x0F12, 0x003E}, /* 0040 0041 Tune_wbt_GAS_147_ */ +{0x0F12, 0x0034}, /* 0037 0036 Tune_wbt_GAS_148_ */ +{0x0F12, 0x0030}, /* 0035 0033 Tune_wbt_GAS_149_ */ +{0x0F12, 0x0032}, /* 0036 0037 Tune_wbt_GAS_150_ */ +{0x0F12, 0x003B}, /* 003F 0045 Tune_wbt_GAS_151_ */ +{0x0F12, 0x0049}, /* 004B 005A Tune_wbt_GAS_152_ */ +{0x0F12, 0x005C}, /* 0053 007A Tune_wbt_GAS_153_ */ +{0x0F12, 0x0077}, /* 0053 00AA Tune_wbt_GAS_154_ */ +{0x0F12, 0x008A}, /* 0070 00E2 Tune_wbt_GAS_155_ */ +{0x0F12, 0x0093}, /* 0075 009E Tune_wbt_GAS_156_ */ +{0x0F12, 0x0077}, /* 006D 007D Tune_wbt_GAS_157_ */ +{0x0F12, 0x0059}, /* 0056 005A Tune_wbt_GAS_158_ */ +{0x0F12, 0x0042}, /* 0043 0041 Tune_wbt_GAS_159_ */ +{0x0F12, 0x0032}, /* 0037 002E Tune_wbt_GAS_160_ */ +{0x0F12, 0x0027}, /* 002F 0022 Tune_wbt_GAS_161_ */ +{0x0F12, 0x0024}, /* 002C 001F Tune_wbt_GAS_162_ */ +{0x0F12, 0x0026}, /* 002F 0022 Tune_wbt_GAS_163_ */ +{0x0F12, 0x002F}, /* 0038 0030 Tune_wbt_GAS_164_ */ +{0x0F12, 0x003D}, /* 0045 0044 Tune_wbt_GAS_165_ */ +{0x0F12, 0x0052}, /* 004E 0063 Tune_wbt_GAS_166_ */ +{0x0F12, 0x006E}, /* 0055 0091 Tune_wbt_GAS_167_ */ +{0x0F12, 0x008B}, /* 007F 00CB Tune_wbt_GAS_168_ */ +{0x0F12, 0x0083}, /* 0077 0093 Tune_wbt_GAS_169_ */ +{0x0F12, 0x0064}, /* 0062 006D Tune_wbt_GAS_170_ */ +{0x0F12, 0x0046}, /* 004A 004A Tune_wbt_GAS_171_ */ +{0x0F12, 0x0030}, /* 0037 0031 Tune_wbt_GAS_172_ */ +{0x0F12, 0x0020}, /* 002A 001E Tune_wbt_GAS_173_ */ +{0x0F12, 0x0016}, /* 0021 0013 Tune_wbt_GAS_174_ */ +{0x0F12, 0x0011}, /* 001E 000F Tune_wbt_GAS_175_ */ +{0x0F12, 0x0014}, /* 0021 0013 Tune_wbt_GAS_176_ */ +{0x0F12, 0x001E}, /* 002B 001F Tune_wbt_GAS_177_ */ +{0x0F12, 0x002D}, /* 003B 0034 Tune_wbt_GAS_178_ */ +{0x0F12, 0x0041}, /* 0046 0051 Tune_wbt_GAS_179_ */ +{0x0F12, 0x005D}, /* 0051 007C Tune_wbt_GAS_180_ */ +{0x0F12, 0x007C}, /* 007F 00B7 Tune_wbt_GAS_181_ */ +{0x0F12, 0x0077}, /* 0062 008A Tune_wbt_GAS_182_ */ +{0x0F12, 0x0057}, /* 004B 0061 Tune_wbt_GAS_183_ */ +{0x0F12, 0x0039}, /* 0034 003E Tune_wbt_GAS_184_ */ +{0x0F12, 0x0024}, /* 0022 0026 Tune_wbt_GAS_185_ */ +{0x0F12, 0x0014}, /* 0014 0013 Tune_wbt_GAS_186_ */ +{0x0F12, 0x000A}, /* 000E 0008 Tune_wbt_GAS_187_ */ +{0x0F12, 0x0007}, /* 000C 0004 Tune_wbt_GAS_188_ */ +{0x0F12, 0x0009}, /* 000D 0007 Tune_wbt_GAS_189_ */ +{0x0F12, 0x0012}, /* 0016 0013 Tune_wbt_GAS_190_ */ +{0x0F12, 0x0021}, /* 0024 0027 Tune_wbt_GAS_191_ */ +{0x0F12, 0x0036}, /* 0036 0045 Tune_wbt_GAS_192_ */ +{0x0F12, 0x0051}, /* 004E 0070 Tune_wbt_GAS_193_ */ +{0x0F12, 0x0070}, /* 0069 00A7 Tune_wbt_GAS_194_ */ +{0x0F12, 0x0077}, /* 005F 0085 Tune_wbt_GAS_195_ */ +{0x0F12, 0x0056}, /* 0048 005D Tune_wbt_GAS_196_ */ +{0x0F12, 0x0038}, /* 002F 003A Tune_wbt_GAS_197_ */ +{0x0F12, 0x0022}, /* 001C 0021 Tune_wbt_GAS_198_ */ +{0x0F12, 0x0013}, /* 0010 0010 Tune_wbt_GAS_199_ */ +{0x0F12, 0x0009}, /* 000B 0004 Tune_wbt_GAS_200_ */ +{0x0F12, 0x0005}, /* 0008 0000 Tune_wbt_GAS_201_ */ +{0x0F12, 0x0008}, /* 000B 0003 Tune_wbt_GAS_202_ */ +{0x0F12, 0x0011}, /* 0010 000E Tune_wbt_GAS_203_ */ +{0x0F12, 0x0020}, /* 001E 0021 Tune_wbt_GAS_204_ */ +{0x0F12, 0x0035}, /* 0031 003F Tune_wbt_GAS_205_ */ +{0x0F12, 0x0051}, /* 0049 006B Tune_wbt_GAS_206_ */ +{0x0F12, 0x0071}, /* 0066 00A1 Tune_wbt_GAS_207_ */ +{0x0F12, 0x006E}, /* 005B 0089 Tune_wbt_GAS_208_ */ +{0x0F12, 0x004E}, /* 0043 0060 Tune_wbt_GAS_209_ */ +{0x0F12, 0x0032}, /* 002B 003D Tune_wbt_GAS_210_ */ +{0x0F12, 0x001C}, /* 0019 0023 Tune_wbt_GAS_211_ */ +{0x0F12, 0x000D}, /* 000C 0012 Tune_wbt_GAS_212_ */ +{0x0F12, 0x0004}, /* 0007 0006 Tune_wbt_GAS_213_ */ +{0x0F12, 0x0000}, /* 0004 0002 Tune_wbt_GAS_214_ */ +{0x0F12, 0x0003}, /* 0007 0005 Tune_wbt_GAS_215_ */ +{0x0F12, 0x000B}, /* 000D 0011 Tune_wbt_GAS_216_ */ +{0x0F12, 0x001A}, /* 001B 0025 Tune_wbt_GAS_217_ */ +{0x0F12, 0x002F}, /* 002E 0043 Tune_wbt_GAS_218_ */ +{0x0F12, 0x0049}, /* 0046 0070 Tune_wbt_GAS_219_ */ +{0x0F12, 0x0068}, /* 0062 00A4 Tune_wbt_GAS_220_ */ +{0x0F12, 0x0072}, /* 0052 0091 Tune_wbt_GAS_221_ */ +{0x0F12, 0x0053}, /* 003D 0067 Tune_wbt_GAS_222_ */ +{0x0F12, 0x0037}, /* 0026 0044 Tune_wbt_GAS_223_ */ +{0x0F12, 0x0021}, /* 0014 002B Tune_wbt_GAS_224_ */ +{0x0F12, 0x0012}, /* 0007 0019 Tune_wbt_GAS_225_ */ +{0x0F12, 0x0009}, /* 0002 000D Tune_wbt_GAS_226_ */ +{0x0F12, 0x0005}, /* 0001 0009 Tune_wbt_GAS_227_ */ +{0x0F12, 0x0008}, /* 0002 000C Tune_wbt_GAS_228_ */ +{0x0F12, 0x0010}, /* 0007 0018 Tune_wbt_GAS_229_ */ +{0x0F12, 0x001F}, /* 0015 002D Tune_wbt_GAS_230_ */ +{0x0F12, 0x0034}, /* 0028 004B Tune_wbt_GAS_231_ */ +{0x0F12, 0x004E}, /* 0040 007B Tune_wbt_GAS_232_ */ +{0x0F12, 0x006C}, /* 005C 00B0 Tune_wbt_GAS_233_ */ +{0x0F12, 0x007F}, /* 005E 00A1 Tune_wbt_GAS_234_ */ +{0x0F12, 0x0060}, /* 0049 0077 Tune_wbt_GAS_235_ */ +{0x0F12, 0x0043}, /* 0030 0054 Tune_wbt_GAS_236_ */ +{0x0F12, 0x002D}, /* 001E 003B Tune_wbt_GAS_237_ */ +{0x0F12, 0x001D}, /* 0010 0029 Tune_wbt_GAS_238_ */ +{0x0F12, 0x0013}, /* 0009 001C Tune_wbt_GAS_239_ */ +{0x0F12, 0x0010}, /* 0007 0018 Tune_wbt_GAS_240_ */ +{0x0F12, 0x0013}, /* 0009 001B Tune_wbt_GAS_241_ */ +{0x0F12, 0x001C}, /* 0012 0029 Tune_wbt_GAS_242_ */ +{0x0F12, 0x002B}, /* 0020 003F Tune_wbt_GAS_243_ */ +{0x0F12, 0x0040}, /* 0032 005F Tune_wbt_GAS_244_ */ +{0x0F12, 0x005A}, /* 004B 008F Tune_wbt_GAS_245_ */ +{0x0F12, 0x0079}, /* 0069 00C6 Tune_wbt_GAS_246_ */ +{0x0F12, 0x0082}, /* 0066 00B1 Tune_wbt_GAS_247_ */ +{0x0F12, 0x0066}, /* 004E 008E Tune_wbt_GAS_248_ */ +{0x0F12, 0x0049}, /* 0037 006D Tune_wbt_GAS_249_ */ +{0x0F12, 0x0035}, /* 0026 0050 Tune_wbt_GAS_250_ */ +{0x0F12, 0x0025}, /* 0019 003D Tune_wbt_GAS_251_ */ +{0x0F12, 0x001B}, /* 0011 0031 Tune_wbt_GAS_252_ */ +{0x0F12, 0x0017}, /* 000F 002F Tune_wbt_GAS_253_ */ +{0x0F12, 0x0019}, /* 0012 0032 Tune_wbt_GAS_254_ */ +{0x0F12, 0x0023}, /* 001B 0042 Tune_wbt_GAS_255_ */ +{0x0F12, 0x0033}, /* 0028 0058 Tune_wbt_GAS_256_ */ +{0x0F12, 0x0046}, /* 003B 007A Tune_wbt_GAS_257_ */ +{0x0F12, 0x0060}, /* 0054 00AC Tune_wbt_GAS_258_ */ +{0x0F12, 0x007B}, /* 0072 00E5 Tune_wbt_GAS_259_ */ +{0x0F12, 0x0092}, /* 006A 00BD Tune_wbt_GAS_260_ */ +{0x0F12, 0x007C}, /* 0058 00AA Tune_wbt_GAS_261_ */ +{0x0F12, 0x0060}, /* 0041 008B Tune_wbt_GAS_262_ */ +{0x0F12, 0x004B}, /* 0030 006E Tune_wbt_GAS_263_ */ +{0x0F12, 0x003C}, /* 0025 005A Tune_wbt_GAS_264_ */ +{0x0F12, 0x0032}, /* 001E 004F Tune_wbt_GAS_265_ */ +{0x0F12, 0x002D}, /* 001B 004B Tune_wbt_GAS_266_ */ +{0x0F12, 0x0030}, /* 001F 0052 Tune_wbt_GAS_267_ */ +{0x0F12, 0x0039}, /* 0027 0062 Tune_wbt_GAS_268_ */ +{0x0F12, 0x0049}, /* 0034 007D Tune_wbt_GAS_269_ */ +{0x0F12, 0x005D}, /* 0046 00A2 Tune_wbt_GAS_270_ */ +{0x0F12, 0x0076}, /* 005D 00D6 Tune_wbt_GAS_271_ */ +{0x0F12, 0x008C}, /* 0078 010C Tune_wbt_GAS_272_ */ +{0x0F12, 0x009F}, /* 007C 00E5 Tune_wbt_GAS_273_ */ +{0x0F12, 0x008F}, /* 006A 00C7 Tune_wbt_GAS_274_ */ +{0x0F12, 0x0077}, /* 0055 00B1 Tune_wbt_GAS_275_ */ +{0x0F12, 0x0061}, /* 0043 0093 Tune_wbt_GAS_276_ */ +{0x0F12, 0x0052}, /* 0037 007F Tune_wbt_GAS_277_ */ +{0x0F12, 0x0048}, /* 0030 0074 Tune_wbt_GAS_278_ */ +{0x0F12, 0x0043}, /* 002E 0071 Tune_wbt_GAS_279_ */ +{0x0F12, 0x0047}, /* 0030 0077 Tune_wbt_GAS_280_ */ +{0x0F12, 0x0050}, /* 0039 0089 Tune_wbt_GAS_281_ */ +{0x0F12, 0x005E}, /* 0045 00A7 Tune_wbt_GAS_282_ */ +{0x0F12, 0x0071}, /* 0056 00CC Tune_wbt_GAS_283_ */ +{0x0F12, 0x0086}, /* 006C 00FE Tune_wbt_GAS_284_ */ +{0x0F12, 0x0097}, /* 0084 0132 Tune_wbt_GAS_285_ */ +{0x0F12, 0x0093}, /* 006E 00A8 Tune_wbt_GAS_286_ */ +{0x0F12, 0x007C}, /* 006D 008D Tune_wbt_GAS_287_ */ +{0x0F12, 0x005F}, /* 005B 006C Tune_wbt_GAS_288_ */ +{0x0F12, 0x0049}, /* 0046 004E Tune_wbt_GAS_289_ */ +{0x0F12, 0x003A}, /* 003A 003C Tune_wbt_GAS_290_ */ +{0x0F12, 0x0030}, /* 0033 0032 Tune_wbt_GAS_291_ */ +{0x0F12, 0x002C}, /* 002D 002D Tune_wbt_GAS_292_ */ +{0x0F12, 0x002F}, /* 0032 0032 Tune_wbt_GAS_293_ */ +{0x0F12, 0x0037}, /* 0039 0040 Tune_wbt_GAS_294_ */ +{0x0F12, 0x0045}, /* 0047 0056 Tune_wbt_GAS_295_ */ +{0x0F12, 0x005A}, /* 004F 0076 Tune_wbt_GAS_296_ */ +{0x0F12, 0x0075}, /* 0050 00A8 Tune_wbt_GAS_297_ */ +{0x0F12, 0x008A}, /* 006E 00E6 Tune_wbt_GAS_298_ */ +{0x0F12, 0x0094}, /* 0077 00A2 Tune_wbt_GAS_299_ */ +{0x0F12, 0x0077}, /* 006C 007C Tune_wbt_GAS_300_ */ +{0x0F12, 0x0057}, /* 0054 0059 Tune_wbt_GAS_301_ */ +{0x0F12, 0x0040}, /* 0040 003E Tune_wbt_GAS_302_ */ +{0x0F12, 0x002F}, /* 0033 002A Tune_wbt_GAS_303_ */ +{0x0F12, 0x0024}, /* 002B 0020 Tune_wbt_GAS_304_ */ +{0x0F12, 0x0020}, /* 0027 001B Tune_wbt_GAS_305_ */ +{0x0F12, 0x0023}, /* 002A 0020 Tune_wbt_GAS_306_ */ +{0x0F12, 0x002D}, /* 0034 002D Tune_wbt_GAS_307_ */ +{0x0F12, 0x003B}, /* 0041 0042 Tune_wbt_GAS_308_ */ +{0x0F12, 0x0051}, /* 004C 0061 Tune_wbt_GAS_309_ */ +{0x0F12, 0x006E}, /* 0052 0092 Tune_wbt_GAS_310_ */ +{0x0F12, 0x008C}, /* 007E 00CE Tune_wbt_GAS_311_ */ +{0x0F12, 0x0085}, /* 0078 0094 Tune_wbt_GAS_312_ */ +{0x0F12, 0x0066}, /* 0063 006F Tune_wbt_GAS_313_ */ +{0x0F12, 0x0046}, /* 0049 004B Tune_wbt_GAS_314_ */ +{0x0F12, 0x002F}, /* 0035 002F Tune_wbt_GAS_315_ */ +{0x0F12, 0x001F}, /* 0028 001D Tune_wbt_GAS_316_ */ +{0x0F12, 0x0014}, /* 001E 0011 Tune_wbt_GAS_317_ */ +{0x0F12, 0x000F}, /* 001B 000D Tune_wbt_GAS_318_ */ +{0x0F12, 0x0012}, /* 001F 0012 Tune_wbt_GAS_319_ */ +{0x0F12, 0x001C}, /* 0028 001D Tune_wbt_GAS_320_ */ +{0x0F12, 0x002B}, /* 0037 0033 Tune_wbt_GAS_321_ */ +{0x0F12, 0x0040}, /* 0044 0051 Tune_wbt_GAS_322_ */ +{0x0F12, 0x005C}, /* 0050 007F Tune_wbt_GAS_323_ */ +{0x0F12, 0x007D}, /* 0080 00BA Tune_wbt_GAS_324_ */ +{0x0F12, 0x007A}, /* 0064 008B Tune_wbt_GAS_325_ */ +{0x0F12, 0x005A}, /* 004E 0064 Tune_wbt_GAS_326_ */ +{0x0F12, 0x003A}, /* 0035 0040 Tune_wbt_GAS_327_ */ +{0x0F12, 0x0024}, /* 0021 0025 Tune_wbt_GAS_328_ */ +{0x0F12, 0x0014}, /* 0013 0013 Tune_wbt_GAS_329_ */ +{0x0F12, 0x0009}, /* 000D 0007 Tune_wbt_GAS_330_ */ +{0x0F12, 0x0006}, /* 000B 0003 Tune_wbt_GAS_331_ */ +{0x0F12, 0x0008}, /* 000C 0006 Tune_wbt_GAS_332_ */ +{0x0F12, 0x0011}, /* 0014 0012 Tune_wbt_GAS_333_ */ +{0x0F12, 0x0020}, /* 0022 0027 Tune_wbt_GAS_334_ */ +{0x0F12, 0x0036}, /* 0036 0046 Tune_wbt_GAS_335_ */ +{0x0F12, 0x0051}, /* 004D 0073 Tune_wbt_GAS_336_ */ +{0x0F12, 0x0072}, /* 006B 00AB Tune_wbt_GAS_337_ */ +{0x0F12, 0x007B}, /* 0066 008B Tune_wbt_GAS_338_ */ +{0x0F12, 0x0059}, /* 004C 0062 Tune_wbt_GAS_339_ */ +{0x0F12, 0x003A}, /* 0032 003F Tune_wbt_GAS_340_ */ +{0x0F12, 0x0023}, /* 001E 0023 Tune_wbt_GAS_341_ */ +{0x0F12, 0x0012}, /* 0010 0010 Tune_wbt_GAS_342_ */ +{0x0F12, 0x0008}, /* 000A 0004 Tune_wbt_GAS_343_ */ +{0x0F12, 0x0004}, /* 0007 0000 Tune_wbt_GAS_344_ */ +{0x0F12, 0x0007}, /* 000B 0003 Tune_wbt_GAS_345_ */ +{0x0F12, 0x000F}, /* 0010 000E Tune_wbt_GAS_346_ */ +{0x0F12, 0x001F}, /* 001E 0022 Tune_wbt_GAS_347_ */ +{0x0F12, 0x0035}, /* 0032 0041 Tune_wbt_GAS_348_ */ +{0x0F12, 0x0051}, /* 004B 006E Tune_wbt_GAS_349_ */ +{0x0F12, 0x0072}, /* 006B 00A4 Tune_wbt_GAS_350_ */ +{0x0F12, 0x0073}, /* 0061 008E Tune_wbt_GAS_351_ */ +{0x0F12, 0x0053}, /* 0049 0065 Tune_wbt_GAS_352_ */ +{0x0F12, 0x0034}, /* 002F 0040 Tune_wbt_GAS_353_ */ +{0x0F12, 0x001D}, /* 001B 0025 Tune_wbt_GAS_354_ */ +{0x0F12, 0x000E}, /* 000E 0013 Tune_wbt_GAS_355_ */ +{0x0F12, 0x0004}, /* 0008 0006 Tune_wbt_GAS_356_ */ +{0x0F12, 0x0000}, /* 0004 0001 Tune_wbt_GAS_357_ */ +{0x0F12, 0x0002}, /* 0008 0005 Tune_wbt_GAS_358_ */ +{0x0F12, 0x000A}, /* 000D 0010 Tune_wbt_GAS_359_ */ +{0x0F12, 0x001A}, /* 001C 0025 Tune_wbt_GAS_360_ */ +{0x0F12, 0x002F}, /* 002F 0044 Tune_wbt_GAS_361_ */ +{0x0F12, 0x004A}, /* 0047 0074 Tune_wbt_GAS_362_ */ +{0x0F12, 0x006A}, /* 0067 00AA Tune_wbt_GAS_363_ */ +{0x0F12, 0x0077}, /* 005A 0097 Tune_wbt_GAS_364_ */ +{0x0F12, 0x0058}, /* 0043 006D Tune_wbt_GAS_365_ */ +{0x0F12, 0x0039}, /* 002B 0048 Tune_wbt_GAS_366_ */ +{0x0F12, 0x0022}, /* 0017 002D Tune_wbt_GAS_367_ */ +{0x0F12, 0x0012}, /* 0009 0019 Tune_wbt_GAS_368_ */ +{0x0F12, 0x0008}, /* 0004 000E Tune_wbt_GAS_369_ */ +{0x0F12, 0x0004}, /* 0002 0009 Tune_wbt_GAS_370_ */ +{0x0F12, 0x0007}, /* 0004 000C Tune_wbt_GAS_371_ */ +{0x0F12, 0x000F}, /* 0008 0018 Tune_wbt_GAS_372_ */ +{0x0F12, 0x001E}, /* 0016 002E Tune_wbt_GAS_373_ */ +{0x0F12, 0x0034}, /* 002A 004E Tune_wbt_GAS_374_ */ +{0x0F12, 0x004F}, /* 0042 007D Tune_wbt_GAS_375_ */ +{0x0F12, 0x006F}, /* 005F 00B5 Tune_wbt_GAS_376_ */ +{0x0F12, 0x0083}, /* 0066 00A6 Tune_wbt_GAS_377_ */ +{0x0F12, 0x0064}, /* 0050 007C Tune_wbt_GAS_378_ */ +{0x0F12, 0x0045}, /* 0035 0058 Tune_wbt_GAS_379_ */ +{0x0F12, 0x002E}, /* 0022 003E Tune_wbt_GAS_380_ */ +{0x0F12, 0x001D}, /* 0013 0029 Tune_wbt_GAS_381_ */ +{0x0F12, 0x0012}, /* 000A 001D Tune_wbt_GAS_382_ */ +{0x0F12, 0x000F}, /* 0008 0018 Tune_wbt_GAS_383_ */ +{0x0F12, 0x0011}, /* 000B 001B Tune_wbt_GAS_384_ */ +{0x0F12, 0x001A}, /* 0014 0028 Tune_wbt_GAS_385_ */ +{0x0F12, 0x002A}, /* 0021 003F Tune_wbt_GAS_386_ */ +{0x0F12, 0x003F}, /* 0035 0062 Tune_wbt_GAS_387_ */ +{0x0F12, 0x005B}, /* 004D 0093 Tune_wbt_GAS_388_ */ +{0x0F12, 0x007B}, /* 006E 00CC Tune_wbt_GAS_389_ */ +{0x0F12, 0x0087}, /* 006E 00B9 Tune_wbt_GAS_390_ */ +{0x0F12, 0x006A}, /* 0057 0094 Tune_wbt_GAS_391_ */ +{0x0F12, 0x004B}, /* 003E 0071 Tune_wbt_GAS_392_ */ +{0x0F12, 0x0036}, /* 002B 0052 Tune_wbt_GAS_393_ */ +{0x0F12, 0x0025}, /* 001C 003D Tune_wbt_GAS_394_ */ +{0x0F12, 0x0019}, /* 0013 0031 Tune_wbt_GAS_395_ */ +{0x0F12, 0x0015}, /* 0011 002D Tune_wbt_GAS_396_ */ +{0x0F12, 0x0017}, /* 0013 0031 Tune_wbt_GAS_397_ */ +{0x0F12, 0x0022}, /* 001D 0040 Tune_wbt_GAS_398_ */ +{0x0F12, 0x0031}, /* 002B 0058 Tune_wbt_GAS_399_ */ +{0x0F12, 0x0045}, /* 003D 007B Tune_wbt_GAS_400_ */ +{0x0F12, 0x0060}, /* 0057 00AE Tune_wbt_GAS_401_ */ +{0x0F12, 0x007D}, /* 0077 00EA Tune_wbt_GAS_402_ */ +{0x0F12, 0x0096}, /* 0072 00C2 Tune_wbt_GAS_403_ */ +{0x0F12, 0x007F}, /* 005F 00AE Tune_wbt_GAS_404_ */ +{0x0F12, 0x0061}, /* 0047 008E Tune_wbt_GAS_405_ */ +{0x0F12, 0x004B}, /* 0035 006F Tune_wbt_GAS_406_ */ +{0x0F12, 0x003B}, /* 0028 0059 Tune_wbt_GAS_407_ */ +{0x0F12, 0x002F}, /* 0020 004E Tune_wbt_GAS_408_ */ +{0x0F12, 0x002A}, /* 001D 0049 Tune_wbt_GAS_409_ */ +{0x0F12, 0x002D}, /* 0020 004F Tune_wbt_GAS_410_ */ +{0x0F12, 0x0036}, /* 0029 005E Tune_wbt_GAS_411_ */ +{0x0F12, 0x0046}, /* 0035 007A Tune_wbt_GAS_412_ */ +{0x0F12, 0x005B}, /* 0047 009F Tune_wbt_GAS_413_ */ +{0x0F12, 0x0075}, /* 0060 00D5 Tune_wbt_GAS_414_ */ +{0x0F12, 0x008D}, /* 007D 010C Tune_wbt_GAS_415_ */ +{0x0F12, 0x00A1}, /* 0084 00E5 Tune_wbt_GAS_416_ */ +{0x0F12, 0x0091}, /* 0072 00C8 Tune_wbt_GAS_417_ */ +{0x0F12, 0x0077}, /* 005B 00B0 Tune_wbt_GAS_418_ */ +{0x0F12, 0x0060}, /* 0046 0091 Tune_wbt_GAS_419_ */ +{0x0F12, 0x0050}, /* 003A 007D Tune_wbt_GAS_420_ */ +{0x0F12, 0x0044}, /* 0031 0070 Tune_wbt_GAS_421_ */ +{0x0F12, 0x0040}, /* 002E 006D Tune_wbt_GAS_422_ */ +{0x0F12, 0x0043}, /* 0032 0074 Tune_wbt_GAS_423_ */ +{0x0F12, 0x004C}, /* 0039 0086 Tune_wbt_GAS_424_ */ +{0x0F12, 0x005A}, /* 0046 00A4 Tune_wbt_GAS_425_ */ +{0x0F12, 0x006D}, /* 0056 00CA Tune_wbt_GAS_426_ */ +{0x0F12, 0x0084}, /* 006E 00FE Tune_wbt_GAS_427_ */ +{0x0F12, 0x0094}, /* 0087 0134 Tune_wbt_GAS_428_ */ +{0x0F12, 0x0072}, /* 004C 009F Tune_wbt_GAS_429_ */ +{0x0F12, 0x0063}, /* 004C 0089 Tune_wbt_GAS_430_ */ +{0x0F12, 0x004C}, /* 0041 0067 Tune_wbt_GAS_431_ */ +{0x0F12, 0x003A}, /* 002F 004E Tune_wbt_GAS_432_ */ +{0x0F12, 0x002D}, /* 0024 003E Tune_wbt_GAS_433_ */ +{0x0F12, 0x0025}, /* 001D 0033 Tune_wbt_GAS_434_ */ +{0x0F12, 0x0023}, /* 001B 0031 Tune_wbt_GAS_435_ */ +{0x0F12, 0x0025}, /* 001E 0036 Tune_wbt_GAS_436_ */ +{0x0F12, 0x002C}, /* 0024 0045 Tune_wbt_GAS_437_ */ +{0x0F12, 0x0038}, /* 0032 0058 Tune_wbt_GAS_438_ */ +{0x0F12, 0x004A}, /* 0037 0074 Tune_wbt_GAS_439_ */ +{0x0F12, 0x005F}, /* 0038 00A0 Tune_wbt_GAS_440_ */ +{0x0F12, 0x006B}, /* 004C 00C9 Tune_wbt_GAS_441_ */ +{0x0F12, 0x0079}, /* 005B 0098 Tune_wbt_GAS_442_ */ +{0x0F12, 0x0065}, /* 0056 0077 Tune_wbt_GAS_443_ */ +{0x0F12, 0x004A}, /* 0041 0055 Tune_wbt_GAS_444_ */ +{0x0F12, 0x0037}, /* 0030 003C Tune_wbt_GAS_445_ */ +{0x0F12, 0x0029}, /* 0026 002A Tune_wbt_GAS_446_ */ +{0x0F12, 0x0021}, /* 001F 0022 Tune_wbt_GAS_447_ */ +{0x0F12, 0x001D}, /* 001C 001F Tune_wbt_GAS_448_ */ +{0x0F12, 0x001F}, /* 001F 0024 Tune_wbt_GAS_449_ */ +{0x0F12, 0x0027}, /* 0027 0030 Tune_wbt_GAS_450_ */ +{0x0F12, 0x0033}, /* 0033 0044 Tune_wbt_GAS_451_ */ +{0x0F12, 0x0044}, /* 003C 0060 Tune_wbt_GAS_452_ */ +{0x0F12, 0x005E}, /* 0041 008B Tune_wbt_GAS_453_ */ +{0x0F12, 0x006E}, /* 0060 00B2 Tune_wbt_GAS_454_ */ +{0x0F12, 0x006A}, /* 005E 0088 Tune_wbt_GAS_455_ */ +{0x0F12, 0x0055}, /* 004F 0065 Tune_wbt_GAS_456_ */ +{0x0F12, 0x003A}, /* 003A 0044 Tune_wbt_GAS_457_ */ +{0x0F12, 0x0028}, /* 002A 002C Tune_wbt_GAS_458_ */ +{0x0F12, 0x001A}, /* 001D 001B Tune_wbt_GAS_459_ */ +{0x0F12, 0x0011}, /* 0016 0012 Tune_wbt_GAS_460_ */ +{0x0F12, 0x000D}, /* 0014 000F Tune_wbt_GAS_461_ */ +{0x0F12, 0x000F}, /* 0016 0013 Tune_wbt_GAS_462_ */ +{0x0F12, 0x0017}, /* 0021 001E Tune_wbt_GAS_463_ */ +{0x0F12, 0x0024}, /* 002D 0032 Tune_wbt_GAS_464_ */ +{0x0F12, 0x0035}, /* 0038 004E Tune_wbt_GAS_465_ */ +{0x0F12, 0x004E}, /* 0040 0078 Tune_wbt_GAS_466_ */ +{0x0F12, 0x0061}, /* 0066 00A2 Tune_wbt_GAS_467_ */ +{0x0F12, 0x0061}, /* 004A 007F Tune_wbt_GAS_468_ */ +{0x0F12, 0x004A}, /* 003C 005B Tune_wbt_GAS_469_ */ +{0x0F12, 0x0031}, /* 0028 0039 Tune_wbt_GAS_470_ */ +{0x0F12, 0x001E}, /* 0019 0021 Tune_wbt_GAS_471_ */ +{0x0F12, 0x0011}, /* 000D 0012 Tune_wbt_GAS_472_ */ +{0x0F12, 0x0008}, /* 0008 0007 Tune_wbt_GAS_473_ */ +{0x0F12, 0x0005}, /* 0007 0004 Tune_wbt_GAS_474_ */ +{0x0F12, 0x0007}, /* 0007 0006 Tune_wbt_GAS_475_ */ +{0x0F12, 0x000E}, /* 000F 0012 Tune_wbt_GAS_476_ */ +{0x0F12, 0x001B}, /* 001C 0024 Tune_wbt_GAS_477_ */ +{0x0F12, 0x002D}, /* 002C 0041 Tune_wbt_GAS_478_ */ +{0x0F12, 0x0045}, /* 0042 006A Tune_wbt_GAS_479_ */ +{0x0F12, 0x0059}, /* 0054 0092 Tune_wbt_GAS_480_ */ +{0x0F12, 0x0062}, /* 004B 007B Tune_wbt_GAS_481_ */ +{0x0F12, 0x004B}, /* 003C 0057 Tune_wbt_GAS_482_ */ +{0x0F12, 0x0031}, /* 0027 0036 Tune_wbt_GAS_483_ */ +{0x0F12, 0x001E}, /* 0017 001E Tune_wbt_GAS_484_ */ +{0x0F12, 0x0010}, /* 000C 000F Tune_wbt_GAS_485_ */ +{0x0F12, 0x0008}, /* 0007 0003 Tune_wbt_GAS_486_ */ +{0x0F12, 0x0004}, /* 0006 0000 Tune_wbt_GAS_487_ */ +{0x0F12, 0x0006}, /* 0008 0002 Tune_wbt_GAS_488_ */ +{0x0F12, 0x000E}, /* 000D 000D Tune_wbt_GAS_489_ */ +{0x0F12, 0x001B}, /* 001A 0020 Tune_wbt_GAS_490_ */ +{0x0F12, 0x002E}, /* 002B 003C Tune_wbt_GAS_491_ */ +{0x0F12, 0x0046}, /* 0041 0067 Tune_wbt_GAS_492_ */ +{0x0F12, 0x005A}, /* 0054 008D Tune_wbt_GAS_493_ */ +{0x0F12, 0x005B}, /* 0049 007E Tune_wbt_GAS_494_ */ +{0x0F12, 0x0045}, /* 003A 005A Tune_wbt_GAS_495_ */ +{0x0F12, 0x002C}, /* 0025 0038 Tune_wbt_GAS_496_ */ +{0x0F12, 0x001A}, /* 0015 0022 Tune_wbt_GAS_497_ */ +{0x0F12, 0x000C}, /* 000A 0013 Tune_wbt_GAS_498_ */ +{0x0F12, 0x0003}, /* 0005 0006 Tune_wbt_GAS_499_ */ +{0x0F12, 0x0000}, /* 0003 0001 Tune_wbt_GAS_500_ */ +{0x0F12, 0x0002}, /* 0006 0004 Tune_wbt_GAS_501_ */ +{0x0F12, 0x0009}, /* 000B 000F Tune_wbt_GAS_502_ */ +{0x0F12, 0x0016}, /* 0018 0023 Tune_wbt_GAS_503_ */ +{0x0F12, 0x0029}, /* 0029 003E Tune_wbt_GAS_504_ */ +{0x0F12, 0x0040}, /* 003E 006A Tune_wbt_GAS_505_ */ +{0x0F12, 0x0054}, /* 0050 0091 Tune_wbt_GAS_506_ */ +{0x0F12, 0x005F}, /* 0044 0085 Tune_wbt_GAS_507_ */ +{0x0F12, 0x004A}, /* 0033 0060 Tune_wbt_GAS_508_ */ +{0x0F12, 0x0031}, /* 0021 0041 Tune_wbt_GAS_509_ */ +{0x0F12, 0x001F}, /* 0011 002A Tune_wbt_GAS_510_ */ +{0x0F12, 0x0010}, /* 0005 0019 Tune_wbt_GAS_511_ */ +{0x0F12, 0x0008}, /* 0002 000D Tune_wbt_GAS_512_ */ +{0x0F12, 0x0004}, /* 0001 0008 Tune_wbt_GAS_513_ */ +{0x0F12, 0x0007}, /* 0003 000A Tune_wbt_GAS_514_ */ +{0x0F12, 0x000E}, /* 0008 0016 Tune_wbt_GAS_515_ */ +{0x0F12, 0x001B}, /* 0014 002A Tune_wbt_GAS_516_ */ +{0x0F12, 0x002E}, /* 0025 0047 Tune_wbt_GAS_517_ */ +{0x0F12, 0x0045}, /* 0039 0074 Tune_wbt_GAS_518_ */ +{0x0F12, 0x0059}, /* 004D 009A Tune_wbt_GAS_519_ */ +{0x0F12, 0x006C}, /* 0050 0097 Tune_wbt_GAS_520_ */ +{0x0F12, 0x0057}, /* 0041 0070 Tune_wbt_GAS_521_ */ +{0x0F12, 0x003E}, /* 002C 0052 Tune_wbt_GAS_522_ */ +{0x0F12, 0x002A}, /* 001C 003C Tune_wbt_GAS_523_ */ +{0x0F12, 0x001B}, /* 0011 0028 Tune_wbt_GAS_524_ */ +{0x0F12, 0x0012}, /* 0009 001D Tune_wbt_GAS_525_ */ +{0x0F12, 0x000F}, /* 0008 0019 Tune_wbt_GAS_526_ */ +{0x0F12, 0x0011}, /* 000A 001A Tune_wbt_GAS_527_ */ +{0x0F12, 0x0019}, /* 0012 0026 Tune_wbt_GAS_528_ */ +{0x0F12, 0x0027}, /* 001F 003B Tune_wbt_GAS_529_ */ +{0x0F12, 0x0039}, /* 002F 005A Tune_wbt_GAS_530_ */ +{0x0F12, 0x0050}, /* 0045 0089 Tune_wbt_GAS_531_ */ +{0x0F12, 0x0063}, /* 005A 00AF Tune_wbt_GAS_532_ */ +{0x0F12, 0x006F}, /* 0056 00A7 Tune_wbt_GAS_533_ */ +{0x0F12, 0x005C}, /* 0048 0088 Tune_wbt_GAS_534_ */ +{0x0F12, 0x0044}, /* 0035 006B Tune_wbt_GAS_535_ */ +{0x0F12, 0x0031}, /* 0026 0050 Tune_wbt_GAS_536_ */ +{0x0F12, 0x0023}, /* 0019 003D Tune_wbt_GAS_537_ */ +{0x0F12, 0x0019}, /* 0012 0032 Tune_wbt_GAS_538_ */ +{0x0F12, 0x0016}, /* 0011 002E Tune_wbt_GAS_539_ */ +{0x0F12, 0x0017}, /* 0012 0030 Tune_wbt_GAS_540_ */ +{0x0F12, 0x0020}, /* 001B 003E Tune_wbt_GAS_541_ */ +{0x0F12, 0x002E}, /* 0027 0052 Tune_wbt_GAS_542_ */ +{0x0F12, 0x0040}, /* 0037 0073 Tune_wbt_GAS_543_ */ +{0x0F12, 0x0055}, /* 004C 00A1 Tune_wbt_GAS_544_ */ +{0x0F12, 0x0064}, /* 0060 00C7 Tune_wbt_GAS_545_ */ +{0x0F12, 0x007E}, /* 0058 00AE Tune_wbt_GAS_546_ */ +{0x0F12, 0x0071}, /* 0050 00A4 Tune_wbt_GAS_547_ */ +{0x0F12, 0x0059}, /* 003D 0088 Tune_wbt_GAS_548_ */ +{0x0F12, 0x0046}, /* 002E 006D Tune_wbt_GAS_549_ */ +{0x0F12, 0x0039}, /* 0023 0059 Tune_wbt_GAS_550_ */ +{0x0F12, 0x002F}, /* 001C 004D Tune_wbt_GAS_551_ */ +{0x0F12, 0x002A}, /* 001B 0049 Tune_wbt_GAS_552_ */ +{0x0F12, 0x002D}, /* 001D 004E Tune_wbt_GAS_553_ */ +{0x0F12, 0x0035}, /* 0024 005B Tune_wbt_GAS_554_ */ +{0x0F12, 0x0043}, /* 002F 0073 Tune_wbt_GAS_555_ */ +{0x0F12, 0x0054}, /* 003E 0095 Tune_wbt_GAS_556_ */ +{0x0F12, 0x0069}, /* 0052 00C4 Tune_wbt_GAS_557_ */ +{0x0F12, 0x0074}, /* 0062 00E9 Tune_wbt_GAS_558_ */ +{0x0F12, 0x0083}, /* 0060 00D5 Tune_wbt_GAS_559_ */ +{0x0F12, 0x007D}, /* 0057 00C1 Tune_wbt_GAS_560_ */ +{0x0F12, 0x0068}, /* 0048 00AB Tune_wbt_GAS_561_ */ +{0x0F12, 0x0055}, /* 0039 008D Tune_wbt_GAS_562_ */ +{0x0F12, 0x0048}, /* 002E 0079 Tune_wbt_GAS_563_ */ +{0x0F12, 0x003E}, /* 0028 0070 Tune_wbt_GAS_564_ */ +{0x0F12, 0x003A}, /* 0027 006A Tune_wbt_GAS_565_ */ +{0x0F12, 0x003D}, /* 0029 006F Tune_wbt_GAS_566_ */ +{0x0F12, 0x0045}, /* 002F 0080 Tune_wbt_GAS_567_ */ +{0x0F12, 0x0051}, /* 0039 0096 Tune_wbt_GAS_568_ */ +{0x0F12, 0x0061}, /* 0047 00B9 Tune_wbt_GAS_569_ */ +{0x0F12, 0x0072}, /* 0059 00E2 Tune_wbt_GAS_570_ */ +{0x0F12, 0x0077}, /* 0067 010F Tune_wbt_GAS_571_ */ +{0x002A, 0x1348}, +{0x0F12, 0x0001}, /* gisp_gras_Enable */ + +/**************************************/ +/* 07. Analog Setting 2 */ +/**************************************/ + +/**************************************/ +/* 08.AF Setting */ +/**************************************/ + +/**************************************/ +/* 09.AWB-BASIC setting */ +/**************************************/ +/* For WB Calibration */ +{0x002A, 0x0B36}, +{0x0F12, 0x0005}, /* awbb_IndoorGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0B3A}, +{0x0F12, 0x00EC}, /* awbb_IndoorGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02C1}, /* awbb_IndoorGrZones_ZInfo_m_BMax */ +{0x002A, 0x0B38}, +{0x0F12, 0x0010}, /* awbb_IndoorGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0AE6}, +{0x0F12, 0x03E1}, /* awbb_IndoorGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x0413}, /* awbb_IndoorGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x039E}, /* awbb_IndoorGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x0416}, /* awbb_IndoorGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x0367}, /* awbb_IndoorGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x03F3}, /* awbb_IndoorGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x032D}, /* awbb_IndoorGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x03C5}, /* awbb_IndoorGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x02FD}, /* awbb_IndoorGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x038F}, /* awbb_IndoorGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x02D3}, /* awbb_IndoorGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x0365}, /* awbb_IndoorGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x02AA}, /* awbb_IndoorGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x033E}, /* awbb_IndoorGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x028D}, /* awbb_IndoorGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0310}, /* awbb_IndoorGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x0271}, /* awbb_IndoorGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x02F1}, /* awbb_IndoorGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x025A}, /* awbb_IndoorGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x02D2}, /* awbb_IndoorGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0249}, /* awbb_IndoorGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x02B9}, /* awbb_IndoorGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0238}, /* awbb_IndoorGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x02A2}, /* awbb_IndoorGrZones_m_BGrid_11__m_right */ +{0x0F12, 0x021B}, /* awbb_IndoorGrZones_m_BGrid_12__m_left */ +{0x0F12, 0x0289}, /* awbb_IndoorGrZones_m_BGrid_12__m_right */ +{0x0F12, 0x0200}, /* awbb_IndoorGrZones_m_BGrid_13__m_left */ +{0x0F12, 0x026C}, /* awbb_IndoorGrZones_m_BGrid_13__m_right */ +{0x0F12, 0x01FC}, /* awbb_IndoorGrZones_m_BGrid_14__m_left */ +{0x0F12, 0x024F}, /* awbb_IndoorGrZones_m_BGrid_14__m_right */ +{0x0F12, 0x021E}, /* awbb_IndoorGrZones_m_BGrid_15__m_left */ +{0x0F12, 0x022C}, /* awbb_IndoorGrZones_m_BGrid_15__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_16__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_16__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_17__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_17__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_18__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_18__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_19__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_19__m_right */ +{0x002A, 0x0BAA}, +{0x0F12, 0x0006}, /* awbb_LowBrGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0BAE}, +{0x0F12, 0x010E}, /* awbb_LowBrGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02E9}, /* awbb_LowBrGrZones_ZInfo_m_BMax */ +{0x002A, 0x0BAC}, +{0x0F12, 0x0009}, /* awbb_LowBrGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0B7A}, +{0x0F12, 0x038C}, /* awbb_LowBrGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x03DA}, /* awbb_LowBrGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x030E}, /* awbb_LowBrGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x03E9}, /* awbb_LowBrGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x02A2}, /* awbb_LowBrGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x03C2}, /* awbb_LowBrGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x0259}, /* awbb_LowBrGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x038A}, /* awbb_LowBrGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x0218}, /* awbb_LowBrGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x0352}, /* awbb_LowBrGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x01F4}, /* awbb_LowBrGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x02E1}, /* awbb_LowBrGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x01D7}, /* awbb_LowBrGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x028E}, /* awbb_LowBrGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x01CB}, /* awbb_LowBrGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0258}, /* awbb_LowBrGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x022B}, /* awbb_LowBrGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x01CC}, /* awbb_LowBrGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_11__m_right */ +{0x002A, 0x0B70}, +{0x0F12, 0x0005}, /* awbb_OutdoorGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0B74}, +{0x0F12, 0x01F8}, /* awbb_OutdoorGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02A8}, /* awbb_OutdoorGrZones_ZInfo_m_BMax */ +{0x002A, 0x0B72}, +{0x0F12, 0x0007}, /* awbb_OutdoorGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0B40}, +{0x0F12, 0x029E}, /* awbb_OutdoorGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x02C8}, /* awbb_OutdoorGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x0281}, /* awbb_OutdoorGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x02C8}, /* awbb_OutdoorGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x0266}, /* awbb_OutdoorGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x02AC}, /* awbb_OutdoorGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x0251}, /* awbb_OutdoorGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x028E}, /* awbb_OutdoorGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x023D}, /* awbb_OutdoorGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x0275}, /* awbb_OutdoorGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x0228}, /* awbb_OutdoorGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x025D}, /* awbb_OutdoorGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x0228}, /* awbb_OutdoorGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x0243}, /* awbb_OutdoorGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_11__m_right */ +{0x002A, 0x0BC8}, +{0x0F12, 0x0005}, /* awbb_CWSkinZone_ZInfo_m_GridStep */ +{0x002A, 0x0BCC}, +{0x0F12, 0x010F}, /* awbb_CWSkinZone_ZInfo_m_BMin */ +{0x0F12, 0x018F}, /* awbb_CWSkinZone_ZInfo_m_BMax */ +{0x002A, 0x0BCA}, +{0x0F12, 0x0005}, /* awbb_CWSkinZone_ZInfo_m_GridSz */ +{0x002A, 0x0BB4}, +{0x0F12, 0x03E7}, /* awbb_CWSkinZone_m_BGrid_0__m_left */ +{0x0F12, 0x03F8}, /* awbb_CWSkinZone_m_BGrid_0__m_right */ +{0x0F12, 0x03A7}, /* awbb_CWSkinZone_m_BGrid_1__m_left */ +{0x0F12, 0x03FC}, /* awbb_CWSkinZone_m_BGrid_1__m_right */ +{0x0F12, 0x0352}, /* awbb_CWSkinZone_m_BGrid_2__m_left */ +{0x0F12, 0x03D0}, /* awbb_CWSkinZone_m_BGrid_2__m_right */ +{0x0F12, 0x0322}, /* awbb_CWSkinZone_m_BGrid_3__m_left */ +{0x0F12, 0x039E}, /* awbb_CWSkinZone_m_BGrid_3__m_right */ +{0x0F12, 0x032B}, /* awbb_CWSkinZone_m_BGrid_4__m_left */ +{0x0F12, 0x034D}, /* awbb_CWSkinZone_m_BGrid_4__m_right */ +{0x002A, 0x0BE6}, +{0x0F12, 0x0006}, /* awbb_DLSkinZone_ZInfo_m_GridStep */ +{0x002A, 0x0BEA}, +{0x0F12, 0x019E}, /* awbb_DLSkinZone_ZInfo_m_BMin */ +{0x0F12, 0x0257}, /* awbb_DLSkinZone_ZInfo_m_BMax */ +{0x002A, 0x0BE8}, +{0x0F12, 0x0004}, /* awbb_DLSkinZone_ZInfo_m_GridSz */ +{0x002A, 0x0BD2}, +{0x0F12, 0x030B}, /* awbb_DLSkinZone_m_BGrid_0__m_left */ +{0x0F12, 0x0323}, /* awbb_DLSkinZone_m_BGrid_0__m_right */ +{0x0F12, 0x02C3}, /* awbb_DLSkinZone_m_BGrid_1__m_left */ +{0x0F12, 0x030F}, /* awbb_DLSkinZone_m_BGrid_1__m_right */ +{0x0F12, 0x0288}, /* awbb_DLSkinZone_m_BGrid_2__m_left */ +{0x0F12, 0x02E5}, /* awbb_DLSkinZone_m_BGrid_2__m_right */ +{0x0F12, 0x026A}, /* awbb_DLSkinZone_m_BGrid_3__m_left */ +{0x0F12, 0x02A2}, /* awbb_DLSkinZone_m_BGrid_3__m_right */ +{0x0F12, 0x0000}, /* awbb_DLSkinZone_m_BGrid_4__m_left */ +{0x0F12, 0x0000}, /* awbb_DLSkinZone_m_BGrid_4__m_right */ +{0x002A, 0x0C2C}, +{0x0F12, 0x0139}, /* awbb_IntcR */ +{0x0F12, 0x0122}, /* awbb_IntcB */ +{0x002A, 0x0BFC}, +{0x0F12, 0x03AD}, /* awbb_IndoorWP_0__r */ +{0x0F12, 0x013F}, /* awbb_IndoorWP_0__b */ +{0x0F12, 0x0341}, /* awbb_IndoorWP_1__r */ +{0x0F12, 0x017B}, /* awbb_IndoorWP_1__b */ +{0x0F12, 0x038D}, /* awbb_IndoorWP_2__r */ +{0x0F12, 0x014B}, /* awbb_IndoorWP_2__b */ +{0x0F12, 0x02C3}, /* awbb_IndoorWP_3__r */ +{0x0F12, 0x01CC}, /* awbb_IndoorWP_3__b */ +{0x0F12, 0x0241}, /* awbb_IndoorWP_4__r */ +{0x0F12, 0x027F}, /* awbb_IndoorWP_4__b */ +{0x0F12, 0x0241}, /* awbb_IndoorWP_5__r */ +{0x0F12, 0x027F}, /* awbb_IndoorWP_5__b */ +{0x0F12, 0x0214}, /* awbb_IndoorWP_6__r */ +{0x0F12, 0x02A8}, /* awbb_IndoorWP_6__b */ +{0x0F12, 0x0270}, /* 255 awbb_OutdoorWP_r */ +{0x0F12, 0x0210}, /* 25B awbb_OutdoorWP_b */ +{0x002A, 0x0C4C}, +{0x0F12, 0x0452}, /* awbb_MvEq_RBthresh */ +{0x002A, 0x0C58}, +{0x0F12, 0x059C}, /* awbb_MvEq_RBthresh */ +{0x002A, 0x0BF8}, +{0x0F12, 0x01AE}, /* awbb_LowTSep_m_RminusB */ +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, /* awbb_SkinPreference */ +{0x002A, 0x0CAC}, +{0x0F12, 0x0F00}, /* awbb_SkinPreference */ +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, /* awbb_SkinPreference */ +{0x002A, 0x0D0E}, +{0x0F12, 0x00B8}, /* awbb_GridCoeff_R_2 */ +{0x0F12, 0x00B2}, /* awbb_GridCoeff_B_2 */ +{0x002A, 0x0CFE}, +{0x0F12, 0x0FAB}, /* awbb_GridConst_2_0_ */ +{0x0F12, 0x0FF5}, /* awbb_GridConst_2_1_ */ +{0x0F12, 0x10BB}, /* awbb_GridConst_2_2_ */ +{0x0F12, 0x1123}, /* 1153 awbb_GridConst_2_3_ */ +{0x0F12, 0x1165}, /* 11C5 awbb_GridConst_2_4_ */ +{0x0F12, 0x122A}, /* awbb_GridConst_2_5_ */ +{0x0F12, 0x00A9}, /* awbb_GridCoeff_R_1 */ +{0x0F12, 0x00C0}, /* awbb_GridCoeff_B_1 */ +{0x002A, 0x0CF8}, +{0x0F12, 0x030E}, /* awbb_GridConst_1_0_ */ +{0x0F12, 0x034C}, /* awbb_GridConst_1_1_ */ +{0x0F12, 0x0388}, /* awbb_GridConst_1_2_ */ + +{0x002A, 0x0CB0}, +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_0__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_0__1_ */ +{0x0F12, 0x0010}, /* 0078 awbb_GridCorr_R_0__2_ */ +{0x0F12, 0x0040}, /* 00AA awbb_GridCorr_R_0__3_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_0__4_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_0__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_1__0_ */ +{0x0F12, 0x0000}, /* 0096 awbb_GridCorr_R_1__1_ */ +{0x0F12, 0x0010}, /* 0000 awbb_GridCorr_R_1__2_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_1__3_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_1__4_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_1__5_ */ + +{0x0F12, 0x0000}, /* 00E6 awbb_GridCorr_R_2__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_2__1_ */ +{0x0F12, 0x0010}, /* 0000 awbb_GridCorr_R_2__2_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_2__3_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_2__4_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_2__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_0__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_0__1_ */ +{0x0F12, 0x0000}, /* 0064 awbb_GridCorr_B_0__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_0__3_ */ +{0x0F12, 0xFF60}, /* 0000 awbb_GridCorr_B_0__4_ */ +{0x0F12, 0xFF00}, /* 0000 awbb_GridCorr_B_0__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_1__0_ */ +{0x0F12, 0x0000}, /* 0032 awbb_GridCorr_B_1__1_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_1__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_1__3_ */ +{0x0F12, 0xFF60}, /* FF38 awbb_GridCorr_B_1__4_ */ +{0x0F12, 0xFF00}, /* 0000 awbb_GridCorr_B_1__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_2__0_ */ +{0x0F12, 0x0000}, /* 0032 awbb_GridCorr_B_2__1_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_2__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_2__3_ */ +{0x0F12, 0xFF60}, /* 0000 awbb_GridCorr_B_2__4_ */ +{0x0F12, 0xFF00}, /* 0000 awbb_GridCorr_B_2__5_ */ + +{0x002A, 0x0D30}, +{0x0F12, 0x0002}, /* awbb_GridEnable */ +/* For Outdoor Detector */ +{0x002A, 0x0C86}, +{0x0F12, 0x0005}, /* awbb_OutdoorDetectionZone_ZInfo_m_GridSz */ +{0x002A, 0x0C70}, +{0x0F12, 0xFF7B}, /* awbb_OutdoorDetectionZone_m_BGrid_0__m_left */ +{0x0F12, 0x00CE}, /* awbb_OutdoorDetectionZone_m_BGrid_0__m_right */ +{0x0F12, 0xFF23}, /* awbb_OutdoorDetectionZone_m_BGrid_1__m_left */ +{0x0F12, 0x010D}, /* awbb_OutdoorDetectionZone_m_BGrid_1__m_right */ +{0x0F12, 0xFEF3}, /* awbb_OutdoorDetectionZone_m_BGrid_2__m_left */ +{0x0F12, 0x012C}, /* awbb_OutdoorDetectionZone_m_BGrid_2__m_right */ +{0x0F12, 0xFED7}, /* awbb_OutdoorDetectionZone_m_BGrid_3__m_left */ +{0x0F12, 0x014E}, /* awbb_OutdoorDetectionZone_m_BGrid_3__m_right */ +{0x0F12, 0xFEBB}, /* awbb_OutdoorDetectionZone_m_BGrid_4__m_left */ +{0x0F12, 0x0162}, /* awbb_OutdoorDetectionZone_m_BGrid_4__m_right */ +{0x0F12, 0x1388}, /* awbb_OutdoorDetectionZone_ZInfo_m_AbsGridStep */ +{0x002A, 0x0C8A}, +{0x0F12, 0x4ACB}, /* awbb_OutdoorDetectionZone_ZInfo_m_MaxNB */ +{0x002A, 0x0C88}, +{0x0F12, 0x0A7C}, /* awbb_OutdoorDetectionZone_ZInfo_m_NBoffs */ + +/**************************************/ +/* 10.Auto Flicker Detection */ +/**************************************/ +{0x0028, 0x7000}, +{0x002A, 0x03F4}, +{0x0F12, 0x0002}, /*REG_SF_USER_FlickerQuant */ +{0x0F12, 0x0001}, /*REG_SF_USER_FlickerQuantChanged */ +{0x002A, 0x0408}, +{0x0F12, 0x067F}, /*REG_TC_DBG_AutoAlgEnBits all AA are on */ + +/**************************************/ +/* 11.AE Setting */ +/**************************************/ + +{0x002A, 0x0D40}, +{0x0F12, 0x003E}, /* 3E TVAR_ae_BrAve */ + +/* For LT Calibration */ +{0x002A, 0x0D46}, +{0x0F12, 0x000F}, /* ae_StatMode */ + +{0x002A, 0x0440}, +{0x0F12, 0x3410}, /* lt_uMaxExp_0_ */ +{0x002A, 0x0444}, +{0x0F12, 0x6820}, /* lt_uMaxExp_1_ */ +{0x002A, 0x0448}, +{0x0F12, 0x8227}, /* lt_uMaxExp_2_ */ +{0x002A, 0x044C}, +{0x0F12, 0xC350}, /* lt_uMaxExp_3_ */ +{0x002A, 0x0450}, +{0x0F12, 0x3410}, /* lt_uCapMaxExp_0_ */ +{0x002A, 0x0454}, +{0x0F12, 0x6820}, /* lt_uCapMaxExp_1_ */ +{0x002A, 0x0458}, +{0x0F12, 0x8227}, /* lt_uCapMaxExp_2_ */ +{0x002A, 0x045C}, +{0x0F12, 0xC350}, /* lt_uCapMaxExp_3_ */ +{0x002A, 0x0460}, +{0x0F12, 0x01B0}, /* lt_uMaxAnGain_0_ */ +{0x0F12, 0x01B0}, /* lt_uMaxAnGain_1_ */ +{0x0F12, 0x0280}, /* lt_uMaxAnGain_2_ */ +{0x0F12, 0x0A80}, /* lt_uMaxAnGain_3_ */ +{0x0F12, 0x00A0}, /* B0 0100 lt_uMaxDigGain */ +{0x0F12, 0x3000}, /* lt_uMaxTotGain */ +{0x002A, 0x042E}, +{0x0F12, 0x010E}, /* lt_uMaxTotGain */ +{0x0F12, 0x00F5}, /* lt_uLimitLow */ +{0x002A, 0x0DE0}, +{0x0F12, 0x0002}, /* ae_Fade2BlackEnable F2B off, F2W on */ + +/* For Illum Type Calibration */ +/* WRITE #SARR_IllumType_0_ 0078 */ +/* WRITE #SARR_IllumType_1_ 00C3 */ +/* WRITE #SARR_IllumType_2_ 00E9 */ +/* WRITE #SARR_IllumType_3_ 0128 */ +/* WRITE #SARR_IllumType_4_ 016F */ +/* WRITE #SARR_IllumType_5_ 0195 */ +/* WRITE #SARR_IllumType_6_ 01A4 */ +/* WRITE #SARR_IllumTypeF_0_ 0100 */ +/* WRITE #SARR_IllumTypeF_1_ 0100 */ +/* WRITE #SARR_IllumTypeF_2_ 0110 */ +/* WRITE #SARR_IllumTypeF_3_ 00E5 */ +/* WRITE #SARR_IllumTypeF_4_ 0100 */ +/* WRITE #SARR_IllumTypeF_5_ 00ED */ +/* WRITE #SARR_IllumTypeF_6_ 00ED */ + +/**************************************/ +/* 12.AE Weight (Normal) */ +/**************************************/ +{0x002A, 0x0D4E}, +{0x0F12, 0x0000}, /* 0000 ae_WeightTbl_16_0_ */ +{0x0F12, 0x0101}, /* 0101 ae_WeightTbl_16_1_ */ +{0x0F12, 0x0101}, /* 0101 ae_WeightTbl_16_2_ */ +{0x0F12, 0x0000}, /* 0000 ae_WeightTbl_16_3_ */ +{0x0F12, 0x0201}, /* 0101 ae_WeightTbl_16_4_ */ +{0x0F12, 0x0202}, /* 0101 ae_WeightTbl_16_5_ */ +{0x0F12, 0x0202}, /* 0101 ae_WeightTbl_16_6_ */ +{0x0F12, 0x0102}, /* 0101 ae_WeightTbl_16_7_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_8_ */ +{0x0F12, 0x0303}, /* 0303 ae_WeightTbl_16_9_ */ +{0x0F12, 0x0303}, /* 0303 ae_WeightTbl_16_10_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_11_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_12_ */ +{0x0F12, 0x0403}, /* 0403 ae_WeightTbl_16_13_ */ +{0x0F12, 0x0304}, /* 0304 ae_WeightTbl_16_14_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_15_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_16_ */ +{0x0F12, 0x0403}, /* 0403 ae_WeightTbl_16_17_ */ +{0x0F12, 0x0304}, /* 0304 ae_WeightTbl_16_18_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_19_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_20_ */ +{0x0F12, 0x0303}, /* 0403 ae_WeightTbl_16_21_ */ +{0x0F12, 0x0303}, /* 0304 ae_WeightTbl_16_22_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_23_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_24_ */ +{0x0F12, 0x0202}, /* 0303 ae_WeightTbl_16_25_ */ +{0x0F12, 0x0202}, /* 0303 ae_WeightTbl_16_26_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_27_ */ +{0x0F12, 0x0000}, /* 0201 ae_WeightTbl_16_28_ */ +{0x0F12, 0x0101}, /* 0202 ae_WeightTbl_16_29_ */ +{0x0F12, 0x0101}, /* 0202 ae_WeightTbl_16_30_ */ +{0x0F12, 0x0000}, /* 0102 ae_WeightTbl_16_31_ */ + +/**************************************/ +/* 13.Flash Setting */ +/**************************************/ + +/**************************************/ +/* 14.CCM Setting */ +/**************************************/ + +{0x002A, 0x33A4}, +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_0__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_0__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_0__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_0__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_0__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_0__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_0__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_0__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_0__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_0__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_0__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_0__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_0__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_0__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_0__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_0__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_0__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_0__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_1__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_1__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_1__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_1__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_1__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_1__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_1__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_1__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_1__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_1__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_1__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_1__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_1__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_1__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_1__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_1__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_1__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_1__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_2__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_2__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_2__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_2__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_2__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_2__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_2__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_2__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_2__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_2__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_2__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_2__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_2__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_2__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_2__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_2__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_2__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_2__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_3__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_3__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_3__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_3__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_3__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_3__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_3__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_3__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_3__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_3__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_3__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_3__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_3__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_3__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_3__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_3__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_3__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_3__17_ */ +{0x0F12, 0x01BF}, /* Tune_wbt_BaseCcms_4__0_ */ +{0x0F12, 0xFFBF}, /* Tune_wbt_BaseCcms_4__1_ */ +{0x0F12, 0xFFFE}, /* Tune_wbt_BaseCcms_4__2_ */ +{0x0F12, 0xFF6D}, /* Tune_wbt_BaseCcms_4__3_ */ +{0x0F12, 0x01B4}, /* Tune_wbt_BaseCcms_4__4_ */ +{0x0F12, 0xFF66}, /* Tune_wbt_BaseCcms_4__5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_BaseCcms_4__6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_BaseCcms_4__7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_BaseCcms_4__8_ */ +{0x0F12, 0x0136}, /* Tune_wbt_BaseCcms_4__9_ */ +{0x0F12, 0x0132}, /* Tune_wbt_BaseCcms_4__10_ */ +{0x0F12, 0xFF85}, /* Tune_wbt_BaseCcms_4__11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_BaseCcms_4__12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_BaseCcms_4__13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_4__14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_BaseCcms_4__15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_BaseCcms_4__16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_BaseCcms_4__17_ */ +{0x0F12, 0x01BF}, /* Tune_wbt_BaseCcms_5__0_ */ +{0x0F12, 0xFFBF}, /* Tune_wbt_BaseCcms_5__1_ */ +{0x0F12, 0xFFFE}, /* Tune_wbt_BaseCcms_5__2_ */ +{0x0F12, 0xFF6D}, /* Tune_wbt_BaseCcms_5__3_ */ +{0x0F12, 0x01B4}, /* Tune_wbt_BaseCcms_5__4_ */ +{0x0F12, 0xFF66}, /* Tune_wbt_BaseCcms_5__5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_BaseCcms_5__6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_BaseCcms_5__7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_BaseCcms_5__8_ */ +{0x0F12, 0x0136}, /* Tune_wbt_BaseCcms_5__9_ */ +{0x0F12, 0x0132}, /* Tune_wbt_BaseCcms_5__10_ */ +{0x0F12, 0xFF85}, /* Tune_wbt_BaseCcms_5__11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_BaseCcms_5__12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_BaseCcms_5__13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_5__14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_BaseCcms_5__15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_BaseCcms_5__16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_BaseCcms_5__17_ */ +{0x002A, 0x3380}, +{0x0F12, 0x01AC}, /* Tune_wbt_OutdoorCcm_0_ */ +{0x0F12, 0xFFD7}, /* Tune_wbt_OutdoorCcm_1_ */ +{0x0F12, 0x0019}, /* Tune_wbt_OutdoorCcm_2_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_OutdoorCcm_3_ */ +{0x0F12, 0x01D9}, /* Tune_wbt_OutdoorCcm_4_ */ +{0x0F12, 0xFF63}, /* Tune_wbt_OutdoorCcm_5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_OutdoorCcm_6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_OutdoorCcm_7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_OutdoorCcm_8_ */ +{0x0F12, 0x0132}, /* Tune_wbt_OutdoorCcm_9_ */ +{0x0F12, 0x012E}, /* Tune_wbt_OutdoorCcm_10_ */ +{0x0F12, 0xFF8D}, /* Tune_wbt_OutdoorCcm_11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_OutdoorCcm_12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_OutdoorCcm_13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_OutdoorCcm_14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_OutdoorCcm_15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_OutdoorCcm_16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_OutdoorCcm_17_ */ +{0x002A, 0x0612}, +{0x0F12, 0x009D}, /* SARR_AwbCcmCord_0_ */ +{0x0F12, 0x00D5}, /* SARR_AwbCcmCord_1_ */ +{0x0F12, 0x0103}, /* SARR_AwbCcmCord_2_ */ +{0x0F12, 0x0128}, /* SARR_AwbCcmCord_3_ */ +{0x0F12, 0x0166}, /* SARR_AwbCcmCord_4_ */ +{0x0F12, 0x0193}, /* SARR_AwbCcmCord_5_ */ + +/**************************************/ +/* 15.GAMMA */ +/**************************************/ +/* For Pre Post Gamma Calibration */ +{0x002A, 0x0538}, +{0x0F12, 0x0000}, /* seti_uGammaLutPreDemNoBin_0_ */ +{0x0F12, 0x001F}, /* seti_uGammaLutPreDemNoBin_1_ */ +{0x0F12, 0x0035}, /* seti_uGammaLutPreDemNoBin_2_ */ +{0x0F12, 0x005A}, /* seti_uGammaLutPreDemNoBin_3_ */ +{0x0F12, 0x0095}, /* seti_uGammaLutPreDemNoBin_4_ */ +{0x0F12, 0x00E6}, /* seti_uGammaLutPreDemNoBin_5_ */ +{0x0F12, 0x0121}, /* seti_uGammaLutPreDemNoBin_6_ */ +{0x0F12, 0x0139}, /* seti_uGammaLutPreDemNoBin_7_ */ +{0x0F12, 0x0150}, /* seti_uGammaLutPreDemNoBin_8_ */ +{0x0F12, 0x0177}, /* seti_uGammaLutPreDemNoBin_9_ */ +{0x0F12, 0x019A}, /* seti_uGammaLutPreDemNoBin_10_ */ +{0x0F12, 0x01BB}, /* seti_uGammaLutPreDemNoBin_11_ */ +{0x0F12, 0x01DC}, /* seti_uGammaLutPreDemNoBin_12_ */ +{0x0F12, 0x0219}, /* seti_uGammaLutPreDemNoBin_13_ */ +{0x0F12, 0x0251}, /* seti_uGammaLutPreDemNoBin_14_ */ +{0x0F12, 0x02B3}, /* seti_uGammaLutPreDemNoBin_15_ */ +{0x0F12, 0x030A}, /* seti_uGammaLutPreDemNoBin_16_ */ +{0x0F12, 0x035F}, /* seti_uGammaLutPreDemNoBin_17_ */ +{0x0F12, 0x03B1}, /* seti_uGammaLutPreDemNoBin_18_ */ +{0x0F12, 0x03FF}, /* seti_uGammaLutPreDemNoBin_19_ */ +{0x0F12, 0x0000}, /* seti_uGammaLutPostDemNoBin_0_ */ +{0x0F12, 0x0001}, /* seti_uGammaLutPostDemNoBin_1_ */ +{0x0F12, 0x0001}, /* seti_uGammaLutPostDemNoBin_2_ */ +{0x0F12, 0x0002}, /* seti_uGammaLutPostDemNoBin_3_ */ +{0x0F12, 0x0004}, /* seti_uGammaLutPostDemNoBin_4_ */ +{0x0F12, 0x000A}, /* seti_uGammaLutPostDemNoBin_5_ */ +{0x0F12, 0x0012}, /* seti_uGammaLutPostDemNoBin_6_ */ +{0x0F12, 0x0016}, /* seti_uGammaLutPostDemNoBin_7_ */ +{0x0F12, 0x001A}, /* seti_uGammaLutPostDemNoBin_8_ */ +{0x0F12, 0x0024}, /* seti_uGammaLutPostDemNoBin_9_ */ +{0x0F12, 0x0031}, /* seti_uGammaLutPostDemNoBin_10_ */ +{0x0F12, 0x003E}, /* seti_uGammaLutPostDemNoBin_11_ */ +{0x0F12, 0x004E}, /* seti_uGammaLutPostDemNoBin_12_ */ +{0x0F12, 0x0075}, /* seti_uGammaLutPostDemNoBin_13_ */ +{0x0F12, 0x00A8}, /* seti_uGammaLutPostDemNoBin_14_ */ +{0x0F12, 0x0126}, /* seti_uGammaLutPostDemNoBin_15_ */ +{0x0F12, 0x01BE}, /* seti_uGammaLutPostDemNoBin_16_ */ +{0x0F12, 0x0272}, /* seti_uGammaLutPostDemNoBin_17_ */ +{0x0F12, 0x0334}, /* seti_uGammaLutPostDemNoBin_18_ */ +{0x0F12, 0x03FF}, /* seti_uGammaLutPostDemNoBin_19_ */ + +/* For Gamma Calibration */ + +{0x002A, 0x0498}, +{0x0F12, 0x0000}, /* SARR_usDualGammaLutRGBIndoor_0__0_ */ +{0x0F12, 0x0002}, /* SARR_usDualGammaLutRGBIndoor_0__1_ */ +{0x0F12, 0x0007}, /* SARR_usDualGammaLutRGBIndoor_0__2_ */ +{0x0F12, 0x001D}, /* SARR_usDualGammaLutRGBIndoor_0__3_ */ +{0x0F12, 0x006E}, /* SARR_usDualGammaLutRGBIndoor_0__4_ */ +{0x0F12, 0x00D3}, /* SARR_usDualGammaLutRGBIndoor_0__5_ */ +{0x0F12, 0x0127}, /* SARR_usDualGammaLutRGBIndoor_0__6_ */ +{0x0F12, 0x014C}, /* SARR_usDualGammaLutRGBIndoor_0__7_ */ +{0x0F12, 0x016E}, /* SARR_usDualGammaLutRGBIndoor_0__8_ */ +{0x0F12, 0x01A5}, /* SARR_usDualGammaLutRGBIndoor_0__9_ */ +{0x0F12, 0x01D3}, /* SARR_usDualGammaLutRGBIndoor_0__10_ */ +{0x0F12, 0x01FB}, /* SARR_usDualGammaLutRGBIndoor_0__11_ */ +{0x0F12, 0x021F}, /* SARR_usDualGammaLutRGBIndoor_0__12_ */ +{0x0F12, 0x0260}, /* SARR_usDualGammaLutRGBIndoor_0__13_ */ +{0x0F12, 0x029A}, /* SARR_usDualGammaLutRGBIndoor_0__14_ */ +{0x0F12, 0x02F7}, /* SARR_usDualGammaLutRGBIndoor_0__15_ */ +{0x0F12, 0x034D}, /* SARR_usDualGammaLutRGBIndoor_0__16_ */ +{0x0F12, 0x0395}, /* SARR_usDualGammaLutRGBIndoor_0__17_ */ +{0x0F12, 0x03CE}, /* SARR_usDualGammaLutRGBIndoor_0__18_ */ +{0x0F12, 0x03FF}, /* SARR_usDualGammaLutRGBIndoor_0__19_ */ +{0x0F12, 0x0000}, /* SARR_usDualGammaLutRGBOutdoor_0__0_ */ +{0x0F12, 0x0004}, /* SARR_usDualGammaLutRGBOutdoor_0__1_ */ +{0x0F12, 0x000C}, /* SARR_usDualGammaLutRGBOutdoor_0__2_ */ +{0x0F12, 0x0024}, /* SARR_usDualGammaLutRGBOutdoor_0__3_ */ +{0x0F12, 0x006E}, /* SARR_usDualGammaLutRGBOutdoor_0__4_ */ +{0x0F12, 0x00D1}, /* SARR_usDualGammaLutRGBOutdoor_0__5_ */ +{0x0F12, 0x0119}, /* SARR_usDualGammaLutRGBOutdoor_0__6_ */ +{0x0F12, 0x0139}, /* SARR_usDualGammaLutRGBOutdoor_0__7_ */ +{0x0F12, 0x0157}, /* SARR_usDualGammaLutRGBOutdoor_0__8_ */ +{0x0F12, 0x018E}, /* SARR_usDualGammaLutRGBOutdoor_0__9_ */ +{0x0F12, 0x01C3}, /* SARR_usDualGammaLutRGBOutdoor_0__10_ */ +{0x0F12, 0x01F3}, /* SARR_usDualGammaLutRGBOutdoor_0__11_ */ +{0x0F12, 0x021F}, /* SARR_usDualGammaLutRGBOutdoor_0__12_ */ +{0x0F12, 0x0269}, /* SARR_usDualGammaLutRGBOutdoor_0__13_ */ +{0x0F12, 0x02A6}, /* SARR_usDualGammaLutRGBOutdoor_0__14_ */ +{0x0F12, 0x02FF}, /* SARR_usDualGammaLutRGBOutdoor_0__15_ */ +{0x0F12, 0x0351}, /* SARR_usDualGammaLutRGBOutdoor_0__16_ */ +{0x0F12, 0x0395}, /* SARR_usDualGammaLutRGBOutdoor_0__17_ */ +{0x0F12, 0x03CE}, /* SARR_usDualGammaLutRGBOutdoor_0__18_ */ +{0x0F12, 0x03FF}, /* SARR_usDualGammaLutRGBOutdoor_0__19_ */ + +/**************************************/ +/* 16.AFIT */ +/**************************************/ +{0x002A, 0x06D4}, +{0x0F12, 0x0032}, /* afit_uNoiseIndInDoor_0_ */ +{0x0F12, 0x0078}, /* afit_uNoiseIndInDoor_1_ */ +{0x0F12, 0x00C8}, /* afit_uNoiseIndInDoor_2_ */ +{0x0F12, 0x0190}, /* afit_uNoiseIndInDoor_3_ */ +{0x0F12, 0x028C}, /* afit_uNoiseIndInDoor_4_ */ + +{0x002A, 0x0734}, +{0x0F12, 0x0000}, /* AfitBaseVals_0__0_ Brightness[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__1_ Contrast[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__4_ */ +{0x0F12, 0x0078}, /* AfitBaseVals_0__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_0__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_0__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_0__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_0__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_0__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_0__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_0__14_ */ +{0x0F12, 0x01FF}, /* AfitBaseVals_0__15_ */ +{0x0F12, 0x0144}, /* AfitBaseVals_0__16_ */ +{0x0F12, 0x000F}, /* AfitBaseVals_0__17_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_0__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_0__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__21_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_0__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_0__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__25_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_0__27_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_0__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_0__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_0__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_0__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_0__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_0__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_0__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_0__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__40_ */ +{0x0F12, 0x1408}, /* AfitBaseVals_0__41_ */ +{0x0F12, 0x0214}, /* AfitBaseVals_0__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_0__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_0__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_0__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_0__47_ */ +{0x0F12, 0x0094}, /* AfitBaseVals_0__48_ */ +{0x0F12, 0x0580}, /* AfitBaseVals_0__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_0__50_ */ +{0x0F12, 0x0308}, /* AfitBaseVals_0__51_ */ +{0x0F12, 0x3186}, /* AfitBaseVals_0__52_ */ +{0x0F12, 0x5260}, /* AfitBaseVals_0__53_ */ +{0x0F12, 0x0A02}, /* AfitBaseVals_0__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_0__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_0__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_0__57_ */ +{0x0F12, 0x324E}, /* AfitBaseVals_0__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_0__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_0__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_0__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_0__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_0__63_ */ +{0x0F12, 0x4646}, /* AfitBaseVals_0__64_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__65_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_0__68_ */ +{0x0F12, 0x3202}, /* AfitBaseVals_0__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_0__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_0__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_0__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_0__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_0__74_ */ +{0x0F12, 0x4646}, /* AfitBaseVals_0__75_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__76_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_0__79_ */ +{0x0F12, 0x3202}, /* AfitBaseVals_0__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_0__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_0__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_0__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__0_ Brightness[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__1_ Contrast[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__4_ */ +{0x0F12, 0x006A}, /* AfitBaseVals_1__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_1__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_1__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_1__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_1__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_1__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_1__12_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_1__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_1__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_1__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_1__16_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__17_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_1__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_1__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__21_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_1__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__25_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_1__27_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_1__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_1__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_1__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_1__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_1__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_1__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_1__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__40_ */ +{0x0F12, 0x1408}, /* AfitBaseVals_1__41_ */ +{0x0F12, 0x0214}, /* AfitBaseVals_1__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_1__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_1__44_ */ +{0x0F12, 0x0002}, /* AfitBaseVals_1__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_1__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_1__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_1__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_1__50_ */ +{0x0F12, 0x0308}, /* AfitBaseVals_1__51_ */ +{0x0F12, 0x1E65}, /* AfitBaseVals_1__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_1__53_ */ +{0x0F12, 0x0A03}, /* AfitBaseVals_1__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_1__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_1__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_1__57_ */ +{0x0F12, 0x324D}, /* AfitBaseVals_1__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_1__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_1__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_1__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_1__63_ */ +{0x0F12, 0x2F34}, /* AfitBaseVals_1__64_ */ +{0x0F12, 0x0504}, /* AfitBaseVals_1__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_1__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_1__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_1__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_1__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_1__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_1__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_1__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_1__74_ */ +{0x0F12, 0x1414}, /* AfitBaseVals_1__75_ */ +{0x0F12, 0x0504}, /* AfitBaseVals_1__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_1__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_1__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_1__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_1__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_1__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_1__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__0_ Brightness[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__1_ Contrast[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__4_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_2__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_2__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_2__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_2__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_2__12_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_2__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_2__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_2__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_2__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_2__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_2__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_2__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__21_ */ +{0x0F12, 0x0019}, /* AfitBaseVals_2__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_2__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__25_ */ +{0x0F12, 0x0019}, /* AfitBaseVals_2__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_2__27_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_2__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_2__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_2__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_2__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_2__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_2__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_2__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_2__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_2__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_2__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_2__44_ */ +{0x0F12, 0x0002}, /* AfitBaseVals_2__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_2__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_2__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_2__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_2__50_ */ +{0x0F12, 0x0208}, /* AfitBaseVals_2__51_ */ +{0x0F12, 0x1E4B}, /* AfitBaseVals_2__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_2__53_ */ +{0x0F12, 0x0A05}, /* AfitBaseVals_2__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_2__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_2__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_2__57_ */ +{0x0F12, 0x324D}, /* AfitBaseVals_2__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_2__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_2__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_2__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_2__63_ */ +{0x0F12, 0x1E23}, /* AfitBaseVals_2__64_ */ +{0x0F12, 0x0505}, /* AfitBaseVals_2__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_2__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_2__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_2__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_2__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_2__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_2__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_2__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_2__74_ */ +{0x0F12, 0x1E23}, /* AfitBaseVals_2__75_ */ +{0x0F12, 0x0505}, /* AfitBaseVals_2__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_2__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_2__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_2__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_2__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_2__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_2__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__0_ Brightness[3] */ +{0x0F12, 0x0018}, /* 0000 AfitBaseVals_3__1_ Contrast[3] */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__4_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_3__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_3__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_3__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_3__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_3__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_3__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_3__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_3__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_3__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_3__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_3__19_ */ +{0x0F12, 0x009F}, /* AfitBaseVals_3__20_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__21_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_3__23_ */ +{0x0F12, 0x0037}, /* AfitBaseVals_3__24_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__25_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_3__27_ */ +{0x0F12, 0x0037}, /* AfitBaseVals_3__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_3__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_3__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_3__34_ */ +{0x0F12, 0x07A0}, /* AfitBaseVals_3__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_3__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_3__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_3__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_3__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_3__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_3__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_3__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_3__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_3__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_3__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_3__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_3__50_ */ +{0x0F12, 0x0108}, /* AfitBaseVals_3__51_ */ +{0x0F12, 0x1E32}, /* AfitBaseVals_3__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_3__53_ */ +{0x0F12, 0x0A05}, /* AfitBaseVals_3__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_3__55_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__56_ */ +{0x0F12, 0x0328}, /* AfitBaseVals_3__57_ */ +{0x0F12, 0x324C}, /* AfitBaseVals_3__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_3__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_3__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_3__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_3__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_3__63_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_3__64_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_3__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_3__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_3__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_3__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_3__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_3__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_3__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_3__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_3__74_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_3__75_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_3__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_3__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_3__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_3__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_3__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_3__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_3__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__0_ Brightness[4] */ +{0x0F12, 0x0014}, /* 0000 AfitBaseVals_4__1_ Contrast[4] */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__4_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_4__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_4__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_4__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_4__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_4__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_4__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_4__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_4__14_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_4__15_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_4__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_4__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_4__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_4__19_ */ +{0x0F12, 0x00B4}, /* AfitBaseVals_4__20_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__21_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_4__23_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_4__24_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__25_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_4__27_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_4__28_ */ +{0x0F12, 0x2B23}, /* AfitBaseVals_4__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_4__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_4__34_ */ +{0x0F12, 0x0B84}, /* AfitBaseVals_4__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_4__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_4__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_4__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_4__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_4__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_4__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_4__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_4__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_4__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_4__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_4__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_4__50_ */ +{0x0F12, 0x0108}, /* AfitBaseVals_4__51_ */ +{0x0F12, 0x1E1E}, /* AfitBaseVals_4__52_ */ +{0x0F12, 0x1419}, /* AfitBaseVals_4__53_ */ +{0x0F12, 0x0A0A}, /* AfitBaseVals_4__54_ */ +{0x0F12, 0x0800}, /* AfitBaseVals_4__55_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__56_ */ +{0x0F12, 0x0328}, /* AfitBaseVals_4__57_ */ +{0x0F12, 0x324C}, /* AfitBaseVals_4__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_4__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_4__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_4__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_4__62_ */ +{0x0F12, 0x6464}, /* AfitBaseVals_4__63_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_4__64_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_4__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_4__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_4__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_4__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_4__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_4__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_4__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_4__73_ */ +{0x0F12, 0x6464}, /* AfitBaseVals_4__74_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_4__75_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_4__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_4__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_4__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_4__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_4__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_4__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_4__83_ */ +{0x0F12, 0x7F5E}, /* ConstAfitBaseVals_0_ */ +{0x0F12, 0xFEEE}, /* ConstAfitBaseVals_1_ */ +{0x0F12, 0xD9B7}, /* ConstAfitBaseVals_2_ */ +{0x0F12, 0x0472}, /* ConstAfitBaseVals_3_ */ +{0x0F12, 0x0001}, /* ConstAfitBaseVals_4_ */ + +/**************************************/ +/* 17.JPEG Thumnail Setting */ +/**************************************/ + +/**************************************/ +/* 18.Input Size Setting */ +/**************************************/ + +/**************************************/ +/* 19.Preview & Capture Configration */ +/* Setting */ +/**************************************/ +/* Preview config[0] 640X480 15~7.5fps */ +{0x002A, 0x01BE}, +{0x0F12, 0x0500}, /* REG_0TC_PCFG_usWidth 500:1280; 280:640 */ +{0x0F12, 0x03C0}, /* REG_0TC_PCFG_usHeight 3C0:960; 1E0:480 */ +{0x0F12, 0x0005}, /* REG_0TC_PCFG_Format 5:YUV422; 7:RAW10 */ +{0x002A, 0x01C8}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uClockInd */ +{0x002A, 0x01C4}, +{0x0F12, 0x0052}, /* REG_0TC_PCFG_PVIMask 52:YUV422, 42:RAW10 */ +{0x002A, 0x01D4}, +{0x0F12, 0x0002}, +{0x002A, 0x01D2}, +{0x0F12, 0x0000}, +{0x002A, 0x01D8}, +{0x0F12, 0x0190}, +{0x002A, 0x01D6}, +{0x0F12, 0x0190}, /* REG_0TC_PCFG_usMinFrTimeMsecMult10 */ +{0x002A, 0x01E8}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uPrevMirror */ +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uCaptureMirror */ + +/* Preview config[1] 1280X960 7.5fps */ +{0x002A, 0x01EE}, +{0x0F12, 0x0500}, /* 1280 */ +{0x0F12, 0x03C0}, /* 960 */ +{0x0F12, 0x0005}, /* YUV422 */ +{0x002A, 0x01F8}, +{0x0F12, 0x0000}, +{0x002A, 0x01F4}, +{0x0F12, 0x0052}, +{0x002A, 0x0204}, +{0x0F12, 0x0002}, /* 1b: FR (bin) 2b: Quality (no-bin) */ +{0x002A, 0x0202}, +{0x0F12, 0x0001}, +{0x002A, 0x0208}, +{0x0F12, 0x0535}, +{0x002A, 0x0206}, +{0x0F12, 0x0000}, +{0x002A, 0x0218}, +{0x0F12, 0x0000}, /* REG_1TC_PCFG_uPrevMirror */ +{0x0F12, 0x0000}, /* REG_1TC_PCFG_uCaptureMirror */ + +/* Capture config[0] 1280x960 7.5fps */ +/* {0x002A, 0x02AE}, */ +/* {0x0F12, 0x0001}, */ /* Capture mode AE On */ +{0x002A, 0x02B0}, +{0x0F12, 0x0500}, /* REG_0TC_CCFG_usWidth 500:1280; 280:640 */ +{0x0F12, 0x03C0}, /* REG_0TC_CCFG_usHeight 3C0:960; 1E0:480 */ +{0x0F12, 0x0005}, /* REG_0TC_CCFG_Format 5:YUV422; 7:RAW10 */ +{0x002A, 0x02BA}, +{0x0F12, 0x0000}, /* REG_0TC_CCFG_uClockInd */ +{0x002A, 0x02B6}, +{0x0F12, 0x0052}, /* REG_0TC_CCFG_PVIMask 52:YUV422; 42:RAW10 */ +{0x002A, 0x02C6}, +{0x0F12, 0x0002}, +{0x002A, 0x02C4}, +{0x0F12, 0x0002}, +{0x002A, 0x02CA}, +{0x0F12, 0x0535}, +{0x002A, 0x02C8}, +{0x0F12, 0x0000}, /* REG_0TC_CCFG_usMinFrTimeMsecMult10 */ + +/**************************************/ +/* 20.Clock Setting */ +/**************************************/ +/* Input Clock (Mclk) */ +{0x002A, 0x012E}, +{0x0F12, 0x5DC0}, /* REG_TC_IPRM_InClockLSBs */ +{0x0F12, 0x0000}, /* REG_TC_IPRM_InClockMSBs */ +{0x002A, 0x0146}, +{0x0F12, 0x0000}, /* REG_TC_IPRM_UseNPviClocks */ +{0x0F12, 0x0001}, /* REG_TC_IPRM_UseNMipiClocks */ + +/* System Clock & Output clock (Pclk) */ +{0x002A, 0x014C}, +{0x0F12, 0x2BF2}, /* REG_TC_IPRM_OpClk4KHz_0 */ +{0x002A, 0x0152}, +{0x0F12, 0x57E4}, /* REG_TC_IPRM_MinOutRate4KHz_0 */ +{0x002A, 0x014E}, +{0x0F12, 0x57E4}, /* REG_TC_IPRM_MaxOutRate4KHz_0 */ +{0x002A, 0x01A8}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActivePrevConfig */ +{0x002A, 0x01B0}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActiveCapConfig */ +{0x002A, 0x019E}, +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreview */ +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreviewChanged */ +{0x002A, 0x0164}, +{0x0F12, 0x0001}, /* REG_TC_IPRM_InitParamsUpdated */ +{0x0028, 0xD000}, +{0x002A, 0x1000}, +{0x0F12, 0x0001}, /* Set host interrupt */ +{0xffff, 0x000a}, + +/* End of Self-Cam init */ +}; + +struct s5k8aay_short_t s5k8aay_skt_vt_common[] = { +/* Start of SKT VT-Call init */ + +/**************************************/ +/* 01.Start Setting */ +/**************************************/ +{0xFCFC, 0xD000}, +{0x0010, 0x0001}, /* S/W Reset */ +{0xFCFC, 0x0000}, +{0x0000, 0x0000}, /* Simmian bug workaround */ + +{0xFCFC, 0xD000}, +{0x1030, 0x0000}, /* contint_host_int */ +{0x0014, 0x0001}, + +{0xffff, 0x0001}, /* Delay 1ms */ + +/**************************************/ +/*02.ETC Setting */ +/**************************************/ +{0x002A, 0x1278}, +{0x0F12, 0xAAF0}, /* gisp_dadlc_config Ladlc mode average*/ + +/************************************** + * 03.Analog Setting & ASP Control + ************************************** + * This register is for FACTORY ONLY. + * If you change it without prior notification + * YOU are RESPONSIBLE for the FAILURE + * that will happen in the future + * For CDS Timing + ************************************** + */ +{0x002A, 0x0EC6}, +{0x0F12, 0x000B}, /* 11d aig_fdba_ptr0 */ +{0x002A, 0x0ECE}, +{0x0F12, 0x000B}, /* 11d aig_fdbb_ptr0 */ +{0x002A, 0x0F16}, +{0x0F12, 0x002B}, /* 43d aig_sfdba_reg0 */ +{0x002A, 0x0F1E}, +{0x0F12, 0x002B}, /* 43d aig_sfdbb_reg0 */ +{0x002A, 0x0EC8}, +{0x0F12, 0x000B}, /* 11d aig_fdba_ptr0 */ +{0x002A, 0x0ED0}, +{0x0F12, 0x033F}, /* 831d aig_fdbb_ptr0 */ +{0x002A, 0x0F18}, +{0x0F12, 0x0366}, /* 870d aig_sfdba_reg0 */ +{0x002A, 0x0F20}, +{0x0F12, 0x0032}, /* 50d aig_sfdbb_reg0 */ + +/* For Other Analog Settings */ +{0x002A, 0x0E38}, +{0x0F12, 0x0476}, /* senHal_RegCompBiasNormSf CDS bias */ +{0x0F12, 0x0476}, /* senHal_RegCompBiasYAv CDS bias */ +{0x002A, 0x0AA0}, +{0x0F12, 0x0001}, /* setot_bUseDigitalHbin 1-Digital, 0-Analog */ +{0x002A, 0x0E2C}, +{0x0F12, 0x0001}, +{0x002A, 0x1250}, +{0x0F12, 0xFFFF}, /* senHal_Bls_nSpExpLines */ +{0x002A, 0x1202}, +{0x0F12, 0x0010}, /* senHal_Dblr_VcoFreqMHZ */ + +/**************************************/ +/* 04.Trap and Patch */ +/**************************************/ +/* Start of Patch data */ +{0x0028, 0x7000}, +{0x002A, 0x2470}, +{0x0F12, 0xB510}, /* 70002470 */ +{0x0F12, 0x490D}, /* 70002472 */ +{0x0F12, 0x480D}, /* 70002474 */ +{0x0F12, 0xF000}, /* 70002476 */ +{0x0F12, 0xF96D}, /* 70002478 */ +{0x0F12, 0x490D}, /* 7000247A */ +{0x0F12, 0x480D}, /* 7000247C */ +{0x0F12, 0xF000}, /* 7000247E */ +{0x0F12, 0xF969}, /* 70002480 */ +{0x0F12, 0x490D}, /* 70002482 */ +{0x0F12, 0x480D}, /* 70002484 */ +{0x0F12, 0x6341}, /* 70002486 */ +{0x0F12, 0x490D}, /* 70002488 */ +{0x0F12, 0x480E}, /* 7000248A */ +{0x0F12, 0xF000}, /* 7000248C */ +{0x0F12, 0xF962}, /* 7000248E */ +{0x0F12, 0x490D}, /* 70002490 */ +{0x0F12, 0x480E}, /* 70002492 */ +{0x0F12, 0xF000}, /* 70002494 */ +{0x0F12, 0xF95E}, /* 70002496 */ +{0x0F12, 0x490D}, /* 70002498 */ +{0x0F12, 0x480E}, /* 7000249A */ +{0x0F12, 0xF000}, /* 7000249C */ +{0x0F12, 0xF95A}, /* 7000249E */ +{0x0F12, 0xBC10}, /* 700024A0 */ +{0x0F12, 0xBC08}, /* 700024A2 */ +{0x0F12, 0x4718}, /* 700024A4 */ +{0x0F12, 0x0000}, /* 700024A6 */ +{0x0F12, 0x26D4}, /* 700024A8 */ +{0x0F12, 0x7000}, /* 700024AA */ +{0x0F12, 0x8EDD}, /* 700024AC */ +{0x0F12, 0x0000}, /* 700024AE */ +{0x0F12, 0x264C}, /* 700024B0 */ +{0x0F12, 0x7000}, /* 700024B2 */ +{0x0F12, 0x8725}, /* 700024B4 */ +{0x0F12, 0x0000}, /* 700024B6 */ +{0x0F12, 0x25EC}, /* 700024B8 */ +{0x0F12, 0x7000}, /* 700024BA */ +{0x0F12, 0x0080}, /* 700024BC */ +{0x0F12, 0x7000}, /* 700024BE */ +{0x0F12, 0x2540}, /* 700024C0 */ +{0x0F12, 0x7000}, /* 700024C2 */ +{0x0F12, 0xA6EF}, /* 700024C4 */ +{0x0F12, 0x0000}, /* 700024C6 */ +{0x0F12, 0x250C}, /* 700024C8 */ +{0x0F12, 0x7000}, /* 700024CA */ +{0x0F12, 0xA0F1}, /* 700024CC */ +{0x0F12, 0x0000}, /* 700024CE */ +{0x0F12, 0x24D8}, /* 700024D0 */ +{0x0F12, 0x7000}, /* 700024D2 */ +{0x0F12, 0x058F}, /* 700024D4 */ +{0x0F12, 0x0000}, /* 700024D6 */ +{0x0F12, 0x4010}, /* 700024D8 */ +{0x0F12, 0xE92D}, /* 700024DA */ +{0x0F12, 0x00A0}, /* 700024DC */ +{0x0F12, 0xEB00}, /* 700024DE */ +{0x0F12, 0x023C}, /* 700024E0 */ +{0x0F12, 0xE59F}, /* 700024E2 */ +{0x0F12, 0x00B2}, /* 700024E4 */ +{0x0F12, 0xE1D0}, /* 700024E6 */ +{0x0F12, 0x0000}, /* 700024E8 */ +{0x0F12, 0xE350}, /* 700024EA */ +{0x0F12, 0x0004}, /* 700024EC */ +{0x0F12, 0x0A00}, /* 700024EE */ +{0x0F12, 0x0080}, /* 700024F0 */ +{0x0F12, 0xE310}, /* 700024F2 */ +{0x0F12, 0x0002}, /* 700024F4 */ +{0x0F12, 0x1A00}, /* 700024F6 */ +{0x0F12, 0x1228}, /* 700024F8 */ +{0x0F12, 0xE59F}, /* 700024FA */ +{0x0F12, 0x0001}, /* 700024FC */ +{0x0F12, 0xE3A0}, /* 700024FE */ +{0x0F12, 0x0DB2}, /* 70002500 */ +{0x0F12, 0xE1C1}, /* 70002502 */ +{0x0F12, 0x4010}, /* 70002504 */ +{0x0F12, 0xE8BD}, /* 70002506 */ +{0x0F12, 0xFF1E}, /* 70002508 */ +{0x0F12, 0xE12F}, /* 7000250A */ +{0x0F12, 0x4010}, /* 7000250C */ +{0x0F12, 0xE92D}, /* 7000250E */ +{0x0F12, 0x4000}, /* 70002510 */ +{0x0F12, 0xE590}, /* 70002512 */ +{0x0F12, 0x0004}, /* 70002514 */ +{0x0F12, 0xE1A0}, /* 70002516 */ +{0x0F12, 0x0094}, /* 70002518 */ +{0x0F12, 0xEB00}, /* 7000251A */ +{0x0F12, 0x0208}, /* 7000251C */ +{0x0F12, 0xE59F}, /* 7000251E */ +{0x0F12, 0x0000}, /* 70002520 */ +{0x0F12, 0xE5D0}, /* 70002522 */ +{0x0F12, 0x0000}, /* 70002524 */ +{0x0F12, 0xE350}, /* 70002526 */ +{0x0F12, 0x0002}, /* 70002528 */ +{0x0F12, 0x0A00}, /* 7000252A */ +{0x0F12, 0x0004}, /* 7000252C */ +{0x0F12, 0xE594}, /* 7000252E */ +{0x0F12, 0x00A0}, /* 70002530 */ +{0x0F12, 0xE1A0}, /* 70002532 */ +{0x0F12, 0x0004}, /* 70002534 */ +{0x0F12, 0xE584}, /* 70002536 */ +{0x0F12, 0x4010}, /* 70002538 */ +{0x0F12, 0xE8BD}, /* 7000253A */ +{0x0F12, 0xFF1E}, /* 7000253C */ +{0x0F12, 0xE12F}, /* 7000253E */ +{0x0F12, 0x4070}, /* 70002540 */ +{0x0F12, 0xE92D}, /* 70002542 */ +{0x0F12, 0x0000}, /* 70002544 */ +{0x0F12, 0xE590}, /* 70002546 */ +{0x0F12, 0x0800}, /* 70002548 */ +{0x0F12, 0xE1A0}, /* 7000254A */ +{0x0F12, 0x0820}, /* 7000254C */ +{0x0F12, 0xE1A0}, /* 7000254E */ +{0x0F12, 0x4041}, /* 70002550 */ +{0x0F12, 0xE280}, /* 70002552 */ +{0x0F12, 0x01D4}, /* 70002554 */ +{0x0F12, 0xE59F}, /* 70002556 */ +{0x0F12, 0x11B8}, /* 70002558 */ +{0x0F12, 0xE1D0}, /* 7000255A */ +{0x0F12, 0x51B6}, /* 7000255C */ +{0x0F12, 0xE1D0}, /* 7000255E */ +{0x0F12, 0x0005}, /* 70002560 */ +{0x0F12, 0xE041}, /* 70002562 */ +{0x0F12, 0x0094}, /* 70002564 */ +{0x0F12, 0xE000}, /* 70002566 */ +{0x0F12, 0x1D11}, /* 70002568 */ +{0x0F12, 0xE3A0}, /* 7000256A */ +{0x0F12, 0x0082}, /* 7000256C */ +{0x0F12, 0xEB00}, /* 7000256E */ +{0x0F12, 0x11B4}, /* 70002570 */ +{0x0F12, 0xE59F}, /* 70002572 */ +{0x0F12, 0x1000}, /* 70002574 */ +{0x0F12, 0xE5D1}, /* 70002576 */ +{0x0F12, 0x0000}, /* 70002578 */ +{0x0F12, 0xE351}, /* 7000257A */ +{0x0F12, 0x0000}, /* 7000257C */ +{0x0F12, 0x0A00}, /* 7000257E */ +{0x0F12, 0x00A0}, /* 70002580 */ +{0x0F12, 0xE1A0}, /* 70002582 */ +{0x0F12, 0x219C}, /* 70002584 */ +{0x0F12, 0xE59F}, /* 70002586 */ +{0x0F12, 0x3FB0}, /* 70002588 */ +{0x0F12, 0xE1D2}, /* 7000258A */ +{0x0F12, 0x0000}, /* 7000258C */ +{0x0F12, 0xE353}, /* 7000258E */ +{0x0F12, 0x0003}, /* 70002590 */ +{0x0F12, 0x0A00}, /* 70002592 */ +{0x0F12, 0x3198}, /* 70002594 */ +{0x0F12, 0xE59F}, /* 70002596 */ +{0x0F12, 0x5BB2}, /* 70002598 */ +{0x0F12, 0xE1C3}, /* 7000259A */ +{0x0F12, 0xC000}, /* 7000259C */ +{0x0F12, 0xE085}, /* 7000259E */ +{0x0F12, 0xCBB4}, /* 700025A0 */ +{0x0F12, 0xE1C3}, /* 700025A2 */ +{0x0F12, 0x0000}, /* 700025A4 */ +{0x0F12, 0xE351}, /* 700025A6 */ +{0x0F12, 0x0000}, /* 700025A8 */ +{0x0F12, 0x0A00}, /* 700025AA */ +{0x0F12, 0x0080}, /* 700025AC */ +{0x0F12, 0xE1A0}, /* 700025AE */ +{0x0F12, 0x1DBC}, /* 700025B0 */ +{0x0F12, 0xE1D2}, /* 700025B2 */ +{0x0F12, 0x3EB4}, /* 700025B4 */ +{0x0F12, 0xE1D2}, /* 700025B6 */ +{0x0F12, 0x2EB2}, /* 700025B8 */ +{0x0F12, 0xE1D2}, /* 700025BA */ +{0x0F12, 0x0193}, /* 700025BC */ +{0x0F12, 0xE001}, /* 700025BE */ +{0x0F12, 0x0092}, /* 700025C0 */ +{0x0F12, 0xE000}, /* 700025C2 */ +{0x0F12, 0x2811}, /* 700025C4 */ +{0x0F12, 0xE3A0}, /* 700025C6 */ +{0x0F12, 0x0194}, /* 700025C8 */ +{0x0F12, 0xE001}, /* 700025CA */ +{0x0F12, 0x0092}, /* 700025CC */ +{0x0F12, 0xE000}, /* 700025CE */ +{0x0F12, 0x11A1}, /* 700025D0 */ +{0x0F12, 0xE1A0}, /* 700025D2 */ +{0x0F12, 0x01A0}, /* 700025D4 */ +{0x0F12, 0xE1A0}, /* 700025D6 */ +{0x0F12, 0x0067}, /* 700025D8 */ +{0x0F12, 0xEB00}, /* 700025DA */ +{0x0F12, 0x1154}, /* 700025DC */ +{0x0F12, 0xE59F}, /* 700025DE */ +{0x0F12, 0x02B4}, /* 700025E0 */ +{0x0F12, 0xE1C1}, /* 700025E2 */ +{0x0F12, 0x4070}, /* 700025E4 */ +{0x0F12, 0xE8BD}, /* 700025E6 */ +{0x0F12, 0xFF1E}, /* 700025E8 */ +{0x0F12, 0xE12F}, /* 700025EA */ +{0x0F12, 0x4010}, /* 700025EC */ +{0x0F12, 0xE92D}, /* 700025EE */ +{0x0F12, 0x0063}, /* 700025F0 */ +{0x0F12, 0xEB00}, /* 700025F2 */ +{0x0F12, 0x213C}, /* 700025F4 */ +{0x0F12, 0xE59F}, /* 700025F6 */ +{0x0F12, 0x14B0}, /* 700025F8 */ +{0x0F12, 0xE1D2}, /* 700025FA */ +{0x0F12, 0x0080}, /* 700025FC */ +{0x0F12, 0xE311}, /* 700025FE */ +{0x0F12, 0x0005}, /* 70002600 */ +{0x0F12, 0x0A00}, /* 70002602 */ +{0x0F12, 0x0130}, /* 70002604 */ +{0x0F12, 0xE59F}, /* 70002606 */ +{0x0F12, 0x00B0}, /* 70002608 */ +{0x0F12, 0xE1D0}, /* 7000260A */ +{0x0F12, 0x0001}, /* 7000260C */ +{0x0F12, 0xE350}, /* 7000260E */ +{0x0F12, 0x0001}, /* 70002610 */ +{0x0F12, 0x9A00}, /* 70002612 */ +{0x0F12, 0x0001}, /* 70002614 */ +{0x0F12, 0xE3A0}, /* 70002616 */ +{0x0F12, 0x0000}, /* 70002618 */ +{0x0F12, 0xEA00}, /* 7000261A */ +{0x0F12, 0x0000}, /* 7000261C */ +{0x0F12, 0xE3A0}, /* 7000261E */ +{0x0F12, 0x3104}, /* 70002620 */ +{0x0F12, 0xE59F}, /* 70002622 */ +{0x0F12, 0x0000}, /* 70002624 */ +{0x0F12, 0xE5C3}, /* 70002626 */ +{0x0F12, 0x0000}, /* 70002628 */ +{0x0F12, 0xE5D3}, /* 7000262A */ +{0x0F12, 0x0000}, /* 7000262C */ +{0x0F12, 0xE350}, /* 7000262E */ +{0x0F12, 0x0003}, /* 70002630 */ +{0x0F12, 0x0A00}, /* 70002632 */ +{0x0F12, 0x0080}, /* 70002634 */ +{0x0F12, 0xE3C1}, /* 70002636 */ +{0x0F12, 0x1100}, /* 70002638 */ +{0x0F12, 0xE59F}, /* 7000263A */ +{0x0F12, 0x04B0}, /* 7000263C */ +{0x0F12, 0xE1C2}, /* 7000263E */ +{0x0F12, 0x00B2}, /* 70002640 */ +{0x0F12, 0xE1C1}, /* 70002642 */ +{0x0F12, 0x4010}, /* 70002644 */ +{0x0F12, 0xE8BD}, /* 70002646 */ +{0x0F12, 0xFF1E}, /* 70002648 */ +{0x0F12, 0xE12F}, /* 7000264A */ +{0x0F12, 0x41F0}, /* 7000264C */ +{0x0F12, 0xE92D}, /* 7000264E */ +{0x0F12, 0x1000}, /* 70002650 */ +{0x0F12, 0xE590}, /* 70002652 */ +{0x0F12, 0xC801}, /* 70002654 */ +{0x0F12, 0xE1A0}, /* 70002656 */ +{0x0F12, 0xC82C}, /* 70002658 */ +{0x0F12, 0xE1A0}, /* 7000265A */ +{0x0F12, 0x1004}, /* 7000265C */ +{0x0F12, 0xE590}, /* 7000265E */ +{0x0F12, 0x1801}, /* 70002660 */ +{0x0F12, 0xE1A0}, /* 70002662 */ +{0x0F12, 0x1821}, /* 70002664 */ +{0x0F12, 0xE1A0}, /* 70002666 */ +{0x0F12, 0x4008}, /* 70002668 */ +{0x0F12, 0xE590}, /* 7000266A */ +{0x0F12, 0x500C}, /* 7000266C */ +{0x0F12, 0xE590}, /* 7000266E */ +{0x0F12, 0x2004}, /* 70002670 */ +{0x0F12, 0xE1A0}, /* 70002672 */ +{0x0F12, 0x3005}, /* 70002674 */ +{0x0F12, 0xE1A0}, /* 70002676 */ +{0x0F12, 0x000C}, /* 70002678 */ +{0x0F12, 0xE1A0}, /* 7000267A */ +{0x0F12, 0x0043}, /* 7000267C */ +{0x0F12, 0xEB00}, /* 7000267E */ +{0x0F12, 0x60BC}, /* 70002680 */ +{0x0F12, 0xE59F}, /* 70002682 */ +{0x0F12, 0x00B2}, /* 70002684 */ +{0x0F12, 0xE1D6}, /* 70002686 */ +{0x0F12, 0x0000}, /* 70002688 */ +{0x0F12, 0xE350}, /* 7000268A */ +{0x0F12, 0x000E}, /* 7000268C */ +{0x0F12, 0x0A00}, /* 7000268E */ +{0x0F12, 0x00B0}, /* 70002690 */ +{0x0F12, 0xE59F}, /* 70002692 */ +{0x0F12, 0x05B4}, /* 70002694 */ +{0x0F12, 0xE1D0}, /* 70002696 */ +{0x0F12, 0x0002}, /* 70002698 */ +{0x0F12, 0xE350}, /* 7000269A */ +{0x0F12, 0x000A}, /* 7000269C */ +{0x0F12, 0x1A00}, /* 7000269E */ +{0x0F12, 0x70A4}, /* 700026A0 */ +{0x0F12, 0xE59F}, /* 700026A2 */ +{0x0F12, 0x10F4}, /* 700026A4 */ +{0x0F12, 0xE1D6}, /* 700026A6 */ +{0x0F12, 0x26B0}, /* 700026A8 */ +{0x0F12, 0xE1D7}, /* 700026AA */ +{0x0F12, 0x00F0}, /* 700026AC */ +{0x0F12, 0xE1D4}, /* 700026AE */ +{0x0F12, 0x0039}, /* 700026B0 */ +{0x0F12, 0xEB00}, /* 700026B2 */ +{0x0F12, 0x00B0}, /* 700026B4 */ +{0x0F12, 0xE1C4}, /* 700026B6 */ +{0x0F12, 0x26B0}, /* 700026B8 */ +{0x0F12, 0xE1D7}, /* 700026BA */ +{0x0F12, 0x10F6}, /* 700026BC */ +{0x0F12, 0xE1D6}, /* 700026BE */ +{0x0F12, 0x00F0}, /* 700026C0 */ +{0x0F12, 0xE1D5}, /* 700026C2 */ +{0x0F12, 0x0034}, /* 700026C4 */ +{0x0F12, 0xEB00}, /* 700026C6 */ +{0x0F12, 0x00B0}, /* 700026C8 */ +{0x0F12, 0xE1C5}, /* 700026CA */ +{0x0F12, 0x41F0}, /* 700026CC */ +{0x0F12, 0xE8BD}, /* 700026CE */ +{0x0F12, 0xFF1E}, /* 700026D0 */ +{0x0F12, 0xE12F}, /* 700026D2 */ +{0x0F12, 0x4010}, /* 700026D4 */ +{0x0F12, 0xE92D}, /* 700026D6 */ +{0x0F12, 0x4000}, /* 700026D8 */ +{0x0F12, 0xE1A0}, /* 700026DA */ +{0x0F12, 0x1004}, /* 700026DC */ +{0x0F12, 0xE594}, /* 700026DE */ +{0x0F12, 0x005C}, /* 700026E0 */ +{0x0F12, 0xE59F}, /* 700026E2 */ +{0x0F12, 0x00B0}, /* 700026E4 */ +{0x0F12, 0xE1D0}, /* 700026E6 */ +{0x0F12, 0x0000}, /* 700026E8 */ +{0x0F12, 0xE350}, /* 700026EA */ +{0x0F12, 0x0008}, /* 700026EC */ +{0x0F12, 0x0A00}, /* 700026EE */ +{0x0F12, 0x0054}, /* 700026F0 */ +{0x0F12, 0xE59F}, /* 700026F2 */ +{0x0F12, 0x3001}, /* 700026F4 */ +{0x0F12, 0xE1A0}, /* 700026F6 */ +{0x0F12, 0x2068}, /* 700026F8 */ +{0x0F12, 0xE590}, /* 700026FA */ +{0x0F12, 0x004C}, /* 700026FC */ +{0x0F12, 0xE59F}, /* 700026FE */ +{0x0F12, 0x1005}, /* 70002700 */ +{0x0F12, 0xE3A0}, /* 70002702 */ +{0x0F12, 0x0027}, /* 70002704 */ +{0x0F12, 0xEB00}, /* 70002706 */ +{0x0F12, 0x0000}, /* 70002708 */ +{0x0F12, 0xE584}, /* 7000270A */ +{0x0F12, 0x4010}, /* 7000270C */ +{0x0F12, 0xE8BD}, /* 7000270E */ +{0x0F12, 0xFF1E}, /* 70002710 */ +{0x0F12, 0xE12F}, /* 70002712 */ +{0x0F12, 0x0000}, /* 70002714 */ +{0x0F12, 0xE594}, /* 70002716 */ +{0x0F12, 0x0025}, /* 70002718 */ +{0x0F12, 0xEB00}, /* 7000271A */ +{0x0F12, 0x0000}, /* 7000271C */ +{0x0F12, 0xE584}, /* 7000271E */ +{0x0F12, 0xFFF9}, /* 70002720 */ +{0x0F12, 0xEAFF}, /* 70002722 */ +{0x0F12, 0x1728}, /* 70002724 */ +{0x0F12, 0x7000}, /* 70002726 */ +{0x0F12, 0x112C}, /* 70002728 */ +{0x0F12, 0x7000}, /* 7000272A */ +{0x0F12, 0x27C4}, /* 7000272C */ +{0x0F12, 0x7000}, /* 7000272E */ +{0x0F12, 0x122C}, /* 70002730 */ +{0x0F12, 0x7000}, /* 70002732 */ +{0x0F12, 0xF200}, /* 70002734 */ +{0x0F12, 0xD000}, /* 70002736 */ +{0x0F12, 0x2340}, /* 70002738 */ +{0x0F12, 0x7000}, /* 7000273A */ +{0x0F12, 0x0E2C}, /* 7000273C */ +{0x0F12, 0x7000}, /* 7000273E */ +{0x0F12, 0xF400}, /* 70002740 */ +{0x0F12, 0xD000}, /* 70002742 */ +{0x0F12, 0x3370}, /* 70002744 */ +{0x0F12, 0x7000}, /* 70002746 */ +{0x0F12, 0x0CDC}, /* 70002748 */ +{0x0F12, 0x7000}, /* 7000274A */ +{0x0F12, 0x20D4}, /* 7000274C */ +{0x0F12, 0x7000}, /* 7000274E */ +{0x0F12, 0x06D4}, /* 70002750 */ +{0x0F12, 0x7000}, /* 70002752 */ +{0x0F12, 0x4778}, /* 70002754 */ +{0x0F12, 0x46C0}, /* 70002756 */ +{0x0F12, 0xC000}, /* 70002758 */ +{0x0F12, 0xE59F}, /* 7000275A */ +{0x0F12, 0xFF1C}, /* 7000275C */ +{0x0F12, 0xE12F}, /* 7000275E */ +{0x0F12, 0xC091}, /* 70002760 */ +{0x0F12, 0x0000}, /* 70002762 */ +{0x0F12, 0xC000}, /* 70002764 */ +{0x0F12, 0xE59F}, /* 70002766 */ +{0x0F12, 0xFF1C}, /* 70002768 */ +{0x0F12, 0xE12F}, /* 7000276A */ +{0x0F12, 0x058F}, /* 7000276C */ +{0x0F12, 0x0000}, /* 7000276E */ +{0x0F12, 0xC000}, /* 70002770 */ +{0x0F12, 0xE59F}, /* 70002772 */ +{0x0F12, 0xFF1C}, /* 70002774 */ +{0x0F12, 0xE12F}, /* 70002776 */ +{0x0F12, 0xA0F1}, /* 70002778 */ +{0x0F12, 0x0000}, /* 7000277A */ +{0x0F12, 0xF004}, /* 7000277C */ +{0x0F12, 0xE51F}, /* 7000277E */ +{0x0F12, 0xD14C}, /* 70002780 */ +{0x0F12, 0x0000}, /* 70002782 */ +{0x0F12, 0xC000}, /* 70002784 */ +{0x0F12, 0xE59F}, /* 70002786 */ +{0x0F12, 0xFF1C}, /* 70002788 */ +{0x0F12, 0xE12F}, /* 7000278A */ +{0x0F12, 0x2B43}, /* 7000278C */ +{0x0F12, 0x0000}, /* 7000278E */ +{0x0F12, 0xC000}, /* 70002790 */ +{0x0F12, 0xE59F}, /* 70002792 */ +{0x0F12, 0xFF1C}, /* 70002794 */ +{0x0F12, 0xE12F}, /* 70002796 */ +{0x0F12, 0x8725}, /* 70002798 */ +{0x0F12, 0x0000}, /* 7000279A */ +{0x0F12, 0xC000}, /* 7000279C */ +{0x0F12, 0xE59F}, /* 7000279E */ +{0x0F12, 0xFF1C}, /* 700027A0 */ +{0x0F12, 0xE12F}, /* 700027A2 */ +{0x0F12, 0x6777}, /* 700027A4 */ +{0x0F12, 0x0000}, /* 700027A6 */ +{0x0F12, 0xC000}, /* 700027A8 */ +{0x0F12, 0xE59F}, /* 700027AA */ +{0x0F12, 0xFF1C}, /* 700027AC */ +{0x0F12, 0xE12F}, /* 700027AE */ +{0x0F12, 0x8E49}, /* 700027B0 */ +{0x0F12, 0x0000}, /* 700027B2 */ +{0x0F12, 0xC000}, /* 700027B4 */ +{0x0F12, 0xE59F}, /* 700027B6 */ +{0x0F12, 0xFF1C}, /* 700027B8 */ +{0x0F12, 0xE12F}, /* 700027BA */ +{0x0F12, 0x8EDD}, /* 700027BC */ +{0x0F12, 0x0000}, /* 700027BE */ +{0x0F12, 0x90C8}, /* 700027C0 */ +{0x0F12, 0x0000}, /* 700027C2 */ +/* End of Patch Data(Last : 700027C2h) */ +/* Total Size 852 (0x0354) */ +/* Addr : 2470 , Size : 850(352h) */ + +/**************************************/ +/* 05.OTP Control */ +/**************************************/ + +/**************************************/ +/* 06.GAS (Grid Anti-Shading) */ +/**************************************/ +{0x002A, 0x1326}, +{0x0F12, 0x0000}, /* gisp_gos_Enable */ +{0x002A, 0x063A}, +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__0_ Horizon */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__3_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__0_ IncandA */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__3_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__0_ WW */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__3_ */ +{0x0F12, 0x00E8}, /* TVAR_ash_GASAlpha_3__0_ CW */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__3_ */ +{0x0F12, 0x00E8}, /* TVAR_ash_GASAlpha_4__0_ D50 */ +{0x0F12, 0x00F8}, /* TVAR_ash_GASAlpha_4__1_ */ +{0x0F12, 0x00F8}, /* TVAR_ash_GASAlpha_4__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_4__3_ */ +{0x0F12, 0x00F0}, /* TVAR_ash_GASAlpha_5__0_ D65 */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__3_ */ +{0x0F12, 0x00F0}, /* TVAR_ash_GASAlpha_6__0_ D75 */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__3_ */ +{0x002A, 0x067A}, +{0x0F12, 0x0000}, /* ash_GASBeta_0__0_ Horizon */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__0_ IncandA */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__0_ WW */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__0_ CW */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__0_ D50 */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__0_ D65 */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__0_ D75 */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__3_ */ +{0x002A, 0x06BA}, +{0x0F12, 0x0001}, /*ash_bLumaMode */ +{0x002A, 0x0632}, +{0x0F12, 0x0100}, /* ash_CGrasAlphas_0_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_1_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_2_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_3_ */ +{0x002A, 0x0672}, +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_0_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_3_ */ +{0x002A, 0x06B2}, +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_0_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_1_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_2_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_3_ */ +{0x002A, 0x06D0}, +{0x0F12, 0x000D}, /* ash_uParabolicScalingA */ +{0x0F12, 0x000F}, /* ash_uParabolicScalingB */ +{0x002A, 0x06CC}, +{0x0F12, 0x0280}, /* ash_uParabolicCenterX */ +{0x0F12, 0x01E0}, /* ash_uParabolicCenterY */ +{0x002A, 0x06C6}, +{0x0F12, 0x0001}, /* ash_bParabolicEstimation */ +{0x002A, 0x0624}, +{0x0F12, 0x009D}, /* TVAR_ash_AwbAshCord_0_ Horizon */ +{0x0F12, 0x00D5}, /* TVAR_ash_AwbAshCord_1_ IncandA */ +{0x0F12, 0x0103}, /* TVAR_ash_AwbAshCord_2_ WW */ +{0x0F12, 0x0128}, /* TVAR_ash_AwbAshCord_3_ CW */ +{0x0F12, 0x0166}, /* TVAR_ash_AwbAshCord_4_ D50 */ +{0x0F12, 0x0193}, /* TVAR_ash_AwbAshCord_5_ D65 */ +{0x0F12, 0x01A0}, /* TVAR_ash_AwbAshCord_6_ D75 */ +{0x002A, 0x347C}, +{0x0F12, 0x013B}, /* 011A 012F Tune_wbt_GAS_0_ */ +{0x0F12, 0x0116}, /* 011A 0111 Tune_wbt_GAS_1_ */ +{0x0F12, 0x00D9}, /* 00EE 00D6 Tune_wbt_GAS_2_ */ +{0x0F12, 0x00A6}, /* 00C1 009E Tune_wbt_GAS_3_ */ +{0x0F12, 0x0082}, /* 009E 007A Tune_wbt_GAS_4_ */ +{0x0F12, 0x006C}, /* 008A 0064 Tune_wbt_GAS_5_ */ +{0x0F12, 0x0065}, /* 0083 005D Tune_wbt_GAS_6_ */ +{0x0F12, 0x006C}, /* 008A 0063 Tune_wbt_GAS_7_ */ +{0x0F12, 0x0080}, /* 009E 007B Tune_wbt_GAS_8_ */ +{0x0F12, 0x00A3}, /* 00BF 00A3 Tune_wbt_GAS_9_ */ +{0x0F12, 0x00D4}, /* 00E5 00E3 Tune_wbt_GAS_10_ */ +{0x0F12, 0x010D}, /* 00F9 013B Tune_wbt_GAS_11_ */ +{0x0F12, 0x012E}, /* 0124 018B Tune_wbt_GAS_12_ */ +{0x0F12, 0x0138}, /* 0126 012B Tune_wbt_GAS_13_ */ +{0x0F12, 0x0104}, /* 010E 00F6 Tune_wbt_GAS_14_ */ +{0x0F12, 0x00BE}, /* 00D3 00B2 Tune_wbt_GAS_15_ */ +{0x0F12, 0x0088}, /* 009F 007B Tune_wbt_GAS_16_ */ +{0x0F12, 0x0062}, /* 007C 0057 Tune_wbt_GAS_17_ */ +{0x0F12, 0x004D}, /* 0068 0042 Tune_wbt_GAS_18_ */ +{0x0F12, 0x0046}, /* 0061 0039 Tune_wbt_GAS_19_ */ +{0x0F12, 0x004C}, /* 0068 003F Tune_wbt_GAS_20_ */ +{0x0F12, 0x0060}, /* 007E 0053 Tune_wbt_GAS_21_ */ +{0x0F12, 0x0084}, /* 00A3 007A Tune_wbt_GAS_22_ */ +{0x0F12, 0x00B8}, /* 00C9 00B6 Tune_wbt_GAS_23_ */ +{0x0F12, 0x00F9}, /* 00F0 0110 Tune_wbt_GAS_24_ */ +{0x0F12, 0x012C}, /* 0131 016A Tune_wbt_GAS_25_ */ +{0x0F12, 0x011A}, /* 011C 0114 Tune_wbt_GAS_26_ */ +{0x0F12, 0x00DB}, /* 00EB 00D4 Tune_wbt_GAS_27_ */ +{0x0F12, 0x0093}, /* 00AA 008F Tune_wbt_GAS_28_ */ +{0x0F12, 0x005F}, /* 0075 005A Tune_wbt_GAS_29_ */ +{0x0F12, 0x003C}, /* 0053 0035 Tune_wbt_GAS_30_ */ +{0x0F12, 0x0027}, /* 003F 0020 Tune_wbt_GAS_31_ */ +{0x0F12, 0x0020}, /* 0038 0019 Tune_wbt_GAS_32_ */ +{0x0F12, 0x0026}, /* 0040 001F Tune_wbt_GAS_33_ */ +{0x0F12, 0x003A}, /* 0055 0032 Tune_wbt_GAS_34_ */ +{0x0F12, 0x005C}, /* 007A 0056 Tune_wbt_GAS_35_ */ +{0x0F12, 0x008E}, /* 00A6 008E Tune_wbt_GAS_36_ */ +{0x0F12, 0x00D2}, /* 00D5 00E6 Tune_wbt_GAS_37_ */ +{0x0F12, 0x010E}, /* 0126 0142 Tune_wbt_GAS_38_ */ +{0x0F12, 0x0101}, /* 00F6 0102 Tune_wbt_GAS_39_ */ +{0x0F12, 0x00BF}, /* 00C0 00BE Tune_wbt_GAS_40_ */ +{0x0F12, 0x0077}, /* 007D 0077 Tune_wbt_GAS_41_ */ +{0x0F12, 0x0044}, /* 004D 0045 Tune_wbt_GAS_42_ */ +{0x0F12, 0x0023}, /* 002C 0022 Tune_wbt_GAS_43_ */ +{0x0F12, 0x0011}, /* 001B 000D Tune_wbt_GAS_44_ */ +{0x0F12, 0x000C}, /* 0017 0006 Tune_wbt_GAS_45_ */ +{0x0F12, 0x0010}, /* 001B 000A Tune_wbt_GAS_46_ */ +{0x0F12, 0x0022}, /* 002D 001D Tune_wbt_GAS_47_ */ +{0x0F12, 0x0043}, /* 004E 003F Tune_wbt_GAS_48_ */ +{0x0F12, 0x0074}, /* 0080 0075 Tune_wbt_GAS_49_ */ +{0x0F12, 0x00B7}, /* 00C1 00CC Tune_wbt_GAS_50_ */ +{0x0F12, 0x00F7}, /* 00FF 0126 Tune_wbt_GAS_51_ */ +{0x0F12, 0x00FC}, /* 00EA 00FB Tune_wbt_GAS_52_ */ +{0x0F12, 0x00B7}, /* 00B0 00B7 Tune_wbt_GAS_53_ */ +{0x0F12, 0x006F}, /* 006D 0070 Tune_wbt_GAS_54_ */ +{0x0F12, 0x003C}, /* 003D 003D Tune_wbt_GAS_55_ */ +{0x0F12, 0x001C}, /* 001E 001B Tune_wbt_GAS_56_ */ +{0x0F12, 0x000A}, /* 000F 0007 Tune_wbt_GAS_57_ */ +{0x0F12, 0x0004}, /* 000A 0000 Tune_wbt_GAS_58_ */ +{0x0F12, 0x000A}, /* 0010 0004 Tune_wbt_GAS_59_ */ +{0x0F12, 0x001B}, /* 001E 0015 Tune_wbt_GAS_60_ */ +{0x0F12, 0x003B}, /* 003E 0034 Tune_wbt_GAS_61_ */ +{0x0F12, 0x006C}, /* 006F 006A Tune_wbt_GAS_62_ */ +{0x0F12, 0x00B0}, /* 00B2 00C0 Tune_wbt_GAS_63_ */ +{0x0F12, 0x00F2}, /* 00F1 011B Tune_wbt_GAS_64_ */ +{0x0F12, 0x00EF}, /* 00E0 0102 Tune_wbt_GAS_65_ */ +{0x0F12, 0x00AB}, /* 00A6 00BA Tune_wbt_GAS_66_ */ +{0x0F12, 0x0065}, /* 0063 0073 Tune_wbt_GAS_67_ */ +{0x0F12, 0x0034}, /* 0033 0040 Tune_wbt_GAS_68_ */ +{0x0F12, 0x0015}, /* 0016 001D Tune_wbt_GAS_69_ */ +{0x0F12, 0x0004}, /* 0008 0009 Tune_wbt_GAS_70_ */ +{0x0F12, 0x0000}, /* 0003 0001 Tune_wbt_GAS_71_ */ +{0x0F12, 0x0004}, /* 0009 0006 Tune_wbt_GAS_72_ */ +{0x0F12, 0x0013}, /* 0016 0017 Tune_wbt_GAS_73_ */ +{0x0F12, 0x0033}, /* 0035 0039 Tune_wbt_GAS_74_ */ +{0x0F12, 0x0063}, /* 0066 006F Tune_wbt_GAS_75_ */ +{0x0F12, 0x00A5}, /* 00A7 00C8 Tune_wbt_GAS_76_ */ +{0x0F12, 0x00E5}, /* 00E9 011E Tune_wbt_GAS_77_ */ +{0x0F12, 0x00F7}, /* 00D5 0111 Tune_wbt_GAS_78_ */ +{0x0F12, 0x00B4}, /* 009D 00C8 Tune_wbt_GAS_79_ */ +{0x0F12, 0x006D}, /* 005D 0081 Tune_wbt_GAS_80_ */ +{0x0F12, 0x003C}, /* 002F 004D Tune_wbt_GAS_81_ */ +{0x0F12, 0x001C}, /* 0010 0028 Tune_wbt_GAS_82_ */ +{0x0F12, 0x000B}, /* 0004 0014 Tune_wbt_GAS_83_ */ +{0x0F12, 0x0005}, /* 0001 000B Tune_wbt_GAS_84_ */ +{0x0F12, 0x000A}, /* 0005 0010 Tune_wbt_GAS_85_ */ +{0x0F12, 0x001B}, /* 0013 0022 Tune_wbt_GAS_86_ */ +{0x0F12, 0x003B}, /* 0031 0047 Tune_wbt_GAS_87_ */ +{0x0F12, 0x006B}, /* 005F 007E Tune_wbt_GAS_88_ */ +{0x0F12, 0x00AD}, /* 00A1 00D8 Tune_wbt_GAS_89_ */ +{0x0F12, 0x00ED}, /* 00DF 0131 Tune_wbt_GAS_90_ */ +{0x0F12, 0x010B}, /* 00E9 0129 Tune_wbt_GAS_91_ */ +{0x0F12, 0x00CB}, /* 00B2 00E4 Tune_wbt_GAS_92_ */ +{0x0F12, 0x0085}, /* 006F 009E Tune_wbt_GAS_93_ */ +{0x0F12, 0x0051}, /* 003F 0068 Tune_wbt_GAS_94_ */ +{0x0F12, 0x002F}, /* 0020 0041 Tune_wbt_GAS_95_ */ +{0x0F12, 0x001C}, /* 000F 002B Tune_wbt_GAS_96_ */ +{0x0F12, 0x0016}, /* 000B 0023 Tune_wbt_GAS_97_ */ +{0x0F12, 0x001C}, /* 0010 0028 Tune_wbt_GAS_98_ */ +{0x0F12, 0x002E}, /* 0021 003B Tune_wbt_GAS_99_ */ +{0x0F12, 0x004F}, /* 0041 0063 Tune_wbt_GAS_100_ */ +{0x0F12, 0x0081}, /* 0071 00A0 Tune_wbt_GAS_101_ */ +{0x0F12, 0x00C4}, /* 00B4 00FD Tune_wbt_GAS_102_ */ +{0x0F12, 0x0102}, /* 00F6 015A Tune_wbt_GAS_103_ */ +{0x0F12, 0x0119}, /* 00F9 014A Tune_wbt_GAS_104_ */ +{0x0F12, 0x00DF}, /* 00C2 010D Tune_wbt_GAS_105_ */ +{0x0F12, 0x009B}, /* 0082 00CA Tune_wbt_GAS_106_ */ +{0x0F12, 0x0067}, /* 0053 008F Tune_wbt_GAS_107_ */ +{0x0F12, 0x0045}, /* 0033 0066 Tune_wbt_GAS_108_ */ +{0x0F12, 0x0030}, /* 0021 004F Tune_wbt_GAS_109_ */ +{0x0F12, 0x0029}, /* 001C 0048 Tune_wbt_GAS_110_ */ +{0x0F12, 0x002F}, /* 0022 004E Tune_wbt_GAS_111_ */ +{0x0F12, 0x0043}, /* 0035 0067 Tune_wbt_GAS_112_ */ +{0x0F12, 0x0066}, /* 0056 008F Tune_wbt_GAS_113_ */ +{0x0F12, 0x0098}, /* 0087 00D1 Tune_wbt_GAS_114_ */ +{0x0F12, 0x00D9}, /* 00CA 0132 Tune_wbt_GAS_115_ */ +{0x0F12, 0x010F}, /* 0107 018D Tune_wbt_GAS_116_ */ +{0x0F12, 0x0138}, /* 0108 0159 Tune_wbt_GAS_117_ */ +{0x0F12, 0x010C}, /* 00E0 0141 Tune_wbt_GAS_118_ */ +{0x0F12, 0x00CB}, /* 00A2 0103 Tune_wbt_GAS_119_ */ +{0x0F12, 0x0097}, /* 0072 00C9 Tune_wbt_GAS_120_ */ +{0x0F12, 0x0073}, /* 0052 009E Tune_wbt_GAS_121_ */ +{0x0F12, 0x005C}, /* 0040 0087 Tune_wbt_GAS_122_ */ +{0x0F12, 0x0054}, /* 003A 007D Tune_wbt_GAS_123_ */ +{0x0F12, 0x005B}, /* 0041 0087 Tune_wbt_GAS_124_ */ +{0x0F12, 0x0070}, /* 0055 00A2 Tune_wbt_GAS_125_ */ +{0x0F12, 0x0096}, /* 0077 00D4 Tune_wbt_GAS_126_ */ +{0x0F12, 0x00C9}, /* 00A8 011A Tune_wbt_GAS_127_ */ +{0x0F12, 0x0106}, /* 00E7 017D Tune_wbt_GAS_128_ */ +{0x0F12, 0x012D}, /* 011E 01CF Tune_wbt_GAS_129_ */ +{0x0F12, 0x0147}, /* 0123 0181 Tune_wbt_GAS_130_ */ +{0x0F12, 0x012F}, /* 0100 0169 Tune_wbt_GAS_131_ */ +{0x0F12, 0x00F8}, /* 00CB 0140 Tune_wbt_GAS_132_ */ +{0x0F12, 0x00C5}, /* 009A 0106 Tune_wbt_GAS_133_ */ +{0x0F12, 0x00A1}, /* 0079 00DD Tune_wbt_GAS_134_ */ +{0x0F12, 0x008B}, /* 0067 00C5 Tune_wbt_GAS_135_ */ +{0x0F12, 0x0083}, /* 0060 00BE Tune_wbt_GAS_136_ */ +{0x0F12, 0x008B}, /* 0068 00C8 Tune_wbt_GAS_137_ */ +{0x0F12, 0x00A0}, /* 007B 00E6 Tune_wbt_GAS_138_ */ +{0x0F12, 0x00C2}, /* 009D 011B Tune_wbt_GAS_139_ */ +{0x0F12, 0x00F3}, /* 00CD 015F Tune_wbt_GAS_140_ */ +{0x0F12, 0x0124}, /* 0108 01BC Tune_wbt_GAS_141_ */ +{0x0F12, 0x0139}, /* 0131 0206 Tune_wbt_GAS_142_ */ +{0x0F12, 0x0093}, /* 006C 00A8 Tune_wbt_GAS_143_ */ +{0x0F12, 0x007E}, /* 006E 008F Tune_wbt_GAS_144_ */ +{0x0F12, 0x0062}, /* 005D 006F Tune_wbt_GAS_145_ */ +{0x0F12, 0x004D}, /* 004C 0054 Tune_wbt_GAS_146_ */ +{0x0F12, 0x003E}, /* 0040 0041 Tune_wbt_GAS_147_ */ +{0x0F12, 0x0034}, /* 0037 0036 Tune_wbt_GAS_148_ */ +{0x0F12, 0x0030}, /* 0035 0033 Tune_wbt_GAS_149_ */ +{0x0F12, 0x0032}, /* 0036 0037 Tune_wbt_GAS_150_ */ +{0x0F12, 0x003B}, /* 003F 0045 Tune_wbt_GAS_151_ */ +{0x0F12, 0x0049}, /* 004B 005A Tune_wbt_GAS_152_ */ +{0x0F12, 0x005C}, /* 0053 007A Tune_wbt_GAS_153_ */ +{0x0F12, 0x0077}, /* 0053 00AA Tune_wbt_GAS_154_ */ +{0x0F12, 0x008A}, /* 0070 00E2 Tune_wbt_GAS_155_ */ +{0x0F12, 0x0093}, /* 0075 009E Tune_wbt_GAS_156_ */ +{0x0F12, 0x0077}, /* 006D 007D Tune_wbt_GAS_157_ */ +{0x0F12, 0x0059}, /* 0056 005A Tune_wbt_GAS_158_ */ +{0x0F12, 0x0042}, /* 0043 0041 Tune_wbt_GAS_159_ */ +{0x0F12, 0x0032}, /* 0037 002E Tune_wbt_GAS_160_ */ +{0x0F12, 0x0027}, /* 002F 0022 Tune_wbt_GAS_161_ */ +{0x0F12, 0x0024}, /* 002C 001F Tune_wbt_GAS_162_ */ +{0x0F12, 0x0026}, /* 002F 0022 Tune_wbt_GAS_163_ */ +{0x0F12, 0x002F}, /* 0038 0030 Tune_wbt_GAS_164_ */ +{0x0F12, 0x003D}, /* 0045 0044 Tune_wbt_GAS_165_ */ +{0x0F12, 0x0052}, /* 004E 0063 Tune_wbt_GAS_166_ */ +{0x0F12, 0x006E}, /* 0055 0091 Tune_wbt_GAS_167_ */ +{0x0F12, 0x008B}, /* 007F 00CB Tune_wbt_GAS_168_ */ +{0x0F12, 0x0083}, /* 0077 0093 Tune_wbt_GAS_169_ */ +{0x0F12, 0x0064}, /* 0062 006D Tune_wbt_GAS_170_ */ +{0x0F12, 0x0046}, /* 004A 004A Tune_wbt_GAS_171_ */ +{0x0F12, 0x0030}, /* 0037 0031 Tune_wbt_GAS_172_ */ +{0x0F12, 0x0020}, /* 002A 001E Tune_wbt_GAS_173_ */ +{0x0F12, 0x0016}, /* 0021 0013 Tune_wbt_GAS_174_ */ +{0x0F12, 0x0011}, /* 001E 000F Tune_wbt_GAS_175_ */ +{0x0F12, 0x0014}, /* 0021 0013 Tune_wbt_GAS_176_ */ +{0x0F12, 0x001E}, /* 002B 001F Tune_wbt_GAS_177_ */ +{0x0F12, 0x002D}, /* 003B 0034 Tune_wbt_GAS_178_ */ +{0x0F12, 0x0041}, /* 0046 0051 Tune_wbt_GAS_179_ */ +{0x0F12, 0x005D}, /* 0051 007C Tune_wbt_GAS_180_ */ +{0x0F12, 0x007C}, /* 007F 00B7 Tune_wbt_GAS_181_ */ +{0x0F12, 0x0077}, /* 0062 008A Tune_wbt_GAS_182_ */ +{0x0F12, 0x0057}, /* 004B 0061 Tune_wbt_GAS_183_ */ +{0x0F12, 0x0039}, /* 0034 003E Tune_wbt_GAS_184_ */ +{0x0F12, 0x0024}, /* 0022 0026 Tune_wbt_GAS_185_ */ +{0x0F12, 0x0014}, /* 0014 0013 Tune_wbt_GAS_186_ */ +{0x0F12, 0x000A}, /* 000E 0008 Tune_wbt_GAS_187_ */ +{0x0F12, 0x0007}, /* 000C 0004 Tune_wbt_GAS_188_ */ +{0x0F12, 0x0009}, /* 000D 0007 Tune_wbt_GAS_189_ */ +{0x0F12, 0x0012}, /* 0016 0013 Tune_wbt_GAS_190_ */ +{0x0F12, 0x0021}, /* 0024 0027 Tune_wbt_GAS_191_ */ +{0x0F12, 0x0036}, /* 0036 0045 Tune_wbt_GAS_192_ */ +{0x0F12, 0x0051}, /* 004E 0070 Tune_wbt_GAS_193_ */ +{0x0F12, 0x0070}, /* 0069 00A7 Tune_wbt_GAS_194_ */ +{0x0F12, 0x0077}, /* 005F 0085 Tune_wbt_GAS_195_ */ +{0x0F12, 0x0056}, /* 0048 005D Tune_wbt_GAS_196_ */ +{0x0F12, 0x0038}, /* 002F 003A Tune_wbt_GAS_197_ */ +{0x0F12, 0x0022}, /* 001C 0021 Tune_wbt_GAS_198_ */ +{0x0F12, 0x0013}, /* 0010 0010 Tune_wbt_GAS_199_ */ +{0x0F12, 0x0009}, /* 000B 0004 Tune_wbt_GAS_200_ */ +{0x0F12, 0x0005}, /* 0008 0000 Tune_wbt_GAS_201_ */ +{0x0F12, 0x0008}, /* 000B 0003 Tune_wbt_GAS_202_ */ +{0x0F12, 0x0011}, /* 0010 000E Tune_wbt_GAS_203_ */ +{0x0F12, 0x0020}, /* 001E 0021 Tune_wbt_GAS_204_ */ +{0x0F12, 0x0035}, /* 0031 003F Tune_wbt_GAS_205_ */ +{0x0F12, 0x0051}, /* 0049 006B Tune_wbt_GAS_206_ */ +{0x0F12, 0x0071}, /* 0066 00A1 Tune_wbt_GAS_207_ */ +{0x0F12, 0x006E}, /* 005B 0089 Tune_wbt_GAS_208_ */ +{0x0F12, 0x004E}, /* 0043 0060 Tune_wbt_GAS_209_ */ +{0x0F12, 0x0032}, /* 002B 003D Tune_wbt_GAS_210_ */ +{0x0F12, 0x001C}, /* 0019 0023 Tune_wbt_GAS_211_ */ +{0x0F12, 0x000D}, /* 000C 0012 Tune_wbt_GAS_212_ */ +{0x0F12, 0x0004}, /* 0007 0006 Tune_wbt_GAS_213_ */ +{0x0F12, 0x0000}, /* 0004 0002 Tune_wbt_GAS_214_ */ +{0x0F12, 0x0003}, /* 0007 0005 Tune_wbt_GAS_215_ */ +{0x0F12, 0x000B}, /* 000D 0011 Tune_wbt_GAS_216_ */ +{0x0F12, 0x001A}, /* 001B 0025 Tune_wbt_GAS_217_ */ +{0x0F12, 0x002F}, /* 002E 0043 Tune_wbt_GAS_218_ */ +{0x0F12, 0x0049}, /* 0046 0070 Tune_wbt_GAS_219_ */ +{0x0F12, 0x0068}, /* 0062 00A4 Tune_wbt_GAS_220_ */ +{0x0F12, 0x0072}, /* 0052 0091 Tune_wbt_GAS_221_ */ +{0x0F12, 0x0053}, /* 003D 0067 Tune_wbt_GAS_222_ */ +{0x0F12, 0x0037}, /* 0026 0044 Tune_wbt_GAS_223_ */ +{0x0F12, 0x0021}, /* 0014 002B Tune_wbt_GAS_224_ */ +{0x0F12, 0x0012}, /* 0007 0019 Tune_wbt_GAS_225_ */ +{0x0F12, 0x0009}, /* 0002 000D Tune_wbt_GAS_226_ */ +{0x0F12, 0x0005}, /* 0001 0009 Tune_wbt_GAS_227_ */ +{0x0F12, 0x0008}, /* 0002 000C Tune_wbt_GAS_228_ */ +{0x0F12, 0x0010}, /* 0007 0018 Tune_wbt_GAS_229_ */ +{0x0F12, 0x001F}, /* 0015 002D Tune_wbt_GAS_230_ */ +{0x0F12, 0x0034}, /* 0028 004B Tune_wbt_GAS_231_ */ +{0x0F12, 0x004E}, /* 0040 007B Tune_wbt_GAS_232_ */ +{0x0F12, 0x006C}, /* 005C 00B0 Tune_wbt_GAS_233_ */ +{0x0F12, 0x007F}, /* 005E 00A1 Tune_wbt_GAS_234_ */ +{0x0F12, 0x0060}, /* 0049 0077 Tune_wbt_GAS_235_ */ +{0x0F12, 0x0043}, /* 0030 0054 Tune_wbt_GAS_236_ */ +{0x0F12, 0x002D}, /* 001E 003B Tune_wbt_GAS_237_ */ +{0x0F12, 0x001D}, /* 0010 0029 Tune_wbt_GAS_238_ */ +{0x0F12, 0x0013}, /* 0009 001C Tune_wbt_GAS_239_ */ +{0x0F12, 0x0010}, /* 0007 0018 Tune_wbt_GAS_240_ */ +{0x0F12, 0x0013}, /* 0009 001B Tune_wbt_GAS_241_ */ +{0x0F12, 0x001C}, /* 0012 0029 Tune_wbt_GAS_242_ */ +{0x0F12, 0x002B}, /* 0020 003F Tune_wbt_GAS_243_ */ +{0x0F12, 0x0040}, /* 0032 005F Tune_wbt_GAS_244_ */ +{0x0F12, 0x005A}, /* 004B 008F Tune_wbt_GAS_245_ */ +{0x0F12, 0x0079}, /* 0069 00C6 Tune_wbt_GAS_246_ */ +{0x0F12, 0x0082}, /* 0066 00B1 Tune_wbt_GAS_247_ */ +{0x0F12, 0x0066}, /* 004E 008E Tune_wbt_GAS_248_ */ +{0x0F12, 0x0049}, /* 0037 006D Tune_wbt_GAS_249_ */ +{0x0F12, 0x0035}, /* 0026 0050 Tune_wbt_GAS_250_ */ +{0x0F12, 0x0025}, /* 0019 003D Tune_wbt_GAS_251_ */ +{0x0F12, 0x001B}, /* 0011 0031 Tune_wbt_GAS_252_ */ +{0x0F12, 0x0017}, /* 000F 002F Tune_wbt_GAS_253_ */ +{0x0F12, 0x0019}, /* 0012 0032 Tune_wbt_GAS_254_ */ +{0x0F12, 0x0023}, /* 001B 0042 Tune_wbt_GAS_255_ */ +{0x0F12, 0x0033}, /* 0028 0058 Tune_wbt_GAS_256_ */ +{0x0F12, 0x0046}, /* 003B 007A Tune_wbt_GAS_257_ */ +{0x0F12, 0x0060}, /* 0054 00AC Tune_wbt_GAS_258_ */ +{0x0F12, 0x007B}, /* 0072 00E5 Tune_wbt_GAS_259_ */ +{0x0F12, 0x0092}, /* 006A 00BD Tune_wbt_GAS_260_ */ +{0x0F12, 0x007C}, /* 0058 00AA Tune_wbt_GAS_261_ */ +{0x0F12, 0x0060}, /* 0041 008B Tune_wbt_GAS_262_ */ +{0x0F12, 0x004B}, /* 0030 006E Tune_wbt_GAS_263_ */ +{0x0F12, 0x003C}, /* 0025 005A Tune_wbt_GAS_264_ */ +{0x0F12, 0x0032}, /* 001E 004F Tune_wbt_GAS_265_ */ +{0x0F12, 0x002D}, /* 001B 004B Tune_wbt_GAS_266_ */ +{0x0F12, 0x0030}, /* 001F 0052 Tune_wbt_GAS_267_ */ +{0x0F12, 0x0039}, /* 0027 0062 Tune_wbt_GAS_268_ */ +{0x0F12, 0x0049}, /* 0034 007D Tune_wbt_GAS_269_ */ +{0x0F12, 0x005D}, /* 0046 00A2 Tune_wbt_GAS_270_ */ +{0x0F12, 0x0076}, /* 005D 00D6 Tune_wbt_GAS_271_ */ +{0x0F12, 0x008C}, /* 0078 010C Tune_wbt_GAS_272_ */ +{0x0F12, 0x009F}, /* 007C 00E5 Tune_wbt_GAS_273_ */ +{0x0F12, 0x008F}, /* 006A 00C7 Tune_wbt_GAS_274_ */ +{0x0F12, 0x0077}, /* 0055 00B1 Tune_wbt_GAS_275_ */ +{0x0F12, 0x0061}, /* 0043 0093 Tune_wbt_GAS_276_ */ +{0x0F12, 0x0052}, /* 0037 007F Tune_wbt_GAS_277_ */ +{0x0F12, 0x0048}, /* 0030 0074 Tune_wbt_GAS_278_ */ +{0x0F12, 0x0043}, /* 002E 0071 Tune_wbt_GAS_279_ */ +{0x0F12, 0x0047}, /* 0030 0077 Tune_wbt_GAS_280_ */ +{0x0F12, 0x0050}, /* 0039 0089 Tune_wbt_GAS_281_ */ +{0x0F12, 0x005E}, /* 0045 00A7 Tune_wbt_GAS_282_ */ +{0x0F12, 0x0071}, /* 0056 00CC Tune_wbt_GAS_283_ */ +{0x0F12, 0x0086}, /* 006C 00FE Tune_wbt_GAS_284_ */ +{0x0F12, 0x0097}, /* 0084 0132 Tune_wbt_GAS_285_ */ +{0x0F12, 0x0093}, /* 006E 00A8 Tune_wbt_GAS_286_ */ +{0x0F12, 0x007C}, /* 006D 008D Tune_wbt_GAS_287_ */ +{0x0F12, 0x005F}, /* 005B 006C Tune_wbt_GAS_288_ */ +{0x0F12, 0x0049}, /* 0046 004E Tune_wbt_GAS_289_ */ +{0x0F12, 0x003A}, /* 003A 003C Tune_wbt_GAS_290_ */ +{0x0F12, 0x0030}, /* 0033 0032 Tune_wbt_GAS_291_ */ +{0x0F12, 0x002C}, /* 002D 002D Tune_wbt_GAS_292_ */ +{0x0F12, 0x002F}, /* 0032 0032 Tune_wbt_GAS_293_ */ +{0x0F12, 0x0037}, /* 0039 0040 Tune_wbt_GAS_294_ */ +{0x0F12, 0x0045}, /* 0047 0056 Tune_wbt_GAS_295_ */ +{0x0F12, 0x005A}, /* 004F 0076 Tune_wbt_GAS_296_ */ +{0x0F12, 0x0075}, /* 0050 00A8 Tune_wbt_GAS_297_ */ +{0x0F12, 0x008A}, /* 006E 00E6 Tune_wbt_GAS_298_ */ +{0x0F12, 0x0094}, /* 0077 00A2 Tune_wbt_GAS_299_ */ +{0x0F12, 0x0077}, /* 006C 007C Tune_wbt_GAS_300_ */ +{0x0F12, 0x0057}, /* 0054 0059 Tune_wbt_GAS_301_ */ +{0x0F12, 0x0040}, /* 0040 003E Tune_wbt_GAS_302_ */ +{0x0F12, 0x002F}, /* 0033 002A Tune_wbt_GAS_303_ */ +{0x0F12, 0x0024}, /* 002B 0020 Tune_wbt_GAS_304_ */ +{0x0F12, 0x0020}, /* 0027 001B Tune_wbt_GAS_305_ */ +{0x0F12, 0x0023}, /* 002A 0020 Tune_wbt_GAS_306_ */ +{0x0F12, 0x002D}, /* 0034 002D Tune_wbt_GAS_307_ */ +{0x0F12, 0x003B}, /* 0041 0042 Tune_wbt_GAS_308_ */ +{0x0F12, 0x0051}, /* 004C 0061 Tune_wbt_GAS_309_ */ +{0x0F12, 0x006E}, /* 0052 0092 Tune_wbt_GAS_310_ */ +{0x0F12, 0x008C}, /* 007E 00CE Tune_wbt_GAS_311_ */ +{0x0F12, 0x0085}, /* 0078 0094 Tune_wbt_GAS_312_ */ +{0x0F12, 0x0066}, /* 0063 006F Tune_wbt_GAS_313_ */ +{0x0F12, 0x0046}, /* 0049 004B Tune_wbt_GAS_314_ */ +{0x0F12, 0x002F}, /* 0035 002F Tune_wbt_GAS_315_ */ +{0x0F12, 0x001F}, /* 0028 001D Tune_wbt_GAS_316_ */ +{0x0F12, 0x0014}, /* 001E 0011 Tune_wbt_GAS_317_ */ +{0x0F12, 0x000F}, /* 001B 000D Tune_wbt_GAS_318_ */ +{0x0F12, 0x0012}, /* 001F 0012 Tune_wbt_GAS_319_ */ +{0x0F12, 0x001C}, /* 0028 001D Tune_wbt_GAS_320_ */ +{0x0F12, 0x002B}, /* 0037 0033 Tune_wbt_GAS_321_ */ +{0x0F12, 0x0040}, /* 0044 0051 Tune_wbt_GAS_322_ */ +{0x0F12, 0x005C}, /* 0050 007F Tune_wbt_GAS_323_ */ +{0x0F12, 0x007D}, /* 0080 00BA Tune_wbt_GAS_324_ */ +{0x0F12, 0x007A}, /* 0064 008B Tune_wbt_GAS_325_ */ +{0x0F12, 0x005A}, /* 004E 0064 Tune_wbt_GAS_326_ */ +{0x0F12, 0x003A}, /* 0035 0040 Tune_wbt_GAS_327_ */ +{0x0F12, 0x0024}, /* 0021 0025 Tune_wbt_GAS_328_ */ +{0x0F12, 0x0014}, /* 0013 0013 Tune_wbt_GAS_329_ */ +{0x0F12, 0x0009}, /* 000D 0007 Tune_wbt_GAS_330_ */ +{0x0F12, 0x0006}, /* 000B 0003 Tune_wbt_GAS_331_ */ +{0x0F12, 0x0008}, /* 000C 0006 Tune_wbt_GAS_332_ */ +{0x0F12, 0x0011}, /* 0014 0012 Tune_wbt_GAS_333_ */ +{0x0F12, 0x0020}, /* 0022 0027 Tune_wbt_GAS_334_ */ +{0x0F12, 0x0036}, /* 0036 0046 Tune_wbt_GAS_335_ */ +{0x0F12, 0x0051}, /* 004D 0073 Tune_wbt_GAS_336_ */ +{0x0F12, 0x0072}, /* 006B 00AB Tune_wbt_GAS_337_ */ +{0x0F12, 0x007B}, /* 0066 008B Tune_wbt_GAS_338_ */ +{0x0F12, 0x0059}, /* 004C 0062 Tune_wbt_GAS_339_ */ +{0x0F12, 0x003A}, /* 0032 003F Tune_wbt_GAS_340_ */ +{0x0F12, 0x0023}, /* 001E 0023 Tune_wbt_GAS_341_ */ +{0x0F12, 0x0012}, /* 0010 0010 Tune_wbt_GAS_342_ */ +{0x0F12, 0x0008}, /* 000A 0004 Tune_wbt_GAS_343_ */ +{0x0F12, 0x0004}, /* 0007 0000 Tune_wbt_GAS_344_ */ +{0x0F12, 0x0007}, /* 000B 0003 Tune_wbt_GAS_345_ */ +{0x0F12, 0x000F}, /* 0010 000E Tune_wbt_GAS_346_ */ +{0x0F12, 0x001F}, /* 001E 0022 Tune_wbt_GAS_347_ */ +{0x0F12, 0x0035}, /* 0032 0041 Tune_wbt_GAS_348_ */ +{0x0F12, 0x0051}, /* 004B 006E Tune_wbt_GAS_349_ */ +{0x0F12, 0x0072}, /* 006B 00A4 Tune_wbt_GAS_350_ */ +{0x0F12, 0x0073}, /* 0061 008E Tune_wbt_GAS_351_ */ +{0x0F12, 0x0053}, /* 0049 0065 Tune_wbt_GAS_352_ */ +{0x0F12, 0x0034}, /* 002F 0040 Tune_wbt_GAS_353_ */ +{0x0F12, 0x001D}, /* 001B 0025 Tune_wbt_GAS_354_ */ +{0x0F12, 0x000E}, /* 000E 0013 Tune_wbt_GAS_355_ */ +{0x0F12, 0x0004}, /* 0008 0006 Tune_wbt_GAS_356_ */ +{0x0F12, 0x0000}, /* 0004 0001 Tune_wbt_GAS_357_ */ +{0x0F12, 0x0002}, /* 0008 0005 Tune_wbt_GAS_358_ */ +{0x0F12, 0x000A}, /* 000D 0010 Tune_wbt_GAS_359_ */ +{0x0F12, 0x001A}, /* 001C 0025 Tune_wbt_GAS_360_ */ +{0x0F12, 0x002F}, /* 002F 0044 Tune_wbt_GAS_361_ */ +{0x0F12, 0x004A}, /* 0047 0074 Tune_wbt_GAS_362_ */ +{0x0F12, 0x006A}, /* 0067 00AA Tune_wbt_GAS_363_ */ +{0x0F12, 0x0077}, /* 005A 0097 Tune_wbt_GAS_364_ */ +{0x0F12, 0x0058}, /* 0043 006D Tune_wbt_GAS_365_ */ +{0x0F12, 0x0039}, /* 002B 0048 Tune_wbt_GAS_366_ */ +{0x0F12, 0x0022}, /* 0017 002D Tune_wbt_GAS_367_ */ +{0x0F12, 0x0012}, /* 0009 0019 Tune_wbt_GAS_368_ */ +{0x0F12, 0x0008}, /* 0004 000E Tune_wbt_GAS_369_ */ +{0x0F12, 0x0004}, /* 0002 0009 Tune_wbt_GAS_370_ */ +{0x0F12, 0x0007}, /* 0004 000C Tune_wbt_GAS_371_ */ +{0x0F12, 0x000F}, /* 0008 0018 Tune_wbt_GAS_372_ */ +{0x0F12, 0x001E}, /* 0016 002E Tune_wbt_GAS_373_ */ +{0x0F12, 0x0034}, /* 002A 004E Tune_wbt_GAS_374_ */ +{0x0F12, 0x004F}, /* 0042 007D Tune_wbt_GAS_375_ */ +{0x0F12, 0x006F}, /* 005F 00B5 Tune_wbt_GAS_376_ */ +{0x0F12, 0x0083}, /* 0066 00A6 Tune_wbt_GAS_377_ */ +{0x0F12, 0x0064}, /* 0050 007C Tune_wbt_GAS_378_ */ +{0x0F12, 0x0045}, /* 0035 0058 Tune_wbt_GAS_379_ */ +{0x0F12, 0x002E}, /* 0022 003E Tune_wbt_GAS_380_ */ +{0x0F12, 0x001D}, /* 0013 0029 Tune_wbt_GAS_381_ */ +{0x0F12, 0x0012}, /* 000A 001D Tune_wbt_GAS_382_ */ +{0x0F12, 0x000F}, /* 0008 0018 Tune_wbt_GAS_383_ */ +{0x0F12, 0x0011}, /* 000B 001B Tune_wbt_GAS_384_ */ +{0x0F12, 0x001A}, /* 0014 0028 Tune_wbt_GAS_385_ */ +{0x0F12, 0x002A}, /* 0021 003F Tune_wbt_GAS_386_ */ +{0x0F12, 0x003F}, /* 0035 0062 Tune_wbt_GAS_387_ */ +{0x0F12, 0x005B}, /* 004D 0093 Tune_wbt_GAS_388_ */ +{0x0F12, 0x007B}, /* 006E 00CC Tune_wbt_GAS_389_ */ +{0x0F12, 0x0087}, /* 006E 00B9 Tune_wbt_GAS_390_ */ +{0x0F12, 0x006A}, /* 0057 0094 Tune_wbt_GAS_391_ */ +{0x0F12, 0x004B}, /* 003E 0071 Tune_wbt_GAS_392_ */ +{0x0F12, 0x0036}, /* 002B 0052 Tune_wbt_GAS_393_ */ +{0x0F12, 0x0025}, /* 001C 003D Tune_wbt_GAS_394_ */ +{0x0F12, 0x0019}, /* 0013 0031 Tune_wbt_GAS_395_ */ +{0x0F12, 0x0015}, /* 0011 002D Tune_wbt_GAS_396_ */ +{0x0F12, 0x0017}, /* 0013 0031 Tune_wbt_GAS_397_ */ +{0x0F12, 0x0022}, /* 001D 0040 Tune_wbt_GAS_398_ */ +{0x0F12, 0x0031}, /* 002B 0058 Tune_wbt_GAS_399_ */ +{0x0F12, 0x0045}, /* 003D 007B Tune_wbt_GAS_400_ */ +{0x0F12, 0x0060}, /* 0057 00AE Tune_wbt_GAS_401_ */ +{0x0F12, 0x007D}, /* 0077 00EA Tune_wbt_GAS_402_ */ +{0x0F12, 0x0096}, /* 0072 00C2 Tune_wbt_GAS_403_ */ +{0x0F12, 0x007F}, /* 005F 00AE Tune_wbt_GAS_404_ */ +{0x0F12, 0x0061}, /* 0047 008E Tune_wbt_GAS_405_ */ +{0x0F12, 0x004B}, /* 0035 006F Tune_wbt_GAS_406_ */ +{0x0F12, 0x003B}, /* 0028 0059 Tune_wbt_GAS_407_ */ +{0x0F12, 0x002F}, /* 0020 004E Tune_wbt_GAS_408_ */ +{0x0F12, 0x002A}, /* 001D 0049 Tune_wbt_GAS_409_ */ +{0x0F12, 0x002D}, /* 0020 004F Tune_wbt_GAS_410_ */ +{0x0F12, 0x0036}, /* 0029 005E Tune_wbt_GAS_411_ */ +{0x0F12, 0x0046}, /* 0035 007A Tune_wbt_GAS_412_ */ +{0x0F12, 0x005B}, /* 0047 009F Tune_wbt_GAS_413_ */ +{0x0F12, 0x0075}, /* 0060 00D5 Tune_wbt_GAS_414_ */ +{0x0F12, 0x008D}, /* 007D 010C Tune_wbt_GAS_415_ */ +{0x0F12, 0x00A1}, /* 0084 00E5 Tune_wbt_GAS_416_ */ +{0x0F12, 0x0091}, /* 0072 00C8 Tune_wbt_GAS_417_ */ +{0x0F12, 0x0077}, /* 005B 00B0 Tune_wbt_GAS_418_ */ +{0x0F12, 0x0060}, /* 0046 0091 Tune_wbt_GAS_419_ */ +{0x0F12, 0x0050}, /* 003A 007D Tune_wbt_GAS_420_ */ +{0x0F12, 0x0044}, /* 0031 0070 Tune_wbt_GAS_421_ */ +{0x0F12, 0x0040}, /* 002E 006D Tune_wbt_GAS_422_ */ +{0x0F12, 0x0043}, /* 0032 0074 Tune_wbt_GAS_423_ */ +{0x0F12, 0x004C}, /* 0039 0086 Tune_wbt_GAS_424_ */ +{0x0F12, 0x005A}, /* 0046 00A4 Tune_wbt_GAS_425_ */ +{0x0F12, 0x006D}, /* 0056 00CA Tune_wbt_GAS_426_ */ +{0x0F12, 0x0084}, /* 006E 00FE Tune_wbt_GAS_427_ */ +{0x0F12, 0x0094}, /* 0087 0134 Tune_wbt_GAS_428_ */ +{0x0F12, 0x0072}, /* 004C 009F Tune_wbt_GAS_429_ */ +{0x0F12, 0x0063}, /* 004C 0089 Tune_wbt_GAS_430_ */ +{0x0F12, 0x004C}, /* 0041 0067 Tune_wbt_GAS_431_ */ +{0x0F12, 0x003A}, /* 002F 004E Tune_wbt_GAS_432_ */ +{0x0F12, 0x002D}, /* 0024 003E Tune_wbt_GAS_433_ */ +{0x0F12, 0x0025}, /* 001D 0033 Tune_wbt_GAS_434_ */ +{0x0F12, 0x0023}, /* 001B 0031 Tune_wbt_GAS_435_ */ +{0x0F12, 0x0025}, /* 001E 0036 Tune_wbt_GAS_436_ */ +{0x0F12, 0x002C}, /* 0024 0045 Tune_wbt_GAS_437_ */ +{0x0F12, 0x0038}, /* 0032 0058 Tune_wbt_GAS_438_ */ +{0x0F12, 0x004A}, /* 0037 0074 Tune_wbt_GAS_439_ */ +{0x0F12, 0x005F}, /* 0038 00A0 Tune_wbt_GAS_440_ */ +{0x0F12, 0x006B}, /* 004C 00C9 Tune_wbt_GAS_441_ */ +{0x0F12, 0x0079}, /* 005B 0098 Tune_wbt_GAS_442_ */ +{0x0F12, 0x0065}, /* 0056 0077 Tune_wbt_GAS_443_ */ +{0x0F12, 0x004A}, /* 0041 0055 Tune_wbt_GAS_444_ */ +{0x0F12, 0x0037}, /* 0030 003C Tune_wbt_GAS_445_ */ +{0x0F12, 0x0029}, /* 0026 002A Tune_wbt_GAS_446_ */ +{0x0F12, 0x0021}, /* 001F 0022 Tune_wbt_GAS_447_ */ +{0x0F12, 0x001D}, /* 001C 001F Tune_wbt_GAS_448_ */ +{0x0F12, 0x001F}, /* 001F 0024 Tune_wbt_GAS_449_ */ +{0x0F12, 0x0027}, /* 0027 0030 Tune_wbt_GAS_450_ */ +{0x0F12, 0x0033}, /* 0033 0044 Tune_wbt_GAS_451_ */ +{0x0F12, 0x0044}, /* 003C 0060 Tune_wbt_GAS_452_ */ +{0x0F12, 0x005E}, /* 0041 008B Tune_wbt_GAS_453_ */ +{0x0F12, 0x006E}, /* 0060 00B2 Tune_wbt_GAS_454_ */ +{0x0F12, 0x006A}, /* 005E 0088 Tune_wbt_GAS_455_ */ +{0x0F12, 0x0055}, /* 004F 0065 Tune_wbt_GAS_456_ */ +{0x0F12, 0x003A}, /* 003A 0044 Tune_wbt_GAS_457_ */ +{0x0F12, 0x0028}, /* 002A 002C Tune_wbt_GAS_458_ */ +{0x0F12, 0x001A}, /* 001D 001B Tune_wbt_GAS_459_ */ +{0x0F12, 0x0011}, /* 0016 0012 Tune_wbt_GAS_460_ */ +{0x0F12, 0x000D}, /* 0014 000F Tune_wbt_GAS_461_ */ +{0x0F12, 0x000F}, /* 0016 0013 Tune_wbt_GAS_462_ */ +{0x0F12, 0x0017}, /* 0021 001E Tune_wbt_GAS_463_ */ +{0x0F12, 0x0024}, /* 002D 0032 Tune_wbt_GAS_464_ */ +{0x0F12, 0x0035}, /* 0038 004E Tune_wbt_GAS_465_ */ +{0x0F12, 0x004E}, /* 0040 0078 Tune_wbt_GAS_466_ */ +{0x0F12, 0x0061}, /* 0066 00A2 Tune_wbt_GAS_467_ */ +{0x0F12, 0x0061}, /* 004A 007F Tune_wbt_GAS_468_ */ +{0x0F12, 0x004A}, /* 003C 005B Tune_wbt_GAS_469_ */ +{0x0F12, 0x0031}, /* 0028 0039 Tune_wbt_GAS_470_ */ +{0x0F12, 0x001E}, /* 0019 0021 Tune_wbt_GAS_471_ */ +{0x0F12, 0x0011}, /* 000D 0012 Tune_wbt_GAS_472_ */ +{0x0F12, 0x0008}, /* 0008 0007 Tune_wbt_GAS_473_ */ +{0x0F12, 0x0005}, /* 0007 0004 Tune_wbt_GAS_474_ */ +{0x0F12, 0x0007}, /* 0007 0006 Tune_wbt_GAS_475_ */ +{0x0F12, 0x000E}, /* 000F 0012 Tune_wbt_GAS_476_ */ +{0x0F12, 0x001B}, /* 001C 0024 Tune_wbt_GAS_477_ */ +{0x0F12, 0x002D}, /* 002C 0041 Tune_wbt_GAS_478_ */ +{0x0F12, 0x0045}, /* 0042 006A Tune_wbt_GAS_479_ */ +{0x0F12, 0x0059}, /* 0054 0092 Tune_wbt_GAS_480_ */ +{0x0F12, 0x0062}, /* 004B 007B Tune_wbt_GAS_481_ */ +{0x0F12, 0x004B}, /* 003C 0057 Tune_wbt_GAS_482_ */ +{0x0F12, 0x0031}, /* 0027 0036 Tune_wbt_GAS_483_ */ +{0x0F12, 0x001E}, /* 0017 001E Tune_wbt_GAS_484_ */ +{0x0F12, 0x0010}, /* 000C 000F Tune_wbt_GAS_485_ */ +{0x0F12, 0x0008}, /* 0007 0003 Tune_wbt_GAS_486_ */ +{0x0F12, 0x0004}, /* 0006 0000 Tune_wbt_GAS_487_ */ +{0x0F12, 0x0006}, /* 0008 0002 Tune_wbt_GAS_488_ */ +{0x0F12, 0x000E}, /* 000D 000D Tune_wbt_GAS_489_ */ +{0x0F12, 0x001B}, /* 001A 0020 Tune_wbt_GAS_490_ */ +{0x0F12, 0x002E}, /* 002B 003C Tune_wbt_GAS_491_ */ +{0x0F12, 0x0046}, /* 0041 0067 Tune_wbt_GAS_492_ */ +{0x0F12, 0x005A}, /* 0054 008D Tune_wbt_GAS_493_ */ +{0x0F12, 0x005B}, /* 0049 007E Tune_wbt_GAS_494_ */ +{0x0F12, 0x0045}, /* 003A 005A Tune_wbt_GAS_495_ */ +{0x0F12, 0x002C}, /* 0025 0038 Tune_wbt_GAS_496_ */ +{0x0F12, 0x001A}, /* 0015 0022 Tune_wbt_GAS_497_ */ +{0x0F12, 0x000C}, /* 000A 0013 Tune_wbt_GAS_498_ */ +{0x0F12, 0x0003}, /* 0005 0006 Tune_wbt_GAS_499_ */ +{0x0F12, 0x0000}, /* 0003 0001 Tune_wbt_GAS_500_ */ +{0x0F12, 0x0002}, /* 0006 0004 Tune_wbt_GAS_501_ */ +{0x0F12, 0x0009}, /* 000B 000F Tune_wbt_GAS_502_ */ +{0x0F12, 0x0016}, /* 0018 0023 Tune_wbt_GAS_503_ */ +{0x0F12, 0x0029}, /* 0029 003E Tune_wbt_GAS_504_ */ +{0x0F12, 0x0040}, /* 003E 006A Tune_wbt_GAS_505_ */ +{0x0F12, 0x0054}, /* 0050 0091 Tune_wbt_GAS_506_ */ +{0x0F12, 0x005F}, /* 0044 0085 Tune_wbt_GAS_507_ */ +{0x0F12, 0x004A}, /* 0033 0060 Tune_wbt_GAS_508_ */ +{0x0F12, 0x0031}, /* 0021 0041 Tune_wbt_GAS_509_ */ +{0x0F12, 0x001F}, /* 0011 002A Tune_wbt_GAS_510_ */ +{0x0F12, 0x0010}, /* 0005 0019 Tune_wbt_GAS_511_ */ +{0x0F12, 0x0008}, /* 0002 000D Tune_wbt_GAS_512_ */ +{0x0F12, 0x0004}, /* 0001 0008 Tune_wbt_GAS_513_ */ +{0x0F12, 0x0007}, /* 0003 000A Tune_wbt_GAS_514_ */ +{0x0F12, 0x000E}, /* 0008 0016 Tune_wbt_GAS_515_ */ +{0x0F12, 0x001B}, /* 0014 002A Tune_wbt_GAS_516_ */ +{0x0F12, 0x002E}, /* 0025 0047 Tune_wbt_GAS_517_ */ +{0x0F12, 0x0045}, /* 0039 0074 Tune_wbt_GAS_518_ */ +{0x0F12, 0x0059}, /* 004D 009A Tune_wbt_GAS_519_ */ +{0x0F12, 0x006C}, /* 0050 0097 Tune_wbt_GAS_520_ */ +{0x0F12, 0x0057}, /* 0041 0070 Tune_wbt_GAS_521_ */ +{0x0F12, 0x003E}, /* 002C 0052 Tune_wbt_GAS_522_ */ +{0x0F12, 0x002A}, /* 001C 003C Tune_wbt_GAS_523_ */ +{0x0F12, 0x001B}, /* 0011 0028 Tune_wbt_GAS_524_ */ +{0x0F12, 0x0012}, /* 0009 001D Tune_wbt_GAS_525_ */ +{0x0F12, 0x000F}, /* 0008 0019 Tune_wbt_GAS_526_ */ +{0x0F12, 0x0011}, /* 000A 001A Tune_wbt_GAS_527_ */ +{0x0F12, 0x0019}, /* 0012 0026 Tune_wbt_GAS_528_ */ +{0x0F12, 0x0027}, /* 001F 003B Tune_wbt_GAS_529_ */ +{0x0F12, 0x0039}, /* 002F 005A Tune_wbt_GAS_530_ */ +{0x0F12, 0x0050}, /* 0045 0089 Tune_wbt_GAS_531_ */ +{0x0F12, 0x0063}, /* 005A 00AF Tune_wbt_GAS_532_ */ +{0x0F12, 0x006F}, /* 0056 00A7 Tune_wbt_GAS_533_ */ +{0x0F12, 0x005C}, /* 0048 0088 Tune_wbt_GAS_534_ */ +{0x0F12, 0x0044}, /* 0035 006B Tune_wbt_GAS_535_ */ +{0x0F12, 0x0031}, /* 0026 0050 Tune_wbt_GAS_536_ */ +{0x0F12, 0x0023}, /* 0019 003D Tune_wbt_GAS_537_ */ +{0x0F12, 0x0019}, /* 0012 0032 Tune_wbt_GAS_538_ */ +{0x0F12, 0x0016}, /* 0011 002E Tune_wbt_GAS_539_ */ +{0x0F12, 0x0017}, /* 0012 0030 Tune_wbt_GAS_540_ */ +{0x0F12, 0x0020}, /* 001B 003E Tune_wbt_GAS_541_ */ +{0x0F12, 0x002E}, /* 0027 0052 Tune_wbt_GAS_542_ */ +{0x0F12, 0x0040}, /* 0037 0073 Tune_wbt_GAS_543_ */ +{0x0F12, 0x0055}, /* 004C 00A1 Tune_wbt_GAS_544_ */ +{0x0F12, 0x0064}, /* 0060 00C7 Tune_wbt_GAS_545_ */ +{0x0F12, 0x007E}, /* 0058 00AE Tune_wbt_GAS_546_ */ +{0x0F12, 0x0071}, /* 0050 00A4 Tune_wbt_GAS_547_ */ +{0x0F12, 0x0059}, /* 003D 0088 Tune_wbt_GAS_548_ */ +{0x0F12, 0x0046}, /* 002E 006D Tune_wbt_GAS_549_ */ +{0x0F12, 0x0039}, /* 0023 0059 Tune_wbt_GAS_550_ */ +{0x0F12, 0x002F}, /* 001C 004D Tune_wbt_GAS_551_ */ +{0x0F12, 0x002A}, /* 001B 0049 Tune_wbt_GAS_552_ */ +{0x0F12, 0x002D}, /* 001D 004E Tune_wbt_GAS_553_ */ +{0x0F12, 0x0035}, /* 0024 005B Tune_wbt_GAS_554_ */ +{0x0F12, 0x0043}, /* 002F 0073 Tune_wbt_GAS_555_ */ +{0x0F12, 0x0054}, /* 003E 0095 Tune_wbt_GAS_556_ */ +{0x0F12, 0x0069}, /* 0052 00C4 Tune_wbt_GAS_557_ */ +{0x0F12, 0x0074}, /* 0062 00E9 Tune_wbt_GAS_558_ */ +{0x0F12, 0x0083}, /* 0060 00D5 Tune_wbt_GAS_559_ */ +{0x0F12, 0x007D}, /* 0057 00C1 Tune_wbt_GAS_560_ */ +{0x0F12, 0x0068}, /* 0048 00AB Tune_wbt_GAS_561_ */ +{0x0F12, 0x0055}, /* 0039 008D Tune_wbt_GAS_562_ */ +{0x0F12, 0x0048}, /* 002E 0079 Tune_wbt_GAS_563_ */ +{0x0F12, 0x003E}, /* 0028 0070 Tune_wbt_GAS_564_ */ +{0x0F12, 0x003A}, /* 0027 006A Tune_wbt_GAS_565_ */ +{0x0F12, 0x003D}, /* 0029 006F Tune_wbt_GAS_566_ */ +{0x0F12, 0x0045}, /* 002F 0080 Tune_wbt_GAS_567_ */ +{0x0F12, 0x0051}, /* 0039 0096 Tune_wbt_GAS_568_ */ +{0x0F12, 0x0061}, /* 0047 00B9 Tune_wbt_GAS_569_ */ +{0x0F12, 0x0072}, /* 0059 00E2 Tune_wbt_GAS_570_ */ +{0x0F12, 0x0077}, /* 0067 010F Tune_wbt_GAS_571_ */ +{0x002A, 0x1348}, +{0x0F12, 0x0001}, /* gisp_gras_Enable */ + +/*************************************/ +/* 07. Analog Setting 2 */ +/*************************************/ + +/*************************************/ +/* 08.AF Setting */ +/*************************************/ + +/*************************************/ +/* 09.AWB-BASIC setting */ +/*************************************/ +/* For WB Calibration */ +{0x002A, 0x0B36}, +{0x0F12, 0x0005}, /* awbb_IndoorGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0B3A}, +{0x0F12, 0x00EC}, /* awbb_IndoorGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02C1}, /* awbb_IndoorGrZones_ZInfo_m_BMax */ +{0x002A, 0x0B38}, +{0x0F12, 0x0010}, /* awbb_IndoorGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0AE6}, +{0x0F12, 0x03E1}, /* awbb_IndoorGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x0413}, /* awbb_IndoorGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x039E}, /* awbb_IndoorGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x0416}, /* awbb_IndoorGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x0367}, /* awbb_IndoorGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x03F3}, /* awbb_IndoorGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x032D}, /* awbb_IndoorGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x03C5}, /* awbb_IndoorGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x02FD}, /* awbb_IndoorGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x038F}, /* awbb_IndoorGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x02D3}, /* awbb_IndoorGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x0365}, /* awbb_IndoorGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x02AA}, /* awbb_IndoorGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x033E}, /* awbb_IndoorGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x028D}, /* awbb_IndoorGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0310}, /* awbb_IndoorGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x0271}, /* awbb_IndoorGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x02F1}, /* awbb_IndoorGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x025A}, /* awbb_IndoorGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x02D2}, /* awbb_IndoorGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0249}, /* awbb_IndoorGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x02B9}, /* awbb_IndoorGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0238}, /* awbb_IndoorGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x02A2}, /* awbb_IndoorGrZones_m_BGrid_11__m_right */ +{0x0F12, 0x021B}, /* awbb_IndoorGrZones_m_BGrid_12__m_left */ +{0x0F12, 0x0289}, /* awbb_IndoorGrZones_m_BGrid_12__m_right */ +{0x0F12, 0x0200}, /* awbb_IndoorGrZones_m_BGrid_13__m_left */ +{0x0F12, 0x026C}, /* awbb_IndoorGrZones_m_BGrid_13__m_right */ +{0x0F12, 0x01FC}, /* awbb_IndoorGrZones_m_BGrid_14__m_left */ +{0x0F12, 0x024F}, /* awbb_IndoorGrZones_m_BGrid_14__m_right */ +{0x0F12, 0x021E}, /* awbb_IndoorGrZones_m_BGrid_15__m_left */ +{0x0F12, 0x022C}, /* awbb_IndoorGrZones_m_BGrid_15__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_16__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_16__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_17__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_17__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_18__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_18__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_19__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_19__m_right */ +{0x002A, 0x0BAA}, +{0x0F12, 0x0006}, /* awbb_LowBrGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0BAE}, +{0x0F12, 0x010E}, /* awbb_LowBrGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02E9}, /* awbb_LowBrGrZones_ZInfo_m_BMax */ +{0x002A, 0x0BAC}, +{0x0F12, 0x0009}, /* awbb_LowBrGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0B7A}, +{0x0F12, 0x038C}, /* awbb_LowBrGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x03DA}, /* awbb_LowBrGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x030E}, /* awbb_LowBrGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x03E9}, /* awbb_LowBrGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x02A2}, /* awbb_LowBrGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x03C2}, /* awbb_LowBrGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x0259}, /* awbb_LowBrGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x038A}, /* awbb_LowBrGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x0218}, /* awbb_LowBrGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x0352}, /* awbb_LowBrGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x01F4}, /* awbb_LowBrGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x02E1}, /* awbb_LowBrGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x01D7}, /* awbb_LowBrGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x028E}, /* awbb_LowBrGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x01CB}, /* awbb_LowBrGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0258}, /* awbb_LowBrGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x022B}, /* awbb_LowBrGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x01CC}, /* awbb_LowBrGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_11__m_right */ +{0x002A, 0x0B70}, +{0x0F12, 0x0005}, /* awbb_OutdoorGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0B74}, +{0x0F12, 0x01F8}, /* awbb_OutdoorGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02A8}, /* awbb_OutdoorGrZones_ZInfo_m_BMax */ +{0x002A, 0x0B72}, +{0x0F12, 0x0007}, /* awbb_OutdoorGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0B40}, +{0x0F12, 0x029E}, /* awbb_OutdoorGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x02C8}, /* awbb_OutdoorGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x0281}, /* awbb_OutdoorGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x02C8}, /* awbb_OutdoorGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x0266}, /* awbb_OutdoorGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x02AC}, /* awbb_OutdoorGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x0251}, /* awbb_OutdoorGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x028E}, /* awbb_OutdoorGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x023D}, /* awbb_OutdoorGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x0275}, /* awbb_OutdoorGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x0228}, /* awbb_OutdoorGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x025D}, /* awbb_OutdoorGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x0228}, /* awbb_OutdoorGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x0243}, /* awbb_OutdoorGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_11__m_right */ +{0x002A, 0x0BC8}, +{0x0F12, 0x0005}, /* awbb_CWSkinZone_ZInfo_m_GridStep */ +{0x002A, 0x0BCC}, +{0x0F12, 0x010F}, /* awbb_CWSkinZone_ZInfo_m_BMin */ +{0x0F12, 0x018F}, /* awbb_CWSkinZone_ZInfo_m_BMax */ +{0x002A, 0x0BCA}, +{0x0F12, 0x0005}, /* awbb_CWSkinZone_ZInfo_m_GridSz */ +{0x002A, 0x0BB4}, +{0x0F12, 0x03E7}, /* awbb_CWSkinZone_m_BGrid_0__m_left */ +{0x0F12, 0x03F8}, /* awbb_CWSkinZone_m_BGrid_0__m_right */ +{0x0F12, 0x03A7}, /* awbb_CWSkinZone_m_BGrid_1__m_left */ +{0x0F12, 0x03FC}, /* awbb_CWSkinZone_m_BGrid_1__m_right */ +{0x0F12, 0x0352}, /* awbb_CWSkinZone_m_BGrid_2__m_left */ +{0x0F12, 0x03D0}, /* awbb_CWSkinZone_m_BGrid_2__m_right */ +{0x0F12, 0x0322}, /* awbb_CWSkinZone_m_BGrid_3__m_left */ +{0x0F12, 0x039E}, /* awbb_CWSkinZone_m_BGrid_3__m_right */ +{0x0F12, 0x032B}, /* awbb_CWSkinZone_m_BGrid_4__m_left */ +{0x0F12, 0x034D}, /* awbb_CWSkinZone_m_BGrid_4__m_right */ +{0x002A, 0x0BE6}, +{0x0F12, 0x0006}, /* awbb_DLSkinZone_ZInfo_m_GridStep */ +{0x002A, 0x0BEA}, +{0x0F12, 0x019E}, /* awbb_DLSkinZone_ZInfo_m_BMin */ +{0x0F12, 0x0257}, /* awbb_DLSkinZone_ZInfo_m_BMax */ +{0x002A, 0x0BE8}, +{0x0F12, 0x0004}, /* awbb_DLSkinZone_ZInfo_m_GridSz */ +{0x002A, 0x0BD2}, +{0x0F12, 0x030B}, /* awbb_DLSkinZone_m_BGrid_0__m_left */ +{0x0F12, 0x0323}, /* awbb_DLSkinZone_m_BGrid_0__m_right */ +{0x0F12, 0x02C3}, /* awbb_DLSkinZone_m_BGrid_1__m_left */ +{0x0F12, 0x030F}, /* awbb_DLSkinZone_m_BGrid_1__m_right */ +{0x0F12, 0x0288}, /* awbb_DLSkinZone_m_BGrid_2__m_left */ +{0x0F12, 0x02E5}, /* awbb_DLSkinZone_m_BGrid_2__m_right */ +{0x0F12, 0x026A}, /* awbb_DLSkinZone_m_BGrid_3__m_left */ +{0x0F12, 0x02A2}, /* awbb_DLSkinZone_m_BGrid_3__m_right */ +{0x0F12, 0x0000}, /* awbb_DLSkinZone_m_BGrid_4__m_left */ +{0x0F12, 0x0000}, /* awbb_DLSkinZone_m_BGrid_4__m_right */ +{0x002A, 0x0C2C}, +{0x0F12, 0x0139}, /* awbb_IntcR */ +{0x0F12, 0x0122}, /* awbb_IntcB */ +{0x002A, 0x0BFC}, +{0x0F12, 0x03AD}, /* awbb_IndoorWP_0__r */ +{0x0F12, 0x013F}, /* awbb_IndoorWP_0__b */ +{0x0F12, 0x0341}, /* awbb_IndoorWP_1__r */ +{0x0F12, 0x017B}, /* awbb_IndoorWP_1__b */ +{0x0F12, 0x038D}, /* awbb_IndoorWP_2__r */ +{0x0F12, 0x014B}, /* awbb_IndoorWP_2__b */ +{0x0F12, 0x02C3}, /* awbb_IndoorWP_3__r */ +{0x0F12, 0x01CC}, /* awbb_IndoorWP_3__b */ +{0x0F12, 0x0241}, /* awbb_IndoorWP_4__r */ +{0x0F12, 0x027F}, /* awbb_IndoorWP_4__b */ +{0x0F12, 0x0241}, /* awbb_IndoorWP_5__r */ +{0x0F12, 0x027F}, /* awbb_IndoorWP_5__b */ +{0x0F12, 0x0214}, /* awbb_IndoorWP_6__r */ +{0x0F12, 0x02A8}, /* awbb_IndoorWP_6__b */ +{0x0F12, 0x0270}, /* 255 awbb_OutdoorWP_r */ +{0x0F12, 0x0210}, /* 25B awbb_OutdoorWP_b */ +{0x002A, 0x0C4C}, +{0x0F12, 0x0452}, /* awbb_MvEq_RBthresh */ +{0x002A, 0x0C58}, +{0x0F12, 0x059C}, /* awbb_MvEq_RBthresh */ +{0x002A, 0x0BF8}, +{0x0F12, 0x01AE}, /* awbb_LowTSep_m_RminusB */ +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, /* awbb_SkinPreference */ +{0x002A, 0x0CAC}, +{0x0F12, 0x0F00}, /* awbb_SkinPreference */ +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, /* awbb_SkinPreference */ +{0x002A, 0x0D0E}, +{0x0F12, 0x00B8}, /* awbb_GridCoeff_R_2 */ +{0x0F12, 0x00B2}, /* awbb_GridCoeff_B_2 */ +{0x002A, 0x0CFE}, +{0x0F12, 0x0FAB}, /* awbb_GridConst_2_0_ */ +{0x0F12, 0x0FF5}, /* awbb_GridConst_2_1_ */ +{0x0F12, 0x10BB}, /* awbb_GridConst_2_2_ */ +{0x0F12, 0x1153}, /* 1123 1153 awbb_GridConst_2_3_ */ +{0x0F12, 0x11C5}, /* 1165 11C5 awbb_GridConst_2_4_ */ +{0x0F12, 0x122A}, /* awbb_GridConst_2_5_ */ +{0x0F12, 0x00A9}, /* awbb_GridCoeff_R_1 */ +{0x0F12, 0x00C0}, /* awbb_GridCoeff_B_1 */ +{0x002A, 0x0CF8}, +{0x0F12, 0x030E}, /* awbb_GridConst_1_0_ */ +{0x0F12, 0x034C}, /* awbb_GridConst_1_1_ */ +{0x0F12, 0x0388}, /* awbb_GridConst_1_2_ */ + +{0x002A, 0x0CB0}, +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_0__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_0__1_ */ +{0x0F12, 0x0010}, /* 0078 awbb_GridCorr_R_0__2_ */ +{0x0F12, 0x0030}, /* 00AA awbb_GridCorr_R_0__3_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_0__4_ */ +{0x0F12, 0x0050}, /* 0000 awbb_GridCorr_R_0__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_1__0_ */ +{0x0F12, 0x0000}, /* 0096 awbb_GridCorr_R_1__1_ */ +{0x0F12, 0x0010}, /* 0000 awbb_GridCorr_R_1__2_ */ +{0x0F12, 0x0030}, /* 0000 awbb_GridCorr_R_1__3_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_1__4_ */ +{0x0F12, 0x0050}, /* 0000 awbb_GridCorr_R_1__5_ */ + +{0x0F12, 0x0000}, /* 00E6 awbb_GridCorr_R_2__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_2__1_ */ +{0x0F12, 0x0010}, /* 0000 awbb_GridCorr_R_2__2_ */ +{0x0F12, 0x0030}, /* 0000 awbb_GridCorr_R_2__3_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_2__4_ */ +{0x0F12, 0x0050}, /* 0000 awbb_GridCorr_R_2__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_0__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_0__1_ */ +{0x0F12, 0x0000}, /* 0064 awbb_GridCorr_B_0__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_0__3_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_0__4_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_0__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_1__0_ */ +{0x0F12, 0x0000}, /* 0032 awbb_GridCorr_B_1__1_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_1__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_1__3_ */ +{0x0F12, 0xFF06}, /* FF38 awbb_GridCorr_B_1__4_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_1__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_2__0_ */ +{0x0F12, 0x0000}, /* 0032 awbb_GridCorr_B_2__1_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_2__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_2__3_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_2__4_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_2__5_ */ + +{0x002A, 0x0D30}, +{0x0F12, 0x0002}, /* awbb_GridEnable */ +/* For Outdoor Detector */ +{0x002A, 0x0C86}, +{0x0F12, 0x0005}, /* awbb_OutdoorDetectionZone_ZInfo_m_GridSz */ +{0x002A, 0x0C70}, +{0x0F12, 0xFF7B}, /* awbb_OutdoorDetectionZone_m_BGrid_0__m_left */ +{0x0F12, 0x00CE}, /* awbb_OutdoorDetectionZone_m_BGrid_0__m_right */ +{0x0F12, 0xFF23}, /* awbb_OutdoorDetectionZone_m_BGrid_1__m_left */ +{0x0F12, 0x010D}, /* awbb_OutdoorDetectionZone_m_BGrid_1__m_right */ +{0x0F12, 0xFEF3}, /* awbb_OutdoorDetectionZone_m_BGrid_2__m_left */ +{0x0F12, 0x012C}, /* awbb_OutdoorDetectionZone_m_BGrid_2__m_right */ +{0x0F12, 0xFED7}, /* awbb_OutdoorDetectionZone_m_BGrid_3__m_left */ +{0x0F12, 0x014E}, /* awbb_OutdoorDetectionZone_m_BGrid_3__m_right */ +{0x0F12, 0xFEBB}, /* awbb_OutdoorDetectionZone_m_BGrid_4__m_left */ +{0x0F12, 0x0162}, /* awbb_OutdoorDetectionZone_m_BGrid_4__m_right */ +{0x0F12, 0x1388}, /* awbb_OutdoorDetectionZone_ZInfo_m_AbsGridStep */ +{0x002A, 0x0C8A}, +{0x0F12, 0x4ACB}, /* awbb_OutdoorDetectionZone_ZInfo_m_MaxNB */ +{0x002A, 0x0C88}, +{0x0F12, 0x0A7C}, /* awbb_OutdoorDetectionZone_ZInfo_m_NBoffs */ + +/*************************************/ +/* 10.Auto Flicker Detection */ +/*************************************/ +{0x0028, 0x7000}, +{0x002A, 0x03F4}, +{0x0F12, 0x0002}, /*REG_SF_USER_FlickerQuant */ +{0x0F12, 0x0001}, /*REG_SF_USER_FlickerQuantChanged */ +{0x002A, 0x0408}, +{0x0F12, 0x067F}, /*REG_TC_DBG_AutoAlgEnBits all AA are on */ + +/*************************************/ +/* 11.AE Setting */ +/*************************************/ + +{0x002A, 0x0D40}, +{0x0F12, 0x003E}, /* 3E TVAR_ae_BrAve */ + +/* For LT Calibration */ +{0x002A, 0x0D46}, +{0x0F12, 0x000F}, /* ae_StatMode */ + +{0x002A, 0x0440}, +{0x0F12, 0x3410}, /* lt_uMaxExp_0_ */ +{0x002A, 0x0444}, +{0x0F12, 0x6820}, /* lt_uMaxExp_1_ */ +{0x002A, 0x0448}, +{0x0F12, 0x8227}, /* lt_uMaxExp_2_ */ +{0x002A, 0x044C}, +{0x0F12, 0xC350}, /* lt_uMaxExp_3_ */ +{0x002A, 0x0450}, +{0x0F12, 0x3410}, /* lt_uCapMaxExp_0_ */ +{0x002A, 0x0454}, +{0x0F12, 0x6820}, /* lt_uCapMaxExp_1_ */ +{0x002A, 0x0458}, +{0x0F12, 0x8227}, /* lt_uCapMaxExp_2_ */ +{0x002A, 0x045C}, +{0x0F12, 0xC350}, /* lt_uCapMaxExp_3_ */ +{0x002A, 0x0460}, +{0x0F12, 0x01B0}, /* lt_uMaxAnGain_0_ */ +{0x0F12, 0x01B0}, /* lt_uMaxAnGain_1_ */ +{0x0F12, 0x0280}, /* lt_uMaxAnGain_2_ */ +{0x0F12, 0x0A80}, /* lt_uMaxAnGain_3_ */ +{0x0F12, 0x0160}, /* 0100 lt_uMaxDigGain */ +{0x0F12, 0x3000}, /* lt_uMaxTotGain */ +{0x002A, 0x042E}, +{0x0F12, 0x010E}, /* lt_uMaxTotGain */ +{0x0F12, 0x00F5}, /* lt_uLimitLow */ +{0x002A, 0x0DE0}, +{0x0F12, 0x0002}, /* ae_Fade2BlackEnable F2B off, F2W on */ + +/* For Illum Type Calibration */ +/* WRITE #SARR_IllumType_0_ 0078 */ +/* WRITE #SARR_IllumType_1_ 00C3 */ +/* WRITE #SARR_IllumType_2_ 00E9 */ +/* WRITE #SARR_IllumType_3_ 0128 */ +/* WRITE #SARR_IllumType_4_ 016F */ +/* WRITE #SARR_IllumType_5_ 0195 */ +/* WRITE #SARR_IllumType_6_ 01A4 */ +/* WRITE #SARR_IllumTypeF_0_ 0100 */ +/* WRITE #SARR_IllumTypeF_1_ 0100 */ +/* WRITE #SARR_IllumTypeF_2_ 0110 */ +/* WRITE #SARR_IllumTypeF_3_ 00E5 */ +/* WRITE #SARR_IllumTypeF_4_ 0100 */ +/* WRITE #SARR_IllumTypeF_5_ 00ED */ +/* WRITE #SARR_IllumTypeF_6_ 00ED */ + +/*************************************/ +/* 12.AE Weight (Normal) */ +/*************************************/ +{0x002A, 0x0D4E}, +{0x0F12, 0x0000}, /* 0000 ae_WeightTbl_16_0_ */ +{0x0F12, 0x0101}, /* 0101 ae_WeightTbl_16_1_ */ +{0x0F12, 0x0101}, /* 0101 ae_WeightTbl_16_2_ */ +{0x0F12, 0x0000}, /* 0000 ae_WeightTbl_16_3_ */ +{0x0F12, 0x0201}, /* 0101 ae_WeightTbl_16_4_ */ +{0x0F12, 0x0202}, /* 0101 ae_WeightTbl_16_5_ */ +{0x0F12, 0x0202}, /* 0101 ae_WeightTbl_16_6_ */ +{0x0F12, 0x0102}, /* 0101 ae_WeightTbl_16_7_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_8_ */ +{0x0F12, 0x0303}, /* 0303 ae_WeightTbl_16_9_ */ +{0x0F12, 0x0303}, /* 0303 ae_WeightTbl_16_10_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_11_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_12_ */ +{0x0F12, 0x0403}, /* 0403 ae_WeightTbl_16_13_ */ +{0x0F12, 0x0304}, /* 0304 ae_WeightTbl_16_14_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_15_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_16_ */ +{0x0F12, 0x0403}, /* 0403 ae_WeightTbl_16_17_ */ +{0x0F12, 0x0304}, /* 0304 ae_WeightTbl_16_18_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_19_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_20_ */ +{0x0F12, 0x0303}, /* 0403 ae_WeightTbl_16_21_ */ +{0x0F12, 0x0303}, /* 0304 ae_WeightTbl_16_22_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_23_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_24_ */ +{0x0F12, 0x0202}, /* 0303 ae_WeightTbl_16_25_ */ +{0x0F12, 0x0202}, /* 0303 ae_WeightTbl_16_26_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_27_ */ +{0x0F12, 0x0000}, /* 0201 ae_WeightTbl_16_28_ */ +{0x0F12, 0x0101}, /* 0202 ae_WeightTbl_16_29_ */ +{0x0F12, 0x0101}, /* 0202 ae_WeightTbl_16_30_ */ +{0x0F12, 0x0000}, /* 0102 ae_WeightTbl_16_31_ */ + +/*************************************/ +/* 13.Flash Setting */ +/*************************************/ + +/*************************************/ +/* 14.CCM Setting */ +/*************************************/ + +{0x002A, 0x33A4}, +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_0__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_0__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_0__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_0__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_0__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_0__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_0__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_0__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_0__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_0__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_0__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_0__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_0__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_0__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_0__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_0__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_0__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_0__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_1__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_1__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_1__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_1__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_1__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_1__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_1__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_1__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_1__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_1__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_1__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_1__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_1__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_1__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_1__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_1__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_1__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_1__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_2__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_2__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_2__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_2__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_2__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_2__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_2__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_2__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_2__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_2__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_2__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_2__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_2__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_2__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_2__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_2__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_2__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_2__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_3__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_3__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_3__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_3__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_3__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_3__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_3__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_3__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_3__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_3__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_3__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_3__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_3__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_3__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_3__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_3__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_3__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_3__17_ */ +{0x0F12, 0x01BF}, /* Tune_wbt_BaseCcms_4__0_ */ +{0x0F12, 0xFFBF}, /* Tune_wbt_BaseCcms_4__1_ */ +{0x0F12, 0xFFFE}, /* Tune_wbt_BaseCcms_4__2_ */ +{0x0F12, 0xFF6D}, /* Tune_wbt_BaseCcms_4__3_ */ +{0x0F12, 0x01B4}, /* Tune_wbt_BaseCcms_4__4_ */ +{0x0F12, 0xFF66}, /* Tune_wbt_BaseCcms_4__5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_BaseCcms_4__6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_BaseCcms_4__7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_BaseCcms_4__8_ */ +{0x0F12, 0x0136}, /* Tune_wbt_BaseCcms_4__9_ */ +{0x0F12, 0x0132}, /* Tune_wbt_BaseCcms_4__10_ */ +{0x0F12, 0xFF85}, /* Tune_wbt_BaseCcms_4__11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_BaseCcms_4__12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_BaseCcms_4__13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_4__14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_BaseCcms_4__15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_BaseCcms_4__16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_BaseCcms_4__17_ */ +{0x0F12, 0x01BF}, /* Tune_wbt_BaseCcms_5__0_ */ +{0x0F12, 0xFFBF}, /* Tune_wbt_BaseCcms_5__1_ */ +{0x0F12, 0xFFFE}, /* Tune_wbt_BaseCcms_5__2_ */ +{0x0F12, 0xFF6D}, /* Tune_wbt_BaseCcms_5__3_ */ +{0x0F12, 0x01B4}, /* Tune_wbt_BaseCcms_5__4_ */ +{0x0F12, 0xFF66}, /* Tune_wbt_BaseCcms_5__5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_BaseCcms_5__6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_BaseCcms_5__7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_BaseCcms_5__8_ */ +{0x0F12, 0x0136}, /* Tune_wbt_BaseCcms_5__9_ */ +{0x0F12, 0x0132}, /* Tune_wbt_BaseCcms_5__10_ */ +{0x0F12, 0xFF85}, /* Tune_wbt_BaseCcms_5__11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_BaseCcms_5__12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_BaseCcms_5__13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_5__14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_BaseCcms_5__15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_BaseCcms_5__16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_BaseCcms_5__17_ */ +{0x002A, 0x3380}, +{0x0F12, 0x01AC}, /* Tune_wbt_OutdoorCcm_0_ */ +{0x0F12, 0xFFD7}, /* Tune_wbt_OutdoorCcm_1_ */ +{0x0F12, 0x0019}, /* Tune_wbt_OutdoorCcm_2_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_OutdoorCcm_3_ */ +{0x0F12, 0x01D9}, /* Tune_wbt_OutdoorCcm_4_ */ +{0x0F12, 0xFF63}, /* Tune_wbt_OutdoorCcm_5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_OutdoorCcm_6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_OutdoorCcm_7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_OutdoorCcm_8_ */ +{0x0F12, 0x0132}, /* Tune_wbt_OutdoorCcm_9_ */ +{0x0F12, 0x012E}, /* Tune_wbt_OutdoorCcm_10_ */ +{0x0F12, 0xFF8D}, /* Tune_wbt_OutdoorCcm_11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_OutdoorCcm_12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_OutdoorCcm_13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_OutdoorCcm_14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_OutdoorCcm_15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_OutdoorCcm_16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_OutdoorCcm_17_ */ +{0x002A, 0x0612}, +{0x0F12, 0x009D}, /* SARR_AwbCcmCord_0_ */ +{0x0F12, 0x00D5}, /* SARR_AwbCcmCord_1_ */ +{0x0F12, 0x0103}, /* SARR_AwbCcmCord_2_ */ +{0x0F12, 0x0128}, /* SARR_AwbCcmCord_3_ */ +{0x0F12, 0x0166}, /* SARR_AwbCcmCord_4_ */ +{0x0F12, 0x0193}, /* SARR_AwbCcmCord_5_ */ + +/*************************************/ +/* 15.GAMMA */ +/*************************************/ +/* For Pre Post Gamma Calibration */ +{0x002A, 0x0538}, +{0x0F12, 0x0000}, /* seti_uGammaLutPreDemNoBin_0_ */ +{0x0F12, 0x001F}, /* seti_uGammaLutPreDemNoBin_1_ */ +{0x0F12, 0x0035}, /* seti_uGammaLutPreDemNoBin_2_ */ +{0x0F12, 0x005A}, /* seti_uGammaLutPreDemNoBin_3_ */ +{0x0F12, 0x0095}, /* seti_uGammaLutPreDemNoBin_4_ */ +{0x0F12, 0x00E6}, /* seti_uGammaLutPreDemNoBin_5_ */ +{0x0F12, 0x0121}, /* seti_uGammaLutPreDemNoBin_6_ */ +{0x0F12, 0x0139}, /* seti_uGammaLutPreDemNoBin_7_ */ +{0x0F12, 0x0150}, /* seti_uGammaLutPreDemNoBin_8_ */ +{0x0F12, 0x0177}, /* seti_uGammaLutPreDemNoBin_9_ */ +{0x0F12, 0x019A}, /* seti_uGammaLutPreDemNoBin_10_ */ +{0x0F12, 0x01BB}, /* seti_uGammaLutPreDemNoBin_11_ */ +{0x0F12, 0x01DC}, /* seti_uGammaLutPreDemNoBin_12_ */ +{0x0F12, 0x0219}, /* seti_uGammaLutPreDemNoBin_13_ */ +{0x0F12, 0x0251}, /* seti_uGammaLutPreDemNoBin_14_ */ +{0x0F12, 0x02B3}, /* seti_uGammaLutPreDemNoBin_15_ */ +{0x0F12, 0x030A}, /* seti_uGammaLutPreDemNoBin_16_ */ +{0x0F12, 0x035F}, /* seti_uGammaLutPreDemNoBin_17_ */ +{0x0F12, 0x03B1}, /* seti_uGammaLutPreDemNoBin_18_ */ +{0x0F12, 0x03FF}, /* seti_uGammaLutPreDemNoBin_19_ */ +{0x0F12, 0x0000}, /* seti_uGammaLutPostDemNoBin_0_ */ +{0x0F12, 0x0001}, /* seti_uGammaLutPostDemNoBin_1_ */ +{0x0F12, 0x0001}, /* seti_uGammaLutPostDemNoBin_2_ */ +{0x0F12, 0x0002}, /* seti_uGammaLutPostDemNoBin_3_ */ +{0x0F12, 0x0004}, /* seti_uGammaLutPostDemNoBin_4_ */ +{0x0F12, 0x000A}, /* seti_uGammaLutPostDemNoBin_5_ */ +{0x0F12, 0x0012}, /* seti_uGammaLutPostDemNoBin_6_ */ +{0x0F12, 0x0016}, /* seti_uGammaLutPostDemNoBin_7_ */ +{0x0F12, 0x001A}, /* seti_uGammaLutPostDemNoBin_8_ */ +{0x0F12, 0x0024}, /* seti_uGammaLutPostDemNoBin_9_ */ +{0x0F12, 0x0031}, /* seti_uGammaLutPostDemNoBin_10_ */ +{0x0F12, 0x003E}, /* seti_uGammaLutPostDemNoBin_11_ */ +{0x0F12, 0x004E}, /* seti_uGammaLutPostDemNoBin_12_ */ +{0x0F12, 0x0075}, /* seti_uGammaLutPostDemNoBin_13_ */ +{0x0F12, 0x00A8}, /* seti_uGammaLutPostDemNoBin_14_ */ +{0x0F12, 0x0126}, /* seti_uGammaLutPostDemNoBin_15_ */ +{0x0F12, 0x01BE}, /* seti_uGammaLutPostDemNoBin_16_ */ +{0x0F12, 0x0272}, /* seti_uGammaLutPostDemNoBin_17_ */ +{0x0F12, 0x0334}, /* seti_uGammaLutPostDemNoBin_18_ */ +{0x0F12, 0x03FF}, /* seti_uGammaLutPostDemNoBin_19_ */ + +/* For Gamma Calibration */ + +{0x002A, 0x0498}, +{0x0F12, 0x0000}, /* SARR_usDualGammaLutRGBIndoor_0__0_ */ +{0x0F12, 0x0002}, /* SARR_usDualGammaLutRGBIndoor_0__1_ */ +{0x0F12, 0x0007}, /* SARR_usDualGammaLutRGBIndoor_0__2_ */ +{0x0F12, 0x001D}, /* SARR_usDualGammaLutRGBIndoor_0__3_ */ +{0x0F12, 0x006E}, /* SARR_usDualGammaLutRGBIndoor_0__4_ */ +{0x0F12, 0x00D3}, /* SARR_usDualGammaLutRGBIndoor_0__5_ */ +{0x0F12, 0x0127}, /* SARR_usDualGammaLutRGBIndoor_0__6_ */ +{0x0F12, 0x014C}, /* SARR_usDualGammaLutRGBIndoor_0__7_ */ +{0x0F12, 0x016E}, /* SARR_usDualGammaLutRGBIndoor_0__8_ */ +{0x0F12, 0x01A5}, /* SARR_usDualGammaLutRGBIndoor_0__9_ */ +{0x0F12, 0x01D3}, /* SARR_usDualGammaLutRGBIndoor_0__10_ */ +{0x0F12, 0x01FB}, /* SARR_usDualGammaLutRGBIndoor_0__11_ */ +{0x0F12, 0x021F}, /* SARR_usDualGammaLutRGBIndoor_0__12_ */ +{0x0F12, 0x0260}, /* SARR_usDualGammaLutRGBIndoor_0__13_ */ +{0x0F12, 0x029A}, /* SARR_usDualGammaLutRGBIndoor_0__14_ */ +{0x0F12, 0x02F7}, /* SARR_usDualGammaLutRGBIndoor_0__15_ */ +{0x0F12, 0x034D}, /* SARR_usDualGammaLutRGBIndoor_0__16_ */ +{0x0F12, 0x0395}, /* SARR_usDualGammaLutRGBIndoor_0__17_ */ +{0x0F12, 0x03CE}, /* SARR_usDualGammaLutRGBIndoor_0__18_ */ +{0x0F12, 0x03FF}, /* SARR_usDualGammaLutRGBIndoor_0__19_ */ +{0x0F12, 0x0000}, /* SARR_usDualGammaLutRGBOutdoor_0__0_ */ +{0x0F12, 0x0004}, /* SARR_usDualGammaLutRGBOutdoor_0__1_ */ +{0x0F12, 0x000C}, /* SARR_usDualGammaLutRGBOutdoor_0__2_ */ +{0x0F12, 0x0024}, /* SARR_usDualGammaLutRGBOutdoor_0__3_ */ +{0x0F12, 0x006E}, /* SARR_usDualGammaLutRGBOutdoor_0__4_ */ +{0x0F12, 0x00D1}, /* SARR_usDualGammaLutRGBOutdoor_0__5_ */ +{0x0F12, 0x0119}, /* SARR_usDualGammaLutRGBOutdoor_0__6_ */ +{0x0F12, 0x0139}, /* SARR_usDualGammaLutRGBOutdoor_0__7_ */ +{0x0F12, 0x0157}, /* SARR_usDualGammaLutRGBOutdoor_0__8_ */ +{0x0F12, 0x018E}, /* SARR_usDualGammaLutRGBOutdoor_0__9_ */ +{0x0F12, 0x01C3}, /* SARR_usDualGammaLutRGBOutdoor_0__10_ */ +{0x0F12, 0x01F3}, /* SARR_usDualGammaLutRGBOutdoor_0__11_ */ +{0x0F12, 0x021F}, /* SARR_usDualGammaLutRGBOutdoor_0__12_ */ +{0x0F12, 0x0269}, /* SARR_usDualGammaLutRGBOutdoor_0__13_ */ +{0x0F12, 0x02A6}, /* SARR_usDualGammaLutRGBOutdoor_0__14_ */ +{0x0F12, 0x02FF}, /* SARR_usDualGammaLutRGBOutdoor_0__15_ */ +{0x0F12, 0x0351}, /* SARR_usDualGammaLutRGBOutdoor_0__16_ */ +{0x0F12, 0x0395}, /* SARR_usDualGammaLutRGBOutdoor_0__17_ */ +{0x0F12, 0x03CE}, /* SARR_usDualGammaLutRGBOutdoor_0__18_ */ +{0x0F12, 0x03FF}, /* SARR_usDualGammaLutRGBOutdoor_0__19_ */ + +/*************************************/ +/* 16.AFIT */ +/*************************************/ +{0x002A, 0x06D4}, +{0x0F12, 0x0032}, /* afit_uNoiseIndInDoor_0_ */ +{0x0F12, 0x0078}, /* afit_uNoiseIndInDoor_1_ */ +{0x0F12, 0x00C8}, /* afit_uNoiseIndInDoor_2_ */ +{0x0F12, 0x0190}, /* afit_uNoiseIndInDoor_3_ */ +{0x0F12, 0x028C}, /* afit_uNoiseIndInDoor_4_ */ + +{0x002A, 0x0734}, +{0x0F12, 0x0000}, /* AfitBaseVals_0__0_ Brightness[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__1_ Contrast[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__2_ Saturaion[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__3_ Sharp_Blur[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__4_ */ +{0x0F12, 0x0078}, /* AfitBaseVals_0__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_0__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_0__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_0__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_0__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_0__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_0__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_0__14_ */ +{0x0F12, 0x01FF}, /* AfitBaseVals_0__15_ */ +{0x0F12, 0x0144}, /* AfitBaseVals_0__16_ */ +{0x0F12, 0x000F}, /* AfitBaseVals_0__17_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_0__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_0__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__21_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_0__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_0__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__25_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_0__27_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_0__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_0__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_0__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_0__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_0__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_0__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_0__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_0__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__40_ */ +{0x0F12, 0x1408}, /* AfitBaseVals_0__41_ */ +{0x0F12, 0x0214}, /* AfitBaseVals_0__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_0__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_0__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_0__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_0__47_ */ +{0x0F12, 0x0094}, /* AfitBaseVals_0__48_ */ +{0x0F12, 0x1080}, +{0x0F12, 0x0180}, /* AfitBaseVals_0__50_ */ +{0x0F12, 0x0308}, /* AfitBaseVals_0__51_ */ +{0x0F12, 0x3186}, /* AfitBaseVals_0__52_ */ +{0x0F12, 0x5260}, /* AfitBaseVals_0__53_ */ +{0x0F12, 0x0A02}, /* AfitBaseVals_0__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_0__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_0__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_0__57_ */ +{0x0F12, 0x324E}, /* AfitBaseVals_0__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_0__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_0__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_0__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_0__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_0__63_ */ +{0x0F12, 0x4646}, /* AfitBaseVals_0__64_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__65_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_0__68_ */ +{0x0F12, 0x3202}, /* AfitBaseVals_0__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_0__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_0__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_0__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_0__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_0__74_ */ +{0x0F12, 0x4646}, /* AfitBaseVals_0__75_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__76_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_0__79_ */ +{0x0F12, 0x3202}, /* AfitBaseVals_0__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_0__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_0__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_0__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__0_ Brightness[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__1_ Contrast[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__2_ Saturaion[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__3_ Sharp_Blur[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__4_ */ +{0x0F12, 0x006A}, /* AfitBaseVals_1__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_1__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_1__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_1__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_1__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_1__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_1__12_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_1__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_1__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_1__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_1__16_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__17_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_1__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_1__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__21_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_1__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__25_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_1__27_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_1__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_1__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_1__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_1__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_1__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_1__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_1__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__40_ */ +{0x0F12, 0x1408}, /* AfitBaseVals_1__41_ */ +{0x0F12, 0x0214}, /* AfitBaseVals_1__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_1__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_1__44_ */ +{0x0F12, 0x0002}, /* AfitBaseVals_1__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_1__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_1__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_1__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_1__50_ */ +{0x0F12, 0x0308}, /* AfitBaseVals_1__51_ */ +{0x0F12, 0x1E65}, /* AfitBaseVals_1__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_1__53_ */ +{0x0F12, 0x0A03}, /* AfitBaseVals_1__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_1__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_1__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_1__57_ */ +{0x0F12, 0x324D}, /* AfitBaseVals_1__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_1__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_1__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_1__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_1__63_ */ +{0x0F12, 0x2F34}, /* AfitBaseVals_1__64_ */ +{0x0F12, 0x0504}, /* AfitBaseVals_1__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_1__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_1__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_1__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_1__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_1__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_1__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_1__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_1__74_ */ +{0x0F12, 0x1414}, /* AfitBaseVals_1__75_ */ +{0x0F12, 0x0504}, /* AfitBaseVals_1__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_1__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_1__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_1__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_1__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_1__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_1__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__0_ Brightness[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__1_ Contrast[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__2_ Saturaion[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__3_ Sharp_Blur[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__4_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_2__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_2__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_2__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_2__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_2__12_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_2__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_2__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_2__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_2__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_2__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_2__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_2__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__21_ */ +{0x0F12, 0x0019}, /* AfitBaseVals_2__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_2__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__25_ */ +{0x0F12, 0x0019}, /* AfitBaseVals_2__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_2__27_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_2__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_2__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_2__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_2__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_2__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_2__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_2__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_2__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_2__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_2__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_2__44_ */ +{0x0F12, 0x0002}, /* AfitBaseVals_2__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_2__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_2__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_2__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_2__50_ */ +{0x0F12, 0x0208}, /* AfitBaseVals_2__51_ */ +{0x0F12, 0x1E4B}, /* AfitBaseVals_2__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_2__53_ */ +{0x0F12, 0x0A05}, /* AfitBaseVals_2__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_2__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_2__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_2__57_ */ +{0x0F12, 0x324D}, /* AfitBaseVals_2__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_2__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_2__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_2__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_2__63_ */ +{0x0F12, 0x1E23}, /* AfitBaseVals_2__64_ */ +{0x0F12, 0x0505}, /* AfitBaseVals_2__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_2__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_2__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_2__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_2__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_2__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_2__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_2__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_2__74_ */ +{0x0F12, 0x1E23}, /* AfitBaseVals_2__75_ */ +{0x0F12, 0x0505}, /* AfitBaseVals_2__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_2__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_2__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_2__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_2__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_2__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_2__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__0_ Brightness[3] */ +{0x0F12, 0x0018}, /* 0000 AfitBaseVals_3__1_ Contrast[3] */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__2_ Saturaion[3] */ +{0x0F12, 0x0004}, /* 0000 AfitBaseVals_3__3_ Sharp_Blur[3] */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__4_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_3__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_3__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_3__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_3__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_3__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_3__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_3__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_3__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_3__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_3__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_3__19_ */ +{0x0F12, 0x009F}, /* AfitBaseVals_3__20_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__21_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_3__23_ */ +{0x0F12, 0x0037}, /* AfitBaseVals_3__24_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__25_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_3__27_ */ +{0x0F12, 0x0037}, /* AfitBaseVals_3__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_3__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_3__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_3__34_ */ +{0x0F12, 0x07A0}, /* AfitBaseVals_3__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_3__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_3__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_3__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_3__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_3__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_3__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_3__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_3__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_3__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_3__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_3__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_3__50_ */ +{0x0F12, 0x0108}, /* AfitBaseVals_3__51_ */ +{0x0F12, 0x1E32}, /* AfitBaseVals_3__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_3__53_ */ +{0x0F12, 0x0A05}, /* AfitBaseVals_3__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_3__55_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__56_ */ +{0x0F12, 0x0328}, /* AfitBaseVals_3__57_ */ +{0x0F12, 0x324C}, /* AfitBaseVals_3__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_3__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_3__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_3__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_3__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_3__63_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_3__64_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_3__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_3__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_3__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_3__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_3__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_3__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_3__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_3__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_3__74_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_3__75_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_3__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_3__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_3__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_3__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_3__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_3__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_3__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__0_ Brightness[4] */ +{0x0F12, 0x0014}, /* 0000 AfitBaseVals_4__1_ Contrast[4] */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__2_ Saturaion[4] */ +{0x0F12, 0x0008}, /* 0000 AfitBaseVals_4__3_ Sharp_Blur[4] */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__4_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_4__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_4__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_4__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_4__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_4__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_4__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_4__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_4__14_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_4__15_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_4__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_4__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_4__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_4__19_ */ +{0x0F12, 0x00B4}, /* AfitBaseVals_4__20_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__21_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_4__23_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_4__24_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__25_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_4__27_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_4__28_ */ +{0x0F12, 0x2B23}, /* AfitBaseVals_4__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_4__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_4__34_ */ +{0x0F12, 0x0B84}, /* AfitBaseVals_4__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_4__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_4__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_4__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_4__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_4__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_4__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_4__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_4__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_4__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_4__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_4__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_4__50_ */ +{0x0F12, 0x0108}, /* AfitBaseVals_4__51_ */ +{0x0F12, 0x1E1E}, /* AfitBaseVals_4__52_ */ +{0x0F12, 0x1419}, /* AfitBaseVals_4__53_ */ +{0x0F12, 0x0A0A}, /* AfitBaseVals_4__54_ */ +{0x0F12, 0x0800}, /* AfitBaseVals_4__55_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__56_ */ +{0x0F12, 0x0328}, /* AfitBaseVals_4__57_ */ +{0x0F12, 0x324C}, /* AfitBaseVals_4__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_4__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_4__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_4__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_4__62_ */ +{0x0F12, 0x6464}, /* AfitBaseVals_4__63_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_4__64_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_4__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_4__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_4__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_4__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_4__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_4__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_4__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_4__73_ */ +{0x0F12, 0x6464}, /* AfitBaseVals_4__74_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_4__75_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_4__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_4__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_4__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_4__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_4__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_4__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_4__83_ */ +{0x0F12, 0x7F5E}, /* ConstAfitBaseVals_0_ */ +{0x0F12, 0xFEEE}, /* ConstAfitBaseVals_1_ */ +{0x0F12, 0xD9B7}, /* ConstAfitBaseVals_2_ */ +{0x0F12, 0x0472}, /* ConstAfitBaseVals_3_ */ +{0x0F12, 0x0001}, /* ConstAfitBaseVals_4_ */ + +/*************************************/ +/* 17.JPEG Thumnail Setting */ +/*************************************/ + +/*************************************/ +/* 18.Input Size Setting */ +/*************************************/ + +/************************************* + * 19.Preview & Capture Configration Setting + ************************************* + */ +/* Preview config[0] 640X480 8fps fixed */ +{0x002A, 0x01BE}, +{0x0F12, 0x0280}, /* REG_0TC_PCFG_usWidth 500:1280; 280:640 */ +{0x0F12, 0x01E0}, /* REG_0TC_PCFG_usHeight 3C0:960; 1E0:480 */ +{0x0F12, 0x0005}, /* REG_0TC_PCFG_Format 5:YUV422; 7:RAW10 */ +{0x002A, 0x01C8}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uClockInd */ +{0x002A, 0x01C4}, +{0x0F12, 0x0052}, /* REG_0TC_PCFG_PVIMask 52:YUV422, 42:RAW10 */ +{0x002A, 0x01D4}, +{0x0F12, 0x0002}, +{0x002A, 0x01D2}, +{0x0F12, 0x0002}, +{0x002A, 0x01D8}, +{0x0F12, 0x04E2}, +{0x002A, 0x01D6}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_usMinFrTimeMsecMult10 */ +{0x002A, 0x01E8}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uPrevMirror */ +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uCaptureMirror */ + +/* Preview config[1] 1280X960 7.5fps */ +{0x002A, 0x01EE}, +{0x0F12, 0x0500}, /* 1280 */ +{0x0F12, 0x03C0}, /* 960 */ +{0x0F12, 0x0005}, /* YUV422 */ +{0x002A, 0x01F8}, +{0x0F12, 0x0000}, +{0x002A, 0x01F4}, +{0x0F12, 0x0052}, +{0x002A, 0x0204}, +{0x0F12, 0x0002}, /* 1b: FR (bin) 2b: Quality (no-bin) */ +{0x002A, 0x0202}, +{0x0F12, 0x0001}, +{0x002A, 0x0208}, +{0x0F12, 0x0535}, +{0x002A, 0x0206}, +{0x0F12, 0x0000}, +{0x002A, 0x0218}, +{0x0F12, 0x0000}, /* REG_1TC_PCFG_uPrevMirror */ +{0x0F12, 0x0000}, /* REG_1TC_PCFG_uCaptureMirror */ + +/* Capture config[0] 1280x960 8fps */ +/* {0x002A, 0x02AE}, */ +/* {0x0F12, 0x0001}, */ /* Capture mode AE On */ +{0x002A, 0x02B0}, +{0x0F12, 0x0500}, /* REG_0TC_CCFG_usWidth 500:1280; 280:640 */ +{0x0F12, 0x03C0}, /* REG_0TC_CCFG_usHeight 3C0:960; 1E0:480 */ +{0x0F12, 0x0005}, /* REG_0TC_CCFG_Format 5:YUV422; 7:RAW10 */ +{0x002A, 0x02BA}, +{0x0F12, 0x0000}, /* REG_0TC_CCFG_uClockInd */ +{0x002A, 0x02B6}, +{0x0F12, 0x0052}, /* REG_0TC_CCFG_PVIMask 52:YUV422; 42:RAW10 */ +{0x002A, 0x02C6}, +{0x0F12, 0x0002}, +{0x002A, 0x02C4}, +{0x0F12, 0x0002}, +{0x002A, 0x02CA}, +{0x0F12, 0x04E2}, +{0x002A, 0x02C8}, +{0x0F12, 0x0000}, /* REG_0TC_CCFG_usMinFrTimeMsecMult10 */ + +/*************************************/ +/* 20.Clock Setting */ +/*************************************/ +/* Input Clock (Mclk) */ +{0x002A, 0x012E}, +{0x0F12, 0x5DC0}, /* REG_TC_IPRM_InClockLSBs */ +{0x0F12, 0x0000}, /* REG_TC_IPRM_InClockMSBs */ +{0x002A, 0x0146}, +{0x0F12, 0x0000}, /* REG_TC_IPRM_UseNPviClocks */ +{0x0F12, 0x0001}, /* REG_TC_IPRM_UseNMipiClocks */ + +/* System Clock & Output clock (Pclk) */ +{0x002A, 0x014C}, +{0x0F12, 0x1B58}, /* REG_TC_IPRM_OpClk4KHz_0 */ +{0x002A, 0x0152}, +{0x0F12, 0x36B0}, /* REG_TC_IPRM_MinOutRate4KHz_0 */ +{0x002A, 0x014E}, +{0x0F12, 0x36B0}, /* REG_TC_IPRM_MaxOutRate4KHz_0 */ +{0x002A, 0x01A8}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActivePrevConfig */ +{0x002A, 0x01B0}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActiveCapConfig */ +{0x002A, 0x019E}, +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreview */ +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreviewChanged */ +{0x002A, 0x0164}, +{0x0F12, 0x0001}, /* REG_TC_IPRM_InitParamsUpdated */ +{0x0028, 0xD000}, +{0x002A, 0x1000}, +{0x0F12, 0x0001}, /* Set host interrupt */ +{0xffff, 0x000a}, + +/* End of SKT VT-Call init */ +}; + + + +struct s5k8aay_short_t s5k8aay_wifi_vt_common[] = { +/* Start of Wifi VT-Call init */ + +/**************************************/ +/* 01.Start Setting */ +/**************************************/ +{0xFCFC, 0xD000}, +{0x0010, 0x0001}, /* S/W Reset */ +{0xFCFC, 0x0000}, +{0x0000, 0x0000}, /* Simmian bug workaround */ + +{0xFCFC, 0xD000}, +{0x1030, 0x0000}, /* contint_host_int */ +{0x0014, 0x0001}, + +{0xffff, 0x0001}, /* Delay 1ms */ + +/**************************************/ +/*02.ETC Setting */ +/**************************************/ +{0x002A, 0x1278}, +{0x0F12, 0xAAF0}, /* gisp_dadlc_config Ladlc mode average*/ + +/********************************************** + * 03.Analog Setting & ASP Control + ********************************************** + * This register is for FACTORY ONLY. + * If you change it without prior notification + * YOU are RESPONSIBLE for the FAILURE that + * will happen in the future + * For CDS Timing + ********************************************** + */ +{0x002A, 0x0EC6}, +{0x0F12, 0x000B}, /* 11d aig_fdba_ptr0 */ +{0x002A, 0x0ECE}, +{0x0F12, 0x000B}, /* 11d aig_fdbb_ptr0 */ +{0x002A, 0x0F16}, +{0x0F12, 0x002B}, /* 43d aig_sfdba_reg0 */ +{0x002A, 0x0F1E}, +{0x0F12, 0x002B}, /* 43d aig_sfdbb_reg0 */ +{0x002A, 0x0EC8}, +{0x0F12, 0x000B}, /* 11d aig_fdba_ptr0 */ +{0x002A, 0x0ED0}, +{0x0F12, 0x033F}, /* 831d aig_fdbb_ptr0 */ +{0x002A, 0x0F18}, +{0x0F12, 0x0366}, /* 870d aig_sfdba_reg0 */ +{0x002A, 0x0F20}, +{0x0F12, 0x0032}, /* 50d aig_sfdbb_reg0 */ + +/* For Other Analog Settings */ +{0x002A, 0x0E38}, +{0x0F12, 0x0476}, /* senHal_RegCompBiasNormSf CDS bias */ +{0x0F12, 0x0476}, /* senHal_RegCompBiasYAv CDS bias */ +{0x002A, 0x0AA0}, +{0x0F12, 0x0001}, /* setot_bUseDigitalHbin 1-Digital, 0-Analog */ +{0x002A, 0x0E2C}, +{0x0F12, 0x0001}, +{0x002A, 0x1250}, +{0x0F12, 0xFFFF}, /* senHal_Bls_nSpExpLines */ +{0x002A, 0x1202}, +{0x0F12, 0x0010}, /* senHal_Dblr_VcoFreqMHZ */ + +/**************************************/ +/* 04.Trap and Patch */ +/**************************************/ +/* Start of Patch data */ +{0x0028, 0x7000}, +{0x002A, 0x2470}, +{0x0F12, 0xB510}, /* 70002470 */ +{0x0F12, 0x490D}, /* 70002472 */ +{0x0F12, 0x480D}, /* 70002474 */ +{0x0F12, 0xF000}, /* 70002476 */ +{0x0F12, 0xF96D}, /* 70002478 */ +{0x0F12, 0x490D}, /* 7000247A */ +{0x0F12, 0x480D}, /* 7000247C */ +{0x0F12, 0xF000}, /* 7000247E */ +{0x0F12, 0xF969}, /* 70002480 */ +{0x0F12, 0x490D}, /* 70002482 */ +{0x0F12, 0x480D}, /* 70002484 */ +{0x0F12, 0x6341}, /* 70002486 */ +{0x0F12, 0x490D}, /* 70002488 */ +{0x0F12, 0x480E}, /* 7000248A */ +{0x0F12, 0xF000}, /* 7000248C */ +{0x0F12, 0xF962}, /* 7000248E */ +{0x0F12, 0x490D}, /* 70002490 */ +{0x0F12, 0x480E}, /* 70002492 */ +{0x0F12, 0xF000}, /* 70002494 */ +{0x0F12, 0xF95E}, /* 70002496 */ +{0x0F12, 0x490D}, /* 70002498 */ +{0x0F12, 0x480E}, /* 7000249A */ +{0x0F12, 0xF000}, /* 7000249C */ +{0x0F12, 0xF95A}, /* 7000249E */ +{0x0F12, 0xBC10}, /* 700024A0 */ +{0x0F12, 0xBC08}, /* 700024A2 */ +{0x0F12, 0x4718}, /* 700024A4 */ +{0x0F12, 0x0000}, /* 700024A6 */ +{0x0F12, 0x26D4}, /* 700024A8 */ +{0x0F12, 0x7000}, /* 700024AA */ +{0x0F12, 0x8EDD}, /* 700024AC */ +{0x0F12, 0x0000}, /* 700024AE */ +{0x0F12, 0x264C}, /* 700024B0 */ +{0x0F12, 0x7000}, /* 700024B2 */ +{0x0F12, 0x8725}, /* 700024B4 */ +{0x0F12, 0x0000}, /* 700024B6 */ +{0x0F12, 0x25EC}, /* 700024B8 */ +{0x0F12, 0x7000}, /* 700024BA */ +{0x0F12, 0x0080}, /* 700024BC */ +{0x0F12, 0x7000}, /* 700024BE */ +{0x0F12, 0x2540}, /* 700024C0 */ +{0x0F12, 0x7000}, /* 700024C2 */ +{0x0F12, 0xA6EF}, /* 700024C4 */ +{0x0F12, 0x0000}, /* 700024C6 */ +{0x0F12, 0x250C}, /* 700024C8 */ +{0x0F12, 0x7000}, /* 700024CA */ +{0x0F12, 0xA0F1}, /* 700024CC */ +{0x0F12, 0x0000}, /* 700024CE */ +{0x0F12, 0x24D8}, /* 700024D0 */ +{0x0F12, 0x7000}, /* 700024D2 */ +{0x0F12, 0x058F}, /* 700024D4 */ +{0x0F12, 0x0000}, /* 700024D6 */ +{0x0F12, 0x4010}, /* 700024D8 */ +{0x0F12, 0xE92D}, /* 700024DA */ +{0x0F12, 0x00A0}, /* 700024DC */ +{0x0F12, 0xEB00}, /* 700024DE */ +{0x0F12, 0x023C}, /* 700024E0 */ +{0x0F12, 0xE59F}, /* 700024E2 */ +{0x0F12, 0x00B2}, /* 700024E4 */ +{0x0F12, 0xE1D0}, /* 700024E6 */ +{0x0F12, 0x0000}, /* 700024E8 */ +{0x0F12, 0xE350}, /* 700024EA */ +{0x0F12, 0x0004}, /* 700024EC */ +{0x0F12, 0x0A00}, /* 700024EE */ +{0x0F12, 0x0080}, /* 700024F0 */ +{0x0F12, 0xE310}, /* 700024F2 */ +{0x0F12, 0x0002}, /* 700024F4 */ +{0x0F12, 0x1A00}, /* 700024F6 */ +{0x0F12, 0x1228}, /* 700024F8 */ +{0x0F12, 0xE59F}, /* 700024FA */ +{0x0F12, 0x0001}, /* 700024FC */ +{0x0F12, 0xE3A0}, /* 700024FE */ +{0x0F12, 0x0DB2}, /* 70002500 */ +{0x0F12, 0xE1C1}, /* 70002502 */ +{0x0F12, 0x4010}, /* 70002504 */ +{0x0F12, 0xE8BD}, /* 70002506 */ +{0x0F12, 0xFF1E}, /* 70002508 */ +{0x0F12, 0xE12F}, /* 7000250A */ +{0x0F12, 0x4010}, /* 7000250C */ +{0x0F12, 0xE92D}, /* 7000250E */ +{0x0F12, 0x4000}, /* 70002510 */ +{0x0F12, 0xE590}, /* 70002512 */ +{0x0F12, 0x0004}, /* 70002514 */ +{0x0F12, 0xE1A0}, /* 70002516 */ +{0x0F12, 0x0094}, /* 70002518 */ +{0x0F12, 0xEB00}, /* 7000251A */ +{0x0F12, 0x0208}, /* 7000251C */ +{0x0F12, 0xE59F}, /* 7000251E */ +{0x0F12, 0x0000}, /* 70002520 */ +{0x0F12, 0xE5D0}, /* 70002522 */ +{0x0F12, 0x0000}, /* 70002524 */ +{0x0F12, 0xE350}, /* 70002526 */ +{0x0F12, 0x0002}, /* 70002528 */ +{0x0F12, 0x0A00}, /* 7000252A */ +{0x0F12, 0x0004}, /* 7000252C */ +{0x0F12, 0xE594}, /* 7000252E */ +{0x0F12, 0x00A0}, /* 70002530 */ +{0x0F12, 0xE1A0}, /* 70002532 */ +{0x0F12, 0x0004}, /* 70002534 */ +{0x0F12, 0xE584}, /* 70002536 */ +{0x0F12, 0x4010}, /* 70002538 */ +{0x0F12, 0xE8BD}, /* 7000253A */ +{0x0F12, 0xFF1E}, /* 7000253C */ +{0x0F12, 0xE12F}, /* 7000253E */ +{0x0F12, 0x4070}, /* 70002540 */ +{0x0F12, 0xE92D}, /* 70002542 */ +{0x0F12, 0x0000}, /* 70002544 */ +{0x0F12, 0xE590}, /* 70002546 */ +{0x0F12, 0x0800}, /* 70002548 */ +{0x0F12, 0xE1A0}, /* 7000254A */ +{0x0F12, 0x0820}, /* 7000254C */ +{0x0F12, 0xE1A0}, /* 7000254E */ +{0x0F12, 0x4041}, /* 70002550 */ +{0x0F12, 0xE280}, /* 70002552 */ +{0x0F12, 0x01D4}, /* 70002554 */ +{0x0F12, 0xE59F}, /* 70002556 */ +{0x0F12, 0x11B8}, /* 70002558 */ +{0x0F12, 0xE1D0}, /* 7000255A */ +{0x0F12, 0x51B6}, /* 7000255C */ +{0x0F12, 0xE1D0}, /* 7000255E */ +{0x0F12, 0x0005}, /* 70002560 */ +{0x0F12, 0xE041}, /* 70002562 */ +{0x0F12, 0x0094}, /* 70002564 */ +{0x0F12, 0xE000}, /* 70002566 */ +{0x0F12, 0x1D11}, /* 70002568 */ +{0x0F12, 0xE3A0}, /* 7000256A */ +{0x0F12, 0x0082}, /* 7000256C */ +{0x0F12, 0xEB00}, /* 7000256E */ +{0x0F12, 0x11B4}, /* 70002570 */ +{0x0F12, 0xE59F}, /* 70002572 */ +{0x0F12, 0x1000}, /* 70002574 */ +{0x0F12, 0xE5D1}, /* 70002576 */ +{0x0F12, 0x0000}, /* 70002578 */ +{0x0F12, 0xE351}, /* 7000257A */ +{0x0F12, 0x0000}, /* 7000257C */ +{0x0F12, 0x0A00}, /* 7000257E */ +{0x0F12, 0x00A0}, /* 70002580 */ +{0x0F12, 0xE1A0}, /* 70002582 */ +{0x0F12, 0x219C}, /* 70002584 */ +{0x0F12, 0xE59F}, /* 70002586 */ +{0x0F12, 0x3FB0}, /* 70002588 */ +{0x0F12, 0xE1D2}, /* 7000258A */ +{0x0F12, 0x0000}, /* 7000258C */ +{0x0F12, 0xE353}, /* 7000258E */ +{0x0F12, 0x0003}, /* 70002590 */ +{0x0F12, 0x0A00}, /* 70002592 */ +{0x0F12, 0x3198}, /* 70002594 */ +{0x0F12, 0xE59F}, /* 70002596 */ +{0x0F12, 0x5BB2}, /* 70002598 */ +{0x0F12, 0xE1C3}, /* 7000259A */ +{0x0F12, 0xC000}, /* 7000259C */ +{0x0F12, 0xE085}, /* 7000259E */ +{0x0F12, 0xCBB4}, /* 700025A0 */ +{0x0F12, 0xE1C3}, /* 700025A2 */ +{0x0F12, 0x0000}, /* 700025A4 */ +{0x0F12, 0xE351}, /* 700025A6 */ +{0x0F12, 0x0000}, /* 700025A8 */ +{0x0F12, 0x0A00}, /* 700025AA */ +{0x0F12, 0x0080}, /* 700025AC */ +{0x0F12, 0xE1A0}, /* 700025AE */ +{0x0F12, 0x1DBC}, /* 700025B0 */ +{0x0F12, 0xE1D2}, /* 700025B2 */ +{0x0F12, 0x3EB4}, /* 700025B4 */ +{0x0F12, 0xE1D2}, /* 700025B6 */ +{0x0F12, 0x2EB2}, /* 700025B8 */ +{0x0F12, 0xE1D2}, /* 700025BA */ +{0x0F12, 0x0193}, /* 700025BC */ +{0x0F12, 0xE001}, /* 700025BE */ +{0x0F12, 0x0092}, /* 700025C0 */ +{0x0F12, 0xE000}, /* 700025C2 */ +{0x0F12, 0x2811}, /* 700025C4 */ +{0x0F12, 0xE3A0}, /* 700025C6 */ +{0x0F12, 0x0194}, /* 700025C8 */ +{0x0F12, 0xE001}, /* 700025CA */ +{0x0F12, 0x0092}, /* 700025CC */ +{0x0F12, 0xE000}, /* 700025CE */ +{0x0F12, 0x11A1}, /* 700025D0 */ +{0x0F12, 0xE1A0}, /* 700025D2 */ +{0x0F12, 0x01A0}, /* 700025D4 */ +{0x0F12, 0xE1A0}, /* 700025D6 */ +{0x0F12, 0x0067}, /* 700025D8 */ +{0x0F12, 0xEB00}, /* 700025DA */ +{0x0F12, 0x1154}, /* 700025DC */ +{0x0F12, 0xE59F}, /* 700025DE */ +{0x0F12, 0x02B4}, /* 700025E0 */ +{0x0F12, 0xE1C1}, /* 700025E2 */ +{0x0F12, 0x4070}, /* 700025E4 */ +{0x0F12, 0xE8BD}, /* 700025E6 */ +{0x0F12, 0xFF1E}, /* 700025E8 */ +{0x0F12, 0xE12F}, /* 700025EA */ +{0x0F12, 0x4010}, /* 700025EC */ +{0x0F12, 0xE92D}, /* 700025EE */ +{0x0F12, 0x0063}, /* 700025F0 */ +{0x0F12, 0xEB00}, /* 700025F2 */ +{0x0F12, 0x213C}, /* 700025F4 */ +{0x0F12, 0xE59F}, /* 700025F6 */ +{0x0F12, 0x14B0}, /* 700025F8 */ +{0x0F12, 0xE1D2}, /* 700025FA */ +{0x0F12, 0x0080}, /* 700025FC */ +{0x0F12, 0xE311}, /* 700025FE */ +{0x0F12, 0x0005}, /* 70002600 */ +{0x0F12, 0x0A00}, /* 70002602 */ +{0x0F12, 0x0130}, /* 70002604 */ +{0x0F12, 0xE59F}, /* 70002606 */ +{0x0F12, 0x00B0}, /* 70002608 */ +{0x0F12, 0xE1D0}, /* 7000260A */ +{0x0F12, 0x0001}, /* 7000260C */ +{0x0F12, 0xE350}, /* 7000260E */ +{0x0F12, 0x0001}, /* 70002610 */ +{0x0F12, 0x9A00}, /* 70002612 */ +{0x0F12, 0x0001}, /* 70002614 */ +{0x0F12, 0xE3A0}, /* 70002616 */ +{0x0F12, 0x0000}, /* 70002618 */ +{0x0F12, 0xEA00}, /* 7000261A */ +{0x0F12, 0x0000}, /* 7000261C */ +{0x0F12, 0xE3A0}, /* 7000261E */ +{0x0F12, 0x3104}, /* 70002620 */ +{0x0F12, 0xE59F}, /* 70002622 */ +{0x0F12, 0x0000}, /* 70002624 */ +{0x0F12, 0xE5C3}, /* 70002626 */ +{0x0F12, 0x0000}, /* 70002628 */ +{0x0F12, 0xE5D3}, /* 7000262A */ +{0x0F12, 0x0000}, /* 7000262C */ +{0x0F12, 0xE350}, /* 7000262E */ +{0x0F12, 0x0003}, /* 70002630 */ +{0x0F12, 0x0A00}, /* 70002632 */ +{0x0F12, 0x0080}, /* 70002634 */ +{0x0F12, 0xE3C1}, /* 70002636 */ +{0x0F12, 0x1100}, /* 70002638 */ +{0x0F12, 0xE59F}, /* 7000263A */ +{0x0F12, 0x04B0}, /* 7000263C */ +{0x0F12, 0xE1C2}, /* 7000263E */ +{0x0F12, 0x00B2}, /* 70002640 */ +{0x0F12, 0xE1C1}, /* 70002642 */ +{0x0F12, 0x4010}, /* 70002644 */ +{0x0F12, 0xE8BD}, /* 70002646 */ +{0x0F12, 0xFF1E}, /* 70002648 */ +{0x0F12, 0xE12F}, /* 7000264A */ +{0x0F12, 0x41F0}, /* 7000264C */ +{0x0F12, 0xE92D}, /* 7000264E */ +{0x0F12, 0x1000}, /* 70002650 */ +{0x0F12, 0xE590}, /* 70002652 */ +{0x0F12, 0xC801}, /* 70002654 */ +{0x0F12, 0xE1A0}, /* 70002656 */ +{0x0F12, 0xC82C}, /* 70002658 */ +{0x0F12, 0xE1A0}, /* 7000265A */ +{0x0F12, 0x1004}, /* 7000265C */ +{0x0F12, 0xE590}, /* 7000265E */ +{0x0F12, 0x1801}, /* 70002660 */ +{0x0F12, 0xE1A0}, /* 70002662 */ +{0x0F12, 0x1821}, /* 70002664 */ +{0x0F12, 0xE1A0}, /* 70002666 */ +{0x0F12, 0x4008}, /* 70002668 */ +{0x0F12, 0xE590}, /* 7000266A */ +{0x0F12, 0x500C}, /* 7000266C */ +{0x0F12, 0xE590}, /* 7000266E */ +{0x0F12, 0x2004}, /* 70002670 */ +{0x0F12, 0xE1A0}, /* 70002672 */ +{0x0F12, 0x3005}, /* 70002674 */ +{0x0F12, 0xE1A0}, /* 70002676 */ +{0x0F12, 0x000C}, /* 70002678 */ +{0x0F12, 0xE1A0}, /* 7000267A */ +{0x0F12, 0x0043}, /* 7000267C */ +{0x0F12, 0xEB00}, /* 7000267E */ +{0x0F12, 0x60BC}, /* 70002680 */ +{0x0F12, 0xE59F}, /* 70002682 */ +{0x0F12, 0x00B2}, /* 70002684 */ +{0x0F12, 0xE1D6}, /* 70002686 */ +{0x0F12, 0x0000}, /* 70002688 */ +{0x0F12, 0xE350}, /* 7000268A */ +{0x0F12, 0x000E}, /* 7000268C */ +{0x0F12, 0x0A00}, /* 7000268E */ +{0x0F12, 0x00B0}, /* 70002690 */ +{0x0F12, 0xE59F}, /* 70002692 */ +{0x0F12, 0x05B4}, /* 70002694 */ +{0x0F12, 0xE1D0}, /* 70002696 */ +{0x0F12, 0x0002}, /* 70002698 */ +{0x0F12, 0xE350}, /* 7000269A */ +{0x0F12, 0x000A}, /* 7000269C */ +{0x0F12, 0x1A00}, /* 7000269E */ +{0x0F12, 0x70A4}, /* 700026A0 */ +{0x0F12, 0xE59F}, /* 700026A2 */ +{0x0F12, 0x10F4}, /* 700026A4 */ +{0x0F12, 0xE1D6}, /* 700026A6 */ +{0x0F12, 0x26B0}, /* 700026A8 */ +{0x0F12, 0xE1D7}, /* 700026AA */ +{0x0F12, 0x00F0}, /* 700026AC */ +{0x0F12, 0xE1D4}, /* 700026AE */ +{0x0F12, 0x0039}, /* 700026B0 */ +{0x0F12, 0xEB00}, /* 700026B2 */ +{0x0F12, 0x00B0}, /* 700026B4 */ +{0x0F12, 0xE1C4}, /* 700026B6 */ +{0x0F12, 0x26B0}, /* 700026B8 */ +{0x0F12, 0xE1D7}, /* 700026BA */ +{0x0F12, 0x10F6}, /* 700026BC */ +{0x0F12, 0xE1D6}, /* 700026BE */ +{0x0F12, 0x00F0}, /* 700026C0 */ +{0x0F12, 0xE1D5}, /* 700026C2 */ +{0x0F12, 0x0034}, /* 700026C4 */ +{0x0F12, 0xEB00}, /* 700026C6 */ +{0x0F12, 0x00B0}, /* 700026C8 */ +{0x0F12, 0xE1C5}, /* 700026CA */ +{0x0F12, 0x41F0}, /* 700026CC */ +{0x0F12, 0xE8BD}, /* 700026CE */ +{0x0F12, 0xFF1E}, /* 700026D0 */ +{0x0F12, 0xE12F}, /* 700026D2 */ +{0x0F12, 0x4010}, /* 700026D4 */ +{0x0F12, 0xE92D}, /* 700026D6 */ +{0x0F12, 0x4000}, /* 700026D8 */ +{0x0F12, 0xE1A0}, /* 700026DA */ +{0x0F12, 0x1004}, /* 700026DC */ +{0x0F12, 0xE594}, /* 700026DE */ +{0x0F12, 0x005C}, /* 700026E0 */ +{0x0F12, 0xE59F}, /* 700026E2 */ +{0x0F12, 0x00B0}, /* 700026E4 */ +{0x0F12, 0xE1D0}, /* 700026E6 */ +{0x0F12, 0x0000}, /* 700026E8 */ +{0x0F12, 0xE350}, /* 700026EA */ +{0x0F12, 0x0008}, /* 700026EC */ +{0x0F12, 0x0A00}, /* 700026EE */ +{0x0F12, 0x0054}, /* 700026F0 */ +{0x0F12, 0xE59F}, /* 700026F2 */ +{0x0F12, 0x3001}, /* 700026F4 */ +{0x0F12, 0xE1A0}, /* 700026F6 */ +{0x0F12, 0x2068}, /* 700026F8 */ +{0x0F12, 0xE590}, /* 700026FA */ +{0x0F12, 0x004C}, /* 700026FC */ +{0x0F12, 0xE59F}, /* 700026FE */ +{0x0F12, 0x1005}, /* 70002700 */ +{0x0F12, 0xE3A0}, /* 70002702 */ +{0x0F12, 0x0027}, /* 70002704 */ +{0x0F12, 0xEB00}, /* 70002706 */ +{0x0F12, 0x0000}, /* 70002708 */ +{0x0F12, 0xE584}, /* 7000270A */ +{0x0F12, 0x4010}, /* 7000270C */ +{0x0F12, 0xE8BD}, /* 7000270E */ +{0x0F12, 0xFF1E}, /* 70002710 */ +{0x0F12, 0xE12F}, /* 70002712 */ +{0x0F12, 0x0000}, /* 70002714 */ +{0x0F12, 0xE594}, /* 70002716 */ +{0x0F12, 0x0025}, /* 70002718 */ +{0x0F12, 0xEB00}, /* 7000271A */ +{0x0F12, 0x0000}, /* 7000271C */ +{0x0F12, 0xE584}, /* 7000271E */ +{0x0F12, 0xFFF9}, /* 70002720 */ +{0x0F12, 0xEAFF}, /* 70002722 */ +{0x0F12, 0x1728}, /* 70002724 */ +{0x0F12, 0x7000}, /* 70002726 */ +{0x0F12, 0x112C}, /* 70002728 */ +{0x0F12, 0x7000}, /* 7000272A */ +{0x0F12, 0x27C4}, /* 7000272C */ +{0x0F12, 0x7000}, /* 7000272E */ +{0x0F12, 0x122C}, /* 70002730 */ +{0x0F12, 0x7000}, /* 70002732 */ +{0x0F12, 0xF200}, /* 70002734 */ +{0x0F12, 0xD000}, /* 70002736 */ +{0x0F12, 0x2340}, /* 70002738 */ +{0x0F12, 0x7000}, /* 7000273A */ +{0x0F12, 0x0E2C}, /* 7000273C */ +{0x0F12, 0x7000}, /* 7000273E */ +{0x0F12, 0xF400}, /* 70002740 */ +{0x0F12, 0xD000}, /* 70002742 */ +{0x0F12, 0x3370}, /* 70002744 */ +{0x0F12, 0x7000}, /* 70002746 */ +{0x0F12, 0x0CDC}, /* 70002748 */ +{0x0F12, 0x7000}, /* 7000274A */ +{0x0F12, 0x20D4}, /* 7000274C */ +{0x0F12, 0x7000}, /* 7000274E */ +{0x0F12, 0x06D4}, /* 70002750 */ +{0x0F12, 0x7000}, /* 70002752 */ +{0x0F12, 0x4778}, /* 70002754 */ +{0x0F12, 0x46C0}, /* 70002756 */ +{0x0F12, 0xC000}, /* 70002758 */ +{0x0F12, 0xE59F}, /* 7000275A */ +{0x0F12, 0xFF1C}, /* 7000275C */ +{0x0F12, 0xE12F}, /* 7000275E */ +{0x0F12, 0xC091}, /* 70002760 */ +{0x0F12, 0x0000}, /* 70002762 */ +{0x0F12, 0xC000}, /* 70002764 */ +{0x0F12, 0xE59F}, /* 70002766 */ +{0x0F12, 0xFF1C}, /* 70002768 */ +{0x0F12, 0xE12F}, /* 7000276A */ +{0x0F12, 0x058F}, /* 7000276C */ +{0x0F12, 0x0000}, /* 7000276E */ +{0x0F12, 0xC000}, /* 70002770 */ +{0x0F12, 0xE59F}, /* 70002772 */ +{0x0F12, 0xFF1C}, /* 70002774 */ +{0x0F12, 0xE12F}, /* 70002776 */ +{0x0F12, 0xA0F1}, /* 70002778 */ +{0x0F12, 0x0000}, /* 7000277A */ +{0x0F12, 0xF004}, /* 7000277C */ +{0x0F12, 0xE51F}, /* 7000277E */ +{0x0F12, 0xD14C}, /* 70002780 */ +{0x0F12, 0x0000}, /* 70002782 */ +{0x0F12, 0xC000}, /* 70002784 */ +{0x0F12, 0xE59F}, /* 70002786 */ +{0x0F12, 0xFF1C}, /* 70002788 */ +{0x0F12, 0xE12F}, /* 7000278A */ +{0x0F12, 0x2B43}, /* 7000278C */ +{0x0F12, 0x0000}, /* 7000278E */ +{0x0F12, 0xC000}, /* 70002790 */ +{0x0F12, 0xE59F}, /* 70002792 */ +{0x0F12, 0xFF1C}, /* 70002794 */ +{0x0F12, 0xE12F}, /* 70002796 */ +{0x0F12, 0x8725}, /* 70002798 */ +{0x0F12, 0x0000}, /* 7000279A */ +{0x0F12, 0xC000}, /* 7000279C */ +{0x0F12, 0xE59F}, /* 7000279E */ +{0x0F12, 0xFF1C}, /* 700027A0 */ +{0x0F12, 0xE12F}, /* 700027A2 */ +{0x0F12, 0x6777}, /* 700027A4 */ +{0x0F12, 0x0000}, /* 700027A6 */ +{0x0F12, 0xC000}, /* 700027A8 */ +{0x0F12, 0xE59F}, /* 700027AA */ +{0x0F12, 0xFF1C}, /* 700027AC */ +{0x0F12, 0xE12F}, /* 700027AE */ +{0x0F12, 0x8E49}, /* 700027B0 */ +{0x0F12, 0x0000}, /* 700027B2 */ +{0x0F12, 0xC000}, /* 700027B4 */ +{0x0F12, 0xE59F}, /* 700027B6 */ +{0x0F12, 0xFF1C}, /* 700027B8 */ +{0x0F12, 0xE12F}, /* 700027BA */ +{0x0F12, 0x8EDD}, /* 700027BC */ +{0x0F12, 0x0000}, /* 700027BE */ +{0x0F12, 0x90C8}, /* 700027C0 */ +{0x0F12, 0x0000}, /* 700027C2 */ +/* End of Patch Data(Last : 700027C2h) */ +/* Total Size 852 (0x0354) */ +/* Addr : 2470 , Size : 850(352h) */ + +/**************************************/ +/* 05.OTP Control */ +/**************************************/ + +/**************************************/ +/* 06.GAS (Grid Anti-Shading) */ +/**************************************/ +{0x002A, 0x1326}, +{0x0F12, 0x0000}, /* gisp_gos_Enable */ +{0x002A, 0x063A}, +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__0_ Horizon */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__3_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__0_ IncandA */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__3_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__0_ WW */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__3_ */ +{0x0F12, 0x00E8}, /* TVAR_ash_GASAlpha_3__0_ CW */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__3_ */ +{0x0F12, 0x00E8}, /* TVAR_ash_GASAlpha_4__0_ D50 */ +{0x0F12, 0x00F8}, /* TVAR_ash_GASAlpha_4__1_ */ +{0x0F12, 0x00F8}, /* TVAR_ash_GASAlpha_4__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_4__3_ */ +{0x0F12, 0x00F0}, /* TVAR_ash_GASAlpha_5__0_ D65 */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__3_ */ +{0x0F12, 0x00F0}, /* TVAR_ash_GASAlpha_6__0_ D75 */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__3_ */ +{0x002A, 0x067A}, +{0x0F12, 0x0000}, /* ash_GASBeta_0__0_ Horizon */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__0_ IncandA */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__0_ WW */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__0_ CW */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__0_ D50 */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__0_ D65 */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__0_ D75 */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__3_ */ +{0x002A, 0x06BA}, +{0x0F12, 0x0001}, /*ash_bLumaMode */ +{0x002A, 0x0632}, +{0x0F12, 0x0100}, /* ash_CGrasAlphas_0_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_1_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_2_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_3_ */ +{0x002A, 0x0672}, +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_0_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_3_ */ +{0x002A, 0x06B2}, +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_0_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_1_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_2_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_3_ */ +{0x002A, 0x06D0}, +{0x0F12, 0x000D}, /* ash_uParabolicScalingA */ +{0x0F12, 0x000F}, /* ash_uParabolicScalingB */ +{0x002A, 0x06CC}, +{0x0F12, 0x0280}, /* ash_uParabolicCenterX */ +{0x0F12, 0x01E0}, /* ash_uParabolicCenterY */ +{0x002A, 0x06C6}, +{0x0F12, 0x0001}, /* ash_bParabolicEstimation */ +{0x002A, 0x0624}, +{0x0F12, 0x009D}, /* TVAR_ash_AwbAshCord_0_ Horizon */ +{0x0F12, 0x00D5}, /* TVAR_ash_AwbAshCord_1_ IncandA */ +{0x0F12, 0x0103}, /* TVAR_ash_AwbAshCord_2_ WW */ +{0x0F12, 0x0128}, /* TVAR_ash_AwbAshCord_3_ CW */ +{0x0F12, 0x0166}, /* TVAR_ash_AwbAshCord_4_ D50 */ +{0x0F12, 0x0193}, /* TVAR_ash_AwbAshCord_5_ D65 */ +{0x0F12, 0x01A0}, /* TVAR_ash_AwbAshCord_6_ D75 */ +{0x002A, 0x347C}, +{0x0F12, 0x013B}, /* 011A 012F Tune_wbt_GAS_0_ */ +{0x0F12, 0x0116}, /* 011A 0111 Tune_wbt_GAS_1_ */ +{0x0F12, 0x00D9}, /* 00EE 00D6 Tune_wbt_GAS_2_ */ +{0x0F12, 0x00A6}, /* 00C1 009E Tune_wbt_GAS_3_ */ +{0x0F12, 0x0082}, /* 009E 007A Tune_wbt_GAS_4_ */ +{0x0F12, 0x006C}, /* 008A 0064 Tune_wbt_GAS_5_ */ +{0x0F12, 0x0065}, /* 0083 005D Tune_wbt_GAS_6_ */ +{0x0F12, 0x006C}, /* 008A 0063 Tune_wbt_GAS_7_ */ +{0x0F12, 0x0080}, /* 009E 007B Tune_wbt_GAS_8_ */ +{0x0F12, 0x00A3}, /* 00BF 00A3 Tune_wbt_GAS_9_ */ +{0x0F12, 0x00D4}, /* 00E5 00E3 Tune_wbt_GAS_10_ */ +{0x0F12, 0x010D}, /* 00F9 013B Tune_wbt_GAS_11_ */ +{0x0F12, 0x012E}, /* 0124 018B Tune_wbt_GAS_12_ */ +{0x0F12, 0x0138}, /* 0126 012B Tune_wbt_GAS_13_ */ +{0x0F12, 0x0104}, /* 010E 00F6 Tune_wbt_GAS_14_ */ +{0x0F12, 0x00BE}, /* 00D3 00B2 Tune_wbt_GAS_15_ */ +{0x0F12, 0x0088}, /* 009F 007B Tune_wbt_GAS_16_ */ +{0x0F12, 0x0062}, /* 007C 0057 Tune_wbt_GAS_17_ */ +{0x0F12, 0x004D}, /* 0068 0042 Tune_wbt_GAS_18_ */ +{0x0F12, 0x0046}, /* 0061 0039 Tune_wbt_GAS_19_ */ +{0x0F12, 0x004C}, /* 0068 003F Tune_wbt_GAS_20_ */ +{0x0F12, 0x0060}, /* 007E 0053 Tune_wbt_GAS_21_ */ +{0x0F12, 0x0084}, /* 00A3 007A Tune_wbt_GAS_22_ */ +{0x0F12, 0x00B8}, /* 00C9 00B6 Tune_wbt_GAS_23_ */ +{0x0F12, 0x00F9}, /* 00F0 0110 Tune_wbt_GAS_24_ */ +{0x0F12, 0x012C}, /* 0131 016A Tune_wbt_GAS_25_ */ +{0x0F12, 0x011A}, /* 011C 0114 Tune_wbt_GAS_26_ */ +{0x0F12, 0x00DB}, /* 00EB 00D4 Tune_wbt_GAS_27_ */ +{0x0F12, 0x0093}, /* 00AA 008F Tune_wbt_GAS_28_ */ +{0x0F12, 0x005F}, /* 0075 005A Tune_wbt_GAS_29_ */ +{0x0F12, 0x003C}, /* 0053 0035 Tune_wbt_GAS_30_ */ +{0x0F12, 0x0027}, /* 003F 0020 Tune_wbt_GAS_31_ */ +{0x0F12, 0x0020}, /* 0038 0019 Tune_wbt_GAS_32_ */ +{0x0F12, 0x0026}, /* 0040 001F Tune_wbt_GAS_33_ */ +{0x0F12, 0x003A}, /* 0055 0032 Tune_wbt_GAS_34_ */ +{0x0F12, 0x005C}, /* 007A 0056 Tune_wbt_GAS_35_ */ +{0x0F12, 0x008E}, /* 00A6 008E Tune_wbt_GAS_36_ */ +{0x0F12, 0x00D2}, /* 00D5 00E6 Tune_wbt_GAS_37_ */ +{0x0F12, 0x010E}, /* 0126 0142 Tune_wbt_GAS_38_ */ +{0x0F12, 0x0101}, /* 00F6 0102 Tune_wbt_GAS_39_ */ +{0x0F12, 0x00BF}, /* 00C0 00BE Tune_wbt_GAS_40_ */ +{0x0F12, 0x0077}, /* 007D 0077 Tune_wbt_GAS_41_ */ +{0x0F12, 0x0044}, /* 004D 0045 Tune_wbt_GAS_42_ */ +{0x0F12, 0x0023}, /* 002C 0022 Tune_wbt_GAS_43_ */ +{0x0F12, 0x0011}, /* 001B 000D Tune_wbt_GAS_44_ */ +{0x0F12, 0x000C}, /* 0017 0006 Tune_wbt_GAS_45_ */ +{0x0F12, 0x0010}, /* 001B 000A Tune_wbt_GAS_46_ */ +{0x0F12, 0x0022}, /* 002D 001D Tune_wbt_GAS_47_ */ +{0x0F12, 0x0043}, /* 004E 003F Tune_wbt_GAS_48_ */ +{0x0F12, 0x0074}, /* 0080 0075 Tune_wbt_GAS_49_ */ +{0x0F12, 0x00B7}, /* 00C1 00CC Tune_wbt_GAS_50_ */ +{0x0F12, 0x00F7}, /* 00FF 0126 Tune_wbt_GAS_51_ */ +{0x0F12, 0x00FC}, /* 00EA 00FB Tune_wbt_GAS_52_ */ +{0x0F12, 0x00B7}, /* 00B0 00B7 Tune_wbt_GAS_53_ */ +{0x0F12, 0x006F}, /* 006D 0070 Tune_wbt_GAS_54_ */ +{0x0F12, 0x003C}, /* 003D 003D Tune_wbt_GAS_55_ */ +{0x0F12, 0x001C}, /* 001E 001B Tune_wbt_GAS_56_ */ +{0x0F12, 0x000A}, /* 000F 0007 Tune_wbt_GAS_57_ */ +{0x0F12, 0x0004}, /* 000A 0000 Tune_wbt_GAS_58_ */ +{0x0F12, 0x000A}, /* 0010 0004 Tune_wbt_GAS_59_ */ +{0x0F12, 0x001B}, /* 001E 0015 Tune_wbt_GAS_60_ */ +{0x0F12, 0x003B}, /* 003E 0034 Tune_wbt_GAS_61_ */ +{0x0F12, 0x006C}, /* 006F 006A Tune_wbt_GAS_62_ */ +{0x0F12, 0x00B0}, /* 00B2 00C0 Tune_wbt_GAS_63_ */ +{0x0F12, 0x00F2}, /* 00F1 011B Tune_wbt_GAS_64_ */ +{0x0F12, 0x00EF}, /* 00E0 0102 Tune_wbt_GAS_65_ */ +{0x0F12, 0x00AB}, /* 00A6 00BA Tune_wbt_GAS_66_ */ +{0x0F12, 0x0065}, /* 0063 0073 Tune_wbt_GAS_67_ */ +{0x0F12, 0x0034}, /* 0033 0040 Tune_wbt_GAS_68_ */ +{0x0F12, 0x0015}, /* 0016 001D Tune_wbt_GAS_69_ */ +{0x0F12, 0x0004}, /* 0008 0009 Tune_wbt_GAS_70_ */ +{0x0F12, 0x0000}, /* 0003 0001 Tune_wbt_GAS_71_ */ +{0x0F12, 0x0004}, /* 0009 0006 Tune_wbt_GAS_72_ */ +{0x0F12, 0x0013}, /* 0016 0017 Tune_wbt_GAS_73_ */ +{0x0F12, 0x0033}, /* 0035 0039 Tune_wbt_GAS_74_ */ +{0x0F12, 0x0063}, /* 0066 006F Tune_wbt_GAS_75_ */ +{0x0F12, 0x00A5}, /* 00A7 00C8 Tune_wbt_GAS_76_ */ +{0x0F12, 0x00E5}, /* 00E9 011E Tune_wbt_GAS_77_ */ +{0x0F12, 0x00F7}, /* 00D5 0111 Tune_wbt_GAS_78_ */ +{0x0F12, 0x00B4}, /* 009D 00C8 Tune_wbt_GAS_79_ */ +{0x0F12, 0x006D}, /* 005D 0081 Tune_wbt_GAS_80_ */ +{0x0F12, 0x003C}, /* 002F 004D Tune_wbt_GAS_81_ */ +{0x0F12, 0x001C}, /* 0010 0028 Tune_wbt_GAS_82_ */ +{0x0F12, 0x000B}, /* 0004 0014 Tune_wbt_GAS_83_ */ +{0x0F12, 0x0005}, /* 0001 000B Tune_wbt_GAS_84_ */ +{0x0F12, 0x000A}, /* 0005 0010 Tune_wbt_GAS_85_ */ +{0x0F12, 0x001B}, /* 0013 0022 Tune_wbt_GAS_86_ */ +{0x0F12, 0x003B}, /* 0031 0047 Tune_wbt_GAS_87_ */ +{0x0F12, 0x006B}, /* 005F 007E Tune_wbt_GAS_88_ */ +{0x0F12, 0x00AD}, /* 00A1 00D8 Tune_wbt_GAS_89_ */ +{0x0F12, 0x00ED}, /* 00DF 0131 Tune_wbt_GAS_90_ */ +{0x0F12, 0x010B}, /* 00E9 0129 Tune_wbt_GAS_91_ */ +{0x0F12, 0x00CB}, /* 00B2 00E4 Tune_wbt_GAS_92_ */ +{0x0F12, 0x0085}, /* 006F 009E Tune_wbt_GAS_93_ */ +{0x0F12, 0x0051}, /* 003F 0068 Tune_wbt_GAS_94_ */ +{0x0F12, 0x002F}, /* 0020 0041 Tune_wbt_GAS_95_ */ +{0x0F12, 0x001C}, /* 000F 002B Tune_wbt_GAS_96_ */ +{0x0F12, 0x0016}, /* 000B 0023 Tune_wbt_GAS_97_ */ +{0x0F12, 0x001C}, /* 0010 0028 Tune_wbt_GAS_98_ */ +{0x0F12, 0x002E}, /* 0021 003B Tune_wbt_GAS_99_ */ +{0x0F12, 0x004F}, /* 0041 0063 Tune_wbt_GAS_100_ */ +{0x0F12, 0x0081}, /* 0071 00A0 Tune_wbt_GAS_101_ */ +{0x0F12, 0x00C4}, /* 00B4 00FD Tune_wbt_GAS_102_ */ +{0x0F12, 0x0102}, /* 00F6 015A Tune_wbt_GAS_103_ */ +{0x0F12, 0x0119}, /* 00F9 014A Tune_wbt_GAS_104_ */ +{0x0F12, 0x00DF}, /* 00C2 010D Tune_wbt_GAS_105_ */ +{0x0F12, 0x009B}, /* 0082 00CA Tune_wbt_GAS_106_ */ +{0x0F12, 0x0067}, /* 0053 008F Tune_wbt_GAS_107_ */ +{0x0F12, 0x0045}, /* 0033 0066 Tune_wbt_GAS_108_ */ +{0x0F12, 0x0030}, /* 0021 004F Tune_wbt_GAS_109_ */ +{0x0F12, 0x0029}, /* 001C 0048 Tune_wbt_GAS_110_ */ +{0x0F12, 0x002F}, /* 0022 004E Tune_wbt_GAS_111_ */ +{0x0F12, 0x0043}, /* 0035 0067 Tune_wbt_GAS_112_ */ +{0x0F12, 0x0066}, /* 0056 008F Tune_wbt_GAS_113_ */ +{0x0F12, 0x0098}, /* 0087 00D1 Tune_wbt_GAS_114_ */ +{0x0F12, 0x00D9}, /* 00CA 0132 Tune_wbt_GAS_115_ */ +{0x0F12, 0x010F}, /* 0107 018D Tune_wbt_GAS_116_ */ +{0x0F12, 0x0138}, /* 0108 0159 Tune_wbt_GAS_117_ */ +{0x0F12, 0x010C}, /* 00E0 0141 Tune_wbt_GAS_118_ */ +{0x0F12, 0x00CB}, /* 00A2 0103 Tune_wbt_GAS_119_ */ +{0x0F12, 0x0097}, /* 0072 00C9 Tune_wbt_GAS_120_ */ +{0x0F12, 0x0073}, /* 0052 009E Tune_wbt_GAS_121_ */ +{0x0F12, 0x005C}, /* 0040 0087 Tune_wbt_GAS_122_ */ +{0x0F12, 0x0054}, /* 003A 007D Tune_wbt_GAS_123_ */ +{0x0F12, 0x005B}, /* 0041 0087 Tune_wbt_GAS_124_ */ +{0x0F12, 0x0070}, /* 0055 00A2 Tune_wbt_GAS_125_ */ +{0x0F12, 0x0096}, /* 0077 00D4 Tune_wbt_GAS_126_ */ +{0x0F12, 0x00C9}, /* 00A8 011A Tune_wbt_GAS_127_ */ +{0x0F12, 0x0106}, /* 00E7 017D Tune_wbt_GAS_128_ */ +{0x0F12, 0x012D}, /* 011E 01CF Tune_wbt_GAS_129_ */ +{0x0F12, 0x0147}, /* 0123 0181 Tune_wbt_GAS_130_ */ +{0x0F12, 0x012F}, /* 0100 0169 Tune_wbt_GAS_131_ */ +{0x0F12, 0x00F8}, /* 00CB 0140 Tune_wbt_GAS_132_ */ +{0x0F12, 0x00C5}, /* 009A 0106 Tune_wbt_GAS_133_ */ +{0x0F12, 0x00A1}, /* 0079 00DD Tune_wbt_GAS_134_ */ +{0x0F12, 0x008B}, /* 0067 00C5 Tune_wbt_GAS_135_ */ +{0x0F12, 0x0083}, /* 0060 00BE Tune_wbt_GAS_136_ */ +{0x0F12, 0x008B}, /* 0068 00C8 Tune_wbt_GAS_137_ */ +{0x0F12, 0x00A0}, /* 007B 00E6 Tune_wbt_GAS_138_ */ +{0x0F12, 0x00C2}, /* 009D 011B Tune_wbt_GAS_139_ */ +{0x0F12, 0x00F3}, /* 00CD 015F Tune_wbt_GAS_140_ */ +{0x0F12, 0x0124}, /* 0108 01BC Tune_wbt_GAS_141_ */ +{0x0F12, 0x0139}, /* 0131 0206 Tune_wbt_GAS_142_ */ +{0x0F12, 0x0093}, /* 006C 00A8 Tune_wbt_GAS_143_ */ +{0x0F12, 0x007E}, /* 006E 008F Tune_wbt_GAS_144_ */ +{0x0F12, 0x0062}, /* 005D 006F Tune_wbt_GAS_145_ */ +{0x0F12, 0x004D}, /* 004C 0054 Tune_wbt_GAS_146_ */ +{0x0F12, 0x003E}, /* 0040 0041 Tune_wbt_GAS_147_ */ +{0x0F12, 0x0034}, /* 0037 0036 Tune_wbt_GAS_148_ */ +{0x0F12, 0x0030}, /* 0035 0033 Tune_wbt_GAS_149_ */ +{0x0F12, 0x0032}, /* 0036 0037 Tune_wbt_GAS_150_ */ +{0x0F12, 0x003B}, /* 003F 0045 Tune_wbt_GAS_151_ */ +{0x0F12, 0x0049}, /* 004B 005A Tune_wbt_GAS_152_ */ +{0x0F12, 0x005C}, /* 0053 007A Tune_wbt_GAS_153_ */ +{0x0F12, 0x0077}, /* 0053 00AA Tune_wbt_GAS_154_ */ +{0x0F12, 0x008A}, /* 0070 00E2 Tune_wbt_GAS_155_ */ +{0x0F12, 0x0093}, /* 0075 009E Tune_wbt_GAS_156_ */ +{0x0F12, 0x0077}, /* 006D 007D Tune_wbt_GAS_157_ */ +{0x0F12, 0x0059}, /* 0056 005A Tune_wbt_GAS_158_ */ +{0x0F12, 0x0042}, /* 0043 0041 Tune_wbt_GAS_159_ */ +{0x0F12, 0x0032}, /* 0037 002E Tune_wbt_GAS_160_ */ +{0x0F12, 0x0027}, /* 002F 0022 Tune_wbt_GAS_161_ */ +{0x0F12, 0x0024}, /* 002C 001F Tune_wbt_GAS_162_ */ +{0x0F12, 0x0026}, /* 002F 0022 Tune_wbt_GAS_163_ */ +{0x0F12, 0x002F}, /* 0038 0030 Tune_wbt_GAS_164_ */ +{0x0F12, 0x003D}, /* 0045 0044 Tune_wbt_GAS_165_ */ +{0x0F12, 0x0052}, /* 004E 0063 Tune_wbt_GAS_166_ */ +{0x0F12, 0x006E}, /* 0055 0091 Tune_wbt_GAS_167_ */ +{0x0F12, 0x008B}, /* 007F 00CB Tune_wbt_GAS_168_ */ +{0x0F12, 0x0083}, /* 0077 0093 Tune_wbt_GAS_169_ */ +{0x0F12, 0x0064}, /* 0062 006D Tune_wbt_GAS_170_ */ +{0x0F12, 0x0046}, /* 004A 004A Tune_wbt_GAS_171_ */ +{0x0F12, 0x0030}, /* 0037 0031 Tune_wbt_GAS_172_ */ +{0x0F12, 0x0020}, /* 002A 001E Tune_wbt_GAS_173_ */ +{0x0F12, 0x0016}, /* 0021 0013 Tune_wbt_GAS_174_ */ +{0x0F12, 0x0011}, /* 001E 000F Tune_wbt_GAS_175_ */ +{0x0F12, 0x0014}, /* 0021 0013 Tune_wbt_GAS_176_ */ +{0x0F12, 0x001E}, /* 002B 001F Tune_wbt_GAS_177_ */ +{0x0F12, 0x002D}, /* 003B 0034 Tune_wbt_GAS_178_ */ +{0x0F12, 0x0041}, /* 0046 0051 Tune_wbt_GAS_179_ */ +{0x0F12, 0x005D}, /* 0051 007C Tune_wbt_GAS_180_ */ +{0x0F12, 0x007C}, /* 007F 00B7 Tune_wbt_GAS_181_ */ +{0x0F12, 0x0077}, /* 0062 008A Tune_wbt_GAS_182_ */ +{0x0F12, 0x0057}, /* 004B 0061 Tune_wbt_GAS_183_ */ +{0x0F12, 0x0039}, /* 0034 003E Tune_wbt_GAS_184_ */ +{0x0F12, 0x0024}, /* 0022 0026 Tune_wbt_GAS_185_ */ +{0x0F12, 0x0014}, /* 0014 0013 Tune_wbt_GAS_186_ */ +{0x0F12, 0x000A}, /* 000E 0008 Tune_wbt_GAS_187_ */ +{0x0F12, 0x0007}, /* 000C 0004 Tune_wbt_GAS_188_ */ +{0x0F12, 0x0009}, /* 000D 0007 Tune_wbt_GAS_189_ */ +{0x0F12, 0x0012}, /* 0016 0013 Tune_wbt_GAS_190_ */ +{0x0F12, 0x0021}, /* 0024 0027 Tune_wbt_GAS_191_ */ +{0x0F12, 0x0036}, /* 0036 0045 Tune_wbt_GAS_192_ */ +{0x0F12, 0x0051}, /* 004E 0070 Tune_wbt_GAS_193_ */ +{0x0F12, 0x0070}, /* 0069 00A7 Tune_wbt_GAS_194_ */ +{0x0F12, 0x0077}, /* 005F 0085 Tune_wbt_GAS_195_ */ +{0x0F12, 0x0056}, /* 0048 005D Tune_wbt_GAS_196_ */ +{0x0F12, 0x0038}, /* 002F 003A Tune_wbt_GAS_197_ */ +{0x0F12, 0x0022}, /* 001C 0021 Tune_wbt_GAS_198_ */ +{0x0F12, 0x0013}, /* 0010 0010 Tune_wbt_GAS_199_ */ +{0x0F12, 0x0009}, /* 000B 0004 Tune_wbt_GAS_200_ */ +{0x0F12, 0x0005}, /* 0008 0000 Tune_wbt_GAS_201_ */ +{0x0F12, 0x0008}, /* 000B 0003 Tune_wbt_GAS_202_ */ +{0x0F12, 0x0011}, /* 0010 000E Tune_wbt_GAS_203_ */ +{0x0F12, 0x0020}, /* 001E 0021 Tune_wbt_GAS_204_ */ +{0x0F12, 0x0035}, /* 0031 003F Tune_wbt_GAS_205_ */ +{0x0F12, 0x0051}, /* 0049 006B Tune_wbt_GAS_206_ */ +{0x0F12, 0x0071}, /* 0066 00A1 Tune_wbt_GAS_207_ */ +{0x0F12, 0x006E}, /* 005B 0089 Tune_wbt_GAS_208_ */ +{0x0F12, 0x004E}, /* 0043 0060 Tune_wbt_GAS_209_ */ +{0x0F12, 0x0032}, /* 002B 003D Tune_wbt_GAS_210_ */ +{0x0F12, 0x001C}, /* 0019 0023 Tune_wbt_GAS_211_ */ +{0x0F12, 0x000D}, /* 000C 0012 Tune_wbt_GAS_212_ */ +{0x0F12, 0x0004}, /* 0007 0006 Tune_wbt_GAS_213_ */ +{0x0F12, 0x0000}, /* 0004 0002 Tune_wbt_GAS_214_ */ +{0x0F12, 0x0003}, /* 0007 0005 Tune_wbt_GAS_215_ */ +{0x0F12, 0x000B}, /* 000D 0011 Tune_wbt_GAS_216_ */ +{0x0F12, 0x001A}, /* 001B 0025 Tune_wbt_GAS_217_ */ +{0x0F12, 0x002F}, /* 002E 0043 Tune_wbt_GAS_218_ */ +{0x0F12, 0x0049}, /* 0046 0070 Tune_wbt_GAS_219_ */ +{0x0F12, 0x0068}, /* 0062 00A4 Tune_wbt_GAS_220_ */ +{0x0F12, 0x0072}, /* 0052 0091 Tune_wbt_GAS_221_ */ +{0x0F12, 0x0053}, /* 003D 0067 Tune_wbt_GAS_222_ */ +{0x0F12, 0x0037}, /* 0026 0044 Tune_wbt_GAS_223_ */ +{0x0F12, 0x0021}, /* 0014 002B Tune_wbt_GAS_224_ */ +{0x0F12, 0x0012}, /* 0007 0019 Tune_wbt_GAS_225_ */ +{0x0F12, 0x0009}, /* 0002 000D Tune_wbt_GAS_226_ */ +{0x0F12, 0x0005}, /* 0001 0009 Tune_wbt_GAS_227_ */ +{0x0F12, 0x0008}, /* 0002 000C Tune_wbt_GAS_228_ */ +{0x0F12, 0x0010}, /* 0007 0018 Tune_wbt_GAS_229_ */ +{0x0F12, 0x001F}, /* 0015 002D Tune_wbt_GAS_230_ */ +{0x0F12, 0x0034}, /* 0028 004B Tune_wbt_GAS_231_ */ +{0x0F12, 0x004E}, /* 0040 007B Tune_wbt_GAS_232_ */ +{0x0F12, 0x006C}, /* 005C 00B0 Tune_wbt_GAS_233_ */ +{0x0F12, 0x007F}, /* 005E 00A1 Tune_wbt_GAS_234_ */ +{0x0F12, 0x0060}, /* 0049 0077 Tune_wbt_GAS_235_ */ +{0x0F12, 0x0043}, /* 0030 0054 Tune_wbt_GAS_236_ */ +{0x0F12, 0x002D}, /* 001E 003B Tune_wbt_GAS_237_ */ +{0x0F12, 0x001D}, /* 0010 0029 Tune_wbt_GAS_238_ */ +{0x0F12, 0x0013}, /* 0009 001C Tune_wbt_GAS_239_ */ +{0x0F12, 0x0010}, /* 0007 0018 Tune_wbt_GAS_240_ */ +{0x0F12, 0x0013}, /* 0009 001B Tune_wbt_GAS_241_ */ +{0x0F12, 0x001C}, /* 0012 0029 Tune_wbt_GAS_242_ */ +{0x0F12, 0x002B}, /* 0020 003F Tune_wbt_GAS_243_ */ +{0x0F12, 0x0040}, /* 0032 005F Tune_wbt_GAS_244_ */ +{0x0F12, 0x005A}, /* 004B 008F Tune_wbt_GAS_245_ */ +{0x0F12, 0x0079}, /* 0069 00C6 Tune_wbt_GAS_246_ */ +{0x0F12, 0x0082}, /* 0066 00B1 Tune_wbt_GAS_247_ */ +{0x0F12, 0x0066}, /* 004E 008E Tune_wbt_GAS_248_ */ +{0x0F12, 0x0049}, /* 0037 006D Tune_wbt_GAS_249_ */ +{0x0F12, 0x0035}, /* 0026 0050 Tune_wbt_GAS_250_ */ +{0x0F12, 0x0025}, /* 0019 003D Tune_wbt_GAS_251_ */ +{0x0F12, 0x001B}, /* 0011 0031 Tune_wbt_GAS_252_ */ +{0x0F12, 0x0017}, /* 000F 002F Tune_wbt_GAS_253_ */ +{0x0F12, 0x0019}, /* 0012 0032 Tune_wbt_GAS_254_ */ +{0x0F12, 0x0023}, /* 001B 0042 Tune_wbt_GAS_255_ */ +{0x0F12, 0x0033}, /* 0028 0058 Tune_wbt_GAS_256_ */ +{0x0F12, 0x0046}, /* 003B 007A Tune_wbt_GAS_257_ */ +{0x0F12, 0x0060}, /* 0054 00AC Tune_wbt_GAS_258_ */ +{0x0F12, 0x007B}, /* 0072 00E5 Tune_wbt_GAS_259_ */ +{0x0F12, 0x0092}, /* 006A 00BD Tune_wbt_GAS_260_ */ +{0x0F12, 0x007C}, /* 0058 00AA Tune_wbt_GAS_261_ */ +{0x0F12, 0x0060}, /* 0041 008B Tune_wbt_GAS_262_ */ +{0x0F12, 0x004B}, /* 0030 006E Tune_wbt_GAS_263_ */ +{0x0F12, 0x003C}, /* 0025 005A Tune_wbt_GAS_264_ */ +{0x0F12, 0x0032}, /* 001E 004F Tune_wbt_GAS_265_ */ +{0x0F12, 0x002D}, /* 001B 004B Tune_wbt_GAS_266_ */ +{0x0F12, 0x0030}, /* 001F 0052 Tune_wbt_GAS_267_ */ +{0x0F12, 0x0039}, /* 0027 0062 Tune_wbt_GAS_268_ */ +{0x0F12, 0x0049}, /* 0034 007D Tune_wbt_GAS_269_ */ +{0x0F12, 0x005D}, /* 0046 00A2 Tune_wbt_GAS_270_ */ +{0x0F12, 0x0076}, /* 005D 00D6 Tune_wbt_GAS_271_ */ +{0x0F12, 0x008C}, /* 0078 010C Tune_wbt_GAS_272_ */ +{0x0F12, 0x009F}, /* 007C 00E5 Tune_wbt_GAS_273_ */ +{0x0F12, 0x008F}, /* 006A 00C7 Tune_wbt_GAS_274_ */ +{0x0F12, 0x0077}, /* 0055 00B1 Tune_wbt_GAS_275_ */ +{0x0F12, 0x0061}, /* 0043 0093 Tune_wbt_GAS_276_ */ +{0x0F12, 0x0052}, /* 0037 007F Tune_wbt_GAS_277_ */ +{0x0F12, 0x0048}, /* 0030 0074 Tune_wbt_GAS_278_ */ +{0x0F12, 0x0043}, /* 002E 0071 Tune_wbt_GAS_279_ */ +{0x0F12, 0x0047}, /* 0030 0077 Tune_wbt_GAS_280_ */ +{0x0F12, 0x0050}, /* 0039 0089 Tune_wbt_GAS_281_ */ +{0x0F12, 0x005E}, /* 0045 00A7 Tune_wbt_GAS_282_ */ +{0x0F12, 0x0071}, /* 0056 00CC Tune_wbt_GAS_283_ */ +{0x0F12, 0x0086}, /* 006C 00FE Tune_wbt_GAS_284_ */ +{0x0F12, 0x0097}, /* 0084 0132 Tune_wbt_GAS_285_ */ +{0x0F12, 0x0093}, /* 006E 00A8 Tune_wbt_GAS_286_ */ +{0x0F12, 0x007C}, /* 006D 008D Tune_wbt_GAS_287_ */ +{0x0F12, 0x005F}, /* 005B 006C Tune_wbt_GAS_288_ */ +{0x0F12, 0x0049}, /* 0046 004E Tune_wbt_GAS_289_ */ +{0x0F12, 0x003A}, /* 003A 003C Tune_wbt_GAS_290_ */ +{0x0F12, 0x0030}, /* 0033 0032 Tune_wbt_GAS_291_ */ +{0x0F12, 0x002C}, /* 002D 002D Tune_wbt_GAS_292_ */ +{0x0F12, 0x002F}, /* 0032 0032 Tune_wbt_GAS_293_ */ +{0x0F12, 0x0037}, /* 0039 0040 Tune_wbt_GAS_294_ */ +{0x0F12, 0x0045}, /* 0047 0056 Tune_wbt_GAS_295_ */ +{0x0F12, 0x005A}, /* 004F 0076 Tune_wbt_GAS_296_ */ +{0x0F12, 0x0075}, /* 0050 00A8 Tune_wbt_GAS_297_ */ +{0x0F12, 0x008A}, /* 006E 00E6 Tune_wbt_GAS_298_ */ +{0x0F12, 0x0094}, /* 0077 00A2 Tune_wbt_GAS_299_ */ +{0x0F12, 0x0077}, /* 006C 007C Tune_wbt_GAS_300_ */ +{0x0F12, 0x0057}, /* 0054 0059 Tune_wbt_GAS_301_ */ +{0x0F12, 0x0040}, /* 0040 003E Tune_wbt_GAS_302_ */ +{0x0F12, 0x002F}, /* 0033 002A Tune_wbt_GAS_303_ */ +{0x0F12, 0x0024}, /* 002B 0020 Tune_wbt_GAS_304_ */ +{0x0F12, 0x0020}, /* 0027 001B Tune_wbt_GAS_305_ */ +{0x0F12, 0x0023}, /* 002A 0020 Tune_wbt_GAS_306_ */ +{0x0F12, 0x002D}, /* 0034 002D Tune_wbt_GAS_307_ */ +{0x0F12, 0x003B}, /* 0041 0042 Tune_wbt_GAS_308_ */ +{0x0F12, 0x0051}, /* 004C 0061 Tune_wbt_GAS_309_ */ +{0x0F12, 0x006E}, /* 0052 0092 Tune_wbt_GAS_310_ */ +{0x0F12, 0x008C}, /* 007E 00CE Tune_wbt_GAS_311_ */ +{0x0F12, 0x0085}, /* 0078 0094 Tune_wbt_GAS_312_ */ +{0x0F12, 0x0066}, /* 0063 006F Tune_wbt_GAS_313_ */ +{0x0F12, 0x0046}, /* 0049 004B Tune_wbt_GAS_314_ */ +{0x0F12, 0x002F}, /* 0035 002F Tune_wbt_GAS_315_ */ +{0x0F12, 0x001F}, /* 0028 001D Tune_wbt_GAS_316_ */ +{0x0F12, 0x0014}, /* 001E 0011 Tune_wbt_GAS_317_ */ +{0x0F12, 0x000F}, /* 001B 000D Tune_wbt_GAS_318_ */ +{0x0F12, 0x0012}, /* 001F 0012 Tune_wbt_GAS_319_ */ +{0x0F12, 0x001C}, /* 0028 001D Tune_wbt_GAS_320_ */ +{0x0F12, 0x002B}, /* 0037 0033 Tune_wbt_GAS_321_ */ +{0x0F12, 0x0040}, /* 0044 0051 Tune_wbt_GAS_322_ */ +{0x0F12, 0x005C}, /* 0050 007F Tune_wbt_GAS_323_ */ +{0x0F12, 0x007D}, /* 0080 00BA Tune_wbt_GAS_324_ */ +{0x0F12, 0x007A}, /* 0064 008B Tune_wbt_GAS_325_ */ +{0x0F12, 0x005A}, /* 004E 0064 Tune_wbt_GAS_326_ */ +{0x0F12, 0x003A}, /* 0035 0040 Tune_wbt_GAS_327_ */ +{0x0F12, 0x0024}, /* 0021 0025 Tune_wbt_GAS_328_ */ +{0x0F12, 0x0014}, /* 0013 0013 Tune_wbt_GAS_329_ */ +{0x0F12, 0x0009}, /* 000D 0007 Tune_wbt_GAS_330_ */ +{0x0F12, 0x0006}, /* 000B 0003 Tune_wbt_GAS_331_ */ +{0x0F12, 0x0008}, /* 000C 0006 Tune_wbt_GAS_332_ */ +{0x0F12, 0x0011}, /* 0014 0012 Tune_wbt_GAS_333_ */ +{0x0F12, 0x0020}, /* 0022 0027 Tune_wbt_GAS_334_ */ +{0x0F12, 0x0036}, /* 0036 0046 Tune_wbt_GAS_335_ */ +{0x0F12, 0x0051}, /* 004D 0073 Tune_wbt_GAS_336_ */ +{0x0F12, 0x0072}, /* 006B 00AB Tune_wbt_GAS_337_ */ +{0x0F12, 0x007B}, /* 0066 008B Tune_wbt_GAS_338_ */ +{0x0F12, 0x0059}, /* 004C 0062 Tune_wbt_GAS_339_ */ +{0x0F12, 0x003A}, /* 0032 003F Tune_wbt_GAS_340_ */ +{0x0F12, 0x0023}, /* 001E 0023 Tune_wbt_GAS_341_ */ +{0x0F12, 0x0012}, /* 0010 0010 Tune_wbt_GAS_342_ */ +{0x0F12, 0x0008}, /* 000A 0004 Tune_wbt_GAS_343_ */ +{0x0F12, 0x0004}, /* 0007 0000 Tune_wbt_GAS_344_ */ +{0x0F12, 0x0007}, /* 000B 0003 Tune_wbt_GAS_345_ */ +{0x0F12, 0x000F}, /* 0010 000E Tune_wbt_GAS_346_ */ +{0x0F12, 0x001F}, /* 001E 0022 Tune_wbt_GAS_347_ */ +{0x0F12, 0x0035}, /* 0032 0041 Tune_wbt_GAS_348_ */ +{0x0F12, 0x0051}, /* 004B 006E Tune_wbt_GAS_349_ */ +{0x0F12, 0x0072}, /* 006B 00A4 Tune_wbt_GAS_350_ */ +{0x0F12, 0x0073}, /* 0061 008E Tune_wbt_GAS_351_ */ +{0x0F12, 0x0053}, /* 0049 0065 Tune_wbt_GAS_352_ */ +{0x0F12, 0x0034}, /* 002F 0040 Tune_wbt_GAS_353_ */ +{0x0F12, 0x001D}, /* 001B 0025 Tune_wbt_GAS_354_ */ +{0x0F12, 0x000E}, /* 000E 0013 Tune_wbt_GAS_355_ */ +{0x0F12, 0x0004}, /* 0008 0006 Tune_wbt_GAS_356_ */ +{0x0F12, 0x0000}, /* 0004 0001 Tune_wbt_GAS_357_ */ +{0x0F12, 0x0002}, /* 0008 0005 Tune_wbt_GAS_358_ */ +{0x0F12, 0x000A}, /* 000D 0010 Tune_wbt_GAS_359_ */ +{0x0F12, 0x001A}, /* 001C 0025 Tune_wbt_GAS_360_ */ +{0x0F12, 0x002F}, /* 002F 0044 Tune_wbt_GAS_361_ */ +{0x0F12, 0x004A}, /* 0047 0074 Tune_wbt_GAS_362_ */ +{0x0F12, 0x006A}, /* 0067 00AA Tune_wbt_GAS_363_ */ +{0x0F12, 0x0077}, /* 005A 0097 Tune_wbt_GAS_364_ */ +{0x0F12, 0x0058}, /* 0043 006D Tune_wbt_GAS_365_ */ +{0x0F12, 0x0039}, /* 002B 0048 Tune_wbt_GAS_366_ */ +{0x0F12, 0x0022}, /* 0017 002D Tune_wbt_GAS_367_ */ +{0x0F12, 0x0012}, /* 0009 0019 Tune_wbt_GAS_368_ */ +{0x0F12, 0x0008}, /* 0004 000E Tune_wbt_GAS_369_ */ +{0x0F12, 0x0004}, /* 0002 0009 Tune_wbt_GAS_370_ */ +{0x0F12, 0x0007}, /* 0004 000C Tune_wbt_GAS_371_ */ +{0x0F12, 0x000F}, /* 0008 0018 Tune_wbt_GAS_372_ */ +{0x0F12, 0x001E}, /* 0016 002E Tune_wbt_GAS_373_ */ +{0x0F12, 0x0034}, /* 002A 004E Tune_wbt_GAS_374_ */ +{0x0F12, 0x004F}, /* 0042 007D Tune_wbt_GAS_375_ */ +{0x0F12, 0x006F}, /* 005F 00B5 Tune_wbt_GAS_376_ */ +{0x0F12, 0x0083}, /* 0066 00A6 Tune_wbt_GAS_377_ */ +{0x0F12, 0x0064}, /* 0050 007C Tune_wbt_GAS_378_ */ +{0x0F12, 0x0045}, /* 0035 0058 Tune_wbt_GAS_379_ */ +{0x0F12, 0x002E}, /* 0022 003E Tune_wbt_GAS_380_ */ +{0x0F12, 0x001D}, /* 0013 0029 Tune_wbt_GAS_381_ */ +{0x0F12, 0x0012}, /* 000A 001D Tune_wbt_GAS_382_ */ +{0x0F12, 0x000F}, /* 0008 0018 Tune_wbt_GAS_383_ */ +{0x0F12, 0x0011}, /* 000B 001B Tune_wbt_GAS_384_ */ +{0x0F12, 0x001A}, /* 0014 0028 Tune_wbt_GAS_385_ */ +{0x0F12, 0x002A}, /* 0021 003F Tune_wbt_GAS_386_ */ +{0x0F12, 0x003F}, /* 0035 0062 Tune_wbt_GAS_387_ */ +{0x0F12, 0x005B}, /* 004D 0093 Tune_wbt_GAS_388_ */ +{0x0F12, 0x007B}, /* 006E 00CC Tune_wbt_GAS_389_ */ +{0x0F12, 0x0087}, /* 006E 00B9 Tune_wbt_GAS_390_ */ +{0x0F12, 0x006A}, /* 0057 0094 Tune_wbt_GAS_391_ */ +{0x0F12, 0x004B}, /* 003E 0071 Tune_wbt_GAS_392_ */ +{0x0F12, 0x0036}, /* 002B 0052 Tune_wbt_GAS_393_ */ +{0x0F12, 0x0025}, /* 001C 003D Tune_wbt_GAS_394_ */ +{0x0F12, 0x0019}, /* 0013 0031 Tune_wbt_GAS_395_ */ +{0x0F12, 0x0015}, /* 0011 002D Tune_wbt_GAS_396_ */ +{0x0F12, 0x0017}, /* 0013 0031 Tune_wbt_GAS_397_ */ +{0x0F12, 0x0022}, /* 001D 0040 Tune_wbt_GAS_398_ */ +{0x0F12, 0x0031}, /* 002B 0058 Tune_wbt_GAS_399_ */ +{0x0F12, 0x0045}, /* 003D 007B Tune_wbt_GAS_400_ */ +{0x0F12, 0x0060}, /* 0057 00AE Tune_wbt_GAS_401_ */ +{0x0F12, 0x007D}, /* 0077 00EA Tune_wbt_GAS_402_ */ +{0x0F12, 0x0096}, /* 0072 00C2 Tune_wbt_GAS_403_ */ +{0x0F12, 0x007F}, /* 005F 00AE Tune_wbt_GAS_404_ */ +{0x0F12, 0x0061}, /* 0047 008E Tune_wbt_GAS_405_ */ +{0x0F12, 0x004B}, /* 0035 006F Tune_wbt_GAS_406_ */ +{0x0F12, 0x003B}, /* 0028 0059 Tune_wbt_GAS_407_ */ +{0x0F12, 0x002F}, /* 0020 004E Tune_wbt_GAS_408_ */ +{0x0F12, 0x002A}, /* 001D 0049 Tune_wbt_GAS_409_ */ +{0x0F12, 0x002D}, /* 0020 004F Tune_wbt_GAS_410_ */ +{0x0F12, 0x0036}, /* 0029 005E Tune_wbt_GAS_411_ */ +{0x0F12, 0x0046}, /* 0035 007A Tune_wbt_GAS_412_ */ +{0x0F12, 0x005B}, /* 0047 009F Tune_wbt_GAS_413_ */ +{0x0F12, 0x0075}, /* 0060 00D5 Tune_wbt_GAS_414_ */ +{0x0F12, 0x008D}, /* 007D 010C Tune_wbt_GAS_415_ */ +{0x0F12, 0x00A1}, /* 0084 00E5 Tune_wbt_GAS_416_ */ +{0x0F12, 0x0091}, /* 0072 00C8 Tune_wbt_GAS_417_ */ +{0x0F12, 0x0077}, /* 005B 00B0 Tune_wbt_GAS_418_ */ +{0x0F12, 0x0060}, /* 0046 0091 Tune_wbt_GAS_419_ */ +{0x0F12, 0x0050}, /* 003A 007D Tune_wbt_GAS_420_ */ +{0x0F12, 0x0044}, /* 0031 0070 Tune_wbt_GAS_421_ */ +{0x0F12, 0x0040}, /* 002E 006D Tune_wbt_GAS_422_ */ +{0x0F12, 0x0043}, /* 0032 0074 Tune_wbt_GAS_423_ */ +{0x0F12, 0x004C}, /* 0039 0086 Tune_wbt_GAS_424_ */ +{0x0F12, 0x005A}, /* 0046 00A4 Tune_wbt_GAS_425_ */ +{0x0F12, 0x006D}, /* 0056 00CA Tune_wbt_GAS_426_ */ +{0x0F12, 0x0084}, /* 006E 00FE Tune_wbt_GAS_427_ */ +{0x0F12, 0x0094}, /* 0087 0134 Tune_wbt_GAS_428_ */ +{0x0F12, 0x0072}, /* 004C 009F Tune_wbt_GAS_429_ */ +{0x0F12, 0x0063}, /* 004C 0089 Tune_wbt_GAS_430_ */ +{0x0F12, 0x004C}, /* 0041 0067 Tune_wbt_GAS_431_ */ +{0x0F12, 0x003A}, /* 002F 004E Tune_wbt_GAS_432_ */ +{0x0F12, 0x002D}, /* 0024 003E Tune_wbt_GAS_433_ */ +{0x0F12, 0x0025}, /* 001D 0033 Tune_wbt_GAS_434_ */ +{0x0F12, 0x0023}, /* 001B 0031 Tune_wbt_GAS_435_ */ +{0x0F12, 0x0025}, /* 001E 0036 Tune_wbt_GAS_436_ */ +{0x0F12, 0x002C}, /* 0024 0045 Tune_wbt_GAS_437_ */ +{0x0F12, 0x0038}, /* 0032 0058 Tune_wbt_GAS_438_ */ +{0x0F12, 0x004A}, /* 0037 0074 Tune_wbt_GAS_439_ */ +{0x0F12, 0x005F}, /* 0038 00A0 Tune_wbt_GAS_440_ */ +{0x0F12, 0x006B}, /* 004C 00C9 Tune_wbt_GAS_441_ */ +{0x0F12, 0x0079}, /* 005B 0098 Tune_wbt_GAS_442_ */ +{0x0F12, 0x0065}, /* 0056 0077 Tune_wbt_GAS_443_ */ +{0x0F12, 0x004A}, /* 0041 0055 Tune_wbt_GAS_444_ */ +{0x0F12, 0x0037}, /* 0030 003C Tune_wbt_GAS_445_ */ +{0x0F12, 0x0029}, /* 0026 002A Tune_wbt_GAS_446_ */ +{0x0F12, 0x0021}, /* 001F 0022 Tune_wbt_GAS_447_ */ +{0x0F12, 0x001D}, /* 001C 001F Tune_wbt_GAS_448_ */ +{0x0F12, 0x001F}, /* 001F 0024 Tune_wbt_GAS_449_ */ +{0x0F12, 0x0027}, /* 0027 0030 Tune_wbt_GAS_450_ */ +{0x0F12, 0x0033}, /* 0033 0044 Tune_wbt_GAS_451_ */ +{0x0F12, 0x0044}, /* 003C 0060 Tune_wbt_GAS_452_ */ +{0x0F12, 0x005E}, /* 0041 008B Tune_wbt_GAS_453_ */ +{0x0F12, 0x006E}, /* 0060 00B2 Tune_wbt_GAS_454_ */ +{0x0F12, 0x006A}, /* 005E 0088 Tune_wbt_GAS_455_ */ +{0x0F12, 0x0055}, /* 004F 0065 Tune_wbt_GAS_456_ */ +{0x0F12, 0x003A}, /* 003A 0044 Tune_wbt_GAS_457_ */ +{0x0F12, 0x0028}, /* 002A 002C Tune_wbt_GAS_458_ */ +{0x0F12, 0x001A}, /* 001D 001B Tune_wbt_GAS_459_ */ +{0x0F12, 0x0011}, /* 0016 0012 Tune_wbt_GAS_460_ */ +{0x0F12, 0x000D}, /* 0014 000F Tune_wbt_GAS_461_ */ +{0x0F12, 0x000F}, /* 0016 0013 Tune_wbt_GAS_462_ */ +{0x0F12, 0x0017}, /* 0021 001E Tune_wbt_GAS_463_ */ +{0x0F12, 0x0024}, /* 002D 0032 Tune_wbt_GAS_464_ */ +{0x0F12, 0x0035}, /* 0038 004E Tune_wbt_GAS_465_ */ +{0x0F12, 0x004E}, /* 0040 0078 Tune_wbt_GAS_466_ */ +{0x0F12, 0x0061}, /* 0066 00A2 Tune_wbt_GAS_467_ */ +{0x0F12, 0x0061}, /* 004A 007F Tune_wbt_GAS_468_ */ +{0x0F12, 0x004A}, /* 003C 005B Tune_wbt_GAS_469_ */ +{0x0F12, 0x0031}, /* 0028 0039 Tune_wbt_GAS_470_ */ +{0x0F12, 0x001E}, /* 0019 0021 Tune_wbt_GAS_471_ */ +{0x0F12, 0x0011}, /* 000D 0012 Tune_wbt_GAS_472_ */ +{0x0F12, 0x0008}, /* 0008 0007 Tune_wbt_GAS_473_ */ +{0x0F12, 0x0005}, /* 0007 0004 Tune_wbt_GAS_474_ */ +{0x0F12, 0x0007}, /* 0007 0006 Tune_wbt_GAS_475_ */ +{0x0F12, 0x000E}, /* 000F 0012 Tune_wbt_GAS_476_ */ +{0x0F12, 0x001B}, /* 001C 0024 Tune_wbt_GAS_477_ */ +{0x0F12, 0x002D}, /* 002C 0041 Tune_wbt_GAS_478_ */ +{0x0F12, 0x0045}, /* 0042 006A Tune_wbt_GAS_479_ */ +{0x0F12, 0x0059}, /* 0054 0092 Tune_wbt_GAS_480_ */ +{0x0F12, 0x0062}, /* 004B 007B Tune_wbt_GAS_481_ */ +{0x0F12, 0x004B}, /* 003C 0057 Tune_wbt_GAS_482_ */ +{0x0F12, 0x0031}, /* 0027 0036 Tune_wbt_GAS_483_ */ +{0x0F12, 0x001E}, /* 0017 001E Tune_wbt_GAS_484_ */ +{0x0F12, 0x0010}, /* 000C 000F Tune_wbt_GAS_485_ */ +{0x0F12, 0x0008}, /* 0007 0003 Tune_wbt_GAS_486_ */ +{0x0F12, 0x0004}, /* 0006 0000 Tune_wbt_GAS_487_ */ +{0x0F12, 0x0006}, /* 0008 0002 Tune_wbt_GAS_488_ */ +{0x0F12, 0x000E}, /* 000D 000D Tune_wbt_GAS_489_ */ +{0x0F12, 0x001B}, /* 001A 0020 Tune_wbt_GAS_490_ */ +{0x0F12, 0x002E}, /* 002B 003C Tune_wbt_GAS_491_ */ +{0x0F12, 0x0046}, /* 0041 0067 Tune_wbt_GAS_492_ */ +{0x0F12, 0x005A}, /* 0054 008D Tune_wbt_GAS_493_ */ +{0x0F12, 0x005B}, /* 0049 007E Tune_wbt_GAS_494_ */ +{0x0F12, 0x0045}, /* 003A 005A Tune_wbt_GAS_495_ */ +{0x0F12, 0x002C}, /* 0025 0038 Tune_wbt_GAS_496_ */ +{0x0F12, 0x001A}, /* 0015 0022 Tune_wbt_GAS_497_ */ +{0x0F12, 0x000C}, /* 000A 0013 Tune_wbt_GAS_498_ */ +{0x0F12, 0x0003}, /* 0005 0006 Tune_wbt_GAS_499_ */ +{0x0F12, 0x0000}, /* 0003 0001 Tune_wbt_GAS_500_ */ +{0x0F12, 0x0002}, /* 0006 0004 Tune_wbt_GAS_501_ */ +{0x0F12, 0x0009}, /* 000B 000F Tune_wbt_GAS_502_ */ +{0x0F12, 0x0016}, /* 0018 0023 Tune_wbt_GAS_503_ */ +{0x0F12, 0x0029}, /* 0029 003E Tune_wbt_GAS_504_ */ +{0x0F12, 0x0040}, /* 003E 006A Tune_wbt_GAS_505_ */ +{0x0F12, 0x0054}, /* 0050 0091 Tune_wbt_GAS_506_ */ +{0x0F12, 0x005F}, /* 0044 0085 Tune_wbt_GAS_507_ */ +{0x0F12, 0x004A}, /* 0033 0060 Tune_wbt_GAS_508_ */ +{0x0F12, 0x0031}, /* 0021 0041 Tune_wbt_GAS_509_ */ +{0x0F12, 0x001F}, /* 0011 002A Tune_wbt_GAS_510_ */ +{0x0F12, 0x0010}, /* 0005 0019 Tune_wbt_GAS_511_ */ +{0x0F12, 0x0008}, /* 0002 000D Tune_wbt_GAS_512_ */ +{0x0F12, 0x0004}, /* 0001 0008 Tune_wbt_GAS_513_ */ +{0x0F12, 0x0007}, /* 0003 000A Tune_wbt_GAS_514_ */ +{0x0F12, 0x000E}, /* 0008 0016 Tune_wbt_GAS_515_ */ +{0x0F12, 0x001B}, /* 0014 002A Tune_wbt_GAS_516_ */ +{0x0F12, 0x002E}, /* 0025 0047 Tune_wbt_GAS_517_ */ +{0x0F12, 0x0045}, /* 0039 0074 Tune_wbt_GAS_518_ */ +{0x0F12, 0x0059}, /* 004D 009A Tune_wbt_GAS_519_ */ +{0x0F12, 0x006C}, /* 0050 0097 Tune_wbt_GAS_520_ */ +{0x0F12, 0x0057}, /* 0041 0070 Tune_wbt_GAS_521_ */ +{0x0F12, 0x003E}, /* 002C 0052 Tune_wbt_GAS_522_ */ +{0x0F12, 0x002A}, /* 001C 003C Tune_wbt_GAS_523_ */ +{0x0F12, 0x001B}, /* 0011 0028 Tune_wbt_GAS_524_ */ +{0x0F12, 0x0012}, /* 0009 001D Tune_wbt_GAS_525_ */ +{0x0F12, 0x000F}, /* 0008 0019 Tune_wbt_GAS_526_ */ +{0x0F12, 0x0011}, /* 000A 001A Tune_wbt_GAS_527_ */ +{0x0F12, 0x0019}, /* 0012 0026 Tune_wbt_GAS_528_ */ +{0x0F12, 0x0027}, /* 001F 003B Tune_wbt_GAS_529_ */ +{0x0F12, 0x0039}, /* 002F 005A Tune_wbt_GAS_530_ */ +{0x0F12, 0x0050}, /* 0045 0089 Tune_wbt_GAS_531_ */ +{0x0F12, 0x0063}, /* 005A 00AF Tune_wbt_GAS_532_ */ +{0x0F12, 0x006F}, /* 0056 00A7 Tune_wbt_GAS_533_ */ +{0x0F12, 0x005C}, /* 0048 0088 Tune_wbt_GAS_534_ */ +{0x0F12, 0x0044}, /* 0035 006B Tune_wbt_GAS_535_ */ +{0x0F12, 0x0031}, /* 0026 0050 Tune_wbt_GAS_536_ */ +{0x0F12, 0x0023}, /* 0019 003D Tune_wbt_GAS_537_ */ +{0x0F12, 0x0019}, /* 0012 0032 Tune_wbt_GAS_538_ */ +{0x0F12, 0x0016}, /* 0011 002E Tune_wbt_GAS_539_ */ +{0x0F12, 0x0017}, /* 0012 0030 Tune_wbt_GAS_540_ */ +{0x0F12, 0x0020}, /* 001B 003E Tune_wbt_GAS_541_ */ +{0x0F12, 0x002E}, /* 0027 0052 Tune_wbt_GAS_542_ */ +{0x0F12, 0x0040}, /* 0037 0073 Tune_wbt_GAS_543_ */ +{0x0F12, 0x0055}, /* 004C 00A1 Tune_wbt_GAS_544_ */ +{0x0F12, 0x0064}, /* 0060 00C7 Tune_wbt_GAS_545_ */ +{0x0F12, 0x007E}, /* 0058 00AE Tune_wbt_GAS_546_ */ +{0x0F12, 0x0071}, /* 0050 00A4 Tune_wbt_GAS_547_ */ +{0x0F12, 0x0059}, /* 003D 0088 Tune_wbt_GAS_548_ */ +{0x0F12, 0x0046}, /* 002E 006D Tune_wbt_GAS_549_ */ +{0x0F12, 0x0039}, /* 0023 0059 Tune_wbt_GAS_550_ */ +{0x0F12, 0x002F}, /* 001C 004D Tune_wbt_GAS_551_ */ +{0x0F12, 0x002A}, /* 001B 0049 Tune_wbt_GAS_552_ */ +{0x0F12, 0x002D}, /* 001D 004E Tune_wbt_GAS_553_ */ +{0x0F12, 0x0035}, /* 0024 005B Tune_wbt_GAS_554_ */ +{0x0F12, 0x0043}, /* 002F 0073 Tune_wbt_GAS_555_ */ +{0x0F12, 0x0054}, /* 003E 0095 Tune_wbt_GAS_556_ */ +{0x0F12, 0x0069}, /* 0052 00C4 Tune_wbt_GAS_557_ */ +{0x0F12, 0x0074}, /* 0062 00E9 Tune_wbt_GAS_558_ */ +{0x0F12, 0x0083}, /* 0060 00D5 Tune_wbt_GAS_559_ */ +{0x0F12, 0x007D}, /* 0057 00C1 Tune_wbt_GAS_560_ */ +{0x0F12, 0x0068}, /* 0048 00AB Tune_wbt_GAS_561_ */ +{0x0F12, 0x0055}, /* 0039 008D Tune_wbt_GAS_562_ */ +{0x0F12, 0x0048}, /* 002E 0079 Tune_wbt_GAS_563_ */ +{0x0F12, 0x003E}, /* 0028 0070 Tune_wbt_GAS_564_ */ +{0x0F12, 0x003A}, /* 0027 006A Tune_wbt_GAS_565_ */ +{0x0F12, 0x003D}, /* 0029 006F Tune_wbt_GAS_566_ */ +{0x0F12, 0x0045}, /* 002F 0080 Tune_wbt_GAS_567_ */ +{0x0F12, 0x0051}, /* 0039 0096 Tune_wbt_GAS_568_ */ +{0x0F12, 0x0061}, /* 0047 00B9 Tune_wbt_GAS_569_ */ +{0x0F12, 0x0072}, /* 0059 00E2 Tune_wbt_GAS_570_ */ +{0x0F12, 0x0077}, /* 0067 010F Tune_wbt_GAS_571_ */ +{0x002A, 0x1348}, +{0x0F12, 0x0001}, /* gisp_gras_Enable */ + +/**************************************/ +/* 07. Analog Setting 2 */ +/**************************************/ + +/**************************************/ +/* 08.AF Setting */ +/**************************************/ + +/**************************************/ +/* 09.AWB-BASIC setting */ +/**************************************/ +/* For WB Calibration */ +{0x002A, 0x0B36}, +{0x0F12, 0x0005}, /* awbb_IndoorGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0B3A}, +{0x0F12, 0x00EC}, /* awbb_IndoorGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02C1}, /* awbb_IndoorGrZones_ZInfo_m_BMax */ +{0x002A, 0x0B38}, +{0x0F12, 0x0010}, /* awbb_IndoorGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0AE6}, +{0x0F12, 0x03E1}, /* awbb_IndoorGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x0413}, /* awbb_IndoorGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x039E}, /* awbb_IndoorGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x0416}, /* awbb_IndoorGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x0367}, /* awbb_IndoorGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x03F3}, /* awbb_IndoorGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x032D}, /* awbb_IndoorGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x03C5}, /* awbb_IndoorGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x02FD}, /* awbb_IndoorGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x038F}, /* awbb_IndoorGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x02D3}, /* awbb_IndoorGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x0365}, /* awbb_IndoorGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x02AA}, /* awbb_IndoorGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x033E}, /* awbb_IndoorGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x028D}, /* awbb_IndoorGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0310}, /* awbb_IndoorGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x0271}, /* awbb_IndoorGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x02F1}, /* awbb_IndoorGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x025A}, /* awbb_IndoorGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x02D2}, /* awbb_IndoorGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0249}, /* awbb_IndoorGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x02B9}, /* awbb_IndoorGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0238}, /* awbb_IndoorGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x02A2}, /* awbb_IndoorGrZones_m_BGrid_11__m_right */ +{0x0F12, 0x021B}, /* awbb_IndoorGrZones_m_BGrid_12__m_left */ +{0x0F12, 0x0289}, /* awbb_IndoorGrZones_m_BGrid_12__m_right */ +{0x0F12, 0x0200}, /* awbb_IndoorGrZones_m_BGrid_13__m_left */ +{0x0F12, 0x026C}, /* awbb_IndoorGrZones_m_BGrid_13__m_right */ +{0x0F12, 0x01FC}, /* awbb_IndoorGrZones_m_BGrid_14__m_left */ +{0x0F12, 0x024F}, /* awbb_IndoorGrZones_m_BGrid_14__m_right */ +{0x0F12, 0x021E}, /* awbb_IndoorGrZones_m_BGrid_15__m_left */ +{0x0F12, 0x022C}, /* awbb_IndoorGrZones_m_BGrid_15__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_16__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_16__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_17__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_17__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_18__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_18__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_19__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_19__m_right */ +{0x002A, 0x0BAA}, +{0x0F12, 0x0006}, /* awbb_LowBrGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0BAE}, +{0x0F12, 0x010E}, /* awbb_LowBrGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02E9}, /* awbb_LowBrGrZones_ZInfo_m_BMax */ +{0x002A, 0x0BAC}, +{0x0F12, 0x0009}, /* awbb_LowBrGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0B7A}, +{0x0F12, 0x038C}, /* awbb_LowBrGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x03DA}, /* awbb_LowBrGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x030E}, /* awbb_LowBrGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x03E9}, /* awbb_LowBrGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x02A2}, /* awbb_LowBrGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x03C2}, /* awbb_LowBrGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x0259}, /* awbb_LowBrGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x038A}, /* awbb_LowBrGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x0218}, /* awbb_LowBrGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x0352}, /* awbb_LowBrGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x01F4}, /* awbb_LowBrGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x02E1}, /* awbb_LowBrGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x01D7}, /* awbb_LowBrGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x028E}, /* awbb_LowBrGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x01CB}, /* awbb_LowBrGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0258}, /* awbb_LowBrGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x022B}, /* awbb_LowBrGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x01CC}, /* awbb_LowBrGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_11__m_right */ +{0x002A, 0x0B70}, +{0x0F12, 0x0005}, /* awbb_OutdoorGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0B74}, +{0x0F12, 0x01F8}, /* awbb_OutdoorGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02A8}, /* awbb_OutdoorGrZones_ZInfo_m_BMax */ +{0x002A, 0x0B72}, +{0x0F12, 0x0007}, /* awbb_OutdoorGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0B40}, +{0x0F12, 0x029E}, /* awbb_OutdoorGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x02C8}, /* awbb_OutdoorGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x0281}, /* awbb_OutdoorGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x02C8}, /* awbb_OutdoorGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x0266}, /* awbb_OutdoorGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x02AC}, /* awbb_OutdoorGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x0251}, /* awbb_OutdoorGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x028E}, /* awbb_OutdoorGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x023D}, /* awbb_OutdoorGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x0275}, /* awbb_OutdoorGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x0228}, /* awbb_OutdoorGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x025D}, /* awbb_OutdoorGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x0228}, /* awbb_OutdoorGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x0243}, /* awbb_OutdoorGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_11__m_right */ +{0x002A, 0x0BC8}, +{0x0F12, 0x0005}, /* awbb_CWSkinZone_ZInfo_m_GridStep */ +{0x002A, 0x0BCC}, +{0x0F12, 0x010F}, /* awbb_CWSkinZone_ZInfo_m_BMin */ +{0x0F12, 0x018F}, /* awbb_CWSkinZone_ZInfo_m_BMax */ +{0x002A, 0x0BCA}, +{0x0F12, 0x0005}, /* awbb_CWSkinZone_ZInfo_m_GridSz */ +{0x002A, 0x0BB4}, +{0x0F12, 0x03E7}, /* awbb_CWSkinZone_m_BGrid_0__m_left */ +{0x0F12, 0x03F8}, /* awbb_CWSkinZone_m_BGrid_0__m_right */ +{0x0F12, 0x03A7}, /* awbb_CWSkinZone_m_BGrid_1__m_left */ +{0x0F12, 0x03FC}, /* awbb_CWSkinZone_m_BGrid_1__m_right */ +{0x0F12, 0x0352}, /* awbb_CWSkinZone_m_BGrid_2__m_left */ +{0x0F12, 0x03D0}, /* awbb_CWSkinZone_m_BGrid_2__m_right */ +{0x0F12, 0x0322}, /* awbb_CWSkinZone_m_BGrid_3__m_left */ +{0x0F12, 0x039E}, /* awbb_CWSkinZone_m_BGrid_3__m_right */ +{0x0F12, 0x032B}, /* awbb_CWSkinZone_m_BGrid_4__m_left */ +{0x0F12, 0x034D}, /* awbb_CWSkinZone_m_BGrid_4__m_right */ +{0x002A, 0x0BE6}, +{0x0F12, 0x0006}, /* awbb_DLSkinZone_ZInfo_m_GridStep */ +{0x002A, 0x0BEA}, +{0x0F12, 0x019E}, /* awbb_DLSkinZone_ZInfo_m_BMin */ +{0x0F12, 0x0257}, /* awbb_DLSkinZone_ZInfo_m_BMax */ +{0x002A, 0x0BE8}, +{0x0F12, 0x0004}, /* awbb_DLSkinZone_ZInfo_m_GridSz */ +{0x002A, 0x0BD2}, +{0x0F12, 0x030B}, /* awbb_DLSkinZone_m_BGrid_0__m_left */ +{0x0F12, 0x0323}, /* awbb_DLSkinZone_m_BGrid_0__m_right */ +{0x0F12, 0x02C3}, /* awbb_DLSkinZone_m_BGrid_1__m_left */ +{0x0F12, 0x030F}, /* awbb_DLSkinZone_m_BGrid_1__m_right */ +{0x0F12, 0x0288}, /* awbb_DLSkinZone_m_BGrid_2__m_left */ +{0x0F12, 0x02E5}, /* awbb_DLSkinZone_m_BGrid_2__m_right */ +{0x0F12, 0x026A}, /* awbb_DLSkinZone_m_BGrid_3__m_left */ +{0x0F12, 0x02A2}, /* awbb_DLSkinZone_m_BGrid_3__m_right */ +{0x0F12, 0x0000}, /* awbb_DLSkinZone_m_BGrid_4__m_left */ +{0x0F12, 0x0000}, /* awbb_DLSkinZone_m_BGrid_4__m_right */ +{0x002A, 0x0C2C}, +{0x0F12, 0x0139}, /* awbb_IntcR */ +{0x0F12, 0x0122}, /* awbb_IntcB */ +{0x002A, 0x0BFC}, +{0x0F12, 0x03AD}, /* awbb_IndoorWP_0__r */ +{0x0F12, 0x013F}, /* awbb_IndoorWP_0__b */ +{0x0F12, 0x0341}, /* awbb_IndoorWP_1__r */ +{0x0F12, 0x017B}, /* awbb_IndoorWP_1__b */ +{0x0F12, 0x038D}, /* awbb_IndoorWP_2__r */ +{0x0F12, 0x014B}, /* awbb_IndoorWP_2__b */ +{0x0F12, 0x02C3}, /* awbb_IndoorWP_3__r */ +{0x0F12, 0x01CC}, /* awbb_IndoorWP_3__b */ +{0x0F12, 0x0241}, /* awbb_IndoorWP_4__r */ +{0x0F12, 0x027F}, /* awbb_IndoorWP_4__b */ +{0x0F12, 0x0241}, /* awbb_IndoorWP_5__r */ +{0x0F12, 0x027F}, /* awbb_IndoorWP_5__b */ +{0x0F12, 0x0214}, /* awbb_IndoorWP_6__r */ +{0x0F12, 0x02A8}, /* awbb_IndoorWP_6__b */ +{0x0F12, 0x0270}, /* 255 awbb_OutdoorWP_r */ +{0x0F12, 0x0210}, /* 25B awbb_OutdoorWP_b */ +{0x002A, 0x0C4C}, +{0x0F12, 0x0452}, /* awbb_MvEq_RBthresh */ +{0x002A, 0x0C58}, +{0x0F12, 0x059C}, /* awbb_MvEq_RBthresh */ +{0x002A, 0x0BF8}, +{0x0F12, 0x01AE}, /* awbb_LowTSep_m_RminusB */ +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, /* awbb_SkinPreference */ +{0x002A, 0x0CAC}, +{0x0F12, 0x0F00}, /* awbb_SkinPreference */ +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, /* awbb_SkinPreference */ +{0x002A, 0x0D0E}, +{0x0F12, 0x00B8}, /* awbb_GridCoeff_R_2 */ +{0x0F12, 0x00B2}, /* awbb_GridCoeff_B_2 */ +{0x002A, 0x0CFE}, +{0x0F12, 0x0FAB}, /* awbb_GridConst_2_0_ */ +{0x0F12, 0x0FF5}, /* awbb_GridConst_2_1_ */ +{0x0F12, 0x10BB}, /* awbb_GridConst_2_2_ */ +{0x0F12, 0x1153}, /* 1123 1153 awbb_GridConst_2_3_ */ +{0x0F12, 0x11C5}, /* 1165 11C5 awbb_GridConst_2_4_ */ +{0x0F12, 0x122A}, /* awbb_GridConst_2_5_ */ +{0x0F12, 0x00A9}, /* awbb_GridCoeff_R_1 */ +{0x0F12, 0x00C0}, /* awbb_GridCoeff_B_1 */ +{0x002A, 0x0CF8}, +{0x0F12, 0x030E}, /* awbb_GridConst_1_0_ */ +{0x0F12, 0x034C}, /* awbb_GridConst_1_1_ */ +{0x0F12, 0x0388}, /* awbb_GridConst_1_2_ */ + +{0x002A, 0x0CB0}, +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_0__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_0__1_ */ +{0x0F12, 0x0010}, /* 0078 awbb_GridCorr_R_0__2_ */ +{0x0F12, 0x0030}, /* 00AA awbb_GridCorr_R_0__3_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_0__4_ */ +{0x0F12, 0x0050}, /* 0000 awbb_GridCorr_R_0__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_1__0_ */ +{0x0F12, 0x0000}, /* 0096 awbb_GridCorr_R_1__1_ */ +{0x0F12, 0x0010}, /* 0000 awbb_GridCorr_R_1__2_ */ +{0x0F12, 0x0030}, /* 0000 awbb_GridCorr_R_1__3_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_1__4_ */ +{0x0F12, 0x0050}, /* 0000 awbb_GridCorr_R_1__5_ */ + +{0x0F12, 0x0000}, /* 00E6 awbb_GridCorr_R_2__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_2__1_ */ +{0x0F12, 0x0010}, /* 0000 awbb_GridCorr_R_2__2_ */ +{0x0F12, 0x0030}, /* 0000 awbb_GridCorr_R_2__3_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_2__4_ */ +{0x0F12, 0x0050}, /* 0000 awbb_GridCorr_R_2__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_0__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_0__1_ */ +{0x0F12, 0x0000}, /* 0064 awbb_GridCorr_B_0__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_0__3_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_0__4_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_0__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_1__0_ */ +{0x0F12, 0x0000}, /* 0032 awbb_GridCorr_B_1__1_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_1__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_1__3_ */ +{0x0F12, 0xFF06}, /* FF38 awbb_GridCorr_B_1__4_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_1__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_2__0_ */ +{0x0F12, 0x0000}, /* 0032 awbb_GridCorr_B_2__1_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_2__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_2__3_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_2__4_ */ +{0x0F12, 0xFF06}, /* 0000 awbb_GridCorr_B_2__5_ */ + +{0x002A, 0x0D30}, +{0x0F12, 0x0002}, /* awbb_GridEnable */ +/* For Outdoor Detector */ +{0x002A, 0x0C86}, +{0x0F12, 0x0005}, /* awbb_OutdoorDetectionZone_ZInfo_m_GridSz */ +{0x002A, 0x0C70}, +{0x0F12, 0xFF7B}, /* awbb_OutdoorDetectionZone_m_BGrid_0__m_left */ +{0x0F12, 0x00CE}, /* awbb_OutdoorDetectionZone_m_BGrid_0__m_right */ +{0x0F12, 0xFF23}, /* awbb_OutdoorDetectionZone_m_BGrid_1__m_left */ +{0x0F12, 0x010D}, /* awbb_OutdoorDetectionZone_m_BGrid_1__m_right */ +{0x0F12, 0xFEF3}, /* awbb_OutdoorDetectionZone_m_BGrid_2__m_left */ +{0x0F12, 0x012C}, /* awbb_OutdoorDetectionZone_m_BGrid_2__m_right */ +{0x0F12, 0xFED7}, /* awbb_OutdoorDetectionZone_m_BGrid_3__m_left */ +{0x0F12, 0x014E}, /* awbb_OutdoorDetectionZone_m_BGrid_3__m_right */ +{0x0F12, 0xFEBB}, /* awbb_OutdoorDetectionZone_m_BGrid_4__m_left */ +{0x0F12, 0x0162}, /* awbb_OutdoorDetectionZone_m_BGrid_4__m_right */ +{0x0F12, 0x1388}, /* awbb_OutdoorDetectionZone_ZInfo_m_AbsGridStep */ +{0x002A, 0x0C8A}, +{0x0F12, 0x4ACB}, /* awbb_OutdoorDetectionZone_ZInfo_m_MaxNB */ +{0x002A, 0x0C88}, +{0x0F12, 0x0A7C}, /* awbb_OutdoorDetectionZone_ZInfo_m_NBoffs */ + +/**************************************/ +/* 10.Auto Flicker Detection */ +/**************************************/ +{0x0028, 0x7000}, +{0x002A, 0x03F4}, +{0x0F12, 0x0002}, /*REG_SF_USER_FlickerQuant */ +{0x0F12, 0x0001}, /*REG_SF_USER_FlickerQuantChanged */ +{0x002A, 0x0408}, +{0x0F12, 0x067F}, /*REG_TC_DBG_AutoAlgEnBits all AA are on */ + +/**************************************/ +/* 11.AE Setting */ +/**************************************/ + +{0x002A, 0x0D40}, +{0x0F12, 0x003E}, /* 3E TVAR_ae_BrAve */ + +/* For LT Calibration */ +{0x002A, 0x0D46}, +{0x0F12, 0x000F}, /* ae_StatMode */ + +{0x002A, 0x0440}, +{0x0F12, 0x3410}, /* lt_uMaxExp_0_ */ +{0x002A, 0x0444}, +{0x0F12, 0x6820}, /* lt_uMaxExp_1_ */ +{0x002A, 0x0448}, +{0x0F12, 0x8227}, /* lt_uMaxExp_2_ */ +{0x002A, 0x044C}, +{0x0F12, 0xC350}, /* lt_uMaxExp_3_ */ +{0x002A, 0x0450}, +{0x0F12, 0x3410}, /* lt_uCapMaxExp_0_ */ +{0x002A, 0x0454}, +{0x0F12, 0x6820}, /* lt_uCapMaxExp_1_ */ +{0x002A, 0x0458}, +{0x0F12, 0x8227}, /* lt_uCapMaxExp_2_ */ +{0x002A, 0x045C}, +{0x0F12, 0xC350}, /* lt_uCapMaxExp_3_ */ +{0x002A, 0x0460}, +{0x0F12, 0x01B0}, /* lt_uMaxAnGain_0_ */ +{0x0F12, 0x01B0}, /* lt_uMaxAnGain_1_ */ +{0x0F12, 0x0280}, /* lt_uMaxAnGain_2_ */ +{0x0F12, 0x0A80}, /* lt_uMaxAnGain_3_ */ +{0x0F12, 0x0160}, /* 0100 lt_uMaxDigGain */ +{0x0F12, 0x3000}, /* lt_uMaxTotGain */ +{0x002A, 0x042E}, +{0x0F12, 0x010E}, /* lt_uMaxTotGain */ +{0x0F12, 0x00F5}, /* lt_uLimitLow */ +{0x002A, 0x0DE0}, +{0x0F12, 0x0002}, /* ae_Fade2BlackEnable F2B off, F2W on */ + +/* For Illum Type Calibration */ +/* WRITE #SARR_IllumType_0_ 0078 */ +/* WRITE #SARR_IllumType_1_ 00C3 */ +/* WRITE #SARR_IllumType_2_ 00E9 */ +/* WRITE #SARR_IllumType_3_ 0128 */ +/* WRITE #SARR_IllumType_4_ 016F */ +/* WRITE #SARR_IllumType_5_ 0195 */ +/* WRITE #SARR_IllumType_6_ 01A4 */ +/* WRITE #SARR_IllumTypeF_0_ 0100 */ +/* WRITE #SARR_IllumTypeF_1_ 0100 */ +/* WRITE #SARR_IllumTypeF_2_ 0110 */ +/* WRITE #SARR_IllumTypeF_3_ 00E5 */ +/* WRITE #SARR_IllumTypeF_4_ 0100 */ +/* WRITE #SARR_IllumTypeF_5_ 00ED */ +/* WRITE #SARR_IllumTypeF_6_ 00ED */ + +/**************************************/ +/* 12.AE Weight (Normal) */ +/**************************************/ +{0x002A, 0x0D4E}, +{0x0F12, 0x0000}, /* 0000 ae_WeightTbl_16_0_ */ +{0x0F12, 0x0101}, /* 0101 ae_WeightTbl_16_1_ */ +{0x0F12, 0x0101}, /* 0101 ae_WeightTbl_16_2_ */ +{0x0F12, 0x0000}, /* 0000 ae_WeightTbl_16_3_ */ +{0x0F12, 0x0201}, /* 0101 ae_WeightTbl_16_4_ */ +{0x0F12, 0x0202}, /* 0101 ae_WeightTbl_16_5_ */ +{0x0F12, 0x0202}, /* 0101 ae_WeightTbl_16_6_ */ +{0x0F12, 0x0102}, /* 0101 ae_WeightTbl_16_7_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_8_ */ +{0x0F12, 0x0303}, /* 0303 ae_WeightTbl_16_9_ */ +{0x0F12, 0x0303}, /* 0303 ae_WeightTbl_16_10_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_11_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_12_ */ +{0x0F12, 0x0403}, /* 0403 ae_WeightTbl_16_13_ */ +{0x0F12, 0x0304}, /* 0304 ae_WeightTbl_16_14_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_15_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_16_ */ +{0x0F12, 0x0403}, /* 0403 ae_WeightTbl_16_17_ */ +{0x0F12, 0x0304}, /* 0304 ae_WeightTbl_16_18_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_19_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_20_ */ +{0x0F12, 0x0303}, /* 0403 ae_WeightTbl_16_21_ */ +{0x0F12, 0x0303}, /* 0304 ae_WeightTbl_16_22_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_23_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_24_ */ +{0x0F12, 0x0202}, /* 0303 ae_WeightTbl_16_25_ */ +{0x0F12, 0x0202}, /* 0303 ae_WeightTbl_16_26_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_27_ */ +{0x0F12, 0x0000}, /* 0201 ae_WeightTbl_16_28_ */ +{0x0F12, 0x0101}, /* 0202 ae_WeightTbl_16_29_ */ +{0x0F12, 0x0101}, /* 0202 ae_WeightTbl_16_30_ */ +{0x0F12, 0x0000}, /* 0102 ae_WeightTbl_16_31_ */ + +/**************************************/ +/* 13.Flash Setting */ +/**************************************/ + +/**************************************/ +/* 14.CCM Setting */ +/**************************************/ + +{0x002A, 0x33A4}, +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_0__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_0__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_0__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_0__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_0__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_0__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_0__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_0__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_0__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_0__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_0__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_0__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_0__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_0__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_0__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_0__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_0__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_0__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_1__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_1__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_1__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_1__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_1__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_1__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_1__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_1__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_1__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_1__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_1__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_1__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_1__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_1__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_1__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_1__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_1__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_1__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_2__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_2__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_2__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_2__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_2__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_2__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_2__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_2__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_2__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_2__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_2__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_2__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_2__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_2__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_2__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_2__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_2__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_2__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_3__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_3__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_3__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_3__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_3__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_3__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_3__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_3__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_3__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_3__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_3__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_3__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_3__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_3__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_3__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_3__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_3__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_3__17_ */ +{0x0F12, 0x01BF}, /* Tune_wbt_BaseCcms_4__0_ */ +{0x0F12, 0xFFBF}, /* Tune_wbt_BaseCcms_4__1_ */ +{0x0F12, 0xFFFE}, /* Tune_wbt_BaseCcms_4__2_ */ +{0x0F12, 0xFF6D}, /* Tune_wbt_BaseCcms_4__3_ */ +{0x0F12, 0x01B4}, /* Tune_wbt_BaseCcms_4__4_ */ +{0x0F12, 0xFF66}, /* Tune_wbt_BaseCcms_4__5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_BaseCcms_4__6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_BaseCcms_4__7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_BaseCcms_4__8_ */ +{0x0F12, 0x0136}, /* Tune_wbt_BaseCcms_4__9_ */ +{0x0F12, 0x0132}, /* Tune_wbt_BaseCcms_4__10_ */ +{0x0F12, 0xFF85}, /* Tune_wbt_BaseCcms_4__11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_BaseCcms_4__12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_BaseCcms_4__13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_4__14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_BaseCcms_4__15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_BaseCcms_4__16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_BaseCcms_4__17_ */ +{0x0F12, 0x01BF}, /* Tune_wbt_BaseCcms_5__0_ */ +{0x0F12, 0xFFBF}, /* Tune_wbt_BaseCcms_5__1_ */ +{0x0F12, 0xFFFE}, /* Tune_wbt_BaseCcms_5__2_ */ +{0x0F12, 0xFF6D}, /* Tune_wbt_BaseCcms_5__3_ */ +{0x0F12, 0x01B4}, /* Tune_wbt_BaseCcms_5__4_ */ +{0x0F12, 0xFF66}, /* Tune_wbt_BaseCcms_5__5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_BaseCcms_5__6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_BaseCcms_5__7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_BaseCcms_5__8_ */ +{0x0F12, 0x0136}, /* Tune_wbt_BaseCcms_5__9_ */ +{0x0F12, 0x0132}, /* Tune_wbt_BaseCcms_5__10_ */ +{0x0F12, 0xFF85}, /* Tune_wbt_BaseCcms_5__11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_BaseCcms_5__12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_BaseCcms_5__13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_5__14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_BaseCcms_5__15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_BaseCcms_5__16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_BaseCcms_5__17_ */ +{0x002A, 0x3380}, +{0x0F12, 0x01AC}, /* Tune_wbt_OutdoorCcm_0_ */ +{0x0F12, 0xFFD7}, /* Tune_wbt_OutdoorCcm_1_ */ +{0x0F12, 0x0019}, /* Tune_wbt_OutdoorCcm_2_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_OutdoorCcm_3_ */ +{0x0F12, 0x01D9}, /* Tune_wbt_OutdoorCcm_4_ */ +{0x0F12, 0xFF63}, /* Tune_wbt_OutdoorCcm_5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_OutdoorCcm_6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_OutdoorCcm_7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_OutdoorCcm_8_ */ +{0x0F12, 0x0132}, /* Tune_wbt_OutdoorCcm_9_ */ +{0x0F12, 0x012E}, /* Tune_wbt_OutdoorCcm_10_ */ +{0x0F12, 0xFF8D}, /* Tune_wbt_OutdoorCcm_11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_OutdoorCcm_12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_OutdoorCcm_13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_OutdoorCcm_14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_OutdoorCcm_15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_OutdoorCcm_16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_OutdoorCcm_17_ */ +{0x002A, 0x0612}, +{0x0F12, 0x009D}, /* SARR_AwbCcmCord_0_ */ +{0x0F12, 0x00D5}, /* SARR_AwbCcmCord_1_ */ +{0x0F12, 0x0103}, /* SARR_AwbCcmCord_2_ */ +{0x0F12, 0x0128}, /* SARR_AwbCcmCord_3_ */ +{0x0F12, 0x0166}, /* SARR_AwbCcmCord_4_ */ +{0x0F12, 0x0193}, /* SARR_AwbCcmCord_5_ */ + +/**************************************/ +/* 15.GAMMA */ +/**************************************/ +/* For Pre Post Gamma Calibration */ +{0x002A, 0x0538}, +{0x0F12, 0x0000}, /* seti_uGammaLutPreDemNoBin_0_ */ +{0x0F12, 0x001F}, /* seti_uGammaLutPreDemNoBin_1_ */ +{0x0F12, 0x0035}, /* seti_uGammaLutPreDemNoBin_2_ */ +{0x0F12, 0x005A}, /* seti_uGammaLutPreDemNoBin_3_ */ +{0x0F12, 0x0095}, /* seti_uGammaLutPreDemNoBin_4_ */ +{0x0F12, 0x00E6}, /* seti_uGammaLutPreDemNoBin_5_ */ +{0x0F12, 0x0121}, /* seti_uGammaLutPreDemNoBin_6_ */ +{0x0F12, 0x0139}, /* seti_uGammaLutPreDemNoBin_7_ */ +{0x0F12, 0x0150}, /* seti_uGammaLutPreDemNoBin_8_ */ +{0x0F12, 0x0177}, /* seti_uGammaLutPreDemNoBin_9_ */ +{0x0F12, 0x019A}, /* seti_uGammaLutPreDemNoBin_10_ */ +{0x0F12, 0x01BB}, /* seti_uGammaLutPreDemNoBin_11_ */ +{0x0F12, 0x01DC}, /* seti_uGammaLutPreDemNoBin_12_ */ +{0x0F12, 0x0219}, /* seti_uGammaLutPreDemNoBin_13_ */ +{0x0F12, 0x0251}, /* seti_uGammaLutPreDemNoBin_14_ */ +{0x0F12, 0x02B3}, /* seti_uGammaLutPreDemNoBin_15_ */ +{0x0F12, 0x030A}, /* seti_uGammaLutPreDemNoBin_16_ */ +{0x0F12, 0x035F}, /* seti_uGammaLutPreDemNoBin_17_ */ +{0x0F12, 0x03B1}, /* seti_uGammaLutPreDemNoBin_18_ */ +{0x0F12, 0x03FF}, /* seti_uGammaLutPreDemNoBin_19_ */ +{0x0F12, 0x0000}, /* seti_uGammaLutPostDemNoBin_0_ */ +{0x0F12, 0x0001}, /* seti_uGammaLutPostDemNoBin_1_ */ +{0x0F12, 0x0001}, /* seti_uGammaLutPostDemNoBin_2_ */ +{0x0F12, 0x0002}, /* seti_uGammaLutPostDemNoBin_3_ */ +{0x0F12, 0x0004}, /* seti_uGammaLutPostDemNoBin_4_ */ +{0x0F12, 0x000A}, /* seti_uGammaLutPostDemNoBin_5_ */ +{0x0F12, 0x0012}, /* seti_uGammaLutPostDemNoBin_6_ */ +{0x0F12, 0x0016}, /* seti_uGammaLutPostDemNoBin_7_ */ +{0x0F12, 0x001A}, /* seti_uGammaLutPostDemNoBin_8_ */ +{0x0F12, 0x0024}, /* seti_uGammaLutPostDemNoBin_9_ */ +{0x0F12, 0x0031}, /* seti_uGammaLutPostDemNoBin_10_ */ +{0x0F12, 0x003E}, /* seti_uGammaLutPostDemNoBin_11_ */ +{0x0F12, 0x004E}, /* seti_uGammaLutPostDemNoBin_12_ */ +{0x0F12, 0x0075}, /* seti_uGammaLutPostDemNoBin_13_ */ +{0x0F12, 0x00A8}, /* seti_uGammaLutPostDemNoBin_14_ */ +{0x0F12, 0x0126}, /* seti_uGammaLutPostDemNoBin_15_ */ +{0x0F12, 0x01BE}, /* seti_uGammaLutPostDemNoBin_16_ */ +{0x0F12, 0x0272}, /* seti_uGammaLutPostDemNoBin_17_ */ +{0x0F12, 0x0334}, /* seti_uGammaLutPostDemNoBin_18_ */ +{0x0F12, 0x03FF}, /* seti_uGammaLutPostDemNoBin_19_ */ + +/* For Gamma Calibration */ + +{0x002A, 0x0498}, +{0x0F12, 0x0000}, /* SARR_usDualGammaLutRGBIndoor_0__0_ */ +{0x0F12, 0x0002}, /* SARR_usDualGammaLutRGBIndoor_0__1_ */ +{0x0F12, 0x0007}, /* SARR_usDualGammaLutRGBIndoor_0__2_ */ +{0x0F12, 0x001D}, /* SARR_usDualGammaLutRGBIndoor_0__3_ */ +{0x0F12, 0x006E}, /* SARR_usDualGammaLutRGBIndoor_0__4_ */ +{0x0F12, 0x00D3}, /* SARR_usDualGammaLutRGBIndoor_0__5_ */ +{0x0F12, 0x0127}, /* SARR_usDualGammaLutRGBIndoor_0__6_ */ +{0x0F12, 0x014C}, /* SARR_usDualGammaLutRGBIndoor_0__7_ */ +{0x0F12, 0x016E}, /* SARR_usDualGammaLutRGBIndoor_0__8_ */ +{0x0F12, 0x01A5}, /* SARR_usDualGammaLutRGBIndoor_0__9_ */ +{0x0F12, 0x01D3}, /* SARR_usDualGammaLutRGBIndoor_0__10_ */ +{0x0F12, 0x01FB}, /* SARR_usDualGammaLutRGBIndoor_0__11_ */ +{0x0F12, 0x021F}, /* SARR_usDualGammaLutRGBIndoor_0__12_ */ +{0x0F12, 0x0260}, /* SARR_usDualGammaLutRGBIndoor_0__13_ */ +{0x0F12, 0x029A}, /* SARR_usDualGammaLutRGBIndoor_0__14_ */ +{0x0F12, 0x02F7}, /* SARR_usDualGammaLutRGBIndoor_0__15_ */ +{0x0F12, 0x034D}, /* SARR_usDualGammaLutRGBIndoor_0__16_ */ +{0x0F12, 0x0395}, /* SARR_usDualGammaLutRGBIndoor_0__17_ */ +{0x0F12, 0x03CE}, /* SARR_usDualGammaLutRGBIndoor_0__18_ */ +{0x0F12, 0x03FF}, /* SARR_usDualGammaLutRGBIndoor_0__19_ */ +{0x0F12, 0x0000}, /* SARR_usDualGammaLutRGBOutdoor_0__0_ */ +{0x0F12, 0x0004}, /* SARR_usDualGammaLutRGBOutdoor_0__1_ */ +{0x0F12, 0x000C}, /* SARR_usDualGammaLutRGBOutdoor_0__2_ */ +{0x0F12, 0x0024}, /* SARR_usDualGammaLutRGBOutdoor_0__3_ */ +{0x0F12, 0x006E}, /* SARR_usDualGammaLutRGBOutdoor_0__4_ */ +{0x0F12, 0x00D1}, /* SARR_usDualGammaLutRGBOutdoor_0__5_ */ +{0x0F12, 0x0119}, /* SARR_usDualGammaLutRGBOutdoor_0__6_ */ +{0x0F12, 0x0139}, /* SARR_usDualGammaLutRGBOutdoor_0__7_ */ +{0x0F12, 0x0157}, /* SARR_usDualGammaLutRGBOutdoor_0__8_ */ +{0x0F12, 0x018E}, /* SARR_usDualGammaLutRGBOutdoor_0__9_ */ +{0x0F12, 0x01C3}, /* SARR_usDualGammaLutRGBOutdoor_0__10_ */ +{0x0F12, 0x01F3}, /* SARR_usDualGammaLutRGBOutdoor_0__11_ */ +{0x0F12, 0x021F}, /* SARR_usDualGammaLutRGBOutdoor_0__12_ */ +{0x0F12, 0x0269}, /* SARR_usDualGammaLutRGBOutdoor_0__13_ */ +{0x0F12, 0x02A6}, /* SARR_usDualGammaLutRGBOutdoor_0__14_ */ +{0x0F12, 0x02FF}, /* SARR_usDualGammaLutRGBOutdoor_0__15_ */ +{0x0F12, 0x0351}, /* SARR_usDualGammaLutRGBOutdoor_0__16_ */ +{0x0F12, 0x0395}, /* SARR_usDualGammaLutRGBOutdoor_0__17_ */ +{0x0F12, 0x03CE}, /* SARR_usDualGammaLutRGBOutdoor_0__18_ */ +{0x0F12, 0x03FF}, /* SARR_usDualGammaLutRGBOutdoor_0__19_ */ + +/**************************************/ +/* 16.AFIT */ +/**************************************/ +{0x002A, 0x06D4}, +{0x0F12, 0x0032}, /* afit_uNoiseIndInDoor_0_ */ +{0x0F12, 0x0078}, /* afit_uNoiseIndInDoor_1_ */ +{0x0F12, 0x00C8}, /* afit_uNoiseIndInDoor_2_ */ +{0x0F12, 0x0190}, /* afit_uNoiseIndInDoor_3_ */ +{0x0F12, 0x028C}, /* afit_uNoiseIndInDoor_4_ */ + +{0x002A, 0x0734}, +{0x0F12, 0x0000}, /* AfitBaseVals_0__0_ Brightness[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__1_ Contrast[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__2_ Saturaion[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__3_ Sharp_Blur[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__4_ */ +{0x0F12, 0x0078}, /* AfitBaseVals_0__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_0__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_0__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_0__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_0__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_0__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_0__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_0__14_ */ +{0x0F12, 0x01FF}, /* AfitBaseVals_0__15_ */ +{0x0F12, 0x0144}, /* AfitBaseVals_0__16_ */ +{0x0F12, 0x000F}, /* AfitBaseVals_0__17_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_0__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_0__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__21_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_0__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_0__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__25_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_0__27_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_0__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_0__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_0__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_0__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_0__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_0__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_0__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_0__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__40_ */ +{0x0F12, 0x1408}, /* AfitBaseVals_0__41_ */ +{0x0F12, 0x0214}, /* AfitBaseVals_0__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_0__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_0__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_0__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_0__47_ */ +{0x0F12, 0x0094}, /* AfitBaseVals_0__48_ */ +{0x0F12, 0x1080}, +{0x0F12, 0x0180}, /* AfitBaseVals_0__50_ */ +{0x0F12, 0x0308}, /* AfitBaseVals_0__51_ */ +{0x0F12, 0x3186}, /* AfitBaseVals_0__52_ */ +{0x0F12, 0x5260}, /* AfitBaseVals_0__53_ */ +{0x0F12, 0x0A02}, /* AfitBaseVals_0__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_0__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_0__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_0__57_ */ +{0x0F12, 0x324E}, /* AfitBaseVals_0__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_0__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_0__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_0__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_0__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_0__63_ */ +{0x0F12, 0x4646}, /* AfitBaseVals_0__64_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__65_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_0__68_ */ +{0x0F12, 0x3202}, /* AfitBaseVals_0__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_0__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_0__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_0__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_0__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_0__74_ */ +{0x0F12, 0x4646}, /* AfitBaseVals_0__75_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__76_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_0__79_ */ +{0x0F12, 0x3202}, /* AfitBaseVals_0__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_0__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_0__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_0__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__0_ Brightness[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__1_ Contrast[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__2_ Saturaion[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__3_ Sharp_Blur[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__4_ */ +{0x0F12, 0x006A}, /* AfitBaseVals_1__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_1__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_1__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_1__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_1__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_1__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_1__12_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_1__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_1__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_1__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_1__16_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__17_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_1__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_1__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__21_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_1__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__25_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_1__27_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_1__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_1__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_1__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_1__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_1__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_1__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_1__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__40_ */ +{0x0F12, 0x1408}, /* AfitBaseVals_1__41_ */ +{0x0F12, 0x0214}, /* AfitBaseVals_1__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_1__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_1__44_ */ +{0x0F12, 0x0002}, /* AfitBaseVals_1__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_1__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_1__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_1__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_1__50_ */ +{0x0F12, 0x0308}, /* AfitBaseVals_1__51_ */ +{0x0F12, 0x1E65}, /* AfitBaseVals_1__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_1__53_ */ +{0x0F12, 0x0A03}, /* AfitBaseVals_1__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_1__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_1__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_1__57_ */ +{0x0F12, 0x324D}, /* AfitBaseVals_1__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_1__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_1__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_1__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_1__63_ */ +{0x0F12, 0x2F34}, /* AfitBaseVals_1__64_ */ +{0x0F12, 0x0504}, /* AfitBaseVals_1__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_1__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_1__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_1__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_1__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_1__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_1__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_1__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_1__74_ */ +{0x0F12, 0x1414}, /* AfitBaseVals_1__75_ */ +{0x0F12, 0x0504}, /* AfitBaseVals_1__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_1__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_1__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_1__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_1__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_1__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_1__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__0_ Brightness[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__1_ Contrast[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__2_ Saturaion[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__3_ Sharp_Blur[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__4_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_2__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_2__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_2__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_2__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_2__12_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_2__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_2__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_2__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_2__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_2__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_2__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_2__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__21_ */ +{0x0F12, 0x0019}, /* AfitBaseVals_2__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_2__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__25_ */ +{0x0F12, 0x0019}, /* AfitBaseVals_2__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_2__27_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_2__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_2__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_2__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_2__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_2__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_2__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_2__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_2__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_2__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_2__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_2__44_ */ +{0x0F12, 0x0002}, /* AfitBaseVals_2__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_2__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_2__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_2__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_2__50_ */ +{0x0F12, 0x0208}, /* AfitBaseVals_2__51_ */ +{0x0F12, 0x1E4B}, /* AfitBaseVals_2__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_2__53_ */ +{0x0F12, 0x0A05}, /* AfitBaseVals_2__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_2__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_2__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_2__57_ */ +{0x0F12, 0x324D}, /* AfitBaseVals_2__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_2__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_2__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_2__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_2__63_ */ +{0x0F12, 0x1E23}, /* AfitBaseVals_2__64_ */ +{0x0F12, 0x0505}, /* AfitBaseVals_2__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_2__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_2__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_2__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_2__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_2__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_2__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_2__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_2__74_ */ +{0x0F12, 0x1E23}, /* AfitBaseVals_2__75_ */ +{0x0F12, 0x0505}, /* AfitBaseVals_2__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_2__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_2__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_2__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_2__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_2__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_2__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__0_ Brightness[3] */ +{0x0F12, 0x0018}, /* 0000 AfitBaseVals_3__1_ Contrast[3] */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__2_ Saturaion[3] */ +{0x0F12, 0x0004}, /* 0000 AfitBaseVals_3__3_ Sharp_Blur[3] */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__4_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_3__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_3__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_3__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_3__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_3__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_3__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_3__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_3__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_3__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_3__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_3__19_ */ +{0x0F12, 0x009F}, /* AfitBaseVals_3__20_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__21_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_3__23_ */ +{0x0F12, 0x0037}, /* AfitBaseVals_3__24_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__25_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_3__27_ */ +{0x0F12, 0x0037}, /* AfitBaseVals_3__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_3__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_3__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_3__34_ */ +{0x0F12, 0x07A0}, /* AfitBaseVals_3__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_3__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_3__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_3__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_3__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_3__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_3__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_3__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_3__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_3__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_3__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_3__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_3__50_ */ +{0x0F12, 0x0108}, /* AfitBaseVals_3__51_ */ +{0x0F12, 0x1E32}, /* AfitBaseVals_3__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_3__53_ */ +{0x0F12, 0x0A05}, /* AfitBaseVals_3__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_3__55_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__56_ */ +{0x0F12, 0x0328}, /* AfitBaseVals_3__57_ */ +{0x0F12, 0x324C}, /* AfitBaseVals_3__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_3__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_3__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_3__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_3__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_3__63_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_3__64_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_3__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_3__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_3__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_3__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_3__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_3__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_3__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_3__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_3__74_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_3__75_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_3__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_3__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_3__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_3__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_3__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_3__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_3__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__0_ Brightness[4] */ +{0x0F12, 0x0014}, /* 0000 AfitBaseVals_4__1_ Contrast[4] */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__2_ Saturaion[4] */ +{0x0F12, 0x0008}, /* 0000 AfitBaseVals_4__3_ Sharp_Blur[4] */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__4_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_4__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_4__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_4__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_4__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_4__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_4__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_4__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_4__14_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_4__15_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_4__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_4__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_4__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_4__19_ */ +{0x0F12, 0x00B4}, /* AfitBaseVals_4__20_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__21_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_4__23_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_4__24_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__25_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_4__27_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_4__28_ */ +{0x0F12, 0x2B23}, /* AfitBaseVals_4__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_4__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_4__34_ */ +{0x0F12, 0x0B84}, /* AfitBaseVals_4__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_4__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_4__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_4__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_4__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_4__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_4__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_4__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_4__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_4__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_4__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_4__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_4__50_ */ +{0x0F12, 0x0108}, /* AfitBaseVals_4__51_ */ +{0x0F12, 0x1E1E}, /* AfitBaseVals_4__52_ */ +{0x0F12, 0x1419}, /* AfitBaseVals_4__53_ */ +{0x0F12, 0x0A0A}, /* AfitBaseVals_4__54_ */ +{0x0F12, 0x0800}, /* AfitBaseVals_4__55_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__56_ */ +{0x0F12, 0x0328}, /* AfitBaseVals_4__57_ */ +{0x0F12, 0x324C}, /* AfitBaseVals_4__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_4__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_4__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_4__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_4__62_ */ +{0x0F12, 0x6464}, /* AfitBaseVals_4__63_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_4__64_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_4__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_4__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_4__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_4__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_4__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_4__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_4__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_4__73_ */ +{0x0F12, 0x6464}, /* AfitBaseVals_4__74_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_4__75_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_4__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_4__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_4__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_4__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_4__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_4__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_4__83_ */ +{0x0F12, 0x7F5E}, /* ConstAfitBaseVals_0_ */ +{0x0F12, 0xFEEE}, /* ConstAfitBaseVals_1_ */ +{0x0F12, 0xD9B7}, /* ConstAfitBaseVals_2_ */ +{0x0F12, 0x0472}, /* ConstAfitBaseVals_3_ */ +{0x0F12, 0x0001}, /* ConstAfitBaseVals_4_ */ + +/**************************************/ +/* 17.JPEG Thumnail Setting */ +/**************************************/ + +/**************************************/ +/* 18.Input Size Setting */ +/**************************************/ + +/************************************************/ +/* 19.Preview & Capture Configration Setting */ +/************************************************/ +/* Preview config[0] 640X480 15fps fixed */ +{0x002A, 0x01BE}, +{0x0F12, 0x0280}, /* REG_0TC_PCFG_usWidth 500:1280; 280:640 */ +{0x0F12, 0x01E0}, /* REG_0TC_PCFG_usHeight 3C0:960; 1E0:480 */ +{0x0F12, 0x0005}, /* REG_0TC_PCFG_Format 5:YUV422; 7:RAW10 */ +{0x002A, 0x01C8}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uClockInd */ +{0x002A, 0x01C4}, +{0x0F12, 0x0052}, /* REG_0TC_PCFG_PVIMask 52:YUV422, 42:RAW10 */ +{0x002A, 0x01D4}, +{0x0F12, 0x0002}, +{0x002A, 0x01D2}, +{0x0F12, 0x0002}, +{0x002A, 0x01D8}, +{0x0F12, 0x029A}, +{0x002A, 0x01D6}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_usMinFrTimeMsecMult10 */ +{0x002A, 0x01E8}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uPrevMirror */ +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uCaptureMirror */ + +/* Preview config[1] 1280X960 7.5fps */ +{0x002A, 0x01EE}, +{0x0F12, 0x0500}, /* 1280 */ +{0x0F12, 0x03C0}, /* 960 */ +{0x0F12, 0x0005}, /* YUV422 */ +{0x002A, 0x01F8}, +{0x0F12, 0x0000}, +{0x002A, 0x01F4}, +{0x0F12, 0x0052}, +{0x002A, 0x0204}, +{0x0F12, 0x0002}, /* 1b: FR (bin) 2b: Quality (no-bin) */ +{0x002A, 0x0202}, +{0x0F12, 0x0001}, +{0x002A, 0x0208}, +{0x0F12, 0x0535}, +{0x002A, 0x0206}, +{0x0F12, 0x0000}, +{0x002A, 0x0218}, +{0x0F12, 0x0000}, /* REG_1TC_PCFG_uPrevMirror */ +{0x0F12, 0x0000}, /* REG_1TC_PCFG_uCaptureMirror */ + +/* Capture config[0] 1280x960 8fps */ +/* {0x002A, 0x02AE}, */ +/* {0x0F12, 0x0001}, */ /* Capture mode AE On */ +{0x002A, 0x02B0}, +{0x0F12, 0x0500}, /* REG_0TC_CCFG_usWidth 500:1280; 280:640 */ +{0x0F12, 0x03C0}, /* REG_0TC_CCFG_usHeight 3C0:960; 1E0:480 */ +{0x0F12, 0x0005}, /* REG_0TC_CCFG_Format 5:YUV422; 7:RAW10 */ +{0x002A, 0x02BA}, +{0x0F12, 0x0000}, /* REG_0TC_CCFG_uClockInd */ +{0x002A, 0x02B6}, +{0x0F12, 0x0052}, /* REG_0TC_CCFG_PVIMask 52:YUV422; 42:RAW10 */ +{0x002A, 0x02C6}, +{0x0F12, 0x0002}, +{0x002A, 0x02C4}, +{0x0F12, 0x0002}, +{0x002A, 0x02CA}, +{0x0F12, 0x04E2}, +{0x002A, 0x02C8}, +{0x0F12, 0x0000}, /* REG_0TC_CCFG_usMinFrTimeMsecMult10 */ + +/**************************************/ +/* 20.Clock Setting */ +/**************************************/ +/* Input Clock (Mclk) */ +{0x002A, 0x012E}, +{0x0F12, 0x5DC0}, /* REG_TC_IPRM_InClockLSBs */ +{0x0F12, 0x0000}, /* REG_TC_IPRM_InClockMSBs */ +{0x002A, 0x0146}, +{0x0F12, 0x0000}, /* REG_TC_IPRM_UseNPviClocks */ +{0x0F12, 0x0001}, /* REG_TC_IPRM_UseNMipiClocks */ + +/* System Clock & Output clock (Pclk) */ +{0x002A, 0x014C}, +{0x0F12, 0x1B58}, /* REG_TC_IPRM_OpClk4KHz_0 */ +{0x002A, 0x0152}, +{0x0F12, 0x36B0}, /* REG_TC_IPRM_MinOutRate4KHz_0 */ +{0x002A, 0x014E}, +{0x0F12, 0x36B0}, /* REG_TC_IPRM_MaxOutRate4KHz_0 */ +{0x002A, 0x01A8}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActivePrevConfig */ +{0x002A, 0x01B0}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActiveCapConfig */ +{0x002A, 0x019E}, +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreview */ +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreviewChanged */ +{0x002A, 0x0164}, +{0x0F12, 0x0001}, /* REG_TC_IPRM_InitParamsUpdated */ +{0x0028, 0xD000}, +{0x002A, 0x1000}, +{0x0F12, 0x0001}, /* Set host interrupt */ +{0xffff, 0x000a}, + +/* End of Wifi VT-Call init */ +}; + + + +struct s5k8aay_short_t s5k8aay_recording_common[] = { +/* Start of Recording init */ + +/**************************************/ +/* 01.Start Setting */ +/**************************************/ +{0xFCFC, 0xD000}, +{0x0010, 0x0001}, /* S/W Reset */ +{0xFCFC, 0x0000}, +{0x0000, 0x0000}, /* Simmian bug workaround */ + +{0xFCFC, 0xD000}, +{0x1030, 0x0000}, /* contint_host_int */ +{0x0014, 0x0001}, +{0xffff, 0x0001}, /* Delay 1ms */ + +/**************************************/ +/*02.ETC Setting */ +/**************************************/ +{0x002A, 0x1278}, +{0x0F12, 0xAAF0}, /* gisp_dadlc_config Ladlc mode average*/ + +/*********************************************** + * 03.Analog Setting & ASP Control + *********************************************** + * This register is for FACTORY ONLY. + * If you change it without prior notification + * YOU are RESPONSIBLE for the FAILURE + *that will happen in the future + * For CDS Timing + *********************************************** + */ +{0x002A, 0x0EC6}, +{0x0F12, 0x000B}, /* 11d aig_fdba_ptr0 */ +{0x002A, 0x0ECE}, +{0x0F12, 0x000B}, /* 11d aig_fdbb_ptr0 */ +{0x002A, 0x0F16}, +{0x0F12, 0x002B}, /* 43d aig_sfdba_reg0 */ +{0x002A, 0x0F1E}, +{0x0F12, 0x002B}, /* 43d aig_sfdbb_reg0 */ +{0x002A, 0x0EC8}, +{0x0F12, 0x000B}, /* 11d aig_fdba_ptr0 */ +{0x002A, 0x0ED0}, +{0x0F12, 0x033F}, /* 831d aig_fdbb_ptr0 */ +{0x002A, 0x0F18}, +{0x0F12, 0x0366}, /* 870d aig_sfdba_reg0 */ +{0x002A, 0x0F20}, +{0x0F12, 0x0032}, /* 50d aig_sfdbb_reg0 */ + +/* For Other Analog Settings */ +{0x002A, 0x0E38}, +{0x0F12, 0x0476}, /* senHal_RegCompBiasNormSf CDS bias */ +{0x0F12, 0x0476}, /* senHal_RegCompBiasYAv CDS bias */ +{0x002A, 0x0AA0}, +{0x0F12, 0x0001}, /* setot_bUseDigitalHbin 1-Digital, 0-Analog */ +{0x002A, 0x0E2C}, +{0x0F12, 0x0001}, +{0x002A, 0x1250}, +{0x0F12, 0xFFFF}, /* senHal_Bls_nSpExpLines */ +{0x002A, 0x1202}, +{0x0F12, 0x0010}, /* senHal_Dblr_VcoFreqMHZ */ + +/**************************************/ +/* 04.Trap and Patch */ +/**************************************/ +/* Start of Patch data */ +{0x0028, 0x7000}, +{0x002A, 0x2470}, +{0x0F12, 0xB510}, /* 70002470 */ +{0x0F12, 0x490D}, /* 70002472 */ +{0x0F12, 0x480D}, /* 70002474 */ +{0x0F12, 0xF000}, /* 70002476 */ +{0x0F12, 0xF96D}, /* 70002478 */ +{0x0F12, 0x490D}, /* 7000247A */ +{0x0F12, 0x480D}, /* 7000247C */ +{0x0F12, 0xF000}, /* 7000247E */ +{0x0F12, 0xF969}, /* 70002480 */ +{0x0F12, 0x490D}, /* 70002482 */ +{0x0F12, 0x480D}, /* 70002484 */ +{0x0F12, 0x6341}, /* 70002486 */ +{0x0F12, 0x490D}, /* 70002488 */ +{0x0F12, 0x480E}, /* 7000248A */ +{0x0F12, 0xF000}, /* 7000248C */ +{0x0F12, 0xF962}, /* 7000248E */ +{0x0F12, 0x490D}, /* 70002490 */ +{0x0F12, 0x480E}, /* 70002492 */ +{0x0F12, 0xF000}, /* 70002494 */ +{0x0F12, 0xF95E}, /* 70002496 */ +{0x0F12, 0x490D}, /* 70002498 */ +{0x0F12, 0x480E}, /* 7000249A */ +{0x0F12, 0xF000}, /* 7000249C */ +{0x0F12, 0xF95A}, /* 7000249E */ +{0x0F12, 0xBC10}, /* 700024A0 */ +{0x0F12, 0xBC08}, /* 700024A2 */ +{0x0F12, 0x4718}, /* 700024A4 */ +{0x0F12, 0x0000}, /* 700024A6 */ +{0x0F12, 0x26D4}, /* 700024A8 */ +{0x0F12, 0x7000}, /* 700024AA */ +{0x0F12, 0x8EDD}, /* 700024AC */ +{0x0F12, 0x0000}, /* 700024AE */ +{0x0F12, 0x264C}, /* 700024B0 */ +{0x0F12, 0x7000}, /* 700024B2 */ +{0x0F12, 0x8725}, /* 700024B4 */ +{0x0F12, 0x0000}, /* 700024B6 */ +{0x0F12, 0x25EC}, /* 700024B8 */ +{0x0F12, 0x7000}, /* 700024BA */ +{0x0F12, 0x0080}, /* 700024BC */ +{0x0F12, 0x7000}, /* 700024BE */ +{0x0F12, 0x2540}, /* 700024C0 */ +{0x0F12, 0x7000}, /* 700024C2 */ +{0x0F12, 0xA6EF}, /* 700024C4 */ +{0x0F12, 0x0000}, /* 700024C6 */ +{0x0F12, 0x250C}, /* 700024C8 */ +{0x0F12, 0x7000}, /* 700024CA */ +{0x0F12, 0xA0F1}, /* 700024CC */ +{0x0F12, 0x0000}, /* 700024CE */ +{0x0F12, 0x24D8}, /* 700024D0 */ +{0x0F12, 0x7000}, /* 700024D2 */ +{0x0F12, 0x058F}, /* 700024D4 */ +{0x0F12, 0x0000}, /* 700024D6 */ +{0x0F12, 0x4010}, /* 700024D8 */ +{0x0F12, 0xE92D}, /* 700024DA */ +{0x0F12, 0x00A0}, /* 700024DC */ +{0x0F12, 0xEB00}, /* 700024DE */ +{0x0F12, 0x023C}, /* 700024E0 */ +{0x0F12, 0xE59F}, /* 700024E2 */ +{0x0F12, 0x00B2}, /* 700024E4 */ +{0x0F12, 0xE1D0}, /* 700024E6 */ +{0x0F12, 0x0000}, /* 700024E8 */ +{0x0F12, 0xE350}, /* 700024EA */ +{0x0F12, 0x0004}, /* 700024EC */ +{0x0F12, 0x0A00}, /* 700024EE */ +{0x0F12, 0x0080}, /* 700024F0 */ +{0x0F12, 0xE310}, /* 700024F2 */ +{0x0F12, 0x0002}, /* 700024F4 */ +{0x0F12, 0x1A00}, /* 700024F6 */ +{0x0F12, 0x1228}, /* 700024F8 */ +{0x0F12, 0xE59F}, /* 700024FA */ +{0x0F12, 0x0001}, /* 700024FC */ +{0x0F12, 0xE3A0}, /* 700024FE */ +{0x0F12, 0x0DB2}, /* 70002500 */ +{0x0F12, 0xE1C1}, /* 70002502 */ +{0x0F12, 0x4010}, /* 70002504 */ +{0x0F12, 0xE8BD}, /* 70002506 */ +{0x0F12, 0xFF1E}, /* 70002508 */ +{0x0F12, 0xE12F}, /* 7000250A */ +{0x0F12, 0x4010}, /* 7000250C */ +{0x0F12, 0xE92D}, /* 7000250E */ +{0x0F12, 0x4000}, /* 70002510 */ +{0x0F12, 0xE590}, /* 70002512 */ +{0x0F12, 0x0004}, /* 70002514 */ +{0x0F12, 0xE1A0}, /* 70002516 */ +{0x0F12, 0x0094}, /* 70002518 */ +{0x0F12, 0xEB00}, /* 7000251A */ +{0x0F12, 0x0208}, /* 7000251C */ +{0x0F12, 0xE59F}, /* 7000251E */ +{0x0F12, 0x0000}, /* 70002520 */ +{0x0F12, 0xE5D0}, /* 70002522 */ +{0x0F12, 0x0000}, /* 70002524 */ +{0x0F12, 0xE350}, /* 70002526 */ +{0x0F12, 0x0002}, /* 70002528 */ +{0x0F12, 0x0A00}, /* 7000252A */ +{0x0F12, 0x0004}, /* 7000252C */ +{0x0F12, 0xE594}, /* 7000252E */ +{0x0F12, 0x00A0}, /* 70002530 */ +{0x0F12, 0xE1A0}, /* 70002532 */ +{0x0F12, 0x0004}, /* 70002534 */ +{0x0F12, 0xE584}, /* 70002536 */ +{0x0F12, 0x4010}, /* 70002538 */ +{0x0F12, 0xE8BD}, /* 7000253A */ +{0x0F12, 0xFF1E}, /* 7000253C */ +{0x0F12, 0xE12F}, /* 7000253E */ +{0x0F12, 0x4070}, /* 70002540 */ +{0x0F12, 0xE92D}, /* 70002542 */ +{0x0F12, 0x0000}, /* 70002544 */ +{0x0F12, 0xE590}, /* 70002546 */ +{0x0F12, 0x0800}, /* 70002548 */ +{0x0F12, 0xE1A0}, /* 7000254A */ +{0x0F12, 0x0820}, /* 7000254C */ +{0x0F12, 0xE1A0}, /* 7000254E */ +{0x0F12, 0x4041}, /* 70002550 */ +{0x0F12, 0xE280}, /* 70002552 */ +{0x0F12, 0x01D4}, /* 70002554 */ +{0x0F12, 0xE59F}, /* 70002556 */ +{0x0F12, 0x11B8}, /* 70002558 */ +{0x0F12, 0xE1D0}, /* 7000255A */ +{0x0F12, 0x51B6}, /* 7000255C */ +{0x0F12, 0xE1D0}, /* 7000255E */ +{0x0F12, 0x0005}, /* 70002560 */ +{0x0F12, 0xE041}, /* 70002562 */ +{0x0F12, 0x0094}, /* 70002564 */ +{0x0F12, 0xE000}, /* 70002566 */ +{0x0F12, 0x1D11}, /* 70002568 */ +{0x0F12, 0xE3A0}, /* 7000256A */ +{0x0F12, 0x0082}, /* 7000256C */ +{0x0F12, 0xEB00}, /* 7000256E */ +{0x0F12, 0x11B4}, /* 70002570 */ +{0x0F12, 0xE59F}, /* 70002572 */ +{0x0F12, 0x1000}, /* 70002574 */ +{0x0F12, 0xE5D1}, /* 70002576 */ +{0x0F12, 0x0000}, /* 70002578 */ +{0x0F12, 0xE351}, /* 7000257A */ +{0x0F12, 0x0000}, /* 7000257C */ +{0x0F12, 0x0A00}, /* 7000257E */ +{0x0F12, 0x00A0}, /* 70002580 */ +{0x0F12, 0xE1A0}, /* 70002582 */ +{0x0F12, 0x219C}, /* 70002584 */ +{0x0F12, 0xE59F}, /* 70002586 */ +{0x0F12, 0x3FB0}, /* 70002588 */ +{0x0F12, 0xE1D2}, /* 7000258A */ +{0x0F12, 0x0000}, /* 7000258C */ +{0x0F12, 0xE353}, /* 7000258E */ +{0x0F12, 0x0003}, /* 70002590 */ +{0x0F12, 0x0A00}, /* 70002592 */ +{0x0F12, 0x3198}, /* 70002594 */ +{0x0F12, 0xE59F}, /* 70002596 */ +{0x0F12, 0x5BB2}, /* 70002598 */ +{0x0F12, 0xE1C3}, /* 7000259A */ +{0x0F12, 0xC000}, /* 7000259C */ +{0x0F12, 0xE085}, /* 7000259E */ +{0x0F12, 0xCBB4}, /* 700025A0 */ +{0x0F12, 0xE1C3}, /* 700025A2 */ +{0x0F12, 0x0000}, /* 700025A4 */ +{0x0F12, 0xE351}, /* 700025A6 */ +{0x0F12, 0x0000}, /* 700025A8 */ +{0x0F12, 0x0A00}, /* 700025AA */ +{0x0F12, 0x0080}, /* 700025AC */ +{0x0F12, 0xE1A0}, /* 700025AE */ +{0x0F12, 0x1DBC}, /* 700025B0 */ +{0x0F12, 0xE1D2}, /* 700025B2 */ +{0x0F12, 0x3EB4}, /* 700025B4 */ +{0x0F12, 0xE1D2}, /* 700025B6 */ +{0x0F12, 0x2EB2}, /* 700025B8 */ +{0x0F12, 0xE1D2}, /* 700025BA */ +{0x0F12, 0x0193}, /* 700025BC */ +{0x0F12, 0xE001}, /* 700025BE */ +{0x0F12, 0x0092}, /* 700025C0 */ +{0x0F12, 0xE000}, /* 700025C2 */ +{0x0F12, 0x2811}, /* 700025C4 */ +{0x0F12, 0xE3A0}, /* 700025C6 */ +{0x0F12, 0x0194}, /* 700025C8 */ +{0x0F12, 0xE001}, /* 700025CA */ +{0x0F12, 0x0092}, /* 700025CC */ +{0x0F12, 0xE000}, /* 700025CE */ +{0x0F12, 0x11A1}, /* 700025D0 */ +{0x0F12, 0xE1A0}, /* 700025D2 */ +{0x0F12, 0x01A0}, /* 700025D4 */ +{0x0F12, 0xE1A0}, /* 700025D6 */ +{0x0F12, 0x0067}, /* 700025D8 */ +{0x0F12, 0xEB00}, /* 700025DA */ +{0x0F12, 0x1154}, /* 700025DC */ +{0x0F12, 0xE59F}, /* 700025DE */ +{0x0F12, 0x02B4}, /* 700025E0 */ +{0x0F12, 0xE1C1}, /* 700025E2 */ +{0x0F12, 0x4070}, /* 700025E4 */ +{0x0F12, 0xE8BD}, /* 700025E6 */ +{0x0F12, 0xFF1E}, /* 700025E8 */ +{0x0F12, 0xE12F}, /* 700025EA */ +{0x0F12, 0x4010}, /* 700025EC */ +{0x0F12, 0xE92D}, /* 700025EE */ +{0x0F12, 0x0063}, /* 700025F0 */ +{0x0F12, 0xEB00}, /* 700025F2 */ +{0x0F12, 0x213C}, /* 700025F4 */ +{0x0F12, 0xE59F}, /* 700025F6 */ +{0x0F12, 0x14B0}, /* 700025F8 */ +{0x0F12, 0xE1D2}, /* 700025FA */ +{0x0F12, 0x0080}, /* 700025FC */ +{0x0F12, 0xE311}, /* 700025FE */ +{0x0F12, 0x0005}, /* 70002600 */ +{0x0F12, 0x0A00}, /* 70002602 */ +{0x0F12, 0x0130}, /* 70002604 */ +{0x0F12, 0xE59F}, /* 70002606 */ +{0x0F12, 0x00B0}, /* 70002608 */ +{0x0F12, 0xE1D0}, /* 7000260A */ +{0x0F12, 0x0001}, /* 7000260C */ +{0x0F12, 0xE350}, /* 7000260E */ +{0x0F12, 0x0001}, /* 70002610 */ +{0x0F12, 0x9A00}, /* 70002612 */ +{0x0F12, 0x0001}, /* 70002614 */ +{0x0F12, 0xE3A0}, /* 70002616 */ +{0x0F12, 0x0000}, /* 70002618 */ +{0x0F12, 0xEA00}, /* 7000261A */ +{0x0F12, 0x0000}, /* 7000261C */ +{0x0F12, 0xE3A0}, /* 7000261E */ +{0x0F12, 0x3104}, /* 70002620 */ +{0x0F12, 0xE59F}, /* 70002622 */ +{0x0F12, 0x0000}, /* 70002624 */ +{0x0F12, 0xE5C3}, /* 70002626 */ +{0x0F12, 0x0000}, /* 70002628 */ +{0x0F12, 0xE5D3}, /* 7000262A */ +{0x0F12, 0x0000}, /* 7000262C */ +{0x0F12, 0xE350}, /* 7000262E */ +{0x0F12, 0x0003}, /* 70002630 */ +{0x0F12, 0x0A00}, /* 70002632 */ +{0x0F12, 0x0080}, /* 70002634 */ +{0x0F12, 0xE3C1}, /* 70002636 */ +{0x0F12, 0x1100}, /* 70002638 */ +{0x0F12, 0xE59F}, /* 7000263A */ +{0x0F12, 0x04B0}, /* 7000263C */ +{0x0F12, 0xE1C2}, /* 7000263E */ +{0x0F12, 0x00B2}, /* 70002640 */ +{0x0F12, 0xE1C1}, /* 70002642 */ +{0x0F12, 0x4010}, /* 70002644 */ +{0x0F12, 0xE8BD}, /* 70002646 */ +{0x0F12, 0xFF1E}, /* 70002648 */ +{0x0F12, 0xE12F}, /* 7000264A */ +{0x0F12, 0x41F0}, /* 7000264C */ +{0x0F12, 0xE92D}, /* 7000264E */ +{0x0F12, 0x1000}, /* 70002650 */ +{0x0F12, 0xE590}, /* 70002652 */ +{0x0F12, 0xC801}, /* 70002654 */ +{0x0F12, 0xE1A0}, /* 70002656 */ +{0x0F12, 0xC82C}, /* 70002658 */ +{0x0F12, 0xE1A0}, /* 7000265A */ +{0x0F12, 0x1004}, /* 7000265C */ +{0x0F12, 0xE590}, /* 7000265E */ +{0x0F12, 0x1801}, /* 70002660 */ +{0x0F12, 0xE1A0}, /* 70002662 */ +{0x0F12, 0x1821}, /* 70002664 */ +{0x0F12, 0xE1A0}, /* 70002666 */ +{0x0F12, 0x4008}, /* 70002668 */ +{0x0F12, 0xE590}, /* 7000266A */ +{0x0F12, 0x500C}, /* 7000266C */ +{0x0F12, 0xE590}, /* 7000266E */ +{0x0F12, 0x2004}, /* 70002670 */ +{0x0F12, 0xE1A0}, /* 70002672 */ +{0x0F12, 0x3005}, /* 70002674 */ +{0x0F12, 0xE1A0}, /* 70002676 */ +{0x0F12, 0x000C}, /* 70002678 */ +{0x0F12, 0xE1A0}, /* 7000267A */ +{0x0F12, 0x0043}, /* 7000267C */ +{0x0F12, 0xEB00}, /* 7000267E */ +{0x0F12, 0x60BC}, /* 70002680 */ +{0x0F12, 0xE59F}, /* 70002682 */ +{0x0F12, 0x00B2}, /* 70002684 */ +{0x0F12, 0xE1D6}, /* 70002686 */ +{0x0F12, 0x0000}, /* 70002688 */ +{0x0F12, 0xE350}, /* 7000268A */ +{0x0F12, 0x000E}, /* 7000268C */ +{0x0F12, 0x0A00}, /* 7000268E */ +{0x0F12, 0x00B0}, /* 70002690 */ +{0x0F12, 0xE59F}, /* 70002692 */ +{0x0F12, 0x05B4}, /* 70002694 */ +{0x0F12, 0xE1D0}, /* 70002696 */ +{0x0F12, 0x0002}, /* 70002698 */ +{0x0F12, 0xE350}, /* 7000269A */ +{0x0F12, 0x000A}, /* 7000269C */ +{0x0F12, 0x1A00}, /* 7000269E */ +{0x0F12, 0x70A4}, /* 700026A0 */ +{0x0F12, 0xE59F}, /* 700026A2 */ +{0x0F12, 0x10F4}, /* 700026A4 */ +{0x0F12, 0xE1D6}, /* 700026A6 */ +{0x0F12, 0x26B0}, /* 700026A8 */ +{0x0F12, 0xE1D7}, /* 700026AA */ +{0x0F12, 0x00F0}, /* 700026AC */ +{0x0F12, 0xE1D4}, /* 700026AE */ +{0x0F12, 0x0039}, /* 700026B0 */ +{0x0F12, 0xEB00}, /* 700026B2 */ +{0x0F12, 0x00B0}, /* 700026B4 */ +{0x0F12, 0xE1C4}, /* 700026B6 */ +{0x0F12, 0x26B0}, /* 700026B8 */ +{0x0F12, 0xE1D7}, /* 700026BA */ +{0x0F12, 0x10F6}, /* 700026BC */ +{0x0F12, 0xE1D6}, /* 700026BE */ +{0x0F12, 0x00F0}, /* 700026C0 */ +{0x0F12, 0xE1D5}, /* 700026C2 */ +{0x0F12, 0x0034}, /* 700026C4 */ +{0x0F12, 0xEB00}, /* 700026C6 */ +{0x0F12, 0x00B0}, /* 700026C8 */ +{0x0F12, 0xE1C5}, /* 700026CA */ +{0x0F12, 0x41F0}, /* 700026CC */ +{0x0F12, 0xE8BD}, /* 700026CE */ +{0x0F12, 0xFF1E}, /* 700026D0 */ +{0x0F12, 0xE12F}, /* 700026D2 */ +{0x0F12, 0x4010}, /* 700026D4 */ +{0x0F12, 0xE92D}, /* 700026D6 */ +{0x0F12, 0x4000}, /* 700026D8 */ +{0x0F12, 0xE1A0}, /* 700026DA */ +{0x0F12, 0x1004}, /* 700026DC */ +{0x0F12, 0xE594}, /* 700026DE */ +{0x0F12, 0x005C}, /* 700026E0 */ +{0x0F12, 0xE59F}, /* 700026E2 */ +{0x0F12, 0x00B0}, /* 700026E4 */ +{0x0F12, 0xE1D0}, /* 700026E6 */ +{0x0F12, 0x0000}, /* 700026E8 */ +{0x0F12, 0xE350}, /* 700026EA */ +{0x0F12, 0x0008}, /* 700026EC */ +{0x0F12, 0x0A00}, /* 700026EE */ +{0x0F12, 0x0054}, /* 700026F0 */ +{0x0F12, 0xE59F}, /* 700026F2 */ +{0x0F12, 0x3001}, /* 700026F4 */ +{0x0F12, 0xE1A0}, /* 700026F6 */ +{0x0F12, 0x2068}, /* 700026F8 */ +{0x0F12, 0xE590}, /* 700026FA */ +{0x0F12, 0x004C}, /* 700026FC */ +{0x0F12, 0xE59F}, /* 700026FE */ +{0x0F12, 0x1005}, /* 70002700 */ +{0x0F12, 0xE3A0}, /* 70002702 */ +{0x0F12, 0x0027}, /* 70002704 */ +{0x0F12, 0xEB00}, /* 70002706 */ +{0x0F12, 0x0000}, /* 70002708 */ +{0x0F12, 0xE584}, /* 7000270A */ +{0x0F12, 0x4010}, /* 7000270C */ +{0x0F12, 0xE8BD}, /* 7000270E */ +{0x0F12, 0xFF1E}, /* 70002710 */ +{0x0F12, 0xE12F}, /* 70002712 */ +{0x0F12, 0x0000}, /* 70002714 */ +{0x0F12, 0xE594}, /* 70002716 */ +{0x0F12, 0x0025}, /* 70002718 */ +{0x0F12, 0xEB00}, /* 7000271A */ +{0x0F12, 0x0000}, /* 7000271C */ +{0x0F12, 0xE584}, /* 7000271E */ +{0x0F12, 0xFFF9}, /* 70002720 */ +{0x0F12, 0xEAFF}, /* 70002722 */ +{0x0F12, 0x1728}, /* 70002724 */ +{0x0F12, 0x7000}, /* 70002726 */ +{0x0F12, 0x112C}, /* 70002728 */ +{0x0F12, 0x7000}, /* 7000272A */ +{0x0F12, 0x27C4}, /* 7000272C */ +{0x0F12, 0x7000}, /* 7000272E */ +{0x0F12, 0x122C}, /* 70002730 */ +{0x0F12, 0x7000}, /* 70002732 */ +{0x0F12, 0xF200}, /* 70002734 */ +{0x0F12, 0xD000}, /* 70002736 */ +{0x0F12, 0x2340}, /* 70002738 */ +{0x0F12, 0x7000}, /* 7000273A */ +{0x0F12, 0x0E2C}, /* 7000273C */ +{0x0F12, 0x7000}, /* 7000273E */ +{0x0F12, 0xF400}, /* 70002740 */ +{0x0F12, 0xD000}, /* 70002742 */ +{0x0F12, 0x3370}, /* 70002744 */ +{0x0F12, 0x7000}, /* 70002746 */ +{0x0F12, 0x0CDC}, /* 70002748 */ +{0x0F12, 0x7000}, /* 7000274A */ +{0x0F12, 0x20D4}, /* 7000274C */ +{0x0F12, 0x7000}, /* 7000274E */ +{0x0F12, 0x06D4}, /* 70002750 */ +{0x0F12, 0x7000}, /* 70002752 */ +{0x0F12, 0x4778}, /* 70002754 */ +{0x0F12, 0x46C0}, /* 70002756 */ +{0x0F12, 0xC000}, /* 70002758 */ +{0x0F12, 0xE59F}, /* 7000275A */ +{0x0F12, 0xFF1C}, /* 7000275C */ +{0x0F12, 0xE12F}, /* 7000275E */ +{0x0F12, 0xC091}, /* 70002760 */ +{0x0F12, 0x0000}, /* 70002762 */ +{0x0F12, 0xC000}, /* 70002764 */ +{0x0F12, 0xE59F}, /* 70002766 */ +{0x0F12, 0xFF1C}, /* 70002768 */ +{0x0F12, 0xE12F}, /* 7000276A */ +{0x0F12, 0x058F}, /* 7000276C */ +{0x0F12, 0x0000}, /* 7000276E */ +{0x0F12, 0xC000}, /* 70002770 */ +{0x0F12, 0xE59F}, /* 70002772 */ +{0x0F12, 0xFF1C}, /* 70002774 */ +{0x0F12, 0xE12F}, /* 70002776 */ +{0x0F12, 0xA0F1}, /* 70002778 */ +{0x0F12, 0x0000}, /* 7000277A */ +{0x0F12, 0xF004}, /* 7000277C */ +{0x0F12, 0xE51F}, /* 7000277E */ +{0x0F12, 0xD14C}, /* 70002780 */ +{0x0F12, 0x0000}, /* 70002782 */ +{0x0F12, 0xC000}, /* 70002784 */ +{0x0F12, 0xE59F}, /* 70002786 */ +{0x0F12, 0xFF1C}, /* 70002788 */ +{0x0F12, 0xE12F}, /* 7000278A */ +{0x0F12, 0x2B43}, /* 7000278C */ +{0x0F12, 0x0000}, /* 7000278E */ +{0x0F12, 0xC000}, /* 70002790 */ +{0x0F12, 0xE59F}, /* 70002792 */ +{0x0F12, 0xFF1C}, /* 70002794 */ +{0x0F12, 0xE12F}, /* 70002796 */ +{0x0F12, 0x8725}, /* 70002798 */ +{0x0F12, 0x0000}, /* 7000279A */ +{0x0F12, 0xC000}, /* 7000279C */ +{0x0F12, 0xE59F}, /* 7000279E */ +{0x0F12, 0xFF1C}, /* 700027A0 */ +{0x0F12, 0xE12F}, /* 700027A2 */ +{0x0F12, 0x6777}, /* 700027A4 */ +{0x0F12, 0x0000}, /* 700027A6 */ +{0x0F12, 0xC000}, /* 700027A8 */ +{0x0F12, 0xE59F}, /* 700027AA */ +{0x0F12, 0xFF1C}, /* 700027AC */ +{0x0F12, 0xE12F}, /* 700027AE */ +{0x0F12, 0x8E49}, /* 700027B0 */ +{0x0F12, 0x0000}, /* 700027B2 */ +{0x0F12, 0xC000}, /* 700027B4 */ +{0x0F12, 0xE59F}, /* 700027B6 */ +{0x0F12, 0xFF1C}, /* 700027B8 */ +{0x0F12, 0xE12F}, /* 700027BA */ +{0x0F12, 0x8EDD}, /* 700027BC */ +{0x0F12, 0x0000}, /* 700027BE */ +{0x0F12, 0x90C8}, /* 700027C0 */ +{0x0F12, 0x0000}, /* 700027C2 */ +/* End of Patch Data(Last : 700027C2h) */ +/* Total Size 852 (0x0354) */ +/* Addr : 2470 , Size : 850(352h) */ + +/**************************************/ +/* 05.OTP Control */ +/**************************************/ + +/**************************************/ +/* 06.GAS (Grid Anti-Shading) */ +/**************************************/ +{0x002A, 0x1326}, +{0x0F12, 0x0000}, /* gisp_gos_Enable */ +{0x002A, 0x063A}, +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__0_ Horizon */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_0__3_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__0_ IncandA */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_1__3_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__0_ WW */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_2__3_ */ +{0x0F12, 0x00E8}, /* TVAR_ash_GASAlpha_3__0_ CW */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_3__3_ */ +{0x0F12, 0x00E8}, /* TVAR_ash_GASAlpha_4__0_ D50 */ +{0x0F12, 0x00F8}, /* TVAR_ash_GASAlpha_4__1_ */ +{0x0F12, 0x00F8}, /* TVAR_ash_GASAlpha_4__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_4__3_ */ +{0x0F12, 0x00F0}, /* TVAR_ash_GASAlpha_5__0_ D65 */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_5__3_ */ +{0x0F12, 0x00F0}, /* TVAR_ash_GASAlpha_6__0_ D75 */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASAlpha_6__3_ */ +{0x002A, 0x067A}, +{0x0F12, 0x0000}, /* ash_GASBeta_0__0_ Horizon */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_0__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__0_ IncandA */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_1__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__0_ WW */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_2__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__0_ CW */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_3__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__0_ D50 */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_4__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__0_ D65 */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_5__3_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__0_ D75 */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__1_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__2_ */ +{0x0F12, 0x0000}, /* ash_GASBeta_6__3_ */ +{0x002A, 0x06BA}, +{0x0F12, 0x0001}, /*ash_bLumaMode */ +{0x002A, 0x0632}, +{0x0F12, 0x0100}, /* ash_CGrasAlphas_0_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_1_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_2_ */ +{0x0F12, 0x0100}, /* ash_CGrasAlphas_3_ */ +{0x002A, 0x0672}, +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_0_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_1_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_2_ */ +{0x0F12, 0x0100}, /* TVAR_ash_GASOutdoorAlpha_3_ */ +{0x002A, 0x06B2}, +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_0_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_1_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_2_ */ +{0x0F12, 0x0000}, /* ash_GASOutdoorBeta_3_ */ +{0x002A, 0x06D0}, +{0x0F12, 0x000D}, /* ash_uParabolicScalingA */ +{0x0F12, 0x000F}, /* ash_uParabolicScalingB */ +{0x002A, 0x06CC}, +{0x0F12, 0x0280}, /* ash_uParabolicCenterX */ +{0x0F12, 0x01E0}, /* ash_uParabolicCenterY */ +{0x002A, 0x06C6}, +{0x0F12, 0x0001}, /* ash_bParabolicEstimation */ +{0x002A, 0x0624}, +{0x0F12, 0x009D}, /* TVAR_ash_AwbAshCord_0_ Horizon */ +{0x0F12, 0x00D5}, /* TVAR_ash_AwbAshCord_1_ IncandA */ +{0x0F12, 0x0103}, /* TVAR_ash_AwbAshCord_2_ WW */ +{0x0F12, 0x0128}, /* TVAR_ash_AwbAshCord_3_ CW */ +{0x0F12, 0x0166}, /* TVAR_ash_AwbAshCord_4_ D50 */ +{0x0F12, 0x0193}, /* TVAR_ash_AwbAshCord_5_ D65 */ +{0x0F12, 0x01A0}, /* TVAR_ash_AwbAshCord_6_ D75 */ +{0x002A, 0x347C}, +{0x0F12, 0x013B}, /* 011A 012F Tune_wbt_GAS_0_ */ +{0x0F12, 0x0116}, /* 011A 0111 Tune_wbt_GAS_1_ */ +{0x0F12, 0x00D9}, /* 00EE 00D6 Tune_wbt_GAS_2_ */ +{0x0F12, 0x00A6}, /* 00C1 009E Tune_wbt_GAS_3_ */ +{0x0F12, 0x0082}, /* 009E 007A Tune_wbt_GAS_4_ */ +{0x0F12, 0x006C}, /* 008A 0064 Tune_wbt_GAS_5_ */ +{0x0F12, 0x0065}, /* 0083 005D Tune_wbt_GAS_6_ */ +{0x0F12, 0x006C}, /* 008A 0063 Tune_wbt_GAS_7_ */ +{0x0F12, 0x0080}, /* 009E 007B Tune_wbt_GAS_8_ */ +{0x0F12, 0x00A3}, /* 00BF 00A3 Tune_wbt_GAS_9_ */ +{0x0F12, 0x00D4}, /* 00E5 00E3 Tune_wbt_GAS_10_ */ +{0x0F12, 0x010D}, /* 00F9 013B Tune_wbt_GAS_11_ */ +{0x0F12, 0x012E}, /* 0124 018B Tune_wbt_GAS_12_ */ +{0x0F12, 0x0138}, /* 0126 012B Tune_wbt_GAS_13_ */ +{0x0F12, 0x0104}, /* 010E 00F6 Tune_wbt_GAS_14_ */ +{0x0F12, 0x00BE}, /* 00D3 00B2 Tune_wbt_GAS_15_ */ +{0x0F12, 0x0088}, /* 009F 007B Tune_wbt_GAS_16_ */ +{0x0F12, 0x0062}, /* 007C 0057 Tune_wbt_GAS_17_ */ +{0x0F12, 0x004D}, /* 0068 0042 Tune_wbt_GAS_18_ */ +{0x0F12, 0x0046}, /* 0061 0039 Tune_wbt_GAS_19_ */ +{0x0F12, 0x004C}, /* 0068 003F Tune_wbt_GAS_20_ */ +{0x0F12, 0x0060}, /* 007E 0053 Tune_wbt_GAS_21_ */ +{0x0F12, 0x0084}, /* 00A3 007A Tune_wbt_GAS_22_ */ +{0x0F12, 0x00B8}, /* 00C9 00B6 Tune_wbt_GAS_23_ */ +{0x0F12, 0x00F9}, /* 00F0 0110 Tune_wbt_GAS_24_ */ +{0x0F12, 0x012C}, /* 0131 016A Tune_wbt_GAS_25_ */ +{0x0F12, 0x011A}, /* 011C 0114 Tune_wbt_GAS_26_ */ +{0x0F12, 0x00DB}, /* 00EB 00D4 Tune_wbt_GAS_27_ */ +{0x0F12, 0x0093}, /* 00AA 008F Tune_wbt_GAS_28_ */ +{0x0F12, 0x005F}, /* 0075 005A Tune_wbt_GAS_29_ */ +{0x0F12, 0x003C}, /* 0053 0035 Tune_wbt_GAS_30_ */ +{0x0F12, 0x0027}, /* 003F 0020 Tune_wbt_GAS_31_ */ +{0x0F12, 0x0020}, /* 0038 0019 Tune_wbt_GAS_32_ */ +{0x0F12, 0x0026}, /* 0040 001F Tune_wbt_GAS_33_ */ +{0x0F12, 0x003A}, /* 0055 0032 Tune_wbt_GAS_34_ */ +{0x0F12, 0x005C}, /* 007A 0056 Tune_wbt_GAS_35_ */ +{0x0F12, 0x008E}, /* 00A6 008E Tune_wbt_GAS_36_ */ +{0x0F12, 0x00D2}, /* 00D5 00E6 Tune_wbt_GAS_37_ */ +{0x0F12, 0x010E}, /* 0126 0142 Tune_wbt_GAS_38_ */ +{0x0F12, 0x0101}, /* 00F6 0102 Tune_wbt_GAS_39_ */ +{0x0F12, 0x00BF}, /* 00C0 00BE Tune_wbt_GAS_40_ */ +{0x0F12, 0x0077}, /* 007D 0077 Tune_wbt_GAS_41_ */ +{0x0F12, 0x0044}, /* 004D 0045 Tune_wbt_GAS_42_ */ +{0x0F12, 0x0023}, /* 002C 0022 Tune_wbt_GAS_43_ */ +{0x0F12, 0x0011}, /* 001B 000D Tune_wbt_GAS_44_ */ +{0x0F12, 0x000C}, /* 0017 0006 Tune_wbt_GAS_45_ */ +{0x0F12, 0x0010}, /* 001B 000A Tune_wbt_GAS_46_ */ +{0x0F12, 0x0022}, /* 002D 001D Tune_wbt_GAS_47_ */ +{0x0F12, 0x0043}, /* 004E 003F Tune_wbt_GAS_48_ */ +{0x0F12, 0x0074}, /* 0080 0075 Tune_wbt_GAS_49_ */ +{0x0F12, 0x00B7}, /* 00C1 00CC Tune_wbt_GAS_50_ */ +{0x0F12, 0x00F7}, /* 00FF 0126 Tune_wbt_GAS_51_ */ +{0x0F12, 0x00FC}, /* 00EA 00FB Tune_wbt_GAS_52_ */ +{0x0F12, 0x00B7}, /* 00B0 00B7 Tune_wbt_GAS_53_ */ +{0x0F12, 0x006F}, /* 006D 0070 Tune_wbt_GAS_54_ */ +{0x0F12, 0x003C}, /* 003D 003D Tune_wbt_GAS_55_ */ +{0x0F12, 0x001C}, /* 001E 001B Tune_wbt_GAS_56_ */ +{0x0F12, 0x000A}, /* 000F 0007 Tune_wbt_GAS_57_ */ +{0x0F12, 0x0004}, /* 000A 0000 Tune_wbt_GAS_58_ */ +{0x0F12, 0x000A}, /* 0010 0004 Tune_wbt_GAS_59_ */ +{0x0F12, 0x001B}, /* 001E 0015 Tune_wbt_GAS_60_ */ +{0x0F12, 0x003B}, /* 003E 0034 Tune_wbt_GAS_61_ */ +{0x0F12, 0x006C}, /* 006F 006A Tune_wbt_GAS_62_ */ +{0x0F12, 0x00B0}, /* 00B2 00C0 Tune_wbt_GAS_63_ */ +{0x0F12, 0x00F2}, /* 00F1 011B Tune_wbt_GAS_64_ */ +{0x0F12, 0x00EF}, /* 00E0 0102 Tune_wbt_GAS_65_ */ +{0x0F12, 0x00AB}, /* 00A6 00BA Tune_wbt_GAS_66_ */ +{0x0F12, 0x0065}, /* 0063 0073 Tune_wbt_GAS_67_ */ +{0x0F12, 0x0034}, /* 0033 0040 Tune_wbt_GAS_68_ */ +{0x0F12, 0x0015}, /* 0016 001D Tune_wbt_GAS_69_ */ +{0x0F12, 0x0004}, /* 0008 0009 Tune_wbt_GAS_70_ */ +{0x0F12, 0x0000}, /* 0003 0001 Tune_wbt_GAS_71_ */ +{0x0F12, 0x0004}, /* 0009 0006 Tune_wbt_GAS_72_ */ +{0x0F12, 0x0013}, /* 0016 0017 Tune_wbt_GAS_73_ */ +{0x0F12, 0x0033}, /* 0035 0039 Tune_wbt_GAS_74_ */ +{0x0F12, 0x0063}, /* 0066 006F Tune_wbt_GAS_75_ */ +{0x0F12, 0x00A5}, /* 00A7 00C8 Tune_wbt_GAS_76_ */ +{0x0F12, 0x00E5}, /* 00E9 011E Tune_wbt_GAS_77_ */ +{0x0F12, 0x00F7}, /* 00D5 0111 Tune_wbt_GAS_78_ */ +{0x0F12, 0x00B4}, /* 009D 00C8 Tune_wbt_GAS_79_ */ +{0x0F12, 0x006D}, /* 005D 0081 Tune_wbt_GAS_80_ */ +{0x0F12, 0x003C}, /* 002F 004D Tune_wbt_GAS_81_ */ +{0x0F12, 0x001C}, /* 0010 0028 Tune_wbt_GAS_82_ */ +{0x0F12, 0x000B}, /* 0004 0014 Tune_wbt_GAS_83_ */ +{0x0F12, 0x0005}, /* 0001 000B Tune_wbt_GAS_84_ */ +{0x0F12, 0x000A}, /* 0005 0010 Tune_wbt_GAS_85_ */ +{0x0F12, 0x001B}, /* 0013 0022 Tune_wbt_GAS_86_ */ +{0x0F12, 0x003B}, /* 0031 0047 Tune_wbt_GAS_87_ */ +{0x0F12, 0x006B}, /* 005F 007E Tune_wbt_GAS_88_ */ +{0x0F12, 0x00AD}, /* 00A1 00D8 Tune_wbt_GAS_89_ */ +{0x0F12, 0x00ED}, /* 00DF 0131 Tune_wbt_GAS_90_ */ +{0x0F12, 0x010B}, /* 00E9 0129 Tune_wbt_GAS_91_ */ +{0x0F12, 0x00CB}, /* 00B2 00E4 Tune_wbt_GAS_92_ */ +{0x0F12, 0x0085}, /* 006F 009E Tune_wbt_GAS_93_ */ +{0x0F12, 0x0051}, /* 003F 0068 Tune_wbt_GAS_94_ */ +{0x0F12, 0x002F}, /* 0020 0041 Tune_wbt_GAS_95_ */ +{0x0F12, 0x001C}, /* 000F 002B Tune_wbt_GAS_96_ */ +{0x0F12, 0x0016}, /* 000B 0023 Tune_wbt_GAS_97_ */ +{0x0F12, 0x001C}, /* 0010 0028 Tune_wbt_GAS_98_ */ +{0x0F12, 0x002E}, /* 0021 003B Tune_wbt_GAS_99_ */ +{0x0F12, 0x004F}, /* 0041 0063 Tune_wbt_GAS_100_ */ +{0x0F12, 0x0081}, /* 0071 00A0 Tune_wbt_GAS_101_ */ +{0x0F12, 0x00C4}, /* 00B4 00FD Tune_wbt_GAS_102_ */ +{0x0F12, 0x0102}, /* 00F6 015A Tune_wbt_GAS_103_ */ +{0x0F12, 0x0119}, /* 00F9 014A Tune_wbt_GAS_104_ */ +{0x0F12, 0x00DF}, /* 00C2 010D Tune_wbt_GAS_105_ */ +{0x0F12, 0x009B}, /* 0082 00CA Tune_wbt_GAS_106_ */ +{0x0F12, 0x0067}, /* 0053 008F Tune_wbt_GAS_107_ */ +{0x0F12, 0x0045}, /* 0033 0066 Tune_wbt_GAS_108_ */ +{0x0F12, 0x0030}, /* 0021 004F Tune_wbt_GAS_109_ */ +{0x0F12, 0x0029}, /* 001C 0048 Tune_wbt_GAS_110_ */ +{0x0F12, 0x002F}, /* 0022 004E Tune_wbt_GAS_111_ */ +{0x0F12, 0x0043}, /* 0035 0067 Tune_wbt_GAS_112_ */ +{0x0F12, 0x0066}, /* 0056 008F Tune_wbt_GAS_113_ */ +{0x0F12, 0x0098}, /* 0087 00D1 Tune_wbt_GAS_114_ */ +{0x0F12, 0x00D9}, /* 00CA 0132 Tune_wbt_GAS_115_ */ +{0x0F12, 0x010F}, /* 0107 018D Tune_wbt_GAS_116_ */ +{0x0F12, 0x0138}, /* 0108 0159 Tune_wbt_GAS_117_ */ +{0x0F12, 0x010C}, /* 00E0 0141 Tune_wbt_GAS_118_ */ +{0x0F12, 0x00CB}, /* 00A2 0103 Tune_wbt_GAS_119_ */ +{0x0F12, 0x0097}, /* 0072 00C9 Tune_wbt_GAS_120_ */ +{0x0F12, 0x0073}, /* 0052 009E Tune_wbt_GAS_121_ */ +{0x0F12, 0x005C}, /* 0040 0087 Tune_wbt_GAS_122_ */ +{0x0F12, 0x0054}, /* 003A 007D Tune_wbt_GAS_123_ */ +{0x0F12, 0x005B}, /* 0041 0087 Tune_wbt_GAS_124_ */ +{0x0F12, 0x0070}, /* 0055 00A2 Tune_wbt_GAS_125_ */ +{0x0F12, 0x0096}, /* 0077 00D4 Tune_wbt_GAS_126_ */ +{0x0F12, 0x00C9}, /* 00A8 011A Tune_wbt_GAS_127_ */ +{0x0F12, 0x0106}, /* 00E7 017D Tune_wbt_GAS_128_ */ +{0x0F12, 0x012D}, /* 011E 01CF Tune_wbt_GAS_129_ */ +{0x0F12, 0x0147}, /* 0123 0181 Tune_wbt_GAS_130_ */ +{0x0F12, 0x012F}, /* 0100 0169 Tune_wbt_GAS_131_ */ +{0x0F12, 0x00F8}, /* 00CB 0140 Tune_wbt_GAS_132_ */ +{0x0F12, 0x00C5}, /* 009A 0106 Tune_wbt_GAS_133_ */ +{0x0F12, 0x00A1}, /* 0079 00DD Tune_wbt_GAS_134_ */ +{0x0F12, 0x008B}, /* 0067 00C5 Tune_wbt_GAS_135_ */ +{0x0F12, 0x0083}, /* 0060 00BE Tune_wbt_GAS_136_ */ +{0x0F12, 0x008B}, /* 0068 00C8 Tune_wbt_GAS_137_ */ +{0x0F12, 0x00A0}, /* 007B 00E6 Tune_wbt_GAS_138_ */ +{0x0F12, 0x00C2}, /* 009D 011B Tune_wbt_GAS_139_ */ +{0x0F12, 0x00F3}, /* 00CD 015F Tune_wbt_GAS_140_ */ +{0x0F12, 0x0124}, /* 0108 01BC Tune_wbt_GAS_141_ */ +{0x0F12, 0x0139}, /* 0131 0206 Tune_wbt_GAS_142_ */ +{0x0F12, 0x0093}, /* 006C 00A8 Tune_wbt_GAS_143_ */ +{0x0F12, 0x007E}, /* 006E 008F Tune_wbt_GAS_144_ */ +{0x0F12, 0x0062}, /* 005D 006F Tune_wbt_GAS_145_ */ +{0x0F12, 0x004D}, /* 004C 0054 Tune_wbt_GAS_146_ */ +{0x0F12, 0x003E}, /* 0040 0041 Tune_wbt_GAS_147_ */ +{0x0F12, 0x0034}, /* 0037 0036 Tune_wbt_GAS_148_ */ +{0x0F12, 0x0030}, /* 0035 0033 Tune_wbt_GAS_149_ */ +{0x0F12, 0x0032}, /* 0036 0037 Tune_wbt_GAS_150_ */ +{0x0F12, 0x003B}, /* 003F 0045 Tune_wbt_GAS_151_ */ +{0x0F12, 0x0049}, /* 004B 005A Tune_wbt_GAS_152_ */ +{0x0F12, 0x005C}, /* 0053 007A Tune_wbt_GAS_153_ */ +{0x0F12, 0x0077}, /* 0053 00AA Tune_wbt_GAS_154_ */ +{0x0F12, 0x008A}, /* 0070 00E2 Tune_wbt_GAS_155_ */ +{0x0F12, 0x0093}, /* 0075 009E Tune_wbt_GAS_156_ */ +{0x0F12, 0x0077}, /* 006D 007D Tune_wbt_GAS_157_ */ +{0x0F12, 0x0059}, /* 0056 005A Tune_wbt_GAS_158_ */ +{0x0F12, 0x0042}, /* 0043 0041 Tune_wbt_GAS_159_ */ +{0x0F12, 0x0032}, /* 0037 002E Tune_wbt_GAS_160_ */ +{0x0F12, 0x0027}, /* 002F 0022 Tune_wbt_GAS_161_ */ +{0x0F12, 0x0024}, /* 002C 001F Tune_wbt_GAS_162_ */ +{0x0F12, 0x0026}, /* 002F 0022 Tune_wbt_GAS_163_ */ +{0x0F12, 0x002F}, /* 0038 0030 Tune_wbt_GAS_164_ */ +{0x0F12, 0x003D}, /* 0045 0044 Tune_wbt_GAS_165_ */ +{0x0F12, 0x0052}, /* 004E 0063 Tune_wbt_GAS_166_ */ +{0x0F12, 0x006E}, /* 0055 0091 Tune_wbt_GAS_167_ */ +{0x0F12, 0x008B}, /* 007F 00CB Tune_wbt_GAS_168_ */ +{0x0F12, 0x0083}, /* 0077 0093 Tune_wbt_GAS_169_ */ +{0x0F12, 0x0064}, /* 0062 006D Tune_wbt_GAS_170_ */ +{0x0F12, 0x0046}, /* 004A 004A Tune_wbt_GAS_171_ */ +{0x0F12, 0x0030}, /* 0037 0031 Tune_wbt_GAS_172_ */ +{0x0F12, 0x0020}, /* 002A 001E Tune_wbt_GAS_173_ */ +{0x0F12, 0x0016}, /* 0021 0013 Tune_wbt_GAS_174_ */ +{0x0F12, 0x0011}, /* 001E 000F Tune_wbt_GAS_175_ */ +{0x0F12, 0x0014}, /* 0021 0013 Tune_wbt_GAS_176_ */ +{0x0F12, 0x001E}, /* 002B 001F Tune_wbt_GAS_177_ */ +{0x0F12, 0x002D}, /* 003B 0034 Tune_wbt_GAS_178_ */ +{0x0F12, 0x0041}, /* 0046 0051 Tune_wbt_GAS_179_ */ +{0x0F12, 0x005D}, /* 0051 007C Tune_wbt_GAS_180_ */ +{0x0F12, 0x007C}, /* 007F 00B7 Tune_wbt_GAS_181_ */ +{0x0F12, 0x0077}, /* 0062 008A Tune_wbt_GAS_182_ */ +{0x0F12, 0x0057}, /* 004B 0061 Tune_wbt_GAS_183_ */ +{0x0F12, 0x0039}, /* 0034 003E Tune_wbt_GAS_184_ */ +{0x0F12, 0x0024}, /* 0022 0026 Tune_wbt_GAS_185_ */ +{0x0F12, 0x0014}, /* 0014 0013 Tune_wbt_GAS_186_ */ +{0x0F12, 0x000A}, /* 000E 0008 Tune_wbt_GAS_187_ */ +{0x0F12, 0x0007}, /* 000C 0004 Tune_wbt_GAS_188_ */ +{0x0F12, 0x0009}, /* 000D 0007 Tune_wbt_GAS_189_ */ +{0x0F12, 0x0012}, /* 0016 0013 Tune_wbt_GAS_190_ */ +{0x0F12, 0x0021}, /* 0024 0027 Tune_wbt_GAS_191_ */ +{0x0F12, 0x0036}, /* 0036 0045 Tune_wbt_GAS_192_ */ +{0x0F12, 0x0051}, /* 004E 0070 Tune_wbt_GAS_193_ */ +{0x0F12, 0x0070}, /* 0069 00A7 Tune_wbt_GAS_194_ */ +{0x0F12, 0x0077}, /* 005F 0085 Tune_wbt_GAS_195_ */ +{0x0F12, 0x0056}, /* 0048 005D Tune_wbt_GAS_196_ */ +{0x0F12, 0x0038}, /* 002F 003A Tune_wbt_GAS_197_ */ +{0x0F12, 0x0022}, /* 001C 0021 Tune_wbt_GAS_198_ */ +{0x0F12, 0x0013}, /* 0010 0010 Tune_wbt_GAS_199_ */ +{0x0F12, 0x0009}, /* 000B 0004 Tune_wbt_GAS_200_ */ +{0x0F12, 0x0005}, /* 0008 0000 Tune_wbt_GAS_201_ */ +{0x0F12, 0x0008}, /* 000B 0003 Tune_wbt_GAS_202_ */ +{0x0F12, 0x0011}, /* 0010 000E Tune_wbt_GAS_203_ */ +{0x0F12, 0x0020}, /* 001E 0021 Tune_wbt_GAS_204_ */ +{0x0F12, 0x0035}, /* 0031 003F Tune_wbt_GAS_205_ */ +{0x0F12, 0x0051}, /* 0049 006B Tune_wbt_GAS_206_ */ +{0x0F12, 0x0071}, /* 0066 00A1 Tune_wbt_GAS_207_ */ +{0x0F12, 0x006E}, /* 005B 0089 Tune_wbt_GAS_208_ */ +{0x0F12, 0x004E}, /* 0043 0060 Tune_wbt_GAS_209_ */ +{0x0F12, 0x0032}, /* 002B 003D Tune_wbt_GAS_210_ */ +{0x0F12, 0x001C}, /* 0019 0023 Tune_wbt_GAS_211_ */ +{0x0F12, 0x000D}, /* 000C 0012 Tune_wbt_GAS_212_ */ +{0x0F12, 0x0004}, /* 0007 0006 Tune_wbt_GAS_213_ */ +{0x0F12, 0x0000}, /* 0004 0002 Tune_wbt_GAS_214_ */ +{0x0F12, 0x0003}, /* 0007 0005 Tune_wbt_GAS_215_ */ +{0x0F12, 0x000B}, /* 000D 0011 Tune_wbt_GAS_216_ */ +{0x0F12, 0x001A}, /* 001B 0025 Tune_wbt_GAS_217_ */ +{0x0F12, 0x002F}, /* 002E 0043 Tune_wbt_GAS_218_ */ +{0x0F12, 0x0049}, /* 0046 0070 Tune_wbt_GAS_219_ */ +{0x0F12, 0x0068}, /* 0062 00A4 Tune_wbt_GAS_220_ */ +{0x0F12, 0x0072}, /* 0052 0091 Tune_wbt_GAS_221_ */ +{0x0F12, 0x0053}, /* 003D 0067 Tune_wbt_GAS_222_ */ +{0x0F12, 0x0037}, /* 0026 0044 Tune_wbt_GAS_223_ */ +{0x0F12, 0x0021}, /* 0014 002B Tune_wbt_GAS_224_ */ +{0x0F12, 0x0012}, /* 0007 0019 Tune_wbt_GAS_225_ */ +{0x0F12, 0x0009}, /* 0002 000D Tune_wbt_GAS_226_ */ +{0x0F12, 0x0005}, /* 0001 0009 Tune_wbt_GAS_227_ */ +{0x0F12, 0x0008}, /* 0002 000C Tune_wbt_GAS_228_ */ +{0x0F12, 0x0010}, /* 0007 0018 Tune_wbt_GAS_229_ */ +{0x0F12, 0x001F}, /* 0015 002D Tune_wbt_GAS_230_ */ +{0x0F12, 0x0034}, /* 0028 004B Tune_wbt_GAS_231_ */ +{0x0F12, 0x004E}, /* 0040 007B Tune_wbt_GAS_232_ */ +{0x0F12, 0x006C}, /* 005C 00B0 Tune_wbt_GAS_233_ */ +{0x0F12, 0x007F}, /* 005E 00A1 Tune_wbt_GAS_234_ */ +{0x0F12, 0x0060}, /* 0049 0077 Tune_wbt_GAS_235_ */ +{0x0F12, 0x0043}, /* 0030 0054 Tune_wbt_GAS_236_ */ +{0x0F12, 0x002D}, /* 001E 003B Tune_wbt_GAS_237_ */ +{0x0F12, 0x001D}, /* 0010 0029 Tune_wbt_GAS_238_ */ +{0x0F12, 0x0013}, /* 0009 001C Tune_wbt_GAS_239_ */ +{0x0F12, 0x0010}, /* 0007 0018 Tune_wbt_GAS_240_ */ +{0x0F12, 0x0013}, /* 0009 001B Tune_wbt_GAS_241_ */ +{0x0F12, 0x001C}, /* 0012 0029 Tune_wbt_GAS_242_ */ +{0x0F12, 0x002B}, /* 0020 003F Tune_wbt_GAS_243_ */ +{0x0F12, 0x0040}, /* 0032 005F Tune_wbt_GAS_244_ */ +{0x0F12, 0x005A}, /* 004B 008F Tune_wbt_GAS_245_ */ +{0x0F12, 0x0079}, /* 0069 00C6 Tune_wbt_GAS_246_ */ +{0x0F12, 0x0082}, /* 0066 00B1 Tune_wbt_GAS_247_ */ +{0x0F12, 0x0066}, /* 004E 008E Tune_wbt_GAS_248_ */ +{0x0F12, 0x0049}, /* 0037 006D Tune_wbt_GAS_249_ */ +{0x0F12, 0x0035}, /* 0026 0050 Tune_wbt_GAS_250_ */ +{0x0F12, 0x0025}, /* 0019 003D Tune_wbt_GAS_251_ */ +{0x0F12, 0x001B}, /* 0011 0031 Tune_wbt_GAS_252_ */ +{0x0F12, 0x0017}, /* 000F 002F Tune_wbt_GAS_253_ */ +{0x0F12, 0x0019}, /* 0012 0032 Tune_wbt_GAS_254_ */ +{0x0F12, 0x0023}, /* 001B 0042 Tune_wbt_GAS_255_ */ +{0x0F12, 0x0033}, /* 0028 0058 Tune_wbt_GAS_256_ */ +{0x0F12, 0x0046}, /* 003B 007A Tune_wbt_GAS_257_ */ +{0x0F12, 0x0060}, /* 0054 00AC Tune_wbt_GAS_258_ */ +{0x0F12, 0x007B}, /* 0072 00E5 Tune_wbt_GAS_259_ */ +{0x0F12, 0x0092}, /* 006A 00BD Tune_wbt_GAS_260_ */ +{0x0F12, 0x007C}, /* 0058 00AA Tune_wbt_GAS_261_ */ +{0x0F12, 0x0060}, /* 0041 008B Tune_wbt_GAS_262_ */ +{0x0F12, 0x004B}, /* 0030 006E Tune_wbt_GAS_263_ */ +{0x0F12, 0x003C}, /* 0025 005A Tune_wbt_GAS_264_ */ +{0x0F12, 0x0032}, /* 001E 004F Tune_wbt_GAS_265_ */ +{0x0F12, 0x002D}, /* 001B 004B Tune_wbt_GAS_266_ */ +{0x0F12, 0x0030}, /* 001F 0052 Tune_wbt_GAS_267_ */ +{0x0F12, 0x0039}, /* 0027 0062 Tune_wbt_GAS_268_ */ +{0x0F12, 0x0049}, /* 0034 007D Tune_wbt_GAS_269_ */ +{0x0F12, 0x005D}, /* 0046 00A2 Tune_wbt_GAS_270_ */ +{0x0F12, 0x0076}, /* 005D 00D6 Tune_wbt_GAS_271_ */ +{0x0F12, 0x008C}, /* 0078 010C Tune_wbt_GAS_272_ */ +{0x0F12, 0x009F}, /* 007C 00E5 Tune_wbt_GAS_273_ */ +{0x0F12, 0x008F}, /* 006A 00C7 Tune_wbt_GAS_274_ */ +{0x0F12, 0x0077}, /* 0055 00B1 Tune_wbt_GAS_275_ */ +{0x0F12, 0x0061}, /* 0043 0093 Tune_wbt_GAS_276_ */ +{0x0F12, 0x0052}, /* 0037 007F Tune_wbt_GAS_277_ */ +{0x0F12, 0x0048}, /* 0030 0074 Tune_wbt_GAS_278_ */ +{0x0F12, 0x0043}, /* 002E 0071 Tune_wbt_GAS_279_ */ +{0x0F12, 0x0047}, /* 0030 0077 Tune_wbt_GAS_280_ */ +{0x0F12, 0x0050}, /* 0039 0089 Tune_wbt_GAS_281_ */ +{0x0F12, 0x005E}, /* 0045 00A7 Tune_wbt_GAS_282_ */ +{0x0F12, 0x0071}, /* 0056 00CC Tune_wbt_GAS_283_ */ +{0x0F12, 0x0086}, /* 006C 00FE Tune_wbt_GAS_284_ */ +{0x0F12, 0x0097}, /* 0084 0132 Tune_wbt_GAS_285_ */ +{0x0F12, 0x0093}, /* 006E 00A8 Tune_wbt_GAS_286_ */ +{0x0F12, 0x007C}, /* 006D 008D Tune_wbt_GAS_287_ */ +{0x0F12, 0x005F}, /* 005B 006C Tune_wbt_GAS_288_ */ +{0x0F12, 0x0049}, /* 0046 004E Tune_wbt_GAS_289_ */ +{0x0F12, 0x003A}, /* 003A 003C Tune_wbt_GAS_290_ */ +{0x0F12, 0x0030}, /* 0033 0032 Tune_wbt_GAS_291_ */ +{0x0F12, 0x002C}, /* 002D 002D Tune_wbt_GAS_292_ */ +{0x0F12, 0x002F}, /* 0032 0032 Tune_wbt_GAS_293_ */ +{0x0F12, 0x0037}, /* 0039 0040 Tune_wbt_GAS_294_ */ +{0x0F12, 0x0045}, /* 0047 0056 Tune_wbt_GAS_295_ */ +{0x0F12, 0x005A}, /* 004F 0076 Tune_wbt_GAS_296_ */ +{0x0F12, 0x0075}, /* 0050 00A8 Tune_wbt_GAS_297_ */ +{0x0F12, 0x008A}, /* 006E 00E6 Tune_wbt_GAS_298_ */ +{0x0F12, 0x0094}, /* 0077 00A2 Tune_wbt_GAS_299_ */ +{0x0F12, 0x0077}, /* 006C 007C Tune_wbt_GAS_300_ */ +{0x0F12, 0x0057}, /* 0054 0059 Tune_wbt_GAS_301_ */ +{0x0F12, 0x0040}, /* 0040 003E Tune_wbt_GAS_302_ */ +{0x0F12, 0x002F}, /* 0033 002A Tune_wbt_GAS_303_ */ +{0x0F12, 0x0024}, /* 002B 0020 Tune_wbt_GAS_304_ */ +{0x0F12, 0x0020}, /* 0027 001B Tune_wbt_GAS_305_ */ +{0x0F12, 0x0023}, /* 002A 0020 Tune_wbt_GAS_306_ */ +{0x0F12, 0x002D}, /* 0034 002D Tune_wbt_GAS_307_ */ +{0x0F12, 0x003B}, /* 0041 0042 Tune_wbt_GAS_308_ */ +{0x0F12, 0x0051}, /* 004C 0061 Tune_wbt_GAS_309_ */ +{0x0F12, 0x006E}, /* 0052 0092 Tune_wbt_GAS_310_ */ +{0x0F12, 0x008C}, /* 007E 00CE Tune_wbt_GAS_311_ */ +{0x0F12, 0x0085}, /* 0078 0094 Tune_wbt_GAS_312_ */ +{0x0F12, 0x0066}, /* 0063 006F Tune_wbt_GAS_313_ */ +{0x0F12, 0x0046}, /* 0049 004B Tune_wbt_GAS_314_ */ +{0x0F12, 0x002F}, /* 0035 002F Tune_wbt_GAS_315_ */ +{0x0F12, 0x001F}, /* 0028 001D Tune_wbt_GAS_316_ */ +{0x0F12, 0x0014}, /* 001E 0011 Tune_wbt_GAS_317_ */ +{0x0F12, 0x000F}, /* 001B 000D Tune_wbt_GAS_318_ */ +{0x0F12, 0x0012}, /* 001F 0012 Tune_wbt_GAS_319_ */ +{0x0F12, 0x001C}, /* 0028 001D Tune_wbt_GAS_320_ */ +{0x0F12, 0x002B}, /* 0037 0033 Tune_wbt_GAS_321_ */ +{0x0F12, 0x0040}, /* 0044 0051 Tune_wbt_GAS_322_ */ +{0x0F12, 0x005C}, /* 0050 007F Tune_wbt_GAS_323_ */ +{0x0F12, 0x007D}, /* 0080 00BA Tune_wbt_GAS_324_ */ +{0x0F12, 0x007A}, /* 0064 008B Tune_wbt_GAS_325_ */ +{0x0F12, 0x005A}, /* 004E 0064 Tune_wbt_GAS_326_ */ +{0x0F12, 0x003A}, /* 0035 0040 Tune_wbt_GAS_327_ */ +{0x0F12, 0x0024}, /* 0021 0025 Tune_wbt_GAS_328_ */ +{0x0F12, 0x0014}, /* 0013 0013 Tune_wbt_GAS_329_ */ +{0x0F12, 0x0009}, /* 000D 0007 Tune_wbt_GAS_330_ */ +{0x0F12, 0x0006}, /* 000B 0003 Tune_wbt_GAS_331_ */ +{0x0F12, 0x0008}, /* 000C 0006 Tune_wbt_GAS_332_ */ +{0x0F12, 0x0011}, /* 0014 0012 Tune_wbt_GAS_333_ */ +{0x0F12, 0x0020}, /* 0022 0027 Tune_wbt_GAS_334_ */ +{0x0F12, 0x0036}, /* 0036 0046 Tune_wbt_GAS_335_ */ +{0x0F12, 0x0051}, /* 004D 0073 Tune_wbt_GAS_336_ */ +{0x0F12, 0x0072}, /* 006B 00AB Tune_wbt_GAS_337_ */ +{0x0F12, 0x007B}, /* 0066 008B Tune_wbt_GAS_338_ */ +{0x0F12, 0x0059}, /* 004C 0062 Tune_wbt_GAS_339_ */ +{0x0F12, 0x003A}, /* 0032 003F Tune_wbt_GAS_340_ */ +{0x0F12, 0x0023}, /* 001E 0023 Tune_wbt_GAS_341_ */ +{0x0F12, 0x0012}, /* 0010 0010 Tune_wbt_GAS_342_ */ +{0x0F12, 0x0008}, /* 000A 0004 Tune_wbt_GAS_343_ */ +{0x0F12, 0x0004}, /* 0007 0000 Tune_wbt_GAS_344_ */ +{0x0F12, 0x0007}, /* 000B 0003 Tune_wbt_GAS_345_ */ +{0x0F12, 0x000F}, /* 0010 000E Tune_wbt_GAS_346_ */ +{0x0F12, 0x001F}, /* 001E 0022 Tune_wbt_GAS_347_ */ +{0x0F12, 0x0035}, /* 0032 0041 Tune_wbt_GAS_348_ */ +{0x0F12, 0x0051}, /* 004B 006E Tune_wbt_GAS_349_ */ +{0x0F12, 0x0072}, /* 006B 00A4 Tune_wbt_GAS_350_ */ +{0x0F12, 0x0073}, /* 0061 008E Tune_wbt_GAS_351_ */ +{0x0F12, 0x0053}, /* 0049 0065 Tune_wbt_GAS_352_ */ +{0x0F12, 0x0034}, /* 002F 0040 Tune_wbt_GAS_353_ */ +{0x0F12, 0x001D}, /* 001B 0025 Tune_wbt_GAS_354_ */ +{0x0F12, 0x000E}, /* 000E 0013 Tune_wbt_GAS_355_ */ +{0x0F12, 0x0004}, /* 0008 0006 Tune_wbt_GAS_356_ */ +{0x0F12, 0x0000}, /* 0004 0001 Tune_wbt_GAS_357_ */ +{0x0F12, 0x0002}, /* 0008 0005 Tune_wbt_GAS_358_ */ +{0x0F12, 0x000A}, /* 000D 0010 Tune_wbt_GAS_359_ */ +{0x0F12, 0x001A}, /* 001C 0025 Tune_wbt_GAS_360_ */ +{0x0F12, 0x002F}, /* 002F 0044 Tune_wbt_GAS_361_ */ +{0x0F12, 0x004A}, /* 0047 0074 Tune_wbt_GAS_362_ */ +{0x0F12, 0x006A}, /* 0067 00AA Tune_wbt_GAS_363_ */ +{0x0F12, 0x0077}, /* 005A 0097 Tune_wbt_GAS_364_ */ +{0x0F12, 0x0058}, /* 0043 006D Tune_wbt_GAS_365_ */ +{0x0F12, 0x0039}, /* 002B 0048 Tune_wbt_GAS_366_ */ +{0x0F12, 0x0022}, /* 0017 002D Tune_wbt_GAS_367_ */ +{0x0F12, 0x0012}, /* 0009 0019 Tune_wbt_GAS_368_ */ +{0x0F12, 0x0008}, /* 0004 000E Tune_wbt_GAS_369_ */ +{0x0F12, 0x0004}, /* 0002 0009 Tune_wbt_GAS_370_ */ +{0x0F12, 0x0007}, /* 0004 000C Tune_wbt_GAS_371_ */ +{0x0F12, 0x000F}, /* 0008 0018 Tune_wbt_GAS_372_ */ +{0x0F12, 0x001E}, /* 0016 002E Tune_wbt_GAS_373_ */ +{0x0F12, 0x0034}, /* 002A 004E Tune_wbt_GAS_374_ */ +{0x0F12, 0x004F}, /* 0042 007D Tune_wbt_GAS_375_ */ +{0x0F12, 0x006F}, /* 005F 00B5 Tune_wbt_GAS_376_ */ +{0x0F12, 0x0083}, /* 0066 00A6 Tune_wbt_GAS_377_ */ +{0x0F12, 0x0064}, /* 0050 007C Tune_wbt_GAS_378_ */ +{0x0F12, 0x0045}, /* 0035 0058 Tune_wbt_GAS_379_ */ +{0x0F12, 0x002E}, /* 0022 003E Tune_wbt_GAS_380_ */ +{0x0F12, 0x001D}, /* 0013 0029 Tune_wbt_GAS_381_ */ +{0x0F12, 0x0012}, /* 000A 001D Tune_wbt_GAS_382_ */ +{0x0F12, 0x000F}, /* 0008 0018 Tune_wbt_GAS_383_ */ +{0x0F12, 0x0011}, /* 000B 001B Tune_wbt_GAS_384_ */ +{0x0F12, 0x001A}, /* 0014 0028 Tune_wbt_GAS_385_ */ +{0x0F12, 0x002A}, /* 0021 003F Tune_wbt_GAS_386_ */ +{0x0F12, 0x003F}, /* 0035 0062 Tune_wbt_GAS_387_ */ +{0x0F12, 0x005B}, /* 004D 0093 Tune_wbt_GAS_388_ */ +{0x0F12, 0x007B}, /* 006E 00CC Tune_wbt_GAS_389_ */ +{0x0F12, 0x0087}, /* 006E 00B9 Tune_wbt_GAS_390_ */ +{0x0F12, 0x006A}, /* 0057 0094 Tune_wbt_GAS_391_ */ +{0x0F12, 0x004B}, /* 003E 0071 Tune_wbt_GAS_392_ */ +{0x0F12, 0x0036}, /* 002B 0052 Tune_wbt_GAS_393_ */ +{0x0F12, 0x0025}, /* 001C 003D Tune_wbt_GAS_394_ */ +{0x0F12, 0x0019}, /* 0013 0031 Tune_wbt_GAS_395_ */ +{0x0F12, 0x0015}, /* 0011 002D Tune_wbt_GAS_396_ */ +{0x0F12, 0x0017}, /* 0013 0031 Tune_wbt_GAS_397_ */ +{0x0F12, 0x0022}, /* 001D 0040 Tune_wbt_GAS_398_ */ +{0x0F12, 0x0031}, /* 002B 0058 Tune_wbt_GAS_399_ */ +{0x0F12, 0x0045}, /* 003D 007B Tune_wbt_GAS_400_ */ +{0x0F12, 0x0060}, /* 0057 00AE Tune_wbt_GAS_401_ */ +{0x0F12, 0x007D}, /* 0077 00EA Tune_wbt_GAS_402_ */ +{0x0F12, 0x0096}, /* 0072 00C2 Tune_wbt_GAS_403_ */ +{0x0F12, 0x007F}, /* 005F 00AE Tune_wbt_GAS_404_ */ +{0x0F12, 0x0061}, /* 0047 008E Tune_wbt_GAS_405_ */ +{0x0F12, 0x004B}, /* 0035 006F Tune_wbt_GAS_406_ */ +{0x0F12, 0x003B}, /* 0028 0059 Tune_wbt_GAS_407_ */ +{0x0F12, 0x002F}, /* 0020 004E Tune_wbt_GAS_408_ */ +{0x0F12, 0x002A}, /* 001D 0049 Tune_wbt_GAS_409_ */ +{0x0F12, 0x002D}, /* 0020 004F Tune_wbt_GAS_410_ */ +{0x0F12, 0x0036}, /* 0029 005E Tune_wbt_GAS_411_ */ +{0x0F12, 0x0046}, /* 0035 007A Tune_wbt_GAS_412_ */ +{0x0F12, 0x005B}, /* 0047 009F Tune_wbt_GAS_413_ */ +{0x0F12, 0x0075}, /* 0060 00D5 Tune_wbt_GAS_414_ */ +{0x0F12, 0x008D}, /* 007D 010C Tune_wbt_GAS_415_ */ +{0x0F12, 0x00A1}, /* 0084 00E5 Tune_wbt_GAS_416_ */ +{0x0F12, 0x0091}, /* 0072 00C8 Tune_wbt_GAS_417_ */ +{0x0F12, 0x0077}, /* 005B 00B0 Tune_wbt_GAS_418_ */ +{0x0F12, 0x0060}, /* 0046 0091 Tune_wbt_GAS_419_ */ +{0x0F12, 0x0050}, /* 003A 007D Tune_wbt_GAS_420_ */ +{0x0F12, 0x0044}, /* 0031 0070 Tune_wbt_GAS_421_ */ +{0x0F12, 0x0040}, /* 002E 006D Tune_wbt_GAS_422_ */ +{0x0F12, 0x0043}, /* 0032 0074 Tune_wbt_GAS_423_ */ +{0x0F12, 0x004C}, /* 0039 0086 Tune_wbt_GAS_424_ */ +{0x0F12, 0x005A}, /* 0046 00A4 Tune_wbt_GAS_425_ */ +{0x0F12, 0x006D}, /* 0056 00CA Tune_wbt_GAS_426_ */ +{0x0F12, 0x0084}, /* 006E 00FE Tune_wbt_GAS_427_ */ +{0x0F12, 0x0094}, /* 0087 0134 Tune_wbt_GAS_428_ */ +{0x0F12, 0x0072}, /* 004C 009F Tune_wbt_GAS_429_ */ +{0x0F12, 0x0063}, /* 004C 0089 Tune_wbt_GAS_430_ */ +{0x0F12, 0x004C}, /* 0041 0067 Tune_wbt_GAS_431_ */ +{0x0F12, 0x003A}, /* 002F 004E Tune_wbt_GAS_432_ */ +{0x0F12, 0x002D}, /* 0024 003E Tune_wbt_GAS_433_ */ +{0x0F12, 0x0025}, /* 001D 0033 Tune_wbt_GAS_434_ */ +{0x0F12, 0x0023}, /* 001B 0031 Tune_wbt_GAS_435_ */ +{0x0F12, 0x0025}, /* 001E 0036 Tune_wbt_GAS_436_ */ +{0x0F12, 0x002C}, /* 0024 0045 Tune_wbt_GAS_437_ */ +{0x0F12, 0x0038}, /* 0032 0058 Tune_wbt_GAS_438_ */ +{0x0F12, 0x004A}, /* 0037 0074 Tune_wbt_GAS_439_ */ +{0x0F12, 0x005F}, /* 0038 00A0 Tune_wbt_GAS_440_ */ +{0x0F12, 0x006B}, /* 004C 00C9 Tune_wbt_GAS_441_ */ +{0x0F12, 0x0079}, /* 005B 0098 Tune_wbt_GAS_442_ */ +{0x0F12, 0x0065}, /* 0056 0077 Tune_wbt_GAS_443_ */ +{0x0F12, 0x004A}, /* 0041 0055 Tune_wbt_GAS_444_ */ +{0x0F12, 0x0037}, /* 0030 003C Tune_wbt_GAS_445_ */ +{0x0F12, 0x0029}, /* 0026 002A Tune_wbt_GAS_446_ */ +{0x0F12, 0x0021}, /* 001F 0022 Tune_wbt_GAS_447_ */ +{0x0F12, 0x001D}, /* 001C 001F Tune_wbt_GAS_448_ */ +{0x0F12, 0x001F}, /* 001F 0024 Tune_wbt_GAS_449_ */ +{0x0F12, 0x0027}, /* 0027 0030 Tune_wbt_GAS_450_ */ +{0x0F12, 0x0033}, /* 0033 0044 Tune_wbt_GAS_451_ */ +{0x0F12, 0x0044}, /* 003C 0060 Tune_wbt_GAS_452_ */ +{0x0F12, 0x005E}, /* 0041 008B Tune_wbt_GAS_453_ */ +{0x0F12, 0x006E}, /* 0060 00B2 Tune_wbt_GAS_454_ */ +{0x0F12, 0x006A}, /* 005E 0088 Tune_wbt_GAS_455_ */ +{0x0F12, 0x0055}, /* 004F 0065 Tune_wbt_GAS_456_ */ +{0x0F12, 0x003A}, /* 003A 0044 Tune_wbt_GAS_457_ */ +{0x0F12, 0x0028}, /* 002A 002C Tune_wbt_GAS_458_ */ +{0x0F12, 0x001A}, /* 001D 001B Tune_wbt_GAS_459_ */ +{0x0F12, 0x0011}, /* 0016 0012 Tune_wbt_GAS_460_ */ +{0x0F12, 0x000D}, /* 0014 000F Tune_wbt_GAS_461_ */ +{0x0F12, 0x000F}, /* 0016 0013 Tune_wbt_GAS_462_ */ +{0x0F12, 0x0017}, /* 0021 001E Tune_wbt_GAS_463_ */ +{0x0F12, 0x0024}, /* 002D 0032 Tune_wbt_GAS_464_ */ +{0x0F12, 0x0035}, /* 0038 004E Tune_wbt_GAS_465_ */ +{0x0F12, 0x004E}, /* 0040 0078 Tune_wbt_GAS_466_ */ +{0x0F12, 0x0061}, /* 0066 00A2 Tune_wbt_GAS_467_ */ +{0x0F12, 0x0061}, /* 004A 007F Tune_wbt_GAS_468_ */ +{0x0F12, 0x004A}, /* 003C 005B Tune_wbt_GAS_469_ */ +{0x0F12, 0x0031}, /* 0028 0039 Tune_wbt_GAS_470_ */ +{0x0F12, 0x001E}, /* 0019 0021 Tune_wbt_GAS_471_ */ +{0x0F12, 0x0011}, /* 000D 0012 Tune_wbt_GAS_472_ */ +{0x0F12, 0x0008}, /* 0008 0007 Tune_wbt_GAS_473_ */ +{0x0F12, 0x0005}, /* 0007 0004 Tune_wbt_GAS_474_ */ +{0x0F12, 0x0007}, /* 0007 0006 Tune_wbt_GAS_475_ */ +{0x0F12, 0x000E}, /* 000F 0012 Tune_wbt_GAS_476_ */ +{0x0F12, 0x001B}, /* 001C 0024 Tune_wbt_GAS_477_ */ +{0x0F12, 0x002D}, /* 002C 0041 Tune_wbt_GAS_478_ */ +{0x0F12, 0x0045}, /* 0042 006A Tune_wbt_GAS_479_ */ +{0x0F12, 0x0059}, /* 0054 0092 Tune_wbt_GAS_480_ */ +{0x0F12, 0x0062}, /* 004B 007B Tune_wbt_GAS_481_ */ +{0x0F12, 0x004B}, /* 003C 0057 Tune_wbt_GAS_482_ */ +{0x0F12, 0x0031}, /* 0027 0036 Tune_wbt_GAS_483_ */ +{0x0F12, 0x001E}, /* 0017 001E Tune_wbt_GAS_484_ */ +{0x0F12, 0x0010}, /* 000C 000F Tune_wbt_GAS_485_ */ +{0x0F12, 0x0008}, /* 0007 0003 Tune_wbt_GAS_486_ */ +{0x0F12, 0x0004}, /* 0006 0000 Tune_wbt_GAS_487_ */ +{0x0F12, 0x0006}, /* 0008 0002 Tune_wbt_GAS_488_ */ +{0x0F12, 0x000E}, /* 000D 000D Tune_wbt_GAS_489_ */ +{0x0F12, 0x001B}, /* 001A 0020 Tune_wbt_GAS_490_ */ +{0x0F12, 0x002E}, /* 002B 003C Tune_wbt_GAS_491_ */ +{0x0F12, 0x0046}, /* 0041 0067 Tune_wbt_GAS_492_ */ +{0x0F12, 0x005A}, /* 0054 008D Tune_wbt_GAS_493_ */ +{0x0F12, 0x005B}, /* 0049 007E Tune_wbt_GAS_494_ */ +{0x0F12, 0x0045}, /* 003A 005A Tune_wbt_GAS_495_ */ +{0x0F12, 0x002C}, /* 0025 0038 Tune_wbt_GAS_496_ */ +{0x0F12, 0x001A}, /* 0015 0022 Tune_wbt_GAS_497_ */ +{0x0F12, 0x000C}, /* 000A 0013 Tune_wbt_GAS_498_ */ +{0x0F12, 0x0003}, /* 0005 0006 Tune_wbt_GAS_499_ */ +{0x0F12, 0x0000}, /* 0003 0001 Tune_wbt_GAS_500_ */ +{0x0F12, 0x0002}, /* 0006 0004 Tune_wbt_GAS_501_ */ +{0x0F12, 0x0009}, /* 000B 000F Tune_wbt_GAS_502_ */ +{0x0F12, 0x0016}, /* 0018 0023 Tune_wbt_GAS_503_ */ +{0x0F12, 0x0029}, /* 0029 003E Tune_wbt_GAS_504_ */ +{0x0F12, 0x0040}, /* 003E 006A Tune_wbt_GAS_505_ */ +{0x0F12, 0x0054}, /* 0050 0091 Tune_wbt_GAS_506_ */ +{0x0F12, 0x005F}, /* 0044 0085 Tune_wbt_GAS_507_ */ +{0x0F12, 0x004A}, /* 0033 0060 Tune_wbt_GAS_508_ */ +{0x0F12, 0x0031}, /* 0021 0041 Tune_wbt_GAS_509_ */ +{0x0F12, 0x001F}, /* 0011 002A Tune_wbt_GAS_510_ */ +{0x0F12, 0x0010}, /* 0005 0019 Tune_wbt_GAS_511_ */ +{0x0F12, 0x0008}, /* 0002 000D Tune_wbt_GAS_512_ */ +{0x0F12, 0x0004}, /* 0001 0008 Tune_wbt_GAS_513_ */ +{0x0F12, 0x0007}, /* 0003 000A Tune_wbt_GAS_514_ */ +{0x0F12, 0x000E}, /* 0008 0016 Tune_wbt_GAS_515_ */ +{0x0F12, 0x001B}, /* 0014 002A Tune_wbt_GAS_516_ */ +{0x0F12, 0x002E}, /* 0025 0047 Tune_wbt_GAS_517_ */ +{0x0F12, 0x0045}, /* 0039 0074 Tune_wbt_GAS_518_ */ +{0x0F12, 0x0059}, /* 004D 009A Tune_wbt_GAS_519_ */ +{0x0F12, 0x006C}, /* 0050 0097 Tune_wbt_GAS_520_ */ +{0x0F12, 0x0057}, /* 0041 0070 Tune_wbt_GAS_521_ */ +{0x0F12, 0x003E}, /* 002C 0052 Tune_wbt_GAS_522_ */ +{0x0F12, 0x002A}, /* 001C 003C Tune_wbt_GAS_523_ */ +{0x0F12, 0x001B}, /* 0011 0028 Tune_wbt_GAS_524_ */ +{0x0F12, 0x0012}, /* 0009 001D Tune_wbt_GAS_525_ */ +{0x0F12, 0x000F}, /* 0008 0019 Tune_wbt_GAS_526_ */ +{0x0F12, 0x0011}, /* 000A 001A Tune_wbt_GAS_527_ */ +{0x0F12, 0x0019}, /* 0012 0026 Tune_wbt_GAS_528_ */ +{0x0F12, 0x0027}, /* 001F 003B Tune_wbt_GAS_529_ */ +{0x0F12, 0x0039}, /* 002F 005A Tune_wbt_GAS_530_ */ +{0x0F12, 0x0050}, /* 0045 0089 Tune_wbt_GAS_531_ */ +{0x0F12, 0x0063}, /* 005A 00AF Tune_wbt_GAS_532_ */ +{0x0F12, 0x006F}, /* 0056 00A7 Tune_wbt_GAS_533_ */ +{0x0F12, 0x005C}, /* 0048 0088 Tune_wbt_GAS_534_ */ +{0x0F12, 0x0044}, /* 0035 006B Tune_wbt_GAS_535_ */ +{0x0F12, 0x0031}, /* 0026 0050 Tune_wbt_GAS_536_ */ +{0x0F12, 0x0023}, /* 0019 003D Tune_wbt_GAS_537_ */ +{0x0F12, 0x0019}, /* 0012 0032 Tune_wbt_GAS_538_ */ +{0x0F12, 0x0016}, /* 0011 002E Tune_wbt_GAS_539_ */ +{0x0F12, 0x0017}, /* 0012 0030 Tune_wbt_GAS_540_ */ +{0x0F12, 0x0020}, /* 001B 003E Tune_wbt_GAS_541_ */ +{0x0F12, 0x002E}, /* 0027 0052 Tune_wbt_GAS_542_ */ +{0x0F12, 0x0040}, /* 0037 0073 Tune_wbt_GAS_543_ */ +{0x0F12, 0x0055}, /* 004C 00A1 Tune_wbt_GAS_544_ */ +{0x0F12, 0x0064}, /* 0060 00C7 Tune_wbt_GAS_545_ */ +{0x0F12, 0x007E}, /* 0058 00AE Tune_wbt_GAS_546_ */ +{0x0F12, 0x0071}, /* 0050 00A4 Tune_wbt_GAS_547_ */ +{0x0F12, 0x0059}, /* 003D 0088 Tune_wbt_GAS_548_ */ +{0x0F12, 0x0046}, /* 002E 006D Tune_wbt_GAS_549_ */ +{0x0F12, 0x0039}, /* 0023 0059 Tune_wbt_GAS_550_ */ +{0x0F12, 0x002F}, /* 001C 004D Tune_wbt_GAS_551_ */ +{0x0F12, 0x002A}, /* 001B 0049 Tune_wbt_GAS_552_ */ +{0x0F12, 0x002D}, /* 001D 004E Tune_wbt_GAS_553_ */ +{0x0F12, 0x0035}, /* 0024 005B Tune_wbt_GAS_554_ */ +{0x0F12, 0x0043}, /* 002F 0073 Tune_wbt_GAS_555_ */ +{0x0F12, 0x0054}, /* 003E 0095 Tune_wbt_GAS_556_ */ +{0x0F12, 0x0069}, /* 0052 00C4 Tune_wbt_GAS_557_ */ +{0x0F12, 0x0074}, /* 0062 00E9 Tune_wbt_GAS_558_ */ +{0x0F12, 0x0083}, /* 0060 00D5 Tune_wbt_GAS_559_ */ +{0x0F12, 0x007D}, /* 0057 00C1 Tune_wbt_GAS_560_ */ +{0x0F12, 0x0068}, /* 0048 00AB Tune_wbt_GAS_561_ */ +{0x0F12, 0x0055}, /* 0039 008D Tune_wbt_GAS_562_ */ +{0x0F12, 0x0048}, /* 002E 0079 Tune_wbt_GAS_563_ */ +{0x0F12, 0x003E}, /* 0028 0070 Tune_wbt_GAS_564_ */ +{0x0F12, 0x003A}, /* 0027 006A Tune_wbt_GAS_565_ */ +{0x0F12, 0x003D}, /* 0029 006F Tune_wbt_GAS_566_ */ +{0x0F12, 0x0045}, /* 002F 0080 Tune_wbt_GAS_567_ */ +{0x0F12, 0x0051}, /* 0039 0096 Tune_wbt_GAS_568_ */ +{0x0F12, 0x0061}, /* 0047 00B9 Tune_wbt_GAS_569_ */ +{0x0F12, 0x0072}, /* 0059 00E2 Tune_wbt_GAS_570_ */ +{0x0F12, 0x0077}, /* 0067 010F Tune_wbt_GAS_571_ */ +{0x002A, 0x1348}, +{0x0F12, 0x0001}, /* gisp_gras_Enable */ + +/*************************/ +/* 07. Analog Setting 2 */ +/*************************/ + +/**************************************/ +/* 08.AF Setting */ +/**************************************/ + +/**************************************/ +/* 09.AWB-BASIC setting */ +/**************************************/ +/* For WB Calibration */ +{0x002A, 0x0B36}, +{0x0F12, 0x0005}, /* awbb_IndoorGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0B3A}, +{0x0F12, 0x00EC}, /* awbb_IndoorGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02C1}, /* awbb_IndoorGrZones_ZInfo_m_BMax */ +{0x002A, 0x0B38}, +{0x0F12, 0x0010}, /* awbb_IndoorGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0AE6}, +{0x0F12, 0x03E1}, /* awbb_IndoorGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x0413}, /* awbb_IndoorGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x039E}, /* awbb_IndoorGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x0416}, /* awbb_IndoorGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x0367}, /* awbb_IndoorGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x03F3}, /* awbb_IndoorGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x032D}, /* awbb_IndoorGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x03C5}, /* awbb_IndoorGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x02FD}, /* awbb_IndoorGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x038F}, /* awbb_IndoorGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x02D3}, /* awbb_IndoorGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x0365}, /* awbb_IndoorGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x02AA}, /* awbb_IndoorGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x033E}, /* awbb_IndoorGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x028D}, /* awbb_IndoorGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0310}, /* awbb_IndoorGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x0271}, /* awbb_IndoorGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x02F1}, /* awbb_IndoorGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x025A}, /* awbb_IndoorGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x02D2}, /* awbb_IndoorGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0249}, /* awbb_IndoorGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x02B9}, /* awbb_IndoorGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0238}, /* awbb_IndoorGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x02A2}, /* awbb_IndoorGrZones_m_BGrid_11__m_right */ +{0x0F12, 0x021B}, /* awbb_IndoorGrZones_m_BGrid_12__m_left */ +{0x0F12, 0x0289}, /* awbb_IndoorGrZones_m_BGrid_12__m_right */ +{0x0F12, 0x0200}, /* awbb_IndoorGrZones_m_BGrid_13__m_left */ +{0x0F12, 0x026C}, /* awbb_IndoorGrZones_m_BGrid_13__m_right */ +{0x0F12, 0x01FC}, /* awbb_IndoorGrZones_m_BGrid_14__m_left */ +{0x0F12, 0x024F}, /* awbb_IndoorGrZones_m_BGrid_14__m_right */ +{0x0F12, 0x021E}, /* awbb_IndoorGrZones_m_BGrid_15__m_left */ +{0x0F12, 0x022C}, /* awbb_IndoorGrZones_m_BGrid_15__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_16__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_16__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_17__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_17__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_18__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_18__m_right */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_19__m_left */ +{0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid_19__m_right */ +{0x002A, 0x0BAA}, +{0x0F12, 0x0006}, /* awbb_LowBrGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0BAE}, +{0x0F12, 0x010E}, /* awbb_LowBrGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02E9}, /* awbb_LowBrGrZones_ZInfo_m_BMax */ +{0x002A, 0x0BAC}, +{0x0F12, 0x0009}, /* awbb_LowBrGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0B7A}, +{0x0F12, 0x038C}, /* awbb_LowBrGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x03DA}, /* awbb_LowBrGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x030E}, /* awbb_LowBrGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x03E9}, /* awbb_LowBrGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x02A2}, /* awbb_LowBrGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x03C2}, /* awbb_LowBrGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x0259}, /* awbb_LowBrGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x038A}, /* awbb_LowBrGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x0218}, /* awbb_LowBrGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x0352}, /* awbb_LowBrGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x01F4}, /* awbb_LowBrGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x02E1}, /* awbb_LowBrGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x01D7}, /* awbb_LowBrGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x028E}, /* awbb_LowBrGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x01CB}, /* awbb_LowBrGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0258}, /* awbb_LowBrGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x022B}, /* awbb_LowBrGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x01CC}, /* awbb_LowBrGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid_11__m_right */ +{0x002A, 0x0B70}, +{0x0F12, 0x0005}, /* awbb_OutdoorGrZones_ZInfo_m_GridStep */ +{0x002A, 0x0B74}, +{0x0F12, 0x01F8}, /* awbb_OutdoorGrZones_ZInfo_m_BMin */ +{0x0F12, 0x02A8}, /* awbb_OutdoorGrZones_ZInfo_m_BMax */ +{0x002A, 0x0B72}, +{0x0F12, 0x0007}, /* awbb_OutdoorGrZones_ZInfo_m_GridSz */ +{0x002A, 0x0B40}, +{0x0F12, 0x029E}, /* awbb_OutdoorGrZones_m_BGrid_0__m_left */ +{0x0F12, 0x02C8}, /* awbb_OutdoorGrZones_m_BGrid_0__m_right */ +{0x0F12, 0x0281}, /* awbb_OutdoorGrZones_m_BGrid_1__m_left */ +{0x0F12, 0x02C8}, /* awbb_OutdoorGrZones_m_BGrid_1__m_right */ +{0x0F12, 0x0266}, /* awbb_OutdoorGrZones_m_BGrid_2__m_left */ +{0x0F12, 0x02AC}, /* awbb_OutdoorGrZones_m_BGrid_2__m_right */ +{0x0F12, 0x0251}, /* awbb_OutdoorGrZones_m_BGrid_3__m_left */ +{0x0F12, 0x028E}, /* awbb_OutdoorGrZones_m_BGrid_3__m_right */ +{0x0F12, 0x023D}, /* awbb_OutdoorGrZones_m_BGrid_4__m_left */ +{0x0F12, 0x0275}, /* awbb_OutdoorGrZones_m_BGrid_4__m_right */ +{0x0F12, 0x0228}, /* awbb_OutdoorGrZones_m_BGrid_5__m_left */ +{0x0F12, 0x025D}, /* awbb_OutdoorGrZones_m_BGrid_5__m_right */ +{0x0F12, 0x0228}, /* awbb_OutdoorGrZones_m_BGrid_6__m_left */ +{0x0F12, 0x0243}, /* awbb_OutdoorGrZones_m_BGrid_6__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_7__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_7__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_8__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_8__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_9__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_9__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_10__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_10__m_right */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_11__m_left */ +{0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid_11__m_right */ +{0x002A, 0x0BC8}, +{0x0F12, 0x0005}, /* awbb_CWSkinZone_ZInfo_m_GridStep */ +{0x002A, 0x0BCC}, +{0x0F12, 0x010F}, /* awbb_CWSkinZone_ZInfo_m_BMin */ +{0x0F12, 0x018F}, /* awbb_CWSkinZone_ZInfo_m_BMax */ +{0x002A, 0x0BCA}, +{0x0F12, 0x0005}, /* awbb_CWSkinZone_ZInfo_m_GridSz */ +{0x002A, 0x0BB4}, +{0x0F12, 0x03E7}, /* awbb_CWSkinZone_m_BGrid_0__m_left */ +{0x0F12, 0x03F8}, /* awbb_CWSkinZone_m_BGrid_0__m_right */ +{0x0F12, 0x03A7}, /* awbb_CWSkinZone_m_BGrid_1__m_left */ +{0x0F12, 0x03FC}, /* awbb_CWSkinZone_m_BGrid_1__m_right */ +{0x0F12, 0x0352}, /* awbb_CWSkinZone_m_BGrid_2__m_left */ +{0x0F12, 0x03D0}, /* awbb_CWSkinZone_m_BGrid_2__m_right */ +{0x0F12, 0x0322}, /* awbb_CWSkinZone_m_BGrid_3__m_left */ +{0x0F12, 0x039E}, /* awbb_CWSkinZone_m_BGrid_3__m_right */ +{0x0F12, 0x032B}, /* awbb_CWSkinZone_m_BGrid_4__m_left */ +{0x0F12, 0x034D}, /* awbb_CWSkinZone_m_BGrid_4__m_right */ +{0x002A, 0x0BE6}, +{0x0F12, 0x0006}, /* awbb_DLSkinZone_ZInfo_m_GridStep */ +{0x002A, 0x0BEA}, +{0x0F12, 0x019E}, /* awbb_DLSkinZone_ZInfo_m_BMin */ +{0x0F12, 0x0257}, /* awbb_DLSkinZone_ZInfo_m_BMax */ +{0x002A, 0x0BE8}, +{0x0F12, 0x0004}, /* awbb_DLSkinZone_ZInfo_m_GridSz */ +{0x002A, 0x0BD2}, +{0x0F12, 0x030B}, /* awbb_DLSkinZone_m_BGrid_0__m_left */ +{0x0F12, 0x0323}, /* awbb_DLSkinZone_m_BGrid_0__m_right */ +{0x0F12, 0x02C3}, /* awbb_DLSkinZone_m_BGrid_1__m_left */ +{0x0F12, 0x030F}, /* awbb_DLSkinZone_m_BGrid_1__m_right */ +{0x0F12, 0x0288}, /* awbb_DLSkinZone_m_BGrid_2__m_left */ +{0x0F12, 0x02E5}, /* awbb_DLSkinZone_m_BGrid_2__m_right */ +{0x0F12, 0x026A}, /* awbb_DLSkinZone_m_BGrid_3__m_left */ +{0x0F12, 0x02A2}, /* awbb_DLSkinZone_m_BGrid_3__m_right */ +{0x0F12, 0x0000}, /* awbb_DLSkinZone_m_BGrid_4__m_left */ +{0x0F12, 0x0000}, /* awbb_DLSkinZone_m_BGrid_4__m_right */ +{0x002A, 0x0C2C}, +{0x0F12, 0x0139}, /* awbb_IntcR */ +{0x0F12, 0x0122}, /* awbb_IntcB */ +{0x002A, 0x0BFC}, +{0x0F12, 0x03AD}, /* awbb_IndoorWP_0__r */ +{0x0F12, 0x013F}, /* awbb_IndoorWP_0__b */ +{0x0F12, 0x0341}, /* awbb_IndoorWP_1__r */ +{0x0F12, 0x017B}, /* awbb_IndoorWP_1__b */ +{0x0F12, 0x038D}, /* awbb_IndoorWP_2__r */ +{0x0F12, 0x014B}, /* awbb_IndoorWP_2__b */ +{0x0F12, 0x02C3}, /* awbb_IndoorWP_3__r */ +{0x0F12, 0x01CC}, /* awbb_IndoorWP_3__b */ +{0x0F12, 0x0241}, /* awbb_IndoorWP_4__r */ +{0x0F12, 0x027F}, /* awbb_IndoorWP_4__b */ +{0x0F12, 0x0241}, /* awbb_IndoorWP_5__r */ +{0x0F12, 0x027F}, /* awbb_IndoorWP_5__b */ +{0x0F12, 0x0214}, /* awbb_IndoorWP_6__r */ +{0x0F12, 0x02A8}, /* awbb_IndoorWP_6__b */ +{0x0F12, 0x0270}, /* 255 awbb_OutdoorWP_r */ +{0x0F12, 0x0210}, /* 25B awbb_OutdoorWP_b */ +{0x002A, 0x0C4C}, +{0x0F12, 0x0452}, /* awbb_MvEq_RBthresh */ +{0x002A, 0x0C58}, +{0x0F12, 0x059C}, /* awbb_MvEq_RBthresh */ +{0x002A, 0x0BF8}, +{0x0F12, 0x01AE}, /* awbb_LowTSep_m_RminusB */ +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, /* awbb_SkinPreference */ +{0x002A, 0x0CAC}, +{0x0F12, 0x0F00}, /* awbb_SkinPreference */ +{0x002A, 0x0C28}, +{0x0F12, 0x0000}, /* awbb_SkinPreference */ +{0x002A, 0x0D0E}, +{0x0F12, 0x00B8}, /* awbb_GridCoeff_R_2 */ +{0x0F12, 0x00B2}, /* awbb_GridCoeff_B_2 */ +{0x002A, 0x0CFE}, +{0x0F12, 0x0FAB}, /* awbb_GridConst_2_0_ */ +{0x0F12, 0x0FF5}, /* awbb_GridConst_2_1_ */ +{0x0F12, 0x10BB}, /* awbb_GridConst_2_2_ */ +{0x0F12, 0x1123}, /* 1153 awbb_GridConst_2_3_ */ +{0x0F12, 0x1165}, /* 11C5 awbb_GridConst_2_4_ */ +{0x0F12, 0x122A}, /* awbb_GridConst_2_5_ */ +{0x0F12, 0x00A9}, /* awbb_GridCoeff_R_1 */ +{0x0F12, 0x00C0}, /* awbb_GridCoeff_B_1 */ +{0x002A, 0x0CF8}, +{0x0F12, 0x030E}, /* awbb_GridConst_1_0_ */ +{0x0F12, 0x034C}, /* awbb_GridConst_1_1_ */ +{0x0F12, 0x0388}, /* awbb_GridConst_1_2_ */ + +{0x002A, 0x0CB0}, +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_0__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_0__1_ */ +{0x0F12, 0x0010}, /* 0078 awbb_GridCorr_R_0__2_ */ +{0x0F12, 0x0040}, /* 00AA awbb_GridCorr_R_0__3_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_0__4_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_0__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_1__0_ */ +{0x0F12, 0x0000}, /* 0096 awbb_GridCorr_R_1__1_ */ +{0x0F12, 0x0010}, /* 0000 awbb_GridCorr_R_1__2_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_1__3_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_1__4_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_1__5_ */ + +{0x0F12, 0x0000}, /* 00E6 awbb_GridCorr_R_2__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_R_2__1_ */ +{0x0F12, 0x0010}, /* 0000 awbb_GridCorr_R_2__2_ */ +{0x0F12, 0x0040}, /* 0000 awbb_GridCorr_R_2__3_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_2__4_ */ +{0x0F12, 0x0080}, /* 0000 awbb_GridCorr_R_2__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_0__0_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_0__1_ */ +{0x0F12, 0x0000}, /* 0064 awbb_GridCorr_B_0__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_0__3_ */ +{0x0F12, 0xFF60}, /* 0000 awbb_GridCorr_B_0__4_ */ +{0x0F12, 0xFF00}, /* 0000 awbb_GridCorr_B_0__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_1__0_ */ +{0x0F12, 0x0000}, /* 0032 awbb_GridCorr_B_1__1_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_1__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_1__3_ */ +{0x0F12, 0xFF60}, /* FF38 awbb_GridCorr_B_1__4_ */ +{0x0F12, 0xFF00}, /* 0000 awbb_GridCorr_B_1__5_ */ + +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_2__0_ */ +{0x0F12, 0x0000}, /* 0032 awbb_GridCorr_B_2__1_ */ +{0x0F12, 0x0000}, /* 0000 awbb_GridCorr_B_2__2_ */ +{0x0F12, 0xFFC0}, /* 0000 awbb_GridCorr_B_2__3_ */ +{0x0F12, 0xFF60}, /* 0000 awbb_GridCorr_B_2__4_ */ +{0x0F12, 0xFF00}, /* 0000 awbb_GridCorr_B_2__5_ */ + +{0x002A, 0x0D30}, +{0x0F12, 0x0002}, /* awbb_GridEnable */ +/* For Outdoor Detector */ +{0x002A, 0x0C86}, +{0x0F12, 0x0005}, /* awbb_OutdoorDetectionZone_ZInfo_m_GridSz */ +{0x002A, 0x0C70}, +{0x0F12, 0xFF7B}, /* awbb_OutdoorDetectionZone_m_BGrid_0__m_left */ +{0x0F12, 0x00CE}, /* awbb_OutdoorDetectionZone_m_BGrid_0__m_right */ +{0x0F12, 0xFF23}, /* awbb_OutdoorDetectionZone_m_BGrid_1__m_left */ +{0x0F12, 0x010D}, /* awbb_OutdoorDetectionZone_m_BGrid_1__m_right */ +{0x0F12, 0xFEF3}, /* awbb_OutdoorDetectionZone_m_BGrid_2__m_left */ +{0x0F12, 0x012C}, /* awbb_OutdoorDetectionZone_m_BGrid_2__m_right */ +{0x0F12, 0xFED7}, /* awbb_OutdoorDetectionZone_m_BGrid_3__m_left */ +{0x0F12, 0x014E}, /* awbb_OutdoorDetectionZone_m_BGrid_3__m_right */ +{0x0F12, 0xFEBB}, /* awbb_OutdoorDetectionZone_m_BGrid_4__m_left */ +{0x0F12, 0x0162}, /* awbb_OutdoorDetectionZone_m_BGrid_4__m_right */ +{0x0F12, 0x1388}, /* awbb_OutdoorDetectionZone_ZInfo_m_AbsGridStep */ +{0x002A, 0x0C8A}, +{0x0F12, 0x4ACB}, /* awbb_OutdoorDetectionZone_ZInfo_m_MaxNB */ +{0x002A, 0x0C88}, +{0x0F12, 0x0A7C}, /* awbb_OutdoorDetectionZone_ZInfo_m_NBoffs */ + +/**************************************/ +/* 10.Auto Flicker Detection */ +/**************************************/ +{0x0028, 0x7000}, +{0x002A, 0x03F4}, +{0x0F12, 0x0002}, /*REG_SF_USER_FlickerQuant */ +{0x0F12, 0x0001}, /*REG_SF_USER_FlickerQuantChanged */ +{0x002A, 0x0408}, +{0x0F12, 0x067F}, /*REG_TC_DBG_AutoAlgEnBits all AA are on */ + +/**************************************/ +/* 11.AE Setting */ +/**************************************/ + +{0x002A, 0x0D40}, +{0x0F12, 0x003E}, /* 3E TVAR_ae_BrAve */ + +/* For LT Calibration */ +{0x002A, 0x0D46}, +{0x0F12, 0x000F}, /* ae_StatMode */ + +{0x002A, 0x0440}, +{0x0F12, 0x3410}, /* lt_uMaxExp_0_ */ +{0x002A, 0x0444}, +{0x0F12, 0x6820}, /* lt_uMaxExp_1_ */ +{0x002A, 0x0448}, +{0x0F12, 0x8227}, /* lt_uMaxExp_2_ */ +{0x002A, 0x044C}, +{0x0F12, 0xC350}, /* lt_uMaxExp_3_ */ +{0x002A, 0x0450}, +{0x0F12, 0x3410}, /* lt_uCapMaxExp_0_ */ +{0x002A, 0x0454}, +{0x0F12, 0x6820}, /* lt_uCapMaxExp_1_ */ +{0x002A, 0x0458}, +{0x0F12, 0x8227}, /* lt_uCapMaxExp_2_ */ +{0x002A, 0x045C}, +{0x0F12, 0xC350}, /* lt_uCapMaxExp_3_ */ +{0x002A, 0x0460}, +{0x0F12, 0x01B0}, /* lt_uMaxAnGain_0_ */ +{0x0F12, 0x01B0}, /* lt_uMaxAnGain_1_ */ +{0x0F12, 0x0280}, /* lt_uMaxAnGain_2_ */ +{0x0F12, 0x0A80}, /* lt_uMaxAnGain_3_ */ +{0x0F12, 0x0100}, /* B0 0100 lt_uMaxDigGain */ +{0x0F12, 0x3000}, /* lt_uMaxTotGain */ +{0x002A, 0x042E}, +{0x0F12, 0x010E}, /* lt_uMaxTotGain */ +{0x0F12, 0x00F5}, /* lt_uLimitLow */ +{0x002A, 0x0DE0}, +{0x0F12, 0x0002}, /* ae_Fade2BlackEnable F2B off, F2W on */ + +/* For Illum Type Calibration */ +/* WRITE #SARR_IllumType_0_ 0078 */ +/* WRITE #SARR_IllumType_1_ 00C3 */ +/* WRITE #SARR_IllumType_2_ 00E9 */ +/* WRITE #SARR_IllumType_3_ 0128 */ +/* WRITE #SARR_IllumType_4_ 016F */ +/* WRITE #SARR_IllumType_5_ 0195 */ +/* WRITE #SARR_IllumType_6_ 01A4 */ +/* WRITE #SARR_IllumTypeF_0_ 0100 */ +/* WRITE #SARR_IllumTypeF_1_ 0100 */ +/* WRITE #SARR_IllumTypeF_2_ 0110 */ +/* WRITE #SARR_IllumTypeF_3_ 00E5 */ +/* WRITE #SARR_IllumTypeF_4_ 0100 */ +/* WRITE #SARR_IllumTypeF_5_ 00ED */ +/* WRITE #SARR_IllumTypeF_6_ 00ED */ + +/**************************************/ +/* 12.AE Weight (Normal) */ +/**************************************/ +{0x002A, 0x0D4E}, +{0x0F12, 0x0000}, /* 0000 ae_WeightTbl_16_0_ */ +{0x0F12, 0x0101}, /* 0101 ae_WeightTbl_16_1_ */ +{0x0F12, 0x0101}, /* 0101 ae_WeightTbl_16_2_ */ +{0x0F12, 0x0000}, /* 0000 ae_WeightTbl_16_3_ */ +{0x0F12, 0x0201}, /* 0101 ae_WeightTbl_16_4_ */ +{0x0F12, 0x0202}, /* 0101 ae_WeightTbl_16_5_ */ +{0x0F12, 0x0202}, /* 0101 ae_WeightTbl_16_6_ */ +{0x0F12, 0x0102}, /* 0101 ae_WeightTbl_16_7_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_8_ */ +{0x0F12, 0x0303}, /* 0303 ae_WeightTbl_16_9_ */ +{0x0F12, 0x0303}, /* 0303 ae_WeightTbl_16_10_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_11_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_12_ */ +{0x0F12, 0x0403}, /* 0403 ae_WeightTbl_16_13_ */ +{0x0F12, 0x0304}, /* 0304 ae_WeightTbl_16_14_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_15_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_16_ */ +{0x0F12, 0x0403}, /* 0403 ae_WeightTbl_16_17_ */ +{0x0F12, 0x0304}, /* 0304 ae_WeightTbl_16_18_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_19_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_20_ */ +{0x0F12, 0x0303}, /* 0403 ae_WeightTbl_16_21_ */ +{0x0F12, 0x0303}, /* 0304 ae_WeightTbl_16_22_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_23_ */ +{0x0F12, 0x0201}, /* 0201 ae_WeightTbl_16_24_ */ +{0x0F12, 0x0202}, /* 0303 ae_WeightTbl_16_25_ */ +{0x0F12, 0x0202}, /* 0303 ae_WeightTbl_16_26_ */ +{0x0F12, 0x0102}, /* 0102 ae_WeightTbl_16_27_ */ +{0x0F12, 0x0000}, /* 0201 ae_WeightTbl_16_28_ */ +{0x0F12, 0x0101}, /* 0202 ae_WeightTbl_16_29_ */ +{0x0F12, 0x0101}, /* 0202 ae_WeightTbl_16_30_ */ +{0x0F12, 0x0000}, /* 0102 ae_WeightTbl_16_31_ */ + +/**************************************/ +/* 13.Flash Setting */ +/**************************************/ + +/**************************************/ +/* 14.CCM Setting */ +/**************************************/ + +{0x002A, 0x33A4}, +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_0__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_0__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_0__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_0__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_0__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_0__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_0__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_0__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_0__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_0__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_0__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_0__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_0__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_0__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_0__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_0__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_0__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_0__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_1__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_1__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_1__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_1__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_1__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_1__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_1__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_1__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_1__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_1__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_1__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_1__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_1__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_1__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_1__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_1__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_1__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_1__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_2__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_2__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_2__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_2__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_2__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_2__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_2__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_2__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_2__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_2__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_2__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_2__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_2__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_2__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_2__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_2__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_2__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_2__17_ */ +{0x0F12, 0x01D0}, /* Tune_wbt_BaseCcms_3__0_ */ +{0x0F12, 0xFFA1}, /* Tune_wbt_BaseCcms_3__1_ */ +{0x0F12, 0xFFFA}, /* Tune_wbt_BaseCcms_3__2_ */ +{0x0F12, 0xFF6F}, /* Tune_wbt_BaseCcms_3__3_ */ +{0x0F12, 0x0140}, /* Tune_wbt_BaseCcms_3__4_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_BaseCcms_3__5_ */ +{0x0F12, 0xFFC1}, /* Tune_wbt_BaseCcms_3__6_ */ +{0x0F12, 0x001F}, /* Tune_wbt_BaseCcms_3__7_ */ +{0x0F12, 0x01BD}, /* Tune_wbt_BaseCcms_3__8_ */ +{0x0F12, 0x013F}, /* Tune_wbt_BaseCcms_3__9_ */ +{0x0F12, 0x00E1}, /* Tune_wbt_BaseCcms_3__10_ */ +{0x0F12, 0xFF43}, /* Tune_wbt_BaseCcms_3__11_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_3__12_ */ +{0x0F12, 0xFFC0}, /* Tune_wbt_BaseCcms_3__13_ */ +{0x0F12, 0x01B7}, /* Tune_wbt_BaseCcms_3__14_ */ +{0x0F12, 0xFF30}, /* Tune_wbt_BaseCcms_3__15_ */ +{0x0F12, 0x015F}, /* Tune_wbt_BaseCcms_3__16_ */ +{0x0F12, 0x0106}, /* Tune_wbt_BaseCcms_3__17_ */ +{0x0F12, 0x01BF}, /* Tune_wbt_BaseCcms_4__0_ */ +{0x0F12, 0xFFBF}, /* Tune_wbt_BaseCcms_4__1_ */ +{0x0F12, 0xFFFE}, /* Tune_wbt_BaseCcms_4__2_ */ +{0x0F12, 0xFF6D}, /* Tune_wbt_BaseCcms_4__3_ */ +{0x0F12, 0x01B4}, /* Tune_wbt_BaseCcms_4__4_ */ +{0x0F12, 0xFF66}, /* Tune_wbt_BaseCcms_4__5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_BaseCcms_4__6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_BaseCcms_4__7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_BaseCcms_4__8_ */ +{0x0F12, 0x0136}, /* Tune_wbt_BaseCcms_4__9_ */ +{0x0F12, 0x0132}, /* Tune_wbt_BaseCcms_4__10_ */ +{0x0F12, 0xFF85}, /* Tune_wbt_BaseCcms_4__11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_BaseCcms_4__12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_BaseCcms_4__13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_4__14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_BaseCcms_4__15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_BaseCcms_4__16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_BaseCcms_4__17_ */ +{0x0F12, 0x01BF}, /* Tune_wbt_BaseCcms_5__0_ */ +{0x0F12, 0xFFBF}, /* Tune_wbt_BaseCcms_5__1_ */ +{0x0F12, 0xFFFE}, /* Tune_wbt_BaseCcms_5__2_ */ +{0x0F12, 0xFF6D}, /* Tune_wbt_BaseCcms_5__3_ */ +{0x0F12, 0x01B4}, /* Tune_wbt_BaseCcms_5__4_ */ +{0x0F12, 0xFF66}, /* Tune_wbt_BaseCcms_5__5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_BaseCcms_5__6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_BaseCcms_5__7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_BaseCcms_5__8_ */ +{0x0F12, 0x0136}, /* Tune_wbt_BaseCcms_5__9_ */ +{0x0F12, 0x0132}, /* Tune_wbt_BaseCcms_5__10_ */ +{0x0F12, 0xFF85}, /* Tune_wbt_BaseCcms_5__11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_BaseCcms_5__12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_BaseCcms_5__13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_BaseCcms_5__14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_BaseCcms_5__15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_BaseCcms_5__16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_BaseCcms_5__17_ */ +{0x002A, 0x3380}, +{0x0F12, 0x01AC}, /* Tune_wbt_OutdoorCcm_0_ */ +{0x0F12, 0xFFD7}, /* Tune_wbt_OutdoorCcm_1_ */ +{0x0F12, 0x0019}, /* Tune_wbt_OutdoorCcm_2_ */ +{0x0F12, 0xFF49}, /* Tune_wbt_OutdoorCcm_3_ */ +{0x0F12, 0x01D9}, /* Tune_wbt_OutdoorCcm_4_ */ +{0x0F12, 0xFF63}, /* Tune_wbt_OutdoorCcm_5_ */ +{0x0F12, 0xFFCA}, /* Tune_wbt_OutdoorCcm_6_ */ +{0x0F12, 0xFFCE}, /* Tune_wbt_OutdoorCcm_7_ */ +{0x0F12, 0x017B}, /* Tune_wbt_OutdoorCcm_8_ */ +{0x0F12, 0x0132}, /* Tune_wbt_OutdoorCcm_9_ */ +{0x0F12, 0x012E}, /* Tune_wbt_OutdoorCcm_10_ */ +{0x0F12, 0xFF8D}, /* Tune_wbt_OutdoorCcm_11_ */ +{0x0F12, 0x018B}, /* Tune_wbt_OutdoorCcm_12_ */ +{0x0F12, 0xFF73}, /* Tune_wbt_OutdoorCcm_13_ */ +{0x0F12, 0x0191}, /* Tune_wbt_OutdoorCcm_14_ */ +{0x0F12, 0xFF3F}, /* Tune_wbt_OutdoorCcm_15_ */ +{0x0F12, 0x015B}, /* Tune_wbt_OutdoorCcm_16_ */ +{0x0F12, 0x00D0}, /* Tune_wbt_OutdoorCcm_17_ */ +{0x002A, 0x0612}, +{0x0F12, 0x009D}, /* SARR_AwbCcmCord_0_ */ +{0x0F12, 0x00D5}, /* SARR_AwbCcmCord_1_ */ +{0x0F12, 0x0103}, /* SARR_AwbCcmCord_2_ */ +{0x0F12, 0x0128}, /* SARR_AwbCcmCord_3_ */ +{0x0F12, 0x0166}, /* SARR_AwbCcmCord_4_ */ +{0x0F12, 0x0193}, /* SARR_AwbCcmCord_5_ */ + +/**************************************/ +/* 15.GAMMA */ +/**************************************/ +/* For Pre Post Gamma Calibration */ +{0x002A, 0x0538}, +{0x0F12, 0x0000}, /* seti_uGammaLutPreDemNoBin_0_ */ +{0x0F12, 0x001F}, /* seti_uGammaLutPreDemNoBin_1_ */ +{0x0F12, 0x0035}, /* seti_uGammaLutPreDemNoBin_2_ */ +{0x0F12, 0x005A}, /* seti_uGammaLutPreDemNoBin_3_ */ +{0x0F12, 0x0095}, /* seti_uGammaLutPreDemNoBin_4_ */ +{0x0F12, 0x00E6}, /* seti_uGammaLutPreDemNoBin_5_ */ +{0x0F12, 0x0121}, /* seti_uGammaLutPreDemNoBin_6_ */ +{0x0F12, 0x0139}, /* seti_uGammaLutPreDemNoBin_7_ */ +{0x0F12, 0x0150}, /* seti_uGammaLutPreDemNoBin_8_ */ +{0x0F12, 0x0177}, /* seti_uGammaLutPreDemNoBin_9_ */ +{0x0F12, 0x019A}, /* seti_uGammaLutPreDemNoBin_10_ */ +{0x0F12, 0x01BB}, /* seti_uGammaLutPreDemNoBin_11_ */ +{0x0F12, 0x01DC}, /* seti_uGammaLutPreDemNoBin_12_ */ +{0x0F12, 0x0219}, /* seti_uGammaLutPreDemNoBin_13_ */ +{0x0F12, 0x0251}, /* seti_uGammaLutPreDemNoBin_14_ */ +{0x0F12, 0x02B3}, /* seti_uGammaLutPreDemNoBin_15_ */ +{0x0F12, 0x030A}, /* seti_uGammaLutPreDemNoBin_16_ */ +{0x0F12, 0x035F}, /* seti_uGammaLutPreDemNoBin_17_ */ +{0x0F12, 0x03B1}, /* seti_uGammaLutPreDemNoBin_18_ */ +{0x0F12, 0x03FF}, /* seti_uGammaLutPreDemNoBin_19_ */ +{0x0F12, 0x0000}, /* seti_uGammaLutPostDemNoBin_0_ */ +{0x0F12, 0x0001}, /* seti_uGammaLutPostDemNoBin_1_ */ +{0x0F12, 0x0001}, /* seti_uGammaLutPostDemNoBin_2_ */ +{0x0F12, 0x0002}, /* seti_uGammaLutPostDemNoBin_3_ */ +{0x0F12, 0x0004}, /* seti_uGammaLutPostDemNoBin_4_ */ +{0x0F12, 0x000A}, /* seti_uGammaLutPostDemNoBin_5_ */ +{0x0F12, 0x0012}, /* seti_uGammaLutPostDemNoBin_6_ */ +{0x0F12, 0x0016}, /* seti_uGammaLutPostDemNoBin_7_ */ +{0x0F12, 0x001A}, /* seti_uGammaLutPostDemNoBin_8_ */ +{0x0F12, 0x0024}, /* seti_uGammaLutPostDemNoBin_9_ */ +{0x0F12, 0x0031}, /* seti_uGammaLutPostDemNoBin_10_ */ +{0x0F12, 0x003E}, /* seti_uGammaLutPostDemNoBin_11_ */ +{0x0F12, 0x004E}, /* seti_uGammaLutPostDemNoBin_12_ */ +{0x0F12, 0x0075}, /* seti_uGammaLutPostDemNoBin_13_ */ +{0x0F12, 0x00A8}, /* seti_uGammaLutPostDemNoBin_14_ */ +{0x0F12, 0x0126}, /* seti_uGammaLutPostDemNoBin_15_ */ +{0x0F12, 0x01BE}, /* seti_uGammaLutPostDemNoBin_16_ */ +{0x0F12, 0x0272}, /* seti_uGammaLutPostDemNoBin_17_ */ +{0x0F12, 0x0334}, /* seti_uGammaLutPostDemNoBin_18_ */ +{0x0F12, 0x03FF}, /* seti_uGammaLutPostDemNoBin_19_ */ + +/* For Gamma Calibration */ + +{0x002A, 0x0498}, +{0x0F12, 0x0000}, /* SARR_usDualGammaLutRGBIndoor_0__0_ */ +{0x0F12, 0x0002}, /* SARR_usDualGammaLutRGBIndoor_0__1_ */ +{0x0F12, 0x0007}, /* SARR_usDualGammaLutRGBIndoor_0__2_ */ +{0x0F12, 0x001D}, /* SARR_usDualGammaLutRGBIndoor_0__3_ */ +{0x0F12, 0x006E}, /* SARR_usDualGammaLutRGBIndoor_0__4_ */ +{0x0F12, 0x00D3}, /* SARR_usDualGammaLutRGBIndoor_0__5_ */ +{0x0F12, 0x0127}, /* SARR_usDualGammaLutRGBIndoor_0__6_ */ +{0x0F12, 0x014C}, /* SARR_usDualGammaLutRGBIndoor_0__7_ */ +{0x0F12, 0x016E}, /* SARR_usDualGammaLutRGBIndoor_0__8_ */ +{0x0F12, 0x01A5}, /* SARR_usDualGammaLutRGBIndoor_0__9_ */ +{0x0F12, 0x01D3}, /* SARR_usDualGammaLutRGBIndoor_0__10_ */ +{0x0F12, 0x01FB}, /* SARR_usDualGammaLutRGBIndoor_0__11_ */ +{0x0F12, 0x021F}, /* SARR_usDualGammaLutRGBIndoor_0__12_ */ +{0x0F12, 0x0260}, /* SARR_usDualGammaLutRGBIndoor_0__13_ */ +{0x0F12, 0x029A}, /* SARR_usDualGammaLutRGBIndoor_0__14_ */ +{0x0F12, 0x02F7}, /* SARR_usDualGammaLutRGBIndoor_0__15_ */ +{0x0F12, 0x034D}, /* SARR_usDualGammaLutRGBIndoor_0__16_ */ +{0x0F12, 0x0395}, /* SARR_usDualGammaLutRGBIndoor_0__17_ */ +{0x0F12, 0x03CE}, /* SARR_usDualGammaLutRGBIndoor_0__18_ */ +{0x0F12, 0x03FF}, /* SARR_usDualGammaLutRGBIndoor_0__19_ */ +{0x0F12, 0x0000}, /* SARR_usDualGammaLutRGBOutdoor_0__0_ */ +{0x0F12, 0x0004}, /* SARR_usDualGammaLutRGBOutdoor_0__1_ */ +{0x0F12, 0x000C}, /* SARR_usDualGammaLutRGBOutdoor_0__2_ */ +{0x0F12, 0x0024}, /* SARR_usDualGammaLutRGBOutdoor_0__3_ */ +{0x0F12, 0x006E}, /* SARR_usDualGammaLutRGBOutdoor_0__4_ */ +{0x0F12, 0x00D1}, /* SARR_usDualGammaLutRGBOutdoor_0__5_ */ +{0x0F12, 0x0119}, /* SARR_usDualGammaLutRGBOutdoor_0__6_ */ +{0x0F12, 0x0139}, /* SARR_usDualGammaLutRGBOutdoor_0__7_ */ +{0x0F12, 0x0157}, /* SARR_usDualGammaLutRGBOutdoor_0__8_ */ +{0x0F12, 0x018E}, /* SARR_usDualGammaLutRGBOutdoor_0__9_ */ +{0x0F12, 0x01C3}, /* SARR_usDualGammaLutRGBOutdoor_0__10_ */ +{0x0F12, 0x01F3}, /* SARR_usDualGammaLutRGBOutdoor_0__11_ */ +{0x0F12, 0x021F}, /* SARR_usDualGammaLutRGBOutdoor_0__12_ */ +{0x0F12, 0x0269}, /* SARR_usDualGammaLutRGBOutdoor_0__13_ */ +{0x0F12, 0x02A6}, /* SARR_usDualGammaLutRGBOutdoor_0__14_ */ +{0x0F12, 0x02FF}, /* SARR_usDualGammaLutRGBOutdoor_0__15_ */ +{0x0F12, 0x0351}, /* SARR_usDualGammaLutRGBOutdoor_0__16_ */ +{0x0F12, 0x0395}, /* SARR_usDualGammaLutRGBOutdoor_0__17_ */ +{0x0F12, 0x03CE}, /* SARR_usDualGammaLutRGBOutdoor_0__18_ */ +{0x0F12, 0x03FF}, /* SARR_usDualGammaLutRGBOutdoor_0__19_ */ + +/**************************************/ +/* 16.AFIT */ +/**************************************/ +{0x002A, 0x06D4}, +{0x0F12, 0x0032}, /* afit_uNoiseIndInDoor_0_ */ +{0x0F12, 0x0078}, /* afit_uNoiseIndInDoor_1_ */ +{0x0F12, 0x00C8}, /* afit_uNoiseIndInDoor_2_ */ +{0x0F12, 0x0190}, /* afit_uNoiseIndInDoor_3_ */ +{0x0F12, 0x028C}, /* afit_uNoiseIndInDoor_4_ */ + +{0x002A, 0x0734}, +{0x0F12, 0x0000}, /* AfitBaseVals_0__0_ Brightness[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__1_ Contrast[0] */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__4_ */ +{0x0F12, 0x0078}, /* AfitBaseVals_0__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_0__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_0__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_0__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_0__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_0__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_0__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_0__14_ */ +{0x0F12, 0x01FF}, /* AfitBaseVals_0__15_ */ +{0x0F12, 0x0144}, /* AfitBaseVals_0__16_ */ +{0x0F12, 0x000F}, /* AfitBaseVals_0__17_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_0__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_0__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__21_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_0__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_0__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_0__25_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_0__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_0__27_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_0__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_0__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_0__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_0__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_0__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_0__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_0__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_0__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__40_ */ +{0x0F12, 0x1408}, /* AfitBaseVals_0__41_ */ +{0x0F12, 0x0214}, /* AfitBaseVals_0__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_0__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_0__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_0__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_0__47_ */ +{0x0F12, 0x0094}, /* AfitBaseVals_0__48_ */ +{0x0F12, 0x0580}, /* AfitBaseVals_0__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_0__50_ */ +{0x0F12, 0x0308}, /* AfitBaseVals_0__51_ */ +{0x0F12, 0x3186}, /* AfitBaseVals_0__52_ */ +{0x0F12, 0x5260}, /* AfitBaseVals_0__53_ */ +{0x0F12, 0x0A02}, /* AfitBaseVals_0__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_0__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_0__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_0__57_ */ +{0x0F12, 0x324E}, /* AfitBaseVals_0__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_0__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_0__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_0__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_0__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_0__63_ */ +{0x0F12, 0x4646}, /* AfitBaseVals_0__64_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__65_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_0__68_ */ +{0x0F12, 0x3202}, /* AfitBaseVals_0__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_0__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_0__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_0__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_0__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_0__74_ */ +{0x0F12, 0x4646}, /* AfitBaseVals_0__75_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__76_ */ +{0x0F12, 0x0802}, /* AfitBaseVals_0__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_0__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_0__79_ */ +{0x0F12, 0x3202}, /* AfitBaseVals_0__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_0__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_0__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_0__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__0_ Brightness[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__1_ Contrast[1] */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__4_ */ +{0x0F12, 0x006A}, /* AfitBaseVals_1__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_1__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_1__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_1__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_1__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_1__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_1__12_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_1__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_1__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_1__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_1__16_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__17_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_1__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_1__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__21_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_1__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_1__25_ */ +{0x0F12, 0x000A}, /* AfitBaseVals_1__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_1__27_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_1__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_1__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_1__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_1__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_1__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_1__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_1__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__40_ */ +{0x0F12, 0x1408}, /* AfitBaseVals_1__41_ */ +{0x0F12, 0x0214}, /* AfitBaseVals_1__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_1__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_1__44_ */ +{0x0F12, 0x0002}, /* AfitBaseVals_1__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_1__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_1__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_1__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_1__50_ */ +{0x0F12, 0x0308}, /* AfitBaseVals_1__51_ */ +{0x0F12, 0x1E65}, /* AfitBaseVals_1__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_1__53_ */ +{0x0F12, 0x0A03}, /* AfitBaseVals_1__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_1__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_1__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_1__57_ */ +{0x0F12, 0x324D}, /* AfitBaseVals_1__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_1__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_1__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_1__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_1__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_1__63_ */ +{0x0F12, 0x2F34}, /* AfitBaseVals_1__64_ */ +{0x0F12, 0x0504}, /* AfitBaseVals_1__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_1__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_1__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_1__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_1__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_1__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_1__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_1__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_1__74_ */ +{0x0F12, 0x1414}, /* AfitBaseVals_1__75_ */ +{0x0F12, 0x0504}, /* AfitBaseVals_1__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_1__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_1__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_1__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_1__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_1__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_1__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_1__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__0_ Brightness[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__1_ Contrast[2] */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__4_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_2__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_2__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_2__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_2__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_2__12_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_2__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_2__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_2__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_2__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_2__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_2__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_2__19_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_2__20_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__21_ */ +{0x0F12, 0x0019}, /* AfitBaseVals_2__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_2__23_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__24_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_2__25_ */ +{0x0F12, 0x0019}, /* AfitBaseVals_2__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_2__27_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_2__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_2__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_2__34_ */ +{0x0F12, 0x07FF}, /* AfitBaseVals_2__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_2__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_2__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_2__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_2__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_2__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_2__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_2__44_ */ +{0x0F12, 0x0002}, /* AfitBaseVals_2__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_2__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_2__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_2__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_2__50_ */ +{0x0F12, 0x0208}, /* AfitBaseVals_2__51_ */ +{0x0F12, 0x1E4B}, /* AfitBaseVals_2__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_2__53_ */ +{0x0F12, 0x0A05}, /* AfitBaseVals_2__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_2__55_ */ +{0x0F12, 0x0500}, /* AfitBaseVals_2__56_ */ +{0x0F12, 0x032D}, /* AfitBaseVals_2__57_ */ +{0x0F12, 0x324D}, /* AfitBaseVals_2__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_2__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_2__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_2__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_2__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_2__63_ */ +{0x0F12, 0x1E23}, /* AfitBaseVals_2__64_ */ +{0x0F12, 0x0505}, /* AfitBaseVals_2__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_2__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_2__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_2__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_2__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_2__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_2__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_2__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_2__74_ */ +{0x0F12, 0x1E23}, /* AfitBaseVals_2__75_ */ +{0x0F12, 0x0505}, /* AfitBaseVals_2__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_2__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_2__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_2__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_2__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_2__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_2__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_2__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__0_ Brightness[3] */ +{0x0F12, 0x0018}, /* 0000 AfitBaseVals_3__1_ Contrast[3] */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__4_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_3__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_3__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_3__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_3__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_3__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_3__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_3__14_ */ +{0x0F12, 0x007D}, /* AfitBaseVals_3__15_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_3__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_3__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_3__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_3__19_ */ +{0x0F12, 0x009F}, /* AfitBaseVals_3__20_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__21_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_3__23_ */ +{0x0F12, 0x0037}, /* AfitBaseVals_3__24_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__25_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_3__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_3__27_ */ +{0x0F12, 0x0037}, /* AfitBaseVals_3__28_ */ +{0x0F12, 0x2B32}, /* AfitBaseVals_3__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_3__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_3__34_ */ +{0x0F12, 0x07A0}, /* AfitBaseVals_3__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_3__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_3__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_3__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_3__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_3__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_3__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_3__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_3__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_3__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_3__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_3__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_3__50_ */ +{0x0F12, 0x0108}, /* AfitBaseVals_3__51_ */ +{0x0F12, 0x1E32}, /* AfitBaseVals_3__52_ */ +{0x0F12, 0x1A24}, /* AfitBaseVals_3__53_ */ +{0x0F12, 0x0A05}, /* AfitBaseVals_3__54_ */ +{0x0F12, 0x080A}, /* AfitBaseVals_3__55_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__56_ */ +{0x0F12, 0x0328}, /* AfitBaseVals_3__57_ */ +{0x0F12, 0x324C}, /* AfitBaseVals_3__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_3__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_3__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_3__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_3__62_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_3__63_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_3__64_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_3__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_3__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_3__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_3__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_3__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_3__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_3__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_3__73_ */ +{0x0F12, 0x9696}, /* AfitBaseVals_3__74_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_3__75_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_3__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_3__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_3__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_3__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_3__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_3__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_3__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_3__83_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__0_ Brightness[4] */ +{0x0F12, 0x0014}, /* 0000 AfitBaseVals_4__1_ Contrast[4] */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__2_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__3_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__4_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__5_ */ +{0x0F12, 0x012C}, /* AfitBaseVals_4__6_ */ +{0x0F12, 0x03FF}, /* AfitBaseVals_4__7_ */ +{0x0F12, 0x0014}, /* AfitBaseVals_4__8_ */ +{0x0F12, 0x0064}, /* AfitBaseVals_4__9_ */ +{0x0F12, 0x000C}, /* AfitBaseVals_4__10_ */ +{0x0F12, 0x0010}, /* AfitBaseVals_4__11_ */ +{0x0F12, 0x01E6}, /* AfitBaseVals_4__12_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__13_ */ +{0x0F12, 0x0070}, /* AfitBaseVals_4__14_ */ +{0x0F12, 0x0087}, /* AfitBaseVals_4__15_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_4__16_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_4__17_ */ +{0x0F12, 0x0096}, /* AfitBaseVals_4__18_ */ +{0x0F12, 0x0073}, /* AfitBaseVals_4__19_ */ +{0x0F12, 0x00B4}, /* AfitBaseVals_4__20_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__21_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__22_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_4__23_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_4__24_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__25_ */ +{0x0F12, 0x0028}, /* AfitBaseVals_4__26_ */ +{0x0F12, 0x0023}, /* AfitBaseVals_4__27_ */ +{0x0F12, 0x0046}, /* AfitBaseVals_4__28_ */ +{0x0F12, 0x2B23}, /* AfitBaseVals_4__29_ */ +{0x0F12, 0x0601}, /* AfitBaseVals_4__30_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__31_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__32_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__33_ */ +{0x0F12, 0x00FF}, /* AfitBaseVals_4__34_ */ +{0x0F12, 0x0B84}, /* AfitBaseVals_4__35_ */ +{0x0F12, 0xFFFF}, /* AfitBaseVals_4__36_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__37_ */ +{0x0F12, 0x050D}, /* AfitBaseVals_4__38_ */ +{0x0F12, 0x1E80}, /* AfitBaseVals_4__39_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__40_ */ +{0x0F12, 0x0A08}, /* AfitBaseVals_4__41_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_4__42_ */ +{0x0F12, 0xFF01}, /* AfitBaseVals_4__43_ */ +{0x0F12, 0x180F}, /* AfitBaseVals_4__44_ */ +{0x0F12, 0x0001}, /* AfitBaseVals_4__45_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__46_ */ +{0x0F12, 0x8003}, /* AfitBaseVals_4__47_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_4__48_ */ +{0x0F12, 0x0080}, /* AfitBaseVals_4__49_ */ +{0x0F12, 0x0180}, /* AfitBaseVals_4__50_ */ +{0x0F12, 0x0108}, /* AfitBaseVals_4__51_ */ +{0x0F12, 0x1E1E}, /* AfitBaseVals_4__52_ */ +{0x0F12, 0x1419}, /* AfitBaseVals_4__53_ */ +{0x0F12, 0x0A0A}, /* AfitBaseVals_4__54_ */ +{0x0F12, 0x0800}, /* AfitBaseVals_4__55_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__56_ */ +{0x0F12, 0x0328}, /* AfitBaseVals_4__57_ */ +{0x0F12, 0x324C}, /* AfitBaseVals_4__58_ */ +{0x0F12, 0x001E}, /* AfitBaseVals_4__59_ */ +{0x0F12, 0x0200}, /* AfitBaseVals_4__60_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_4__61_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_4__62_ */ +{0x0F12, 0x6464}, /* AfitBaseVals_4__63_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_4__64_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_4__65_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_4__66_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__67_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_4__68_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_4__69_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_4__70_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_4__71_ */ +{0x0F12, 0x0103}, /* AfitBaseVals_4__72_ */ +{0x0F12, 0x010C}, /* AfitBaseVals_4__73_ */ +{0x0F12, 0x6464}, /* AfitBaseVals_4__74_ */ +{0x0F12, 0x0F0F}, /* AfitBaseVals_4__75_ */ +{0x0F12, 0x0307}, /* AfitBaseVals_4__76_ */ +{0x0F12, 0x080F}, /* AfitBaseVals_4__77_ */ +{0x0F12, 0x0000}, /* AfitBaseVals_4__78_ */ +{0x0F12, 0x030F}, /* AfitBaseVals_4__79_ */ +{0x0F12, 0x3208}, /* AfitBaseVals_4__80_ */ +{0x0F12, 0x0F1E}, /* AfitBaseVals_4__81_ */ +{0x0F12, 0x020F}, /* AfitBaseVals_4__82_ */ +{0x0F12, 0x0003}, /* AfitBaseVals_4__83_ */ +{0x0F12, 0x7F5E}, /* ConstAfitBaseVals_0_ */ +{0x0F12, 0xFEEE}, /* ConstAfitBaseVals_1_ */ +{0x0F12, 0xD9B7}, /* ConstAfitBaseVals_2_ */ +{0x0F12, 0x0472}, /* ConstAfitBaseVals_3_ */ +{0x0F12, 0x0001}, /* ConstAfitBaseVals_4_ */ + +/**************************************/ +/* 17.JPEG Thumnail Setting */ +/**************************************/ + +/**************************************/ +/* 18.Input Size Setting */ +/**************************************/ + +/**************************************/ +/* 19.Preview & Capture Configration Setting */ +/**************************************/ +/* Preview config[0] 640X480 Recording 25fps */ +{0x002A, 0x01BE}, +{0x0F12, 0x0280}, /* REG_0TC_PCFG_usWidth 500:1280; 280:640 */ +{0x0F12, 0x01E0}, /* REG_0TC_PCFG_usHeight 3C0:960; 1E0:480 */ +{0x0F12, 0x0005}, /* REG_0TC_PCFG_Format 5:YUV422; 7:RAW10 */ +{0x002A, 0x01C8}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uClockInd */ +{0x002A, 0x01C4}, +{0x0F12, 0x0052}, /* REG_0TC_PCFG_PVIMask 52:YUV422, 42:RAW10 */ +{0x002A, 0x01D4}, +{0x0F12, 0x0001}, /* 1b:FR(bin) 2b:Quality(no-bin) */ +{0x002A, 0x01D2}, +{0x0F12, 0x0002}, +{0x002A, 0x01D8}, +{0x0F12, 0x018E}, +{0x002A, 0x01D6}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_usMinFrTimeMsecMult10 */ +{0x002A, 0x01E8}, +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uPrevMirror */ +{0x0F12, 0x0000}, /* REG_0TC_PCFG_uCaptureMirror */ + +/* Preview config[1] 1280X960 7.5fps */ +{0x002A, 0x01EE}, +{0x0F12, 0x0500}, /* 1280 */ +{0x0F12, 0x03C0}, /* 960 */ +{0x0F12, 0x0005}, /* YUV422 */ +{0x002A, 0x01F8}, +{0x0F12, 0x0000}, +{0x002A, 0x01F4}, +{0x0F12, 0x0052}, +{0x002A, 0x0204}, +{0x0F12, 0x0002}, /* 1b: FR (bin) 2b: Quality (no-bin) */ +{0x002A, 0x0202}, +{0x0F12, 0x0001}, /* 0:dynamic; 1:fixed not accurate; 2:fixed accurate*/ +{0x002A, 0x0208}, +{0x0F12, 0x0535}, +{0x002A, 0x0206}, +{0x0F12, 0x0000}, +{0x002A, 0x0218}, +{0x0F12, 0x0000}, /* REG_1TC_PCFG_uPrevMirror */ +{0x0F12, 0x0000}, /* REG_1TC_PCFG_uCaptureMirror */ + +/* Capture config[0] 1280x960 7.5fps */ +/* {0x002A, 0x02AE}, */ +/* {0x0F12, 0x0001}, */ /* Capture mode AE On */ +{0x002A, 0x02B0}, +{0x0F12, 0x0500}, /* REG_0TC_CCFG_usWidth 500:1280; 280:640 */ +{0x0F12, 0x03C0}, /* REG_0TC_CCFG_usHeight 3C0:960; 1E0:480 */ +{0x0F12, 0x0005}, /* REG_0TC_CCFG_Format 5:YUV422; 7:RAW10 */ +{0x002A, 0x02BA}, +{0x0F12, 0x0000}, /* REG_0TC_CCFG_uClockInd */ +{0x002A, 0x02B6}, +{0x0F12, 0x0052}, /* REG_0TC_CCFG_PVIMask 52:YUV422; 42:RAW10 */ +{0x002A, 0x02C6}, +{0x0F12, 0x0002}, +{0x002A, 0x02C4}, +{0x0F12, 0x0002}, +{0x002A, 0x02CA}, +{0x0F12, 0x0535}, +{0x002A, 0x02C8}, +{0x0F12, 0x0000}, /* REG_0TC_CCFG_usMinFrTimeMsecMult10 */ + +/**************************************/ +/* 20.Clock Setting */ +/**************************************/ +/* Input Clock (Mclk) */ +{0x002A, 0x012E}, +{0x0F12, 0x5DC0}, /* REG_TC_IPRM_InClockLSBs */ +{0x0F12, 0x0000}, /* REG_TC_IPRM_InClockMSBs */ +{0x002A, 0x0146}, +{0x0F12, 0x0000}, /* REG_TC_IPRM_UseNPviClocks */ +{0x0F12, 0x0001}, /* REG_TC_IPRM_UseNMipiClocks */ + +/* System Clock & Output clock (Pclk) */ +{0x002A, 0x014C}, +{0x0F12, 0x1B58}, /* REG_TC_IPRM_OpClk4KHz_0 */ +{0x002A, 0x0152}, +{0x0F12, 0x36B0}, /* REG_TC_IPRM_MinOutRate4KHz_0 */ +{0x002A, 0x014E}, +{0x0F12, 0x36B0}, /* REG_TC_IPRM_MaxOutRate4KHz_0 */ +{0x002A, 0x01A8}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActivePrevConfig */ +{0x002A, 0x01B0}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActiveCapConfig */ +{0x002A, 0x019E}, +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreview */ +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreviewChanged */ +{0x002A, 0x0164}, +{0x0F12, 0x0001}, /* REG_TC_IPRM_InitParamsUpdated */ +{0x0028, 0xD000}, +{0x002A, 0x1000}, +{0x0F12, 0x0001}, /* Set host interrupt */ +{0xffff, 0x000a}, + +/* End of Recording init */ +}; + + + +struct s5k8aay_short_t s5k8aay_preview[] = { + +{0xFCFC, 0xD000}, +{0x0028, 0x7000}, +{0x002A, 0x01A8}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActiveCapConfig */ +{0x002A, 0x01A6}, +{0x0F12, 0x0001}, /* REG_TC_GP_NewConfigSync */ +{0x002A, 0x01AA}, +{0x0F12, 0x0001}, /* REG_TC_GP_CapConfigChanged */ +{0x002A, 0x019E}, +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreview */ +{0x0F12, 0x0001}, /* REG_TC_GP_EnablePreviewChanged */ +{0xffff, 0x0096}, /* Delay 150msec */ + +}; + + +struct s5k8aay_short_t s5k8aay_capture[] = { + +{0xFCFC, 0xD000}, +{0x0028, 0x7000}, +{0x002A, 0x01B0}, +{0x0F12, 0x0000}, /* REG_TC_GP_ActiveCapConfig */ +{0x002A, 0x01A6}, +{0x0F12, 0x0001}, /* REG_TC_GP_NewConfigSync */ +{0x002A, 0x01B2}, +{0x0F12, 0x0001}, /* REG_TC_GP_CapConfigChanged */ +{0x002A, 0x01A2}, +{0x0F12, 0x0001}, /* REG_TC_GP_EnableCapture */ +{0x0F12, 0x0001}, /* REG_TC_GP_EnableCaptureChanged */ +{0xffff, 0x0096}, /* Delay 150msec */ + +}; + +/***********************************/ +/* Brightness -4 ~ +4 */ +/***********************************/ + +struct s5k8aay_short_t s5k8aay_brightness_M4[] = { + /* Brightness -4*/ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x018E}, + {0x0F12, 0xFFB0}, /* REG_TC_UserBrightness */ +}; + + +struct s5k8aay_short_t s5k8aay_brightness_M3[] = { + /* Brightness -3*/ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x018E}, + {0x0F12, 0xFFC0}, /* REG_TC_UserBrightness */ +}; + + +struct s5k8aay_short_t s5k8aay_brightness_M2[] = { + /* Brightness -2*/ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x018E}, + {0x0F12, 0xFFD0}, /* REG_TC_UserBrightness */ +}; + + +struct s5k8aay_short_t s5k8aay_brightness_M1[] = { + /* Brightness -1*/ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x018E}, + {0x0F12, 0xFFF0}, /* REG_TC_UserBrightness */ +}; + + +struct s5k8aay_short_t s5k8aay_brightness_default[] = { + /* Brightness 0*/ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x018E}, + {0x0F12, 0x0000}, /* REG_TC_UserBrightness */ +}; + + +struct s5k8aay_short_t s5k8aay_brightness_P1[] = { + /* Brightness +1*/ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x018E}, + {0x0F12, 0x0020}, /* REG_TC_UserBrightness */ +}; + + +struct s5k8aay_short_t s5k8aay_brightness_P2[] = { + /* Brightness +2*/ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x018E}, + {0x0F12, 0x0040}, /* REG_TC_UserBrightness */ +}; + + +struct s5k8aay_short_t s5k8aay_brightness_P3[] = { + /* Brightness +3*/ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x018E}, + {0x0F12, 0x0060}, /* REG_TC_UserBrightness */ +}; + + +struct s5k8aay_short_t s5k8aay_brightness_P4[] = { + /* Brightness +4*/ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x018E}, + {0x0F12, 0x0080}, /* REG_TC_UserBrightness */ +}; + + +struct s5k8aay_short_t s5k8aay_effect_none[] = { + /* Effet None */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x019c}, + {0x0F12, 0x0000}, /* REG_TC_GP_SpecialEffects 00:Normal Mode */ +}; + + +struct s5k8aay_short_t s5k8aay_effect_mono[] = { + /* Mono */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x019c}, + {0x0F12, 0x0001}, /* REG_TC_GP_SpecialEffects 01:Mono Mode */ +}; + + +struct s5k8aay_short_t s5k8aay_effect_negative_mono[] = { + /* Negative & Mono */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x019c}, + {0x0F12, 0x0002}, /* 02:Negative&Mono Mode */ +}; + + +struct s5k8aay_short_t s5k8aay_effect_negative[] = { + /* Negative */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x019c}, + {0x0F12, 0x0003}, /* REG_TC_GP_SpecialEffects 03:Negative Mode */ +}; + + +struct s5k8aay_short_t s5k8aay_effect_sepia[] = { + /* Sepia */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x019c}, + {0x0F12, 0x0004}, /* REG_TC_GP_SpecialEffects 04:Sepia Mode */ +}; + + +struct s5k8aay_short_t s5k8aay_effect_aqua[] = { + /* Aqua */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x019c}, + {0x0F12, 0x0005}, /* REG_TC_GP_SpecialEffects 05:Aqua Mode */ +}; + + +struct s5k8aay_short_t s5k8aay_effect_sketch[] = { + /* Sketch */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x019c}, + {0x0F12, 0x0006}, /* REG_TC_GP_SpecialEffects 06:Sketch Mode */ +}; + +struct s5k8aay_short_t s5k8aay_stream_stop[] = { + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x019E}, + {0x0F12, 0x0000}, /* REG_TC_GP_EnablePreview */ + {0x0F12, 0x0001}, /* REG_TC_GP_EnablePreviewChanged*/ + /* {0xffff, 0x0096}, */ /* 150ms*/ +}; + +struct s5k8aay_short_t s5k8aay_wb_auto[] = { + /* WhiteBalance - Auto(Default) */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x2162}, + {0x0F12, 0x0001}, /* Mon_AAIO_bAWB AWB ON */ +}; + + +struct s5k8aay_short_t s5k8aay_wb_daylight[] = { + /* WhiteBalance - DayLight */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x2162}, + {0x0F12, 0x0000}, /* Mon_AAIO_bAWB AWB OFF */ + {0x002A, 0x03DA}, + {0x0F12, 0x0620}, /* REG_SF_USER_Rgain */ + {0x0F12, 0x0001}, /* REG_SF_USER_RgainChanged */ + {0x0F12, 0x0400}, /* REG_SF_USER_Ggain */ + {0x0F12, 0x0001}, /* REG_SF_USER_GgainChanged */ + {0x0F12, 0x0530}, /* REG_SF_USER_Bgain */ + {0x0F12, 0x0001}, /* REG_SF_USER_BgainChaged */ +}; + + +struct s5k8aay_short_t s5k8aay_wb_cloudy[] = { + /* WhiteBalance - Cloudy */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x2162}, + {0x0F12, 0x0000}, /* Mon_AAIO_bAWB AWB OFF */ + {0x002A, 0x03DA}, + {0x0F12, 0x0850}, /* REG_SF_USER_Rgain */ + {0x0F12, 0x0001}, /* REG_SF_USER_RgainChanged */ + {0x0F12, 0x0400}, /* REG_SF_USER_Ggain */ + {0x0F12, 0x0001}, /* REG_SF_USER_GgainChanged */ + {0x0F12, 0x04E0}, /* REG_SF_USER_Bgain */ + {0x0F12, 0x0001}, /* REG_SF_USER_BgainChaged */ +}; + + +struct s5k8aay_short_t s5k8aay_wb_fluorescent[] = { + /* WhiteBalance - Fluorescent */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x2162}, + {0x0F12, 0x0000}, /* Mon_AAIO_bAWB AWB OFF */ + {0x002A, 0x03DA}, + {0x0F12, 0x0560}, /* REG_SF_USER_Rgain */ + {0x0F12, 0x0001}, /* REG_SF_USER_RgainChanged */ + {0x0F12, 0x0400}, /* REG_SF_USER_Ggain */ + {0x0F12, 0x0001}, /* REG_SF_USER_GgainChanged */ + {0x0F12, 0x0880}, /* REG_SF_USER_Bgain */ + {0x0F12, 0x0001}, /* REG_SF_USER_BgainChaged */ +}; + + +struct s5k8aay_short_t s5k8aay_wb_incandescent[] = { + /* WhiteBalance - Incandescent */ + {0xFCFC, 0xD000}, + {0x0028, 0x7000}, + {0x002A, 0x2162}, + {0x0F12, 0x0000}, /* Mon_AAIO_bAWB AWB OFF */ + {0x002A, 0x03DA}, + {0x0F12, 0x03C0}, /* REG_SF_USER_Rgain */ + {0x0F12, 0x0001}, /* REG_SF_USER_RgainChanged */ + {0x0F12, 0x0400}, /* REG_SF_USER_Ggain */ + {0x0F12, 0x0001}, /* REG_SF_USER_GgainChanged */ + {0x0F12, 0x0980}, /* REG_SF_USER_Bgain */ + {0x0F12, 0x0001}, /* REG_SF_USER_BgainChaged */ +}; +#endif diff --git a/drivers/media/video/msm_zsl/s5k8aay_v4l2.c b/drivers/media/video/msm_zsl/s5k8aay_v4l2.c new file mode 100644 index 00000000000..f549f2edd43 --- /dev/null +++ b/drivers/media/video/msm_zsl/s5k8aay_v4l2.c @@ -0,0 +1,1058 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "msm.h" +#include "s5k8aay.h" + +#include "msm.h" +#include "msm_ispif.h" + +/*#define CONFIG_LOAD_FILE */ + +#ifdef CONFIG_LOAD_FILE + +#include +#include +#include +#include +#include + +static char *s5k8aay_regs_table; +static int s5k8aay_regs_table_size; +static int s5k8aay_write_regs_from_sd(char *name); +static int s5k8aay_i2c_write_multi(unsigned short addr, unsigned int w_data); + + + +#endif + +#define S5K8_WRT_LIST(A) s5k8_i2c_wrt_list(A, (sizeof(A) / sizeof(A[0])), #A); + +#define CAM_5M_RST 107 +#define CAM_5M_ISP_INIT 4 +#define CAM_1_3M_RST 76 +#define CAM_1_3M_EN 18 +#define CAM_MCLK 5 +#define CAM_I2C_SDA 20 +#define CAM_I2C_SCL 21 +#define CAM_REV ((system_rev <= 1) ? 0 : 1) +#ifdef CAM_REV + #include "s5k8aay_regs_v2.h" +#else + #include "s5k8aay_regs.h" +#endif + +struct s5k8aay_work { + struct work_struct work; +}; + +static struct s5k8aay_work *s5k8aay_sensorw; +static struct i2c_client *s5k8aay_client; + +struct s5k8aay_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + uint32_t sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + uint16_t fps; + int16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + enum s5k8aay_resolution_t prev_res; + enum s5k8aay_resolution_t pict_res; + enum s5k8aay_resolution_t curr_res; + enum s5k8aay_test_mode_t set_test; + unsigned short imgaddr; + + struct v4l2_subdev *sensor_dev; + struct s5k8aay_format *fmt; +}; + +struct s5k8aay_ctrl { + const struct msm_camera_sensor_info *sensordata; + + struct s5k8aay_userset settings; + struct v4l2_subdev *sensor_dev; + + int op_mode; + int dtp_mode; + int app_mode; + int vtcall_mode; + int started; + int dtpTest; + int isCapture; +}; + +static unsigned int config_csi2; +static struct s5k8aay_ctrl *s5k8aay_ctrl; + +struct s5k8aay_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; + + +#ifdef CONFIG_LOAD_FILE + +void s5k8aay_regs_table_init(void) +{ + struct file *filp; + char *dp; + long lsize; + loff_t pos; + int ret; + + /*Get the current address space */ + mm_segment_t fs = get_fs(); + + CAM_DEBUG("%s %d\n", __func__, __LINE__); + + /*Set the current segment to kernel data segment */ + set_fs(get_ds()); + + filp = filp_open("/mnt/sdcard/s5k8aay_regs.h", O_RDONLY, 0); + + if (IS_ERR_OR_NULL(filp)) { + cam_err("file open error\n"); + return ; + } + + lsize = filp->f_path.dentry->d_inode->i_size; + CAM_DEBUG("size : %ld\n", lsize); + dp = vmalloc(lsize); + if (dp == NULL) { + cam_err("Out of Memory"); + filp_close(filp, current->files); + } + + pos = 0; + memset(dp, 0, lsize); + ret = vfs_read(filp, (char __user *)dp, lsize, &pos); + if (ret != lsize) { + cam_err("Failed to read file ret = %d\n", ret); + vfree(dp); + filp_close(filp, current->files); + } + /*close the file*/ + filp_close(filp, current->files); + + /*restore the previous address space*/ + set_fs(fs); + + s5k8aay_regs_table = dp; + + s5k8aay_regs_table_size = lsize; + + *((s5k8aay_regs_table + s5k8aay_regs_table_size) - 1) = '\0'; + + CAM_DEBUG("s5k8aay_reg_table_init"); + + return; +} +#endif + +#ifdef CONFIG_LOAD_FILE + +void s5k8aay_regs_table_exit(void) +{ + CAM_DEBUG("%s %d", __func__, __LINE__); + if (s5k8aay_regs_table) { + vfree(s5k8aay_regs_table); + s5k8aay_regs_table = NULL; + } +} + +#endif + +#ifdef CONFIG_LOAD_FILE +static int s5k8aay_write_regs_from_sd(char *name) +{ + char *start, *end, *reg, *size; + unsigned short addr; + unsigned int len, value; + char reg_buf[7], data_buf1[5], data_buf2[7]; + + + *(reg_buf + 6) = '\0'; + *(data_buf1 + 4) = '\0'; + *(data_buf2 + 6) = '\0'; + + CAM_DEBUG("s5k8aay_regs_table_write start!\n"); + CAM_DEBUG("E string = %s\n", name); + + start = strstr(s5k8aay_regs_table, name); + end = strstr(start, "};"); + + while (1) { + /* Find Address */ + reg = strstr(start, "{0x"); + + if ((reg == NULL) || (reg > end)) + break; + /* Write Value to Address */ + if (reg != NULL) { + memcpy(reg_buf, (reg + 1), 6); + memcpy(data_buf2, (reg + 9), 6); + + size = strstr(data_buf2, ","); + if (size) { /* 1 byte write */ + memcpy(data_buf1, (reg + 9), 4); + kstrtoint(reg_buf, 16, &addr); + kstrtoint(data_buf1, 16, &value); + + if (reg) + start = (reg + 12); + } else {/* 2 byte write */ + kstrtoint(reg_buf, 16, &addr); + kstrtoint(data_buf2, 16, &value); + if (reg) + start = (reg + 14); + } + size = NULL; + + CAM_DEBUG("addr 0x%04x, value 0x%04x\n", addr, value); + + if (addr == 0xFFFF) + msleep(value); + else + s5k8aay_i2c_write_multi(addr, value); + + } + } + CAM_DEBUG("s5k8aay_regs_table_write end!"); + + return 0; +} + +#endif + +static DECLARE_WAIT_QUEUE_HEAD(s5k8aay_wait_queue); + +/** + * s5k8aay_i2c_read_multi: Read (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * @r_data: buffer where data is read + * @r_len: number of bytes to read + * + * Returns 0 on success, <0 on error + */ + +static int s5k8aay_i2c_read_multi(unsigned short subaddr, unsigned long *data) +{ + unsigned char buf[4]; + struct i2c_msg msg = {s5k8aay_client->addr, 0, 2, buf}; + + int err = 0; + + if (!s5k8aay_client->adapter) + return -EIO; + + buf[0] = subaddr >> 8; + buf[1] = subaddr & 0xFF; + + err = i2c_transfer(s5k8aay_client->adapter, &msg, 1); + if (unlikely(err < 0)) + return -EIO; + + msg.flags = I2C_M_RD; + msg.len = 4; + + err = i2c_transfer(s5k8aay_client->adapter, &msg, 1); + if (unlikely(err < 0)) + return -EIO; + /* + * Data comes in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + + *data = *(unsigned long *)(&buf); + + return err; +} + + +/** + * s5k8aay_i2c_read: Read (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @data: data to be read + * + * Returns 0 on success, <0 on error + */ +static int s5k8aay_i2c_read(unsigned short subaddr, unsigned short *data) +{ + unsigned char buf[2]; + struct i2c_msg msg = {s5k8aay_client->addr, 0, 2, buf}; + + int err = 0; + + if (!s5k8aay_client->adapter) + return -EIO; + + buf[0] = subaddr >> 8; + buf[1] = subaddr & 0xFF; + + err = i2c_transfer(s5k8aay_client->adapter, &msg, 1); + if (unlikely(err < 0)) + return -EIO; + + msg.flags = I2C_M_RD; + + err = i2c_transfer(s5k8aay_client->adapter, &msg, 1); + if (unlikely(err < 0)) + return -EIO; + /* + * Data comes in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + + *data = *(unsigned short *)(&buf); + + return err; +} + +/** + * s5k8aa_i2c_write_multi: Write (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * + * Returns 0 on success, <0 on error + */ +static int s5k8aay_i2c_write_multi(unsigned short addr, unsigned int w_data) +{ + unsigned char buf[4]; + struct i2c_msg msg = {s5k8aay_client->addr, 0, 4, buf}; + + int retry_count = 5; + int err = 0; + + if (!s5k8aay_client->adapter) + return -EIO; + + buf[0] = addr >> 8; + buf[1] = addr & 0xFF; + buf[2] = w_data >> 8; + buf[3] = w_data & 0xFF; + /* + * Data should be written in Little Endian in parallel mode; So there + * is no need for byte swapping here + */ + + while (retry_count--) { + err = i2c_transfer(s5k8aay_client->adapter, &msg, 1); + if (likely(err == 1)) + break; + } + return (err == 1) ? 0 : -EIO; +} + +static int s5k8_i2c_wrt_list(struct s5k8aay_short_t regs[], + int size, char *name) +{ +#ifdef CONFIG_LOAD_FILE + s5k8aay_write_regs_from_sd(name); +#else + int err = 0; + int i = 0; + + CAM_DEBUG(""); + + if (!s5k8aay_client->adapter) { + cam_err("Can't search i2c client adapter"); + return -EIO; + } + + for (i = 0; i < size; i++) { + if (regs[i].subaddr == 0xFFFF) { + msleep(regs[i].value); + CAM_DEBUG("delay = 0x%04x, value = 0x%04x\n", + regs[i].subaddr, regs[i].value); + } else { + err = s5k8aay_i2c_write_multi(regs[i].subaddr, + regs[i].value); + if (unlikely(err < 0)) { + cam_err("register set failed"); + return -EIO; + } + } + } +#endif + + return 0; +} + + +#ifdef FACTORY_TEST +struct class *sec_class; +struct device *s5k8aay_dev; + +static ssize_t cameratype_file_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) { + char sensor_info[30] = "s5k8aay"; + return snprintf(buf, "%s\n", sensor_info); +} + +static ssize_t cameratype_file_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) { + /*Reserved*/ + return size; +} + +static struct device_attribute s5k8aay_camtype_attr = { + .attr = { + .name = "camtype", + .mode = (S_IRUGO | S_IWUGO)}, + .show = cameratype_file_cmd_show, + .store = cameratype_file_cmd_store +}; + +static ssize_t cameraflash_file_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) { + /*Reserved*/ + return 0; +} + +static ssize_t cameraflash_file_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) { + int value; + sscanf(buf, "%d", &value); + + if (value == 0) { + CAM_DEBUG("[Factory flash]OFF"); + s5k8aay_set_flash(MOVIE_FLASH, 0); + } else { + CAM_DEBUG("[Factory flash]ON"); + s5k8aay_set_flash(MOVIE_FLASH, 1); + } + return size; +} + +static struct device_attribute s5k8aay_cameraflash_attr = { + .attr = { + .name = "cameraflash", + .mode = (S_IRUGO | S_IWUGO)}, + .show = cameraflash_file_cmd_show, + .store = cameraflash_file_cmd_store +}; +#endif + +void s5k8aay_set_preview(void) +{ + +} + +void s5k8aay_set_capture(void) +{ + CAM_DEBUG(""); + S5K8_WRT_LIST(s5k8aay_capture); +} + +static int32_t s5k8aay_sensor_setting(int update_type, int rt) +{ + CAM_DEBUG("Start"); + + int32_t rc = 0; + int temp = 0; + struct msm_camera_csid_params s5k8aay_csid_params; + struct msm_camera_csiphy_params s5k8aay_csiphy_params; + switch (update_type) { + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) + /* Add some condition statements */ + break; + + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + CAM_DEBUG("UPDATE_PERIODIC"); + + v4l2_subdev_notify(s5k8aay_ctrl->sensor_dev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_OFF_IMMEDIATELY)); + + /* stop streaming */ + S5K8_WRT_LIST(s5k8aay_stream_stop); + msleep(100); + + if (config_csi2 == 0) { + struct msm_camera_csid_vc_cfg + s5k8aay_vccfg[] = { + {0, 0x1E, CSI_DECODE_8BIT}, + /* {0, CSI_RAW10, CSI_DECODE_10BIT}, */ + {1, CSI_EMBED_DATA, CSI_DECODE_8BIT}, + }; + s5k8aay_csid_params.lane_cnt = 1; + s5k8aay_csid_params.lane_assign = 0xe4; + s5k8aay_csid_params.lut_params.num_cid = + ARRAY_SIZE(s5k8aay_vccfg); + s5k8aay_csid_params.lut_params.vc_cfg = + &s5k8aay_vccfg[0]; + s5k8aay_csiphy_params.lane_cnt = 1; + if (system_rev <= 1) + s5k8aay_csiphy_params.settle_cnt = 0x07; + else + s5k8aay_csiphy_params.settle_cnt = 0x1B; + v4l2_subdev_notify(s5k8aay_ctrl->sensor_dev, + NOTIFY_CSID_CFG, &s5k8aay_csid_params); + v4l2_subdev_notify(s5k8aay_ctrl->sensor_dev, + NOTIFY_CID_CHANGE, NULL); + mb(); + v4l2_subdev_notify(s5k8aay_ctrl->sensor_dev, + NOTIFY_CSIPHY_CFG, &s5k8aay_csiphy_params); + mb(); + /*s5k8aay_delay_msecs_stdby*/ + msleep(350); + config_csi2 = 1; + } + if (rc < 0) + return rc; + + v4l2_subdev_notify(s5k8aay_ctrl->sensor_dev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_ON_FRAME_BOUNDARY)); + + /*start stream*/ + S5K8_WRT_LIST(s5k8aay_preview); + msleep(100); + } + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static int32_t s5k8aay_video_config(int mode) +{ + CAM_DEBUG("=== Start ==="); + + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + /* if (s5k8aay_ctrl->prev_res == QTR_SIZE) */ + rt = RES_PREVIEW; + /* else */ + /* rt = RES_CAPTURE; */ + + if (s5k8aay_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; +/* s5k8aay_ctrl->curr_res = s5k8aay_ctrl->prev_res; + s5k8aay_ctrl->sensormode = mode; */ + return rc; +} + +static long s5k8aay_set_sensor_mode(int mode) +{ + CAM_DEBUG("=== Start ==="); + + switch (mode) { + case SENSOR_PREVIEW_MODE: + case SENSOR_VIDEO_MODE: + if (s5k8aay_ctrl->isCapture == 1) { + s5k8aay_ctrl->isCapture = 0; + S5K8_WRT_LIST(s5k8aay_preview); + } + s5k8aay_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + s5k8aay_set_capture(); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + s5k8aay_set_capture(); + break; + default: + return 0; + } + return 0; +} + +static int s5k8aay_sensor_pre_init(const struct msm_camera_sensor_info *data) +{ + CAM_DEBUG("== Start =="); + + int rc = 0; + +#ifndef CONFIG_LOAD_FILE + rc = S5K8_WRT_LIST(s5k8aay_common); + if (rc < 0) + CAM_DEBUG("Fail!"); +#endif + usleep(10*1000); + + return rc; +} + + +static int s5k8aay_sensor_init_probe(const struct msm_camera_sensor_info *data) +{ + CAM_DEBUG("=== Start ==="); + + int rc = 0; + int temp = 0; + int status = 0; + int count = 0; + gpio_tlmm_config(GPIO_CFG(CAM_1_3M_RST, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + gpio_tlmm_config(GPIO_CFG(CAM_1_3M_EN, 0, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), GPIO_CFG_ENABLE); + + gpio_set_value_cansleep(CAM_1_3M_RST, 0); + temp = gpio_get_value(CAM_1_3M_RST); + CAM_DEBUG("CAM_1_3M_RST : %d", temp); + + gpio_set_value_cansleep(CAM_1_3M_EN, 0); + temp = gpio_get_value(CAM_1_3M_EN); + CAM_DEBUG("CAM_1_3M_EN : %d", temp); + + data->sensor_platform_info->sensor_power_on(1); + usleep(1000); + + gpio_set_value_cansleep(CAM_1_3M_EN, 1); + temp = gpio_get_value(CAM_1_3M_EN); + CAM_DEBUG("CAM_1_3M_EN : %d", temp); + usleep(1000); + + gpio_tlmm_config(GPIO_CFG(CAM_MCLK, 1, GPIO_CFG_OUTPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), GPIO_CFG_ENABLE); + msm_camio_clk_rate_set(24000000); + usleep(10*1000); + + gpio_set_value_cansleep(CAM_1_3M_RST, 1); + temp = gpio_get_value(CAM_1_3M_RST); + CAM_DEBUG("CAM_1_3M_RST : %d", temp); + + usleep(100*1000); + + S5K8_WRT_LIST(s5k8aay_common); + S5K8_WRT_LIST(s5k8aay_preview); + + return rc; +} + +int s5k8aay_sensor_init(const struct msm_camera_sensor_info *data) +{ + CAM_DEBUG("=== Start ==="); + + int rc = 0; +/* s5k8aay_ctrl = kzalloc(sizeof(struct s5k8aay_ctrl), GFP_KERNEL); */ + if (!s5k8aay_ctrl) { + cam_err("Failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + if (data) + s5k8aay_ctrl->sensordata = data; + + config_csi2 = 0; +#ifdef CONFIG_LOAD_FILE + s5k8aay_regs_table_init(); +#endif + + rc = s5k8aay_sensor_init_probe(data); + if (rc < 0) { + cam_err("Failed!"); + goto init_fail; + } + +init_done: + return rc; + +init_fail: + kfree(s5k8aay_ctrl); + return rc; +} + +static int s5k8aay_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&s5k8aay_wait_queue); + return 0; +} + +static void s5k8aay_check_dataline(int val) +{ + if (val) { + printk(KERN_DEBUG "DTP ON\n"); + s5k8aay_ctrl->dtpTest = 1; + + } else { + printk(KERN_DEBUG "DTP OFF\n"); + s5k8aay_ctrl->dtpTest = 0; + } +} + +static int s5k8aay_set_effect(int effect) +{ + printk(KERN_DEBUG "[s5k8aay] %s : %d\n", __func__, effect); + + switch (effect) { + case CAMERA_EFFECT_OFF: + S5K8_WRT_LIST(s5k8aay_effect_none); + break; + + case CAMERA_EFFECT_MONO: + S5K8_WRT_LIST(s5k8aay_effect_mono); + break; + + case CAMERA_EFFECT_NEGATIVE: + S5K8_WRT_LIST(s5k8aay_effect_negative); + break; + + case CAMERA_EFFECT_SEPIA: + S5K8_WRT_LIST(s5k8aay_effect_sepia); + break; + + case CAMERA_EFFECT_WHITEBOARD: + S5K8_WRT_LIST(s5k8aay_effect_sketch); + break; + + default: + printk(KERN_DEBUG "[s5k8aay] default effect\n"); + S5K8_WRT_LIST(s5k8aay_effect_none); + return 0; + } + + return 0; +} + +static int s5k8aay_set_whitebalance(int wb) +{ + switch (wb) { + case CAMERA_WHITE_BALANCE_AUTO: + S5K8_WRT_LIST(s5k8aay_wb_auto); + break; + + case CAMERA_WHITE_BALANCE_INCANDESCENT: + S5K8_WRT_LIST(s5k8aay_wb_incandescent); + break; + + case CAMERA_WHITE_BALANCE_FLUORESCENT: + S5K8_WRT_LIST(s5k8aay_wb_fluorescent); + break; + + case CAMERA_WHITE_BALANCE_DAYLIGHT: + S5K8_WRT_LIST(s5k8aay_wb_daylight); + break; + + case CAMERA_WHITE_BALANCE_CLOUDY_DAYLIGHT: + S5K8_WRT_LIST(s5k8aay_wb_cloudy); + break; + + default: + printk(KERN_DEBUG "[s5k8aay] unexpected WB mode %s/%d\n", + __func__, __LINE__); + return 0; + } + return 0; +} + +static void s5k8aay_set_ev(int ev) +{ + printk(KERN_DEBUG "[s5k8aay] %s : %d\n", __func__, ev); + + switch (ev) { + case CAMERA_EV_M2: + S5K8_WRT_LIST(s5k8aay_brightness_M4); + break; + + case CAMERA_EV_M1: + S5K8_WRT_LIST(s5k8aay_brightness_M2); + break; + + case CAMERA_EV_DEFAULT: + S5K8_WRT_LIST(s5k8aay_brightness_default); + break; + + case CAMERA_EV_P1: + S5K8_WRT_LIST(s5k8aay_brightness_P2); + break; + + case CAMERA_EV_P2: + S5K8_WRT_LIST(s5k8aay_brightness_P4); + break; + + default: + printk(KERN_DEBUG "[s5k8aay] unexpected ev mode %s/%d\n", + __func__, __LINE__); + break; + } +} +void sensor_native_control_front(void __user *arg) +{ + struct ioctl_native_cmd ctrl_info; + + printk(KERN_DEBUG "[s5k8aa] %s/%d\n", __func__, __LINE__); + + if (copy_from_user((void *)&ctrl_info, + (const void *)arg, sizeof(ctrl_info))) + printk(KERN_DEBUG + "[s5k8aa] %s fail copy_from_user!\n", __func__); + + printk(KERN_DEBUG "[s5k8aa] %d %d %d %d %d\n", + ctrl_info.mode, ctrl_info.address, ctrl_info.value_1, + ctrl_info.value_2, ctrl_info.value_3); + + switch (ctrl_info.mode) { + case EXT_CAM_EV: + s5k8aay_set_ev(ctrl_info.value_1); + break; + + case EXT_CAM_EFFECT: + s5k8aay_set_effect(ctrl_info.value_1); + break; + + case EXT_CAM_WB: + s5k8aay_set_whitebalance(ctrl_info.value_1); + break; + + case EXT_CAM_DTP_TEST: + s5k8aay_check_dataline(ctrl_info.value_1); + break; + + default: + printk(KERN_DEBUG "[s5k8aa] default mode\n"); + break; + } + + if (copy_to_user((void *)arg, + (const void *)&ctrl_info, sizeof(ctrl_info))) + printk(KERN_DEBUG "[s5k8aa] %s fail copy_to_user!\n", __func__); +} + +int s5k8aay_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cfg_data; + long rc = 0; + + if (copy_from_user(&cfg_data, (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + CAM_DEBUG(" cfgtype = %d, mode = %d\n", + cfg_data.cfgtype, cfg_data.mode); + switch (cfg_data.cfgtype) { + case CFG_SET_MODE: + rc = s5k8aay_set_sensor_mode(cfg_data.mode); + break; + + case CFG_SET_EFFECT: +/* rc = s5k8aay_set_effect(cfg_data.mode, cfg_data.cfg.effect); */ + break; + + case CFG_GET_AF_MAX_STEPS: + default: + rc = 0; + cam_err(" Invalid cfgtype = %d", cfg_data.cfgtype); + break; + } + return rc; +} + +int s5k8aay_sensor_release(void) +{ + int rc = 0; + + CAM_DEBUG("=== Start ==="); + +#ifdef CONFIG_LOAD_FILE + s5k8aay_regs_table_exit(); +#endif + gpio_set_value_cansleep(CAM_1_3M_RST, 0); + usleep(1000); + gpio_set_value_cansleep(CAM_1_3M_EN, 0); + usleep(1000); + s5k8aay_ctrl->sensordata->sensor_platform_info->sensor_power_off(1); + return rc; +} + +static int s5k8aay_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CAM_DEBUG("=== Start ==="); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + cam_err("=== i2c Probe error ==="); + rc = -ENOTSUPP; + goto probe_failure; + } + + s5k8aay_sensorw = + kzalloc(sizeof(struct s5k8aay_work), GFP_KERNEL); + + if (!s5k8aay_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, s5k8aay_sensorw); + s5k8aay_init_client(client); + s5k8aay_client = client; + + CAM_DEBUG("s5k8aay_probe succeeded!"); + + return 0; + +probe_failure: + kfree(s5k8aay_sensorw); + s5k8aay_sensorw = NULL; + cam_err("s5k8aay_probe failed!"); + return rc; +} + +static const struct i2c_device_id s5k8aay_i2c_id[] = { + { "s5k8aay", 0}, + { }, +}; + +static struct i2c_driver s5k8aay_i2c_driver = { + .id_table = s5k8aay_i2c_id, + .probe = s5k8aay_i2c_probe, + .remove = __exit_p(s5k8aay_i2c_remove), + .driver = { + .name = "s5k8aay", + }, +}; + +static int s5k8aay_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) { + CAM_DEBUG("== Start =="); + int rc = i2c_add_driver(&s5k8aay_i2c_driver); + + if (rc < 0 || s5k8aay_client == NULL) { + CAM_DEBUG("rc = %d, s5k8aay_client = %d", rc, + s5k8aay_client); + + rc = -ENOTSUPP; + goto probe_done; + } + + msm_camio_clk_rate_set(24000000); + + s->s_init = s5k8aay_sensor_init; + s->s_release = s5k8aay_sensor_release; + s->s_config = s5k8aay_sensor_config; + s->s_camera_type = FRONT_CAMERA_2D; + s->s_mount_angle = 270; /* HC - 0/180, GB - 90/270 */ + + +probe_done: + CAM_DEBUG("=== DONE ==="); + return rc; +} + +static struct s5k8aay_format s5k8aay_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static int s5k8aay_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) { + CAM_DEBUG("Index is %d", index); + if ((unsigned int)index >= ARRAY_SIZE(s5k8aay_subdev_info)) + return -EINVAL; + + *code = s5k8aay_subdev_info[index].code; + return 0; +} + +static struct v4l2_subdev_core_ops s5k8aay_subdev_core_ops; +static struct v4l2_subdev_video_ops s5k8aay_subdev_video_ops = { + .enum_mbus_fmt = s5k8aay_enum_fmt, +}; + +static struct v4l2_subdev_ops s5k8aay_subdev_ops = { + .core = &s5k8aay_subdev_core_ops, + .video = &s5k8aay_subdev_video_ops, +}; + +static int s5k8aay_sensor_probe_cb(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) { + + int rc = 0; + CAM_DEBUG("=== Start ==="); + rc = s5k8aay_sensor_probe(info, s); + + if (rc < 0) + return rc; + + s5k8aay_ctrl = kzalloc(sizeof(struct s5k8aay_ctrl_t), GFP_KERNEL); + if (!s5k8aay_ctrl) { + cam_err("s5k8aay_sensor_probe failed!"); + return -ENOMEM; + } + + /* probe is successful, init a v4l2 subdevice */ + CAM_DEBUG("going into v4l2_i2c_subdev_init"); + if (sdev) { + v4l2_i2c_subdev_init(sdev, s5k8aay_client, &s5k8aay_subdev_ops); + s5k8aay_ctrl->sensor_dev = sdev; + } + else + cam_err("sdev is null in probe_cb"); + + return rc; +} + +static int __s5k8aay_probe(struct platform_device *pdev) +{ + CAM_DEBUG("=== s5k8aay probe ==="); + + return msm_sensor_register(pdev, s5k8aay_sensor_probe_cb); +} + +static struct platform_driver msm_camera_driver = { + .probe = __s5k8aay_probe, + .driver = { + .name = "msm_camera_s5k8aay", + .owner = THIS_MODULE, + }, +}; + +static int __init s5k8aay_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(s5k8aay_init); diff --git a/drivers/media/video/msm_zsl/sensors/Makefile b/drivers/media/video/msm_zsl/sensors/Makefile new file mode 100644 index 00000000000..cb1d40a5e13 --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/Makefile @@ -0,0 +1,10 @@ +GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) +EXTRA_CFLAGS += -Idrivers/media/video/msm_zsl +EXTRA_CFLAGS += -Idrivers/media/video/msm_zsl/io +EXTRA_CFLAGS += -Idrivers/media/video/msm_zsl/csi +obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o +obj-$(CONFIG_IMX074) += imx074_v4l2.o +obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o +obj-$(CONFIG_OV2720) += ov2720.o +obj-$(CONFIG_S5C73M3) += s5c73m3.o s5c73m3_spi.o +obj-$(CONFIG_S5K6A3YX) += s5k6a3yx.o diff --git a/drivers/media/video/msm_zsl/sensors/imx074_v4l2.c b/drivers/media/video/msm_zsl/sensors/imx074_v4l2.c new file mode 100644 index 00000000000..f721441b510 --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/imx074_v4l2.c @@ -0,0 +1,371 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_sensor.h" +#define SENSOR_NAME "imx074" +#define PLATFORM_DRIVER_NAME "msm_camera_imx074" +#define imx074_obj imx074_##obj + +DEFINE_MUTEX(imx074_mut); +static struct msm_sensor_ctrl_t imx074_s_ctrl; + +static struct msm_camera_i2c_reg_conf imx074_start_settings[] = { + {0x0100, 0x01}, +}; + +static struct msm_camera_i2c_reg_conf imx074_stop_settings[] = { + {0x0100, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf imx074_groupon_settings[] = { + {0x104, 0x01}, +}; + +static struct msm_camera_i2c_reg_conf imx074_groupoff_settings[] = { + {0x104, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf imx074_prev_settings[] = { + {0x0307, 0x2D}, /*pll_multiplier*/ + {0x0340, 0x06}, /*frame_length_lines_hi*/ + {0x0341, 0x2D}, /*frame_length_lines_lo*/ + {0x0342, 0x11}, /*line_length_pclk_hi*/ + {0x0343, 0x78}, /*line_length_pclk_lo*/ + {0x0347, 0x00}, /*y_addr_start*/ + {0x034b, 0x2F}, /*y_add_end*/ + {0x034c, 0x08}, /*x_output_size_msb*/ + {0x034d, 0x38}, /*x_output_size_lsb*/ + {0x034e, 0x06}, /*y_output_size_msb*/ + {0x034f, 0x18}, /*y_output_size_lsb*/ + {0x0381, 0x01}, /*x_even_inc*/ + {0x0383, 0x03}, /*x_odd_inc*/ + {0x0385, 0x01}, /*y_even_inc*/ + {0x0387, 0x03}, /*y_odd_inc*/ + {0x3001, 0x80}, /*hmodeadd*/ + {0x3016, 0x16}, /*vmodeadd*/ + {0x3069, 0x24}, /*vapplinepos_start*/ + {0x306b, 0x53}, /*vapplinepos_end*/ + {0x3086, 0x00}, /*shutter*/ + {0x30e8, 0x80}, /*haddave*/ + {0x3301, 0x83}, /*lanesel*/ +}; + +static struct msm_camera_i2c_reg_conf imx074_snap_settings[] = { + {0x0307, 0x26}, /*pll_multiplier*/ + {0x0340, 0x0C}, /*frame_length_lines_hi*/ + {0x0341, 0x90}, /*frame_length_lines_lo*/ + {0x0342, 0x11}, /*line_length_pclk_hi*/ + {0x0343, 0x78}, /*line_length_pclk_lo*/ + {0x0347, 0x00}, /*y_addr_start*/ + {0x034b, 0x2F}, /*y_add_end*/ + {0x034c, 0x10}, /*x_output_size_msb*/ + {0x034d, 0x70}, /*x_output_size_lsb*/ + {0x034e, 0x0c}, /*y_output_size_msb*/ + {0x034f, 0x30}, /*y_output_size_lsb*/ + {0x0381, 0x01}, /*x_even_inc*/ + {0x0383, 0x01}, /*x_odd_inc*/ + {0x0385, 0x01}, /*y_even_inc*/ + {0x0387, 0x01}, /*y_odd_inc*/ + {0x3001, 0x00}, /*hmodeadd*/ + {0x3016, 0x06}, /*vmodeadd*/ + {0x3069, 0x24}, /*vapplinepos_start*/ + {0x306b, 0x53}, /*vapplinepos_end*/ + {0x3086, 0x00}, /*shutter*/ + {0x30e8, 0x00}, /*haddave*/ + {0x3301, 0x03}, /*lanesel*/ +}; + +static struct msm_camera_i2c_reg_conf imx074_recommend_settings[] = { + {0x0305, 0x02}, + {0x302b, 0x4B}, + {0x3024, 0x03}, + {0x0101, 0x00}, + {0x300a, 0x80}, + {0x3014, 0x08}, + {0x3015, 0x37}, + {0x301c, 0x01}, + {0x302c, 0x05}, + {0x3031, 0x26}, + {0x3041, 0x60}, + {0x3051, 0x24}, + {0x3053, 0x34}, + {0x3057, 0xc0}, + {0x305c, 0x09}, + {0x305d, 0x07}, + {0x3060, 0x30}, + {0x3065, 0x00}, + {0x30aa, 0x08}, + {0x30ab, 0x1c}, + {0x30b0, 0x32}, + {0x30b2, 0x83}, + {0x30d3, 0x04}, + {0x3106, 0x78}, + {0x310c, 0x82}, + {0x3304, 0x05}, + {0x3305, 0x04}, + {0x3306, 0x11}, + {0x3307, 0x02}, + {0x3308, 0x0c}, + {0x3309, 0x06}, + {0x330a, 0x08}, + {0x330b, 0x04}, + {0x330c, 0x08}, + {0x330d, 0x06}, + {0x330f, 0x01}, + {0x3381, 0x00}, +}; + +static struct v4l2_subdev_info imx074_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static struct msm_camera_i2c_conf_array imx074_init_conf[] = { + {&imx074_recommend_settings[0], + ARRAY_SIZE(imx074_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA} +}; + +static struct msm_camera_i2c_conf_array imx074_confs[] = { + {&imx074_snap_settings[0], + ARRAY_SIZE(imx074_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}, + {&imx074_prev_settings[0], + ARRAY_SIZE(imx074_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}, +}; + +static struct msm_sensor_output_info_t imx074_dimensions[] = { + { + .x_output = 0x1070, + .y_output = 0xC30, + .line_length_pclk = 0x1178, + .frame_length_lines = 0xC90, + .vt_pixel_clk = 182400000, + .op_pixel_clk = 182400000, + .binning_factor = 1, + }, + { + .x_output = 0x838, + .y_output = 0x618, + .line_length_pclk = 0x1178, + .frame_length_lines = 0x62D, + .vt_pixel_clk = 216000000, + .op_pixel_clk = 216000000, + .binning_factor = 2, + }, +}; + +static struct msm_camera_csid_vc_cfg imx074_cid_cfg[] = { + {0, CSI_RAW10, CSI_DECODE_10BIT}, + {1, CSI_EMBED_DATA, CSI_DECODE_8BIT}, +}; + +static struct msm_camera_csi2_params imx074_csi_params = { + .csid_params = { + .lane_assign = 0xe4, + .lane_cnt = 4, + .lut_params = { + .num_cid = 2, + .vc_cfg = imx074_cid_cfg, + }, + }, + .csiphy_params = { + .lane_cnt = 4, + .settle_cnt = 0x1B, + }, +}; + +static struct msm_camera_csi2_params *imx074_csi_params_array[] = { + &imx074_csi_params, + &imx074_csi_params, +}; + +static struct msm_sensor_output_reg_addr_t imx074_reg_addr = { + .x_output = 0x34C, + .y_output = 0x34E, + .line_length_pclk = 0x342, + .frame_length_lines = 0x340, +}; + +static struct msm_sensor_id_info_t imx074_id_info = { + .sensor_id_reg_addr = 0x0, + .sensor_id = 0x0074, +}; + +static struct msm_sensor_exp_gain_info_t imx074_exp_gain_info = { + .coarse_int_time_addr = 0x202, + .global_gain_addr = 0x204, + .vert_offset = 3, +}; + +static int imx074_sensor_config(void __user *argp) +{ + return msm_sensor_config(&imx074_s_ctrl, argp); +} + +static struct sensor_calib_data imx074_calib_data; + +static int imx074_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + return msm_sensor_open_init(&imx074_s_ctrl, data); +} + +static int imx074_sensor_release(void) +{ + return msm_sensor_release(&imx074_s_ctrl); +} + +static const struct i2c_device_id imx074_i2c_id[] = { + {SENSOR_NAME, (kernel_ulong_t)&imx074_s_ctrl}, + { } +}; + +static struct i2c_driver imx074_i2c_driver = { + .id_table = imx074_i2c_id, + .probe = msm_sensor_i2c_probe, + .driver = { + .name = SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client imx074_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static struct msm_camera_i2c_client imx074_eeprom_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +static struct msm_camera_eeprom_read_t imx074_eeprom_read_tbl[] = { + {0x10, &imx074_calib_data.r_over_g, 2, 1}, + {0x12, &imx074_calib_data.b_over_g, 2, 1}, + {0x14, &imx074_calib_data.gr_over_gb, 2, 1}, +}; + +static struct msm_camera_eeprom_data_t imx074_eeprom_data_tbl[] = { + {&imx074_calib_data, sizeof(struct sensor_calib_data)}, +}; + +static struct msm_camera_eeprom_client imx074_eeprom_client = { + .i2c_client = &imx074_eeprom_i2c_client, + .i2c_addr = 0xA4, + + .func_tbl = { + .eeprom_set_dev_addr = NULL, + .eeprom_init = msm_camera_eeprom_init, + .eeprom_release = msm_camera_eeprom_release, + .eeprom_get_data = msm_camera_eeprom_get_data, + }, + + .read_tbl = imx074_eeprom_read_tbl, + .read_tbl_size = ARRAY_SIZE(imx074_eeprom_read_tbl), + .data_tbl = imx074_eeprom_data_tbl, + .data_tbl_size = ARRAY_SIZE(imx074_eeprom_data_tbl), +}; + +static int imx074_sensor_v4l2_probe(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + return msm_sensor_v4l2_probe(&imx074_s_ctrl, info, sdev, s); +} + +static int imx074_probe(struct platform_device *pdev) +{ + return msm_sensor_register(pdev, imx074_sensor_v4l2_probe); +} + +struct platform_driver imx074_driver = { + .probe = imx074_probe, + .driver = { + .name = PLATFORM_DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_sensor_init_module(void) +{ + return platform_driver_register(&imx074_driver); +} + +static struct v4l2_subdev_core_ops imx074_subdev_core_ops; +static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { + .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt, +}; + +static struct v4l2_subdev_ops imx074_subdev_ops = { + .core = &imx074_subdev_core_ops, + .video = &imx074_subdev_video_ops, +}; + +static struct msm_sensor_fn_t imx074_func_tbl = { + .sensor_start_stream = msm_sensor_start_stream, + .sensor_stop_stream = msm_sensor_stop_stream, + .sensor_group_hold_on = msm_sensor_group_hold_on, + .sensor_group_hold_off = msm_sensor_group_hold_off, + .sensor_set_fps = msm_sensor_set_fps, + .sensor_write_exp_gain = msm_sensor_write_exp_gain1, + .sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1, + .sensor_setting = msm_sensor_setting, + .sensor_set_sensor_mode = msm_sensor_set_sensor_mode, + .sensor_mode_init = msm_sensor_mode_init, + .sensor_get_output_info = msm_sensor_get_output_info, + .sensor_config = imx074_sensor_config, + .sensor_open_init = imx074_sensor_open_init, + .sensor_release = imx074_sensor_release, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_probe = msm_sensor_probe, +}; + +static struct msm_sensor_reg_t imx074_regs = { + .default_data_type = MSM_CAMERA_I2C_BYTE_DATA, + .start_stream_conf = imx074_start_settings, + .start_stream_conf_size = ARRAY_SIZE(imx074_start_settings), + .stop_stream_conf = imx074_stop_settings, + .stop_stream_conf_size = ARRAY_SIZE(imx074_stop_settings), + .group_hold_on_conf = imx074_groupon_settings, + .group_hold_on_conf_size = ARRAY_SIZE(imx074_groupon_settings), + .group_hold_off_conf = imx074_groupoff_settings, + .group_hold_off_conf_size = + ARRAY_SIZE(imx074_groupoff_settings), + .init_settings = &imx074_init_conf[0], + .init_size = ARRAY_SIZE(imx074_init_conf), + .mode_settings = &imx074_confs[0], + .output_settings = &imx074_dimensions[0], + .num_conf = ARRAY_SIZE(imx074_confs), +}; + +static struct msm_sensor_ctrl_t imx074_s_ctrl = { + .msm_sensor_reg = &imx074_regs, + .sensor_i2c_client = &imx074_sensor_i2c_client, + .sensor_i2c_addr = 0x34, + .sensor_eeprom_client = &imx074_eeprom_client, + .sensor_output_reg_addr = &imx074_reg_addr, + .sensor_id_info = &imx074_id_info, + .sensor_exp_gain_info = &imx074_exp_gain_info, + .cam_mode = MSM_SENSOR_MODE_INVALID, + .csi_params = &imx074_csi_params_array[0], + .msm_sensor_mutex = &imx074_mut, + .sensor_i2c_driver = &imx074_i2c_driver, + .sensor_v4l2_subdev_info = imx074_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx074_subdev_info), + .sensor_v4l2_subdev_ops = &imx074_subdev_ops, + .func_tbl = &imx074_func_tbl, +}; + +module_init(msm_sensor_init_module); +MODULE_DESCRIPTION("Sony 13MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/sensors/msm_sensor.c b/drivers/media/video/msm_zsl/sensors/msm_sensor.c new file mode 100644 index 00000000000..cb30aeea5a6 --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/msm_sensor.c @@ -0,0 +1,760 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include "msm_sensor.h" +#include "../../msm_zsl/io/msm_camera_i2c.h" +#include "msm.h" +#include +#include "msm_ispif.h" + +/*=============================================================*/ + +int32_t msm_sensor_write_init_settings(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc; + rc = msm_sensor_write_all_conf_array( + s_ctrl->sensor_i2c_client, + s_ctrl->msm_sensor_reg->init_settings, + s_ctrl->msm_sensor_reg->init_size); + return rc; +} + +int32_t msm_sensor_write_res_settings(struct msm_sensor_ctrl_t *s_ctrl, + uint16_t res) +{ + int32_t rc; + rc = msm_sensor_write_conf_array( + s_ctrl->sensor_i2c_client, + s_ctrl->msm_sensor_reg->mode_settings, res); + if (rc < 0) + return rc; + + rc = msm_sensor_write_output_settings(s_ctrl, res); + return rc; +} + +int32_t msm_sensor_write_output_settings(struct msm_sensor_ctrl_t *s_ctrl, + uint16_t res) +{ + int32_t rc = -EFAULT; + struct msm_camera_i2c_reg_conf dim_settings[] = { + {s_ctrl->sensor_output_reg_addr->x_output, + s_ctrl->msm_sensor_reg-> + output_settings[res].x_output}, + {s_ctrl->sensor_output_reg_addr->y_output, + s_ctrl->msm_sensor_reg-> + output_settings[res].y_output}, + {s_ctrl->sensor_output_reg_addr->line_length_pclk, + s_ctrl->msm_sensor_reg-> + output_settings[res].line_length_pclk}, + {s_ctrl->sensor_output_reg_addr->frame_length_lines, + s_ctrl->msm_sensor_reg-> + output_settings[res].frame_length_lines}, + }; + + rc = msm_camera_i2c_write_tbl(s_ctrl->sensor_i2c_client, dim_settings, + ARRAY_SIZE(dim_settings), MSM_CAMERA_I2C_WORD_DATA); + return rc; +} + +void msm_sensor_start_stream(struct msm_sensor_ctrl_t *s_ctrl) +{ + msm_camera_i2c_write_tbl( + s_ctrl->sensor_i2c_client, + s_ctrl->msm_sensor_reg->start_stream_conf, + s_ctrl->msm_sensor_reg->start_stream_conf_size, + s_ctrl->msm_sensor_reg->default_data_type); +} + +void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl) +{ + msm_camera_i2c_write_tbl( + s_ctrl->sensor_i2c_client, + s_ctrl->msm_sensor_reg->stop_stream_conf, + s_ctrl->msm_sensor_reg->stop_stream_conf_size, + s_ctrl->msm_sensor_reg->default_data_type); +} + +void msm_sensor_group_hold_on(struct msm_sensor_ctrl_t *s_ctrl) +{ + msm_camera_i2c_write_tbl( + s_ctrl->sensor_i2c_client, + s_ctrl->msm_sensor_reg->group_hold_on_conf, + s_ctrl->msm_sensor_reg->group_hold_on_conf_size, + s_ctrl->msm_sensor_reg->default_data_type); +} + +void msm_sensor_group_hold_off(struct msm_sensor_ctrl_t *s_ctrl) +{ + msm_camera_i2c_write_tbl( + s_ctrl->sensor_i2c_client, + s_ctrl->msm_sensor_reg->group_hold_off_conf, + s_ctrl->msm_sensor_reg->group_hold_off_conf_size, + s_ctrl->msm_sensor_reg->default_data_type); +} + +int32_t msm_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl, + struct fps_cfg *fps) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + s_ctrl->fps_divider = fps->fps_div; + + if (s_ctrl->curr_res != MSM_SENSOR_INVALID_RES) { + total_lines_per_frame = (uint16_t) + ((s_ctrl->curr_frame_length_lines) * + s_ctrl->fps_divider/Q10); + + rc = msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines, + total_lines_per_frame, MSM_CAMERA_I2C_WORD_DATA); + } + return rc; +} + +int32_t msm_sensor_write_exp_gain1(struct msm_sensor_ctrl_t *s_ctrl, + uint16_t gain, uint32_t line) +{ + uint32_t fl_lines; + uint8_t offset; + fl_lines = s_ctrl->curr_frame_length_lines; + fl_lines = (fl_lines * s_ctrl->fps_divider) / Q10; + offset = s_ctrl->sensor_exp_gain_info->vert_offset; + if (line > (fl_lines - offset)) + fl_lines = line + offset; + + s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines, fl_lines, + MSM_CAMERA_I2C_WORD_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, line, + MSM_CAMERA_I2C_WORD_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr, gain, + MSM_CAMERA_I2C_WORD_DATA); + s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl); + return 0; +} + +int32_t msm_sensor_write_exp_gain2(struct msm_sensor_ctrl_t *s_ctrl, + uint16_t gain, uint32_t line) +{ + uint32_t fl_lines, ll_pclk, ll_ratio; + uint8_t offset; + fl_lines = s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider / Q10; + ll_pclk = s_ctrl->curr_line_length_pclk; + offset = s_ctrl->sensor_exp_gain_info->vert_offset; + if (line > (fl_lines - offset)) { + ll_ratio = (line * Q10) / (fl_lines - offset); + ll_pclk = ll_pclk * ll_ratio / Q10; + line = fl_lines - offset; + } + + s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->line_length_pclk, ll_pclk, + MSM_CAMERA_I2C_WORD_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, line, + MSM_CAMERA_I2C_WORD_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr, gain, + MSM_CAMERA_I2C_WORD_DATA); + s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl); + return 0; +} + +int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl, + int update_type, int res) +{ + int32_t rc = 0; + + v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_OFF_IMMEDIATELY)); + s_ctrl->func_tbl->sensor_stop_stream(s_ctrl); + msleep(30); + if (update_type == MSM_SENSOR_REG_INIT) { + s_ctrl->curr_csi_params = NULL; + msm_sensor_enable_debugfs(s_ctrl); + rc = msm_sensor_write_init_settings(s_ctrl); + } else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) { + msm_sensor_write_res_settings(s_ctrl, res); + if (s_ctrl->curr_csi_params != s_ctrl->csi_params[res]) { + s_ctrl->curr_csi_params = s_ctrl->csi_params[res]; + v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev, + NOTIFY_CSID_CFG, + &s_ctrl->curr_csi_params->csid_params); + v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev, + NOTIFY_CID_CHANGE, NULL); + mb(); + v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev, + NOTIFY_CSIPHY_CFG, + &s_ctrl->curr_csi_params->csiphy_params); + mb(); + msleep(20); + } + + v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev, + NOTIFY_PCLK_CHANGE, &s_ctrl->msm_sensor_reg-> + output_settings[res].op_pixel_clk); + v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_ON_FRAME_BOUNDARY)); + s_ctrl->func_tbl->sensor_start_stream(s_ctrl); + msleep(30); + } + return rc; +} + +int32_t msm_sensor_set_sensor_mode(struct msm_sensor_ctrl_t *s_ctrl, + int mode, int res) +{ + int32_t rc = 0; + if (s_ctrl->curr_res != res) { + s_ctrl->curr_frame_length_lines = + s_ctrl->msm_sensor_reg-> + output_settings[res].frame_length_lines; + + s_ctrl->curr_line_length_pclk = + s_ctrl->msm_sensor_reg-> + output_settings[res].line_length_pclk; + + if (s_ctrl->func_tbl->sensor_setting + (s_ctrl, MSM_SENSOR_UPDATE_PERIODIC, res) < 0) + return rc; + s_ctrl->curr_res = res; + } + + return rc; +} + +#define OTP_PAGE 0x0A02 +#define READ_MODE 0x0A00 + +#define START_ADDR 0x0A3D +#define END_ADDR 0x0A42 + +int32_t msm_sensor_mode_init(struct msm_sensor_ctrl_t *s_ctrl, + int mode, struct sensor_init_cfg *init_info) +{ + int32_t rc = 0; + uint8_t uOTPData[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + uint8_t uReadCheckSum = 0; + uint16_t uOTPStartAddr; + uint16_t uOTPEndAddr; + int i = 0; + s_ctrl->fps_divider = Q10; + s_ctrl->cam_mode = MSM_SENSOR_MODE_INVALID; + + CDBG("%s: %d\n", __func__, __LINE__); + + rc = msm_camera_i2c_write(s_ctrl->sensor_i2c_client, OTP_PAGE, + 0x0F, MSM_CAMERA_I2C_BYTE_DATA); + rc = msm_camera_i2c_write(s_ctrl->sensor_i2c_client, READ_MODE, + 0x01, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + printk(KERN_DEBUG "fail s5k6a3yx_i2c_write!!\n"); + return rc; + } + printk(KERN_DEBUG "Start calibrating....\n"); + uOTPStartAddr = START_ADDR; + uOTPEndAddr = END_ADDR; + + for (i = uOTPStartAddr; i <= uOTPEndAddr; i++) { + msm_camera_i2c_read(s_ctrl->sensor_i2c_client, i, + (uint16_t*) &uOTPData[i-uOTPStartAddr], + MSM_CAMERA_I2C_BYTE_DATA); + uReadCheckSum += uOTPData[i-uOTPStartAddr]; + printk(KERN_DEBUG "uOPTData[0x%x] = 0x%x...Sum = %d...\n", + i, uOTPData[i-uOTPStartAddr], uReadCheckSum); + } + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, READ_MODE, + 0x00, MSM_CAMERA_I2C_BYTE_DATA); + + if (uReadCheckSum == 0) { + printk(KERN_DEBUG "[No OTP Calibration]..\n"); + } else { + printk(KERN_DEBUG "Ajusting Calibration data to the sensor!!\n"); + /* Dgain_greenR */ + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x020E, + uOTPData[2], MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x020F, + uOTPData[3], MSM_CAMERA_I2C_BYTE_DATA); + /* Dgain_Red */ + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x0210, + uOTPData[0], MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x0211, + uOTPData[1], MSM_CAMERA_I2C_BYTE_DATA); + /* Dgain_Blue */ + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x0212, + uOTPData[4], MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x0213, + uOTPData[5], MSM_CAMERA_I2C_BYTE_DATA); + /* Dgain_greenB */ + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x0214, + uOTPData[2], MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x0215, + uOTPData[3], MSM_CAMERA_I2C_BYTE_DATA); + } + + if (mode != s_ctrl->cam_mode) { + s_ctrl->curr_res = MSM_SENSOR_INVALID_RES; + s_ctrl->cam_mode = mode; + + rc = s_ctrl->func_tbl->sensor_setting(s_ctrl, + MSM_SENSOR_REG_INIT, 0); + } + return rc; +} + +int32_t msm_sensor_get_output_info(struct msm_sensor_ctrl_t *s_ctrl, + struct sensor_output_info_t *sensor_output_info) +{ + int rc = 0; + sensor_output_info->num_info = s_ctrl->msm_sensor_reg->num_conf; + if (copy_to_user((void *)sensor_output_info->output_info, + s_ctrl->msm_sensor_reg->output_settings, + sizeof(struct msm_sensor_output_info_t) * + s_ctrl->msm_sensor_reg->num_conf)) + rc = -EFAULT; + + return rc; +} + +int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("msm_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + if (s_ctrl->func_tbl-> + sensor_set_fps == NULL) { + rc = -EFAULT; + break; + } + rc = s_ctrl->func_tbl-> + sensor_set_fps( + s_ctrl, + &(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + if (s_ctrl->func_tbl-> + sensor_write_exp_gain == NULL) { + rc = -EFAULT; + break; + } + rc = + s_ctrl->func_tbl-> + sensor_write_exp_gain( + s_ctrl, + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + if (s_ctrl->func_tbl-> + sensor_write_snapshot_exp_gain == NULL) { + rc = -EFAULT; + break; + } + rc = + s_ctrl->func_tbl-> + sensor_write_snapshot_exp_gain( + s_ctrl, + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + if (s_ctrl->func_tbl-> + sensor_set_sensor_mode == NULL) { + rc = -EFAULT; + break; + } + rc = s_ctrl->func_tbl-> + sensor_set_sensor_mode( + s_ctrl, + cdata.mode, + cdata.rs); + break; + + case CFG_SET_EFFECT: + break; + + case CFG_SENSOR_INIT: + if (s_ctrl->func_tbl-> + sensor_mode_init == NULL) { + rc = -EFAULT; + break; + } + rc = s_ctrl->func_tbl-> + sensor_mode_init( + s_ctrl, + cdata.mode, + &(cdata.cfg.init_info)); + break; + + case CFG_GET_OUTPUT_INFO: + if (s_ctrl->func_tbl-> + sensor_get_output_info == NULL) { + rc = -EFAULT; + break; + } + rc = s_ctrl->func_tbl-> + sensor_get_output_info( + s_ctrl, + &cdata.cfg.output_info); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_EEPROM_DATA: + if (s_ctrl->sensor_eeprom_client == NULL || + s_ctrl->sensor_eeprom_client-> + func_tbl.eeprom_get_data == NULL) { + rc = -EFAULT; + break; + } + rc = s_ctrl->sensor_eeprom_client-> + func_tbl.eeprom_get_data( + s_ctrl->sensor_eeprom_client, + &cdata.cfg.eeprom_data); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_eeprom_data_t))) + rc = -EFAULT; + break; + + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +int32_t msm_sensor_power_up(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + CDBG("%s: %d\n", __func__, __LINE__); + msm_camio_clk_rate_set(MSM_SENSOR_MCLK_24HZ); + rc = gpio_request(data->sensor_platform_info->sensor_reset, + "SENSOR_NAME"); + if (!rc) { + CDBG("%s: reset sensor\n", __func__); + gpio_direction_output(data->sensor_platform_info->sensor_reset, + 0); + usleep_range(1000, 2000); + gpio_set_value_cansleep(data->sensor_platform_info-> + sensor_reset, 1); + usleep_range(4000, 5000); + } else { + CDBG("%s: gpio request fail", __func__); + } + return rc; +} + +int32_t msm_sensor_power_down(const struct msm_camera_sensor_info *data) +{ + CDBG("%s\n", __func__); + gpio_set_value_cansleep(data->sensor_platform_info->sensor_reset, 0); + usleep_range(1000, 2000); + gpio_free(data->sensor_platform_info->sensor_reset); + return 0; +} + + +int32_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint16_t chipid = 0; + rc = msm_camera_i2c_read( + s_ctrl->sensor_i2c_client, + s_ctrl->sensor_id_info->sensor_id_reg_addr, &chipid, + MSM_CAMERA_I2C_WORD_DATA); + if (rc < 0) { + CDBG("%s: read id failed\n", __func__); + return rc; + } + + CDBG("msm_sensor id: %d\n", chipid); + if (chipid != s_ctrl->sensor_id_info->sensor_id) { + CDBG("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + return rc; +} + +int32_t msm_sensor_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct msm_sensor_ctrl_t *this_ctrl; + CDBG("%s_i2c_probe called\n", client->name); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + rc = -EFAULT; + goto probe_failure; + } + + this_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data); + if (this_ctrl->sensor_i2c_client != NULL) { + this_ctrl->sensor_i2c_client->client = client; + if (this_ctrl->sensor_i2c_addr != 0) + this_ctrl->sensor_i2c_client->client->addr = + this_ctrl->sensor_i2c_addr; + } else { + rc = -EFAULT; + } + +probe_failure: + CDBG("%s_i2c_probe failed\n", client->name); + return rc; +} + +int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl) +{ + mutex_lock(s_ctrl->msm_sensor_mutex); + s_ctrl->func_tbl->sensor_power_down(s_ctrl->sensordata); + mutex_unlock(s_ctrl->msm_sensor_mutex); + CDBG("%s completed\n", __func__); + return 0; +} + +int32_t msm_sensor_open_init(struct msm_sensor_ctrl_t *s_ctrl, + const struct msm_camera_sensor_info *data) +{ + if (data) + s_ctrl->sensordata = data; + + return s_ctrl->func_tbl->sensor_power_up(data); +} + +int32_t msm_sensor_probe(struct msm_sensor_ctrl_t *s_ctrl, + const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(s_ctrl->sensor_i2c_driver); + if (rc < 0 || s_ctrl->sensor_i2c_client->client == NULL) { + rc = -ENOTSUPP; + CDBG("I2C add driver failed"); + goto probe_fail; + } + +#if !defined(CONFIG_S5C73M3) && !defined(CONFIG_S5K6A3YX) + rc = s_ctrl->func_tbl->sensor_power_up(info); + if (rc < 0) + goto probe_fail; + + rc = msm_sensor_match_id(s_ctrl); + if (rc < 0) + goto probe_fail; + + if (s_ctrl->sensor_eeprom_client != NULL) { + struct msm_camera_eeprom_client *eeprom_client = + s_ctrl->sensor_eeprom_client; + if (eeprom_client->func_tbl.eeprom_init != NULL && + eeprom_client->func_tbl.eeprom_release != NULL) { + rc = eeprom_client->func_tbl.eeprom_init( + eeprom_client, + s_ctrl->sensor_i2c_client->client->adapter); + if (rc < 0) + goto probe_fail; + + rc = msm_camera_eeprom_read_tbl(eeprom_client, + eeprom_client->read_tbl, eeprom_client->read_tbl_size); + eeprom_client->func_tbl.eeprom_release(eeprom_client); + if (rc < 0) + goto probe_fail; + } + } +#endif + + s->s_init = s_ctrl->func_tbl->sensor_open_init; + s->s_release = s_ctrl->func_tbl->sensor_release; + s->s_config = s_ctrl->func_tbl->sensor_config; + s->s_camera_type = info->camera_type; + if (info->sensor_platform_info != NULL) + s->s_mount_angle = info->sensor_platform_info->mount_angle; + else + s->s_mount_angle = 0; + + goto power_down; +probe_fail: + i2c_del_driver(s_ctrl->sensor_i2c_driver); +power_down: +#if !defined(CONFIG_S5C73M3) && !defined(CONFIG_S5K6A3YX) + s_ctrl->func_tbl->sensor_power_down(info); +#endif + return rc; +} + +int32_t msm_sensor_v4l2_probe(struct msm_sensor_ctrl_t *s_ctrl, + const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + int32_t rc = 0; + rc = s_ctrl->func_tbl->sensor_probe(s_ctrl, info, s); + if (rc < 0) + return rc; + + s_ctrl->sensor_v4l2_subdev = sdev; + v4l2_i2c_subdev_init(s_ctrl->sensor_v4l2_subdev, + s_ctrl->sensor_i2c_client->client, + s_ctrl->sensor_v4l2_subdev_ops); + s_ctrl->sensor_v4l2_subdev->dev_priv = (void *) s_ctrl; + return rc; +} + +int32_t msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + struct msm_sensor_ctrl_t *s_ctrl = + (struct msm_sensor_ctrl_t *) sd->dev_priv; + if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size) + return -EINVAL; + + *code = s_ctrl->sensor_v4l2_subdev_info[index].code; + return 0; +} + +int32_t msm_sensor_v4l2_s_ctrl(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int rc = -1, i = 0; + struct msm_sensor_ctrl_t *s_ctrl = + (struct msm_sensor_ctrl_t *) sd->dev_priv; + struct msm_sensor_v4l2_ctrl_info_t *v4l2_ctrl = + s_ctrl->msm_sensor_v4l2_ctrl_info; + + CDBG("%s\n", __func__); + CDBG("%d\n", ctrl->id); + if (v4l2_ctrl == NULL) + return rc; + + for (i = 0; i < s_ctrl->num_v4l2_ctrl; i++) { + if (v4l2_ctrl[i].ctrl_id == ctrl->id) { + if (v4l2_ctrl[i].s_v4l2_ctrl != NULL) { + rc = v4l2_ctrl[i].s_v4l2_ctrl( + s_ctrl, + &s_ctrl->msm_sensor_v4l2_ctrl_info[i], + ctrl->value); + } + break; + } + } + + return rc; +} + +int32_t msm_sensor_v4l2_query_ctrl( + struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) +{ + int rc = -1, i = 0; + struct msm_sensor_ctrl_t *s_ctrl = + (struct msm_sensor_ctrl_t *) sd->dev_priv; + + CDBG("%s\n", __func__); + CDBG("%s id: %d\n", __func__, qctrl->id); + + if (s_ctrl->msm_sensor_v4l2_ctrl_info == NULL) + return rc; + + for (i = 0; i < s_ctrl->num_v4l2_ctrl; i++) { + if (s_ctrl->msm_sensor_v4l2_ctrl_info[i].ctrl_id == qctrl->id) { + qctrl->minimum = + s_ctrl->msm_sensor_v4l2_ctrl_info[i].min; + qctrl->maximum = + s_ctrl->msm_sensor_v4l2_ctrl_info[i].max; + qctrl->flags = 1; + rc = 0; + break; + } + } + + return rc; +} + +int msm_sensor_s_ctrl_by_enum(struct msm_sensor_ctrl_t *s_ctrl, + struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value) +{ + int rc = 0; + CDBG("%s enter\n", __func__); + rc = msm_sensor_write_enum_conf_array( + s_ctrl->sensor_i2c_client, + ctrl_info->enum_cfg_settings, value); + return rc; +} + +static int msm_sensor_debugfs_stream_s(void *data, u64 val) +{ + struct msm_sensor_ctrl_t *s_ctrl = (struct msm_sensor_ctrl_t *) data; + if (val) + s_ctrl->func_tbl->sensor_start_stream(s_ctrl); + else + s_ctrl->func_tbl->sensor_stop_stream(s_ctrl); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(sensor_debugfs_stream, NULL, + msm_sensor_debugfs_stream_s, "%llu\n"); + +static int msm_sensor_debugfs_test_s(void *data, u64 val) +{ + CDBG("val: %llu\n", val); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(sensor_debugfs_test, NULL, + msm_sensor_debugfs_test_s, "%llu\n"); + +int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl) +{ + struct dentry *debugfs_base, *sensor_dir; + debugfs_base = debugfs_create_dir("msm_sensor", NULL); + if (!debugfs_base) + return -ENOMEM; + + sensor_dir = debugfs_create_dir + (s_ctrl->sensordata->sensor_name, debugfs_base); + if (!sensor_dir) + return -ENOMEM; + + if (!debugfs_create_file("stream", S_IRUGO | S_IWUSR, sensor_dir, + (void *) s_ctrl, &sensor_debugfs_stream)) + return -ENOMEM; + + if (!debugfs_create_file("test", S_IRUGO | S_IWUSR, sensor_dir, + (void *) s_ctrl, &sensor_debugfs_test)) + return -ENOMEM; + + return 0; +} diff --git a/drivers/media/video/msm_zsl/sensors/msm_sensor.h b/drivers/media/video/msm_zsl/sensors/msm_sensor.h new file mode 100644 index 00000000000..f1a15b2f929 --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/msm_sensor.h @@ -0,0 +1,233 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm.h" +#include "msm_camera_i2c.h" +#include "msm_camera_eeprom.h" +#define Q8 0x00000100 +#define Q10 0x00000400 + +#define MSM_SENSOR_MCLK_8HZ 8000000 +#define MSM_SENSOR_MCLK_16HZ 16000000 +#define MSM_SENSOR_MCLK_24HZ 24000000 + +enum msm_sensor_reg_update { + /* Sensor egisters that need to be updated during initialization */ + MSM_SENSOR_REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + MSM_SENSOR_UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + MSM_SENSOR_UPDATE_ALL, + /* Not valid update */ + MSM_SENSOR_UPDATE_INVALID +}; + +enum msm_sensor_cam_mode_t { + MSM_SENSOR_MODE_2D_RIGHT, + MSM_SENSOR_MODE_2D_LEFT, + MSM_SENSOR_MODE_3D, + MSM_SENSOR_MODE_INVALID +}; + +struct msm_sensor_output_reg_addr_t { + uint16_t x_output; + uint16_t y_output; + uint16_t line_length_pclk; + uint16_t frame_length_lines; +}; + +struct msm_sensor_id_info_t { + uint16_t sensor_id_reg_addr; + uint16_t sensor_id; +}; + +struct msm_sensor_exp_gain_info_t { + uint16_t coarse_int_time_addr; + uint16_t global_gain_addr; + uint16_t vert_offset; +}; + +struct msm_sensor_reg_t { + enum msm_camera_i2c_data_type default_data_type; + struct msm_camera_i2c_reg_conf *start_stream_conf; + uint8_t start_stream_conf_size; + struct msm_camera_i2c_reg_conf *stop_stream_conf; + uint8_t stop_stream_conf_size; + struct msm_camera_i2c_reg_conf *group_hold_on_conf; + uint8_t group_hold_on_conf_size; + struct msm_camera_i2c_reg_conf *group_hold_off_conf; + uint8_t group_hold_off_conf_size; + struct msm_camera_i2c_conf_array *init_settings; + uint8_t init_size; + struct msm_camera_i2c_conf_array *mode_settings; + struct msm_sensor_output_info_t *output_settings; + uint8_t num_conf; +}; + +struct v4l2_subdev_info { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + uint16_t fmt; + uint16_t order; +}; + +struct msm_sensor_ctrl_t; + +struct msm_sensor_v4l2_ctrl_info_t { + uint32_t ctrl_id; + int16_t min; + int16_t max; + int16_t step; + struct msm_camera_i2c_enum_conf_array *enum_cfg_settings; + int (*s_v4l2_ctrl) (struct msm_sensor_ctrl_t *, + struct msm_sensor_v4l2_ctrl_info_t *, int); +}; + +struct msm_sensor_fn_t { + void (*sensor_start_stream) (struct msm_sensor_ctrl_t *); + void (*sensor_stop_stream) (struct msm_sensor_ctrl_t *); + void (*sensor_group_hold_on) (struct msm_sensor_ctrl_t *); + void (*sensor_group_hold_off) (struct msm_sensor_ctrl_t *); + + int32_t (*sensor_set_fps) (struct msm_sensor_ctrl_t *, + struct fps_cfg *); + int32_t (*sensor_write_exp_gain) (struct msm_sensor_ctrl_t *, + uint16_t, uint32_t); + int32_t (*sensor_write_snapshot_exp_gain) (struct msm_sensor_ctrl_t *, + uint16_t, uint32_t); + int32_t (*sensor_setting) (struct msm_sensor_ctrl_t *, + int update_type, int rt); + int32_t (*sensor_set_sensor_mode) + (struct msm_sensor_ctrl_t *, int, int); + int32_t (*sensor_mode_init) (struct msm_sensor_ctrl_t *, + int, struct sensor_init_cfg *); + int32_t (*sensor_get_output_info) (struct msm_sensor_ctrl_t *, + struct sensor_output_info_t *); + int (*sensor_config) (void __user *); + int (*sensor_open_init) (const struct msm_camera_sensor_info *); + int (*sensor_release) (void); + int (*sensor_power_down) + (const struct msm_camera_sensor_info *); + int (*sensor_power_up) (const struct msm_camera_sensor_info *); + int (*sensor_probe) (struct msm_sensor_ctrl_t *s_ctrl, + const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s); +}; + +struct msm_sensor_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + struct i2c_client *msm_sensor_client; + struct i2c_driver *sensor_i2c_driver; + struct msm_camera_i2c_client *sensor_i2c_client; + uint16_t sensor_i2c_addr; + + struct msm_camera_eeprom_client *sensor_eeprom_client; + + struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr; + struct msm_sensor_id_info_t *sensor_id_info; + struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info; + struct msm_sensor_reg_t *msm_sensor_reg; + struct msm_sensor_v4l2_ctrl_info_t *msm_sensor_v4l2_ctrl_info; + uint16_t num_v4l2_ctrl; + + uint16_t curr_line_length_pclk; + uint16_t curr_frame_length_lines; + + uint32_t fps_divider; + enum msm_sensor_resolution_t curr_res; + enum msm_sensor_cam_mode_t cam_mode; + + struct mutex *msm_sensor_mutex; + struct msm_camera_csi2_params *curr_csi_params; + struct msm_camera_csi2_params **csi_params; + + struct v4l2_subdev *sensor_v4l2_subdev; + struct v4l2_subdev_info *sensor_v4l2_subdev_info; + uint8_t sensor_v4l2_subdev_info_size; + struct v4l2_subdev_ops *sensor_v4l2_subdev_ops; + struct msm_sensor_fn_t *func_tbl; +}; + +void msm_sensor_start_stream(struct msm_sensor_ctrl_t *s_ctrl); +void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl); +void msm_sensor_group_hold_on(struct msm_sensor_ctrl_t *s_ctrl); +void msm_sensor_group_hold_off(struct msm_sensor_ctrl_t *s_ctrl); + +int32_t msm_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl, + struct fps_cfg *fps); +int32_t msm_sensor_write_exp_gain1(struct msm_sensor_ctrl_t *s_ctrl, + uint16_t gain, uint32_t line); +int32_t msm_sensor_write_exp_gain2(struct msm_sensor_ctrl_t *s_ctrl, + uint16_t gain, uint32_t line); +int32_t msm_sensor_set_sensor_mode(struct msm_sensor_ctrl_t *s_ctrl, + int mode, int res); +int32_t msm_sensor_mode_init(struct msm_sensor_ctrl_t *s_ctrl, + int mode, struct sensor_init_cfg *init_info); +int32_t msm_sensor_get_output_info(struct msm_sensor_ctrl_t *, + struct sensor_output_info_t *); +int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp); +int32_t msm_sensor_power_up(const struct msm_camera_sensor_info *data); +int32_t msm_sensor_power_down(const struct msm_camera_sensor_info *data); + +int32_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl); +int msm_sensor_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id); +int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl); +int32_t msm_sensor_open_init(struct msm_sensor_ctrl_t *s_ctrl, + const struct msm_camera_sensor_info *data); +int msm_sensor_probe(struct msm_sensor_ctrl_t *s_ctrl, + const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s); + +int msm_sensor_v4l2_probe(struct msm_sensor_ctrl_t *s_ctrl, + const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s); + +int32_t msm_sensor_v4l2_s_ctrl(struct v4l2_subdev *sd, + struct v4l2_control *ctrl); + +int32_t msm_sensor_v4l2_query_ctrl( + struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl); + +int msm_sensor_s_ctrl_by_index(struct msm_sensor_ctrl_t *s_ctrl, + struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value); + +int msm_sensor_s_ctrl_by_enum(struct msm_sensor_ctrl_t *s_ctrl, + struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value); + +int msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code); + +int msm_sensor_write_init_settings(struct msm_sensor_ctrl_t *s_ctrl); +int msm_sensor_write_res_settings + (struct msm_sensor_ctrl_t *s_ctrl, uint16_t res); + +int32_t msm_sensor_write_output_settings(struct msm_sensor_ctrl_t *s_ctrl, + uint16_t res); + +int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl, + int update_type, int res); + +int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl); diff --git a/drivers/media/video/msm_zsl/sensors/mt9m114_v4l2.c b/drivers/media/video/msm_zsl/sensors/mt9m114_v4l2.c new file mode 100644 index 00000000000..fc45705a1eb --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/mt9m114_v4l2.c @@ -0,0 +1,1340 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_sensor.h" +#define SENSOR_NAME "mt9m114" +#define PLATFORM_DRIVER_NAME "msm_camera_mt9m114" +#define mt9m114_obj mt9m114_##obj + +/* Sysctl registers */ +#define MT9M114_COMMAND_REGISTER 0x0080 +#define MT9M114_COMMAND_REGISTER_APPLY_PATCH (1 << 0) +#define MT9M114_COMMAND_REGISTER_SET_STATE (1 << 1) +#define MT9M114_COMMAND_REGISTER_REFRESH (1 << 2) +#define MT9M114_COMMAND_REGISTER_WAIT_FOR_EVENT (1 << 3) +#define MT9M114_COMMAND_REGISTER_OK (1 << 15) + +DEFINE_MUTEX(mt9m114_mut); +static struct msm_sensor_ctrl_t mt9m114_s_ctrl; + +static struct msm_camera_i2c_reg_conf mt9m114_720p_settings[] = { + {0xdc00, 0x50, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {MT9M114_COMMAND_REGISTER, (MT9M114_COMMAND_REGISTER_OK | + MT9M114_COMMAND_REGISTER_SET_STATE), MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {0xDC01, 0x52, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_POLL}, + + {0x098E, 0, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC800, 0x007C,},/*y_addr_start = 124*/ + {0xC802, 0x0004,},/*x_addr_start = 4*/ + {0xC804, 0x0353,},/*y_addr_end = 851*/ + {0xC806, 0x050B,},/*x_addr_end = 1291*/ + {0xC808, 0x02DC,},/*pixclk = 48000000*/ + {0xC80A, 0x6C00,},/*pixclk = 48000000*/ + {0xC80C, 0x0001,},/*row_speed = 1*/ + {0xC80E, 0x00DB,},/*fine_integ_time_min = 219*/ + {0xC810, 0x05BD,},/*fine_integ_time_max = 1469*/ + {0xC812, 0x03E8,},/*frame_length_lines = 1000*/ + {0xC814, 0x0640,},/*line_length_pck = 1600*/ + {0xC816, 0x0060,},/*fine_correction = 96*/ + {0xC818, 0x02D3,},/*cpipe_last_row = 723*/ + {0xC826, 0x0020,},/*reg_0_data = 32*/ + {0xC834, 0x0000,},/*sensor_control_read_mode = 0*/ + {0xC854, 0x0000,},/*crop_window_xoffset = 0*/ + {0xC856, 0x0000,},/*crop_window_yoffset = 0*/ + {0xC858, 0x0500,},/*crop_window_width = 1280*/ + {0xC85A, 0x02D0,},/*crop_window_height = 720*/ + {0xC85C, 0x03, MSM_CAMERA_I2C_BYTE_DATA}, /*crop_cropmode = 3*/ + {0xC868, 0x0500,},/*output_width = 1280*/ + {0xC86A, 0x02D0,},/*output_height = 720*/ + {0xC878, 0x00, MSM_CAMERA_I2C_BYTE_DATA}, /*aet_aemode = 0*/ + {0xC88C, 0x1E00,},/*aet_max_frame_rate = 7680*/ + {0xC88E, 0x1E00,},/*aet_min_frame_rate = 7680*/ + {0xC914, 0x0000,},/*stat_awb_window_xstart = 0*/ + {0xC916, 0x0000,},/*stat_awb_window_ystart = 0*/ + {0xC918, 0x04FF,},/*stat_awb_window_xend = 1279*/ + {0xC91A, 0x02CF,},/*stat_awb_window_yend = 719*/ + {0xC91C, 0x0000,},/*stat_ae_window_xstart = 0*/ + {0xC91E, 0x0000,},/*stat_ae_window_ystart = 0*/ + {0xC920, 0x00FF,},/*stat_ae_window_xend = 255*/ + {0xC922, 0x008F,},/*stat_ae_window_yend = 143*/ +}; + +static struct msm_camera_i2c_reg_conf mt9m114_recommend_settings[] = { + {0x301A, 0x0200, MSM_CAMERA_I2C_SET_WORD_MASK}, + {0x098E, 0, MSM_CAMERA_I2C_BYTE_DATA}, + /*cam_sysctl_pll_enable = 1*/ + {0xC97E, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, + /*cam_sysctl_pll_divider_m_n = 288*/ + {0xC980, 0x0120,}, + /*cam_sysctl_pll_divider_p = 1792*/ + {0xC982, 0x0700,}, + /*output_control = 32769*/ + {0xC984, 0x8001,}, + /*mipi_timing_t_hs_zero = 3840*/ + {0xC988, 0x0F00,}, + /*mipi_timing_t_hs_exit_hs_trail = 2823*/ + {0xC98A, 0x0B07,}, + /*mipi_timing_t_clk_post_clk_pre = 3329*/ + {0xC98C, 0x0D01,}, + /*mipi_timing_t_clk_trail_clk_zero = 1821*/ + {0xC98E, 0x071D,}, + /*mipi_timing_t_lpx = 6*/ + {0xC990, 0x0006,}, + /*mipi_timing_init_timing = 2572*/ + {0xC992, 0x0A0C,}, + {0xC800, 0x007C,},/*y_addr_start = 124*/ + {0xC802, 0x0004,},/*x_addr_start = 4*/ + {0xC804, 0x0353,},/*y_addr_end = 851*/ + {0xC806, 0x050B,},/*x_addr_end = 1291*/ + {0xC808, 0x02DC,},/*pixclk = 48000000*/ + {0xC80A, 0x6C00,},/*pixclk = 48000000*/ + {0xC80C, 0x0001,},/*row_speed = 1*/ + {0xC80E, 0x00DB,},/*fine_integ_time_min = 219*/ + {0xC810, 0x05BD,},/*fine_integ_time_max = 1469*/ + {0xC812, 0x03E8,},/*frame_length_lines = 1000*/ + {0xC814, 0x0640,},/*line_length_pck = 1600*/ + {0xC816, 0x0060,},/*fine_correction = 96*/ + {0xC818, 0x02D3,},/*cpipe_last_row = 723*/ + {0xC826, 0x0020,},/*reg_0_data = 32*/ + {0xC834, 0x0000,},/*sensor_control_read_mode = 0*/ + {0xC854, 0x0000,},/*crop_window_xoffset = 0*/ + {0xC856, 0x0000,},/*crop_window_yoffset = 0*/ + {0xC858, 0x0500,},/*crop_window_width = 1280*/ + {0xC85A, 0x02D0,},/*crop_window_height = 720*/ + {0xC85C, 0x03, MSM_CAMERA_I2C_BYTE_DATA}, /*crop_cropmode = 3*/ + {0xC868, 0x0500,},/*output_width = 1280*/ + {0xC86A, 0x02D0,},/*output_height = 720*/ + {0xC878, 0x00, MSM_CAMERA_I2C_BYTE_DATA}, /*aet_aemode = 0*/ + {0xC88C, 0x1E00,},/*aet_max_frame_rate = 7680*/ + {0xC88E, 0x1E00,},/*aet_min_frame_rate = 7680*/ + {0xC914, 0x0000,},/*stat_awb_window_xstart = 0*/ + {0xC916, 0x0000,},/*stat_awb_window_ystart = 0*/ + {0xC918, 0x04FF,},/*stat_awb_window_xend = 1279*/ + {0xC91A, 0x02CF,},/*stat_awb_window_yend = 719*/ + {0xC91C, 0x0000,},/*stat_ae_window_xstart = 0*/ + {0xC91E, 0x0000,},/*stat_ae_window_ystart = 0*/ + {0xC920, 0x00FF,},/*stat_ae_window_xend = 255*/ + {0xC922, 0x008F,},/*stat_ae_window_yend = 143*/ + + /*Sensor optimization*/ + {0x316A, 0x8270,}, + {0x316C, 0x8270,}, + {0x3ED0, 0x2305,}, + {0x3ED2, 0x77CF,}, + {0x316E, 0x8202,}, + {0x3180, 0x87FF,}, + {0x30D4, 0x6080,}, + {0xA802, 0x0008,},/*AE_TRACK_MODE*/ + {0x3E14, 0xFF39,}, + {0x0982, 0x0001,},/*ACCESS_CTL_STAT*/ + {0x098A, 0x5000,},/*PHYSICAL_ADDRESS_ACCESS*/ + {0xD000, 0x70CF,}, + {0xD002, 0xFFFF,}, + {0xD004, 0xC5D4,}, + {0xD006, 0x903A,}, + {0xD008, 0x2144,}, + {0xD00A, 0x0C00,}, + {0xD00C, 0x2186,}, + {0xD00E, 0x0FF3,}, + {0xD010, 0xB844,}, + {0xD012, 0xB948,}, + {0xD014, 0xE082,}, + {0xD016, 0x20CC,}, + {0xD018, 0x80E2,}, + {0xD01A, 0x21CC,}, + {0xD01C, 0x80A2,}, + {0xD01E, 0x21CC,}, + {0xD020, 0x80E2,}, + {0xD022, 0xF404,}, + {0xD024, 0xD801,}, + {0xD026, 0xF003,}, + {0xD028, 0xD800,}, + {0xD02A, 0x7EE0,}, + {0xD02C, 0xC0F1,}, + {0xD02E, 0x08BA,}, + {0xD030, 0x0600,}, + {0xD032, 0xC1A1,}, + {0xD034, 0x76CF,}, + {0xD036, 0xFFFF,}, + {0xD038, 0xC130,}, + {0xD03A, 0x6E04,}, + {0xD03C, 0xC040,}, + {0xD03E, 0x71CF,}, + {0xD040, 0xFFFF,}, + {0xD042, 0xC790,}, + {0xD044, 0x8103,}, + {0xD046, 0x77CF,}, + {0xD048, 0xFFFF,}, + {0xD04A, 0xC7C0,}, + {0xD04C, 0xE001,}, + {0xD04E, 0xA103,}, + {0xD050, 0xD800,}, + {0xD052, 0x0C6A,}, + {0xD054, 0x04E0,}, + {0xD056, 0xB89E,}, + {0xD058, 0x7508,}, + {0xD05A, 0x8E1C,}, + {0xD05C, 0x0809,}, + {0xD05E, 0x0191,}, + {0xD060, 0xD801,}, + {0xD062, 0xAE1D,}, + {0xD064, 0xE580,}, + {0xD066, 0x20CA,}, + {0xD068, 0x0022,}, + {0xD06A, 0x20CF,}, + {0xD06C, 0x0522,}, + {0xD06E, 0x0C5C,}, + {0xD070, 0x04E2,}, + {0xD072, 0x21CA,}, + {0xD074, 0x0062,}, + {0xD076, 0xE580,}, + {0xD078, 0xD901,}, + {0xD07A, 0x79C0,}, + {0xD07C, 0xD800,}, + {0xD07E, 0x0BE6,}, + {0xD080, 0x04E0,}, + {0xD082, 0xB89E,}, + {0xD084, 0x70CF,}, + {0xD086, 0xFFFF,}, + {0xD088, 0xC8D4,}, + {0xD08A, 0x9002,}, + {0xD08C, 0x0857,}, + {0xD08E, 0x025E,}, + {0xD090, 0xFFDC,}, + {0xD092, 0xE080,}, + {0xD094, 0x25CC,}, + {0xD096, 0x9022,}, + {0xD098, 0xF225,}, + {0xD09A, 0x1700,}, + {0xD09C, 0x108A,}, + {0xD09E, 0x73CF,}, + {0xD0A0, 0xFF00,}, + {0xD0A2, 0x3174,}, + {0xD0A4, 0x9307,}, + {0xD0A6, 0x2A04,}, + {0xD0A8, 0x103E,}, + {0xD0AA, 0x9328,}, + {0xD0AC, 0x2942,}, + {0xD0AE, 0x7140,}, + {0xD0B0, 0x2A04,}, + {0xD0B2, 0x107E,}, + {0xD0B4, 0x9349,}, + {0xD0B6, 0x2942,}, + {0xD0B8, 0x7141,}, + {0xD0BA, 0x2A04,}, + {0xD0BC, 0x10BE,}, + {0xD0BE, 0x934A,}, + {0xD0C0, 0x2942,}, + {0xD0C2, 0x714B,}, + {0xD0C4, 0x2A04,}, + {0xD0C6, 0x10BE,}, + {0xD0C8, 0x130C,}, + {0xD0CA, 0x010A,}, + {0xD0CC, 0x2942,}, + {0xD0CE, 0x7142,}, + {0xD0D0, 0x2250,}, + {0xD0D2, 0x13CA,}, + {0xD0D4, 0x1B0C,}, + {0xD0D6, 0x0284,}, + {0xD0D8, 0xB307,}, + {0xD0DA, 0xB328,}, + {0xD0DC, 0x1B12,}, + {0xD0DE, 0x02C4,}, + {0xD0E0, 0xB34A,}, + {0xD0E2, 0xED88,}, + {0xD0E4, 0x71CF,}, + {0xD0E6, 0xFF00,}, + {0xD0E8, 0x3174,}, + {0xD0EA, 0x9106,}, + {0xD0EC, 0xB88F,}, + {0xD0EE, 0xB106,}, + {0xD0F0, 0x210A,}, + {0xD0F2, 0x8340,}, + {0xD0F4, 0xC000,}, + {0xD0F6, 0x21CA,}, + {0xD0F8, 0x0062,}, + {0xD0FA, 0x20F0,}, + {0xD0FC, 0x0040,}, + {0xD0FE, 0x0B02,}, + {0xD100, 0x0320,}, + {0xD102, 0xD901,}, + {0xD104, 0x07F1,}, + {0xD106, 0x05E0,}, + {0xD108, 0xC0A1,}, + {0xD10A, 0x78E0,}, + {0xD10C, 0xC0F1,}, + {0xD10E, 0x71CF,}, + {0xD110, 0xFFFF,}, + {0xD112, 0xC7C0,}, + {0xD114, 0xD840,}, + {0xD116, 0xA900,}, + {0xD118, 0x71CF,}, + {0xD11A, 0xFFFF,}, + {0xD11C, 0xD02C,}, + {0xD11E, 0xD81E,}, + {0xD120, 0x0A5A,}, + {0xD122, 0x04E0,}, + {0xD124, 0xDA00,}, + {0xD126, 0xD800,}, + {0xD128, 0xC0D1,}, + {0xD12A, 0x7EE0,}, + {0x098E, 0x0000,}, + + {0x0982, 0x0001,}, + {0x098A, 0x5C10,}, + {0xDC10, 0xC0F1,}, + {0xDC12, 0x0CDA,}, + {0xDC14, 0x0580,}, + {0xDC16, 0x76CF,}, + {0xDC18, 0xFF00,}, + {0xDC1A, 0x2184,}, + {0xDC1C, 0x9624,}, + {0xDC1E, 0x218C,}, + {0xDC20, 0x8FC3,}, + {0xDC22, 0x75CF,}, + {0xDC24, 0xFFFF,}, + {0xDC26, 0xE058,}, + {0xDC28, 0xF686,}, + {0xDC2A, 0x1550,}, + {0xDC2C, 0x1080,}, + {0xDC2E, 0xE001,}, + {0xDC30, 0x1D50,}, + {0xDC32, 0x1002,}, + {0xDC34, 0x1552,}, + {0xDC36, 0x1100,}, + {0xDC38, 0x6038,}, + {0xDC3A, 0x1D52,}, + {0xDC3C, 0x1004,}, + {0xDC3E, 0x1540,}, + {0xDC40, 0x1080,}, + {0xDC42, 0x081B,}, + {0xDC44, 0x00D1,}, + {0xDC46, 0x8512,}, + {0xDC48, 0x1000,}, + {0xDC4A, 0x00C0,}, + {0xDC4C, 0x7822,}, + {0xDC4E, 0x2089,}, + {0xDC50, 0x0FC1,}, + {0xDC52, 0x2008,}, + {0xDC54, 0x0F81,}, + {0xDC56, 0xFFFF,}, + {0xDC58, 0xFF80,}, + {0xDC5A, 0x8512,}, + {0xDC5C, 0x1801,}, + {0xDC5E, 0x0052,}, + {0xDC60, 0xA512,}, + {0xDC62, 0x1544,}, + {0xDC64, 0x1080,}, + {0xDC66, 0xB861,}, + {0xDC68, 0x262F,}, + {0xDC6A, 0xF007,}, + {0xDC6C, 0x1D44,}, + {0xDC6E, 0x1002,}, + {0xDC70, 0x20CA,}, + {0xDC72, 0x0021,}, + {0xDC74, 0x20CF,}, + {0xDC76, 0x04E1,}, + {0xDC78, 0x0850,}, + {0xDC7A, 0x04A1,}, + {0xDC7C, 0x21CA,}, + {0xDC7E, 0x0021,}, + {0xDC80, 0x1542,}, + {0xDC82, 0x1140,}, + {0xDC84, 0x8D2C,}, + {0xDC86, 0x6038,}, + {0xDC88, 0x1D42,}, + {0xDC8A, 0x1004,}, + {0xDC8C, 0x1542,}, + {0xDC8E, 0x1140,}, + {0xDC90, 0xB601,}, + {0xDC92, 0x046D,}, + {0xDC94, 0x0580,}, + {0xDC96, 0x78E0,}, + {0xDC98, 0xD800,}, + {0xDC9A, 0xB893,}, + {0xDC9C, 0x002D,}, + {0xDC9E, 0x04A0,}, + {0xDCA0, 0xD900,}, + {0xDCA2, 0x78E0,}, + {0xDCA4, 0x72CF,}, + {0xDCA6, 0xFFFF,}, + {0xDCA8, 0xE058,}, + {0xDCAA, 0x2240,}, + {0xDCAC, 0x0340,}, + {0xDCAE, 0xA212,}, + {0xDCB0, 0x208A,}, + {0xDCB2, 0x0FFF,}, + {0xDCB4, 0x1A42,}, + {0xDCB6, 0x0004,}, + {0xDCB8, 0xD830,}, + {0xDCBA, 0x1A44,}, + {0xDCBC, 0x0002,}, + {0xDCBE, 0xD800,}, + {0xDCC0, 0x1A50,}, + {0xDCC2, 0x0002,}, + {0xDCC4, 0x1A52,}, + {0xDCC6, 0x0004,}, + {0xDCC8, 0x1242,}, + {0xDCCA, 0x0140,}, + {0xDCCC, 0x8A2C,}, + {0xDCCE, 0x6038,}, + {0xDCD0, 0x1A42,}, + {0xDCD2, 0x0004,}, + {0xDCD4, 0x1242,}, + {0xDCD6, 0x0141,}, + {0xDCD8, 0x70CF,}, + {0xDCDA, 0xFF00,}, + {0xDCDC, 0x2184,}, + {0xDCDE, 0xB021,}, + {0xDCE0, 0xD800,}, + {0xDCE2, 0xB893,}, + {0xDCE4, 0x07E5,}, + {0xDCE6, 0x0460,}, + {0xDCE8, 0xD901,}, + {0xDCEA, 0x78E0,}, + {0xDCEC, 0xC0F1,}, + {0xDCEE, 0x0BFA,}, + {0xDCF0, 0x05A0,}, + {0xDCF2, 0x216F,}, + {0xDCF4, 0x0043,}, + {0xDCF6, 0xC1A4,}, + {0xDCF8, 0x220A,}, + {0xDCFA, 0x1F80,}, + {0xDCFC, 0xFFFF,}, + {0xDCFE, 0xE058,}, + {0xDD00, 0x2240,}, + {0xDD02, 0x134F,}, + {0xDD04, 0x1A48,}, + {0xDD06, 0x13C0,}, + {0xDD08, 0x1248,}, + {0xDD0A, 0x1002,}, + {0xDD0C, 0x70CF,}, + {0xDD0E, 0x7FFF,}, + {0xDD10, 0xFFFF,}, + {0xDD12, 0xE230,}, + {0xDD14, 0xC240,}, + {0xDD16, 0xDA00,}, + {0xDD18, 0xF00C,}, + {0xDD1A, 0x1248,}, + {0xDD1C, 0x1003,}, + {0xDD1E, 0x1301,}, + {0xDD20, 0x04CB,}, + {0xDD22, 0x7261,}, + {0xDD24, 0x2108,}, + {0xDD26, 0x0081,}, + {0xDD28, 0x2009,}, + {0xDD2A, 0x0080,}, + {0xDD2C, 0x1A48,}, + {0xDD2E, 0x10C0,}, + {0xDD30, 0x1248,}, + {0xDD32, 0x100B,}, + {0xDD34, 0xC300,}, + {0xDD36, 0x0BE7,}, + {0xDD38, 0x90C4,}, + {0xDD3A, 0x2102,}, + {0xDD3C, 0x0003,}, + {0xDD3E, 0x238C,}, + {0xDD40, 0x8FC3,}, + {0xDD42, 0xF6C7,}, + {0xDD44, 0xDAFF,}, + {0xDD46, 0x1A05,}, + {0xDD48, 0x1082,}, + {0xDD4A, 0xC241,}, + {0xDD4C, 0xF005,}, + {0xDD4E, 0x7A6F,}, + {0xDD50, 0xC241,}, + {0xDD52, 0x1A05,}, + {0xDD54, 0x10C2,}, + {0xDD56, 0x2000,}, + {0xDD58, 0x8040,}, + {0xDD5A, 0xDA00,}, + {0xDD5C, 0x20C0,}, + {0xDD5E, 0x0064,}, + {0xDD60, 0x781C,}, + {0xDD62, 0xC042,}, + {0xDD64, 0x1C0E,}, + {0xDD66, 0x3082,}, + {0xDD68, 0x1A48,}, + {0xDD6A, 0x13C0,}, + {0xDD6C, 0x7548,}, + {0xDD6E, 0x7348,}, + {0xDD70, 0x7148,}, + {0xDD72, 0x7648,}, + {0xDD74, 0xF002,}, + {0xDD76, 0x7608,}, + {0xDD78, 0x1248,}, + {0xDD7A, 0x1000,}, + {0xDD7C, 0x1400,}, + {0xDD7E, 0x300B,}, + {0xDD80, 0x084D,}, + {0xDD82, 0x02C5,}, + {0xDD84, 0x1248,}, + {0xDD86, 0x1000,}, + {0xDD88, 0xE101,}, + {0xDD8A, 0x1001,}, + {0xDD8C, 0x04CB,}, + {0xDD8E, 0x1A48,}, + {0xDD90, 0x1000,}, + {0xDD92, 0x7361,}, + {0xDD94, 0x1408,}, + {0xDD96, 0x300B,}, + {0xDD98, 0x2302,}, + {0xDD9A, 0x02C0,}, + {0xDD9C, 0x780D,}, + {0xDD9E, 0x2607,}, + {0xDDA0, 0x903E,}, + {0xDDA2, 0x07D6,}, + {0xDDA4, 0xFFE3,}, + {0xDDA6, 0x792F,}, + {0xDDA8, 0x09CF,}, + {0xDDAA, 0x8152,}, + {0xDDAC, 0x1248,}, + {0xDDAE, 0x100E,}, + {0xDDB0, 0x2400,}, + {0xDDB2, 0x334B,}, + {0xDDB4, 0xE501,}, + {0xDDB6, 0x7EE2,}, + {0xDDB8, 0x0DBF,}, + {0xDDBA, 0x90F2,}, + {0xDDBC, 0x1B0C,}, + {0xDDBE, 0x1382,}, + {0xDDC0, 0xC123,}, + {0xDDC2, 0x140E,}, + {0xDDC4, 0x3080,}, + {0xDDC6, 0x7822,}, + {0xDDC8, 0x1A07,}, + {0xDDCA, 0x1002,}, + {0xDDCC, 0x124C,}, + {0xDDCE, 0x1000,}, + {0xDDD0, 0x120B,}, + {0xDDD2, 0x1081,}, + {0xDDD4, 0x1207,}, + {0xDDD6, 0x1083,}, + {0xDDD8, 0x2142,}, + {0xDDDA, 0x004B,}, + {0xDDDC, 0x781B,}, + {0xDDDE, 0x0B21,}, + {0xDDE0, 0x02E2,}, + {0xDDE2, 0x1A4C,}, + {0xDDE4, 0x1000,}, + {0xDDE6, 0xE101,}, + {0xDDE8, 0x0915,}, + {0xDDEA, 0x00C2,}, + {0xDDEC, 0xC101,}, + {0xDDEE, 0x1204,}, + {0xDDF0, 0x1083,}, + {0xDDF2, 0x090D,}, + {0xDDF4, 0x00C2,}, + {0xDDF6, 0xE001,}, + {0xDDF8, 0x1A4C,}, + {0xDDFA, 0x1000,}, + {0xDDFC, 0x1A06,}, + {0xDDFE, 0x1002,}, + {0xDE00, 0x234A,}, + {0xDE02, 0x1000,}, + {0xDE04, 0x7169,}, + {0xDE06, 0xF008,}, + {0xDE08, 0x2053,}, + {0xDE0A, 0x0003,}, + {0xDE0C, 0x6179,}, + {0xDE0E, 0x781C,}, + {0xDE10, 0x2340,}, + {0xDE12, 0x104B,}, + {0xDE14, 0x1203,}, + {0xDE16, 0x1083,}, + {0xDE18, 0x0BF1,}, + {0xDE1A, 0x90C2,}, + {0xDE1C, 0x1202,}, + {0xDE1E, 0x1080,}, + {0xDE20, 0x091D,}, + {0xDE22, 0x0004,}, + {0xDE24, 0x70CF,}, + {0xDE26, 0xFFFF,}, + {0xDE28, 0xC644,}, + {0xDE2A, 0x881B,}, + {0xDE2C, 0xE0B2,}, + {0xDE2E, 0xD83C,}, + {0xDE30, 0x20CA,}, + {0xDE32, 0x0CA2,}, + {0xDE34, 0x1A01,}, + {0xDE36, 0x1002,}, + {0xDE38, 0x1A4C,}, + {0xDE3A, 0x1080,}, + {0xDE3C, 0x02B9,}, + {0xDE3E, 0x05A0,}, + {0xDE40, 0xC0A4,}, + {0xDE42, 0x78E0,}, + {0xDE44, 0xC0F1,}, + {0xDE46, 0xFF95,}, + {0xDE48, 0xD800,}, + {0xDE4A, 0x71CF,}, + {0xDE4C, 0xFF00,}, + {0xDE4E, 0x1FE0,}, + {0xDE50, 0x19D0,}, + {0xDE52, 0x001C,}, + {0xDE54, 0x19D1,}, + {0xDE56, 0x001C,}, + {0xDE58, 0x70CF,}, + {0xDE5A, 0xFFFF,}, + {0xDE5C, 0xE058,}, + {0xDE5E, 0x901F,}, + {0xDE60, 0xB861,}, + {0xDE62, 0x19D2,}, + {0xDE64, 0x001C,}, + {0xDE66, 0xC0D1,}, + {0xDE68, 0x7EE0,}, + {0xDE6A, 0x78E0,}, + {0xDE6C, 0xC0F1,}, + {0xDE6E, 0x0A7A,}, + {0xDE70, 0x0580,}, + {0xDE72, 0x70CF,}, + {0xDE74, 0xFFFF,}, + {0xDE76, 0xC5D4,}, + {0xDE78, 0x9041,}, + {0xDE7A, 0x9023,}, + {0xDE7C, 0x75CF,}, + {0xDE7E, 0xFFFF,}, + {0xDE80, 0xE058,}, + {0xDE82, 0x7942,}, + {0xDE84, 0xB967,}, + {0xDE86, 0x7F30,}, + {0xDE88, 0xB53F,}, + {0xDE8A, 0x71CF,}, + {0xDE8C, 0xFFFF,}, + {0xDE8E, 0xC84C,}, + {0xDE90, 0x91D3,}, + {0xDE92, 0x108B,}, + {0xDE94, 0x0081,}, + {0xDE96, 0x2615,}, + {0xDE98, 0x1380,}, + {0xDE9A, 0x090F,}, + {0xDE9C, 0x0C91,}, + {0xDE9E, 0x0A8E,}, + {0xDEA0, 0x05A0,}, + {0xDEA2, 0xD906,}, + {0xDEA4, 0x7E10,}, + {0xDEA6, 0x2615,}, + {0xDEA8, 0x1380,}, + {0xDEAA, 0x0A82,}, + {0xDEAC, 0x05A0,}, + {0xDEAE, 0xD960,}, + {0xDEB0, 0x790F,}, + {0xDEB2, 0x090D,}, + {0xDEB4, 0x0133,}, + {0xDEB6, 0xAD0C,}, + {0xDEB8, 0xD904,}, + {0xDEBA, 0xAD2C,}, + {0xDEBC, 0x79EC,}, + {0xDEBE, 0x2941,}, + {0xDEC0, 0x7402,}, + {0xDEC2, 0x71CF,}, + {0xDEC4, 0xFF00,}, + {0xDEC6, 0x2184,}, + {0xDEC8, 0xB142,}, + {0xDECA, 0x1906,}, + {0xDECC, 0x0E44,}, + {0xDECE, 0xFFDE,}, + {0xDED0, 0x70C9,}, + {0xDED2, 0x0A5A,}, + {0xDED4, 0x05A0,}, + {0xDED6, 0x8D2C,}, + {0xDED8, 0xAD0B,}, + {0xDEDA, 0xD800,}, + {0xDEDC, 0xAD01,}, + {0xDEDE, 0x0219,}, + {0xDEE0, 0x05A0,}, + {0xDEE2, 0xA513,}, + {0xDEE4, 0xC0F1,}, + {0xDEE6, 0x71CF,}, + {0xDEE8, 0xFFFF,}, + {0xDEEA, 0xC644,}, + {0xDEEC, 0xA91B,}, + {0xDEEE, 0xD902,}, + {0xDEF0, 0x70CF,}, + {0xDEF2, 0xFFFF,}, + {0xDEF4, 0xC84C,}, + {0xDEF6, 0x093E,}, + {0xDEF8, 0x03A0,}, + {0xDEFA, 0xA826,}, + {0xDEFC, 0xFFDC,}, + {0xDEFE, 0xF1B5,}, + {0xDF00, 0xC0F1,}, + {0xDF02, 0x09EA,}, + {0xDF04, 0x0580,}, + {0xDF06, 0x75CF,}, + {0xDF08, 0xFFFF,}, + {0xDF0A, 0xE058,}, + {0xDF0C, 0x1540,}, + {0xDF0E, 0x1080,}, + {0xDF10, 0x08A7,}, + {0xDF12, 0x0010,}, + {0xDF14, 0x8D00,}, + {0xDF16, 0x0813,}, + {0xDF18, 0x009E,}, + {0xDF1A, 0x1540,}, + {0xDF1C, 0x1081,}, + {0xDF1E, 0xE181,}, + {0xDF20, 0x20CA,}, + {0xDF22, 0x00A1,}, + {0xDF24, 0xF24B,}, + {0xDF26, 0x1540,}, + {0xDF28, 0x1081,}, + {0xDF2A, 0x090F,}, + {0xDF2C, 0x0050,}, + {0xDF2E, 0x1540,}, + {0xDF30, 0x1081,}, + {0xDF32, 0x0927,}, + {0xDF34, 0x0091,}, + {0xDF36, 0x1550,}, + {0xDF38, 0x1081,}, + {0xDF3A, 0xDE00,}, + {0xDF3C, 0xAD2A,}, + {0xDF3E, 0x1D50,}, + {0xDF40, 0x1382,}, + {0xDF42, 0x1552,}, + {0xDF44, 0x1101,}, + {0xDF46, 0x1D52,}, + {0xDF48, 0x1384,}, + {0xDF4A, 0xB524,}, + {0xDF4C, 0x082D,}, + {0xDF4E, 0x015F,}, + {0xDF50, 0xFF55,}, + {0xDF52, 0xD803,}, + {0xDF54, 0xF033,}, + {0xDF56, 0x1540,}, + {0xDF58, 0x1081,}, + {0xDF5A, 0x0967,}, + {0xDF5C, 0x00D1,}, + {0xDF5E, 0x1550,}, + {0xDF60, 0x1081,}, + {0xDF62, 0xDE00,}, + {0xDF64, 0xAD2A,}, + {0xDF66, 0x1D50,}, + {0xDF68, 0x1382,}, + {0xDF6A, 0x1552,}, + {0xDF6C, 0x1101,}, + {0xDF6E, 0x1D52,}, + {0xDF70, 0x1384,}, + {0xDF72, 0xB524,}, + {0xDF74, 0x0811,}, + {0xDF76, 0x019E,}, + {0xDF78, 0xB8A0,}, + {0xDF7A, 0xAD00,}, + {0xDF7C, 0xFF47,}, + {0xDF7E, 0x1D40,}, + {0xDF80, 0x1382,}, + {0xDF82, 0xF01F,}, + {0xDF84, 0xFF5A,}, + {0xDF86, 0x8D01,}, + {0xDF88, 0x8D40,}, + {0xDF8A, 0xE812,}, + {0xDF8C, 0x71CF,}, + {0xDF8E, 0xFFFF,}, + {0xDF90, 0xC644,}, + {0xDF92, 0x893B,}, + {0xDF94, 0x7030,}, + {0xDF96, 0x22D1,}, + {0xDF98, 0x8062,}, + {0xDF9A, 0xF20A,}, + {0xDF9C, 0x0A0F,}, + {0xDF9E, 0x009E,}, + {0xDFA0, 0x71CF,}, + {0xDFA2, 0xFFFF,}, + {0xDFA4, 0xC84C,}, + {0xDFA6, 0x893B,}, + {0xDFA8, 0xE902,}, + {0xDFAA, 0xFFCF,}, + {0xDFAC, 0x8D00,}, + {0xDFAE, 0xB8E7,}, + {0xDFB0, 0x26CA,}, + {0xDFB2, 0x1022,}, + {0xDFB4, 0xF5E2,}, + {0xDFB6, 0xFF3C,}, + {0xDFB8, 0xD801,}, + {0xDFBA, 0x1D40,}, + {0xDFBC, 0x1002,}, + {0xDFBE, 0x0141,}, + {0xDFC0, 0x0580,}, + {0xDFC2, 0x78E0,}, + {0xDFC4, 0xC0F1,}, + {0xDFC6, 0xC5E1,}, + {0xDFC8, 0xFF34,}, + {0xDFCA, 0xDD00,}, + {0xDFCC, 0x70CF,}, + {0xDFCE, 0xFFFF,}, + {0xDFD0, 0xE090,}, + {0xDFD2, 0xA8A8,}, + {0xDFD4, 0xD800,}, + {0xDFD6, 0xB893,}, + {0xDFD8, 0x0C8A,}, + {0xDFDA, 0x0460,}, + {0xDFDC, 0xD901,}, + {0xDFDE, 0x71CF,}, + {0xDFE0, 0xFFFF,}, + {0xDFE2, 0xDC10,}, + {0xDFE4, 0xD813,}, + {0xDFE6, 0x0B96,}, + {0xDFE8, 0x0460,}, + {0xDFEA, 0x72A9,}, + {0xDFEC, 0x0119,}, + {0xDFEE, 0x0580,}, + {0xDFF0, 0xC0F1,}, + {0xDFF2, 0x71CF,}, + {0xDFF4, 0x0000,}, + {0xDFF6, 0x5BAE,}, + {0xDFF8, 0x7940,}, + {0xDFFA, 0xFF9D,}, + {0xDFFC, 0xF135,}, + {0xDFFE, 0x78E0,}, + {0xE000, 0xC0F1,}, + {0xE002, 0x70CF,}, + {0xE004, 0x0000,}, + {0xE006, 0x5CBA,}, + {0xE008, 0x7840,}, + {0xE00A, 0x70CF,}, + {0xE00C, 0xFFFF,}, + {0xE00E, 0xE058,}, + {0xE010, 0x8800,}, + {0xE012, 0x0815,}, + {0xE014, 0x001E,}, + {0xE016, 0x70CF,}, + {0xE018, 0xFFFF,}, + {0xE01A, 0xC84C,}, + {0xE01C, 0x881A,}, + {0xE01E, 0xE080,}, + {0xE020, 0x0EE0,}, + {0xE022, 0xFFC1,}, + {0xE024, 0xF121,}, + {0xE026, 0x78E0,}, + {0xE028, 0xC0F1,}, + {0xE02A, 0xD900,}, + {0xE02C, 0xF009,}, + {0xE02E, 0x70CF,}, + {0xE030, 0xFFFF,}, + {0xE032, 0xE0AC,}, + {0xE034, 0x7835,}, + {0xE036, 0x8041,}, + {0xE038, 0x8000,}, + {0xE03A, 0xE102,}, + {0xE03C, 0xA040,}, + {0xE03E, 0x09F3,}, + {0xE040, 0x8114,}, + {0xE042, 0x71CF,}, + {0xE044, 0xFFFF,}, + {0xE046, 0xE058,}, + {0xE048, 0x70CF,}, + {0xE04A, 0xFFFF,}, + {0xE04C, 0xC594,}, + {0xE04E, 0xB030,}, + {0xE050, 0xFFDD,}, + {0xE052, 0xD800,}, + {0xE054, 0xF109,}, + {0xE056, 0x0000,}, + {0xE058, 0x0300,}, + {0xE05A, 0x0204,}, + {0xE05C, 0x0700,}, + {0xE05E, 0x0000,}, + {0xE060, 0x0000,}, + {0xE062, 0x0000,}, + {0xE064, 0x0000,}, + {0xE066, 0x0000,}, + {0xE068, 0x0000,}, + {0xE06A, 0x0000,}, + {0xE06C, 0x0000,}, + {0xE06E, 0x0000,}, + {0xE070, 0x0000,}, + {0xE072, 0x0000,}, + {0xE074, 0x0000,}, + {0xE076, 0x0000,}, + {0xE078, 0x0000,}, + {0xE07A, 0x0000,}, + {0xE07C, 0x0000,}, + {0xE07E, 0x0000,}, + {0xE080, 0x0000,}, + {0xE082, 0x0000,}, + {0xE084, 0x0000,}, + {0xE086, 0x0000,}, + {0xE088, 0x0000,}, + {0xE08A, 0x0000,}, + {0xE08C, 0x0000,}, + {0xE08E, 0x0000,}, + {0xE090, 0x0000,}, + {0xE092, 0x0000,}, + {0xE094, 0x0000,}, + {0xE096, 0x0000,}, + {0xE098, 0x0000,}, + {0xE09A, 0x0000,}, + {0xE09C, 0x0000,}, + {0xE09E, 0x0000,}, + {0xE0A0, 0x0000,}, + {0xE0A2, 0x0000,}, + {0xE0A4, 0x0000,}, + {0xE0A6, 0x0000,}, + {0xE0A8, 0x0000,}, + {0xE0AA, 0x0000,}, + {0xE0AC, 0xFFFF,}, + {0xE0AE, 0xCB68,}, + {0xE0B0, 0xFFFF,}, + {0xE0B2, 0xDFF0,}, + {0xE0B4, 0xFFFF,}, + {0xE0B6, 0xCB6C,}, + {0xE0B8, 0xFFFF,}, + {0xE0BA, 0xE000,}, + {0x098E, 0x0000,}, + + /*MIPI setting for SOC1040*/ + {0x3C5A, 0x0009,}, + {0x3C44, 0x0080,},/*MIPI_CUSTOM_SHORT_PKT*/ + + /*[Tuning_settings]*/ + + /*[CCM]*/ + {0xC892, 0x0267,},/*CAM_AWB_CCM_L_0*/ + {0xC894, 0xFF1A,},/*CAM_AWB_CCM_L_1*/ + {0xC896, 0xFFB3,},/*CAM_AWB_CCM_L_2*/ + {0xC898, 0xFF80,},/*CAM_AWB_CCM_L_3*/ + {0xC89A, 0x0166,},/*CAM_AWB_CCM_L_4*/ + {0xC89C, 0x0003,},/*CAM_AWB_CCM_L_5*/ + {0xC89E, 0xFF9A,},/*CAM_AWB_CCM_L_6*/ + {0xC8A0, 0xFEB4,},/*CAM_AWB_CCM_L_7*/ + {0xC8A2, 0x024D,},/*CAM_AWB_CCM_L_8*/ + {0xC8A4, 0x01BF,},/*CAM_AWB_CCM_M_0*/ + {0xC8A6, 0xFF01,},/*CAM_AWB_CCM_M_1*/ + {0xC8A8, 0xFFF3,},/*CAM_AWB_CCM_M_2*/ + {0xC8AA, 0xFF75,},/*CAM_AWB_CCM_M_3*/ + {0xC8AC, 0x0198,},/*CAM_AWB_CCM_M_4*/ + {0xC8AE, 0xFFFD,},/*CAM_AWB_CCM_M_5*/ + {0xC8B0, 0xFF9A,},/*CAM_AWB_CCM_M_6*/ + {0xC8B2, 0xFEE7,},/*CAM_AWB_CCM_M_7*/ + {0xC8B4, 0x02A8,},/*CAM_AWB_CCM_M_8*/ + {0xC8B6, 0x01D9,},/*CAM_AWB_CCM_R_0*/ + {0xC8B8, 0xFF26,},/*CAM_AWB_CCM_R_1*/ + {0xC8BA, 0xFFF3,},/*CAM_AWB_CCM_R_2*/ + {0xC8BC, 0xFFB3,},/*CAM_AWB_CCM_R_3*/ + {0xC8BE, 0x0132,},/*CAM_AWB_CCM_R_4*/ + {0xC8C0, 0xFFE8,},/*CAM_AWB_CCM_R_5*/ + {0xC8C2, 0xFFDA,},/*CAM_AWB_CCM_R_6*/ + {0xC8C4, 0xFECD,},/*CAM_AWB_CCM_R_7*/ + {0xC8C6, 0x02C2,},/*CAM_AWB_CCM_R_8*/ + {0xC8C8, 0x0075,},/*CAM_AWB_CCM_L_RG_GAIN*/ + {0xC8CA, 0x011C,},/*CAM_AWB_CCM_L_BG_GAIN*/ + {0xC8CC, 0x009A,},/*CAM_AWB_CCM_M_RG_GAIN*/ + {0xC8CE, 0x0105,},/*CAM_AWB_CCM_M_BG_GAIN*/ + {0xC8D0, 0x00A4,},/*CAM_AWB_CCM_R_RG_GAIN*/ + {0xC8D2, 0x00AC,},/*CAM_AWB_CCM_R_BG_GAIN*/ + {0xC8D4, 0x0A8C,},/*CAM_AWB_CCM_L_CTEMP*/ + {0xC8D6, 0x0F0A,},/*CAM_AWB_CCM_M_CTEMP*/ + {0xC8D8, 0x1964,},/*CAM_AWB_CCM_R_CTEMP*/ + + /*[AWB]*/ + {0xC914, 0x0000,},/*CAM_STAT_AWB_CLIP_WINDOW_XSTART*/ + {0xC916, 0x0000,},/*CAM_STAT_AWB_CLIP_WINDOW_YSTART*/ + {0xC918, 0x04FF,},/*CAM_STAT_AWB_CLIP_WINDOW_XEND*/ + {0xC91A, 0x02CF,},/*CAM_STAT_AWB_CLIP_WINDOW_YEND*/ + {0xC904, 0x0033,},/*CAM_AWB_AWB_XSHIFT_PRE_ADJ*/ + {0xC906, 0x0040,},/*CAM_AWB_AWB_YSHIFT_PRE_ADJ*/ + {0xC8F2, 0x03, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_AWB_XSCALE*/ + {0xC8F3, 0x02, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_AWB_YSCALE*/ + {0xC906, 0x003C,},/*CAM_AWB_AWB_YSHIFT_PRE_ADJ*/ + {0xC8F4, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_0*/ + {0xC8F6, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_1*/ + {0xC8F8, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_2*/ + {0xC8FA, 0xE724,},/*CAM_AWB_AWB_WEIGHTS_3*/ + {0xC8FC, 0x1583,},/*CAM_AWB_AWB_WEIGHTS_4*/ + {0xC8FE, 0x2045,},/*CAM_AWB_AWB_WEIGHTS_5*/ + {0xC900, 0x03FF,},/*CAM_AWB_AWB_WEIGHTS_6*/ + {0xC902, 0x007C,},/*CAM_AWB_AWB_WEIGHTS_7*/ + {0xC90C, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_R_L*/ + {0xC90D, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_G_L*/ + {0xC90E, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_B_L*/ + {0xC90F, 0x88, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_R_R*/ + {0xC910, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_G_R*/ + {0xC911, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_B_R*/ + + /*[Step7-CPIPE_Preference]*/ + {0xC926, 0x0020,},/*CAM_LL_START_BRIGHTNESS*/ + {0xC928, 0x009A,},/*CAM_LL_STOP_BRIGHTNESS*/ + {0xC946, 0x0070,},/*CAM_LL_START_GAIN_METRIC*/ + {0xC948, 0x00F3,},/*CAM_LL_STOP_GAIN_METRIC*/ + {0xC952, 0x0020,},/*CAM_LL_START_TARGET_LUMA_BM*/ + {0xC954, 0x009A,},/*CAM_LL_STOP_TARGET_LUMA_BM*/ + {0xC92A, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_SATURATION*/ + {0xC92B, 0x4B, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_END_SATURATION*/ + {0xC92C, 0x00, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_DESATURATION*/ + {0xC92D, 0xFF, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_END_DESATURATION*/ + {0xC92E, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_DEMOSAIC*/ + {0xC92F, 0x02, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_AP_GAIN*/ + {0xC930, 0x06, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_AP_THRESH*/ + {0xC931, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_DEMOSAIC*/ + {0xC932, 0x01, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_AP_GAIN*/ + {0xC933, 0x0C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_AP_THRESH*/ + {0xC934, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_RED*/ + {0xC935, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_GREEN*/ + {0xC936, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_BLUE*/ + {0xC937, 0x0F, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_THRESH*/ + {0xC938, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_RED*/ + {0xC939, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_GREEN*/ + {0xC93A, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_BLUE*/ + {0xC93B, 0x32, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_THRESH*/ + {0xC93C, 0x0020,},/*CAM_LL_START_CONTRAST_BM*/ + {0xC93E, 0x009A,},/*CAM_LL_STOP_CONTRAST_BM*/ + {0xC940, 0x00DC,},/*CAM_LL_GAMMA*/ + /*CAM_LL_START_CONTRAST_GRADIENT*/ + {0xC942, 0x38, MSM_CAMERA_I2C_BYTE_DATA}, + /*CAM_LL_STOP_CONTRAST_GRADIENT*/ + {0xC943, 0x30, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC944, 0x50, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_CONTRAST_LUMA*/ + {0xC945, 0x19, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_CONTRAST_LUMA*/ + {0xC94A, 0x0230,},/*CAM_LL_START_FADE_TO_BLACK_LUMA*/ + {0xC94C, 0x0010,},/*CAM_LL_STOP_FADE_TO_BLACK_LUMA*/ + {0xC94E, 0x01CD,},/*CAM_LL_CLUSTER_DC_TH_BM*/ + {0xC950, 0x05, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_CLUSTER_DC_GATE*/ + {0xC951, 0x40, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_SUMMING_SENSITIVITY*/ + /*CAM_AET_TARGET_AVERAGE_LUMA_DARK*/ + {0xC87B, 0x1B, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC878, 0x0E, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AET_AEMODE*/ + {0xC890, 0x0080,},/*CAM_AET_TARGET_GAIN*/ + {0xC886, 0x0100,},/*CAM_AET_AE_MAX_VIRT_AGAIN*/ + {0xC87C, 0x005A,},/*CAM_AET_BLACK_CLIPPING_TARGET*/ + {0xB42A, 0x05, MSM_CAMERA_I2C_BYTE_DATA},/*CCM_DELTA_GAIN*/ + /*AE_TRACK_AE_TRACKING_DAMPENING*/ + {0xA80A, 0x20, MSM_CAMERA_I2C_BYTE_DATA}, + {0x3C44, 0x0080,}, + {0x3C40, 0x0004, MSM_CAMERA_I2C_UNSET_WORD_MASK}, + {0xA802, 0x08, MSM_CAMERA_I2C_SET_BYTE_MASK}, + {0xC908, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC879, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC909, 0x01, MSM_CAMERA_I2C_UNSET_BYTE_MASK}, + {0xA80A, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, + {0xA80B, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, + {0xAC16, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC878, 0x08, MSM_CAMERA_I2C_SET_BYTE_MASK}, + {0xBC02, 0x08, MSM_CAMERA_I2C_UNSET_BYTE_MASK}, +}; + +static struct v4l2_subdev_info mt9m114_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static struct msm_camera_i2c_reg_conf mt9m114_config_change_settings[] = { + {0xdc00, 0x28, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {MT9M114_COMMAND_REGISTER, (MT9M114_COMMAND_REGISTER_OK | + MT9M114_COMMAND_REGISTER_SET_STATE), MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {0xDC01, 0x31, MSM_CAMERA_I2C_BYTE_DATA}, +}; + +static void mt9m114_stop_stream(struct msm_sensor_ctrl_t *s_ctrl) {} + +static struct msm_camera_i2c_conf_array mt9m114_init_conf[] = { + {mt9m114_recommend_settings, + ARRAY_SIZE(mt9m114_recommend_settings), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_config_change_settings, + ARRAY_SIZE(mt9m114_config_change_settings), + 0, MSM_CAMERA_I2C_WORD_DATA}, +}; + +static struct msm_camera_i2c_conf_array mt9m114_confs[] = { + {mt9m114_720p_settings, + ARRAY_SIZE(mt9m114_720p_settings), 0, MSM_CAMERA_I2C_WORD_DATA}, +}; + +static struct msm_camera_i2c_reg_conf mt9m114_saturation[][1] = { + {{0xCC12, 0x00},}, + {{0xCC12, 0x1A},}, + {{0xCC12, 0x34},}, + {{0xCC12, 0x4E},}, + {{0xCC12, 0x68},}, + {{0xCC12, 0x80},}, + {{0xCC12, 0x9A},}, + {{0xCC12, 0xB4},}, + {{0xCC12, 0xCE},}, + {{0xCC12, 0xE8},}, + {{0xCC12, 0xFF},}, +}; + +static struct msm_camera_i2c_reg_conf mt9m114_refresh[] = { + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_REFRESH, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {MT9M114_COMMAND_REGISTER, (MT9M114_COMMAND_REGISTER_OK | + MT9M114_COMMAND_REGISTER_REFRESH), MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_REFRESH, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_OK, + MSM_CAMERA_I2C_SET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, +}; + +static struct msm_camera_i2c_conf_array mt9m114_saturation_confs[][2] = { + {{mt9m114_saturation[0], + ARRAY_SIZE(mt9m114_saturation[0]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[1], + ARRAY_SIZE(mt9m114_saturation[1]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[2], + ARRAY_SIZE(mt9m114_saturation[2]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[3], + ARRAY_SIZE(mt9m114_saturation[3]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[4], + ARRAY_SIZE(mt9m114_saturation[4]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[5], + ARRAY_SIZE(mt9m114_saturation[5]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[6], + ARRAY_SIZE(mt9m114_saturation[6]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[7], + ARRAY_SIZE(mt9m114_saturation[7]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[8], + ARRAY_SIZE(mt9m114_saturation[8]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[9], + ARRAY_SIZE(mt9m114_saturation[9]), 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, + {{mt9m114_saturation[10], + ARRAY_SIZE(mt9m114_saturation[10]), + 0, MSM_CAMERA_I2C_WORD_DATA}, + {mt9m114_refresh, + ARRAY_SIZE(mt9m114_refresh), 0, MSM_CAMERA_I2C_WORD_DATA},}, +}; + +static int mt9m114_saturation_enum_map[] = { + MSM_V4L2_SATURATION_L0, + MSM_V4L2_SATURATION_L1, + MSM_V4L2_SATURATION_L2, + MSM_V4L2_SATURATION_L3, + MSM_V4L2_SATURATION_L4, + MSM_V4L2_SATURATION_L5, + MSM_V4L2_SATURATION_L6, + MSM_V4L2_SATURATION_L7, + MSM_V4L2_SATURATION_L8, + MSM_V4L2_SATURATION_L9, + MSM_V4L2_SATURATION_L10, +}; + +static struct msm_camera_i2c_enum_conf_array mt9m114_saturation_enum_confs = { + .conf = &mt9m114_saturation_confs[0][0], + .conf_enum = mt9m114_saturation_enum_map, + .num_enum = ARRAY_SIZE(mt9m114_saturation_enum_map), + .num_index = ARRAY_SIZE(mt9m114_saturation_confs), + .num_conf = ARRAY_SIZE(mt9m114_saturation_confs[0]), + .data_type = MSM_CAMERA_I2C_WORD_DATA, +}; + +struct msm_sensor_v4l2_ctrl_info_t mt9m114_v4l2_ctrl_info[] = { + { + .ctrl_id = V4L2_CID_SATURATION, + .min = MSM_V4L2_SATURATION_L0, + .max = MSM_V4L2_SATURATION_L10, + .step = 1, + .enum_cfg_settings = &mt9m114_saturation_enum_confs, + .s_v4l2_ctrl = msm_sensor_s_ctrl_by_enum, + }, +}; + +static struct msm_sensor_output_info_t mt9m114_dimensions[] = { + { + .x_output = 0x500, + .y_output = 0x2D0, + .line_length_pclk = 0x500, + .frame_length_lines = 0x2D0, + .vt_pixel_clk = 48000000, + .op_pixel_clk = 128000000, + .binning_factor = 1, + }, +}; + +static struct msm_camera_csid_vc_cfg mt9m114_cid_cfg[] = { + {0, CSI_YUV422_8, CSI_DECODE_8BIT}, + {1, CSI_EMBED_DATA, CSI_DECODE_8BIT}, +}; + +static struct msm_camera_csi2_params mt9m114_csi_params = { + .csid_params = { + .lane_assign = 0xe4, + .lane_cnt = 1, + .lut_params = { + .num_cid = 2, + .vc_cfg = mt9m114_cid_cfg, + }, + }, + .csiphy_params = { + .lane_cnt = 1, + .settle_cnt = 0x14, + }, +}; + +static struct msm_camera_csi2_params *mt9m114_csi_params_array[] = { + &mt9m114_csi_params, + &mt9m114_csi_params, +}; + +static struct msm_sensor_output_reg_addr_t mt9m114_reg_addr = { + .x_output = 0xC868, + .y_output = 0xC86A, + .line_length_pclk = 0xC868, + .frame_length_lines = 0xC86A, +}; + +static struct msm_sensor_id_info_t mt9m114_id_info = { + .sensor_id_reg_addr = 0x0, + .sensor_id = 0x2481, +}; + +static int mt9m114_sensor_config(void __user *argp) +{ + return msm_sensor_config(&mt9m114_s_ctrl, argp); +} + +static int mt9m114_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + return msm_sensor_open_init(&mt9m114_s_ctrl, data); +} + +static int mt9m114_sensor_release(void) +{ + return msm_sensor_release(&mt9m114_s_ctrl); +} + +static const struct i2c_device_id mt9m114_i2c_id[] = { + {SENSOR_NAME, (kernel_ulong_t)&mt9m114_s_ctrl}, + { } +}; + +static struct i2c_driver mt9m114_i2c_driver = { + .id_table = mt9m114_i2c_id, + .probe = msm_sensor_i2c_probe, + .driver = { + .name = SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client mt9m114_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static int mt9m114_sensor_v4l2_probe(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + return msm_sensor_v4l2_probe(&mt9m114_s_ctrl, info, sdev, s); +} + +static int mt9m114_probe(struct platform_device *pdev) +{ + return msm_sensor_register(pdev, mt9m114_sensor_v4l2_probe); +} + +struct platform_driver mt9m114_driver = { + .probe = mt9m114_probe, + .driver = { + .name = PLATFORM_DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_sensor_init_module(void) +{ + return platform_driver_register(&mt9m114_driver); +} + +static struct v4l2_subdev_core_ops mt9m114_subdev_core_ops = { + .s_ctrl = msm_sensor_v4l2_s_ctrl, + .queryctrl = msm_sensor_v4l2_query_ctrl, +}; + +static struct v4l2_subdev_video_ops mt9m114_subdev_video_ops = { + .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt, +}; + +static struct v4l2_subdev_ops mt9m114_subdev_ops = { + .core = &mt9m114_subdev_core_ops, + .video = &mt9m114_subdev_video_ops, +}; + +static struct msm_sensor_fn_t mt9m114_func_tbl = { + .sensor_start_stream = msm_sensor_start_stream, + .sensor_stop_stream = mt9m114_stop_stream, + .sensor_setting = msm_sensor_setting, + .sensor_set_sensor_mode = msm_sensor_set_sensor_mode, + .sensor_mode_init = msm_sensor_mode_init, + .sensor_get_output_info = msm_sensor_get_output_info, + .sensor_config = mt9m114_sensor_config, + .sensor_open_init = mt9m114_sensor_open_init, + .sensor_release = mt9m114_sensor_release, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_probe = msm_sensor_probe, +}; + +static struct msm_sensor_reg_t mt9m114_regs = { + .default_data_type = MSM_CAMERA_I2C_BYTE_DATA, + .start_stream_conf = mt9m114_config_change_settings, + .start_stream_conf_size = ARRAY_SIZE(mt9m114_config_change_settings), + .init_settings = &mt9m114_init_conf[0], + .init_size = ARRAY_SIZE(mt9m114_init_conf), + .mode_settings = &mt9m114_confs[0], + .output_settings = &mt9m114_dimensions[0], + .num_conf = ARRAY_SIZE(mt9m114_confs), +}; + +static struct msm_sensor_ctrl_t mt9m114_s_ctrl = { + .msm_sensor_reg = &mt9m114_regs, + .msm_sensor_v4l2_ctrl_info = mt9m114_v4l2_ctrl_info, + .num_v4l2_ctrl = ARRAY_SIZE(mt9m114_v4l2_ctrl_info), + .sensor_i2c_client = &mt9m114_sensor_i2c_client, + .sensor_i2c_addr = 0x90, + .sensor_output_reg_addr = &mt9m114_reg_addr, + .sensor_id_info = &mt9m114_id_info, + .cam_mode = MSM_SENSOR_MODE_INVALID, + .csi_params = &mt9m114_csi_params_array[0], + .msm_sensor_mutex = &mt9m114_mut, + .sensor_i2c_driver = &mt9m114_i2c_driver, + .sensor_v4l2_subdev_info = mt9m114_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(mt9m114_subdev_info), + .sensor_v4l2_subdev_ops = &mt9m114_subdev_ops, + .func_tbl = &mt9m114_func_tbl, +}; + +module_init(msm_sensor_init_module); +MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/sensors/ov2720.c b/drivers/media/video/msm_zsl/sensors/ov2720.c new file mode 100644 index 00000000000..70f5852c24c --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/ov2720.c @@ -0,0 +1,532 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_sensor.h" +#include "ov2720.h" +#define SENSOR_NAME "ov2720" +#define PLATFORM_DRIVER_NAME "msm_camera_ov2720" +#define ov2720_obj ov2720_##obj + +DEFINE_MUTEX(ov2720_mut); +static struct msm_sensor_ctrl_t ov2720_s_ctrl; + +static struct msm_camera_i2c_reg_conf ov2720_start_settings[] = { + {0x0100, 0x01}, +}; + +static struct msm_camera_i2c_reg_conf ov2720_stop_settings[] = { + {0x0100, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf ov2720_groupon_settings[] = { + {0x3208, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf ov2720_groupoff_settings[] = { + {0x3208, 0x10}, + {0x3208, 0xA0}, +}; + +static struct msm_camera_i2c_reg_conf ov2720_prev_settings[] = { + {0x3800, 0x00}, + {0x3801, 0x02}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x07}, + {0x3805, 0xA1}, + {0x3806, 0x04}, + {0x3807, 0x47}, + {0x3810, 0x00}, + {0x3811, 0x09}, + {0x3812, 0x00}, + {0x3813, 0x02}, + {0x3820, 0x80}, + {0x3821, 0x06}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3612, 0x0b}, + {0x3618, 0x04}, + {0x3a08, 0x01}, + {0x3a09, 0x50}, + {0x3a0a, 0x01}, + {0x3a0b, 0x18}, + {0x3a0d, 0x03}, + {0x3a0e, 0x03}, + {0x4520, 0x00}, + {0x4837, 0x1b}, + {0x3000, 0xff}, + {0x3001, 0xff}, + {0x3002, 0xf0}, + {0x3600, 0x08}, + {0x3621, 0xc0}, + {0x3632, 0xd2}, + {0x3633, 0x23}, + {0x3634, 0x54}, + {0x3f01, 0x0c}, + {0x5001, 0xc1}, + {0x3614, 0xf0}, + {0x3630, 0x2d}, + {0x370b, 0x62}, + {0x3706, 0x61}, + {0x4000, 0x02}, + {0x4002, 0xc5}, + {0x4005, 0x08}, + {0x404f, 0x84}, + {0x4051, 0x00}, + {0x5000, 0xcf}, + {0x3a18, 0x00}, + {0x3a19, 0x80}, + {0x3503, 0x03}, + {0x4521, 0x00}, + {0x5183, 0xb0}, + {0x5184, 0xb0}, + {0x5185, 0xb0}, + {0x370c, 0x0c}, + {0x3035, 0x10}, + {0x3036, 0x1e}, + {0x3037, 0x21}, + {0x303e, 0x19}, + {0x3038, 0x06}, + {0x3018, 0x04}, + {0x3000, 0x00}, + {0x3001, 0x00}, + {0x3002, 0x00}, + {0x3a0f, 0x40}, + {0x3a10, 0x38}, + {0x3a1b, 0x48}, + {0x3a1e, 0x30}, + {0x3a11, 0x90}, + {0x3a1f, 0x10}, + {0x4800, 0x24}, +}; + +static struct msm_camera_i2c_reg_conf ov2720_720_settings[] = { + {0x3800, 0x01}, + {0x3801, 0x4a}, + {0x3802, 0x00}, + {0x3803, 0xba}, + {0x3804, 0x06}, + {0x3805, 0x51+32}, + {0x3806, 0x03}, + {0x3807, 0x8d+24}, + {0x3810, 0x00}, + {0x3811, 0x05}, + {0x3812, 0x00}, + {0x3813, 0x02}, + {0x3820, 0x80}, + {0x3821, 0x06}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3612, 0x0b}, + {0x3618, 0x04}, + {0x3a08, 0x01}, + {0x3a09, 0x50}, + {0x3a0a, 0x01}, + {0x3a0b, 0x18}, + {0x3a0d, 0x03}, + {0x3a0e, 0x03}, + {0x4520, 0x00}, + {0x4837, 0x1b}, + {0x3000, 0xff}, + {0x3001, 0xff}, + {0x3002, 0xf0}, + {0x3600, 0x08}, + {0x3621, 0xc0}, + {0x3632, 0xd2}, + {0x3633, 0x23}, + {0x3634, 0x54}, + {0x3f01, 0x0c}, + {0x5001, 0xc1}, + {0x3614, 0xf0}, + {0x3630, 0x2d}, + {0x370b, 0x62}, + {0x3706, 0x61}, + {0x4000, 0x02}, + {0x4002, 0xc5}, + {0x4005, 0x08}, + {0x404f, 0x84}, + {0x4051, 0x00}, + {0x5000, 0xff}, + {0x3a18, 0x00}, + {0x3a19, 0x80}, + {0x3503, 0x13}, + {0x4521, 0x00}, + {0x5183, 0xb0}, + {0x5184, 0xb0}, + {0x5185, 0xb0}, + {0x370c, 0x0c}, + {0x3035, 0x10}, + {0x3036, 0x04}, + {0x3037, 0x61}, + {0x303e, 0x19}, + {0x3038, 0x06}, + {0x3018, 0x04}, + {0x3000, 0x00}, + {0x3001, 0x00}, + {0x3002, 0x00}, + {0x3a0f, 0x40}, + {0x3a10, 0x38}, + {0x3a1b, 0x48}, + {0x3a1e, 0x30}, + {0x3a11, 0x90}, + {0x3a1f, 0x10}, + {0x4800, 0x24}, +}; + +static struct msm_camera_i2c_reg_conf ov2720_vga_settings[] = { + {0x3800, 0x00}, + {0x3801, 0x0c}, + {0x3802, 0x00}, + {0x3803, 0x02}, + {0x3804, 0x07}, + {0x3805, 0x97+32}, + {0x3806, 0x04}, + {0x3807, 0x45+24}, + {0x3810, 0x00}, + {0x3811, 0x03}, + {0x3812, 0x00}, + {0x3813, 0x03}, + {0x3820, 0x80}, + {0x3821, 0x06}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3612, 0x0b}, + {0x3618, 0x04}, + {0x3a08, 0x01}, + {0x3a09, 0x50}, + {0x3a0a, 0x01}, + {0x3a0b, 0x18}, + {0x3a0d, 0x03}, + {0x3a0e, 0x03}, + {0x4520, 0x00}, + {0x4837, 0x1b}, + {0x3000, 0xff}, + {0x3001, 0xff}, + {0x3002, 0xf0}, + {0x3600, 0x08}, + {0x3621, 0xc0}, + {0x3632, 0xd2}, + {0x3633, 0x23}, + {0x3634, 0x54}, + {0x3f01, 0x0c}, + {0x5001, 0xc1}, + {0x3614, 0xf0}, + {0x3630, 0x2d}, + {0x370b, 0x62}, + {0x3706, 0x61}, + {0x4000, 0x02}, + {0x4002, 0xc5}, + {0x4005, 0x08}, + {0x404f, 0x84}, + {0x4051, 0x00}, + {0x5000, 0xff}, + {0x3a18, 0x00}, + {0x3a19, 0x80}, + {0x3503, 0x13}, + {0x4521, 0x00}, + {0x5183, 0xb0}, + {0x5184, 0xb0}, + {0x5185, 0xb0}, + {0x370c, 0x0c}, + {0x3035, 0x10}, + {0x3036, 0x04}, + {0x3037, 0x61}, + {0x303e, 0x19}, + {0x3038, 0x06}, + {0x3018, 0x04}, + {0x3000, 0x00}, + {0x3001, 0x00}, + {0x3002, 0x00}, + {0x3a0f, 0x40}, + {0x3a10, 0x38}, + {0x3a1b, 0x48}, + {0x3a1e, 0x30}, + {0x3a11, 0x90}, + {0x3a1f, 0x10}, + {0x4800, 0x24}, + {0x3500, 0x00}, + {0x3501, 0x17}, + {0x3502, 0xf0}, + {0x3508, 0x00}, + {0x3509, 0x20}, +}; + +static struct msm_camera_i2c_reg_conf ov2720_recommend_settings[] = { + {0x0103, 0x01}, + {0x3718, 0x10}, + {0x3702, 0x24}, + {0x373a, 0x60}, + {0x3715, 0x01}, + {0x3703, 0x2e}, + {0x3705, 0x10}, + {0x3730, 0x30}, + {0x3704, 0x62}, + {0x3f06, 0x3a}, + {0x371c, 0x00}, + {0x371d, 0xc4}, + {0x371e, 0x01}, + {0x371f, 0x0d}, + {0x3708, 0x61}, + {0x3709, 0x12}, +}; + +static struct v4l2_subdev_info ov2720_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static struct msm_camera_i2c_conf_array ov2720_init_conf[] = { + {&ov2720_recommend_settings[0], + ARRAY_SIZE(ov2720_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA} +}; + +static struct msm_camera_i2c_conf_array ov2720_confs[] = { + {&ov2720_prev_settings[0], + ARRAY_SIZE(ov2720_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}, + {&ov2720_vga_settings[0], + ARRAY_SIZE(ov2720_vga_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}, + {&ov2720_720_settings[0], + ARRAY_SIZE(ov2720_720_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}, +}; + +static struct msm_sensor_output_info_t ov2720_dimensions[] = { + { + .x_output = 0x78C, + .y_output = 0x444, + .line_length_pclk = 0x85c, + .frame_length_lines = 0x460, + .vt_pixel_clk = 72000000, + .op_pixel_clk = 72000000, + .binning_factor = 1, + }, + { + .x_output = 0x510, + .y_output = 0x278, + .line_length_pclk = 0x85c, + .frame_length_lines = 0x460, + .vt_pixel_clk = 72000000, + .op_pixel_clk = 72000000, + .binning_factor = 1, + }, + { + .x_output = 0x298, + .y_output = 0x1F2, + .line_length_pclk = 0x85c, + .frame_length_lines = 0x460, + .vt_pixel_clk = 72000000, + .op_pixel_clk = 72000000, + .binning_factor = 1, + }, +}; + +static struct msm_camera_csid_vc_cfg ov2720_cid_cfg[] = { + {0, CSI_RAW10, CSI_DECODE_10BIT}, + {1, CSI_EMBED_DATA, CSI_DECODE_8BIT}, +}; + +static struct msm_camera_csi2_params ov2720_csi_params = { + .csid_params = { + .lane_assign = 0xe4, + .lane_cnt = 2, + .lut_params = { + .num_cid = 2, + .vc_cfg = ov2720_cid_cfg, + }, + }, + .csiphy_params = { + .lane_cnt = 2, + .settle_cnt = 0x1B, + }, +}; + +static struct msm_camera_csi2_params *ov2720_csi_params_array[] = { + &ov2720_csi_params, + &ov2720_csi_params, + &ov2720_csi_params, +}; + +static struct msm_sensor_output_reg_addr_t ov2720_reg_addr = { + .x_output = 0x3808, + .y_output = 0x380a, + .line_length_pclk = 0x380c, + .frame_length_lines = 0x380e, +}; + +static struct msm_sensor_id_info_t ov2720_id_info = { + .sensor_id_reg_addr = 0x300A, + .sensor_id = 0x2720, +}; + +static struct msm_sensor_exp_gain_info_t ov2720_exp_gain_info = { + .coarse_int_time_addr = 0x3501, + .global_gain_addr = 0x3508, + .vert_offset = 6, +}; + +static int32_t ov2720_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl, + uint16_t gain, uint32_t line) +{ + uint32_t fl_lines, offset; + uint8_t int_time[3]; + fl_lines = + (s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider) / Q10; + offset = s_ctrl->sensor_exp_gain_info->vert_offset; + if (line > (fl_lines - offset)) + fl_lines = line + offset; + + s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines, fl_lines, + MSM_CAMERA_I2C_WORD_DATA); + int_time[0] = line >> 12; + int_time[1] = line >> 4; + int_time[2] = line << 4; + msm_camera_i2c_write_seq(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr-1, + &int_time[0], 3); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr, gain, + MSM_CAMERA_I2C_WORD_DATA); + s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl); + return 0; +} + +static int ov2720_sensor_config(void __user *argp) +{ + return msm_sensor_config(&ov2720_s_ctrl, argp); +} + +static int ov2720_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + return msm_sensor_open_init(&ov2720_s_ctrl, data); +} + +static int ov2720_sensor_release(void) +{ + return msm_sensor_release(&ov2720_s_ctrl); +} + +static const struct i2c_device_id ov2720_i2c_id[] = { + {SENSOR_NAME, (kernel_ulong_t)&ov2720_s_ctrl}, + { } +}; + +static struct i2c_driver ov2720_i2c_driver = { + .id_table = ov2720_i2c_id, + .probe = msm_sensor_i2c_probe, + .driver = { + .name = SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov2720_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static int ov2720_sensor_v4l2_probe(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + return msm_sensor_v4l2_probe(&ov2720_s_ctrl, info, sdev, s); +} + +static int ov2720_probe(struct platform_device *pdev) +{ + return msm_sensor_register(pdev, ov2720_sensor_v4l2_probe); +} + +struct platform_driver ov2720_driver = { + .probe = ov2720_probe, + .driver = { + .name = PLATFORM_DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_sensor_init_module(void) +{ + return platform_driver_register(&ov2720_driver); +} + +static struct v4l2_subdev_core_ops ov2720_subdev_core_ops; +static struct v4l2_subdev_video_ops ov2720_subdev_video_ops = { + .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt, +}; + +static struct v4l2_subdev_ops ov2720_subdev_ops = { + .core = &ov2720_subdev_core_ops, + .video = &ov2720_subdev_video_ops, +}; + +static struct msm_sensor_fn_t ov2720_func_tbl = { + .sensor_start_stream = msm_sensor_start_stream, + .sensor_stop_stream = msm_sensor_stop_stream, + .sensor_group_hold_on = msm_sensor_group_hold_on, + .sensor_group_hold_off = msm_sensor_group_hold_off, + .sensor_set_fps = msm_sensor_set_fps, + .sensor_write_exp_gain = ov2720_write_exp_gain, + .sensor_write_snapshot_exp_gain = ov2720_write_exp_gain, + .sensor_setting = msm_sensor_setting, + .sensor_set_sensor_mode = msm_sensor_set_sensor_mode, + .sensor_mode_init = msm_sensor_mode_init, + .sensor_get_output_info = msm_sensor_get_output_info, + .sensor_config = ov2720_sensor_config, + .sensor_open_init = ov2720_sensor_open_init, + .sensor_release = ov2720_sensor_release, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_probe = msm_sensor_probe, +}; + +static struct msm_sensor_reg_t ov2720_regs = { + .default_data_type = MSM_CAMERA_I2C_BYTE_DATA, + .start_stream_conf = ov2720_start_settings, + .start_stream_conf_size = ARRAY_SIZE(ov2720_start_settings), + .stop_stream_conf = ov2720_stop_settings, + .stop_stream_conf_size = ARRAY_SIZE(ov2720_stop_settings), + .group_hold_on_conf = ov2720_groupon_settings, + .group_hold_on_conf_size = ARRAY_SIZE(ov2720_groupon_settings), + .group_hold_off_conf = ov2720_groupoff_settings, + .group_hold_off_conf_size = + ARRAY_SIZE(ov2720_groupoff_settings), + .init_settings = &ov2720_init_conf[0], + .init_size = ARRAY_SIZE(ov2720_init_conf), + .mode_settings = &ov2720_confs[0], + .output_settings = &ov2720_dimensions[0], + .num_conf = ARRAY_SIZE(ov2720_confs), +}; + +static struct msm_sensor_ctrl_t ov2720_s_ctrl = { + .msm_sensor_reg = &ov2720_regs, + .sensor_i2c_client = &ov2720_sensor_i2c_client, + .sensor_i2c_addr = 0x6C, + .sensor_output_reg_addr = &ov2720_reg_addr, + .sensor_id_info = &ov2720_id_info, + .sensor_exp_gain_info = &ov2720_exp_gain_info, + .cam_mode = MSM_SENSOR_MODE_INVALID, + .csi_params = &ov2720_csi_params_array[0], + .msm_sensor_mutex = &ov2720_mut, + .sensor_i2c_driver = &ov2720_i2c_driver, + .sensor_v4l2_subdev_info = ov2720_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov2720_subdev_info), + .sensor_v4l2_subdev_ops = &ov2720_subdev_ops, + .func_tbl = &ov2720_func_tbl, +}; + +module_init(msm_sensor_init_module); +MODULE_DESCRIPTION("Omnivision 2MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/sensors/ov2720.h b/drivers/media/video/msm_zsl/sensors/ov2720.h new file mode 100644 index 00000000000..634515bab20 --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/ov2720.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +extern struct platform_driver ov2720_driver; diff --git a/drivers/media/video/msm_zsl/sensors/s5c73m3.c b/drivers/media/video/msm_zsl/sensors/s5c73m3.c new file mode 100644 index 00000000000..d339303d111 --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/s5c73m3.c @@ -0,0 +1,3888 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "msm.h" +#include "s5c73m3.h" +#include "msm_ispif.h" +#include +#include + +#define SENSOR_NAME "s5c73m3" +#define PLATFORM_DRIVER_NAME "msm_camera_s5c73m3" +#define CAMERA_FLASH_OFF 0 +#define CAMERA_FLASH_ON 1 +#define CAMERA_FLASH_AUTO 2 +#define CAMERA_FLASH_TORCH 3 + +#define S5C73M3_FW_PATH "/mnt/sdcard/SlimISP.bin" +#define S5C73M3_FW_REQUEST_PATH "/system/cameradata/" +#define S5C73M3_FW_REQUEST_SECOND_PATH "/data/" + +#define MOVIEMODE_FLASH 17 +#define FLASHMODE_FLASH 18 + +#define ERROR 1 + +#define IN_AUTO_MODE 1 +#define IN_MACRO_MODE 2 + +#undef QC_TEST + +/*#define YUV_PREVIEW*/ +#define SPI_DMA_MODE + +static uint32_t op_pixel_clk1; +const int camcorder_30fps = 30; + +struct s5c73m3_work { + struct work_struct work; +}; + +static struct s5c73m3_work *s5c73m3_sensorw; +static struct i2c_client *s5c73m3_client; + +struct s5c73m3_ctrl { + const struct msm_camera_sensor_info *sensordata; + struct v4l2_subdev *sensor_dev; + + int op_mode; + int dtp_mode; + int app_mode; + int vtcall_mode; + int started; + int isCapture; + int flash_mode; + int hdr_mode; + int low_light_mode; + int low_light_mode_size; + int jpeg_size; + int preview_size; + int preview_size_width; + int preview_size_height; + int wide_preview; + int i2c_write_check; + int wb; + int scene; + int fps; + bool isAeLock; + bool isAwbLock; + bool camcorder_mode; + bool vdis_mode; + bool anti_shake_mode; + int record_size_width; + int record_size_height; + int fw_index; + int zoomPreValue; + + u8 sensor_fw[10]; + u8 phone_fw[10]; + u32 crc_table[256]; + u32 sensor_size; +}; + +static unsigned int config_csi2; +static struct s5c73m3_ctrl *s5c73m3_ctrl; + +struct s5c73m3_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; +static int32_t s5c73m3_sensor_setting(int update_type, int rt); +static int s5c73m3_set_touch_auto_focus(void); +static int s5c73m3_wait_ISP_status(void); +static int s5c73m3_set_fps(int fps); +static int s5c73m3_set_af_mode(int val); +static int s5c73m3_open_firmware_file(const char *filename, + u8 *buf, u16 offset, u16 size); + + +static DECLARE_WAIT_QUEUE_HEAD(s5c73m3_wait_queue); + + +static char *Fbuf; /*static QCTK*/ +static char FW_buf[409600] = {0}; /*static QCTK 400KB*/ + +#define CHECK_ERR(x) if ((x) < 0) { \ + cam_err("i2c failed, err %d\n", x); \ + return x; \ + } + +static char fw_path[40] = {0}; +static char fw_path_in_data[40] = {0}; +struct s5c73m3_fw_version camfw_info[S5C73M3_PATH_MAX]; + +static int s5c73m3_i2c_write(unsigned short addr, unsigned short data) +{ + unsigned char buf[4]; + int i, err; + int retry_count = 5; + struct i2c_msg msg = {s5c73m3_client->addr, 0, sizeof(buf), buf}; + + if (!s5c73m3_client->adapter) { + cam_err("s5c73m3_client->adapter is not!!\n"); + return -EIO; + } + + buf[0] = addr >> 8; + buf[1] = addr & 0xff; + buf[2] = data >> 8; + buf[3] = data & 0xff; + + cam_i2c_dbg("addr %#x, data %#x\n", addr, data); + + for (i = retry_count; i; i--) { + err = i2c_transfer(s5c73m3_client->adapter, &msg, 1); + if (err == 1) + break; + + msleep(20); + } + + if (err != 1) { + cam_err("fail i2c_transfer!!\n"); + err = -EIO; + return err; + } + + return err; +} + +static void s5c73m3_i2c_write_check(void) +{ + int index = 0; + + do { + if (s5c73m3_ctrl->i2c_write_check == 1) { + cam_err("i2c is writing now!!, index : %d\n", index); + index++; + usleep(1*1000); + } else + break; + + } while (index < 20); + + if (index == 20) { + cam_err("error index : %d\n", index); + s5c73m3_ctrl->i2c_write_check = 0; + } +} + +static int s5c73m3_i2c_write_block(const u32 regs[], int size) +{ + int i, err = 0; + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + for (i = 0; i < size; i++) { + err = s5c73m3_i2c_write((regs[i]>>16), regs[i]); + if (err < 0) { + s5c73m3_ctrl->i2c_write_check = 0; + cam_err("fail s5c73m3_i2c_write!!\n"); + break; + } + } + s5c73m3_ctrl->i2c_write_check = 0; + return err; +} + +static int s5c73m3_i2c_read(unsigned short addr, unsigned short *data) +{ + unsigned char buf[2]; + int i, err; + int retry_count = 5; + struct i2c_msg msg = {s5c73m3_client->addr, 0, sizeof(buf), buf}; + + if (!s5c73m3_client->adapter) { + cam_err("s5c73m3_client->adapter is not!!\n"); + return -ENODEV; + } + + buf[0] = addr >> 8; + buf[1] = addr & 0xff; + + for (i = retry_count; i; i--) { + err = i2c_transfer(s5c73m3_client->adapter, &msg, 1); + if (err == 1) + break; + + msleep(20); + } + + if (err != 1) { + cam_err("fail i2c_transfer!!\n"); + err = -EIO; + return err; + } + + msg.flags = I2C_M_RD; + + for (i = retry_count; i; i--) { + err = i2c_transfer(s5c73m3_client->adapter, &msg, 1); + if (err == 1) + break; + msleep(20); + } + + if (err != 1) { + cam_err("fail i2c_transfer!!\n"); + err = -EIO; + return err; + } + + *data = ((buf[0] << 8) | buf[1]); + + return err; +} + +static int s5c73m3_writeb(unsigned short addr, unsigned short data) +{ + int err; + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + + err = s5c73m3_i2c_write(0x0050, 0x0009); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, 0x5000); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, addr); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, data); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, 0x5080); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, 0x0001); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + + s5c73m3_ctrl->i2c_write_check = 0; + + return err; +} + +static int s5c73m3_write(unsigned short addr1, + unsigned short addr2, unsigned short data) +{ + int err; + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + + err = s5c73m3_i2c_write(0x0050, addr1); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, addr2); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, data); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + + s5c73m3_ctrl->i2c_write_check = 0; + + return err; +} + +static int s5c73m3_read(unsigned short addr1, + unsigned short addr2, unsigned short *data) +{ + int err; + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + + err = s5c73m3_i2c_write(0xfcfc, 0x3310); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0058, addr1); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x005C, addr2); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_read(0x0F14, data); + if (err < 0) + cam_err("fail s5c73m3_i2c_read!!\n"); + + s5c73m3_ctrl->i2c_write_check = 0; + + return err; +} + +static int s5c73m3_set_timing_register_for_vdd(void) +{ + int err = 0; + + err = s5c73m3_write(0x3010, 0x0018, 0x0618); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x001C, 0x10C1); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x0020, 0x249E); + CHECK_ERR(err); + + return err; +} + +static int s5c73m3_i2c_check_status_with_CRC(void) +{ + int err = 0; + int index = 0; + u16 status = 0; + u16 i2c_status = 0; + u16 i2c_seq_status = 0; + + do { + err = s5c73m3_read(0x0009, S5C73M3_STATUS, &status); + err = s5c73m3_read(0x0009, + S5C73M3_I2C_ERR_STATUS, &i2c_status); + if (i2c_status & ERROR_STATUS_CHECK_BIN_CRC) { + CAM_DBG_M("failed to check CRC value of ISP Ram\n"); + err = -1; + break; + } + + if (status == 0xffff) + break; + + index++; + udelay(500); + } while (index < 2000); /* 1 sec */ + + if (index >= 2000) { + err = s5c73m3_read(0x0009, + S5C73M3_I2C_ERR_STATUS, &i2c_status); + err = s5c73m3_read(0x0009, + S5C73M3_I2C_SEQ_STATUS, &i2c_seq_status); + CAM_DBG_M("TimeOut!! index:%d,status:%#x\n", + index, + status); + CAM_DBG_M("i2c_stauts:%#x,i2c_seq_status:%#x\n", + i2c_status, + i2c_seq_status); + + err = -1; + } + + return err; +} + +void s5c73m3_make_CRC_table(u32 *table, u32 id) +{ + u32 i, j, k; + + for (i = 0; i < 256; ++i) { + k = i; + for (j = 0; j < 8; ++j) { + if (k & 1) + k = (k >> 1) ^ id; + else + k >>= 1; + } + table[i] = k; + } +} + +static int s5c73m3_reset_module(bool powerReset) +{ + int err = 0; + + CAM_DBG_M("E\n"); + + if (powerReset) { + s5c73m3_ctrl->sensordata->sensor_platform_info \ + ->sensor_power_off(0); + s5c73m3_ctrl->sensordata->sensor_platform_info \ + ->sensor_power_on(0, 0); + s5c73m3_ctrl->sensordata->sensor_platform_info \ + ->sensor_power_on(0, 1); + } else { + s5c73m3_ctrl->sensordata->sensor_platform_info \ + ->sensor_isp_reset(); + } + + err = s5c73m3_set_timing_register_for_vdd(); + CHECK_ERR(err); + + CAM_DBG_M("X\n"); + + return err; +} + +void s5c73m3_sensor_reset(void) +{ + s5c73m3_ctrl->sensordata->sensor_platform_info->sensor_isp_reset(); +} + +static int s5c73m3_wait_ISP_status(void) +{ + int err = 0; + u16 stream_status = 0; + int index = 0; + + CAM_DBG_H("Entered\n"); + + /*Waiting until ISP will be prepared*/ + do { + err = s5c73m3_read(0x0009, 0x5080, &stream_status); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_H("stream_status1 = 0x%#x\n", stream_status); + + if (stream_status == 0xffff) + break; + + ++index; + CAM_DBG_H("Waiting until to finish handling a command" + "in ISP =====>> %d\n", index); + usleep(500); /* Just for test delay */ + + } while (index < 400); + + if (index == 400) { + cam_err("FAIL : ISP has been not prepared!! : 0x%#x\n", + stream_status); + + err = s5c73m3_read(0x0009, 0x599E, &stream_status); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + cam_err("0009_599E = 0x%#x\n", stream_status); + + err = s5c73m3_read(0x0009, 0x59A6, &stream_status); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + cam_err("0009_59A6 = 0x%#x\n", stream_status); + + return -EIO; + } + + return err; +} + +void s5c73m3_jpeg_update(void) +{ + CAM_DBG_H("Entered\n"); + +} +#if 0 +static int s5c73m3_sensor_af_status(void) +{ + CAM_DBG_H("Entered\n"); + return 0; +} +static int s5c73m3_sensor_af_result(void) +{ + + CAM_DBG_H("Entered\n"); + return 0; +} + +#endif +static int s5c73m3_set_antibanding(int val) +{ + int err = 0; + int antibanding_mode = 0; + + CAM_DBG_M("E, value %d\n", val); + + switch (val) { + case ANTI_BANDING_OFF: + antibanding_mode = S5C73M3_FLICKER_NONE; + break; + case ANTI_BANDING_50HZ: + antibanding_mode = S5C73M3_FLICKER_AUTO_50HZ; + break; + case ANTI_BANDING_60HZ: + antibanding_mode = S5C73M3_FLICKER_AUTO_60HZ; + break; + case ANTI_BANDING_AUTO: + default: + antibanding_mode = S5C73M3_FLICKER_AUTO; + break; + + } + + err = s5c73m3_writeb(S5C73M3_FLICKER_MODE, antibanding_mode); + CHECK_ERR(err); + + return err; +} + +static int s5c73m3_set_flash(int val) +{ + int err; + CAM_DBG_H("E, value %d\n", val); + +retry: + switch (val) { + case MAIN_CAMERA_FLASH_OFF: + err = s5c73m3_writeb(S5C73M3_FLASH_MODE, + S5C73M3_FLASH_MODE_OFF); + CHECK_ERR(err); + err = s5c73m3_writeb(S5C73M3_FLASH_TORCH, + S5C73M3_FLASH_TORCH_OFF); + CHECK_ERR(err); + break; + + case MAIN_CAMERA_FLASH_AUTO: + err = s5c73m3_writeb(S5C73M3_FLASH_TORCH, + S5C73M3_FLASH_TORCH_OFF); + CHECK_ERR(err); + err = s5c73m3_writeb(S5C73M3_FLASH_MODE, + S5C73M3_FLASH_MODE_AUTO); + CHECK_ERR(err); + break; + + case MAIN_CAMERA_FLASH_ON: + err = s5c73m3_writeb(S5C73M3_FLASH_TORCH, + S5C73M3_FLASH_TORCH_OFF); + CHECK_ERR(err); + err = s5c73m3_writeb(S5C73M3_FLASH_MODE, + S5C73M3_FLASH_MODE_ON); + CHECK_ERR(err); + break; + + case MAIN_CAMERA_FLASH_TORCH: + err = s5c73m3_writeb(S5C73M3_FLASH_MODE, + S5C73M3_FLASH_MODE_OFF); + CHECK_ERR(err); + err = s5c73m3_writeb(S5C73M3_FLASH_TORCH, + S5C73M3_FLASH_TORCH_ON); + CHECK_ERR(err); + break; + + default: + cam_err("invalid value, %d\n", val); + val = CAMERA_FLASH_OFF; + goto retry; + } + flash_mode = val; + + CAM_DBG_H("X\n"); + return 0; +} + +static int s5c73m3_set_preview(void) +{ + CAM_DBG_H("Entered\n"); + return 0; +} + +static int s5c73m3_set_capture(void) +{ + int32_t rc = 0; + CAM_DBG_H("Entered\n"); + /*frame capture*/ + s5c73m3_ctrl->isCapture = 1; + if (s5c73m3_sensor_setting(UPDATE_PERIODIC, RES_CAPTURE) < 0) { + cam_err("fail s5c73m3_sensor_setting fullsize!!\n"); + return rc; +} + + return rc; +} + +bool s5c73m3_CAF_enabled(void) +{ + bool val = false; + + CAM_DBG_H("Entered\n"); + + if (camera_focus.mode >= + FOCUS_MODE_CONTINOUS && + camera_focus.mode <= + FOCUS_MODE_CONTINOUS_VIDEO) { + val = true; + } + + return val; +} + +static int s5c73m3_s_stream_preview(int enable, int rt) +{ + int err = 0; + + CAM_DBG_M("Entered, enable %d\n", enable); + + if (enable) { + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } +#if defined(YUV_PREVIEW) + CAM_DBG_M("YUV_PREVIEW\n"); + err = s5c73m3_i2c_write_block(S5C73M3_YUV_PREVIEW, + sizeof(S5C73M3_YUV_PREVIEW)/ + sizeof(S5C73M3_YUV_PREVIEW[0])); + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } +#else + switch (rt) { /*nishu rhint*/ + case RES_PREVIEW: + CAM_DBG_H("Camcorder Interleaved Preview\n"); + if ((s5c73m3_ctrl->record_size_width >= 1920) && + (s5c73m3_ctrl->record_size_height >= 1080)) { + if (s5c73m3_ctrl->vdis_mode == true) { + CAM_DBG_M("FHD VDIS preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_FHD_VDIS, + sizeof(S5C73M3_FHD_VDIS)/ + sizeof(S5C73M3_FHD_VDIS[0])); + } else { + CAM_DBG_M("FHD Normal preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_FHD, + sizeof(S5C73M3_FHD)/ + sizeof(S5C73M3_FHD[0])); + } + } else if ((s5c73m3_ctrl->record_size_width >= 1280) || + (s5c73m3_ctrl->record_size_height >= 720)) { + if (s5c73m3_ctrl->vdis_mode == true) { + CAM_DBG_M("HD VDIS preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_HD_VDIS, + sizeof(S5C73M3_HD_VDIS)/ + sizeof(S5C73M3_HD_VDIS[0])); + } else { + CAM_DBG_M("HD Normal preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_HD, + sizeof(S5C73M3_HD)/ + sizeof(S5C73M3_HD[0])); + } + } else { + if (s5c73m3_ctrl->wide_preview) { + CAM_DBG_M("WVGA preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_WVGA, + sizeof(S5C73M3_WVGA)/ + sizeof(S5C73M3_WVGA[0])); + } else { + CAM_DBG_M("VGA preview\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_VGA, + sizeof(S5C73M3_VGA)/ + sizeof(S5C73M3_VGA[0])); + } + } + + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MOVIE_CAF_START); + + s5c73m3_set_fps(camcorder_30fps); + /* Set VFE to turbo mode */ + op_pixel_clk1 = 320000000; + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_PCLK_CHANGE, &op_pixel_clk1); + break; + + case RES_CAPTURE: + CAM_DBG_M("Camera Interleaved Preview\n"); + + if (s5c73m3_ctrl->hdr_mode == 1) { + CAM_DBG_H("Start HDR\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_HDR, + sizeof(S5C73M3_HDR)/ + sizeof(S5C73M3_HDR[0]) + ); + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } + + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } else if (s5c73m3_ctrl->low_light_mode_size == 1) { + CAM_DBG_H("Start Low Light Shot\n"); + err = s5c73m3_i2c_write_block( + S5C73M3_LLS, + sizeof(S5C73M3_LLS)/ + sizeof(S5C73M3_LLS[0]) + ); + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } + + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } else { + CAM_DBG_M("preview_size : %x\n", + s5c73m3_ctrl->preview_size); + CAM_DBG_M("jpeg_size : %x\n", + s5c73m3_ctrl->jpeg_size); + err = s5c73m3_i2c_write_block( + S5C73M3_PREVIEW, + sizeof(S5C73M3_PREVIEW)/ + sizeof(S5C73M3_PREVIEW[0])); + + err = s5c73m3_writeb(S5C73M3_CHG_MODE, + S5C73M3_YUV_MODE | + s5c73m3_ctrl->preview_size | + s5c73m3_ctrl->jpeg_size); + } + + err = s5c73m3_writeb(S5C73M3_SENSOR_STREAMING, + S5C73M3_SENSOR_STREAMING_ON); + + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + + /* Set VFE to turbo mode */ + op_pixel_clk1 = 320000000; + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_PCLK_CHANGE, &op_pixel_clk1); + break; + + default: + err = -1; + break; + + }; + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } +#endif + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } + + return err; +} + + +static int s5c73m3_sensor_setting(int update_type, int rt) +{ + int32_t rc = 0; +#ifdef QC_TEST + int index = 0; + u16 stream_status = 0; + u16 temp, temp1, temp2, temp3 = 0; +#endif + struct msm_camera_csid_params s5c73m3_csid_params; + struct msm_camera_csiphy_params s5c73m3_csiphy_params; + + CAM_DBG_M("Entered\n"); + + switch (update_type) { + case REG_INIT: + break; + + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + CAM_DBG_H("UPDATE_PERIODIC\n"); +#if defined(YUV_PREVIEW) + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_OFF_IMMEDIATELY)); +#endif + +#ifdef QC_TEST + do { + rc = s5c73m3_read( + 0x0009, 0x5804, &stream_status); + if (rc < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_M("#####1stream_status : %x\n", + stream_status); + index++; + msleep(30); + } while (index < 10); +#endif + + if (config_csi2 == 0) { + struct msm_camera_csid_vc_cfg + s5c73m3_vccfg[] = { + {0, 0x1E, CSI_DECODE_8BIT}, + {1, CSI_EMBED_DATA, CSI_DECODE_8BIT}, +#if !defined(YUV_PREVIEW) + {2, 0x30, CSI_DECODE_8BIT}, +#endif + }; + s5c73m3_csid_params.lane_cnt = 4; + s5c73m3_csid_params.lane_assign = 0xe4; + s5c73m3_csid_params.lut_params.num_cid = + ARRAY_SIZE(s5c73m3_vccfg); + s5c73m3_csid_params.lut_params.vc_cfg = + &s5c73m3_vccfg[0]; + s5c73m3_csiphy_params.lane_cnt = 4; + s5c73m3_csiphy_params.settle_cnt = 0x27; + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_CSID_CFG, + &s5c73m3_csid_params); + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_CID_CHANGE, NULL); + mb(); + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_CSIPHY_CFG, + &s5c73m3_csiphy_params); + mb(); + /*s5c73m3_delay_msecs_stdby*/ + /*msleep(20);*/ + config_csi2 = 1; + } + + if (rc < 0) { + cam_err("fail!!\n"); + return rc; + } + + rc = s5c73m3_s_stream_preview(1, rt); + if (rc < 0) { + cam_err("failed s5c73m3_s_stream_preview!!\n"); + return -EIO; + } + +#if defined(YUV_PREVIEW) + v4l2_subdev_notify(s5c73m3_ctrl->sensor_dev, + NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM( + PIX0, ISPIF_ON_FRAME_BOUNDARY)); +#endif + +#ifdef QC_TEST + do { + rc = s5c73m3_read(0x0009, 0x5804, + &stream_status); + if (rc < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_M("#####2stream_status : %x\n", + stream_status); + index++; + msleep(30); + } while (index < 20); + + rc = s5c73m3_read(0x0009, 0x583C, &stream_status); + if (rc < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_M("#####0x583C : %x\n", + stream_status); + + s5c73m3_read(0x2A00, 0x0060, &temp); + CAM_DBG_M("### 1 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x0064, &temp); + CAM_DBG_M("### 2 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x008C, &temp); + CAM_DBG_M("### 3 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x0090, &temp); + CAM_DBG_M("### 4 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x01CC, &temp); + CAM_DBG_M("### 5 value : %#x\n", temp); + s5c73m3_read(0x2A00, 0x002C, &temp1); + s5c73m3_read(0x2A00, 0x0030, &temp2); + s5c73m3_read(0x2A00, 0x0034, &temp3); + temp = (temp1<<16)|(temp2<<8)|temp3; + CAM_DBG_M("### jpeg size : %#x\n", temp); + + s5c73m3_read(0x2A00, 0x0100, &temp); + CAM_DBG_M("### preview buffer : %#x\n", temp); + + s5c73m3_read(0x2A00, 0x0104, &temp); + CAM_DBG_M("### jpeg buffer : %#x\n", temp); + +#endif + if (s5c73m3_CAF_enabled()) + s5c73m3_set_af_mode(camera_focus.mode); + + } + break; + default: + cam_err("fail!!\n"); + rc = -EINVAL; + break; + } + + CAM_DBG_M("sensor setting is done!!\n"); + return rc; +} + +static int s5c73m3_video_config(int mode) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, mode %d\n", mode); + + if (s5c73m3_sensor_setting(UPDATE_PERIODIC, RES_PREVIEW) < 0) { + cam_err("fail s5c73m3_sensor_setting!!\n"); + return rc; + } + + return rc; +} + +static int s5c73m3_set_sensor_mode(int mode) +{ + int err = 0; + CAM_DBG_M("Entered, mode %d\n", mode); + + switch (mode) { + case SENSOR_PREVIEW_MODE: + case SENSOR_VIDEO_MODE: + s5c73m3_ctrl->camcorder_mode = true; + if (s5c73m3_ctrl->isCapture == 1) { + s5c73m3_ctrl->isCapture = 0; + err = s5c73m3_set_preview(); + if (err < 0) { + cam_err("fail s5c73m3_set_preview!!\n"); + return err; + } + } + + err = s5c73m3_video_config(mode); + if (err < 0) { + cam_err("fail s5c73m3_video_config!!\n"); + return err; + } + break; + + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + s5c73m3_ctrl->camcorder_mode = false; + err = s5c73m3_set_capture(); + if (err < 0) { + cam_err("fail s5c73m3_set_capture!!\n"); + return err; + } + break; + + default: + return 0; + } + return 0; +} + +static int s5c73m3_set_effect(int effect) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, effect %d\n", effect); + switch (effect) { + case CAMERA_EFFECT_OFF: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_NONE); + break; + + case CAMERA_EFFECT_MONO: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_MONO); + break; + + case CAMERA_EFFECT_NEGATIVE: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_NEGATIVE); + break; + + case CAMERA_EFFECT_SEPIA: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_SEPIA); + break; + + case CAMERA_EFFECT_WASHED: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_WASHED); + break; + + case CAMERA_EFFECT_VINTAGE_WARM: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_VINTAGE_WARM); + break; + + case CAMERA_EFFECT_VINTAGE_COLD: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_VINTAGE_COLD); + break; + + case CAMERA_EFFECT_SOLARIZE: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_SOLARIZE); + break; + + case CAMERA_EFFECT_POSTERIZE: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POSTERIZE); + break; + + case CAMERA_EFFECT_POINT_COLOR_1: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POINT_COLOR_1); + break; + + case CAMERA_EFFECT_POINT_COLOR_2: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POINT_COLOR_2); + break; + + case CAMERA_EFFECT_POINT_COLOR_3: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POINT_COLOR_3); + break; + + case CAMERA_EFFECT_POINT_COLOR_4: + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_POINT_COLOR_4); + break; + + default: + CAM_DBG_M("default effect\n"); + rc = s5c73m3_writeb(S5C73M3_IMAGE_EFFECT, + S5C73M3_IMAGE_EFFECT_NONE); + return 0; +} + return rc; +} + +static int s5c73m3_set_whitebalance(int wb) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, %d\n", wb); + + switch (wb) { + case CAMERA_WHITE_BALANCE_AUTO: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_AUTO); + break; + + case CAMERA_WHITE_BALANCE_INCANDESCENT: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_INCANDESCENT); + break; + + case CAMERA_WHITE_BALANCE_FLUORESCENT: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_FLUORESCENT1); + break; + + case CAMERA_WHITE_BALANCE_DAYLIGHT: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_DAYLIGHT); + break; + + case CAMERA_WHITE_BALANCE_CLOUDY_DAYLIGHT: + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_CLOUDY); + break; + + default: + CAM_DBG_M("default WB mode\n"); + rc = s5c73m3_writeb(S5C73M3_AWB_MODE, + S5C73M3_AWB_MODE_AUTO); + break; + } + s5c73m3_ctrl->wb = wb; + + return rc; +} + +static int s5c73m3_set_ev(int ev) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, ev %d\n", ev); + + switch (ev) { + case CAMERA_EV_M4: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_M20); + break; + + case CAMERA_EV_M3: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_M15); + break; + + case CAMERA_EV_M2: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_M10); + break; + + case CAMERA_EV_M1: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_M05); + break; + + case CAMERA_EV_DEFAULT: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_ZERO); + break; + + case CAMERA_EV_P1: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_P05); + break; + + case CAMERA_EV_P2: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_P10); + break; + + case CAMERA_EV_P3: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_P15); + break; + + case CAMERA_EV_P4: + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_P20); + break; + + default: + CAM_DBG_M("default ev mode\n"); + rc = s5c73m3_writeb(S5C73M3_EV, + S5C73M3_EV_ZERO); + break; + } + return rc; +} + +static int s5c73m3_set_scene_mode(int mode) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, mode %d\n", mode); + + switch (mode) { + case CAMERA_SCENE_AUTO: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_NONE); + break; + + case CAMERA_SCENE_LANDSCAPE: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_LANDSCAPE); + break; + + case CAMERA_SCENE_DAWN: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_DAWN); + break; + + case CAMERA_SCENE_BEACH: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_BEACH); + break; + + case CAMERA_SCENE_SUNSET: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_SUNSET); + break; + + case CAMERA_SCENE_NIGHT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_NIGHT); + break; + + case CAMERA_SCENE_PORTRAIT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_PORTRAIT); + break; + + case CAMERA_SCENE_AGAINST_LIGHT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_AGAINSTLIGHT); + break; + + case CAMERA_SCENE_SPORT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_SPORTS); + break; + + case CAMERA_SCENE_FALL: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_FALL); + break; + + case CAMERA_SCENE_TEXT: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_TEXT); + break; + + case CAMERA_SCENE_CANDLE: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_CANDLE); + break; + + case CAMERA_SCENE_FIRE: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_FIRE); + break; + + case CAMERA_SCENE_PARTY: + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_INDOOR); + break; + + default: + CAM_DBG_M("default scene mode\n"); + rc = s5c73m3_writeb(S5C73M3_SCENE_MODE, + S5C73M3_SCENE_MODE_NONE); + break; + } + s5c73m3_ctrl->scene = mode; + + return rc; +} + +static int s5c73m3_set_iso(int iso) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, iso %d\n", iso); + switch (iso) { + case CAMERA_ISO_MODE_AUTO: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_AUTO); + break; + + case CAMERA_ISO_MODE_100: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_100); + break; + + case CAMERA_ISO_MODE_200: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_200); + break; + + case CAMERA_ISO_MODE_400: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_400); + break; + + case CAMERA_ISO_MODE_800: + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_800); + break; + + default: + CAM_DBG_M("default iso mode\n"); + rc = s5c73m3_writeb(S5C73M3_ISO, + S5C73M3_ISO_AUTO); + break; + } + return rc; +} + +static int s5c73m3_set_metering(int mode) +{ + int32_t rc = 0; + + CAM_DBG_H("Entered, mode %d\n", mode); + switch (mode) { + case CAMERA_CENTER_WEIGHT: + rc = s5c73m3_writeb(S5C73M3_METER, + S5C73M3_METER_CENTER); + break; + + case CAMERA_AVERAGE: + rc = s5c73m3_writeb(S5C73M3_METER, + S5C73M3_METER_AVERAGE); + break; + + case CAMERA_SPOT: + rc = s5c73m3_writeb(S5C73M3_METER, + S5C73M3_METER_SPOT); + break; + + default: + CAM_DBG_M("default metering mode\n"); + rc = s5c73m3_writeb(S5C73M3_METER, + S5C73M3_METER_CENTER); + break; + } + return rc; +} + +static int s5c73m3_set_zoom(int level) +{ + int32_t rc = 0; + int err; + int diff = 0; + + CAM_DBG_H("Entered, zoom %d\n", level); + +retry: + if (level < 0 || level > 30) { + cam_err("invalid value, %d\n", level); + level = 0; + s5c73m3_ctrl->zoomPreValue = 0; + goto retry; + } + + if (s5c73m3_ctrl->zoomPreValue > level) + diff = s5c73m3_ctrl->zoomPreValue - level; + else + diff = level - s5c73m3_ctrl->zoomPreValue; + + if (diff > 2) { + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } else + usleep(10*1000); + + s5c73m3_ctrl->zoomPreValue = level; + + err = s5c73m3_i2c_write(0x0050, 0x0009); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, 0x5000); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, S5C73M3_ZOOM_STEP); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, level); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0054, 0x5080); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + err = s5c73m3_i2c_write(0x0F14, 0x0001); + if (err < 0) + cam_err("fail s5c73m3_i2c_write!!\n"); + + + if (rc < 0) { + cam_err("fail s5c73m3_zoom!!\n"); + return rc; + } + + return rc; +} + +static int s5c73m3_set_jpeg_quality(int quality) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, quality %d\n", quality); + + if (quality <= 80) /* LOW for camcorder */ + rc = s5c73m3_writeb(S5C73M3_IMAGE_QUALITY, + S5C73M3_IMAGE_QUALITY_LOW); + else if (quality <= 90) /* Normal */ + rc = s5c73m3_writeb(S5C73M3_IMAGE_QUALITY, + S5C73M3_IMAGE_QUALITY_NORMAL); + else if (quality <= 95) /* Fine */ + rc = s5c73m3_writeb(S5C73M3_IMAGE_QUALITY, + S5C73M3_IMAGE_QUALITY_FINE); + else /* Superfine */ + rc = s5c73m3_writeb(S5C73M3_IMAGE_QUALITY, + S5C73M3_IMAGE_QUALITY_SUPERFINE); + + if (rc < 0) { + cam_err("fail s5c73m3_quality!!\n"); + return rc; + } + + return rc; +} + +static int s5c73m3_set_face_detection(int val) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, Face detection %d\n", val); + +retry: + switch (val) { + case FACE_DETECTION_ON: + rc = s5c73m3_writeb(S5C73M3_FACE_DET, + S5C73M3_FACE_DET_ON); + break; + + case FACE_DETECTION_OFF: + rc = s5c73m3_writeb(S5C73M3_FACE_DET, + S5C73M3_FACE_DET_OFF); + break; + + default: + cam_err("invalid value, %d\n", val); + val = FACE_DETECTION_OFF; + goto retry; + } + + return rc; +} + +static int s5c73m3_aeawb_lock_unlock(int32_t ae_lock, int32_t awb_lock) +{ + int err = 0; + + CAM_DBG_H("Entered, wb :%d\n", s5c73m3_ctrl->wb); + + if (ae_lock) { + CAM_DBG_M("ae lock"); + err = s5c73m3_writeb(S5C73M3_AE_CON, S5C73M3_AE_STOP); + CHECK_ERR(err); + s5c73m3_ctrl->isAeLock = true; + } else { + CAM_DBG_M("ae unlock"); + err = s5c73m3_writeb(S5C73M3_AE_CON, S5C73M3_AE_START); + CHECK_ERR(err); + s5c73m3_ctrl->isAeLock = false; + } + + if (s5c73m3_ctrl->wb == CAMERA_WHITE_BALANCE_AUTO && + s5c73m3_ctrl->scene != CAMERA_SCENE_SUNSET && + s5c73m3_ctrl->scene != CAMERA_SCENE_DAWN && + s5c73m3_ctrl->scene != CAMERA_SCENE_CANDLE) { + if (awb_lock) { + CAM_DBG_M("awb lock"); + err = s5c73m3_writeb(S5C73M3_AWB_CON, + S5C73M3_AWB_STOP); + CHECK_ERR(err); + s5c73m3_ctrl->isAwbLock = true; + } else { + CAM_DBG_M("awb unlock"); + err = s5c73m3_writeb(S5C73M3_AWB_CON, + S5C73M3_AWB_START); + CHECK_ERR(err); + s5c73m3_ctrl->isAwbLock = false; + } + } + + return 0; +} + +static int s5c73m3_set_focus(int val) +{ + int err = 0; + + CAM_DBG_M("%s, mode %#x\n", + val ? "start" : "stop", camera_focus.mode); + + camera_focus.status = 0; + + if (val) { + isflash = S5C73M3_ISNEED_FLASH_ON; + + if (!s5c73m3_ctrl->camcorder_mode) + s5c73m3_aeawb_lock_unlock(1, 1); + if (camera_focus.mode == FOCUS_MODE_TOUCH) + err = s5c73m3_set_touch_auto_focus(); + else { + err = s5c73m3_writeb(S5C73M3_AF_CON, + S5C73M3_AF_CON_START); + } + } else { + s5c73m3_aeawb_lock_unlock(0, 0); + err = s5c73m3_writeb(S5C73M3_STILL_MAIN_FLASH + , S5C73M3_STILL_MAIN_FLASH_CANCEL); + err = s5c73m3_writeb(S5C73M3_AF_CON, S5C73M3_AF_CON_STOP); + isflash = S5C73M3_ISNEED_FLASH_UNDEFINED; + } + + CHECK_ERR(err); + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_set_caf_focus(int val) +{ + int err = 0; + + CAM_DBG_M("%s, mode %#x\n", + val ? "start" : "stop", camera_focus.mode); + + if (val) { + if (camera_focus.mode == FOCUS_MODE_CONTINOUS_VIDEO) { + CAM_DBG_M("Movie CAF\n"); + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MOVIE_CAF_START); + } else { + CAM_DBG_M("Preview CAF\n"); + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_PREVIEW_CAF_START); + } + } else { + err = s5c73m3_writeb(S5C73M3_AF_CON, S5C73M3_AF_CON_STOP); + } + + CHECK_ERR(err); + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_get_pre_flash(int val) +{ + int err = 0; + u16 pre_flash = false; + + err = s5c73m3_read(0x0009, + S5C73M3_STILL_PRE_FLASH | 0x5000, &pre_flash); + isPreflashFired |= pre_flash; + + return err; +} + +static int s5c73m3_get_af_result(void) +{ + int ret = 0; + u16 af_status = S5C73M3_AF_STATUS_UNFOCUSED; + /*u16 temp_status = 0;*/ + + CAM_DBG_M("Entered\n"); + + ret = s5c73m3_read(0x0009, S5C73M3_AF_STATUS, &af_status); + + switch (af_status) { + case S5C73M3_AF_STATUS_FOCUSING: + case S5C73M3_CAF_STATUS_FOCUSING: + case S5C73M3_CAF_STATUS_FIND_SEARCHING_DIR: + case S5C73M3_CAF_STATUS_INITIALIZE: + case S5C73M3_AF_STATUS_INVALID: + ret = MSM_V4L2_AF_STATUS_IN_PROGRESS; + break; + + case S5C73M3_AF_STATUS_FOCUSED: + case S5C73M3_CAF_STATUS_FOCUSED: + ret = MSM_V4L2_AF_STATUS_SUCCESS; + break; + + case S5C73M3_AF_STATUS_UNFOCUSED: + default: + ret = MSM_V4L2_AF_STATUS_FAIL; + break; + } + camera_focus.status = af_status; + + return ret; +} + +static int s5c73m3_set_af_mode(int val) +{ + int err; + CAM_DBG_M("Entered, new mode %d, old mode %d\n", + val, camera_focus.mode); + +retry: + switch (val) { + case FOCUS_MODE_AUTO: + case FOCUS_MODE_INFINITY: + if (camera_focus.mode >= + FOCUS_MODE_CONTINOUS_PICTURE) { + err = s5c73m3_writeb(S5C73M3_AF_CON, + S5C73M3_AF_CON_STOP); + } + + if (camera_focus.mode != + FOCUS_MODE_CONTINOUS_PICTURE) { + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_NORMAL); + CHECK_ERR(err); + } + camera_focus.mode = val; + camera_focus.caf_mode = S5C73M3_AF_MODE_NORMAL; + break; + + case FOCUS_MODE_MACRO: + if (camera_focus.mode != + FOCUS_MODE_CONTINOUS_PICTURE_MACRO) { + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MACRO); + CHECK_ERR(err); + } + camera_focus.mode = val; + camera_focus.caf_mode = S5C73M3_AF_MODE_MACRO; + break; + + case FOCUS_MODE_CONTINOUS_PICTURE: + if (val != camera_focus.mode && + camera_focus.caf_mode != S5C73M3_AF_MODE_NORMAL) { + camera_focus.mode = val; + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_NORMAL); + CHECK_ERR(err); + camera_focus.caf_mode = S5C73M3_AF_MODE_NORMAL; + } + + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_PREVIEW_CAF_START); + CHECK_ERR(err); + break; + + case FOCUS_MODE_CONTINOUS_PICTURE_MACRO: + if (val != camera_focus.mode && + camera_focus.caf_mode != S5C73M3_AF_MODE_MACRO) { + camera_focus.mode = val; + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MACRO); + CHECK_ERR(err); + camera_focus.caf_mode = S5C73M3_AF_MODE_MACRO; + } + + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_PREVIEW_CAF_START); + CHECK_ERR(err); + break; + + case FOCUS_MODE_CONTINOUS_VIDEO: + camera_focus.mode = val; + + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_MOVIE_CAF_START); + CHECK_ERR(err); + break; + + case FOCUS_MODE_FACEDETECT: + camera_focus.mode = val; + break; + + case FOCUS_MODE_TOUCH: + camera_focus.mode = val; + break; + + default: + cam_err("invalid value, %d\n", val); + val = FOCUS_MODE_AUTO; + goto retry; + } + + camera_focus.mode = val; + + CAM_DBG_H("X\n"); + return 0; +} + +static int s5c73m3_set_touch_auto_focus(void) +{ + int err; + + CAM_DBG_M("s5c73m3_set_touch_auto_focus\n"); + CAM_DBG_H("Touch Position(%d,%d)\n", + camera_focus.pos_x, camera_focus.pos_y); + + s5c73m3_i2c_write_check(); + s5c73m3_ctrl->i2c_write_check = 1; + + err = s5c73m3_i2c_write(0xfcfc, 0x3310); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0050, 0x0009); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, S5C73M3_AF_TOUCH_POSITION); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, camera_focus.pos_x); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, camera_focus.pos_y); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, s5c73m3_ctrl->preview_size_width); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, s5c73m3_ctrl->preview_size_height); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0050, 0x0009); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, 0x5000); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, 0x0E0A); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, 0x0000); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, 0x5080); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, 0x0001); + CHECK_ERR(err); + + s5c73m3_ctrl->i2c_write_check = 0; + + return 0; +} + +static int s5c73m3_capture_firework(void) +{ + int err = 0; + CAM_DBG_H("E\n"); + + err = s5c73m3_writeb(S5C73M3_FIREWORK_CAPTURE, 0x0001); + CHECK_ERR(err); + + return err; +} + +static int s5c73m3_capture_nightshot(void) +{ + int err = 0; + CAM_DBG_H("E\n"); + + err = s5c73m3_writeb(S5C73M3_NIGHTSHOT_CAPTURE, 0x0001); + CHECK_ERR(err); + + return err; +} + +static int s5c73m3_start_capture(int val) +{ + int err = 0; + u16 isneed_flash = false; + u16 pre_flash = false; + + isPreflashFired = false; + + err = s5c73m3_read(0x0009, + S5C73M3_STILL_PRE_FLASH | 0x5000, &pre_flash); + + if (flash_mode == MAIN_CAMERA_FLASH_ON) { + if (!pre_flash) { + err = s5c73m3_writeb(S5C73M3_STILL_PRE_FLASH + , S5C73M3_STILL_PRE_FLASH_FIRE); + isPreflashFired = true; + msleep(100); + } + err = s5c73m3_writeb(S5C73M3_STILL_MAIN_FLASH + , S5C73M3_STILL_MAIN_FLASH_FIRE); + CAM_DBG_H("full flash!!!\n"); + } else if (flash_mode == MAIN_CAMERA_FLASH_AUTO) { + if (pre_flash) { + err = s5c73m3_writeb(S5C73M3_STILL_MAIN_FLASH + , S5C73M3_STILL_MAIN_FLASH_FIRE); + } else if (isflash != S5C73M3_ISNEED_FLASH_ON) { + err = s5c73m3_read(0x0009, + S5C73M3_AE_ISNEEDFLASH | 0x5000, &isneed_flash); + if (isneed_flash) { + err = s5c73m3_writeb(S5C73M3_STILL_PRE_FLASH + , S5C73M3_STILL_PRE_FLASH_FIRE); + isPreflashFired = true; + msleep(100); + err = s5c73m3_writeb(S5C73M3_STILL_MAIN_FLASH + , S5C73M3_STILL_MAIN_FLASH_FIRE); + CAM_DBG_H("full flash with CAF!!!\n"); + } + } + } + + isflash = S5C73M3_ISNEED_FLASH_UNDEFINED; + + return 0; +} + + +static int s5c73m3_set_wdr(int val) +{ + int err; + CAM_DBG_H("E, value %d\n", val); + +retry: + switch (val) { + case WDR_OFF: + err = s5c73m3_writeb(S5C73M3_WDR, + S5C73M3_WDR_OFF); + CHECK_ERR(err); + break; + + case WDR_ON: + err = s5c73m3_writeb(S5C73M3_WDR, + S5C73M3_WDR_ON); + CHECK_ERR(err); + break; + + default: + cam_err("invalid value, %d\n", val); + val = WDR_OFF; + goto retry; + } + + CAM_DBG_H("X\n"); + return 0; +} + +static int s5c73m3_set_HDR(int val) +{ + int err = 0; + CAM_DBG_H("E, value %d\n", val); + s5c73m3_ctrl->hdr_mode = val; + +#if defined(TEMP_REMOVE) + /* this case for JPEG HDR */ + if (val) { + err = s5c73m3_writeb(S5C73M3_AE_AUTO_BRAKET, + S5C73M3_AE_AUTO_BRAKET_EV20); + CHECK_ERR(err); + } + + /* this case for interealved JPEG HDR(full yuv : 420) */ + if (val) { + err = s5c73m3_i2c_write_block(S5C73M3_HDR, + sizeof(S5C73M3_HDR)/ + sizeof(S5C73M3_HDR[0])); + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + } +#endif + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_start_HDR(int val) +{ + int err = 0; + CAM_DBG_H("E, value %d\n", val); + + if (s5c73m3_ctrl->hdr_mode & val) { + CAM_DBG_H("SET AE_BRACKET\n"); + err = s5c73m3_writeb(S5C73M3_AE_AUTO_BRAKET, + S5C73M3_AE_AUTO_BRAKET_EV20); + CHECK_ERR(err); + } + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_set_low_light(int val) +{ + int err = 0; + CAM_DBG_H("E, value %d\n", val); + + s5c73m3_ctrl->low_light_mode = val; + + if (s5c73m3_ctrl->low_light_mode) { + CAM_DBG_H("LLS mode : 0N\n"); + err = s5c73m3_writeb(S5C73M3_LLS_MODE, + S5C73M3_LLS_MODE_ON); + CHECK_ERR(err); + } else { + CAM_DBG_H("LLS mode : OFF\n"); + err = s5c73m3_writeb(S5C73M3_LLS_MODE, + S5C73M3_LLS_MODE_OFF); + CHECK_ERR(err); + } + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return -EIO; + } + + CAM_DBG_H("X\n"); + return err; +} + +static int s5c73m3_set_antishake(int val) +{ + + int err = 0; + CAM_DBG_H("Entered, %d\n", val); + if (val) { + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_ANTI_SHAKE_ON); + CHECK_ERR(err); + s5c73m3_ctrl->anti_shake_mode = true; + } else { + if (s5c73m3_ctrl->anti_shake_mode) { + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_AUTO_MODE_AE_SET); + CHECK_ERR(err); + s5c73m3_ctrl->anti_shake_mode = false; + } + } + return err; +} + +static int s5c73m3_set_jpeg_size(int width, int height) +{ + int32_t rc = 0; + CAM_DBG_M("Entered, width : %d, height : %d\n", width, height); + + if (width == 3264 && height == 2448) + s5c73m3_ctrl->jpeg_size = 0x00F0; + else if (width == 3264 && height == 1836) + s5c73m3_ctrl->jpeg_size = 0x00E0; + else if (width == 1024 && height == 768) + s5c73m3_ctrl->jpeg_size = 0x00D0; + else if (width == 3264 && height == 2176) + s5c73m3_ctrl->jpeg_size = 0x00C0; + else if (width == 2560 && height == 1920) + s5c73m3_ctrl->jpeg_size = 0x00B0; + else if (width == 2560 && height == 1440) + s5c73m3_ctrl->jpeg_size = 0x00A0; + else if (width == 2048 && height == 1536) + s5c73m3_ctrl->jpeg_size = 0x0090; + else if (width == 2048 && height == 1152) + s5c73m3_ctrl->jpeg_size = 0x0080; + else if (width == 1600 && height == 1200) + s5c73m3_ctrl->jpeg_size = 0x0070; + else if (width == 1600 && height == 900) + s5c73m3_ctrl->jpeg_size = 0x0060; + else if (width == 1280 && height == 960) + s5c73m3_ctrl->jpeg_size = 0x0050; + else if (width == 1280 && height == 720) + s5c73m3_ctrl->jpeg_size = 0x0040; + else if (width == 960 && height == 720) + s5c73m3_ctrl->jpeg_size = 0x0030; + else if (width == 960 && height == 540) + s5c73m3_ctrl->jpeg_size = 0x0020; + else if (width == 640 && height == 480) + s5c73m3_ctrl->jpeg_size = 0x0010; + else + s5c73m3_ctrl->jpeg_size = 0x00F0; + + return rc; +} + +static int s5c73m3_set_record_size(int width, int height) +{ + int32_t rc = 0; + CAM_DBG_M("Entered, width : %d, height : %d\n", width, height); + s5c73m3_ctrl->record_size_width = width; + s5c73m3_ctrl->record_size_height = height; + + return rc; +} + +static int s5c73m3_set_face_beauty(int val) +{ + CAM_DBG_H("Entered, %d\n", val); + return 0; +} + +static int s5c73m3_set_fps(int fps) +{ + int err; + + CAM_DBG_M("Entered, %s mode fps %d\n", + s5c73m3_ctrl->camcorder_mode ? "camcorder" : "camera", + fps); + + /* It can't support camera mode */ + if (s5c73m3_ctrl->camcorder_mode == 0) { + CAM_DBG_M("set default fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_AUTO_MODE_AE_SET); + CHECK_ERR(err); + } else { + switch (fps) { + case 30: + CAM_DBG_M("set 30fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_FIXED_30FPS); + CHECK_ERR(err); + break; + + case 20: + CAM_DBG_M("set 20fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_FIXED_20FPS); + CHECK_ERR(err); + break; + + case 15: + CAM_DBG_M("set 15fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_FIXED_15FPS); + CHECK_ERR(err); + break; + + case 7: + CAM_DBG_M("set 7fps\n"); + err = s5c73m3_writeb(S5C73M3_AE_MODE, + S5C73M3_FIXED_7FPS); + CHECK_ERR(err); + break; + + default: + cam_err("invalid value, %d\n", fps); + } + } + + s5c73m3_ctrl->fps = fps; + + return 0; +} + +static int s5c73m3_set_face_zoom(int val) +{ + int err; + + CAM_DBG_M("s5c73m3_set_face_zoom, %d\n", val); + CAM_DBG_H("Touch Position(%d,%d)\n", + camera_focus.pos_x, camera_focus.pos_y); + CAM_DBG_H("Preview Size(%d,%d)\n", + s5c73m3_ctrl->preview_size_width, + s5c73m3_ctrl->preview_size_height); + + err = s5c73m3_writeb(S5C73M3_AF_CON, + S5C73M3_AF_CON_STOP); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0xfcfc, 0x3310); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0050, 0x0009); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, S5C73M3_AF_TOUCH_POSITION); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, camera_focus.pos_x); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, camera_focus.pos_y); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, s5c73m3_ctrl->preview_size_width); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, s5c73m3_ctrl->preview_size_height); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0050, 0x0009); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, 0x5000); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, S5C73M3_AF_FACE_ZOOM); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, val); /*0:reset, 1:Start*/ + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0054, 0x5080); + CHECK_ERR(err); + + err = s5c73m3_i2c_write(0x0F14, 0x0001); + CHECK_ERR(err); + + udelay(400); + err = s5c73m3_writeb(S5C73M3_AF_MODE, + S5C73M3_AF_MODE_PREVIEW_CAF_START); + CHECK_ERR(err); + + return 0; +} + +static int s5c73m3_set_vdis(int onoff) +{ + int32_t rc = 0; + CAM_DBG_H("Entered, VDIS onoff %d\n", onoff); + + switch (onoff) { + case 0: + s5c73m3_ctrl->vdis_mode = false; + break; + + case 1: + s5c73m3_ctrl->vdis_mode = true; + break; + + default: + CAM_DBG_M("unexpected ev mode\n"); + break; + } + return rc; +} + +static int s5c73m3_get_lux(void) +{ + int err = 0; + u16 lux_val = 0; + + err = s5c73m3_read(0x0009, 0x5C88, &lux_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + + return lux_val; +} + +static int s5c73m3_set_preview_size(int32_t width, int32_t height) +{ + CAM_DBG_H("Entered, width %d, height %d\n", + width, height); + + s5c73m3_ctrl->preview_size_width = width; + s5c73m3_ctrl->preview_size_height = height; + + if ((width == 1008 && height == 672) || + (width == 720 && height == 480)) + s5c73m3_ctrl->preview_size = 0x000F; + else if (width == 352 && height == 288) + s5c73m3_ctrl->preview_size = 0x000E; + else if (width == 3264 && height == 2448) + s5c73m3_ctrl->preview_size = 0x000D; + else if (width == 2304 && height == 1296) + s5c73m3_ctrl->preview_size = 0x000C; + else if (width == 720 && height == 480) + s5c73m3_ctrl->preview_size = 0x000B; + else if (width == 1920 && height == 1080) + s5c73m3_ctrl->preview_size = 0x000A; + else if (width == 800 && height == 600) + s5c73m3_ctrl->preview_size = 0x0009; + else if (width == 1600 && height == 1200) + s5c73m3_ctrl->preview_size = 0x0008; + else if (width == 1536 && height == 864) + s5c73m3_ctrl->preview_size = 0x0007; + else if (width == 1280 && height == 720) + s5c73m3_ctrl->preview_size = 0x0006; + else if (width == 1184 && height == 666) + s5c73m3_ctrl->preview_size = 0x0005; + else if (width == 960 && height == 720) + s5c73m3_ctrl->preview_size = 0x0004; + else if (width == 880 && height == 720) + s5c73m3_ctrl->preview_size = 0x0003; + else if (width == 640 && height == 480) + s5c73m3_ctrl->preview_size = 0x0002; + else if (width == 320 && height == 240) + s5c73m3_ctrl->preview_size = 0x0001; + else + s5c73m3_ctrl->preview_size = 0x0004; + + if ((width == 1920 && height == 1080) || + (width == 1280 && height == 720) || + (width == 720 && height == 480)) + s5c73m3_ctrl->wide_preview = 1; + else + s5c73m3_ctrl->wide_preview = 0; + + return 0; +} + +static int s5c73m3_load_fw(void) +{ +#if defined(SPI_DMA_MODE) + #define FW_WRITE_SIZE 65536 +#endif + + int err=0; + int txSize; + + struct file *fp = NULL; + mm_segment_t old_fs; + long fsize, nread; + + CAM_DBG_M("Entered\n"); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if (s5c73m3_ctrl->fw_index == S5C73M3_SD_CARD || + s5c73m3_ctrl->fw_index == S5C73M3_IN_DATA) { + + if (s5c73m3_ctrl->fw_index == S5C73M3_SD_CARD) + fp = filp_open(S5C73M3_FW_PATH, O_RDONLY, 0); + else + fp = filp_open(fw_path_in_data, O_RDONLY, 0); + if (IS_ERR(fp)) { + cam_err("failed to filp_open\n"); + goto out; + } + } else { + fp = filp_open(fw_path, O_RDONLY, 0); + if (IS_ERR(fp)) { + cam_err("failed to filp_open\n"); + goto out; + } + } + + fsize = fp->f_path.dentry->d_inode->i_size; + + CAM_DBG_M("index %d is opened\n", + s5c73m3_ctrl->fw_index); + CAM_DBG_M("fsize is %ld\n", fsize); + + Fbuf = (char *)roundup((unsigned int)FW_buf, 64); /*ALRAN 64*/ + nread = vfs_read(fp, (char __user *)Fbuf, + fsize, &fp->f_pos); + if (nread != fsize) { + cam_err("failed to read firmware file, %ld Bytes\n", nread); + err = -EIO; + goto out; + } + set_fs(old_fs); + +#if defined(SPI_DMA_MODE) + txSize = FW_WRITE_SIZE; /*QCTK*/ +#else + txSize = 8; +#endif + err = s5c73m3_spi_write(Fbuf, fsize, txSize); + + if (err < 0) { + cam_err("s5c73m3_spi_write falied\n"); + goto out; + } + + CAM_DBG_M("Exit\n"); + +out: + filp_close(fp, current->files); + set_fs(old_fs); + + return err; +} + +static int s5c73m3_SPI_booting(void) +{ + u16 read_val; + int i, err; + + CAM_DBG_M("Entered\n"); + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + udelay(400); + + /*Check boot done*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + if (read_val == 0x0C) + break; + + udelay(100); + } + + if (read_val != 0x0C) { + cam_err("boot fail, read_val %#x\n", read_val); + return -EIO; + } + + /*P,M,S and Boot Mode*/ + err = s5c73m3_write(0x3010, 0x0014, 0x2146); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + err = s5c73m3_write(0x3010, 0x0010, 0x210C); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + udelay(200); + + /*Check SPI ready*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + + if (read_val == 0x210D) + break; + + udelay(100); + } + + if (read_val != 0x210D) { + cam_err("SPI not ready, read_val %#x\n", read_val); + return -EIO; + } + + /*download fw by SPI*/ + err = s5c73m3_load_fw(); + if (err < 0) { + cam_err("failed s5c73m3_load_fw!!\n"); + return -EIO; + } + + /*ARM reset*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFD); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + /*remap*/ + err = s5c73m3_write(0x3010, 0x00A4, 0x0183); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + +#if defined(DEBUG_LEVEL_HIGH) + /* check FW version name */ + CAM_DBG_H("FW version is : "); + for (i = 0; i < 19; i++) { + err = s5c73m3_read(0x0000, 0x0060+i, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + CAM_DBG_H("%c%c", read_val&0xff, + (read_val>>8)&0xff); + i++; + } +#endif + + /*ARM go again*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + return 0; +} + +static int s5c73m3_dump_fw(void) +{ + return 0; +} + +static int s5c73m3_get_sensor_fw_binary(void) +{ + u16 read_val; + int i, rxSize; + int err = 0; + struct file *fp = NULL; + mm_segment_t old_fs; + long ret = 0; + char l_fw_path[40] = {0}; + u8 mem0 = 0, mem1 = 0; + u32 CRC = 0; + u32 DataCRC = 0; + u32 IntOriginalCRC = 0; + u32 crc_index = 0; + int retryCnt = 2; + + CAM_DBG_M("Entered\n"); + + if (s5c73m3_ctrl->sensor_fw[0] == 'O') { + sprintf(l_fw_path, "%sSlimISP_G%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[1]); + } else if (s5c73m3_ctrl->sensor_fw[0] == 'S') { + sprintf(l_fw_path, "%sSlimISP_Z%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[1]); + } else { + sprintf(l_fw_path, "%sSlimISP_%c%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[0], + s5c73m3_ctrl->sensor_fw[1]); + } + + /* Make CRC Table */ + s5c73m3_make_CRC_table((u32 *)&s5c73m3_ctrl->crc_table, 0xEDB88320); + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + CHECK_ERR(err); + + udelay(400); + + /*Check boot done*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + CHECK_ERR(err); + + if (read_val == 0x0C) + break; + + udelay(100); + } + + if (read_val != 0x0C) { + cam_err("boot fail, read_val %#x\n", read_val); + return -EINVAL; + } + + /* Change I/O Driver Current in order to read from F-ROM */ + err = s5c73m3_write(0x3010, 0x0120, 0x0820); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x0124, 0x0820); + CHECK_ERR(err); + + /*P,M,S and Boot Mode*/ + err = s5c73m3_write(0x3010, 0x0014, 0x2146); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x0010, 0x230C); + CHECK_ERR(err); + + udelay(200); + + /*Check SPI ready*/ + for (i = 0; i < 300; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + CHECK_ERR(err); + + if (read_val == 0x230E) + break; + + udelay(100); + } + + if (read_val != 0x230E) { + cam_err("SPI not ready, read_val %#x\n", read_val); + return -EINVAL; + } + + /*ARM reset*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFD); + CHECK_ERR(err); + + /*remap*/ + err = s5c73m3_write(0x3010, 0x00A4, 0x0183); + CHECK_ERR(err); + + /*ARM go again*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + CHECK_ERR(err); + + mdelay(200); + +retry: + mem0 = 0, mem1 = 0; + CRC = 0; + DataCRC = 0; + IntOriginalCRC = 0; + crc_index = 0; + + /* SPI Copy mode ready I2C CMD */ + err = s5c73m3_writeb(0x0924, 0x0000); + CHECK_ERR(err); + CAM_DBG_M("sent SPI ready CMD\n"); + + rxSize = 64*1024; + mdelay(10); + s5c73m3_wait_ISP_status(); + + Fbuf = (char *)roundup((unsigned int)FW_buf, 64); /*ALRAN 64*/ + err = s5c73m3_spi_read(Fbuf, + s5c73m3_ctrl->sensor_size, rxSize); + CHECK_ERR(err); + + CRC = ~CRC; + for (crc_index = 0; crc_index < (s5c73m3_ctrl->sensor_size-4)/2 + ; crc_index++) { + /*low byte*/ + mem0 = (unsigned char)(Fbuf[crc_index*2] & 0x00ff); + /*high byte*/ + mem1 = (unsigned char)(Fbuf[crc_index*2+1] & 0x00ff); + CRC = s5c73m3_ctrl->crc_table[(CRC ^ (mem0)) & 0xFF] \ + ^ (CRC >> 8); + CRC = s5c73m3_ctrl->crc_table[(CRC ^ (mem1)) & 0xFF] \ + ^ (CRC >> 8); + } + CRC = ~CRC; + + DataCRC = (CRC&0x000000ff)<<24; + DataCRC += (CRC&0x0000ff00)<<8; + DataCRC += (CRC&0x00ff0000)>>8; + DataCRC += (CRC&0xff000000)>>24; + CAM_DBG_M("made CSC value by S/W = 0x%x\n", DataCRC); + + IntOriginalCRC = (Fbuf[s5c73m3_ctrl->sensor_size-4]&0x00ff)<<24; + IntOriginalCRC += (Fbuf[s5c73m3_ctrl->sensor_size-3]&0x00ff)<<16; + IntOriginalCRC += (Fbuf[s5c73m3_ctrl->sensor_size-2]&0x00ff)<<8; + IntOriginalCRC += (Fbuf[s5c73m3_ctrl->sensor_size-1]&0x00ff); + CAM_DBG_M("Original CRC Int = 0x%x\n", IntOriginalCRC); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if (IntOriginalCRC == DataCRC) { + fp = filp_open(l_fw_path, O_WRONLY|O_CREAT, 0644); + if (IS_ERR(fp) || fp == NULL) { + cam_err("failed to open %s, err %ld\n", + l_fw_path, PTR_ERR(fp)); + err = -EINVAL; + goto out; + } + + ret = vfs_write(fp, (char __user *)Fbuf, + s5c73m3_ctrl->sensor_size, &fp->f_pos); + + memcpy(s5c73m3_ctrl->phone_fw, + s5c73m3_ctrl->sensor_fw, + S5C73M3_FW_VER_LEN); + s5c73m3_ctrl->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; + + CAM_DBG_M("Changed to Phone_version = %s\n", + s5c73m3_ctrl->phone_fw); + } else { + if (retryCnt > 0) { + set_fs(old_fs); + retryCnt--; + goto retry; + } + } + + if (fp != NULL) + filp_close(fp, current->files); + +out: + set_fs(old_fs); + + CAM_DBG_M("Exit\n"); + + return err; +} + +static int s5c73m3_get_sensor_fw_version(void) +{ + u16 read_val; + int i, err; + u16 temp_buf; + + CAM_DBG_H("Entered\n"); + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + udelay(400); + + /*Check boot done*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + if (read_val == 0x0C) + break; + + udelay(100); + } + + if (read_val != 0x0C) { + cam_err("boot fail, read_val %#x\n", read_val); + return -EIO; + } + + /* Change I/O Driver Current in order to read from F-ROM */ + err = s5c73m3_write(0x3010, 0x0120, 0x0820); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + err = s5c73m3_write(0x3010, 0x0124, 0x0820); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + /* Offset Setting */ + err = s5c73m3_write(0x0001, 0x0418, 0x0008); + CHECK_ERR(err); + + /*P,M,S and Boot Mode*/ + err = s5c73m3_write(0x3010, 0x0014, 0x2146); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + err = s5c73m3_write(0x3010, 0x0010, 0x230C); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + udelay(200); + + /*Check SPI ready*/ + for (i = 0; i < 300; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + + if (read_val == 0x230E) + break; + + udelay(100); + } + + if (read_val != 0x230E) { + cam_err("SPI not ready, read_val %#x\n", read_val); + return -EIO; + } + + /*ARM reset*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFD); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + /*remap*/ + err = s5c73m3_write(0x3010, 0x00A4, 0x0183); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + +#if defined(TEMP_REMOVE) + /*ARM go again*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + if (err < 0) { + cam_err("failed s5c73m3_write!!\n"); + return -EIO; + } + + /* check FW version name */ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x0000, 0x0060+i*2, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + s5c73m3_ctrl->sensor_fw[i*2] = read_val&0x00ff; + s5c73m3_ctrl->sensor_fw[i*2+1] = (read_val&0xff00)>>8; + } + s5c73m3_ctrl->sensor_fw[i*2+2] = ' '; +#else + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x0000, i*2, &read_val); + if (err < 0) { + cam_err("failed s5c73m3_read!!\n"); + return -EIO; + } + s5c73m3_ctrl->sensor_fw[i*2] = read_val&0x00ff; + s5c73m3_ctrl->sensor_fw[i*2+1] = (read_val&0xff00)>>8; + } + s5c73m3_ctrl->sensor_fw[i*2+2] = ' '; +#endif + + s5c73m3_ctrl->sensor_size = 0; + for (i = 0; i < 2; i++) { + err = s5c73m3_read(0x0000, 0x0014+i*2, &temp_buf); + s5c73m3_ctrl->sensor_size += temp_buf<<(i*16); + CHECK_ERR(err); + } + + if ((s5c73m3_ctrl->sensor_fw[0] >= 'A') + && s5c73m3_ctrl->sensor_fw[0] <= 'Z') { + cam_err("sensor_fw = %s\n", + s5c73m3_ctrl->sensor_fw); + return 0; + } else { + cam_err("Sensor is not connected!!\n"); + return -EIO; + } +} + +static int s5c73m3_open_firmware_file(const char *filename, + u8 *buf, u16 offset, u16 size) { + struct file *fp; + int err = 0; + mm_segment_t old_fs; + long nread; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(fp)) { + err = -ENOENT; + goto out; + } else { + CAM_DBG_H("%s is opened\n", filename); + } + + err = vfs_llseek(fp, offset, SEEK_SET); + if (err < 0) { + cam_err("failed to fseek, %d\n", err); + goto out; + } + + nread = vfs_read(fp, (char __user *)buf, size, &fp->f_pos); + + if (nread != size) { + cam_err("failed to read firmware file, %ld Bytes\n", nread); + err = -EIO; + goto out; + } +out: + if (!IS_ERR(fp)) + filp_close(fp, current->files); + + set_fs(old_fs); + + return err; +} + +static int s5c73m3_compare_date(char *camfw_info_ver1, + char *camfw_info_ver2) +{ + u8 date1[5] = {0,}; + u8 date2[5] = {0,}; + + strncpy((char *)&date1, camfw_info_ver1, 4); + strncpy((char *)&date2, camfw_info_ver2, 4); + CAM_DBG_M("date1 = %s, date2 = %s\n, compare result = %d", + date1, + date2, + strcmp((char *)&date1, (char *)&date2)); + + return strcmp((char *)&date1, (char *)&date2); +} + +static int s5c73m3_get_phone_fw_version(void) +{ +#if defined(SPI_DMA_MODE) +#define FW_WRITE_SIZE 65536 +#endif + + static char *buf; /*static*/ + int err = 0; + int retVal = 0; + int fw_requested = 1; + + CAM_DBG_M("Entered\n"); + + buf = vmalloc(S5C73M3_FW_VER_LEN+1); + if (!buf) { + cam_err("failed to allocate memory\n"); + err = -ENOMEM; + goto out; + } + + if (s5c73m3_ctrl->sensor_fw[0] == 'O') { + sprintf(fw_path, "%sSlimISP_G%c.bin", + S5C73M3_FW_REQUEST_PATH, + s5c73m3_ctrl->sensor_fw[1]); + sprintf(fw_path_in_data, "%sSlimISP_G%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[1]); + } else if (s5c73m3_ctrl->sensor_fw[0] == 'S') { + sprintf(fw_path, "%sSlimISP_Z%c.bin", + S5C73M3_FW_REQUEST_PATH, + s5c73m3_ctrl->sensor_fw[1]); + sprintf(fw_path_in_data, "%sSlimISP_G%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[1]); + } else { + sprintf(fw_path, "%sSlimISP_%c%c.bin", + S5C73M3_FW_REQUEST_PATH, + s5c73m3_ctrl->sensor_fw[0], + s5c73m3_ctrl->sensor_fw[1]); + sprintf(fw_path_in_data, "%sSlimISP_%c%c.bin", + S5C73M3_FW_REQUEST_SECOND_PATH, + s5c73m3_ctrl->sensor_fw[0], + s5c73m3_ctrl->sensor_fw[1]); + } + + retVal = s5c73m3_open_firmware_file(S5C73M3_FW_PATH, + buf, + S5C73M3_FW_VER_FILE_CUR, + S5C73M3_FW_VER_LEN); + if (retVal >= 0) { + camfw_info[S5C73M3_SD_CARD].opened = 1; + memcpy(camfw_info[S5C73M3_SD_CARD].ver, + buf, + S5C73M3_FW_VER_LEN); + camfw_info[S5C73M3_SD_CARD] + .ver[S5C73M3_FW_VER_LEN+1] = '\0'; + s5c73m3_ctrl->fw_index = S5C73M3_SD_CARD; + fw_requested = 0; + } + +request_fw: + if (fw_requested) { + /* check fw in data folder */ + retVal = s5c73m3_open_firmware_file(fw_path_in_data, + buf, + S5C73M3_FW_VER_FILE_CUR, + S5C73M3_FW_VER_LEN); + if (retVal >= 0) { + camfw_info[S5C73M3_IN_DATA].opened = 1; + memcpy(camfw_info[S5C73M3_IN_DATA].ver, + buf, + S5C73M3_FW_VER_LEN); + camfw_info[S5C73M3_IN_DATA] + .ver[S5C73M3_FW_VER_LEN+1] = '\0'; + } + + /* check fw in system folder */ + retVal = s5c73m3_open_firmware_file(fw_path, + buf, + S5C73M3_FW_VER_FILE_CUR, + S5C73M3_FW_VER_LEN); + if (retVal >= 0) { + camfw_info[S5C73M3_IN_SYSTEM].opened = 1; + memcpy(camfw_info[S5C73M3_IN_SYSTEM].ver, + buf, + S5C73M3_FW_VER_LEN); + camfw_info[S5C73M3_IN_SYSTEM] + .ver[S5C73M3_FW_VER_LEN+1] = '\0'; + } + + /* compare */ + if (camfw_info[S5C73M3_IN_DATA].opened == 0 && + camfw_info[S5C73M3_IN_SYSTEM].opened == 1) { + s5c73m3_ctrl->fw_index = S5C73M3_IN_SYSTEM; + } else if (camfw_info[S5C73M3_IN_DATA].opened == 1 && + camfw_info[S5C73M3_IN_SYSTEM].opened == 0) { + s5c73m3_ctrl->fw_index = S5C73M3_IN_DATA; + } else if (camfw_info[S5C73M3_IN_DATA].opened == 1 && + camfw_info[S5C73M3_IN_SYSTEM].opened == 1) { + int i = 1; + retVal = s5c73m3_compare_date( + (char *)(&camfw_info[S5C73M3_IN_DATA].ver[2]), + (char *)(&camfw_info[S5C73M3_IN_SYSTEM].ver[2])); + + while (1) { + if (camfw_info[S5C73M3_IN_DATA].ver[i] != + camfw_info[S5C73M3_IN_SYSTEM].ver[i]) { + cam_err("FW is diff!\n"); + retVal = 1; + break; + } + if (--i < 0) { + CAM_DBG_M("FW is same!!\n"); + break; + } + } + if (retVal <= 0) { + /*unlink(&fw_path_in_data);*/ + s5c73m3_ctrl->fw_index = S5C73M3_IN_SYSTEM; + } else { + s5c73m3_ctrl->fw_index = S5C73M3_IN_DATA; + } + } else { + CAM_DBG_M("can't open %s. download from F-ROM\n", + s5c73m3_ctrl->sensor_fw); + + s5c73m3_reset_module(true); + + retVal = s5c73m3_get_sensor_fw_binary(); + CHECK_ERR(retVal); + goto request_fw; + } + } + + memcpy(s5c73m3_ctrl->phone_fw, + camfw_info[s5c73m3_ctrl->fw_index].ver, + S5C73M3_FW_VER_LEN); + s5c73m3_ctrl->phone_fw[S5C73M3_FW_VER_LEN+1] = '\0'; + CAM_DBG_M("Phone_version = %s(index=%d)\n", + s5c73m3_ctrl->phone_fw, s5c73m3_ctrl->fw_index); + +out: + if (buf != NULL) + vfree(buf); + + CAM_DBG_M("Exit\n"); + return err; +} + +static int s5c73m3_update_camerafw_to_FROM(void) +{ + int err; + int index = 0; + u16 status = 0; + + do { + /* stauts 0 : not ready ISP */ + if (status == 0) { + err = s5c73m3_writeb(0x0906, 0x0000); + CHECK_ERR(err); + } + + err = s5c73m3_read(0x0009, 0x5906, &status); + /* Success : 0x05, Fail : 0x07 , Progressing : 0xFFFF*/ + if (status == 0x0005 || + status == 0x0007) + break; + + index++; + msleep(20); + } while (index < 500); /* 10 sec */ + + + if (status == 0x0007) + return -EIO; + else + return 0; +} +#if 0 +static int s5c73m3_SPI_booting_by_ISP(void) +{ + u16 read_val; + int i; + int err = 0; + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + CHECK_ERR(err); + + udelay(400); + + /*Check boot done*/ + for (i = 0; i < 3; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + CHECK_ERR(err); + + if (read_val == 0x0C) + break; + + udelay(100); + } + + if (read_val != 0x0C) { + cam_err("boot fail, read_val %#x\n", read_val); + return -1; + } + + /*P,M,S and Boot Mode*/ + err = s5c73m3_write(0x3010, 0x0014, 0x2146); + CHECK_ERR(err); + err = s5c73m3_write(0x3010, 0x0010, 0x230C); + CHECK_ERR(err); + + udelay(200); + + /*Check SPI ready*/ + for (i = 0; i < 300; i++) { + err = s5c73m3_read(0x3010, 0x0010, &read_val); + CHECK_ERR(err); + + if (read_val == 0x230E) + break; + + udelay(100); + } + + if (read_val != 0x230E) { + cam_err("SPI not ready, read_val %#x\n", read_val); + return -1; + } + + /*ARM reset*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFD); + CHECK_ERR(err); + + /*remap*/ + err = s5c73m3_write(0x3010, 0x00A4, 0x0183); + CHECK_ERR(err); + + /*ARM go*/ + err = s5c73m3_write(0x3000, 0x0004, 0xFFFF); + CHECK_ERR(err); + + return err; +} +#endif +static int s5c73m3_check_fw_date(void) +{ + u8 sensor_date[5] = {0,}; + u8 phone_date[5] = {0,}; + + int i = 1; + while (1) { + if (s5c73m3_ctrl->sensor_fw[i] != + s5c73m3_ctrl->phone_fw[i]) { + cam_err("Sensor is diff!\n"); + cam_err("Sensor_date = %s, " + "Phone_date = %s\n", + s5c73m3_ctrl->sensor_fw, + s5c73m3_ctrl->phone_fw); + return 1; + } + if (--i < 0) { + CAM_DBG_M("FW is same!!\n"); + break; + } + } + + strncpy((char *)&sensor_date, + &s5c73m3_ctrl->sensor_fw[2], 4); + strncpy((char *)&phone_date, + (const char *)&s5c73m3_ctrl->phone_fw[2], 4); + CAM_DBG_M("Sensor_date = %s, Phone_date = %s\n, " + "compare result = %d", + sensor_date, + phone_date, + strcmp((char *)&sensor_date, (char *)&phone_date)); + + return strcmp((char *)&sensor_date, (char *)&phone_date); +} + +static int s5c73m3_check_fw(const struct msm_camera_sensor_info *data, + bool download) +{ + int err = 0; + int retVal; + int i = 0; + + CAM_DBG_M("Enter\n"); + + if (!download) { + for (i = 0; i < S5C73M3_PATH_MAX; i++) + camfw_info[i].opened = 0; + + err = s5c73m3_get_sensor_fw_version(); + if (err < 0) { + cam_err("failed s5c73m3_get_sensor_fw_version!!\n"); + return -EIO; + } + err = s5c73m3_get_phone_fw_version(); + if (err < 0) { + cam_err("failed s5c73m3_get_phone_fw_version!!\n"); + return -EIO; + } + } + + data->sensor_platform_info->sensor_get_fw(s5c73m3_ctrl->sensor_fw, + s5c73m3_ctrl->phone_fw); + + retVal = s5c73m3_check_fw_date(); + + /* retVal = 0 : Same Version + retVal < 0 : Phone Version is latest Version than sensorFW. + retVal > 0 : Sensor Version is latest version than phoenFW. */ + if (retVal <= 0 || download || s5c73m3_ctrl->fw_index == 0) { + if (s5c73m3_ctrl->fw_index == 0) + CAM_DBG_M("Loading From PhoneFW forced......\n"); + else + CAM_DBG_M("Loading From PhoneFW......\n"); + + if ((s5c73m3_ctrl->phone_fw[0] >= 'A') + && s5c73m3_ctrl->phone_fw[0] <= 'Z') { + s5c73m3_reset_module(false); + err = s5c73m3_SPI_booting(); + if (err < 0) { + cam_err("failed s5c73m3_SPI_booting!!\n"); + return -EIO; + } + if (download) { + err = s5c73m3_update_camerafw_to_FROM(); + if (err < 0) { + cam_err("failed s5c73m3_update_camerafw_to_FROM!!\n"); + return -EIO; + } + } + } else { + cam_err("phone FW is wrong!!\n"); + return -EIO; + } + } else { + CAM_DBG_M("Loading From SensorFW......\n"); + s5c73m3_reset_module(true); + err = s5c73m3_get_sensor_fw_binary(); + if (err < 0) { + cam_err("failed s5c73m3_get_sensor_fw_binary!!\n"); + return -EIO; + } + /* check fw in data folder */ + { + static char *buf; /*static*/ + buf = vmalloc(S5C73M3_FW_VER_LEN+1); + if (buf == NULL) { + cam_err("Mem allocation failed\n"); + return -EIO; + } + retVal = s5c73m3_open_firmware_file(fw_path_in_data, + buf, + S5C73M3_FW_VER_FILE_CUR, + S5C73M3_FW_VER_LEN); + if (retVal >= 0) { + camfw_info[S5C73M3_IN_DATA].opened = 1; + memcpy(camfw_info[S5C73M3_IN_DATA].ver, + buf, + S5C73M3_FW_VER_LEN); + camfw_info[S5C73M3_IN_DATA] + .ver[S5C73M3_FW_VER_LEN+1] = '\0'; + s5c73m3_ctrl->fw_index = S5C73M3_IN_DATA; + memcpy(s5c73m3_ctrl->phone_fw, + camfw_info[s5c73m3_ctrl->fw_index].ver, + S5C73M3_FW_VER_LEN); + s5c73m3_ctrl->phone_fw[S5C73M3_FW_VER_LEN+1] = '\0'; +// CAM_DBG_M("FW is %s!!\n", &s5c73m3_ctrl->phone_fw); + data->sensor_platform_info->sensor_get_fw( + s5c73m3_ctrl->sensor_fw, + s5c73m3_ctrl->phone_fw); + } else + cam_err("Warnning!! can't check FW!\n"); + if (buf) + vfree(buf); + } + } +#if defined(TEMP_REMOVE) + data->sensor_platform_info->sensor_get_fw(s5c73m3_ctrl->sensor_fw, + s5c73m3_ctrl->phone_fw); + + if ((s5c73m3_ctrl->phone_fw[0] >= 'A') + && s5c73m3_ctrl->phone_fw[0] <= 'Z') { + s5c73m3_sensor_reset(); + + err = s5c73m3_SPI_booting(); + if (err < 0) { + cam_err("failed s5c73m3_SPI_booting!!\n"); + return -EIO; + } + } +#endif + + CAM_DBG_M("Exit\n"); + return 0; +} +#if 0 +static int s5c73m3_init_param(void) +{ + int err = 0; + + CAM_DBG_H("Entered\n"); + + err = s5c73m3_i2c_write_block(S5C73M3_INIT, + sizeof(S5C73M3_INIT)/sizeof(S5C73M3_INIT[0])); + + if (err < 0) { + cam_err("failed s5c73m3_write_block!!\n"); + return -EIO; + } + + return err; +} +#endif +static int s5c73m3_read_vdd_core(void) +{ + u16 read_val; + int err; + + CAM_DBG_M("Entered\n"); + + /*Initialize OTP Controller*/ + err = s5c73m3_write(0x3800, 0xA004, 0x0000); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA000, 0x0004); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0D8, 0x0000); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0DC, 0x0004); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0C4, 0x4000); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0D4, 0x0015); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA000, 0x0001); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0B4, 0x9F90); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA09C, 0x9A95); + CHECK_ERR(err); + + /*Page Select*/ + err = s5c73m3_write(0x3800, 0xA0C4, 0x4800); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0C4, 0x4400); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA0C4, 0x4200); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA004, 0x00C0); + CHECK_ERR(err); + err = s5c73m3_write(0x3800, 0xA000, 0x0001); + CHECK_ERR(err); + + /*Read Data*/ + err = s5c73m3_read(0x3800, 0xA034, &read_val); + CHECK_ERR(err); + CAM_DBG_M("vdd_core_info %#x\n", read_val); + + err = s5c73m3_read(0x3800, 0xA040, &read_val); + CHECK_ERR(err); + CAM_DBG_M("chip info#1 %#x\n", read_val); + + err = s5c73m3_read(0x3800, 0xA044, &read_val); + CHECK_ERR(err); + CAM_DBG_M("chip info#2 %#x\n", read_val); + + err = s5c73m3_read(0x3800, 0xA048, &read_val); + CHECK_ERR(err); + CAM_DBG_M("chip info#3 %#x\n", read_val); + + /*Read Data End*/ + err = s5c73m3_write(0x3800, 0xA000, 0x0000); + CHECK_ERR(err); + + if (read_val & 0x200) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1150000); + else if (read_val & 0x800) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1100000); + else if (read_val & 0x2000) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1050000); + else if (read_val & 0x8000) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1000000); + else +#if defined(CONFIG_MACH_M2_DCM) + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1230000); +#else + s5c73m3_ctrl->sensordata->sensor_platform_info + ->sensor_set_isp_core(1150000); +#endif + + CAM_DBG_H("X\n"); + + return 0; +} + +static int s5c73m3_set_af_softlanding(void) +{ + int err = 0; + CAM_DBG_M("Entered\n"); + + err = s5c73m3_writeb(S5C73M3_AF_SOFTLANDING, + S5C73M3_AF_SOFTLANDING_ON); + CHECK_ERR(err); + + return 0; +} + +static int s5c73m3_sensor_init_probe(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + int retVal = 0; + + CAM_DBG_M("Entered\n"); + + /*data->sensor_platform_info->sensor_power_on(0);*/ + usleep(5*1000); + + if (!data->sensor_platform_info->sensor_is_vdd_core_set()) { + rc = s5c73m3_read_vdd_core(); + if (rc < 0) { + cam_err("failed s5c73m3_read_vdd_core!!\n"); + return -EIO; + } + } + rc = s5c73m3_set_timing_register_for_vdd(); + CHECK_ERR(rc); + + rc = s5c73m3_check_fw(data, 0); + /*rc = s5c73m3_SPI_booting();*/ + if (rc < 0) { + cam_err("failed s5c73m3_check_fw!!\n"); + return -EIO; + } + + rc = s5c73m3_i2c_check_status_with_CRC(); + if (rc < 0) { + cam_err("ISP is not ready. retry loading fw!!\n"); + /* retry */ + retVal = s5c73m3_check_fw_date(); + + /* retVal = 0 : Same Version + retVal < 0 : Phone Version is latest Version than sensorFW. + retVal > 0 : Sensor Version is latest version than phoenFW. */ + if (retVal <= 0) { + cam_err("Loading From PhoneFW......\n"); + s5c73m3_reset_module(false); + rc = s5c73m3_SPI_booting(); + CHECK_ERR(rc); + } else { + cam_err("Loading From SensorFW......\n"); + s5c73m3_reset_module(true); + rc = s5c73m3_get_sensor_fw_binary(); + CHECK_ERR(rc); + } + } + + return rc; +} + + +int s5c73m3_sensor_init(const struct msm_camera_sensor_info *data) +{ + int rc = 0; + + CAM_DBG_M("Entered\n"); + + if (!s5c73m3_ctrl) { + cam_err("s5c73m3_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + + if (data) + s5c73m3_ctrl->sensordata = data; + + s5c73m3_ctrl->i2c_write_check = 0; + s5c73m3_ctrl->fps = 0; + s5c73m3_ctrl->low_light_mode_size = 0; + + config_csi2 = 0; + rc = s5c73m3_sensor_init_probe(data); + if (rc < 0) + cam_err("s5c73m3_sensor_init failed!\n"); + +init_done: + return rc; +} + +static int s5c73m3_init_client(struct i2c_client *client) +{ + CAM_DBG_M("Entered\n"); + + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&s5c73m3_wait_queue); + return 0; +} + +void sensor_native_control(void __user *arg) +{ + struct ioctl_native_cmd ctrl_info; + int err = 0; + + if (copy_from_user((void *)&ctrl_info, + (const void *)arg, sizeof(ctrl_info))) + CAM_DBG_M("fail copy_from_user!\n"); + + CAM_DBG_M("Entered, %d, %d, %d, %d\n", + ctrl_info.mode, ctrl_info.address, + ctrl_info.value_1, ctrl_info.value_2); + + switch (ctrl_info.mode) { + + case EXT_CAM_EV: + s5c73m3_set_ev(ctrl_info.value_1); + break; + + case EXT_CAM_EFFECT: + s5c73m3_set_effect(ctrl_info.value_1); + break; + + case EXT_CAM_SCENE_MODE: + s5c73m3_set_scene_mode(ctrl_info.value_1); + break; + + case EXT_CAM_ISO: + s5c73m3_set_iso(ctrl_info.value_1); + break; + + case EXT_CAM_METERING: + s5c73m3_set_metering(ctrl_info.value_1); + break; + + case EXT_CAM_WB: + s5c73m3_set_whitebalance(ctrl_info.value_1); + break; + + case EXT_CAM_QUALITY: + s5c73m3_set_jpeg_quality(ctrl_info.value_1); + break; + + case EXT_CAM_ZOOM: + s5c73m3_set_zoom(ctrl_info.value_1); + break; + + case EXT_CAM_FD_MODE: + s5c73m3_set_face_detection(ctrl_info.value_1); + break; + + case EXT_CAM_SET_WDR: + s5c73m3_set_wdr(ctrl_info.value_1); + break; + + case EXT_CAM_SET_HDR: + s5c73m3_set_HDR(ctrl_info.value_1); + break; + + case EXT_CAM_START_HDR: + s5c73m3_start_HDR(ctrl_info.value_1); + break; + + case EXT_CAM_SET_LOW_LIGHT_MODE: + s5c73m3_set_low_light(ctrl_info.value_1); + break; + + case EXT_CAM_SET_LOW_LIGHT_SIZE: + s5c73m3_ctrl->low_light_mode_size = ctrl_info.value_1; + break; + + case EXT_CAM_SET_ANTI_SHAKE: + s5c73m3_set_antishake(ctrl_info.value_1); + break; + + case EXT_CAM_SET_BEAUTY_SHOT: + s5c73m3_set_face_beauty(ctrl_info.value_1); + break; + + case EXT_CAM_SET_FPS: + s5c73m3_set_fps(ctrl_info.value_1); + break; + + case EXT_CAM_AF: + CAM_DBG_M("Entered %s mode %d\n", + "EXT_CAM_AF", ctrl_info.address); + + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + if (ctrl_info.address == MSM_V4L2_AF_SET_AUTO_FOCUS) { + err = s5c73m3_set_focus(ctrl_info.value_1); + } else if (ctrl_info.address == + MSM_V4L2_AF_SET_AUTO_FOCUS_MODE) { + err = s5c73m3_set_af_mode(ctrl_info.value_1); + } else if (ctrl_info.address == + MSM_V4L2_AF_GET_AUTO_FOCUS) { + ctrl_info.value_1 = camera_focus.mode; + } else if (ctrl_info.address == + MSM_V4L2_AF_GET_AUTO_FOCUS_RESULT) { + ctrl_info.value_1 = s5c73m3_get_af_result(); + } else if (ctrl_info.address == + MSM_V4L2_AF_SET_AUTO_FOCUS_DEFAULT_POSITION) { + err = s5c73m3_set_af_mode(ctrl_info.value_1); + } else if (ctrl_info.address == + MSM_V4L2_AF_CANCEL_AUTO_FOCUS) { + err = s5c73m3_set_focus(ctrl_info.value_1); + } else if (ctrl_info.address == + MSM_V4L2_CAF_FOCUS) { + err = s5c73m3_set_caf_focus(ctrl_info.value_1); + } else{ /* MSM_V4L2_AF_COMMAND_MAX */ + cam_err("%s can't support %d\n", + "EXT_CAM_AF", ctrl_info.address); + } + break; + + case EXT_CAM_SET_TOUCHAF_POS: + CAM_DBG_H("Entered %s\n", + "EXT_CAM_SET_TOUCHAF_POS"); + CAM_DBG_H("w %d, h %d\n", + ctrl_info.value_1, ctrl_info.value_2); + camera_focus.pos_x = ctrl_info.value_1; + camera_focus.pos_y = ctrl_info.value_2; + break; + + case EXT_CAM_FLASH_MODE: + s5c73m3_set_flash(ctrl_info.value_1); + break; + + case EXT_CAM_START_CAPTURE: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + err = s5c73m3_start_capture(ctrl_info.value_1); + + if (s5c73m3_ctrl->scene == CAMERA_SCENE_FIRE) + err = s5c73m3_capture_firework(); + else if (s5c73m3_ctrl->scene == CAMERA_SCENE_NIGHT) + err = s5c73m3_capture_nightshot(); + break; + + case EXT_CAM_SET_JPEG_SIZE: + err = s5c73m3_set_jpeg_size(ctrl_info.value_1, + ctrl_info.value_2); + break; + + case EXT_CAM_SET_RECORD_SIZE: + err = s5c73m3_set_record_size(ctrl_info.value_1, + ctrl_info.value_2); + break; + + case EXT_CAM_SET_PREVIEW_SIZE: + err = s5c73m3_set_preview_size(ctrl_info.value_1, + ctrl_info.value_2); + break; + + case EXT_CAM_GET_FLASH_STATUS: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + err = s5c73m3_get_pre_flash(ctrl_info.value_1); + ctrl_info.value_1 = isPreflashFired; + break; + + case EXT_CAM_START_AE_AWB_LOCK: + err = s5c73m3_aeawb_lock_unlock(ctrl_info.value_1, + ctrl_info.value_2); + break; + + case EXT_CAM_GET_AE_AWB_LOCK: + ctrl_info.value_1 = s5c73m3_ctrl->isAeLock; + ctrl_info.value_2 = s5c73m3_ctrl->isAwbLock; + break; + + case EXT_CAM_SET_VDIS: + s5c73m3_set_vdis(ctrl_info.value_1); + break; + + case EXT_CAM_GET_LUX: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + ctrl_info.value_1 = s5c73m3_get_lux(); + break; + + case EXT_CAM_SET_FACE_ZOOM: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + err = s5c73m3_set_face_zoom(ctrl_info.value_1); + break; + + case EXT_CAM_UPDATE_FW: + /* check whether ISP can be used */ + err = s5c73m3_wait_ISP_status(); + if (err < 0) { + cam_err("failed s5c73m3_wait_ISP_status\n"); + return; + } + + if (ctrl_info.value_1 == CAM_FW_MODE_DUMP) + err = s5c73m3_dump_fw(); + else if (ctrl_info.value_1 == CAM_FW_MODE_UPDATE) + err = s5c73m3_check_fw(s5c73m3_ctrl->sensordata, 1); + else + err = 0; + break; + + case EXT_CAM_ANTI_BANDING: + err = s5c73m3_set_antibanding(ctrl_info.value_1); + break; + + default: + CAM_DBG_M("default mode\n"); + break; + } + + if (err < 0) + cam_err("failed sensor_native_control handle " + "ctrl_info.mode %d\n", ctrl_info.mode); + + if (copy_to_user((void *)arg, + (const void *)&ctrl_info, sizeof(ctrl_info))) + CAM_DBG_M("fail copy_to_user!\n"); + +} + +int s5c73m3_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cfg_data; + long rc = 0; + + CAM_DBG_M("Entered\n"); + + if (copy_from_user(&cfg_data, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + cam_err("s5c73m3_ioctl, cfgtype = %d, mode = %d\n", + cfg_data.cfgtype, cfg_data.mode); + + switch (cfg_data.cfgtype) { + case CFG_SET_MODE: + rc = s5c73m3_set_sensor_mode( + cfg_data.mode); + break; + + case CFG_GET_AF_MAX_STEPS: + default: + rc = 0; + cam_err("Invalid cfgtype\n"); + break; + } + + return rc; +} + +int s5c73m3_sensor_release(void) +{ + int rc = 0; + CAM_DBG_M("Entered\n"); + s5c73m3_set_af_softlanding(); + usleep(10*1000); + /*power off the LDOs*/ + /*s5c73m3_ctrl->sensordata->sensor_platform_info->sensor_power_off(0);*/ + + return rc; +} + +static int s5c73m3_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CAM_DBG_M("Entered\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + rc = -ENOTSUPP; + goto probe_failure; + } + + s5c73m3_sensorw = + kzalloc(sizeof(struct s5c73m3_work), GFP_KERNEL); + + if (!s5c73m3_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, s5c73m3_sensorw); + s5c73m3_init_client(client); + s5c73m3_client = client; + + + CAM_DBG_M("Exit\n"); + + return 0; + +probe_failure: + kfree(s5c73m3_sensorw); + s5c73m3_sensorw = NULL; + cam_err("s5c73m3_probe failed!\n"); + return rc; +} + +static const struct i2c_device_id s5c73m3_i2c_id[] = { + { SENSOR_NAME, 0}, + { }, +}; + +static struct i2c_driver s5c73m3_i2c_driver = { + .id_table = s5c73m3_i2c_id, + .probe = s5c73m3_i2c_probe, + .remove = __exit_p(s5c73m3_i2c_remove), + .driver = { + .name = SENSOR_NAME, + }, +}; + + +static int s5c73m3_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int ret = -EIO; + int rc = i2c_add_driver(&s5c73m3_i2c_driver); + CAM_DBG_M("Entered\n"); + + if (rc < 0 || s5c73m3_client == NULL) { + //cam_err("%d :%d\n", rc, s5c73m3_client); + rc = -ENOTSUPP; + goto probe_done; + } + + ret = s5c73m3_spi_init(); + if (ret) + cam_err("failed to register s5c73mc fw - %x\n", ret); + +#if !defined(CONFIG_S5C73M3) && !defined(CONFIG_S5K6A3YX) + msm_camio_clk_rate_set(24000000); +#endif + + s->s_init = s5c73m3_sensor_init; + s->s_release = s5c73m3_sensor_release; + s->s_config = s5c73m3_sensor_config; + s->s_camera_type = BACK_CAMERA_2D; + s->s_mount_angle = 90; + +probe_done: + cam_err("Probe_done!!\n"); + return rc; +} + + +static struct s5c73m3_format s5c73m3_subdev_info[] = { + { +#if defined(YUV_PREVIEW) + .code = V4L2_MBUS_FMT_YUYV8_2X8, +#else + .code = V4L2_MBUS_FMT_SBGGR10_1X10, +#endif + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static int s5c73m3_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + CAM_DBG_H("Entered, index %d\n", index); + if ((unsigned int)index >= ARRAY_SIZE(s5c73m3_subdev_info)) + return -EINVAL; + + *code = s5c73m3_subdev_info[index].code; + return 0; +} + +static struct v4l2_subdev_core_ops s5c73m3_subdev_core_ops; +static struct v4l2_subdev_video_ops s5c73m3_subdev_video_ops = { + .enum_mbus_fmt = s5c73m3_enum_fmt, +}; + +static struct v4l2_subdev_ops s5c73m3_subdev_ops = { + .core = &s5c73m3_subdev_core_ops, + .video = &s5c73m3_subdev_video_ops, +}; + +static int s5c73m3_sensor_probe_cb(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + int rc = 0; + CAM_DBG_M("Entered\n"); + + rc = s5c73m3_sensor_probe(info, s); + if (rc < 0) + return rc; + + s5c73m3_ctrl = kzalloc(sizeof(struct s5c73m3_ctrl), GFP_KERNEL); + if (!s5c73m3_ctrl) { + cam_err("s5c73m3_sensor_probe failed!\n"); + return -ENOMEM; + } + + /* probe is successful, init a v4l2 subdevice */ + if (sdev) { + v4l2_i2c_subdev_init(sdev, s5c73m3_client, + &s5c73m3_subdev_ops); + s5c73m3_ctrl->sensor_dev = sdev; + } else { + cam_err("sdev is null in probe_cb\n"); + } + return rc; +} + +static int __s5c73m3_probe(struct platform_device *pdev) +{ + CAM_DBG_M("S5C73M3 probe\n"); + + return msm_sensor_register(pdev, s5c73m3_sensor_probe_cb); +} + +static struct platform_driver msm_camera_driver = { + .probe = __s5c73m3_probe, + .driver = { + .name = PLATFORM_DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init s5c73m3_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(s5c73m3_init); +MODULE_DESCRIPTION("Samsung 8 MP camera driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/sensors/s5c73m3.h b/drivers/media/video/msm_zsl/sensors/s5c73m3.h new file mode 100644 index 00000000000..1886d5d8318 --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/s5c73m3.h @@ -0,0 +1,1067 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __S5C73M3_H__ +#define __S5C73M3_H__ + +#include +#include + +/*#define DEBUG_LEVEL_HIGH */ +#define DEBUG_LEVEL_MID + +/* #define DEBUG_CAM_I2C */ + +#if defined(DEBUG_LEVEL_HIGH) +#define CAM_DBG_H(fmt, arg...)\ + do { \ + printk(KERN_ERR "[%s:%d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) +#define CAM_DBG_M(fmt, arg...)\ + do { \ + printk(KERN_ERR "[%s:%d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) +#elif defined(DEBUG_LEVEL_MID) +#define CAM_DBG_H(fmt, arg...) +#define CAM_DBG_M(fmt, arg...)\ + do { \ + printk(KERN_ERR "[%s:%d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) +#else +#define CAM_DBG_H(fmt, arg...) +#define CAM_DBG_M(fmt, arg...) +#endif + +#if defined(DEBUG_CAM_I2C) +#define cam_i2c_dbg(fmt, arg...) \ + do { \ + printk(KERN_ERR "[%s : % d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) +#else +#define cam_i2c_dbg(fmt, arg...) +#endif + +#define cam_err(fmt, arg...) \ + do { \ + printk(KERN_ERR "[%s : % d] " fmt, \ + __func__, __LINE__, ##arg); \ + } \ + while (0) + +#define CAPTURE_FLASH 1 +#define MOVIE_FLASH 0 + +#define S5C73M3_FW_VER_LEN 6 +#define S5C73M3_FW_VER_FILE_CUR 0x60 +/* level at or below which we need to enable flash when in auto mode */ +#define LOW_LIGHT_LEVEL 0x20 + + +/* DTP */ +#define DTP_OFF 0 +#define DTP_ON 1 +#define DTP_OFF_ACK 2 +#define DTP_ON_ACK 3 + +struct s5c73m3_userset { + unsigned int focus_mode; + unsigned int focus_status; + unsigned int continuous_af; + + unsigned int metering; + unsigned int exposure; + unsigned int wb; + unsigned int iso; + int contrast; + int saturation; + int sharpness; + int brightness; + int scene; + unsigned int zoom; + unsigned int effect; /* Color FX (AKA Color tone) */ + unsigned int scenemode; + unsigned int detectmode; + unsigned int antishake; + unsigned int fps; + unsigned int flash_mode; + unsigned int flash_state; + + unsigned int stabilize; /* IS */ + + unsigned int strobe; + unsigned int jpeg_quality; + /*unsigned int preview_size;*/ + /*struct m5mo_preview_size preview_size;*/ + unsigned int preview_size_idx; + unsigned int capture_size; + unsigned int thumbnail_size; + + +}; + + +/*extern struct s5c73m3_reg s5c73m3_regs;*/ +struct reg_struct_init { + /* PLL setting */ + uint8_t pre_pll_clk_div; /* 0x0305 */ + uint8_t plstatim; /* 0x302b */ + uint8_t reg_3024; /*ox3024*/ + uint8_t image_orientation; /* 0x0101*/ + uint8_t vndmy_ablmgshlmt; /*0x300a*/ + uint8_t y_opbaddr_start_di; /*0x3014*/ + uint8_t reg_0x3015; /*0x3015*/ + uint8_t reg_0x301c; /*0x301c*/ + uint8_t reg_0x302c; /*0x302c*/ + uint8_t reg_0x3031; /*0x3031*/ + uint8_t reg_0x3041; /* 0x3041 */ + uint8_t reg_0x3051; /* 0x3051 */ + uint8_t reg_0x3053; /* 0x3053 */ + uint8_t reg_0x3057; /* 0x3057 */ + uint8_t reg_0x305c; /* 0x305c */ + uint8_t reg_0x305d; /* 0x305d */ + uint8_t reg_0x3060; /* 0x3060 */ + uint8_t reg_0x3065; /* 0x3065 */ + uint8_t reg_0x30aa; /* 0x30aa */ + uint8_t reg_0x30ab; + uint8_t reg_0x30b0; + uint8_t reg_0x30b2; + uint8_t reg_0x30d3; + uint8_t reg_0x3106; + uint8_t reg_0x310c; + uint8_t reg_0x3304; + uint8_t reg_0x3305; + uint8_t reg_0x3306; + uint8_t reg_0x3307; + uint8_t reg_0x3308; + uint8_t reg_0x3309; + uint8_t reg_0x330a; + uint8_t reg_0x330b; + uint8_t reg_0x330c; + uint8_t reg_0x330d; + uint8_t reg_0x330f; + uint8_t reg_0x3381; +}; + +struct reg_struct { + uint8_t pll_multiplier; /* 0x0307 */ + uint8_t frame_length_lines_hi; /* 0x0340*/ + uint8_t frame_length_lines_lo; /* 0x0341*/ + uint8_t y_addr_start; /* 0x347 */ + uint8_t y_add_end; /* 0x034b */ + uint8_t x_output_size_msb; /* 0x034c */ + uint8_t x_output_size_lsb; /* 0x034d */ + uint8_t y_output_size_msb; /* 0x034e */ + uint8_t y_output_size_lsb; /* 0x034f */ + uint8_t x_even_inc; /* 0x0381 */ + uint8_t x_odd_inc; /* 0x0383 */ + uint8_t y_even_inc; /* 0x0385 */ + uint8_t y_odd_inc; /* 0x0387 */ + uint8_t hmodeadd; /* 0x3001 */ + uint8_t vmodeadd; /* 0x3016 */ + uint8_t vapplinepos_start;/*ox3069*/ + uint8_t vapplinepos_end;/*306b*/ + uint8_t shutter; /* 0x3086 */ + uint8_t haddave; /* 0x30e8 */ + uint8_t lanesel; /* 0x3301 */ +}; + +struct s5c73m3_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum s5c73m3_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +struct s5c73m3_focus { + unsigned int mode; + unsigned int caf_mode; + unsigned int lock; + unsigned int status; + unsigned int touch; + unsigned int pos_x; + unsigned int pos_y; +}; + +struct s5c73m3_fw_version { + unsigned int index; + unsigned int opened; + char path[25]; + char ver[10]; +}; + +enum s5c73m_flash_mode { + MAIN_CAMERA_FLASH_OFF, + MAIN_CAMERA_FLASH_ON, + MAIN_CAMERA_FLASH_AUTO, + MAIN_CAMERA_FLASH_TORCH, + MAIN_CAMERA_FLASH_MAX +}; + +enum s5c73m_fd_mode { + FACE_DETECTION_OFF, + FACE_DETECTION_ON, + FACE_DETECTION_MAX +}; + +enum s5c73m_jpeg_size { + JPEG_3264_2448, + JPEG_3264_1836, + JPEG_2048_1536, + JPEG_2048_1152, + JPEG_1600_1200, + JPEG_1280_720, + JPEG_640_480 +}; + +enum s5c73m3_isneed_flash_tristate { + S5C73M3_ISNEED_FLASH_OFF = 0x00, + S5C73M3_ISNEED_FLASH_ON = 0x01, + S5C73M3_ISNEED_FLASH_UNDEFINED = 0x02, +}; + +enum s5c73m3_wdr_mode { + WDR_OFF, + WDR_ON, + WDR_MAX, +}; + +struct s5c73m3_focus camera_focus; +enum s5c73m_flash_mode flash_mode; +char isflash; +unsigned int isPreflashFired; + +enum s5c73m3_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +enum s5c73m3_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum s5c73m3_fw_path { + S5C73M3_SD_CARD, + S5C73M3_IN_DATA, + S5C73M3_IN_SYSTEM, + S5C73M3_PATH_MAX, +}; + + +#define S5C73M3_IMG_OUTPUT 0x0902 +#define S5C73M3_HDR_OUTPUT 0x0008 +#define S5C73M3_YUV_OUTPUT 0x0009 +#define S5C73M3_INTERLEAVED_OUTPUT 0x000D +#define S5C73M3_HYBRID_OUTPUT 0x0016 + +#define S5C73M3_STILL_PRE_FLASH 0x0A00 +#define S5C73M3_STILL_PRE_FLASH_FIRE 0x0000 +#define S5C73M3_STILL_PRE_FLASH_NON_FIRED 0x0000 +#define S5C73M3_STILL_PRE_FLASH_FIRED 0x0001 + +#define S5C73M3_STILL_MAIN_FLASH 0x0A02 +#define S5C73M3_STILL_MAIN_FLASH_CANCEL 0x0001 +#define S5C73M3_STILL_MAIN_FLASH_FIRE 0x0002 + + +#define S5C73M3_ZOOM_STEP 0x0B00 + + +#define S5C73M3_IMAGE_EFFECT 0x0B0A +#define S5C73M3_IMAGE_EFFECT_NONE 0x0001 +#define S5C73M3_IMAGE_EFFECT_NEGATIVE 0x0002 +#define S5C73M3_IMAGE_EFFECT_AQUA 0x0003 +#define S5C73M3_IMAGE_EFFECT_SEPIA 0x0004 +#define S5C73M3_IMAGE_EFFECT_MONO 0x0005 +#define S5C73M3_IMAGE_EFFECT_SKETCH 0x0006 +#define S5C73M3_IMAGE_EFFECT_WASHED 0x0007 +#define S5C73M3_IMAGE_EFFECT_VINTAGE_WARM 0x0008 +#define S5C73M3_IMAGE_EFFECT_VINTAGE_COLD 0x0009 +#define S5C73M3_IMAGE_EFFECT_SOLARIZE 0x000A +#define S5C73M3_IMAGE_EFFECT_POSTERIZE 0x000B +#define S5C73M3_IMAGE_EFFECT_POINT_COLOR_1 0x000C +#define S5C73M3_IMAGE_EFFECT_POINT_COLOR_2 0x000D +#define S5C73M3_IMAGE_EFFECT_POINT_COLOR_3 0x000E +#define S5C73M3_IMAGE_EFFECT_POINT_COLOR_4 0x000F + + +#define S5C73M3_IMAGE_QUALITY 0x0B0C +#define S5C73M3_IMAGE_QUALITY_SUPERFINE 0x0000 +#define S5C73M3_IMAGE_QUALITY_FINE 0x0001 +#define S5C73M3_IMAGE_QUALITY_NORMAL 0x0002 +#define S5C73M3_IMAGE_QUALITY_LOW 0x0003 + +#define S5C73M3_FLASH_MODE 0x0B0E +#define S5C73M3_FLASH_MODE_OFF 0x0000 +#define S5C73M3_FLASH_MODE_ON 0x0001 +#define S5C73M3_FLASH_MODE_AUTO 0x0002 + +#define S5C73M3_FLASH_STATUS 0x0B80 +#define S5C73M3_FLASH_STATUS_OFF 0x0001 +#define S5C73M3_FLASH_STATUS_ON 0x0002 +#define S5C73M3_FLASH_STATUS_AUTO 0x0003 + +#define S5C73M3_FLASH_TORCH 0x0B12 +#define S5C73M3_FLASH_TORCH_OFF 0x0000 +#define S5C73M3_FLASH_TORCH_ON 0x0001 + +#define S5C73M3_AE_ISNEEDFLASH 0x0CBA +#define S5C73M3_AE_ISNEEDFLASH_OFF 0x0000 +#define S5C73M3_AE_ISNEEDFLASH_ON 0x0001 + + +#define S5C73M3_CHG_MODE 0x0B10 +#define S5C73M3_YUV_MODE 0x8000 +#define S5C73M3_INTERLEAVED_MODE 0x8000 +#define S5C73M3_CHG_MODE_YUV_320_240 0x8001 +#define S5C73M3_CHG_MODE_YUV_640_480 0x8002 +#define S5C73M3_CHG_MODE_YUV_880_720 0x8003 +#define S5C73M3_CHG_MODE_YUV_960_720 0x8004 +#define S5C73M3_CHG_MODE_YUV_1184_666 0x8005 +#define S5C73M3_CHG_MODE_YUV_1280_720 0x8006 +#define S5C73M3_CHG_MODE_YUV_1280_960 0x8007 +#define S5C73M3_CHG_MODE_YUV_1600_1200 0x8008 +#define S5C73M3_CHG_MODE_YUV_1632_1224 0x8009 +#define S5C73M3_CHG_MODE_YUV_1920_1080 0x800A +#define S5C73M3_CHG_MODE_YUV_1920_1440 0x800B +#define S5C73M3_CHG_MODE_YUV_2304_1296 0x800C +#define S5C73M3_CHG_MODE_YUV_2304_1728 0x800D +#define S5C73M3_CHG_MODE_JPEG_640_480 0x0010 +#define S5C73M3_CHG_MODE_JPEG_800_450 0x0020 +#define S5C73M3_CHG_MODE_JPEG_800_600 0x0030 +#define S5C73M3_CHG_MODE_JPEG_1280_720 0x0040 +#define S5C73M3_CHG_MODE_JPEG_1280_960 0x0050 +#define S5C73M3_CHG_MODE_JPEG_1600_960 0x0060 +#define S5C73M3_CHG_MODE_JPEG_1600_1200 0x0070 +#define S5C73M3_CHG_MODE_JPEG_2048_1152 0x0080 +#define S5C73M3_CHG_MODE_JPEG_2048_1536 0x0090 +#define S5C73M3_CHG_MODE_JPEG_2560_1440 0x00A0 +#define S5C73M3_CHG_MODE_JPEG_2560_1920 0x00B0 +#define S5C73M3_CHG_MODE_JPEG_3072_1728 0x00C0 +#define S5C73M3_CHG_MODE_JPEG_3264_2304 0x00D0 +#define S5C73M3_CHG_MODE_JPEG_3264_1836 0x00E0 +#define S5C73M3_CHG_MODE_JPEG_3264_2448 0x00F0 + + +#define S5C73M3_AF_CON 0x0E00 +#define S5C73M3_AF_CON_STOP 0x0000 +#define S5C73M3_AF_CON_SCAN 0x0001/*AF_SCAN:Full Search*/ +#define S5C73M3_AF_CON_START 0x0002/*AF_START:Fast Search*/ + +#define S5C73M3_AF_STATUS 0x5E80 + +#define S5C73M3_AF_TOUCH_AF 0x0E0A + +#define S5C73M3_AF_CAL 0x0E06 + +#define S5C73M3_CAF_STATUS_FIND_SEARCHING_DIR 0x0001 +#define S5C73M3_CAF_STATUS_FOCUSING 0x0002 +#define S5C73M3_CAF_STATUS_FOCUSED 0x0003 +#define S5C73M3_CAF_STATUS_INITIALIZE 0x0004 + +#define S5C73M3_AF_STATUS_INVALID 0x0010 +#define S5C73M3_AF_STATUS_FOCUSING 0x0020 +#define S5C73M3_AF_STATUS_FOCUSED 0x0030/*SUCCESS*/ +#define S5C73M3_AF_STATUS_UNFOCUSED 0x0040/*FAIL*/ + +#define S5C73M3_AF_TOUCH_POSITION 0x5E8E + +#define S5C73M3_AF_FACE_ZOOM 0x0E10 + +#define S5C73M3_AF_MODE 0x0E02 +#define S5C73M3_AF_MODE_NORMAL 0x0000 +#define S5C73M3_AF_MODE_MACRO 0x0001 +#define S5C73M3_AF_MODE_MOVIE_CAF_START 0x0002 +#define S5C73M3_AF_MODE_MOVIE_CAF_STOP 0x0003 +#define S5C73M3_AF_MODE_PREVIEW_CAF_START 0x0004 +#define S5C73M3_AF_MODE_PREVIEW_CAF_STOP 0x0005 + +#define S5C73M3_AF_SOFTLANDING 0x0E16 +#define S5C73M3_AF_SOFTLANDING_ON 0x0000 + +#define S5C73M3_FACE_DET 0x0E0C +#define S5C73M3_FACE_DET_OFF 0x0000 +#define S5C73M3_FACE_DET_ON 0x0001 + +#define S5C73M3_FACE_DET_OSD 0x0E0E +#define S5C73M3_FACE_DET_OSD_OFF 0x0000 +#define S5C73M3_FACE_DET_OSD_ON 0x0001 + +#define S5C73M3_AE_CON 0x0C00 +#define S5C73M3_AE_STOP 0x0000/*LOCK*/ +#define S5C73M3_AE_START 0x0001/*UNLOCK*/ + +#define S5C73M3_ISO 0x0C02 +#define S5C73M3_ISO_AUTO 0x0000 +#define S5C73M3_ISO_100 0x0001 +#define S5C73M3_ISO_200 0x0002 +#define S5C73M3_ISO_400 0x0003 +#define S5C73M3_ISO_800 0x0004 +#define S5C73M3_ISO_SPORTS 0x0005 +#define S5C73M3_ISO_NIGHT 0x0006 +#define S5C73M3_ISO_INDOOR 0x0007 + +#define S5C73M3_EV 0x0C04 +#define S5C73M3_EV_M20 0x0000 +#define S5C73M3_EV_M15 0x0001 +#define S5C73M3_EV_M10 0x0002 +#define S5C73M3_EV_M05 0x0003 +#define S5C73M3_EV_ZERO 0x0004 +#define S5C73M3_EV_P05 0x0005 +#define S5C73M3_EV_P10 0x0006 +#define S5C73M3_EV_P15 0x0007 +#define S5C73M3_EV_P20 0x0008 + +#define S5C73M3_METER 0x0C06 +#define S5C73M3_METER_CENTER 0x0000 +#define S5C73M3_METER_SPOT 0x0001 +#define S5C73M3_METER_AVERAGE 0x0002 +#define S5C73M3_METER_SMART 0x0003 + +#define S5C73M3_WDR 0x0C08 +#define S5C73M3_WDR_OFF 0x0000 +#define S5C73M3_WDR_ON 0x0001 + +#define S5C73M3_FLICKER_MODE 0x0C12 +#define S5C73M3_FLICKER_NONE 0x0000 +#define S5C73M3_FLICKER_MANUAL_50HZ 0x0001 +#define S5C73M3_FLICKER_MANUAL_60HZ 0x0002 +#define S5C73M3_FLICKER_AUTO 0x0003 +#define S5C73M3_FLICKER_AUTO_50HZ 0x0004 +#define S5C73M3_FLICKER_AUTO_60HZ 0x0005 + +#define S5C73M3_AE_MODE 0x0C1E +#define S5C73M3_AUTO_MODE_AE_SET 0x0000 +#define S5C73M3_FIXED_30FPS 0x0002 +#define S5C73M3_FIXED_20FPS 0x0003 +#define S5C73M3_FIXED_15FPS 0x0004 +#define S5C73M3_FIXED_7FPS 0x0009 +#define S5C73M3_ANTI_SHAKE_ON 0x0013 + +#define S5C73M3_SHARPNESS 0x0C14 +#define S5C73M3_SHARPNESS_0 0x0000 +#define S5C73M3_SHARPNESS_1 0x0001 +#define S5C73M3_SHARPNESS_2 0x0002 +#define S5C73M3_SHARPNESS_M1 0x0003 +#define S5C73M3_SHARPNESS_M2 0x0004 + +#define S5C73M3_SATURATION 0x0C16 +#define S5C73M3_SATURATION_0 0x0000 +#define S5C73M3_SATURATION_1 0x0001 +#define S5C73M3_SATURATION_2 0x0002 +#define S5C73M3_SATURATION_M1 0x0003 +#define S5C73M3_SATURATION_M2 0x0004 + +#define S5C73M3_CONTRAST 0x0C18 +#define S5C73M3_CONTRAST_0 0x0000 +#define S5C73M3_CONTRAST_1 0x0001 +#define S5C73M3_CONTRAST_2 0x0002 +#define S5C73M3_CONTRAST_M1 0x0003 +#define S5C73M3_CONTRAST_M2 0x0004 + +#define S5C73M3_SCENE_MODE 0x0C1A +#define S5C73M3_SCENE_MODE_NONE 0x0000 +#define S5C73M3_SCENE_MODE_PORTRAIT 0x0001 +#define S5C73M3_SCENE_MODE_LANDSCAPE 0x0002 +#define S5C73M3_SCENE_MODE_SPORTS 0x0003 +#define S5C73M3_SCENE_MODE_INDOOR 0x0004 +#define S5C73M3_SCENE_MODE_BEACH 0x0005 +#define S5C73M3_SCENE_MODE_SUNSET 0x0006 +#define S5C73M3_SCENE_MODE_DAWN 0x0007 +#define S5C73M3_SCENE_MODE_FALL 0x0008 +#define S5C73M3_SCENE_MODE_NIGHT 0x0009 +#define S5C73M3_SCENE_MODE_AGAINSTLIGHT 0x000A +#define S5C73M3_SCENE_MODE_FIRE 0x000B +#define S5C73M3_SCENE_MODE_TEXT 0x000C +#define S5C73M3_SCENE_MODE_CANDLE 0x000D + +#define S5C73M3_FIREWORK_CAPTURE 0x0C20 +#define S5C73M3_NIGHTSHOT_CAPTURE 0x0C22 + +#define S5C73M3_AE_AUTO_BRAKET 0x0B14 +#define S5C73M3_AE_AUTO_BRAKET_EV05 0x0080 +#define S5C73M3_AE_AUTO_BRAKET_EV10 0xC100 +#define S5C73M3_AE_AUTO_BRAKET_EV15 0x0180 +#define S5C73M3_AE_AUTO_BRAKET_EV20 0x8200 + +#define S5C73M3_LLS_MODE 0x0C2C +#define S5C73M3_LLS_MODE_ON 0x0001 +#define S5C73M3_LLS_MODE_OFF 0x0000 + +#define S5C73M3_SENSOR_STREAMING 0x090A +#define S5C73M3_SENSOR_STREAMING_OFF 0x0000 +#define S5C73M3_SENSOR_STREAMING_ON 0x0001 + +#define S5C73M3_AWB_MODE 0x0D02 +#define S5C73M3_AWB_MODE_INCANDESCENT 0x0000 +#define S5C73M3_AWB_MODE_FLUORESCENT1 0x0001 +#define S5C73M3_AWB_MODE_FLUORESCENT2 0x0002 +#define S5C73M3_AWB_MODE_DAYLIGHT 0x0003 +#define S5C73M3_AWB_MODE_CLOUDY 0x0004 +#define S5C73M3_AWB_MODE_AUTO 0x0005 + +#define S5C73M3_AWB_CON 0x0D00 +#define S5C73M3_AWB_STOP 0x0000/*LOCK*/ +#define S5C73M3_AWB_START 0x0001/*UNLOCK*/ + +#define S5C73M3_HYBRID_CAPTURE 0x0996 + +/* S5C73M3 Sensor Mode */ +#define S5C73M3_SYSINIT_MODE 0x0 +#define S5C73M3_PARMSET_MODE 0x1 +#define S5C73M3_MONITOR_MODE 0x2 +#define S5C73M3_STILLCAP_MODE 0x3 + +#define S5C73M3_STATUS 0x5080 +#define S5C73M3_I2C_ERR_STATUS 0x599E +#define S5C73M3_I2C_SEQ_STATUS 0x59A6 +#define ERROR_STATUS_CHECK_BIN_CRC (1<<0x8) + +static const u32 S5C73M3_INIT[] = { +0x00500009, +0x00545000, +0x0F140B08, +0x0F140000, +0x0F140900, +0x0F140403, /*640MHz*/ +0x00545080, +0x0F140002 +}; + +/* +MIPI_BIT_RATE_360MHz=0, +MIPI_BIT_RATE_450MHz=1, +MIPI_BIT_RATE_540MHz=2, +MIPI_BIT_RATE_640MHz=3, +MIPI_BIT_RATE_720MHz=4, +MIPI_BIT_RATE_750MHz=5, +*/ +#if 0 +static u32 S5C73M3_YUV_PREVIEW[] = { + 0x00500009, + 0x00545000, + 0x0F140902, + 0x0F140009, + 0x0F140900, /* MIPI OUTPUT CLK */ + 0x0F140401, /* MIPI_BIT_RATE_450MHz=1 */ + 0x0F140B10, + 0x0F148004, + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140004, +}; +#endif +static u32 S5C73M3_HDR[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MiPi 0xetting */ + 0x0F140403, /* Lane:4 , DataRate:3(640Mbp0x) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :D(interleave)0x14VC */ + 0x0F140B10, + 0x0F14801D, /* (1:640x480 JPEG D:3264 2448 YUV) */ + 0x00545080, + 0x0F140003, +}; + +static u32 S5C73M3_LLS[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MiPi 0xetting */ + 0x0F140403, /* Lane:4 , DataRate:3(640Mbp0x) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :D(interleave)0x14VC */ + 0x0F140B10, + 0x0F14801D, /* (1:640x480 JPEG D:3264 2448 YUV) */ + 0x00545080, + 0x0F140003, +}; + +static u32 S5C73M3_FHD_VDIS[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140003, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F14811C, /*E:3264X1836 JPEG, C:2304 x 1296 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_FHD[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481EA, /*E:3264X1836 JPEG, A:1920 x 1080 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_HD_VDIS[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148117, /*E:3264X1836 JPEG, 7: YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_HD[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481E6, /*E:3264X1836 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_WVGA[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481CF, /*C:3264X2176 JPEG, F:1008X672 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_VGA[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481F2, /*F:3264X2448 JPEG, 2:640 x 480 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_PREVIEW[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x00545080, + 0x0F140003, +}; +#if 0 +/* Below Not used settings will be removed later */ +static u32 S5C73M3_INTERLEAVED_PREVIEW[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140401, /*450MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140003, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1480F4, /*F:3264X2448 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_8M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1480F4, /*F:3264X2448 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_6M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1480E6, /*E:3264X1836 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_3_2M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148094, /*9:2048X1536 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_2_4M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148086, /*8:2048X1156 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_2M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148074, /*7:1600X1200 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_1M[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148046, /*4:1280X720 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_VGA[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148014, /*1:640X480 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_INTERLEAVED_PREVIEW_HD[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1480F6, /*F:3264X2448 JPEG, 6:1280X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_STND[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481FA, /*F:3264X2448 JPEG, A:1920 x 1080 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 CAM_IL_PREVIEW_WIDE[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140403, /*640MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F1481EA, /*E:3264X1836 JPEG, A:1920 x 1080 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +static u32 S5C73M3_INTERLEAVED_PREVIEW_30[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /*MIPI Setting*/ + 0x0F140402, /*540MHz*/ + 0x0F140902, /*Change out interleave*/ + 0x0F140014, /*Image out mode*/ + 0x0F14091A, /*ISP PCLK SET*/ + 0x0F140004, /*0:27, 1:129.6, 2:140.4, 3:194.4, 4:264*/ + 0x0F140B10, + 0x0F148074, /*F:1600X1200 JPEG, 4:960X720 YUV*/ + 0x0F14090A, + 0x0F140001, + 0x00545080, + 0x0F140005, +}; + +/* MIPI 4lane(540Mhz),30fps, YUV 1920x1080(FHD), JPEG : 1600x1200(2M) */ +static u32 S5C73M3_INTERLEAVED_CAMCORDER_1[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MIPI Setting */ + 0x0F140402, /* Mipi Lane 4:4Lane, + DataRate(1:450Mbps, 2:540Mbps 3:640Mbps, 4:720Mbps) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :14 + (For Qualcomm VC Interleaved) */ + 0x0F14091A, /* ISP PCLK Set */ + 0x0F140004, /* Mhz 0:27 1:129.6 + 2:140 3:194.4 4:264Mhz */ + 0x0F140B10, /* Mode Change */ + 0x0F14807A, /* 7:1600x1200 JPEG A:1920x1080 YUV */ + 0x0F140C1E, /* Frame rate set */ + 0x0F140002, /* 0 : 30~15f/s 1:24~30f/s 2:30f/s + 3:20f/s 4:15f/s fixed 5:24f/s 6:27f/s */ + 0x0F14090A, /* Sensor Stream control */ + 0x0F140001, /* 0 : Stop 1:Start */ + 0x00545080, /* Run I2C Function */ + 0x0F140006, +}; + +/* MIPI 4lane(540Mhz),30fps, YUV 1920x1080(FHD), JPEG : 2560x1920 */ +static u32 S5C73M3_INTERLEAVED_CAMCORDER_2[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MIPI Setting */ + 0x0F140402, /* Mipi Lane 4:4Lane, + DataRate(1:450Mbps, 2:540Mbps 3:640Mbps, 4:720Mbps) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :14 (For Qualcomm VC Interleaved) */ + 0x0F14091A, /* ISP PCLK Set */ + 0x0F140004, /* Mhz 0:27 1:129.6 + 2:140 3:194.4 4:264Mhz */ + 0x0F140B10, /* Mode Change */ + 0x0F1480BA, /* B:2560x1920 JPEG A:1920x1080 YUV */ + 0x0F140C1E, /* Frame rate set */ + 0x0F140002, /* 0 : 30~15f/s 1:24~30f/s 2:30f/s + 3:20f/s 4:15f/s fixed 5:24f/s 6:27f/s */ + 0x0F14090A, /* Sensor Stream control */ + 0x0F140001, /* 0 : Stop 1:Start */ + 0x00545080, /* Run I2C Function */ + 0x0F140006, +}; + +/* MIPI 4lane(540Mhz),30fps, YUV 1920x1080(FHD), JPEG : 3264x1836(6M wide) */ +static u32 S5C73M3_INTERLEAVED_CAMCORDER_3[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MIPI Setting */ + 0x0F140402, /* Mipi Lane 4:4Lane, + DataRate(1:450Mbps, 2:540Mbps 3:640Mbps, 4:720Mbps) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :14 (For Qualcomm VC Interleaved) */ + 0x0F14091A, /* ISP PCLK Set */ + 0x0F140004, /* Mhz 0:27 1:129.6 + 2:140 3:194.4 4:264Mhz */ + 0x0F140B10, /* Mode Change */ + 0x0F1480EA, /* E:3264x1836 JPEG A:1920x1080 YUV */ + 0x0F140C1E, /* Frame rate set */ + 0x0F140002, /* 0 : 30~15f/s 1:24~30f/s 2:30f/s + 3:20f/s 4:15f/s fixed 5:24f/s 6:27f/s */ + 0x0F14090A, /* Sensor Stream control */ + 0x0F140001, /* 0 : Stop 1:Start */ + 0x00545080, /* Run I2C Function */ + 0x0F140006, +}; + +/* MIPI 4lane(540Mhz),30fps, YUV 1920x1080(FHD), JPEG : 3264x2448(8M wide) */ +static u32 S5C73M3_INTERLEAVED_CAMCORDER_4[] = { + 0x00500009, + 0x00545000, + 0x0F140900, /* MIPI Setting */ + 0x0F140402, /* Mipi Lane 4:4Lane, + DataRate(1:450Mbps, 2:540Mbps 3:640Mbps, 4:720Mbps) */ + 0x0F140902, /* Change Out interface */ + 0x0F140014, /* Image Out Mode :14 (For Qualcomm VC Interleaved) */ + 0x0F14091A, /* ISP PCLK Set */ + 0x0F140004, /* Mhz 0:27 1:129.6 + 2:140 3:194.4 4:264Mhz */ + 0x0F140B10, /* Mode Change */ + 0x0F1480FA, /* F:3264x2448 JPEG A:1920x1080 YUV */ + 0x0F140C1E, /* Frame rate set */ + 0x0F140002, /* 0 : 30~15f/s 1:24~30f/s 2:30f/s + 3:20f/s 4:15f/s fixed 5:24f/s 6:27f/s */ + 0x0F14090A, /* Sensor Stream control */ + 0x0F140001, /* 0 : Stop 1:Start */ + 0x00545080, /* Run I2C Function */ + 0x0F140006, +}; +static u32 S5C73M3_OTP_CONTROL[] = { +0xFCFC3310, +0x00503800, +0x0054A004, +0x0F140000, +0x0054A000, +0x0F140004, +0x0054A0D8, +0x0F140000, +0x0054A0DC, +0x0F140004, +0x0054A0C4, +0x0F144000, +0x0054A0D4, +0x0F140015, +0x0054A000, +0x0F140001, +0x0054A0B4, +0x0F149F90, +0x0054A09C, +0x0F149A95, +}; + +static u32 S5C73M3_OTP_PAGE[] = { +0x0054A0C4, +0x0F144800, +0x0054A0C4, +0x0F144400, +0x0054A0C4, +0x0F144200, +0x0054A004, +0x0F1400C0, +0x0054A000, +0x0F140001, +}; +#endif + +extern int s5c73m3_spi_read(u8 *buf, size_t len, const int rxSize); +extern int s5c73m3_spi_write(const u8 *addr, const int len, const int txSize); +extern int s5c73m3_spi_init(void); +extern void print_ldos(void); +#endif /* __S5C73M3_H__ */ diff --git a/drivers/media/video/msm_zsl/sensors/s5c73m3_spi.c b/drivers/media/video/msm_zsl/sensors/s5c73m3_spi.c new file mode 100644 index 00000000000..4fc3f33d939 --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/s5c73m3_spi.c @@ -0,0 +1,234 @@ +/* + * driver for S5C73M3 SPI + * + * Copyright (c) 2011, Samsung Electronics. All rights reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include + +#define cam_err(fmt, arg...) \ + do { \ + printk(KERN_ERR "[%s:%d] " fmt , \ + __func__, __LINE__, ##arg); \ + } \ + while (0) + +static struct spi_device *g_spi; + +/* If AP can't change the endian to BIG */ +/* for s5c73m ISP, this option must is required.*/ +/* This option depends on SPI_DMA_MODE */ +/* in camera driver file*/ +/*#define CHANGE_ENDIAN */ + +static inline +int spi_xmit(const u8 *addr, const int len) +{ + int ret; +#if defined(CHANGE_ENDIAN) + u8 buf[8] = {0}; +#endif + + struct spi_message msg; + + struct spi_transfer xfer = { + .len = len, +#if !defined(CHANGE_ENDIAN) + .tx_buf = addr, + /*QCTK ALRAN QUP_CONFIG 0-4 bits BIG ENDIAN*/ + .bits_per_word = 32, +#else + .tx_buf = buf, +#endif + }; + +#if defined(CHANGE_ENDIAN) + buf[0] = addr[3]; + buf[1] = addr[2]; + buf[2] = addr[1]; + buf[3] = addr[0]; + + buf[4] = addr[7]; + buf[5] = addr[6]; + buf[6] = addr[5]; + buf[7] = addr[4]; +#endif + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + ret = spi_sync(g_spi, &msg); + + if (ret < 0) + cam_err("error %d\n", ret); + + return ret; +} + +static inline +int spi_xmit_rx(u8 *in_buf, size_t len) +{ + int ret; + u8 read_out_buf[2]; + + struct spi_message msg; + struct spi_transfer xfer = { + .tx_buf = read_out_buf, + .rx_buf = in_buf, + .len = len, + .cs_change = 0, + }; + + spi_message_init(&msg); + + spi_message_add_tail(&xfer, &msg); + + ret = spi_sync(g_spi, &msg); + + if (ret < 0) + cam_err("%s - error %d\n", + __func__, ret); + + return ret; +} + +int s5c73m3_spi_read(u8 *buf, size_t len, const int rxSize) +{ + int k; + int ret = 0; +// int z = 0; + +// u8 paddingData[32]; + u8 temp_buf[4] = {0}; + u32 count = len/rxSize; + u32 extra = len%rxSize; + + for (k = 0; k < count; k++) { + ret = spi_xmit_rx(&buf[rxSize*k], rxSize); + if (ret < 0) { + cam_err("%s - error %d\n", + __func__, ret); + return -EINVAL; + } + } + + if (extra != 0) { + ret = spi_xmit_rx(&buf[rxSize*k], extra); + if (ret < 0) { + cam_err("%s - error %d\n", + __func__, ret); + return -EINVAL; + } + } + + for (k = 0; k < len-3; k += 4) { + memcpy(temp_buf, (char *)&buf[k], sizeof(temp_buf)); + buf[k] = temp_buf[3]; + buf[k+1] = temp_buf[2]; + buf[k+2] = temp_buf[1]; + buf[k+3] = temp_buf[0]; + } + + return 0; +} + +int s5c73m3_spi_write(const u8 *addr, const int len, const int txSize) +{ + int i, j = 0; + int ret = 0; + u8 paddingData[8]; + u32 count = len/txSize; + u32 extra = len%txSize; + cam_err("Entered\n"); + cam_err("count = %d extra = %d\n", count, extra); + + memset(paddingData, 0, sizeof(paddingData)); + + for (i = 0 ; i < count ; i++) { + ret = spi_xmit(&addr[j], txSize); + j += txSize; + if (ret < 0) { + cam_err("failed to write spi_xmit\n"); + goto exit_err; + } + } + + if (extra) { + ret = spi_xmit(&addr[j], extra); + if (ret < 0) { + cam_err("failed to write spi_xmit\n"); + goto exit_err; + } + } + + for (i = 0; i < 4; i++) { + memset(paddingData, 0, sizeof(paddingData)); + ret = spi_xmit(paddingData, 8); + if (ret < 0) { + cam_err("failed to write spi_xmit\n"); + goto exit_err; + } + } + cam_err("Finish!!\n"); +exit_err: + return ret; +} + +static int s5c73m3_spi_probe(struct spi_device *spi) +{ + int ret; + + cam_err("Entered\n"); + + if (spi_setup(spi)) { + cam_err("failed to setup spi for s5c73m3_spi\n"); + ret = -EINVAL; + goto err_setup; + } + + g_spi = spi; + + cam_err("s5c73m3_spi successfully probed\n"); + + return 0; + +err_setup: + return ret; +} + +static int __devexit s5c73m3_spi_remove(struct spi_device *spi) +{ + return 0; +} + +static struct spi_driver s5c73m3_spi_driver = { + .driver = { + .name = "s5c73m3_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = s5c73m3_spi_probe, + .remove = __devexit_p(s5c73m3_spi_remove), +}; + +int s5c73m3_spi_init(void) +{ + cam_err("Entered\n"); + + return spi_register_driver(&s5c73m3_spi_driver); +} + +void s5c73m3_spi_exit(void) +{ + spi_unregister_driver(&s5c73m3_spi_driver); +} diff --git a/drivers/media/video/msm_zsl/sensors/s5k6a3yx.c b/drivers/media/video/msm_zsl/sensors/s5k6a3yx.c new file mode 100644 index 00000000000..d0d5f86be6a --- /dev/null +++ b/drivers/media/video/msm_zsl/sensors/s5k6a3yx.c @@ -0,0 +1,559 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_sensor.h" +#include +#define SENSOR_NAME "s5k6a3yx" +#define PLATFORM_DRIVER_NAME "msm_camera_s5k6a3yx" + +DEFINE_MUTEX(s5k6a3yx_mut); +static struct msm_sensor_ctrl_t s5k6a3yx_s_ctrl; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_start_settings[] = { + {0x0100, 0x01}, +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_stop_settings[] = { + {0x0100, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_groupon_settings[] = { + {0x104, 0x01}, +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_groupoff_settings[] = { + {0x104, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_mode0_settings[] = { + {0x0344, 0x00}, /* x_addr_start MSB */ + {0x0345, 0x00}, /* x_addr_start LSB */ + {0x0346, 0x00}, /* y_addr_start MSB */ + {0x0347, 0x00}, /* y_addr_start LSB */ + {0x0348, 0x05}, /* x_addr_end MSB */ + {0x0349, 0x83}, /* x_addr_end LSB */ + {0x034A, 0x05}, /* y_addr_end MSB */ + {0x034B, 0x83}, /* y_addr_end LSB */ + {0x034C, 0x05}, /* x_output_size */ + {0x034D, 0x84}, /* x_output_size */ + {0x034E, 0x05}, /* y_output_size */ + {0x034F, 0x84}, /* y_output_size */ +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_mode1_settings[] = { + {0x0344, 0x00}, /* x_addr_start MSB */ + {0x0345, 0x00}, /* x_addr_start LSB */ + {0x0346, 0x00}, /* y_addr_start MSB */ + {0x0347, 0x00}, /* y_addr_start LSB */ + {0x0348, 0x05}, /* x_addr_end MSB */ + {0x0349, 0x83}, /* x_addr_end LSB */ + {0x034A, 0x05}, /* y_addr_end MSB */ + {0x034B, 0x83}, /* y_addr_end LSB */ + {0x034C, 0x05}, /* x_output_size */ + {0x034D, 0x80}, /* x_output_size */ + {0x034E, 0x05}, /* y_output_size */ + {0x034F, 0x84}, /* y_output_size */ +}; + +static struct msm_camera_i2c_reg_conf s5k6a3yx_recommend_settings[] = { + {0x0100, 0x00}, /* Streaming off */ + {0x3061, 0x55}, + {0x3062, 0x54}, + {0x5703, 0x07}, + {0x5704, 0x07}, + {0x305E, 0x0D}, + {0x305F, 0x2E}, + {0x3052, 0x01}, + {0x300B, 0x28}, + {0x300C, 0x2E}, + {0x3004, 0x0A}, + {0x5700, 0x08}, + {0x3005, 0x3D}, + {0x3008, 0x1E}, + {0x3025, 0x40}, + {0x3023, 0x20}, + {0x3029, 0xFF}, + {0x302A, 0xFF}, + {0x3505, 0x41}, + {0x3506, 0x00}, + {0x3521, 0x01}, + {0x3522, 0x01}, + {0x3D20, 0x63}, + {0x3095, 0x15}, + {0x3110, 0x01}, + {0x3111, 0x62}, + {0x3112, 0x0E}, + {0x3113, 0xBC}, + {0x311D, 0x30}, + {0x311F, 0x40}, + {0x3009, 0x1E}, + {0x0138, 0x00}, + /* MIPI CLK 720Mbps */ + {0x0305, 0x06}, /* pre_pll_clk_div */ + {0x0306, 0x00}, /* pll_multiplier MSB */ + {0x0307, 0xB4}, /* pll_multiplier LSB */ + {0x0820, 0x02}, /* requested_link_bit_rate_mbps MSB MSB */ + {0x0821, 0xD0}, /* requested_link_bit_rate_mbps MSB LSB */ + {0x0822, 0x00}, /* requested_link_bit_rate_mbps LSB MSB */ + {0x0823, 0x00}, /* requested_link_bit_rate_mbps LSB LSB */ + {0x0101, 0x00}, /* image_orientation */ + {0x0111, 0x02}, /* CSI_signaling_mode */ + {0x0112, 0x0A}, /* CSI_data_format MSB */ + {0x0113, 0x0A}, /* CSI_data_format LSB */ + {0x0136, 0x18}, /* extclk_frequency_mhz MSB */ + {0x0137, 0x00}, /* extclk_frequency_mhz LSB */ + {0x0200, 0x01}, /* fine_integration_time MSB */ + {0x0201, 0xD3}, /* fine_integration_time LSB */ + {0x0202, 0x05}, /* coarse_integration_time MSB */ + {0x0203, 0xA6}, /* coarse_integration_time LSB */ + {0x0204, 0x00}, /* analogue_gain_code_global MSB */ + {0x0205, 0x20}, /* analogue_gain_code_global LSB */ + {0x0340, 0x05}, /* frame_length_lines MSB */ + {0x0341, 0xAA}, /* frame_length_lines LSB */ + {0x0342, 0x06}, /* line_length_pck MSB */ + {0x0343, 0x42}, /* line_length_pck LSB */ + {0x0381, 0x01}, /* x_even_inc */ + {0x0383, 0x01}, /* x_odd_inc */ + {0x0385, 0x01}, /* y_even_inc */ + {0x0387, 0x01}, /* y_odd_inc */ + {0x0408, 0x00}, /* digital_crop_x_offset MSB */ + {0x0409, 0x00}, /* digital_crop_x_offset LSB */ + {0x040A, 0x00}, /* digital_crop_y_offset MSB */ + {0x040B, 0x00}, /* digital_crop_y_offset LSB */ + {0x040C, 0x05}, /* digital_crop_image_width MSB */ + {0x040D, 0x84}, /* digital_crop_image_width LSB */ + {0x040E, 0x05}, /* digital_crop_image_height MSB */ + {0x040F, 0x84}, /* digital_crop_image_height LSB */ + {0x0900, 0x00}, /* binning_mode */ + {0x0105, 0x01}, /* frame mask */ + }; + +static struct v4l2_subdev_info s5k6a3yx_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + /* more can be supported, to be added later */ +}; + +static struct msm_camera_i2c_conf_array s5k6a3yx_init_conf[] = { + {&s5k6a3yx_recommend_settings[0], + ARRAY_SIZE(s5k6a3yx_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA} +}; + +static struct msm_camera_i2c_conf_array s5k6a3yx_confs[] = { + {&s5k6a3yx_mode0_settings[0], + ARRAY_SIZE(s5k6a3yx_mode0_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}, + {&s5k6a3yx_mode1_settings[0], + ARRAY_SIZE(s5k6a3yx_mode1_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}, +}; + +static struct msm_sensor_output_info_t s5k6a3yx_dimensions[] = { + /* mode 0 */ + { + .x_output = 0x0584, /* 1412 */ + .y_output = 0x0584, /* 1412 */ + .line_length_pclk = 0x0642, /* 1602 */ + .frame_length_lines = 0x05AA, /* 1450*/ + .vt_pixel_clk = 72000000, /*76800000*/ + .op_pixel_clk = 72000000, /*76800000*/ + .binning_factor = 1, + }, + /* mode 1 */ + { + .x_output = 0x0580, /* 1408 */ + .y_output = 0x0584, /* 1412 */ + .line_length_pclk = 0x0642, /* 1602 */ + .frame_length_lines = 0x05AA, /* 1450*/ + .vt_pixel_clk = 72000000, /*76800000*/ + .op_pixel_clk = 72000000, /*76800000*/ + .binning_factor = 1, + }, +}; + +static struct msm_camera_csid_vc_cfg s5k6a3yx_cid_cfg[] = { + {0, CSI_RAW10, CSI_DECODE_10BIT}, +}; + +static struct msm_camera_csi2_params s5k6a3yx_csi_params = { + .csid_params = { + .lane_assign = 0xe4, + .lane_cnt = 1, + .lut_params = { + .num_cid = ARRAY_SIZE(s5k6a3yx_cid_cfg), + .vc_cfg = s5k6a3yx_cid_cfg, + }, + }, + .csiphy_params = { + .lane_cnt = 1, + .settle_cnt = 0x20, /* MIPI CLK 720Mbps */ + }, +}; + +static struct msm_camera_csi2_params *s5k6a3yx_csi_params_array[] = { + &s5k6a3yx_csi_params, + &s5k6a3yx_csi_params, +}; + +static struct msm_sensor_output_reg_addr_t s5k6a3yx_reg_addr = { + .x_output = 0x34C, + .y_output = 0x34E, + .line_length_pclk = 0x342, + .frame_length_lines = 0x340, +}; + +static struct msm_sensor_id_info_t s5k6a3yx_id_info = { + .sensor_id_reg_addr = 0x0, + .sensor_id = 0x0000, +}; + +static struct msm_sensor_exp_gain_info_t s5k6a3yx_exp_gain_info = { + .coarse_int_time_addr = 0x202, + .global_gain_addr = 0x204, + .vert_offset = 8, +}; + +#if !defined(CONFIG_S5C73M3) +void sensor_native_control(void __user *arg) +{ + printk(KERN_DEBUG "%s Entered\n", __func__); +} +#endif + +static int s5k6a3yx_sensor_config(void __user *argp) +{ + return msm_sensor_config(&s5k6a3yx_s_ctrl, argp); +} + +static int s5k6a3yx_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + return msm_sensor_open_init(&s5k6a3yx_s_ctrl, data); +} + +static int s5k6a3yx_sensor_release(void) +{ + return msm_sensor_release(&s5k6a3yx_s_ctrl); +} + +static const struct i2c_device_id s5k6a3yx_i2c_id[] = { + {SENSOR_NAME, (kernel_ulong_t)&s5k6a3yx_s_ctrl}, + { } +}; + +static struct i2c_driver s5k6a3yx_i2c_driver = { + .id_table = s5k6a3yx_i2c_id, + .probe = msm_sensor_i2c_probe, + .driver = { + .name = SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client s5k6a3yx_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static int s5k6a3yx_sensor_v4l2_probe(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + printk(KERN_DEBUG "#######s5k6a3yx_sensor_v4l2_probe #########\n"); + return msm_sensor_v4l2_probe(&s5k6a3yx_s_ctrl, info, sdev, s); +} + +static int s5k6a3yx_probe(struct platform_device *pdev) +{ + printk(KERN_DEBUG "############# s5k6a3yx_probe ##############\n"); + return msm_sensor_register(pdev, s5k6a3yx_sensor_v4l2_probe); +} + +struct platform_driver s5k6a3yx_driver = { + .probe = s5k6a3yx_probe, + .driver = { + .name = PLATFORM_DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_sensor_init_module(void) +{ + return platform_driver_register(&s5k6a3yx_driver); +} + +static struct v4l2_subdev_core_ops s5k6a3yx_subdev_core_ops; +static struct v4l2_subdev_video_ops s5k6a3yx_subdev_video_ops = { + .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt, +}; + +static struct v4l2_subdev_ops s5k6a3yx_subdev_ops = { + .core = &s5k6a3yx_subdev_core_ops, + .video = &s5k6a3yx_subdev_video_ops, +}; + +static void s5k6a3yx_write_exp_params( + struct msm_sensor_ctrl_t *s_ctrl, + uint32_t gain, + uint32_t fl_lines, + uint32_t line) +{ + +uint8_t msb_fl_lines, lsb_fl_lines; +uint8_t msb_line, lsb_line; +uint8_t msb_gain, lsb_gain; + + CDBG("%s gain %d fl %d line %d\n", + __func__, + gain, + fl_lines, + line); + s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl); + + + msb_fl_lines = (uint8_t)((fl_lines >> 8) & 0xFF); + lsb_fl_lines = (uint8_t)(fl_lines & 0xFF); + + msb_line = (uint8_t)((line >> 8) & 0xFF); + lsb_line = (uint8_t)(line & 0xFF); + + msb_gain = (uint8_t)((gain >> 8) & 0xFF); + lsb_gain = (uint8_t)(gain & 0xFF); + + CDBG("%s : %d %d %d %d %d %d\n", + __func__, msb_fl_lines, lsb_fl_lines, msb_line + , lsb_line, msb_gain, lsb_gain); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines, + msb_fl_lines, MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines+1, + lsb_fl_lines, MSM_CAMERA_I2C_BYTE_DATA); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, msb_line, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr+1, lsb_line, + MSM_CAMERA_I2C_BYTE_DATA); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr, msb_gain, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr+1, lsb_gain, + MSM_CAMERA_I2C_BYTE_DATA); + + s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl); +} +#if 0 +static void s5k6a3yx_write_fl_lines( + struct msm_sensor_ctrl_t *s_ctrl, + uint32_t gain, + uint32_t fl_lines, + uint32_t line) +{ + uint8_t msb_fl_lines, lsb_fl_lines; + uint8_t msb_line, lsb_line; + + CDBG("%s gain %d fl %d line %d", + __func__, + gain, + fl_lines, + line); + s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl); + + + msb_fl_lines = (uint8_t)((fl_lines >> 8) & 0xFF); + lsb_fl_lines = (uint8_t)(fl_lines & 0xFF); + + msb_line = (uint8_t)((line >> 8) & 0xFF); + lsb_line = (uint8_t)(line & 0xFF); + + CDBG("%s : %d %d %d %d", + __func__, msb_fl_lines, lsb_fl_lines, msb_line, lsb_line); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines, + msb_fl_lines, MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_output_reg_addr->frame_length_lines + 1, + lsb_fl_lines, MSM_CAMERA_I2C_BYTE_DATA); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, msb_line, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->coarse_int_time_addr+1, lsb_line, + MSM_CAMERA_I2C_BYTE_DATA); + + + s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl); +} +static void s5k6a3yx_write_gain( + struct msm_sensor_ctrl_t *s_ctrl, + uint32_t gain, + uint32_t fl_lines, + uint32_t line) +{ + uint8_t msb_gain, lsb_gain; + + CDBG("%s gain %d fl %d line %d\n", + __func__, + gain, + fl_lines, + line); + s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl); + + msb_gain = (uint8_t)((gain >> 8) & 0xFF); + lsb_gain = (uint8_t)(gain & 0xFF); + + CDBG("%s : %d %d", + __func__, msb_gain, lsb_gain); + + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr, msb_gain, + MSM_CAMERA_I2C_BYTE_DATA); + msm_camera_i2c_write(s_ctrl->sensor_i2c_client, + s_ctrl->sensor_exp_gain_info->global_gain_addr+1, lsb_gain, + MSM_CAMERA_I2C_BYTE_DATA); + + s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl); +} + +#endif +static int32_t s5k6a3yx_write_exp_gain( + struct msm_sensor_ctrl_t *s_ctrl, + uint16_t gain, + uint32_t line) +{ + int rc = 0; + uint32_t fl_lines = 0; + uint8_t offset; + static uint32_t old_gain; + static uint32_t old_line; + static uint32_t old_fl_lines; + + CDBG("%s E gain %d line %d\n", __func__, gain, line); + CDBG("%s E old_gain %d old_fl %d old_line %d\n", + __func__, + old_gain, + old_fl_lines, + old_line); + + if ((gain == old_gain) && (line == old_line)) { + CDBG("%s XXX\n", __func__); + return rc; + } + + fl_lines = s_ctrl->curr_frame_length_lines; + fl_lines = (fl_lines * s_ctrl->fps_divider) / Q10; + offset = s_ctrl->sensor_exp_gain_info->vert_offset; + + if (line > (fl_lines - offset)) + fl_lines = line + offset; + + s5k6a3yx_write_exp_params(s_ctrl, gain, fl_lines, line); + + old_gain = gain; + old_line = line; + old_fl_lines = fl_lines; + + CDBG("%s X old_gain %d old_line %d\n", __func__, old_gain, old_line); + + return rc; +} + + +static int32_t s5k6a3yx_write_snapshot_exp_gain( + struct msm_sensor_ctrl_t *s_ctrl, + uint16_t gain, + uint32_t line) +{ + int rc = 0; + uint32_t fl_lines = 0; + uint8_t offset; + + CDBG("%s E gain %d line %d\n", __func__, gain, line); + + fl_lines = s_ctrl->curr_frame_length_lines; + fl_lines = (fl_lines * s_ctrl->fps_divider) / Q10; + offset = s_ctrl->sensor_exp_gain_info->vert_offset; + + if (line > (fl_lines - offset)) + fl_lines = line + offset; + + s5k6a3yx_write_exp_params(s_ctrl, gain, fl_lines, line); + + return rc; +} + +static struct msm_sensor_fn_t s5k6a3yx_func_tbl = { + .sensor_start_stream = msm_sensor_start_stream, + .sensor_stop_stream = msm_sensor_stop_stream, + .sensor_group_hold_on = msm_sensor_group_hold_on, + .sensor_group_hold_off = msm_sensor_group_hold_off, + .sensor_set_fps = msm_sensor_set_fps, + + .sensor_write_exp_gain = s5k6a3yx_write_exp_gain, + .sensor_write_snapshot_exp_gain = s5k6a3yx_write_snapshot_exp_gain, + + .sensor_setting = msm_sensor_setting, + .sensor_set_sensor_mode = msm_sensor_set_sensor_mode, + .sensor_mode_init = msm_sensor_mode_init, + .sensor_get_output_info = msm_sensor_get_output_info, + .sensor_config = s5k6a3yx_sensor_config, + .sensor_open_init = s5k6a3yx_sensor_open_init, + .sensor_release = s5k6a3yx_sensor_release, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_probe = msm_sensor_probe, +}; + +static struct msm_sensor_reg_t s5k6a3yx_regs = { + .default_data_type = MSM_CAMERA_I2C_BYTE_DATA, + .start_stream_conf = s5k6a3yx_start_settings, + .start_stream_conf_size = ARRAY_SIZE(s5k6a3yx_start_settings), + .stop_stream_conf = s5k6a3yx_stop_settings, + .stop_stream_conf_size = ARRAY_SIZE(s5k6a3yx_stop_settings), + .group_hold_on_conf = s5k6a3yx_groupon_settings, + .group_hold_on_conf_size = ARRAY_SIZE(s5k6a3yx_groupon_settings), + .group_hold_off_conf = s5k6a3yx_groupoff_settings, + .group_hold_off_conf_size = + ARRAY_SIZE(s5k6a3yx_groupoff_settings), + .init_settings = &s5k6a3yx_init_conf[0], + .init_size = ARRAY_SIZE(s5k6a3yx_init_conf), + .mode_settings = &s5k6a3yx_confs[0], + .output_settings = &s5k6a3yx_dimensions[0], + .num_conf = ARRAY_SIZE(s5k6a3yx_confs), +}; + +static struct msm_sensor_ctrl_t s5k6a3yx_s_ctrl = { + .msm_sensor_reg = &s5k6a3yx_regs, + .sensor_i2c_client = &s5k6a3yx_sensor_i2c_client, + .sensor_i2c_addr = 0x20, + .sensor_output_reg_addr = &s5k6a3yx_reg_addr, + .sensor_id_info = &s5k6a3yx_id_info, + .sensor_exp_gain_info = &s5k6a3yx_exp_gain_info, + .cam_mode = MSM_SENSOR_MODE_INVALID, + .csi_params = &s5k6a3yx_csi_params_array[0], + .msm_sensor_mutex = &s5k6a3yx_mut, + .sensor_i2c_driver = &s5k6a3yx_i2c_driver, + .sensor_v4l2_subdev_info = s5k6a3yx_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k6a3yx_subdev_info), + .sensor_v4l2_subdev_ops = &s5k6a3yx_subdev_ops, + .func_tbl = &s5k6a3yx_func_tbl, +}; + +module_init(msm_sensor_init_module); +MODULE_DESCRIPTION("Samsung 2 MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/sn12m0pz.c b/drivers/media/video/msm_zsl/sn12m0pz.c new file mode 100644 index 00000000000..affa581c559 --- /dev/null +++ b/drivers/media/video/msm_zsl/sn12m0pz.c @@ -0,0 +1,1850 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sn12m0pz.h" + + +#define Q8 0x00000100 +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD_OFF 0x00 +#define GROUPED_PARAMETER_HOLD 0x01 +#define REG_MODE_SELECT 0x0100 +#define MODE_SELECT_STANDBY_MODE 0x00 +#define MODE_SELECT_STREAM 0x01 + +/* Integration Time */ +#define REG_COARSE_INTEGRATION_TIME_MSB 0x0202 +#define REG_COARSE_INTEGRATION_TIME_LSB 0x0203 + +/* Gain */ +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204 +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205 + +/* PLL Register Defines */ +#define REG_PLL_MULTIPLIER 0x0307 +#define REG_0x302B 0x302B + +/* MIPI Enable Settings */ +#define REG_0x30E5 0x30E5 +#define REG_0x3300 0x3300 + +/* Global Setting */ +#define REG_IMAGE_ORIENTATION 0x0101 + +#define REG_0x300A 0x300A +#define REG_0x3014 0x3014 +#define REG_0x3015 0x3015 +#define REG_0x3017 0x3017 +#define REG_0x301C 0x301C +#define REG_0x3031 0x3031 +#define REG_0x3040 0x3040 +#define REG_0x3041 0x3041 +#define REG_0x3051 0x3051 +#define REG_0x3053 0x3053 +#define REG_0x3055 0x3055 +#define REG_0x3057 0x3057 +#define REG_0x3060 0x3060 +#define REG_0x3065 0x3065 +#define REG_0x30AA 0x30AA +#define REG_0x30AB 0x30AB +#define REG_0x30B0 0x30B0 +#define REG_0x30B2 0x30B2 +#define REG_0x30D3 0x30D3 + +#define REG_0x3106 0x3106 +#define REG_0x3108 0x3108 +#define REG_0x310A 0x310A +#define REG_0x310C 0x310C +#define REG_0x310E 0x310E +#define REG_0x3126 0x3126 +#define REG_0x312E 0x312E +#define REG_0x313C 0x313C +#define REG_0x313E 0x313E +#define REG_0x3140 0x3140 +#define REG_0x3142 0x3142 +#define REG_0x3144 0x3144 +#define REG_0x3148 0x3148 +#define REG_0x314A 0x314A +#define REG_0x3166 0x3166 +#define REG_0x3168 0x3168 +#define REG_0x316F 0x316F +#define REG_0x3171 0x3171 +#define REG_0x3173 0x3173 +#define REG_0x3175 0x3175 +#define REG_0x3177 0x3177 +#define REG_0x3179 0x3179 +#define REG_0x317B 0x317B +#define REG_0x317D 0x317D +#define REG_0x317F 0x317F +#define REG_0x3181 0x3181 +#define REG_0x3184 0x3184 +#define REG_0x3185 0x3185 +#define REG_0x3187 0x3187 + +#define REG_0x31A4 0x31A4 +#define REG_0x31A6 0x31A6 +#define REG_0x31AC 0x31AC +#define REG_0x31AE 0x31AE +#define REG_0x31B4 0x31B4 +#define REG_0x31B6 0x31B6 + +#define REG_0x3254 0x3254 +#define REG_0x3256 0x3256 +#define REG_0x3258 0x3258 +#define REG_0x325A 0x325A +#define REG_0x3260 0x3260 +#define REG_0x3262 0x3262 + + +#define REG_0x3304 0x3304 +#define REG_0x3305 0x3305 +#define REG_0x3306 0x3306 +#define REG_0x3307 0x3307 +#define REG_0x3308 0x3308 +#define REG_0x3309 0x3309 +#define REG_0x330A 0x330A +#define REG_0x330B 0x330B +#define REG_0x330C 0x330C +#define REG_0x330D 0x330D + +/* Mode Setting */ +#define REG_FRAME_LENGTH_LINES_MSB 0x0340 +#define REG_FRAME_LENGTH_LINES_LSB 0x0341 +#define REG_LINE_LENGTH_PCK_MSB 0x0342 +#define REG_LINE_LENGTH_PCK_LSB 0x0343 +#define REG_X_OUTPUT_SIZE_MSB 0x034C +#define REG_X_OUTPUT_SIZE_LSB 0x034D +#define REG_Y_OUTPUT_SIZE_MSB 0x034E +#define REG_Y_OUTPUT_SIZE_LSB 0x034F +#define REG_X_EVEN_INC_LSB 0x0381 +#define REG_X_ODD_INC_LSB 0x0383 +#define REG_Y_EVEN_INC_LSB 0x0385 +#define REG_Y_ODD_INC_LSB 0x0387 +#define REG_0x3016 0x3016 +#define REG_0x30E8 0x30E8 +#define REG_0x3301 0x3301 +/* for 120fps support */ +#define REG_0x0344 0x0344 +#define REG_0x0345 0x0345 +#define REG_0x0346 0x0346 +#define REG_0x0347 0x0347 +#define REG_0x0348 0x0348 +#define REG_0x0349 0x0349 +#define REG_0x034A 0x034A +#define REG_0x034B 0x034B + +/* Test Pattern */ +#define REG_0x30D8 0x30D8 +#define REG_TEST_PATTERN_MODE 0x0601 + +/* Solid Color Test Pattern */ +#define REG_TEST_DATA_RED_MSB 0x0603 +#define REG_TEST_DATA_RED_LSB 0x0603 +#define REG_TEST_DATA_GREENR_MSB 0x0604 +#define REG_TEST_DATA_GREENR_LSB 0x0605 +#define REG_TEST_DATA_BLUE_MSB 0x0606 +#define REG_TEST_DATA_BLUE_LSB 0x0607 +#define REG_TEST_DATA_GREENB_MSB 0x0608 +#define REG_TEST_DATA_GREENB_LSB 0x0609 +#define SN12M0PZ_AF_I2C_SLAVE_ID 0xE4 +#define SN12M0PZ_STEPS_NEAR_TO_CLOSEST_INF 42 +#define SN12M0PZ_TOTAL_STEPS_NEAR_TO_FAR 42 + + +/* TYPE DECLARATIONS */ + + +enum mipi_config_type { + IU060F_SN12M0PZ_STMIPID01, + IU060F_SN12M0PZ_STMIPID02 +}; + +enum sn12m0pz_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum sn12m0pz_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE, + QVGA_SIZE, +}; + +enum sn12m0pz_setting { + RES_PREVIEW, + RES_CAPTURE, + RES_VIDEO_120FPS, +}; + +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +/* 816x612, 24MHz MCLK 96MHz PCLK */ +#define IU060F_SN12M0PZ_OFFSET 3 +/* Time in milisecs for waiting for the sensor to reset.*/ +#define SN12M0PZ_RESET_DELAY_MSECS 66 +#define SN12M0PZ_WIDTH 4032 +#define SN12M0PZ_HEIGHT 3024 +#define SN12M0PZ_FULL_SIZE_WIDTH 4032 +#define SN12M0PZ_FULL_SIZE_HEIGHT 3024 +#define SN12M0PZ_HRZ_FULL_BLK_PIXELS 176 +#define SN12M0PZ_VER_FULL_BLK_LINES 50 +#define SN12M0PZ_QTR_SIZE_WIDTH 2016 +#define SN12M0PZ_QTR_SIZE_HEIGHT 1512 +#define SN12M0PZ_HRZ_QTR_BLK_PIXELS 2192 +#define SN12M0PZ_VER_QTR_BLK_LINES 26 + +/* 120fps mode */ +#define SN12M0PZ_QVGA_SIZE_WIDTH 4032 +#define SN12M0PZ_QVGA_SIZE_HEIGHT 249 +#define SN12M0PZ_HRZ_QVGA_BLK_PIXELS 176 +#define SN12M0PZ_VER_QVGA_BLK_LINES 9 +#define SN12M0PZ_DEFAULT_CLOCK_RATE 24000000 + +static uint32_t IU060F_SN12M0PZ_DELAY_MSECS = 30; +static enum mipi_config_type mipi_config = IU060F_SN12M0PZ_STMIPID02; +/* AF Tuning Parameters */ +static int16_t enable_single_D02_lane; +static int16_t fullsize_cropped_at_8mp; + +struct sn12m0pz_work_t { + struct work_struct work; +}; + +static struct sn12m0pz_work_t *sn12m0pz_sensorw; +static struct i2c_client *sn12m0pz_client; + +struct sn12m0pz_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + uint32_t sensormode; + uint32_t fps_divider;/* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */ + uint16_t fps; + int16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + enum sn12m0pz_resolution_t prev_res; + enum sn12m0pz_resolution_t pict_res; + enum sn12m0pz_resolution_t curr_res; + enum sn12m0pz_test_mode_t set_test; + unsigned short imgaddr; +}; + +static struct sn12m0pz_ctrl_t *sn12m0pz_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(sn12m0pz_wait_queue); +DEFINE_MUTEX(sn12m0pz_mut); + + +static int sn12m0pz_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 2, + .buf = rxdata, + }, + }; + + if (i2c_transfer(sn12m0pz_client->adapter, msgs, 2) < 0) { + CDBG("sn12m0pz_i2c_rxdata failed!"); + return -EIO; + } + + return 0; +} +static int32_t sn12m0pz_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + if (i2c_transfer(sn12m0pz_client->adapter, msg, 1) < 0) { + CDBG("sn12m0pz_i2c_txdata faild 0x%x", sn12m0pz_client->addr); + return -EIO; + } + + return 0; +} + +static int32_t sn12m0pz_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc; + unsigned char buf[2]; + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + + rc = sn12m0pz_i2c_rxdata(sn12m0pz_client->addr, buf, rlen); + + if (rc < 0) { + CDBG("sn12m0pz_i2c_read 0x%x failed!", raddr); + return rc; + } + + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + + return rc; +} + +static int32_t sn12m0pz_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata) +{ + int32_t rc; + unsigned char buf[3]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + udelay(90); + CDBG("i2c_write_b addr = %x, val = %x\n", waddr, bdata); + rc = sn12m0pz_i2c_txdata(sn12m0pz_client->addr, buf, 3); + + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!", + waddr, bdata); + } + + return rc; +} + +static int16_t sn12m0pz_i2c_write_b_af(unsigned short saddr, + unsigned short baddr, unsigned short bdata) +{ + int16_t rc; + unsigned char buf[2]; + + memset(buf, 0, sizeof(buf)); + buf[0] = baddr; + buf[1] = bdata; + rc = sn12m0pz_i2c_txdata(saddr, buf, 2); + + if (rc < 0) + CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!", + saddr, baddr, bdata); + + return rc; +} + +static int32_t sn12m0pz_i2c_write_byte_bridge(unsigned short saddr, + unsigned short waddr, uint8_t bdata) +{ + int32_t rc; + unsigned char buf[3]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + + CDBG("i2c_write_b addr = %x, val = %x", waddr, bdata); + rc = sn12m0pz_i2c_txdata(saddr, buf, 3); + + if (rc < 0) + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!", + waddr, bdata); + + return rc; +} + +static int32_t sn12m0pz_stmipid01_config(void) +{ + int32_t rc = 0; + /* Initiate I2C for D01: */ + /* MIPI Bridge configuration */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0002, 0x19) < 0) + return rc; /* enable clock lane*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0003, 0x00) < 0) + return rc; + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0004, 0x3E) < 0) + return rc; /* mipi mode clock*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0005, 0x01) < 0) + return rc; /* enable data line*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0006, 0x0F) < 0) + return rc; /* mipi mode data 0x01*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0009, 0x00) < 0) + return rc; /* Data_Lane1_Reg1*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000D, 0x92) < 0) + return rc; /* CCPRxRegisters*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000E, 0x28) < 0) + return rc; /* 10 bits for pixel width input for CCP rx.*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0014, 0xC0) < 0) + return rc; /* no bypass, no decomp, 1Lane System,CSIstreaming*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0015, 0x48) < 0) + return rc; /* ModeControlRegisters-- Don't reset error flag*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0017, 0x2B) < 0) + return rc; /* Data_ID_Rreg*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0018, 0x2B) < 0) + return rc; /* Data_ID_Rreg_emb*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0019, 0x0C) < 0) + return rc; + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001E, 0x0A) < 0) + return rc; + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001F, 0x0A) < 0) + return rc; + + return rc; +} +static int32_t sn12m0pz_stmipid02_config(void) +{ + int32_t rc = 0; + + /* Main Camera Clock Lane 1 (CLHP1, CLKN1)*/ + /* Enable Clock Lane 1 (CLHP1, CLKN1), 0x15 for 400MHz */ + if (enable_single_D02_lane) { + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0002, 0x19) < 0) + return rc; + /* Main Camera Data Lane 1.1 (DATA2P1, DATA2N1) */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0009, 0x00) < 0) + return rc;/* Enable Data Lane 1.2 (DATA2P1, DATA2N1) */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000A, 0x00) < 0) + return rc; /*CSIMode on Data Lane1.2(DATA2P1,DATA2N1)*/ + /* Mode Control */ + /* Enable single lane for qtr preview */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0014, 0xC0) < 0) + return rc; /*set 0xC0 - left justified on upper bits)*/ + /* bit 1 set to 0 i.e. 1 lane system for qtr size preview */ + } else { + if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) { + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, + 0x0002, 0x19) < 0) + return rc; + } else { + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, + 0x0002, 0x21) < 0) + return rc; + } + /* Main Camera Data Lane 1.1 (DATA2P1, DATA2N1) */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0009, 0x01) < 0) + return rc; /* Enable Data Lane 1.2 (DATA2P1, DATA2N1) */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000A, 0x01) < 0) + return rc; /* CSI Mode Data Lane1.2(DATA2P1, DATA2N1)*/ + + /* Mode Control */ + /* Enable two lanes for full size preview/ snapshot */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0014, 0xC2) < 0) + return rc; /* No decompression, CSI dual lane */ + } + + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0004, 0x1E) < 0) + return rc; + + /* Main Camera Data Lane 1.1 (DATA1P1, DATA1N1) */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0005, 0x03) < 0) + return rc; /* Enable Data Lane 1.1 (DATA1P1, DATA1N1) */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0006, 0x0f) < 0) + return rc; /* CSI Mode on Data Lane 1.1 (DATA1P1, DATA1N1) */ + + /* Tristated Output, continuous clock, */ + /*polarity of clock is inverted and sync signals not inverted*/ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0015, 0x08) < 0) + return rc; + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0036, 0x20) < 0) + return rc; /* Enable compensation macro, main camera */ + + /* Data type: 0x2B Raw 10 */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0017, 0x2B) < 0) + return rc; + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0018, 0x2B) < 0) + return rc; /* Data type of embedded data: 0x2B Raw 10 */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0019, 0x0C) < 0) + return rc; /* Data type and pixel width programmed 0x0C*/ + + /* Decompression Mode */ + + /* Pixel Width and Decompression ON/OFF */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001E, 0x0A) < 0) + return rc; /* Image data not compressed: 0x0A for 10 bits */ + if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001F, 0x0A) < 0) + return rc; /* Embedded data not compressed: 0x0A for 10 bits */ + return rc; +} + +static int16_t sn12m0pz_af_init(void) +{ + int16_t rc; + /* Initialize waveform */ + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x01, 0xA9); + + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x02, 0xD2); + + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x03, 0x0C); + + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x04, 0x14); + + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x05, 0xB6); + + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x06, 0x4F); + + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x07, 0x00); + + return rc; +} + +static int32_t sn12m0pz_move_focus(int direction, + int32_t num_steps) +{ + int8_t step_direction, dest_step_position, bit_mask; + int32_t rc = 0; + uint16_t sn12m0pz_l_region_code_per_step = 3; + + if (num_steps == 0) + return rc; + + if (direction == MOVE_NEAR) { + step_direction = 1; + bit_mask = 0x80; + } else if (direction == MOVE_FAR) { + step_direction = -1; + bit_mask = 0x00; + } else { + CDBG("sn12m0pz_move_focus: Illegal focus direction"); + return -EINVAL; + } + + dest_step_position = sn12m0pz_ctrl->curr_step_pos + + (step_direction * num_steps); + + if (dest_step_position < 0) + dest_step_position = 0; + else if (dest_step_position > SN12M0PZ_TOTAL_STEPS_NEAR_TO_FAR) + dest_step_position = SN12M0PZ_TOTAL_STEPS_NEAR_TO_FAR; + + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x00, + ((num_steps * sn12m0pz_l_region_code_per_step) | bit_mask)); + + sn12m0pz_ctrl->curr_step_pos = dest_step_position; + + return rc; +} +static int32_t sn12m0pz_set_default_focus(uint8_t af_step) +{ + int32_t rc; + + /* Initialize to infinity */ + + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x00, 0x7F); + + rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x00, 0x7F); + + sn12m0pz_ctrl->curr_step_pos = 0; + + return rc; +} +static void sn12m0pz_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint16_t preview_frame_length_lines, snapshot_frame_length_lines; + uint16_t preview_line_length_pck, snapshot_line_length_pck; + uint32_t divider, pclk_mult, d1, d2; + + /* Total frame_length_lines and line_length_pck for preview */ + CDBG("sn12m0pz_get_pict_fps prev_res %d", sn12m0pz_ctrl->prev_res); + if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) { + preview_frame_length_lines = SN12M0PZ_QVGA_SIZE_HEIGHT + + SN12M0PZ_VER_QVGA_BLK_LINES; + preview_line_length_pck = SN12M0PZ_QVGA_SIZE_WIDTH + + SN12M0PZ_HRZ_QVGA_BLK_PIXELS; + } else { + preview_frame_length_lines = SN12M0PZ_QTR_SIZE_HEIGHT + + SN12M0PZ_VER_QTR_BLK_LINES; + preview_line_length_pck = SN12M0PZ_QTR_SIZE_WIDTH + + SN12M0PZ_HRZ_QTR_BLK_PIXELS; + } + /* Total frame_length_lines and line_length_pck for snapshot */ + snapshot_frame_length_lines = SN12M0PZ_FULL_SIZE_HEIGHT + + SN12M0PZ_HRZ_FULL_BLK_PIXELS; + snapshot_line_length_pck = SN12M0PZ_FULL_SIZE_WIDTH + + SN12M0PZ_HRZ_FULL_BLK_PIXELS; + d1 = preview_frame_length_lines * + 0x00000400 / snapshot_frame_length_lines; + d2 = preview_line_length_pck * + 0x00000400/snapshot_line_length_pck; + divider = d1 * d2 / 0x400; + pclk_mult = + (uint32_t) + (sn12m0pz_regs.reg_pat[RES_CAPTURE].pll_multiplier_lsb * + 0x400) / (uint32_t) + sn12m0pz_regs.reg_pat[RES_PREVIEW].pll_multiplier_lsb; + *pfps = (uint16_t) (((fps * divider) / 0x400 * pclk_mult) / 0x400); +} + +static uint16_t sn12m0pz_get_prev_lines_pf(void) +{ + if (sn12m0pz_ctrl->prev_res == QTR_SIZE) + return SN12M0PZ_QTR_SIZE_HEIGHT + + SN12M0PZ_VER_QTR_BLK_LINES; + else if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) + return SN12M0PZ_QVGA_SIZE_HEIGHT + + SN12M0PZ_VER_QVGA_BLK_LINES; + + else + return SN12M0PZ_FULL_SIZE_HEIGHT + + SN12M0PZ_VER_FULL_BLK_LINES; +} + +static uint16_t sn12m0pz_get_prev_pixels_pl(void) +{ + if (sn12m0pz_ctrl->prev_res == QTR_SIZE) + return SN12M0PZ_QTR_SIZE_WIDTH + + SN12M0PZ_HRZ_QTR_BLK_PIXELS; + else + return SN12M0PZ_FULL_SIZE_WIDTH + + SN12M0PZ_HRZ_FULL_BLK_PIXELS; +} + +static uint16_t sn12m0pz_get_pict_lines_pf(void) +{ + if (sn12m0pz_ctrl->pict_res == QTR_SIZE) + return SN12M0PZ_QTR_SIZE_HEIGHT + + SN12M0PZ_VER_QTR_BLK_LINES; + else + return SN12M0PZ_FULL_SIZE_HEIGHT + + SN12M0PZ_VER_FULL_BLK_LINES; +} + +static uint16_t sn12m0pz_get_pict_pixels_pl(void) +{ + if (sn12m0pz_ctrl->pict_res == QTR_SIZE) + return SN12M0PZ_QTR_SIZE_WIDTH + + SN12M0PZ_HRZ_QTR_BLK_PIXELS; + else + return SN12M0PZ_FULL_SIZE_WIDTH + + SN12M0PZ_HRZ_FULL_BLK_PIXELS; +} + +static uint32_t sn12m0pz_get_pict_max_exp_lc(void) +{ + if (sn12m0pz_ctrl->pict_res == QTR_SIZE) + return (SN12M0PZ_QTR_SIZE_HEIGHT + + SN12M0PZ_VER_QTR_BLK_LINES) * 24; + else + return (SN12M0PZ_FULL_SIZE_HEIGHT + + SN12M0PZ_VER_FULL_BLK_LINES) * 24; +} + +static int32_t sn12m0pz_set_fps(struct fps_cfg *fps) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + + total_lines_per_frame = (uint16_t)((SN12M0PZ_QTR_SIZE_HEIGHT + + SN12M0PZ_VER_QTR_BLK_LINES) * + sn12m0pz_ctrl->fps_divider / 0x400); + + if (sn12m0pz_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_MSB, + ((total_lines_per_frame & 0xFF00) >> 8)) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LSB, + (total_lines_per_frame & 0x00FF)) < 0) + return rc; + + return rc; +} + +static int32_t sn12m0pz_write_exp_gain(uint16_t gain, uint32_t line) +{ + static uint16_t max_legal_gain = 0x00E0; + uint8_t gain_msb, gain_lsb; + uint8_t intg_time_msb, intg_time_lsb; + uint8_t line_length_pck_msb, line_length_pck_lsb; + uint16_t line_length_pck, frame_length_lines, temp_lines; + uint32_t line_length_ratio = 1 * Q8; + int32_t rc = 0; + CDBG("sn12m0pz_write_exp_gain : gain = %d line = %d", gain, line); + + if (sn12m0pz_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) { + if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) { + frame_length_lines = SN12M0PZ_QVGA_SIZE_HEIGHT + + SN12M0PZ_VER_QVGA_BLK_LINES; + line_length_pck = SN12M0PZ_QVGA_SIZE_WIDTH + + SN12M0PZ_HRZ_QVGA_BLK_PIXELS; + if (line > (frame_length_lines - + IU060F_SN12M0PZ_OFFSET)) + line = frame_length_lines - + IU060F_SN12M0PZ_OFFSET; + sn12m0pz_ctrl->fps = (uint16_t) (120 * Q8); + } else { + if (sn12m0pz_ctrl->curr_res == QTR_SIZE) { + frame_length_lines = SN12M0PZ_QTR_SIZE_HEIGHT + + SN12M0PZ_VER_QTR_BLK_LINES; + line_length_pck = SN12M0PZ_QTR_SIZE_WIDTH + + SN12M0PZ_HRZ_QTR_BLK_PIXELS; + } else { + frame_length_lines = SN12M0PZ_HEIGHT + + SN12M0PZ_VER_FULL_BLK_LINES; + line_length_pck = SN12M0PZ_WIDTH + + SN12M0PZ_HRZ_FULL_BLK_PIXELS; + } + if (line > (frame_length_lines - + IU060F_SN12M0PZ_OFFSET)) + sn12m0pz_ctrl->fps = (uint16_t) (30 * Q8 * + (frame_length_lines - IU060F_SN12M0PZ_OFFSET) / line); + else + sn12m0pz_ctrl->fps = (uint16_t) (30 * Q8); + } + } else { + if (sn12m0pz_ctrl->curr_res == QTR_SIZE) { + frame_length_lines = SN12M0PZ_QTR_SIZE_HEIGHT + + SN12M0PZ_VER_QTR_BLK_LINES; + line_length_pck = SN12M0PZ_QTR_SIZE_WIDTH + + SN12M0PZ_HRZ_QTR_BLK_PIXELS; + } else { + frame_length_lines = SN12M0PZ_HEIGHT + + SN12M0PZ_VER_FULL_BLK_LINES; + line_length_pck = SN12M0PZ_WIDTH + + SN12M0PZ_HRZ_FULL_BLK_PIXELS; + } + } + if (gain > max_legal_gain) + /* range: 0 to 224 */ + gain = max_legal_gain; + temp_lines = line; + /* calculate line_length_ratio */ + if (line > (frame_length_lines - IU060F_SN12M0PZ_OFFSET)) { + line_length_ratio = (line * Q8) / (frame_length_lines - + IU060F_SN12M0PZ_OFFSET); + temp_lines = frame_length_lines - IU060F_SN12M0PZ_OFFSET; + if (line_length_ratio == 0) + line_length_ratio = 1 * Q8; + } else + line_length_ratio = 1 * Q8; + + line = (uint32_t) (line * sn12m0pz_ctrl->fps_divider/0x400); + + /* update gain registers */ + gain_msb = (uint8_t) ((gain & 0xFF00) >> 8); + gain_lsb = (uint8_t) (gain & 0x00FF); + + /* linear AFR horizontal stretch */ + line_length_pck = (uint16_t) (line_length_pck * line_length_ratio / Q8); + line_length_pck_msb = (uint8_t) ((line_length_pck & 0xFF00) >> 8); + line_length_pck_lsb = (uint8_t) (line_length_pck & 0x00FF); + + /* update line count registers */ + intg_time_msb = (uint8_t) ((temp_lines & 0xFF00) >> 8); + intg_time_lsb = (uint8_t) (temp_lines & 0x00FF); + + + if (sn12m0pz_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, + gain_msb) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, + gain_lsb) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_MSB, + line_length_pck_msb) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_LSB, + line_length_pck_lsb) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_MSB, + intg_time_msb) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LSB, + intg_time_lsb) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF) < 0) + return rc; + + return rc; +} + + +static int32_t sn12m0pz_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc; + rc = sn12m0pz_write_exp_gain(gain, line); + return rc; +} + +static int32_t sn12m0pz_test(enum sn12m0pz_test_mode_t mo) +{ + uint8_t test_data_val_msb = 0x07; + uint8_t test_data_val_lsb = 0xFF; + int32_t rc = 0; + if (mo == TEST_OFF) + return rc; + else { + /* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation, + 1: Bypass Signal Processing. REG_0x30D8[5] is EBDMASK: + 0: Output Embedded data, 1: No output embedded data */ + + if (sn12m0pz_i2c_write_b_sensor(REG_0x30D8, 0x10) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_TEST_PATTERN_MODE, + (uint8_t) mo) < 0) + return rc; + + /* Solid Color Test Pattern */ + + if (mo == TEST_1) { + if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_RED_MSB, + test_data_val_msb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_RED_LSB, + test_data_val_lsb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor( + REG_TEST_DATA_GREENR_MSB, + test_data_val_msb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor( + REG_TEST_DATA_GREENR_LSB, + test_data_val_lsb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_BLUE_MSB, + test_data_val_msb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_BLUE_LSB, + test_data_val_lsb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor( + REG_TEST_DATA_GREENB_MSB, + test_data_val_msb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor( + REG_TEST_DATA_GREENB_LSB, + test_data_val_lsb) < 0) + return rc; + } + + } + + return rc; +} + +static int32_t sn12m0pz_reset(void) +{ + int32_t rc = 0; + /* register 0x0002 is Port 2, CAM_XCLRO */ + gpio_direction_output(sn12m0pz_ctrl-> + sensordata->sensor_reset, + 0); + msleep(50); + gpio_direction_output(sn12m0pz_ctrl-> + sensordata->sensor_reset, + 1); + msleep(13); + return rc; +} + +static int32_t sn12m0pz_sensor_setting(int update_type, int rt) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + + switch (update_type) { + case UPDATE_PERIODIC: + /* Put Sensor into sofware standby mode */ + if (sn12m0pz_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + msleep(5); + /* Hardware reset D02, lane config between full size/qtr size*/ + rc = sn12m0pz_reset(); + if (rc < 0) + return rc; + + if (sn12m0pz_stmipid02_config() < 0) + return rc; + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE + || rt == RES_VIDEO_120FPS) { + /* reset fps_divider */ + sn12m0pz_ctrl->fps_divider = 1 * 0x400; + + /* PLL settings */ + if (sn12m0pz_i2c_write_b_sensor(REG_PLL_MULTIPLIER, + sn12m0pz_regs.reg_pat[rt].pll_multiplier_lsb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x302B, + sn12m0pz_regs.reg_pat_init[0].reg_0x302B) < 0) + return rc; + + /* MIPI Enable Settings */ + if (sn12m0pz_i2c_write_b_sensor(REG_0x30E5, + sn12m0pz_regs.reg_pat_init[0].reg_0x30E5) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_0x3300, + sn12m0pz_regs.reg_pat_init[0].reg_0x3300) < 0) + return rc; + + /* Global Setting */ + if ( + sn12m0pz_i2c_write_b_sensor( + REG_IMAGE_ORIENTATION, + sn12m0pz_regs.reg_pat_init[0].image_orient) < 0) + return rc; + if ( + sn12m0pz_i2c_write_b_sensor( + REG_COARSE_INTEGRATION_TIME_MSB, + sn12m0pz_regs.reg_pat[rt].coarse_integ_time_msb) + < 0) + return rc; + if ( + sn12m0pz_i2c_write_b_sensor( + REG_COARSE_INTEGRATION_TIME_LSB, + sn12m0pz_regs.reg_pat[rt].coarse_integ_time_lsb) + < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x300A, + sn12m0pz_regs.reg_pat_init[0].reg_0x300A) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3014, + sn12m0pz_regs.reg_pat_init[0].reg_0x3014) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3015, + sn12m0pz_regs.reg_pat_init[0].reg_0x3015) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3017, + sn12m0pz_regs.reg_pat_init[0].reg_0x3017) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x301C, + sn12m0pz_regs.reg_pat_init[0].reg_0x301C) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3031, + sn12m0pz_regs.reg_pat_init[0].reg_0x3031) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3040, + sn12m0pz_regs.reg_pat_init[0].reg_0x3040) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3041, + sn12m0pz_regs.reg_pat_init[0].reg_0x3041) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3051, + sn12m0pz_regs.reg_pat_init[0].reg_0x3051) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3053, + sn12m0pz_regs.reg_pat_init[0].reg_0x3053) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3055, + sn12m0pz_regs.reg_pat_init[0].reg_0x3055) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3057, + sn12m0pz_regs.reg_pat_init[0].reg_0x3057) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3060, + sn12m0pz_regs.reg_pat_init[0].reg_0x3060) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3065, + sn12m0pz_regs.reg_pat_init[0].reg_0x3065) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x30AA, + sn12m0pz_regs.reg_pat_init[0].reg_0x30AA) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x30AB, + sn12m0pz_regs.reg_pat_init[0].reg_0x30AB) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x30B0, + sn12m0pz_regs.reg_pat_init[0].reg_0x30B0) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x30B2, + sn12m0pz_regs.reg_pat_init[0].reg_0x30B2) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_0x30D3, + sn12m0pz_regs.reg_pat_init[0].reg_0x30D3) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x30D8, + sn12m0pz_regs.reg_pat_init[0].reg_0x30D8) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_0x3106, + sn12m0pz_regs.reg_pat_init[0].reg_0x3106) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3108, + sn12m0pz_regs.reg_pat_init[0].reg_0x3108) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x310A, + sn12m0pz_regs.reg_pat_init[0].reg_0x310A) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x310C, + sn12m0pz_regs.reg_pat_init[0].reg_0x310C) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x310E, + sn12m0pz_regs.reg_pat_init[0].reg_0x310E) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3126, + sn12m0pz_regs.reg_pat_init[0].reg_0x3126) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x312E, + sn12m0pz_regs.reg_pat_init[0].reg_0x312E) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x313C, + sn12m0pz_regs.reg_pat_init[0].reg_0x313C) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x313E, + sn12m0pz_regs.reg_pat_init[0].reg_0x313E) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3140, + sn12m0pz_regs.reg_pat_init[0].reg_0x3140) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3142, + sn12m0pz_regs.reg_pat_init[0].reg_0x3142) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3144, + sn12m0pz_regs.reg_pat_init[0].reg_0x3144) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3148, + sn12m0pz_regs.reg_pat_init[0].reg_0x3148) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x314A, + sn12m0pz_regs.reg_pat_init[0].reg_0x314A) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3166, + sn12m0pz_regs.reg_pat_init[0].reg_0x3166) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3168, + sn12m0pz_regs.reg_pat_init[0].reg_0x3168) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x316F, + sn12m0pz_regs.reg_pat_init[0].reg_0x316F) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3171, + sn12m0pz_regs.reg_pat_init[0].reg_0x3171) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3173, + sn12m0pz_regs.reg_pat_init[0].reg_0x3173) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3175, + sn12m0pz_regs.reg_pat_init[0].reg_0x3175) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3177, + sn12m0pz_regs.reg_pat_init[0].reg_0x3177) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3179, + sn12m0pz_regs.reg_pat_init[0].reg_0x3179) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x317B, + sn12m0pz_regs.reg_pat_init[0].reg_0x317B) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x317D, + sn12m0pz_regs.reg_pat_init[0].reg_0x317D) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x317F, + sn12m0pz_regs.reg_pat_init[0].reg_0x317F) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3181, + sn12m0pz_regs.reg_pat_init[0].reg_0x3181) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3184, + sn12m0pz_regs.reg_pat_init[0].reg_0x3184) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3185, + sn12m0pz_regs.reg_pat_init[0].reg_0x3185) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3187, + sn12m0pz_regs.reg_pat_init[0].reg_0x3187) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_0x31A4, + sn12m0pz_regs.reg_pat_init[0].reg_0x31A4) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x31A6, + sn12m0pz_regs.reg_pat_init[0].reg_0x31A6) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x31AC, + sn12m0pz_regs.reg_pat_init[0].reg_0x31AC) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x31AE, + sn12m0pz_regs.reg_pat_init[0].reg_0x31AE) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x31B4, + sn12m0pz_regs.reg_pat_init[0].reg_0x31B4) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x31B6, + sn12m0pz_regs.reg_pat_init[0].reg_0x31B6) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_0x3254, + sn12m0pz_regs.reg_pat_init[0].reg_0x3254) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3256, + sn12m0pz_regs.reg_pat_init[0].reg_0x3256) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3258, + sn12m0pz_regs.reg_pat_init[0].reg_0x3258) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x325A, + sn12m0pz_regs.reg_pat_init[0].reg_0x325A) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3260, + sn12m0pz_regs.reg_pat_init[0].reg_0x3260) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3262, + sn12m0pz_regs.reg_pat_init[0].reg_0x3262) < 0) + return rc; + + + if (sn12m0pz_i2c_write_b_sensor(REG_0x3304, + sn12m0pz_regs.reg_pat_init[0].reg_0x3304) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3305, + sn12m0pz_regs.reg_pat_init[0].reg_0x3305) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3306, + sn12m0pz_regs.reg_pat_init[0].reg_0x3306) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3307, + sn12m0pz_regs.reg_pat_init[0].reg_0x3307) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3308, + sn12m0pz_regs.reg_pat_init[0].reg_0x3308) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3309, + sn12m0pz_regs.reg_pat_init[0].reg_0x3309) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x330A, + sn12m0pz_regs.reg_pat_init[0].reg_0x330A) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x330B, + sn12m0pz_regs.reg_pat_init[0].reg_0x330B) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x330C, + sn12m0pz_regs.reg_pat_init[0].reg_0x330C) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x330D, + sn12m0pz_regs.reg_pat_init[0].reg_0x330D) < 0) + return rc; + + /* Mode setting */ + /* Update registers with correct + frame_length_line value for AFR */ + total_lines_per_frame = (uint16_t)( + (sn12m0pz_regs.reg_pat[rt].frame_length_lines_msb << 8) + & 0xFF00) + + sn12m0pz_regs.reg_pat[rt].frame_length_lines_lsb; + total_lines_per_frame = total_lines_per_frame * + sn12m0pz_ctrl->fps_divider / 0x400; + + if (sn12m0pz_i2c_write_b_sensor( + REG_FRAME_LENGTH_LINES_MSB, + (total_lines_per_frame & 0xFF00) >> 8) + < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor( + REG_FRAME_LENGTH_LINES_LSB, + (total_lines_per_frame & 0x00FF)) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_MSB, + sn12m0pz_regs.reg_pat[rt].line_length_pck_msb) < + 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_LSB, + sn12m0pz_regs.reg_pat[rt].line_length_pck_lsb) < + 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_X_OUTPUT_SIZE_MSB, + sn12m0pz_regs.reg_pat[rt].x_output_size_msb) < + 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_X_OUTPUT_SIZE_LSB, + sn12m0pz_regs.reg_pat[rt].x_output_size_lsb) < + 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_Y_OUTPUT_SIZE_MSB, + sn12m0pz_regs.reg_pat[rt].y_output_size_msb) < + 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_Y_OUTPUT_SIZE_LSB, + sn12m0pz_regs.reg_pat[rt].y_output_size_lsb) < + 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_X_EVEN_INC_LSB, + sn12m0pz_regs.reg_pat[rt].x_even_inc_lsb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_X_ODD_INC_LSB, + sn12m0pz_regs.reg_pat[rt].x_odd_inc_lsb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_Y_EVEN_INC_LSB, + sn12m0pz_regs.reg_pat[rt].y_even_inc_lsb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_Y_ODD_INC_LSB, + sn12m0pz_regs.reg_pat[rt].y_odd_inc_lsb) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3016, + sn12m0pz_regs.reg_pat[rt].reg_0x3016) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x30E8, + sn12m0pz_regs.reg_pat[rt].reg_0x30E8) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x3301, + sn12m0pz_regs.reg_pat[rt].reg_0x3301) < 0) + return rc; + + if (sn12m0pz_i2c_write_b_sensor(REG_0x0344, + sn12m0pz_regs.reg_pat[rt].reg_0x0344) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x0345, + sn12m0pz_regs.reg_pat[rt].reg_0x0345) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x0346, + sn12m0pz_regs.reg_pat[rt].reg_0x0346) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x0347, + sn12m0pz_regs.reg_pat[rt].reg_0x0347) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x0348, + sn12m0pz_regs.reg_pat[rt].reg_0x0348) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x0349, + sn12m0pz_regs.reg_pat[rt].reg_0x0349) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x034A, + sn12m0pz_regs.reg_pat[rt].reg_0x034A) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(REG_0x034B, + sn12m0pz_regs.reg_pat[rt].reg_0x034B) < 0) + return rc; + + if ((rt == RES_CAPTURE) && fullsize_cropped_at_8mp) { + /* x address end */ + if (sn12m0pz_i2c_write_b_sensor(0x0348, + 0x0C) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(0x0349, + 0x0CF) < 0) + return rc; + /* y address end */ + if (sn12m0pz_i2c_write_b_sensor(0x034A, + 0x09) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor(0x034B, + 0x9F) < 0) + return rc; + } + + if (mipi_config == IU060F_SN12M0PZ_STMIPID01) { + if (sn12m0pz_i2c_write_b_sensor( + REG_PLL_MULTIPLIER, 0x43) < 0) + return rc; + if (rt == RES_CAPTURE) { + if (sn12m0pz_i2c_write_b_sensor( + REG_0x3301, 0x01) < 0) + return rc; + if (sn12m0pz_i2c_write_b_sensor( + REG_0x3017, 0xE0) < 0) + return rc; + } + } + + if (sn12m0pz_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STREAM) < 0) + return rc; + + msleep(IU060F_SN12M0PZ_DELAY_MSECS); + + if (sn12m0pz_test(sn12m0pz_ctrl->set_test) < 0) + return rc; + + if (mipi_config == IU060F_SN12M0PZ_STMIPID02) + CDBG("%s,%d", __func__, __LINE__); + return rc; + } + default: + return rc; + } +} + + +static int32_t sn12m0pz_video_config(int mode) +{ + + int32_t rc = 0; + int rt; + + + if (mode == SENSOR_HFR_120FPS_MODE) + sn12m0pz_ctrl->prev_res = QVGA_SIZE; + + /* change sensor resolution if needed */ + if (sn12m0pz_ctrl->curr_res != sn12m0pz_ctrl->prev_res) { + if (sn12m0pz_ctrl->prev_res == QTR_SIZE) { + rt = RES_PREVIEW; + IU060F_SN12M0PZ_DELAY_MSECS = 35; /*measured on scope*/ + enable_single_D02_lane = 1; + } else if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) { + rt = RES_VIDEO_120FPS; + IU060F_SN12M0PZ_DELAY_MSECS = 35; /*measured on scope*/ + enable_single_D02_lane = 0; + } else { + rt = RES_CAPTURE; + enable_single_D02_lane = 0; + } + + if (sn12m0pz_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + + sn12m0pz_ctrl->curr_res = sn12m0pz_ctrl->prev_res; + sn12m0pz_ctrl->sensormode = mode; + + return rc; +} +static int32_t sn12m0pz_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + if (sn12m0pz_ctrl->curr_res != sn12m0pz_ctrl->pict_res) { + if (sn12m0pz_ctrl->pict_res == QTR_SIZE) { + rt = RES_PREVIEW; + enable_single_D02_lane = 1; + } else { + rt = RES_CAPTURE; + IU060F_SN12M0PZ_DELAY_MSECS = 100;/*measured on scope*/ + enable_single_D02_lane = 0; + } + + if (sn12m0pz_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + + sn12m0pz_ctrl->curr_res = sn12m0pz_ctrl->pict_res; + sn12m0pz_ctrl->sensormode = mode; + return rc; +} + +static int32_t sn12m0pz_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + if (sn12m0pz_ctrl->curr_res != sn12m0pz_ctrl->pict_res) { + if (sn12m0pz_ctrl->pict_res == QTR_SIZE) { + rt = RES_PREVIEW; + enable_single_D02_lane = 1; + } else { + rt = RES_CAPTURE; + IU060F_SN12M0PZ_DELAY_MSECS = 100;/*measured on scope*/ + enable_single_D02_lane = 0; + } + if (sn12m0pz_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + sn12m0pz_ctrl->curr_res = sn12m0pz_ctrl->pict_res; + sn12m0pz_ctrl->sensormode = mode; + return rc; +} +static int32_t sn12m0pz_set_sensor_mode(int mode, + int res) +{ + int32_t rc; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + case SENSOR_HFR_120FPS_MODE: + rc = sn12m0pz_video_config(mode); + break; + + case SENSOR_SNAPSHOT_MODE: + rc = sn12m0pz_snapshot_config(mode); + break; + + case SENSOR_RAW_SNAPSHOT_MODE: + rc = sn12m0pz_raw_snapshot_config(mode); + break; + + default: + rc = -EINVAL; + break; + } + return rc; +} + +static int32_t sn12m0pz_power_down(void) +{ + return 0; +} + + +static int sn12m0pz_probe_init_done(const struct msm_camera_sensor_info *data) +{ + + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + gpio_direction_output(data->vcm_pwd, 0); + gpio_free(data->vcm_pwd); + return 0; +} + +static int sn12m0pz_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + unsigned short chipidl, chipidh; + CDBG("Requesting gpio"); + rc = gpio_request(data->sensor_reset, "sn12m0pz"); + CDBG(" sn12m0pz_probe_init_sensor"); + if (!rc) { + gpio_direction_output(data->sensor_reset, 0); + msleep(20); + gpio_direction_output(data->sensor_reset, 1); + msleep(13); + } else { + goto init_probe_done; + } + CDBG("Requestion gpio"); + rc = gpio_request(data->vcm_pwd, "sn12m0pz"); + CDBG(" sn12m0pz_probe_init_sensor"); + + if (!rc) { + gpio_direction_output(data->vcm_pwd, 0); + msleep(20); + gpio_direction_output(data->vcm_pwd, 1); + msleep(13); + } else { + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + goto init_probe_done; + } + + msleep(20); + + /* 3. Read sensor Model ID: */ + rc = sn12m0pz_i2c_read(0x0000, &chipidh, 1); + if (rc < 0) { + CDBG(" sn12m0pz_probe_init_sensor3"); + goto init_probe_fail; + } + rc = sn12m0pz_i2c_read(0x0001, &chipidl, 1); + if (rc < 0) { + CDBG(" sn12m0pz_probe_init_sensor4"); + goto init_probe_fail; + } + + /* 4. Compare sensor ID to SN12M0PZ ID: */ + if (chipidh != 0x00 || chipidl != 0x60) { + rc = -ENODEV; + CDBG("sn12m0pz_probe_init_sensor fail chip id doesnot match"); + goto init_probe_fail; + } + + msleep(SN12M0PZ_RESET_DELAY_MSECS); + + goto init_probe_done; + +init_probe_fail: + CDBG(" sn12m0pz_probe_init_sensor fails"); + sn12m0pz_probe_init_done(data); + +init_probe_done: + CDBG(" sn12m0pz_probe_init_sensor finishes"); + return rc; +} + +int sn12m0pz_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + CDBG("Calling sn12m0pz_sensor_open_init"); + + sn12m0pz_ctrl = kzalloc(sizeof(struct sn12m0pz_ctrl_t), GFP_KERNEL); + if (!sn12m0pz_ctrl) { + CDBG("sn12m0pz_init failed!"); + rc = -ENOMEM; + goto init_done; + } + + sn12m0pz_ctrl->fps_divider = 1 * 0x00000400; + sn12m0pz_ctrl->pict_fps_divider = 1 * 0x00000400; + sn12m0pz_ctrl->set_test = TEST_OFF; + sn12m0pz_ctrl->prev_res = QTR_SIZE; + sn12m0pz_ctrl->pict_res = FULL_SIZE; + sn12m0pz_ctrl->curr_res = INVALID_SIZE; + if (data) + sn12m0pz_ctrl->sensordata = data; + + if (rc < 0) + return rc; + + /* enable mclk first */ + msm_camio_clk_rate_set(SN12M0PZ_DEFAULT_CLOCK_RATE); + msleep(20); + msm_camio_camif_pad_reg_reset(); + msleep(20); + CDBG("Calling sn12m0pz_sensor_open_init"); + rc = sn12m0pz_probe_init_sensor(data); + + if (rc < 0) + goto init_fail; + /* send reset signal */ + if (mipi_config == IU060F_SN12M0PZ_STMIPID01) { + if (sn12m0pz_stmipid01_config() < 0) { + CDBG("Calling sn12m0pz_sensor_open_init fail"); + return rc; + } + } else { + if (sn12m0pz_ctrl->prev_res == QTR_SIZE) + enable_single_D02_lane = 1; + else /* FULL_SIZE */ + enable_single_D02_lane = 0; + + if (sn12m0pz_stmipid02_config() < 0) { + CDBG("Calling sn12m0pz_sensor_open_init fail"); + return rc; + } + } + + + if (sn12m0pz_ctrl->prev_res == QTR_SIZE) { + if (sn12m0pz_sensor_setting(REG_INIT, RES_PREVIEW) < 0) + return rc; + } else if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) { + if (sn12m0pz_sensor_setting(REG_INIT, RES_VIDEO_120FPS) < 0) + return rc; + } else { + if (sn12m0pz_sensor_setting(REG_INIT, RES_CAPTURE) < 0) + return rc; + } + + if (sn12m0pz_af_init() < 0) + return rc; + sn12m0pz_ctrl->fps = 30*Q8; + if (rc < 0) + goto init_fail; + else + goto init_done; +init_fail: + CDBG(" init_fail"); + sn12m0pz_probe_init_done(data); + kfree(sn12m0pz_ctrl); +init_done: + CDBG("init_done"); + return rc; +} +static int __init sn12m0pz_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&sn12m0pz_wait_queue); + return 0; +} + +static const struct i2c_device_id sn12m0pz_i2c_id[] = { + { "sn12m0pz", 0}, + { } +}; + +static int sn12m0pz_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("sn12m0pz_probe called!"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed"); + goto probe_failure; + } + + sn12m0pz_sensorw = kzalloc(sizeof(struct sn12m0pz_work_t), GFP_KERNEL); + if (!sn12m0pz_sensorw) { + CDBG("kzalloc failed"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, sn12m0pz_sensorw); + sn12m0pz_init_client(client); + sn12m0pz_client = client; + + msleep(50); + + CDBG("sn12m0pz_probe successed! rc = %d", rc); + return 0; + +probe_failure: + CDBG("sn12m0pz_probe failed! rc = %d", rc); + return rc; +} + +static int __exit sn12m0pz_remove(struct i2c_client *client) +{ + struct sn12m0pz_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + sn12m0pz_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver sn12m0pz_i2c_driver = { + .id_table = sn12m0pz_i2c_id, + .probe = sn12m0pz_i2c_probe, + .remove = __exit_p(sn12m0pz_i2c_remove), + .driver = { + .name = "sn12m0pz", + }, +}; + +int sn12m0pz_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + int32_t rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + + mutex_lock(&sn12m0pz_mut); + + CDBG("sn12m0pz_sensor_config: cfgtype = %d", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + sn12m0pz_get_pict_fps(cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = + sn12m0pz_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = + sn12m0pz_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = + sn12m0pz_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + sn12m0pz_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + sn12m0pz_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = sn12m0pz_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = + sn12m0pz_write_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + case CFG_SET_PICT_EXP_GAIN: + rc = + sn12m0pz_set_pict_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = sn12m0pz_set_sensor_mode(cdata.mode, + cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = sn12m0pz_power_down(); + break; + + case CFG_MOVE_FOCUS: + rc = sn12m0pz_move_focus(cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = sn12m0pz_set_default_focus(cdata.cfg.focus.steps); + break; + + case CFG_SET_EFFECT: + rc = 0; + break; + case CFG_SET_LENS_SHADING: + rc = 0; + break; + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&sn12m0pz_mut); + + return rc; +} + +static int sn12m0pz_sensor_release(void) +{ + int rc = -EBADF; + + mutex_lock(&sn12m0pz_mut); + + sn12m0pz_power_down(); + + gpio_direction_output(sn12m0pz_ctrl->sensordata->sensor_reset, + 0); + gpio_free(sn12m0pz_ctrl->sensordata->sensor_reset); + + gpio_direction_output(sn12m0pz_ctrl->sensordata->vcm_pwd, + 0); + gpio_free(sn12m0pz_ctrl->sensordata->vcm_pwd); + + kfree(sn12m0pz_ctrl); + sn12m0pz_ctrl = NULL; + + CDBG("sn12m0pz_release completed"); + + + mutex_unlock(&sn12m0pz_mut); + + return rc; +} + +static int sn12m0pz_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc; + + rc = i2c_add_driver(&sn12m0pz_i2c_driver); + if (rc < 0 || sn12m0pz_client == NULL) { + rc = -ENOTSUPP; + goto probe_fail; + } + + msm_camio_clk_rate_set(SN12M0PZ_DEFAULT_CLOCK_RATE); + msleep(20); + + rc = sn12m0pz_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + + s->s_init = sn12m0pz_sensor_open_init; + s->s_release = sn12m0pz_sensor_release; + s->s_config = sn12m0pz_sensor_config; + s->s_mount_angle = 0; + sn12m0pz_probe_init_done(info); + + return rc; + +probe_fail: + CDBG("SENSOR PROBE FAILS!"); + i2c_del_driver(&sn12m0pz_i2c_driver); + return rc; +} + +static int __sn12m0pz_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, sn12m0pz_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __sn12m0pz_probe, + .driver = { + .name = "msm_camera_sn12m0pz", + .owner = THIS_MODULE, + }, +}; + +static int __init sn12m0pz_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(sn12m0pz_init); + +MODULE_DESCRIPTION("Sony 12M MP Bayer sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm_zsl/sn12m0pz.h b/drivers/media/video/msm_zsl/sn12m0pz.h new file mode 100644 index 00000000000..f2abc473421 --- /dev/null +++ b/drivers/media/video/msm_zsl/sn12m0pz.h @@ -0,0 +1,138 @@ + +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +#ifndef SN12M0PZ_H +#define SN12M0PZ_H + +#include +extern struct sn12m0pz_reg sn12m0pz_regs; /* from mt9t013_reg.c */ +struct reg_struct{ + uint8_t pll_multiplier_lsb; /* 0x0307*/ + uint8_t coarse_integ_time_msb; /* 0x0202*/ + uint8_t coarse_integ_time_lsb; /* 0x0203*/ + uint8_t frame_length_lines_msb; /* 0x0340*/ + uint8_t frame_length_lines_lsb; /* 0x0341*/ + uint8_t line_length_pck_msb; /* 0x0342*/ + uint8_t line_length_pck_lsb; /* 0x0343*/ + uint8_t x_output_size_msb; /* 0x034C*/ + uint8_t x_output_size_lsb; /* 0x034D*/ + uint8_t y_output_size_msb; /* 0x034E*/ + uint8_t y_output_size_lsb; /* 0x034F*/ + uint8_t x_even_inc_lsb; /* 0x0381*/ + uint8_t x_odd_inc_lsb; /* 0x0383*/ + uint8_t y_even_inc_lsb; /* 0x0385*/ + uint8_t y_odd_inc_lsb; /* 0x0387*/ + uint8_t reg_0x3016; /* 0x3016 VMODEADD*/ + uint8_t reg_0x30E8; /* 0x30E8 HADDAVE*/ + uint8_t reg_0x3301; /* 0x3301 RGLANESEL*/ + /*added for 120fps support */ + uint8_t reg_0x0344; + uint8_t reg_0x0345; + uint8_t reg_0x0346; + uint8_t reg_0x0347; + uint8_t reg_0x0348; + uint8_t reg_0x0349; + uint8_t reg_0x034A; + uint8_t reg_0x034B; +}; +struct reg_struct_init{ + uint8_t reg_0x302B;/* 0x302B*/ + + uint8_t reg_0x30E5;/* 0x30E5*/ + uint8_t reg_0x3300; /* 0x3300*/ + + uint8_t image_orient; /* 0x0101*/ + + uint8_t reg_0x300A; /* 0x300A*/ + uint8_t reg_0x3014; /* 0x3014*/ + uint8_t reg_0x3015; /* 0x3015*/ + uint8_t reg_0x3017; /* 0x3017*/ + uint8_t reg_0x301C; /* 0x301C*/ + uint8_t reg_0x3031; /* 0x3031*/ + uint8_t reg_0x3040; /* 0x3040*/ + uint8_t reg_0x3041; /* 0x3041*/ + uint8_t reg_0x3051; /* 0x3051*/ + uint8_t reg_0x3053; /* 0x3053*/ + uint8_t reg_0x3055; /* 0x3055*/ + uint8_t reg_0x3057; /* 0x3057*/ + uint8_t reg_0x3060; /* 0x3060*/ + uint8_t reg_0x3065; /* 0x3065*/ + uint8_t reg_0x30AA; /* 0x30AA*/ + uint8_t reg_0x30AB; /* 0x30AB*/ + uint8_t reg_0x30B0; /* 0x30B0*/ + uint8_t reg_0x30B2; /* 0x30B2*/ + + uint8_t reg_0x30D3; /* 0X30D3*/ + uint8_t reg_0x30D8; /* 0X30D8*/ + + uint8_t reg_0x3106; /* 0x3106*/ + uint8_t reg_0x3108; /* 0x3108*/ + uint8_t reg_0x310A; /* 0x310A*/ + uint8_t reg_0x310C; /* 0x310C*/ + uint8_t reg_0x310E; /* 0x310E*/ + uint8_t reg_0x3126; /* 0x3126*/ + uint8_t reg_0x312E; /* 0x312E*/ + uint8_t reg_0x313C; /* 0x313C*/ + uint8_t reg_0x313E; /* 0x313E*/ + uint8_t reg_0x3140; /* 0x3140*/ + uint8_t reg_0x3142; /* 0x3142*/ + uint8_t reg_0x3144; /* 0x3144*/ + uint8_t reg_0x3148; /* 0x3148*/ + uint8_t reg_0x314A; /* 0x314A*/ + uint8_t reg_0x3166; /* 0x3166*/ + uint8_t reg_0x3168; /* 0x3168*/ + uint8_t reg_0x316F; /* 0x316F*/ + uint8_t reg_0x3171; /* 0x3171*/ + uint8_t reg_0x3173; /* 0x3173*/ + uint8_t reg_0x3175; /* 0x3175*/ + uint8_t reg_0x3177; /* 0x3177*/ + uint8_t reg_0x3179; /* 0x3179*/ + uint8_t reg_0x317B; /* 0x317B*/ + uint8_t reg_0x317D; /* 0x317D*/ + uint8_t reg_0x317F; /* 0x317F*/ + uint8_t reg_0x3181; /* 0x3181*/ + uint8_t reg_0x3184; /* 0x3184*/ + uint8_t reg_0x3185; /* 0x3185*/ + uint8_t reg_0x3187; /* 0x3187*/ + + uint8_t reg_0x31A4; /* 0x31A4*/ + uint8_t reg_0x31A6; /* 0x31A6*/ + uint8_t reg_0x31AC; /* 0x31AC*/ + uint8_t reg_0x31AE; /* 0x31AE*/ + uint8_t reg_0x31B4; /* 0x31B4*/ + uint8_t reg_0x31B6; /* 0x31B6*/ + + uint8_t reg_0x3254; /* 0x3254*/ + uint8_t reg_0x3256; /* 0x3256*/ + uint8_t reg_0x3258; /* 0x3258*/ + uint8_t reg_0x325A; /* 0x325A*/ + uint8_t reg_0x3260; /* 0x3260*/ + uint8_t reg_0x3262; /* 0x3262*/ + + uint8_t reg_0x3304; /* 0x3304*/ + uint8_t reg_0x3305; /* 0x3305*/ + uint8_t reg_0x3306; /* 0x3306*/ + uint8_t reg_0x3307; /* 0x3307*/ + uint8_t reg_0x3308; /* 0x3308*/ + uint8_t reg_0x3309; /* 0x3309*/ + uint8_t reg_0x330A; /* 0x330A*/ + uint8_t reg_0x330B; /* 0x330B*/ + uint8_t reg_0x330C; /* 0x330C*/ + uint8_t reg_0x330D; /* 0x330D*/ + +}; +struct sn12m0pz_reg{ + const struct reg_struct *reg_pat; + const struct reg_struct_init *reg_pat_init; +}; +#endif diff --git a/drivers/media/video/msm_zsl/sn12m0pz_reg.c b/drivers/media/video/msm_zsl/sn12m0pz_reg.c new file mode 100644 index 00000000000..124d8d98806 --- /dev/null +++ b/drivers/media/video/msm_zsl/sn12m0pz_reg.c @@ -0,0 +1,212 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "sn12m0pz.h" +/* Initialisation settings */ + +const struct reg_struct_init iu060f_reg_pat_init[1] = {{ + /* PLL setting */ + 0x4B, /* reg 0x302B*/ + /* MIPI Enable Setting */ + 0x04, /* reg 0x30E5*/ + 0x00, /* reg 0x3300*/ + /* Global Setting */ + 0x00, /* image_orientation*/ + 0x80, /* reg 0x300A*/ + 0x08, /* reg 0x3014*/ + 0x37, /* reg 0x3015*/ + 0x60, /* reg 0x3017*/ + 0x01, /* reg 0x301C*/ + 0x28, /* reg 0x3031*/ + 0x00, /* reg 0x3040*/ + 0x60, /* reg 0x3041*/ + 0x24, /* reg 0x3051*/ + 0x34, /* reg 0x3053*/ + 0x3B, /* reg 0x3055*/ + 0xC0, /* reg 0x3057*/ + 0x30, /* reg 0x3060*/ + 0x00, /* reg 0x3065*/ + 0x88, /* reg 0x30AA*/ + 0x1C, /* reg 0x30AB*/ + 0x32, /* reg 0x30B0*/ + 0x83, /* reg 0x30B2*/ + 0x04, /* reg 0x30D3*/ + 0xC0, /* reg 0x30D8*/ + 0x50, /* reg 0x3106*/ + 0xA5, /* reg 0x3108*/ + 0xA9, /* reg 0x310A*/ + 0x0C, /* reg 0x310C*/ + 0x55, /* reg 0x310E*/ + 0xCC, /* reg 0x3126*/ + 0x83, /* reg 0x312E*/ + 0xC7, /* reg 0x313C*/ + 0x07, /* reg 0x313E*/ + 0x32, /* reg 0x3140*/ + 0x35, /* reg 0x3142*/ + 0x35, /* reg 0x3144*/ + 0x73, /* reg 0x3148*/ + 0x80, /* reg 0x314A*/ + 0xBE, /* reg 0x3166*/ + 0xBD, /* reg 0x3168*/ + 0x82, /* reg 0x316F*/ + 0xBC, /* reg 0x3171*/ + 0x82, /* reg 0x3173*/ + 0xBC, /* reg 0x3175*/ + 0x0C, /* reg 0x3177*/ + 0x2C, /* reg 0x3179*/ + 0x83, /* reg 0x317B*/ + 0xAF, /* reg 0x317D*/ + 0x83, /* reg 0x317F*/ + 0xAF, /* reg 0x3181*/ + 0x06, /* reg 0x3184*/ + 0xBA, /* reg 0x3185*/ + 0xBE, /* reg 0x3187*/ + 0xD8, /* reg 0x31A4*/ + 0x17, /* reg 0x31A6*/ + 0xCF, /* reg 0x31AC*/ + 0xF1, /* reg 0x31AE*/ + 0xD8, /* reg 0x31B4*/ + 0x17, /* reg 0x31B6*/ + 0x09, /* reg 0x3254 */ + 0xC5, /* reg 0x3256 */ + 0x84, /* reg 0x3258 */ + 0x6C, /* reg 0x325A */ + 0x0B, /* reg 0x3260 */ + 0x09, /* reg 0x3262 */ + 0x05, /* reg 0x3304*/ + 0x04, /* reg 0x3305*/ + 0x15, /* reg 0x3306*/ + 0x03, /* reg 0x3307*/ + 0x13, /* reg 0x3308*/ + 0x05, /* reg 0x3309*/ + 0x0B, /* reg 0x330A*/ + 0x04, /* reg 0x330B*/ + 0x0B, /* reg 0x330C*/ + 0x06 /* reg 0x330D*/ +} +}; + +/* Preview / Snapshot register settings */ +const struct reg_struct iu060f_reg_pat[3] = { + { /* Preview */ + 0x22, /*0x1b*/ /* fps*/ + + /* Global Setting */ + 0x01, /* coarse_integration_time_msb*/ + 0xFF, /* coarse_integration_time_lsb*/ + + /* Mode Setting */ + /* V: 1/2 V-addition (1,3), + H: 1/2 H-averaging (1,3) */ + + 0x06, /* frame_length_lines_msb 0x0340*/ + 0x02, /* frame_length_lines_lsb 0x0341*/ + 0x10, /* line_length_pck_msb 0x0342*/ + 0x70, /* line_length_pck_lsb 0x0343*/ + 0x07, /* x_output_size_msb 0x034C*/ + 0xe0, /* x_output_size_lsb 0x034D*/ + 0x05, /* y_output_size_msb 0x034E*/ + 0xe8, /* y_output_size_lsb 0x034F*/ + 0x01, /* x_even_inc_lsb 0x0381*/ + 0x03, /* x_odd_inc_lsb 0x0383*/ + 0x01, /* y_even_inc_lsb 0x0385*/ + 0x03, /* y_odd_inc_lsb 0x0387*/ + 0x46, /* reg 0x3016 VMODEADD 0x3016*/ + 0x86, /* reg 0x30E8 HADDAVE 0x30E8*/ + 0x01, /* reg 0x3301 RGLANESEL 0x3301*/ + + 0x00, /* 0x0344 */ + 0x00, /* 0x0345 */ + 0x00, /* 0x0346 */ + 0x00, /* 0x0347 */ + 0x0F, /* 0x0348 */ + 0xBF, /* 0x0349 */ + 0x0B, /* 0x034A */ + 0xCF, /* 0x034B */ + }, + { /* Snapshot */ + 0x14, /* pll_multiplier_lsb // 20/10 fps*/ + /* 0x14 for pclk 96MHz at 7.5 fps */ + + /* Global Setting */ + 0x0B, /* coarse_integration_time_msb*/ + 0xFF, /* coarse_integration_time_lsb*/ + + /* Mode Setting */ + /* Full */ + 0x0C,/*frame_length_lines_msb 0x0340*/ + 0x02,/*frame_length_lines_lsb 0x0341*/ + 0x10,/*line_length_pck_msb 0x0342*/ + 0x70,/* line_length_pck_lsb 0x0343*/ + 0x0F,/* x_output_size_msb 0x034C*/ + 0xC0, /* x_output_size_lsb 0x034D*/ + 0x0B, /* y_output_size_msb 0x034E*/ + 0xD0, /* y_output_size_lsb 0x034F*/ + 0x01, /* x_even_inc_lsb 0x0381*/ + 0x01, /* x_odd_inc_lsb 0x0383*/ + 0x01, /* y_even_inc_lsb 0x0385*/ + 0x01, /* y_odd_inc_lsb 0x0387*/ + 0x06, /* reg 0x3016 VMODEADD 0x3016*/ + 0x06, /* reg 0x30E8 HADDAVE 0x30E8*/ + 0x00, /* reg 0x3301 RGLANESEL 0x3301*/ + + 0x00, /* 0x0344 */ + 0x00, /* 0x0345 */ + 0x00, /* 0x0346 */ + 0x00, /* 0x0347 */ + 0x0F, /* 0x0348 */ + 0xBF, /* 0x0349 */ + 0x0B, /* 0x034A */ + 0xCF, /* 0x034B */ + }, + /* 120 fps settings */ + { + 0x1B, /*0x1B fps*/ + /* Global Setting */ + 0x00, /* coarse_integration_time_msb*/ + 0xFE, /* coarse_integration_time_lsb*/ + + /* Mode Setting */ + /* V: 1/8 V-addition (9,7), + H: Full */ + + 0x01, /* frame_length_lines_msb 0x0340*/ + 0x01, /* frame_length_lines_lsb 0x0341*/ + 0x10, /* line_length_pck_msb 0x0342*/ + 0x70, /* line_length_pck_lsb 0x0343*/ + 0x0f, /* x_output_size_msb 0x034C*/ + 0xc0, /* x_output_size_lsb 0x034D*/ + 0x00, /* y_output_size_msb 0x034E*/ + 0xF8, /* y_output_size_lsb 0x034F*/ + 0x01, /* x_even_inc_lsb 0x0381*/ + 0x01, /* x_odd_inc_lsb 0x0383*/ + 0x09, /* y_even_inc_lsb 0x0385*/ + 0x07, /* y_odd_inc_lsb 0x0387*/ + 0x46, /* reg 0x3016 VMODEADD 0x3016*/ + 0x86, /* reg 0x30E8 HADDAVE 0x30E8*/ + 0x00, /* reg 0x3301 RGLANESEL 0x3301*/ + /* add for 120fps support */ + 0x00, /* 0x0344*/ + 0x00, /* 0x0345*/ + 0x02, /* 0x0346*/ + 0x10, /* 0x0347*/ + 0x0F, /* 0x0348*/ + 0xBF, /* 0x0349*/ + 0x09, /* 0x034A*/ + 0xCF, /* 0x034B*/ + } +}; +struct sn12m0pz_reg sn12m0pz_regs = { + .reg_pat = &iu060f_reg_pat[0], + .reg_pat_init = &iu060f_reg_pat_init[0], +}; diff --git a/drivers/media/video/msm_zsl/vb6801.c b/drivers/media/video/msm_zsl/vb6801.c new file mode 100644 index 00000000000..fa825700c32 --- /dev/null +++ b/drivers/media/video/msm_zsl/vb6801.c @@ -0,0 +1,1616 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "vb6801.h" + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ +enum { + REG_HOLD = 0x0104, + RELEASE_HOLD = 0x0000, + HOLD = 0x0001, + STANDBY_MODE = 0x0000, + REG_COARSE_INTEGRATION_TIME = 0x0202, + REG_ANALOGUE_GAIN_CODE_GLOBAL = 0x0204, + REG_RAMP_SCALE = 0x3116, + REG_POWER_MAN_ENABLE_3 = 0x3142, + REG_POWER_MAN_ENABLE_4 = 0x3143, + REG_POWER_MAN_ENABLE_5 = 0x3144, + REG_CCP2_DATA_FORMAT = 0x0112, + REG_PRE_PLL_CLK_DIV = 0x0304, + REG_PLL_MULTIPLIER = 0x0306, + REG_VT_SYS_CLK_DIV = 0x0302, + REG_VT_PIX_CLK_DIV = 0x0300, + REG_OP_SYS_CLK_DIV = 0x030A, + REG_OP_PIX_CLK_DIV = 0x0308, + REG_VT_LINE_LENGTH_PCK = 0x0342, + REG_X_OUTPUT_SIZE = 0x034C, + REG_Y_OUTPUT_SIZE = 0x034E, + REG_X_ODD_INC = 0x0382, + REG_Y_ODD_INC = 0x0386, + REG_VT_FRAME_LENGTH_LINES = 0x0340, + REG_ANALOG_TIMING_MODES_2 = 0x3113, + REG_BRUCE_ENABLE = 0x37B0, + REG_OP_CODER_SYNC_CLK_SETUP = 0x3400, + REG_OP_CODER_ENABLE = 0x3401, + REG_OP_CODER_SLOW_PAD_EN = 0x3402, + REG_OP_CODER_AUTO_STARTUP = 0x3414, + REG_SCYTHE_ENABLE = 0x3204, + REG_SCYTHE_WEIGHT = 0x3206, + REG_FRAME_COUNT = 0x0005, + REG_MODE_SELECT = 0x0100, + REG_CCP2_CHANNEL_IDENTIFIER = 0x0110, + REG_CCP2_SIGNALLING_MODE = 0x0111, + REG_BTL_LEVEL_SETUP = 0x311B, + REG_OP_CODER_AUTOMATIC_MODE_ENABLE = 0x3403, + REG_PLL_CTRL = 0x3801, + REG_VCM_DAC_CODE = 0x3860, + REG_VCM_DAC_STROBE = 0x3868, + REG_VCM_DAC_ENABLE = 0x386C, + REG_NVM_T1_ADDR_00 = 0x3600, + REG_NVM_T1_ADDR_01 = 0x3601, + REG_NVM_T1_ADDR_02 = 0x3602, + REG_NVM_T1_ADDR_03 = 0x3603, + REG_NVM_T1_ADDR_04 = 0x3604, + REG_NVM_T1_ADDR_05 = 0x3605, + REG_NVM_T1_ADDR_06 = 0x3606, + REG_NVM_T1_ADDR_07 = 0x3607, + REG_NVM_T1_ADDR_08 = 0x3608, + REG_NVM_T1_ADDR_09 = 0x3609, + REG_NVM_T1_ADDR_0A = 0x360A, + REG_NVM_T1_ADDR_0B = 0x360B, + REG_NVM_T1_ADDR_0C = 0x360C, + REG_NVM_T1_ADDR_0D = 0x360D, + REG_NVM_T1_ADDR_0E = 0x360E, + REG_NVM_T1_ADDR_0F = 0x360F, + REG_NVM_T1_ADDR_10 = 0x3610, + REG_NVM_T1_ADDR_11 = 0x3611, + REG_NVM_T1_ADDR_12 = 0x3612, + REG_NVM_T1_ADDR_13 = 0x3613, + REG_NVM_CTRL = 0x3680, + REG_NVM_PDN = 0x3681, + REG_NVM_PULSE_WIDTH = 0x368B, +}; + +#define VB6801_LINES_PER_FRAME_PREVIEW 800 +#define VB6801_LINES_PER_FRAME_SNAPSHOT 1600 +#define VB6801_PIXELS_PER_LINE_PREVIEW 2500 +#define VB6801_PIXELS_PER_LINE_SNAPSHOT 2500 + +/* AF constant */ +#define VB6801_TOTAL_STEPS_NEAR_TO_FAR 25 +#define VB6801_STEPS_NEAR_TO_CLOSEST_INF 25 + +/* for 30 fps preview */ +#define VB6801_DEFAULT_CLOCK_RATE 12000000 + +enum vb6801_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum vb6801_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; + +enum vb6801_setting_t { + RES_PREVIEW, + RES_CAPTURE +}; + +struct vb6801_work_t { + struct work_struct work; +}; + +struct sensor_dynamic_params_t { + uint16_t preview_pixelsPerLine; + uint16_t preview_linesPerFrame; + uint16_t snapshot_pixelsPerLine; + uint16_t snapshot_linesPerFrame; + uint8_t snapshot_changed_fps; + uint32_t pclk; +}; + +struct vb6801_sensor_info { + /* Sensor Configuration Input Parameters */ + uint32_t ext_clk_freq_mhz; + uint32_t target_frame_rate_fps; + uint32_t target_vt_pix_clk_freq_mhz; + uint32_t sub_sampling_factor; + uint32_t analog_binning_allowed; + uint32_t raw_mode; + uint32_t capture_mode; + + /* Image Readout Registers */ + uint32_t x_odd_inc; /* x pixel array addressing odd increment */ + uint32_t y_odd_inc; /* y pixel array addressing odd increment */ + uint32_t x_output_size; /* width of output image */ + uint32_t y_output_size; /* height of output image */ + + /* Declare data format */ + uint32_t ccp2_data_format; + + /* Clock Tree Registers */ + uint32_t pre_pll_clk_div; + uint32_t pll_multiplier; + uint32_t vt_sys_clk_div; + uint32_t vt_pix_clk_div; + uint32_t op_sys_clk_div; + uint32_t op_pix_clk_div; + + /* Video Timing Registers */ + uint32_t vt_line_length_pck; + uint32_t vt_frame_length_lines; + + /* Analogue Binning Registers */ + uint8_t vtiming_major; + uint8_t analog_timing_modes_4; + + /* Fine (pixel) Integration Time Registers */ + uint32_t fine_integration_time; + + /* Coarse (lines) Integration Time Limit Registers */ + uint32_t coarse_integration_time_max; + + /* Coarse (lines) Integration Timit Register (16-bit) */ + uint32_t coarse_integration_time; + + /* Analogue Gain Code Global Registers */ + uint32_t analogue_gain_code_global; + + /* Digital Gain Code Registers */ + uint32_t digital_gain_code; + + /* Overall gain (analogue & digital) code + * Note that this is not a real register but just + * an abstraction for the combination of analogue + * and digital gain */ + uint32_t gain_code; + + /* FMT Test Information */ + uint32_t pass_fail; + uint32_t day; + uint32_t month; + uint32_t year; + uint32_t tester; + uint32_t part_number; + + /* Autofocus controls */ + uint32_t vcm_dac_code; + int vcm_max_dac_code_step; + int vcm_proportional_factor; + int vcm_dac_code_spacing_ms; + + /* VCM NVM Characterisation Information */ + uint32_t vcm_dac_code_infinity_dn; + uint32_t vcm_dac_code_macro_up; + uint32_t vcm_dac_code_up_dn_delta; + + /* Internal Variables */ + uint32_t min_vt_frame_length_lines; +}; + +struct vb6801_work_t *vb6801_sensorw; +struct i2c_client *vb6801_client; + +struct vb6801_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + + int sensormode; + uint32_t factor_fps; /* init to 1 * 0x00000400 */ + uint16_t curr_fps; + uint16_t max_fps; + int8_t pict_exp_update; + int8_t reducel; + uint16_t curr_lens_pos; + uint16_t init_curr_lens_pos; + enum vb6801_resolution_t prev_res; + enum vb6801_resolution_t pict_res; + enum vb6801_resolution_t curr_res; + enum vb6801_test_mode_t set_test; + + struct vb6801_sensor_info s_info; + struct sensor_dynamic_params_t s_dynamic_params; +}; + +static struct vb6801_ctrl_t *vb6801_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(vb6801_wait_queue); +DEFINE_MUTEX(vb6801_mut); + +static int vb6801_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 2, + .buf = rxdata, + }, + }; + + if (i2c_transfer(vb6801_client->adapter, msgs, 2) < 0) { + CDBG("vb6801_i2c_rxdata failed!\n"); + return -EIO; + } + + return 0; +} + +static int32_t vb6801_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + + if (!rdata) + return -EIO; + + memset(buf, 0, sizeof(buf)); + + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + + rc = vb6801_i2c_rxdata(vb6801_client->addr, buf, rlen); + + if (rc < 0) { + CDBG("vb6801_i2c_read 0x%x failed!\n", raddr); + return rc; + } + + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + + return rc; +} + +static int32_t vb6801_i2c_read_table(struct vb6801_i2c_reg_conf_t *regs, + int items) +{ + int i; + int32_t rc = -EFAULT; + + for (i = 0; i < items; i++) { + unsigned short *buf = + regs->dlen == D_LEN_BYTE ? + (unsigned short *)®s->bdata : + (unsigned short *)®s->wdata; + rc = vb6801_i2c_read(regs->waddr, buf, regs->dlen + 1); + + if (rc < 0) { + CDBG("vb6801_i2c_read_table Failed!!!\n"); + break; + } + + regs++; + } + + return rc; +} + +static int32_t vb6801_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + if (i2c_transfer(vb6801_client->adapter, msg, 1) < 0) { + CDBG("vb6801_i2c_txdata faild 0x%x\n", vb6801_client->addr); + return -EIO; + } + + return 0; +} + +static int32_t vb6801_i2c_write_b(unsigned short waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[3]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + + CDBG("i2c_write_b addr = %d, val = %d\n", waddr, bdata); + rc = vb6801_i2c_txdata(vb6801_client->addr, buf, 3); + + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + + return rc; +} + +static int32_t vb6801_i2c_write_w(unsigned short waddr, unsigned short wdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[4]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00) >> 8; + buf[3] = (wdata & 0x00FF); + + CDBG("i2c_write_w addr = %d, val = %d, buf[2] = 0x%x, buf[3] = 0x%x\n", + waddr, wdata, buf[2], buf[3]); + + rc = vb6801_i2c_txdata(vb6801_client->addr, buf, 4); + if (rc < 0) { + CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + } + + return rc; +} + +static int32_t vb6801_i2c_write_table(struct vb6801_i2c_reg_conf_t *regs, + int items) +{ + int i; + int32_t rc = -EFAULT; + + for (i = 0; i < items; i++) { + rc = ((regs->dlen == D_LEN_BYTE) ? + vb6801_i2c_write_b(regs->waddr, regs->bdata) : + vb6801_i2c_write_w(regs->waddr, regs->wdata)); + + if (rc < 0) { + CDBG("vb6801_i2c_write_table Failed!!!\n"); + break; + } + + regs++; + } + + return rc; +} + +static int32_t vb6801_reset(const struct msm_camera_sensor_info *data) +{ + int rc; + + rc = gpio_request(data->sensor_reset, "vb6801"); + if (!rc) { + CDBG("sensor_reset SUcceeded\n"); + gpio_direction_output(data->sensor_reset, 0); + mdelay(50); + gpio_direction_output(data->sensor_reset, 1); + mdelay(13); + } else + CDBG("sensor_reset FAiled\n"); + + return rc; +} + +static int32_t vb6801_set_default_focus(void) +{ + int32_t rc = 0; + + /* FIXME: Default focus not supported */ + + return rc; +} + +static void vb6801_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint32_t divider; /*Q10 */ + uint32_t pclk_mult; /*Q10 */ + uint32_t d1; + uint32_t d2; + + d1 = + (uint32_t)( + (vb6801_ctrl->s_dynamic_params.preview_linesPerFrame * + 0x00000400) / + vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame); + + d2 = + (uint32_t)( + (vb6801_ctrl->s_dynamic_params.preview_pixelsPerLine * + 0x00000400) / + vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine); + + + divider = (uint32_t) (d1 * d2) / 0x00000400; + + pclk_mult = (48 * 0x400) / 60; + + /* Verify PCLK settings and frame sizes. */ + *pfps = (uint16_t)((((fps * pclk_mult) / 0x00000400) * divider)/ + 0x00000400); +} + +static uint16_t vb6801_get_prev_lines_pf(void) +{ + if (vb6801_ctrl->prev_res == QTR_SIZE) + return vb6801_ctrl->s_dynamic_params.preview_linesPerFrame; + else + return vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame; +} + +static uint16_t vb6801_get_prev_pixels_pl(void) +{ + if (vb6801_ctrl->prev_res == QTR_SIZE) + return vb6801_ctrl->s_dynamic_params.preview_pixelsPerLine; + else + return vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine; +} + +static uint16_t vb6801_get_pict_lines_pf(void) +{ + return vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame; +} + +static uint16_t vb6801_get_pict_pixels_pl(void) +{ + return vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine; +} + +static uint32_t vb6801_get_pict_max_exp_lc(void) +{ + uint16_t snapshot_lines_per_frame; + + if (vb6801_ctrl->pict_res == QTR_SIZE) { + snapshot_lines_per_frame = + vb6801_ctrl->s_dynamic_params.preview_linesPerFrame - 3; + } else { + snapshot_lines_per_frame = + vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame - 3; + } + + return snapshot_lines_per_frame; +} + +static int32_t vb6801_set_fps(struct fps_cfg *fps) +{ + int32_t rc = 0; + + /* input is new fps in Q8 format */ + switch (fps->fps_div) { + case 7680: /* 30 * Q8 */ + vb6801_ctrl->factor_fps = 1; + break; + + case 3840: /* 15 * Q8 */ + vb6801_ctrl->factor_fps = 2; + break; + + case 2560: /* 10 * Q8 */ + vb6801_ctrl->factor_fps = 3; + break; + + case 1920: /* 7.5 * Q8 */ + vb6801_ctrl->factor_fps = 4; + break; + + default: + rc = -ENODEV; + break; + } + + return rc; +} + +static int32_t vb6801_write_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + uint16_t lpf; + + if (vb6801_ctrl->curr_res == SENSOR_FULL_SIZE) + lpf = VB6801_LINES_PER_FRAME_SNAPSHOT; + else + lpf = VB6801_LINES_PER_FRAME_PREVIEW; + + /* hold */ + rc = vb6801_i2c_write_w(REG_HOLD, HOLD); + if (rc < 0) + goto exp_gain_done; + + if ((vb6801_ctrl->curr_fps < + vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps) && + (!vb6801_ctrl->pict_exp_update)) { + + if (vb6801_ctrl->reducel) { + + rc = vb6801_i2c_write_w(REG_VT_FRAME_LENGTH_LINES, + lpf * vb6801_ctrl->factor_fps); + + vb6801_ctrl->curr_fps = + vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps; + + } else if (!vb6801_ctrl->reducel) { + + rc = vb6801_i2c_write_w(REG_COARSE_INTEGRATION_TIME, + line * vb6801_ctrl->factor_fps); + + vb6801_ctrl->reducel = 1; + } + } else if ((vb6801_ctrl->curr_fps > + vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps) && + (!vb6801_ctrl->pict_exp_update)) { + + rc = vb6801_i2c_write_w(REG_VT_FRAME_LENGTH_LINES, + lpf * vb6801_ctrl->factor_fps); + + vb6801_ctrl->curr_fps = + vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps; + + } else { + /* analogue_gain_code_global */ + rc = vb6801_i2c_write_w(REG_ANALOGUE_GAIN_CODE_GLOBAL, gain); + if (rc < 0) + goto exp_gain_done; + + /* coarse_integration_time */ + rc = vb6801_i2c_write_w(REG_COARSE_INTEGRATION_TIME, + line * vb6801_ctrl->factor_fps); + if (rc < 0) + goto exp_gain_done; + + vb6801_ctrl->pict_exp_update = 1; + } + + rc = vb6801_i2c_write_w(REG_HOLD, RELEASE_HOLD); + +exp_gain_done: + return rc; +} + +static int32_t vb6801_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + vb6801_ctrl->pict_exp_update = 1; + return vb6801_write_exp_gain(gain, line); +} + +static int32_t vb6801_power_down(void) +{ + int32_t rc = 0; + rc = vb6801_i2c_write_b(REG_NVM_PDN, 0); + + mdelay(5); + return rc; +} + +static int32_t vb6801_go_to_position(uint32_t target_vcm_dac_code, + struct vb6801_sensor_info *ps) +{ + /* Prior to running this function the following values must + * be initialised in the sensor data structure, PS + * ps->vcm_dac_code + * ps->vcm_max_dac_code_step + * ps->vcm_dac_code_spacing_ms */ + + int32_t rc = 0; + + ps->vcm_dac_code = target_vcm_dac_code; + + /* Restore Strobe to zero state */ + rc = vb6801_i2c_write_b(REG_VCM_DAC_STROBE, 0x00); + if (rc < 0) + return rc; + + /* Write 9-bit VCM DAC Code */ + rc = vb6801_i2c_write_w(REG_VCM_DAC_CODE, ps->vcm_dac_code); + if (rc < 0) + return rc; + + /* Generate a rising edge on the dac_strobe to latch + * new DAC value */ + + rc = vb6801_i2c_write_w(REG_VCM_DAC_STROBE, 0x01); + + return rc; +} + +static int32_t vb6801_move_focus(int direction, int32_t num_steps) +{ + int16_t step_direction; + int16_t actual_step; + int16_t next_position; + uint32_t step_size; + int16_t small_move[4]; + uint16_t i; + int32_t rc = 0; + + step_size = (vb6801_ctrl->s_info.vcm_dac_code_macro_up - + vb6801_ctrl->s_info.vcm_dac_code_infinity_dn) / + VB6801_TOTAL_STEPS_NEAR_TO_FAR; + + if (num_steps > VB6801_TOTAL_STEPS_NEAR_TO_FAR) + num_steps = VB6801_TOTAL_STEPS_NEAR_TO_FAR; + else if (num_steps == 0) + return -EINVAL; + + if (direction == MOVE_NEAR) + step_direction = 4; + else if (direction == MOVE_FAR) + step_direction = -4; + else + return -EINVAL; + + /* need to decide about default position and power supplied + * at start up and reset */ + if (vb6801_ctrl->curr_lens_pos < vb6801_ctrl->init_curr_lens_pos) + vb6801_ctrl->curr_lens_pos = vb6801_ctrl->init_curr_lens_pos; + + actual_step = (step_direction * num_steps); + + next_position = vb6801_ctrl->curr_lens_pos; + + for (i = 0; i < 4; i++) { + if (actual_step >= 0) + small_move[i] = + (i + 1) * actual_step / 4 - i * actual_step / 4; + + if (actual_step < 0) + small_move[i] = + (i + 1) * actual_step / 4 - i * actual_step / 4; + } + + if (next_position > 511) + next_position = 511; + else if (next_position < 0) + next_position = 0; + + /* for damping */ + for (i = 0; i < 4; i++) { + next_position = + (int16_t) (vb6801_ctrl->curr_lens_pos + small_move[i]); + + /* Writing the digital code for current to the actuator */ + CDBG("next_position in damping mode = %d\n", next_position); + + rc = vb6801_go_to_position(next_position, &vb6801_ctrl->s_info); + if (rc < 0) { + CDBG("go_to_position Failed!!!\n"); + return rc; + } + + vb6801_ctrl->curr_lens_pos = next_position; + if (i < 3) + mdelay(5); + } + + return rc; +} + +static int vb6801_read_nvm_data(struct vb6801_sensor_info *ps) +{ + /* +--------+------+------+----------------+---------------+ + * | Index | NVM | NVM | Name | Description | + * | | Addr | Byte | | | + * +--------+------+------+----------------+---------------+ + * | 0x3600 | 0 | 3 | nvm_t1_addr_00 | {PF[2:0]:Day[4:0]} | + * | 0x3601 | 0 | 2 | nvm_t1_addr_01 | {Month[3:0]:Year[3:0]} | + * | 0x3602 | 0 | 1 | nvm_t1_addr_02 | Tester[7:0] | + * | 0x3603 | 0 | 0 | nvm_t1_addr_03 | Part[15:8] | + * +--------+------+------+----------------+---------------+ + * | 0x3604 | 1 | 3 | nvm_t1_addr_04 | Part[7:0] | + * | 0x3605 | 1 | 2 | nvm_t1_addr_05 | StartWPM[7:0] | + * | 0x3606 | 1 | 1 | nvm_t1_addr_06 | Infinity[7:0] | + * | 0x3607 | 1 | 0 | nvm_t1_addr_07 | Macro[7:0] | + * +--------+------+------+----------------+---------------+ + * | 0x3608 | 2 | 3 | nvm_t1_addr_08 | Reserved | + * | 0x3609 | 2 | 2 | nvm_t1_addr_09 | Reserved | + * | 0x360A | 2 | 1 | nvm_t1_addr_0A | UpDown[7:0] | + * | 0x360B | 2 | 0 | nvm_t1_addr_0B | Reserved | + * +--------+------+------+----------------+---------------+ + * | 0x360C | 3 | 3 | nvm_t1_addr_0C | Reserved | + * | 0x360D | 3 | 2 | nvm_t1_addr_0D | Reserved | + * | 0x360E | 3 | 1 | nvm_t1_addr_0E | Reserved | + * | 0x360F | 3 | 0 | nvm_t1_addr_0F | Reserved | + * +--------+------+------+----------------+---------------+ + * | 0x3610 | 4 | 3 | nvm_t1_addr_10 | Reserved | + * | 0x3611 | 4 | 2 | nvm_t1_addr_11 | Reserved | + * | 0x3612 | 4 | 1 | nvm_t1_addr_12 | Reserved | + * | 0x3613 | 4 | 0 | nvm_t1_addr_13 | Reserved | + * +--------+------+------+----------------+---------------+*/ + + int32_t rc; + struct vb6801_i2c_reg_conf_t rreg[] = { + {REG_NVM_T1_ADDR_00, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_01, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_02, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_03, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_04, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_05, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_06, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_07, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_08, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_09, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_0A, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_0B, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_0C, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_0D, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_0E, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_0F, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_10, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_11, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_12, 0, 0, D_LEN_BYTE}, + {REG_NVM_T1_ADDR_13, 0, 0, D_LEN_BYTE}, + }; + + struct vb6801_i2c_reg_conf_t wreg[] = { + /* Enable NVM for Direct Reading */ + {REG_NVM_CTRL, 0, 2, D_LEN_BYTE}, + + /* Power up NVM */ + {REG_NVM_PDN, 0, 1, D_LEN_BYTE}, + }; + + rc = vb6801_i2c_write_table(wreg, ARRAY_SIZE(wreg)); + if (rc < 0) { + CDBG("I2C Write Table FAILED!!!\n"); + return rc; + } + + /* NVM Read Pulse Width + * ==================== + * nvm_pulse_width_us = nvm_pulse_width_ext_clk / ext_clk_freq_mhz + * Valid Range for Read Pulse Width = 400ns -> 3.0us + * Min ext_clk_freq_mhz = 6MHz => 3.0 * 6 = 18 + * Max ext_clk_freq_mhz = 27MHz => 0.4 * 27 = 10.8 + * Choose 15 as a common value + * - 15 / 6.0 = 2.5000us + * - 15 / 12.0 = 1.2500us + * - 15 / 27.0 = 0.5555us */ + rc = vb6801_i2c_write_w(REG_NVM_PULSE_WIDTH, 15); + if (rc < 0) { + rc = -EBUSY; + goto nv_shutdown; + } + + rc = vb6801_i2c_read_table(rreg, ARRAY_SIZE(rreg)); + if (rc < 0) { + CDBG("I2C Read Table FAILED!!!\n"); + rc = -EBUSY; + goto nv_shutdown; + } + + /* Decode and Save FMT Info */ + ps->pass_fail = (rreg[0].bdata & 0x00E0) >> 5; + ps->day = (rreg[0].bdata & 0x001F); + ps->month = (rreg[1].bdata & 0x00F0) >> 4; + ps->year = (rreg[1].bdata & 0x000F) + 2000; + ps->tester = rreg[2].bdata; + ps->part_number = (rreg[3].bdata << 8) + rreg[4].bdata; + + /* Decode and Save VCM Dac Values in data structure */ + ps->vcm_dac_code_infinity_dn = rreg[6].bdata; + ps->vcm_dac_code_macro_up = rreg[7].bdata << 1; + ps->vcm_dac_code_up_dn_delta = rreg[10].bdata; + +nv_shutdown: + /* Power Down NVM to extend life time */ + rc = vb6801_i2c_write_b(REG_NVM_PDN, 0); + + return rc; +} + +static int vb6801_config_sensor(int32_t ext_clk_freq_mhz, + int32_t target_frame_rate_fps, + int32_t target_vt_pix_clk_freq_mhz, + uint32_t sub_sampling_factor, + uint32_t analog_binning_allowed, + uint32_t raw_mode, int capture_mode, + enum vb6801_resolution_t res) +{ + uint32_t rc; + /* ext_clk_freq_mhz = 6.0 -> 27.0 MHz + * target_frame_rate_fps = 15 fps + * target_vt_pix_clk_freq_mhz = 24.0 -> 64.0MHz + * sub_sampling factor = 1, 2, 3, or 4 + * raw_mode factor = 10 + * + * capture_mode, 0 = CCP1 + * capture_mode, 1 = CCP2 + * capture_mode, 2 = 10-bit parallel + hsync + vsync */ + + /* Declare data format */ + uint32_t ccp2_data_format = 0x0A0A; + + /* Declare clock tree variables */ + int32_t min_pll_ip_freq_mhz = 6; + int32_t max_pll_op_freq_mhz = 640; + uint32_t pre_pll_clk_div = 1; + int32_t pll_ip_freq_mhz = 6; + uint32_t pll_multiplier = 100; + int32_t pll_op_freq_mhz = 600; + uint32_t vt_sys_clk_div = 1; + int32_t vt_sys_clk_freq_mhz = 600; + uint32_t vt_pix_clk_div = 10; + int32_t vt_pix_clk_freq_mhz = 60; + uint32_t op_sys_clk_div = 1; + int32_t op_sys_clk_freq_mhz = 60; + uint32_t op_pix_clk_div = 10; + int32_t op_pix_clk_freq_mhz = 60; + + /* Declare pixel array and frame timing variables */ + uint32_t x_pixel_array = 2064; + uint32_t y_pixel_array = 1544; + uint32_t x_even_inc = 1; + uint32_t x_odd_inc = 1; + uint32_t y_even_inc = 1; + uint32_t y_odd_inc = 1; + uint32_t x_output_size = 2064; + uint32_t y_output_size = 1544; + uint32_t additional_rows = 2; + uint32_t min_vt_frame_blanking_lines = 16; + uint32_t vt_line_length_pck = 2500; + uint32_t vt_line_length_us = 0; + uint32_t min_vt_frame_length_lines = 1562; + uint32_t vt_frame_length_lines = 1600; + uint32_t target_vt_frame_length_ms; /* 200 * 0x0001000 / 3; */ + uint32_t vt_frame_length_ms; /* 200 * 0x0001000 / 3; */ + uint32_t frame_rate_fps = 15; + + /* Coarse intergration time */ + uint32_t coarse_integration_time = 1597; + uint32_t coarse_integration_time_max_margin = 3; + uint16_t frame_count; + int timeout; + + struct vb6801_sensor_info *pinfo = &vb6801_ctrl->s_info; + + struct vb6801_i2c_reg_conf_t rreg[] = { + {REG_PRE_PLL_CLK_DIV, 0, 0, D_LEN_WORD}, + {REG_PLL_MULTIPLIER, 0, 0, D_LEN_WORD}, + {REG_VT_SYS_CLK_DIV, 0, 0, D_LEN_WORD}, + {REG_VT_PIX_CLK_DIV, 0, 0, D_LEN_WORD}, + {REG_OP_SYS_CLK_DIV, 0, 0, D_LEN_WORD}, + {REG_OP_PIX_CLK_DIV, 0, 0, D_LEN_WORD}, + {REG_FRAME_COUNT, 0, 0, D_LEN_BYTE}, + }; + + struct vb6801_i2c_reg_conf_t wreg2[] = { + {REG_POWER_MAN_ENABLE_3, 0, 95, D_LEN_BYTE}, + {REG_POWER_MAN_ENABLE_4, 0, 142, D_LEN_BYTE}, + {REG_POWER_MAN_ENABLE_5, 0, 7, D_LEN_BYTE}, + }; + + /* VIDEO TIMING CALCULATIONS + * ========================= */ + + /* Pixel Array Size */ + x_pixel_array = 2064; + y_pixel_array = 1544; + + /* set current resolution */ + vb6801_ctrl->curr_res = res; + + /* Analogue binning setup */ + if (pinfo->analog_binning_allowed > 0 && + pinfo->sub_sampling_factor == 4) { + + pinfo->vtiming_major = 1; + pinfo->analog_timing_modes_4 = 32; + } else if (pinfo->analog_binning_allowed > 0 && + pinfo->sub_sampling_factor == 2) { + + pinfo->vtiming_major = 1; + pinfo->analog_timing_modes_4 = 0; + } else { + + pinfo->vtiming_major = 0; + pinfo->analog_timing_modes_4 = 0; + } + + /* Sub-Sampling X & Y Odd Increments: valid values 1, 3, 5, 7 */ + x_even_inc = 1; + y_even_inc = 1; + x_odd_inc = (sub_sampling_factor << 1) - x_even_inc; + y_odd_inc = (sub_sampling_factor << 1) - y_even_inc; + + /* Output image size + * Must always be a multiple of 2 - round down */ + x_output_size = ((x_pixel_array / sub_sampling_factor) >> 1) << 1; + y_output_size = ((y_pixel_array / sub_sampling_factor) >> 1) << 1; + + /* Output data format */ + ccp2_data_format = (raw_mode << 8) + raw_mode; + + /* Pre PLL clock divider : valid values 1, 2 or 4 + * The 1st step is to ensure that PLL input frequency is as close + * as possible to the min allowed PLL input frequency. + * This yields the smallest step size in the PLL output frequency. */ + pre_pll_clk_div = + ((int)(ext_clk_freq_mhz / min_pll_ip_freq_mhz) >> 1) << 1; + if (pre_pll_clk_div < 2) + pre_pll_clk_div = 1; + + pll_ip_freq_mhz = ext_clk_freq_mhz / pre_pll_clk_div; + + /* Video Timing System Clock divider: valid values 1, 2, 4 + * Now need to work backwards through the clock tree to determine the + * 1st pass estimates for vt_sys_clk_freq_mhz and then the PLL output + * frequency.*/ + vt_sys_clk_freq_mhz = vt_pix_clk_div * target_vt_pix_clk_freq_mhz; + vt_sys_clk_div = max_pll_op_freq_mhz / vt_sys_clk_freq_mhz; + if (vt_sys_clk_div < 2) + vt_sys_clk_div = 1; + + /* PLL Mulitplier: min , max 106 */ + pll_op_freq_mhz = vt_sys_clk_div * vt_sys_clk_freq_mhz; + pll_multiplier = (pll_op_freq_mhz * 0x0001000) / pll_ip_freq_mhz; + + /* Calculate the acutal pll output frequency + * - the pll_multiplier calculation introduces a quantisation error + * due the integer nature of the pll multiplier */ + pll_op_freq_mhz = (pll_ip_freq_mhz * pll_multiplier) / 0x0001000; + + /* Re-calculate video timing clock frequencies based + * on actual PLL freq */ + vt_sys_clk_freq_mhz = pll_op_freq_mhz / vt_sys_clk_div; + vt_pix_clk_freq_mhz = ((vt_sys_clk_freq_mhz * 0x0001000) / + vt_pix_clk_div)/0x0001000; + + /* Output System Clock Divider: valid value 1, 2, 4, 6, 8 + * op_sys_clk_div = vt_sys_clk_div;*/ + op_sys_clk_div = (vt_sys_clk_div * sub_sampling_factor); + if (op_sys_clk_div < 2) + op_sys_clk_div = 1; + + /* Calculate output timing clock frequencies */ + op_sys_clk_freq_mhz = pll_op_freq_mhz / op_sys_clk_div; + op_pix_clk_freq_mhz = + (op_sys_clk_freq_mhz * 0x0001000) / (op_pix_clk_div * 0x0001000); + + /* Line length in pixels and us */ + vt_line_length_pck = 2500; + vt_line_length_us = + vt_line_length_pck * 0x0001000 / vt_pix_clk_freq_mhz; + + /* Target vt_frame_length_ms */ + target_vt_frame_length_ms = (1000 * 0x0001000 / target_frame_rate_fps); + + /* Frame length in lines */ + min_vt_frame_length_lines = + additional_rows + y_output_size + min_vt_frame_blanking_lines; + + vt_frame_length_lines = + ((1000 * target_vt_frame_length_ms) / vt_line_length_us); + + if (vt_frame_length_lines <= min_vt_frame_length_lines) + vt_frame_length_lines = min_vt_frame_length_lines; + + /* Calcuate the actual frame length in ms */ + vt_frame_length_ms = (vt_frame_length_lines * vt_line_length_us / 1000); + + /* Frame Rate in fps */ + frame_rate_fps = (1000 * 0x0001000 / vt_frame_length_ms); + + /* Set coarse integration to max */ + coarse_integration_time = + vt_frame_length_lines - coarse_integration_time_max_margin; + + CDBG("SENSOR VIDEO TIMING SUMMARY:\n"); + CDBG(" ============================\n"); + CDBG("ext_clk_freq_mhz = %d\n", ext_clk_freq_mhz); + CDBG("pre_pll_clk_div = %d\n", pre_pll_clk_div); + CDBG("pll_ip_freq_mhz = %d\n", pll_ip_freq_mhz); + CDBG("pll_multiplier = %d\n", pll_multiplier); + CDBG("pll_op_freq_mhz = %d\n", pll_op_freq_mhz); + CDBG("vt_sys_clk_div = %d\n", vt_sys_clk_div); + CDBG("vt_sys_clk_freq_mhz = %d\n", vt_sys_clk_freq_mhz); + CDBG("vt_pix_clk_div = %d\n", vt_pix_clk_div); + CDBG("vt_pix_clk_freq_mhz = %d\n", vt_pix_clk_freq_mhz); + CDBG("op_sys_clk_div = %d\n", op_sys_clk_div); + CDBG("op_sys_clk_freq_mhz = %d\n", op_sys_clk_freq_mhz); + CDBG("op_pix_clk_div = %d\n", op_pix_clk_div); + CDBG("op_pix_clk_freq_mhz = %d\n", op_pix_clk_freq_mhz); + CDBG("vt_line_length_pck = %d\n", vt_line_length_pck); + CDBG("vt_line_length_us = %d\n", vt_line_length_us/0x0001000); + CDBG("vt_frame_length_lines = %d\n", vt_frame_length_lines); + CDBG("vt_frame_length_ms = %d\n", vt_frame_length_ms/0x0001000); + CDBG("frame_rate_fps = %d\n", frame_rate_fps); + CDBG("ccp2_data_format = %d\n", ccp2_data_format); + CDBG("x_output_size = %d\n", x_output_size); + CDBG("y_output_size = %d\n", y_output_size); + CDBG("x_odd_inc = %d\n", x_odd_inc); + CDBG("y_odd_inc = %d\n", y_odd_inc); + CDBG("(vt_frame_length_lines * frame_rate_factor ) = %d\n", + (vt_frame_length_lines * vb6801_ctrl->factor_fps)); + CDBG("coarse_integration_time = %d\n", coarse_integration_time); + CDBG("pinfo->vcm_dac_code = %d\n", pinfo->vcm_dac_code); + CDBG("capture_mode = %d\n", capture_mode); + + /* RE-CONFIGURE SENSOR WITH NEW TIMINGS + * ==================================== + * Enter Software Standby Mode */ + rc = vb6801_i2c_write_b(REG_MODE_SELECT, 0); + if (rc < 0) { + CDBG("I2C vb6801_i2c_write_b FAILED!!!\n"); + return rc; + } + + /* Wait 100ms */ + mdelay(100); + + if (capture_mode == 0) { + + rc = vb6801_i2c_write_b(REG_CCP2_CHANNEL_IDENTIFIER, 0); + rc = vb6801_i2c_write_b(REG_CCP2_SIGNALLING_MODE, 0); + } else if (capture_mode == 1) { + + rc = vb6801_i2c_write_b(REG_CCP2_CHANNEL_IDENTIFIER, 0); + rc = vb6801_i2c_write_b(REG_CCP2_SIGNALLING_MODE, 1); + } + + { + struct vb6801_i2c_reg_conf_t wreg[] = { + /* Re-configure Sensor */ + {REG_CCP2_DATA_FORMAT, ccp2_data_format, 0, + D_LEN_WORD}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL, 128, 0, D_LEN_WORD}, + {REG_PRE_PLL_CLK_DIV, pre_pll_clk_div, 0, D_LEN_WORD}, + {REG_VT_SYS_CLK_DIV, vt_sys_clk_div, 0, D_LEN_WORD}, + {REG_VT_PIX_CLK_DIV, vt_pix_clk_div, 0, D_LEN_WORD}, + {REG_OP_SYS_CLK_DIV, vt_sys_clk_div, 0, D_LEN_WORD}, + {REG_OP_PIX_CLK_DIV, vt_pix_clk_div, 0, D_LEN_WORD}, + {REG_VT_LINE_LENGTH_PCK, vt_line_length_pck, 0, + D_LEN_WORD}, + {REG_X_OUTPUT_SIZE, x_output_size, 0, D_LEN_WORD}, + {REG_Y_OUTPUT_SIZE, y_output_size, 0, D_LEN_WORD}, + {REG_X_ODD_INC, x_odd_inc, 0, D_LEN_WORD}, + {REG_Y_ODD_INC, y_odd_inc, 0, D_LEN_WORD}, + {REG_VT_FRAME_LENGTH_LINES, + vt_frame_length_lines * vb6801_ctrl->factor_fps, 0, + D_LEN_WORD}, + {REG_COARSE_INTEGRATION_TIME, + coarse_integration_time, 0, D_LEN_WORD}, + /* Analogue Settings */ + {REG_ANALOG_TIMING_MODES_2, 0, 132, D_LEN_BYTE}, + {REG_RAMP_SCALE, 0, 5, D_LEN_BYTE}, + {REG_BTL_LEVEL_SETUP, 0, 11, D_LEN_BYTE}, + /* Enable Defect Correction */ + {REG_SCYTHE_ENABLE, 0, 1, D_LEN_BYTE}, + {REG_SCYTHE_WEIGHT, 0, 16, D_LEN_BYTE}, + {REG_BRUCE_ENABLE, 0, 1, D_LEN_BYTE}, + /* Auto Focus Configuration + * Please note that the DAC Code is a written as a + * 16-bit value 0 = infinity (no DAC current) */ + {REG_VCM_DAC_CODE, pinfo->vcm_dac_code, 0, D_LEN_WORD}, + {REG_VCM_DAC_STROBE, 0, 0, D_LEN_BYTE}, + {REG_VCM_DAC_ENABLE, 0, 1, D_LEN_BYTE}, + }; + + rc = vb6801_i2c_write_table(wreg, ARRAY_SIZE(wreg)); + if (rc < 0) { + CDBG("I2C Write Table FAILED!!!\n"); + return rc; + } + } + /* Parallel Interface Configuration */ + if (capture_mode >= 2) { + struct vb6801_i2c_reg_conf_t wreg1[] = { + {REG_OP_CODER_SYNC_CLK_SETUP, 0, 15, D_LEN_BYTE}, + {REG_OP_CODER_ENABLE, 0, 3, D_LEN_BYTE}, + {REG_OP_CODER_SLOW_PAD_EN, 0, 1, D_LEN_BYTE}, + {REG_OP_CODER_AUTOMATIC_MODE_ENABLE, 0, 3, D_LEN_BYTE}, + {REG_OP_CODER_AUTO_STARTUP, 0, 2, D_LEN_BYTE}, + }; + + rc = vb6801_i2c_write_table(wreg1, ARRAY_SIZE(wreg1)); + if (rc < 0) { + CDBG("I2C Write Table FAILED!!!\n"); + return rc; + } + } + + /* Enter Streaming Mode */ + rc = vb6801_i2c_write_b(REG_MODE_SELECT, 1); + if (rc < 0) { + CDBG("I2C Write Table FAILED!!!\n"); + return rc; + } + + /* Wait until the sensor starts streaming + * Poll until the reported frame_count value is != 0xFF */ + frame_count = 0xFF; + timeout = 2000; + while (frame_count == 0xFF && timeout > 0) { + rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); + if (rc < 0) + return rc; + + CDBG("REG_FRAME_COUNT = 0x%x\n", frame_count); + timeout--; + } + + /* Post Streaming Configuration */ + + rc = vb6801_i2c_write_table(wreg2, ARRAY_SIZE(wreg2)); + if (rc < 0) { + CDBG("I2C Write Table FAILED!!!\n"); + return rc; + } + + rc = vb6801_i2c_read_table(rreg, ARRAY_SIZE(rreg)); + if (rc < 0) { + CDBG("I2C Read Table FAILED!!!\n"); + return rc; + } + + CDBG("REG_PRE_PLL_CLK_DIV = 0x%x\n", rreg[0].wdata); + CDBG("REG_PLL_MULTIPLIER = 0x%x\n", rreg[1].wdata); + CDBG("REG_VT_SYS_CLK_DIV = 0x%x\n", rreg[2].wdata); + CDBG("REG_VT_PIX_CLK_DIV = 0x%x\n", rreg[3].wdata); + CDBG("REG_OP_SYS_CLK_DIV = 0x%x\n", rreg[4].wdata); + CDBG("REG_OP_PIX_CLK_DIV = 0x%x\n", rreg[5].wdata); + CDBG("REG_FRAME_COUNT = 0x%x\n", rreg[6].bdata); + + mdelay(50); + frame_count = 0; + rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); + CDBG("REG_FRAME_COUNT1 = 0x%x\n", frame_count); + + mdelay(150); + frame_count = 0; + rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); + CDBG("REG_FRAME_COUNT2 = 0x%x\n", frame_count); + + mdelay(100); + frame_count = 0; + rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); + CDBG("REG_FRAME_COUNT3 = 0x%x\n", frame_count); + + mdelay(250); + frame_count = 0; + rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); + CDBG("REG_FRAME_COUNT4 = 0x%x\n", frame_count); + + return rc; +} + +static int vb6801_sensor_init_done(const struct msm_camera_sensor_info *data) +{ + gpio_direction_output(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + return 0; +} + +static int vb6801_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&vb6801_wait_queue); + return 0; +} + +static int32_t vb6801_video_config(int mode, int res) +{ + int32_t rc = 0; + + vb6801_ctrl->prev_res = res; + vb6801_ctrl->curr_res = res; + vb6801_ctrl->sensormode = mode; + + rc = vb6801_config_sensor(12, 30, 60, 2, 1, 10, 2, RES_PREVIEW); + if (rc < 0) + return rc; + + rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK, + &vb6801_ctrl->s_dynamic_params. + preview_pixelsPerLine, 2); + if (rc < 0) + return rc; + + rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK, + &vb6801_ctrl->s_dynamic_params. + preview_linesPerFrame, 2); + + return rc; +} + +static int32_t vb6801_snapshot_config(int mode, int res) +{ + int32_t rc = 0; + + vb6801_ctrl->curr_res = vb6801_ctrl->pict_res; + vb6801_ctrl->sensormode = mode; + + rc = vb6801_config_sensor(12, 12, 48, 1, 1, 10, 2, RES_CAPTURE); + if (rc < 0) + return rc; + + rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK, + &vb6801_ctrl->s_dynamic_params. + snapshot_pixelsPerLine, 2); + if (rc < 0) + return rc; + + rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK, + &vb6801_ctrl->s_dynamic_params. + snapshot_linesPerFrame, 2); + + return rc; +} + +static int32_t vb6801_set_sensor_mode(int mode, int res) +{ + int32_t rc = 0; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = vb6801_video_config(mode, res); + break; + + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + rc = vb6801_snapshot_config(mode, res); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +int vb6801_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + + if (copy_from_user(&cdata, + (void *)argp, sizeof(struct sensor_cfg_data))) + return -EFAULT; + + mutex_lock(&vb6801_mut); + + CDBG("vb6801_sensor_config, cfgtype = %d\n", cdata.cfgtype); + + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + vb6801_get_pict_fps(cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = vb6801_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = vb6801_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = vb6801_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = vb6801_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = vb6801_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = vb6801_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = vb6801_write_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + rc = vb6801_set_pict_exp_gain(cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = vb6801_set_sensor_mode(cdata.mode, cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = vb6801_power_down(); + break; + + case CFG_MOVE_FOCUS: + rc = vb6801_move_focus(cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = vb6801_set_default_focus(); + break; + + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&vb6801_mut); + + return rc; +} + +static int vb6801_sensor_release(void) +{ + int rc = -EBADF; + + mutex_lock(&vb6801_mut); + + vb6801_power_down(); + vb6801_sensor_init_done(vb6801_ctrl->sensordata); + kfree(vb6801_ctrl); + mutex_unlock(&vb6801_mut); + + return rc; +} + +static int vb6801_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + rc = -ENOTSUPP; + goto probe_failure; + } + + vb6801_sensorw = kzalloc(sizeof(struct vb6801_work_t), GFP_KERNEL); + + if (!vb6801_sensorw) { + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, vb6801_sensorw); + vb6801_init_client(client); + vb6801_client = client; + vb6801_client->addr = vb6801_client->addr >> 1; + + return 0; + +probe_failure: + if (vb6801_sensorw != NULL) { + kfree(vb6801_sensorw); + vb6801_sensorw = NULL; + } + return rc; +} + +static int __exit vb6801_i2c_remove(struct i2c_client *client) +{ + struct vb6801_work_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + vb6801_client = NULL; + kfree(sensorw); + return 0; +} + +static const struct i2c_device_id vb6801_i2c_id[] = { + {"vb6801", 0}, + {} +}; + +static struct i2c_driver vb6801_i2c_driver = { + .id_table = vb6801_i2c_id, + .probe = vb6801_i2c_probe, + .remove = __exit_p(vb6801_i2c_remove), + .driver = { + .name = "vb6801", + }, +}; + +static int vb6801_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int rc; + + struct vb6801_i2c_reg_conf_t rreg[] = { + {0x0000, 0, 0, D_LEN_BYTE}, + {0x0001, 0, 0, D_LEN_BYTE}, + }; + + rc = vb6801_reset(data); + if (rc < 0) + goto init_probe_done; + + mdelay(20); + + rc = vb6801_i2c_read_table(rreg, ARRAY_SIZE(rreg)); + if (rc < 0) { + CDBG("I2C Read Table FAILED!!!\n"); + goto init_probe_fail; + } + + /* 4. Compare sensor ID to VB6801 ID: */ + if (rreg[0].bdata != 0x03 || rreg[1].bdata != 0x53) { + CDBG("vb6801_sensor_init: sensor ID don't match!\n"); + goto init_probe_fail; + } + + goto init_probe_done; + +init_probe_fail: + vb6801_sensor_init_done(data); +init_probe_done: + return rc; +} + +int vb6801_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + int32_t rc; + struct vb6801_i2c_reg_conf_t wreg[] = { + {REG_MODE_SELECT, 0, STANDBY_MODE, D_LEN_BYTE}, + {0x0113, 0, 0x0A, D_LEN_BYTE}, + }; + + vb6801_ctrl = kzalloc(sizeof(struct vb6801_ctrl_t), GFP_KERNEL); + if (!vb6801_ctrl) { + rc = -ENOMEM; + goto open_init_fail1; + } + + vb6801_ctrl->factor_fps = 1 /** 0x00000400*/ ; + vb6801_ctrl->curr_fps = 7680; /* 30 * Q8 */ ; + vb6801_ctrl->max_fps = 7680; /* 30 * Q8 */ ; + vb6801_ctrl->pict_exp_update = 0; /* 30 * Q8 */ ; + vb6801_ctrl->reducel = 0; /* 30 * Q8 */ ; + + vb6801_ctrl->set_test = TEST_OFF; + vb6801_ctrl->prev_res = QTR_SIZE; + vb6801_ctrl->pict_res = FULL_SIZE; + + vb6801_ctrl->s_dynamic_params.preview_linesPerFrame = + VB6801_LINES_PER_FRAME_PREVIEW; + vb6801_ctrl->s_dynamic_params.preview_pixelsPerLine = + VB6801_PIXELS_PER_LINE_PREVIEW; + vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame = + VB6801_LINES_PER_FRAME_SNAPSHOT; + vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine = + VB6801_PIXELS_PER_LINE_SNAPSHOT; + + if (data) + vb6801_ctrl->sensordata = data; + + /* enable mclk first */ + msm_camio_clk_rate_set(VB6801_DEFAULT_CLOCK_RATE); + mdelay(20); + + rc = vb6801_reset(data); + if (rc < 0) + goto open_init_fail1; + + rc = vb6801_i2c_write_table(wreg, ARRAY_SIZE(wreg)); + if (rc < 0) { + CDBG("I2C Write Table FAILED!!!\n"); + goto open_init_fail2; + } + + rc = vb6801_read_nvm_data(&vb6801_ctrl->s_info); + if (rc < 0) { + CDBG("vb6801_read_nvm_data FAILED!!!\n"); + goto open_init_fail2; + } + mdelay(66); + + rc = vb6801_config_sensor(12, 30, 60, 2, 1, 10, 2, RES_PREVIEW); + if (rc < 0) + goto open_init_fail2; + + goto open_init_done; + +open_init_fail2: + vb6801_sensor_init_done(data); +open_init_fail1: + kfree(vb6801_ctrl); +open_init_done: + return rc; +} + +static int vb6801_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = i2c_add_driver(&vb6801_i2c_driver); + if (rc < 0 || vb6801_client == NULL) { + rc = -ENOTSUPP; + goto probe_done; + } + + /* enable mclk first */ + msm_camio_clk_rate_set(VB6801_DEFAULT_CLOCK_RATE); + mdelay(20); + + rc = vb6801_probe_init_sensor(info); + if (rc < 0) + goto probe_done; + + s->s_init = vb6801_sensor_open_init; + s->s_release = vb6801_sensor_release; + s->s_config = vb6801_sensor_config; + s->s_mount_angle = 0; + vb6801_sensor_init_done(info); + +probe_done: + return rc; +} + +static int __vb6801_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, vb6801_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __vb6801_probe, + .driver = { + .name = "msm_camera_vb6801", + .owner = THIS_MODULE, + }, +}; + +static int __init vb6801_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(vb6801_init); +void vb6801_exit(void) +{ + i2c_del_driver(&vb6801_i2c_driver); +} diff --git a/drivers/media/video/msm_zsl/vb6801.h b/drivers/media/video/msm_zsl/vb6801.h new file mode 100644 index 00000000000..8248f8d97e0 --- /dev/null +++ b/drivers/media/video/msm_zsl/vb6801.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef VB6801_H +#define VB6801_H + +#include + +extern struct vb6801_reg_t vb6801_regs; /* from vb6801_reg.c */ + +struct reg_struct { + uint16_t vt_pix_clk_div; /* 0x0300 */ + uint16_t vt_sys_clk_div; /* 0x0302 */ + uint16_t pre_pll_clk_div; /* 0x0304 */ + uint16_t pll_multiplier; /* 0x0306 */ + uint16_t op_pix_clk_div; /* 0x0308 */ + uint16_t op_sys_clk_div; /* 0x030A */ + uint16_t scale_m; /* 0x0404 */ + uint16_t row_speed; /* 0x3016 */ + uint16_t x_addr_start; /* 0x3004 */ + uint16_t x_addr_end; /* 0x3008 */ + uint16_t y_addr_start; /* 0x3002 */ + uint16_t y_addr_end; /* 0x3006 */ + uint16_t read_mode; /* 0x3040 */ + uint16_t x_output_size; /* 0x034C */ + uint16_t y_output_size; /* 0x034E */ + uint16_t line_length_pck; /* 0x300C */ + uint16_t frame_length_lines; /* 0x300A */ + uint16_t coarse_int_time; /* 0x3012 */ + uint16_t fine_int_time; /* 0x3014 */ +}; + +enum i2c_data_len { + D_LEN_BYTE, + D_LEN_WORD +}; + +struct vb6801_i2c_reg_conf_t { + unsigned short waddr; + unsigned short wdata; + uint8_t bdata; + enum i2c_data_len dlen; +}; + +struct vb6801_reg_t { + struct reg_struct const *reg_pat; + uint16_t reg_pat_size; + struct vb6801_i2c_reg_conf_t const *ttbl; + uint16_t ttbl_size; + struct vb6801_i2c_reg_conf_t const *lctbl; + uint16_t lctbl_size; + struct vb6801_i2c_reg_conf_t const *rftbl; + uint16_t rftbl_size; +}; + +#endif /* VB6801_H */ diff --git a/drivers/media/video/msm_zsl/vx6953.c b/drivers/media/video/msm_zsl/vx6953.c new file mode 100644 index 00000000000..08b1593a22a --- /dev/null +++ b/drivers/media/video/msm_zsl/vx6953.c @@ -0,0 +1,3664 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vx6953.h" + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ + +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD_OFF 0x00 +#define GROUPED_PARAMETER_HOLD 0x01 +#define REG_MODE_SELECT 0x0100 +#define MODE_SELECT_STANDBY_MODE 0x00 +#define MODE_SELECT_STREAM 0x01 +/* Integration Time */ +#define REG_COARSE_INTEGRATION_TIME_HI 0x0202 +#define REG_COARSE_INTEGRATION_TIME_LO 0x0203 +/* Gain */ +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204 +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205 +/* Digital Gain */ +#define REG_DIGITAL_GAIN_GREEN_R_HI 0x020E +#define REG_DIGITAL_GAIN_GREEN_R_LO 0x020F +#define REG_DIGITAL_GAIN_RED_HI 0x0210 +#define REG_DIGITAL_GAIN_RED_LO 0x0211 +#define REG_DIGITAL_GAIN_BLUE_HI 0x0212 +#define REG_DIGITAL_GAIN_BLUE_LO 0x0213 +#define REG_DIGITAL_GAIN_GREEN_B_HI 0x0214 +#define REG_DIGITAL_GAIN_GREEN_B_LO 0x0215 +/* output bits setting */ +#define REG_0x0112 0x0112 +#define REG_0x0113 0x0113 +/* PLL registers */ +#define REG_VT_PIX_CLK_DIV 0x0301 +#define REG_PRE_PLL_CLK_DIV 0x0305 +#define REG_PLL_MULTIPLIER 0x0307 +#define REG_OP_PIX_CLK_DIV 0x0309 +#define REG_0x034c 0x034c +#define REG_0x034d 0x034d +#define REG_0x034e 0x034e +#define REG_0x034f 0x034f +#define REG_0x0387 0x0387 +#define REG_0x0383 0x0383 +#define REG_FRAME_LENGTH_LINES_HI 0x0340 +#define REG_FRAME_LENGTH_LINES_LO 0x0341 +#define REG_LINE_LENGTH_PCK_HI 0x0342 +#define REG_LINE_LENGTH_PCK_LO 0x0343 +#define REG_0x3030 0x3030 +#define REG_0x0111 0x0111 +#define REG_0x0136 0x0136 +#define REG_0x0137 0x0137 +#define REG_0x0b00 0x0b00 +#define REG_0x3001 0x3001 +#define REG_0x3004 0x3004 +#define REG_0x3007 0x3007 +#define REG_0x301a 0x301a +#define REG_0x3101 0x3101 +#define REG_0x3364 0x3364 +#define REG_0x3365 0x3365 +#define REG_0x0b83 0x0b83 +#define REG_0x0b84 0x0b84 +#define REG_0x0b85 0x0b85 +#define REG_0x0b88 0x0b88 +#define REG_0x0b89 0x0b89 +#define REG_0x0b8a 0x0b8a +#define REG_0x3005 0x3005 +#define REG_0x3010 0x3010 +#define REG_0x3036 0x3036 +#define REG_0x3041 0x3041 +#define REG_0x0b80 0x0b80 +#define REG_0x0900 0x0900 +#define REG_0x0901 0x0901 +#define REG_0x0902 0x0902 +#define REG_0x3016 0x3016 +#define REG_0x301d 0x301d +#define REG_0x317e 0x317e +#define REG_0x317f 0x317f +#define REG_0x3400 0x3400 +#define REG_0x303a 0x303a +#define REG_0x1716 0x1716 +#define REG_0x1717 0x1717 +#define REG_0x1718 0x1718 +#define REG_0x1719 0x1719 +#define REG_0x3006 0x3006 +#define REG_0x301b 0x301b +#define REG_0x3098 0x3098 +#define REG_0x309d 0x309d +#define REG_0x3011 0x3011 +#define REG_0x3035 0x3035 +#define REG_0x3045 0x3045 +#define REG_0x3210 0x3210 +#define REG_0x0111 0x0111 +#define REG_0x3410 0x3410 +#define REG_0x0b06 0x0b06 +#define REG_0x0b07 0x0b07 +#define REG_0x0b08 0x0b08 +#define REG_0x0b09 0x0b09 +#define REG_0x3640 0x3640 +/* Test Pattern */ +#define REG_TEST_PATTERN_MODE 0x0601 + +/*============================================================================ + TYPE DECLARATIONS +============================================================================*/ + +/* 16bit address - 8 bit context register structure */ +#define VX6953_STM5M0EDOF_OFFSET 9 +#define Q8 0x00000100 +#define Q10 0x00000400 +#define VX6953_STM5M0EDOF_MAX_SNAPSHOT_EXPOSURE_LINE_COUNT 2922 +#define VX6953_STM5M0EDOF_DEFAULT_MASTER_CLK_RATE 24000000 +#define VX6953_STM5M0EDOF_OP_PIXEL_CLOCK_RATE 79800000 +#define VX6953_STM5M0EDOF_VT_PIXEL_CLOCK_RATE 88670000 +/* Full Size */ +#define VX6953_FULL_SIZE_WIDTH 2608 +#define VX6953_FULL_SIZE_HEIGHT 1960 +#define VX6953_FULL_SIZE_DUMMY_PIXELS 1 +#define VX6953_FULL_SIZE_DUMMY_LINES 0 +/* Quarter Size */ +#define VX6953_QTR_SIZE_WIDTH 1304 +#define VX6953_QTR_SIZE_HEIGHT 980 +#define VX6953_QTR_SIZE_DUMMY_PIXELS 1 +#define VX6953_QTR_SIZE_DUMMY_LINES 0 +/* Blanking as measured on the scope */ +/* Full Size */ +#define VX6953_HRZ_FULL_BLK_PIXELS 348 +#define VX6953_VER_FULL_BLK_LINES 40 +/* Quarter Size */ +#define VX6953_HRZ_QTR_BLK_PIXELS 1628 +#define VX6953_VER_QTR_BLK_LINES 28 +#define MAX_LINE_LENGTH_PCK 8190 +#define MAX_FRAME_LENGTH_LINES 16383 +#define VX6953_REVISION_NUMBER_CUT2 0x10/*revision number for Cut2.0*/ +#define VX6953_REVISION_NUMBER_CUT3 0x20/*revision number for Cut3.0*/ +/* FIXME: Changes from here */ +struct vx6953_work_t { + struct work_struct work; +}; + +static struct vx6953_work_t *vx6953_sensorw; +static struct i2c_client *vx6953_client; + +struct vx6953_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + + uint32_t sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + uint16_t fps; + + int16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + + enum vx6953_resolution_t prev_res; + enum vx6953_resolution_t pict_res; + enum vx6953_resolution_t curr_res; + enum vx6953_test_mode_t set_test; + enum sensor_revision_t sensor_type; + + enum edof_mode_t edof_mode; + + unsigned short imgaddr; +}; + + +static uint8_t vx6953_stm5m0edof_delay_msecs_stdby; +static uint16_t vx6953_stm5m0edof_delay_msecs_stream = 20; +static uint8_t count; +static struct vx6953_ctrl_t *vx6953_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(vx6953_wait_queue); +DEFINE_MUTEX(vx6953_mut); +static struct vx6953_i2c_reg_conf patch_tbl_cut2[] = { + {0xFB94, 0}, /*intialise Data Xfer Status reg*/ + {0xFB95, 0}, /*gain 1 (0x00)*/ + {0xFB96, 0}, /*gain 1.07 (0x10)*/ + {0xFB97, 0}, /*gain 1.14 (0x20)*/ + {0xFB98, 0}, /*gain 1.23 (0x30)*/ + {0xFB99, 0}, /*gain 1.33 (0x40)*/ + {0xFB9A, 0}, /*gain 1.45 (0x50)*/ + {0xFB9B, 0}, /*gain 1.6 (0x60)*/ + {0xFB9C, 0}, /*gain 1.78 (0x70)*/ + {0xFB9D, 2}, /*gain 2 (0x80)*/ + {0xFB9E, 2}, /*gain 2.29 (0x90)*/ + {0xFB9F, 3}, /*gain 2.67 (0xA0)*/ + {0xFBA0, 3}, /*gain 3.2 (0xB0)*/ + {0xFBA1, 4}, /*gain 4 (0xC0)*/ + {0xFBA2, 7}, /*gain 5.33 (0xD0)*/ + {0xFBA3, 10}, /*gain 8 (0xE0)*/ + {0xFBA4, 11}, /*gain 9.14 (0xE4)*/ + {0xFBA5, 13}, /*gain 10.67 (0xE8)*/ + {0xFBA6, 15}, /*gain 12.8 (0xEC)*/ + {0xFBA7, 19}, /*gain 16 (0xF0)*/ + {0xF800, 0x12}, + {0xF801, 0x06}, + {0xF802, 0xf7}, + {0xF803, 0x90}, + {0xF804, 0x02}, + {0xF805, 0x05}, + {0xF806, 0xe0}, + {0xF807, 0xff}, + {0xF808, 0x65}, + {0xF809, 0x7d}, + {0xF80A, 0x70}, + {0xF80B, 0x03}, + {0xF80C, 0x02}, + {0xF80D, 0xf9}, + {0xF80E, 0x1c}, + {0xF80F, 0x8f}, + {0xF810, 0x7d}, + {0xF811, 0xe4}, + {0xF812, 0xf5}, + {0xF813, 0x7a}, + {0xF814, 0x75}, + {0xF815, 0x78}, + {0xF816, 0x30}, + {0xF817, 0x75}, + {0xF818, 0x79}, + {0xF819, 0x53}, + {0xF81A, 0x85}, + {0xF81B, 0x79}, + {0xF81C, 0x82}, + {0xF81D, 0x85}, + {0xF81E, 0x78}, + {0xF81F, 0x83}, + {0xF820, 0xe0}, + {0xF821, 0xc3}, + {0xF822, 0x95}, + {0xF823, 0x7b}, + {0xF824, 0xf0}, + {0xF825, 0x74}, + {0xF826, 0x02}, + {0xF827, 0x25}, + {0xF828, 0x79}, + {0xF829, 0xf5}, + {0xF82A, 0x79}, + {0xF82B, 0xe4}, + {0xF82C, 0x35}, + {0xF82D, 0x78}, + {0xF82E, 0xf5}, + {0xF82F, 0x78}, + {0xF830, 0x05}, + {0xF831, 0x7a}, + {0xF832, 0xe5}, + {0xF833, 0x7a}, + {0xF834, 0xb4}, + {0xF835, 0x08}, + {0xF836, 0xe3}, + {0xF837, 0xe5}, + {0xF838, 0x7d}, + {0xF839, 0x70}, + {0xF83A, 0x04}, + {0xF83B, 0xff}, + {0xF83C, 0x02}, + {0xF83D, 0xf8}, + {0xF83E, 0xe4}, + {0xF83F, 0xe5}, + {0xF840, 0x7d}, + {0xF841, 0xb4}, + {0xF842, 0x10}, + {0xF843, 0x05}, + {0xF844, 0x7f}, + {0xF845, 0x01}, + {0xF846, 0x02}, + {0xF847, 0xf8}, + {0xF848, 0xe4}, + {0xF849, 0xe5}, + {0xF84A, 0x7d}, + {0xF84B, 0xb4}, + {0xF84C, 0x20}, + {0xF84D, 0x05}, + {0xF84E, 0x7f}, + {0xF84F, 0x02}, + {0xF850, 0x02}, + {0xF851, 0xf8}, + {0xF852, 0xe4}, + {0xF853, 0xe5}, + {0xF854, 0x7d}, + {0xF855, 0xb4}, + {0xF856, 0x30}, + {0xF857, 0x05}, + {0xF858, 0x7f}, + {0xF859, 0x03}, + {0xF85A, 0x02}, + {0xF85B, 0xf8}, + {0xF85C, 0xe4}, + {0xF85D, 0xe5}, + {0xF85E, 0x7d}, + {0xF85F, 0xb4}, + {0xF860, 0x40}, + {0xF861, 0x04}, + {0xF862, 0x7f}, + {0xF863, 0x04}, + {0xF864, 0x80}, + {0xF865, 0x7e}, + {0xF866, 0xe5}, + {0xF867, 0x7d}, + {0xF868, 0xb4}, + {0xF869, 0x50}, + {0xF86A, 0x04}, + {0xF86B, 0x7f}, + {0xF86C, 0x05}, + {0xF86D, 0x80}, + {0xF86E, 0x75}, + {0xF86F, 0xe5}, + {0xF870, 0x7d}, + {0xF871, 0xb4}, + {0xF872, 0x60}, + {0xF873, 0x04}, + {0xF874, 0x7f}, + {0xF875, 0x06}, + {0xF876, 0x80}, + {0xF877, 0x6c}, + {0xF878, 0xe5}, + {0xF879, 0x7d}, + {0xF87A, 0xb4}, + {0xF87B, 0x70}, + {0xF87C, 0x04}, + {0xF87D, 0x7f}, + {0xF87E, 0x07}, + {0xF87F, 0x80}, + {0xF880, 0x63}, + {0xF881, 0xe5}, + {0xF882, 0x7d}, + {0xF883, 0xb4}, + {0xF884, 0x80}, + {0xF885, 0x04}, + {0xF886, 0x7f}, + {0xF887, 0x08}, + {0xF888, 0x80}, + {0xF889, 0x5a}, + {0xF88A, 0xe5}, + {0xF88B, 0x7d}, + {0xF88C, 0xb4}, + {0xF88D, 0x90}, + {0xF88E, 0x04}, + {0xF88F, 0x7f}, + {0xF890, 0x09}, + {0xF891, 0x80}, + {0xF892, 0x51}, + {0xF893, 0xe5}, + {0xF894, 0x7d}, + {0xF895, 0xb4}, + {0xF896, 0xa0}, + {0xF897, 0x04}, + {0xF898, 0x7f}, + {0xF899, 0x0a}, + {0xF89A, 0x80}, + {0xF89B, 0x48}, + {0xF89C, 0xe5}, + {0xF89D, 0x7d}, + {0xF89E, 0xb4}, + {0xF89F, 0xb0}, + {0xF8A0, 0x04}, + {0xF8A1, 0x7f}, + {0xF8A2, 0x0b}, + {0xF8A3, 0x80}, + {0xF8A4, 0x3f}, + {0xF8A5, 0xe5}, + {0xF8A6, 0x7d}, + {0xF8A7, 0xb4}, + {0xF8A8, 0xc0}, + {0xF8A9, 0x04}, + {0xF8AA, 0x7f}, + {0xF8AB, 0x0c}, + {0xF8AC, 0x80}, + {0xF8AD, 0x36}, + {0xF8AE, 0xe5}, + {0xF8AF, 0x7d}, + {0xF8B0, 0xb4}, + {0xF8B1, 0xd0}, + {0xF8B2, 0x04}, + {0xF8B3, 0x7f}, + {0xF8B4, 0x0d}, + {0xF8B5, 0x80}, + {0xF8B6, 0x2d}, + {0xF8B7, 0xe5}, + {0xF8B8, 0x7d}, + {0xF8B9, 0xb4}, + {0xF8BA, 0xe0}, + {0xF8BB, 0x04}, + {0xF8BC, 0x7f}, + {0xF8BD, 0x0e}, + {0xF8BE, 0x80}, + {0xF8BF, 0x24}, + {0xF8C0, 0xe5}, + {0xF8C1, 0x7d}, + {0xF8C2, 0xb4}, + {0xF8C3, 0xe4}, + {0xF8C4, 0x04}, + {0xF8C5, 0x7f}, + {0xF8C6, 0x0f}, + {0xF8C7, 0x80}, + {0xF8C8, 0x1b}, + {0xF8C9, 0xe5}, + {0xF8CA, 0x7d}, + {0xF8CB, 0xb4}, + {0xF8CC, 0xe8}, + {0xF8CD, 0x04}, + {0xF8CE, 0x7f}, + {0xF8CF, 0x10}, + {0xF8D0, 0x80}, + {0xF8D1, 0x12}, + {0xF8D2, 0xe5}, + {0xF8D3, 0x7d}, + {0xF8D4, 0xb4}, + {0xF8D5, 0xec}, + {0xF8D6, 0x04}, + {0xF8D7, 0x7f}, + {0xF8D8, 0x11}, + {0xF8D9, 0x80}, + {0xF8DA, 0x09}, + {0xF8DB, 0xe5}, + {0xF8DC, 0x7d}, + {0xF8DD, 0x7f}, + {0xF8DE, 0x00}, + {0xF8DF, 0xb4}, + {0xF8E0, 0xf0}, + {0xF8E1, 0x02}, + {0xF8E2, 0x7f}, + {0xF8E3, 0x12}, + {0xF8E4, 0x8f}, + {0xF8E5, 0x7c}, + {0xF8E6, 0xef}, + {0xF8E7, 0x24}, + {0xF8E8, 0x95}, + {0xF8E9, 0xff}, + {0xF8EA, 0xe4}, + {0xF8EB, 0x34}, + {0xF8EC, 0xfb}, + {0xF8ED, 0x8f}, + {0xF8EE, 0x82}, + {0xF8EF, 0xf5}, + {0xF8F0, 0x83}, + {0xF8F1, 0xe4}, + {0xF8F2, 0x93}, + {0xF8F3, 0xf5}, + {0xF8F4, 0x7c}, + {0xF8F5, 0xf5}, + {0xF8F6, 0x7b}, + {0xF8F7, 0xe4}, + {0xF8F8, 0xf5}, + {0xF8F9, 0x7a}, + {0xF8FA, 0x75}, + {0xF8FB, 0x78}, + {0xF8FC, 0x30}, + {0xF8FD, 0x75}, + {0xF8FE, 0x79}, + {0xF8FF, 0x53}, + {0xF900, 0x85}, + {0xF901, 0x79}, + {0xF902, 0x82}, + {0xF903, 0x85}, + {0xF904, 0x78}, + {0xF905, 0x83}, + {0xF906, 0xe0}, + {0xF907, 0x25}, + {0xF908, 0x7c}, + {0xF909, 0xf0}, + {0xF90A, 0x74}, + {0xF90B, 0x02}, + {0xF90C, 0x25}, + {0xF90D, 0x79}, + {0xF90E, 0xf5}, + {0xF90F, 0x79}, + {0xF910, 0xe4}, + {0xF911, 0x35}, + {0xF912, 0x78}, + {0xF913, 0xf5}, + {0xF914, 0x78}, + {0xF915, 0x05}, + {0xF916, 0x7a}, + {0xF917, 0xe5}, + {0xF918, 0x7a}, + {0xF919, 0xb4}, + {0xF91A, 0x08}, + {0xF91B, 0xe4}, + {0xF91C, 0x02}, + {0xF91D, 0x18}, + {0xF91E, 0x32}, + {0xF91F, 0x22}, + {0xF920, 0xf0}, + {0xF921, 0x90}, + {0xF922, 0xa0}, + {0xF923, 0xf8}, + {0xF924, 0xe0}, + {0xF925, 0x70}, + {0xF926, 0x02}, + {0xF927, 0xa3}, + {0xF928, 0xe0}, + {0xF929, 0x70}, + {0xF92A, 0x0a}, + {0xF92B, 0x90}, + {0xF92C, 0xa1}, + {0xF92D, 0x10}, + {0xF92E, 0xe0}, + {0xF92F, 0xfe}, + {0xF930, 0xa3}, + {0xF931, 0xe0}, + {0xF932, 0xff}, + {0xF933, 0x80}, + {0xF934, 0x04}, + {0xF935, 0x7e}, + {0xF936, 0x00}, + {0xF937, 0x7f}, + {0xF938, 0x00}, + {0xF939, 0x8e}, + {0xF93A, 0x7e}, + {0xF93B, 0x8f}, + {0xF93C, 0x7f}, + {0xF93D, 0x90}, + {0xF93E, 0x36}, + {0xF93F, 0x0d}, + {0xF940, 0xe0}, + {0xF941, 0x44}, + {0xF942, 0x02}, + {0xF943, 0xf0}, + {0xF944, 0x90}, + {0xF945, 0x36}, + {0xF946, 0x0e}, + {0xF947, 0xe5}, + {0xF948, 0x7e}, + {0xF949, 0xf0}, + {0xF94A, 0xa3}, + {0xF94B, 0xe5}, + {0xF94C, 0x7f}, + {0xF94D, 0xf0}, + {0xF94E, 0xe5}, + {0xF94F, 0x3a}, + {0xF950, 0x60}, + {0xF951, 0x0c}, + {0xF952, 0x90}, + {0xF953, 0x36}, + {0xF954, 0x09}, + {0xF955, 0xe0}, + {0xF956, 0x70}, + {0xF957, 0x06}, + {0xF958, 0x90}, + {0xF959, 0x36}, + {0xF95A, 0x08}, + {0xF95B, 0xf0}, + {0xF95C, 0xf5}, + {0xF95D, 0x3a}, + {0xF95E, 0x02}, + {0xF95F, 0x03}, + {0xF960, 0x94}, + {0xF961, 0x22}, + {0xF962, 0x78}, + {0xF963, 0x07}, + {0xF964, 0xe6}, + {0xF965, 0xd3}, + {0xF966, 0x94}, + {0xF967, 0x00}, + {0xF968, 0x40}, + {0xF969, 0x16}, + {0xF96A, 0x16}, + {0xF96B, 0xe6}, + {0xF96C, 0x90}, + {0xF96D, 0x30}, + {0xF96E, 0xa1}, + {0xF96F, 0xf0}, + {0xF970, 0x90}, + {0xF971, 0x43}, + {0xF972, 0x83}, + {0xF973, 0xe0}, + {0xF974, 0xb4}, + {0xF975, 0x01}, + {0xF976, 0x0f}, + {0xF977, 0x90}, + {0xF978, 0x43}, + {0xF979, 0x87}, + {0xF97A, 0xe0}, + {0xF97B, 0xb4}, + {0xF97C, 0x01}, + {0xF97D, 0x08}, + {0xF97E, 0x80}, + {0xF97F, 0x00}, + {0xF980, 0x90}, + {0xF981, 0x30}, + {0xF982, 0xa0}, + {0xF983, 0x74}, + {0xF984, 0x01}, + {0xF985, 0xf0}, + {0xF986, 0x22}, + {0xF987, 0xf0}, + {0xF988, 0x90}, + {0xF989, 0x35}, + {0xF98A, 0xba}, + {0xF98B, 0xe0}, + {0xF98C, 0xb4}, + {0xF98D, 0x0a}, + {0xF98E, 0x0d}, + {0xF98F, 0xa3}, + {0xF990, 0xe0}, + {0xF991, 0xb4}, + {0xF992, 0x01}, + {0xF993, 0x08}, + {0xF994, 0x90}, + {0xF995, 0xfb}, + {0xF996, 0x94}, + {0xF997, 0xe0}, + {0xF998, 0x90}, + {0xF999, 0x35}, + {0xF99A, 0xb8}, + {0xF99B, 0xf0}, + {0xF99C, 0xd0}, + {0xF99D, 0xd0}, + {0xF99E, 0xd0}, + {0xF99F, 0x82}, + {0xF9A0, 0xd0}, + {0xF9A1, 0x83}, + {0xF9A2, 0xd0}, + {0xF9A3, 0xe0}, + {0xF9A4, 0x32}, + {0xF9A5, 0x22}, + {0xF9A6, 0xe5}, + {0xF9A7, 0x7f}, + {0xF9A8, 0x45}, + {0xF9A9, 0x7e}, + {0xF9AA, 0x60}, + {0xF9AB, 0x15}, + {0xF9AC, 0x90}, + {0xF9AD, 0x01}, + {0xF9AE, 0x00}, + {0xF9AF, 0xe0}, + {0xF9B0, 0x70}, + {0xF9B1, 0x0f}, + {0xF9B2, 0x90}, + {0xF9B3, 0xa0}, + {0xF9B4, 0xf8}, + {0xF9B5, 0xe5}, + {0xF9B6, 0x7e}, + {0xF9B7, 0xf0}, + {0xF9B8, 0xa3}, + {0xF9B9, 0xe5}, + {0xF9BA, 0x7f}, + {0xF9BB, 0xf0}, + {0xF9BC, 0xe4}, + {0xF9BD, 0xf5}, + {0xF9BE, 0x7e}, + {0xF9BF, 0xf5}, + {0xF9C0, 0x7f}, + {0xF9C1, 0x22}, + {0xF9C2, 0x02}, + {0xF9C3, 0x0e}, + {0xF9C4, 0x79}, + {0xF9C5, 0x22}, + /* Offsets:*/ + {0x35C6, 0x00},/* FIDDLEDARKCAL*/ + {0x35C7, 0x00}, + {0x35C8, 0x01},/*STOREDISTANCEATSTOPSTREAMING*/ + {0x35C9, 0x20}, + {0x35CA, 0x01},/*BRUCEFIX*/ + {0x35CB, 0x62}, + {0x35CC, 0x01},/*FIXDATAXFERSTATUSREG*/ + {0x35CD, 0x87}, + {0x35CE, 0x01},/*FOCUSDISTANCEUPDATE*/ + {0x35CF, 0xA6}, + {0x35D0, 0x01},/*SKIPEDOFRESET*/ + {0x35D1, 0xC2}, + {0x35D2, 0x00}, + {0x35D3, 0xFB}, + {0x35D4, 0x00}, + {0x35D5, 0x94}, + {0x35D6, 0x00}, + {0x35D7, 0xFB}, + {0x35D8, 0x00}, + {0x35D9, 0x94}, + {0x35DA, 0x00}, + {0x35DB, 0xFB}, + {0x35DC, 0x00}, + {0x35DD, 0x94}, + {0x35DE, 0x00}, + {0x35DF, 0xFB}, + {0x35E0, 0x00}, + {0x35E1, 0x94}, + {0x35E6, 0x18},/* FIDDLEDARKCAL*/ + {0x35E7, 0x2F}, + {0x35E8, 0x03},/* STOREDISTANCEATSTOPSTREAMING*/ + {0x35E9, 0x93}, + {0x35EA, 0x18},/* BRUCEFIX*/ + {0x35EB, 0x99}, + {0x35EC, 0x00},/* FIXDATAXFERSTATUSREG*/ + {0x35ED, 0xA3}, + {0x35EE, 0x21},/* FOCUSDISTANCEUPDATE*/ + {0x35EF, 0x5B}, + {0x35F0, 0x0E},/* SKIPEDOFRESET*/ + {0x35F1, 0x74}, + {0x35F2, 0x04}, + {0x35F3, 0x64}, + {0x35F4, 0x04}, + {0x35F5, 0x65}, + {0x35F6, 0x04}, + {0x35F7, 0x7B}, + {0x35F8, 0x04}, + {0x35F9, 0x7C}, + {0x35FA, 0x04}, + {0x35FB, 0xDD}, + {0x35FC, 0x04}, + {0x35FD, 0xDE}, + {0x35FE, 0x04}, + {0x35FF, 0xEF}, + {0x3600, 0x04}, + {0x3601, 0xF0}, + /*Jump/Data:*/ + {0x35C2, 0x3F},/* Jump Reg*/ + {0x35C3, 0xFF},/* Jump Reg*/ + {0x35C4, 0x3F},/* Data Reg*/ + {0x35C5, 0xC0},/* Data Reg*/ + {0x35C0, 0x01},/* Enable*/ + +}; + +static struct vx6953_i2c_reg_conf cut3_cali_data[] = { + {0x360A, 0x07 }, + {0x3530, 0x07 }, + {0x35B5, 0x00 }, + {0x35BC, 0x00 }, + {0xAFF8, 0x00 }, + {0xAFF9, 0x01 }, + {0xF800, 0x90 }, + {0xF801, 0x30 }, + {0xF802, 0x31 }, + {0xF803, 0xe0 }, + {0xF804, 0xf5 }, + {0xF805, 0x7d }, + {0xF806, 0xb4 }, + {0xF807, 0x01 }, + {0xF808, 0x06 }, + {0xF809, 0x75 }, + {0xF80A, 0x7d }, + {0xF80B, 0x03 }, + {0xF80C, 0x74 }, + {0xF80D, 0x03 }, + {0xF80E, 0xf0 }, + {0xF80F, 0x90 }, + {0xF810, 0x30 }, + {0xF811, 0x04 }, + {0xF812, 0x74 }, + {0xF813, 0x33 }, + {0xF814, 0xf0 }, + {0xF815, 0x90 }, + {0xF816, 0x30 }, + {0xF817, 0x06 }, + {0xF818, 0xe4 }, + {0xF819, 0xf0 }, + {0xF81A, 0xa3 }, + {0xF81B, 0x74 }, + {0xF81C, 0x08 }, + {0xF81D, 0xf0 }, + {0xF81E, 0x90 }, + {0xF81F, 0x30 }, + {0xF820, 0x10 }, + {0xF821, 0xe4 }, + {0xF822, 0xf0 }, + {0xF823, 0xa3 }, + {0xF824, 0xf0 }, + {0xF825, 0x90 }, + {0xF826, 0x30 }, + {0xF827, 0x16 }, + {0xF828, 0x74 }, + {0xF829, 0x1e }, + {0xF82A, 0xf0 }, + {0xF82B, 0x90 }, + {0xF82C, 0x30 }, + {0xF82D, 0x1a }, + {0xF82E, 0x74 }, + {0xF82F, 0x6a }, + {0xF830, 0xf0 }, + {0xF831, 0x90 }, + {0xF832, 0x30 }, + {0xF833, 0x30 }, + {0xF834, 0x74 }, + {0xF835, 0x08 }, + {0xF836, 0xf0 }, + {0xF837, 0x90 }, + {0xF838, 0x30 }, + {0xF839, 0x36 }, + {0xF83A, 0x74 }, + {0xF83B, 0x2c }, + {0xF83C, 0xf0 }, + {0xF83D, 0x90 }, + {0xF83E, 0x30 }, + {0xF83F, 0x41 }, + {0xF840, 0xe4 }, + {0xF841, 0xf0 }, + {0xF842, 0xa3 }, + {0xF843, 0x74 }, + {0xF844, 0x24 }, + {0xF845, 0xf0 }, + {0xF846, 0x90 }, + {0xF847, 0x30 }, + {0xF848, 0x45 }, + {0xF849, 0x74 }, + {0xF84A, 0x81 }, + {0xF84B, 0xf0 }, + {0xF84C, 0x90 }, + {0xF84D, 0x30 }, + {0xF84E, 0x98 }, + {0xF84F, 0x74 }, + {0xF850, 0x01 }, + {0xF851, 0xf0 }, + {0xF852, 0x90 }, + {0xF853, 0x30 }, + {0xF854, 0x9d }, + {0xF855, 0x74 }, + {0xF856, 0x05 }, + {0xF857, 0xf0 }, + {0xF858, 0xe5 }, + {0xF859, 0x7d }, + {0xF85A, 0x70 }, + {0xF85B, 0x22 }, + {0xF85C, 0x90 }, + {0xF85D, 0x02 }, + {0xF85E, 0x00 }, + {0xF85F, 0x74 }, + {0xF860, 0x02 }, + {0xF861, 0xf0 }, + {0xF862, 0xa3 }, + {0xF863, 0x74 }, + {0xF864, 0x54 }, + {0xF865, 0xf0 }, + {0xF866, 0x90 }, + {0xF867, 0x30 }, + {0xF868, 0x05 }, + {0xF869, 0x74 }, + {0xF86A, 0x01 }, + {0xF86B, 0xf0 }, + {0xF86C, 0x90 }, + {0xF86D, 0x30 }, + {0xF86E, 0x1b }, + {0xF86F, 0x74 }, + {0xF870, 0x29 }, + {0xF871, 0xf0 }, + {0xF872, 0x90 }, + {0xF873, 0x30 }, + {0xF874, 0x30 }, + {0xF875, 0xe4 }, + {0xF876, 0xf0 }, + {0xF877, 0x90 }, + {0xF878, 0x30 }, + {0xF879, 0x35 }, + {0xF87A, 0x04 }, + {0xF87B, 0xf0 }, + {0xF87C, 0x80 }, + {0xF87D, 0x69 }, + {0xF87E, 0xe5 }, + {0xF87F, 0x7d }, + {0xF880, 0x64 }, + {0xF881, 0x02 }, + {0xF882, 0x70 }, + {0xF883, 0x3c }, + {0xF884, 0x90 }, + {0xF885, 0x02 }, + {0xF886, 0x00 }, + {0xF887, 0x74 }, + {0xF888, 0x04 }, + {0xF889, 0xf0 }, + {0xF88A, 0xa3 }, + {0xF88B, 0x74 }, + {0xF88C, 0x10 }, + {0xF88D, 0xf0 }, + {0xF88E, 0x90 }, + {0xF88F, 0x30 }, + {0xF890, 0x04 }, + {0xF891, 0x74 }, + {0xF892, 0x34 }, + {0xF893, 0xf0 }, + {0xF894, 0xa3 }, + {0xF895, 0x74 }, + {0xF896, 0x07 }, + {0xF897, 0xf0 }, + {0xF898, 0x90 }, + {0xF899, 0x30 }, + {0xF89A, 0x10 }, + {0xF89B, 0x74 }, + {0xF89C, 0x10 }, + {0xF89D, 0xf0 }, + {0xF89E, 0x90 }, + {0xF89F, 0x30 }, + {0xF8A0, 0x16 }, + {0xF8A1, 0x74 }, + {0xF8A2, 0x1f }, + {0xF8A3, 0xf0 }, + {0xF8A4, 0x90 }, + {0xF8A5, 0x30 }, + {0xF8A6, 0x1a }, + {0xF8A7, 0x74 }, + {0xF8A8, 0x62 }, + {0xF8A9, 0xf0 }, + {0xF8AA, 0xa3 }, + {0xF8AB, 0x74 }, + {0xF8AC, 0x2a }, + {0xF8AD, 0xf0 }, + {0xF8AE, 0x90 }, + {0xF8AF, 0x30 }, + {0xF8B0, 0x35 }, + {0xF8B1, 0x74 }, + {0xF8B2, 0x04 }, + {0xF8B3, 0xf0 }, + {0xF8B4, 0x90 }, + {0xF8B5, 0x30 }, + {0xF8B6, 0x41 }, + {0xF8B7, 0x74 }, + {0xF8B8, 0x60 }, + {0xF8B9, 0xf0 }, + {0xF8BA, 0xa3 }, + {0xF8BB, 0x74 }, + {0xF8BC, 0x64 }, + {0xF8BD, 0xf0 }, + {0xF8BE, 0x80 }, + {0xF8BF, 0x27 }, + {0xF8C0, 0xe5 }, + {0xF8C1, 0x7d }, + {0xF8C2, 0xb4 }, + {0xF8C3, 0x03 }, + {0xF8C4, 0x22 }, + {0xF8C5, 0x90 }, + {0xF8C6, 0x02 }, + {0xF8C7, 0x00 }, + {0xF8C8, 0x74 }, + {0xF8C9, 0x02 }, + {0xF8CA, 0xf0 }, + {0xF8CB, 0xa3 }, + {0xF8CC, 0x74 }, + {0xF8CD, 0x26 }, + {0xF8CE, 0xf0 }, + {0xF8CF, 0x90 }, + {0xF8D0, 0x30 }, + {0xF8D1, 0x05 }, + {0xF8D2, 0x74 }, + {0xF8D3, 0x03 }, + {0xF8D4, 0xf0 }, + {0xF8D5, 0x90 }, + {0xF8D6, 0x30 }, + {0xF8D7, 0x11 }, + {0xF8D8, 0x74 }, + {0xF8D9, 0x01 }, + {0xF8DA, 0xf0 }, + {0xF8DB, 0x90 }, + {0xF8DC, 0x30 }, + {0xF8DD, 0x1b }, + {0xF8DE, 0x74 }, + {0xF8DF, 0x2a }, + {0xF8E0, 0xf0 }, + {0xF8E1, 0x90 }, + {0xF8E2, 0x30 }, + {0xF8E3, 0x35 }, + {0xF8E4, 0x74 }, + {0xF8E5, 0x03 }, + {0xF8E6, 0xf0 }, + {0xF8E7, 0x90 }, + {0xF8E8, 0x41 }, + {0xF8E9, 0x01 }, + {0xF8EA, 0xe0 }, + {0xF8EB, 0xf5 }, + {0xF8EC, 0x79 }, + {0xF8ED, 0x90 }, + {0xF8EE, 0x43 }, + {0xF8EF, 0x87 }, + {0xF8F0, 0xe0 }, + {0xF8F1, 0xf5 }, + {0xF8F2, 0x7a }, + {0xF8F3, 0x90 }, + {0xF8F4, 0x42 }, + {0xF8F5, 0x05 }, + {0xF8F6, 0xe0 }, + {0xF8F7, 0xf5 }, + {0xF8F8, 0x7b }, + {0xF8F9, 0x22 }, + {0xF8FA, 0x78 }, + {0xF8FB, 0x07 }, + {0xF8FC, 0xe6 }, + {0xF8FD, 0xf5 }, + {0xF8FE, 0x7c }, + {0xF8FF, 0xe5 }, + {0xF900, 0x7c }, + {0xF901, 0x60 }, + {0xF902, 0x1e }, + {0xF903, 0x90 }, + {0xF904, 0x43 }, + {0xF905, 0x83 }, + {0xF906, 0xe0 }, + {0xF907, 0xb4 }, + {0xF908, 0x01 }, + {0xF909, 0x17 }, + {0xF90A, 0x90 }, + {0xF90B, 0x43 }, + {0xF90C, 0x87 }, + {0xF90D, 0xe0 }, + {0xF90E, 0xb4 }, + {0xF90F, 0x01 }, + {0xF910, 0x10 }, + {0xF911, 0x15 }, + {0xF912, 0x7c }, + {0xF913, 0x90 }, + {0xF914, 0x30 }, + {0xF915, 0xa1 }, + {0xF916, 0xe5 }, + {0xF917, 0x7c }, + {0xF918, 0xf0 }, + {0xF919, 0x90 }, + {0xF91A, 0x30 }, + {0xF91B, 0xa0 }, + {0xF91C, 0x74 }, + {0xF91D, 0x01 }, + {0xF91E, 0xf0 }, + {0xF91F, 0x80 }, + {0xF920, 0x05 }, + {0xF921, 0xe4 }, + {0xF922, 0x90 }, + {0xF923, 0x30 }, + {0xF924, 0xa0 }, + {0xF925, 0xf0 }, + {0xF926, 0x90 }, + {0xF927, 0x41 }, + {0xF928, 0x01 }, + {0xF929, 0xe0 }, + {0xF92A, 0xfc }, + {0xF92B, 0x54 }, + {0xF92C, 0x02 }, + {0xF92D, 0xfe }, + {0xF92E, 0xe5 }, + {0xF92F, 0x79 }, + {0xF930, 0x54 }, + {0xF931, 0x02 }, + {0xF932, 0xb5 }, + {0xF933, 0x06 }, + {0xF934, 0x0f }, + {0xF935, 0x90 }, + {0xF936, 0x43 }, + {0xF937, 0x87 }, + {0xF938, 0xe0 }, + {0xF939, 0xb5 }, + {0xF93A, 0x7a }, + {0xF93B, 0x08 }, + {0xF93C, 0x90 }, + {0xF93D, 0x42 }, + {0xF93E, 0x05 }, + {0xF93F, 0xe0 }, + {0xF940, 0x65 }, + {0xF941, 0x7b }, + {0xF942, 0x60 }, + {0xF943, 0x0b }, + {0xF944, 0x90 }, + {0xF945, 0x30 }, + {0xF946, 0x50 }, + {0xF947, 0xe0 }, + {0xF948, 0x54 }, + {0xF949, 0xf9 }, + {0xF94A, 0x44 }, + {0xF94B, 0x02 }, + {0xF94C, 0xf0 }, + {0xF94D, 0x80 }, + {0xF94E, 0x09 }, + {0xF94F, 0x90 }, + {0xF950, 0x30 }, + {0xF951, 0x50 }, + {0xF952, 0xe0 }, + {0xF953, 0x54 }, + {0xF954, 0xf9 }, + {0xF955, 0x44 }, + {0xF956, 0x04 }, + {0xF957, 0xf0 }, + {0xF958, 0x8c }, + {0xF959, 0x79 }, + {0xF95A, 0x90 }, + {0xF95B, 0x43 }, + {0xF95C, 0x87 }, + {0xF95D, 0xe0 }, + {0xF95E, 0xf5 }, + {0xF95F, 0x7a }, + {0xF960, 0x90 }, + {0xF961, 0x42 }, + {0xF962, 0x05 }, + {0xF963, 0xe0 }, + {0xF964, 0xf5 }, + {0xF965, 0x7b }, + {0xF966, 0x22 }, + {0xF967, 0xc3 }, + {0xF968, 0x90 }, + {0xF969, 0x0b }, + {0xF96A, 0x89 }, + {0xF96B, 0xe0 }, + {0xF96C, 0x94 }, + {0xF96D, 0x1e }, + {0xF96E, 0x90 }, + {0xF96F, 0x0b }, + {0xF970, 0x88 }, + {0xF971, 0xe0 }, + {0xF972, 0x94 }, + {0xF973, 0x00 }, + {0xF974, 0x50 }, + {0xF975, 0x06 }, + {0xF976, 0x7e }, + {0xF977, 0x00 }, + {0xF978, 0x7f }, + {0xF979, 0x01 }, + {0xF97A, 0x80 }, + {0xF97B, 0x3d }, + {0xF97C, 0xc3 }, + {0xF97D, 0x90 }, + {0xF97E, 0x0b }, + {0xF97F, 0x89 }, + {0xF980, 0xe0 }, + {0xF981, 0x94 }, + {0xF982, 0x3c }, + {0xF983, 0x90 }, + {0xF984, 0x0b }, + {0xF985, 0x88 }, + {0xF986, 0xe0 }, + {0xF987, 0x94 }, + {0xF988, 0x00 }, + {0xF989, 0x50 }, + {0xF98A, 0x06 }, + {0xF98B, 0x7e }, + {0xF98C, 0x00 }, + {0xF98D, 0x7f }, + {0xF98E, 0x02 }, + {0xF98F, 0x80 }, + {0xF990, 0x28 }, + {0xF991, 0xc3 }, + {0xF992, 0x90 }, + {0xF993, 0x0b }, + {0xF994, 0x89 }, + {0xF995, 0xe0 }, + {0xF996, 0x94 }, + {0xF997, 0xfa }, + {0xF998, 0x90 }, + {0xF999, 0x0b }, + {0xF99A, 0x88 }, + {0xF99B, 0xe0 }, + {0xF99C, 0x94 }, + {0xF99D, 0x00 }, + {0xF99E, 0x50 }, + {0xF99F, 0x06 }, + {0xF9A0, 0x7e }, + {0xF9A1, 0x00 }, + {0xF9A2, 0x7f }, + {0xF9A3, 0x03 }, + {0xF9A4, 0x80 }, + {0xF9A5, 0x13 }, + {0xF9A6, 0xc3 }, + {0xF9A7, 0x90 }, + {0xF9A8, 0x0b }, + {0xF9A9, 0x88 }, + {0xF9AA, 0xe0 }, + {0xF9AB, 0x94 }, + {0xF9AC, 0x80 }, + {0xF9AD, 0x50 }, + {0xF9AE, 0x06 }, + {0xF9AF, 0x7e }, + {0xF9B0, 0x00 }, + {0xF9B1, 0x7f }, + {0xF9B2, 0x04 }, + {0xF9B3, 0x80 }, + {0xF9B4, 0x04 }, + {0xF9B5, 0xae }, + {0xF9B6, 0x7e }, + {0xF9B7, 0xaf }, + {0xF9B8, 0x7f }, + {0xF9B9, 0x90 }, + {0xF9BA, 0xa0 }, + {0xF9BB, 0xf8 }, + {0xF9BC, 0xee }, + {0xF9BD, 0xf0 }, + {0xF9BE, 0xa3 }, + {0xF9BF, 0xef }, + {0xF9C0, 0xf0 }, + {0xF9C1, 0x22 }, + {0xF9C2, 0x90 }, + {0xF9C3, 0x33 }, + {0xF9C4, 0x82 }, + {0xF9C5, 0xe0 }, + {0xF9C6, 0xff }, + {0xF9C7, 0x64 }, + {0xF9C8, 0x01 }, + {0xF9C9, 0x70 }, + {0xF9CA, 0x30 }, + {0xF9CB, 0xe5 }, + {0xF9CC, 0x7f }, + {0xF9CD, 0x64 }, + {0xF9CE, 0x02 }, + {0xF9CF, 0x45 }, + {0xF9D0, 0x7e }, + {0xF9D1, 0x70 }, + {0xF9D2, 0x04 }, + {0xF9D3, 0x7d }, + {0xF9D4, 0x1e }, + {0xF9D5, 0x80 }, + {0xF9D6, 0x1d }, + {0xF9D7, 0xe5 }, + {0xF9D8, 0x7f }, + {0xF9D9, 0x64 }, + {0xF9DA, 0x03 }, + {0xF9DB, 0x45 }, + {0xF9DC, 0x7e }, + {0xF9DD, 0x70 }, + {0xF9DE, 0x04 }, + {0xF9DF, 0x7d }, + {0xF9E0, 0x3c }, + {0xF9E1, 0x80 }, + {0xF9E2, 0x11 }, + {0xF9E3, 0xe5 }, + {0xF9E4, 0x7f }, + {0xF9E5, 0x64 }, + {0xF9E6, 0x04 }, + {0xF9E7, 0x45 }, + {0xF9E8, 0x7e }, + {0xF9E9, 0x70 }, + {0xF9EA, 0x04 }, + {0xF9EB, 0x7d }, + {0xF9EC, 0xfa }, + {0xF9ED, 0x80 }, + {0xF9EE, 0x05 }, + {0xF9EF, 0x90 }, + {0xF9F0, 0x33 }, + {0xF9F1, 0x81 }, + {0xF9F2, 0xe0 }, + {0xF9F3, 0xfd }, + {0xF9F4, 0xae }, + {0xF9F5, 0x05 }, + {0xF9F6, 0x90 }, + {0xF9F7, 0x33 }, + {0xF9F8, 0x81 }, + {0xF9F9, 0xed }, + {0xF9FA, 0xf0 }, + {0xF9FB, 0xef }, + {0xF9FC, 0xb4 }, + {0xF9FD, 0x01 }, + {0xF9FE, 0x10 }, + {0xF9FF, 0x90 }, + {0xFA00, 0x01 }, + {0xFA01, 0x00 }, + {0xFA02, 0xe0 }, + {0xFA03, 0x60 }, + {0xFA04, 0x0a }, + {0xFA05, 0x90 }, + {0xFA06, 0xa1 }, + {0xFA07, 0x10 }, + {0xFA08, 0xe0 }, + {0xFA09, 0xf5 }, + {0xFA0A, 0x7e }, + {0xFA0B, 0xa3 }, + {0xFA0C, 0xe0 }, + {0xFA0D, 0xf5 }, + {0xFA0E, 0x7f }, + {0xFA0F, 0x22 }, + {0xFA10, 0x12 }, + {0xFA11, 0x2f }, + {0xFA12, 0x4d }, + {0xFA13, 0x90 }, + {0xFA14, 0x35 }, + {0xFA15, 0x38 }, + {0xFA16, 0xe0 }, + {0xFA17, 0x70 }, + {0xFA18, 0x05 }, + {0xFA19, 0x12 }, + {0xFA1A, 0x00 }, + {0xFA1B, 0x0e }, + {0xFA1C, 0x80 }, + {0xFA1D, 0x03 }, + {0xFA1E, 0x12 }, + {0xFA1F, 0x07 }, + {0xFA20, 0xc9 }, + {0xFA21, 0x90 }, + {0xFA22, 0x40 }, + {0xFA23, 0x06 }, + {0xFA24, 0xe0 }, + {0xFA25, 0xf4 }, + {0xFA26, 0x54 }, + {0xFA27, 0x02 }, + {0xFA28, 0xff }, + {0xFA29, 0xe0 }, + {0xFA2A, 0x54 }, + {0xFA2B, 0x01 }, + {0xFA2C, 0x4f }, + {0xFA2D, 0x90 }, + {0xFA2E, 0x31 }, + {0xFA2F, 0x32 }, + {0xFA30, 0xf0 }, + {0xFA31, 0x90 }, + {0xFA32, 0xfa }, + {0xFA33, 0x9d }, + {0xFA34, 0xe0 }, + {0xFA35, 0x70 }, + {0xFA36, 0x03 }, + {0xFA37, 0x12 }, + {0xFA38, 0x27 }, + {0xFA39, 0x27 }, + {0xFA3A, 0x02 }, + {0xFA3B, 0x05 }, + {0xFA3C, 0xac }, + {0xFA3D, 0x22 }, + {0xFA3E, 0xf0 }, + {0xFA3F, 0xe5 }, + {0xFA40, 0x3a }, + {0xFA41, 0xb4 }, + {0xFA42, 0x06 }, + {0xFA43, 0x06 }, + {0xFA44, 0x63 }, + {0xFA45, 0x3e }, + {0xFA46, 0x02 }, + {0xFA47, 0x12 }, + {0xFA48, 0x03 }, + {0xFA49, 0xea }, + {0xFA4A, 0x02 }, + {0xFA4B, 0x17 }, + {0xFA4C, 0x4a }, + {0xFA4D, 0x22 }, + {0x35C9, 0xFA }, + {0x35CA, 0x01 }, + {0x35CB, 0x67 }, + {0x35CC, 0x01 }, + {0x35CD, 0xC2 }, + {0x35CE, 0x02 }, + {0x35CF, 0x10 }, + {0x35D0, 0x02 }, + {0x35D1, 0x3E }, + {0x35D3, 0xF6 }, + {0x35D5, 0x07 }, + {0x35D7, 0xA3 }, + {0x35DB, 0x02 }, + {0x35DD, 0x06 }, + {0x35DF, 0x27 }, + {0x35E6, 0x28 }, + {0x35E7, 0x76 }, + {0x35E8, 0x2A }, + {0x35E9, 0x15 }, + {0x35EA, 0x2D }, + {0x35EB, 0x07 }, + {0x35EC, 0x04 }, + {0x35ED, 0x43 }, + {0x35EE, 0x05 }, + {0x35EF, 0xA9 }, + {0x35F0, 0x17 }, + {0x35F1, 0x41 }, + {0x35F2, 0x24 }, + {0x35F3, 0x88 }, + {0x35F4, 0x01 }, + {0x35F5, 0x54 }, + {0x35F6, 0x01 }, + {0x35F7, 0x55 }, + {0x35F8, 0x2E }, + {0x35F9, 0xF2 }, + {0x35FA, 0x06 }, + {0x35FB, 0x02 }, + {0x35FC, 0x06 }, + {0x35FD, 0x03 }, + {0x35FE, 0x06 }, + {0x35FF, 0x04 }, + {0x3600, 0x0F }, + {0x3601, 0x48 }, + {0x3602, 0x0F }, + {0x3603, 0x49 }, + {0x3604, 0x0F }, + {0x3605, 0x4A }, + {0x35C2, 0xFF }, + {0x35C3, 0xFF }, + {0x35C4, 0xFF }, + {0x35C5, 0xC0 }, + {0x35C0, 0x01 }, + + + {0xa098, 0x02 }, + {0xa099, 0x87 }, + {0xa09c, 0x00 }, + {0xa09d, 0xc5 }, + {0xa4ec, 0x05 }, + {0xa4ed, 0x05 }, + {0xa4f0, 0x04 }, + {0xa4f1, 0x04 }, + {0xa4f4, 0x04 }, + {0xa4f5, 0x05 }, + {0xa4f8, 0x05 }, + {0xa4f9, 0x07 }, + {0xa4fc, 0x07 }, + {0xa4fd, 0x07 }, + {0xa500, 0x07 }, + {0xa501, 0x07 }, + {0xa504, 0x08 }, + {0xa505, 0x08 }, + {0xa518, 0x01 }, + {0xa519, 0x02 }, + {0xa51c, 0x01 }, + {0xa51d, 0x00 }, + {0xa534, 0x00 }, + {0xa535, 0x04 }, + {0xa538, 0x04 }, + {0xa539, 0x03 }, + {0xa53c, 0x05 }, + {0xa53d, 0x07 }, + {0xa540, 0x07 }, + {0xa541, 0x06 }, + {0xa544, 0x07 }, + {0xa545, 0x06 }, + {0xa548, 0x05 }, + {0xa549, 0x06 }, + {0xa54c, 0x06 }, + {0xa54d, 0x07 }, + {0xa550, 0x07 }, + {0xa551, 0x04 }, + {0xa554, 0x04 }, + {0xa555, 0x04 }, + {0xa558, 0x05 }, + {0xa559, 0x06 }, + {0xa55c, 0x07 }, + {0xa55d, 0x07 }, + {0xa56c, 0x00 }, + {0xa56d, 0x0a }, + {0xa570, 0x08 }, + {0xa571, 0x05 }, + {0xa574, 0x04 }, + {0xa575, 0x03 }, + {0xa578, 0x04 }, + {0xa579, 0x04 }, + {0xa58c, 0x1f }, + {0xa58d, 0x1b }, + {0xa590, 0x17 }, + {0xa591, 0x13 }, + {0xa594, 0x10 }, + {0xa595, 0x0d }, + {0xa598, 0x0f }, + {0xa599, 0x11 }, + {0xa59c, 0x03 }, + {0xa59d, 0x03 }, + {0xa5a0, 0x03 }, + {0xa5a1, 0x03 }, + {0xa5a4, 0x03 }, + {0xa5a5, 0x04 }, + {0xa5a8, 0x05 }, + {0xa5a9, 0x00 }, + {0xa5ac, 0x00 }, + {0xa5ad, 0x00 }, + {0xa5b0, 0x00 }, + {0xa5b1, 0x00 }, + {0xa5b4, 0x00 }, + {0xa5b5, 0x00 }, + {0xa5c4, 0x1f }, + {0xa5c5, 0x13 }, + {0xa5c8, 0x14 }, + {0xa5c9, 0x14 }, + {0xa5cc, 0x14 }, + {0xa5cd, 0x13 }, + {0xa5d0, 0x17 }, + {0xa5d1, 0x1a }, + {0xa5f4, 0x05 }, + {0xa5f5, 0x05 }, + {0xa5f8, 0x05 }, + {0xa5f9, 0x06 }, + {0xa5fc, 0x06 }, + {0xa5fd, 0x06 }, + {0xa600, 0x06 }, + {0xa601, 0x06 }, + {0xa608, 0x07 }, + {0xa609, 0x08 }, + {0xa60c, 0x08 }, + {0xa60d, 0x07 }, + {0xa63c, 0x00 }, + {0xa63d, 0x02 }, + {0xa640, 0x02 }, + {0xa641, 0x02 }, + {0xa644, 0x02 }, + {0xa645, 0x02 }, + {0xa648, 0x03 }, + {0xa649, 0x04 }, + {0xa64c, 0x0a }, + {0xa64d, 0x09 }, + {0xa650, 0x08 }, + {0xa651, 0x09 }, + {0xa654, 0x09 }, + {0xa655, 0x0a }, + {0xa658, 0x0a }, + {0xa659, 0x0a }, + {0xa65c, 0x0a }, + {0xa65d, 0x09 }, + {0xa660, 0x09 }, + {0xa661, 0x09 }, + {0xa664, 0x09 }, + {0xa665, 0x08 }, + {0xa680, 0x01 }, + {0xa681, 0x02 }, + {0xa694, 0x1f }, + {0xa695, 0x10 }, + {0xa698, 0x0e }, + {0xa699, 0x0c }, + {0xa69c, 0x0d }, + {0xa69d, 0x0d }, + {0xa6a0, 0x0f }, + {0xa6a1, 0x11 }, + {0xa6a4, 0x00 }, + {0xa6a5, 0x00 }, + {0xa6a8, 0x00 }, + {0xa6a9, 0x00 }, + {0xa6ac, 0x00 }, + {0xa6ad, 0x00 }, + {0xa6b0, 0x00 }, + {0xa6b1, 0x04 }, + {0xa6b4, 0x04 }, + {0xa6b5, 0x04 }, + {0xa6b8, 0x04 }, + {0xa6b9, 0x04 }, + {0xa6bc, 0x05 }, + {0xa6bd, 0x05 }, + {0xa6c0, 0x1f }, + {0xa6c1, 0x1f }, + {0xa6c4, 0x1f }, + {0xa6c5, 0x1f }, + {0xa6c8, 0x1f }, + {0xa6c9, 0x1f }, + {0xa6cc, 0x1f }, + {0xa6cd, 0x0b }, + {0xa6d0, 0x0c }, + {0xa6d1, 0x0d }, + {0xa6d4, 0x0d }, + {0xa6d5, 0x0d }, + {0xa6d8, 0x11 }, + {0xa6d9, 0x14 }, + {0xa6fc, 0x02 }, + {0xa6fd, 0x03 }, + {0xa700, 0x03 }, + {0xa701, 0x03 }, + {0xa704, 0x03 }, + {0xa705, 0x04 }, + {0xa708, 0x05 }, + {0xa709, 0x02 }, + {0xa70c, 0x02 }, + {0xa70d, 0x02 }, + {0xa710, 0x03 }, + {0xa711, 0x04 }, + {0xa714, 0x04 }, + {0xa715, 0x04 }, + {0xa744, 0x00 }, + {0xa745, 0x03 }, + {0xa748, 0x04 }, + {0xa749, 0x04 }, + {0xa74c, 0x05 }, + {0xa74d, 0x06 }, + {0xa750, 0x07 }, + {0xa751, 0x07 }, + {0xa754, 0x05 }, + {0xa755, 0x05 }, + {0xa758, 0x05 }, + {0xa759, 0x05 }, + {0xa75c, 0x05 }, + {0xa75d, 0x06 }, + {0xa760, 0x07 }, + {0xa761, 0x07 }, + {0xa764, 0x06 }, + {0xa765, 0x05 }, + {0xa768, 0x05 }, + {0xa769, 0x05 }, + {0xa76c, 0x06 }, + {0xa76d, 0x07 }, + {0xa77c, 0x00 }, + {0xa77d, 0x05 }, + {0xa780, 0x05 }, + {0xa781, 0x05 }, + {0xa784, 0x05 }, + {0xa785, 0x04 }, + {0xa788, 0x05 }, + {0xa789, 0x06 }, + {0xa79c, 0x1f }, + {0xa79d, 0x15 }, + {0xa7a0, 0x13 }, + {0xa7a1, 0x10 }, + {0xa7a4, 0x0f }, + {0xa7a5, 0x0d }, + {0xa7a8, 0x11 }, + {0xa7a9, 0x14 }, + {0xa7ac, 0x02 }, + {0xa7ad, 0x02 }, + {0xa7b0, 0x02 }, + {0xa7b1, 0x02 }, + {0xa7b4, 0x02 }, + {0xa7b5, 0x03 }, + {0xa7b8, 0x03 }, + {0xa7b9, 0x00 }, + {0xa7bc, 0x00 }, + {0xa7bd, 0x00 }, + {0xa7c0, 0x00 }, + {0xa7c1, 0x00 }, + {0xa7c4, 0x00 }, + {0xa7c5, 0x00 }, + {0xa7d4, 0x1f }, + {0xa7d5, 0x0d }, + {0xa7d8, 0x0f }, + {0xa7d9, 0x10 }, + {0xa7dc, 0x10 }, + {0xa7dd, 0x10 }, + {0xa7e0, 0x13 }, + {0xa7e1, 0x16 }, + {0xa7f4, 0x00 }, + {0xa7f5, 0x03 }, + {0xa7f8, 0x04 }, + {0xa7f9, 0x04 }, + {0xa7fc, 0x04 }, + {0xa7fd, 0x03 }, + {0xa800, 0x03 }, + {0xa801, 0x03 }, + {0xa804, 0x03 }, + {0xa805, 0x03 }, + {0xa808, 0x03 }, + {0xa809, 0x03 }, + {0xa80c, 0x03 }, + {0xa80d, 0x04 }, + {0xa810, 0x04 }, + {0xa811, 0x0a }, + {0xa814, 0x0a }, + {0xa815, 0x0a }, + {0xa818, 0x0f }, + {0xa819, 0x14 }, + {0xa81c, 0x14 }, + {0xa81d, 0x14 }, + {0xa82c, 0x00 }, + {0xa82d, 0x04 }, + {0xa830, 0x02 }, + {0xa831, 0x00 }, + {0xa834, 0x00 }, + {0xa835, 0x00 }, + {0xa838, 0x00 }, + {0xa839, 0x00 }, + {0xa840, 0x1f }, + {0xa841, 0x1f }, + {0xa848, 0x1f }, + {0xa849, 0x1f }, + {0xa84c, 0x1f }, + {0xa84d, 0x0c }, + {0xa850, 0x0c }, + {0xa851, 0x0c }, + {0xa854, 0x0c }, + {0xa855, 0x0c }, + {0xa858, 0x0c }, + {0xa859, 0x0c }, + {0xa85c, 0x0c }, + {0xa85d, 0x0c }, + {0xa860, 0x0c }, + {0xa861, 0x0c }, + {0xa864, 0x0c }, + {0xa865, 0x0c }, + {0xa868, 0x0c }, + {0xa869, 0x0c }, + {0xa86c, 0x0c }, + {0xa86d, 0x0c }, + {0xa870, 0x0c }, + {0xa871, 0x0c }, + {0xa874, 0x0c }, + {0xa875, 0x0c }, + {0xa878, 0x1f }, + {0xa879, 0x1f }, + {0xa87c, 0x1f }, + {0xa87d, 0x1f }, + {0xa880, 0x1f }, + {0xa881, 0x1f }, + {0xa884, 0x1f }, + {0xa885, 0x0c }, + {0xa888, 0x0c }, + {0xa889, 0x0c }, + {0xa88c, 0x0c }, + {0xa88d, 0x0c }, + {0xa890, 0x0c }, + {0xa891, 0x0c }, + {0xa898, 0x1f }, + {0xa899, 0x1f }, + {0xa8a0, 0x1f }, + {0xa8a1, 0x1f }, + {0xa8a4, 0x1f }, + {0xa8a5, 0x0c }, + {0xa8a8, 0x0c }, + {0xa8a9, 0x0c }, + {0xa8ac, 0x0c }, + {0xa8ad, 0x0c }, + {0xa8b0, 0x0c }, + {0xa8b1, 0x0c }, + {0xa8b4, 0x0c }, + {0xa8b5, 0x0c }, + {0xa8b8, 0x0c }, + {0xa8b9, 0x0c }, + {0xa8bc, 0x0c }, + {0xa8bd, 0x0c }, + {0xa8c0, 0x0c }, + {0xa8c1, 0x0c }, + {0xa8c4, 0x0c }, + {0xa8c5, 0x0c }, + {0xa8c8, 0x0c }, + {0xa8c9, 0x0c }, + {0xa8cc, 0x0c }, + {0xa8cd, 0x0c }, + {0xa8d0, 0x1f }, + {0xa8d1, 0x1f }, + {0xa8d4, 0x1f }, + {0xa8d5, 0x1f }, + {0xa8d8, 0x1f }, + {0xa8d9, 0x1f }, + {0xa8dc, 0x1f }, + {0xa8dd, 0x0c }, + {0xa8e0, 0x0c }, + {0xa8e1, 0x0c }, + {0xa8e4, 0x0c }, + {0xa8e5, 0x0c }, + {0xa8e8, 0x0c }, + {0xa8e9, 0x0c }, + {0xa8f0, 0x1f }, + {0xa8f1, 0x1f }, + {0xa8f8, 0x1f }, + {0xa8f9, 0x1f }, + {0xa8fc, 0x1f }, + {0xa8fd, 0x0c }, + {0xa900, 0x0c }, + {0xa901, 0x0c }, + {0xa904, 0x0c }, + {0xa905, 0x0c }, + {0xa908, 0x0c }, + {0xa909, 0x0c }, + {0xa90c, 0x0c }, + {0xa90d, 0x0c }, + {0xa910, 0x0c }, + {0xa911, 0x0c }, + {0xa914, 0x0c }, + {0xa915, 0x0c }, + {0xa918, 0x0c }, + {0xa919, 0x0c }, + {0xa91c, 0x0c }, + {0xa91d, 0x0c }, + {0xa920, 0x0c }, + {0xa921, 0x0c }, + {0xa924, 0x0c }, + {0xa925, 0x0c }, + {0xa928, 0x1f }, + {0xa929, 0x1f }, + {0xa92c, 0x1f }, + {0xa92d, 0x1f }, + {0xa930, 0x1f }, + {0xa931, 0x1f }, + {0xa934, 0x1f }, + {0xa935, 0x0c }, + {0xa938, 0x0c }, + {0xa939, 0x0c }, + {0xa93c, 0x0c }, + {0xa93d, 0x0c }, + {0xa940, 0x0c }, + {0xa941, 0x0c }, + {0xa96c, 0x0d }, + {0xa96d, 0x16 }, + {0xa970, 0x19 }, + {0xa971, 0x0e }, + {0xa974, 0x16 }, + {0xa975, 0x1a }, + {0xa978, 0x0d }, + {0xa979, 0x15 }, + {0xa97c, 0x19 }, + {0xa97d, 0x0d }, + {0xa980, 0x15 }, + {0xa981, 0x1a }, + {0xa984, 0x0d }, + {0xa985, 0x15 }, + {0xa988, 0x1a }, + {0xa989, 0x0d }, + {0xa98c, 0x15 }, + {0xa98d, 0x1a }, + {0xa990, 0x0b }, + {0xa991, 0x11 }, + {0xa994, 0x02 }, + {0xa995, 0x0e }, + {0xa998, 0x16 }, + {0xa999, 0x02 }, + {0xa99c, 0x0c }, + {0xa99d, 0x13 }, + {0xa9a0, 0x02 }, + {0xa9a1, 0x0c }, + {0xa9a4, 0x12 }, + {0xa9a5, 0x02 }, + {0xa9a8, 0x0c }, + {0xa9a9, 0x12 }, + {0xa9ac, 0x02 }, + {0xa9ad, 0x0c }, + {0xa9b0, 0x12 }, + {0xa9b1, 0x02 }, + {0xa9b4, 0x10 }, + {0xa9b5, 0x1e }, + {0xa9b8, 0x0f }, + {0xa9b9, 0x13 }, + {0xa9bc, 0x20 }, + {0xa9bd, 0x10 }, + {0xa9c0, 0x11 }, + {0xa9c1, 0x1e }, + {0xa9c4, 0x10 }, + {0xa9c5, 0x11 }, + {0xa9c8, 0x1e }, + {0xa9c9, 0x10 }, + {0xa9cc, 0x11 }, + {0xa9cd, 0x20 }, + {0xa9d0, 0x10 }, + {0xa9d1, 0x13 }, + {0xa9d4, 0x24 }, + {0xa9d5, 0x10 }, + {0xa9f0, 0x02 }, + {0xa9f1, 0x01 }, + {0xa9f8, 0x19 }, + {0xa9f9, 0x0b }, + {0xa9fc, 0x0a }, + {0xa9fd, 0x07 }, + {0xaa00, 0x0c }, + {0xaa01, 0x0e }, + {0xaa08, 0x0c }, + {0xaa09, 0x06 }, + {0xaa0c, 0x0c }, + {0xaa0d, 0x0a }, + {0xaa24, 0x10 }, + {0xaa25, 0x12 }, + {0xaa28, 0x0b }, + {0xaa29, 0x07 }, + {0xaa2c, 0x10 }, + {0xaa2d, 0x14 }, + {0xaa34, 0x0e }, + {0xaa35, 0x0e }, + {0xaa38, 0x07 }, + {0xaa39, 0x07 }, + {0xaa3c, 0x0e }, + {0xaa3d, 0x0c }, + {0xaa48, 0x09 }, + {0xaa49, 0x0c }, + {0xaa4c, 0x0c }, + {0xaa4d, 0x07 }, + {0xaa54, 0x08 }, + {0xaa55, 0x06 }, + {0xaa58, 0x04 }, + {0xaa59, 0x05 }, + {0xaa5c, 0x06 }, + {0xaa5d, 0x06 }, + {0xaa68, 0x05 }, + {0xaa69, 0x05 }, + {0xaa6c, 0x04 }, + {0xaa6d, 0x05 }, + {0xaa74, 0x06 }, + {0xaa75, 0x04 }, + {0xaa78, 0x05 }, + {0xaa79, 0x05 }, + {0xaa7c, 0x04 }, + {0xaa7d, 0x06 }, + {0xac18, 0x14 }, + {0xac19, 0x00 }, + {0xac1c, 0x14 }, + {0xac1d, 0x00 }, + {0xac20, 0x14 }, + {0xac21, 0x00 }, + {0xac24, 0x14 }, + {0xac25, 0x00 }, + {0xac28, 0x14 }, + {0xac29, 0x00 }, + {0xac2c, 0x14 }, + {0xac2d, 0x00 }, + {0xac34, 0x16 }, + {0xac35, 0x00 }, + {0xac38, 0x16 }, + {0xac39, 0x00 }, + {0xac3c, 0x16 }, + {0xac3d, 0x00 }, + {0xac40, 0x16 }, + {0xac41, 0x00 }, + {0xac44, 0x16 }, + {0xac45, 0x00 }, + {0xac48, 0x16 }, + {0xac49, 0x00 }, + {0xac50, 0x1b }, + {0xac51, 0x00 }, + {0xac54, 0x1b }, + {0xac55, 0x00 }, + {0xac58, 0x1b }, + {0xac59, 0x00 }, + {0xac5c, 0x1b }, + {0xac5d, 0x00 }, + {0xac60, 0x1b }, + {0xac61, 0x00 }, + {0xac64, 0x1b }, + {0xac65, 0x00 }, + {0xac74, 0x09 }, + {0xac75, 0x0c }, + {0xac78, 0x0f }, + {0xac79, 0x11 }, + {0xac7c, 0x12 }, + {0xac7d, 0x14 }, + {0xac80, 0x09 }, + {0xac81, 0x0c }, + {0xac84, 0x0f }, + {0xac85, 0x11 }, + {0xac88, 0x12 }, + {0xac89, 0x14 }, + {0xac8c, 0x09 }, + {0xac8d, 0x0c }, + {0xac90, 0x0f }, + {0xac91, 0x11 }, + {0xac94, 0x12 }, + {0xac95, 0x14 }, + {0xac98, 0x09 }, + {0xac99, 0x0c }, + {0xac9c, 0x0f }, + {0xac9d, 0x11 }, + {0xaca0, 0x12 }, + {0xaca1, 0x14 }, + {0xaca4, 0x09 }, + {0xaca5, 0x0c }, + {0xaca8, 0x0f }, + {0xaca9, 0x11 }, + {0xacac, 0x12 }, + {0xacad, 0x14 }, + {0xacb0, 0x07 }, + {0xacb1, 0x09 }, + {0xacb4, 0x0c }, + {0xacb5, 0x0d }, + {0xacb8, 0x0d }, + {0xacb9, 0x0e }, + {0xacbc, 0x05 }, + {0xacbd, 0x07 }, + {0xacc0, 0x0a }, + {0xacc1, 0x0b }, + {0xacc4, 0x0b }, + {0xacc5, 0x0c }, + {0xacc8, 0x03 }, + {0xacc9, 0x04 }, + {0xaccc, 0x07 }, + {0xaccd, 0x08 }, + {0xacd0, 0x09 }, + {0xacd1, 0x09 }, + {0x35B5, 0x01 }, + {0x35BC, 0x01 }, + {0x360A, 0x02 }, + {0xFA9B, 0x01 }, +}; + +#define NUM_LSC_CAST_REGS 33 + +enum LSC_Cast_t{ + cast_H = 0, + cast_U30, + cast_CW, + cast_D, + cast_MAX +}; + +static short int LSC_CorrectionForCast[cast_MAX][NUM_LSC_CAST_REGS] = { + {-30, -20, 8, 11, -16, -26, -35, -53, -9, -10, 44, 57, -39, + -14, 50, -173, -38, -32, -1, 9, 39, 51, -33, -49, -28, + -22, 7, 11, -21, 17, -62, -56, 0}, + {-29, -18, 6, 1, 17, -35, -77, 0, 5, -17, -6, -22, -41, -1, + -37, 83, -38, -32, 1, -2, 15, 25, -67, 19, -28, -22, 5, + 2, -18, 21, -86, 0, 0}, + {-10, -15, -4, -6, -8, -3, -63, 8, 25, -9, -39, -51, -9, + 0, -21, 112, -10, -23, -7, -9, 10, 18, -11, 23, -10, + -15, -4, -6, -10, -3, -52, 7, 0}, + { 5, 3, -4, -5, -1, 3, 4, 8, 12, 3, -22, -21, 7, 17, + 2, 35, 8, 2, -3, -2, -9, -5, 10, 4, 9, 2, -4, -5, + -2, 0, -6, 9, 0} +}; + +static unsigned short LSC_CastRegs[] = { + 0xFB7E, /* H */ + 0xFB3C, /* U30 */ + 0xFAFA, /* CW */ + 0xFAB8 /* D65 */ +}; + +/*=============================================================*/ + +static int vx6953_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 2, + .buf = rxdata, + }, + }; + if (i2c_transfer(vx6953_client->adapter, msgs, 2) < 0) { + CDBG("vx6953_i2c_rxdata failed!\n"); + return -EIO; + } + return 0; +} +static int32_t vx6953_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(vx6953_client->adapter, msg, 1) < 0) { + CDBG("vx6953_i2c_txdata faild 0x%x\n", vx6953_client->addr); + return -EIO; + } + + return 0; +} + + +static int32_t vx6953_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + rc = vx6953_i2c_rxdata(vx6953_client->addr>>1, buf, rlen); + if (rc < 0) { + CDBG("vx6953_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + return rc; +} +static int32_t vx6953_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[3]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata); + rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, 3); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + return rc; +} +static int32_t vx6953_i2c_write_w_sensor(unsigned short waddr, uint16_t wdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[4]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = (wdata & 0xFF00) >> 8; + buf[3] = (wdata & 0x00FF); + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata); + rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, 4); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, wdata); + } + return rc; +} +static int32_t vx6953_i2c_write_seq_sensor(unsigned short waddr, + uint8_t *bdata, uint16_t len) +{ + int32_t rc = -EFAULT; + unsigned char buf[len+2]; + int i; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + for (i = 2; i < len+2; i++) + buf[i] = *bdata++; + rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, len+2); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata[0]); + } + return rc; +} + +static int32_t vx6953_i2c_write_w_table(struct vx6953_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + for (i = 0; i < num; i++) { + rc = vx6953_i2c_write_b_sensor(reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +static void vx6953_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint16_t preview_frame_length_lines, snapshot_frame_length_lines; + uint16_t preview_line_length_pck, snapshot_line_length_pck; + uint32_t divider, d1, d2; + /* Total frame_length_lines and line_length_pck for preview */ + preview_frame_length_lines = VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES; + preview_line_length_pck = VX6953_QTR_SIZE_WIDTH + + VX6953_HRZ_QTR_BLK_PIXELS; + /* Total frame_length_lines and line_length_pck for snapshot */ + snapshot_frame_length_lines = VX6953_FULL_SIZE_HEIGHT + + VX6953_VER_FULL_BLK_LINES; + snapshot_line_length_pck = VX6953_FULL_SIZE_WIDTH + + VX6953_HRZ_FULL_BLK_PIXELS; + d1 = preview_frame_length_lines * 0x00000400/ + snapshot_frame_length_lines; + d2 = preview_line_length_pck * 0x00000400/ + snapshot_line_length_pck; + divider = d1 * d2 / 0x400; + /*Verify PCLK settings and frame sizes.*/ + *pfps = (uint16_t) (fps * divider / 0x400); + /* 2 is the ratio of no.of snapshot channels + to number of preview channels */ + +} + +static uint16_t vx6953_get_prev_lines_pf(void) +{ + if (vx6953_ctrl->prev_res == QTR_SIZE) + return VX6953_QTR_SIZE_HEIGHT + VX6953_VER_QTR_BLK_LINES; + else + return VX6953_FULL_SIZE_HEIGHT + VX6953_VER_FULL_BLK_LINES; + +} + +static uint16_t vx6953_get_prev_pixels_pl(void) +{ + if (vx6953_ctrl->prev_res == QTR_SIZE) + return VX6953_QTR_SIZE_WIDTH + VX6953_HRZ_QTR_BLK_PIXELS; + else + return VX6953_FULL_SIZE_WIDTH + VX6953_HRZ_FULL_BLK_PIXELS; +} + +static uint16_t vx6953_get_pict_lines_pf(void) +{ + if (vx6953_ctrl->pict_res == QTR_SIZE) + return VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES; + else + return VX6953_FULL_SIZE_HEIGHT + + VX6953_VER_FULL_BLK_LINES; +} + +static uint16_t vx6953_get_pict_pixels_pl(void) +{ + if (vx6953_ctrl->pict_res == QTR_SIZE) + return VX6953_QTR_SIZE_WIDTH + + VX6953_HRZ_QTR_BLK_PIXELS; + else + return VX6953_FULL_SIZE_WIDTH + + VX6953_HRZ_FULL_BLK_PIXELS; +} + +static uint32_t vx6953_get_pict_max_exp_lc(void) +{ + if (vx6953_ctrl->pict_res == QTR_SIZE) + return (VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES)*24; + else + return (VX6953_FULL_SIZE_HEIGHT + + VX6953_VER_FULL_BLK_LINES)*24; +} + +static int32_t vx6953_set_fps(struct fps_cfg *fps) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + total_lines_per_frame = (uint16_t)((VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES) * vx6953_ctrl->fps_divider/0x400); + + vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if (vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI, + ((total_lines_per_frame & 0xFF00) >> 8)) < 0) + return rc; + if (vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO, + (total_lines_per_frame & 0x00FF)) < 0) + return rc; + vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF); + return rc; +} + +static int32_t vx6953_write_exp_gain(uint16_t gain, uint32_t line) +{ + uint16_t line_length_pck, frame_length_lines; + uint8_t gain_hi, gain_lo; + uint8_t intg_time_hi, intg_time_lo; + uint8_t frame_length_lines_hi = 0, frame_length_lines_lo = 0; + int32_t rc = 0; + if (vx6953_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) { + frame_length_lines = VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES; + line_length_pck = VX6953_QTR_SIZE_WIDTH + + VX6953_HRZ_QTR_BLK_PIXELS; + if (line > (frame_length_lines - + VX6953_STM5M0EDOF_OFFSET)) { + vx6953_ctrl->fps = (uint16_t) (30 * Q8 * + (frame_length_lines - VX6953_STM5M0EDOF_OFFSET)/ + line); + } else { + vx6953_ctrl->fps = (uint16_t) (30 * Q8); + } + } else { + frame_length_lines = VX6953_FULL_SIZE_HEIGHT + + VX6953_VER_FULL_BLK_LINES; + line_length_pck = VX6953_FULL_SIZE_WIDTH + + VX6953_HRZ_FULL_BLK_PIXELS; + } + + vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + if ((line + VX6953_STM5M0EDOF_OFFSET) > MAX_FRAME_LENGTH_LINES) { + frame_length_lines = MAX_FRAME_LENGTH_LINES; + line = MAX_FRAME_LENGTH_LINES - VX6953_STM5M0EDOF_OFFSET; + } else if ((line + VX6953_STM5M0EDOF_OFFSET) > frame_length_lines) { + frame_length_lines = line + VX6953_STM5M0EDOF_OFFSET; + line = frame_length_lines; + } + + frame_length_lines_hi = (uint8_t) ((frame_length_lines & + 0xFF00) >> 8); + frame_length_lines_lo = (uint8_t) (frame_length_lines & + 0x00FF); + vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI, + frame_length_lines_hi); + vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO, + frame_length_lines_lo); + + /* update analogue gain registers */ + gain_hi = (uint8_t) ((gain & 0xFF00) >> 8); + gain_lo = (uint8_t) (gain & 0x00FF); + vx6953_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + gain_lo); + vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_GREEN_R_LO, gain_hi); + vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_RED_LO, gain_hi); + vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_BLUE_LO, gain_hi); + vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_GREEN_B_LO, gain_hi); + CDBG("%s, gain_hi 0x%x, gain_lo 0x%x\n", __func__, + gain_hi, gain_lo); + /* update line count registers */ + intg_time_hi = (uint8_t) (((uint16_t)line & 0xFF00) >> 8); + intg_time_lo = (uint8_t) ((uint16_t)line & 0x00FF); + vx6953_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_HI, + intg_time_hi); + vx6953_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LO, + intg_time_lo); + vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF); + + return rc; +} + +static int32_t vx6953_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + rc = vx6953_write_exp_gain(gain, line); + return rc; +} /* endof vx6953_set_pict_exp_gain*/ + +static int32_t vx6953_move_focus(int direction, + int32_t num_steps) +{ + return 0; +} + + +static int32_t vx6953_set_default_focus(uint8_t af_step) +{ + return 0; +} + +static int32_t vx6953_test(enum vx6953_test_mode_t mo) +{ + int32_t rc = 0; + if (mo == TEST_OFF) + return rc; + else { + /* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation, + 1: Bypass Signal Processing + REG_0x30D8[5] is EBDMASK: 0: + Output Embedded data, 1: No output embedded data */ + if (vx6953_i2c_write_b_sensor(REG_TEST_PATTERN_MODE, + (uint8_t) mo) < 0) { + return rc; + } + } + return rc; +} + +static int vx6953_enable_edof(enum edof_mode_t edof_mode) +{ + int rc = 0; + if (edof_mode == VX6953_EDOF_ESTIMATION) { + /* EDof Estimation mode for preview */ + if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x02) < 0) + return rc; + CDBG("VX6953_EDOF_ESTIMATION"); + } else if (edof_mode == VX6953_EDOF_APPLICATION) { + /* EDof Application mode for Capture */ + if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x01) < 0) + return rc; + CDBG("VX6953_EDOF_APPLICATION"); + } else { + /* EDOF disabled */ + if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x00) < 0) + return rc; + CDBG("VX6953_EDOF_DISABLE"); + } + return rc; +} + +static int32_t vx6953_patch_for_cut2(void) +{ + int32_t rc = 0; + rc = vx6953_i2c_write_w_table(patch_tbl_cut2, + ARRAY_SIZE(patch_tbl_cut2)); + if (rc < 0) + return rc; + + return rc; +} + +static int32_t vx6953_lsc_patch(void) +{ + int32_t rc = 0; + int i, j; + short int v; + unsigned short version = 0; + unsigned short LSC_Raw[NUM_LSC_CAST_REGS]; + unsigned short LSC_Fixed[NUM_LSC_CAST_REGS]; + + vx6953_i2c_read(0x10, &version, 1); + CDBG("Cut 3 Version %d\n", version); + if (version != 1) + return 0; + + vx6953_i2c_write_b_sensor(0x3640, 0x00); + for (j = cast_H; j < cast_MAX; j++) { + for (i = 0; i < NUM_LSC_CAST_REGS; i++) { + rc = vx6953_i2c_read(LSC_CastRegs[cast_D]+(2*i), + &LSC_Raw[i], 2); + if (rc < 0) + return rc; + v = LSC_Raw[i]; + v += LSC_CorrectionForCast[j][i]; + LSC_Fixed[i] = (unsigned short) v; + } + for (i = 0; i < NUM_LSC_CAST_REGS; i++) { + rc = vx6953_i2c_write_w_sensor(LSC_CastRegs[j]+(2*i), + LSC_Fixed[i]); + if (rc < 0) + return rc; + } + } + CDBG("vx6953_lsc_patch done\n"); + return rc; +} + +static int32_t vx6953_sensor_setting(int update_type, int rt) +{ + + int32_t rc = 0; + unsigned short frame_cnt; + struct msm_camera_csi_params vx6953_csi_params; + if (vx6953_ctrl->sensor_type != VX6953_STM5M0EDOF_CUT_2) { + switch (update_type) { + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct vx6953_i2c_reg_conf init_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0]. + reg_0x0112}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0]. + reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {0x303, 0x01}, + {0x30b, 0x01}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + {REG_0x3210, 0x01}, + {REG_0x0111, + vx6953_regs.reg_pat_init[0]. + reg_0x0111}, + {REG_0x0b00, + vx6953_regs.reg_pat_init[0]. + reg_0x0b00}, + {REG_0x0136, + vx6953_regs.reg_pat_init[0]. + reg_0x0136}, + {REG_0x0137, + vx6953_regs.reg_pat_init[0]. + reg_0x0137}, + {REG_0x0b06, + vx6953_regs.reg_pat_init[0]. + reg_0x0b06}, + {REG_0x0b07, + vx6953_regs.reg_pat_init[0]. + reg_0x0b07}, + {REG_0x0b08, + vx6953_regs.reg_pat_init[0]. + reg_0x0b08}, + {REG_0x0b09, + vx6953_regs.reg_pat_init[0]. + reg_0x0b09}, + {REG_0x0b83, + vx6953_regs.reg_pat_init[0]. + reg_0x0b83}, + {REG_0x0b84, + vx6953_regs.reg_pat_init[0]. + reg_0x0b84}, + {REG_0x0b85, + vx6953_regs.reg_pat_init[0]. + reg_0x0b85}, + {REG_0x0b88, + vx6953_regs.reg_pat_init[0]. + reg_0x0b88}, + {REG_0x0b89, + vx6953_regs.reg_pat_init[0]. + reg_0x0b89}, + {REG_0x0b8a, + vx6953_regs.reg_pat_init[0]. + reg_0x0b8a}, + {0x3393, 0x06}, + {0x3394, 0x07}, + {0x338d, 0x08}, + {0x338e, 0x08}, + {0x338f, 0x00}, + }; + /* reset fps_divider */ + vx6953_ctrl->fps = 30 * Q8; + /* stop streaming */ + + count = 0; + CDBG("Init vx6953_sensor_setting standby\n"); + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + + rc = vx6953_i2c_write_w_table(cut3_cali_data, + ARRAY_SIZE(cut3_cali_data)); + + vx6953_lsc_patch(); + + vx6953_i2c_write_w_sensor(0x100A, 0x07A3); + vx6953_i2c_write_w_sensor(0x114A, 0x002A); + vx6953_i2c_write_w_sensor(0x1716, 0x0204); + vx6953_i2c_write_w_sensor(0x1718, 0x0880); + + rc = vx6953_i2c_write_w_table(&init_tbl[0], + ARRAY_SIZE(init_tbl)); + if (rc < 0) + return rc; + + msleep(10); + + } + return rc; + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct vx6953_i2c_reg_conf preview_mode_tbl[] = { + {0x200, 0x02}, + {0x201, 0x26}, + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_0x0b80, + vx6953_regs.reg_pat[rt]. + reg_0x0b80}, + {REG_0x0900, + vx6953_regs.reg_pat[rt]. + reg_0x0900}, + {REG_0x0901, + vx6953_regs.reg_pat[rt]. + reg_0x0901}, + {REG_0x0902, + vx6953_regs.reg_pat[rt]. + reg_0x0902}, + {REG_0x0383, + vx6953_regs.reg_pat[rt]. + reg_0x0383}, + {REG_0x0387, + vx6953_regs.reg_pat[rt]. + reg_0x0387}, + {REG_0x034c, + vx6953_regs.reg_pat[rt]. + reg_0x034c}, + {REG_0x034d, + vx6953_regs.reg_pat[rt]. + reg_0x034d}, + {REG_0x034e, + vx6953_regs.reg_pat[rt]. + reg_0x034e}, + {REG_0x034f, + vx6953_regs.reg_pat[rt]. + reg_0x034f}, + {REG_0x3640, 0x00}, + }; + + struct vx6953_i2c_reg_conf snapshot_mode_tbl[] = { + {0x0200, 0x02}, + {0x0201, 0x54}, + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_0x0b80, + vx6953_regs.reg_pat[rt]. + reg_0x0b80}, + {REG_0x0900, + vx6953_regs.reg_pat[rt]. + reg_0x0900}, + {REG_0x0901, + vx6953_regs.reg_pat[rt]. + reg_0x0901}, + {REG_0x0902, + vx6953_regs.reg_pat[rt]. + reg_0x0902}, + {REG_0x0383, + vx6953_regs.reg_pat[rt]. + reg_0x0383}, + {REG_0x0387, + vx6953_regs.reg_pat[rt]. + reg_0x0387}, + {REG_0x034c, + vx6953_regs.reg_pat[rt]. + reg_0x034c}, + {REG_0x034d, + vx6953_regs.reg_pat[rt]. + reg_0x034d}, + {REG_0x034e, + vx6953_regs.reg_pat[rt]. + reg_0x034e}, + {REG_0x034f, + vx6953_regs.reg_pat[rt]. + reg_0x034f}, + {0x3140, 0x01}, + {REG_0x3640, 0x00}, + }; + /* stop streaming */ + + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + if (count == 0) { + vx6953_csi_params.data_format = CSI_8BIT; + vx6953_csi_params.lane_cnt = 1; + vx6953_csi_params.lane_assign = 0xe4; + vx6953_csi_params.dpcm_scheme = 0; + vx6953_csi_params.settle_cnt = 7; + rc = msm_camio_csi_config(&vx6953_csi_params); + if (rc < 0) + CDBG("config csi controller failed\n"); + + msleep(20); + count = 1; + } + + vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + + if (rt == RES_PREVIEW) { + rc = vx6953_i2c_write_w_table( + &preview_mode_tbl[0], + ARRAY_SIZE(preview_mode_tbl)); + if (rc < 0) + return rc; + } + if (rt == RES_CAPTURE) { + rc = vx6953_i2c_write_w_table( + &snapshot_mode_tbl[0], + ARRAY_SIZE(snapshot_mode_tbl)); + if (rc < 0) + return rc; + } + + vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF); + + /* Start sensor streaming */ + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STREAM) < 0) + return rc; + msleep(10); + + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + + while (frame_cnt == 0xFF) { + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + CDBG("frame_cnt=%d\n", frame_cnt); + msleep(2); + } + } + return rc; + default: + return rc; + } + } else { + switch (update_type) { + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct vx6953_i2c_reg_conf init_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + {REG_0x3030, + vx6953_regs.reg_pat_init[0].reg_0x3030}, + /* 953 specific registers */ + {REG_0x0111, + vx6953_regs.reg_pat_init[0].reg_0x0111}, + {REG_0x0b00, + vx6953_regs.reg_pat_init[0].reg_0x0b00}, + {REG_0x3001, + vx6953_regs.reg_pat_init[0].reg_0x3001}, + {REG_0x3004, + vx6953_regs.reg_pat_init[0].reg_0x3004}, + {REG_0x3007, + vx6953_regs.reg_pat_init[0].reg_0x3007}, + {REG_0x3016, + vx6953_regs.reg_pat_init[0].reg_0x3016}, + {REG_0x301d, + vx6953_regs.reg_pat_init[0].reg_0x301d}, + {REG_0x317e, + vx6953_regs.reg_pat_init[0].reg_0x317e}, + {REG_0x317f, + vx6953_regs.reg_pat_init[0].reg_0x317f}, + {REG_0x3400, + vx6953_regs.reg_pat_init[0].reg_0x3400}, + /* DEFCOR settings */ + /*Single Defect Correction Weight DISABLE*/ + {0x0b06, + vx6953_regs.reg_pat_init[0].reg_0x0b06}, + /*Single_defect_correct_weight = auto*/ + {0x0b07, + vx6953_regs.reg_pat_init[0].reg_0x0b07}, + /*Dynamic couplet correction ENABLED*/ + {0x0b08, + vx6953_regs.reg_pat_init[0].reg_0x0b08}, + /*Dynamic couplet correction weight*/ + {0x0b09, + vx6953_regs.reg_pat_init[0].reg_0x0b09}, + /* Clock Setup */ + /* Tell sensor ext clk is 24MHz*/ + {0x0136, + vx6953_regs.reg_pat_init[0].reg_0x0136}, + {0x0137, + vx6953_regs.reg_pat_init[0].reg_0x0137}, + /* The white balance gains must be written + to the sensor every frame. */ + /* Edof */ + {REG_0x0b83, + vx6953_regs.reg_pat_init[0].reg_0x0b83}, + {REG_0x0b84, + vx6953_regs.reg_pat_init[0].reg_0x0b84}, + {0x0b85, + vx6953_regs.reg_pat_init[0].reg_0x0b85}, + {0x0b88, + vx6953_regs.reg_pat_init[0].reg_0x0b88}, + {0x0b89, + vx6953_regs.reg_pat_init[0].reg_0x0b89}, + {REG_0x0b8a, + vx6953_regs.reg_pat_init[0].reg_0x0b8a}, + /* Mode specific regieters */ + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_0x3005, + vx6953_regs.reg_pat[rt].reg_0x3005}, + {0x3010, + vx6953_regs.reg_pat[rt].reg_0x3010}, + {REG_0x3011, + vx6953_regs.reg_pat[rt].reg_0x3011}, + {REG_0x301a, + vx6953_regs.reg_pat[rt].reg_0x301a}, + {REG_0x3035, + vx6953_regs.reg_pat[rt].reg_0x3035}, + {REG_0x3036, + vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3041, + vx6953_regs.reg_pat[rt].reg_0x3041}, + {0x3042, + vx6953_regs.reg_pat[rt].reg_0x3042}, + {REG_0x3045, + vx6953_regs.reg_pat[rt].reg_0x3045}, + /*EDOF: Estimation settings for Preview mode + Application settings for capture mode + (standard settings - Not tuned) */ + {REG_0x0b80, + vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0900, + vx6953_regs.reg_pat[rt].reg_0x0900}, + {REG_0x0901, + vx6953_regs.reg_pat[rt].reg_0x0901}, + {REG_0x0902, + vx6953_regs.reg_pat[rt].reg_0x0902}, + {REG_0x0383, + vx6953_regs.reg_pat[rt].reg_0x0383}, + {REG_0x0387, + vx6953_regs.reg_pat[rt].reg_0x0387}, + /* Change output size / frame rate */ + {REG_0x034c, + vx6953_regs.reg_pat[rt].reg_0x034c}, + {REG_0x034d, + vx6953_regs.reg_pat[rt].reg_0x034d}, + {REG_0x034e, + vx6953_regs.reg_pat[rt].reg_0x034e}, + {REG_0x034f, + vx6953_regs.reg_pat[rt].reg_0x034f}, + {REG_0x1716, + vx6953_regs.reg_pat[rt].reg_0x1716}, + {REG_0x1717, + vx6953_regs.reg_pat[rt].reg_0x1717}, + {REG_0x1718, + vx6953_regs.reg_pat[rt].reg_0x1718}, + {REG_0x1719, + vx6953_regs.reg_pat[rt].reg_0x1719}, + }; + /* reset fps_divider */ + vx6953_ctrl->fps = 30 * Q8; + /* stop streaming */ + + /* Reset everything first */ + if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) { + CDBG("S/W reset failed\n"); + return rc; + } else + CDBG("S/W reset successful\n"); + + msleep(10); + + CDBG("Init vx6953_sensor_setting standby\n"); + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + /*vx6953_stm5m0edof_delay_msecs_stdby*/ + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + vx6953_patch_for_cut2(); + rc = vx6953_i2c_write_w_table(&init_tbl[0], + ARRAY_SIZE(init_tbl)); + if (rc < 0) + return rc; + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + } + return rc; + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct vx6953_i2c_reg_conf init_mode_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + {REG_0x3030, + vx6953_regs.reg_pat_init[0].reg_0x3030}, + /* 953 specific registers */ + {REG_0x0111, + vx6953_regs.reg_pat_init[0].reg_0x0111}, + {REG_0x0b00, + vx6953_regs.reg_pat_init[0].reg_0x0b00}, + {REG_0x3001, + vx6953_regs.reg_pat_init[0].reg_0x3001}, + {REG_0x3004, + vx6953_regs.reg_pat_init[0].reg_0x3004}, + {REG_0x3007, + vx6953_regs.reg_pat_init[0].reg_0x3007}, + {REG_0x3016, + vx6953_regs.reg_pat_init[0].reg_0x3016}, + {REG_0x301d, + vx6953_regs.reg_pat_init[0].reg_0x301d}, + {REG_0x317e, + vx6953_regs.reg_pat_init[0].reg_0x317e}, + {REG_0x317f, + vx6953_regs.reg_pat_init[0].reg_0x317f}, + {REG_0x3400, + vx6953_regs.reg_pat_init[0].reg_0x3400}, + {0x0b06, + vx6953_regs.reg_pat_init[0].reg_0x0b06}, + /*Single_defect_correct_weight = auto*/ + {0x0b07, + vx6953_regs.reg_pat_init[0].reg_0x0b07}, + /*Dynamic couplet correction ENABLED*/ + {0x0b08, + vx6953_regs.reg_pat_init[0].reg_0x0b08}, + /*Dynamic couplet correction weight*/ + {0x0b09, + vx6953_regs.reg_pat_init[0].reg_0x0b09}, + /* Clock Setup */ + /* Tell sensor ext clk is 24MHz*/ + {0x0136, + vx6953_regs.reg_pat_init[0].reg_0x0136}, + {0x0137, + vx6953_regs.reg_pat_init[0].reg_0x0137}, + /* The white balance gains must be written + to the sensor every frame. */ + /* Edof */ + {REG_0x0b83, + vx6953_regs.reg_pat_init[0].reg_0x0b83}, + {REG_0x0b84, + vx6953_regs.reg_pat_init[0].reg_0x0b84}, + {0x0b85, + vx6953_regs.reg_pat_init[0].reg_0x0b85}, + {0x0b88, + vx6953_regs.reg_pat_init[0].reg_0x0b88}, + {0x0b89, + vx6953_regs.reg_pat_init[0].reg_0x0b89}, + {REG_0x0b8a, + vx6953_regs.reg_pat_init[0].reg_0x0b8a}, + /* Mode specific regieters */ + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_0x3005, + vx6953_regs.reg_pat[rt].reg_0x3005}, + {0x3010, + vx6953_regs.reg_pat[rt].reg_0x3010}, + {REG_0x3011, + vx6953_regs.reg_pat[rt].reg_0x3011}, + {REG_0x301a, + vx6953_regs.reg_pat[rt].reg_0x301a}, + {REG_0x3035, + vx6953_regs.reg_pat[rt].reg_0x3035}, + {REG_0x3036, + vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3041, + vx6953_regs.reg_pat[rt].reg_0x3041}, + {0x3042, + vx6953_regs.reg_pat[rt].reg_0x3042}, + {REG_0x3045, + vx6953_regs.reg_pat[rt].reg_0x3045}, + /*EDOF: Estimation settings for Preview mode + Application settings for capture mode + (standard settings - Not tuned) */ + {REG_0x0b80, + vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0900, + vx6953_regs.reg_pat[rt].reg_0x0900}, + {REG_0x0901, + vx6953_regs.reg_pat[rt].reg_0x0901}, + {REG_0x0902, + vx6953_regs.reg_pat[rt].reg_0x0902}, + {REG_0x0383, + vx6953_regs.reg_pat[rt].reg_0x0383}, + {REG_0x0387, + vx6953_regs.reg_pat[rt].reg_0x0387}, + /* Change output size / frame rate */ + {REG_0x034c, + vx6953_regs.reg_pat[rt].reg_0x034c}, + {REG_0x034d, + vx6953_regs.reg_pat[rt].reg_0x034d}, + {REG_0x034e, + vx6953_regs.reg_pat[rt].reg_0x034e}, + {REG_0x034f, + vx6953_regs.reg_pat[rt].reg_0x034f}, + {REG_0x1716, + vx6953_regs.reg_pat[rt].reg_0x1716}, + {REG_0x1717, + vx6953_regs.reg_pat[rt].reg_0x1717}, + {REG_0x1718, + vx6953_regs.reg_pat[rt].reg_0x1718}, + {REG_0x1719, + vx6953_regs.reg_pat[rt].reg_0x1719}, + }; + struct vx6953_i2c_reg_conf mode_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + /* Mode specific regieters */ + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt].frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt].frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt].line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt].line_length_pck_lo}, + {REG_0x3005, vx6953_regs.reg_pat[rt].reg_0x3005}, + {0x3010, vx6953_regs.reg_pat[rt].reg_0x3010}, + {REG_0x3011, vx6953_regs.reg_pat[rt].reg_0x3011}, + {REG_0x301a, vx6953_regs.reg_pat[rt].reg_0x301a}, + {REG_0x3035, vx6953_regs.reg_pat[rt].reg_0x3035}, + {REG_0x3036, vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3041, vx6953_regs.reg_pat[rt].reg_0x3041}, + {0x3042, vx6953_regs.reg_pat[rt].reg_0x3042}, + {REG_0x3045, vx6953_regs.reg_pat[rt].reg_0x3045}, + /*EDOF: Estimation settings for Preview mode + Application settings for capture + mode(standard settings - Not tuned) */ + {REG_0x0b80, vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0900, vx6953_regs.reg_pat[rt].reg_0x0900}, + {REG_0x0901, vx6953_regs.reg_pat[rt].reg_0x0901}, + {REG_0x0902, vx6953_regs.reg_pat[rt].reg_0x0902}, + {REG_0x0383, vx6953_regs.reg_pat[rt].reg_0x0383}, + {REG_0x0387, vx6953_regs.reg_pat[rt].reg_0x0387}, + /* Change output size / frame rate */ + {REG_0x034c, vx6953_regs.reg_pat[rt].reg_0x034c}, + {REG_0x034d, vx6953_regs.reg_pat[rt].reg_0x034d}, + {REG_0x034e, vx6953_regs.reg_pat[rt].reg_0x034e}, + {REG_0x034f, vx6953_regs.reg_pat[rt].reg_0x034f}, + /*{0x200, vx6953_regs.reg_pat[rt].reg_0x0200}, + {0x201, vx6953_regs.reg_pat[rt].reg_0x0201},*/ + {REG_0x1716, vx6953_regs.reg_pat[rt].reg_0x1716}, + {REG_0x1717, vx6953_regs.reg_pat[rt].reg_0x1717}, + {REG_0x1718, vx6953_regs.reg_pat[rt].reg_0x1718}, + {REG_0x1719, vx6953_regs.reg_pat[rt].reg_0x1719}, + }; + /* stop streaming */ + msleep(5); + + /* Reset everything first */ + if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) { + CDBG("S/W reset failed\n"); + return rc; + } else + CDBG("S/W reset successful\n"); + + msleep(10); + + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + /*vx6953_stm5m0edof_delay_msecs_stdby*/ + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + + vx6953_csi_params.data_format = CSI_8BIT; + vx6953_csi_params.lane_cnt = 1; + vx6953_csi_params.lane_assign = 0xe4; + vx6953_csi_params.dpcm_scheme = 0; + vx6953_csi_params.settle_cnt = 7; + rc = msm_camio_csi_config(&vx6953_csi_params); + if (rc < 0) + return rc; + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + vx6953_patch_for_cut2(); + rc = vx6953_i2c_write_w_table(&init_mode_tbl[0], + ARRAY_SIZE(init_mode_tbl)); + if (rc < 0) + return rc; + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + rc = vx6953_i2c_write_w_table(&mode_tbl[0], + ARRAY_SIZE(mode_tbl)); + if (rc < 0) + return rc; + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + /* Start sensor streaming */ + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STREAM) < 0) + return rc; + msleep(vx6953_stm5m0edof_delay_msecs_stream); + + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + + while (frame_cnt == 0xFF) { + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + CDBG("frame_cnt=%d", frame_cnt); + msleep(10); + } + } + return rc; + default: + return rc; + } + } + return rc; +} + + +static int32_t vx6953_video_config(int mode) +{ + + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + if (vx6953_ctrl->curr_res != vx6953_ctrl->prev_res) { + if (vx6953_ctrl->prev_res == QTR_SIZE) { + rt = RES_PREVIEW; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((2 * 1000 * vx6953_ctrl->fps_divider) / + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } else { + rt = RES_CAPTURE; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((1000 * vx6953_ctrl->fps_divider) / + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } + if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + if (vx6953_ctrl->set_test) { + if (vx6953_test(vx6953_ctrl->set_test) < 0) + return rc; + } + vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION; + rc = vx6953_enable_edof(vx6953_ctrl->edof_mode); + if (rc < 0) + return rc; + vx6953_ctrl->curr_res = vx6953_ctrl->prev_res; + vx6953_ctrl->sensormode = mode; + return rc; +} + +static int32_t vx6953_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt; + /*change sensor resolution if needed */ + if (vx6953_ctrl->curr_res != vx6953_ctrl->pict_res) { + if (vx6953_ctrl->pict_res == QTR_SIZE) { + rt = RES_PREVIEW; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((2 * 1000 * vx6953_ctrl->fps_divider) / + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } else { + rt = RES_CAPTURE; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((1000 * vx6953_ctrl->fps_divider) / + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } + if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + + vx6953_ctrl->edof_mode = VX6953_EDOF_APPLICATION; + if (vx6953_enable_edof(vx6953_ctrl->edof_mode) < 0) + return rc; + vx6953_ctrl->curr_res = vx6953_ctrl->pict_res; + vx6953_ctrl->sensormode = mode; + return rc; +} /*end of vx6953_snapshot_config*/ + +static int32_t vx6953_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + if (vx6953_ctrl->curr_res != vx6953_ctrl->pict_res) { + if (vx6953_ctrl->pict_res == QTR_SIZE) { + rt = RES_PREVIEW; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((2 * 1000 * vx6953_ctrl->fps_divider)/ + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } else { + rt = RES_CAPTURE; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((1000 * vx6953_ctrl->fps_divider)/ + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } + if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + vx6953_ctrl->edof_mode = VX6953_EDOF_APPLICATION; + if (vx6953_enable_edof(vx6953_ctrl->edof_mode) < 0) + return rc; + vx6953_ctrl->curr_res = vx6953_ctrl->pict_res; + vx6953_ctrl->sensormode = mode; + return rc; +} /*end of vx6953_raw_snapshot_config*/ +static int32_t vx6953_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = vx6953_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + rc = vx6953_snapshot_config(mode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + rc = vx6953_raw_snapshot_config(mode); + break; + default: + rc = -EINVAL; + break; + } + return rc; +} +static int32_t vx6953_power_down(void) +{ + return 0; +} + + +static int vx6953_probe_init_done(const struct msm_camera_sensor_info *data) +{ + gpio_set_value_cansleep(data->sensor_reset, 0); + gpio_free(data->sensor_reset); + return 0; +} +static int vx6953_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + int32_t rc = 0; + unsigned short chipidl, chipidh; + CDBG("%s: %d\n", __func__, __LINE__); + rc = gpio_request(data->sensor_reset, "vx6953"); + CDBG(" vx6953_probe_init_sensor \n"); + if (!rc) { + CDBG("sensor_reset = %d\n", rc); + CDBG(" vx6953_probe_init_sensor 1\n"); + gpio_direction_output(data->sensor_reset, 0); + msleep(10); + CDBG(" vx6953_probe_init_sensor 1\n"); + gpio_set_value_cansleep(data->sensor_reset, 1); + } else { + CDBG(" vx6953_probe_init_sensor 2\n"); + goto init_probe_done; + } + msleep(20); + CDBG(" vx6953_probe_init_sensor is called\n"); + /* 3. Read sensor Model ID: */ + rc = vx6953_i2c_read(0x0000, &chipidh, 1); + if (rc < 0) { + CDBG(" vx6953_probe_init_sensor 3\n"); + goto init_probe_fail; + } + rc = vx6953_i2c_read(0x0001, &chipidl, 1); + if (rc < 0) { + CDBG(" vx6953_probe_init_sensor4\n"); + goto init_probe_fail; + } + CDBG("vx6953 model_id = 0x%x 0x%x\n", chipidh, chipidl); + /* 4. Compare sensor ID to VX6953 ID: */ + if (chipidh != 0x03 || chipidl != 0xB9) { + rc = -ENODEV; + CDBG("vx6953_probe_init_sensor fail chip id doesnot match\n"); + goto init_probe_fail; + } + goto init_probe_done; +init_probe_fail: + CDBG(" vx6953_probe_init_sensor fails\n"); + vx6953_probe_init_done(data); +init_probe_done: + CDBG(" vx6953_probe_init_sensor finishes\n"); + return rc; + } +/* camsensor_iu060f_vx6953_reset */ +int vx6953_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + unsigned short revision_number; + int32_t rc = 0; + + CDBG("%s: %d\n", __func__, __LINE__); + CDBG("Calling vx6953_sensor_open_init\n"); + vx6953_ctrl = kzalloc(sizeof(struct vx6953_ctrl_t), GFP_KERNEL); + if (!vx6953_ctrl) { + CDBG("vx6953_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + vx6953_ctrl->fps_divider = 1 * 0x00000400; + vx6953_ctrl->pict_fps_divider = 1 * 0x00000400; + vx6953_ctrl->set_test = TEST_OFF; + vx6953_ctrl->prev_res = QTR_SIZE; + vx6953_ctrl->pict_res = FULL_SIZE; + vx6953_ctrl->curr_res = INVALID_SIZE; + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2; + vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION; + if (data) + vx6953_ctrl->sensordata = data; + if (rc < 0) { + CDBG("Calling vx6953_sensor_open_init fail1\n"); + return rc; + } + CDBG("%s: %d\n", __func__, __LINE__); + /* enable mclk first */ + msm_camio_clk_rate_set(VX6953_STM5M0EDOF_DEFAULT_MASTER_CLK_RATE); + CDBG("%s: %d\n", __func__, __LINE__); + rc = vx6953_probe_init_sensor(data); + if (rc < 0) { + CDBG("Calling vx6953_sensor_open_init fail3\n"); + goto init_fail; + } + if (vx6953_i2c_read(0x0002, &revision_number, 1) < 0) + return rc; + CDBG("sensor revision number major = 0x%x\n", revision_number); + if (vx6953_i2c_read(0x0018, &revision_number, 1) < 0) + return rc; + CDBG("sensor revision number = 0x%x\n", revision_number); + if (revision_number == VX6953_REVISION_NUMBER_CUT3) { + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_3; + CDBG("VX6953 EDof Cut 3.0 sensor\n "); + } else if (revision_number == VX6953_REVISION_NUMBER_CUT2) { + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2; + CDBG("VX6953 EDof Cut 2.0 sensor\n "); + } else {/* Cut1.0 reads 0x00 for register 0x0018*/ + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_1; + CDBG("VX6953 EDof Cut 1.0 sensor\n "); + } + if (vx6953_ctrl->prev_res == QTR_SIZE) { + if (vx6953_sensor_setting(REG_INIT, RES_PREVIEW) < 0) + return rc; + } else { + if (vx6953_sensor_setting(REG_INIT, RES_CAPTURE) < 0) + return rc; + } + vx6953_ctrl->fps = 30*Q8; + if (rc < 0) + goto init_fail; + else + goto init_done; +init_fail: + CDBG("init_fail\n"); + vx6953_probe_init_done(data); + kfree(vx6953_ctrl); +init_done: + CDBG("init_done\n"); + return rc; +} /*endof vx6953_sensor_open_init*/ + +static int vx6953_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&vx6953_wait_queue); + return 0; +} + +static const struct i2c_device_id vx6953_i2c_id[] = { + {"vx6953", 0}, + { } +}; + +static int vx6953_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("vx6953_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + vx6953_sensorw = kzalloc(sizeof(struct vx6953_work_t), GFP_KERNEL); + if (!vx6953_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, vx6953_sensorw); + vx6953_init_client(client); + vx6953_client = client; + + msleep(50); + + CDBG("vx6953_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("vx6953_probe failed! rc = %d\n", rc); + return rc; +} + +static int vx6953_send_wb_info(struct wb_info_cfg *wb) +{ + unsigned short read_data; + uint8_t temp[8]; + int rc = 0; + int i = 0; + + /* red_gain */ + temp[2] = wb->red_gain >> 8; + temp[3] = wb->red_gain & 0xFF; + + /* green_gain */ + temp[0] = wb->green_gain >> 8; + temp[1] = wb->green_gain & 0xFF; + temp[6] = temp[0]; + temp[7] = temp[1]; + + /* blue_gain */ + temp[4] = wb->blue_gain >> 8; + temp[5] = wb->blue_gain & 0xFF; + rc = vx6953_i2c_write_seq_sensor(0x0B8E, &temp[0], 8); + + for (i = 0; i < 6; i++) { + rc = vx6953_i2c_read(0x0B8E + i, &read_data, 1); + CDBG("%s addr 0x%x val %d \n", __func__, 0x0B8E + i, read_data); + } + rc = vx6953_i2c_read(0x0B82, &read_data, 1); + CDBG("%s addr 0x%x val %d \n", __func__, 0x0B82, read_data); + if (rc < 0) + return rc; + return rc; +} /*end of vx6953_snapshot_config*/ + +static int __exit vx6953_remove(struct i2c_client *client) +{ + struct vx6953_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + vx6953_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver vx6953_i2c_driver = { + .id_table = vx6953_i2c_id, + .probe = vx6953_i2c_probe, + .remove = __exit_p(vx6953_i2c_remove), + .driver = { + .name = "vx6953", + }, +}; + +int vx6953_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&vx6953_mut); + CDBG("vx6953_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + vx6953_get_pict_fps( + cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = + vx6953_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = + vx6953_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = + vx6953_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + vx6953_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + vx6953_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = vx6953_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = + vx6953_write_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + rc = + vx6953_set_pict_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = vx6953_set_sensor_mode(cdata.mode, + cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = vx6953_power_down(); + break; + + case CFG_MOVE_FOCUS: + rc = + vx6953_move_focus( + cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = + vx6953_set_default_focus( + cdata.cfg.focus.steps); + break; + + case CFG_SET_EFFECT: + rc = vx6953_set_default_focus( + cdata.cfg.effect); + break; + + + case CFG_SEND_WB_INFO: + rc = vx6953_send_wb_info( + &(cdata.cfg.wb_info)); + break; + + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&vx6953_mut); + + return rc; +} + + + + +static int vx6953_sensor_release(void) +{ + int rc = -EBADF; + mutex_lock(&vx6953_mut); + vx6953_power_down(); + gpio_direction_output(vx6953_ctrl->sensordata->sensor_reset, 0); + gpio_free(vx6953_ctrl->sensordata->sensor_reset); + kfree(vx6953_ctrl); + vx6953_ctrl = NULL; + CDBG("vx6953_release completed\n"); + mutex_unlock(&vx6953_mut); + + return rc; +} + +static int vx6953_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(&vx6953_i2c_driver); + if (rc < 0 || vx6953_client == NULL) { + rc = -ENOTSUPP; + goto probe_fail; + } + msm_camio_clk_rate_set(24000000); + rc = vx6953_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + s->s_init = vx6953_sensor_open_init; + s->s_release = vx6953_sensor_release; + s->s_config = vx6953_sensor_config; + s->s_mount_angle = info->sensor_platform_info->mount_angle; + vx6953_probe_init_done(info); + return rc; + +probe_fail: + CDBG("vx6953_sensor_probe: SENSOR PROBE FAILS!\n"); + return rc; +} + +static int __vx6953_probe(struct platform_device *pdev) +{ + return msm_camera_drv_start(pdev, vx6953_sensor_probe); +} + +static struct platform_driver msm_camera_driver = { + .probe = __vx6953_probe, + .driver = { + .name = "msm_camera_vx6953", + .owner = THIS_MODULE, + }, +}; + +static int __init vx6953_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(vx6953_init); +void vx6953_exit(void) +{ + i2c_del_driver(&vx6953_i2c_driver); +} diff --git a/drivers/media/video/msm_zsl/vx6953.h b/drivers/media/video/msm_zsl/vx6953.h new file mode 100644 index 00000000000..0e120635a5d --- /dev/null +++ b/drivers/media/video/msm_zsl/vx6953.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef VX6953_H +#define VX6953_H +#include +#include +extern struct vx6953_reg vx6953_regs; +struct reg_struct_init { + uint8_t reg_0x0112; /* 0x0112*/ + uint8_t reg_0x0113; /* 0x0113*/ + uint8_t vt_pix_clk_div; /* 0x0301*/ + uint8_t pre_pll_clk_div; /* 0x0305*/ + uint8_t pll_multiplier; /* 0x0307*/ + uint8_t op_pix_clk_div; /* 0x0309*/ + uint8_t reg_0x3030; /*0x3030*/ + uint8_t reg_0x0111; /*0x0111*/ + uint8_t reg_0x0b00; /*0x0b00*/ + uint8_t reg_0x3001; /*0x3001*/ + uint8_t reg_0x3004; /*0x3004*/ + uint8_t reg_0x3007; /*0x3007*/ + uint8_t reg_0x3016; /*0x3016*/ + uint8_t reg_0x301d; /*0x301d*/ + uint8_t reg_0x317e; /*0x317E*/ + uint8_t reg_0x317f; /*0x317F*/ + uint8_t reg_0x3400; /*0x3400*/ + uint8_t reg_0x0b06; /*0x0b06*/ + uint8_t reg_0x0b07; /*0x0b07*/ + uint8_t reg_0x0b08; /*0x0b08*/ + uint8_t reg_0x0b09; /*0x0b09*/ + uint8_t reg_0x0136; + uint8_t reg_0x0137; + /* Edof */ + uint8_t reg_0x0b83; /*0x0b83*/ + uint8_t reg_0x0b84; /*0x0b84*/ + uint8_t reg_0x0b85; /*0x0b85*/ + uint8_t reg_0x0b88; /*0x0b88*/ + uint8_t reg_0x0b89; /*0x0b89*/ + uint8_t reg_0x0b8a; /*0x0b8a*/ + }; +struct reg_struct { + uint8_t coarse_integration_time_hi; /*REG_COARSE_INTEGRATION_TIME_HI*/ + uint8_t coarse_integration_time_lo; /*REG_COARSE_INTEGRATION_TIME_LO*/ + uint8_t analogue_gain_code_global; + uint8_t frame_length_lines_hi; /* 0x0340*/ + uint8_t frame_length_lines_lo; /* 0x0341*/ + uint8_t line_length_pck_hi; /* 0x0342*/ + uint8_t line_length_pck_lo; /* 0x0343*/ + uint8_t reg_0x3005; /* 0x3005*/ + uint8_t reg_0x3010; /* 0x3010*/ + uint8_t reg_0x3011; /* 0x3011*/ + uint8_t reg_0x301a; /* 0x301a*/ + uint8_t reg_0x3035; /* 0x3035*/ + uint8_t reg_0x3036; /* 0x3036*/ + uint8_t reg_0x3041; /*0x3041*/ + uint8_t reg_0x3042; /*0x3042*/ + uint8_t reg_0x3045; /*0x3045*/ + uint8_t reg_0x0b80; /* 0x0b80*/ + uint8_t reg_0x0900; /*0x0900*/ + uint8_t reg_0x0901; /* 0x0901*/ + uint8_t reg_0x0902; /*0x0902*/ + uint8_t reg_0x0383; /*0x0383*/ + uint8_t reg_0x0387; /* 0x0387*/ + uint8_t reg_0x034c; /* 0x034c*/ + uint8_t reg_0x034d; /*0x034d*/ + uint8_t reg_0x034e; /* 0x034e*/ + uint8_t reg_0x034f; /* 0x034f*/ + uint8_t reg_0x1716; /*0x1716*/ + uint8_t reg_0x1717; /*0x1717*/ + uint8_t reg_0x1718; /*0x1718*/ + uint8_t reg_0x1719; /*0x1719*/ + uint8_t reg_0x3210;/*0x3210*/ + uint8_t reg_0x111; /*0x111*/ + uint8_t reg_0x3410; /*0x3410*/ + uint8_t reg_0x3098; + uint8_t reg_0x309D; + uint8_t reg_0x0200; + uint8_t reg_0x0201; + }; +struct vx6953_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum vx6953_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum vx6953_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +enum vx6953_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum sensor_revision_t { + VX6953_STM5M0EDOF_CUT_1, + VX6953_STM5M0EDOF_CUT_2, + VX6953_STM5M0EDOF_CUT_3 +}; +enum edof_mode_t { + VX6953_EDOF_DISABLE, /* 0x00 */ + VX6953_EDOF_APPLICATION, /* 0x01 */ + VX6953_EDOF_ESTIMATION /* 0x02 */ +}; +struct vx6953_reg { + const struct reg_struct_init *reg_pat_init; + const struct reg_struct *reg_pat; +}; +#endif /* VX6953_H */ diff --git a/drivers/media/video/msm_zsl/vx6953_reg.c b/drivers/media/video/msm_zsl/vx6953_reg.c new file mode 100644 index 00000000000..48fc71f5bf4 --- /dev/null +++ b/drivers/media/video/msm_zsl/vx6953_reg.c @@ -0,0 +1,135 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + + +#include "vx6953.h" +const struct reg_struct_init vx6953_reg_init[1] = { + { + 10, /*REG = 0x0112 , 10 bit */ + 10, /*REG = 0x0113*/ + 9, /*REG = 0x0301 vt_pix_clk_div*/ + 4, /*REG = 0x0305 pre_pll_clk_div*/ + 133, /*REG = 0x0307 pll_multiplier*/ + 10, /*REG = 0x0309 op_pix_clk_div*/ + 0x08, /*REG = 0x3030*/ + 0x02, /*REG = 0x0111*/ + 0x01, /*REG = 0x0b00 ,lens shading off */ + 0x30, /*REG = 0x3001*/ + 0x33, /*REG = 0x3004*/ + 0x09, /*REG = 0x3007*/ + 0x1F, /*REG = 0x3016*/ + 0x03, /*REG = 0x301d*/ + 0x11, /*REG = 0x317E*/ + 0x09, /*REG = 0x317F*/ + 0x38, /*REG = 0x3400*/ + 0x00, /*REG_0x0b06*/ + 0x80, /*REG_0x0b07*/ + 0x01, /*REG_0x0b08*/ + 0x4F, /*REG_0x0b09*/ + 0x18, /*REG_0x0136*/ + 0x00, /*/REG_0x0137*/ + 0x20, /*REG = 0x0b83*/ + 0x90, /*REG = 0x0b84*/ + 0x20, /*REG = 0x0b85*/ + 0x80, /*REG = 0x0b88*/ + 0x00, /*REG = 0x0b89*/ + 0x00, /*REG = 0x0b8a*/ + } +}; +const struct reg_struct vx6953_reg_pat[2] = { + {/* Preview */ + 0x03, /*REG = 0x0202 coarse integration_time_hi*/ + 0xd0, /*REG = 0x0203 coarse_integration_time_lo*/ + 0xc0, /*REG = 0x0205 analogue_gain_code_global*/ + 0x03, /*REG = 0x0340 frame_length_lines_hi*/ + 0xf0, /*REG = 0x0341 frame_length_lines_lo*/ + 0x0b, /*REG = 0x0342 line_length_pck_hi*/ + 0x74, /*REG = 0x0343 line_length_pck_lo*/ + 0x03, /*REG = 0x3005*/ + 0x00, /*REG = 0x3010*/ + 0x01, /*REG = 0x3011*/ + 0x6a, /*REG = 0x301a*/ + 0x03, /*REG = 0x3035*/ + 0x2c, /*REG = 0x3036*/ + 0x00, /*REG = 0x3041*/ + 0x24, /*REG = 0x3042*/ + 0x81, /*REG = 0x3045*/ + 0x02, /*REG = 0x0b80 edof estimate*/ + 0x01, /*REG = 0x0900*/ + 0x22, /*REG = 0x0901*/ + 0x04, /*REG = 0x0902*/ + 0x03, /*REG = 0x0383*/ + 0x03, /*REG = 0x0387*/ + 0x05, /*REG = 0x034c*/ + 0x18, /*REG = 0x034d*/ + 0x03, /*REG = 0x034e*/ + 0xd4, /*REG = 0x034f*/ + 0x02, /*0x1716*/ + 0x04, /*0x1717*/ + 0x08, /*0x1718*/ + 0x2c, /*0x1719*/ + 0x01, /*0x3210*/ + 0x02, /*0x111*/ + 0x01, /*0x3410*/ + 0x01, /*0x3098*/ + 0x05, /*0x309D*/ + 0x02, + 0x04, + }, + { /* Snapshot */ + 0x07,/*REG = 0x0202 coarse_integration_time_hi*/ + 0x00,/*REG = 0x0203 coarse_integration_time_lo*/ + 0xc0,/*REG = 0x0205 analogue_gain_code_global*/ + 0x07,/*REG = 0x0340 frame_length_lines_hi*/ + 0xd0,/*REG = 0x0341 frame_length_lines_lo*/ + 0x0b,/*REG = 0x0342 line_length_pck_hi*/ + 0x8c,/*REG = 0x0343 line_length_pck_lo*/ + 0x01,/*REG = 0x3005*/ + 0x00,/*REG = 0x3010*/ + 0x00,/*REG = 0x3011*/ + 0x55,/*REG = 0x301a*/ + 0x01,/*REG = 0x3035*/ + 0x23,/*REG = 0x3036*/ + 0x00,/*REG = 0x3041*/ + 0x24,/*REG = 0x3042*/ + 0xb7,/*REG = 0x3045*/ + 0x01,/*REG = 0x0b80 edof application*/ + 0x00,/*REG = 0x0900*/ + 0x00,/*REG = 0x0901*/ + 0x00,/*REG = 0x0902*/ + 0x01,/*REG = 0x0383*/ + 0x01,/*REG = 0x0387*/ + 0x0A,/*REG = 0x034c*/ + 0x30,/*REG = 0x034d*/ + 0x07,/*REG = 0x034e*/ + 0xA8,/*REG = 0x034f*/ + 0x02,/*0x1716*/ + 0x0d,/*0x1717*/ + 0x07,/*0x1718*/ + 0x7d,/*0x1719*/ + 0x01,/*0x3210*/ + 0x02,/*0x111*/ + 0x01,/*0x3410*/ + 0x01,/*0x3098*/ + 0x05, /*0x309D*/ + 0x02, + 0x00, + } +}; + + + +struct vx6953_reg vx6953_regs = { + .reg_pat_init = &vx6953_reg_init[0], + .reg_pat = &vx6953_reg_pat[0], +}; diff --git a/drivers/media/video/msm_zsl/vx6953_reg_v4l2.c b/drivers/media/video/msm_zsl/vx6953_reg_v4l2.c new file mode 100644 index 00000000000..f16054b6865 --- /dev/null +++ b/drivers/media/video/msm_zsl/vx6953_reg_v4l2.c @@ -0,0 +1,135 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + + +#include "vx6953_v4l2.h" +const struct reg_struct_init vx6953_reg_init[1] = { + { + 10, /*REG = 0x0112 , 10 bit */ + 10, /*REG = 0x0113*/ + 9, /*REG = 0x0301 vt_pix_clk_div*/ + 4, /*REG = 0x0305 pre_pll_clk_div*/ + 133, /*REG = 0x0307 pll_multiplier*/ + 10, /*REG = 0x0309 op_pix_clk_div*/ + 0x08, /*REG = 0x3030*/ + 0x02, /*REG = 0x0111*/ + 0x01, /*REG = 0x0b00 ,lens shading off */ + 0x30, /*REG = 0x3001*/ + 0x33, /*REG = 0x3004*/ + 0x09, /*REG = 0x3007*/ + 0x1F, /*REG = 0x3016*/ + 0x03, /*REG = 0x301d*/ + 0x11, /*REG = 0x317E*/ + 0x09, /*REG = 0x317F*/ + 0x38, /*REG = 0x3400*/ + 0x00, /*REG_0x0b06*/ + 0x80, /*REG_0x0b07*/ + 0x01, /*REG_0x0b08*/ + 0x4F, /*REG_0x0b09*/ + 0x18, /*REG_0x0136*/ + 0x00, /*/REG_0x0137*/ + 0x20, /*REG = 0x0b83*/ + 0x90, /*REG = 0x0b84*/ + 0x20, /*REG = 0x0b85*/ + 0x80, /*REG = 0x0b88*/ + 0x00, /*REG = 0x0b89*/ + 0x00, /*REG = 0x0b8a*/ + } +}; +const struct reg_struct vx6953_reg_pat[2] = { + {/* Preview */ + 0x03, /*REG = 0x0202 coarse integration_time_hi*/ + 0xd0, /*REG = 0x0203 coarse_integration_time_lo*/ + 0xc0, /*REG = 0x0205 analogue_gain_code_global*/ + 0x03, /*REG = 0x0340 frame_length_lines_hi*/ + 0xf0, /*REG = 0x0341 frame_length_lines_lo*/ + 0x0b, /*REG = 0x0342 line_length_pck_hi*/ + 0xa5, /*REG = 0x0343 line_length_pck_lo*/ + 0x03, /*REG = 0x3005*/ + 0x00, /*REG = 0x3010*/ + 0x01, /*REG = 0x3011*/ + 0x6a, /*REG = 0x301a*/ + 0x03, /*REG = 0x3035*/ + 0x2c, /*REG = 0x3036*/ + 0x00, /*REG = 0x3041*/ + 0x24, /*REG = 0x3042*/ + 0x81, /*REG = 0x3045*/ + 0x02, /*REG = 0x0b80 edof estimate*/ + 0x01, /*REG = 0x0900*/ + 0x22, /*REG = 0x0901*/ + 0x04, /*REG = 0x0902*/ + 0x03, /*REG = 0x0383*/ + 0x03, /*REG = 0x0387*/ + 0x05, /*REG = 0x034c*/ + 0x18, /*REG = 0x034d*/ + 0x03, /*REG = 0x034e*/ + 0xd4, /*REG = 0x034f*/ + 0x02, /*0x1716*/ + 0x04, /*0x1717*/ + 0x08, /*0x1718*/ + 0x80, /*0x1719*/ + 0x01, /*0x3210*/ + 0x02, /*0x111*/ + 0x01, /*0x3410*/ + 0x01, /*0x3098*/ + 0x05, /*0x309D*/ + 0x02, + 0x04, + }, + { /* Snapshot */ + 0x07,/*REG = 0x0202 coarse_integration_time_hi*/ + 0x00,/*REG = 0x0203 coarse_integration_time_lo*/ + 0xc0,/*REG = 0x0205 analogue_gain_code_global*/ + 0x07,/*REG = 0x0340 frame_length_lines_hi*/ + 0xd0,/*REG = 0x0341 frame_length_lines_lo*/ + 0x0b,/*REG = 0x0342 line_length_pck_hi*/ + 0x8c,/*REG = 0x0343 line_length_pck_lo*/ + 0x01,/*REG = 0x3005*/ + 0x00,/*REG = 0x3010*/ + 0x00,/*REG = 0x3011*/ + 0x55,/*REG = 0x301a*/ + 0x01,/*REG = 0x3035*/ + 0x23,/*REG = 0x3036*/ + 0x00,/*REG = 0x3041*/ + 0x24,/*REG = 0x3042*/ + 0xb7,/*REG = 0x3045*/ + 0x01,/*REG = 0x0b80 edof application*/ + 0x00,/*REG = 0x0900*/ + 0x00,/*REG = 0x0901*/ + 0x00,/*REG = 0x0902*/ + 0x01,/*REG = 0x0383*/ + 0x01,/*REG = 0x0387*/ + 0x0A,/*REG = 0x034c*/ + 0x30,/*REG = 0x034d*/ + 0x07,/*REG = 0x034e*/ + 0xA8,/*REG = 0x034f*/ + 0x02,/*0x1716*/ + 0x0d,/*0x1717*/ + 0x07,/*0x1718*/ + 0x7d,/*0x1719*/ + 0x01,/*0x3210*/ + 0x02,/*0x111*/ + 0x01,/*0x3410*/ + 0x01,/*0x3098*/ + 0x05, /*0x309D*/ + 0x02, + 0x00, + } +}; + + + +struct vx6953_reg vx6953_regs = { + .reg_pat_init = &vx6953_reg_init[0], + .reg_pat = &vx6953_reg_pat[0], +}; diff --git a/drivers/media/video/msm_zsl/vx6953_v4l2.c b/drivers/media/video/msm_zsl/vx6953_v4l2.c new file mode 100644 index 00000000000..24592c08d50 --- /dev/null +++ b/drivers/media/video/msm_zsl/vx6953_v4l2.c @@ -0,0 +1,4147 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vx6953_v4l2.h" +#include "msm.h" + +#define V4L2_IDENT_VX6953 50000 + +/*============================================================= + SENSOR REGISTER DEFINES +==============================================================*/ + +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define GROUPED_PARAMETER_HOLD_OFF 0x00 +#define GROUPED_PARAMETER_HOLD 0x01 +#define REG_MODE_SELECT 0x0100 +#define MODE_SELECT_STANDBY_MODE 0x00 +#define MODE_SELECT_STREAM 0x01 +/* Integration Time */ +#define REG_COARSE_INTEGRATION_TIME_HI 0x0202 +#define REG_COARSE_INTEGRATION_TIME_LO 0x0203 +/* Gain */ +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204 +#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205 +/* Digital Gain */ +#define REG_DIGITAL_GAIN_GREEN_R_HI 0x020E +#define REG_DIGITAL_GAIN_GREEN_R_LO 0x020F +#define REG_DIGITAL_GAIN_RED_HI 0x0210 +#define REG_DIGITAL_GAIN_RED_LO 0x0211 +#define REG_DIGITAL_GAIN_BLUE_HI 0x0212 +#define REG_DIGITAL_GAIN_BLUE_LO 0x0213 +#define REG_DIGITAL_GAIN_GREEN_B_HI 0x0214 +#define REG_DIGITAL_GAIN_GREEN_B_LO 0x0215 +/* output bits setting */ +#define REG_0x0112 0x0112 +#define REG_0x0113 0x0113 +/* PLL registers */ +#define REG_VT_PIX_CLK_DIV 0x0301 +#define REG_PRE_PLL_CLK_DIV 0x0305 +#define REG_PLL_MULTIPLIER 0x0307 +#define REG_OP_PIX_CLK_DIV 0x0309 +#define REG_0x034c 0x034c +#define REG_0x034d 0x034d +#define REG_0x034e 0x034e +#define REG_0x034f 0x034f +#define REG_0x0387 0x0387 +#define REG_0x0383 0x0383 +#define REG_FRAME_LENGTH_LINES_HI 0x0340 +#define REG_FRAME_LENGTH_LINES_LO 0x0341 +#define REG_LINE_LENGTH_PCK_HI 0x0342 +#define REG_LINE_LENGTH_PCK_LO 0x0343 +#define REG_0x3030 0x3030 +#define REG_0x0111 0x0111 +#define REG_0x0136 0x0136 +#define REG_0x0137 0x0137 +#define REG_0x0b00 0x0b00 +#define REG_0x3001 0x3001 +#define REG_0x3004 0x3004 +#define REG_0x3007 0x3007 +#define REG_0x301a 0x301a +#define REG_0x3101 0x3101 +#define REG_0x3364 0x3364 +#define REG_0x3365 0x3365 +#define REG_0x0b83 0x0b83 +#define REG_0x0b84 0x0b84 +#define REG_0x0b85 0x0b85 +#define REG_0x0b88 0x0b88 +#define REG_0x0b89 0x0b89 +#define REG_0x0b8a 0x0b8a +#define REG_0x3005 0x3005 +#define REG_0x3010 0x3010 +#define REG_0x3036 0x3036 +#define REG_0x3041 0x3041 +#define REG_0x0b80 0x0b80 +#define REG_0x0900 0x0900 +#define REG_0x0901 0x0901 +#define REG_0x0902 0x0902 +#define REG_0x3016 0x3016 +#define REG_0x301d 0x301d +#define REG_0x317e 0x317e +#define REG_0x317f 0x317f +#define REG_0x3400 0x3400 +#define REG_0x303a 0x303a +#define REG_0x1716 0x1716 +#define REG_0x1717 0x1717 +#define REG_0x1718 0x1718 +#define REG_0x1719 0x1719 +#define REG_0x3006 0x3006 +#define REG_0x301b 0x301b +#define REG_0x3098 0x3098 +#define REG_0x309d 0x309d +#define REG_0x3011 0x3011 +#define REG_0x3035 0x3035 +#define REG_0x3045 0x3045 +#define REG_0x3210 0x3210 +#define REG_0x0111 0x0111 +#define REG_0x3410 0x3410 +/* Test Pattern */ +#define REG_TEST_PATTERN_MODE 0x0601 + +/*============================================================================ + TYPE DECLARATIONS +============================================================================*/ + +/* 16bit address - 8 bit context register structure */ +#define VX6953_STM5M0EDOF_OFFSET 9 +#define Q8 0x00000100 +#define Q10 0x00000400 +#define VX6953_STM5M0EDOF_MAX_SNAPSHOT_EXPOSURE_LINE_COUNT 2922 +#define VX6953_STM5M0EDOF_DEFAULT_MASTER_CLK_RATE 24000000 +#define VX6953_STM5M0EDOF_OP_PIXEL_CLOCK_RATE 79800000 +#define VX6953_STM5M0EDOF_VT_PIXEL_CLOCK_RATE 88670000 +/* Full Size */ +#define VX6953_FULL_SIZE_WIDTH 2608 +#define VX6953_FULL_SIZE_HEIGHT 1960 +#define VX6953_FULL_SIZE_DUMMY_PIXELS 1 +#define VX6953_FULL_SIZE_DUMMY_LINES 0 +/* Quarter Size */ +#define VX6953_QTR_SIZE_WIDTH 1304 +#define VX6953_QTR_SIZE_HEIGHT 980 +#define VX6953_QTR_SIZE_DUMMY_PIXELS 1 +#define VX6953_QTR_SIZE_DUMMY_LINES 0 +/* Blanking as measured on the scope */ +/* Full Size */ +#define VX6953_HRZ_FULL_BLK_PIXELS 348 +#define VX6953_VER_FULL_BLK_LINES 40 +/* Quarter Size */ +#define VX6953_HRZ_QTR_BLK_PIXELS 1628 +#define VX6953_VER_QTR_BLK_LINES 28 +#define MAX_LINE_LENGTH_PCK 8190 +#define VX6953_REVISION_NUMBER_CUT2 0x10/*revision number for Cut2.0*/ +#define VX6953_REVISION_NUMBER_CUT3 0x20/*revision number for Cut3.0*/ +/* FIXME: Changes from here */ +struct vx6953_work_t { + struct work_struct work; +}; + +static struct vx6953_work_t *vx6953_sensorw; +static struct i2c_client *vx6953_client; + +struct vx6953_ctrl_t { + const struct msm_camera_sensor_info *sensordata; + + uint32_t sensormode; + uint32_t fps_divider; /* init to 1 * 0x00000400 */ + uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ + uint16_t fps; + + int16_t curr_lens_pos; + uint16_t curr_step_pos; + uint16_t my_reg_gain; + uint32_t my_reg_line_count; + uint16_t total_lines_per_frame; + + enum vx6953_resolution_t prev_res; + enum vx6953_resolution_t pict_res; + enum vx6953_resolution_t curr_res; + enum vx6953_test_mode_t set_test; + enum sensor_revision_t sensor_type; + + enum edof_mode_t edof_mode; + + unsigned short imgaddr; + + struct v4l2_subdev *sensor_dev; + struct vx6953_format *fmt; +}; + + +static uint8_t vx6953_stm5m0edof_delay_msecs_stdby; +static uint16_t vx6953_stm5m0edof_delay_msecs_stream = 20; + +static struct vx6953_ctrl_t *vx6953_ctrl; +static DECLARE_WAIT_QUEUE_HEAD(vx6953_wait_queue); +DEFINE_MUTEX(vx6953_mut); +static struct vx6953_i2c_reg_conf patch_tbl_cut2[] = { + {0xFB94, 0}, /*intialise Data Xfer Status reg*/ + {0xFB95, 0}, /*gain 1 (0x00)*/ + {0xFB96, 0}, /*gain 1.07 (0x10)*/ + {0xFB97, 0}, /*gain 1.14 (0x20)*/ + {0xFB98, 0}, /*gain 1.23 (0x30)*/ + {0xFB99, 0}, /*gain 1.33 (0x40)*/ + {0xFB9A, 0}, /*gain 1.45 (0x50)*/ + {0xFB9B, 0}, /*gain 1.6 (0x60)*/ + {0xFB9C, 0}, /*gain 1.78 (0x70)*/ + {0xFB9D, 2}, /*gain 2 (0x80)*/ + {0xFB9E, 2}, /*gain 2.29 (0x90)*/ + {0xFB9F, 3}, /*gain 2.67 (0xA0)*/ + {0xFBA0, 3}, /*gain 3.2 (0xB0)*/ + {0xFBA1, 4}, /*gain 4 (0xC0)*/ + {0xFBA2, 7}, /*gain 5.33 (0xD0)*/ + {0xFBA3, 10}, /*gain 8 (0xE0)*/ + {0xFBA4, 11}, /*gain 9.14 (0xE4)*/ + {0xFBA5, 13}, /*gain 10.67 (0xE8)*/ + {0xFBA6, 15}, /*gain 12.8 (0xEC)*/ + {0xFBA7, 19}, /*gain 16 (0xF0)*/ + {0xF800, 0x12}, + {0xF801, 0x06}, + {0xF802, 0xf7}, + {0xF803, 0x90}, + {0xF804, 0x02}, + {0xF805, 0x05}, + {0xF806, 0xe0}, + {0xF807, 0xff}, + {0xF808, 0x65}, + {0xF809, 0x7d}, + {0xF80A, 0x70}, + {0xF80B, 0x03}, + {0xF80C, 0x02}, + {0xF80D, 0xf9}, + {0xF80E, 0x1c}, + {0xF80F, 0x8f}, + {0xF810, 0x7d}, + {0xF811, 0xe4}, + {0xF812, 0xf5}, + {0xF813, 0x7a}, + {0xF814, 0x75}, + {0xF815, 0x78}, + {0xF816, 0x30}, + {0xF817, 0x75}, + {0xF818, 0x79}, + {0xF819, 0x53}, + {0xF81A, 0x85}, + {0xF81B, 0x79}, + {0xF81C, 0x82}, + {0xF81D, 0x85}, + {0xF81E, 0x78}, + {0xF81F, 0x83}, + {0xF820, 0xe0}, + {0xF821, 0xc3}, + {0xF822, 0x95}, + {0xF823, 0x7b}, + {0xF824, 0xf0}, + {0xF825, 0x74}, + {0xF826, 0x02}, + {0xF827, 0x25}, + {0xF828, 0x79}, + {0xF829, 0xf5}, + {0xF82A, 0x79}, + {0xF82B, 0xe4}, + {0xF82C, 0x35}, + {0xF82D, 0x78}, + {0xF82E, 0xf5}, + {0xF82F, 0x78}, + {0xF830, 0x05}, + {0xF831, 0x7a}, + {0xF832, 0xe5}, + {0xF833, 0x7a}, + {0xF834, 0xb4}, + {0xF835, 0x08}, + {0xF836, 0xe3}, + {0xF837, 0xe5}, + {0xF838, 0x7d}, + {0xF839, 0x70}, + {0xF83A, 0x04}, + {0xF83B, 0xff}, + {0xF83C, 0x02}, + {0xF83D, 0xf8}, + {0xF83E, 0xe4}, + {0xF83F, 0xe5}, + {0xF840, 0x7d}, + {0xF841, 0xb4}, + {0xF842, 0x10}, + {0xF843, 0x05}, + {0xF844, 0x7f}, + {0xF845, 0x01}, + {0xF846, 0x02}, + {0xF847, 0xf8}, + {0xF848, 0xe4}, + {0xF849, 0xe5}, + {0xF84A, 0x7d}, + {0xF84B, 0xb4}, + {0xF84C, 0x20}, + {0xF84D, 0x05}, + {0xF84E, 0x7f}, + {0xF84F, 0x02}, + {0xF850, 0x02}, + {0xF851, 0xf8}, + {0xF852, 0xe4}, + {0xF853, 0xe5}, + {0xF854, 0x7d}, + {0xF855, 0xb4}, + {0xF856, 0x30}, + {0xF857, 0x05}, + {0xF858, 0x7f}, + {0xF859, 0x03}, + {0xF85A, 0x02}, + {0xF85B, 0xf8}, + {0xF85C, 0xe4}, + {0xF85D, 0xe5}, + {0xF85E, 0x7d}, + {0xF85F, 0xb4}, + {0xF860, 0x40}, + {0xF861, 0x04}, + {0xF862, 0x7f}, + {0xF863, 0x04}, + {0xF864, 0x80}, + {0xF865, 0x7e}, + {0xF866, 0xe5}, + {0xF867, 0x7d}, + {0xF868, 0xb4}, + {0xF869, 0x50}, + {0xF86A, 0x04}, + {0xF86B, 0x7f}, + {0xF86C, 0x05}, + {0xF86D, 0x80}, + {0xF86E, 0x75}, + {0xF86F, 0xe5}, + {0xF870, 0x7d}, + {0xF871, 0xb4}, + {0xF872, 0x60}, + {0xF873, 0x04}, + {0xF874, 0x7f}, + {0xF875, 0x06}, + {0xF876, 0x80}, + {0xF877, 0x6c}, + {0xF878, 0xe5}, + {0xF879, 0x7d}, + {0xF87A, 0xb4}, + {0xF87B, 0x70}, + {0xF87C, 0x04}, + {0xF87D, 0x7f}, + {0xF87E, 0x07}, + {0xF87F, 0x80}, + {0xF880, 0x63}, + {0xF881, 0xe5}, + {0xF882, 0x7d}, + {0xF883, 0xb4}, + {0xF884, 0x80}, + {0xF885, 0x04}, + {0xF886, 0x7f}, + {0xF887, 0x08}, + {0xF888, 0x80}, + {0xF889, 0x5a}, + {0xF88A, 0xe5}, + {0xF88B, 0x7d}, + {0xF88C, 0xb4}, + {0xF88D, 0x90}, + {0xF88E, 0x04}, + {0xF88F, 0x7f}, + {0xF890, 0x09}, + {0xF891, 0x80}, + {0xF892, 0x51}, + {0xF893, 0xe5}, + {0xF894, 0x7d}, + {0xF895, 0xb4}, + {0xF896, 0xa0}, + {0xF897, 0x04}, + {0xF898, 0x7f}, + {0xF899, 0x0a}, + {0xF89A, 0x80}, + {0xF89B, 0x48}, + {0xF89C, 0xe5}, + {0xF89D, 0x7d}, + {0xF89E, 0xb4}, + {0xF89F, 0xb0}, + {0xF8A0, 0x04}, + {0xF8A1, 0x7f}, + {0xF8A2, 0x0b}, + {0xF8A3, 0x80}, + {0xF8A4, 0x3f}, + {0xF8A5, 0xe5}, + {0xF8A6, 0x7d}, + {0xF8A7, 0xb4}, + {0xF8A8, 0xc0}, + {0xF8A9, 0x04}, + {0xF8AA, 0x7f}, + {0xF8AB, 0x0c}, + {0xF8AC, 0x80}, + {0xF8AD, 0x36}, + {0xF8AE, 0xe5}, + {0xF8AF, 0x7d}, + {0xF8B0, 0xb4}, + {0xF8B1, 0xd0}, + {0xF8B2, 0x04}, + {0xF8B3, 0x7f}, + {0xF8B4, 0x0d}, + {0xF8B5, 0x80}, + {0xF8B6, 0x2d}, + {0xF8B7, 0xe5}, + {0xF8B8, 0x7d}, + {0xF8B9, 0xb4}, + {0xF8BA, 0xe0}, + {0xF8BB, 0x04}, + {0xF8BC, 0x7f}, + {0xF8BD, 0x0e}, + {0xF8BE, 0x80}, + {0xF8BF, 0x24}, + {0xF8C0, 0xe5}, + {0xF8C1, 0x7d}, + {0xF8C2, 0xb4}, + {0xF8C3, 0xe4}, + {0xF8C4, 0x04}, + {0xF8C5, 0x7f}, + {0xF8C6, 0x0f}, + {0xF8C7, 0x80}, + {0xF8C8, 0x1b}, + {0xF8C9, 0xe5}, + {0xF8CA, 0x7d}, + {0xF8CB, 0xb4}, + {0xF8CC, 0xe8}, + {0xF8CD, 0x04}, + {0xF8CE, 0x7f}, + {0xF8CF, 0x10}, + {0xF8D0, 0x80}, + {0xF8D1, 0x12}, + {0xF8D2, 0xe5}, + {0xF8D3, 0x7d}, + {0xF8D4, 0xb4}, + {0xF8D5, 0xec}, + {0xF8D6, 0x04}, + {0xF8D7, 0x7f}, + {0xF8D8, 0x11}, + {0xF8D9, 0x80}, + {0xF8DA, 0x09}, + {0xF8DB, 0xe5}, + {0xF8DC, 0x7d}, + {0xF8DD, 0x7f}, + {0xF8DE, 0x00}, + {0xF8DF, 0xb4}, + {0xF8E0, 0xf0}, + {0xF8E1, 0x02}, + {0xF8E2, 0x7f}, + {0xF8E3, 0x12}, + {0xF8E4, 0x8f}, + {0xF8E5, 0x7c}, + {0xF8E6, 0xef}, + {0xF8E7, 0x24}, + {0xF8E8, 0x95}, + {0xF8E9, 0xff}, + {0xF8EA, 0xe4}, + {0xF8EB, 0x34}, + {0xF8EC, 0xfb}, + {0xF8ED, 0x8f}, + {0xF8EE, 0x82}, + {0xF8EF, 0xf5}, + {0xF8F0, 0x83}, + {0xF8F1, 0xe4}, + {0xF8F2, 0x93}, + {0xF8F3, 0xf5}, + {0xF8F4, 0x7c}, + {0xF8F5, 0xf5}, + {0xF8F6, 0x7b}, + {0xF8F7, 0xe4}, + {0xF8F8, 0xf5}, + {0xF8F9, 0x7a}, + {0xF8FA, 0x75}, + {0xF8FB, 0x78}, + {0xF8FC, 0x30}, + {0xF8FD, 0x75}, + {0xF8FE, 0x79}, + {0xF8FF, 0x53}, + {0xF900, 0x85}, + {0xF901, 0x79}, + {0xF902, 0x82}, + {0xF903, 0x85}, + {0xF904, 0x78}, + {0xF905, 0x83}, + {0xF906, 0xe0}, + {0xF907, 0x25}, + {0xF908, 0x7c}, + {0xF909, 0xf0}, + {0xF90A, 0x74}, + {0xF90B, 0x02}, + {0xF90C, 0x25}, + {0xF90D, 0x79}, + {0xF90E, 0xf5}, + {0xF90F, 0x79}, + {0xF910, 0xe4}, + {0xF911, 0x35}, + {0xF912, 0x78}, + {0xF913, 0xf5}, + {0xF914, 0x78}, + {0xF915, 0x05}, + {0xF916, 0x7a}, + {0xF917, 0xe5}, + {0xF918, 0x7a}, + {0xF919, 0xb4}, + {0xF91A, 0x08}, + {0xF91B, 0xe4}, + {0xF91C, 0x02}, + {0xF91D, 0x18}, + {0xF91E, 0x32}, + {0xF91F, 0x22}, + {0xF920, 0xf0}, + {0xF921, 0x90}, + {0xF922, 0xa0}, + {0xF923, 0xf8}, + {0xF924, 0xe0}, + {0xF925, 0x70}, + {0xF926, 0x02}, + {0xF927, 0xa3}, + {0xF928, 0xe0}, + {0xF929, 0x70}, + {0xF92A, 0x0a}, + {0xF92B, 0x90}, + {0xF92C, 0xa1}, + {0xF92D, 0x10}, + {0xF92E, 0xe0}, + {0xF92F, 0xfe}, + {0xF930, 0xa3}, + {0xF931, 0xe0}, + {0xF932, 0xff}, + {0xF933, 0x80}, + {0xF934, 0x04}, + {0xF935, 0x7e}, + {0xF936, 0x00}, + {0xF937, 0x7f}, + {0xF938, 0x00}, + {0xF939, 0x8e}, + {0xF93A, 0x7e}, + {0xF93B, 0x8f}, + {0xF93C, 0x7f}, + {0xF93D, 0x90}, + {0xF93E, 0x36}, + {0xF93F, 0x0d}, + {0xF940, 0xe0}, + {0xF941, 0x44}, + {0xF942, 0x02}, + {0xF943, 0xf0}, + {0xF944, 0x90}, + {0xF945, 0x36}, + {0xF946, 0x0e}, + {0xF947, 0xe5}, + {0xF948, 0x7e}, + {0xF949, 0xf0}, + {0xF94A, 0xa3}, + {0xF94B, 0xe5}, + {0xF94C, 0x7f}, + {0xF94D, 0xf0}, + {0xF94E, 0xe5}, + {0xF94F, 0x3a}, + {0xF950, 0x60}, + {0xF951, 0x0c}, + {0xF952, 0x90}, + {0xF953, 0x36}, + {0xF954, 0x09}, + {0xF955, 0xe0}, + {0xF956, 0x70}, + {0xF957, 0x06}, + {0xF958, 0x90}, + {0xF959, 0x36}, + {0xF95A, 0x08}, + {0xF95B, 0xf0}, + {0xF95C, 0xf5}, + {0xF95D, 0x3a}, + {0xF95E, 0x02}, + {0xF95F, 0x03}, + {0xF960, 0x94}, + {0xF961, 0x22}, + {0xF962, 0x78}, + {0xF963, 0x07}, + {0xF964, 0xe6}, + {0xF965, 0xd3}, + {0xF966, 0x94}, + {0xF967, 0x00}, + {0xF968, 0x40}, + {0xF969, 0x16}, + {0xF96A, 0x16}, + {0xF96B, 0xe6}, + {0xF96C, 0x90}, + {0xF96D, 0x30}, + {0xF96E, 0xa1}, + {0xF96F, 0xf0}, + {0xF970, 0x90}, + {0xF971, 0x43}, + {0xF972, 0x83}, + {0xF973, 0xe0}, + {0xF974, 0xb4}, + {0xF975, 0x01}, + {0xF976, 0x0f}, + {0xF977, 0x90}, + {0xF978, 0x43}, + {0xF979, 0x87}, + {0xF97A, 0xe0}, + {0xF97B, 0xb4}, + {0xF97C, 0x01}, + {0xF97D, 0x08}, + {0xF97E, 0x80}, + {0xF97F, 0x00}, + {0xF980, 0x90}, + {0xF981, 0x30}, + {0xF982, 0xa0}, + {0xF983, 0x74}, + {0xF984, 0x01}, + {0xF985, 0xf0}, + {0xF986, 0x22}, + {0xF987, 0xf0}, + {0xF988, 0x90}, + {0xF989, 0x35}, + {0xF98A, 0xba}, + {0xF98B, 0xe0}, + {0xF98C, 0xb4}, + {0xF98D, 0x0a}, + {0xF98E, 0x0d}, + {0xF98F, 0xa3}, + {0xF990, 0xe0}, + {0xF991, 0xb4}, + {0xF992, 0x01}, + {0xF993, 0x08}, + {0xF994, 0x90}, + {0xF995, 0xfb}, + {0xF996, 0x94}, + {0xF997, 0xe0}, + {0xF998, 0x90}, + {0xF999, 0x35}, + {0xF99A, 0xb8}, + {0xF99B, 0xf0}, + {0xF99C, 0xd0}, + {0xF99D, 0xd0}, + {0xF99E, 0xd0}, + {0xF99F, 0x82}, + {0xF9A0, 0xd0}, + {0xF9A1, 0x83}, + {0xF9A2, 0xd0}, + {0xF9A3, 0xe0}, + {0xF9A4, 0x32}, + {0xF9A5, 0x22}, + {0xF9A6, 0xe5}, + {0xF9A7, 0x7f}, + {0xF9A8, 0x45}, + {0xF9A9, 0x7e}, + {0xF9AA, 0x60}, + {0xF9AB, 0x15}, + {0xF9AC, 0x90}, + {0xF9AD, 0x01}, + {0xF9AE, 0x00}, + {0xF9AF, 0xe0}, + {0xF9B0, 0x70}, + {0xF9B1, 0x0f}, + {0xF9B2, 0x90}, + {0xF9B3, 0xa0}, + {0xF9B4, 0xf8}, + {0xF9B5, 0xe5}, + {0xF9B6, 0x7e}, + {0xF9B7, 0xf0}, + {0xF9B8, 0xa3}, + {0xF9B9, 0xe5}, + {0xF9BA, 0x7f}, + {0xF9BB, 0xf0}, + {0xF9BC, 0xe4}, + {0xF9BD, 0xf5}, + {0xF9BE, 0x7e}, + {0xF9BF, 0xf5}, + {0xF9C0, 0x7f}, + {0xF9C1, 0x22}, + {0xF9C2, 0x02}, + {0xF9C3, 0x0e}, + {0xF9C4, 0x79}, + {0xF9C5, 0x22}, + /* Offsets:*/ + {0x35C6, 0x00},/* FIDDLEDARKCAL*/ + {0x35C7, 0x00}, + {0x35C8, 0x01},/*STOREDISTANCEATSTOPSTREAMING*/ + {0x35C9, 0x20}, + {0x35CA, 0x01},/*BRUCEFIX*/ + {0x35CB, 0x62}, + {0x35CC, 0x01},/*FIXDATAXFERSTATUSREG*/ + {0x35CD, 0x87}, + {0x35CE, 0x01},/*FOCUSDISTANCEUPDATE*/ + {0x35CF, 0xA6}, + {0x35D0, 0x01},/*SKIPEDOFRESET*/ + {0x35D1, 0xC2}, + {0x35D2, 0x00}, + {0x35D3, 0xFB}, + {0x35D4, 0x00}, + {0x35D5, 0x94}, + {0x35D6, 0x00}, + {0x35D7, 0xFB}, + {0x35D8, 0x00}, + {0x35D9, 0x94}, + {0x35DA, 0x00}, + {0x35DB, 0xFB}, + {0x35DC, 0x00}, + {0x35DD, 0x94}, + {0x35DE, 0x00}, + {0x35DF, 0xFB}, + {0x35E0, 0x00}, + {0x35E1, 0x94}, + {0x35E6, 0x18},/* FIDDLEDARKCAL*/ + {0x35E7, 0x2F}, + {0x35E8, 0x03},/* STOREDISTANCEATSTOPSTREAMING*/ + {0x35E9, 0x93}, + {0x35EA, 0x18},/* BRUCEFIX*/ + {0x35EB, 0x99}, + {0x35EC, 0x00},/* FIXDATAXFERSTATUSREG*/ + {0x35ED, 0xA3}, + {0x35EE, 0x21},/* FOCUSDISTANCEUPDATE*/ + {0x35EF, 0x5B}, + {0x35F0, 0x0E},/* SKIPEDOFRESET*/ + {0x35F1, 0x74}, + {0x35F2, 0x04}, + {0x35F3, 0x64}, + {0x35F4, 0x04}, + {0x35F5, 0x65}, + {0x35F6, 0x04}, + {0x35F7, 0x7B}, + {0x35F8, 0x04}, + {0x35F9, 0x7C}, + {0x35FA, 0x04}, + {0x35FB, 0xDD}, + {0x35FC, 0x04}, + {0x35FD, 0xDE}, + {0x35FE, 0x04}, + {0x35FF, 0xEF}, + {0x3600, 0x04}, + {0x3601, 0xF0}, + /*Jump/Data:*/ + {0x35C2, 0x3F},/* Jump Reg*/ + {0x35C3, 0xFF},/* Jump Reg*/ + {0x35C4, 0x3F},/* Data Reg*/ + {0x35C5, 0xC0},/* Data Reg*/ + {0x35C0, 0x01},/* Enable*/ + +}; + +static struct vx6953_i2c_reg_conf edof_tbl[] = { + {0xa098, 0x02}, + {0xa099, 0x87}, + {0xa09c, 0x00}, + {0xa09d, 0xc5}, + {0xa4ec, 0x05}, + {0xa4ed, 0x05}, + {0xa4f0, 0x04}, + {0xa4f1, 0x04}, + {0xa4f4, 0x04}, + {0xa4f5, 0x05}, + {0xa4f8, 0x05}, + {0xa4f9, 0x07}, + {0xa4fc, 0x07}, + {0xa4fd, 0x07}, + {0xa500, 0x07}, + {0xa501, 0x07}, + {0xa504, 0x08}, + {0xa505, 0x08}, + {0xa518, 0x01}, + {0xa519, 0x02}, + {0xa51c, 0x01}, + {0xa51d, 0x00}, + {0xa534, 0x00}, + {0xa535, 0x04}, + {0xa538, 0x04}, + {0xa539, 0x03}, + {0xa53c, 0x05}, + {0xa53d, 0x07}, + {0xa540, 0x07}, + {0xa541, 0x06}, + {0xa544, 0x07}, + {0xa545, 0x06}, + {0xa548, 0x05}, + {0xa549, 0x06}, + {0xa54c, 0x06}, + {0xa54d, 0x07}, + {0xa550, 0x07}, + {0xa551, 0x04}, + {0xa554, 0x04}, + {0xa555, 0x04}, + {0xa558, 0x05}, + {0xa559, 0x06}, + {0xa55c, 0x07}, + {0xa55d, 0x07}, + {0xa56c, 0x00}, + {0xa56d, 0x0a}, + {0xa570, 0x08}, + {0xa571, 0x05}, + {0xa574, 0x04}, + {0xa575, 0x03}, + {0xa578, 0x04}, + {0xa579, 0x04}, + {0xa58c, 0x1f}, + {0xa58d, 0x1b}, + {0xa590, 0x17}, + {0xa591, 0x13}, + {0xa594, 0x10}, + {0xa595, 0x0d}, + {0xa598, 0x0f}, + {0xa599, 0x11}, + {0xa59c, 0x03}, + {0xa59d, 0x03}, + {0xa5a0, 0x03}, + {0xa5a1, 0x03}, + {0xa5a4, 0x03}, + {0xa5a5, 0x04}, + {0xa5a8, 0x05}, + {0xa5a9, 0x00}, + {0xa5ac, 0x00}, + {0xa5ad, 0x00}, + {0xa5b0, 0x00}, + {0xa5b1, 0x00}, + {0xa5b4, 0x00}, + {0xa5b5, 0x00}, + {0xa5c4, 0x1f}, + {0xa5c5, 0x13}, + {0xa5c8, 0x14}, + {0xa5c9, 0x14}, + {0xa5cc, 0x14}, + {0xa5cd, 0x13}, + {0xa5d0, 0x17}, + {0xa5d1, 0x1a}, + {0xa5f4, 0x05}, + {0xa5f5, 0x05}, + {0xa5f8, 0x05}, + {0xa5f9, 0x06}, + {0xa5fc, 0x06}, + {0xa5fd, 0x06}, + {0xa600, 0x06}, + {0xa601, 0x06}, + {0xa608, 0x07}, + {0xa609, 0x08}, + {0xa60c, 0x08}, + {0xa60d, 0x07}, + {0xa63c, 0x00}, + {0xa63d, 0x02}, + {0xa640, 0x02}, + {0xa641, 0x02}, + {0xa644, 0x02}, + {0xa645, 0x02}, + {0xa648, 0x03}, + {0xa649, 0x04}, + {0xa64c, 0x0a}, + {0xa64d, 0x09}, + {0xa650, 0x08}, + {0xa651, 0x09}, + {0xa654, 0x09}, + {0xa655, 0x0a}, + {0xa658, 0x0a}, + {0xa659, 0x0a}, + {0xa65c, 0x0a}, + {0xa65d, 0x09}, + {0xa660, 0x09}, + {0xa661, 0x09}, + {0xa664, 0x09}, + {0xa665, 0x08}, + {0xa680, 0x01}, + {0xa681, 0x02}, + {0xa694, 0x1f}, + {0xa695, 0x10}, + {0xa698, 0x0e}, + {0xa699, 0x0c}, + {0xa69c, 0x0d}, + {0xa69d, 0x0d}, + {0xa6a0, 0x0f}, + {0xa6a1, 0x11}, + {0xa6a4, 0x00}, + {0xa6a5, 0x00}, + {0xa6a8, 0x00}, + {0xa6a9, 0x00}, + {0xa6ac, 0x00}, + {0xa6ad, 0x00}, + {0xa6b0, 0x00}, + {0xa6b1, 0x04}, + {0xa6b4, 0x04}, + {0xa6b5, 0x04}, + {0xa6b8, 0x04}, + {0xa6b9, 0x04}, + {0xa6bc, 0x05}, + {0xa6bd, 0x05}, + {0xa6c0, 0x1f}, + {0xa6c1, 0x1f}, + {0xa6c4, 0x1f}, + {0xa6c5, 0x1f}, + {0xa6c8, 0x1f}, + {0xa6c9, 0x1f}, + {0xa6cc, 0x1f}, + {0xa6cd, 0x0b}, + {0xa6d0, 0x0c}, + {0xa6d1, 0x0d}, + {0xa6d4, 0x0d}, + {0xa6d5, 0x0d}, + {0xa6d8, 0x11}, + {0xa6d9, 0x14}, + {0xa6fc, 0x02}, + {0xa6fd, 0x03}, + {0xa700, 0x03}, + {0xa701, 0x03}, + {0xa704, 0x03}, + {0xa705, 0x04}, + {0xa708, 0x05}, + {0xa709, 0x02}, + {0xa70c, 0x02}, + {0xa70d, 0x02}, + {0xa710, 0x03}, + {0xa711, 0x04}, + {0xa714, 0x04}, + {0xa715, 0x04}, + {0xa744, 0x00}, + {0xa745, 0x03}, + {0xa748, 0x04}, + {0xa749, 0x04}, + {0xa74c, 0x05}, + {0xa74d, 0x06}, + {0xa750, 0x07}, + {0xa751, 0x07}, + {0xa754, 0x05}, + {0xa755, 0x05}, + {0xa758, 0x05}, + {0xa759, 0x05}, + {0xa75c, 0x05}, + {0xa75d, 0x06}, + {0xa760, 0x07}, + {0xa761, 0x07}, + {0xa764, 0x06}, + {0xa765, 0x05}, + {0xa768, 0x05}, + {0xa769, 0x05}, + {0xa76c, 0x06}, + {0xa76d, 0x07}, + {0xa77c, 0x00}, + {0xa77d, 0x05}, + {0xa780, 0x05}, + {0xa781, 0x05}, + {0xa784, 0x05}, + {0xa785, 0x04}, + {0xa788, 0x05}, + {0xa789, 0x06}, + {0xa79c, 0x1f}, + {0xa79d, 0x15}, + {0xa7a0, 0x13}, + {0xa7a1, 0x10}, + {0xa7a4, 0x0f}, + {0xa7a5, 0x0d}, + {0xa7a8, 0x11}, + {0xa7a9, 0x14}, + {0xa7ac, 0x02}, + {0xa7ad, 0x02}, + {0xa7b0, 0x02}, + {0xa7b1, 0x02}, + {0xa7b4, 0x02}, + {0xa7b5, 0x03}, + {0xa7b8, 0x03}, + {0xa7b9, 0x00}, + {0xa7bc, 0x00}, + {0xa7bd, 0x00}, + {0xa7c0, 0x00}, + {0xa7c1, 0x00}, + {0xa7c4, 0x00}, + {0xa7c5, 0x00}, + {0xa7d4, 0x1f}, + {0xa7d5, 0x0d}, + {0xa7d8, 0x0f}, + {0xa7d9, 0x10}, + {0xa7dc, 0x10}, + {0xa7dd, 0x10}, + {0xa7e0, 0x13}, + {0xa7e1, 0x16}, + {0xa7f4, 0x00}, + {0xa7f5, 0x03}, + {0xa7f8, 0x04}, + {0xa7f9, 0x04}, + {0xa7fc, 0x04}, + {0xa7fd, 0x03}, + {0xa800, 0x03}, + {0xa801, 0x03}, + {0xa804, 0x03}, + {0xa805, 0x03}, + {0xa808, 0x03}, + {0xa809, 0x03}, + {0xa80c, 0x03}, + {0xa80d, 0x04}, + {0xa810, 0x04}, + {0xa811, 0x0a}, + {0xa814, 0x0a}, + {0xa815, 0x0a}, + {0xa818, 0x0f}, + {0xa819, 0x14}, + {0xa81c, 0x14}, + {0xa81d, 0x14}, + {0xa82c, 0x00}, + {0xa82d, 0x04}, + {0xa830, 0x02}, + {0xa831, 0x00}, + {0xa834, 0x00}, + {0xa835, 0x00}, + {0xa838, 0x00}, + {0xa839, 0x00}, + {0xa840, 0x1f}, + {0xa841, 0x1f}, + {0xa848, 0x1f}, + {0xa849, 0x1f}, + {0xa84c, 0x1f}, + {0xa84d, 0x0c}, + {0xa850, 0x0c}, + {0xa851, 0x0c}, + {0xa854, 0x0c}, + {0xa855, 0x0c}, + {0xa858, 0x0c}, + {0xa859, 0x0c}, + {0xa85c, 0x0c}, + {0xa85d, 0x0c}, + {0xa860, 0x0c}, + {0xa861, 0x0c}, + {0xa864, 0x0c}, + {0xa865, 0x0c}, + {0xa868, 0x0c}, + {0xa869, 0x0c}, + {0xa86c, 0x0c}, + {0xa86d, 0x0c}, + {0xa870, 0x0c}, + {0xa871, 0x0c}, + {0xa874, 0x0c}, + {0xa875, 0x0c}, + {0xa878, 0x1f}, + {0xa879, 0x1f}, + {0xa87c, 0x1f}, + {0xa87d, 0x1f}, + {0xa880, 0x1f}, + {0xa881, 0x1f}, + {0xa884, 0x1f}, + {0xa885, 0x0c}, + {0xa888, 0x0c}, + {0xa889, 0x0c}, + {0xa88c, 0x0c}, + {0xa88d, 0x0c}, + {0xa890, 0x0c}, + {0xa891, 0x0c}, + {0xa898, 0x1f}, + {0xa899, 0x1f}, + {0xa8a0, 0x1f}, + {0xa8a1, 0x1f}, + {0xa8a4, 0x1f}, + {0xa8a5, 0x0c}, + {0xa8a8, 0x0c}, + {0xa8a9, 0x0c}, + {0xa8ac, 0x0c}, + {0xa8ad, 0x0c}, + {0xa8b0, 0x0c}, + {0xa8b1, 0x0c}, + {0xa8b4, 0x0c}, + {0xa8b5, 0x0c}, + {0xa8b8, 0x0c}, + {0xa8b9, 0x0c}, + {0xa8bc, 0x0c}, + {0xa8bd, 0x0c}, + {0xa8c0, 0x0c}, + {0xa8c1, 0x0c}, + {0xa8c4, 0x0c}, + {0xa8c5, 0x0c}, + {0xa8c8, 0x0c}, + {0xa8c9, 0x0c}, + {0xa8cc, 0x0c}, + {0xa8cd, 0x0c}, + {0xa8d0, 0x1f}, + {0xa8d1, 0x1f}, + {0xa8d4, 0x1f}, + {0xa8d5, 0x1f}, + {0xa8d8, 0x1f}, + {0xa8d9, 0x1f}, + {0xa8dc, 0x1f}, + {0xa8dd, 0x0c}, + {0xa8e0, 0x0c}, + {0xa8e1, 0x0c}, + {0xa8e4, 0x0c}, + {0xa8e5, 0x0c}, + {0xa8e8, 0x0c}, + {0xa8e9, 0x0c}, + {0xa8f0, 0x1f}, + {0xa8f1, 0x1f}, + {0xa8f8, 0x1f}, + {0xa8f9, 0x1f}, + {0xa8fc, 0x1f}, + {0xa8fd, 0x0c}, + {0xa900, 0x0c}, + {0xa901, 0x0c}, + {0xa904, 0x0c}, + {0xa905, 0x0c}, + {0xa908, 0x0c}, + {0xa909, 0x0c}, + {0xa90c, 0x0c}, + {0xa90d, 0x0c}, + {0xa910, 0x0c}, + {0xa911, 0x0c}, + {0xa914, 0x0c}, + {0xa915, 0x0c}, + {0xa918, 0x0c}, + {0xa919, 0x0c}, + {0xa91c, 0x0c}, + {0xa91d, 0x0c}, + {0xa920, 0x0c}, + {0xa921, 0x0c}, + {0xa924, 0x0c}, + {0xa925, 0x0c}, + {0xa928, 0x1f}, + {0xa929, 0x1f}, + {0xa92c, 0x1f}, + {0xa92d, 0x1f}, + {0xa930, 0x1f}, + {0xa931, 0x1f}, + {0xa934, 0x1f}, + {0xa935, 0x0c}, + {0xa938, 0x0c}, + {0xa939, 0x0c}, + {0xa93c, 0x0c}, + {0xa93d, 0x0c}, + {0xa940, 0x0c}, + {0xa941, 0x0c}, + {0xa96c, 0x0d}, + {0xa96d, 0x16}, + {0xa970, 0x19}, + {0xa971, 0x0e}, + {0xa974, 0x16}, + {0xa975, 0x1a}, + {0xa978, 0x0d}, + {0xa979, 0x15}, + {0xa97c, 0x19}, + {0xa97d, 0x0d}, + {0xa980, 0x15}, + {0xa981, 0x1a}, + {0xa984, 0x0d}, + {0xa985, 0x15}, + {0xa988, 0x1a}, + {0xa989, 0x0d}, + {0xa98c, 0x15}, + {0xa98d, 0x1a}, + {0xa990, 0x0b}, + {0xa991, 0x11}, + {0xa994, 0x02}, + {0xa995, 0x0e}, + {0xa998, 0x16}, + {0xa999, 0x02}, + {0xa99c, 0x0c}, + {0xa99d, 0x13}, + {0xa9a0, 0x02}, + {0xa9a1, 0x0c}, + {0xa9a4, 0x12}, + {0xa9a5, 0x02}, + {0xa9a8, 0x0c}, + {0xa9a9, 0x12}, + {0xa9ac, 0x02}, + {0xa9ad, 0x0c}, + {0xa9b0, 0x12}, + {0xa9b1, 0x02}, + {0xa9b4, 0x10}, + {0xa9b5, 0x1e}, + {0xa9b8, 0x0f}, + {0xa9b9, 0x13}, + {0xa9bc, 0x20}, + {0xa9bd, 0x10}, + {0xa9c0, 0x11}, + {0xa9c1, 0x1e}, + {0xa9c4, 0x10}, + {0xa9c5, 0x11}, + {0xa9c8, 0x1e}, + {0xa9c9, 0x10}, + {0xa9cc, 0x11}, + {0xa9cd, 0x20}, + {0xa9d0, 0x10}, + {0xa9d1, 0x13}, + {0xa9d4, 0x24}, + {0xa9d5, 0x10}, + {0xa9f0, 0x02}, + {0xa9f1, 0x01}, + {0xa9f8, 0x19}, + {0xa9f9, 0x0b}, + {0xa9fc, 0x0a}, + {0xa9fd, 0x07}, + {0xaa00, 0x0c}, + {0xaa01, 0x0e}, + {0xaa08, 0x0c}, + {0xaa09, 0x06}, + {0xaa0c, 0x0c}, + {0xaa0d, 0x0a}, + {0xaa24, 0x10}, + {0xaa25, 0x12}, + {0xaa28, 0x0b}, + {0xaa29, 0x07}, + {0xaa2c, 0x10}, + {0xaa2d, 0x14}, + {0xaa34, 0x0e}, + {0xaa35, 0x0e}, + {0xaa38, 0x07}, + {0xaa39, 0x07}, + {0xaa3c, 0x0e}, + {0xaa3d, 0x0c}, + {0xaa48, 0x09}, + {0xaa49, 0x0c}, + {0xaa4c, 0x0c}, + {0xaa4d, 0x07}, + {0xaa54, 0x08}, + {0xaa55, 0x06}, + {0xaa58, 0x04}, + {0xaa59, 0x05}, + {0xaa5c, 0x06}, + {0xaa5d, 0x06}, + {0xaa68, 0x05}, + {0xaa69, 0x05}, + {0xaa6c, 0x04}, + {0xaa6d, 0x05}, + {0xaa74, 0x06}, + {0xaa75, 0x04}, + {0xaa78, 0x05}, + {0xaa79, 0x05}, + {0xaa7c, 0x04}, + {0xaa7d, 0x06}, + {0xac18, 0x14}, + {0xac19, 0x00}, + {0xac1c, 0x14}, + {0xac1d, 0x00}, + {0xac20, 0x14}, + {0xac21, 0x00}, + {0xac24, 0x14}, + {0xac25, 0x00}, + {0xac28, 0x14}, + {0xac29, 0x00}, + {0xac2c, 0x14}, + {0xac2d, 0x00}, + {0xac34, 0x16}, + {0xac35, 0x00}, + {0xac38, 0x16}, + {0xac39, 0x00}, + {0xac3c, 0x16}, + {0xac3d, 0x00}, + {0xac40, 0x16}, + {0xac41, 0x00}, + {0xac44, 0x16}, + {0xac45, 0x00}, + {0xac48, 0x16}, + {0xac49, 0x00}, + {0xac50, 0x1b}, + {0xac51, 0x00}, + {0xac54, 0x1b}, + {0xac55, 0x00}, + {0xac58, 0x1b}, + {0xac59, 0x00}, + {0xac5c, 0x1b}, + {0xac5d, 0x00}, + {0xac60, 0x1b}, + {0xac61, 0x00}, + {0xac64, 0x1b}, + {0xac65, 0x00}, + {0xac74, 0x09}, + {0xac75, 0x0c}, + {0xac78, 0x0f}, + {0xac79, 0x11}, + {0xac7c, 0x12}, + {0xac7d, 0x14}, + {0xac80, 0x09}, + {0xac81, 0x0c}, + {0xac84, 0x0f}, + {0xac85, 0x11}, + {0xac88, 0x12}, + {0xac89, 0x14}, + {0xac8c, 0x09}, + {0xac8d, 0x0c}, + {0xac90, 0x0f}, + {0xac91, 0x11}, + {0xac94, 0x12}, + {0xac95, 0x14}, + {0xac98, 0x09}, + {0xac99, 0x0c}, + {0xac9c, 0x0f}, + {0xac9d, 0x11}, + {0xaca0, 0x12}, + {0xaca1, 0x14}, + {0xaca4, 0x09}, + {0xaca5, 0x0c}, + {0xaca8, 0x0f}, + {0xaca9, 0x11}, + {0xacac, 0x12}, + {0xacad, 0x14}, + {0xacb0, 0x07}, + {0xacb1, 0x09}, + {0xacb4, 0x0c}, + {0xacb5, 0x0d}, + {0xacb8, 0x0d}, + {0xacb9, 0x0e}, + {0xacbc, 0x05}, + {0xacbd, 0x07}, + {0xacc0, 0x0a}, + {0xacc1, 0x0b}, + {0xacc4, 0x0b}, + {0xacc5, 0x0c}, + {0xacc8, 0x03}, + {0xacc9, 0x04}, + {0xaccc, 0x07}, + {0xaccd, 0x08}, + {0xacd0, 0x09}, + {0xacd1, 0x09} +}; + +static struct vx6953_i2c_reg_conf patch_tbl_cut3[] = { + {0xF800, 0x90}, + {0xF801, 0x30}, + {0xF802, 0x31}, + {0xF803, 0xe0}, + {0xF804, 0xf5}, + {0xF805, 0x7d}, + {0xF806, 0xb4}, + {0xF807, 0x01}, + {0xF808, 0x06}, + {0xF809, 0x75}, + {0xF80A, 0x7d}, + {0xF80B, 0x03}, + {0xF80C, 0x74}, + {0xF80D, 0x03}, + {0xF80E, 0xf0}, + {0xF80F, 0x90}, + {0xF810, 0x30}, + {0xF811, 0x04}, + {0xF812, 0x74}, + {0xF813, 0x33}, + {0xF814, 0xf0}, + {0xF815, 0x90}, + {0xF816, 0x30}, + {0xF817, 0x06}, + {0xF818, 0xe4}, + {0xF819, 0xf0}, + {0xF81A, 0xa3}, + {0xF81B, 0x74}, + {0xF81C, 0x09}, + {0xF81D, 0xf0}, + {0xF81E, 0x90}, + {0xF81F, 0x30}, + {0xF820, 0x10}, + {0xF821, 0xe4}, + {0xF822, 0xf0}, + {0xF823, 0xa3}, + {0xF824, 0xf0}, + {0xF825, 0x90}, + {0xF826, 0x30}, + {0xF827, 0x16}, + {0xF828, 0x74}, + {0xF829, 0x1e}, + {0xF82A, 0xf0}, + {0xF82B, 0x90}, + {0xF82C, 0x30}, + {0xF82D, 0x1a}, + {0xF82E, 0x74}, + {0xF82F, 0x6a}, + {0xF830, 0xf0}, + {0xF831, 0xa3}, + {0xF832, 0x74}, + {0xF833, 0x29}, + {0xF834, 0xf0}, + {0xF835, 0x90}, + {0xF836, 0x30}, + {0xF837, 0x30}, + {0xF838, 0x74}, + {0xF839, 0x08}, + {0xF83A, 0xf0}, + {0xF83B, 0x90}, + {0xF83C, 0x30}, + {0xF83D, 0x36}, + {0xF83E, 0x74}, + {0xF83F, 0x2c}, + {0xF840, 0xf0}, + {0xF841, 0x90}, + {0xF842, 0x30}, + {0xF843, 0x41}, + {0xF844, 0xe4}, + {0xF845, 0xf0}, + {0xF846, 0xa3}, + {0xF847, 0x74}, + {0xF848, 0x24}, + {0xF849, 0xf0}, + {0xF84A, 0x90}, + {0xF84B, 0x30}, + {0xF84C, 0x45}, + {0xF84D, 0x74}, + {0xF84E, 0x81}, + {0xF84F, 0xf0}, + {0xF850, 0x90}, + {0xF851, 0x30}, + {0xF852, 0x98}, + {0xF853, 0x74}, + {0xF854, 0x01}, + {0xF855, 0xf0}, + {0xF856, 0x90}, + {0xF857, 0x30}, + {0xF858, 0x9d}, + {0xF859, 0x74}, + {0xF85A, 0x05}, + {0xF85B, 0xf0}, + {0xF85C, 0xe5}, + {0xF85D, 0x7d}, + {0xF85E, 0x70}, + {0xF85F, 0x10}, + {0xF860, 0x90}, + {0xF861, 0x30}, + {0xF862, 0x05}, + {0xF863, 0x04}, + {0xF864, 0xf0}, + {0xF865, 0x90}, + {0xF866, 0x30}, + {0xF867, 0x30}, + {0xF868, 0xe4}, + {0xF869, 0xf0}, + {0xF86A, 0x90}, + {0xF86B, 0x30}, + {0xF86C, 0x35}, + {0xF86D, 0x04}, + {0xF86E, 0xf0}, + {0xF86F, 0x22}, + {0xF870, 0xe5}, + {0xF871, 0x7d}, + {0xF872, 0x64}, + {0xF873, 0x02}, + {0xF874, 0x70}, + {0xF875, 0x2d}, + {0xF876, 0x90}, + {0xF877, 0x30}, + {0xF878, 0x04}, + {0xF879, 0x74}, + {0xF87A, 0x34}, + {0xF87B, 0xf0}, + {0xF87C, 0xa3}, + {0xF87D, 0x74}, + {0xF87E, 0x07}, + {0xF87F, 0xf0}, + {0xF880, 0x90}, + {0xF881, 0x30}, + {0xF882, 0x10}, + {0xF883, 0x74}, + {0xF884, 0x10}, + {0xF885, 0xf0}, + {0xF886, 0x90}, + {0xF887, 0x30}, + {0xF888, 0x16}, + {0xF889, 0x74}, + {0xF88A, 0x1f}, + {0xF88B, 0xf0}, + {0xF88C, 0x90}, + {0xF88D, 0x30}, + {0xF88E, 0x1a}, + {0xF88F, 0x74}, + {0xF890, 0x62}, + {0xF891, 0xf0}, + {0xF892, 0x90}, + {0xF893, 0x30}, + {0xF894, 0x35}, + {0xF895, 0x74}, + {0xF896, 0x04}, + {0xF897, 0xf0}, + {0xF898, 0x90}, + {0xF899, 0x30}, + {0xF89A, 0x41}, + {0xF89B, 0x74}, + {0xF89C, 0x60}, + {0xF89D, 0xf0}, + {0xF89E, 0xa3}, + {0xF89F, 0x74}, + {0xF8A0, 0x64}, + {0xF8A1, 0xf0}, + {0xF8A2, 0x22}, + {0xF8A3, 0xe5}, + {0xF8A4, 0x7d}, + {0xF8A5, 0xb4}, + {0xF8A6, 0x03}, + {0xF8A7, 0x12}, + {0xF8A8, 0x90}, + {0xF8A9, 0x30}, + {0xF8AA, 0x05}, + {0xF8AB, 0x74}, + {0xF8AC, 0x03}, + {0xF8AD, 0xf0}, + {0xF8AE, 0x90}, + {0xF8AF, 0x30}, + {0xF8B0, 0x11}, + {0xF8B1, 0x74}, + {0xF8B2, 0x01}, + {0xF8B3, 0xf0}, + {0xF8B4, 0x90}, + {0xF8B5, 0x30}, + {0xF8B6, 0x35}, + {0xF8B7, 0x74}, + {0xF8B8, 0x03}, + {0xF8B9, 0xf0}, + {0xF8BA, 0x22}, + {0xF8BB, 0xc3}, + {0xF8BC, 0x90}, + {0xF8BD, 0x0b}, + {0xF8BE, 0x89}, + {0xF8BF, 0xe0}, + {0xF8C0, 0x94}, + {0xF8C1, 0x1e}, + {0xF8C2, 0x90}, + {0xF8C3, 0x0b}, + {0xF8C4, 0x88}, + {0xF8C5, 0xe0}, + {0xF8C6, 0x94}, + {0xF8C7, 0x00}, + {0xF8C8, 0x50}, + {0xF8C9, 0x06}, + {0xF8CA, 0x7e}, + {0xF8CB, 0x00}, + {0xF8CC, 0x7f}, + {0xF8CD, 0x01}, + {0xF8CE, 0x80}, + {0xF8CF, 0x3d}, + {0xF8D0, 0xc3}, + {0xF8D1, 0x90}, + {0xF8D2, 0x0b}, + {0xF8D3, 0x89}, + {0xF8D4, 0xe0}, + {0xF8D5, 0x94}, + {0xF8D6, 0x3c}, + {0xF8D7, 0x90}, + {0xF8D8, 0x0b}, + {0xF8D9, 0x88}, + {0xF8DA, 0xe0}, + {0xF8DB, 0x94}, + {0xF8DC, 0x00}, + {0xF8DD, 0x50}, + {0xF8DE, 0x06}, + {0xF8DF, 0x7e}, + {0xF8E0, 0x00}, + {0xF8E1, 0x7f}, + {0xF8E2, 0x02}, + {0xF8E3, 0x80}, + {0xF8E4, 0x28}, + {0xF8E5, 0xc3}, + {0xF8E6, 0x90}, + {0xF8E7, 0x0b}, + {0xF8E8, 0x89}, + {0xF8E9, 0xe0}, + {0xF8EA, 0x94}, + {0xF8EB, 0xfa}, + {0xF8EC, 0x90}, + {0xF8ED, 0x0b}, + {0xF8EE, 0x88}, + {0xF8EF, 0xe0}, + {0xF8F0, 0x94}, + {0xF8F1, 0x00}, + {0xF8F2, 0x50}, + {0xF8F3, 0x06}, + {0xF8F4, 0x7e}, + {0xF8F5, 0x00}, + {0xF8F6, 0x7f}, + {0xF8F7, 0x03}, + {0xF8F8, 0x80}, + {0xF8F9, 0x13}, + {0xF8FA, 0xc3}, + {0xF8FB, 0x90}, + {0xF8FC, 0x0b}, + {0xF8FD, 0x88}, + {0xF8FE, 0xe0}, + {0xF8FF, 0x94}, + {0xF900, 0x80}, + {0xF901, 0x50}, + {0xF902, 0x06}, + {0xF903, 0x7e}, + {0xF904, 0x00}, + {0xF905, 0x7f}, + {0xF906, 0x04}, + {0xF907, 0x80}, + {0xF908, 0x04}, + {0xF909, 0xae}, + {0xF90A, 0x7e}, + {0xF90B, 0xaf}, + {0xF90C, 0x7f}, + {0xF90D, 0x90}, + {0xF90E, 0xa0}, + {0xF90F, 0xf8}, + {0xF910, 0xee}, + {0xF911, 0xf0}, + {0xF912, 0xa3}, + {0xF913, 0xef}, + {0xF914, 0xf0}, + {0xF915, 0x22}, + {0xF916, 0x90}, + {0xF917, 0x33}, + {0xF918, 0x82}, + {0xF919, 0xe0}, + {0xF91A, 0xff}, + {0xF91B, 0x64}, + {0xF91C, 0x01}, + {0xF91D, 0x70}, + {0xF91E, 0x30}, + {0xF91F, 0xe5}, + {0xF920, 0x7f}, + {0xF921, 0x64}, + {0xF922, 0x02}, + {0xF923, 0x45}, + {0xF924, 0x7e}, + {0xF925, 0x70}, + {0xF926, 0x04}, + {0xF927, 0x7d}, + {0xF928, 0x1e}, + {0xF929, 0x80}, + {0xF92A, 0x1d}, + {0xF92B, 0xe5}, + {0xF92C, 0x7f}, + {0xF92D, 0x64}, + {0xF92E, 0x03}, + {0xF92F, 0x45}, + {0xF930, 0x7e}, + {0xF931, 0x70}, + {0xF932, 0x04}, + {0xF933, 0x7d}, + {0xF934, 0x3c}, + {0xF935, 0x80}, + {0xF936, 0x11}, + {0xF937, 0xe5}, + {0xF938, 0x7f}, + {0xF939, 0x64}, + {0xF93A, 0x04}, + {0xF93B, 0x45}, + {0xF93C, 0x7e}, + {0xF93D, 0x70}, + {0xF93E, 0x04}, + {0xF93F, 0x7d}, + {0xF940, 0xfa}, + {0xF941, 0x80}, + {0xF942, 0x05}, + {0xF943, 0x90}, + {0xF944, 0x33}, + {0xF945, 0x81}, + {0xF946, 0xe0}, + {0xF947, 0xfd}, + {0xF948, 0xae}, + {0xF949, 0x05}, + {0xF94A, 0x90}, + {0xF94B, 0x33}, + {0xF94C, 0x81}, + {0xF94D, 0xed}, + {0xF94E, 0xf0}, + {0xF94F, 0xef}, + {0xF950, 0xb4}, + {0xF951, 0x01}, + {0xF952, 0x10}, + {0xF953, 0x90}, + {0xF954, 0x01}, + {0xF955, 0x00}, + {0xF956, 0xe0}, + {0xF957, 0x60}, + {0xF958, 0x0a}, + {0xF959, 0x90}, + {0xF95A, 0xa1}, + {0xF95B, 0x10}, + {0xF95C, 0xe0}, + {0xF95D, 0xf5}, + {0xF95E, 0x7e}, + {0xF95F, 0xa3}, + {0xF960, 0xe0}, + {0xF961, 0xf5}, + {0xF962, 0x7f}, + {0xF963, 0x22}, + {0xF964, 0x12}, + {0xF965, 0x2f}, + {0xF966, 0x4d}, + {0xF967, 0x90}, + {0xF968, 0x35}, + {0xF969, 0x38}, + {0xF96A, 0xe0}, + {0xF96B, 0x70}, + {0xF96C, 0x05}, + {0xF96D, 0x12}, + {0xF96E, 0x00}, + {0xF96F, 0x0e}, + {0xF970, 0x80}, + {0xF971, 0x03}, + {0xF972, 0x12}, + {0xF973, 0x07}, + {0xF974, 0xc9}, + {0xF975, 0x90}, + {0xF976, 0x40}, + {0xF977, 0x06}, + {0xF978, 0xe0}, + {0xF979, 0xf4}, + {0xF97A, 0x54}, + {0xF97B, 0x02}, + {0xF97C, 0xff}, + {0xF97D, 0xe0}, + {0xF97E, 0x54}, + {0xF97F, 0x01}, + {0xF980, 0x4f}, + {0xF981, 0x90}, + {0xF982, 0x31}, + {0xF983, 0x32}, + {0xF984, 0xf0}, + {0xF985, 0x90}, + {0xF986, 0xfa}, + {0xF987, 0x9d}, + {0xF988, 0xe0}, + {0xF989, 0x70}, + {0xF98A, 0x03}, + {0xF98B, 0x12}, + {0xF98C, 0x27}, + {0xF98D, 0x27}, + {0xF98E, 0x02}, + {0xF98F, 0x05}, + {0xF990, 0xac}, + {0xF991, 0x22}, + {0xF992, 0x78}, + {0xF993, 0x07}, + {0xF994, 0xe6}, + {0xF995, 0xf5}, + {0xF996, 0x7c}, + {0xF997, 0xe5}, + {0xF998, 0x7c}, + {0xF999, 0x60}, + {0xF99A, 0x1d}, + {0xF99B, 0x90}, + {0xF99C, 0x43}, + {0xF99D, 0x83}, + {0xF99E, 0xe0}, + {0xF99F, 0xb4}, + {0xF9A0, 0x01}, + {0xF9A1, 0x16}, + {0xF9A2, 0x90}, + {0xF9A3, 0x43}, + {0xF9A4, 0x87}, + {0xF9A5, 0xe0}, + {0xF9A6, 0xb4}, + {0xF9A7, 0x01}, + {0xF9A8, 0x0f}, + {0xF9A9, 0x15}, + {0xF9AA, 0x7c}, + {0xF9AB, 0x90}, + {0xF9AC, 0x30}, + {0xF9AD, 0xa1}, + {0xF9AE, 0xe5}, + {0xF9AF, 0x7c}, + {0xF9B0, 0xf0}, + {0xF9B1, 0x90}, + {0xF9B2, 0x30}, + {0xF9B3, 0xa0}, + {0xF9B4, 0x74}, + {0xF9B5, 0x01}, + {0xF9B6, 0xf0}, + {0xF9B7, 0x22}, + {0xF9B8, 0xe4}, + {0xF9B9, 0x90}, + {0xF9BA, 0x30}, + {0xF9BB, 0xa0}, + {0xF9BC, 0xf0}, + {0xF9BD, 0x22}, + {0xF9BE, 0xf0}, + {0xF9BF, 0xe5}, + {0xF9C0, 0x3a}, + {0xF9C1, 0xb4}, + {0xF9C2, 0x06}, + {0xF9C3, 0x06}, + {0xF9C4, 0x63}, + {0xF9C5, 0x3e}, + {0xF9C6, 0x02}, + {0xF9C7, 0x12}, + {0xF9C8, 0x03}, + {0xF9C9, 0xea}, + {0xF9CA, 0x02}, + {0xF9CB, 0x17}, + {0xF9CC, 0x4a}, + {0xF9CD, 0x22}, + {0x35C9, 0xBB}, + {0x35CA, 0x01}, + {0x35CB, 0x16}, + {0x35CC, 0x01}, + {0x35CD, 0x64}, + {0x35CE, 0x01}, + {0x35CF, 0x92}, + {0x35D0, 0x01}, + {0x35D1, 0xBE}, + {0x35D3, 0xF6}, + {0x35D5, 0x07}, + {0x35D7, 0xA3}, + {0x35DB, 0x02}, + {0x35DD, 0x06}, + {0x35DF, 0x1B}, + {0x35E6, 0x28}, + {0x35E7, 0x76}, + {0x35E8, 0x2D}, + {0x35E9, 0x07}, + {0x35EA, 0x04}, + {0x35EB, 0x43}, + {0x35EC, 0x05}, + {0x35ED, 0xA9}, + {0x35EE, 0x2A}, + {0x35EF, 0x15}, + {0x35F0, 0x17}, + {0x35F1, 0x41}, + {0x35F2, 0x24}, + {0x35F3, 0x88}, + {0x35F4, 0x01}, + {0x35F5, 0x54}, + {0x35F6, 0x01}, + {0x35F7, 0x55}, + {0x35F8, 0x2E}, + {0x35F9, 0xF2}, + {0x35FA, 0x06}, + {0x35FB, 0x02}, + {0x35FC, 0x06}, + {0x35FD, 0x03}, + {0x35FE, 0x06}, + {0x35FF, 0x04}, + {0x35C2, 0x1F}, + {0x35C3, 0xFF}, + {0x35C4, 0x1F}, + {0x35C5, 0xC0}, + {0x35C0, 0x01}, +}; + +struct vx6953_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; + +static const struct vx6953_format vx6953_cfmts[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + } + /* more can be supported, to be added later */ +}; + + +/*=============================================================*/ + +static int vx6953_i2c_rxdata(unsigned short saddr, + unsigned char *rxdata, int length) +{ + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = 2, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = 2, + .buf = rxdata, + }, + }; + if (i2c_transfer(vx6953_client->adapter, msgs, 2) < 0) { + CDBG("vx6953_i2c_rxdata failed!\n"); + return -EIO; + } + return 0; +} +static int32_t vx6953_i2c_txdata(unsigned short saddr, + unsigned char *txdata, int length) +{ + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + if (i2c_transfer(vx6953_client->adapter, msg, 1) < 0) { + CDBG("vx6953_i2c_txdata faild 0x%x\n", vx6953_client->addr); + return -EIO; + } + + return 0; +} + + +static int32_t vx6953_i2c_read(unsigned short raddr, + unsigned short *rdata, int rlen) +{ + int32_t rc = 0; + unsigned char buf[2]; + if (!rdata) + return -EIO; + memset(buf, 0, sizeof(buf)); + buf[0] = (raddr & 0xFF00) >> 8; + buf[1] = (raddr & 0x00FF); + rc = vx6953_i2c_rxdata(vx6953_client->addr>>1, buf, rlen); + if (rc < 0) { + CDBG("vx6953_i2c_read 0x%x failed!\n", raddr); + return rc; + } + *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); + return rc; +} +static int32_t vx6953_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata) +{ + int32_t rc = -EFAULT; + unsigned char buf[3]; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + buf[2] = bdata; + CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata); + rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, 3); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata); + } + return rc; +} +static int32_t vx6953_i2c_write_seq_sensor(unsigned short waddr, + uint8_t *bdata, uint16_t len) +{ + int32_t rc = -EFAULT; + unsigned char buf[len+2]; + int i; + memset(buf, 0, sizeof(buf)); + buf[0] = (waddr & 0xFF00) >> 8; + buf[1] = (waddr & 0x00FF); + for (i = 2; i < len+2; i++) + buf[i] = *bdata++; + rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, len+2); + if (rc < 0) { + CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", + waddr, bdata[0]); + } + return rc; +} + +static int32_t vx6953_i2c_write_w_table(struct vx6953_i2c_reg_conf const + *reg_conf_tbl, int num) +{ + int i; + int32_t rc = -EIO; + for (i = 0; i < num; i++) { + rc = vx6953_i2c_write_b_sensor(reg_conf_tbl->waddr, + reg_conf_tbl->wdata); + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +static void vx6953_get_pict_fps(uint16_t fps, uint16_t *pfps) +{ + /* input fps is preview fps in Q8 format */ + uint16_t preview_frame_length_lines, snapshot_frame_length_lines; + uint16_t preview_line_length_pck, snapshot_line_length_pck; + uint32_t divider, d1, d2; + /* Total frame_length_lines and line_length_pck for preview */ + preview_frame_length_lines = VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES; + preview_line_length_pck = VX6953_QTR_SIZE_WIDTH + + VX6953_HRZ_QTR_BLK_PIXELS; + /* Total frame_length_lines and line_length_pck for snapshot */ + snapshot_frame_length_lines = VX6953_FULL_SIZE_HEIGHT + + VX6953_VER_FULL_BLK_LINES; + snapshot_line_length_pck = VX6953_FULL_SIZE_WIDTH + + VX6953_HRZ_FULL_BLK_PIXELS; + d1 = preview_frame_length_lines * 0x00000400/ + snapshot_frame_length_lines; + d2 = preview_line_length_pck * 0x00000400/ + snapshot_line_length_pck; + divider = d1 * d2 / 0x400; + /*Verify PCLK settings and frame sizes.*/ + *pfps = (uint16_t) (fps * divider / 0x400); + /* 2 is the ratio of no.of snapshot channels + to number of preview channels */ + +} + +static uint16_t vx6953_get_prev_lines_pf(void) +{ + if (vx6953_ctrl->prev_res == QTR_SIZE) + return VX6953_QTR_SIZE_HEIGHT + VX6953_VER_QTR_BLK_LINES; + else + return VX6953_FULL_SIZE_HEIGHT + VX6953_VER_FULL_BLK_LINES; + +} + +static uint16_t vx6953_get_prev_pixels_pl(void) +{ + if (vx6953_ctrl->prev_res == QTR_SIZE) + return VX6953_QTR_SIZE_WIDTH + VX6953_HRZ_QTR_BLK_PIXELS; + else + return VX6953_FULL_SIZE_WIDTH + VX6953_HRZ_FULL_BLK_PIXELS; +} + +static uint16_t vx6953_get_pict_lines_pf(void) +{ + if (vx6953_ctrl->pict_res == QTR_SIZE) + return VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES; + else + return VX6953_FULL_SIZE_HEIGHT + + VX6953_VER_FULL_BLK_LINES; +} + +static uint16_t vx6953_get_pict_pixels_pl(void) +{ + if (vx6953_ctrl->pict_res == QTR_SIZE) + return VX6953_QTR_SIZE_WIDTH + + VX6953_HRZ_QTR_BLK_PIXELS; + else + return VX6953_FULL_SIZE_WIDTH + + VX6953_HRZ_FULL_BLK_PIXELS; +} + +static uint32_t vx6953_get_pict_max_exp_lc(void) +{ + if (vx6953_ctrl->pict_res == QTR_SIZE) + return (VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES)*24; + else + return (VX6953_FULL_SIZE_HEIGHT + + VX6953_VER_FULL_BLK_LINES)*24; +} + +static int32_t vx6953_set_fps(struct fps_cfg *fps) +{ + uint16_t total_lines_per_frame; + int32_t rc = 0; + total_lines_per_frame = (uint16_t)((VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES) * vx6953_ctrl->fps_divider/0x400); + if (vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI, + ((total_lines_per_frame & 0xFF00) >> 8)) < 0) + return rc; + if (vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO, + (total_lines_per_frame & 0x00FF)) < 0) + return rc; + return rc; +} + +static int32_t vx6953_write_exp_gain(uint16_t gain, uint32_t line) +{ + uint16_t line_length_pck, frame_length_lines; + uint8_t gain_hi, gain_lo; + uint8_t intg_time_hi, intg_time_lo; + uint8_t line_length_pck_hi = 0, line_length_pck_lo = 0; + uint16_t line_length_ratio = 1 * Q8; + int32_t rc = 0; + if (vx6953_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) { + frame_length_lines = VX6953_QTR_SIZE_HEIGHT + + VX6953_VER_QTR_BLK_LINES; + line_length_pck = VX6953_QTR_SIZE_WIDTH + + VX6953_HRZ_QTR_BLK_PIXELS; + if (line > (frame_length_lines - + VX6953_STM5M0EDOF_OFFSET)) { + vx6953_ctrl->fps = (uint16_t) (30 * Q8 * + (frame_length_lines - VX6953_STM5M0EDOF_OFFSET)/ + line); + } else { + vx6953_ctrl->fps = (uint16_t) (30 * Q8); + } + } else { + frame_length_lines = VX6953_FULL_SIZE_HEIGHT + + VX6953_VER_FULL_BLK_LINES; + line_length_pck = VX6953_FULL_SIZE_WIDTH + + VX6953_HRZ_FULL_BLK_PIXELS; + } + /* calculate line_length_ratio */ + if ((frame_length_lines - VX6953_STM5M0EDOF_OFFSET) < line) { + line_length_ratio = (line*Q8) / + (frame_length_lines - VX6953_STM5M0EDOF_OFFSET); + line = frame_length_lines - VX6953_STM5M0EDOF_OFFSET; + } else { + line_length_ratio = 1*Q8; + } + vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD); + line_length_pck = (line_length_pck > + MAX_LINE_LENGTH_PCK) ? + MAX_LINE_LENGTH_PCK : line_length_pck; + line_length_pck = (uint16_t) (line_length_pck * + line_length_ratio/Q8); + line_length_pck_hi = (uint8_t) ((line_length_pck & + 0xFF00) >> 8); + line_length_pck_lo = (uint8_t) (line_length_pck & + 0x00FF); + vx6953_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_HI, + line_length_pck_hi); + vx6953_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_LO, + line_length_pck_lo); + /* update analogue gain registers */ + gain_hi = (uint8_t) ((gain & 0xFF00) >> 8); + gain_lo = (uint8_t) (gain & 0x00FF); + vx6953_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + gain_lo); + vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_GREEN_R_LO, gain_hi); + vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_RED_LO, gain_hi); + vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_BLUE_LO, gain_hi); + vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_GREEN_B_LO, gain_hi); + CDBG("%s, gain_hi 0x%x, gain_lo 0x%x\n", __func__, + gain_hi, gain_lo); + /* update line count registers */ + intg_time_hi = (uint8_t) (((uint16_t)line & 0xFF00) >> 8); + intg_time_lo = (uint8_t) ((uint16_t)line & 0x00FF); + vx6953_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_HI, + intg_time_hi); + vx6953_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LO, + intg_time_lo); + vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD, + GROUPED_PARAMETER_HOLD_OFF); + + return rc; +} + +static int32_t vx6953_set_pict_exp_gain(uint16_t gain, uint32_t line) +{ + int32_t rc = 0; + rc = vx6953_write_exp_gain(gain, line); + return rc; +} /* endof vx6953_set_pict_exp_gain*/ + +static int32_t vx6953_move_focus(int direction, + int32_t num_steps) +{ + return 0; +} + + +static int32_t vx6953_set_default_focus(uint8_t af_step) +{ + return 0; +} + +static int32_t vx6953_test(enum vx6953_test_mode_t mo) +{ + int32_t rc = 0; + if (mo == TEST_OFF) + return rc; + else { + /* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation, + 1: Bypass Signal Processing + REG_0x30D8[5] is EBDMASK: 0: + Output Embedded data, 1: No output embedded data */ + if (vx6953_i2c_write_b_sensor(REG_TEST_PATTERN_MODE, + (uint8_t) mo) < 0) { + return rc; + } + } + return rc; +} + +static int vx6953_enable_edof(enum edof_mode_t edof_mode) +{ + int rc = 0; + if (edof_mode == VX6953_EDOF_ESTIMATION) { + /* EDof Estimation mode for preview */ + if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x02) < 0) + return rc; + CDBG("VX6953_EDOF_ESTIMATION"); + } else if (edof_mode == VX6953_EDOF_APPLICATION) { + /* EDof Application mode for Capture */ + if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x01) < 0) + return rc; + CDBG("VX6953_EDOF_APPLICATION"); + } else { + /* EDOF disabled */ + if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x00) < 0) + return rc; + CDBG("VX6953_EDOF_DISABLE"); + } + return rc; +} + +static int32_t vx6953_patch_for_cut2(void) +{ + int32_t rc = 0; + rc = vx6953_i2c_write_w_table(patch_tbl_cut2, + ARRAY_SIZE(patch_tbl_cut2)); + if (rc < 0) + return rc; + + return rc; +} +static int32_t vx6953_patch_for_cut3(void) +{ + int32_t rc = 0; + rc = vx6953_i2c_write_w_table(patch_tbl_cut3, + ARRAY_SIZE(patch_tbl_cut3)); + if (rc < 0) + return rc; + + return rc; +} +static int32_t vx6953_sensor_setting(int update_type, int rt) +{ + + int32_t rc = 0; + unsigned short frame_cnt; + struct msm_camera_csi_params vx6953_csi_params; + if (vx6953_ctrl->sensor_type != VX6953_STM5M0EDOF_CUT_2) { + switch (update_type) { + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct vx6953_i2c_reg_conf init_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {0x6003, 0x01}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + {REG_0x3030, + vx6953_regs.reg_pat_init[0].reg_0x3030}, + /* 953 specific registers */ + {REG_0x0111, + vx6953_regs.reg_pat_init[0].reg_0x0111}, + {REG_0x0b00, + vx6953_regs.reg_pat_init[0].reg_0x0b00}, + {REG_0x3001, + vx6953_regs.reg_pat_init[0].reg_0x3001}, + {REG_0x3004, + vx6953_regs.reg_pat_init[0].reg_0x3004}, + {0x3006, 0x00}, + {REG_0x3007, + vx6953_regs.reg_pat_init[0].reg_0x3007}, + {0x301b, 0x29}, + /* DEFCOR settings */ + /*Single Defect Correction Weight DISABLE*/ + {0x0b06, + vx6953_regs.reg_pat_init[0].reg_0x0b06}, + /*Single_defect_correct_weight = auto*/ + {0x0b07, + vx6953_regs.reg_pat_init[0].reg_0x0b07}, + /*Dynamic couplet correction ENABLED*/ + {0x0b08, + vx6953_regs.reg_pat_init[0].reg_0x0b08}, + /*Dynamic couplet correction weight*/ + {0x0b09, + vx6953_regs.reg_pat_init[0].reg_0x0b09}, + /* Clock Setup */ + /* Tell sensor ext clk is 24MHz*/ + {REG_0x0136, + vx6953_regs.reg_pat_init[0].reg_0x0136}, + {REG_0x0137, + vx6953_regs.reg_pat_init[0].reg_0x0137}, + /* The white balance gains must be written + to the sensor every frame. */ + /* Edof */ + {REG_0x0b83, + vx6953_regs.reg_pat_init[0].reg_0x0b83}, + {REG_0x0b84, + vx6953_regs.reg_pat_init[0].reg_0x0b84}, + {REG_0x0b85, + vx6953_regs.reg_pat_init[0].reg_0x0b85}, + {REG_0x0b88, + vx6953_regs.reg_pat_init[0].reg_0x0b88}, + {REG_0x0b89, + vx6953_regs.reg_pat_init[0].reg_0x0b89}, + {REG_0x0b8a, + vx6953_regs.reg_pat_init[0].reg_0x0b8a}, + /* Mode specific regieters */ + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_0x3005, + vx6953_regs.reg_pat[rt].reg_0x3005}, + {0x3010, + vx6953_regs.reg_pat[rt].reg_0x3010}, + {REG_0x3011, + vx6953_regs.reg_pat[rt].reg_0x3011}, + {REG_0x301a, + vx6953_regs.reg_pat[rt].reg_0x301a}, + {REG_0x3035, + vx6953_regs.reg_pat[rt].reg_0x3035}, + {REG_0x3036, + vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3041, + vx6953_regs.reg_pat[rt].reg_0x3041}, + {0x3042, + vx6953_regs.reg_pat[rt].reg_0x3042}, + {REG_0x3045, + vx6953_regs.reg_pat[rt].reg_0x3045}, + /*EDOF: Estimation settings for Preview mode + Application settings for capture mode + (standard settings - Not tuned) */ + {REG_0x0b80, + vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0900, + vx6953_regs.reg_pat[rt].reg_0x0900}, + {REG_0x0901, + vx6953_regs.reg_pat[rt].reg_0x0901}, + {REG_0x0902, + vx6953_regs.reg_pat[rt].reg_0x0902}, + {REG_0x0383, + vx6953_regs.reg_pat[rt].reg_0x0383}, + {REG_0x0387, + vx6953_regs.reg_pat[rt].reg_0x0387}, + /* Change output size / frame rate */ + {REG_0x034c, + vx6953_regs.reg_pat[rt].reg_0x034c}, + {REG_0x034d, + vx6953_regs.reg_pat[rt].reg_0x034d}, + {REG_0x034e, + vx6953_regs.reg_pat[rt].reg_0x034e}, + {REG_0x034f, + vx6953_regs.reg_pat[rt].reg_0x034f}, + }; + /* reset fps_divider */ + vx6953_ctrl->fps = 30 * Q8; + /* stop streaming */ + + /* Reset everything first */ + if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) { + CDBG("S/W reset failed\n"); + return rc; + } else + CDBG("S/W reset successful\n"); + + msleep(10); + + CDBG("Init vx6953_sensor_setting standby\n"); + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + /*vx6953_stm5m0edof_delay_msecs_stdby*/ + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + + + vx6953_patch_for_cut3(); + rc = vx6953_i2c_write_w_table(&init_tbl[0], + ARRAY_SIZE(init_tbl)); + if (rc < 0) + return rc; + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + vx6953_i2c_write_b_sensor(0x0b80, 0x00); + vx6953_i2c_write_b_sensor(0x3388, 0x03); + vx6953_i2c_write_b_sensor(0x3640, 0x00); + + rc = vx6953_i2c_write_w_table(&edof_tbl[0], + ARRAY_SIZE(edof_tbl)); + vx6953_i2c_write_b_sensor(0x3388, 0x00); + + } + return rc; + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct vx6953_i2c_reg_conf preview_mode_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {0x6003, 0x01}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + + {REG_0x3210, vx6953_regs.reg_pat[rt].reg_0x3210}, + {REG_0x0111, vx6953_regs.reg_pat[rt].reg_0x111}, + {REG_0x3410, vx6953_regs.reg_pat[rt].reg_0x3410}, + + {REG_0x3004, + vx6953_regs.reg_pat_init[0].reg_0x3004}, + {REG_0x3006, 0x00}, + {REG_0x3007, + vx6953_regs.reg_pat_init[0].reg_0x3007}, + {REG_0x301b, 0x29}, + {REG_0x3036, + vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3045, vx6953_regs.reg_pat[rt].reg_0x3045}, + {REG_0x3098, vx6953_regs.reg_pat[rt].reg_0x3098}, + {REG_0x309d, vx6953_regs.reg_pat[rt].reg_0x309D}, + + {REG_0x0900, vx6953_regs.reg_pat[rt].reg_0x0900}, + {REG_0x0901, vx6953_regs.reg_pat[rt].reg_0x0901}, + {REG_0x0902, vx6953_regs.reg_pat[rt].reg_0x0902}, + {REG_0x0383, vx6953_regs.reg_pat[rt].reg_0x0383}, + {REG_0x0387, vx6953_regs.reg_pat[rt].reg_0x0387}, + + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_0x034c, + vx6953_regs.reg_pat[rt].reg_0x034c}, + {REG_0x034d, + vx6953_regs.reg_pat[rt].reg_0x034d}, + {REG_0x034e, + vx6953_regs.reg_pat[rt].reg_0x034e}, + {REG_0x034f, + vx6953_regs.reg_pat[rt].reg_0x034f}, + + {REG_0x3005, vx6953_regs.reg_pat[rt].reg_0x3005}, + {REG_0x3010, vx6953_regs.reg_pat[rt].reg_0x3010}, + {REG_0x3011, vx6953_regs.reg_pat[rt].reg_0x3011}, + {REG_0x301a, vx6953_regs.reg_pat[rt].reg_0x301a}, + {REG_0x3030, 0x08}, + {REG_0x3035, vx6953_regs.reg_pat[rt].reg_0x3035}, + {REG_0x3041, vx6953_regs.reg_pat[rt].reg_0x3041}, + {0x3042, vx6953_regs.reg_pat[rt].reg_0x3042}, + + {0x200, vx6953_regs.reg_pat[rt].reg_0x0200}, + {0x201, vx6953_regs.reg_pat[rt].reg_0x0201}, + + {0x0b06, + vx6953_regs.reg_pat_init[0].reg_0x0b06}, + /*Single_defect_correct_weight = auto*/ + {0x0b07, + vx6953_regs.reg_pat_init[0].reg_0x0b07}, + /*Dynamic couplet correction ENABLED*/ + {0x0b08, + vx6953_regs.reg_pat_init[0].reg_0x0b08}, + /*Dynamic couplet correction weight*/ + {0x0b09, + vx6953_regs.reg_pat_init[0].reg_0x0b09}, + + {REG_0x0136, + vx6953_regs.reg_pat_init[0].reg_0x0136}, + {REG_0x0137, + vx6953_regs.reg_pat_init[0].reg_0x0137}, + + /*EDOF: Estimation settings for Preview mode + Application settings for capture + mode(standard settings - Not tuned) */ + {REG_0x0b80, vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0b83, + vx6953_regs.reg_pat_init[0].reg_0x0b83}, + {REG_0x0b84, + vx6953_regs.reg_pat_init[0].reg_0x0b84}, + {REG_0x0b85, + vx6953_regs.reg_pat_init[0].reg_0x0b85}, + {REG_0x0b88, + vx6953_regs.reg_pat_init[0].reg_0x0b88}, + {REG_0x0b89, + vx6953_regs.reg_pat_init[0].reg_0x0b89}, + {REG_0x0b8a, + vx6953_regs.reg_pat_init[0].reg_0x0b8a}, + {0x3393, 0x06}, /* man_spec_edof_ctrl_edof*/ + {0x3394, 0x07}, /* man_spec_edof_ctrl_edof*/ + }; + + struct vx6953_i2c_reg_conf snapshot_mode_tbl[] = { + {REG_MODE_SELECT, MODE_SELECT_STANDBY_MODE}, + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {0x6003, 0x01}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {0x303, 1}, /* VT_SYS_CLK_DIV */ + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + {0x30b, 1}, + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_0x3210, vx6953_regs.reg_pat[rt].reg_0x3210}, + {REG_0x0111, vx6953_regs.reg_pat[rt].reg_0x111}, + + {REG_0x0b00, + vx6953_regs.reg_pat_init[0].reg_0x0b00}, + {0x3140, 0x01}, /* AV2X2 block enabled */ + {REG_0x3410, vx6953_regs.reg_pat[rt].reg_0x3410}, + {0x0b06, + vx6953_regs.reg_pat_init[0].reg_0x0b06}, + /*Single_defect_correct_weight = auto*/ + {0x0b07, + vx6953_regs.reg_pat_init[0].reg_0x0b07}, + /*Dynamic couplet correction ENABLED*/ + {0x0b08, + vx6953_regs.reg_pat_init[0].reg_0x0b08}, + /*Dynamic couplet correction weight*/ + {0x0b09, + vx6953_regs.reg_pat_init[0].reg_0x0b09}, + + + {REG_0x3004, + vx6953_regs.reg_pat_init[0].reg_0x3004}, + {REG_0x3006, 0x00}, + {REG_0x3007, + vx6953_regs.reg_pat_init[0].reg_0x3007}, + {0x301A, 0x6A}, + {REG_0x301b, 0x29}, + {REG_0x3036, + vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3045, vx6953_regs.reg_pat[rt].reg_0x3045}, + {REG_0x3098, vx6953_regs.reg_pat[rt].reg_0x3098}, + {REG_0x309d, vx6953_regs.reg_pat[rt].reg_0x309D}, + + {REG_0x0136, + vx6953_regs.reg_pat_init[0].reg_0x0136}, + {REG_0x0137, + vx6953_regs.reg_pat_init[0].reg_0x0137}, + + {REG_0x0b80, vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0b83, + vx6953_regs.reg_pat_init[0].reg_0x0b83}, + {REG_0x0b84, + vx6953_regs.reg_pat_init[0].reg_0x0b84}, + {REG_0x0b85, + vx6953_regs.reg_pat_init[0].reg_0x0b85}, + {REG_0x0b88, + vx6953_regs.reg_pat_init[0].reg_0x0b88}, + {REG_0x0b89, + vx6953_regs.reg_pat_init[0].reg_0x0b89}, + {REG_0x0b8a, + vx6953_regs.reg_pat_init[0].reg_0x0b8a}, + {0x3393, 0x06}, /* man_spec_edof_ctrl*/ + {0x3394, 0x07}, /* man_spec_edof_ctrl*/ + }; + /* stop streaming */ + msleep(5); + + /* Reset everything first */ + + if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) { + CDBG("S/W reset failed\n"); + return rc; + } else + CDBG("S/W reset successful\n"); + + msleep(10); + + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + /*vx6953_stm5m0edof_delay_msecs_stdby*/ + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + vx6953_csi_params.data_format = CSI_8BIT; + vx6953_csi_params.lane_cnt = 1; + vx6953_csi_params.lane_assign = 0xe4; + vx6953_csi_params.dpcm_scheme = 0; + vx6953_csi_params.settle_cnt = 7; + rc = msm_camio_csi_config(&vx6953_csi_params); + if (rc < 0) + CDBG(" config csi controller failed\n"); + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + vx6953_patch_for_cut3(); + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + if (rt == RES_PREVIEW) { + rc = vx6953_i2c_write_w_table( + &preview_mode_tbl[0], + ARRAY_SIZE(preview_mode_tbl)); + if (rc < 0) + return rc; + } + if (rt == RES_CAPTURE) { + rc = vx6953_i2c_write_w_table( + &snapshot_mode_tbl[0], + ARRAY_SIZE(snapshot_mode_tbl)); + if (rc < 0) + return rc; + } + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + /* Start sensor streaming */ + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STREAM) < 0) + return rc; + msleep(vx6953_stm5m0edof_delay_msecs_stream); + /* man_spec_edof_ctrl_tune_smooth_lowlight*/ + vx6953_i2c_write_b_sensor(0x338d, 0x08); + /* man_spec_edof_ctrl_tune_smooth_indoor*/ + vx6953_i2c_write_b_sensor(0x338e, 0x08); + /* man_spec_edof_ctrl_tune_smooth_outdoor*/ + vx6953_i2c_write_b_sensor(0x338f, 0x00); + /*Apply Capture FPGA state machine reset*/ + vx6953_i2c_write_b_sensor(0x16, 0x00); + msleep(100); + vx6953_i2c_write_b_sensor(0x16, 0x01); + + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + + while (frame_cnt == 0xFF) { + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + CDBG("frame_cnt=%d", frame_cnt); + msleep(10); + } + } + return rc; + default: + return rc; + } + } else { + switch (update_type) { + case REG_INIT: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct vx6953_i2c_reg_conf init_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + {REG_0x3030, + vx6953_regs.reg_pat_init[0].reg_0x3030}, + /* 953 specific registers */ + {REG_0x0111, + vx6953_regs.reg_pat_init[0].reg_0x0111}, + {REG_0x0b00, + vx6953_regs.reg_pat_init[0].reg_0x0b00}, + {REG_0x3001, + vx6953_regs.reg_pat_init[0].reg_0x3001}, + {REG_0x3004, + vx6953_regs.reg_pat_init[0].reg_0x3004}, + {REG_0x3007, + vx6953_regs.reg_pat_init[0].reg_0x3007}, + {REG_0x3016, + vx6953_regs.reg_pat_init[0].reg_0x3016}, + {REG_0x301d, + vx6953_regs.reg_pat_init[0].reg_0x301d}, + {REG_0x317e, + vx6953_regs.reg_pat_init[0].reg_0x317e}, + {REG_0x317f, + vx6953_regs.reg_pat_init[0].reg_0x317f}, + {REG_0x3400, + vx6953_regs.reg_pat_init[0].reg_0x3400}, + /* DEFCOR settings */ + /*Single Defect Correction Weight DISABLE*/ + {0x0b06, + vx6953_regs.reg_pat_init[0].reg_0x0b06}, + /*Single_defect_correct_weight = auto*/ + {0x0b07, + vx6953_regs.reg_pat_init[0].reg_0x0b07}, + /*Dynamic couplet correction ENABLED*/ + {0x0b08, + vx6953_regs.reg_pat_init[0].reg_0x0b08}, + /*Dynamic couplet correction weight*/ + {0x0b09, + vx6953_regs.reg_pat_init[0].reg_0x0b09}, + /* Clock Setup */ + /* Tell sensor ext clk is 24MHz*/ + {0x0136, + vx6953_regs.reg_pat_init[0].reg_0x0136}, + {0x0137, + vx6953_regs.reg_pat_init[0].reg_0x0137}, + /* The white balance gains must be written + to the sensor every frame. */ + /* Edof */ + {REG_0x0b83, + vx6953_regs.reg_pat_init[0].reg_0x0b83}, + {REG_0x0b84, + vx6953_regs.reg_pat_init[0].reg_0x0b84}, + {0x0b85, + vx6953_regs.reg_pat_init[0].reg_0x0b85}, + {0x0b88, + vx6953_regs.reg_pat_init[0].reg_0x0b88}, + {0x0b89, + vx6953_regs.reg_pat_init[0].reg_0x0b89}, + {REG_0x0b8a, + vx6953_regs.reg_pat_init[0].reg_0x0b8a}, + /* Mode specific regieters */ + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_0x3005, + vx6953_regs.reg_pat[rt].reg_0x3005}, + {0x3010, + vx6953_regs.reg_pat[rt].reg_0x3010}, + {REG_0x3011, + vx6953_regs.reg_pat[rt].reg_0x3011}, + {REG_0x301a, + vx6953_regs.reg_pat[rt].reg_0x301a}, + {REG_0x3035, + vx6953_regs.reg_pat[rt].reg_0x3035}, + {REG_0x3036, + vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3041, + vx6953_regs.reg_pat[rt].reg_0x3041}, + {0x3042, + vx6953_regs.reg_pat[rt].reg_0x3042}, + {REG_0x3045, + vx6953_regs.reg_pat[rt].reg_0x3045}, + /*EDOF: Estimation settings for Preview mode + Application settings for capture mode + (standard settings - Not tuned) */ + {REG_0x0b80, + vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0900, + vx6953_regs.reg_pat[rt].reg_0x0900}, + {REG_0x0901, + vx6953_regs.reg_pat[rt].reg_0x0901}, + {REG_0x0902, + vx6953_regs.reg_pat[rt].reg_0x0902}, + {REG_0x0383, + vx6953_regs.reg_pat[rt].reg_0x0383}, + {REG_0x0387, + vx6953_regs.reg_pat[rt].reg_0x0387}, + /* Change output size / frame rate */ + {REG_0x034c, + vx6953_regs.reg_pat[rt].reg_0x034c}, + {REG_0x034d, + vx6953_regs.reg_pat[rt].reg_0x034d}, + {REG_0x034e, + vx6953_regs.reg_pat[rt].reg_0x034e}, + {REG_0x034f, + vx6953_regs.reg_pat[rt].reg_0x034f}, + {REG_0x1716, + vx6953_regs.reg_pat[rt].reg_0x1716}, + {REG_0x1717, + vx6953_regs.reg_pat[rt].reg_0x1717}, + {REG_0x1718, + vx6953_regs.reg_pat[rt].reg_0x1718}, + {REG_0x1719, + vx6953_regs.reg_pat[rt].reg_0x1719}, + }; + /* reset fps_divider */ + vx6953_ctrl->fps = 30 * Q8; + /* stop streaming */ + + /* Reset everything first */ + if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) { + CDBG("S/W reset failed\n"); + return rc; + } else + CDBG("S/W reset successful\n"); + + msleep(10); + + CDBG("Init vx6953_sensor_setting standby\n"); + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + /*vx6953_stm5m0edof_delay_msecs_stdby*/ + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + vx6953_patch_for_cut2(); + rc = vx6953_i2c_write_w_table(&init_tbl[0], + ARRAY_SIZE(init_tbl)); + if (rc < 0) + return rc; + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + } + return rc; + case UPDATE_PERIODIC: + if (rt == RES_PREVIEW || rt == RES_CAPTURE) { + struct vx6953_i2c_reg_conf init_mode_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + {REG_0x3030, + vx6953_regs.reg_pat_init[0].reg_0x3030}, + /* 953 specific registers */ + {REG_0x0111, + vx6953_regs.reg_pat_init[0].reg_0x0111}, + {REG_0x0b00, + vx6953_regs.reg_pat_init[0].reg_0x0b00}, + {REG_0x3001, + vx6953_regs.reg_pat_init[0].reg_0x3001}, + {REG_0x3004, + vx6953_regs.reg_pat_init[0].reg_0x3004}, + {REG_0x3007, + vx6953_regs.reg_pat_init[0].reg_0x3007}, + {REG_0x3016, + vx6953_regs.reg_pat_init[0].reg_0x3016}, + {REG_0x301d, + vx6953_regs.reg_pat_init[0].reg_0x301d}, + {REG_0x317e, + vx6953_regs.reg_pat_init[0].reg_0x317e}, + {REG_0x317f, + vx6953_regs.reg_pat_init[0].reg_0x317f}, + {REG_0x3400, + vx6953_regs.reg_pat_init[0].reg_0x3400}, + {0x0b06, + vx6953_regs.reg_pat_init[0].reg_0x0b06}, + /*Single_defect_correct_weight = auto*/ + {0x0b07, + vx6953_regs.reg_pat_init[0].reg_0x0b07}, + /*Dynamic couplet correction ENABLED*/ + {0x0b08, + vx6953_regs.reg_pat_init[0].reg_0x0b08}, + /*Dynamic couplet correction weight*/ + {0x0b09, + vx6953_regs.reg_pat_init[0].reg_0x0b09}, + /* Clock Setup */ + /* Tell sensor ext clk is 24MHz*/ + {0x0136, + vx6953_regs.reg_pat_init[0].reg_0x0136}, + {0x0137, + vx6953_regs.reg_pat_init[0].reg_0x0137}, + /* The white balance gains must be written + to the sensor every frame. */ + /* Edof */ + {REG_0x0b83, + vx6953_regs.reg_pat_init[0].reg_0x0b83}, + {REG_0x0b84, + vx6953_regs.reg_pat_init[0].reg_0x0b84}, + {0x0b85, + vx6953_regs.reg_pat_init[0].reg_0x0b85}, + {0x0b88, + vx6953_regs.reg_pat_init[0].reg_0x0b88}, + {0x0b89, + vx6953_regs.reg_pat_init[0].reg_0x0b89}, + {REG_0x0b8a, + vx6953_regs.reg_pat_init[0].reg_0x0b8a}, + /* Mode specific regieters */ + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_0x3005, + vx6953_regs.reg_pat[rt].reg_0x3005}, + {0x3010, + vx6953_regs.reg_pat[rt].reg_0x3010}, + {REG_0x3011, + vx6953_regs.reg_pat[rt].reg_0x3011}, + {REG_0x301a, + vx6953_regs.reg_pat[rt].reg_0x301a}, + {REG_0x3035, + vx6953_regs.reg_pat[rt].reg_0x3035}, + {REG_0x3036, + vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3041, + vx6953_regs.reg_pat[rt].reg_0x3041}, + {0x3042, + vx6953_regs.reg_pat[rt].reg_0x3042}, + {REG_0x3045, + vx6953_regs.reg_pat[rt].reg_0x3045}, + /*EDOF: Estimation settings for Preview mode + Application settings for capture mode + (standard settings - Not tuned) */ + {REG_0x0b80, + vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0900, + vx6953_regs.reg_pat[rt].reg_0x0900}, + {REG_0x0901, + vx6953_regs.reg_pat[rt].reg_0x0901}, + {REG_0x0902, + vx6953_regs.reg_pat[rt].reg_0x0902}, + {REG_0x0383, + vx6953_regs.reg_pat[rt].reg_0x0383}, + {REG_0x0387, + vx6953_regs.reg_pat[rt].reg_0x0387}, + /* Change output size / frame rate */ + {REG_0x034c, + vx6953_regs.reg_pat[rt].reg_0x034c}, + {REG_0x034d, + vx6953_regs.reg_pat[rt].reg_0x034d}, + {REG_0x034e, + vx6953_regs.reg_pat[rt].reg_0x034e}, + {REG_0x034f, + vx6953_regs.reg_pat[rt].reg_0x034f}, + {REG_0x1716, + vx6953_regs.reg_pat[rt].reg_0x1716}, + {REG_0x1717, + vx6953_regs.reg_pat[rt].reg_0x1717}, + {REG_0x1718, + vx6953_regs.reg_pat[rt].reg_0x1718}, + {REG_0x1719, + vx6953_regs.reg_pat[rt].reg_0x1719}, + }; + struct vx6953_i2c_reg_conf mode_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + /* Mode specific regieters */ + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt].frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt].frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt].line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt].line_length_pck_lo}, + {REG_0x3005, vx6953_regs.reg_pat[rt].reg_0x3005}, + {0x3010, vx6953_regs.reg_pat[rt].reg_0x3010}, + {REG_0x3011, vx6953_regs.reg_pat[rt].reg_0x3011}, + {REG_0x301a, vx6953_regs.reg_pat[rt].reg_0x301a}, + {REG_0x3035, vx6953_regs.reg_pat[rt].reg_0x3035}, + {REG_0x3036, vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3041, vx6953_regs.reg_pat[rt].reg_0x3041}, + {0x3042, vx6953_regs.reg_pat[rt].reg_0x3042}, + {REG_0x3045, vx6953_regs.reg_pat[rt].reg_0x3045}, + /*EDOF: Estimation settings for Preview mode + Application settings for capture + mode(standard settings - Not tuned) */ + {REG_0x0b80, vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0900, vx6953_regs.reg_pat[rt].reg_0x0900}, + {REG_0x0901, vx6953_regs.reg_pat[rt].reg_0x0901}, + {REG_0x0902, vx6953_regs.reg_pat[rt].reg_0x0902}, + {REG_0x0383, vx6953_regs.reg_pat[rt].reg_0x0383}, + {REG_0x0387, vx6953_regs.reg_pat[rt].reg_0x0387}, + /* Change output size / frame rate */ + {REG_0x034c, vx6953_regs.reg_pat[rt].reg_0x034c}, + {REG_0x034d, vx6953_regs.reg_pat[rt].reg_0x034d}, + {REG_0x034e, vx6953_regs.reg_pat[rt].reg_0x034e}, + {REG_0x034f, vx6953_regs.reg_pat[rt].reg_0x034f}, + /*{0x200, vx6953_regs.reg_pat[rt].reg_0x0200}, + {0x201, vx6953_regs.reg_pat[rt].reg_0x0201},*/ + {REG_0x1716, vx6953_regs.reg_pat[rt].reg_0x1716}, + {REG_0x1717, vx6953_regs.reg_pat[rt].reg_0x1717}, + {REG_0x1718, vx6953_regs.reg_pat[rt].reg_0x1718}, + {REG_0x1719, vx6953_regs.reg_pat[rt].reg_0x1719}, + }; + /* stop streaming */ + msleep(5); + + /* Reset everything first */ + if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) { + CDBG("S/W reset failed\n"); + return rc; + } else + CDBG("S/W reset successful\n"); + + msleep(10); + + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + /*vx6953_stm5m0edof_delay_msecs_stdby*/ + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + vx6953_csi_params.data_format = CSI_8BIT; + vx6953_csi_params.lane_cnt = 1; + vx6953_csi_params.lane_assign = 0xe4; + vx6953_csi_params.dpcm_scheme = 0; + vx6953_csi_params.settle_cnt = 7; + rc = msm_camio_csi_config(&vx6953_csi_params); + if (rc < 0) + CDBG(" config csi controller failed\n"); + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + vx6953_patch_for_cut2(); + rc = vx6953_i2c_write_w_table(&init_mode_tbl[0], + ARRAY_SIZE(init_mode_tbl)); + if (rc < 0) + return rc; + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + rc = vx6953_i2c_write_w_table(&mode_tbl[0], + ARRAY_SIZE(mode_tbl)); + if (rc < 0) + return rc; + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + /* Start sensor streaming */ + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STREAM) < 0) + return rc; + msleep(vx6953_stm5m0edof_delay_msecs_stream); + + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + + while (frame_cnt == 0xFF) { + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + CDBG("frame_cnt=%d", frame_cnt); + msleep(10); + } + } + return rc; + default: + return rc; + } + } + return rc; +} + + +static int32_t vx6953_video_config(int mode) +{ + + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + if (vx6953_ctrl->prev_res == QTR_SIZE) { + rt = RES_PREVIEW; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((2 * 1000 * vx6953_ctrl->fps_divider) / + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } else { + rt = RES_CAPTURE; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((1000 * vx6953_ctrl->fps_divider) / + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } + if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + if (vx6953_ctrl->set_test) { + if (vx6953_test(vx6953_ctrl->set_test) < 0) + return rc; + } + vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION; + rc = vx6953_enable_edof(vx6953_ctrl->edof_mode); + if (rc < 0) + return rc; + vx6953_ctrl->curr_res = vx6953_ctrl->prev_res; + vx6953_ctrl->sensormode = mode; + return rc; +} + +static int32_t vx6953_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt; + /*change sensor resolution if needed */ + if (vx6953_ctrl->curr_res != vx6953_ctrl->pict_res) { + if (vx6953_ctrl->pict_res == QTR_SIZE) { + rt = RES_PREVIEW; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((2 * 1000 * vx6953_ctrl->fps_divider) / + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } else { + rt = RES_CAPTURE; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((1000 * vx6953_ctrl->fps_divider) / + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } + if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + + vx6953_ctrl->edof_mode = VX6953_EDOF_APPLICATION; + if (vx6953_enable_edof(vx6953_ctrl->edof_mode) < 0) + return rc; + vx6953_ctrl->curr_res = vx6953_ctrl->pict_res; + vx6953_ctrl->sensormode = mode; + return rc; +} /*end of vx6953_snapshot_config*/ + +static int32_t vx6953_raw_snapshot_config(int mode) +{ + int32_t rc = 0; + int rt; + /* change sensor resolution if needed */ + if (vx6953_ctrl->curr_res != vx6953_ctrl->pict_res) { + if (vx6953_ctrl->pict_res == QTR_SIZE) { + rt = RES_PREVIEW; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((2 * 1000 * vx6953_ctrl->fps_divider)/ + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } else { + rt = RES_CAPTURE; + vx6953_stm5m0edof_delay_msecs_stdby = + ((((1000 * vx6953_ctrl->fps_divider)/ + vx6953_ctrl->fps) * Q8) / Q10) + 1; + } + if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0) + return rc; + } + vx6953_ctrl->edof_mode = VX6953_EDOF_APPLICATION; + if (vx6953_enable_edof(vx6953_ctrl->edof_mode) < 0) + return rc; + vx6953_ctrl->curr_res = vx6953_ctrl->pict_res; + vx6953_ctrl->sensormode = mode; + return rc; +} /*end of vx6953_raw_snapshot_config*/ +static int32_t vx6953_set_sensor_mode(int mode, + int res) +{ + int32_t rc = 0; + switch (mode) { + case SENSOR_PREVIEW_MODE: + rc = vx6953_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + rc = vx6953_snapshot_config(mode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + rc = vx6953_raw_snapshot_config(mode); + break; + default: + rc = -EINVAL; + break; + } + return rc; +} +static int32_t vx6953_power_down(void) +{ + vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE); + return 0; +} + + +static int vx6953_probe_init_done(const struct msm_camera_sensor_info *data) +{ + gpio_free(data->sensor_reset); + kfree(vx6953_ctrl); + vx6953_ctrl = NULL; + return 0; +} +static int vx6953_probe_init_sensor(const struct msm_camera_sensor_info *data) +{ + unsigned short revision_number; + int32_t rc = 0; + unsigned short chipidl, chipidh; + CDBG("%s: %d\n", __func__, __LINE__); + rc = gpio_request(data->sensor_reset, "vx6953"); + CDBG(" vx6953_probe_init_sensor\n"); + if (!rc) { + CDBG("sensor_reset = %d\n", rc); + CDBG(" vx6953_probe_init_sensor 1\n"); + gpio_direction_output(data->sensor_reset, 0); + msleep(50); + CDBG(" vx6953_probe_init_sensor 1\n"); + gpio_direction_output(data->sensor_reset, 1); + msleep(13); + } else { + CDBG(" vx6953_probe_init_sensor 2\n"); + goto init_probe_done; + } + msleep(20); + CDBG(" vx6953_probe_init_sensor is called\n"); + /* 3. Read sensor Model ID: */ + rc = vx6953_i2c_read(0x0000, &chipidh, 1); + if (rc < 0) { + CDBG(" vx6953_probe_init_sensor 3\n"); + goto init_probe_fail; + } + rc = vx6953_i2c_read(0x0001, &chipidl, 1); + if (rc < 0) { + CDBG(" vx6953_probe_init_sensor4\n"); + goto init_probe_fail; + } + CDBG("vx6953 model_id = 0x%x 0x%x\n", chipidh, chipidl); + /* 4. Compare sensor ID to VX6953 ID: */ + if (chipidh != 0x03 || chipidl != 0xB9) { + rc = -ENODEV; + CDBG("vx6953_probe_init_sensor fail chip id doesnot match\n"); + goto init_probe_fail; + } + + vx6953_ctrl = kzalloc(sizeof(struct vx6953_ctrl_t), GFP_KERNEL); + if (!vx6953_ctrl) { + CDBG("vx6953_init failed!\n"); + rc = -ENOMEM; + } + vx6953_ctrl->fps_divider = 1 * 0x00000400; + vx6953_ctrl->pict_fps_divider = 1 * 0x00000400; + vx6953_ctrl->set_test = TEST_OFF; + vx6953_ctrl->prev_res = QTR_SIZE; + vx6953_ctrl->pict_res = FULL_SIZE; + vx6953_ctrl->curr_res = INVALID_SIZE; + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2; + vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION; + + if (data) + vx6953_ctrl->sensordata = data; + + if (vx6953_i2c_read(0x0002, &revision_number, 1) < 0) + return rc; + CDBG("sensor revision number major = 0x%x\n", revision_number); + if (vx6953_i2c_read(0x0018, &revision_number, 1) < 0) + return rc; + CDBG("sensor revision number = 0x%x\n", revision_number); + if (revision_number == VX6953_REVISION_NUMBER_CUT3) { + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_3; + CDBG("VX6953 EDof Cut 3.0 sensor\n "); + } else if (revision_number == VX6953_REVISION_NUMBER_CUT2) { + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2; + CDBG("VX6953 EDof Cut 2.0 sensor\n "); + } else {/* Cut1.0 reads 0x00 for register 0x0018*/ + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_1; + CDBG("VX6953 EDof Cut 1.0 sensor\n "); + } + + if (vx6953_ctrl->prev_res == QTR_SIZE) { + if (vx6953_sensor_setting(REG_INIT, RES_PREVIEW) < 0) + goto init_probe_fail; + } else { + if (vx6953_sensor_setting(REG_INIT, RES_CAPTURE) < 0) + goto init_probe_fail; + } + + goto init_probe_done; +init_probe_fail: + CDBG(" vx6953_probe_init_sensor fails\n"); + gpio_direction_output(data->sensor_reset, 0); + vx6953_probe_init_done(data); +init_probe_done: + CDBG(" vx6953_probe_init_sensor finishes\n"); + return rc; + } +/* camsensor_iu060f_vx6953_reset */ +int vx6953_sensor_open_init(const struct msm_camera_sensor_info *data) +{ + unsigned short revision_number; + int32_t rc = 0; + + CDBG("%s: %d\n", __func__, __LINE__); + CDBG("Calling vx6953_sensor_open_init\n"); + rc = gpio_request(data->sensor_reset, "vx6953"); + if (!rc) + CDBG("vx6953 gpio_request fail\n"); + + vx6953_ctrl = kzalloc(sizeof(struct vx6953_ctrl_t), GFP_KERNEL); + if (!vx6953_ctrl) { + CDBG("vx6953_init failed!\n"); + rc = -ENOMEM; + goto init_done; + } + vx6953_ctrl->fps_divider = 1 * 0x00000400; + vx6953_ctrl->pict_fps_divider = 1 * 0x00000400; + vx6953_ctrl->set_test = TEST_OFF; + vx6953_ctrl->prev_res = QTR_SIZE; + vx6953_ctrl->pict_res = FULL_SIZE; + vx6953_ctrl->curr_res = INVALID_SIZE; + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2; + vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION; + if (data) + vx6953_ctrl->sensordata = data; + if (rc < 0) { + CDBG("Calling vx6953_sensor_open_init fail1\n"); + return rc; + } + CDBG("%s: %d\n", __func__, __LINE__); + /* enable mclk first */ + msm_camio_clk_rate_set(VX6953_STM5M0EDOF_DEFAULT_MASTER_CLK_RATE); + CDBG("%s: %d\n", __func__, __LINE__); + if (vx6953_i2c_read(0x0002, &revision_number, 1) < 0) + return rc; + CDBG("sensor revision number major = 0x%x\n", revision_number); + if (vx6953_i2c_read(0x0018, &revision_number, 1) < 0) + return rc; + CDBG("sensor revision number = 0x%x\n", revision_number); + if (revision_number == VX6953_REVISION_NUMBER_CUT3) { + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_3; + CDBG("VX6953 EDof Cut 3.0 sensor\n "); + } else if (revision_number == VX6953_REVISION_NUMBER_CUT2) { + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2; + CDBG("VX6953 EDof Cut 2.0 sensor\n "); + } else {/* Cut1.0 reads 0x00 for register 0x0018*/ + vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_1; + CDBG("VX6953 EDof Cut 1.0 sensor\n "); + } + + vx6953_ctrl->fps = 30*Q8; + if (rc < 0) + goto init_fail; + else + goto init_done; +init_fail: + CDBG("init_fail\n"); + gpio_direction_output(data->sensor_reset, 0); + vx6953_probe_init_done(data); +init_done: + CDBG("init_done\n"); + return rc; +} /*endof vx6953_sensor_open_init*/ + +static int vx6953_init_client(struct i2c_client *client) +{ + /* Initialize the MSM_CAMI2C Chip */ + init_waitqueue_head(&vx6953_wait_queue); + return 0; +} + +static const struct i2c_device_id vx6953_i2c_id[] = { + {"vx6953", 0}, + { } +}; + +static int vx6953_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + CDBG("vx6953_probe called!\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CDBG("i2c_check_functionality failed\n"); + goto probe_failure; + } + + vx6953_sensorw = kzalloc(sizeof(struct vx6953_work_t), GFP_KERNEL); + if (!vx6953_sensorw) { + CDBG("kzalloc failed.\n"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, vx6953_sensorw); + vx6953_init_client(client); + vx6953_client = client; + + msleep(50); + + CDBG("vx6953_probe successed! rc = %d\n", rc); + return 0; + +probe_failure: + CDBG("vx6953_probe failed! rc = %d\n", rc); + return rc; +} + +static int vx6953_send_wb_info(struct wb_info_cfg *wb) +{ + unsigned short read_data; + uint8_t temp[8]; + int rc = 0; + int i = 0; + + /* red_gain */ + temp[2] = wb->red_gain >> 8; + temp[3] = wb->red_gain & 0xFF; + + /* green_gain */ + temp[0] = wb->green_gain >> 8; + temp[1] = wb->green_gain & 0xFF; + temp[6] = temp[0]; + temp[7] = temp[1]; + + /* blue_gain */ + temp[4] = wb->blue_gain >> 8; + temp[5] = wb->blue_gain & 0xFF; + rc = vx6953_i2c_write_seq_sensor(0x0B8E, &temp[0], 8); + + for (i = 0; i < 6; i++) { + rc = vx6953_i2c_read(0x0B8E + i, &read_data, 1); + CDBG("%s addr 0x%x val %d\n", __func__, 0x0B8E + i, read_data); + } + rc = vx6953_i2c_read(0x0B82, &read_data, 1); + CDBG("%s addr 0x%x val %d\n", __func__, 0x0B82, read_data); + if (rc < 0) + return rc; + return rc; +} /*end of vx6953_snapshot_config*/ + +static int __exit vx6953_remove(struct i2c_client *client) +{ + struct vx6953_work_t_t *sensorw = i2c_get_clientdata(client); + free_irq(client->irq, sensorw); + vx6953_client = NULL; + kfree(sensorw); + return 0; +} + +static struct i2c_driver vx6953_i2c_driver = { + .id_table = vx6953_i2c_id, + .probe = vx6953_i2c_probe, + .remove = __exit_p(vx6953_i2c_remove), + .driver = { + .name = "vx6953", + }, +}; + +static int vx6953_sensor_config(void __user *argp) +{ + struct sensor_cfg_data cdata; + long rc = 0; + if (copy_from_user(&cdata, + (void *)argp, + sizeof(struct sensor_cfg_data))) + return -EFAULT; + mutex_lock(&vx6953_mut); + CDBG("vx6953_sensor_config: cfgtype = %d\n", + cdata.cfgtype); + switch (cdata.cfgtype) { + case CFG_GET_PICT_FPS: + vx6953_get_pict_fps( + cdata.cfg.gfps.prevfps, + &(cdata.cfg.gfps.pictfps)); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_L_PF: + cdata.cfg.prevl_pf = + vx6953_get_prev_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PREV_P_PL: + cdata.cfg.prevp_pl = + vx6953_get_prev_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_L_PF: + cdata.cfg.pictl_pf = + vx6953_get_pict_lines_pf(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_P_PL: + cdata.cfg.pictp_pl = + vx6953_get_pict_pixels_pl(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_GET_PICT_MAX_EXP_LC: + cdata.cfg.pict_max_exp_lc = + vx6953_get_pict_max_exp_lc(); + + if (copy_to_user((void *)argp, + &cdata, + sizeof(struct sensor_cfg_data))) + rc = -EFAULT; + break; + + case CFG_SET_FPS: + case CFG_SET_PICT_FPS: + rc = vx6953_set_fps(&(cdata.cfg.fps)); + break; + + case CFG_SET_EXP_GAIN: + rc = + vx6953_write_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_PICT_EXP_GAIN: + rc = + vx6953_set_pict_exp_gain( + cdata.cfg.exp_gain.gain, + cdata.cfg.exp_gain.line); + break; + + case CFG_SET_MODE: + rc = vx6953_set_sensor_mode(cdata.mode, + cdata.rs); + break; + + case CFG_PWR_DOWN: + rc = vx6953_power_down(); + break; + + case CFG_MOVE_FOCUS: + rc = + vx6953_move_focus( + cdata.cfg.focus.dir, + cdata.cfg.focus.steps); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = + vx6953_set_default_focus( + cdata.cfg.focus.steps); + break; + + case CFG_SET_EFFECT: + rc = vx6953_set_default_focus( + cdata.cfg.effect); + break; + + + case CFG_SEND_WB_INFO: + rc = vx6953_send_wb_info( + &(cdata.cfg.wb_info)); + break; + + default: + rc = -EFAULT; + break; + } + + mutex_unlock(&vx6953_mut); + + return rc; +} + + + + +static int vx6953_sensor_release(void) +{ + int rc = -EBADF; + mutex_lock(&vx6953_mut); + vx6953_power_down(); + gpio_free(vx6953_ctrl->sensordata->sensor_reset); + kfree(vx6953_ctrl); + vx6953_ctrl = NULL; + CDBG("vx6953_release completed\n"); + mutex_unlock(&vx6953_mut); + + return rc; +} + +static int vx6953_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + /* TODO: Need to add this ID in v4l2-chip-ident.h */ + id->ident = V4L2_IDENT_VX6953; + id->revision = 0; + + return 0; +} + +static int vx6953_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) +{ + int ret = 0; + /* return current mode value */ + param->parm.capture.capturemode = vx6953_ctrl->sensormode; + return ret; +} + +static int vx6953_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) +{ + /* set the desired mode */ + /* right now, the only purpose is to set the desired mode - + preview or snapshot */ + vx6953_ctrl->sensormode = param->parm.capture.capturemode; + return 0; +} + +static int vx6953_s_stream(struct v4l2_subdev *sd, int enable) +{ + long rc = 0; + int mode = vx6953_ctrl->sensormode; + int rt = RES_PREVIEW; + unsigned short frame_cnt; + struct msm_camera_csi_params vx6953_csi_params; + + CDBG("mode = %d, enable = %d\n", mode, enable); + + if (!enable) { + /* turn off streaming */ + /* TODO: Make call to I2C write to turn streaming off */ + /* rc = vx6953_i2c_write_b_sensor(); */ + + struct vx6953_i2c_reg_conf init_tbl[] = { + {REG_0x0112, + vx6953_regs.reg_pat_init[0].reg_0x0112}, + {0x6003, 0x01}, + {REG_0x0113, + vx6953_regs.reg_pat_init[0].reg_0x0113}, + {REG_VT_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + vt_pix_clk_div}, + {REG_PRE_PLL_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + pre_pll_clk_div}, + {REG_PLL_MULTIPLIER, + vx6953_regs.reg_pat_init[0]. + pll_multiplier}, + {REG_OP_PIX_CLK_DIV, + vx6953_regs.reg_pat_init[0]. + op_pix_clk_div}, + {REG_COARSE_INTEGRATION_TIME_HI, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_hi}, + {REG_COARSE_INTEGRATION_TIME_LO, + vx6953_regs.reg_pat[rt]. + coarse_integration_time_lo}, + {REG_ANALOGUE_GAIN_CODE_GLOBAL_LO, + vx6953_regs.reg_pat[rt]. + analogue_gain_code_global}, + {REG_0x3030, + vx6953_regs.reg_pat_init[0].reg_0x3030}, + /* 953 specific registers */ + {REG_0x0111, + vx6953_regs.reg_pat_init[0].reg_0x0111}, + {REG_0x0b00, + vx6953_regs.reg_pat_init[0].reg_0x0b00}, + {REG_0x3001, + vx6953_regs.reg_pat_init[0].reg_0x3001}, + {REG_0x3004, + vx6953_regs.reg_pat_init[0].reg_0x3004}, + {0x3006, 0x00}, + {REG_0x3007, + vx6953_regs.reg_pat_init[0].reg_0x3007}, + {0x301b, 0x29}, + /* DEFCOR settings */ + /*Single Defect Correction Weight DISABLE*/ + {0x0b06, + vx6953_regs.reg_pat_init[0].reg_0x0b06}, + /*Single_defect_correct_weight = auto*/ + {0x0b07, + vx6953_regs.reg_pat_init[0].reg_0x0b07}, + /*Dynamic couplet correction ENABLED*/ + {0x0b08, + vx6953_regs.reg_pat_init[0].reg_0x0b08}, + /*Dynamic couplet correction weight*/ + {0x0b09, + vx6953_regs.reg_pat_init[0].reg_0x0b09}, + /* Clock Setup */ + /* Tell sensor ext clk is 24MHz*/ + {REG_0x0136, + vx6953_regs.reg_pat_init[0].reg_0x0136}, + {REG_0x0137, + vx6953_regs.reg_pat_init[0].reg_0x0137}, + /* The white balance gains must be written + to the sensor every frame. */ + /* Edof */ + {REG_0x0b83, + vx6953_regs.reg_pat_init[0].reg_0x0b83}, + {REG_0x0b84, + vx6953_regs.reg_pat_init[0].reg_0x0b84}, + {REG_0x0b85, + vx6953_regs.reg_pat_init[0].reg_0x0b85}, + {REG_0x0b88, + vx6953_regs.reg_pat_init[0].reg_0x0b88}, + {REG_0x0b89, + vx6953_regs.reg_pat_init[0].reg_0x0b89}, + {REG_0x0b8a, + vx6953_regs.reg_pat_init[0].reg_0x0b8a}, + /* Mode specific regieters */ + {REG_FRAME_LENGTH_LINES_HI, + vx6953_regs.reg_pat[rt]. + frame_length_lines_hi}, + {REG_FRAME_LENGTH_LINES_LO, + vx6953_regs.reg_pat[rt]. + frame_length_lines_lo}, + {REG_LINE_LENGTH_PCK_HI, + vx6953_regs.reg_pat[rt]. + line_length_pck_hi}, + {REG_LINE_LENGTH_PCK_LO, + vx6953_regs.reg_pat[rt]. + line_length_pck_lo}, + {REG_0x3005, + vx6953_regs.reg_pat[rt].reg_0x3005}, + {0x3010, + vx6953_regs.reg_pat[rt].reg_0x3010}, + {REG_0x3011, + vx6953_regs.reg_pat[rt].reg_0x3011}, + {REG_0x301a, + vx6953_regs.reg_pat[rt].reg_0x301a}, + {REG_0x3035, + vx6953_regs.reg_pat[rt].reg_0x3035}, + {REG_0x3036, + vx6953_regs.reg_pat[rt].reg_0x3036}, + {REG_0x3041, + vx6953_regs.reg_pat[rt].reg_0x3041}, + {0x3042, + vx6953_regs.reg_pat[rt].reg_0x3042}, + {REG_0x3045, + vx6953_regs.reg_pat[rt].reg_0x3045}, + /*EDOF: Estimation settings for Preview mode + Application settings for capture mode + (standard settings - Not tuned) */ + {REG_0x0b80, + vx6953_regs.reg_pat[rt].reg_0x0b80}, + {REG_0x0900, + vx6953_regs.reg_pat[rt].reg_0x0900}, + {REG_0x0901, + vx6953_regs.reg_pat[rt].reg_0x0901}, + {REG_0x0902, + vx6953_regs.reg_pat[rt].reg_0x0902}, + {REG_0x0383, + vx6953_regs.reg_pat[rt].reg_0x0383}, + {REG_0x0387, + vx6953_regs.reg_pat[rt].reg_0x0387}, + /* Change output size / frame rate */ + {REG_0x034c, + vx6953_regs.reg_pat[rt].reg_0x034c}, + {REG_0x034d, + vx6953_regs.reg_pat[rt].reg_0x034d}, + {REG_0x034e, + vx6953_regs.reg_pat[rt].reg_0x034e}, + {REG_0x034f, + vx6953_regs.reg_pat[rt].reg_0x034f}, + }; + /* reset fps_divider */ + vx6953_ctrl->fps = 30 * Q8; + /* stop streaming */ + + /* Reset everything first */ + if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) { + CDBG("S/W reset failed\n"); + return rc; + } else + CDBG("S/W reset successful\n"); + + msleep(10); + + CDBG("Init vx6953_sensor_setting standby\n"); + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STANDBY_MODE) < 0) + return rc; + + /*vx6953_stm5m0edof_delay_msecs_stdby*/ + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + vx6953_csi_params.data_format = CSI_8BIT; + vx6953_csi_params.lane_cnt = 1; + vx6953_csi_params.lane_assign = 0xe4; + vx6953_csi_params.dpcm_scheme = 0; + vx6953_csi_params.settle_cnt = 7; + rc = msm_camio_csi_config(&vx6953_csi_params); + if (rc < 0) + CDBG(" config csi controller failed\n"); + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + vx6953_patch_for_cut3(); + rc = vx6953_i2c_write_w_table(&init_tbl[0], + ARRAY_SIZE(init_tbl)); + if (rc < 0) + return rc; + + msleep(vx6953_stm5m0edof_delay_msecs_stdby); + + vx6953_i2c_write_b_sensor(0x0b80, 0x00); + vx6953_i2c_write_b_sensor(0x3388, 0x03); + vx6953_i2c_write_b_sensor(0x3640, 0x00); + return rc; + } else { + /* Start sensor streaming */ + if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT, + MODE_SELECT_STREAM) < 0) + return rc; + CDBG("Init vx6953_sensor_setting stream\n"); + msleep(vx6953_stm5m0edof_delay_msecs_stream); + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + + rc = vx6953_i2c_write_w_table(&edof_tbl[0], + ARRAY_SIZE(edof_tbl)); + vx6953_i2c_write_b_sensor(0x3388, 0x00); + + while (frame_cnt == 0xFF) { + if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0) + return rc; + CDBG("frame_cnt=%d", frame_cnt); + msleep(10); + } + + /* set desired mode */ + switch (mode) { + case SENSOR_PREVIEW_MODE: + CDBG("SENSOR_PREVIEW_MODE\n"); + rc = vx6953_video_config(mode); + break; + case SENSOR_SNAPSHOT_MODE: + CDBG("SENSOR_SNAPSHOT_MODE\n"); + rc = vx6953_snapshot_config(mode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + CDBG("SENSOR_RAW_SNAPSHOT_MODE\n"); + rc = vx6953_raw_snapshot_config(mode); + break; + default: + CDBG("default\n"); + return -EINVAL; + } + } + + return 0; +} + +static void vx6953_frame_check(u32 *width, u32 *height) +{ + /* get mode first */ + int mode = vx6953_ctrl->sensormode; + + switch (mode) { + case SENSOR_PREVIEW_MODE: + if (*width > VX6953_QTR_SIZE_WIDTH) + *width = VX6953_QTR_SIZE_WIDTH; + + if (*height > VX6953_QTR_SIZE_HEIGHT) + *height = VX6953_QTR_SIZE_HEIGHT; + break; + case SENSOR_SNAPSHOT_MODE: + case SENSOR_RAW_SNAPSHOT_MODE: + if (*width > VX6953_HRZ_FULL_BLK_PIXELS) + *width = VX6953_HRZ_FULL_BLK_PIXELS; + + if (*height > VX6953_VER_FULL_BLK_LINES) + *height = VX6953_VER_FULL_BLK_LINES; + break; + default: + break; + } +} + + +static int vx6953_set_params(struct i2c_client *client, u32 width, u32 height, + enum v4l2_mbus_pixelcode code) +{ + int i; + vx6953_ctrl->fmt = NULL; + + /* + * frame size check + */ + vx6953_frame_check(&width, &height); + + /* + * get color format + */ + for (i = 0; i < ARRAY_SIZE(vx6953_cfmts); i++) + if (vx6953_cfmts[i].code == code) + break; + if (i == ARRAY_SIZE(vx6953_cfmts)) + return -EINVAL; + + /* sensor supports one fixed size depending upon the mode */ + switch (vx6953_ctrl->sensormode) { + case SENSOR_PREVIEW_MODE: + vx6953_video_config(vx6953_ctrl->sensormode); + break; + case SENSOR_SNAPSHOT_MODE: + vx6953_snapshot_config(vx6953_ctrl->sensormode); + break; + case SENSOR_RAW_SNAPSHOT_MODE: + vx6953_raw_snapshot_config(vx6953_ctrl->sensormode); + break; + default: + return -EINVAL; + } + + /* why need this ? vx6953_ctrl->fmt = &(vx6953_cfmts[i]); */ + + return 0; +} + +static int vx6953_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + /* right now we are not supporting, probably vfe can take care */ + return -EINVAL; +} + +static int vx6953_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + return -EINVAL; +} + +static int vx6953_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + return -EINVAL; +} + +static int vx6953_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + /* by this time vx6953_client should already be set */ + struct i2c_client *client = vx6953_client; + + /* currently sensor supports fixed dimensions only + * depending upon the mode*/ + if (!vx6953_ctrl->fmt) { + int ret = vx6953_set_params(client, VX6953_QTR_SIZE_WIDTH, + VX6953_QTR_SIZE_HEIGHT, + V4L2_MBUS_FMT_YUYV8_2X8); + if (ret < 0) + return ret; + } + + mf->width = vx6953_get_pict_pixels_pl(); + mf->height = vx6953_get_pict_lines_pf(); + /* TODO: set colorspace */ + mf->code = vx6953_ctrl->fmt->code; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int vx6953_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + /* by this time vx6953_client should already be set */ + struct i2c_client *client = vx6953_client; + + /* TODO: We need to define this function */ + /* TODO: set colorspace */ + return vx6953_set_params(client, mf->width, mf->height, mf->code); +} + +static int vx6953_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vx6953_cfmts); i++) + if (mf->code == vx6953_cfmts[i].code) + break; + + if (i == ARRAY_SIZE(vx6953_cfmts)) + return -EINVAL; + + /* check that frame is within max sensor supported frame size */ + vx6953_frame_check(&mf->width, &mf->height); + + /* TODO: set colorspace */ + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int vx6953_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + printk(KERN_DEBUG "Index is %d\n", index); + if ((unsigned int)index >= ARRAY_SIZE(vx6953_cfmts)) + return -EINVAL; + + *code = vx6953_cfmts[index].code; + return 0; +} + +static struct v4l2_subdev_core_ops vx6953_subdev_core_ops = { + .g_chip_ident = vx6953_g_chip_ident, +}; + +static struct v4l2_subdev_video_ops vx6953_subdev_video_ops = { + .g_parm = vx6953_g_parm, + .s_parm = vx6953_s_parm, + .s_stream = vx6953_s_stream, + .g_mbus_fmt = vx6953_g_fmt, + .s_mbus_fmt = vx6953_s_fmt, + .try_mbus_fmt = vx6953_try_fmt, + .cropcap = vx6953_cropcap, + .g_crop = vx6953_g_crop, + .s_crop = vx6953_s_crop, + .enum_mbus_fmt = vx6953_enum_fmt, +}; + +static struct v4l2_subdev_ops vx6953_subdev_ops = { + .core = &vx6953_subdev_core_ops, + .video = &vx6953_subdev_video_ops, +}; + +static int vx6953_sensor_probe(const struct msm_camera_sensor_info *info, + struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = i2c_add_driver(&vx6953_i2c_driver); + if (rc < 0 || vx6953_client == NULL) { + rc = -ENOTSUPP; + goto probe_fail; + } + msm_camio_clk_rate_set(24000000); + rc = vx6953_probe_init_sensor(info); + if (rc < 0) + goto probe_fail; + s->s_init = vx6953_sensor_open_init; + s->s_release = vx6953_sensor_release; + s->s_config = vx6953_sensor_config; + vx6953_probe_init_done(info); + return rc; + +probe_fail: + CDBG("vx6953_sensor_probe: SENSOR PROBE FAILS!\n"); + return rc; +} + + +static int vx6953_sensor_probe_cb(const struct msm_camera_sensor_info *info, + struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s) +{ + int rc = 0; + rc = vx6953_sensor_probe(info, s); + if (rc < 0) + return rc; + + vx6953_ctrl = kzalloc(sizeof(struct vx6953_ctrl_t), GFP_KERNEL); + if (!vx6953_ctrl) { + CDBG("vx6953_sensor_probe failed!\n"); + return -ENOMEM; + } + + /* probe is successful, init a v4l2 subdevice */ + printk(KERN_DEBUG "going into v4l2_i2c_subdev_init\n"); + if (sdev) { + v4l2_i2c_subdev_init(sdev, vx6953_client, + &vx6953_subdev_ops); + vx6953_ctrl->sensor_dev = sdev; + } + return rc; +} + +static int __vx6953_probe(struct platform_device *pdev) +{ + return msm_sensor_register(pdev, vx6953_sensor_probe_cb); +} + +static struct platform_driver msm_camera_driver = { + .probe = __vx6953_probe, + .driver = { + .name = "msm_camera_vx6953", + .owner = THIS_MODULE, + }, +}; + +static int __init vx6953_init(void) +{ + return platform_driver_register(&msm_camera_driver); +} + +module_init(vx6953_init); +void vx6953_exit(void) +{ + i2c_del_driver(&vx6953_i2c_driver); +} diff --git a/drivers/media/video/msm_zsl/vx6953_v4l2.h b/drivers/media/video/msm_zsl/vx6953_v4l2.h new file mode 100644 index 00000000000..e5428e99192 --- /dev/null +++ b/drivers/media/video/msm_zsl/vx6953_v4l2.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef VX6953_V4L2_H +#define VX6953_V4L2_H +#include +#include +extern struct vx6953_reg vx6953_regs; +struct reg_struct_init { + uint8_t reg_0x0112; /* 0x0112*/ + uint8_t reg_0x0113; /* 0x0113*/ + uint8_t vt_pix_clk_div; /* 0x0301*/ + uint8_t pre_pll_clk_div; /* 0x0305*/ + uint8_t pll_multiplier; /* 0x0307*/ + uint8_t op_pix_clk_div; /* 0x0309*/ + uint8_t reg_0x3030; /*0x3030*/ + uint8_t reg_0x0111; /*0x0111*/ + uint8_t reg_0x0b00; /*0x0b00*/ + uint8_t reg_0x3001; /*0x3001*/ + uint8_t reg_0x3004; /*0x3004*/ + uint8_t reg_0x3007; /*0x3007*/ + uint8_t reg_0x3016; /*0x3016*/ + uint8_t reg_0x301d; /*0x301d*/ + uint8_t reg_0x317e; /*0x317E*/ + uint8_t reg_0x317f; /*0x317F*/ + uint8_t reg_0x3400; /*0x3400*/ + uint8_t reg_0x0b06; /*0x0b06*/ + uint8_t reg_0x0b07; /*0x0b07*/ + uint8_t reg_0x0b08; /*0x0b08*/ + uint8_t reg_0x0b09; /*0x0b09*/ + uint8_t reg_0x0136; + uint8_t reg_0x0137; + /* Edof */ + uint8_t reg_0x0b83; /*0x0b83*/ + uint8_t reg_0x0b84; /*0x0b84*/ + uint8_t reg_0x0b85; /*0x0b85*/ + uint8_t reg_0x0b88; /*0x0b88*/ + uint8_t reg_0x0b89; /*0x0b89*/ + uint8_t reg_0x0b8a; /*0x0b8a*/ + }; +struct reg_struct { + uint8_t coarse_integration_time_hi; /*REG_COARSE_INTEGRATION_TIME_HI*/ + uint8_t coarse_integration_time_lo; /*REG_COARSE_INTEGRATION_TIME_LO*/ + uint8_t analogue_gain_code_global; + uint8_t frame_length_lines_hi; /* 0x0340*/ + uint8_t frame_length_lines_lo; /* 0x0341*/ + uint8_t line_length_pck_hi; /* 0x0342*/ + uint8_t line_length_pck_lo; /* 0x0343*/ + uint8_t reg_0x3005; /* 0x3005*/ + uint8_t reg_0x3010; /* 0x3010*/ + uint8_t reg_0x3011; /* 0x3011*/ + uint8_t reg_0x301a; /* 0x301a*/ + uint8_t reg_0x3035; /* 0x3035*/ + uint8_t reg_0x3036; /* 0x3036*/ + uint8_t reg_0x3041; /*0x3041*/ + uint8_t reg_0x3042; /*0x3042*/ + uint8_t reg_0x3045; /*0x3045*/ + uint8_t reg_0x0b80; /* 0x0b80*/ + uint8_t reg_0x0900; /*0x0900*/ + uint8_t reg_0x0901; /* 0x0901*/ + uint8_t reg_0x0902; /*0x0902*/ + uint8_t reg_0x0383; /*0x0383*/ + uint8_t reg_0x0387; /* 0x0387*/ + uint8_t reg_0x034c; /* 0x034c*/ + uint8_t reg_0x034d; /*0x034d*/ + uint8_t reg_0x034e; /* 0x034e*/ + uint8_t reg_0x034f; /* 0x034f*/ + uint8_t reg_0x1716; /*0x1716*/ + uint8_t reg_0x1717; /*0x1717*/ + uint8_t reg_0x1718; /*0x1718*/ + uint8_t reg_0x1719; /*0x1719*/ + uint8_t reg_0x3210;/*0x3210*/ + uint8_t reg_0x111; /*0x111*/ + uint8_t reg_0x3410; /*0x3410*/ + uint8_t reg_0x3098; + uint8_t reg_0x309D; + uint8_t reg_0x0200; + uint8_t reg_0x0201; + }; +struct vx6953_i2c_reg_conf { + unsigned short waddr; + unsigned short wdata; +}; + +enum vx6953_test_mode_t { + TEST_OFF, + TEST_1, + TEST_2, + TEST_3 +}; + +enum vx6953_resolution_t { + QTR_SIZE, + FULL_SIZE, + INVALID_SIZE +}; +enum vx6953_setting { + RES_PREVIEW, + RES_CAPTURE +}; +enum mt9p012_reg_update { + /* Sensor egisters that need to be updated during initialization */ + REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + UPDATE_ALL, + /* Not valid update */ + UPDATE_INVALID +}; + +enum sensor_revision_t { + VX6953_STM5M0EDOF_CUT_1, + VX6953_STM5M0EDOF_CUT_2, + VX6953_STM5M0EDOF_CUT_3 +}; +enum edof_mode_t { + VX6953_EDOF_DISABLE, /* 0x00 */ + VX6953_EDOF_APPLICATION, /* 0x01 */ + VX6953_EDOF_ESTIMATION /* 0x02 */ +}; +struct vx6953_reg { + const struct reg_struct_init *reg_pat_init; + const struct reg_struct *reg_pat; +}; +#endif /* VX6953_H */ diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 5b2ec1fd2d0..33fe8fc6557 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -27,7 +27,6 @@ #include #include #include - #define dbgarg(cmd, fmt, arg...) \ do { \ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ @@ -2209,7 +2208,7 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_subscribe_event) break; - + ev->id = 0; ret = v4l2_event_dequeue(fh, ev, file->f_flags & O_NONBLOCK); if (ret < 0) { dbgarg(cmd, "no pending events?"); @@ -2293,11 +2292,11 @@ static long __video_do_ioctl(struct file *file, break; } /* switch */ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { +// if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { if (ret < 0) { v4l_print_ioctl(vfd->name, cmd); printk(KERN_CONT " error %ld\n", ret); - } +// } } return ret; diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index a7d13a81079..05a66d17275 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -342,13 +342,20 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) ret = __verify_planes_array(vb, b); if (ret) return ret; - +#if 0 /* * Fill in plane-related data if userspace provided an array * for it. The memory and size is verified above. */ memcpy(b->m.planes, vb->v4l2_planes, b->length * sizeof(struct v4l2_plane)); + for (i=0; ilength;i++) { + pr_info("%s returning offsets for buffer index %d, plane %d as" + "addr offset %d, data offset %d", + __func__, b->index, i, b->m.planes[i].reserved[0], + b->m.planes[i].data_offset); + } +#endif } else { /* * We use length and offset in v4l2_planes array even for @@ -896,13 +903,17 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) dprintk(3, "qbuf: userspace address for plane %d changed, " "reacquiring memory\n", plane); - +/* HACK: detule: This fails for us, and is not present in 3.0. I + * backported it there and it fails there as well, so remove for now. + * Need to know why it fails though. + */ +#if 0 /* Check if the provided plane buffer is large enough */ if (planes[plane].length < q->plane_sizes[plane]) { ret = -EINVAL; goto err; } - +#endif /* Release previously acquired memory if present */ if (vb->planes[plane].mem_priv) call_memop(q, put_userptr, vb->planes[plane].mem_priv); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 8f6735dc6ad..f9230bf840c 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -681,6 +681,111 @@ config BU52031NVX_POUCHDETECT help depends on BU52031NVX +config NFC_PN544 + bool "NXP PN544 NFC Controller Driver" + default n + help + NXP PN544 Near Field Communication controller support. + +config SEC_MISC + bool "Samsung P series miscellaneous driver" + default n + ---help--- + Samsung P series miscellaneous driver + +config USB_SWITCH_FSA9485 + tristate "FSA9480 USB Switch" + depends on I2C + help + The FSA9480 is a USB port accessory detector and switch. + The FSA9480 is fully controlled using I2C and enables USB data, + stereo and mono audio, video, microphone and UART data to use + a common connector port. + +config MPU_411_ENABLE + bool "mpu gyro sensor MPL 4.1.1" + depends on I2C + default n + +config YAS_532_ENABLE + bool "yas 532 sensor YAS 4.2.602" + depends on I2C + default n + +config OPTICAL_GP2A + depends on I2C + tristate "GP2A driver" + default n + help + This option enables proximity & light sensors using gp2a driver. + +config OPTICAL_GP2AP020A00F + depends on I2C + tristate "GP2AP020A00F driver" + default n + help + This option enables proximity & light sensors using gp2ap020a00f driver. + +config OPTICAL_TAOS_TRITON + depends on I2C + tristate "TAOS ambient light and proximity input device" + default n + +config OPTICAL_TAOS_TMD2672X + depends on I2C + tristate "TAOS ambient proximity input device without light sensor" + default n + +config SENSORS_AL3201 + depends on I2C + tristate "LITEON AL3201 ambient light sensor" + default n + +config SENSORS_CM36651 + depends on I2C + tristate "CM36651 driver" + default n + help + The CM36651 is a RGB sensor. + The CM36651 is fully controlled using I2C. + This option enables proximity sensor and RGB sensor + using cm36651 driver. + +config VP_A2220 + tristate "VP driver" + default n + help + This option enables voice processing audience chip.Please enable this chip + if you want to enable voice processing during call. + +config ADC_STMPE811 + tristate "ADC stmpe811 driver" + default n + depends on I2C + help + This option enables ADC checking driver. stmpe811. + +config SAMSUNG_JACK + bool "3.5 PI JACK driver for Samsung devices" + depends on INPUT + default n + help + This is 3.5 PI JACK driver for Samsung devices. + +config SAMSUNG_JACK_GNDLDET + bool "GND plus L Detection for Earjack" + depends on INPUT + default n + help + This is gnd plus l detection for earjack. + The gnd gpio is added for the detection of earjack. + This is added to decide the earjack properly + in case of the insertion of water. + +config OPTICAL_BH1721 + tristate "Rohm bh1721 Optical Sensor" + default n + depends on I2C source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" @@ -688,6 +793,7 @@ source "drivers/misc/iwmc3200top/Kconfig" source "drivers/misc/ti-st/Kconfig" source "drivers/misc/lis3lv02d/Kconfig" source "drivers/misc/carma/Kconfig" +source "drivers/misc/inv_mpu/Kconfig" source "drivers/misc/altera-stapl/Kconfig" source "drivers/misc/slimport_anx7808/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 90f1803d0d2..1ae7858ac02 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -75,3 +75,13 @@ obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o obj-y += tspdrv/ obj-$(CONFIG_BU52031NVX) += pm8xxx-cradle.o obj-$(CONFIG_SLIMPORT_ANX7808) += slimport_anx7808/ +obj-$(CONFIG_TI_DRV2667) += ti_drv2667.o +obj-$(CONFIG_NFC_PN544) += pn544.o +obj-$(CONFIG_USB_SWITCH_FSA9485) += fsa9485.o +obj-$(CONFIG_SEC_MISC) += sec_param.o sec_misc.o +obj-$(CONFIG_ADC_STMPE811) += stmpe811.o +obj-$(CONFIG_MPU_411_ENABLE) += inv_mpu/ +obj-$(CONFIG_SAMSUNG_JACK) += sec_jack.o +obj-$(CONFIG_OPTICAL_BH1721) += bh1721.o +obj-$(CONFIG_SENSORS_CM36651) += cm36651.o +obj-$(CONFIG_VP_A2220) += a2220.o diff --git a/drivers/misc/a2220.c b/drivers/misc/a2220.c new file mode 100644 index 00000000000..8e396dec544 --- /dev/null +++ b/drivers/misc/a2220.c @@ -0,0 +1,1274 @@ +/* drivers/i2c/chips/a2220.c - a2220 voice processor driver + * + * Copyright (C) 2009 HTC Corporation. + * + * Complete rewrite, anish kumar (anish.singh@samsung.com) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "a2220_firmware.h" +#include +#include + +#define ENABLE_DIAG_IOCTLS (0) + +struct a2220_data { + struct i2c_client *this_client; + struct mutex lock; + struct a2220_platform_data *pdata; + struct miscdevice device; + atomic_t opened; + int suspended; +}; + +static int execute_cmdmsg(struct a2220_data *a2220, unsigned int); +static unsigned int a2220_NS_state = A2220_NS_STATE_AUTO; +static int a2220_current_config = A2220_PATH_SUSPEND; + +struct vp_ctxt { + unsigned char *data; + unsigned int img_size; +}; + +struct vp_ctxt the_vp; + +static struct msm_xo_voter *xo; + +static int xoclk_control(bool onoff) +{ + pr_debug("%s onoff %d\n", __func__, onoff); + if (!xo) { + pr_err("%s XO Clock is not available" + " for Audience!!\n", __func__); + return -EAGAIN; + } + + if (onoff) + msm_xo_mode_vote(xo, MSM_XO_MODE_ON); + else + msm_xo_mode_vote(xo, MSM_XO_MODE_OFF); + return 0; +} + + +static int a2220_i2c_read(struct a2220_data *a2220, char *rxData, int length) +{ + int rc; + struct i2c_msg msgs[] = { + { + .addr = a2220->this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxData, + }, + }; + + rc = i2c_transfer(a2220->this_client->adapter, msgs, 1); + if (rc < 0) { + pr_err("%s: transfer error %d\n", __func__, rc); + return rc; + } + + { + int i = 0; + for (i = 0; i < length; i++) + pr_debug("%s: rx[%d] = %2x\n", __func__, i, rxData[i]); + } + return 0; +} + +static int a2220_i2c_write(struct a2220_data *a2220, char *txData, int length) +{ + int rc; + struct i2c_msg msg[] = { + { + .addr = a2220->this_client->addr, + .flags = 0, + .len = length, + .buf = txData, + }, + }; + + rc = i2c_transfer(a2220->this_client->adapter, msg, 1); + if (rc < 0) { + pr_err("%s: transfer error %d\n", __func__, rc); + return rc; + } + + { + int i = 0; + for (i = 0; i < length; i++) + pr_debug("%s: tx[%d] = %2x\n", __func__, i, txData[i]); + } + return 0; +} + +static int a2220_open(struct inode *inode, struct file *file) +{ + int rc = 0; + struct a2220_data *a2220 = container_of(file->private_data, + struct a2220_data, device); + + if (!atomic_dec_and_test(&a2220->opened)) { + pr_err("audience device busy\n"); + atomic_inc(&a2220->opened); + return -EBUSY; + } + return rc; +} + +static int a2220_release(struct inode *inode, struct file *file) +{ + struct a2220_data *a2220 = container_of(file->private_data, + struct a2220_data, device); + atomic_inc(&a2220->opened); /* release the device */ + return 0; +} + +#ifdef AUDIENCE_BYPASS +#define A100_msg_mutimedia1 0x801C0000 +#define A100_msg_mutimedia2 0x8026001F +#define A100_msg_mutimedia3 0x800C0B03 +#define A100_msg_mutimedia4 0x800D0001 +#define A100_msg_mutimedia5 0x800C0A03 +#define A100_msg_mutimedia6 0x800D0001 +#endif + +static void a2220_i2c_sw_reset(struct a2220_data *a2220, unsigned int reset_cmd) +{ + int rc = 0; + unsigned char msgbuf[4]; + + msgbuf[0] = (reset_cmd >> 24) & 0xFF; + msgbuf[1] = (reset_cmd >> 16) & 0xFF; + msgbuf[2] = (reset_cmd >> 8) & 0xFF; + msgbuf[3] = reset_cmd & 0xFF; + + pr_info("%s: %08x\n", __func__, reset_cmd); + + rc = a2220_i2c_write(a2220, msgbuf, 4); + if (!rc) + msleep(20); +} + + static ssize_t +a2220_hw_reset(struct a2220_data *a2220, struct a2220img *img) +{ + struct a2220img *vp = img; + int rc, i, pass = 0; + int remaining; + int retry = RETRY_CNT; + unsigned char *index; + char buf[2]; + + pr_info("%s\n", __func__); + while (retry--) { + /* Reset A2220 chip */ + gpio_set_value(a2220->pdata->gpio_reset, 0); + + mdelay(1); + + /* Take out of reset */ + gpio_set_value(a2220->pdata->gpio_reset, 1); + + msleep(50); /* Delay before send I2C command */ + + /* Boot Cmd to A2220 */ + buf[0] = A2220_msg_BOOT >> 8; + buf[1] = A2220_msg_BOOT & 0xff; + + rc = a2220_i2c_write(a2220, buf, 2); + if (rc < 0) { + pr_err("%s: set boot mode error (%d retries left)\n", + __func__, retry); + continue; + } + + mdelay(1); + rc = a2220_i2c_read(a2220, buf, 1); + if (rc < 0) { + pr_err("%s: boot mode ack error (%d retries left)\n", + __func__, retry); + continue; + } + + remaining = vp->img_size / 32; + index = vp->buf; + + for (; remaining; remaining--, index += 32) { + rc = a2220_i2c_write(a2220, index, 32); + if (rc < 0) + break; + } + + if (rc >= 0 && vp->img_size % 32) + rc = a2220_i2c_write(a2220, index, vp->img_size % 32); + + if (rc < 0) { + pr_err("%s: fw load error %d (%d retries left)\n", + __func__, rc, retry); + continue; + } + + msleep(20); /* Delay time before issue a Sync Cmd */ + + for (i = 0; i < 10 ; i++) + msleep(20); + + rc = execute_cmdmsg(a2220, A100_msg_Sync); + if (rc < 0) { + pr_err("%s: sync command error %d (%d retries left)\n", + __func__, rc, retry); + continue; + } + + pass = 1; + break; + } + return rc; +} + +unsigned char bypass_multimedia[] = { + 0x80, 0x52, 0x00, 0x48, + 0x80, 0x52, 0x00, 0x5C, + 0x80, 0x10, 0x00, 0x01, +}; + +int a2220_bootup_init(struct a2220_data *a2220, struct a2220img *pImg) +{ + struct a2220img *vp = pImg; + int rc, pass = 0, size, i; + unsigned int msg; + int remaining; + int retry = RETRY_CNT; + unsigned char *index; + unsigned char *pMsg; + unsigned char *i2c_cmds; + char buf[2]; + xoclk_control(true); + + mdelay(100); + while (retry--) { + /* Reset A2220 chip */ + gpio_set_value(a2220->pdata->gpio_reset, 0); + + mdelay(1); + + /* Take out of reset */ + gpio_set_value(a2220->pdata->gpio_reset, 1); + + msleep(50); /* Delay before send I2C command */ + + /* Boot Cmd to A2220 */ + buf[0] = A2220_msg_BOOT >> 8; + buf[1] = A2220_msg_BOOT & 0xff; + + rc = a2220_i2c_write(a2220, buf, 2); + if (rc < 0) { + pr_err("%s: set boot mode error (%d retries left)\n", + __func__, retry); + continue; + } + + mdelay(1); + rc = a2220_i2c_read(a2220, buf, 1); + if (rc < 0) { + pr_err("%s: boot mode ack error (%d retries left)\n", + __func__, retry); + continue; + } + + + remaining = vp->img_size / 32; + index = vp->buf; + pr_info("%s: starting to load image (%d passes)...\n", + __func__, + remaining + !!(vp->img_size % 32)); + + for (; remaining; remaining--, index += 32) { + rc = a2220_i2c_write(a2220, index, 32); + if (rc < 0) + break; + } + + if (rc >= 0 && vp->img_size % 32) + rc = a2220_i2c_write(a2220, index, vp->img_size % 32); + + if (rc < 0) { + pr_err("%s: fw load error %d (%d retries left)\n", + __func__, rc, retry); + continue; + } + pr_info("%s:a2220_bootup_init 7\n", __func__); + + msleep(20); /* Delay time before issue a Sync Cmd */ + + pr_info("%s:firmware loaded successfully\n", __func__); + + msleep(200); + + rc = execute_cmdmsg(a2220, A100_msg_Sync); + if (rc < 0) { + pr_err("%s: sync command error %d (%d retries left)\n", + __func__, rc, retry); + continue; + } + pr_info("%s:a2220_bootup_init 8\n", __func__); + + pass = 1; + break; + } + + /*setting bypass mode for Multi-Media*/ + pMsg = (unsigned char *)&msg; + i2c_cmds = bypass_multimedia; + size = sizeof(bypass_multimedia); + + for (i = 0 ; i < size ; i += 4) { + pMsg[3] = i2c_cmds[i]; + pMsg[2] = i2c_cmds[i+1]; + pMsg[1] = i2c_cmds[i+2]; + pMsg[0] = i2c_cmds[i+3]; + + do { + rc = execute_cmdmsg(a2220, msg); + } while ((rc < 0) && --retry); + + if (rc < 0) + pr_err("Audience bypass mode setting Failed\n"); + } + + pr_info("%s : a2220_bootup_init - finish\n", __func__); + xoclk_control(false); + return rc; +} + +static unsigned char phonecall_receiver_nson[] = { + 0x80, 0x31, 0x00, 0x00, +}; + +static unsigned char ft_loopback[] = { + 0x80, 0x31, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x00, + 0x80, 0x1B, 0x01, 0x00, + 0x80, 0x1B, 0x02, 0x00, + 0x80, 0x1B, 0x03, 0x00, + 0x80, 0x1B, 0x04, 0x00, + 0x80, 0x1B, 0x05, 0x00, + 0x80, 0x1B, 0x06, 0x00, + 0x80, 0x1B, 0x07, 0x00, + 0x80, 0x15, 0x00, 0x00, + 0x80, 0x15, 0x01, 0x00, + 0x80, 0x15, 0x02, 0x00, + 0x80, 0x15, 0x03, 0x00, + 0x80, 0x15, 0x04, 0x00, + 0x80, 0x15, 0x05, 0x00, + 0x80, 0x15, 0x06, 0x00, + 0x80, 0x15, 0x07, 0x00, + 0x80, 0x17, 0x00, 0x4B, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x42, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x40, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x0D, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x20, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x1F, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x30, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x31, + 0x80, 0x18, 0x00, 0x00, +}; + +static unsigned char phonecall_receiver_nson_wb[] = { + 0x80, 0x31, 0x00, 0x02, +}; + +static unsigned char phonecall_receiver_nsoff[] = { + 0x80, 0x52, 0x00, 0x48, + 0x80, 0x52, 0x00, 0x5C, + 0x80, 0x10, 0x00, 0x01, +}; + +static unsigned char phonecall_headset[] = { + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x02, 0x80, 0x18, 0x00, 0x03, + 0x80, 0x26, 0x00, 0x1A, + 0x80, 0x1B, 0x00, 0x00, + 0x80, 0x1B, 0x01, 0x00, + 0x80, 0x15, 0x04, 0x00, + 0x80, 0x15, 0x05, 0x00, + 0x80, 0x1B, 0x02, 0x00, + 0x80, 0x1B, 0x03, 0x00, + 0x80, 0x15, 0x06, 0x00, + 0x80, 0x15, 0x07, 0x00, + 0x80, 0x17, 0x00, 0x4B, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x15, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x03, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x12, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x34, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x04, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x28, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x09, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x0E, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x4C, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x20, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x1F, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x30, 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x31, 0x80, 0x18, 0x00, 0x01, + 0x80, 0x17, 0x00, 0x1A, 0x80, 0x18, 0x00, 0x00, +}; + +static unsigned char phonecall_speaker[] = { + 0x80, 0x31, 0x00, 0x01, +}; + +static unsigned char phonecall_bt[] = { + 0x80, 0x17, 0x00, 0x02, + 0x80, 0x18, 0x00, 0x03, + 0x80, 0x26, 0x00, 0x06, + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x00, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char phonecall_tty[] = { + 0x80, 0x26, 0x00, 0x15, + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x00, + 0x80, 0x15, 0x00, 0xFB, +}; + +static unsigned char INT_MIC_recording_receiver[] = { + 0x80, 0x26, 0x00, 0x07, + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x12, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char EXT_MIC_recording[] = { + 0x80, 0x26, 0x00, 0x15, + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x12, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char INT_MIC_recording_speaker[] = { + 0x80, 0x17, 0x00, 0x02, + 0x80, 0x18, 0x00, 0x02, + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x12, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char BACK_MIC_recording[] = { + 0x80, 0x17, 0x00, 0x02, + 0x80, 0x18, 0x00, 0x02, + 0x80, 0x26, 0x00, 0x15, + 0x80, 0x1C, 0x00, 0x01, + 0x80, 0x17, 0x00, 0x04, + 0x80, 0x18, 0x00, 0x01, + 0x80, 0x17, 0x00, 0x1A, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x00, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x12, + 0x80, 0x15, 0x00, 0x06, +}; + +static unsigned char vr_no_ns_receiver[] = { + 0x80, 0x17, 0x00, 0x02, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x0C, + 0x80, 0x1B, 0x01, 0x0C, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char vr_no_ns_headset[] = { + 0x80, 0x17, 0x00, 0x02, + 0x80, 0x18, 0x00, 0x03, + 0x80, 0x26, 0x00, 0x15, + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x12, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char vr_no_ns_speaker[] = { + 0x80, 0x17, 0x00, 0x02, + 0x80, 0x18, 0x00, 0x02, + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x0C, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char vr_no_ns_bt[] = { + 0x80, 0x26, 0x00, 0x06, + 0x80, 0x1C, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x00, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char vr_ns_receiver[] = { + 0x80, 0x17, 0x00, 0x02, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x1C, 0x00, 0x01, + 0x80, 0x17, 0x00, 0x1A, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x04, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x00, + 0x80, 0x18, 0x00, 0x04, + 0x80, 0x1B, 0x00, 0x0C, + 0x80, 0x1B, 0x01, 0x0C, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char vr_ns_headset[] = { + 0x80, 0x17, 0x00, 0x02, + 0x80, 0x18, 0x00, 0x03, + 0x80, 0x26, 0x00, 0x15, + 0x80, 0x1C, 0x00, 0x01, + 0x80, 0x17, 0x00, 0x00, + 0x80, 0x18, 0x00, 0x02, + 0x80, 0x17, 0x00, 0x1A, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x04, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x12, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char vr_ns_speaker[] = { + 0x80, 0x17, 0x00, 0x02, + 0x80, 0x18, 0x00, 0x02, + 0x80, 0x1C, 0x00, 0x01, + 0x80, 0x17, 0x00, 0x00, + 0x80, 0x18, 0x00, 0x04, + 0x80, 0x17, 0x00, 0x04, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x1A, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x0C, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char vr_ns_bt[] = { + 0x80, 0x26, 0x00, 0x06, + 0x80, 0x1C, 0x00, 0x01, + 0x80, 0x17, 0x00, 0x00, + 0x80, 0x18, 0x00, 0x02, + 0x80, 0x17, 0x00, 0x04, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x17, 0x00, 0x1A, + 0x80, 0x18, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x00, + 0x80, 0x15, 0x00, 0x00, +}; + +static unsigned char suspend_mode[] = { + 0x80, 0x10, 0x00, 0x01 +}; + +static unsigned char pcm_reset[] = { + 0x80, 0x31, 0x00, 0x00 +}; + +static ssize_t chk_wakeup_a2220(struct a2220_data *a2220) +{ + int rc = 0, retry = 4; + + if (a2220->suspended == 1) { + mdelay(1); + gpio_set_value(a2220->pdata->gpio_wakeup, 0); + msleep(30); + do { + rc = execute_cmdmsg(a2220, A100_msg_Sync); + } while ((rc < 0) && --retry); + + if ((retry == 0) && (rc < 0)) { + struct a2220img img; + img.buf = a2220_firmware_buf; + img.img_size = sizeof(a2220_firmware_buf); + rc = a2220_hw_reset(a2220, &img); + } + if (rc < 0) + pr_err("Audience HW Reset Failed rc %d\n", rc); + gpio_set_value(a2220->pdata->gpio_wakeup, 1); + if (rc < 0) { + pr_err("%s: failed (%d)\n", __func__, rc); + goto wakeup_sync_err; + } + a2220->suspended = 0; + } +wakeup_sync_err: + return rc; +} + +/* Filter commands according to noise suppression state forced by + * A2220_SET_NS_STATE ioctl. + * + * For this function to operate properly, all configurations must include + * both A100_msg_Bypass and Mic_Config commands even if default values + * are selected or if Mic_Config is useless because VP is off + */ +int a2220_filter_vp_cmd(int cmd, int mode) +{ + int msg = (cmd >> 16) & 0xFFFF; + int filtered_cmd = cmd; + static int a2220_param_ID; + + if (a2220_NS_state == A2220_NS_STATE_AUTO) + return cmd; + + switch (msg) { + case A100_msg_Bypass: + if (a2220_NS_state == A2220_NS_STATE_OFF) + filtered_cmd = A2220_msg_VP_OFF; + else + filtered_cmd = A2220_msg_VP_ON; + break; + case A100_msg_SetAlgorithmParmID: + a2220_param_ID = cmd & 0xFFFF; + break; + case A100_msg_SetAlgorithmParm: + if (a2220_param_ID == Mic_Config) { + if (a2220_NS_state == A2220_NS_STATE_CT) + filtered_cmd = (msg << 16); + else if (a2220_NS_state == A2220_NS_STATE_FT) + filtered_cmd = (msg << 16) | 0x0002; + } + break; + default: + if (mode == A2220_CONFIG_VP) + filtered_cmd = -1; + break; + } + + pr_info("%s: %x filtered = %x, a2220_NS_state %d, mode %d\n", __func__, + cmd, filtered_cmd, a2220_NS_state, mode); + + return filtered_cmd; +} + +int a2220_set_config(struct a2220_data *a2220, char newid, int mode) +{ + int i = 0, rc = 0, size = 0; + int retry = 4; + unsigned int sw_reset = 0; + unsigned char *i2c_cmds; + unsigned int msg; + unsigned char *pMsg; + + pr_info("[AUD] new mode = %d\n", newid); + if ((a2220->suspended) && (newid == A2220_PATH_SUSPEND)) + return rc; + + if ((a2220_current_config == newid) && + (a2220_current_config != A2220_PATH_PCMRESET)) { + pr_info("already configured this path!!!\n"); + return rc; + } + + rc = chk_wakeup_a2220(a2220); + if (rc < 0) + return rc; + + sw_reset = ((A100_msg_Reset << 16) | RESET_IMMEDIATE); + + switch (newid) { + case A2220_PATH_INCALL_RECEIVER_NSON: + i2c_cmds = phonecall_receiver_nson; + size = sizeof(phonecall_receiver_nson); + break; + case A2220_PATH_INCALL_RECEIVER_NSON_WB: + i2c_cmds = phonecall_receiver_nson_wb; + size = sizeof(phonecall_receiver_nson_wb); + break; + case A2220_PATH_INCALL_RECEIVER_NSOFF: + i2c_cmds = phonecall_receiver_nsoff; + size = sizeof(phonecall_receiver_nsoff); + break; +#ifdef AUDIENCE_BYPASS + case A2220_PATH_BYPASS_MULTIMEDIA: + pr_info("%s:A2220_PATH_BYPASS_MULTIMEDIA\n", __func__); + i2c_cmds = bypass_multimedia; + size = sizeof(bypass_multimedia); + break; +#endif + case A2220_PATH_INCALL_HEADSET: + i2c_cmds = phonecall_headset; + size = sizeof(phonecall_headset); + break; + case A2220_PATH_INCALL_SPEAKER: + i2c_cmds = phonecall_speaker; + size = sizeof(phonecall_speaker); + break; + case A2220_PATH_INCALL_BT: + i2c_cmds = phonecall_bt; + size = sizeof(phonecall_bt); + break; + case A2220_PATH_INCALL_TTY: + i2c_cmds = phonecall_tty; + size = sizeof(phonecall_tty); + break; + case A2220_PATH_VR_NO_NS_RECEIVER: + i2c_cmds = vr_no_ns_receiver; + size = sizeof(vr_no_ns_receiver); + break; + case A2220_PATH_VR_NO_NS_HEADSET: + i2c_cmds = vr_no_ns_headset; + size = sizeof(vr_no_ns_headset); + break; + case A2220_PATH_VR_NO_NS_SPEAKER: + i2c_cmds = vr_no_ns_speaker; + size = sizeof(vr_no_ns_speaker); + break; + case A2220_PATH_VR_NO_NS_BT: + i2c_cmds = vr_no_ns_bt; + size = sizeof(vr_no_ns_bt); + break; + case A2220_PATH_VR_NS_RECEIVER: + i2c_cmds = vr_ns_receiver; + size = sizeof(vr_ns_receiver); + break; + case A2220_PATH_VR_NS_HEADSET: + i2c_cmds = vr_ns_headset; + size = sizeof(vr_ns_headset); + break; + case A2220_PATH_VR_NS_SPEAKER: + i2c_cmds = vr_ns_speaker; + size = sizeof(vr_ns_speaker); + break; + case A2220_PATH_VR_NS_BT: + i2c_cmds = vr_ns_bt; + size = sizeof(vr_ns_bt); + break; + case A2220_PATH_RECORD_RECEIVER: + i2c_cmds = INT_MIC_recording_receiver; + size = sizeof(INT_MIC_recording_receiver); + break; + case A2220_PATH_RECORD_HEADSET: + i2c_cmds = EXT_MIC_recording; + size = sizeof(EXT_MIC_recording); + break; + case A2220_PATH_RECORD_SPEAKER: + i2c_cmds = INT_MIC_recording_speaker; + size = sizeof(INT_MIC_recording_speaker); + break; + case A2220_PATH_RECORD_BT: + i2c_cmds = phonecall_bt; + size = sizeof(phonecall_bt); + break; + case A2220_PATH_SUSPEND: + i2c_cmds = (unsigned char *)suspend_mode; + size = sizeof(suspend_mode); + break; + case A2220_PATH_CAMCORDER: + i2c_cmds = BACK_MIC_recording; + size = sizeof(BACK_MIC_recording); + break; + case A2220_PATH_PCMRESET: + i2c_cmds = pcm_reset; + size = sizeof(pcm_reset); + msleep(30); + break; + case A2220_PATH_FT_LOOPBACK: + i2c_cmds = ft_loopback; + size = sizeof(ft_loopback); + break; + default: + pr_err("%s: invalid cmd %d\n", __func__, newid); + rc = -1; + goto input_err; + break; + } + + a2220_current_config = newid; + + pr_info("%s: change to mode %d\n", __func__, newid); + pr_info("%s: block write start (size = %d)\n", __func__, size); + for (i = 1; i <= size; i++) { + pr_info("%x ", *(i2c_cmds + i - 1)); + if (!(i % 4)) + pr_info("\n"); + } + + pMsg = (unsigned char *)&msg; + + for (i = 0 ; i < size ; i += 4) { + pMsg[3] = i2c_cmds[i]; + pMsg[2] = i2c_cmds[i+1]; + pMsg[1] = i2c_cmds[i+2]; + pMsg[0] = i2c_cmds[i+3]; + + do { + rc = execute_cmdmsg(a2220, msg); + } while ((rc < 0) && --retry); + + if ((retry == 0) && (rc < 0)) { + struct a2220img img; + img.buf = a2220_firmware_buf; + img.img_size = sizeof(a2220_firmware_buf); + rc = a2220_hw_reset(a2220, &img); + if (rc < 0) { + pr_err("Audience HW Reset Failed\n"); + return rc; + } + } + + } + +input_err: + return rc; +} + +int execute_cmdmsg(struct a2220_data *a2220, unsigned int msg) +{ + int rc = 0; + int retries, pass = 0; + unsigned char msgbuf[4]; + unsigned char chkbuf[4]; + unsigned int sw_reset = 0; + + sw_reset = ((A100_msg_Reset << 16) | RESET_IMMEDIATE); + + msgbuf[0] = (msg >> 24) & 0xFF; + msgbuf[1] = (msg >> 16) & 0xFF; + msgbuf[2] = (msg >> 8) & 0xFF; + msgbuf[3] = msg & 0xFF; + + pr_info("%s : execute_cmdmsg :: %x %x %x %x\n" , __func__, + msgbuf[0] , msgbuf[1] , msgbuf[2] , msgbuf[3]); + memcpy(chkbuf, msgbuf, 4); + + rc = a2220_i2c_write(a2220, msgbuf, 4); + if (rc < 0) { + pr_err("%s: error %d\n", __func__, rc); + a2220_i2c_sw_reset(a2220, sw_reset); + + if (msg == A100_msg_Sleep) { + pr_info("execute_cmdmsg ...go to suspend first\n"); + a2220->suspended = 1; + msleep(120); + + } + return rc; + } + + pr_info("execute_cmdmsg + 1\n"); + /* We don't need to get Ack after sending out a suspend command */ + if (msg == A100_msg_Sleep) { + pr_info("%s : ...go to suspend first\n", __func__); + a2220->suspended = 1; + + return rc; + } + pr_info("execute_cmdmsg + 2\n"); + + retries = POLLING_RETRY_CNT; + while (retries--) { + rc = 0; + memset(msgbuf, 0, sizeof(msgbuf)); + rc = a2220_i2c_read(a2220, msgbuf, 4); + if (rc < 0) { + pr_err("%s: ack-read error %d (%d retries)\n", __func__, + rc, retries); + continue; + } + + pr_info("execute_cmdmsg + 3\n"); + + if (msgbuf[0] == 0x80 && msgbuf[1] == chkbuf[1]) { + pass = 1; + pr_info("execute_cmdmsg + 4\n"); + pr_info("got ACK\n"); + break; + } else if (msgbuf[0] == 0xff && msgbuf[1] == 0xff) { + pr_err("%s: illegal cmd %08x\n", __func__, msg); + rc = -EINVAL; + pr_info("execute_cmdmsg + 5\n"); + } else if (msgbuf[0] == 0x00 && msgbuf[1] == 0x00) { + pr_info("%s: not ready (%d retries)\n", __func__, + retries); + pr_info("execute_cmdmsg + 6\n"); + rc = -EBUSY; + } else { + pr_info("%s: cmd/ack mismatch: (%d retries left)\n", + __func__, + retries); + pr_err("%s: msgbuf[0] = %x\n", __func__, msgbuf[0]); + pr_err("%s: msgbuf[1] = %x\n", __func__, msgbuf[1]); + pr_err("%s: msgbuf[2] = %x\n", __func__, msgbuf[2]); + pr_err("%s: msgbuf[3] = %x\n", __func__, msgbuf[3]); + pr_err("execute_cmdmsg + 7\n"); + rc = -EBUSY; + } + msleep(20); /* use polling */ + } + + if (!pass) { + pr_err("%s: failed execute cmd %08x (%d)\n", __func__, + msg, rc); + a2220_i2c_sw_reset(a2220, sw_reset); + } + + pr_info("execute_cmdmsg - finish\n"); + + return rc; +} + +#if ENABLE_DIAG_IOCTLS +static int a2220_set_mic_state(struct a2220_data *a2220, char miccase) +{ + int rc = 0; + unsigned int cmd_msg = 0; + + switch (miccase) { + case 1: /* Mic-1 ON / Mic-2 OFF */ + cmd_msg = 0x80260007; + break; + case 2: /* Mic-1 OFF / Mic-2 ON */ + cmd_msg = 0x80260015; + break; + case 3: /* both ON */ + cmd_msg = 0x80260001; + break; + case 4: /* both OFF */ + cmd_msg = 0x80260006; + break; + default: + pr_info("%s: invalid input %d\n", __func__, miccase); + rc = -EINVAL; + break; + } + rc = execute_cmdmsg(a2220, cmd_msg); + return rc; +} + +static int exe_cmd_in_file(struct a2220_data *a2220, unsigned char *incmd) +{ + int rc = 0; + int i = 0; + unsigned int cmd_msg = 0; + unsigned char tmp = 0; + + for (i = 0; i < 4; i++) { + tmp = *(incmd + i); + cmd_msg |= (unsigned int)tmp; + if (i != 3) + cmd_msg = cmd_msg << 8; + } + rc = execute_cmdmsg(a2220, cmd_msg); + if (rc < 0) + pr_err("%s: cmd %08x error %d\n", __func__, cmd_msg, rc); + return rc; +} +#endif /* ENABLE_DIAG_IOCTLS */ + +static int thread_start(void *a2220) +{ + int rc = 0; + struct a2220img img; + pr_info("%s\n", __func__); + img.buf = a2220_firmware_buf; + img.img_size = sizeof(a2220_firmware_buf); + rc = a2220_bootup_init(a2220, &img); + return rc; +} + +static long a2220_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct a2220_data *a2220 = container_of(file->private_data, + struct a2220_data, device); + static struct task_struct *task; + int rc = 0; +#if 0 + char msg[4]; + int mic_cases = 0; + int mic_sel = 0; +#endif + int ns_state; + xoclk_control(true); + switch (cmd) { + case A2220_BOOTUP_INIT: + task = kthread_run(thread_start, a2220, "thread_start"); + if (IS_ERR(task)) { + rc = PTR_ERR(task); + task = NULL; + } + break; + case A2220_SET_CONFIG: + mutex_lock(&a2220->lock); + rc = a2220_set_config(a2220, arg, A2220_CONFIG_FULL); + if (rc < 0) + goto handle_error; + mutex_unlock(&a2220->lock); + break; + case A2220_SET_NS_STATE: + mutex_lock(&a2220->lock); + if (copy_from_user(&ns_state, argp, sizeof(ns_state))) { + rc = -EFAULT; + goto handle_error; + } + if (ns_state >= A2220_NS_NUM_STATES) { + rc = -EINVAL; + goto handle_error; + } + a2220_NS_state = ns_state; + if (!a2220->suspended) + a2220_set_config(a2220, a2220_current_config, + A2220_CONFIG_VP); + mutex_unlock(&a2220->lock); + break; +#if 0 + case A2220_SET_MIC_ONOFF: + mutex_lock(&a2220->lock); + rc = chk_wakeup_a2220(a2220); + if (rc < 0) + goto handle_error; + if (copy_from_user(&mic_cases, + argp, sizeof(mic_cases))) { + rc = -EFAULT; + goto handle_error; + } + rc = a2220_set_mic_state(a2220, mic_cases); + if (rc < 0) { + pr_err("%s: A2220_SET_MIC_ONOFF %d error %d!\n", + __func__, mic_cases, rc); + goto handle_error; + } + mutex_unlock(&a2220->lock); + break; + case A2220_SET_MICSEL_ONOFF: + mutex_lock(&a2220->lock); + rc = chk_wakeup_a2220(a2220); + if (rc < 0) + goto handle_error; + if (copy_from_user(&mic_sel, argp, sizeof(mic_sel))) { + rc = -EFAULT; + goto handle_error; + } + mutex_unlock(&a2220->lock); + break; + case A2220_READ_DATA: + mutex_lock(&a2220->lock); + rc = chk_wakeup_a2220(a2220); + if (rc < 0) + goto handle_error; + rc = a2220_i2c_read(a2220, msg, 4); + if (copy_to_user(argp, &msg, 4)) { + rc = -EFAULT; + goto handle_error; + } + mutex_unlock(&a2220->lock); + break; + case A2220_WRITE_MSG: + mutex_lock(&a2220->lock); + rc = chk_wakeup_a2220(a2220); + if (rc < 0) + goto handle_error; + if (copy_from_user(msg, argp, sizeof(msg))) { + rc = -EFAULT; + goto handle_error; + } + rc = a2220_i2c_write(a2220, msg, 4); + mutex_unlock(&a2220->lock); + break; + case A2220_SYNC_CMD: + mutex_lock(&a2220->lock); + rc = chk_wakeup_a2220(a2220); + if (rc < 0) + goto handle_error; + msg[0] = 0x80; + msg[1] = 0x00; + msg[2] = 0x00; + msg[3] = 0x00; + rc = a2220_i2c_write(a2220, msg, 4); + mutex_unlock(&a2220->lock); + break; + case A2220_SET_CMD_FILE: + mutex_lock(&a2220->lock); + rc = chk_wakeup_a2220(a2220); + if (rc < 0) + goto handle_error; + if (copy_from_user(msg, argp, sizeof(msg))) { + rc = -EFAULT; + goto handle_error; + } + rc = exe_cmd_in_file(msg); + mutex_unlock(&a2220->lock); + break; +#endif + default: + pr_err("%s: invalid command %d\n", __func__, _IOC_NR(cmd)); + rc = -EINVAL; + goto handle_error; + } + xoclk_control(false); + return rc; +handle_error: + mutex_unlock(&a2220->lock); + pr_err("%s rc[%d]\n", __func__, rc); + return rc; +} + +static const struct file_operations a2220_fops = { + .owner = THIS_MODULE, + .open = a2220_open, + .release = a2220_release, + .unlocked_ioctl = a2220_ioctl, +}; + +static int a2220_probe( + struct i2c_client *client, const struct i2c_device_id *id) +{ + int rc = 0; + struct a2220_data *a2220; + static struct a2220_platform_data *pdata; + + pdata = client->dev.platform_data; + if (pdata == NULL) { + pr_err("%s: platform data is NULL\n", __func__); + goto err_alloc_data_failed; + } + + if (!pdata->a2220_hw_init) { + pr_err("%s: a2220_hw_init is NULL\n", __func__); + goto err_alloc_data_failed; + } + + rc = pdata->a2220_hw_init(); + if (rc < 0) + goto err_alloc_data_failed; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s: i2c check functionality error\n", __func__); + rc = -ENODEV; + goto err_alloc_data_failed; + } + + a2220 = kzalloc(sizeof(*a2220), GFP_KERNEL); + if (!a2220) { + pr_err("failed to allocate memory for module data\n"); + rc = -ENOMEM; + goto err_alloc_data_failed; + } + + a2220->pdata = client->dev.platform_data; + mutex_init(&a2220->lock); + + i2c_set_clientdata(client, a2220); + a2220->this_client = client; + + a2220->device.minor = MISC_DYNAMIC_MINOR; + a2220->device.name = "audience_a2220"; + a2220->device.fops = &a2220_fops; + + rc = misc_register(&a2220->device); + if (rc) { + pr_err("%s: a2220_device register failed\n", __func__); + goto err_mem_alloc_failed; + } + + atomic_set(&a2220->opened, 1); + xo = msm_xo_get(MSM_XO_TCXO_D0, "audio_driver"); + if (!xo) { + pr_err("please check the xo driver,something is wrong!!"); + rc = -EAGAIN; + goto err_misc_register_failed; + } + kthread_run(thread_start, a2220, "thread_start"); + pr_info("a2220_probe - finish\n"); + return 0; + +err_misc_register_failed: + misc_deregister(&a2220->device); +err_mem_alloc_failed: + mutex_destroy(&a2220->lock); + kfree(a2220); +err_alloc_data_failed: + pr_err("a2220_probe - failed!!!\n"); + return rc; +} + +static int a2220_remove(struct i2c_client *client) +{ + struct a2220_data *a2220 = i2c_get_clientdata(client); + misc_deregister(&a2220->device); + mutex_destroy(&a2220->lock); + if (xo) { + msm_xo_put(xo); + xo = NULL; + } + kfree(a2220); + return 0; +} + +static int a2220_suspend(struct i2c_client *client, pm_message_t mesg) +{ + return 0; +} + +static int a2220_resume(struct i2c_client *client) +{ + return 0; +} + +static const struct i2c_device_id a2220_id[] = { + { "audience_a2220", 0 }, + { } +}; + +static struct i2c_driver a2220_driver = { + .probe = a2220_probe, + .remove = a2220_remove, + .suspend = a2220_suspend, + .resume = a2220_resume, + .id_table = a2220_id, + .driver = { + .name = "audience_a2220", + }, +}; + +static int __init a2220_init(void) +{ + return i2c_add_driver(&a2220_driver); +} + +static void __exit a2220_exit(void) +{ + i2c_del_driver(&a2220_driver); +} + +module_init(a2220_init); +module_exit(a2220_exit); + +MODULE_DESCRIPTION("A2220 voice processor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/a2220_firmware.h b/drivers/misc/a2220_firmware.h new file mode 100755 index 00000000000..3607d9e3acb --- /dev/null +++ b/drivers/misc/a2220_firmware.h @@ -0,0 +1,31 @@ +/* + * + * Copyright(C) 2012 Samsung Electronics All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#if defined(CONFIG_MACH_GOGH) || defined(CONFIG_MACH_INFINITE) +#include "a2220_firmware_gogh.h" +#elif defined(CONFIG_MACH_COMANCHE) +#include "a2220_firmware_comanche.h" +#elif defined(CONFIG_MACH_EXPRESS) +#include "a2220_firmware_express.h" +#elif defined(CONFIG_MACH_AEGIS2) +#include "a2220_firmware_aegis2.h" +#elif defined(CONFIG_MACH_JASPER) +#include "a2220_firmware_jasper.h" +#elif defined(_d2tmo_) +#include "a2220_firmware_t999.h" +#else +#include "a2220_firmware_i747.h" +#endif + diff --git a/drivers/misc/a2220_firmware_i747.h b/drivers/misc/a2220_firmware_i747.h new file mode 100644 index 00000000000..42d8c96a687 --- /dev/null +++ b/drivers/misc/a2220_firmware_i747.h @@ -0,0 +1,4867 @@ +/* + * + * Copyright(C) 2012 Samsung Electronics All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +/* D2 ATT eS305B Audience firmware */ +/* Version: M70.4.0.13_B10895_SEC_D2ATT_NB_I2C_STREAM_MCFFillIn_STREAM */ +unsigned char a2220_firmware_buf[] = { +0x41,0x55,0x44,0x49,0x45,0x4e,0x43,0x45,0x00,0x00,0x00,0x00,0x06,0x00,0x00, +0x00,0x84,0x03,0x08,0x20,0xc5,0x0b,0x00,0x00,0x00,0x01,0x05,0x20,0x00,0x00, +0x03,0x01,0x04,0x02,0x05,0x00,0x58,0x2d,0x18,0x20,0x00,0x00,0x00,0x00,0xd8, +0xe3,0x07,0x20,0xd3,0x75,0xb5,0xd3,0x01,0x00,0x00,0x00,0x00,0x4a,0x05,0x20, +0xf0,0x36,0x05,0x20,0x1c,0x09,0x18,0x20,0x60,0x0c,0x05,0x20,0x39,0x00,0x00, +0x00,0x10,0x96,0x19,0x20,0x54,0x97,0x19,0x20,0xb0,0x97,0x19,0x20,0x70,0x07, +0x05,0x20,0x00,0x00,0x80,0x46,0x04,0x33,0x0d,0x19,0xab,0xaa,0xaa,0x3c,0x00, +0x00,0xd0,0xcc,0x2f,0xba,0xe8,0x38,0x19,0x00,0x00,0x00,0xab,0xaa,0xaa,0x3c, +0x66,0x66,0x66,0x3a,0xba,0x49,0x0c,0x2c,0x00,0x00,0x00,0x43,0x00,0x00,0x40, +0x46,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x00,0x00,0x00,0x40,0x19,0x00, +0x00,0x00,0x30,0x15,0x05,0x20,0x19,0x00,0x00,0x00,0x00,0x00,0x80,0x4a,0x0d, +0x00,0x00,0x00,0xa0,0x15,0x05,0x20,0x0d,0x00,0x00,0x00,0x38,0x01,0x00,0x00, +0x1a,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x30,0x15,0x05, +0x20,0x00,0x00,0x00,0x43,0x18,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00, +0x00,0x3e,0x0d,0x00,0x00,0x00,0xe0,0x15,0x05,0x20,0x10,0x00,0x00,0x00,0x38, +0x01,0x00,0x00,0x08,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x20,0x16,0x05,0x20, +0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x80,0x0b, +0x39,0xb8,0x0b,0x00,0x00,0x29,0x5c,0x8f,0xb2,0xec,0x8d,0xea,0xcc,0xab,0xaa, +0xaa,0xbc,0x0d,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x1d, +0x00,0x00,0x00,0xf8,0x0c,0xbb,0x28,0xb8,0x0b,0x00,0x00,0x33,0x33,0x33,0x3f, +0x33,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x06,0x00,0x00, +0x00,0x60,0x16,0x05,0x20,0x62,0x27,0x76,0x38,0x0d,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x27,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x5a,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xa0,0x14,0x05,0x20,0x46,0xff,0xff,0x01, +0x0a,0x00,0x00,0x00,0x9f,0x0e,0x1f,0x37,0x9f,0x0e,0x1f,0x37,0x02,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x9f,0x0e,0x1f,0x37,0x00,0x00,0x80,0xcc,0x01,0x00, +0x00,0x00,0x76,0x5e,0xf1,0x3f,0x00,0x00,0x00,0x3e,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x9d,0x4a,0x87,0x3e, +0x6e,0xb9,0x8d,0x30,0xed,0x19,0x2e,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x80, +0xcc,0x00,0x00,0xc0,0xc9,0x00,0x00,0x80,0x46,0x14,0x00,0x00,0x00,0x05,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x80, +0x16,0x05,0x20,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x80,0x16,0x05,0x20,0x00,0x00,0x00, +0x00,0x0a,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x66,0x66,0x66,0xc4,0x01, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x90,0x16,0x05,0x20,0x5a,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xa0,0x14,0x05,0x20,0x00,0x00,0x00, +0x00,0x36,0x5c,0xff,0x3f,0x9e,0xef,0xff,0x3f,0x50,0x1f,0xfa,0x3f,0x36,0x5c, +0xff,0x3f,0x9e,0xef,0xff,0x3f,0x76,0x5e,0xf1,0x3f,0x03,0x00,0x00,0x00,0x15, +0x00,0x00,0x00,0xb0,0x16,0x05,0x20,0x50,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +0x33,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0xf4,0xde,0x18,0x18,0xc3,0x73,0xaf,0x23,0x70,0x12,0xe1,0x30,0xc2,0x2a, +0xb6,0x3f,0xb0,0xf4,0x02,0x40,0x1f,0x77,0x2b,0x41,0x00,0x00,0x20,0x4d,0xc3, +0x73,0xaf,0x23,0x9d,0x4a,0x87,0x3e,0x62,0xba,0xdd,0x3e,0x62,0xba,0xdd,0x3e, +0x1f,0x38,0xd3,0x40,0x06,0x93,0xfd,0x41,0xd1,0x94,0xea,0x3d,0x00,0x00,0x00, +0x3f,0x9a,0x99,0x99,0x3d,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x40,0x00,0x00, +0x80,0x46,0x82,0x3d,0x65,0x07,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0f, +0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x33,0x00,0x00,0x00,0xe0,0x16,0x05,0x20, +0x0b,0x00,0x17,0x00,0x0a,0x00,0x00,0x00,0xb0,0x19,0xf9,0x3f,0xe4,0xc6,0x46, +0x27,0xdc,0x31,0xaf,0x0a,0x33,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x03,0x00, +0x00,0x00,0x00,0x00,0x80,0x46,0x33,0x33,0x33,0x37,0x00,0x00,0xc0,0xcd,0x1f, +0x38,0xd3,0x40,0xcd,0xcc,0x8c,0x44,0x00,0x00,0x80,0xca,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1f,0x00,0x00,0x50,0x00,0x00, +0x00,0x00,0x33,0x33,0x33,0x03,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00, +0x01,0x00,0x03,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x14, +0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x50,0x17,0x05,0x20,0x03,0x00,0x00,0x00,0x60,0x17,0x05,0x20,0x03,0x00,0x00, +0x00,0x02,0x00,0x00,0x00,0x70,0x17,0x05,0x20,0xcd,0xcc,0xcc,0x3e,0x84,0x27, +0xfb,0x43,0x00,0x20,0x71,0x22,0x84,0x27,0xfb,0x43,0x84,0x27,0xfb,0x43,0x00, +0x20,0x54,0x76,0x84,0x27,0xfb,0x43,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00, +0x02,0x00,0x19,0x00,0x25,0x00,0x07,0x00,0x05,0x00,0x05,0x00,0x6c,0xa2,0x87, +0x3c,0x1c,0x62,0xd8,0x3a,0x31,0x6f,0x02,0x3c,0x0f,0x07,0x00,0x00,0x33,0x00, +0x00,0x00,0xc0,0x1a,0x05,0x20,0x33,0x00,0x00,0x00,0x30,0x1b,0x05,0x20,0x00, +0x2d,0x97,0x28,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x50,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x1f,0x00,0x00,0x50,0x00,0x00, +0x00,0x29,0x5c,0x8f,0xb6,0x0a,0x00,0x00,0x00,0x33,0x33,0x33,0x33,0x02,0x00, +0x00,0x00,0x95,0x7a,0xe6,0x3a,0x01,0x00,0x00,0x00,0x00,0x00,0x40,0x46,0x00, +0x00,0x00,0xc4,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xc9,0x00,0x00,0x40,0xc9,0x00,0x00,0x40, +0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xc9,0x00, +0x00,0xd0,0xcc,0x00,0x00,0x00,0x44,0x00,0x00,0xc0,0x47,0x00,0x00,0x00,0x44, +0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x00,0x29,0x25,0x35,0x37,0xba,0x49,0x0c, +0x2a,0xba,0x49,0x0c,0x2a,0xba,0x49,0x0c,0x2a,0xba,0x49,0x0c,0x2a,0x50,0x00, +0x00,0x00,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x40,0x50,0x00,0x00,0x00,0x95, +0x7a,0xe6,0x3a,0x00,0x00,0x80,0x46,0x00,0x00,0x00,0xc2,0x19,0xf4,0xff,0x3f, +0xab,0x6a,0x75,0x3f,0x34,0xa5,0x30,0x31,0x08,0xa8,0xe0,0x37,0x37,0xaf,0xf9, +0x22,0x54,0x55,0x2a,0x3a,0xb6,0x9e,0xf9,0x3f,0x7f,0xf5,0xc1,0x3f,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0xcc, +0x5d,0xdc,0x46,0x25,0xcb,0x8a,0x12,0x22,0x61,0x64,0x2d,0x3f,0xcb,0x8a,0x12, +0x22,0x29,0x5c,0x8f,0x32,0x7d,0x2d,0x97,0x28,0x00,0x00,0x00,0x46,0x29,0x5c, +0x8f,0x32,0x00,0x00,0x00,0x3e,0x29,0x5c,0x8f,0x32,0xf6,0x28,0x5c,0x3b,0x7b, +0x14,0xae,0x3d,0x00,0x33,0x33,0x39,0x00,0xd3,0x25,0x3d,0x00,0x9a,0x99,0xc3, +0x6f,0x12,0x83,0x41,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x0e,0x7f,0xfc, +0x41,0x00,0xa3,0x02,0x3f,0x1d,0xb7,0xbc,0xc9,0x00,0x7f,0xfc,0x3f,0x33,0x33, +0x33,0x39,0x00,0xb9,0x8d,0x30,0x00,0xef,0xba,0x28,0x00,0x00,0xa8,0xcc,0x00, +0x00,0x00,0xcd,0x05,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x33,0x00,0x00,0x00,0xa0,0x1b,0x05,0x20,0x00,0x6f,0x02,0x3c,0x0f,0x00,0x05, +0x00,0x00,0x37,0x01,0x3e,0x00,0x7b,0xe6,0x3a,0x00,0x18,0x8c,0x32,0x00,0x2c, +0x89,0x3a,0x00,0x92,0x0b,0x39,0x00,0xfe,0x5a,0x11,0x33,0x00,0x00,0x00,0x70, +0x1c,0x05,0x20,0x00,0xcd,0x8c,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xda,0x88,0x34,0x00,0x33,0x33,0x39,0x00,0x9c,0xcb,0x39,0xfb,0xff,0x09, +0x00,0x00,0xe5,0x27,0x45,0x0d,0x00,0x00,0x00,0xb0,0x1c,0x05,0x20,0x00,0x0c, +0xfa,0x34,0x04,0x00,0x00,0x00,0xd0,0x1c,0x05,0x20,0x08,0x00,0x00,0x00,0xe0, +0x1c,0x05,0x20,0x07,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x1d,0x05,0x20, +0x00,0x00,0x00,0xcb,0x00,0xda,0x88,0x34,0x00,0x18,0x8c,0x32,0x00,0x00,0xc0, +0xcb,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x43,0x01,0x00,0x00,0x00,0x00,0x33, +0x33,0x39,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x1d,0x05,0x20,0x04, +0x00,0x00,0x00,0x30,0x1d,0x05,0x20,0x00,0x7b,0xe6,0x3a,0x00,0x00,0x00,0xcb, +0x00,0x38,0xd3,0x40,0x66,0x66,0xde,0x4a,0x08,0x03,0x18,0x05,0x78,0x00,0x00, +0x00,0x40,0x1d,0x05,0x20,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, +0x00,0x40,0x33,0x00,0x00,0x00,0x20,0x1f,0x05,0x20,0x46,0xff,0xff,0x01,0x00, +0x00,0x00,0x06,0x33,0x33,0x33,0x39,0x03,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +0xf0,0x1f,0x05,0x20,0x19,0xf4,0xff,0x3f,0x91,0xd9,0x88,0x34,0x9d,0x4a,0x87, +0x3e,0x9f,0x0e,0x1f,0x37,0x00,0x00,0x00,0x40,0x5d,0xdc,0x46,0x25,0xb1,0x16, +0x9f,0x1e,0xc9,0xed,0xf3,0x49,0x01,0xcc,0xcf,0x44,0x27,0xfe,0x11,0x40,0xe0, +0xb0,0xe8,0x3f,0x7d,0x2d,0x97,0x28,0x84,0x27,0xfb,0x43,0xcd,0xcc,0x8c,0x44, +0x71,0x3d,0x0a,0x42,0x84,0x27,0xfb,0x43,0xcd,0xcc,0x8c,0x44,0x71,0x3d,0x0a, +0x42,0x84,0x27,0xfb,0x43,0xcd,0xcc,0x8c,0x44,0x71,0x3d,0x0a,0x42,0x84,0x27, +0xfb,0x43,0xcd,0xcc,0x8c,0x44,0xff,0xff,0xff,0x7f,0x00,0x00,0xc0,0xc7,0x00, +0x00,0x80,0x46,0x17,0x18,0x8c,0x32,0x66,0x92,0x0b,0x39,0x44,0x01,0x05,0x20, +0x58,0x01,0x05,0x20,0x9c,0x01,0x05,0x20,0xf0,0x01,0x05,0x20,0x10,0x02,0x05, +0x20,0x38,0x02,0x05,0x20,0x48,0x02,0x05,0x20,0x78,0x02,0x05,0x20,0xd8,0x02, +0x05,0x20,0x70,0x4a,0x05,0x20,0x78,0x4a,0x05,0x20,0x34,0x03,0x05,0x20,0x98, +0x03,0x05,0x20,0xb8,0x03,0x05,0x20,0xc8,0x03,0x05,0x20,0xfc,0x03,0x05,0x20, +0x18,0x04,0x05,0x20,0x80,0x4a,0x05,0x20,0x64,0x04,0x05,0x20,0x68,0x04,0x05, +0x20,0x94,0x47,0x05,0x20,0x80,0x04,0x05,0x20,0xa0,0x4a,0x05,0x20,0xac,0x05, +0x05,0x20,0xbc,0x05,0x05,0x20,0xd4,0x05,0x05,0x20,0xf8,0x05,0x05,0x20,0x04, +0x06,0x05,0x20,0x78,0x48,0x05,0x20,0xdc,0x06,0x05,0x20,0xe0,0x06,0x05,0x20, +0xb0,0x4a,0x05,0x20,0xec,0x06,0x05,0x20,0xf4,0x06,0x05,0x20,0x00,0x07,0x05, +0x20,0x30,0x07,0x05,0x20,0x3c,0x07,0x05,0x20,0x48,0x07,0x05,0x20,0x54,0x07, +0x05,0x20,0x60,0x07,0x05,0x20,0x6c,0x07,0x05,0x20,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0xee,0xff, +0x00,0x00,0x00,0x00,0x00,0x00,0xfd,0xff,0x01,0x00,0xac,0xff,0x06,0x00,0x03, +0x00,0x02,0x00,0x01,0x00,0xe6,0xff,0x04,0x00,0xa6,0xff,0x0f,0x00,0x04,0x00, +0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfd, +0xff,0x06,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0xe6,0xff,0x04,0x00,0xa6,0xff, +0x0f,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f, +0x00,0xf0,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x00,0x00,0x00, +0x00,0x00,0x19,0x00,0x00,0x00,0x00,0x00,0xfa,0xff,0x00,0x00,0xac,0xff,0x01, +0x00,0x01,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0xd0,0x20,0x05,0x20,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0xd8,0x20,0x05,0x20,0x07,0x00,0x00,0x00,0x70,0x20, +0x05,0x20,0x07,0x00,0x00,0x00,0xe0,0x20,0x05,0x20,0x07,0x00,0x00,0x00,0x50, +0x20,0x05,0x20,0x07,0x00,0x00,0x00,0xf0,0x20,0x05,0x20,0x00,0x00,0x00,0x40, +0x00,0x00,0x00,0x40,0x31,0x6f,0x02,0x3c,0x84,0x27,0xfb,0x43,0x07,0x00,0x00, +0x00,0x10,0x21,0x05,0x20,0x07,0x00,0x00,0x00,0x70,0x20,0x05,0x20,0x00,0x00, +0x00,0x00,0xf7,0xff,0xff,0xff,0x33,0x00,0x00,0x00,0x70,0x20,0x05,0x20,0x02, +0x00,0x02,0x00,0x0e,0x00,0x00,0x00,0x20,0x21,0x05,0x20,0x0e,0x00,0x00,0x00, +0x40,0x21,0x05,0x20,0x02,0x00,0x02,0x00,0x0e,0x00,0x00,0x00,0x60,0x21,0x05, +0x20,0x0e,0x00,0x00,0x00,0x80,0x21,0x05,0x20,0x02,0x00,0x00,0x00,0x0e,0x00, +0x00,0x00,0x20,0x21,0x05,0x20,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x02, +0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x60,0x21,0x05,0x20,0x00,0x00,0x00,0x00, +0x80,0x4f,0x05,0x20,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x05,0x00,0x00, +0x00,0xa0,0x21,0x05,0x20,0x05,0x00,0x00,0x00,0xb0,0x21,0x05,0x20,0x05,0x00, +0x00,0x00,0xc0,0x21,0x05,0x20,0x05,0x00,0x00,0x00,0x50,0x20,0x05,0x20,0x05, +0x00,0x00,0x00,0xb0,0x20,0x05,0x20,0x05,0x00,0x00,0x00,0xb0,0x20,0x05,0x20, +0x05,0x00,0x00,0x00,0xe0,0x21,0x05,0x20,0x05,0x00,0x00,0x00,0xb0,0x20,0x05, +0x20,0x1e,0x00,0x00,0x00,0x00,0x22,0x05,0x20,0x1e,0x00,0x00,0x00,0x00,0x22, +0x05,0x20,0x00,0x00,0x00,0x3e,0x66,0x00,0x00,0x00,0x40,0x22,0x05,0x20,0x33, +0x00,0x00,0x00,0xe0,0x23,0x05,0x20,0x33,0x00,0x00,0x00,0x50,0x24,0x05,0x20, +0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xc3,0xf5,0x28,0x44,0x82,0x3d,0x65, +0x07,0x33,0x33,0x33,0x39,0x10,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x20,0x25, +0x05,0x20,0x33,0x00,0x00,0x00,0xc0,0x26,0x05,0x20,0x33,0x00,0x00,0x00,0x30, +0x27,0x05,0x20,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xc3,0xf5,0x28,0x44, +0x82,0x3d,0x65,0x07,0x33,0x33,0x33,0x39,0x10,0x00,0x00,0x00,0x66,0x00,0x00, +0x00,0x20,0x25,0x05,0x20,0x33,0x00,0x00,0x00,0xc0,0x26,0x05,0x20,0x33,0x00, +0x00,0x00,0x30,0x27,0x05,0x20,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xc3, +0xf5,0x28,0x44,0x82,0x3d,0x65,0x07,0xe1,0x7a,0x14,0x3a,0x10,0x00,0x00,0x00, +0x00,0x00,0x20,0xcd,0x30,0x00,0x00,0x00,0x00,0x00,0x20,0xcd,0x25,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x00, +0x00,0x00,0x04,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x28,0x05,0x20,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x07,0x00,0x00,0x00, +0x40,0x28,0x05,0x20,0x07,0x00,0x00,0x00,0xb0,0x20,0x05,0x20,0x07,0x00,0x00, +0x00,0x50,0x28,0x05,0x20,0x0c,0x00,0x00,0x00,0x70,0x28,0x05,0x20,0x48,0x00, +0x00,0x00,0x90,0x28,0x05,0x20,0x06,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x20, +0x29,0x05,0x20,0x0b,0x00,0x00,0x00,0x90,0x29,0x05,0x20,0x0c,0x00,0x00,0x00, +0xb0,0x29,0x05,0x20,0x48,0x00,0x00,0x00,0xd0,0x29,0x05,0x20,0x06,0x00,0x00, +0x00,0x33,0x00,0x00,0x00,0x20,0x29,0x05,0x20,0x0b,0x00,0x00,0x00,0x60,0x2a, +0x05,0x20,0x07,0x00,0x00,0x00,0x80,0x2a,0x05,0x20,0x07,0x00,0x00,0x00,0x90, +0x2a,0x05,0x20,0x07,0x00,0x00,0x00,0x50,0x28,0x05,0x20,0x34,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0xb0,0x2a,0x05,0x20,0x68,0x00,0x00,0x00,0xc0,0x2a,0x05, +0x20,0x0b,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x32,0x00,0x00,0x00,0x04,0x00, +0x0f,0x00,0xff,0xff,0x9a,0xf9,0x9a,0xf9,0x00,0x00,0x32,0x00,0x27,0x00,0x00, +0x00,0x04,0x00,0x0f,0x00,0xff,0xff,0x9a,0xf9,0x5c,0xff,0x00,0x00,0x32,0x00, +0x2e,0x00,0x00,0x00,0x04,0x00,0x0f,0x00,0xff,0xff,0x9a,0xf9,0x5c,0xff,0x00, +0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0xff,0xff, +0x00,0x00,0x34,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x90,0x2b,0x05,0x20,0x9c, +0x00,0x00,0x00,0xa0,0x2b,0x05,0x20,0x07,0x00,0x00,0x00,0xe0,0x2c,0x05,0x20, +0x07,0x00,0x00,0x00,0x00,0x2d,0x05,0x20,0x07,0x00,0x00,0x00,0x20,0x2d,0x05, +0x20,0x12,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x2d,0x05,0x20,0x02,0x00, +0x00,0x00,0x50,0x2d,0x05,0x20,0x02,0x00,0x00,0x00,0x60,0x2d,0x05,0x20,0x02, +0x00,0x00,0x00,0x50,0x2d,0x05,0x20,0x02,0x00,0x00,0x00,0x70,0x2d,0x05,0x20, +0x02,0x00,0x00,0x00,0x50,0x2d,0x05,0x20,0x33,0x33,0x33,0x3b,0x66,0x66,0x66, +0x3e,0x33,0x33,0x33,0x3b,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,0x3f,0x33,0x33, +0x33,0x37,0x66,0x66,0x66,0x3e,0x33,0x33,0x33,0x3b,0x66,0x66,0x66,0x3c,0x00, +0x00,0x00,0x3f,0x33,0x33,0x33,0x39,0x66,0x66,0x66,0x3e,0x33,0x33,0x33,0x3b, +0x66,0x66,0x66,0x3c,0x00,0x00,0x00,0x3f,0x04,0x00,0x00,0x00,0x02,0x00,0x00, +0x00,0x80,0x2d,0x05,0x20,0x02,0x00,0x00,0x00,0x90,0x2d,0x05,0x20,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x00,0x00,0x00,0x00,0x80, +0x4f,0x05,0x20,0x33,0x00,0x00,0x00,0xa0,0x2d,0x05,0x20,0x1f,0x00,0x00,0x00, +0x33,0x00,0x00,0x00,0x10,0x2e,0x05,0x20,0x1f,0x00,0x00,0x00,0x33,0x00,0x00, +0x00,0x80,0x2e,0x05,0x20,0x1f,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xf0,0x2e, +0x05,0x20,0x1f,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x60,0x2f,0x05,0x20,0x1f, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x00,0x00,0x00,0x00, +0x14,0x08,0x05,0x20,0xa0,0x08,0x05,0x20,0xf8,0x08,0x05,0x20,0xc0,0x4a,0x05, +0x20,0xe0,0x4a,0x05,0x20,0x00,0x4b,0x05,0x20,0x58,0x09,0x05,0x20,0x20,0x4b, +0x05,0x20,0x40,0x4b,0x05,0x20,0xb0,0x09,0x05,0x20,0x60,0x4b,0x05,0x20,0x80, +0x4b,0x05,0x20,0xa0,0x4b,0x05,0x20,0x7c,0x0a,0x05,0x20,0xc0,0x4b,0x05,0x20, +0xdc,0x0a,0x05,0x20,0xf4,0x0a,0x05,0x20,0xe0,0x4b,0x05,0x20,0x44,0x0b,0x05, +0x20,0x80,0x0b,0x05,0x20,0x00,0x4c,0x05,0x20,0x20,0x4c,0x05,0x20,0x40,0x4c, +0x05,0x20,0x60,0x4c,0x05,0x20,0x80,0x4c,0x05,0x20,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x4f,0x53,0x4b,0x4f,0x5f,0x4c,0x41, +0x42,0x45,0x4c,0x3a,0x42,0x4f,0x53,0x4b,0x4f,0x5f,0x36,0x30,0x2e,0x30,0x32, +0x2e,0x34,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x57,0x43,0x3a,0x24,0x43, +0x68,0x61,0x6e,0x67,0x65,0x3a,0x20,0x39,0x30,0x33,0x35,0x38,0x70,0x20,0x24, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x77,0x63,0x5f, +0x53,0x45,0x43,0x5f,0x44,0x32,0x41,0x54,0x54,0x00,0x00,0x00,0x62,0x6e,0x6f, +0x3a,0x31,0x31,0x30,0x38,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xec, +0x48,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xdc,0x42,0x08,0x20,0x40,0x48,0x08, +0x20,0xa0,0x44,0x08,0x20,0x6c,0x43,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44, +0x4b,0x08,0x20,0x10,0x4b,0x08,0x20,0x9c,0x2a,0x08,0x20,0x4c,0x42,0x08,0x20, +0x14,0x42,0x08,0x20,0xb4,0x41,0x08,0x20,0x00,0x00,0x00,0x00,0x38,0x2b,0x08, +0x20,0x20,0x2b,0x08,0x20,0x04,0x2b,0x08,0x20,0xb4,0x2a,0x08,0x20,0xd4,0x4a, +0x08,0x20,0x9c,0x4a,0x08,0x20,0x7c,0x2a,0x08,0x20,0x60,0x2a,0x08,0x20,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x48,0x08,0x20, +0x60,0x41,0x08,0x20,0xd4,0x47,0x08,0x20,0xf4,0x47,0x08,0x20,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x47,0x08,0x20,0x00,0x00,0x00,0x00,0xa0, +0x46,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x43,0x08,0x20,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0x2b,0x08,0x20,0xc8,0x2a,0x08,0x20, +0x34,0x4b,0x08,0x20,0x38,0x4a,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x08,0x4a,0x08,0x20,0x18,0x4a,0x08,0x20,0x7c,0x4d, +0x08,0x20,0xe4,0x4c,0x08,0x20,0xbc,0x42,0x08,0x20,0x9c,0x42,0x08,0x20,0x7c, +0x42,0x08,0x20,0xf8,0x42,0x08,0x20,0x18,0x43,0x08,0x20,0x04,0x49,0x08,0x20, +0x00,0x00,0x00,0x00,0x40,0x48,0x08,0x20,0xa0,0x44,0x08,0x20,0x6c,0x43,0x08, +0x20,0x00,0x00,0x00,0x00,0x7c,0x38,0x05,0x20,0x00,0x00,0x1f,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x1f,0x00,0x84,0x38,0x05,0x20,0x00,0x00,0x20,0x00,0x88, +0x38,0x05,0x20,0x00,0x00,0x20,0x00,0x98,0x38,0x05,0x20,0x00,0x00,0x03,0x00, +0x98,0x38,0x05,0x20,0x00,0x00,0x01,0x00,0x98,0x38,0x05,0x20,0x00,0x00,0x01, +0x00,0x98,0x38,0x05,0x20,0x00,0x00,0x01,0x00,0xbc,0x3a,0x05,0x20,0x00,0x00, +0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0xc4,0x3a,0x05,0x20,0x00, +0x00,0x20,0x00,0xc8,0x3a,0x05,0x20,0x00,0x00,0x20,0x00,0xd8,0x3a,0x05,0x20, +0x00,0x00,0x03,0x00,0xd8,0x3a,0x05,0x20,0x00,0x00,0x01,0x00,0xd8,0x3a,0x05, +0x20,0x00,0x00,0x01,0x00,0xd8,0x3a,0x05,0x20,0x00,0x00,0x01,0x00,0xfc,0x3c, +0x05,0x20,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x04, +0x3d,0x05,0x20,0x00,0x00,0x20,0x00,0x08,0x3d,0x05,0x20,0x00,0x00,0x20,0x00, +0x18,0x3d,0x05,0x20,0x00,0x00,0x03,0x00,0x18,0x3d,0x05,0x20,0x00,0x00,0x01, +0x00,0x18,0x3d,0x05,0x20,0x00,0x00,0x01,0x00,0x18,0x3d,0x05,0x20,0x00,0x00, +0x01,0x00,0x3c,0x3f,0x05,0x20,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x1f,0x00,0x44,0x3f,0x05,0x20,0x00,0x00,0x20,0x00,0x48,0x3f,0x05,0x20, +0x00,0x00,0x20,0x00,0x58,0x3f,0x05,0x20,0x00,0x00,0x03,0x00,0x58,0x3f,0x05, +0x20,0x00,0x00,0x01,0x00,0x58,0x3f,0x05,0x20,0x00,0x00,0x01,0x00,0x58,0x3f, +0x05,0x20,0x00,0x00,0x01,0x00,0x40,0x36,0x05,0x20,0x00,0x00,0x0e,0x00,0x4c, +0x36,0x05,0x20,0x00,0x00,0x0e,0x00,0x58,0x36,0x05,0x20,0x00,0x00,0x0e,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x36,0x05,0x20,0x00,0x00,0x0e, +0x00,0x70,0x36,0x05,0x20,0x00,0x00,0x09,0x00,0x74,0x36,0x05,0x20,0x00,0x00, +0x01,0x00,0xd0,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0xd8,0x36,0x05,0x20,0x00, +0x00,0x10,0x00,0xdc,0x36,0x05,0x20,0x00,0x00,0x04,0x00,0xe0,0x36,0x05,0x20, +0x00,0x00,0x01,0x00,0xc8,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0x64,0x36,0x05, +0x20,0x00,0x00,0x01,0x00,0x6c,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0x78,0x36, +0x05,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, +0x36,0x05,0x20,0x00,0x00,0x0e,0x00,0x88,0x36,0x05,0x20,0x00,0x00,0x09,0x00, +0x8c,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0xd4,0x36,0x05,0x20,0x00,0x00,0x01, +0x00,0xd8,0x36,0x05,0x20,0x00,0x00,0x10,0x00,0xdc,0x36,0x05,0x20,0x00,0x00, +0x04,0x00,0xe0,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0xcc,0x36,0x05,0x20,0x00, +0x00,0x01,0x00,0x7c,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0x84,0x36,0x05,0x20, +0x00,0x00,0x01,0x00,0x90,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xc0,0x36,0x05,0x20,0x00,0x00,0x0e,0x00,0xbc,0x36, +0x05,0x20,0x00,0x00,0x01,0x00,0xd8,0x36,0x05,0x20,0x00,0x00,0x10,0x00,0xe0, +0x36,0x05,0x20,0x00,0x00,0x01,0x00,0xb4,0x36,0x05,0x20,0x00,0x00,0x01,0x00, +0xb8,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0xc4,0x36,0x05,0x20,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x36,0x05,0x20,0x00,0x00, +0x0e,0x00,0x9c,0x36,0x05,0x20,0x00,0x00,0x04,0x00,0xd0,0x36,0x05,0x20,0x00, +0x00,0x01,0x00,0xe0,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0xc8,0x36,0x05,0x20, +0x00,0x00,0x01,0x00,0x94,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0xa0,0x36,0x05, +0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x36, +0x05,0x20,0x00,0x00,0x0e,0x00,0xac,0x36,0x05,0x20,0x00,0x00,0x04,0x00,0xd4, +0x36,0x05,0x20,0x00,0x00,0x01,0x00,0xe0,0x36,0x05,0x20,0x00,0x00,0x01,0x00, +0xcc,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0xa4,0x36,0x05,0x20,0x00,0x00,0x01, +0x00,0xb0,0x36,0x05,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x0e,0x05,0x20,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x0e,0x05,0x20,0x08,0x00,0x00,0x00, +0xd0,0x0e,0x05,0x20,0x08,0x00,0x00,0x00,0x10,0x0f,0x05,0x20,0x08,0x00,0x00, +0x00,0x50,0x0f,0x05,0x20,0x08,0x00,0x00,0x00,0x90,0x0f,0x05,0x20,0x01,0x00, +0x00,0x00,0x98,0x0f,0x05,0x20,0x01,0x00,0x00,0x00,0xb0,0x0f,0x05,0x20,0x0b, +0x00,0x00,0x00,0x10,0x10,0x05,0x20,0x0b,0x00,0x00,0x00,0x70,0x10,0x05,0x20, +0x07,0x00,0x00,0x00,0xa0,0x0f,0x05,0x20,0x01,0x00,0x00,0x00,0xb0,0x10,0x05, +0x20,0x07,0x00,0x00,0x00,0xf0,0x10,0x05,0x20,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x08,0x00,0x00, +0x00,0x0a,0x00,0x00,0x00,0x05,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x4d,0x37,0x30,0x2e,0x34,0x2e,0x30,0x2e,0x31,0x33,0x5f,0x42,0x31, +0x31,0x30,0x38,0x32,0x5f,0x53,0x45,0x43,0x5f,0x44,0x32,0x41,0x54,0x54,0x5f, +0x4e,0x42,0x5f,0x49,0x32,0x43,0x5f,0x53,0x54,0x52,0x45,0x41,0x4d,0x5f,0x4d, +0x43,0x46,0x46,0x69,0x6c,0x6c,0x49,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xb4,0x54,0xa8,0x3a,0xc3,0x43,0x20,0x34,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0xc8,0x00,0x01,0x00,0xff,0xff, +0xff,0x00,0xcc,0x00,0x01,0x00,0xff,0xff,0x08,0x00,0x04,0x00,0x00,0x02,0x80, +0x00,0x02,0x00,0x08,0x00,0x00,0x06,0x00,0x00,0x01,0x00,0xd4,0x00,0x00,0x01, +0x7c,0x00,0x4b,0x00,0x10,0x00,0x00,0x0f,0x20,0x00,0x4c,0x00,0x14,0x00,0x00, +0x0f,0x42,0x00,0x15,0x00,0x18,0x00,0x00,0x02,0x10,0x00,0x16,0x00,0x1c,0x00, +0xc9,0xf3,0x12,0x00,0x1f,0x00,0x20,0x00,0x00,0x02,0x64,0x00,0x20,0x00,0x24, +0x00,0x00,0x02,0x36,0x00,0x09,0x00,0x28,0x00,0x00,0x04,0x58,0x00,0x0d,0x00, +0xb8,0x00,0xd8,0x00,0x40,0x00,0x0e,0x00,0x2c,0x00,0x00,0x04,0x44,0x00,0x25, +0x00,0xb4,0x00,0xe2,0x1e,0x62,0x00,0x36,0x00,0x30,0x00,0x00,0x01,0x0c,0x00, +0x31,0x00,0x34,0x00,0x00,0x02,0x66,0x00,0x30,0x00,0x38,0x00,0x00,0x02,0x38, +0x00,0x03,0x00,0x44,0x00,0x00,0x05,0x02,0x00,0x34,0x00,0x5c,0x00,0x80,0x7f, +0x08,0x00,0x1a,0x00,0x48,0x00,0x00,0x01,0x1c,0x00,0x1b,0x00,0x64,0x00,0xa0, +0xce,0x1e,0x00,0x23,0x00,0x4c,0x00,0x00,0x01,0x04,0x00,0x2e,0x00,0x50,0x00, +0xa6,0x00,0x06,0x00,0x21,0x00,0xd0,0x00,0x00,0x01,0x82,0x00,0x1e,0x00,0x0c, +0x00,0x01,0x07,0x22,0x00,0x37,0x00,0x60,0x00,0x0a,0x64,0x0e,0x00,0x04,0x00, +0x40,0x00,0x00,0x01,0x26,0x00,0x05,0x00,0x68,0x00,0xdc,0x00,0x28,0x00,0x06, +0x00,0x70,0x00,0xa6,0xe2,0x2c,0x00,0x07,0x00,0x6c,0x00,0x00,0x04,0x2a,0x00, +0x00,0x01,0xe0,0x00,0x00,0x2d,0x2e,0x00,0x26,0x00,0x74,0x00,0x00,0x32,0x30, +0x00,0x27,0x00,0x78,0x00,0x00,0x64,0x32,0x00,0x3e,0x00,0x7c,0x00,0x00,0x0f, +0x34,0x00,0x28,0x00,0x3c,0x00,0x00,0x01,0x48,0x00,0x29,0x00,0x80,0x00,0xdc, +0x00,0x4a,0x00,0x2a,0x00,0x88,0x00,0xa6,0xe2,0x4e,0x00,0x2b,0x00,0x84,0x00, +0x00,0x04,0x4c,0x00,0x02,0x01,0xe4,0x00,0x00,0x2d,0x50,0x00,0x2c,0x00,0x8c, +0x00,0x00,0x32,0x52,0x00,0x2d,0x00,0x90,0x00,0x00,0x32,0x54,0x00,0x3f,0x00, +0x94,0x00,0x00,0x0f,0x56,0x00,0x41,0x00,0x98,0x00,0xa6,0x1e,0x14,0x00,0x42, +0x00,0x9c,0x00,0xd8,0x00,0x16,0x00,0x44,0x00,0xa0,0x00,0xa6,0x1e,0x18,0x00, +0x39,0x00,0xa4,0x00,0x01,0x02,0x24,0x00,0x12,0x00,0xa8,0x00,0xa6,0x28,0x3c, +0x00,0x14,0x00,0xd8,0x00,0x00,0x01,0x7e,0x00,0x43,0x00,0xac,0x00,0x01,0x02, +0x46,0x00,0x3d,0x00,0xb0,0x00,0x00,0x0f,0x5e,0x00,0x40,0x00,0xbc,0x00,0xd8, +0x00,0x1a,0x00,0x19,0x00,0xc0,0x00,0xa6,0x1e,0x3e,0x00,0x3c,0x00,0xdc,0x00, +0x80,0x7f,0x88,0x00,0x3a,0x00,0xc4,0x00,0x00,0x01,0x3a,0x00,0x47,0x00,0xe8, +0x00,0xe7,0x32,0x86,0x00,0x56,0x00,0xec,0x00,0x00,0x06,0x84,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0x05,0x20,0x3c,0x01,0x05,0x20,0x88, +0x85,0x17,0x20,0x88,0x85,0x17,0x20,0x30,0x85,0x17,0x20,0x30,0x85,0x17,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4e,0x42,0x5f,0x53,0x45,0x43,0x5f, +0x44,0x32,0x5f,0x41,0x54,0x54,0x00,0x00,0x00,0x41,0x4c,0x47,0x4f,0x5f,0x4c, +0x41,0x42,0x45,0x4c,0x3a,0x20,0x6a,0x75,0x72,0x61,0x5f,0x37,0x30,0x2e,0x34, +0x2e,0x30,0x5f,0x4d,0x61,0x74,0x5f,0x63,0x31,0x31,0x5f,0x44,0x32,0x30,0x30, +0x5f,0x63,0x31,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x30,0xe3, +0xc6,0xa4,0x09,0x57,0x1d,0xa4,0x89,0x7b,0x97,0x09,0x48,0x00,0x40,0xd5,0xd8, +0x0e,0x06,0x87,0x3b,0xc5,0x82,0x5e,0xb7,0x62,0x55,0x00,0x40,0xae,0xde,0xb5, +0x81,0x79,0x3e,0x56,0x01,0xfc,0xbc,0xc3,0x5d,0x00,0x00,0x00,0x00,0x00,0x00, +0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff, +0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff, +0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46, +0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x00, +0x00,0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x09,0x00, +0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0xd0,0xcc,0x00,0x00,0xb8,0xcc,0x00, +0x00,0xa0,0xcc,0x00,0x00,0x88,0xcc,0x00,0x00,0x70,0xcc,0x00,0x00,0x58,0xcc, +0x00,0x00,0x40,0xcc,0x00,0x00,0x28,0xcc,0x00,0x00,0x10,0xcc,0x00,0x00,0xf0, +0xcb,0x00,0x00,0xc0,0xcb,0x00,0x00,0x90,0xcb,0x00,0x00,0x60,0xcb,0x00,0x00, +0x30,0xcb,0x00,0x00,0x00,0xcb,0x00,0x00,0xd0,0xca,0x00,0x00,0xa0,0xca,0x00, +0x00,0x70,0xca,0x00,0x00,0x40,0xca,0x00,0x00,0x10,0xca,0x00,0x00,0xc0,0xc9, +0x00,0x00,0x60,0xc9,0x00,0x00,0x00,0xc9,0x00,0x00,0xa0,0xc8,0x00,0x00,0x40, +0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x40,0x00,0x00,0x80,0x44,0x00,0x00,0x40,0x46,0x00,0x00,0x40,0x47,0x00, +0x00,0x20,0x48,0x00,0x00,0xa0,0x48,0x00,0x00,0x20,0x49,0x00,0x00,0xa0,0x49, +0x00,0x00,0x10,0x4a,0x00,0x00,0x50,0x4a,0x00,0x00,0x90,0x4a,0x00,0x00,0xd0, +0x4a,0x00,0x00,0x10,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0d, +0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x19,0x00,0x00,0x00, +0x1d,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x29,0x00,0x00, +0x00,0x2d,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x12, +0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x12,0x00,0x00,0x00, +0x13,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x14,0x00,0x00, +0x00,0x13,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x92,0x24,0x49,0x3a,0x00, +0x00,0x00,0x3a,0xe4,0x38,0x8e,0x39,0x33,0x33,0x33,0x39,0x2f,0xba,0xe8,0x38, +0xab,0xaa,0xaa,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x65,0x00,0x00, +0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00, +0x00,0x40,0x9a,0x00,0x9e,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x05,0x00, +0x40,0x74,0xcb,0xa7,0x0f,0xa9,0x1b,0x7b,0x8c,0x74,0xa6,0x52,0x52,0x00,0x40, +0xf6,0xde,0xd4,0x00,0xef,0x3d,0xd2,0x80,0xbf,0xbe,0x5f,0x5f,0x00,0x00,0x00, +0x00,0x00,0x00,0x43,0xed,0x29,0xee,0x81,0xef,0x54,0xf0,0xea,0xf0,0x7d,0xf1, +0x0a,0xf2,0x91,0xf2,0x16,0xf3,0x96,0xf3,0x13,0xf4,0x8c,0xf4,0x00,0xf5,0x70, +0xf5,0xdb,0xf5,0x43,0xf6,0xa6,0xf6,0x06,0xf7,0x62,0xf7,0xbd,0xf7,0x13,0xf8, +0x63,0xf8,0xb2,0xf8,0x01,0xf9,0x48,0xf9,0x8f,0xf9,0xcf,0xf9,0xed,0xf9,0xed, +0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9, +0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed, +0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0f, +0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +0x3c,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66, +0x3f,0xcd,0xcc,0xcc,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0xb1, +0xe7,0xb1,0xe7,0xb1,0xc5,0xb2,0x69,0xb5,0x4e,0xb6,0x1d,0xb8,0xe0,0xba,0xd0, +0xbb,0xc1,0xbc,0x4d,0xc0,0xca,0xc0,0x48,0xc2,0xc9,0xc2,0xd7,0xc4,0xd7,0xc4, +0x5e,0xc5,0x0c,0xc8,0x98,0xc8,0xb4,0xc9,0x44,0xca,0xfa,0xcb,0x8e,0xcc,0x51, +0xce,0x58,0xd1,0xf6,0xd1,0xf6,0xd1,0xd9,0xd3,0xc7,0xd5,0x6e,0xd6,0x6c,0xd8, +0x25,0xdb,0xc1,0xd7,0x3e,0xdd,0x63,0xdf,0x95,0xe1,0x95,0xe1,0x97,0xe4,0xd4, +0xe3,0x97,0xe4,0x7a,0xe8,0x46,0xe9,0x84,0xec,0x2d,0xee,0x2d,0xee,0x4e,0xf3, +0xb6,0xf0,0x58,0xed,0x13,0xea,0xd9,0xe0,0xd7,0xdb,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00, +0x00,0x00,0x0a,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd5,0xac,0xaa,0xad,0x0a,0xb1, +0x0a,0xb1,0xc5,0xb2,0xa4,0xb3,0x4e,0xb6,0x69,0xb5,0x34,0xb7,0xf3,0xb9,0xe0, +0xba,0xd0,0xbb,0xb4,0xbd,0x4d,0xc0,0x4d,0xc0,0x48,0xc1,0xc7,0xc1,0x4b,0xc3, +0x52,0xc4,0xd7,0xc4,0xe5,0xc5,0x6d,0xc6,0x98,0xc8,0xb4,0xc9,0xb4,0xc9,0xd5, +0xca,0x67,0xcb,0x8e,0xcc,0xb9,0xcd,0xe9,0xce,0xf6,0xd1,0x83,0xcf,0x58,0xd1, +0x96,0xd2,0x21,0xd5,0x37,0xd3,0xc7,0xd5,0xc7,0xd5,0x17,0xd7,0x21,0xd5,0xc1, +0xd7,0xc6,0xd9,0x75,0xda,0xc6,0xd9,0x8a,0xdc,0x8a,0xdc,0x8a,0xdc,0x75,0xda, +0x6e,0xd6,0x17,0xd7,0x96,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x8e,0x69,0xee,0x3e,0x77,0x35,0x9b,0x3f,0x8e,0x69,0xee,0x3e,0x00,0x00, +0x00,0x00,0x27,0xfe,0x11,0x40,0xbe,0xed,0x05,0x40,0x27,0xfe,0x11,0x40,0x00, +0x00,0x00,0x00,0xe9,0x8e,0x83,0x8f,0xba,0x90,0xf6,0x91,0x21,0x95,0xc1,0x97, +0x6c,0x98,0xd7,0x9b,0x8a,0x9c,0x1d,0xa0,0x54,0xa2,0x97,0xa4,0x21,0xa6,0x21, +0xa6,0xb2,0xab,0x84,0xac,0xdc,0xaf,0x11,0xb5,0xf5,0xb5,0x85,0xba,0x64,0xbc, +0x1c,0xc0,0x99,0xc0,0x1f,0xc4,0x4b,0xc7,0x62,0xc8,0xd6,0xc7,0x7f,0xcd,0x48, +0xcf,0xe2,0xcf,0xf9,0xd2,0x3d,0xd4,0x2e,0xd6,0x83,0xd9,0x44,0xdc,0x4c,0xe1, +0xc9,0xe2,0x9b,0xe6,0x4c,0xe4,0x2c,0xe8,0x62,0xeb,0x06,0xed,0xda,0xed,0x82, +0xf6,0x9d,0xf5,0x07,0xfc,0x07,0xfc,0x9d,0xf5,0x92,0xea,0xad,0xdd,0x2e,0xd6, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf3,0x8a,0xf3,0x8a, +0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3, +0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a, +0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0x0c,0x93,0xab,0x9c,0x0d,0xa4,0xd9, +0xaa,0xed,0xb2,0x86,0xbc,0xf7,0xc3,0xbf,0xca,0xce,0xd2,0x62,0xdc,0xe2,0xe3, +0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xe2,0xe3,0x62,0xdc,0xce, +0xd2,0xbf,0xca,0xce,0xd2,0x62,0xdc,0xe2,0xe3,0xa5,0xea,0xce,0xd2,0x86,0xbc, +0x0d,0xa4,0xf3,0x8a,0x2b,0x73,0xf5,0x5c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00, +0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x8e,0x69, +0xee,0x3e,0x8e,0x69,0xee,0x3e,0x00,0x00,0x00,0x00,0x27,0xfe,0x11,0x40,0x27, +0xfe,0x11,0x40,0x27,0xfe,0x11,0x40,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x66,0x66,0x66,0x3e,0x33,0x33,0x33,0x3b,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x3c,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xc6,0x97,0x3b,0x9c,0x18,0xa2,0x31,0xa6,0x20,0xab, +0x68,0xb0,0x91,0xb3,0x13,0xb7,0xfb,0xba,0x4a,0xbf,0xff,0xc1,0x89,0xc4,0x41, +0xc7,0x26,0xca,0x35,0xcd,0x36,0xd0,0xe4,0xd1,0xa4,0xd3,0x73,0xd5,0x5d,0xd7, +0x51,0xd9,0x3d,0xdb,0x44,0xdd,0x68,0xdf,0xba,0xe0,0xcd,0xe1,0xd1,0xe2,0xe0, +0xe3,0xf0,0xe4,0x00,0xe6,0x08,0xe7,0x0c,0xe8,0x0d,0xe9,0x08,0xea,0xef,0xea, +0xdd,0xeb,0xc9,0xec,0xa3,0xed,0x7a,0xee,0x2e,0xef,0xad,0xef,0x09,0xf0,0x50, +0xf0,0xa0,0xf0,0xeb,0xf0,0x45,0xf1,0x9d,0xf1,0xa5,0xf1,0x01,0xf2,0x0a,0xf2, +0xfd,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd6,0xf8,0x85, +0xf1,0x95,0xe7,0xf1,0xde,0x81,0xd6,0x9f,0xce,0x81,0xc7,0x91,0xc0,0xc1,0xb9, +0x71,0xb3,0xd5,0xad,0x9a,0xa8,0xfe,0xa2,0x69,0x9e,0xad,0x99,0x4b,0x95,0x52, +0x91,0x51,0x8d,0xb3,0x89,0x41,0x86,0xae,0x82,0x35,0x80,0xad,0x7c,0xd5,0x79, +0xaa,0x77,0x85,0x74,0x41,0x72,0x6c,0x70,0xf6,0x6d,0xaf,0x6b,0xe7,0x69,0x7b, +0x68,0xa2,0x66,0xbf,0x64,0x47,0x63,0xfb,0x61,0xe0,0x60,0xfb,0x5f,0x75,0x5e, +0x51,0x5d,0x94,0x5c,0x08,0x5c,0x4f,0x5b,0x91,0x5a,0xeb,0x59,0x37,0x59,0x95, +0x58,0x86,0x58,0xdc,0x57,0xbf,0x57,0xe9,0x57,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xe1,0x3f,0x3a,0x00,0x26,0x46,0x3a,0x00,0x8e,0x4c, +0x3a,0x00,0x1a,0x53,0x3a,0x00,0xcd,0x59,0x3a,0x00,0xa6,0x60,0x3a,0x00,0xa7, +0x67,0x3a,0x00,0xd2,0x6e,0x3a,0x00,0x28,0x76,0x3a,0x00,0xab,0x7d,0x3a,0x00, +0x5c,0x85,0x3a,0x00,0x3d,0x8d,0x3a,0x00,0x50,0x95,0x3a,0x00,0x97,0x9d,0x3a, +0x00,0x12,0xa6,0x3a,0x00,0xc6,0xae,0x3a,0x00,0xb3,0xb7,0x3a,0x00,0xdc,0xc0, +0x3a,0x00,0x44,0xca,0x3a,0x00,0xec,0xd3,0x3a,0x00,0xd8,0xdd,0x3a,0x00,0x0b, +0xe8,0x3a,0x00,0x86,0xf2,0x3a,0x00,0x4e,0xfd,0x3a,0x00,0x66,0x08,0x3b,0x00, +0xd1,0x13,0x3b,0x00,0x93,0x1f,0x3b,0x00,0xaf,0x2b,0x3b,0x00,0x2b,0x38,0x3b, +0x00,0x09,0x45,0x3b,0x00,0x50,0x52,0x3b,0x00,0x04,0x60,0x3b,0x00,0x2a,0x6e, +0x3b,0x00,0xc8,0x7c,0x3b,0x00,0xe4,0x8b,0x3b,0x00,0x84,0x9b,0x3b,0x00,0xb0, +0xab,0x3b,0x00,0x6e,0xbc,0x3b,0x00,0xc6,0xcd,0x3b,0x00,0xc1,0xdf,0x3b,0x00, +0x69,0xf2,0x3b,0x00,0xe3,0x02,0x3c,0x00,0xf1,0x0c,0x3c,0x00,0x65,0x17,0x3c, +0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17, +0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x00, +0x00,0x00,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77, +0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x74,0x72,0x6f,0x6d,0x6a,0x68,0x65, +0x63,0x60,0x5e,0x5b,0x59,0x59,0x59,0x59,0x59,0x5b,0x5e,0x60,0x63,0x60,0x5e, +0x5b,0x59,0x60,0x68,0x6f,0x77,0x7e,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f, +0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xad,0x3c,0x00,0x00,0xc0, +0x47,0x00,0x00,0x80,0x44,0x00,0xa3,0x02,0x43,0x00,0x00,0x00,0xc7,0x00,0x00, +0x00,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x47,0x00, +0x00,0x40,0x48,0x00,0x00,0x00,0x49,0x00,0x00,0x40,0x4a,0x00,0xab,0xaa,0x3a, +0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa, +0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x38,0x00,0x00,0x00,0x00,0x09,0x12, +0x12,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe4, +0x38,0x8e,0x39,0xe4,0x38,0x8e,0x37,0xe4,0x38,0x8e,0x37,0xab,0xaa,0xaa,0x3a, +0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xa0,0xfa,0xfa,0xf4,0xf4,0xf4,0xe8,0xe8, +0xa0,0xfa,0xfa,0xfa,0xf4,0xe8,0xd0,0xa0,0xa0,0xf4,0xf4,0xf4,0xf4,0xf4,0xe8, +0xc4,0xa0,0xf4,0xf4,0xe8,0xdc,0xd0,0xb8,0xb8,0xa0,0xe8,0xe8,0xe8,0xe8,0xd0, +0xb8,0xa0,0xa0,0xe8,0xe8,0xe8,0xdc,0xdc,0xd0,0xb8,0xa0,0xe8,0xdc,0xdc,0xc4, +0xa0,0xa0,0xa0,0xa0,0xdc,0xdc,0xdc,0xdc,0xb8,0xa0,0xa0,0xa0,0xdc,0xdc,0xdc, +0xd0,0xc4,0xb8,0xa0,0xa0,0xd0,0xd0,0xd0,0xb8,0xa0,0xa0,0xa0,0xa0,0xd0,0xd0, +0xd0,0xc4,0xa0,0xa0,0xa0,0xa0,0xd0,0xd0,0xd0,0xc4,0xb8,0xa0,0xa0,0xa0,0xc4, +0xc4,0xc4,0xa0,0xa0,0xa0,0xa0,0xa0,0xc4,0xc4,0xc4,0xb8,0xa0,0xa0,0xa0,0xa0, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf, +0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31, +0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc, +0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a, +0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf, +0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31, +0xaf,0x0a,0x86,0xbb,0x30,0x0b,0x3c,0xb0,0xca,0x0b,0x2a,0xd5,0x40,0x0c,0x21, +0x91,0xad,0x0c,0x3d,0xcc,0x2e,0x0d,0x96,0x63,0xc8,0x0d,0x5c,0x77,0x3f,0x0e, +0x63,0xf1,0xab,0x0e,0x20,0xde,0x2c,0x0f,0x55,0x18,0xc6,0x0f,0x62,0x1a,0x3e, +0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52, +0xaa,0x10,0xa0,0x52,0xaa,0x10,0x62,0x1a,0x3e,0x10,0x55,0x18,0xc6,0x0f,0x20, +0xde,0x2c,0x0f,0x63,0xf1,0xab,0x0e,0x20,0xde,0x2c,0x0f,0x55,0x18,0xc6,0x0f, +0x62,0x1a,0x3e,0x10,0xa0,0x52,0xaa,0x10,0x20,0xde,0x2c,0x0f,0x96,0x63,0xc8, +0x0d,0x2a,0xd5,0x40,0x0c,0xdc,0x31,0xaf,0x0a,0xfc,0xab,0x32,0x09,0xba,0x4d, +0xcf,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0xcd,0x13,0xd4,0x40,0x00, +0x00,0x00,0x40,0xcd,0x13,0xd4,0x3e,0x00,0x00,0x00,0x3e,0xcd,0x13,0xd4,0x3c, +0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0xbd,0xe2,0xd7,0xe1,0x7f,0xe0,0xb1, +0xde,0x59,0xdc,0x0d,0xda,0xda,0xd7,0xbb,0xd5,0xaa,0xd3,0xa6,0xd1,0xb3,0xcf, +0xd1,0xcd,0x01,0xcc,0x41,0xca,0x93,0xc8,0xf5,0xc6,0x66,0xc5,0xe7,0xc3,0x77, +0xc2,0x0d,0xc1,0x68,0xbf,0xeb,0xbc,0x71,0xba,0xfa,0xb7,0xbf,0xb5,0x86,0xb3, +0x86,0xb1,0x87,0xaf,0x9d,0xad,0xc7,0xab,0x0f,0xaa,0x6f,0xa8,0xe0,0xa6,0x69, +0xa5,0x19,0xa4,0xc9,0xa2,0x84,0xa1,0x5f,0xa0,0x8d,0x9e,0xbf,0x9c,0x7e,0x9b, +0x82,0x9a,0x23,0x99,0xa0,0x97,0x37,0x96,0x91,0x94,0xf8,0x92,0xd2,0x92,0x31, +0x91,0x08,0x91,0x43,0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0x3b,0x72,0x55,0x3f,0x76,0x5d,0x24, +0x3f,0x29,0x57,0xe7,0x3e,0xfe,0xdf,0x98,0x3e,0x00,0x00,0x00,0x00,0x6e,0x3a, +0xc3,0xd7,0x35,0x85,0x57,0x35,0xf5,0x04,0x58,0xb5,0x69,0x5a,0x00,0x40,0xe5, +0xdd,0x78,0x84,0x11,0x3c,0x32,0x04,0x04,0xb8,0xbe,0x5b,0x00,0x40,0xfe,0xde, +0x7b,0x81,0x43,0x3e,0x34,0x01,0xf4,0xbc,0x33,0x5e,0x00,0x00,0x00,0x00,0x00, +0x00,0x43,0x46,0x47,0x3a,0x20,0x4e,0x42,0x5f,0x53,0x45,0x43,0x5f,0x44,0x32, +0x5f,0x41,0x54,0x54,0x20,0x4d,0x43,0x46,0x5f,0x43,0x4c,0x3a,0x20,0x39,0x39, +0x34,0x39,0x31,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f, +0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c, +0x8f,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02, +0x03,0x04,0x05,0x06,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0x00,0x00,0x01,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33, +0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9, +0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x00,0x00,0x00, +0x00,0x02,0x02,0x01,0x01,0x01,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xc2,0x39,0x85,0xd5,0x24,0x88,0xf3,0x31,0x7a,0x07,0xde,0xaf,0x40, +0x57,0x00,0x40,0xc0,0xdd,0x1d,0x84,0x45,0x3c,0x59,0x03,0xc1,0xb8,0xa3,0x5b, +0x00,0x00,0x00,0x00,0xcd,0x3c,0x95,0xda,0x59,0x84,0x8b,0x38,0x2a,0x04,0x5a, +0xb7,0x7e,0x5b,0x00,0x40,0xf5,0xde,0xfe,0x81,0x1b,0x3e,0xcc,0x01,0x44,0xbc, +0xf1,0x5d,0x00,0x00,0x00,0x00,0x5e,0x2a,0x77,0xbb,0x0c,0x96,0x8d,0x17,0x98, +0x0f,0xc6,0x93,0x7d,0x42,0x00,0x40,0xa1,0xd3,0x23,0x93,0x77,0x32,0xef,0x07, +0xca,0xa7,0x1f,0x4a,0x00,0x00,0x00,0x00,0x1d,0x34,0x69,0xcc,0x48,0x8e,0xf4, +0x26,0x0a,0x0c,0xc1,0xa3,0x7d,0x4f,0x00,0x40,0xe6,0xda,0xb7,0x88,0xc5,0x38, +0xbe,0x05,0x5b,0xb2,0x64,0x56,0x00,0x00,0x00,0x00,0x2e,0x00,0x22,0x00,0x16, +0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x0c,0x00, +0x0c,0x00,0x0c,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x33,0x33, +0x3b,0x33,0x33,0x33,0x3b,0x33,0x33,0x33,0x3b,0x33,0x33,0x33,0x3b,0x33,0x33, +0x33,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80, +0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xa0,0x00,0xb0,0x00,0xc4,0x00,0xd8,0x00,0xec,0x00,0x00,0x00,0xa0, +0x00,0xb0,0x00,0xc4,0x00,0xd8,0x00,0xec,0x00,0x00,0x00,0xa0,0x00,0xb0,0x00, +0xc4,0x00,0xd8,0x00,0xec,0x00,0x00,0x00,0xa0,0x00,0xb0,0x00,0xc4,0x00,0xd8, +0x00,0xec,0x00,0x00,0x00,0xa0,0x00,0xb0,0x00,0xc4,0x00,0xd8,0x00,0xec,0x00, +0x00,0x00,0x00,0x00,0x00,0x3b,0xc5,0x35,0x36,0xb0,0x8f,0x6f,0x33,0x63,0x11, +0xdd,0x35,0xe4,0xce,0x27,0x34,0x45,0x15,0x2d,0x35,0xf5,0x1a,0x4f,0x34,0x7c, +0xbe,0x14,0x32,0x57,0x5f,0xf7,0x36,0x49,0x9e,0x73,0xb4,0x39,0xa9,0x1e,0x37, +0xc2,0x40,0x38,0xb6,0xc3,0xdf,0x75,0x33,0xe4,0xac,0xc6,0xad,0xb1,0xbe,0xc2, +0xb6,0x8d,0x89,0x9c,0x34,0x91,0xbf,0x88,0xb6,0x77,0xd9,0x87,0x36,0xe6,0x17, +0x02,0xb5,0x0d,0xf4,0xfd,0x36,0xfe,0x55,0xc1,0x33,0x44,0x56,0xfc,0x35,0x81, +0xac,0x5d,0x36,0x56,0x4a,0x1a,0x34,0x96,0x9b,0xd7,0x36,0x65,0x7b,0xe1,0x2e, +0x2f,0x42,0x37,0x37,0x80,0x39,0x21,0xb4,0x57,0x65,0x6c,0x36,0x77,0xe1,0xcc, +0xb0,0xdb,0x57,0xb5,0x36,0xdf,0x00,0xa4,0xb5,0x50,0x1b,0xe8,0x37,0x7b,0x72, +0xec,0xb7,0x17,0x87,0x03,0x37,0x0b,0xf9,0xb5,0xb7,0x39,0x70,0x1b,0x36,0xfd, +0x34,0x0b,0xb8,0x1c,0x3f,0x76,0x35,0x1d,0xbf,0x8c,0xb8,0x2c,0x4a,0xe4,0x33, +0x27,0x1e,0xad,0xb8,0x6a,0x30,0x80,0xaf,0x9e,0x93,0xad,0xb8,0x6c,0x53,0x16, +0xb4,0x21,0xfa,0xb3,0xb8,0xcf,0x94,0xf6,0xb6,0x11,0x7d,0x38,0xb8,0xaf,0xf4, +0xee,0xb7,0x5f,0x84,0x34,0xb8,0x4b,0x4f,0xf3,0xb7,0xf3,0x1a,0x3f,0xb7,0xc3, +0x82,0x52,0xb8,0x2b,0x9f,0x4d,0xb7,0x7b,0x7e,0x0b,0xb7,0x7f,0x79,0xe3,0xb7, +0xe2,0x05,0xee,0xb7,0xa4,0xac,0x53,0xb6,0x89,0x4d,0x03,0xb9,0x6a,0xa9,0xe7, +0xb3,0x34,0xd3,0x1f,0xb9,0xff,0xea,0x60,0x33,0xbc,0xb1,0x31,0xb9,0x89,0xf1, +0x6f,0x35,0xd9,0x7c,0x79,0xb8,0xfb,0x4f,0x13,0x34,0xda,0x2a,0x09,0xb8,0xfa, +0x38,0x16,0x30,0x39,0x2b,0x37,0xb8,0x69,0x3b,0x40,0x33,0x06,0xe0,0x56,0xb8, +0x67,0xb3,0x06,0x34,0x23,0xc3,0x80,0xb8,0xbc,0xb9,0xbe,0x34,0x58,0x9e,0xcf, +0xb8,0x2c,0xd2,0x3d,0x36,0xd3,0x42,0x01,0xb9,0xd3,0x38,0x7c,0x37,0x13,0x2a, +0xc2,0xb8,0x85,0xb4,0xb5,0x37,0x2c,0xbc,0x96,0xb8,0xca,0xd1,0xbd,0x38,0x5b, +0x4d,0x25,0xb8,0x61,0x12,0xbb,0x38,0xeb,0xb9,0x02,0xb6,0xc6,0x7c,0x0f,0x38, +0xda,0x23,0x04,0xb6,0x40,0xbb,0x1e,0x38,0x01,0xde,0x77,0xb6,0xe8,0xe4,0x26, +0x38,0x0a,0x30,0x6d,0xb6,0xfe,0x3e,0x1f,0x38,0xa5,0x16,0x9f,0xb5,0x60,0x16, +0x68,0x37,0xa1,0x24,0x53,0xb5,0x23,0x7f,0x0a,0x37,0x51,0xaa,0xc7,0xb6,0x43, +0x20,0x53,0x38,0xd0,0x38,0xc9,0xb7,0x5c,0x10,0xd1,0x38,0x45,0x7b,0xc8,0xb6, +0x76,0x17,0xd9,0x38,0x83,0x45,0x72,0xb6,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x1a,0x67,0x5e,0x6a,0xce,0x6c,0x3b,0x76,0xe8,0x79,0x1b,0x7e,0x38,0xf8, +0x27,0xf3,0xed,0xea,0x63,0x64,0xdf,0x70,0x64,0x74,0x6e,0x77,0x1c,0x7a,0xa8, +0x78,0x39,0x7a,0xaa,0x7c,0x5f,0x7d,0xf6,0x7d,0x0a,0x7f,0xcb,0xff,0x05,0xff, +0x72,0xfd,0x4f,0xfc,0x48,0xfc,0x1b,0xfb,0x35,0xfc,0xf9,0xfb,0xe0,0xf9,0xca, +0xf8,0xa9,0xf6,0x98,0xf4,0x75,0xf5,0x67,0xf7,0x40,0xf6,0xf7,0xf5,0x90,0xf5, +0x5d,0xf4,0x43,0xf2,0xab,0xf1,0x87,0xed,0x5f,0xe6,0x45,0xe9,0xbd,0xea,0x75, +0xea,0x37,0xe8,0x40,0xe9,0x16,0xef,0xec,0xed,0x59,0xe9,0x44,0xe8,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf7,0x9f,0xcf,0x2c,0x73,0x57,0x72, +0x2c,0x65,0xd3,0xda,0x2b,0x3f,0x74,0x44,0x2e,0xe7,0x13,0xcf,0x2e,0xdd,0x7b, +0xd6,0x2c,0x74,0x58,0xd1,0x2d,0x79,0x20,0x08,0x2e,0x79,0xa8,0x2a,0x2e,0x3a, +0x57,0x75,0x2e,0x2c,0x6a,0x64,0x2e,0x0c,0xbf,0x4b,0x2e,0xc9,0xf1,0x97,0x2e, +0x3e,0xe4,0x80,0x2d,0x5e,0x99,0xba,0x2d,0x5f,0x6b,0x52,0x30,0x24,0x49,0x0f, +0x31,0x44,0xbc,0x46,0x30,0x8d,0x89,0x76,0x30,0xa7,0x79,0x5e,0x31,0x5b,0x4d, +0x96,0x31,0xa9,0xd9,0xb8,0x31,0x6a,0x19,0x60,0x32,0x4d,0x27,0x33,0x32,0x98, +0xe7,0x30,0x32,0xc5,0xcb,0x01,0x32,0xe5,0xd7,0x85,0x30,0x7e,0x0d,0xd2,0x31, +0xc7,0x97,0x9b,0x32,0x9e,0xf9,0x7f,0x32,0x2e,0x5e,0x98,0x32,0x38,0x52,0x6e, +0x31,0x60,0xf5,0x34,0x30,0xa7,0x75,0x76,0x30,0xb6,0xa0,0xd1,0x30,0xf6,0xbf, +0x42,0x31,0xb2,0xda,0x17,0x32,0x0a,0x48,0x92,0x32,0xc7,0x54,0xa9,0x32,0xad, +0x1f,0x89,0x32,0xde,0xaa,0x07,0x33,0x49,0xee,0x1d,0x32,0x8b,0x85,0xa1,0x30, +0xbb,0x41,0x02,0x31,0x74,0x28,0x0d,0x31,0x4d,0x51,0xa9,0x30,0xe5,0x93,0x97, +0x2f,0x90,0x39,0x1f,0x30,0xb1,0x37,0x3f,0x32,0x28,0xae,0x77,0x32,0x29,0xdf, +0x66,0x32,0x00,0x00,0x00,0x00,0x1a,0x59,0x51,0x30,0x2f,0x41,0xe9,0xba,0x22, +0xe2,0xa6,0xb6,0x73,0xe4,0x3e,0xbc,0xd1,0x51,0x0c,0x35,0xe8,0x7b,0xa2,0xbc, +0x0f,0x00,0x04,0x35,0xba,0x44,0x6e,0xbc,0xc5,0x4a,0x9a,0x30,0xce,0xb3,0xb1, +0xbc,0x40,0x18,0xa9,0x35,0x67,0x1e,0xcc,0xbc,0x2c,0x82,0x38,0x34,0x14,0x16, +0xa1,0xbc,0xfc,0xb8,0x15,0xb8,0x2a,0xa1,0x8c,0xbc,0xa1,0xda,0xe4,0xba,0xbe, +0xe2,0xc1,0xbd,0x2a,0xa8,0x65,0xba,0x67,0x70,0xad,0xbe,0x24,0x32,0x06,0xb8, +0x69,0x37,0x13,0xbf,0xb5,0xa0,0x10,0x36,0xd2,0x1d,0x9b,0xbf,0xb1,0x5b,0x1d, +0x3c,0x9c,0x06,0xa3,0xbf,0x02,0x88,0x98,0x3c,0x64,0x36,0x6b,0xbf,0x89,0x2d, +0x29,0x3d,0xd7,0xa2,0x68,0xbf,0xd5,0xea,0x83,0x3d,0xc5,0x92,0x5e,0xbf,0x8a, +0xb6,0x2a,0x3e,0xa9,0x8f,0x8d,0xbf,0x01,0x18,0xab,0x3e,0x25,0x5b,0x50,0xbf, +0x45,0xa0,0xe1,0x3e,0x7b,0xc7,0x02,0xbf,0x96,0xe6,0xcf,0x3e,0x65,0x6e,0x9f, +0xbe,0x07,0xb4,0x97,0x3e,0x77,0x23,0xd0,0xbe,0xa2,0xdf,0x1b,0x3f,0x1b,0xde, +0x50,0xbf,0x5d,0xe9,0x16,0x40,0x34,0x1e,0xcd,0xbe,0x7c,0x51,0x18,0x40,0x2d, +0x91,0x13,0xbd,0xbd,0x31,0x7a,0x3f,0xa8,0x70,0x44,0xbc,0x7a,0x3f,0x33,0x3f, +0x1c,0x91,0xdf,0xbc,0x52,0xaf,0x56,0x3f,0xcd,0xe6,0xea,0xbc,0x40,0x71,0x53, +0x3f,0xb9,0x88,0xb0,0xbc,0x07,0x1a,0x58,0x3f,0x0c,0x04,0x6e,0xbc,0xac,0xb2, +0x22,0x3f,0x17,0x35,0xa0,0xbb,0xfd,0x35,0xcd,0x3e,0x6a,0xfb,0xd9,0xbb,0xd0, +0x22,0xa4,0x3e,0xee,0x71,0x55,0xbc,0x60,0x8f,0xa4,0x3e,0x4c,0x36,0xba,0xbc, +0xa2,0x05,0xb4,0x3e,0x1a,0xdb,0xfa,0xbc,0x53,0xce,0xca,0x3e,0xa7,0x52,0x33, +0xbd,0x44,0x27,0xe5,0x3e,0x37,0xd8,0x45,0xbd,0xc2,0x66,0xf7,0x3e,0x8b,0xeb, +0x40,0xbd,0xdb,0xd6,0xf1,0x3e,0xbb,0xdf,0x2b,0xbd,0x67,0x10,0xe0,0x3e,0xcd, +0xff,0x4a,0xbd,0xcd,0xc0,0xde,0x3e,0xd3,0xed,0x94,0xbd,0xa2,0x41,0xeb,0x3e, +0xf8,0xcd,0xd0,0xbd,0xdb,0x73,0xf0,0x3e,0x0f,0x13,0xef,0xbd,0xa5,0x29,0xeb, +0x3e,0x6c,0x15,0x16,0xbe,0x37,0x15,0xf6,0x3e,0x61,0x5d,0x55,0xbe,0x26,0xf2, +0x1f,0x3f,0x6e,0xee,0x74,0xbe,0x3b,0x3e,0x11,0x3f,0x07,0x61,0x78,0xbe,0x3d, +0x6e,0xe2,0x3e,0xca,0x30,0xc2,0xbe,0xb8,0x57,0x1c,0x3f,0x7c,0xcf,0x78,0xbf, +0x0e,0x7c,0x6c,0x3f,0x34,0x90,0x9a,0xbf,0xa6,0xc1,0x7c,0x3f,0xd5,0x7d,0xc0, +0xbf,0x70,0xf6,0x4b,0x3f,0x3f,0x01,0x03,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xbf,0xf7,0xbf,0xf8,0x44,0xf7,0x36,0xf7,0xd9,0xf7,0x2b,0xf7,0x76, +0xf7,0x07,0xf9,0xdf,0xf9,0x1f,0xf9,0x6b,0xf8,0xa3,0xf7,0x1e,0xf5,0x4e,0xf4, +0x94,0xf3,0x1a,0xf3,0x6c,0xf2,0x18,0xf1,0x39,0xf0,0x4a,0xef,0x6a,0xf0,0x54, +0xf0,0x08,0xec,0x56,0xe6,0xd7,0xe4,0x99,0xe8,0x64,0xe8,0xa8,0xe7,0x33,0xe6, +0x77,0xe3,0x7d,0xe5,0x7a,0xe8,0xb4,0xe9,0x43,0xea,0x9a,0xea,0x7b,0xea,0x38, +0xea,0x10,0xea,0x98,0xea,0x5d,0xeb,0xcb,0xeb,0x04,0xec,0xa5,0xec,0x98,0xed, +0x93,0xed,0xd0,0xed,0x8c,0xef,0x8f,0xf0,0x43,0xf0,0x5f,0xf0,0x02,0xf1,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0xb9,0x1e,0x36,0x45,0x93, +0x93,0x38,0x98,0x2d,0x7d,0x39,0x0e,0xd5,0xf8,0x38,0xde,0x4a,0xa1,0x39,0x2a, +0x50,0xf0,0x39,0xcd,0x51,0x77,0x39,0x88,0xa8,0x62,0x39,0x0a,0xc5,0x06,0x3c, +0x53,0x99,0xc3,0x3d,0x5d,0x48,0x61,0x3e,0xe9,0x3c,0x41,0x3f,0x0f,0x0b,0x96, +0x3f,0x54,0xdb,0x57,0x3f,0x7d,0x80,0x87,0x3f,0xe2,0x4f,0x9c,0x3f,0x03,0x34, +0x2a,0x40,0xa2,0x42,0x43,0x40,0x1a,0xc2,0x2b,0x40,0x3e,0x5d,0xb2,0x3f,0x60, +0x9f,0xa8,0x3f,0xde,0x20,0x95,0x40,0x7a,0xf3,0x29,0x41,0xd9,0x81,0x7d,0x40, +0x63,0x20,0x58,0x3f,0xf7,0x87,0x13,0x3f,0xea,0x8f,0x51,0x3f,0x7b,0xb4,0x37, +0x3f,0xff,0x30,0x2a,0x3f,0x02,0xcf,0xa9,0x3e,0xe0,0xab,0x31,0x3e,0xc2,0x96, +0x15,0x3e,0x23,0x06,0x36,0x3e,0x6f,0xbf,0x61,0x3e,0x82,0xdc,0x96,0x3e,0x0e, +0xd1,0xc3,0x3e,0x5d,0x8c,0xdc,0x3e,0x9f,0xe0,0xcb,0x3e,0x10,0x97,0xbe,0x3e, +0xf8,0x78,0xdc,0x3e,0x39,0x40,0x0a,0x3f,0xa5,0x85,0x20,0x3f,0x5b,0xba,0x37, +0x3f,0x94,0xb3,0x8d,0x3f,0x06,0x33,0xf3,0x3f,0x7b,0xaf,0xe0,0x3f,0x3a,0x84, +0xfb,0x3f,0x36,0x62,0xb7,0x40,0x89,0xb2,0x16,0x41,0xc1,0xa0,0x47,0x41,0x20, +0xd1,0x61,0x41,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, +0xc8,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0xc5,0x00,0x00, +0x00,0xc5,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0x00,0xa0, +0xaa,0x00,0xa7,0xab,0xa3,0x55,0xa0,0x00,0x9a,0x55,0x8d,0x55,0x0d,0x00,0x1a, +0x55,0x20,0xab,0x23,0x00,0x27,0xa0,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x99,0xa3,0xf5,0xa3,0xfc,0xa2,0x55,0xa1,0xfd,0x9c,0xe9,0x9c,0xad,0xa2, +0x1b,0xa3,0x5d,0xa2,0x9f,0xa0,0x90,0x9c,0x0a,0x9c,0x2f,0xa2,0xa7,0xa2,0x08, +0xa2,0x3e,0xa0,0x56,0x9c,0x93,0x9b,0xb1,0xa1,0x33,0xa2,0xb3,0xa1,0xbb,0x9f, +0x1c,0x9c,0x1c,0x9b,0xa6,0xa0,0x58,0xa1,0xf9,0xa0,0x4e,0x9e,0xf1,0x9a,0x08, +0x9a,0xdd,0x9e,0x48,0xa0,0x0c,0xa0,0x9e,0x9c,0x7d,0x99,0xcc,0x98,0xec,0x9b, +0xcd,0x9d,0xb0,0x9d,0xad,0x9a,0xf8,0x97,0x13,0x97,0x4f,0x98,0x3f,0x9a,0x88, +0x9a,0x43,0x98,0x7f,0x94,0x24,0x94,0xac,0x91,0x20,0x95,0x2d,0x96,0x48,0x93, +0xe0,0x90,0x0f,0x91,0x85,0x89,0xd2,0x8e,0x68,0x90,0x87,0x8d,0x81,0x8b,0x84, +0x8c,0x03,0x86,0x71,0x8a,0x1c,0x8c,0xbf,0x89,0xcb,0x88,0xe3,0x89,0xc2,0x00, +0x61,0x80,0x86,0x80,0x02,0x00,0x1b,0x80,0x2b,0x80,0x00,0x00,0xd5,0x00,0xab, +0x01,0x80,0x02,0x55,0x03,0x2b,0x04,0x00,0x05,0xd5,0x05,0xab,0x06,0x80,0x07, +0x55,0x08,0x2b,0x09,0x00,0x0a,0xd5,0x0a,0xab,0x0b,0x80,0x0c,0x55,0x0d,0x2b, +0x0e,0x00,0x0f,0xd5,0x0f,0x55,0x10,0xc0,0x10,0x2b,0x11,0x95,0x11,0x00,0x12, +0x6b,0x12,0xd5,0x12,0x40,0x13,0xab,0x13,0x15,0x14,0x80,0x14,0xeb,0x14,0x55, +0x15,0xc0,0x15,0x2b,0x16,0x95,0x16,0x00,0x17,0x6b,0x17,0xd5,0x17,0x20,0x18, +0x55,0x18,0x8b,0x18,0xc0,0x18,0xf5,0x18,0x2b,0x19,0x60,0x19,0x95,0x19,0xcb, +0x19,0x00,0x1a,0x00,0x1a,0x00,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x48,0x01,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66, +0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x40,0xab,0x00,0xa7,0xab,0xa3,0x55,0xa0,0x00,0x9a,0x55, +0x8d,0x55,0x0d,0x00,0x1a,0x55,0x20,0xab,0x23,0x00,0x27,0xa0,0x32,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xf5,0xa0,0xe7,0x9b,0x88,0x9a,0xf7,0x9d,0xf8, +0x96,0xdd,0x99,0x01,0xa0,0x7f,0x9c,0xc7,0x9b,0x85,0x9c,0x74,0x98,0x21,0x99, +0x29,0x9f,0xc2,0x9c,0x55,0x9c,0xe0,0x9b,0xe2,0x98,0xcd,0x98,0x86,0x9e,0xfa, +0x9c,0xc6,0x9c,0x89,0x9b,0x01,0x99,0x93,0x98,0xdd,0x9d,0xf8,0x9c,0x05,0x9d, +0x6d,0x9b,0xaf,0x98,0x53,0x98,0x8e,0x9c,0x47,0x9c,0xc0,0x9c,0x03,0x9b,0x0f, +0x98,0x5b,0x97,0x10,0x9a,0x74,0x9a,0x80,0x9b,0xe5,0x99,0xbe,0x95,0xae,0x94, +0x97,0x95,0x92,0x97,0x53,0x99,0x07,0x98,0x6a,0x92,0x15,0x91,0x64,0x8e,0xc5, +0x91,0x44,0x95,0x7a,0x93,0xb6,0x8d,0x10,0x8b,0xf2,0x84,0x07,0x8a,0x5a,0x90, +0xc2,0x8e,0x2f,0x88,0x2d,0x86,0x3c,0x81,0x10,0x86,0x5a,0x8c,0x33,0x8b,0x07, +0x86,0x73,0x84,0xaf,0x0b,0xe7,0x09,0xf0,0x07,0x8c,0x07,0x0c,0x08,0x3b,0x08, +0x11,0x01,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66, +0x02,0x66,0x02,0x66,0x02,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc, +0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0, +0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x00,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x00,0x34,0x00,0x00,0x00,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e, +0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec, +0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e, +0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0x7e,0xec,0xe3,0xe6,0xb1,0xe8,0x5b,0xf0, +0x38,0xe9,0x95,0xe3,0x4b,0xe4,0xba,0xe2,0x94,0xeb,0x61,0xf2,0x97,0xf2,0x55, +0xf4,0x57,0xf1,0x76,0xec,0x81,0xe7,0x2a,0xe6,0x7f,0xe7,0x63,0xe2,0x3e,0xeb, +0xb2,0xf6,0xa4,0xf4,0x9d,0xf3,0x49,0xf6,0x07,0xff,0xaa,0xf7,0x05,0xe7,0x0e, +0xe4,0x87,0xda,0x00,0x00,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83, +0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c, +0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83, +0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0xb5,0x82,0x9d,0x84,0x37,0x83,0xd3, +0x83,0x11,0x84,0xb8,0x87,0xf3,0x8c,0x81,0x8e,0xd7,0x8c,0xcb,0x8a,0xa7,0x88, +0x1a,0x87,0x53,0x86,0xd5,0x86,0x42,0x87,0x50,0x86,0x04,0x85,0x6c,0x84,0xd2, +0x83,0xee,0x81,0x2b,0x80,0x73,0x80,0xb5,0x7f,0x31,0x77,0x71,0x74,0xc6,0x72, +0xa8,0x70,0x00,0x00,0x00,0x00,0x34,0x00,0x34,0x00,0x00,0x00,0x68,0x00,0x00, +0x00,0x34,0x00,0x00,0x00,0xf6,0x8a,0x1b,0x8a,0x3e,0x8b,0x73,0x8a,0x13,0x88, +0xce,0x87,0x0a,0x84,0x15,0x79,0xd9,0x7b,0x69,0x87,0x88,0x80,0xd2,0x79,0x87, +0x74,0x33,0x7a,0x11,0x73,0x47,0x7d,0x2c,0x82,0x40,0x7f,0xad,0x7c,0xd7,0x7f, +0x45,0x7b,0xdd,0x78,0x54,0x7b,0x69,0x7d,0x81,0x7e,0x3a,0x81,0x64,0x7e,0x78, +0x75,0xb9,0x81,0xd6,0x80,0xed,0x79,0x8a,0x80,0x25,0x7b,0xb7,0x7b,0x91,0x6f, +0x9f,0x71,0x16,0x6a,0xf5,0x69,0x7a,0x69,0x7d,0x67,0xe9,0x63,0xd1,0x66,0xdb, +0x89,0x8d,0x84,0xdc,0x56,0x22,0x58,0x9f,0x6f,0x72,0x6f,0xb1,0x70,0x83,0x72, +0xe0,0x83,0x00,0x00,0x63,0xd6,0x42,0xd4,0x05,0xd4,0x24,0xd6,0xa3,0xd5,0x01, +0xd6,0x5f,0xdf,0x48,0xe1,0x94,0xe4,0x68,0xef,0x4c,0xef,0x17,0xf1,0x22,0xea, +0x5b,0xeb,0x80,0xe2,0x10,0xcf,0xa6,0xc0,0xd9,0xc1,0x57,0xc6,0x1a,0xc2,0x8a, +0xc0,0x3c,0xbf,0xdf,0xbc,0x7e,0xbd,0xdb,0xba,0x90,0xb9,0x05,0xbb,0xb1,0xbb, +0x44,0xbc,0x9d,0xbf,0x19,0xbc,0xed,0xb4,0x11,0xb2,0x04,0xac,0x9d,0xa8,0xcf, +0xa5,0xf5,0xa0,0x44,0xa0,0x9e,0x9a,0x68,0xa0,0xe6,0xa2,0xfd,0xa2,0xe0,0xae, +0xc6,0xa7,0x51,0xb2,0x12,0xb4,0x15,0xb8,0x19,0xb0,0xcb,0xb9,0x56,0xb3,0xfe, +0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x00, +0x00,0x33,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x33,0x00, +0x00,0x00,0x33,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xb5,0x00,0x00,0x00,0x0f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xb8,0x00,0x00,0x00,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xa4,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0xc0,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xae,0x8a,0xea,0x8a,0x3f,0x8b,0xcd,0x8c, +0x58,0x87,0x8a,0x87,0xc2,0x89,0x2a,0x88,0xf1,0x87,0xf6,0x87,0x98,0x87,0x78, +0x87,0x5e,0x87,0xef,0x87,0x69,0x88,0xcd,0x88,0x71,0x89,0x95,0x8b,0xa7,0x8d, +0xa2,0x8d,0x53,0x91,0x61,0x92,0xd2,0x8e,0x0a,0x90,0xaf,0x90,0xdb,0x91,0xa0, +0x92,0xa6,0x92,0x3d,0x94,0x13,0x96,0x77,0x96,0xbc,0x95,0x5c,0x95,0xbe,0x96, +0x73,0x97,0x75,0x99,0x6e,0x9b,0xd3,0x9c,0xd1,0x9b,0xfd,0x9b,0x8e,0x9f,0x37, +0xa0,0xfe,0xa1,0xa2,0xa7,0x3d,0xae,0xe3,0xb3,0x5c,0xae,0x17,0xaf,0x5e,0xb6, +0x80,0xbb,0x27,0xb7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf, +0x90,0xd8,0x91,0x77,0x93,0x02,0x94,0x0d,0x95,0xd2,0x93,0x70,0x92,0x9b,0x92, +0xd8,0x92,0x12,0x93,0xe6,0x93,0x73,0x95,0x37,0x93,0x52,0x94,0x83,0x94,0x5e, +0x94,0xe1,0x95,0x72,0x96,0x99,0x95,0x68,0x95,0x7d,0x95,0x0e,0x98,0xb4,0x97, +0x3e,0x98,0x1d,0x9b,0x6c,0x9b,0x5f,0x9b,0xe6,0x9b,0x0f,0x9d,0xf1,0x9f,0x57, +0x9f,0x96,0x9e,0x9c,0xa1,0x41,0xa2,0x03,0xa6,0x92,0xaa,0x42,0xa6,0x11,0xa9, +0xb5,0xab,0x57,0xa8,0x3d,0xab,0xa7,0xae,0x55,0xad,0x94,0xae,0x2a,0xb0,0xc4, +0xb0,0x9b,0xb3,0xe0,0xb3,0xbc,0xb8,0xe9,0xba,0x73,0xb9,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xca,0x62, +0x03,0x63,0x5e,0x63,0xcc,0x64,0x41,0x64,0x07,0x64,0xa5,0x64,0xbc,0x64,0x5c, +0x65,0x70,0x65,0x49,0x65,0x0f,0x64,0x30,0x64,0x19,0x65,0x23,0x66,0xbc,0x65, +0x95,0x66,0xa4,0x68,0x81,0x69,0xe4,0x6a,0x38,0x6d,0x07,0x6f,0x9d,0x6a,0xf2, +0x6a,0x53,0x6d,0xb5,0x6e,0xe0,0x6f,0x45,0x70,0x18,0x70,0x4d,0x70,0x17,0x71, +0x56,0x72,0x9b,0x72,0xab,0x72,0x76,0x73,0x0d,0x75,0x81,0x77,0x56,0x7f,0x50, +0x7c,0xb2,0x7b,0x4a,0x7c,0x32,0x7c,0x29,0x7e,0xd3,0x80,0x52,0x84,0x85,0x8a, +0xb8,0x86,0x18,0x8e,0x2b,0x97,0x62,0x9d,0x73,0x99,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xc8,0x8f,0xda,0x92,0xc1,0x98,0xca,0xa2,0x9f,0xa4, +0xa2,0xa0,0x37,0x95,0xb6,0x94,0xf3,0x93,0x18,0x91,0xf0,0x91,0xd7,0x92,0x67, +0x92,0x10,0x92,0xb2,0x93,0xab,0x96,0x22,0x95,0xd0,0x93,0x7c,0x96,0xf6,0x96, +0xd8,0x98,0x43,0x99,0xa2,0xa0,0x87,0xa0,0x51,0x98,0xe5,0x98,0xd5,0xa0,0x6d, +0xa1,0xbd,0x9f,0xb5,0xa0,0x1c,0xa2,0xab,0xa9,0x71,0xa5,0x02,0xa3,0xc6,0xa6, +0x8a,0xa6,0x89,0xa9,0x32,0xb4,0x06,0xb1,0xf9,0xaa,0x84,0xaf,0x43,0xb1,0xc5, +0xb4,0x22,0xb7,0xb0,0xb6,0x41,0xc2,0xc7,0xc3,0x4c,0xc5,0x3f,0xc4,0x61,0xcd, +0xcb,0xd5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x3f,0xc8,0x00, +0xc8,0x00,0xc8,0x00,0xc8,0x00,0x58,0x00,0x58,0x00,0xc8,0x00,0xc8,0x00,0x58, +0x00,0x58,0x00,0x00,0x10,0x00,0x10,0xf4,0x10,0x00,0x10,0x00,0x20,0x00,0x40, +0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x80,0x00,0x40,0xf0,0x4e,0x05, +0x20,0xe8,0x7f,0x05,0x20,0x4f,0x01,0x00,0x00,0x14,0x30,0x05,0x20,0x10,0x01, +0x05,0x20,0x00,0x00,0x80,0x48,0x00,0x00,0x00,0xc0,0xf0,0xd8,0xff,0xff,0xff, +0xf0,0x00,0x00,0x0f,0xff,0x00,0x00,0xff,0x0f,0x00,0x00,0xf0,0xff,0x00,0x00, +0xfb,0xff,0x00,0x00,0xfe,0xff,0x00,0x00,0xf7,0xff,0x00,0x00,0x7f,0xff,0x00, +0x00,0xfd,0xff,0x00,0x00,0xff,0xfe,0x00,0x00,0xff,0xfd,0x00,0x00,0xff,0xfb, +0x00,0x00,0x00,0x00,0x80,0x46,0x00,0xe1,0xf5,0x05,0x94,0x4f,0x05,0x20,0x00, +0x4f,0x05,0x20,0xcc,0x40,0x05,0x20,0x6c,0x43,0x19,0x20,0x8c,0x3f,0x19,0x20, +0xa4,0x3e,0x19,0x20,0x00,0x00,0x00,0x40,0xd8,0x8d,0x19,0x20,0x90,0x03,0x08, +0x20,0x18,0x54,0x19,0x20,0x90,0xa1,0x19,0x20,0x58,0x76,0x19,0x20,0xd0,0x2f, +0x05,0x20,0x88,0x63,0x19,0x20,0xb0,0x62,0x19,0x20,0x40,0x9e,0x19,0x20,0x28, +0x39,0x19,0x20,0x60,0x34,0x19,0x20,0x90,0x33,0x19,0x20,0xf4,0x03,0x08,0x20, +0x48,0x0d,0x08,0x20,0x68,0x46,0x19,0x20,0x00,0x00,0xe0,0xca,0x00,0x00,0x40, +0xc9,0x30,0x47,0x19,0x20,0x9c,0xf3,0x18,0x20,0xdc,0xf5,0x18,0x20,0x74,0xf5, +0x18,0x20,0x18,0xe8,0x18,0x20,0xbc,0xf2,0x18,0x20,0x04,0xee,0x18,0x20,0xd0, +0x25,0x19,0x20,0xa8,0x0d,0x19,0x20,0xa8,0xd2,0x18,0x20,0x50,0xe6,0x18,0x20, +0x6c,0xce,0x18,0x20,0x14,0xcd,0x18,0x20,0x50,0xc0,0x18,0x20,0x48,0xd1,0x18, +0x20,0xbc,0x0e,0x08,0x20,0x80,0x53,0x19,0x20,0xec,0x10,0x08,0x20,0xc0,0xcf, +0x18,0x20,0x48,0x6a,0x19,0x20,0xf0,0x7d,0x19,0x20,0x48,0x82,0x19,0x20,0x90, +0x0b,0x19,0x20,0xc0,0x69,0x19,0x20,0x4c,0xbf,0x18,0x20,0x34,0xbc,0x18,0x20, +0x04,0xb7,0x18,0x20,0xbc,0xb5,0x18,0x20,0x14,0xbf,0x18,0x20,0xb0,0xbd,0x18, +0x20,0xc0,0xb1,0x18,0x20,0x74,0xb1,0x18,0x20,0xd4,0xae,0x18,0x20,0x18,0xad, +0x18,0x20,0xb8,0x07,0x19,0x20,0x9c,0x07,0x19,0x20,0x88,0x04,0x19,0x20,0x24, +0x04,0x19,0x20,0x14,0xfd,0x18,0x20,0xd4,0xfe,0x18,0x20,0x28,0xfa,0x18,0x20, +0xd4,0xe5,0x18,0x20,0x7c,0x0e,0x08,0x20,0x88,0xe4,0x18,0x20,0x58,0xe4,0x18, +0x20,0x78,0xe1,0x18,0x20,0x88,0x64,0x19,0x20,0x78,0x66,0x19,0x20,0x08,0x8f, +0x19,0x20,0x44,0x90,0x19,0x20,0x84,0x10,0x08,0x20,0xd4,0x45,0x19,0x20,0xc8, +0x3d,0x19,0x20,0xe0,0xf7,0x18,0x20,0x58,0xf6,0x18,0x20,0x78,0x0b,0x19,0x20, +0x08,0x09,0x19,0x20,0x58,0x7a,0x19,0x20,0x50,0x79,0x19,0x20,0x64,0x10,0x05, +0x20,0x20,0x12,0x05,0x20,0xba,0x49,0x0c,0x2c,0x9c,0x85,0x17,0x20,0x40,0x1f, +0x00,0x00,0x98,0x85,0x17,0x20,0x05,0xa3,0x02,0x43,0xb4,0x54,0xa8,0x3a,0xba, +0x49,0x0c,0x26,0x33,0x33,0x33,0x39,0xb4,0x54,0xa8,0x3c,0x50,0x9b,0x18,0x20, +0x30,0x9a,0x18,0x20,0x34,0x95,0x18,0x20,0xc8,0x94,0x18,0x20,0xe0,0x91,0x18, +0x20,0x58,0x12,0x05,0x20,0x70,0x07,0x05,0x20,0xc8,0x40,0x05,0x20,0x44,0x12, +0x05,0x20,0x50,0xe3,0x17,0x20,0x80,0x3e,0x00,0x00,0xb0,0xe3,0x17,0x20,0x00, +0x01,0x05,0x20,0x00,0x80,0xff,0xff,0x72,0x11,0x05,0x20,0xff,0xff,0x00,0x00, +0x14,0x08,0x05,0x20,0x9a,0x19,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x0d,0x00, +0x00,0x00,0x0a,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x0c, +0x00,0x00,0x50,0x35,0x05,0x20,0x00,0x0f,0x00,0x00,0x00,0x10,0x00,0x00,0x38, +0x40,0x05,0x20,0xff,0x7f,0x00,0x00,0x34,0x0f,0x05,0x20,0x60,0x36,0x05,0x20, +0x58,0x3f,0x05,0x20,0x14,0x10,0x05,0x20,0x0c,0x48,0x05,0x20,0x70,0x3f,0x05, +0x20,0x00,0x12,0x00,0x00,0x04,0x10,0x05,0x20,0x34,0x0b,0x05,0x20,0x8a,0x36, +0x05,0x20,0x38,0x0f,0x05,0x20,0x00,0x00,0x05,0x20,0xe4,0xe4,0x00,0x00,0x00, +0xfe,0xff,0x0f,0x60,0x35,0x05,0x20,0xcd,0xab,0x00,0x00,0xde,0xbc,0x00,0x00, +0x00,0xfe,0xff,0x3f,0xf0,0x4e,0x05,0x20,0x64,0x35,0x05,0x20,0x52,0x80,0x00, +0x00,0x34,0x0b,0x03,0x20,0x24,0x80,0x00,0x00,0x2c,0x80,0x00,0x00,0x32,0x80, +0x00,0x00,0x33,0x80,0x00,0x00,0x34,0x80,0x00,0x00,0x35,0x80,0x00,0x00,0x36, +0x80,0x00,0x00,0x37,0x80,0x00,0x00,0x38,0x80,0x00,0x00,0x3d,0x80,0x00,0x00, +0x3e,0x80,0x00,0x00,0x3f,0x80,0x00,0x00,0x70,0x35,0x05,0x20,0x00,0x00,0x01, +0x00,0x18,0x37,0x05,0x20,0xf0,0x36,0x05,0x20,0xac,0x35,0x05,0x20,0x8c,0x41, +0x05,0x20,0x7c,0x35,0x05,0x20,0xdc,0x4c,0x08,0x20,0x08,0x01,0x05,0x20,0x68, +0x4b,0x08,0x20,0x00,0x00,0x11,0x00,0xf4,0x11,0x05,0x20,0xbc,0x13,0x05,0x20, +0x8c,0xaf,0x00,0x00,0x00,0x55,0xa8,0x3c,0xd8,0x40,0x05,0x20,0xcc,0x42,0x05, +0x20,0x74,0x4f,0x05,0x20,0xe4,0x40,0x05,0x20,0x48,0x12,0x05,0x20,0x16,0x07, +0x05,0x20,0x54,0x12,0x05,0x20,0x24,0x40,0x05,0x20,0x00,0x09,0x00,0x00,0x34, +0x29,0x08,0x20,0x44,0x7e,0x08,0x20,0x06,0x00,0x44,0x00,0x07,0x00,0x19,0x00, +0xb0,0x4c,0x05,0x20,0xa0,0x6b,0x05,0x20,0x3c,0xf4,0xfd,0x3f,0xa4,0xa4,0x08, +0x20,0x20,0x52,0x05,0x20,0x40,0x52,0x05,0x20,0x44,0x88,0x08,0x20,0x14,0x7a, +0x08,0x20,0xfc,0x4b,0x08,0x20,0x24,0xa1,0x08,0x20,0xf0,0x4e,0x05,0x20,0xe8, +0x7f,0x05,0x20,0x14,0x30,0x05,0x20,0xe8,0x4e,0x05,0x20,0x4c,0x80,0x08,0x20, +0x71,0xd1,0x08,0x20,0x68,0x7e,0x08,0x20,0x48,0x9b,0x08,0x20,0x00,0x00,0x18, +0x20,0x00,0x00,0x02,0x00,0xa0,0x4c,0x05,0x20,0x50,0x79,0x05,0x20,0x00,0x70, +0x05,0x20,0xa0,0x70,0x05,0x20,0xc0,0x73,0x05,0x20,0x40,0x71,0x05,0x20,0x40, +0x76,0x05,0x20,0xe0,0x71,0x05,0x20,0x60,0x74,0x05,0x20,0xe0,0x4c,0x05,0x20, +0x04,0x4f,0x05,0x20,0x78,0x41,0x05,0x20,0x80,0x37,0x05,0x20,0x40,0x4a,0x05, +0x20,0x80,0x77,0x05,0x20,0x00,0x78,0x05,0x20,0xc0,0x4f,0x05,0x20,0x00,0x79, +0x05,0x20,0x30,0x4a,0x05,0x20,0x00,0x4d,0x05,0x20,0x10,0x4d,0x05,0x20,0x30, +0x79,0x05,0x20,0x80,0x78,0x05,0x20,0x70,0x79,0x05,0x20,0x00,0x6b,0x05,0x20, +0x20,0x4d,0x05,0x20,0xd0,0x79,0x05,0x20,0x90,0x7a,0x05,0x20,0xff,0xf7,0xff, +0xff,0xe0,0x2f,0x05,0x20,0x12,0x83,0x00,0x40,0xb4,0x51,0x05,0x20,0x03,0x20, +0x00,0x00,0xc0,0xbd,0x08,0x20,0x78,0xae,0x08,0x20,0x58,0xae,0x08,0x20,0x18, +0xaf,0x08,0x20,0x98,0xae,0x08,0x20,0x2c,0xb7,0x08,0x20,0x34,0xb4,0x08,0x20, +0xf4,0x91,0x08,0x20,0x08,0x4f,0x05,0x20,0xa0,0x94,0x08,0x20,0xc8,0x92,0x08, +0x20,0x9c,0xbd,0x08,0x20,0x00,0x52,0x05,0x20,0x18,0x4f,0x05,0x20,0xac,0xac, +0x08,0x20,0x94,0xac,0x08,0x20,0x14,0x6a,0x05,0x20,0x64,0x4f,0x05,0x20,0xf0, +0x7d,0x05,0x20,0xe5,0x4f,0x05,0x20,0x00,0x08,0x00,0x00,0x6c,0x77,0x05,0x20, +0xab,0xaa,0x02,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x20, +0x00,0x00,0x00,0x10,0x00,0x55,0x55,0x05,0x00,0x00,0x00,0x30,0x00,0x6e,0xdb, +0xfe,0xff,0x6e,0xdb,0xde,0x00,0x90,0x4d,0x05,0x20,0x00,0x1f,0x00,0x40,0xf4, +0x7d,0x05,0x20,0x12,0x34,0x00,0x00,0x30,0x7e,0x05,0x20,0x00,0x0e,0x00,0x10, +0xec,0x36,0x05,0x20,0xb0,0x4d,0x05,0x20,0xd4,0xa2,0x08,0x20,0x50,0x7e,0x05, +0x20,0x00,0x3e,0x00,0x40,0x00,0x1e,0x00,0x40,0x00,0x20,0x00,0x40,0x00,0x4e, +0x05,0x20,0x04,0x20,0x00,0x40,0xb0,0x7f,0x05,0x20,0xa2,0x41,0x05,0x20,0x20, +0x7f,0x05,0x20,0x60,0x7e,0x05,0x20,0x80,0x7f,0x05,0x20,0x8e,0x41,0x05,0x20, +0xd0,0x4d,0x05,0x20,0xb0,0x4e,0x05,0x20,0x00,0x00,0x00,0x80,0xff,0xff,0xff, +0x00,0xb0,0x1e,0x00,0x40,0x90,0x4e,0x05,0x20,0xc0,0x4d,0x05,0x20,0x30,0x4e, +0x05,0x20,0x00,0xff,0x00,0x00,0x00,0x18,0x00,0x00,0xa8,0x37,0x05,0x20,0xdc, +0x37,0x05,0x20,0x10,0x38,0x05,0x20,0x44,0x38,0x05,0x20,0xe0,0x7f,0x05,0x20, +0xc8,0xc0,0x08,0x20,0xd4,0xc1,0x08,0x20,0xc0,0xc4,0x08,0x20,0x00,0xc6,0x08, +0x20,0x58,0xc3,0x08,0x20,0x50,0xc6,0x08,0x20,0xe4,0x7f,0x05,0x20,0x63,0x72, +0x73,0x61,0x00,0x00,0x10,0x01,0xf0,0xf0,0x00,0x00,0x00,0x00,0x50,0x01,0x44, +0x4f,0x05,0x20,0x02,0x00,0x00,0x00,0x50,0x35,0x05,0x20,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x62,0x06,0x00,0x00,0x60,0x35,0x05,0x20,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, +0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0xff,0xff,0xfe,0x87,0x00,0x00,0x01,0x68,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0x00, +0x00,0xfc,0xff,0xd0,0x6f,0x30,0x06,0x00,0x00,0x30,0x06,0x00,0x00,0xb5,0xd3, +0x75,0xb5,0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00, +0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00, +0x00,0x8f,0x6f,0x03,0x00,0x96,0x8f,0x0c,0x00,0xbf,0xe6,0x00,0x00,0x44,0x4d, +0x07,0x00,0x05,0xd3,0x02,0x00,0xe8,0x3a,0x08,0x00,0x43,0x84,0x0c,0x00,0x66, +0x5d,0x0f,0x00,0x57,0xc6,0x00,0x00,0xfa,0x83,0x05,0x00,0x48,0x99,0x0a,0x00, +0x84,0x0d,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd5,0x75,0xb5,0xd3,0x0c,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x75,0x75,0x75,0xb5,0x0c,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x75,0x75,0xd3,0xdf,0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x75,0x75, +0x75,0xd3,0x01,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00, +0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0xd3,0x75,0x75,0xb5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xaf,0x01,0x00,0x00,0xfa,0x01,0x00,0x00,0x41,0x00,0x00,0x00,0x8c,0x00,0x00, +0x00,0x06,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3e,0x00, +0x00,0x00,0x75,0xd3,0x75,0xb5,0x00,0xf8,0x24,0x01,0x01,0x00,0x00,0x00,0x10, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x19,0x00,0x00, +0x00,0x6a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00, +0x00,0x00,0xfa,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +0x18,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x00, +0x00,0xd5,0x75,0x75,0xb5,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00, +0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3a,0x0e,0x00,0x00,0x14,0x01, +0x00,0x00,0x73,0xfa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x3a,0x0e,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf8,0x3d, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3a,0x0e,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x3a,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0f,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00, +0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f, +0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00, +0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00, +0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82, +0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0, +0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00, +0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00, +0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00, +0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00, +0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00, +0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x13,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35, +0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00, +0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c, +0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0b,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0, +0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00, +0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00, +0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00, +0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00, +0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00, +0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35, +0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c, +0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f, +0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17, +0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00, +0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00, +0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00, +0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00, +0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00, +0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35, +0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00, +0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c, +0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f, +0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17, +0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00, +0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00, +0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00, +0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f, +0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00, +0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x00, +0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35, +0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c, +0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f, +0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17, +0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00, +0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00, +0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00, +0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f, +0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00, +0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82, +0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0, +0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00, +0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x78,0x38,0x05,0x20,0xb8,0x3a,0x05,0x20, +0xf8,0x3c,0x05,0x20,0x38,0x3f,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x10,0x00,0x20,0x00, +0x10,0x00,0x20,0x00,0x10,0x00,0x20,0x00,0x10,0x00,0x20,0x00,0x10,0x00,0x20, +0x00,0x10,0x00,0x20,0x00,0x10,0x00,0x20,0x00,0x10,0x00,0xf0,0x0f,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0d,0x00,0x0d,0x00, +0x0b,0x00,0x0b,0x00,0x0c,0x00,0x0c,0x00,0x0a,0x00,0x0a,0x00,0x00,0x00,0x00, +0x00,0xa0,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x50,0x00, +0x00,0x00,0x50,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x40,0x1f,0x00,0x00,0x80, +0xe5,0x07,0x20,0xa0,0xe5,0x07,0x20,0x50,0xe5,0x07,0x20,0x19,0x00,0x00,0x00, +0x90,0xaa,0x18,0x20,0x74,0xac,0x18,0x20,0xb0,0xab,0x18,0x20,0x80,0xdf,0x18, +0x20,0x30,0xd3,0x18,0x20,0x98,0x6b,0x19,0x20,0x90,0x6d,0x19,0x20,0xa8,0x71, +0x19,0x20,0x50,0xa5,0x18,0x20,0x9c,0xa9,0x18,0x20,0x0c,0xa3,0x18,0x20,0xec, +0xa3,0x18,0x20,0x80,0xa8,0x18,0x20,0x04,0xa8,0x18,0x20,0x98,0xa7,0x18,0x20, +0x80,0xa2,0x18,0x20,0xa0,0xa1,0x18,0x20,0x24,0xe0,0x18,0x20,0xfc,0xe0,0x18, +0x20,0xa0,0xa0,0x18,0x20,0x7c,0xa0,0x18,0x20,0x58,0xa0,0x18,0x20,0x34,0xa0, +0x18,0x20,0x04,0xa0,0x18,0x20,0xd4,0x9f,0x18,0x20,0x60,0xa1,0x18,0x20,0x30, +0xa1,0x18,0x20,0x3c,0x9f,0x18,0x20,0xf8,0x9c,0x18,0x20,0x04,0x9e,0x18,0x20, +0xcc,0x9d,0x18,0x20,0x18,0x9d,0x18,0x20,0x70,0x9d,0x18,0x20,0xa0,0x9c,0x18, +0x20,0x58,0x9c,0x18,0x20,0x38,0x42,0x05,0x20,0x94,0x4f,0x05,0x20,0x01,0x00, +0x00,0x00,0xe8,0x9f,0x19,0x20,0xe8,0xa2,0x19,0x20,0x94,0xa3,0x19,0x20,0xdc, +0xa3,0x19,0x20,0xe8,0x9f,0x19,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,0x04,0x05,0x20,0x0d,0x00,0x00, +0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x4c,0x04, +0x05,0x20,0x00,0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x33,0x00,0x00,0x00,0x80, +0x17,0x05,0x20,0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe,0x11,0x40, +0x7b,0x2a,0x9c,0x3f,0x7a,0xde,0x05,0x40,0x77,0x35,0x9b,0x3f,0xbe,0xed,0x05, +0x40,0xed,0x93,0xdd,0x3f,0xed,0xf2,0x01,0x40,0x05,0x00,0x00,0x00,0x05,0x00, +0x00,0x00,0xf0,0x17,0x05,0x20,0x3a,0x37,0x01,0x3e,0x5d,0x83,0x60,0x40,0x05, +0x00,0x00,0x00,0xd0,0x14,0x05,0x20,0x05,0x00,0x00,0x00,0x10,0x18,0x05,0x20, +0x05,0x00,0x00,0x00,0x00,0x15,0x05,0x20,0x00,0x00,0x00,0x05,0x01,0x00,0x00, +0x00,0x33,0x00,0x00,0x00,0x30,0x18,0x05,0x20,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x0c,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc,0x3e,0x00, +0x00,0x00,0x43,0x03,0x00,0x00,0x00,0xa0,0x18,0x05,0x20,0x03,0x00,0x00,0x00, +0xb0,0x18,0x05,0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x4f, +0x05,0x20,0x0d,0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x4e,0x04,0x05,0x20,0x00,0x00,0x00,0x00,0x62,0x27,0x76,0x38, +0x33,0x00,0x00,0x00,0xc0,0x18,0x05,0x20,0x00,0x00,0x00,0x00,0xfb,0xd4,0xc7, +0x3f,0xfd,0x96,0x00,0x40,0xfb,0xd4,0xc7,0x3f,0xfd,0x96,0x00,0x40,0xfb,0xd4, +0xc7,0x3f,0xfd,0x96,0x00,0x40,0xfb,0xd4,0xc7,0x3f,0xfd,0x96,0x00,0x40,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x00,0x00,0x00, +0x00,0x80,0x4f,0x05,0x20,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x00,0x00, +0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x30,0x19,0x05, +0x20,0x03,0x00,0x00,0x00,0x30,0x19,0x05,0x20,0x00,0x00,0x00,0x40,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x50,0x04,0x05,0x20,0x0d,0x00,0x00,0x00,0x33,0x33,0x33,0x3f, +0x1e,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x40,0x19,0x05,0x20,0x00,0x00,0x00, +0x40,0x62,0x27,0x76,0x38,0x33,0x00,0x00,0x00,0x80,0x17,0x05,0x20,0x01,0x00, +0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe,0x11,0x40,0x7b,0x2a,0x9c,0x3f,0x7a, +0xde,0x05,0x40,0x77,0x35,0x9b,0x3f,0xbe,0xed,0x05,0x40,0xed,0x93,0xdd,0x3f, +0xed,0xf2,0x01,0x40,0x0c,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0xb0,0x19,0x05, +0x20,0x3a,0x37,0x01,0x3e,0x06,0x93,0xfd,0x41,0x0c,0x00,0x00,0x00,0xd0,0x14, +0x05,0x20,0x0c,0x00,0x00,0x00,0xe0,0x19,0x05,0x20,0x0c,0x00,0x00,0x00,0x00, +0x15,0x05,0x20,0x00,0x00,0x00,0x05,0x01,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +0x30,0x18,0x05,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0c,0x00,0x00, +0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc,0x3e,0x00,0x00,0x00,0x43,0x03,0x00, +0x00,0x00,0x30,0x19,0x05,0x20,0x03,0x00,0x00,0x00,0x30,0x19,0x05,0x20,0xb1, +0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x54,0x04,0x05,0x20,0x0d,0x00,0x00, +0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x58,0x04, +0x05,0x20,0x00,0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x33,0x00,0x00,0x00,0x80, +0x17,0x05,0x20,0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe,0x11,0x40, +0x7b,0x2a,0x9c,0x3f,0x7a,0xde,0x05,0x40,0x8e,0x69,0xee,0x3e,0x27,0xfe,0x11, +0x40,0x7b,0x2a,0x9c,0x3f,0x7a,0xde,0x05,0x40,0x05,0x00,0x00,0x00,0x05,0x00, +0x00,0x00,0xf0,0x17,0x05,0x20,0x3a,0x37,0x01,0x3e,0x5d,0x83,0x60,0x40,0x05, +0x00,0x00,0x00,0xd0,0x14,0x05,0x20,0x05,0x00,0x00,0x00,0x10,0x18,0x05,0x20, +0x05,0x00,0x00,0x00,0x00,0x15,0x05,0x20,0x00,0x00,0x00,0x05,0x01,0x00,0x00, +0x00,0x33,0x00,0x00,0x00,0x30,0x18,0x05,0x20,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x0c,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc,0x3e,0x00, +0x00,0x00,0x43,0x03,0x00,0x00,0x00,0x10,0x1a,0x05,0x20,0x03,0x00,0x00,0x00, +0x20,0x1a,0x05,0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x4f, +0x05,0x20,0x0d,0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x5a,0x04,0x05,0x20,0x00,0x00,0x00,0x40,0x62,0x27,0x76,0x38, +0x33,0x00,0x00,0x00,0x30,0x1a,0x05,0x20,0x02,0x00,0x00,0x00,0x95,0x8f,0x63, +0x3f,0xfd,0x52,0x5c,0x40,0x95,0x8f,0x63,0x3f,0xfd,0x52,0x5c,0x40,0x95,0x8f, +0x63,0x3f,0xfd,0x52,0x5c,0x40,0x95,0x8f,0x63,0x3f,0xfd,0x52,0x5c,0x40,0x05, +0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xf0,0x17,0x05,0x20,0xd3,0x8c,0xa4,0x3e, +0x80,0xf1,0x06,0x41,0x05,0x00,0x00,0x00,0xd0,0x14,0x05,0x20,0x05,0x00,0x00, +0x00,0x10,0x18,0x05,0x20,0x05,0x00,0x00,0x00,0x00,0x15,0x05,0x20,0x00,0x00, +0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x4f,0x05,0x20,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x30,0x19,0x05, +0x20,0x03,0x00,0x00,0x00,0x30,0x19,0x05,0x20,0x00,0x00,0x00,0x40,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x5c,0x04,0x05,0x20,0x0d,0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e, +0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x04,0x05,0x20,0x00,0x00,0x00, +0x40,0x62,0x27,0x76,0x38,0x33,0x00,0x00,0x00,0x80,0x17,0x05,0x20,0x01,0x00, +0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe,0x11,0x40,0x7b,0x2a,0x9c,0x3f,0x7a, +0xde,0x05,0x40,0x77,0x35,0x9b,0x3f,0xbe,0xed,0x05,0x40,0xed,0x93,0xdd,0x3f, +0xed,0xf2,0x01,0x40,0x05,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xf0,0x17,0x05, +0x20,0x3a,0x37,0x01,0x3e,0x5d,0x83,0x60,0x40,0x05,0x00,0x00,0x00,0xd0,0x14, +0x05,0x20,0x05,0x00,0x00,0x00,0x10,0x18,0x05,0x20,0x05,0x00,0x00,0x00,0x00, +0x15,0x05,0x20,0x00,0x00,0x00,0x05,0x01,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +0x30,0x18,0x05,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0c,0x00,0x00, +0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc,0x3e,0x00,0x00,0x00,0x43,0x03,0x00, +0x00,0x00,0x30,0x19,0x05,0x20,0x03,0x00,0x00,0x00,0x30,0x19,0x05,0x20,0xb1, +0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x33,0x33,0xb7, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00, +0x00,0x00,0xa0,0x1a,0x05,0x20,0x19,0xf4,0xff,0x3f,0x00,0x00,0x00,0x32,0x00, +0x00,0x00,0x4e,0x00,0x00,0x80,0x48,0x00,0x00,0x00,0x00,0x00,0x9a,0x99,0x3f, +0xcd,0xcc,0x8c,0x48,0xcd,0xcc,0x8c,0x44,0x00,0x00,0x00,0x3e,0x07,0x00,0x00, +0x00,0x27,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x22,0x00, +0x00,0x00,0x66,0x66,0x66,0x3f,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x33, +0x33,0x33,0x39,0x29,0x5c,0x8f,0x2c,0x3d,0x0a,0xd7,0xad,0x29,0x5c,0x8f,0x30, +0x3d,0x0a,0xd7,0xb1,0x9a,0x99,0x99,0xbf,0x00,0x00,0x00,0x3e,0x33,0x33,0x33, +0xb9,0xc8,0x00,0x00,0x00,0x29,0x5c,0x8f,0x32,0x37,0xd0,0x69,0xaf,0x29,0x5c, +0x8f,0x32,0x37,0xd0,0x69,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x29,0x5c,0x8f,0x2c,0x3d,0x0a,0xd7,0xad, +0x29,0x5c,0x8f,0x30,0x3d,0x0a,0xd7,0xb1,0x9a,0x99,0x99,0xbf,0x00,0x00,0x00, +0x3e,0x33,0x33,0x33,0xb9,0xc8,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xa0,0x1a, +0x05,0x20,0x02,0x00,0x00,0x00,0xb0,0x1a,0x05,0x20,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x08,0x51,0x3c,0x00,0x0b,0x83,0x42,0x33,0x00,0x00,0x00, +0xc0,0x1d,0x05,0x20,0x00,0x6f,0x02,0x3c,0x07,0x00,0x00,0x00,0x90,0x1e,0x05, +0x20,0x00,0x00,0x00,0x3e,0x66,0x66,0x66,0x3c,0x9a,0x99,0x99,0x3f,0x00,0x14, +0xd4,0x40,0x00,0x26,0x07,0x40,0x00,0xe7,0xf1,0x3f,0x00,0x00,0x08,0x4c,0x51, +0x14,0xe8,0x33,0x00,0x0f,0x1f,0x37,0x00,0x92,0x84,0x40,0x00,0x0f,0xce,0x3f, +0x37,0xaf,0xf9,0x22,0x3a,0x37,0x01,0x3e,0x07,0x00,0x00,0x00,0x00,0xab,0xaa, +0x3a,0x03,0x00,0x00,0x00,0x00,0x5f,0x49,0x3e,0x00,0xb9,0x8d,0x30,0x00,0xc8, +0x0e,0x28,0x00,0x7f,0xfc,0x41,0x00,0x7f,0xfc,0x43,0x33,0x33,0x33,0x3f,0x07, +0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xb0,0x1e,0x05,0x20,0x00,0x03,0x03,0x2f, +0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0xbd,0xef,0xd4,0x3e,0x41,0xd3,0x25, +0x3d,0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0x46,0xff,0xff,0x01,0x00,0x00, +0x00,0x40,0x9f,0x8a,0x8e,0x2e,0x34,0xa5,0x30,0x31,0x08,0xa8,0xe0,0x37,0x19, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f, +0xbd,0xef,0xd4,0x3e,0x41,0xd3,0x25,0x3d,0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75, +0x3f,0x46,0xff,0xff,0x01,0x00,0x00,0x00,0x40,0x9f,0x8a,0x8e,0x2e,0x34,0xa5, +0x30,0x31,0x08,0xa8,0xe0,0x37,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19, +0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40, +0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x46,0xff,0xff,0x01,0x00,0x00,0x00, +0x40,0x9f,0x8a,0x8e,0x2e,0x34,0xa5,0x30,0x31,0x06,0xff,0xff,0x3f,0x19,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x20,0x00,0x1a,0x00,0x02,0x00,0x30, +0x00,0x12,0x00,0x2e,0x00,0x1e,0x01,0x0d,0xfd,0x28,0x00,0x03,0x01,0x4b,0x08, +0x0e,0x00,0x34,0x03,0x04,0x00,0x31,0x00,0x42,0xfd,0x4c,0x03,0x1f,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x80,0x00,0x00,0x1c,0x80, +0x01,0x00,0x26,0x80,0x1a,0x00,0x1b,0x80,0x11,0x00,0x1b,0x80,0x02,0x01,0x15, +0x80,0xef,0x04,0x15,0x80,0xef,0x05,0x1b,0x80,0x0c,0x02,0x1b,0x80,0x0c,0x03, +0x15,0x80,0xf4,0x06,0x15,0x80,0xf4,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x13, +0x00,0x00,0x00,0x0b,0x00,0xa0,0x49,0x05,0x20,0x00,0x00,0x00,0x00,0xd0,0x49, +0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb5, +0xd3,0x75,0xd3,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x10,0xa2,0xaa,0xaa,0xbb,0xbb,0xb6,0xb7,0x75,0x00,0x00,0x00,0x1a,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8b, +0x00,0x00,0x00,0x75,0x75,0xb5,0xb4,0x75,0x75,0x75,0x75,0xf3,0x67,0x97,0x54, +0x00,0x00,0x00,0x00,0x10,0x03,0x05,0x20,0x1c,0x03,0x05,0x20,0x28,0x03,0x05, +0x20,0x28,0x03,0x05,0x20,0xe4,0x42,0x05,0x20,0xac,0x43,0x05,0x20,0x74,0x44, +0x05,0x20,0x3c,0x45,0x05,0x20,0x04,0x46,0x05,0x20,0xcc,0x46,0x05,0x20,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x04,0x05,0x20,0x98,0x04,0x05,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x49,0x05,0x20,0x38,0x49,0x05, +0x20,0x6c,0x49,0x05,0x20,0x00,0x00,0x00,0x00,0xfc,0x08,0x05,0x20,0xfc,0x08, +0x05,0x20,0xfc,0x08,0x05,0x20,0xfc,0x08,0x05,0x20,0xfc,0x08,0x05,0x20,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x08,0x05,0x20, +0xfc,0x08,0x05,0x20,0xfc,0x08,0x05,0x20,0xfc,0x08,0x05,0x20,0xfc,0x08,0x05, +0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x09, +0x05,0x20,0x1c,0x09,0x05,0x20,0x1c,0x09,0x05,0x20,0x08,0x09,0x05,0x20,0x08, +0x09,0x05,0x20,0x30,0x09,0x05,0x20,0x44,0x09,0x05,0x20,0x00,0x00,0x00,0x00, +0x5c,0x09,0x05,0x20,0x5c,0x09,0x05,0x20,0x5c,0x09,0x05,0x20,0x5c,0x09,0x05, +0x20,0x5c,0x09,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x5c,0x09,0x05,0x20,0x5c,0x09,0x05,0x20,0x5c,0x09,0x05,0x20,0x5c, +0x09,0x05,0x20,0x5c,0x09,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xb4,0x09,0x05,0x20,0xe4,0x09,0x05,0x20,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb4,0x09,0x05,0x20,0x14,0x0a, +0x05,0x20,0x00,0x00,0x00,0x00,0x44,0x0a,0x05,0x20,0x4c,0x0a,0x05,0x20,0x4c, +0x0a,0x05,0x20,0x44,0x0a,0x05,0x20,0x44,0x0a,0x05,0x20,0x54,0x0a,0x05,0x20, +0x5c,0x0a,0x05,0x20,0x00,0x00,0x00,0x00,0x64,0x0a,0x05,0x20,0x70,0x0a,0x05, +0x20,0x70,0x0a,0x05,0x20,0x64,0x0a,0x05,0x20,0x64,0x0a,0x05,0x20,0x70,0x0a, +0x05,0x20,0x70,0x0a,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x94,0x0a,0x05,0x20,0xb8,0x0a,0x05,0x20,0x00,0x00,0x00,0x00,0x0c,0x0b,0x05, +0x20,0x1e,0x0b,0x05,0x20,0x1e,0x0b,0x05,0x20,0x0c,0x0b,0x05,0x20,0x30,0x0b, +0x05,0x20,0x0c,0x0b,0x05,0x20,0x1e,0x0b,0x05,0x20,0x00,0x00,0x00,0x00,0x84, +0x0b,0x05,0x20,0x94,0x0b,0x05,0x20,0x94,0x0b,0x05,0x20,0x84,0x0b,0x05,0x20, +0xa4,0x0b,0x05,0x20,0x84,0x0b,0x05,0x20,0x94,0x0b,0x05,0x20,0x00,0x00,0x00, +0x00,0xb4,0x0b,0x05,0x20,0xc8,0x0b,0x05,0x20,0xdc,0x0b,0x05,0x20,0xdc,0x0b, +0x05,0x20,0xdc,0x0b,0x05,0x20,0xdc,0x0b,0x05,0x20,0xc8,0x0b,0x05,0x20,0x00, +0x00,0x00,0x00,0xf0,0x0b,0x05,0x20,0xf0,0x0b,0x05,0x20,0xf0,0x0b,0x05,0x20, +0xf0,0x0b,0x05,0x20,0xf0,0x0b,0x05,0x20,0x04,0x0c,0x05,0x20,0x04,0x0c,0x05, +0x20,0x00,0x00,0x00,0x00,0x18,0x0c,0x05,0x20,0x24,0x0c,0x05,0x20,0x24,0x0c, +0x05,0x20,0x30,0x0c,0x05,0x20,0x30,0x0c,0x05,0x20,0x18,0x0c,0x05,0x20,0x24, +0x0c,0x05,0x20,0x00,0x00,0x00,0x00,0x3c,0x0c,0x05,0x20,0x48,0x0c,0x05,0x20, +0x54,0x0c,0x05,0x20,0x54,0x0c,0x05,0x20,0x54,0x0c,0x05,0x20,0x3c,0x0c,0x05, +0x20,0x48,0x0c,0x05,0x20,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x1c,0x09, +0x18,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xc0,0x52,0x05,0x20,0xe0, +0x55,0x05,0x20,0x00,0x59,0x05,0x20,0x20,0x5c,0x05,0x20,0x40,0x5f,0x05,0x20, +0xa0,0x60,0x05,0x20,0x00,0x62,0x05,0x20,0x20,0x65,0x05,0x20,0x40,0x68,0x05, +0x20,0xa0,0x69,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x04,0x00,0x05,0x00,0x08,0x00,0x09,0x00,0x0c,0x00,0x0d, +0x00,0x02,0x00,0x03,0x00,0x06,0x00,0x07,0x00,0x0a,0x00,0x0b,0x00,0x0e,0x00, +0x0f,0x00,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40, +0x01,0x40,0x01,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x05,0x00, +0x06,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x05, +0x00,0x06,0x00,0x07,0x00,0x0a,0x00,0x0a,0x00,0x0b,0x00,0x0b,0x00,0x0c,0x00, +0x0c,0x00,0x0d,0x00,0x0d,0x00,0x0a,0x00,0x0a,0x00,0x0b,0x00,0x0b,0x00,0x0c, +0x00,0x0c,0x00,0x0d,0x00,0x0d,0x00,0xa0,0xe6,0x07,0x20,0xe0,0xe5,0x07,0x20, +0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0b,0x00, +0x00,0x00,0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x09, +0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x64,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x88,0x18, +0x20,0x98,0x8b,0x18,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7d,0x33,0x00,0x00,0x80,0x03,0x08, +0x20,0x4c,0x80,0x08,0x20,0x21,0xff,0xff,0xa0,0x02,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x36,0x41,0x00,0x68,0x02,0x68,0x06,0x71,0x1f,0x4b,0x68,0x06,0x78, +0xa7,0xe0,0x56,0x11,0x47,0x93,0x10,0xa8,0x62,0xb8,0x14,0xa8,0x0a,0xcd,0x05, +0xa8,0x1a,0xe0,0x07,0x00,0x48,0x62,0x48,0x04,0xb8,0x13,0xdd,0x06,0x88,0x42, +0xc8,0x22,0xad,0x08,0x82,0x28,0x61,0xc8,0x1c,0xe0,0x08,0x00,0x0c,0x0a,0xd8, +0x22,0xe8,0x32,0xd8,0x1d,0x60,0xee,0xc0,0x50,0x9d,0x80,0x76,0xae,0x0d,0xd8, +0x22,0xf8,0x09,0xd8,0x1d,0x4b,0x99,0xda,0x8a,0xf9,0x08,0x4b,0xaa,0xcd,0x05, +0xd0,0xae,0xa0,0xb8,0x14,0xe0,0x07,0x00,0x1d,0xf0,0x00,0x00,0x36,0x21,0x01, +0x38,0x32,0x0c,0x0d,0x0c,0x05,0x2f,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11,0x0c, +0xf6,0x48,0x42,0x0f,0x82,0x88,0x04,0x44,0x0c,0x0c,0x11,0x78,0x12,0xb1,0x01, +0x4b,0xb9,0x01,0x92,0xc7,0x3c,0xa2,0xc7,0x48,0x2f,0x40,0x91,0x04,0x44,0x0c, +0x0c,0x11,0x2f,0x21,0x89,0x04,0x44,0x0c,0x0c,0x11,0xa8,0x02,0x98,0x54,0xb2, +0xc7,0x40,0xaf,0x61,0x89,0x04,0x44,0x0c,0x0c,0x11,0x98,0x09,0x88,0x6a,0xa8, +0x8a,0x80,0x82,0x21,0x89,0x81,0x00,0x0a,0x40,0x60,0xc0,0xb1,0x4f,0xab,0x92, +0x43,0xe0,0x90,0x27,0x0b,0x4f,0x2d,0x8d,0x43,0xe0,0xa0,0xa7,0x0b,0x76,0xa8, +0xbb,0xe8,0x83,0x88,0x04,0xf8,0x14,0x98,0x24,0xf8,0x1f,0x98,0x19,0x88,0x18, +0x90,0x6d,0x97,0xe8,0x1e,0x2f,0x1a,0x43,0x43,0xd0,0x50,0x2f,0x0c,0xea,0xed, +0xaf,0xfa,0x43,0x43,0xe0,0x30,0x85,0x02,0xb0,0x04,0x03,0x6f,0x67,0x01,0x42, +0x50,0x20,0x08,0x01,0xb0,0xba,0x20,0x0f,0x7d,0x01,0x82,0x50,0x20,0x0c,0x11, +0x92,0x22,0x13,0xaf,0xe0,0x0a,0x22,0x50,0x20,0x08,0x29,0x98,0x19,0xaf,0xe0, +0x0a,0x22,0x50,0x20,0x0c,0x39,0x90,0x6d,0x97,0xaf,0xe0,0x0a,0x22,0xd0,0x10, +0x0f,0x09,0xaf,0xe0,0x0a,0x22,0xd0,0x50,0xaf,0x0b,0xaf,0xe0,0x0a,0x22,0xf8, +0x50,0x0e,0x0d,0xd0,0x69,0xd6,0x88,0x74,0xef,0x11,0x03,0x62,0x50,0x30,0x00, +0x01,0x0f,0xb1,0xc3,0x2a,0x50,0x30,0x04,0x11,0xf2,0x22,0x12,0xaf,0xe0,0x0a, +0x22,0x50,0x30,0x00,0x29,0xf8,0x1f,0xaf,0xe0,0x0a,0x22,0x50,0x30,0x04,0x39, +0xf0,0x6d,0x97,0xaf,0xe0,0x0a,0x22,0xd0,0x00,0x87,0x09,0xaf,0xe0,0x0a,0x22, +0xd0,0x50,0x2f,0x0b,0xaf,0xe0,0x0a,0x22,0xf8,0x50,0x86,0x0c,0xd0,0x6f,0xd6, +0xe8,0x64,0xe8,0x1e,0xd0,0x6e,0xd6,0x1b,0xdd,0xfd,0x01,0xd2,0xc7,0x28,0x92, +0xc7,0x1c,0x82,0xc7,0x20,0xa2,0xc7,0x2c,0xb2,0xc7,0x24,0xe2,0xc7,0x18,0x2f, +0xc1,0x89,0x04,0x44,0x0c,0x0c,0x11,0x2f,0x61,0x91,0x04,0x44,0x0c,0x0c,0x11, +0xaf,0x40,0x91,0x04,0x44,0x0c,0x0c,0x11,0x2f,0x00,0x91,0x04,0x44,0x0c,0x0c, +0x11,0xaf,0x21,0x89,0x04,0x44,0x0c,0x0c,0x11,0xaf,0xa1,0x91,0x04,0x44,0x0c, +0x0c,0x11,0xaf,0xe1,0x81,0x04,0x44,0x0c,0x0c,0x11,0x0c,0x0d,0xf8,0x81,0xcf, +0x81,0x09,0x22,0x44,0x0c,0x0c,0x11,0x76,0xaf,0x74,0x92,0x22,0x13,0x98,0x19, +0x82,0x27,0x17,0x90,0x6d,0x97,0xcc,0x68,0x8f,0x08,0x00,0x08,0xc4,0x50,0xb7, +0x0a,0xa2,0x22,0x14,0xa8,0x1a,0xa0,0xad,0x87,0xaf,0xe0,0x0a,0x22,0xc4,0x50, +0xb7,0x0a,0xaf,0xe0,0x0a,0x22,0xd0,0x10,0x97,0x0d,0xbf,0x46,0x8c,0x22,0xd0, +0x00,0x17,0x0d,0xaf,0xe0,0x0a,0x22,0xc8,0x10,0xc7,0x08,0x3f,0x63,0x84,0x20, +0xc4,0x00,0x3f,0x08,0x3f,0x63,0x00,0x21,0x44,0x0c,0x0c,0x11,0x0f,0xb5,0x43, +0x29,0xd0,0x20,0x97,0x0c,0xf8,0x23,0xef,0xff,0x03,0x62,0xe8,0x30,0x2d,0x01, +0xb0,0x04,0x03,0xb0,0xb8,0x34,0xfa,0xfd,0xb2,0x4f,0x00,0xe8,0xa4,0xe8,0x1e, +0xea,0xed,0xb2,0x4e,0x00,0x1b,0xdd,0xcf,0xc3,0x42,0x43,0x44,0x0c,0x0c,0x11, +0x4f,0x63,0x42,0x43,0x44,0x0c,0x0c,0x11,0xcf,0x82,0x42,0x43,0x44,0x0c,0x0c, +0x11,0x4f,0xa2,0x42,0x43,0x44,0x0c,0x0c,0x11,0xa2,0xc2,0x3c,0xb2,0xc2,0x38, +0x92,0xc7,0x38,0xe8,0x44,0xf2,0xc7,0x34,0xaf,0xe0,0x91,0x04,0x44,0x0c,0x0c, +0x11,0x88,0x1e,0xe8,0x0e,0x2f,0x21,0x91,0x04,0x44,0x0c,0x0c,0x11,0x8a,0xee, +0xe2,0xce,0x80,0xd2,0x0e,0x7f,0x88,0x81,0xc0,0xdd,0x10,0xd2,0x4e,0x7f,0x92, +0x22,0x11,0xb0,0x00,0x2c,0xa0,0xc0,0x1c,0x4f,0x00,0x14,0x2c,0x44,0x0c,0x0c, +0x11,0xcf,0x01,0x8c,0x2b,0x44,0x0c,0x0c,0x11,0x90,0x88,0x1c,0xe6,0x18,0x02, +0x86,0x43,0x00,0x8f,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11,0x0c,0x28,0xf8,0x81, +0x0f,0xa0,0xa1,0x42,0x2e,0x3a,0x21,0x00,0x76,0xaf,0xe2,0x0f,0x80,0x17,0x22, +0x44,0x0c,0x0c,0x11,0xe2,0x22,0x12,0xc8,0x44,0x98,0x33,0xc8,0x1c,0x98,0x19, +0xe8,0x1e,0x9a,0x9d,0xe0,0x6d,0x87,0xca,0xcd,0x2f,0x98,0x01,0x82,0xe8,0x30, +0x8d,0x04,0x80,0x04,0x03,0x80,0x88,0x34,0x80,0x8c,0x10,0x82,0x49,0x00,0xf8, +0x34,0xe8,0x43,0xf8,0x1f,0xe8,0x1e,0xf0,0xed,0xa7,0x3f,0x48,0x9c,0x2b,0x44, +0x0c,0x0c,0x11,0xcf,0xdb,0x69,0x43,0xe4,0x30,0x5c,0x16,0xa0,0x04,0x03,0xa0, +0xa4,0x34,0xa0,0xac,0x10,0xa2,0x4e,0x00,0xb8,0x53,0xb8,0x1b,0xba,0xbd,0xa2, +0x4b,0x00,0xef,0x27,0x13,0x62,0xe0,0x30,0x5d,0x06,0x80,0x04,0x03,0x98,0x19, +0x80,0x80,0x34,0x9a,0x9d,0x82,0x49,0x00,0xf8,0x73,0xf8,0x1f,0xfa,0xfd,0x52, +0x4f,0x00,0xe8,0x63,0xe8,0x1e,0xea,0xed,0x52,0x4e,0x00,0xb8,0x94,0xef,0x77, +0x03,0x62,0x3e,0x0b,0x01,0x00,0x7f,0x63,0x02,0x2d,0x44,0x0c,0x0c,0x11,0xd0, +0xab,0xc6,0xa2,0x22,0x13,0xa8,0x1a,0xa0,0x2d,0x87,0xaf,0xe0,0x0a,0x22,0x48, +0x00,0x00,0x01,0xaf,0xe0,0x0a,0x22,0x48,0x00,0x04,0x11,0xaf,0xe0,0x0a,0x22, +0x48,0x00,0x00,0x29,0xaf,0xe0,0x0a,0x22,0x48,0x00,0x04,0x39,0x98,0x03,0xaf, +0xe0,0x0a,0x22,0xd0,0x00,0x87,0x08,0x98,0x19,0x7f,0x62,0x02,0x28,0x44,0x0c, +0x0c,0x11,0xd0,0x29,0xc6,0x0f,0xba,0x03,0x82,0xe0,0x60,0xb7,0x09,0xd8,0x81, +0xcf,0x82,0x42,0x43,0x44,0x0c,0x0c,0x11,0x4f,0xa2,0x42,0x43,0x44,0x0c,0x0c, +0x11,0x46,0x00,0x00,0x0c,0x0d,0xb8,0x93,0xb8,0x1b,0x7c,0xf9,0xba,0xbd,0xb2, +0xcb,0x80,0xa2,0x0b,0x7f,0xe8,0x81,0xa0,0xa0,0x24,0xa2,0x4b,0x7f,0xa8,0xb2, +0x88,0x33,0x1b,0xaa,0x88,0x18,0xa0,0xd2,0x21,0xa0,0xa0,0x14,0x8a,0x8d,0xf2, +0x08,0x00,0x00,0x1a,0x40,0x1b,0xdd,0xd0,0xee,0xc0,0x00,0xa6,0xa1,0x90,0xaa, +0x30,0xa0,0xff,0x10,0xf2,0x48,0x00,0x76,0xae,0x0a,0xc8,0x33,0xc8,0x1c,0xca, +0xcd,0x52,0x4c,0x00,0x1b,0xdd,0x59,0x11,0xb8,0x81,0x88,0x62,0xa8,0x33,0x82, +0x28,0x20,0xa8,0x1a,0xe0,0x08,0x00,0x0f,0xa2,0xb8,0x43,0x44,0x0c,0x0c,0x11, +0xaf,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0x4f,0x82,0xb8,0x43,0x44,0x0c,0x0c, +0x11,0x1c,0xf9,0x16,0x7a,0x09,0x8f,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11,0xb8, +0x81,0xef,0x80,0x09,0x22,0x44,0x0c,0x0c,0x11,0xa6,0x1b,0x3f,0x0c,0x0d,0xf8, +0x81,0xb8,0x34,0xc8,0x93,0xe8,0x33,0xc8,0x1c,0xe2,0x2e,0x01,0xb2,0x2b,0x01, +0x76,0xaf,0x2a,0x82,0x0c,0x00,0xb0,0xad,0x87,0xf2,0x0e,0x00,0x1b,0xdd,0x0f, +0xdc,0x03,0x82,0x32,0x0a,0x01,0x00,0x1f,0x62,0x84,0x20,0xfe,0x0b,0x01,0x00, +0x7f,0x62,0x02,0x28,0x44,0x0c,0x0c,0x11,0x0f,0x98,0x03,0x82,0xf4,0x30,0x1e, +0x08,0x6f,0xf4,0x00,0x22,0xa8,0x30,0x1f,0x38,0xaf,0xe0,0x0a,0x22,0x42,0x0a, +0x04,0x00,0xaf,0xe0,0x0a,0x22,0x44,0x38,0x18,0x11,0xaf,0xe0,0x0a,0x22,0x48, +0x00,0x00,0x01,0xaf,0xe0,0x0a,0x22,0x30,0x3c,0x99,0x01,0x4f,0x83,0x42,0x43, +0x44,0x0c,0x0c,0x11,0x0f,0x62,0x09,0x82,0xa4,0x30,0x18,0x00,0x4f,0xa2,0x42, +0x43,0x44,0x0c,0x0c,0x11,0x00,0xcb,0x0d,0xb8,0x44,0x88,0x62,0xa8,0x1b,0x82, +0x28,0x20,0xb8,0x0b,0xe0,0x08,0x00,0x1c,0xfc,0xd1,0xe2,0x49,0x0c,0x0e,0x8c, +0x5a,0x98,0xd2,0xd7,0x99,0x01,0x0c,0x1e,0x8c,0x2e,0x0c,0x1b,0xb9,0x72,0xf8, +0x47,0xe8,0x82,0xf7,0x2e,0x0a,0x59,0x82,0x59,0x72,0x0c,0x0e,0x0c,0x09,0x46, +0x00,0x00,0x98,0x72,0x0c,0x0f,0x66,0x19,0x04,0x0c,0x18,0xa0,0xf8,0x93,0x8c, +0x6f,0x1b,0xfe,0xf9,0x82,0xb8,0x11,0xb9,0xd2,0xe2,0xc2,0x34,0xcc,0x4a,0xd9, +0xd2,0x06,0x10,0x00,0x00,0xfc,0xc9,0x2f,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11, +0x2f,0x82,0xb8,0x43,0x44,0x0c,0x0c,0x11,0x92,0xc7,0x4c,0x90,0xc0,0x0c,0xe0, +0x40,0x0c,0x4b,0x81,0x4f,0xa2,0xb8,0x43,0xa4,0x10,0x88,0x01,0x2f,0x01,0x01, +0xa2,0xa8,0x30,0x18,0x02,0x4f,0xa3,0x42,0x43,0x80,0x14,0x90,0x01,0xcf,0x82, +0x42,0x43,0x44,0x0c,0x0c,0x11,0x00,0x4e,0x0d,0x2f,0x82,0xba,0x43,0x44,0x0c, +0x0c,0x11,0xa2,0xc7,0x50,0xa0,0x80,0x1c,0xe0,0x40,0x1c,0xcf,0x82,0x4a,0x43, +0xc4,0x10,0x2c,0x03,0x76,0x01,0x14,0xb8,0x81,0x0c,0x0d,0x76,0xab,0x0a,0xf8, +0x93,0xf8,0x1f,0xfa,0xfd,0x62,0x4f,0x00,0x1b,0xdd,0x06,0x0d,0x00,0xd8,0xc2, +0x88,0x53,0xd0,0xf0,0x14,0x88,0x18,0xd0,0xd2,0x21,0x00,0x1f,0x40,0x00,0x96, +0xa1,0x8a,0x8d,0xf2,0x08,0x00,0x90,0x90,0x34,0x90,0xff,0x20,0xf2,0x48,0x00, +0x88,0x81,0x1b,0xdd,0xd0,0x88,0xc0,0x76,0xa8,0x0a,0x98,0x53,0x98,0x19,0x9a, +0x9d,0x62,0x49,0x00,0x1b,0xdd,0xa8,0xa2,0xd8,0x92,0x88,0x63,0xf8,0x93,0x88, +0x18,0xf8,0x1f,0xd0,0x90,0x14,0x00,0x09,0x40,0xd0,0xd2,0x21,0xfa,0xfd,0xf2, +0x0f,0x00,0x8a,0x8d,0xf0,0xf0,0xb1,0x1b,0xdd,0x00,0x19,0x40,0x00,0xff,0xa1, +0xf2,0x48,0x00,0xa0,0xf0,0x14,0xa0,0xa2,0x21,0xd7,0x2a,0x1b,0xd0,0x8a,0xc0, +0x1b,0x88,0x76,0xa8,0x13,0xb8,0x63,0x98,0x93,0xb8,0x1b,0x98,0x19,0xba,0xbd, +0x9a,0x9d,0x92,0x09,0x00,0x92,0x4b,0x00,0x1b,0xdd,0x82,0xaf,0x9c,0x7c,0xf5, +0x00,0x1f,0x40,0xb8,0x63,0x0c,0xed,0xb8,0x1b,0x00,0xdd,0xa1,0xba,0xba,0x92, +0x0b,0x00,0x50,0xdd,0x30,0xd0,0x99,0x10,0x92,0x4b,0x00,0x6f,0x22,0xba,0x43, +0x44,0x0c,0x0c,0x11,0xd8,0x57,0xef,0xf1,0x08,0x22,0x44,0x0c,0x0c,0x11,0xcf, +0x23,0x4a,0x43,0x02,0x7b,0x04,0x00,0xcf,0x01,0x8c,0x2b,0x44,0x0c,0x0c,0x11, +0xcf,0x23,0x4a,0x43,0x44,0x0c,0x0c,0x11,0x16,0x8d,0x32,0xf8,0x81,0x0c,0x0d, +0x76,0xaf,0x22,0xa8,0x83,0xb8,0x44,0xa8,0x1a,0xb8,0x1b,0xaa,0xad,0xba,0xbd, +0xb2,0x0b,0x00,0x92,0x0a,0x00,0xb0,0x99,0x10,0x92,0x4a,0x00,0x88,0x93,0x88, +0x18,0x8a,0x8d,0x62,0x48,0x00,0x1b,0xdd,0x92,0xc7,0x58,0x0f,0x82,0xbc,0x43, +0x44,0x0c,0x0c,0x11,0xb8,0x83,0x88,0x62,0x2f,0xa2,0xbc,0x43,0x44,0x0c,0x0c, +0x11,0xe0,0x40,0x2c,0xcf,0xa2,0x52,0x43,0x44,0x0c,0x0c,0x11,0x82,0x28,0x20, +0xa8,0x1b,0x90,0x00,0x2c,0xb8,0x0b,0x4f,0x82,0x52,0x43,0x44,0x0c,0x0c,0x11, +0xe0,0x08,0x00,0xcd,0x0a,0x0c,0x09,0x9c,0x9a,0x6f,0x82,0xbc,0x43,0x44,0x0c, +0x0c,0x11,0x4f,0xa2,0xbc,0x43,0x44,0x0c,0x0c,0x11,0x2f,0xa0,0xa1,0x42,0xc8, +0x10,0xd4,0x05,0x20,0x9d,0xd3,0x16,0x09,0x1e,0x0f,0xc2,0xb8,0x43,0x44,0x0c, +0x0c,0x11,0x0f,0x25,0x01,0x22,0x44,0x0c,0x0c,0x11,0x0c,0x0d,0x8f,0x20,0x09, +0x22,0x44,0x0c,0x0c,0x11,0xe8,0x81,0xef,0x80,0x09,0x22,0x44,0x0c,0x0c,0x11, +0x76,0xae,0x5e,0x98,0x03,0x98,0x19,0x90,0x6d,0xb7,0xaf,0xe0,0x0a,0x22,0x20, +0xd0,0x68,0x01,0xaf,0xe0,0x0a,0x22,0x1c,0xd0,0x6d,0x11,0xaf,0xe0,0x0a,0x22, +0x18,0xd0,0x6a,0x29,0xaf,0xe0,0x0a,0x22,0x14,0xd0,0x6f,0x39,0x88,0x13,0x0f, +0x22,0xbe,0x43,0xd0,0xd0,0x6f,0x08,0x88,0x18,0xaf,0xe0,0x0a,0x22,0xc4,0xc0, +0xe7,0x0e,0xd0,0x28,0xf6,0xf8,0x83,0xf8,0x1f,0xfa,0xfd,0xf2,0x0f,0x00,0x0f, +0xba,0x03,0x82,0xf6,0x0b,0x01,0x00,0x3f,0x62,0x1a,0x2e,0x44,0x0c,0x0c,0x11, +0x4f,0xa2,0x5a,0x43,0xf4,0x30,0x1e,0x0e,0x4f,0xa2,0xbe,0x43,0x44,0x0c,0x0c, +0x11,0x1c,0xfa,0x6f,0xf9,0x18,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22, +0x82,0xea,0x04,0x00,0xaf,0xe0,0x0a,0x22,0x48,0xe0,0x70,0x01,0xaf,0xe0,0x0a, +0x22,0x48,0xe0,0x74,0x11,0xaf,0xe0,0x0a,0x22,0x44,0x38,0x18,0x11,0xaf,0xe0, +0x0a,0x22,0x48,0xe0,0x70,0x29,0xaf,0xe0,0x0a,0x22,0x30,0x3c,0x99,0x01,0xaf, +0xe0,0x0a,0x22,0x48,0xe0,0x74,0x39,0x4f,0xa3,0x5a,0x43,0xd0,0xe0,0x1f,0x0f, +0x92,0xc1,0x10,0x00,0x89,0x3d,0xb8,0x63,0x88,0x62,0xa8,0x1b,0x82,0x28,0x20, +0xb8,0x0b,0xe0,0x08,0x00,0xbc,0x9a,0xa8,0x63,0xf8,0x0a,0xe0,0xcf,0x11,0x0b, +0x9f,0x96,0x59,0x02,0xd8,0x1a,0xda,0xa9,0x0b,0xdd,0x0c,0x1e,0x92,0x0a,0x00, +0x0c,0x48,0x76,0xa8,0x0d,0x37,0x69,0x05,0xe0,0xfc,0xc0,0x06,0x03,0x00,0xf0, +0x99,0x11,0x1b,0xee,0xc2,0xcc,0xfc,0x0b,0xaa,0xd7,0x9a,0xdf,0xe8,0xb2,0xf0, +0xee,0x43,0x86,0x00,0x00,0x00,0x0c,0x0e,0x0c,0x0d,0x1c,0xf9,0x0f,0x82,0x88, +0x04,0x44,0x0c,0x0c,0x11,0xb2,0xc7,0x60,0x6f,0x62,0xb8,0x43,0x44,0x0c,0x0c, +0x11,0xa1,0x0f,0x49,0x0f,0xa2,0xb8,0x43,0x44,0x0c,0x0c,0x11,0x4f,0x22,0xb8, +0x43,0x44,0x0c,0x0c,0x11,0xe0,0xf2,0x21,0x1b,0x8f,0x4f,0x01,0x04,0x29,0x44, +0x0c,0x0c,0x11,0x6f,0xf4,0x00,0x22,0x44,0x0c,0x0c,0x11,0xaf,0x61,0x81,0x04, +0x44,0x0c,0x0c,0x11,0x4f,0x23,0x42,0x43,0x42,0x0a,0x04,0x00,0x4f,0x00,0x04, +0x28,0xf4,0x20,0x96,0x09,0x76,0xa8,0x3e,0xa8,0x43,0x88,0x73,0x98,0x13,0x88, +0x18,0x98,0x19,0xa8,0x1a,0x90,0xed,0x87,0xaa,0xad,0x8a,0x8d,0xc2,0x08,0x00, +0xa2,0x0a,0x00,0x1b,0xdd,0x4f,0xb5,0xa6,0x43,0xb2,0x0a,0x01,0x00,0x9f,0x63, +0x80,0x21,0x44,0x0c,0x0c,0x11,0x8f,0x59,0x79,0x43,0xec,0x30,0x1d,0x01,0x90, +0x04,0x03,0x90,0x9c,0x34,0x90,0xcc,0x20,0xc2,0x48,0x00,0x7c,0xf8,0xe0,0xd0, +0x14,0xc8,0x73,0x00,0x1d,0x40,0xc8,0x1c,0x00,0xd6,0xa1,0xca,0xcf,0xb2,0x0c, +0x00,0x80,0xdd,0x30,0xd0,0xbb,0x10,0xb2,0x4c,0x00,0xe8,0x57,0x16,0xde,0x0b, +0x98,0x93,0xf8,0x81,0xe8,0x19,0xe6,0x1f,0x02,0xc6,0x2b,0x00,0x2f,0x20,0x01, +0x22,0x44,0x0c,0x0c,0x11,0x8f,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11,0x0c,0x0d, +0x76,0xaf,0x9a,0xf8,0x23,0xa8,0x53,0x88,0x63,0xc8,0x94,0xea,0xbd,0xb2,0x0b, +0x00,0xc8,0x1c,0x88,0x18,0xa8,0x1a,0xf8,0x1f,0xaa,0xad,0xfa,0xfd,0x8a,0x8d, +0x82,0x08,0x00,0xf2,0x0f,0x00,0xc0,0xad,0x97,0x80,0xff,0x10,0x88,0x03,0xc8, +0x73,0x88,0x18,0xc8,0x1c,0x80,0xed,0x97,0xca,0xcd,0x2f,0x98,0x01,0x82,0xd0, +0x40,0xbf,0x0b,0xa2,0x0a,0x00,0xef,0xf9,0x93,0x43,0xf4,0x40,0x26,0x08,0x50, +0xcc,0x30,0x6f,0xf7,0x79,0x43,0x48,0x40,0x20,0x01,0x88,0x84,0x6f,0x6f,0x01, +0x42,0x48,0x40,0x24,0x11,0x4f,0x95,0x79,0x43,0xfa,0x0a,0x01,0x00,0xef,0x11, +0x03,0x62,0x48,0x40,0x20,0x29,0x5f,0x63,0x0a,0x2b,0x44,0x0c,0x0c,0x11,0x0f, +0xb1,0xc3,0x2b,0x48,0x40,0x24,0x39,0x98,0x94,0x4f,0x4f,0x01,0x42,0xd0,0x40, +0x27,0x0b,0xef,0x33,0x03,0x62,0xb6,0x0a,0x01,0x00,0x3f,0x62,0x0c,0x2a,0x44, +0x0c,0x0c,0x11,0xd0,0x29,0xd6,0x1b,0xdd,0x1d,0xf0,0x98,0x83,0x86,0xcf,0xff, +0x36,0x41,0x00,0xd8,0x81,0xc8,0x0d,0xd8,0x1d,0x98,0x1c,0xc8,0x0c,0xd8,0x0d, +0x88,0xb9,0xd8,0x1d,0xc8,0x7c,0x92,0x29,0x0d,0x80,0x87,0xa0,0x80,0x40,0x0c, +0x90,0x97,0xa0,0x90,0x80,0x0c,0xcf,0x00,0x84,0x28,0x44,0x0c,0x0c,0x11,0x4f, +0x01,0x04,0x29,0x44,0x0c,0x0c,0x11,0xe6,0x1c,0x02,0x86,0x3d,0x00,0xd0,0x7d, +0x20,0x76,0xac,0x65,0xe1,0xa7,0x48,0xa2,0x05,0x00,0x60,0x03,0x8c,0xf2,0x04, +0x00,0x0f,0x88,0x02,0x82,0xec,0x30,0x84,0x10,0x0f,0xaa,0x02,0x82,0xe0,0x30, +0x05,0x01,0xb0,0x04,0x03,0xe0,0xbb,0x10,0x80,0xea,0x11,0xe0,0xbb,0x20,0xb0, +0x04,0x13,0x20,0x20,0x00,0x91,0x9c,0x48,0x80,0x04,0x03,0x90,0x88,0x10,0xc0, +0x9f,0x11,0x90,0x88,0x20,0x80,0x04,0x13,0x20,0x20,0x00,0xaf,0x30,0x21,0x22, +0x44,0x0c,0x0c,0x11,0x0f,0x30,0x25,0x22,0x44,0x0c,0x0c,0x11,0x0f,0x30,0x05, +0x22,0x44,0x0c,0x0c,0x11,0xe0,0x04,0x03,0xe0,0xe0,0x34,0xe2,0x47,0x00,0x1b, +0x77,0xd0,0x7d,0x20,0x76,0xac,0x84,0x81,0x8e,0x48,0x50,0x04,0x03,0x42,0x07, +0x00,0x80,0x55,0x10,0x40,0x84,0x11,0x80,0x55,0x20,0x50,0x04,0x13,0x20,0x20, +0x00,0xf1,0x86,0x48,0xe0,0x04,0x03,0xd2,0x02,0x00,0xf0,0xee,0x10,0x80,0xfd, +0x11,0xf0,0xee,0x20,0xe0,0x04,0x13,0x20,0x20,0x00,0xb1,0x81,0x48,0x4f,0x21, +0x65,0x22,0x44,0x0c,0x0c,0x11,0xa0,0x04,0x03,0xc0,0x04,0x03,0xc0,0xc8,0x34, +0xc2,0x42,0x00,0x92,0x07,0x00,0xb0,0xaa,0x10,0xc0,0xb9,0x11,0xb0,0xaa,0x20, +0xa0,0x04,0x13,0x20,0x20,0x00,0x81,0x78,0x48,0x50,0x04,0x03,0x42,0x03,0x00, +0x80,0x55,0x10,0x40,0x55,0x20,0x50,0x04,0x13,0x20,0x20,0x00,0x1b,0x77,0x0f, +0x20,0x45,0x22,0x44,0x0c,0x0c,0x11,0x1b,0x22,0xf0,0x04,0x03,0xf0,0xf0,0x34, +0xf2,0x43,0x00,0x1b,0x33,0x1d,0xf0,0x00,0x36,0x41,0x00,0xb8,0x25,0x0c,0x0a, +0x92,0x9b,0x01,0xb2,0x2b,0x12,0x30,0x99,0xd1,0xb0,0x99,0x90,0xcf,0x34,0xc1, +0x42,0x44,0x0c,0x0c,0x11,0x0c,0x78,0x6f,0xe4,0x00,0x22,0x12,0x12,0x04,0x00, +0x3f,0x40,0x02,0x40,0x44,0x0c,0x0c,0x11,0x76,0x00,0x0c,0xdd,0x05,0xbd,0x03, +0xad,0x02,0x88,0xc4,0xcd,0x04,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x36,0x41,0x00, +0x68,0x16,0x58,0x15,0x88,0x42,0xa8,0x02,0xb8,0x13,0x0c,0x1c,0x38,0x81,0xc0, +0x00,0xf3,0xb0,0xb7,0xa0,0xa8,0x1a,0xe0,0xc7,0x11,0xd8,0x6a,0xf2,0x9a,0x0e, +0x37,0x18,0x0b,0xe8,0x32,0x39,0x42,0xe0,0x31,0x21,0x39,0x32,0x46,0x00,0x00, +0x38,0x32,0xe2,0x9a,0x0f,0xf7,0x97,0x04,0x30,0x31,0x21,0x39,0x32,0xe7,0x97, +0x04,0x30,0x31,0x21,0x39,0x32,0x50,0xe3,0x47,0x88,0x12,0x60,0x23,0x57,0xf7, +0xa7,0x17,0xaf,0xe0,0x0a,0x22,0x0a,0x28,0x21,0x02,0xaf,0xe0,0x0a,0x22,0x0a, +0x18,0x99,0x01,0xcf,0x10,0x00,0x08,0xe0,0x00,0x1e,0x1a,0x60,0x33,0x57,0x50, +0xf3,0x47,0xaf,0xe0,0x0a,0x22,0x0a,0x28,0x21,0x02,0xaf,0xe0,0x0a,0x22,0x0a, +0x18,0x99,0x01,0xef,0xff,0xbf,0x42,0xe0,0x00,0x1e,0x1a,0xef,0xce,0x91,0x62, +0xd0,0x00,0x1e,0x1a,0x60,0x23,0x57,0x50,0xe3,0x47,0x50,0xf3,0x47,0x60,0x33, +0x57,0xaf,0xe0,0x0a,0x22,0x02,0x18,0x99,0x01,0xaf,0xe0,0x0a,0x22,0x02,0x28, +0x21,0x02,0xaf,0xe0,0x0a,0x22,0xc0,0x00,0x1e,0x2a,0xaf,0xe0,0x0a,0x22,0xee, +0x2b,0x11,0x00,0xaf,0xe0,0x0a,0x22,0xc0,0x00,0x1e,0x1a,0xaf,0xe0,0x0a,0x22, +0xee,0x1b,0x09,0x00,0xaf,0xe0,0x0a,0x22,0xee,0x0b,0x01,0x00,0xaf,0xe0,0x0a, +0x22,0x44,0x28,0x14,0x11,0xaf,0xe0,0x0a,0x22,0x44,0x18,0x0c,0x11,0xaf,0xe0, +0x0a,0x22,0x44,0x0c,0x04,0x01,0x8f,0x21,0x01,0x22,0x44,0x0c,0x0c,0x11,0x0c, +0x0f,0x70,0x52,0x21,0xaf,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11,0xe8,0x62,0x0f, +0x80,0x04,0x29,0x44,0x0c,0x0c,0x11,0xea,0xec,0xe0,0x20,0x1c,0x9c,0x88,0x98, +0x3a,0xcf,0xaf,0xc1,0x42,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x42,0x36, +0x10,0x10,0xcf,0x01,0x84,0x29,0x44,0x0c,0x0c,0x11,0x98,0xa2,0xd8,0x82,0x90, +0x97,0xb0,0xda,0xdc,0xd0,0x30,0x1c,0x90,0x02,0x1c,0x0f,0x00,0x85,0x28,0xe0, +0x70,0xaf,0x09,0x8f,0x1f,0xbf,0x42,0xd0,0x40,0xa7,0x09,0x0f,0x0f,0x79,0x43, +0xf8,0x40,0x86,0x0b,0x80,0x87,0xc0,0x00,0x2e,0x1d,0x00,0x3d,0x1d,0x6f,0x53, +0x00,0x2a,0x50,0xb0,0x20,0x31,0xef,0xc9,0x02,0x62,0x50,0xa0,0x20,0x21,0xa0, +0x80,0x1c,0x8f,0xf0,0x0a,0x22,0xa4,0xa0,0xd0,0x05,0xaf,0xca,0x68,0x43,0xc4, +0x10,0x24,0x33,0x2f,0x6a,0x00,0x82,0xc0,0x10,0x24,0x23,0xd0,0x04,0x03,0xe0, +0x04,0x03,0xcf,0xc1,0x03,0x42,0xa4,0x90,0x50,0x02,0xaf,0xa1,0x01,0x42,0xa4, +0x90,0x55,0x02,0xe0,0x6d,0x10,0xcf,0x4c,0x01,0x22,0x0a,0x88,0xc9,0x04,0x60, +0x33,0x20,0x0f,0x6b,0x00,0x82,0x50,0x90,0x40,0x01,0xf9,0x0b,0x6f,0xdb,0x1f, +0x62,0xa4,0x80,0xc0,0x04,0x1f,0xe0,0x13,0x0c,0x44,0x0c,0x0c,0x11,0x00,0x0b, +0x2d,0x1d,0xf0,0x36,0x41,0x00,0xdd,0x05,0xcd,0x04,0xbd,0x03,0x88,0x22,0xad, +0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0x06,0x7d,0x02, +0x28,0x73,0x0c,0x08,0x8c,0x52,0x48,0x23,0x77,0x14,0x01,0x0c,0x16,0x9c,0x16, +0x98,0x63,0x58,0x03,0x1b,0x99,0x99,0x63,0x97,0xa5,0x05,0x89,0x73,0x89,0x63, +0x2d,0x08,0x1d,0xf0,0x6d,0x08,0xcc,0x52,0xa8,0x33,0x77,0x9a,0x01,0x0c,0x16, +0x9c,0x36,0xc8,0x53,0xb8,0x13,0x1b,0xcc,0xc9,0x53,0xc7,0xab,0xe5,0x89,0x53, +0x0c,0x12,0x0c,0x1d,0xd9,0x73,0x1d,0xf0,0x89,0x53,0x89,0x63,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x61,0x00,0xef,0xeb,0x00,0x22,0x44,0x0c,0x0c,0x11,0xc8,0x02, +0xf1,0xce,0x47,0xd1,0xd6,0x47,0xe0,0x04,0x03,0xd9,0x01,0xd8,0x22,0xf0,0xee, +0x10,0xb2,0x0d,0x01,0xc8,0x2c,0xe0,0xfb,0x11,0xf0,0xee,0x20,0xe0,0x04,0x13, +0x20,0x20,0x00,0xb2,0x02,0x11,0x31,0xc6,0x47,0x1c,0xff,0xa2,0xcc,0x20,0xa0, +0x40,0x0c,0x0f,0x3a,0x11,0x82,0xc2,0x3b,0x04,0x00,0x2f,0x20,0x01,0xa2,0xa8, +0x10,0x88,0x01,0x4b,0x8d,0x2f,0x01,0x01,0xa2,0xc4,0x10,0x84,0x00,0x2f,0x81, +0xc2,0x43,0x44,0x0c,0x0c,0x11,0xe0,0x04,0x03,0x30,0xee,0x10,0xb0,0xee,0x20, +0xe0,0x04,0x13,0x20,0x20,0x00,0xa1,0xb6,0x47,0x90,0x04,0x03,0x0c,0x03,0xa0, +0x99,0x10,0x90,0x04,0x13,0x20,0x20,0x00,0x80,0x04,0x03,0x80,0x82,0x04,0x82, +0x41,0x04,0x76,0x10,0x02,0x86,0x57,0x00,0xe2,0x0d,0x00,0xa2,0xcc,0x10,0x91, +0xaf,0x47,0x80,0x04,0x03,0x90,0x88,0x10,0xa0,0x00,0x0c,0xd0,0x9e,0x11,0x90, +0x88,0x20,0x80,0x04,0x13,0x20,0x20,0x00,0xe2,0xc2,0x14,0xaf,0x20,0x09,0x22, +0x44,0x0c,0x0c,0x11,0xef,0x23,0x6c,0x43,0x44,0x0c,0x0c,0x11,0x0f,0xe6,0x34, +0x22,0x48,0x70,0x38,0x01,0xe0,0x40,0x0c,0x3f,0x40,0x0a,0x41,0x44,0x0c,0x0c, +0x11,0x76,0x04,0x0d,0xcb,0xbc,0xb0,0x00,0x0c,0x46,0x01,0x00,0x82,0xcc,0x1c, +0x80,0x80,0x0c,0x80,0x04,0x03,0x80,0x81,0x04,0x82,0x41,0x05,0x2f,0xc0,0x09, +0xa2,0xa8,0x10,0x28,0x00,0xcf,0x73,0x8f,0x02,0xa4,0x30,0x10,0x00,0x0f,0x5a, +0x19,0x82,0x3c,0x3c,0x08,0x02,0xef,0xf6,0x00,0x22,0x44,0x0c,0x0c,0x11,0x8f, +0x1d,0x80,0x49,0xc2,0x1b,0x04,0x00,0xaf,0x41,0x01,0xa2,0x48,0x10,0x08,0x01, +0x0f,0x22,0x01,0x82,0xc4,0x10,0x9f,0x08,0x2f,0x21,0x09,0xa2,0x14,0x10,0x88, +0x03,0x0f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0x0f,0xe2,0x26,0x22,0xa4,0x10, +0x08,0x03,0x90,0x04,0x03,0xa2,0xcc,0x14,0xa0,0x00,0x0c,0x90,0x91,0x04,0x92, +0x41,0x05,0x80,0x04,0x03,0xb2,0xc2,0x18,0x2f,0x60,0x09,0xa2,0xa8,0x30,0x28, +0x00,0x91,0x7f,0x47,0x0f,0x58,0x49,0x82,0xa4,0x30,0x18,0x02,0x0f,0x31,0x79, +0x43,0x3c,0x3c,0x08,0x00,0x6f,0xec,0x08,0x22,0x44,0x0c,0x0c,0x11,0x00,0xcb, +0x0d,0xb2,0x0d,0x00,0xa0,0x00,0x2c,0xaf,0xc0,0x01,0xa2,0xc2,0x4b,0x04,0x00, +0x2f,0x37,0x83,0x43,0x80,0x48,0x20,0x04,0x0f,0x31,0x93,0x43,0x30,0x3c,0x18, +0x02,0x80,0x04,0x13,0x20,0x20,0x00,0x0f,0x64,0x91,0x82,0xd8,0x10,0x8c,0x01, +0xcf,0x33,0x6d,0x43,0x44,0x0c,0x0c,0x11,0xa0,0x04,0x03,0xa0,0xa6,0x04,0xa5, +0xdf,0xff,0xb1,0x69,0x47,0x90,0x04,0x03,0x82,0x01,0x05,0xb0,0x99,0x10,0xf0, +0xb8,0x11,0xb0,0x99,0x20,0x90,0x04,0x13,0x20,0x20,0x00,0xf1,0x64,0x47,0xe0, +0x04,0x03,0xa0,0xd0,0x04,0xf0,0xee,0x10,0x80,0xfd,0x11,0xf0,0xee,0x20,0xe0, +0x04,0x13,0x20,0x20,0x00,0xc0,0x04,0x03,0xc0,0xc8,0x04,0xc2,0x41,0x04,0xb2, +0xc2,0x1c,0xa0,0x04,0x03,0xa0,0xa1,0x04,0x65,0xdb,0xff,0xd1,0x5a,0x47,0xc0, +0x04,0x03,0xa0,0xb0,0x04,0xd0,0xcc,0x10,0x70,0xdb,0x11,0xd0,0xcc,0x20,0xc0, +0x04,0x13,0x20,0x20,0x00,0x76,0x19,0x4d,0x0c,0x1b,0x0c,0x1c,0x0c,0x0a,0xe2, +0x22,0x10,0x0c,0x09,0xcc,0x3e,0x66,0x1c,0x01,0x0c,0x19,0x8c,0x89,0x82,0x22, +0x11,0xf8,0xf2,0x87,0xaf,0x01,0x0c,0x1a,0x16,0x3a,0x05,0x98,0xf2,0x1b,0x99, +0x0c,0x0a,0x99,0xf2,0xc2,0x22,0x1b,0x0c,0x09,0xcc,0x3c,0x66,0x1b,0x01,0x0c, +0x19,0x8c,0x99,0xe2,0x22,0x1c,0xd2,0x22,0x1a,0xe7,0xad,0x01,0x0c,0x1a,0xbc, +0x7a,0x32,0x22,0x1a,0x1b,0x33,0x32,0x62,0x1a,0x1d,0xf0,0xa1,0x40,0x47,0x90, +0x04,0x03,0x82,0x01,0x04,0xa0,0x99,0x10,0x60,0xa8,0x11,0xa0,0x99,0x20,0x90, +0x04,0x13,0x20,0x20,0x00,0x76,0x0a,0x06,0x0c,0x1b,0x0c,0x0c,0xc6,0xe4,0xff, +0x0c,0x0b,0x06,0xe3,0xff,0xc2,0x62,0x10,0x9d,0x03,0xc6,0xe9,0xff,0xb2,0x62, +0x1b,0x46,0xf1,0xff,0x00,0x00,0x36,0x41,0x00,0x71,0x35,0x47,0x51,0x35,0x47, +0x61,0x35,0x47,0xec,0x04,0x0c,0x09,0xa2,0x25,0x16,0x82,0x25,0x17,0x1b,0xaa, +0xa2,0x65,0x16,0xe0,0xaa,0x11,0x5a,0xba,0x7a,0xaa,0xa2,0x66,0x7f,0xcc,0x48, +0x92,0x6b,0x24,0x86,0x00,0x00,0x92,0x6b,0x25,0x66,0x14,0x0a,0xb2,0x25,0x16, +0xe6,0x1b,0x04,0x0c,0x1c,0xc2,0x65,0x17,0x8c,0xe4,0xd2,0x25,0x17,0x32,0x65, +0x18,0xcc,0x6d,0x82,0x25,0x19,0xad,0x03,0xe0,0x08,0x00,0xad,0x02,0x25,0x13, +0x00,0x2d,0x0a,0x66,0x24,0x37,0xa2,0x25,0x16,0x92,0x25,0x17,0x50,0xba,0xa0, +0xac,0xd9,0xc2,0x2b,0x25,0xb2,0xcb,0xfc,0xc2,0x65,0x18,0x0b,0xaa,0xa2,0x65, +0x16,0x70,0xda,0xa0,0xd2,0x66,0x7f,0xa2,0x2b,0x25,0x8c,0x99,0xc2,0x2b,0x26, +0xc7,0xba,0x0d,0xc2,0x6b,0x25,0x1d,0xf0,0xe2,0x2b,0x24,0xa7,0xbe,0x02,0xa2, +0x6b,0x24,0x1d,0xf0,0x82,0x25,0x19,0xa2,0x2b,0x24,0xe0,0x08,0x00,0xa2,0x25, +0x16,0x92,0x25,0x17,0x50,0xba,0xa0,0xc2,0x2b,0x24,0xc6,0xee,0xff,0x36,0x41, +0x00,0x7c,0x85,0x31,0x0a,0x47,0x7b,0x42,0x82,0x23,0x17,0x50,0x44,0x10,0x9c, +0x88,0x91,0x08,0x47,0xa2,0x23,0x18,0x92,0x29,0x7f,0x7b,0xaa,0x50,0x5a,0x10, +0x88,0x09,0x4a,0x45,0x40,0x88,0x53,0x89,0x09,0x46,0x0d,0x00,0x82,0x23,0x1a, +0xe0,0x08,0x00,0xc2,0x23,0x18,0xcc,0x3c,0xcd,0x0a,0xa2,0x63,0x18,0xad,0x02, +0x0c,0x8b,0x82,0x23,0x1b,0x7b,0x9c,0x50,0x59,0x10,0x4a,0x45,0xe0,0x08,0x00, +0x82,0x23,0x1a,0xe0,0x08,0x00,0xa2,0x23,0x16,0x30,0xaa,0xa0,0x92,0x2a,0x24, +0x47,0xb9,0x02,0x42,0x6a,0x24,0x2d,0x05,0x42,0x63,0x18,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0x7c,0xc5,0x31,0xef,0x46,0x3b,0x42,0x82,0x23,0x17,0x50, +0x44,0x10,0x9c,0x88,0x91,0xed,0x46,0xa2,0x23,0x18,0x92,0x29,0x7f,0x3b,0xaa, +0x50,0x5a,0x10,0x88,0x09,0x4a,0x45,0x40,0x88,0x53,0x89,0x09,0x46,0x0d,0x00, +0x82,0x23,0x1a,0xe0,0x08,0x00,0xc2,0x23,0x18,0xcc,0x3c,0xcd,0x0a,0xa2,0x63, +0x18,0xad,0x02,0x0c,0x4b,0x82,0x23,0x1b,0x3b,0x9c,0x50,0x59,0x10,0x4a,0x45, +0xe0,0x08,0x00,0x82,0x23,0x1a,0xe0,0x08,0x00,0xa2,0x23,0x16,0x30,0xaa,0xa0, +0x92,0x2a,0x24,0x47,0xb9,0x02,0x42,0x6a,0x24,0x2d,0x05,0x42,0x63,0x18,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x7c,0x05,0x31,0xd4,0x46,0xfb,0x42,0x82, +0x23,0x17,0x50,0x44,0x10,0x9c,0x88,0x91,0xd2,0x46,0xa2,0x23,0x18,0x92,0x29, +0x7f,0xfb,0xaa,0x50,0x5a,0x10,0x88,0x09,0x4a,0x45,0x40,0x88,0x53,0x89,0x09, +0x46,0x0d,0x00,0x82,0x23,0x1a,0xe0,0x08,0x00,0xc2,0x23,0x18,0xcc,0x3c,0xcd, +0x0a,0xa2,0x63,0x18,0xad,0x02,0x1c,0x0b,0x82,0x23,0x1b,0xfb,0x9c,0x50,0x59, +0x10,0x4a,0x45,0xe0,0x08,0x00,0x82,0x23,0x1a,0xe0,0x08,0x00,0xa2,0x23,0x16, +0x30,0xaa,0xa0,0x92,0x2a,0x24,0x47,0xb9,0x02,0x42,0x6a,0x24,0x2d,0x05,0x42, +0x63,0x18,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0x65, +0x8d,0x05,0x5d,0x0a,0xbd,0x04,0x25,0x80,0x00,0x59,0x02,0xad,0x04,0x1c,0x0b, +0x65,0x8e,0x00,0x2d,0x0a,0x0c,0x4b,0x0c,0x8a,0xa5,0x8b,0x05,0x29,0x1a,0x49, +0x0a,0xa9,0x03,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x0c,0x4a,0xe5,0x8d, +0x05,0xb8,0x02,0xb8,0x0b,0x3d,0x0a,0xb8,0x7b,0x65,0xd8,0x03,0x39,0x12,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0x0c,0x1a,0x25,0x8c,0x05,0xa9, +0x12,0x49,0x22,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0x0c,0x4a,0x25,0x8b,0x05, +0x3d,0x0a,0x65,0xca,0x03,0x39,0x12,0x49,0x22,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x00,0xbd,0x03,0x5c,0x0a,0xa5,0x89,0x05,0x3d,0x0a,0xb8,0x02,0x25,0xe0, +0x03,0x39,0x52,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0x0c,0x1a, +0x25,0x88,0x05,0xa9,0x12,0x49,0x22,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0x1c, +0x8a,0x25,0x87,0x05,0xb2,0x22,0x11,0x3d,0x0a,0xb8,0x0b,0xa5,0xdb,0x03,0x32, +0x62,0x14,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0x65,0xd7,0x00, +0x8b,0xa2,0x25,0xad,0x00,0x1d,0xf0,0x00,0x36,0x41,0x00,0xa1,0x89,0x46,0x1c, +0x0b,0xa2,0x2a,0x1c,0xa9,0x02,0xc0,0xaa,0x11,0x65,0x82,0x00,0xa9,0x12,0x1d, +0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x0c,0xca,0xe5,0x82,0x05,0x3d,0x0a,0xb8, +0x02,0x65,0xaf,0x03,0x39,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xbd, +0x03,0x0c,0x1a,0x65,0x81,0x05,0xa9,0x12,0x49,0x22,0x1d,0xf0,0x36,0x41,0x00, +0xbd,0x03,0x0c,0x4a,0x65,0x80,0x05,0x3d,0x0a,0xbd,0x02,0xc8,0x92,0xa5,0xae, +0x03,0x39,0x32,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x4c,0x0a,0xe5,0x7e, +0x05,0xb8,0x82,0xb8,0x1b,0xb8,0xfb,0x3d,0x0a,0xb8,0x0b,0x65,0x0e,0x04,0x39, +0x92,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02,0x25,0xcf,0x00,0xb8,0x73,0x8b, +0xa2,0xe5,0xad,0x00,0xa2,0xc2,0x10,0x65,0xce,0x00,0x1d,0xf0,0x00,0x36,0x61, +0x00,0xbd,0x03,0xa2,0xa0,0x90,0x65,0x7b,0x05,0xf8,0xd2,0xe8,0xc2,0xd8,0xb2, +0xc8,0xa2,0xb8,0x92,0x88,0xe2,0x89,0x01,0x38,0xf2,0x39,0x11,0x3d,0x0a,0x25, +0xbe,0x03,0x39,0x12,0xe8,0x32,0xd8,0x42,0xc8,0x52,0xb8,0x62,0xa8,0x72,0xf8, +0x22,0x98,0x82,0x39,0x1f,0x39,0x1e,0x39,0x1d,0x39,0x1c,0x39,0x1b,0x39,0x5a, +0x39,0x59,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0x4c,0x4a,0x65,0x77, +0x05,0xc8,0x02,0x3d,0x0a,0xb8,0x1c,0xc8,0x0c,0xa5,0x53,0x01,0x39,0x12,0x65, +0x7b,0x05,0x4d,0x0a,0x1c,0x0a,0xbd,0x04,0xa5,0x75,0x05,0xb8,0x02,0x3d,0x0a, +0xb8,0x1b,0x25,0xb6,0x03,0xc8,0x22,0xad,0x04,0x39,0x1c,0xa5,0x73,0x05,0x1d, +0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x1c,0x8a,0xe5,0x73,0x05,0x3d,0x0a,0x25, +0x14,0x04,0x39,0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x4c,0xca,0xa5, +0x72,0x05,0x3d,0x0a,0xb8,0x12,0xe5,0xac,0x03,0x39,0x22,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0xbd,0x03,0x1c,0x0a,0x25,0x71,0x05,0x3d,0x0a,0x65,0xaa, +0x03,0x39,0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x0c,0x8a,0xe5,0x6f, +0x05,0x3d,0x0a,0x65,0xa8,0x03,0x39,0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd, +0x03,0x3c,0xca,0xa5,0x6e,0x05,0x3d,0x0a,0xb8,0x02,0x25,0x9c,0x03,0x39,0x12, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0x2c,0x0a,0x25,0x6d,0x05, +0x3d,0x0a,0xb8,0x22,0xe5,0xa2,0x03,0x39,0x32,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x00,0xbd,0x03,0x1c,0x4a,0xa5,0x6b,0x05,0xb8,0x32,0xb8,0x1b,0xb8,0xfb, +0x3d,0x0a,0xb8,0x0b,0xa5,0x4f,0x04,0x39,0x42,0x1d,0xf0,0x00,0x36,0x41,0x00, +0xbd,0x03,0x0c,0x4a,0xe5,0x69,0x05,0x3d,0x0a,0xb8,0x02,0xe5,0x9d,0x03,0x49, +0x22,0x39,0x12,0x98,0x82,0xa8,0x62,0xb8,0x72,0xa8,0x2a,0xa9,0x0b,0x88,0x03, +0x89,0x09,0x25,0x6d,0x05,0x48,0x42,0x3d,0x0a,0x58,0x72,0x0c,0x4a,0xbd,0x03, +0x25,0x67,0x05,0x6d,0x0a,0xb8,0x04,0xa5,0x99,0x03,0x69,0x14,0x59,0x24,0x65, +0x6b,0x05,0x6d,0x0a,0x48,0x64,0x0c,0x4a,0xbd,0x06,0xa5,0x65,0x05,0x5d,0x0a, +0xb8,0x04,0x25,0x96,0x03,0xad,0x06,0x59,0x64,0xe5,0x63,0x05,0x0c,0x1a,0x48, +0x52,0xbd,0x03,0x28,0x82,0x25,0x64,0x05,0xa9,0x14,0x29,0x24,0xad,0x03,0xa5, +0x62,0x05,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0xa5,0x5f,0x05,0x5d, +0x0a,0xbd,0x04,0xa5,0x93,0x00,0x59,0x02,0xad,0x04,0x1c,0x0b,0xa5,0x60,0x00, +0x2d,0x0a,0x0c,0x4b,0x0c,0x8a,0xe5,0x5d,0x05,0x29,0x1a,0x49,0x0a,0xa9,0x03, +0x1d,0xf0,0x00,0x36,0x41,0x00,0x32,0x62,0x12,0x3c,0xaa,0xbd,0x03,0xe5,0x5f, +0x05,0xa9,0x42,0xbd,0x03,0x4c,0x4a,0x65,0x5f,0x05,0xa9,0x52,0xbd,0x03,0xa2, +0xa0,0xfe,0xa5,0x5e,0x05,0xa9,0x32,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0x3c, +0x8a,0xe5,0x5d,0x05,0x3d,0x0a,0xb2,0x22,0x12,0x65,0x6f,0x0b,0xd2,0xc3,0x28, +0xe2,0xc3,0x20,0x92,0x22,0x14,0x88,0x13,0xc8,0x23,0x41,0xe8,0x45,0xb8,0x63, +0xf2,0x24,0x10,0x32,0x62,0x13,0xf8,0x4f,0x89,0x09,0x88,0x92,0xf8,0x8f,0x89, +0x29,0x82,0xc3,0x30,0xf2,0x2f,0x16,0xc9,0x19,0xa8,0xe2,0xf9,0x39,0xb9,0x59, +0xa9,0x49,0xe9,0x69,0x89,0x89,0xd9,0x79,0x82,0xc2,0x40,0x92,0x22,0x15,0xf8, +0x33,0xf9,0x19,0xe8,0xf2,0xe9,0x29,0xd8,0x53,0xd9,0x09,0xc9,0x39,0xb9,0x49, +0xa9,0x59,0x89,0x69,0xe5,0x5c,0x05,0x3d,0x0a,0xa8,0x22,0xbd,0x03,0xe5,0xe9, +0xff,0xa8,0x72,0xbd,0x03,0xa5,0xd7,0xff,0xc2,0x24,0x10,0xa8,0x82,0xbd,0x03, +0xd2,0x22,0x19,0xe2,0x22,0x18,0x65,0xbc,0x01,0xbd,0x03,0xa8,0x92,0x0c,0x09, +0x99,0x4a,0xc2,0x22,0x16,0xa8,0xb2,0xa5,0xea,0xff,0xa8,0xa2,0xbd,0x03,0xe5, +0xd3,0xff,0xa8,0xc2,0xbd,0x03,0xc2,0x22,0x17,0x25,0xd2,0xff,0xa8,0x42,0xbd, +0x03,0x65,0xe4,0xff,0xa8,0x52,0xbd,0x03,0x25,0xe4,0xff,0xa8,0x62,0xbd,0x03, +0x65,0xcf,0xff,0xa8,0x32,0xbd,0x03,0xa5,0xe4,0xff,0xad,0x03,0xe5,0x50,0x05, +0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x2c,0x4a,0x25,0x51,0x05,0x3d,0x0a, +0xb8,0xc2,0xa5,0x6b,0x0b,0xe1,0xb8,0x45,0x98,0xe2,0xe2,0x2e,0x10,0xf8,0x33, +0xa8,0x5e,0xe8,0x4e,0x4b,0x8a,0x39,0xd2,0xe2,0xce,0x40,0xf9,0x09,0xd8,0x43, +0xd9,0x29,0xc8,0x63,0xc9,0x39,0xb8,0x2a,0xb9,0x69,0xf8,0x3a,0xf9,0x59,0xe9, +0xa9,0xd2,0x22,0x13,0xd9,0x19,0xc8,0x73,0xc9,0xb9,0xb8,0x83,0xb9,0xc9,0xa9, +0x79,0x89,0x49,0xe5,0x51,0x05,0x3d,0x0a,0xc2,0x22,0x12,0xa8,0xf2,0xbd,0x03, +0xe5,0xe1,0xff,0xa8,0x52,0xbd,0x03,0xa5,0xdf,0xff,0xa8,0x42,0xbd,0x03,0xa5, +0xdd,0xff,0xa8,0x72,0xbd,0x03,0x25,0x99,0x01,0xbd,0x03,0xa8,0x32,0x88,0x82, +0x0c,0x0f,0xf9,0x48,0xe5,0xda,0xff,0xad,0x03,0xa5,0x48,0x05,0x1d,0xf0,0x00, +0x36,0x41,0x00,0x4b,0xa2,0x0c,0x5b,0x0c,0x8c,0x25,0x72,0x00,0xcb,0xa2,0x0c, +0x5b,0x0c,0x8c,0xa5,0x71,0x00,0xa2,0xc2,0x14,0x0c,0x5b,0xe5,0xc2,0x04,0xa2, +0xc2,0x1c,0x0c,0x5b,0x65,0xc2,0x04,0xa2,0xc2,0x24,0x0c,0x5b,0xe5,0xc1,0x04, +0xa2,0xc2,0x2c,0x0c,0x5b,0x65,0xc1,0x04,0xa2,0xc2,0x34,0x0c,0x5b,0xe5,0xc0, +0x04,0xa2,0xc2,0x3c,0x0c,0x5b,0x65,0xc0,0x04,0xa2,0xc2,0x44,0x1c,0xeb,0x0c, +0x8c,0xe5,0x6d,0x00,0xa2,0xc2,0x4c,0x1c,0xeb,0x0c,0x8c,0x65,0x6d,0x00,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x38,0x03,0x0c,0x8a,0x0c,0x4b,0xa5,0x3f,0x05,0x5d, +0x0a,0xb8,0x44,0xa5,0xbd,0x04,0x59,0x22,0x0c,0x8a,0x0c,0x4b,0xa5,0x3e,0x05, +0x5d,0x0a,0xf0,0xb3,0x11,0xa5,0xbc,0x04,0x81,0x80,0x45,0x91,0x7e,0x45,0xa1, +0x7c,0x45,0x0c,0x0e,0x39,0x52,0xf8,0x44,0xf9,0x12,0xd8,0x54,0xe9,0x62,0xe9, +0x42,0xd9,0x02,0xc8,0x64,0xc9,0x72,0xb8,0x74,0xb9,0x82,0x59,0x32,0xa9,0x92, +0x99,0xa2,0x89,0xb2,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0xca,0x0c,0x4b,0xe5, +0x3a,0x05,0x49,0x1a,0x39,0x0a,0x59,0x2a,0x91,0x72,0x45,0x99,0x32,0x88,0x25, +0x89,0x42,0xa9,0x02,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0xca,0x0c, +0x4b,0xe5,0x38,0x05,0x59,0x2a,0x39,0x0a,0x49,0x1a,0x1c,0x0b,0xa9,0x02,0xa2, +0xa1,0x90,0xe5,0x37,0x05,0xc8,0x02,0xc8,0x2c,0x3d,0x0a,0xb8,0x6c,0xc8,0x8c, +0xa5,0x7c,0x01,0x1c,0xca,0x0c,0x4b,0xd1,0x64,0x45,0xd2,0x63,0x61,0x39,0x52, +0x25,0x36,0x05,0x3d,0x0a,0x0c,0x4b,0x0c,0x8a,0x65,0x35,0x05,0x5d,0x0a,0xb8, +0x06,0xa5,0xb3,0x04,0x59,0x23,0x0c,0x8a,0x0c,0x4b,0x65,0x34,0x05,0x49,0x0a, +0x69,0x1a,0x1c,0x0b,0xa9,0x03,0xa2,0xa1,0x90,0xa5,0x33,0x05,0x4d,0x0a,0xa5, +0xb7,0x00,0xb8,0x03,0xb8,0x1b,0xad,0x04,0xc8,0x3b,0xb8,0x1b,0x49,0x43,0x25, +0x78,0x01,0x0c,0x8a,0x0c,0x4b,0xc1,0x52,0x45,0xd8,0x06,0xd9,0x33,0xc9,0x53, +0x39,0x62,0x25,0x31,0x05,0x0c,0x4b,0x0c,0x03,0xe1,0x4f,0x45,0xe9,0x1a,0x32, +0x5a,0x00,0xa9,0x42,0x0c,0x4a,0x25,0x30,0x05,0xa9,0x72,0x79,0x32,0x39,0x92, +0xf1,0x4b,0x45,0xf9,0x82,0x1d,0xf0,0x00,0x36,0x41,0x00,0x39,0x02,0xe0,0xa3, +0x11,0x1c,0x0b,0x65,0x30,0x00,0xa9,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41, +0x00,0xad,0x02,0xa5,0x82,0x00,0x0c,0x8a,0x0c,0x4b,0xe5,0x2c,0x05,0x81,0x42, +0x45,0x91,0x40,0x45,0x49,0x1a,0x39,0x0a,0xa9,0x22,0x99,0x42,0x89,0x32,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x82,0x23,0x15,0x39,0x22,0x92,0x04,0x01, +0x99,0x08,0xf2,0x04,0x02,0xf9,0x18,0xe2,0x04,0x03,0xe9,0x28,0xd8,0x14,0xd9, +0x38,0xc8,0x24,0xc9,0x48,0xb8,0x34,0xb9,0xc8,0x0f,0x82,0x08,0xa2,0x44,0x0c, +0x0c,0x11,0x0c,0x7a,0xaf,0x20,0x09,0x22,0x82,0x4a,0x04,0x00,0x4f,0x00,0x0c, +0x2a,0x44,0x0c,0x0c,0x11,0x8f,0x80,0x09,0x22,0x48,0x30,0x24,0x01,0xcb,0xb4, +0xaf,0x00,0xaa,0x49,0x44,0x0c,0x0c,0x11,0x59,0xb8,0xa2,0x04,0x10,0xcf,0x09, +0x84,0x29,0x44,0x0c,0x0c,0x11,0xa6,0x1a,0x15,0x0c,0x07,0x0c,0x06,0x76,0xaa, +0x07,0x58,0xe8,0x5a,0x56,0x79,0x05,0x4b,0x66,0x46,0x01,0x00,0x00,0x00,0x00, +0x00,0x0c,0x0a,0x78,0xe8,0xb0,0x40,0x0c,0x70,0x7a,0xa0,0xaf,0x40,0x64,0x43, +0x44,0x0c,0x0c,0x11,0x97,0xaa,0x20,0xa0,0xc9,0xc0,0x76,0xac,0x17,0xaf,0xe0, +0x0a,0x22,0xa4,0x00,0x0c,0x00,0x1f,0xec,0x23,0x00,0x44,0x0c,0x0c,0x11,0x2f, +0x2f,0x44,0x48,0x30,0x0c,0x08,0x10,0x82,0x23,0x15,0x8f,0x80,0x09,0x22,0x44, +0x0c,0x0c,0x11,0xaf,0x80,0x09,0x22,0x44,0x0c,0x0c,0x11,0xc8,0xa8,0xb8,0x68, +0xa8,0x88,0x2f,0x72,0xd0,0x22,0x30,0x1c,0x2c,0x02,0x0c,0x07,0x8d,0x0c,0x76, +0xa9,0x59,0x0f,0x20,0xa1,0x42,0xc0,0x00,0x81,0x08,0x76,0x00,0x04,0x87,0xbc, +0x01,0x0c,0x19,0xac,0x19,0xd2,0x04,0x02,0xd2,0xcd,0xfe,0xaf,0xae,0x13,0x62, +0xf4,0x10,0x0e,0x0a,0x1b,0x77,0xc6,0x03,0x00,0x2f,0x80,0x01,0x22,0x44,0x0c, +0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa8,0x10,0x00,0x12,0xaf,0xe0,0x0a,0x22,0xe0, +0x20,0x87,0x08,0xaf,0xe0,0x0a,0x22,0x44,0x2c,0x10,0x11,0x8f,0xf0,0x00,0x82, +0xd0,0x20,0x97,0x09,0x4b,0x88,0x10,0x8b,0x8d,0x2f,0x35,0x42,0x49,0xf4,0x00, +0x86,0x0a,0x82,0x23,0x15,0x89,0x32,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00, +0xad,0x02,0xb2,0x26,0x10,0xe5,0x0a,0x00,0x8b,0xa2,0xb8,0x14,0xc8,0x24,0xe5, +0x08,0x00,0xa2,0xc2,0x14,0xb8,0x14,0xc8,0x24,0x65,0x08,0x00,0xa2,0xc2,0x20, +0xb8,0x14,0x1c,0x0c,0xa5,0x42,0x00,0xa2,0xc2,0x30,0x0c,0x08,0x89,0xb2,0x89, +0xa2,0xb8,0x14,0xa5,0x93,0x04,0xb8,0x14,0xa2,0xc2,0x38,0x25,0x93,0x04,0x3c, +0xca,0x1c,0x0b,0x25,0x14,0x05,0x3d,0x0a,0xb2,0x07,0x01,0xa2,0xca,0x14,0xe5, +0x91,0x04,0xa2,0xc3,0x1c,0xb2,0x07,0x01,0x65,0x91,0x04,0xa2,0xc3,0x24,0xb2, +0x07,0x01,0x65,0xe3,0xff,0xb2,0x07,0x01,0xa2,0xc3,0x34,0x25,0x90,0x04,0x32, +0x62,0x15,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x8a,0x1c,0x0b,0xe5,0x10,0x05,0x81, +0xd3,0x44,0x91,0xd1,0x44,0x49,0x1a,0x39,0x0a,0xa9,0x02,0x99,0x22,0x89,0x32, +0x1d,0xf0,0x36,0x41,0x00,0x39,0x02,0x49,0x12,0x59,0x22,0x59,0x32,0x69,0x42, +0x79,0x52,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x39,0x02,0x49,0x12,0x1c, +0x0b,0x40,0xa3,0x82,0xe0,0xaa,0x11,0x65,0x0f,0x00,0xa9,0x22,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0xad,0x03,0x39,0x02,0x1c,0x0b,0x25,0x0e,0x00,0xa9,0x12, +0x1d,0xf0,0x36,0x41,0x00,0x68,0x63,0x0c,0x8a,0x0c,0x4b,0x25,0x0b,0x05,0x49, +0x1a,0x39,0x0a,0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0x65,0x0a,0x05,0x3d,0x0a,0xbd, +0x06,0x65,0x88,0x04,0x39,0x42,0xc8,0x02,0x0c,0x09,0x76,0xa6,0x0f,0xa8,0x42, +0x88,0x02,0xa8,0x1a,0x88,0x18,0xaa,0xa9,0x88,0x38,0x4b,0x99,0x89,0x0a,0xc8, +0x1c,0xb1,0xb2,0x44,0xc8,0x0c,0xc9,0x32,0x59,0x22,0xb9,0x52,0x1d,0xf0,0x36, +0x41,0x00,0x79,0x42,0x69,0x32,0x0c,0xca,0x0c,0x4b,0xa5,0x06,0x05,0x59,0x2a, +0x49,0x1a,0x39,0x0a,0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0xa5,0x05,0x05,0x3d,0x0a, +0xa5,0x5a,0x00,0x39,0x72,0x0c,0x8a,0x0c,0x4b,0xa5,0x04,0x05,0x3d,0x0a,0xa5, +0x59,0x00,0x39,0x82,0x81,0xa4,0x44,0x91,0xa2,0x44,0x0c,0x1a,0xa9,0x62,0x99, +0x92,0x89,0xa2,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x39,0x02,0x49,0x12,0x59, +0x22,0x79,0x62,0xa2,0xc2,0x40,0x0c,0x4b,0x65,0x80,0x04,0x0c,0x8a,0x0c,0x4b, +0xa5,0x01,0x05,0x3d,0x0a,0x65,0x56,0x00,0x32,0x62,0x12,0x0c,0x8a,0x0c,0x4b, +0xa5,0x00,0x05,0x3d,0x0a,0xa5,0x55,0x00,0x32,0x62,0x13,0x0c,0x8a,0x0c,0x4b, +0xa5,0xff,0x04,0x3d,0x0a,0xa5,0x54,0x00,0x32,0x62,0x14,0x69,0x52,0x81,0x91, +0x44,0x91,0x8f,0x44,0x92,0x62,0x16,0x82,0x62,0x17,0x1d,0xf0,0x36,0x41,0x00, +0x66,0xb3,0x08,0xad,0x02,0xe5,0x68,0xff,0x2d,0x0a,0x1d,0xf0,0x66,0x43,0x08, +0xad,0x02,0x65,0x61,0xff,0x2d,0x0a,0x1d,0xf0,0xad,0x02,0x25,0x5a,0xff,0x2d, +0x0a,0x1d,0xf0,0x36,0x41,0x00,0x39,0x02,0x49,0x12,0x59,0x22,0x69,0x32,0x79, +0x42,0xa2,0xc2,0x1c,0x88,0x91,0x98,0x81,0x99,0x52,0x89,0x62,0x65,0x4f,0x00, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xa1,0x6a,0x44,0x1c,0x0b,0xa2,0x2a, +0x1c,0xa9,0x02,0xe5,0xfa,0xff,0xa9,0x12,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x8a, +0x0c,0x4b,0x25,0xf8,0x04,0x81,0x76,0x44,0x49,0x1a,0x39,0x0a,0xa9,0x02,0x89, +0x22,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0xa5,0xf6,0x04,0x49, +0x1a,0x39,0x0a,0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0xa5,0xf5,0x04,0x4d,0x0a,0xb8, +0x63,0xe5,0x73,0x04,0x49,0x32,0x0c,0x09,0x88,0x43,0xa1,0x5c,0x44,0x76,0xa8, +0x07,0xb8,0x14,0xba,0xb9,0xa9,0x0b,0x4b,0x99,0xc1,0x67,0x44,0xc9,0x42,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0xe5,0xf2,0x04,0x81, +0x65,0x44,0x91,0x63,0x44,0xb1,0x62,0x44,0x49,0x1a,0x39,0x0a,0x59,0x32,0x69, +0x42,0xa9,0x02,0xb9,0x52,0xb9,0x62,0x99,0x72,0x89,0x82,0x0c,0x0a,0xa9,0x12, +0x1d,0xf0,0x00,0x36,0x41,0x00,0x79,0x42,0xa2,0xc2,0x18,0x25,0x1b,0x00,0xa2, +0xc2,0x20,0xe5,0x1a,0x00,0xa2,0xc2,0x28,0x65,0x1a,0x00,0xa2,0xc2,0x30,0x25, +0x44,0x00,0xa2,0xc2,0x38,0xa5,0x43,0x00,0xa2,0xc2,0x58,0x65,0x43,0x00,0x39, +0x02,0x49,0x12,0x59,0x22,0x69,0x32,0x81,0x56,0x44,0x91,0x55,0x44,0xa1,0x53, +0x44,0xb1,0x51,0x44,0xc1,0x4f,0x44,0xd1,0x4e,0x44,0xd2,0x62,0x1b,0xc2,0x62, +0x1c,0xb2,0x62,0x1d,0xa2,0x62,0x20,0x92,0x62,0x1f,0x82,0x62,0x1e,0x1d,0xf0, +0x00,0x36,0x41,0x00,0x0c,0x4a,0x0c,0x4b,0xa5,0xea,0x04,0x81,0x4b,0x44,0x39, +0x0a,0xa9,0x02,0x49,0x32,0x89,0x42,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02, +0xb8,0x63,0xa5,0x67,0x04,0x0c,0x8a,0x0c,0x4b,0xa5,0xe8,0x04,0x81,0x44,0x44, +0x49,0x1a,0x39,0x0a,0xa9,0x22,0x89,0x32,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0x0c,0x8a,0x0c,0x4b,0x25,0xe7,0x04,0x81,0x3f,0x44,0x49,0x1a,0x39,0x0a,0xa9, +0x02,0x89,0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0xa5,0xe5, +0x04,0x81,0x3a,0x44,0x49,0x1a,0x39,0x0a,0xa9,0x02,0x89,0x12,0x1d,0xf0,0x00, +0x36,0x81,0x00,0x39,0x41,0xa2,0xc2,0x18,0xb2,0x24,0x15,0xc2,0x24,0x14,0x3b, +0xbb,0x0b,0xcc,0xc0,0xc2,0x21,0xb0,0xb2,0x21,0xc0,0xbb,0xc0,0x65,0x17,0x00, +0xa2,0xc2,0x20,0xa5,0xe8,0xff,0xa2,0xc2,0x28,0x65,0x37,0x00,0xa2,0xc2,0x30, +0xe5,0x36,0x00,0x2c,0x4a,0x1c,0x0b,0x25,0xe1,0x04,0xf2,0x24,0x1f,0xe2,0x24, +0x1d,0xd2,0x24,0x20,0xc2,0x24,0x1e,0xb2,0x24,0x24,0x82,0x24,0x21,0x89,0x01, +0x32,0x24,0x22,0x39,0x11,0x3d,0x0a,0xa5,0xe3,0xff,0x39,0xe2,0x2c,0x4a,0x1c, +0x0b,0x0c,0x09,0x99,0xf2,0xa5,0xde,0x04,0xf2,0x24,0x27,0xe2,0x24,0x25,0xd2, +0x24,0x28,0xc2,0x24,0x26,0xb2,0x24,0x2c,0x82,0x24,0x29,0x89,0x01,0x32,0x24, +0x2a,0x39,0x11,0x3d,0x0a,0xe5,0xe0,0xff,0x32,0x62,0x10,0x72,0x62,0x13,0x62, +0x62,0x12,0x1c,0x0a,0x1c,0x0b,0x92,0x21,0x10,0x92,0x62,0x18,0x65,0xdb,0x04, +0xb1,0x13,0x44,0xc1,0x11,0x44,0x0c,0x0d,0xf8,0x26,0xe8,0x41,0x50,0xff,0xa0, +0xf8,0x0f,0x59,0x3a,0xf9,0x2a,0x49,0x1a,0xe9,0x0a,0xd2,0x62,0x14,0xc2,0x62, +0x15,0xa2,0x62,0x11,0xb2,0x62,0x16,0xa1,0x0b,0x44,0xa2,0x62,0x17,0x1d,0xf0, +0x00,0x36,0x41,0x00,0x0c,0xca,0x0c,0x4b,0xe5,0xd7,0x04,0x59,0x2a,0x49,0x1a, +0x39,0x0a,0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0xe5,0xd6,0x04,0x3d,0x0a,0xe5,0x2b, +0x00,0xb8,0x02,0x39,0x72,0xb8,0x1b,0x88,0xf7,0xa8,0x3b,0xb8,0x1b,0xe0,0x08, +0x00,0xa9,0x62,0x69,0x22,0xc1,0xfd,0x43,0xc9,0x82,0x1d,0xf0,0x36,0x41,0x00, +0xa1,0xd6,0x43,0x1c,0x0b,0xa2,0x2a,0x1c,0xa9,0x02,0xd0,0xaa,0x11,0xa5,0xd5, +0xff,0xa9,0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x04,0x39,0x02,0xf0,0xa3, +0x11,0xa5,0xd4,0xff,0xa9,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x39, +0x02,0xd0,0xa3,0x11,0x1c,0x0b,0x65,0xd3,0xff,0xa9,0x12,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0xa2,0xc2,0x14,0xa5,0x25,0x00,0xa2,0xc2,0x1c,0x25,0x25, +0x00,0xa2,0xc2,0x24,0xe5,0xfa,0xff,0x0c,0x8a,0x0c,0x4b,0x25,0xcf,0x04,0x81, +0xe6,0x43,0x0c,0x09,0x49,0x1a,0x39,0x0a,0xa9,0x02,0x99,0x22,0x89,0xb2,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xcb,0xa2,0xbd,0x03,0x1c,0x0c,0xe5,0xf9, +0xff,0x98,0x42,0x82,0x24,0x14,0x89,0x22,0x59,0xf2,0x99,0x02,0x90,0xa3,0x90, +0xa2,0xca,0xfe,0xa9,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x03, +0x39,0x02,0x1c,0x0b,0xe5,0xcc,0xff,0xa9,0x12,0x1d,0xf0,0x36,0x41,0x00,0x0c, +0x8a,0x0c,0x4b,0x25,0xca,0x04,0x81,0xd2,0x43,0x49,0x1a,0x39,0x0a,0xa9,0x12, +0x89,0x22,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0xca,0x0c,0x4b,0xa5,0xc8,0x04, +0x0c,0x19,0xf8,0x75,0xc8,0x05,0x49,0x1a,0x39,0x0a,0x59,0x2a,0xf9,0x52,0xe8, +0x65,0xe9,0x62,0x92,0x62,0x10,0x0c,0x0e,0xe9,0xe2,0xe9,0xc2,0xe9,0xd2,0xe9, +0xb2,0xe9,0xf2,0xd2,0x25,0x10,0xd9,0x72,0xb2,0x25,0x11,0xb9,0x82,0x88,0x25, +0x82,0x62,0x11,0xf2,0x25,0x12,0xf9,0x92,0xd2,0x25,0x13,0xe2,0x62,0x19,0xe2, +0x62,0x17,0xe2,0x62,0x18,0xe2,0x62,0x16,0xe2,0x62,0x1a,0xd9,0xa2,0x92,0x62, +0x1b,0xb8,0xa5,0x8f,0x64,0x25,0x82,0x02,0x0f,0x02,0x00,0xb0,0x04,0x03,0x88, +0xb5,0x82,0x62,0x13,0xb0,0xb0,0x04,0x81,0xb5,0x43,0xf8,0x15,0xf2,0x62,0x1c, +0xe8,0xc5,0xe2,0x62,0x14,0xd8,0xd5,0xd2,0x62,0x15,0x69,0x32,0xb2,0x42,0x11, +0x92,0x42,0x10,0xa9,0x02,0x82,0x62,0x1d,0x1d,0xf0,0x36,0x41,0x00,0x1c,0x0b, +0x0c,0x08,0x91,0x8b,0x43,0xa8,0x05,0x39,0x02,0x49,0x12,0xa9,0x22,0x99,0x62, +0xa2,0xa1,0x90,0x82,0x52,0x0a,0x48,0x05,0x65,0xbe,0x04,0x3d,0x0a,0x65,0x42, +0x00,0xad,0x03,0x0c,0x05,0x39,0x72,0xb8,0x04,0xc8,0x24,0x25,0x03,0x01,0x59, +0x92,0x69,0x42,0x0c,0x1b,0xad,0x02,0xb9,0x82,0xbd,0x07,0xe5,0xcd,0x00,0x1d, +0xf0,0x00,0x00,0x36,0x61,0x00,0x69,0x01,0x0c,0x8a,0x0c,0x4b,0x65,0xbb,0x04, +0x0c,0x8b,0x98,0x43,0x49,0x1a,0x39,0x0a,0xa9,0x82,0x99,0x02,0x2c,0x8a,0x65, +0xba,0x04,0x7d,0x0a,0xbd,0x03,0x65,0x3c,0x00,0x79,0x12,0x2c,0x8a,0x0c,0x8b, +0x65,0xb9,0x04,0x7d,0x0a,0xbd,0x03,0x65,0x3b,0x00,0x79,0x22,0x1c,0x4a,0x0c, +0x4b,0x65,0xb8,0x04,0x7d,0x0a,0xb8,0xf4,0xc2,0x24,0x1e,0x25,0x39,0x00,0x79, +0x32,0x2c,0x8a,0x0c,0x8b,0x25,0xb7,0x04,0x7d,0x0a,0xbd,0x03,0x25,0x39,0x00, +0x79,0x42,0x1c,0x4a,0x0c,0x4b,0x25,0xb6,0x04,0x7d,0x0a,0xb8,0xf4,0xc2,0x24, +0x1e,0x25,0x37,0x00,0x79,0x52,0xa8,0x03,0x3c,0x2b,0x25,0x8f,0x00,0x0c,0x8b, +0x82,0x25,0x13,0x68,0xf4,0x88,0x08,0x68,0x06,0xaa,0x88,0x4c,0x0a,0x80,0x66, +0x90,0xa5,0xb3,0x04,0xcd,0x05,0xbd,0x06,0x7d,0x0a,0xd8,0x01,0x25,0xe5,0xff, +0x79,0x62,0x3c,0x0a,0x0c,0x4b,0x65,0xb2,0x04,0xbd,0x03,0xc8,0xc4,0x3d,0x0a, +0x25,0xe1,0xff,0x39,0x72,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0xca, +0x0c,0x4b,0xe5,0xb0,0x04,0x59,0x2a,0x49,0x1a,0x39,0x0a,0x1c,0x0b,0xa9,0x02, +0xa2,0xa1,0x90,0xe5,0xaf,0x04,0x3d,0x0a,0xa5,0x33,0x00,0xb8,0x02,0xb8,0x2b, +0xad,0x03,0xc8,0x2b,0xb8,0x0b,0x39,0x32,0x65,0xf4,0x00,0x1d,0xf0,0x36,0x41, +0x00,0x0c,0x8a,0x0c,0x4b,0xe5,0xad,0x04,0x5d,0x0a,0xbd,0x04,0xe5,0x2b,0x04, +0x59,0x02,0xe0,0xa4,0x11,0x1c,0x0b,0xa5,0xae,0xff,0x2d,0x0a,0x0c,0x4b,0x0c, +0x8a,0x25,0xac,0x04,0x29,0x1a,0x49,0x0a,0xa9,0x03,0x1d,0xf0,0x36,0x41,0x00, +0x21,0x31,0x43,0x22,0x22,0x18,0x1d,0xf0,0x00,0x36,0x41,0x00,0xa1,0x2e,0x43, +0x1c,0x0b,0xa2,0x2a,0x1c,0xa9,0x02,0xe0,0xaa,0x11,0xa5,0xab,0xff,0xa9,0x12, +0x1d,0xf0,0x00,0x36,0x81,0x00,0x39,0x92,0x49,0xa2,0x59,0xb2,0x69,0xc2,0x79, +0xd2,0x5c,0x8a,0x0c,0x4b,0x82,0x21,0x11,0x92,0x21,0x10,0x99,0x41,0x99,0xe2, +0x89,0x51,0x89,0xf2,0x65,0xa7,0x04,0xfd,0x07,0xed,0x06,0xdd,0x05,0xc8,0x41, +0xb8,0x51,0xb9,0x11,0xc9,0x01,0xbd,0x03,0xcd,0x04,0x3d,0x0a,0xa5,0x8d,0xff, +0x39,0x02,0x1c,0x0a,0x0c,0x4b,0x65,0xa5,0x04,0x0c,0x4b,0xd8,0x02,0xe8,0x92, +0xe9,0x3a,0xd9,0x2a,0xa9,0x22,0x1c,0x0a,0x25,0xa4,0x04,0x0c,0x4b,0xf8,0x02, +0x88,0xa2,0x89,0x3a,0xf9,0x2a,0xa9,0x32,0x1c,0x0a,0x25,0xa3,0x04,0x98,0x02, +0xb8,0xb2,0xb9,0x3a,0x99,0x2a,0x0c,0x4b,0xa9,0x42,0x1c,0x4a,0x25,0xa2,0x04, +0x0c,0x4b,0xc8,0x02,0xd8,0xc2,0xd9,0x3a,0xc9,0x2a,0xa9,0x52,0x1c,0x0a,0x25, +0xa1,0x04,0x3d,0x0a,0xb8,0x02,0xc8,0xd2,0xe5,0x74,0xff,0x39,0x62,0x1c,0x8a, +0x0c,0x4b,0xe5,0x9f,0x04,0x3d,0x0a,0xb8,0xf2,0xc8,0xe2,0xa5,0x71,0xff,0x39, +0x72,0x1c,0x8a,0x0c,0x4b,0xe5,0x9e,0x04,0x3d,0x0a,0xb8,0xf2,0xc8,0xe2,0x65, +0x70,0xff,0x81,0x28,0x43,0xa1,0x26,0x43,0x39,0x82,0xd8,0x32,0xb8,0x42,0x98, +0x52,0xf8,0x22,0xe1,0x21,0x43,0xc1,0x21,0x43,0xe9,0x0f,0xe1,0x23,0x43,0xf8, +0x62,0xc9,0x0d,0xa9,0x0b,0x89,0x09,0xe9,0x0f,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0x0c,0x8a,0x0c,0x4b,0x25,0x9b,0x04,0x81,0x1d,0x43,0x49,0x1a,0x39,0x0a, +0xa9,0x02,0x89,0x12,0x1d,0xf0,0x00,0x36,0x61,0x00,0x79,0x32,0xa2,0xc2,0x10, +0xa5,0xee,0xff,0xa2,0xc2,0x18,0x65,0xee,0xff,0xa2,0xc2,0x20,0xe5,0xed,0xff, +0xa2,0xc2,0x28,0x0c,0x2b,0xa5,0x16,0x04,0xa2,0xc2,0x30,0xb2,0x05,0xc5,0xc2, +0x05,0xc4,0x00,0xbb,0x23,0x00,0xcc,0x23,0xe5,0x88,0xff,0xa2,0xc2,0x3c,0xb2, +0x05,0xc5,0xc2,0x05,0xc4,0x00,0xbb,0x23,0x00,0xcc,0x23,0xa5,0x87,0xff,0xa2, +0xc2,0x48,0xe5,0xea,0xff,0xa2,0xc2,0x50,0x65,0xea,0xff,0x1c,0x8a,0x0c,0x4b, +0x78,0xe4,0xc8,0xf4,0xd8,0xd4,0xd9,0x01,0xc9,0x11,0x42,0x23,0x13,0xe5,0x93, +0x04,0xfd,0x07,0xbd,0x05,0x3d,0x0a,0xcd,0x06,0xd8,0x01,0xe8,0x11,0xa5,0x83, +0xff,0x1c,0x0a,0xe8,0x13,0x0c,0x4b,0xe8,0x7e,0xe2,0x62,0x1c,0x39,0x02,0x25, +0x92,0x04,0xcd,0x04,0xbd,0x06,0x3d,0x0a,0x25,0x80,0xff,0x39,0x22,0x81,0xf7, +0x42,0xf1,0xf8,0x42,0x98,0xc1,0xa1,0xfb,0x42,0xb1,0xfa,0x42,0xc1,0xf8,0x42, +0xd1,0xf6,0x42,0xe1,0xf4,0x42,0xe2,0x62,0x28,0xd2,0x62,0x29,0xc2,0x62,0x2a, +0xb2,0x62,0x2b,0xa2,0x62,0x2c,0x92,0x62,0x25,0xf2,0x62,0x27,0x82,0x62,0x26, +0xf1,0xf5,0x42,0x81,0xf3,0x42,0x91,0xf1,0x42,0x92,0x62,0x2d,0x82,0x62,0x2e, +0xf2,0x62,0x2f,0x1d,0xf0,0x36,0x41,0x00,0x59,0xa2,0x0c,0xca,0x0c,0x4b,0x65, +0x8c,0x04,0x5d,0x0a,0x0c,0x1b,0x65,0x0a,0x04,0x59,0xd2,0x1c,0x0a,0x0c,0x4b, +0x65,0x8b,0x04,0x81,0xec,0x42,0x91,0xea,0x42,0xb8,0xd2,0xb9,0x2a,0x49,0x1a, +0x39,0x0a,0x99,0x82,0xa9,0x02,0x89,0x92,0xa1,0xe5,0x42,0xa9,0x72,0x1d,0xf0, +0x00,0x36,0x41,0x00,0xcb,0xa2,0xb2,0x24,0x17,0x65,0x07,0x04,0xa2,0xc2,0x14, +0xe5,0xdd,0xff,0xa2,0xc2,0x1c,0x65,0xdd,0xff,0xa2,0xc2,0x24,0xb8,0x63,0xe5, +0x7a,0xff,0x0c,0xca,0x0c,0x4b,0x65,0x87,0x04,0x81,0xdf,0x42,0x91,0xdd,0x42, +0xb1,0xdb,0x42,0x59,0x2a,0x49,0x1a,0x39,0x0a,0xa9,0x12,0xb9,0xb2,0x99,0xc2, +0x89,0xe2,0xa1,0xd7,0x42,0xa9,0xd2,0x1d,0xf0,0x36,0x41,0x00,0x8b,0xa2,0xb8, +0x24,0x65,0x03,0x04,0xa2,0xc2,0x10,0xb8,0x24,0xe5,0x02,0x04,0xa2,0xc2,0x18, +0xb8,0x24,0x65,0x02,0x04,0x0c,0xca,0x0c,0x4b,0x65,0x83,0x04,0x81,0xd4,0x42, +0x91,0xd3,0x42,0xb1,0xd0,0x42,0xc1,0xce,0x42,0x59,0x2a,0x49,0x1a,0x39,0x0a, +0xa9,0x02,0xc9,0x82,0xb9,0x92,0x99,0xa2,0x89,0xb2,0xa1,0xcb,0x42,0xa9,0xc2, +0x1d,0xf0,0x36,0x41,0x00,0x59,0x42,0x0c,0x8a,0x0c,0x4b,0x65,0x80,0x04,0x49, +0x1a,0x39,0x0a,0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0xa5,0x7f,0x04,0x3d,0x0a,0xa5, +0xd4,0xff,0x39,0x32,0x0c,0x08,0x89,0x22,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0x39,0x02,0x51,0xc1,0x42,0x49,0x12,0x59,0x42,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0xc8,0xe3,0xb8,0x33,0x8b,0xa2,0xca,0xbb,0x1b,0xbb,0xa5,0xaa,0xff,0x39, +0x82,0xd1,0xbb,0x42,0xd9,0x92,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x31, +0x78,0x42,0x32,0x62,0x61,0x1d,0xf0,0x00,0x36,0x41,0x00,0x39,0x02,0x1c,0x4a, +0x0c,0x4b,0x65,0x7a,0x04,0xf0,0xc3,0x11,0x49,0x0a,0x59,0x2a,0x7d,0x0a,0xcb, +0xb7,0x4b,0xaa,0x25,0xcb,0xff,0xcd,0x07,0x81,0xb0,0x42,0xa1,0xae,0x42,0x91, +0xb0,0x42,0x69,0x47,0x79,0x12,0xb8,0x02,0x99,0x42,0xa9,0x22,0x89,0x32,0xad, +0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0x25,0xcc, +0xff,0x0c,0x8a,0x0c,0x4b,0x65,0x76,0x04,0x49,0x1a,0x39,0x0a,0xa9,0x22,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x0c,0xca,0x0c,0x4b,0x65,0x75,0x04,0x0c,0x4b,0x88, +0xf4,0x98,0x64,0x99,0x2a,0x89,0x1a,0x39,0x0a,0xa9,0x02,0x3c,0x0a,0x25,0x74, +0x04,0x5d,0x0a,0xbd,0x03,0xc8,0xf4,0xd8,0x84,0xe8,0x54,0xfd,0x06,0xe5,0x39, +0xff,0x59,0x42,0x1c,0x4a,0x0c,0x4b,0xa5,0x72,0x04,0xc8,0xf4,0xbd,0x03,0xd8, +0x94,0x3d,0x0a,0xd0,0xd7,0xa0,0xd8,0x0d,0x65,0x36,0xff,0x39,0x52,0x3c,0x0a, +0x0c,0x4b,0x25,0x71,0x04,0x3d,0x0a,0xb8,0xf4,0xc8,0x64,0x25,0x30,0xff,0x39, +0x62,0x0c,0x4a,0x0c,0x4b,0xe5,0x6f,0x04,0xa9,0x72,0x0c,0x4b,0x0c,0x4a,0x65, +0x6f,0x04,0xe1,0x8b,0x42,0xf1,0x8a,0x42,0x69,0x32,0xa9,0x82,0x88,0x64,0x0c, +0x0a,0xa9,0x92,0x98,0x78,0x99,0xa2,0x98,0x52,0x88,0x98,0x89,0x49,0xf9,0xb2, +0xe9,0xc2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xc8,0x44,0xb8,0x05,0x4b, +0xa2,0xca,0xbb,0x1b,0xbb,0xa5,0xea,0x03,0x0c,0xca,0x0c,0x4b,0xa5,0x6b,0x04, +0xd1,0x7f,0x42,0xe1,0x7d,0x42,0x59,0x2a,0x49,0x1a,0x39,0x0a,0xa9,0x32,0xe9, +0x52,0xd9,0x62,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0xe5,0x69, +0x04,0x0c,0x8b,0x88,0x43,0x49,0x1a,0x39,0x0a,0xa9,0x32,0x89,0x02,0x2c,0x8a, +0xa5,0x68,0x04,0xbd,0x03,0x5d,0x0a,0xe5,0xea,0xff,0x59,0x12,0x1c,0x4a,0x0c, +0x4b,0xa5,0x67,0x04,0xb8,0xf4,0xc2,0x24,0x1e,0x3d,0x0a,0xa5,0xe8,0xff,0x39, +0x22,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x1c,0x0a,0x0c,0x4b,0x25,0x66, +0x04,0x81,0x6a,0x42,0x91,0x68,0x42,0x39,0x3a,0x49,0x2a,0x0c,0x0b,0xb9,0x1a, +0xb9,0x0a,0xa9,0x02,0x59,0x22,0x99,0xb2,0x89,0xc2,0x1d,0xf0,0x36,0x41,0x00, +0xc8,0x05,0xb8,0x04,0xad,0x02,0xc0,0xbb,0xc0,0xe5,0xe1,0x03,0x69,0x42,0x0c, +0xca,0x0c,0x4b,0xe5,0x62,0x04,0xd1,0x60,0x42,0xe1,0x5e,0x42,0x59,0x2a,0x49, +0x1a,0x39,0x0a,0xa9,0x22,0xe9,0x52,0xd9,0x62,0x1d,0xf0,0x36,0x41,0x00,0x0c, +0x8a,0x0c,0x4b,0x25,0x61,0x04,0x39,0x0a,0x49,0x1a,0x1c,0x0b,0xa9,0x02,0xa2, +0xa1,0x90,0x25,0x60,0x04,0x3d,0x0a,0x25,0xe4,0xff,0xad,0x03,0x39,0x12,0xb8, +0x04,0xc8,0x24,0xe5,0xa4,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x59,0x12, +0x0c,0x8a,0x0c,0x4b,0x25,0x5e,0x04,0x49,0x1a,0x39,0x0a,0x1c,0x0b,0xa9,0x02, +0xa2,0xa1,0x90,0x65,0x5d,0x04,0x4d,0x0a,0x25,0xe1,0xff,0xad,0x02,0x0c,0x1b, +0x88,0x03,0x49,0x32,0x89,0x22,0x25,0x94,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0x0c,0x8a,0x1c,0x0b,0x68,0x33,0x98,0x43,0x68,0x76,0x88,0x69,0x38,0x89, +0x88,0x38,0x89,0x62,0x65,0x5a,0x04,0x1c,0x0b,0x1c,0xc8,0x4d,0x0a,0x89,0x0a, +0x3c,0x8a,0xa5,0x5b,0xff,0xb8,0x16,0xd8,0x06,0xc8,0x0b,0xa9,0x14,0x49,0x02, +0xe8,0x0d,0xd9,0x72,0x98,0x63,0xe9,0x82,0xa8,0x09,0xc9,0xb2,0x99,0x92,0xa9, +0xa2,0xb9,0xc2,0x5c,0x4a,0x1c,0x0b,0x65,0x57,0x04,0x4d,0x0a,0xb8,0xb2,0xe5, +0x10,0xff,0x5c,0x4a,0xf8,0x83,0x1c,0x0b,0x88,0x0f,0xf9,0xe2,0x49,0x12,0x89, +0xd2,0xe5,0x55,0x04,0x3d,0x0a,0xb8,0xd2,0x65,0x0f,0xff,0x39,0x22,0x52,0x62, +0x10,0x4c,0x09,0x50,0x99,0xc0,0x92,0x62,0x11,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0x21,0xd4,0x41,0x0c,0x09,0x82,0x22,0x1a,0x92,0x62,0x17,0xe0,0x08,0x00, +0xa2,0x62,0x18,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x31,0xce,0x41,0x0c,0x12, +0x22,0x63,0x17,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x4d,0x02,0x8c,0x33, +0x2d,0x03,0x06,0x01,0x00,0x25,0x59,0x04,0x2d,0x0a,0xe5,0xfd,0xff,0x51,0xc6, +0x41,0x1c,0xca,0xb2,0x25,0x10,0x25,0x53,0x04,0x6d,0x0a,0x0c,0x0b,0x65,0x78, +0x0a,0x62,0x65,0x10,0xe5,0xfa,0xff,0xa2,0x25,0x10,0xbd,0x02,0xe5,0x7a,0x02, +0xa5,0x59,0x04,0x52,0x25,0x10,0x58,0x55,0x50,0x5a,0xc0,0x59,0x24,0xcc,0x33, +0xad,0x02,0xa5,0x4f,0x04,0x0c,0x09,0x0c,0x18,0x89,0x04,0x90,0x95,0x53,0x99, +0x14,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x1c,0xf5,0x6f,0xe6,0x00,0x22, +0x44,0x0c,0x0c,0x11,0x0c,0x18,0x61,0x03,0x42,0x80,0x00,0xf3,0x60,0x62,0xa0, +0x62,0x26,0x7f,0xef,0xec,0x00,0x22,0x42,0x09,0x04,0x00,0xaf,0xe0,0x0a,0x22, +0xa4,0x00,0x80,0x00,0xaf,0xe0,0x0a,0x22,0x40,0x00,0x01,0x01,0x4f,0x00,0x04, +0x28,0x44,0x0c,0x0c,0x11,0x80,0x04,0x0d,0x1d,0xf0,0x36,0x41,0x00,0x30,0x52, +0x21,0x7c,0xf6,0x0c,0x19,0x1c,0xfa,0x82,0xa0,0x20,0x40,0x88,0xc0,0x40,0xaa, +0xc0,0x00,0x1a,0x40,0x42,0xa0,0x00,0x00,0x99,0xa1,0x6f,0xf3,0x00,0x22,0x44, +0x0c,0x0c,0x11,0x00,0x18,0x40,0xcf,0x4c,0x01,0x22,0x02,0x29,0x04,0x00,0x4f, +0x01,0x04,0x29,0x44,0x0c,0x0c,0x11,0xef,0xec,0x00,0x22,0x44,0x0c,0x0c,0x11, +0xcf,0x00,0x84,0x28,0x44,0x0c,0x0c,0x11,0x76,0xa5,0x35,0x20,0x08,0x0c,0xaf, +0xe0,0x0a,0x22,0xf4,0x00,0x06,0x09,0xaf,0xe0,0x0a,0x22,0x02,0x01,0x04,0x11, +0xaf,0xe0,0x0a,0x22,0x02,0x01,0x05,0x11,0xaf,0xe0,0x0a,0x22,0x02,0x01,0x06, +0x11,0xaf,0xe0,0x0a,0x22,0x02,0x01,0x07,0x11,0x1f,0x02,0x03,0x60,0x44,0x0c, +0x0c,0x11,0x30,0x02,0x8d,0x1d,0xf0,0x36,0x41,0x00,0x3d,0xf0,0x76,0x94,0x04, +0x32,0x42,0x00,0x1b,0x22,0x1d,0xf0,0x00,0x36,0x41,0x00,0x61,0x7f,0x41,0x48, +0xd6,0x38,0xc6,0x1b,0x84,0x4a,0x33,0x32,0x03,0x00,0x39,0x02,0x0c,0x72,0x8c, +0x03,0x89,0xd6,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x03,0x0c,0x14,0x71,0x77, +0x41,0x51,0xc9,0x41,0x59,0xc7,0x52,0x05,0x00,0x59,0x02,0x0c,0x72,0x50,0x43, +0x83,0x49,0xd7,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xb8,0x02,0x00,0xab, +0x23,0xb0,0xb8,0x74,0xe5,0xaa,0x05,0x0c,0x7c,0x0c,0x82,0xa0,0x2c,0x83,0x1d, +0xf0,0x00,0x36,0x41,0x00,0xbd,0x02,0xa8,0x02,0x65,0xb4,0x05,0x0c,0x88,0x0c, +0x72,0xa0,0x28,0xa3,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x13,0x51,0x64,0x41, +0x4d,0x02,0x58,0x35,0x58,0x35,0x0c,0x02,0x50,0x23,0x83,0x29,0x04,0x0c,0x72, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x51,0x5e,0x41,0x0c,0x02,0x52,0x25, +0x10,0x38,0x35,0x58,0x45,0x48,0x45,0x58,0x55,0x38,0x33,0x29,0x95,0x29,0x94, +0x29,0x93,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xa8,0x02,0x65,0xce,0x04, +0x81,0x55,0x41,0x0c,0x1a,0x88,0x08,0x1c,0x9b,0x88,0xf8,0x7c,0xfc,0xe0,0x08, +0x00,0x0c,0x72,0x1d,0xf0,0x36,0x41,0x00,0xb8,0x02,0x00,0xab,0x23,0xb0,0xb8, +0x74,0x25,0x9f,0x05,0x0c,0x7c,0x0c,0x82,0xa0,0x2c,0x83,0x1d,0xf0,0x00,0x36, +0x41,0x00,0xbd,0x02,0xa8,0x02,0x65,0xaa,0x05,0x0c,0x88,0x0c,0x72,0xa0,0x28, +0xa3,0x1d,0xf0,0x00,0x36,0x61,0x00,0x51,0x44,0x41,0x52,0x25,0x10,0x48,0x02, +0x9c,0x65,0x58,0x45,0x52,0x25,0x19,0x8c,0xf5,0x9c,0x24,0x26,0x14,0x69,0x26, +0x24,0x6c,0x26,0x34,0x71,0x26,0x44,0x74,0x26,0x54,0x79,0x7c,0xf4,0x86,0x11, +0x00,0x41,0x3f,0x41,0x58,0x25,0xef,0xea,0x00,0x22,0x44,0x0c,0x0c,0x11,0xef, +0xe8,0x02,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x10,0x89,0x00, +0x0c,0xf9,0x4f,0x01,0xa8,0x48,0x44,0x0c,0x0c,0x11,0x6f,0xf4,0x00,0x22,0x44, +0x0c,0x0c,0x11,0x0f,0x80,0xa0,0x42,0x42,0x02,0x44,0x10,0x0f,0x01,0x28,0x48, +0x44,0x0c,0x0c,0x11,0x80,0x80,0x31,0x80,0x88,0x23,0x89,0x01,0x66,0x04,0x04, +0x0c,0x84,0x46,0x01,0x00,0x0c,0x74,0xb8,0x01,0xb9,0x02,0x2d,0x04,0x1d,0xf0, +0x41,0x21,0x41,0xc6,0xe8,0xff,0x41,0x27,0x41,0x58,0x35,0x46,0xe7,0xff,0x41, +0x1d,0x41,0x06,0xfd,0xff,0x41,0x24,0x41,0x58,0x45,0xc6,0xe3,0xff,0x41,0x1a, +0x41,0x06,0xfd,0xff,0x00,0x00,0x00,0x36,0x81,0x00,0x1c,0xf4,0xa2,0xc1,0x14, +0x29,0x41,0x39,0x51,0x92,0xc1,0x10,0xb1,0x6b,0x41,0xb9,0x01,0x90,0x40,0x0c, +0xa0,0x10,0x0c,0xaf,0xe0,0x0a,0x22,0x02,0x19,0x04,0x00,0xaf,0xe0,0x0a,0x22, +0x02,0x09,0x05,0x00,0x0f,0x02,0x01,0x82,0x40,0x00,0x00,0x14,0x2f,0x01,0x01, +0xa2,0xa4,0x10,0x0c,0x00,0xaf,0xe0,0x0a,0x22,0xa4,0x10,0x0c,0x11,0x0f,0x62, +0x08,0x82,0x02,0x11,0x05,0x11,0x00,0x53,0x0d,0x88,0x11,0x4f,0x00,0xb5,0x43, +0xc0,0x80,0x05,0x00,0x00,0x82,0xd3,0x2d,0x08,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0x8b,0xa2,0xa5,0x74,0xff,0xa2,0xc2,0x10,0x65,0x74,0xff,0xa2,0xc2,0x18, +0xe5,0x73,0xff,0xa2,0xc2,0x20,0xc2,0x04,0xc7,0xb2,0x04,0xc6,0x00,0xcc,0x23, +0x00,0xbb,0x23,0xc0,0xbb,0xd1,0xe5,0x9b,0x03,0xa2,0xc2,0x28,0x25,0x72,0xff, +0xb2,0x04,0xc4,0xa2,0xc2,0x30,0x00,0xbb,0x23,0x2b,0xbb,0xa5,0x9a,0x03,0xa2, +0xc2,0x38,0xb8,0xc2,0x25,0x9a,0x03,0x1d,0xf0,0x00,0x36,0x41,0x00,0x7c,0xc9, +0x0c,0x0f,0xa8,0x32,0xe8,0x42,0xb8,0x3a,0xc8,0x2e,0xa8,0x2a,0x88,0xcc,0xf2, +0x6a,0x14,0xb8,0x2b,0xb2,0x6a,0x11,0x3b,0xbb,0x90,0x9b,0x10,0x92,0x6a,0x12, +0xb0,0xb2,0x21,0xb2,0x6a,0x13,0xa6,0x18,0x17,0x0c,0x0a,0xd8,0x3e,0xbd,0x0f, +0x1b,0xaa,0x88,0xdc,0x92,0x2d,0x14,0x8a,0x8b,0x99,0x08,0x88,0xcc,0x4b,0xbb, +0x87,0x2a,0xed,0x98,0xec,0x0c,0x0b,0xa6,0x19,0x15,0x0c,0x0a,0xd8,0x3e,0x1b, +0xaa,0x98,0xfc,0x82,0x2d,0x14,0x9a,0x9b,0x89,0x09,0xe8,0xec,0x4b,0xbb,0xe7, +0x2a,0xed,0x0c,0x09,0xd8,0xf2,0xc8,0x52,0xd8,0x0d,0xa8,0x3c,0xb8,0x2c,0xa8, +0xea,0xf2,0x6b,0x10,0x76,0xaa,0x11,0xf8,0x2c,0xe8,0x3c,0xf8,0x1f,0xe8,0xae, +0xfa,0xf9,0xe2,0xce,0xfe,0x1b,0x99,0xe2,0x4f,0x00,0xb1,0xd4,0x40,0x91,0x23, +0x41,0xa1,0x23,0x41,0x81,0x24,0x41,0xa0,0xad,0xc0,0xa0,0x89,0x93,0xa8,0x72, +0x88,0x08,0x89,0x4c,0x65,0xf5,0x03,0xa8,0x82,0xb1,0xcd,0x40,0xe5,0xf4,0x03, +0x1d,0xf0,0x36,0x41,0x00,0xad,0x02,0xb8,0x12,0xa5,0x55,0x02,0xbd,0x03,0x82, +0x22,0x26,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xad, +0x02,0x88,0xb2,0xb8,0x12,0xe0,0x08,0x00,0x98,0x12,0x98,0x19,0x92,0x29,0x31, +0x99,0xf2,0x1d,0xf0,0x00,0x36,0x41,0x00,0xd8,0x42,0x88,0x32,0xb8,0x2d,0x80, +0x8b,0xa0,0x88,0x08,0x8c,0x88,0xad,0x02,0x82,0x22,0x1b,0xc8,0x3d,0xe0,0x08, +0x00,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x57,0x51,0x09,0x41,0x0c,0x76,0xef,0xea, +0x00,0x22,0x44,0x0c,0x0c,0x11,0xf0,0x20,0x00,0x3d,0xf0,0x3d,0xf0,0x76,0xa4, +0x27,0x0f,0x60,0x40,0xc2,0x44,0x0c,0x0c,0x11,0x4f,0xee,0x00,0x22,0x44,0x0c, +0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x00,0x84,0x00,0xaf,0xe0,0x0a,0x22,0x82, +0x01,0x41,0x10,0x4f,0x05,0x42,0x48,0x44,0x0c,0x0c,0x11,0x1d,0xf0,0x00,0x00, +0x36,0x41,0x00,0x51,0xf8,0x40,0x62,0xa0,0x05,0xef,0xea,0x00,0x22,0x44,0x0c, +0x0c,0x11,0x76,0xa4,0x1a,0x0f,0x60,0x40,0xc2,0x44,0x0c,0x0c,0x11,0x4f,0xec, +0x00,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x00,0x84,0x00,0x10, +0x12,0x8d,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x06,0x76,0xa4,0x12, +0x0f,0x60,0x40,0xc2,0x44,0x0c,0x0c,0x11,0x4f,0xec,0x00,0x22,0x44,0x0c,0x0c, +0x11,0x10,0x02,0x8d,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x28,0x14,0x50, +0x62,0x21,0x72,0x93,0x00,0x81,0xe2,0x40,0x4b,0x33,0x6f,0xf1,0x00,0x22,0x44, +0x0c,0x0c,0x11,0x4f,0x01,0x04,0x29,0x44,0x0c,0x0c,0x11,0xf0,0x20,0x00,0x3d, +0xf0,0x76,0xa6,0x3a,0x6f,0x62,0x40,0xa2,0x44,0x0c,0x0c,0x11,0x4f,0xee,0x02, +0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xd0,0x10,0x07,0x09,0xaf,0xe0, +0x0a,0x22,0x40,0x00,0x09,0x01,0xaf,0xe0,0x0a,0x22,0x40,0x00,0x0d,0x11,0xaf, +0xe0,0x0a,0x22,0x40,0x00,0x09,0x29,0xaf,0xe0,0x0a,0x22,0x40,0x00,0x0d,0x39, +0x30,0x02,0x8d,0x0c,0x79,0xa8,0x04,0x0c,0x02,0xa2,0xca,0xc0,0xa0,0x29,0x93, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x5d,0x0c,0x58,0xa2,0x93,0x00, +0xa2,0x54,0x00,0x92,0x93,0x01,0xa2,0xa0,0x00,0x92,0x54,0x01,0x30,0x93,0x20, +0x76,0xa8,0x0d,0xb2,0x99,0x02,0xc8,0x24,0x2b,0x99,0xaa,0xcc,0xb2,0x5c,0x00, +0x2b,0xaa,0x9d,0x03,0x0c,0x0a,0x76,0xad,0x0d,0xe2,0x99,0x07,0xf8,0x44,0x2b, +0x99,0xaa,0xff,0xe2,0x5f,0x00,0x2b,0xaa,0xa8,0x64,0xb2,0xc3,0x18,0x0c,0x5c, +0x65,0xf2,0xff,0xa8,0x84,0xb2,0xc3,0x22,0x0c,0x5c,0xa5,0xf1,0xff,0xa8,0xa4, +0xb2,0xc3,0x2c,0x0c,0x5c,0xe5,0xed,0xff,0xa8,0xc4,0xb2,0xc3,0x36,0x0c,0x5c, +0x25,0xed,0xff,0xa8,0xe4,0xb2,0xc3,0x40,0x0c,0x5c,0xa5,0xec,0xff,0xa2,0x24, +0x10,0xb2,0xc3,0x4a,0x0c,0x5c,0xe5,0xeb,0xff,0xa2,0x24,0x12,0x1c,0xec,0xb2, +0xa0,0x86,0xba,0xb3,0xa5,0xe6,0xff,0xa2,0x24,0x14,0x1c,0xec,0xb2,0xa0,0xc2, +0xba,0xb3,0xe5,0xe5,0xff,0x0c,0x7c,0x0c,0x02,0x20,0x2c,0x93,0x1d,0xf0,0x00, +0x36,0x41,0x00,0x82,0x22,0x15,0xad,0x02,0xe0,0x08,0x00,0xa2,0x22,0x11,0x98, +0x2a,0xa8,0x1a,0xd8,0x19,0xd9,0x0a,0xc8,0x29,0xc9,0x3a,0xb8,0x39,0xb9,0x5a, +0x98,0x49,0x99,0x2a,0x1d,0xf0,0x36,0x41,0x00,0xa1,0x97,0x40,0x1c,0xf6,0xef, +0xe6,0x08,0x22,0x44,0x0c,0x0c,0x11,0x4f,0x12,0x81,0x02,0x82,0x59,0x04,0x00, +0x6f,0xf5,0x08,0x22,0x44,0x0c,0x0c,0x11,0xef,0x25,0x09,0x62,0xa4,0x30,0x28, +0x03,0x6f,0xf0,0x08,0x22,0x44,0x0c,0x0c,0x11,0x0f,0x32,0xc9,0x82,0x60,0x30, +0x18,0x01,0x90,0x40,0x0c,0xaf,0xe0,0x0a,0x22,0xa4,0x30,0x18,0x02,0xcf,0xb0, +0x80,0x02,0x82,0x19,0x04,0x00,0xaf,0xe0,0x0a,0x22,0xa8,0x10,0x88,0x01,0x6f, +0xeb,0x00,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x10,0x08,0x01, +0xaf,0xe0,0x0a,0x22,0x40,0x00,0x09,0x01,0x42,0xc2,0x20,0x00,0x04,0x0d,0x1d, +0xf0,0x00,0x36,0x61,0x00,0xad,0x03,0xa5,0x14,0x05,0x88,0x22,0x91,0x79,0x40, +0x6f,0xf4,0x00,0x22,0x44,0x0c,0x0c,0x11,0x6f,0xf2,0x02,0x22,0x44,0x0c,0x0c, +0x11,0x4f,0x6e,0x81,0x02,0xa4,0x00,0x01,0x00,0x82,0x28,0x1a,0x2f,0x01,0x28, +0x48,0x44,0x0c,0x0c,0x11,0x40,0xa9,0x93,0xe0,0x08,0x00,0x2f,0x02,0xb8,0x43, +0x44,0x0c,0x0c,0x11,0xa9,0x62,0xef,0xf4,0x02,0x22,0x44,0x0c,0x0c,0x11,0x4f, +0xab,0x92,0x43,0x48,0x10,0x0c,0x11,0xcf,0x02,0x42,0x43,0x44,0x0c,0x0c,0x11, +0x65,0x0f,0x05,0x88,0x22,0x82,0x28,0x1a,0xb1,0x62,0x40,0xe0,0x08,0x00,0x4f, +0x02,0xb8,0x43,0x44,0x0c,0x0c,0x11,0xc8,0x02,0x6f,0xf5,0x00,0x22,0x44,0x0c, +0x0c,0x11,0x2f,0x20,0xa1,0x42,0xa4,0x20,0x11,0x01,0xc8,0x2c,0x4f,0x01,0x28, +0x49,0x44,0x0c,0x0c,0x11,0xa9,0x82,0xcc,0x33,0x0c,0x0b,0x50,0x9b,0x83,0x99, +0xa2,0xc8,0xbc,0xc9,0x92,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0xa2,0xc2, +0x24,0xa5,0x0c,0x05,0xbd,0x04,0xa2,0xc2,0x3c,0x25,0x0c,0x05,0xbd,0x05,0xa2, +0xc2,0x30,0xa5,0x0b,0x05,0xbd,0x06,0xa2,0xc2,0x50,0x25,0x0b,0x05,0xbd,0x07, +0xa2,0xc2,0x58,0xa5,0x0a,0x05,0xb8,0x81,0xa2,0xa0,0x94,0xaa,0xa2,0x25,0x0a, +0x05,0xb8,0x91,0xa2,0xa0,0x84,0xaa,0xa2,0x65,0x09,0x05,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x61,0x00,0x1c,0xf8,0x4b,0xa1,0x39,0x01,0x9d,0x01,0xb1,0x3f,0x40, +0xb9,0x11,0x90,0x00,0x0c,0xa0,0x40,0x0c,0xaf,0xe0,0x0a,0x22,0x02,0x0a,0x04, +0x00,0xaf,0xe0,0x0a,0x22,0xa4,0x00,0x80,0x00,0xaf,0xe0,0x0a,0x22,0x40,0x00, +0x01,0x01,0x8f,0x00,0x28,0x48,0x44,0x0c,0x0c,0x11,0x49,0x22,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0x38,0x42,0x1c,0xf4,0x58,0x33,0x88,0x03,0x32,0xc3,0x24, +0x52,0x25,0x14,0x88,0x28,0x6f,0xea,0x00,0x22,0x44,0x0c,0x0c,0x11,0x82,0xc8, +0x14,0xaf,0x00,0x01,0xa2,0x02,0x09,0x04,0x00,0xaf,0xe0,0x0a,0x22,0xa8,0x00, +0x80,0x00,0x00,0x03,0x0d,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x04,0x0c,0x19, +0x0c,0x0a,0x0c,0x18,0x58,0x32,0x68,0x02,0xe8,0xc5,0x68,0x26,0x78,0x05,0x38, +0x06,0x78,0x17,0xc8,0x76,0x70,0x78,0x93,0xc9,0x52,0xb8,0x66,0xb9,0x62,0xa9, +0xc2,0xa2,0x62,0x17,0x92,0x62,0x10,0x8f,0x24,0x37,0x82,0xc2,0x0c,0x02,0x00, +0x0f,0xe0,0x1e,0x22,0x8a,0x0f,0x02,0x00,0xaf,0xe0,0x0a,0x22,0xc6,0x0d,0x02, +0x00,0x10,0x48,0xd3,0xd0,0x04,0x03,0x40,0x80,0x04,0x82,0x42,0x11,0xd0,0xd2, +0x04,0xd2,0x42,0x10,0x1d,0xf0,0x36,0x61,0x00,0xa2,0xc2,0x2c,0xb2,0xc2,0x30, +0xb0,0x40,0x0c,0xa0,0x00,0x0c,0xaf,0xe0,0x0a,0x22,0x30,0x0c,0x84,0x00,0x9d, +0x01,0x00,0x19,0x0d,0x88,0xa2,0xb1,0x0b,0x40,0x82,0x28,0x1a,0xa8,0x01,0xe0, +0x08,0x00,0xc8,0xd2,0xc8,0x1c,0xa9,0x0c,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41, +0x00,0xad,0x02,0xbd,0x03,0x39,0x02,0xc8,0x12,0x88,0x32,0x49,0x0c,0x59,0x2c, +0x69,0x4c,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0xe8,0x02,0xd8,0x12,0xe8, +0x1e,0xd8,0x2d,0xe0,0xdd,0xa0,0xd8,0x0d,0x9c,0x0d,0xb2,0x9d,0x00,0xc8,0x2d, +0xa8,0x32,0x25,0x0c,0x00,0xf8,0x02,0xf8,0x0f,0xf8,0x0f,0xf9,0x22,0x1d,0xf0, +0x00,0x00,0x36,0x41,0x00,0x31,0x99,0x3f,0x32,0x23,0x10,0x38,0x43,0xa8,0x73, +0xa8,0x6a,0xe5,0xba,0x01,0xa8,0x73,0xa8,0x7a,0x25,0xe0,0x01,0x38,0x83,0x38, +0x33,0xb8,0x33,0xb8,0x2b,0xe6,0x4b,0x23,0x88,0x63,0xad,0x08,0xb8,0x58,0x82, +0x28,0x16,0xb8,0x2b,0xe0,0x08,0x00,0x88,0x73,0xbd,0x02,0xad,0x08,0xe8,0x38, +0x88,0x98,0xc8,0x2e,0xd8,0x0e,0xe2,0x2e,0x17,0xd8,0x3d,0xe0,0x08,0x00,0x1d, +0xf0,0x00,0x00,0x36,0x41,0x00,0xa8,0x02,0x98,0x22,0xa8,0x2a,0x98,0x29,0xb8, +0x2a,0xb0,0x99,0x90,0x92,0x99,0x00,0xd8,0x4a,0x66,0x09,0x15,0x0c,0x0d,0xd9, +0x52,0x0c,0x0b,0xc8,0x72,0x81,0x6c,0x3f,0xa8,0x1c,0x88,0x88,0xc8,0x0c,0xe0, +0x08,0x00,0x1d,0xf0,0xd0,0xd9,0x90,0x46,0xf9,0xff,0x36,0x41,0x00,0x38,0x02, +0x0c,0x06,0x38,0x13,0x0c,0x05,0x38,0x23,0x0c,0x07,0xa6,0x13,0x1e,0x1b,0x55, +0xa8,0x32,0x48,0x02,0x88,0x72,0x98,0x52,0x8a,0x86,0x9a,0x96,0x48,0x14,0xaa, +0xa6,0x79,0x0a,0x79,0x09,0x79,0x08,0x48,0x24,0x4b,0x66,0x47,0x25,0xe0,0x1d, +0xf0,0x00,0x36,0x41,0x00,0xe6,0x53,0x73,0x32,0x62,0x60,0xa0,0xb3,0x11,0x61, +0x57,0x3f,0x52,0xa0,0x80,0x68,0x96,0x5a,0xa2,0xe0,0x06,0x00,0xa6,0x13,0x55, +0x0c,0x0c,0x0c,0x2a,0x0c,0x1b,0x0c,0x38,0x1b,0xcc,0x0f,0x80,0x40,0xc2,0x44, +0x0c,0x0c,0x11,0x20,0x9a,0xa0,0x4b,0xaa,0x2f,0xb3,0x68,0x43,0xe2,0x02,0x14, +0x10,0x00,0x09,0x4d,0x92,0xc9,0x10,0x76,0xa8,0x28,0x0f,0x80,0x40,0xc2,0x44, +0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xe2,0x02,0x14,0x10,0x00,0x09,0x0d,0x0f, +0x80,0x40,0xc2,0x44,0x0c,0x0c,0x11,0x0f,0x54,0x09,0x82,0xe2,0x02,0x14,0x10, +0x00,0x09,0x4d,0x92,0xc9,0x10,0x0c,0x38,0xc7,0x93,0xb1,0xad,0x02,0xb0,0xb3, +0x11,0xe0,0x06,0x00,0x1d,0xf0,0x36,0x41,0x00,0x49,0x62,0x39,0x82,0xa2,0xa0, +0xb4,0x0c,0x4b,0x0c,0x08,0x89,0x72,0x65,0xb1,0x03,0xb8,0x23,0x3d,0x0a,0xa2, +0xa0,0xac,0xaa,0xa3,0x25,0x2f,0x03,0x39,0x52,0xb1,0xa6,0x3f,0xc1,0xa5,0x3f, +0xd1,0xa3,0x3f,0xe1,0xa1,0x3f,0xf1,0x9f,0x3f,0xf9,0x02,0xe9,0x12,0xd9,0x22, +0xc9,0x32,0xb9,0x42,0x65,0x03,0xff,0x20,0x8a,0xc0,0x89,0x92,0x1d,0xf0,0x36, +0x41,0x00,0xbd,0x03,0x4c,0xca,0x25,0xb1,0x03,0x3d,0x0a,0xb8,0x92,0xe5,0x52, +0x02,0x39,0xa2,0x65,0xb5,0x03,0x3d,0x0a,0xa8,0x02,0xbd,0x03,0x65,0x3f,0xfe, +0xa8,0x12,0xbd,0x03,0xe5,0x3d,0xfe,0xa8,0x22,0xbd,0x03,0xe5,0x3b,0xfe,0xa8, +0x32,0xbd,0x03,0x65,0x3b,0xfe,0xa8,0x42,0xbd,0x03,0xa5,0x39,0xfe,0xa8,0x52, +0xbd,0x03,0xe5,0x35,0xfe,0xa8,0x82,0xbd,0x03,0x25,0x31,0xfe,0xad,0x03,0x88, +0xa2,0x98,0x42,0x88,0x58,0x98,0x09,0x88,0x18,0x89,0x39,0x25,0xab,0x03,0x1d, +0xf0,0x36,0xa1,0x00,0x49,0xb2,0x0c,0xca,0x0c,0x4b,0x91,0x85,0x3f,0xe0,0x83, +0x11,0x62,0xc9,0xf0,0x72,0xc9,0xec,0x70,0x73,0xa0,0x60,0x63,0xa0,0x9a,0x88, +0x82,0x28,0x7f,0x62,0x26,0x7f,0x72,0x27,0x7f,0x68,0x06,0x78,0x07,0x38,0x08, +0xa5,0xa5,0x03,0x79,0x2a,0x69,0x1a,0x39,0x0a,0x0c,0x4b,0xa9,0x92,0x1c,0x4a, +0xe5,0xa4,0x03,0xa9,0x41,0xbd,0x03,0xc8,0x47,0xdd,0x05,0xc8,0x0c,0xe5,0x22, +0xff,0x3c,0x4a,0x0c,0x4b,0xd8,0x41,0xd9,0x02,0x65,0xa3,0x03,0xa9,0x51,0xbd, +0x03,0xd8,0x87,0xc2,0x26,0x1a,0xd8,0x0d,0x25,0x1d,0xff,0x4c,0x0a,0x0c,0x4b, +0xe8,0x51,0xe9,0x12,0xa5,0xa1,0x03,0xa9,0x61,0xbd,0x03,0x0c,0x0d,0xc2,0x26, +0x11,0x0c,0x3e,0xc8,0x3c,0x25,0x17,0xff,0x4c,0x0a,0x0c,0x4b,0xd8,0x61,0xd9, +0x22,0x25,0xa0,0x03,0xa9,0x71,0xbd,0x03,0x0c,0x0d,0xc2,0x26,0x11,0x0c,0x4e, +0xc8,0x4c,0xa5,0x15,0xff,0x3c,0x8a,0x0c,0x4b,0xd8,0x71,0xd9,0x32,0x65,0x9e, +0x03,0xa9,0x81,0xbd,0x03,0xc2,0x26,0x22,0xdd,0x05,0xa5,0x10,0xff,0xa2,0xa0, +0xc0,0x0c,0x4b,0xe8,0x81,0xe9,0x42,0xe5,0x9c,0x03,0xcd,0x07,0xbd,0x06,0xed, +0x03,0xd2,0x26,0x1b,0xfd,0x05,0x49,0x01,0x4d,0x0a,0xa5,0x01,0xff,0x49,0x52, +0x0c,0x8a,0x0c,0x4b,0x25,0x9b,0x03,0xb8,0x92,0x4d,0x0a,0xc8,0x1b,0xb8,0x0b, +0xc2,0x2c,0x15,0xe5,0xfe,0xfe,0x49,0x72,0x4c,0x0a,0x0c,0x4b,0xa5,0x99,0x03, +0xf8,0x06,0xe8,0x16,0xd8,0x26,0xc8,0x36,0xb8,0x46,0x82,0x26,0x19,0x59,0x21, +0x39,0x11,0x89,0x01,0x3d,0x0a,0xe5,0xee,0xfe,0x39,0x82,0x0c,0x8a,0x0c,0x4b, +0xa5,0x97,0x03,0x3d,0x0a,0xa5,0xec,0xfe,0x39,0xc2,0xa5,0xeb,0xfe,0x20,0x9a, +0xc0,0x99,0xd2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0xcd,0x05,0xbd,0x03, +0x52,0x22,0x1a,0xa2,0xa0,0x6c,0x58,0x05,0xc9,0x01,0x58,0x75,0x65,0x98,0x03, +0x3d,0x0a,0xb2,0x22,0x1a,0xa5,0xf7,0x01,0x88,0x54,0x32,0x62,0x1c,0xf2,0x22, +0x20,0xc2,0x22,0x1f,0xd8,0x43,0xd9,0x0c,0x92,0x23,0x10,0x99,0x1c,0xa8,0x28, +0xa9,0x3c,0xb8,0x83,0xb9,0x2c,0xd8,0x43,0xc2,0x22,0x1e,0xb9,0x2f,0x99,0x1f, +0xa9,0x3f,0xd9,0x0f,0xe2,0x23,0x11,0xe9,0x2c,0xb2,0x23,0x12,0xe2,0x22,0x21, +0xd9,0x4c,0xb9,0x3c,0xc2,0x23,0x16,0xc9,0x4e,0x92,0x23,0x14,0x99,0x5e,0xf8, +0x38,0xf9,0x6e,0xf8,0x44,0xd2,0x23,0x19,0x92,0x2f,0x13,0xd9,0x7e,0xf8,0xef, +0xd2,0xc9,0x20,0xb8,0x09,0xb9,0xbe,0xf9,0x9e,0xb2,0xc9,0x28,0xf2,0x23,0x15, +0xf9,0xae,0xd9,0x2e,0x92,0xc9,0x30,0x99,0x3e,0xb9,0x1e,0x92,0x22,0x23,0xd2, +0x23,0x17,0xd9,0x8e,0xc9,0x39,0xb8,0xe3,0xb9,0x49,0xa9,0x59,0x89,0x19,0xa5, +0x94,0x03,0x7d,0x0a,0x2c,0xca,0xbd,0x07,0x25,0x8f,0x03,0xbd,0x05,0x3d,0x0a, +0xe5,0xeb,0x01,0xb2,0x22,0x1c,0x39,0x7b,0x8b,0xab,0xcb,0xbb,0xe5,0xe9,0x01, +0xb2,0x22,0x1c,0xa2,0xcb,0x4c,0xb2,0xcb,0x3c,0x25,0xe9,0x01,0xc2,0x22,0x1c, +0xc8,0x7c,0xd2,0x22,0x23,0xc2,0xcc,0x1c,0xc9,0x6d,0x25,0x91,0x03,0x3d,0x0a, +0xa8,0x02,0xbd,0x03,0x25,0x04,0xfe,0xa8,0x12,0xbd,0x03,0xa5,0x03,0xfe,0xa8, +0x32,0xbd,0x03,0xc2,0x22,0x21,0x25,0x3f,0x00,0xa8,0x72,0xbd,0x03,0xc2,0x22, +0x22,0x65,0x01,0xfe,0xa8,0x82,0xbd,0x03,0x25,0x18,0xfe,0xa8,0x62,0xbd,0x03, +0xe5,0x18,0xfe,0xa2,0x22,0x16,0xbd,0x03,0xa5,0xfe,0xfd,0xbd,0x03,0xe8,0x52, +0xa8,0xa2,0xf8,0x42,0xd2,0x22,0x1e,0xd9,0x1f,0xd9,0x1e,0x65,0x14,0xfe,0xa8, +0xb2,0xbd,0x03,0x25,0x14,0xfe,0xa8,0xc2,0xbd,0x03,0xa5,0x13,0xfe,0xa8,0xd2, +0xbd,0x03,0x25,0x13,0xfe,0xa8,0xe2,0xbd,0x03,0x58,0x01,0xa5,0x12,0xfe,0xcd, +0x05,0xbd,0x03,0x82,0x22,0x1c,0xa8,0x44,0x82,0x28,0x1a,0xa2,0x2a,0x15,0x92, +0xc8,0x10,0xa8,0x6a,0xa9,0x16,0x8b,0x88,0xa9,0x05,0xa2,0x22,0x18,0x99,0x15, +0x89,0x06,0xe5,0xf7,0xfd,0xcd,0x06,0xa2,0x22,0x19,0xbd,0x03,0x25,0xf6,0xfd, +0xa2,0x22,0x1d,0xbd,0x03,0xe5,0xf3,0xfd,0xad,0x03,0xe5,0x80,0x03,0xa2,0x22, +0x17,0xbd,0x07,0x65,0x05,0xfe,0xa2,0x22,0x12,0xbd,0x07,0x25,0x09,0xfe,0xad, +0x07,0xa5,0x7f,0x03,0x1d,0xf0,0x00,0x36,0x61,0x01,0x62,0x62,0x1b,0x0c,0xca, +0x0c,0x4b,0x65,0x7c,0x03,0x88,0x15,0x0c,0x09,0xb2,0xc2,0x50,0xc2,0xc2,0x10, +0xd2,0xc2,0x4c,0xe2,0xc2,0x14,0xe2,0x61,0x1f,0xd2,0x61,0x20,0xc2,0x61,0x1a, +0xb2,0x61,0x1b,0x92,0x61,0x21,0x39,0x0a,0x49,0x1a,0x59,0x2a,0x82,0x98,0x00, +0x89,0x41,0xa2,0x62,0x1a,0x2c,0x4a,0x0c,0x4b,0x25,0x79,0x03,0xa2,0x61,0x1d, +0xbd,0x03,0xc2,0x24,0x17,0xd2,0x25,0x10,0xed,0x06,0xfd,0x07,0xa5,0x9f,0xfe, +0x0c,0xca,0x0c,0x4b,0x82,0x21,0x1f,0xf2,0x21,0x1d,0xf9,0x08,0x25,0x77,0x03, +0xa2,0x61,0x1e,0xbd,0x03,0xc2,0x24,0x1e,0x25,0xff,0xfe,0x92,0x21,0x21,0xc2, +0x21,0x1b,0xb2,0x21,0x20,0xd2,0x21,0x1e,0xa2,0x21,0x1a,0xa2,0x61,0x1f,0xd9, +0x0b,0xc2,0x61,0x20,0x1b,0x99,0x92,0x61,0x21,0x66,0x29,0xad,0xa2,0xa0,0x64, +0x0c,0x4b,0xe5,0x73,0x03,0xa9,0x51,0xbd,0x03,0xd2,0x25,0x15,0xc2,0x24,0x14, +0x0c,0x0e,0xfd,0x07,0xe9,0x01,0xed,0x06,0x25,0x8e,0xfe,0xa2,0xa0,0x64,0x0c, +0x4b,0xf8,0x51,0xf9,0x02,0xe5,0x71,0x03,0xa9,0x61,0xbd,0x03,0xed,0x06,0xfd, +0x07,0xd2,0x25,0x15,0xc2,0x24,0x14,0x0c,0x18,0x89,0x01,0x25,0x8c,0xfe,0x0c, +0x8a,0x0c,0x4b,0x98,0x61,0x99,0x12,0xe5,0x6f,0x03,0xa9,0x71,0xbd,0x03,0xc2, +0x24,0x15,0xa5,0xd3,0xfe,0xa8,0x71,0x1c,0x0b,0xa9,0x22,0x4c,0x0a,0xa5,0x6e, +0x03,0xa9,0x81,0xbd,0x03,0xcd,0x04,0xdd,0x05,0xed,0x06,0xfd,0x07,0x65,0x2f, +0x00,0xb8,0x81,0x1c,0x4a,0xb9,0x32,0x0c,0x4b,0xe5,0x6c,0x03,0xa9,0x91,0xc8, +0x35,0xd8,0x41,0xbd,0x03,0xc0,0xcd,0xa0,0xe0,0xdd,0x11,0xc8,0x0c,0xd2,0x61, +0x1c,0xdd,0x07,0x65,0xea,0xfe,0x4c,0x0a,0x0c,0x4b,0xd8,0x91,0xd9,0x62,0xa5, +0x6a,0x03,0xa9,0xa1,0xbd,0x03,0x0c,0x0d,0xc2,0x24,0x11,0x0c,0x0e,0xc8,0x0c, +0x25,0xe0,0xfe,0x4c,0x0a,0x0c,0x4b,0xd8,0xa1,0xd9,0xa2,0x25,0x69,0x03,0xa9, +0xb1,0xbd,0x03,0xe2,0x25,0x17,0xc2,0x24,0x11,0xd2,0x21,0x1c,0xc8,0x1c,0xea, +0xdd,0xd8,0x0d,0x0c,0x1e,0x25,0xde,0xfe,0x4c,0x0a,0x0c,0x4b,0xf8,0xb1,0xf9, +0xb2,0xe5,0x66,0x03,0xbd,0x03,0x0c,0x1e,0xa9,0xc1,0xf2,0x25,0x18,0xc2,0x24, +0x11,0xd2,0x21,0x1c,0xc8,0x1c,0xfa,0xdd,0xd8,0x0d,0xe5,0xdb,0xfe,0x4c,0x0a, +0x0c,0x4b,0xd8,0xc1,0xd9,0xc2,0xa5,0x64,0x03,0xa9,0xd1,0xbd,0x03,0x0c,0x0d, +0xc2,0x24,0x11,0x0c,0x2e,0xc8,0x2c,0x25,0xda,0xfe,0x4c,0x0a,0x0c,0x4b,0xd8, +0xd1,0xd9,0xd2,0xe5,0x62,0x03,0xa9,0xe1,0xbd,0x03,0x0c,0x0d,0xc2,0x24,0x11, +0x0c,0x5e,0xc8,0x5c,0x65,0xd8,0xfe,0x3c,0x4a,0x0c,0x4b,0xd8,0xe1,0xd9,0xe2, +0x65,0x61,0x03,0xa9,0xf1,0xbd,0x03,0xd8,0x75,0xc2,0x24,0x1a,0xd8,0x0d,0x25, +0xdb,0xfe,0x0c,0x8a,0x0c,0x4b,0xe8,0xf1,0xe9,0x82,0xa5,0x5f,0x03,0xa2,0x61, +0x10,0xbd,0x03,0xc2,0x24,0x20,0x25,0x79,0xfe,0x0c,0x8a,0x0c,0x4b,0xf2,0x21, +0x10,0xf9,0x92,0x65,0x5e,0x03,0xa2,0x61,0x11,0xbd,0x03,0xc2,0x24,0x1d,0x25, +0x76,0xfe,0x1c,0x0a,0x0c,0x4b,0x82,0x21,0x11,0x89,0xf2,0xe5,0x5c,0x03,0xa2, +0x61,0x12,0xbd,0x03,0xc2,0x24,0x18,0xa5,0x72,0xfe,0x1c,0x0a,0x0c,0x4b,0x92, +0x21,0x12,0x92,0x62,0x10,0x65,0x5b,0x03,0xa2,0x61,0x13,0xbd,0x03,0xc2,0x24, +0x18,0x25,0x71,0xfe,0xa2,0x21,0x13,0x0c,0x4b,0xa2,0x62,0x11,0xa2,0xa0,0xc0, +0xe5,0x59,0x03,0xa2,0x61,0x14,0xbd,0x04,0xcd,0x05,0xed,0x03,0xfd,0x07,0xd2, +0x24,0x1b,0x69,0x01,0xa5,0xbe,0xfe,0xb2,0x21,0x14,0x1c,0x4a,0xb2,0x62,0x12, +0x0c,0x4b,0xe5,0x57,0x03,0xa2,0x61,0x15,0xbd,0x03,0xcd,0x06,0x25,0x6c,0xfe, +0x0c,0xca,0x0c,0x4b,0xc2,0x21,0x15,0xc9,0x72,0x65,0x56,0x03,0xa2,0x61,0x16, +0xbd,0x03,0xc2,0x24,0x1e,0x65,0xde,0xfe,0xa2,0xa0,0x84,0x0c,0x4b,0xd2,0x21, +0x16,0xd2,0x62,0x15,0xe5,0x54,0x03,0xa2,0x61,0x17,0xbd,0x03,0xc2,0x24,0x1c, +0xd8,0x95,0xe8,0xa5,0xfd,0x06,0x65,0x63,0xfe,0x3c,0x0a,0x0c,0x4b,0xe2,0x21, +0x17,0xe2,0x62,0x16,0xe5,0x52,0x03,0xa2,0x62,0x21,0x0c,0x4b,0x1c,0x4a,0x65, +0x52,0x03,0xa2,0x62,0x1f,0x0c,0x4b,0x1c,0x4a,0xa5,0x51,0x03,0xa2,0x62,0x20, +0x0c,0x4b,0x1c,0x4a,0x25,0x51,0x03,0xa2,0x62,0x1e,0x0c,0x4b,0x1c,0x4a,0x65, +0x50,0x03,0xa2,0x62,0x22,0x0c,0x4b,0x1c,0xca,0xe5,0x4f,0x03,0xa2,0x62,0x23, +0x0c,0x4b,0x4c,0x0a,0x25,0x4f,0x03,0xa2,0x61,0x18,0x82,0x24,0x19,0xb8,0x44, +0xc8,0x34,0xd8,0x24,0xe8,0x14,0xf8,0x04,0x39,0x11,0x79,0x21,0x89,0x01,0x65, +0xa4,0xfe,0x2c,0x4a,0x0c,0x4b,0x92,0x21,0x18,0x92,0x62,0x17,0xe5,0x4c,0x03, +0xed,0x07,0xdd,0x06,0xa2,0x61,0x19,0xbd,0x03,0xc2,0x24,0x27,0xa5,0x58,0xfe, +0xa2,0x21,0x19,0x0c,0x4b,0xa2,0x62,0x18,0x1c,0x4a,0x25,0x4b,0x03,0xc2,0x24, +0x28,0xbd,0x03,0x4d,0x0a,0x65,0x53,0xfe,0x42,0x62,0x19,0xa5,0x9e,0xfe,0x20, +0xba,0xc0,0xb2,0x62,0x24,0x0c,0xca,0x0c,0x4b,0x65,0x49,0x03,0xbd,0x03,0xc8, +0x15,0x3d,0x0a,0x25,0x50,0xfe,0x32,0x62,0x1d,0x1d,0xf0,0x36,0x41,0x00,0xbd, +0x03,0x1c,0x4a,0x25,0x4b,0x03,0x3d,0x0a,0xb8,0x02,0x65,0x9d,0x01,0xd8,0xb2, +0xe8,0xa2,0xa8,0x84,0xf8,0x74,0x49,0x22,0x39,0x12,0xa9,0x0e,0xc8,0x44,0xc9, +0x2e,0x98,0x24,0x99,0x3e,0x88,0x34,0xf9,0x5e,0x89,0x4e,0xf8,0x03,0xf9,0x6e, +0x88,0x13,0x89,0x7e,0xb8,0x23,0xb9,0x8e,0x98,0x33,0x99,0x9e,0xa8,0x43,0xa9, +0xae,0xa9,0x5d,0x89,0x1d,0xf9,0x0d,0xb9,0x2d,0x99,0x4d,0xb8,0x94,0x98,0xc2, +0xe8,0x54,0xe9,0x3d,0xb9,0x6d,0xc9,0x09,0xb9,0x19,0x88,0x64,0xa8,0xa4,0xa9, +0x39,0x89,0x29,0x65,0x4a,0x03,0x38,0x62,0x4d,0x0a,0x68,0xa2,0x2c,0x8a,0xbd, +0x04,0xa5,0x44,0x03,0x5d,0x0a,0xbd,0x03,0x25,0x93,0x01,0x0c,0x8a,0xbd,0x04, +0x59,0x33,0x69,0x43,0x68,0x72,0x38,0xb2,0x25,0x43,0x03,0x5d,0x0a,0xa5,0x8f, +0x01,0xad,0x04,0x39,0x26,0x59,0x16,0xc8,0x82,0xb8,0xc2,0xb9,0x1c,0xe5,0x40, +0x03,0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x0c,0xca,0x0c,0x4b,0xe5,0x3d, +0x03,0x0c,0x4b,0x0c,0x08,0x59,0x2a,0x49,0x1a,0x39,0x0a,0x69,0x32,0xa9,0x02, +0x79,0x42,0x0c,0xca,0x89,0x12,0x65,0x3c,0x03,0xa9,0x01,0xbd,0x03,0xc2,0x24, +0x1e,0x65,0xc4,0xfe,0xa2,0xa0,0x60,0x0c,0x4b,0x98,0x01,0x99,0x52,0xe5,0x3a, +0x03,0xbd,0x03,0xc8,0xb4,0xed,0x06,0xd2,0x25,0x11,0xf8,0x42,0x5d,0x0a,0xe5, +0x36,0xfe,0x59,0x62,0x2c,0xca,0x0c,0x4b,0x65,0x39,0x03,0xfd,0x07,0x5d,0x0a, +0xbd,0x03,0xd8,0x02,0xc8,0xe4,0xd8,0x2d,0xed,0x06,0xd2,0x2d,0x12,0xe5,0x30, +0xfe,0x59,0x72,0x1c,0x8a,0x0c,0x4b,0xa5,0x37,0x03,0xdd,0x06,0xbd,0x03,0xc8, +0xd4,0x3d,0x0a,0x25,0x2b,0xfe,0x39,0x82,0x2c,0xca,0x0c,0x4b,0x65,0x36,0x03, +0xa9,0xa2,0x0c,0x4b,0x1c,0xca,0xe5,0x35,0x03,0xa9,0xb2,0x0c,0x4b,0x1c,0x0a, +0x25,0x35,0x03,0xa9,0xc2,0x65,0x89,0xfe,0x20,0xea,0xc0,0xe9,0xf2,0x1d,0xf0, +0x00,0x36,0x41,0x00,0x58,0x82,0x48,0x62,0x38,0x72,0x81,0x3f,0x3d,0xad,0x02, +0x88,0x98,0xb8,0x92,0xe0,0x08,0x00,0x2c,0x8a,0xbd,0x02,0xe5,0x35,0x03,0xcd, +0x04,0xbd,0x05,0xa5,0x7f,0xff,0x8c,0x73,0xbd,0x03,0x0c,0x4a,0xe5,0x34,0x03, +0xa9,0x72,0x1d,0xf0,0x36,0xa1,0x00,0xb1,0xab,0x3d,0x51,0xab,0x3d,0xf1,0xab, +0x3d,0x2c,0xec,0x41,0x45,0x3d,0x0c,0x19,0xd2,0x24,0x10,0x90,0x00,0xf3,0x68, +0x4d,0xe8,0x3d,0x78,0x86,0x88,0x7e,0x89,0x61,0xc7,0x22,0x14,0x27,0x2c,0x41, +0xa8,0xb6,0x25,0x59,0xff,0xa2,0x24,0x10,0xa8,0x3a,0xa8,0xfa,0x65,0x58,0xff, +0x86,0x31,0x00,0x1c,0x9c,0xc7,0x22,0x4d,0x27,0x2c,0x02,0xc6,0x79,0x00,0x2c, +0x5b,0xb7,0xa2,0x02,0x86,0x55,0x00,0x27,0xab,0x02,0x46,0x7c,0x00,0xa2,0x24, +0x12,0xa2,0x2a,0x2d,0x65,0x59,0x04,0xb8,0x61,0xb8,0x4b,0xa9,0xcb,0xad,0x0b, +0x25,0x5e,0xff,0x86,0x25,0x00,0x4c,0x1c,0xc7,0xa2,0x02,0x86,0x24,0x00,0x4c, +0x28,0x27,0xa8,0x02,0xc6,0x2c,0x00,0xa8,0x46,0xd2,0x24,0x12,0x0c,0x0c,0xb2, +0x2d,0x26,0xd2,0x2d,0x27,0x65,0x41,0xff,0xc6,0x1c,0x00,0xa6,0x62,0x25,0xe6, +0x82,0x02,0x06,0x89,0x00,0x1c,0x2a,0xa7,0xa2,0x02,0x06,0x62,0x00,0x27,0x2a, +0x02,0x46,0x88,0x00,0x1c,0x6e,0xe7,0x92,0x57,0xb2,0x24,0x12,0xa8,0x66,0xb8, +0x7b,0xe5,0x4c,0xff,0x86,0x12,0x00,0xe6,0x32,0x02,0xc6,0x86,0x00,0xe6,0x42, +0x02,0xc6,0x80,0x00,0x66,0x52,0x3b,0x7c,0xf2,0x82,0xa0,0xe0,0xf2,0x24,0x12, +0xa8,0x16,0xb2,0xcf,0x68,0xc2,0xcf,0x70,0xd2,0xcf,0x6c,0xe2,0xcf,0x74,0xa8, +0x5a,0x92,0xcf,0x7c,0x8a,0x8f,0x99,0x01,0x89,0x11,0xf2,0xcf,0x78,0x25,0x45, +0xff,0xd2,0x24,0x10,0xd8,0x4d,0x1b,0xb2,0xd8,0x1d,0xc2,0x25,0x7f,0xad,0x0d, +0x88,0x1d,0xd8,0x8d,0xe0,0x08,0x00,0x0c,0x02,0x1d,0xf0,0x3c,0xdc,0xc7,0x22, +0x68,0x27,0xac,0x02,0x86,0x3c,0x00,0xa2,0x24,0x12,0xa2,0x2a,0x2c,0xa5,0x4d, +0x04,0x82,0x25,0x7f,0x82,0x28,0x1a,0xb1,0x5a,0x3d,0xe0,0x08,0x00,0x98,0x61, +0x98,0x49,0xa9,0x59,0x86,0xf4,0xff,0x5c,0x6c,0xc7,0xa2,0x02,0x46,0x2c,0x00, +0x27,0xac,0x02,0x46,0x47,0x00,0x56,0x13,0x35,0x88,0x0d,0xc2,0x24,0x12,0xe8, +0x61,0xc8,0x2c,0xa8,0x1e,0xf0,0x88,0xa0,0x82,0x28,0x7f,0xe8,0x0e,0x88,0x08, +0xe8,0x0e,0xb8,0x88,0x88,0x48,0xb0,0xbc,0xa0,0x80,0xcc,0xa0,0xc8,0x0c,0xc9, +0x1e,0xc8,0x0a,0xb8,0x0b,0xb9,0x2c,0x8c,0x1b,0xe5,0x5c,0xff,0x0c,0x02,0x1d, +0xf0,0x3c,0x9a,0xa7,0xa2,0x02,0x06,0x51,0x00,0x27,0xaa,0x02,0x06,0xdf,0x00, +0x82,0x2b,0x11,0x92,0x24,0x12,0x88,0x08,0x92,0x29,0x29,0xf2,0x28,0x2f,0xa2, +0x28,0x2d,0xf0,0xf9,0xa0,0xa0,0x99,0xa0,0x98,0x09,0x99,0xf8,0xf8,0x0f,0xf2, +0x68,0x10,0x06,0xd7,0xff,0x1c,0xcb,0xb7,0xa2,0x02,0x86,0xa2,0x00,0x27,0xab, +0x02,0x06,0xd5,0x00,0x17,0x63,0x04,0xad,0x07,0xa5,0x35,0x01,0x27,0x63,0x04, +0xa8,0x61,0xe5,0x38,0x01,0x37,0x63,0x0c,0xa2,0x24,0x10,0xa8,0x4a,0xb2,0x25, +0x7f,0xa8,0x1a,0x25,0x2f,0x01,0x30,0xb4,0x04,0x16,0x8b,0xf2,0xa2,0x24,0x10, +0xa8,0x3a,0xb2,0x25,0x7f,0xa8,0x1a,0x25,0x2e,0x01,0x06,0xc6,0xff,0x4c,0x4a, +0xa7,0xa2,0x02,0xc6,0x96,0x00,0x27,0xaa,0x20,0xb2,0xc2,0xb9,0x56,0x7b,0xf0, +0xa8,0x76,0xa8,0x6a,0xa5,0x07,0x01,0x46,0xbf,0xff,0x3c,0xfb,0xb7,0xa2,0x02, +0x46,0x9a,0x00,0xa6,0xd2,0x57,0xc2,0xc2,0xc0,0x56,0xcc,0xee,0xa8,0x56,0xd2, +0x24,0x12,0x0c,0x0c,0xb2,0x2d,0x28,0xd2,0x2d,0x2f,0xe5,0x27,0xff,0x46,0xb6, +0xff,0xf2,0xc2,0xf3,0x56,0x3f,0xed,0xa8,0x3e,0xd2,0x24,0x12,0x0c,0x1c,0xb2, +0x2d,0x37,0xd2,0x2d,0x2e,0x65,0x26,0xff,0x0c,0x0a,0xa5,0x47,0xff,0xc6,0xae, +0xff,0x2c,0x9a,0xa7,0xa2,0x02,0x06,0x8c,0x00,0x27,0xaa,0x02,0x86,0xb0,0x00, +0x7c,0xf2,0xe9,0x81,0xc6,0x03,0x00,0xa2,0xa1,0x02,0xa7,0x22,0x54,0x27,0xaa, +0x02,0x86,0xa6,0xff,0x0c,0x02,0xe9,0x81,0x92,0xa0,0x94,0x62,0xa0,0xe4,0xf2, +0xa0,0x90,0xe2,0xa0,0x8c,0xd2,0xa0,0x84,0xc2,0xa0,0x88,0xb2,0xa0,0x80,0xa8, +0x81,0x82,0x24,0x12,0xa8,0x1a,0xba,0xb8,0xca,0xc8,0xda,0xd8,0xea,0xe8,0xfa, +0xf8,0x6a,0x68,0xa8,0x5a,0x69,0x11,0x9a,0x88,0x89,0x01,0x25,0x2a,0xff,0xd2, +0x24,0x10,0xd8,0x3d,0x1b,0xb2,0xd8,0x1d,0xc2,0x25,0x7f,0xad,0x0d,0x88,0x1d, +0xd8,0x8d,0xe0,0x08,0x00,0xc6,0x92,0xff,0xe2,0xd2,0xff,0x56,0x5e,0xe4,0x0c, +0x02,0x86,0x81,0xff,0xf2,0xc2,0xcc,0x56,0xaf,0xe3,0x0c,0x0a,0x25,0x3f,0xff, +0xa2,0x24,0x10,0xa8,0x4a,0xa8,0xca,0xe5,0x31,0xff,0x06,0x8a,0xff,0xc2,0xc2, +0xfe,0x56,0x2c,0xe2,0x28,0x0d,0xe0,0x83,0x11,0x89,0x71,0xf0,0x22,0xa0,0x22, +0x22,0x7f,0xd8,0x66,0x28,0x02,0xa8,0x3d,0xc8,0xc2,0xd8,0x0d,0xc0,0xc3,0xa0, +0xc8,0x0c,0xc9,0x2d,0xb8,0x0c,0xc8,0x2c,0xe5,0x46,0xff,0x92,0x24,0x12,0x92, +0x29,0x3b,0x68,0x71,0xdc,0xd9,0xb8,0x42,0xa8,0x61,0xba,0xb6,0xc8,0x0a,0xa8, +0x1a,0xc8,0x0c,0xb8,0x0b,0xb9,0x1c,0xb8,0x82,0xc8,0x0a,0xba,0xb6,0xb8,0x0b, +0xb9,0x2c,0x8c,0x1b,0x25,0x41,0xff,0xa8,0x87,0xe8,0x32,0xd8,0x72,0xf8,0x67, +0xda,0xd6,0xf8,0x0f,0xea,0xe6,0xe8,0x0e,0xe9,0x1f,0xe8,0x0a,0xd8,0x0d,0xd9, +0x2e,0x8c,0x1d,0x65,0x3f,0xff,0xd2,0x22,0x17,0xe8,0xb7,0xc2,0x22,0x18,0xa8, +0x17,0xca,0xc6,0x82,0x2a,0x12,0xe8,0x1e,0x92,0x2a,0x11,0xda,0xd6,0xd8,0x0d, +0xb8,0x39,0xd9,0x2e,0x88,0x28,0xd8,0xc7,0xc8,0x0c,0xd8,0x1d,0xb0,0x88,0xa0, +0x88,0x08,0xc9,0x2d,0x89,0x29,0x25,0x09,0xff,0xa8,0x07,0x82,0x2a,0x11,0xf2, +0x2a,0x12,0x98,0x38,0xf8,0x2f,0x90,0xff,0xa0,0xf8,0x0f,0xf9,0x28,0xa5,0x07, +0xff,0xa2,0x27,0x16,0xa5,0xea,0xfe,0xa8,0x57,0xe5,0x36,0xff,0xa8,0x47,0xa5, +0x36,0xff,0xa2,0x24,0x10,0xa8,0x4a,0xa8,0x7a,0xa8,0x6a,0xe5,0xec,0x00,0x0c, +0x1a,0xe5,0x30,0xff,0xa2,0x24,0x10,0xb2,0x24,0x12,0xa8,0x3a,0xb8,0x0b,0xa8, +0x2a,0xb8,0x7b,0x65,0x2d,0xff,0xd2,0x24,0x10,0xd8,0x4d,0xc2,0x25,0x7f,0xd8, +0x1d,0x0c,0x1b,0xad,0x0d,0x88,0x1d,0xd8,0x8d,0xe0,0x08,0x00,0xf2,0x22,0x16, +0xe2,0x24,0x12,0xa2,0x24,0x10,0xe8,0x2e,0xa8,0x3a,0xf0,0xee,0xa0,0xe8,0x0e, +0xa8,0x9a,0xb2,0x9e,0x00,0x4b,0xce,0xcb,0xde,0xe2,0x9e,0x01,0x65,0x28,0xff, +0x51,0xae,0x3c,0x88,0xb2,0xf2,0x24,0x12,0xa8,0x61,0xf8,0x2f,0xa8,0x4a,0x80, +0xff,0xa0,0xf8,0x0f,0x98,0xda,0x82,0x9f,0x02,0x89,0x29,0xf8,0x0f,0xf9,0xba, +0x25,0x23,0xff,0x88,0x12,0x88,0x78,0x8a,0x83,0x92,0x08,0x00,0xa2,0x25,0x14, +0x00,0x99,0x23,0x99,0xfa,0x82,0x08,0x00,0x92,0x25,0x1c,0x00,0x88,0x23,0x89, +0x09,0x46,0x32,0xff,0x92,0xc2,0xe5,0x56,0x39,0xcc,0xb2,0x26,0x12,0xb8,0x0b, +0xa8,0xa6,0xb8,0x0b,0x65,0xfe,0xfe,0x06,0x2d,0xff,0xc2,0xc2,0xbd,0x56,0xec, +0xca,0xe2,0x2b,0x11,0xf2,0x24,0x12,0xe8,0x3e,0xf2,0x2f,0x2b,0xd2,0x2e,0x2f, +0x82,0x2e,0x2d,0xd0,0xdf,0xa0,0x80,0xff,0xa0,0xf8,0x0f,0xf9,0xfe,0xd8,0x0d, +0xd2,0x6e,0x10,0xc6,0x22,0xff,0xf2,0xc2,0xc2,0x56,0x5f,0xc8,0x06,0x8f,0xff, +0x2c,0x68,0x87,0xa2,0x02,0x86,0x1e,0xff,0x2c,0x79,0x27,0x29,0x02,0x06,0x8b, +0xff,0xc6,0x1b,0xff,0xa8,0xce,0xa8,0x0a,0xb1,0x79,0x3c,0xa8,0x0a,0xb7,0x9a, +0x05,0x41,0x87,0x3c,0x46,0x03,0x00,0x0c,0x04,0xc1,0x86,0x3c,0xb1,0x86,0x3c, +0xc0,0xca,0xc0,0xc0,0x4b,0x83,0x16,0x44,0x07,0xa2,0xc1,0x10,0xb1,0x84,0x3c, +0x0c,0x7c,0xe5,0xb0,0x08,0xc2,0xc1,0x10,0xca,0xc3,0xc2,0x0c,0x00,0xc0,0xcc, +0x11,0xca,0x44,0xb8,0x24,0xa8,0x34,0xb8,0x0b,0x25,0xca,0x03,0x0c,0x0c,0x8c, +0x3a,0x26,0x7a,0x01,0x0c,0x1c,0xa8,0x14,0xb8,0x04,0x0c,0x0d,0x7c,0xf2,0xc0, +0x2d,0x83,0xb8,0x0b,0x65,0xc8,0x03,0x0c,0x09,0x8c,0x3a,0x26,0x7a,0x01,0x0c, +0x19,0x7c,0xfe,0x90,0x2e,0x93,0x1d,0xf0,0xf2,0xc2,0xc4,0x56,0xcf,0xbf,0x46, +0x49,0xff,0x82,0xc2,0xe2,0x56,0x38,0xbf,0xa2,0x27,0x16,0xa5,0xd2,0xfe,0x86, +0xfa,0xfe,0x2c,0xa9,0x97,0xa2,0x02,0x86,0xf8,0xfe,0x2c,0xda,0x27,0x2a,0x02, +0xc6,0x4f,0xff,0xc6,0xf5,0xfe,0x7c,0xf2,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0x3c,0xc5,0xc1,0x65,0x3c,0x26,0x32,0x22,0x82,0xc2,0xf2,0x16,0x48,0x0d,0x57, +0x92,0x25,0x0c,0x0a,0xc7,0x13,0x0c,0x92,0xa4,0xb0,0xb2,0xa3,0x84,0xba,0xb3, +0xb7,0xb9,0x01,0x0c,0x1a,0x9c,0x0a,0x31,0x5d,0x3c,0xc6,0x2c,0x00,0xc7,0x13, +0x08,0xe6,0x23,0x02,0xd6,0x23,0x00,0x66,0x33,0xed,0x61,0xee,0x3b,0xb1,0x58, +0x3c,0x3c,0x9d,0x76,0xad,0x6a,0xe2,0x1b,0x7f,0x27,0x9e,0x62,0xc7,0x93,0x10, +0xf1,0x55,0x3c,0xa2,0x1b,0x82,0xf7,0x1a,0xd0,0x31,0x54,0x3c,0x3a,0x3a,0x32, +0x93,0x00,0x0c,0x0a,0xe2,0xa0,0x80,0xea,0xdb,0xd2,0x0d,0x83,0x0c,0x1c,0x00, +0xdd,0x23,0x37,0xad,0x07,0xf2,0xa0,0x7f,0xf7,0x1d,0x01,0x0c,0x0c,0x9c,0x8c, +0xea,0xdb,0xd2,0x0d,0x82,0x0c,0x1c,0x00,0xdd,0x23,0xd7,0xa3,0x07,0xe2,0xaf, +0x80,0xe7,0x1d,0x01,0x0c,0x0c,0x0c,0x1f,0xc0,0xaf,0x93,0x8c,0xfa,0x98,0xe6, +0x82,0x1b,0x80,0xad,0x04,0x9a,0x88,0x39,0x08,0x25,0xc6,0x02,0x86,0x02,0x00, +0x31,0x3d,0x3c,0x06,0x01,0x00,0x8b,0xbb,0x31,0x3b,0x3c,0x1c,0x9a,0xa7,0x12, +0x1b,0x57,0x92,0x26,0xc8,0xe6,0xe1,0x3b,0x3c,0xb2,0x9c,0x6e,0xd1,0x3b,0x3c, +0xe0,0xbb,0xd1,0xda,0xbb,0xb0,0xb0,0x31,0xb2,0x6c,0x30,0x46,0x03,0x00,0x88, +0xe6,0xf2,0x98,0x60,0xf0,0xff,0xa0,0xf0,0xff,0x11,0xf2,0x68,0x37,0x2d,0x03, +0x1d,0xf0,0x82,0xc3,0xfc,0x56,0xd8,0xf4,0x3d,0x0c,0x06,0xfc,0xff,0x00,0x00, +0x00,0x36,0x61,0x00,0xa8,0x02,0x65,0x2b,0x04,0x2d,0x0a,0x66,0x0a,0x03,0x0c, +0x82,0x1d,0xf0,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0xd1,0x2a,0x3c,0x31,0xb9,0x3b, +0xed,0x01,0x88,0x03,0x0c,0x19,0x82,0x28,0x10,0x99,0x01,0xe0,0x08,0x00,0xa8, +0x01,0xf8,0x03,0x9c,0x2a,0xed,0x02,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0x82,0x2f, +0x10,0xd1,0x22,0x3c,0xe0,0x08,0x00,0x86,0x02,0x00,0xcd,0x02,0x0c,0x1a,0x88, +0xff,0x1c,0x9b,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x36,0x41,0x00,0xc1,0xaa, +0x3b,0x98,0xbc,0x7c,0xfa,0x82,0xd9,0xf0,0x9c,0x18,0xcc,0xf9,0xa8,0xac,0xb2, +0x92,0x00,0xe5,0x51,0x03,0x0c,0x79,0x0c,0x82,0xa0,0x29,0x83,0x1d,0xf0,0xc6, +0xfc,0xff,0x00,0x00,0x00,0x36,0x41,0x00,0x1c,0xc4,0x47,0x92,0x07,0x0c,0x02, +0x29,0x03,0x1d,0xf0,0x00,0x00,0x61,0x08,0x3c,0x3c,0x98,0x76,0xa8,0x19,0x92, +0x16,0x7f,0x27,0x99,0x11,0xb1,0x99,0x3b,0xa2,0x16,0x80,0xb8,0xeb,0x0c,0x02, +0xba,0xaa,0xa8,0x0a,0xa9,0x03,0x1d,0xf0,0x8b,0x66,0x7c,0xf2,0x1d,0xf0,0x00, +0x00,0x36,0x61,0x00,0xa1,0x04,0x3c,0x38,0x02,0x0c,0x82,0xa0,0x43,0x10,0x82, +0xd4,0xf0,0x9c,0xf8,0xa7,0x83,0x1d,0x30,0xa0,0xb4,0xbd,0x01,0xe5,0xfa,0xff, +0x0c,0x79,0x0c,0x82,0xa0,0x29,0x83,0x66,0x72,0x09,0xa1,0x89,0x3b,0x30,0xb0, +0xb4,0xb9,0xaa,0x49,0xba,0x1d,0xf0,0x46,0xfb,0xff,0x00,0x00,0x36,0x61,0x00, +0xa1,0xf6,0x3b,0xc8,0x02,0xa0,0x8c,0x10,0x82,0xd8,0xf0,0x9c,0x38,0xa7,0x8c, +0x11,0xc0,0xa0,0xb4,0xbd,0x01,0x65,0xf7,0xff,0xcc,0xaa,0x98,0x01,0x99,0x02, +0x0c,0x72,0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x00,0x00,0x00, +0x36,0x41,0x00,0xed,0x02,0x1c,0x9a,0x81,0x77,0x3b,0x0c,0x0b,0x88,0x08,0x0c, +0x4c,0x82,0x28,0x10,0xd1,0xe7,0x3b,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0xe8,0x02,0x1c,0x9a,0x81,0x6f,0x3b,0x0c,0x0b,0x88, +0x08,0x0c,0x4c,0x82,0x28,0x10,0xd1,0xe0,0x3b,0xe0,0x08,0x00,0x0c,0x72,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xed,0x02,0x1c,0x9a,0x81,0x67,0x3b,0x0c, +0x0b,0x88,0x08,0x0c,0x4c,0x82,0x28,0x10,0xd1,0xd4,0x3b,0xe0,0x08,0x00,0x0c, +0x72,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x38,0x02,0x0c,0x84,0x66,0x13, +0x0b,0x81,0xd3,0x3b,0x0c,0x74,0x88,0x18,0x89,0x02,0xc6,0xff,0xff,0x2d,0x04, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xed,0x02,0x1c,0x9a,0x81,0x58,0x3b,0x0c, +0x0b,0x88,0x08,0x0c,0x4c,0x82,0x28,0x10,0xd1,0xcb,0x3b,0xe0,0x08,0x00,0x0c, +0x72,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xe8,0x02,0x26,0x8e,0x0b,0x26, +0xbe,0x08,0x3c,0x08,0x87,0x1e,0x03,0x0c,0x82,0x1d,0xf0,0x1c,0x9a,0x81,0x4c, +0x3b,0x0c,0x0b,0x88,0x08,0x0c,0x4c,0x82,0x28,0x10,0xd1,0xc0,0x3b,0xe0,0x08, +0x00,0x0c,0x72,0x1d,0xf0,0x36,0x41,0x00,0xc8,0x02,0x0c,0x82,0xc0,0x81,0x64, +0xdc,0x68,0xc0,0x98,0x74,0xf6,0xa9,0x11,0x81,0x42,0x3b,0x88,0x08,0x1c,0x3a, +0x88,0xf8,0x0c,0x8b,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x1d,0xf0,0x00,0x00, +0x36,0x41,0x00,0x31,0x3c,0x3b,0x41,0xb3,0x3b,0xb2,0x13,0x12,0xa2,0x24,0x7f, +0xa5,0x4a,0x00,0xcc,0x2a,0x0c,0x02,0x1d,0xf0,0xe2,0x13,0x12,0xd8,0x02,0x81, +0xae,0x3b,0xb2,0x24,0x7f,0xd7,0xa8,0x04,0x91,0xa2,0x3b,0x9a,0xdd,0x81,0xac, +0x3b,0xd0,0xfb,0x11,0x8a,0xff,0xf2,0x2f,0x7f,0x0c,0x82,0xf0,0xfe,0xb0,0xa2, +0x9f,0x02,0x92,0x9f,0x03,0xa7,0x2d,0x1e,0xd7,0x29,0x1b,0xb6,0x9b,0x04,0x0c, +0xda,0xb7,0xba,0x15,0xf6,0xbb,0x02,0x86,0x27,0x00,0x1c,0x5c,0xb7,0xbc,0x02, +0x86,0x25,0x00,0xc1,0xa0,0x3b,0x86,0x24,0x00,0x1d,0xf0,0xe0,0xab,0x11,0xf1, +0x9f,0x3b,0xb6,0x4e,0x3e,0xfa,0x9a,0x92,0x29,0x7f,0x82,0xce,0xfc,0x98,0x89, +0x16,0xb8,0x08,0x0c,0x0b,0xc2,0xce,0xfb,0x16,0xec,0x08,0x82,0xce,0xfa,0x16, +0x88,0x09,0x66,0x7e,0x19,0xb1,0x97,0x3b,0xe2,0xae,0x70,0xc1,0x96,0x3b,0xe0, +0x99,0x10,0xca,0xca,0xd2,0x6c,0x7f,0xb0,0x8d,0xa0,0x82,0x28,0x7f,0x90,0x98, +0x20,0xdd,0x09,0x0c,0x7e,0xe2,0x53,0x12,0xc1,0x90,0x3b,0xfa,0xba,0xca,0xca, +0xc2,0x2c,0x79,0xb2,0x2b,0x7f,0x98,0x0c,0x0c,0x0a,0xa6,0x19,0x0e,0xb0,0xbe, +0xa0,0x1b,0xaa,0xd9,0x1b,0xe8,0x0c,0xb2,0xcb,0x34,0xe7,0x2a,0xf3,0x1c,0x9a, +0x0c,0x0b,0x0c,0x4c,0x88,0x03,0xd1,0x87,0x3b,0x82,0x28,0x10,0x0c,0x0e,0xe0, +0x08,0x00,0x0c,0x1a,0x88,0x03,0x1c,0x9b,0x88,0xf8,0x7c,0xfc,0xe0,0x08,0x00, +0x0c,0x42,0x1d,0xf0,0x0c,0x0c,0x0c,0x1a,0x88,0x03,0x98,0x0f,0x88,0xf8,0xd2, +0x59,0x00,0xe0,0x08,0x00,0x06,0xfa,0xff,0x7c,0x3b,0xb0,0x99,0x10,0xb1,0x7b, +0x3b,0x86,0xe2,0xff,0x6c,0xfc,0x1c,0x0e,0xd0,0xbe,0x93,0xc0,0x99,0x10,0xb0, +0x99,0x20,0xc6,0xe0,0xff,0xc2,0xaf,0xdf,0x2c,0x0e,0xd0,0xbe,0x93,0xc0,0x99, +0x10,0xb0,0x99,0x20,0x86,0xdc,0xff,0x00,0x36,0x41,0x00,0x38,0x02,0x30,0x48, +0x74,0xad,0x04,0x30,0x30,0x74,0xbd,0x03,0x65,0x37,0x00,0x8c,0xea,0x0c,0x72, +0x81,0xea,0x3a,0x91,0x61,0x3b,0x32,0x58,0x12,0x42,0x69,0x7f,0x1d,0xf0,0x0c, +0x02,0x1d,0xf0,0x36,0x81,0x00,0x49,0x31,0x0c,0x09,0x99,0x04,0xec,0x53,0x96, +0xa2,0x13,0xa1,0xcf,0x3a,0xb8,0x2a,0xb7,0x32,0x02,0xc6,0x4b,0x00,0x16,0x7b, +0x12,0x0c,0x04,0xa2,0x2a,0x03,0x76,0x9b,0x0a,0xb2,0x1a,0x00,0xb7,0x92,0x01, +0x4d,0x0a,0xa2,0xca,0x14,0xc6,0x44,0x00,0x4d,0x09,0xcc,0x43,0x72,0x14,0x01, +0x86,0x03,0x00,0x82,0x03,0x03,0x72,0x03,0x02,0x80,0x88,0x11,0x80,0x77,0x20, +0x80,0x77,0x23,0x61,0xd3,0x3a,0xcc,0x53,0x98,0x24,0x99,0x21,0xc6,0x00,0x00, +0x8b,0xa3,0xa9,0x21,0xa6,0x17,0x1c,0x58,0x21,0x2d,0x05,0x50,0x57,0x90,0xb2, +0x02,0x01,0xa2,0x02,0x00,0xa2,0x56,0x13,0x00,0xbb,0x23,0xb9,0x01,0xe5,0x1a, +0x03,0x2b,0x22,0x57,0x92,0xe9,0xcc,0x73,0x92,0x14,0x02,0x46,0x04,0x00,0x00, +0x00,0x00,0xa2,0x03,0x05,0x92,0x03,0x04,0x80,0xaa,0x11,0xa0,0x99,0x20,0x80, +0x99,0x23,0x49,0x51,0xcc,0x53,0xb8,0x34,0xb9,0x11,0xc6,0x02,0x00,0xd8,0x21, +0x0c,0x0c,0xc0,0xc7,0x53,0xd0,0xcc,0x90,0xc9,0x11,0x0c,0x07,0x16,0xb9,0x09, +0x58,0x11,0x49,0x51,0x50,0x89,0xa0,0x89,0x41,0xfc,0x03,0xc2,0x15,0x00,0xc9, +0x01,0xc0,0xa8,0x74,0x26,0x9a,0x07,0x0c,0xb9,0x97,0x1a,0x02,0x66,0xaa,0x07, +0x0c,0x1a,0xb8,0x31,0xa9,0x86,0xa9,0x0b,0xc0,0x20,0x74,0xc0,0x48,0x74,0xad, +0x04,0xbd,0x02,0xa5,0x27,0x00,0xdc,0x8a,0x0c,0x02,0xc6,0x07,0x00,0x00,0x00, +0x00,0xd2,0x05,0x00,0xc2,0x05,0x01,0x80,0xdd,0x11,0xd0,0xcc,0x20,0x80,0xcc, +0x23,0x86,0xef,0xff,0x22,0x56,0x12,0xe1,0x1d,0x3b,0x0c,0x72,0x42,0x6e,0x7f, +0x26,0x82,0x2b,0xac,0x82,0xdc,0x43,0xb2,0x15,0x01,0xb9,0x01,0xad,0x01,0xa5, +0xd8,0xff,0x1b,0x77,0xf8,0x41,0x4b,0x55,0xf7,0x95,0x94,0x06,0x09,0x00,0xc2, +0x05,0x02,0xb2,0x05,0x03,0x80,0xcc,0x11,0xc0,0xbb,0x20,0x80,0xbb,0x23,0x86, +0xf6,0xff,0x0c,0x0d,0xd9,0x86,0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x0c,0x04,0x56, +0xa4,0xee,0x7c,0xf2,0x1d,0xf0,0x48,0x51,0x0c,0x0e,0xe9,0x86,0xcc,0x43,0x52, +0x14,0x03,0x86,0x03,0x00,0x82,0x03,0x07,0x52,0x03,0x06,0x80,0x88,0x11,0x80, +0x55,0x20,0x80,0x55,0x23,0xcc,0x33,0x28,0x44,0x06,0x01,0x00,0x28,0x11,0x20, +0x27,0xa0,0x0c,0x04,0x16,0x45,0xfc,0x1c,0x27,0x5c,0x2b,0xcc,0xc3,0xc2,0x12, +0x00,0x2b,0x22,0xc0,0xc0,0x74,0xc2,0x56,0x13,0xc6,0x01,0x00,0xc2,0x02,0x00, +0xc2,0x56,0x13,0x1b,0x22,0xec,0x63,0xa2,0x12,0x00,0xa9,0x01,0x2b,0x22,0xc7, +0xb7,0x2f,0xc7,0x3b,0x2c,0x81,0xfe,0x3a,0x80,0x8c,0xa0,0x82,0x28,0x7f,0xad, +0x01,0xe0,0x08,0x00,0x5c,0x2b,0x66,0x7a,0x19,0x1b,0x44,0x47,0x95,0xc0,0x86, +0xdf,0xff,0xd2,0x02,0x00,0xa2,0x02,0x01,0x80,0xdd,0x11,0xd0,0xaa,0x20,0x80, +0xaa,0x23,0x06,0xf2,0xff,0x0c,0x82,0x1d,0xf0,0x00,0x36,0x61,0x00,0xb8,0x02, +0xa1,0x5b,0x3a,0x96,0x0b,0x02,0xc8,0x2a,0xc7,0xbb,0x1b,0x9c,0x3c,0x0c,0x04, +0xa8,0x3a,0x76,0x9c,0x0a,0x82,0x1a,0x00,0x87,0x9b,0x01,0x4d,0x0a,0xa2,0xca, +0x14,0x46,0x00,0x00,0x0c,0x04,0x56,0x44,0x05,0x7c,0xf9,0x86,0x11,0x00,0x0c, +0x09,0x99,0x83,0x92,0x14,0x03,0x28,0x44,0xbc,0x89,0x1c,0x25,0x71,0xe2,0x3a, +0x5c,0x26,0x20,0x49,0xa0,0xb2,0x12,0x00,0xc2,0x12,0x01,0xc9,0x01,0xb0,0xb0, +0x74,0xb2,0x53,0x13,0xb7,0x35,0x02,0x06,0x2b,0x00,0xb7,0xb6,0x02,0x86,0x29, +0x00,0x70,0x8b,0xa0,0x82,0x28,0x7f,0xad,0x01,0xe0,0x08,0x00,0x92,0xca,0xf9, +0x56,0x59,0x09,0x4b,0x22,0x47,0x92,0xcf,0x0c,0x09,0x0c,0x7a,0x0c,0x82,0x90, +0x2a,0x83,0x1d,0xf0,0x28,0x24,0x92,0x14,0x01,0x31,0x4e,0x3a,0xa6,0x19,0x18, +0x20,0x59,0x90,0xb2,0x02,0x01,0xa2,0x02,0x00,0xa2,0x53,0x13,0x00,0xbb,0x23, +0xb9,0x01,0xa5,0xfa,0x02,0x2b,0x22,0x57,0x92,0xe9,0xa2,0x14,0x02,0x28,0x34, +0x16,0x3a,0xf8,0x20,0x7a,0xa0,0xc2,0x12,0x00,0xc9,0x01,0xc0,0xa8,0x74,0x26, +0x9a,0x07,0x0c,0xbf,0xf7,0x1a,0x02,0x66,0xaa,0x03,0x0c,0x18,0x89,0x83,0xc0, +0x50,0x74,0xc0,0x68,0x74,0xad,0x06,0xbd,0x05,0x25,0x0b,0x00,0xcc,0x6a,0x0c, +0x09,0x46,0x03,0x00,0x00,0x00,0x00,0x91,0xb0,0x3a,0x52,0x53,0x12,0x62,0x69, +0x7f,0x0c,0x79,0x26,0x89,0x13,0x9c,0x09,0xa2,0x12,0x01,0xa9,0x01,0xad,0x01, +0x65,0xbd,0xff,0x4b,0x22,0x77,0x92,0xb2,0x06,0xcc,0xff,0x0c,0x0b,0xb9,0x83, +0x06,0xdc,0xff,0x0c,0x89,0xc6,0xda,0xff,0x36,0x41,0x00,0xe8,0x02,0x82,0xa1, +0xff,0xe7,0xb8,0x03,0x0c,0x82,0x1d,0xf0,0x0c,0x7a,0x81,0x28,0x3a,0x0c,0x0b, +0x88,0x08,0x0c,0x4c,0x82,0x28,0x10,0x0c,0x0d,0xe0,0x08,0x00,0x0c,0x72,0x1d, +0xf0,0x00,0x00,0x36,0x41,0x00,0x88,0x02,0x3d,0x02,0x66,0x18,0x0b,0x91,0xa3, +0x3a,0x92,0x19,0x7f,0x99,0x03,0x0c,0x72,0x1d,0xf0,0xa5,0xd0,0x03,0xa0,0x90, +0xf4,0x06,0xfc,0xff,0x00,0x36,0x41,0x00,0x81,0x1a,0x3a,0xc8,0x02,0x88,0x08, +0x1c,0xca,0x88,0xf8,0x1c,0x9b,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x81,0x14,0x3a,0xc8,0x02,0x88,0x08,0x0c,0x1a,0x88,0xf8,0x1c,0x7b, +0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x00,0x36,0x41,0x00,0x1c,0x94,0x27,0x34, +0x0f,0x51,0x91,0x3a,0x50,0x52,0xb0,0x52,0x25,0x7f,0x0c,0x12,0x57,0xa3,0x01, +0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x36,0x41,0x00,0x38,0x02,0x30,0x48,0x74,0xad, +0x04,0x30,0x30,0x74,0xbd,0x03,0x65,0xfd,0xff,0xcc,0x2a,0x0c,0x02,0x1d,0xf0, +0xb1,0x7c,0x3a,0xd0,0xa4,0x11,0xba,0xaa,0xa2,0x2a,0x7f,0xa0,0xa3,0xb0,0xa8, +0x0a,0xcc,0x2a,0x0c,0x82,0x1d,0xf0,0xb6,0x94,0x04,0x0c,0xdc,0x47,0xbc,0x11, +0x92,0x9a,0x00,0xd6,0x29,0x00,0x92,0xd9,0x80,0x90,0xd0,0xf4,0xd9,0x02,0x0c, +0x72,0x1d,0xf0,0x91,0x72,0x3a,0xe0,0xb4,0x11,0x9a,0x9b,0x92,0x29,0x7f,0x4b, +0xa9,0xb6,0x43,0x1a,0xa8,0x89,0x0c,0x09,0x26,0x43,0x26,0x26,0x53,0x33,0x26, +0x63,0x18,0x66,0x73,0x18,0x91,0x6c,0x3a,0x9a,0x9b,0x92,0x19,0xfe,0x46,0x03, +0x00,0xa0,0xb3,0xa0,0xb2,0x1b,0x00,0xb9,0x02,0x46,0xf1,0xff,0xa0,0x95,0x04, +0x99,0x02,0x46,0xef,0xff,0x0c,0xcc,0xc0,0xba,0x10,0x26,0x4b,0xf2,0xc7,0x8a, +0x0a,0x0c,0x19,0x86,0xfa,0xff,0xa0,0x94,0x04,0x06,0xf9,0xff,0x66,0xab,0x04, +0x0c,0x29,0x06,0xf7,0xff,0x66,0x8b,0x9c,0x0c,0x39,0x06,0xf5,0xff,0x36,0x41, +0x00,0x31,0x61,0x3a,0x4d,0x02,0x28,0x02,0x20,0x20,0xf4,0x3a,0x22,0x22,0x02, +0x00,0x29,0x04,0x0c,0x72,0x1d,0xf0,0x36,0x61,0x00,0x98,0x02,0x90,0x88,0x41, +0x90,0x30,0x74,0x39,0x01,0x56,0x08,0x0b,0x0c,0x34,0x90,0x26,0x14,0xa2,0xc2, +0xfe,0x16,0x5a,0x0a,0xec,0x72,0x1c,0x9a,0x0c,0x0b,0x51,0xce,0x39,0x0c,0x4c, +0x88,0x05,0xd1,0x4d,0x3a,0x82,0x28,0x10,0x0c,0x0e,0xe0,0x08,0x00,0x0c,0x1a, +0x88,0x05,0x1c,0x9b,0x88,0xf8,0x7c,0xfc,0xe0,0x08,0x00,0xa1,0x4d,0x3a,0x46, +0x00,0x00,0x0c,0x0a,0x7c,0xff,0xb1,0x4b,0x3a,0x26,0x12,0x05,0x92,0xc2,0xfd, +0x56,0x39,0x0a,0x0c,0x1a,0xc0,0x20,0x00,0xd2,0x2b,0xb1,0x30,0x84,0x14,0xf0, +0xc8,0x11,0x00,0x1c,0x40,0x00,0xe4,0xa1,0xf0,0xee,0x30,0xe0,0xdd,0x10,0x00, +0x1c,0x40,0x30,0xe2,0x14,0x00,0x9e,0xa1,0x90,0xdd,0x20,0xf0,0x9e,0x11,0xe2, +0xce,0x11,0x00,0x19,0x40,0x00,0xc4,0xa1,0xf0,0xcc,0x30,0x00,0x19,0x40,0xc0, +0xdd,0x10,0x00,0xc8,0xa1,0x82,0xc8,0x11,0xd0,0xcc,0x20,0x00,0x18,0x40,0x00, +0xda,0xa1,0x00,0x1e,0x40,0x00,0xaa,0xa1,0xd0,0xaa,0x20,0xc0,0xaa,0x20,0x66, +0x32,0x4a,0x30,0xc4,0x14,0x30,0xe2,0x14,0xc7,0x1e,0x08,0x30,0xd0,0x14,0xc7, +0x1d,0x09,0xe7,0x1d,0x03,0x0c,0x82,0x1d,0xf0,0xc7,0x9d,0x31,0x0c,0x82,0x20, +0x8c,0x90,0x20,0x2e,0x90,0x00,0x12,0x40,0x00,0x94,0xa1,0xf0,0x99,0x30,0x00, +0x18,0x40,0x90,0x9a,0x10,0x00,0xa4,0xa1,0xf0,0xaa,0x30,0x00,0x12,0x40,0x00, +0x2d,0xa1,0xa0,0x99,0x10,0x00,0x18,0x40,0x90,0x22,0x20,0x00,0xad,0xa1,0x20, +0xaa,0x20,0xc0,0x20,0x00,0xa2,0x6b,0xb1,0x0c,0x72,0x1d,0xf0,0x36,0x41,0x00, +0x38,0x02,0x0c,0x82,0xb6,0x23,0x01,0x1d,0xf0,0x0c,0x72,0x1d,0xf0,0x36,0x41, +0x00,0x41,0x19,0x3a,0x0c,0x05,0x38,0x04,0x59,0x02,0x8c,0x63,0x59,0x02,0x59, +0x04,0x0c,0x72,0x1d,0xf0,0x0c,0x16,0x69,0x04,0x4d,0x02,0x06,0xfc,0xff,0x00, +0x36,0x41,0x00,0x51,0x12,0x3a,0x38,0x02,0x59,0x02,0x30,0x50,0x74,0x30,0x38, +0x74,0xcc,0x83,0x1c,0x38,0x91,0x0f,0x3a,0x99,0x02,0x57,0xb8,0x03,0x0c,0x82, +0x1d,0xf0,0xd1,0x0e,0x3a,0x0c,0x08,0x89,0x02,0x61,0x0b,0x3a,0x91,0x0c,0x3a, +0x60,0x65,0xa0,0xc0,0x20,0x00,0x42,0x26,0x80,0xb8,0x09,0x0c,0x1a,0xc8,0x0d, +0x59,0x0d,0xc0,0xc5,0xc0,0xc0,0xab,0x83,0x8c,0xfa,0x89,0x09,0x40,0x40,0xf5, +0x49,0x02,0xc0,0x20,0x00,0x82,0x66,0x80,0x0c,0x72,0x1d,0xf0,0x40,0x40,0xf4, +0x0c,0x1a,0xa9,0x09,0x46,0xfa,0xff,0x00,0x00,0x00,0x36,0x41,0x00,0x4d,0x02, +0x28,0x02,0x51,0x6f,0x39,0x9c,0xd2,0x26,0x12,0x08,0x51,0xd9,0x39,0x59,0x04, +0x0c,0x72,0x1d,0xf0,0x58,0x35,0x28,0x75,0x82,0x95,0x04,0x20,0x56,0x21,0x80, +0x55,0xd1,0x50,0x56,0x21,0x86,0xf9,0xff,0x58,0x35,0x0c,0x09,0x28,0x65,0x99, +0x65,0x46,0xf9,0xff,0x00,0x00,0x36,0x41,0x00,0x41,0x62,0x39,0x28,0x02,0x0c, +0x79,0x9c,0x22,0x26,0x52,0x1d,0xa6,0x92,0x08,0x38,0x34,0x0c,0x04,0x29,0x43, +0x86,0x02,0x00,0x7c,0xf4,0x46,0x01,0x00,0x88,0x34,0x0c,0x04,0x49,0x48,0x0c, +0x82,0x40,0x29,0x83,0x1d,0xf0,0xa2,0xa3,0xe8,0xb8,0x34,0x0c,0x04,0xa9,0x4b, +0x06,0xfb,0xff,0x00,0x00,0x00,0x36,0x41,0x00,0xa8,0x02,0xf6,0xba,0x14,0x81, +0x52,0x39,0x88,0x18,0x0c,0x0b,0x82,0x28,0x31,0x1c,0x0c,0xe0,0x08,0x00,0xa9, +0x02,0x0c,0x72,0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00, +0xa8,0x02,0x65,0x90,0x03,0xa9,0x02,0x0c,0x72,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0xa8,0x02,0xf6,0xba,0x14,0x81,0x45,0x39,0x88,0x18,0x0c,0x0b,0x82,0x28, +0x30,0x1c,0x0c,0xe0,0x08,0x00,0xa9,0x02,0x0c,0x72,0x1d,0xf0,0x0c,0x82,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x61,0xa9,0x39,0x20,0x50,0xf5,0x20,0x90, +0xf4,0x81,0xb4,0x39,0x99,0x04,0x57,0xa8,0x11,0xa1,0xc7,0x39,0xb1,0xc7,0x39, +0x57,0x2a,0x08,0xb0,0xb5,0xa0,0xb2,0x2b,0x7f,0x46,0x00,0x00,0x0c,0x0b,0x8c, +0xcb,0xad,0x04,0xe0,0x0b,0x00,0x2d,0x0a,0x26,0x8a,0x58,0x59,0x03,0x1d,0xf0, +0xc1,0xc0,0x39,0xd1,0xc0,0x39,0xc7,0x15,0x42,0xd7,0x15,0x3f,0xe1,0xbf,0x39, +0xf1,0xbf,0x39,0xe7,0x15,0x36,0xf7,0x15,0x33,0x81,0xbe,0x39,0x91,0xbe,0x39, +0x87,0x15,0x2a,0x97,0x15,0x27,0xa1,0xbd,0x39,0xb1,0xbd,0x39,0xa7,0x15,0x1e, +0xb7,0x15,0x1b,0xc1,0xbc,0x39,0xd1,0xbc,0x39,0xc7,0x15,0x12,0xd7,0x15,0x0f, +0xe1,0xbb,0x39,0xf1,0xbb,0x39,0xe7,0x15,0x06,0xf7,0x15,0x03,0x0c,0x02,0x1d, +0xf0,0x69,0x03,0x0c,0x72,0x3d,0x04,0x86,0xe9,0xff,0x69,0x03,0x3d,0x04,0xc6, +0xe7,0xff,0x36,0x41,0x00,0x41,0xb4,0x39,0x21,0x17,0x39,0x16,0xc3,0x08,0x82, +0xc3,0xfe,0x16,0xc8,0x0a,0x92,0xc3,0xfd,0x16,0xa9,0x09,0xa2,0xc3,0xf4,0x56, +0x8a,0x07,0x0c,0x6a,0x0c,0x0b,0x0c,0xdc,0x88,0x02,0xd8,0x52,0x82,0x28,0x10, +0xe1,0xab,0x39,0xe0,0x08,0x00,0x98,0x52,0x7c,0xfa,0xa0,0x99,0x30,0x99,0x52, +0x1d,0xf0,0xa2,0x64,0x86,0x0c,0x1a,0x88,0x02,0x0c,0x1b,0x88,0xf8,0xc1,0xa5, +0x39,0xe0,0x08,0x00,0xc1,0xa4,0x39,0x0c,0x09,0x97,0x1c,0x0a,0x88,0x02,0x0c, +0x1a,0x88,0xf8,0x0c,0x7b,0xe0,0x08,0x00,0x0c,0x1a,0x88,0x02,0x1c,0x6b,0x88, +0xf8,0xc1,0x9f,0x39,0xe0,0x08,0x00,0x0c,0x1a,0x88,0x02,0x0c,0x8b,0x88,0xf8, +0xc1,0x9c,0x39,0xe0,0x08,0x00,0x0c,0x1a,0x88,0x02,0x0c,0x6b,0x88,0xf8,0xc1, +0x9a,0x39,0xe0,0x08,0x00,0x92,0x24,0x7c,0xcc,0x69,0xb8,0x02,0xa1,0x97,0x39, +0xa2,0x6b,0x18,0x1d,0xf0,0xc2,0x24,0x86,0x66,0x0c,0x9f,0xa2,0x24,0x85,0xe5, +0x77,0x03,0x66,0x0a,0x93,0x0c,0x0d,0xd2,0x64,0x86,0xd2,0x64,0x85,0xc6,0xe2, +0xff,0x81,0x90,0x39,0x88,0x08,0x0c,0x0a,0xe0,0x08,0x00,0x1d,0xf0,0x0c,0x1a, +0x88,0x02,0xb2,0xa0,0x80,0x88,0xf8,0xc1,0x8c,0x39,0xe0,0x08,0x00,0xc2,0x24, +0x86,0x88,0x02,0x0c,0x1a,0x88,0xf8,0x1c,0x9b,0xe0,0x08,0x00,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0x20,0xea,0x03,0x1d,0xf0,0x36,0x61,0x00,0x98,0x02,0x81, +0x44,0x39,0xcc,0x49,0xb1,0x32,0x39,0x86,0x01,0x00,0x0b,0xa9,0x0c,0x0b,0xa0, +0xb8,0x83,0xa6,0x1b,0x78,0x31,0xd8,0x38,0xf8,0x33,0x0c,0x02,0xc8,0xcf,0xad, +0x0f,0x76,0x9c,0x0a,0xd2,0x2a,0x10,0xa2,0xca,0x10,0xb7,0x1d,0x01,0x1b,0x22, +0xc7,0xb2,0x5c,0xe2,0x2f,0x45,0xe7,0x12,0x52,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c, +0xd1,0x3e,0x39,0xed,0x01,0x22,0x6f,0x45,0x88,0x03,0x0c,0x19,0x82,0x28,0x10, +0x99,0x01,0xe0,0x08,0x00,0xa8,0x01,0xf8,0x03,0x9c,0x9a,0x1c,0x9a,0x0c,0x0b, +0x0c,0x4c,0x81,0x6c,0x39,0x80,0xe2,0x01,0x80,0xee,0x20,0x82,0x2f,0x10,0xd1, +0x34,0x39,0xe0,0x08,0x00,0xc6,0x05,0x00,0xbd,0x02,0x1c,0xfa,0x88,0xff,0x0c, +0x0c,0xe0,0x08,0x00,0x0c,0x1a,0x88,0x03,0x1c,0x9b,0x88,0xf8,0x7c,0xfc,0xe0, +0x08,0x00,0x0c,0x72,0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x00,0x36,0x41,0x00,0x51, +0xb8,0x38,0x0c,0x16,0x58,0x35,0x7c,0xf4,0x82,0x25,0x45,0x31,0x0b,0x39,0xc0, +0x88,0x11,0x8a,0x55,0x52,0x25,0x10,0x81,0x19,0x39,0x37,0x95,0x04,0x0c,0x04, +0x46,0x01,0x00,0x80,0x85,0xc0,0x80,0x46,0x83,0x26,0x04,0x05,0x49,0x02,0x0c, +0x72,0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x36,0x41,0x00,0x38,0xf2,0x0c,0x0a,0x48, +0x42,0x88,0x32,0x9d,0x04,0x76,0xa8,0x04,0xa2,0x59,0x00,0x2b,0x99,0x88,0x22, +0x58,0x23,0x80,0x55,0xa0,0x58,0x05,0xa8,0xd2,0x58,0x15,0xb2,0x23,0x3a,0x58, +0x05,0xa5,0xe1,0xfd,0x88,0x22,0x98,0x23,0xc8,0x02,0xb8,0x12,0x5a,0xda,0xf0, +0xed,0x11,0xe0,0xe4,0xc0,0xc0,0xbb,0xc0,0x80,0x89,0xa0,0x88,0x08,0x1b,0xcb, +0xb0,0xcb,0xb3,0xc0,0xa2,0x21,0x88,0x38,0x99,0xa2,0x40,0xba,0x90,0x40,0x9d, +0x90,0x88,0x08,0x89,0xe2,0xd0,0x9e,0xa3,0x90,0xaa,0x90,0xf2,0x23,0x3a,0xf9, +0x92,0xd9,0xb2,0xb9,0x82,0x99,0x52,0x49,0x62,0xa9,0x72,0x1d,0xf0,0x00,0x36, +0x01,0x01,0x71,0xf8,0x38,0xb1,0x8d,0x38,0x1c,0xc8,0xc2,0x2b,0x10,0x4d,0x02, +0x28,0x0c,0x87,0x14,0x02,0xc6,0x21,0x00,0x51,0x76,0x38,0x42,0x61,0x14,0x30, +0x90,0x04,0x0c,0x1a,0xa0,0x00,0xf3,0x16,0x69,0x09,0x48,0x4c,0x48,0x74,0xa8, +0x64,0x25,0xf6,0xff,0xa8,0x74,0x65,0x1b,0x00,0x98,0x44,0x0f,0x20,0x01,0x22, +0x44,0x0c,0x0c,0x11,0x88,0x29,0x98,0x39,0x76,0xa8,0x02,0x40,0x09,0x8d,0x61, +0x7c,0x38,0x42,0x26,0x10,0x48,0x44,0x48,0x84,0x48,0x34,0x88,0x95,0xb8,0xf4, +0xa8,0x34,0x98,0x44,0xe8,0x24,0xf8,0x14,0xf9,0x51,0xe9,0x61,0x99,0x41,0xa9, +0x31,0x98,0x04,0xad,0x04,0xc8,0x19,0xd8,0x09,0xd9,0x01,0xc9,0x11,0x98,0x29, +0x99,0x21,0xe0,0x08,0x00,0x4c,0x0a,0xbd,0x04,0xe5,0xfd,0x01,0xb8,0x01,0xc8, +0x11,0xd8,0x21,0xe8,0x31,0xf8,0x41,0xa5,0xbb,0xfe,0xad,0x04,0xb8,0x51,0xc8, +0x61,0xe5,0xb0,0xfe,0x0c,0x19,0xc6,0x08,0x00,0xbd,0x03,0xcd,0x02,0xad,0x04, +0x25,0x1a,0xff,0x3d,0x0a,0x42,0x61,0x14,0x70,0x8a,0xc0,0x16,0x08,0x12,0xa2, +0x21,0x14,0xbd,0x03,0xe5,0xc5,0xfe,0x2d,0x0a,0x1d,0xf0,0x6d,0x0b,0x0c,0x09, +0x17,0x63,0x64,0x42,0x26,0x10,0x49,0x71,0x48,0x44,0x48,0x84,0x88,0x95,0xb2, +0x24,0x24,0xd8,0x04,0xc2,0x24,0x18,0xe2,0x24,0x1a,0x92,0x24,0x1c,0xa2,0x24, +0x1b,0xa9,0xb1,0x99,0xd1,0xad,0x04,0x92,0x24,0x19,0xf8,0x0e,0xc8,0x2c,0xd2, +0x2d,0x13,0xd9,0xc1,0xc9,0xe1,0xf9,0x81,0x98,0x29,0xf8,0x1e,0xf9,0x91,0x99, +0xf1,0xe8,0x2e,0xe9,0xa1,0xe0,0x08,0x00,0xa2,0xa0,0x94,0xbd,0x04,0x25,0xf5, +0x01,0xb8,0x81,0xc8,0x91,0xd8,0xa1,0xe8,0xb1,0xf8,0xc1,0x25,0x74,0xfe,0xad, +0x04,0xb8,0xd1,0xc8,0x71,0xd8,0xe1,0xe8,0xf1,0x25,0x5a,0xfe,0x0c,0x19,0x27, +0x63,0x44,0xc2,0x26,0x10,0x88,0x95,0x48,0x3c,0xc8,0x0c,0x48,0x74,0xc2,0x61, +0x10,0x98,0x54,0xb8,0xa4,0xa8,0xb4,0xa2,0x61,0x12,0xb2,0x61,0x11,0xad,0x04, +0xb8,0xd4,0x98,0x39,0x92,0x61,0x13,0xe0,0x08,0x00,0x52,0x21,0x13,0x3c,0x8a, +0xbd,0x04,0x25,0xf0,0x01,0xdd,0x05,0xb2,0x21,0x10,0xc2,0x21,0x12,0xe5,0x43, +0xfe,0xad,0x04,0xb2,0x21,0x11,0xa5,0x3d,0xfe,0x0c,0x19,0x37,0x63,0x0b,0xa2, +0x26,0x10,0xa8,0x4a,0xa8,0x1a,0xa5,0xb6,0xfe,0x0c,0x19,0x47,0x63,0x0b,0xa2, +0x26,0x10,0xa8,0x3a,0xa8,0x1a,0xa5,0xb5,0xfe,0x0c,0x19,0x16,0xe9,0xf1,0x41, +0xd0,0x38,0x51,0xd1,0x38,0xc2,0x04,0x80,0xb2,0x04,0x81,0x00,0xcc,0x23,0x00, +0xbb,0x23,0xc7,0x2b,0x1f,0xb2,0x14,0x3f,0xc1,0x23,0x38,0x62,0x14,0x3e,0xc8, +0xec,0xad,0x06,0xca,0xbb,0xcd,0x02,0xb8,0x0b,0xa5,0x08,0xff,0xbd,0x0a,0x77, +0x1a,0x0f,0xad,0x06,0x25,0xb5,0xfe,0x8b,0x44,0x57,0x94,0xcb,0x46,0xb8,0xff, +0x00,0x00,0x00,0x7c,0xf2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xbd,0x03, +0xad,0x02,0x88,0x02,0xc8,0x82,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0xa2, +0xc2,0x14,0x0c,0x0b,0x65,0xc7,0x01,0xa2,0xc2,0x1c,0x0c,0x0b,0xe5,0xc6,0x01, +0x88,0x92,0x0c,0x0c,0xf0,0x88,0x11,0x80,0x82,0x41,0xa6,0x18,0x1b,0x0c,0x0a, +0x0f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0xb8,0xa2,0xa0,0x2b,0xc6,0x98,0x92, +0x1b,0xaa,0xf0,0x99,0x11,0x90,0x92,0x41,0x97,0x2a,0xed,0xc9,0x22,0x1d,0xf0, +0x36,0x41,0x00,0xa8,0xa2,0xa5,0xd0,0xfd,0xa8,0xb2,0x65,0xd0,0xfd,0xa8,0xc2, +0x25,0xd0,0xfd,0xa8,0xd2,0xa5,0xcf,0xfd,0xa8,0xe2,0x65,0xcf,0xfd,0xa8,0x02, +0x65,0xed,0xfd,0xa8,0x12,0x25,0xed,0xfd,0xa2,0x22,0x12,0x0c,0x0b,0xe5,0xcc, +0xfd,0xa2,0x22,0x16,0x65,0xcf,0xfd,0xa2,0x22,0x17,0x65,0xc1,0xfd,0x1d,0xf0, +0x36,0x41,0x00,0xa8,0x22,0xe5,0xcc,0xfd,0xa8,0x32,0xa5,0xcc,0xfd,0xa8,0x52, +0x0c,0x1b,0xa5,0xca,0xfd,0xb8,0x42,0xad,0x0b,0x88,0x8b,0xb8,0x0b,0xe0,0x08, +0x00,0xa8,0x82,0xe5,0xbe,0xfd,0xa8,0xc2,0xb1,0xf0,0x37,0xa5,0xbd,0x01,0x1d, +0xf0,0x00,0x00,0x36,0x41,0x00,0x31,0x8f,0x38,0x41,0x8f,0x38,0x51,0x52,0x38, +0x61,0xe6,0x37,0x0c,0xa8,0x98,0xe6,0xa1,0x8d,0x38,0xa2,0x69,0x32,0x82,0x69, +0x33,0xc2,0x03,0x80,0xb2,0x03,0x81,0x00,0xcc,0x23,0x00,0xbb,0x23,0xc7,0x2b, +0x22,0x9c,0x02,0xd2,0x13,0x41,0x57,0x1d,0x1a,0xa2,0x13,0x3e,0xb1,0x45,0x38, +0xe5,0xd2,0xff,0x86,0x03,0x00,0xc8,0xe6,0xb2,0x13,0x3f,0xa2,0x13,0x3e,0xca, +0xbb,0xb8,0x0b,0xe5,0xd1,0xff,0x8b,0x33,0x47,0x93,0xc8,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0xbd,0x03,0x5c,0x8a,0xa5,0xd6,0x01,0x3d,0x0a,0xb8,0x02, +0x65,0xf6,0x07,0x39,0x52,0xe5,0xda,0x01,0x3d,0x0a,0xa8,0x32,0xbd,0x03,0xa5, +0x83,0xfc,0xa8,0x42,0xbd,0x03,0xa5,0x76,0xfc,0xad,0x03,0x65,0xd3,0x01,0x65, +0xd9,0x01,0x3d,0x0a,0xa8,0x62,0xbd,0x03,0x25,0x73,0xfc,0xad,0x03,0x65,0xd2, +0x01,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xb8,0x13,0xad,0x02,0xb8,0x0b,0xa5, +0x4d,0x01,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xb8,0x33,0xa2,0xc2,0x14,0xa5, +0x4c,0x01,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x88,0x13,0x0c, +0x4b,0x88,0x08,0x00,0x14,0x40,0x00,0x48,0xa1,0xa5,0xcc,0x01,0xbd,0x04,0x3d, +0x0a,0xa5,0x4a,0x01,0x39,0x02,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x48, +0x03,0x0c,0x4b,0x48,0x04,0x25,0xcb,0x01,0xbd,0x04,0x3d,0x0a,0x25,0x49,0x01, +0x39,0x02,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x48,0x13,0x0c, +0x4b,0x48,0x04,0x65,0xc9,0x01,0xbd,0x04,0x3d,0x0a,0x65,0x47,0x01,0x39,0x02, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x48,0x13,0x0c,0x4b,0x48, +0x04,0xa5,0xc7,0x01,0xbd,0x04,0x3d,0x0a,0xa5,0x45,0x01,0x39,0x02,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x41,0x00,0xb8,0x13,0xad,0x02,0xb8,0x8b,0x65,0x44,0x01, +0xb8,0x13,0x8b,0xa2,0xb8,0x8b,0x65,0x96,0xfc,0xb8,0x13,0xa2,0xc2,0x10,0xb8, +0x3b,0x25,0x43,0x01,0xb8,0x13,0xa2,0xc2,0x18,0xb8,0x0b,0xa5,0x42,0x01,0x1d, +0xf0,0x00,0x36,0x41,0x00,0xad,0x02,0xa5,0x18,0xfd,0x1d,0xf0,0x00,0x00,0x36, +0x41,0x00,0xad,0x02,0xe5,0x17,0xfd,0x8b,0xa2,0xa5,0x17,0xfd,0x1d,0xf0,0x00, +0x36,0x41,0x00,0xad,0x02,0xe5,0x16,0xfd,0xb8,0x03,0x8b,0xa2,0xb8,0x7b,0xa5, +0xf5,0xfc,0xc8,0x03,0xb8,0x13,0xc8,0x6c,0xb2,0x2b,0x28,0xa2,0xc2,0x10,0xc0, +0xbb,0x90,0x65,0x3e,0x01,0xa2,0xc2,0x18,0xe5,0x14,0xfd,0xa2,0xc2,0x20,0x65, +0x14,0xfd,0xa2,0xc2,0x28,0x25,0x14,0xfd,0xb8,0x13,0xa2,0xc2,0x30,0xb2,0x2b, +0x17,0x25,0x8f,0xfc,0xa2,0xc2,0x38,0x25,0x13,0xfd,0xa2,0xc2,0x44,0xa5,0x12, +0xfd,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0xa5,0xbc,0x01, +0x3d,0x0a,0x65,0x11,0xfd,0x39,0x02,0x1d,0xf0,0x00,0x36,0x41,0x00,0xb8,0x63, +0xad,0x02,0x8b,0xbb,0xa5,0x39,0x01,0x8b,0xa2,0x25,0x10,0xfd,0x1d,0xf0,0x00, +0x36,0x41,0x00,0xbd,0x03,0x4c,0x4a,0x65,0xbd,0x01,0xc8,0x02,0x3d,0x0a,0xb8, +0x1c,0xc8,0x0c,0xa5,0x99,0xfd,0x39,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41, +0x00,0xad,0x02,0xa5,0x0d,0xfd,0x8b,0xa2,0x65,0x0d,0xfd,0xa2,0xc2,0x10,0xb8, +0xe6,0x25,0x36,0x01,0xa2,0xc2,0x18,0xb8,0x14,0xc8,0x24,0xa5,0xa8,0xfc,0xa2, +0xc2,0x24,0xb8,0xa6,0x65,0x87,0xfc,0xa2,0xc2,0x2c,0xb8,0xa6,0x65,0x34,0x01, +0xa2,0xc2,0x34,0xb8,0xa6,0xe5,0x33,0x01,0xa2,0xc2,0x3c,0xb8,0xa6,0x65,0x33, +0x01,0xa2,0xc2,0x44,0xb8,0xa6,0xe5,0x32,0x01,0xb8,0xa6,0xa2,0xc2,0x4c,0xe5, +0x84,0xfc,0xa2,0xc2,0x54,0xb8,0x14,0x65,0x84,0xfc,0xb8,0x14,0xa2,0xc2,0x5c, +0xe5,0x83,0xfc,0xa2,0xc2,0x64,0xe5,0x07,0xfd,0xa2,0xc2,0x6c,0x65,0x07,0xfd, +0xa2,0xc2,0x74,0x25,0x07,0xfd,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c, +0x4b,0x25,0xb1,0x01,0xbd,0x03,0x4d,0x0a,0x25,0xe5,0xfc,0x49,0x02,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0xa5,0xaf,0x01,0x3d,0x0a, +0x65,0x04,0xfd,0x39,0x02,0x0c,0x8a,0x0c,0x4b,0xa5,0xae,0x01,0x3d,0x0a,0xa5, +0x03,0xfd,0x39,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x88,0x03,0xa2, +0xc2,0x10,0x38,0x78,0xb2,0xc2,0x18,0xcd,0x03,0x25,0x1f,0xfc,0xa2,0xc2,0x24, +0xcb,0xb2,0xcd,0x03,0x65,0x1e,0xfc,0xa2,0xc2,0x20,0x8b,0xb2,0xcd,0x03,0xe5, +0x1d,0xfc,0xcd,0x03,0xa2,0xc2,0x14,0xb2,0xc2,0x1c,0x25,0x1d,0xfc,0xad,0x02, +0x4b,0xb2,0xa5,0x09,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x48, +0x03,0x0c,0x4b,0x48,0x74,0x65,0xa9,0x01,0xbd,0x04,0x3d,0x0a,0x25,0x9c,0xfc, +0x39,0x42,0xad,0x02,0x4b,0xb2,0xa5,0x07,0x00,0x8b,0xa2,0xcb,0xb2,0x25,0x07, +0x00,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02,0xb8,0x73,0xa5,0xdb,0xfc,0xb8, +0x73,0x8b,0xa2,0x25,0xdb,0xfc,0xa2,0xc2,0x10,0x65,0xfb,0xfc,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0xad,0x02,0xa5,0xfa,0xfc,0x8b,0xa2,0x65,0xfa,0xfc, +0xa2,0xc2,0x10,0xe5,0xf9,0xfc,0xa2,0xc2,0x18,0xb8,0x73,0xa5,0xd8,0xfc,0xa2, +0xc2,0x20,0xb8,0x73,0x25,0xd8,0xfc,0xa2,0xc2,0x28,0xb8,0x73,0xa5,0xd7,0xfc, +0xa2,0xc2,0x30,0xb8,0x73,0x25,0xd7,0xfc,0xa2,0xc2,0x38,0xb8,0x73,0xa5,0xd6, +0xfc,0xa2,0xc2,0x40,0xb8,0x73,0x25,0xd6,0xfc,0xb8,0x73,0xa2,0xc2,0x48,0xa5, +0xd5,0xfc,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0xc1,0x05,0x37, +0xbd,0x03,0xc2,0x2c,0x1c,0xa5,0xf1,0xfc,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0x39,0x02,0x4b,0xa2,0x65,0xf4,0xfc,0xcb,0xa2,0xe5,0xf3,0xfc,0xa2,0xc2,0x14, +0xa5,0xf3,0xfc,0xa2,0xc2,0x1c,0xbd,0x03,0x65,0xd2,0xfc,0xbd,0x03,0xa2,0xc2, +0x24,0xe5,0xd1,0xfc,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02,0x4b,0xb2,0x48, +0x03,0x7c,0xc8,0x68,0x44,0x48,0x74,0x4b,0x66,0x80,0x66,0x10,0xe5,0xfa,0xff, +0x0c,0x8a,0x0c,0x4b,0x65,0x9b,0x01,0x5d,0x0a,0x25,0xf0,0xfc,0x59,0x42,0xa2, +0xc2,0x14,0xb2,0xc2,0x38,0xa5,0xf9,0xff,0xa2,0xc2,0x20,0xb2,0xc2,0x40,0xcd, +0x04,0xa5,0x39,0xfc,0xa2,0xc2,0x24,0xb2,0xc2,0x28,0x65,0xf8,0xff,0xa2,0xc2, +0x2c,0xb2,0xc2,0x34,0xa5,0xf7,0xff,0x0c,0x8a,0x0c,0x4b,0x25,0x98,0x01,0x5d, +0x0a,0xe0,0xb4,0x11,0x1c,0x0c,0x25,0xc4,0xfc,0xcd,0x04,0x59,0xc2,0xa2,0xc2, +0x44,0xb2,0xc2,0x48,0xa5,0x36,0xfc,0x0c,0x4a,0x0c,0x4b,0x25,0x96,0x01,0xa2, +0x62,0x19,0x0c,0x4b,0x0c,0x8a,0xa5,0x95,0x01,0xbd,0x06,0x4d,0x0a,0xa5,0x13, +0x01,0x42,0x62,0x14,0xa2,0xc2,0x54,0xb2,0xc2,0x58,0xa5,0xf3,0xff,0xa2,0xc2, +0x5c,0xb2,0xc2,0x60,0x25,0xf3,0xff,0x1c,0x8a,0x0c,0x4b,0x65,0x93,0x01,0xb8, +0x03,0x3d,0x0a,0xa5,0x18,0xfc,0x32,0x62,0x1a,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x00,0x0c,0x1a,0xb8,0x12,0x25,0x95,0x01,0x88,0x42,0xa9,0x12,0xc8,0x32, +0xad,0x02,0xb2,0x2c,0x13,0xc2,0x2c,0x14,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0x68,0x02,0x78,0x14,0x68,0x16,0x48,0x15,0x62,0x26,0x07, +0x22,0x23,0x01,0x76,0xa6,0x15,0x40,0x03,0x8c,0xaf,0xe2,0x44,0xa2,0xd0,0x00, +0x07,0x08,0xaf,0xe0,0x0a,0x22,0xd0,0x00,0x87,0x08,0x30,0x02,0x8d,0x1d,0xf0, +0x36,0x41,0x00,0x0c,0x4a,0xb8,0x12,0x65,0x90,0x01,0x4d,0x0a,0xa5,0xcf,0xff, +0xbd,0x03,0x49,0x12,0x88,0x82,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41, +0x00,0x0c,0x1a,0xb8,0x12,0xa5,0x8e,0x01,0xbd,0x03,0xcd,0x04,0xdd,0x05,0xed, +0x06,0xa9,0x12,0x88,0x42,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x00, +0x36,0x81,0x00,0x39,0x41,0x0c,0x4a,0xb8,0x12,0x65,0x8c,0x01,0xb8,0x02,0xb8, +0x0b,0x3d,0x0a,0xb8,0x7b,0xe5,0xd6,0xff,0xbd,0x04,0xcd,0x05,0xdd,0x06,0xed, +0x07,0xa8,0x41,0x39,0x12,0x29,0x01,0x88,0x22,0xf2,0x21,0x10,0xe0,0x08,0x00, +0x1d,0xf0,0x00,0x36,0x61,0x00,0x38,0x22,0x1c,0x4a,0xb8,0x12,0x78,0x02,0x68, +0x32,0x78,0x07,0x68,0x06,0x78,0x67,0x68,0x16,0xa5,0x88,0x01,0x5d,0x0a,0xb8, +0x02,0xe5,0xda,0xff,0x59,0x12,0xb8,0x13,0xa8,0x52,0xe5,0x57,0x01,0xdd,0x0a, +0x8f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0x6f,0xe8,0x00,0x22,0x44,0x0c,0x0c, +0x11,0xef,0x87,0x01,0x62,0xc0,0x80,0x84,0x00,0x0f,0xe0,0x7c,0x22,0xa4,0x00, +0x00,0x00,0x0c,0x09,0x2f,0x21,0x01,0x22,0x48,0x00,0x00,0x01,0x70,0x82,0x21, +0xcf,0x00,0x04,0x28,0x44,0x0c,0x0c,0x11,0x76,0xa8,0x1f,0xb8,0x03,0xb8,0x1b, +0xb0,0xe9,0x87,0xa8,0x83,0xaf,0xe0,0x0a,0x22,0xd0,0x30,0x9f,0x08,0xa8,0x1a, +0xaf,0xe0,0x0a,0x22,0xc8,0x30,0x97,0x09,0x90,0xea,0xc6,0x1b,0x99,0xc8,0x83, +0x48,0x62,0x2c,0x8a,0xe8,0x44,0xb8,0x34,0xd9,0x1e,0xc9,0x0e,0xe5,0x80,0x01, +0x5d,0x0a,0xbd,0x04,0xa5,0xcf,0xff,0xad,0x04,0x82,0x24,0x17,0x59,0x34,0xe0, +0x08,0x00,0x26,0x56,0x1e,0x58,0x72,0x0c,0x8a,0xb8,0x15,0x25,0x7f,0x01,0x4d, +0x0a,0xa5,0xcb,0xff,0xad,0x05,0xbd,0x01,0xc8,0x35,0x88,0xa5,0xc8,0x0c,0x49, +0x15,0xc8,0x1c,0xe0,0x08,0x00,0xa8,0x82,0x88,0x5a,0xe0,0x08,0x00,0xa8,0xb3, +0x98,0x01,0x99,0x0a,0x28,0x01,0x1d,0xf0,0x00,0x36,0x41,0x00,0x5c,0x0a,0xb8, +0x52,0x25,0x7c,0x01,0x7d,0x0a,0xb8,0x02,0xa5,0xd2,0xff,0xbd,0x03,0xcd,0x04, +0xdd,0x05,0xed,0x06,0x79,0x52,0xad,0x02,0xf8,0x42,0x0c,0x18,0x80,0x00,0xf3, +0x82,0x22,0x20,0xf8,0x2f,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x36,0x61,0x00, +0x1c,0x8a,0xb2,0x22,0x14,0x72,0x22,0x11,0x39,0x01,0x78,0x17,0xa5,0x78,0x01, +0xb2,0x22,0x11,0x3d,0x0a,0xb8,0x0b,0x25,0xcd,0xff,0xb8,0x01,0xc2,0x22,0x18, +0x32,0x62,0x14,0x9c,0x8c,0xf2,0x27,0x38,0xd2,0x27,0x37,0xd9,0x97,0xcd,0x04, +0xdd,0x05,0xed,0x06,0xf9,0xa7,0x82,0x22,0x17,0xad,0x02,0xe0,0x08,0x00,0x1d, +0xf0,0xf2,0x27,0x36,0x92,0x27,0x35,0x99,0x97,0x86,0xf8,0xff,0x00,0x36,0x41, +0x00,0xbd,0x03,0x32,0x22,0x1a,0x38,0x03,0xa2,0xa0,0x6c,0x38,0x73,0xe5,0x73, +0x01,0x4d,0x0a,0xb2,0x22,0x1a,0x25,0xd3,0xff,0x42,0x62,0x1c,0x2c,0xca,0x1c, +0x0b,0x65,0x6f,0x01,0xbd,0x03,0x4d,0x0a,0x65,0xcf,0xff,0xb2,0x22,0x1c,0x49, +0x7b,0x8b,0xab,0xcb,0xbb,0x65,0xcd,0xff,0xb2,0x22,0x1c,0xa2,0xcb,0x4c,0xb2, +0xcb,0x3c,0xa5,0xcc,0xff,0xc2,0x22,0x1c,0xc8,0x7c,0xd2,0x22,0x23,0xc2,0xcc, +0x1c,0xc9,0x6d,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0xbd,0x03,0xe5, +0x99,0xfc,0x8b,0xa2,0xbd,0x03,0x65,0x99,0xfc,0xa2,0xc2,0x10,0xbd,0x03,0xe5, +0x98,0xfc,0xa2,0xc2,0x18,0xbd,0x03,0x65,0x98,0xfc,0xa2,0xc2,0x20,0xbd,0x03, +0x65,0xe8,0x00,0xa2,0xc2,0x28,0xbd,0x03,0x65,0x97,0xfc,0xbd,0x03,0xa2,0xc2, +0x30,0xe5,0x96,0xfc,0x1c,0x0a,0x1c,0x0b,0x65,0x68,0x01,0xa9,0xe2,0x1c,0x0b, +0x1c,0x0a,0xe5,0x67,0x01,0xa9,0xf2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00, +0x0c,0x08,0x98,0x22,0x78,0x02,0x1b,0x63,0x78,0x07,0x38,0x14,0x48,0x77,0x59, +0x42,0x59,0x32,0x97,0x26,0x0a,0x89,0x12,0x1b,0xa9,0xa9,0x22,0x46,0x01,0x00, +0x00,0x00,0x0c,0x1b,0xb9,0x12,0x2d,0x03,0x76,0xa4,0x04,0x82,0x42,0x00,0x1b, +0x22,0x1d,0xf0,0x00,0x36,0x41,0x00,0xa8,0xc2,0x4f,0x04,0x44,0x43,0x44,0x0c, +0x0c,0x11,0x0c,0x39,0xcc,0x65,0x88,0x52,0x78,0x62,0x06,0x01,0x00,0x00,0x88, +0x72,0x78,0x82,0x76,0xaa,0x1d,0x40,0x41,0x8c,0x0f,0xe0,0xe0,0x43,0x44,0x0c, +0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x7a,0x12,0x0c,0x10,0x8f,0x10,0xa0,0x48,0x72, +0x02,0x14,0x10,0x10,0x03,0x8d,0xcc,0x55,0x89,0x52,0x79,0x62,0xc6,0x00,0x00, +0x89,0x72,0x79,0x82,0x0c,0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x4c, +0x0a,0xe5,0x61,0x01,0xb8,0x82,0xb8,0x1b,0xb8,0xfb,0x3d,0x0a,0xb8,0x0b,0x65, +0xf1,0xff,0x39,0x92,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0xcd,0x04,0xdd, +0x05,0x82,0x22,0x61,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x36,0x41,0x00, +0xad,0x02,0xe5,0xb0,0xfc,0x8b,0xa2,0xa5,0xb0,0xfc,0xa2,0xc2,0x10,0x25,0xb0, +0xfc,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0x48,0x03,0x4b,0xb2, +0x48,0x74,0x25,0xb9,0xff,0x8b,0xa2,0xcb,0xb2,0xa5,0xb8,0xff,0xa2,0xc2,0x10, +0xb2,0xc2,0x14,0x25,0xb8,0xff,0xa2,0xc2,0x18,0xb2,0xc2,0x1c,0x65,0xb7,0xff, +0xa2,0xc2,0x20,0xb2,0xc2,0x28,0xe5,0xb6,0xff,0xa2,0xc2,0x2c,0xb2,0xc2,0x30, +0x65,0xb6,0xff,0xa2,0xc2,0x38,0xb2,0xc2,0x3c,0xe5,0xb5,0xff,0xa2,0xc2,0x40, +0xb2,0xc2,0x44,0x25,0xb5,0xff,0xcd,0x04,0xa2,0xc2,0x24,0xb2,0xc2,0x34,0x65, +0xf5,0xfb,0x1c,0x8a,0x0c,0x4b,0xe5,0x54,0x01,0xb8,0x03,0x3d,0x0a,0x25,0xda, +0xfb,0x32,0x62,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x1c,0x0a,0xb8, +0x12,0xa5,0x56,0x01,0x5d,0x0a,0xe5,0x8f,0xff,0xad,0x03,0xbd,0x04,0x59,0x12, +0xdd,0x02,0xe8,0x02,0x88,0xb2,0x0c,0x0c,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00, +0x36,0x41,0x00,0x58,0x02,0x78,0x14,0x88,0x13,0x48,0x12,0x0c,0x03,0x50,0x52, +0x41,0x9c,0x95,0x70,0x43,0x8c,0x80,0x03,0x8c,0xaf,0xe0,0x0a,0x22,0xd0,0x00, +0x87,0x08,0x30,0x04,0x8d,0x68,0x02,0x1b,0x33,0x60,0x62,0x41,0x67,0x33,0xe4, +0x1d,0xf0,0x00,0x36,0x81,0x00,0x1c,0x8a,0xb8,0x12,0x49,0x61,0x39,0x51,0x25, +0x51,0x01,0x4d,0x0a,0x65,0xf1,0xff,0x38,0x61,0x49,0x12,0xa8,0x54,0x81,0xa4, +0x35,0xc8,0x44,0x88,0x88,0x0c,0x0b,0xe0,0x08,0x00,0xd8,0x02,0x98,0x13,0xd8, +0x2d,0xb8,0x12,0xd8,0x2d,0xb8,0x5b,0x0b,0xdd,0xd0,0xc2,0x21,0xa6,0x1c,0x0b, +0x76,0xac,0x05,0x90,0x03,0x8c,0x30,0x0b,0x8d,0x46,0x00,0x00,0x0c,0x0c,0xe0, +0xec,0x11,0xe0,0xed,0xc0,0x76,0xae,0x05,0x90,0x01,0x8c,0x10,0x0b,0x8d,0x0c, +0x0b,0x48,0x17,0x88,0x02,0x38,0x16,0x88,0x08,0xa8,0x15,0x98,0x48,0xf8,0x88, +0xf9,0x41,0x88,0x78,0xa0,0x99,0xa0,0x0b,0x88,0x8a,0x33,0x8a,0x44,0x76,0xaf, +0x03,0xb9,0x09,0x4b,0x99,0xcd,0x05,0xdd,0x06,0xed,0x07,0xa8,0x51,0xf2,0x03, +0x00,0x88,0x41,0x0c,0xfb,0x00,0x08,0x40,0xb0,0xb0,0xb1,0xb0,0xff,0x10,0xf2, +0x43,0x00,0x92,0x04,0x00,0xfd,0x02,0xb0,0x99,0x10,0x92,0x44,0x00,0xb8,0x12, +0x88,0x02,0x89,0x01,0x88,0x92,0xb2,0xcb,0x10,0xe0,0x08,0x00,0x1d,0xf0,0x36, +0x41,0x00,0x0c,0x8a,0xb8,0x12,0x65,0x46,0x01,0x5d,0x0a,0xe5,0x7e,0xff,0xd8, +0x02,0x88,0x22,0xd8,0x1d,0x59,0x12,0xd7,0x18,0x13,0x4b,0xad,0x88,0x42,0xb8, +0x0d,0x82,0x28,0x1d,0xc8,0x32,0xe0,0x08,0x00,0x98,0x02,0x98,0x19,0x99,0x22, +0x8c,0xc4,0xad,0x03,0x88,0x42,0xbd,0x03,0x82,0x28,0x1e,0xc8,0x32,0xe0,0x08, +0x00,0x1d,0xf0,0x36,0xe1,0x00,0xad,0x02,0xb8,0x12,0x52,0x61,0x10,0x62,0x61, +0x11,0x25,0x84,0xff,0xe2,0x21,0x11,0x62,0x22,0x25,0xd2,0x21,0x10,0xcc,0xd6, +0x88,0x02,0x88,0x08,0x82,0x08,0x00,0x00,0x88,0x23,0x89,0xf1,0x06,0x01,0x00, +0x92,0x26,0x35,0x99,0xf1,0xcc,0xb6,0x58,0x02,0x58,0x05,0x52,0x05,0x98,0x00, +0x55,0x23,0x86,0x00,0x00,0x52,0x26,0x36,0xfd,0x07,0x92,0x21,0x20,0xc2,0x21, +0x1d,0xb2,0x21,0x1e,0x82,0x21,0x1c,0xa2,0x21,0x1f,0xa9,0x31,0x89,0x01,0xb9, +0x21,0xc9,0x11,0x99,0x41,0x72,0x21,0x24,0x98,0xf1,0x79,0x81,0xc2,0x21,0x22, +0xb2,0x21,0x23,0x82,0x21,0x21,0x89,0x51,0xb9,0x71,0xc9,0x61,0xbd,0x03,0xa8, +0x06,0xcd,0x04,0xa8,0x1a,0xa9,0x91,0x99,0xa1,0x59,0xb1,0x82,0x22,0x2f,0xad, +0x02,0xe0,0x08,0x00,0x6d,0x0a,0xac,0xf5,0x58,0x22,0x98,0x57,0xa8,0x13,0xa9, +0xc1,0x99,0xd1,0x1c,0x0a,0xb8,0x15,0x25,0x39,0x01,0xb8,0x05,0xa9,0xe1,0xb8, +0x0b,0xa5,0x79,0xff,0xc8,0xd1,0xed,0x05,0xdd,0x06,0xb8,0xc1,0x98,0x05,0xf8, +0xe1,0xf9,0x15,0x99,0x01,0x88,0x25,0xad,0x0b,0xe0,0x08,0x00,0xa8,0x17,0xb8, +0x13,0x31,0x3e,0x35,0xc8,0x07,0x38,0xa3,0xe0,0xcc,0x11,0xe0,0x03,0x00,0x8c, +0xc4,0xa8,0x14,0xb8,0x12,0xc8,0x04,0xb8,0xbb,0xe0,0xcc,0x11,0xe0,0x03,0x00, +0x2d,0x06,0x1d,0xf0,0x00,0x00,0x36,0x81,0x00,0xa2,0xa0,0x90,0xb8,0x12,0x59, +0x41,0x39,0x51,0xa5,0x33,0x01,0xf8,0xd2,0xe8,0xc2,0xd8,0xb2,0xc8,0xa2,0xb8, +0x92,0x88,0xe2,0x58,0x51,0x89,0x01,0x38,0xf2,0x39,0x11,0x3d,0x0a,0x25,0x76, +0xff,0x92,0x21,0x11,0x88,0x22,0x39,0x12,0xc8,0x38,0x52,0x63,0x20,0x42,0x63, +0x22,0x62,0x63,0x21,0xb8,0x28,0xa8,0x18,0x92,0x63,0x23,0x32,0x21,0x12,0x88, +0x08,0xdd,0x03,0xe0,0x08,0x00,0xc8,0x32,0xa8,0x1c,0xb8,0x2c,0x88,0x0c,0xc8, +0x3c,0xe0,0x08,0x00,0xc8,0x42,0xdd,0x03,0xa8,0x1c,0xb8,0x2c,0x88,0x0c,0xc8, +0x3c,0xe0,0x08,0x00,0xd8,0x52,0xa8,0x1d,0xb8,0x2d,0xc8,0x3d,0x88,0x0d,0xd8, +0x4d,0xe0,0x08,0x00,0xc8,0x62,0xa8,0x1c,0xb8,0x2c,0x88,0x0c,0xc8,0x3c,0xe0, +0x08,0x00,0xd8,0x12,0xe2,0x2d,0x1c,0x8c,0x9e,0xc1,0xd0,0x35,0xb2,0xcd,0x6c, +0xad,0x0b,0xe5,0xa7,0x00,0xc8,0x72,0xbd,0x07,0xad,0x0c,0x88,0x4c,0xc8,0x5c, +0xe0,0x08,0x00,0xb2,0x21,0x10,0x9c,0x0b,0xa8,0x12,0x88,0x82,0x98,0x41,0xc8, +0x58,0x92,0x6a,0x22,0xad,0x08,0x88,0x48,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x68,0x12,0x78,0x13,0x48,0x02,0x0c,0x03,0x40,0x42,0x41,0x8c,0xe4, +0x70,0x03,0x8c,0x30,0x06,0x8d,0x58,0x02,0x1b,0x33,0x50,0x52,0x41,0x57,0x33, +0xef,0x1d,0xf0,0x00,0x00,0x36,0x81,0x00,0x39,0x41,0x4c,0xca,0xb8,0x22,0xe5, +0x25,0x01,0x3d,0x0a,0xb8,0x12,0x25,0x60,0xff,0x98,0x02,0x39,0x22,0xa6,0x19, +0x63,0x98,0xf2,0xa6,0x19,0x0c,0xa8,0x12,0x0b,0xb9,0xb9,0xf2,0xa9,0x51,0x0c, +0x1b,0x86,0x04,0x00,0xc8,0x12,0xc9,0x51,0x8c,0x96,0xd8,0x1c,0xe8,0x06,0xd8, +0x6d,0x0c,0x1b,0xe7,0x3d,0x01,0x0c,0x0b,0xbc,0xfb,0xb8,0x15,0xd8,0x51,0x92, +0x23,0x12,0xc8,0x0d,0xd8,0x1d,0xe2,0xa0,0xc0,0xea,0xdd,0xd0,0x40,0x0c,0xc8, +0x7c,0xcf,0x00,0x84,0x28,0x44,0x0c,0x0c,0x11,0xa6,0x1c,0x16,0x76,0xac,0x0d, +0xb0,0x83,0x8c,0xaf,0xe0,0x0a,0x22,0xc8,0x20,0x97,0x08,0x30,0x89,0x8d,0x38, +0x22,0xe8,0x12,0xe9,0x51,0x52,0xc3,0x44,0xc6,0x00,0x00,0xf8,0x12,0xf9,0x51, +0xbd,0x04,0xcd,0x05,0xdd,0x06,0xed,0x07,0xa8,0x41,0x29,0x01,0x98,0x51,0x99, +0x11,0x88,0xc2,0xf2,0x21,0x10,0xe0,0x08,0x00,0x2d,0x0a,0x1d,0xf0,0x00,0x00, +0x36,0x41,0x00,0xbd,0x03,0x4c,0xca,0x25,0x1c,0x01,0x3d,0x0a,0xb8,0x92,0xe5, +0xbd,0xff,0x39,0xa2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0xbd, +0x03,0x65,0x45,0xfc,0xbd,0x03,0x8b,0xa2,0xe5,0x44,0xfc,0x1c,0x0a,0x1c,0x0b, +0x65,0x16,0x01,0xa9,0x42,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0xcd,0x04,0xdd, +0x05,0xed,0x06,0xfd,0x07,0x88,0x42,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0xbd,0x03,0xcd,0x04,0xdd,0x05,0xed,0x06,0xfd,0x07,0x88, +0x92,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0xca, +0xb8,0x12,0xe5,0x15,0x01,0x6d,0x0a,0xb8,0x02,0x65,0x42,0xff,0x38,0x13,0x69, +0x12,0x7d,0x03,0xbc,0xa5,0x66,0x25,0x10,0xb8,0x16,0xd8,0x02,0xc8,0x14,0xd8, +0x1d,0xa8,0x32,0xd8,0x0d,0x25,0xb3,0xff,0x48,0x12,0x8b,0xf2,0x98,0x14,0xf0, +0x80,0x0c,0xe8,0x04,0x4f,0x01,0x04,0x29,0x44,0x0c,0x0c,0x11,0xe0,0xe2,0x41, +0x76,0x9e,0x10,0x90,0x03,0x9c,0x70,0xc3,0x8c,0xaf,0xe0,0x0a,0x22,0xf8,0x30, +0x26,0x09,0x30,0xc3,0x8d,0x1d,0xf0,0x00,0x36,0x41,0x00,0x68,0x04,0x0c,0x4a, +0xb8,0x32,0x25,0x10,0x01,0x7d,0x0a,0xbd,0x02,0xc8,0x92,0xa5,0x3e,0xff,0xa2, +0xc2,0x14,0xcd,0x06,0x88,0x62,0x58,0x07,0x79,0x32,0xb8,0x15,0xe0,0x08,0x00, +0xa8,0x72,0xc8,0x15,0xd8,0x04,0xbd,0x0c,0x65,0xad,0xff,0x0c,0x09,0xb2,0xc2, +0x20,0xb0,0x80,0x0c,0x60,0xa2,0x41,0x4f,0x01,0x04,0x29,0x44,0x0c,0x0c,0x11, +0x76,0x9a,0x16,0xe8,0x15,0xd8,0x14,0xe0,0x29,0x97,0xd0,0xe9,0x87,0xef,0x87, +0x03,0x62,0xf8,0x30,0x26,0x09,0x90,0xec,0xc6,0x1b,0x99,0x1d,0xf0,0x00,0x36, +0x61,0x00,0xad,0x03,0x65,0xee,0x00,0xed,0x05,0x0c,0x0f,0xc8,0x82,0xb8,0x52, +0x0c,0x0d,0xd9,0x21,0xd9,0x11,0xd9,0x01,0x98,0x62,0x99,0x31,0x88,0x22,0xdd, +0x04,0xe0,0x08,0x00,0xc8,0x52,0xd8,0x82,0xbd,0x0a,0x88,0x32,0xa8,0x13,0xe0, +0x08,0x00,0xc8,0x52,0xd8,0x82,0x88,0x42,0x4d,0x0a,0xbd,0x04,0xa8,0x13,0xe0, +0x08,0x00,0x6f,0xf4,0x00,0x22,0x44,0x0c,0x0c,0x11,0x6f,0xe8,0x02,0x22,0x44, +0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x00,0x01,0x00,0x4f,0x00,0x28,0x48, +0x44,0x0c,0x0c,0x11,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x1a,0xb8, +0x12,0x25,0x04,0x01,0xbd,0x03,0xcd,0x04,0x82,0x22,0x1d,0xa9,0x12,0xe8,0x32, +0xad,0x02,0xd2,0x2e,0x2a,0xe2,0x2e,0x18,0xe0,0x08,0x00,0x82,0x22,0x10,0x89, +0x04,0xf2,0x22,0x1b,0xf9,0x03,0x1d,0xf0,0x36,0xe1,0x00,0xad,0x02,0xb2,0x22, +0x1c,0x82,0x22,0x1b,0x59,0xe1,0x68,0x08,0x78,0x28,0x68,0x06,0x88,0x48,0x89, +0xf1,0xa5,0x8b,0xff,0xf2,0x22,0x1c,0xcc,0x74,0xb2,0x22,0x1b,0xb8,0x0b,0x0c, +0x0a,0xa9,0x1b,0xcc,0x36,0x0c,0x0b,0x46,0x00,0x00,0xb8,0x3f,0xa8,0x2f,0x41, +0x1c,0x35,0xc8,0x33,0x82,0x24,0x81,0xc8,0x1c,0xe0,0x08,0x00,0xb2,0x22,0x1c, +0xa2,0x22,0x13,0xb8,0x2b,0x65,0xcd,0x00,0x0c,0x0f,0xe8,0x03,0x4d,0x0a,0xdd, +0x0a,0xc2,0x22,0x1c,0x5d,0x0a,0xb8,0xec,0xa8,0xb2,0xc8,0x5c,0x69,0x01,0x25, +0xd5,0xff,0x82,0x22,0x20,0xe2,0x22,0x1a,0x0c,0x0f,0xe8,0x0e,0xf9,0x48,0xe8, +0x7e,0xe2,0x61,0x11,0x16,0x86,0x13,0xb2,0x22,0x1c,0xa2,0x22,0x14,0xb8,0x3b, +0x10,0x11,0x20,0xe5,0xc9,0x00,0x0c,0x0f,0xe8,0x03,0xdd,0x0a,0xc2,0x22,0x1c, +0xa2,0x61,0x10,0xb8,0xfc,0xa8,0xc2,0xc8,0x5c,0x69,0x01,0xa5,0xd1,0xff,0xdd, +0x05,0xf2,0x22,0x1c,0x88,0xf2,0xe8,0xff,0xa2,0x2f,0x10,0xb2,0x2f,0x11,0xc2, +0x2f,0x12,0xf8,0xef,0xe9,0x01,0x89,0x11,0x98,0x08,0x99,0x21,0x88,0x18,0xe2, +0x21,0x10,0xe0,0x08,0x00,0xa1,0x4e,0x34,0xa8,0xfa,0x8c,0x1a,0xe0,0x0a,0x00, +0xb2,0x22,0x1b,0xb2,0x2b,0x34,0x16,0xeb,0x0b,0xdd,0x05,0x0c,0x0f,0xe8,0x03, +0xc2,0x22,0x1c,0xa8,0xd2,0xb2,0x2c,0x16,0xc8,0x5c,0x69,0x01,0xe5,0xcc,0xff, +0x92,0x22,0x1a,0x98,0x29,0x98,0x19,0xd8,0x59,0xda,0xd7,0xd2,0x0d,0x00,0x00, +0xdd,0x23,0xe6,0x1d,0x02,0x46,0xfe,0x00,0x92,0x21,0x10,0xb2,0x22,0x1e,0xa8, +0x42,0x59,0x0b,0x88,0x8a,0x99,0x1b,0xe0,0x08,0x00,0xb2,0xc1,0x30,0xc8,0x15, +0xd2,0x22,0x1c,0x81,0xe3,0x34,0xf2,0x22,0x1a,0x82,0x28,0x7e,0xe8,0x0f,0xa8, +0x8d,0xf8,0x1f,0xd2,0x2d,0x16,0xa8,0x1a,0xd8,0x1d,0xf2,0x2f,0x23,0xe0,0x08, +0x00,0xa8,0x12,0xcd,0x05,0xd2,0x22,0x1f,0xb2,0x22,0x1c,0xe8,0x03,0xb8,0x7b, +0x25,0x74,0xff,0xe2,0x22,0x23,0xf2,0x22,0x1c,0xd2,0x22,0x20,0xc8,0x7f,0xc9, +0x4d,0xc9,0x2e,0xb2,0x2f,0x13,0xa2,0x22,0x16,0xc8,0x43,0xd8,0x33,0x88,0x03, +0x89,0x0e,0x25,0x6f,0xff,0xa1,0x24,0x34,0xa8,0xfa,0x8c,0x1a,0xe0,0x0a,0x00, +0xb2,0x22,0x1c,0xa2,0x22,0x15,0xb2,0x2b,0x13,0x65,0xba,0x00,0xbd,0x05,0xcd, +0x0a,0x4d,0x0a,0x88,0x92,0xa2,0x22,0x1c,0xdd,0x08,0xe8,0x08,0x88,0x18,0xa2, +0x2a,0x14,0xe0,0x08,0x00,0x51,0xc4,0x34,0xb2,0x21,0x10,0x92,0x22,0x1e,0xa8, +0x52,0x49,0x09,0x88,0x8a,0xb9,0x19,0xe0,0x08,0x00,0x8c,0x66,0xc2,0x22,0x1b, +0xc2,0x2c,0x34,0xdc,0xcc,0x51,0xbd,0x34,0xd2,0x21,0x11,0x0f,0x20,0xa1,0x42, +0xe0,0x00,0x07,0x08,0x76,0xad,0x0c,0xe2,0x22,0x1c,0xe2,0x2e,0x14,0xe8,0x1e, +0x90,0x2e,0xc6,0x1b,0x99,0xdd,0x04,0x0c,0x0f,0xa8,0xa2,0xc2,0x22,0x1c,0xe8, +0x03,0xb2,0x2c,0x16,0xc8,0x5c,0x69,0x01,0x25,0xbd,0xff,0x82,0x25,0x7e,0xbd, +0x0a,0xe2,0x22,0x1a,0xd2,0x22,0x1c,0xf8,0x1e,0xc2,0x2d,0x19,0xe8,0x0e,0xa8, +0x8d,0xf2,0x2f,0x23,0xd2,0x2d,0x16,0xa8,0x1a,0xd8,0x1d,0xb9,0x0c,0xb2,0xc3, +0x24,0xc8,0x14,0xe0,0x08,0x00,0x8c,0xf6,0xa8,0x02,0xcd,0x04,0xd2,0x22,0x20, +0xb2,0x22,0x1c,0xe8,0x03,0xb8,0x7b,0xa5,0x66,0xff,0x92,0x22,0x1b,0x98,0x09, +0x98,0x19,0x16,0x89,0x04,0xd2,0x22,0x21,0x26,0x29,0x24,0xa8,0x5d,0xa2,0x2a, +0x00,0xa0,0xa2,0x41,0x2f,0x74,0x32,0x22,0xe0,0x00,0x07,0x08,0x92,0xa0,0x00, +0x76,0x9a,0x0b,0xb2,0x22,0x21,0xb8,0x5b,0xb8,0x1b,0x90,0x2b,0xc6,0x1b,0x99, +0xd2,0x22,0x21,0xc8,0xb3,0xb2,0x22,0x1c,0xa8,0x32,0xb2,0x2b,0x19,0x49,0x0d, +0xb8,0x0b,0xa5,0x51,0xff,0xa1,0xe5,0x33,0xa8,0xfa,0x9c,0x0a,0xe0,0x0a,0x00, +0xc6,0x02,0x00,0xb2,0x22,0x1c,0xa2,0x2b,0x15,0xb2,0x2b,0x16,0x65,0xb1,0xff, +0x16,0x16,0x07,0xc2,0x22,0x1b,0xc8,0x0c,0xc8,0x1c,0xac,0xdc,0xa2,0x22,0x1d, +0xd8,0x0a,0xd8,0x1d,0xd8,0x9d,0xd0,0xd7,0x90,0xd2,0x9d,0x00,0x9c,0xcd,0xc2, +0x22,0x1c,0xd8,0x53,0xe2,0x22,0x20,0xd8,0x1d,0xe8,0x3e,0xf2,0x2c,0x14,0xc8, +0x7c,0xf8,0x1f,0xe8,0x1e,0xb8,0x8c,0xc8,0xac,0x79,0x01,0x65,0x49,0xff,0xcd, +0x04,0x82,0x22,0x10,0xe2,0x22,0x1f,0xf2,0x22,0x1c,0xe8,0x0e,0xb8,0x9f,0xad, +0x08,0xf8,0x7f,0x88,0x38,0xd2,0xcf,0x1c,0xe0,0x08,0x00,0xcd,0x04,0x82,0x22, +0x11,0xe2,0x22,0x1f,0xf2,0x22,0x1c,0xe8,0x0e,0xb8,0xaf,0xad,0x08,0xf8,0x7f, +0x88,0x38,0xd2,0xcf,0x24,0xe0,0x08,0x00,0x06,0x09,0x00,0x00,0xf2,0x21,0x11, +0x0f,0x20,0xa1,0x42,0xe0,0x00,0x07,0x08,0x76,0xaf,0x15,0xa2,0x22,0x1c,0xa8, +0x9a,0xa8,0x1a,0x90,0x2a,0xc6,0x82,0x22,0x1c,0x88,0xa8,0x88,0x18,0x90,0x28, +0xc6,0x1b,0x99,0x16,0xa6,0x1d,0xb2,0x22,0x1a,0xb8,0x1b,0xb8,0xfb,0xb2,0x9b, +0x07,0xb2,0xcb,0xfe,0x16,0x7b,0x1c,0xec,0x86,0x46,0x71,0x00,0xe8,0x53,0xb8, +0x14,0xa2,0x22,0x17,0xd2,0x22,0x1c,0x0c,0x08,0xf8,0x9d,0xc2,0x2d,0x16,0xf8, +0x1f,0xd2,0x2d,0x15,0xc8,0x1c,0xd8,0x1d,0x89,0x01,0x88,0xe1,0x98,0x03,0x99, +0x11,0x89,0x21,0x25,0x98,0xff,0x92,0x22,0x1a,0x99,0xd1,0x98,0x19,0x92,0x61, +0x12,0x9c,0xf6,0xa8,0xf9,0xa2,0x9a,0x07,0x92,0x61,0x12,0xdc,0x5a,0xb2,0x22, +0x1c,0xa8,0x63,0xb8,0x9b,0xe5,0xa1,0xff,0xb2,0x22,0x1c,0xa8,0xdb,0xb8,0xab, +0x25,0xa1,0xff,0x86,0x12,0x00,0xd8,0x14,0x82,0x25,0x80,0xe8,0xd1,0xc2,0x22, +0x1c,0xa8,0x63,0xf2,0x21,0x12,0xa8,0x1a,0xf2,0x2f,0x1e,0xb8,0x9c,0xe8,0x0e, +0xc2,0x2c,0x16,0xe8,0x7e,0xf8,0x2f,0xb8,0x1b,0xc8,0x1c,0xe0,0x08,0x00,0xd8, +0x14,0x82,0x25,0x80,0xb2,0x22,0x1c,0xf2,0x22,0x1a,0xc8,0x5b,0xe8,0x0f,0xa8, +0xdb,0xf8,0x1f,0xa8,0x1a,0xc8,0x1c,0xe8,0x7e,0xb8,0xab,0xf2,0x2f,0x1e,0xb8, +0x1b,0xf8,0x2f,0xe0,0x08,0x00,0xa1,0x8a,0x33,0xa8,0xfa,0x8c,0x1a,0xe0,0x0a, +0x00,0x98,0xf1,0x0c,0x06,0x88,0x53,0xe8,0x63,0xb8,0x13,0xd2,0x22,0x1c,0xa2, +0x22,0x12,0xf8,0xdd,0xc2,0x2d,0x18,0x79,0x21,0x89,0x01,0x69,0x11,0x99,0x31, +0x98,0xed,0x69,0x51,0x99,0x41,0x82,0x2d,0x14,0x89,0x61,0x62,0x2d,0x16,0x69, +0x71,0xd2,0x2d,0x1a,0xd9,0x81,0xdd,0x04,0x65,0x7e,0xff,0xb8,0x63,0xe8,0x53, +0xd2,0x22,0x1c,0x62,0x22,0x12,0xc2,0x2d,0x16,0x68,0x16,0xd2,0x2d,0x14,0xa9, +0x73,0xa2,0x22,0x19,0x88,0x06,0x89,0xa3,0x68,0x16,0x25,0x30,0xff,0x92,0x22, +0x1b,0x82,0x29,0x31,0x8c,0x98,0xbd,0x06,0xa2,0x22,0x18,0x65,0x2d,0xff,0x92, +0x22,0x1b,0xa8,0x09,0xa8,0x1a,0x16,0x0a,0x05,0xa2,0x22,0x12,0xcd,0x04,0xb2, +0x22,0x1c,0xd8,0x13,0xb2,0x2b,0x17,0xe5,0x28,0xff,0x0c,0x0e,0xf8,0x53,0xa8, +0xe2,0xb2,0x22,0x1c,0x0c,0x18,0xd2,0x2b,0x17,0xb2,0x2b,0x18,0xcd,0x0d,0x89, +0x01,0x65,0x94,0xff,0xa8,0x72,0xe2,0x22,0x1c,0xd2,0x22,0x22,0x82,0x2e,0x1a, +0x49,0x0d,0xf8,0x53,0xf9,0x3d,0x89,0x2d,0xe2,0x2e,0x17,0xe9,0x1d,0xc8,0x13, +0xc9,0x4d,0x65,0x23,0xff,0xa1,0x5a,0x33,0xa8,0xfa,0x8c,0x1a,0xe0,0x0a,0x00, +0x82,0x25,0x7f,0xb2,0x22,0x1c,0xc2,0x22,0x12,0xb2,0x2b,0x1a,0xc8,0x0c,0xad, +0x0b,0xc8,0x0c,0xb2,0xcb,0x10,0xe0,0x08,0x00,0x92,0x22,0x1b,0xa9,0x83,0xc8, +0xe9,0x9c,0x0c,0xa8,0x82,0xd8,0x0a,0xd8,0x2d,0x8c,0x8d,0xcd,0x04,0xb8,0x13, +0x65,0x5e,0xff,0x92,0x22,0x1b,0xc8,0x99,0x8c,0xbc,0xa8,0x62,0xe8,0x0a,0xe8, +0x1e,0x8c,0x3e,0xb8,0x13,0x65,0x6d,0xff,0xc8,0x23,0xb8,0x13,0x88,0x22,0xb8, +0x1b,0xad,0x08,0x88,0x18,0xc8,0x1c,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x56,0x96, +0xe3,0x0c,0x0e,0x86,0x8d,0xff,0x0c,0xfa,0xc8,0x79,0xe2,0x22,0x23,0xca,0xc7, +0x98,0x6e,0xc2,0x0c,0x00,0x98,0x19,0x00,0xcc,0x23,0xa6,0x1c,0x20,0xd2,0x21, +0x11,0xa6,0x1d,0x0a,0x76,0xad,0x04,0xa2,0x49,0x00,0x1b,0x99,0xe2,0x22,0x23, +0x91,0xe2,0x33,0x99,0x2e,0x82,0x22,0x20,0xf2,0x22,0x1c,0x99,0x48,0xc6,0x08, +0xff,0xb2,0x21,0x11,0xa6,0x1b,0x0a,0x76,0xab,0x04,0xa2,0x49,0x00,0x1b,0x99, +0xe2,0x22,0x23,0x91,0xda,0x33,0x99,0x2e,0xc6,0xf6,0xff,0x00,0x00,0x00,0x36, +0x21,0x01,0x52,0x61,0x15,0x72,0x61,0x18,0x49,0xf1,0x32,0x61,0x17,0x22,0x61, +0x1b,0x32,0x21,0x1b,0x69,0xe1,0xad,0x03,0x68,0x83,0xb8,0x93,0x88,0x06,0x68, +0x16,0x98,0xe8,0x92,0x61,0x10,0x68,0xf6,0x88,0xf8,0x82,0x61,0x13,0x68,0x06, +0xe5,0x47,0xff,0x48,0x93,0x92,0x21,0x17,0xe8,0x33,0xb8,0x49,0xa8,0x19,0xd8, +0x0e,0xc2,0xc4,0x10,0x88,0xf4,0x82,0x61,0x14,0xc9,0xc1,0xf8,0x0d,0xa8,0x1a, +0xb8,0x1b,0x98,0x09,0x92,0x61,0x11,0xb9,0xa1,0xa9,0x51,0xb8,0xe1,0xf9,0x3e, +0xfd,0x04,0xd8,0x1d,0xd9,0x2e,0x16,0x8b,0x07,0x52,0xc4,0x28,0x72,0x21,0x17, +0xa8,0x63,0x78,0x67,0xe8,0xea,0xc8,0x07,0xe2,0x61,0x1a,0x22,0xcc,0xfc,0xc7, +0xb2,0x17,0x0c,0x0b,0xe0,0xa2,0x11,0x98,0x17,0x1b,0x22,0xaa,0x99,0xb9,0x09, +0x88,0x07,0x4b,0xaa,0x87,0x32,0xf0,0xf8,0x93,0xa8,0x63,0x22,0x21,0x17,0xc2, +0xcf,0x20,0xd8,0xef,0xb8,0xba,0xd9,0xb1,0xc9,0x41,0x88,0x72,0x89,0x81,0x28, +0x82,0x96,0x4b,0x01,0xb8,0x9f,0xc8,0xe1,0x0c,0x0d,0xa5,0x3a,0xff,0x98,0x41, +0xe2,0x21,0x1a,0x98,0x19,0x99,0x91,0xc6,0x00,0x00,0xa8,0xe1,0xa9,0x91,0xbd, +0x0e,0xa8,0x73,0xcd,0x02,0xdd,0x06,0xe5,0x35,0xff,0xc8,0x53,0xb8,0x0c,0xd8, +0x0b,0xd9,0x3c,0xb8,0x1b,0xb9,0x2c,0x46,0x04,0x00,0x0c,0x05,0x0c,0x07,0x0c, +0x02,0x0c,0x0f,0x0c,0x0e,0xe9,0x81,0xf9,0x91,0x29,0xb1,0x0c,0x02,0x82,0x21, +0x17,0xb8,0xe1,0x88,0x38,0x92,0x21,0x15,0x16,0xf8,0x17,0x16,0xc9,0x17,0xa8, +0xc1,0xa2,0x61,0x12,0x9c,0xeb,0xa8,0x63,0xc8,0xba,0xd6,0x8c,0x01,0xc8,0xf1, +0x0c,0x0d,0xbd,0x0c,0xa5,0x34,0xff,0xd2,0x21,0x15,0x8c,0x9d,0xbd,0x0d,0xcd, +0x0d,0xa8,0x63,0x0c,0x1d,0xa5,0x33,0xff,0x79,0x61,0x29,0x71,0xe8,0x03,0x59, +0xd1,0xe6,0x1e,0x02,0x46,0x51,0x00,0x0c,0x05,0x0c,0x02,0x78,0x51,0x0c,0x09, +0x0c,0x0a,0xa2,0x61,0x19,0x92,0x61,0x16,0xc2,0x21,0x10,0xb2,0x21,0x16,0xd2, +0x21,0x13,0xc7,0xab,0x14,0xd8,0x0d,0x1b,0xfb,0x27,0x9d,0x0d,0x60,0x61,0x21, +0xe2,0x21,0x13,0xf2,0x61,0x16,0x4b,0xee,0xe2,0x61,0x13,0xa8,0x13,0xb8,0xf1, +0xcd,0x02,0xdd,0x04,0xe8,0x93,0xfd,0x06,0x8b,0xee,0x25,0x7e,0xff,0xa2,0x21, +0x15,0x20,0xf0,0x14,0xdc,0x1f,0x82,0x21,0x18,0x98,0xa1,0x8c,0xa8,0x7c,0xf8, +0x52,0x09,0x00,0x1b,0x99,0x99,0xa1,0x80,0x55,0x30,0xbc,0xca,0xa8,0x23,0xb2, +0x21,0x15,0xcd,0x02,0xd8,0xc1,0xe8,0x93,0xfd,0x06,0xe2,0xce,0x18,0x25,0x7b, +0xff,0xa8,0x33,0xbd,0x04,0xc8,0xc1,0x0c,0x1d,0xed,0x07,0xfd,0x06,0xa5,0x78, +0xff,0xa2,0x21,0x17,0xa8,0x3a,0xac,0x7a,0xc2,0x21,0x14,0xdd,0x07,0xed,0x02, +0xb2,0x21,0x17,0x82,0x2a,0x1f,0xb8,0x5b,0xe0,0x08,0x00,0xc6,0x04,0x00,0xc2, +0x21,0x18,0x8c,0xdc,0xa8,0x33,0xbd,0x04,0x0c,0x0c,0x0c,0x0d,0xed,0x07,0xfd, +0x06,0xa5,0x75,0xff,0xbd,0x04,0xc2,0x21,0x12,0xdd,0x02,0x50,0xe0,0x04,0xa2, +0x21,0x11,0x82,0x21,0x17,0xa8,0x0a,0x88,0x28,0x89,0x01,0x88,0x58,0xf2,0x21, +0x14,0xe0,0x08,0x00,0xb2,0x21,0x18,0xc8,0xe1,0x16,0x7b,0x04,0x16,0x4c,0x04, +0xa8,0x43,0xb8,0x91,0xcd,0x02,0xd8,0xd1,0xe8,0x93,0xfd,0x06,0xe2,0xce,0x30, +0x65,0x73,0xff,0xb8,0x61,0xc8,0x71,0xdd,0x04,0xe8,0xd1,0x88,0x73,0x69,0x01, +0xad,0x08,0x88,0xb8,0xfd,0x02,0xe0,0x08,0x00,0xa8,0x53,0xb8,0xd1,0x0c,0x0c, +0x0c,0x0d,0xe8,0xb1,0xfd,0x06,0xa5,0x6f,0xff,0xa2,0x21,0x19,0xb8,0x81,0x98, +0xb1,0xb8,0x1b,0x98,0x09,0xba,0xaa,0x99,0x0a,0x20,0xc0,0x44,0xcc,0x8c,0xa1, +0x95,0x32,0xa8,0xfa,0x8c,0x1a,0xe0,0x0a,0x00,0x72,0xc7,0x10,0x50,0x51,0x21, +0xb8,0x03,0xc2,0x21,0x19,0x1b,0x22,0x4b,0xcc,0xc2,0x61,0x19,0xb7,0xa2,0x02, +0x46,0xb2,0xff,0x1d,0xf0,0x0c,0x0d,0xd2,0x61,0x12,0xc6,0x9f,0xff,0x36,0x41, +0x00,0x39,0x02,0xe0,0xa3,0x11,0x1c,0x0b,0xe5,0x82,0xfb,0xa9,0x12,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x41,0x00,0x58,0x02,0x78,0x13,0xef,0xe8,0x00,0x22,0x44, +0x0c,0x0c,0x11,0xcf,0x00,0x84,0x28,0x44,0x0c,0x0c,0x11,0x48,0x12,0x0c,0x03, +0x50,0x52,0x41,0x9c,0x65,0x70,0x03,0x8c,0xaf,0xe0,0x0a,0x22,0xd0,0x00,0x87, +0x08,0x30,0x04,0x8d,0x68,0x02,0x1b,0x33,0x60,0x62,0x41,0x67,0x33,0xe7,0x1d, +0xf0,0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0x3c,0x8a,0x65,0x7f,0x00,0x3d,0x0a, +0xb2,0x22,0x12,0xe5,0x90,0x06,0x32,0x62,0x13,0x1d,0xf0,0x00,0x36,0x81,0x00, +0x79,0x31,0x3c,0xca,0x49,0x01,0x69,0x21,0x39,0x41,0x59,0x11,0x38,0x12,0x58, +0x02,0x68,0x41,0x48,0x25,0xbd,0x03,0x58,0x35,0xa5,0x7c,0x00,0x7d,0x0a,0xb8, +0x02,0x25,0xaa,0xfe,0xa8,0x02,0x79,0x12,0xa8,0x2a,0x98,0x62,0x99,0x7a,0x88, +0x06,0x87,0x95,0x28,0x59,0x33,0xc8,0x84,0xc9,0x03,0xb8,0x94,0xb9,0x13,0x58, +0xa4,0xfd,0x02,0xb8,0x01,0xc8,0x11,0xd8,0x21,0xe8,0x31,0x59,0x23,0xa8,0x12, +0x92,0x94,0x18,0x88,0xc2,0x92,0x5a,0x08,0xad,0x06,0xe0,0x08,0x00,0x1d,0xf0, +0xf0,0xb5,0x11,0xb9,0x33,0xa8,0x84,0x65,0x9e,0x01,0xa9,0x03,0xa8,0x94,0x25, +0x9e,0x01,0xa9,0x13,0xa8,0xa4,0xa5,0x9d,0x01,0x5d,0x0a,0x46,0xf1,0xff,0x00, +0x00,0x36,0xa1,0x00,0x0c,0x4a,0xcd,0x06,0xb8,0x12,0x68,0x02,0xc9,0x71,0x68, +0x26,0xa5,0x75,0x00,0x7d,0x0a,0xb8,0x02,0x69,0x41,0x65,0xa9,0xfe,0x79,0x12, +0xa8,0x14,0x88,0xb2,0xb8,0x04,0xe0,0x08,0x00,0x98,0x32,0x92,0x29,0x13,0x6d, +0x0a,0x16,0x49,0x06,0xad,0x02,0xbd,0x06,0x88,0xc2,0xcd,0x05,0xe0,0x08,0x00, +0x98,0x41,0x98,0x89,0xa9,0x01,0x8c,0x99,0xa8,0x62,0xbd,0x04,0x88,0xba,0xcd, +0x05,0xe0,0x08,0x00,0x0c,0x4a,0x78,0x42,0x98,0x12,0xb8,0x17,0x98,0x09,0x99, +0x11,0xe5,0x70,0x00,0xa9,0x21,0xb8,0x07,0x25,0xa3,0xfe,0x0c,0x4a,0xc8,0x21, +0xb8,0x67,0xb9,0x61,0xc9,0x17,0xb8,0x6b,0x65,0x6f,0x00,0xb8,0x61,0xa9,0x31, +0xb8,0x0b,0xe5,0x9f,0xfe,0xb8,0x11,0xc8,0x01,0xa8,0x61,0x98,0x31,0x88,0x87, +0x99,0x6a,0xad,0x07,0xe0,0x08,0x00,0x69,0x51,0x06,0x09,0x00,0x00,0x00,0x00, +0xb8,0x03,0x0c,0x05,0xa6,0x1b,0x18,0x0c,0x0c,0x0c,0x0a,0x0c,0x0b,0xe8,0x82, +0xe8,0x0e,0xe8,0x1e,0x1b,0xaa,0xea,0xeb,0xc9,0x0e,0xd8,0x03,0x4b,0xbb,0xd7, +0x2a,0xec,0x69,0x51,0x68,0x52,0x0c,0x1a,0x78,0x26,0x28,0x06,0xb8,0x16,0xf8, +0x12,0x28,0x22,0xf8,0x0f,0xf9,0x81,0xe5,0x69,0x00,0xc8,0x81,0xa9,0x16,0x1c, +0xfb,0x98,0x71,0xaf,0x21,0x09,0x22,0x44,0x0c,0x0c,0x11,0x9c,0xc9,0x20,0x40, +0x1c,0x4b,0x82,0xcf,0x00,0x8c,0x2a,0x44,0x0c,0x0c,0x11,0x9c,0xa5,0x80,0x40, +0x1c,0xcf,0x00,0x8c,0x2a,0x44,0x0c,0x0c,0x11,0x46,0x03,0x00,0x00,0x8b,0xa2, +0xa0,0x40,0x1c,0xcf,0x00,0x8c,0x2a,0x44,0x0c,0x0c,0x11,0x6f,0xf2,0x10,0x22, +0xe0,0x60,0xbf,0x0a,0x0f,0xac,0x19,0x82,0xc2,0x8a,0x04,0x00,0x0f,0x20,0xa1, +0x42,0xd0,0x60,0x37,0x0c,0x76,0xac,0x3b,0xd0,0x00,0x1c,0x8f,0x21,0x04,0x2b, +0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xf8,0x30,0x2e,0x0a,0x00,0xcd,0x0d, +0xe8,0x07,0xf8,0x14,0xe8,0x1e,0xf0,0x89,0x06,0xcf,0xd2,0xe1,0x42,0xa8,0x00, +0xb8,0x01,0xaf,0xe0,0x0a,0x22,0xa4,0x20,0x90,0x01,0xef,0x87,0x03,0x62,0x3c, +0x2c,0x08,0x00,0x90,0x8c,0x46,0x1b,0x99,0x28,0x51,0x1d,0xf0,0x36,0xc1,0x00, +0xad,0x02,0xb8,0xa2,0x65,0x43,0xff,0x0c,0x0f,0xa8,0x22,0xd8,0x33,0xe8,0x23, +0x88,0xb2,0x68,0x92,0xc8,0xa2,0x68,0x26,0xb8,0x7c,0x58,0x58,0xc8,0x8c,0x88, +0x08,0x68,0x16,0x88,0x08,0x62,0x96,0x00,0x89,0x01,0x25,0x37,0xff,0xd8,0xb2, +0x0c,0x19,0xd8,0xcd,0x71,0x99,0x32,0x16,0x2d,0x24,0xb2,0xc1,0x30,0x82,0x27, +0x7f,0xd8,0xa2,0xc8,0x33,0xf8,0x92,0xc8,0x1c,0xe8,0x0f,0xa8,0x9d,0xf8,0x1f, +0xd8,0x7d,0xa8,0x1a,0xd8,0x1d,0xf2,0x2f,0x24,0xe0,0x08,0x00,0xa9,0xd1,0xb2, +0xc1,0x30,0x82,0x27,0x7f,0xf8,0x92,0x98,0x43,0xe8,0xd1,0xa8,0x63,0xd8,0xa2, +0xc8,0x33,0xd8,0x7d,0xc8,0x1c,0xa8,0x1a,0xe9,0x09,0xe8,0x0f,0xf8,0x1f,0xd8, +0x1d,0xf2,0x2f,0x25,0xe0,0x08,0x00,0x98,0x92,0xc8,0x19,0xbd,0x0a,0xa8,0xfc, +0xc8,0x73,0xa2,0x9a,0x0c,0xb9,0x0c,0x16,0x4a,0x04,0x0c,0x0f,0xa8,0x32,0xd8, +0x33,0xb8,0xa2,0xe8,0xb2,0xc2,0x2b,0x11,0xe8,0x0e,0xb2,0x2b,0x10,0xe8,0x0e, +0xe9,0x01,0x0c,0x0e,0xe5,0x2e,0xff,0xb2,0xc1,0x30,0x82,0x27,0x7f,0xd8,0xa2, +0xf8,0x92,0xa8,0x53,0xc8,0x33,0xa8,0x1a,0xc8,0x1c,0xe8,0x0f,0xd2,0x2d,0x10, +0xf8,0x1f,0xd8,0x1d,0xf2,0x2f,0x26,0xe0,0x08,0x00,0x98,0x92,0x0c,0x0a,0xc6, +0x00,0x00,0x00,0x00,0x0c,0xfa,0x7c,0xfb,0x78,0x09,0x98,0x53,0x78,0x77,0x98, +0x19,0x76,0xa7,0x10,0x82,0x09,0x00,0xb0,0x88,0x30,0x80,0x8a,0x20,0x80,0x80, +0x34,0x82,0x49,0x00,0x1b,0x99,0x98,0xb2,0x0c,0x1d,0xb8,0xf9,0x98,0x09,0xb0, +0xbd,0x93,0xc2,0x99,0x08,0xa2,0x99,0x09,0xc2,0xcc,0xfd,0xc0,0xc0,0xf4,0xb6, +0x2c,0x0e,0xdc,0x0a,0xc2,0x99,0x0b,0xcc,0x6c,0xcc,0x4b,0xd2,0x99,0x0a,0x16, +0x8d,0x15,0xcc,0x1a,0x16,0x3b,0x18,0xe2,0xca,0xfe,0x16,0x8e,0x16,0xcc,0xfa, +0x8c,0xdb,0xf8,0x92,0xf8,0x1f,0xf8,0xff,0xf2,0x9f,0x0a,0xf2,0xcf,0xfe,0x16, +0x5f,0x15,0x26,0x3a,0x0f,0xfc,0x1a,0xac,0xfb,0x88,0x92,0x88,0x18,0x88,0xf8, +0x82,0x98,0x0a,0x66,0x38,0x24,0x0c,0x0e,0xa8,0x82,0xb8,0x33,0xd8,0xa2,0xb8, +0x1b,0x88,0xbd,0xf8,0xad,0xc8,0x7d,0xf8,0x1f,0xc8,0x1c,0xd8,0x8d,0x88,0x18, +0xd8,0x1d,0x89,0x01,0x98,0x23,0x99,0x11,0x49,0x21,0x65,0x14,0xff,0x0c,0x19, +0x0c,0x08,0xa8,0x52,0xc8,0xc3,0x48,0xa2,0xd8,0x33,0xb8,0xc4,0xe8,0xa4,0xf8, +0xb4,0x69,0x21,0x59,0x31,0x89,0x01,0x99,0x11,0x98,0xe4,0x99,0x41,0x89,0x51, +0x89,0x61,0x89,0x71,0x42,0x24,0x12,0x49,0x81,0x65,0x03,0xff,0xa9,0x83,0xa8, +0x52,0xb1,0x8e,0x31,0xa8,0x1a,0xb8,0xfb,0xa8,0x0a,0xa9,0x93,0x8c,0x1b,0xe0, +0x0b,0x00,0xb8,0xb2,0xb8,0x0b,0xd8,0xa2,0xb2,0x9b,0x09,0xa8,0x5d,0xcc,0xab, +0xb1,0x8b,0x31,0x65,0x24,0x00,0xc6,0x01,0x00,0x00,0x00,0x00,0xb8,0xcd,0x65, +0x1a,0xff,0x98,0xb2,0x98,0x09,0xc2,0x99,0x0a,0x9c,0x1c,0xa8,0x02,0xb8,0x0a, +0xb8,0x1b,0x8c,0x9b,0xb8,0xa2,0xb8,0x5b,0xe5,0xfa,0xfe,0x98,0xb2,0x98,0x09, +0xa2,0x99,0x08,0x26,0x4a,0x27,0x48,0xb3,0x66,0x3a,0x16,0xbd,0x04,0xa8,0x42, +0xf8,0xa2,0xc8,0x33,0xf2,0x2f,0x12,0xd8,0xa3,0x8b,0xff,0xed,0x0f,0xa5,0xed, +0xfe,0xc6,0x01,0x00,0xad,0x04,0xb1,0x77,0x31,0x65,0x1f,0x00,0x98,0xb2,0x98, +0x09,0xa2,0x99,0x09,0xd8,0xa2,0x16,0x9a,0x05,0xc8,0xc2,0xb8,0x5d,0x88,0x72, +0xb8,0x1b,0xad,0x08,0x88,0x18,0xc8,0x1c,0xe0,0x08,0x00,0xb8,0xa2,0xa8,0xc2, +0xb8,0x5b,0xa5,0x13,0xff,0xb8,0xa2,0xc8,0xb3,0xa8,0xfb,0xb8,0x5b,0xe5,0xe6, +0xfe,0xc6,0x01,0x00,0x00,0x00,0x00,0xbd,0x04,0x25,0x12,0xff,0xc8,0xb2,0xc8, +0x0c,0xc2,0x9c,0x0b,0x8c,0xfc,0xa8,0x12,0xd8,0x0a,0xd8,0x2d,0x8c,0x7d,0xb8, +0xa2,0xc8,0x33,0xb8,0xfb,0x65,0xe2,0xfe,0xb8,0xa2,0xa8,0x03,0xb8,0xfb,0xe5, +0x0f,0xff,0x1d,0xf0,0x99,0xd1,0x46,0x76,0xff,0x48,0xb3,0xe2,0x99,0x0a,0xa8, +0xfd,0x16,0x6e,0xfc,0xcd,0x04,0xb8,0x5d,0x65,0xe2,0xfe,0x46,0xf0,0xff,0xb8, +0xa2,0xa8,0xab,0xb8,0x7b,0xa5,0x0d,0xff,0xb8,0xa2,0xa8,0xbb,0xb8,0x8b,0x25, +0x0d,0xff,0x06,0xb3,0xff,0xa8,0xa2,0x0c,0x0b,0xa8,0x6a,0x10,0x11,0x20,0xa5, +0x15,0x00,0xa8,0xa2,0xb1,0x4e,0x31,0xa8,0x5a,0x10,0x11,0x20,0xe5,0x14,0x00, +0x98,0xa2,0x0c,0x1a,0x92,0x29,0x12,0xa9,0x83,0x98,0x39,0x76,0xa7,0x06,0x0c, +0xfa,0xa2,0x49,0x00,0x1b,0x99,0x46,0xbe,0xff,0x36,0x41,0x00,0x2c,0x0a,0xb8, +0x32,0x25,0x32,0x00,0x5d,0x0a,0xb8,0x22,0xe5,0x67,0xfe,0xad,0x04,0x59,0x32, +0xbd,0x02,0x0c,0x19,0x88,0x52,0x90,0x00,0xf3,0xe0,0x08,0x00,0xbd,0x03,0x88, +0x62,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0x58,0x13,0x68,0x22, +0x38,0x12,0x48,0x06,0x68,0x16,0x48,0x74,0x68,0x16,0x76,0xa4,0x18,0x30,0x08, +0x0c,0x50,0x43,0x8c,0x2f,0xc3,0x44,0xa2,0xe0,0x10,0x0f,0x08,0xaf,0xe0,0x0a, +0x22,0xf8,0x00,0x0e,0x09,0x30,0x03,0x8d,0x1d,0xf0,0x00,0x36,0xa1,0x00,0x69, +0xb1,0x1c,0x4a,0xb8,0x42,0xcd,0x05,0x39,0x41,0x58,0x32,0xc9,0x81,0x88,0x05, +0x58,0x15,0x98,0xe8,0x99,0x91,0x58,0xf5,0x88,0xf8,0x89,0xa1,0x58,0x05,0xa5, +0x2a,0x00,0xb8,0x32,0xb8,0x1b,0xb8,0xfb,0x7d,0x0a,0xb8,0x0b,0xe5,0x0e,0xff, +0x79,0x42,0xf8,0x22,0xc8,0x47,0xe8,0x0f,0xc9,0x61,0x88,0x0e,0xcc,0x34,0x0c, +0x06,0x46,0x00,0x00,0x68,0x14,0x89,0x3f,0xe8,0x1e,0xe9,0x2f,0xd8,0x02,0xe6, +0x1d,0x02,0x46,0x20,0x00,0x0c,0x03,0x0c,0x04,0xa2,0xd6,0xfe,0x8b,0xb7,0xb9, +0x71,0xa9,0x51,0xc8,0x91,0xd8,0xa1,0xc7,0xa3,0x0f,0xd8,0x0d,0xe8,0xa1,0x47, +0x9d,0x08,0x50,0x51,0x21,0x1b,0x33,0x4b,0xee,0xe9,0xa1,0xa8,0x12,0xb8,0x81, +0xcd,0x04,0xdd,0x07,0xe8,0x71,0xfd,0x05,0xa5,0x0c,0xff,0x9c,0xc6,0xa8,0x22, +0xbd,0x07,0x0c,0x0c,0x0c,0x0d,0xe8,0x61,0xfd,0x05,0x25,0x0a,0xff,0x4b,0x66, +0xf8,0x61,0x88,0x51,0xf8,0x0f,0x4b,0x88,0x89,0x51,0xf2,0x68,0x7f,0x88,0xb1, +0x9c,0x38,0xbd,0x07,0x0c,0x0c,0xdd,0x04,0xa8,0x41,0x0c,0x0e,0xa8,0x0a,0x89, +0x01,0x88,0x58,0x0c,0x0f,0xe0,0x08,0x00,0x40,0xb0,0x44,0xcc,0x8b,0xa1,0xf8, +0x30,0xa8,0xfa,0x8c,0x1a,0xe0,0x0a,0x00,0xb8,0x02,0x1b,0x44,0xb7,0x24,0x8a, +0x1d,0xf0,0x36,0x61,0x00,0x68,0x12,0x0c,0x05,0x39,0x11,0x0f,0x82,0x88,0x04, +0x44,0x0c,0x0c,0x11,0x48,0x02,0x4b,0x71,0x40,0x42,0x41,0x2f,0xe0,0x80,0x04, +0x44,0x0c,0x0c,0x11,0x8c,0xb4,0x30,0x06,0x8d,0x88,0x02,0x1b,0x55,0x80,0x82, +0x41,0x87,0x35,0xf2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x48,0x12,0x0f, +0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0x38,0x02,0x20,0x80,0x0c,0x52,0xa0,0x1f, +0x6f,0x64,0x9e,0x43,0x42,0x29,0x04,0x00,0x76,0x93,0x0a,0x40,0x43,0x8c,0xaf, +0xe0,0x0a,0x22,0x02,0x08,0x89,0x00,0xaf,0xe0,0x0a,0x22,0x44,0x48,0x00,0x11, +0xaf,0xe0,0x0a,0x22,0xa4,0x30,0x20,0x01,0xaf,0xe0,0x0a,0x22,0x50,0x30,0x18, +0x01,0x0f,0x20,0xa1,0x42,0xa4,0x30,0xa0,0x01,0x8d,0x01,0x90,0xc8,0x46,0x28, +0x01,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0x2c,0x4a,0x65,0x16,0x00,0x3d,0x0a, +0xb8,0xc2,0xe5,0x30,0x06,0x39,0xd2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00, +0x41,0xcb,0x30,0x42,0x24,0x10,0x51,0x78,0x31,0x48,0x04,0x50,0x44,0xa0,0x42, +0x24,0x7f,0x48,0x04,0x48,0xf4,0x48,0x04,0x40,0x42,0x21,0x76,0xa4,0x05,0x30, +0x03,0x8c,0x30,0x02,0x8d,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0x5c,0x8a,0x65, +0x12,0x00,0x3d,0x0a,0xb8,0x02,0x25,0x32,0x06,0x39,0x52,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0x51,0xbb,0x30,0x58,0xe5,0x62,0x25,0x11,0x0c,0x17,0xcc, +0x56,0x98,0xc5,0x0c,0x18,0x90,0x68,0x93,0x91,0x1b,0x31,0x90,0x92,0xa0,0x92, +0x29,0x7f,0x98,0x09,0x28,0x19,0x88,0x25,0xa2,0x22,0x13,0x48,0x05,0xaa,0xa8, +0xa2,0x0a,0x00,0xc8,0x45,0x00,0xaa,0x23,0xe6,0x2a,0x01,0x0c,0x07,0xa2,0x22, +0x15,0x0b,0xd6,0xaa,0xa8,0xa2,0x0a,0x00,0x0c,0x02,0x00,0xaa,0x23,0x16,0x2a, +0x07,0x8c,0x37,0x0c,0x1b,0xc0,0x2b,0x93,0xad,0x02,0xe2,0x29,0x12,0x0c,0x37, +0xe8,0x6e,0x29,0x04,0xe0,0xe8,0x90,0xe2,0x9e,0x00,0x16,0x8d,0x06,0x2d,0x06, +0x69,0x14,0x0c,0x06,0x66,0x0e,0x03,0x69,0x14,0x2d,0x06,0x69,0x24,0x8c,0x22, +0x0c,0x1f,0xf9,0x24,0x22,0x25,0x2a,0x29,0x34,0x98,0xd5,0x28,0xa5,0x38,0x85, +0x66,0x12,0x05,0x72,0x54,0x08,0x86,0x00,0x00,0x22,0x54,0x08,0x28,0xb5,0x26, +0x12,0x01,0x7d,0x02,0x72,0x54,0x09,0x0c,0x12,0xcc,0x63,0x82,0x25,0x3b,0x0c, +0x06,0x80,0x26,0x83,0x22,0x54,0x0a,0x0c,0x16,0x0c,0x02,0xcc,0x69,0xb2,0x25, +0x3b,0x0c,0x0a,0xb0,0x6a,0x83,0x62,0x54,0x0b,0x1d,0xf0,0x0c,0x0a,0x8c,0x67, +0xc8,0x45,0xcc,0x0c,0x8c,0x06,0x0c,0x1a,0x2d,0x0a,0x06,0xe1,0xff,0x8c,0x5a, +0x0c,0x22,0x0c,0x26,0xc6,0xe3,0xff,0x2d,0x07,0x6d,0x07,0x06,0xe2,0xff,0x00, +0x36,0x41,0x00,0x66,0xb3,0x08,0xad,0x02,0xe5,0x6a,0xfa,0x2d,0x0a,0x1d,0xf0, +0x66,0x43,0x08,0xad,0x02,0x65,0x63,0xfa,0x2d,0x0a,0x1d,0xf0,0xad,0x02,0x25, +0x5c,0xfa,0x2d,0x0a,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x02,0x0c,0x4a,0x0c,0x2c, +0x65,0x50,0xfa,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0xbd,0x03,0x0c, +0x1c,0x65,0x4f,0xfa,0x2d,0x0a,0x1d,0xf0,0x36,0x41,0x00,0xad,0x02,0xb1,0x18, +0x31,0xf1,0x21,0x31,0xd1,0xdc,0x30,0xe1,0x6f,0x30,0x3c,0x98,0xe8,0xee,0x76, +0xa8,0x22,0x92,0x0b,0x80,0x82,0x0b,0x81,0x00,0x99,0x23,0x00,0x88,0x23,0x97, +0x28,0x11,0xc2,0x1b,0x41,0x92,0x1b,0x3f,0xd7,0x1c,0x08,0xea,0x99,0xfa,0x8c, +0x82,0x98,0x7f,0x89,0x09,0x8b,0xbb,0x25,0xea,0xff,0x1d,0xf0,0x36,0x41,0x00, +0x0c,0x4a,0x0c,0x0b,0x0c,0x0c,0x65,0x4a,0xfa,0x2d,0x0a,0x1d,0xf0,0x36,0x41, +0x00,0xa2,0xa0,0xf0,0x0c,0x4b,0x25,0xf6,0xff,0x21,0x5c,0x30,0x0c,0x4b,0xa9, +0xe2,0x2c,0x0a,0x65,0xf5,0xff,0x28,0xe2,0xa9,0x02,0x1d,0xf0,0x00,0x00,0x00, +0x36,0x41,0x00,0x81,0x56,0x30,0x82,0x28,0x1a,0xe0,0x08,0x00,0x2d,0x0a,0x1d, +0xf0,0x36,0x41,0x00,0x31,0x52,0x30,0x0c,0x02,0x22,0x63,0x17,0x22,0x63,0x18, +0x1d,0xf0,0x36,0x41,0x00,0xcc,0x72,0x8c,0x53,0x4c,0xfa,0x0c,0x1b,0xa5,0x7b, +0x00,0x1d,0xf0,0x36,0x41,0x00,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x76, +0xa2,0x0b,0x58,0x04,0x28,0x03,0x4b,0x44,0x5a,0x22,0x29,0x03,0x4b,0x33,0x1d, +0xf0,0x36,0x61,0x01,0x9d,0x02,0x0c,0x0c,0x71,0x42,0x30,0xad,0x06,0xf2,0x27, +0x12,0x0c,0x06,0xb8,0x1f,0xa2,0x61,0x1e,0xa6,0x1b,0x06,0x8c,0x32,0x0c,0x18, +0x50,0xc8,0x93,0xe2,0x27,0x10,0x8c,0x6c,0x66,0x2b,0x04,0x0c,0x1a,0x30,0x6a, +0x93,0x28,0x5e,0xa8,0x0f,0xd8,0x3e,0xc8,0x4e,0xd8,0xcd,0xc2,0x2c,0x12,0xc2, +0x61,0x1d,0xd2,0x61,0x13,0x9c,0xbf,0x82,0x9a,0x09,0x0c,0x1c,0xcc,0xf8,0xd2, +0x9a,0x0b,0xcc,0xad,0x88,0xff,0xcc,0x68,0x82,0x9a,0x0a,0x0c,0x0d,0x80,0xcd, +0x83,0xdd,0x0c,0x46,0x00,0x00,0x0c,0x0d,0x0c,0x1c,0xd2,0x61,0x12,0xb2,0x61, +0x10,0x82,0x9a,0x08,0x92,0x61,0x1f,0x82,0xc8,0xfd,0x80,0x80,0xf4,0xb6,0x28, +0x0c,0x88,0x1a,0xcc,0x78,0xcc,0x5d,0x88,0xcf,0x0c,0x0a,0x80,0xca,0x83,0xa2, +0x27,0x13,0xc2,0x61,0x11,0xcc,0x2a,0x0c,0x12,0x1d,0xf0,0xad,0x0e,0x0c,0x1b, +0xc2,0x27,0x15,0xb0,0x00,0xf3,0xbd,0x02,0x1b,0xcc,0xc2,0x67,0x15,0x65,0xd6, +0xff,0x59,0xb2,0xe2,0x21,0x1f,0xe9,0x52,0x30,0x3e,0x83,0x39,0x81,0x39,0x72, +0x16,0x04,0x06,0xf2,0x21,0x1e,0x39,0x81,0x16,0x8f,0x05,0xbd,0x04,0x82,0x27, +0x10,0xa2,0x21,0x1e,0x88,0x18,0x49,0x92,0xa9,0xd2,0x89,0x82,0x89,0xc2,0xe5, +0xd0,0xff,0x92,0x27,0x10,0xa8,0x39,0xa8,0xca,0xa8,0x0a,0xb1,0x63,0x30,0xa8, +0x0a,0x98,0x19,0xb0,0xaa,0xc0,0xcc,0x1a,0xf0,0x99,0x11,0x39,0x81,0xb2,0x21, +0x10,0xc2,0x22,0x14,0x99,0xe2,0xd2,0x21,0x1e,0xd9,0xf2,0x0c,0x09,0xc8,0x1c, +0xc2,0x61,0x1b,0xa6,0x1b,0x0d,0xe2,0x21,0x1f,0x39,0x81,0x8c,0x5e,0x39,0x81, +0x0c,0x1f,0x50,0x9f,0x93,0x3d,0x09,0x06,0x05,0x00,0x0c,0x03,0x0c,0x08,0x0c, +0x09,0x99,0x82,0x99,0x92,0x99,0xc2,0x99,0xd2,0x99,0xe2,0x99,0xf2,0x82,0x61, +0x1b,0x59,0x61,0x98,0x22,0x0c,0x0d,0x9c,0xa9,0xf8,0x09,0x0c,0x0a,0x2f,0x7e, +0x28,0x22,0xb2,0x0a,0x01,0x00,0x98,0x19,0x76,0xaf,0x0a,0xb0,0x04,0x03,0xb0, +0xb0,0x34,0xb2,0x49,0x00,0x1b,0x99,0xd9,0x02,0x16,0xa3,0x27,0x52,0x27,0x10, +0x58,0x35,0xad,0x05,0xb8,0xd5,0xb2,0x61,0x20,0x65,0xc6,0xff,0x82,0x21,0x11, +0xcc,0x38,0x0c,0x09,0x46,0x00,0x00,0x98,0x85,0xf8,0xf7,0x99,0x71,0x8c,0x1f, +0xe0,0x0f,0x00,0xcd,0x04,0xd2,0x21,0x20,0xa8,0x05,0xd8,0x5d,0xa8,0x1a,0xb8, +0x1d,0xd8,0x0d,0x25,0x7a,0xfe,0xe2,0x27,0x12,0xe8,0xfe,0x16,0xfe,0x05,0xa2, +0x22,0x12,0xe5,0xbd,0xff,0xb8,0xb5,0xa2,0x61,0x16,0x88,0x15,0xa2,0x22,0x12, +0xc8,0x58,0xd8,0x88,0x88,0x38,0xa8,0x1a,0xe0,0x08,0x00,0xbd,0x0a,0xa9,0x91, +0x88,0x15,0x92,0x22,0x12,0xc8,0x58,0xd8,0x88,0x88,0x48,0xa8,0x19,0xe0,0x08, +0x00,0xb8,0x91,0x6f,0xf6,0x00,0x22,0x44,0x0c,0x0c,0x11,0x6f,0xf4,0x02,0x22, +0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x00,0x01,0x00,0xa2,0x22,0x12, +0x2f,0x01,0x28,0x48,0x44,0x0c,0x0c,0x11,0x92,0x61,0x1c,0xa5,0xb8,0xff,0xa2, +0x61,0x17,0xc6,0x03,0x00,0xc1,0xcc,0x2f,0x0c,0x0d,0x0c,0x0e,0xe2,0x61,0x17, +0xd2,0x61,0x16,0xc2,0x61,0x1c,0xb1,0xc8,0x2f,0x88,0xe5,0x0c,0x1f,0x98,0x48, +0xa8,0x08,0xf9,0x09,0xf9,0x88,0xe5,0xb2,0xff,0xa8,0xe5,0xb1,0xc3,0x2f,0xa8, +0xba,0x25,0xb2,0xff,0xb2,0x21,0x11,0x16,0x7b,0x0b,0xa8,0x55,0xdd,0x04,0xc2, +0x21,0x20,0xe8,0x71,0xb8,0x0c,0xc8,0x2c,0x65,0xa3,0xff,0xf8,0xf7,0x8c,0x1f, +0xe0,0x0f,0x00,0xb2,0x21,0x20,0xa8,0x65,0xb8,0x2b,0x65,0x9f,0xff,0xc2,0x27, +0x12,0xd8,0xe5,0xc8,0xfc,0xa9,0x3d,0xbc,0x8c,0xc2,0x21,0x1c,0x81,0x13,0x30, +0xb8,0x1a,0xd2,0x27,0x10,0xa8,0xd5,0xd8,0x3d,0x82,0x28,0x7f,0xd8,0xcd,0xa8, +0x6a,0x98,0x2d,0x82,0x28,0x22,0x92,0x29,0x16,0xa8,0x1a,0x98,0x19,0xd8,0x0d, +0x92,0x29,0x44,0xd8,0x7d,0xc0,0xc9,0x73,0xc2,0x61,0x1c,0xe0,0x08,0x00,0xe8, +0xd5,0xf8,0xe5,0xe8,0x6e,0xe9,0x3f,0xb2,0x21,0x20,0xa8,0x45,0xc8,0x5b,0xb8, +0x4b,0xc8,0x1c,0x65,0x97,0xff,0xa8,0x75,0xc1,0x01,0x30,0xb8,0xe5,0xc2,0x2c, +0x7f,0xe5,0x68,0xff,0xd2,0x27,0x12,0xd8,0x0d,0xd2,0x9d,0x08,0xd2,0xcd,0xfd, +0xd0,0xd0,0xf4,0xb6,0x2d,0x04,0xe2,0x21,0x12,0x9c,0xfe,0xe2,0x21,0x1e,0xa2, +0x21,0x20,0xb2,0x27,0x10,0x88,0x85,0xb8,0x3b,0xdd,0x08,0xc8,0x3a,0x88,0x68, +0xa8,0x0a,0xc8,0x1c,0xb2,0x2b,0x13,0xa8,0x0a,0xb8,0x1b,0xe0,0x08,0x00,0xb2, +0x27,0x12,0xb8,0xfb,0x16,0xab,0x06,0xc8,0xe5,0xc8,0x8c,0xc2,0x61,0x14,0x66, +0x1c,0x18,0xd2,0x21,0x13,0xe2,0x21,0x20,0xd8,0x2d,0xe8,0x4e,0xd2,0x2d,0x10, +0xe8,0x0e,0xd8,0xbd,0xe7,0x3d,0x04,0x0c,0x0e,0xe2,0x61,0x14,0x88,0x15,0xa2, +0x22,0x14,0x88,0x58,0xf2,0x21,0x1c,0x92,0x28,0x1c,0x99,0xd1,0xf2,0x68,0x1c, +0xa5,0xa5,0xff,0x0c,0x1d,0x92,0x21,0x17,0x88,0x15,0xe8,0xe5,0xb8,0x58,0xc8, +0x88,0xf8,0xbe,0xe8,0x9e,0xf8,0x1f,0x99,0x21,0xd9,0x01,0xd2,0x21,0x16,0xd9, +0x11,0x98,0x68,0x99,0x31,0x88,0x28,0xd2,0x21,0x14,0xe0,0x08,0x00,0x98,0x15, +0x88,0xd1,0x98,0x59,0xa9,0xb5,0x82,0x69,0x1c,0xf8,0xf7,0x8c,0x1f,0xe0,0x0f, +0x00,0xf2,0x27,0x12,0xa8,0xcf,0xbc,0x6a,0xb8,0x0f,0xf2,0x27,0x10,0xb2,0x9b, +0x09,0xf8,0x3f,0x66,0x4b,0x04,0x0c,0x0d,0x06,0x03,0x00,0xe8,0xef,0xe8,0x4e, +0x0c,0x1c,0xe8,0x0e,0x0c,0x0d,0xe0,0xdc,0x83,0xa8,0xff,0xc2,0x22,0x14,0xe2, +0x2f,0x10,0xbd,0x0c,0x65,0x44,0xff,0xf8,0xf7,0xa9,0xb1,0x8c,0x1f,0xe0,0x0f, +0x00,0xf2,0x27,0x12,0x98,0x0f,0x92,0x99,0x08,0x8c,0x19,0x66,0x39,0x17,0xc2, +0x22,0x14,0xa8,0x25,0xd8,0x0c,0xc8,0x1c,0xa8,0x3a,0xbd,0x0c,0xe5,0x57,0xfe, +0x92,0x27,0x12,0x98,0x09,0x92,0x99,0x08,0x66,0x29,0x04,0xa2,0x21,0x12,0x8c, +0xea,0xa8,0x35,0x0c,0x0c,0x0c,0x0d,0xe2,0x22,0x14,0x0c,0x0f,0xbd,0x0e,0x25, +0x38,0xff,0xf8,0xf7,0x58,0x61,0x8c,0x1f,0xe0,0x0f,0x00,0x0c,0x09,0x49,0xa1, +0xb2,0x21,0x10,0x59,0x61,0xa6,0x1b,0x09,0xc2,0x21,0x1f,0x8c,0x3c,0x0c,0x1d, +0x50,0x9d,0x93,0x16,0x39,0x0e,0x52,0x27,0x10,0x58,0x45,0x42,0x25,0x13,0xad, +0x05,0xbd,0x04,0xa5,0x33,0xff,0xf2,0x27,0x12,0x16,0x56,0x37,0x88,0x0f,0x88, +0x08,0x16,0xe8,0x36,0x98,0x81,0x92,0x61,0x18,0x16,0x56,0x0b,0x92,0x27,0x10, +0xa1,0xa2,0x2f,0x98,0x09,0xa0,0x99,0xa0,0x92,0x29,0x7f,0x98,0x09,0x98,0x19, +0xa8,0x2f,0xb8,0xf9,0xc8,0xe9,0xc2,0x61,0x1a,0xb2,0x61,0x15,0x66,0x6a,0x0b, +0xa2,0x29,0x11,0xb2,0x29,0x10,0xb2,0x61,0x1a,0xa2,0x61,0x15,0xb2,0x22,0x10, +0xc2,0x21,0x1a,0xad,0x0b,0x25,0x2b,0xff,0xb2,0x22,0x11,0xc2,0x21,0x1a,0xad, +0x0b,0x65,0x2a,0xff,0xc2,0x27,0x10,0xc8,0x4c,0xc2,0x2c,0x12,0xd1,0x30,0x2f, +0xc8,0x2c,0xe2,0x25,0x15,0xc8,0xfc,0xe9,0xc1,0xc2,0x9c,0x0b,0xd9,0xbe,0x9c, +0x2c,0xa8,0x45,0xf2,0x22,0x11,0xd8,0xc1,0xe2,0x22,0x10,0xd2,0xcd,0x2c,0xbd, +0x0e,0xcd,0x0f,0xa5,0x2c,0xff,0xb2,0x25,0x13,0x0c,0x8a,0xb8,0x7b,0x65,0xaa, +0xff,0xb2,0x25,0x12,0xb8,0x2b,0xb8,0xfb,0xa9,0xe1,0xb8,0x0b,0xa5,0x24,0xff, +0xc2,0x21,0x1f,0xf2,0x25,0x13,0xe8,0xe1,0xe9,0x4f,0xd8,0x44,0xa8,0x05,0xb8, +0x1d,0xa8,0x1a,0xd8,0x0d,0x65,0x47,0xfe,0xa8,0x25,0xc8,0x44,0xb8,0x54,0xc8, +0x1c,0xe5,0x74,0xff,0xf8,0xf7,0x8c,0x1f,0xe0,0x0f,0x00,0xf2,0x27,0x12,0xd2, +0x2f,0x34,0xec,0xcd,0x0c,0x09,0x46,0x0b,0x00,0x8c,0xa5,0xe2,0x21,0x1f,0x8c, +0x5e,0xbd,0x0e,0xad,0x05,0xe5,0x8f,0xff,0x9c,0x33,0xb2,0x22,0x14,0xc2,0x22, +0x10,0xa2,0x27,0x10,0xd2,0x27,0x12,0xa8,0x4a,0xd8,0x6d,0xa8,0x6a,0x65,0x8d, +0xfe,0x0c,0x02,0x1d,0xf0,0x98,0x85,0x92,0x29,0x16,0xa8,0x0f,0xb2,0x25,0x14, +0xa8,0x1a,0x99,0x3b,0x8c,0x2a,0xb8,0xa1,0xcc,0x3b,0x0c,0x0c,0xc2,0x61,0x1b, +0xb2,0x25,0x13,0x0c,0x4a,0xb8,0x7b,0x65,0xa1,0xff,0xb2,0x25,0x12,0xa9,0xf1, +0xc8,0x2b,0xb8,0x0b,0xc8,0xfc,0x10,0x11,0x20,0xa5,0xcc,0x05,0xa8,0x75,0xb2, +0x25,0x14,0xe2,0x21,0x1b,0xd2,0x25,0x13,0xc8,0xf1,0xfd,0x06,0xc9,0x1d,0xc2, +0x21,0x1f,0xd2,0x21,0x18,0xa5,0xf1,0xfe,0xf8,0xf7,0x8c,0x1f,0xe0,0x0f,0x00, +0xd2,0x25,0x12,0x0c,0xff,0xd8,0x0d,0x98,0xe5,0xd8,0x7d,0x98,0x19,0x76,0xad, +0x04,0xf2,0x49,0x00,0x1b,0x99,0xac,0x66,0xe8,0xa1,0x0c,0x0c,0x8c,0x6e,0x82, +0x21,0x1e,0x0c,0x1f,0x80,0xcf,0x93,0xa8,0x85,0xd1,0x49,0x2f,0xb2,0x25,0x15, +0xd2,0x2d,0x7f,0x25,0x99,0xfe,0xb2,0x27,0x10,0xb8,0x4b,0xb8,0xfb,0xb8,0x1b, +0x46,0x06,0x00,0x2f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0xb8,0x34,0x0c,0x09, +0xb8,0x1b,0x76,0xad,0x08,0xc8,0x34,0xc8,0x1c,0x90,0x2c,0xc6,0x1b,0x99,0xf8, +0xf7,0xb2,0x61,0x21,0x8c,0x4f,0xe0,0x0f,0x00,0xb2,0x21,0x21,0xe8,0x61,0xc8, +0x34,0xa8,0x14,0x88,0x95,0xa8,0x0a,0xdd,0x08,0x88,0x68,0xc8,0x1c,0xe0,0x08, +0x00,0x16,0x36,0xf1,0x0c,0x09,0xf2,0x27,0x12,0x62,0x25,0x15,0xa2,0x2f,0x10, +0x68,0x76,0x8c,0xda,0xa2,0x21,0x1d,0xa8,0x2a,0xa8,0xfa,0xa2,0x9a,0x08,0x0c, +0x18,0xa0,0x98,0x93,0x99,0x51,0x0c,0x0c,0xb8,0xcf,0xc2,0x61,0x19,0x9c,0x5b, +0x9c,0x33,0xf2,0x21,0x1d,0xf8,0x2f,0xf8,0xff,0xd2,0x21,0x19,0xf2,0x9f,0x09, +0x0c,0x1e,0xf0,0xde,0x93,0xd2,0x61,0x19,0xb2,0x22,0x13,0xc2,0x21,0x15,0xad, +0x0b,0x25,0x0e,0xff,0x88,0x51,0xcc,0x38,0x92,0x21,0x19,0xac,0x39,0xa8,0x35, +0xc2,0x22,0x13,0xb8,0x54,0xc8,0x1c,0xe5,0x5d,0xff,0x48,0x54,0x66,0x16,0x15, +0xd2,0x21,0x1d,0xd8,0x2d,0xd2,0x2d,0x10,0xe8,0x04,0xd8,0xbd,0xe7,0x3d,0x06, +0x0c,0x06,0x46,0x00,0x00,0x0c,0x04,0x92,0x27,0x10,0xf2,0x27,0x12,0x98,0x39, +0x0c,0x08,0x82,0x69,0x11,0x89,0x41,0xe8,0xcf,0x16,0xfe,0x06,0x16,0xc3,0x06, +0xa8,0x61,0xb2,0x25,0x12,0x81,0x0e,0x2f,0xb8,0x2b,0x82,0x28,0x7f,0xb8,0xfb, +0x82,0x28,0x10,0xb8,0x0b,0xe0,0x08,0x00,0x0c,0x09,0xe2,0x25,0x17,0xf8,0xb1, +0xc2,0x27,0x10,0x8d,0x0a,0xd8,0x85,0xa8,0xc5,0xd2,0x2d,0x21,0xc8,0x3c,0xd8, +0xbd,0xf9,0x2e,0xb8,0xec,0x89,0x1e,0xc2,0xcc,0x40,0x0b,0x86,0x0c,0x1f,0xb8, +0x4b,0xd8,0x0d,0xd9,0x3e,0xb8,0x0b,0x0c,0x0d,0x80,0xdf,0x83,0xd0,0xd0,0x04, +0x0b,0xbb,0xb0,0x9f,0x83,0xd2,0x4e,0x00,0xb2,0xc1,0x10,0x90,0x90,0x04,0x92, +0x4e,0x01,0xe5,0x82,0xfe,0xa2,0x27,0x10,0xa8,0x3a,0xf2,0x27,0x12,0x92,0x2a, +0x10,0x92,0x6a,0x11,0xb2,0x2f,0x10,0x8c,0xdb,0xcd,0x06,0xa8,0x15,0xd2,0x25, +0x15,0xb2,0x22,0x13,0xd8,0xad,0x65,0x7a,0xfe,0xf8,0xf7,0x8c,0x1f,0xe0,0x0f, +0x00,0xf2,0x27,0x12,0xe8,0xcf,0xbc,0xae,0xbc,0x83,0xdd,0x04,0xe2,0x25,0x15, +0x88,0xd5,0xb8,0x8e,0xc8,0x9e,0xad,0x08,0xe8,0x5e,0x88,0x28,0xe8,0x1e,0xe0, +0x08,0x00,0x82,0x27,0x10,0xdd,0x0a,0x88,0x48,0xc2,0x22,0x13,0xf8,0x88,0xbd, +0x0c,0xf2,0x2f,0x21,0xa8,0xb8,0xf8,0xbf,0x82,0x28,0x17,0xf8,0x0f,0xf9,0x38, +0xe8,0x41,0x65,0x0a,0xff,0xf2,0x27,0x12,0x92,0x2f,0x12,0x8c,0xb9,0xc2,0x22, +0x13,0xa8,0xa5,0xbd,0x0c,0xe5,0x6e,0xfe,0xf2,0x27,0x12,0xa8,0x9f,0xec,0x0a, +0xb8,0x0f,0xb2,0x9b,0x0b,0xdc,0x9b,0xc2,0x2f,0x10,0xdc,0x4c,0xa8,0x55,0xd8, +0xaa,0x0c,0x19,0xcc,0x5d,0xe8,0x9a,0xe6,0x1e,0x01,0x0c,0x09,0xcc,0x39,0x0c, +0x09,0x46,0x00,0x00,0x0c,0x19,0x16,0x99,0xd7,0xa8,0x55,0x0c,0x0c,0x0c,0x0d, +0xe2,0x22,0x13,0x0c,0x0f,0xbd,0x0e,0xa5,0xfd,0xfe,0x86,0x59,0xff,0x0c,0x08, +0x82,0x61,0x18,0x46,0x23,0xff,0x00,0x00,0x00,0x36,0x41,0x00,0x76,0xa4,0x07, +0x58,0x03,0x59,0x02,0x4b,0x33,0x4b,0x22,0x1d,0xf0,0x36,0x81,0x00,0xbd,0x03, +0x39,0x51,0xad,0x02,0x25,0x73,0xfd,0x3d,0x0a,0x56,0xca,0x08,0x41,0x59,0x2e, +0x51,0xf5,0x2e,0xa8,0x34,0x0c,0x09,0x99,0x7a,0x66,0x22,0x2f,0xad,0x02,0xb2, +0xc1,0x14,0xe5,0xac,0xfc,0x3d,0x0a,0xec,0x2a,0x98,0x51,0x96,0xe9,0x01,0xe6, +0x79,0x1b,0x50,0xa9,0xa0,0xa2,0x2a,0x87,0x96,0x2a,0x01,0x1c,0x9a,0x0c,0x0b, +0x0c,0x4c,0x88,0x04,0xd1,0xcc,0x2e,0x82,0x28,0x10,0x0c,0x0e,0xe0,0x08,0x00, +0x4c,0xf9,0x97,0x92,0x48,0x28,0x51,0xf6,0x32,0x1c,0x88,0x34,0xad,0x02,0x22, +0x68,0x43,0x25,0x07,0x00,0xed,0x02,0x1c,0x9a,0x0c,0x0b,0x88,0x04,0x0c,0x4c, +0x82,0x28,0x10,0xd2,0xa2,0x00,0xe0,0x08,0x00,0xa2,0x25,0x85,0xa5,0xcb,0x00, +0x2d,0x0a,0x66,0x0a,0x1f,0x0c,0x89,0xc6,0x03,0x00,0x00,0x00,0x00,0xcd,0x02, +0x0c,0x1a,0x88,0xff,0x1c,0x9b,0xe0,0x08,0x00,0x0c,0x79,0x26,0x79,0x03,0x7c, +0xf2,0x1d,0xf0,0x2d,0x03,0x1d,0xf0,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0xd1,0xa4, +0x2e,0xed,0x01,0x88,0x04,0x0c,0x19,0x82,0x28,0x10,0x99,0x01,0xe0,0x08,0x00, +0xa8,0x01,0xf8,0x04,0x16,0x9a,0xfc,0xed,0x02,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c, +0x82,0x2f,0x10,0xd1,0x9c,0x2e,0xe0,0x08,0x00,0x06,0xf0,0xff,0x36,0x41,0x00, +0x3d,0x02,0xd1,0x27,0x2e,0x0c,0x09,0x82,0x2d,0x13,0xb2,0x2d,0x12,0xd2,0x2d, +0x10,0xb8,0x0b,0xa8,0x2d,0xc8,0x7b,0x99,0x0a,0x66,0x18,0x0b,0xb8,0x7b,0xc7, +0x1b,0x06,0xa8,0x3d,0xa8,0x2a,0xe5,0x9e,0xfb,0x0c,0x0b,0x0c,0x12,0x30,0x2b, +0x83,0x1d,0xf0,0x00,0x36,0x41,0x00,0x31,0x1b,0x2e,0xf8,0x33,0x8c,0x72,0x88, +0x3f,0x8c,0x38,0x65,0x2e,0xfb,0xf8,0x33,0x1c,0x9a,0x0c,0x4c,0xd2,0xa3,0x00, +0x88,0x03,0x0c,0x19,0x0c,0x0e,0x0c,0x0b,0xb9,0x7f,0x20,0xe9,0x83,0x82,0x28, +0x10,0xe9,0x3f,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x00,0x36,0x81,0x00,0x0c, +0x06,0x41,0x0d,0x2e,0x8c,0x52,0x62,0x64,0x13,0x0c,0x12,0x1d,0xf0,0xb2,0x24, +0x14,0x81,0xf7,0x2d,0xa2,0x24,0x10,0x0c,0x15,0x50,0x00,0xf3,0x98,0x5a,0x88, +0x98,0x99,0x01,0xe0,0x08,0x00,0x1c,0xca,0xb2,0x24,0x10,0x25,0x63,0xff,0xa9, +0x11,0xbd,0x02,0x10,0x11,0x20,0x25,0x88,0x05,0xb8,0x01,0xa8,0x11,0xa2,0x64, +0x10,0x58,0x4a,0x78,0x3a,0xa5,0x8a,0xfd,0x0c,0x19,0x90,0x00,0xf3,0xcc,0x33, +0xa2,0x24,0x13,0xcc,0x3a,0x0c,0x1a,0x25,0xf4,0xff,0x0c,0x1a,0xcc,0x63,0xc2, +0x24,0x13,0x0c,0x0b,0xc0,0xab,0x93,0x0c,0x13,0x0c,0x1d,0xa0,0xad,0x93,0xa5, +0x82,0xfd,0x62,0x64,0x15,0xa8,0x77,0x25,0x7f,0xfd,0xa8,0x85,0x25,0x7b,0xfd, +0xa8,0x45,0xa9,0x21,0x98,0x8a,0x88,0xba,0x99,0x31,0xe0,0x08,0x00,0xc8,0x31, +0xb8,0x21,0xa8,0x55,0xa9,0x41,0x88,0xba,0x39,0xab,0x69,0x9b,0xc9,0x8b,0x98, +0x8a,0x99,0x51,0xe0,0x08,0x00,0xc8,0x51,0xb8,0x41,0xa8,0x37,0xa9,0x61,0x88, +0xba,0x39,0xab,0x69,0x9b,0xc9,0x8b,0x98,0x8a,0x99,0x71,0xe0,0x08,0x00,0xf8, +0x71,0xe8,0x61,0xd1,0x42,0x2e,0xa8,0x75,0xd0,0xd2,0xa0,0xa8,0x6a,0x69,0x9e, +0x39,0xae,0xd2,0x2d,0x7f,0xf9,0x8e,0xd8,0x0d,0xe2,0x24,0x10,0xd8,0x0d,0xe8, +0x1e,0xe9,0xca,0xd9,0xda,0x65,0x4b,0xfd,0xa8,0x75,0xa8,0x7a,0xa5,0x70,0xfd, +0xd8,0xd5,0xc8,0x1d,0xa8,0x15,0xc8,0x0c,0xb1,0x37,0x2e,0xc8,0x8c,0x0c,0xf2, +0x00,0x0c,0x40,0x20,0xe0,0xb1,0xef,0x77,0xff,0x62,0xb2,0x0b,0x01,0x00,0xc0, +0x04,0x03,0xc0,0xc0,0x34,0xc2,0x4d,0x00,0x25,0x6d,0xfd,0xb1,0x2f,0x2e,0xa8, +0x17,0xb2,0x2b,0x7f,0x65,0x6c,0xfd,0x2f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11, +0x98,0xe5,0xc2,0x24,0x10,0xb8,0xf5,0xc8,0x4c,0xa2,0x27,0x13,0xc2,0x2c,0x12, +0xa8,0x1a,0xc8,0x0c,0xb8,0x1b,0xc8,0x7c,0x98,0x19,0x76,0xac,0x0a,0x30,0x0b, +0x8d,0x30,0x0a,0x8d,0x22,0x49,0x00,0x1b,0x99,0xd2,0x24,0x12,0x32,0x64,0x13, +0xd8,0x0d,0x0c,0x02,0x69,0x6d,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xad,0x04, +0x88,0x03,0x0c,0x0b,0xe0,0x08,0x00,0x3d,0x0a,0x98,0x14,0x99,0x22,0xa9,0x12, +0x25,0x57,0xff,0x30,0xaa,0xc0,0xa9,0x02,0x2d,0x03,0x1d,0xf0,0x36,0x41,0x00, +0x3d,0x02,0x25,0x57,0xff,0xe5,0x55,0xff,0x2d,0x0a,0xa5,0x53,0xff,0x51,0xad, +0x2d,0xa2,0x65,0x12,0x25,0x52,0xff,0x4d,0x0a,0x0c,0x0a,0xa5,0x4d,0xff,0x1c, +0xca,0xbd,0x04,0x25,0x4c,0xff,0x6d,0x0a,0x0c,0x0b,0x65,0x71,0x05,0x62,0x65, +0x10,0x65,0x53,0xff,0xc1,0x07,0x2e,0x91,0x54,0x2e,0x20,0xba,0xc0,0x40,0x8a, +0xc0,0x82,0x65,0x14,0xb9,0x23,0xad,0x04,0x92,0x29,0x7f,0xc8,0xfc,0x98,0x09, +0xc8,0x0c,0xc9,0x33,0xb8,0x49,0xb9,0x53,0x98,0x09,0x99,0x43,0xe5,0x47,0xff, +0xa5,0x50,0xff,0x0c,0x0c,0x0c,0x1d,0x20,0xea,0xc0,0x40,0xfa,0xc0,0xf2,0x65, +0x14,0xe9,0x13,0xd9,0x03,0xc2,0x65,0x13,0x1d,0xf0,0x00,0x00,0x36,0x81,0x00, +0x29,0x01,0x71,0x43,0x2e,0x0c,0x0e,0x51,0x90,0x2d,0x68,0x32,0x16,0xf3,0x06, +0x82,0xc3,0xfe,0x16,0x38,0x26,0x92,0xc3,0xeb,0x16,0x59,0x17,0xa2,0xc3,0xe1, +0x56,0xda,0x16,0xad,0x04,0xc8,0x35,0xb2,0x26,0x43,0x42,0x6c,0x44,0x25,0x4f, +0xff,0xa8,0x35,0x0c,0x0b,0xa2,0x2a,0x44,0x65,0xdd,0xff,0xa8,0x35,0xb2,0x26, +0x43,0xa2,0x2a,0x44,0xe5,0x4c,0xff,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0xd2,0xa4, +0x00,0x98,0x35,0x88,0x05,0xe2,0x29,0x44,0x82,0x28,0x10,0xc0,0xee,0x11,0xea, +0x99,0xe2,0x29,0x10,0xe2,0x67,0x80,0x98,0xf9,0x92,0x67,0x7f,0xe0,0x08,0x00, +0xe2,0x27,0x7f,0x1c,0x9a,0x0c,0x0b,0x88,0x05,0x0c,0x4c,0x82,0x28,0x10,0xd1, +0x27,0x2e,0xe0,0x08,0x00,0x1d,0xf0,0x88,0x05,0xa2,0xa1,0x1c,0x82,0x28,0x1d, +0x0c,0x8b,0xe0,0x08,0x00,0x0c,0x4b,0x0c,0x52,0x91,0x22,0x2e,0x92,0x6a,0x3b, +0x00,0x50,0x00,0x88,0x05,0x3d,0x0a,0x82,0x28,0x1d,0x0c,0x0a,0xe0,0x08,0x00, +0xa0,0xa0,0x60,0xbd,0x02,0xa9,0x45,0xa2,0xc3,0x30,0x65,0xed,0xff,0xc2,0xa0, +0xc4,0xb2,0xa0,0xec,0xa2,0xa0,0xb8,0xaa,0xa3,0xba,0xb3,0xca,0xc3,0x25,0xea, +0xff,0x88,0x05,0x0c,0x0a,0x82,0x28,0x1d,0x0c,0x4b,0xe0,0x08,0x00,0xb8,0x45, +0x0c,0x09,0x92,0x63,0x44,0x92,0x63,0x45,0xaa,0xab,0xa9,0x45,0x0c,0x1b,0x0c, +0x0a,0xa5,0xd2,0xff,0x0c,0x1a,0xd2,0xa0,0x64,0xe8,0x01,0x0c,0x62,0x0c,0x0c, +0x92,0x23,0x44,0xb1,0x0a,0x2e,0xb9,0xf5,0xc0,0x99,0x11,0x9a,0x93,0x82,0x29, +0x10,0x82,0x67,0x80,0x98,0xf9,0xc9,0x83,0x92,0x67,0x7f,0x00,0x50,0x00,0x39, +0x35,0x22,0x63,0x3c,0x39,0x3e,0xe2,0x63,0x46,0xd9,0x23,0xc9,0x73,0xc9,0x63, +0xa5,0xcb,0xff,0x0c,0x0a,0x0c,0x2c,0x0c,0x0d,0xd9,0x43,0xd9,0x53,0xd2,0x63, +0x3e,0xd2,0x63,0x3f,0xd2,0x63,0x40,0xd2,0x63,0x42,0xd2,0x63,0x43,0xc2,0x63, +0x3d,0xa5,0xc6,0xff,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0x88,0x05,0xd2,0xa4,0x00, +0x82,0x28,0x10,0xe2,0x27,0x80,0xe0,0x08,0x00,0xe2,0x27,0x7f,0x1c,0x9a,0x0c, +0x0b,0x88,0x05,0x0c,0x4c,0x82,0x28,0x10,0xd1,0xed,0x2d,0xe0,0x08,0x00,0x1c, +0x9a,0x0c,0x0b,0x0c,0x4c,0x88,0x05,0xd2,0xa5,0x00,0x82,0x28,0x10,0xe1,0xeb, +0x2d,0xe0,0x08,0x00,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0x88,0x05,0xd2,0xa5,0x00, +0x82,0x28,0x10,0xe1,0xe7,0x2d,0xe0,0x08,0x00,0x1d,0xf0,0x41,0xe6,0x2d,0x98, +0x86,0xa8,0x24,0x38,0x74,0xb8,0x44,0xc8,0x54,0x56,0xd9,0xfe,0xb9,0x41,0xc9, +0x31,0xa9,0x21,0xf1,0x7e,0x2d,0x0c,0x18,0xd2,0x27,0x80,0x89,0x86,0xf7,0x9d, +0x08,0x92,0x26,0x43,0x66,0x19,0x02,0x31,0xdc,0x2d,0xb0,0xea,0x03,0xb9,0x11, +0xe9,0x96,0xf8,0x04,0xa8,0x36,0xd8,0x64,0xac,0x7a,0xad,0x0d,0xbd,0x0f,0xc2, +0x27,0x7f,0xe5,0xae,0xff,0xb8,0x21,0xad,0x03,0xc2,0x27,0x7f,0x25,0xae,0xff, +0xb8,0x41,0xa8,0x84,0x5c,0x0c,0xa5,0xad,0xff,0xb8,0x31,0xa8,0x94,0x5c,0x0c, +0x25,0xad,0xff,0x86,0x02,0x00,0xad,0x0f,0xb8,0x14,0xc8,0x21,0xed,0x03,0xa5, +0x33,0xff,0x90,0xea,0x03,0xd8,0x46,0x99,0x51,0x9c,0x5d,0xa8,0x64,0xbd,0x03, +0xc2,0x27,0x7f,0x88,0x15,0xe2,0x27,0x80,0x82,0x28,0x2e,0xf2,0xc6,0x14,0xe0, +0x08,0x00,0x98,0x51,0xa8,0x76,0xb8,0x66,0x38,0x11,0x88,0x96,0x30,0x39,0xc0, +0x80,0x33,0xc0,0x30,0xbb,0x53,0xb9,0x66,0xcc,0x2a,0x39,0x76,0xad,0x03,0x88, +0x15,0x82,0x28,0x28,0xe0,0x08,0x00,0x88,0x15,0x4d,0x0a,0x82,0x28,0x28,0xad, +0x03,0xe0,0x08,0x00,0xc1,0xb9,0x2d,0x88,0x15,0xbd,0x0a,0x82,0x28,0x2a,0xad, +0x04,0xe0,0x08,0x00,0x88,0x15,0x82,0x28,0x29,0x0c,0x03,0xe0,0x08,0x00,0x39, +0x86,0x0c,0x0b,0x0c,0x0c,0x88,0x05,0xa9,0x76,0x88,0xf8,0x1c,0x6a,0xe0,0x08, +0x00,0x1d,0xf0,0xb2,0x26,0x43,0x4c,0xfa,0x25,0xa5,0xff,0x1c,0x9a,0x0c,0x0b, +0x0c,0x4c,0x88,0x05,0xd2,0xa2,0x00,0x82,0x28,0x10,0x0c,0x0e,0xe0,0x08,0x00, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x41,0xeb,0x2c,0x42,0x24,0x10,0x48, +0x64,0x52,0x24,0x12,0x3c,0xaa,0xbd,0x05,0x25,0x1c,0xff,0xa9,0x44,0xbd,0x05, +0x4c,0x4a,0xa5,0x1b,0xff,0xa9,0x54,0xbd,0x05,0xa2,0xa0,0xfe,0xe5,0x1a,0xff, +0xa9,0x34,0x0b,0xb2,0xed,0x03,0xc2,0x24,0x11,0x0b,0x91,0x0c,0x48,0x76,0xa8, +0x0b,0x1b,0x22,0xd2,0x0b,0x01,0xd2,0x49,0x01,0x1b,0xbb,0x1b,0x99,0x92,0x01, +0x00,0xf2,0xa0,0xef,0x47,0x69,0x08,0xe2,0xc3,0xfe,0xf0,0x99,0x10,0x92,0x41, +0x00,0x66,0x19,0x25,0xd1,0xc2,0x2c,0x92,0x01,0x01,0xb2,0xa1,0x02,0x26,0x19, +0x27,0x26,0x29,0x4f,0x0c,0x13,0x4c,0x4a,0x82,0xc9,0xfd,0x16,0x98,0x07,0xb2, +0xc9,0xfc,0x16,0x3b,0x0a,0x26,0x59,0x07,0x0c,0x42,0x1d,0xf0,0x0c,0x22,0x1d, +0xf0,0xc2,0x01,0x02,0x26,0x2c,0x59,0x0c,0x32,0x1d,0xf0,0xf2,0x01,0x02,0x66, +0x1f,0xf5,0xb7,0x9e,0x51,0xbd,0x02,0x88,0xad,0xc2,0xa0,0xfe,0xe0,0x08,0x00, +0xad,0x04,0xb8,0x34,0xc8,0x24,0xe5,0x14,0xfb,0xb8,0xd4,0x2d,0x0a,0x98,0x24, +0xa8,0xe4,0x99,0x2b,0x65,0x51,0xfb,0x1d,0xf0,0xc2,0x01,0x02,0x66,0x1c,0xca, +0xb7,0x9e,0x26,0xbd,0x02,0x88,0xad,0xc2,0xa0,0xfe,0xe0,0x08,0x00,0xad,0x04, +0xb8,0x34,0xc8,0x14,0x25,0x12,0xfb,0xb8,0xb4,0x2d,0x0a,0x98,0x14,0xa8,0xc4, +0x99,0x2b,0xa5,0x4e,0xfb,0x1d,0xf0,0x3c,0xec,0xc7,0x1e,0x68,0x0c,0x62,0x1d, +0xf0,0xf2,0x01,0x02,0x66,0x1f,0x96,0x82,0xce,0xfc,0xc0,0xca,0xc0,0x87,0x9c, +0xec,0xbd,0x02,0x88,0xad,0xa8,0x54,0xe0,0x08,0x00,0xd8,0x94,0xad,0x04,0xd8, +0x3d,0xb8,0x54,0xcd,0x0d,0xd8,0x0d,0xe5,0x06,0xfb,0xb8,0x94,0x2d,0x0a,0x98, +0x0b,0x86,0x0b,0x00,0xf2,0x01,0x02,0x0b,0xff,0x56,0x4f,0xf6,0x82,0xce,0xfc, +0xc0,0xca,0xc0,0x87,0x9c,0xba,0xbd,0x02,0x88,0xad,0xa8,0x54,0xe0,0x08,0x00, +0xd8,0x74,0xad,0x04,0xd8,0x3d,0xb8,0x54,0xcd,0x0d,0xd8,0x0d,0xe5,0x03,0xfb, +0xb8,0x74,0x2d,0x0a,0x98,0x0b,0x39,0x19,0x39,0x2b,0x1d,0xf0,0xbd,0x02,0xa8, +0x44,0x88,0xad,0x3c,0xac,0xe0,0x08,0x00,0x1c,0xcb,0xc8,0x04,0xd8,0x44,0xc8, +0x1c,0xad,0x0d,0xc0,0x9c,0x20,0x76,0xab,0x09,0xe2,0x9a,0x01,0xe2,0x59,0x00, +0x2b,0xaa,0x2b,0x99,0xa8,0x64,0xb2,0x9d,0x00,0x25,0x48,0xfb,0x0c,0x02,0x1d, +0xf0,0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0xad,0x02,0x65,0xe7,0xff,0x2d,0x0a, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xb0,0xea,0x03,0x21,0x85,0x2c,0x98,0x32, +0x88,0x99,0xa8,0x02,0xb0,0x88,0xc0,0x89,0x99,0x65,0x00,0x04,0xe0,0xea,0x03, +0xd8,0x32,0xc8,0x9d,0xea,0xcc,0xc9,0x9d,0x1d,0xf0,0x36,0x41,0x00,0x65,0x13, +0x04,0x0c,0x32,0x00,0x50,0x00,0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x21, +0x79,0x2c,0x88,0x02,0x88,0x18,0x0c,0x1a,0xe0,0x08,0x00,0x88,0x02,0x88,0x18, +0x0c,0x2a,0xe0,0x08,0x00,0x88,0x02,0x88,0x18,0x0c,0x3a,0xe0,0x08,0x00,0x88, +0x02,0x88,0x18,0x0c,0x4a,0xe0,0x08,0x00,0x88,0x02,0x88,0x18,0x0c,0x5a,0xe0, +0x08,0x00,0x88,0x02,0x88,0x18,0x0c,0x6a,0xe0,0x08,0x00,0x88,0x02,0x88,0x18, +0xa1,0x25,0x2d,0xe0,0x08,0x00,0x0c,0x0c,0x61,0x24,0x2d,0x0c,0x89,0x3d,0x06, +0x52,0xc6,0x20,0x76,0xa9,0x03,0xc9,0x03,0x4b,0x33,0xa9,0x21,0x91,0x20,0x2d, +0x0c,0x8b,0x3d,0x09,0x42,0xc9,0x20,0x76,0xab,0x03,0xc9,0x03,0x4b,0x33,0x88, +0x02,0x88,0x18,0x0c,0xaa,0xe0,0x08,0x00,0x88,0x02,0xa9,0x01,0x88,0x18,0x0c, +0xba,0xe0,0x08,0x00,0x88,0x02,0x3d,0x0a,0x88,0x18,0x0c,0xca,0xe0,0x08,0x00, +0x39,0x31,0x88,0x02,0xa9,0x11,0x88,0x18,0x0c,0xda,0xe0,0x08,0x00,0x7d,0x0a, +0x3d,0x06,0x88,0x02,0x88,0x58,0xe0,0x08,0x00,0xa9,0x03,0x4b,0x33,0x57,0x93, +0xf1,0x31,0x0c,0x2d,0x88,0x02,0x88,0x58,0xe0,0x08,0x00,0xa9,0x03,0x4b,0x33, +0x47,0x93,0xf1,0x88,0x02,0xa8,0x01,0x88,0x48,0xb8,0x06,0xe0,0x08,0x00,0x88, +0x02,0xa8,0x01,0x88,0x48,0xb8,0x16,0xe0,0x08,0x00,0xb8,0x26,0x88,0x02,0x38, +0x31,0x88,0x48,0xad,0x03,0xe0,0x08,0x00,0x88,0x02,0xad,0x03,0x88,0x48,0xb8, +0x36,0xe0,0x08,0x00,0x41,0xfc,0x2c,0x38,0x11,0x88,0x02,0xad,0x03,0x88,0x38, +0xb8,0x44,0xe0,0x08,0x00,0x88,0x02,0xad,0x03,0x88,0x38,0xb8,0x54,0xe0,0x08, +0x00,0x88,0x02,0xad,0x03,0x88,0x48,0xb8,0x46,0xe0,0x08,0x00,0x88,0x02,0xad, +0x07,0x88,0x38,0xb8,0x64,0xe0,0x08,0x00,0x88,0x02,0xb8,0x74,0x88,0x38,0xad, +0x07,0xe0,0x08,0x00,0x88,0x02,0xad,0x07,0x88,0x48,0xb8,0x66,0xe0,0x08,0x00, +0x88,0x02,0x88,0x18,0x0c,0x8a,0xe0,0x08,0x00,0x88,0x02,0x88,0x08,0xa2,0xa0, +0x80,0xe0,0x08,0x00,0x88,0x02,0x6d,0x0a,0x88,0x18,0xa1,0xe5,0x2c,0xe0,0x08, +0x00,0x88,0x02,0x7d,0x0a,0x88,0x08,0xa1,0xe3,0x2c,0xe0,0x08,0x00,0x88,0x02, +0x88,0x08,0xa1,0xe2,0x2c,0xe0,0x08,0x00,0x88,0x02,0x88,0x58,0xe0,0x08,0x00, +0x88,0x02,0x88,0x58,0x5d,0x0a,0xe0,0x08,0x00,0xbd,0x05,0x4d,0x0a,0x88,0x02, +0x38,0x21,0x88,0x48,0xad,0x03,0xe0,0x08,0x00,0x88,0x02,0xad,0x03,0x88,0x38, +0xbd,0x04,0xe0,0x08,0x00,0x88,0x02,0xbd,0x05,0x88,0x38,0xad,0x06,0xe0,0x08, +0x00,0x88,0x02,0xbd,0x04,0x88,0x48,0xad,0x06,0xe0,0x08,0x00,0x88,0x02,0x88, +0x18,0xa1,0xd0,0x2c,0xe0,0x08,0x00,0x88,0x02,0xbd,0x0a,0x88,0x28,0x1c,0x7a, +0xe0,0x08,0x00,0x88,0x02,0xbd,0x07,0x88,0x28,0x1c,0x9a,0xe0,0x08,0x00,0x88, +0x02,0xbd,0x03,0x88,0x28,0x0c,0x7a,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x36, +0x61,0x00,0xe5,0xfb,0x03,0xa1,0xc5,0x2c,0xb1,0xc5,0x2c,0xc1,0xc6,0x2c,0xd1, +0xc6,0x2c,0xe1,0xc6,0x2c,0xf1,0xc6,0x2c,0x0c,0x42,0x00,0x50,0x00,0xe0,0x02, +0x00,0xbd,0x0a,0x31,0xfc,0x2b,0xa1,0xc3,0x2c,0xb9,0x03,0xa2,0x6b,0x15,0x91, +0x80,0x2c,0xc0,0x20,0x00,0x92,0x29,0x98,0x0c,0x02,0x27,0x69,0x01,0x1d,0xf0, +0xad,0x01,0x0c,0x0c,0x0c,0x62,0xf1,0xbd,0x2c,0x92,0x2b,0x1f,0x51,0xdf,0x2b, +0xd2,0x2b,0x1e,0xe2,0x2b,0x1d,0xe2,0x63,0x1b,0xd2,0x63,0x1a,0x88,0x05,0x92, +0x63,0x19,0xf9,0x08,0x00,0x50,0x00,0x29,0x13,0xf2,0x22,0x14,0xd2,0x22,0x13, +0xd9,0x23,0xf8,0x0f,0xf9,0x11,0xe9,0x31,0xd9,0x21,0xc9,0x01,0x65,0xf8,0x03, +0x25,0xdb,0xff,0x41,0x5b,0x2c,0xe8,0x04,0xcc,0xfe,0xa1,0xae,0x2c,0x88,0x55, +0xb1,0xae,0x2c,0xe0,0x08,0x00,0xa9,0x14,0x0c,0x19,0x99,0x04,0xa8,0x03,0x82, +0x2a,0x17,0xe0,0x08,0x00,0x0c,0x12,0x1d,0xf0,0x36,0x41,0x00,0x2f,0x20,0x01, +0x22,0x44,0x0c,0x0c,0x11,0x6f,0xe4,0x04,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0, +0x0a,0x22,0xa8,0x00,0x06,0x10,0xaf,0xe0,0x0a,0x22,0x50,0x00,0x00,0x19,0xaf, +0xe0,0x0a,0x22,0xa4,0x00,0x06,0x10,0xaf,0xe0,0x0a,0x22,0xa8,0x00,0x01,0x00, +0x4f,0x00,0x28,0x48,0x44,0x0c,0x0c,0x11,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41, +0x00,0x6f,0xe4,0x00,0x22,0x44,0x0c,0x0c,0x11,0x1c,0xf2,0xaf,0xe0,0x0a,0x22, +0x82,0x08,0x04,0x00,0x4f,0x00,0x28,0x48,0x44,0x0c,0x0c,0x11,0x1d,0xf0,0x00, +0x36,0x41,0x00,0x30,0x00,0x0c,0x1c,0xf4,0xaf,0xe0,0x0a,0x22,0x02,0x09,0x04, +0x00,0x00,0x02,0x0d,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x02,0x70, +0x64,0x00,0x61,0x7a,0x2c,0x41,0xbc,0x2b,0x3d,0x06,0x62,0xc6,0x20,0xa8,0x03, +0x8c,0x8a,0x88,0x04,0x88,0x98,0xe0,0x08,0x00,0x20,0x2a,0x53,0x4b,0x33,0x67, +0x93,0xec,0xa1,0x81,0x2c,0xa2,0x1a,0x40,0xa7,0xa2,0x05,0x20,0x5a,0xc0,0x46, +0x00,0x00,0x0c,0x05,0x31,0x6e,0x2c,0xb8,0x03,0x0c,0x02,0x9c,0x1b,0xa6,0x15, +0x0f,0x88,0x04,0xa8,0x03,0x88,0x68,0x0c,0x0b,0xe0,0x08,0x00,0x1b,0x22,0x27, +0x95,0xef,0x4b,0x33,0x67,0x93,0xe1,0x70,0xe6,0x13,0x20,0x20,0x00,0x1d,0xf0, +0x36,0x41,0x00,0x51,0x73,0x2c,0x0c,0xb6,0x0c,0x83,0x76,0xa3,0x14,0x48,0x05, +0x4b,0x55,0x67,0x14,0x0a,0x98,0x22,0x88,0x12,0x97,0x18,0x03,0x0c,0x02,0x1d, +0xf0,0x22,0xc2,0x10,0x0c,0x12,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0x0b, +0x0c,0x1c,0x0c,0x0d,0xed,0x02,0x31,0x66,0x2c,0xf1,0x67,0x2c,0xa2,0x93,0x20, +0xe5,0xaa,0x01,0xa2,0x93,0x22,0x0c,0x0b,0x0c,0x1c,0x0c,0x0d,0xed,0x02,0xf1, +0x63,0x2c,0xe5,0xa9,0x01,0xa2,0x93,0x24,0x0c,0x0b,0x0c,0x1c,0x0c,0x0d,0xed, +0x02,0xf1,0x60,0x2c,0xe5,0xa8,0x01,0xa2,0x93,0x26,0x0c,0x0b,0x0c,0x1c,0x0c, +0x0d,0xed,0x02,0xf1,0x5d,0x2c,0xe5,0xa7,0x01,0xa2,0x93,0x28,0x0c,0x0b,0x0c, +0x1c,0x0c,0x0d,0xf0,0xe2,0x11,0xf1,0x59,0x2c,0xa5,0xa6,0x01,0xed,0x02,0xa2, +0x93,0x2a,0x0c,0x0b,0x0c,0x1c,0x0c,0x0d,0xf1,0x56,0x2c,0xa5,0xa5,0x01,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x61,0x54,0x2c,0x41,0x54,0x2c,0xf0,0x73,0x11,0x52, +0xc4,0x18,0x88,0x04,0x80,0xa8,0x23,0x66,0x78,0x23,0x66,0x12,0x10,0xb1,0x4c, +0x2c,0xa5,0xaa,0x01,0xbd,0x07,0xa2,0x94,0x00,0xe5,0xac,0x01,0x06,0x05,0x00, +0xbd,0x06,0xa5,0xa9,0x01,0xa2,0x94,0x00,0xbd,0x03,0xe5,0xab,0x01,0x06,0x01, +0x00,0xbd,0x03,0x65,0xab,0x01,0x4b,0x44,0x57,0x94,0xc9,0x1d,0xf0,0x00,0x36, +0x61,0x00,0x3d,0x02,0x29,0x11,0x0c,0x14,0x21,0x42,0x2c,0x71,0x6c,0x2b,0x28, +0x02,0x82,0x23,0xbd,0x22,0x22,0x52,0x56,0xc8,0x04,0x42,0x63,0xbd,0xa8,0x02, +0x39,0x11,0xa6,0x1a,0x42,0x5d,0x02,0x61,0x3c,0x2c,0x0c,0x08,0x89,0x01,0xd8, +0x15,0x0c,0x03,0x98,0x0d,0x0c,0x04,0xa6,0x19,0x21,0x3c,0x4c,0x88,0x07,0xb8, +0x16,0xda,0xa3,0x4b,0xaa,0x3a,0xbb,0x82,0x28,0x20,0x4b,0xbb,0xe0,0x08,0x00, +0xd8,0x15,0x32,0xc3,0x34,0xb8,0x0d,0x1b,0x44,0xb7,0x24,0xdf,0xa8,0x02,0x4b, +0x66,0xc8,0x01,0x4b,0x55,0x1b,0xcc,0xc9,0x01,0xa7,0x2c,0xc5,0x38,0x11,0x0c, +0x14,0x0c,0x1a,0x0c,0xab,0xc8,0x12,0x3c,0x4e,0x91,0x2a,0x2c,0x88,0x07,0x98, +0x29,0x51,0x29,0x2c,0xc0,0x99,0x11,0x9a,0x55,0xd8,0x25,0x88,0xf8,0xd0,0xd0, +0x34,0xe0,0xdd,0xd1,0xda,0xcc,0x4b,0xcc,0xe0,0x08,0x00,0x0c,0x1a,0x0c,0xbb, +0xc8,0x22,0x3c,0x4e,0x88,0x07,0xd8,0x25,0x88,0xf8,0xd0,0xd4,0x34,0xe0,0xdd, +0xd1,0xda,0xcc,0x4b,0xcc,0xe0,0x08,0x00,0x0c,0x1a,0x0c,0xcb,0xc8,0x32,0x3c, +0x4e,0x88,0x07,0xd8,0x25,0x88,0xf8,0xd0,0xd8,0x34,0xe0,0xdd,0xd1,0xda,0xcc, +0x4b,0xcc,0xe0,0x08,0x00,0x0c,0x1a,0x0c,0xdb,0xc8,0x42,0x3c,0x4e,0x88,0x07, +0xd8,0x25,0x88,0xf8,0xd0,0xdc,0x34,0xe0,0xdd,0xd1,0xda,0xcc,0x4b,0xcc,0xe0, +0x08,0x00,0x0c,0x1a,0x88,0x07,0x1c,0x9b,0x88,0xf8,0x7c,0xfc,0xe0,0x08,0x00, +0x42,0x63,0xc6,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x31,0x0a,0x2c,0x0c,0x02, +0xa2,0x93,0x01,0xbd,0x02,0x25,0x17,0x00,0x32,0xc3,0x10,0x1b,0x22,0x66,0x82, +0xef,0x31,0x06,0x2c,0x0c,0x02,0xa2,0x93,0x01,0xbd,0x02,0x65,0x19,0x00,0x32, +0xc3,0x10,0x1b,0x22,0x66,0x82,0xef,0x1d,0xf0,0x00,0x36,0x41,0x00,0x51,0x00, +0x2c,0x88,0x05,0x42,0x28,0x3e,0x40,0x44,0x04,0xcc,0x28,0x0c,0x02,0x1d,0xf0, +0xf6,0x92,0x1d,0x81,0xfc,0x2b,0x80,0x22,0xa0,0xa8,0x02,0x0c,0x09,0x96,0x8a, +0x02,0xbd,0x03,0x65,0x2f,0xff,0xd6,0xba,0x01,0x7c,0xf9,0x99,0x02,0x0c,0x09, +0x46,0x00,0x00,0x0c,0x09,0xa2,0x25,0x8b,0x0c,0x02,0x8c,0x6a,0x8c,0x09,0x8c, +0x24,0x0c,0x12,0x1d,0xf0,0x1d,0xf0,0x0c,0x19,0x46,0xfa,0xff,0x86,0xf9,0xff, +0x36,0x41,0x00,0x61,0xee,0x2b,0x7c,0xf5,0x82,0xa0,0x8b,0x1b,0x55,0x72,0x96, +0x0e,0x62,0xc6,0x10,0x27,0x17,0x02,0x87,0x97,0xf1,0x20,0x37,0xc0,0x7c,0xf2, +0x30,0x25,0x83,0x1d,0xf0,0x00,0x36,0x41,0x00,0x61,0xd4,0x2b,0xe6,0x62,0x23, +0x0c,0x05,0x62,0xc6,0xe0,0x32,0xa0,0x08,0x76,0xa3,0x13,0x48,0x06,0x4b,0x66, +0x27,0x94,0x0a,0x21,0xe0,0x2b,0x20,0x25,0x90,0x22,0x12,0x00,0x1d,0xf0,0x1b, +0x55,0x7c,0xf2,0x1d,0xf0,0x00,0x0c,0x05,0x0c,0x83,0x76,0xa3,0x13,0x48,0x06, +0x4b,0x66,0x27,0x94,0x0a,0x21,0xd9,0x2b,0x20,0x25,0x90,0x22,0x12,0x00,0x1d, +0xf0,0x1b,0x55,0x7c,0xf2,0x1d,0xf0,0x36,0x41,0x00,0x41,0xd0,0x2b,0x0c,0x03, +0x32,0x64,0x8a,0x22,0x64,0x89,0x1d,0xf0,0x36,0x41,0x00,0xb1,0xcc,0x2b,0xa2, +0x2b,0x8a,0x82,0x2b,0x89,0x1b,0xca,0x87,0x2a,0x03,0x0c,0x12,0x1d,0xf0,0xd2, +0xcb,0x24,0xda,0xda,0x22,0x4d,0x00,0x92,0x2b,0x89,0xc2,0x6b,0x8a,0xc7,0x99, +0x13,0x81,0xe7,0x2a,0x1c,0x8a,0x88,0x08,0x1c,0x9b,0x88,0xf8,0x0c,0x0c,0xe0, +0x08,0x00,0x0c,0x12,0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0x31,0xb8,0x2b,0x38,0x23,0x21,0xb8,0x2b,0xc0,0x33,0x11,0x3a,0x22,0x22,0x92, +0x06,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x21,0xb6,0x2b,0x28,0x02,0x41, +0xb2,0x2b,0x32,0x22,0x40,0x22,0x22,0x41,0x8c,0x83,0xc0,0x22,0x11,0x2a,0x24, +0x22,0x92,0x06,0x1d,0xf0,0x21,0xab,0x2b,0x28,0x22,0x46,0xfb,0xff,0x00,0x00, +0x00,0x36,0x41,0x00,0xf6,0x83,0x2a,0xa1,0xb0,0x2b,0xbd,0x02,0xa0,0xa3,0xa0, +0xa8,0x0a,0xe5,0xe9,0xff,0xc2,0xa0,0xc8,0xc0,0xe3,0x11,0xd1,0xa4,0x2b,0x81, +0xa0,0x2b,0xbd,0x0a,0x88,0x08,0xad,0x02,0x82,0x28,0x2c,0xea,0xdd,0xe0,0x08, +0x00,0x0c,0x02,0x1d,0xf0,0x7c,0xf2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00, +0xf6,0x83,0x3b,0x41,0x9d,0x2b,0xe8,0x04,0x82,0x2e,0x40,0x0c,0x1b,0xdc,0x28, +0xa1,0x8b,0x2b,0xbd,0x02,0xa0,0xa3,0xa0,0xa8,0x0a,0xa5,0xe5,0xff,0xbd,0x0a, +0xe8,0x04,0xc6,0xff,0xff,0xad,0x02,0xc2,0x2e,0x45,0x81,0x8e,0x2b,0xc0,0xf3, +0x11,0x88,0x08,0xd1,0x91,0x2b,0x82,0x28,0x2c,0xfa,0xdd,0xe0,0x08,0x00,0x0c, +0x02,0x1d,0xf0,0x7c,0xf2,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xc0,0x73,0x11, +0x52,0x22,0xc0,0xc0,0x64,0x11,0x6a,0x65,0x7a,0x55,0x58,0x15,0x59,0x16,0x1d, +0xf0,0x00,0x00,0x36,0x41,0x00,0xf6,0x83,0x22,0xad,0x02,0x0c,0x1b,0xc1,0x84, +0x2b,0xc0,0xe3,0x11,0xd1,0x89,0x2b,0x81,0x7c,0x2b,0xea,0xdd,0x88,0x08,0xc8, +0x0c,0x82,0x28,0x2c,0xc2,0x2c,0x45,0xe0,0x08,0x00,0x0c,0x02,0x1d,0xf0,0x7c, +0xf2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xb6,0x82,0x03,0x7c,0xf2,0x1d, +0xf0,0x41,0x76,0x2b,0xc0,0x22,0x11,0x2a,0x24,0x22,0x92,0x01,0x29,0x03,0x0c, +0x02,0x1d,0xf0,0x00,0x36,0x41,0x00,0xb6,0x82,0x03,0x7c,0xf2,0x1d,0xf0,0x41, +0x70,0x2b,0xc0,0x22,0x11,0x2a,0x24,0x22,0x92,0x01,0x29,0x03,0x0c,0x02,0x1d, +0xf0,0x00,0x36,0x61,0x00,0x71,0x48,0x2b,0x61,0x5d,0x2b,0x51,0x6a,0x2b,0x21, +0x5b,0x2b,0x31,0x63,0x2b,0x42,0xc2,0xe0,0x88,0x03,0x82,0x28,0x3f,0xa8,0x04, +0xe0,0x08,0x00,0x9c,0xaa,0xa8,0x04,0xc8,0x05,0x88,0x03,0xc2,0x2c,0x33,0x82, +0x28,0x20,0xa0,0xba,0xa0,0xb0,0xbb,0x11,0x70,0xaa,0xa0,0xa8,0x0a,0xba,0xb6, +0xe0,0x08,0x00,0x4b,0x44,0x27,0x94,0xd2,0x41,0x63,0x2b,0x0c,0x0f,0xf9,0x01, +0xd8,0x02,0x0c,0xa8,0xd7,0x28,0x4a,0x66,0x7d,0x2a,0x98,0x01,0x0c,0x1a,0xe6, +0x19,0x40,0xa9,0x01,0x66,0x7d,0x1e,0xe8,0x05,0xb2,0x2e,0x3e,0x37,0x6b,0x16, +0xa1,0x30,0x2b,0xb1,0x48,0x2b,0x88,0x03,0xc2,0x2e,0x33,0x82,0x28,0x20,0xf0, +0xcc,0x11,0xe0,0x08,0x00,0x06,0x07,0x00,0xe6,0x9d,0x19,0xc8,0x05,0x88,0x03, +0xd0,0xbd,0xa0,0x70,0xad,0xa0,0xa8,0x0a,0xb0,0xbb,0x11,0xba,0xb6,0x82,0x28, +0x20,0xc2,0x2c,0x33,0xe0,0x08,0x00,0x4b,0x22,0x47,0x92,0xa8,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0x0c,0x84,0x51,0x22,0x2b,0xc1,0x32,0x2b,0xf1,0x1e,0x2b, +0xd2,0xcc,0x60,0xe2,0xcc,0x10,0x32,0xcf,0xe0,0x82,0xc5,0x70,0x92,0xc5,0x40, +0xa2,0xc5,0x20,0xb8,0x0c,0xf9,0xd2,0x42,0x62,0x37,0x42,0x52,0x16,0x42,0x52, +0x17,0x59,0x92,0xe9,0xc2,0xd2,0x62,0x1b,0xb2,0x62,0x36,0xc2,0xcc,0x70,0xa9, +0xa2,0xc2,0x62,0x1c,0x92,0x62,0x46,0x82,0x62,0xbf,0x32,0x62,0x14,0x81,0x3a, +0x2b,0x31,0x2f,0x2b,0x32,0x62,0x18,0x82,0x62,0x10,0x92,0xd8,0x0e,0xc2,0xc8, +0x60,0xb2,0xd8,0xe7,0xa2,0xd8,0x0d,0xd2,0xc8,0x40,0xe2,0xc8,0x20,0xe2,0x62, +0x11,0xd2,0x62,0x12,0xa2,0x62,0x19,0xb2,0x62,0x15,0xc2,0x62,0x13,0x92,0x62, +0x22,0x52,0xd3,0x01,0x42,0xd3,0x03,0x42,0x62,0x2c,0x52,0x62,0xc0,0x91,0x28, +0x2b,0xc1,0x2b,0x2b,0xc2,0x62,0x1e,0x92,0x62,0x23,0xb2,0xc9,0x20,0xa2,0xc9, +0x40,0xd2,0xcc,0x30,0xe2,0xcc,0x20,0xf2,0xcc,0x10,0xf2,0x62,0x1f,0xe2,0x62, +0x20,0xd2,0x62,0x21,0xa2,0x62,0xc2,0xb2,0x62,0x24,0xa1,0x23,0x2b,0x0c,0x09, +0x92,0x52,0x3a,0x92,0x52,0x77,0x92,0x52,0x7a,0x92,0x52,0x7b,0x92,0x62,0xc5, +0x92,0x62,0xc6,0xa2,0x62,0x2e,0xc1,0x1c,0x2b,0xc2,0x62,0x25,0xb2,0xca,0x40, +0xb2,0x62,0x30,0x82,0xcc,0x10,0x52,0xcc,0x20,0x32,0xcc,0x50,0x42,0xcc,0x30, +0xd2,0xcc,0xf0,0xe2,0xcc,0xe0,0xf2,0xcc,0x70,0x0c,0xaa,0xa2,0x52,0x75,0xf2, +0x62,0x2b,0xe2,0x62,0xc3,0xd2,0x62,0xc4,0x42,0x62,0x28,0x32,0x62,0x29,0x52, +0x62,0x27,0x82,0x62,0x26,0x1c,0x0b,0xb2,0x52,0x3b,0x7c,0xe8,0x52,0x22,0x3e, +0x0c,0x73,0x3c,0x04,0xd1,0x0c,0x2b,0xe2,0xa1,0x00,0x0c,0x3f,0xf2,0x52,0x73, +0xe2,0x52,0x74,0xd9,0xe2,0x42,0x62,0x38,0x32,0x52,0x72,0x92,0xad,0xff,0x31, +0xf5,0x2a,0x80,0x55,0x10,0x41,0xf5,0x2a,0x49,0x12,0x7c,0xd8,0x39,0x22,0x80, +0x55,0x10,0x0c,0x48,0x0c,0x2c,0x80,0x55,0x20,0x7c,0x78,0x80,0x55,0x10,0xc2, +0x52,0x34,0x6c,0xf8,0x80,0x55,0x10,0x82,0xaf,0xdf,0x80,0x55,0x10,0x82,0xaf, +0xbf,0x80,0x55,0x10,0x90,0x55,0x10,0x81,0xf8,0x2a,0x0c,0xd9,0x92,0x52,0x76, +0x80,0x55,0x10,0x82,0xae,0xff,0x80,0x55,0x10,0x52,0x62,0x3e,0x82,0xa0,0xc8, +0x82,0x52,0x62,0x51,0xf3,0x2a,0x52,0x62,0x3c,0x1d,0xf0,0x00,0x00,0x00,0x36, +0xa1,0x00,0x29,0x81,0x61,0xe1,0x2a,0x0c,0x0f,0x71,0x04,0x2a,0x9d,0x03,0x31, +0xd9,0x2a,0x16,0xc9,0x04,0x0c,0x1b,0xd1,0x68,0x2a,0xc1,0xcc,0x2a,0xa1,0x55, +0x2a,0x0b,0x89,0x16,0xa8,0x20,0xe2,0xc9,0xfe,0x16,0x9e,0x6c,0x82,0xc9,0xfc, +0x16,0x98,0x26,0xa2,0xc9,0xfb,0x16,0x6a,0x1f,0xe1,0xe4,0x2a,0x82,0xc9,0xf9, +0x16,0x38,0x2b,0xa2,0xcc,0x40,0x82,0xc9,0xea,0x16,0x78,0x2d,0xd2,0xc9,0xe8, +0x16,0x7d,0x46,0xe2,0xc9,0xe4,0x16,0x3e,0x21,0xf1,0xdd,0x2a,0xf0,0xf9,0xc0, +0x56,0xff,0x1c,0xb9,0x76,0x1d,0xf0,0x0c,0x05,0x91,0xe1,0x2a,0x81,0xda,0x2a, +0xb1,0xde,0x2a,0xf1,0xd9,0x2a,0xe1,0xda,0x2a,0xd1,0xda,0x2a,0xa8,0x03,0xc1, +0xda,0x2a,0xc2,0x6a,0x3a,0xd2,0x6a,0x35,0xe2,0x6a,0x39,0xf2,0x6a,0x38,0xb2, +0x6a,0x41,0x82,0x6a,0x3f,0x1c,0x0b,0x88,0x07,0x92,0x6a,0x33,0x82,0x28,0x1d, +0xa2,0xa3,0x40,0xe0,0x08,0x00,0x4d,0x0a,0x0c,0x0b,0xc2,0xa3,0x40,0x65,0x16, +0xfa,0x9d,0x04,0x0c,0x4b,0xd8,0x81,0xa1,0xb3,0x2a,0x49,0x3d,0x49,0x06,0x52, +0x64,0x40,0xc8,0x2a,0xc2,0x64,0x41,0xc2,0xc4,0x10,0x76,0xab,0x10,0x0c,0x8e, +0x1c,0x8f,0x1c,0x08,0x82,0x69,0x9f,0xf2,0x69,0xa9,0xe2,0x69,0xb3,0x4b,0x99, +0x92,0xc4,0x18,0xa2,0xc4,0x20,0x0c,0x2b,0x76,0xab,0x10,0x0c,0x8d,0x1c,0x8e, +0x1c,0x0f,0xf2,0x69,0x9f,0xe2,0x69,0xa9,0xd2,0x69,0xb3,0x4b,0x99,0x3c,0x8d, +0x4c,0x09,0xb2,0xa0,0x48,0x82,0xa0,0x02,0x76,0xa8,0x0a,0x92,0x6c,0x9f,0xb2, +0x6c,0xa9,0xd2,0x6c,0xb3,0x4b,0xcc,0x0c,0x2c,0x76,0xac,0x0a,0x92,0x6a,0x9f, +0xb2,0x6a,0xa9,0xd2,0x6a,0xb3,0x4b,0xaa,0xad,0x04,0xd1,0xb8,0x2a,0xe1,0xb5, +0x2a,0x81,0xb3,0x2a,0x98,0x03,0xf1,0xb4,0x2a,0xf2,0x69,0x4d,0x82,0x69,0x4f, +0xe8,0x0e,0x81,0xb2,0x2a,0x82,0x69,0x4c,0xf2,0x2e,0x16,0xf2,0x64,0xbe,0xd2, +0x6e,0x16,0xe5,0xd3,0xff,0xa1,0xaf,0x2a,0x0c,0x89,0x76,0xa9,0x03,0x59,0x0a, +0x4b,0xaa,0x91,0x90,0x2a,0x7c,0xfa,0xb2,0xa0,0x0a,0x76,0xab,0x03,0xa9,0x09, +0x4b,0x99,0x0c,0x62,0x00,0x50,0x00,0x29,0x66,0x29,0x04,0x88,0x03,0x82,0x28, +0x46,0xad,0x04,0xe0,0x08,0x00,0x88,0x07,0x0c,0x0a,0x82,0x28,0x1d,0x0c,0x4b, +0xe0,0x08,0x00,0xa0,0x90,0x60,0xa1,0xa1,0x2a,0x88,0x03,0x99,0x0a,0x82,0x28, +0x47,0xad,0x04,0xe0,0x08,0x00,0x88,0x07,0x0c,0x0a,0x82,0x28,0x1d,0x0c,0x4b, +0xe0,0x08,0x00,0xc1,0x9a,0x2a,0xb8,0x0c,0xaa,0xbb,0xa1,0x77,0x2a,0xb9,0x0c, +0xa8,0x1a,0x25,0xa3,0xff,0x91,0x74,0x2a,0xbd,0x0a,0xa9,0x29,0x66,0x0a,0x05, +0x59,0x19,0x0c,0x0b,0xb9,0x29,0x88,0x03,0xad,0x04,0x82,0x28,0x3d,0xc2,0xa0, +0x8b,0xe0,0x08,0x00,0x52,0x66,0x8b,0x0c,0x03,0x0c,0x0a,0xbd,0x03,0x65,0xb0, +0xff,0x1b,0x33,0x66,0x83,0xf3,0x4c,0x06,0x0c,0x03,0x0c,0x0a,0xbd,0x03,0xe5, +0xb2,0xff,0x0c,0x0a,0xbd,0x03,0xa5,0xb8,0xff,0x1b,0x33,0x66,0x83,0xec,0x52, +0x64,0xbd,0x52,0x64,0x45,0x92,0x24,0x3e,0x2c,0x0a,0xa0,0x99,0x20,0x60,0x99, +0x20,0x92,0x64,0x3e,0x65,0x95,0xff,0x0c,0x8a,0x0c,0x0b,0x0c,0x4c,0x88,0x07, +0xd2,0xa5,0x00,0x82,0x28,0x10,0xe1,0x7d,0x2a,0xe0,0x08,0x00,0x0c,0x8a,0x0c, +0x0b,0x0c,0x4c,0x88,0x07,0xd2,0xa4,0x00,0x82,0x28,0x10,0xe1,0x79,0x2a,0xe0, +0x08,0x00,0x1d,0xf0,0x7c,0x77,0x1c,0x9e,0x40,0x90,0x74,0xe7,0x99,0xf3,0xf9, +0x76,0xb9,0x2c,0xe8,0x06,0xb9,0x3c,0xc8,0x3e,0x5c,0x04,0xa0,0x8c,0xc0,0x56, +0xe8,0x2f,0xd2,0x2e,0x3e,0x0c,0x89,0x92,0x6e,0x37,0x70,0xcd,0x10,0xd0,0xd9, +0x04,0xd0,0xdd,0x11,0xd0,0xcc,0x20,0xc2,0x6e,0x3e,0xd2,0x2e,0x3f,0xc6,0xc3, +0x00,0x3d,0x0f,0x4d,0x0a,0xf8,0x07,0xf2,0x2f,0x10,0x37,0x55,0x0f,0x1c,0x7a, +0x0c,0x0b,0x0c,0x4c,0x0c,0x3d,0xed,0x04,0xe0,0x0f,0x00,0x06,0x03,0x00,0x1c, +0x7a,0x0c,0x0b,0x0c,0x4c,0x0c,0x4d,0xed,0x04,0xe0,0x0f,0x00,0x4b,0x44,0x1b, +0x33,0x66,0x73,0xd3,0x1d,0xf0,0xe1,0xd1,0x29,0x7c,0x73,0xe7,0xa4,0x02,0x86, +0x97,0x00,0x47,0xae,0x02,0x86,0xed,0x00,0xe8,0x06,0x92,0x2e,0x40,0x16,0x59, +0x51,0xb6,0x49,0x02,0xc6,0xdc,0xff,0x16,0x09,0xf7,0x50,0x84,0x35,0xcc,0x78, +0xb2,0x6e,0x42,0x50,0xa0,0xf4,0xa2,0x6e,0x41,0x50,0xc0,0x35,0x8c,0x7c,0xb2, +0x6e,0x43,0x50,0xd8,0x75,0xd2,0x6e,0x44,0x66,0x39,0x12,0x0c,0x03,0xa2,0xaf, +0xbf,0xbd,0x03,0xe5,0xa8,0xff,0x0c,0x1b,0x1b,0x33,0x66,0x83,0xf0,0xe8,0x06, +0xb2,0x6e,0x40,0x1d,0xf0,0xe2,0xc4,0xf6,0xb6,0x4e,0x02,0x06,0xcc,0xff,0x98, +0x06,0x92,0x29,0x40,0x26,0x19,0x7e,0xa2,0xc9,0xfd,0x56,0x0a,0x0e,0xa1,0x26, +0x2a,0x25,0x67,0xff,0x16,0x7a,0x0d,0xc8,0x06,0x0c,0x0b,0xb2,0x6c,0x40,0xe5, +0x83,0xff,0x86,0x32,0x00,0x7d,0x0e,0x98,0x3c,0x4d,0x0a,0xa6,0x19,0x1b,0xe1, +0x39,0x2a,0x81,0x24,0x2a,0x0b,0xa9,0xa9,0x3c,0xd2,0x98,0x06,0x82,0x98,0x07, +0xd2,0xcd,0xf0,0xd2,0x5e,0x7c,0x82,0xc8,0xf0,0x82,0x5e,0x7d,0x0c,0x05,0xe5, +0xa8,0xff,0xad,0x04,0x0c,0x7b,0xe5,0x0c,0x01,0xa8,0x06,0xe5,0x37,0x02,0xa8, +0x06,0xa5,0x06,0x03,0x88,0x03,0x82,0x28,0x4e,0xa8,0x06,0xe0,0x08,0x00,0x88, +0x03,0x82,0x28,0x4b,0xa8,0x06,0xe0,0x08,0x00,0xe8,0x06,0x92,0x2e,0xc6,0x59, +0xf7,0xe6,0x19,0x02,0x06,0xac,0xff,0x0b,0xa9,0xa2,0x6e,0xc6,0x1d,0xf0,0xa1, +0x08,0x2a,0xa5,0x5f,0xff,0xcc,0x6a,0xb8,0x06,0xb2,0x2b,0xc5,0x16,0x7b,0x05, +0xc1,0xff,0x29,0xd1,0x03,0x2a,0xd9,0x91,0xc9,0x71,0xa2,0xaf,0xa6,0x0c,0x0b, +0x88,0x03,0x0c,0x0c,0x82,0x28,0x2c,0xd8,0x91,0xe0,0x08,0x00,0x98,0x91,0xa8, +0x71,0x92,0xc9,0x10,0x99,0x91,0xa7,0x99,0xe2,0xe8,0x06,0xb2,0x2e,0x43,0x9c, +0x3b,0xb2,0x2e,0x44,0x88,0x07,0x1c,0xfa,0x88,0xf8,0x0c,0x0c,0xe0,0x08,0x00, +0xe8,0x06,0x0c,0x09,0x92,0x6e,0x43,0xc2,0x2e,0x41,0x88,0x07,0x0c,0x1a,0x88, +0xf8,0x1c,0x9b,0xe0,0x08,0x00,0xa8,0x06,0x0c,0x29,0x92,0x6a,0x40,0xd8,0x76, +0x56,0xcd,0xe3,0x88,0x03,0x82,0x28,0x36,0xa8,0x06,0xe0,0x08,0x00,0xe8,0x06, +0x92,0x2e,0x3e,0x90,0x97,0x04,0x16,0x99,0x3f,0x0c,0x0a,0xb2,0x1e,0x16,0xa9, +0xa1,0xa6,0x1b,0x48,0x0c,0x04,0xc2,0x2e,0x23,0x4a,0xcc,0xc8,0x0c,0xc2,0xcc, +0xf4,0xb6,0x2c,0x2e,0xa8,0x9e,0xaa,0xa4,0xa8,0x0a,0xac,0x5a,0x88,0x07,0x88, +0x98,0xe0,0x08,0x00,0x5d,0x0a,0x0c,0x03,0xa6,0x1a,0x13,0xa8,0x06,0x88,0x07, +0xa8,0x9a,0x88,0x78,0x4a,0xaa,0xa8,0x0a,0xe0,0x08,0x00,0x1b,0x33,0x57,0x93, +0xeb,0xe8,0x06,0xb2,0x1e,0x16,0xc8,0xa1,0x4b,0x44,0x1b,0xcc,0xc9,0xa1,0xb7, +0x2c,0xb8,0x0c,0x0d,0xb2,0x1e,0x17,0xd9,0xa1,0xe6,0x1b,0x02,0xc6,0x71,0xff, +0x0c,0x04,0xf2,0x2e,0x24,0x4a,0xff,0xf8,0x0f,0xf2,0xcf,0xf4,0xb6,0x2f,0x34, +0xa8,0xae,0xaa,0xa4,0xa8,0x0a,0xac,0xba,0x88,0x07,0x88,0x98,0xe0,0x08,0x00, +0x0c,0x03,0x52,0xa0,0xff,0xa0,0x55,0xc0,0xa6,0x15,0x15,0x0c,0x0b,0xa8,0x06, +0x88,0x07,0xa8,0xaa,0x88,0x68,0x4a,0xaa,0xa8,0x0a,0xe0,0x08,0x00,0x1b,0x33, +0x57,0x93,0xe9,0xe8,0x06,0xb2,0x1e,0x17,0xc8,0xa1,0x4b,0x44,0x1b,0xcc,0xc9, +0xa1,0xb7,0x2c,0xb2,0x1d,0xf0,0x40,0xd0,0x74,0xd2,0xcd,0xe7,0x56,0xdd,0xd6, +0xd2,0x06,0x24,0x42,0xc6,0x24,0xd0,0xf4,0x04,0x16,0xaf,0x1b,0xad,0x04,0x8d, +0x0c,0xbd,0x0e,0xb8,0xcb,0x88,0x18,0x0b,0x5b,0xb2,0xcb,0xfe,0xe0,0x08,0x00, +0xb1,0xcd,0x29,0xba,0xb5,0xd2,0x0b,0x7f,0xa0,0xe0,0x74,0xe7,0x9d,0x0b,0xd2, +0x0b,0x80,0xa0,0xe8,0x21,0xe0,0xdd,0xc0,0x16,0xfd,0x17,0x0c,0x9f,0x82,0xa0, +0xff,0x82,0x46,0x24,0xf9,0x01,0x06,0x5d,0x00,0xb2,0xa5,0x00,0xb7,0x24,0x18, +0x47,0xab,0x02,0xc6,0x87,0x00,0x50,0x90,0x31,0xb1,0x9f,0x29,0x50,0xa0,0xf4, +0xb0,0xaa,0xa0,0x99,0x0a,0xa5,0x63,0xff,0x1d,0xf0,0xb2,0xa3,0x00,0xb7,0xa4, +0x02,0x06,0x5a,0x00,0x47,0xab,0x02,0x86,0x73,0x00,0x6c,0xfb,0xe8,0x06,0x50, +0xa0,0x04,0x92,0x2e,0x3e,0xc0,0xaa,0x11,0xb0,0x99,0x10,0xa0,0xb9,0x20,0xb2, +0x6e,0x3e,0x1d,0xf0,0xd7,0x9c,0x0d,0xc2,0x2e,0x3e,0x1c,0x09,0x92,0x6e,0x37, +0x70,0xcc,0x10,0xc6,0x40,0xff,0xa9,0x3e,0x42,0x6e,0x3f,0xdd,0x04,0x82,0x2e, +0x3e,0x0c,0x8c,0xc2,0x6e,0x37,0x9d,0x0c,0xc0,0x88,0x20,0xc2,0xa2,0x00,0xc0, +0x88,0x20,0x82,0x6e,0x3e,0x82,0x2e,0x36,0x66,0xb8,0x16,0x66,0x89,0x13,0x0c, +0x07,0xad,0x0e,0x88,0x03,0xf0,0xcd,0x11,0x82,0x28,0x42,0x5c,0x0b,0xe0,0x08, +0x00,0xc6,0x03,0x00,0x0c,0x07,0xad,0x0e,0x88,0x03,0xcd,0x0d,0x82,0x28,0x42, +0x5c,0x0b,0xe0,0x08,0x00,0xe8,0x06,0x92,0x2e,0x3e,0x90,0x90,0x04,0x16,0x99, +0x0a,0xa2,0x2e,0x36,0xa2,0xca,0xd0,0x56,0x0a,0x0a,0xc2,0x2e,0x37,0xc2,0xcc, +0xf0,0x56,0x7c,0x09,0x42,0x5e,0x7a,0x42,0x5e,0x7b,0xad,0x0e,0x88,0x03,0x50, +0xb0,0xf4,0x82,0x28,0x3d,0xc2,0xa0,0x8b,0xe0,0x08,0x00,0x4d,0x0a,0xb8,0x06, +0xa9,0x51,0xa2,0x2b,0x3e,0xb2,0x2b,0x3f,0xa0,0xa3,0x04,0xf0,0xbb,0x11,0xe5, +0x42,0xff,0xb1,0x8a,0x29,0x8c,0x54,0x98,0x0b,0x8c,0x19,0x66,0x05,0x0e,0x58, +0x51,0xa5,0x55,0xff,0xb1,0x86,0x29,0x98,0x0b,0x90,0x57,0x83,0x4d,0x05,0x8c, +0x04,0xcc,0xd9,0xa8,0x06,0x72,0x6a,0xbd,0xe5,0x44,0xff,0xd1,0x80,0x29,0x0c, +0x1c,0xc9,0x0d,0xe8,0x06,0xf2,0x2e,0x40,0x66,0x2f,0x31,0x51,0x54,0x29,0x41, +0x5f,0x29,0x0c,0x03,0xa2,0xaf,0xbf,0x0c,0x0b,0x88,0x05,0x0c,0x0c,0x82,0x28, +0x2c,0xdd,0x04,0xe0,0x08,0x00,0x0c,0x0a,0xbd,0x03,0xe5,0x72,0xff,0x42,0xc4, +0x10,0x1b,0x33,0x66,0x83,0xdf,0xe8,0x06,0x0c,0x39,0x72,0x6e,0x42,0x92,0x6e, +0x40,0x72,0x6e,0xc5,0x1d,0xf0,0x72,0x5e,0x7a,0x4d,0x07,0x86,0xd8,0xff,0xa1, +0xe4,0x28,0xa7,0xa4,0x02,0x06,0x35,0x00,0x47,0xaa,0x02,0xc6,0x37,0x00,0x98, +0x0c,0x99,0x05,0x1d,0xf0,0xa9,0x01,0xb1,0x53,0x29,0xa8,0xcb,0xd2,0x06,0x24, +0xa2,0xca,0xfe,0xa9,0xcb,0xd0,0x90,0x24,0xbc,0x69,0x0b,0xb9,0x16,0x1b,0x2f, +0x48,0x01,0xc6,0x13,0x00,0xc2,0xd4,0xfe,0x56,0x1c,0xb9,0x50,0xb0,0x04,0xe8, +0x06,0xc2,0xad,0xff,0x92,0x2e,0x3e,0xd8,0x3e,0xc0,0x99,0x10,0xa0,0xdd,0xc0, +0x70,0xcb,0x11,0xc0,0x99,0x20,0x92,0x6e,0x3e,0x56,0x2d,0xb7,0x30,0x99,0x10, +0xd0,0xab,0x11,0x86,0x9f,0xff,0x7c,0xfa,0xb1,0x55,0x29,0x4b,0xc1,0xa5,0x5b, +0xfb,0xd8,0x11,0x4d,0x0a,0x9c,0x0d,0xa8,0x06,0xc2,0xa0,0x8b,0x88,0x03,0xb1, +0x28,0x29,0x82,0x28,0x3d,0xb8,0x1b,0xe0,0x08,0x00,0xcd,0x04,0x88,0x07,0x1c, +0x8a,0x88,0xf8,0x0c,0x7b,0xe0,0x08,0x00,0x1d,0xf0,0xa8,0x06,0xa2,0x2a,0x3f, +0xf0,0xaa,0x11,0xa5,0x2a,0xff,0x1d,0xf0,0xb2,0xa4,0x00,0xc2,0xd4,0xfc,0x56, +0x2c,0xb2,0xa0,0xe5,0xc0,0x16,0xae,0x26,0xd0,0xf5,0xc0,0x16,0x4f,0x26,0xe8, +0x06,0x58,0x3e,0x92,0x2e,0x3e,0xd0,0x85,0xc0,0x30,0xa9,0x10,0x56,0x48,0x09, +0x9d,0x0a,0xa2,0x6e,0x3e,0xad,0x0b,0x46,0x84,0xff,0xa1,0x3b,0x29,0xa7,0x24, +0x30,0x47,0x2a,0x47,0xad,0x05,0xa5,0x51,0xff,0x1d,0xf0,0xa1,0xa6,0x28,0xa7, +0x24,0x2d,0x47,0x2a,0x44,0x98,0x06,0x92,0x29,0x45,0x46,0xc8,0xff,0xa1,0xb2, +0x28,0xa7,0x24,0x44,0x47,0xaa,0x02,0xc6,0xb3,0xfe,0xa8,0x06,0xf2,0x6a,0xbd, +0xe5,0x2f,0xff,0x1d,0xf0,0xa2,0xd4,0xf9,0x56,0xfa,0xab,0xad,0x05,0x65,0x4d, +0xff,0x1d,0xf0,0xb2,0xd4,0xf4,0x56,0x2b,0xab,0xc8,0x06,0x52,0x6c,0x45,0x1d, +0xf0,0xd2,0xd4,0xf7,0x56,0x5d,0xaa,0xe8,0x06,0x52,0x6e,0x3f,0x1d,0xf0,0xf2, +0xd4,0xf2,0x56,0x8f,0xa9,0x98,0x06,0x92,0x29,0x40,0x86,0xb5,0xff,0xa2,0xd4, +0xf0,0x56,0xaa,0xa8,0x0c,0x1a,0x1c,0x9b,0x7c,0xfc,0x98,0x06,0x88,0x07,0x52, +0x69,0x36,0x91,0xe7,0x28,0x88,0xf8,0x59,0x09,0xe0,0x08,0x00,0x1d,0xf0,0x90, +0x99,0x04,0xd0,0x99,0x11,0x90,0x9a,0x20,0xad,0x09,0x86,0xd7,0xff,0x50,0xa0, +0x35,0x50,0xf4,0x35,0xb2,0x6e,0x40,0xc1,0xea,0x28,0xb2,0x6e,0x42,0xc8,0x2c, +0x50,0xd0,0xf4,0xf0,0xcd,0x83,0xc2,0x6e,0x41,0x8c,0x7a,0xb2,0x6e,0x43,0x50, +0xd8,0x75,0xd2,0x6e,0x44,0x0c,0x03,0xa2,0xaf,0xbf,0xbd,0x03,0xa5,0x57,0xff, +0x1b,0x33,0x66,0x83,0xf2,0x1d,0xf0,0x88,0x03,0xad,0x0e,0x82,0x28,0x39,0xbd, +0x04,0xe0,0x08,0x00,0xec,0x9a,0x88,0x03,0xa8,0x06,0x82,0x28,0x38,0xbd,0x04, +0xe0,0x08,0x00,0xdc,0xba,0x88,0x03,0x82,0x28,0x45,0xa8,0x06,0xe0,0x08,0x00, +0x47,0x1a,0x0f,0xa8,0x06,0x88,0x03,0xbd,0x04,0x82,0x28,0x3a,0x7c,0xfc,0xe0, +0x08,0x00,0x1d,0xf0,0xe8,0x06,0xb1,0xfa,0x28,0xe0,0xa4,0x11,0xa9,0x61,0xc2, +0xcb,0x10,0xc0,0xc4,0xa0,0xba,0xaa,0xb2,0x2a,0x7f,0x52,0x6a,0x7f,0xb0,0xb5, +0xc0,0xb0,0xb2,0x21,0xb2,0x6c,0x7f,0x92,0x2e,0xc6,0xac,0x09,0x88,0x03,0xad, +0x0e,0x82,0x28,0x38,0xbd,0x04,0xe0,0x08,0x00,0xe8,0x06,0xdc,0x0a,0x88,0x03, +0x82,0x28,0x45,0xad,0x0e,0xe0,0x08,0x00,0xe8,0x06,0x40,0x9a,0xc0,0x56,0x99, +0x11,0xcd,0x05,0x88,0x03,0xbd,0x04,0x82,0x28,0x49,0xad,0x0e,0xe0,0x08,0x00, +0x41,0xaf,0x28,0x96,0x8a,0x99,0xe8,0x06,0x88,0x03,0x82,0x28,0x4a,0xad,0x0e, +0xe0,0x08,0x00,0x88,0x03,0x82,0x28,0x4b,0xa8,0x06,0xe0,0x08,0x00,0xa8,0x06, +0x8b,0xb1,0x88,0x03,0xcb,0xc1,0x82,0x28,0x44,0xd2,0xc1,0x10,0xe0,0x08,0x00, +0xe8,0x06,0xa2,0x6e,0xc5,0x98,0x21,0x16,0x69,0x08,0xb8,0x24,0xa6,0x1b,0x2f, +0x0b,0xab,0xa9,0x24,0x25,0x05,0xff,0xe8,0x06,0xc1,0xcf,0x28,0xd2,0x2e,0x3f, +0xb2,0x2e,0x34,0xb2,0x5c,0x76,0xb2,0x5c,0x86,0xb2,0x5c,0x77,0xb2,0x5c,0x87, +0xd2,0xcd,0x10,0xd2,0x5c,0x78,0xd2,0x5c,0x88,0xb2,0xcb,0x10,0xb2,0x5c,0x79, +0xb2,0x5c,0x89,0x88,0x03,0x82,0x28,0x34,0xad,0x0e,0xe0,0x08,0x00,0xa8,0x06, +0x25,0xa1,0x02,0xe8,0x06,0x92,0x2e,0xc5,0xec,0x69,0xa1,0xad,0x28,0xa8,0xfa, +0xfc,0x3a,0x1c,0x5a,0x88,0x07,0x0c,0x0b,0x88,0xf8,0x0c,0x0c,0xe0,0x08,0x00, +0x88,0x03,0x82,0x28,0x50,0xa8,0x06,0xe0,0x08,0x00,0xa1,0xa6,0x28,0x0c,0x19, +0x99,0xfa,0xc6,0x04,0x00,0x88,0x03,0x82,0x28,0x50,0xad,0x0e,0xe0,0x08,0x00, +0x88,0x03,0x82,0x28,0x4e,0xa8,0x06,0xe0,0x08,0x00,0x98,0x31,0x16,0xb9,0x8d, +0xa8,0x06,0xb2,0xc1,0x10,0x25,0x84,0x02,0xa8,0xc4,0xb8,0x84,0xc8,0x41,0x25, +0x53,0xfe,0xa8,0xd4,0xb8,0x94,0xc8,0x41,0xa5,0x52,0xfe,0xa8,0x06,0xb8,0x41, +0x65,0x57,0x02,0xa8,0x06,0xb8,0x41,0x65,0xac,0x02,0x1d,0xf0,0xe8,0x06,0x59, +0x3e,0xc6,0x65,0xff,0xad,0x04,0xb1,0x90,0x28,0xc2,0xa0,0xef,0xc0,0xcd,0x10, +0xc2,0x46,0x24,0xb8,0xcb,0xe5,0xc5,0xfe,0x4d,0x0a,0x86,0x52,0xff,0xf8,0x61, +0xd2,0x2e,0x27,0x41,0x6b,0x28,0xfa,0xdd,0xd2,0xdd,0xff,0x52,0x6d,0x36,0x06, +0xba,0xff,0x00,0x00,0x36,0x41,0x00,0x32,0x62,0x2f,0x26,0x03,0x4c,0x3c,0x04, +0xb2,0x12,0x75,0x62,0x22,0x36,0xb0,0xb3,0xc0,0x20,0xbb,0xa0,0x47,0x96,0x11, +0x52,0x22,0x37,0x61,0x96,0x28,0x82,0xc5,0xf8,0x56,0x58,0x09,0x51,0x95,0x28, +0x46,0x04,0x00,0x66,0xb6,0x08,0x51,0x95,0x28,0x61,0x93,0x28,0x46,0x01,0x00, +0x51,0x94,0x28,0x61,0x93,0x28,0x52,0x6b,0x47,0xa2,0x12,0x75,0xa0,0xa3,0xc0, +0x20,0xaa,0xa0,0x62,0x6a,0x4b,0x92,0x22,0x3e,0x17,0x69,0x02,0x26,0xb3,0x01, +0x1d,0xf0,0xa2,0x12,0x75,0xe0,0xaa,0x11,0xa0,0xa2,0xc0,0x52,0x6a,0x58,0x92, +0x12,0x75,0xe0,0x99,0x11,0x90,0x92,0xc0,0x52,0x69,0x59,0x82,0x12,0x75,0x0c, +0x0e,0xe0,0x88,0x11,0x80,0x82,0xc0,0xe2,0x68,0x5b,0x42,0x12,0x75,0xe0,0x44, +0x11,0x40,0x42,0xc0,0xe2,0x64,0x5c,0x32,0x12,0x75,0xe0,0x33,0x11,0x30,0x32, +0xc0,0xe2,0x63,0x5c,0xf2,0x12,0x75,0xe0,0xff,0x11,0xf0,0xf2,0xc0,0xe2,0x6f, +0x5d,0xd2,0x12,0x75,0xe0,0xdd,0x11,0xd0,0xd2,0xc0,0x62,0x6d,0x5f,0xc2,0x12, +0x75,0xe0,0xcc,0x11,0xc0,0xc2,0xc0,0x62,0x6c,0x60,0x1d,0xf0,0x66,0xb5,0x08, +0x61,0x73,0x28,0x51,0x73,0x28,0x46,0xdd,0xff,0x61,0x70,0x28,0x51,0x6f,0x28, +0x06,0xdb,0xff,0x00,0x00,0x00,0x36,0x01,0x01,0x41,0x3b,0x28,0x88,0x04,0xad, +0x02,0x82,0x28,0x39,0xbd,0x03,0xe0,0x08,0x00,0x16,0xda,0x1b,0x88,0x04,0xad, +0x02,0x82,0x28,0x48,0xbd,0x03,0xe0,0x08,0x00,0xcc,0x7a,0x92,0x22,0x36,0x92, +0xc9,0xd0,0x56,0x69,0x1a,0xad,0x02,0xbd,0x03,0x0c,0x1c,0xa5,0x46,0x00,0x30, +0xc0,0xf4,0x0c,0x1b,0xd2,0xc1,0x10,0x88,0x04,0x6d,0x0a,0x82,0x28,0x3b,0xad, +0x02,0xe0,0x08,0x00,0xa0,0x90,0xf4,0xe6,0x19,0x02,0x06,0x60,0x00,0x62,0x61, +0x17,0x32,0xc1,0x10,0x30,0x59,0x90,0xe2,0x93,0x00,0x1b,0xde,0x16,0x7d,0x16, +0x42,0x22,0x23,0x40,0x4e,0xa0,0x48,0x04,0xf2,0xc4,0xf6,0x16,0x9f,0x15,0xa8, +0x92,0xa0,0xae,0xa0,0xa8,0x0a,0xf0,0x74,0x11,0x16,0xca,0x14,0xb8,0xe2,0xc2, +0x22,0x10,0xb0,0xb4,0x90,0xc0,0xc4,0x90,0xc2,0x9c,0x00,0xb2,0x9b,0x00,0xc0, +0xbb,0xc0,0xb2,0xcb,0xf8,0xe6,0x1b,0x02,0xc6,0x4b,0x00,0x81,0x3f,0x27,0x88, +0x08,0x88,0x98,0xb2,0x61,0x15,0xe0,0x08,0x00,0x7c,0xc9,0x90,0x6a,0x10,0x97, +0x8a,0x02,0xc6,0x45,0x00,0xa2,0x12,0x7a,0xa7,0xa6,0x02,0x86,0x43,0x00,0xb2, +0x12,0x62,0x67,0xab,0x01,0x6d,0x0b,0xb2,0x22,0x30,0xcd,0x06,0xd8,0x92,0x88, +0x02,0xa2,0x93,0x00,0x88,0x98,0xd0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x81, +0x05,0x28,0x88,0x08,0xa2,0x22,0x30,0x82,0x28,0x17,0xbd,0x06,0xe0,0x08,0x00, +0xa2,0x22,0x23,0xe2,0x93,0x00,0xb2,0x22,0x22,0xa0,0xae,0xa0,0xa8,0x0a,0xb0, +0xaa,0xa0,0xa8,0x0a,0xe0,0x9e,0x11,0x96,0x5a,0x00,0xb2,0x22,0x3e,0x47,0x6b, +0x20,0xa2,0x22,0x30,0xbd,0x06,0xc1,0x78,0x27,0x81,0xf7,0x27,0xc0,0xee,0x11, +0x88,0x08,0xd2,0x22,0x18,0x82,0x28,0x2d,0xea,0xdd,0xe0,0x08,0x00,0x92,0x93, +0x00,0xe0,0x99,0x11,0xa2,0x22,0x2b,0x9a,0xaa,0xa8,0x0a,0x16,0x6a,0x09,0xb2, +0x22,0x3e,0xa2,0x61,0x16,0x87,0x6b,0x2f,0xd2,0x22,0x12,0xc2,0x12,0x77,0x7a, +0xdd,0xd2,0x9d,0x00,0xd7,0xac,0x21,0x81,0xe9,0x27,0x88,0x08,0xa2,0x21,0x17, +0x82,0x28,0x25,0xb2,0x22,0x3c,0xe0,0x08,0x00,0xb2,0x22,0x2b,0x92,0x93,0x00, +0xa2,0x61,0x17,0xb0,0x99,0xa0,0x98,0x09,0x92,0x61,0x16,0xa2,0x21,0x16,0x60, +0xe0,0xf4,0xd2,0x21,0x17,0x81,0xfd,0x27,0xb2,0x22,0x30,0xf2,0x21,0x15,0x98, +0xc2,0xc2,0x22,0x10,0x90,0x94,0xa0,0x7a,0xcc,0xc2,0x9c,0x00,0x98,0x09,0xf9, +0x01,0x88,0x08,0x90,0xcc,0xa0,0x82,0x28,0x16,0xf2,0xc1,0x50,0xe0,0x08,0x00, +0xe2,0x21,0x14,0x66,0x8a,0x0c,0xb2,0x22,0x14,0xba,0xb7,0xa2,0x9b,0x00,0x1b, +0xaa,0xa2,0x5b,0x00,0x82,0x22,0x10,0xd2,0x22,0x11,0x8a,0x87,0xf2,0x98,0x00, +0xda,0xd7,0xea,0xff,0xf2,0x58,0x00,0xc2,0x9d,0x00,0xea,0xcc,0xc2,0x5d,0x00, +0x2b,0x33,0x50,0x93,0xc0,0x56,0x79,0xe8,0x1d,0xf0,0x00,0x00,0x00,0x36,0x21, +0x01,0x82,0x22,0x35,0x56,0xc8,0x0b,0x41,0xc3,0x27,0x88,0x04,0xad,0x02,0x82, +0x28,0x39,0xbd,0x03,0xe0,0x08,0x00,0x16,0xaa,0x0a,0x88,0x04,0xad,0x02,0x82, +0x28,0x48,0xbd,0x03,0xe0,0x08,0x00,0xcc,0x7a,0x92,0x22,0x36,0x92,0xc9,0xd0, +0x56,0x39,0x09,0xad,0x02,0xbd,0x03,0x0c,0x0c,0xa5,0x28,0x00,0x30,0xc0,0xf4, +0x0c,0x0b,0xd2,0xc1,0x10,0x88,0x04,0xa2,0x61,0x18,0x82,0x28,0x3b,0xad,0x02, +0xe0,0x08,0x00,0xa0,0x90,0xf4,0xa6,0x19,0x6f,0x61,0xda,0x26,0x32,0xc1,0x10, +0x30,0xa9,0x90,0xa2,0x61,0x19,0xa2,0x93,0x00,0x26,0x0a,0x55,0x82,0x22,0xc1, +0x92,0x22,0xc2,0x66,0x28,0x04,0x98,0x19,0xa7,0x19,0x47,0x52,0x22,0x24,0xb8, +0xa2,0x50,0x5a,0xa0,0xb0,0xaa,0xa0,0xa8,0x0a,0x58,0x05,0xbc,0x5a,0x0c,0xb8, +0x87,0x95,0x3b,0xc6,0x07,0x00,0x00,0x00,0x00,0x0c,0x0b,0xc8,0xa2,0x88,0x06, +0xa2,0x93,0x00,0x88,0x68,0xc0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0xb8,0xa2, +0xa2,0x93,0x00,0xb0,0xaa,0xa0,0xa8,0x0a,0x88,0x06,0x88,0x98,0xe0,0x08,0x00, +0x92,0x12,0x74,0x0b,0x99,0x97,0x3a,0xd3,0xa2,0x21,0x19,0x2b,0x33,0xa7,0x93, +0x9b,0x1d,0xf0,0xf0,0x75,0x11,0xe0,0xb5,0x11,0xb2,0x61,0x1a,0x88,0x06,0x88, +0x98,0xe0,0x08,0x00,0xcc,0xba,0xa2,0x22,0x13,0xaa,0xa7,0x92,0x9a,0x00,0x1b, +0x99,0x92,0x5a,0x00,0xb8,0xa2,0x88,0x06,0xa2,0x93,0x00,0x88,0x98,0xb0,0xaa, +0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x42,0x12,0x74,0xc2,0x22,0xc1,0xa0,0x44,0xc0, +0x0b,0x44,0x66,0x2c,0x25,0xd2,0x22,0xc2,0x82,0x93,0x00,0x98,0x0d,0x97,0x98, +0x1a,0xb8,0xa2,0x88,0x06,0xa8,0x1d,0x88,0x98,0xb0,0xaa,0xa0,0xa8,0x0a,0xe0, +0x08,0x00,0xc2,0x12,0x74,0xa0,0xcc,0xc0,0x0b,0xcc,0xc0,0x44,0x43,0x16,0xe4, +0xf8,0xd2,0x12,0x7b,0xd7,0x24,0x88,0xb2,0x12,0x62,0xd2,0x21,0x18,0x47,0xab, +0x01,0x4d,0x0b,0x66,0x75,0x08,0xe2,0x22,0x3e,0x37,0x6e,0x02,0xf0,0xdd,0x11, +0x7c,0xca,0xe1,0xa1,0x27,0xd0,0xc4,0x82,0xea,0xcc,0xc0,0xc4,0x31,0xd0,0x4c, +0x93,0xa0,0xa4,0x10,0xa2,0xca,0xfc,0xe6,0x1a,0x02,0x46,0xd5,0xff,0xf2,0x22, +0x10,0x98,0xe2,0xfa,0xf7,0x7a,0x99,0x92,0x99,0x00,0x66,0x75,0x0a,0xc2,0x22, +0x3e,0x37,0x6c,0x04,0xe2,0x22,0x33,0x9a,0x9e,0xe2,0x9f,0x00,0xe0,0x49,0xc0, +0x40,0x4a,0x43,0xe6,0x14,0x02,0x06,0xcb,0xff,0xb2,0x61,0x16,0xe2,0x61,0x15, +0xa2,0x21,0x1a,0x98,0xc2,0x82,0x93,0x00,0xaa,0x99,0x98,0x09,0xa2,0x22,0x2b, +0x66,0x75,0x07,0xc2,0x22,0x3e,0x37,0x6c,0x01,0x98,0xd2,0x92,0x61,0x17,0xc2, +0x12,0x16,0x42,0x61,0x14,0xca,0x88,0xcd,0x04,0xa0,0x88,0xa0,0x88,0x08,0x82, +0x61,0x1b,0xac,0xb8,0xa2,0x21,0x1b,0x81,0x72,0x27,0xc2,0x21,0x17,0x92,0x21, +0x16,0xc0,0xbe,0xa0,0xc2,0x22,0x30,0x99,0x01,0x88,0x08,0xf2,0xc1,0x50,0x82, +0x28,0x16,0x40,0xe0,0xf4,0xe0,0x08,0x00,0xf2,0x22,0x10,0xc2,0x21,0x14,0xfa, +0xf7,0xe2,0x9f,0x00,0xbd,0x0c,0x81,0x48,0x27,0xa2,0x22,0x30,0x88,0x08,0x4a, +0x9e,0x82,0x28,0x19,0x92,0x5f,0x00,0xe0,0x08,0x00,0xb8,0xa2,0x88,0x06,0xa2, +0x93,0x00,0x88,0x98,0xb0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0xc2,0x21,0x14, +0xd2,0xa0,0xff,0xa0,0xdd,0xc0,0xc7,0xbd,0x1e,0xb8,0xa2,0x88,0x06,0xa2,0x93, +0x00,0x88,0x98,0xb0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x7c,0xcd,0xc2,0xa0, +0xff,0xa0,0xcc,0xc0,0xd0,0xcc,0x10,0xc2,0x61,0x14,0xb8,0xa2,0x88,0x02,0xa2, +0x93,0x00,0x88,0x88,0xb0,0xaa,0xa0,0xa8,0x0a,0xb2,0x22,0x30,0xe0,0x08,0x00, +0xc2,0x22,0xc1,0x66,0x2c,0x20,0xd2,0x22,0xc2,0xe2,0x93,0x00,0xf8,0x0d,0xf7, +0x9e,0x15,0xb2,0x22,0x30,0xc2,0x21,0x14,0xe8,0xa2,0x88,0x02,0xa8,0x1d,0x88, +0x88,0xe0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0xb8,0xa2,0xa2,0x93,0x00,0xb0, +0xaa,0xa0,0xa8,0x0a,0x86,0x90,0xff,0x00,0x00,0x36,0x61,0x00,0xbd,0x06,0x0c, +0xa8,0xb0,0xc4,0x11,0xa2,0x12,0x75,0x20,0xd5,0xa0,0xf2,0x2d,0xa9,0xe2,0x2d, +0xb3,0xa0,0xa3,0xc0,0xd2,0x2d,0x9f,0xa0,0xaa,0x11,0xaa,0xa2,0xca,0xaa,0x89, +0x01,0xc2,0xa1,0x7c,0xca,0xaa,0x0c,0x0c,0x25,0x1f,0x03,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0x52,0x22,0x26,0x82,0x12,0x75,0x62,0x22,0x2f,0x80,0xa3, +0xc0,0x80,0x66,0xc0,0x50,0x66,0xa0,0x68,0x06,0x50,0x5a,0xa0,0x58,0x05,0x20, +0xaa,0xa0,0x66,0x14,0x20,0x92,0x2a,0x4f,0x57,0x99,0x08,0xb2,0x2a,0x53,0x60, +0xbb,0xc0,0x16,0x2b,0x14,0x52,0x6a,0x4f,0xc2,0x12,0x75,0xc0,0xc3,0xc0,0x20, +0xcc,0xa0,0x62,0x6c,0x53,0xc6,0x07,0x00,0xd2,0x2a,0x57,0x57,0x9d,0x0a,0xe2, +0x2a,0x5b,0x67,0x9e,0x04,0x22,0x2a,0x4b,0x1d,0xf0,0x52,0x6a,0x57,0xf2,0x12, +0x75,0xf0,0xf3,0xc0,0x20,0xff,0xa0,0x62,0x6f,0x5b,0x71,0xfc,0x26,0x88,0x07, +0xad,0x02,0x82,0x28,0x38,0xbd,0x03,0xe0,0x08,0x00,0xac,0x5a,0x88,0x07,0xad, +0x02,0x82,0x28,0x39,0xb2,0x22,0x2f,0xe0,0x08,0x00,0x16,0xca,0x0b,0xa2,0x22, +0x36,0x3c,0x09,0x97,0x1a,0x0e,0x5a,0x95,0x9a,0x95,0x66,0xba,0x04,0x5d,0x09, +0x86,0x00,0x00,0xf0,0x59,0x11,0x88,0x07,0xad,0x02,0x82,0x28,0x39,0xbd,0x03, +0xe0,0x08,0x00,0xf2,0x12,0x75,0x9c,0x6a,0x9c,0x43,0xa2,0x22,0x36,0x92,0xca, +0xd0,0x56,0xb9,0x07,0x92,0x22,0x37,0xa2,0xc9,0xf0,0x56,0x3a,0x0a,0x6a,0xb6, +0xba,0x66,0xf0,0xf3,0xc0,0xa0,0xff,0x11,0xfa,0xf2,0x66,0x14,0x31,0xbd,0x05, +0xcd,0x06,0x1c,0x2d,0x1c,0x4e,0xa2,0xa1,0x9c,0xaa,0xaf,0xe5,0xfc,0x02,0x92, +0x12,0x75,0x90,0x93,0xc0,0x20,0xa9,0xa0,0xa0,0x99,0x11,0x9a,0x92,0x92,0x29, +0x6d,0x92,0x6a,0x47,0x82,0x12,0x75,0x80,0x83,0xc0,0x20,0x28,0xa0,0x22,0x22, +0x47,0x1d,0xf0,0xbd,0x06,0xcd,0x05,0x1c,0x2d,0x1c,0x4e,0xa2,0xa1,0x7c,0xaa, +0xaf,0xe5,0xf9,0x02,0x92,0x12,0x75,0x90,0x93,0xc0,0x20,0xa9,0xa0,0xa0,0x99, +0x11,0x9a,0x92,0x92,0x29,0x65,0x92,0x6a,0x4b,0x82,0x12,0x75,0x80,0x83,0xc0, +0x20,0x28,0xa0,0x22,0x22,0x4b,0x1d,0xf0,0x66,0xba,0x8d,0xa2,0x22,0x37,0x66, +0x8a,0x87,0x6a,0x66,0x86,0xe0,0xff,0xb2,0x22,0x3e,0xb0,0xb1,0x04,0x16,0x0b, +0xf5,0x88,0x07,0xad,0x02,0x82,0x28,0x38,0xb2,0x22,0x2f,0xe0,0x08,0x00,0x5a, +0x95,0x9a,0x95,0xf0,0x99,0x11,0xa0,0x59,0x83,0x86,0xcd,0xff,0xa2,0xc9,0xf8, +0x56,0x9a,0xf5,0x6a,0x86,0x8a,0x66,0xf0,0x66,0x11,0xc6,0xd3,0xff,0x22,0x2a, +0x47,0x1d,0xf0,0x00,0x00,0x00,0x36,0x01,0x01,0x42,0x61,0x11,0x82,0x12,0x16, +0x32,0x61,0x13,0xad,0x05,0x31,0xb2,0x26,0x51,0xdb,0x25,0xa2,0x61,0x12,0xe6, +0x18,0x02,0x46,0x28,0x00,0x0c,0x07,0x0c,0x06,0x0c,0x0a,0xa2,0x61,0x15,0xad, +0x02,0x0c,0x1b,0xcd,0x06,0x42,0x22,0x23,0x88,0x03,0x7a,0x44,0x82,0x28,0x3c, +0x48,0x04,0xe0,0x08,0x00,0x88,0x03,0xa2,0x61,0x16,0x82,0x28,0x3f,0xad,0x04, +0xe0,0x08,0x00,0x16,0x3a,0x06,0x98,0x92,0x7a,0x99,0x98,0x09,0x16,0xa9,0x05, +0xad,0x02,0x88,0x03,0xb2,0x21,0x16,0xc2,0x21,0x15,0xb0,0xb0,0xf4,0x1b,0xcc, +0x82,0x28,0x48,0xc2,0x61,0x15,0xe0,0x08,0x00,0x9c,0x2a,0xd2,0x22,0x11,0xe2, +0x22,0x33,0xd0,0xd4,0x90,0xd2,0x9d,0x00,0xe7,0xad,0x31,0x0c,0x09,0xc6,0x10, +0x00,0xe2,0x22,0x36,0x3c,0x0f,0xf7,0x9e,0x11,0x82,0x22,0x11,0x92,0x22,0x34, +0x80,0x84,0x90,0x82,0x98,0x00,0x97,0xa8,0x15,0x06,0xf8,0xff,0xa8,0x92,0x88, +0x05,0x7a,0xaa,0x88,0x98,0xa8,0x0a,0xe0,0x08,0x00,0x92,0x22,0x34,0x97,0x2a, +0xcd,0x4b,0x77,0xa2,0x12,0x16,0x1b,0x66,0xa7,0xa6,0x02,0x46,0xda,0xff,0x06, +0x01,0x00,0x0c,0x0b,0xb2,0x61,0x15,0x0c,0x19,0xd2,0x21,0x13,0xe2,0x21,0x15, +0x0c,0x0a,0xe0,0xa9,0x93,0xa9,0x0d,0x66,0x1a,0x12,0x92,0x22,0x35,0x16,0x09, +0x18,0x0c,0x1f,0x0b,0x89,0x82,0x62,0x35,0xf2,0x61,0x14,0x06,0x01,0x00,0x0c, +0x09,0x92,0x61,0x14,0x52,0x12,0x75,0xa2,0x12,0x76,0x57,0xba,0x02,0x06,0x3b, +0x00,0x0c,0x19,0x0c,0x0a,0xa2,0x61,0x17,0x92,0x61,0x10,0xad,0x02,0xbd,0x05, +0xe5,0xf9,0x01,0x16,0xca,0x09,0x42,0x22,0x32,0x88,0x03,0xad,0x02,0x82,0x28, +0x48,0xbd,0x05,0xe0,0x08,0x00,0xac,0xaa,0xad,0x02,0xbd,0x05,0x0c,0x1c,0xe5, +0xd5,0xff,0x9c,0xfa,0xb1,0x9f,0x26,0x91,0x9f,0x26,0xba,0xba,0xb7,0x39,0x02, +0xc6,0x24,0x00,0x0c,0x02,0xd2,0x21,0x11,0x0c,0x0c,0xc9,0x0d,0x1d,0xf0,0x0c, +0x44,0x40,0x4a,0x53,0x80,0x44,0x10,0xad,0x02,0x0c,0x1b,0x88,0x03,0xcd,0x05, +0x82,0x28,0x3b,0xdd,0x01,0xe0,0x08,0x00,0xa6,0x1a,0x4c,0x6d,0x01,0x7d,0x01, +0x70,0x7a,0x90,0x92,0x96,0x00,0x26,0x09,0x58,0xa2,0x22,0x23,0xa0,0xa9,0xa0, +0xa8,0x0a,0xe6,0x7a,0x4d,0xb8,0x92,0xb0,0xb9,0xa0,0xb8,0x0b,0x16,0x3b,0x04, +0x88,0x03,0x82,0x28,0x3e,0xe0,0x08,0x00,0xbc,0x8a,0xb8,0x92,0x81,0x7d,0x25, +0xa2,0x96,0x00,0x88,0x08,0xb0,0xaa,0xa0,0x88,0x98,0xa8,0x0a,0xe0,0x08,0x00, +0x47,0xba,0x1d,0x0c,0x09,0x0c,0x1a,0xa2,0x61,0x17,0x92,0x61,0x10,0xb2,0x12, +0x76,0x1b,0x55,0x50,0x50,0xf4,0x57,0x3b,0x02,0x86,0xd2,0xff,0x92,0x21,0x10, +0x86,0x0b,0x00,0x0c,0x18,0x82,0x61,0x17,0x2b,0x66,0x77,0x96,0x9b,0x86,0xf7, +0xff,0x7c,0xc8,0xb1,0x71,0x26,0x40,0xaa,0x82,0xba,0xaa,0xb2,0x12,0x62,0xa0, +0xa4,0x31,0xa7,0x2b,0x02,0x06,0xd8,0xff,0x4d,0x0b,0x06,0xd8,0xff,0x0c,0x19, +0x0c,0x0c,0xc2,0x61,0x17,0xd2,0x21,0x17,0x0c,0x0a,0x8c,0x3d,0x0c,0x1e,0x90, +0xae,0x93,0xf2,0x21,0x11,0x82,0x21,0x12,0xa9,0x0f,0x49,0x08,0xf8,0x0f,0x66, +0x1f,0x23,0xa2,0x22,0x3e,0x0c,0x19,0x57,0x6a,0x16,0xb2,0x21,0x13,0x0c,0x2c, +0xc2,0x62,0x35,0xb8,0x0b,0x66,0x1b,0x0e,0x92,0x62,0x35,0x92,0x61,0x14,0x46, +0x01,0x00,0x00,0x0c,0x0e,0xe2,0x62,0x35,0xf2,0x21,0x14,0x9c,0xff,0xa2,0x12, +0x17,0xa6,0x1a,0x1a,0x92,0x22,0x24,0x0c,0x06,0x76,0x9a,0x19,0x88,0x09,0x4b, +0x99,0x66,0x68,0x10,0xa2,0x22,0x19,0xc0,0xb6,0x11,0xba,0xaa,0x98,0x2a,0x99, +0x1a,0x22,0x21,0x14,0x1d,0xf0,0x1b,0x66,0x46,0xfd,0xff,0x0c,0x0c,0xc2,0x61, +0x14,0x06,0xa2,0xff,0x00,0x00,0x00,0x36,0x41,0x00,0xed,0x03,0x81,0x1d,0x26, +0x51,0x50,0x26,0x91,0x1b,0x26,0xf0,0x64,0x00,0x98,0x29,0xb2,0xc5,0xe0,0xc0, +0x99,0x11,0x9a,0x88,0x88,0x28,0x92,0xc2,0xf6,0xe0,0xa9,0x11,0x00,0x0a,0x40, +0xa2,0xc5,0xf0,0x80,0x80,0xb1,0x80,0x80,0x34,0xec,0xd8,0xd8,0x0b,0x50,0xc2, +0xb0,0xc2,0xdc,0xff,0xc2,0x2c,0x2c,0xd0,0xdc,0xa0,0x88,0x0d,0xe0,0xcc,0x11, +0x66,0x28,0x44,0x88,0x1b,0x80,0xcc,0xa0,0xb8,0x1c,0xa0,0x89,0xa0,0xbc,0x7b, +0xb9,0x08,0x0c,0x08,0x89,0x1c,0x0c,0x18,0x89,0x0d,0xc6,0x0a,0x00,0xa0,0xc2, +0xa0,0xc2,0xdc,0xff,0xc2,0x2c,0x36,0xd8,0x1b,0x9c,0xdc,0x48,0x0b,0xa0,0x89, +0xa0,0x50,0x32,0xb0,0x32,0xd3,0xff,0x32,0x23,0x2c,0x88,0x08,0xe0,0xc3,0x11, +0x40,0x33,0xa0,0xd0,0xcc,0xa0,0x89,0x1c,0x0c,0x2d,0xd9,0x03,0xf0,0xe6,0x13, +0x20,0x20,0x00,0x0c,0x8a,0x0c,0x0b,0x81,0x20,0x25,0x0c,0x4c,0x88,0x08,0xd2, +0xa2,0x00,0x82,0x28,0x10,0xd0,0xd2,0x20,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x0c,0x93,0x37,0x12,0x23,0x26,0x92,0x49,0x0c,0xb4,0x47,0x12,0x4e, +0x26,0xa2,0x50,0x0c,0xd8,0x87,0x12,0x37,0x1c,0x39,0x97,0x12,0x3c,0x1c,0x4a, +0xa7,0x12,0x2d,0x1c,0x5b,0xb7,0x12,0x32,0x7c,0xf2,0x46,0x00,0x00,0x0c,0x02, +0xf6,0xa2,0x1a,0x81,0x1b,0x26,0xc0,0x32,0x11,0x8a,0x33,0xc0,0x20,0x00,0x22, +0x13,0x85,0x1b,0x22,0xc0,0x20,0x00,0x32,0x13,0x82,0x30,0x22,0xe0,0x1d,0xf0, +0x0c,0x02,0x1d,0xf0,0x0c,0x42,0x06,0xf6,0xff,0x0c,0xa2,0xc6,0xf4,0xff,0x0c, +0x22,0x86,0xf3,0xff,0x0c,0x62,0x46,0xf2,0xff,0x0c,0x82,0x06,0xf1,0xff,0x00, +0x00,0x00,0x36,0x41,0x00,0xe5,0x46,0x00,0x8c,0xfa,0xa6,0x13,0x0d,0x20,0x33, +0xa0,0xa2,0x92,0x00,0x25,0x19,0x00,0x4b,0x22,0x37,0x92,0xf4,0x1d,0xf0,0x00, +0x36,0x41,0x00,0x3d,0x02,0x21,0x05,0x26,0x88,0x02,0x1c,0x4a,0x82,0x28,0x1d, +0x0c,0x4b,0xe0,0x08,0x00,0x0c,0x4b,0x88,0x02,0x2d,0x0a,0x82,0x28,0x1d,0xe0, +0xa3,0x11,0xe0,0x08,0x00,0x39,0x32,0xa9,0x02,0xa9,0x12,0xa9,0x22,0x0c,0x09, +0x99,0x42,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x91,0xf9,0x25,0xb8,0x19, +0xa1,0xf9,0x25,0x9c,0x5b,0x00,0x22,0x11,0xa0,0x22,0x20,0x88,0x0b,0x27,0x98, +0x03,0x0c,0x12,0x1d,0xf0,0xb8,0x7b,0x56,0x1b,0xff,0x46,0x01,0x00,0x00,0x22, +0x11,0xa0,0x22,0x20,0x81,0xef,0x25,0x88,0x08,0x2c,0x4a,0x82,0x28,0x1d,0x0c, +0x4b,0xe0,0x08,0x00,0x69,0x2a,0x49,0x3a,0x59,0x5a,0x79,0x4a,0x32,0x5a,0x10, +0x29,0x0a,0xb1,0xe8,0x25,0x0c,0x0c,0xc9,0x1a,0xc9,0x6a,0xc2,0x5a,0x11,0xc9, +0x7a,0xb8,0x1b,0x0c,0x02,0xcc,0x6b,0xd1,0xe3,0x25,0xa9,0x1d,0x06,0x03,0x00, +0x98,0x7b,0x8c,0x59,0xbd,0x09,0x98,0x79,0x56,0x89,0xff,0xa9,0x7b,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x41,0x00,0x61,0xdc,0x25,0x00,0x22,0x11,0x68,0x16,0x41, +0xdb,0x25,0x9c,0x06,0x40,0x22,0x20,0x58,0x06,0x27,0x95,0x04,0x0c,0x02,0x86, +0x01,0x00,0x68,0x76,0x56,0x06,0xff,0x0c,0x22,0x26,0x22,0x01,0x39,0x46,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x61,0xd1,0x25,0x00,0x22,0x11,0x68,0x16,0x41,0xd0, +0x25,0x9c,0x06,0x40,0x22,0x20,0x58,0x06,0x27,0x95,0x04,0x0c,0x02,0x86,0x01, +0x00,0x68,0x76,0x56,0x06,0xff,0x0c,0x22,0x26,0x22,0x01,0x39,0x26,0x1d,0xf0, +0x00,0x36,0x41,0x00,0x21,0xc6,0x25,0x28,0x12,0x0c,0x03,0xbc,0x62,0x88,0x32, +0xec,0xd8,0xa2,0x92,0x11,0x92,0x92,0x10,0x1b,0xba,0xb2,0x52,0x11,0xa7,0x99, +0x20,0x40,0x64,0x00,0x0c,0x4a,0xbd,0x02,0x65,0x14,0x00,0x0c,0x4a,0x8b,0xb2, +0xe5,0x13,0x00,0xa8,0x22,0xb8,0x42,0xa5,0x13,0x00,0x40,0xe6,0x13,0x20,0x20, +0x00,0x32,0x52,0x11,0x28,0x72,0x56,0x72,0xfc,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0x4d,0x02,0x21,0xb3,0x25,0x81,0xb4,0x25,0x28,0x12,0x00,0x54,0x11,0x9c, +0x12,0x80,0x55,0x20,0x98,0x02,0x57,0x99,0x05,0x0c,0x0a,0xa9,0x62,0x1d,0xf0, +0x28,0x72,0x56,0xf2,0xfe,0x1d,0xf0,0x00,0x36,0x41,0x00,0x80,0xa2,0x23,0x25, +0xfd,0xff,0x8c,0x4a,0x0c,0x02,0x39,0x1a,0x1d,0xf0,0x0c,0x22,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0x80,0xa2,0x23,0x0c,0x24,0x65,0xfb,0xff,0x3d,0x0a, +0xac,0x6a,0x88,0x5a,0xec,0x28,0x98,0x1a,0x9c,0xe9,0x20,0x64,0x00,0x0c,0x4a, +0xbd,0x03,0x65,0x0c,0x00,0x0c,0x4a,0x8b,0xb3,0xe5,0x0b,0x00,0xa8,0x23,0xb8, +0x43,0x65,0x0b,0x00,0x20,0xe6,0x13,0x20,0x20,0x00,0x0c,0x04,0x2d,0x04,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x71,0x95,0x25,0x0c,0x05,0x68,0x27,0x1c,0x03,0x48, +0x06,0x49,0x16,0x49,0x26,0x76,0xa3,0x07,0x88,0x26,0x4b,0x98,0x99,0x26,0x59, +0x08,0xa8,0x22,0x48,0x37,0x9c,0x1a,0x1c,0x0b,0xc8,0x04,0xc9,0x14,0xc9,0x24, +0x76,0xab,0x07,0xd8,0x24,0x4b,0xed,0xe9,0x24,0x59,0x0d,0x1d,0xf0,0x36,0x41, +0x00,0x68,0x12,0x58,0x22,0x28,0x32,0x67,0x35,0x0c,0x60,0x35,0xc0,0x3b,0x23, +0x30,0x23,0xb3,0x20,0x22,0x21,0x1d,0xf0,0x50,0x86,0xc0,0x3b,0x38,0x80,0x38, +0xb3,0x30,0x32,0x21,0x30,0x22,0xc0,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00, +0xa1,0x7c,0x25,0x88,0x3a,0xa8,0x2a,0x20,0xa8,0x93,0x65,0xfc,0xff,0x2d,0x0a, +0x1d,0xf0,0x36,0x41,0x00,0x68,0x02,0x38,0x12,0x48,0x32,0x58,0x03,0x60,0x44, +0xa0,0x4b,0x33,0x39,0x12,0x47,0x33,0x01,0x69,0x12,0x2d,0x05,0x1d,0xf0,0x00, +0x36,0x41,0x00,0xa1,0x70,0x25,0x88,0x3a,0xa8,0x2a,0x20,0xa8,0x93,0x65,0xfd, +0xff,0x2d,0x0a,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x0a,0x65,0xfb,0xff,0xb1,0x6a, +0x25,0x20,0xc2,0x21,0xb8,0x2b,0xaa,0x8c,0x98,0x3b,0xa8,0x2b,0x97,0x38,0x03, +0x0c,0x32,0x1d,0xf0,0x0c,0x02,0xa6,0x1c,0x1e,0x76,0xac,0x1b,0xc8,0x0b,0x4b, +0xda,0xf8,0x03,0x4b,0x33,0xd9,0x2b,0xf9,0x0a,0xe8,0x3b,0xad,0x0d,0xc0,0xee, +0xa0,0xe7,0x3d,0x03,0xad,0x0c,0xc9,0x2b,0x3d,0xf0,0x1d,0xf0,0x00,0x36,0x41, +0x00,0x51,0x5a,0x25,0x58,0x35,0x9c,0x05,0xa8,0x25,0x68,0x05,0x4b,0x8a,0x89, +0x25,0x29,0x0a,0x98,0x35,0x60,0x99,0xa0,0x97,0xb8,0x01,0x1d,0xf0,0x69,0x25, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x61,0x51,0x25,0x48,0x02,0x51,0x51,0x25, +0x8d,0x04,0x1b,0x44,0x37,0xa8,0x1b,0xa8,0x36,0x25,0xf5,0xff,0xa0,0xb0,0xf4, +0x57,0x9b,0x09,0x49,0x02,0xa0,0x20,0x31,0x80,0x22,0x23,0x1d,0xf0,0x16,0x0b, +0xfe,0x7c,0xe2,0x1d,0xf0,0x49,0x02,0x7c,0xf2,0x1d,0xf0,0x36,0x41,0x00,0x0c, +0x08,0x31,0x43,0x25,0x7c,0xf2,0x29,0x93,0x89,0x73,0x89,0x83,0x89,0xb3,0x89, +0xa3,0x1d,0xf0,0x00,0x00,0x36,0x61,0x00,0x31,0x3e,0x25,0x0c,0x05,0x88,0x73, +0x59,0x01,0x8c,0x28,0x7c,0xe2,0x1d,0xf0,0xa8,0x33,0x65,0xec,0xff,0x4d,0x0a, +0x16,0xea,0x08,0x0c,0x26,0xb8,0x83,0x0c,0x37,0x16,0x4b,0x09,0xc2,0xcb,0xfe, +0x16,0x5c,0x0a,0x66,0x3b,0x01,0x28,0xa3,0xb8,0x01,0x47,0xab,0x69,0xdd,0x02, +0x0b,0x22,0xa6,0x1d,0x30,0xa8,0x33,0x1b,0xeb,0xe9,0x01,0xa5,0xed,0xff,0xb8, +0xc3,0x9c,0x0b,0xf8,0x5b,0x66,0x1f,0x0c,0x88,0x6b,0x98,0x4b,0x1b,0xc8,0xc9, +0x6b,0x90,0x88,0xa0,0xa9,0x08,0xe8,0x2b,0xd8,0x6b,0xe0,0xe2,0x21,0xe7,0x9d, +0x32,0xf8,0xd3,0x59,0x6b,0x1b,0xff,0xf9,0xd3,0x59,0x83,0xad,0x01,0xbd,0x04, +0x25,0xf4,0xff,0x2d,0x0a,0x96,0x3a,0x03,0xa9,0x93,0x80,0xaa,0x23,0x65,0xda, +0xff,0x88,0x01,0xa9,0xc3,0x1b,0x98,0x99,0x01,0x47,0xa8,0x1a,0xa8,0x33,0xa5, +0xe8,0xff,0xa0,0x22,0x21,0x29,0xa3,0xb8,0x01,0xdd,0x02,0x47,0x2b,0x97,0x8c, +0x22,0x79,0x83,0x29,0xa3,0x0c,0x02,0x1d,0xf0,0x69,0x83,0x7c,0xf2,0x1d,0xf0, +0x7c,0xea,0xa7,0x92,0xf2,0x0c,0x1b,0xb9,0x73,0x1d,0xf0,0xad,0x01,0xbd,0x04, +0x65,0xef,0xff,0x2d,0x0a,0xd6,0xfa,0x01,0x7c,0xec,0xc7,0x9a,0xdb,0x0c,0x1d, +0xd9,0x73,0x1d,0xf0,0xa8,0x33,0xa5,0xe4,0xff,0xb8,0x01,0xa0,0x22,0x21,0x1b, +0xbb,0xb9,0x01,0x29,0xa3,0x79,0x83,0xc6,0xd2,0xff,0xa9,0x93,0x69,0x83,0x80, +0xaa,0x23,0xa5,0xd3,0xff,0xc8,0x01,0xa9,0xc3,0x1b,0xdc,0xd9,0x01,0x47,0xac, +0xaf,0xa8,0x33,0xe5,0xe1,0xff,0xa0,0x22,0x21,0xb8,0x01,0x86,0xf5,0xff,0x36, +0x41,0x00,0xa8,0x02,0xa0,0xa2,0x21,0xe5,0xbc,0xff,0x31,0xfa,0x24,0xb8,0x22, +0xa9,0x23,0x8c,0x8b,0xa8,0x02,0xa0,0xa2,0x21,0xe5,0xbb,0xff,0xa9,0x33,0x1d, +0xf0,0x36,0x41,0x00,0x21,0xf4,0x24,0x28,0x42,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0x0c,0x13,0x41,0xf0,0x24,0x0c,0x02,0x48,0x44,0x42,0xc4,0xfe,0x40,0x23, +0x83,0x1d,0xf0,0x36,0x41,0x00,0x30,0x64,0x00,0x65,0xfe,0xff,0x27,0x1a,0x2a, +0x41,0xea,0x24,0x0c,0x1a,0x51,0x76,0x24,0x9d,0x02,0x88,0x15,0x20,0x9a,0x93, +0x99,0x44,0xad,0x05,0x89,0x54,0xa5,0xd3,0xff,0x8c,0xf2,0xb8,0x25,0x8c,0x1b, +0x65,0xe7,0xff,0xc8,0x54,0xcc,0x4c,0xd8,0x44,0x1b,0xdd,0xd9,0x44,0x30,0xe6, +0x13,0x20,0x20,0x00,0x1d,0xf0,0x00,0x36,0x41,0x00,0x2d,0x05,0x61,0x69,0x24, +0x51,0xdb,0x24,0xac,0x73,0x0c,0x07,0x26,0x13,0x2c,0x26,0x43,0x4a,0x26,0x73, +0x71,0x82,0xc3,0xeb,0x16,0x68,0x09,0x1c,0x69,0x97,0x93,0x19,0x98,0x45,0x66, +0x19,0x14,0xa8,0x55,0x0b,0xaa,0xa9,0x55,0xcc,0xba,0x1b,0xb9,0xb9,0x45,0x1d, +0xf0,0x29,0x05,0xad,0x06,0x65,0xf4,0xff,0x1d,0xf0,0x1c,0x7d,0x40,0xc0,0x74, +0xd7,0x9c,0xf5,0xad,0x02,0x65,0xf7,0xff,0x56,0xd2,0xfe,0x79,0x65,0x1c,0xda, +0x88,0x05,0x1c,0x8b,0x88,0xf8,0x0c,0x0c,0xe0,0x08,0x00,0x1d,0xf0,0x16,0xa4, +0x09,0x0b,0x94,0x16,0xb9,0x09,0x26,0x24,0x6a,0xa2,0xc4,0xfd,0x16,0x9a,0x09, +0xb2,0xc4,0xfc,0x16,0xfb,0x09,0x26,0x54,0x6d,0xc2,0xc4,0xfa,0x16,0x9c,0x07, +0x66,0x74,0xb9,0x20,0xd0,0xf4,0xd9,0x16,0x1d,0xf0,0x25,0xf2,0xff,0x16,0xca, +0xfa,0xe8,0x26,0x16,0x7e,0xfa,0x25,0xde,0xff,0xf8,0xd5,0x66,0x3f,0x9f,0xa8, +0xe5,0x79,0xd5,0x8c,0x1a,0xe0,0x0a,0x00,0x1c,0x5a,0x88,0x05,0x0c,0x0b,0x88, +0xf8,0x0c,0x0c,0xe0,0x08,0x00,0x1d,0xf0,0x65,0xef,0xff,0x16,0x1a,0xf8,0x0c, +0x0a,0xa5,0xb9,0xff,0x98,0x65,0x56,0x79,0xf7,0x1c,0xda,0x1c,0x8b,0x88,0x05, +0x0c,0x1c,0x88,0xf8,0xc9,0x65,0xe0,0x08,0x00,0x1d,0xf0,0xa8,0x02,0xa0,0xa0, +0xf4,0xa6,0x2a,0x02,0xc6,0xd6,0xff,0xe5,0xc9,0xff,0xa9,0x02,0x1d,0xf0,0xa8, +0x02,0xa0,0xa0,0xf4,0xa6,0x2a,0x02,0x46,0xd2,0xff,0xe5,0xcb,0xff,0xa9,0x02, +0x1d,0xf0,0x29,0xe5,0x1d,0xf0,0xe5,0xea,0xff,0x86,0x00,0x00,0xa5,0xe9,0xff, +0xa9,0x02,0x1d,0xf0,0xa8,0x02,0x0c,0x1b,0xa0,0xa0,0xf4,0x65,0xbb,0xff,0x1d, +0xf0,0xa8,0x02,0xbd,0x07,0xa0,0xa0,0xf4,0xa5,0xba,0xff,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x4d,0x02,0x20,0x64,0x00,0x51,0x94,0x24,0x0c,0x13,0x49,0x35,0x39, +0x25,0x20,0xe6,0x13,0x20,0x20,0x00,0x0c,0x02,0x1d,0xf0,0x00,0x36,0x41,0x00, +0x0c,0x0b,0x21,0x8f,0x24,0x31,0x8e,0x24,0xc0,0x20,0x00,0xb2,0x63,0x9b,0xf8, +0xa2,0xc0,0x20,0x00,0x0c,0xcd,0xf2,0x63,0x82,0xe8,0x92,0x0c,0x4c,0xe0,0xcd, +0x83,0xc0,0x20,0x00,0xc2,0x63,0x80,0xc0,0x20,0x00,0xb2,0x63,0x8c,0xa8,0x12, +0xc0,0x20,0x00,0xa2,0x63,0x8e,0x98,0x22,0xc0,0x20,0x00,0x92,0x63,0x8f,0x88, +0x32,0xc0,0x20,0x00,0x82,0x63,0x85,0x78,0x42,0xc0,0x20,0x00,0x72,0x63,0x86, +0x68,0x52,0xc0,0x20,0x00,0x62,0x63,0x87,0x58,0x62,0xc0,0x20,0x00,0x52,0x63, +0x88,0x48,0x72,0xc0,0x20,0x00,0x42,0x63,0x89,0x28,0x82,0xc0,0x20,0x00,0x22, +0x63,0x8a,0x1d,0xf0,0x36,0x81,0x00,0x0c,0x04,0x31,0x71,0x24,0x21,0x72,0x24, +0xa1,0xe7,0x23,0xc0,0x20,0x00,0x42,0x6a,0x9c,0xc0,0x20,0x00,0x92,0x22,0x8d, +0xc0,0x20,0x00,0x99,0x01,0x49,0x11,0x49,0x21,0x1c,0x7a,0xbd,0x04,0x0c,0x4c, +0x88,0x43,0x0c,0x0d,0x82,0x28,0x10,0x8b,0xe1,0xe0,0x08,0x00,0x61,0x68,0x24, +0xc8,0x06,0xc0,0x20,0x00,0xb8,0x01,0xc7,0x8b,0x02,0x46,0x46,0x00,0xc0,0x20, +0x00,0xd8,0x01,0xe8,0x21,0xd0,0xd5,0x04,0x16,0x9d,0x08,0x56,0xbe,0x10,0xf8, +0x03,0x98,0x11,0x16,0x0f,0x12,0x0c,0x6a,0x0c,0x0b,0x0c,0x4c,0x88,0x43,0x0c, +0x1d,0x82,0x28,0x10,0x0c,0x1e,0xe0,0x08,0x00,0x88,0x43,0x88,0x98,0xa8,0x03, +0xe0,0x08,0x00,0x9d,0x0a,0x92,0x61,0x01,0xa6,0x49,0x02,0x46,0x3f,0x00,0x92, +0xa0,0x04,0x76,0xa9,0x05,0xc0,0x20,0x00,0x42,0x62,0x84,0xc6,0x0f,0x00,0x49, +0x31,0x1c,0x7a,0x0c,0x0b,0x0c,0x4c,0x88,0x43,0x0c,0x5d,0x82,0x28,0x10,0xcb, +0xe1,0xe0,0x08,0x00,0xd8,0x31,0xd0,0xd0,0x74,0xc0,0x20,0x00,0xd2,0x62,0x84, +0xc8,0x31,0xc0,0xc8,0x74,0xc0,0x20,0x00,0xc2,0x62,0x84,0xb8,0x31,0xb0,0xb0, +0x75,0xc0,0x20,0x00,0xb2,0x62,0x84,0x98,0x31,0x90,0x98,0x75,0xc0,0x20,0x00, +0x92,0x62,0x84,0xc0,0x20,0x00,0xe2,0x22,0x94,0xc0,0x20,0x00,0xe9,0x01,0xc0, +0x20,0x00,0xf8,0x01,0x27,0x6f,0x4f,0xc0,0x20,0x00,0x52,0x22,0x9e,0xbc,0x15, +0xc0,0x20,0x00,0x82,0x22,0x84,0x80,0x80,0x74,0xc0,0x20,0x00,0xa8,0x13,0x89, +0x41,0x9c,0xaa,0x98,0x23,0x66,0x29,0x0a,0xc0,0x20,0x00,0xa8,0x41,0xe5,0x0b, +0xfe,0xc6,0x02,0x00,0xc0,0x20,0x00,0x88,0x43,0x88,0x68,0xb8,0x41,0xe0,0x08, +0x00,0x0b,0x55,0x56,0xc5,0xfc,0x88,0x43,0x82,0x28,0x18,0xe0,0x08,0x00,0x0c, +0x7b,0x88,0x43,0xcd,0x0a,0x88,0xf8,0x0c,0x7a,0xe0,0x08,0x00,0xc0,0x20,0x00, +0x98,0x01,0x67,0x69,0x0a,0xc0,0x20,0x00,0xb2,0x22,0x95,0xc0,0x20,0x00,0xb9, +0x01,0xc0,0x20,0x00,0xe2,0x22,0x8d,0xc0,0x20,0x00,0xe9,0x01,0xc0,0x20,0x00, +0xd8,0x01,0xc8,0x06,0xd7,0x0c,0x02,0x46,0xb9,0xff,0x1d,0xf0,0x49,0x11,0x1c, +0x7a,0x0c,0x0b,0x0c,0x4c,0x88,0x43,0x0c,0x2d,0x82,0x28,0x10,0x4b,0xe1,0xe0, +0x08,0x00,0x98,0x11,0xe0,0x99,0x11,0xc6,0xbe,0xff,0xc6,0xbe,0xff,0xb8,0x21, +0xc8,0x03,0x56,0x9b,0xf0,0xbc,0x4c,0x0c,0x45,0x9c,0xf9,0x9c,0xd5,0x88,0x43, +0x88,0x78,0xa8,0x03,0xe0,0x08,0x00,0xa0,0xb0,0x74,0xc0,0x20,0x00,0xb2,0x62, +0x84,0x98,0x11,0x0b,0x55,0x0b,0x99,0x99,0x11,0x86,0xf7,0xff,0x00,0x00,0xb8, +0x23,0x66,0x1b,0x0d,0xa8,0x33,0x1b,0xcb,0xc9,0x23,0xe5,0xff,0xfd,0x46,0x00, +0x00,0x0c,0x45,0x76,0xa5,0x05,0xc0,0x20,0x00,0x42,0x62,0x84,0xc6,0xc0,0xff, +0x00,0x00,0x00,0x36,0x41,0x00,0x61,0xfe,0x23,0x16,0x53,0x06,0x26,0x13,0x71, +0x1c,0x07,0x82,0xc3,0xfe,0x16,0xb8,0x0d,0x92,0xc3,0xfd,0x16,0x89,0x0b,0xb2, +0xc3,0xfc,0x16,0x5b,0x0a,0xd2,0xc3,0xf9,0x16,0x3d,0x07,0x1c,0x8e,0xe7,0x93, +0x50,0x40,0xf0,0x74,0x66,0x7f,0x4a,0xb2,0xa0,0x80,0x0c,0x09,0x70,0x64,0x00, +0x88,0x46,0xa8,0x06,0x88,0x68,0x99,0x26,0xe0,0x08,0x00,0x88,0x46,0xa8,0x06, +0x88,0x68,0x2c,0xfb,0xe0,0x08,0x00,0x88,0x46,0xa8,0x06,0x88,0x68,0x50,0xb8, +0x74,0xe0,0x08,0x00,0x88,0x46,0xa8,0x06,0x88,0x68,0x50,0xb0,0x74,0xe0,0x08, +0x00,0x70,0xe6,0x13,0x20,0x20,0x00,0x1d,0xf0,0x59,0x46,0x98,0x22,0xa8,0x12, +0xa9,0x06,0x99,0x16,0x65,0xd4,0xff,0x1d,0xf0,0x40,0xb0,0x74,0x66,0x7b,0xf7, +0x8c,0xd5,0xbd,0x05,0x88,0x46,0xa1,0x6b,0x23,0x82,0x28,0x20,0x2c,0x8c,0xe0, +0x08,0x00,0xa5,0xd2,0xff,0x1d,0xf0,0xa8,0x06,0x16,0xca,0xfd,0x88,0x46,0x88, +0x98,0xe0,0x08,0x00,0xb6,0x4a,0xd2,0x0c,0x6a,0x0c,0x0b,0x0c,0x4c,0x50,0x64, +0x00,0x88,0x46,0x0c,0x1d,0x82,0x28,0x10,0x0c,0x0e,0xe0,0x08,0x00,0x50,0xe6, +0x13,0x20,0x20,0x00,0x1d,0xf0,0x40,0x90,0x74,0x56,0xf9,0xfa,0xad,0x05,0x65, +0xcd,0xff,0x1d,0xf0,0xf0,0x64,0x00,0xa0,0xe4,0x03,0x70,0xaa,0x20,0x70,0xaa, +0x30,0xa0,0xe4,0x13,0xf0,0xe6,0x13,0x10,0x20,0x00,0x70,0xe3,0x13,0x65,0xcd, +0xff,0x1d,0xf0,0xe5,0xcc,0xff,0xc1,0xc3,0x23,0xd2,0xa0,0x64,0x41,0xc4,0x23, +0x0c,0x43,0x0c,0x1b,0x2d,0x0b,0x00,0x50,0x00,0x70,0xe3,0x13,0xf0,0x64,0x00, +0xe0,0xe4,0x03,0x70,0xee,0x20,0xe0,0xe4,0x13,0xf0,0xe6,0x13,0x10,0x20,0x00, +0xc0,0x20,0x00,0xd2,0x6c,0x8c,0xc0,0x20,0x00,0xb2,0x6c,0x9b,0x1d,0xf0,0x36, +0x41,0x00,0x31,0xb9,0x23,0x0c,0x04,0x22,0xa1,0x00,0x42,0x63,0x01,0x31,0xb7, +0x23,0x76,0xa2,0x07,0xc0,0x20,0x00,0x42,0x63,0x80,0x4b,0x33,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0x51,0xb3,0x23,0x81,0xa8,0x23,0x0c,0x04,0x0c,0x0b,0xc1, +0xae,0x23,0x0c,0xc3,0x72,0x2c,0x01,0x76,0xa3,0x49,0xc0,0x20,0x00,0x62,0x12, +0x00,0xb2,0x65,0x80,0x07,0xe4,0x04,0x9d,0x06,0x46,0x00,0x00,0x0c,0x09,0xc0, +0x20,0x00,0x92,0x58,0x82,0xc0,0x20,0x00,0xb2,0x58,0x83,0xc0,0x20,0x00,0x72, +0x58,0x84,0x60,0xd2,0x41,0x0b,0xdd,0xc0,0x20,0x00,0xd2,0x58,0x85,0xa2,0x12, +0x01,0x0b,0xaa,0xc0,0x20,0x00,0xa2,0x58,0x86,0x4b,0x22,0x1b,0x44,0x52,0xc5, +0x10,0x60,0xd2,0xf4,0xda,0x77,0x82,0xc8,0x10,0x79,0x1c,0x1d,0xf0,0x00,0x00, +0x36,0x41,0x00,0x0c,0x03,0x7c,0xfd,0x00,0x12,0x40,0x0c,0x1c,0x00,0xcc,0xa1, +0xd0,0xcc,0x30,0x8d,0x03,0xd1,0x09,0x23,0xc0,0x20,0x00,0xf2,0x2d,0x81,0xf0, +0xfc,0x10,0xc0,0x20,0x00,0xf2,0x6d,0x81,0xc0,0x20,0x00,0xe2,0x2d,0x80,0xe0, +0xcc,0x10,0xc0,0x20,0x00,0xc2,0x6d,0x80,0xb1,0x8d,0x23,0xc0,0x92,0x11,0xba, +0xb9,0xc0,0x20,0x00,0x39,0x0b,0xa1,0x7f,0x23,0xaa,0x99,0xc0,0x20,0x00,0x32, +0x59,0x83,0x20,0xa0,0x04,0xa0,0x85,0x83,0xc0,0x20,0x00,0x82,0x59,0x82,0x07, +0xe2,0x1a,0x0b,0xc5,0xad,0x02,0x0c,0x0b,0xa5,0x01,0x00,0xf1,0x82,0x23,0xe0, +0xe2,0x11,0xd2,0xcf,0x60,0xd0,0xd2,0xa0,0xfa,0xee,0x39,0x0e,0x39,0x0d,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x51,0x7d,0x23,0xc0,0x72,0x11,0x5a,0x57, +0xc0,0x20,0x00,0x81,0x77,0x23,0x52,0x15,0x00,0x8a,0x77,0xc0,0x20,0x00,0x1b, +0x25,0x1b,0x64,0x42,0x27,0x80,0x0b,0x22,0x8c,0xa2,0x0b,0x66,0x96,0x66,0x00, +0x39,0x04,0x4b,0x44,0xc6,0xfb,0xff,0xc0,0x20,0x00,0x42,0x67,0x80,0x1d,0xf0, +0x36,0x41,0x00,0x0c,0x0f,0x71,0x6f,0x23,0xb1,0x70,0x23,0x62,0xc7,0xd0,0x52, +0xc7,0xa0,0xe2,0xcb,0xea,0xac,0x43,0x26,0x13,0x68,0x7c,0xf3,0xf6,0xa3,0x1b, +0xa1,0x6b,0x23,0xc0,0xc3,0x11,0xa0,0xa3,0xa0,0x98,0x0a,0xb1,0x69,0x23,0xe6, +0x49,0x0a,0xca,0xbb,0x1b,0xd9,0xd9,0x0a,0xb0,0xb9,0xa0,0x49,0x0b,0x1d,0xf0, +0xad,0x0e,0x3d,0x0f,0x82,0x1a,0x32,0x87,0x12,0x09,0xa7,0x3b,0x06,0x2b,0x33, +0x4b,0xaa,0xc6,0xfb,0xff,0xe6,0xa3,0xc7,0x81,0x56,0x23,0x60,0xc3,0xa0,0x0c, +0x8b,0x50,0xd3,0xa0,0x70,0xa3,0xa0,0xf9,0x0a,0x29,0x0d,0xad,0x03,0xb9,0x0c, +0xe0,0xd3,0xa0,0x0c,0x0b,0x0c,0x8c,0xe8,0x38,0x98,0xdd,0xd2,0x1d,0x00,0x90, +0xee,0x20,0xe9,0x38,0xe5,0xec,0xff,0x06,0xe6,0xff,0xa2,0xcb,0xec,0x0c,0x13, +0x82,0x1a,0x32,0x87,0x12,0x09,0xa7,0x3b,0x06,0x2b,0x33,0x4b,0xaa,0xc6,0xfb, +0xff,0xe6,0xa3,0x80,0x81,0x44,0x23,0x60,0xc3,0xa0,0x0c,0x8b,0x50,0xd3,0xa0, +0x70,0xa3,0xa0,0xf9,0x0a,0x29,0x0d,0xad,0x03,0xb9,0x0c,0xe0,0xd3,0xa0,0x0c, +0x0b,0x0c,0x8c,0xe8,0x28,0x98,0xdd,0xd2,0x1d,0x00,0x90,0xee,0x20,0xe9,0x28, +0xa5,0xe8,0xff,0x46,0xd4,0xff,0x00,0x00,0x00,0x36,0x81,0x00,0xad,0x03,0x0c, +0x06,0x59,0x21,0x49,0x11,0x9d,0x02,0x21,0xc0,0x22,0x99,0x01,0x7d,0x02,0x82, +0x17,0x32,0x87,0x1a,0x09,0xe6,0xa6,0x06,0x2b,0x66,0x4b,0x77,0xc6,0xfb,0xff, +0x51,0x37,0x23,0xa9,0x41,0xb1,0x33,0x23,0x41,0x36,0x23,0xb2,0xcb,0xa0,0x42, +0xc4,0xf0,0xa6,0xa6,0x02,0x06,0x21,0x00,0xa9,0x41,0xe0,0x36,0x11,0xb0,0xe6, +0xa0,0xd8,0x01,0xa9,0x0e,0x9c,0x1d,0x0c,0x0f,0x81,0x2b,0x23,0x98,0x11,0xa2, +0xc5,0x60,0xa0,0xa6,0xa0,0x99,0x0a,0x8a,0x83,0xf9,0x08,0xad,0x06,0x0c,0x0b, +0x0c,0x8c,0x98,0x34,0x2a,0xd3,0xe8,0xdd,0xd2,0x1d,0x00,0xe0,0x99,0x20,0x99, +0x34,0xe5,0xe0,0xff,0x5a,0xb3,0xb9,0x31,0xb8,0x0b,0x0c,0x03,0xa6,0x1b,0x41, +0xc0,0x86,0x11,0x61,0x20,0x23,0x8a,0x66,0xa8,0x06,0xac,0xda,0x50,0x64,0x00, +0x88,0x04,0x88,0x88,0xe0,0x08,0x00,0x92,0x17,0x3e,0x0c,0x02,0xa6,0x19,0x12, +0x88,0x04,0xa8,0x06,0x88,0x68,0x0c,0x0b,0xe0,0x08,0x00,0x92,0x17,0x3e,0x1b, +0x22,0x97,0x22,0xec,0x50,0xe6,0x13,0x20,0x20,0x00,0xb8,0x31,0xb8,0x0b,0x4b, +0x66,0x1b,0x33,0xb7,0x23,0xc5,0xa8,0x41,0x0c,0x16,0x51,0x0f,0x23,0x21,0x92, +0x22,0xb2,0xc5,0x30,0x2b,0x72,0xc2,0x17,0x32,0xc7,0x1a,0x09,0xe6,0xa6,0x6e, +0x4b,0x77,0x2b,0x66,0xc6,0xfb,0xff,0xe6,0xa6,0x64,0xe0,0x36,0x11,0xb0,0xe6, +0xa0,0xd8,0x01,0xa9,0x0e,0x9c,0x2d,0xf8,0x21,0x98,0x11,0x81,0x01,0x23,0xa1, +0x04,0x23,0x80,0x86,0xa0,0xa0,0xa6,0xa0,0x99,0x0a,0xf9,0x08,0xad,0x06,0x0c, +0x0b,0x0c,0x8c,0xe8,0x24,0x2a,0xd3,0xf8,0xdd,0xd2,0x1d,0x00,0xf0,0xee,0x20, +0xe9,0x24,0xa5,0xd6,0xff,0x5a,0x23,0xb8,0x02,0x0c,0x03,0xa6,0x1b,0x24,0xc0, +0x86,0x11,0x61,0xf7,0x22,0x8a,0x66,0xa8,0x06,0x9c,0x0a,0x50,0x64,0x00,0x88, +0x04,0x88,0x88,0xe0,0x08,0x00,0x50,0xe6,0x13,0x20,0x20,0x00,0xb8,0x02,0x4b, +0x66,0x1b,0x33,0xb7,0x23,0xe2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c, +0x06,0x0c,0x19,0x51,0x6f,0x22,0x81,0x58,0x22,0x72,0xc5,0x16,0x32,0x15,0x32, +0x37,0x12,0x09,0x57,0x37,0x06,0x2b,0x66,0x4b,0x55,0xc6,0xfb,0xff,0xe6,0xa6, +0x23,0x00,0x16,0x40,0x00,0x49,0xa1,0xc0,0x20,0x00,0xb2,0x28,0x80,0xb0,0xb4, +0x20,0xc0,0x20,0x00,0xb2,0x68,0x80,0xc0,0x20,0x00,0xa2,0x28,0x81,0xa0,0x44, +0x20,0xc0,0x20,0x00,0x42,0x68,0x81,0x51,0xde,0x22,0x0c,0x16,0xc2,0x15,0x32, +0xc7,0x12,0x09,0x57,0x37,0x06,0x2b,0x66,0x4b,0x55,0xc6,0xfb,0xff,0xe6,0xa6, +0x23,0x00,0x16,0x40,0x00,0xd9,0xa1,0xc0,0x20,0x00,0xf2,0x28,0x80,0xf0,0xfd, +0x20,0xc0,0x20,0x00,0xf2,0x68,0x80,0xc0,0x20,0x00,0xe2,0x28,0x81,0xe0,0xdd, +0x20,0xc0,0x20,0x00,0xd2,0x68,0x81,0x1d,0xf0,0x00,0x00,0x00,0x36,0x81,0x00, +0x91,0x38,0x22,0xc0,0x20,0x00,0x92,0x29,0x87,0x90,0x90,0x34,0xa6,0xa9,0x02, +0x46,0x5e,0x00,0xe1,0xc6,0x22,0x81,0xca,0x22,0xb1,0xc8,0x22,0xe0,0xa9,0x11, +0x41,0xb2,0x22,0x51,0xc0,0x22,0xc0,0xf9,0x11,0x62,0xc5,0xa0,0x4a,0x4f,0x72, +0xc5,0xd0,0x70,0x79,0xa0,0x49,0x51,0x60,0x69,0xa0,0x41,0x8e,0x21,0x5a,0x5a, +0x69,0x21,0x79,0x61,0x61,0xb4,0x22,0xf0,0x79,0x11,0xba,0xaa,0xa9,0x11,0x8a, +0x77,0x79,0x31,0x6a,0x6f,0x71,0xbc,0x22,0x69,0x41,0xea,0xff,0xf9,0x71,0x61, +0x9c,0x21,0xc0,0x20,0x00,0x38,0x41,0x32,0x23,0x80,0xc0,0x20,0x00,0x98,0x71, +0x28,0x51,0x98,0x09,0x22,0x12,0x82,0x16,0xd9,0x0c,0x99,0x01,0x86,0x00,0x00, +0x77,0x1b,0x1e,0x8d,0x02,0x0b,0x22,0xe6,0x18,0x02,0x86,0x30,0x00,0xd8,0x03, +0x98,0x05,0x4b,0x33,0x16,0x79,0x06,0x40,0xbd,0x10,0x47,0x0d,0x41,0x67,0x9b, +0xe0,0x06,0x06,0x00,0x0c,0x7a,0xb8,0x21,0x81,0x9a,0x22,0xc1,0xa9,0x22,0x88, +0x08,0xc0,0xcd,0x10,0x88,0xf8,0xb8,0x0b,0xe0,0x08,0x00,0xc6,0xf1,0xff,0xa8, +0x01,0xb8,0x31,0x81,0x94,0x22,0xc8,0x61,0x88,0x08,0xc8,0x0c,0x92,0x9b,0x00, +0x00,0x1c,0x40,0x1b,0x99,0x88,0x68,0x92,0x5b,0x00,0x00,0xbd,0xa1,0xe0,0x08, +0x00,0x06,0xe9,0xff,0x98,0x01,0xb8,0x61,0x81,0x8b,0x22,0xa8,0x71,0x88,0x08, +0xa8,0x1a,0xb8,0x0b,0xa0,0xa9,0x83,0x00,0x1b,0x40,0x88,0x68,0x00,0xbd,0xa1, +0xe0,0x08,0x00,0x06,0xe1,0xff,0xa8,0x01,0xb8,0x31,0x81,0x83,0x22,0xc8,0x61, +0x88,0x08,0xc8,0x0c,0x92,0x9b,0x00,0x00,0x1c,0x40,0x1b,0x99,0x88,0x68,0x92, +0x5b,0x00,0x00,0xbd,0xa1,0xe0,0x08,0x00,0xa8,0x11,0x98,0x0a,0x1b,0x99,0x99, +0x0a,0xe6,0x89,0x02,0x86,0xd5,0xff,0x0c,0x0c,0xa8,0x11,0x0c,0x09,0xb8,0x21, +0x81,0x77,0x22,0xb8,0x0b,0x88,0x08,0x99,0x0a,0x88,0xf8,0x0c,0x7a,0xe0,0x08, +0x00,0xc6,0xce,0xff,0x4b,0x33,0x9d,0x02,0x0b,0x22,0xe6,0x19,0xf6,0xc0,0x20, +0x00,0xb8,0x41,0x32,0x6b,0x80,0xc0,0x20,0x00,0x8b,0x55,0x98,0x21,0x88,0x11, +0xf8,0x61,0xe8,0x71,0xa8,0x31,0xc2,0x2b,0x80,0xd8,0x51,0xb2,0xcb,0x20,0xb9, +0x41,0xd2,0xcd,0x20,0x4b,0xaa,0xe2,0xce,0x20,0x8b,0xff,0x8b,0x88,0x8b,0x99, +0x99,0x21,0x89,0x11,0xf9,0x61,0xe9,0x71,0xa9,0x31,0xa1,0x72,0x22,0xd9,0x51, +0xb7,0x2a,0x02,0xc6,0xb3,0xff,0x1d,0xf0,0x00,0x00,0x00,0x36,0x81,0x00,0x91, +0xd3,0x21,0xc0,0x20,0x00,0x92,0x29,0x86,0x90,0x90,0x34,0xa6,0xa9,0x02,0xc6, +0x4f,0x00,0xf0,0xb9,0x11,0xe0,0x69,0x11,0xc1,0x68,0x22,0x31,0x5a,0x22,0x71, +0x5d,0x22,0x82,0xc3,0x30,0xa2,0xc7,0x60,0xd2,0xcc,0x40,0xd0,0xd9,0x90,0xa0, +0xa9,0xa0,0x7a,0x76,0xca,0xbb,0x80,0x89,0xa0,0x89,0x21,0xc1,0x47,0x22,0x3a, +0x66,0xb9,0x51,0xa9,0x11,0xd9,0x01,0xa1,0x55,0x22,0xd1,0x4d,0x22,0xc0,0xb9, +0x11,0x32,0xc3,0x60,0x30,0x39,0xa0,0xca,0xcb,0xc9,0x41,0xda,0xdb,0xd9,0x31, +0xaa,0xbb,0xb9,0x61,0x0c,0x0b,0xc0,0x20,0x00,0x28,0x31,0x22,0x22,0x80,0xc0, +0x20,0x00,0x58,0x41,0xf8,0x51,0x52,0x15,0x82,0xe2,0x9f,0x00,0x5a,0xee,0xe2, +0x5f,0x00,0xe6,0x15,0x02,0x06,0x22,0x00,0x98,0x07,0x48,0x06,0xa8,0x61,0x1b, +0x84,0x89,0x06,0xa0,0x44,0xa0,0x48,0x04,0x97,0x28,0x01,0xb9,0x06,0x8c,0xc4, +0x81,0x37,0x22,0x88,0x08,0x88,0x98,0xad,0x04,0xe0,0x08,0x00,0x0c,0x0b,0x98, +0x03,0x9c,0x09,0xb9,0x02,0x98,0x03,0x4b,0x22,0x0b,0xa9,0xa9,0x03,0x0b,0x55, +0xe6,0x15,0xc8,0x86,0x13,0x00,0x8c,0xf4,0x81,0x2e,0x22,0x88,0x08,0x88,0x98, +0xad,0x04,0xe0,0x08,0x00,0x0c,0x0b,0x46,0x00,0x00,0x0c,0x0a,0xac,0x5a,0x81, +0x28,0x22,0x88,0x08,0x88,0x78,0xad,0x04,0xe0,0x08,0x00,0xc8,0x11,0xc8,0x0c, +0x98,0x21,0x00,0x0c,0x40,0xa0,0xa0,0xb1,0xa9,0x02,0x98,0x09,0x0c,0x0b,0x8c, +0x09,0xb9,0x02,0x4b,0x22,0x46,0xee,0xff,0xe8,0x01,0xd2,0x9e,0x00,0xb9,0x02, +0x98,0x07,0x1b,0xdd,0xd2,0x5e,0x00,0x86,0xe8,0xff,0xc0,0x20,0x00,0xf8,0x31, +0x22,0x6f,0x80,0xc0,0x20,0x00,0x8b,0x33,0x8b,0x77,0x8b,0x66,0xd8,0x01,0xc8, +0x51,0xa8,0x61,0x98,0x41,0xe8,0x11,0x88,0x21,0x8b,0xee,0x8b,0x88,0x92,0xc9, +0x20,0xa2,0xca,0x20,0x4b,0xcc,0x4b,0xdd,0xd9,0x01,0xc9,0x51,0xa9,0x61,0x99, +0x41,0x89,0x21,0xe9,0x11,0x82,0x2f,0x80,0xe1,0x1c,0x22,0xf2,0xcf,0x20,0xf9, +0x31,0xf7,0x2e,0x02,0x86,0xc3,0xff,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x09, +0xa1,0x78,0x21,0xc0,0x20,0x00,0x81,0x17,0x22,0x88,0x08,0x92,0x6a,0x9c,0xe0, +0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x09,0xa1,0x72,0x21,0xc0,0x20,0x00, +0x81,0x11,0x22,0x88,0x18,0x92,0x6a,0x9c,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41, +0x00,0x0c,0xcb,0x0c,0xba,0x0c,0x17,0xe1,0xf9,0x21,0x61,0x85,0x21,0xbc,0x13, +0x26,0x13,0x79,0x82,0xc3,0xfc,0x16,0x48,0x09,0x92,0xc3,0xfb,0x16,0xf9,0x0c, +0x1c,0x3a,0xa7,0x93,0x66,0x40,0xb0,0x74,0x66,0x8b,0x60,0x50,0xc1,0x64,0x56, +0xac,0x05,0x50,0x98,0x74,0xf6,0xa9,0x54,0xe1,0x01,0x22,0x50,0xd0,0x74,0xe0, +0xe9,0xa0,0xd9,0x0e,0x1d,0xf0,0x59,0x0e,0x25,0x8c,0xff,0xad,0x06,0xe5,0x8d, +0xff,0x0c,0x0c,0x0c,0x4f,0xb1,0xef,0x21,0xa1,0xef,0x21,0xe2,0xcb,0x30,0xd2, +0xca,0x10,0x9d,0x0a,0xd2,0xcd,0x10,0xc9,0x0b,0xa2,0xca,0x10,0x4b,0xbb,0x76, +0xaf,0x03,0xc9,0x09,0x4b,0x99,0x0c,0x4f,0x9d,0x0a,0xe7,0x9b,0xe7,0x41,0xc5, +0x21,0x0c,0xc3,0x2d,0x07,0x00,0x50,0x00,0x0c,0xb3,0x41,0xc1,0x21,0x2d,0x07, +0x00,0x50,0x00,0x1d,0xf0,0x40,0x80,0x74,0x66,0x88,0xf7,0x8c,0xd5,0xbd,0x05, +0x88,0x0e,0xad,0x06,0x82,0x28,0x20,0xc2,0xa0,0x94,0xe0,0x08,0x00,0x25,0x86, +0xff,0xad,0x06,0xe5,0x87,0xff,0x1d,0xf0,0x91,0xe4,0x21,0x90,0xc4,0x10,0x97, +0x84,0x02,0x86,0x28,0x00,0xe2,0xdc,0xff,0x16,0xce,0x0b,0xf2,0xa2,0x00,0xf7, +0x1c,0x75,0x82,0xdc,0xfd,0x16,0xc8,0x0b,0x92,0xdc,0xfc,0x16,0x69,0x09,0xb2, +0xa5,0x00,0xb7,0x9c,0xb2,0x16,0xf5,0xfa,0xc0,0x64,0x00,0x4d,0x05,0x3d,0x0a, +0x2d,0x07,0x00,0x50,0x00,0xc0,0xe6,0x13,0x20,0x20,0x00,0x1d,0xf0,0xf1,0x32, +0x21,0x58,0x3e,0xc0,0x20,0x00,0x52,0x6f,0x92,0xd8,0x2e,0xc0,0x20,0x00,0xd2, +0x6f,0x93,0x0c,0x05,0xad,0x05,0x0c,0x0b,0x0c,0x8c,0x25,0x90,0xff,0x2b,0x55, +0xa6,0xa5,0xf1,0x91,0x2d,0x21,0xc8,0xc6,0xc0,0x20,0x00,0xc2,0x69,0x80,0xb1, +0xc9,0x21,0xf0,0x64,0x00,0xa0,0xe4,0x03,0xb0,0xaa,0x20,0xa0,0xe4,0x13,0xf0, +0xe6,0x13,0x10,0x20,0x00,0x88,0xc6,0xc0,0x20,0x00,0x82,0x69,0x81,0x1d,0xf0, +0xad,0x07,0x40,0x60,0x74,0x50,0xe0,0x31,0xe6,0x1e,0x01,0x0c,0x0a,0x50,0xd0, +0xf4,0xbd,0x06,0x2c,0x0c,0xe0,0xcc,0xc0,0xa5,0x9b,0xff,0xad,0x06,0x25,0xb0, +0xff,0x1d,0xf0,0x40,0xa0,0x74,0x0c,0x0b,0xcd,0x05,0xe5,0x8d,0xff,0x1d,0xf0, +0xd0,0x64,0x00,0x4d,0x05,0x3d,0x0b,0x2d,0x07,0x00,0x50,0x00,0xd0,0xe6,0x13, +0x20,0x20,0x00,0x1d,0xf0,0x40,0xa0,0x74,0xbd,0x07,0xcd,0x05,0xe5,0x8b,0xff, +0x1d,0xf0,0x40,0xa0,0x74,0xe5,0xac,0xff,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0x62,0x12,0x75,0x42,0x12,0x76,0x67,0x23,0x0f,0x37,0x24,0x0c,0x42,0x22,0xc3, +0x60,0x23,0xc0,0x40,0x22,0xa0,0x28,0x02,0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x36, +0x41,0x00,0x62,0x12,0x75,0x42,0x12,0x76,0x67,0x23,0x0f,0x37,0x24,0x0c,0x42, +0x22,0xc4,0x60,0x23,0xc0,0x40,0x22,0xa0,0x28,0x02,0x1d,0xf0,0x0c,0x02,0x1d, +0xf0,0x36,0xe1,0x00,0x42,0x61,0x10,0xad,0x02,0x81,0x46,0x21,0x30,0xc0,0xf4, +0x88,0x08,0x0c,0x0b,0x82,0x28,0x3b,0xdd,0x01,0xe0,0x08,0x00,0xa0,0x90,0xf4, +0xa6,0x19,0x5c,0x71,0x6a,0x20,0x5d,0x01,0x50,0x49,0x90,0xb2,0x95,0x00,0x26, +0x0b,0x49,0xa8,0xa2,0xa0,0xab,0xa0,0xa8,0x0a,0x0c,0xbd,0xbc,0xda,0xc2,0x22, +0x24,0xc0,0xcb,0xa0,0xc8,0x0c,0xd7,0x9c,0x33,0xd2,0x21,0x10,0x6d,0x0d,0x66, +0x0d,0x0e,0x88,0x07,0x88,0x98,0xe0,0x08,0x00,0x62,0x12,0x74,0xa0,0x66,0xc0, +0x0b,0x66,0xa6,0x16,0x19,0x0c,0x03,0x0c,0x0b,0xc8,0xa2,0x88,0x07,0xa2,0x95, +0x00,0x88,0x68,0xc0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x1b,0x33,0x37,0x96, +0xe7,0x2b,0x55,0x47,0x95,0xaa,0x1d,0xf0,0x00,0x36,0x81,0x00,0xc2,0x12,0x17, +0x0c,0x03,0xe6,0x1c,0x02,0xc6,0xb2,0x00,0x0c,0xbb,0x0c,0x05,0x0c,0x06,0x0c, +0x07,0x42,0x22,0x24,0xd2,0x22,0xc1,0x3a,0x44,0x48,0x04,0x66,0x2d,0x0a,0x82, +0x22,0xc2,0x88,0x18,0x50,0x88,0xc0,0x16,0xc8,0x29,0xa6,0xa4,0x02,0x86,0xa5, +0x00,0x98,0xa2,0x9a,0x93,0x98,0x09,0xe0,0xa4,0x11,0x16,0xa9,0x28,0xa9,0x11, +0xb0,0xf4,0xc0,0x98,0xc2,0xd2,0x22,0x33,0x90,0x94,0xa0,0x98,0x09,0xd9,0x01, +0x66,0x74,0x0f,0xe2,0x22,0x3e,0x37,0x6e,0x09,0x98,0xd2,0x47,0xee,0x04,0xf0, +0xed,0x11,0xe9,0x01,0x99,0x21,0x16,0x1f,0x26,0x81,0x0d,0x21,0xad,0x02,0x88, +0x08,0x0c,0x0b,0x82,0x28,0x3c,0xcd,0x05,0xe0,0x08,0x00,0xb8,0x11,0x92,0x22, +0x22,0xba,0x99,0x98,0x09,0xa9,0x41,0x96,0x59,0x00,0xc2,0x22,0x3e,0x47,0x6c, +0x1a,0xa8,0x21,0xb8,0x01,0xc1,0x09,0x21,0xd2,0x22,0x19,0x81,0x02,0x21,0x7a, +0xdd,0x88,0x08,0xc8,0x0c,0x82,0x28,0x2d,0xc8,0x3c,0xe0,0x08,0x00,0xd2,0x22, +0x40,0xac,0xed,0xa8,0x21,0xb8,0x01,0xc1,0x01,0x21,0xd2,0x22,0xc0,0x81,0xfa, +0x20,0x7a,0xdd,0x88,0x08,0xc8,0x0c,0x82,0x28,0x2d,0xc8,0x3c,0xe0,0x08,0x00, +0x66,0x74,0x11,0xd2,0x22,0xc1,0x66,0x2d,0x0b,0xad,0x02,0xc2,0x22,0xc2,0xbd, +0x05,0xc8,0x1c,0xa5,0x5a,0xfd,0xa8,0x21,0xb8,0x01,0xd2,0x12,0x3a,0xe2,0x12, +0x3b,0x81,0xee,0x20,0xc2,0x22,0x1c,0x88,0x08,0x6a,0xcc,0x82,0x28,0x2f,0xc2, +0x1c,0x00,0xe0,0x08,0x00,0x98,0x41,0x92,0xc9,0xec,0xf6,0x29,0x11,0x81,0xe7, +0x20,0xa2,0x22,0x17,0x88,0x08,0xb8,0x21,0x82,0x28,0x21,0xc8,0x01,0xe0,0x08, +0x00,0x81,0xe2,0x20,0x88,0x08,0xad,0x02,0x82,0x28,0x48,0xb8,0x41,0xe0,0x08, +0x00,0xcc,0x7a,0x92,0x22,0x36,0x92,0xc9,0xd0,0x56,0xf9,0x0c,0x92,0x22,0x3f, +0xb8,0xe2,0xf0,0xc4,0x11,0xc9,0x51,0x88,0xe2,0xc2,0x22,0x12,0xf0,0x99,0x11, +0xb0,0xb4,0x90,0xb2,0x9b,0x00,0xb9,0x31,0x66,0x74,0x0c,0xd2,0x22,0x3e,0x37, +0x6d,0x06,0xf2,0x22,0x33,0xba,0xef,0xe9,0x31,0x48,0x21,0xb8,0x31,0xe8,0x51, +0xd2,0x22,0x10,0xea,0x88,0xca,0xae,0xea,0xdd,0xd2,0x9d,0x00,0xea,0xcc,0xd0, +0xbb,0xc0,0xb2,0x5c,0x00,0x82,0x98,0x00,0xc2,0x9a,0x00,0x90,0x88,0xc0,0xc7, +0xb8,0x16,0xc8,0x51,0x0c,0x0e,0xd2,0x22,0x14,0xe2,0x5a,0x00,0xda,0xcc,0xb2, +0x9c,0x00,0x1b,0xbb,0xb2,0x5c,0x00,0xc2,0x9a,0x00,0xb8,0x51,0x81,0xe1,0x20, +0xa2,0x22,0x10,0x88,0x08,0xba,0xaa,0xb2,0x22,0x30,0xa2,0x9a,0x00,0x88,0x78, +0x40,0xaa,0xa0,0xe0,0x08,0x00,0xad,0x04,0xb8,0x31,0xd8,0x01,0x81,0xd9,0x20, +0xcd,0x0d,0x88,0x08,0xd0,0xbb,0xc0,0x88,0x78,0x40,0xbb,0xa0,0xe0,0x08,0x00, +0xa2,0x22,0x30,0xf8,0x01,0xc2,0x22,0x12,0xd8,0x51,0x81,0xd2,0x20,0xb2,0x22, +0x10,0x88,0x08,0xda,0xbb,0xda,0xcc,0x88,0x78,0xd8,0x31,0xe2,0x9c,0x00,0xf0, +0xdd,0xc0,0xe0,0xdd,0xc0,0xd2,0x5b,0x00,0xb2,0x9b,0x00,0xc2,0x9c,0x00,0x40, +0xbb,0xa0,0xe0,0x08,0x00,0x0c,0xbb,0x06,0x32,0x00,0xa2,0x12,0x16,0xb2,0x22, +0x2e,0xaa,0xa5,0xb0,0xaa,0xa0,0xa8,0x0a,0x48,0x21,0x9c,0x5a,0xbd,0x04,0x81, +0xc2,0x20,0xc2,0x22,0x30,0x88,0x08,0xd2,0x11,0x00,0x88,0xe8,0xed,0x01,0xe0, +0x08,0x00,0x42,0x22,0x30,0x98,0x41,0xb8,0x01,0x66,0x99,0x0e,0xc1,0xf1,0x20, +0xad,0x04,0xc8,0x0c,0xe5,0x87,0xf7,0x49,0x21,0x86,0x10,0x00,0x0c,0xbe,0xe7, +0x99,0x0e,0xc1,0xed,0x20,0xad,0x04,0xc8,0x0c,0xa5,0x86,0xf7,0x49,0x21,0x86, +0x0b,0x00,0x66,0xa9,0x0e,0xc1,0xea,0x20,0xad,0x04,0xc8,0x0c,0xa5,0x85,0xf7, +0x49,0x21,0x06,0x07,0x00,0x0c,0xde,0xe7,0x99,0x0e,0xc1,0xe6,0x20,0xad,0x04, +0xc8,0x0c,0x65,0x84,0xf7,0x49,0x21,0x06,0x02,0x00,0xad,0x04,0x49,0x21,0x1c, +0x0c,0x65,0x83,0xf7,0xc8,0x01,0x88,0x02,0x48,0x21,0xa8,0xa2,0xbd,0x04,0x3a, +0xaa,0x88,0x88,0xa8,0x0a,0xe0,0x08,0x00,0xb2,0x22,0xc1,0xd2,0x22,0xc2,0x66, +0x2b,0x18,0xc8,0x0d,0x57,0x9c,0x13,0xbd,0x04,0xc8,0x01,0xe8,0xa2,0x88,0x02, +0xa8,0x1d,0x88,0x88,0xe0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x81,0x7a,0x20, +0xb8,0x41,0x88,0x08,0xad,0x02,0x82,0x28,0x3a,0xc8,0x01,0xe0,0x08,0x00,0x0c, +0xbb,0xc2,0x12,0x17,0x2b,0x66,0x72,0xc7,0x10,0x4b,0x33,0x1b,0x55,0xc7,0xa5, +0x02,0xc6,0x4e,0xff,0x1d,0xf0,0x36,0x61,0x00,0x51,0x70,0x20,0x88,0x05,0x82, +0x28,0x51,0xad,0x02,0xe0,0x08,0x00,0xc2,0x12,0x75,0x0c,0xe9,0xc0,0x99,0xc0, +0xa6,0x19,0x4d,0x0c,0x04,0x0c,0x03,0x62,0xa1,0x7c,0x72,0xa1,0x9c,0x7a,0x72, +0x6a,0x62,0x88,0x05,0xca,0xb4,0x82,0x28,0x39,0xad,0x02,0xe0,0x08,0x00,0x1c, +0x09,0x4c,0x0b,0xa0,0xb9,0x93,0xb9,0x01,0xad,0x07,0xe5,0x5b,0x01,0xad,0x06, +0xb8,0x01,0xa5,0x5b,0x01,0x62,0xc6,0x40,0x72,0xc7,0x40,0x1b,0x44,0xb1,0x8d, +0x20,0xc2,0x12,0x75,0xd2,0x22,0x28,0x0c,0xea,0x3a,0xdd,0x4b,0x33,0xc0,0xaa, +0xc0,0xb9,0x0d,0xa7,0x24,0xbf,0xa2,0x12,0x16,0x71,0x75,0x20,0xe6,0x1a,0x02, +0xc6,0x2f,0x00,0x3c,0x06,0x0c,0x04,0x0c,0x03,0xb2,0x22,0x23,0x3a,0xbb,0xb8, +0x0b,0xf6,0x6b,0x3b,0xad,0x02,0x88,0x05,0x0c,0x1b,0x82,0x28,0x3c,0xcd,0x04, +0xe0,0x08,0x00,0x88,0x05,0xbd,0x0a,0x82,0x28,0x48,0xad,0x02,0xe0,0x08,0x00, +0xac,0x8a,0x92,0x12,0x72,0xa2,0x12,0x54,0xb2,0x22,0x29,0x97,0xba,0x10,0xb0, +0xba,0xa0,0x1b,0xca,0xc2,0x52,0x54,0xc2,0x22,0x2b,0xb8,0x0b,0x3a,0xcc,0xb9, +0x0c,0xa2,0x12,0x16,0x4b,0x33,0x1b,0x44,0xa7,0x24,0xb2,0x46,0x1a,0x00,0x88, +0x05,0xa2,0x22,0x23,0x82,0x28,0x3f,0x3a,0xaa,0xa8,0x0a,0xe0,0x08,0x00,0x16, +0x0a,0xfe,0xa2,0x22,0x36,0x92,0x12,0x72,0x67,0x9a,0x1c,0xa2,0x12,0x54,0xb2, +0x22,0x29,0x97,0xba,0xce,0x1b,0xca,0xb0,0xba,0xa0,0xc2,0x52,0x54,0xc2,0x22, +0x2b,0xb8,0x0b,0x3a,0xcc,0xb9,0x0c,0x86,0xee,0xff,0x66,0xba,0xb7,0xd2,0x22, +0x37,0x66,0x8d,0xb1,0xe2,0x12,0x73,0xc2,0x12,0x5a,0xe7,0xbc,0xa8,0xa2,0x22, +0x2c,0x92,0x22,0x2e,0x1b,0xbc,0x88,0x07,0xb2,0x52,0x5a,0x7c,0xfb,0x88,0xc8, +0x3a,0x99,0xa0,0xac,0xa0,0xa8,0x0a,0xa9,0x09,0xe0,0x08,0x00,0x06,0xe2,0xff, +0xa2,0x12,0x17,0x0c,0x03,0xe6,0x1a,0x02,0xc6,0x3e,0x00,0x0c,0x04,0xc2,0x22, +0x24,0x3a,0xcc,0xc8,0x0c,0xa6,0x9c,0x02,0x86,0x38,0x00,0xad,0x02,0x88,0x05, +0x0c,0x0b,0x82,0x28,0x3c,0xcd,0x04,0xe0,0x08,0x00,0x6d,0x0a,0x88,0x05,0xad, +0x02,0x82,0x28,0x48,0xbd,0x06,0xe0,0x08,0x00,0xcc,0xba,0x92,0x22,0x24,0x3a, +0x99,0x98,0x09,0x92,0xc9,0xf9,0x56,0x49,0x0b,0xb2,0x12,0x72,0xa2,0x12,0x54, +0xe2,0x22,0x2b,0xb7,0xba,0x16,0xc2,0x22,0x29,0x1b,0xda,0xd2,0x52,0x54,0xc0, +0xca,0xa0,0xd2,0x12,0x16,0xc8,0x0c,0xda,0xd4,0xe0,0xdd,0xa0,0xc9,0x0d,0xe2, +0x22,0x24,0x3a,0xee,0xe8,0x0e,0xe2,0xce,0xf9,0x56,0x4e,0x08,0x88,0x05,0xbd, +0x06,0x82,0x28,0x48,0xad,0x02,0xe0,0x08,0x00,0x56,0x5a,0x07,0xa2,0x22,0x36, +0x92,0x22,0x37,0x66,0x8a,0x34,0x66,0x89,0x05,0xa2,0x22,0x3e,0x37,0xea,0x02, +0x66,0xb9,0x60,0xb2,0x22,0x2c,0x92,0x12,0x16,0x88,0x07,0xa2,0x12,0x5a,0x88, +0xc8,0x1b,0xca,0x9a,0x94,0xb0,0xaa,0xa0,0xc2,0x52,0x5a,0xb2,0x22,0x2e,0xa8, +0x0a,0xb0,0x99,0xa0,0xa9,0x09,0x7c,0xfb,0xe0,0x08,0x00,0xc6,0x0d,0x00,0x66, +0xba,0x34,0xd2,0x22,0x37,0x66,0x8d,0x2e,0x92,0x22,0x3e,0x37,0x69,0x02,0x47, +0x69,0x25,0xb2,0x22,0x2c,0x92,0x12,0x16,0x88,0x07,0xa2,0x12,0x5a,0x88,0xc8, +0x1b,0xca,0x9a,0x94,0xb0,0xaa,0xa0,0xc2,0x52,0x5a,0xb2,0x22,0x2e,0xa8,0x0a, +0xb0,0x99,0xa0,0xa9,0x09,0x0c,0x1b,0xe0,0x08,0x00,0xa2,0x12,0x17,0x4b,0x33, +0x1b,0x44,0xa7,0xa4,0x02,0x46,0xc1,0xff,0x1d,0xf0,0x00,0x00,0x36,0x61,0x00, +0x82,0x22,0x3e,0x39,0x11,0x27,0x68,0x06,0xad,0x02,0x7c,0xfb,0x25,0xdb,0xfd, +0x0c,0x05,0x0c,0x06,0xb2,0xa0,0x0a,0x76,0xab,0x0f,0xc2,0x22,0xbf,0xd2,0x22, +0x46,0x5a,0xcc,0x5a,0xdd,0x69,0x0d,0x69,0x0c,0x4b,0x55,0x0c,0x05,0x31,0xd5, +0x1f,0x0c,0x4d,0x88,0x11,0x78,0x12,0xc0,0x88,0x11,0x89,0x01,0x8a,0x77,0x76, +0xad,0x0f,0xe2,0x22,0xc4,0xf2,0x22,0xc3,0x5a,0xee,0x5a,0xff,0x69,0x0f,0x69, +0x0e,0x4b,0x55,0xf2,0x12,0x16,0x78,0x07,0xe6,0x1f,0x02,0x06,0x34,0x00,0x0c, +0x06,0x0c,0x04,0x0c,0x05,0xc2,0x22,0x23,0x70,0xd0,0x34,0x5a,0xec,0xd9,0x0e, +0xca,0xc5,0xa8,0x0c,0xb6,0x6a,0x0c,0xf2,0xca,0xf4,0xb6,0x2f,0x06,0x26,0x9a, +0x03,0x0c,0xaa,0xa9,0x0c,0x82,0x22,0x3e,0x27,0x68,0x1d,0xdc,0xaa,0xad,0x02, +0x88,0x03,0x0c,0x1b,0x82,0x28,0x3c,0xcd,0x06,0xe0,0x08,0x00,0xbd,0x0a,0xad, +0x02,0x65,0xd2,0xfd,0xa2,0x22,0x23,0xaa,0xa5,0xa8,0x0a,0xf6,0x6a,0x28,0xd2, +0x22,0xbf,0xb8,0x92,0xc2,0x22,0x23,0x82,0x22,0x46,0xf2,0x22,0x21,0x80,0x8a, +0xa0,0x4a,0xff,0xca,0xe5,0x5a,0xbb,0x5a,0xcc,0xb8,0x0b,0xf2,0x1f,0x00,0xf9, +0x08,0xc8,0x0c,0xa8,0x0e,0xd0,0xcc,0xa0,0xb9,0x0c,0x88,0x03,0x82,0x28,0x3f, +0xe0,0x08,0x00,0x9c,0x6a,0x0c,0x19,0xa2,0x22,0x21,0xc2,0x12,0x75,0x4a,0xaa, +0xa2,0x1a,0x00,0xb2,0x22,0xc3,0xc0,0xaa,0xc0,0xb0,0xaa,0xa0,0x99,0x0a,0xa2, +0x22,0x23,0x88,0x03,0x5a,0xaa,0x82,0x28,0x3e,0xa8,0x0a,0xe0,0x08,0x00,0x4b, +0x55,0x70,0x74,0x21,0x1b,0x66,0x9c,0x6a,0x0c,0x19,0xa2,0x22,0x21,0xc2,0x12, +0x75,0x4a,0xaa,0xa2,0x1a,0x00,0xb2,0x22,0xc4,0xc0,0xaa,0xc0,0xb0,0xaa,0xa0, +0x99,0x0a,0xb2,0x12,0x16,0x2b,0x44,0xb7,0xa6,0x02,0x06,0xcd,0xff,0xc2,0x22, +0x3e,0x27,0x6c,0x17,0x88,0x03,0x82,0x28,0x45,0xad,0x02,0xe0,0x08,0x00,0x66, +0x0a,0x0a,0x92,0x12,0x16,0x0c,0x06,0xa6,0x19,0x02,0x06,0x60,0x00,0x88,0x01, +0x0c,0x09,0x78,0x12,0x92,0x62,0xc1,0x92,0x12,0x17,0x8a,0x77,0x78,0x17,0xe6, +0x19,0x02,0xc6,0x34,0x00,0x0c,0x06,0x0c,0x04,0x0c,0x05,0xc2,0x22,0x24,0x70, +0xd0,0x34,0x5a,0xec,0xd9,0x0e,0xca,0xc5,0xa8,0x0c,0x70,0x74,0x21,0xb2,0xca, +0xfa,0xb6,0x4b,0x0e,0xf2,0xca,0xf4,0xb6,0x2f,0x08,0x0c,0xb8,0x87,0x1a,0x03, +0x0c,0xba,0xa9,0x0c,0x66,0x7a,0x1e,0xa2,0x22,0xc1,0xb2,0x22,0xc2,0x1b,0xca, +0xc2,0x62,0xc1,0xb0,0xaa,0xa0,0x69,0x0a,0x92,0x22,0xc1,0x0b,0x99,0x56,0xd9, +0x07,0xa2,0x22,0x24,0xaa,0xa5,0xa8,0x0a,0xe6,0x9a,0x28,0xd2,0x22,0xbf,0xb8, +0xa2,0xc2,0x22,0x24,0x82,0x22,0x46,0xf2,0x22,0x21,0x80,0x8a,0xa0,0x4a,0xff, +0xca,0xe5,0x5a,0xbb,0x5a,0xcc,0xb8,0x0b,0xf2,0x1f,0x08,0xf9,0x08,0xc8,0x0c, +0xa8,0x0e,0xd0,0xcc,0xa0,0xb9,0x0c,0x88,0x03,0x82,0x28,0x3f,0xe0,0x08,0x00, +0x9c,0x6a,0x0c,0x19,0xa2,0x22,0x21,0xc2,0x12,0x75,0x4a,0xaa,0xa2,0x1a,0x08, +0xb2,0x22,0xc3,0xc0,0xaa,0xc0,0xb0,0xaa,0xa0,0x99,0x0a,0x88,0x03,0xa2,0x22, +0x24,0x82,0x28,0x3e,0x5a,0xaa,0xa8,0x0a,0xe0,0x08,0x00,0x9c,0x6a,0x0c,0x19, +0xa2,0x22,0x21,0xc2,0x12,0x75,0x4a,0xaa,0xa2,0x1a,0x08,0xb2,0x22,0xc4,0xc0, +0xaa,0xc0,0xb0,0xaa,0xa0,0x99,0x0a,0x2b,0x44,0x4b,0x55,0xb2,0x12,0x17,0x1b, +0x66,0xb7,0xa6,0x02,0x46,0xcc,0xff,0xa2,0x12,0x16,0xd2,0x22,0x3e,0xe2,0xa0, +0x80,0xe0,0xdd,0x20,0xd2,0x62,0x3e,0xa6,0x1a,0x19,0xe2,0xaf,0x7f,0x0c,0x06, +0xc2,0x22,0x23,0x1b,0x66,0xf8,0x0c,0x4b,0xcc,0xe6,0x6f,0x05,0xe0,0xdd,0x10, +0xd2,0x62,0x3e,0xa7,0x26,0xed,0x0c,0x06,0xad,0x02,0xb8,0x11,0xa5,0xb5,0xff, +0x0c,0x04,0x0c,0x68,0x76,0xa8,0x19,0xb2,0x22,0x10,0xa2,0x22,0x11,0x92,0x22, +0x12,0x4a,0xaa,0x4a,0x99,0x4a,0xbb,0x62,0x5b,0x00,0x2b,0x44,0x62,0x5a,0x00, +0x62,0x59,0x00,0x0c,0xc4,0xf2,0x22,0x3e,0x0c,0x4b,0x76,0xab,0x18,0xd8,0xe2, +0xe2,0x22,0x10,0xc2,0x22,0x12,0x4a,0xee,0x4a,0xcc,0x4a,0xdd,0xd2,0x9d,0x00, +0x2b,0x44,0xd2,0x5e,0x00,0x62,0x5c,0x00,0x17,0x6f,0x09,0x88,0x03,0x82,0x28, +0x32,0xad,0x02,0xe0,0x08,0x00,0x0c,0x0a,0x0c,0x0b,0xc2,0xa3,0x20,0xca,0xc2, +0x25,0x29,0xf7,0x62,0x62,0xcc,0x1d,0xf0,0xc2,0x22,0x23,0x76,0x99,0x20,0xd8, +0x0c,0x4b,0xcc,0x66,0x4d,0x17,0xcd,0x06,0x88,0x03,0xad,0x02,0x82,0x28,0x3c, +0x0c,0x1b,0xe0,0x08,0x00,0xbd,0x0a,0xad,0x02,0x65,0xad,0xfd,0x46,0x96,0xff, +0x1b,0x66,0x06,0x95,0xff,0x00,0x00,0x36,0xa1,0x00,0xa2,0x12,0x17,0x39,0x91, +0xe6,0x1a,0x02,0x46,0x92,0x00,0x0c,0x05,0x0c,0x03,0x0c,0x06,0x0c,0x04,0x98, +0x41,0xb8,0x91,0x99,0x71,0xb0,0xb0,0xf4,0xb9,0x61,0x72,0x22,0x24,0xc8,0xa2, +0x4a,0x77,0x4a,0xcc,0xc8,0x0c,0x78,0x07,0x16,0x7c,0x21,0xa6,0x97,0x02,0x46, +0x84,0x00,0x82,0x22,0xc1,0xb2,0xc7,0xf9,0x66,0x28,0x0a,0x92,0x22,0xc2,0x98, +0x19,0x50,0x99,0xc0,0x16,0xd9,0x1f,0xb6,0x3b,0x02,0xc6,0x7d,0x00,0x98,0xc2, +0xd8,0x91,0xd9,0x51,0x90,0xc7,0xa0,0xc8,0x0c,0xc9,0xa1,0x66,0x77,0x03,0xe8, +0x89,0xe9,0xa1,0xa8,0xa1,0xb8,0x91,0x81,0x08,0x1f,0xc8,0x32,0x88,0x08,0xd2, +0x22,0x19,0x82,0x28,0x2d,0x6a,0xdd,0xe0,0x08,0x00,0x92,0x22,0x40,0x9c,0x49, +0xa8,0xa1,0xb8,0x91,0x81,0x02,0x1f,0xc8,0x32,0x88,0x08,0xd2,0x22,0xc0,0x82, +0x28,0x2d,0x6a,0xdd,0xe0,0x08,0x00,0xa8,0xa1,0xb8,0x91,0xd2,0x12,0x3a,0xe2, +0x12,0x3b,0x81,0xfb,0x1e,0xc2,0x22,0x1c,0x88,0x08,0x3a,0xcc,0x82,0x28,0x2f, +0xc2,0x1c,0x00,0xe0,0x08,0x00,0x81,0xf6,0x1e,0xad,0x02,0x88,0x08,0x0c,0x0b, +0x82,0x28,0x3c,0xcd,0x05,0xe0,0x08,0x00,0xa9,0x81,0x92,0xca,0xec,0xf6,0x29, +0x11,0x81,0xf0,0x1e,0xa2,0x22,0x17,0x88,0x08,0xb8,0xa1,0x82,0x28,0x21,0xc8, +0x91,0xe0,0x08,0x00,0x81,0xeb,0x1e,0x88,0x08,0xad,0x02,0x82,0x28,0x48,0xb8, +0x81,0xe0,0x08,0x00,0x16,0xca,0x0b,0x92,0x12,0x16,0x0c,0x0a,0xa9,0x51,0xa2, +0x22,0x2b,0x9a,0x95,0xa0,0x99,0xa0,0x98,0x09,0x16,0x49,0x04,0xad,0x02,0xb8, +0x81,0x0c,0x0c,0xe5,0xf2,0xfd,0xe8,0x61,0x81,0xfe,0x1e,0xc2,0x22,0x30,0x92, +0x12,0x62,0xdd,0x0a,0xa9,0x71,0xa2,0x12,0x16,0xb2,0x22,0x2b,0xaa,0xa5,0xb0, +0xaa,0xa0,0xa8,0x0a,0x99,0x01,0x88,0x08,0xf2,0xc1,0x14,0x82,0x28,0x16,0xb8, +0xa1,0xe0,0x08,0x00,0x66,0x8a,0x0d,0xc2,0x22,0x14,0xc0,0xc7,0x90,0xb2,0x9c, +0x00,0x1b,0xbb,0xb2,0x5c,0x00,0xd2,0x22,0x30,0xd9,0xa1,0x81,0xf9,0x1d,0xa8, +0xa2,0x88,0x08,0x4a,0xaa,0x88,0x98,0xa8,0x0a,0xe0,0x08,0x00,0xcc,0xca,0xa2, +0x22,0x13,0xa0,0xa7,0x90,0x92,0x9a,0x00,0x1b,0x99,0x92,0x5a,0x00,0x81,0xc7, +0x1e,0x88,0x08,0xa8,0xa1,0x82,0x28,0x19,0xb8,0x51,0xe0,0x08,0x00,0xc8,0x51, +0xa6,0xfc,0x04,0xc2,0xa0,0xfc,0xc9,0x51,0xb8,0xa1,0xa8,0xa2,0x88,0x02,0x4a, +0xaa,0x88,0x88,0xa8,0x0a,0xe0,0x08,0x00,0xb2,0x22,0xc1,0xf2,0x22,0xc2,0xb2, +0xcb,0xfe,0x56,0xfb,0x08,0xc8,0x0f,0x57,0x1c,0x02,0xc6,0x21,0x00,0x06,0x1c, +0x00,0x66,0x77,0x9d,0xf2,0x22,0x36,0x3c,0x0d,0xd7,0x1f,0x95,0x66,0xbf,0x07, +0xe1,0xe7,0x1e,0xe9,0x71,0xc6,0x04,0x00,0x66,0x8f,0x10,0x81,0xe4,0x1e,0x92, +0x22,0x3e,0xf1,0xde,0x1e,0x90,0x93,0x04,0x90,0xf8,0x93,0xf9,0x71,0xa2,0x12, +0x16,0x0c,0x0b,0xb9,0x51,0xb2,0x22,0x2b,0xaa,0xa5,0xb0,0xaa,0xa0,0xa8,0x0a, +0x16,0xda,0xf5,0xb8,0xa1,0xd8,0x71,0x81,0xc6,0x1e,0xc2,0x22,0x30,0x92,0x12, +0x62,0x99,0x01,0x88,0x08,0xe8,0x61,0x82,0x28,0x16,0xf2,0xc1,0x14,0xe0,0x08, +0x00,0xa2,0xca,0xf8,0x56,0xba,0xf3,0xc2,0x22,0x14,0xc0,0xc7,0x90,0xb2,0x9c, +0x00,0x1b,0xbb,0xb2,0x5c,0x00,0x86,0xca,0xff,0xb8,0xa1,0xc8,0x51,0xd8,0xa2, +0x88,0x02,0xa8,0x1f,0x88,0x88,0xd0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x66, +0x77,0x10,0x81,0x95,0x1e,0xb8,0x81,0x88,0x08,0xad,0x02,0x82,0x28,0x3a,0xc8, +0x51,0xe0,0x08,0x00,0xa2,0x12,0x17,0x2b,0x33,0x62,0xc6,0x10,0x4b,0x44,0x1b, +0x55,0xa7,0xa5,0x02,0x06,0x72,0xff,0x1d,0xf0,0x00,0x00,0x36,0xc1,0x00,0x26, +0x03,0x48,0x30,0xc0,0xf4,0x41,0x89,0x1e,0xad,0x02,0x88,0x04,0x0c,0x1b,0x82, +0x28,0x3b,0xdd,0x01,0xe0,0x08,0x00,0xa0,0x90,0xf4,0xa6,0x19,0x2e,0x3d,0x01, +0x30,0x59,0x90,0xb2,0x93,0x00,0x26,0x0b,0x1e,0x98,0x92,0x90,0x9b,0xa0,0x98, +0x09,0x9c,0x49,0x88,0x04,0xa2,0x22,0x23,0x82,0x28,0x3e,0xa0,0xab,0xa0,0xa8, +0x0a,0xe0,0x08,0x00,0x8c,0x2a,0x0c,0x12,0x1d,0xf0,0x2b,0x33,0x57,0x93,0xd5, +0x0c,0x02,0x1d,0xf0,0x00,0x36,0xa1,0x00,0x9d,0x03,0x88,0x03,0xa2,0x12,0x16, +0x89,0x81,0xe6,0x1a,0x02,0x06,0x59,0x00,0x0c,0x05,0x0c,0x06,0x0c,0x07,0x0c, +0x04,0x39,0xa1,0x80,0xe0,0xf4,0xe9,0x61,0x32,0x22,0x23,0xf8,0x92,0x4a,0x33, +0x4a,0xff,0xf8,0x0f,0x38,0x03,0x9c,0x0f,0x81,0x6b,0x1e,0x88,0x08,0x82,0x28, +0x3e,0xad,0x03,0xe0,0x08,0x00,0xdc,0x2a,0xa2,0x12,0x16,0x2b,0x66,0x72,0xc7, +0x10,0x4b,0x44,0x1b,0x55,0xa7,0x25,0xd2,0x98,0xa1,0xc6,0x48,0x00,0x81,0x62, +0x1e,0xad,0x02,0x88,0x08,0x0c,0x1b,0x82,0x28,0x3c,0xcd,0x05,0xe0,0x08,0x00, +0x81,0x5e,0x1e,0xbd,0x0a,0x88,0x08,0xa9,0x71,0x82,0x28,0x48,0xad,0x02,0xe0, +0x08,0x00,0xcc,0xaa,0x98,0xc2,0x90,0x93,0xa0,0x98,0x09,0x99,0x91,0x06,0x01, +0x00,0xa2,0x22,0x30,0xa9,0x91,0xb8,0x91,0xc8,0x81,0xa8,0x92,0x88,0x02,0x4a, +0xaa,0x88,0x98,0xa8,0x0a,0xe0,0x08,0x00,0x81,0x50,0x1e,0x88,0x08,0xa8,0x91, +0x82,0x28,0x17,0xb8,0x81,0xe0,0x08,0x00,0xa8,0x91,0xb8,0x81,0x81,0x4c,0x1e, +0xc8,0x32,0x88,0x08,0xd2,0x22,0x18,0x82,0x28,0x2d,0x7a,0xdd,0xe0,0x08,0x00, +0x98,0x71,0x92,0xc9,0xf0,0xf6,0x39,0x11,0x81,0x45,0x1e,0xa2,0x22,0x16,0x88, +0x08,0xb8,0x91,0x82,0x28,0x21,0xc8,0x81,0xe0,0x08,0x00,0x81,0x41,0x1e,0x88, +0x08,0xad,0x02,0x82,0x28,0x48,0xb8,0x71,0xe0,0x08,0x00,0x16,0xaa,0x06,0xe0, +0x93,0x11,0x0c,0x0b,0xa2,0x22,0x2b,0xb9,0x41,0x4a,0xaa,0xa8,0x0a,0x99,0x51, +0x16,0xaa,0x04,0xb8,0x71,0xad,0x02,0x0c,0x1c,0x65,0xc8,0xfd,0xb8,0x91,0xf2, +0xc1,0x10,0x81,0x53,0x1e,0xe8,0x51,0xc8,0xc2,0xdd,0x0a,0x98,0xe2,0xa2,0x22, +0x2b,0x90,0x93,0x90,0x92,0x99,0x00,0x4a,0xaa,0xea,0xcc,0xc8,0x0c,0xa8,0x0a, +0x99,0x01,0x88,0x08,0xf0,0x33,0x11,0x82,0x28,0x16,0xe8,0x61,0xe0,0x08,0x00, +0x98,0x51,0x66,0x8a,0x0c,0x82,0x22,0x14,0x8a,0x83,0xf2,0x98,0x00,0x1b,0xff, +0xf2,0x58,0x00,0xc8,0xc2,0xb8,0x41,0x9a,0xcc,0xc8,0x0c,0xc9,0x91,0xc6,0x00, +0x00,0xb8,0x81,0xb9,0x41,0xa8,0x91,0xd2,0x12,0x3a,0xe2,0x12,0x3b,0x31,0x1e, +0x1e,0xc2,0x22,0x1b,0x88,0x03,0x6a,0xcc,0x82,0x28,0x2f,0xc2,0x1c,0x00,0xe0, +0x08,0x00,0xc6,0xb1,0xff,0xd8,0x41,0xd9,0x09,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x01,0x9d,0x01,0x0c,0x0a,0x1c,0x98,0x76,0xa8,0x03,0xa9,0x09,0x4b,0x99, +0xa2,0x12,0x16,0x0c,0x03,0xe6,0x1a,0x02,0xc6,0x22,0x00,0x61,0x10,0x1e,0x0c, +0x04,0x52,0x22,0x23,0xc8,0x92,0x3a,0x55,0x3a,0xcc,0xc8,0x0c,0x58,0x05,0x8c, +0xdc,0x88,0x06,0x82,0x28,0x3f,0xad,0x05,0xe0,0x08,0x00,0xcc,0xba,0xa2,0x12, +0x16,0x4b,0x33,0x1b,0x44,0xa7,0x24,0xda,0x86,0x17,0x00,0xad,0x02,0x88,0x06, +0x0c,0x1b,0x82,0x28,0x3c,0xcd,0x04,0xe0,0x08,0x00,0x7d,0x0a,0x88,0x06,0xad, +0x02,0x82,0x28,0x48,0xbd,0x07,0xe0,0x08,0x00,0x9d,0x01,0x90,0x97,0xa0,0xbc, +0x3a,0xa8,0x09,0xec,0xfa,0xb2,0x22,0xc6,0xec,0xab,0x92,0x61,0x1c,0x66,0x35, +0x07,0xc2,0x22,0xcc,0x92,0x61,0x1c,0xdc,0xcc,0xbd,0x07,0xad,0x02,0xe2,0x22, +0x23,0x0c,0x1c,0xea,0xe3,0xe8,0x0e,0xf2,0x22,0x12,0xdd,0x0e,0xf0,0xee,0x90, +0xe2,0x9e,0x00,0xa5,0xb3,0xfd,0x92,0x21,0x1c,0x0c,0x1f,0xf9,0x09,0xc6,0xe4, +0xff,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x01,0x9d,0x01,0x0c,0x0a,0x1c,0x98, +0x76,0xa8,0x03,0xa9,0x09,0x4b,0x99,0xa2,0x12,0x17,0x0c,0x03,0xa6,0x1a,0x5c, +0x61,0xe6,0x1d,0x0c,0x17,0x0c,0x04,0x52,0x22,0x24,0x3a,0x55,0x58,0x05,0x0c, +0xab,0x57,0x2b,0x42,0x88,0xa2,0x3a,0x88,0x88,0x08,0xbc,0x98,0xad,0x02,0x88, +0x06,0x0c,0x0b,0x82,0x28,0x3c,0xcd,0x04,0xe0,0x08,0x00,0xbd,0x0a,0x9d,0x01, +0x90,0x9a,0xa0,0xa8,0x09,0xdc,0xba,0xa2,0x22,0xc6,0x92,0x61,0x1c,0xdc,0x3a, +0xdd,0x05,0xad,0x02,0xe2,0x22,0x12,0x0c,0x0c,0xe0,0xe5,0x90,0xe2,0x9e,0x00, +0x65,0xac,0xfd,0x92,0x21,0x1c,0xa2,0x12,0x17,0x79,0x09,0x4b,0x33,0x1b,0x44, +0xa7,0x24,0xa9,0x1d,0xf0,0x00,0x36,0x81,0x00,0x0c,0x06,0x0c,0x04,0x0c,0x87, +0x9d,0x03,0x0c,0xb3,0x99,0x41,0x52,0x22,0x24,0x88,0xa2,0x4a,0x55,0x4a,0x88, +0x88,0x08,0x58,0x05,0x16,0x18,0x0f,0x30,0x85,0xc0,0x16,0xb8,0x0e,0x92,0xc5, +0xf9,0xb6,0x39,0x02,0x86,0x38,0x00,0x81,0xc2,0x1d,0xad,0x02,0x88,0x08,0x0c, +0x0b,0x82,0x28,0x3c,0xcd,0x06,0xe0,0x08,0x00,0xa9,0x51,0x66,0x75,0x52,0x90, +0x64,0x00,0x99,0x21,0x81,0xe5,0x1c,0xa8,0xa2,0x88,0x08,0x4a,0xaa,0x88,0x98, +0xa8,0x0a,0xe0,0x08,0x00,0xa9,0x01,0xa8,0x51,0x65,0xf1,0xfd,0x81,0xb6,0x1d, +0x98,0x01,0xb8,0x21,0xaa,0x99,0xb0,0xe6,0x13,0x20,0x20,0x00,0xa8,0x41,0xb2, +0x22,0x46,0x88,0x08,0xb8,0x4b,0x82,0x28,0x48,0xa0,0x99,0xc0,0x99,0x31,0xad, +0x02,0xe0,0x08,0x00,0x8c,0xea,0xad,0x02,0x0c,0x1c,0x0c,0x4d,0xb2,0x22,0x46, +0xe8,0x31,0xb8,0x4b,0xa5,0xa1,0xfd,0x66,0x85,0x76,0x50,0x64,0x00,0x81,0xd0, +0x1c,0xa8,0xa2,0x88,0x08,0x4a,0xaa,0x88,0x98,0xa8,0x0a,0xe0,0x08,0x00,0xa9, +0x11,0x59,0x21,0xa8,0x51,0x25,0xec,0xfd,0xb8,0x51,0x81,0xa0,0x1d,0x58,0x11, +0x98,0x21,0xaa,0x55,0x90,0xe6,0x13,0x20,0x20,0x00,0xad,0x02,0x88,0x08,0x98, +0x41,0x82,0x28,0x48,0x90,0x55,0xc0,0xe0,0x08,0x00,0x59,0x31,0x8c,0xba,0xb8, +0x51,0xad,0x02,0x0c,0x0c,0x0c,0x8d,0xed,0x05,0xa5,0x9c,0xfd,0x82,0x22,0x3e, +0x17,0x68,0x23,0x81,0x92,0x1d,0xad,0x02,0x88,0x08,0xb2,0x22,0x46,0x82,0x28, +0x48,0xb8,0x4b,0xe0,0x08,0x00,0x8c,0xea,0xad,0x02,0x0c,0x1c,0x0c,0x4d,0xb2, +0x22,0x46,0xe8,0x31,0xb8,0x4b,0x25,0x9a,0xfd,0x1b,0x66,0x4b,0x44,0x0b,0x77, +0x56,0x47,0xef,0x1d,0xf0,0x36,0x61,0x00,0xfd,0x07,0xed,0x06,0xdd,0x05,0xcd, +0x04,0x81,0x8a,0x1d,0x98,0xc1,0x99,0x01,0x88,0x08,0xbd,0x03,0x82,0x28,0xbe, +0xad,0x02,0xe0,0x08,0x00,0x2d,0x0a,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xe6, +0x42,0x02,0xd6,0x52,0x00,0xe6,0x82,0x06,0xa6,0x62,0x03,0x0c,0x12,0x1d,0xf0, +0x0c,0x02,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x48,0xf0,0x64,0x00,0x0c,0xf7, +0x80,0x87,0x10,0xf0,0x77,0x10,0xf0,0xf7,0x30,0xf0,0xf8,0x20,0xf0,0xe6,0x13, +0x10,0x20,0x00,0x88,0x12,0x68,0x22,0x0c,0x09,0x87,0x96,0x1b,0x3d,0x09,0xf0, +0x64,0x00,0x0c,0xfa,0x90,0x9a,0x10,0xf0,0xaa,0x10,0xf0,0xfa,0x30,0xf0,0xf9, +0x20,0xf0,0xe6,0x13,0x10,0x20,0x00,0x86,0x0f,0x00,0x8c,0x53,0xb8,0x08,0xb0, +0xb0,0xf5,0xb9,0x03,0x8c,0x54,0xc8,0x08,0xc0,0xc0,0xf4,0xc9,0x04,0x38,0x02, +0x8c,0x25,0xd8,0x18,0xd9,0x05,0xe2,0xd3,0x04,0x8b,0x88,0xe7,0x98,0x01,0x8d, +0x03,0x0c,0x13,0x89,0x12,0xf0,0x64,0x00,0x0c,0xf6,0x90,0x96,0x10,0xf0,0x66, +0x10,0xf0,0xf6,0x30,0xf0,0xf9,0x20,0xf0,0xe6,0x13,0x10,0x20,0x00,0x2d,0x03, +0x1d,0xf0,0xf0,0x49,0x18,0x20,0x36,0x81,0x00,0x0c,0x07,0x0c,0x06,0x0c,0x04, +0x1c,0xf5,0x0c,0x08,0x0c,0x0b,0x0c,0x0c,0xc9,0x51,0xb9,0x31,0x89,0x41,0x89, +0x01,0x89,0x11,0x89,0x21,0xbd,0x01,0x4b,0xc1,0xa2,0x22,0x1c,0x8b,0xd1,0xa8, +0x0a,0xe5,0xf4,0xff,0x16,0x7a,0x07,0xb8,0x01,0xdc,0x14,0x66,0x7b,0x0f,0xc8, +0x11,0x66,0x7c,0x0a,0x0c,0x0a,0x0c,0x14,0xd8,0x21,0xd9,0x31,0x46,0x00,0x00, +0x0c,0x1a,0x66,0x1b,0x10,0xe8,0x11,0x1c,0x9f,0xf7,0x9e,0x09,0x0c,0x0a,0x0c, +0x18,0x98,0x21,0x99,0x41,0x89,0x51,0x57,0x9b,0x05,0x78,0x11,0x0c,0x0a,0x0c, +0x16,0x16,0x5a,0xfb,0x32,0x22,0x1a,0x38,0x03,0x9c,0x03,0xad,0x03,0xb8,0x01, +0xc8,0x11,0x88,0x03,0xd8,0x21,0xe0,0x08,0x00,0x38,0x43,0x56,0xd3,0xfe,0x32, +0x22,0x1b,0x38,0x03,0x16,0x43,0xf9,0xb8,0x01,0xe8,0x03,0x66,0x7b,0x05,0x81, +0xdb,0xff,0x87,0x1e,0x08,0xad,0x03,0xc8,0x11,0xd8,0x21,0xe0,0x0e,0x00,0x38, +0x43,0x56,0x43,0xfe,0x86,0xdd,0xff,0x8c,0x94,0xc8,0x31,0x0c,0x7a,0x88,0xf2, +0x0c,0x7b,0xe0,0x08,0x00,0x98,0x51,0x8c,0x99,0xc8,0x41,0x0c,0x1a,0x88,0xf2, +0x1c,0x9b,0xe0,0x08,0x00,0x8c,0x96,0xbd,0x07,0x1c,0xfa,0x88,0xf2,0x0c,0x0c, +0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x82,0x22,0x14,0xa2, +0x22,0x1c,0x0c,0x0b,0xa8,0x0a,0xb9,0x01,0xb9,0x11,0xb9,0x21,0xe0,0x08,0x00, +0x6d,0x0a,0xa6,0x1a,0x27,0x0c,0x05,0xbd,0x01,0x4b,0xc1,0xa2,0x22,0x1c,0x8b, +0xd1,0xa8,0x0a,0xa5,0xe7,0xff,0x8c,0xfa,0xb8,0x11,0xa8,0x01,0xb7,0x93,0x02, +0xa7,0x14,0x06,0x88,0xf2,0xc8,0x21,0xe0,0x08,0x00,0x1b,0x55,0x57,0x96,0xd9, +0x1d,0xf0,0x00,0x00,0x00,0xec,0xc7,0x08,0x20,0x71,0xd1,0x08,0x20,0xe8,0x4e, +0x05,0x20,0x00,0x80,0x05,0x20,0xf0,0xc7,0x08,0x20,0x00,0x00,0x04,0x00,0x00, +0x80,0xff,0xff,0xeb,0xce,0xff,0xff,0x00,0x01,0x05,0x20,0x36,0x41,0x00,0x71, +0xfa,0xff,0x31,0xf7,0xff,0x51,0xf7,0xff,0x7c,0xc6,0x41,0xf3,0xff,0x21,0xf3, +0xff,0x29,0x04,0x3b,0x22,0x60,0x22,0x10,0x29,0x04,0x37,0x35,0x0b,0x0c,0x03, +0x39,0x07,0x0c,0x12,0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x91,0xf1,0xff,0xa1,0xf1, +0xff,0x81,0xf1,0xff,0x41,0xf1,0xff,0x60,0x68,0x10,0xa0,0x44,0x10,0x20,0x44, +0xc0,0x9a,0x44,0x67,0x24,0xe1,0x69,0x07,0x80,0xb2,0x41,0x16,0x5b,0xfd,0x0c, +0x06,0x1b,0x66,0xd8,0x05,0x4b,0x55,0xd9,0x02,0xc8,0x07,0x4b,0x22,0xc0,0xc2, +0x41,0xc7,0x36,0xed,0x86,0xef,0xff,0x00,0x00,0x00,0xfe,0xfe,0xfe,0xfe,0x36, +0x41,0x00,0xd1,0xdf,0xff,0x81,0xfd,0xff,0xa8,0x0d,0xb1,0xd9,0xff,0x87,0x9a, +0x06,0x25,0xf8,0xff,0x2d,0x0a,0x1d,0xf0,0xa0,0x92,0x41,0xa8,0x0b,0x9c,0x59, +0xb1,0xd7,0xff,0x0c,0x0c,0x1b,0xcc,0xf8,0x0a,0x4b,0xaa,0xf9,0x0b,0xe8,0x0d, +0x4b,0xbb,0xe0,0xe2,0x41,0xe7,0x3c,0xed,0x0c,0x12,0x1d,0xf0,0x00,0x00,0x36, +0x41,0x00,0x31,0x34,0x1d,0xc8,0x03,0x8c,0x7c,0x88,0x2c,0x8c,0x38,0x1d,0xf0, +0x00,0x00,0x00,0xc8,0x22,0xc9,0x03,0x16,0xe2,0x04,0xa8,0x02,0x98,0x12,0x16, +0xea,0x04,0xa9,0x1c,0xd8,0x32,0x8c,0x09,0x99,0x4c,0x16,0x8d,0x04,0xd9,0x5c, +0x91,0x2a,0x1d,0xb1,0x2d,0x1d,0x81,0x2a,0x1d,0xe1,0x2b,0x1d,0xf1,0x29,0x1d, +0xf2,0x6c,0x12,0xe2,0x6c,0x13,0x82,0x6c,0x11,0xb2,0x6c,0x15,0x99,0xfc,0x1c, +0x0b,0x91,0x27,0x1d,0x92,0x6c,0x16,0xe0,0x0d,0x00,0x88,0x03,0xa9,0x28,0xa8, +0x18,0x88,0x58,0x1c,0x0b,0xe0,0x08,0x00,0x98,0x03,0xa9,0x39,0x1d,0xf0,0xa8, +0x1c,0xd8,0x5c,0x46,0xef,0xff,0xa8,0x1c,0x46,0xeb,0xff,0xd8,0x5c,0xc6,0xec, +0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x81,0x00,0x39,0x22,0x39,0x51,0xd2, +0xc1,0x14,0xd0,0x80,0x0c,0x1c,0xf6,0xaf,0xe0,0x0a,0x22,0x82,0x29,0x04,0x00, +0xaf,0xe0,0x0a,0x22,0x82,0x29,0x05,0x00,0xaf,0xe0,0x0a,0x22,0x82,0x29,0x06, +0x00,0x8f,0x9d,0xbf,0x42,0x82,0x29,0x07,0x00,0x0f,0x62,0x01,0x82,0x2e,0x2b, +0x11,0x00,0x00,0x8b,0x0d,0xb0,0x00,0x0c,0x4b,0xa2,0x00,0x0a,0x0d,0x82,0x92, +0x08,0x80,0x58,0x01,0x40,0x98,0x01,0x90,0x9c,0x31,0x50,0x5c,0x31,0xc0,0x88, +0x01,0x80,0x8c,0x31,0x9a,0x55,0x8a,0x55,0x0f,0x84,0x40,0x82,0x6e,0x09,0x01, +0x00,0x8f,0x20,0x04,0x28,0x44,0x0c,0x0c,0x11,0x8f,0xa4,0x1c,0x82,0x48,0x10, +0x08,0x01,0x2f,0x20,0x64,0x43,0x44,0x0c,0x0c,0x11,0x00,0x44,0x0d,0x58,0x22, +0x38,0xe2,0x59,0x92,0x2f,0x66,0xe0,0x22,0xc0,0x10,0x0c,0x00,0x00,0x13,0x40, +0x00,0xe5,0xa1,0xe9,0x92,0x42,0xc2,0x28,0x91,0xef,0x1c,0xa2,0x22,0x06,0x92, +0x29,0x00,0x82,0x92,0x08,0x92,0x29,0x01,0x80,0x8c,0x21,0x90,0x92,0x41,0xa0, +0x99,0xc0,0x92,0xc9,0xf0,0x92,0x62,0x0a,0x76,0x00,0x07,0x0f,0x20,0x84,0x28, +0x44,0x0c,0x0c,0x11,0xaf,0x81,0x00,0xa2,0x2e,0x4a,0x01,0x00,0xaf,0xe0,0x0a, +0x22,0x48,0x40,0x20,0x01,0xaf,0xe0,0x0a,0x22,0x82,0x39,0x04,0x00,0xaf,0xe0, +0x0a,0x22,0xa4,0x30,0x18,0x02,0xaf,0xe0,0x0a,0x22,0x82,0x31,0x04,0x11,0x00, +0xc4,0x0d,0xf8,0xa2,0x7c,0xc3,0x30,0xff,0x10,0xf9,0xa2,0x1d,0xf0,0x00,0x00, +0xd6,0x83,0xf9,0x30,0xb0,0x60,0x00,0x0b,0x40,0x50,0xa0,0x91,0xa9,0x92,0x86, +0xe2,0xff,0x00,0x00,0x00,0x36,0x61,0x00,0xad,0x03,0x81,0xd0,0x1c,0x49,0x21, +0x7c,0xc6,0x3b,0xc5,0x7d,0x02,0xb8,0x67,0x21,0xd4,0x1c,0x98,0x97,0x60,0xcc, +0x10,0x48,0x77,0x92,0x61,0x01,0x82,0x28,0x00,0x28,0x02,0x88,0x78,0x30,0xbb, +0xa0,0xe0,0x08,0x00,0x81,0xc7,0x1c,0xa8,0x57,0x88,0x08,0xbd,0x03,0x88,0x78, +0xc2,0x27,0x06,0xe0,0x08,0x00,0x6c,0xdb,0x1c,0xfc,0xed,0x01,0xf2,0xc5,0x15, +0xc0,0xff,0x01,0x40,0xff,0xc0,0xf0,0xf1,0x41,0xf9,0x01,0xe0,0x00,0x0c,0x0f, +0xae,0x41,0x82,0x2a,0x31,0x80,0x10,0xaf,0xa0,0x01,0xa2,0x02,0x0b,0x04,0x00, +0x2f,0x01,0x81,0x49,0xee,0x0a,0x01,0x00,0x2f,0x49,0x01,0x42,0xa4,0x00,0x80, +0x00,0xa0,0xa5,0x41,0xef,0x45,0x92,0x43,0x6c,0x0c,0x83,0x00,0x00,0x0e,0x0d, +0xd8,0x01,0x1b,0xcb,0xd0,0xbc,0x93,0x60,0xbb,0x10,0xb9,0x31,0xe6,0x1b,0x02, +0x06,0x34,0x00,0x0b,0xbb,0x0c,0x16,0xe8,0x11,0xb0,0x99,0x11,0x30,0xaa,0xa0, +0x8f,0xf4,0x02,0x22,0x44,0x0c,0x0c,0x11,0x9a,0x92,0xea,0xc4,0x90,0x03,0xbc, +0x4f,0xf5,0x92,0x22,0x44,0x0c,0x0c,0x11,0xcf,0xf4,0x82,0x22,0x44,0x0c,0x0c, +0x11,0x90,0xe6,0xa7,0xaf,0x22,0x55,0xa2,0x22,0x33,0x80,0x10,0x4f,0x99,0x93, +0x43,0xe0,0x40,0x5d,0x0e,0xef,0x83,0x05,0x62,0xc0,0x40,0x5e,0x0e,0x90,0x26, +0xa7,0x8f,0x54,0x93,0x43,0x0a,0x58,0x51,0x02,0x2f,0x09,0x01,0x42,0xe0,0x40, +0xc5,0x0c,0x0f,0x0b,0x9f,0x43,0xc0,0x40,0xc6,0x0c,0x76,0x9b,0x59,0xb0,0x99, +0x11,0x8f,0xc8,0x69,0x43,0x02,0x58,0x09,0x02,0x2f,0x01,0x81,0x49,0x2e,0x31, +0x80,0x10,0x2f,0x3f,0x69,0x43,0x30,0x5c,0xa9,0x02,0x30,0x88,0xa0,0x10,0x4c, +0x9d,0x90,0x03,0x8c,0x90,0xa6,0x87,0x8f,0xf0,0x02,0x22,0x44,0x0c,0x0c,0x11, +0xcf,0xf0,0x82,0x22,0xe0,0x40,0x15,0x08,0x2f,0x22,0x45,0xa2,0xc0,0x40,0x16, +0x08,0x90,0xa6,0x87,0xcf,0xf0,0x82,0x22,0x0a,0x58,0x09,0x02,0x2f,0x69,0x01, +0x42,0xe0,0x40,0x15,0x08,0x0f,0x6b,0x9f,0x43,0xc0,0x40,0x16,0x08,0xaf,0xe0, +0x0a,0x22,0x02,0x58,0x09,0x02,0xaf,0xe0,0x0a,0x22,0x30,0x5c,0xa9,0x02,0x10, +0x4c,0x9d,0x81,0x78,0x1c,0x30,0xa5,0xa0,0x88,0x08,0xb8,0x57,0x88,0x88,0xc8, +0x67,0xe0,0x08,0x00,0x28,0x31,0xc0,0x95,0x01,0x90,0x94,0xc0,0x99,0x77,0x1d, +0xf0,0x00,0x00,0x36,0x81,0x00,0x5d,0x07,0x0c,0x08,0x89,0x07,0xac,0x12,0x9c, +0xb3,0x9c,0x94,0xa1,0x6d,0x1c,0xf8,0x0a,0x98,0x1f,0x90,0x92,0x41,0x67,0x39, +0x0d,0x8c,0xa7,0xb1,0x71,0x1c,0xa8,0x02,0xb7,0x1a,0x0b,0x0c,0x12,0x1d,0xf0, +0x0c,0x32,0x1d,0xf0,0x0c,0x12,0x1d,0xf0,0xad,0x03,0xb8,0x2f,0x88,0x8f,0xcd, +0x06,0xe0,0x08,0x00,0xf1,0x61,0x1c,0xf8,0x0f,0x78,0x3f,0x38,0x2f,0x69,0x01, +0xa8,0xb2,0x6d,0x03,0xbc,0x0a,0x88,0xbf,0xe0,0x08,0x00,0xf1,0x5c,0x1c,0xf8, +0x0f,0xac,0x4a,0xbd,0x03,0x39,0x21,0xa8,0xb2,0xcd,0x07,0xd2,0x11,0x00,0x88, +0xef,0xed,0x01,0xe0,0x08,0x00,0x8c,0x2a,0x0c,0x62,0x1d,0xf0,0x38,0x01,0x16, +0xd3,0x0d,0x6d,0x07,0xf1,0x52,0x1c,0x78,0x21,0xf8,0x0f,0xa8,0xc2,0xac,0x5a, +0x88,0xbf,0xe0,0x08,0x00,0xf1,0x4e,0x1c,0x38,0x01,0xf8,0x0f,0x9c,0x9a,0xbd, +0x06,0x69,0x11,0x30,0xd0,0xf4,0xa8,0xc2,0xcd,0x07,0x88,0xef,0xed,0x01,0xe0, +0x08,0x00,0x16,0x2a,0x09,0x0c,0x62,0x1d,0xf0,0x38,0x01,0xb8,0x62,0xa8,0x1f, +0x3a,0xbb,0xa0,0xa2,0x41,0xb7,0xba,0x03,0x0c,0x72,0x1d,0xf0,0xcd,0x07,0xbd, +0x06,0x69,0x31,0x79,0x41,0x30,0xd0,0xf4,0x82,0x2f,0x11,0xad,0x02,0xe0,0x08, +0x00,0x78,0x41,0x3d,0x0a,0xa9,0x01,0x16,0x0a,0x07,0xa8,0xd2,0x6d,0x07,0xac, +0xfa,0x81,0x39,0x1c,0x88,0x08,0x88,0xb8,0xe0,0x08,0x00,0x38,0x01,0xac,0x1a, +0xbd,0x07,0xa8,0xd2,0x81,0x34,0x1c,0x30,0xd0,0xf4,0x88,0x08,0xc8,0x31,0x88, +0xe8,0xed,0x01,0xe0,0x08,0x00,0x8c,0x3a,0x0c,0x62,0x1d,0xf0,0x00,0x38,0x01, +0x16,0x23,0x05,0x68,0x31,0xa2,0x21,0x10,0x26,0x0a,0x39,0x37,0xba,0x08,0xa9, +0x01,0x3d,0x0a,0x0c,0x82,0x46,0x00,0x00,0x0c,0x02,0x81,0x28,0x1c,0xad,0x06, +0x88,0x08,0xbd,0x04,0x88,0x88,0xcd,0x03,0xe0,0x08,0x00,0x98,0x01,0x99,0x05, +0x1d,0xf0,0x38,0x01,0x9c,0xb3,0x6d,0x07,0xf1,0x21,0x1c,0x78,0x11,0xf8,0x0f, +0x86,0xd8,0xff,0xa9,0x05,0x0c,0x02,0x1d,0xf0,0x0c,0x02,0x86,0xf3,0xff,0x39, +0x05,0x0c,0x02,0x1d,0xf0,0x39,0x05,0x0c,0x02,0x1d,0xf0,0x39,0x05,0x0c,0x02, +0x1d,0xf0,0x00,0x36,0x81,0x00,0x29,0x41,0xcc,0x25,0x0c,0x12,0x1d,0xf0,0x61, +0x14,0x1c,0x88,0x06,0x3c,0xca,0x88,0x58,0x0c,0x4b,0xe0,0x08,0x00,0x2d,0x0a, +0xcc,0x2a,0x0c,0x42,0x1d,0xf0,0xf2,0xc1,0x10,0x91,0x17,0x1c,0xa1,0x17,0x1c, +0x88,0x41,0xb1,0x14,0x1c,0xb9,0x02,0xa0,0x88,0x73,0x90,0x88,0x63,0x89,0x41, +0x89,0x22,0xf0,0x00,0x0c,0x1c,0xfe,0x0f,0x82,0x01,0x82,0x82,0x0b,0x04,0x00, +0x8f,0xbd,0xbf,0x42,0x82,0x0b,0x05,0x00,0x0f,0x62,0xa1,0x42,0x82,0x0b,0x06, +0x00,0x0f,0x4e,0xa1,0x42,0x82,0x0b,0x07,0x00,0x8f,0x23,0xa1,0x42,0x6e,0x0b, +0x01,0x00,0x00,0x0c,0x0d,0x88,0x06,0x39,0x32,0x88,0x58,0x99,0x62,0xe0,0x08, +0x00,0xa9,0x52,0x16,0xaa,0x06,0x16,0xf4,0x08,0x92,0x14,0x00,0x92,0x52,0x08, +0x88,0x06,0xad,0x02,0x88,0xf8,0xb2,0x21,0x04,0xe0,0x08,0x00,0xc2,0x92,0x08, +0xd8,0x32,0x0c,0x03,0x39,0xb2,0x39,0xc2,0x39,0xd2,0xd0,0x90,0x04,0x40,0xac, +0x01,0xa0,0xac,0x31,0x07,0x6d,0x04,0x0c,0x13,0x46,0x00,0x00,0x9c,0x8a,0x88, +0x06,0xbd,0x03,0x88,0x98,0xc2,0xc2,0x2c,0xe0,0x08,0x00,0x8c,0x2a,0x0c,0x52, +0x1d,0xf0,0x98,0x32,0xc2,0x92,0x08,0x90,0x90,0x04,0x80,0xac,0x01,0xa0,0xac, +0x31,0xcc,0x09,0x9c,0xca,0x88,0x06,0xbd,0x03,0x88,0x98,0xc2,0xc2,0x30,0xe0, +0x08,0x00,0x8c,0x6a,0x0c,0x52,0x1d,0xf0,0x0c,0x42,0x1d,0xf0,0x98,0x32,0xc2, +0x92,0x08,0x90,0x90,0x04,0xc0,0xac,0x01,0xa0,0xac,0x31,0xcc,0x09,0xac,0x7a, +0x88,0x06,0xbd,0x03,0x88,0x98,0xc2,0xc2,0x34,0xe0,0x08,0x00,0x9c,0x9a,0x0c, +0x52,0x1d,0xf0,0x88,0x06,0x82,0x28,0x10,0xa8,0x01,0xe0,0x08,0x00,0xa9,0x11, +0x4b,0x91,0x92,0x19,0x00,0x92,0x52,0x08,0x86,0xd7,0xff,0x91,0xd4,0x1b,0xa8, +0x09,0xcc,0xaa,0xb8,0x06,0xb8,0x4b,0xb9,0x09,0x29,0x05,0x0c,0x02,0x1d,0xf0, +0x29,0x05,0x0c,0x02,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x8c,0x62,0x91,0xcd, +0x1b,0x88,0x02,0x97,0x18,0x03,0x0c,0x12,0x1d,0xf0,0xb1,0xcd,0x1b,0xa8,0x62, +0xb9,0x72,0xa6,0x1a,0x1a,0x0c,0x0b,0x0c,0x0a,0x0c,0x0c,0x76,0x80,0x0e,0xe8, +0x52,0x1b,0xaa,0xba,0xee,0xc9,0x0e,0xd8,0x62,0x4b,0xbb,0xd7,0xaa,0x02,0x86, +0xfa,0xff,0xcb,0x32,0x41,0xb9,0x1b,0xa8,0xb2,0x8c,0x5a,0x88,0x04,0x88,0xa8, +0xe0,0x08,0x00,0x4b,0x22,0x37,0x92,0xef,0x0c,0x02,0x1d,0xf0,0x00,0x36,0xe1, +0x00,0xa2,0xc1,0x3c,0x59,0xf1,0x16,0x42,0x0c,0x8c,0xe3,0x8c,0xc4,0x8c,0xa7, +0xc1,0xb6,0x1b,0xb8,0x02,0xc7,0x1b,0x07,0x0c,0x12,0x1d,0xf0,0x0c,0x32,0x1d, +0xf0,0xb1,0xb4,0x1b,0xc1,0xb3,0x1b,0xb0,0xb5,0x73,0xc0,0xbb,0x63,0xb9,0xf1, +0xb9,0x22,0xa0,0x00,0x0c,0x1c,0xf9,0xaf,0xe0,0x0a,0x22,0x42,0x0a,0x04,0x00, +0xaf,0xe0,0x0a,0x22,0x42,0x0a,0x05,0x00,0x2f,0xd4,0x37,0x02,0x42,0x0a,0x06, +0x00,0x8f,0x1d,0xbf,0x42,0x42,0x0a,0x07,0x00,0x0f,0xe2,0x21,0x82,0x2e,0x0a, +0x01,0x00,0x00,0x0f,0x0d,0xa8,0x41,0xd8,0x12,0xc8,0x32,0xa7,0x1d,0x11,0x07, +0xec,0x6a,0x81,0x97,0x1b,0x88,0x08,0xad,0x02,0x88,0xf8,0xb2,0x21,0x0f,0xe0, +0x08,0x00,0x0c,0x09,0x99,0x07,0x16,0x06,0x05,0x52,0x21,0x1c,0xad,0x02,0xbd, +0x03,0xcd,0x04,0xf2,0xc1,0x1c,0x81,0x8f,0x1b,0xe8,0xa2,0xd8,0x41,0xe0,0xe6, +0x63,0x59,0x01,0x88,0x08,0xe9,0x91,0x82,0x28,0x15,0xe0,0xe0,0xf4,0xe0,0x08, +0x00,0x8c,0x2a,0x2d,0x0a,0x1d,0xf0,0x98,0x71,0xa8,0x91,0x88,0x07,0x30,0x3a, +0xa0,0xa0,0x66,0xc0,0x9a,0x88,0x89,0x07,0x98,0x71,0x60,0x60,0xf4,0x40,0x49, +0xa0,0x90,0x55,0xc0,0x56,0x96,0xfb,0x06,0x01,0x00,0x00,0x0c,0x12,0x1d,0xf0, +0x0c,0x02,0x1d,0xf0,0x8d,0x0e,0x88,0x08,0x82,0x28,0x10,0xe0,0x08,0x00,0xb2, +0xc1,0x18,0xa9,0x51,0xd2,0x92,0x08,0xa2,0xc1,0x14,0x40,0x9d,0x01,0xa2,0x1a, +0x00,0xa2,0x5b,0x00,0xc2,0x91,0x0c,0x90,0x9c,0x31,0x40,0xbc,0x01,0x80,0x5c, +0x01,0x50,0x5c,0x31,0xb0,0xbc,0x31,0x97,0x9b,0x21,0xc0,0xac,0x01,0x80,0xed, +0x01,0xe0,0xec,0x31,0xa0,0xac,0x31,0xa9,0x81,0xe7,0x95,0x18,0xc0,0xcd,0x01, +0xc0,0xcc,0x31,0xc0,0xca,0xc0,0x16,0x4c,0xf4,0xa9,0x81,0xc6,0x01,0x00,0xc0, +0xdc,0x01,0xd0,0xdc,0x31,0xd9,0x81,0xa8,0xb2,0x81,0x65,0x1b,0x92,0xc1,0x14, +0x82,0x28,0x00,0x92,0x19,0x00,0x82,0x28,0x0c,0x92,0x52,0x08,0xe0,0x08,0x00, +0x81,0x60,0x1b,0x3d,0xf0,0x82,0x28,0x00,0x82,0x28,0x0a,0xa2,0x22,0x0b,0xe0, +0x08,0x00,0x81,0x5b,0x1b,0x88,0x08,0xbd,0x05,0x88,0xc8,0xa2,0x22,0x0c,0xe0, +0x08,0x00,0x81,0x58,0x1b,0x88,0x08,0x58,0x81,0x88,0xa8,0xa8,0xc2,0xe0,0x08, +0x00,0x81,0x54,0x1b,0x88,0x08,0xbd,0x05,0x88,0xc8,0xa8,0xd2,0xe0,0x08,0x00, +0x81,0x51,0x1b,0x88,0x08,0x88,0xa8,0xa8,0xd2,0xe0,0x08,0x00,0xad,0x02,0xa5, +0xe1,0xff,0x06,0xb4,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0x36,0x41, +0x00,0x39,0x02,0x39,0x12,0x0c,0x08,0x2c,0x04,0x49,0x72,0x89,0x22,0x89,0x32, +0x89,0x42,0x89,0x52,0x89,0x62,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x6f, +0xe9,0x08,0x22,0x44,0x0c,0x0c,0x11,0x1c,0xfb,0x0c,0x0a,0xa0,0x00,0xf3,0x50, +0x9b,0xc0,0x6f,0xe7,0x0a,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x42, +0x6a,0x04,0x00,0xaf,0xe0,0x0a,0x22,0x42,0x6a,0x05,0x00,0xaf,0xe0,0x0a,0x22, +0x48,0x40,0x30,0x11,0xaf,0xe0,0x0a,0x22,0xe0,0xe0,0x21,0x03,0xaf,0xe0,0x0a, +0x22,0x44,0x3c,0x70,0x09,0xcf,0x21,0x74,0x43,0x44,0x0c,0x0c,0x11,0xaf,0xe0, +0x0a,0x22,0x00,0x32,0x18,0x40,0xaf,0xe0,0x0a,0x22,0xa8,0xa0,0xd8,0x01,0xaf, +0xe0,0x0a,0x22,0xdc,0xd0,0x20,0x05,0xaf,0xe0,0x0a,0x22,0x44,0x3c,0x68,0x09, +0xaf,0xe0,0x0a,0x22,0xc0,0x41,0x18,0x40,0xaf,0xe0,0x0a,0x22,0xfc,0xc0,0x21, +0x03,0xaf,0xe0,0x0a,0x22,0x44,0x3c,0x60,0x09,0xaf,0xe0,0x0a,0x22,0xc0,0x33, +0x18,0x40,0xaf,0xe0,0x0a,0x22,0xa8,0xa0,0xd8,0x01,0xaf,0xe0,0x0a,0x22,0xf8, +0xa0,0x20,0x05,0xaf,0xe0,0x0a,0x22,0x44,0x3c,0x50,0x09,0xaf,0xe0,0x0a,0x22, +0x80,0x43,0x18,0x40,0xaf,0xe0,0x0a,0x22,0xf4,0x90,0x30,0x02,0xaf,0xe0,0x0a, +0x22,0x44,0x3c,0x48,0x09,0xaf,0xe0,0x0a,0x22,0x40,0x13,0x18,0x40,0xaf,0xe0, +0x0a,0x22,0xf0,0x80,0x09,0x03,0xaf,0xe0,0x0a,0x22,0x44,0x3c,0x40,0x09,0xaf, +0xe0,0x0a,0x22,0x00,0x73,0x18,0x40,0xef,0x65,0x0c,0x62,0xa8,0x50,0xb0,0x03, +0xa8,0x52,0x6f,0xd7,0xa2,0x43,0xf0,0x40,0xa0,0x02,0x4f,0x41,0x63,0x43,0x44, +0x3c,0x20,0x09,0x88,0x42,0xef,0x25,0x05,0x62,0x00,0x23,0x18,0x40,0x0f,0x01, +0x63,0x43,0x30,0x0c,0x08,0x01,0xaa,0x88,0xef,0xe5,0x06,0x62,0xc2,0x02,0x04, +0x11,0x4f,0x01,0x28,0x48,0x44,0x0c,0x0c,0x11,0xaa,0x99,0x9a,0x77,0x8a,0x47, +0x8c,0x23,0x58,0x72,0xcc,0x35,0x3d,0x04,0x46,0x03,0x00,0x00,0x05,0x40,0x40, +0xb3,0xc0,0xb0,0xb0,0xb1,0xb0,0x33,0xc0,0x4d,0x03,0x49,0x62,0x2d,0x03,0x1d, +0xf0,0x36,0x41,0x00,0xa8,0x81,0x1c,0xf8,0xef,0xeb,0x00,0x22,0x44,0x0c,0x0c, +0x11,0xb8,0x02,0x00,0x04,0x40,0x30,0xcb,0xc0,0xc0,0xc0,0xb1,0xc0,0x4b,0xc0, +0x40,0x95,0xc0,0xef,0xf2,0x00,0x22,0x02,0x3a,0x04,0x00,0xaf,0xe0,0x0a,0x22, +0x02,0x1a,0x04,0x00,0xef,0xf4,0x02,0x22,0x48,0x20,0x18,0x01,0xaf,0xe0,0x0a, +0x22,0x02,0x1a,0x05,0x00,0xaf,0xe0,0x0a,0x22,0xa4,0x10,0x89,0x08,0xaf,0xe0, +0x0a,0x22,0xa4,0x00,0x08,0x21,0xaf,0xe0,0x0a,0x22,0x40,0x00,0x00,0x04,0x8f, +0x84,0x00,0x82,0x40,0x00,0x01,0x01,0x0c,0x0b,0x0f,0x73,0x80,0x42,0x02,0x02, +0x00,0x11,0x4f,0x01,0x28,0x48,0x44,0x0c,0x0c,0x11,0xa9,0x32,0xa8,0x42,0x57, +0xa4,0x35,0xd8,0x12,0x47,0x2d,0x47,0x0b,0x9a,0x99,0x42,0x57,0xa3,0x36,0x38, +0x52,0x0b,0x33,0x39,0x52,0x67,0x24,0x07,0x47,0x27,0x04,0x2c,0x03,0x46,0x00, +0x00,0x0c,0x13,0x39,0x72,0x49,0x12,0x1d,0xf0,0xa6,0x19,0x37,0x4f,0x01,0x28, +0x48,0x44,0x0c,0x0c,0x11,0xa0,0xa0,0x60,0x86,0xf0,0xff,0x47,0xa5,0x18,0xc8, +0x12,0x1b,0x9a,0xc7,0x24,0x24,0xc6,0xf0,0xff,0x37,0xa5,0x14,0x38,0x52,0x1b, +0x33,0x86,0xf0,0xff,0x2b,0x9a,0x06,0xed,0xff,0xa6,0x1a,0x15,0x92,0xca,0xfe, +0xc6,0xea,0xff,0x3d,0x0b,0xc6,0xeb,0xff,0xad,0x0b,0xc6,0xe4,0xff,0x92,0xca, +0xfe,0xc6,0xe6,0xff,0xd6,0xaa,0xf9,0x2b,0x9a,0xc6,0xe4,0xff,0x36,0x41,0x00, +0xef,0xe8,0x08,0x22,0x44,0x0c,0x0c,0x11,0x0c,0x09,0x90,0x00,0xf3,0xaf,0xe0, +0x0a,0x22,0x42,0x59,0x04,0x00,0xaf,0xe0,0x0a,0x22,0x48,0x20,0x28,0x01,0xaf, +0xe0,0x0a,0x22,0xe0,0x50,0x90,0x02,0xaf,0xe0,0x0a,0x22,0x44,0x0c,0x28,0x09, +0x4f,0x20,0x6c,0x43,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x00,0x02,0x00, +0x40,0xaf,0xe0,0x0a,0x22,0xa8,0x30,0x20,0x00,0xaf,0xe0,0x0a,0x22,0xd8,0x30, +0x90,0x01,0xef,0xe4,0x00,0x22,0x44,0x0c,0x18,0x09,0xaf,0xe0,0x0a,0x22,0xc2, +0x18,0x04,0x00,0xaf,0xe0,0x0a,0x22,0x80,0x21,0x00,0x40,0xaf,0xe0,0x0a,0x22, +0xc8,0x10,0x08,0x01,0xaf,0xe0,0x0a,0x22,0x44,0x0c,0x08,0x09,0xaf,0xe0,0x0a, +0x22,0x80,0x00,0x00,0x40,0x4f,0x00,0x28,0x48,0x44,0x0c,0x0c,0x11,0x1d,0xf0, +0x00,0x00,0x00,0x76,0x94,0x09,0x62,0x03,0x00,0x1b,0x33,0x62,0x45,0x00,0x1b, +0x55,0x1d,0xf0,0xb6,0x74,0xed,0x62,0x03,0x00,0x1b,0x33,0x42,0xc4,0xff,0x62, +0x45,0x00,0x52,0xc5,0x01,0x17,0x65,0x27,0xb6,0x64,0xd9,0x62,0x03,0x00,0x72, +0x03,0x01,0x2b,0x33,0x42,0xc4,0xfe,0x62,0x45,0x00,0x72,0x45,0x01,0x2b,0x55, +0x86,0x03,0x00,0x00,0x00,0x00,0x36,0x21,0x00,0x20,0x52,0x20,0x07,0xe2,0xc6, +0x17,0xe2,0xd7,0x40,0x74,0x41,0x82,0xa0,0x03,0x87,0x83,0x5a,0x76,0x97,0x15, +0x68,0x03,0x78,0x13,0x69,0x05,0x68,0x23,0x79,0x15,0x78,0x33,0x69,0x25,0x32, +0xc3,0x10,0x79,0x35,0x52,0xc5,0x10,0x37,0x64,0x0b,0x68,0x03,0x78,0x13,0x8b, +0x33,0x69,0x05,0x79,0x15,0x8b,0x55,0x27,0xe4,0x07,0x17,0xe4,0x14,0x07,0xe4, +0x21,0x1d,0xf0,0x68,0x03,0x4b,0x33,0x69,0x05,0x4b,0x55,0x17,0xe4,0x04,0x07, +0xe4,0x11,0x1d,0xf0,0x62,0x13,0x00,0x2b,0x33,0x62,0x55,0x00,0x2b,0x55,0x07, +0xe4,0x02,0x1d,0xf0,0x00,0x62,0x03,0x00,0x62,0x45,0x00,0x1d,0xf0,0x16,0xa4, +0xff,0x00,0x23,0x40,0x80,0xb3,0x10,0xb0,0x33,0xc0,0x68,0x03,0x76,0x97,0x21, +0x78,0x13,0x88,0x23,0x60,0x67,0x81,0x69,0x05,0x98,0x33,0x70,0x78,0x81,0x79, +0x15,0x68,0x43,0x80,0x89,0x81,0x89,0x25,0x32,0xc3,0x10,0x90,0x96,0x81,0x99, +0x35,0x52,0xc5,0x10,0x37,0x64,0x15,0x78,0x13,0x88,0x23,0x60,0x67,0x81,0x69, +0x05,0x8b,0x33,0x70,0x78,0x81,0x79,0x15,0x52,0xc5,0x08,0x80,0x68,0x20,0x27, +0x64,0x0c,0x78,0x13,0x4b,0x33,0x60,0x67,0x81,0x69,0x05,0x4b,0x55,0x6d,0x07, +0xba,0x33,0x17,0xe4,0x06,0x07,0xe4,0x18,0x1d,0xf0,0x00,0x00,0x62,0x03,0x00, +0x72,0x03,0x01,0x2b,0x33,0x62,0x45,0x00,0x72,0x45,0x01,0x2b,0x55,0x07,0xe4, +0x01,0x1d,0xf0,0x62,0x03,0x00,0x62,0x45,0x00,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x81,0x00,0xa2,0xc2,0x40,0xe5,0x79,0xf5,0x1c,0x0a,0x0c,0x4b,0x81,0xc5,0x19, +0xe0,0x43,0x11,0x52,0xc8,0xf0,0x92,0xc8,0xf4,0x90,0x93,0xa0,0x50,0x53,0xa0, +0x8a,0x44,0x42,0x24,0x7f,0x52,0x25,0x7f,0x82,0xc8,0xf8,0x58,0x05,0x80,0x83, +0xa0,0x48,0x04,0x32,0x29,0x7f,0x82,0x28,0x7f,0x38,0x03,0x88,0x08,0x89,0x41, +0x25,0x21,0xfa,0x0c,0x4b,0x59,0x3a,0x39,0x2a,0x88,0x41,0x49,0x0a,0x89,0x1a, +0xa2,0x62,0x12,0x0c,0x8a,0xe5,0x1f,0xfa,0x6d,0x0a,0xbd,0x04,0xc2,0x23,0x21, +0xe5,0xbd,0xf5,0x69,0x02,0x1c,0xca,0x0c,0x4b,0xa5,0x1e,0xfa,0x7d,0x0a,0xbd, +0x04,0xc2,0x23,0x10,0x61,0x60,0x19,0xd8,0xf3,0xe2,0x26,0x7f,0x65,0xb9,0xf5, +0x79,0x22,0x1c,0xca,0x0c,0x4b,0x25,0x1d,0xfa,0x7d,0x0a,0xbd,0x04,0xc2,0x23, +0x10,0xd8,0xf3,0xe2,0x26,0x7f,0xe5,0xb7,0xf5,0x79,0x32,0x3c,0x4a,0x0c,0x4b, +0xa5,0x1b,0xfa,0x7d,0x0a,0xd2,0x26,0x7f,0xb8,0xf3,0xc2,0x23,0x1f,0xb8,0x0b, +0xc8,0x2c,0xe5,0xb3,0xf5,0x79,0x42,0x3c,0x4a,0x0c,0x4b,0xe5,0x19,0xfa,0x7d, +0x0a,0xd2,0x26,0x7f,0xb8,0xf3,0xc2,0x23,0x1f,0xb8,0x0b,0xc8,0x1c,0x65,0xb2, +0xf5,0x79,0x52,0x1c,0x4a,0x0c,0x4b,0x65,0x18,0xfa,0x7d,0x0a,0xbd,0x04,0xd8, +0xc5,0xc8,0xf3,0xd8,0x0d,0x25,0x66,0xf5,0x79,0x62,0x2c,0x8a,0x0c,0x4b,0xe5, +0x16,0xfa,0xa9,0x01,0xbd,0x04,0xcd,0x03,0x71,0xdd,0x18,0xdd,0x05,0xe2,0x27, +0x12,0xe5,0x59,0xf5,0xa2,0xa0,0x94,0x1c,0x0b,0xe8,0x01,0xe9,0x72,0x25,0x15, +0xfa,0xa9,0x11,0xbd,0x04,0xcd,0x03,0xdd,0x05,0xe2,0x27,0x12,0xf2,0x26,0x7f, +0x25,0x97,0xf6,0x1c,0xca,0x0c,0x4b,0xf8,0x11,0xf9,0x82,0x65,0x13,0xfa,0xc8, +0x41,0xa9,0x21,0xbd,0x04,0xd8,0xf3,0xa5,0xa5,0xf5,0x2c,0x8a,0x0c,0x4b,0x88, +0x21,0x89,0x92,0xe5,0x11,0xfa,0xbd,0x04,0xc8,0xf3,0xd8,0xa3,0xf2,0x22,0x12, +0xe2,0x27,0x12,0xf8,0x0f,0xa9,0x31,0xf8,0x0f,0x65,0x50,0xf5,0x3c,0x4a,0x0c, +0x4b,0x88,0x31,0x89,0xa2,0xe5,0x0f,0xfa,0xbd,0x04,0xcd,0x03,0xe2,0x27,0x12, +0xdd,0x05,0x0c,0x1f,0x5d,0x0a,0x25,0x99,0xf5,0x59,0xb2,0xa2,0xa0,0x78,0x0c, +0x4b,0x65,0x0e,0xfa,0xe2,0x27,0x12,0x5d,0x0a,0xbd,0x04,0xc8,0xf3,0xd8,0x73, +0x65,0x44,0xf5,0x59,0xc2,0x2c,0x8a,0x1c,0x0b,0xe5,0x0c,0xfa,0xc2,0x26,0x7f, +0xb2,0x23,0x16,0x5d,0x0a,0xb8,0x0b,0xa5,0x59,0xf6,0x59,0x12,0x0c,0xca,0x0c, +0x4b,0xa5,0x0b,0xfa,0xc8,0x63,0xbd,0x04,0x3d,0x0a,0x65,0x40,0xf5,0x39,0xd2, +0x0c,0x8a,0x0c,0x4b,0x65,0x0a,0xfa,0xb8,0x74,0x3d,0x0a,0x65,0x3e,0xf5,0x39, +0xe2,0x0c,0x8a,0x0c,0x4b,0x65,0x09,0xfa,0x3d,0x0a,0x65,0x5e,0xf5,0x39,0xf2, +0x2c,0x4a,0x0c,0x4b,0xa5,0x08,0xfa,0xa2,0x62,0x14,0x0c,0x4b,0x3c,0x0a,0xe5, +0x07,0xfa,0xa2,0x62,0x15,0x0c,0x4b,0x0c,0x1a,0x65,0x07,0xfa,0xa2,0x62,0x16, +0x0c,0x4b,0x1c,0x0a,0xa5,0x06,0xfa,0xa2,0x62,0x17,0x0c,0x4b,0x0c,0x8a,0x25, +0x06,0xfa,0xa2,0x62,0x18,0x0c,0x4b,0x1c,0x4a,0x65,0x05,0xfa,0xa2,0x62,0x19, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x81,0x00,0x1c,0x0a,0x0c,0x4b,0xe0,0x53,0x11, +0x81,0xf6,0x18,0x0c,0x09,0x92,0x62,0x11,0x99,0xb2,0x62,0xc8,0xec,0x72,0xc8, +0xf8,0x42,0xc8,0xf0,0x40,0x43,0xa0,0x70,0x73,0xa0,0x60,0x63,0xa0,0x8a,0x55, +0x52,0x25,0x7f,0x62,0x26,0x7f,0x72,0x27,0x7f,0x42,0x24,0x7f,0x78,0x07,0x48, +0x04,0x68,0x06,0x58,0x05,0x0c,0x18,0x82,0x62,0x10,0xa5,0x00,0xfa,0xbd,0x0a, +0x69,0x3a,0x49,0x2a,0x79,0x1a,0x59,0x0a,0xa8,0x16,0xb9,0xc2,0xa2,0x9a,0x00, +0x0c,0x4b,0xa9,0x01,0x1c,0x0a,0x25,0xff,0xf9,0xa9,0x11,0xbd,0x05,0xd1,0x7e, +0x18,0xc8,0x56,0xd2,0x2d,0x12,0x65,0x9f,0xf5,0x0c,0x8a,0x0c,0x4b,0xe8,0x11, +0xe9,0x22,0x65,0xfd,0xf9,0xa9,0x21,0xbd,0x05,0xc2,0x24,0x21,0x65,0x9b,0xf5, +0x1c,0xca,0x0c,0x4b,0xf8,0x21,0xf9,0x02,0x25,0xfc,0xf9,0xa9,0x31,0xbd,0x05, +0xc2,0x24,0x10,0xe1,0xd6,0x18,0xd8,0xf4,0xe2,0x2e,0x7f,0xa5,0x96,0xf5,0x3c, +0x4a,0x0c,0x4b,0xf8,0x31,0xf9,0x42,0x65,0xfa,0xf9,0xa9,0x41,0xd1,0xd0,0x18, +0xb8,0xf4,0xc2,0x24,0x1f,0xb8,0x0b,0xc8,0x0c,0xd2,0x2d,0x7f,0xa5,0x92,0xf5, +0x1c,0x4a,0x0c,0x4b,0xc8,0x41,0xc9,0x32,0x65,0xf8,0xf9,0xa9,0x51,0xbd,0x05, +0xcd,0x04,0xdd,0x06,0x65,0x8d,0xf5,0x3c,0x8a,0x1c,0x0b,0xd8,0x51,0xd9,0x52, +0xe5,0xf6,0xf9,0xd1,0xc3,0x18,0xbd,0x03,0xc1,0x5e,0x18,0x3d,0x0a,0xc2,0x2c, +0x12,0xd2,0x2d,0x7f,0x65,0x4d,0xf6,0x39,0x72,0x1c,0xca,0x0c,0x4b,0x25,0xf5, +0xf9,0xbd,0x05,0xcd,0x07,0xd8,0xf4,0x7d,0x0a,0xa5,0x87,0xf5,0x79,0x82,0x2c, +0x8a,0x1c,0x0b,0x31,0xb8,0x18,0xe5,0xf3,0xf9,0xc2,0x23,0x7f,0xb2,0x24,0x16, +0x3d,0x0a,0xb8,0x1b,0x65,0x40,0xf6,0x39,0x12,0x3c,0x4a,0x0c,0x4b,0x71,0x4d, +0x18,0x25,0xf2,0xf9,0xe2,0x27,0x12,0x3d,0x0a,0xbd,0x05,0xcd,0x04,0xdd,0x06, +0x0c,0x0f,0x65,0x7b,0xf5,0x39,0xf2,0x0c,0xca,0x0c,0x4b,0xa5,0xf0,0xf9,0xbd, +0x05,0xc2,0x24,0x1e,0x3d,0x0a,0xe5,0x78,0xf5,0x39,0x62,0x3c,0x4a,0x0c,0x4b, +0x65,0xef,0xf9,0xa9,0xe2,0x0c,0x4b,0x0c,0x1a,0xe5,0xee,0xf9,0x38,0x01,0xa2, +0x62,0x12,0xb2,0xc2,0x4c,0xa2,0xc2,0x28,0x65,0x4d,0xf8,0xe0,0x53,0x11,0x42, +0x26,0x16,0x1c,0x4a,0x40,0x33,0xa0,0x38,0x03,0x0c,0x4b,0x4b,0x43,0xcb,0x33, +0xa5,0xec,0xf9,0xcd,0x04,0xe2,0x26,0x16,0xdd,0x03,0xea,0xe5,0xe8,0x0e,0x3d, +0x0a,0xb2,0x9e,0x00,0xe2,0x9e,0x01,0x65,0x70,0xf5,0x39,0x92,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0xa2,0xc2,0x20,0xa5,0x3f,0xf5,0xa2,0xc2,0x28,0x25,0x3f, +0xf5,0xb8,0x03,0xa2,0xc2,0x30,0xb8,0x7b,0xa5,0xdc,0xf4,0x78,0x03,0x68,0x23, +0x0c,0x4a,0x68,0xf6,0x0c,0x4b,0x68,0x06,0x65,0xe8,0xf9,0xa9,0x02,0x0c,0x4b, +0x0c,0x8a,0xe5,0xe7,0xf9,0x4d,0x0a,0x25,0x66,0xf4,0x49,0x22,0x0c,0x8a,0x0c, +0x4b,0xe5,0xe6,0xf9,0x4d,0x0a,0xe5,0x3b,0xf5,0x49,0x32,0x0c,0x8a,0x0c,0x4b, +0x25,0xe6,0xf9,0xa9,0x52,0x0c,0x4b,0x1c,0x0a,0xa5,0xe5,0xf9,0x4d,0x0a,0xa5, +0x62,0xf4,0x49,0x62,0x25,0xed,0xf9,0x4d,0x0a,0x0c,0x8a,0xbd,0x04,0xa5,0xe7, +0xf9,0xbd,0x06,0x5d,0x0a,0x65,0x62,0xf9,0x59,0x42,0x0c,0x4a,0xbd,0x04,0xa5, +0xe6,0xf9,0xbd,0x07,0xc8,0x23,0x3d,0x0a,0xc8,0xfc,0x65,0x12,0x00,0x39,0x12, +0xad,0x04,0x65,0xe4,0xf9,0x49,0x72,0x1d,0xf0,0x00,0x36,0x41,0x00,0x58,0x03, +0x48,0x23,0x0c,0x4a,0x48,0xf4,0x0c,0x4b,0x48,0x04,0xe5,0xe0,0xf9,0xbd,0x05, +0xc8,0x23,0x3d,0x0a,0xc8,0xfc,0xe5,0x0f,0x00,0x39,0x02,0x4b,0xa2,0x8b,0xb2, +0xe5,0x3e,0xf8,0x0c,0x8a,0x0c,0x4b,0x25,0xdf,0xf9,0xa9,0x42,0x0c,0x4b,0x0c, +0x8a,0xa5,0xde,0xf9,0xbd,0x04,0x3d,0x0a,0xa5,0x5c,0xf9,0x39,0x52,0xcb,0xa2, +0xb2,0xc2,0x18,0xa5,0x3c,0xf8,0xa2,0xc2,0x1c,0xb2,0xc2,0x20,0x25,0x3c,0xf8, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x8b,0xa2,0xcb,0xb2,0x91,0xa3,0x18,0xe0, +0x83,0x11,0xcb,0xc9,0xc0,0xc3,0xa0,0x9a,0x88,0x82,0x28,0x7f,0xc2,0x2c,0x7f, +0x88,0x08,0xc8,0x0c,0x88,0xf8,0xc8,0x7c,0x38,0x08,0x25,0x7a,0xf4,0x39,0x42, +0x39,0x62,0x39,0xa2,0xa2,0xc2,0x38,0xb2,0xc2,0x30,0xc2,0xc2,0x28,0xd2,0xc2, +0x20,0xe2,0xc2,0x18,0xf2,0xc2,0x10,0xf2,0x62,0x10,0xe2,0x62,0x11,0xd2,0x62, +0x12,0xc2,0x62,0x13,0xb2,0x62,0x14,0xa2,0x62,0x15,0x1d,0xf0,0x00,0x36,0x41, +0x00,0x5c,0x0a,0x0c,0x4b,0xc1,0xdf,0x17,0x39,0x02,0x91,0x8f,0x18,0xe0,0x43, +0x11,0x82,0xc9,0xf4,0x9a,0x44,0x80,0x83,0xa0,0x82,0x28,0x7f,0x42,0x24,0x7f, +0x88,0x08,0x98,0x04,0x88,0xf8,0x98,0x69,0x92,0x6c,0x1c,0x88,0x08,0x89,0x12, +0x65,0xd4,0xf9,0x5d,0x0a,0xbd,0x03,0x25,0xcf,0xff,0x59,0x32,0xa2,0xa0,0x68, +0x0c,0x4b,0x25,0xd3,0xf9,0xbd,0x03,0x5d,0x0a,0xe5,0xad,0xff,0x59,0x42,0xa1, +0x09,0x19,0x0c,0x4b,0xa9,0x22,0x4c,0xca,0xe5,0xd1,0xf9,0xbd,0x02,0x3d,0x0a, +0xd8,0x04,0xc1,0x2d,0x18,0xd8,0x6d,0xc2,0x2c,0x7f,0x25,0x75,0xf5,0x39,0x62, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x58,0x04,0x0c,0xca,0x0c,0x4b,0xa5, +0xcf,0xf9,0x4d,0x0a,0x1c,0x0b,0xa8,0x43,0xa9,0x04,0x59,0x14,0xa0,0xa5,0x82, +0xf0,0xaa,0x11,0x65,0xd0,0xf4,0xa9,0x24,0x49,0x02,0x1d,0xf0,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x91,0x9e,0xe2,0xd6 +}; diff --git a/drivers/misc/a2220_firmware_t999.h b/drivers/misc/a2220_firmware_t999.h new file mode 100644 index 00000000000..a2fe19ccf53 --- /dev/null +++ b/drivers/misc/a2220_firmware_t999.h @@ -0,0 +1,5379 @@ +/* + * + * Copyright(C) 2012 Samsung Electronics All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +/* D2 ATT eS305B Audience firmware */ +/* Version: M70.4.0.13_B10437_SEC_D2TMO_NB_WB_UART_Streaming_MCFFillIn_STREAM */ +unsigned char a2220_firmware_buf[] = { +0x41,0x55,0x44,0x49,0x45,0x4e,0x43,0x45,0x00,0x00,0x00,0x00,0x06,0x00,0x00, +0x00,0x84,0x03,0x08,0x20,0x11,0x15,0x00,0x00,0x00,0x01,0x05,0x20,0x00,0x00, +0x03,0x01,0x04,0x02,0x05,0x00,0x58,0x2d,0x18,0x20,0x00,0x00,0x00,0x00,0xd8, +0xe3,0x07,0x20,0xd3,0x75,0xb5,0xd3,0x03,0x00,0x00,0x00,0x70,0x76,0x05,0x20, +0xb0,0x5b,0x05,0x20,0x1c,0x09,0x18,0x20,0x70,0x15,0x05,0x20,0x50,0x0b,0x05, +0x20,0x37,0x00,0x00,0x00,0x10,0x96,0x19,0x20,0x54,0x97,0x19,0x20,0xb0,0x97, +0x19,0x20,0xec,0x10,0x05,0x20,0x84,0x06,0x05,0x20,0x00,0x00,0x80,0x46,0x5a, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xb0,0x1d,0x05,0x20, +0x46,0xff,0xff,0x01,0x0a,0x00,0x00,0x00,0x9f,0x0e,0x1f,0x37,0x9f,0x0e,0x1f, +0x37,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x9f,0x0e,0x1f,0x37,0x00,0x00, +0x80,0xcc,0x01,0x00,0x00,0x00,0x76,0x5e,0xf1,0x3f,0x00,0x00,0x00,0x3e,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, +0x9d,0x4a,0x87,0x3e,0x6e,0xb9,0x8d,0x30,0xed,0x19,0x2e,0x33,0x00,0x00,0x00, +0x00,0x00,0x00,0x80,0xcc,0x00,0x00,0xc0,0xc9,0x00,0x00,0x80,0x46,0x14,0x00, +0x00,0x00,0x05,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02, +0x00,0x00,0x00,0x40,0x1e,0x05,0x20,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x1e,0x05, +0x20,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x02,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x66, +0x66,0x66,0xc4,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x50,0x1e,0x05,0x20, +0x5a,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xb0,0x1d,0x05, +0x20,0x00,0x00,0x00,0x00,0x36,0x5c,0xff,0x3f,0x9e,0xef,0xff,0x3f,0x50,0x1f, +0xfa,0x3f,0x36,0x5c,0xff,0x3f,0x9e,0xef,0xff,0x3f,0x76,0x5e,0xf1,0x3f,0x03, +0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x70,0x1e,0x05,0x20,0x50,0x00,0x00,0x00, +0x02,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0xf4,0xde,0x18,0x18,0xc3,0x73,0xaf,0x23,0x70,0x12, +0xe1,0x30,0xc2,0x2a,0xb6,0x3f,0xb0,0xf4,0x02,0x40,0x1f,0x77,0x2b,0x41,0x00, +0x00,0x20,0x4d,0xc3,0x73,0xaf,0x23,0x9d,0x4a,0x87,0x3e,0x62,0xba,0xdd,0x3e, +0x62,0xba,0xdd,0x3e,0x1f,0x38,0xd3,0x40,0x06,0x93,0xfd,0x41,0xd1,0x94,0xea, +0x3d,0x00,0x00,0x00,0x3f,0x9a,0x99,0x99,0x3d,0x00,0x00,0x00,0x3e,0x00,0x00, +0x00,0x40,0x00,0x00,0x80,0x46,0x82,0x3d,0x65,0x07,0x00,0x00,0x00,0x00,0x04, +0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x33,0x00,0x00,0x00, +0xa0,0x1e,0x05,0x20,0x0b,0x00,0x17,0x00,0x0a,0x00,0x00,0x00,0xb0,0x19,0xf9, +0x3f,0xe4,0xc6,0x46,0x27,0xdc,0x31,0xaf,0x0a,0x33,0x00,0x00,0x00,0x33,0x00, +0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x80,0x46,0x33,0x33,0x33,0x37,0x00, +0x00,0xc0,0xcd,0x1f,0x38,0xd3,0x40,0xcd,0xcc,0x8c,0x44,0x00,0x00,0x80,0xca, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1f,0x00, +0x00,0x50,0x00,0x00,0x00,0x00,0x33,0x33,0x33,0x03,0x00,0x00,0x00,0x01,0x00, +0x01,0x00,0x01,0x00,0x01,0x00,0x03,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0xe0, +0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x7c,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x10,0x1f,0x05,0x20,0x03,0x00,0x00,0x00,0x20,0x1f,0x05, +0x20,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x30,0x1f,0x05,0x20,0xcd,0xcc, +0xcc,0x3e,0x84,0x27,0xfb,0x43,0x00,0x20,0x71,0x22,0x84,0x27,0xfb,0x43,0x84, +0x27,0xfb,0x43,0x00,0x20,0x54,0x76,0x84,0x27,0xfb,0x43,0x00,0x20,0x00,0x00, +0x00,0x00,0x00,0x00,0x02,0x00,0x19,0x00,0x25,0x00,0x07,0x00,0x05,0x00,0x05, +0x00,0x6c,0xa2,0x87,0x3c,0x1c,0x62,0xd8,0x3a,0x31,0x6f,0x02,0x3c,0x0f,0x07, +0x00,0x00,0x33,0x00,0x00,0x00,0x80,0x22,0x05,0x20,0x33,0x00,0x00,0x00,0xf0, +0x22,0x05,0x20,0x00,0x2d,0x97,0x28,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x1f,0x00, +0x00,0x50,0x00,0x00,0x00,0x29,0x5c,0x8f,0xb6,0x0a,0x00,0x00,0x00,0x33,0x33, +0x33,0x33,0x02,0x00,0x00,0x00,0x95,0x7a,0xe6,0x3a,0x01,0x00,0x00,0x00,0x00, +0x00,0x40,0x46,0x00,0x00,0x00,0xc4,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xc9,0x00,0x00,0x40, +0xc9,0x00,0x00,0x40,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x40,0xc9,0x00,0x00,0xd0,0xcc,0x00,0x00,0x00,0x44,0x00,0x00,0xc0,0x47, +0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x00,0x29,0x25,0x35, +0x37,0xba,0x49,0x0c,0x2a,0xba,0x49,0x0c,0x2a,0xba,0x49,0x0c,0x2a,0xba,0x49, +0x0c,0x2a,0x50,0x00,0x00,0x00,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x40,0x50, +0x00,0x00,0x00,0x95,0x7a,0xe6,0x3a,0x00,0x00,0x80,0x46,0x00,0x00,0x00,0xc2, +0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0x34,0xa5,0x30,0x31,0x08,0xa8,0xe0, +0x37,0x37,0xaf,0xf9,0x22,0x54,0x55,0x2a,0x3a,0xb6,0x9e,0xf9,0x3f,0x7f,0xf5, +0xc1,0x3f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xd0,0xcc,0x5d,0xdc,0x46,0x25,0xcb,0x8a,0x12,0x22,0x61,0x64,0x2d, +0x3f,0xcb,0x8a,0x12,0x22,0x29,0x5c,0x8f,0x32,0x7d,0x2d,0x97,0x28,0x00,0x00, +0x00,0x46,0x29,0x5c,0x8f,0x32,0x00,0x00,0x00,0x3e,0x29,0x5c,0x8f,0x32,0xf6, +0x28,0x5c,0x3b,0x7b,0x14,0xae,0x3d,0x00,0x33,0x33,0x39,0x00,0xd3,0x25,0x3d, +0x00,0x9a,0x99,0xc3,0x6f,0x12,0x83,0x41,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +0x00,0x0e,0x7f,0xfc,0x41,0x00,0xa3,0x02,0x3f,0x1d,0xb7,0xbc,0xc9,0x00,0x7f, +0xfc,0x3f,0x33,0x33,0x33,0x39,0x00,0xb9,0x8d,0x30,0x00,0xef,0xba,0x28,0x00, +0x00,0xa8,0xcc,0x00,0x00,0x00,0xcd,0x05,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x60,0x23,0x05,0x20,0x00,0x6f,0x02, +0x3c,0x0f,0x00,0x05,0x00,0x00,0x37,0x01,0x3e,0x00,0x7b,0xe6,0x3a,0x00,0x18, +0x8c,0x32,0x00,0x2c,0x89,0x3a,0x00,0x92,0x0b,0x39,0x00,0xfe,0x5a,0x11,0x33, +0x00,0x00,0x00,0x30,0x24,0x05,0x20,0x00,0xcd,0x8c,0x42,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xda,0x88,0x34,0x00,0x33,0x33,0x39,0x00,0x9c,0xcb, +0x39,0xfb,0xff,0x09,0x00,0x00,0xe5,0x27,0x45,0x0d,0x00,0x00,0x00,0x70,0x24, +0x05,0x20,0x00,0x0c,0xfa,0x34,0x04,0x00,0x00,0x00,0x90,0x24,0x05,0x20,0x08, +0x00,0x00,0x00,0xa0,0x24,0x05,0x20,0x07,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0xc0,0x24,0x05,0x20,0x00,0x00,0x00,0xcb,0x00,0xda,0x88,0x34,0x00,0x18,0x8c, +0x32,0x00,0x00,0xc0,0xcb,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x43,0x01,0x00, +0x00,0x00,0x00,0x33,0x33,0x39,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xe0, +0x24,0x05,0x20,0x04,0x00,0x00,0x00,0xf0,0x24,0x05,0x20,0x00,0x7b,0xe6,0x3a, +0x00,0x00,0x00,0xcb,0x00,0x38,0xd3,0x40,0x66,0x66,0xde,0x4a,0x08,0x03,0x18, +0x05,0x78,0x00,0x00,0x00,0x00,0x25,0x05,0x20,0x06,0x00,0x00,0x00,0x00,0x00, +0x00,0x40,0x00,0x00,0x00,0x40,0x33,0x00,0x00,0x00,0xe0,0x26,0x05,0x20,0x46, +0xff,0xff,0x01,0x00,0x00,0x00,0x06,0x33,0x33,0x33,0x39,0x03,0x00,0x00,0x00, +0x15,0x00,0x00,0x00,0xb0,0x27,0x05,0x20,0x19,0xf4,0xff,0x3f,0x91,0xd9,0x88, +0x34,0x9d,0x4a,0x87,0x3e,0x9f,0x0e,0x1f,0x37,0x00,0x00,0x00,0x40,0x5d,0xdc, +0x46,0x25,0xb1,0x16,0x9f,0x1e,0xc9,0xed,0xf3,0x49,0x01,0xcc,0xcf,0x44,0x27, +0xfe,0x11,0x40,0xe0,0xb0,0xe8,0x3f,0x7d,0x2d,0x97,0x28,0x84,0x27,0xfb,0x43, +0xcd,0xcc,0x8c,0x44,0x71,0x3d,0x0a,0x42,0x84,0x27,0xfb,0x43,0xcd,0xcc,0x8c, +0x44,0x71,0x3d,0x0a,0x42,0x84,0x27,0xfb,0x43,0xcd,0xcc,0x8c,0x44,0x71,0x3d, +0x0a,0x42,0x84,0x27,0xfb,0x43,0xcd,0xcc,0x8c,0x44,0xff,0xff,0xff,0x7f,0x00, +0x00,0xc0,0xc7,0x00,0x00,0x80,0x46,0x17,0x18,0x8c,0x32,0x66,0x92,0x0b,0x39, +0x4c,0x01,0x05,0x20,0x5c,0x01,0x05,0x20,0x8c,0x01,0x05,0x20,0xec,0x01,0x05, +0x20,0x00,0x77,0x05,0x20,0x08,0x77,0x05,0x20,0x48,0x02,0x05,0x20,0xac,0x02, +0x05,0x20,0xcc,0x02,0x05,0x20,0xdc,0x02,0x05,0x20,0x10,0x03,0x05,0x20,0x2c, +0x03,0x05,0x20,0x10,0x77,0x05,0x20,0x78,0x03,0x05,0x20,0x7c,0x03,0x05,0x20, +0x50,0x6c,0x05,0x20,0x94,0x03,0x05,0x20,0x30,0x77,0x05,0x20,0xc0,0x04,0x05, +0x20,0xd0,0x04,0x05,0x20,0xe8,0x04,0x05,0x20,0x0c,0x05,0x05,0x20,0x18,0x05, +0x05,0x20,0x34,0x6d,0x05,0x20,0xf0,0x05,0x05,0x20,0xf4,0x05,0x05,0x20,0x40, +0x77,0x05,0x20,0x00,0x06,0x05,0x20,0x08,0x06,0x05,0x20,0x14,0x06,0x05,0x20, +0x44,0x06,0x05,0x20,0x50,0x06,0x05,0x20,0x5c,0x06,0x05,0x20,0x68,0x06,0x05, +0x20,0x74,0x06,0x05,0x20,0x80,0x06,0x05,0x20,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0xee,0xff,0x00, +0x00,0x00,0x00,0x00,0x00,0xfd,0xff,0x01,0x00,0xac,0xff,0x06,0x00,0x03,0x00, +0x02,0x00,0x01,0x00,0xe6,0xff,0x04,0x00,0xa6,0xff,0x0f,0x00,0x04,0x00,0x04, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfd,0xff, +0x06,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0xe6,0xff,0x04,0x00,0xa6,0xff,0x0f, +0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00, +0xf0,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x00, +0x00,0x19,0x00,0x00,0x00,0x00,0x00,0xfa,0xff,0x00,0x00,0xac,0xff,0x01,0x00, +0x01,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x90,0x28,0x05,0x20,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x98,0x28,0x05,0x20,0x07,0x00,0x00,0x00,0xa0,0x28,0x05, +0x20,0x07,0x00,0x00,0x00,0xb0,0x28,0x05,0x20,0x07,0x00,0x00,0x00,0x10,0x28, +0x05,0x20,0x07,0x00,0x00,0x00,0xc0,0x28,0x05,0x20,0x00,0x00,0x00,0x40,0x00, +0x00,0x00,0x40,0x31,0x6f,0x02,0x3c,0x84,0x27,0xfb,0x43,0x07,0x00,0x00,0x00, +0xe0,0x28,0x05,0x20,0x07,0x00,0x00,0x00,0x30,0x28,0x05,0x20,0x00,0x00,0x00, +0x00,0xf7,0xff,0xff,0xff,0x33,0x00,0x00,0x00,0x30,0x28,0x05,0x20,0x02,0x00, +0x02,0x00,0x0e,0x00,0x00,0x00,0xf0,0x28,0x05,0x20,0x0e,0x00,0x00,0x00,0x10, +0x29,0x05,0x20,0x02,0x00,0x02,0x00,0x0e,0x00,0x00,0x00,0x30,0x29,0x05,0x20, +0x0e,0x00,0x00,0x00,0x50,0x29,0x05,0x20,0x02,0x00,0x00,0x00,0x0e,0x00,0x00, +0x00,0xf0,0x28,0x05,0x20,0x00,0x00,0x00,0x00,0x40,0x7e,0x05,0x20,0x02,0x00, +0x00,0x00,0x0e,0x00,0x00,0x00,0x30,0x29,0x05,0x20,0x00,0x00,0x00,0x00,0x40, +0x7e,0x05,0x20,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x05,0x00,0x00,0x00, +0x70,0x29,0x05,0x20,0x05,0x00,0x00,0x00,0x80,0x29,0x05,0x20,0x05,0x00,0x00, +0x00,0x90,0x29,0x05,0x20,0x05,0x00,0x00,0x00,0x10,0x28,0x05,0x20,0x05,0x00, +0x00,0x00,0x70,0x28,0x05,0x20,0x05,0x00,0x00,0x00,0x70,0x28,0x05,0x20,0x05, +0x00,0x00,0x00,0xb0,0x29,0x05,0x20,0x05,0x00,0x00,0x00,0x70,0x28,0x05,0x20, +0x1e,0x00,0x00,0x00,0xd0,0x29,0x05,0x20,0x1e,0x00,0x00,0x00,0xd0,0x29,0x05, +0x20,0x00,0x00,0x00,0x3e,0x66,0x00,0x00,0x00,0x10,0x2a,0x05,0x20,0x33,0x00, +0x00,0x00,0xb0,0x2b,0x05,0x20,0x33,0x00,0x00,0x00,0x20,0x2c,0x05,0x20,0x18, +0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xc3,0xf5,0x28,0x44,0x82,0x3d,0x65,0x07, +0xb8,0x1e,0x85,0x39,0x10,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0xf0,0x2c,0x05, +0x20,0x33,0x00,0x00,0x00,0x90,0x2e,0x05,0x20,0x33,0x00,0x00,0x00,0x00,0x2f, +0x05,0x20,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xc3,0xf5,0x28,0x44,0x82, +0x3d,0x65,0x07,0xe1,0x7a,0x14,0x3a,0x10,0x00,0x00,0x00,0x66,0x00,0x00,0x00, +0x10,0x2a,0x05,0x20,0x33,0x00,0x00,0x00,0xb0,0x2b,0x05,0x20,0x33,0x00,0x00, +0x00,0x20,0x2c,0x05,0x20,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xc3,0xf5, +0x28,0x44,0x82,0x3d,0x65,0x07,0xe1,0x7a,0x14,0x3a,0x10,0x00,0x00,0x00,0x00, +0x00,0x20,0xcd,0x30,0x00,0x00,0x00,0x00,0x00,0x20,0xcd,0x25,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x00,0x00, +0x00,0x04,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0xd0,0x2f,0x05,0x20,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x7e,0x05,0x20,0x07,0x00,0x00,0x00,0xb0, +0x28,0x05,0x20,0x07,0x00,0x00,0x00,0x70,0x28,0x05,0x20,0x07,0x00,0x00,0x00, +0x10,0x30,0x05,0x20,0x0c,0x00,0x00,0x00,0x30,0x30,0x05,0x20,0x48,0x00,0x00, +0x00,0x50,0x30,0x05,0x20,0x06,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xe0,0x30, +0x05,0x20,0x0b,0x00,0x00,0x00,0x50,0x31,0x05,0x20,0x0c,0x00,0x00,0x00,0x70, +0x31,0x05,0x20,0x48,0x00,0x00,0x00,0x90,0x31,0x05,0x20,0x06,0x00,0x00,0x00, +0x33,0x00,0x00,0x00,0xe0,0x30,0x05,0x20,0x0b,0x00,0x00,0x00,0x20,0x32,0x05, +0x20,0x07,0x00,0x00,0x00,0x40,0x32,0x05,0x20,0x07,0x00,0x00,0x00,0x50,0x32, +0x05,0x20,0x07,0x00,0x00,0x00,0x10,0x30,0x05,0x20,0x34,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x70,0x32,0x05,0x20,0x9c,0x00,0x00,0x00,0x80,0x32,0x05,0x20, +0x0b,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x32,0x00,0x00,0x00,0x04,0x00,0x0f, +0x00,0xff,0xff,0x9a,0xf9,0x9a,0xf9,0x00,0x00,0x32,0x00,0x27,0x00,0x00,0x00, +0x04,0x00,0x0f,0x00,0xff,0xff,0x9a,0xf9,0x5c,0xff,0x00,0x00,0x32,0x00,0x2e, +0x00,0x00,0x00,0x04,0x00,0x0f,0x00,0xff,0xff,0x9a,0xf9,0x5c,0xff,0x00,0x00, +0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0xff,0xff,0x00, +0x00,0x34,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0xc0,0x33,0x05,0x20,0x9c,0x00, +0x00,0x00,0xd0,0x33,0x05,0x20,0x07,0x00,0x00,0x00,0x10,0x35,0x05,0x20,0x07, +0x00,0x00,0x00,0x30,0x35,0x05,0x20,0x07,0x00,0x00,0x00,0x50,0x35,0x05,0x20, +0x12,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x70,0x35,0x05,0x20,0x02,0x00,0x00, +0x00,0x80,0x35,0x05,0x20,0x02,0x00,0x00,0x00,0x90,0x35,0x05,0x20,0x02,0x00, +0x00,0x00,0x80,0x35,0x05,0x20,0x33,0x33,0x33,0x3b,0x33,0x33,0x33,0x3f,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x3f,0x33,0x33,0x33,0x37, +0x66,0x66,0x66,0x3e,0x33,0x33,0x33,0x3b,0x66,0x66,0x66,0x3c,0x00,0x00,0x00, +0x3f,0x33,0x33,0x33,0x39,0x66,0x66,0x66,0x3e,0x33,0x33,0x33,0x3b,0x66,0x66, +0x66,0x3c,0x00,0x00,0x00,0x3f,0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xa0, +0x35,0x05,0x20,0x02,0x00,0x00,0x00,0xb0,0x35,0x05,0x20,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x40,0x7e,0x05,0x20,0x00,0x00,0x00,0x00,0x40,0x7e,0x05, +0x20,0x33,0x00,0x00,0x00,0xc0,0x35,0x05,0x20,0x1f,0x00,0x00,0x00,0x33,0x00, +0x00,0x00,0x30,0x36,0x05,0x20,0x1f,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xa0, +0x36,0x05,0x20,0x1f,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x10,0x37,0x05,0x20, +0x1f,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x80,0x37,0x05,0x20,0x1f,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x40,0x7e,0x05,0x20,0x00,0x00,0x00,0x00,0x14,0x07, +0x05,0x20,0xa0,0x07,0x05,0x20,0xf8,0x07,0x05,0x20,0x50,0x77,0x05,0x20,0x70, +0x77,0x05,0x20,0x90,0x77,0x05,0x20,0x58,0x08,0x05,0x20,0xb0,0x77,0x05,0x20, +0xd0,0x77,0x05,0x20,0xb0,0x08,0x05,0x20,0xf0,0x77,0x05,0x20,0x10,0x78,0x05, +0x20,0x30,0x78,0x05,0x20,0x7c,0x09,0x05,0x20,0x50,0x78,0x05,0x20,0xdc,0x09, +0x05,0x20,0xf4,0x09,0x05,0x20,0x70,0x78,0x05,0x20,0x44,0x0a,0x05,0x20,0x80, +0x0a,0x05,0x20,0x90,0x78,0x05,0x20,0xb0,0x78,0x05,0x20,0xd0,0x78,0x05,0x20, +0xf0,0x78,0x05,0x20,0x10,0x79,0x05,0x20,0xc8,0x00,0x00,0x00,0x02,0x00,0x00, +0x00,0x0e,0x00,0x00,0x00,0xf0,0x37,0x05,0x20,0x46,0xff,0xff,0x01,0x0a,0x00, +0x00,0x00,0x9f,0x0e,0x1f,0x37,0x9f,0x0e,0x1f,0x37,0x02,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x9f,0x0e,0x1f,0x37,0x00,0x00,0x80,0xcc,0x01,0x00,0x00,0x00, +0x7e,0xa8,0xf8,0x3f,0x00,0x00,0x00,0x3e,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x9d,0x4a,0x87,0x3e,0x6e,0xb9, +0x8d,0x30,0xed,0x19,0x2e,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xcc,0x00, +0x00,0xc0,0xc9,0x00,0x00,0x80,0x46,0x14,0x00,0x00,0x00,0x05,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x90,0x38,0x05, +0x20,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x02,0x00,0x00,0x00,0x90,0x38,0x05,0x20,0x00,0x00,0x00,0x00,0x0a, +0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x66,0x66,0x66,0xc4,0x01,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0xa0,0x38,0x05,0x20,0xc8,0x00,0x00,0x00,0x02,0x00, +0x00,0x00,0x0e,0x00,0x00,0x00,0xf0,0x37,0x05,0x20,0x00,0x00,0x00,0x00,0x18, +0xae,0xff,0x3f,0xcf,0xf7,0xff,0x3f,0x93,0x0e,0xfd,0x3f,0x18,0xae,0xff,0x3f, +0xcf,0xf7,0xff,0x3f,0x7e,0xa8,0xf8,0x3f,0x03,0x00,0x00,0x00,0x15,0x00,0x00, +0x00,0xc0,0x38,0x05,0x20,0xa0,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x25,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xf4, +0xde,0x18,0x18,0xc3,0x73,0xaf,0x23,0x70,0x12,0xe1,0x30,0xc2,0x2a,0xb6,0x3f, +0xb0,0xf4,0x02,0x40,0x1f,0x77,0x2b,0x41,0x00,0x00,0x20,0x4d,0xc3,0x73,0xaf, +0x23,0x9d,0x4a,0x87,0x3e,0x62,0xba,0xdd,0x3e,0x62,0xba,0xdd,0x3e,0x1f,0x38, +0xd3,0x40,0x06,0x93,0xfd,0x41,0xd1,0x94,0xea,0x3d,0x00,0x00,0x00,0x3f,0x9a, +0x99,0x99,0x3d,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x40,0x00,0x00,0x80,0x46, +0x82,0x3d,0x65,0x07,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0f,0x00,0x00, +0x00,0xff,0xff,0x00,0x00,0x3f,0x00,0x00,0x00,0xf0,0x38,0x05,0x20,0x17,0x00, +0x23,0x00,0x0a,0x00,0x00,0x00,0xb0,0x19,0xf9,0x3f,0xe4,0xc6,0x46,0x27,0xdc, +0x31,0xaf,0x0a,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x00,0x00,0x80,0x46,0x33,0x33,0x33,0x37,0x00,0x00,0xc0,0xcd,0x1f,0x38,0xd3, +0x40,0x66,0x66,0x26,0x45,0x00,0x00,0x80,0xca,0x00,0x00,0x00,0x00,0x0c,0x00, +0x00,0x00,0x05,0x00,0x00,0x00,0x80,0x3e,0x00,0x00,0xa0,0x00,0x00,0x00,0x00, +0x33,0x33,0x31,0x03,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, +0x03,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0x28,0x00,0x00, +0x00,0xa0,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x70,0x39, +0x05,0x20,0x03,0x00,0x00,0x00,0x80,0x39,0x05,0x20,0x03,0x00,0x00,0x00,0x02, +0x00,0x00,0x00,0x90,0x39,0x05,0x20,0xcd,0xcc,0xcc,0x3e,0x84,0x27,0xfb,0x43, +0x00,0x20,0x71,0x22,0x84,0x27,0xfb,0x43,0x84,0x27,0xfb,0x43,0x00,0x20,0x54, +0x76,0x84,0x27,0xfb,0x43,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00, +0x25,0x00,0x31,0x00,0x07,0x00,0x05,0x00,0x05,0x00,0x6c,0xa2,0x87,0x3c,0x1c, +0x62,0xd8,0x3a,0x31,0x6f,0x02,0x3c,0x0f,0x05,0x00,0x00,0x3f,0x00,0x00,0x00, +0x50,0x3d,0x05,0x20,0x3f,0x00,0x00,0x00,0xd0,0x3d,0x05,0x20,0x00,0x2d,0x97, +0x28,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x3e,0x00,0x00,0xa0,0x00,0x00,0x00,0x29, +0x5c,0x8f,0xb6,0x0a,0x00,0x00,0x00,0x33,0x33,0x33,0x31,0x02,0x00,0x00,0x00, +0x95,0x7a,0xe6,0x3a,0x01,0x00,0x00,0x00,0x00,0x00,0x40,0x46,0x00,0x00,0x00, +0xc4,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x40,0xc9,0x00,0x00,0x40,0xc9,0x00,0x00,0x40,0xc9,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xc9,0x00,0x00,0xd0, +0xcc,0x00,0x00,0x00,0x44,0x00,0x00,0xc0,0x47,0x00,0x00,0x00,0x44,0x00,0x00, +0x00,0x44,0x00,0x00,0x00,0x00,0x29,0x25,0x35,0x37,0xba,0x49,0x0c,0x28,0xba, +0x49,0x0c,0x28,0xba,0x49,0x0c,0x28,0xba,0x49,0x0c,0x28,0xa0,0x00,0x00,0x00, +0x33,0x33,0x33,0x31,0x00,0x00,0x00,0x40,0xa0,0x00,0x00,0x00,0x95,0x7a,0xe6, +0x3a,0x00,0x00,0x80,0x46,0x00,0x00,0x00,0xc2,0x19,0xf4,0xff,0x3f,0xab,0x6a, +0x75,0x3f,0xdc,0xeb,0x31,0x2f,0x56,0x2a,0xf0,0x35,0x37,0xaf,0xf9,0x22,0x54, +0x55,0x2a,0x3a,0x14,0xce,0xfc,0x3f,0xad,0x7e,0xe0,0x3f,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0xcc,0x5d,0xdc, +0x46,0x25,0xcb,0x8a,0x12,0x22,0x61,0x64,0x2d,0x3f,0xcb,0x8a,0x12,0x22,0x29, +0x5c,0x8f,0x32,0x7d,0x2d,0x97,0x28,0x00,0x00,0x00,0x46,0x29,0x5c,0x8f,0x32, +0x00,0x00,0x00,0x3e,0x29,0x5c,0x8f,0x32,0xf6,0x28,0x5c,0x3b,0x7b,0x14,0xae, +0x3d,0x00,0x33,0x33,0x39,0x00,0xd3,0x25,0x3d,0x00,0x9a,0x99,0xc3,0x6f,0x12, +0x83,0x41,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x0e,0x7f,0xfc,0x41,0x00, +0xa3,0x02,0x3f,0x1d,0xb7,0xbc,0xc9,0x00,0x7f,0xfc,0x3f,0x33,0x33,0x33,0x39, +0x00,0xb9,0x8d,0x30,0x00,0xef,0xba,0x28,0x00,0x00,0xa8,0xcc,0x00,0x00,0x00, +0xcd,0x05,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x50,0x3e,0x05,0x20,0x00,0x6f,0x02,0x3c,0x12,0x00,0x06,0x00,0x00, +0x37,0x01,0x3e,0x00,0x7b,0xe6,0x3a,0x00,0x18,0x8c,0x32,0x00,0x2c,0x89,0x3a, +0x00,0x92,0x0b,0x39,0x00,0xfe,0x5a,0x11,0x3f,0x00,0x00,0x00,0x50,0x3f,0x05, +0x20,0x00,0x66,0x26,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xda, +0x88,0x34,0x00,0x33,0x33,0x39,0x00,0x5b,0xaa,0x39,0xfb,0xff,0x09,0x00,0x00, +0xe5,0x27,0x45,0x10,0x00,0x00,0x00,0x90,0x3f,0x05,0x20,0x00,0xc8,0x53,0x34, +0x04,0x00,0x00,0x00,0xb0,0x3f,0x05,0x20,0x08,0x00,0x00,0x00,0xc0,0x3f,0x05, +0x20,0x07,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0xe0,0x3f,0x05,0x20,0x00,0x00, +0x00,0xcb,0x00,0xda,0x88,0x34,0x00,0x18,0x8c,0x32,0x00,0x00,0xc0,0xcb,0x00, +0x00,0x00,0x47,0x00,0x00,0x00,0x43,0x01,0x00,0x00,0x00,0x00,0x33,0x33,0x39, +0x05,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x40,0x05,0x20,0x05,0x00,0x00, +0x00,0x10,0x40,0x05,0x20,0x00,0x7b,0xe6,0x3a,0x00,0x00,0x00,0xcb,0x00,0x38, +0xd3,0x40,0x33,0x33,0x8b,0x4b,0x08,0x04,0x20,0x05,0xa0,0x00,0x00,0x00,0x30, +0x40,0x05,0x20,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40, +0x3f,0x00,0x00,0x00,0x70,0x42,0x05,0x20,0x46,0xff,0xff,0x01,0x00,0x00,0x00, +0x06,0x33,0x33,0x33,0x39,0x03,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x70,0x43, +0x05,0x20,0x19,0xf4,0xff,0x3f,0x91,0xd9,0x88,0x34,0x9d,0x4a,0x87,0x3e,0x9f, +0x0e,0x1f,0x37,0x00,0x00,0x00,0x40,0x5d,0xdc,0x46,0x25,0xb1,0x16,0x9f,0x1e, +0xc9,0xed,0xf3,0x49,0x01,0xcc,0xcf,0x44,0x27,0xfe,0x11,0x40,0xe0,0xb0,0xe8, +0x3f,0x7d,0x2d,0x97,0x28,0x84,0x27,0xfb,0x43,0x66,0x66,0x26,0x45,0xb8,0x1e, +0x85,0x42,0x84,0x27,0xfb,0x43,0x66,0x66,0x26,0x45,0xb8,0x1e,0x85,0x42,0x84, +0x27,0xfb,0x43,0x66,0x66,0x26,0x45,0xb8,0x1e,0x85,0x42,0x84,0x27,0xfb,0x43, +0x66,0x66,0x26,0x45,0xff,0xff,0xff,0x7f,0x00,0x00,0xc0,0xc7,0x00,0x00,0x80, +0x46,0x17,0x18,0x8c,0x32,0x66,0x92,0x0b,0x39,0xb4,0x0b,0x05,0x20,0xc4,0x0b, +0x05,0x20,0xf4,0x0b,0x05,0x20,0x54,0x0c,0x05,0x20,0x30,0x79,0x05,0x20,0x38, +0x79,0x05,0x20,0xb0,0x0c,0x05,0x20,0x14,0x0d,0x05,0x20,0x34,0x0d,0x05,0x20, +0x44,0x0d,0x05,0x20,0x78,0x0d,0x05,0x20,0x94,0x0d,0x05,0x20,0x40,0x79,0x05, +0x20,0xe0,0x0d,0x05,0x20,0xe4,0x0d,0x05,0x20,0x0c,0x73,0x05,0x20,0xfc,0x0d, +0x05,0x20,0x60,0x79,0x05,0x20,0x28,0x0f,0x05,0x20,0x38,0x0f,0x05,0x20,0x50, +0x0f,0x05,0x20,0x74,0x0f,0x05,0x20,0x80,0x0f,0x05,0x20,0xf0,0x73,0x05,0x20, +0x58,0x10,0x05,0x20,0x5c,0x10,0x05,0x20,0x70,0x79,0x05,0x20,0x68,0x10,0x05, +0x20,0x70,0x10,0x05,0x20,0x7c,0x10,0x05,0x20,0xac,0x10,0x05,0x20,0xb8,0x10, +0x05,0x20,0xc4,0x10,0x05,0x20,0xd0,0x10,0x05,0x20,0xdc,0x10,0x05,0x20,0xe8, +0x10,0x05,0x20,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x0a,0x00,0x00,0x00,0xee,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xfd, +0xff,0x01,0x00,0xac,0xff,0x06,0x00,0x02,0x00,0x02,0x00,0x01,0x00,0xe6,0xff, +0x04,0x00,0xa6,0xff,0x0f,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfd,0xff,0x06,0x00,0x01,0x00,0x02,0x00, +0x00,0x00,0xe6,0xff,0x04,0x00,0xa6,0xff,0x0f,0x00,0x04,0x00,0x04,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0xf0,0xff,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x00, +0x00,0xfa,0xff,0x00,0x00,0xac,0xff,0x01,0x00,0x01,0x00,0x02,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x40,0x44,0x05,0x20,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x48,0x44, +0x05,0x20,0x07,0x00,0x00,0x00,0x50,0x44,0x05,0x20,0x07,0x00,0x00,0x00,0x60, +0x44,0x05,0x20,0x07,0x00,0x00,0x00,0xc0,0x43,0x05,0x20,0x07,0x00,0x00,0x00, +0x70,0x44,0x05,0x20,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x31,0x6f,0x02, +0x3c,0x84,0x27,0xfb,0x43,0x07,0x00,0x00,0x00,0x90,0x44,0x05,0x20,0x07,0x00, +0x00,0x00,0xe0,0x43,0x05,0x20,0x00,0x00,0x00,0x00,0xf7,0xff,0xff,0xff,0x3f, +0x00,0x00,0x00,0xe0,0x43,0x05,0x20,0x02,0x00,0x00,0x00,0x0e,0x00,0x00,0x00, +0xa0,0x44,0x05,0x20,0x00,0x00,0x00,0x00,0x50,0x7e,0x05,0x20,0x02,0x00,0x00, +0x00,0x0e,0x00,0x00,0x00,0xc0,0x44,0x05,0x20,0x00,0x00,0x00,0x00,0x50,0x7e, +0x05,0x20,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x05,0x00,0x00,0x00,0xe0, +0x44,0x05,0x20,0x05,0x00,0x00,0x00,0xf0,0x44,0x05,0x20,0x05,0x00,0x00,0x00, +0x00,0x45,0x05,0x20,0x05,0x00,0x00,0x00,0xc0,0x43,0x05,0x20,0x05,0x00,0x00, +0x00,0x20,0x44,0x05,0x20,0x05,0x00,0x00,0x00,0x20,0x44,0x05,0x20,0x05,0x00, +0x00,0x00,0x20,0x45,0x05,0x20,0x05,0x00,0x00,0x00,0x20,0x44,0x05,0x20,0x1e, +0x00,0x00,0x00,0x40,0x45,0x05,0x20,0x1e,0x00,0x00,0x00,0x40,0x45,0x05,0x20, +0x00,0x00,0x00,0x3e,0x7e,0x00,0x00,0x00,0x80,0x45,0x05,0x20,0x3f,0x00,0x00, +0x00,0x80,0x47,0x05,0x20,0x3f,0x00,0x00,0x00,0x00,0x48,0x05,0x20,0x25,0x00, +0x00,0x00,0x25,0x00,0x00,0x00,0xe1,0x7a,0x14,0x44,0x82,0x3d,0x65,0x07,0xb8, +0x1e,0x85,0x39,0x10,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x49,0x05,0x20, +0x3f,0x00,0x00,0x00,0x00,0x4b,0x05,0x20,0x3f,0x00,0x00,0x00,0x80,0x4b,0x05, +0x20,0x25,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0xe1,0x7a,0x14,0x44,0x82,0x3d, +0x65,0x07,0x33,0x33,0x33,0x39,0x11,0x00,0x00,0x00,0x00,0x00,0x20,0xcd,0x3d, +0x00,0x00,0x00,0x00,0x00,0x20,0xcd,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x04,0x00,0x00, +0x00,0x1c,0x00,0x00,0x00,0x80,0x4c,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x50,0x7e,0x05,0x20,0x07,0x00,0x00,0x00,0xc0,0x4c,0x05,0x20,0x07, +0x00,0x00,0x00,0x20,0x44,0x05,0x20,0x07,0x00,0x00,0x00,0xd0,0x4c,0x05,0x20, +0x0c,0x00,0x00,0x00,0xf0,0x4c,0x05,0x20,0x48,0x00,0x00,0x00,0x10,0x4d,0x05, +0x20,0x06,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0xa0,0x4d,0x05,0x20,0x0b,0x00, +0x00,0x00,0x20,0x4e,0x05,0x20,0x0c,0x00,0x00,0x00,0x40,0x4e,0x05,0x20,0x48, +0x00,0x00,0x00,0x60,0x4e,0x05,0x20,0x06,0x00,0x00,0x00,0x3f,0x00,0x00,0x00, +0xa0,0x4d,0x05,0x20,0x0b,0x00,0x00,0x00,0xf0,0x4e,0x05,0x20,0x07,0x00,0x00, +0x00,0x10,0x4f,0x05,0x20,0x07,0x00,0x00,0x00,0x20,0x4f,0x05,0x20,0x07,0x00, +0x00,0x00,0xd0,0x4c,0x05,0x20,0x40,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x40, +0x4f,0x05,0x20,0x80,0x00,0x00,0x00,0x50,0x4f,0x05,0x20,0x0d,0x00,0x00,0x00, +0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,0x00,0x04,0x00,0x0f,0x00,0xff,0xff,0x9a, +0xf9,0x9a,0xf9,0x00,0x00,0x3e,0x00,0x30,0x00,0x00,0x00,0x04,0x00,0x0f,0x00, +0xff,0xff,0x9a,0xf9,0x5c,0xff,0x00,0x00,0x3e,0x00,0x3a,0x00,0x00,0x00,0x04, +0x00,0x0f,0x00,0xff,0xff,0x9a,0xf9,0x5c,0xff,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x40,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x50,0x50,0x05,0x20,0xc0,0x00,0x00,0x00,0x60,0x50, +0x05,0x20,0x07,0x00,0x00,0x00,0xe0,0x51,0x05,0x20,0x07,0x00,0x00,0x00,0x00, +0x52,0x05,0x20,0x07,0x00,0x00,0x00,0x20,0x52,0x05,0x20,0x1c,0x02,0x00,0x00, +0x02,0x00,0x00,0x00,0x40,0x52,0x05,0x20,0x02,0x00,0x00,0x00,0x50,0x52,0x05, +0x20,0x02,0x00,0x00,0x00,0x60,0x52,0x05,0x20,0x02,0x00,0x00,0x00,0x70,0x52, +0x05,0x20,0x02,0x00,0x00,0x00,0x80,0x52,0x05,0x20,0x02,0x00,0x00,0x00,0x50, +0x52,0x05,0x20,0x33,0x33,0x33,0x3b,0x33,0x33,0x33,0x3f,0x66,0x66,0x66,0x3c, +0x66,0x66,0x66,0x3c,0x00,0x00,0x00,0x3f,0x3d,0x0a,0xd7,0x39,0x66,0x66,0x66, +0x3e,0x33,0x33,0x33,0x3b,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,0x3f,0x33,0x33, +0x33,0x39,0x66,0x66,0x66,0x3e,0x33,0x33,0x33,0x3b,0x66,0x66,0x66,0x3c,0x00, +0x00,0x00,0x3f,0x33,0x33,0x33,0x39,0x66,0x66,0x66,0x3e,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x50,0x7e,0x05,0x20,0x00,0x00,0x00,0x00,0x50,0x7e,0x05,0x20,0x3f,0x00, +0x00,0x00,0x90,0x52,0x05,0x20,0x1f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x10, +0x53,0x05,0x20,0x1f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x90,0x53,0x05,0x20, +0x1f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x10,0x54,0x05,0x20,0x1f,0x00,0x00, +0x00,0x3f,0x00,0x00,0x00,0x90,0x54,0x05,0x20,0x1f,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x50,0x7e,0x05,0x20,0x00,0x00,0x00,0x00,0x7c,0x11,0x05,0x20,0x08, +0x12,0x05,0x20,0x60,0x12,0x05,0x20,0x80,0x79,0x05,0x20,0xa0,0x79,0x05,0x20, +0xc0,0x79,0x05,0x20,0x98,0x12,0x05,0x20,0xe0,0x79,0x05,0x20,0x00,0x7a,0x05, +0x20,0xf0,0x12,0x05,0x20,0x20,0x7a,0x05,0x20,0x40,0x7a,0x05,0x20,0x60,0x7a, +0x05,0x20,0x8c,0x13,0x05,0x20,0x80,0x7a,0x05,0x20,0xec,0x13,0x05,0x20,0x04, +0x14,0x05,0x20,0xa0,0x7a,0x05,0x20,0x54,0x14,0x05,0x20,0x90,0x14,0x05,0x20, +0xc0,0x7a,0x05,0x20,0xe0,0x7a,0x05,0x20,0x00,0x7b,0x05,0x20,0x20,0x7b,0x05, +0x20,0x40,0x7b,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x42,0x4f,0x53,0x4b,0x4f,0x5f,0x4c,0x41,0x42,0x45,0x4c,0x3a,0x42, +0x4f,0x53,0x4b,0x4f,0x5f,0x36,0x30,0x2e,0x30,0x32,0x2e,0x34,0x35,0x00,0x00, +0x00,0x00,0x00,0x00,0x48,0x57,0x43,0x3a,0x24,0x43,0x68,0x61,0x6e,0x67,0x65, +0x3a,0x20,0x39,0x36,0x37,0x39,0x34,0x70,0x20,0x24,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x77,0x63,0x5f,0x53,0x45,0x43,0x5f,0x44, +0x32,0x54,0x4d,0x4f,0x00,0x00,0x00,0x62,0x6e,0x6f,0x3a,0x31,0x35,0x32,0x31, +0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3e,0x08,0x20,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x30,0x38,0x08,0x20,0x68,0x3d,0x08,0x20,0xf4,0x39,0x08,0x20, +0xc0,0x38,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x40,0x08,0x20,0x3c,0x40, +0x08,0x20,0x94,0x21,0x08,0x20,0xa0,0x37,0x08,0x20,0x68,0x37,0x08,0x20,0x08, +0x37,0x08,0x20,0x00,0x00,0x00,0x00,0x30,0x22,0x08,0x20,0x18,0x22,0x08,0x20, +0xfc,0x21,0x08,0x20,0xac,0x21,0x08,0x20,0x00,0x40,0x08,0x20,0xc8,0x3f,0x08, +0x20,0x74,0x21,0x08,0x20,0x58,0x21,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x3d,0x08,0x20,0xb4,0x36,0x08,0x20,0xfc, +0x3c,0x08,0x20,0x1c,0x3d,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xd4,0x3c,0x08,0x20,0x00,0x00,0x00,0x00,0xc4,0x3b,0x08,0x20,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x98,0x38,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x44,0x22,0x08,0x20,0xc0,0x21,0x08,0x20,0x60,0x40,0x08,0x20,0x64, +0x3f,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x34,0x3f,0x08,0x20,0x44,0x3f,0x08,0x20,0xa8,0x42,0x08,0x20,0x10,0x42,0x08, +0x20,0x10,0x38,0x08,0x20,0xf0,0x37,0x08,0x20,0xd0,0x37,0x08,0x20,0x4c,0x38, +0x08,0x20,0x6c,0x38,0x08,0x20,0x30,0x3e,0x08,0x20,0x00,0x00,0x00,0x00,0x68, +0x3d,0x08,0x20,0xf4,0x39,0x08,0x20,0xc0,0x38,0x08,0x20,0x00,0x00,0x00,0x00, +0x3c,0x5d,0x05,0x20,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f, +0x00,0x44,0x5d,0x05,0x20,0x00,0x00,0x20,0x00,0x48,0x5d,0x05,0x20,0x00,0x00, +0x20,0x00,0x58,0x5d,0x05,0x20,0x00,0x00,0x03,0x00,0x58,0x5d,0x05,0x20,0x00, +0x00,0x01,0x00,0x58,0x5d,0x05,0x20,0x00,0x00,0x01,0x00,0x58,0x5d,0x05,0x20, +0x00,0x00,0x01,0x00,0x7c,0x5f,0x05,0x20,0x00,0x00,0x1f,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x1f,0x00,0x84,0x5f,0x05,0x20,0x00,0x00,0x20,0x00,0x88,0x5f, +0x05,0x20,0x00,0x00,0x20,0x00,0x98,0x5f,0x05,0x20,0x00,0x00,0x03,0x00,0x98, +0x5f,0x05,0x20,0x00,0x00,0x01,0x00,0x98,0x5f,0x05,0x20,0x00,0x00,0x01,0x00, +0x98,0x5f,0x05,0x20,0x00,0x00,0x01,0x00,0xbc,0x61,0x05,0x20,0x00,0x00,0x1f, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0xc4,0x61,0x05,0x20,0x00,0x00, +0x20,0x00,0xc8,0x61,0x05,0x20,0x00,0x00,0x20,0x00,0xd8,0x61,0x05,0x20,0x00, +0x00,0x03,0x00,0xd8,0x61,0x05,0x20,0x00,0x00,0x01,0x00,0xd8,0x61,0x05,0x20, +0x00,0x00,0x01,0x00,0xd8,0x61,0x05,0x20,0x00,0x00,0x01,0x00,0xfc,0x63,0x05, +0x20,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x04,0x64, +0x05,0x20,0x00,0x00,0x20,0x00,0x08,0x64,0x05,0x20,0x00,0x00,0x20,0x00,0x18, +0x64,0x05,0x20,0x00,0x00,0x03,0x00,0x18,0x64,0x05,0x20,0x00,0x00,0x01,0x00, +0x18,0x64,0x05,0x20,0x00,0x00,0x01,0x00,0x18,0x64,0x05,0x20,0x00,0x00,0x01, +0x00,0x00,0x5b,0x05,0x20,0x00,0x00,0x0e,0x00,0x0c,0x5b,0x05,0x20,0x00,0x00, +0x0e,0x00,0x18,0x5b,0x05,0x20,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x28,0x5b,0x05,0x20,0x00,0x00,0x0e,0x00,0x30,0x5b,0x05,0x20, +0x00,0x00,0x09,0x00,0x34,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x90,0x5b,0x05, +0x20,0x00,0x00,0x01,0x00,0x98,0x5b,0x05,0x20,0x00,0x00,0x10,0x00,0x9c,0x5b, +0x05,0x20,0x00,0x00,0x04,0x00,0xa0,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x88, +0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x24,0x5b,0x05,0x20,0x00,0x00,0x01,0x00, +0x2c,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x38,0x5b,0x05,0x20,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x5b,0x05,0x20,0x00,0x00, +0x0e,0x00,0x48,0x5b,0x05,0x20,0x00,0x00,0x09,0x00,0x4c,0x5b,0x05,0x20,0x00, +0x00,0x01,0x00,0x94,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x98,0x5b,0x05,0x20, +0x00,0x00,0x10,0x00,0x9c,0x5b,0x05,0x20,0x00,0x00,0x04,0x00,0xa0,0x5b,0x05, +0x20,0x00,0x00,0x01,0x00,0x8c,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x3c,0x5b, +0x05,0x20,0x00,0x00,0x01,0x00,0x44,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x50, +0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x80,0x5b,0x05,0x20,0x00,0x00,0x0e,0x00,0x7c,0x5b,0x05,0x20,0x00,0x00,0x01, +0x00,0x98,0x5b,0x05,0x20,0x00,0x00,0x10,0x00,0xa0,0x5b,0x05,0x20,0x00,0x00, +0x01,0x00,0x74,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x78,0x5b,0x05,0x20,0x00, +0x00,0x01,0x00,0x84,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x58,0x5b,0x05,0x20,0x00,0x00,0x0e,0x00,0x5c,0x5b,0x05, +0x20,0x00,0x00,0x04,0x00,0x90,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0xa0,0x5b, +0x05,0x20,0x00,0x00,0x01,0x00,0x88,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x54, +0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x60,0x5b,0x05,0x20,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x5b,0x05,0x20,0x00,0x00,0x0e, +0x00,0x6c,0x5b,0x05,0x20,0x00,0x00,0x04,0x00,0x94,0x5b,0x05,0x20,0x00,0x00, +0x01,0x00,0xa0,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x8c,0x5b,0x05,0x20,0x00, +0x00,0x01,0x00,0x64,0x5b,0x05,0x20,0x00,0x00,0x01,0x00,0x70,0x5b,0x05,0x20, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xa0,0x17,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xa0,0x17,0x05,0x20,0x08,0x00,0x00,0x00,0xe0,0x17,0x05,0x20,0x08, +0x00,0x00,0x00,0x20,0x18,0x05,0x20,0x08,0x00,0x00,0x00,0x60,0x18,0x05,0x20, +0x08,0x00,0x00,0x00,0xa0,0x18,0x05,0x20,0x01,0x00,0x00,0x00,0xa8,0x18,0x05, +0x20,0x01,0x00,0x00,0x00,0xc0,0x18,0x05,0x20,0x0b,0x00,0x00,0x00,0x20,0x19, +0x05,0x20,0x0b,0x00,0x00,0x00,0x80,0x19,0x05,0x20,0x07,0x00,0x00,0x00,0xb0, +0x18,0x05,0x20,0x01,0x00,0x00,0x00,0xc0,0x19,0x05,0x20,0x07,0x00,0x00,0x00, +0x00,0x1a,0x05,0x20,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, +0x05,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0x37,0x30, +0x2e,0x34,0x2e,0x30,0x2e,0x31,0x33,0x5f,0x42,0x31,0x35,0x32,0x31,0x30,0x5f, +0x53,0x45,0x43,0x5f,0x44,0x32,0x54,0x4d,0x4f,0x5f,0x4e,0x42,0x5f,0x57,0x42, +0x5f,0x55,0x41,0x52,0x54,0x5f,0x53,0x74,0x72,0x65,0x61,0x6d,0x69,0x6e,0x67, +0x5f,0x4d,0x43,0x46,0x46,0x69,0x6c,0x6c,0x49,0x6e,0x00,0x00,0x00,0x00,0x00, +0x00,0xb4,0x54,0xa8,0x3a,0xc3,0x43,0x20,0x34,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xfe,0x00,0xc0,0x00,0x01,0x00,0xff,0xff,0xff,0x00,0xc4,0x00,0x01, +0x00,0xff,0xff,0x08,0x00,0x04,0x00,0x00,0x02,0x80,0x00,0x02,0x00,0x08,0x00, +0x00,0x06,0x00,0x00,0x01,0x00,0xcc,0x00,0x00,0x01,0x7c,0x00,0x4b,0x00,0x10, +0x00,0x00,0x0f,0x20,0x00,0x4c,0x00,0x14,0x00,0x00,0x0f,0x42,0x00,0x15,0x00, +0x18,0x00,0x00,0x02,0x10,0x00,0x16,0x00,0x1c,0x00,0xc9,0xf3,0x12,0x00,0x1f, +0x00,0x20,0x00,0x00,0x02,0x64,0x00,0x20,0x00,0x24,0x00,0x00,0x02,0x36,0x00, +0x09,0x00,0x28,0x00,0x00,0x04,0x58,0x00,0x0d,0x00,0xb0,0x00,0xd8,0x00,0x40, +0x00,0x0e,0x00,0x2c,0x00,0x00,0x04,0x44,0x00,0x25,0x00,0xac,0x00,0xe2,0x1e, +0x62,0x00,0x31,0x00,0x30,0x00,0x00,0x02,0x66,0x00,0x30,0x00,0x34,0x00,0x00, +0x02,0x38,0x00,0x03,0x00,0x40,0x00,0x00,0x05,0x02,0x00,0x34,0x00,0x58,0x00, +0x80,0x7f,0x08,0x00,0x1a,0x00,0x44,0x00,0x00,0x01,0x1c,0x00,0x1b,0x00,0x5c, +0x00,0xa0,0xce,0x1e,0x00,0x23,0x00,0x48,0x00,0x00,0x01,0x04,0x00,0x2e,0x00, +0x4c,0x00,0xa6,0x00,0x06,0x00,0x21,0x00,0xc8,0x00,0x00,0x01,0x82,0x00,0x1e, +0x00,0x0c,0x00,0x01,0x07,0x22,0x00,0x04,0x00,0x3c,0x00,0x00,0x01,0x26,0x00, +0x05,0x00,0x60,0x00,0xdc,0x00,0x28,0x00,0x06,0x00,0x68,0x00,0xa6,0xe2,0x2c, +0x00,0x07,0x00,0x64,0x00,0x00,0x04,0x2a,0x00,0x00,0x01,0xd8,0x00,0x00,0x2d, +0x2e,0x00,0x26,0x00,0x6c,0x00,0x00,0x32,0x30,0x00,0x27,0x00,0x70,0x00,0x00, +0x64,0x32,0x00,0x3e,0x00,0x74,0x00,0x00,0x0f,0x34,0x00,0x28,0x00,0x38,0x00, +0x00,0x01,0x48,0x00,0x29,0x00,0x78,0x00,0xdc,0x00,0x4a,0x00,0x2a,0x00,0x80, +0x00,0xa6,0xe2,0x4e,0x00,0x2b,0x00,0x7c,0x00,0x00,0x04,0x4c,0x00,0x02,0x01, +0xdc,0x00,0x00,0x2d,0x50,0x00,0x2c,0x00,0x84,0x00,0x00,0x32,0x52,0x00,0x2d, +0x00,0x88,0x00,0x00,0x32,0x54,0x00,0x3f,0x00,0x8c,0x00,0x00,0x0f,0x56,0x00, +0x41,0x00,0x90,0x00,0xa6,0x1e,0x14,0x00,0x42,0x00,0x94,0x00,0xd8,0x00,0x16, +0x00,0x44,0x00,0x98,0x00,0xa6,0x1e,0x18,0x00,0x39,0x00,0x9c,0x00,0x01,0x02, +0x24,0x00,0x12,0x00,0xa0,0x00,0xa6,0x28,0x3c,0x00,0x14,0x00,0xd0,0x00,0x00, +0x01,0x7e,0x00,0x43,0x00,0xa4,0x00,0x01,0x02,0x46,0x00,0x3d,0x00,0xa8,0x00, +0x00,0x0f,0x5e,0x00,0x40,0x00,0xb4,0x00,0xd8,0x00,0x1a,0x00,0x19,0x00,0xb8, +0x00,0xa6,0x1e,0x3e,0x00,0x3c,0x00,0xd4,0x00,0x80,0x7f,0x88,0x00,0x3a,0x00, +0xbc,0x00,0x00,0x01,0x3a,0x00,0x47,0x00,0xe0,0x00,0xe7,0x32,0x86,0x00,0x56, +0x00,0xe4,0x00,0x00,0x06,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x2c,0x01,0x05,0x20,0x28,0x01,0x05,0x20,0x44,0x01,0x05,0x20,0x40,0x01,0x05, +0x20,0x88,0x85,0x17,0x20,0x8c,0x85,0x17,0x20,0x88,0x85,0x17,0x20,0x8c,0x85, +0x17,0x20,0x30,0x85,0x17,0x20,0x34,0x85,0x17,0x20,0x30,0x85,0x17,0x20,0x34, +0x85,0x17,0x20,0x43,0x6f,0x6d,0x62,0x6f,0x53,0x45,0x43,0x44,0x32,0x54,0x4d, +0x4f,0x00,0x00,0x00,0x41,0x4c,0x47,0x4f,0x5f,0x4c,0x41,0x42,0x45,0x4c,0x3a, +0x20,0x6a,0x75,0x72,0x61,0x5f,0x37,0x30,0x2e,0x34,0x2e,0x30,0x5f,0x4d,0x61, +0x74,0x5f,0x63,0x31,0x31,0x5f,0x44,0x32,0x30,0x30,0x5f,0x63,0x31,0x33,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x30,0xe3,0xc6,0xa4,0x09,0x57,0x1d, +0xa4,0x89,0x7b,0x97,0x09,0x48,0x00,0x40,0xd5,0xd8,0x0e,0x06,0x87,0x3b,0xc5, +0x82,0x5e,0xb7,0x62,0x55,0x00,0x40,0xae,0xde,0xb5,0x81,0x79,0x3e,0x56,0x01, +0xfc,0xbc,0xc3,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xff,0xff,0x01,0x46, +0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01, +0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff, +0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0a,0x00,0x00, +0x00,0x65,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80, +0x00,0x00,0x00,0x00,0x00,0x40,0x9a,0x00,0x9e,0x14,0x00,0x00,0x00,0x00,0x00, +0x00,0x5f,0x05,0x00,0x40,0x74,0xcb,0xa7,0x0f,0xa9,0x1b,0x7b,0x8c,0x74,0xa6, +0x52,0x52,0x00,0x40,0xf6,0xde,0xd4,0x00,0xef,0x3d,0xd2,0x80,0xbf,0xbe,0x5f, +0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0xed,0x29,0xee,0x81,0xef,0x54,0xf0, +0xea,0xf0,0x7d,0xf1,0x0a,0xf2,0x91,0xf2,0x16,0xf3,0x96,0xf3,0x13,0xf4,0x8c, +0xf4,0x00,0xf5,0x70,0xf5,0xdb,0xf5,0x43,0xf6,0xa6,0xf6,0x06,0xf7,0x62,0xf7, +0xbd,0xf7,0x13,0xf8,0x63,0xf8,0xb2,0xf8,0x01,0xf9,0x48,0xf9,0x8f,0xf9,0xcf, +0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9, +0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed, +0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9, +0xed,0xf9,0xed,0xf9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05, +0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x14,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x66,0x66,0x66,0x3f,0xcd,0xcc,0xcc,0x3f,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x0a,0xb1,0xe7,0xb1,0xe7,0xb1,0xc5,0xb2,0x69,0xb5,0x4e,0xb6,0x1d, +0xb8,0xe0,0xba,0xd0,0xbb,0xc1,0xbc,0x4d,0xc0,0xca,0xc0,0x48,0xc2,0xc9,0xc2, +0xd7,0xc4,0xd7,0xc4,0x5e,0xc5,0x0c,0xc8,0x98,0xc8,0xb4,0xc9,0x44,0xca,0xfa, +0xcb,0x8e,0xcc,0x51,0xce,0x58,0xd1,0xf6,0xd1,0xf6,0xd1,0xd9,0xd3,0xc7,0xd5, +0x6e,0xd6,0x6c,0xd8,0x25,0xdb,0xc1,0xd7,0x3e,0xdd,0x63,0xdf,0x95,0xe1,0x95, +0xe1,0x97,0xe4,0xd4,0xe3,0x97,0xe4,0x7a,0xe8,0x46,0xe9,0x84,0xec,0x2d,0xee, +0x2d,0xee,0x4e,0xf3,0xb6,0xf0,0x58,0xed,0x13,0xea,0xd9,0xe0,0xd7,0xdb,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00, +0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd5,0xac, +0xaa,0xad,0x0a,0xb1,0x0a,0xb1,0xc5,0xb2,0xa4,0xb3,0x4e,0xb6,0x69,0xb5,0x34, +0xb7,0xf3,0xb9,0xe0,0xba,0xd0,0xbb,0xb4,0xbd,0x4d,0xc0,0x4d,0xc0,0x48,0xc1, +0xc7,0xc1,0x4b,0xc3,0x52,0xc4,0xd7,0xc4,0xe5,0xc5,0x6d,0xc6,0x98,0xc8,0xb4, +0xc9,0xb4,0xc9,0xd5,0xca,0x67,0xcb,0x8e,0xcc,0xb9,0xcd,0xe9,0xce,0xf6,0xd1, +0x83,0xcf,0x58,0xd1,0x96,0xd2,0x21,0xd5,0x37,0xd3,0xc7,0xd5,0xc7,0xd5,0x17, +0xd7,0x21,0xd5,0xc1,0xd7,0xc6,0xd9,0x75,0xda,0xc6,0xd9,0x8a,0xdc,0x8a,0xdc, +0x8a,0xdc,0x75,0xda,0x6e,0xd6,0x17,0xd7,0x96,0xd2,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x77,0x35,0x9b,0x3f,0x8e,0x69, +0xee,0x3e,0x00,0x00,0x00,0x00,0x27,0xfe,0x11,0x40,0xbe,0xed,0x05,0x40,0x27, +0xfe,0x11,0x40,0x00,0x00,0x00,0x00,0xe9,0x8e,0x83,0x8f,0xba,0x90,0xf6,0x91, +0x21,0x95,0xc1,0x97,0x6c,0x98,0xd7,0x9b,0x8a,0x9c,0x1d,0xa0,0x54,0xa2,0x97, +0xa4,0x21,0xa6,0x21,0xa6,0xb2,0xab,0x84,0xac,0xdc,0xaf,0x11,0xb5,0xf5,0xb5, +0x85,0xba,0x64,0xbc,0x1c,0xc0,0x99,0xc0,0x1f,0xc4,0x4b,0xc7,0x62,0xc8,0xd6, +0xc7,0x7f,0xcd,0x48,0xcf,0xe2,0xcf,0xf9,0xd2,0x3d,0xd4,0x2e,0xd6,0x83,0xd9, +0x44,0xdc,0x4c,0xe1,0xc9,0xe2,0x9b,0xe6,0x4c,0xe4,0x2c,0xe8,0x62,0xeb,0x06, +0xed,0xda,0xed,0x82,0xf6,0x9d,0xf5,0x07,0xfc,0x07,0xfc,0x9d,0xf5,0x92,0xea, +0xad,0xdd,0x2e,0xd6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3, +0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a, +0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0x0c,0x93,0xab, +0x9c,0x0d,0xa4,0xd9,0xaa,0xed,0xb2,0x86,0xbc,0xf7,0xc3,0xbf,0xca,0xce,0xd2, +0x62,0xdc,0xe2,0xe3,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xe2, +0xe3,0x62,0xdc,0xce,0xd2,0xbf,0xca,0xce,0xd2,0x62,0xdc,0xe2,0xe3,0xa5,0xea, +0xce,0xd2,0x86,0xbc,0x0d,0xa4,0xf3,0x8a,0x2b,0x73,0xf5,0x5c,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00, +0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00, +0x00,0x00,0x04,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x8e,0x69, +0xee,0x3e,0x8e,0x69,0xee,0x3e,0x8e,0x69,0xee,0x3e,0x00,0x00,0x00,0x00,0x27, +0xfe,0x11,0x40,0x27,0xfe,0x11,0x40,0x27,0xfe,0x11,0x40,0x00,0x00,0x00,0x00, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x3e,0x33,0x33,0x33,0x3b, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00, +0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc6,0x97,0x3b,0x9c,0x18,0xa2, +0x31,0xa6,0x20,0xab,0x68,0xb0,0x91,0xb3,0x13,0xb7,0xfb,0xba,0x4a,0xbf,0xff, +0xc1,0x89,0xc4,0x41,0xc7,0x26,0xca,0x35,0xcd,0x36,0xd0,0xe4,0xd1,0xa4,0xd3, +0x73,0xd5,0x5d,0xd7,0x51,0xd9,0x3d,0xdb,0x44,0xdd,0x68,0xdf,0xba,0xe0,0xcd, +0xe1,0xd1,0xe2,0xe0,0xe3,0xf0,0xe4,0x00,0xe6,0x08,0xe7,0x0c,0xe8,0x0d,0xe9, +0x08,0xea,0xef,0xea,0xdd,0xeb,0xc9,0xec,0xa3,0xed,0x7a,0xee,0x2e,0xef,0xad, +0xef,0x09,0xf0,0x50,0xf0,0xa0,0xf0,0xeb,0xf0,0x45,0xf1,0x9d,0xf1,0xa5,0xf1, +0x01,0xf2,0x0a,0xf2,0xfd,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xd6,0xf8,0x85,0xf1,0x95,0xe7,0xf1,0xde,0x81,0xd6,0x9f,0xce,0x81,0xc7, +0x91,0xc0,0xc1,0xb9,0x71,0xb3,0xd5,0xad,0x9a,0xa8,0xfe,0xa2,0x69,0x9e,0xad, +0x99,0x4b,0x95,0x52,0x91,0x51,0x8d,0xb3,0x89,0x41,0x86,0xae,0x82,0x35,0x80, +0xad,0x7c,0xd5,0x79,0xaa,0x77,0x85,0x74,0x41,0x72,0x6c,0x70,0xf6,0x6d,0xaf, +0x6b,0xe7,0x69,0x7b,0x68,0xa2,0x66,0xbf,0x64,0x47,0x63,0xfb,0x61,0xe0,0x60, +0xfb,0x5f,0x75,0x5e,0x51,0x5d,0x94,0x5c,0x08,0x5c,0x4f,0x5b,0x91,0x5a,0xeb, +0x59,0x37,0x59,0x95,0x58,0x86,0x58,0xdc,0x57,0xbf,0x57,0xe9,0x57,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe1,0x3f,0x3a,0x00,0x26,0x46, +0x3a,0x00,0x8e,0x4c,0x3a,0x00,0x1a,0x53,0x3a,0x00,0xcd,0x59,0x3a,0x00,0xa6, +0x60,0x3a,0x00,0xa7,0x67,0x3a,0x00,0xd2,0x6e,0x3a,0x00,0x28,0x76,0x3a,0x00, +0xab,0x7d,0x3a,0x00,0x5c,0x85,0x3a,0x00,0x3d,0x8d,0x3a,0x00,0x50,0x95,0x3a, +0x00,0x97,0x9d,0x3a,0x00,0x12,0xa6,0x3a,0x00,0xc6,0xae,0x3a,0x00,0xb3,0xb7, +0x3a,0x00,0xdc,0xc0,0x3a,0x00,0x44,0xca,0x3a,0x00,0xec,0xd3,0x3a,0x00,0xd8, +0xdd,0x3a,0x00,0x0b,0xe8,0x3a,0x00,0x86,0xf2,0x3a,0x00,0x4e,0xfd,0x3a,0x00, +0x66,0x08,0x3b,0x00,0xd1,0x13,0x3b,0x00,0x93,0x1f,0x3b,0x00,0xaf,0x2b,0x3b, +0x00,0x2b,0x38,0x3b,0x00,0x09,0x45,0x3b,0x00,0x50,0x52,0x3b,0x00,0x04,0x60, +0x3b,0x00,0x2a,0x6e,0x3b,0x00,0xc8,0x7c,0x3b,0x00,0xe4,0x8b,0x3b,0x00,0x84, +0x9b,0x3b,0x00,0xb0,0xab,0x3b,0x00,0x6e,0xbc,0x3b,0x00,0xc6,0xcd,0x3b,0x00, +0xc1,0xdf,0x3b,0x00,0x69,0xf2,0x3b,0x00,0xe3,0x02,0x3c,0x00,0xf1,0x0c,0x3c, +0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17, +0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65, +0x17,0x3c,0x00,0x00,0x00,0x00,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77, +0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x74,0x72,0x6f, +0x6d,0x6a,0x68,0x65,0x63,0x60,0x5e,0x5b,0x59,0x59,0x59,0x59,0x59,0x5b,0x5e, +0x60,0x63,0x60,0x5e,0x5b,0x59,0x60,0x68,0x6f,0x77,0x7e,0x86,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x0f,0x00,0x0f, +0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xad, +0x3c,0x00,0x00,0xc0,0x47,0x00,0x00,0x80,0x44,0x00,0xa3,0x02,0x43,0x00,0x00, +0x00,0xc7,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x00, +0x00,0x00,0x47,0x00,0x00,0x40,0x48,0x00,0x00,0x00,0x49,0x00,0x00,0x40,0x4a, +0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa, +0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x38,0x00,0x00, +0x00,0x00,0x09,0x12,0x12,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xe4,0x38,0x8e,0x39,0xe4,0x38,0x8e,0x37,0xe4,0x38,0x8e,0x37, +0xab,0xaa,0xaa,0x3a,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xa0,0xfa,0xfa,0xf4, +0xf4,0xf4,0xe8,0xe8,0xa0,0xfa,0xfa,0xfa,0xf4,0xe8,0xd0,0xa0,0xa0,0xf4,0xf4, +0xf4,0xf4,0xf4,0xe8,0xc4,0xa0,0xf4,0xf4,0xe8,0xdc,0xd0,0xb8,0xb8,0xa0,0xe8, +0xe8,0xe8,0xe8,0xd0,0xb8,0xa0,0xa0,0xe8,0xe8,0xe8,0xdc,0xdc,0xd0,0xb8,0xa0, +0xe8,0xdc,0xdc,0xc4,0xa0,0xa0,0xa0,0xa0,0xdc,0xdc,0xdc,0xdc,0xb8,0xa0,0xa0, +0xa0,0xdc,0xdc,0xdc,0xd0,0xc4,0xb8,0xa0,0xa0,0xd0,0xd0,0xd0,0xb8,0xa0,0xa0, +0xa0,0xa0,0xd0,0xd0,0xd0,0xc4,0xa0,0xa0,0xa0,0xa0,0xd0,0xd0,0xd0,0xc4,0xb8, +0xa0,0xa0,0xa0,0xc4,0xc4,0xc4,0xa0,0xa0,0xa0,0xa0,0xa0,0xc4,0xc4,0xc4,0xb8, +0xa0,0xa0,0xa0,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xdc,0x31,0xaf, +0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31, +0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc, +0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a, +0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf, +0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31, +0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0x86,0xbb,0x30,0x0b,0x3c,0xb0,0xca,0x0b,0x2a, +0xd5,0x40,0x0c,0x21,0x91,0xad,0x0c,0x3d,0xcc,0x2e,0x0d,0x96,0x63,0xc8,0x0d, +0x5c,0x77,0x3f,0x0e,0x63,0xf1,0xab,0x0e,0x20,0xde,0x2c,0x0f,0x55,0x18,0xc6, +0x0f,0x62,0x1a,0x3e,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52, +0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0x62,0x1a,0x3e,0x10,0x55, +0x18,0xc6,0x0f,0x20,0xde,0x2c,0x0f,0x63,0xf1,0xab,0x0e,0x20,0xde,0x2c,0x0f, +0x55,0x18,0xc6,0x0f,0x62,0x1a,0x3e,0x10,0xa0,0x52,0xaa,0x10,0x20,0xde,0x2c, +0x0f,0x96,0x63,0xc8,0x0d,0x2a,0xd5,0x40,0x0c,0xdc,0x31,0xaf,0x0a,0xfc,0xab, +0x32,0x09,0xba,0x4d,0xcf,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0xcd, +0x13,0xd4,0x40,0x00,0x00,0x00,0x40,0xcd,0x13,0xd4,0x3e,0x00,0x00,0x00,0x3e, +0xcd,0x13,0xd4,0x3c,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0xbd,0xe2,0xd7, +0xe1,0x7f,0xe0,0xb1,0xde,0x59,0xdc,0x0d,0xda,0xda,0xd7,0xbb,0xd5,0xaa,0xd3, +0xa6,0xd1,0xb3,0xcf,0xd1,0xcd,0x01,0xcc,0x41,0xca,0x93,0xc8,0xf5,0xc6,0x66, +0xc5,0xe7,0xc3,0x77,0xc2,0x0d,0xc1,0x68,0xbf,0xeb,0xbc,0x71,0xba,0xfa,0xb7, +0xbf,0xb5,0x86,0xb3,0x86,0xb1,0x87,0xaf,0x9d,0xad,0xc7,0xab,0x0f,0xaa,0x6f, +0xa8,0xe0,0xa6,0x69,0xa5,0x19,0xa4,0xc9,0xa2,0x84,0xa1,0x5f,0xa0,0x8d,0x9e, +0xbf,0x9c,0x7e,0x9b,0x82,0x9a,0x23,0x99,0xa0,0x97,0x37,0x96,0x91,0x94,0xf8, +0x92,0xd2,0x92,0x31,0x91,0x08,0x91,0x43,0x91,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0x3b,0x72,0x55, +0x3f,0x76,0x5d,0x24,0x3f,0x29,0x57,0xe7,0x3e,0xfe,0xdf,0x98,0x3e,0x00,0x00, +0x00,0x00,0x6e,0x3a,0xc3,0xd7,0x35,0x85,0x57,0x35,0xf5,0x04,0x58,0xb5,0x69, +0x5a,0x00,0x40,0xe5,0xdd,0x78,0x84,0x11,0x3c,0x32,0x04,0x04,0xb8,0xbe,0x5b, +0x00,0x40,0xfe,0xde,0x7b,0x81,0x43,0x3e,0x34,0x01,0xf4,0xbc,0x33,0x5e,0x00, +0x00,0x00,0x00,0x00,0x00,0x43,0x46,0x47,0x3a,0x20,0x4e,0x42,0x5f,0x53,0x45, +0x43,0x5f,0x44,0x32,0x5f,0x41,0x54,0x54,0x20,0x4d,0x43,0x46,0x5f,0x43,0x4c, +0x3a,0x20,0x39,0x36,0x30,0x34,0x37,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f, +0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c, +0x8f,0x36,0x29,0x5c,0x8f,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x00,0x01,0x00,0xff,0xff,0xff,0x01, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x33,0x33,0x33, +0xb9,0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x33,0x33, +0x33,0xb9,0x00,0x00,0x00,0x00,0x02,0x02,0x01,0x01,0x01,0x02,0x02,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x39,0x85,0xd5,0x24,0x88,0xf3,0x31, +0x7a,0x07,0xde,0xaf,0x40,0x57,0x00,0x40,0xc0,0xdd,0x1d,0x84,0x45,0x3c,0x59, +0x03,0xc1,0xb8,0xa3,0x5b,0x00,0x00,0x00,0x00,0xcd,0x3c,0x95,0xda,0x59,0x84, +0x8b,0x38,0x2a,0x04,0x5a,0xb7,0x7e,0x5b,0x00,0x40,0xf5,0xde,0xfe,0x81,0x1b, +0x3e,0xcc,0x01,0x44,0xbc,0xf1,0x5d,0x00,0x00,0x00,0x00,0x5e,0x2a,0x77,0xbb, +0x0c,0x96,0x8d,0x17,0x98,0x0f,0xc6,0x93,0x7d,0x42,0x00,0x40,0xa1,0xd3,0x23, +0x93,0x77,0x32,0xef,0x07,0xca,0xa7,0x1f,0x4a,0x00,0x00,0x00,0x00,0x1d,0x34, +0x69,0xcc,0x48,0x8e,0xf4,0x26,0x0a,0x0c,0xc1,0xa3,0x7d,0x4f,0x00,0x40,0xe6, +0xda,0xb7,0x88,0xc5,0x38,0xbe,0x05,0x5b,0xb2,0x64,0x56,0x00,0x00,0x00,0x00, +0x2e,0x00,0x22,0x00,0x16,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x05,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0a,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x33,0x33,0x33,0x3b,0x33,0x33,0x33,0x3b,0x33,0x33,0x33,0x3b,0x33, +0x33,0x33,0x3b,0x33,0x33,0x33,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x00,0xb0,0x00,0xc4,0x00,0xd8,0x00, +0xec,0x00,0x00,0x00,0xa0,0x00,0xb0,0x00,0xc4,0x00,0xd8,0x00,0xec,0x00,0x00, +0x00,0xa0,0x00,0xb0,0x00,0xc4,0x00,0xd8,0x00,0xec,0x00,0x00,0x00,0xa0,0x00, +0xb0,0x00,0xc4,0x00,0xd8,0x00,0xec,0x00,0x00,0x00,0xa0,0x00,0xb0,0x00,0xc4, +0x00,0xd8,0x00,0xec,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x5c,0xf0,0xb1,0x13, +0xbd,0x3f,0xb0,0x94,0xec,0x11,0xb2,0x25,0x9c,0x22,0xb3,0x15,0xc5,0x81,0xb0, +0xce,0x0b,0xf1,0xb0,0x5a,0xa6,0x71,0x2c,0x12,0x77,0x0b,0xb6,0x98,0x7c,0xc0, +0x34,0xbe,0xed,0x45,0xb5,0xec,0x2f,0x9f,0x33,0x8a,0xc8,0xf8,0xb3,0x60,0xd4, +0xda,0x31,0x71,0x1f,0xa4,0xb3,0xaa,0x63,0x00,0xad,0x79,0xfc,0x6a,0xb6,0x4c, +0xc2,0x35,0x36,0x10,0xe1,0xd0,0xb5,0x74,0x70,0x86,0x36,0xda,0x94,0x43,0xb1, +0x3e,0x7c,0x00,0x37,0x0f,0x5f,0x2f,0x32,0xe1,0x2f,0x55,0x37,0x28,0xc2,0x5e, +0x35,0xa1,0xfb,0xff,0x36,0x3e,0x56,0x55,0x36,0xa1,0xf4,0x9d,0x35,0x26,0x53, +0xca,0x36,0xf6,0x41,0x4a,0x36,0xc1,0x38,0xc1,0x36,0x59,0xaa,0xa3,0x36,0xdd, +0x67,0x38,0x38,0xe8,0xd9,0x51,0xb0,0x48,0x0b,0x39,0x39,0xbe,0x93,0x1a,0xb5, +0xc3,0xd8,0x5e,0x39,0x7c,0xbd,0x18,0xb8,0x94,0x77,0x5f,0x39,0x24,0x00,0x06, +0xb9,0xbb,0x38,0x06,0x38,0x5c,0x59,0xd8,0xb8,0x50,0x0a,0x6f,0x37,0x5a,0x40, +0x1d,0xba,0xa9,0x77,0xfe,0x36,0xd8,0x75,0x71,0xba,0x96,0x8f,0xa9,0xb5,0xf4, +0x73,0xa6,0xb9,0x3b,0x30,0x1d,0xb8,0xd1,0x7a,0x67,0xb8,0xcf,0x58,0x5c,0xb7, +0x96,0x71,0x16,0xb8,0x54,0xe1,0xeb,0xb7,0xec,0x5a,0x69,0xb7,0x93,0x89,0x87, +0xb6,0x44,0xb2,0x55,0xb8,0x31,0x49,0xa1,0xb6,0x21,0x88,0xc2,0xb8,0x6c,0xa8, +0x60,0xb8,0x82,0xa7,0x0a,0xb8,0xac,0xfb,0x4d,0xb9,0x7b,0x39,0xcf,0xb3,0x1d, +0xbf,0xa9,0xb9,0x1d,0xeb,0xc3,0x32,0x0a,0xfd,0x12,0xb9,0x75,0x8e,0x8e,0x33, +0x3a,0x3d,0x84,0xb8,0xba,0x32,0xf1,0x2e,0xa1,0xc2,0xbf,0xb6,0x2d,0x5a,0x99, +0xb5,0xb9,0x69,0xdd,0xb6,0x2f,0x9e,0xdb,0xb6,0x0b,0xf3,0x60,0xb8,0x14,0x4f, +0xb6,0xb5,0x1f,0x5f,0xa8,0xb9,0xd1,0x5f,0x5d,0xac,0x6a,0xd5,0x41,0xba,0x1f, +0xcc,0x7f,0x36,0x13,0xf9,0x4f,0xba,0xb8,0x24,0x7c,0x38,0x48,0x07,0x22,0xba, +0x1a,0x5f,0xee,0x38,0xb9,0x49,0x21,0xb9,0x38,0xaf,0x36,0x39,0x94,0x38,0x6b, +0xb8,0x54,0x56,0x08,0x39,0x5e,0x6a,0x3b,0xb7,0x80,0x80,0x45,0x38,0xcb,0x2f, +0x49,0xb6,0x66,0x49,0x3f,0x38,0xf9,0xcf,0x3e,0xb7,0x03,0x76,0x4a,0x38,0x98, +0x5e,0x57,0xb6,0xa0,0x04,0x74,0x37,0xb2,0xb0,0xcf,0xb6,0xf3,0xf6,0xcd,0x37, +0x7d,0xfe,0x88,0xb7,0xd1,0x76,0x11,0x38,0x43,0x96,0x7e,0xb8,0x55,0xb3,0xc7, +0x38,0x90,0x9a,0x84,0xb8,0xc5,0x0e,0xc9,0x38,0x63,0x5e,0x30,0xb8,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0xfd,0xf9,0xfa,0x98,0xfb,0x9f,0xf7,0xe1, +0xf0,0x78,0xf0,0x0a,0xf3,0x33,0xf8,0x82,0xee,0x0e,0xdd,0xab,0x5e,0x89,0x69, +0x78,0x6d,0x24,0x72,0xf0,0x70,0x8a,0x72,0x3b,0x78,0x27,0x79,0xd5,0x7a,0xff, +0x7c,0x3c,0x7d,0x44,0x7e,0x0f,0xff,0x54,0xfd,0xe5,0xfc,0x29,0xfc,0xc0,0xfc, +0x63,0xfd,0x61,0xfc,0xd2,0xfa,0xa9,0xf8,0xdc,0xf6,0x38,0xf6,0x52,0xf7,0xdb, +0xfa,0xc1,0xfa,0x44,0xf9,0x0b,0xf8,0x50,0xf5,0xa1,0xf2,0x56,0xf0,0x25,0xed, +0xf9,0xe9,0x7f,0xe9,0xbe,0xec,0xa0,0xe9,0xeb,0xed,0x41,0xef,0xf3,0xf0,0xfe, +0xee,0x92,0xed,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x55, +0x92,0x24,0x94,0x52,0x87,0x27,0xbf,0x00,0xbc,0x23,0x00,0xef,0x17,0x2c,0x3f, +0x2b,0x49,0x2c,0x8f,0x92,0x9c,0x29,0xe4,0x1e,0x1f,0x28,0x43,0x74,0xed,0x2c, +0x1c,0x90,0x21,0x2e,0x86,0x7c,0x45,0x2d,0x6c,0xd3,0x53,0x2e,0x08,0x98,0x7c, +0x2f,0x49,0x6c,0x9c,0x2f,0x16,0xa0,0xc3,0x2e,0xeb,0x52,0x35,0x2f,0x00,0xf0, +0x55,0x31,0xd3,0x16,0x9a,0x32,0x01,0x97,0xfd,0x32,0x5d,0x70,0xf1,0x33,0x9f, +0x4b,0x4f,0x33,0x94,0xb5,0xc2,0x32,0x0a,0xe3,0x83,0x34,0xa9,0xe3,0x16,0x35, +0xe6,0x60,0x39,0x34,0x21,0xa6,0x26,0x32,0x7b,0xf9,0x0c,0x32,0xbe,0x2c,0x41, +0x30,0xb3,0x14,0x97,0x31,0xe3,0x44,0x51,0x33,0xbd,0xad,0xc5,0x33,0x3b,0x45, +0x69,0x33,0x50,0x7b,0x64,0x32,0x7f,0xef,0x43,0x31,0x48,0xab,0xcb,0x2d,0x45, +0x89,0xdc,0x2e,0xc5,0x9d,0xd9,0x31,0xaa,0x5c,0x8f,0x33,0x0c,0x2d,0x8c,0x34, +0xe1,0x67,0xde,0x34,0x57,0xea,0x0b,0x35,0xfa,0x6f,0x4c,0x34,0x8c,0xb2,0x05, +0x34,0x65,0xb7,0xf3,0x32,0xb1,0xa5,0x3b,0x31,0x8e,0x6e,0xd7,0x31,0xb8,0x29, +0x4f,0x31,0x3e,0x7e,0x7a,0x30,0xae,0x18,0x5f,0x31,0x64,0xff,0x9f,0x32,0xe8, +0x6b,0x84,0x33,0x17,0x30,0x23,0x33,0x00,0x00,0x00,0x00,0x1a,0x59,0x51,0x30, +0x2f,0x41,0xe9,0xba,0x22,0xe2,0xa6,0xb6,0x73,0xe4,0x3e,0xbc,0xd1,0x51,0x0c, +0x35,0xe8,0x7b,0xa2,0xbc,0x0f,0x00,0x04,0x35,0xba,0x44,0x6e,0xbc,0xc5,0x4a, +0x9a,0x30,0xce,0xb3,0xb1,0xbc,0x40,0x18,0xa9,0x35,0x67,0x1e,0xcc,0xbc,0x2c, +0x82,0x38,0x34,0x14,0x16,0xa1,0xbc,0xfc,0xb8,0x15,0xb8,0x2a,0xa1,0x8c,0xbc, +0xa1,0xda,0xe4,0xba,0xbe,0xe2,0xc1,0xbd,0x2a,0xa8,0x65,0xba,0x67,0x70,0xad, +0xbe,0x24,0x32,0x06,0xb8,0x69,0x37,0x13,0xbf,0xb5,0xa0,0x10,0x36,0xd2,0x1d, +0x9b,0xbf,0xb1,0x5b,0x1d,0x3c,0x9c,0x06,0xa3,0xbf,0x02,0x88,0x98,0x3c,0x64, +0x36,0x6b,0xbf,0x89,0x2d,0x29,0x3d,0xd7,0xa2,0x68,0xbf,0xd5,0xea,0x83,0x3d, +0xc5,0x92,0x5e,0xbf,0x8a,0xb6,0x2a,0x3e,0xa9,0x8f,0x8d,0xbf,0x01,0x18,0xab, +0x3e,0x25,0x5b,0x50,0xbf,0x45,0xa0,0xe1,0x3e,0x7b,0xc7,0x02,0xbf,0x96,0xe6, +0xcf,0x3e,0x65,0x6e,0x9f,0xbe,0x07,0xb4,0x97,0x3e,0x77,0x23,0xd0,0xbe,0xa2, +0xdf,0x1b,0x3f,0x1b,0xde,0x50,0xbf,0x5d,0xe9,0x16,0x40,0x34,0x1e,0xcd,0xbe, +0x7c,0x51,0x18,0x40,0x2d,0x91,0x13,0xbd,0xbd,0x31,0x7a,0x3f,0xa8,0x70,0x44, +0xbc,0x7a,0x3f,0x33,0x3f,0x1c,0x91,0xdf,0xbc,0x52,0xaf,0x56,0x3f,0xcd,0xe6, +0xea,0xbc,0x40,0x71,0x53,0x3f,0xb9,0x88,0xb0,0xbc,0x07,0x1a,0x58,0x3f,0x0c, +0x04,0x6e,0xbc,0xac,0xb2,0x22,0x3f,0x17,0x35,0xa0,0xbb,0xfd,0x35,0xcd,0x3e, +0x6a,0xfb,0xd9,0xbb,0xd0,0x22,0xa4,0x3e,0xee,0x71,0x55,0xbc,0x60,0x8f,0xa4, +0x3e,0x4c,0x36,0xba,0xbc,0xa2,0x05,0xb4,0x3e,0x1a,0xdb,0xfa,0xbc,0x53,0xce, +0xca,0x3e,0xa7,0x52,0x33,0xbd,0x44,0x27,0xe5,0x3e,0x37,0xd8,0x45,0xbd,0xc2, +0x66,0xf7,0x3e,0x8b,0xeb,0x40,0xbd,0xdb,0xd6,0xf1,0x3e,0xbb,0xdf,0x2b,0xbd, +0x67,0x10,0xe0,0x3e,0xcd,0xff,0x4a,0xbd,0xcd,0xc0,0xde,0x3e,0xd3,0xed,0x94, +0xbd,0xa2,0x41,0xeb,0x3e,0xf8,0xcd,0xd0,0xbd,0xdb,0x73,0xf0,0x3e,0x0f,0x13, +0xef,0xbd,0xa5,0x29,0xeb,0x3e,0x6c,0x15,0x16,0xbe,0x37,0x15,0xf6,0x3e,0x61, +0x5d,0x55,0xbe,0x26,0xf2,0x1f,0x3f,0x6e,0xee,0x74,0xbe,0x3b,0x3e,0x11,0x3f, +0x07,0x61,0x78,0xbe,0x3d,0x6e,0xe2,0x3e,0xca,0x30,0xc2,0xbe,0xb8,0x57,0x1c, +0x3f,0x7c,0xcf,0x78,0xbf,0x0e,0x7c,0x6c,0x3f,0x34,0x90,0x9a,0xbf,0xa6,0xc1, +0x7c,0x3f,0xd5,0x7d,0xc0,0xbf,0x70,0xf6,0x4b,0x3f,0x3f,0x01,0x03,0xc0,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xbf,0xf7,0xbf,0xf8,0x44,0xf7,0x36,0xf7, +0xd9,0xf7,0x2b,0xf7,0x76,0xf7,0x07,0xf9,0xdf,0xf9,0x1f,0xf9,0x6b,0xf8,0xa3, +0xf7,0x1e,0xf5,0x4e,0xf4,0x94,0xf3,0x1a,0xf3,0x6c,0xf2,0x18,0xf1,0x39,0xf0, +0x4a,0xef,0x6a,0xf0,0x54,0xf0,0x08,0xec,0x56,0xe6,0xd7,0xe4,0x99,0xe8,0x64, +0xe8,0xa8,0xe7,0x33,0xe6,0x77,0xe3,0x7d,0xe5,0x7a,0xe8,0xb4,0xe9,0x43,0xea, +0x9a,0xea,0x7b,0xea,0x38,0xea,0x10,0xea,0x98,0xea,0x5d,0xeb,0xcb,0xeb,0x04, +0xec,0xa5,0xec,0x98,0xed,0x93,0xed,0xd0,0xed,0x8c,0xef,0x8f,0xf0,0x43,0xf0, +0x5f,0xf0,0x02,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11, +0xb9,0x1e,0x36,0x45,0x93,0x93,0x38,0x98,0x2d,0x7d,0x39,0x0e,0xd5,0xf8,0x38, +0xde,0x4a,0xa1,0x39,0x2a,0x50,0xf0,0x39,0xcd,0x51,0x77,0x39,0x88,0xa8,0x62, +0x39,0x0a,0xc5,0x06,0x3c,0x53,0x99,0xc3,0x3d,0x5d,0x48,0x61,0x3e,0xe9,0x3c, +0x41,0x3f,0x0f,0x0b,0x96,0x3f,0x54,0xdb,0x57,0x3f,0x7d,0x80,0x87,0x3f,0xe2, +0x4f,0x9c,0x3f,0x03,0x34,0x2a,0x40,0xa2,0x42,0x43,0x40,0x1a,0xc2,0x2b,0x40, +0x3e,0x5d,0xb2,0x3f,0x60,0x9f,0xa8,0x3f,0xde,0x20,0x95,0x40,0x7a,0xf3,0x29, +0x41,0xd9,0x81,0x7d,0x40,0x63,0x20,0x58,0x3f,0xf7,0x87,0x13,0x3f,0xea,0x8f, +0x51,0x3f,0x7b,0xb4,0x37,0x3f,0xff,0x30,0x2a,0x3f,0x02,0xcf,0xa9,0x3e,0xe0, +0xab,0x31,0x3e,0xc2,0x96,0x15,0x3e,0x23,0x06,0x36,0x3e,0x6f,0xbf,0x61,0x3e, +0x82,0xdc,0x96,0x3e,0x0e,0xd1,0xc3,0x3e,0x5d,0x8c,0xdc,0x3e,0x9f,0xe0,0xcb, +0x3e,0x10,0x97,0xbe,0x3e,0xf8,0x78,0xdc,0x3e,0x39,0x40,0x0a,0x3f,0xa5,0x85, +0x20,0x3f,0x5b,0xba,0x37,0x3f,0x94,0xb3,0x8d,0x3f,0x06,0x33,0xf3,0x3f,0x7b, +0xaf,0xe0,0x3f,0x3a,0x84,0xfb,0x3f,0x36,0x62,0xb7,0x40,0x89,0xb2,0x16,0x41, +0xc1,0xa0,0x47,0x41,0x20,0xd1,0x61,0x41,0x00,0x00,0x00,0x00,0x00,0x40,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x40,0xc8,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0xc5,0x00,0x00, +0x00,0xc5,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0xc5,0x00, +0x00,0x00,0x00,0xa0,0xaa,0x00,0xa7,0xab,0xa3,0x55,0xa0,0x00,0x9a,0x55,0x8d, +0x55,0x0d,0x00,0x1a,0x55,0x20,0xab,0x23,0x00,0x27,0xa0,0x32,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xd3,0xa3,0x50,0xa3,0x75,0xa3,0xc5,0xa1,0x7d,0x9e, +0xb1,0x9b,0x3f,0xa2,0x24,0xa2,0x4f,0xa2,0xe2,0xa0,0x70,0x9d,0xe3,0x9a,0x68, +0xa1,0x84,0xa1,0xb2,0xa1,0x68,0xa0,0xe0,0x9c,0x75,0x9a,0x90,0xa0,0xe4,0xa0, +0x15,0xa1,0xde,0x9f,0x51,0x9c,0x07,0x9a,0x04,0x9e,0x42,0x9f,0x09,0xa0,0x15, +0x9e,0xd2,0x9a,0xbf,0x98,0x15,0x9b,0xbf,0x9c,0xe5,0x9d,0x1c,0x9c,0x20,0x99, +0xc3,0x96,0xa0,0x98,0x51,0x9a,0x7c,0x9b,0xf1,0x99,0xcb,0x96,0x1d,0x94,0xdc, +0x93,0xc5,0x96,0x68,0x98,0x98,0x96,0xd5,0x92,0xfd,0x90,0x66,0x8d,0xe8,0x90, +0x80,0x92,0x37,0x91,0xd0,0x8d,0xab,0x8b,0xa9,0x85,0xe8,0x88,0x4f,0x8b,0x18, +0x8a,0xb1,0x87,0xb7,0x86,0x8c,0x82,0x6c,0x85,0x8d,0x87,0xd3,0x86,0x42,0x85, +0xb7,0x84,0x5a,0x08,0xec,0x06,0x0a,0x06,0xfe,0x05,0x0c,0x06,0xf7,0x05,0x00, +0x00,0xd5,0x00,0xab,0x01,0x80,0x02,0x55,0x03,0x2b,0x04,0x00,0x05,0xd5,0x05, +0xab,0x06,0x80,0x07,0x55,0x08,0x2b,0x09,0x00,0x0a,0xd5,0x0a,0xab,0x0b,0x80, +0x0c,0x55,0x0d,0x2b,0x0e,0x00,0x0f,0xd5,0x0f,0x55,0x10,0xc0,0x10,0x2b,0x11, +0x95,0x11,0x00,0x12,0x6b,0x12,0xd5,0x12,0x40,0x13,0xab,0x13,0x15,0x14,0x80, +0x14,0xeb,0x14,0x55,0x15,0xc0,0x15,0x2b,0x16,0x95,0x16,0x00,0x17,0x6b,0x17, +0xd5,0x17,0x20,0x18,0x55,0x18,0x8b,0x18,0xc0,0x18,0xf5,0x18,0x2b,0x19,0x60, +0x19,0x95,0x19,0xcb,0x19,0x00,0x1a,0x00,0x1a,0x00,0x1a,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x01,0x66,0x02,0x66,0x02,0x66,0x02,0x66, +0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x4a,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xab,0x00,0xa7,0xab,0xa3,0x55, +0xa0,0x00,0x9a,0x55,0x8d,0x55,0x0d,0x00,0x1a,0x55,0x20,0xab,0x23,0x00,0x27, +0xa0,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf5,0xa0,0xe7,0x9b,0x88, +0x9a,0xf7,0x9d,0xf8,0x96,0xdd,0x99,0x01,0xa0,0x7f,0x9c,0xc7,0x9b,0x85,0x9c, +0x74,0x98,0x21,0x99,0x29,0x9f,0xc2,0x9c,0x55,0x9c,0xe0,0x9b,0xe2,0x98,0xcd, +0x98,0x86,0x9e,0xfa,0x9c,0xc6,0x9c,0x89,0x9b,0x01,0x99,0x93,0x98,0xdd,0x9d, +0xf8,0x9c,0x05,0x9d,0x6d,0x9b,0xaf,0x98,0x53,0x98,0x8e,0x9c,0x47,0x9c,0xc0, +0x9c,0x03,0x9b,0x0f,0x98,0x5b,0x97,0x10,0x9a,0x74,0x9a,0x80,0x9b,0xe5,0x99, +0xbe,0x95,0xae,0x94,0x97,0x95,0x92,0x97,0x53,0x99,0x07,0x98,0x6a,0x92,0x15, +0x91,0x64,0x8e,0xc5,0x91,0x44,0x95,0x7a,0x93,0xb6,0x8d,0x10,0x8b,0xf2,0x84, +0x07,0x8a,0x5a,0x90,0xc2,0x8e,0x2f,0x88,0x2d,0x86,0x3c,0x81,0x10,0x86,0x5a, +0x8c,0x33,0x8b,0x07,0x86,0x73,0x84,0xaf,0x0b,0xe7,0x09,0xf0,0x07,0x8c,0x07, +0x0c,0x08,0x3b,0x08,0x11,0x01,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66, +0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x4a,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01, +0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc, +0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0, +0xcc,0x00,0x00,0xd0,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x00,0xff,0xff, +0xff,0xff,0xff,0xff,0x68,0x00,0x34,0x00,0x00,0x00,0x96,0xce,0x96,0xce,0x96, +0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce, +0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96, +0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x96,0xce,0x31,0xd1, +0x04,0xd2,0x15,0xdc,0x23,0xd4,0x41,0xc6,0x39,0xc4,0x77,0xc5,0xf9,0xcf,0x41, +0xd5,0x92,0xe3,0xee,0xe3,0x9d,0xd1,0xf7,0xc4,0xa3,0xbe,0xee,0xba,0x14,0xb9, +0x9e,0xc1,0x29,0xc4,0x56,0xcb,0xf9,0xd7,0x8c,0xd2,0xf9,0xd5,0x72,0xde,0x28, +0xd7,0x7d,0xcc,0x27,0xc6,0xbe,0xc5,0x00,0x00,0x2c,0x83,0x2c,0x83,0x2c,0x83, +0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c, +0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83, +0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0x2c,0x83,0xb5,0x82,0x9d, +0x84,0x37,0x83,0xd3,0x83,0x11,0x84,0xb8,0x87,0xf3,0x8c,0x81,0x8e,0xd7,0x8c, +0xcb,0x8a,0xa7,0x88,0x1a,0x87,0x53,0x86,0xd5,0x86,0x42,0x87,0x50,0x86,0x04, +0x85,0x6c,0x84,0xd2,0x83,0xee,0x81,0x2b,0x80,0x73,0x80,0xb5,0x7f,0x31,0x77, +0x71,0x74,0xc6,0x72,0xa8,0x70,0x00,0x00,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e, +0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7, +0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e, +0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x2e,0xe7,0x0e,0xea,0x4f,0xeb, +0x48,0xf5,0x85,0xee,0xde,0xe0,0xa6,0xde,0x44,0xe0,0x3b,0xe8,0x1c,0xf0,0xaa, +0xfd,0x36,0xfe,0xb2,0xea,0xc7,0xdf,0x38,0xd7,0x69,0xd4,0x01,0xd3,0xb4,0xda, +0x8f,0xde,0xb7,0xe4,0x2b,0xf2,0x1c,0xec,0xa7,0xf0,0x12,0xf7,0x8d,0xf1,0x97, +0xe5,0xca,0xe0,0x7a,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x34,0x00,0x34,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x34,0x00,0x00, +0x00,0x13,0x8e,0x86,0x8e,0xa2,0x90,0xce,0x91,0xad,0x8e,0x92,0x8a,0xb2,0x87, +0x3c,0x86,0x60,0x7a,0x13,0x81,0x77,0x84,0xe8,0x74,0xb7,0x7d,0xd2,0x82,0xb6, +0x76,0xfc,0x68,0x5f,0x62,0xf6,0x60,0xcb,0x73,0xba,0x80,0x9a,0x76,0x86,0x6f, +0xc1,0x67,0x59,0x60,0xb9,0x61,0xfa,0x76,0xdf,0x69,0xcb,0x64,0x94,0x60,0xb3, +0x60,0x46,0x6b,0x49,0x6a,0x55,0x66,0xc7,0x5c,0xae,0x60,0x17,0x63,0xfd,0x5d, +0x13,0x58,0x89,0x52,0x31,0x54,0x91,0x53,0xda,0x50,0xeb,0x56,0x27,0x5a,0x18, +0x69,0x96,0x72,0x21,0x67,0xd2,0x6a,0x45,0x47,0x4e,0x7a,0xf5,0x7a,0x00,0x00, +0x63,0xd6,0x42,0xd4,0x05,0xd4,0x24,0xd6,0xa3,0xd5,0x01,0xd6,0x5f,0xdf,0x48, +0xe1,0x94,0xe4,0x68,0xef,0x4c,0xef,0x17,0xf1,0x22,0xea,0x5b,0xeb,0x80,0xe2, +0x10,0xcf,0xa6,0xc0,0xd9,0xc1,0x57,0xc6,0x1a,0xc2,0x8a,0xc0,0x3c,0xbf,0xdf, +0xbc,0x7e,0xbd,0xdb,0xba,0x90,0xb9,0x05,0xbb,0xb1,0xbb,0x44,0xbc,0x9d,0xbf, +0x19,0xbc,0xed,0xb4,0x11,0xb2,0x04,0xac,0x9d,0xa8,0xcf,0xa5,0xf5,0xa0,0x44, +0xa0,0x9e,0x9a,0x68,0xa0,0xe6,0xa2,0xfd,0xa2,0xe0,0xae,0xc6,0xa7,0x51,0xb2, +0x12,0xb4,0x15,0xb8,0x19,0xb0,0xcb,0xb9,0x56,0xb3,0xfe,0xb0,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x33,0x00,0x00, +0x00,0x33,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x33,0x00, +0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x00,0x00, +0x00,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00, +0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa4, +0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x40,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x0a,0x77,0x02,0x77,0x22,0x7a,0xe0,0x80,0x73,0x76,0xf9,0x82,0x5a, +0x81,0x5a,0x7b,0xf3,0x79,0xdd,0x7e,0xe2,0x84,0xd2,0x8d,0x7b,0x8a,0x48,0x80, +0x12,0x81,0xb9,0x83,0xf6,0x87,0xd7,0x86,0x9e,0x89,0x6e,0x82,0x44,0x80,0xc4, +0x7e,0x08,0x85,0x95,0x83,0x79,0x79,0x0c,0x7d,0xff,0x77,0x3b,0x78,0x60,0x79, +0xd9,0x7e,0x7b,0x87,0x06,0x92,0x29,0x90,0x79,0x8d,0x8f,0x92,0x9b,0x92,0xf8, +0x91,0x63,0x92,0x07,0x97,0xaf,0xa4,0xe7,0xac,0xaf,0xaa,0x57,0xb7,0x12,0xb4, +0x7a,0xc2,0x42,0xc4,0xa0,0xbb,0xb0,0xbb,0x9c,0xb4,0xab,0xb1,0xa4,0xc0,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x90,0xd8,0x91,0x77,0x93, +0x02,0x94,0x0d,0x95,0xd2,0x93,0x70,0x92,0x9b,0x92,0xd8,0x92,0x12,0x93,0xe6, +0x93,0x73,0x95,0x37,0x93,0x52,0x94,0x83,0x94,0x5e,0x94,0xe1,0x95,0x72,0x96, +0x99,0x95,0x68,0x95,0x7d,0x95,0x0e,0x98,0xb4,0x97,0x3e,0x98,0x1d,0x9b,0x6c, +0x9b,0x5f,0x9b,0xe6,0x9b,0x0f,0x9d,0xf1,0x9f,0x57,0x9f,0x96,0x9e,0x9c,0xa1, +0x41,0xa2,0x03,0xa6,0x92,0xaa,0x42,0xa6,0x11,0xa9,0xb5,0xab,0x57,0xa8,0x3d, +0xab,0xa7,0xae,0x55,0xad,0x94,0xae,0x2a,0xb0,0xc4,0xb0,0x9b,0xb3,0xe0,0xb3, +0xbc,0xb8,0xe9,0xba,0x73,0xb9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x5c,0x30,0x5c,0x19,0x61,0x09, +0x63,0x81,0x62,0x53,0x63,0x05,0x62,0xe5,0x62,0xef,0x60,0x65,0x62,0x76,0x63, +0x0e,0x64,0xca,0x5f,0x5d,0x61,0xf0,0x61,0xfe,0x61,0xab,0x61,0x38,0x66,0xb2, +0x62,0x25,0x65,0x87,0x64,0xfe,0x64,0x1a,0x6b,0x7e,0x66,0x7c,0x62,0x17,0x6c, +0xde,0x72,0x13,0x70,0xa1,0x6d,0x6b,0x6a,0x4b,0x6f,0x10,0x70,0x89,0x65,0xd6, +0x6c,0xda,0x70,0xf4,0x70,0xfe,0x6a,0x3d,0x79,0xe3,0x79,0x32,0x77,0x6d,0x74, +0x5a,0x7e,0xe2,0x85,0x32,0x8d,0x29,0x91,0x8f,0x86,0xad,0x92,0x97,0xa3,0x25, +0xa3,0xd2,0xa9,0x23,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xc8,0x8f,0xda,0x92,0xc1,0x98,0xca,0xa2,0x9f,0xa4,0xa2,0xa0,0x37,0x95,0xb6, +0x94,0xf3,0x93,0x18,0x91,0xf0,0x91,0xd7,0x92,0x67,0x92,0x10,0x92,0xb2,0x93, +0xab,0x96,0x22,0x95,0xd0,0x93,0x7c,0x96,0xf6,0x96,0xd8,0x98,0x43,0x99,0xa2, +0xa0,0x87,0xa0,0x51,0x98,0xe5,0x98,0xd5,0xa0,0x6d,0xa1,0xbd,0x9f,0xb5,0xa0, +0x1c,0xa2,0xab,0xa9,0x71,0xa5,0x02,0xa3,0xc6,0xa6,0x8a,0xa6,0x89,0xa9,0x32, +0xb4,0x06,0xb1,0xf9,0xaa,0x84,0xaf,0x43,0xb1,0xc5,0xb4,0x22,0xb7,0xb0,0xb6, +0x41,0xc2,0xc7,0xc3,0x4c,0xc5,0x3f,0xc4,0x61,0xcd,0xcb,0xd5,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,0x31,0x0b,0xc3,0x80,0x17,0x42,0x1e, +0x38,0x8e,0x4a,0x98,0xa8,0x42,0x00,0x40,0x92,0xde,0xcc,0x82,0x43,0x3d,0xae, +0x02,0xa4,0xba,0x34,0x5d,0x00,0x00,0x00,0x00,0x46,0xff,0xff,0x01,0x46,0xff, +0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46, +0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01, +0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff, +0x01,0x46,0xff,0xff,0x01,0x46,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0a,0x00,0x00, +0x00,0x0b,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x65,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +0x80,0x00,0x00,0x00,0x00,0x00,0x40,0x9a,0x00,0x9e,0x14,0x00,0x00,0x00,0x00, +0x00,0x00,0x5f,0x05,0x00,0x40,0x74,0xcb,0xa7,0x0f,0xa9,0x1b,0x7b,0x8c,0x74, +0xa6,0x52,0x52,0x00,0x40,0xf6,0xde,0xd4,0x00,0xef,0x3d,0xd2,0x80,0xbf,0xbe, +0x5f,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0xd5,0xac,0xd9,0xe7,0xdc,0xd2, +0xdf,0x52,0xe1,0xb5,0xe2,0x13,0xe4,0x6c,0xe5,0xc3,0xe6,0x15,0xe8,0x65,0xe9, +0xb0,0xea,0xf6,0xeb,0x32,0xed,0x68,0xee,0x97,0xef,0x63,0xf0,0xf7,0xf0,0x88, +0xf1,0x14,0xf2,0x9a,0xf2,0x1f,0xf3,0xa1,0xf3,0x21,0xf4,0x98,0xf4,0x0e,0xf5, +0x80,0xf5,0xe8,0xf5,0x48,0xf6,0xa6,0xf6,0x06,0xf7,0x5d,0xf7,0xb5,0xf7,0x09, +0xf8,0x5a,0xf8,0xa9,0xf8,0xf5,0xf8,0x3d,0xf9,0x83,0xf9,0xc7,0xf9,0xed,0xf9, +0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed, +0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9, +0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0xed,0xf9,0x00, +0x00,0x0a,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x3d,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x28,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0xf7,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x66,0x66,0x66,0x3f,0xcd,0xcc,0xcc,0x3f,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x37,0x9c,0xb7,0x9e,0x6a,0xa0,0x26,0xa2,0x26,0xa2,0xea, +0xa3,0xb6,0xa5,0xb6,0xa5,0x9f,0xa6,0x66,0xa9,0x58,0xaa,0x58,0xaa,0x39,0xad, +0x39,0xad,0x2e,0xb0,0x2f,0xb1,0x32,0xb2,0x4a,0xb5,0x57,0xb6,0x78,0xb8,0xa2, +0xba,0xa2,0xba,0xd6,0xbc,0xf4,0xbd,0xaf,0xc0,0xd8,0xc1,0x6f,0xc2,0xa1,0xc3, +0x3c,0xc4,0x76,0xc5,0xb6,0xc6,0xfb,0xc7,0x46,0xc9,0xee,0xc9,0x42,0xcb,0xef, +0xcb,0x4c,0xcd,0xfd,0xcd,0x8b,0xd1,0x02,0xd3,0x45,0xd2,0x80,0xd4,0x41,0xd5, +0x91,0xd7,0x24,0xd9,0x24,0xd9,0xbe,0xda,0x5f,0xdc,0x33,0xdd,0xb9,0xdf,0xb9, +0xdf,0x94,0xe0,0x72,0xe1,0xfb,0xe4,0xb7,0xe7,0xa4,0xe8,0xa4,0xe8,0x94,0xe9, +0x69,0xed,0x86,0xea,0xfb,0xe4,0xb9,0xdf,0x8e,0xdb,0x00,0x00,0x0a,0x00,0x00, +0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00, +0x00,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x37,0x9c,0xdf,0x9d,0xdf,0x9d,0x8f,0x9f,0x6a,0xa0,0x47,0xa1,0x26,0xa2, +0x07,0xa3,0xb6,0xa5,0x9f,0xa6,0x9f,0xa6,0x8a,0xa7,0x66,0xa9,0x58,0xaa,0x41, +0xac,0x41,0xac,0x33,0xae,0x2f,0xb1,0x32,0xb2,0x32,0xb2,0x40,0xb4,0x57,0xb6, +0x78,0xb8,0x8c,0xb9,0xbb,0xbb,0xf4,0xbd,0xf4,0xbd,0x1c,0xc0,0x1c,0xc0,0xd8, +0xc1,0x6f,0xc2,0x07,0xc3,0x3c,0xc4,0xd8,0xc4,0x15,0xc6,0xfb,0xc7,0xfb,0xc7, +0xee,0xc9,0xee,0xc9,0xee,0xc9,0x9d,0xcc,0x9d,0xcc,0xfd,0xcd,0x64,0xcf,0xd2, +0xd0,0xd2,0xd0,0x45,0xd2,0xd2,0xd0,0x02,0xd3,0x41,0xd5,0x41,0xd5,0x41,0xd5, +0x05,0xd6,0x41,0xd5,0x41,0xd5,0x91,0xd7,0xf0,0xd9,0xf0,0xd9,0x59,0xd8,0x24, +0xd9,0x05,0xd6,0x41,0xd5,0x80,0xd4,0x00,0x00,0x8e,0x69,0xee,0x3e,0x77,0x35, +0x9b,0x3f,0x8e,0x69,0xee,0x3e,0x00,0x00,0x00,0x00,0x27,0xfe,0x11,0x40,0xbe, +0xed,0x05,0x40,0x27,0xfe,0x11,0x40,0x00,0x00,0x00,0x00,0x4a,0x75,0x78,0x78, +0xbb,0x7b,0xf4,0x7d,0x1c,0x80,0x43,0x81,0x6f,0x82,0x3c,0x84,0x3c,0x84,0xb6, +0x86,0xa0,0x88,0xee,0x89,0x42,0x8b,0x4c,0x8d,0xb0,0x8e,0x64,0x8f,0x8b,0x91, +0xc0,0x93,0x41,0x95,0x91,0x97,0xf0,0x99,0x33,0x9d,0x33,0x9d,0x72,0xa1,0xfb, +0xa4,0xe2,0xa5,0xa4,0xa8,0x94,0xa9,0x70,0xac,0x63,0xae,0x6a,0xb3,0x8b,0xb6, +0xc1,0xb9,0xc1,0xb9,0x4c,0xbf,0x38,0xc0,0x8c,0xc2,0xbf,0xc3,0xd4,0xc6,0x63, +0xcb,0x66,0xc9,0x6e,0xcd,0x1f,0xce,0xae,0xd1,0xa5,0xd4,0xe5,0xd3,0xa5,0xd4, +0xb7,0xd7,0xe5,0xda,0x88,0xdc,0x32,0xde,0x41,0xe4,0x7c,0xe2,0xf8,0xe6,0xa9, +0xeb,0x98,0xed,0xb4,0xea,0xa9,0xeb,0xbe,0xf6,0x9d,0xf3,0xd2,0xe8,0x09,0xdf, +0xa5,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x42,0x2b,0x42,0x2b,0x42,0x2b,0x42,0x2b,0x42,0x2b, +0x1a,0x3d,0x27,0x4b,0xf5,0x5c,0x0d,0x6b,0x2b,0x73,0xd0,0x7c,0x23,0x84,0xf3, +0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a, +0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3, +0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0xf3,0x8a,0x0c,0x93,0xab,0x9c, +0x0d,0xa4,0xd9,0xaa,0xed,0xb2,0x86,0xbc,0xf7,0xc3,0xbf,0xca,0xce,0xd2,0x62, +0xdc,0xe2,0xe3,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea, +0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xa5,0xea,0xce, +0xd2,0x86,0xbc,0x0d,0xa4,0xf3,0x8a,0x2b,0x73,0xf5,0x5c,0x00,0x00,0x04,0x00, +0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04, +0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00, +0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x8e,0x69,0xee,0x3e,0x8e, +0x69,0xee,0x3e,0x00,0x00,0x00,0x00,0x27,0xfe,0x11,0x40,0x27,0xfe,0x11,0x40, +0x27,0xfe,0x11,0x40,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0, +0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00, +0x00,0x66,0x66,0x66,0x3e,0x33,0x33,0x33,0x3b,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xf5,0x13,0xe0,0x2b,0x5f,0x3b,0xab,0x47,0x33,0x53,0xc2,0x5d, +0x3c,0x66,0x1b,0x70,0xbc,0x76,0x5d,0x7f,0x33,0x85,0x24,0x8c,0x58,0x92,0x78, +0x97,0x91,0x9d,0x61,0xa2,0xa5,0xa6,0x98,0xab,0xa6,0xb0,0xd2,0xb3,0x52,0xb7, +0x48,0xbb,0xaf,0xbf,0x47,0xc2,0xcf,0xc4,0x98,0xc7,0x9a,0xca,0x97,0xcd,0x4b, +0xd0,0xe2,0xd1,0xa1,0xd3,0x59,0xd5,0x33,0xd7,0x17,0xd9,0x06,0xdb,0x0a,0xdd, +0x14,0xdf,0x8f,0xe0,0x9d,0xe1,0xad,0xe2,0xbf,0xe3,0xcc,0xe4,0xda,0xe5,0xe4, +0xe6,0xf7,0xe7,0xb2,0xe8,0x7d,0xe9,0x64,0xea,0x54,0xeb,0x36,0xec,0x1a,0xed, +0xfa,0xed,0xd1,0xee,0xa4,0xef,0x33,0xf0,0x4a,0xf0,0xa0,0xf0,0x07,0xf1,0x65, +0xf1,0xa4,0xf1,0x91,0xf1,0xbe,0xf1,0x20,0xf2,0x00,0x00,0x7e,0xf9,0x7e,0xf9, +0x7e,0xf9,0x7e,0xf9,0x7e,0xf9,0x7e,0xf9,0x7e,0xf9,0x7e,0xf9,0x7e,0xf9,0x7e, +0xf9,0x7e,0xf9,0x7e,0xf9,0x3c,0xf3,0x42,0xe9,0x0f,0xe0,0xb8,0xd6,0xe5,0xcd, +0xa3,0xc5,0xdd,0xbd,0xce,0xb6,0x3f,0xb0,0x5f,0xa9,0xf0,0xa2,0x15,0x9d,0x33, +0x98,0x6e,0x92,0x8b,0x8d,0x3b,0x89,0x0d,0x85,0x55,0x81,0x59,0x7d,0xde,0x79, +0xa0,0x76,0x08,0x73,0x71,0x70,0x09,0x6d,0x36,0x6a,0x1f,0x68,0x00,0x65,0x88, +0x62,0x9e,0x60,0x4c,0x5e,0xf8,0x5b,0x20,0x5a,0x96,0x58,0x68,0x57,0xc1,0x55, +0x23,0x54,0xb4,0x52,0x8b,0x51,0x89,0x50,0x57,0x4f,0xe3,0x4d,0xa1,0x4c,0x98, +0x4b,0x5f,0x4b,0x90,0x4a,0xb1,0x49,0xf9,0x48,0x89,0x48,0xa9,0x48,0x5c,0x48, +0x7c,0x47,0x00,0x00,0x00,0xe1,0x3f,0x3a,0x00,0xc4,0x44,0x3a,0x00,0xbe,0x49, +0x3a,0x00,0xcd,0x4e,0x3a,0x00,0xf2,0x53,0x3a,0x00,0x2f,0x59,0x3a,0x00,0x84, +0x5e,0x3a,0x00,0xf0,0x63,0x3a,0x00,0x76,0x69,0x3a,0x00,0x16,0x6f,0x3a,0x00, +0xd0,0x74,0x3a,0x00,0xa5,0x7a,0x3a,0x00,0x95,0x80,0x3a,0x00,0xa3,0x86,0x3a, +0x00,0xce,0x8c,0x3a,0x00,0x17,0x93,0x3a,0x00,0x80,0x99,0x3a,0x00,0x09,0xa0, +0x3a,0x00,0xb3,0xa6,0x3a,0x00,0x7e,0xad,0x3a,0x00,0x6d,0xb4,0x3a,0x00,0x80, +0xbb,0x3a,0x00,0xb9,0xc2,0x3a,0x00,0x18,0xca,0x3a,0x00,0x9e,0xd1,0x3a,0x00, +0x4d,0xd9,0x3a,0x00,0x27,0xe1,0x3a,0x00,0x2c,0xe9,0x3a,0x00,0x5e,0xf1,0x3a, +0x00,0xbe,0xf9,0x3a,0x00,0x4f,0x02,0x3b,0x00,0x11,0x0b,0x3b,0x00,0x07,0x14, +0x3b,0x00,0x32,0x1d,0x3b,0x00,0x93,0x26,0x3b,0x00,0x2e,0x30,0x3b,0x00,0x04, +0x3a,0x3b,0x00,0x16,0x44,0x3b,0x00,0x68,0x4e,0x3b,0x00,0xfc,0x58,0x3b,0x00, +0xd4,0x63,0x3b,0x00,0xf3,0x6e,0x3b,0x00,0x5b,0x7a,0x3b,0x00,0x10,0x86,0x3b, +0x00,0x14,0x92,0x3b,0x00,0x6a,0x9e,0x3b,0x00,0x17,0xab,0x3b,0x00,0x1c,0xb8, +0x3b,0x00,0x7f,0xc5,0x3b,0x00,0x43,0xd3,0x3b,0x00,0x6c,0xe1,0x3b,0x00,0xff, +0xef,0x3b,0x00,0x00,0xff,0x3b,0x00,0x3a,0x07,0x3c,0x00,0x30,0x0f,0x3c,0x00, +0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c, +0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17,0x3c,0x00,0x65,0x17, +0x3c,0x00,0x00,0x00,0x00,0x94,0x94,0x94,0x94,0x94,0x8f,0x8a,0x85,0x80,0x7d, +0x7b,0x78,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76, +0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x73,0x71,0x6e,0x6c,0x69,0x67,0x64, +0x62,0x5f,0x5d,0x5a,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58, +0x58,0x58,0x5f,0x67,0x6e,0x76,0x7d,0x85,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00, +0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f, +0x00,0x0f,0x00,0x0f,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xad,0x3c, +0x00,0x00,0xc0,0x47,0x00,0x00,0x80,0x44,0x00,0xa3,0x02,0x43,0x00,0x00,0x00, +0xc7,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x00,0x00, +0x00,0x47,0x00,0x00,0x40,0x48,0x00,0x00,0x00,0x49,0x00,0x00,0x40,0x4a,0x00, +0xab,0xaa,0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x3a, +0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x3a,0x00,0xab,0xaa,0x38,0x00,0x00,0x00, +0x00,0x07,0x0f,0x12,0x11,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x92,0x24,0x49,0x3a,0x22,0x22,0x22,0x38,0xe4,0x38,0x8e,0x37,0xc4, +0xc3,0xc3,0x37,0xab,0xaa,0xaa,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xa0,0xfa,0xfa,0xfa, +0xfa,0xfa,0xfa,0xfa,0xa0,0xfa,0xfa,0xf4,0xf4,0xf4,0xe8,0xe8,0xa0,0xfa,0xfa, +0xfa,0xf4,0xe8,0xd0,0xa0,0xa0,0xf4,0xf4,0xf4,0xf4,0xf4,0xe8,0xc4,0xa0,0xf4, +0xf4,0xf4,0xf4,0xf4,0xe8,0xc4,0xa0,0xf4,0xf4,0xe8,0xdc,0xd0,0xb8,0xb8,0xa0, +0xe8,0xe8,0xe8,0xe8,0xd0,0xb8,0xa0,0xa0,0xe8,0xe8,0xe8,0xdc,0xdc,0xd0,0xb8, +0xa0,0xe8,0xe8,0xe8,0xdc,0xdc,0xd0,0xb8,0xa0,0xe8,0xdc,0xdc,0xc4,0xa0,0xa0, +0xa0,0xa0,0xdc,0xdc,0xdc,0xdc,0xb8,0xa0,0xa0,0xa0,0xdc,0xdc,0xdc,0xd0,0xc4, +0xb8,0xa0,0xa0,0xdc,0xdc,0xdc,0xd0,0xc4,0xb8,0xa0,0xa0,0xd0,0xd0,0xd0,0xb8, +0xa0,0xa0,0xa0,0xa0,0xd0,0xd0,0xd0,0xc4,0xa0,0xa0,0xa0,0xa0,0xd0,0xd0,0xd0, +0xc4,0xb8,0xa0,0xa0,0xa0,0xd0,0xd0,0xd0,0xc4,0xb8,0xa0,0xa0,0xa0,0xc4,0xc4, +0xc4,0xa0,0xa0,0xa0,0xa0,0xa0,0xc4,0xc4,0xc4,0xb8,0xa0,0xa0,0xa0,0xa0,0x00, +0x1a,0xb4,0x04,0x00,0x1a,0xb4,0x04,0x00,0x1a,0xb4,0x04,0x00,0x1a,0xb4,0x04, +0x00,0x1a,0xb4,0x04,0x94,0x9e,0xd1,0x05,0x4b,0x76,0xb2,0x06,0xba,0x4d,0xcf, +0x07,0x95,0xd3,0xb0,0x08,0xfc,0xab,0x32,0x09,0x47,0xfe,0xcc,0x09,0xcc,0x33, +0x42,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc, +0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a, +0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf, +0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31, +0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc, +0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0xdc,0x31,0xaf,0x0a,0x86,0xbb,0x30,0x0b, +0x3c,0xb0,0xca,0x0b,0x2a,0xd5,0x40,0x0c,0x21,0x91,0xad,0x0c,0x3d,0xcc,0x2e, +0x0d,0x96,0x63,0xc8,0x0d,0x5c,0x77,0x3f,0x0e,0x63,0xf1,0xab,0x0e,0x20,0xde, +0x2c,0x0f,0x55,0x18,0xc6,0x0f,0x62,0x1a,0x3e,0x10,0xa0,0x52,0xaa,0x10,0xa0, +0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10, +0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa, +0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52,0xaa,0x10,0xa0,0x52, +0xaa,0x10,0x20,0xde,0x2c,0x0f,0x96,0x63,0xc8,0x0d,0x2a,0xd5,0x40,0x0c,0xdc, +0x31,0xaf,0x0a,0xfc,0xab,0x32,0x09,0xba,0x4d,0xcf,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x42,0xcd,0x13,0xd4,0x40,0x00,0x00,0x00,0x40,0xcd,0x13,0xd4, +0x3e,0x00,0x00,0x00,0x3e,0xcd,0x13,0xd4,0x3c,0x00,0x00,0x00,0x3c,0x00,0x00, +0x00,0x00,0x49,0xf5,0x2a,0xf3,0x8d,0xf1,0x17,0xf0,0xae,0xee,0x4b,0xed,0xed, +0xeb,0x94,0xea,0x3d,0xe9,0xeb,0xe7,0x9b,0xe6,0x50,0xe5,0x0a,0xe4,0xce,0xe2, +0x98,0xe1,0x69,0xe0,0x76,0xde,0x25,0xdc,0xde,0xd9,0xb0,0xd7,0x98,0xd5,0x83, +0xd3,0x7a,0xd1,0x7c,0xcf,0xa0,0xcd,0xca,0xcb,0xff,0xc9,0x5f,0xc8,0xe0,0xc6, +0x68,0xc5,0xe9,0xc3,0x8c,0xc2,0x2b,0xc1,0xb6,0xbf,0x2f,0xbd,0xb6,0xba,0x59, +0xb8,0x1b,0xb6,0xe6,0xb3,0xca,0xb1,0xc3,0xaf,0xdc,0xad,0x07,0xac,0x4a,0xaa, +0x90,0xa8,0x6c,0xa7,0x38,0xa6,0xe2,0xa4,0x8a,0xa3,0x4d,0xa2,0x17,0xa1,0xd9, +0x9f,0xac,0x9d,0x94,0x9b,0xb0,0x99,0x41,0x99,0x9e,0x97,0xb2,0x95,0xfa,0x93, +0xd8,0x92,0x2d,0x93,0x60,0x92,0xa7,0x90,0x00,0x00,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab, +0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f, +0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75, +0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a,0x75,0x3f,0xab,0x6a, +0x75,0x3f,0xab,0x6a,0x75,0x3f,0x19,0x88,0x5b,0x3f,0x0c,0xa0,0x29,0x3f,0xb3, +0x3b,0xeb,0x3e,0x7b,0x0d,0x9e,0x3e,0x00,0x00,0x00,0x00,0x27,0x3d,0x05,0xdc, +0x4e,0x83,0xf5,0x3a,0x3d,0x03,0x6e,0xba,0x26,0x5d,0x00,0x40,0xa4,0xde,0x8f, +0x81,0x5a,0x3d,0x7e,0x01,0xe0,0xbb,0xde,0x5d,0x00,0x40,0x93,0xdf,0xcf,0x80, +0x3a,0x3f,0xbe,0x00,0x75,0xbe,0x29,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x43, +0x46,0x47,0x3a,0x20,0x57,0x42,0x5f,0x53,0x45,0x43,0x5f,0x4d,0x30,0x20,0x4d, +0x43,0x46,0x5f,0x43,0x4c,0x3a,0x20,0x31,0x31,0x36,0x37,0x38,0x35,0x66,0x00, +0x00,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c, +0x8f,0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f,0x36,0x29,0x5c,0x8f,0x36,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05, +0x06,0x00,0x01,0x00,0xff,0xff,0xff,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x33,0x33, +0xb9,0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x33,0x33, +0x33,0xb9,0x33,0x33,0x33,0xb9,0x33,0x33,0x33,0xb9,0x00,0x00,0x00,0x00,0x02, +0x02,0x01,0x01,0x01,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xcd,0x3c,0x95,0xda,0x59,0x84,0x8b,0x38,0x2a,0x04,0x5a,0xb7,0x7e,0x5b,0x00, +0x40,0xf5,0xde,0xfe,0x81,0x1b,0x3e,0xcc,0x01,0x44,0xbc,0xf1,0x5d,0x00,0x00, +0x00,0x00,0x7f,0x31,0x53,0xc8,0xbb,0x90,0x61,0x22,0x81,0x0d,0xe0,0x9e,0xf1, +0x4b,0x00,0x40,0x44,0xd9,0x2e,0x8b,0x1c,0x37,0x9b,0x06,0x73,0xaf,0x82,0x53, +0x00,0x00,0x00,0x00,0x2e,0x00,0x22,0x00,0x16,0x00,0x0a,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0a,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x33,0x33,0x3b,0x33,0x33,0x33,0x3b,0x33, +0x33,0x33,0x3b,0x33,0x33,0x33,0x3b,0x33,0x33,0x33,0x3b,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x00,0xb0,0x00, +0xc4,0x00,0xd8,0x00,0xec,0x00,0x00,0x00,0xa0,0x00,0xb0,0x00,0xc4,0x00,0xd8, +0x00,0xec,0x00,0x00,0x00,0xa0,0x00,0xb0,0x00,0xc4,0x00,0xd8,0x00,0xec,0x00, +0x00,0x00,0xa0,0x00,0xb0,0x00,0xc4,0x00,0xd8,0x00,0xec,0x00,0x00,0x00,0xa0, +0x00,0xb0,0x00,0xc4,0x00,0xd8,0x00,0xec,0x00,0x00,0x00,0x00,0x00,0x00,0x10, +0x51,0xd2,0xb4,0x45,0x81,0xa8,0xb6,0x2a,0x85,0xc8,0x31,0xe3,0xd1,0xe5,0xb6, +0xb3,0x36,0x21,0x36,0xdf,0xf3,0x76,0xb7,0xe8,0xb3,0x92,0x38,0x94,0xce,0x83, +0xb5,0x7d,0x71,0xf3,0x38,0x68,0x3b,0xe4,0x34,0xaa,0x41,0x8d,0x38,0xcd,0xb3, +0x61,0x38,0xc4,0xbb,0xb7,0x35,0xbe,0x9a,0x02,0x3a,0x2c,0x2f,0x20,0xb9,0xb7, +0x19,0x18,0x3a,0x74,0x65,0x42,0xbb,0x22,0x67,0x1a,0xb6,0xaa,0x39,0x90,0xb9, +0xc4,0x56,0xe3,0xba,0x7f,0x18,0x67,0x36,0xee,0x9b,0xe9,0xba,0x2f,0xc0,0x18, +0x39,0x32,0x60,0xa7,0xb8,0x47,0x15,0x84,0x38,0x59,0xd9,0x34,0xb4,0xc5,0x8c, +0xe2,0x36,0x8f,0x2a,0x42,0xb4,0xfe,0x97,0xe1,0x37,0xe2,0xe0,0xd0,0xb4,0x0f, +0x16,0xd6,0x38,0x98,0x15,0x19,0x31,0x20,0x80,0x39,0x38,0xbe,0x0c,0xdf,0x37, +0x1a,0xfe,0xe4,0x32,0x7d,0xa4,0xe6,0x38,0x10,0x78,0x06,0xb8,0x16,0xe0,0x3a, +0x36,0x64,0xb0,0x9f,0xb4,0x58,0x0a,0x29,0xb7,0xb6,0x92,0xaf,0x36,0xd7,0xe1, +0x24,0xb7,0xcd,0x58,0xdc,0x38,0x59,0x8e,0xc1,0xac,0xc6,0x69,0x7a,0x38,0x13, +0xcd,0x0c,0x37,0x8e,0xe3,0x15,0x38,0xf4,0xf6,0x45,0x38,0x67,0xdc,0x12,0x37, +0x76,0x68,0x0a,0x39,0x1b,0xab,0xab,0x35,0xe9,0x22,0xcc,0x39,0x19,0x2e,0xc0, +0xb1,0x4c,0x5d,0x2a,0x3a,0x42,0xac,0x35,0xb6,0x79,0xbb,0x50,0x3a,0xd4,0x62, +0xcb,0xb8,0x18,0x39,0x61,0x3a,0x3e,0xe9,0x0c,0xba,0x0e,0xd8,0x12,0x3a,0x7e, +0x06,0xd4,0xba,0x48,0x7d,0x66,0x39,0x8f,0x0e,0x58,0xbb,0xfb,0xd6,0x92,0x37, +0xc6,0xb1,0x67,0xbb,0x66,0xc5,0x31,0xb0,0x35,0xa4,0x2b,0xbb,0x7b,0x97,0xdf, +0xb6,0x98,0x99,0x25,0xbb,0x12,0x1b,0x73,0xb8,0x17,0xec,0xee,0xba,0x96,0x90, +0xbb,0xb9,0xb0,0xbd,0x71,0xba,0x86,0xcd,0x73,0xba,0x7e,0x96,0xb2,0xb9,0x37, +0x6b,0xd3,0xba,0x80,0x4f,0x90,0xb8,0xe8,0x14,0xc4,0xba,0x21,0x0b,0x1b,0xb8, +0x0b,0x62,0xc8,0xba,0xe0,0xbc,0x13,0xb7,0x3c,0xdc,0xe9,0xba,0x3d,0xf6,0x1a, +0xb5,0xf4,0xed,0xf5,0xba,0x3d,0x49,0xfa,0xb0,0xc8,0x1e,0xee,0xba,0x07,0x41, +0x8c,0x33,0xeb,0xa5,0xf9,0xba,0x6e,0x2b,0x64,0x36,0xef,0x7f,0xd1,0xba,0x14, +0x08,0xe4,0x36,0xdb,0xc5,0x98,0xba,0x3b,0xe0,0x5c,0x37,0x5f,0x52,0x93,0xba, +0x80,0xba,0xfe,0x37,0x61,0x49,0x8b,0xba,0xab,0x71,0x47,0x38,0xa6,0x0a,0x8c, +0xba,0xb5,0xf5,0xcc,0x38,0x4a,0xd4,0x97,0xba,0xd4,0xa3,0x7e,0x39,0xc0,0xf3, +0x78,0xba,0xd0,0xff,0xe5,0x39,0xfd,0xf4,0x35,0xba,0xe7,0x82,0x12,0x3a,0x42, +0x81,0x04,0xba,0xa6,0x8e,0x23,0x3a,0x8a,0x80,0xa9,0xb9,0xb7,0x24,0x23,0x3a, +0x14,0x3e,0x71,0xb9,0xcb,0x65,0x3e,0x3a,0x66,0x3f,0x5e,0xb9,0x7c,0x13,0x6d, +0x3a,0xad,0xce,0x44,0xb9,0x15,0x73,0xa5,0x3a,0x91,0xc8,0xdc,0xb8,0xc1,0xb6, +0xa9,0x3a,0x77,0x1f,0x54,0xb8,0x20,0xdd,0x92,0x3a,0x70,0x73,0x06,0xb8,0x11, +0x61,0x93,0x3a,0x0e,0xca,0xcf,0xb7,0x1b,0x5c,0xaa,0x3a,0xec,0x90,0x69,0xb7, +0x29,0x5e,0xdd,0x3a,0xc1,0xe1,0xaa,0xb6,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x7c,0xfa,0x5a,0xf6,0x63,0xf2,0x69,0xe5,0xca,0x61,0x4c,0x6f,0xb0,0x75, +0x44,0x7b,0x2f,0xff,0xd1,0xfa,0xee,0xf5,0x6f,0xee,0xcb,0xe0,0x33,0xe7,0x2e, +0xe6,0x1c,0x53,0x96,0x6e,0xbc,0x76,0x70,0x7d,0x01,0xfa,0xcd,0xf0,0xd0,0xc1, +0x3d,0x6b,0x70,0x70,0x3c,0x73,0x96,0x75,0x47,0x78,0x31,0x79,0xb4,0x7a,0xf9, +0x7b,0x3e,0x7d,0xac,0x7e,0xe6,0xff,0xdd,0xfe,0x1c,0xfe,0x1d,0xfd,0xfe,0xfb, +0xf3,0xfa,0x36,0xfa,0xd8,0xf9,0x51,0xf9,0xaa,0xf8,0x29,0xf8,0x3e,0xf7,0xdf, +0xf5,0x3c,0xf5,0xc9,0xf4,0x31,0xf4,0xb7,0xf3,0xf5,0xf2,0xbc,0xf1,0xa4,0xf0, +0xba,0xef,0x6c,0xee,0xd0,0xed,0x1e,0xed,0x14,0xec,0x1a,0xea,0x66,0xe8,0x46, +0xe7,0x70,0xe6,0x9f,0xe4,0x52,0xe1,0x00,0x00,0x95,0x9c,0x43,0x2e,0x5e,0xb6, +0x27,0x2e,0xdd,0x44,0x11,0x30,0x4f,0x46,0xb2,0x31,0x44,0xc3,0x4e,0x32,0x40, +0xc4,0x0b,0x33,0x6a,0xdd,0x20,0x34,0xb3,0xfa,0x69,0x35,0xa2,0x97,0xb9,0x36, +0x32,0xf9,0xe0,0x36,0xd6,0xfe,0x35,0x36,0xa5,0x3a,0x14,0x34,0xfa,0x2f,0x51, +0x31,0x3f,0x48,0x66,0x2e,0x1e,0x7b,0x21,0x30,0x86,0x3e,0x05,0x32,0xee,0x84, +0x2c,0x32,0x49,0xf8,0x22,0x32,0x61,0x26,0xac,0x30,0x7a,0x5a,0xed,0x2e,0x03, +0x2a,0x23,0x30,0x5e,0xe1,0x0b,0x32,0x2a,0xe3,0x1d,0x32,0x0d,0x1a,0x61,0x32, +0xa8,0xe0,0xe6,0x32,0xcb,0xca,0xd0,0x33,0x23,0xfe,0x59,0x34,0x5b,0x41,0xd5, +0x34,0x7f,0xcc,0xce,0x35,0xbe,0x43,0x20,0x36,0xab,0xec,0xb8,0x36,0x67,0xbd, +0xfe,0x36,0xd7,0x57,0xe6,0x36,0x11,0x59,0xa4,0x36,0xae,0xca,0xd9,0x36,0x0d, +0x98,0x05,0x37,0x09,0x46,0xff,0x36,0x7b,0xd3,0xd9,0x36,0x62,0xca,0x52,0x36, +0xdf,0x88,0x36,0x36,0xb0,0x24,0x45,0x36,0xe5,0xa2,0x3a,0x36,0xf5,0x0b,0x26, +0x36,0x8d,0xa8,0x39,0x36,0xf7,0x3b,0x13,0x36,0x73,0xfb,0xa1,0x35,0x33,0x80, +0xab,0x35,0xd0,0x25,0xbc,0x35,0xfd,0x99,0xe4,0x35,0x48,0xd6,0x2b,0x36,0xe6, +0xa4,0x4a,0x36,0xfd,0xf6,0x2b,0x36,0xe7,0x5e,0x17,0x36,0x39,0xbd,0xf6,0x35, +0x80,0xe4,0xc3,0x35,0x31,0x6c,0xef,0x35,0x4a,0xa7,0x23,0x36,0x32,0x47,0x43, +0x36,0x9d,0x99,0x1c,0x36,0xa7,0x19,0xd3,0x35,0x96,0x69,0xc5,0x35,0xdd,0x8e, +0xea,0x35,0x74,0xaf,0x29,0x36,0x00,0x00,0x00,0x00,0xc9,0xd5,0x7e,0x3c,0x53, +0x72,0x3c,0x40,0xb0,0xe0,0x1c,0x35,0x7c,0xd4,0x9d,0x3e,0xf6,0xc3,0x5e,0x34, +0xbf,0x8c,0x31,0x3d,0x86,0x88,0x2f,0x38,0x88,0x95,0x2f,0x3b,0x27,0x2d,0x7c, +0x3a,0xe4,0xad,0x42,0x3a,0x15,0xb5,0x09,0x3b,0x60,0x2c,0x5f,0x39,0x19,0x27, +0x5f,0x3b,0x21,0x91,0xa2,0x37,0xae,0xc5,0x23,0x3c,0x2a,0xf5,0xcb,0x36,0x93, +0x03,0x06,0x3c,0xa1,0xeb,0x0e,0x38,0x5d,0x86,0xf5,0x3b,0x79,0xe7,0xac,0x35, +0x3c,0x06,0x16,0x3c,0xcc,0x9c,0x2e,0x36,0x8c,0x7a,0x3b,0x3b,0x0d,0xcf,0x15, +0x35,0x11,0xd4,0xbf,0x3a,0x2e,0xd0,0xad,0xb8,0x0f,0x79,0x67,0x3b,0x1e,0x4d, +0x43,0xba,0x6a,0xc4,0xa4,0x3b,0x8f,0x95,0xe8,0xba,0xaa,0x42,0xfe,0x3b,0xec, +0xf2,0x33,0xbb,0x3e,0x74,0x13,0x3c,0xdd,0xfd,0xe5,0xbb,0xb0,0x06,0x46,0x3c, +0xaa,0x79,0x18,0xbc,0x23,0xcc,0x80,0x3c,0x73,0x3e,0x86,0xbc,0x23,0x56,0xab, +0x3c,0x1d,0x79,0x61,0xbc,0xd5,0x0b,0x81,0x3c,0x12,0xd6,0xd5,0xbc,0xa5,0x6c, +0xe4,0x3c,0xbb,0x2f,0x65,0xbd,0x48,0xf5,0x09,0x3d,0x4f,0xec,0xad,0xbd,0x5c, +0xa4,0x60,0x3d,0x42,0x40,0x62,0xbe,0x8e,0x29,0x50,0x3e,0xfb,0xab,0xc4,0xbe, +0x24,0xf3,0x41,0x3f,0x76,0xfa,0x6c,0xbe,0x0c,0x39,0x2c,0x3f,0x6e,0xa9,0x93, +0xbd,0x3f,0xea,0x1a,0x3f,0xd0,0xf2,0x15,0xbe,0x05,0x86,0xa6,0x3f,0xba,0xa2, +0xbc,0xbd,0x78,0xa7,0xb6,0x3f,0xe5,0xc9,0xe0,0xbc,0x0d,0x23,0x8e,0x3f,0xd9, +0x86,0xa7,0xbc,0x59,0x52,0x9a,0x3f,0x1a,0x64,0xfc,0xbc,0x99,0x0e,0x03,0x40, +0x74,0xb5,0xf8,0xbc,0x94,0x3c,0x38,0x40,0x3a,0x1a,0x00,0xbc,0x47,0x7e,0x36, +0x40,0xd2,0xbd,0xf8,0xb8,0x89,0xbf,0x0c,0x40,0xda,0x8b,0xd9,0xb6,0xd2,0xcb, +0xf5,0x3f,0xa7,0x15,0xfb,0xb2,0x58,0x69,0xd2,0x3f,0x32,0x79,0x99,0x29,0xf3, +0x24,0xc8,0x3f,0xcb,0x21,0x79,0x37,0x4f,0x3b,0x81,0x3f,0xfd,0xc0,0xbd,0x38, +0xd8,0x07,0x36,0x3f,0x27,0xeb,0x84,0x38,0x74,0x45,0x14,0x3f,0x65,0xfc,0xe2, +0x32,0x3d,0xbe,0x26,0x3f,0x91,0x9c,0x14,0x30,0xdf,0x6f,0x15,0x3f,0x74,0xf4, +0x10,0x34,0x1c,0xe8,0xec,0x3e,0x2c,0xca,0xa1,0xb3,0xff,0xe4,0x05,0x3f,0x52, +0x20,0x45,0xb8,0x07,0xd1,0x2f,0x3f,0x77,0xd2,0xc9,0xb7,0x67,0xc2,0x35,0x3f, +0xd7,0x84,0xb6,0xb6,0xe5,0x2e,0x32,0x3f,0xa9,0x77,0x7d,0xb5,0xcd,0x72,0x1a, +0x3f,0xf3,0xdb,0x9e,0xb4,0xf2,0xd7,0x02,0x3f,0x2d,0x25,0x00,0xb7,0x6a,0x30, +0x1f,0x3f,0x6e,0x67,0x99,0xb8,0x67,0x3e,0x47,0x3f,0x44,0xc3,0x43,0xb8,0xd8, +0x4f,0x49,0x3f,0xf0,0x69,0x13,0xb7,0xa0,0xb1,0x3b,0x3f,0xb4,0x8a,0xd3,0xb6, +0x67,0x4f,0x4c,0x3f,0xf1,0x8c,0x3f,0xb7,0xfe,0xef,0x53,0x3f,0xab,0xf3,0xd3, +0xb5,0x82,0xc3,0x46,0x3f,0x61,0x49,0xee,0xb5,0xd5,0x5a,0x52,0x3f,0x16,0x34, +0xed,0xb6,0xf1,0x96,0x6b,0x3f,0x8b,0x2e,0x12,0xb6,0x7b,0xd3,0x74,0x3f,0x40, +0x45,0x3e,0xae,0xab,0xf4,0x65,0x3f,0x00,0xa5,0x8b,0x35,0x75,0x86,0x24,0x3f, +0xad,0x56,0x79,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3b,0x7d,0x9f, +0x7f,0x87,0x7f,0xa2,0x7c,0x09,0x77,0x52,0x72,0xba,0x6a,0x32,0x65,0x25,0x6a, +0x6a,0x61,0x98,0x62,0xad,0x61,0x3c,0xf1,0xf4,0xf3,0xb9,0xf5,0xc6,0xf5,0x5c, +0xf7,0x2c,0xf7,0x0b,0xf8,0xd6,0xf6,0xa2,0xf8,0xd0,0xf8,0xf8,0xf8,0xb9,0xf9, +0xe9,0xf8,0x0a,0xf5,0x75,0xf2,0x0d,0xf4,0xa3,0xf1,0x10,0xef,0x8f,0xee,0x01, +0xf0,0x69,0xee,0x07,0xe9,0xa6,0xdd,0x27,0xd6,0x55,0xc7,0x98,0x21,0x58,0x59, +0xe2,0x5f,0xee,0x5f,0x8c,0x49,0x73,0x3d,0xa6,0x4d,0xa5,0xcc,0x41,0xdf,0x16, +0xdc,0x9a,0xd8,0x1e,0xd3,0x99,0xd0,0x23,0xda,0x73,0xe0,0x0a,0xde,0x86,0xd9, +0xe5,0xd8,0x05,0xda,0xb6,0xd3,0x37,0xd4,0xf7,0xd8,0x54,0xd4,0x39,0xb5,0xa0, +0x52,0x04,0x50,0x00,0x00,0xfd,0xd8,0xb1,0x40,0x32,0x86,0x6d,0x3d,0x73,0x20, +0x8e,0x3a,0xb3,0x05,0xd6,0x36,0x85,0x41,0xd2,0x36,0xf2,0x8d,0x04,0x37,0xb3, +0x6c,0x0c,0x37,0xd5,0xaf,0x59,0x38,0xa4,0xfd,0x2d,0x38,0x5e,0xaa,0xf8,0x37, +0xe0,0x84,0x36,0x38,0xf5,0x30,0xa6,0x36,0xd5,0x97,0x56,0x36,0xdd,0xb1,0x16, +0x38,0x8c,0x89,0xb7,0x38,0x92,0x8a,0x46,0x39,0x11,0xfc,0x06,0x3a,0x07,0xe0, +0x63,0x3a,0x24,0xd7,0x28,0x3b,0x8c,0xc1,0x32,0x3b,0x9d,0xcc,0x93,0x3b,0x2c, +0x94,0x7c,0x3c,0xbe,0xba,0xd8,0x3c,0xf0,0x32,0x22,0x3e,0xfc,0xe1,0x40,0x3f, +0xcb,0xdf,0x0f,0x40,0xc5,0xf0,0x50,0x3f,0xb8,0x7f,0x7f,0x3f,0x44,0x25,0x1a, +0x40,0x6f,0x18,0xf7,0x3f,0x18,0xab,0x99,0x3f,0xab,0x63,0xcd,0x3f,0x8e,0xc5, +0x4c,0x40,0xb6,0xa9,0x96,0x40,0xa3,0x33,0x77,0x40,0x36,0xd4,0x1a,0x40,0x36, +0xd5,0xeb,0x3f,0x51,0xda,0xa6,0x3f,0xe4,0x59,0x96,0x3f,0xd6,0xab,0x19,0x3f, +0x48,0x3e,0x9a,0x3e,0x3f,0xf0,0x5e,0x3e,0xf1,0x98,0x7b,0x3e,0x00,0xdf,0x60, +0x3e,0x12,0xec,0x23,0x3e,0x5a,0x07,0x4e,0x3e,0xa9,0x8b,0x8d,0x3e,0x2c,0x4d, +0x95,0x3e,0xd2,0x7e,0x8e,0x3e,0xf6,0xc8,0x68,0x3e,0x28,0x86,0x46,0x3e,0x5b, +0x7d,0x76,0x3e,0x82,0xf3,0xb4,0x3e,0xea,0x94,0xb5,0x3e,0x84,0x04,0x9f,0x3e, +0x30,0xca,0xba,0x3e,0xd0,0xb3,0xc5,0x3e,0x5c,0x00,0xb0,0x3e,0xfb,0x4b,0xc4, +0x3e,0xcc,0xc2,0xed,0x3e,0x90,0x92,0xfc,0x3e,0xe0,0xde,0xe3,0x3e,0x23,0x79, +0x78,0x3e,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5, +0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0xc5,0x00,0x00,0x00, +0xc5,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0xc5,0x00,0x00,0x00,0x00,0x20,0xaa, +0x00,0xa7,0xab,0xa3,0x55,0xa0,0x00,0x9a,0x55,0x8d,0x55,0x0d,0x00,0x1a,0x55, +0x20,0xab,0x23,0x00,0x27,0xa0,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xec,0xab,0x1b,0xa7,0x16,0xa5,0xea,0xa3,0x80,0xa0,0xe0,0xa1,0x28,0xab,0xc5, +0xa6,0x7e,0xa4,0x29,0xa3,0x43,0xa0,0x3f,0xa1,0xac,0xaa,0x8f,0xa6,0x1e,0xa4, +0xae,0xa2,0x1d,0xa0,0xd9,0xa0,0x2f,0xaa,0x59,0xa6,0xbd,0xa3,0x33,0xa2,0xec, +0x9f,0x73,0xa0,0xa1,0xa9,0xec,0xa5,0x3e,0xa3,0x9f,0xa1,0x56,0x9f,0xec,0x9f, +0x7f,0xa8,0x09,0xa4,0xf3,0xa1,0x71,0xa0,0x14,0x9d,0xc0,0x9d,0x89,0xa5,0x79, +0xa1,0x3f,0xa0,0x24,0x9e,0xa6,0x9a,0x24,0x9b,0x8e,0xa1,0x3b,0x9d,0x59,0x9c, +0xd0,0x9a,0x01,0x98,0x5a,0x98,0xe6,0x9b,0xfb,0x97,0x0a,0x98,0x5e,0x96,0xb0, +0x92,0x8a,0x93,0x8d,0x95,0x91,0x90,0x52,0x91,0x72,0x90,0xfb,0x8c,0x23,0x8f, +0x7f,0x91,0x7c,0x8b,0x5d,0x8d,0x31,0x8c,0x97,0x89,0xba,0x8b,0x88,0x00,0x81, +0x00,0x1d,0x81,0xcd,0x80,0x43,0x80,0x64,0x80,0x00,0x00,0xab,0x00,0x55,0x01, +0x00,0x02,0xab,0x02,0x55,0x03,0x00,0x04,0xab,0x04,0x55,0x05,0x00,0x06,0xab, +0x06,0x55,0x07,0x00,0x08,0xab,0x08,0x55,0x09,0x00,0x0a,0xab,0x0a,0x55,0x0b, +0x00,0x0c,0xab,0x0c,0x55,0x0d,0x00,0x0e,0xab,0x0e,0x55,0x0f,0x00,0x10,0x55, +0x10,0xab,0x10,0x00,0x11,0x55,0x11,0xab,0x11,0x00,0x12,0x55,0x12,0xab,0x12, +0x00,0x13,0x55,0x13,0xab,0x13,0x00,0x14,0x55,0x14,0xab,0x14,0x00,0x15,0x55, +0x15,0xab,0x15,0x00,0x16,0x55,0x16,0xab,0x16,0x00,0x17,0x55,0x17,0xab,0x17, +0x00,0x18,0x2b,0x18,0x55,0x18,0x80,0x18,0xab,0x18,0xd5,0x18,0x00,0x19,0x2b, +0x19,0x55,0x19,0x80,0x19,0xab,0x19,0xd5,0x19,0x00,0x1a,0x00,0x1a,0x00,0x1a, +0x00,0x00,0x86,0x01,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66, +0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x80,0xac,0x00,0xa7,0xab,0xa3,0x55,0xa0,0x00,0x9a,0x55, +0x8d,0x55,0x0d,0x00,0x1a,0x55,0x20,0xab,0x23,0x00,0x27,0x60,0x31,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xab,0x65,0xa3,0x8c,0xa0,0x6a,0x9e,0xdf, +0x99,0x75,0xa1,0x9e,0xa8,0xa1,0xa3,0x52,0xa0,0x19,0x9e,0x15,0x9b,0xbe,0x9b, +0x75,0xa8,0x74,0xa3,0x47,0xa0,0x1f,0x9e,0xd8,0x9a,0x1d,0x9b,0x3e,0xa8,0x36, +0xa3,0x3b,0xa0,0x27,0x9e,0x86,0x9a,0x5c,0x9a,0xc7,0xa7,0xc6,0xa2,0x1b,0xa0, +0x1c,0x9e,0x16,0x9a,0xb0,0x99,0x7a,0xa6,0xd7,0xa1,0x52,0x9f,0xa5,0x9d,0x77, +0x99,0x1c,0x99,0x18,0xa4,0x13,0xa0,0x34,0x9d,0x35,0x9c,0x36,0x98,0xbc,0x97, +0x2a,0xa1,0xcb,0x9b,0x2a,0x9a,0xd3,0x99,0xcf,0x94,0x22,0x94,0x7a,0x9c,0x43, +0x97,0xc7,0x95,0xfb,0x95,0xcb,0x90,0x2b,0x90,0xd7,0x96,0xcc,0x90,0x4c,0x90, +0xf1,0x90,0xe7,0x8a,0xe9,0x89,0x36,0x92,0x13,0x8c,0xd4,0x8b,0x6c,0x8d,0x12, +0x88,0x39,0x87,0x73,0x02,0x31,0x02,0x89,0x01,0xad,0x00,0x79,0x01,0xe1,0x01, +0xcd,0x00,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66,0x02,0x66, +0x02,0x66,0x02,0x66,0x02,0x5b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc, +0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0,0xcc,0x00,0x00,0xd0, +0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x00,0x40,0x00,0x00,0x00,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39, +0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee, +0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39, +0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee, +0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39,0xee,0x39, +0xee,0x39,0xee,0x39,0xee,0xe3,0xe5,0x40,0xeb,0xbd,0xec,0xf4,0xeb,0x75,0xec, +0x98,0xed,0x73,0xec,0x81,0xee,0x89,0xf1,0x5f,0xf1,0x15,0xf1,0x5c,0xf0,0x34, +0xed,0xaf,0xeb,0x51,0xed,0x7c,0xee,0x18,0xf0,0xf6,0xf0,0x35,0xf0,0xb2,0xed, +0x0a,0xec,0x29,0xee,0xae,0xf0,0xe0,0xf0,0x0f,0xf0,0xda,0xeb,0x00,0x00,0xcd, +0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7, +0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd, +0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7, +0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd, +0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0xcd,0xa7,0x6a,0xa1, +0xa7,0xa1,0x7c,0xa4,0x35,0xa8,0xad,0xaa,0xae,0xa9,0xc1,0xaa,0x96,0xad,0x98, +0xab,0xfe,0xa8,0xb6,0xa8,0xf9,0xa8,0x7a,0xaa,0x04,0xac,0xe2,0xa9,0x95,0xa7, +0x91,0xa7,0x57,0xa8,0x5c,0xa7,0x07,0xa7,0xbf,0xa7,0x0a,0xa7,0xbb,0xa5,0x29, +0xa5,0x6a,0xa5,0x62,0xa7,0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00, +0x80,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x55,0x68,0x2c,0x63,0xec,0x63,0x27, +0x6c,0xce,0x75,0x90,0x82,0x5e,0x89,0xb4,0x8b,0x05,0x88,0x96,0x88,0xc5,0x8b, +0x79,0x8a,0x77,0x86,0xc1,0x81,0x40,0x7f,0x20,0x80,0x98,0x81,0xb1,0x81,0xfb, +0x7e,0xd6,0x77,0xe6,0x6f,0xf5,0x5f,0x82,0x52,0x07,0x56,0xdd,0x56,0xf5,0x55, +0x70,0x54,0x1e,0x53,0xc7,0x55,0xac,0x55,0x3b,0x55,0xb0,0x52,0x4d,0x51,0x81, +0x4e,0xaa,0x4e,0x0a,0x4f,0x53,0x4c,0x3a,0x4e,0x11,0x50,0x2f,0x50,0xc9,0x4d, +0x4c,0x4c,0x58,0x48,0x65,0x4a,0xe7,0x4a,0x5f,0x4b,0xc3,0x49,0xd5,0x48,0xce, +0x47,0x7b,0x45,0xaf,0x43,0x06,0x42,0xda,0x40,0x05,0x41,0x62,0x41,0x76,0x39, +0xe5,0x37,0xc5,0x3a,0x88,0x39,0xeb,0x50,0xd6,0x5f,0x0f,0x60,0xd5,0x64,0x00, +0x00,0xfb,0xd8,0x7d,0xe1,0x72,0xe7,0x22,0xf1,0x98,0xf4,0x56,0xf2,0x05,0xf3, +0x97,0xf7,0x09,0xf7,0x7c,0xe7,0x9e,0xd9,0x53,0xcf,0xbe,0xcc,0x01,0xc6,0x72, +0xc1,0xf7,0xc0,0xc8,0xc1,0x5f,0xc2,0x9b,0xc3,0x35,0xc7,0xab,0xca,0x3b,0xd0, +0x78,0xd5,0x67,0xda,0xdd,0xe0,0x63,0xd7,0xb5,0xd1,0x3f,0xcc,0x8e,0xc7,0x29, +0xcc,0x70,0xc6,0x36,0xc1,0x04,0xbf,0x9a,0xba,0x1c,0xb9,0xbf,0xb4,0x7a,0xb2, +0x8b,0xb0,0x21,0xb1,0xa7,0xb0,0xb4,0xa8,0xe9,0xa4,0x77,0xa6,0x36,0xa3,0x56, +0xa3,0x5a,0xa1,0x4f,0x9d,0xdb,0x96,0xea,0x8f,0x64,0x86,0xaf,0x85,0xa6,0x84, +0x2a,0x95,0x05,0xa0,0x6e,0xb1,0x16,0x9d,0xdc,0xab,0xa5,0xb0,0xee,0xb7,0x29, +0xbb,0x6d,0xbc,0x90,0xbd,0x90,0xbd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00, +0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x01,0x00,0x00,0x1c,0x02,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x01,0x00,0x00,0xfe, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x01,0x00, +0x00,0x10,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x75,0x5a, +0xa1,0x58,0xd6,0x57,0x63,0x57,0x0c,0x58,0x17,0x57,0xbb,0x56,0x7b,0x57,0x01, +0x56,0xc4,0x54,0x34,0x54,0xb9,0x53,0x20,0x53,0x71,0x53,0xc5,0x52,0xb4,0x52, +0xcd,0x52,0x65,0x52,0x5e,0x53,0x9c,0x53,0x64,0x52,0xb4,0x52,0xd2,0x52,0xc7, +0x52,0xd1,0x51,0x03,0x52,0xfe,0x50,0x0b,0x51,0x8e,0x54,0x05,0x55,0x0b,0x55, +0x0f,0x55,0xa6,0x55,0xb7,0x56,0x7b,0x57,0x9a,0x56,0xcf,0x57,0x7e,0x58,0xb0, +0x58,0x82,0x5b,0x10,0x5e,0x9b,0x5c,0x0a,0x5c,0x80,0x5e,0x80,0x61,0xac,0x64, +0x06,0x65,0x4c,0x66,0xa4,0x67,0xf8,0x64,0xbe,0x66,0xac,0x6b,0xdf,0x6a,0xce, +0x6e,0x6c,0x70,0x93,0x74,0x5a,0x76,0x2c,0x7b,0x18,0x82,0x68,0x87,0x50,0x8f, +0x6b,0x93,0xc0,0x9a,0x00,0x00,0x87,0xa5,0x2b,0xa5,0xfe,0xa6,0x6e,0xaa,0xd9, +0xaf,0x04,0xb3,0x5b,0xb2,0xa2,0xad,0x4a,0xa8,0xf7,0xa5,0xf0,0xa4,0x5d,0xa4, +0x7b,0xa2,0x4a,0xa0,0x53,0x9e,0xf9,0x9c,0x3c,0x9d,0xb3,0x9b,0x27,0x9a,0xc1, +0x9a,0x94,0x9b,0x43,0x9b,0x0b,0x9a,0x06,0x9a,0xa5,0x9b,0xf2,0x9b,0xdc,0x9a, +0x4c,0x9a,0xbb,0x9a,0x46,0x9c,0xf1,0x9f,0xee,0x9e,0x4a,0x9e,0xd2,0x9d,0x92, +0x9b,0x19,0x9c,0x07,0x9f,0x26,0x9e,0x6c,0x9d,0x3f,0x9e,0x97,0x9e,0xc6,0x9f, +0x44,0xa0,0x48,0xa1,0xac,0xa1,0xf8,0xa1,0x66,0xa2,0xd2,0xa2,0xf0,0xa4,0xe2, +0xa6,0xf2,0xa7,0x73,0xab,0x45,0xac,0x04,0xab,0x57,0xae,0x01,0xb2,0xce,0xb2, +0x1a,0xb5,0xde,0xb5,0xab,0xb6,0x1d,0xb7,0xad,0xb7,0x64,0xb2,0x00,0x00,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31, +0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24,0x31,0x24, +0x31,0x24,0x31,0x24,0x31,0x00,0x00,0x0b,0x55,0xba,0x53,0xe8,0x53,0xa5,0x53, +0xc6,0x53,0x4d,0x54,0xe0,0x54,0x48,0x54,0xf1,0x53,0x3a,0x54,0x0e,0x54,0xd9, +0x54,0x71,0x54,0x83,0x54,0xec,0x55,0x31,0x58,0x9d,0x58,0x83,0x59,0xbc,0x5a, +0x08,0x59,0xa0,0x58,0x82,0x57,0x81,0x55,0x1d,0x55,0xa2,0x53,0xe0,0x53,0x64, +0x53,0x10,0x55,0x6a,0x55,0x4a,0x54,0x63,0x55,0x11,0x58,0x3e,0x57,0x27,0x56, +0x14,0x56,0x15,0x56,0x48,0x56,0x71,0x57,0xc8,0x58,0x42,0x58,0x5f,0x58,0x8a, +0x5a,0x06,0x5c,0xd1,0x5b,0x1e,0x60,0xa9,0x60,0x29,0x62,0x28,0x66,0x9b,0x66, +0x7d,0x65,0xe2,0x67,0x2c,0x6a,0xd9,0x6b,0xc7,0x6f,0xe7,0x70,0x69,0x72,0x57, +0x75,0x7a,0x7d,0x56,0x80,0x36,0x86,0xa8,0x8b,0x7c,0x92,0x5a,0x9b,0x00,0x00, +0x75,0xb1,0xc3,0xac,0xd5,0xab,0xc0,0xad,0xc8,0xad,0xb3,0xa9,0x26,0xa7,0xa8, +0xa3,0xf5,0xa1,0xe6,0xa0,0x1d,0xa0,0xda,0x9f,0x3d,0x9e,0xd4,0x9d,0xca,0x9c, +0xb8,0x9c,0x44,0x9c,0x8b,0x9a,0x35,0x9b,0xba,0x9b,0x09,0x9c,0xe4,0x9c,0x2e, +0x9c,0xd6,0x9d,0x32,0x9e,0x3f,0x9d,0x68,0x9d,0xd2,0x9e,0x8c,0x9d,0x48,0x9e, +0x23,0xa0,0x01,0xa1,0x2b,0xa1,0xab,0xa0,0xa9,0xa0,0x53,0xa2,0x4d,0xa5,0x8b, +0xa3,0x78,0xa2,0xd9,0xa1,0xb1,0xa2,0x72,0xa3,0xc3,0xa3,0x3c,0xa4,0x83,0xa4, +0xec,0xa4,0xf9,0xa6,0x91,0xa7,0x10,0xaa,0x0d,0xab,0x30,0xac,0x95,0xab,0xc0, +0xac,0xd2,0xb0,0xce,0xb2,0xd6,0xb4,0x5d,0xb5,0xc3,0xb6,0x27,0xb8,0x23,0xb8, +0xe1,0xb6,0xd0,0xb7,0xc4,0xb3,0x00,0x00,0x90,0x01,0x90,0x01,0x90,0x01,0x90, +0x01,0x58,0x00,0x58,0x00,0x90,0x01,0x90,0x01,0x58,0x00,0x58,0x00,0x00,0x10, +0x00,0x10,0xf4,0x10,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x00,0x00,0x40,0x00, +0x40,0x00,0x40,0x00,0x80,0x00,0x40,0xb0,0x7d,0x05,0x20,0x78,0xd0,0x05,0x20, +0x34,0x01,0x00,0x00,0x44,0x55,0x05,0x20,0x00,0x00,0x80,0x48,0x00,0x00,0x00, +0xc0,0xf0,0xd8,0xff,0xff,0xff,0xf0,0x00,0x00,0x0f,0xff,0x00,0x00,0xff,0x0f, +0x00,0x00,0xf0,0xff,0x00,0x00,0x8c,0x65,0x05,0x20,0x64,0x7e,0x05,0x20,0xc0, +0x7d,0x05,0x20,0x88,0x63,0x19,0x20,0xb0,0x62,0x19,0x20,0x40,0x9e,0x19,0x20, +0x28,0x39,0x19,0x20,0x60,0x34,0x19,0x20,0x90,0x33,0x19,0x20,0x90,0x03,0x08, +0x20,0xe8,0x0c,0x08,0x20,0x00,0x00,0x00,0x40,0x68,0x46,0x19,0x20,0x00,0x00, +0xe0,0xca,0x00,0x00,0x40,0xc9,0x30,0x47,0x19,0x20,0x9c,0xf3,0x18,0x20,0xdc, +0xf5,0x18,0x20,0x74,0xf5,0x18,0x20,0x18,0xe8,0x18,0x20,0xbc,0xf2,0x18,0x20, +0x04,0xee,0x18,0x20,0xd0,0x25,0x19,0x20,0xa8,0x0d,0x19,0x20,0xa8,0xd2,0x18, +0x20,0x50,0xe6,0x18,0x20,0x6c,0xce,0x18,0x20,0x14,0xcd,0x18,0x20,0x50,0xc0, +0x18,0x20,0x48,0xd1,0x18,0x20,0x5c,0x0e,0x08,0x20,0x18,0x54,0x19,0x20,0xc0, +0x69,0x19,0x20,0x4c,0xbf,0x18,0x20,0x34,0xbc,0x18,0x20,0x04,0xb7,0x18,0x20, +0xbc,0xb5,0x18,0x20,0x14,0xbf,0x18,0x20,0xb0,0xbd,0x18,0x20,0xc0,0xb1,0x18, +0x20,0x74,0xb1,0x18,0x20,0xd4,0xae,0x18,0x20,0x18,0xad,0x18,0x20,0xb8,0x07, +0x19,0x20,0x9c,0x07,0x19,0x20,0x88,0x04,0x19,0x20,0x24,0x04,0x19,0x20,0x14, +0xfd,0x18,0x20,0xd4,0xfe,0x18,0x20,0x28,0xfa,0x18,0x20,0xd4,0xe5,0x18,0x20, +0x1c,0x0e,0x08,0x20,0x88,0xe4,0x18,0x20,0x58,0xe4,0x18,0x20,0x78,0xe1,0x18, +0x20,0x88,0x64,0x19,0x20,0x78,0x66,0x19,0x20,0xd8,0x8d,0x19,0x20,0x08,0x8f, +0x19,0x20,0x44,0x90,0x19,0x20,0x24,0x10,0x08,0x20,0xe0,0xf7,0x18,0x20,0x58, +0xf6,0x18,0x20,0x78,0x0b,0x19,0x20,0x08,0x09,0x19,0x20,0x58,0x7a,0x19,0x20, +0x50,0x79,0x19,0x20,0x74,0x19,0x05,0x20,0x30,0x1b,0x05,0x20,0x00,0x00,0x80, +0x46,0xba,0x49,0x0c,0x2c,0x05,0xa3,0x02,0x43,0xb4,0x54,0xa8,0x3a,0xba,0x49, +0x0c,0x26,0x33,0x33,0x33,0x39,0xb4,0x54,0xa8,0x3c,0x10,0x01,0x05,0x20,0x50, +0x9b,0x18,0x20,0x30,0x9a,0x18,0x20,0x34,0x95,0x18,0x20,0xc8,0x94,0x18,0x20, +0xe0,0x91,0x18,0x20,0x6c,0x1b,0x05,0x20,0xec,0x10,0x05,0x20,0x84,0x06,0x05, +0x20,0x44,0x1b,0x05,0x20,0x88,0x65,0x05,0x20,0x40,0x1f,0x00,0x00,0x50,0xe3, +0x17,0x20,0x80,0x3e,0x00,0x00,0xb0,0xe3,0x17,0x20,0x00,0x01,0x05,0x20,0x00, +0x80,0xff,0xff,0x82,0x1a,0x05,0x20,0xff,0xff,0x00,0x00,0x70,0x15,0x05,0x20, +0x50,0x0b,0x05,0x20,0x9a,0x19,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x0d,0x00, +0x00,0x00,0x0a,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x0c, +0x00,0x00,0x14,0x5a,0x05,0x20,0x00,0x0f,0x00,0x00,0x00,0x10,0x00,0x00,0xf8, +0x64,0x05,0x20,0xff,0x7f,0x00,0x00,0x44,0x18,0x05,0x20,0x20,0x5b,0x05,0x20, +0x18,0x64,0x05,0x20,0xc4,0x74,0x05,0x20,0x24,0x19,0x05,0x20,0x30,0x64,0x05, +0x20,0x00,0x12,0x00,0x00,0x14,0x19,0x05,0x20,0x44,0x14,0x05,0x20,0x4a,0x5b, +0x05,0x20,0x48,0x18,0x05,0x20,0x00,0x00,0x05,0x20,0xe4,0xe4,0x00,0x00,0x00, +0xfe,0xff,0x0f,0x20,0x5a,0x05,0x20,0xcd,0xab,0x00,0x00,0xde,0xbc,0x00,0x00, +0x00,0xfe,0xff,0x3f,0xb0,0x7d,0x05,0x20,0x24,0x5a,0x05,0x20,0x52,0x80,0x00, +0x00,0x44,0x14,0x03,0x20,0x24,0x80,0x00,0x00,0x2c,0x80,0x00,0x00,0x32,0x80, +0x00,0x00,0x33,0x80,0x00,0x00,0x34,0x80,0x00,0x00,0x35,0x80,0x00,0x00,0x36, +0x80,0x00,0x00,0x37,0x80,0x00,0x00,0x38,0x80,0x00,0x00,0x3d,0x80,0x00,0x00, +0x3e,0x80,0x00,0x00,0x3f,0x80,0x00,0x00,0x30,0x5a,0x05,0x20,0x00,0x00,0x01, +0x00,0xd8,0x5b,0x05,0x20,0xb0,0x5b,0x05,0x20,0x6c,0x5a,0x05,0x20,0x4c,0x66, +0x05,0x20,0x3c,0x5a,0x05,0x20,0x08,0x42,0x08,0x20,0x08,0x01,0x05,0x20,0x94, +0x40,0x08,0x20,0x00,0x00,0x11,0x00,0x04,0x1b,0x05,0x20,0xbc,0x1c,0x05,0x20, +0x8c,0xaf,0x00,0x00,0x98,0x65,0x05,0x20,0x8c,0x67,0x05,0x20,0x34,0x7e,0x05, +0x20,0xa0,0x65,0x05,0x20,0x4c,0x1b,0x05,0x20,0xe4,0x64,0x05,0x20,0x00,0x09, +0x00,0x00,0x1c,0x20,0x08,0x20,0x0c,0x6e,0x08,0x20,0x06,0x00,0x44,0x00,0x07, +0x00,0x19,0x00,0x70,0x7b,0x05,0x20,0x30,0xad,0x05,0x20,0x3c,0xf4,0xfd,0x3f, +0x64,0x94,0x08,0x20,0xf0,0x80,0x05,0x20,0x10,0x81,0x05,0x20,0x04,0x78,0x08, +0x20,0xe4,0x69,0x08,0x20,0x28,0x41,0x08,0x20,0xe4,0x90,0x08,0x20,0xb0,0x7d, +0x05,0x20,0x78,0xd0,0x05,0x20,0x44,0x55,0x05,0x20,0xa8,0x7d,0x05,0x20,0x0c, +0x70,0x08,0x20,0xad,0xc0,0x08,0x20,0x30,0x6e,0x08,0x20,0x08,0x8b,0x08,0x20, +0x00,0x00,0x18,0x20,0x00,0x00,0x02,0x00,0x60,0x7b,0x05,0x20,0xc0,0xc6,0x05, +0x20,0xf0,0xb5,0x05,0x20,0x30,0xb7,0x05,0x20,0x70,0xbd,0x05,0x20,0x70,0xb8, +0x05,0x20,0x70,0xc2,0x05,0x20,0xb0,0xb9,0x05,0x20,0xb0,0xbe,0x05,0x20,0xa0, +0x7b,0x05,0x20,0xc4,0x7d,0x05,0x20,0x38,0x66,0x05,0x20,0x40,0x5c,0x05,0x20, +0xd0,0x76,0x05,0x20,0xf0,0xc4,0x05,0x20,0x70,0xc5,0x05,0x20,0x90,0x7e,0x05, +0x20,0x70,0xc6,0x05,0x20,0xc0,0x76,0x05,0x20,0xc0,0x7b,0x05,0x20,0xd0,0x7b, +0x05,0x20,0xa0,0xc6,0x05,0x20,0xf0,0xc5,0x05,0x20,0xe0,0xc6,0x05,0x20,0x90, +0xac,0x05,0x20,0xe0,0x7b,0x05,0x20,0x40,0xc7,0x05,0x20,0x00,0xc8,0x05,0x20, +0xff,0xf7,0xff,0xff,0x10,0x55,0x05,0x20,0x12,0x83,0x00,0x40,0x84,0x80,0x05, +0x20,0x03,0x20,0x00,0x00,0x80,0xad,0x08,0x20,0x38,0x9e,0x08,0x20,0x18,0x9e, +0x08,0x20,0xd8,0x9e,0x08,0x20,0x58,0x9e,0x08,0x20,0xec,0xa6,0x08,0x20,0xf4, +0xa3,0x08,0x20,0xb4,0x81,0x08,0x20,0xc8,0x7d,0x05,0x20,0x60,0x84,0x08,0x20, +0x88,0x82,0x08,0x20,0x5c,0xad,0x08,0x20,0xd0,0x80,0x05,0x20,0xd8,0x7d,0x05, +0x20,0x6c,0x9c,0x08,0x20,0x54,0x9c,0x08,0x20,0xa4,0xab,0x05,0x20,0x34,0x7e, +0x05,0x20,0x80,0xce,0x05,0x20,0xb5,0x7e,0x05,0x20,0x00,0x08,0x00,0x00,0xdc, +0xc4,0x05,0x20,0xab,0xaa,0x02,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x08,0x00, +0x00,0x00,0x20,0x00,0x00,0x00,0x10,0x00,0x55,0x55,0x05,0x00,0x00,0x00,0x30, +0x00,0x6e,0xdb,0xfe,0xff,0x6e,0xdb,0xde,0x00,0x50,0x7c,0x05,0x20,0x00,0x1f, +0x00,0x40,0x84,0xce,0x05,0x20,0x12,0x34,0x00,0x00,0xc0,0xce,0x05,0x20,0x00, +0x0e,0x00,0x10,0xac,0x5b,0x05,0x20,0x70,0x7c,0x05,0x20,0x94,0x92,0x08,0x20, +0xe0,0xce,0x05,0x20,0x00,0x3e,0x00,0x40,0x00,0x1e,0x00,0x40,0x00,0x20,0x00, +0x40,0xc0,0x7c,0x05,0x20,0x04,0x20,0x00,0x40,0x40,0xd0,0x05,0x20,0x62,0x66, +0x05,0x20,0xb0,0xcf,0x05,0x20,0xf0,0xce,0x05,0x20,0x10,0xd0,0x05,0x20,0x4e, +0x66,0x05,0x20,0x90,0x7c,0x05,0x20,0x70,0x7d,0x05,0x20,0x00,0x00,0x00,0x80, +0xff,0xff,0xff,0x00,0xb0,0x1e,0x00,0x40,0x50,0x7d,0x05,0x20,0x80,0x7c,0x05, +0x20,0xf0,0x7c,0x05,0x20,0x00,0xff,0x00,0x00,0x00,0x18,0x00,0x00,0x68,0x5c, +0x05,0x20,0x9c,0x5c,0x05,0x20,0xd0,0x5c,0x05,0x20,0x04,0x5d,0x05,0x20,0x70, +0xd0,0x05,0x20,0x88,0xb0,0x08,0x20,0x94,0xb1,0x08,0x20,0x80,0xb4,0x08,0x20, +0xc0,0xb5,0x08,0x20,0x18,0xb3,0x08,0x20,0x10,0xb6,0x08,0x20,0x74,0xd0,0x05, +0x20,0x63,0x72,0x73,0x61,0x00,0x00,0x10,0x01,0xf0,0xf0,0x00,0x00,0x00,0x00, +0x50,0x01,0x64,0x1b,0x05,0x20,0x04,0x7e,0x05,0x20,0x02,0x00,0x00,0x00,0x14, +0x5a,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0x08,0x00,0x00, +0x20,0x5a,0x05,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xff,0xff,0xfe,0x87,0x00, +0x00,0x01,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xf0,0xff,0x00,0x00,0xfc,0xff,0xd0,0x6f,0x30,0x06,0x00, +0x00,0x30,0x06,0x00,0x00,0xb5,0xd3,0x75,0xb5,0x04,0x00,0x00,0x00,0x02,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x8f,0x6f,0x03,0x00,0x96,0x8f,0x0c, +0x00,0xbf,0xe6,0x00,0x00,0x44,0x4d,0x07,0x00,0x05,0xd3,0x02,0x00,0xe8,0x3a, +0x08,0x00,0x43,0x84,0x0c,0x00,0x66,0x5d,0x0f,0x00,0x57,0xc6,0x00,0x00,0xfa, +0x83,0x05,0x00,0x48,0x99,0x0a,0x00,0x84,0x0d,0x0e,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd5, +0x75,0xb5,0xd3,0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x75,0x75,0x75,0xb5, +0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x75,0x75,0xd3,0xdf,0x0c,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x75,0x75,0x75,0xd3,0x01,0x00,0x00,0x00,0x0c,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0c,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xd3,0x75,0x75,0xb5,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x01,0x00,0x00,0xfa,0x01,0x00,0x00, +0x41,0x00,0x00,0x00,0x8c,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0f,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x75,0xd3,0x75,0xb5,0x00,0xf8, +0x24,0x01,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x09,0x00,0x00,0x00, +0x18,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x6a,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xfa,0x00,0x00,0x00,0x02,0x00, +0x00,0x00,0x10,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xd5,0x75,0x75,0xb5,0x1a,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x3a,0x0e,0x00,0x00,0x14,0x01,0x00,0x00,0x73,0xfa,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3a,0x0e,0x00,0x00,0x82,0x00,0x00, +0x00,0x0c,0x17,0x00,0x00,0xf8,0x3d,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x3a,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3a,0x0e,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x0b,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f, +0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00, +0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82, +0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0, +0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00, +0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00, +0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00, +0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00, +0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00, +0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35, +0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c, +0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f, +0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00, +0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00, +0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00, +0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00, +0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00, +0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35, +0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c, +0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f, +0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17, +0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00, +0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00, +0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00, +0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00, +0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00, +0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35, +0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c, +0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f, +0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00, +0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17, +0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00, +0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00, +0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00, +0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f, +0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00, +0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82, +0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c, +0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f, +0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00, +0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17, +0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00, +0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00, +0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00, +0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f, +0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00, +0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82, +0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0, +0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x35,0x0f,0x00,0x00,0x82,0x00, +0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3f,0x00,0x00, +0x00,0x35,0x0f,0x00,0x00,0x82,0x00,0x00,0x00,0x0c,0x17,0x00,0x00,0xf0,0x01, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x38, +0x5d,0x05,0x20,0x78,0x5f,0x05,0x20,0xb8,0x61,0x05,0x20,0xf8,0x63,0x05,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x20,0x00,0x10,0x00,0x20,0x00,0x10,0x00,0x20,0x00,0x10,0x00,0x20,0x00, +0x10,0x00,0x20,0x00,0x10,0x00,0x20,0x00,0x10,0x00,0x20,0x00,0x10,0x00,0x20, +0x00,0x10,0x00,0xf0,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0x0d,0x00,0x0d,0x00,0x0b,0x00,0x0b,0x00,0x0c,0x00,0x0c,0x00, +0x0a,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x00,0x00,0x40,0x01,0x00, +0x00,0xa0,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0x50,0x00, +0x00,0x00,0x40,0x1f,0x00,0x00,0x80,0xe5,0x07,0x20,0xa0,0xe5,0x07,0x20,0x50, +0xe5,0x07,0x20,0x19,0x00,0x00,0x00,0x90,0xaa,0x18,0x20,0x74,0xac,0x18,0x20, +0xb0,0xab,0x18,0x20,0x80,0xdf,0x18,0x20,0x30,0xd3,0x18,0x20,0x98,0x6b,0x19, +0x20,0x90,0x6d,0x19,0x20,0xa8,0x71,0x19,0x20,0x50,0xa5,0x18,0x20,0x9c,0xa9, +0x18,0x20,0x0c,0xa3,0x18,0x20,0xec,0xa3,0x18,0x20,0x80,0xa8,0x18,0x20,0x04, +0xa8,0x18,0x20,0x98,0xa7,0x18,0x20,0x80,0xa2,0x18,0x20,0xa0,0xa1,0x18,0x20, +0x24,0xe0,0x18,0x20,0xfc,0xe0,0x18,0x20,0xa0,0xa0,0x18,0x20,0x7c,0xa0,0x18, +0x20,0x58,0xa0,0x18,0x20,0x34,0xa0,0x18,0x20,0x04,0xa0,0x18,0x20,0xd4,0x9f, +0x18,0x20,0x60,0xa1,0x18,0x20,0x30,0xa1,0x18,0x20,0x3c,0x9f,0x18,0x20,0xf8, +0x9c,0x18,0x20,0x04,0x9e,0x18,0x20,0xcc,0x9d,0x18,0x20,0x18,0x9d,0x18,0x20, +0x70,0x9d,0x18,0x20,0xa0,0x9c,0x18,0x20,0x58,0x9c,0x18,0x20,0xf8,0x66,0x05, +0x20,0x64,0x7e,0x05,0x20,0x01,0x00,0x00,0x00,0xe8,0x9f,0x19,0x20,0x94,0xa3, +0x19,0x20,0xdc,0xa3,0x19,0x20,0xe8,0x9f,0x19,0x20,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5c,0x03,0x05,0x20, +0x0d,0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x60,0x03,0x05,0x20,0x00,0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x33,0x00, +0x00,0x00,0x40,0x1f,0x05,0x20,0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27, +0xfe,0x11,0x40,0x7b,0x2a,0x9c,0x3f,0x7a,0xde,0x05,0x40,0x77,0x35,0x9b,0x3f, +0xbe,0xed,0x05,0x40,0xed,0x93,0xdd,0x3f,0xed,0xf2,0x01,0x40,0x05,0x00,0x00, +0x00,0x05,0x00,0x00,0x00,0xb0,0x1f,0x05,0x20,0x3a,0x37,0x01,0x3e,0x5d,0x83, +0x60,0x40,0x05,0x00,0x00,0x00,0xe0,0x1d,0x05,0x20,0x05,0x00,0x00,0x00,0xd0, +0x1f,0x05,0x20,0x05,0x00,0x00,0x00,0x10,0x1e,0x05,0x20,0x00,0x00,0x00,0x05, +0x01,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xf0,0x1f,0x05,0x20,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc, +0xcc,0x3e,0x00,0x00,0x00,0x43,0x03,0x00,0x00,0x00,0x60,0x20,0x05,0x20,0x03, +0x00,0x00,0x00,0x70,0x20,0x05,0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x40,0x7e,0x05,0x20,0x0d,0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x62,0x03,0x05,0x20,0x00,0x00,0x00,0x00,0x62, +0x27,0x76,0x38,0x33,0x00,0x00,0x00,0x80,0x20,0x05,0x20,0x00,0x00,0x00,0x00, +0xfb,0xd4,0xc7,0x3f,0xfd,0x96,0x00,0x40,0xfb,0xd4,0xc7,0x3f,0xfd,0x96,0x00, +0x40,0xfb,0xd4,0xc7,0x3f,0xfd,0x96,0x00,0x40,0xfb,0xd4,0xc7,0x3f,0xfd,0x96, +0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x7e,0x05,0x20,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x7e,0x05,0x20, +0x00,0x00,0x00,0x00,0x40,0x7e,0x05,0x20,0x00,0x00,0x00,0x00,0x40,0x7e,0x05, +0x20,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x7e, +0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0xf0,0x20,0x05,0x20,0x03,0x00,0x00,0x00,0xf0,0x20,0x05,0x20,0x00,0x00,0x00, +0x40,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x64,0x03,0x05,0x20,0x0d,0x00,0x00,0x00,0x33, +0x33,0x33,0x3f,0x1e,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x21,0x05,0x20, +0x00,0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x33,0x00,0x00,0x00,0x40,0x1f,0x05, +0x20,0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe,0x11,0x40,0x7b,0x2a, +0x9c,0x3f,0x7a,0xde,0x05,0x40,0x77,0x35,0x9b,0x3f,0xbe,0xed,0x05,0x40,0xed, +0x93,0xdd,0x3f,0xed,0xf2,0x01,0x40,0x0c,0x00,0x00,0x00,0x0c,0x00,0x00,0x00, +0x70,0x21,0x05,0x20,0x3a,0x37,0x01,0x3e,0x06,0x93,0xfd,0x41,0x0c,0x00,0x00, +0x00,0xe0,0x1d,0x05,0x20,0x0c,0x00,0x00,0x00,0xa0,0x21,0x05,0x20,0x0c,0x00, +0x00,0x00,0x10,0x1e,0x05,0x20,0x00,0x00,0x00,0x05,0x01,0x00,0x00,0x00,0x33, +0x00,0x00,0x00,0xf0,0x1f,0x05,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x0c,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc,0x3e,0x00,0x00,0x00, +0x43,0x03,0x00,0x00,0x00,0xf0,0x20,0x05,0x20,0x03,0x00,0x00,0x00,0xf0,0x20, +0x05,0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x03,0x05,0x20, +0x0d,0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x6c,0x03,0x05,0x20,0x00,0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x33,0x00, +0x00,0x00,0x40,0x1f,0x05,0x20,0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27, +0xfe,0x11,0x40,0x7b,0x2a,0x9c,0x3f,0x7a,0xde,0x05,0x40,0x8e,0x69,0xee,0x3e, +0x27,0xfe,0x11,0x40,0x7b,0x2a,0x9c,0x3f,0x7a,0xde,0x05,0x40,0x05,0x00,0x00, +0x00,0x05,0x00,0x00,0x00,0xb0,0x1f,0x05,0x20,0x3a,0x37,0x01,0x3e,0x5d,0x83, +0x60,0x40,0x05,0x00,0x00,0x00,0xe0,0x1d,0x05,0x20,0x05,0x00,0x00,0x00,0xd0, +0x1f,0x05,0x20,0x05,0x00,0x00,0x00,0x10,0x1e,0x05,0x20,0x00,0x00,0x00,0x05, +0x01,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xf0,0x1f,0x05,0x20,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc, +0xcc,0x3e,0x00,0x00,0x00,0x43,0x03,0x00,0x00,0x00,0xd0,0x21,0x05,0x20,0x03, +0x00,0x00,0x00,0xe0,0x21,0x05,0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x40,0x7e,0x05,0x20,0x0d,0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x6e,0x03,0x05,0x20,0x00,0x00,0x00,0x40,0x62, +0x27,0x76,0x38,0x33,0x00,0x00,0x00,0xf0,0x21,0x05,0x20,0x02,0x00,0x00,0x00, +0x95,0x8f,0x63,0x3f,0xfd,0x52,0x5c,0x40,0x95,0x8f,0x63,0x3f,0xfd,0x52,0x5c, +0x40,0x95,0x8f,0x63,0x3f,0xfd,0x52,0x5c,0x40,0x95,0x8f,0x63,0x3f,0xfd,0x52, +0x5c,0x40,0x05,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xb0,0x1f,0x05,0x20,0xd3, +0x8c,0xa4,0x3e,0x80,0xf1,0x06,0x41,0x05,0x00,0x00,0x00,0xe0,0x1d,0x05,0x20, +0x05,0x00,0x00,0x00,0xd0,0x1f,0x05,0x20,0x05,0x00,0x00,0x00,0x10,0x1e,0x05, +0x20,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x7e, +0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0xf0,0x20,0x05,0x20,0x03,0x00,0x00,0x00,0xf0,0x20,0x05,0x20,0x00,0x00,0x00, +0x40,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x70,0x03,0x05,0x20,0x0d,0x00,0x00,0x00,0xcd, +0xcc,0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x74,0x03,0x05,0x20, +0x00,0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x33,0x00,0x00,0x00,0x40,0x1f,0x05, +0x20,0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe,0x11,0x40,0x7b,0x2a, +0x9c,0x3f,0x7a,0xde,0x05,0x40,0x77,0x35,0x9b,0x3f,0xbe,0xed,0x05,0x40,0xed, +0x93,0xdd,0x3f,0xed,0xf2,0x01,0x40,0x05,0x00,0x00,0x00,0x05,0x00,0x00,0x00, +0xb0,0x1f,0x05,0x20,0x3a,0x37,0x01,0x3e,0x5d,0x83,0x60,0x40,0x05,0x00,0x00, +0x00,0xe0,0x1d,0x05,0x20,0x05,0x00,0x00,0x00,0xd0,0x1f,0x05,0x20,0x05,0x00, +0x00,0x00,0x10,0x1e,0x05,0x20,0x00,0x00,0x00,0x05,0x01,0x00,0x00,0x00,0x33, +0x00,0x00,0x00,0xf0,0x1f,0x05,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0x0c,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc,0x3e,0x00,0x00,0x00, +0x43,0x03,0x00,0x00,0x00,0xf0,0x20,0x05,0x20,0x03,0x00,0x00,0x00,0xf0,0x20, +0x05,0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33, +0x33,0x33,0xb7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x00,0x00,0x00,0x60,0x22,0x05,0x20,0x19,0xf4,0xff,0x3f,0x00,0x00, +0x00,0x32,0x00,0x00,0x00,0x4e,0x00,0x00,0x80,0x48,0x00,0x00,0x00,0x00,0x00, +0x9a,0x99,0x3f,0xcd,0xcc,0x8c,0x48,0xcd,0xcc,0x8c,0x44,0x00,0x00,0x00,0x3e, +0x07,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x14,0x00,0x00, +0x00,0x22,0x00,0x00,0x00,0x66,0x66,0x66,0x3f,0x00,0x00,0x00,0x3e,0x00,0x00, +0x00,0x00,0x33,0x33,0x33,0x39,0x29,0x5c,0x8f,0x2c,0x3d,0x0a,0xd7,0xad,0x29, +0x5c,0x8f,0x30,0x3d,0x0a,0xd7,0xb1,0x9a,0x99,0x99,0xbf,0x00,0x00,0x00,0x3e, +0x33,0x33,0x33,0xb9,0xc8,0x00,0x00,0x00,0x29,0x5c,0x8f,0x32,0x37,0xd0,0x69, +0xaf,0x29,0x5c,0x8f,0x32,0x37,0xd0,0x69,0xaf,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x3f,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x29,0x5c,0x8f,0x2c,0x3d, +0x0a,0xd7,0xad,0x29,0x5c,0x8f,0x30,0x3d,0x0a,0xd7,0xb1,0x9a,0x99,0x99,0xbf, +0x00,0x00,0x00,0x3e,0x33,0x33,0x33,0xb9,0xc8,0x00,0x00,0x00,0x02,0x00,0x00, +0x00,0x60,0x22,0x05,0x20,0x02,0x00,0x00,0x00,0x70,0x22,0x05,0x20,0x00,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x08,0x51,0x3c,0x00,0x0b,0x83,0x42,0x33, +0x00,0x00,0x00,0x80,0x25,0x05,0x20,0x00,0x6f,0x02,0x3c,0x07,0x00,0x00,0x00, +0x50,0x26,0x05,0x20,0x00,0x00,0x00,0x3e,0x66,0x66,0x66,0x3c,0x9a,0x99,0x99, +0x3f,0x00,0x14,0xd4,0x40,0x00,0x26,0x07,0x40,0x00,0xe7,0xf1,0x3f,0x00,0x00, +0x08,0x4c,0x51,0x14,0xe8,0x33,0x00,0x0f,0x1f,0x37,0x00,0x92,0x84,0x40,0x00, +0x0f,0xce,0x3f,0x37,0xaf,0xf9,0x22,0x3a,0x37,0x01,0x3e,0x07,0x00,0x00,0x00, +0x00,0xab,0xaa,0x3a,0x03,0x00,0x00,0x00,0x00,0x5f,0x49,0x3e,0x00,0xb9,0x8d, +0x30,0x00,0xc8,0x0e,0x28,0x00,0x7f,0xfc,0x41,0x00,0x7f,0xfc,0x43,0x33,0x33, +0x33,0x3f,0x07,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x70,0x26,0x05,0x20,0x00, +0x03,0x03,0x2f,0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0xbd,0xef,0xd4,0x3e, +0x41,0xd3,0x25,0x3d,0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0x46,0xff,0xff, +0x01,0x00,0x00,0x00,0x40,0x9f,0x8a,0x8e,0x2e,0x34,0xa5,0x30,0x31,0x08,0xa8, +0xe0,0x37,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0xf4,0xff,0x3f,0xab, +0x6a,0x75,0x3f,0xbd,0xef,0xd4,0x3e,0x41,0xd3,0x25,0x3d,0x19,0xf4,0xff,0x3f, +0xab,0x6a,0x75,0x3f,0x46,0xff,0xff,0x01,0x00,0x00,0x00,0x40,0x9f,0x8a,0x8e, +0x2e,0x34,0xa5,0x30,0x31,0x08,0xa8,0xe0,0x37,0x19,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0x00,0x00,0x00,0x40,0x00, +0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x46,0xff,0xff,0x01, +0x00,0x00,0x00,0x40,0x9f,0x8a,0x8e,0x2e,0x34,0xa5,0x30,0x31,0x06,0xff,0xff, +0x3f,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xc4,0x0d,0x05,0x20,0x0d, +0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0xc8,0x0d,0x05,0x20,0x00,0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x3f,0x00,0x00, +0x00,0xa0,0x39,0x05,0x20,0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe, +0x11,0x40,0x7b,0x2a,0x9c,0x3f,0x7a,0xde,0x05,0x40,0x77,0x35,0x9b,0x3f,0xbe, +0xed,0x05,0x40,0xed,0x93,0xdd,0x3f,0xed,0xf2,0x01,0x40,0x06,0x00,0x00,0x00, +0x06,0x00,0x00,0x00,0x20,0x3a,0x05,0x20,0x3a,0x37,0x01,0x3e,0x5d,0x83,0x60, +0x40,0x06,0x00,0x00,0x00,0x10,0x38,0x05,0x20,0x06,0x00,0x00,0x00,0x40,0x3a, +0x05,0x20,0x06,0x00,0x00,0x00,0x50,0x38,0x05,0x20,0x00,0x00,0x00,0x05,0x01, +0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x60,0x3a,0x05,0x20,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc, +0x3e,0x00,0x00,0x00,0x43,0x03,0x00,0x00,0x00,0xe0,0x3a,0x05,0x20,0x03,0x00, +0x00,0x00,0xf0,0x3a,0x05,0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x50,0x7e,0x05,0x20,0x0d,0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0xca,0x0d,0x05,0x20,0x00,0x00,0x00,0x00,0x62,0x27, +0x76,0x38,0x3f,0x00,0x00,0x00,0x00,0x3b,0x05,0x20,0x00,0x00,0x00,0x00,0xfb, +0xd4,0xc7,0x3f,0xfd,0x96,0x00,0x40,0xfb,0xd4,0xc7,0x3f,0xfd,0x96,0x00,0x40, +0xfb,0xd4,0xc7,0x3f,0xfd,0x96,0x00,0x40,0xfb,0xd4,0xc7,0x3f,0xfd,0x96,0x00, +0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x7e,0x05,0x20,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x7e,0x05,0x20,0x00, +0x00,0x00,0x00,0x50,0x7e,0x05,0x20,0x00,0x00,0x00,0x00,0x50,0x7e,0x05,0x20, +0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x7e,0x05, +0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x80, +0x3b,0x05,0x20,0x03,0x00,0x00,0x00,0x80,0x3b,0x05,0x20,0x00,0x00,0x00,0x40, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0xcc,0x0d,0x05,0x20,0x0d,0x00,0x00,0x00,0x33,0x33, +0x33,0x3f,0x1e,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x90,0x3b,0x05,0x20,0x00, +0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x3f,0x00,0x00,0x00,0xa0,0x39,0x05,0x20, +0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe,0x11,0x40,0x7b,0x2a,0x9c, +0x3f,0x7a,0xde,0x05,0x40,0x77,0x35,0x9b,0x3f,0xbe,0xed,0x05,0x40,0xed,0x93, +0xdd,0x3f,0xed,0xf2,0x01,0x40,0x0f,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x10, +0x3c,0x05,0x20,0x3a,0x37,0x01,0x3e,0x06,0x93,0xfd,0x41,0x0f,0x00,0x00,0x00, +0x10,0x38,0x05,0x20,0x0f,0x00,0x00,0x00,0x50,0x3c,0x05,0x20,0x0f,0x00,0x00, +0x00,0x50,0x38,0x05,0x20,0x00,0x00,0x00,0x05,0x01,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x60,0x3a,0x05,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0c, +0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc,0x3e,0x00,0x00,0x00,0x43, +0x03,0x00,0x00,0x00,0x80,0x3b,0x05,0x20,0x03,0x00,0x00,0x00,0x80,0x3b,0x05, +0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xd0,0x0d,0x05,0x20,0x0d, +0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +0xd4,0x0d,0x05,0x20,0x00,0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x3f,0x00,0x00, +0x00,0xa0,0x39,0x05,0x20,0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe, +0x11,0x40,0x7b,0x2a,0x9c,0x3f,0x7a,0xde,0x05,0x40,0x8e,0x69,0xee,0x3e,0x27, +0xfe,0x11,0x40,0x7b,0x2a,0x9c,0x3f,0x7a,0xde,0x05,0x40,0x06,0x00,0x00,0x00, +0x06,0x00,0x00,0x00,0x20,0x3a,0x05,0x20,0x3a,0x37,0x01,0x3e,0x5d,0x83,0x60, +0x40,0x06,0x00,0x00,0x00,0x10,0x38,0x05,0x20,0x06,0x00,0x00,0x00,0x40,0x3a, +0x05,0x20,0x06,0x00,0x00,0x00,0x50,0x38,0x05,0x20,0x00,0x00,0x00,0x05,0x01, +0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x60,0x3a,0x05,0x20,0x01,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc, +0x3e,0x00,0x00,0x00,0x43,0x03,0x00,0x00,0x00,0x90,0x3c,0x05,0x20,0x03,0x00, +0x00,0x00,0xa0,0x3c,0x05,0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x50,0x7e,0x05,0x20,0x0d,0x00,0x00,0x00,0xcd,0xcc,0xcc,0x3e,0x1f,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0xd6,0x0d,0x05,0x20,0x00,0x00,0x00,0x40,0x62,0x27, +0x76,0x38,0x3f,0x00,0x00,0x00,0xb0,0x3c,0x05,0x20,0x02,0x00,0x00,0x00,0x95, +0x8f,0x63,0x3f,0xfd,0x52,0x5c,0x40,0x95,0x8f,0x63,0x3f,0xfd,0x52,0x5c,0x40, +0x95,0x8f,0x63,0x3f,0xfd,0x52,0x5c,0x40,0x95,0x8f,0x63,0x3f,0xfd,0x52,0x5c, +0x40,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x20,0x3a,0x05,0x20,0xd3,0x8c, +0xa4,0x3e,0x80,0xf1,0x06,0x41,0x06,0x00,0x00,0x00,0x10,0x38,0x05,0x20,0x06, +0x00,0x00,0x00,0x40,0x3a,0x05,0x20,0x06,0x00,0x00,0x00,0x50,0x38,0x05,0x20, +0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x7e,0x05, +0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x80, +0x3b,0x05,0x20,0x03,0x00,0x00,0x00,0x80,0x3b,0x05,0x20,0x00,0x00,0x00,0x40, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0xd8,0x0d,0x05,0x20,0x0d,0x00,0x00,0x00,0xcd,0xcc, +0xcc,0x3e,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xdc,0x0d,0x05,0x20,0x00, +0x00,0x00,0x40,0x62,0x27,0x76,0x38,0x3f,0x00,0x00,0x00,0xa0,0x39,0x05,0x20, +0x01,0x00,0x00,0x00,0x8e,0x69,0xee,0x3e,0x27,0xfe,0x11,0x40,0x7b,0x2a,0x9c, +0x3f,0x7a,0xde,0x05,0x40,0x77,0x35,0x9b,0x3f,0xbe,0xed,0x05,0x40,0xed,0x93, +0xdd,0x3f,0xed,0xf2,0x01,0x40,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x20, +0x3a,0x05,0x20,0x3a,0x37,0x01,0x3e,0x5d,0x83,0x60,0x40,0x06,0x00,0x00,0x00, +0x10,0x38,0x05,0x20,0x06,0x00,0x00,0x00,0x40,0x3a,0x05,0x20,0x06,0x00,0x00, +0x00,0x50,0x38,0x05,0x20,0x00,0x00,0x00,0x05,0x01,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x60,0x3a,0x05,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0c, +0x00,0x00,0x00,0x29,0x5c,0x8f,0x36,0xcd,0xcc,0xcc,0x3e,0x00,0x00,0x00,0x43, +0x03,0x00,0x00,0x00,0x80,0x3b,0x05,0x20,0x03,0x00,0x00,0x00,0x80,0x3b,0x05, +0x20,0xb1,0x16,0x9f,0x1e,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x33, +0x33,0xb7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x02,0x00,0x00,0x00,0x30,0x3d,0x05,0x20,0x19,0xf4,0xff,0x3f,0x00,0x00,0x00, +0x32,0x00,0x00,0x00,0x4e,0x00,0x00,0x80,0x48,0x00,0x00,0x00,0x00,0x00,0x9a, +0x99,0x3f,0x66,0x66,0x26,0x49,0x66,0x66,0x26,0x45,0x00,0x00,0x00,0x3e,0x14, +0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +0x2e,0x00,0x00,0x00,0x66,0x66,0x66,0x3f,0x00,0x00,0x00,0x3e,0x00,0x00,0x00, +0x00,0x33,0x33,0x33,0x39,0x29,0x5c,0x8f,0x2c,0x3d,0x0a,0xd7,0xad,0x29,0x5c, +0x8f,0x30,0x3d,0x0a,0xd7,0xb1,0x9a,0x99,0x99,0xbf,0x00,0x00,0x00,0x3e,0x33, +0x33,0x33,0xb9,0xc8,0x00,0x00,0x00,0x29,0x5c,0x8f,0x32,0x37,0xd0,0x69,0xaf, +0x29,0x5c,0x8f,0x32,0x37,0xd0,0x69,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3f,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x29,0x5c,0x8f,0x2c,0x3d,0x0a, +0xd7,0xad,0x29,0x5c,0x8f,0x30,0x3d,0x0a,0xd7,0xb1,0x9a,0x99,0x99,0xbf,0x00, +0x00,0x00,0x3e,0x33,0x33,0x33,0xb9,0xc8,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +0x30,0x3d,0x05,0x20,0x02,0x00,0x00,0x00,0x40,0x3d,0x05,0x20,0x00,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x08,0x51,0x3c,0x00,0x0b,0x83,0x42,0x3f,0x00, +0x00,0x00,0xd0,0x40,0x05,0x20,0x00,0x6f,0x02,0x3c,0x07,0x00,0x00,0x00,0xd0, +0x41,0x05,0x20,0x00,0x00,0x00,0x3e,0x66,0x66,0x66,0x3c,0x9a,0x99,0x99,0x3f, +0x00,0x14,0xd4,0x40,0x00,0x26,0x07,0x40,0x00,0xe7,0xf1,0x3f,0x00,0x00,0x08, +0x4c,0x51,0x14,0xe8,0x33,0x00,0x0f,0x1f,0x37,0x00,0x92,0x84,0x40,0x00,0x0f, +0xce,0x3f,0x37,0xaf,0xf9,0x22,0x3a,0x37,0x01,0x3e,0x07,0x00,0x00,0x00,0x00, +0xab,0xaa,0x3a,0x03,0x00,0x00,0x00,0x00,0x5f,0x49,0x3e,0x00,0xb9,0x8d,0x30, +0x00,0xc8,0x0e,0x28,0x00,0x7f,0xfc,0x41,0x00,0x7f,0xfc,0x43,0x33,0x33,0x33, +0x3f,0x07,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0xf0,0x41,0x05,0x20,0x00,0x03, +0x03,0x2f,0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0xbd,0xef,0xd4,0x3e,0x41, +0xd3,0x25,0x3d,0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0x46,0xff,0xff,0x01, +0x00,0x00,0x00,0x40,0x59,0xf3,0x8e,0x2c,0xdc,0xeb,0x31,0x2f,0x56,0x2a,0xf0, +0x35,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0xf4,0xff,0x3f,0xab,0x6a, +0x75,0x3f,0xbd,0xef,0xd4,0x3e,0x41,0xd3,0x25,0x3d,0x19,0xf4,0xff,0x3f,0xab, +0x6a,0x75,0x3f,0x46,0xff,0xff,0x01,0x00,0x00,0x00,0x40,0x59,0xf3,0x8e,0x2c, +0xdc,0xeb,0x31,0x2f,0x56,0x2a,0xf0,0x35,0x19,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x19,0xf4,0xff,0x3f,0xab,0x6a,0x75,0x3f,0x00,0x00,0x00,0x40,0x00,0x00, +0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x46,0xff,0xff,0x01,0x00, +0x00,0x00,0x40,0x59,0xf3,0x8e,0x2c,0xdc,0xeb,0x31,0x2f,0xf1,0x05,0xfe,0x3f, +0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x00,0x42,0xfd,0x0d,0xfd,0x1e,0x01,0x4b,0x07,0x03,0x01,0x12,0x00, +0x23,0x00,0x34,0x03,0x2e,0x00,0x04,0x00,0x28,0x00,0x0e,0x00,0x4c,0x03,0x1a, +0x00,0x20,0x00,0x1f,0x00,0x30,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x52,0x80,0x00,0x00,0x51,0x80,0x30,0x00,0x4c,0x80,0x01, +0x00,0x4e,0x80,0x80,0x0c,0x4f,0x80,0x00,0x00,0x1c,0x80,0x01,0x00,0x26,0x80, +0x1a,0x00,0x1b,0x80,0x11,0x00,0x1b,0x80,0x05,0x01,0x15,0x80,0xef,0x04,0x15, +0x80,0xef,0x05,0x1b,0x80,0x0c,0x02,0x1b,0x80,0x0c,0x03,0x15,0x80,0xf4,0x06, +0x15,0x80,0xf4,0x07,0x00,0x00,0x00,0x00,0x02,0x00,0x42,0xfd,0x0d,0xfd,0x1e, +0x01,0x4b,0x07,0x03,0x01,0x12,0x04,0x23,0x00,0x34,0x03,0x2e,0x00,0x04,0x00, +0x28,0x00,0x0e,0x00,0x4c,0x03,0x1a,0x00,0x20,0x00,0x1f,0x00,0x30,0x00,0x31, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x80,0x00,0x00, +0x51,0x80,0x30,0x00,0x4c,0x80,0x00,0x00,0x4e,0x80,0x80,0x0c,0x4f,0x80,0x00, +0x00,0x1c,0x80,0x01,0x00,0x26,0x80,0x1a,0x00,0x1b,0x80,0x11,0x00,0x1b,0x80, +0x05,0x01,0x15,0x80,0xed,0x04,0x15,0x80,0xed,0x05,0x1b,0x80,0x0c,0x02,0x1b, +0x80,0x0c,0x03,0x15,0x80,0xf4,0x06,0x15,0x80,0xf4,0x07,0x00,0x00,0x00,0x00, +0x02,0x00,0x42,0xfd,0x0d,0xfd,0x1e,0x01,0x4b,0x07,0x03,0x01,0x12,0x04,0x23, +0x00,0x34,0x03,0x2e,0x00,0x04,0x00,0x28,0x00,0x0e,0x00,0x4c,0x03,0x1a,0x00, +0x20,0x00,0x1f,0x00,0x30,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x52,0x80,0x00,0x00,0x51,0x80,0x30,0x00,0x4c,0x80,0x01,0x00, +0x4e,0x80,0x80,0x0c,0x4f,0x80,0x00,0x00,0x1c,0x80,0x01,0x00,0x26,0x80,0x1a, +0x00,0x1b,0x80,0x11,0x00,0x1b,0x80,0x05,0x01,0x15,0x80,0xed,0x04,0x15,0x80, +0xed,0x05,0x1b,0x80,0x0c,0x02,0x1b,0x80,0x0c,0x03,0x15,0x80,0xf4,0x06,0x15, +0x80,0xf4,0x07,0x00,0x00,0x00,0x00,0x01,0x00,0x13,0x00,0x00,0x00,0x0f,0x00, +0x20,0x75,0x05,0x20,0x00,0x00,0x00,0x00,0x50,0x75,0x05,0x20,0x00,0x00,0x13, +0x00,0x00,0x00,0x0f,0x00,0x90,0x75,0x05,0x20,0x00,0x00,0x00,0x00,0xc0,0x75, +0x05,0x20,0x02,0x00,0x13,0x00,0x00,0x00,0x0f,0x00,0x00,0x76,0x05,0x20,0x00, +0x00,0x00,0x00,0x30,0x76,0x05,0x20,0x00,0x00,0x00,0x00,0xb5,0xd3,0x75,0xd3, +0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0xa2, +0xaa,0xaa,0xbb,0xbb,0xb6,0xb7,0x75,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8b,0x00,0x00,0x00, +0x75,0x75,0xb5,0xb4,0x75,0x75,0x75,0x75,0xf3,0x61,0x87,0x54,0x00,0x00,0x00, +0x00,0x24,0x02,0x05,0x20,0x30,0x02,0x05,0x20,0x3c,0x02,0x05,0x20,0x3c,0x02, +0x05,0x20,0xa0,0x67,0x05,0x20,0x68,0x68,0x05,0x20,0x30,0x69,0x05,0x20,0xf8, +0x69,0x05,0x20,0xc0,0x6a,0x05,0x20,0x88,0x6b,0x05,0x20,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xac,0x03,0x05,0x20,0xac,0x03,0x05,0x20,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xc0,0x6d,0x05,0x20,0xf4,0x6d,0x05,0x20,0x28,0x6e, +0x05,0x20,0x00,0x00,0x00,0x00,0xfc,0x07,0x05,0x20,0xfc,0x07,0x05,0x20,0xfc, +0x07,0x05,0x20,0xfc,0x07,0x05,0x20,0xfc,0x07,0x05,0x20,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x07,0x05,0x20,0xfc,0x07,0x05, +0x20,0xfc,0x07,0x05,0x20,0xfc,0x07,0x05,0x20,0xfc,0x07,0x05,0x20,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x05,0x20,0x1c, +0x08,0x05,0x20,0x1c,0x08,0x05,0x20,0x08,0x08,0x05,0x20,0x08,0x08,0x05,0x20, +0x30,0x08,0x05,0x20,0x44,0x08,0x05,0x20,0x00,0x00,0x00,0x00,0x5c,0x08,0x05, +0x20,0x5c,0x08,0x05,0x20,0x5c,0x08,0x05,0x20,0x5c,0x08,0x05,0x20,0x5c,0x08, +0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5c, +0x08,0x05,0x20,0x5c,0x08,0x05,0x20,0x5c,0x08,0x05,0x20,0x5c,0x08,0x05,0x20, +0x5c,0x08,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xb4,0x08,0x05,0x20,0xe4,0x08,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x09,0x05,0x20,0xe4,0x08,0x05,0x20,0x00, +0x00,0x00,0x00,0x44,0x09,0x05,0x20,0x4c,0x09,0x05,0x20,0x4c,0x09,0x05,0x20, +0x44,0x09,0x05,0x20,0x44,0x09,0x05,0x20,0x54,0x09,0x05,0x20,0x5c,0x09,0x05, +0x20,0x00,0x00,0x00,0x00,0x64,0x09,0x05,0x20,0x70,0x09,0x05,0x20,0x70,0x09, +0x05,0x20,0x64,0x09,0x05,0x20,0x64,0x09,0x05,0x20,0x70,0x09,0x05,0x20,0x70, +0x09,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x09,0x05, +0x20,0xb8,0x09,0x05,0x20,0x00,0x00,0x00,0x00,0x0c,0x0a,0x05,0x20,0x1e,0x0a, +0x05,0x20,0x1e,0x0a,0x05,0x20,0x0c,0x0a,0x05,0x20,0x30,0x0a,0x05,0x20,0x0c, +0x0a,0x05,0x20,0x1e,0x0a,0x05,0x20,0x00,0x00,0x00,0x00,0x84,0x0a,0x05,0x20, +0x84,0x0a,0x05,0x20,0x84,0x0a,0x05,0x20,0x84,0x0a,0x05,0x20,0x94,0x0a,0x05, +0x20,0x84,0x0a,0x05,0x20,0x84,0x0a,0x05,0x20,0x00,0x00,0x00,0x00,0xa4,0x0a, +0x05,0x20,0xb8,0x0a,0x05,0x20,0xcc,0x0a,0x05,0x20,0xcc,0x0a,0x05,0x20,0xcc, +0x0a,0x05,0x20,0xcc,0x0a,0x05,0x20,0xb8,0x0a,0x05,0x20,0x00,0x00,0x00,0x00, +0xe0,0x0a,0x05,0x20,0xe0,0x0a,0x05,0x20,0xe0,0x0a,0x05,0x20,0xe0,0x0a,0x05, +0x20,0xe0,0x0a,0x05,0x20,0xf4,0x0a,0x05,0x20,0xf4,0x0a,0x05,0x20,0x00,0x00, +0x00,0x00,0x08,0x0b,0x05,0x20,0x14,0x0b,0x05,0x20,0x14,0x0b,0x05,0x20,0x20, +0x0b,0x05,0x20,0x20,0x0b,0x05,0x20,0x08,0x0b,0x05,0x20,0x14,0x0b,0x05,0x20, +0x00,0x00,0x00,0x00,0x2c,0x0b,0x05,0x20,0x38,0x0b,0x05,0x20,0x44,0x0b,0x05, +0x20,0x44,0x0b,0x05,0x20,0x44,0x0b,0x05,0x20,0x2c,0x0b,0x05,0x20,0x38,0x0b, +0x05,0x20,0x00,0x00,0x00,0x00,0x8c,0x0c,0x05,0x20,0x98,0x0c,0x05,0x20,0xa4, +0x0c,0x05,0x20,0xa4,0x0c,0x05,0x20,0x5c,0x6e,0x05,0x20,0x24,0x6f,0x05,0x20, +0xec,0x6f,0x05,0x20,0xb4,0x70,0x05,0x20,0x7c,0x71,0x05,0x20,0x44,0x72,0x05, +0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x0e,0x05,0x20,0x14,0x0e, +0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x74,0x05,0x20,0xb0, +0x74,0x05,0x20,0xe4,0x74,0x05,0x20,0x00,0x00,0x00,0x00,0x64,0x12,0x05,0x20, +0x64,0x12,0x05,0x20,0x64,0x12,0x05,0x20,0x64,0x12,0x05,0x20,0x64,0x12,0x05, +0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x12, +0x05,0x20,0x64,0x12,0x05,0x20,0x64,0x12,0x05,0x20,0x64,0x12,0x05,0x20,0x64, +0x12,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x70,0x12,0x05,0x20,0x84,0x12,0x05,0x20,0x84,0x12,0x05,0x20,0x70,0x12,0x05, +0x20,0x70,0x12,0x05,0x20,0x70,0x12,0x05,0x20,0x84,0x12,0x05,0x20,0x00,0x00, +0x00,0x00,0x9c,0x12,0x05,0x20,0x9c,0x12,0x05,0x20,0x9c,0x12,0x05,0x20,0x9c, +0x12,0x05,0x20,0x9c,0x12,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x9c,0x12,0x05,0x20,0x9c,0x12,0x05,0x20,0x9c,0x12,0x05, +0x20,0x9c,0x12,0x05,0x20,0x9c,0x12,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xf4,0x12,0x05,0x20,0x24,0x13,0x05,0x20,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf4,0x12,0x05,0x20, +0x24,0x13,0x05,0x20,0x00,0x00,0x00,0x00,0x54,0x13,0x05,0x20,0x5c,0x13,0x05, +0x20,0x5c,0x13,0x05,0x20,0x54,0x13,0x05,0x20,0x54,0x13,0x05,0x20,0x64,0x13, +0x05,0x20,0x6c,0x13,0x05,0x20,0x00,0x00,0x00,0x00,0x74,0x13,0x05,0x20,0x80, +0x13,0x05,0x20,0x80,0x13,0x05,0x20,0x74,0x13,0x05,0x20,0x74,0x13,0x05,0x20, +0x80,0x13,0x05,0x20,0x80,0x13,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xa4,0x13,0x05,0x20,0xc8,0x13,0x05,0x20,0x00,0x00,0x00,0x00,0x1c, +0x14,0x05,0x20,0x2e,0x14,0x05,0x20,0x2e,0x14,0x05,0x20,0x1c,0x14,0x05,0x20, +0x40,0x14,0x05,0x20,0x1c,0x14,0x05,0x20,0x2e,0x14,0x05,0x20,0x00,0x00,0x00, +0x00,0x94,0x14,0x05,0x20,0xa4,0x14,0x05,0x20,0xa4,0x14,0x05,0x20,0x94,0x14, +0x05,0x20,0xb4,0x14,0x05,0x20,0x94,0x14,0x05,0x20,0xa4,0x14,0x05,0x20,0x00, +0x00,0x00,0x00,0xc4,0x14,0x05,0x20,0xd8,0x14,0x05,0x20,0xec,0x14,0x05,0x20, +0xec,0x14,0x05,0x20,0xec,0x14,0x05,0x20,0x00,0x15,0x05,0x20,0xd8,0x14,0x05, +0x20,0x00,0x00,0x00,0x00,0x14,0x15,0x05,0x20,0x14,0x15,0x05,0x20,0x14,0x15, +0x05,0x20,0x14,0x15,0x05,0x20,0x14,0x15,0x05,0x20,0x14,0x15,0x05,0x20,0x14, +0x15,0x05,0x20,0x00,0x00,0x00,0x00,0x28,0x15,0x05,0x20,0x34,0x15,0x05,0x20, +0x34,0x15,0x05,0x20,0x40,0x15,0x05,0x20,0x40,0x15,0x05,0x20,0x28,0x15,0x05, +0x20,0x34,0x15,0x05,0x20,0x00,0x00,0x00,0x00,0x4c,0x15,0x05,0x20,0x58,0x15, +0x05,0x20,0x64,0x15,0x05,0x20,0x64,0x15,0x05,0x20,0x64,0x15,0x05,0x20,0x4c, +0x15,0x05,0x20,0x58,0x15,0x05,0x20,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00, +0x1c,0x09,0x18,0x20,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x90,0x81,0x05, +0x20,0xd0,0x87,0x05,0x20,0x10,0x8e,0x05,0x20,0x50,0x94,0x05,0x20,0x90,0x9a, +0x05,0x20,0xf0,0x9b,0x05,0x20,0x50,0x9d,0x05,0x20,0x90,0xa3,0x05,0x20,0xd0, +0xa9,0x05,0x20,0x30,0xab,0x05,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x06,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x05,0x00,0x08,0x00,0x09,0x00,0x0c, +0x00,0x0d,0x00,0x02,0x00,0x03,0x00,0x06,0x00,0x07,0x00,0x0a,0x00,0x0b,0x00, +0x0e,0x00,0x0f,0x00,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40, +0x01,0x40,0x01,0x40,0x01,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00, +0x05,0x00,0x06,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04, +0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x0a,0x00,0x0a,0x00,0x0b,0x00,0x0b,0x00, +0x0c,0x00,0x0c,0x00,0x0d,0x00,0x0d,0x00,0x0a,0x00,0x0a,0x00,0x0b,0x00,0x0b, +0x00,0x0c,0x00,0x0c,0x00,0x0d,0x00,0x0d,0x00,0xa0,0xe6,0x07,0x20,0xe0,0xe5, +0x07,0x20,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, +0x0b,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x08,0x00,0x00, +0x00,0x09,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x64,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x74, +0x88,0x18,0x20,0x98,0x8b,0x18,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0x2f,0x00,0x00,0x80, +0x03,0x08,0x20,0x0c,0x70,0x08,0x20,0x21,0xff,0xff,0xa0,0x02,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x36,0x21,0x01,0x38,0x32,0x0c,0x0d,0x0c,0x05,0x2f,0x20, +0x09,0x22,0x44,0x0c,0x0c,0x11,0x0c,0xf6,0x48,0x42,0x0f,0x82,0x88,0x04,0x44, +0x0c,0x0c,0x11,0x78,0x12,0xb1,0x65,0x54,0xb9,0x01,0x92,0xc7,0x3c,0xa2,0xc7, +0x48,0x2f,0x40,0x91,0x04,0x44,0x0c,0x0c,0x11,0x2f,0x21,0x89,0x04,0x44,0x0c, +0x0c,0x11,0xa8,0x02,0x98,0x54,0xb2,0xc7,0x40,0xaf,0x61,0x89,0x04,0x44,0x0c, +0x0c,0x11,0x98,0x09,0x88,0x6a,0xa8,0x8a,0x80,0x82,0x21,0x89,0x81,0x00,0x0a, +0x40,0x60,0xc0,0xb1,0x4f,0xab,0x92,0x43,0xe0,0x90,0x27,0x0b,0x4f,0x2d,0x8d, +0x43,0xe0,0xa0,0xa7,0x0b,0x76,0xa8,0xbb,0xe8,0x83,0x88,0x04,0xf8,0x14,0x98, +0x24,0xf8,0x1f,0x98,0x19,0x88,0x18,0x90,0x6d,0x97,0xe8,0x1e,0x2f,0x1a,0x43, +0x43,0xd0,0x50,0x2f,0x0c,0xea,0xed,0xaf,0xfa,0x43,0x43,0xe0,0x30,0x85,0x02, +0xb0,0x04,0x03,0x6f,0x67,0x01,0x42,0x50,0x20,0x08,0x01,0xb0,0xba,0x20,0x0f, +0x7d,0x01,0x82,0x50,0x20,0x0c,0x11,0x92,0x22,0x13,0xaf,0xe0,0x0a,0x22,0x50, +0x20,0x08,0x29,0x98,0x19,0xaf,0xe0,0x0a,0x22,0x50,0x20,0x0c,0x39,0x90,0x6d, +0x97,0xaf,0xe0,0x0a,0x22,0xd0,0x10,0x0f,0x09,0xaf,0xe0,0x0a,0x22,0xd0,0x50, +0xaf,0x0b,0xaf,0xe0,0x0a,0x22,0xf8,0x50,0x0e,0x0d,0xd0,0x69,0xd6,0x88,0x74, +0xef,0x11,0x03,0x62,0x50,0x30,0x00,0x01,0x0f,0xb1,0xc3,0x2a,0x50,0x30,0x04, +0x11,0xf2,0x22,0x12,0xaf,0xe0,0x0a,0x22,0x50,0x30,0x00,0x29,0xf8,0x1f,0xaf, +0xe0,0x0a,0x22,0x50,0x30,0x04,0x39,0xf0,0x6d,0x97,0xaf,0xe0,0x0a,0x22,0xd0, +0x00,0x87,0x09,0xaf,0xe0,0x0a,0x22,0xd0,0x50,0x2f,0x0b,0xaf,0xe0,0x0a,0x22, +0xf8,0x50,0x86,0x0c,0xd0,0x6f,0xd6,0xe8,0x64,0xe8,0x1e,0xd0,0x6e,0xd6,0x1b, +0xdd,0xfd,0x01,0xd2,0xc7,0x28,0x92,0xc7,0x1c,0x82,0xc7,0x20,0xa2,0xc7,0x2c, +0xb2,0xc7,0x24,0xe2,0xc7,0x18,0x2f,0xc1,0x89,0x04,0x44,0x0c,0x0c,0x11,0x2f, +0x61,0x91,0x04,0x44,0x0c,0x0c,0x11,0xaf,0x40,0x91,0x04,0x44,0x0c,0x0c,0x11, +0x2f,0x00,0x91,0x04,0x44,0x0c,0x0c,0x11,0xaf,0x21,0x89,0x04,0x44,0x0c,0x0c, +0x11,0xaf,0xa1,0x91,0x04,0x44,0x0c,0x0c,0x11,0xaf,0xe1,0x81,0x04,0x44,0x0c, +0x0c,0x11,0x0c,0x0d,0xf8,0x81,0xcf,0x81,0x09,0x22,0x44,0x0c,0x0c,0x11,0x76, +0xaf,0x74,0x92,0x22,0x13,0x98,0x19,0x82,0x27,0x17,0x90,0x6d,0x97,0xcc,0x68, +0x8f,0x08,0x00,0x08,0xc4,0x50,0xb7,0x0a,0xa2,0x22,0x14,0xa8,0x1a,0xa0,0xad, +0x87,0xaf,0xe0,0x0a,0x22,0xc4,0x50,0xb7,0x0a,0xaf,0xe0,0x0a,0x22,0xd0,0x10, +0x97,0x0d,0xbf,0x46,0x8c,0x22,0xd0,0x00,0x17,0x0d,0xaf,0xe0,0x0a,0x22,0xc8, +0x10,0xc7,0x08,0x3f,0x63,0x84,0x20,0xc4,0x00,0x3f,0x08,0x3f,0x63,0x00,0x21, +0x44,0x0c,0x0c,0x11,0x0f,0xb5,0x43,0x29,0xd0,0x20,0x97,0x0c,0xf8,0x23,0xef, +0xff,0x03,0x62,0xe8,0x30,0x2d,0x01,0xb0,0x04,0x03,0xb0,0xb8,0x34,0xfa,0xfd, +0xb2,0x4f,0x00,0xe8,0xa4,0xe8,0x1e,0xea,0xed,0xb2,0x4e,0x00,0x1b,0xdd,0xcf, +0xc3,0x42,0x43,0x44,0x0c,0x0c,0x11,0x4f,0x63,0x42,0x43,0x44,0x0c,0x0c,0x11, +0xcf,0x82,0x42,0x43,0x44,0x0c,0x0c,0x11,0x4f,0xa2,0x42,0x43,0x44,0x0c,0x0c, +0x11,0xa2,0xc2,0x3c,0xb2,0xc2,0x38,0x92,0xc7,0x38,0xe8,0x44,0xf2,0xc7,0x34, +0xaf,0xe0,0x91,0x04,0x44,0x0c,0x0c,0x11,0x88,0x1e,0xe8,0x0e,0x2f,0x21,0x91, +0x04,0x44,0x0c,0x0c,0x11,0x80,0xee,0x80,0xe2,0xce,0x80,0xd2,0x0e,0x7f,0x82, +0x21,0x08,0xc0,0xdd,0x10,0xd2,0x4e,0x7f,0x92,0x22,0x11,0xb0,0x00,0x2c,0xa0, +0xc0,0x1c,0x4f,0x00,0x14,0x2c,0x44,0x0c,0x0c,0x11,0xcf,0x01,0x8c,0x2b,0x44, +0x0c,0x0c,0x11,0x90,0x88,0x1c,0xe6,0x18,0x02,0x06,0x44,0x00,0x8f,0x20,0x09, +0x22,0x44,0x0c,0x0c,0x11,0x82,0xa0,0x02,0xf2,0x21,0x08,0x0f,0xa0,0xa1,0x42, +0x2e,0x3a,0x21,0x00,0x76,0xaf,0xe2,0x0f,0x80,0x17,0x22,0x44,0x0c,0x0c,0x11, +0xe2,0x22,0x12,0xc8,0x44,0x98,0x33,0xc8,0x1c,0x98,0x19,0xe8,0x1e,0x9a,0x9d, +0xe0,0x6d,0x87,0xca,0xcd,0x2f,0x98,0x01,0x82,0xe8,0x30,0x8d,0x04,0x80,0x04, +0x03,0x80,0x88,0x34,0x80,0x8c,0x10,0x82,0x49,0x00,0xf8,0x34,0xe8,0x43,0xf8, +0x1f,0xe8,0x1e,0xf0,0xed,0xa7,0x3f,0x48,0x9c,0x2b,0x44,0x0c,0x0c,0x11,0xcf, +0xdb,0x69,0x43,0xe4,0x30,0x5c,0x16,0xa0,0x04,0x03,0xa0,0xa4,0x34,0xa0,0xac, +0x10,0xa2,0x4e,0x00,0xb8,0x53,0xb8,0x1b,0xba,0xbd,0xa2,0x4b,0x00,0xef,0x27, +0x13,0x62,0xe0,0x30,0x5d,0x06,0x80,0x04,0x03,0x98,0x19,0x80,0x80,0x34,0x9a, +0x9d,0x82,0x49,0x00,0xf8,0x73,0xf8,0x1f,0xfa,0xfd,0x52,0x4f,0x00,0xe8,0x63, +0xe8,0x1e,0xea,0xed,0x52,0x4e,0x00,0xb8,0x94,0xef,0x77,0x03,0x62,0x3e,0x0b, +0x01,0x00,0x7f,0x63,0x02,0x2d,0x44,0x0c,0x0c,0x11,0xd0,0xab,0xc6,0xa2,0x22, +0x13,0xa8,0x1a,0xa0,0x2d,0x87,0xaf,0xe0,0x0a,0x22,0x48,0x00,0x00,0x01,0xaf, +0xe0,0x0a,0x22,0x48,0x00,0x04,0x11,0xaf,0xe0,0x0a,0x22,0x48,0x00,0x00,0x29, +0xaf,0xe0,0x0a,0x22,0x48,0x00,0x04,0x39,0x98,0x03,0xaf,0xe0,0x0a,0x22,0xd0, +0x00,0x87,0x08,0x98,0x19,0x7f,0x62,0x02,0x28,0x44,0x0c,0x0c,0x11,0xd0,0x29, +0xc6,0x0f,0xba,0x03,0x82,0xe0,0x60,0xb7,0x09,0xd8,0x81,0xcf,0x82,0x42,0x43, +0x44,0x0c,0x0c,0x11,0x4f,0xa2,0x42,0x43,0x44,0x0c,0x0c,0x11,0x46,0x00,0x00, +0x0c,0x0d,0xb8,0x93,0xb8,0x1b,0x7c,0xf9,0xba,0xbd,0xb2,0xcb,0x80,0xa2,0x0b, +0x7f,0xe8,0x81,0xa0,0xa0,0x24,0xa2,0x4b,0x7f,0xa8,0xb2,0x88,0x33,0x1b,0xaa, +0x88,0x18,0xa0,0xd2,0x21,0xa0,0xa0,0x14,0x8a,0x8d,0xf2,0x08,0x00,0x00,0x1a, +0x40,0x1b,0xdd,0xd0,0xee,0xc0,0x00,0xa6,0xa1,0x90,0xaa,0x30,0xa0,0xff,0x10, +0xf2,0x48,0x00,0x76,0xae,0x0a,0xc8,0x33,0xc8,0x1c,0xca,0xcd,0x52,0x4c,0x00, +0x1b,0xdd,0x59,0x11,0xb8,0x81,0x88,0x62,0xa8,0x33,0x82,0x28,0x20,0xa8,0x1a, +0xe0,0x08,0x00,0x0f,0xa2,0xb8,0x43,0x44,0x0c,0x0c,0x11,0xaf,0x20,0x01,0x22, +0x44,0x0c,0x0c,0x11,0x4f,0x82,0xb8,0x43,0x44,0x0c,0x0c,0x11,0x1c,0xf9,0x16, +0x7a,0x09,0x8f,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11,0xb8,0x81,0xef,0x80,0x09, +0x22,0x44,0x0c,0x0c,0x11,0xa6,0x1b,0x3f,0x0c,0x0d,0xf8,0x81,0xb8,0x34,0xc8, +0x93,0xe8,0x33,0xc8,0x1c,0xe2,0x2e,0x01,0xb2,0x2b,0x01,0x76,0xaf,0x2a,0x82, +0x0c,0x00,0xb0,0xad,0x87,0xf2,0x0e,0x00,0x1b,0xdd,0x0f,0xdc,0x03,0x82,0x32, +0x0a,0x01,0x00,0x1f,0x62,0x84,0x20,0xfe,0x0b,0x01,0x00,0x7f,0x62,0x02,0x28, +0x44,0x0c,0x0c,0x11,0x0f,0x98,0x03,0x82,0xf4,0x30,0x1e,0x08,0x6f,0xf4,0x00, +0x22,0xa8,0x30,0x1f,0x38,0xaf,0xe0,0x0a,0x22,0x42,0x0a,0x04,0x00,0xaf,0xe0, +0x0a,0x22,0x44,0x38,0x18,0x11,0xaf,0xe0,0x0a,0x22,0x48,0x00,0x00,0x01,0xaf, +0xe0,0x0a,0x22,0x30,0x3c,0x99,0x01,0x4f,0x83,0x42,0x43,0x44,0x0c,0x0c,0x11, +0x0f,0x62,0x09,0x82,0xa4,0x30,0x18,0x00,0x4f,0xa2,0x42,0x43,0x44,0x0c,0x0c, +0x11,0x00,0xcb,0x0d,0xb8,0x44,0x88,0x62,0xa8,0x1b,0x82,0x28,0x20,0xb8,0x0b, +0xe0,0x08,0x00,0x1c,0xfc,0xd1,0x45,0x53,0x0c,0x0e,0x8c,0x5a,0x98,0xd2,0xd7, +0x99,0x01,0x0c,0x1e,0x8c,0x2e,0x0c,0x1b,0xb9,0x72,0xf8,0x47,0xe8,0x82,0xf7, +0x2e,0x0a,0x59,0x82,0x59,0x72,0x0c,0x0e,0x0c,0x09,0x46,0x00,0x00,0x98,0x72, +0x0c,0x0f,0x66,0x19,0x04,0x0c,0x18,0xa0,0xf8,0x93,0x8c,0x6f,0x1b,0xfe,0xf9, +0x82,0xb8,0x11,0xb9,0xd2,0xe2,0xc2,0x34,0xcc,0x4a,0xd9,0xd2,0x06,0x10,0x00, +0x00,0xfc,0xc9,0x2f,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11,0x2f,0x82,0xb8,0x43, +0x44,0x0c,0x0c,0x11,0x92,0xc7,0x4c,0x90,0xc0,0x0c,0xe0,0x40,0x0c,0x4b,0x81, +0x4f,0xa2,0xb8,0x43,0xa4,0x10,0x88,0x01,0x2f,0x01,0x01,0xa2,0xa8,0x30,0x18, +0x02,0x4f,0xa3,0x42,0x43,0x80,0x14,0x90,0x01,0xcf,0x82,0x42,0x43,0x44,0x0c, +0x0c,0x11,0x00,0x4e,0x0d,0x2f,0x82,0xba,0x43,0x44,0x0c,0x0c,0x11,0xa2,0xc7, +0x50,0xa0,0x80,0x1c,0xe0,0x40,0x1c,0xcf,0x82,0x4a,0x43,0xc4,0x10,0x2c,0x03, +0x76,0x01,0x14,0xb8,0x81,0x0c,0x0d,0x76,0xab,0x0a,0xf8,0x93,0xf8,0x1f,0xfa, +0xfd,0x62,0x4f,0x00,0x1b,0xdd,0x06,0x0d,0x00,0xd8,0xc2,0x88,0x53,0xd0,0xf0, +0x14,0x88,0x18,0xd0,0xd2,0x21,0x00,0x1f,0x40,0x00,0x96,0xa1,0x8a,0x8d,0xf2, +0x08,0x00,0x90,0x90,0x34,0x90,0xff,0x20,0xf2,0x48,0x00,0x88,0x81,0x1b,0xdd, +0xd0,0x88,0xc0,0x76,0xa8,0x0a,0x98,0x53,0x98,0x19,0x9a,0x9d,0x62,0x49,0x00, +0x1b,0xdd,0xa8,0xa2,0xd8,0x92,0x88,0x63,0xf8,0x93,0x88,0x18,0xf8,0x1f,0xd0, +0x90,0x14,0x00,0x09,0x40,0xd0,0xd2,0x21,0xfa,0xfd,0xf2,0x0f,0x00,0x8a,0x8d, +0xf0,0xf0,0xb1,0x1b,0xdd,0x00,0x19,0x40,0x00,0xff,0xa1,0xf2,0x48,0x00,0xa0, +0xf0,0x14,0xa0,0xa2,0x21,0xd7,0x2a,0x1b,0xd0,0x8a,0xc0,0x1b,0x88,0x76,0xa8, +0x13,0xb8,0x63,0x98,0x93,0xb8,0x1b,0x98,0x19,0xba,0xbd,0x9a,0x9d,0x92,0x09, +0x00,0x92,0x4b,0x00,0x1b,0xdd,0x82,0xaf,0x9c,0x7c,0xf5,0x00,0x1f,0x40,0xb8, +0x63,0x0c,0xed,0xb8,0x1b,0x00,0xdd,0xa1,0xba,0xba,0x92,0x0b,0x00,0x50,0xdd, +0x30,0xd0,0x99,0x10,0x92,0x4b,0x00,0x6f,0x22,0xba,0x43,0x44,0x0c,0x0c,0x11, +0xd8,0x57,0xef,0xf1,0x08,0x22,0x44,0x0c,0x0c,0x11,0xcf,0x23,0x4a,0x43,0x02, +0x7b,0x04,0x00,0xcf,0x01,0x8c,0x2b,0x44,0x0c,0x0c,0x11,0xcf,0x23,0x4a,0x43, +0x44,0x0c,0x0c,0x11,0x16,0x8d,0x32,0xf8,0x81,0x0c,0x0d,0x76,0xaf,0x22,0xa8, +0x83,0xb8,0x44,0xa8,0x1a,0xb8,0x1b,0xaa,0xad,0xba,0xbd,0xb2,0x0b,0x00,0x92, +0x0a,0x00,0xb0,0x99,0x10,0x92,0x4a,0x00,0x88,0x93,0x88,0x18,0x8a,0x8d,0x62, +0x48,0x00,0x1b,0xdd,0x92,0xc7,0x58,0x0f,0x82,0xbc,0x43,0x44,0x0c,0x0c,0x11, +0xb8,0x83,0x88,0x62,0x2f,0xa2,0xbc,0x43,0x44,0x0c,0x0c,0x11,0xe0,0x40,0x2c, +0xcf,0xa2,0x52,0x43,0x44,0x0c,0x0c,0x11,0x82,0x28,0x20,0xa8,0x1b,0x90,0x00, +0x2c,0xb8,0x0b,0x4f,0x82,0x52,0x43,0x44,0x0c,0x0c,0x11,0xe0,0x08,0x00,0xcd, +0x0a,0x0c,0x09,0x9c,0x9a,0x6f,0x82,0xbc,0x43,0x44,0x0c,0x0c,0x11,0x4f,0xa2, +0xbc,0x43,0x44,0x0c,0x0c,0x11,0x2f,0xa0,0xa1,0x42,0xc8,0x10,0xd4,0x05,0x20, +0x9d,0xd3,0x16,0x09,0x1e,0x0f,0xc2,0xb8,0x43,0x44,0x0c,0x0c,0x11,0x0f,0x25, +0x01,0x22,0x44,0x0c,0x0c,0x11,0x0c,0x0d,0x8f,0x20,0x09,0x22,0x44,0x0c,0x0c, +0x11,0xe8,0x81,0xef,0x80,0x09,0x22,0x44,0x0c,0x0c,0x11,0x76,0xae,0x5e,0x98, +0x03,0x98,0x19,0x90,0x6d,0xb7,0xaf,0xe0,0x0a,0x22,0x20,0xd0,0x68,0x01,0xaf, +0xe0,0x0a,0x22,0x1c,0xd0,0x6d,0x11,0xaf,0xe0,0x0a,0x22,0x18,0xd0,0x6a,0x29, +0xaf,0xe0,0x0a,0x22,0x14,0xd0,0x6f,0x39,0x88,0x13,0x0f,0x22,0xbe,0x43,0xd0, +0xd0,0x6f,0x08,0x88,0x18,0xaf,0xe0,0x0a,0x22,0xc4,0xc0,0xe7,0x0e,0xd0,0x28, +0xf6,0xf8,0x83,0xf8,0x1f,0xfa,0xfd,0xf2,0x0f,0x00,0x0f,0xba,0x03,0x82,0xf6, +0x0b,0x01,0x00,0x3f,0x62,0x1a,0x2e,0x44,0x0c,0x0c,0x11,0x4f,0xa2,0x5a,0x43, +0xf4,0x30,0x1e,0x0e,0x4f,0xa2,0xbe,0x43,0x44,0x0c,0x0c,0x11,0x1c,0xfa,0x6f, +0xf9,0x18,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x82,0xea,0x04,0x00, +0xaf,0xe0,0x0a,0x22,0x48,0xe0,0x70,0x01,0xaf,0xe0,0x0a,0x22,0x48,0xe0,0x74, +0x11,0xaf,0xe0,0x0a,0x22,0x44,0x38,0x18,0x11,0xaf,0xe0,0x0a,0x22,0x48,0xe0, +0x70,0x29,0xaf,0xe0,0x0a,0x22,0x30,0x3c,0x99,0x01,0xaf,0xe0,0x0a,0x22,0x48, +0xe0,0x74,0x39,0x4f,0xa3,0x5a,0x43,0xd0,0xe0,0x1f,0x0f,0x92,0xc1,0x10,0x00, +0x89,0x3d,0xb8,0x63,0x88,0x62,0xa8,0x1b,0x82,0x28,0x20,0xb8,0x0b,0xe0,0x08, +0x00,0xbc,0x9a,0xa8,0x63,0xf8,0x0a,0xe0,0xcf,0x11,0x0b,0x9f,0x96,0x59,0x02, +0xd8,0x1a,0xda,0xa9,0x0b,0xdd,0x0c,0x1e,0x92,0x0a,0x00,0x0c,0x48,0x76,0xa8, +0x0d,0x37,0x69,0x05,0xe0,0xfc,0xc0,0x06,0x03,0x00,0xf0,0x99,0x11,0x1b,0xee, +0xc2,0xcc,0xfc,0x0b,0xaa,0xd7,0x9a,0xdf,0xe8,0xb2,0xf0,0xee,0x43,0x86,0x00, +0x00,0x00,0x0c,0x0e,0x0c,0x0d,0x1c,0xf9,0x0f,0x82,0x88,0x04,0x44,0x0c,0x0c, +0x11,0xb2,0xc7,0x60,0x6f,0x62,0xb8,0x43,0x44,0x0c,0x0c,0x11,0xa1,0x72,0x52, +0x0f,0xa2,0xb8,0x43,0x44,0x0c,0x0c,0x11,0x4f,0x22,0xb8,0x43,0x44,0x0c,0x0c, +0x11,0xe0,0xf2,0x21,0x1b,0x8f,0x4f,0x01,0x04,0x29,0x44,0x0c,0x0c,0x11,0x6f, +0xf4,0x00,0x22,0x44,0x0c,0x0c,0x11,0xaf,0x61,0x81,0x04,0x44,0x0c,0x0c,0x11, +0x4f,0x23,0x42,0x43,0x42,0x0a,0x04,0x00,0x4f,0x00,0x04,0x28,0xf4,0x20,0x96, +0x09,0x76,0xa8,0x3e,0xa8,0x43,0x88,0x73,0x98,0x13,0x88,0x18,0x98,0x19,0xa8, +0x1a,0x90,0xed,0x87,0xaa,0xad,0x8a,0x8d,0xc2,0x08,0x00,0xa2,0x0a,0x00,0x1b, +0xdd,0x4f,0xb5,0xa6,0x43,0xb2,0x0a,0x01,0x00,0x9f,0x63,0x80,0x21,0x44,0x0c, +0x0c,0x11,0x8f,0x59,0x79,0x43,0xec,0x30,0x1d,0x01,0x90,0x04,0x03,0x90,0x9c, +0x34,0x90,0xcc,0x20,0xc2,0x48,0x00,0x7c,0xf8,0xe0,0xd0,0x14,0xc8,0x73,0x00, +0x1d,0x40,0xc8,0x1c,0x00,0xd6,0xa1,0xca,0xcf,0xb2,0x0c,0x00,0x80,0xdd,0x30, +0xd0,0xbb,0x10,0xb2,0x4c,0x00,0xe8,0x57,0x16,0xde,0x0b,0x98,0x93,0xf8,0x81, +0xe8,0x19,0xe6,0x1f,0x02,0xc6,0x2b,0x00,0x2f,0x20,0x01,0x22,0x44,0x0c,0x0c, +0x11,0x8f,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11,0x0c,0x0d,0x76,0xaf,0x9a,0xf8, +0x23,0xa8,0x53,0x88,0x63,0xc8,0x94,0xea,0xbd,0xb2,0x0b,0x00,0xc8,0x1c,0x88, +0x18,0xa8,0x1a,0xf8,0x1f,0xaa,0xad,0xfa,0xfd,0x8a,0x8d,0x82,0x08,0x00,0xf2, +0x0f,0x00,0xc0,0xad,0x97,0x80,0xff,0x10,0x88,0x03,0xc8,0x73,0x88,0x18,0xc8, +0x1c,0x80,0xed,0x97,0xca,0xcd,0x2f,0x98,0x01,0x82,0xd0,0x40,0xbf,0x0b,0xa2, +0x0a,0x00,0xef,0xf9,0x93,0x43,0xf4,0x40,0x26,0x08,0x50,0xcc,0x30,0x6f,0xf7, +0x79,0x43,0x48,0x40,0x20,0x01,0x88,0x84,0x6f,0x6f,0x01,0x42,0x48,0x40,0x24, +0x11,0x4f,0x95,0x79,0x43,0xfa,0x0a,0x01,0x00,0xef,0x11,0x03,0x62,0x48,0x40, +0x20,0x29,0x5f,0x63,0x0a,0x2b,0x44,0x0c,0x0c,0x11,0x0f,0xb1,0xc3,0x2b,0x48, +0x40,0x24,0x39,0x98,0x94,0x4f,0x4f,0x01,0x42,0xd0,0x40,0x27,0x0b,0xef,0x33, +0x03,0x62,0xb6,0x0a,0x01,0x00,0x3f,0x62,0x0c,0x2a,0x44,0x0c,0x0c,0x11,0xd0, +0x29,0xd6,0x1b,0xdd,0x1d,0xf0,0x98,0x83,0x86,0xcf,0xff,0x36,0x41,0x00,0xd8, +0x81,0xc8,0x0d,0xd8,0x1d,0x98,0x1c,0xc8,0x0c,0xd8,0x0d,0x88,0xb9,0xd8,0x1d, +0xc8,0x7c,0x92,0x29,0x0d,0x80,0x87,0xa0,0x80,0x40,0x0c,0x90,0x97,0xa0,0x90, +0x80,0x0c,0xcf,0x00,0x84,0x28,0x44,0x0c,0x0c,0x11,0x4f,0x01,0x04,0x29,0x44, +0x0c,0x0c,0x11,0xe6,0x1c,0x02,0x86,0x3d,0x00,0xd0,0x7d,0x20,0x76,0xac,0x65, +0xe1,0x0a,0x52,0xa2,0x05,0x00,0x60,0x03,0x8c,0xf2,0x04,0x00,0x0f,0x88,0x02, +0x82,0xec,0x30,0x84,0x10,0x0f,0xaa,0x02,0x82,0xe0,0x30,0x05,0x01,0xb0,0x04, +0x03,0xe0,0xbb,0x10,0x80,0xea,0x11,0xe0,0xbb,0x20,0xb0,0x04,0x13,0x20,0x20, +0x00,0x91,0xff,0x51,0x80,0x04,0x03,0x90,0x88,0x10,0xc0,0x9f,0x11,0x90,0x88, +0x20,0x80,0x04,0x13,0x20,0x20,0x00,0xaf,0x30,0x21,0x22,0x44,0x0c,0x0c,0x11, +0x0f,0x30,0x25,0x22,0x44,0x0c,0x0c,0x11,0x0f,0x30,0x05,0x22,0x44,0x0c,0x0c, +0x11,0xe0,0x04,0x03,0xe0,0xe0,0x34,0xe2,0x47,0x00,0x1b,0x77,0xd0,0x7d,0x20, +0x76,0xac,0x84,0x81,0xf1,0x51,0x50,0x04,0x03,0x42,0x07,0x00,0x80,0x55,0x10, +0x40,0x84,0x11,0x80,0x55,0x20,0x50,0x04,0x13,0x20,0x20,0x00,0xf1,0xe9,0x51, +0xe0,0x04,0x03,0xd2,0x02,0x00,0xf0,0xee,0x10,0x80,0xfd,0x11,0xf0,0xee,0x20, +0xe0,0x04,0x13,0x20,0x20,0x00,0xb1,0xe4,0x51,0x4f,0x21,0x65,0x22,0x44,0x0c, +0x0c,0x11,0xa0,0x04,0x03,0xc0,0x04,0x03,0xc0,0xc8,0x34,0xc2,0x42,0x00,0x92, +0x07,0x00,0xb0,0xaa,0x10,0xc0,0xb9,0x11,0xb0,0xaa,0x20,0xa0,0x04,0x13,0x20, +0x20,0x00,0x81,0xdb,0x51,0x50,0x04,0x03,0x42,0x03,0x00,0x80,0x55,0x10,0x40, +0x55,0x20,0x50,0x04,0x13,0x20,0x20,0x00,0x1b,0x77,0x0f,0x20,0x45,0x22,0x44, +0x0c,0x0c,0x11,0x1b,0x22,0xf0,0x04,0x03,0xf0,0xf0,0x34,0xf2,0x43,0x00,0x1b, +0x33,0x1d,0xf0,0x00,0x36,0x41,0x00,0xb8,0x25,0x0c,0x0a,0x92,0x9b,0x01,0xb2, +0x2b,0x12,0x30,0x99,0xd1,0xb0,0x99,0x90,0xcf,0x34,0xc1,0x42,0x44,0x0c,0x0c, +0x11,0x0c,0x78,0x6f,0xe4,0x00,0x22,0x12,0x12,0x04,0x00,0x3f,0x40,0x02,0x40, +0x44,0x0c,0x0c,0x11,0x76,0x00,0x0c,0xdd,0x05,0xbd,0x03,0xad,0x02,0x88,0xc4, +0xcd,0x04,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x36,0x41,0x00,0x68,0x16,0x58,0x15, +0x88,0x42,0xa8,0x02,0xb8,0x13,0x0c,0x1c,0x38,0x81,0xc0,0x00,0xf3,0xb0,0xb7, +0xa0,0xa8,0x1a,0xe0,0xc7,0x11,0xd8,0x6a,0xf2,0x9a,0x0e,0x37,0x18,0x0b,0xe8, +0x32,0x39,0x42,0xe0,0x31,0x21,0x39,0x32,0x46,0x00,0x00,0x38,0x32,0xe2,0x9a, +0x0f,0xf7,0x97,0x04,0x30,0x31,0x21,0x39,0x32,0xe7,0x97,0x04,0x30,0x31,0x21, +0x39,0x32,0x50,0xe3,0x47,0x88,0x12,0x60,0x23,0x57,0xf7,0xa7,0x17,0xaf,0xe0, +0x0a,0x22,0x0a,0x28,0x21,0x02,0xaf,0xe0,0x0a,0x22,0x0a,0x18,0x99,0x01,0xcf, +0x10,0x00,0x08,0xe0,0x00,0x1e,0x1a,0x60,0x33,0x57,0x50,0xf3,0x47,0xaf,0xe0, +0x0a,0x22,0x0a,0x28,0x21,0x02,0xaf,0xe0,0x0a,0x22,0x0a,0x18,0x99,0x01,0xef, +0xff,0xbf,0x42,0xe0,0x00,0x1e,0x1a,0xef,0xce,0x91,0x62,0xd0,0x00,0x1e,0x1a, +0x60,0x23,0x57,0x50,0xe3,0x47,0x50,0xf3,0x47,0x60,0x33,0x57,0xaf,0xe0,0x0a, +0x22,0x02,0x18,0x99,0x01,0xaf,0xe0,0x0a,0x22,0x02,0x28,0x21,0x02,0xaf,0xe0, +0x0a,0x22,0xc0,0x00,0x1e,0x2a,0xaf,0xe0,0x0a,0x22,0xee,0x2b,0x11,0x00,0xaf, +0xe0,0x0a,0x22,0xc0,0x00,0x1e,0x1a,0xaf,0xe0,0x0a,0x22,0xee,0x1b,0x09,0x00, +0xaf,0xe0,0x0a,0x22,0xee,0x0b,0x01,0x00,0xaf,0xe0,0x0a,0x22,0x44,0x28,0x14, +0x11,0xaf,0xe0,0x0a,0x22,0x44,0x18,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x44,0x0c, +0x04,0x01,0x8f,0x21,0x01,0x22,0x44,0x0c,0x0c,0x11,0x0c,0x0f,0x70,0x52,0x21, +0xaf,0x20,0x09,0x22,0x44,0x0c,0x0c,0x11,0xe8,0x62,0x0f,0x80,0x04,0x29,0x44, +0x0c,0x0c,0x11,0xea,0xec,0xe0,0x20,0x1c,0x9c,0x88,0x98,0x3a,0xcf,0xaf,0xc1, +0x42,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x42,0x36,0x10,0x10,0xcf,0x01, +0x84,0x29,0x44,0x0c,0x0c,0x11,0x98,0xa2,0xd8,0x82,0x90,0x97,0xb0,0xda,0xdc, +0xd0,0x30,0x1c,0x90,0x02,0x1c,0x0f,0x00,0x85,0x28,0xe0,0x70,0xaf,0x09,0x8f, +0x1f,0xbf,0x42,0xd0,0x40,0xa7,0x09,0x0f,0x0f,0x79,0x43,0xf8,0x40,0x86,0x0b, +0x80,0x87,0xc0,0x00,0x2e,0x1d,0x00,0x3d,0x1d,0x6f,0x53,0x00,0x2a,0x50,0xb0, +0x20,0x31,0xef,0xc9,0x02,0x62,0x50,0xa0,0x20,0x21,0xa0,0x80,0x1c,0x8f,0xf0, +0x0a,0x22,0xa4,0xa0,0xd0,0x05,0xaf,0xca,0x68,0x43,0xc4,0x10,0x24,0x33,0x2f, +0x6a,0x00,0x82,0xc0,0x10,0x24,0x23,0xd0,0x04,0x03,0xe0,0x04,0x03,0xcf,0xc1, +0x03,0x42,0xa4,0x90,0x50,0x02,0xaf,0xa1,0x01,0x42,0xa4,0x90,0x55,0x02,0xe0, +0x6d,0x10,0xcf,0x4c,0x01,0x22,0x0a,0x88,0xc9,0x04,0x60,0x33,0x20,0x0f,0x6b, +0x00,0x82,0x50,0x90,0x40,0x01,0xf9,0x0b,0x6f,0xdb,0x1f,0x62,0xa4,0x80,0xc0, +0x04,0x1f,0xe0,0x13,0x0c,0x44,0x0c,0x0c,0x11,0x00,0x0b,0x2d,0x1d,0xf0,0x36, +0x41,0x00,0xdd,0x05,0xcd,0x04,0xbd,0x03,0x88,0x22,0xad,0x02,0xe0,0x08,0x00, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x71,0x49,0x51,0x61,0x49,0x51,0x51,0x49, +0x51,0xec,0x04,0x0c,0x09,0xa2,0x25,0x16,0x82,0x25,0x17,0x1b,0xaa,0xa2,0x65, +0x16,0xe0,0xaa,0x11,0x5a,0xba,0x6a,0xaa,0xa2,0x67,0x7f,0xcc,0x48,0x92,0x6b, +0x28,0x86,0x00,0x00,0x92,0x6b,0x29,0x66,0x14,0x0a,0xb2,0x25,0x16,0xe6,0x1b, +0x04,0x0c,0x1c,0xc2,0x65,0x17,0x8c,0xe4,0xd2,0x25,0x17,0x32,0x65,0x18,0xcc, +0x6d,0x82,0x25,0x19,0xad,0x03,0xe0,0x08,0x00,0xad,0x02,0x25,0x13,0x00,0x2d, +0x0a,0x66,0x24,0x37,0xa2,0x25,0x16,0x92,0x25,0x17,0x50,0xba,0xa0,0xac,0xd9, +0xc2,0x2b,0x29,0xb2,0xcb,0xfc,0xc2,0x65,0x18,0x0b,0xaa,0xa2,0x65,0x16,0x60, +0xda,0xa0,0xd2,0x67,0x7f,0xa2,0x2b,0x29,0x8c,0x99,0xc2,0x2b,0x2a,0xc7,0xba, +0x0d,0xc2,0x6b,0x29,0x1d,0xf0,0xe2,0x2b,0x28,0xa7,0xbe,0x02,0xa2,0x6b,0x28, +0x1d,0xf0,0x82,0x25,0x19,0xa2,0x2b,0x28,0xe0,0x08,0x00,0xa2,0x25,0x16,0x92, +0x25,0x17,0x50,0xba,0xa0,0xc2,0x2b,0x28,0xc6,0xee,0xff,0x36,0x41,0x00,0x7c, +0x85,0x31,0x1f,0x51,0x7b,0x42,0x82,0x23,0x17,0x50,0x44,0x10,0x9c,0x88,0x91, +0x1a,0x51,0xa2,0x23,0x18,0x92,0x29,0x7f,0x7b,0xaa,0x50,0x5a,0x10,0x88,0x09, +0x4a,0x45,0x40,0x88,0x53,0x89,0x09,0x46,0x0d,0x00,0x82,0x23,0x1a,0xe0,0x08, +0x00,0xc2,0x23,0x18,0xcc,0x3c,0xcd,0x0a,0xa2,0x63,0x18,0xad,0x02,0x0c,0x8b, +0x82,0x23,0x1b,0x7b,0x9c,0x50,0x59,0x10,0x4a,0x45,0xe0,0x08,0x00,0x82,0x23, +0x1a,0xe0,0x08,0x00,0xa2,0x23,0x16,0x30,0xaa,0xa0,0x92,0x2a,0x28,0x47,0xb9, +0x02,0x42,0x6a,0x28,0x2d,0x05,0x42,0x63,0x18,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x00,0x7c,0xc5,0x31,0x04,0x51,0x3b,0x42,0x82,0x23,0x17,0x50,0x44,0x10, +0x9c,0x88,0x91,0xff,0x50,0xa2,0x23,0x18,0x92,0x29,0x7f,0x3b,0xaa,0x50,0x5a, +0x10,0x88,0x09,0x4a,0x45,0x40,0x88,0x53,0x89,0x09,0x46,0x0d,0x00,0x82,0x23, +0x1a,0xe0,0x08,0x00,0xc2,0x23,0x18,0xcc,0x3c,0xcd,0x0a,0xa2,0x63,0x18,0xad, +0x02,0x0c,0x4b,0x82,0x23,0x1b,0x3b,0x9c,0x50,0x59,0x10,0x4a,0x45,0xe0,0x08, +0x00,0x82,0x23,0x1a,0xe0,0x08,0x00,0xa2,0x23,0x16,0x30,0xaa,0xa0,0x92,0x2a, +0x28,0x47,0xb9,0x02,0x42,0x6a,0x28,0x2d,0x05,0x42,0x63,0x18,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0x7c,0x05,0x31,0xe9,0x50,0xfb,0x42,0x82,0x23,0x17, +0x50,0x44,0x10,0x9c,0x88,0x91,0xe4,0x50,0xa2,0x23,0x18,0x92,0x29,0x7f,0xfb, +0xaa,0x50,0x5a,0x10,0x88,0x09,0x4a,0x45,0x40,0x88,0x53,0x89,0x09,0x46,0x0d, +0x00,0x82,0x23,0x1a,0xe0,0x08,0x00,0xc2,0x23,0x18,0xcc,0x3c,0xcd,0x0a,0xa2, +0x63,0x18,0xad,0x02,0x1c,0x0b,0x82,0x23,0x1b,0xfb,0x9c,0x50,0x59,0x10,0x4a, +0x45,0xe0,0x08,0x00,0x82,0x23,0x1a,0xe0,0x08,0x00,0xa2,0x23,0x16,0x30,0xaa, +0xa0,0x92,0x2a,0x28,0x47,0xb9,0x02,0x42,0x6a,0x28,0x2d,0x05,0x42,0x63,0x18, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x39,0x02,0xe0,0xa3,0x11,0x1c,0x0b, +0x25,0x53,0x00,0xa9,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a, +0x0c,0x4b,0xe5,0xd2,0x04,0x5d,0x0a,0xbd,0x04,0xe5,0x42,0x00,0x59,0x02,0xad, +0x04,0x1c,0x0b,0x25,0x51,0x00,0x2d,0x0a,0x0c,0x4b,0x0c,0x8a,0x25,0xd1,0x04, +0x29,0x1a,0x49,0x0a,0xa9,0x03,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x0c, +0x4a,0x65,0xd3,0x04,0xb8,0x02,0xb8,0x0b,0x3d,0x0a,0xb8,0x7b,0xa5,0x51,0x03, +0x39,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0x0c,0x1a,0xa5, +0xd1,0x04,0xa9,0x12,0x49,0x22,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0x0c,0x4a, +0xa5,0xd0,0x04,0x3d,0x0a,0xe5,0x4a,0x03,0x39,0x12,0x49,0x22,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0x5c,0x0a,0x25,0xcf,0x04,0x3d,0x0a,0xb8, +0x02,0x65,0x59,0x03,0x39,0x52,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xbd, +0x03,0x0c,0x1a,0xa5,0xcd,0x04,0xa9,0x12,0x49,0x22,0x1d,0xf0,0x36,0x41,0x00, +0xbd,0x03,0x1c,0x8a,0xa5,0xcc,0x04,0xb2,0x22,0x11,0x3d,0x0a,0xb8,0x0b,0xe5, +0x54,0x03,0x32,0x62,0x14,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x02, +0xe5,0x8f,0x00,0x8b,0xa2,0xe5,0x6f,0x00,0x1d,0xf0,0x00,0x36,0x41,0x00,0xa1, +0x99,0x50,0x1c,0x0b,0xa2,0x2a,0x1c,0xa9,0x02,0xc0,0xaa,0x11,0x25,0x45,0x00, +0xa9,0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x0c,0xca,0x65,0xc8,0x04, +0x3d,0x0a,0xb8,0x02,0x25,0x35,0x03,0x39,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x00,0xbd,0x03,0x0c,0x4a,0xe5,0xc6,0x04,0x3d,0x0a,0xbd,0x02,0xc8,0x92, +0x65,0x35,0x03,0x39,0x32,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x4c,0x0a, +0x65,0xc5,0x04,0xb8,0x82,0xb8,0x1b,0xb8,0xab,0x3d,0x0a,0xb8,0x0b,0xa5,0x88, +0x03,0x39,0x92,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02,0xa5,0x88,0x00,0xb8, +0x73,0x8b,0xa2,0xa5,0x71,0x00,0xa2,0xc2,0x10,0xe5,0x87,0x00,0x1d,0xf0,0x00, +0x36,0x41,0x00,0xbd,0x03,0x4c,0x4a,0x25,0xc2,0x04,0xc8,0x02,0x3d,0x0a,0xb8, +0x1c,0xc8,0x0c,0xe5,0xfb,0x00,0x39,0x12,0xa5,0xc6,0x04,0x4d,0x0a,0x1c,0x0a, +0xbd,0x04,0x65,0xc0,0x04,0xb8,0x02,0x3d,0x0a,0xb8,0x1b,0xe5,0x3b,0x03,0xc8, +0x22,0xad,0x04,0x39,0x1c,0x65,0xbe,0x04,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd, +0x03,0x1c,0x8a,0xa5,0xbe,0x04,0x3d,0x0a,0xa5,0x92,0x03,0x39,0x12,0x1d,0xf0, +0x00,0x36,0x41,0x00,0xbd,0x03,0x4c,0xca,0x65,0xbd,0x04,0x3d,0x0a,0xb8,0x12, +0xa5,0x32,0x03,0x39,0x22,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xbd,0x03, +0x1c,0x0a,0xe5,0xbb,0x04,0x3d,0x0a,0x25,0x30,0x03,0x39,0x12,0x1d,0xf0,0x00, +0x36,0x41,0x00,0xbd,0x03,0x0c,0x8a,0xa5,0xba,0x04,0x3d,0x0a,0x25,0x2e,0x03, +0x39,0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x3c,0xca,0x65,0xb9,0x04, +0x3d,0x0a,0xb8,0x02,0x25,0x27,0x03,0x39,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x00,0xbd,0x03,0x2c,0x0a,0xe5,0xb7,0x04,0x3d,0x0a,0xb8,0x22,0xa5,0x28, +0x03,0x39,0x32,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b, +0x25,0xb3,0x04,0x5d,0x0a,0xbd,0x04,0x65,0x64,0x00,0x59,0x02,0xad,0x04,0x1c, +0x0b,0x65,0x31,0x00,0x2d,0x0a,0x0c,0x4b,0x0c,0x8a,0x65,0xb1,0x04,0x29,0x1a, +0x49,0x0a,0xa9,0x03,0x1d,0xf0,0x00,0x36,0x41,0x00,0x32,0x62,0x12,0x3c,0xaa, +0xbd,0x03,0x65,0xb3,0x04,0xa9,0x42,0xbd,0x03,0x4c,0x4a,0xe5,0xb2,0x04,0xa9, +0x52,0xbd,0x03,0xa2,0xa0,0xfe,0x25,0xb2,0x04,0xa9,0x32,0x1d,0xf0,0x36,0x41, +0x00,0xbd,0x03,0x3c,0x8a,0x65,0xb1,0x04,0x3d,0x0a,0xb8,0xf2,0xe5,0xa4,0x0a, +0xd2,0xc3,0x28,0xe2,0xc3,0x20,0x92,0x22,0x11,0x88,0x13,0xc8,0x23,0x41,0x30, +0x50,0xb8,0x63,0xf2,0x24,0x10,0x32,0x62,0x10,0xf8,0x4f,0x89,0x09,0x88,0x92, +0xf8,0x8f,0x89,0x29,0x82,0xc3,0x30,0xf2,0x2f,0x16,0xc9,0x19,0xa8,0xb2,0xf9, +0x39,0xb9,0x59,0xa9,0x49,0xe9,0x69,0x89,0x89,0xd9,0x79,0x82,0xc2,0x34,0x92, +0x22,0x12,0xf8,0x33,0xf9,0x19,0xe8,0xc2,0xe9,0x29,0xd8,0x53,0xd9,0x09,0xc9, +0x39,0xb9,0x49,0xa9,0x59,0x89,0x69,0x25,0xb1,0x04,0x3d,0x0a,0xa8,0x22,0xbd, +0x03,0xa5,0xf2,0xff,0xa8,0x72,0xbd,0x03,0xe5,0xe4,0xff,0xc2,0x24,0x10,0xa8, +0x82,0xbd,0x03,0xd2,0x22,0x14,0xe2,0x22,0x13,0xa5,0x57,0x01,0xa8,0x92,0x0c, +0x09,0xbd,0x03,0x99,0x4a,0xa8,0xa2,0x65,0xe1,0xff,0xa8,0x42,0xbd,0x03,0xa5, +0xee,0xff,0xa8,0x52,0xbd,0x03,0x25,0xee,0xff,0xa8,0x62,0xbd,0x03,0xa5,0xde, +0xff,0xa8,0x32,0xbd,0x03,0xa5,0xee,0xff,0xad,0x03,0xa5,0xa5,0x04,0x1d,0xf0, +0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0x2c,0x4a,0xa5,0xa5, +0x04,0x3d,0x0a,0xb8,0xc2,0x25,0xa2,0x0a,0xe1,0x04,0x50,0x98,0xe2,0xe2,0x2e, +0x10,0xf8,0x33,0xa8,0x5e,0xe8,0x4e,0x4b,0x8a,0x39,0xd2,0xe2,0xce,0x34,0xf9, +0x09,0xd8,0x43,0xd9,0x29,0xc8,0x63,0xc9,0x39,0xb8,0x2a,0xb9,0x69,0xf8,0x3a, +0xf9,0x59,0xe9,0xa9,0xd2,0x22,0x11,0xd9,0x19,0xc8,0x73,0xc9,0xb9,0xb8,0x83, +0xb9,0xc9,0xa9,0x79,0x89,0x49,0xe5,0xa6,0x04,0x3d,0x0a,0x48,0x52,0x1c,0x4a, +0xbd,0x03,0xa5,0xa0,0x04,0xb8,0x34,0xb8,0x1b,0xb8,0xab,0x5d,0x0a,0xb8,0x0b, +0xe5,0xac,0x03,0x59,0x44,0xa8,0x42,0xbd,0x03,0xe5,0xe6,0xff,0xa8,0x72,0xbd, +0x03,0x65,0x37,0x01,0xbd,0x03,0xa8,0x32,0xd8,0x82,0x0c,0x0c,0xc9,0x4d,0x25, +0xe4,0xff,0xad,0x03,0xa5,0x9c,0x04,0x1d,0xf0,0x00,0x00,0x00,0x00,0x00,0x00, +0x36,0x41,0x00,0x4b,0xa2,0x0c,0x5b,0x0c,0x8c,0x25,0x43,0x00,0xcb,0xa2,0x0c, +0x5b,0x0c,0x8c,0xa5,0x42,0x00,0xa2,0xc2,0x14,0x0c,0x5b,0x25,0x35,0x04,0xa2, +0xc2,0x1c,0x0c,0x5b,0xa5,0x34,0x04,0xa2,0xc2,0x24,0x0c,0x5b,0x25,0x34,0x04, +0xa2,0xc2,0x2c,0x0c,0x5b,0xa5,0x33,0x04,0xa2,0xc2,0x34,0x0c,0x5b,0x25,0x33, +0x04,0xa2,0xc2,0x3c,0x0c,0x5b,0xa5,0x32,0x04,0xa2,0xc2,0x44,0x1c,0xeb,0x0c, +0x8c,0xe5,0x3e,0x00,0xa2,0xc2,0x4c,0x1c,0xeb,0x0c,0x8c,0x65,0x3e,0x00,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x1c,0x0b,0xa5,0x93,0x04,0x81,0xcd,0x4f, +0x91,0xcb,0x4f,0x49,0x1a,0x39,0x0a,0xa9,0x02,0x99,0x22,0x89,0x32,0x1d,0xf0, +0x36,0x41,0x00,0x39,0x02,0x49,0x12,0x59,0x22,0x59,0x32,0x69,0x42,0x79,0x52, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x39,0x02,0x49,0x12,0x1c,0x0b,0x40, +0xa3,0x82,0xe0,0xaa,0x11,0x65,0x0f,0x00,0xa9,0x22,0x1d,0xf0,0x00,0x00,0x36, +0x41,0x00,0xad,0x03,0x39,0x02,0x1c,0x0b,0x25,0x0e,0x00,0xa9,0x12,0x1d,0xf0, +0x36,0x41,0x00,0x68,0x63,0x0c,0x8a,0x0c,0x4b,0xe5,0x8d,0x04,0x49,0x1a,0x39, +0x0a,0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0x25,0x8d,0x04,0x3d,0x0a,0xbd,0x06,0xa5, +0x29,0x04,0x39,0x42,0xc8,0x02,0x0c,0x09,0x76,0xa6,0x0f,0xa8,0x42,0x88,0x02, +0xa8,0x1a,0x88,0x18,0xaa,0xa9,0x88,0x38,0x4b,0x99,0x89,0x0a,0xc8,0x1c,0xb1, +0xac,0x4f,0xc8,0x0c,0xc9,0x32,0x59,0x22,0xb9,0x52,0x1d,0xf0,0x36,0x41,0x00, +0x79,0x42,0x69,0x32,0x0c,0xca,0x0c,0x4b,0x65,0x89,0x04,0x59,0x2a,0x49,0x1a, +0x39,0x0a,0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0x65,0x88,0x04,0x3d,0x0a,0x65,0x50, +0x00,0x39,0x72,0x0c,0x8a,0x0c,0x4b,0x65,0x87,0x04,0x3d,0x0a,0x65,0x4f,0x00, +0x39,0x82,0x81,0x9e,0x4f,0x91,0x9c,0x4f,0x0c,0x1a,0xa9,0x62,0x99,0x92,0x89, +0xa2,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x39,0x02,0x49,0x12,0x59,0x22,0x79, +0x62,0xa2,0xc2,0x40,0x0c,0x4b,0xa5,0x21,0x04,0x0c,0x8a,0x0c,0x4b,0x65,0x84, +0x04,0x3d,0x0a,0x25,0x4c,0x00,0x32,0x62,0x12,0x0c,0x8a,0x0c,0x4b,0x65,0x83, +0x04,0x3d,0x0a,0x65,0x4b,0x00,0x32,0x62,0x13,0x0c,0x8a,0x0c,0x4b,0x65,0x82, +0x04,0x3d,0x0a,0x65,0x4a,0x00,0x32,0x62,0x14,0x69,0x52,0x81,0x8b,0x4f,0x91, +0x89,0x4f,0x92,0x62,0x16,0x82,0x62,0x17,0x1d,0xf0,0x36,0x41,0x00,0x66,0xb3, +0x08,0xad,0x02,0xe5,0xa4,0xff,0x2d,0x0a,0x1d,0xf0,0x66,0x43,0x08,0xad,0x02, +0x65,0x9d,0xff,0x2d,0x0a,0x1d,0xf0,0xad,0x02,0x25,0x96,0xff,0x2d,0x0a,0x1d, +0xf0,0x36,0x41,0x00,0x39,0x02,0x49,0x12,0x59,0x22,0x69,0x32,0x79,0x42,0xa2, +0xc2,0x1c,0x88,0x91,0x98,0x81,0x99,0x52,0x89,0x62,0x25,0x45,0x00,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x41,0x00,0xa1,0x6f,0x4f,0x1c,0x0b,0xa2,0x2a,0x1c,0xa9, +0x02,0xe5,0xfa,0xff,0xa9,0x12,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b, +0xe5,0x7a,0x04,0x81,0x70,0x4f,0x49,0x1a,0x39,0x0a,0xa9,0x02,0x89,0x22,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0x65,0x79,0x04,0x49,0x1a,0x39, +0x0a,0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0x65,0x78,0x04,0x4d,0x0a,0xb8,0x63,0x25, +0x15,0x04,0x49,0x32,0x0c,0x09,0x88,0x43,0xa1,0x65,0x4f,0x76,0xa8,0x07,0xb8, +0x14,0xba,0xb9,0xa9,0x0b,0x4b,0x99,0xc1,0x62,0x4f,0xc9,0x42,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0xa5,0x75,0x04,0x81,0x60,0x4f, +0x91,0x5e,0x4f,0xb1,0x5d,0x4f,0x49,0x1a,0x39,0x0a,0x59,0x32,0x69,0x42,0xa9, +0x02,0xb9,0x52,0xb9,0x62,0x99,0x72,0x89,0x82,0x0c,0x0a,0xa9,0x12,0x1d,0xf0, +0x00,0x36,0x41,0x00,0x79,0x42,0xa2,0xc2,0x18,0x25,0x1b,0x00,0xa2,0xc2,0x20, +0xe5,0x1a,0x00,0xa2,0xc2,0x28,0x65,0x1a,0x00,0xa2,0xc2,0x30,0xe5,0x39,0x00, +0xa2,0xc2,0x38,0x65,0x39,0x00,0xa2,0xc2,0x58,0x25,0x39,0x00,0x39,0x02,0x49, +0x12,0x59,0x22,0x69,0x32,0x81,0x51,0x4f,0x91,0x50,0x4f,0xa1,0x4e,0x4f,0xb1, +0x4c,0x4f,0xc1,0x4a,0x4f,0xd1,0x49,0x4f,0xd2,0x62,0x1b,0xc2,0x62,0x1c,0xb2, +0x62,0x1d,0xa2,0x62,0x20,0x92,0x62,0x1f,0x82,0x62,0x1e,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x0c,0x4a,0x0c,0x4b,0x65,0x6d,0x04,0x81,0x46,0x4f,0x39,0x0a,0xa9, +0x02,0x49,0x32,0x89,0x42,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02,0xb8,0x63, +0xe5,0x08,0x04,0x0c,0x8a,0x0c,0x4b,0x65,0x6b,0x04,0x81,0x3f,0x4f,0x49,0x1a, +0x39,0x0a,0xa9,0x22,0x89,0x32,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a, +0x0c,0x4b,0xe5,0x69,0x04,0x81,0x3a,0x4f,0x49,0x1a,0x39,0x0a,0xa9,0x02,0x89, +0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0x65,0x68,0x04,0x81, +0x35,0x4f,0x49,0x1a,0x39,0x0a,0xa9,0x02,0x89,0x12,0x1d,0xf0,0x00,0x36,0x81, +0x00,0x39,0x41,0xa2,0xc2,0x18,0xb2,0x24,0x15,0xc2,0x24,0x14,0x3b,0xbb,0x0b, +0xcc,0xc0,0xc2,0x21,0xb0,0xb2,0x21,0xc0,0xbb,0xc0,0x65,0x17,0x00,0xa2,0xc2, +0x20,0xa5,0xe8,0xff,0xa2,0xc2,0x28,0x25,0x2d,0x00,0xa2,0xc2,0x30,0xa5,0x2c, +0x00,0x2c,0x4a,0x1c,0x0b,0xe5,0x63,0x04,0xf2,0x24,0x1f,0xe2,0x24,0x1d,0xd2, +0x24,0x20,0xc2,0x24,0x1e,0xb2,0x24,0x24,0x82,0x24,0x21,0x89,0x01,0x32,0x24, +0x22,0x39,0x11,0x3d,0x0a,0xa5,0xe3,0xff,0x39,0xe2,0x2c,0x4a,0x1c,0x0b,0x0c, +0x09,0x99,0xf2,0x65,0x61,0x04,0xf2,0x24,0x27,0xe2,0x24,0x25,0xd2,0x24,0x28, +0xc2,0x24,0x26,0xb2,0x24,0x2c,0x82,0x24,0x29,0x89,0x01,0x32,0x24,0x2a,0x39, +0x11,0x3d,0x0a,0xe5,0xe0,0xff,0x32,0x62,0x10,0x72,0x62,0x13,0x62,0x62,0x12, +0x1c,0x0a,0x1c,0x0b,0x92,0x21,0x10,0x92,0x62,0x18,0x25,0x5e,0x04,0xb1,0x0e, +0x4f,0xc1,0x0c,0x4f,0x0c,0x0d,0xf8,0x26,0xe8,0x41,0x50,0xff,0xa0,0xf8,0x0f, +0x59,0x3a,0xf9,0x2a,0x49,0x1a,0xe9,0x0a,0xd2,0x62,0x14,0xc2,0x62,0x15,0xa2, +0x62,0x11,0xb2,0x62,0x16,0xa1,0x06,0x4f,0xa2,0x62,0x17,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x0c,0xca,0x0c,0x4b,0xa5,0x5a,0x04,0x59,0x2a,0x49,0x1a,0x39,0x0a, +0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0xa5,0x59,0x04,0x3d,0x0a,0xa5,0x21,0x00,0xb8, +0x02,0x39,0x72,0xb8,0x1b,0x88,0xf7,0xa8,0x3b,0xb8,0x1b,0xe0,0x08,0x00,0xa9, +0x62,0x69,0x22,0xc1,0xf8,0x4e,0xc9,0x82,0x1d,0xf0,0x36,0x41,0x00,0xa1,0xdb, +0x4e,0x1c,0x0b,0xa2,0x2a,0x1c,0xa9,0x02,0xd0,0xaa,0x11,0xa5,0xd5,0xff,0xa9, +0x12,0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x04,0x39,0x02,0xf0,0xa3,0x11,0xa5, +0xd4,0xff,0xa9,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x39,0x02,0xd0, +0xa3,0x11,0x1c,0x0b,0x65,0xd3,0xff,0xa9,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x00,0xa2,0xc2,0x14,0x65,0x1b,0x00,0xa2,0xc2,0x1c,0xe5,0x1a,0x00,0xa2, +0xc2,0x24,0xe5,0xfa,0xff,0x0c,0x8a,0x0c,0x4b,0xe5,0x51,0x04,0x81,0xe1,0x4e, +0x0c,0x09,0x49,0x1a,0x39,0x0a,0xa9,0x02,0x99,0x22,0x89,0xb2,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0xcb,0xa2,0xbd,0x03,0x1c,0x0c,0xe5,0xf9,0xff,0x98, +0x42,0x82,0x24,0x14,0x89,0x22,0x59,0xf2,0x99,0x02,0x90,0xa3,0x90,0xa2,0xca, +0xfe,0xa9,0x12,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x03,0x39,0x02, +0x1c,0x0b,0xe5,0xcc,0xff,0xa9,0x12,0x1d,0xf0,0x36,0x41,0x00,0x1c,0x0b,0x0c, +0x08,0x91,0xce,0x4e,0xa8,0x05,0x39,0x02,0x49,0x12,0xa9,0x22,0x99,0x62,0xa2, +0xa1,0x90,0x82,0x52,0x0a,0x48,0x05,0x65,0x4b,0x04,0x3d,0x0a,0xa5,0x34,0x00, +0xad,0x03,0x0c,0x05,0x39,0x72,0xb8,0x04,0xc8,0x24,0xe5,0xd9,0x00,0x59,0x92, +0x69,0x42,0x0c,0x1b,0xad,0x02,0xb9,0x82,0xbd,0x07,0x65,0xad,0x00,0x1d,0xf0, +0x00,0x00,0x36,0x61,0x00,0x69,0x01,0x0c,0x8a,0x0c,0x4b,0x65,0x48,0x04,0x0c, +0x8b,0x98,0x43,0x49,0x1a,0x39,0x0a,0xa9,0x82,0x99,0x02,0x2c,0x8a,0x65,0x47, +0x04,0x7d,0x0a,0xbd,0x03,0xa5,0x2e,0x00,0x79,0x12,0x2c,0x8a,0x0c,0x8b,0x65, +0x46,0x04,0x7d,0x0a,0xbd,0x03,0xa5,0x2d,0x00,0x79,0x22,0x1c,0x4a,0x0c,0x4b, +0x65,0x45,0x04,0x7d,0x0a,0xb8,0xa4,0xc2,0x24,0x19,0x65,0x2b,0x00,0x79,0x32, +0x2c,0x8a,0x0c,0x8b,0x25,0x44,0x04,0x7d,0x0a,0xbd,0x03,0x65,0x2b,0x00,0x79, +0x42,0x1c,0x4a,0x0c,0x4b,0x25,0x43,0x04,0x7d,0x0a,0xb8,0xa4,0xc2,0x24,0x19, +0x65,0x29,0x00,0x79,0x52,0xa8,0x03,0x3c,0x2b,0xa5,0x79,0x00,0x0c,0x8b,0x82, +0x25,0x13,0x68,0xa4,0x88,0x08,0x68,0x06,0xaa,0x88,0x4c,0x0a,0x80,0x66,0x90, +0xa5,0x40,0x04,0xcd,0x05,0xbd,0x06,0x7d,0x0a,0xd8,0x01,0x65,0xef,0xff,0x79, +0x62,0x3c,0x0a,0x0c,0x4b,0x65,0x3f,0x04,0xbd,0x03,0xc8,0x74,0x3d,0x0a,0x65, +0xeb,0xff,0x39,0x72,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0xca,0x0c, +0x4b,0xe5,0x3d,0x04,0x59,0x2a,0x49,0x1a,0x39,0x0a,0x1c,0x0b,0xa9,0x02,0xa2, +0xa1,0x90,0xe5,0x3c,0x04,0x3d,0x0a,0xe5,0x25,0x00,0xb8,0x02,0xb8,0x2b,0xad, +0x03,0xc8,0x2b,0xb8,0x0b,0x39,0x32,0x25,0xcb,0x00,0x1d,0xf0,0x36,0x41,0x00, +0x0c,0x8a,0x0c,0x4b,0xe5,0x3a,0x04,0x5d,0x0a,0xbd,0x04,0x65,0xd7,0x03,0x59, +0x02,0xe0,0xa4,0x11,0x1c,0x0b,0xe5,0xb8,0xff,0x2d,0x0a,0x0c,0x4b,0x0c,0x8a, +0x25,0x39,0x04,0x29,0x1a,0x49,0x0a,0xa9,0x03,0x1d,0xf0,0x36,0x41,0x00,0x21, +0x5f,0x4e,0x22,0x22,0x18,0x1d,0xf0,0x00,0x36,0x41,0x00,0xa1,0x5c,0x4e,0x1c, +0x0b,0xa2,0x2a,0x1c,0xa9,0x02,0xe0,0xaa,0x11,0xe5,0xb5,0xff,0xa9,0x12,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0xe5,0x35,0x04,0x81,0x72,0x4e, +0x49,0x1a,0x39,0x0a,0xa9,0x02,0x89,0x12,0x1d,0xf0,0x00,0x36,0x61,0x00,0x79, +0x32,0xa2,0xc2,0x10,0x65,0xfc,0xff,0xa2,0xc2,0x18,0x25,0xfc,0xff,0xa2,0xc2, +0x20,0xa5,0xfb,0xff,0xa2,0xc2,0x28,0x0c,0x2b,0xe5,0xcf,0x03,0xa2,0xc2,0x30, +0xb2,0x05,0xc5,0xc2,0x05,0xc4,0x00,0xbb,0x23,0x00,0xcc,0x23,0xe5,0xa0,0xff, +0xa2,0xc2,0x3c,0xb2,0x05,0xc5,0xc2,0x05,0xc4,0x00,0xbb,0x23,0x00,0xcc,0x23, +0xa5,0x9f,0xff,0xa2,0xc2,0x48,0xa5,0xf8,0xff,0xa2,0xc2,0x50,0x25,0xf8,0xff, +0x1c,0x8a,0x0c,0x4b,0x78,0xe4,0xc8,0xf4,0xd8,0xd4,0xd9,0x01,0xc9,0x11,0x48, +0xe3,0xe5,0x2e,0x04,0xfd,0x07,0xbd,0x05,0x3d,0x0a,0xcd,0x06,0xd8,0x01,0xe8, +0x11,0xa5,0x9b,0xff,0x1c,0x0a,0xe8,0x13,0x0c,0x4b,0xe8,0x7e,0xe2,0x62,0x1c, +0x39,0x02,0xe5,0x2c,0x04,0xcd,0x04,0xbd,0x06,0x3d,0x0a,0x65,0x98,0xff,0x39, +0x22,0x81,0x4d,0x4e,0xf1,0x4d,0x4e,0x98,0xc1,0xa1,0x51,0x4e,0xb1,0x4f,0x4e, +0xc1,0x4d,0x4e,0xd1,0x4b,0x4e,0xe1,0x4a,0x4e,0xe2,0x62,0x28,0xd2,0x62,0x29, +0xc2,0x62,0x2a,0xb2,0x62,0x2b,0xa2,0x62,0x2c,0x92,0x62,0x25,0xf2,0x62,0x27, +0x82,0x62,0x26,0xf1,0x4a,0x4e,0x81,0x48,0x4e,0x91,0x46,0x4e,0x92,0x62,0x2d, +0x82,0x62,0x2e,0xf2,0x62,0x2f,0x1d,0xf0,0x00,0x36,0x41,0x00,0x59,0xa2,0x0c, +0xca,0x0c,0x4b,0x25,0x27,0x04,0x5d,0x0a,0x0c,0x1b,0xa5,0xc3,0x03,0x59,0xd2, +0x1c,0x0a,0x0c,0x4b,0x25,0x26,0x04,0x81,0x41,0x4e,0x91,0x3f,0x4e,0xb8,0xd2, +0xb9,0x2a,0x49,0x1a,0x39,0x0a,0x99,0x82,0xa9,0x02,0x89,0x92,0xa1,0x3a,0x4e, +0xa9,0x72,0x1d,0xf0,0x00,0x36,0x41,0x00,0xcb,0xa2,0xb2,0x24,0x17,0xa5,0xc0, +0x03,0xa2,0xc2,0x14,0xa5,0xeb,0xff,0xa2,0xc2,0x1c,0x25,0xeb,0xff,0xa2,0xc2, +0x24,0xb8,0x63,0xe5,0x92,0xff,0x0c,0xca,0x0c,0x4b,0x25,0x22,0x04,0x81,0x34, +0x4e,0x91,0x32,0x4e,0xb1,0x30,0x4e,0x59,0x2a,0x49,0x1a,0x39,0x0a,0xa9,0x12, +0xb9,0xb2,0x99,0xc2,0x89,0xe2,0xa1,0x2c,0x4e,0xa9,0xd2,0x1d,0xf0,0x36,0x41, +0x00,0x8b,0xa2,0xb8,0x24,0xa5,0xbc,0x03,0xa2,0xc2,0x10,0xb8,0x24,0x25,0xbc, +0x03,0xa2,0xc2,0x18,0xb8,0x24,0xa5,0xbb,0x03,0x0c,0xca,0x0c,0x4b,0x25,0x1e, +0x04,0x81,0x29,0x4e,0x91,0x28,0x4e,0xb1,0x25,0x4e,0xc1,0x23,0x4e,0x59,0x2a, +0x49,0x1a,0x39,0x0a,0xa9,0x02,0xc9,0x82,0xb9,0x92,0x99,0xa2,0x89,0xb2,0xa1, +0x20,0x4e,0xa9,0xc2,0x1d,0xf0,0x36,0x41,0x00,0x59,0x42,0x0c,0x8a,0x0c,0x4b, +0x25,0x1b,0x04,0x49,0x1a,0x39,0x0a,0x0c,0x4b,0xa9,0x02,0x0c,0x8a,0x65,0x1a, +0x04,0x3d,0x0a,0x65,0xe2,0xff,0x39,0x32,0x0c,0x08,0x89,0x22,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0x39,0x02,0x51,0x16,0x4e,0x49,0x12,0x59,0x42,0x1d,0xf0, +0x00,0x00,0x36,0x41,0x00,0xc8,0xe3,0xb8,0x33,0x8b,0xa2,0xca,0xbb,0x1b,0xbb, +0xa5,0xc2,0xff,0x39,0x82,0xd1,0x10,0x4e,0xd9,0x92,0x1d,0xf0,0x00,0x00,0x00, +0x36,0x41,0x00,0x31,0x0e,0x4e,0x32,0x62,0x61,0x1d,0xf0,0x00,0x36,0x41,0x00, +0x39,0x02,0x1c,0x4a,0x0c,0x4b,0x25,0x15,0x04,0xf0,0xc3,0x11,0x49,0x0a,0x59, +0x2a,0x7d,0x0a,0xcb,0xb7,0x4b,0xaa,0xe5,0xd8,0xff,0xcd,0x07,0x81,0x06,0x4e, +0xa1,0x04,0x4e,0x91,0x06,0x4e,0x69,0x47,0x79,0x12,0xb8,0x02,0x99,0x42,0xa9, +0x22,0x89,0x32,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0xad,0x02,0xe5,0xd9,0xff,0x0c,0x8a,0x0c,0x4b,0x25,0x11,0x04,0x49,0x1a,0x39, +0x0a,0xa9,0x22,0x1d,0xf0,0x00,0x36,0x41,0x00,0xc8,0x44,0xb8,0x05,0x4b,0xa2, +0xca,0xbb,0x1b,0xbb,0xa5,0xac,0x03,0x0c,0xca,0x0c,0x4b,0x25,0x0f,0x04,0xd1, +0xf6,0x4d,0xe1,0xf4,0x4d,0x59,0x2a,0x49,0x1a,0x39,0x0a,0xa9,0x32,0xe9,0x52, +0xd9,0x62,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0x65,0x0d,0x04, +0x0c,0x8b,0x88,0x43,0x49,0x1a,0x39,0x0a,0xa9,0x32,0x89,0x02,0x2c,0x8a,0x25, +0x0c,0x04,0xbd,0x03,0x5d,0x0a,0xa5,0xf3,0xff,0x59,0x12,0x1c,0x4a,0x0c,0x4b, +0x25,0x0b,0x04,0xb8,0xa4,0xc2,0x24,0x19,0x3d,0x0a,0x65,0xf1,0xff,0x39,0x22, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x1c,0x0a,0x0c,0x4b,0xa5,0x09,0x04, +0x81,0xe1,0x4d,0x91,0xdf,0x4d,0x39,0x3a,0x49,0x2a,0x0c,0x0b,0xb9,0x1a,0xb9, +0x0a,0xa9,0x02,0x59,0x22,0x99,0xb2,0x89,0xc2,0x1d,0xf0,0x36,0x41,0x00,0xc8, +0x05,0xb8,0x04,0xad,0x02,0xc0,0xbb,0xc0,0xe5,0xa3,0x03,0x69,0x42,0x0c,0xca, +0x0c,0x4b,0x65,0x06,0x04,0xd1,0xd7,0x4d,0xe1,0xd5,0x4d,0x59,0x2a,0x49,0x1a, +0x39,0x0a,0xa9,0x22,0xe9,0x52,0xd9,0x62,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x8a, +0x0c,0x4b,0xa5,0x04,0x04,0x39,0x0a,0x49,0x1a,0x1c,0x0b,0xa9,0x02,0xa2,0xa1, +0x90,0xa5,0x03,0x04,0x3d,0x0a,0xe5,0xec,0xff,0xad,0x03,0x39,0x12,0xb8,0x04, +0xc8,0x24,0x25,0x92,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x59,0x12,0x0c, +0x8a,0x0c,0x4b,0xa5,0x01,0x04,0x49,0x1a,0x39,0x0a,0x1c,0x0b,0xa9,0x02,0xa2, +0xa1,0x90,0xe5,0x00,0x04,0x4d,0x0a,0xe5,0xe9,0xff,0xad,0x02,0x0c,0x1b,0x88, +0x03,0x49,0x32,0x89,0x22,0x65,0x81,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0x0c,0x8a,0x1c,0x0b,0x68,0x33,0x98,0x43,0x68,0x76,0x88,0x69,0x38,0x89,0x88, +0x38,0x89,0x62,0xe5,0xfd,0x03,0x1c,0x0b,0x1c,0xc8,0x4d,0x0a,0x89,0x0a,0x3c, +0x8a,0x65,0x7c,0xff,0xb8,0x16,0xd8,0x06,0xc8,0x0b,0xa9,0x14,0x49,0x02,0xe8, +0x0d,0xd9,0x72,0x98,0x63,0xe9,0x82,0xa8,0x09,0xc9,0xb2,0x99,0x92,0xa9,0xa2, +0xb9,0xc2,0x5c,0x4a,0x1c,0x0b,0xe5,0xfa,0x03,0x4d,0x0a,0xb8,0xb2,0xa5,0x60, +0xff,0x5c,0x4a,0xf8,0x83,0x1c,0x0b,0x88,0x0f,0xf9,0xe2,0x49,0x12,0x89,0xd2, +0x65,0xf9,0x03,0x3d,0x0a,0xb8,0xd2,0x25,0x5f,0xff,0x39,0x22,0x52,0x62,0x10, +0x4c,0x09,0x50,0x99,0xc0,0x92,0x62,0x11,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0x21,0x5c,0x4d,0x0c,0x09,0x82,0x22,0x1a,0x92,0x62,0x17,0xe0,0x08,0x00,0xa2, +0x62,0x18,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x31,0x56,0x4d,0x0c,0x12,0x22, +0x63,0x17,0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x29,0x01,0x8c,0x33,0x2d, +0x03,0x06,0x01,0x00,0x25,0xfd,0x03,0x2d,0x0a,0x78,0x01,0x0c,0x04,0x0c,0x05, +0x61,0x4d,0x4d,0x65,0xfd,0xff,0x1c,0xca,0xb2,0x26,0x10,0x65,0xf6,0x03,0xa9, +0x11,0xbd,0x04,0x65,0xfd,0x09,0x98,0x11,0x92,0x66,0x10,0x65,0xfa,0xff,0xa2, +0x26,0x10,0xbd,0x02,0x25,0x5e,0x02,0x25,0xfd,0x03,0xb2,0x26,0x10,0x1b,0x44, +0xb8,0x5b,0x4b,0x77,0xb0,0xaa,0xc0,0x50,0x5a,0x53,0xa9,0x17,0x66,0x24,0xc6, +0xcc,0x33,0xad,0x02,0x25,0xf2,0x03,0xd8,0x01,0x0c,0x2c,0x59,0x1d,0xc9,0x0d, +0x1d,0xf0,0x00,0x00,0x00,0x00,0x36,0x41,0x00,0x1c,0xf5,0x6f,0xe6,0x00,0x22, +0x44,0x0c,0x0c,0x11,0x0c,0x18,0x61,0x76,0x4d,0x80,0x00,0xf3,0x60,0x62,0xa0, +0x62,0x26,0x7f,0xef,0xec,0x00,0x22,0x42,0x09,0x04,0x00,0xaf,0xe0,0x0a,0x22, +0xa4,0x00,0x80,0x00,0xaf,0xe0,0x0a,0x22,0x40,0x00,0x01,0x01,0x4f,0x00,0x04, +0x28,0x44,0x0c,0x0c,0x11,0x80,0x04,0x0d,0x1d,0xf0,0x36,0x41,0x00,0x30,0x52, +0x21,0x7c,0xf6,0x0c,0x19,0x1c,0xfa,0x82,0xa0,0x20,0x40,0x88,0xc0,0x40,0xaa, +0xc0,0x00,0x1a,0x40,0x42,0xa0,0x00,0x00,0x99,0xa1,0x6f,0xf3,0x00,0x22,0x44, +0x0c,0x0c,0x11,0x00,0x18,0x40,0xcf,0x4c,0x01,0x22,0x02,0x29,0x04,0x00,0x4f, +0x01,0x04,0x29,0x44,0x0c,0x0c,0x11,0xef,0xec,0x00,0x22,0x44,0x0c,0x0c,0x11, +0xcf,0x00,0x84,0x28,0x44,0x0c,0x0c,0x11,0x76,0xa5,0x35,0x20,0x08,0x0c,0xaf, +0xe0,0x0a,0x22,0xf4,0x00,0x06,0x09,0xaf,0xe0,0x0a,0x22,0x02,0x01,0x04,0x11, +0xaf,0xe0,0x0a,0x22,0x02,0x01,0x05,0x11,0xaf,0xe0,0x0a,0x22,0x02,0x01,0x06, +0x11,0xaf,0xe0,0x0a,0x22,0x02,0x01,0x07,0x11,0x1f,0x02,0x03,0x60,0x44,0x0c, +0x0c,0x11,0x30,0x02,0x8d,0x1d,0xf0,0x36,0x41,0x00,0x3d,0xf0,0x76,0x94,0x04, +0x32,0x42,0x00,0x1b,0x22,0x1d,0xf0,0x00,0x36,0x41,0x00,0x61,0x03,0x4d,0x48, +0xd6,0x38,0xc6,0x1b,0x84,0x4a,0x33,0x32,0x03,0x00,0x39,0x02,0x0c,0x72,0x8c, +0x03,0x89,0xd6,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x03,0x0c,0x14,0x71,0xfb, +0x4c,0x51,0x3c,0x4d,0x59,0xc7,0x52,0x05,0x00,0x59,0x02,0x0c,0x72,0x50,0x43, +0x83,0x49,0xd7,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xb8,0x02,0x00,0xab, +0x23,0xb0,0xb8,0x74,0x65,0x37,0x05,0x0c,0x7c,0x0c,0x82,0xa0,0x2c,0x83,0x1d, +0xf0,0x00,0x36,0x41,0x00,0xbd,0x02,0xa8,0x02,0xe5,0x40,0x05,0x0c,0x88,0x0c, +0x72,0xa0,0x28,0xa3,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x13,0x51,0xe8,0x4c, +0x4d,0x02,0x58,0x35,0x58,0x35,0x0c,0x02,0x50,0x23,0x83,0x29,0x04,0x0c,0x72, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x51,0xe2,0x4c,0x0c,0x02,0x52,0x25, +0x10,0x38,0x35,0x58,0x45,0x48,0x45,0x58,0x55,0x38,0x33,0x29,0x95,0x29,0x94, +0x29,0x93,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xa8,0x02,0xa5,0x5b,0x04, +0x81,0xd9,0x4c,0x0c,0x1a,0x88,0x08,0x1c,0x9b,0x88,0xf8,0x7c,0xfc,0xe0,0x08, +0x00,0x0c,0x72,0x1d,0xf0,0x36,0x41,0x00,0xb8,0x02,0x00,0xab,0x23,0xb0,0xb8, +0x74,0xa5,0x2b,0x05,0x0c,0x7c,0x0c,0x82,0xa0,0x2c,0x83,0x1d,0xf0,0x00,0x36, +0x41,0x00,0xbd,0x02,0xa8,0x02,0xe5,0x36,0x05,0x0c,0x88,0x0c,0x72,0xa0,0x28, +0xa3,0x1d,0xf0,0x00,0x36,0x61,0x00,0x51,0xc8,0x4c,0x52,0x25,0x10,0x48,0x02, +0x9c,0x65,0x58,0x45,0x52,0x25,0x14,0x8c,0xf5,0x9c,0x24,0x26,0x14,0x69,0x26, +0x24,0x6c,0x26,0x34,0x71,0x26,0x44,0x74,0x26,0x54,0x79,0x7c,0xf4,0x86,0x11, +0x00,0x41,0xc7,0x4c,0x58,0x25,0xef,0xea,0x00,0x22,0x44,0x0c,0x0c,0x11,0xef, +0xe8,0x02,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x10,0x89,0x00, +0x0c,0xf9,0x4f,0x01,0xa8,0x48,0x44,0x0c,0x0c,0x11,0x6f,0xf4,0x00,0x22,0x44, +0x0c,0x0c,0x11,0x0f,0x80,0xa0,0x42,0x42,0x02,0x44,0x10,0x0f,0x01,0x28,0x48, +0x44,0x0c,0x0c,0x11,0x80,0x80,0x31,0x80,0x88,0x23,0x89,0x01,0x66,0x04,0x04, +0x0c,0x84,0x46,0x01,0x00,0x0c,0x74,0xb8,0x01,0xb9,0x02,0x2d,0x04,0x1d,0xf0, +0x41,0xeb,0x4c,0xc6,0xe8,0xff,0x41,0xaf,0x4c,0x58,0x35,0x46,0xe7,0xff,0x41, +0xe7,0x4c,0x06,0xfd,0xff,0x41,0xac,0x4c,0x58,0x45,0xc6,0xe3,0xff,0x41,0xe4, +0x4c,0x06,0xfd,0xff,0x00,0x00,0x00,0x36,0x81,0x00,0x1c,0xf4,0xa2,0xc1,0x14, +0x29,0x41,0x39,0x51,0x92,0xc1,0x10,0xb1,0xdf,0x4c,0xb9,0x01,0x90,0x40,0x0c, +0xa0,0x10,0x0c,0xaf,0xe0,0x0a,0x22,0x02,0x19,0x04,0x00,0xaf,0xe0,0x0a,0x22, +0x02,0x09,0x05,0x00,0x0f,0x02,0x01,0x82,0x40,0x00,0x00,0x14,0x2f,0x01,0x01, +0xa2,0xa4,0x10,0x0c,0x00,0xaf,0xe0,0x0a,0x22,0xa4,0x10,0x0c,0x11,0x0f,0x62, +0x08,0x82,0x02,0x11,0x05,0x11,0x00,0x53,0x0d,0x88,0x11,0x4f,0x00,0xb5,0x43, +0xc0,0x80,0x05,0x00,0x00,0x82,0xd3,0x2d,0x08,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0x8b,0xa2,0x25,0x8a,0xff,0xa2,0xc2,0x10,0xe5,0x89,0xff,0xa2,0xc2,0x18, +0x65,0x89,0xff,0xa2,0xc2,0x20,0xc2,0x04,0xc7,0xb2,0x04,0xc6,0x00,0xcc,0x23, +0x00,0xbb,0x23,0xc0,0xbb,0xd1,0xe5,0x5c,0x03,0xa2,0xc2,0x28,0xa5,0x87,0xff, +0xb2,0x04,0xc4,0xa2,0xc2,0x30,0x00,0xbb,0x23,0x2b,0xbb,0xa5,0x5b,0x03,0xa2, +0xc2,0x38,0xb8,0xc2,0x25,0x5b,0x03,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02, +0xb8,0x12,0xe5,0x3d,0x02,0xbd,0x03,0x82,0x22,0x26,0xad,0x02,0xe0,0x08,0x00, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0x88,0xb2,0xb8,0x12,0xe0,0x08, +0x00,0x98,0x12,0x98,0x19,0x92,0x29,0x31,0x99,0xf2,0x1d,0xf0,0x00,0x36,0x41, +0x00,0xd8,0x42,0x88,0x32,0xb8,0x2d,0x80,0x8b,0xa0,0x88,0x08,0x8c,0x88,0xad, +0x02,0x82,0x22,0x1b,0xc8,0x3d,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0x0c, +0x57,0x51,0xa5,0x4c,0x0c,0x76,0xef,0xea,0x00,0x22,0x44,0x0c,0x0c,0x11,0xf0, +0x20,0x00,0x76,0xa4,0x27,0x0f,0x60,0x40,0xc2,0x44,0x0c,0x0c,0x11,0x4f,0xee, +0x00,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x00,0x84,0x00,0xaf, +0xe0,0x0a,0x22,0x82,0x01,0x41,0x10,0x4f,0x05,0x42,0x48,0x44,0x0c,0x0c,0x11, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x51,0x95,0x4c,0x62,0xa0,0x05,0xef,0xea, +0x00,0x22,0x44,0x0c,0x0c,0x11,0x76,0xa4,0x1a,0x0f,0x60,0x40,0xc2,0x44,0x0c, +0x0c,0x11,0x4f,0xec,0x00,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4, +0x00,0x84,0x00,0x10,0x12,0x8d,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c, +0x06,0x76,0xa4,0x12,0x0f,0x60,0x40,0xc2,0x44,0x0c,0x0c,0x11,0x4f,0xec,0x00, +0x22,0x44,0x0c,0x0c,0x11,0x10,0x02,0x8d,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41, +0x00,0x28,0x14,0x50,0x62,0x21,0x72,0x93,0x00,0x81,0x7f,0x4c,0x4b,0x33,0x6f, +0xf1,0x00,0x22,0x44,0x0c,0x0c,0x11,0x4f,0x01,0x04,0x29,0x44,0x0c,0x0c,0x11, +0xf0,0x20,0x00,0x3d,0xf0,0x76,0xa6,0x3a,0x6f,0x62,0x40,0xa2,0x44,0x0c,0x0c, +0x11,0x4f,0xee,0x02,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xd0,0x10, +0x07,0x09,0xaf,0xe0,0x0a,0x22,0x40,0x00,0x09,0x01,0xaf,0xe0,0x0a,0x22,0x40, +0x00,0x0d,0x11,0xaf,0xe0,0x0a,0x22,0x40,0x00,0x09,0x29,0xaf,0xe0,0x0a,0x22, +0x40,0x00,0x0d,0x39,0x30,0x02,0x8d,0x0c,0x79,0xa8,0x04,0x0c,0x02,0xa2,0xca, +0xc0,0xa0,0x29,0x93,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x5d,0x0c, +0x58,0xa2,0x93,0x00,0xa2,0x54,0x00,0x92,0x93,0x01,0xa2,0xa0,0x00,0x92,0x54, +0x01,0x30,0x93,0x20,0x76,0xa8,0x0d,0xb2,0x99,0x02,0xc8,0x24,0x2b,0x99,0xaa, +0xcc,0xb2,0x5c,0x00,0x2b,0xaa,0x9d,0x03,0x0c,0x0a,0x76,0xad,0x0d,0xe2,0x99, +0x07,0xf8,0x44,0x2b,0x99,0xaa,0xff,0xe2,0x5f,0x00,0x2b,0xaa,0xa8,0x64,0xb2, +0xc3,0x18,0x0c,0x5c,0x65,0xf2,0xff,0xa8,0x84,0xb2,0xc3,0x22,0x0c,0x5c,0xa5, +0xf1,0xff,0xa8,0xa4,0xb2,0xc3,0x2c,0x0c,0x5c,0xe5,0xed,0xff,0xa8,0xc4,0xb2, +0xc3,0x36,0x0c,0x5c,0x25,0xed,0xff,0xa8,0xe4,0xb2,0xc3,0x40,0x0c,0x5c,0xa5, +0xec,0xff,0xa2,0x24,0x10,0xb2,0xc3,0x4a,0x0c,0x5c,0xe5,0xeb,0xff,0xa2,0x24, +0x12,0x1c,0xec,0xb2,0xa0,0x86,0xba,0xb3,0xe5,0xe6,0xff,0xa2,0x24,0x14,0x1c, +0xec,0xb2,0xa0,0xc2,0xba,0xb3,0x25,0xe6,0xff,0x0c,0x7c,0x0c,0x02,0x20,0x2c, +0x93,0x1d,0xf0,0x00,0x36,0x41,0x00,0x82,0x22,0x15,0xad,0x02,0xe0,0x08,0x00, +0xa2,0x22,0x11,0x98,0x2a,0xa8,0x1a,0xd8,0x19,0xd9,0x0a,0xc8,0x29,0xc9,0x3a, +0xb8,0x39,0xb9,0x5a,0x98,0x49,0x99,0x2a,0x1d,0xf0,0x36,0x41,0x00,0xa1,0x34, +0x4c,0x1c,0xf6,0xef,0xe6,0x08,0x22,0x44,0x0c,0x0c,0x11,0xef,0x05,0x99,0x02, +0x82,0x59,0x04,0x00,0x6f,0xf5,0x08,0x22,0x44,0x0c,0x0c,0x11,0xef,0x25,0x09, +0x62,0xa4,0x30,0x28,0x03,0x6f,0xf0,0x08,0x22,0x44,0x0c,0x0c,0x11,0x0f,0x32, +0xb9,0x82,0x60,0x30,0x18,0x01,0x90,0x40,0x0c,0xaf,0xe0,0x0a,0x22,0xa4,0x30, +0x18,0x02,0x6f,0xa4,0x98,0x02,0x82,0x19,0x04,0x00,0xaf,0xe0,0x0a,0x22,0xa8, +0x10,0x88,0x01,0x6f,0xeb,0x00,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22, +0xa4,0x10,0x08,0x01,0xaf,0xe0,0x0a,0x22,0x40,0x00,0x09,0x01,0x42,0xc2,0x20, +0x00,0x04,0x0d,0x1d,0xf0,0x00,0x36,0x61,0x00,0xad,0x03,0x25,0xac,0x04,0x88, +0x22,0x91,0x16,0x4c,0x6f,0xf4,0x00,0x22,0x44,0x0c,0x0c,0x11,0x6f,0xf2,0x02, +0x22,0x44,0x0c,0x0c,0x11,0xef,0x61,0x99,0x02,0xa4,0x00,0x01,0x00,0x82,0x28, +0x1a,0x2f,0x01,0x28,0x48,0x44,0x0c,0x0c,0x11,0x40,0xa9,0x93,0xe0,0x08,0x00, +0x2f,0x02,0xb8,0x43,0x44,0x0c,0x0c,0x11,0xa9,0x62,0xef,0xf4,0x02,0x22,0x44, +0x0c,0x0c,0x11,0x4f,0xab,0x92,0x43,0x48,0x10,0x0c,0x11,0xcf,0x02,0x42,0x43, +0x44,0x0c,0x0c,0x11,0xe5,0xa6,0x04,0x88,0x22,0x82,0x28,0x1a,0xb1,0xff,0x4b, +0xe0,0x08,0x00,0x4f,0x02,0xb8,0x43,0x44,0x0c,0x0c,0x11,0xc8,0x02,0x6f,0xf5, +0x00,0x22,0x44,0x0c,0x0c,0x11,0x2f,0x20,0xa1,0x42,0xa4,0x20,0x11,0x01,0xc8, +0x2c,0x4f,0x01,0x28,0x49,0x44,0x0c,0x0c,0x11,0xa9,0x82,0xcc,0x33,0x0c,0x0b, +0x50,0x9b,0x83,0x99,0xa2,0xc8,0xbc,0xc9,0x92,0x1d,0xf0,0x00,0x36,0x41,0x00, +0xbd,0x03,0xa2,0xc2,0x24,0x25,0xa4,0x04,0xbd,0x04,0xa2,0xc2,0x3c,0xa5,0xa3, +0x04,0xbd,0x05,0xa2,0xc2,0x30,0x25,0xa3,0x04,0xbd,0x06,0xa2,0xc2,0x50,0xa5, +0xa2,0x04,0xbd,0x07,0xa2,0xc2,0x58,0x25,0xa2,0x04,0xb8,0x81,0xa2,0xa0,0x94, +0xaa,0xa2,0xa5,0xa1,0x04,0xb8,0x91,0xa2,0xa0,0x84,0xaa,0xa2,0xe5,0xa0,0x04, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x1c,0xf8,0x4b,0xa1,0x39,0x01,0x9d, +0x01,0xb1,0xdc,0x4b,0xb9,0x11,0x90,0x00,0x0c,0xa0,0x40,0x0c,0xaf,0xe0,0x0a, +0x22,0x02,0x0a,0x04,0x00,0xaf,0xe0,0x0a,0x22,0xa4,0x00,0x80,0x00,0xaf,0xe0, +0x0a,0x22,0x40,0x00,0x01,0x01,0x8f,0x00,0x28,0x48,0x44,0x0c,0x0c,0x11,0x49, +0x22,0x1d,0xf0,0x00,0x00,0x36,0x61,0x00,0xa2,0xc2,0x2c,0xb2,0xc2,0x30,0xb0, +0x40,0x0c,0xa0,0x00,0x0c,0xaf,0xe0,0x0a,0x22,0x30,0x0c,0x84,0x00,0x9d,0x01, +0x00,0x19,0x0d,0x88,0xa2,0xb1,0xcb,0x4b,0x82,0x28,0x1a,0xa8,0x01,0xe0,0x08, +0x00,0xc8,0xd2,0xc8,0x1c,0xa9,0x0c,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00, +0xad,0x02,0xbd,0x03,0x39,0x02,0xc8,0x12,0x88,0x32,0x49,0x0c,0x59,0x2c,0x69, +0x4c,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0xe8,0x02,0xd8,0x12,0xe8,0x1e, +0xd8,0x2d,0xe0,0xdd,0xa0,0xd8,0x0d,0x9c,0x0d,0xb2,0x9d,0x00,0xc8,0x2d,0xa8, +0x32,0x25,0x0c,0x00,0xf8,0x02,0xf8,0x0f,0xf8,0x0f,0xf9,0x22,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0x31,0x6c,0x4b,0x32,0x23,0x10,0x38,0x43,0xa8,0x73,0xa8, +0x6a,0xe5,0xb1,0x01,0xa8,0x73,0xa8,0x7a,0x25,0xd7,0x01,0x38,0x83,0x38,0x33, +0xb8,0x33,0xb8,0x2b,0xe6,0x4b,0x23,0x88,0x63,0xad,0x08,0xb8,0x58,0x82,0x28, +0x16,0xb8,0x2b,0xe0,0x08,0x00,0x88,0x73,0xbd,0x02,0xad,0x08,0xe8,0x38,0x88, +0x98,0xc8,0x2e,0xd8,0x0e,0xe2,0x2e,0x16,0xd8,0x3d,0xe0,0x08,0x00,0x1d,0xf0, +0x00,0x00,0x36,0x41,0x00,0xa8,0x02,0x98,0x22,0xa8,0x2a,0x98,0x29,0xb8,0x2a, +0xb0,0x99,0x90,0x92,0x99,0x00,0xd8,0x4a,0x66,0x09,0x15,0x0c,0x0d,0xd9,0x52, +0x0c,0x0b,0xc8,0x72,0x81,0x9c,0x4b,0xa8,0x1c,0x88,0x98,0xc8,0x0c,0xe0,0x08, +0x00,0x1d,0xf0,0xd0,0xd9,0x90,0x46,0xf9,0xff,0x36,0x41,0x00,0x38,0x02,0x0c, +0x06,0x38,0x13,0x0c,0x05,0x38,0x23,0x0c,0x07,0xa6,0x13,0x1e,0x1b,0x55,0xa8, +0x32,0x48,0x02,0x88,0x72,0x98,0x52,0x8a,0x86,0x9a,0x96,0x48,0x14,0xaa,0xa6, +0x79,0x0a,0x79,0x09,0x79,0x08,0x48,0x24,0x4b,0x66,0x47,0x25,0xe0,0x1d,0xf0, +0x00,0x36,0x41,0x00,0xe6,0x53,0x77,0x32,0x62,0x60,0xa0,0xb3,0x11,0x61,0x87, +0x4b,0x52,0xa0,0x80,0x68,0xa6,0x5a,0xa2,0xe0,0x06,0x00,0xa6,0x13,0x59,0x0c, +0x0c,0xa2,0xa0,0x02,0xb2,0xa0,0x01,0x82,0xa0,0x03,0x1b,0xcc,0x0f,0x80,0x40, +0xc2,0x44,0x0c,0x0c,0x11,0x20,0x9a,0xa0,0xa2,0xca,0x04,0x2f,0xb3,0x68,0x43, +0xe2,0x02,0x14,0x10,0x00,0x09,0x4d,0x92,0xc9,0x10,0x76,0xa8,0x28,0x0f,0x80, +0x40,0xc2,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xe2,0x02,0x14,0x10,0x00, +0x09,0x0d,0x0f,0x80,0x40,0xc2,0x44,0x0c,0x0c,0x11,0x0f,0x54,0x09,0x82,0xe2, +0x02,0x14,0x10,0x00,0x09,0x4d,0x92,0xc9,0x10,0x0c,0x38,0xc7,0x93,0xb0,0xad, +0x02,0xb0,0xb3,0x11,0xe0,0x06,0x00,0x1d,0xf0,0x36,0x41,0x00,0x49,0x62,0x39, +0x82,0xa2,0xa0,0xb4,0x0c,0x4b,0x0c,0x08,0x89,0x72,0x65,0x67,0x03,0xb8,0x23, +0x3d,0x0a,0xa2,0xa0,0xac,0xaa,0xa3,0xa5,0x03,0x03,0x39,0x52,0xb1,0x66,0x4b, +0xc1,0x65,0x4b,0xd1,0x63,0x4b,0xe1,0x61,0x4b,0xf1,0x5f,0x4b,0xf9,0x02,0xe9, +0x12,0xd9,0x22,0xc9,0x32,0xb9,0x42,0x65,0x2c,0xff,0x20,0x8a,0xc0,0x89,0x92, +0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0x4c,0xca,0x25,0x67,0x03,0x3d,0x0a,0xb8, +0x92,0xa5,0x3c,0x02,0x39,0xa2,0xe5,0x6b,0x03,0x3d,0x0a,0xa8,0x02,0xbd,0x03, +0xa5,0xaa,0xfe,0xa8,0x12,0xbd,0x03,0x25,0xa9,0xfe,0xa8,0x22,0xbd,0x03,0x25, +0xa7,0xfe,0xa8,0x32,0xbd,0x03,0xa5,0xa6,0xfe,0xa8,0x42,0xbd,0x03,0xe5,0xa4, +0xfe,0xa8,0x52,0xbd,0x03,0x25,0xa1,0xfe,0xad,0x03,0x88,0xa2,0x98,0x42,0x88, +0x58,0x98,0x09,0x88,0x18,0x89,0x39,0x65,0x61,0x03,0x1d,0xf0,0x00,0x00,0x00, +0x36,0xa1,0x00,0x49,0xb2,0x0c,0xca,0x0c,0x4b,0x91,0x46,0x4b,0xe0,0x83,0x11, +0x62,0xc9,0xe0,0x72,0xc9,0xd8,0x70,0x73,0xa0,0x60,0x63,0xa0,0x9a,0x88,0x82, +0x28,0x7f,0x62,0x26,0x7f,0x72,0x27,0x7f,0x68,0x06,0x78,0x07,0x38,0x08,0xe5, +0x5b,0x03,0x79,0x2a,0x69,0x1a,0x39,0x0a,0x0c,0x4b,0xa9,0x92,0x1c,0x4a,0x25, +0x5b,0x03,0xa9,0x41,0xbd,0x03,0xc8,0x47,0xdd,0x05,0xc8,0x0c,0x65,0x3e,0xff, +0x3c,0x4a,0x0c,0x4b,0xd8,0x41,0xd9,0x02,0xa5,0x59,0x03,0xa9,0x51,0xbd,0x03, +0xd8,0x87,0xc2,0x26,0x15,0xd8,0x0d,0xa5,0x38,0xff,0x4c,0x0a,0x0c,0x4b,0xe8, +0x51,0xe9,0x12,0xe5,0x57,0x03,0xa9,0x61,0xbd,0x03,0x0c,0x0d,0xc8,0xc6,0x0c, +0x3e,0xc8,0x3c,0xe5,0x32,0xff,0x4c,0x0a,0x0c,0x4b,0xd8,0x61,0xd9,0x22,0x65, +0x56,0x03,0xa9,0x71,0xbd,0x03,0x0c,0x0d,0xc8,0xc6,0x0c,0x4e,0xc8,0x4c,0x25, +0x31,0xff,0x3c,0x8a,0x0c,0x4b,0xd8,0x71,0xd9,0x32,0xa5,0x54,0x03,0xa9,0x81, +0xbd,0x03,0xc2,0x26,0x1d,0xdd,0x05,0x25,0x2c,0xff,0xa2,0xa0,0xc0,0x0c,0x4b, +0xe8,0x81,0xe9,0x42,0x25,0x53,0x03,0xfd,0x05,0xcd,0x07,0xbd,0x06,0xed,0x03, +0xd2,0x26,0x16,0x49,0x01,0x3d,0x0a,0x65,0x1d,0xff,0x39,0x52,0x0c,0x8a,0x0c, +0x4b,0xa5,0x51,0x03,0xb8,0x92,0x3d,0x0a,0xc8,0x1b,0xb8,0x0b,0xc2,0x2c,0x10, +0x65,0x1a,0xff,0x39,0x72,0x0c,0x8a,0x0c,0x4b,0x25,0x50,0x03,0x3d,0x0a,0x25, +0x18,0xff,0x39,0xc2,0xe5,0x16,0xff,0x20,0xca,0xc0,0xc9,0xd2,0x1d,0xf0,0x00, +0x00,0x36,0x61,0x00,0xcd,0x05,0xbd,0x03,0x52,0x22,0x1a,0xa2,0xa0,0x6c,0x58, +0x05,0xc9,0x01,0x58,0x75,0xe5,0x50,0x03,0x3d,0x0a,0xb2,0x22,0x1a,0xe5,0xe3, +0x01,0x88,0x54,0x32,0x62,0x1c,0xf2,0x22,0x20,0xc2,0x22,0x1f,0xd8,0x43,0xd9, +0x0c,0x92,0x23,0x10,0x99,0x1c,0xa8,0x28,0xa9,0x3c,0xb8,0x83,0xb9,0x2c,0xd8, +0x43,0xc2,0x22,0x1e,0xb9,0x2f,0x99,0x1f,0xa9,0x3f,0xd9,0x0f,0xe2,0x23,0x11, +0xe9,0x2c,0xb2,0x23,0x12,0xe2,0x22,0x21,0xd9,0x4c,0xb9,0x3c,0xc2,0x23,0x16, +0xc9,0x4e,0x92,0x23,0x14,0x99,0x5e,0xf8,0x38,0xf9,0x6e,0xf8,0x44,0xd2,0x23, +0x19,0x92,0x2f,0x10,0xd9,0x7e,0xf8,0xbf,0xd2,0xc9,0x20,0xb8,0x09,0xb9,0xbe, +0xf9,0x9e,0xb2,0xc9,0x28,0xf2,0x23,0x15,0xf9,0xae,0xd9,0x2e,0x92,0xc9,0x30, +0x99,0x3e,0xb9,0x1e,0x92,0x22,0x23,0xd2,0x23,0x17,0xd9,0x8e,0xc9,0x39,0xb8, +0xe3,0xb9,0x49,0xa9,0x59,0x89,0x19,0xa5,0x4d,0x03,0x7d,0x0a,0x2c,0xca,0xbd, +0x07,0xa5,0x47,0x03,0xbd,0x05,0x3d,0x0a,0x25,0xd8,0x01,0xb2,0x22,0x1c,0x39, +0x7b,0x8b,0xab,0xcb,0xbb,0x25,0xd6,0x01,0xb2,0x22,0x1c,0xa2,0xcb,0x4c,0xb2, +0xcb,0x3c,0x65,0xd5,0x01,0xc2,0x22,0x1c,0xc8,0x7c,0xd2,0x22,0x23,0xc2,0xcc, +0x1c,0xc9,0x6d,0x25,0x4a,0x03,0x3d,0x0a,0xa8,0x02,0xbd,0x03,0x25,0x77,0xfe, +0xa8,0x12,0xbd,0x03,0xa5,0x76,0xfe,0xa8,0x32,0xbd,0x03,0xc2,0x22,0x21,0xe5, +0x3b,0x00,0xa8,0x72,0xbd,0x03,0xc2,0x22,0x22,0x65,0x74,0xfe,0xa8,0x82,0xbd, +0x03,0xe5,0x85,0xfe,0xa8,0x62,0xbd,0x03,0xa5,0x86,0xfe,0xa2,0x22,0x16,0xbd, +0x03,0xa5,0x71,0xfe,0xbd,0x03,0xe8,0x52,0xa8,0xa2,0xf8,0x42,0xd2,0x22,0x1e, +0xd9,0x1f,0xd9,0x1e,0x25,0x82,0xfe,0xa8,0xb2,0xbd,0x03,0xe5,0x81,0xfe,0xa8, +0xc2,0xbd,0x03,0x65,0x81,0xfe,0xa8,0xd2,0xbd,0x03,0xe5,0x80,0xfe,0xa8,0xe2, +0xbd,0x03,0x58,0x01,0x65,0x80,0xfe,0xcd,0x05,0xbd,0x03,0x82,0x22,0x1c,0xa8, +0x44,0x82,0x28,0x1a,0xa2,0x2a,0x12,0x92,0xc8,0x10,0xa8,0x6a,0xa9,0x16,0x8b, +0x88,0xa9,0x05,0xa2,0x22,0x18,0x99,0x15,0x89,0x06,0xe5,0x6a,0xfe,0xcd,0x06, +0xa2,0x22,0x19,0xbd,0x03,0x25,0x69,0xfe,0xa2,0x22,0x1d,0xbd,0x03,0xe5,0x66, +0xfe,0xad,0x03,0x65,0x39,0x03,0xa2,0x22,0x12,0xbd,0x07,0x65,0x77,0xfe,0xad, +0x07,0xa5,0x38,0x03,0x1d,0xf0,0x00,0x36,0x61,0x01,0x62,0x62,0x1b,0x0c,0xca, +0x0c,0x4b,0x65,0x35,0x03,0x88,0x15,0x0c,0x09,0xb2,0xc2,0x50,0xc2,0xc2,0x10, +0xd2,0xc2,0x4c,0xe2,0xc2,0x14,0xe2,0x61,0x1e,0xd2,0x61,0x1f,0xc2,0x61,0x19, +0xb2,0x61,0x1a,0x92,0x61,0x20,0x39,0x0a,0x49,0x1a,0x59,0x2a,0x82,0x98,0x00, +0x89,0x41,0xa2,0x62,0x1a,0x2c,0x4a,0x0c,0x4b,0x25,0x32,0x03,0xa2,0x61,0x1c, +0xbd,0x03,0xc2,0x24,0x12,0xd2,0x25,0x10,0xed,0x06,0xfd,0x07,0xe5,0xd5,0xfe, +0x0c,0xca,0x0c,0x4b,0x82,0x21,0x1e,0xf2,0x21,0x1c,0xf9,0x08,0x25,0x30,0x03, +0xa2,0x61,0x1d,0xbd,0x03,0xc2,0x24,0x19,0x65,0x1d,0xff,0x92,0x21,0x20,0xc2, +0x21,0x1a,0xb2,0x21,0x1f,0xd2,0x21,0x1d,0xa2,0x21,0x19,0xa2,0x61,0x1e,0xd9, +0x0b,0xc2,0x61,0x1f,0x1b,0x99,0x92,0x61,0x20,0x66,0x29,0xad,0xa2,0xa0,0x64, +0x0c,0x4b,0xe5,0x2c,0x03,0xa9,0x51,0xbd,0x03,0xd2,0x25,0x15,0xc8,0xf4,0x0c, +0x0e,0xfd,0x07,0xe9,0x01,0xed,0x06,0x65,0xc4,0xfe,0xa2,0xa0,0x64,0x0c,0x4b, +0xf8,0x51,0xf9,0x02,0xe5,0x2a,0x03,0xa9,0x61,0xbd,0x03,0xed,0x06,0xfd,0x07, +0xd2,0x25,0x15,0xc8,0xf4,0x0c,0x18,0x89,0x01,0x65,0xc2,0xfe,0x0c,0x8a,0x0c, +0x4b,0x98,0x61,0x99,0x12,0xe5,0x28,0x03,0xa9,0x71,0xbd,0x03,0xc2,0x24,0x10, +0x25,0xf2,0xfe,0xa8,0x71,0x1c,0x0b,0xa9,0x22,0x4c,0x0a,0xa5,0x27,0x03,0xa9, +0x81,0xbd,0x03,0xcd,0x04,0xdd,0x05,0xed,0x06,0xfd,0x07,0xa5,0x2c,0x00,0xb8, +0x81,0x1c,0x4a,0xb9,0x32,0x0c,0x4b,0x25,0x26,0x03,0xa9,0x91,0xc8,0x35,0xd8, +0x41,0xbd,0x03,0xc0,0xcd,0xa0,0xe0,0xdd,0x11,0xc8,0x0c,0xd2,0x61,0x1b,0xdd, +0x07,0xe5,0x08,0xff,0x4c,0x0a,0x0c,0x4b,0xd8,0x91,0xd9,0x62,0xe5,0x23,0x03, +0xa9,0xa1,0xbd,0x03,0x0c,0x0d,0xc8,0xc4,0x0c,0x0e,0xc8,0x0c,0xa5,0xfe,0xfe, +0x4c,0x0a,0x0c,0x4b,0xd8,0xa1,0xd9,0xa2,0x25,0x22,0x03,0xa9,0xb1,0xbd,0x03, +0xe2,0x25,0x17,0xc8,0xc4,0xd2,0x21,0x1b,0xc8,0x1c,0xea,0xdd,0xd8,0x0d,0x0c, +0x1e,0xa5,0xfc,0xfe,0x4c,0x0a,0x0c,0x4b,0xf8,0xb1,0xf9,0xb2,0x25,0x20,0x03, +0xbd,0x03,0x0c,0x1e,0xa9,0xc1,0xf2,0x25,0x18,0xc8,0xc4,0xd2,0x21,0x1b,0xc8, +0x1c,0xfa,0xdd,0xd8,0x0d,0x65,0xfa,0xfe,0x4c,0x0a,0x0c,0x4b,0xd8,0xc1,0xd9, +0xc2,0xe5,0x1d,0x03,0xa9,0xd1,0xbd,0x03,0x0c,0x0d,0xc8,0xc4,0x0c,0x2e,0xc8, +0x2c,0xe5,0xf8,0xfe,0x4c,0x0a,0x0c,0x4b,0xd8,0xd1,0xd9,0xd2,0x65,0x1c,0x03, +0xa9,0xe1,0xbd,0x03,0x0c,0x0d,0xc8,0xc4,0x0c,0x5e,0xc8,0x5c,0x25,0xf7,0xfe, +0x3c,0x4a,0x0c,0x4b,0xd8,0xe1,0xd9,0xe2,0xa5,0x1a,0x03,0xa9,0xf1,0xbd,0x03, +0xd8,0x75,0xc2,0x24,0x15,0xd8,0x0d,0xe5,0xf9,0xfe,0x0c,0x8a,0x0c,0x4b,0xe8, +0xf1,0xe9,0x82,0x25,0x19,0x03,0xa2,0x61,0x10,0xbd,0x03,0xc2,0x24,0x1b,0xa5, +0xaf,0xfe,0x0c,0x8a,0x0c,0x4b,0xf2,0x21,0x10,0xf9,0x92,0xa5,0x17,0x03,0xa2, +0x61,0x11,0xbd,0x03,0xc2,0x24,0x18,0xe5,0xac,0xfe,0x1c,0x0a,0x0c,0x4b,0x82, +0x21,0x11,0x89,0xf2,0x65,0x16,0x03,0xa2,0x61,0x12,0xbd,0x03,0xc2,0x24,0x13, +0x65,0xa9,0xfe,0x1c,0x0a,0x0c,0x4b,0x92,0x21,0x12,0x92,0x62,0x10,0xe5,0x14, +0x03,0xa2,0x61,0x13,0xbd,0x03,0xc2,0x24,0x13,0xe5,0xa7,0xfe,0xa2,0x21,0x13, +0x0c,0x4b,0xa2,0x62,0x11,0xa2,0xa0,0xc0,0x25,0x13,0x03,0xa2,0x61,0x14,0xbd, +0x04,0xcd,0x05,0xed,0x03,0xfd,0x07,0xd2,0x24,0x16,0x69,0x01,0x65,0xdd,0xfe, +0xb2,0x21,0x14,0x1c,0x4a,0xb2,0x62,0x12,0x0c,0x4b,0x25,0x11,0x03,0xa2,0x61, +0x15,0xbd,0x03,0xcd,0x06,0xe5,0xa2,0xfe,0x0c,0xca,0x0c,0x4b,0xc2,0x21,0x15, +0xc9,0x72,0xe5,0x0f,0x03,0xa2,0x61,0x16,0xbd,0x03,0xc2,0x24,0x19,0x25,0xfd, +0xfe,0xa2,0xa0,0x84,0x0c,0x4b,0xd2,0x21,0x16,0xd2,0x62,0x15,0x65,0x0e,0x03, +0xa2,0x61,0x17,0xbd,0x03,0xc2,0x24,0x17,0xd8,0x95,0xe8,0xa5,0xfd,0x06,0xe5, +0x99,0xfe,0x3c,0x0a,0x0c,0x4b,0xe2,0x21,0x17,0xe2,0x62,0x16,0x65,0x0c,0x03, +0xa2,0x62,0x21,0x0c,0x4b,0x1c,0x4a,0xe5,0x0b,0x03,0xa2,0x62,0x1f,0x0c,0x4b, +0x1c,0x4a,0x25,0x0b,0x03,0xa2,0x62,0x20,0x0c,0x4b,0x1c,0x4a,0xa5,0x0a,0x03, +0xa2,0x62,0x1e,0x0c,0x4b,0x1c,0x4a,0xe5,0x09,0x03,0xa2,0x62,0x22,0x0c,0x4b, +0x1c,0xca,0x65,0x09,0x03,0xa2,0x62,0x23,0x0c,0x4b,0x2c,0x4a,0xa5,0x08,0x03, +0xed,0x07,0xdd,0x06,0xa2,0x61,0x18,0xbd,0x03,0xc2,0x24,0x22,0xa5,0x91,0xfe, +0x1c,0x4a,0x0c,0x4b,0xf2,0x21,0x18,0xf2,0x62,0x18,0xe5,0x06,0x03,0xc2,0x24, +0x23,0xbd,0x03,0x4d,0x0a,0xa5,0x8c,0xfe,0x42,0x62,0x19,0x65,0xcd,0xfe,0x20, +0x8a,0xc0,0x0c,0x4b,0x0c,0xca,0x82,0x62,0x24,0x25,0x05,0x03,0xbd,0x03,0xc8, +0x15,0x3d,0x0a,0x65,0x89,0xfe,0x32,0x62,0x1d,0x1d,0xf0,0x00,0x36,0x41,0x00, +0xbd,0x03,0x1c,0x4a,0xe5,0x06,0x03,0x3d,0x0a,0xb8,0x02,0xe5,0x8c,0x01,0xd8, +0xb2,0xe8,0xa2,0xa8,0x84,0xf8,0x74,0x49,0x22,0x39,0x12,0xa9,0x0e,0xc8,0x44, +0xc9,0x2e,0x98,0x24,0x99,0x3e,0x88,0x34,0xf9,0x5e,0x89,0x4e,0xf8,0x03,0xf9, +0x6e,0x88,0x13,0x89,0x7e,0xb8,0x23,0xb9,0x8e,0x98,0x33,0x99,0x9e,0xa8,0x43, +0xa9,0xae,0xa9,0x5d,0x89,0x1d,0xf9,0x0d,0xb9,0x2d,0x99,0x4d,0xb8,0x94,0x98, +0xc2,0xe8,0x54,0xe9,0x3d,0xb9,0x6d,0xc9,0x09,0xb9,0x19,0x88,0x64,0xa8,0xa4, +0xa9,0x39,0x89,0x29,0xa5,0x06,0x03,0x38,0x62,0x4d,0x0a,0x68,0xa2,0x2c,0x8a, +0xbd,0x04,0x65,0x00,0x03,0x5d,0x0a,0xbd,0x03,0xa5,0x82,0x01,0x0c,0x8a,0xbd, +0x04,0x59,0x33,0x69,0x43,0x68,0x72,0x38,0xb2,0xe5,0xfe,0x02,0x5d,0x0a,0x25, +0x7f,0x01,0xad,0x04,0x39,0x26,0x59,0x16,0xc8,0x82,0xb8,0xc2,0xb9,0x1c,0xa5, +0xfc,0x02,0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x0c,0xca,0x0c,0x4b,0xa5, +0xf9,0x02,0x0c,0x4b,0x0c,0x08,0x59,0x2a,0x49,0x1a,0x39,0x0a,0x69,0x32,0xa9, +0x02,0x79,0x42,0x0c,0xca,0x89,0x12,0x25,0xf8,0x02,0xa9,0x01,0xbd,0x03,0xc2, +0x24,0x19,0x65,0xe5,0xfe,0xa2,0xa0,0x60,0x0c,0x4b,0x98,0x01,0x99,0x52,0xa5, +0xf6,0x02,0xbd,0x03,0xc8,0x64,0xed,0x06,0xd2,0x25,0x11,0xf8,0x42,0x5d,0x0a, +0xe5,0x6f,0xfe,0x59,0x62,0x2c,0xca,0x0c,0x4b,0x25,0xf5,0x02,0xfd,0x07,0x5d, +0x0a,0xbd,0x03,0xd8,0x02,0xc8,0x94,0xd8,0x2d,0xed,0x06,0xd2,0x2d,0x12,0xe5, +0x69,0xfe,0x59,0x72,0x1c,0x8a,0x0c,0x4b,0x65,0xf3,0x02,0xdd,0x06,0xbd,0x03, +0xc8,0x84,0x3d,0x0a,0x25,0x64,0xfe,0x39,0x82,0x2c,0xca,0x0c,0x4b,0x25,0xf2, +0x02,0xa9,0xa2,0x0c,0x4b,0x1c,0xca,0xa5,0xf1,0x02,0xa9,0xb2,0x0c,0x4b,0x1c, +0x0a,0xe5,0xf0,0x02,0xa9,0xc2,0x25,0xb8,0xfe,0x20,0xea,0xc0,0xe9,0xf2,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x58,0x82,0x48,0x62,0x38,0x72,0x81,0x85,0x49,0xad, +0x02,0x88,0xa8,0xb8,0x92,0xe0,0x08,0x00,0x2c,0x8a,0xbd,0x02,0xa5,0xf1,0x02, +0xcd,0x04,0xbd,0x05,0x65,0x85,0xff,0x8c,0x73,0xbd,0x03,0x0c,0x4a,0xa5,0xf0, +0x02,0xa9,0x72,0x1d,0xf0,0x36,0xa1,0x00,0xf1,0x84,0x49,0x2c,0xec,0x61,0x81, +0x49,0xb1,0x81,0x49,0x41,0x2e,0x49,0x0c,0x18,0x72,0x24,0x10,0x80,0x00,0xf3, +0xd8,0x07,0xe8,0x37,0xd0,0xb6,0x93,0x58,0x7e,0x78,0x47,0x59,0x61,0x51,0x7c, +0x49,0x68,0x87,0xc7,0x22,0x06,0x27,0x2c,0x33,0x0c,0x02,0x1d,0xf0,0x1c,0x9c, +0xc7,0x22,0x47,0x27,0x2c,0x02,0xc6,0x69,0x00,0x2c,0x5b,0xb7,0xa2,0x02,0x46, +0x49,0x00,0x27,0xab,0x02,0x46,0x6c,0x00,0xa2,0x24,0x12,0xa2,0x2a,0x2b,0x65, +0xff,0x03,0xb8,0x61,0xb8,0x4b,0xa9,0xcb,0xad,0x0b,0x25,0x64,0xff,0xc6,0xf2, +0xff,0x4c,0x1c,0xc7,0x22,0x43,0x4c,0x28,0x27,0x28,0x6a,0xa8,0x47,0xd2,0x24, +0x12,0x0c,0x0c,0xb2,0x2d,0x24,0xd2,0x2d,0x25,0x65,0x50,0xff,0x86,0xeb,0xff, +0xe6,0x62,0x02,0x06,0x25,0x00,0xe6,0x82,0x02,0x86,0x88,0x00,0x1c,0x2a,0xa7, +0xa2,0x02,0xc6,0x52,0x00,0x27,0x2a,0x02,0xc6,0x87,0x00,0x1c,0x6e,0xe7,0x92, +0x8f,0xb2,0x24,0x12,0xa8,0x67,0xb8,0x7b,0xa5,0x5b,0xff,0x86,0xe0,0xff,0x3c, +0xdc,0xc7,0xa2,0x02,0xc6,0x3e,0x00,0x27,0xac,0x02,0xc6,0x5c,0x00,0xa2,0x24, +0x12,0xa2,0x2a,0x2a,0xa5,0xf8,0x03,0x82,0x25,0x7f,0x82,0x28,0x1a,0xb1,0x45, +0x49,0xe0,0x08,0x00,0x98,0x61,0x98,0x49,0xa9,0x59,0x86,0xd5,0xff,0x5c,0x6c, +0xc7,0xa2,0x02,0x86,0x4c,0x00,0x27,0xac,0x02,0xc6,0x5a,0x00,0x56,0xd3,0x38, +0xb2,0x24,0x12,0xa8,0x61,0xf0,0xcd,0xa0,0xc2,0x2c,0x7f,0x88,0x0a,0xb8,0x2b, +0xa8,0x1a,0xc8,0x0c,0x88,0x08,0xe8,0x4c,0xc8,0x8c,0xe0,0xeb,0xa0,0xc0,0xbb, +0xa0,0xe8,0x0e,0xe9,0x18,0xc8,0x0a,0xb8,0x0b,0xb9,0x2c,0x8c,0x1b,0xe5,0x67, +0xff,0x0c,0x02,0x1d,0xf0,0xe6,0x32,0x02,0x06,0x68,0x00,0xe6,0x42,0x02,0x86, +0x64,0x00,0xd2,0xc2,0xfb,0x56,0x1d,0xf0,0x7c,0xf2,0x82,0xa0,0xd8,0xf2,0x24, +0x12,0xa8,0x17,0xb2,0xcf,0x60,0xc2,0xcf,0x68,0xd2,0xcf,0x64,0xe2,0xcf,0x6c, +0xa8,0x5a,0x92,0xcf,0x74,0x8a,0x8f,0x99,0x01,0x89,0x11,0xf2,0xcf,0x70,0xe5, +0x4c,0xff,0xd2,0x24,0x10,0xd8,0x4d,0x1b,0xb2,0xd8,0x1d,0xc2,0x25,0x7f,0xad, +0x0d,0x88,0x1d,0xd8,0x8d,0xe0,0x08,0x00,0x86,0xb0,0xff,0x1c,0xcb,0xb7,0xa2, +0x02,0x86,0xaa,0x00,0x27,0xab,0x02,0x86,0xdc,0x00,0x17,0x63,0x04,0xad,0x06, +0xa5,0x35,0x01,0x27,0x63,0x04,0xa8,0x61,0xa5,0x38,0x01,0x37,0x63,0x0c,0xa2, +0x24,0x10,0xa8,0x4a,0xb2,0x25,0x7f,0xa8,0x1a,0x25,0x2f,0x01,0x30,0xb4,0x04, +0x16,0xeb,0xe8,0xa2,0x24,0x10,0xa8,0x3a,0xb2,0x25,0x7f,0xa8,0x1a,0xe5,0x2d, +0x01,0x86,0x9f,0xff,0x3c,0x9a,0xa7,0xa2,0x02,0xc6,0x3e,0x00,0x27,0xaa,0x02, +0x46,0xc9,0x00,0xd8,0xcb,0xe2,0x24,0x12,0xd8,0x0d,0xe2,0x2e,0x27,0xc2,0x2d, +0x2f,0xf2,0x2d,0x2d,0xc0,0xce,0xa0,0xf0,0xee,0xa0,0xe8,0x0e,0xe9,0xfd,0xc8, +0x0c,0xc2,0x6d,0x10,0x86,0x93,0xff,0xf2,0xc2,0xf3,0x56,0x8f,0xe4,0xa8,0x3e, +0xd2,0x24,0x12,0x0c,0x1c,0xb2,0x2d,0x35,0xd2,0x2d,0x2c,0xe5,0x38,0xff,0x0c, +0x0a,0xa5,0x51,0xff,0x06,0x8c,0xff,0x2c,0x9a,0xa7,0xa2,0x02,0x06,0x8b,0x00, +0x27,0xaa,0x02,0xc6,0xbb,0x00,0x7c,0xf2,0xe9,0x91,0x86,0x13,0x00,0x4c,0x4a, +0xa7,0xa2,0x02,0x86,0x8a,0x00,0x27,0xaa,0x20,0xe2,0xc2,0xb9,0x56,0xae,0xe0, +0xa8,0x77,0xa8,0x6a,0x65,0x01,0x01,0x06,0x80,0xff,0x3c,0xfb,0xb7,0xa2,0x02, +0xc6,0x8d,0x00,0xa6,0xd2,0x24,0xc2,0xc2,0xc0,0x56,0xfc,0xde,0xa8,0x57,0xd2, +0x24,0x12,0x0c,0x0c,0xb2,0x2d,0x26,0xd2,0x2d,0x2d,0x65,0x33,0xff,0x06,0x77, +0xff,0xa2,0xa1,0x02,0xa7,0x22,0x50,0x27,0xaa,0x02,0x06,0x74,0xff,0x0c,0x02, +0xe9,0x91,0x92,0xa0,0x8c,0x62,0xa0,0xdc,0xf2,0xa0,0x88,0xe2,0xa0,0x84,0xc2, +0xa0,0x80,0x82,0x24,0x12,0xa8,0x91,0xb2,0xc8,0x78,0xd2,0xc8,0x7c,0xa8,0x1a, +0xca,0xc8,0xea,0xe8,0xfa,0xf8,0x6a,0x68,0xa8,0x5a,0x69,0x11,0x9a,0x88,0x89, +0x01,0xe5,0x38,0xff,0xd2,0x24,0x10,0xd8,0x3d,0x1b,0xb2,0xd8,0x1d,0xc2,0x25, +0x7f,0xad,0x0d,0x88,0x1d,0xd8,0x8d,0xe0,0x08,0x00,0x46,0x61,0xff,0xe2,0xd2, +0xff,0x56,0xfe,0xd7,0x0c,0x02,0x86,0x9e,0xff,0xf2,0xc2,0xcc,0x56,0x4f,0xd7, +0x0c,0x0a,0x65,0x45,0xff,0x06,0x5b,0xff,0xb9,0x71,0x82,0xc2,0xfe,0x56,0x48, +0xd6,0xf0,0x2d,0xa0,0xe0,0x83,0x11,0x89,0x81,0x22,0x22,0x7f,0xd8,0x67,0x28, +0x02,0xa8,0x3d,0xc8,0xc2,0xd8,0x0d,0xc0,0xc3,0xa0,0xc8,0x0c,0xc9,0x2d,0xb8, +0x0c,0xc8,0x2c,0xa5,0x4d,0xff,0x92,0x24,0x12,0x92,0x29,0x39,0x78,0x81,0xdc, +0xd9,0xb8,0x42,0xa8,0x61,0xba,0xb7,0xc8,0x0a,0xa8,0x1a,0xc8,0x0c,0xb8,0x0b, +0xb9,0x1c,0xb8,0x82,0xc8,0x0a,0xba,0xb7,0xb8,0x0b,0xb9,0x2c,0x8c,0x1b,0xe5, +0x47,0xff,0xa8,0x86,0xe8,0x32,0xd8,0x72,0xf8,0x66,0xda,0xd7,0xf8,0x0f,0xea, +0xe7,0xe8,0x0e,0xe9,0x1f,0xe8,0x0a,0xd8,0x0d,0xd9,0x2e,0x8c,0x1d,0x25,0x46, +0xff,0xd2,0x22,0x17,0xe8,0xb6,0xc2,0x22,0x18,0xa8,0x16,0xca,0xc7,0x82,0x2a, +0x12,0xe8,0x1e,0x92,0x2a,0x11,0xda,0xd7,0xd8,0x0d,0xb8,0x39,0xd9,0x2e,0x88, +0x28,0xd8,0xc6,0xc8,0x0c,0xd8,0x1d,0xb0,0x88,0xa0,0x88,0x08,0xc9,0x2d,0x89, +0x29,0xa5,0x18,0xff,0xa8,0x06,0x82,0x2a,0x11,0xf2,0x2a,0x12,0x98,0x38,0xf8, +0x2f,0x90,0xff,0xa0,0xf8,0x0f,0xf9,0x28,0x25,0x17,0xff,0xa2,0x26,0x16,0x65, +0xfa,0xfe,0xa8,0x56,0xe5,0x3d,0xff,0xa8,0x46,0x65,0x3d,0xff,0xa2,0x24,0x10, +0xa8,0x4a,0xa8,0x7a,0xa8,0x6a,0xa5,0xea,0x00,0x0c,0x1a,0xa5,0x37,0xff,0xa2, +0x24,0x10,0xb2,0x24,0x12,0xa8,0x3a,0xb8,0x0b,0xa8,0x2a,0xb8,0x7b,0x25,0x34, +0xff,0xd2,0x24,0x10,0xd8,0x4d,0xc2,0x25,0x7f,0xd8,0x1d,0x0c,0x1b,0xad,0x0d, +0x88,0x1d,0xd8,0x8d,0xe0,0x08,0x00,0xf2,0x22,0x16,0xe2,0x24,0x12,0xa2,0x24, +0x10,0xe8,0x2e,0xa8,0x3a,0xf0,0xee,0xa0,0xe8,0x0e,0xa8,0x9a,0xb2,0x9e,0x00, +0x4b,0xce,0xcb,0xde,0xe2,0x9e,0x01,0x25,0x2f,0xff,0x58,0x71,0x88,0xb2,0xf2, +0x24,0x12,0xa8,0x61,0xf8,0x2f,0xa8,0x4a,0x80,0xff,0xa0,0xf8,0x0f,0x98,0xda, +0x82,0x9f,0x02,0x89,0x29,0xf8,0x0f,0xf9,0xba,0xe5,0x29,0xff,0x88,0x12,0x88, +0x78,0x8a,0x83,0x92,0x08,0x00,0xa8,0xf5,0x00,0x99,0x23,0x99,0xfa,0x82,0x08, +0x00,0x92,0x25,0x17,0x00,0x88,0x23,0x89,0x09,0xc6,0x03,0xff,0x92,0xc2,0xe5, +0x56,0x99,0xc0,0xb8,0xf7,0xb8,0x0b,0xa8,0xa7,0xb8,0x0b,0x25,0x0e,0xff,0xc6, +0xfe,0xfe,0x2c,0x6c,0xc7,0xa2,0x02,0xc6,0xfc,0xfe,0x2c,0x7d,0x27,0x2d,0x02, +0xc6,0x9a,0xff,0x06,0xfa,0xfe,0xe2,0xc2,0xbd,0x56,0x2e,0xbe,0x88,0xcb,0x92, +0x24,0x12,0x88,0x38,0x92,0x29,0x29,0xf2,0x28,0x2f,0xa2,0x28,0x2d,0xf0,0xf9, +0xa0,0xa0,0x99,0xa0,0x98,0x09,0x99,0xf8,0xf8,0x0f,0xf2,0x68,0x10,0x06,0xf0, +0xfe,0x92,0xc2,0xc2,0x56,0xa9,0xbb,0xc6,0x8d,0xff,0xa8,0xce,0xa8,0x0a,0xb1, +0x67,0x48,0xa8,0x0a,0xb7,0x9a,0x05,0x41,0x66,0x48,0x46,0x03,0x00,0x0c,0x04, +0xc1,0x65,0x48,0xb1,0x66,0x48,0xc0,0xca,0xc0,0xc0,0x4b,0x83,0x16,0x44,0x07, +0xa2,0xc1,0x10,0xb1,0x63,0x48,0x0c,0x7c,0x25,0x58,0x08,0xc2,0xc1,0x10,0xca, +0xc3,0xc2,0x0c,0x00,0xc0,0xcc,0x11,0xca,0x44,0xb8,0x24,0xa8,0x34,0xb8,0x0b, +0x65,0x72,0x03,0x0c,0x0c,0x8c,0x3a,0x26,0x7a,0x01,0x0c,0x1c,0xa8,0x14,0xb8, +0x04,0x0c,0x0d,0x7c,0xf2,0xc0,0x2d,0x83,0xb8,0x0b,0xe5,0x70,0x03,0x0c,0x09, +0x8c,0x3a,0x26,0x7a,0x01,0x0c,0x19,0x7c,0xfe,0x90,0x2e,0x93,0x1d,0xf0,0xf2, +0xc2,0xc4,0x56,0x4f,0xb4,0x06,0x3e,0xff,0x82,0xc2,0xe2,0x56,0xb8,0xb3,0xa2, +0x26,0x16,0xa5,0xe2,0xfe,0x86,0xcc,0xfe,0x2c,0xa9,0x97,0xa2,0x02,0x86,0xca, +0xfe,0x2c,0xda,0x27,0x2a,0x02,0x46,0x54,0xff,0xc6,0xc7,0xfe,0x7c,0xf2,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x3c,0xc5,0xc1,0x44,0x48,0x26,0x32,0x22, +0x82,0xc2,0xf2,0x16,0xc8,0x0d,0x57,0x92,0x25,0x0c,0x0a,0xc7,0x13,0x0c,0x92, +0xa4,0xb0,0xb2,0xa3,0x84,0xba,0xb3,0xb7,0xb9,0x01,0x0c,0x1a,0x9c,0x0a,0x31, +0x3c,0x48,0xc6,0x2e,0x00,0xc7,0x13,0x08,0xe6,0x23,0x02,0xd6,0x23,0x00,0x66, +0x33,0xed,0x61,0xdd,0x47,0xb1,0x37,0x48,0x3c,0x7d,0x76,0xad,0x72,0xe2,0x1b, +0x7f,0x27,0x9e,0x6a,0xc7,0x93,0x18,0xf1,0x34,0x48,0xa2,0x1b,0x82,0xf7,0x1a, +0xd0,0x81,0x33,0x48,0x31,0x33,0x48,0x40,0x38,0x93,0x38,0x03,0xaa,0x33,0x32, +0x93,0x00,0x0c,0x0a,0xe2,0xa0,0x80,0xea,0xdb,0xd2,0x0d,0x83,0x0c,0x1c,0x00, +0xdd,0x23,0x37,0xad,0x07,0xf2,0xa0,0x7f,0xf7,0x1d,0x01,0x0c,0x0c,0x9c,0x8c, +0xea,0xdb,0xd2,0x0d,0x82,0x0c,0x1c,0x00,0xdd,0x23,0xd7,0xa3,0x07,0xe2,0xaf, +0x80,0xe7,0x1d,0x01,0x0c,0x0c,0x0c,0x1f,0xc0,0xaf,0x93,0x8c,0xfa,0x98,0xe6, +0x82,0x1b,0x80,0xad,0x04,0x9a,0x88,0x39,0x08,0xa5,0x83,0x02,0x86,0x02,0x00, +0x31,0x1a,0x48,0x06,0x01,0x00,0x8b,0xbb,0x31,0x18,0x48,0x1c,0x9a,0xa7,0x12, +0x1b,0x57,0x92,0x26,0xc8,0xe6,0xe1,0x19,0x48,0xb2,0x9c,0x6a,0xd1,0x19,0x48, +0xe0,0xbb,0xd1,0xda,0xbb,0xb0,0xb0,0x31,0xb2,0x6c,0x2e,0x46,0x03,0x00,0x88, +0xe6,0xf2,0x98,0x5c,0xf0,0xff,0xa0,0xf0,0xff,0x11,0xf2,0x68,0x35,0x2d,0x03, +0x1d,0xf0,0x26,0x33,0x05,0x82,0xc3,0xfc,0x56,0x28,0xf4,0x3d,0x0c,0x46,0xfb, +0xff,0x36,0x61,0x00,0xa8,0x02,0x25,0xd2,0x03,0x2d,0x0a,0x66,0x0a,0x03,0x0c, +0x82,0x1d,0xf0,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0xd1,0x08,0x48,0x31,0xa6,0x47, +0xed,0x01,0x88,0x03,0x0c,0x19,0x82,0x28,0x10,0x99,0x01,0xe0,0x08,0x00,0xa8, +0x01,0xf8,0x03,0x9c,0x2a,0xed,0x02,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0x82,0x2f, +0x10,0xd1,0x00,0x48,0xe0,0x08,0x00,0x86,0x02,0x00,0xcd,0x02,0x0c,0x1a,0x88, +0xff,0x1c,0x9b,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x36,0x41,0x00,0xc1,0x97, +0x47,0x98,0xbc,0x7c,0xfa,0x82,0xd9,0xf0,0x9c,0x18,0xcc,0xf9,0xa8,0xac,0xb2, +0x92,0x00,0x65,0xf9,0x02,0x0c,0x79,0x0c,0x82,0xa0,0x29,0x83,0x1d,0xf0,0xc6, +0xfc,0xff,0x00,0x00,0x00,0x36,0x41,0x00,0x1c,0xc4,0x47,0x92,0x07,0x0c,0x02, +0x29,0x03,0x1d,0xf0,0x00,0x00,0x61,0xe5,0x47,0x3c,0x78,0x76,0xa8,0x19,0x92, +0x16,0x7f,0x27,0x99,0x11,0xb1,0x86,0x47,0xa2,0x16,0x80,0xb8,0xeb,0x0c,0x02, +0xba,0xaa,0xa8,0x0a,0xa9,0x03,0x1d,0xf0,0x8b,0x66,0x7c,0xf2,0x1d,0xf0,0x00, +0x00,0x36,0x61,0x00,0xa1,0xe2,0x47,0x38,0x02,0x0c,0x82,0xa0,0x43,0x10,0x82, +0xd4,0xf0,0x9c,0xf8,0xa7,0x83,0x1d,0x30,0xa0,0xb4,0xbd,0x01,0xe5,0xfa,0xff, +0x0c,0x79,0x0c,0x82,0xa0,0x29,0x83,0x66,0x72,0x09,0xa1,0x76,0x47,0x30,0xb0, +0xb4,0xb9,0xaa,0x49,0xba,0x1d,0xf0,0x46,0xfb,0xff,0x00,0x00,0x36,0x61,0x00, +0xa1,0xd4,0x47,0xc8,0x02,0xa0,0x8c,0x10,0x82,0xd8,0xf0,0x9c,0x38,0xa7,0x8c, +0x11,0xc0,0xa0,0xb4,0xbd,0x01,0x65,0xf7,0xff,0xcc,0xaa,0x98,0x01,0x99,0x02, +0x0c,0x72,0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x00,0x00,0x00, +0x36,0x41,0x00,0xed,0x02,0x1c,0x9a,0x81,0x64,0x47,0x0c,0x0b,0x88,0x08,0x0c, +0x4c,0x82,0x28,0x10,0xd1,0xc5,0x47,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0xe8,0x02,0x1c,0x9a,0x81,0x5c,0x47,0x0c,0x0b,0x88, +0x08,0x0c,0x4c,0x82,0x28,0x10,0xd1,0xbe,0x47,0xe0,0x08,0x00,0x0c,0x72,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xed,0x02,0x1c,0x9a,0x81,0x54,0x47,0x0c, +0x0b,0x88,0x08,0x0c,0x4c,0x82,0x28,0x10,0xd1,0xb2,0x47,0xe0,0x08,0x00,0x0c, +0x72,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x38,0x02,0x0c,0x84,0x66,0x13, +0x0b,0x81,0xb1,0x47,0x0c,0x74,0x88,0x18,0x89,0x02,0xc6,0xff,0xff,0x2d,0x04, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xed,0x02,0x1c,0x9a,0x81,0x45,0x47,0x0c, +0x0b,0x88,0x08,0x0c,0x4c,0x82,0x28,0x10,0xd1,0xa9,0x47,0xe0,0x08,0x00,0x0c, +0x72,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xe8,0x02,0x26,0x8e,0x0b,0x26, +0xbe,0x08,0x3c,0x08,0x87,0x1e,0x03,0x0c,0x82,0x1d,0xf0,0x1c,0x9a,0x81,0x39, +0x47,0x0c,0x0b,0x88,0x08,0x0c,0x4c,0x82,0x28,0x10,0xd1,0x9e,0x47,0xe0,0x08, +0x00,0x0c,0x72,0x1d,0xf0,0x36,0x41,0x00,0xc8,0x02,0x0c,0x82,0xc0,0x81,0x64, +0xdc,0x68,0xc0,0x98,0x74,0xf6,0xa9,0x11,0x81,0x2f,0x47,0x88,0x08,0x1c,0x3a, +0x88,0xf8,0x0c,0x8b,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x1d,0xf0,0x00,0x00, +0x36,0x41,0x00,0x31,0x29,0x47,0x41,0x91,0x47,0xb2,0x13,0x12,0xa2,0x24,0x7f, +0xe5,0x47,0x00,0xcc,0x2a,0x0c,0x02,0x1d,0xf0,0xd8,0x02,0xa2,0x13,0x12,0xb2, +0x24,0x7f,0xf1,0x8d,0x47,0xd0,0xeb,0x11,0xfa,0xee,0xe2,0x2e,0x7f,0x81,0x89, +0x47,0xe0,0xea,0xb0,0xc2,0x9e,0x02,0xd7,0xa8,0x04,0x91,0x7c,0x47,0x9a,0xdd, +0xc7,0x2d,0x21,0x82,0x9e,0x03,0xd7,0x28,0x1b,0xb6,0x9b,0x04,0x0c,0xd9,0xb7, +0xb9,0x17,0xf6,0xbb,0x02,0x46,0x28,0x00,0x1c,0x5a,0xb7,0xba,0x02,0x46,0x26, +0x00,0xc1,0x7f,0x47,0x46,0x25,0x00,0x0c,0x82,0x1d,0xf0,0x91,0x7d,0x47,0xe0, +0xeb,0x11,0x9a,0x9e,0x92,0x29,0x7f,0xc2,0xca,0xfc,0x4b,0xf9,0xb6,0x4a,0x3a, +0x98,0x89,0x16,0xac,0x08,0x0c,0x0c,0x82,0xca,0xfb,0x16,0xd8,0x08,0x82,0xca, +0xfa,0x16,0x78,0x09,0x66,0x7a,0x1d,0x81,0x74,0x47,0xa2,0xae,0x70,0xc2,0xcb, +0xf6,0xa0,0x99,0x10,0xa1,0x72,0x47,0x80,0xcc,0xa0,0xd2,0x6c,0x7f,0xa0,0xbd, +0xa0,0xb2,0x2b,0x7f,0x90,0x9b,0x20,0xdd,0x09,0x0c,0x7a,0xa2,0x53,0x12,0xc1, +0x6d,0x47,0xca,0xce,0xc2,0x2c,0x79,0xf0,0xba,0xa0,0x88,0x0c,0x0c,0x0a,0xa6, +0x18,0x0b,0x1b,0xaa,0xd9,0x0b,0xe8,0x0c,0xb2,0xcb,0x34,0xe7,0x2a,0xf3,0x1c, +0x9a,0x0c,0x0b,0x0c,0x4c,0x88,0x03,0xd1,0x64,0x47,0x82,0x28,0x10,0x0c,0x0e, +0xe0,0x08,0x00,0x0c,0x1a,0x88,0x03,0x1c,0x9b,0x88,0xf8,0x7c,0xfc,0xe0,0x08, +0x00,0x0c,0x42,0x1d,0xf0,0x0c,0x0c,0x0c,0x1a,0x88,0x03,0x98,0x0e,0x88,0xf8, +0xd2,0x59,0x00,0xe0,0x08,0x00,0x06,0xfa,0xff,0x7c,0x3a,0xa0,0x99,0x10,0xa1, +0x58,0x47,0xc6,0xe3,0xff,0x6c,0xfa,0x1c,0x0b,0xd0,0xcb,0x93,0xa0,0x99,0x10, +0xc0,0x99,0x20,0x06,0xe2,0xff,0xa2,0xaf,0xdf,0x2c,0x0b,0xd0,0xcb,0x93,0xa0, +0x99,0x10,0xc0,0x99,0x20,0xc6,0xdd,0xff,0x36,0x41,0x00,0x38,0x02,0x30,0x48, +0x74,0xad,0x04,0x30,0x30,0x74,0xbd,0x03,0xa5,0x34,0x00,0x8c,0xea,0x0c,0x72, +0x81,0xd7,0x46,0x91,0x3f,0x47,0x32,0x58,0x12,0x42,0x69,0x7f,0x1d,0xf0,0x0c, +0x02,0x1d,0xf0,0x36,0x61,0x00,0x49,0x11,0x88,0x11,0x0c,0x04,0x49,0x08,0xec, +0x43,0x96,0x22,0x11,0xa1,0x19,0x47,0xb8,0x2a,0xb7,0x32,0x02,0xc6,0x41,0x00, +0x16,0xfb,0x0f,0x7d,0x04,0xa8,0x3a,0x76,0x9b,0x0a,0x92,0x1a,0x00,0x97,0x92, +0x01,0x7d,0x0a,0xa2,0xca,0x14,0x06,0x3b,0x00,0x7d,0x04,0xcc,0x43,0x52,0x17, +0x01,0x86,0x03,0x00,0x82,0x03,0x03,0x52,0x03,0x02,0x80,0x88,0x11,0x80,0x55, +0x20,0x80,0x55,0x23,0x61,0xc0,0x46,0xcc,0x33,0x28,0x27,0x46,0x00,0x00,0x8b, +0x23,0x9c,0x65,0x0b,0x55,0xb2,0x02,0x01,0xa2,0x02,0x00,0xa2,0x56,0x13,0x2b, +0x22,0x00,0xbb,0x23,0xb9,0x01,0xa5,0xc2,0x02,0xe6,0x15,0xe7,0xcc,0x43,0x52, +0x17,0x02,0x86,0x03,0x00,0x82,0x03,0x05,0x52,0x03,0x04,0x80,0x88,0x11,0x80, +0x55,0x20,0x80,0x55,0x23,0x79,0x21,0xcc,0x03,0x28,0x37,0x16,0x45,0x09,0x79, +0x21,0x0b,0x55,0x2b,0x72,0xfc,0x03,0xc2,0x12,0x00,0xc9,0x01,0xc0,0xa8,0x74, +0x26,0x9a,0x07,0x0c,0xbd,0xd7,0x1a,0x02,0x66,0xaa,0x07,0x0c,0x1e,0xf8,0x11, +0xe9,0x86,0xe9,0x0f,0xc0,0x20,0x74,0xc0,0x48,0x74,0xad,0x04,0xbd,0x02,0x25, +0x27,0x00,0xdc,0x8a,0x0c,0x02,0xc6,0x07,0x00,0x00,0x00,0x00,0xd2,0x02,0x00, +0xc2,0x02,0x01,0x80,0xdd,0x11,0xd0,0xcc,0x20,0x80,0xcc,0x23,0x86,0xef,0xff, +0x22,0x56,0x12,0xe1,0x03,0x47,0x0c,0x72,0x42,0x6e,0x7f,0x26,0x82,0x27,0xac, +0x42,0xdc,0x03,0xb2,0x17,0x00,0xb9,0x01,0x2b,0x27,0xad,0x01,0xa5,0xda,0xff, +0x56,0x45,0xf9,0x06,0x09,0x00,0xc2,0x07,0x00,0xb2,0x07,0x01,0x80,0xcc,0x11, +0xc0,0xbb,0x20,0x80,0xbb,0x23,0x86,0xf7,0xff,0x0c,0x0d,0xd9,0x86,0x1d,0xf0, +0x0c,0x02,0x1d,0xf0,0x7d,0x04,0x56,0x17,0xf1,0x7c,0xf2,0x1d,0xf0,0x78,0x21, +0x0c,0x0e,0xe9,0x86,0xcc,0x43,0x52,0x17,0x03,0x86,0x03,0x00,0x82,0x03,0x07, +0x52,0x03,0x06,0x80,0x88,0x11,0x80,0x55,0x20,0x80,0x55,0x23,0xcc,0x03,0x28, +0x47,0x16,0xe5,0xfc,0x1c,0x24,0x5c,0x27,0x0b,0x55,0xcc,0xc3,0xb2,0x12,0x00, +0x2b,0x22,0xb0,0xb0,0x74,0xb2,0x56,0x13,0xc6,0x01,0x00,0xb2,0x02,0x00,0xb2, +0x56,0x13,0x1b,0x22,0xec,0x23,0xa2,0x12,0x00,0xa9,0x01,0x2b,0x22,0xb7,0xb4, +0x2b,0xb7,0x37,0x28,0x81,0xe8,0x46,0x80,0x8b,0xa0,0x82,0x28,0x7f,0xad,0x01, +0xe0,0x08,0x00,0x66,0x7a,0x17,0x56,0x25,0xfc,0x86,0xe2,0xff,0xc2,0x02,0x00, +0xa2,0x02,0x01,0x80,0xcc,0x11,0xc0,0xaa,0x20,0x80,0xaa,0x23,0x06,0xf3,0xff, +0x0c,0x82,0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0xb8,0x02,0xa1,0xb1,0x46, +0x96,0x0b,0x02,0xc8,0x2a,0xc7,0xbb,0x1b,0x9c,0x3c,0x0c,0x05,0xa8,0x3a,0x76, +0x9c,0x0a,0x82,0x1a,0x00,0x87,0x9b,0x01,0x5d,0x0a,0xa2,0xca,0x14,0x46,0x00, +0x00,0x0c,0x05,0x56,0x55,0x05,0x7c,0xf9,0xc6,0x11,0x00,0x38,0x45,0x92,0x15, +0x03,0x0c,0x0a,0xa9,0x84,0x2d,0x09,0xbc,0x79,0x1c,0x25,0x71,0xcc,0x46,0x5c, +0x26,0x0b,0x22,0xb2,0x13,0x00,0xc2,0x13,0x01,0xc9,0x01,0x4b,0x33,0xb0,0xb0, +0x74,0xb2,0x54,0x13,0xb7,0x35,0x02,0xc6,0x2a,0x00,0xb7,0xb6,0x02,0x46,0x29, +0x00,0x70,0x8b,0xa0,0x82,0x28,0x7f,0xad,0x01,0xe0,0x08,0x00,0x92,0xca,0xf9, +0x56,0x49,0x09,0x56,0xd2,0xfc,0x0c,0x09,0x0c,0x7a,0x0c,0x82,0x90,0x2a,0x83, +0x1d,0xf0,0x41,0x48,0x46,0xb2,0x15,0x01,0x38,0x25,0x2d,0x0b,0x9c,0x6b,0x0b, +0x22,0xb2,0x03,0x01,0xa2,0x03,0x00,0xa2,0x54,0x13,0x2b,0x33,0x00,0xbb,0x23, +0xb9,0x01,0xe5,0xa4,0x02,0xe6,0x12,0xe7,0xc2,0x15,0x02,0x38,0x35,0x2d,0x0c, +0x16,0x0c,0xf8,0x0b,0x22,0xc2,0x13,0x00,0xc9,0x01,0xc0,0xa8,0x74,0x26,0x9a, +0x07,0x0c,0xb8,0x87,0x1a,0x02,0x66,0xaa,0x03,0x0c,0x19,0x99,0x84,0xc0,0x60, +0x74,0xc0,0x78,0x74,0xad,0x07,0xbd,0x06,0x65,0x0b,0x00,0xcc,0x6a,0x0c,0x09, +0x46,0x03,0x00,0x00,0x00,0x00,0x0c,0x79,0xa1,0x99,0x46,0x62,0x54,0x12,0x72, +0x6a,0x7f,0x26,0x89,0x13,0x9c,0x09,0xad,0x01,0xb2,0x13,0x01,0xb9,0x01,0x4b, +0x33,0x25,0xc0,0xff,0x56,0x02,0xfb,0x86,0xcb,0xff,0x0c,0x0c,0xc9,0x84,0xc6, +0xdb,0xff,0x0c,0x89,0x86,0xda,0xff,0x00,0x00,0x36,0x41,0x00,0xe8,0x02,0x82, +0xa1,0xff,0xe7,0xb8,0x03,0x0c,0x82,0x1d,0xf0,0x0c,0x7a,0x81,0x20,0x46,0x0c, +0x0b,0x88,0x08,0x0c,0x4c,0x82,0x28,0x10,0x0c,0x0d,0xe0,0x08,0x00,0x0c,0x72, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x88,0x02,0x3d,0x02,0x66,0x18,0x0b,0x91, +0x8c,0x46,0x92,0x19,0x7f,0x99,0x03,0x0c,0x72,0x1d,0xf0,0x25,0x7a,0x03,0xa0, +0x90,0xf4,0x06,0xfc,0xff,0x00,0x36,0x41,0x00,0x81,0x12,0x46,0xc8,0x02,0x88, +0x08,0x1c,0xca,0x88,0xf8,0x1c,0x9b,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x00, +0x36,0x41,0x00,0x81,0x0c,0x46,0xc8,0x02,0x88,0x08,0x0c,0x1a,0x88,0xf8,0x1c, +0x7b,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x00,0x36,0x41,0x00,0x1c,0x94,0x27, +0x34,0x0f,0x51,0x7a,0x46,0x50,0x52,0xb0,0x52,0x25,0x7f,0x0c,0x12,0x57,0xa3, +0x01,0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x36,0x41,0x00,0x38,0x02,0x30,0x48,0x74, +0xad,0x04,0x30,0x30,0x74,0xbd,0x03,0x65,0xfd,0xff,0xcc,0x2a,0x0c,0x02,0x1d, +0xf0,0xb1,0x65,0x46,0xd0,0xa4,0x11,0xba,0xaa,0xa2,0x2a,0x7f,0xa0,0xa3,0xb0, +0xa8,0x0a,0xcc,0x2a,0x0c,0x82,0x1d,0xf0,0xb6,0x94,0x04,0x0c,0xdc,0x47,0xbc, +0x11,0x92,0x9a,0x00,0xd6,0x29,0x00,0x92,0xd9,0x80,0x90,0xd0,0xf4,0xd9,0x02, +0x0c,0x72,0x1d,0xf0,0x91,0x5b,0x46,0x90,0x94,0xa0,0x92,0x29,0x7f,0x4b,0xa9, +0xb6,0x43,0x1e,0xa8,0x89,0x0c,0x09,0x26,0x43,0x2a,0x26,0x53,0x37,0x26,0x63, +0x1c,0x66,0x73,0x1c,0xa1,0x54,0x46,0x92,0xc4,0xf6,0xa0,0x99,0xa0,0x92,0x19, +0xfe,0x46,0x03,0x00,0xa0,0xb3,0xa0,0xb2,0x1b,0x00,0xb9,0x02,0xc6,0xf0,0xff, +0xa0,0x95,0x04,0x99,0x02,0xc6,0xee,0xff,0x0c,0xcc,0xc0,0xba,0x10,0x26,0x4b, +0xf2,0xc7,0x8a,0x0a,0x0c,0x19,0x86,0xfa,0xff,0xa0,0x94,0x04,0x06,0xf9,0xff, +0x66,0xab,0x04,0x0c,0x29,0x06,0xf7,0xff,0x66,0x8b,0x9a,0x0c,0x39,0x06,0xf5, +0xff,0x00,0x00,0x36,0x41,0x00,0x31,0x49,0x46,0x4d,0x02,0x28,0x02,0x20,0x20, +0xf4,0x3a,0x22,0x22,0x02,0x00,0x29,0x04,0x0c,0x72,0x1d,0xf0,0x36,0x61,0x00, +0x98,0x02,0x90,0x88,0x41,0x90,0x30,0x74,0x39,0x01,0x56,0x08,0x0b,0x0c,0x34, +0x90,0x26,0x14,0xa2,0xc2,0xfe,0x16,0x5a,0x0a,0xec,0x72,0x1c,0x9a,0x0c,0x0b, +0x51,0xc5,0x45,0x0c,0x4c,0x88,0x05,0xd1,0x35,0x46,0x82,0x28,0x10,0x0c,0x0e, +0xe0,0x08,0x00,0x0c,0x1a,0x88,0x05,0x1c,0x9b,0x88,0xf8,0x7c,0xfc,0xe0,0x08, +0x00,0xa1,0x35,0x46,0x46,0x00,0x00,0x0c,0x0a,0x7c,0xff,0xb1,0x33,0x46,0x26, +0x12,0x05,0x92,0xc2,0xfd,0x56,0x39,0x0a,0x0c,0x1a,0xc0,0x20,0x00,0xd2,0x2b, +0xb1,0x30,0x84,0x14,0xf0,0xc8,0x11,0x00,0x1c,0x40,0x00,0xe4,0xa1,0xf0,0xee, +0x30,0xe0,0xdd,0x10,0x00,0x1c,0x40,0x30,0xe2,0x14,0x00,0x9e,0xa1,0x90,0xdd, +0x20,0xf0,0x9e,0x11,0xe2,0xce,0x11,0x00,0x19,0x40,0x00,0xc4,0xa1,0xf0,0xcc, +0x30,0x00,0x19,0x40,0xc0,0xdd,0x10,0x00,0xc8,0xa1,0x82,0xc8,0x11,0xd0,0xcc, +0x20,0x00,0x18,0x40,0x00,0xda,0xa1,0x00,0x1e,0x40,0x00,0xaa,0xa1,0xd0,0xaa, +0x20,0xc0,0xaa,0x20,0x66,0x32,0x4a,0x30,0xc4,0x14,0x30,0xe2,0x14,0xc7,0x1e, +0x08,0x30,0xd0,0x14,0xc7,0x1d,0x09,0xe7,0x1d,0x03,0x0c,0x82,0x1d,0xf0,0xc7, +0x9d,0x31,0x0c,0x82,0x20,0x8c,0x90,0x20,0x2e,0x90,0x00,0x12,0x40,0x00,0x94, +0xa1,0xf0,0x99,0x30,0x00,0x18,0x40,0x90,0x9a,0x10,0x00,0xa4,0xa1,0xf0,0xaa, +0x30,0x00,0x12,0x40,0x00,0x2d,0xa1,0xa0,0x99,0x10,0x00,0x18,0x40,0x90,0x22, +0x20,0x00,0xad,0xa1,0x20,0xaa,0x20,0xc0,0x20,0x00,0xa2,0x6b,0xb1,0x0c,0x72, +0x1d,0xf0,0x36,0x41,0x00,0x38,0x02,0x0c,0x82,0xb6,0x23,0x01,0x1d,0xf0,0x0c, +0x72,0x1d,0xf0,0x36,0x41,0x00,0x41,0x01,0x46,0x0c,0x05,0x38,0x04,0x59,0x02, +0x8c,0x63,0x59,0x02,0x59,0x04,0x0c,0x72,0x1d,0xf0,0x0c,0x16,0x69,0x04,0x4d, +0x02,0x06,0xfc,0xff,0x00,0x36,0x41,0x00,0x51,0xfa,0x45,0x38,0x02,0x59,0x02, +0x30,0x50,0x74,0x30,0x38,0x74,0xcc,0x83,0x1c,0x38,0x91,0xf7,0x45,0x99,0x02, +0x57,0xb8,0x03,0x0c,0x82,0x1d,0xf0,0xd1,0xf6,0x45,0x0c,0x08,0x89,0x02,0x61, +0xf3,0x45,0x91,0xf4,0x45,0x60,0x65,0xa0,0xc0,0x20,0x00,0x42,0x26,0x80,0xb8, +0x09,0x0c,0x1a,0xc8,0x0d,0x59,0x0d,0xc0,0xc5,0xc0,0xc0,0xab,0x83,0x8c,0xfa, +0x89,0x09,0x40,0x40,0xf5,0x49,0x02,0xc0,0x20,0x00,0x82,0x66,0x80,0x0c,0x72, +0x1d,0xf0,0x40,0x40,0xf4,0x0c,0x1a,0xa9,0x09,0x46,0xfa,0xff,0x00,0x00,0x00, +0x36,0x41,0x00,0x4d,0x02,0x28,0x02,0x51,0x66,0x45,0x9c,0xd2,0x26,0x12,0x08, +0x51,0xc0,0x45,0x59,0x04,0x0c,0x72,0x1d,0xf0,0x58,0x35,0x28,0x75,0x82,0x95, +0x04,0x20,0x56,0x21,0x80,0x55,0xd1,0x50,0x56,0x21,0x86,0xf9,0xff,0x58,0x35, +0x0c,0x09,0x28,0x65,0x99,0x65,0x46,0xf9,0xff,0x00,0x00,0x36,0x41,0x00,0x41, +0x59,0x45,0x28,0x02,0x0c,0x79,0x9c,0x22,0x26,0x52,0x1d,0xa6,0x92,0x08,0x38, +0x34,0x0c,0x04,0x29,0x43,0x86,0x02,0x00,0x7c,0xf4,0x46,0x01,0x00,0x88,0x34, +0x0c,0x04,0x49,0x48,0x0c,0x82,0x40,0x29,0x83,0x1d,0xf0,0xa2,0xa3,0xe8,0xb8, +0x34,0x0c,0x04,0xa9,0x4b,0x06,0xfb,0xff,0x00,0x00,0x00,0x36,0x41,0x00,0xa8, +0x02,0xf6,0xba,0x14,0x81,0x49,0x45,0x88,0x18,0x0c,0x0b,0x82,0x28,0x31,0x1c, +0x0c,0xe0,0x08,0x00,0xa9,0x02,0x0c,0x72,0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0xa8,0x02,0xa5,0x39,0x03,0xa9,0x02,0x0c,0x72,0x1d, +0xf0,0x00,0x00,0x36,0x41,0x00,0xa8,0x02,0xf6,0xba,0x14,0x81,0x3c,0x45,0x88, +0x18,0x0c,0x0b,0x82,0x28,0x30,0x1c,0x0c,0xe0,0x08,0x00,0xa9,0x02,0x0c,0x72, +0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x61,0x90,0x45, +0x20,0x50,0xf5,0x20,0x90,0xf4,0x81,0x9c,0x45,0x99,0x04,0x57,0xa8,0x11,0xa1, +0xaf,0x45,0xb1,0xaf,0x45,0x57,0x2a,0x08,0xb0,0xb5,0xa0,0xb2,0x2b,0x7f,0x46, +0x00,0x00,0x0c,0x0b,0x8c,0xcb,0xad,0x04,0xe0,0x0b,0x00,0x2d,0x0a,0x26,0x8a, +0x58,0x59,0x03,0x1d,0xf0,0xc1,0xa8,0x45,0xd1,0xa8,0x45,0xc7,0x15,0x42,0xd7, +0x15,0x3f,0xe1,0xa7,0x45,0xf1,0xa7,0x45,0xe7,0x15,0x36,0xf7,0x15,0x33,0x81, +0xa6,0x45,0x91,0xa6,0x45,0x87,0x15,0x2a,0x97,0x15,0x27,0xa1,0xa5,0x45,0xb1, +0xa5,0x45,0xa7,0x15,0x1e,0xb7,0x15,0x1b,0xc1,0xa4,0x45,0xd1,0xa4,0x45,0xc7, +0x15,0x12,0xd7,0x15,0x0f,0xe1,0xa3,0x45,0xf1,0xa3,0x45,0xe7,0x15,0x06,0xf7, +0x15,0x03,0x0c,0x02,0x1d,0xf0,0x69,0x03,0x0c,0x72,0x3d,0x04,0x86,0xe9,0xff, +0x69,0x03,0x3d,0x04,0xc6,0xe7,0xff,0x36,0x41,0x00,0x41,0x9c,0x45,0x21,0x0e, +0x45,0x16,0xc3,0x08,0x82,0xc3,0xfe,0x16,0xc8,0x0a,0x92,0xc3,0xfd,0x16,0xa9, +0x09,0xa2,0xc3,0xf4,0x56,0x8a,0x07,0x0c,0x6a,0x0c,0x0b,0x0c,0xdc,0x88,0x02, +0xd8,0x52,0x82,0x28,0x10,0xe1,0x93,0x45,0xe0,0x08,0x00,0x98,0x52,0x7c,0xfa, +0xa0,0x99,0x30,0x99,0x52,0x1d,0xf0,0xa2,0x64,0x86,0x0c,0x1a,0x88,0x02,0x0c, +0x1b,0x88,0xf8,0xc1,0x8d,0x45,0xe0,0x08,0x00,0xc1,0x8c,0x45,0x0c,0x09,0x97, +0x1c,0x0a,0x88,0x02,0x0c,0x1a,0x88,0xf8,0x0c,0x7b,0xe0,0x08,0x00,0x0c,0x1a, +0x88,0x02,0x1c,0x6b,0x88,0xf8,0xc1,0x87,0x45,0xe0,0x08,0x00,0x0c,0x1a,0x88, +0x02,0x0c,0x8b,0x88,0xf8,0xc1,0x84,0x45,0xe0,0x08,0x00,0x0c,0x1a,0x88,0x02, +0x0c,0x6b,0x88,0xf8,0xc1,0x82,0x45,0xe0,0x08,0x00,0x92,0x24,0x7c,0xcc,0x69, +0xb8,0x02,0xa1,0x7f,0x45,0xa2,0x6b,0x18,0x1d,0xf0,0xc2,0x24,0x86,0x66,0x0c, +0x9f,0xa2,0x24,0x85,0x25,0x21,0x03,0x66,0x0a,0x93,0x0c,0x0d,0xd2,0x64,0x86, +0xd2,0x64,0x85,0xc6,0xe2,0xff,0x81,0x78,0x45,0x88,0x08,0x0c,0x0a,0xe0,0x08, +0x00,0x1d,0xf0,0x0c,0x1a,0x88,0x02,0xb2,0xa0,0x80,0x88,0xf8,0xc1,0x74,0x45, +0xe0,0x08,0x00,0xc2,0x24,0x86,0x88,0x02,0x0c,0x1a,0x88,0xf8,0x1c,0x9b,0xe0, +0x08,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x20,0xea,0x03,0x1d,0xf0,0x36, +0x61,0x00,0x98,0x02,0x81,0x2b,0x45,0xcc,0x49,0xb1,0x28,0x45,0x86,0x01,0x00, +0x0b,0xa9,0x0c,0x0b,0xa0,0xb8,0x83,0xa6,0x1b,0x78,0x31,0xcf,0x44,0xf8,0x33, +0x0c,0x02,0xc8,0xcf,0xad,0x0f,0x76,0x9c,0x0a,0xd2,0x2a,0x10,0xa2,0xca,0x10, +0xb7,0x1d,0x01,0x1b,0x22,0xc7,0xb2,0x5c,0xe2,0x2f,0x45,0xe7,0x12,0x52,0x1c, +0x9a,0x0c,0x0b,0x0c,0x4c,0xd1,0x26,0x45,0xed,0x01,0x22,0x6f,0x45,0x88,0x03, +0x0c,0x19,0x82,0x28,0x10,0x99,0x01,0xe0,0x08,0x00,0xa8,0x01,0xf8,0x03,0x9c, +0x9a,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0x81,0x54,0x45,0x80,0xe2,0x01,0x80,0xee, +0x20,0x82,0x2f,0x10,0xd1,0x1c,0x45,0xe0,0x08,0x00,0xc6,0x05,0x00,0xbd,0x02, +0x1c,0xfa,0x88,0xff,0x0c,0x0c,0xe0,0x08,0x00,0x0c,0x1a,0x88,0x03,0x1c,0x9b, +0x88,0xf8,0x7c,0xfc,0xe0,0x08,0x00,0x0c,0x72,0x1d,0xf0,0x0c,0x82,0x1d,0xf0, +0x00,0x36,0x41,0x00,0x51,0xaf,0x44,0x0c,0x16,0x58,0x35,0x7c,0xf4,0x82,0x25, +0x45,0x31,0x01,0x45,0xc0,0x88,0x11,0x8a,0x55,0x52,0x25,0x10,0x81,0x00,0x45, +0x37,0x95,0x04,0x0c,0x04,0x46,0x01,0x00,0x80,0x85,0xc0,0x80,0x46,0x83,0x26, +0x04,0x05,0x49,0x02,0x0c,0x72,0x1d,0xf0,0x0c,0x82,0x1d,0xf0,0x36,0x41,0x00, +0x38,0xf2,0x0c,0x0a,0x48,0x42,0x88,0x32,0x9d,0x04,0x76,0xa8,0x04,0xa2,0x59, +0x00,0x2b,0x99,0x88,0x22,0x58,0x23,0x80,0x55,0xa0,0x58,0x05,0xa8,0xd2,0x58, +0x15,0xb2,0x23,0x38,0x58,0x05,0x65,0xfe,0xfd,0x88,0x22,0x98,0x23,0xc8,0x02, +0xb8,0x12,0x5a,0xda,0xf0,0xed,0x11,0xe0,0xe4,0xc0,0xc0,0xbb,0xc0,0x80,0x89, +0xa0,0x88,0x08,0x1b,0xcb,0xb0,0xcb,0xb3,0xc0,0xa2,0x21,0x88,0x38,0x99,0xa2, +0x40,0xba,0x90,0x40,0x9d,0x90,0x88,0x08,0x89,0xe2,0xd0,0x9e,0xa3,0x90,0xaa, +0x90,0xf2,0x23,0x38,0xf9,0x92,0xd9,0xb2,0xb9,0x82,0x99,0x52,0x49,0x62,0xa9, +0x72,0x1d,0xf0,0x00,0x36,0x01,0x01,0x61,0xdf,0x44,0xb1,0x84,0x44,0x1c,0xc8, +0xc2,0x2b,0x10,0x4d,0x02,0x28,0x0c,0x87,0x14,0x02,0xc6,0x21,0x00,0x51,0xca, +0x44,0x42,0x61,0x14,0x30,0x90,0x04,0x0c,0x1a,0xa0,0x00,0xf3,0x16,0x69,0x09, +0x48,0x4c,0x48,0x74,0xa8,0x64,0x25,0xf6,0xff,0xa8,0x74,0x65,0x1b,0x00,0x98, +0x44,0x0f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0x88,0x29,0x98,0x39,0x76,0xa8, +0x02,0x40,0x09,0x8d,0x71,0x73,0x44,0x42,0x27,0x10,0x48,0x44,0x48,0x84,0x48, +0x34,0x88,0xa5,0xb8,0xf4,0xa8,0x34,0x98,0x44,0xe8,0x24,0xf8,0x14,0xf9,0x51, +0xe9,0x61,0x99,0x41,0xa9,0x31,0x98,0x04,0xad,0x04,0xc8,0x19,0xd8,0x09,0xd9, +0x01,0xc9,0x11,0x98,0x29,0x99,0x21,0xe0,0x08,0x00,0x4c,0x0a,0xbd,0x04,0x25, +0xbd,0x01,0xb8,0x01,0xc8,0x11,0xd8,0x21,0xe8,0x31,0xf8,0x41,0x25,0xbf,0xfe, +0xad,0x04,0xb8,0x51,0xc8,0x61,0x65,0xb4,0xfe,0x0c,0x19,0xc6,0x08,0x00,0xbd, +0x03,0xcd,0x02,0xad,0x04,0x25,0x1c,0xff,0x3d,0x0a,0x42,0x61,0x14,0x60,0x8a, +0xc0,0x16,0x08,0x12,0xa2,0x21,0x14,0xbd,0x03,0x65,0xc9,0xfe,0x2d,0x0a,0x1d, +0xf0,0x7d,0x0b,0x0c,0x09,0x17,0x63,0x64,0x42,0x27,0x10,0x49,0x71,0x48,0x44, +0x48,0x84,0x88,0xa5,0xb2,0x24,0x24,0xd8,0x04,0xc2,0x24,0x18,0xe2,0x24,0x1a, +0x92,0x24,0x1c,0xa2,0x24,0x1b,0xa9,0xb1,0x99,0xd1,0xad,0x04,0x92,0x24,0x19, +0xf8,0x0e,0xc8,0x2c,0xd2,0x2d,0x13,0xd9,0xc1,0xc9,0xe1,0xf9,0x81,0x98,0x29, +0xf8,0x1e,0xf9,0x91,0x99,0xf1,0xe8,0x2e,0xe9,0xa1,0xe0,0x08,0x00,0xa2,0xa0, +0x94,0xbd,0x04,0x65,0xb4,0x01,0xb8,0x81,0xc8,0x91,0xd8,0xa1,0xe8,0xb1,0xf8, +0xc1,0x65,0x7a,0xfe,0xad,0x04,0xb8,0xd1,0xc8,0x71,0xd8,0xe1,0xe8,0xf1,0xe5, +0x60,0xfe,0x0c,0x19,0x27,0x63,0x44,0xc2,0x27,0x10,0x88,0xa5,0x48,0x3c,0xc8, +0x0c,0x48,0x74,0xc2,0x61,0x10,0x98,0x54,0xb8,0xa4,0xa8,0xb4,0xa2,0x61,0x12, +0xb2,0x61,0x11,0xad,0x04,0xb8,0xd4,0x98,0x39,0x92,0x61,0x13,0xe0,0x08,0x00, +0x52,0x21,0x13,0x3c,0x8a,0xbd,0x04,0x65,0xaf,0x01,0xdd,0x05,0xb2,0x21,0x10, +0xc2,0x21,0x12,0xe5,0x4c,0xfe,0xad,0x04,0xb2,0x21,0x11,0xe5,0x46,0xfe,0x0c, +0x19,0x37,0x63,0x0b,0xa2,0x27,0x10,0xa8,0x4a,0xa8,0x1a,0x25,0xba,0xfe,0x0c, +0x19,0x47,0x63,0x0b,0xa2,0x27,0x10,0xa8,0x3a,0xa8,0x1a,0x25,0xb9,0xfe,0x0c, +0x19,0x16,0xe9,0xf1,0x41,0xb8,0x44,0x51,0xb9,0x44,0xc2,0x04,0x80,0xb2,0x04, +0x81,0x00,0xcc,0x23,0x00,0xbb,0x23,0xc7,0x2b,0x1f,0xb2,0x14,0x3f,0xc1,0x1a, +0x44,0x72,0x14,0x3e,0xc8,0xec,0xad,0x07,0xca,0xbb,0xcd,0x02,0xb8,0x0b,0xa5, +0x0a,0xff,0xbd,0x0a,0x67,0x1a,0x0f,0xad,0x07,0xa5,0xb8,0xfe,0x8b,0x44,0x57, +0x94,0xcb,0x46,0xb8,0xff,0x00,0x00,0x00,0x7c,0xf2,0x1d,0xf0,0x00,0x00,0x00, +0x36,0x41,0x00,0xbd,0x03,0xad,0x02,0x88,0x02,0xc8,0x82,0xe0,0x08,0x00,0x1d, +0xf0,0x36,0x41,0x00,0xa2,0xc2,0x14,0x0c,0x0b,0x65,0x87,0x01,0xa2,0xc2,0x1c, +0x0c,0x0b,0xe5,0x86,0x01,0x88,0x92,0x0c,0x0c,0xf0,0x88,0x11,0x80,0x82,0x41, +0xa6,0x18,0x1b,0x0c,0x0a,0x0f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0xb8,0xa2, +0xa0,0x2b,0xc6,0x98,0x92,0x1b,0xaa,0xf0,0x99,0x11,0x90,0x92,0x41,0x97,0x2a, +0xed,0xc9,0x22,0x1d,0xf0,0x36,0x41,0x00,0xa8,0xa2,0xa5,0xe2,0xfd,0xa8,0xb2, +0x65,0xe2,0xfd,0xa8,0xc2,0x25,0xe2,0xfd,0xa8,0xd2,0xa5,0xe1,0xfd,0xa8,0xe2, +0x65,0xe1,0xfd,0xa8,0x02,0x25,0xff,0xfd,0xa8,0x12,0xe5,0xfe,0xfd,0xa2,0x22, +0x12,0x0c,0x0b,0xe5,0xde,0xfd,0xa2,0x22,0x16,0x65,0xe1,0xfd,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0xa8,0x22,0x25,0xdf,0xfd,0xa8,0x32,0xe5,0xde,0xfd,0xa8, +0x52,0x0c,0x1b,0xe5,0xdc,0xfd,0xb8,0x42,0xad,0x0b,0x88,0x8b,0xb8,0x0b,0xe0, +0x08,0x00,0xa8,0xc2,0xb1,0xed,0x43,0x25,0x7e,0x01,0x1d,0xf0,0x00,0x00,0x00, +0x36,0x41,0x00,0x31,0x79,0x44,0x41,0x79,0x44,0x51,0x3b,0x44,0x61,0xdf,0x43, +0x0c,0xa8,0x98,0xe6,0xa1,0x77,0x44,0xa2,0x69,0x30,0x82,0x69,0x31,0xc2,0x03, +0x80,0xb2,0x03,0x81,0x00,0xcc,0x23,0x00,0xbb,0x23,0xc7,0x2b,0x22,0x9c,0x02, +0xd2,0x13,0x41,0x57,0x1d,0x1a,0xa2,0x13,0x3e,0xb1,0x2e,0x44,0x65,0xd3,0xff, +0x86,0x03,0x00,0xc8,0xe6,0xb2,0x13,0x3f,0xa2,0x13,0x3e,0xca,0xbb,0xb8,0x0b, +0x65,0xd2,0xff,0x8b,0x33,0x47,0x93,0xc8,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41, +0x00,0xbd,0x03,0x5c,0x8a,0x65,0x96,0x01,0x3d,0x0a,0xb8,0x02,0x25,0x98,0x07, +0x39,0x52,0x25,0x9b,0x01,0x3d,0x0a,0xa8,0x32,0xbd,0x03,0xe5,0xee,0xfc,0xa8, +0x42,0xbd,0x03,0xe5,0xe2,0xfc,0xad,0x03,0x25,0x93,0x01,0xa5,0x99,0x01,0x3d, +0x0a,0xa8,0x62,0xbd,0x03,0x65,0xdf,0xfc,0xad,0x03,0x25,0x92,0x01,0x1d,0xf0, +0x00,0x00,0x36,0x41,0x00,0xb8,0x13,0xad,0x02,0xb8,0x0b,0xe5,0x2b,0x01,0x1d, +0xf0,0x00,0x00,0x36,0x41,0x00,0xb8,0x33,0xa2,0xc2,0x14,0xe5,0x2a,0x01,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x88,0x13,0x0c,0x4b,0x88,0x08, +0x00,0x14,0x40,0x00,0x48,0xa1,0x65,0x8c,0x01,0xbd,0x04,0x3d,0x0a,0xe5,0x28, +0x01,0x39,0x02,0x1d,0xf0,0x00,0x36,0x41,0x00,0xb8,0x13,0xad,0x02,0xb8,0x8b, +0xe5,0x27,0x01,0xb8,0x13,0x8b,0xa2,0xb8,0x8b,0xe5,0xb5,0xfc,0xb8,0x13,0xa2, +0xc2,0x10,0xb8,0x3b,0xa5,0x26,0x01,0xb8,0x13,0xa2,0xc2,0x18,0xb8,0x0b,0x25, +0x26,0x01,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02,0xa5,0x50,0xfd,0x1d,0xf0, +0x00,0x00,0x36,0x41,0x00,0xad,0x02,0xe5,0x4f,0xfd,0x8b,0xa2,0xa5,0x4f,0xfd, +0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02,0xe5,0x4e,0xfd,0xb8,0x03,0x8b,0xa2, +0xb8,0x7b,0xe5,0x37,0xfd,0xc8,0x03,0xb8,0x13,0xc8,0x6c,0xb2,0x2b,0x28,0xa2, +0xc2,0x10,0xc0,0xbb,0x90,0xe5,0x21,0x01,0xa2,0xc2,0x18,0xe5,0x4c,0xfd,0xa2, +0xc2,0x20,0x65,0x4c,0xfd,0xa2,0xc2,0x28,0x25,0x4c,0xfd,0xb8,0x13,0xa2,0xc2, +0x30,0xb2,0x2b,0x17,0xa5,0xae,0xfc,0xa2,0xc2,0x38,0x25,0x4b,0xfd,0xa2,0xc2, +0x44,0xa5,0x4a,0xfd,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b, +0xa5,0x81,0x01,0x3d,0x0a,0x65,0x49,0xfd,0x39,0x02,0x1d,0xf0,0x00,0x36,0x41, +0x00,0xb8,0x63,0xad,0x02,0x8b,0xbb,0x25,0x1d,0x01,0x8b,0xa2,0x25,0x48,0xfd, +0x1d,0xf0,0x00,0x36,0x41,0x00,0xbd,0x03,0x4c,0x4a,0x65,0x82,0x01,0xc8,0x02, +0x3d,0x0a,0xb8,0x1c,0xc8,0x0c,0x25,0xbc,0xfd,0x39,0x12,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0x0c,0x8a,0x0c,0x4b,0x65,0x7d,0x01,0xbd,0x03,0x4d,0x0a, +0xa5,0x2e,0xfd,0x49,0x02,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x8a, +0x0c,0x4b,0xe5,0x7b,0x01,0x3d,0x0a,0xa5,0x43,0xfd,0x39,0x02,0x0c,0x8a,0x0c, +0x4b,0xe5,0x7a,0x01,0x3d,0x0a,0xe5,0x42,0xfd,0x39,0x12,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0x88,0x03,0xa2,0xc2,0x10,0x38,0x78,0xb2,0xc2,0x18,0xcd, +0x03,0xe5,0xa5,0xfc,0xa2,0xc2,0x24,0xcb,0xb2,0xcd,0x03,0x25,0xa5,0xfc,0xa2, +0xc2,0x20,0x8b,0xb2,0xcd,0x03,0xa5,0xa4,0xfc,0xcd,0x03,0xa2,0xc2,0x14,0xb2, +0xc2,0x1c,0xe5,0xa3,0xfc,0xad,0x02,0x4b,0xb2,0xa5,0x09,0x00,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0x0c,0x8a,0x48,0x03,0x0c,0x4b,0x48,0x74,0xa5,0x75,0x01, +0xbd,0x04,0x3d,0x0a,0xa5,0xe5,0xfc,0x39,0x42,0xad,0x02,0x4b,0xb2,0xa5,0x07, +0x00,0x8b,0xa2,0xcb,0xb2,0x25,0x07,0x00,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad, +0x02,0xb8,0x73,0x25,0x25,0xfd,0xb8,0x73,0x8b,0xa2,0xa5,0x24,0xfd,0xa2,0xc2, +0x10,0xa5,0x3a,0xfd,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0xe5, +0x39,0xfd,0x8b,0xa2,0xa5,0x39,0xfd,0xa2,0xc2,0x10,0x25,0x39,0xfd,0xa2,0xc2, +0x18,0xb8,0x73,0x25,0x22,0xfd,0xa2,0xc2,0x20,0xb8,0x73,0xa5,0x21,0xfd,0xa2, +0xc2,0x28,0xb8,0x73,0x25,0x21,0xfd,0xa2,0xc2,0x30,0xb8,0x73,0xa5,0x20,0xfd, +0xa2,0xc2,0x38,0xb8,0x73,0x25,0x20,0xfd,0xa2,0xc2,0x40,0xb8,0x73,0xa5,0x1f, +0xfd,0xb8,0x73,0xa2,0xc2,0x48,0x25,0x1f,0xfd,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x00,0xad,0x02,0xc1,0x30,0x43,0xbd,0x03,0xc2,0x2c,0x1c,0xe5,0x30,0xfd, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x39,0x02,0x4b,0xa2,0xa5,0x33,0xfd,0xcb, +0xa2,0x25,0x33,0xfd,0xa2,0xc2,0x14,0xe5,0x32,0xfd,0xa2,0xc2,0x1c,0xbd,0x03, +0xe5,0x1b,0xfd,0xbd,0x03,0xa2,0xc2,0x24,0x65,0x1b,0xfd,0x1d,0xf0,0x00,0x36, +0x41,0x00,0xad,0x02,0x4b,0xb2,0x48,0x03,0x7c,0xc8,0x68,0x44,0x48,0x74,0x4b, +0x66,0x80,0x66,0x10,0xe5,0xfa,0xff,0x0c,0x8a,0x0c,0x4b,0xa5,0x67,0x01,0x5d, +0x0a,0x65,0x2f,0xfd,0x59,0x42,0xa2,0xc2,0x14,0xb2,0xc2,0x38,0xa5,0xf9,0xff, +0xa2,0xc2,0x20,0xb2,0xc2,0x40,0xcd,0x04,0x65,0xb2,0xfc,0xa2,0xc2,0x24,0xb2, +0xc2,0x28,0x65,0xf8,0xff,0xa2,0xc2,0x2c,0xb2,0xc2,0x34,0xa5,0xf7,0xff,0x0c, +0x8a,0x0c,0x4b,0x65,0x64,0x01,0x5d,0x0a,0xe0,0xb4,0x11,0x1c,0x0c,0xa5,0x0d, +0xfd,0xcd,0x04,0x59,0xc2,0xa2,0xc2,0x44,0xb2,0xc2,0x48,0x65,0xaf,0xfc,0x0c, +0x4a,0x0c,0x4b,0x65,0x62,0x01,0xa2,0x62,0x19,0x0c,0x4b,0x0c,0x8a,0xe5,0x61, +0x01,0xbd,0x06,0x4d,0x0a,0x65,0xfe,0x00,0x42,0x62,0x14,0xa2,0xc2,0x54,0xb2, +0xc2,0x58,0xa5,0xf3,0xff,0xa2,0xc2,0x5c,0xb2,0xc2,0x60,0x25,0xf3,0xff,0x1c, +0x8a,0x0c,0x4b,0xa5,0x5f,0x01,0xb8,0x03,0x3d,0x0a,0x65,0x9e,0xfc,0x32,0x62, +0x1a,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x1a,0xb8,0x12,0x65,0x61, +0x01,0x88,0x42,0xa9,0x12,0xc8,0x32,0xad,0x02,0xb2,0x2c,0x12,0xc2,0x2c,0x13, +0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x68,0x02,0x78,0x14, +0x68,0x16,0x48,0x15,0x62,0x26,0x07,0x22,0x23,0x01,0x76,0xa6,0x15,0x40,0x03, +0x8c,0xaf,0xe2,0x44,0xa2,0xd0,0x00,0x07,0x08,0xaf,0xe0,0x0a,0x22,0xd0,0x00, +0x87,0x08,0x30,0x02,0x8d,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x4a,0xb8,0x12,0xa5, +0x5c,0x01,0x4d,0x0a,0xe5,0xd6,0xff,0xbd,0x03,0x49,0x12,0x88,0x82,0xad,0x02, +0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x1a,0xb8,0x12,0xe5,0x5a,0x01, +0xbd,0x03,0xcd,0x04,0xdd,0x05,0xed,0x06,0xa9,0x12,0x88,0x42,0xad,0x02,0xe0, +0x08,0x00,0x1d,0xf0,0x00,0x00,0x00,0x36,0x81,0x00,0x39,0x41,0x0c,0x4a,0xb8, +0x12,0xa5,0x58,0x01,0xb8,0x02,0xb8,0x0b,0x3d,0x0a,0xb8,0x7b,0xe5,0xd6,0xff, +0xbd,0x04,0xcd,0x05,0xdd,0x06,0xed,0x07,0xa8,0x41,0x39,0x12,0x29,0x01,0x88, +0x22,0xf2,0x21,0x10,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x36,0x61,0x00,0x38,0x22, +0x1c,0x4a,0xb8,0x12,0x78,0x02,0x68,0x32,0x78,0x07,0x68,0x06,0x78,0x67,0x68, +0x16,0xe5,0x54,0x01,0x5d,0x0a,0xb8,0x02,0xe5,0xda,0xff,0x59,0x12,0xb8,0x13, +0xa8,0x52,0xe5,0x24,0x01,0xdd,0x0a,0x8f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11, +0x6f,0xe8,0x00,0x22,0x44,0x0c,0x0c,0x11,0xef,0x87,0x01,0x62,0xc0,0x80,0x84, +0x00,0x0f,0xe0,0x7c,0x22,0xa4,0x00,0x00,0x00,0x0c,0x09,0x2f,0x21,0x01,0x22, +0x48,0x00,0x00,0x01,0x70,0x82,0x21,0xcf,0x00,0x04,0x28,0x44,0x0c,0x0c,0x11, +0x76,0xa8,0x1f,0xb8,0x03,0xb8,0x1b,0xb0,0xe9,0x87,0xa8,0x83,0xaf,0xe0,0x0a, +0x22,0xd0,0x30,0x9f,0x08,0xa8,0x1a,0xaf,0xe0,0x0a,0x22,0xc8,0x30,0x97,0x09, +0x90,0xea,0xc6,0x1b,0x99,0xc8,0x83,0x48,0x62,0x2c,0x8a,0xe8,0x44,0xb8,0x34, +0xd9,0x1e,0xc9,0x0e,0x25,0x4d,0x01,0x5d,0x0a,0xbd,0x04,0xa5,0xcf,0xff,0xad, +0x04,0x82,0x24,0x17,0x59,0x34,0xe0,0x08,0x00,0x26,0x56,0x1e,0x58,0x72,0x0c, +0x8a,0xb8,0x15,0x65,0x4b,0x01,0x4d,0x0a,0xa5,0xcb,0xff,0xad,0x05,0xbd,0x01, +0xc8,0x35,0x88,0xa5,0xc8,0x0c,0x49,0x15,0xc8,0x1c,0xe0,0x08,0x00,0xa8,0x82, +0x88,0x5a,0xe0,0x08,0x00,0xa8,0xb3,0x98,0x01,0x99,0x0a,0x28,0x01,0x1d,0xf0, +0x00,0x36,0x41,0x00,0x5c,0x0a,0xb8,0x52,0x65,0x48,0x01,0x7d,0x0a,0xb8,0x02, +0xa5,0xd2,0xff,0xbd,0x03,0xcd,0x04,0xdd,0x05,0xed,0x06,0x79,0x52,0xad,0x02, +0xf8,0x42,0x0c,0x18,0x80,0x00,0xf3,0x82,0x22,0x20,0xf8,0x2f,0xe0,0x08,0x00, +0x1d,0xf0,0x00,0x00,0x36,0x61,0x00,0x1c,0x8a,0xb2,0x22,0x14,0x72,0x22,0x11, +0x39,0x01,0x78,0x17,0xe5,0x44,0x01,0xb2,0x22,0x11,0x3d,0x0a,0xb8,0x0b,0x25, +0xcd,0xff,0xb8,0x01,0xc2,0x22,0x18,0x32,0x62,0x14,0x9c,0x8c,0xf2,0x27,0x38, +0xd2,0x27,0x37,0xd9,0x97,0xcd,0x04,0xdd,0x05,0xed,0x06,0xf9,0xa7,0x82,0x22, +0x17,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0xf2,0x27,0x36,0x92,0x27,0x35,0x99, +0x97,0x86,0xf8,0xff,0x00,0x36,0x41,0x00,0xbd,0x03,0x32,0x22,0x1a,0x38,0x03, +0xa2,0xa0,0x6c,0x38,0x73,0x25,0x40,0x01,0x4d,0x0a,0xb2,0x22,0x1a,0x25,0xd3, +0xff,0x42,0x62,0x1c,0x2c,0xca,0x1c,0x0b,0xa5,0x3b,0x01,0xbd,0x03,0x4d,0x0a, +0x65,0xcf,0xff,0xb2,0x22,0x1c,0x49,0x7b,0x8b,0xab,0xcb,0xbb,0x65,0xcd,0xff, +0xb2,0x22,0x1c,0xa2,0xcb,0x4c,0xb2,0xcb,0x3c,0xa5,0xcc,0xff,0xc2,0x22,0x1c, +0xc8,0x7c,0xd2,0x22,0x23,0xc2,0xcc,0x1c,0xc9,0x6d,0x1d,0xf0,0x00,0x00,0x36, +0x41,0x00,0xad,0x02,0xbd,0x03,0x65,0xe3,0xfc,0x8b,0xa2,0xbd,0x03,0xe5,0xe2, +0xfc,0xa2,0xc2,0x10,0xbd,0x03,0x65,0xe2,0xfc,0xa2,0xc2,0x18,0xbd,0x03,0xe5, +0xe1,0xfc,0xa2,0xc2,0x20,0xbd,0x03,0x25,0xd3,0x00,0xa2,0xc2,0x28,0xbd,0x03, +0xe5,0xe0,0xfc,0xbd,0x03,0xa2,0xc2,0x30,0x65,0xe0,0xfc,0x1c,0x0a,0x1c,0x0b, +0xa5,0x34,0x01,0xa9,0xe2,0x1c,0x0b,0x1c,0x0a,0x25,0x34,0x01,0xa9,0xf2,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x08,0x98,0x22,0x78,0x02,0x1b,0x63, +0x78,0x07,0x38,0x14,0x48,0x77,0x59,0x42,0x59,0x32,0x97,0x26,0x0a,0x89,0x12, +0x1b,0xa9,0xa9,0x22,0x46,0x01,0x00,0x00,0x00,0x0c,0x1b,0xb9,0x12,0x2d,0x03, +0x76,0xa4,0x04,0x82,0x42,0x00,0x1b,0x22,0x1d,0xf0,0x00,0x36,0x41,0x00,0xa8, +0xc2,0x4f,0x04,0x44,0x43,0x44,0x0c,0x0c,0x11,0x0c,0x39,0xcc,0x65,0x88,0x52, +0x78,0x62,0x06,0x01,0x00,0x00,0x88,0x72,0x78,0x82,0x76,0xaa,0x1d,0x40,0x41, +0x8c,0x0f,0xe0,0xe0,0x43,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x7a,0x12, +0x0c,0x10,0x8f,0x10,0xa0,0x48,0x72,0x02,0x14,0x10,0x10,0x03,0x8d,0xcc,0x55, +0x89,0x52,0x79,0x62,0xc6,0x00,0x00,0x89,0x72,0x79,0x82,0x0c,0x12,0x1d,0xf0, +0x00,0x36,0x41,0x00,0xbd,0x03,0x4c,0x0a,0x25,0x2e,0x01,0xb8,0x82,0xb8,0x1b, +0xb8,0xab,0x3d,0x0a,0xb8,0x0b,0x65,0xf1,0xff,0x39,0x92,0x1d,0xf0,0x00,0x36, +0x41,0x00,0xbd,0x03,0xcd,0x04,0xdd,0x05,0x82,0x22,0x61,0xad,0x02,0xe0,0x08, +0x00,0x1d,0xf0,0x00,0x36,0x41,0x00,0xad,0x02,0x25,0xf0,0xfc,0x8b,0xa2,0xe5, +0xef,0xfc,0xa2,0xc2,0x10,0x65,0xef,0xfc,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41, +0x00,0xad,0x02,0x48,0x03,0x4b,0xb2,0x48,0x74,0x25,0xb9,0xff,0x8b,0xa2,0xcb, +0xb2,0xa5,0xb8,0xff,0xa2,0xc2,0x10,0xb2,0xc2,0x14,0x25,0xb8,0xff,0xa2,0xc2, +0x18,0xb2,0xc2,0x1c,0x65,0xb7,0xff,0xa2,0xc2,0x20,0xb2,0xc2,0x28,0xe5,0xb6, +0xff,0xa2,0xc2,0x2c,0xb2,0xc2,0x30,0x65,0xb6,0xff,0xa2,0xc2,0x38,0xb2,0xc2, +0x3c,0xe5,0xb5,0xff,0xa2,0xc2,0x40,0xb2,0xc2,0x44,0x25,0xb5,0xff,0xcd,0x04, +0xa2,0xc2,0x24,0xb2,0xc2,0x34,0x25,0x6e,0xfc,0x1c,0x8a,0x0c,0x4b,0x25,0x21, +0x01,0xb8,0x03,0x3d,0x0a,0xe5,0x5f,0xfc,0x32,0x62,0x12,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0x1c,0x0a,0xb8,0x12,0xe5,0x22,0x01,0x5d,0x0a,0x25,0x97, +0xff,0xad,0x03,0xbd,0x04,0x59,0x12,0xdd,0x02,0xe8,0x02,0x88,0xb2,0x0c,0x0c, +0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x58,0x02,0x78,0x14,0x88, +0x13,0x48,0x12,0x0c,0x03,0x50,0x52,0x41,0x9c,0x95,0x70,0x43,0x8c,0x80,0x03, +0x8c,0xaf,0xe0,0x0a,0x22,0xd0,0x00,0x87,0x08,0x30,0x04,0x8d,0x68,0x02,0x1b, +0x33,0x60,0x62,0x41,0x67,0x33,0xe4,0x1d,0xf0,0x00,0x36,0x81,0x00,0x1c,0x8a, +0xb8,0x12,0x49,0x61,0x39,0x51,0x65,0x1d,0x01,0x4d,0x0a,0x65,0xf1,0xff,0x38, +0x61,0x49,0x12,0xa8,0x54,0x81,0x2c,0x42,0xc8,0x44,0x88,0x98,0x0c,0x0b,0xe0, +0x08,0x00,0xd8,0x02,0x98,0x13,0xd8,0x2d,0xb8,0x12,0xd8,0x2d,0xb8,0x5b,0x0b, +0xdd,0xd0,0xc2,0x21,0xa6,0x1c,0x0b,0x76,0xac,0x05,0x90,0x03,0x8c,0x30,0x0b, +0x8d,0x46,0x00,0x00,0x0c,0x0c,0xe0,0xec,0x11,0xe0,0xed,0xc0,0x76,0xae,0x05, +0x90,0x01,0x8c,0x10,0x0b,0x8d,0x0c,0x0b,0x48,0x17,0x88,0x02,0x38,0x16,0x88, +0x08,0xa8,0x15,0x98,0x48,0xf8,0x88,0xf9,0x41,0x88,0x78,0xa0,0x99,0xa0,0x0b, +0x88,0x8a,0x33,0x8a,0x44,0x76,0xaf,0x03,0xb9,0x09,0x4b,0x99,0xcd,0x05,0xdd, +0x06,0xed,0x07,0xa8,0x51,0xf2,0x03,0x00,0x88,0x41,0x0c,0xfb,0x00,0x08,0x40, +0xb0,0xb0,0xb1,0xb0,0xff,0x10,0xf2,0x43,0x00,0x92,0x04,0x00,0xfd,0x02,0xb0, +0x99,0x10,0x92,0x44,0x00,0xb8,0x12,0x88,0x02,0x89,0x01,0x88,0x92,0xb2,0xcb, +0x10,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x8a,0xb8,0x12,0xa5,0x12, +0x01,0x5d,0x0a,0x25,0x86,0xff,0xd8,0x02,0x88,0x22,0xd8,0x1d,0x59,0x12,0xd7, +0x18,0x13,0x4b,0xad,0x88,0x42,0xb8,0x0d,0x82,0x28,0x1d,0xc8,0x32,0xe0,0x08, +0x00,0x98,0x02,0x98,0x19,0x99,0x22,0x8c,0xc4,0xad,0x03,0x88,0x42,0xbd,0x03, +0x82,0x28,0x1e,0xc8,0x32,0xe0,0x08,0x00,0x1d,0xf0,0x36,0xe1,0x00,0xad,0x02, +0xb8,0x12,0x52,0x61,0x10,0x62,0x61,0x11,0x65,0x8b,0xff,0xe2,0x21,0x11,0x62, +0x22,0x25,0xd2,0x21,0x10,0xcc,0xd6,0x88,0x02,0x88,0x08,0x82,0x08,0x00,0x00, +0x88,0x23,0x89,0xf1,0x06,0x01,0x00,0x92,0x26,0x33,0x99,0xf1,0xcc,0xb6,0x58, +0x02,0x58,0x05,0x52,0x05,0x98,0x00,0x55,0x23,0x86,0x00,0x00,0x52,0x26,0x34, +0xfd,0x07,0x92,0x21,0x20,0xc2,0x21,0x1d,0xb2,0x21,0x1e,0x82,0x21,0x1c,0xa2, +0x21,0x1f,0xa9,0x31,0x89,0x01,0xb9,0x21,0xc9,0x11,0x99,0x41,0x72,0x21,0x24, +0x98,0xf1,0x79,0x81,0xc2,0x21,0x22,0xb2,0x21,0x23,0x82,0x21,0x21,0x89,0x51, +0xb9,0x71,0xc9,0x61,0xbd,0x03,0xa8,0x06,0xcd,0x04,0xa8,0x1a,0xa9,0x91,0x99, +0xa1,0x59,0xb1,0x82,0x22,0x2f,0xad,0x02,0xe0,0x08,0x00,0x6d,0x0a,0xac,0xf5, +0x58,0x22,0x98,0x57,0xa8,0x13,0xa9,0xc1,0x99,0xd1,0x1c,0x0a,0xb8,0x15,0x65, +0x05,0x01,0xb8,0x05,0xa9,0xe1,0xb8,0x0b,0xe5,0x80,0xff,0xc8,0xd1,0xed,0x05, +0xdd,0x06,0xb8,0xc1,0x98,0x05,0xf8,0xe1,0xf9,0x15,0x99,0x01,0x88,0x25,0xad, +0x0b,0xe0,0x08,0x00,0xa8,0x17,0xb8,0x13,0x31,0xc6,0x41,0xc8,0x07,0x38,0xb3, +0xe0,0xcc,0x11,0xe0,0x03,0x00,0x8c,0xc4,0xa8,0x14,0xb8,0x12,0xc8,0x04,0xb8, +0xbb,0xe0,0xcc,0x11,0xe0,0x03,0x00,0x2d,0x06,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0x68,0x12,0x78,0x13,0x48,0x02,0x0c,0x03,0x40,0x42,0x41,0x8c,0xe4,0x70, +0x03,0x8c,0x30,0x06,0x8d,0x58,0x02,0x1b,0x33,0x50,0x52,0x41,0x57,0x33,0xef, +0x1d,0xf0,0x00,0x00,0x36,0x81,0x00,0x39,0x41,0x4c,0xca,0xb8,0x22,0xe5,0xfd, +0x00,0x3d,0x0a,0xb8,0x12,0x25,0x73,0xff,0x98,0x02,0x39,0x22,0xa6,0x19,0x63, +0x98,0xf2,0xa6,0x19,0x0c,0xa8,0x12,0x0b,0xb9,0xb9,0xf2,0xa9,0x51,0x0c,0x1b, +0x86,0x04,0x00,0xc8,0x12,0xc9,0x51,0x8c,0x96,0xd8,0x1c,0xe8,0x06,0xd8,0x6d, +0x0c,0x1b,0xe7,0x3d,0x01,0x0c,0x0b,0xbc,0xfb,0xb8,0x15,0xd8,0x51,0x92,0x23, +0x12,0xc8,0x0d,0xd8,0x1d,0xe2,0xa0,0xc0,0xea,0xdd,0xd0,0x40,0x0c,0xc8,0x7c, +0xcf,0x00,0x84,0x28,0x44,0x0c,0x0c,0x11,0xa6,0x1c,0x16,0x76,0xac,0x0d,0xb0, +0x83,0x8c,0xaf,0xe0,0x0a,0x22,0xc8,0x20,0x97,0x08,0x30,0x89,0x8d,0x38,0x22, +0xe8,0x12,0xe9,0x51,0x52,0xc3,0x44,0xc6,0x00,0x00,0xf8,0x12,0xf9,0x51,0xbd, +0x04,0xcd,0x05,0xdd,0x06,0xed,0x07,0xa8,0x41,0x29,0x01,0x98,0x51,0x99,0x11, +0x88,0xc2,0xf2,0x21,0x10,0xe0,0x08,0x00,0x2d,0x0a,0x1d,0xf0,0x00,0x00,0x36, +0x41,0x00,0xbd,0x03,0x4c,0xca,0x25,0xf4,0x00,0x3d,0x0a,0xb8,0x92,0xa5,0xc9, +0xff,0x39,0xa2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x02,0xbd,0x03, +0xa5,0x9a,0xfc,0xbd,0x03,0x8b,0xa2,0x25,0x9a,0xfc,0x1c,0x0a,0x1c,0x0b,0x65, +0xee,0x00,0xa9,0x42,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0xcd,0x04,0xdd,0x05, +0xed,0x06,0xfd,0x07,0x88,0x42,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00, +0x36,0x41,0x00,0xbd,0x03,0xcd,0x04,0xdd,0x05,0xed,0x06,0xfd,0x07,0x88,0x92, +0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0xca,0xb8, +0x12,0xe5,0xed,0x00,0x6d,0x0a,0xb8,0x02,0xa5,0x5a,0xff,0x38,0x13,0x69,0x12, +0x7d,0x03,0xbc,0xa5,0x66,0x25,0x10,0xb8,0x16,0xd8,0x02,0xc8,0x14,0xd8,0x1d, +0xa8,0x32,0xd8,0x0d,0xe5,0xbe,0xff,0x48,0x12,0x8b,0xf2,0x98,0x14,0xf0,0x80, +0x0c,0xe8,0x04,0x4f,0x01,0x04,0x29,0x44,0x0c,0x0c,0x11,0xe0,0xe2,0x41,0x76, +0x9e,0x10,0x90,0x03,0x9c,0x70,0xc3,0x8c,0xaf,0xe0,0x0a,0x22,0xf8,0x30,0x26, +0x09,0x30,0xc3,0x8d,0x1d,0xf0,0x00,0x36,0x41,0x00,0x68,0x04,0x0c,0x4a,0xb8, +0x32,0x25,0xe8,0x00,0x7d,0x0a,0xbd,0x02,0xc8,0x92,0xe5,0x56,0xff,0xa2,0xc2, +0x14,0xcd,0x06,0x88,0x62,0x58,0x07,0x79,0x32,0xb8,0x15,0xe0,0x08,0x00,0xa8, +0x72,0xc8,0x15,0xd8,0x04,0xbd,0x0c,0x25,0xb9,0xff,0x0c,0x09,0xb2,0xc2,0x20, +0xb0,0x80,0x0c,0x60,0xa2,0x41,0x4f,0x01,0x04,0x29,0x44,0x0c,0x0c,0x11,0x76, +0x9a,0x16,0xe8,0x15,0xd8,0x14,0xe0,0x29,0x97,0xd0,0xe9,0x87,0xef,0x87,0x03, +0x62,0xf8,0x30,0x26,0x09,0x90,0xec,0xc6,0x1b,0x99,0x1d,0xf0,0x00,0x36,0x61, +0x00,0xad,0x03,0x25,0xc7,0x00,0xed,0x05,0x0c,0x0f,0xc8,0x82,0xb8,0x52,0x0c, +0x0d,0xd9,0x21,0xd9,0x11,0xd9,0x01,0x98,0x62,0x99,0x31,0x88,0x22,0xdd,0x04, +0xe0,0x08,0x00,0xc8,0x52,0xd8,0x82,0xbd,0x0a,0x88,0x32,0xa8,0x13,0xe0,0x08, +0x00,0xc8,0x52,0xd8,0x82,0x88,0x42,0x4d,0x0a,0xbd,0x04,0xa8,0x13,0xe0,0x08, +0x00,0x6f,0xf4,0x00,0x22,0x44,0x0c,0x0c,0x11,0x6f,0xe8,0x02,0x22,0x44,0x0c, +0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x00,0x01,0x00,0x4f,0x00,0x28,0x48,0x44, +0x0c,0x0c,0x11,0x1d,0xf0,0x00,0x00,0x00,0x36,0xe1,0x00,0xad,0x02,0x82,0x22, +0x1b,0xb2,0x22,0x1c,0x58,0x08,0x68,0x28,0x58,0x05,0x88,0x48,0x89,0xe1,0x25, +0x9a,0xff,0xf2,0x22,0x1c,0xcc,0x74,0xb2,0x22,0x1b,0xb8,0x0b,0x0c,0x0a,0xa9, +0x1b,0xcc,0x35,0x0c,0x0b,0x46,0x00,0x00,0xb8,0x3f,0xa8,0x2f,0x41,0x71,0x41, +0xc8,0x33,0x82,0x24,0x80,0xc8,0x1c,0xe0,0x08,0x00,0xb2,0x22,0x1c,0xa2,0x22, +0x13,0xb8,0x2b,0x25,0xa9,0x00,0x0c,0x0f,0xe8,0x03,0x4d,0x0a,0xdd,0x0a,0xc2, +0x22,0x1c,0x7d,0x0a,0xb8,0xec,0xa8,0xb2,0xc8,0x5c,0x59,0x01,0x25,0xd8,0xff, +0x82,0x22,0x20,0xe2,0x22,0x1a,0x0c,0x0f,0xe8,0x0e,0xf9,0x48,0xe8,0x7e,0xe2, +0x61,0x10,0x16,0x15,0x13,0xb2,0x22,0x1c,0xa2,0x22,0x14,0xb8,0x3b,0xa5,0xa5, +0x00,0x0c,0x0f,0xe8,0x03,0xdd,0x0a,0xc2,0x22,0x1c,0xa9,0xf1,0xb8,0xfc,0xa8, +0xc2,0xc8,0x5c,0x59,0x01,0xe5,0xd4,0xff,0xdd,0x07,0xf2,0x22,0x1c,0x88,0xf2, +0xe8,0xff,0xa2,0x2f,0x10,0xb2,0x2f,0x11,0xc2,0x2f,0x12,0xf8,0xef,0xe9,0x01, +0x89,0x11,0x98,0x08,0x99,0x21,0x88,0x18,0xe8,0xf1,0xe0,0x08,0x00,0xa1,0xb4, +0x40,0xa8,0xfa,0x8c,0x1a,0xe0,0x0a,0x00,0xb2,0x22,0x1b,0xb2,0x2b,0x32,0x16, +0xdb,0x0b,0xdd,0x07,0x0c,0x0f,0xe8,0x03,0xc2,0x22,0x1c,0xa8,0xd2,0xb2,0x2c, +0x16,0xc8,0x5c,0x59,0x01,0x25,0xd0,0xff,0x92,0x22,0x1a,0x98,0x29,0x98,0x19, +0xd8,0x59,0xda,0xd6,0xd2,0x0d,0x00,0x00,0xdd,0x23,0xe6,0x1d,0x02,0x06,0xe5, +0x00,0x98,0xf1,0xb2,0x22,0x1e,0xa8,0x42,0x79,0x0b,0x88,0x8a,0x99,0x1b,0xe0, +0x08,0x00,0xb2,0xc1,0x30,0xc8,0x17,0xd2,0x22,0x1c,0x81,0x3a,0x41,0xf2,0x22, +0x1a,0x82,0x28,0x7e,0xe8,0x0f,0xa8,0x8d,0xf8,0x1f,0xd2,0x2d,0x16,0xa8,0x1a, +0xd8,0x1d,0xf2,0x2f,0x1e,0xe0,0x08,0x00,0xa8,0x12,0xcd,0x07,0xd2,0x22,0x1f, +0xb2,0x22,0x1c,0xe8,0x03,0xb8,0x7b,0x25,0x83,0xff,0xe2,0x22,0x23,0xf2,0x22, +0x1c,0xd2,0x22,0x20,0xc8,0x7f,0xc9,0x4d,0xc9,0x2e,0xb2,0x2f,0x13,0xa2,0x22, +0x16,0xc8,0x43,0xd8,0x33,0x88,0x03,0x89,0x0e,0x25,0x7e,0xff,0xa1,0x8b,0x40, +0xa8,0xfa,0x8c,0x1a,0xe0,0x0a,0x00,0xb2,0x22,0x1c,0xa2,0x22,0x15,0xb2,0x2b, +0x13,0x65,0x96,0x00,0xbd,0x07,0xcd,0x0a,0x4d,0x0a,0x88,0x92,0xa2,0x22,0x1c, +0xdd,0x08,0xe8,0x08,0x88,0x18,0xa2,0x2a,0x14,0xe0,0x08,0x00,0x71,0x80,0x40, +0xb8,0xf1,0x92,0x22,0x1e,0xa8,0x52,0x49,0x09,0x88,0x8a,0xb9,0x19,0xe0,0x08, +0x00,0x8c,0x65,0xc2,0x22,0x1b,0xc2,0x2c,0x32,0xdc,0xcc,0x71,0x79,0x40,0xd2, +0x21,0x10,0x0f,0x20,0xa1,0x42,0xe0,0x00,0x07,0x08,0x76,0xad,0x0c,0xe2,0x22, +0x1c,0xe2,0x2e,0x14,0xe8,0x1e,0x90,0x2e,0xc6,0x1b,0x99,0xdd,0x04,0x0c,0x0f, +0xa8,0xa2,0xc2,0x22,0x1c,0xe8,0x03,0xb2,0x2c,0x16,0xc8,0x5c,0x59,0x01,0xa5, +0xc0,0xff,0xbd,0x0a,0xd2,0x22,0x1c,0x81,0x06,0x41,0xe2,0x22,0x1a,0x82,0x28, +0x7e,0xf8,0x1e,0xc2,0x2d,0x19,0xe8,0x0e,0xa8,0x8d,0xf2,0x2f,0x1e,0xd2,0x2d, +0x16,0xa8,0x1a,0xd8,0x1d,0xb9,0x0c,0xb2,0xc3,0x20,0xc8,0x14,0xe0,0x08,0x00, +0x8c,0xf5,0xa8,0x02,0xcd,0x04,0xd2,0x22,0x20,0xb2,0x22,0x1c,0xe8,0x03,0xb8, +0x7b,0x65,0x75,0xff,0x92,0x22,0x1b,0x98,0x09,0x98,0x19,0x16,0x39,0x04,0xd2, +0x22,0x21,0x26,0x29,0x22,0xa8,0x5d,0xa8,0x0a,0xa0,0xa2,0x41,0x2f,0x74,0x30, +0x22,0xe0,0x00,0x07,0x08,0x0c,0x09,0x76,0x9a,0x0b,0xb2,0x22,0x21,0xb8,0x5b, +0xb8,0x1b,0x90,0x2b,0xc6,0x1b,0x99,0xd2,0x22,0x21,0xa8,0x32,0xb2,0x22,0x1c, +0xc8,0xa3,0xb2,0x2b,0x19,0x49,0x0d,0xb8,0x0b,0xa5,0x60,0xff,0xa8,0xf7,0x9c, +0x0a,0xe0,0x0a,0x00,0xc6,0x02,0x00,0xb2,0x22,0x1c,0xa2,0x2b,0x15,0xb2,0x2b, +0x16,0xe5,0xb4,0xff,0x16,0x05,0x07,0xc2,0x22,0x1b,0xc8,0x0c,0xc8,0x1c,0xac, +0xdc,0xa2,0x22,0x1d,0xd8,0x0a,0xd8,0x1d,0xd8,0x9d,0xd0,0xd6,0x90,0xd2,0x9d, +0x00,0x9c,0xcd,0xc2,0x22,0x1c,0xd8,0x53,0xe2,0x22,0x20,0xd8,0x1d,0xe8,0x3e, +0xf2,0x2c,0x14,0xc8,0x7c,0xf8,0x1f,0xe8,0x1e,0xb8,0x8c,0xc8,0xac,0x69,0x01, +0xa5,0x58,0xff,0xcd,0x04,0x82,0x22,0x10,0xe2,0x22,0x1f,0xf2,0x22,0x1c,0xe8, +0x0e,0xb8,0x9f,0xad,0x08,0xf8,0x7f,0x88,0x38,0xd2,0xcf,0x1c,0xe0,0x08,0x00, +0xcd,0x04,0x82,0x22,0x11,0xe2,0x22,0x1f,0xf2,0x22,0x1c,0xe8,0x0e,0xb8,0xaf, +0xad,0x08,0xf8,0x7f,0x88,0x38,0xd2,0xcf,0x24,0xe0,0x08,0x00,0xc6,0x08,0x00, +0xf2,0x21,0x10,0x0f,0x20,0xa1,0x42,0xe0,0x00,0x07,0x08,0x76,0xaf,0x15,0xa2, +0x22,0x1c,0xa8,0x9a,0xa8,0x1a,0x90,0x2a,0xc6,0x82,0x22,0x1c,0x88,0xa8,0x88, +0x18,0x90,0x28,0xc6,0x1b,0x99,0x92,0x22,0x1a,0x99,0xd1,0x98,0x19,0x92,0x61, +0x11,0x9c,0xf5,0xa8,0xa9,0xa2,0x9a,0x07,0x92,0x61,0x11,0xdc,0x5a,0xb2,0x22, +0x1c,0xa8,0x63,0xb8,0x9b,0x65,0xa9,0xff,0xb2,0x22,0x1c,0xa8,0xdb,0xb8,0xab, +0xa5,0xa8,0xff,0x06,0x14,0x00,0xd8,0x14,0xe8,0xd1,0xc2,0x22,0x1c,0xf2,0x21, +0x11,0xa8,0x63,0x81,0xad,0x40,0xa8,0x1a,0x82,0x28,0x7f,0xf2,0x2f,0x19,0xb8, +0x9c,0xe8,0x0e,0xc2,0x2c,0x16,0xe8,0x7e,0xf8,0x2f,0xb8,0x1b,0xc8,0x1c,0xe0, +0x08,0x00,0xd8,0x14,0xf2,0x22,0x1a,0x81,0xa4,0x40,0xb2,0x22,0x1c,0x82,0x28, +0x7f,0xc8,0x5b,0xe8,0x0f,0xa8,0xdb,0xf8,0x1f,0xa8,0x1a,0xc8,0x1c,0xe8,0x7e, +0xb8,0xab,0xf2,0x2f,0x19,0xb8,0x1b,0xf8,0x2f,0xe0,0x08,0x00,0xa8,0xf7,0x8c, +0x1a,0xe0,0x0a,0x00,0x88,0xe1,0x0c,0x0d,0x58,0x53,0xe8,0x63,0xb8,0x13,0x92, +0x22,0x1c,0xa2,0x22,0x12,0xf8,0xd9,0xc2,0x29,0x18,0x69,0x21,0x59,0x01,0xd9, +0x11,0x89,0x31,0x88,0xe9,0xd9,0x51,0x89,0x41,0x52,0x29,0x14,0x59,0x61,0xd2, +0x29,0x16,0xd9,0x71,0xdd,0x04,0x92,0x29,0x1a,0x99,0x81,0x65,0x91,0xff,0xb8, +0x63,0xe8,0x53,0xd2,0x22,0x1c,0x52,0x22,0x12,0xc2,0x2d,0x16,0x58,0x15,0xd2, +0x2d,0x14,0xa9,0x73,0xa2,0x22,0x19,0x88,0x05,0x89,0x93,0x58,0x15,0x25,0x43, +0xff,0x92,0x22,0x1b,0x82,0x29,0x2f,0x8c,0x98,0xbd,0x05,0xa2,0x22,0x18,0x65, +0x40,0xff,0x92,0x22,0x1b,0xa8,0x09,0xa8,0x1a,0x16,0x0a,0x05,0xa2,0x22,0x12, +0xcd,0x04,0xb2,0x22,0x1c,0xd8,0x13,0xb2,0x2b,0x17,0xe5,0x3b,0xff,0x0c,0x0e, +0xf8,0x53,0xa8,0xe2,0xb2,0x22,0x1c,0x0c,0x18,0xd2,0x2b,0x17,0xb2,0x2b,0x18, +0xcd,0x0d,0x89,0x01,0xa5,0x9b,0xff,0xa8,0x72,0xe2,0x22,0x1c,0xd2,0x22,0x22, +0x82,0x2e,0x1a,0x49,0x0d,0xf8,0x53,0xf9,0x3d,0x89,0x2d,0xe2,0x2e,0x17,0xe9, +0x1d,0xc8,0x13,0xc9,0x4d,0x65,0x36,0xff,0xa8,0xf7,0x8c,0x1a,0xe0,0x0a,0x00, +0x92,0x22,0x1b,0xa8,0xd9,0x9c,0x0a,0xa8,0x82,0xb8,0x0a,0xb8,0x2b,0x8c,0x8b, +0xcd,0x04,0xb8,0x13,0x25,0x73,0xff,0x92,0x22,0x1b,0xc8,0x99,0x8c,0xbc,0xa8, +0x62,0xd8,0x0a,0xd8,0x1d,0x8c,0x3d,0xb8,0x13,0x25,0x82,0xff,0xc8,0x23,0xb8, +0x13,0x88,0x22,0xb8,0x1b,0xad,0x08,0x88,0x18,0xc8,0x1c,0xe0,0x08,0x00,0x1d, +0xf0,0x00,0x00,0x0c,0xfa,0xc8,0x79,0xe2,0x22,0x23,0xca,0xc6,0x98,0x6e,0xc2, +0x0c,0x00,0x98,0x19,0x00,0xcc,0x23,0xa6,0x1c,0x20,0xd2,0x21,0x10,0xa6,0x1d, +0x0a,0x76,0xad,0x04,0xa2,0x49,0x00,0x1b,0x99,0xe2,0x22,0x23,0x91,0x52,0x40, +0x99,0x2e,0x82,0x22,0x20,0xf2,0x22,0x1c,0x99,0x48,0xc6,0x21,0xff,0xb2,0x21, +0x10,0xa6,0x1b,0x0a,0x76,0xab,0x04,0xa2,0x49,0x00,0x1b,0x99,0xe2,0x22,0x23, +0x91,0x4a,0x40,0x99,0x2e,0xc6,0xf6,0xff,0x00,0x00,0x00,0x36,0x21,0x01,0x52, +0x61,0x15,0x72,0x61,0x18,0x49,0xf1,0x32,0x61,0x17,0x22,0x61,0x1b,0x32,0x21, +0x1b,0x69,0xe1,0xad,0x03,0x68,0x83,0xb8,0x93,0x88,0x06,0x68,0x16,0x98,0xe8, +0x92,0x61,0x10,0x68,0xa6,0x88,0xf8,0x82,0x61,0x13,0x68,0x06,0x25,0x5d,0xff, +0x48,0x93,0x92,0x21,0x17,0xe8,0x33,0xb8,0x49,0xa8,0x19,0xd8,0x0e,0xc2,0xc4, +0x10,0x88,0xf4,0x82,0x61,0x14,0xc9,0xc1,0xf8,0x0d,0xa8,0x1a,0xb8,0x1b,0x98, +0x09,0x92,0x61,0x11,0xb9,0xa1,0xa9,0x51,0xb8,0xe1,0xf9,0x3e,0xfd,0x04,0xd8, +0x1d,0xd9,0x2e,0x16,0x8b,0x07,0x52,0xc4,0x28,0x72,0x21,0x17,0xa8,0x63,0x78, +0x67,0xe8,0xea,0xc8,0x07,0xe2,0x61,0x1a,0x22,0xcc,0xfc,0xc7,0xb2,0x17,0x0c, +0x0b,0xe0,0xa2,0x11,0x98,0x17,0x1b,0x22,0xaa,0x99,0xb9,0x09,0x88,0x07,0x4b, +0xaa,0x87,0x32,0xf0,0xf8,0x93,0xa8,0x63,0x22,0x21,0x17,0xc2,0xcf,0x20,0xd8, +0xef,0xb8,0xba,0xd9,0xb1,0xc9,0x41,0x88,0x72,0x89,0x81,0x28,0x82,0x96,0x4b, +0x01,0xb8,0x9f,0xc8,0xe1,0x0c,0x0d,0xe5,0x4f,0xff,0x98,0x41,0xe2,0x21,0x1a, +0x98,0x19,0x99,0x91,0xc6,0x00,0x00,0xa8,0xe1,0xa9,0x91,0xbd,0x0e,0xa8,0x73, +0xcd,0x02,0xdd,0x06,0x25,0x4b,0xff,0xc8,0x53,0xb8,0x0c,0xd8,0x0b,0xd9,0x3c, +0xb8,0x1b,0xb9,0x2c,0x46,0x04,0x00,0x0c,0x05,0x0c,0x07,0x0c,0x02,0x0c,0x0f, +0x0c,0x0e,0xe9,0x81,0xf9,0x91,0x29,0xb1,0x0c,0x02,0x82,0x21,0x17,0xb8,0xe1, +0x88,0x38,0x92,0x21,0x15,0x16,0xf8,0x17,0x16,0xc9,0x17,0xa8,0xc1,0xa2,0x61, +0x12,0x9c,0xeb,0xa8,0x63,0xc8,0xba,0xd6,0x8c,0x01,0xc8,0xf1,0x0c,0x0d,0xbd, +0x0c,0xe5,0x49,0xff,0xd2,0x21,0x15,0x8c,0x9d,0xbd,0x0d,0xcd,0x0d,0xa8,0x63, +0x0c,0x1d,0xe5,0x48,0xff,0x79,0x61,0x29,0x71,0xe8,0x03,0x59,0xd1,0xe6,0x1e, +0x02,0x46,0x51,0x00,0x0c,0x05,0x0c,0x02,0x78,0x51,0x0c,0x09,0x0c,0x0a,0xa2, +0x61,0x19,0x92,0x61,0x16,0xc2,0x21,0x10,0xb2,0x21,0x16,0xd2,0x21,0x13,0xc7, +0xab,0x14,0xd8,0x0d,0x1b,0xfb,0x27,0x9d,0x0d,0x60,0x61,0x21,0xe2,0x21,0x13, +0xf2,0x61,0x16,0x4b,0xee,0xe2,0x61,0x13,0xa8,0x13,0xb8,0xf1,0xcd,0x02,0xdd, +0x04,0xe8,0x93,0xfd,0x06,0x8b,0xee,0xa5,0x87,0xff,0xa2,0x21,0x15,0x20,0xf0, +0x14,0xdc,0x1f,0x82,0x21,0x18,0x98,0xa1,0x8c,0xa8,0x7c,0xf8,0x52,0x09,0x00, +0x1b,0x99,0x99,0xa1,0x80,0x55,0x30,0xbc,0xca,0xa8,0x23,0xb2,0x21,0x15,0xcd, +0x02,0xd8,0xc1,0xe8,0x93,0xfd,0x06,0xe2,0xce,0x18,0xa5,0x84,0xff,0xa8,0x33, +0xbd,0x04,0xc8,0xc1,0x0c,0x1d,0xed,0x07,0xfd,0x06,0x25,0x82,0xff,0xa2,0x21, +0x17,0xa8,0x3a,0xac,0x7a,0xc2,0x21,0x14,0xdd,0x07,0xed,0x02,0xb2,0x21,0x17, +0x82,0x2a,0x1f,0xb8,0x5b,0xe0,0x08,0x00,0xc6,0x04,0x00,0xc2,0x21,0x18,0x8c, +0xdc,0xa8,0x33,0xbd,0x04,0x0c,0x0c,0x0c,0x0d,0xed,0x07,0xfd,0x06,0x25,0x7f, +0xff,0xbd,0x04,0xc2,0x21,0x12,0xdd,0x02,0x50,0xe0,0x04,0xa2,0x21,0x11,0x82, +0x21,0x17,0xa8,0x0a,0x88,0x28,0x89,0x01,0x88,0x58,0xf2,0x21,0x14,0xe0,0x08, +0x00,0xb2,0x21,0x18,0xc8,0xe1,0x16,0x7b,0x04,0x16,0x4c,0x04,0xa8,0x43,0xb8, +0x91,0xcd,0x02,0xd8,0xd1,0xe8,0x93,0xfd,0x06,0xe2,0xce,0x30,0xe5,0x7c,0xff, +0xb8,0x61,0xc8,0x71,0xdd,0x04,0xe8,0xd1,0x88,0x73,0x69,0x01,0xad,0x08,0x88, +0xb8,0xfd,0x02,0xe0,0x08,0x00,0xa8,0x53,0xb8,0xd1,0x0c,0x0c,0x0c,0x0d,0xe8, +0xb1,0xfd,0x06,0x25,0x79,0xff,0xa2,0x21,0x19,0xb8,0x81,0x98,0xb1,0xb8,0x1b, +0x98,0x09,0xba,0xaa,0x99,0x0a,0x20,0xc0,0x44,0xcc,0x8c,0xa1,0x15,0x3f,0xa8, +0xfa,0x8c,0x1a,0xe0,0x0a,0x00,0x72,0xc7,0x10,0x50,0x51,0x21,0xb8,0x03,0xc2, +0x21,0x19,0x1b,0x22,0x4b,0xcc,0xc2,0x61,0x19,0xb7,0xa2,0x02,0x46,0xb2,0xff, +0x1d,0xf0,0x0c,0x0d,0xd2,0x61,0x12,0xc6,0x9f,0xff,0x36,0x41,0x00,0x39,0x02, +0xe0,0xa3,0x11,0x1c,0x0b,0xa5,0xe1,0xfb,0xa9,0x12,0x1d,0xf0,0x00,0x00,0x00, +0x36,0x41,0x00,0x58,0x02,0x78,0x13,0xef,0xe8,0x00,0x22,0x44,0x0c,0x0c,0x11, +0xcf,0x00,0x84,0x28,0x44,0x0c,0x0c,0x11,0x48,0x12,0x0c,0x03,0x50,0x52,0x41, +0x9c,0x65,0x70,0x03,0x8c,0xaf,0xe0,0x0a,0x22,0xd0,0x00,0x87,0x08,0x30,0x04, +0x8d,0x68,0x02,0x1b,0x33,0x60,0x62,0x41,0x67,0x33,0xe7,0x1d,0xf0,0x00,0x00, +0x36,0x41,0x00,0xbd,0x03,0x3c,0x8a,0xe5,0x60,0x00,0x3d,0x0a,0xb8,0xf2,0x65, +0x54,0x06,0x32,0x62,0x10,0x1d,0xf0,0x00,0x00,0x36,0x81,0x00,0x79,0x31,0x3c, +0xca,0x49,0x01,0x69,0x21,0x39,0x41,0x59,0x11,0x38,0x12,0x58,0x02,0x68,0x41, +0x48,0x25,0xbd,0x03,0x58,0x35,0x25,0x5e,0x00,0x7d,0x0a,0xb8,0x02,0xe5,0xcb, +0xfe,0xa8,0x02,0x79,0x12,0xa8,0x2a,0x98,0x62,0x99,0x7a,0x88,0x06,0x87,0x95, +0x28,0x59,0x33,0xc8,0x84,0xc9,0x03,0xb8,0x94,0xb9,0x13,0x58,0xa4,0xfd,0x02, +0xb8,0x01,0xc8,0x11,0xd8,0x21,0xe8,0x31,0x59,0x23,0xa8,0x12,0x92,0x94,0x18, +0x88,0xc2,0x92,0x5a,0x08,0xad,0x06,0xe0,0x08,0x00,0x1d,0xf0,0xf0,0xb5,0x11, +0xb9,0x33,0xa8,0x84,0xe5,0x69,0x01,0xa9,0x03,0xa8,0x94,0xa5,0x69,0x01,0xa9, +0x13,0xa8,0xa4,0x25,0x69,0x01,0x5d,0x0a,0x46,0xf1,0xff,0x00,0x00,0x36,0xc1, +0x00,0xad,0x02,0xb8,0xa2,0x25,0x63,0xff,0x0c,0x0f,0xa8,0x22,0xd8,0x33,0xe8, +0x23,0x88,0xb2,0x58,0x92,0xc8,0xa2,0x58,0x25,0xb8,0x7c,0x48,0x58,0xc8,0x8c, +0x88,0x08,0x58,0x15,0x88,0x08,0x52,0x95,0x00,0x89,0x01,0xe5,0x56,0xff,0xb2, +0xc1,0x30,0x98,0x43,0x0c,0x17,0xd8,0xa2,0xf8,0x92,0xc8,0x33,0x61,0x60,0x3f, +0xa8,0x63,0x82,0x26,0x7f,0xa8,0x1a,0xc8,0x1c,0xe8,0x0f,0xd8,0x7d,0xf8,0x1f, +0xd8,0x1d,0xf2,0x2f,0x20,0x79,0x09,0xe0,0x08,0x00,0x98,0x92,0xb8,0x19,0xb8, +0xab,0xc8,0x73,0xb2,0x9b,0x0c,0xa9,0x0c,0x16,0x2b,0x04,0x0c,0x0f,0xa8,0x32, +0xd8,0x33,0xb8,0xa2,0xe8,0xb2,0xc2,0x2b,0x11,0xe8,0x0e,0xb2,0x2b,0x10,0xe8, +0x0e,0xe9,0x01,0x0c,0x0e,0xa5,0x51,0xff,0xb2,0xc1,0x30,0x82,0x26,0x7f,0xd8, +0xa2,0xf8,0x92,0xa8,0x53,0xc8,0x33,0xa8,0x1a,0xc8,0x1c,0xe8,0x0f,0xd2,0x2d, +0x10,0xf8,0x1f,0xd8,0x1d,0xf2,0x2f,0x21,0xe0,0x08,0x00,0x98,0x92,0x0c,0x0a, +0x46,0x00,0x00,0x0c,0xfa,0x7c,0xfb,0x68,0x09,0x98,0x53,0x68,0x76,0x98,0x19, +0x76,0xa6,0x10,0x82,0x09,0x00,0xb0,0x88,0x30,0x80,0x8a,0x20,0x80,0x80,0x34, +0x82,0x49,0x00,0x1b,0x99,0x98,0xb2,0x0c,0x1d,0xb8,0xe9,0x98,0x09,0xb0,0xbd, +0x93,0xc2,0x99,0x08,0xa2,0x99,0x09,0xc2,0xcc,0xfd,0xc0,0xc0,0xf4,0xb6,0x2c, +0x0e,0xdc,0xfa,0xc2,0x99,0x0b,0xcc,0x6c,0xcc,0x4b,0xd2,0x99,0x0a,0x16,0x8d, +0x12,0xdc,0x0a,0x16,0x9b,0x13,0xcc,0xba,0x9c,0xbb,0xe8,0x92,0xe8,0x1e,0xe8, +0xae,0xe2,0x9e,0x0a,0x9c,0x0e,0xb8,0xa2,0xa8,0xab,0xb8,0x7b,0x65,0x46,0xff, +0xb8,0xa2,0xa8,0xbb,0xb8,0x8b,0xe5,0x45,0xff,0x0c,0x19,0x0c,0x08,0xa8,0x52, +0xc8,0xc3,0x68,0xa2,0xd8,0x33,0xb8,0xc6,0xe8,0xa6,0xf8,0xb6,0x59,0x21,0x49, +0x31,0x89,0x01,0x99,0x11,0x98,0xe6,0x99,0x41,0x89,0x51,0x89,0x61,0x89,0x71, +0x62,0x26,0x12,0x69,0x81,0xe5,0x34,0xff,0xa9,0x83,0xa8,0x52,0xb1,0x7e,0x3e, +0xa8,0x1a,0xb8,0xfb,0xa8,0x0a,0xa9,0x93,0x8c,0x1b,0xe0,0x0b,0x00,0xb8,0xb2, +0xb8,0x0b,0xd8,0xa2,0xb2,0x9b,0x09,0xa8,0x5d,0xcc,0xab,0xb1,0x80,0x3e,0xe5, +0x22,0x00,0xc6,0x01,0x00,0x00,0x00,0x00,0xb8,0xcd,0xe5,0x3f,0xff,0x98,0xb2, +0x98,0x09,0xc2,0x99,0x0a,0x9c,0x1c,0xa8,0x02,0xb8,0x0a,0xb8,0x1b,0x8c,0x9b, +0xb8,0xa2,0xb8,0x5b,0x25,0x2c,0xff,0x98,0xb2,0x98,0x09,0xa2,0x99,0x08,0x26, +0x4a,0x27,0x48,0xb3,0x66,0x3a,0x16,0xbd,0x04,0xa8,0x42,0xf8,0xa2,0xc8,0x33, +0xf2,0x2f,0x12,0xd8,0xa3,0x8b,0xff,0xed,0x0f,0x25,0x1f,0xff,0xc6,0x01,0x00, +0xad,0x04,0xb1,0x6c,0x3e,0xe5,0x1d,0x00,0x98,0xb2,0x98,0x09,0xa2,0x99,0x09, +0xd8,0xa2,0x16,0x4a,0x05,0xc8,0xc2,0xb8,0x5d,0x88,0x72,0xb8,0x1b,0xad,0x08, +0x88,0x18,0xc8,0x1c,0xe0,0x08,0x00,0xb8,0xa2,0xa8,0xc2,0xb8,0x5b,0x25,0x39, +0xff,0xb8,0xa2,0xc8,0xb3,0xa8,0xfb,0xb8,0x5b,0x65,0x18,0xff,0xc6,0x01,0x00, +0x00,0x00,0x00,0xbd,0x04,0xe5,0x37,0xff,0xc8,0xb2,0xc8,0x0c,0xc2,0x9c,0x0b, +0x8c,0xfc,0xa8,0x12,0xd8,0x0a,0xd8,0x2d,0x8c,0x7d,0xb8,0xa2,0xc8,0x33,0xb8, +0xfb,0xa5,0x13,0xff,0xb8,0xa2,0xa8,0x03,0xb8,0xfb,0xa5,0x35,0xff,0x1d,0xf0, +0x48,0xb3,0xc2,0x99,0x0a,0xa8,0xfd,0x16,0xbc,0xfc,0xcd,0x04,0xb8,0x5d,0x25, +0x14,0xff,0x86,0xf1,0xff,0xa8,0xa2,0x0c,0x0b,0xa8,0x6a,0x10,0x11,0x20,0xe5, +0x15,0x00,0xa8,0xa2,0xb1,0x4a,0x3e,0xa8,0x5a,0x10,0x11,0x20,0xe5,0x14,0x00, +0x98,0xa2,0x0c,0xfa,0x92,0x29,0x12,0x79,0x83,0x98,0x39,0x76,0xa6,0x04,0xa2, +0x49,0x00,0x1b,0x99,0x46,0xc5,0xff,0x00,0x00,0x00,0x36,0x41,0x00,0x2c,0x0a, +0xb8,0x32,0x65,0x31,0x00,0x5d,0x0a,0xb8,0x22,0x25,0xa2,0xfe,0xad,0x04,0x59, +0x32,0xbd,0x02,0x0c,0x19,0x88,0x52,0x90,0x00,0xf3,0xe0,0x08,0x00,0xbd,0x03, +0x88,0x62,0xad,0x02,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0x58,0x13,0x68, +0x22,0x38,0x12,0x48,0x06,0x68,0x16,0x48,0x74,0x68,0x16,0x76,0xa4,0x18,0x30, +0x08,0x0c,0x50,0x43,0x8c,0x2f,0xc3,0x44,0xa2,0xe0,0x10,0x0f,0x08,0xaf,0xe0, +0x0a,0x22,0xf8,0x00,0x0e,0x09,0x30,0x03,0x8d,0x1d,0xf0,0x00,0x36,0xa1,0x00, +0x69,0xb1,0x1c,0x4a,0xb8,0x42,0xcd,0x05,0x39,0x41,0x58,0x32,0xc9,0x81,0x88, +0x05,0x58,0x15,0x98,0xe8,0x99,0x91,0x58,0xa5,0x88,0xf8,0x89,0xa1,0x58,0x05, +0xe5,0x29,0x00,0xb8,0x32,0xb8,0x1b,0xb8,0xab,0x7d,0x0a,0xb8,0x0b,0x25,0x36, +0xff,0x79,0x42,0xf8,0x22,0xc8,0x47,0xe8,0x0f,0xc9,0x61,0x88,0x0e,0xcc,0x34, +0x0c,0x06,0x46,0x00,0x00,0x68,0x14,0x89,0x3f,0xe8,0x1e,0xe9,0x2f,0xd8,0x02, +0xe6,0x1d,0x02,0x46,0x20,0x00,0x0c,0x03,0x0c,0x04,0xa2,0xd6,0xfe,0x8b,0xb7, +0xb9,0x71,0xa9,0x51,0xc8,0x91,0xd8,0xa1,0xc7,0xa3,0x0f,0xd8,0x0d,0xe8,0xa1, +0x47,0x9d,0x08,0x50,0x51,0x21,0x1b,0x33,0x4b,0xee,0xe9,0xa1,0xa8,0x12,0xb8, +0x81,0xcd,0x04,0xdd,0x07,0xe8,0x71,0xfd,0x05,0xe5,0x33,0xff,0x9c,0xc6,0xa8, +0x22,0xbd,0x07,0x0c,0x0c,0x0c,0x0d,0xe8,0x61,0xfd,0x05,0x65,0x31,0xff,0x4b, +0x66,0xf8,0x61,0x88,0x51,0xf8,0x0f,0x4b,0x88,0x89,0x51,0xf2,0x68,0x7f,0x88, +0xb1,0x9c,0x38,0xbd,0x07,0x0c,0x0c,0xdd,0x04,0xa8,0x41,0x0c,0x0e,0xa8,0x0a, +0x89,0x01,0x88,0x58,0x0c,0x0f,0xe0,0x08,0x00,0x40,0xb0,0x44,0xcc,0x8b,0xa1, +0xef,0x3d,0xa8,0xfa,0x8c,0x1a,0xe0,0x0a,0x00,0xb8,0x02,0x1b,0x44,0xb7,0x24, +0x8a,0x1d,0xf0,0x36,0x61,0x00,0x68,0x12,0x0c,0x05,0x39,0x11,0x0f,0x82,0x88, +0x04,0x44,0x0c,0x0c,0x11,0x48,0x02,0x4b,0x71,0x40,0x42,0x41,0x2f,0xe0,0x80, +0x04,0x44,0x0c,0x0c,0x11,0x8c,0xb4,0x30,0x06,0x8d,0x88,0x02,0x1b,0x55,0x80, +0x82,0x41,0x87,0x35,0xf2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x48,0x12, +0x0f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0x38,0x02,0x20,0x80,0x0c,0x52,0xa0, +0x1f,0x6f,0x64,0x9e,0x43,0x42,0x29,0x04,0x00,0x76,0x93,0x0a,0x40,0x43,0x8c, +0xaf,0xe0,0x0a,0x22,0x02,0x08,0x89,0x00,0xaf,0xe0,0x0a,0x22,0x44,0x48,0x00, +0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x30,0x20,0x01,0xaf,0xe0,0x0a,0x22,0x50,0x30, +0x18,0x01,0x0f,0x20,0xa1,0x42,0xa4,0x30,0xa0,0x01,0x8d,0x01,0x90,0xc8,0x46, +0x28,0x01,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0x2c,0x4a,0xa5,0x15,0x00,0x3d, +0x0a,0xb8,0xc2,0x25,0x12,0x06,0x39,0xd2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41, +0x00,0x41,0xc2,0x3d,0x42,0x24,0x10,0x51,0x5f,0x3e,0x48,0x04,0x50,0x44,0xa0, +0x42,0x24,0x7f,0x48,0x04,0x48,0xa4,0x48,0x04,0x40,0x42,0x21,0x76,0xa4,0x05, +0x30,0x03,0x8c,0x30,0x02,0x8d,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x03,0x5c,0x8a, +0xa5,0x11,0x00,0x3d,0x0a,0xb8,0x02,0x65,0x13,0x06,0x39,0x52,0x1d,0xf0,0x00, +0x00,0x00,0x36,0x41,0x00,0x0c,0x17,0xa1,0x04,0x3e,0x41,0xb1,0x3d,0xa0,0xa2, +0xa0,0xa2,0x2a,0x7f,0x28,0xe4,0xa8,0x0a,0x52,0x22,0x10,0x48,0x1a,0x98,0x22, +0xb2,0x24,0x15,0x32,0x24,0x13,0x48,0x02,0x3a,0x39,0xba,0xb9,0xb2,0x0b,0x00, +0x32,0x03,0x00,0x00,0xbb,0x23,0x00,0x33,0x23,0xe6,0x23,0x01,0x0c,0x07,0x0c, +0x38,0x16,0x4b,0x07,0x0c,0x06,0x8c,0x57,0xd8,0x42,0x0c,0x1c,0xd0,0x6c,0x93, +0xbd,0x06,0x0c,0x27,0xf2,0x2a,0x12,0x0b,0xe5,0xf8,0x6f,0x69,0x04,0xf0,0xf9, +0x90,0xf2,0x9f,0x00,0x16,0x4e,0x06,0x6d,0x05,0x59,0x14,0x0c,0x05,0x66,0x0f, +0x03,0x59,0x14,0x6d,0x05,0x59,0x24,0x8c,0x26,0x0c,0x13,0x39,0x24,0x52,0x22, +0x28,0x59,0x34,0x58,0xa2,0xb8,0xc2,0x26,0x15,0x01,0x8d,0x05,0x58,0xb2,0x82, +0x54,0x08,0x88,0x82,0x26,0x15,0x01,0x7d,0x05,0x72,0x54,0x09,0x0c,0x15,0xcc, +0x68,0xa2,0x22,0x39,0x0c,0x09,0xa0,0x59,0x83,0x52,0x54,0x0a,0x0c,0x15,0xcc, +0x6b,0xd2,0x22,0x39,0x0c,0x0c,0xd0,0x5c,0x83,0x52,0x54,0x0b,0x0c,0x02,0x1d, +0xf0,0x0c,0x0b,0x8c,0x67,0xe8,0x42,0xcc,0x0e,0x8c,0x05,0x0c,0x1b,0x6d,0x0b, +0x86,0xe1,0xff,0x8c,0x5b,0x6d,0x07,0x5d,0x07,0xc6,0xe4,0xff,0x6d,0x08,0x5d, +0x08,0x06,0xe3,0xff,0x36,0x41,0x00,0x66,0xb3,0x08,0xad,0x02,0x25,0x24,0xfb, +0x2d,0x0a,0x1d,0xf0,0x66,0x43,0x08,0xad,0x02,0xa5,0x1c,0xfb,0x2d,0x0a,0x1d, +0xf0,0xad,0x02,0x65,0x15,0xfb,0x2d,0x0a,0x1d,0xf0,0x36,0x41,0x00,0xbd,0x02, +0x0c,0x4a,0x0c,0x2c,0xa5,0x09,0xfb,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xad, +0x02,0xbd,0x03,0x0c,0x1c,0xa5,0x08,0xfb,0x2d,0x0a,0x1d,0xf0,0x36,0x41,0x00, +0xb1,0x04,0x3e,0xd1,0xc7,0x3d,0x81,0xc8,0x3d,0xe1,0x6a,0x3d,0xf1,0xc6,0x3d, +0xe8,0xee,0x20,0xf8,0x83,0x3c,0x78,0x76,0xa8,0x24,0xa2,0x0b,0x80,0x92,0x0b, +0x81,0x00,0xaa,0x23,0x00,0x99,0x23,0xa7,0x29,0x13,0xc2,0x1b,0x41,0x92,0x1b, +0x3f,0xd7,0x1c,0x0a,0x88,0x0f,0xea,0x99,0xca,0x88,0x82,0x98,0x00,0x89,0x09, +0x8b,0xbb,0xad,0x02,0x65,0xea,0xff,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x4a,0x0c, +0x0b,0x0c,0x0c,0x25,0x03,0xfb,0x2d,0x0a,0x1d,0xf0,0x36,0x41,0x00,0xa2,0xa0, +0xe8,0x0c,0x4b,0xa5,0xf5,0xff,0x21,0x54,0x3d,0x0c,0x4b,0xa9,0xe2,0x2c,0x0a, +0xe5,0xf4,0xff,0x28,0xe2,0xa9,0x02,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00, +0x81,0x4e,0x3d,0x82,0x28,0x1a,0xe0,0x08,0x00,0x2d,0x0a,0x1d,0xf0,0x36,0x41, +0x00,0x31,0x4a,0x3d,0x0c,0x02,0x22,0x63,0x17,0x22,0x63,0x18,0x1d,0xf0,0x36, +0x41,0x00,0xcc,0x72,0x8c,0x53,0x4c,0xfa,0x0c,0x1b,0xe5,0x65,0x00,0x1d,0xf0, +0x36,0x41,0x00,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x76,0xa2,0x0b,0x58, +0x04,0x28,0x03,0x4b,0x44,0x5a,0x22,0x29,0x03,0x4b,0x33,0x1d,0xf0,0x36,0x21, +0x01,0x9d,0x02,0x71,0x3a,0x3d,0x0c,0x0a,0xf2,0x27,0x12,0xbd,0x06,0xc8,0x1f, +0x0c,0x06,0xa6,0x1c,0x06,0x8c,0x32,0x0c,0x18,0x50,0xa8,0x93,0xd2,0x27,0x10, +0xd2,0x61,0x14,0x28,0x5d,0xe8,0x3d,0xd8,0x4d,0xe8,0xce,0xe9,0xe1,0x8c,0x6a, +0x66,0x2c,0x04,0x0c,0x1a,0x30,0x6a,0x93,0xa8,0x0f,0xd8,0xfd,0xd2,0x61,0x15, +0x9c,0xbf,0xe2,0x9a,0x09,0x0c,0x1d,0xcc,0xfe,0x82,0x9a,0x0b,0xcc,0xa8,0xe8, +0xef,0xcc,0x6e,0x82,0x9a,0x0a,0x0c,0x0f,0x80,0xdf,0x83,0xed,0x0d,0x46,0x00, +0x00,0x0c,0x0e,0x0c,0x1d,0xe9,0xd1,0xc9,0xb1,0xb2,0x61,0x13,0xf2,0x9a,0x08, +0x92,0x61,0x17,0xf2,0xcf,0xfd,0xf0,0xf0,0xf4,0xb6,0x2f,0x08,0x88,0x1a,0xcc, +0x38,0x0c,0x0a,0xe0,0xda,0x83,0xf2,0x27,0x13,0xd9,0xc1,0xcc,0x2f,0x0c,0x12, +0x1d,0xf0,0xa2,0x21,0x14,0xbd,0x02,0x92,0x27,0x15,0x0c,0x18,0x80,0x00,0xf3, +0x1b,0x99,0x92,0x67,0x15,0xe5,0xd6,0xff,0x59,0xb2,0xb2,0x21,0x17,0xb9,0x52, +0x30,0x3b,0x83,0x39,0x72,0x16,0x84,0x05,0xc2,0x21,0x13,0x16,0x2c,0x05,0xbd, +0x04,0xd2,0x27,0x10,0xa2,0x21,0x13,0xd8,0x1d,0xd9,0x82,0xd9,0xc2,0x49,0x92, +0xa9,0xd2,0xe5,0xd1,0xff,0x92,0x27,0x10,0xe8,0x39,0xe8,0xce,0xe8,0x0e,0xf1, +0x5c,0x3d,0xe8,0x0e,0x98,0x19,0xf0,0xee,0xc0,0xcc,0x1e,0xf0,0x99,0x11,0xf8, +0xb1,0x99,0xe2,0x82,0x22,0x14,0x92,0x21,0x13,0x99,0xf2,0x88,0x18,0x82,0x61, +0x16,0x0c,0x09,0xa6,0x1f,0x09,0xa2,0x21,0x17,0x8c,0x3a,0x0c,0x1b,0x50,0x9b, +0x93,0x92,0x61,0x19,0xc6,0x05,0x00,0x0c,0x0d,0x0c,0x0e,0x0c,0x0f,0xf9,0x82, +0xf9,0x92,0xf9,0xc2,0xf9,0xd2,0xf9,0xe2,0xf9,0xf2,0xe2,0x61,0x19,0xd2,0x61, +0x16,0x32,0x61,0x1a,0x59,0x41,0x0c,0x0d,0x98,0x22,0xb2,0x21,0x19,0x9c,0xb9, +0xf8,0x09,0x0c,0x08,0x2f,0x7e,0x2a,0x22,0x32,0x0a,0x01,0x00,0x92,0x29,0x01, +0x76,0xaf,0x0a,0xa0,0x04,0x03,0xa0,0xa0,0x34,0xa2,0x49,0x00,0x1b,0x99,0xd9, +0x02,0x16,0x5b,0x22,0x52,0x27,0x10,0x58,0x35,0x38,0xd5,0xad,0x05,0xbd,0x03, +0x25,0xc7,0xff,0x88,0xc1,0xcc,0x38,0x0c,0x0b,0x46,0x00,0x00,0xb8,0x85,0xf8, +0xf7,0xb9,0x51,0x8c,0x1f,0xe0,0x0f,0x00,0xcd,0x04,0xd8,0x53,0xa8,0x05,0xb8, +0x1d,0xa8,0x1a,0xd8,0x0d,0x25,0xae,0xfe,0xe2,0x27,0x12,0xe8,0xee,0x16,0xfe, +0x05,0xa2,0x22,0x12,0xa5,0xbe,0xff,0xb8,0xb5,0xa2,0x61,0x11,0x88,0x15,0xa2, +0x22,0x12,0xc8,0x58,0xd8,0x88,0x88,0x38,0xa8,0x1a,0xe0,0x08,0x00,0xbd,0x0a, +0xa9,0x61,0x88,0x15,0x92,0x22,0x12,0xc8,0x58,0xd8,0x88,0x88,0x48,0xa8,0x19, +0xe0,0x08,0x00,0xb8,0x61,0x6f,0xf6,0x00,0x22,0x44,0x0c,0x0c,0x11,0x6f,0xf4, +0x02,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa4,0x00,0x01,0x00,0xa2, +0x22,0x12,0x2f,0x01,0x28,0x48,0x44,0x0c,0x0c,0x11,0x92,0x61,0x18,0x65,0xb9, +0xff,0xa2,0x61,0x12,0xc6,0x03,0x00,0xc1,0xca,0x3c,0x0c,0x0d,0x0c,0x0e,0xe2, +0x61,0x12,0xd2,0x61,0x11,0xc2,0x61,0x18,0xb1,0xc6,0x3c,0x88,0xe5,0x0c,0x1f, +0x98,0x48,0xa8,0x08,0xf9,0x09,0xf9,0x88,0xa5,0xb3,0xff,0xa8,0xe5,0xb1,0xc1, +0x3c,0xa8,0xba,0x25,0xb3,0xff,0xb8,0xc1,0x16,0xab,0x0a,0xa8,0x55,0xb8,0x03, +0xc8,0x23,0xdd,0x04,0xe8,0x51,0x65,0xa4,0xff,0xf8,0xf7,0x8c,0x1f,0xe0,0x0f, +0x00,0xa8,0x65,0xb8,0x23,0xa5,0xa0,0xff,0xc2,0x27,0x12,0xd8,0xe5,0xc8,0xec, +0xa9,0x3d,0xbc,0x8c,0xc2,0x21,0x18,0x81,0xff,0x3c,0xb8,0x1a,0xd2,0x27,0x10, +0xa8,0xd5,0xd8,0x3d,0x82,0x28,0x7f,0xd8,0xcd,0xa8,0x6a,0x98,0x2d,0x82,0x28, +0x22,0x92,0x29,0x11,0xa8,0x1a,0x98,0x19,0xd8,0x0d,0x92,0x29,0x44,0xd8,0x7d, +0xc0,0xc9,0x73,0xc2,0x61,0x18,0xe0,0x08,0x00,0xe8,0xd5,0xf8,0xe5,0xe8,0x6e, +0xe9,0x3f,0xa8,0x45,0xc8,0x53,0xb8,0x43,0xc8,0x1c,0xe5,0x98,0xff,0xa8,0x75, +0xc1,0xee,0x3c,0xb8,0xe5,0xc2,0x2c,0x7f,0xe5,0x71,0xff,0xd2,0x27,0x12,0xd8, +0x0d,0xd2,0x9d,0x08,0xd2,0xcd,0xfd,0xd0,0xd0,0xf4,0xb6,0x2d,0x03,0xe8,0xd1, +0x9c,0xce,0xe2,0x21,0x13,0x88,0x85,0xb2,0x27,0x10,0xa8,0x03,0xc8,0x33,0xa8, +0x0a,0xc8,0x1c,0xb8,0x3b,0xdd,0x08,0xb2,0x2b,0x11,0x88,0x68,0xb8,0x1b,0xe0, +0x08,0x00,0xb2,0x27,0x12,0xb8,0xeb,0x16,0x2b,0x06,0xc8,0xe5,0xc8,0x8c,0xc9, +0xf1,0x66,0x1c,0x12,0xd8,0xe1,0xd8,0x2d,0xe8,0x43,0xd8,0xbd,0xe8,0x0e,0xd8, +0xbd,0xe7,0x3d,0x03,0x0c,0x0e,0xe9,0xf1,0x88,0x15,0xa2,0x22,0x14,0x88,0x58, +0xf2,0x21,0x18,0x92,0x28,0x1c,0x99,0x71,0xf2,0x68,0x1c,0xe5,0xa7,0xff,0x0c, +0x1d,0x92,0x21,0x12,0x88,0x15,0xe8,0xe5,0xb8,0x58,0xc8,0x88,0xf8,0xbe,0xe8, +0x9e,0xf8,0x1f,0x99,0x21,0xd9,0x01,0xd2,0x21,0x11,0xd9,0x11,0x98,0x68,0x99, +0x31,0x88,0x28,0xd8,0xf1,0xe0,0x08,0x00,0x98,0x15,0x88,0x71,0x98,0x59,0xa9, +0xb5,0x82,0x69,0x1c,0xf8,0xf7,0x32,0x21,0x1a,0x8c,0x1f,0xe0,0x0f,0x00,0x92, +0x27,0x12,0x98,0x09,0x92,0x99,0x08,0x8c,0x19,0x66,0x39,0x17,0xc2,0x22,0x14, +0xa8,0x25,0xd8,0x0c,0xc8,0x1c,0xa8,0x3a,0xbd,0x0c,0xa5,0x90,0xfe,0x92,0x27, +0x12,0x98,0x09,0x92,0x99,0x08,0x66,0x29,0x03,0xa8,0xd1,0x8c,0xea,0xa8,0x35, +0x0c,0x0c,0x0c,0x0d,0xe2,0x22,0x14,0x0c,0x0f,0xbd,0x0e,0xe5,0x5b,0xff,0xf8, +0xf7,0x58,0x41,0x8c,0x1f,0xe0,0x0f,0x00,0x0c,0x09,0x49,0x91,0xb8,0xb1,0x59, +0x41,0xa6,0x1b,0x09,0xc2,0x21,0x17,0x8c,0x3c,0x0c,0x1d,0x50,0x9d,0x93,0x16, +0x09,0x0d,0x52,0x27,0x10,0x58,0x45,0x42,0x25,0x10,0xad,0x05,0xbd,0x04,0x65, +0x57,0xff,0xf2,0x27,0x12,0x16,0x76,0x27,0x88,0x0f,0x88,0x08,0x16,0x08,0x27, +0x39,0x81,0x16,0x56,0x0a,0xb2,0x27,0x10,0xc1,0xa0,0x3c,0xb8,0x0b,0xc0,0xbb, +0xa0,0xb2,0x2b,0x7f,0xb8,0x0b,0xb8,0x1b,0xa8,0x2f,0x38,0xeb,0xc8,0xfb,0xc2, +0x61,0x10,0x66,0x6a,0x08,0x32,0x2b,0x10,0xc2,0x2b,0x11,0xc2,0x61,0x10,0xb2, +0x22,0x10,0xcd,0x03,0xad,0x0b,0x65,0x4f,0xff,0xb2,0x22,0x11,0xcd,0x03,0xad, +0x0b,0xa5,0x4e,0xff,0xd2,0x27,0x10,0xd8,0x4d,0xd8,0xfd,0xd8,0x2d,0x32,0x25, +0x12,0xd8,0xad,0xe1,0x44,0x3c,0xd2,0x9d,0x0b,0xe9,0xa3,0x9c,0x0d,0xd2,0xc3, +0x28,0xa8,0x45,0xe2,0x22,0x10,0xf2,0x22,0x11,0xbd,0x0e,0xcd,0x0f,0x65,0x51, +0xff,0xb2,0x25,0x10,0x0c,0x8a,0xb8,0x7b,0x65,0xb0,0xff,0xb8,0xf5,0xb8,0x2b, +0xb8,0xab,0x3d,0x0a,0xb8,0x0b,0x65,0x49,0xff,0xe2,0x25,0x10,0xc2,0x21,0x17, +0x39,0x4e,0xd8,0x44,0xa8,0x05,0xb8,0x1d,0xa8,0x1a,0xd8,0x0d,0xa5,0x81,0xfe, +0xa8,0x25,0xc8,0x44,0xb8,0x54,0xc8,0x1c,0xe5,0x7b,0xff,0xf8,0xf7,0x8c,0x1f, +0xe0,0x0f,0x00,0xf2,0x27,0x12,0xd2,0x2f,0x32,0xec,0xfd,0x0c,0x0b,0x06,0x0c, +0x00,0x8c,0xa5,0xe2,0x21,0x17,0x8c,0x5e,0xbd,0x0e,0xad,0x05,0x25,0x97,0xff, +0xf2,0x21,0x19,0x9c,0x3f,0xb2,0x22,0x14,0xc2,0x22,0x10,0xa2,0x27,0x10,0xd2, +0x27,0x12,0xa8,0x4a,0xd8,0x6d,0xa8,0x6a,0xa5,0xbb,0xfe,0x0c,0x02,0x1d,0xf0, +0xb8,0x85,0xb2,0x2b,0x16,0xc8,0x0f,0xd2,0x25,0x11,0xc8,0x1c,0xb9,0x3d,0x8c, +0x2c,0xd8,0x91,0xcc,0x3d,0x0c,0x0e,0xe2,0x61,0x16,0xb2,0x25,0x10,0x0c,0x4a, +0xb8,0x7b,0x65,0xa7,0xff,0x38,0x81,0xb8,0xf5,0xa9,0xa1,0xc8,0x2b,0xb8,0x0b, +0xc8,0xac,0xe5,0xb4,0x05,0xa8,0x75,0xb2,0x25,0x11,0xe2,0x21,0x16,0xd2,0x25, +0x10,0xc8,0xa1,0xfd,0x06,0xc9,0x1d,0xdd,0x03,0xc2,0x21,0x17,0x65,0x16,0xff, +0xf8,0xf7,0x8c,0x1f,0xe0,0x0f,0x00,0xb8,0xf5,0x0c,0xf3,0xb8,0x0b,0xf8,0xb5, +0xb8,0x7b,0xf8,0x1f,0x76,0xab,0x04,0x32,0x4f,0x00,0x1b,0xff,0xac,0x96,0xd8, +0x91,0x0c,0x0c,0x8c,0x6d,0xf2,0x21,0x13,0x0c,0x1e,0xf0,0xce,0x93,0xa8,0x85, +0xd1,0x4d,0x3c,0xb2,0x25,0x12,0xd2,0x2d,0x7f,0xe5,0xc4,0xfe,0x32,0x27,0x10, +0x38,0x43,0x38,0xc3,0x38,0x13,0x06,0x07,0x00,0x00,0x00,0x00,0x2f,0x20,0x01, +0x22,0x44,0x0c,0x0c,0x11,0x38,0x34,0x0c,0x0d,0x38,0x13,0x76,0xab,0x08,0x88, +0x34,0x88,0x18,0xd0,0x28,0xc6,0x1b,0xdd,0xf8,0xf7,0x8c,0x1f,0xe0,0x0f,0x00, +0xbd,0x03,0xe8,0x41,0xc8,0x34,0xa8,0x14,0x88,0x95,0xa8,0x0a,0xdd,0x08,0x88, +0x68,0xc8,0x1c,0xe0,0x08,0x00,0x16,0x56,0xf1,0x0c,0x03,0x92,0x27,0x12,0x62, +0x25,0x12,0x98,0xf9,0x68,0x76,0x8c,0xd9,0x92,0x21,0x15,0x98,0x29,0x98,0xa9, +0x92,0x99,0x08,0x0c,0x18,0x90,0x38,0x93,0xb2,0x22,0x13,0xc2,0x21,0x10,0xad, +0x0b,0x65,0x35,0xff,0x9c,0xf3,0xa8,0x35,0xc2,0x22,0x13,0xb8,0x54,0xc8,0x1c, +0xe5,0x67,0xff,0x66,0x16,0x11,0xd2,0x21,0x15,0xd8,0x2d,0xe8,0x54,0xd8,0xbd, +0xe8,0x0e,0xd8,0xbd,0xe7,0x3d,0x01,0x0c,0x06,0x82,0x27,0x10,0xe2,0x27,0x12, +0x88,0x38,0x0c,0x0f,0xf2,0x68,0x10,0xe8,0xfe,0x8c,0xde,0xcd,0x06,0xa8,0x15, +0xd2,0x25,0x12,0xb2,0x22,0x13,0xd8,0x9d,0x65,0xb3,0xfe,0xf8,0xf7,0x8c,0x1f, +0xe0,0x0f,0x00,0xf2,0x27,0x12,0xe2,0x2f,0x11,0x8c,0xbe,0xc2,0x22,0x13,0xa8, +0xa5,0xbd,0x0c,0xe5,0xab,0xfe,0xf2,0x27,0x12,0x88,0x9f,0xdc,0xf8,0x98,0x0f, +0x92,0x99,0x0b,0xdc,0x89,0xa8,0xff,0xdc,0x4a,0xb8,0x55,0xc8,0xab,0x0c,0x1a, +0xcc,0x5c,0xd8,0x9b,0xe6,0x1d,0x01,0x0c,0x0a,0xcc,0x3a,0x0c,0x0a,0x46,0x00, +0x00,0x0c,0x1a,0x16,0x4a,0xe6,0xa8,0x55,0x0c,0x0c,0x0c,0x0d,0xe2,0x22,0x13, +0x0c,0x0f,0xbd,0x0e,0x25,0x31,0xff,0x46,0x94,0xff,0x0c,0x0e,0xe9,0x81,0x46, +0x62,0xff,0x00,0x36,0x41,0x00,0x76,0xa4,0x07,0x58,0x03,0x59,0x02,0x4b,0x33, +0x4b,0x22,0x1d,0xf0,0x36,0x81,0x00,0xbd,0x03,0x39,0x51,0xad,0x02,0x25,0xc9, +0xfd,0x3d,0x0a,0x56,0xca,0x08,0x41,0xa8,0x3b,0x51,0x35,0x3c,0xa8,0x34,0x0c, +0x09,0x99,0x7a,0x66,0x22,0x2f,0xad,0x02,0xb2,0xc1,0x14,0x65,0x05,0xfd,0x3d, +0x0a,0xec,0x2a,0x98,0x51,0x96,0xe9,0x01,0xe6,0x79,0x1b,0x50,0xa9,0xa0,0xa2, +0x2a,0x87,0x96,0x2a,0x01,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0x88,0x04,0xd1,0x0c, +0x3c,0x82,0x28,0x10,0x0c,0x0e,0xe0,0x08,0x00,0x4c,0xf9,0x97,0x92,0x48,0x28, +0x51,0xf6,0x32,0x1c,0x88,0x34,0xad,0x02,0x22,0x68,0x43,0x25,0x07,0x00,0xed, +0x02,0x1c,0x9a,0x0c,0x0b,0x88,0x04,0x0c,0x4c,0x82,0x28,0x10,0xd2,0xa2,0x00, +0xe0,0x08,0x00,0xa2,0x25,0x85,0xe5,0xca,0x00,0x2d,0x0a,0x66,0x0a,0x1f,0x0c, +0x89,0xc6,0x03,0x00,0x00,0x00,0x00,0xcd,0x02,0x0c,0x1a,0x88,0xff,0x1c,0x9b, +0xe0,0x08,0x00,0x0c,0x79,0x26,0x79,0x03,0x7c,0xf2,0x1d,0xf0,0x2d,0x03,0x1d, +0xf0,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0xd1,0xe4,0x3b,0xed,0x01,0x88,0x04,0x0c, +0x19,0x82,0x28,0x10,0x99,0x01,0xe0,0x08,0x00,0xa8,0x01,0xf8,0x04,0x16,0x9a, +0xfc,0xed,0x02,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0x82,0x2f,0x10,0xd1,0xdc,0x3b, +0xe0,0x08,0x00,0x06,0xf0,0xff,0x36,0x41,0x00,0x3d,0x02,0xd1,0x76,0x3b,0x0c, +0x09,0x82,0x2d,0x13,0xb2,0x2d,0x12,0xd2,0x2d,0x10,0xb8,0x0b,0xa8,0x2d,0xc8, +0x7b,0x99,0x0a,0x66,0x18,0x0b,0xb8,0x7b,0xc7,0x1b,0x06,0xa8,0x3d,0xa8,0x2a, +0xe5,0xfd,0xfb,0x0c,0x0b,0x0c,0x12,0x30,0x2b,0x83,0x1d,0xf0,0x00,0x36,0x41, +0x00,0x31,0x6a,0x3b,0xf8,0x33,0x8c,0x72,0x88,0x3f,0x8c,0x38,0x25,0xa1,0xfb, +0xf8,0x33,0x1c,0x9a,0x0c,0x4c,0xd2,0xa3,0x00,0x88,0x03,0x0c,0x19,0x0c,0x0e, +0x0c,0x0b,0xb9,0x7f,0x20,0xe9,0x83,0x82,0x28,0x10,0xe9,0x3f,0xe0,0x08,0x00, +0x1d,0xf0,0x00,0x00,0x00,0x36,0xa1,0x00,0xcd,0x03,0x0c,0x07,0x51,0x5c,0x3b, +0xb6,0x22,0x06,0x72,0x65,0x13,0x0c,0x12,0x1d,0xf0,0xb2,0x25,0x14,0xc9,0x01, +0x81,0xa1,0x3b,0xa2,0x25,0x10,0x0c,0x13,0x30,0x00,0xf3,0x98,0x5a,0x88,0xa8, +0x99,0x11,0xe0,0x08,0x00,0x1c,0xca,0xb2,0x25,0x10,0x25,0x78,0xff,0xa9,0x21, +0xbd,0x02,0x25,0x7f,0x05,0xb8,0x11,0xa8,0x21,0xa2,0x65,0x10,0x48,0x4a,0x68, +0x3a,0x25,0xe0,0xfd,0xa8,0x01,0x30,0x00,0xf3,0xcc,0x3a,0xb2,0x25,0x13,0xcc, +0x3b,0x0c,0x1a,0xe5,0xf3,0xff,0xc8,0x01,0x0c,0x1a,0xcc,0x6c,0xe2,0x25,0x13, +0x0c,0x0d,0xe0,0xad,0x93,0x0c,0x1f,0xa0,0xaf,0x93,0x25,0xd8,0xfd,0x72,0x65, +0x15,0xa8,0x76,0xe5,0xd4,0xfd,0xa8,0x84,0x25,0xd1,0xfd,0xa8,0x44,0xa9,0x31, +0x98,0x8a,0x88,0xba,0x99,0x41,0xe0,0x08,0x00,0xc8,0x41,0xb8,0x31,0xa8,0x54, +0xa9,0x51,0x88,0xba,0x39,0xab,0x79,0x9b,0xc9,0x8b,0x98,0x8a,0x99,0x61,0xe0, +0x08,0x00,0xc8,0x61,0xb8,0x51,0xa8,0x36,0xa9,0x71,0x88,0xba,0x39,0xab,0x79, +0x9b,0xc9,0x8b,0x98,0x8a,0x99,0x81,0xe0,0x08,0x00,0xf8,0x81,0xe8,0x71,0xd1, +0x7e,0x3b,0xa8,0x74,0xd0,0xd2,0xa0,0xa8,0x6a,0x79,0x9e,0x39,0xae,0xd2,0x2d, +0x7f,0xf9,0x8e,0xd8,0x0d,0xe2,0x25,0x10,0xd8,0x0d,0xe8,0x1e,0xe9,0xca,0xd9, +0xda,0x25,0xa1,0xfd,0xa8,0x74,0xa8,0x7a,0x65,0xc6,0xfd,0x21,0x78,0x3b,0xa8, +0x14,0xb2,0x22,0x7f,0xe5,0xc4,0xfd,0xb2,0x22,0x7f,0xa8,0x16,0x65,0xc4,0xfd, +0x2f,0x20,0x01,0x22,0x44,0x0c,0x0c,0x11,0x0c,0xfc,0x98,0xb4,0xd2,0x25,0x10, +0xb8,0xc4,0xd8,0x4d,0xa2,0x26,0x11,0xd8,0xfd,0xa8,0x1a,0xd8,0x0d,0xb8,0x1b, +0xd8,0x7d,0x92,0x29,0x01,0x76,0xad,0x0a,0x30,0x0b,0x8d,0x30,0x0a,0x8d,0xc2, +0x49,0x00,0x1b,0x99,0xe2,0x25,0x12,0x0c,0x02,0xe8,0x0e,0x32,0x65,0x13,0x79, +0x6e,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xad,0x04,0x88,0x03,0x0c,0x0b, +0xe0,0x08,0x00,0x3d,0x0a,0x98,0x14,0x99,0x22,0xa9,0x12,0xa5,0x6e,0xff,0x30, +0xaa,0xc0,0xa9,0x02,0x2d,0x03,0x1d,0xf0,0x36,0x61,0x00,0x29,0x01,0xa5,0x6e, +0xff,0x65,0x6d,0xff,0x2d,0x0a,0x25,0x6b,0xff,0x81,0x03,0x3b,0xa2,0x68,0x12, +0xa5,0x69,0xff,0x4d,0x0a,0x78,0x01,0x61,0x9e,0x3b,0x0c,0x03,0x52,0xc6,0x18, +0xad,0x03,0x25,0x64,0xff,0x1c,0xca,0xbd,0x04,0xa5,0x62,0xff,0xa9,0x11,0xbd, +0x03,0xa5,0x69,0x05,0xa1,0xf9,0x3a,0x98,0x11,0x92,0x6a,0x10,0xe5,0x69,0xff, +0x1b,0x33,0xc1,0xf5,0x3a,0x40,0xba,0xc0,0x20,0x8a,0xc0,0xd2,0x25,0x7f,0xf2, +0x26,0x7f,0x4b,0x55,0x4b,0x66,0x89,0x27,0xf8,0x0f,0xb2,0x6c,0x14,0xf8,0xaf, +0xd8,0x0d,0xf8,0x0f,0xf9,0x37,0xe8,0x4d,0xe9,0x57,0xd8,0x0d,0xd9,0x47,0x72, +0xc7,0x10,0x66,0x23,0xaf,0xad,0x04,0x25,0x5d,0xff,0x38,0x01,0x25,0x66,0xff, +0x0c,0x09,0xb1,0xe6,0x3a,0x40,0xea,0xc0,0x0c,0x2c,0x20,0xda,0xc0,0xd9,0x13, +0xc9,0x03,0xe2,0x6b,0x14,0x92,0x6b,0x13,0x1d,0xf0,0x36,0x81,0x00,0x29,0x01, +0x0c,0x0e,0x71,0x7f,0x3b,0x51,0xde,0x3a,0x68,0x32,0x16,0xf3,0x06,0x82,0xc3, +0xfe,0x16,0x38,0x26,0x92,0xc3,0xeb,0x16,0x59,0x17,0xa2,0xc3,0xe1,0x56,0xda, +0x16,0xad,0x04,0xc8,0x35,0xb2,0x26,0x43,0x42,0x6c,0x44,0xa5,0x64,0xff,0xa8, +0x35,0x0c,0x0b,0xa2,0x2a,0x44,0x25,0xdd,0xff,0xa8,0x35,0xb2,0x26,0x43,0xa2, +0x2a,0x44,0x65,0x62,0xff,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0xd2,0xa4,0x00,0x98, +0x35,0x88,0x05,0xe2,0x29,0x44,0x82,0x28,0x10,0xc0,0xee,0x11,0xea,0x99,0xe2, +0x29,0x10,0xe2,0x67,0x80,0x98,0xf9,0x92,0x67,0x7f,0xe0,0x08,0x00,0xe2,0x27, +0x7f,0x1c,0x9a,0x0c,0x0b,0x88,0x05,0x0c,0x4c,0x82,0x28,0x10,0xd1,0x63,0x3b, +0xe0,0x08,0x00,0x1d,0xf0,0x88,0x05,0xa2,0xa1,0x1c,0x82,0x28,0x1d,0x0c,0x8b, +0xe0,0x08,0x00,0x0c,0x4b,0x0c,0x52,0x91,0x5e,0x3b,0x92,0x6a,0x3b,0x00,0x50, +0x00,0x88,0x05,0x3d,0x0a,0x82,0x28,0x1d,0x0c,0x0a,0xe0,0x08,0x00,0xa0,0xa0, +0x60,0xbd,0x02,0xa9,0x45,0xa2,0xc3,0x30,0x65,0xeb,0xff,0xc2,0xa0,0xc4,0xb2, +0xa0,0xec,0xa2,0xa0,0xb8,0xaa,0xa3,0xba,0xb3,0xca,0xc3,0x25,0xe8,0xff,0x88, +0x05,0x0c,0x0a,0x82,0x28,0x1d,0x0c,0x4b,0xe0,0x08,0x00,0xb8,0x45,0x0c,0x09, +0x92,0x63,0x44,0x92,0x63,0x45,0xaa,0xab,0xa9,0x45,0x0c,0x1b,0x0c,0x0a,0x65, +0xd2,0xff,0x0c,0x1a,0xd2,0xa0,0x64,0xe8,0x01,0x0c,0x62,0x0c,0x0c,0x92,0x23, +0x44,0xb1,0x46,0x3b,0xb9,0xf5,0xc0,0x99,0x11,0x9a,0x93,0x82,0x29,0x10,0x82, +0x67,0x80,0x98,0xf9,0xc9,0x83,0x92,0x67,0x7f,0x00,0x50,0x00,0x39,0x35,0x22, +0x63,0x3c,0x39,0x3e,0xe2,0x63,0x46,0xd9,0x23,0xc9,0x73,0xc9,0x63,0x65,0xcb, +0xff,0x0c,0x0a,0x0c,0x2c,0x0c,0x0d,0xd9,0x43,0xd9,0x53,0xd2,0x63,0x3e,0xd2, +0x63,0x3f,0xd2,0x63,0x40,0xd2,0x63,0x42,0xd2,0x63,0x43,0xc2,0x63,0x3d,0x65, +0xc6,0xff,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0x88,0x05,0xd2,0xa4,0x00,0x82,0x28, +0x10,0xe2,0x27,0x80,0xe0,0x08,0x00,0xe2,0x27,0x7f,0x1c,0x9a,0x0c,0x0b,0x88, +0x05,0x0c,0x4c,0x82,0x28,0x10,0xd1,0x29,0x3b,0xe0,0x08,0x00,0x1c,0x9a,0x0c, +0x0b,0x0c,0x4c,0x88,0x05,0xd2,0xa5,0x00,0x82,0x28,0x10,0xe1,0x27,0x3b,0xe0, +0x08,0x00,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c,0x88,0x05,0xd2,0xa5,0x00,0x82,0x28, +0x10,0xe1,0x23,0x3b,0xe0,0x08,0x00,0x1d,0xf0,0x41,0x22,0x3b,0x98,0x86,0xa8, +0x24,0x38,0x74,0xb8,0x44,0xc8,0x54,0x56,0xd9,0xfe,0xb9,0x41,0xc9,0x31,0xa9, +0x21,0xf1,0xcb,0x3a,0x0c,0x18,0xd2,0x27,0x80,0x89,0x86,0xf7,0x9d,0x08,0x92, +0x26,0x43,0x66,0x19,0x02,0x31,0x18,0x3b,0xb0,0xea,0x03,0xb9,0x11,0xe9,0x96, +0xf8,0x04,0xa8,0x36,0xd8,0x64,0xac,0x7a,0xad,0x0d,0xbd,0x0f,0xc2,0x27,0x7f, +0xa5,0xae,0xff,0xb8,0x21,0xad,0x03,0xc2,0x27,0x7f,0xe5,0xad,0xff,0xb8,0x41, +0xa8,0x84,0x5c,0x0c,0x65,0xad,0xff,0xb8,0x31,0xa8,0x94,0x5c,0x0c,0xe5,0xac, +0xff,0x86,0x02,0x00,0xad,0x0f,0xb8,0x14,0xc8,0x21,0xed,0x03,0x25,0x49,0xff, +0x90,0xea,0x03,0xd8,0x46,0x99,0x51,0x9c,0x5d,0xa8,0x64,0xbd,0x03,0xc2,0x27, +0x7f,0x88,0x15,0xe2,0x27,0x80,0x82,0x28,0x2e,0xf2,0xc6,0x14,0xe0,0x08,0x00, +0x98,0x51,0xa8,0x76,0xb8,0x66,0x38,0x11,0x88,0x96,0x30,0x39,0xc0,0x80,0x33, +0xc0,0x30,0xbb,0x53,0xb9,0x66,0xcc,0x2a,0x39,0x76,0xad,0x03,0x88,0x15,0x82, +0x28,0x28,0xe0,0x08,0x00,0x88,0x15,0x4d,0x0a,0x82,0x28,0x28,0xad,0x03,0xe0, +0x08,0x00,0xc1,0xf5,0x3a,0x88,0x15,0xbd,0x0a,0x82,0x28,0x2a,0xad,0x04,0xe0, +0x08,0x00,0x88,0x15,0x82,0x28,0x29,0x0c,0x03,0xe0,0x08,0x00,0x39,0x86,0x0c, +0x0b,0x0c,0x0c,0x88,0x05,0xa9,0x76,0x88,0xf8,0x1c,0x6a,0xe0,0x08,0x00,0x1d, +0xf0,0xb2,0x26,0x43,0x4c,0xfa,0xe5,0xa4,0xff,0x1c,0x9a,0x0c,0x0b,0x0c,0x4c, +0x88,0x05,0xd2,0xa2,0x00,0x82,0x28,0x10,0x0c,0x0e,0xe0,0x08,0x00,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x61,0x00,0x41,0x39,0x3a,0x42,0x24,0x10,0x48,0x64,0x52, +0x24,0x12,0x3c,0xaa,0xbd,0x05,0x25,0x31,0xff,0xa9,0x44,0xbd,0x05,0x4c,0x4a, +0xa5,0x30,0xff,0xa9,0x54,0xbd,0x05,0xa2,0xa0,0xfe,0xe5,0x2f,0xff,0xa9,0x34, +0x4b,0xb2,0x92,0xc2,0x80,0xed,0x03,0xf2,0x24,0x11,0xcd,0x01,0x82,0xa0,0x04, +0x76,0xa8,0x09,0xd2,0x09,0x80,0xd2,0x4c,0x00,0x1b,0x99,0x1b,0xcc,0x92,0x01, +0x00,0x0c,0x22,0x47,0x69,0x0b,0xe2,0xc3,0xfe,0x82,0xa0,0xef,0x80,0x99,0x10, +0x92,0x41,0x00,0x66,0x19,0x25,0xc2,0xa1,0x02,0x92,0x01,0x01,0xd1,0x6b,0x3a, +0x26,0x19,0x25,0x26,0x29,0x4b,0x0c,0x13,0x4c,0x4a,0xc2,0xc9,0xfd,0x16,0x3c, +0x07,0x82,0xc9,0xfc,0x16,0xb8,0x09,0x26,0x59,0x05,0x0c,0x42,0x1d,0xf0,0x1d, +0xf0,0x92,0x01,0x02,0x26,0x29,0x55,0x0c,0x32,0x1d,0xf0,0xf2,0x01,0x02,0x66, +0x1f,0xf5,0xc7,0x9e,0x4d,0x88,0xbd,0xc2,0xa0,0xfe,0xe0,0x08,0x00,0xad,0x04, +0xb8,0x34,0xc8,0x24,0x65,0x7c,0xfb,0xb8,0xd4,0x2d,0x0a,0x98,0x24,0xa8,0xe4, +0x99,0x2b,0x25,0xb0,0xfb,0x1d,0xf0,0xf2,0x01,0x02,0x66,0x1f,0xcc,0xc7,0x9e, +0x24,0x88,0xbd,0xc2,0xa0,0xfe,0xe0,0x08,0x00,0xad,0x04,0xb8,0x34,0xc8,0x14, +0xe5,0x79,0xfb,0xb8,0xb4,0x2d,0x0a,0x98,0x14,0xa8,0xc4,0x99,0x2b,0x65,0xad, +0xfb,0x1d,0xf0,0x3c,0xec,0xc7,0x1e,0x64,0x0c,0x62,0x1d,0xf0,0x82,0x01,0x02, +0x66,0x18,0x9a,0x92,0xce,0xfc,0xf0,0xca,0xc0,0x97,0x9c,0xec,0x88,0xbd,0xa8, +0x54,0xe0,0x08,0x00,0xd8,0x94,0xad,0x04,0xd8,0x3d,0xb8,0x54,0xcd,0x0d,0xd8, +0x0d,0xa5,0x6e,0xfb,0xb8,0x94,0x2d,0x0a,0x98,0x0b,0x06,0x0b,0x00,0x82,0x01, +0x02,0x0b,0x88,0x56,0xa8,0xf6,0x92,0xce,0xfc,0xf0,0xca,0xc0,0x97,0x9c,0xbc, +0x88,0xbd,0xa8,0x54,0xe0,0x08,0x00,0xd8,0x74,0xad,0x04,0xd8,0x3d,0xb8,0x54, +0xcd,0x0d,0xd8,0x0d,0xa5,0x6b,0xfb,0xb8,0x74,0x2d,0x0a,0x98,0x0b,0x39,0x19, +0x39,0x2b,0x1d,0xf0,0xa8,0x44,0x88,0xbd,0x3c,0xac,0xe0,0x08,0x00,0x1c,0xcb, +0xc8,0x04,0xd8,0x44,0xc8,0x1c,0xad,0x0d,0xc0,0x9c,0x20,0x76,0xab,0x09,0xe2, +0x9a,0x01,0xe2,0x59,0x00,0x2b,0xaa,0x2b,0x99,0xa8,0x64,0xb2,0x9d,0x00,0x65, +0xa7,0xfb,0x0c,0x02,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xbd,0x03,0xad,0x02, +0xe5,0xe7,0xff,0x2d,0x0a,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xb0,0xea,0x03, +0x21,0xd5,0x39,0x98,0x32,0x88,0x99,0xa8,0x02,0xb0,0x88,0xc0,0x89,0x99,0xe5, +0xff,0x03,0xe0,0xea,0x03,0xd8,0x32,0xc8,0x9d,0xea,0xcc,0xc9,0x9d,0x1d,0xf0, +0x36,0x41,0x00,0xe5,0x12,0x04,0x0c,0x32,0x00,0x50,0x00,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x61,0x00,0x21,0xc9,0x39,0x88,0x02,0x88,0x18,0x0c,0x1a,0xe0,0x08, +0x00,0x88,0x02,0x88,0x18,0x0c,0x2a,0xe0,0x08,0x00,0x88,0x02,0x88,0x18,0x0c, +0x3a,0xe0,0x08,0x00,0x88,0x02,0x88,0x18,0x0c,0x4a,0xe0,0x08,0x00,0x88,0x02, +0x88,0x18,0x0c,0x5a,0xe0,0x08,0x00,0x88,0x02,0x88,0x18,0x0c,0x6a,0xe0,0x08, +0x00,0x88,0x02,0x88,0x18,0xa1,0x63,0x3a,0xe0,0x08,0x00,0x0c,0x0e,0xc1,0x63, +0x3a,0xbd,0x0a,0x51,0x60,0x3a,0x0c,0x8a,0xdd,0x05,0x32,0xc5,0x20,0x76,0xaa, +0x07,0xe9,0x0c,0xe9,0x0d,0x4b,0xcc,0x4b,0xdd,0x88,0x02,0x0c,0xaa,0x88,0x18, +0xb9,0x11,0xe0,0x08,0x00,0x88,0x02,0xa9,0x01,0x88,0x18,0x0c,0xba,0xe0,0x08, +0x00,0x88,0x02,0x4d,0x0a,0x88,0x18,0x0c,0xca,0xe0,0x08,0x00,0x49,0x21,0x88, +0x02,0x7d,0x0a,0x88,0x18,0x0c,0xda,0xe0,0x08,0x00,0x6d,0x0a,0x4d,0x05,0x88, +0x02,0x88,0x58,0xe0,0x08,0x00,0xa9,0x04,0x4b,0x44,0x37,0x94,0xf1,0x31,0x4c, +0x3a,0x42,0xc3,0x20,0x88,0x02,0x88,0x58,0xe0,0x08,0x00,0xa9,0x03,0x4b,0x33, +0x47,0x93,0xf1,0x88,0x02,0xa8,0x01,0x88,0x48,0xb8,0x05,0xe0,0x08,0x00,0x88, +0x02,0xa8,0x01,0x88,0x48,0xb8,0x15,0xe0,0x08,0x00,0xb8,0x25,0x88,0x02,0x38, +0x21,0x88,0x48,0xad,0x03,0xe0,0x08,0x00,0x88,0x02,0xad,0x03,0x88,0x48,0xb8, +0x35,0xe0,0x08,0x00,0xad,0x07,0x88,0x02,0x31,0x3b,0x3a,0x88,0x38,0xb8,0x43, +0xe0,0x08,0x00,0x88,0x02,0xad,0x07,0x88,0x38,0xb8,0x53,0xe0,0x08,0x00,0x88, +0x02,0xad,0x07,0x88,0x48,0xb8,0x45,0xe0,0x08,0x00,0x88,0x02,0xad,0x06,0x88, +0x38,0xb8,0x63,0xe0,0x08,0x00,0x88,0x02,0xb8,0x73,0x88,0x38,0xad,0x06,0xe0, +0x08,0x00,0x88,0x02,0xad,0x06,0x88,0x48,0xb8,0x65,0xe0,0x08,0x00,0x88,0x02, +0x88,0x18,0x0c,0x8a,0xe0,0x08,0x00,0x88,0x02,0x88,0x08,0xa2,0xa0,0x80,0xe0, +0x08,0x00,0x88,0x02,0x6d,0x0a,0x88,0x18,0xa1,0x25,0x3a,0xe0,0x08,0x00,0x88, +0x02,0x7d,0x0a,0x88,0x08,0xa1,0x23,0x3a,0xe0,0x08,0x00,0x88,0x02,0x88,0x08, +0xa1,0x22,0x3a,0xe0,0x08,0x00,0x88,0x02,0x88,0x58,0xe0,0x08,0x00,0x88,0x02, +0x88,0x58,0x5d,0x0a,0xe0,0x08,0x00,0xbd,0x05,0x4d,0x0a,0x88,0x02,0x38,0x11, +0x88,0x48,0xad,0x03,0xe0,0x08,0x00,0x88,0x02,0xad,0x03,0x88,0x38,0xbd,0x04, +0xe0,0x08,0x00,0x88,0x02,0xbd,0x05,0x88,0x38,0xad,0x06,0xe0,0x08,0x00,0x88, +0x02,0xad,0x06,0x88,0x48,0xbd,0x04,0xe0,0x08,0x00,0x88,0x02,0x88,0x18,0xa1, +0x10,0x3a,0xe0,0x08,0x00,0x88,0x02,0xbd,0x0a,0x88,0x28,0x1c,0x7a,0xe0,0x08, +0x00,0x88,0x02,0xbd,0x07,0x88,0x28,0x1c,0x9a,0xe0,0x08,0x00,0x88,0x02,0xbd, +0x03,0x88,0x28,0x0c,0x7a,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x36,0x61,0x00,0xe5, +0xfb,0x03,0xa1,0x05,0x3a,0xb1,0x05,0x3a,0xc1,0x06,0x3a,0xd1,0x06,0x3a,0xe1, +0x06,0x3a,0xf1,0x06,0x3a,0x0c,0x42,0x00,0x50,0x00,0xe0,0x02,0x00,0xbd,0x0a, +0x31,0x4e,0x39,0xa1,0x03,0x3a,0xb9,0x03,0xa2,0x6b,0x15,0x91,0xc3,0x39,0xc0, +0x20,0x00,0x92,0x29,0x98,0x0c,0x02,0x27,0x69,0x01,0x1d,0xf0,0xad,0x01,0x0c, +0x0c,0x0c,0x62,0xf1,0xfd,0x39,0x92,0x2b,0x1f,0x51,0x8e,0x39,0xd2,0x2b,0x1e, +0xe2,0x2b,0x1d,0xe2,0x63,0x1b,0xd2,0x63,0x1a,0x88,0x05,0x92,0x63,0x19,0xf9, +0x08,0x00,0x50,0x00,0x29,0x13,0xf2,0x22,0x14,0xd2,0x22,0x13,0xd9,0x23,0xf8, +0x0f,0xf9,0x11,0xe9,0x31,0xd9,0x21,0xc9,0x01,0x65,0xf8,0x03,0xa5,0xdb,0xff, +0x41,0x9e,0x39,0xe8,0x04,0xcc,0xfe,0xa1,0xee,0x39,0x88,0x55,0xb1,0xee,0x39, +0xe0,0x08,0x00,0xa9,0x14,0x0c,0x19,0x99,0x04,0xa8,0x03,0x82,0x2a,0x17,0xe0, +0x08,0x00,0x0c,0x12,0x1d,0xf0,0x36,0x41,0x00,0x2f,0x20,0x01,0x22,0x44,0x0c, +0x0c,0x11,0x6f,0xe4,0x04,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0xa8, +0x00,0x06,0x10,0xaf,0xe0,0x0a,0x22,0x50,0x00,0x00,0x19,0xaf,0xe0,0x0a,0x22, +0xa4,0x00,0x06,0x10,0xaf,0xe0,0x0a,0x22,0xa8,0x00,0x01,0x00,0x4f,0x00,0x28, +0x48,0x44,0x0c,0x0c,0x11,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x6f,0xe4, +0x00,0x22,0x44,0x0c,0x0c,0x11,0x1c,0xf2,0xaf,0xe0,0x0a,0x22,0x82,0x08,0x04, +0x00,0x4f,0x00,0x28,0x48,0x44,0x0c,0x0c,0x11,0x1d,0xf0,0x00,0x36,0x41,0x00, +0x30,0x00,0x0c,0x1c,0xf4,0xaf,0xe0,0x0a,0x22,0x02,0x09,0x04,0x00,0x00,0x02, +0x0d,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x02,0x70,0x64,0x00,0x61, +0xba,0x39,0x41,0x0e,0x39,0x3d,0x06,0x62,0xc6,0x20,0xa8,0x03,0x8c,0x8a,0x88, +0x04,0x88,0x98,0xe0,0x08,0x00,0x20,0x2a,0x53,0x4b,0x33,0x67,0x93,0xec,0xa1, +0xc1,0x39,0xa2,0x1a,0x40,0xa7,0xa2,0x05,0x20,0x5a,0xc0,0x46,0x00,0x00,0x0c, +0x05,0x31,0xae,0x39,0xb8,0x03,0x0c,0x02,0x9c,0x1b,0xa6,0x15,0x0f,0x88,0x04, +0xa8,0x03,0x88,0x68,0x0c,0x0b,0xe0,0x08,0x00,0x1b,0x22,0x27,0x95,0xef,0x4b, +0x33,0x67,0x93,0xe1,0x70,0xe6,0x13,0x20,0x20,0x00,0x1d,0xf0,0x36,0x41,0x00, +0x51,0xb3,0x39,0x0c,0xb6,0x0c,0x83,0x76,0xa3,0x14,0x48,0x05,0x4b,0x55,0x67, +0x14,0x0a,0x98,0x22,0x88,0x12,0x97,0x18,0x03,0x0c,0x02,0x1d,0xf0,0x22,0xc2, +0x10,0x0c,0x12,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0x0b,0x0c,0x1c,0x0c, +0x0d,0xed,0x02,0x31,0xa6,0x39,0xf1,0xa7,0x39,0xa2,0x93,0x20,0xe5,0xaa,0x01, +0xa2,0x93,0x22,0x0c,0x0b,0x0c,0x1c,0x0c,0x0d,0xed,0x02,0xf1,0xa3,0x39,0xe5, +0xa9,0x01,0xa2,0x93,0x24,0x0c,0x0b,0x0c,0x1c,0x0c,0x0d,0xed,0x02,0xf1,0xa0, +0x39,0xe5,0xa8,0x01,0xa2,0x93,0x26,0x0c,0x0b,0x0c,0x1c,0x0c,0x0d,0xed,0x02, +0xf1,0x9d,0x39,0xe5,0xa7,0x01,0xa2,0x93,0x28,0x0c,0x0b,0x0c,0x1c,0x0c,0x0d, +0xf0,0xe2,0x11,0xf1,0x99,0x39,0xa5,0xa6,0x01,0xed,0x02,0xa2,0x93,0x2a,0x0c, +0x0b,0x0c,0x1c,0x0c,0x0d,0xf1,0x96,0x39,0xa5,0xa5,0x01,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x61,0x94,0x39,0x41,0x94,0x39,0xf0,0x73,0x11,0x52,0xc4,0x18,0x88, +0x04,0x80,0xa8,0x23,0x66,0x78,0x23,0x66,0x12,0x10,0xb1,0x8c,0x39,0xa5,0xaa, +0x01,0xbd,0x07,0xa2,0x94,0x00,0xe5,0xac,0x01,0x06,0x05,0x00,0xbd,0x06,0xa5, +0xa9,0x01,0xa2,0x94,0x00,0xbd,0x03,0xe5,0xab,0x01,0x06,0x01,0x00,0xbd,0x03, +0x65,0xab,0x01,0x4b,0x44,0x57,0x94,0xc9,0x1d,0xf0,0x00,0x36,0x61,0x00,0x3d, +0x02,0x29,0x11,0x0c,0x14,0x21,0x82,0x39,0x71,0xbe,0x38,0x28,0x02,0x82,0x23, +0xbd,0x22,0x22,0x52,0x56,0xc8,0x04,0x42,0x63,0xbd,0xa8,0x02,0x39,0x11,0xa6, +0x1a,0x42,0x5d,0x02,0x61,0x7c,0x39,0x0c,0x08,0x89,0x01,0xd8,0x15,0x0c,0x03, +0x98,0x0d,0x0c,0x04,0xa6,0x19,0x21,0x3c,0x4c,0x88,0x07,0xb8,0x16,0xda,0xa3, +0x4b,0xaa,0x3a,0xbb,0x82,0x28,0x20,0x4b,0xbb,0xe0,0x08,0x00,0xd8,0x15,0x32, +0xc3,0x34,0xb8,0x0d,0x1b,0x44,0xb7,0x24,0xdf,0xa8,0x02,0x4b,0x66,0xc8,0x01, +0x4b,0x55,0x1b,0xcc,0xc9,0x01,0xa7,0x2c,0xc5,0x38,0x11,0x0c,0x14,0x0c,0x1a, +0x0c,0xab,0xc8,0x12,0x3c,0x4e,0x91,0x6a,0x39,0x88,0x07,0x98,0x29,0x51,0x69, +0x39,0xc0,0x99,0x11,0x9a,0x55,0xd8,0x25,0x88,0xf8,0xd0,0xd0,0x34,0xe0,0xdd, +0xd1,0xda,0xcc,0x4b,0xcc,0xe0,0x08,0x00,0x0c,0x1a,0x0c,0xbb,0xc8,0x22,0x3c, +0x4e,0x88,0x07,0xd8,0x25,0x88,0xf8,0xd0,0xd4,0x34,0xe0,0xdd,0xd1,0xda,0xcc, +0x4b,0xcc,0xe0,0x08,0x00,0x0c,0x1a,0x0c,0xcb,0xc8,0x32,0x3c,0x4e,0x88,0x07, +0xd8,0x25,0x88,0xf8,0xd0,0xd8,0x34,0xe0,0xdd,0xd1,0xda,0xcc,0x4b,0xcc,0xe0, +0x08,0x00,0x0c,0x1a,0x0c,0xdb,0xc8,0x42,0x3c,0x4e,0x88,0x07,0xd8,0x25,0x88, +0xf8,0xd0,0xdc,0x34,0xe0,0xdd,0xd1,0xda,0xcc,0x4b,0xcc,0xe0,0x08,0x00,0x0c, +0x1a,0x88,0x07,0x1c,0x9b,0x88,0xf8,0x7c,0xfc,0xe0,0x08,0x00,0x42,0x63,0xc6, +0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x31,0x4a,0x39,0x0c,0x02,0xa2,0x93,0x01, +0xbd,0x02,0x25,0x17,0x00,0x32,0xc3,0x10,0x1b,0x22,0x66,0x82,0xef,0x31,0x46, +0x39,0x0c,0x02,0xa2,0x93,0x01,0xbd,0x02,0x65,0x19,0x00,0x32,0xc3,0x10,0x1b, +0x22,0x66,0x82,0xef,0x1d,0xf0,0x00,0x36,0x41,0x00,0x51,0x40,0x39,0x88,0x05, +0x42,0x28,0x3e,0x40,0x44,0x04,0xcc,0x28,0x0c,0x02,0x1d,0xf0,0xf6,0x92,0x1d, +0x81,0x3c,0x39,0x80,0x22,0xa0,0xa8,0x02,0x0c,0x09,0x96,0x8a,0x02,0xbd,0x03, +0x25,0x30,0xff,0xd6,0xba,0x01,0x7c,0xf9,0x99,0x02,0x0c,0x09,0x46,0x00,0x00, +0x0c,0x09,0xa2,0x25,0x8b,0x0c,0x02,0x8c,0x6a,0x8c,0x09,0x8c,0x24,0x0c,0x12, +0x1d,0xf0,0x1d,0xf0,0x0c,0x19,0x46,0xfa,0xff,0x86,0xf9,0xff,0x36,0x41,0x00, +0x61,0x2e,0x39,0x7c,0xf5,0x82,0xa0,0x8b,0x1b,0x55,0x72,0x96,0x0e,0x62,0xc6, +0x10,0x27,0x17,0x02,0x87,0x97,0xf1,0x20,0x37,0xc0,0x7c,0xf2,0x30,0x25,0x83, +0x1d,0xf0,0x00,0x36,0x41,0x00,0x61,0x14,0x39,0xe6,0x62,0x23,0x0c,0x05,0x62, +0xc6,0xe0,0x32,0xa0,0x08,0x76,0xa3,0x13,0x48,0x06,0x4b,0x66,0x27,0x94,0x0a, +0x21,0x20,0x39,0x20,0x25,0x90,0x22,0x12,0x00,0x1d,0xf0,0x1b,0x55,0x7c,0xf2, +0x1d,0xf0,0x00,0x0c,0x05,0x0c,0x83,0x76,0xa3,0x13,0x48,0x06,0x4b,0x66,0x27, +0x94,0x0a,0x21,0x19,0x39,0x20,0x25,0x90,0x22,0x12,0x00,0x1d,0xf0,0x1b,0x55, +0x7c,0xf2,0x1d,0xf0,0x36,0x41,0x00,0x41,0x10,0x39,0x0c,0x03,0x32,0x64,0x8a, +0x22,0x64,0x89,0x1d,0xf0,0x36,0x41,0x00,0xb1,0x0c,0x39,0xa2,0x2b,0x8a,0x82, +0x2b,0x89,0x1b,0xca,0x87,0x2a,0x03,0x0c,0x12,0x1d,0xf0,0xd2,0xcb,0x24,0xda, +0xda,0x22,0x4d,0x00,0x92,0x2b,0x89,0xc2,0x6b,0x8a,0xc7,0x99,0x13,0x81,0x39, +0x38,0x1c,0x8a,0x88,0x08,0x1c,0x9b,0x88,0xf8,0x0c,0x0c,0xe0,0x08,0x00,0x0c, +0x12,0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x31,0xf8,0x38, +0x38,0x23,0x21,0xf8,0x38,0xc0,0x33,0x11,0x3a,0x22,0x22,0x92,0x06,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x41,0x00,0x21,0xf6,0x38,0x28,0x02,0x41,0xf2,0x38,0x32, +0x22,0x40,0x22,0x22,0x41,0x8c,0x83,0xc0,0x22,0x11,0x2a,0x24,0x22,0x92,0x06, +0x1d,0xf0,0x21,0xeb,0x38,0x28,0x22,0x46,0xfb,0xff,0x00,0x00,0x00,0x36,0x41, +0x00,0xf6,0x83,0x2a,0xa1,0xf0,0x38,0xbd,0x02,0xa0,0xa3,0xa0,0xa8,0x0a,0xe5, +0xe9,0xff,0xc2,0xa0,0xc8,0xc0,0xe3,0x11,0xd1,0xe4,0x38,0x81,0xe0,0x38,0xbd, +0x0a,0x88,0x08,0xad,0x02,0x82,0x28,0x2c,0xea,0xdd,0xe0,0x08,0x00,0x0c,0x02, +0x1d,0xf0,0x7c,0xf2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xf6,0x83,0x3b, +0x41,0xdd,0x38,0xe8,0x04,0x82,0x2e,0x40,0x0c,0x1b,0xdc,0x28,0xa1,0xcb,0x38, +0xbd,0x02,0xa0,0xa3,0xa0,0xa8,0x0a,0xa5,0xe5,0xff,0xbd,0x0a,0xe8,0x04,0xc6, +0xff,0xff,0xad,0x02,0xc2,0x2e,0x45,0x81,0xce,0x38,0xc0,0xf3,0x11,0x88,0x08, +0xd1,0xd1,0x38,0x82,0x28,0x2c,0xfa,0xdd,0xe0,0x08,0x00,0x0c,0x02,0x1d,0xf0, +0x7c,0xf2,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xc0,0x73,0x11,0x52,0x22,0xc0, +0xc0,0x64,0x11,0x6a,0x65,0x7a,0x55,0x58,0x15,0x59,0x16,0x1d,0xf0,0x00,0x00, +0x36,0x41,0x00,0xf6,0x83,0x22,0xad,0x02,0x0c,0x1b,0xc1,0xc4,0x38,0xc0,0xe3, +0x11,0xd1,0xc9,0x38,0x81,0xbc,0x38,0xea,0xdd,0x88,0x08,0xc8,0x0c,0x82,0x28, +0x2c,0xc2,0x2c,0x45,0xe0,0x08,0x00,0x0c,0x02,0x1d,0xf0,0x7c,0xf2,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x41,0x00,0xb6,0x82,0x03,0x7c,0xf2,0x1d,0xf0,0x41,0xb6, +0x38,0xc0,0x22,0x11,0x2a,0x24,0x22,0x92,0x01,0x29,0x03,0x0c,0x02,0x1d,0xf0, +0x00,0x36,0x41,0x00,0xb6,0x82,0x03,0x7c,0xf2,0x1d,0xf0,0x41,0xb0,0x38,0xc0, +0x22,0x11,0x2a,0x24,0x22,0x92,0x01,0x29,0x03,0x0c,0x02,0x1d,0xf0,0x00,0x36, +0x61,0x00,0x71,0x9e,0x38,0x61,0x87,0x38,0x51,0xaa,0x38,0x21,0x9b,0x38,0x31, +0xa3,0x38,0x42,0xc2,0xe0,0x88,0x03,0x82,0x28,0x3f,0xa8,0x04,0xe0,0x08,0x00, +0x9c,0xaa,0xa8,0x04,0xc8,0x05,0x88,0x03,0xc2,0x2c,0x33,0x82,0x28,0x20,0xa0, +0xba,0xa0,0xa0,0xbb,0x11,0x60,0xaa,0xa0,0xa8,0x0a,0xba,0xb7,0xe0,0x08,0x00, +0x4b,0x44,0x27,0x94,0xd2,0x41,0xa3,0x38,0x0c,0x0f,0xf9,0x01,0xd8,0x02,0x0c, +0xa8,0xd7,0x28,0x4a,0x66,0x7d,0x2a,0x98,0x01,0x0c,0x1a,0xe6,0x19,0x40,0xa9, +0x01,0x66,0x7d,0x1e,0xe8,0x05,0xb2,0x2e,0x3e,0x37,0x6b,0x16,0xa1,0x70,0x38, +0xb1,0x88,0x38,0x88,0x03,0xc2,0x2e,0x33,0x82,0x28,0x20,0xf0,0xcc,0x11,0xe0, +0x08,0x00,0x06,0x07,0x00,0xe6,0x9d,0x19,0xc8,0x05,0x88,0x03,0xd0,0xbd,0xa0, +0x60,0xad,0xa0,0xa8,0x0a,0xa0,0xbb,0x11,0xba,0xb7,0x82,0x28,0x20,0xc2,0x2c, +0x33,0xe0,0x08,0x00,0x4b,0x22,0x47,0x92,0xa8,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0xc1,0x73,0x38,0xd2,0xcc,0x60,0xe2,0xcc,0x10,0xb8,0x0c,0xb2,0x62,0x36, +0xe9,0xc2,0xd2,0x62,0x1b,0xb1,0x5b,0x38,0xb9,0xd2,0xc2,0xcc,0x70,0x0c,0x8d, +0xe1,0x5c,0x38,0xe9,0x92,0xd2,0x52,0x16,0xd2,0x52,0x17,0xc2,0x62,0x1c,0x52, +0xce,0xe0,0xc2,0xcb,0xe0,0x32,0xde,0x45,0xa2,0xce,0x20,0x92,0xce,0x40,0x82, +0xce,0x70,0x42,0xde,0x44,0xf2,0xde,0x47,0xf2,0x62,0x2c,0x42,0x62,0x18,0x82, +0x62,0xbf,0x92,0x62,0x46,0xa9,0xa2,0x32,0x62,0xc0,0xc2,0x62,0x14,0x52,0x62, +0x15,0xc1,0x75,0x38,0x51,0x74,0x38,0x31,0x6a,0x38,0x32,0x62,0x19,0x52,0x62, +0x10,0xc2,0x62,0x1e,0xa2,0xc5,0x20,0x92,0xc5,0x40,0x82,0xc5,0x60,0x42,0xd3, +0x01,0xd2,0xcc,0x30,0xf2,0xcc,0x10,0xf2,0x62,0x1f,0xd2,0x62,0x21,0x42,0x62, +0x22,0x82,0x62,0x13,0x92,0x62,0x12,0xa2,0x62,0x11,0x91,0x64,0x38,0x92,0x62, +0x23,0xa2,0xc9,0x40,0xb2,0xc9,0x20,0xb2,0x62,0x24,0xa2,0x62,0xc2,0xe2,0xcc, +0x20,0xe2,0x62,0x20,0xa1,0x64,0x38,0x0c,0x09,0xc1,0x62,0x38,0xc2,0x62,0x25, +0x92,0x62,0x37,0x92,0x52,0x3a,0x92,0x52,0x77,0x92,0x52,0x7a,0x92,0x52,0x7b, +0x92,0x62,0xc5,0x92,0x62,0xc6,0xa2,0x62,0x2e,0x82,0xcc,0x10,0x52,0xcc,0x20, +0x32,0xcc,0x50,0x42,0xcc,0x30,0xb2,0xca,0x40,0xd2,0xcc,0xf0,0xf2,0xcc,0x70, +0xf2,0x62,0x2b,0xd2,0x62,0xc4,0xb2,0x62,0x30,0x42,0x62,0x28,0x32,0x62,0x29, +0xe2,0xcc,0xe0,0x52,0x62,0x27,0x82,0x62,0x26,0x0c,0xaa,0xa2,0x52,0x75,0x7c, +0xe8,0x52,0x22,0x3e,0xe2,0x62,0xc3,0x0c,0x73,0x3c,0x04,0x1c,0x0b,0xd1,0x4d, +0x38,0x0c,0x3f,0xf2,0x52,0x73,0xd9,0xe2,0xb2,0x52,0x3b,0x42,0x62,0x38,0x32, +0x52,0x72,0xe2,0xa1,0x00,0xe2,0x52,0x74,0x80,0x55,0x10,0x31,0x35,0x38,0x41, +0x35,0x38,0x49,0x12,0x39,0x22,0x7c,0xd8,0x80,0x55,0x10,0x92,0xad,0xff,0x0c, +0x48,0x0c,0x2c,0x80,0x55,0x20,0x7c,0x78,0x80,0x55,0x10,0xc2,0x52,0x34,0x6c, +0xf8,0x80,0x55,0x10,0x82,0xaf,0xdf,0x80,0x55,0x10,0x82,0xaf,0xbf,0x80,0x55, +0x10,0x90,0x55,0x10,0x81,0x38,0x38,0x0c,0xd9,0x92,0x52,0x76,0x80,0x55,0x10, +0x82,0xae,0xff,0x80,0x55,0x10,0x52,0x62,0x3e,0x82,0xa1,0x90,0x82,0x52,0x62, +0x51,0x33,0x38,0x52,0x62,0x3c,0x1d,0xf0,0x00,0x00,0x00,0x36,0xa1,0x00,0x29, +0x81,0x61,0x21,0x38,0x0c,0x0f,0x71,0x56,0x37,0x9d,0x03,0x31,0x19,0x38,0x16, +0xc9,0x04,0x0c,0x1b,0xd1,0xaa,0x37,0xc1,0x0c,0x38,0xa1,0xa6,0x37,0x0b,0x89, +0x16,0xa8,0x20,0xe2,0xc9,0xfe,0x16,0x9e,0x6c,0x82,0xc9,0xfc,0x16,0x98,0x26, +0xa2,0xc9,0xfb,0x16,0x6a,0x1f,0xe1,0x24,0x38,0x82,0xc9,0xf9,0x16,0x38,0x2b, +0xa2,0xcc,0x40,0x82,0xc9,0xea,0x16,0x78,0x2d,0xd2,0xc9,0xe8,0x16,0x7d,0x46, +0xe2,0xc9,0xe4,0x16,0x3e,0x21,0xf1,0x1d,0x38,0xf0,0xf9,0xc0,0x56,0xff,0x1c, +0xb9,0x76,0x1d,0xf0,0x0c,0x05,0x91,0x21,0x38,0x81,0x1a,0x38,0xb1,0x1e,0x38, +0xf1,0x19,0x38,0xe1,0x1a,0x38,0xd1,0x1a,0x38,0xa8,0x03,0xc1,0x1a,0x38,0xc2, +0x6a,0x3a,0xd2,0x6a,0x35,0xe2,0x6a,0x39,0xf2,0x6a,0x38,0xb2,0x6a,0x41,0x82, +0x6a,0x3f,0x1c,0x0b,0x88,0x07,0x92,0x6a,0x33,0x82,0x28,0x1d,0xa2,0xa3,0x40, +0xe0,0x08,0x00,0x4d,0x0a,0x0c,0x0b,0xc2,0xa3,0x40,0xe5,0x89,0xfa,0x9d,0x04, +0x0c,0x4b,0xd8,0x81,0xa1,0xf3,0x37,0x49,0x3d,0x49,0x06,0x52,0x64,0x40,0xc8, +0x2a,0xc2,0x64,0x41,0xc2,0xc4,0x10,0x76,0xab,0x10,0x0c,0x8e,0x1c,0x8f,0x1c, +0x08,0x82,0x69,0x9f,0xf2,0x69,0xa9,0xe2,0x69,0xb3,0x4b,0x99,0x92,0xc4,0x18, +0xa2,0xc4,0x20,0x0c,0x2b,0x76,0xab,0x10,0x0c,0x8d,0x1c,0x8e,0x1c,0x0f,0xf2, +0x69,0x9f,0xe2,0x69,0xa9,0xd2,0x69,0xb3,0x4b,0x99,0x3c,0x8d,0x4c,0x09,0xb2, +0xa0,0x48,0x82,0xa0,0x02,0x76,0xa8,0x0a,0x92,0x6c,0x9f,0xb2,0x6c,0xa9,0xd2, +0x6c,0xb3,0x4b,0xcc,0x0c,0x2c,0x76,0xac,0x0a,0x92,0x6a,0x9f,0xb2,0x6a,0xa9, +0xd2,0x6a,0xb3,0x4b,0xaa,0xad,0x04,0xd1,0xf8,0x37,0xe1,0xf5,0x37,0x81,0xf3, +0x37,0x98,0x03,0xf1,0xf4,0x37,0xf2,0x69,0x4d,0x82,0x69,0x4f,0xe8,0x0e,0x81, +0xf2,0x37,0x82,0x69,0x4c,0xf2,0x2e,0x16,0xf2,0x64,0xbe,0xd2,0x6e,0x16,0xe5, +0xd3,0xff,0xa1,0xef,0x37,0x0c,0x89,0x76,0xa9,0x03,0x59,0x0a,0x4b,0xaa,0x91, +0xd0,0x37,0x7c,0xfa,0xb2,0xa0,0x0a,0x76,0xab,0x03,0xa9,0x09,0x4b,0x99,0x0c, +0x62,0x00,0x50,0x00,0x29,0x66,0x29,0x04,0x88,0x03,0x82,0x28,0x46,0xad,0x04, +0xe0,0x08,0x00,0x88,0x07,0x0c,0x0a,0x82,0x28,0x1d,0x0c,0x4b,0xe0,0x08,0x00, +0xa0,0x90,0x60,0xa1,0xe1,0x37,0x88,0x03,0x99,0x0a,0x82,0x28,0x47,0xad,0x04, +0xe0,0x08,0x00,0x88,0x07,0x0c,0x0a,0x82,0x28,0x1d,0x0c,0x4b,0xe0,0x08,0x00, +0xc1,0xda,0x37,0xb8,0x0c,0xaa,0xbb,0xa1,0xb7,0x37,0xb9,0x0c,0xa8,0x1a,0x25, +0xa3,0xff,0x91,0xb4,0x37,0xbd,0x0a,0xa9,0x29,0x66,0x0a,0x05,0x59,0x19,0x0c, +0x0b,0xb9,0x29,0x88,0x03,0xad,0x04,0x82,0x28,0x3d,0xc2,0xa0,0x8b,0xe0,0x08, +0x00,0x52,0x66,0x8b,0x0c,0x03,0x0c,0x0a,0xbd,0x03,0x65,0xb0,0xff,0x1b,0x33, +0x66,0x83,0xf3,0x4c,0x06,0x0c,0x03,0x0c,0x0a,0xbd,0x03,0xe5,0xb2,0xff,0x0c, +0x0a,0xbd,0x03,0xa5,0xb8,0xff,0x1b,0x33,0x66,0x83,0xec,0x52,0x64,0xbd,0x52, +0x64,0x45,0x92,0x24,0x3e,0x2c,0x0a,0xa0,0x99,0x20,0x60,0x99,0x20,0x92,0x64, +0x3e,0x65,0x95,0xff,0x0c,0x8a,0x0c,0x0b,0x0c,0x4c,0x88,0x07,0xd2,0xa5,0x00, +0x82,0x28,0x10,0xe1,0xbd,0x37,0xe0,0x08,0x00,0x0c,0x8a,0x0c,0x0b,0x0c,0x4c, +0x88,0x07,0xd2,0xa4,0x00,0x82,0x28,0x10,0xe1,0xb9,0x37,0xe0,0x08,0x00,0x1d, +0xf0,0x7c,0x77,0x1c,0x9e,0x40,0x90,0x74,0xe7,0x99,0xf3,0xf9,0x76,0xb9,0x2c, +0xe8,0x06,0xb9,0x3c,0xc8,0x3e,0x5c,0x04,0xa0,0x8c,0xc0,0x56,0xe8,0x2f,0xd2, +0x2e,0x3e,0x0c,0x89,0x92,0x6e,0x37,0x70,0xcd,0x10,0xd0,0xd9,0x04,0xd0,0xdd, +0x11,0xd0,0xcc,0x20,0xc2,0x6e,0x3e,0xd2,0x2e,0x3f,0xc6,0xc3,0x00,0x3d,0x0f, +0x4d,0x0a,0xf8,0x07,0xf2,0x2f,0x10,0x37,0x55,0x0f,0x1c,0x7a,0x0c,0x0b,0x0c, +0x4c,0x0c,0x3d,0xed,0x04,0xe0,0x0f,0x00,0x06,0x03,0x00,0x1c,0x7a,0x0c,0x0b, +0x0c,0x4c,0x0c,0x4d,0xed,0x04,0xe0,0x0f,0x00,0x4b,0x44,0x1b,0x33,0x66,0x73, +0xd3,0x1d,0xf0,0xe1,0x14,0x37,0x7c,0x73,0xe7,0xa4,0x02,0x86,0x97,0x00,0x47, +0xae,0x02,0x86,0xed,0x00,0xe8,0x06,0x92,0x2e,0x40,0x16,0x59,0x51,0xb6,0x49, +0x02,0xc6,0xdc,0xff,0x16,0x09,0xf7,0x50,0x84,0x35,0xcc,0x78,0xb2,0x6e,0x42, +0x50,0xa0,0xf4,0xa2,0x6e,0x41,0x50,0xc0,0x35,0x8c,0x7c,0xb2,0x6e,0x43,0x50, +0xd8,0x75,0xd2,0x6e,0x44,0x66,0x39,0x12,0x0c,0x03,0xa2,0xaf,0xbf,0xbd,0x03, +0xe5,0xa8,0xff,0x0c,0x1b,0x1b,0x33,0x66,0x83,0xf0,0xe8,0x06,0xb2,0x6e,0x40, +0x1d,0xf0,0xe2,0xc4,0xf6,0xb6,0x4e,0x02,0x06,0xcc,0xff,0x98,0x06,0x92,0x29, +0x40,0x26,0x19,0x7e,0xa2,0xc9,0xfd,0x56,0x0a,0x0e,0xa1,0x66,0x37,0x25,0x67, +0xff,0x16,0x7a,0x0d,0xc8,0x06,0x0c,0x0b,0xb2,0x6c,0x40,0xe5,0x83,0xff,0x86, +0x32,0x00,0x7d,0x0e,0x98,0x3c,0x4d,0x0a,0xa6,0x19,0x1b,0xe1,0x79,0x37,0x81, +0x64,0x37,0x0b,0xa9,0xa9,0x3c,0xd2,0x98,0x06,0x82,0x98,0x07,0xd2,0xcd,0xf0, +0xd2,0x5e,0x7c,0x82,0xc8,0xf0,0x82,0x5e,0x7d,0x0c,0x05,0xe5,0xa8,0xff,0xad, +0x04,0x0c,0x7b,0xe5,0x0c,0x01,0xa8,0x06,0xe5,0x37,0x02,0xa8,0x06,0xa5,0x06, +0x03,0x88,0x03,0x82,0x28,0x4e,0xa8,0x06,0xe0,0x08,0x00,0x88,0x03,0x82,0x28, +0x4b,0xa8,0x06,0xe0,0x08,0x00,0xe8,0x06,0x92,0x2e,0xc6,0x59,0xf7,0xe6,0x19, +0x02,0x06,0xac,0xff,0x0b,0xa9,0xa2,0x6e,0xc6,0x1d,0xf0,0xa1,0x48,0x37,0xa5, +0x5f,0xff,0xcc,0x6a,0xb8,0x06,0xb2,0x2b,0xc5,0x16,0x7b,0x05,0xc1,0x3f,0x37, +0xd1,0x43,0x37,0xd9,0x91,0xc9,0x71,0xa2,0xaf,0xa6,0x0c,0x0b,0x88,0x03,0x0c, +0x0c,0x82,0x28,0x2c,0xd8,0x91,0xe0,0x08,0x00,0x98,0x91,0xa8,0x71,0x92,0xc9, +0x10,0x99,0x91,0xa7,0x99,0xe2,0xe8,0x06,0xb2,0x2e,0x43,0x9c,0x3b,0xb2,0x2e, +0x44,0x88,0x07,0x1c,0xfa,0x88,0xf8,0x0c,0x0c,0xe0,0x08,0x00,0xe8,0x06,0x0c, +0x09,0x92,0x6e,0x43,0xc2,0x2e,0x41,0x88,0x07,0x0c,0x1a,0x88,0xf8,0x1c,0x9b, +0xe0,0x08,0x00,0xa8,0x06,0x0c,0x29,0x92,0x6a,0x40,0xd8,0x76,0x56,0xcd,0xe3, +0x88,0x03,0x82,0x28,0x36,0xa8,0x06,0xe0,0x08,0x00,0xe8,0x06,0x92,0x2e,0x3e, +0x90,0x97,0x04,0x16,0x99,0x3f,0x0c,0x0a,0xb2,0x1e,0x16,0xa9,0xa1,0xa6,0x1b, +0x48,0x0c,0x04,0xc2,0x2e,0x23,0x4a,0xcc,0xc8,0x0c,0xc2,0xcc,0xf4,0xb6,0x2c, +0x2e,0xa8,0x9e,0xaa,0xa4,0xa8,0x0a,0xac,0x5a,0x88,0x07,0x88,0x98,0xe0,0x08, +0x00,0x5d,0x0a,0x0c,0x03,0xa6,0x1a,0x13,0xa8,0x06,0x88,0x07,0xa8,0x9a,0x88, +0x78,0x4a,0xaa,0xa8,0x0a,0xe0,0x08,0x00,0x1b,0x33,0x57,0x93,0xeb,0xe8,0x06, +0xb2,0x1e,0x16,0xc8,0xa1,0x4b,0x44,0x1b,0xcc,0xc9,0xa1,0xb7,0x2c,0xb8,0x0c, +0x0d,0xb2,0x1e,0x17,0xd9,0xa1,0xe6,0x1b,0x02,0xc6,0x71,0xff,0x0c,0x04,0xf2, +0x2e,0x24,0x4a,0xff,0xf8,0x0f,0xf2,0xcf,0xf4,0xb6,0x2f,0x34,0xa8,0xae,0xaa, +0xa4,0xa8,0x0a,0xac,0xba,0x88,0x07,0x88,0x98,0xe0,0x08,0x00,0x0c,0x03,0x52, +0xa0,0xff,0xa0,0x55,0xc0,0xa6,0x15,0x15,0x0c,0x0b,0xa8,0x06,0x88,0x07,0xa8, +0xaa,0x88,0x68,0x4a,0xaa,0xa8,0x0a,0xe0,0x08,0x00,0x1b,0x33,0x57,0x93,0xe9, +0xe8,0x06,0xb2,0x1e,0x17,0xc8,0xa1,0x4b,0x44,0x1b,0xcc,0xc9,0xa1,0xb7,0x2c, +0xb2,0x1d,0xf0,0x40,0xd0,0x74,0xd2,0xcd,0xe7,0x56,0xdd,0xd6,0xd2,0x06,0x24, +0x42,0xc6,0x24,0xd0,0xf4,0x04,0x16,0xaf,0x1b,0xad,0x04,0x8d,0x0c,0xbd,0x0e, +0xb8,0xcb,0x88,0x18,0x0b,0x5b,0xb2,0xcb,0xfe,0xe0,0x08,0x00,0xb1,0x0d,0x37, +0xba,0xb5,0xd2,0x0b,0x7f,0xa0,0xe0,0x74,0xe7,0x9d,0x0b,0xd2,0x0b,0x80,0xa0, +0xe8,0x21,0xe0,0xdd,0xc0,0x16,0xfd,0x17,0x0c,0x9f,0x82,0xa0,0xff,0x82,0x46, +0x24,0xf9,0x01,0x06,0x5d,0x00,0xb2,0xa5,0x00,0xb7,0x24,0x18,0x47,0xab,0x02, +0xc6,0x87,0x00,0x50,0x90,0x31,0xb1,0xdf,0x36,0x50,0xa0,0xf4,0xb0,0xaa,0xa0, +0x99,0x0a,0xa5,0x63,0xff,0x1d,0xf0,0xb2,0xa3,0x00,0xb7,0xa4,0x02,0x06,0x5a, +0x00,0x47,0xab,0x02,0x86,0x73,0x00,0x6c,0xfb,0xe8,0x06,0x50,0xa0,0x04,0x92, +0x2e,0x3e,0xc0,0xaa,0x11,0xb0,0x99,0x10,0xa0,0xb9,0x20,0xb2,0x6e,0x3e,0x1d, +0xf0,0xd7,0x9c,0x0d,0xc2,0x2e,0x3e,0x1c,0x09,0x92,0x6e,0x37,0x70,0xcc,0x10, +0xc6,0x40,0xff,0xa9,0x3e,0x42,0x6e,0x3f,0xdd,0x04,0x82,0x2e,0x3e,0x0c,0x8c, +0xc2,0x6e,0x37,0x9d,0x0c,0xc0,0x88,0x20,0xc2,0xa2,0x00,0xc0,0x88,0x20,0x82, +0x6e,0x3e,0x82,0x2e,0x36,0x66,0xb8,0x16,0x66,0x89,0x13,0x0c,0x07,0xad,0x0e, +0x88,0x03,0xf0,0xcd,0x11,0x82,0x28,0x42,0x5c,0x0b,0xe0,0x08,0x00,0xc6,0x03, +0x00,0x0c,0x07,0xad,0x0e,0x88,0x03,0xcd,0x0d,0x82,0x28,0x42,0x5c,0x0b,0xe0, +0x08,0x00,0xe8,0x06,0x92,0x2e,0x3e,0x90,0x90,0x04,0x16,0x99,0x0a,0xa2,0x2e, +0x36,0xa2,0xca,0xd0,0x56,0x0a,0x0a,0xc2,0x2e,0x37,0xc2,0xcc,0xf0,0x56,0x7c, +0x09,0x42,0x5e,0x7a,0x42,0x5e,0x7b,0xad,0x0e,0x88,0x03,0x50,0xb0,0xf4,0x82, +0x28,0x3d,0xc2,0xa0,0x8b,0xe0,0x08,0x00,0x4d,0x0a,0xb8,0x06,0xa9,0x51,0xa2, +0x2b,0x3e,0xb2,0x2b,0x3f,0xa0,0xa3,0x04,0xf0,0xbb,0x11,0xe5,0x42,0xff,0xb1, +0xca,0x36,0x8c,0x54,0x98,0x0b,0x8c,0x19,0x66,0x05,0x0e,0x58,0x51,0xa5,0x55, +0xff,0xb1,0xc6,0x36,0x98,0x0b,0x90,0x57,0x83,0x4d,0x05,0x8c,0x04,0xcc,0xd9, +0xa8,0x06,0x72,0x6a,0xbd,0xe5,0x44,0xff,0xd1,0xc0,0x36,0x0c,0x1c,0xc9,0x0d, +0xe8,0x06,0xf2,0x2e,0x40,0x66,0x2f,0x31,0x51,0x94,0x36,0x41,0x9f,0x36,0x0c, +0x03,0xa2,0xaf,0xbf,0x0c,0x0b,0x88,0x05,0x0c,0x0c,0x82,0x28,0x2c,0xdd,0x04, +0xe0,0x08,0x00,0x0c,0x0a,0xbd,0x03,0xe5,0x72,0xff,0x42,0xc4,0x10,0x1b,0x33, +0x66,0x83,0xdf,0xe8,0x06,0x0c,0x39,0x72,0x6e,0x42,0x92,0x6e,0x40,0x72,0x6e, +0xc5,0x1d,0xf0,0x72,0x5e,0x7a,0x4d,0x07,0x86,0xd8,0xff,0xa1,0x27,0x36,0xa7, +0xa4,0x02,0x06,0x35,0x00,0x47,0xaa,0x02,0xc6,0x37,0x00,0x98,0x0c,0x99,0x05, +0x1d,0xf0,0xa9,0x01,0xb1,0x93,0x36,0xa8,0xcb,0xd2,0x06,0x24,0xa2,0xca,0xfe, +0xa9,0xcb,0xd0,0x90,0x24,0xbc,0x69,0x0b,0xb9,0x16,0x1b,0x2f,0x48,0x01,0xc6, +0x13,0x00,0xc2,0xd4,0xfe,0x56,0x1c,0xb9,0x50,0xb0,0x04,0xe8,0x06,0xc2,0xad, +0xff,0x92,0x2e,0x3e,0xd8,0x3e,0xc0,0x99,0x10,0xa0,0xdd,0xc0,0x70,0xcb,0x11, +0xc0,0x99,0x20,0x92,0x6e,0x3e,0x56,0x2d,0xb7,0x30,0x99,0x10,0xd0,0xab,0x11, +0x86,0x9f,0xff,0x7c,0xfa,0xb1,0x95,0x36,0x4b,0xc1,0xe5,0xb4,0xfb,0xd8,0x11, +0x4d,0x0a,0x9c,0x0d,0xa8,0x06,0xc2,0xa0,0x8b,0x88,0x03,0xb1,0x68,0x36,0x82, +0x28,0x3d,0xb8,0x1b,0xe0,0x08,0x00,0xcd,0x04,0x88,0x07,0x1c,0x8a,0x88,0xf8, +0x0c,0x7b,0xe0,0x08,0x00,0x1d,0xf0,0xa8,0x06,0xa2,0x2a,0x3f,0xf0,0xaa,0x11, +0xa5,0x2a,0xff,0x1d,0xf0,0xb2,0xa4,0x00,0xc2,0xd4,0xfc,0x56,0x2c,0xb2,0xa0, +0xe5,0xc0,0x16,0xae,0x26,0xd0,0xf5,0xc0,0x16,0x4f,0x26,0xe8,0x06,0x58,0x3e, +0x92,0x2e,0x3e,0xd0,0x85,0xc0,0x30,0xa9,0x10,0x56,0x48,0x09,0x9d,0x0a,0xa2, +0x6e,0x3e,0xad,0x0b,0x46,0x84,0xff,0xa1,0x7b,0x36,0xa7,0x24,0x30,0x47,0x2a, +0x47,0xad,0x05,0xa5,0x51,0xff,0x1d,0xf0,0xa1,0xe9,0x35,0xa7,0x24,0x2d,0x47, +0x2a,0x44,0x98,0x06,0x92,0x29,0x45,0x46,0xc8,0xff,0xa1,0xf5,0x35,0xa7,0x24, +0x44,0x47,0xaa,0x02,0xc6,0xb3,0xfe,0xa8,0x06,0xf2,0x6a,0xbd,0xe5,0x2f,0xff, +0x1d,0xf0,0xa2,0xd4,0xf9,0x56,0xfa,0xab,0xad,0x05,0x65,0x4d,0xff,0x1d,0xf0, +0xb2,0xd4,0xf4,0x56,0x2b,0xab,0xc8,0x06,0x52,0x6c,0x45,0x1d,0xf0,0xd2,0xd4, +0xf7,0x56,0x5d,0xaa,0xe8,0x06,0x52,0x6e,0x3f,0x1d,0xf0,0xf2,0xd4,0xf2,0x56, +0x8f,0xa9,0x98,0x06,0x92,0x29,0x40,0x86,0xb5,0xff,0xa2,0xd4,0xf0,0x56,0xaa, +0xa8,0x0c,0x1a,0x1c,0x9b,0x7c,0xfc,0x98,0x06,0x88,0x07,0x52,0x69,0x36,0x91, +0x27,0x36,0x88,0xf8,0x59,0x09,0xe0,0x08,0x00,0x1d,0xf0,0x90,0x99,0x04,0xd0, +0x99,0x11,0x90,0x9a,0x20,0xad,0x09,0x86,0xd7,0xff,0x50,0xa0,0x35,0x50,0xf4, +0x35,0xb2,0x6e,0x40,0xc1,0x2a,0x36,0xb2,0x6e,0x42,0xc8,0x2c,0x50,0xd0,0xf4, +0xf0,0xcd,0x83,0xc2,0x6e,0x41,0x8c,0x7a,0xb2,0x6e,0x43,0x50,0xd8,0x75,0xd2, +0x6e,0x44,0x0c,0x03,0xa2,0xaf,0xbf,0xbd,0x03,0xa5,0x57,0xff,0x1b,0x33,0x66, +0x83,0xf2,0x1d,0xf0,0x88,0x03,0xad,0x0e,0x82,0x28,0x39,0xbd,0x04,0xe0,0x08, +0x00,0xec,0x9a,0x88,0x03,0xa8,0x06,0x82,0x28,0x38,0xbd,0x04,0xe0,0x08,0x00, +0xdc,0xba,0x88,0x03,0x82,0x28,0x45,0xa8,0x06,0xe0,0x08,0x00,0x47,0x1a,0x0f, +0xa8,0x06,0x88,0x03,0xbd,0x04,0x82,0x28,0x3a,0x7c,0xfc,0xe0,0x08,0x00,0x1d, +0xf0,0xe8,0x06,0xb1,0x3a,0x36,0xe0,0xa4,0x11,0xa9,0x61,0xc2,0xcb,0x10,0xc0, +0xc4,0xa0,0xba,0xaa,0xb2,0x2a,0x7f,0x52,0x6a,0x7f,0xb0,0xb5,0xc0,0xb0,0xb2, +0x21,0xb2,0x6c,0x7f,0x92,0x2e,0xc6,0xac,0x09,0x88,0x03,0xad,0x0e,0x82,0x28, +0x38,0xbd,0x04,0xe0,0x08,0x00,0xe8,0x06,0xdc,0x0a,0x88,0x03,0x82,0x28,0x45, +0xad,0x0e,0xe0,0x08,0x00,0xe8,0x06,0x40,0x9a,0xc0,0x56,0x99,0x11,0xcd,0x05, +0x88,0x03,0xbd,0x04,0x82,0x28,0x49,0xad,0x0e,0xe0,0x08,0x00,0x41,0xef,0x35, +0x96,0x8a,0x99,0xe8,0x06,0x88,0x03,0x82,0x28,0x4a,0xad,0x0e,0xe0,0x08,0x00, +0x88,0x03,0x82,0x28,0x4b,0xa8,0x06,0xe0,0x08,0x00,0xa8,0x06,0x8b,0xb1,0x88, +0x03,0xcb,0xc1,0x82,0x28,0x44,0xd2,0xc1,0x10,0xe0,0x08,0x00,0xe8,0x06,0xa2, +0x6e,0xc5,0x98,0x21,0x16,0x69,0x08,0xb8,0x24,0xa6,0x1b,0x2f,0x0b,0xab,0xa9, +0x24,0x25,0x05,0xff,0xe8,0x06,0xc1,0x0f,0x36,0xd2,0x2e,0x3f,0xb2,0x2e,0x34, +0xb2,0x5c,0x76,0xb2,0x5c,0x86,0xb2,0x5c,0x77,0xb2,0x5c,0x87,0xd2,0xcd,0x10, +0xd2,0x5c,0x78,0xd2,0x5c,0x88,0xb2,0xcb,0x10,0xb2,0x5c,0x79,0xb2,0x5c,0x89, +0x88,0x03,0x82,0x28,0x34,0xad,0x0e,0xe0,0x08,0x00,0xa8,0x06,0x25,0xa1,0x02, +0xe8,0x06,0x92,0x2e,0xc5,0xec,0x69,0xa1,0xed,0x35,0xa8,0xfa,0xfc,0x3a,0x1c, +0x5a,0x88,0x07,0x0c,0x0b,0x88,0xf8,0x0c,0x0c,0xe0,0x08,0x00,0x88,0x03,0x82, +0x28,0x50,0xa8,0x06,0xe0,0x08,0x00,0xa1,0xe6,0x35,0x0c,0x19,0x99,0xfa,0xc6, +0x04,0x00,0x88,0x03,0x82,0x28,0x50,0xad,0x0e,0xe0,0x08,0x00,0x88,0x03,0x82, +0x28,0x4e,0xa8,0x06,0xe0,0x08,0x00,0x98,0x31,0x16,0xb9,0x8d,0xa8,0x06,0xb2, +0xc1,0x10,0x25,0x84,0x02,0xa8,0xc4,0xb8,0x84,0xc8,0x41,0xe5,0x53,0xfe,0xa8, +0xd4,0xb8,0x94,0xc8,0x41,0x65,0x53,0xfe,0xa8,0x06,0xb8,0x41,0x65,0x57,0x02, +0xa8,0x06,0xb8,0x41,0x65,0xac,0x02,0x1d,0xf0,0xe8,0x06,0x59,0x3e,0xc6,0x65, +0xff,0xad,0x04,0xb1,0xd0,0x35,0xc2,0xa0,0xef,0xc0,0xcd,0x10,0xc2,0x46,0x24, +0xb8,0xcb,0x65,0xc6,0xfe,0x4d,0x0a,0x86,0x52,0xff,0xf8,0x61,0xd2,0x2e,0x27, +0x41,0xab,0x35,0xfa,0xdd,0xd2,0xdd,0xff,0x52,0x6d,0x36,0x06,0xba,0xff,0x00, +0x00,0x36,0x41,0x00,0x32,0x62,0x2f,0x26,0x03,0x4c,0x3c,0x04,0xb2,0x12,0x75, +0x62,0x22,0x36,0xb0,0xb3,0xc0,0x20,0xbb,0xa0,0x47,0x96,0x11,0x52,0x22,0x37, +0x61,0xd6,0x35,0x82,0xc5,0xf8,0x56,0x58,0x09,0x51,0xd5,0x35,0x46,0x04,0x00, +0x66,0xb6,0x08,0x51,0xd5,0x35,0x61,0xd3,0x35,0x46,0x01,0x00,0x51,0xd4,0x35, +0x61,0xd3,0x35,0x52,0x6b,0x47,0xa2,0x12,0x75,0xa0,0xa3,0xc0,0x20,0xaa,0xa0, +0x62,0x6a,0x4b,0x92,0x22,0x3e,0x17,0x69,0x02,0x26,0xb3,0x01,0x1d,0xf0,0xa2, +0x12,0x75,0xe0,0xaa,0x11,0xa0,0xa2,0xc0,0x52,0x6a,0x58,0x92,0x12,0x75,0xe0, +0x99,0x11,0x90,0x92,0xc0,0x52,0x69,0x59,0x82,0x12,0x75,0x0c,0x0e,0xe0,0x88, +0x11,0x80,0x82,0xc0,0xe2,0x68,0x5b,0x42,0x12,0x75,0xe0,0x44,0x11,0x40,0x42, +0xc0,0xe2,0x64,0x5c,0x32,0x12,0x75,0xe0,0x33,0x11,0x30,0x32,0xc0,0xe2,0x63, +0x5c,0xf2,0x12,0x75,0xe0,0xff,0x11,0xf0,0xf2,0xc0,0xe2,0x6f,0x5d,0xd2,0x12, +0x75,0xe0,0xdd,0x11,0xd0,0xd2,0xc0,0x62,0x6d,0x5f,0xc2,0x12,0x75,0xe0,0xcc, +0x11,0xc0,0xc2,0xc0,0x62,0x6c,0x60,0x1d,0xf0,0x66,0xb5,0x08,0x61,0xb3,0x35, +0x51,0xb3,0x35,0x46,0xdd,0xff,0x61,0xb0,0x35,0x51,0xaf,0x35,0x06,0xdb,0xff, +0x00,0x00,0x00,0x36,0x01,0x01,0x41,0x7b,0x35,0x88,0x04,0xad,0x02,0x82,0x28, +0x39,0xbd,0x03,0xe0,0x08,0x00,0x16,0xda,0x1b,0x88,0x04,0xad,0x02,0x82,0x28, +0x48,0xbd,0x03,0xe0,0x08,0x00,0xcc,0x7a,0x92,0x22,0x36,0x92,0xc9,0xd0,0x56, +0x69,0x1a,0xad,0x02,0xbd,0x03,0x0c,0x1c,0xa5,0x46,0x00,0x30,0xc0,0xf4,0x0c, +0x1b,0xd2,0xc1,0x10,0x88,0x04,0x6d,0x0a,0x82,0x28,0x3b,0xad,0x02,0xe0,0x08, +0x00,0xa0,0x90,0xf4,0xe6,0x19,0x02,0x06,0x60,0x00,0x62,0x61,0x17,0x32,0xc1, +0x10,0x30,0x59,0x90,0xe2,0x93,0x00,0x1b,0xde,0x16,0x7d,0x16,0x42,0x22,0x23, +0x40,0x4e,0xa0,0x48,0x04,0xf2,0xc4,0xf6,0x16,0x9f,0x15,0xa8,0x92,0xa0,0xae, +0xa0,0xa8,0x0a,0xf0,0x74,0x11,0x16,0xca,0x14,0xb8,0xe2,0xc2,0x22,0x10,0xb0, +0xb4,0x90,0xc0,0xc4,0x90,0xc2,0x9c,0x00,0xb2,0x9b,0x00,0xc0,0xbb,0xc0,0xb2, +0xcb,0xf8,0xe6,0x1b,0x02,0xc6,0x4b,0x00,0x81,0x91,0x34,0x88,0x08,0x88,0x98, +0xb2,0x61,0x15,0xe0,0x08,0x00,0x7c,0xc9,0x90,0x6a,0x10,0x97,0x8a,0x02,0xc6, +0x45,0x00,0xa2,0x12,0x7a,0xa7,0xa6,0x02,0x86,0x43,0x00,0xb2,0x12,0x62,0x67, +0xab,0x01,0x6d,0x0b,0xb2,0x22,0x30,0xcd,0x06,0xd8,0x92,0x88,0x02,0xa2,0x93, +0x00,0x88,0x98,0xd0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x81,0x45,0x35,0x88, +0x08,0xa2,0x22,0x30,0x82,0x28,0x17,0xbd,0x06,0xe0,0x08,0x00,0xa2,0x22,0x23, +0xe2,0x93,0x00,0xb2,0x22,0x22,0xa0,0xae,0xa0,0xa8,0x0a,0xb0,0xaa,0xa0,0xa8, +0x0a,0xe0,0x9e,0x11,0x96,0x5a,0x00,0xb2,0x22,0x3e,0x47,0x6b,0x20,0xa2,0x22, +0x30,0xbd,0x06,0xc1,0xc9,0x34,0x81,0x37,0x35,0xc0,0xee,0x11,0x88,0x08,0xd2, +0x22,0x18,0x82,0x28,0x2d,0xea,0xdd,0xe0,0x08,0x00,0x92,0x93,0x00,0xe0,0x99, +0x11,0xa2,0x22,0x2b,0x9a,0xaa,0xa8,0x0a,0x16,0x6a,0x09,0xb2,0x22,0x3e,0xa2, +0x61,0x16,0x87,0x6b,0x2f,0xd2,0x22,0x12,0xc2,0x12,0x77,0x7a,0xdd,0xd2,0x9d, +0x00,0xd7,0xac,0x21,0x81,0x29,0x35,0x88,0x08,0xa2,0x21,0x17,0x82,0x28,0x25, +0xb2,0x22,0x3c,0xe0,0x08,0x00,0xb2,0x22,0x2b,0x92,0x93,0x00,0xa2,0x61,0x17, +0xb0,0x99,0xa0,0x98,0x09,0x92,0x61,0x16,0xa2,0x21,0x16,0x60,0xe0,0xf4,0xd2, +0x21,0x17,0x81,0x3d,0x35,0xb2,0x22,0x30,0xf2,0x21,0x15,0x98,0xc2,0xc2,0x22, +0x10,0x90,0x94,0xa0,0x7a,0xcc,0xc2,0x9c,0x00,0x98,0x09,0xf9,0x01,0x88,0x08, +0x90,0xcc,0xa0,0x82,0x28,0x16,0xf2,0xc1,0x50,0xe0,0x08,0x00,0xe2,0x21,0x14, +0x66,0x8a,0x0c,0xb2,0x22,0x14,0xba,0xb7,0xa2,0x9b,0x00,0x1b,0xaa,0xa2,0x5b, +0x00,0x82,0x22,0x10,0xd2,0x22,0x11,0x8a,0x87,0xf2,0x98,0x00,0xda,0xd7,0xea, +0xff,0xf2,0x58,0x00,0xc2,0x9d,0x00,0xea,0xcc,0xc2,0x5d,0x00,0x2b,0x33,0x50, +0x93,0xc0,0x56,0x79,0xe8,0x1d,0xf0,0x00,0x00,0x00,0x36,0x21,0x01,0x82,0x22, +0x35,0x56,0xc8,0x0b,0x41,0x03,0x35,0x88,0x04,0xad,0x02,0x82,0x28,0x39,0xbd, +0x03,0xe0,0x08,0x00,0x16,0xaa,0x0a,0x88,0x04,0xad,0x02,0x82,0x28,0x48,0xbd, +0x03,0xe0,0x08,0x00,0xcc,0x7a,0x92,0x22,0x36,0x92,0xc9,0xd0,0x56,0x39,0x09, +0xad,0x02,0xbd,0x03,0x0c,0x0c,0xa5,0x28,0x00,0x30,0xc0,0xf4,0x0c,0x0b,0xd2, +0xc1,0x10,0x88,0x04,0xa2,0x61,0x18,0x82,0x28,0x3b,0xad,0x02,0xe0,0x08,0x00, +0xa0,0x90,0xf4,0xa6,0x19,0x6f,0x61,0x2c,0x34,0x32,0xc1,0x10,0x30,0xa9,0x90, +0xa2,0x61,0x19,0xa2,0x93,0x00,0x26,0x0a,0x55,0x82,0x22,0xc1,0x92,0x22,0xc2, +0x66,0x28,0x04,0x98,0x19,0xa7,0x19,0x47,0x52,0x22,0x24,0xb8,0xa2,0x50,0x5a, +0xa0,0xb0,0xaa,0xa0,0xa8,0x0a,0x58,0x05,0xbc,0x5a,0x0c,0xb8,0x87,0x95,0x3b, +0xc6,0x07,0x00,0x00,0x00,0x00,0x0c,0x0b,0xc8,0xa2,0x88,0x06,0xa2,0x93,0x00, +0x88,0x68,0xc0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0xb8,0xa2,0xa2,0x93,0x00, +0xb0,0xaa,0xa0,0xa8,0x0a,0x88,0x06,0x88,0x98,0xe0,0x08,0x00,0x92,0x12,0x74, +0x0b,0x99,0x97,0x3a,0xd3,0xa2,0x21,0x19,0x2b,0x33,0xa7,0x93,0x9b,0x1d,0xf0, +0xf0,0x75,0x11,0xe0,0xb5,0x11,0xb2,0x61,0x1a,0x88,0x06,0x88,0x98,0xe0,0x08, +0x00,0xcc,0xba,0xa2,0x22,0x13,0xaa,0xa7,0x92,0x9a,0x00,0x1b,0x99,0x92,0x5a, +0x00,0xb8,0xa2,0x88,0x06,0xa2,0x93,0x00,0x88,0x98,0xb0,0xaa,0xa0,0xa8,0x0a, +0xe0,0x08,0x00,0x42,0x12,0x74,0xc2,0x22,0xc1,0xa0,0x44,0xc0,0x0b,0x44,0x66, +0x2c,0x25,0xd2,0x22,0xc2,0x82,0x93,0x00,0x98,0x0d,0x97,0x98,0x1a,0xb8,0xa2, +0x88,0x06,0xa8,0x1d,0x88,0x98,0xb0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0xc2, +0x12,0x74,0xa0,0xcc,0xc0,0x0b,0xcc,0xc0,0x44,0x43,0x16,0xe4,0xf8,0xd2,0x12, +0x7b,0xd7,0x24,0x88,0xb2,0x12,0x62,0xd2,0x21,0x18,0x47,0xab,0x01,0x4d,0x0b, +0x66,0x75,0x08,0xe2,0x22,0x3e,0x37,0x6e,0x02,0xf0,0xdd,0x11,0x7c,0xca,0xe1, +0xe1,0x34,0xd0,0xc4,0x82,0xea,0xcc,0xc0,0xc4,0x31,0xd0,0x4c,0x93,0xa0,0xa4, +0x10,0xa2,0xca,0xfc,0xe6,0x1a,0x02,0x46,0xd5,0xff,0xf2,0x22,0x10,0x98,0xe2, +0xfa,0xf7,0x7a,0x99,0x92,0x99,0x00,0x66,0x75,0x0a,0xc2,0x22,0x3e,0x37,0x6c, +0x04,0xe2,0x22,0x33,0x9a,0x9e,0xe2,0x9f,0x00,0xe0,0x49,0xc0,0x40,0x4a,0x43, +0xe6,0x14,0x02,0x06,0xcb,0xff,0xb2,0x61,0x16,0xe2,0x61,0x15,0xa2,0x21,0x1a, +0x98,0xc2,0x82,0x93,0x00,0xaa,0x99,0x98,0x09,0xa2,0x22,0x2b,0x66,0x75,0x07, +0xc2,0x22,0x3e,0x37,0x6c,0x01,0x98,0xd2,0x92,0x61,0x17,0xc2,0x12,0x16,0x42, +0x61,0x14,0xca,0x88,0xcd,0x04,0xa0,0x88,0xa0,0x88,0x08,0x82,0x61,0x1b,0xac, +0xb8,0xa2,0x21,0x1b,0x81,0xb2,0x34,0xc2,0x21,0x17,0x92,0x21,0x16,0xc0,0xbe, +0xa0,0xc2,0x22,0x30,0x99,0x01,0x88,0x08,0xf2,0xc1,0x50,0x82,0x28,0x16,0x40, +0xe0,0xf4,0xe0,0x08,0x00,0xf2,0x22,0x10,0xc2,0x21,0x14,0xfa,0xf7,0xe2,0x9f, +0x00,0xbd,0x0c,0x81,0x88,0x34,0xa2,0x22,0x30,0x88,0x08,0x4a,0x9e,0x82,0x28, +0x19,0x92,0x5f,0x00,0xe0,0x08,0x00,0xb8,0xa2,0x88,0x06,0xa2,0x93,0x00,0x88, +0x98,0xb0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0xc2,0x21,0x14,0xd2,0xa0,0xff, +0xa0,0xdd,0xc0,0xc7,0xbd,0x1e,0xb8,0xa2,0x88,0x06,0xa2,0x93,0x00,0x88,0x98, +0xb0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x7c,0xcd,0xc2,0xa0,0xff,0xa0,0xcc, +0xc0,0xd0,0xcc,0x10,0xc2,0x61,0x14,0xb8,0xa2,0x88,0x02,0xa2,0x93,0x00,0x88, +0x88,0xb0,0xaa,0xa0,0xa8,0x0a,0xb2,0x22,0x30,0xe0,0x08,0x00,0xc2,0x22,0xc1, +0x66,0x2c,0x20,0xd2,0x22,0xc2,0xe2,0x93,0x00,0xf8,0x0d,0xf7,0x9e,0x15,0xb2, +0x22,0x30,0xc2,0x21,0x14,0xe8,0xa2,0x88,0x02,0xa8,0x1d,0x88,0x88,0xe0,0xaa, +0xa0,0xa8,0x0a,0xe0,0x08,0x00,0xb8,0xa2,0xa2,0x93,0x00,0xb0,0xaa,0xa0,0xa8, +0x0a,0x86,0x90,0xff,0x00,0x00,0x36,0x61,0x00,0xbd,0x06,0x0c,0xa8,0xb0,0xc4, +0x11,0xa2,0x12,0x75,0x20,0xd5,0xa0,0xf2,0x2d,0xa9,0xe2,0x2d,0xb3,0xa0,0xa3, +0xc0,0xd2,0x2d,0x9f,0xa0,0xaa,0x11,0xaa,0xa2,0xca,0xaa,0x89,0x01,0xc2,0xa1, +0x7c,0xca,0xaa,0x0c,0x0c,0x25,0x1f,0x03,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41, +0x00,0x52,0x22,0x26,0x82,0x12,0x75,0x62,0x22,0x2f,0x80,0xa3,0xc0,0x80,0x66, +0xc0,0x50,0x66,0xa0,0x68,0x06,0x50,0x5a,0xa0,0x58,0x05,0x20,0xaa,0xa0,0x66, +0x14,0x20,0x92,0x2a,0x4f,0x57,0x99,0x08,0xb2,0x2a,0x53,0x60,0xbb,0xc0,0x16, +0x2b,0x14,0x52,0x6a,0x4f,0xc2,0x12,0x75,0xc0,0xc3,0xc0,0x20,0xcc,0xa0,0x62, +0x6c,0x53,0xc6,0x07,0x00,0xd2,0x2a,0x57,0x57,0x9d,0x0a,0xe2,0x2a,0x5b,0x67, +0x9e,0x04,0x22,0x2a,0x4b,0x1d,0xf0,0x52,0x6a,0x57,0xf2,0x12,0x75,0xf0,0xf3, +0xc0,0x20,0xff,0xa0,0x62,0x6f,0x5b,0x71,0x3c,0x34,0x88,0x07,0xad,0x02,0x82, +0x28,0x38,0xbd,0x03,0xe0,0x08,0x00,0xac,0x5a,0x88,0x07,0xad,0x02,0x82,0x28, +0x39,0xb2,0x22,0x2f,0xe0,0x08,0x00,0x16,0xca,0x0b,0xa2,0x22,0x36,0x3c,0x09, +0x97,0x1a,0x0e,0x5a,0x95,0x9a,0x95,0x66,0xba,0x04,0x5d,0x09,0x86,0x00,0x00, +0xf0,0x59,0x11,0x88,0x07,0xad,0x02,0x82,0x28,0x39,0xbd,0x03,0xe0,0x08,0x00, +0xf2,0x12,0x75,0x9c,0x6a,0x9c,0x43,0xa2,0x22,0x36,0x92,0xca,0xd0,0x56,0xb9, +0x07,0x92,0x22,0x37,0xa2,0xc9,0xf0,0x56,0x3a,0x0a,0x6a,0xb6,0xba,0x66,0xf0, +0xf3,0xc0,0xa0,0xff,0x11,0xfa,0xf2,0x66,0x14,0x31,0xbd,0x05,0xcd,0x06,0x1c, +0x2d,0x1c,0x4e,0xa2,0xa1,0x9c,0xaa,0xaf,0xe5,0xfc,0x02,0x92,0x12,0x75,0x90, +0x93,0xc0,0x20,0xa9,0xa0,0xa0,0x99,0x11,0x9a,0x92,0x92,0x29,0x6d,0x92,0x6a, +0x47,0x82,0x12,0x75,0x80,0x83,0xc0,0x20,0x28,0xa0,0x22,0x22,0x47,0x1d,0xf0, +0xbd,0x06,0xcd,0x05,0x1c,0x2d,0x1c,0x4e,0xa2,0xa1,0x7c,0xaa,0xaf,0xe5,0xf9, +0x02,0x92,0x12,0x75,0x90,0x93,0xc0,0x20,0xa9,0xa0,0xa0,0x99,0x11,0x9a,0x92, +0x92,0x29,0x65,0x92,0x6a,0x4b,0x82,0x12,0x75,0x80,0x83,0xc0,0x20,0x28,0xa0, +0x22,0x22,0x4b,0x1d,0xf0,0x66,0xba,0x8d,0xa2,0x22,0x37,0x66,0x8a,0x87,0x6a, +0x66,0x86,0xe0,0xff,0xb2,0x22,0x3e,0xb0,0xb1,0x04,0x16,0x0b,0xf5,0x88,0x07, +0xad,0x02,0x82,0x28,0x38,0xb2,0x22,0x2f,0xe0,0x08,0x00,0x5a,0x95,0x9a,0x95, +0xf0,0x99,0x11,0xa0,0x59,0x83,0x86,0xcd,0xff,0xa2,0xc9,0xf8,0x56,0x9a,0xf5, +0x6a,0x86,0x8a,0x66,0xf0,0x66,0x11,0xc6,0xd3,0xff,0x22,0x2a,0x47,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x01,0x01,0x42,0x61,0x11,0x82,0x12,0x16,0x32,0x61,0x13, +0xad,0x05,0x31,0xf2,0x33,0x51,0x2d,0x33,0xa2,0x61,0x12,0xe6,0x18,0x02,0x46, +0x28,0x00,0x0c,0x07,0x0c,0x06,0x0c,0x0a,0xa2,0x61,0x15,0xad,0x02,0x0c,0x1b, +0xcd,0x06,0x42,0x22,0x23,0x88,0x03,0x7a,0x44,0x82,0x28,0x3c,0x48,0x04,0xe0, +0x08,0x00,0x88,0x03,0xa2,0x61,0x16,0x82,0x28,0x3f,0xad,0x04,0xe0,0x08,0x00, +0x16,0x3a,0x06,0x98,0x92,0x7a,0x99,0x98,0x09,0x16,0xa9,0x05,0xad,0x02,0x88, +0x03,0xb2,0x21,0x16,0xc2,0x21,0x15,0xb0,0xb0,0xf4,0x1b,0xcc,0x82,0x28,0x48, +0xc2,0x61,0x15,0xe0,0x08,0x00,0x9c,0x2a,0xd2,0x22,0x11,0xe2,0x22,0x33,0xd0, +0xd4,0x90,0xd2,0x9d,0x00,0xe7,0xad,0x31,0x0c,0x09,0xc6,0x10,0x00,0xe2,0x22, +0x36,0x3c,0x0f,0xf7,0x9e,0x11,0x82,0x22,0x11,0x92,0x22,0x34,0x80,0x84,0x90, +0x82,0x98,0x00,0x97,0xa8,0x15,0x06,0xf8,0xff,0xa8,0x92,0x88,0x05,0x7a,0xaa, +0x88,0x98,0xa8,0x0a,0xe0,0x08,0x00,0x92,0x22,0x34,0x97,0x2a,0xcd,0x4b,0x77, +0xa2,0x12,0x16,0x1b,0x66,0xa7,0xa6,0x02,0x46,0xda,0xff,0x06,0x01,0x00,0x0c, +0x0b,0xb2,0x61,0x15,0x0c,0x19,0xd2,0x21,0x13,0xe2,0x21,0x15,0x0c,0x0a,0xe0, +0xa9,0x93,0xa9,0x0d,0x66,0x1a,0x12,0x92,0x22,0x35,0x16,0x09,0x18,0x0c,0x1f, +0x0b,0x89,0x82,0x62,0x35,0xf2,0x61,0x14,0x06,0x01,0x00,0x0c,0x09,0x92,0x61, +0x14,0x52,0x12,0x75,0xa2,0x12,0x76,0x57,0xba,0x02,0x06,0x3b,0x00,0x0c,0x19, +0x0c,0x0a,0xa2,0x61,0x17,0x92,0x61,0x10,0xad,0x02,0xbd,0x05,0xe5,0xf9,0x01, +0x16,0xca,0x09,0x42,0x22,0x32,0x88,0x03,0xad,0x02,0x82,0x28,0x48,0xbd,0x05, +0xe0,0x08,0x00,0xac,0xaa,0xad,0x02,0xbd,0x05,0x0c,0x1c,0xe5,0xd5,0xff,0x9c, +0xfa,0xb1,0xdf,0x33,0x91,0xdf,0x33,0xba,0xba,0xb7,0x39,0x02,0xc6,0x24,0x00, +0x0c,0x02,0xd2,0x21,0x11,0x0c,0x0c,0xc9,0x0d,0x1d,0xf0,0x0c,0x44,0x40,0x4a, +0x53,0x80,0x44,0x10,0xad,0x02,0x0c,0x1b,0x88,0x03,0xcd,0x05,0x82,0x28,0x3b, +0xdd,0x01,0xe0,0x08,0x00,0xa6,0x1a,0x4c,0x6d,0x01,0x7d,0x01,0x70,0x7a,0x90, +0x92,0x96,0x00,0x26,0x09,0x58,0xa2,0x22,0x23,0xa0,0xa9,0xa0,0xa8,0x0a,0xe6, +0x7a,0x4d,0xb8,0x92,0xb0,0xb9,0xa0,0xb8,0x0b,0x16,0x3b,0x04,0x88,0x03,0x82, +0x28,0x3e,0xe0,0x08,0x00,0xbc,0x8a,0xb8,0x92,0x81,0xcf,0x32,0xa2,0x96,0x00, +0x88,0x08,0xb0,0xaa,0xa0,0x88,0x98,0xa8,0x0a,0xe0,0x08,0x00,0x47,0xba,0x1d, +0x0c,0x09,0x0c,0x1a,0xa2,0x61,0x17,0x92,0x61,0x10,0xb2,0x12,0x76,0x1b,0x55, +0x50,0x50,0xf4,0x57,0x3b,0x02,0x86,0xd2,0xff,0x92,0x21,0x10,0x86,0x0b,0x00, +0x0c,0x18,0x82,0x61,0x17,0x2b,0x66,0x77,0x96,0x9b,0x86,0xf7,0xff,0x7c,0xc8, +0xb1,0xb1,0x33,0x40,0xaa,0x82,0xba,0xaa,0xb2,0x12,0x62,0xa0,0xa4,0x31,0xa7, +0x2b,0x02,0x06,0xd8,0xff,0x4d,0x0b,0x06,0xd8,0xff,0x0c,0x19,0x0c,0x0c,0xc2, +0x61,0x17,0xd2,0x21,0x17,0x0c,0x0a,0x8c,0x3d,0x0c,0x1e,0x90,0xae,0x93,0xf2, +0x21,0x11,0x82,0x21,0x12,0xa9,0x0f,0x49,0x08,0xf8,0x0f,0x66,0x1f,0x23,0xa2, +0x22,0x3e,0x0c,0x19,0x57,0x6a,0x16,0xb2,0x21,0x13,0x0c,0x2c,0xc2,0x62,0x35, +0xb8,0x0b,0x66,0x1b,0x0e,0x92,0x62,0x35,0x92,0x61,0x14,0x46,0x01,0x00,0x00, +0x0c,0x0e,0xe2,0x62,0x35,0xf2,0x21,0x14,0x9c,0xff,0xa2,0x12,0x17,0xa6,0x1a, +0x1a,0x92,0x22,0x24,0x0c,0x06,0x76,0x9a,0x19,0x88,0x09,0x4b,0x99,0x66,0x68, +0x10,0xa2,0x22,0x19,0xc0,0xb6,0x11,0xba,0xaa,0x98,0x2a,0x99,0x1a,0x22,0x21, +0x14,0x1d,0xf0,0x1b,0x66,0x46,0xfd,0xff,0x0c,0x0c,0xc2,0x61,0x14,0x06,0xa2, +0xff,0x00,0x00,0x00,0x36,0x41,0x00,0xed,0x03,0x81,0x5d,0x33,0x51,0x90,0x33, +0x91,0x5b,0x33,0xf0,0x64,0x00,0x98,0x29,0xb2,0xc5,0xe0,0xc0,0x99,0x11,0x9a, +0x88,0x88,0x28,0x92,0xc2,0xf6,0xe0,0xa9,0x11,0x00,0x0a,0x40,0xa2,0xc5,0xf0, +0x80,0x80,0xb1,0x80,0x80,0x34,0xec,0xd8,0xd8,0x0b,0x50,0xc2,0xb0,0xc2,0xdc, +0xff,0xc2,0x2c,0x2c,0xd0,0xdc,0xa0,0x88,0x0d,0xe0,0xcc,0x11,0x66,0x28,0x44, +0x88,0x1b,0x80,0xcc,0xa0,0xb8,0x1c,0xa0,0x89,0xa0,0xbc,0x7b,0xb9,0x08,0x0c, +0x08,0x89,0x1c,0x0c,0x18,0x89,0x0d,0xc6,0x0a,0x00,0xa0,0xc2,0xa0,0xc2,0xdc, +0xff,0xc2,0x2c,0x36,0xd8,0x1b,0x9c,0xdc,0x48,0x0b,0xa0,0x89,0xa0,0x50,0x32, +0xb0,0x32,0xd3,0xff,0x32,0x23,0x2c,0x88,0x08,0xe0,0xc3,0x11,0x40,0x33,0xa0, +0xd0,0xcc,0xa0,0x89,0x1c,0x0c,0x2d,0xd9,0x03,0xf0,0xe6,0x13,0x20,0x20,0x00, +0x0c,0x8a,0x0c,0x0b,0x81,0x72,0x32,0x0c,0x4c,0x88,0x08,0xd2,0xa2,0x00,0x82, +0x28,0x10,0xd0,0xd2,0x20,0xe0,0x08,0x00,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c, +0x93,0x37,0x12,0x23,0x26,0x92,0x49,0x0c,0xb4,0x47,0x12,0x4e,0x26,0xa2,0x50, +0x0c,0xd8,0x87,0x12,0x37,0x1c,0x39,0x97,0x12,0x3c,0x1c,0x4a,0xa7,0x12,0x2d, +0x1c,0x5b,0xb7,0x12,0x32,0x7c,0xf2,0x46,0x00,0x00,0x0c,0x02,0xf6,0xa2,0x1a, +0x81,0x5b,0x33,0xc0,0x32,0x11,0x8a,0x33,0xc0,0x20,0x00,0x22,0x13,0x85,0x1b, +0x22,0xc0,0x20,0x00,0x32,0x13,0x82,0x30,0x22,0xe0,0x1d,0xf0,0x0c,0x02,0x1d, +0xf0,0x0c,0x42,0x06,0xf6,0xff,0x0c,0xa2,0xc6,0xf4,0xff,0x0c,0x22,0x86,0xf3, +0xff,0x0c,0x62,0x46,0xf2,0xff,0x0c,0x82,0x06,0xf1,0xff,0x00,0x00,0x00,0x36, +0x41,0x00,0xe5,0x46,0x00,0x8c,0xfa,0xa6,0x13,0x0d,0x20,0x33,0xa0,0xa2,0x92, +0x00,0x25,0x19,0x00,0x4b,0x22,0x37,0x92,0xf4,0x1d,0xf0,0x00,0x36,0x41,0x00, +0x3d,0x02,0x21,0x45,0x33,0x88,0x02,0x1c,0x4a,0x82,0x28,0x1d,0x0c,0x4b,0xe0, +0x08,0x00,0x0c,0x4b,0x88,0x02,0x2d,0x0a,0x82,0x28,0x1d,0xe0,0xa3,0x11,0xe0, +0x08,0x00,0x39,0x32,0xa9,0x02,0xa9,0x12,0xa9,0x22,0x0c,0x09,0x99,0x42,0x1d, +0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x91,0x39,0x33,0xb8,0x19,0xa1,0x39,0x33, +0x9c,0x5b,0x00,0x22,0x11,0xa0,0x22,0x20,0x88,0x0b,0x27,0x98,0x03,0x0c,0x12, +0x1d,0xf0,0xb8,0x7b,0x56,0x1b,0xff,0x46,0x01,0x00,0x00,0x22,0x11,0xa0,0x22, +0x20,0x81,0x2f,0x33,0x88,0x08,0x2c,0x4a,0x82,0x28,0x1d,0x0c,0x4b,0xe0,0x08, +0x00,0x69,0x2a,0x49,0x3a,0x59,0x5a,0x79,0x4a,0x32,0x5a,0x10,0x29,0x0a,0xb1, +0x28,0x33,0x0c,0x0c,0xc9,0x1a,0xc9,0x6a,0xc2,0x5a,0x11,0xc9,0x7a,0xb8,0x1b, +0x0c,0x02,0xcc,0x6b,0xd1,0x23,0x33,0xa9,0x1d,0x06,0x03,0x00,0x98,0x7b,0x8c, +0x59,0xbd,0x09,0x98,0x79,0x56,0x89,0xff,0xa9,0x7b,0x1d,0xf0,0x00,0x00,0x00, +0x36,0x41,0x00,0x61,0x1c,0x33,0x00,0x22,0x11,0x68,0x16,0x41,0x1b,0x33,0x9c, +0x06,0x40,0x22,0x20,0x58,0x06,0x27,0x95,0x04,0x0c,0x02,0x86,0x01,0x00,0x68, +0x76,0x56,0x06,0xff,0x0c,0x22,0x26,0x22,0x01,0x39,0x46,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x61,0x11,0x33,0x00,0x22,0x11,0x68,0x16,0x41,0x10,0x33,0x9c,0x06, +0x40,0x22,0x20,0x58,0x06,0x27,0x95,0x04,0x0c,0x02,0x86,0x01,0x00,0x68,0x76, +0x56,0x06,0xff,0x0c,0x22,0x26,0x22,0x01,0x39,0x26,0x1d,0xf0,0x00,0x36,0x41, +0x00,0x21,0x06,0x33,0x28,0x12,0x0c,0x03,0xbc,0x62,0x88,0x32,0xec,0xd8,0xa2, +0x92,0x11,0x92,0x92,0x10,0x1b,0xba,0xb2,0x52,0x11,0xa7,0x99,0x20,0x40,0x64, +0x00,0x0c,0x4a,0xbd,0x02,0x65,0x14,0x00,0x0c,0x4a,0x8b,0xb2,0xe5,0x13,0x00, +0xa8,0x22,0xb8,0x42,0xa5,0x13,0x00,0x40,0xe6,0x13,0x20,0x20,0x00,0x32,0x52, +0x11,0x28,0x72,0x56,0x72,0xfc,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x4d,0x02, +0x21,0xf3,0x32,0x81,0xf4,0x32,0x28,0x12,0x00,0x54,0x11,0x9c,0x12,0x80,0x55, +0x20,0x98,0x02,0x57,0x99,0x05,0x0c,0x0a,0xa9,0x62,0x1d,0xf0,0x28,0x72,0x56, +0xf2,0xfe,0x1d,0xf0,0x00,0x36,0x41,0x00,0x80,0xa2,0x23,0x25,0xfd,0xff,0x8c, +0x4a,0x0c,0x02,0x39,0x1a,0x1d,0xf0,0x0c,0x22,0x1d,0xf0,0x00,0x00,0x00,0x36, +0x41,0x00,0x80,0xa2,0x23,0x0c,0x24,0x65,0xfb,0xff,0x3d,0x0a,0xac,0x6a,0x88, +0x5a,0xec,0x28,0x98,0x1a,0x9c,0xe9,0x20,0x64,0x00,0x0c,0x4a,0xbd,0x03,0x65, +0x0c,0x00,0x0c,0x4a,0x8b,0xb3,0xe5,0x0b,0x00,0xa8,0x23,0xb8,0x43,0x65,0x0b, +0x00,0x20,0xe6,0x13,0x20,0x20,0x00,0x0c,0x04,0x2d,0x04,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x71,0xd5,0x32,0x0c,0x05,0x68,0x27,0x1c,0x03,0x48,0x06,0x49,0x16, +0x49,0x26,0x76,0xa3,0x07,0x88,0x26,0x4b,0x98,0x99,0x26,0x59,0x08,0xa8,0x22, +0x48,0x37,0x9c,0x1a,0x1c,0x0b,0xc8,0x04,0xc9,0x14,0xc9,0x24,0x76,0xab,0x07, +0xd8,0x24,0x4b,0xed,0xe9,0x24,0x59,0x0d,0x1d,0xf0,0x36,0x41,0x00,0x68,0x12, +0x58,0x22,0x28,0x32,0x67,0x35,0x0c,0x60,0x35,0xc0,0x3b,0x23,0x30,0x23,0xb3, +0x20,0x22,0x21,0x1d,0xf0,0x50,0x86,0xc0,0x3b,0x38,0x80,0x38,0xb3,0x30,0x32, +0x21,0x30,0x22,0xc0,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0xa1,0xbc,0x32, +0x88,0x3a,0xa8,0x2a,0x20,0xa8,0x93,0x65,0xfc,0xff,0x2d,0x0a,0x1d,0xf0,0x36, +0x41,0x00,0x68,0x02,0x38,0x12,0x48,0x32,0x58,0x03,0x60,0x44,0xa0,0x4b,0x33, +0x39,0x12,0x47,0x33,0x01,0x69,0x12,0x2d,0x05,0x1d,0xf0,0x00,0x36,0x41,0x00, +0xa1,0xb0,0x32,0x88,0x3a,0xa8,0x2a,0x20,0xa8,0x93,0x65,0xfd,0xff,0x2d,0x0a, +0x1d,0xf0,0x36,0x41,0x00,0x0c,0x0a,0x65,0xfb,0xff,0xb1,0xaa,0x32,0x20,0xc2, +0x21,0xb8,0x2b,0xaa,0x8c,0x98,0x3b,0xa8,0x2b,0x97,0x38,0x03,0x0c,0x32,0x1d, +0xf0,0x0c,0x02,0xa6,0x1c,0x1e,0x76,0xac,0x1b,0xc8,0x0b,0x4b,0xda,0xf8,0x03, +0x4b,0x33,0xd9,0x2b,0xf9,0x0a,0xe8,0x3b,0xad,0x0d,0xc0,0xee,0xa0,0xe7,0x3d, +0x03,0xad,0x0c,0xc9,0x2b,0x3d,0xf0,0x1d,0xf0,0x00,0x36,0x41,0x00,0x51,0x9a, +0x32,0x58,0x35,0x9c,0x05,0xa8,0x25,0x68,0x05,0x4b,0x8a,0x89,0x25,0x29,0x0a, +0x98,0x35,0x60,0x99,0xa0,0x97,0xb8,0x01,0x1d,0xf0,0x69,0x25,0x1d,0xf0,0x00, +0x00,0x36,0x41,0x00,0x61,0x91,0x32,0x48,0x02,0x51,0x91,0x32,0x8d,0x04,0x1b, +0x44,0x37,0xa8,0x1b,0xa8,0x36,0x25,0xf5,0xff,0xa0,0xb0,0xf4,0x57,0x9b,0x09, +0x49,0x02,0xa0,0x20,0x31,0x80,0x22,0x23,0x1d,0xf0,0x16,0x0b,0xfe,0x7c,0xe2, +0x1d,0xf0,0x49,0x02,0x7c,0xf2,0x1d,0xf0,0x36,0x41,0x00,0x0c,0x08,0x31,0x83, +0x32,0x7c,0xf2,0x29,0x93,0x89,0x73,0x89,0x83,0x89,0xb3,0x89,0xa3,0x1d,0xf0, +0x00,0x00,0x36,0x61,0x00,0x31,0x7e,0x32,0x0c,0x05,0x88,0x73,0x59,0x01,0x8c, +0x28,0x7c,0xe2,0x1d,0xf0,0xa8,0x33,0x65,0xec,0xff,0x4d,0x0a,0x16,0xea,0x08, +0x0c,0x26,0xb8,0x83,0x0c,0x37,0x16,0x4b,0x09,0xc2,0xcb,0xfe,0x16,0x5c,0x0a, +0x66,0x3b,0x01,0x28,0xa3,0xb8,0x01,0x47,0xab,0x69,0xdd,0x02,0x0b,0x22,0xa6, +0x1d,0x30,0xa8,0x33,0x1b,0xeb,0xe9,0x01,0xa5,0xed,0xff,0xb8,0xc3,0x9c,0x0b, +0xf8,0x5b,0x66,0x1f,0x0c,0x88,0x6b,0x98,0x4b,0x1b,0xc8,0xc9,0x6b,0x90,0x88, +0xa0,0xa9,0x08,0xe8,0x2b,0xd8,0x6b,0xe0,0xe2,0x21,0xe7,0x9d,0x32,0xf8,0xd3, +0x59,0x6b,0x1b,0xff,0xf9,0xd3,0x59,0x83,0xad,0x01,0xbd,0x04,0x25,0xf4,0xff, +0x2d,0x0a,0x96,0x3a,0x03,0xa9,0x93,0x80,0xaa,0x23,0x65,0xda,0xff,0x88,0x01, +0xa9,0xc3,0x1b,0x98,0x99,0x01,0x47,0xa8,0x1a,0xa8,0x33,0xa5,0xe8,0xff,0xa0, +0x22,0x21,0x29,0xa3,0xb8,0x01,0xdd,0x02,0x47,0x2b,0x97,0x8c,0x22,0x79,0x83, +0x29,0xa3,0x0c,0x02,0x1d,0xf0,0x69,0x83,0x7c,0xf2,0x1d,0xf0,0x7c,0xea,0xa7, +0x92,0xf2,0x0c,0x1b,0xb9,0x73,0x1d,0xf0,0xad,0x01,0xbd,0x04,0x65,0xef,0xff, +0x2d,0x0a,0xd6,0xfa,0x01,0x7c,0xec,0xc7,0x9a,0xdb,0x0c,0x1d,0xd9,0x73,0x1d, +0xf0,0xa8,0x33,0xa5,0xe4,0xff,0xb8,0x01,0xa0,0x22,0x21,0x1b,0xbb,0xb9,0x01, +0x29,0xa3,0x79,0x83,0xc6,0xd2,0xff,0xa9,0x93,0x69,0x83,0x80,0xaa,0x23,0xa5, +0xd3,0xff,0xc8,0x01,0xa9,0xc3,0x1b,0xdc,0xd9,0x01,0x47,0xac,0xaf,0xa8,0x33, +0xe5,0xe1,0xff,0xa0,0x22,0x21,0xb8,0x01,0x86,0xf5,0xff,0x36,0x41,0x00,0xa8, +0x02,0xa0,0xa2,0x21,0xe5,0xbc,0xff,0x31,0x3a,0x32,0xb8,0x22,0xa9,0x23,0x8c, +0x8b,0xa8,0x02,0xa0,0xa2,0x21,0xe5,0xbb,0xff,0xa9,0x33,0x1d,0xf0,0x36,0x41, +0x00,0x21,0x34,0x32,0x28,0x42,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x0c,0x13, +0x41,0x30,0x32,0x0c,0x02,0x48,0x44,0x42,0xc4,0xfe,0x40,0x23,0x83,0x1d,0xf0, +0x36,0x41,0x00,0x30,0x64,0x00,0x65,0xfe,0xff,0x27,0x1a,0x2a,0x41,0x2a,0x32, +0x0c,0x1a,0x51,0xb9,0x31,0x9d,0x02,0x88,0x15,0x20,0x9a,0x93,0x99,0x44,0xad, +0x05,0x89,0x54,0xa5,0xd3,0xff,0x8c,0xf2,0xb8,0x25,0x8c,0x1b,0x65,0xe7,0xff, +0xc8,0x54,0xcc,0x4c,0xd8,0x44,0x1b,0xdd,0xd9,0x44,0x30,0xe6,0x13,0x20,0x20, +0x00,0x1d,0xf0,0x00,0x36,0x41,0x00,0x2d,0x05,0x61,0xac,0x31,0x51,0x1b,0x32, +0xac,0x73,0x0c,0x07,0x26,0x13,0x2c,0x26,0x43,0x4a,0x26,0x73,0x71,0x82,0xc3, +0xeb,0x16,0x68,0x09,0x1c,0x69,0x97,0x93,0x19,0x98,0x45,0x66,0x19,0x14,0xa8, +0x55,0x0b,0xaa,0xa9,0x55,0xcc,0xba,0x1b,0xb9,0xb9,0x45,0x1d,0xf0,0x29,0x05, +0xad,0x06,0x65,0xf4,0xff,0x1d,0xf0,0x1c,0x7d,0x40,0xc0,0x74,0xd7,0x9c,0xf5, +0xad,0x02,0x65,0xf7,0xff,0x56,0xd2,0xfe,0x79,0x65,0x1c,0xda,0x88,0x05,0x1c, +0x8b,0x88,0xf8,0x0c,0x0c,0xe0,0x08,0x00,0x1d,0xf0,0x16,0xa4,0x09,0x0b,0x94, +0x16,0xb9,0x09,0x26,0x24,0x6a,0xa2,0xc4,0xfd,0x16,0x9a,0x09,0xb2,0xc4,0xfc, +0x16,0xfb,0x09,0x26,0x54,0x6d,0xc2,0xc4,0xfa,0x16,0x9c,0x07,0x66,0x74,0xb9, +0x20,0xd0,0xf4,0xd9,0x16,0x1d,0xf0,0x25,0xf2,0xff,0x16,0xca,0xfa,0xe8,0x26, +0x16,0x7e,0xfa,0x25,0xde,0xff,0xf8,0xd5,0x66,0x3f,0x9f,0xa8,0xe5,0x79,0xd5, +0x8c,0x1a,0xe0,0x0a,0x00,0x1c,0x5a,0x88,0x05,0x0c,0x0b,0x88,0xf8,0x0c,0x0c, +0xe0,0x08,0x00,0x1d,0xf0,0x65,0xef,0xff,0x16,0x1a,0xf8,0x0c,0x0a,0xa5,0xb9, +0xff,0x98,0x65,0x56,0x79,0xf7,0x1c,0xda,0x1c,0x8b,0x88,0x05,0x0c,0x1c,0x88, +0xf8,0xc9,0x65,0xe0,0x08,0x00,0x1d,0xf0,0xa8,0x02,0xa0,0xa0,0xf4,0xa6,0x2a, +0x02,0xc6,0xd6,0xff,0xe5,0xc9,0xff,0xa9,0x02,0x1d,0xf0,0xa8,0x02,0xa0,0xa0, +0xf4,0xa6,0x2a,0x02,0x46,0xd2,0xff,0xe5,0xcb,0xff,0xa9,0x02,0x1d,0xf0,0x29, +0xe5,0x1d,0xf0,0xe5,0xea,0xff,0x86,0x00,0x00,0xa5,0xe9,0xff,0xa9,0x02,0x1d, +0xf0,0xa8,0x02,0x0c,0x1b,0xa0,0xa0,0xf4,0x65,0xbb,0xff,0x1d,0xf0,0xa8,0x02, +0xbd,0x07,0xa0,0xa0,0xf4,0xa5,0xba,0xff,0x1d,0xf0,0x00,0x36,0x41,0x00,0x4d, +0x02,0x20,0x64,0x00,0x51,0xd4,0x31,0x0c,0x13,0x49,0x35,0x39,0x25,0x20,0xe6, +0x13,0x20,0x20,0x00,0x0c,0x02,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x0b,0x21, +0xcf,0x31,0x31,0xce,0x31,0xc0,0x20,0x00,0xb2,0x63,0x9b,0xf8,0xa2,0xc0,0x20, +0x00,0x0c,0xcd,0xf2,0x63,0x82,0xe8,0x92,0x0c,0x4c,0xe0,0xcd,0x83,0xc0,0x20, +0x00,0xc2,0x63,0x80,0xc0,0x20,0x00,0xb2,0x63,0x8c,0xa8,0x12,0xc0,0x20,0x00, +0xa2,0x63,0x8e,0x98,0x22,0xc0,0x20,0x00,0x92,0x63,0x8f,0x88,0x32,0xc0,0x20, +0x00,0x82,0x63,0x85,0x78,0x42,0xc0,0x20,0x00,0x72,0x63,0x86,0x68,0x52,0xc0, +0x20,0x00,0x62,0x63,0x87,0x58,0x62,0xc0,0x20,0x00,0x52,0x63,0x88,0x48,0x72, +0xc0,0x20,0x00,0x42,0x63,0x89,0x28,0x82,0xc0,0x20,0x00,0x22,0x63,0x8a,0x1d, +0xf0,0x36,0x81,0x00,0x0c,0x04,0x31,0xb1,0x31,0x21,0xb2,0x31,0xa1,0x2a,0x31, +0xc0,0x20,0x00,0x42,0x6a,0x9c,0xc0,0x20,0x00,0x92,0x22,0x8d,0xc0,0x20,0x00, +0x99,0x01,0x49,0x11,0x49,0x21,0x1c,0x7a,0xbd,0x04,0x0c,0x4c,0x88,0x43,0x0c, +0x0d,0x82,0x28,0x10,0x8b,0xe1,0xe0,0x08,0x00,0x61,0xa8,0x31,0xc8,0x06,0xc0, +0x20,0x00,0xb8,0x01,0xc7,0x8b,0x02,0x46,0x46,0x00,0xc0,0x20,0x00,0xd8,0x01, +0xe8,0x21,0xd0,0xd5,0x04,0x16,0x9d,0x08,0x56,0xbe,0x10,0xf8,0x03,0x98,0x11, +0x16,0x0f,0x12,0x0c,0x6a,0x0c,0x0b,0x0c,0x4c,0x88,0x43,0x0c,0x1d,0x82,0x28, +0x10,0x0c,0x1e,0xe0,0x08,0x00,0x88,0x43,0x88,0x98,0xa8,0x03,0xe0,0x08,0x00, +0x9d,0x0a,0x92,0x61,0x01,0xa6,0x49,0x02,0x46,0x3f,0x00,0x92,0xa0,0x04,0x76, +0xa9,0x05,0xc0,0x20,0x00,0x42,0x62,0x84,0xc6,0x0f,0x00,0x49,0x31,0x1c,0x7a, +0x0c,0x0b,0x0c,0x4c,0x88,0x43,0x0c,0x5d,0x82,0x28,0x10,0xcb,0xe1,0xe0,0x08, +0x00,0xd8,0x31,0xd0,0xd0,0x74,0xc0,0x20,0x00,0xd2,0x62,0x84,0xc8,0x31,0xc0, +0xc8,0x74,0xc0,0x20,0x00,0xc2,0x62,0x84,0xb8,0x31,0xb0,0xb0,0x75,0xc0,0x20, +0x00,0xb2,0x62,0x84,0x98,0x31,0x90,0x98,0x75,0xc0,0x20,0x00,0x92,0x62,0x84, +0xc0,0x20,0x00,0xe2,0x22,0x94,0xc0,0x20,0x00,0xe9,0x01,0xc0,0x20,0x00,0xf8, +0x01,0x27,0x6f,0x4f,0xc0,0x20,0x00,0x52,0x22,0x9e,0xbc,0x15,0xc0,0x20,0x00, +0x82,0x22,0x84,0x80,0x80,0x74,0xc0,0x20,0x00,0xa8,0x13,0x89,0x41,0x9c,0xaa, +0x98,0x23,0x66,0x29,0x0a,0xc0,0x20,0x00,0xa8,0x41,0xe5,0x0b,0xfe,0xc6,0x02, +0x00,0xc0,0x20,0x00,0x88,0x43,0x88,0x68,0xb8,0x41,0xe0,0x08,0x00,0x0b,0x55, +0x56,0xc5,0xfc,0x88,0x43,0x82,0x28,0x18,0xe0,0x08,0x00,0x0c,0x7b,0x88,0x43, +0xcd,0x0a,0x88,0xf8,0x0c,0x7a,0xe0,0x08,0x00,0xc0,0x20,0x00,0x98,0x01,0x67, +0x69,0x0a,0xc0,0x20,0x00,0xb2,0x22,0x95,0xc0,0x20,0x00,0xb9,0x01,0xc0,0x20, +0x00,0xe2,0x22,0x8d,0xc0,0x20,0x00,0xe9,0x01,0xc0,0x20,0x00,0xd8,0x01,0xc8, +0x06,0xd7,0x0c,0x02,0x46,0xb9,0xff,0x1d,0xf0,0x49,0x11,0x1c,0x7a,0x0c,0x0b, +0x0c,0x4c,0x88,0x43,0x0c,0x2d,0x82,0x28,0x10,0x4b,0xe1,0xe0,0x08,0x00,0x98, +0x11,0xe0,0x99,0x11,0xc6,0xbe,0xff,0xc6,0xbe,0xff,0xb8,0x21,0xc8,0x03,0x56, +0x9b,0xf0,0xbc,0x4c,0x0c,0x45,0x9c,0xf9,0x9c,0xd5,0x88,0x43,0x88,0x78,0xa8, +0x03,0xe0,0x08,0x00,0xa0,0xb0,0x74,0xc0,0x20,0x00,0xb2,0x62,0x84,0x98,0x11, +0x0b,0x55,0x0b,0x99,0x99,0x11,0x86,0xf7,0xff,0x00,0x00,0xb8,0x23,0x66,0x1b, +0x0d,0xa8,0x33,0x1b,0xcb,0xc9,0x23,0xe5,0xff,0xfd,0x46,0x00,0x00,0x0c,0x45, +0x76,0xa5,0x05,0xc0,0x20,0x00,0x42,0x62,0x84,0xc6,0xc0,0xff,0x00,0x00,0x00, +0x36,0x41,0x00,0x61,0x3e,0x31,0x16,0x53,0x06,0x26,0x13,0x71,0x1c,0x07,0x82, +0xc3,0xfe,0x16,0xb8,0x0d,0x92,0xc3,0xfd,0x16,0x89,0x0b,0xb2,0xc3,0xfc,0x16, +0x5b,0x0a,0xd2,0xc3,0xf9,0x16,0x3d,0x07,0x1c,0x8e,0xe7,0x93,0x50,0x40,0xf0, +0x74,0x66,0x7f,0x4a,0xb2,0xa0,0x80,0x0c,0x09,0x70,0x64,0x00,0x88,0x46,0xa8, +0x06,0x88,0x68,0x99,0x26,0xe0,0x08,0x00,0x88,0x46,0xa8,0x06,0x88,0x68,0x2c, +0xfb,0xe0,0x08,0x00,0x88,0x46,0xa8,0x06,0x88,0x68,0x50,0xb8,0x74,0xe0,0x08, +0x00,0x88,0x46,0xa8,0x06,0x88,0x68,0x50,0xb0,0x74,0xe0,0x08,0x00,0x70,0xe6, +0x13,0x20,0x20,0x00,0x1d,0xf0,0x59,0x46,0x98,0x22,0xa8,0x12,0xa9,0x06,0x99, +0x16,0x65,0xd4,0xff,0x1d,0xf0,0x40,0xb0,0x74,0x66,0x7b,0xf7,0x8c,0xd5,0xbd, +0x05,0x88,0x46,0xa1,0xae,0x30,0x82,0x28,0x20,0x2c,0x8c,0xe0,0x08,0x00,0xa5, +0xd2,0xff,0x1d,0xf0,0xa8,0x06,0x16,0xca,0xfd,0x88,0x46,0x88,0x98,0xe0,0x08, +0x00,0xb6,0x4a,0xd2,0x0c,0x6a,0x0c,0x0b,0x0c,0x4c,0x50,0x64,0x00,0x88,0x46, +0x0c,0x1d,0x82,0x28,0x10,0x0c,0x0e,0xe0,0x08,0x00,0x50,0xe6,0x13,0x20,0x20, +0x00,0x1d,0xf0,0x40,0x90,0x74,0x56,0xf9,0xfa,0xad,0x05,0x65,0xcd,0xff,0x1d, +0xf0,0xf0,0x64,0x00,0xa0,0xe4,0x03,0x70,0xaa,0x20,0x70,0xaa,0x30,0xa0,0xe4, +0x13,0xf0,0xe6,0x13,0x10,0x20,0x00,0x70,0xe3,0x13,0x65,0xcd,0xff,0x1d,0xf0, +0xe5,0xcc,0xff,0xc1,0x03,0x31,0xd2,0xa0,0x64,0x41,0x04,0x31,0x0c,0x43,0x0c, +0x1b,0x2d,0x0b,0x00,0x50,0x00,0x70,0xe3,0x13,0xf0,0x64,0x00,0xe0,0xe4,0x03, +0x70,0xee,0x20,0xe0,0xe4,0x13,0xf0,0xe6,0x13,0x10,0x20,0x00,0xc0,0x20,0x00, +0xd2,0x6c,0x8c,0xc0,0x20,0x00,0xb2,0x6c,0x9b,0x1d,0xf0,0x36,0x41,0x00,0x31, +0xf9,0x30,0x0c,0x04,0x22,0xa1,0x00,0x42,0x63,0x01,0x31,0xf7,0x30,0x76,0xa2, +0x07,0xc0,0x20,0x00,0x42,0x63,0x80,0x4b,0x33,0x1d,0xf0,0x00,0x00,0x36,0x41, +0x00,0x51,0xf3,0x30,0x81,0xe8,0x30,0x0c,0x04,0x0c,0x0b,0xc1,0xee,0x30,0x0c, +0xc3,0x72,0x2c,0x01,0x76,0xa3,0x49,0xc0,0x20,0x00,0x62,0x12,0x00,0xb2,0x65, +0x80,0x07,0xe4,0x04,0x9d,0x06,0x46,0x00,0x00,0x0c,0x09,0xc0,0x20,0x00,0x92, +0x58,0x82,0xc0,0x20,0x00,0xb2,0x58,0x83,0xc0,0x20,0x00,0x72,0x58,0x84,0x60, +0xd2,0x41,0x0b,0xdd,0xc0,0x20,0x00,0xd2,0x58,0x85,0xa2,0x12,0x01,0x0b,0xaa, +0xc0,0x20,0x00,0xa2,0x58,0x86,0x4b,0x22,0x1b,0x44,0x52,0xc5,0x10,0x60,0xd2, +0xf4,0xda,0x77,0x82,0xc8,0x10,0x79,0x1c,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00, +0x0c,0x03,0x7c,0xfd,0x00,0x12,0x40,0x0c,0x1c,0x00,0xcc,0xa1,0xd0,0xcc,0x30, +0x8d,0x03,0xd1,0x4c,0x30,0xc0,0x20,0x00,0xf2,0x2d,0x81,0xf0,0xfc,0x10,0xc0, +0x20,0x00,0xf2,0x6d,0x81,0xc0,0x20,0x00,0xe2,0x2d,0x80,0xe0,0xcc,0x10,0xc0, +0x20,0x00,0xc2,0x6d,0x80,0xb1,0xcd,0x30,0xc0,0x92,0x11,0xba,0xb9,0xc0,0x20, +0x00,0x39,0x0b,0xa1,0xbf,0x30,0xaa,0x99,0xc0,0x20,0x00,0x32,0x59,0x83,0x20, +0xa0,0x04,0xa0,0x85,0x83,0xc0,0x20,0x00,0x82,0x59,0x82,0x07,0xe2,0x1a,0x0b, +0xc5,0xad,0x02,0x0c,0x0b,0xa5,0x01,0x00,0xf1,0xc2,0x30,0xe0,0xe2,0x11,0xd2, +0xcf,0x60,0xd0,0xd2,0xa0,0xfa,0xee,0x39,0x0e,0x39,0x0d,0x1d,0xf0,0x00,0x00, +0x00,0x36,0x41,0x00,0x51,0xbd,0x30,0xc0,0x72,0x11,0x5a,0x57,0xc0,0x20,0x00, +0x81,0xb7,0x30,0x52,0x15,0x00,0x8a,0x77,0xc0,0x20,0x00,0x1b,0x25,0x1b,0x64, +0x42,0x27,0x80,0x0b,0x22,0x8c,0xa2,0x0b,0x66,0x96,0x66,0x00,0x39,0x04,0x4b, +0x44,0xc6,0xfb,0xff,0xc0,0x20,0x00,0x42,0x67,0x80,0x1d,0xf0,0x36,0x41,0x00, +0x0c,0x0f,0x71,0xaf,0x30,0xb1,0xb0,0x30,0x62,0xc7,0xd0,0x52,0xc7,0xa0,0xe2, +0xcb,0xea,0xac,0x43,0x26,0x13,0x68,0x7c,0xf3,0xf6,0xa3,0x1b,0xa1,0xab,0x30, +0xc0,0xc3,0x11,0xa0,0xa3,0xa0,0x98,0x0a,0xb1,0xa9,0x30,0xe6,0x49,0x0a,0xca, +0xbb,0x1b,0xd9,0xd9,0x0a,0xb0,0xb9,0xa0,0x49,0x0b,0x1d,0xf0,0xad,0x0e,0x3d, +0x0f,0x82,0x1a,0x32,0x87,0x12,0x09,0xa7,0x3b,0x06,0x2b,0x33,0x4b,0xaa,0xc6, +0xfb,0xff,0xe6,0xa3,0xc7,0x81,0x96,0x30,0x60,0xc3,0xa0,0x0c,0x8b,0x50,0xd3, +0xa0,0x70,0xa3,0xa0,0xf9,0x0a,0x29,0x0d,0xad,0x03,0xb9,0x0c,0xe0,0xd3,0xa0, +0x0c,0x0b,0x0c,0x8c,0xe8,0x38,0x98,0xdd,0xd2,0x1d,0x00,0x90,0xee,0x20,0xe9, +0x38,0xe5,0xec,0xff,0x06,0xe6,0xff,0xa2,0xcb,0xec,0x0c,0x13,0x82,0x1a,0x32, +0x87,0x12,0x09,0xa7,0x3b,0x06,0x2b,0x33,0x4b,0xaa,0xc6,0xfb,0xff,0xe6,0xa3, +0x80,0x81,0x84,0x30,0x60,0xc3,0xa0,0x0c,0x8b,0x50,0xd3,0xa0,0x70,0xa3,0xa0, +0xf9,0x0a,0x29,0x0d,0xad,0x03,0xb9,0x0c,0xe0,0xd3,0xa0,0x0c,0x0b,0x0c,0x8c, +0xe8,0x28,0x98,0xdd,0xd2,0x1d,0x00,0x90,0xee,0x20,0xe9,0x28,0xa5,0xe8,0xff, +0x46,0xd4,0xff,0x00,0x00,0x00,0x36,0x81,0x00,0xad,0x03,0x0c,0x06,0x59,0x21, +0x49,0x11,0x9d,0x02,0x21,0x03,0x30,0x99,0x01,0x7d,0x02,0x82,0x17,0x32,0x87, +0x1a,0x09,0xe6,0xa6,0x06,0x2b,0x66,0x4b,0x77,0xc6,0xfb,0xff,0x51,0x77,0x30, +0xa9,0x41,0xb1,0x73,0x30,0x41,0x76,0x30,0xb2,0xcb,0xa0,0x42,0xc4,0xf0,0xa6, +0xa6,0x02,0x06,0x21,0x00,0xa9,0x41,0xe0,0x36,0x11,0xb0,0xe6,0xa0,0xd8,0x01, +0xa9,0x0e,0x9c,0x1d,0x0c,0x0f,0x81,0x6b,0x30,0x98,0x11,0xa2,0xc5,0x60,0xa0, +0xa6,0xa0,0x99,0x0a,0x8a,0x83,0xf9,0x08,0xad,0x06,0x0c,0x0b,0x0c,0x8c,0x98, +0x34,0x2a,0xd3,0xe8,0xdd,0xd2,0x1d,0x00,0xe0,0x99,0x20,0x99,0x34,0xe5,0xe0, +0xff,0x5a,0xb3,0xb9,0x31,0xb8,0x0b,0x0c,0x03,0xa6,0x1b,0x41,0xc0,0x86,0x11, +0x61,0x60,0x30,0x8a,0x66,0xa8,0x06,0xac,0xda,0x50,0x64,0x00,0x88,0x04,0x88, +0x88,0xe0,0x08,0x00,0x92,0x17,0x3e,0x0c,0x02,0xa6,0x19,0x12,0x88,0x04,0xa8, +0x06,0x88,0x68,0x0c,0x0b,0xe0,0x08,0x00,0x92,0x17,0x3e,0x1b,0x22,0x97,0x22, +0xec,0x50,0xe6,0x13,0x20,0x20,0x00,0xb8,0x31,0xb8,0x0b,0x4b,0x66,0x1b,0x33, +0xb7,0x23,0xc5,0xa8,0x41,0x0c,0x16,0x51,0x4f,0x30,0x21,0xd5,0x2f,0xb2,0xc5, +0x30,0x2b,0x72,0xc2,0x17,0x32,0xc7,0x1a,0x09,0xe6,0xa6,0x6e,0x4b,0x77,0x2b, +0x66,0xc6,0xfb,0xff,0xe6,0xa6,0x64,0xe0,0x36,0x11,0xb0,0xe6,0xa0,0xd8,0x01, +0xa9,0x0e,0x9c,0x2d,0xf8,0x21,0x98,0x11,0x81,0x41,0x30,0xa1,0x44,0x30,0x80, +0x86,0xa0,0xa0,0xa6,0xa0,0x99,0x0a,0xf9,0x08,0xad,0x06,0x0c,0x0b,0x0c,0x8c, +0xe8,0x24,0x2a,0xd3,0xf8,0xdd,0xd2,0x1d,0x00,0xf0,0xee,0x20,0xe9,0x24,0xa5, +0xd6,0xff,0x5a,0x23,0xb8,0x02,0x0c,0x03,0xa6,0x1b,0x24,0xc0,0x86,0x11,0x61, +0x37,0x30,0x8a,0x66,0xa8,0x06,0x9c,0x0a,0x50,0x64,0x00,0x88,0x04,0x88,0x88, +0xe0,0x08,0x00,0x50,0xe6,0x13,0x20,0x20,0x00,0xb8,0x02,0x4b,0x66,0x1b,0x33, +0xb7,0x23,0xe2,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x0c,0x06,0x0c,0x19, +0x51,0xb2,0x2f,0x81,0x9b,0x2f,0x72,0xc5,0x16,0x32,0x15,0x32,0x37,0x12,0x09, +0x57,0x37,0x06,0x2b,0x66,0x4b,0x55,0xc6,0xfb,0xff,0xe6,0xa6,0x23,0x00,0x16, +0x40,0x00,0x49,0xa1,0xc0,0x20,0x00,0xb2,0x28,0x80,0xb0,0xb4,0x20,0xc0,0x20, +0x00,0xb2,0x68,0x80,0xc0,0x20,0x00,0xa2,0x28,0x81,0xa0,0x44,0x20,0xc0,0x20, +0x00,0x42,0x68,0x81,0x51,0x1e,0x30,0x0c,0x16,0xc2,0x15,0x32,0xc7,0x12,0x09, +0x57,0x37,0x06,0x2b,0x66,0x4b,0x55,0xc6,0xfb,0xff,0xe6,0xa6,0x23,0x00,0x16, +0x40,0x00,0xd9,0xa1,0xc0,0x20,0x00,0xf2,0x28,0x80,0xf0,0xfd,0x20,0xc0,0x20, +0x00,0xf2,0x68,0x80,0xc0,0x20,0x00,0xe2,0x28,0x81,0xe0,0xdd,0x20,0xc0,0x20, +0x00,0xd2,0x68,0x81,0x1d,0xf0,0x00,0x00,0x00,0x36,0x81,0x00,0x91,0x7b,0x2f, +0xc0,0x20,0x00,0x92,0x29,0x87,0x90,0x90,0x34,0xa6,0xa9,0x02,0x46,0x5e,0x00, +0xe1,0x06,0x30,0x81,0x0a,0x30,0xb1,0x08,0x30,0xe0,0xa9,0x11,0x41,0xf2,0x2f, +0x51,0x00,0x30,0xc0,0xf9,0x11,0x62,0xc5,0xa0,0x4a,0x4f,0x72,0xc5,0xd0,0x70, +0x79,0xa0,0x49,0x51,0x60,0x69,0xa0,0x41,0xe9,0x2e,0x5a,0x5a,0x69,0x21,0x79, +0x61,0x61,0xf4,0x2f,0xf0,0x79,0x11,0xba,0xaa,0xa9,0x11,0x8a,0x77,0x79,0x31, +0x6a,0x6f,0x71,0xfc,0x2f,0x69,0x41,0xea,0xff,0xf9,0x71,0x61,0xf2,0x2e,0xc0, +0x20,0x00,0x38,0x41,0x32,0x23,0x80,0xc0,0x20,0x00,0x98,0x71,0x28,0x51,0x98, +0x09,0x22,0x12,0x82,0x16,0xd9,0x0c,0x99,0x01,0x86,0x00,0x00,0x77,0x1b,0x1e, +0x8d,0x02,0x0b,0x22,0xe6,0x18,0x02,0x86,0x30,0x00,0xd8,0x03,0x98,0x05,0x4b, +0x33,0x16,0x79,0x06,0x40,0xbd,0x10,0x47,0x0d,0x41,0x67,0x9b,0xe0,0x06,0x06, +0x00,0x0c,0x7a,0xb8,0x21,0x81,0xda,0x2f,0xc1,0xe9,0x2f,0x88,0x08,0xc0,0xcd, +0x10,0x88,0xf8,0xb8,0x0b,0xe0,0x08,0x00,0xc6,0xf1,0xff,0xa8,0x01,0xb8,0x31, +0x81,0xd4,0x2f,0xc8,0x61,0x88,0x08,0xc8,0x0c,0x92,0x9b,0x00,0x00,0x1c,0x40, +0x1b,0x99,0x88,0x68,0x92,0x5b,0x00,0x00,0xbd,0xa1,0xe0,0x08,0x00,0x06,0xe9, +0xff,0x98,0x01,0xb8,0x61,0x81,0xcb,0x2f,0xa8,0x71,0x88,0x08,0xa8,0x1a,0xb8, +0x0b,0xa0,0xa9,0x83,0x00,0x1b,0x40,0x88,0x68,0x00,0xbd,0xa1,0xe0,0x08,0x00, +0x06,0xe1,0xff,0xa8,0x01,0xb8,0x31,0x81,0xc3,0x2f,0xc8,0x61,0x88,0x08,0xc8, +0x0c,0x92,0x9b,0x00,0x00,0x1c,0x40,0x1b,0x99,0x88,0x68,0x92,0x5b,0x00,0x00, +0xbd,0xa1,0xe0,0x08,0x00,0xa8,0x11,0x98,0x0a,0x1b,0x99,0x99,0x0a,0xe6,0x89, +0x02,0x86,0xd5,0xff,0x0c,0x0c,0xa8,0x11,0x0c,0x09,0xb8,0x21,0x81,0xb7,0x2f, +0xb8,0x0b,0x88,0x08,0x99,0x0a,0x88,0xf8,0x0c,0x7a,0xe0,0x08,0x00,0xc6,0xce, +0xff,0x4b,0x33,0x9d,0x02,0x0b,0x22,0xe6,0x19,0xf6,0xc0,0x20,0x00,0xb8,0x41, +0x32,0x6b,0x80,0xc0,0x20,0x00,0x8b,0x55,0x98,0x21,0x88,0x11,0xf8,0x61,0xe8, +0x71,0xa8,0x31,0xc2,0x2b,0x80,0xd8,0x51,0xb2,0xcb,0x20,0xb9,0x41,0xd2,0xcd, +0x20,0x4b,0xaa,0xe2,0xce,0x20,0x8b,0xff,0x8b,0x88,0x8b,0x99,0x99,0x21,0x89, +0x11,0xf9,0x61,0xe9,0x71,0xa9,0x31,0xa1,0xb2,0x2f,0xd9,0x51,0xb7,0x2a,0x02, +0xc6,0xb3,0xff,0x1d,0xf0,0x00,0x00,0x00,0x36,0x81,0x00,0x91,0x16,0x2f,0xc0, +0x20,0x00,0x92,0x29,0x86,0x90,0x90,0x34,0xa6,0xa9,0x02,0xc6,0x4f,0x00,0xf0, +0xb9,0x11,0xe0,0x69,0x11,0xc1,0xa8,0x2f,0x31,0x9a,0x2f,0x71,0x9d,0x2f,0x82, +0xc3,0x30,0xa2,0xc7,0x60,0xd2,0xcc,0x40,0xd0,0xd9,0x90,0xa0,0xa9,0xa0,0x7a, +0x76,0xca,0xbb,0x80,0x89,0xa0,0x89,0x21,0xc1,0x87,0x2f,0x3a,0x66,0xb9,0x51, +0xa9,0x11,0xd9,0x01,0xa1,0x95,0x2f,0xd1,0x8d,0x2f,0xc0,0xb9,0x11,0x32,0xc3, +0x60,0x30,0x39,0xa0,0xca,0xcb,0xc9,0x41,0xda,0xdb,0xd9,0x31,0xaa,0xbb,0xb9, +0x61,0x0c,0x0b,0xc0,0x20,0x00,0x28,0x31,0x22,0x22,0x80,0xc0,0x20,0x00,0x58, +0x41,0xf8,0x51,0x52,0x15,0x82,0xe2,0x9f,0x00,0x5a,0xee,0xe2,0x5f,0x00,0xe6, +0x15,0x02,0x06,0x22,0x00,0x98,0x07,0x48,0x06,0xa8,0x61,0x1b,0x84,0x89,0x06, +0xa0,0x44,0xa0,0x48,0x04,0x97,0x28,0x01,0xb9,0x06,0x8c,0xc4,0x81,0x77,0x2f, +0x88,0x08,0x88,0x98,0xad,0x04,0xe0,0x08,0x00,0x0c,0x0b,0x98,0x03,0x9c,0x09, +0xb9,0x02,0x98,0x03,0x4b,0x22,0x0b,0xa9,0xa9,0x03,0x0b,0x55,0xe6,0x15,0xc8, +0x86,0x13,0x00,0x8c,0xf4,0x81,0x6e,0x2f,0x88,0x08,0x88,0x98,0xad,0x04,0xe0, +0x08,0x00,0x0c,0x0b,0x46,0x00,0x00,0x0c,0x0a,0xac,0x5a,0x81,0x68,0x2f,0x88, +0x08,0x88,0x78,0xad,0x04,0xe0,0x08,0x00,0xc8,0x11,0xc8,0x0c,0x98,0x21,0x00, +0x0c,0x40,0xa0,0xa0,0xb1,0xa9,0x02,0x98,0x09,0x0c,0x0b,0x8c,0x09,0xb9,0x02, +0x4b,0x22,0x46,0xee,0xff,0xe8,0x01,0xd2,0x9e,0x00,0xb9,0x02,0x98,0x07,0x1b, +0xdd,0xd2,0x5e,0x00,0x86,0xe8,0xff,0xc0,0x20,0x00,0xf8,0x31,0x22,0x6f,0x80, +0xc0,0x20,0x00,0x8b,0x33,0x8b,0x77,0x8b,0x66,0xd8,0x01,0xc8,0x51,0xa8,0x61, +0x98,0x41,0xe8,0x11,0x88,0x21,0x8b,0xee,0x8b,0x88,0x92,0xc9,0x20,0xa2,0xca, +0x20,0x4b,0xcc,0x4b,0xdd,0xd9,0x01,0xc9,0x51,0xa9,0x61,0x99,0x41,0x89,0x21, +0xe9,0x11,0x82,0x2f,0x80,0xe1,0x5c,0x2f,0xf2,0xcf,0x20,0xf9,0x31,0xf7,0x2e, +0x02,0x86,0xc3,0xff,0x1d,0xf0,0x00,0x36,0x41,0x00,0x0c,0x09,0xa1,0xbb,0x2e, +0xc0,0x20,0x00,0x81,0x57,0x2f,0x88,0x08,0x92,0x6a,0x9c,0xe0,0x08,0x00,0x1d, +0xf0,0x36,0x41,0x00,0x0c,0x09,0xa1,0xb5,0x2e,0xc0,0x20,0x00,0x81,0x51,0x2f, +0x88,0x18,0x92,0x6a,0x9c,0xe0,0x08,0x00,0x1d,0xf0,0x36,0x41,0x00,0x0c,0xcb, +0x0c,0xba,0x0c,0x17,0xe1,0x39,0x2f,0x61,0xc8,0x2e,0xbc,0x13,0x26,0x13,0x79, +0x82,0xc3,0xfc,0x16,0x48,0x09,0x92,0xc3,0xfb,0x16,0xf9,0x0c,0x1c,0x3a,0xa7, +0x93,0x66,0x40,0xb0,0x74,0x66,0x8b,0x60,0x50,0xc1,0x64,0x56,0xac,0x05,0x50, +0x98,0x74,0xf6,0xa9,0x54,0xe1,0x41,0x2f,0x50,0xd0,0x74,0xe0,0xe9,0xa0,0xd9, +0x0e,0x1d,0xf0,0x59,0x0e,0x25,0x8c,0xff,0xad,0x06,0xe5,0x8d,0xff,0x0c,0x0c, +0x0c,0x4f,0xb1,0x2f,0x2f,0xa1,0x2f,0x2f,0xe2,0xcb,0x30,0xd2,0xca,0x10,0x9d, +0x0a,0xd2,0xcd,0x10,0xc9,0x0b,0xa2,0xca,0x10,0x4b,0xbb,0x76,0xaf,0x03,0xc9, +0x09,0x4b,0x99,0x0c,0x4f,0x9d,0x0a,0xe7,0x9b,0xe7,0x41,0x05,0x2f,0x0c,0xc3, +0x2d,0x07,0x00,0x50,0x00,0x0c,0xb3,0x41,0x01,0x2f,0x2d,0x07,0x00,0x50,0x00, +0x1d,0xf0,0x40,0x80,0x74,0x66,0x88,0xf7,0x8c,0xd5,0xbd,0x05,0x88,0x0e,0xad, +0x06,0x82,0x28,0x20,0xc2,0xa0,0x94,0xe0,0x08,0x00,0x25,0x86,0xff,0xad,0x06, +0xe5,0x87,0xff,0x1d,0xf0,0x91,0x24,0x2f,0x90,0xc4,0x10,0x97,0x84,0x02,0x86, +0x28,0x00,0xe2,0xdc,0xff,0x16,0xce,0x0b,0xf2,0xa2,0x00,0xf7,0x1c,0x75,0x82, +0xdc,0xfd,0x16,0xc8,0x0b,0x92,0xdc,0xfc,0x16,0x69,0x09,0xb2,0xa5,0x00,0xb7, +0x9c,0xb2,0x16,0xf5,0xfa,0xc0,0x64,0x00,0x4d,0x05,0x3d,0x0a,0x2d,0x07,0x00, +0x50,0x00,0xc0,0xe6,0x13,0x20,0x20,0x00,0x1d,0xf0,0xf1,0x75,0x2e,0x58,0x3e, +0xc0,0x20,0x00,0x52,0x6f,0x92,0xd8,0x2e,0xc0,0x20,0x00,0xd2,0x6f,0x93,0x0c, +0x05,0xad,0x05,0x0c,0x0b,0x0c,0x8c,0x25,0x90,0xff,0x2b,0x55,0xa6,0xa5,0xf1, +0x91,0x70,0x2e,0xc8,0xc6,0xc0,0x20,0x00,0xc2,0x69,0x80,0xb1,0x09,0x2f,0xf0, +0x64,0x00,0xa0,0xe4,0x03,0xb0,0xaa,0x20,0xa0,0xe4,0x13,0xf0,0xe6,0x13,0x10, +0x20,0x00,0x88,0xc6,0xc0,0x20,0x00,0x82,0x69,0x81,0x1d,0xf0,0xad,0x07,0x40, +0x60,0x74,0x50,0xe0,0x31,0xe6,0x1e,0x01,0x0c,0x0a,0x50,0xd0,0xf4,0xbd,0x06, +0x2c,0x0c,0xe0,0xcc,0xc0,0xa5,0x9b,0xff,0xad,0x06,0x25,0xb0,0xff,0x1d,0xf0, +0x40,0xa0,0x74,0x0c,0x0b,0xcd,0x05,0xe5,0x8d,0xff,0x1d,0xf0,0xd0,0x64,0x00, +0x4d,0x05,0x3d,0x0b,0x2d,0x07,0x00,0x50,0x00,0xd0,0xe6,0x13,0x20,0x20,0x00, +0x1d,0xf0,0x40,0xa0,0x74,0xbd,0x07,0xcd,0x05,0xe5,0x8b,0xff,0x1d,0xf0,0x40, +0xa0,0x74,0xe5,0xac,0xff,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x62,0x12,0x75, +0x42,0x12,0x76,0x67,0x23,0x0f,0x37,0x24,0x0c,0x42,0x22,0xc3,0x60,0x23,0xc0, +0x40,0x22,0xa0,0x28,0x02,0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x36,0x41,0x00,0x62, +0x12,0x75,0x42,0x12,0x76,0x67,0x23,0x0f,0x37,0x24,0x0c,0x42,0x22,0xc4,0x60, +0x23,0xc0,0x40,0x22,0xa0,0x28,0x02,0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x36,0xe1, +0x00,0x42,0x61,0x10,0xad,0x02,0x81,0x86,0x2e,0x30,0xc0,0xf4,0x88,0x08,0x0c, +0x0b,0x82,0x28,0x3b,0xdd,0x01,0xe0,0x08,0x00,0xa0,0x90,0xf4,0xa6,0x19,0x5c, +0x71,0xbc,0x2d,0x5d,0x01,0x50,0x49,0x90,0xb2,0x95,0x00,0x26,0x0b,0x49,0xa8, +0xa2,0xa0,0xab,0xa0,0xa8,0x0a,0x0c,0xbd,0xbc,0xda,0xc2,0x22,0x24,0xc0,0xcb, +0xa0,0xc8,0x0c,0xd7,0x9c,0x33,0xd2,0x21,0x10,0x6d,0x0d,0x66,0x0d,0x0e,0x88, +0x07,0x88,0x98,0xe0,0x08,0x00,0x62,0x12,0x74,0xa0,0x66,0xc0,0x0b,0x66,0xa6, +0x16,0x19,0x0c,0x03,0x0c,0x0b,0xc8,0xa2,0x88,0x07,0xa2,0x95,0x00,0x88,0x68, +0xc0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x1b,0x33,0x37,0x96,0xe7,0x2b,0x55, +0x47,0x95,0xaa,0x1d,0xf0,0x00,0x36,0x81,0x00,0xc2,0x12,0x17,0x0c,0x03,0xe6, +0x1c,0x02,0xc6,0xb2,0x00,0x0c,0xbb,0x0c,0x05,0x0c,0x06,0x0c,0x07,0x42,0x22, +0x24,0xd2,0x22,0xc1,0x3a,0x44,0x48,0x04,0x66,0x2d,0x0a,0x82,0x22,0xc2,0x88, +0x18,0x50,0x88,0xc0,0x16,0xc8,0x29,0xa6,0xa4,0x02,0x86,0xa5,0x00,0x98,0xa2, +0x9a,0x93,0x98,0x09,0xe0,0xa4,0x11,0x16,0xa9,0x28,0xa9,0x11,0xb0,0xf4,0xc0, +0x98,0xc2,0xd2,0x22,0x33,0x90,0x94,0xa0,0x98,0x09,0xd9,0x01,0x66,0x74,0x0f, +0xe2,0x22,0x3e,0x37,0x6e,0x09,0x98,0xd2,0x47,0xee,0x04,0xf0,0xed,0x11,0xe9, +0x01,0x99,0x21,0x16,0x1f,0x26,0x81,0x4d,0x2e,0xad,0x02,0x88,0x08,0x0c,0x0b, +0x82,0x28,0x3c,0xcd,0x05,0xe0,0x08,0x00,0xb8,0x11,0x92,0x22,0x22,0xba,0x99, +0x98,0x09,0xa9,0x41,0x96,0x59,0x00,0xc2,0x22,0x3e,0x47,0x6c,0x1a,0xa8,0x21, +0xb8,0x01,0xc1,0x49,0x2e,0xd2,0x22,0x19,0x81,0x42,0x2e,0x7a,0xdd,0x88,0x08, +0xc8,0x0c,0x82,0x28,0x2d,0xc8,0x3c,0xe0,0x08,0x00,0xd2,0x22,0x40,0xac,0xed, +0xa8,0x21,0xb8,0x01,0xc1,0x41,0x2e,0xd2,0x22,0xc0,0x81,0x3a,0x2e,0x7a,0xdd, +0x88,0x08,0xc8,0x0c,0x82,0x28,0x2d,0xc8,0x3c,0xe0,0x08,0x00,0x66,0x74,0x11, +0xd2,0x22,0xc1,0x66,0x2d,0x0b,0xad,0x02,0xc2,0x22,0xc2,0xbd,0x05,0xc8,0x1c, +0xa5,0x5a,0xfd,0xa8,0x21,0xb8,0x01,0xd2,0x12,0x3a,0xe2,0x12,0x3b,0x81,0x2e, +0x2e,0xc2,0x22,0x1c,0x88,0x08,0x6a,0xcc,0x82,0x28,0x2f,0xc2,0x1c,0x00,0xe0, +0x08,0x00,0x98,0x41,0x92,0xc9,0xec,0xf6,0x29,0x11,0x81,0x27,0x2e,0xa2,0x22, +0x17,0x88,0x08,0xb8,0x21,0x82,0x28,0x21,0xc8,0x01,0xe0,0x08,0x00,0x81,0x22, +0x2e,0x88,0x08,0xad,0x02,0x82,0x28,0x48,0xb8,0x41,0xe0,0x08,0x00,0xcc,0x7a, +0x92,0x22,0x36,0x92,0xc9,0xd0,0x56,0xf9,0x0c,0x92,0x22,0x3f,0xb8,0xe2,0xf0, +0xc4,0x11,0xc9,0x51,0x88,0xe2,0xc2,0x22,0x12,0xf0,0x99,0x11,0xb0,0xb4,0x90, +0xb2,0x9b,0x00,0xb9,0x31,0x66,0x74,0x0c,0xd2,0x22,0x3e,0x37,0x6d,0x06,0xf2, +0x22,0x33,0xba,0xef,0xe9,0x31,0x48,0x21,0xb8,0x31,0xe8,0x51,0xd2,0x22,0x10, +0xea,0x88,0xca,0xae,0xea,0xdd,0xd2,0x9d,0x00,0xea,0xcc,0xd0,0xbb,0xc0,0xb2, +0x5c,0x00,0x82,0x98,0x00,0xc2,0x9a,0x00,0x90,0x88,0xc0,0xc7,0xb8,0x16,0xc8, +0x51,0x0c,0x0e,0xd2,0x22,0x14,0xe2,0x5a,0x00,0xda,0xcc,0xb2,0x9c,0x00,0x1b, +0xbb,0xb2,0x5c,0x00,0xc2,0x9a,0x00,0xb8,0x51,0x81,0x21,0x2e,0xa2,0x22,0x10, +0x88,0x08,0xba,0xaa,0xb2,0x22,0x30,0xa2,0x9a,0x00,0x88,0x78,0x40,0xaa,0xa0, +0xe0,0x08,0x00,0xad,0x04,0xb8,0x31,0xd8,0x01,0x81,0x19,0x2e,0xcd,0x0d,0x88, +0x08,0xd0,0xbb,0xc0,0x88,0x78,0x40,0xbb,0xa0,0xe0,0x08,0x00,0xa2,0x22,0x30, +0xf8,0x01,0xc2,0x22,0x12,0xd8,0x51,0x81,0x12,0x2e,0xb2,0x22,0x10,0x88,0x08, +0xda,0xbb,0xda,0xcc,0x88,0x78,0xd8,0x31,0xe2,0x9c,0x00,0xf0,0xdd,0xc0,0xe0, +0xdd,0xc0,0xd2,0x5b,0x00,0xb2,0x9b,0x00,0xc2,0x9c,0x00,0x40,0xbb,0xa0,0xe0, +0x08,0x00,0x0c,0xbb,0x06,0x32,0x00,0xa2,0x12,0x16,0xb2,0x22,0x2e,0xaa,0xa5, +0xb0,0xaa,0xa0,0xa8,0x0a,0x48,0x21,0x9c,0x5a,0xbd,0x04,0x81,0x02,0x2e,0xc2, +0x22,0x30,0x88,0x08,0xd2,0x11,0x00,0x88,0xe8,0xed,0x01,0xe0,0x08,0x00,0x42, +0x22,0x30,0x98,0x41,0xb8,0x01,0x66,0x99,0x0e,0xc1,0x31,0x2e,0xad,0x04,0xc8, +0x0c,0x65,0xfb,0xf7,0x49,0x21,0x86,0x10,0x00,0x0c,0xbe,0xe7,0x99,0x0e,0xc1, +0x2d,0x2e,0xad,0x04,0xc8,0x0c,0x25,0xfa,0xf7,0x49,0x21,0x86,0x0b,0x00,0x66, +0xa9,0x0e,0xc1,0x2a,0x2e,0xad,0x04,0xc8,0x0c,0x25,0xf9,0xf7,0x49,0x21,0x06, +0x07,0x00,0x0c,0xde,0xe7,0x99,0x0e,0xc1,0x26,0x2e,0xad,0x04,0xc8,0x0c,0xe5, +0xf7,0xf7,0x49,0x21,0x06,0x02,0x00,0xad,0x04,0x49,0x21,0x1c,0x0c,0xe5,0xf6, +0xf7,0xc8,0x01,0x88,0x02,0x48,0x21,0xa8,0xa2,0xbd,0x04,0x3a,0xaa,0x88,0x88, +0xa8,0x0a,0xe0,0x08,0x00,0xb2,0x22,0xc1,0xd2,0x22,0xc2,0x66,0x2b,0x18,0xc8, +0x0d,0x57,0x9c,0x13,0xbd,0x04,0xc8,0x01,0xe8,0xa2,0x88,0x02,0xa8,0x1d,0x88, +0x88,0xe0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x81,0xba,0x2d,0xb8,0x41,0x88, +0x08,0xad,0x02,0x82,0x28,0x3a,0xc8,0x01,0xe0,0x08,0x00,0x0c,0xbb,0xc2,0x12, +0x17,0x2b,0x66,0x72,0xc7,0x10,0x4b,0x33,0x1b,0x55,0xc7,0xa5,0x02,0xc6,0x4e, +0xff,0x1d,0xf0,0x36,0x61,0x00,0x51,0xb0,0x2d,0x88,0x05,0x82,0x28,0x51,0xad, +0x02,0xe0,0x08,0x00,0xc2,0x12,0x75,0x0c,0xe9,0xc0,0x99,0xc0,0xa6,0x19,0x4d, +0x0c,0x04,0x0c,0x03,0x62,0xa1,0x7c,0x72,0xa1,0x9c,0x7a,0x72,0x6a,0x62,0x88, +0x05,0xca,0xb4,0x82,0x28,0x39,0xad,0x02,0xe0,0x08,0x00,0x1c,0x09,0x4c,0x0b, +0xa0,0xb9,0x93,0xb9,0x01,0xad,0x07,0xe5,0x5b,0x01,0xad,0x06,0xb8,0x01,0xa5, +0x5b,0x01,0x62,0xc6,0x40,0x72,0xc7,0x40,0x1b,0x44,0xb1,0xcd,0x2d,0xc2,0x12, +0x75,0xd2,0x22,0x28,0x0c,0xea,0x3a,0xdd,0x4b,0x33,0xc0,0xaa,0xc0,0xb9,0x0d, +0xa7,0x24,0xbf,0xa2,0x12,0x16,0x71,0xb5,0x2d,0xe6,0x1a,0x02,0xc6,0x2f,0x00, +0x3c,0x06,0x0c,0x04,0x0c,0x03,0xb2,0x22,0x23,0x3a,0xbb,0xb8,0x0b,0xf6,0x6b, +0x3b,0xad,0x02,0x88,0x05,0x0c,0x1b,0x82,0x28,0x3c,0xcd,0x04,0xe0,0x08,0x00, +0x88,0x05,0xbd,0x0a,0x82,0x28,0x48,0xad,0x02,0xe0,0x08,0x00,0xac,0x8a,0x92, +0x12,0x72,0xa2,0x12,0x54,0xb2,0x22,0x29,0x97,0xba,0x10,0xb0,0xba,0xa0,0x1b, +0xca,0xc2,0x52,0x54,0xc2,0x22,0x2b,0xb8,0x0b,0x3a,0xcc,0xb9,0x0c,0xa2,0x12, +0x16,0x4b,0x33,0x1b,0x44,0xa7,0x24,0xb2,0x46,0x1a,0x00,0x88,0x05,0xa2,0x22, +0x23,0x82,0x28,0x3f,0x3a,0xaa,0xa8,0x0a,0xe0,0x08,0x00,0x16,0x0a,0xfe,0xa2, +0x22,0x36,0x92,0x12,0x72,0x67,0x9a,0x1c,0xa2,0x12,0x54,0xb2,0x22,0x29,0x97, +0xba,0xce,0x1b,0xca,0xb0,0xba,0xa0,0xc2,0x52,0x54,0xc2,0x22,0x2b,0xb8,0x0b, +0x3a,0xcc,0xb9,0x0c,0x86,0xee,0xff,0x66,0xba,0xb7,0xd2,0x22,0x37,0x66,0x8d, +0xb1,0xe2,0x12,0x73,0xc2,0x12,0x5a,0xe7,0xbc,0xa8,0xa2,0x22,0x2c,0x92,0x22, +0x2e,0x1b,0xbc,0x88,0x07,0xb2,0x52,0x5a,0x7c,0xfb,0x88,0xc8,0x3a,0x99,0xa0, +0xac,0xa0,0xa8,0x0a,0xa9,0x09,0xe0,0x08,0x00,0x06,0xe2,0xff,0xa2,0x12,0x17, +0x0c,0x03,0xe6,0x1a,0x02,0xc6,0x3e,0x00,0x0c,0x04,0xc2,0x22,0x24,0x3a,0xcc, +0xc8,0x0c,0xa6,0x9c,0x02,0x86,0x38,0x00,0xad,0x02,0x88,0x05,0x0c,0x0b,0x82, +0x28,0x3c,0xcd,0x04,0xe0,0x08,0x00,0x6d,0x0a,0x88,0x05,0xad,0x02,0x82,0x28, +0x48,0xbd,0x06,0xe0,0x08,0x00,0xcc,0xba,0x92,0x22,0x24,0x3a,0x99,0x98,0x09, +0x92,0xc9,0xf9,0x56,0x49,0x0b,0xb2,0x12,0x72,0xa2,0x12,0x54,0xe2,0x22,0x2b, +0xb7,0xba,0x16,0xc2,0x22,0x29,0x1b,0xda,0xd2,0x52,0x54,0xc0,0xca,0xa0,0xd2, +0x12,0x16,0xc8,0x0c,0xda,0xd4,0xe0,0xdd,0xa0,0xc9,0x0d,0xe2,0x22,0x24,0x3a, +0xee,0xe8,0x0e,0xe2,0xce,0xf9,0x56,0x4e,0x08,0x88,0x05,0xbd,0x06,0x82,0x28, +0x48,0xad,0x02,0xe0,0x08,0x00,0x56,0x5a,0x07,0xa2,0x22,0x36,0x92,0x22,0x37, +0x66,0x8a,0x34,0x66,0x89,0x05,0xa2,0x22,0x3e,0x37,0xea,0x02,0x66,0xb9,0x60, +0xb2,0x22,0x2c,0x92,0x12,0x16,0x88,0x07,0xa2,0x12,0x5a,0x88,0xc8,0x1b,0xca, +0x9a,0x94,0xb0,0xaa,0xa0,0xc2,0x52,0x5a,0xb2,0x22,0x2e,0xa8,0x0a,0xb0,0x99, +0xa0,0xa9,0x09,0x7c,0xfb,0xe0,0x08,0x00,0xc6,0x0d,0x00,0x66,0xba,0x34,0xd2, +0x22,0x37,0x66,0x8d,0x2e,0x92,0x22,0x3e,0x37,0x69,0x02,0x47,0x69,0x25,0xb2, +0x22,0x2c,0x92,0x12,0x16,0x88,0x07,0xa2,0x12,0x5a,0x88,0xc8,0x1b,0xca,0x9a, +0x94,0xb0,0xaa,0xa0,0xc2,0x52,0x5a,0xb2,0x22,0x2e,0xa8,0x0a,0xb0,0x99,0xa0, +0xa9,0x09,0x0c,0x1b,0xe0,0x08,0x00,0xa2,0x12,0x17,0x4b,0x33,0x1b,0x44,0xa7, +0xa4,0x02,0x46,0xc1,0xff,0x1d,0xf0,0x00,0x00,0x36,0x61,0x00,0x82,0x22,0x3e, +0x39,0x11,0x27,0x68,0x06,0xad,0x02,0x7c,0xfb,0x25,0xdb,0xfd,0x0c,0x05,0x0c, +0x06,0xb2,0xa0,0x0a,0x76,0xab,0x0f,0xc2,0x22,0xbf,0xd2,0x22,0x46,0x5a,0xcc, +0x5a,0xdd,0x69,0x0d,0x69,0x0c,0x4b,0x55,0x0c,0x05,0x31,0x15,0x2d,0x0c,0x4d, +0x88,0x11,0x78,0x12,0xc0,0x88,0x11,0x89,0x01,0x8a,0x77,0x76,0xad,0x0f,0xe2, +0x22,0xc4,0xf2,0x22,0xc3,0x5a,0xee,0x5a,0xff,0x69,0x0f,0x69,0x0e,0x4b,0x55, +0xf2,0x12,0x16,0x78,0x07,0xe6,0x1f,0x02,0x06,0x34,0x00,0x0c,0x06,0x0c,0x04, +0x0c,0x05,0xc2,0x22,0x23,0x70,0xd0,0x34,0x5a,0xec,0xd9,0x0e,0xca,0xc5,0xa8, +0x0c,0xb6,0x6a,0x0c,0xf2,0xca,0xf4,0xb6,0x2f,0x06,0x26,0x9a,0x03,0x0c,0xaa, +0xa9,0x0c,0x82,0x22,0x3e,0x27,0x68,0x1d,0xdc,0xaa,0xad,0x02,0x88,0x03,0x0c, +0x1b,0x82,0x28,0x3c,0xcd,0x06,0xe0,0x08,0x00,0xbd,0x0a,0xad,0x02,0x65,0xd2, +0xfd,0xa2,0x22,0x23,0xaa,0xa5,0xa8,0x0a,0xf6,0x6a,0x28,0xd2,0x22,0xbf,0xb8, +0x92,0xc2,0x22,0x23,0x82,0x22,0x46,0xf2,0x22,0x21,0x80,0x8a,0xa0,0x4a,0xff, +0xca,0xe5,0x5a,0xbb,0x5a,0xcc,0xb8,0x0b,0xf2,0x1f,0x00,0xf9,0x08,0xc8,0x0c, +0xa8,0x0e,0xd0,0xcc,0xa0,0xb9,0x0c,0x88,0x03,0x82,0x28,0x3f,0xe0,0x08,0x00, +0x9c,0x6a,0x0c,0x19,0xa2,0x22,0x21,0xc2,0x12,0x75,0x4a,0xaa,0xa2,0x1a,0x00, +0xb2,0x22,0xc3,0xc0,0xaa,0xc0,0xb0,0xaa,0xa0,0x99,0x0a,0xa2,0x22,0x23,0x88, +0x03,0x5a,0xaa,0x82,0x28,0x3e,0xa8,0x0a,0xe0,0x08,0x00,0x4b,0x55,0x70,0x74, +0x21,0x1b,0x66,0x9c,0x6a,0x0c,0x19,0xa2,0x22,0x21,0xc2,0x12,0x75,0x4a,0xaa, +0xa2,0x1a,0x00,0xb2,0x22,0xc4,0xc0,0xaa,0xc0,0xb0,0xaa,0xa0,0x99,0x0a,0xb2, +0x12,0x16,0x2b,0x44,0xb7,0xa6,0x02,0x06,0xcd,0xff,0xc2,0x22,0x3e,0x27,0x6c, +0x17,0x88,0x03,0x82,0x28,0x45,0xad,0x02,0xe0,0x08,0x00,0x66,0x0a,0x0a,0x92, +0x12,0x16,0x0c,0x06,0xa6,0x19,0x02,0x06,0x60,0x00,0x88,0x01,0x0c,0x09,0x78, +0x12,0x92,0x62,0xc1,0x92,0x12,0x17,0x8a,0x77,0x78,0x17,0xe6,0x19,0x02,0xc6, +0x34,0x00,0x0c,0x06,0x0c,0x04,0x0c,0x05,0xc2,0x22,0x24,0x70,0xd0,0x34,0x5a, +0xec,0xd9,0x0e,0xca,0xc5,0xa8,0x0c,0x70,0x74,0x21,0xb2,0xca,0xfa,0xb6,0x4b, +0x0e,0xf2,0xca,0xf4,0xb6,0x2f,0x08,0x0c,0xb8,0x87,0x1a,0x03,0x0c,0xba,0xa9, +0x0c,0x66,0x7a,0x1e,0xa2,0x22,0xc1,0xb2,0x22,0xc2,0x1b,0xca,0xc2,0x62,0xc1, +0xb0,0xaa,0xa0,0x69,0x0a,0x92,0x22,0xc1,0x0b,0x99,0x56,0xd9,0x07,0xa2,0x22, +0x24,0xaa,0xa5,0xa8,0x0a,0xe6,0x9a,0x28,0xd2,0x22,0xbf,0xb8,0xa2,0xc2,0x22, +0x24,0x82,0x22,0x46,0xf2,0x22,0x21,0x80,0x8a,0xa0,0x4a,0xff,0xca,0xe5,0x5a, +0xbb,0x5a,0xcc,0xb8,0x0b,0xf2,0x1f,0x08,0xf9,0x08,0xc8,0x0c,0xa8,0x0e,0xd0, +0xcc,0xa0,0xb9,0x0c,0x88,0x03,0x82,0x28,0x3f,0xe0,0x08,0x00,0x9c,0x6a,0x0c, +0x19,0xa2,0x22,0x21,0xc2,0x12,0x75,0x4a,0xaa,0xa2,0x1a,0x08,0xb2,0x22,0xc3, +0xc0,0xaa,0xc0,0xb0,0xaa,0xa0,0x99,0x0a,0x88,0x03,0xa2,0x22,0x24,0x82,0x28, +0x3e,0x5a,0xaa,0xa8,0x0a,0xe0,0x08,0x00,0x9c,0x6a,0x0c,0x19,0xa2,0x22,0x21, +0xc2,0x12,0x75,0x4a,0xaa,0xa2,0x1a,0x08,0xb2,0x22,0xc4,0xc0,0xaa,0xc0,0xb0, +0xaa,0xa0,0x99,0x0a,0x2b,0x44,0x4b,0x55,0xb2,0x12,0x17,0x1b,0x66,0xb7,0xa6, +0x02,0x46,0xcc,0xff,0xa2,0x12,0x16,0xd2,0x22,0x3e,0xe2,0xa0,0x80,0xe0,0xdd, +0x20,0xd2,0x62,0x3e,0xa6,0x1a,0x19,0xe2,0xaf,0x7f,0x0c,0x06,0xc2,0x22,0x23, +0x1b,0x66,0xf8,0x0c,0x4b,0xcc,0xe6,0x6f,0x05,0xe0,0xdd,0x10,0xd2,0x62,0x3e, +0xa7,0x26,0xed,0x0c,0x06,0xad,0x02,0xb8,0x11,0xa5,0xb5,0xff,0x0c,0x04,0x0c, +0x68,0x76,0xa8,0x19,0xb2,0x22,0x10,0xa2,0x22,0x11,0x92,0x22,0x12,0x4a,0xaa, +0x4a,0x99,0x4a,0xbb,0x62,0x5b,0x00,0x2b,0x44,0x62,0x5a,0x00,0x62,0x59,0x00, +0x0c,0xc4,0xf2,0x22,0x3e,0x0c,0x4b,0x76,0xab,0x18,0xd8,0xe2,0xe2,0x22,0x10, +0xc2,0x22,0x12,0x4a,0xee,0x4a,0xcc,0x4a,0xdd,0xd2,0x9d,0x00,0x2b,0x44,0xd2, +0x5e,0x00,0x62,0x5c,0x00,0x17,0x6f,0x09,0x88,0x03,0x82,0x28,0x32,0xad,0x02, +0xe0,0x08,0x00,0x0c,0x0a,0x0c,0x0b,0xc2,0xa3,0x20,0xca,0xc2,0xa5,0x9c,0xf7, +0x62,0x62,0xcc,0x1d,0xf0,0xc2,0x22,0x23,0x76,0x99,0x20,0xd8,0x0c,0x4b,0xcc, +0x66,0x4d,0x17,0xcd,0x06,0x88,0x03,0xad,0x02,0x82,0x28,0x3c,0x0c,0x1b,0xe0, +0x08,0x00,0xbd,0x0a,0xad,0x02,0x65,0xad,0xfd,0x46,0x96,0xff,0x1b,0x66,0x06, +0x95,0xff,0x00,0x00,0x36,0xa1,0x00,0xa2,0x12,0x17,0x39,0x91,0xe6,0x1a,0x02, +0x46,0x92,0x00,0x0c,0x05,0x0c,0x03,0x0c,0x06,0x0c,0x04,0x98,0x41,0xb8,0x91, +0x99,0x71,0xb0,0xb0,0xf4,0xb9,0x61,0x72,0x22,0x24,0xc8,0xa2,0x4a,0x77,0x4a, +0xcc,0xc8,0x0c,0x78,0x07,0x16,0x7c,0x21,0xa6,0x97,0x02,0x46,0x84,0x00,0x82, +0x22,0xc1,0xb2,0xc7,0xf9,0x66,0x28,0x0a,0x92,0x22,0xc2,0x98,0x19,0x50,0x99, +0xc0,0x16,0xd9,0x1f,0xb6,0x3b,0x02,0xc6,0x7d,0x00,0x98,0xc2,0xd8,0x91,0xd9, +0x51,0x90,0xc7,0xa0,0xc8,0x0c,0xc9,0xa1,0x66,0x77,0x03,0xe8,0x89,0xe9,0xa1, +0xa8,0xa1,0xb8,0x91,0x81,0x48,0x2c,0xc8,0x32,0x88,0x08,0xd2,0x22,0x19,0x82, +0x28,0x2d,0x6a,0xdd,0xe0,0x08,0x00,0x92,0x22,0x40,0x9c,0x49,0xa8,0xa1,0xb8, +0x91,0x81,0x42,0x2c,0xc8,0x32,0x88,0x08,0xd2,0x22,0xc0,0x82,0x28,0x2d,0x6a, +0xdd,0xe0,0x08,0x00,0xa8,0xa1,0xb8,0x91,0xd2,0x12,0x3a,0xe2,0x12,0x3b,0x81, +0x3b,0x2c,0xc2,0x22,0x1c,0x88,0x08,0x3a,0xcc,0x82,0x28,0x2f,0xc2,0x1c,0x00, +0xe0,0x08,0x00,0x81,0x36,0x2c,0xad,0x02,0x88,0x08,0x0c,0x0b,0x82,0x28,0x3c, +0xcd,0x05,0xe0,0x08,0x00,0xa9,0x81,0x92,0xca,0xec,0xf6,0x29,0x11,0x81,0x30, +0x2c,0xa2,0x22,0x17,0x88,0x08,0xb8,0xa1,0x82,0x28,0x21,0xc8,0x91,0xe0,0x08, +0x00,0x81,0x2b,0x2c,0x88,0x08,0xad,0x02,0x82,0x28,0x48,0xb8,0x81,0xe0,0x08, +0x00,0x16,0xca,0x0b,0x92,0x12,0x16,0x0c,0x0a,0xa9,0x51,0xa2,0x22,0x2b,0x9a, +0x95,0xa0,0x99,0xa0,0x98,0x09,0x16,0x49,0x04,0xad,0x02,0xb8,0x81,0x0c,0x0c, +0xe5,0xf2,0xfd,0xe8,0x61,0x81,0x3e,0x2c,0xc2,0x22,0x30,0x92,0x12,0x62,0xdd, +0x0a,0xa9,0x71,0xa2,0x12,0x16,0xb2,0x22,0x2b,0xaa,0xa5,0xb0,0xaa,0xa0,0xa8, +0x0a,0x99,0x01,0x88,0x08,0xf2,0xc1,0x14,0x82,0x28,0x16,0xb8,0xa1,0xe0,0x08, +0x00,0x66,0x8a,0x0d,0xc2,0x22,0x14,0xc0,0xc7,0x90,0xb2,0x9c,0x00,0x1b,0xbb, +0xb2,0x5c,0x00,0xd2,0x22,0x30,0xd9,0xa1,0x81,0x4b,0x2b,0xa8,0xa2,0x88,0x08, +0x4a,0xaa,0x88,0x98,0xa8,0x0a,0xe0,0x08,0x00,0xcc,0xca,0xa2,0x22,0x13,0xa0, +0xa7,0x90,0x92,0x9a,0x00,0x1b,0x99,0x92,0x5a,0x00,0x81,0x07,0x2c,0x88,0x08, +0xa8,0xa1,0x82,0x28,0x19,0xb8,0x51,0xe0,0x08,0x00,0xc8,0x51,0xa6,0xfc,0x04, +0xc2,0xa0,0xfc,0xc9,0x51,0xb8,0xa1,0xa8,0xa2,0x88,0x02,0x4a,0xaa,0x88,0x88, +0xa8,0x0a,0xe0,0x08,0x00,0xb2,0x22,0xc1,0xf2,0x22,0xc2,0xb2,0xcb,0xfe,0x56, +0xfb,0x08,0xc8,0x0f,0x57,0x1c,0x02,0xc6,0x21,0x00,0x06,0x1c,0x00,0x66,0x77, +0x9d,0xf2,0x22,0x36,0x3c,0x0d,0xd7,0x1f,0x95,0x66,0xbf,0x07,0xe1,0x27,0x2c, +0xe9,0x71,0xc6,0x04,0x00,0x66,0x8f,0x10,0x81,0x24,0x2c,0x92,0x22,0x3e,0xf1, +0x1e,0x2c,0x90,0x93,0x04,0x90,0xf8,0x93,0xf9,0x71,0xa2,0x12,0x16,0x0c,0x0b, +0xb9,0x51,0xb2,0x22,0x2b,0xaa,0xa5,0xb0,0xaa,0xa0,0xa8,0x0a,0x16,0xda,0xf5, +0xb8,0xa1,0xd8,0x71,0x81,0x06,0x2c,0xc2,0x22,0x30,0x92,0x12,0x62,0x99,0x01, +0x88,0x08,0xe8,0x61,0x82,0x28,0x16,0xf2,0xc1,0x14,0xe0,0x08,0x00,0xa2,0xca, +0xf8,0x56,0xba,0xf3,0xc2,0x22,0x14,0xc0,0xc7,0x90,0xb2,0x9c,0x00,0x1b,0xbb, +0xb2,0x5c,0x00,0x86,0xca,0xff,0xb8,0xa1,0xc8,0x51,0xd8,0xa2,0x88,0x02,0xa8, +0x1f,0x88,0x88,0xd0,0xaa,0xa0,0xa8,0x0a,0xe0,0x08,0x00,0x66,0x77,0x10,0x81, +0xd5,0x2b,0xb8,0x81,0x88,0x08,0xad,0x02,0x82,0x28,0x3a,0xc8,0x51,0xe0,0x08, +0x00,0xa2,0x12,0x17,0x2b,0x33,0x62,0xc6,0x10,0x4b,0x44,0x1b,0x55,0xa7,0xa5, +0x02,0x06,0x72,0xff,0x1d,0xf0,0x00,0x00,0x36,0xc1,0x00,0x26,0x03,0x48,0x30, +0xc0,0xf4,0x41,0xc9,0x2b,0xad,0x02,0x88,0x04,0x0c,0x1b,0x82,0x28,0x3b,0xdd, +0x01,0xe0,0x08,0x00,0xa0,0x90,0xf4,0xa6,0x19,0x2e,0x3d,0x01,0x30,0x59,0x90, +0xb2,0x93,0x00,0x26,0x0b,0x1e,0x98,0x92,0x90,0x9b,0xa0,0x98,0x09,0x9c,0x49, +0x88,0x04,0xa2,0x22,0x23,0x82,0x28,0x3e,0xa0,0xab,0xa0,0xa8,0x0a,0xe0,0x08, +0x00,0x8c,0x2a,0x0c,0x12,0x1d,0xf0,0x2b,0x33,0x57,0x93,0xd5,0x0c,0x02,0x1d, +0xf0,0x00,0x36,0xa1,0x00,0x9d,0x03,0x88,0x03,0xa2,0x12,0x16,0x89,0x81,0xe6, +0x1a,0x02,0x06,0x59,0x00,0x0c,0x05,0x0c,0x06,0x0c,0x07,0x0c,0x04,0x39,0xa1, +0x80,0xe0,0xf4,0xe9,0x61,0x32,0x22,0x23,0xf8,0x92,0x4a,0x33,0x4a,0xff,0xf8, +0x0f,0x38,0x03,0x9c,0x0f,0x81,0xab,0x2b,0x88,0x08,0x82,0x28,0x3e,0xad,0x03, +0xe0,0x08,0x00,0xdc,0x2a,0xa2,0x12,0x16,0x2b,0x66,0x72,0xc7,0x10,0x4b,0x44, +0x1b,0x55,0xa7,0x25,0xd2,0x98,0xa1,0xc6,0x48,0x00,0x81,0xa2,0x2b,0xad,0x02, +0x88,0x08,0x0c,0x1b,0x82,0x28,0x3c,0xcd,0x05,0xe0,0x08,0x00,0x81,0x9e,0x2b, +0xbd,0x0a,0x88,0x08,0xa9,0x71,0x82,0x28,0x48,0xad,0x02,0xe0,0x08,0x00,0xcc, +0xaa,0x98,0xc2,0x90,0x93,0xa0,0x98,0x09,0x99,0x91,0x06,0x01,0x00,0xa2,0x22, +0x30,0xa9,0x91,0xb8,0x91,0xc8,0x81,0xa8,0x92,0x88,0x02,0x4a,0xaa,0x88,0x98, +0xa8,0x0a,0xe0,0x08,0x00,0x81,0x90,0x2b,0x88,0x08,0xa8,0x91,0x82,0x28,0x17, +0xb8,0x81,0xe0,0x08,0x00,0xa8,0x91,0xb8,0x81,0x81,0x8c,0x2b,0xc8,0x32,0x88, +0x08,0xd2,0x22,0x18,0x82,0x28,0x2d,0x7a,0xdd,0xe0,0x08,0x00,0x98,0x71,0x92, +0xc9,0xf0,0xf6,0x39,0x11,0x81,0x85,0x2b,0xa2,0x22,0x16,0x88,0x08,0xb8,0x91, +0x82,0x28,0x21,0xc8,0x81,0xe0,0x08,0x00,0x81,0x81,0x2b,0x88,0x08,0xad,0x02, +0x82,0x28,0x48,0xb8,0x71,0xe0,0x08,0x00,0x16,0xaa,0x06,0xe0,0x93,0x11,0x0c, +0x0b,0xa2,0x22,0x2b,0xb9,0x41,0x4a,0xaa,0xa8,0x0a,0x99,0x51,0x16,0xaa,0x04, +0xb8,0x71,0xad,0x02,0x0c,0x1c,0x65,0xc8,0xfd,0xb8,0x91,0xf2,0xc1,0x10,0x81, +0x93,0x2b,0xe8,0x51,0xc8,0xc2,0xdd,0x0a,0x98,0xe2,0xa2,0x22,0x2b,0x90,0x93, +0x90,0x92,0x99,0x00,0x4a,0xaa,0xea,0xcc,0xc8,0x0c,0xa8,0x0a,0x99,0x01,0x88, +0x08,0xf0,0x33,0x11,0x82,0x28,0x16,0xe8,0x61,0xe0,0x08,0x00,0x98,0x51,0x66, +0x8a,0x0c,0x82,0x22,0x14,0x8a,0x83,0xf2,0x98,0x00,0x1b,0xff,0xf2,0x58,0x00, +0xc8,0xc2,0xb8,0x41,0x9a,0xcc,0xc8,0x0c,0xc9,0x91,0xc6,0x00,0x00,0xb8,0x81, +0xb9,0x41,0xa8,0x91,0xd2,0x12,0x3a,0xe2,0x12,0x3b,0x31,0x5e,0x2b,0xc2,0x22, +0x1b,0x88,0x03,0x6a,0xcc,0x82,0x28,0x2f,0xc2,0x1c,0x00,0xe0,0x08,0x00,0xc6, +0xb1,0xff,0xd8,0x41,0xd9,0x09,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x01,0x9d, +0x01,0x0c,0x0a,0x1c,0x98,0x76,0xa8,0x03,0xa9,0x09,0x4b,0x99,0xa2,0x12,0x16, +0x0c,0x03,0xe6,0x1a,0x02,0xc6,0x22,0x00,0x61,0x50,0x2b,0x0c,0x04,0x52,0x22, +0x23,0xc8,0x92,0x3a,0x55,0x3a,0xcc,0xc8,0x0c,0x58,0x05,0x8c,0xdc,0x88,0x06, +0x82,0x28,0x3f,0xad,0x05,0xe0,0x08,0x00,0xcc,0xba,0xa2,0x12,0x16,0x4b,0x33, +0x1b,0x44,0xa7,0x24,0xda,0x86,0x17,0x00,0xad,0x02,0x88,0x06,0x0c,0x1b,0x82, +0x28,0x3c,0xcd,0x04,0xe0,0x08,0x00,0x7d,0x0a,0x88,0x06,0xad,0x02,0x82,0x28, +0x48,0xbd,0x07,0xe0,0x08,0x00,0x9d,0x01,0x90,0x97,0xa0,0xbc,0x3a,0xa8,0x09, +0xec,0xfa,0xb2,0x22,0xc6,0xec,0xab,0x92,0x61,0x1c,0x66,0x35,0x07,0xc2,0x22, +0xcc,0x92,0x61,0x1c,0xdc,0xcc,0xbd,0x07,0xad,0x02,0xe2,0x22,0x23,0x0c,0x1c, +0xea,0xe3,0xe8,0x0e,0xf2,0x22,0x12,0xdd,0x0e,0xf0,0xee,0x90,0xe2,0x9e,0x00, +0xa5,0xb3,0xfd,0x92,0x21,0x1c,0x0c,0x1f,0xf9,0x09,0xc6,0xe4,0xff,0x1d,0xf0, +0x00,0x00,0x00,0x36,0x41,0x01,0x9d,0x01,0x0c,0x0a,0x1c,0x98,0x76,0xa8,0x03, +0xa9,0x09,0x4b,0x99,0xa2,0x12,0x17,0x0c,0x03,0xa6,0x1a,0x5c,0x61,0x26,0x2b, +0x0c,0x17,0x0c,0x04,0x52,0x22,0x24,0x3a,0x55,0x58,0x05,0x0c,0xab,0x57,0x2b, +0x42,0x88,0xa2,0x3a,0x88,0x88,0x08,0xbc,0x98,0xad,0x02,0x88,0x06,0x0c,0x0b, +0x82,0x28,0x3c,0xcd,0x04,0xe0,0x08,0x00,0xbd,0x0a,0x9d,0x01,0x90,0x9a,0xa0, +0xa8,0x09,0xdc,0xba,0xa2,0x22,0xc6,0x92,0x61,0x1c,0xdc,0x3a,0xdd,0x05,0xad, +0x02,0xe2,0x22,0x12,0x0c,0x0c,0xe0,0xe5,0x90,0xe2,0x9e,0x00,0x65,0xac,0xfd, +0x92,0x21,0x1c,0xa2,0x12,0x17,0x79,0x09,0x4b,0x33,0x1b,0x44,0xa7,0x24,0xa9, +0x1d,0xf0,0x00,0x36,0x81,0x00,0x0c,0x06,0x0c,0x04,0x0c,0x87,0x9d,0x03,0x0c, +0xb3,0x99,0x41,0x52,0x22,0x24,0x88,0xa2,0x4a,0x55,0x4a,0x88,0x88,0x08,0x58, +0x05,0x16,0x18,0x0f,0x30,0x85,0xc0,0x16,0xb8,0x0e,0x92,0xc5,0xf9,0xb6,0x39, +0x02,0x86,0x38,0x00,0x81,0x02,0x2b,0xad,0x02,0x88,0x08,0x0c,0x0b,0x82,0x28, +0x3c,0xcd,0x06,0xe0,0x08,0x00,0xa9,0x51,0x66,0x75,0x52,0x90,0x64,0x00,0x99, +0x21,0x81,0x37,0x2a,0xa8,0xa2,0x88,0x08,0x4a,0xaa,0x88,0x98,0xa8,0x0a,0xe0, +0x08,0x00,0xa9,0x01,0xa8,0x51,0x65,0xf1,0xfd,0x81,0xf6,0x2a,0x98,0x01,0xb8, +0x21,0xaa,0x99,0xb0,0xe6,0x13,0x20,0x20,0x00,0xa8,0x41,0xb2,0x22,0x46,0x88, +0x08,0xb8,0x4b,0x82,0x28,0x48,0xa0,0x99,0xc0,0x99,0x31,0xad,0x02,0xe0,0x08, +0x00,0x8c,0xea,0xad,0x02,0x0c,0x1c,0x0c,0x4d,0xb2,0x22,0x46,0xe8,0x31,0xb8, +0x4b,0xa5,0xa1,0xfd,0x66,0x85,0x76,0x50,0x64,0x00,0x81,0x22,0x2a,0xa8,0xa2, +0x88,0x08,0x4a,0xaa,0x88,0x98,0xa8,0x0a,0xe0,0x08,0x00,0xa9,0x11,0x59,0x21, +0xa8,0x51,0x25,0xec,0xfd,0xb8,0x51,0x81,0xe0,0x2a,0x58,0x11,0x98,0x21,0xaa, +0x55,0x90,0xe6,0x13,0x20,0x20,0x00,0xad,0x02,0x88,0x08,0x98,0x41,0x82,0x28, +0x48,0x90,0x55,0xc0,0xe0,0x08,0x00,0x59,0x31,0x8c,0xba,0xb8,0x51,0xad,0x02, +0x0c,0x0c,0x0c,0x8d,0xed,0x05,0xa5,0x9c,0xfd,0x82,0x22,0x3e,0x17,0x68,0x23, +0x81,0xd2,0x2a,0xad,0x02,0x88,0x08,0xb2,0x22,0x46,0x82,0x28,0x48,0xb8,0x4b, +0xe0,0x08,0x00,0x8c,0xea,0xad,0x02,0x0c,0x1c,0x0c,0x4d,0xb2,0x22,0x46,0xe8, +0x31,0xb8,0x4b,0x25,0x9a,0xfd,0x1b,0x66,0x4b,0x44,0x0b,0x77,0x56,0x47,0xef, +0x1d,0xf0,0x36,0x61,0x00,0xfd,0x07,0xed,0x06,0xdd,0x05,0xcd,0x04,0x81,0xca, +0x2a,0x98,0xc1,0x99,0x01,0x88,0x08,0xbd,0x03,0x82,0x28,0xbe,0xad,0x02,0xe0, +0x08,0x00,0x2d,0x0a,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xe6,0x42,0x02,0xd6, +0x52,0x00,0xe6,0x82,0x06,0xa6,0x62,0x03,0x0c,0x12,0x1d,0xf0,0x0c,0x02,0x1d, +0xf0,0x00,0x36,0x41,0x00,0x0c,0x48,0xf0,0x64,0x00,0x0c,0xf7,0x80,0x87,0x10, +0xf0,0x77,0x10,0xf0,0xf7,0x30,0xf0,0xf8,0x20,0xf0,0xe6,0x13,0x10,0x20,0x00, +0x88,0x12,0x68,0x22,0x0c,0x09,0x87,0x96,0x1b,0x3d,0x09,0xf0,0x64,0x00,0x0c, +0xfa,0x90,0x9a,0x10,0xf0,0xaa,0x10,0xf0,0xfa,0x30,0xf0,0xf9,0x20,0xf0,0xe6, +0x13,0x10,0x20,0x00,0x86,0x0f,0x00,0x8c,0x53,0xb8,0x08,0xb0,0xb0,0xf5,0xb9, +0x03,0x8c,0x54,0xc8,0x08,0xc0,0xc0,0xf4,0xc9,0x04,0x38,0x02,0x8c,0x25,0xd8, +0x18,0xd9,0x05,0xe2,0xd3,0x04,0x8b,0x88,0xe7,0x98,0x01,0x8d,0x03,0x0c,0x13, +0x89,0x12,0xf0,0x64,0x00,0x0c,0xf6,0x90,0x96,0x10,0xf0,0x66,0x10,0xf0,0xf6, +0x30,0xf0,0xf9,0x20,0xf0,0xe6,0x13,0x10,0x20,0x00,0x2d,0x03,0x1d,0xf0,0xf0, +0x49,0x18,0x20,0x36,0x81,0x00,0x0c,0x07,0x0c,0x06,0x0c,0x04,0x1c,0xf5,0x0c, +0x08,0x0c,0x0b,0x0c,0x0c,0xc9,0x51,0xb9,0x31,0x89,0x41,0x89,0x01,0x89,0x11, +0x89,0x21,0xbd,0x01,0x4b,0xc1,0xa2,0x22,0x1c,0x8b,0xd1,0xa8,0x0a,0xe5,0xf4, +0xff,0x16,0x7a,0x07,0xb8,0x01,0xdc,0x14,0x66,0x7b,0x0f,0xc8,0x11,0x66,0x7c, +0x0a,0x0c,0x0a,0x0c,0x14,0xd8,0x21,0xd9,0x31,0x46,0x00,0x00,0x0c,0x1a,0x66, +0x1b,0x10,0xe8,0x11,0x1c,0x9f,0xf7,0x9e,0x09,0x0c,0x0a,0x0c,0x18,0x98,0x21, +0x99,0x41,0x89,0x51,0x57,0x9b,0x05,0x78,0x11,0x0c,0x0a,0x0c,0x16,0x16,0x5a, +0xfb,0x32,0x22,0x1a,0x38,0x03,0x9c,0x03,0xad,0x03,0xb8,0x01,0xc8,0x11,0x88, +0x03,0xd8,0x21,0xe0,0x08,0x00,0x38,0x43,0x56,0xd3,0xfe,0x32,0x22,0x1b,0x38, +0x03,0x16,0x43,0xf9,0xb8,0x01,0xe8,0x03,0x66,0x7b,0x05,0x81,0xdb,0xff,0x87, +0x1e,0x08,0xad,0x03,0xc8,0x11,0xd8,0x21,0xe0,0x0e,0x00,0x38,0x43,0x56,0x43, +0xfe,0x86,0xdd,0xff,0x8c,0x94,0xc8,0x31,0x0c,0x7a,0x88,0xf2,0x0c,0x7b,0xe0, +0x08,0x00,0x98,0x51,0x8c,0x99,0xc8,0x41,0x0c,0x1a,0x88,0xf2,0x1c,0x9b,0xe0, +0x08,0x00,0x8c,0x96,0xbd,0x07,0x1c,0xfa,0x88,0xf2,0x0c,0x0c,0xe0,0x08,0x00, +0x1d,0xf0,0x00,0x00,0x00,0x36,0x61,0x00,0x82,0x22,0x14,0xa2,0x22,0x1c,0x0c, +0x0b,0xa8,0x0a,0xb9,0x01,0xb9,0x11,0xb9,0x21,0xe0,0x08,0x00,0x6d,0x0a,0xa6, +0x1a,0x27,0x0c,0x05,0xbd,0x01,0x4b,0xc1,0xa2,0x22,0x1c,0x8b,0xd1,0xa8,0x0a, +0xa5,0xe7,0xff,0x8c,0xfa,0xb8,0x11,0xa8,0x01,0xb7,0x93,0x02,0xa7,0x14,0x06, +0x88,0xf2,0xc8,0x21,0xe0,0x08,0x00,0x1b,0x55,0x57,0x96,0xd9,0x1d,0xf0,0x00, +0x00,0x00,0xac,0xb7,0x08,0x20,0xad,0xc0,0x08,0x20,0xa8,0x7d,0x05,0x20,0x00, +0x80,0x05,0x20,0xb0,0xb7,0x08,0x20,0x00,0x00,0x04,0x00,0x00,0x80,0xff,0xff, +0xab,0xfd,0xff,0xff,0x00,0x01,0x05,0x20,0x36,0x41,0x00,0x71,0xfa,0xff,0x31, +0xf7,0xff,0x51,0xf7,0xff,0x7c,0xc6,0x41,0xf3,0xff,0x21,0xf3,0xff,0x29,0x04, +0x3b,0x22,0x60,0x22,0x10,0x29,0x04,0x37,0x35,0x0b,0x0c,0x03,0x39,0x07,0x0c, +0x12,0x1d,0xf0,0x0c,0x02,0x1d,0xf0,0x91,0xf1,0xff,0xa1,0xf1,0xff,0x81,0xf1, +0xff,0x41,0xf1,0xff,0x60,0x68,0x10,0xa0,0x44,0x10,0x20,0x44,0xc0,0x9a,0x44, +0x67,0x24,0xe1,0x69,0x07,0x80,0xb2,0x41,0x16,0x5b,0xfd,0x0c,0x06,0x1b,0x66, +0xd8,0x05,0x4b,0x55,0xd9,0x02,0xc8,0x07,0x4b,0x22,0xc0,0xc2,0x41,0xc7,0x36, +0xed,0x86,0xef,0xff,0x00,0x00,0x00,0xfe,0xfe,0xfe,0xfe,0x36,0x41,0x00,0xd1, +0xdf,0xff,0x81,0xfd,0xff,0xa8,0x0d,0xb1,0xd9,0xff,0x87,0x9a,0x06,0x25,0xf8, +0xff,0x2d,0x0a,0x1d,0xf0,0xa0,0x92,0x41,0xa8,0x0b,0x9c,0x59,0xb1,0xd7,0xff, +0x0c,0x0c,0x1b,0xcc,0xf8,0x0a,0x4b,0xaa,0xf9,0x0b,0xe8,0x0d,0x4b,0xbb,0xe0, +0xe2,0x41,0xe7,0x3c,0xed,0x0c,0x12,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x31, +0x74,0x2a,0xc8,0x03,0x8c,0x7c,0x88,0x2c,0x8c,0x38,0x1d,0xf0,0x00,0x00,0x00, +0xc8,0x22,0xc9,0x03,0x16,0xe2,0x04,0xa8,0x02,0x98,0x12,0x16,0xea,0x04,0xa9, +0x1c,0xd8,0x32,0x8c,0x09,0x99,0x4c,0x16,0x8d,0x04,0xd9,0x5c,0x91,0x6a,0x2a, +0xb1,0x6d,0x2a,0x81,0x6a,0x2a,0xe1,0x6b,0x2a,0xf1,0x69,0x2a,0xf2,0x6c,0x12, +0xe2,0x6c,0x13,0x82,0x6c,0x11,0xb2,0x6c,0x15,0x99,0xfc,0x1c,0x0b,0x91,0x67, +0x2a,0x92,0x6c,0x16,0xe0,0x0d,0x00,0x88,0x03,0xa9,0x28,0xa8,0x18,0x88,0x58, +0x1c,0x0b,0xe0,0x08,0x00,0x98,0x03,0xa9,0x39,0x1d,0xf0,0xa8,0x1c,0xd8,0x5c, +0x46,0xef,0xff,0xa8,0x1c,0x46,0xeb,0xff,0xd8,0x5c,0xc6,0xec,0xff,0x00,0x00, +0x00,0x00,0x00,0x00,0x36,0x81,0x00,0x39,0x22,0x39,0x51,0xd2,0xc1,0x14,0xd0, +0x80,0x0c,0x1c,0xf6,0xaf,0xe0,0x0a,0x22,0x82,0x29,0x04,0x00,0xaf,0xe0,0x0a, +0x22,0x82,0x29,0x05,0x00,0xaf,0xe0,0x0a,0x22,0x82,0x29,0x06,0x00,0x8f,0x9d, +0xbf,0x42,0x82,0x29,0x07,0x00,0x0f,0x62,0x01,0x82,0x2e,0x2b,0x11,0x00,0x00, +0x8b,0x0d,0xb0,0x00,0x0c,0x4b,0xa2,0x00,0x0a,0x0d,0x82,0x92,0x08,0x80,0x58, +0x01,0x40,0x98,0x01,0x90,0x9c,0x31,0x50,0x5c,0x31,0xc0,0x88,0x01,0x80,0x8c, +0x31,0x9a,0x55,0x8a,0x55,0x0f,0x84,0x40,0x82,0x6e,0x09,0x01,0x00,0x8f,0x20, +0x04,0x28,0x44,0x0c,0x0c,0x11,0x8f,0xa4,0x1c,0x82,0x48,0x10,0x08,0x01,0x2f, +0x20,0x64,0x43,0x44,0x0c,0x0c,0x11,0x00,0x44,0x0d,0x58,0x22,0x38,0xe2,0x59, +0x92,0x2f,0x66,0xe0,0x22,0xc0,0x10,0x0c,0x00,0x00,0x13,0x40,0x00,0xe5,0xa1, +0xe9,0x92,0x42,0xc2,0x28,0x91,0x2f,0x2a,0xa2,0x22,0x06,0x92,0x29,0x00,0x82, +0x92,0x08,0x92,0x29,0x01,0x80,0x8c,0x21,0x90,0x92,0x41,0xa0,0x99,0xc0,0x92, +0xc9,0xf0,0x92,0x62,0x0a,0x76,0x00,0x07,0x0f,0x20,0x84,0x28,0x44,0x0c,0x0c, +0x11,0xaf,0x81,0x00,0xa2,0x2e,0x4a,0x01,0x00,0xaf,0xe0,0x0a,0x22,0x48,0x40, +0x20,0x01,0xaf,0xe0,0x0a,0x22,0x82,0x39,0x04,0x00,0xaf,0xe0,0x0a,0x22,0xa4, +0x30,0x18,0x02,0xaf,0xe0,0x0a,0x22,0x82,0x31,0x04,0x11,0x00,0xc4,0x0d,0xf8, +0xa2,0x7c,0xc3,0x30,0xff,0x10,0xf9,0xa2,0x1d,0xf0,0x00,0x00,0xd6,0x83,0xf9, +0x30,0xb0,0x60,0x00,0x0b,0x40,0x50,0xa0,0x91,0xa9,0x92,0x86,0xe2,0xff,0x00, +0x00,0x00,0x36,0x61,0x00,0xad,0x03,0x81,0x10,0x2a,0x49,0x21,0x7c,0xc6,0x3b, +0xc5,0x7d,0x02,0xb8,0x67,0x21,0x14,0x2a,0x98,0x97,0x60,0xcc,0x10,0x48,0x77, +0x92,0x61,0x01,0x82,0x28,0x00,0x28,0x02,0x88,0x78,0x30,0xbb,0xa0,0xe0,0x08, +0x00,0x81,0x07,0x2a,0xa8,0x57,0x88,0x08,0xbd,0x03,0x88,0x78,0xc2,0x27,0x06, +0xe0,0x08,0x00,0x6c,0xdb,0x1c,0xfc,0xed,0x01,0xf2,0xc5,0x15,0xc0,0xff,0x01, +0x40,0xff,0xc0,0xf0,0xf1,0x41,0xf9,0x01,0xe0,0x00,0x0c,0x0f,0xae,0x41,0x82, +0x2a,0x31,0x80,0x10,0xaf,0xa0,0x01,0xa2,0x02,0x0b,0x04,0x00,0x2f,0x01,0x81, +0x49,0xee,0x0a,0x01,0x00,0x2f,0x49,0x01,0x42,0xa4,0x00,0x80,0x00,0xa0,0xa5, +0x41,0xef,0x45,0x92,0x43,0x6c,0x0c,0x83,0x00,0x00,0x0e,0x0d,0xd8,0x01,0x1b, +0xcb,0xd0,0xbc,0x93,0x60,0xbb,0x10,0xb9,0x31,0xe6,0x1b,0x02,0x06,0x34,0x00, +0x0b,0xbb,0x0c,0x16,0xe8,0x11,0xb0,0x99,0x11,0x30,0xaa,0xa0,0x8f,0xf4,0x02, +0x22,0x44,0x0c,0x0c,0x11,0x9a,0x92,0xea,0xc4,0x90,0x03,0xbc,0x4f,0xf5,0x92, +0x22,0x44,0x0c,0x0c,0x11,0xcf,0xf4,0x82,0x22,0x44,0x0c,0x0c,0x11,0x90,0xe6, +0xa7,0xaf,0x22,0x55,0xa2,0x22,0x33,0x80,0x10,0x4f,0x99,0x93,0x43,0xe0,0x40, +0x5d,0x0e,0xef,0x83,0x05,0x62,0xc0,0x40,0x5e,0x0e,0x90,0x26,0xa7,0x8f,0x54, +0x93,0x43,0x0a,0x58,0x51,0x02,0x2f,0x09,0x01,0x42,0xe0,0x40,0xc5,0x0c,0x0f, +0x0b,0x9f,0x43,0xc0,0x40,0xc6,0x0c,0x76,0x9b,0x59,0xb0,0x99,0x11,0x8f,0xc8, +0x69,0x43,0x02,0x58,0x09,0x02,0x2f,0x01,0x81,0x49,0x2e,0x31,0x80,0x10,0x2f, +0x3f,0x69,0x43,0x30,0x5c,0xa9,0x02,0x30,0x88,0xa0,0x10,0x4c,0x9d,0x90,0x03, +0x8c,0x90,0xa6,0x87,0x8f,0xf0,0x02,0x22,0x44,0x0c,0x0c,0x11,0xcf,0xf0,0x82, +0x22,0xe0,0x40,0x15,0x08,0x2f,0x22,0x45,0xa2,0xc0,0x40,0x16,0x08,0x90,0xa6, +0x87,0xcf,0xf0,0x82,0x22,0x0a,0x58,0x09,0x02,0x2f,0x69,0x01,0x42,0xe0,0x40, +0x15,0x08,0x0f,0x6b,0x9f,0x43,0xc0,0x40,0x16,0x08,0xaf,0xe0,0x0a,0x22,0x02, +0x58,0x09,0x02,0xaf,0xe0,0x0a,0x22,0x30,0x5c,0xa9,0x02,0x10,0x4c,0x9d,0x81, +0xb8,0x29,0x30,0xa5,0xa0,0x88,0x08,0xb8,0x57,0x88,0x88,0xc8,0x67,0xe0,0x08, +0x00,0x28,0x31,0xc0,0x95,0x01,0x90,0x94,0xc0,0x99,0x77,0x1d,0xf0,0x00,0x00, +0x36,0x81,0x00,0x5d,0x07,0x0c,0x08,0x89,0x07,0xac,0x12,0x9c,0xb3,0x9c,0x94, +0xa1,0xad,0x29,0xf8,0x0a,0x98,0x1f,0x90,0x92,0x41,0x67,0x39,0x0d,0x8c,0xa7, +0xb1,0xb1,0x29,0xa8,0x02,0xb7,0x1a,0x0b,0x0c,0x12,0x1d,0xf0,0x0c,0x32,0x1d, +0xf0,0x0c,0x12,0x1d,0xf0,0xad,0x03,0xb8,0x2f,0x88,0x8f,0xcd,0x06,0xe0,0x08, +0x00,0xf1,0xa1,0x29,0xf8,0x0f,0x78,0x3f,0x38,0x2f,0x69,0x01,0xa8,0xb2,0x6d, +0x03,0xbc,0x0a,0x88,0xbf,0xe0,0x08,0x00,0xf1,0x9c,0x29,0xf8,0x0f,0xac,0x4a, +0xbd,0x03,0x39,0x21,0xa8,0xb2,0xcd,0x07,0xd2,0x11,0x00,0x88,0xef,0xed,0x01, +0xe0,0x08,0x00,0x8c,0x2a,0x0c,0x62,0x1d,0xf0,0x38,0x01,0x16,0xd3,0x0d,0x6d, +0x07,0xf1,0x92,0x29,0x78,0x21,0xf8,0x0f,0xa8,0xc2,0xac,0x5a,0x88,0xbf,0xe0, +0x08,0x00,0xf1,0x8e,0x29,0x38,0x01,0xf8,0x0f,0x9c,0x9a,0xbd,0x06,0x69,0x11, +0x30,0xd0,0xf4,0xa8,0xc2,0xcd,0x07,0x88,0xef,0xed,0x01,0xe0,0x08,0x00,0x16, +0x2a,0x09,0x0c,0x62,0x1d,0xf0,0x38,0x01,0xb8,0x62,0xa8,0x1f,0x3a,0xbb,0xa0, +0xa2,0x41,0xb7,0xba,0x03,0x0c,0x72,0x1d,0xf0,0xcd,0x07,0xbd,0x06,0x69,0x31, +0x79,0x41,0x30,0xd0,0xf4,0x82,0x2f,0x11,0xad,0x02,0xe0,0x08,0x00,0x78,0x41, +0x3d,0x0a,0xa9,0x01,0x16,0x0a,0x07,0xa8,0xd2,0x6d,0x07,0xac,0xfa,0x81,0x79, +0x29,0x88,0x08,0x88,0xb8,0xe0,0x08,0x00,0x38,0x01,0xac,0x1a,0xbd,0x07,0xa8, +0xd2,0x81,0x74,0x29,0x30,0xd0,0xf4,0x88,0x08,0xc8,0x31,0x88,0xe8,0xed,0x01, +0xe0,0x08,0x00,0x8c,0x3a,0x0c,0x62,0x1d,0xf0,0x00,0x38,0x01,0x16,0x23,0x05, +0x68,0x31,0xa2,0x21,0x10,0x26,0x0a,0x39,0x37,0xba,0x08,0xa9,0x01,0x3d,0x0a, +0x0c,0x82,0x46,0x00,0x00,0x0c,0x02,0x81,0x68,0x29,0xad,0x06,0x88,0x08,0xbd, +0x04,0x88,0x88,0xcd,0x03,0xe0,0x08,0x00,0x98,0x01,0x99,0x05,0x1d,0xf0,0x38, +0x01,0x9c,0xb3,0x6d,0x07,0xf1,0x61,0x29,0x78,0x11,0xf8,0x0f,0x86,0xd8,0xff, +0xa9,0x05,0x0c,0x02,0x1d,0xf0,0x0c,0x02,0x86,0xf3,0xff,0x39,0x05,0x0c,0x02, +0x1d,0xf0,0x39,0x05,0x0c,0x02,0x1d,0xf0,0x39,0x05,0x0c,0x02,0x1d,0xf0,0x00, +0x36,0x81,0x00,0x29,0x41,0xcc,0x25,0x0c,0x12,0x1d,0xf0,0x61,0x54,0x29,0x88, +0x06,0x3c,0xca,0x88,0x58,0x0c,0x4b,0xe0,0x08,0x00,0x2d,0x0a,0xcc,0x2a,0x0c, +0x42,0x1d,0xf0,0xf2,0xc1,0x10,0x91,0x57,0x29,0xa1,0x57,0x29,0x88,0x41,0xb1, +0x54,0x29,0xb9,0x02,0xa0,0x88,0x73,0x90,0x88,0x63,0x89,0x41,0x89,0x22,0xf0, +0x00,0x0c,0x1c,0xfe,0x0f,0x82,0x01,0x82,0x82,0x0b,0x04,0x00,0x8f,0xbd,0xbf, +0x42,0x82,0x0b,0x05,0x00,0x0f,0x62,0xa1,0x42,0x82,0x0b,0x06,0x00,0x0f,0x4e, +0xa1,0x42,0x82,0x0b,0x07,0x00,0x8f,0x23,0xa1,0x42,0x6e,0x0b,0x01,0x00,0x00, +0x0c,0x0d,0x88,0x06,0x39,0x32,0x88,0x58,0x99,0x62,0xe0,0x08,0x00,0xa9,0x52, +0x16,0xaa,0x06,0x16,0xf4,0x08,0x92,0x14,0x00,0x92,0x52,0x08,0x88,0x06,0xad, +0x02,0x88,0xf8,0xb2,0x21,0x04,0xe0,0x08,0x00,0xc2,0x92,0x08,0xd8,0x32,0x0c, +0x03,0x39,0xb2,0x39,0xc2,0x39,0xd2,0xd0,0x90,0x04,0x40,0xac,0x01,0xa0,0xac, +0x31,0x07,0x6d,0x04,0x0c,0x13,0x46,0x00,0x00,0x9c,0x8a,0x88,0x06,0xbd,0x03, +0x88,0x98,0xc2,0xc2,0x2c,0xe0,0x08,0x00,0x8c,0x2a,0x0c,0x52,0x1d,0xf0,0x98, +0x32,0xc2,0x92,0x08,0x90,0x90,0x04,0x80,0xac,0x01,0xa0,0xac,0x31,0xcc,0x09, +0x9c,0xca,0x88,0x06,0xbd,0x03,0x88,0x98,0xc2,0xc2,0x30,0xe0,0x08,0x00,0x8c, +0x6a,0x0c,0x52,0x1d,0xf0,0x0c,0x42,0x1d,0xf0,0x98,0x32,0xc2,0x92,0x08,0x90, +0x90,0x04,0xc0,0xac,0x01,0xa0,0xac,0x31,0xcc,0x09,0xac,0x7a,0x88,0x06,0xbd, +0x03,0x88,0x98,0xc2,0xc2,0x34,0xe0,0x08,0x00,0x9c,0x9a,0x0c,0x52,0x1d,0xf0, +0x88,0x06,0x82,0x28,0x10,0xa8,0x01,0xe0,0x08,0x00,0xa9,0x11,0x4b,0x91,0x92, +0x19,0x00,0x92,0x52,0x08,0x86,0xd7,0xff,0x91,0x14,0x29,0xa8,0x09,0xcc,0xaa, +0xb8,0x06,0xb8,0x4b,0xb9,0x09,0x29,0x05,0x0c,0x02,0x1d,0xf0,0x29,0x05,0x0c, +0x02,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x8c,0x62,0x91,0x0d,0x29,0x88,0x02, +0x97,0x18,0x03,0x0c,0x12,0x1d,0xf0,0xb1,0x0d,0x29,0xa8,0x62,0xb9,0x72,0xa6, +0x1a,0x1a,0x0c,0x0b,0x0c,0x0a,0x0c,0x0c,0x76,0x80,0x0e,0xe8,0x52,0x1b,0xaa, +0xba,0xee,0xc9,0x0e,0xd8,0x62,0x4b,0xbb,0xd7,0xaa,0x02,0x86,0xfa,0xff,0xcb, +0x32,0x41,0xf9,0x28,0xa8,0xb2,0x8c,0x5a,0x88,0x04,0x88,0xa8,0xe0,0x08,0x00, +0x4b,0x22,0x37,0x92,0xef,0x0c,0x02,0x1d,0xf0,0x00,0x36,0xe1,0x00,0xa2,0xc1, +0x3c,0x59,0xf1,0x16,0x42,0x0c,0x8c,0xe3,0x8c,0xc4,0x8c,0xa7,0xc1,0xf6,0x28, +0xb8,0x02,0xc7,0x1b,0x07,0x0c,0x12,0x1d,0xf0,0x0c,0x32,0x1d,0xf0,0xb1,0xf4, +0x28,0xc1,0xf3,0x28,0xb0,0xb5,0x73,0xc0,0xbb,0x63,0xb9,0xf1,0xb9,0x22,0xa0, +0x00,0x0c,0x1c,0xf9,0xaf,0xe0,0x0a,0x22,0x42,0x0a,0x04,0x00,0xaf,0xe0,0x0a, +0x22,0x42,0x0a,0x05,0x00,0x2f,0xdc,0x51,0x02,0x42,0x0a,0x06,0x00,0x8f,0x1d, +0xbf,0x42,0x42,0x0a,0x07,0x00,0x0f,0xe2,0x21,0x82,0x2e,0x0a,0x01,0x00,0x00, +0x0f,0x0d,0xa8,0x41,0xd8,0x12,0xc8,0x32,0xa7,0x1d,0x11,0x07,0xec,0x6a,0x81, +0xd7,0x28,0x88,0x08,0xad,0x02,0x88,0xf8,0xb2,0x21,0x0f,0xe0,0x08,0x00,0x0c, +0x09,0x99,0x07,0x16,0x06,0x05,0x52,0x21,0x1c,0xad,0x02,0xbd,0x03,0xcd,0x04, +0xf2,0xc1,0x1c,0x81,0xcf,0x28,0xe8,0xa2,0xd8,0x41,0xe0,0xe6,0x63,0x59,0x01, +0x88,0x08,0xe9,0x91,0x82,0x28,0x15,0xe0,0xe0,0xf4,0xe0,0x08,0x00,0x8c,0x2a, +0x2d,0x0a,0x1d,0xf0,0x98,0x71,0xa8,0x91,0x88,0x07,0x30,0x3a,0xa0,0xa0,0x66, +0xc0,0x9a,0x88,0x89,0x07,0x98,0x71,0x60,0x60,0xf4,0x40,0x49,0xa0,0x90,0x55, +0xc0,0x56,0x96,0xfb,0x06,0x01,0x00,0x00,0x0c,0x12,0x1d,0xf0,0x0c,0x02,0x1d, +0xf0,0x8d,0x0e,0x88,0x08,0x82,0x28,0x10,0xe0,0x08,0x00,0xb2,0xc1,0x18,0xa9, +0x51,0xd2,0x92,0x08,0xa2,0xc1,0x14,0x40,0x9d,0x01,0xa2,0x1a,0x00,0xa2,0x5b, +0x00,0xc2,0x91,0x0c,0x90,0x9c,0x31,0x40,0xbc,0x01,0x80,0x5c,0x01,0x50,0x5c, +0x31,0xb0,0xbc,0x31,0x97,0x9b,0x21,0xc0,0xac,0x01,0x80,0xed,0x01,0xe0,0xec, +0x31,0xa0,0xac,0x31,0xa9,0x81,0xe7,0x95,0x18,0xc0,0xcd,0x01,0xc0,0xcc,0x31, +0xc0,0xca,0xc0,0x16,0x4c,0xf4,0xa9,0x81,0xc6,0x01,0x00,0xc0,0xdc,0x01,0xd0, +0xdc,0x31,0xd9,0x81,0xa8,0xb2,0x81,0xa5,0x28,0x92,0xc1,0x14,0x82,0x28,0x00, +0x92,0x19,0x00,0x82,0x28,0x0c,0x92,0x52,0x08,0xe0,0x08,0x00,0x81,0xa0,0x28, +0x3d,0xf0,0x82,0x28,0x00,0x82,0x28,0x0a,0xa2,0x22,0x0b,0xe0,0x08,0x00,0x81, +0x9b,0x28,0x88,0x08,0xbd,0x05,0x88,0xc8,0xa2,0x22,0x0c,0xe0,0x08,0x00,0x81, +0x98,0x28,0x88,0x08,0x58,0x81,0x88,0xa8,0xa8,0xc2,0xe0,0x08,0x00,0x81,0x94, +0x28,0x88,0x08,0xbd,0x05,0x88,0xc8,0xa8,0xd2,0xe0,0x08,0x00,0x81,0x91,0x28, +0x88,0x08,0x88,0xa8,0xa8,0xd2,0xe0,0x08,0x00,0xad,0x02,0xa5,0xe1,0xff,0x06, +0xb4,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0x36,0x41,0x00,0x39,0x02, +0x39,0x12,0x0c,0x08,0x2c,0x04,0x49,0x72,0x89,0x22,0x89,0x32,0x89,0x42,0x89, +0x52,0x89,0x62,0x1d,0xf0,0x00,0x00,0x00,0x36,0x41,0x00,0x6f,0xe9,0x08,0x22, +0x44,0x0c,0x0c,0x11,0x1c,0xfb,0x0c,0x0a,0xa0,0x00,0xf3,0x50,0x9b,0xc0,0x6f, +0xe7,0x0a,0x22,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x42,0x6a,0x04,0x00, +0xaf,0xe0,0x0a,0x22,0x42,0x6a,0x05,0x00,0xaf,0xe0,0x0a,0x22,0x48,0x40,0x30, +0x11,0xaf,0xe0,0x0a,0x22,0xe0,0xe0,0x21,0x03,0xaf,0xe0,0x0a,0x22,0x44,0x3c, +0x70,0x09,0xcf,0x21,0x74,0x43,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x00, +0x32,0x18,0x40,0xaf,0xe0,0x0a,0x22,0xa8,0xa0,0xd8,0x01,0xaf,0xe0,0x0a,0x22, +0xdc,0xd0,0x20,0x05,0xaf,0xe0,0x0a,0x22,0x44,0x3c,0x68,0x09,0xaf,0xe0,0x0a, +0x22,0xc0,0x41,0x18,0x40,0xaf,0xe0,0x0a,0x22,0xfc,0xc0,0x21,0x03,0xaf,0xe0, +0x0a,0x22,0x44,0x3c,0x60,0x09,0xaf,0xe0,0x0a,0x22,0xc0,0x33,0x18,0x40,0xaf, +0xe0,0x0a,0x22,0xa8,0xa0,0xd8,0x01,0xaf,0xe0,0x0a,0x22,0xf8,0xa0,0x20,0x05, +0xaf,0xe0,0x0a,0x22,0x44,0x3c,0x50,0x09,0xaf,0xe0,0x0a,0x22,0x80,0x43,0x18, +0x40,0xaf,0xe0,0x0a,0x22,0xf4,0x90,0x30,0x02,0xaf,0xe0,0x0a,0x22,0x44,0x3c, +0x48,0x09,0xaf,0xe0,0x0a,0x22,0x40,0x13,0x18,0x40,0xaf,0xe0,0x0a,0x22,0xf0, +0x80,0x09,0x03,0xaf,0xe0,0x0a,0x22,0x44,0x3c,0x40,0x09,0xaf,0xe0,0x0a,0x22, +0x00,0x73,0x18,0x40,0xef,0x65,0x0c,0x62,0xa8,0x50,0xb0,0x03,0xa8,0x52,0x6f, +0xd7,0xa2,0x43,0xf0,0x40,0xa0,0x02,0x4f,0x41,0x63,0x43,0x44,0x3c,0x20,0x09, +0x88,0x42,0xef,0x25,0x05,0x62,0x00,0x23,0x18,0x40,0x0f,0x01,0x63,0x43,0x30, +0x0c,0x08,0x01,0xaa,0x88,0xef,0xe5,0x06,0x62,0xc2,0x02,0x04,0x11,0x4f,0x01, +0x28,0x48,0x44,0x0c,0x0c,0x11,0xaa,0x99,0x9a,0x77,0x8a,0x47,0x8c,0x23,0x58, +0x72,0xcc,0x35,0x3d,0x04,0x46,0x03,0x00,0x00,0x05,0x40,0x40,0xb3,0xc0,0xb0, +0xb0,0xb1,0xb0,0x33,0xc0,0x4d,0x03,0x49,0x62,0x2d,0x03,0x1d,0xf0,0x36,0x41, +0x00,0xa8,0x81,0x1c,0xf8,0xef,0xeb,0x00,0x22,0x44,0x0c,0x0c,0x11,0xb8,0x02, +0x00,0x04,0x40,0x30,0xcb,0xc0,0xc0,0xc0,0xb1,0xc0,0x4b,0xc0,0x40,0x95,0xc0, +0xef,0xf2,0x00,0x22,0x02,0x3a,0x04,0x00,0xaf,0xe0,0x0a,0x22,0x02,0x1a,0x04, +0x00,0xef,0xf4,0x02,0x22,0x48,0x20,0x18,0x01,0xaf,0xe0,0x0a,0x22,0x02,0x1a, +0x05,0x00,0xaf,0xe0,0x0a,0x22,0xa4,0x10,0x89,0x08,0xaf,0xe0,0x0a,0x22,0xa4, +0x00,0x08,0x21,0xaf,0xe0,0x0a,0x22,0x40,0x00,0x00,0x04,0x8f,0x84,0x00,0x82, +0x40,0x00,0x01,0x01,0x0c,0x0b,0x0f,0x73,0x80,0x42,0x02,0x02,0x00,0x11,0x4f, +0x01,0x28,0x48,0x44,0x0c,0x0c,0x11,0xa9,0x32,0xa8,0x42,0x57,0xa4,0x35,0xd8, +0x12,0x47,0x2d,0x47,0x0b,0x9a,0x99,0x42,0x57,0xa3,0x36,0x38,0x52,0x0b,0x33, +0x39,0x52,0x67,0x24,0x07,0x47,0x27,0x04,0x2c,0x03,0x46,0x00,0x00,0x0c,0x13, +0x39,0x72,0x49,0x12,0x1d,0xf0,0xa6,0x19,0x37,0x4f,0x01,0x28,0x48,0x44,0x0c, +0x0c,0x11,0xa0,0xa0,0x60,0x86,0xf0,0xff,0x47,0xa5,0x18,0xc8,0x12,0x1b,0x9a, +0xc7,0x24,0x24,0xc6,0xf0,0xff,0x37,0xa5,0x14,0x38,0x52,0x1b,0x33,0x86,0xf0, +0xff,0x2b,0x9a,0x06,0xed,0xff,0xa6,0x1a,0x15,0x92,0xca,0xfe,0xc6,0xea,0xff, +0x3d,0x0b,0xc6,0xeb,0xff,0xad,0x0b,0xc6,0xe4,0xff,0x92,0xca,0xfe,0xc6,0xe6, +0xff,0xd6,0xaa,0xf9,0x2b,0x9a,0xc6,0xe4,0xff,0x36,0x41,0x00,0xef,0xe8,0x08, +0x22,0x44,0x0c,0x0c,0x11,0x0c,0x09,0x90,0x00,0xf3,0xaf,0xe0,0x0a,0x22,0x42, +0x59,0x04,0x00,0xaf,0xe0,0x0a,0x22,0x48,0x20,0x28,0x01,0xaf,0xe0,0x0a,0x22, +0xe0,0x50,0x90,0x02,0xaf,0xe0,0x0a,0x22,0x44,0x0c,0x28,0x09,0x4f,0x20,0x6c, +0x43,0x44,0x0c,0x0c,0x11,0xaf,0xe0,0x0a,0x22,0x00,0x02,0x00,0x40,0xaf,0xe0, +0x0a,0x22,0xa8,0x30,0x20,0x00,0xaf,0xe0,0x0a,0x22,0xd8,0x30,0x90,0x01,0xef, +0xe4,0x00,0x22,0x44,0x0c,0x18,0x09,0xaf,0xe0,0x0a,0x22,0xc2,0x18,0x04,0x00, +0xaf,0xe0,0x0a,0x22,0x80,0x21,0x00,0x40,0xaf,0xe0,0x0a,0x22,0xc8,0x10,0x08, +0x01,0xaf,0xe0,0x0a,0x22,0x44,0x0c,0x08,0x09,0xaf,0xe0,0x0a,0x22,0x80,0x00, +0x00,0x40,0x4f,0x00,0x28,0x48,0x44,0x0c,0x0c,0x11,0x1d,0xf0,0x00,0x00,0x00, +0x76,0x94,0x09,0x62,0x03,0x00,0x1b,0x33,0x62,0x45,0x00,0x1b,0x55,0x1d,0xf0, +0xb6,0x74,0xed,0x62,0x03,0x00,0x1b,0x33,0x42,0xc4,0xff,0x62,0x45,0x00,0x52, +0xc5,0x01,0x17,0x65,0x27,0xb6,0x64,0xd9,0x62,0x03,0x00,0x72,0x03,0x01,0x2b, +0x33,0x42,0xc4,0xfe,0x62,0x45,0x00,0x72,0x45,0x01,0x2b,0x55,0x86,0x03,0x00, +0x00,0x00,0x00,0x36,0x21,0x00,0x20,0x52,0x20,0x07,0xe2,0xc6,0x17,0xe2,0xd7, +0x40,0x74,0x41,0x82,0xa0,0x03,0x87,0x83,0x5a,0x76,0x97,0x15,0x68,0x03,0x78, +0x13,0x69,0x05,0x68,0x23,0x79,0x15,0x78,0x33,0x69,0x25,0x32,0xc3,0x10,0x79, +0x35,0x52,0xc5,0x10,0x37,0x64,0x0b,0x68,0x03,0x78,0x13,0x8b,0x33,0x69,0x05, +0x79,0x15,0x8b,0x55,0x27,0xe4,0x07,0x17,0xe4,0x14,0x07,0xe4,0x21,0x1d,0xf0, +0x68,0x03,0x4b,0x33,0x69,0x05,0x4b,0x55,0x17,0xe4,0x04,0x07,0xe4,0x11,0x1d, +0xf0,0x62,0x13,0x00,0x2b,0x33,0x62,0x55,0x00,0x2b,0x55,0x07,0xe4,0x02,0x1d, +0xf0,0x00,0x62,0x03,0x00,0x62,0x45,0x00,0x1d,0xf0,0x16,0xa4,0xff,0x00,0x23, +0x40,0x80,0xb3,0x10,0xb0,0x33,0xc0,0x68,0x03,0x76,0x97,0x21,0x78,0x13,0x88, +0x23,0x60,0x67,0x81,0x69,0x05,0x98,0x33,0x70,0x78,0x81,0x79,0x15,0x68,0x43, +0x80,0x89,0x81,0x89,0x25,0x32,0xc3,0x10,0x90,0x96,0x81,0x99,0x35,0x52,0xc5, +0x10,0x37,0x64,0x15,0x78,0x13,0x88,0x23,0x60,0x67,0x81,0x69,0x05,0x8b,0x33, +0x70,0x78,0x81,0x79,0x15,0x52,0xc5,0x08,0x80,0x68,0x20,0x27,0x64,0x0c,0x78, +0x13,0x4b,0x33,0x60,0x67,0x81,0x69,0x05,0x4b,0x55,0x6d,0x07,0xba,0x33,0x17, +0xe4,0x06,0x07,0xe4,0x18,0x1d,0xf0,0x00,0x00,0x62,0x03,0x00,0x72,0x03,0x01, +0x2b,0x33,0x62,0x45,0x00,0x72,0x45,0x01,0x2b,0x55,0x07,0xe4,0x01,0x1d,0xf0, +0x62,0x03,0x00,0x62,0x45,0x00,0x1d,0xf0,0x00,0x00,0x00,0x36,0x81,0x00,0xa2, +0xc2,0x34,0xe5,0x02,0xf6,0x1c,0x0a,0x0c,0x4b,0x71,0x8f,0x27,0xe0,0x43,0x11, +0x52,0xc7,0xe0,0x82,0xc7,0xe8,0x80,0x83,0xa0,0x50,0x53,0xa0,0x7a,0x44,0x42, +0x24,0x7f,0x52,0x25,0x7f,0x72,0xc7,0xf0,0x58,0x05,0x48,0x04,0x70,0x73,0xa0, +0x72,0x27,0x7f,0x32,0x28,0x7f,0x78,0x07,0x38,0x03,0x65,0x37,0xfa,0x59,0x3a, +0x39,0x2a,0x79,0x1a,0x49,0x0a,0x0c,0x4b,0xa9,0xf2,0x0c,0x8a,0x25,0x36,0xfa, +0x6d,0x0a,0xbd,0x04,0xc2,0x23,0x1c,0xa5,0x30,0xf6,0x69,0x02,0x1c,0xca,0x0c, +0x4b,0x25,0x35,0xfa,0xa9,0x01,0xbd,0x04,0xc8,0xb3,0x61,0xa4,0x26,0xd8,0xa3, +0xe2,0x26,0x7f,0x25,0x2c,0xf6,0x1c,0xca,0x0c,0x4b,0x88,0x01,0x89,0x22,0x65, +0x33,0xfa,0xa9,0x11,0xbd,0x04,0xc8,0xb3,0xd8,0xa3,0xe2,0x26,0x7f,0xa5,0x2a, +0xf6,0x3c,0x4a,0x0c,0x4b,0x98,0x11,0x99,0x32,0xa5,0x31,0xfa,0xa9,0x21,0xd2, +0x26,0x7f,0xb8,0xa3,0xc2,0x23,0x1a,0xb8,0x0b,0xc8,0x2c,0xa5,0x26,0xf6,0x3c, +0x4a,0x0c,0x4b,0xc8,0x21,0xc9,0x42,0xe5,0x2f,0xfa,0xa9,0x31,0xd2,0x26,0x7f, +0xb8,0xa3,0xc2,0x23,0x1a,0xb8,0x0b,0xc8,0x1c,0xe5,0x24,0xf6,0x1c,0x4a,0x0c, +0x4b,0xc8,0x31,0xc9,0x52,0x25,0x2e,0xfa,0xa9,0x41,0xbd,0x04,0xd8,0xc5,0xc8, +0xa3,0xd8,0x0d,0x25,0xef,0xf5,0x2c,0x8a,0x0c,0x4b,0xe8,0x41,0xe9,0x62,0xa5, +0x2c,0xfa,0xa9,0x51,0xbd,0x04,0xcd,0x03,0xe1,0x2e,0x26,0xdd,0x05,0xe2,0x2e, +0x12,0xa5,0xe2,0xf5,0xa2,0xa0,0x94,0x1c,0x0b,0xf8,0x51,0xf9,0x72,0xe5,0x2a, +0xfa,0xbd,0x04,0xcd,0x03,0xf2,0x26,0x7f,0xdd,0x05,0xe1,0x26,0x26,0x5d,0x0a, +0xe2,0x2e,0x12,0xa5,0xf3,0xf6,0x59,0x82,0x1c,0xca,0x0c,0x4b,0x25,0x29,0xfa, +0xcd,0x07,0x5d,0x0a,0xbd,0x04,0xd8,0xa3,0xe5,0x17,0xf6,0x59,0x92,0x2c,0x8a, +0x0c,0x4b,0x71,0x1d,0x26,0xa5,0x27,0xfa,0xe2,0x27,0x12,0x5d,0x0a,0xbd,0x04, +0xf8,0xf2,0xc8,0xa3,0xf8,0x0f,0xd8,0x53,0xf8,0x0f,0x25,0xd9,0xf5,0x59,0xa2, +0x2c,0x8a,0x1c,0x0b,0xe5,0x25,0xfa,0xc2,0x26,0x7f,0xb2,0x23,0x11,0x3d,0x0a, +0xb8,0x0b,0xa5,0xbc,0xf6,0x39,0x12,0x0c,0x8a,0x0c,0x4b,0x65,0x24,0xfa,0xb8, +0x74,0x3d,0x0a,0xe5,0xd5,0xf5,0x39,0xb2,0x0c,0x8a,0x0c,0x4b,0x65,0x23,0xfa, +0x3d,0x0a,0x65,0xeb,0xf5,0x39,0xc2,0x2c,0x4a,0x0c,0x4b,0xa5,0x22,0xfa,0xa2, +0x62,0x11,0x0c,0x4b,0x2c,0xca,0xe5,0x21,0xfa,0xa2,0x62,0x12,0x0c,0x4b,0x0c, +0x8a,0x65,0x21,0xfa,0xa2,0x62,0x13,0x0c,0x4b,0x1c,0x4a,0xa5,0x20,0xfa,0xa2, +0x62,0x14,0x1d,0xf0,0x36,0x81,0x00,0x1c,0x0a,0x0c,0x4b,0xe0,0x53,0x11,0x81, +0x4c,0x26,0x0c,0x09,0x92,0x62,0x10,0x99,0xb2,0x62,0xc8,0xd8,0x72,0xc8,0xf0, +0x42,0xc8,0xe0,0x40,0x43,0xa0,0x70,0x73,0xa0,0x60,0x63,0xa0,0x8a,0x55,0x52, +0x25,0x7f,0x62,0x26,0x7f,0x72,0x27,0x7f,0x42,0x24,0x7f,0x78,0x07,0x48,0x04, +0x68,0x06,0x58,0x05,0x0c,0x18,0x89,0xf2,0x25,0x1c,0xfa,0xbd,0x0a,0x69,0x3a, +0x49,0x2a,0x79,0x1a,0x59,0x0a,0xa8,0x16,0xb9,0xc2,0xa2,0x9a,0x00,0x0c,0x4b, +0xa9,0x01,0x1c,0x0a,0xa5,0x1a,0xfa,0xa9,0x11,0xbd,0x05,0xd1,0xe6,0x25,0xc8, +0x56,0xd2,0x2d,0x12,0x65,0x17,0xf6,0x0c,0x8a,0x0c,0x4b,0xe8,0x11,0xe9,0x22, +0xe5,0x18,0xfa,0xa9,0x21,0xbd,0x05,0xc2,0x24,0x1c,0x65,0x13,0xf6,0x1c,0xca, +0x0c,0x4b,0xf8,0x21,0xf9,0x02,0xa5,0x17,0xfa,0xa9,0x31,0xbd,0x05,0xc8,0xb4, +0xe1,0x2e,0x26,0xd8,0xa4,0xe2,0x2e,0x7f,0xe5,0x0e,0xf6,0x3c,0x4a,0x0c,0x4b, +0xf8,0x31,0xf9,0x42,0xe5,0x15,0xfa,0xa9,0x41,0xd1,0x28,0x26,0xb8,0xa4,0xc2, +0x24,0x1a,0xb8,0x0b,0xc8,0x0c,0xd2,0x2d,0x7f,0xa5,0x0a,0xf6,0x1c,0x4a,0x0c, +0x4b,0xc8,0x41,0xc9,0x32,0xe5,0x13,0xfa,0xa9,0x51,0xbd,0x05,0xcd,0x04,0xdd, +0x06,0xa5,0x05,0xf6,0x3c,0x8a,0x1c,0x0b,0xd8,0x51,0xd9,0x52,0xa5,0x12,0xfa, +0xd1,0x1b,0x26,0xbd,0x03,0xc1,0xc6,0x25,0x3d,0x0a,0xc2,0x2c,0x12,0xd2,0x2d, +0x7f,0xa5,0xb2,0xf6,0x39,0x72,0x1c,0xca,0x0c,0x4b,0xe5,0x10,0xfa,0xbd,0x05, +0xcd,0x07,0xd8,0xa4,0x7d,0x0a,0xa5,0xff,0xf5,0x79,0x82,0x2c,0x8a,0x1c,0x0b, +0x31,0x10,0x26,0x65,0x0f,0xfa,0xc2,0x23,0x7f,0xb2,0x24,0x11,0x3d,0x0a,0xb8, +0x1b,0x25,0xa6,0xf6,0x39,0x12,0x0c,0xca,0x0c,0x4b,0x25,0x0e,0xfa,0xbd,0x05, +0xc2,0x24,0x19,0x3d,0x0a,0x65,0xfb,0xf5,0x39,0x62,0x3c,0x4a,0x0c,0x4b,0xe5, +0x0c,0xfa,0x38,0x01,0xa9,0xe2,0xb2,0xc2,0x44,0xa2,0xc2,0x28,0x25,0x9f,0xf8, +0xe0,0x53,0x11,0x42,0x26,0x16,0x1c,0x4a,0x40,0x33,0xa0,0x38,0x03,0x0c,0x4b, +0x4b,0x43,0xcb,0x33,0xa5,0x0a,0xfa,0xcd,0x04,0xe2,0x26,0x16,0xdd,0x03,0xea, +0xe5,0xe8,0x0e,0x3d,0x0a,0xb2,0x9e,0x00,0xe2,0x9e,0x01,0xa5,0xf3,0xf5,0x39, +0x92,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0xa2,0xc2,0x20,0xa5,0xd0,0xf5,0xa2, +0xc2,0x28,0x25,0xd0,0xf5,0xb8,0x03,0xa2,0xc2,0x30,0xb8,0x7b,0xe5,0x77,0xf5, +0x78,0x03,0x68,0x23,0x0c,0x4a,0x68,0xa6,0x0c,0x4b,0x68,0x06,0x65,0x06,0xfa, +0xa9,0x02,0x0c,0x4b,0x0c,0x8a,0xe5,0x05,0xfa,0x4d,0x0a,0xa5,0x3e,0xf5,0x49, +0x22,0x0c,0x8a,0x0c,0x4b,0xe5,0x04,0xfa,0x4d,0x0a,0xe5,0xcc,0xf5,0x49,0x32, +0x0c,0x8a,0x0c,0x4b,0x25,0x04,0xfa,0xa9,0x52,0x0c,0x4b,0x1c,0x0a,0xa5,0x03, +0xfa,0x4d,0x0a,0x25,0x3b,0xf5,0x49,0x62,0xa5,0x0b,0xfa,0x4d,0x0a,0x0c,0x8a, +0xbd,0x04,0xa5,0x05,0xfa,0xbd,0x06,0x5d,0x0a,0xe5,0x9e,0xf9,0x59,0x42,0x0c, +0x4a,0xbd,0x04,0xa5,0x04,0xfa,0xbd,0x07,0xc8,0x23,0x3d,0x0a,0xc8,0xac,0x25, +0x12,0x00,0x39,0x12,0xad,0x04,0x65,0x02,0xfa,0x49,0x72,0x1d,0xf0,0x00,0x36, +0x41,0x00,0x58,0x03,0x48,0x23,0x0c,0x4a,0x48,0xa4,0x0c,0x4b,0x48,0x04,0xe5, +0xfe,0xf9,0xbd,0x05,0xc8,0x23,0x3d,0x0a,0xc8,0xac,0xa5,0x0f,0x00,0x39,0x02, +0x4b,0xa2,0x8b,0xb2,0xa5,0x90,0xf8,0x0c,0x8a,0x0c,0x4b,0x25,0xfd,0xf9,0xa9, +0x42,0x0c,0x4b,0x0c,0x8a,0xa5,0xfc,0xf9,0xbd,0x04,0x3d,0x0a,0x25,0x99,0xf9, +0x39,0x52,0xcb,0xa2,0xb2,0xc2,0x18,0x65,0x8e,0xf8,0xa2,0xc2,0x1c,0xb2,0xc2, +0x20,0xe5,0x8d,0xf8,0x1d,0xf0,0x00,0x00,0x36,0x41,0x00,0x8b,0xa2,0xcb,0xb2, +0x91,0x05,0x26,0xe0,0x83,0x11,0xc2,0xc9,0x18,0xc0,0xc3,0xa0,0x9a,0x88,0x82, +0x28,0x7f,0xc2,0x2c,0x7f,0x88,0x08,0xc8,0x0c,0x88,0xa8,0xc8,0x7c,0x38,0x08, +0xa5,0x44,0xf5,0x39,0x42,0x39,0x62,0x39,0xa2,0xa2,0xc2,0x38,0xb2,0xc2,0x30, +0xc2,0xc2,0x28,0xd2,0xc2,0x20,0xe2,0xc2,0x18,0xf2,0xc2,0x10,0xf2,0x62,0x10, +0xe2,0x62,0x11,0xd2,0x62,0x12,0xc2,0x62,0x13,0xb2,0x62,0x14,0xa2,0x62,0x15, +0x1d,0xf0,0x36,0x41,0x00,0x4c,0x8a,0x0c,0x4b,0xc1,0x51,0x25,0x39,0x02,0x91, +0x79,0x26,0xe0,0x43,0x11,0x82,0xc9,0xe8,0x9a,0x44,0x80,0x83,0xa0,0x82,0x28, +0x7f,0x42,0x24,0x7f,0x88,0x08,0x98,0x04,0x88,0xa8,0x98,0x69,0x92,0x6c,0x1c, +0x88,0x08,0x89,0x12,0x65,0xf2,0xf9,0x5d,0x0a,0xbd,0x03,0xa5,0xd1,0xff,0x59, +0x32,0x5c,0x4a,0x0c,0x4b,0x65,0xf1,0xf9,0xbd,0x03,0x5d,0x0a,0xe5,0xb5,0xff, +0x59,0x42,0xa1,0x6a,0x26,0x0c,0x4b,0xa9,0x22,0x4c,0xca,0xe5,0xef,0xf9,0xbd, +0x02,0x3d,0x0a,0xd8,0x04,0xc1,0x8f,0x25,0xd8,0x6d,0xc2,0x2c,0x7f,0xa5,0xef, +0xf5,0x39,0x62,0x1d,0xf0,0x36,0x41,0x00,0x58,0x04,0x0c,0xca,0x0c,0x4b,0xe5, +0xed,0xf9,0x4d,0x0a,0x1c,0x0b,0xa8,0x43,0xa9,0x04,0x59,0x14,0xa0,0xa5,0x82, +0xf0,0xaa,0x11,0xe5,0x6b,0xf5,0xa9,0x24,0x49,0x02,0x1d,0xf0,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xae,0xb4,0xc9,0x46 +}; diff --git a/drivers/misc/bh1721.c b/drivers/misc/bh1721.c new file mode 100644 index 00000000000..30a1d6dfb86 --- /dev/null +++ b/drivers/misc/bh1721.c @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2010 Samsung Electronics. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 + +#define SENSOR_AL3201_ADDR 0x1c +#define SENSOR_BH1721FVC_ADDR 0x23 + +#define BH1721FVC_DRV_NAME "bh1721fvc" +#define DRIVER_VERSION "1.1" + +#define LIMIT_RESET_COUNT 5 + +#define LUX_MIN_VALUE 0 +#define LUX_MAX_VALUE 65528 + +#define bh1721fvc_dbmsg(str, args...) pr_debug("%s: " str, __func__, ##args) + +enum BH1721FVC_STATE { + POWER_DOWN = 0, + POWER_ON, + AUTO_MEASURE, + H_MEASURE, + L_MEASURE, +}; + +static const u8 commands[] = { + 0x00, /* Power Down */ + 0x01, /* Power On */ + 0x10, /* Continuously Auto-Resolution Mode */ + 0x12, /* Continuously H-Resolution Mode */ + 0x13, /* Continuously L-Resolution Mode */ +}; + +struct bh1721fvc_data { + int (*reset) (void); + struct bh1721fvc_platform_data *pdata; + struct i2c_client *client; + struct input_dev *input_dev; + struct work_struct work_light; + struct hrtimer timer; + struct mutex lock; + struct workqueue_struct *wq; + struct class *factory_class; + struct device *factory_dev; + ktime_t light_poll_delay; + enum BH1721FVC_STATE state; + u8 measure_mode; + struct device *light_sensor_device; +}; + +static int bh1721fvc_get_luxvalue(struct bh1721fvc_data *bh1721fvc, + u16 *value); + +static int bh1721fvc_write_byte(struct i2c_client *client, u8 value) +{ + int retry; + for (retry = 0; retry < 5; retry++) + if (!i2c_smbus_write_byte(client, value)) + return 0; + return -EIO; +} + +static bool bh1721fvc_is_measuring(struct bh1721fvc_data *bh1721fvc) +{ + return ((bh1721fvc->state == H_MEASURE) || + (bh1721fvc->state == L_MEASURE) || + (bh1721fvc->state == AUTO_MEASURE)); +} + +static int bh1721fvc_enable(struct bh1721fvc_data *bh1721fvc) +{ + int err; + bh1721fvc_dbmsg("starting poll timer, delay %lldns\n", + ktime_to_ns(bh1721fvc->light_poll_delay)); + err = bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_ON]); + if (err) { + pr_err("%s: Failed to write byte (POWER_ON)\n", __func__); + goto err_power_on; + } + + err = + bh1721fvc_write_byte(bh1721fvc->client, + commands[bh1721fvc->measure_mode]); + + if (err) { + pr_err("%s: Failed to write byte (measure mode)\n", __func__); + goto err_measure_mode; + } + + if (bh1721fvc->measure_mode == H_MEASURE) + mdelay(120); + else if (bh1721fvc->measure_mode == L_MEASURE) + mdelay(16); + else + /* AUTO_MEASURE */ + mdelay(120 + 16); + + hrtimer_start(&bh1721fvc->timer, bh1721fvc->light_poll_delay, + HRTIMER_MODE_REL); + goto done; + +err_measure_mode: +err_power_on: + bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); +done: + return err; +} + +static int bh1721fvc_disable(struct bh1721fvc_data *bh1721fvc) +{ + int err; + hrtimer_cancel(&bh1721fvc->timer); + cancel_work_sync(&bh1721fvc->work_light); + err = bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); + if (unlikely(err != 0)) + pr_err("%s: Failed to write byte (POWER_DOWN)\n", __func__); + return err; +} + +static ssize_t bh1721fvc_poll_delay_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bh1721fvc_data *bh1721fvc = dev_get_drvdata(dev); + return sprintf(buf, "%lld\n", ktime_to_ns(bh1721fvc->light_poll_delay)); +} + +static ssize_t bh1721fvc_poll_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err; + int64_t new_delay; + struct bh1721fvc_data *bh1721fvc = dev_get_drvdata(dev); + err = kstrtoll(buf, 10, &new_delay); + if (err < 0) + return err; + bh1721fvc_dbmsg("new delay = %lldns, old delay = %lldns\n", + new_delay, ktime_to_ns(bh1721fvc->light_poll_delay)); + mutex_lock(&bh1721fvc->lock); + if (new_delay != ktime_to_ns(bh1721fvc->light_poll_delay)) { + bh1721fvc->light_poll_delay = ns_to_ktime(new_delay); + if (bh1721fvc_is_measuring(bh1721fvc)) { + bh1721fvc_disable(bh1721fvc); + bh1721fvc_enable(bh1721fvc); + } + } + + mutex_unlock(&bh1721fvc->lock); + return size; +} + +static ssize_t bh1721fvc_light_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bh1721fvc_data *bh1721fvc = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", bh1721fvc_is_measuring(bh1721fvc)); +} + +static ssize_t bh1721fvc_light_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err = 0; + bool new_value = false; + struct bh1721fvc_data *bh1721fvc = dev_get_drvdata(dev); + bh1721fvc_dbmsg("enable %s\n", buf); + if (sysfs_streq(buf, "1")) { + new_value = true; + } else if (sysfs_streq(buf, "0")) { + new_value = false; + } else { + pr_err("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + bh1721fvc_dbmsg("new_value = %d, old state = %d\n", + new_value, bh1721fvc_is_measuring(bh1721fvc)); + + mutex_lock(&bh1721fvc->lock); + + if (new_value && (!bh1721fvc_is_measuring(bh1721fvc))) { + err = bh1721fvc_enable(bh1721fvc); + if (!err) { + bh1721fvc->state = bh1721fvc->measure_mode; + } else { + pr_err("%s: couldn't enable", __func__); + bh1721fvc->state = POWER_DOWN; + } + + } else if (!new_value && (bh1721fvc_is_measuring(bh1721fvc))) { + err = bh1721fvc_disable(bh1721fvc); + if (!err) + bh1721fvc->state = POWER_DOWN; + else + pr_err("%s: couldn't enable", __func__); + } else { + bh1721fvc_dbmsg("no nothing\n"); + } + + mutex_unlock(&bh1721fvc->lock); + return size; +} + +static ssize_t bh1721fvc_light_sensor_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bh1721fvc_data *bh1721fvc = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", + (bh1721fvc->measure_mode == AUTO_MEASURE) ? "auto" : + (bh1721fvc->measure_mode == H_MEASURE) ? "high" : + (bh1721fvc->measure_mode == + L_MEASURE) ? "low" : "invalid"); +} + +static ssize_t bh1721fvc_light_sensor_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 measure_mode; + struct bh1721fvc_data *bh1721fvc = dev_get_drvdata(dev); + bh1721fvc_dbmsg("bh1721fvc_light_sensor_mode_store +\n"); + if (sysfs_streq(buf, "auto")) { + measure_mode = AUTO_MEASURE; + } else if (sysfs_streq(buf, "high")) { + measure_mode = H_MEASURE; + } else if (sysfs_streq(buf, "low")) { + measure_mode = L_MEASURE; + } else { + pr_err("%s: invalid value %s\n", __func__, buf); + return -EINVAL; + } + + mutex_lock(&bh1721fvc->lock); + + if (bh1721fvc->measure_mode != measure_mode) { + bh1721fvc->measure_mode = measure_mode; + if (bh1721fvc_is_measuring(bh1721fvc)) { + bh1721fvc_disable(bh1721fvc); + bh1721fvc_enable(bh1721fvc); + bh1721fvc->state = measure_mode; + } + } + + mutex_unlock(&bh1721fvc->lock); + bh1721fvc_dbmsg("bh1721fvc_light_sensor_mode_store -\n"); + return size; + +} + +static DEVICE_ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + bh1721fvc_poll_delay_show, bh1721fvc_poll_delay_store); + +static DEVICE_ATTR(sensor_mode, S_IRUGO | S_IWUSR | S_IWGRP, + bh1721fvc_light_sensor_mode_show, + bh1721fvc_light_sensor_mode_store); + +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, + bh1721fvc_light_enable_show, bh1721fvc_light_enable_store); + +static struct attribute *bh1721fvc_sysfs_attrs[] = { + &dev_attr_enable.attr, + &dev_attr_poll_delay.attr, + &dev_attr_sensor_mode.attr, + NULL +}; + +static struct attribute_group bh1721fvc_attribute_group = { + .attrs = bh1721fvc_sysfs_attrs, +}; + +static ssize_t bh1721fvc_light_sensor_lux_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u16 lux; + int retry; + int err; + u32 result; + struct bh1721fvc_data *bh1721fvc = dev_get_drvdata(dev); + if (bh1721fvc->state == POWER_DOWN) { + err = + bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_ON]); + if (err) + goto err_exit; + err = + bh1721fvc_write_byte(bh1721fvc->client, + commands[AUTO_MEASURE]); + if (err) + goto err_exit; + msleep(210); + } + + for (retry = 0; retry < 10; retry++) { + if (i2c_master_recv(bh1721fvc->client, (u8 *) &lux, 2) == 2) { + be16_to_cpus(&lux); + break; + } + } + if (retry == 10) { + pr_err("%s : I2C read failed.. retry %d\n", __func__, retry); + goto err_exit; + } + + if (lux < 3) + result = lux; + else if (3 <= lux && lux < 14) + result = (lux-3)*(150-15)/(14-3)+15; + else if (14 <= lux && lux < 180) + result = (lux-14)*(1500-150)/(180-14)+150; + else if (180 <= lux && lux < 1894) + result = (lux-180)*(15000-1500)/(1894-180)+1500; + else if (1894 <= lux) + result = (lux-1894)*(30000-15000)/(3237-1894)+15000; + + if (bh1721fvc->state == POWER_DOWN) + bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); + return sprintf(buf, "%u\n", result); + +err_exit: + bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); + return err; +} + +static struct device_attribute dev_attr_light_sensor_lux = + __ATTR(lux, S_IRUSR | S_IRGRP, bh1721fvc_light_sensor_lux_show, NULL); +static struct device_attribute dev_attr_light_sensor_raw_data = + __ATTR(raw_data, S_IRUSR | S_IRGRP, + bh1721fvc_light_sensor_lux_show, NULL); + +static ssize_t bh1721fvc_light_vendor_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", "ROHM"); +} +static struct device_attribute dev_attr_light_sensor_vendor = + __ATTR(vendor, S_IRUSR | S_IRGRP, bh1721fvc_light_vendor_show, NULL); + +static ssize_t bh1721fvc_light_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", "BH1721"); +} +static struct device_attribute dev_attr_light_sensor_name = + __ATTR(name, S_IRUSR | S_IRGRP, bh1721fvc_light_name_show, NULL); + + +static struct device_attribute *additional_light_attrs[] = { + &dev_attr_light_sensor_lux, + &dev_attr_light_sensor_raw_data, + &dev_attr_light_sensor_vendor, + &dev_attr_light_sensor_name, + NULL, +}; + +static int bh1721fvc_get_luxvalue(struct bh1721fvc_data *bh1721fvc, u16 * value) +{ + int retry; + for (retry = 0; retry < 10; retry++) { + if (i2c_master_recv(bh1721fvc->client, (u8 *) value, 2) == 2) { + be16_to_cpus(value); + break; + } + } + + if (retry == 10) { + pr_err("%s : I2C read failed.. retry %d\n", __func__, retry); + return -EIO; + } + return 0; +} + +static void bh1721fvc_work_func_light(struct work_struct *work) +{ + int err; + u16 lux; + u32 result; + static int wake_adc = 1; + struct bh1721fvc_data *bh1721fvc = container_of(work, + struct bh1721fvc_data, + work_light); + + err = bh1721fvc_get_luxvalue(bh1721fvc, &lux); + if (!err) { + + if (lux < 3) + result = lux; + else if (3 <= lux && lux < 14) + result = (lux-3)*(150-15)/(14-3)+15; + else if (14 <= lux && lux < 180) + result = (lux-14)*(1500-150)/(180-14)+150; + else if (180 <= lux && lux < 1894) + result = (lux-180)*(15000-1500)/(1894-180)+1500; + else if (1894 <= lux) + result = (lux-1894)*(30000-15000)/(3237-1894)+15000; + + bh1721fvc_dbmsg("lux 0x%0X (%d)\n", result, result); + if (result > 60000) + result = 60000; + if (!result) + result += wake_adc++; + input_report_abs(bh1721fvc->input_dev, ABS_MISC, result); + input_sync(bh1721fvc->input_dev); + if (wake_adc > 2) + wake_adc = 0; + } else { + pr_err("%s: read word failed! (errno=%d)\n", __func__, err); + } +} + +static enum hrtimer_restart bh1721fvc_timer_func(struct hrtimer *timer) +{ + struct bh1721fvc_data *bh1721fvc = container_of(timer, + struct bh1721fvc_data, + timer); + queue_work(bh1721fvc->wq, &bh1721fvc->work_light); + hrtimer_forward_now(&bh1721fvc->timer, bh1721fvc->light_poll_delay); + return HRTIMER_RESTART; +} + +int bh1721fvc_test_luxvalue(struct bh1721fvc_data *bh1721fvc) +{ + unsigned int result; + int retry; + u16 lux; + int err; + if (bh1721fvc->state == POWER_DOWN) { + err = + bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_ON]); + if (err) + return err; + err = + bh1721fvc_write_byte(bh1721fvc->client, + commands[AUTO_MEASURE]); + if (err) + goto err_exit; + msleep(210); + } + for (retry = 0; retry < 5; retry++) { + if (i2c_master_recv(bh1721fvc->client, (u8 *) &lux, 2) == 2) { + be16_to_cpus(&lux); + break; + } + } + if (retry == 5) { + printk(KERN_ERR "I2C read failed.. retry %d\n", retry); + goto err_exit; + } + + if (lux < 3) + result = lux; + else if (3 <= lux && lux < 14) + result = (lux-3)*(150-15)/(14-3)+15; + else if (14 <= lux && lux < 180) + result = (lux-14)*(1500-150)/(180-14)+150; + else if (180 <= lux && lux < 1894) + result = (lux-180)*(15000-1500)/(1894-180)+1500; + else if (1894 <= lux) + result = (lux-1894)*(30000-15000)/(3237-1894)+15000; + + if (bh1721fvc->state == POWER_DOWN) + bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); + return (int)result; +err_exit: + bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); + return err; +} + +static int __devinit bh1721fvc_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + struct bh1721fvc_data *bh1721fvc; + struct input_dev *input_dev; + struct bh1721fvc_platform_data *pdata = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -EIO; + bh1721fvc = kzalloc(sizeof(*bh1721fvc), GFP_KERNEL); + if (!bh1721fvc) { + pr_err("%s, failed to alloc memory for module data\n", + __func__); + return -ENOMEM; + } + bh1721fvc->reset = pdata->reset; + if (!bh1721fvc->reset) { + pr_err("%s: reset callback is null\n", __func__); + err = -EIO; + goto err_reset_null; + } + + err = bh1721fvc->reset(); + + if (err) { + pr_err("%s: Failed to reset\n", __func__); + goto err_reset_failed; + } + + bh1721fvc->client = client; + i2c_set_clientdata(client, bh1721fvc); + mutex_init(&bh1721fvc->lock); + bh1721fvc->state = POWER_DOWN; + bh1721fvc->measure_mode = AUTO_MEASURE; + err = bh1721fvc_test_luxvalue(bh1721fvc); + if (err < 0) { + pr_err("%s: No search bh1721fvc lightsensor!\n", __func__); + goto err_test_lightsensor; + } else { + printk(KERN_ERR "Lux : %d\n", err); + } + + hrtimer_init(&bh1721fvc->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + bh1721fvc->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC); + bh1721fvc->timer.function = bh1721fvc_timer_func; + bh1721fvc->wq = + alloc_workqueue("bh1721fvc_wq", WQ_UNBOUND | WQ_RESCUER, 1); + + if (!bh1721fvc->wq) { + err = -ENOMEM; + pr_err("%s: could not create workqueue\n", __func__); + goto err_create_workqueue; + } + + INIT_WORK(&bh1721fvc->work_light, bh1721fvc_work_func_light); + input_dev = input_allocate_device(); + + if (!input_dev) { + pr_err("%s: could not allocate input device\n", __func__); + err = -ENOMEM; + goto err_input_allocate_device_light; + } + + input_set_drvdata(input_dev, bh1721fvc); + input_dev->name = "light_sensor"; + input_set_capability(input_dev, EV_ABS, ABS_MISC); + input_set_abs_params(input_dev, ABS_MISC, + LUX_MIN_VALUE, LUX_MAX_VALUE, 0, 0); + + bh1721fvc_dbmsg("registering lightsensor-level input device\n"); + err = input_register_device(input_dev); + + if (err < 0) { + pr_err("%s: could not register input device\n", __func__); + input_free_device(input_dev); + goto err_input_register_device_light; + } + bh1721fvc->input_dev = input_dev; + err = + sysfs_create_group(&input_dev->dev.kobj, + &bh1721fvc_attribute_group); + if (err) { + pr_err("%s: could not create sysfs group\n", __func__); + goto err_sysfs_create_group_light; + } + + err = sensors_register(bh1721fvc->light_sensor_device, + bh1721fvc, additional_light_attrs, "light_sensor"); + if (err) { + pr_err("%s: cound not register sensor device\n", __func__); + goto err_sysfs_create_factory_light; + } + printk(KERN_INFO "%s: success!\n", __func__); + + goto done; + +err_sysfs_create_factory_light: + sysfs_remove_group(&bh1721fvc->input_dev->dev.kobj, + &bh1721fvc_attribute_group); +err_sysfs_create_group_light: + input_unregister_device(bh1721fvc->input_dev); +err_input_register_device_light: +err_input_allocate_device_light: + destroy_workqueue(bh1721fvc->wq); +err_create_workqueue: +err_test_lightsensor: + mutex_destroy(&bh1721fvc->lock); +err_reset_failed: +err_reset_null: + kfree(bh1721fvc); + +done: + return err; + +} + +static int bh1721fvc_remove(struct i2c_client *client) +{ + struct bh1721fvc_data *bh1721fvc = i2c_get_clientdata(client); + sensors_unregister(bh1721fvc->light_sensor_device); + sysfs_remove_group(&bh1721fvc->input_dev->dev.kobj, + &bh1721fvc_attribute_group); + input_unregister_device(bh1721fvc->input_dev); + if (bh1721fvc_is_measuring(bh1721fvc)) + bh1721fvc_disable(bh1721fvc); + destroy_workqueue(bh1721fvc->wq); + mutex_destroy(&bh1721fvc->lock); + kfree(bh1721fvc); + bh1721fvc_dbmsg("bh1721fvc_remove -\n"); + return 0; +} + +static int bh1721fvc_suspend(struct device *dev) +{ + int err = 0; + struct i2c_client *client = to_i2c_client(dev); + struct bh1721fvc_data *bh1721fvc = i2c_get_clientdata(client); + + if (bh1721fvc_is_measuring(bh1721fvc)) { + err = bh1721fvc_disable(bh1721fvc); + if (err) + pr_err("%s: could not disable\n", __func__); + } + return err; +} + +static int bh1721fvc_resume(struct device *dev) +{ + int err = 0; + struct i2c_client *client = to_i2c_client(dev); + struct bh1721fvc_data *bh1721fvc = i2c_get_clientdata(client); + bh1721fvc_dbmsg("bh1721fvc_resume +\n"); + if (bh1721fvc_is_measuring(bh1721fvc)) { + err = bh1721fvc_enable(bh1721fvc); + if (err) + pr_err("%s: could not enable\n", __func__); + } + bh1721fvc_dbmsg("bh1721fvc_resume -\n"); + return err; +} + +static const struct i2c_device_id bh1721fvc_id[] = { + {BH1721FVC_DRV_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bh1721fvc_id); + +static const struct dev_pm_ops bh1721fvc_pm_ops = { + .suspend = bh1721fvc_suspend, + .resume = bh1721fvc_resume, +}; + +static struct i2c_driver bh1721fvc_driver = { + .driver = { + .name = BH1721FVC_DRV_NAME, + .owner = THIS_MODULE, + .pm = &bh1721fvc_pm_ops, + }, + .probe = bh1721fvc_probe, + .remove = bh1721fvc_remove, + .id_table = bh1721fvc_id, +}; + +static int __init bh1721fvc_init(void) +{ + return i2c_add_driver(&bh1721fvc_driver); +} + +module_init(bh1721fvc_init); + +static void __exit bh1721fvc_exit(void) +{ + bh1721fvc_dbmsg("bh1721fvc_exit +\n"); + i2c_del_driver(&bh1721fvc_driver); + bh1721fvc_dbmsg("bh1721fvc_exit -\n"); +} + +module_exit(bh1721fvc_exit); + +MODULE_AUTHOR("WonHyoung Lee "); + +MODULE_DESCRIPTION("BH1721FVC Ambient light sensor driver"); + +MODULE_LICENSE("GPL v2"); + +MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/misc/cm36651.c b/drivers/misc/cm36651.c new file mode 100644 index 00000000000..a07daa42c20 --- /dev/null +++ b/drivers/misc/cm36651.c @@ -0,0 +1,1341 @@ +/* + * driver/sensor/cm36651.c + * Copyright (c) 2011 SAMSUNG ELECTRONICS + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Intelligent Cancelation*/ +#define CM36651_CANCELATION +#ifdef CM36651_CANCELATION +#define CANCELATION_FILE_PATH "/efs/prox_cal" +#endif + +#define RGB_VENDOR "CAPELLA" +#define RGB_CHIP_ID "CM36651" + +#define I2C_M_WR 0 /* for i2c Write */ +#define I2c_M_RD 1 /* for i2c Read */ + +#define REL_RED REL_X +#define REL_GREEN REL_Y +#define REL_BLUE REL_Z +#define REL_WHITE REL_MISC + +/* slave addresses */ +#define CM36651_ALS 0x30 /* 7bits : 0x18 */ +#define CM36651_PS 0x32 /* 7bits : 0x19 */ + +/* register addresses */ +/* Ambient light sensor */ +#define CS_CONF1 0x00 +#define CS_CONF2 0x01 +#define ALS_WH_M 0x02 +#define ALS_WH_L 0x03 +#define ALS_WL_M 0x04 +#define ALS_WL_L 0x05 +#define CS_CONF3 0x06 + +#define RED 0x00 +#define GREEN 0x01 +#define BLUE 0x02 +#define WHITE 0x03 + +/* Proximity sensor */ +#define PS_CONF1 0x00 +#define PS_THD 0x01 +#define PS_CANC 0x02 +#define PS_CONF2 0x03 + +#define ALS_REG_NUM 3 +#define PS_REG_NUM 4 +#define PROX_READ_NUM 40 + +enum { + LIGHT_ENABLED = BIT(0), + PROXIMITY_ENABLED = BIT(1), +}; + +/* register settings */ +static u8 als_reg_setting[ALS_REG_NUM][2] = { + {0x00, 0x04}, /* CS_CONF1 */ + {0x01, 0x08}, /* CS_CONF2 */ + {0x06, 0x00} /* CS_CONF3 */ +}; + +static u8 ps_reg_setting[PS_REG_NUM][2] = { + {0x00, 0x3C}, /* PS_CONF1 */ + {0x01, 0x07}, /* PS_THD */ + {0x02, 0x00}, /* PS_CANC */ + {0x03, 0x13}, /* PS_CONF2 */ +}; + + /* driver data */ +struct cm36651_data { + struct i2c_client *i2c_client; + struct wake_lock prx_wake_lock; + struct input_dev *proximity_input_dev; + struct input_dev *light_input_dev; + struct cm36651_platform_data *pdata; + struct mutex power_lock; + struct mutex read_lock; + struct hrtimer light_timer; + struct hrtimer prox_timer; + struct workqueue_struct *light_wq; + struct workqueue_struct *prox_wq; + struct work_struct work_light; + struct work_struct work_prox; + struct device *proximity_dev; + struct device *light_dev; + ktime_t light_poll_delay; + ktime_t prox_poll_delay; + int irq; + u8 power_state; +#ifdef CM36651_CANCELATION + u8 prox_cal; +#endif + int avg[3]; +}; + +static int cm36651_i2c_read_byte(struct cm36651_data *cm36651, + u8 addr, u8 *val) +{ + int err = 0; + int retry = 3; + struct i2c_msg msg[1]; + struct i2c_client *client = cm36651->i2c_client; + + if ((client == NULL) || (!client->adapter)) + return -ENODEV; + + /* send slave address & command */ + msg->addr = addr >> 1; + msg->flags = I2C_M_RD; + msg->len = 1; + msg->buf = val; + + while (retry--) { + err = i2c_transfer(client->adapter, msg, 1); + if (err >= 0) + return err; + } + pr_err("%s: i2c read failed at addr 0x%x: %d\n", __func__, addr, err); + return err; +} + +static int cm36651_i2c_read_word(struct cm36651_data *cm36651, + u8 addr, u8 command, u16 *val) +{ + int err = 0; + int retry = 3; + struct i2c_client *client = cm36651->i2c_client; + struct i2c_msg msg[2]; + unsigned char data[2] = {0,}; + u16 value = 0; + + if ((client == NULL) || (!client->adapter)) + return -ENODEV; + + while (retry--) { + /* send slave address & command */ + msg[0].addr = addr>>1; + msg[0].flags = I2C_M_WR; + msg[0].len = 1; + msg[0].buf = &command; + + /* read word data */ + msg[1].addr = addr>>1; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + value = (u16)data[1]; + *val = (value << 8) | (u16)data[0]; + return err; + } + } + pr_err("%s, i2c transfer error ret=%d\n", __func__, err); + return err; +} + +static int cm36651_i2c_write_byte(struct cm36651_data *cm36651, + u8 addr, u8 command, u8 val) +{ + int err = 0; + struct i2c_client *client = cm36651->i2c_client; + struct i2c_msg msg[1]; + unsigned char data[2]; + int retry = 3; + + if ((client == NULL) || (!client->adapter)) + return -ENODEV; + + while (retry--) { + data[0] = command; + data[1] = val; + + /* send slave address & command */ + msg->addr = addr>>1; + msg->flags = I2C_M_WR; + msg->len = 2; + msg->buf = data; + + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) + return 0; + } + pr_err("%s, i2c transfer error(%d)\n", __func__, err); + return err; +} + +static void cm36651_light_enable(struct cm36651_data *cm36651) +{ + /* enable setting */ + cm36651_i2c_write_byte(cm36651, CM36651_ALS, CS_CONF1, + als_reg_setting[0][1]); + + hrtimer_start(&cm36651->light_timer, cm36651->light_poll_delay, + HRTIMER_MODE_REL); +} + +static void cm36651_light_disable(struct cm36651_data *cm36651) +{ + /* disable setting */ + cm36651_i2c_write_byte(cm36651, CM36651_ALS, CS_CONF1, + 0x01); + hrtimer_cancel(&cm36651->light_timer); + cancel_work_sync(&cm36651->work_light); +} + +/* sysfs */ +static ssize_t cm36651_poll_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + return sprintf(buf, "%lld\n", ktime_to_ns(cm36651->light_poll_delay)); +} + +static ssize_t cm36651_poll_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + int64_t new_delay; + int err; + + err = kstrtoll(buf, 10, &new_delay); + if (err < 0) + return err; + + mutex_lock(&cm36651->power_lock); + if (new_delay != ktime_to_ns(cm36651->light_poll_delay)) { + cm36651->light_poll_delay = ns_to_ktime(new_delay); + if (cm36651->power_state & LIGHT_ENABLED) { + cm36651_light_disable(cm36651); + cm36651_light_enable(cm36651); + } + pr_info("%s, poll_delay = %lld\n", __func__, new_delay); + } + mutex_unlock(&cm36651->power_lock); + + return size; +} + +static ssize_t light_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + bool new_value; + + if (sysfs_streq(buf, "1")) { + new_value = true; + } else if (sysfs_streq(buf, "0")) { + new_value = false; + } else { + pr_err("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + pr_info("%s,new_value=%d\n", __func__, new_value); + mutex_lock(&cm36651->power_lock); + if (new_value && !(cm36651->power_state & LIGHT_ENABLED)) { + cm36651->power_state |= LIGHT_ENABLED; + cm36651_light_enable(cm36651); + } else if (!new_value && (cm36651->power_state & LIGHT_ENABLED)) { + cm36651_light_disable(cm36651); + cm36651->power_state &= ~LIGHT_ENABLED; + } + mutex_unlock(&cm36651->power_lock); + return size; +} + +static ssize_t light_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", + (cm36651->power_state & LIGHT_ENABLED) ? 1 : 0); +} + +#ifdef CM36651_CANCELATION +static int proximity_open_cancelation(struct cm36651_data *data) +{ + struct file *cancel_filp = NULL; + int err = 0; + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cancel_filp)) { + err = PTR_ERR(cancel_filp); + if (err != -ENOENT) + pr_err("%s: Can't open cancelation file\n", __func__); + set_fs(old_fs); + return err; + } + + err = cancel_filp->f_op->read(cancel_filp, + (char *)&data->prox_cal, sizeof(u8), &cancel_filp->f_pos); + if (err != sizeof(u8)) { + pr_err("%s: Can't read the cancel data from file\n", __func__); + err = -EIO; + } + ps_reg_setting[2][1] = data->prox_cal; + if (ps_reg_setting[2][1] != 0) /*If there is an offset cal data. */ + ps_reg_setting[1][1] = 0x09; + + pr_info("%s: proximity ps_data = %d, thresh = %d\n", __func__, + data->prox_cal, ps_reg_setting[1][1]); + + filp_close(cancel_filp, current->files); + set_fs(old_fs); + + return err; +} + +static int proximity_store_cancelation(struct device *dev, bool do_calib) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + struct file *cancel_filp = NULL; + mm_segment_t old_fs; + int err = 0; + + if (do_calib) { + mutex_lock(&cm36651->read_lock); + cm36651_i2c_read_byte(cm36651, CM36651_PS, &cm36651->prox_cal); + mutex_unlock(&cm36651->read_lock); + ps_reg_setting[1][1] = 0x09; + } else { + cm36651->prox_cal = 0; + ps_reg_setting[1][1] = cm36651->pdata->threshold; + } + cm36651_i2c_write_byte(cm36651, CM36651_PS, PS_THD, + ps_reg_setting[1][1]); + cm36651_i2c_write_byte(cm36651, CM36651_PS, PS_CANC, + cm36651->prox_cal); + + if (!do_calib) + msleep(150); + pr_info("%s: prox_cal = 0x%x\n", __func__, cm36651->prox_cal); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(CANCELATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (IS_ERR(cancel_filp)) { + pr_err("%s: Can't open cancelation file\n", __func__); + set_fs(old_fs); + err = PTR_ERR(cancel_filp); + return err; + } + + err = cancel_filp->f_op->write(cancel_filp, + (char *)&cm36651->prox_cal, sizeof(u8), &cancel_filp->f_pos); + if (err != sizeof(u8)) { + pr_err("%s: Can't write the cancel data to file\n", __func__); + err = -EIO; + } + + filp_close(cancel_filp, current->files); + set_fs(old_fs); + + return err; +} + +static ssize_t proximity_cancel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + bool do_calib; + int err; + + if (sysfs_streq(buf, "1")) { /* calibrate cancelation value */ + do_calib = true; + } else if (sysfs_streq(buf, "0")) { /* reset cancelation value */ + do_calib = false; + } else { + pr_debug("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + err = proximity_store_cancelation(dev, do_calib); + if (err < 0) { + pr_err("%s: proximity_store_cancelation() failed\n", __func__); + return err; + } + + return size; +} + +static ssize_t proximity_cancel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + + return sprintf(buf, "%d,%d\n", cm36651->prox_cal, + ps_reg_setting[1][1]); +} +#endif + +static ssize_t proximity_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + bool new_value; + int err = 0; + + if (sysfs_streq(buf, "1")) { + new_value = true; + } else if (sysfs_streq(buf, "0")) { + new_value = false; + } else { + pr_err("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + pr_info("%s,new_value=%d, prox_cal %d\n", __func__, + new_value, cm36651->prox_cal); + mutex_lock(&cm36651->power_lock); + if (new_value && !(cm36651->power_state & PROXIMITY_ENABLED)) { + u8 val = 1; + int i; + cm36651->pdata->cm36651_led_on(1); + msleep(20); +#ifdef CM36651_CANCELATION + /* open cancelation data */ + err = proximity_open_cancelation(cm36651); + if (err < 0 && err != -ENOENT) + pr_err("%s: proximity_open_cancelation() failed\n", + __func__); +#endif + cm36651->power_state |= PROXIMITY_ENABLED; + /* enable settings */ + + for (i = 0; i < 4; i++) { + cm36651_i2c_write_byte(cm36651, CM36651_PS, + ps_reg_setting[i][0], ps_reg_setting[i][1]); + } + + val = gpio_get_value_cansleep(cm36651->pdata->irq); + /* 0 is close, 1 is far */ + input_report_abs(cm36651->proximity_input_dev, + ABS_DISTANCE, val); + input_sync(cm36651->proximity_input_dev); + + enable_irq(cm36651->irq); + enable_irq_wake(cm36651->irq); + } else if (!new_value && (cm36651->power_state & PROXIMITY_ENABLED)) { + cm36651->power_state &= ~PROXIMITY_ENABLED; + disable_irq_wake(cm36651->irq); + disable_irq(cm36651->irq); + /* disable settings */ + cm36651_i2c_write_byte(cm36651, CM36651_PS, PS_CONF1, + 0x01); + cm36651->pdata->cm36651_led_on(0); + } + mutex_unlock(&cm36651->power_lock); + return size; +} + +static ssize_t proximity_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", + (cm36651->power_state & PROXIMITY_ENABLED) ? 1 : 0); +} + +static DEVICE_ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + cm36651_poll_delay_show, cm36651_poll_delay_store); + +static struct device_attribute dev_attr_light_enable = +__ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, + light_enable_show, light_enable_store); + +static struct device_attribute dev_attr_proximity_enable = +__ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, + proximity_enable_show, proximity_enable_store); + +static struct attribute *light_sysfs_attrs[] = { + &dev_attr_light_enable.attr, + &dev_attr_poll_delay.attr, + NULL +}; + +static struct attribute_group light_attribute_group = { + .attrs = light_sysfs_attrs, +}; + +static struct attribute *proximity_sysfs_attrs[] = { + &dev_attr_proximity_enable.attr, + NULL +}; + +static struct attribute_group proximity_attribute_group = { + .attrs = proximity_sysfs_attrs, +}; + +static ssize_t proximity_avg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + + return sprintf(buf, "%d,%d,%d\n", cm36651->avg[0], + cm36651->avg[1], cm36651->avg[2]); +} + +static ssize_t proximity_avg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + bool new_value = false; + + if (sysfs_streq(buf, "1")) + new_value = true; + else if (sysfs_streq(buf, "0")) + new_value = false; + else { + pr_err("%s, invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + mutex_lock(&cm36651->power_lock); + if (new_value) { + if (!(cm36651->power_state & PROXIMITY_ENABLED)) { + cm36651->pdata->cm36651_led_on(true); + msleep(20); + cm36651_i2c_write_byte(cm36651, CM36651_PS, PS_CONF1, + ps_reg_setting[0][1]); + } + hrtimer_start(&cm36651->prox_timer, cm36651->prox_poll_delay, + HRTIMER_MODE_REL); + } else if (!new_value) { + hrtimer_cancel(&cm36651->prox_timer); + cancel_work_sync(&cm36651->work_prox); + if (!(cm36651->power_state & PROXIMITY_ENABLED)) { + cm36651_i2c_write_byte(cm36651, CM36651_PS, PS_CONF1, + 0x01); + cm36651->pdata->cm36651_led_on(false); + } + } + mutex_unlock(&cm36651->power_lock); + + return size; +} + +static ssize_t proximity_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + u8 proximity_value = 0; + + mutex_lock(&cm36651->power_lock); + if (!(cm36651->power_state & PROXIMITY_ENABLED)) { + cm36651->pdata->cm36651_led_on(true); + cm36651_i2c_write_byte(cm36651, CM36651_PS, PS_CONF1, + ps_reg_setting[0][1]); + msleep(20); + } + + mutex_lock(&cm36651->read_lock); + cm36651_i2c_read_byte(cm36651, CM36651_PS, &proximity_value); + mutex_unlock(&cm36651->read_lock); + + if (!(cm36651->power_state & PROXIMITY_ENABLED)) { + cm36651_i2c_write_byte(cm36651, CM36651_PS, PS_CONF1, 0x01); + cm36651->pdata->cm36651_led_on(false); + } + mutex_unlock(&cm36651->power_lock); + + return sprintf(buf, "%d\n", proximity_value); +} + +static ssize_t proximity_thresh_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "prox_threshold = %d\n", ps_reg_setting[1][1]); +} + +static ssize_t proximity_thresh_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + u8 thresh_value = 0x09; + int err = 0; + + err = kstrtou8(buf, 10, &thresh_value); + if (err < 0) + pr_err("%s, kstrtoint failed.", __func__); + + ps_reg_setting[1][1] = thresh_value; + err = cm36651_i2c_write_byte(cm36651, CM36651_PS, + PS_THD, ps_reg_setting[1][1]); + if (err < 0) { + pr_err("%s: cm36651_ps_reg is failed. %d\n", __func__, + err); + return err; + } + pr_info("%s, new threshold = 0x%x\n", + __func__, ps_reg_setting[1][1]); + msleep(150); + + return size; +} + + +static ssize_t lightsensor_lux_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + u16 val_red = 0, val_green = 0, val_blue = 0, val_white = 0; + + mutex_lock(&cm36651->power_lock); + if (!(cm36651->power_state & LIGHT_ENABLED)) + cm36651_light_enable(cm36651); + + mutex_lock(&cm36651->read_lock); + cm36651_i2c_read_word(cm36651, CM36651_ALS, RED, &val_red); + cm36651_i2c_read_word(cm36651, CM36651_ALS, GREEN, &val_green); + cm36651_i2c_read_word(cm36651, CM36651_ALS, BLUE, &val_blue); + cm36651_i2c_read_word(cm36651, CM36651_ALS, WHITE, &val_white); + mutex_unlock(&cm36651->read_lock); + + if (!(cm36651->power_state & LIGHT_ENABLED)) + cm36651_light_disable(cm36651); + + mutex_unlock(&cm36651->power_lock); + + return sprintf(buf, "%d,%d,%d,%d\n", + (int)val_red+1, (int)val_green+1, (int)val_blue+1, + (int)val_white+1); +} + +static ssize_t cm36651_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", RGB_VENDOR); +} + +static ssize_t cm36651_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", RGB_CHIP_ID); +} + +static DEVICE_ATTR(prox_avg, S_IRUGO | S_IWUSR, proximity_avg_show, + proximity_avg_store); +#ifdef CM36651_CANCELATION +static DEVICE_ATTR(prox_cal, S_IRUGO | S_IWUSR, proximity_cancel_show, + proximity_cancel_store); +#endif +static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, proximity_state_show, NULL); + +static DEVICE_ATTR(prox_thresh, S_IRUGO | S_IWUSR, proximity_thresh_show, + proximity_thresh_store); + +static DEVICE_ATTR(lux, S_IRUGO | S_IWUSR, lightsensor_lux_show, NULL); + +static DEVICE_ATTR(vendor, S_IRUGO, cm36651_vendor_show, NULL); + +static DEVICE_ATTR(name, S_IRUGO, cm36651_name_show, NULL); + +static DEVICE_ATTR(raw_data, S_IRUGO, lightsensor_lux_show, NULL); + +/* interrupt happened due to transition/change of near/far proximity state */ +static irqreturn_t cm36651_irq_thread_fn(int irq, void *data) +{ + struct cm36651_data *cm36651 = data; + u8 val = 1; + u8 ps_data = 0; + + val = gpio_get_value_cansleep(cm36651->pdata->irq); + + mutex_lock(&cm36651->read_lock); + cm36651_i2c_read_byte(cm36651, CM36651_PS, &ps_data); + mutex_unlock(&cm36651->read_lock); + + + /* 0 is close, 1 is far */ + input_report_abs(cm36651->proximity_input_dev, ABS_DISTANCE, val); + input_sync(cm36651->proximity_input_dev); + wake_lock_timeout(&cm36651->prx_wake_lock, 3 * HZ); + pr_info("%s: val = %d (close:0, far:1), ps_data = %d\n", __func__, + val, ps_data); + + return IRQ_HANDLED; +} + +static int cm36651_setup_reg(struct cm36651_data *cm36651) +{ + int err = 0, i = 0; + u8 tmp = 0; + + /* ALS initialization */ + for (i = 0; i < ALS_REG_NUM; i++) { + err = cm36651_i2c_write_byte(cm36651, + CM36651_ALS, als_reg_setting[i][0], + als_reg_setting[i][1]); + if (err < 0) { + pr_err("%s: cm36651_als_reg is failed. %d\n", __func__, + err); + return err; + } + } + + /* PS initialization */ + for (i = 0; i < PS_REG_NUM; i++) { + err = cm36651_i2c_write_byte(cm36651, CM36651_PS, + ps_reg_setting[i][0], ps_reg_setting[i][1]); + if (err < 0) { + pr_err("%s: cm36651_ps_reg is failed. %d\n", __func__, + err); + return err; + } + } + + /* printing the inital proximity value with no contact */ + msleep(50); + mutex_lock(&cm36651->read_lock); + err = cm36651_i2c_read_byte(cm36651, CM36651_PS, &tmp); + mutex_unlock(&cm36651->read_lock); + if (err < 0) { + pr_err("%s: read ps_data failed\n", __func__); + err = -EIO; + } + pr_err("%s: initial proximity value = %d\n", __func__, tmp); + + /* turn off */ + cm36651_i2c_write_byte(cm36651, CM36651_ALS, CS_CONF1, 0x01); + cm36651_i2c_write_byte(cm36651, CM36651_ALS, PS_CONF1, 0x01); + + pr_info("%s is success.", __func__); + return err; +} + +static int cm36651_setup_irq(struct cm36651_data *cm36651) +{ + int rc = -EIO; + struct cm36651_platform_data *pdata = cm36651->pdata; + + rc = gpio_request(pdata->irq, "gpio_proximity_out"); + if (rc < 0) { + pr_err("%s: gpio %d request failed (%d)\n", + __func__, pdata->irq, rc); + goto done; + } + + rc = gpio_direction_input(pdata->irq); + if (rc < 0) { + pr_err("%s: failed to set gpio %d as input (%d)\n", + __func__, pdata->irq, rc); + goto err_gpio_direction_input; + } + + cm36651->irq = gpio_to_irq(pdata->irq); + rc = request_threaded_irq(cm36651->irq, NULL, + cm36651_irq_thread_fn, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "proximity_int", cm36651); + if (rc < 0) { + pr_err("%s: request_irq(%d) failed for gpio %d (%d)\n", + __func__, cm36651->irq, pdata->irq, rc); + goto err_request_irq; + } + + /* start with interrupts disabled */ + disable_irq(cm36651->irq); + + goto done; + +err_request_irq: +err_gpio_direction_input: + gpio_free(pdata->irq); +done: + return rc; +} + +/* + * This function is for light sensor. It operates every a few seconds. + * It asks for work to be done on a thread because i2c needs a thread + * context (slow and blocking) and then reschedules the timer to run again. + */ +static enum hrtimer_restart cm36651_light_timer_func(struct hrtimer *timer) +{ + struct cm36651_data *cm36651 + = container_of(timer, struct cm36651_data, light_timer); + queue_work(cm36651->light_wq, &cm36651->work_light); + hrtimer_forward_now(&cm36651->light_timer, cm36651->light_poll_delay); + return HRTIMER_RESTART; +} + +static void cm36651_work_func_light(struct work_struct *work) +{ + u16 val_red = 0, val_green = 0, val_blue = 0, val_white = 0; + struct cm36651_data *cm36651 = container_of(work, struct cm36651_data, + work_light); + + mutex_lock(&cm36651->read_lock); + cm36651_i2c_read_word(cm36651, CM36651_ALS, RED, &val_red); + cm36651_i2c_read_word(cm36651, CM36651_ALS, GREEN, &val_green); + cm36651_i2c_read_word(cm36651, CM36651_ALS, BLUE, &val_blue); + cm36651_i2c_read_word(cm36651, CM36651_ALS, WHITE, &val_white); + mutex_unlock(&cm36651->read_lock); + + input_report_rel(cm36651->light_input_dev, REL_RED, (int)val_red+1); + input_report_rel(cm36651->light_input_dev, REL_GREEN, (int)val_green+1); + input_report_rel(cm36651->light_input_dev, REL_BLUE, (int)val_blue+1); + input_report_rel(cm36651->light_input_dev, REL_WHITE, (int)val_white+1); + input_sync(cm36651->light_input_dev); +#ifdef CM36651_DEBUG + pr_info("%s, red = %d, green = %d, blue = %d, white = %d\n", + __func__, val_red+1, val_green+1, val_blue+1, val_white+1); +#endif +} + +static void proxsensor_get_avg_val(struct cm36651_data *cm36651) +{ + int min = 0, max = 0, avg = 0; + int i; + u8 ps_data = 0; + + for (i = 0; i < PROX_READ_NUM; i++) { + msleep(40); + cm36651_i2c_read_byte(cm36651, CM36651_PS, &ps_data); + avg += ps_data; + + if (!i) + min = ps_data; + else if (ps_data < min) + min = ps_data; + + if (ps_data > max) + max = ps_data; + } + avg /= PROX_READ_NUM; + + cm36651->avg[0] = min; + cm36651->avg[1] = avg; + cm36651->avg[2] = max; +} + +static void cm36651_work_func_prox(struct work_struct *work) +{ + struct cm36651_data *cm36651 = container_of(work, struct cm36651_data, + work_prox); + proxsensor_get_avg_val(cm36651); +} + +static enum hrtimer_restart cm36651_prox_timer_func(struct hrtimer *timer) +{ + struct cm36651_data *cm36651 + = container_of(timer, struct cm36651_data, prox_timer); + queue_work(cm36651->prox_wq, &cm36651->work_prox); + hrtimer_forward_now(&cm36651->prox_timer, cm36651->prox_poll_delay); + return HRTIMER_RESTART; +} + +static int cm36651_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = -ENODEV; + int retry = 4; + struct cm36651_data *cm36651 = NULL; + struct cm36651_platform_data *pdata = client->dev.platform_data; + + if (!pdata) { + pr_err("%s: missing pdata!\n", __func__); + return ret; + } + + if (pdata->cm36651_power_on) + pdata->cm36651_power_on(1); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s: i2c functionality check failed!\n", __func__); + if (pdata->cm36651_power_on) + pdata->cm36651_power_on(0); + return ret; + } + + cm36651 = kzalloc(sizeof(struct cm36651_data), GFP_KERNEL); + if (!cm36651) { + pr_err + ("%s: failed to alloc memory for RGB sensor module data\n", + __func__); + if (pdata->cm36651_power_on) + pdata->cm36651_power_on(0); + return -ENOMEM; + } + + cm36651->pdata = pdata; + cm36651->i2c_client = client; + i2c_set_clientdata(client, cm36651); + mutex_init(&cm36651->power_lock); + mutex_init(&cm36651->read_lock); + + /* wake lock init for proximity sensor */ + wake_lock_init(&cm36651->prx_wake_lock, WAKE_LOCK_SUSPEND, + "prx_wake_lock"); + if (pdata->threshold) + ps_reg_setting[1][1] = pdata->threshold; + + cm36651->pdata->cm36651_led_on(1); + do { + retry--; + /* Check if the device is there or not. */ + ret = cm36651_i2c_write_byte(cm36651, CM36651_PS, + CS_CONF1, 0x01); + if (ret < 0) { + pr_err("%s: checking i2c error.(%d), retry %d\n", + __func__, ret, retry); + msleep(20); + } else { + break; + } + } while (retry); + if (ret < 0) { + pr_err("%s: cm36651 is not connected.(%d)\n", __func__, ret); + cm36651->pdata->cm36651_led_on(0); + goto err_setup_reg; + } + /* setup initial registers */ + ret = cm36651_setup_reg(cm36651); + if (ret < 0) { + pr_err("%s: could not setup regs\n", __func__); + cm36651->pdata->cm36651_led_on(0); + goto err_setup_reg; + } + cm36651->pdata->cm36651_led_on(0); + + /* allocate proximity input_device */ + cm36651->proximity_input_dev = input_allocate_device(); + if (!cm36651->proximity_input_dev) { + pr_err("%s: could not allocate proximity input device\n", + __func__); + goto err_input_allocate_device_proximity; + } + + input_set_drvdata(cm36651->proximity_input_dev, cm36651); + cm36651->proximity_input_dev->name = "proximity_sensor"; + input_set_capability(cm36651->proximity_input_dev, EV_ABS, + ABS_DISTANCE); + input_set_abs_params(cm36651->proximity_input_dev, ABS_DISTANCE, 0, 1, + 0, 0); + + ret = input_register_device(cm36651->proximity_input_dev); + if (ret < 0) { + input_free_device(cm36651->proximity_input_dev); + pr_err("%s: could not register input device\n", __func__); + goto err_input_register_device_proximity; + } + + ret = sysfs_create_group(&cm36651->proximity_input_dev->dev.kobj, + &proximity_attribute_group); + if (ret) { + pr_err("%s: could not create sysfs group\n", __func__); + goto err_sysfs_create_group_proximity; + } + + /* setup irq */ + ret = cm36651_setup_irq(cm36651); + if (ret) { + pr_err("%s: could not setup irq\n", __func__); + goto err_setup_irq; + } + + /* For factory test mode, we use timer to get average proximity data. */ + /* prox_timer settings. we poll for light values using a timer. */ + hrtimer_init(&cm36651->prox_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + cm36651->prox_poll_delay = ns_to_ktime(2000 * NSEC_PER_MSEC);/*2 sec*/ + cm36651->prox_timer.function = cm36651_prox_timer_func; + + /* the timer just fires off a work queue request. we need a thread + to read the i2c (can be slow and blocking). */ + cm36651->prox_wq = create_singlethread_workqueue("cm36651_prox_wq"); + if (!cm36651->prox_wq) { + ret = -ENOMEM; + pr_err("%s: could not create prox workqueue\n", __func__); + goto err_create_prox_workqueue; + } + /* this is the thread function we run on the work queue */ + INIT_WORK(&cm36651->work_prox, cm36651_work_func_prox); + + /* allocate lightsensor input_device */ + cm36651->light_input_dev = input_allocate_device(); + if (!cm36651->light_input_dev) { + pr_err("%s: could not allocate light input device\n", __func__); + goto err_input_allocate_device_light; + } + + input_set_drvdata(cm36651->light_input_dev, cm36651); + cm36651->light_input_dev->name = "light_sensor"; + input_set_capability(cm36651->light_input_dev, EV_REL, REL_RED); + input_set_capability(cm36651->light_input_dev, EV_REL, REL_GREEN); + input_set_capability(cm36651->light_input_dev, EV_REL, REL_BLUE); + input_set_capability(cm36651->light_input_dev, EV_REL, REL_WHITE); + + ret = input_register_device(cm36651->light_input_dev); + if (ret < 0) { + input_free_device(cm36651->light_input_dev); + pr_err("%s: could not register input device\n", __func__); + goto err_input_register_device_light; + } + + ret = sysfs_create_group(&cm36651->light_input_dev->dev.kobj, + &light_attribute_group); + if (ret) { + pr_err("%s: could not create sysfs group\n", __func__); + goto err_sysfs_create_group_light; + } + + /* light_timer settings. we poll for light values using a timer. */ + hrtimer_init(&cm36651->light_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + cm36651->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC); + cm36651->light_timer.function = cm36651_light_timer_func; + + /* the timer just fires off a work queue request. we need a thread + to read the i2c (can be slow and blocking). */ + cm36651->light_wq = create_singlethread_workqueue("cm36651_light_wq"); + if (!cm36651->light_wq) { + ret = -ENOMEM; + pr_err("%s: could not create light workqueue\n", __func__); + goto err_create_light_workqueue; + } + + /* this is the thread function we run on the work queue */ + INIT_WORK(&cm36651->work_light, cm36651_work_func_light); + + cm36651->proximity_dev = device_create(sensors_class, + NULL, 0, NULL, "proximity_sensor"); + if (IS_ERR(cm36651->proximity_dev)) { + pr_err("%s: could not create proximity_dev\n", __func__); + goto err_proximity_device_create; + } + + cm36651->light_dev = device_create(sensors_class, + NULL, 0, NULL, "light_sensor"); + if (IS_ERR(cm36651->light_dev)) { + pr_err("%s: could not create light_dev\n", __func__); + goto err_light_device_create; + } + + if (device_create_file(cm36651->proximity_dev, &dev_attr_state) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_state.attr.name); + goto err_proximity_device_create_file1; + } + +#ifdef CM36651_CANCELATION + if (device_create_file(cm36651->proximity_dev, + &dev_attr_prox_cal) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_prox_cal.attr.name); + goto err_proximity_device_create_file2; + } +#endif + + if (device_create_file(cm36651->proximity_dev, + &dev_attr_prox_avg) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_prox_avg.attr.name); + goto err_proximity_device_create_file3; + } + + if (device_create_file(cm36651->proximity_dev, + &dev_attr_vendor) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_vendor.attr.name); + goto err_proximity_device_create_file4; + } + + if (device_create_file(cm36651->proximity_dev, + &dev_attr_name) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_name.attr.name); + goto err_proximity_device_create_file5; + } + + if (device_create_file(cm36651->proximity_dev, + &dev_attr_prox_thresh) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_prox_thresh.attr.name); + goto err_proximity_device_create_file6; + } + + dev_set_drvdata(cm36651->proximity_dev, cm36651); + + + if (device_create_file(cm36651->light_dev, &dev_attr_lux) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_lux.attr.name); + goto err_light_device_create_file1; + } + if (device_create_file(cm36651->light_dev, &dev_attr_raw_data) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_raw_data.attr.name); + goto err_light_device_create_file2; + } + if (device_create_file(cm36651->light_dev, &dev_attr_vendor) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_vendor.attr.name); + goto err_light_device_create_file3; + } + if (device_create_file(cm36651->light_dev, &dev_attr_name) < 0) { + pr_err("%s: could not create device file(%s)!\n", __func__, + dev_attr_name.attr.name); + goto err_light_device_create_file4; + } + dev_set_drvdata(cm36651->light_dev, cm36651); + pr_info("%s is success.\n", __func__); + goto done; + +/* error, unwind it all */ +err_light_device_create_file4: + device_remove_file(cm36651->light_dev, &dev_attr_vendor); +err_light_device_create_file3: + device_remove_file(cm36651->light_dev, &dev_attr_raw_data); +err_light_device_create_file2: + device_remove_file(cm36651->light_dev, &dev_attr_lux); +err_light_device_create_file1: + device_remove_file(cm36651->proximity_dev, &dev_attr_prox_thresh); +err_proximity_device_create_file6: + device_remove_file(cm36651->proximity_dev, &dev_attr_name); +err_proximity_device_create_file5: + device_remove_file(cm36651->proximity_dev, &dev_attr_vendor); +err_proximity_device_create_file4: + device_remove_file(cm36651->proximity_dev, &dev_attr_prox_avg); +err_proximity_device_create_file3: +#ifdef CM36651_CANCELATION + device_remove_file(cm36651->proximity_dev, &dev_attr_prox_cal); +err_proximity_device_create_file2: +#endif + device_remove_file(cm36651->proximity_dev, &dev_attr_state); +err_proximity_device_create_file1: +err_light_device_create: + device_destroy(sensors_class, 0); +err_proximity_device_create: + destroy_workqueue(cm36651->light_wq); +err_create_light_workqueue: + sysfs_remove_group(&cm36651->light_input_dev->dev.kobj, + &light_attribute_group); +err_sysfs_create_group_light: + input_unregister_device(cm36651->light_input_dev); +err_input_register_device_light: +err_input_allocate_device_light: + destroy_workqueue(cm36651->prox_wq); +err_create_prox_workqueue: + free_irq(cm36651->irq, cm36651); + gpio_free(cm36651->pdata->irq); +err_setup_irq: + sysfs_remove_group(&cm36651->proximity_input_dev->dev.kobj, + &proximity_attribute_group); +err_sysfs_create_group_proximity: + input_unregister_device(cm36651->proximity_input_dev); +err_input_register_device_proximity: +err_input_allocate_device_proximity: +err_setup_reg: + wake_lock_destroy(&cm36651->prx_wake_lock); + mutex_destroy(&cm36651->read_lock); + mutex_destroy(&cm36651->power_lock); + if (pdata->cm36651_power_on) + pdata->cm36651_power_on(0); + kfree(cm36651); +done: + return ret; +} + +static int cm36651_i2c_remove(struct i2c_client *client) +{ + struct cm36651_data *cm36651 = i2c_get_clientdata(client); + + /* free irq */ + free_irq(cm36651->irq, cm36651); + gpio_free(cm36651->pdata->irq); + + /* destroy workqueue */ + destroy_workqueue(cm36651->light_wq); + destroy_workqueue(cm36651->prox_wq); + + /* device off */ + if (cm36651->power_state) { + if (cm36651->power_state & LIGHT_ENABLED) + cm36651_light_disable(cm36651); + if (cm36651->power_state & PROXIMITY_ENABLED) { + cm36651_i2c_write_byte(cm36651, CM36651_PS, PS_CONF1, + 0x01); + cm36651->pdata->cm36651_led_on(0); + } + } + + /* sysfs destroy */ + device_remove_file(cm36651->light_dev, &dev_attr_lux); + device_remove_file(cm36651->light_dev, &dev_attr_raw_data); + device_remove_file(cm36651->light_dev, &dev_attr_vendor); + device_remove_file(cm36651->light_dev, &dev_attr_name); + device_remove_file(cm36651->proximity_dev, &dev_attr_prox_avg); +#ifdef CM36651_CANCELATION + device_remove_file(cm36651->proximity_dev, &dev_attr_prox_cal); +#endif + device_remove_file(cm36651->proximity_dev, &dev_attr_state); + device_remove_file(cm36651->proximity_dev, &dev_attr_vendor); + device_remove_file(cm36651->proximity_dev, &dev_attr_name); + + device_destroy(sensors_class, 0); + + /* input device destroy */ + sysfs_remove_group(&cm36651->light_input_dev->dev.kobj, + &light_attribute_group); + input_unregister_device(cm36651->light_input_dev); + sysfs_remove_group(&cm36651->proximity_input_dev->dev.kobj, + &proximity_attribute_group); + input_unregister_device(cm36651->proximity_input_dev); + + /* lock destroy */ + mutex_destroy(&cm36651->read_lock); + mutex_destroy(&cm36651->power_lock); + wake_lock_destroy(&cm36651->prx_wake_lock); + + kfree(cm36651); + + return 0; +} + +static int cm36651_suspend(struct device *dev) +{ + /* We disable power only if proximity is disabled. If proximity + is enabled, we leave power on because proximity is allowed + to wake up device. We remove power without changing + cm36651->power_state because we use that state in resume. + */ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + + if (cm36651->power_state & LIGHT_ENABLED) + cm36651_light_disable(cm36651); + if (!(cm36651->power_state & PROXIMITY_ENABLED)) { + gpio_free(cm36651->pdata->irq); + if (cm36651->pdata->cm36651_power_on) + cm36651->pdata->cm36651_power_on(0); + } + + return 0; +} + +static int cm36651_resume(struct device *dev) +{ + struct cm36651_data *cm36651 = dev_get_drvdata(dev); + int ret = 0; + if (!(cm36651->power_state & PROXIMITY_ENABLED)) { + ret = gpio_request(cm36651->pdata->irq, "gpio_proximity_out"); + if (ret) { + pr_err("%s gpio request %d err\n", __func__, + cm36651->pdata->irq); + } + if (cm36651->pdata->cm36651_power_on) + cm36651->pdata->cm36651_power_on(1); + } + if (cm36651->power_state & LIGHT_ENABLED) + cm36651_light_enable(cm36651); + + return 0; +} + +static const struct i2c_device_id cm36651_device_id[] = { + {"cm36651", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cm36651_device_id); + +static const struct dev_pm_ops cm36651_pm_ops = { + .suspend = cm36651_suspend, + .resume = cm36651_resume +}; + +static struct i2c_driver cm36651_i2c_driver = { + .driver = { + .name = "cm36651", + .owner = THIS_MODULE, + .pm = &cm36651_pm_ops}, + .probe = cm36651_i2c_probe, + .remove = cm36651_i2c_remove, + .id_table = cm36651_device_id, +}; + +static int __init cm36651_init(void) +{ + return i2c_add_driver(&cm36651_i2c_driver); +} + +static void __exit cm36651_exit(void) +{ + i2c_del_driver(&cm36651_i2c_driver); +} + +module_init(cm36651_init); +module_exit(cm36651_exit); + +MODULE_AUTHOR("Samsung Electronics"); +MODULE_DESCRIPTION("RGB Sensor device driver for cm36651"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/fsa9485.c b/drivers/misc/fsa9485.c new file mode 100644 index 00000000000..84783d1e1d1 --- /dev/null +++ b/drivers/misc/fsa9485.c @@ -0,0 +1,1362 @@ +/* + * driver/misc/fsa9480.c - FSA9480 micro USB switch device driver + * + * Copyright (C) 2010 Samsung Electronics + * Minkyu Kang + * Wonguk Jeong + * + * 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 + +/* FSA9480 I2C registers */ +#define FSA9485_REG_DEVID 0x01 +#define FSA9485_REG_CTRL 0x02 +#define FSA9485_REG_INT1 0x03 +#define FSA9485_REG_INT2 0x04 +#define FSA9485_REG_INT1_MASK 0x05 +#define FSA9485_REG_INT2_MASK 0x06 +#define FSA9485_REG_ADC 0x07 +#define FSA9485_REG_TIMING1 0x08 +#define FSA9485_REG_TIMING2 0x09 +#define FSA9485_REG_DEV_T1 0x0a +#define FSA9485_REG_DEV_T2 0x0b +#define FSA9485_REG_BTN1 0x0c +#define FSA9485_REG_BTN2 0x0d +#define FSA9485_REG_CK 0x0e +#define FSA9485_REG_CK_INT1 0x0f +#define FSA9485_REG_CK_INT2 0x10 +#define FSA9485_REG_CK_INTMASK1 0x11 +#define FSA9485_REG_CK_INTMASK2 0x12 +#define FSA9485_REG_MANSW1 0x13 +#define FSA9485_REG_MANSW2 0x14 +#define FSA9485_REG_MANUAL_OVERRIDES1 0x1B +#define FSA9485_REG_RESERVED_1D 0x1D +#define FSA9485_REG_RESERVED_20 0x20 + + +/* Control */ +#define CON_SWITCH_OPEN (1 << 4) +#define CON_RAW_DATA (1 << 3) +#define CON_MANUAL_SW (1 << 2) +#define CON_WAIT (1 << 1) +#define CON_INT_MASK (1 << 0) +#define CON_MASK (CON_SWITCH_OPEN | CON_RAW_DATA | \ + CON_MANUAL_SW | CON_WAIT) + +/* Device Type 1 */ +#define DEV_USB_OTG (1 << 7) +#define DEV_DEDICATED_CHG (1 << 6) +#define DEV_USB_CHG (1 << 5) +#define DEV_CAR_KIT (1 << 4) +#define DEV_UART (1 << 3) +#define DEV_USB (1 << 2) +#define DEV_AUDIO_2 (1 << 1) +#define DEV_AUDIO_1 (1 << 0) + +#define DEV_T1_USB_MASK (DEV_USB_OTG | DEV_USB_CHG | DEV_USB) +#define DEV_T1_UART_MASK (DEV_UART) +#define DEV_T1_CHARGER_MASK (DEV_DEDICATED_CHG | DEV_CAR_KIT) + +/* Device Type 2 */ +#define DEV_AUDIO_DOCK (1 << 8) +#define DEV_SMARTDOCK (1 << 7) +#define DEV_AV (1 << 6) +#define DEV_TTY (1 << 5) +#define DEV_PPD (1 << 4) +#define DEV_JIG_UART_OFF (1 << 3) +#define DEV_JIG_UART_ON (1 << 2) +#define DEV_JIG_USB_OFF (1 << 1) +#define DEV_JIG_USB_ON (1 << 0) + +#define DEV_T2_USB_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON) +#define DEV_T2_UART_MASK (DEV_JIG_UART_OFF) +#define DEV_T2_JIG_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \ + DEV_JIG_UART_OFF) + +/* + * Manual Switch + * D- [7:5] / D+ [4:2] + * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO + */ +#define SW_VAUDIO ((4 << 5) | (4 << 2) | (1 << 1) | (1 << 0)) +#define SW_UART ((3 << 5) | (3 << 2)) +#define SW_AUDIO ((2 << 5) | (2 << 2) | (1 << 1) | (1 << 0)) +#define SW_DHOST ((1 << 5) | (1 << 2) | (1 << 1) | (1 << 0)) +#define SW_AUTO ((0 << 5) | (0 << 2)) +#define SW_USB_OPEN (1 << 0) +#define SW_ALL_OPEN (0) + +/* Interrupt 1 */ +#define INT_DETACH (1 << 1) +#define INT_ATTACH (1 << 0) + +#define ADC_GND 0x00 +#define ADC_MHL 0x01 +#define ADC_DOCK_PREV_KEY 0x04 +#define ADC_DOCK_NEXT_KEY 0x07 +#define ADC_DOCK_VOL_DN 0x0a +#define ADC_DOCK_VOL_UP 0x0b +#define ADC_DOCK_PLAY_PAUSE_KEY 0x0d +#define ADC_CEA936ATYPE1_CHG 0x17 +#define ADC_JIG_USB_OFF 0x18 +#define ADC_JIG_USB_ON 0x19 +#define ADC_DESKDOCK 0x1a +#define ADC_CEA936ATYPE2_CHG 0x1b +#define ADC_JIG_UART_OFF 0x1c +#define ADC_JIG_UART_ON 0x1d +#define ADC_CARDOCK 0x1d +#define ADC_OPEN 0x1f + +int uart_connecting; +EXPORT_SYMBOL(uart_connecting); + +int detached_status; +EXPORT_SYMBOL(detached_status); + +struct fsa9485_usbsw { + struct i2c_client *client; + struct fsa9485_platform_data *pdata; + int dev1; + int dev2; + int mansw; + int dock_attached; + + struct input_dev *input; + int previous_key; + + struct delayed_work init_work; + struct mutex mutex; + int adc; + int deskdock; +}; + +enum { + DOCK_KEY_NONE = 0, + DOCK_KEY_VOL_UP_PRESSED, + DOCK_KEY_VOL_UP_RELEASED, + DOCK_KEY_VOL_DOWN_PRESSED, + DOCK_KEY_VOL_DOWN_RELEASED, + DOCK_KEY_PREV_PRESSED, + DOCK_KEY_PREV_RELEASED, + DOCK_KEY_PLAY_PAUSE_PRESSED, + DOCK_KEY_PLAY_PAUSE_RELEASED, + DOCK_KEY_NEXT_PRESSED, + DOCK_KEY_NEXT_RELEASED, + +}; + +static struct fsa9485_usbsw *local_usbsw; + +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) +#define MHL_DEVICE 2 +static int isDeskdockconnected; +#endif + +static void DisableFSA9480Interrupts(void) +{ + struct i2c_client *client = local_usbsw->client; + int value, ret; + + value = i2c_smbus_read_byte_data(client, FSA9485_REG_CTRL); + value |= 0x01; + + ret = i2c_smbus_write_byte_data(client, FSA9485_REG_CTRL, value); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + +} + +static void EnableFSA9480Interrupts(void) +{ + struct i2c_client *client = local_usbsw->client; + int value, ret; + + value = i2c_smbus_read_byte_data(client, FSA9485_REG_CTRL); + value &= 0xFE; + + ret = i2c_smbus_write_byte_data(client, FSA9485_REG_CTRL, value); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + +} + +void FSA9485_CheckAndHookAudioDock(int value) +{ + struct i2c_client *client = local_usbsw->client; + struct fsa9485_platform_data *pdata = local_usbsw->pdata; + int ret = 0; + + if (value) { + pr_info("FSA9485_CheckAndHookAudioDock ON\n"); + if (pdata->dock_cb) + pdata->dock_cb(FSA9485_ATTACHED_DESK_DOCK); + + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, SW_AUDIO); + + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", + __func__, ret); + + ret = i2c_smbus_read_byte_data(client, + FSA9485_REG_CTRL); + + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", + __func__, ret); + + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, + ret & ~CON_MANUAL_SW & ~CON_RAW_DATA); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + } else { + dev_info(&client->dev, + "FSA9485_CheckAndHookAudioDock Off\n"); + + if (pdata->dock_cb) + pdata->dock_cb(FSA9485_DETACHED_DOCK); + + ret = i2c_smbus_read_byte_data(client, + FSA9485_REG_CTRL); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, + ret | CON_MANUAL_SW | CON_RAW_DATA); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + } +} + +static void fsa9485_reg_init(struct fsa9485_usbsw *usbsw) +{ + struct i2c_client *client = usbsw->client; + unsigned int ctrl = CON_MASK; + int ret; + pr_info("fsa9485_reg_init is called\n"); + /* mask interrupts (unmask attach/detach only) */ + ret = i2c_smbus_write_word_data(client, FSA9485_REG_INT1_MASK, 0x18fc); + + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + /* mask all car kit interrupts */ + ret = i2c_smbus_write_word_data(client, + FSA9485_REG_CK_INTMASK1, 0x07ff); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + /* ADC Detect Time: 500ms */ + ret = i2c_smbus_write_byte_data(client, FSA9485_REG_TIMING1, 0x0); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + usbsw->mansw = i2c_smbus_read_byte_data(client, FSA9485_REG_MANSW1); + if (usbsw->mansw < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, usbsw->mansw); + + if (usbsw->mansw) + ctrl &= ~CON_MANUAL_SW; /* Manual Switching Mode */ + else + ctrl &= ~(CON_INT_MASK); + + ret = i2c_smbus_write_byte_data(client, FSA9485_REG_CTRL, ctrl); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + /* apply Battery Charging Spec. 1.1 @TA/USB detect */ + ret = i2c_smbus_write_byte_data(client, FSA9485_REG_RESERVED_20, 0x04); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_read_byte_data(client, FSA9485_REG_DEVID); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + dev_info(&client->dev, " fsa9485_reg_init dev ID: 0x%x\n", ret); +} + +static ssize_t fsa9485_show_control(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fsa9485_usbsw *usbsw = dev_get_drvdata(dev); + struct i2c_client *client = usbsw->client; + int value; + + value = i2c_smbus_read_byte_data(client, FSA9485_REG_CTRL); + if (value < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, value); + + return snprintf(buf, 13, "CONTROL: %02x\n", value); +} + +static ssize_t fsa9485_show_device_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fsa9485_usbsw *usbsw = dev_get_drvdata(dev); + struct i2c_client *client = usbsw->client; + int value; + + value = i2c_smbus_read_byte_data(client, FSA9485_REG_DEV_T1); + if (value < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, value); + + return snprintf(buf, 11, "DEVICE_TYPE: %02x\n", value); +} + +static ssize_t fsa9485_show_manualsw(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fsa9485_usbsw *usbsw = dev_get_drvdata(dev); + struct i2c_client *client = usbsw->client; + int value; + + value = i2c_smbus_read_byte_data(client, FSA9485_REG_MANSW1); + if (value < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, value); + + if (value == SW_VAUDIO) + return snprintf(buf, 7, "VAUDIO\n"); + else if (value == SW_UART) + return snprintf(buf, 5, "UART\n"); + else if (value == SW_AUDIO) + return snprintf(buf, 6, "AUDIO\n"); + else if (value == SW_DHOST) + return snprintf(buf, 6, "DHOST\n"); + else if (value == SW_AUTO) + return snprintf(buf, 5, "AUTO\n"); + else + return snprintf(buf, 4, "%x", value); +} + +static ssize_t fsa9485_set_manualsw(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fsa9485_usbsw *usbsw = dev_get_drvdata(dev); + struct i2c_client *client = usbsw->client; + int value, ret; + unsigned int path = 0; + + value = i2c_smbus_read_byte_data(client, FSA9485_REG_CTRL); + if (value < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, value); + + if ((value & ~CON_MANUAL_SW) != + (CON_SWITCH_OPEN | CON_RAW_DATA | CON_WAIT)) + return 0; + + if (!strncmp(buf, "VAUDIO", 6)) { + path = SW_VAUDIO; + value &= ~CON_MANUAL_SW; + } else if (!strncmp(buf, "UART", 4)) { + path = SW_UART; + value &= ~CON_MANUAL_SW; + } else if (!strncmp(buf, "AUDIO", 5)) { + path = SW_AUDIO; + value &= ~CON_MANUAL_SW; + } else if (!strncmp(buf, "DHOST", 5)) { + path = SW_DHOST; + value &= ~CON_MANUAL_SW; + } else if (!strncmp(buf, "AUTO", 4)) { + path = SW_AUTO; + value |= CON_MANUAL_SW; + } else { + dev_err(dev, "Wrong command\n"); + return 0; + } + + usbsw->mansw = path; + + ret = i2c_smbus_write_byte_data(client, FSA9485_REG_MANSW1, path); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_write_byte_data(client, FSA9485_REG_CTRL, value); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + return count; +} +static ssize_t fsa9480_show_usb_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fsa9485_usbsw *usbsw = dev_get_drvdata(dev); + struct i2c_client *client = usbsw->client; + int device_type; + unsigned char device_type1, device_type2; + + device_type = i2c_smbus_read_word_data(client, FSA9485_REG_DEV_T1); + if (device_type < 0) { + dev_err(&client->dev, "%s: err %d ", __func__, device_type); + return (ssize_t)device_type; + } + device_type1 = device_type & 0xff; + device_type2 = device_type >> 8; + + if (device_type1 & DEV_T1_USB_MASK || device_type2 & DEV_T2_USB_MASK) + return snprintf(buf, 22, "USB_STATE_CONFIGURED\n"); + + return snprintf(buf, 25, "USB_STATE_NOTCONFIGURED\n"); +} + +static ssize_t fsa9485_show_adc(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fsa9485_usbsw *usbsw = dev_get_drvdata(dev); + struct i2c_client *client = usbsw->client; + int adc; + + adc = i2c_smbus_read_byte_data(client, FSA9485_REG_ADC); + if (adc < 0) { + dev_err(&client->dev, + "%s: err at read adc %d\n", __func__, adc); + return snprintf(buf, 9, "UNKNOWN\n"); + } + + return snprintf(buf, 4, "%x\n", adc); +} + +static ssize_t fsa9485_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fsa9485_usbsw *usbsw = dev_get_drvdata(dev); + struct i2c_client *client = usbsw->client; + int ret; + + if (!strncmp(buf, "1", 1)) { + dev_info(&client->dev, "fsa9480 reset after delay 1000 msec.\n"); + mdelay(1000); + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANUAL_OVERRIDES1, 0x01); + if (ret < 0) + dev_err(&client->dev, + "cannot soft reset, err %d\n", ret); + + dev_info(&client->dev, "fsa9480_reset_control done!\n"); + } else { + dev_info(&client->dev, + "fsa9480_reset_control, but not reset_value!\n"); + } + + fsa9485_reg_init(usbsw); + + return count; +} + + +static DEVICE_ATTR(control, S_IRUGO, fsa9485_show_control, NULL); +static DEVICE_ATTR(device_type, S_IRUGO, fsa9485_show_device_type, NULL); +static DEVICE_ATTR(switch, S_IRUGO | S_IWUSR, + fsa9485_show_manualsw, fsa9485_set_manualsw); +static DEVICE_ATTR(usb_state, S_IRUGO, fsa9480_show_usb_state, NULL); +static DEVICE_ATTR(adc, S_IRUGO, fsa9485_show_adc, NULL); +static DEVICE_ATTR(reset_switch, S_IWUSR | S_IWGRP, NULL, fsa9485_reset); + +static struct attribute *fsa9485_attributes[] = { + &dev_attr_control.attr, + &dev_attr_device_type.attr, + &dev_attr_switch.attr, + NULL +}; + +static const struct attribute_group fsa9485_group = { + .attrs = fsa9485_attributes, +}; + +void fsa9485_otg_detach(void) +{ + unsigned int data = 0; + int ret; + struct i2c_client *client = local_usbsw->client; + + if (local_usbsw->dev1 & DEV_USB_OTG) { + dev_info(&client->dev, "%s: real device\n", __func__); + data = 0x00; + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW2, data); + if (ret < 0) + dev_info(&client->dev, "%s: err %d\n", __func__, ret); + data = SW_ALL_OPEN; + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, data); + if (ret < 0) + dev_info(&client->dev, "%s: err %d\n", __func__, ret); + + data = 0x1A; + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, data); + if (ret < 0) + dev_info(&client->dev, "%s: err %d\n", __func__, ret); + } else + dev_info(&client->dev, "%s: not real device\n", __func__); +} +EXPORT_SYMBOL(fsa9485_otg_detach); + + +void fsa9485_manual_switching(int path) +{ + struct i2c_client *client = local_usbsw->client; + int value, ret; + unsigned int data = 0; + + value = i2c_smbus_read_byte_data(client, FSA9485_REG_CTRL); + if (value < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, value); + + if ((value & ~CON_MANUAL_SW) != + (CON_SWITCH_OPEN | CON_RAW_DATA | CON_WAIT)) + return; + + if (path == SWITCH_PORT_VAUDIO) { + data = SW_VAUDIO; + value &= ~CON_MANUAL_SW; + } else if (path == SWITCH_PORT_UART) { + data = SW_UART; + value &= ~CON_MANUAL_SW; + } else if (path == SWITCH_PORT_AUDIO) { + data = SW_AUDIO; + value &= ~CON_MANUAL_SW; + } else if (path == SWITCH_PORT_USB) { + data = SW_DHOST; + value &= ~CON_MANUAL_SW; + } else if (path == SWITCH_PORT_AUTO) { + data = SW_AUTO; + value |= CON_MANUAL_SW; + } else if (path == SWITCH_PORT_USB_OPEN) { + data = SW_USB_OPEN; + value &= ~CON_MANUAL_SW; + } else if (path == SWITCH_PORT_ALL_OPEN) { + data = SW_ALL_OPEN; + value &= ~CON_MANUAL_SW; + } else { + pr_info("%s: wrong path (%d)\n", __func__, path); + return; + } + + local_usbsw->mansw = data; + + /* path for FTM sleep */ + if (path == SWITCH_PORT_ALL_OPEN) { + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANUAL_OVERRIDES1, 0x0a); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, data); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW2, data); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, value); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + } else { + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, data); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, value); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + } + +} +EXPORT_SYMBOL(fsa9485_manual_switching); + +static int fsa9485_detect_dev(struct fsa9485_usbsw *usbsw) +{ + int device_type, ret; + unsigned int val1, val2, adc; + struct fsa9485_platform_data *pdata = usbsw->pdata; + struct i2c_client *client = usbsw->client; +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + u8 mhl_ret = 0; +#endif + device_type = i2c_smbus_read_word_data(client, FSA9485_REG_DEV_T1); + if (device_type < 0) { + dev_err(&client->dev, "%s: err %d\n", __func__, device_type); + return device_type; + } + val1 = device_type & 0xff; + val2 = device_type >> 8; + adc = i2c_smbus_read_byte_data(client, FSA9485_REG_ADC); + + if (usbsw->dock_attached) + pdata->dock_cb(FSA9485_DETACHED_DOCK); + + if (adc == 0x10) + val2 = DEV_SMARTDOCK; + else if (adc == 0x12) + val2 = DEV_AUDIO_DOCK; + + dev_info(&client->dev, "dev1: 0x%x, dev2: 0x%x adc : 0x%x\n", val1, val2, adc); + + /* Attached */ + if (val1 || val2) { + /* USB */ + if (val1 & DEV_USB || val2 & DEV_T2_USB_MASK) { + dev_info(&client->dev, "usb connect\n"); + + if (pdata->usb_cb) + pdata->usb_cb(FSA9485_ATTACHED); + if (usbsw->mansw) { + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, usbsw->mansw); + + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + } + /* USB_CDP */ + } else if (val1 & DEV_USB_CHG) { + dev_info(&client->dev, "usb_cdp connect\n"); + + if (pdata->usb_cdp_cb) + pdata->usb_cdp_cb(FSA9485_ATTACHED); + if (usbsw->mansw) { + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, usbsw->mansw); + + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + } + + /* UART */ + } else if (val1 & DEV_T1_UART_MASK || val2 & DEV_T2_UART_MASK) { + uart_connecting = 1; + dev_info(&client->dev, "uart connect\n"); + i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, 0x1E); + if (pdata->uart_cb) + pdata->uart_cb(FSA9485_ATTACHED); + + if (usbsw->mansw) { + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, SW_UART); + + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + } + /* CHARGER */ + } else if (val1 & DEV_T1_CHARGER_MASK) { + dev_info(&client->dev, "charger connect\n"); + + if (pdata->charger_cb) + pdata->charger_cb(FSA9485_ATTACHED); + /* for SAMSUNG OTG */ + } else if (val1 & DEV_USB_OTG) { + dev_info(&client->dev, "otg connect\n"); + if (pdata->otg_cb) + pdata->otg_cb(FSA9485_ATTACHED); + i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, 0x27); + i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW2, 0x02); + msleep(50); + i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, 0x1a); + /* JIG */ + } else if (val2 & DEV_T2_JIG_MASK) { + dev_info(&client->dev, "jig connect\n"); + + if (pdata->jig_cb) + pdata->jig_cb(FSA9485_ATTACHED); + /* Desk Dock */ + } else if (val2 & DEV_AV) { + if ((adc & 0x1F) == ADC_DESKDOCK) { + pr_info("FSA Deskdock Attach\n"); + FSA9485_CheckAndHookAudioDock(1); + usbsw->deskdock = 1; +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + isDeskdockconnected = 1; +#endif + i2c_smbus_write_byte_data(client, + FSA9485_REG_RESERVED_20, 0x08); + } else { + pr_info("FSA MHL Attach\n"); + i2c_smbus_write_byte_data(client, + FSA9485_REG_RESERVED_20, 0x08); +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + DisableFSA9480Interrupts(); + if (!isDeskdockconnected) + mhl_ret = mhl_onoff_ex(1); + + if (mhl_ret != MHL_DEVICE && + (adc & 0x1F) == 0x1A) { + FSA9485_CheckAndHookAudioDock(1); + isDeskdockconnected = 1; + } + EnableFSA9480Interrupts(); +#else + pr_info("FSA mhl attach, but not support MHL feature!\n"); +#endif + } + /* Car Dock */ + } else if (val2 & DEV_JIG_UART_ON) { + if (pdata->dock_cb) + pdata->dock_cb(FSA9485_ATTACHED_CAR_DOCK); + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, SW_AUDIO); + + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_read_byte_data(client, + FSA9485_REG_CTRL); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, ret & ~CON_MANUAL_SW); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + usbsw->dock_attached = FSA9485_ATTACHED; + /* SmartDock */ + } else if (val2 & DEV_SMARTDOCK) { + usbsw->adc = adc; + dev_info(&client->dev, "smart dock connect\n"); + + usbsw->mansw = SW_DHOST; + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, SW_DHOST); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + ret = i2c_smbus_read_byte_data(client, + FSA9485_REG_CTRL); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, ret & ~CON_MANUAL_SW); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + + if (pdata->smartdock_cb) + pdata->smartdock_cb(FSA9485_ATTACHED); +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + mhl_onoff_ex(1); +#endif + } else if (val2 & DEV_AUDIO_DOCK) { + usbsw->adc = adc; + dev_info(&client->dev, "audio dock connect\n"); + + usbsw->mansw = SW_DHOST; + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_MANSW1, SW_DHOST); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + ret = i2c_smbus_read_byte_data(client, + FSA9485_REG_CTRL); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, ret & ~CON_MANUAL_SW); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + + if (pdata->smartdock_cb) + pdata->audio_dock_cb(FSA9485_ATTACHED); + } + /* Detached */ + } else { + /* USB */ + if (usbsw->dev1 & DEV_USB || + usbsw->dev2 & DEV_T2_USB_MASK) { + if (pdata->usb_cb) + pdata->usb_cb(FSA9485_DETACHED); + } else if (usbsw->dev1 & DEV_USB_CHG) { + if (pdata->usb_cdp_cb) + pdata->usb_cdp_cb(FSA9485_DETACHED); + + /* UART */ + } else if (usbsw->dev1 & DEV_T1_UART_MASK || + usbsw->dev2 & DEV_T2_UART_MASK) { + if (pdata->uart_cb) + pdata->uart_cb(FSA9485_DETACHED); + uart_connecting = 0; + dev_info(&client->dev, "[FSA9485] uart disconnect\n"); + + /* CHARGER */ + } else if (usbsw->dev1 & DEV_T1_CHARGER_MASK) { + if (pdata->charger_cb) + pdata->charger_cb(FSA9485_DETACHED); + /* for SAMSUNG OTG */ + } else if (usbsw->dev1 & DEV_USB_OTG) { + i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, 0x1E); + /* JIG */ + } else if (usbsw->dev2 & DEV_T2_JIG_MASK) { + if (pdata->jig_cb) + pdata->jig_cb(FSA9485_DETACHED); + /* Desk Dock */ + } else if (usbsw->dev2 & DEV_AV) { + + pr_info("FSA MHL Detach\n"); + i2c_smbus_write_byte_data(client, + FSA9485_REG_RESERVED_20, 0x04); +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + if (isDeskdockconnected) + FSA9485_CheckAndHookAudioDock(0); +#if defined CONFIG_MHL_D3_SUPPORT + mhl_onoff_ex(false); + detached_status = 1; +#endif + isDeskdockconnected = 0; +#else + if (usbsw->deskdock) { + FSA9485_CheckAndHookAudioDock(0); + usbsw->deskdock = 0; + } else { + pr_info("FSA detach mhl cable, but not support MHL feature\n"); + } +#endif + /* Car Dock */ + } else if (usbsw->dev2 & DEV_JIG_UART_ON) { + if (pdata->dock_cb) + pdata->dock_cb(FSA9485_DETACHED_DOCK); + ret = i2c_smbus_read_byte_data(client, + FSA9485_REG_CTRL); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, + ret | CON_MANUAL_SW); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + usbsw->dock_attached = FSA9485_DETACHED; + } else if (usbsw->adc == 0x10) { + dev_info(&client->dev, "smart dock disconnect\n"); + + ret = i2c_smbus_read_byte_data(client, + FSA9485_REG_CTRL); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, + ret | CON_MANUAL_SW); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + + if (pdata->smartdock_cb) + pdata->smartdock_cb(FSA9485_DETACHED); + usbsw->adc = 0; +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) + mhl_onoff_ex(false); +#endif + } else if (usbsw->adc == 0x12) { + dev_info(&client->dev, "audio dock disconnect\n"); + + ret = i2c_smbus_read_byte_data(client, + FSA9485_REG_CTRL); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + ret = i2c_smbus_write_byte_data(client, + FSA9485_REG_CTRL, + ret | CON_MANUAL_SW); + if (ret < 0) + dev_err(&client->dev, + "%s: err %d\n", __func__, ret); + + if (pdata->smartdock_cb) + pdata->audio_dock_cb(FSA9485_DETACHED); + usbsw->adc = 0; + } + + } + usbsw->dev1 = val1; + usbsw->dev2 = val2; + + return adc; +} + +static int fsa9485_check_dev(struct fsa9485_usbsw *usbsw) +{ + struct i2c_client *client = usbsw->client; + int device_type; + device_type = i2c_smbus_read_word_data(client, FSA9485_REG_DEV_T1); + if (device_type < 0) { + dev_err(&client->dev, "%s: err %d\n", __func__, device_type); + return 0; + } + return device_type; +} + +static int fsa9485_handle_dock_vol_key(struct fsa9485_usbsw *info, int adc) +{ + struct input_dev *input = info->input; + int pre_key = info->previous_key; + unsigned int code=0; + int state=0; + + if (adc == ADC_OPEN) { + switch (pre_key) { + case DOCK_KEY_VOL_UP_PRESSED: + code = KEY_VOLUMEUP; + state = 0; + info->previous_key = DOCK_KEY_VOL_UP_RELEASED; + break; + case DOCK_KEY_VOL_DOWN_PRESSED: + code = KEY_VOLUMEDOWN; + state = 0; + info->previous_key = DOCK_KEY_VOL_DOWN_RELEASED; + break; + case DOCK_KEY_PREV_PRESSED: + code = KEY_PREVIOUSSONG; + state = 0; + info->previous_key = DOCK_KEY_PREV_RELEASED; + break; + case DOCK_KEY_PLAY_PAUSE_PRESSED: + code = KEY_PLAYPAUSE; + state = 0; + info->previous_key = DOCK_KEY_PLAY_PAUSE_RELEASED; + break; + case DOCK_KEY_NEXT_PRESSED: + code = KEY_NEXTSONG; + state = 0; + info->previous_key = DOCK_KEY_NEXT_RELEASED; + break; + default: + return 0; + } + input_event(input, EV_KEY, code, state); + input_sync(input); + return 0; + } + + if (pre_key == DOCK_KEY_NONE) { + if (adc != ADC_DOCK_VOL_UP && adc != ADC_DOCK_VOL_DN + && adc != ADC_DOCK_PREV_KEY && adc != ADC_DOCK_NEXT_KEY + && adc != ADC_DOCK_PLAY_PAUSE_KEY) + return 0; + } + + + switch (adc) { + case ADC_DOCK_VOL_UP: + code = KEY_VOLUMEUP; + state = 1; + info->previous_key = DOCK_KEY_VOL_UP_PRESSED; + break; + case ADC_DOCK_VOL_DN: + code = KEY_VOLUMEDOWN; + state = 1; + info->previous_key = DOCK_KEY_VOL_DOWN_PRESSED; + break; + case ADC_DOCK_PREV_KEY-1 ... ADC_DOCK_PREV_KEY+1: + code = KEY_PREVIOUSSONG; + state = 1; + info->previous_key = DOCK_KEY_PREV_PRESSED; + break; + case ADC_DOCK_PLAY_PAUSE_KEY-1 ... ADC_DOCK_PLAY_PAUSE_KEY+1: + code = KEY_PLAYPAUSE; + state = 1; + info->previous_key = DOCK_KEY_PLAY_PAUSE_PRESSED; + break; + case ADC_DOCK_NEXT_KEY-1 ... ADC_DOCK_NEXT_KEY+1: + code = KEY_NEXTSONG; + state = 1; + info->previous_key = DOCK_KEY_NEXT_PRESSED; + break; + case ADC_DESKDOCK: + if (pre_key == DOCK_KEY_VOL_UP_PRESSED) { + code = KEY_VOLUMEUP; + state = 0; + info->previous_key = DOCK_KEY_VOL_UP_RELEASED; + } else if (pre_key == DOCK_KEY_VOL_DOWN_PRESSED) { + code = KEY_VOLUMEDOWN; + state = 0; + info->previous_key = DOCK_KEY_VOL_DOWN_RELEASED; + } else if (pre_key == DOCK_KEY_PREV_PRESSED) { + code = KEY_PREVIOUSSONG; + state = 0; + info->previous_key = DOCK_KEY_PREV_RELEASED; + } else if (pre_key == DOCK_KEY_PLAY_PAUSE_PRESSED) { + code = KEY_PLAYPAUSE; + state = 0; + info->previous_key = DOCK_KEY_PLAY_PAUSE_RELEASED; + } else if (pre_key == DOCK_KEY_NEXT_PRESSED) { + code = KEY_NEXTSONG; + state = 0; + info->previous_key = DOCK_KEY_NEXT_RELEASED; + } else { + return 0; + } + break; + default: + break; + return 0; + } + + input_event(input, EV_KEY, code, state); + input_sync(input); + + return 1; +} + +static irqreturn_t fsa9485_irq_thread(int irq, void *data) +{ + struct fsa9485_usbsw *usbsw = data; + struct i2c_client *client = usbsw->client; + int intr, intr2, detect; + + /* FSA9485 : Read interrupt -> Read Device + FSA9485 : Read Device -> Read interrupt */ + + pr_info("fsa9485_irq_thread is called\n"); + /* device detection */ + mutex_lock(&usbsw->mutex); + detect = fsa9485_detect_dev(usbsw); + mutex_unlock(&usbsw->mutex); + pr_info("%s: detect dev_adc: %x\n", __func__, detect); + + /* read and clear interrupt status bits */ + intr = i2c_smbus_read_word_data(client, FSA9485_REG_INT1); + dev_info(&client->dev, "%s: intr : 0x%x intr2 : 0x%x\n", + __func__, intr & 0xff, intr >> 8); + intr2 = intr >> 8; + + if (intr < 0) { + msleep(100); + dev_err(&client->dev, "%s: err %d\n", __func__, intr); + intr = i2c_smbus_read_word_data(client, FSA9485_REG_INT1); + if (intr < 0) + dev_err(&client->dev, + "%s: err at read %d\n", __func__, intr); + fsa9485_reg_init(usbsw); + return IRQ_HANDLED; + } else if (intr == 0) { + /* interrupt was fired, but no status bits were set, + so device was reset. In this case, the registers were + reset to defaults so they need to be reinitialised. */ + fsa9485_reg_init(usbsw); + } + /* ADC_value(key pressed) changed at AV_Dock.*/ + if (intr2) { + if (intr2 & 0x4) { /* for adc change */ + fsa9485_handle_dock_vol_key(usbsw, detect); + dev_info(&client->dev, + "intr2: 0x%x, adc_val: %x\n", + intr2, detect); + } else if (intr2 & 0x2) { /* for smart dock */ + i2c_smbus_read_word_data(client, FSA9485_REG_INT1); + + } else if (intr2 & 0x1) { /* for av change (desk dock, hdmi) */ + dev_info(&client->dev, + "%s enter Av charing\n", __func__); + fsa9485_detect_dev(usbsw); + } else { + dev_info(&client->dev, + "%s intr2 but, nothing happend, intr2: 0x%x\n", + __func__, intr2); + } + return IRQ_HANDLED; + } + + return IRQ_HANDLED; +} + +static int fsa9485_irq_init(struct fsa9485_usbsw *usbsw) +{ + struct i2c_client *client = usbsw->client; + int ret; + + if (client->irq) { + ret = request_threaded_irq(client->irq, NULL, + fsa9485_irq_thread, IRQF_TRIGGER_FALLING, + "fsa9485 micro USB", usbsw); + if (ret) { + dev_err(&client->dev, "failed to reqeust IRQ\n"); + return ret; + } + + ret = enable_irq_wake(client->irq); + if (ret < 0) + dev_err(&client->dev, + "failed to enable wakeup src %d\n", ret); + } + + return 0; +} + +static void fsa9485_init_detect(struct work_struct *work) +{ + struct fsa9485_usbsw *usbsw = container_of(work, + struct fsa9485_usbsw, init_work.work); + int ret = 0; + + dev_info(&usbsw->client->dev, "%s\n", __func__); + + mutex_lock(&usbsw->mutex); + fsa9485_detect_dev(usbsw); + mutex_unlock(&usbsw->mutex); + + ret = fsa9485_irq_init(usbsw); + if (ret) + dev_info(&usbsw->client->dev, + "failed to enable irq init %s\n", __func__); +} + +static int __devinit fsa9485_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct fsa9485_usbsw *usbsw; + int ret = 0; + struct input_dev *input; + struct device *switch_dev; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + input = input_allocate_device(); + usbsw = kzalloc(sizeof(struct fsa9485_usbsw), GFP_KERNEL); + if (!usbsw || !input) { + dev_err(&client->dev, "failed to allocate driver data\n"); + kfree(usbsw); + return -ENOMEM; + } + + usbsw->input = input; + input->name = client->name; + input->phys = "deskdock-key/input0"; + input->dev.parent = &client->dev; + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0001; + + /* Enable auto repeat feature of Linux input subsystem */ + __set_bit(EV_REP, input->evbit); + + input_set_capability(input, EV_KEY, KEY_VOLUMEUP); + input_set_capability(input, EV_KEY, KEY_VOLUMEDOWN); + input_set_capability(input, EV_KEY, KEY_PLAYPAUSE); + input_set_capability(input, EV_KEY, KEY_PREVIOUSSONG); + input_set_capability(input, EV_KEY, KEY_NEXTSONG); + + ret = input_register_device(input); + if (ret) { + dev_err(&client->dev, + "input_register_device %s: err %d\n", __func__, ret); + input_free_device(input); + kfree(usbsw); + return ret; + } + + usbsw->client = client; + usbsw->pdata = client->dev.platform_data; + if (!usbsw->pdata) + goto fail1; + + i2c_set_clientdata(client, usbsw); + + mutex_init(&usbsw->mutex); + + local_usbsw = usbsw; + + if (usbsw->pdata->cfg_gpio) + usbsw->pdata->cfg_gpio(); + + fsa9485_reg_init(usbsw); + + uart_connecting = 0; + + ret = sysfs_create_group(&client->dev.kobj, &fsa9485_group); + if (ret) { + dev_err(&client->dev, + "failed to create fsa9485 attribute group\n"); + goto fail2; + } + + /* make sysfs node /sys/class/sec/switch/usb_state */ + switch_dev = device_create(sec_class, NULL, 0, NULL, "switch"); + if (IS_ERR(switch_dev)) { + pr_err("[FSA9485] Failed to create device (switch_dev)!\n"); + ret = PTR_ERR(switch_dev); + goto fail2; + } + + ret = device_create_file(switch_dev, &dev_attr_usb_state); + if (ret < 0) { + pr_err("[FSA9485] Failed to create file (usb_state)!\n"); + goto err_create_file_state; + } + + ret = device_create_file(switch_dev, &dev_attr_adc); + if (ret < 0) { + pr_err("[FSA9485] Failed to create file (adc)!\n"); + goto err_create_file_adc; + } + + ret = device_create_file(switch_dev, &dev_attr_reset_switch); + if (ret < 0) { + pr_err("[FSA9485] Failed to create file (reset_switch)!\n"); + goto err_create_file_reset_switch; + } + + dev_set_drvdata(switch_dev, usbsw); + /* fsa9485 dock init*/ + if (usbsw->pdata->dock_init) + usbsw->pdata->dock_init(); + + /* fsa9485 reset */ + if (usbsw->pdata->reset_cb) + usbsw->pdata->reset_cb(); + + /* set fsa9485 init flag. */ + if (usbsw->pdata->set_init_flag) + usbsw->pdata->set_init_flag(); + + /* initial cable detection */ + INIT_DELAYED_WORK(&usbsw->init_work, fsa9485_init_detect); + schedule_delayed_work(&usbsw->init_work, msecs_to_jiffies(2700)); + + return 0; + +err_create_file_reset_switch: + device_remove_file(switch_dev, &dev_attr_reset_switch); +err_create_file_adc: + device_remove_file(switch_dev, &dev_attr_adc); +err_create_file_state: + device_remove_file(switch_dev, &dev_attr_usb_state); +fail2: + if (client->irq) + free_irq(client->irq, usbsw); +fail1: + input_unregister_device(input); + mutex_destroy(&usbsw->mutex); + i2c_set_clientdata(client, NULL); + kfree(usbsw); + return ret; +} + +static int __devexit fsa9485_remove(struct i2c_client *client) +{ + struct fsa9485_usbsw *usbsw = i2c_get_clientdata(client); + + cancel_delayed_work(&usbsw->init_work); + if (client->irq) { + disable_irq_wake(client->irq); + free_irq(client->irq, usbsw); + } + mutex_destroy(&usbsw->mutex); + i2c_set_clientdata(client, NULL); + + sysfs_remove_group(&client->dev.kobj, &fsa9485_group); + kfree(usbsw); + return 0; +} + +static int fsa9485_resume(struct i2c_client *client) +{ + struct fsa9485_usbsw *usbsw = i2c_get_clientdata(client); + +/* add for fsa9485_irq_thread i2c error during wakeup */ + fsa9485_check_dev(usbsw); + + i2c_smbus_read_byte_data(client, FSA9485_REG_INT1); + + /* device detection */ + mutex_lock(&usbsw->mutex); + fsa9485_detect_dev(usbsw); + mutex_unlock(&usbsw->mutex); + + return 0; +} + + +static const struct i2c_device_id fsa9485_id[] = { + {"fsa9485", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, fsa9485_id); + +static struct i2c_driver fsa9485_i2c_driver = { + .driver = { + .name = "fsa9485", + }, + .probe = fsa9485_probe, + .remove = __devexit_p(fsa9485_remove), + .resume = fsa9485_resume, + .id_table = fsa9485_id, +}; + +static int __init fsa9485_init(void) +{ + return i2c_add_driver(&fsa9485_i2c_driver); +} +module_init(fsa9485_init); + +static void __exit fsa9485_exit(void) +{ + i2c_del_driver(&fsa9485_i2c_driver); +} +module_exit(fsa9485_exit); + +MODULE_AUTHOR("Minkyu Kang "); +MODULE_DESCRIPTION("FSA9485 USB Switch driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/inv_mpu/Kconfig b/drivers/misc/inv_mpu/Kconfig new file mode 100644 index 00000000000..f9e8297f7a3 --- /dev/null +++ b/drivers/misc/inv_mpu/Kconfig @@ -0,0 +1,78 @@ +config MPU_SENSORS_TIMERIRQ_411 + tristate "MPU Timer IRQ" + help + If you say yes here you get access to the timerirq device handle which + can be used to select on. This can be used instead of IRQ's, sleeping, + or timer threads. Reading from this device returns the same type of + information as reading from the MPU and slave IRQ's. + +menuconfig: INV_SENSORS_411 + tristate "Motion Processing Unit" + depends on I2C + default y + +if INV_SENSORS_411 + +choice + prompt "MPU Master" + depends on I2C && INV_SENSORS_411 + default MPU_SENSORS_MPU3050_411 + +config MPU_SENSORS_MPU3050_411 + bool "MPU3050" + depends on I2C + select MPU_SENSORS_MPU3050_GYRO + help + If you say yes here you get support for the MPU3050 Gyroscope driver + This driver can also be built as a module. + If so, the module + will be called mpu3050. + +config MPU_SENSORS_MPU6050A2_411 + bool "MPU6050A2" + depends on I2C + select MPU_SENSORS_MPU6050_GYRO + help + If you say yes here you get support for the MPU6050 Gyroscope driver + This driver can also be built as a module. + If so, the module + will be called mpu6050a2. + +config MPU_SENSORS_MPU6050B1_411 + bool "MPU6050B1" + select MPU_SENSORS_MPU6050_GYRO + depends on I2C + help + If you say yes here you get support for the MPU6050 Gyroscope driver + This driver can also be built as a module. If so, the module + will be called mpu6050b1. + +endchoice + +choice + prompt "Gyroscope Type" + depends on I2C && INV_SENSORS + default MPU_SENSORS_MPU3050_GYRO + +config MPU_SENSORS_MPU3050_GYRO + bool "MPU3050 built in gyroscope" + depends on MPU_SENSORS_MPU3050 + +config MPU_SENSORS_MPU6050_GYRO + bool "MPU6050 built in gyroscope" + depends on MPU_SENSORS_MPU6050B1_411 || MPU_SENSORS_MPU6050A2_411 + +endchoice + +source "drivers/misc/inv_mpu/accel/Kconfig" +source "drivers/misc/inv_mpu/compass/Kconfig" + +config MPU_USERSPACE_DEBUG + bool "MPU Userspace debugging ioctls" + help + Allows the ioctls MPU_SET_MPU_PLATFORM_DATA and + MPU_SET_EXT_SLAVE_PLATFORM_DATA, which allows userspace applications + to override the slave address and orientation. This is dangerous + and could cause the devices not to work. + +endif #INV_SENSORS_411 diff --git a/drivers/misc/inv_mpu/Makefile b/drivers/misc/inv_mpu/Makefile new file mode 100644 index 00000000000..238201e687a --- /dev/null +++ b/drivers/misc/inv_mpu/Makefile @@ -0,0 +1,51 @@ + +# Kernel makefile for motions sensors +# +# + +# MPU +ifdef CONFIG_MPU_SENSORS_MPU3050_411 +INV_MODULE_NAME := mpu3050 +endif + +ifdef CONFIG_MPU_SENSORS_MPU6050A2_411 +INV_MODULE_NAME := mpu6050 +endif + +ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 +INV_MODULE_NAME := mpu6050 +endif + +obj-$(CONFIG_INV_SENSORS_411) += $(INV_MODULE_NAME).o + +$(INV_MODULE_NAME)-objs += mpuirq.o +$(INV_MODULE_NAME)-objs += slaveirq.o +$(INV_MODULE_NAME)-objs += mpu-dev.o +$(INV_MODULE_NAME)-objs += mlsl-kernel.o +$(INV_MODULE_NAME)-objs += mldl_cfg.o +$(INV_MODULE_NAME)-objs += mldl_print_cfg.o + +ifdef CONFIG_INPUT_YAS_MAGNETOMETER +$(INV_MODULE_NAME)-objs += compass/yas530_ext.o +endif + +ifdef CONFIG_MPU_SENSORS_MPU6050A2_411 +$(INV_MODULE_NAME)-objs += accel/mpu6050.o +endif + +ifdef CONFIG_MPU_SENSORS_MPU6050B1_411 +$(INV_MODULE_NAME)-objs += accel/mpu6050.o +endif + +ifdef CONFIG_SENSORS_AK8975 +$(INV_MODULE_NAME)-objs += compass/ak8975.o +endif + +EXTRA_CFLAGS += -Idrivers/misc/inv_mpu +EXTRA_CFLAGS += -D__C99_DESIGNATED_INITIALIZER +EXTRA_CFLAGS += -DINV_CACHE_DMP=1 + +obj-$(CONFIG_MPU_SENSORS_TIMERIRQ_411)+= timerirq.o + +obj-y += accel/ +obj-y += compass/ diff --git a/drivers/misc/inv_mpu/README b/drivers/misc/inv_mpu/README new file mode 100755 index 00000000000..ce592c81ba5 --- /dev/null +++ b/drivers/misc/inv_mpu/README @@ -0,0 +1,104 @@ +Kernel driver mpu +===================== + +Supported chips: + * InvenSense IMU3050 + Prefix: 'mpu3050' + Datasheet: + PS-MPU-3000A-00.2.4b.pdf + +Author: InvenSense + +Description +----------- +The mpu is a motion processor unit that controls the mpu3050 gyroscope, a slave +accelerometer, a compass and a pressure sensor. This document describes how to +install the driver into a Linux kernel. + +Sysfs entries +------------- +/dev/mpu +/dev/mpuirq +/dev/accelirq +/dev/compassirq +/dev/pressureirq + +General Remarks MPU3050 +----------------------- +* Valid addresses for the MPU3050 is 0x68. +* Accelerometer must be on the secondary I2C bus for MPU3050, the + magnetometer must be on the primary bus and pressure sensor must + be on the primary bus. + +Programming the chip using /dev/mpu +---------------------------------- +Programming of MPU3050 is done by first opening the /dev/mpu file and +then performing a series of IOCTLS on the handle returned. The IOCTL codes can +be found in mpu.h. Typically this is done by the mllite library in user +space. + +Board and Platform Data +----------------------- + +In order for the driver to work, board and platform data specific to the device +needs to be added to the board file. A mpu_platform_data structure must +be created and populated and set in the i2c_board_info_structure. For details +of each structure member see mpu.h. All values below are simply an example and +should be modified for your platform. + +#include + +static struct mpu_platform_data mpu3050_data = { + .int_config = 0x10, + .orientation = { -1, 0, 0, + 0, 1, 0, + 0, 0, -1 }, +}; + +/* accel */ +static struct ext_slave_platform_data inv_mpu_kxtf9_data = { + .bus = EXT_SLAVE_BUS_SECONDARY, + .orientation = { -1, 0, 0, + 0, 1, 0, + 0, 0, -1 }, +}; +/* compass */ +static struct ext_slave_platform_data inv_mpu_ak8975_data = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = { 1, 0, 0, + 0, 1, 0, + 0, 0, 1 }, +}; + +static struct i2c_board_info __initdata panda_inv_mpu_i2c4_boardinfo[] = { + { + I2C_BOARD_INFO("mpu3050", 0x68), + .irq = (IH_GPIO_BASE + MPUIRQ_GPIO), + .platform_data = &mpu3050_data, + }, + { + I2C_BOARD_INFO("kxtf9", 0x0F), + .irq = (IH_GPIO_BASE + ACCEL_IRQ_GPIO), + .platform_data = &inv_mpu_kxtf9_data + }, + { + I2C_BOARD_INFO("ak8975", 0x0E), + .irq = (IH_GPIO_BASE + COMPASS_IRQ_GPIO), + .platform_data = &inv_mpu_ak8975_data, + }, +}; + +Typically the IRQ is a GPIO input pin and needs to be configured properly. If +in the above example GPIO 168 corresponds to IRQ 299, the following should be +done as well: + +#define MPU_GPIO_IRQ 168 + + gpio_request(MPU_GPIO_IRQ,"MPUIRQ"); + gpio_direction_input(MPU_GPIO_IRQ) + +Dynamic Debug +============= + +The mpu3050 makes use of dynamic debug. For details on how to use this +refer to Documentation/dynamic-debug-howto.txt diff --git a/drivers/misc/inv_mpu/accel/Kconfig b/drivers/misc/inv_mpu/accel/Kconfig new file mode 100644 index 00000000000..a0144813a79 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/Kconfig @@ -0,0 +1,133 @@ +menuconfig INV_SENSORS_ACCELEROMETERS + bool "Accelerometer Slave Sensors" + default y + ---help--- + Say Y here to get to see options for device drivers for various + accelerometrs for integration with the MPU3050 or MPU6050 driver. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if INV_SENSORS_ACCELEROMETERS + +config MPU_SENSORS_ADXL34X_411 + tristate "ADI adxl34x" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the ADI adxl345 or adxl346 accelerometers. + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_BMA222_411 + tristate "Bosch BMA222" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Bosch BMA222 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_BMA150_411 + tristate "Bosch BMA150" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Bosch BMA150 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_BMA250_411 + tristate "Bosch BMA250" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Bosch BMA250 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_KXSD9_411 + tristate "Kionix KXSD9" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Kionix KXSD9 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_KXTF9_411 + tristate "Kionix KXTF9" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Kionix KXFT9 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_LIS331DLH_411 + tristate "ST lis331dlh" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the ST lis331dlh accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_LIS3DH_411 + tristate "ST lis3dh" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the ST lis3dh accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_LSM303DLX_A_411 + tristate "ST lsm303dlx" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the ST lsm303dlh and lsm303dlm accelerometers + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_MMA8450_411 + tristate "Freescale mma8450" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Freescale mma8450 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_MMA845X_411 + tristate "Freescale mma8451/8452/8453" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Freescale mma8451/8452/8453 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_MPU6050_ACCEL_411 + tristate "MPU6050 built in accelerometer" + depends on MPU_SENSORS_MPU6050B1_411 || MPU_SENSORS_MPU6050A2_411 + help + This enables support for the MPU6050 built in accelerometer. + This the built in support for integration with the MPU6050 gyroscope + device driver. This is the only accelerometer supported with the + MPU6050. Specifying another accelerometer in the board file will + result in runtime errors. + +endif diff --git a/drivers/misc/inv_mpu/accel/Makefile b/drivers/misc/inv_mpu/accel/Makefile new file mode 100644 index 00000000000..293326aced5 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/Makefile @@ -0,0 +1,38 @@ +# +# Accel Slaves to MPUxxxx +# +obj-$(CONFIG_MPU_SENSORS_ADXL34X_411) += inv_mpu_adxl34x.o +inv_mpu_adxl34x-objs += adxl34x.o + +obj-$(CONFIG_MPU_SENSORS_BMA150_411) += inv_mpu_bma150.o +inv_mpu_bma150-objs += bma150.o + +obj-$(CONFIG_MPU_SENSORS_KXTF9_411) += inv_mpu_kxtf9.o +inv_mpu_kxtf9-objs += kxtf9.o + +obj-$(CONFIG_MPU_SENSORS_BMA222_411) += inv_mpu_bma222.o +inv_mpu_bma222-objs += bma222.o + +obj-$(CONFIG_MPU_SENSORS_BMA250_411) += inv_mpu_bma250.o +inv_mpu_bma250-objs += bma250.o + +obj-$(CONFIG_MPU_SENSORS_KXSD9_411) += inv_mpu_kxsd9.o +inv_mpu_kxsd9-objs += kxsd9.o + +obj-$(CONFIG_MPU_SENSORS_LIS331DLH_411) += inv_mpu_lis331.o +inv_mpu_lis331-objs += lis331.o + +obj-$(CONFIG_MPU_SENSORS_LIS3DH_411) += inv_mpu_lis3dh.o +inv_mpu_lis3dh-objs += lis3dh.o + +obj-$(CONFIG_MPU_SENSORS_LSM303DLX_A_411) += inv_mpu_lsm303dlx_a.o +inv_mpu_lsm303dlx_a-objs += lsm303dlx_a.o + +obj-$(CONFIG_MPU_SENSORS_MMA8450_411) += inv_mpu_mma8450.o +inv_mpu_mma8450-objs += mma8450.o + +obj-$(CONFIG_MPU_SENSORS_MMA845X_411) += inv_mpu_mma845x.o +inv_mpu_mma845x-objs += mma845x.o + +EXTRA_CFLAGS += -Idrivers/misc/inv_mpu +EXTRA_CFLAGS += -D__C99_DESIGNATED_INITIALIZER diff --git a/drivers/misc/inv_mpu/accel/mpu6050.c b/drivers/misc/inv_mpu/accel/mpu6050.c new file mode 100644 index 00000000000..2c2fbb7858b --- /dev/null +++ b/drivers/misc/inv_mpu/accel/mpu6050.c @@ -0,0 +1,700 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file mpu6050.c + * @brief Accelerometer setup and handling methods for Invensense MPU6050 + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mpu6050b1.h" +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* -------------------------------------------------------------------------- */ + +struct mpu6050_config { + unsigned int odr; /**< output data rate 1/1000 Hz */ + unsigned int fsr; /**< full scale range mg */ + unsigned int ths; /**< mot/no-mot thseshold mg */ + unsigned int dur; /**< mot/no-mot duration ms */ + unsigned int irq_type; /**< irq type */ +}; + +struct mpu6050_private_data { + struct mpu6050_config suspend; + struct mpu6050_config resume; + struct mldl_cfg *mldl_cfg_ref; +}; + + +static int mpu6050_set_mldl_cfg_ref(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mldl_cfg *mldl_cfg_ref) +{ + struct mpu6050_private_data *private_data = + (struct mpu6050_private_data *)pdata->private_data; + private_data->mldl_cfg_ref = mldl_cfg_ref; + return 0; +} +static int mpu6050_set_lp_mode(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + unsigned char lpa_freq) +{ + unsigned char b = 0; + int result = INV_SUCCESS; + /* Reducing the duration setting for lp mode */ + b = 1; + result |= inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_DUR, b); + /* Setting the cycle bit and LPA wake up freq */ + inv_serial_read(mlsl_handle, pdata->address, MPUREG_PWR_MGMT_1, 1, + &b); + b |= BIT_CYCLE | BIT_PD_PTAT; + result |= inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, + b); + inv_serial_read(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, 1, &b); + b |= lpa_freq & BITS_LPA_WAKE_CTRL; + result |= inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, b); + + return result; +} + +static int mpu6050_set_fp_mode(void *mlsl_handle, + struct ext_slave_platform_data *pdata) +{ + unsigned char b; + int result = INV_SUCCESS; + struct mpu6050_private_data *private_data = + (struct mpu6050_private_data *)pdata->private_data; + /* Resetting the cycle bit and LPA wake up freq */ + inv_serial_read(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, 1, &b); + b &= ~BIT_CYCLE & ~BIT_PD_PTAT; + result |= inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, b); + inv_serial_read(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, 1, &b); + b &= ~BITS_LPA_WAKE_CTRL; + result |= inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, b); + /* Resetting the duration setting for fp mode */ + b = (unsigned char)private_data->suspend.ths / ACCEL_MOT_DUR_LSB; + result |= inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_DUR, b); + + return result; +} +/** + * Record the odr for use in computing duration values. + * + * @param config Config to set, suspend or resume structure + * @param odr output data rate in 1/1000 hz + */ +int mpu6050_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mpu6050_config *config, long apply, long odr) +{ + int result; + unsigned char b; + unsigned char lpa_freq = 1; /* Default value */ + long base; + int total_divider; + struct mpu6050_private_data *private_data = + (struct mpu6050_private_data *)pdata->private_data; + struct mldl_cfg *mldl_cfg_ref = + (struct mldl_cfg *)private_data->mldl_cfg_ref; + + if (mldl_cfg_ref) { + base = 1000 * + inv_mpu_get_sampling_rate_hz(mldl_cfg_ref->mpu_gyro_cfg) + * (mldl_cfg_ref->mpu_gyro_cfg->divider + 1); + } else { + /* have no reference to mldl_cfg => assume base rate is 1000 */ + base = 1000000L; + } + + if (odr != 0) { + total_divider = (base / odr) - 1; + /* final odr MAY be different from requested odr due to + integer truncation */ + config->odr = base / (total_divider + 1); + } else { + config->odr = 0; + return 0; + } + + /* if the DMP and/or gyros are on, don't set the ODR => + the DMP/gyro mldl_cfg->divider setting will handle it */ + if (apply + && (mldl_cfg_ref && + !(mldl_cfg_ref->inv_mpu_cfg->requested_sensors & + INV_DMP_PROCESSOR))) { + MPL_LOGI("mpu6050_set_odr:%d\n", total_divider); + result = inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_SMPLRT_DIV, + (unsigned char)total_divider); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGI("ODR : %d (%d)mHz\n", config->odr, total_divider); + } + /* Decide whether to put accel in LP mode or pull out of LP mode + based on the odr. */ + switch (odr) { + case 1000: + lpa_freq = BITS_LPA_WAKE_1HZ; + break; + case 2000: + lpa_freq = BITS_LPA_WAKE_2HZ; + break; + case 10000: + lpa_freq = BITS_LPA_WAKE_10HZ; + break; + case 40000: + lpa_freq = BITS_LPA_WAKE_40HZ; + break; + default: + inv_serial_read(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, 1, &b); + b &= BIT_CYCLE; + if (b == BIT_CYCLE) { + MPL_LOGI("Accel LP - > FP mode.\n"); + result = mpu6050_set_fp_mode(mlsl_handle, pdata); + if (result) + LOG_RESULT_LOCATION(result); + } + } + /* If lpa_freq default value was changed, set into LP mode */ + if (lpa_freq != 1) { + MPL_LOGI("Accel FP - > LP mode.\n"); + result = mpu6050_set_lp_mode(mlsl_handle, pdata, lpa_freq); + if (result) + LOG_RESULT_LOCATION(result); + } + return 0; +} + +static int mpu6050_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mpu6050_config *config, long apply, long fsr) +{ + unsigned char fsr_mask; + int result; + + if (fsr <= 2000) { + config->fsr = 2000; + fsr_mask = 0x01; + } else if (fsr <= 4000) { + config->fsr = 4000; + fsr_mask = 0x08; + } else if (fsr <= 8000) { + config->fsr = 8000; + fsr_mask = 0x10; + } else { /* fsr = [8001, oo) */ + config->fsr = 16000; + fsr_mask = 0x18; + } + + if (apply) { + unsigned char reg; + result = inv_serial_read(mlsl_handle, pdata->address, + MPUREG_ACCEL_CONFIG, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_CONFIG, + reg | fsr_mask); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGV("FSR: %d\n", config->fsr); + } + return 0; +} + +/* ACCEL IRQ is not used */ +static int mpu6050_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mpu6050_config *config, long apply, + long irq_type) +{ + return 0; +} + +static int mpu6050_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *slave, + struct mpu6050_config *config, long apply, long ths) +{ + if (ths < 0) + ths = 0; + + config->ths = ths; + MPL_LOGV("THS: %d\n", config->ths); + return 0; +} + +static int mpu6050_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *slave, + struct mpu6050_config *config, long apply, long dur) +{ + if (dur < 0) + dur = 0; + + config->dur = dur; + MPL_LOGV("DUR: %d\n", config->dur); + return 0; +} + + +static int mpu6050_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + struct mpu6050_private_data *private_data; + + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->suspend, + false, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, 2000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, 2000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->suspend, + false, MPU_SLAVE_IRQ_TYPE_NONE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->resume, + false, MPU_SLAVE_IRQ_TYPE_NONE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = mpu6050_set_ths(mlsl_handle, pdata, &private_data->suspend, + false, 128); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu6050_set_ths(mlsl_handle, pdata, &private_data->resume, + false, 128); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu6050_set_dur(mlsl_handle, pdata, &private_data->suspend, + false, 2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu6050_set_dur(mlsl_handle, pdata, &private_data->resume, + false, 2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return 0; +} + +static int mpu6050_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + pdata->private_data = NULL; + return 0; +} + +static int mpu6050_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + unsigned char reg; + int result; + struct mpu6050_private_data *private_data = + (struct mpu6050_private_data *)pdata->private_data; + + result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->suspend, + true, private_data->suspend.odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->suspend, + true, private_data->suspend.irq_type); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_read(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reg |= (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return 0; +} + +static int mpu6050_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char reg; + struct mpu6050_private_data *private_data = + (struct mpu6050_private_data *)pdata->private_data; + + struct mldl_cfg *mldl_cfg_ref = + (struct mldl_cfg *)private_data->mldl_cfg_ref; + + result = inv_serial_read(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (reg & BIT_SLEEP) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, reg & ~BIT_SLEEP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + mdelay(2); + + result = inv_serial_read(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reg &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA); + result = inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* settings */ + + /*----- LPF configuration : 44hz ---->*/ + reg = + MPUREG_CONFIG_VALUE(mldl_cfg_ref->mpu_gyro_cfg->ext_sync, + mldl_cfg_ref->mpu_gyro_cfg->lpf); + result = + inv_serial_single_write(mlsl_handle, + mldl_cfg_ref->mpu_chip_info->addr, MPUREG_CONFIG, reg); + /*<----- LPF configuration : 44hz ----*/ + + result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->resume, + true, private_data->resume.fsr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->resume, + true, private_data->resume.odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->resume, + true, private_data->resume.irq_type); + + /* motion, no_motion */ + /* TODO : port these in their respective _set_thrs and _set_dur + functions and use the APPLY paremeter to apply just like + _set_odr, _set_irq, and _set_fsr. */ + reg = (unsigned char)private_data->suspend.ths / ACCEL_MOT_THR_LSB; + result = inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_THR, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reg = (unsigned char) + ACCEL_ZRMOT_THR_LSB_CONVERSION(private_data->resume.ths); + result = inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_ZRMOT_THR, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reg = (unsigned char)private_data->suspend.ths / ACCEL_MOT_DUR_LSB; + result = inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_DUR, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reg = (unsigned char)private_data->resume.ths / ACCEL_ZRMOT_DUR_LSB; + result = inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_ZRMOT_DUR, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return 0; +} + +static int mpu6050_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result; + int x, y, z; + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, data); + + if (slave->read_len == 6) { + x = (s16)((data[0] << 8) | data[1]) - cal_data.x; + y = (s16)((data[2] << 8) | data[3]) - cal_data.y; + z = (s16)((data[4] << 8) | data[5]) - cal_data.z; + + data[0] = (x & 0xff00) >> 8; + data[1] = ((x << 4) >> 4) & 0xff; + data[2] = (y & 0xff00) >> 8; + data[3] = ((y << 4) >> 4) & 0xff; + data[4] = (z & 0xff00) >> 8; + data[5] = ((z << 4) >> 4) & 0xff; +} + + return result; +} + +static int mpu6050_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct mpu6050_private_data *private_data = + (struct mpu6050_private_data *)pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return mpu6050_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return mpu6050_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return mpu6050_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return mpu6050_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return mpu6050_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return mpu6050_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return mpu6050_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return mpu6050_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return mpu6050_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return mpu6050_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_INTERNAL_REFERENCE: + return mpu6050_set_mldl_cfg_ref(mlsl_handle, pdata, + (struct mldl_cfg *)data->data); + break; + + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return 0; +} + +static int mpu6050_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct mpu6050_private_data *private_data = + (struct mpu6050_private_data *)pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_MOT_THS: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.ths; + break; + case MPU_SLAVE_CONFIG_NMOT_THS: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.ths; + break; + case MPU_SLAVE_CONFIG_MOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.dur; + break; + case MPU_SLAVE_CONFIG_NMOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.dur; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.irq_type; + break; + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return 0; +} + +static struct ext_slave_descr mpu6050_descr = { + .init = mpu6050_init, + .exit = mpu6050_exit, + .suspend = mpu6050_suspend, + .resume = mpu6050_resume, + .read = mpu6050_read, + .config = mpu6050_config, + .get_config = mpu6050_get_config, + .name = "mpu6050", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_MPU6050, + .read_reg = 0x3B, + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {2, 0}, + .trigger = NULL, +}; + +struct ext_slave_descr *mpu6050_get_slave_descr(void) +{ + return &mpu6050_descr; +} + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/mpu6050.h b/drivers/misc/inv_mpu/accel/mpu6050.h new file mode 100644 index 00000000000..3d6bcedaa73 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/mpu6050.h @@ -0,0 +1,39 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + + +#ifndef __MPU6050_H__ +#define __MPU6050_H__ + +#include + +struct mpu6050_config { + unsigned int odr; /**< output data rate 1/1000 Hz */ + unsigned int fsr; /**< full scale range mg */ + unsigned int ths; /**< mot/no-mot thseshold mg */ + unsigned int dur; /**< mot/no-mot duration ms */ + unsigned int irq_type; /**< irq type */ +}; + +struct ext_slave_descr *mpu6050_get_slave_descr(void); +extern int mpu6050_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mpu6050_config *config, long apply, long odr); + +#endif diff --git a/drivers/misc/inv_mpu/compass/Kconfig b/drivers/misc/inv_mpu/compass/Kconfig new file mode 100644 index 00000000000..fe701600cfb --- /dev/null +++ b/drivers/misc/inv_mpu/compass/Kconfig @@ -0,0 +1,121 @@ +menuconfig INV_SENSORS_COMPASS + bool "Compass Slave Sensors" + default y + ---help--- + Say Y here to get to see options for device drivers for various + compasses. This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if INV_SENSORS_COMPASS + +config MPU_SENSORS_AK8975_411 + tristate "AKM ak8975" + help + This enables support for the AKM ak8975 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_AK8972_411 + tristate "AKM ak8972" + help + This enables support for the AKM ak8972 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_MMC314X_411 + tristate "MEMSIC mmc314x" + help + This enables support for the MEMSIC mmc314x compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_AMI30X_411 + tristate "Aichi Steel ami30X" + help + This enables support for the Aichi Steel ami304/ami305 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_AMI306_411 + tristate "Aichi Steel ami306" + help + This enables support for the Aichi Steel ami306 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_HMC5883_411 + tristate "Honeywell hmc5883" + help + This enables support for the Honeywell hmc5883 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_LSM303DLX_M_411 + tristate "ST lsm303dlx" + help + This enables support for the ST lsm303dlh and lsm303dlm compasses + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_MMC314XMS_411 + tristate "MEMSIC mmc314xMS" + help + This enables support for the MEMSIC mmc314xMS compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_YAS529_411 + tristate "Yamaha yas529" + depends on INPUT_YAS_MAGNETOMETER + help + This enables support for the Yamaha yas529 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_YAS530_411 + tristate "Yamaha yas530" + help + This enables support for the Yamaha yas530 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_HSCDTD002B_411 + tristate "Alps hscdtd002b" + help + This enables support for the Alps hscdtd002b compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_HSCDTD004A_411 + tristate "Alps hscdtd004a" + help + This enables support for the Alps hscdtd004a compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +endif diff --git a/drivers/misc/inv_mpu/compass/Makefile b/drivers/misc/inv_mpu/compass/Makefile new file mode 100644 index 00000000000..9505d5f30a8 --- /dev/null +++ b/drivers/misc/inv_mpu/compass/Makefile @@ -0,0 +1,38 @@ +# +# Compass Slaves MPUxxxx +# +obj-$(CONFIG_MPU_SENSORS_AMI30X) += inv_mpu_ami30x.o +inv_mpu_ami30x-objs += ami30x.o + +obj-$(CONFIG_MPU_SENSORS_AMI306) += inv_mpu_ami306.o +inv_mpu_ami306-objs += ami306.o + +obj-$(CONFIG_MPU_SENSORS_HMC5883) += inv_mpu_hmc5883.o +inv_mpu_hmc5883-objs += hmc5883.o + +obj-$(CONFIG_MPU_SENSORS_LSM303DLX_M) += inv_mpu_lsm303dlx_m.o +inv_mpu_lsm303dlx_m-objs += lsm303dlx_m.o + +obj-$(CONFIG_MPU_SENSORS_MMC314X) += inv_mpu_mmc314x.o +inv_mpu_mmc314x-objs += mmc314x.o + +obj-$(CONFIG_MPU_SENSORS_YAS529) += inv_mpu_yas529.o +inv_mpu_yas529-objs += yas529-kernel.o + +obj-$(CONFIG_MPU_SENSORS_YAS530_411) += inv_mpu_yas530.o +inv_mpu_yas530-objs += yas530.o + +obj-$(CONFIG_MPU_SENSORS_HSCDTD002B) += inv_mpu_hscdtd002b.o +inv_mpu_hscdtd002b-objs += hscdtd002b.o + +obj-$(CONFIG_MPU_SENSORS_HSCDTD004A) += inv_mpu_hscdtd004a.o +inv_mpu_hscdtd004a-objs += hscdtd004a.o + +obj-$(CONFIG_MPU_SENSORS_AK8975_411) += inv_mpu_ak8975.o +inv_mpu_ak8975-objs += ak8975.o + +obj-$(CONFIG_MPU_SENSORS_AK8972) += inv_mpu_ak8972.o +inv_mpu_ak8972-objs += ak8972.o + +EXTRA_CFLAGS += -Idrivers/misc/inv_mpu +EXTRA_CFLAGS += -D__C99_DESIGNATED_INITIALIZER diff --git a/drivers/misc/inv_mpu/compass/ak8975.c b/drivers/misc/inv_mpu/compass/ak8975.c new file mode 100644 index 00000000000..11d8b46de3d --- /dev/null +++ b/drivers/misc/inv_mpu/compass/ak8975.c @@ -0,0 +1,504 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file ak8975.c + * @brief Magnetometer setup and handling methods for the AKM AK8975, + * AKM AK8975B, and AKM AK8975C compass devices. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ +#define AK8975_REG_ST1 (0x02) +#define AK8975_REG_HXL (0x03) +#define AK8975_REG_ST2 (0x09) + +#define AK8975_REG_CNTL (0x0A) +#define AK8975_REG_ASAX (0x10) +#define AK8975_REG_ASAY (0x11) +#define AK8975_REG_ASAZ (0x12) + +#define AK8975_CNTL_MODE_POWER_DOWN (0x10) +#define AK8975_CNTL_MODE_SINGLE_MEASUREMENT (0x11) +#define AK8975_CNTL_MODE_FUSE_ROM_ACCESS (0x1f) + +/* -------------------------------------------------------------------------- */ +struct ak8975_config { + char asa[COMPASS_NUM_AXES]; /* axis sensitivity adjustment */ +}; + +struct ak8975_private_data { + struct ak8975_config init; +}; + +/* -------------------------------------------------------------------------- */ + +static int ak8975_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char serial_data[COMPASS_NUM_AXES]; + + struct ak8975_private_data *private_data; + private_data = (struct ak8975_private_data *) + kzalloc(sizeof(struct ak8975_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_POWER_DOWN); + if (result) { + LOG_RESULT_LOCATION(result); + kfree(private_data); + return result; + } + /* Wait at least 100us */ + udelay(100); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_FUSE_ROM_ACCESS); + if (result) { + LOG_RESULT_LOCATION(result); + kfree(private_data); + return result; + } + + /* Wait at least 200us */ + udelay(200); + + result = inv_serial_read(mlsl_handle, pdata->address, + AK8975_REG_ASAX, + COMPASS_NUM_AXES, serial_data); + if (result) { + LOG_RESULT_LOCATION(result); + kfree(private_data); + return result; + } + + pdata->private_data = private_data; + + private_data->init.asa[0] = serial_data[0]; + private_data->init.asa[1] = serial_data[1]; + private_data->init.asa[2] = serial_data[2]; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_POWER_DOWN); + if (result) { + LOG_RESULT_LOCATION(result); + kfree(private_data); + return result; + } + + udelay(100); + return INV_SUCCESS; +} + +static int ak8975_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +static int ak8975_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_POWER_DOWN); + mdelay(1); /* wait at least 100us */ + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static int ak8975_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_SINGLE_MEASUREMENT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} +static int ak8975_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, unsigned char *data) +{ + unsigned char regs[8]; + unsigned char *stat = ®s[0]; + unsigned char *stat2 = ®s[7]; + int result = INV_SUCCESS; + int status = INV_SUCCESS; + + result = + inv_serial_read(mlsl_handle, pdata->address, AK8975_REG_ST1, + 8, regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Always return the data and the status registers */ + memcpy(data, ®s[1], 6); + data[6] = regs[0]; + data[7] = regs[7]; + + /* + * ST : data ready - + * Measurement has been completed and data is ready to be read. + */ + if (*stat & 0x01) + status = INV_SUCCESS; + + /* + * ST2 : data error - + * occurs when data read is started outside of a readable period; + * data read would not be correct. + * Valid in continuous measurement mode only. + * In single measurement mode this error should not occour but we + * stil account for it and return an error, since the data would be + * corrupted. + * DERR bit is self-clearing when ST2 register is read. + */ + if (*stat2 & 0x04) + status = INV_ERROR_COMPASS_DATA_ERROR; + /* + * ST2 : overflow - + * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT. + * This is likely to happen in presence of an external magnetic + * disturbance; it indicates, the sensor data is incorrect and should + * be ignored. + * An error is returned. + * HOFL bit clears when a new measurement starts. + */ + if (*stat2 & 0x08) + status = INV_ERROR_COMPASS_DATA_OVERFLOW; + /* + * ST : overrun - + * the previous sample was not fetched and lost. + * Valid in continuous measurement mode only. + * In single measurement mode this error should not occour and we + * don't consider this condition an error. + * DOR bit is self-clearing when ST2 or any meas. data register is + * read. + */ + if (*stat & 0x02) { + /* status = INV_ERROR_COMPASS_DATA_UNDERFLOW; */ + status = INV_SUCCESS; + } + + /* + * trigger next measurement if: + * - stat is non zero; + * - if stat is zero and stat2 is non zero. + * Won't trigger if data is not ready and there was no error. + */ + if (*stat != 0x00 || *stat2 != 0x00) { + result = inv_serial_single_write( + mlsl_handle, pdata->address, + AK8975_REG_CNTL, AK8975_CNTL_MODE_SINGLE_MEASUREMENT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + return status; +} + +static int ak8975_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + int result; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_WRITE_REGISTERS: + result = inv_serial_write(mlsl_handle, pdata->address, + data->len, + (unsigned char *)data->data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + break; + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + case MPU_SLAVE_CONFIG_ODR_RESUME: + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + case MPU_SLAVE_CONFIG_FSR_RESUME: + case MPU_SLAVE_CONFIG_MOT_THS: + case MPU_SLAVE_CONFIG_NMOT_THS: + case MPU_SLAVE_CONFIG_MOT_DUR: + case MPU_SLAVE_CONFIG_NMOT_DUR: + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static int ak8975_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct ak8975_private_data *private_data = pdata->private_data; + int result; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_READ_REGISTERS: + { + unsigned char *serial_data = + (unsigned char *)data->data; + result = + inv_serial_read(mlsl_handle, pdata->address, + serial_data[0], data->len - 1, + &serial_data[1]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + break; + } + case MPU_SLAVE_READ_SCALE: + { + unsigned char *serial_data = + (unsigned char *)data->data; + serial_data[0] = private_data->init.asa[0]; + serial_data[1] = private_data->init.asa[1]; + serial_data[2] = private_data->init.asa[2]; + result = INV_SUCCESS; + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + break; + } + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = 0; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = 8000; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + case MPU_SLAVE_CONFIG_FSR_RESUME: + case MPU_SLAVE_CONFIG_MOT_THS: + case MPU_SLAVE_CONFIG_NMOT_THS: + case MPU_SLAVE_CONFIG_MOT_DUR: + case MPU_SLAVE_CONFIG_NMOT_DUR: + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static struct ext_slave_read_trigger ak8975_read_trigger = { + /*.reg = */ 0x0A, + /*.value = */ 0x01 +}; + +static struct ext_slave_descr ak8975_descr = { + .init = ak8975_init, + .exit = ak8975_exit, + .suspend = ak8975_suspend, + .resume = ak8975_resume, + .read = ak8975_read, + .config = ak8975_config, + .get_config = ak8975_get_config, + .name = "ak8975", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_AK8975, + .read_reg = 0x01, + .read_len = 10, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {9830, 4000}, + .trigger = &ak8975_read_trigger, +}; + +static +struct ext_slave_descr *ak8975_get_slave_descr(void) +{ + return &ak8975_descr; +} + +/* -------------------------------------------------------------------------- */ +struct ak8975_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int ak8975_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct ak8975_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + ak8975_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int ak8975_mod_remove(struct i2c_client *client) +{ + struct ak8975_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + inv_mpu_unregister_slave(client, private_data->pdata, + ak8975_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id ak8975_mod_id[] = { + { "ak8975_mod", COMPASS_ID_AK8975 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ak8975_mod_id); + +static struct i2c_driver ak8975_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = ak8975_mod_probe, + .remove = ak8975_mod_remove, + .id_table = ak8975_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "ak8975_mod", + }, + .address_list = normal_i2c, +}; + +static int __init ak8975_mod_init(void) +{ + int res = i2c_add_driver(&ak8975_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "ak8975_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit ak8975_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&ak8975_mod_driver); +} + +module_init(ak8975_mod_init); +module_exit(ak8975_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate AK8975 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ak8975_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/yas530_ext.c b/drivers/misc/inv_mpu/compass/yas530_ext.c new file mode 100644 index 00000000000..76334d64ae6 --- /dev/null +++ b/drivers/misc/inv_mpu/compass/yas530_ext.c @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include "mpu-dev.h" + +#include "log.h" +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#include "yas530_ext.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +struct yas530_ext_private_data { + int flags; + char offsets[3]; + const int *correction_matrix; +}; + +static int yas530_ext_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + geomagnetic_api_suspend(); + + return result; +} + +static int yas530_ext_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + struct yas530_ext_private_data *private_data = pdata->private_data; + + geomagnetic_api_resume(); + + return result; +} + +static int yas530_ext_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result = INV_SUCCESS; + int raw[3] = {0,}; + int xyz[3] = {0,}; + int accuracy = 0; + int i = 0; + short xyz_scaled[3] = {0,}; + + geomagnetic_api_read(xyz, raw, NULL, &accuracy); + + xyz_scaled[0] = (short)(xyz[0]/100); + xyz_scaled[1] = (short)(xyz[1]/100); + xyz_scaled[2] = (short)(xyz[2]/100); + + data[0] = xyz_scaled[0] >> 8; + data[1] = xyz_scaled[0] & 0xFF; + data[2] = xyz_scaled[1] >> 8; + data[3] = xyz_scaled[1] & 0xFF; + data[4] = xyz_scaled[2] >> 8; + data[5] = xyz_scaled[2] & 0xFF; + data[6] = (unsigned char)accuracy; + + return result; +} + +static int yas530_ext_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + int result = INV_SUCCESS; + struct yas530_private_data *private_data = pdata->private_data; + + return result; +} + + +static int yas530_ext_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + int result = INV_SUCCESS; + struct yas530_ext_private_data *private_data = pdata->private_data; + + switch (data->key) { + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + } + return result; +} + +static int yas530_ext_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + + struct yas530_ext_private_data *private_data; + int result = INV_SUCCESS; + char offset[3] = {0, 0, 0}; + + private_data = (struct yas530_ext_private_data *) + kzalloc(sizeof(struct yas530_ext_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + private_data->correction_matrix = pdata->private_data; + + pdata->private_data = private_data; + + return result; +} + +static int yas530_ext_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +static struct ext_slave_descr yas530_ext_descr = { + .init = yas530_ext_init, + .exit = yas530_ext_exit, + .suspend = yas530_ext_suspend, + .resume = yas530_ext_resume, + .read = yas530_ext_read, + .config = yas530_ext_config, + .get_config = yas530_ext_get_config, + .name = "yas530ext", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_YAS530_EXT, + .read_reg = 0x06, + .read_len = 7, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {3276, 8001}, + .trigger = NULL, +}; + + +struct ext_slave_descr *yas530_ext_get_slave_descr(void) +{ + return &yas530_ext_descr; +} + +/* -------------------------------------------------------------------------- */ +struct yas530_ext_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int yas530_ext_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct yas530_ext_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + yas530_ext_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int yas530_ext_mod_remove(struct i2c_client *client) +{ + struct yas530_ext_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + yas530_ext_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id yas530_ext_mod_id[] = { + { "yas530ext", COMPASS_ID_YAS530_EXT}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, yas530_ext_mod_id); + +static struct i2c_driver yas530_ext_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = yas530_ext_mod_probe, + .remove = yas530_ext_mod_remove, + .id_table = yas530_ext_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "yas530_ext_mod", + }, + .address_list = normal_i2c, +}; + +static int __init yas530_ext_mod_init(void) +{ + int res = i2c_add_driver(&yas530_ext_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "yas530_ext_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit yas530_ext_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&yas530_ext_mod_driver); +} + +module_init(yas530_ext_mod_init); +module_exit(yas530_ext_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate YAS530 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("yas530_ext_mod"); diff --git a/drivers/misc/inv_mpu/compass/yas530_ext.h b/drivers/misc/inv_mpu/compass/yas530_ext.h new file mode 100644 index 00000000000..f1b1678bf8d --- /dev/null +++ b/drivers/misc/inv_mpu/compass/yas530_ext.h @@ -0,0 +1,31 @@ +/* +$License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + + +#ifndef __YAS530_EXT_H__ +#define __YAS530_EXT_H__ + +#include + +struct ext_slave_descr *yas530_ext_get_slave_descr(void); +extern int geomagnetic_api_read(int *xyz, int *raw, int *xy1y2, int *accuracy); +extern int geomagnetic_api_resume(void); +extern int geomagnetic_api_suspend(void); + +#endif diff --git a/drivers/misc/inv_mpu/log.h b/drivers/misc/inv_mpu/log.h new file mode 100644 index 00000000000..5630602e3ef --- /dev/null +++ b/drivers/misc/inv_mpu/log.h @@ -0,0 +1,287 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +/* + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * C/C++ logging functions. See the logging documentation for API details. + * + * We'd like these to be available from C code (in case we import some from + * somewhere), so this has a C interface. + * + * The output will be correct when the log file is shared between multiple + * threads and/or multiple processes so long as the operating system + * supports O_APPEND. These calls have mutex-protected data structures + * and so are NOT reentrant. Do not use MPL_LOG in a signal handler. + */ +#ifndef _LIBS_CUTILS_MPL_LOG_H +#define _LIBS_CUTILS_MPL_LOG_H + +#include "mltypes.h" +#include + + +#include + + +/* --------------------------------------------------------------------- */ + +/* + * Normally we strip MPL_LOGV (VERBOSE messages) from release builds. + * You can modify this (for example with "#define MPL_LOG_NDEBUG 0" + * at the top of your source file) to change that behavior. + */ +#ifndef MPL_LOG_NDEBUG +#ifdef NDEBUG +#define MPL_LOG_NDEBUG 1 +#else +#define MPL_LOG_NDEBUG 0 +#endif +#endif + +#define MPL_LOG_UNKNOWN MPL_LOG_VERBOSE +#define MPL_LOG_DEFAULT KERN_DEFAULT +#define MPL_LOG_VERBOSE KERN_CONT +#define MPL_LOG_DEBUG KERN_NOTICE +#define MPL_LOG_INFO KERN_INFO +#define MPL_LOG_WARN KERN_WARNING +#define MPL_LOG_ERROR KERN_ERR +#define MPL_LOG_SILENT MPL_LOG_VERBOSE + + + +/* + * This is the local tag used for the following simplified + * logging macros. You can change this preprocessor definition + * before using the other macros to change the tag. + */ +#ifndef MPL_LOG_TAG +#define MPL_LOG_TAG +#endif + +/* --------------------------------------------------------------------- */ + +/* + * Simplified macro to send a verbose log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGV +#if MPL_LOG_NDEBUG +#define MPL_LOGV(fmt, ...) \ + do { \ + if (0) \ + MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__);\ + } while (0) +#else +#define MPL_LOGV(fmt, ...) MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__) +#endif +#endif + +#ifndef CONDITION +#define CONDITION(cond) ((cond) != 0) +#endif + +#ifndef MPL_LOGV_IF +#if MPL_LOG_NDEBUG +#define MPL_LOGV_IF(cond, fmt, ...) \ + do { if (0) MPL_LOG(fmt, ##__VA_ARGS__); } while (0) +#else +#define MPL_LOGV_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ + : (void)0) +#endif +#endif + +/* + * Simplified macro to send a debug log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGD +#define MPL_LOGD(fmt, ...) MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__VA_ARGS__) +#endif + +#ifndef MPL_LOGD_IF +#define MPL_LOGD_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ + : (void)0) +#endif + +/* + * Simplified macro to send an info log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGI +#define MPL_LOGI(fmt, ...) pr_info(KERN_INFO MPL_LOG_TAG fmt, ##__VA_ARGS__) +#endif + +#ifndef MPL_LOGI_IF +#define MPL_LOGI_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_INFO, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ + : (void)0) +#endif + +/* + * Simplified macro to send a warning log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGW +#define MPL_LOGW(fmt, ...) printk(KERN_WARNING MPL_LOG_TAG fmt, ##__VA_ARGS__) +#endif + +#ifndef MPL_LOGW_IF +#define MPL_LOGW_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_WARN, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ + : (void)0) +#endif + +/* + * Simplified macro to send an error log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGE +#define MPL_LOGE(fmt, ...) printk(KERN_ERR MPL_LOG_TAG fmt, ##__VA_ARGS__) +#endif + +#ifndef MPL_LOGE_IF +#define MPL_LOGE_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_ERROR, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ + : (void)0) +#endif + +/* --------------------------------------------------------------------- */ + +/* + * Log a fatal error. If the given condition fails, this stops program + * execution like a normal assertion, but also generating the given message. + * It is NOT stripped from release builds. Note that the condition test + * is -inverted- from the normal assert() semantics. + */ +#define MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? ((void)android_printAssert(#cond, MPL_LOG_TAG, \ + fmt, ##__VA_ARGS__)) \ + : (void)0) + +#define MPL_LOG_ALWAYS_FATAL(fmt, ...) \ + (((void)android_printAssert(NULL, MPL_LOG_TAG, fmt, ##__VA_ARGS__))) + +/* + * Versions of MPL_LOG_ALWAYS_FATAL_IF and MPL_LOG_ALWAYS_FATAL that + * are stripped out of release builds. + */ +#if MPL_LOG_NDEBUG +#define MPL_LOG_FATAL_IF(cond, fmt, ...) \ + do { \ + if (0) \ + MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__); \ + } while (0) +#define MPL_LOG_FATAL(fmt, ...) \ + do { \ + if (0) \ + MPL_LOG_ALWAYS_FATAL(fmt, ##__VA_ARGS__) \ + } while (0) +#else +#define MPL_LOG_FATAL_IF(cond, fmt, ...) \ + MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__) +#define MPL_LOG_FATAL(fmt, ...) \ + MPL_LOG_ALWAYS_FATAL(fmt, ##__VA_ARGS__) +#endif + +/* + * Assertion that generates a log message when the assertion fails. + * Stripped out of release builds. Uses the current MPL_LOG_TAG. + */ +#define MPL_LOG_ASSERT(cond, fmt, ...) \ + MPL_LOG_FATAL_IF(!(cond), fmt, ##__VA_ARGS__) + +/* --------------------------------------------------------------------- */ + +/* + * Basic log message macro. + * + * Example: + * MPL_LOG(MPL_LOG_WARN, NULL, "Failed with error %d", errno); + * + * The second argument may be NULL or "" to indicate the "global" tag. + */ +#ifndef MPL_LOG +#define MPL_LOG(priority, tag, fmt, ...) \ + MPL_LOG_PRI(priority, tag, fmt, ##__VA_ARGS__) +#endif + +/* + * Log macro that allows you to specify a number for the priority. + */ +#ifndef MPL_LOG_PRI +#define MPL_LOG_PRI(priority, tag, fmt, ...) \ + pr_debug(MPL_##priority tag fmt, ##__VA_ARGS__) +#endif + +/* + * Log macro that allows you to pass in a varargs ("args" is a va_list). + */ +#ifndef MPL_LOG_PRI_VA +/* not allowed in the Kernel because there is no dev_dbg that takes a va_list */ +#endif + +/* --------------------------------------------------------------------- */ + +/* + * =========================================================================== + * + * The stuff in the rest of this file should not be used directly. + */ + +int _MLPrintLog(int priority, const char *tag, const char *fmt, ...); +int _MLPrintVaLog(int priority, const char *tag, const char *fmt, va_list args); +/* Final implementation of actual writing to a character device */ +int _MLWriteLog(const char *buf, int buflen); + +static inline void __print_result_location(int result, + const char *file, + const char *func, int line) +{ + MPL_LOGE("%s|%s|%d returning %d\n", file, func, line, result); +} + +#define LOG_RESULT_LOCATION(condition) \ + do { \ + __print_result_location((int)(condition), __FILE__, \ + __func__, __LINE__); \ + } while (0) + + +#endif /* _LIBS_CUTILS_MPL_LOG_H */ diff --git a/drivers/misc/inv_mpu/mldl_cfg.c b/drivers/misc/inv_mpu/mldl_cfg.c new file mode 100644 index 00000000000..05da3964d0a --- /dev/null +++ b/drivers/misc/inv_mpu/mldl_cfg.c @@ -0,0 +1,2054 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +/** + * @addtogroup MLDL + * + * @{ + * @file mldl_cfg.c + * @brief The Motion Library Driver Layer. + */ + +/* -------------------------------------------------------------------------- */ +#include +#include + +#include + +#include "mldl_cfg.h" +#include +#include "mpu6050b1.h" + +#include "mlsl.h" +#include "mldl_print_cfg.h" +#include "log.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "mldl_cfg:" + +/* -------------------------------------------------------------------------- */ + +#define SLEEP 0 +#define WAKE_UP 7 +#define RESET 1 +#define STANDBY 1 +#define FEATURE_REDUCE_DMPTIME + +struct motion_int_data { + unsigned char pwr_mnt[2]; + unsigned char cfg; + unsigned char accel_cfg; + unsigned char int_cfg; + bool is_set; +}; + +static struct motion_int_data motion_int_data; +/* -------------------------------------------------------------------------- */ + +/** + * @brief Stop the DMP running + * + * @return INV_SUCCESS or non-zero error code + */ +static int dmp_stop(struct mldl_cfg *mldl_cfg, void *gyro_handle) +{ + unsigned char user_ctrl_reg; + int result; + + if (mldl_cfg->inv_mpu_state->status & MPU_DMP_IS_SUSPENDED) + return INV_SUCCESS; + + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, 1, &user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + user_ctrl_reg = (user_ctrl_reg & (~BIT_FIFO_EN)) | BIT_FIFO_RST; + user_ctrl_reg = (user_ctrl_reg & (~BIT_DMP_EN)) | BIT_DMP_RST; + + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status |= MPU_DMP_IS_SUSPENDED; + + return result; +} + +/** + * @brief Starts the DMP running + * + * @return INV_SUCCESS or non-zero error code + */ +static int dmp_start(struct mldl_cfg *mldl_cfg, void *mlsl_handle) +{ + unsigned char user_ctrl_reg; + int result; + + if ((!(mldl_cfg->inv_mpu_state->status & MPU_DMP_IS_SUSPENDED) && + mldl_cfg->mpu_gyro_cfg->dmp_enable) + || + ((mldl_cfg->inv_mpu_state->status & MPU_DMP_IS_SUSPENDED) && + !mldl_cfg->mpu_gyro_cfg->dmp_enable)) + return INV_SUCCESS; + + result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, 1, &user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, + ((user_ctrl_reg & (~BIT_FIFO_EN)) + | BIT_FIFO_RST)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, 1, &user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + user_ctrl_reg |= BIT_DMP_EN; + + if (mldl_cfg->mpu_gyro_cfg->fifo_enable) + user_ctrl_reg |= BIT_FIFO_EN; + else + user_ctrl_reg &= ~BIT_FIFO_EN; + + user_ctrl_reg |= BIT_DMP_RST; + + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status &= ~MPU_DMP_IS_SUSPENDED; + + return result; +} + +/** + * @brief enables/disables the I2C bypass to an external device + * connected to MPU's secondary I2C bus. + * @param enable + * Non-zero to enable pass through. + * @return INV_SUCCESS if successful, a non-zero error code otherwise. + */ +static int mpu6050b1_set_i2c_bypass(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, unsigned char enable) +{ + unsigned char reg; + int result; + unsigned char status = mldl_cfg->inv_mpu_state->status; + if ((status & MPU_GYRO_IS_BYPASSED && enable) || + (!(status & MPU_GYRO_IS_BYPASSED) && !enable)) + return INV_SUCCESS; + + /*---- get current 'USER_CTRL' into b ----*/ + result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (!enable) { + /* setting int_config with the property flag BIT_BYPASS_EN + should be done by the setup functions */ + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_INT_PIN_CFG, + (mldl_cfg->pdata->int_config & ~(BIT_BYPASS_EN))); + if (!(reg & BIT_I2C_MST_EN)) { + result = + inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, + (reg | BIT_I2C_MST_EN)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + } else if (enable) { + if (reg & BIT_AUX_IF_EN) { + result = + inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, + (reg & (~BIT_I2C_MST_EN))); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /***************************************** + * To avoid hanging the bus we must sleep until all + * slave transactions have been completed. + * 24 bytes max slave reads + * +1 byte possible extra write + * +4 max slave address + * --- + * 33 Maximum bytes + * x9 Approximate bits per byte + * --- + * 297 bits. + * 2.97 ms minimum @ 100kbps + * 0.75 ms minimum @ 400kbps. + *****************************************/ + mdelay(3); + } + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_INT_PIN_CFG, + (mldl_cfg->pdata->int_config | BIT_BYPASS_EN)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + if (enable) + mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_BYPASSED; + else + mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_BYPASSED; + + return result; +} + + + + +/** + * @brief enables/disables the I2C bypass to an external device + * connected to MPU's secondary I2C bus. + * @param enable + * Non-zero to enable pass through. + * @return INV_SUCCESS if successful, a non-zero error code otherwise. + */ +static int mpu_set_i2c_bypass(struct mldl_cfg *mldl_cfg, void *mlsl_handle, + unsigned char enable) +{ + return mpu6050b1_set_i2c_bypass(mldl_cfg, mlsl_handle, enable); +} + + +#define NUM_OF_PROD_REVS (ARRAY_SIZE(prod_rev_map)) + +/* NOTE : when not indicated, product revision + is considered an 'npp'; non production part */ + +/* produces an unique identifier for each device based on the + combination of product version and product revision */ +struct prod_rev_map_t { + unsigned short mpl_product_key; + unsigned char silicon_rev; + unsigned short gyro_trim; + unsigned short accel_trim; +}; + +/* NOTE: product entries are in chronological order */ +static struct prod_rev_map_t prod_rev_map[] = { + /* prod_ver = 0 */ + {MPL_PROD_KEY(0, 1), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 2), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 3), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 4), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 5), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 6), MPU_SILICON_REV_A2, 131, 16384}, /* (A2/C2-1) */ + /* prod_ver = 1, forced to 0 for MPU6050 A2 */ + {MPL_PROD_KEY(0, 7), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 8), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 9), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 10), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 11), MPU_SILICON_REV_A2, 131, 16384}, /* (A2/D2-1) */ + {MPL_PROD_KEY(0, 12), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 13), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 14), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 15), MPU_SILICON_REV_A2, 131, 16384}, + {MPL_PROD_KEY(0, 27), MPU_SILICON_REV_A2, 131, 16384}, /* (A2/D4) */ + /* prod_ver = 1 */ + {MPL_PROD_KEY(1, 16), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-1) */ + {MPL_PROD_KEY(1, 17), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-2) */ + {MPL_PROD_KEY(1, 18), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-3) */ + {MPL_PROD_KEY(1, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-4) */ + {MPL_PROD_KEY(1, 20), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-5) */ + {MPL_PROD_KEY(1, 28), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D4) */ + {MPL_PROD_KEY(1, 1), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-1) */ + {MPL_PROD_KEY(1, 2), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-2) */ + {MPL_PROD_KEY(1, 3), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-3) */ + {MPL_PROD_KEY(1, 4), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-4) */ + {MPL_PROD_KEY(1, 5), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-5) */ + {MPL_PROD_KEY(1, 6), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-6) */ + /* prod_ver = 2 */ + {MPL_PROD_KEY(2, 7), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-1) */ + {MPL_PROD_KEY(2, 8), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-2) */ + {MPL_PROD_KEY(2, 9), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-3) */ + {MPL_PROD_KEY(2, 10), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-4) */ + {MPL_PROD_KEY(2, 11), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-5) */ + {MPL_PROD_KEY(2, 12), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-6) */ + {MPL_PROD_KEY(2, 29), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/D4) */ + /* prod_ver = 3 */ + {MPL_PROD_KEY(3, 30), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E2) */ + /* prod_ver = 4 */ + {MPL_PROD_KEY(4, 31), MPU_SILICON_REV_B1, 131, 8192}, /* (B2/F1) */ + {MPL_PROD_KEY(4, 1), MPU_SILICON_REV_B1, 131, 8192}, /* (B3/F1) */ + {MPL_PROD_KEY(4, 3), MPU_SILICON_REV_B1, 131, 8192}, /* (B4/F1) */ + /* prod_ver = 5 */ + {MPL_PROD_KEY(6, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2) */ + /* prod_ver = 7 */ + {MPL_PROD_KEY(7, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2) */ + /* prod_ver = 8 */ + {MPL_PROD_KEY(8, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2) */ + {MPL_PROD_KEY(40, 19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2) */ + {MPL_PROD_KEY(41, 19), MPU_SILICON_REV_B1, 131, 16384} /* (B5/E2) */ +}; + +/** + * @internal + * @brief Inverse lookup of the index of an MPL product key . + * @param key + * the MPL product indentifier also referred to as 'key'. + * @return the index position of the key in the array, -1 if not found. + */ +short index_of_key(unsigned short key) +{ + int i; + printk(KERN_INFO "%s\n", __func__); + for (i = 0; i < NUM_OF_PROD_REVS; i++) + if (prod_rev_map[i].mpl_product_key == key) + return (short)i; + return -1; +} + +/** + * @internal + * @brief Get the product revision and version for MPU6050 and + * extract all per-part specific information. + * The product version number is read from the PRODUCT_ID register in + * user space register map. + * The product revision number is in read from OTP bank 0, ADDR6[7:2]. + * These 2 numbers, combined, provide an unique key to be used to + * retrieve some per-device information such as the silicon revision + * and the gyro and accel sensitivity trim values. + * + * @param mldl_cfg + * a pointer to the mldl config data structure. + * @param mlsl_handle + * an file handle to the serial communication device the + * device is connected to. + * + * @return 0 on success, a non-zero error code otherwise. + */ +static int inv_get_silicon_rev_mpu6050( + struct mldl_cfg *mldl_cfg, void *mlsl_handle) +{ + int result; + unsigned char prod_ver = 0x00, prod_rev = 0x00; + unsigned char bank = + (BIT_PRFTCH_EN | BIT_CFG_USER_BANK | MPU_MEM_OTP_BANK_0); + unsigned short memAddr = ((bank << 8) | 0x06); + unsigned short key; + struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info; + + result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PRODUCT_ID, 1, &prod_ver); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_read_mem(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + memAddr, 1, &prod_rev); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + prod_rev >>= 2; + + /* clean the prefetch and cfg user bank bits */ + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_BANK_SEL, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + key = MPL_PROD_KEY(prod_ver, prod_rev); + if (key == 0) { + MPL_LOGE("Product id read as 0 " + "indicates device is either " + "incompatible or an MPU3050\n"); + return INV_ERROR_INVALID_MODULE; + } + + mpu_chip_info->product_id = prod_ver; + mpu_chip_info->product_revision = prod_rev; + mpu_chip_info->silicon_revision = MPU_SILICON_REV_B1; + mpu_chip_info->gyro_sens_trim = 131; + mpu_chip_info->accel_sens_trim = 16384; + + if (prod_ver == 4) + mpu_chip_info->accel_sens_trim = 8192; + + return result; +} +#define inv_get_silicon_rev inv_get_silicon_rev_mpu6050 + + +/** + * @brief Enable / Disable the use MPU's secondary I2C interface level + * shifters. + * When enabled the secondary I2C interface to which the external + * device is connected runs at VDD voltage (main supply). + * When disabled the 2nd interface runs at VDDIO voltage. + * See the device specification for more details. + * + * @note using this API may produce unpredictable results, depending on how + * the MPU and slave device are setup on the target platform. + * Use of this API should entirely be restricted to system + * integrators. Once the correct value is found, there should be no + * need to change the level shifter at runtime. + * + * @pre Must be called after inv_serial_start(). + * @note Typically called before inv_dmp_open(). + * + * @param[in] enable: + * 0 to run at VDDIO (default), + * 1 to run at VDD. + * + * @return INV_SUCCESS if successfull, a non-zero error code otherwise. + */ +static int inv_mpu_set_level_shifter_bit(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, unsigned char enable) +{ + int result; + unsigned char regval; + + result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_YG_OFFS_TC, 1, ®val); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (enable) + regval |= BIT_I2C_MST_VDDIO; + + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_YG_OFFS_TC, regval); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return INV_SUCCESS; +} + + +/** + * @internal + * @brief MPU6050 B1 power management functions. + * @param mldl_cfg + * a pointer to the internal mldl_cfg data structure. + * @param mlsl_handle + * a file handle to the serial device used to communicate + * with the MPU6050 B1 device. + * @param reset + * 1 to reset hardware. + * @param sensors + * Bitfield of sensors to leave on + * + * @return 0 on success, a non-zero error code on error. + */ +static int mpu60xx_pwr_mgmt(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, + unsigned int reset, unsigned long sensors) +{ + unsigned char pwr_mgmt[2]; + unsigned char pwr_mgmt_prev[2]; + int result; + int sleep = !(sensors & (INV_THREE_AXIS_GYRO | INV_THREE_AXIS_ACCEL + | INV_DMP_PROCESSOR)); + + if (reset) { + MPL_LOGI("Reset MPU6050 B1\n"); + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGMT_1, BIT_H_RESET); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_BYPASSED; + msleep(100); + } + + /* NOTE : reading both PWR_MGMT_1 and PWR_MGMT_2 for efficiency because + they are accessible even when the device is powered off */ + result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGMT_1, 2, pwr_mgmt_prev); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + pwr_mgmt[0] = pwr_mgmt_prev[0]; + pwr_mgmt[1] = pwr_mgmt_prev[1]; + + if (sleep) { + mldl_cfg->inv_mpu_state->status |= MPU_DEVICE_IS_SUSPENDED; + pwr_mgmt[0] |= BIT_SLEEP; + } else { + mldl_cfg->inv_mpu_state->status &= ~MPU_DEVICE_IS_SUSPENDED; + pwr_mgmt[0] &= ~BIT_SLEEP; + } + if (pwr_mgmt[0] != pwr_mgmt_prev[0]) { + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGMT_1, pwr_mgmt[0]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + pwr_mgmt[1] &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG); + if (!(sensors & INV_X_GYRO)) + pwr_mgmt[1] |= BIT_STBY_XG; + if (!(sensors & INV_Y_GYRO)) + pwr_mgmt[1] |= BIT_STBY_YG; + if (!(sensors & INV_Z_GYRO)) + pwr_mgmt[1] |= BIT_STBY_ZG; + + if (pwr_mgmt[1] != pwr_mgmt_prev[1]) { + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGMT_2, pwr_mgmt[1]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + if ((pwr_mgmt[1] & (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) == + (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) { + mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_SUSPENDED; + } else { + mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_SUSPENDED; + } + + return INV_SUCCESS; +} + + +/** + * @brief sets the clock source for the gyros. + * @param mldl_cfg + * a pointer to the struct mldl_cfg data structure. + * @param gyro_handle + * an handle to the serial device the gyro is assigned to. + * @return ML_SUCCESS if successful, a non-zero error code otherwise. + */ +static int mpu_set_clock_source(void *gyro_handle, struct mldl_cfg *mldl_cfg) +{ + int result; + unsigned char cur_clk_src; + unsigned char reg; + + /* clock source selection */ + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + cur_clk_src = reg & BITS_CLKSEL; + reg &= ~BITS_CLKSEL; + + + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, mldl_cfg->mpu_gyro_cfg->clk_src | reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* ERRATA: + workaroud to switch from any MPU_CLK_SEL_PLLGYROx to + MPU_CLK_SEL_INTERNAL and XGyro is powered up: + 1) Select INT_OSC + 2) PD XGyro + 3) PU XGyro + */ + if ((cur_clk_src == MPU_CLK_SEL_PLLGYROX + || cur_clk_src == MPU_CLK_SEL_PLLGYROY + || cur_clk_src == MPU_CLK_SEL_PLLGYROZ) + && mldl_cfg->mpu_gyro_cfg->clk_src == MPU_CLK_SEL_INTERNAL + && mldl_cfg->inv_mpu_cfg->requested_sensors & INV_X_GYRO) { + unsigned char first_result = INV_SUCCESS; + mldl_cfg->inv_mpu_cfg->requested_sensors &= ~INV_X_GYRO; + result = mpu60xx_pwr_mgmt( + mldl_cfg, gyro_handle, + false, mldl_cfg->inv_mpu_cfg->requested_sensors); + ERROR_CHECK_FIRST(first_result, result); + mldl_cfg->inv_mpu_cfg->requested_sensors |= INV_X_GYRO; + result = mpu60xx_pwr_mgmt( + mldl_cfg, gyro_handle, + false, mldl_cfg->inv_mpu_cfg->requested_sensors); + ERROR_CHECK_FIRST(first_result, result); + result = first_result; + } + return result; +} + +/** + * Configures the MPU I2C Master + * + * @mldl_cfg Handle to the configuration data + * @gyro_handle handle to the gyro communictation interface + * @slave Can be Null if turning off the slave + * @slave_pdata Can be null if turning off the slave + * @slave_id enum ext_slave_type to determine which index to use + * + * + * This fucntion configures the slaves by: + * 1) Setting up the read + * a) Read Register + * b) Read Length + * 2) Set up the data trigger (MPU6050 only) + * a) Set trigger write register + * b) Set Trigger write value + * 3) Set up the divider (MPU6050 only) + * 4) Set the slave bypass mode depending on slave + * + * returns INV_SUCCESS or non-zero error code + */ + +static int mpu_set_slave_mpu60xx(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *slave_pdata, + int slave_id) +{ + int result; + unsigned char reg; + /* Slave values */ + unsigned char slave_reg; + unsigned char slave_len; + unsigned char slave_endian; + unsigned char slave_address; + /* Which MPU6050 registers to use */ + unsigned char addr_reg; + unsigned char reg_reg; + unsigned char ctrl_reg; + /* Which MPU6050 registers to use for the trigger */ + unsigned char addr_trig_reg; + unsigned char reg_trig_reg; + unsigned char ctrl_trig_reg; + + unsigned char bits_slave_delay = 0; + /* Divide down rate for the Slave, from the mpu rate */ + unsigned char d0_trig_reg; + unsigned char delay_ctrl_orig; + unsigned char delay_ctrl; + long divider; + + if (NULL == slave || NULL == slave_pdata) { + slave_reg = 0; + slave_len = 0; + slave_endian = 0; + slave_address = 0; + } else { + slave_reg = slave->read_reg; + slave_len = slave->read_len; + slave_endian = slave->endian; + slave_address = slave_pdata->address; + slave_address |= BIT_I2C_READ; + } + + switch (slave_id) { + case EXT_SLAVE_TYPE_ACCEL: + addr_reg = MPUREG_I2C_SLV1_ADDR; + reg_reg = MPUREG_I2C_SLV1_REG; + ctrl_reg = MPUREG_I2C_SLV1_CTRL; + addr_trig_reg = 0; + reg_trig_reg = 0; + ctrl_trig_reg = 0; + bits_slave_delay = BIT_SLV1_DLY_EN; + break; + case EXT_SLAVE_TYPE_COMPASS: + addr_reg = MPUREG_I2C_SLV0_ADDR; + reg_reg = MPUREG_I2C_SLV0_REG; + ctrl_reg = MPUREG_I2C_SLV0_CTRL; + addr_trig_reg = MPUREG_I2C_SLV2_ADDR; + reg_trig_reg = MPUREG_I2C_SLV2_REG; + ctrl_trig_reg = MPUREG_I2C_SLV2_CTRL; + d0_trig_reg = MPUREG_I2C_SLV2_DO; + bits_slave_delay = BIT_SLV2_DLY_EN | BIT_SLV0_DLY_EN; + break; + case EXT_SLAVE_TYPE_PRESSURE: + addr_reg = MPUREG_I2C_SLV3_ADDR; + reg_reg = MPUREG_I2C_SLV3_REG; + ctrl_reg = MPUREG_I2C_SLV3_CTRL; + addr_trig_reg = MPUREG_I2C_SLV4_ADDR; + reg_trig_reg = MPUREG_I2C_SLV4_REG; + ctrl_trig_reg = MPUREG_I2C_SLV4_CTRL; + bits_slave_delay = BIT_SLV4_DLY_EN | BIT_SLV3_DLY_EN; + break; + default: + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + }; + + /* return if this slave has already been set */ + if ((slave_address && + ((mldl_cfg->inv_mpu_state->i2c_slaves_enabled & bits_slave_delay) + == bits_slave_delay)) || + (!slave_address && + (mldl_cfg->inv_mpu_state->i2c_slaves_enabled & bits_slave_delay) == + 0)) + return 0; + + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, true); + + /* Address */ + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + addr_reg, slave_address); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Register */ + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + reg_reg, slave_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Length, byte swapping, grouping & enable */ + if (slave_len > BITS_SLV_LENG) { + MPL_LOGW("Limiting slave burst read length to " + "the allowed maximum (15B, req. %d)\n", slave_len); + slave_len = BITS_SLV_LENG; + return INV_ERROR_INVALID_CONFIGURATION; + } + reg = slave_len; + if (slave_endian == EXT_SLAVE_LITTLE_ENDIAN) { + reg |= BIT_SLV_BYTE_SW; + if (slave_reg & 1) + reg |= BIT_SLV_GRP; + } + if (slave_address) + reg |= BIT_SLV_ENABLE; + + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + ctrl_reg, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Trigger */ + if (addr_trig_reg) { + /* If slave address is 0 this clears the trigger */ + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + addr_trig_reg, + slave_address & ~BIT_I2C_READ); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + if (slave && slave->trigger && reg_trig_reg) { + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + reg_trig_reg, + slave->trigger->reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + ctrl_trig_reg, + BIT_SLV_ENABLE | 0x01); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + d0_trig_reg, + slave->trigger->value); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } else if (ctrl_trig_reg) { + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + ctrl_trig_reg, 0x00); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + /* Data rate */ + if (slave) { + struct ext_slave_config config; + long data; + config.key = MPU_SLAVE_CONFIG_ODR_RESUME; + config.len = sizeof(long); + config.apply = false; + config.data = &data; + if (!(slave->get_config)) + return INV_ERROR_INVALID_CONFIGURATION; + + result = slave->get_config(NULL, slave, slave_pdata, &config); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGI("Slave %d ODR: %ld Hz\n", slave_id, data / 1000); + divider = ((1000 * inv_mpu_get_sampling_rate_hz( + mldl_cfg->mpu_gyro_cfg)) + / data) - 1; + } else { + divider = 0; + } + + result = inv_serial_read(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + MPUREG_I2C_MST_DELAY_CTRL, + 1, &delay_ctrl_orig); + delay_ctrl = delay_ctrl_orig; + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (divider > 0 && divider <= MASK_I2C_MST_DLY) { + result = inv_serial_read(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + MPUREG_I2C_SLV4_CTRL, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if ((reg & MASK_I2C_MST_DLY) && + ((long)(reg & MASK_I2C_MST_DLY) != + (divider & MASK_I2C_MST_DLY))) { + MPL_LOGW("Changing slave divider: %ld to %ld\n", + (long)(reg & MASK_I2C_MST_DLY), + (divider & MASK_I2C_MST_DLY)); + + } + reg |= (unsigned char)(divider & MASK_I2C_MST_DLY); + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + MPUREG_I2C_SLV4_CTRL, + reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + delay_ctrl |= bits_slave_delay; + } else { + delay_ctrl &= ~(bits_slave_delay); + } + if (delay_ctrl != delay_ctrl_orig) { + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_I2C_MST_DELAY_CTRL, + delay_ctrl); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + if (slave_address) + mldl_cfg->inv_mpu_state->i2c_slaves_enabled |= + bits_slave_delay; + else + mldl_cfg->inv_mpu_state->i2c_slaves_enabled &= + ~bits_slave_delay; + + return result; +} + +static int mpu_set_slave(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *slave_pdata, + int slave_id) +{ + return mpu_set_slave_mpu60xx(mldl_cfg, gyro_handle, slave, + slave_pdata, slave_id); +} +/** + * Check to see if the gyro was reset by testing a couple of registers known + * to change on reset. + * + * @mldl_cfg mldl configuration structure + * @gyro_handle handle used to communicate with the gyro + * + * @return INV_SUCCESS or non-zero error code + */ +static int mpu_was_reset(struct mldl_cfg *mldl_cfg, void *gyro_handle) +{ + int result = INV_SUCCESS; + unsigned char reg; + + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_DMP_CFG_2, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (mldl_cfg->mpu_gyro_cfg->dmp_cfg2 != reg) + return true; + + if (0 != mldl_cfg->mpu_gyro_cfg->dmp_cfg1) + return false; + + /* Inconclusive assume it was reset */ + return true; +} + + +int inv_mpu_set_firmware(struct mldl_cfg *mldl_cfg, void *mlsl_handle, + const unsigned char *data, int size) +{ + int bank, offset, write_size; + int result; +#ifndef FEATURE_REDUCE_DMPTIME + unsigned char read[MPU_MEM_BANK_SIZE]; +#endif + + if (mldl_cfg->inv_mpu_state->status & MPU_DEVICE_IS_SUSPENDED) { +#if INV_CACHE_DMP == 1 + memcpy(mldl_cfg->mpu_ram->ram, data, size); + return INV_SUCCESS; +#else + LOG_RESULT_LOCATION(INV_ERROR_MEMORY_SET); + return INV_ERROR_MEMORY_SET; +#endif + } + + if (!(mldl_cfg->inv_mpu_state->status & MPU_DMP_IS_SUSPENDED)) { + LOG_RESULT_LOCATION(INV_ERROR_MEMORY_SET); + return INV_ERROR_MEMORY_SET; + } + /* Write and verify memory */ + for (bank = 0; size > 0; bank++, + size -= write_size, + data += write_size) { + if (size > MPU_MEM_BANK_SIZE) + write_size = MPU_MEM_BANK_SIZE; + else + write_size = size; + + result = inv_serial_write_mem(mlsl_handle, + mldl_cfg->mpu_chip_info->addr, + ((bank << 8) | 0x00), + write_size, + data); + if (result) { + LOG_RESULT_LOCATION(result); + MPL_LOGE("Write mem error in bank %d\n", bank); + return result; + } +#ifndef FEATURE_REDUCE_DMPTIME + result = inv_serial_read_mem(mlsl_handle, + mldl_cfg->mpu_chip_info->addr, + ((bank << 8) | 0x00), + write_size, + read); + if (result) { + LOG_RESULT_LOCATION(result); + MPL_LOGE("Read mem error in bank %d\n", bank); + return result; + } + +#define ML_SKIP_CHECK 38 + for (offset = 0; offset < write_size; offset++) { + /* skip the register memory locations */ + if (bank == 0 && offset < ML_SKIP_CHECK) + continue; + if (data[offset] != read[offset]) { + result = INV_ERROR_SERIAL_WRITE; + break; + } + } +#endif + if (result != INV_SUCCESS) { + LOG_RESULT_LOCATION(result); + MPL_LOGE("Read data mismatch at bank %d, offset %d\n", + bank, offset); + return result; + } + } + return INV_SUCCESS; +} + +static int set_fp_mode(struct mldl_cfg *mldl_cfg, void *gyro_handle) +{ + unsigned char b; + int result = INV_SUCCESS; + + /* Resetting the cycle bit and LPA wake up freq */ + inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGMT_1, 1, &b); + + if (b & BIT_CYCLE) { + b &= ~BIT_CYCLE & ~BIT_PD_PTAT; + result |= inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGMT_1, b); + inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGMT_2, 1, &b); + b &= ~BITS_LPA_WAKE_CTRL; + result |= inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGMT_2, b); + } + + return result; +} + +static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle, + unsigned long sensors) +{ + int result; + int ii; + unsigned char reg; + unsigned char regs[7]; + unsigned char int_cfg = mldl_cfg->mpu_gyro_cfg->int_config; + + result = set_fp_mode(mldl_cfg, gyro_handle); + if (result) + LOG_RESULT_LOCATION(result); + + /* Wake up the part */ + result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, false, sensors); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Always set the INT_ENABLE and DIVIDER as the Accel Only mode for 6050 + can set these too */ + if (mldl_cfg->inv_mpu_state->accel_reactive) + int_cfg |= 0x40; + + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_INT_ENABLE, int_cfg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_SMPLRT_DIV, mldl_cfg->mpu_gyro_cfg->divider); + pr_info("mpu6050_gyro_resume: %d, result %d\n", + mldl_cfg->mpu_gyro_cfg->divider, result); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_NEEDS_CONFIG) && + !mpu_was_reset(mldl_cfg, gyro_handle)) { + return INV_SUCCESS; + } + + /* Configure the MPU */ + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu_set_clock_source(gyro_handle, mldl_cfg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + reg = MPUREG_GYRO_CONFIG_VALUE(0, 0, 0, + mldl_cfg->mpu_gyro_cfg->full_scale); + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_GYRO_CONFIG, reg); + reg = MPUREG_CONFIG_VALUE(mldl_cfg->mpu_gyro_cfg->ext_sync, + mldl_cfg->mpu_gyro_cfg->lpf); + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_CONFIG, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_DMP_CFG_1, mldl_cfg->mpu_gyro_cfg->dmp_cfg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_DMP_CFG_2, mldl_cfg->mpu_gyro_cfg->dmp_cfg2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Write and verify memory */ +#if INV_CACHE_DMP != 0 + inv_mpu_set_firmware(mldl_cfg, gyro_handle, + mldl_cfg->mpu_ram->ram, mldl_cfg->mpu_ram->length); +#endif + + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_XG_OFFS_TC, + ((mldl_cfg->mpu_offsets->tc[0] << 1) & BITS_XG_OFFS_TC)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + regs[0] = ((mldl_cfg->mpu_offsets->tc[1] << 1) & BITS_YG_OFFS_TC); + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_YG_OFFS_TC, regs[0]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_ZG_OFFS_TC, + ((mldl_cfg->mpu_offsets->tc[2] << 1) & BITS_ZG_OFFS_TC)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + regs[0] = MPUREG_X_OFFS_USRH; + for (ii = 0; ii < ARRAY_SIZE(mldl_cfg->mpu_offsets->gyro); ii++) { + regs[1 + ii * 2] = + (unsigned char)(mldl_cfg->mpu_offsets->gyro[ii] >> 8) + & 0xff; + regs[1 + ii * 2 + 1] = + (unsigned char)(mldl_cfg->mpu_offsets->gyro[ii] & 0xff); + } + result = inv_serial_write(gyro_handle, mldl_cfg->mpu_chip_info->addr, + 7, regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Configure slaves */ + result = inv_mpu_set_level_shifter_bit(mldl_cfg, gyro_handle, + mldl_cfg->pdata->level_shifter); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_NEEDS_CONFIG; + + return result; +} + +int gyro_config(void *mlsl_handle, + struct mldl_cfg *mldl_cfg, + struct ext_slave_config *data) +{ + struct mpu_gyro_cfg *mpu_gyro_cfg = mldl_cfg->mpu_gyro_cfg; + struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info; + struct mpu_offsets *mpu_offsets = mldl_cfg->mpu_offsets; + int ii; + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_INT_CONFIG: + mpu_gyro_cfg->int_config = *((__u8 *)data->data); + break; + case MPU_SLAVE_EXT_SYNC: + mpu_gyro_cfg->ext_sync = *((__u8 *)data->data); + break; + case MPU_SLAVE_FULL_SCALE: + mpu_gyro_cfg->full_scale = *((__u8 *)data->data); + break; + case MPU_SLAVE_LPF: + mpu_gyro_cfg->lpf = *((__u8 *)data->data); + break; + case MPU_SLAVE_CLK_SRC: + mpu_gyro_cfg->clk_src = *((__u8 *)data->data); + break; + case MPU_SLAVE_DIVIDER: + mpu_gyro_cfg->divider = *((__u8 *)data->data); + break; + case MPU_SLAVE_DMP_ENABLE: + mpu_gyro_cfg->dmp_enable = *((__u8 *)data->data); + break; + case MPU_SLAVE_FIFO_ENABLE: + mpu_gyro_cfg->fifo_enable = *((__u8 *)data->data); + break; + case MPU_SLAVE_DMP_CFG1: + mpu_gyro_cfg->dmp_cfg1 = *((__u8 *)data->data); + break; + case MPU_SLAVE_DMP_CFG2: + mpu_gyro_cfg->dmp_cfg2 = *((__u8 *)data->data); + break; + case MPU_SLAVE_TC: + for (ii = 0; ii < GYRO_NUM_AXES; ii++) + mpu_offsets->tc[ii] = ((__u8 *)data->data)[ii]; + break; + case MPU_SLAVE_GYRO: + for (ii = 0; ii < GYRO_NUM_AXES; ii++) + mpu_offsets->gyro[ii] = ((__u16 *)data->data)[ii]; + break; + case MPU_SLAVE_ADDR: + mpu_chip_info->addr = *((__u8 *)data->data); + break; + case MPU_SLAVE_PRODUCT_REVISION: + mpu_chip_info->product_revision = *((__u8 *)data->data); + break; + case MPU_SLAVE_SILICON_REVISION: + mpu_chip_info->silicon_revision = *((__u8 *)data->data); + break; + case MPU_SLAVE_PRODUCT_ID: + mpu_chip_info->product_id = *((__u8 *)data->data); + break; + case MPU_SLAVE_GYRO_SENS_TRIM: + mpu_chip_info->gyro_sens_trim = *((__u16 *)data->data); + break; + case MPU_SLAVE_ACCEL_SENS_TRIM: + mpu_chip_info->accel_sens_trim = *((__u16 *)data->data); + break; + case MPU_SLAVE_RAM: + if (data->len != mldl_cfg->mpu_ram->length) + return INV_ERROR_INVALID_PARAMETER; + + memcpy(mldl_cfg->mpu_ram->ram, data->data, data->len); + break; + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + mldl_cfg->inv_mpu_state->status |= MPU_GYRO_NEEDS_CONFIG; + return INV_SUCCESS; +} + +int gyro_get_config(void *mlsl_handle, + struct mldl_cfg *mldl_cfg, + struct ext_slave_config *data) +{ + struct mpu_gyro_cfg *mpu_gyro_cfg = mldl_cfg->mpu_gyro_cfg; + struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info; + struct mpu_offsets *mpu_offsets = mldl_cfg->mpu_offsets; + int ii; + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_INT_CONFIG: + *((__u8 *)data->data) = mpu_gyro_cfg->int_config; + break; + case MPU_SLAVE_EXT_SYNC: + *((__u8 *)data->data) = mpu_gyro_cfg->ext_sync; + break; + case MPU_SLAVE_FULL_SCALE: + *((__u8 *)data->data) = mpu_gyro_cfg->full_scale; + break; + case MPU_SLAVE_LPF: + *((__u8 *)data->data) = mpu_gyro_cfg->lpf; + break; + case MPU_SLAVE_CLK_SRC: + *((__u8 *)data->data) = mpu_gyro_cfg->clk_src; + break; + case MPU_SLAVE_DIVIDER: + *((__u8 *)data->data) = mpu_gyro_cfg->divider; + break; + case MPU_SLAVE_DMP_ENABLE: + *((__u8 *)data->data) = mpu_gyro_cfg->dmp_enable; + break; + case MPU_SLAVE_FIFO_ENABLE: + *((__u8 *)data->data) = mpu_gyro_cfg->fifo_enable; + break; + case MPU_SLAVE_DMP_CFG1: + *((__u8 *)data->data) = mpu_gyro_cfg->dmp_cfg1; + break; + case MPU_SLAVE_DMP_CFG2: + *((__u8 *)data->data) = mpu_gyro_cfg->dmp_cfg2; + break; + case MPU_SLAVE_TC: + for (ii = 0; ii < GYRO_NUM_AXES; ii++) + ((__u8 *)data->data)[ii] = mpu_offsets->tc[ii]; + break; + case MPU_SLAVE_GYRO: + for (ii = 0; ii < GYRO_NUM_AXES; ii++) + ((__u16 *)data->data)[ii] = mpu_offsets->gyro[ii]; + break; + case MPU_SLAVE_ADDR: + *((__u8 *)data->data) = mpu_chip_info->addr; + break; + case MPU_SLAVE_PRODUCT_REVISION: + *((__u8 *)data->data) = mpu_chip_info->product_revision; + break; + case MPU_SLAVE_SILICON_REVISION: + *((__u8 *)data->data) = mpu_chip_info->silicon_revision; + break; + case MPU_SLAVE_PRODUCT_ID: + *((__u8 *)data->data) = mpu_chip_info->product_id; + break; + case MPU_SLAVE_GYRO_SENS_TRIM: + *((__u16 *)data->data) = mpu_chip_info->gyro_sens_trim; + break; + case MPU_SLAVE_ACCEL_SENS_TRIM: + *((__u16 *)data->data) = mpu_chip_info->accel_sens_trim; + break; + case MPU_SLAVE_RAM: + if (data->len != mldl_cfg->mpu_ram->length) + return INV_ERROR_INVALID_PARAMETER; + + memcpy(data->data, mldl_cfg->mpu_ram->ram, data->len); + break; + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + + +/******************************************************************************* + ******************************************************************************* + * Exported functions + ******************************************************************************* + ******************************************************************************/ + +/** + * Initializes the pdata structure to defaults. + * + * Opens the device to read silicon revision, product id and whoami. + * + * @mldl_cfg + * The internal device configuration data structure. + * @mlsl_handle + * The serial communication handle. + * + * @return INV_SUCCESS if silicon revision, product id and woami are supported + * by this software. + */ +int inv_mpu_open(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, void *pressure_handle) +{ + int result; + void *slave_handle[EXT_SLAVE_NUM_TYPES]; + int ii; + + /* Default is Logic HIGH, pushpull, latch disabled, anyread to clear */ + ii = 0; + mldl_cfg->inv_mpu_cfg->ignore_system_suspend = false; + mldl_cfg->mpu_gyro_cfg->int_config = BIT_DMP_INT_EN; + mldl_cfg->mpu_gyro_cfg->clk_src = MPU_CLK_SEL_PLLGYROZ; + mldl_cfg->mpu_gyro_cfg->lpf = MPU_FILTER_42HZ; + mldl_cfg->mpu_gyro_cfg->full_scale = MPU_FS_2000DPS; + mldl_cfg->mpu_gyro_cfg->divider = 4; + mldl_cfg->mpu_gyro_cfg->dmp_enable = 1; + mldl_cfg->mpu_gyro_cfg->fifo_enable = 1; + mldl_cfg->mpu_gyro_cfg->ext_sync = 0; + mldl_cfg->mpu_gyro_cfg->dmp_cfg1 = 0; + mldl_cfg->mpu_gyro_cfg->dmp_cfg2 = 0; + mldl_cfg->inv_mpu_state->status = + MPU_DMP_IS_SUSPENDED | + MPU_GYRO_IS_SUSPENDED | + MPU_ACCEL_IS_SUSPENDED | + MPU_COMPASS_IS_SUSPENDED | + MPU_PRESSURE_IS_SUSPENDED | + MPU_DEVICE_IS_SUSPENDED; + mldl_cfg->inv_mpu_state->i2c_slaves_enabled = 0; + mldl_cfg->inv_mpu_state->accel_reactive = false; + mldl_cfg->inv_mpu_state->use_accel_reactive = false; + + slave_handle[EXT_SLAVE_TYPE_GYROSCOPE] = gyro_handle; + slave_handle[EXT_SLAVE_TYPE_ACCEL] = accel_handle; + slave_handle[EXT_SLAVE_TYPE_COMPASS] = compass_handle; + slave_handle[EXT_SLAVE_TYPE_PRESSURE] = pressure_handle; + + if (mldl_cfg->mpu_chip_info->addr == 0) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + /* + * Reset, + * Take the DMP out of sleep, and + * read the product_id, sillicon rev and whoami + */ + mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_BYPASSED; + result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, true, + INV_THREE_AXIS_GYRO); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_get_silicon_rev(mldl_cfg, gyro_handle); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Get the factory temperature compensation offsets */ + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_XG_OFFS_TC, 1, + &mldl_cfg->mpu_offsets->tc[0]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_YG_OFFS_TC, 1, + &mldl_cfg->mpu_offsets->tc[1]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_ZG_OFFS_TC, 1, + &mldl_cfg->mpu_offsets->tc[2]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Into bypass mode before sleeping and calling the slaves init */ + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, true); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_mpu_set_level_shifter_bit(mldl_cfg, gyro_handle, + mldl_cfg->pdata->level_shifter); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + for (ii = 0; ii < GYRO_NUM_AXES; ii++) { + mldl_cfg->mpu_offsets->tc[ii] = + (mldl_cfg->mpu_offsets->tc[ii] & BITS_XG_OFFS_TC) >> 1; + } + +#if INV_CACHE_DMP != 0 + result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, false, 0); +#endif + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + + return result; + +} + +/** + * Close the mpu interface + * + * @mldl_cfg pointer to the configuration structure + * @mlsl_handle pointer to the serial layer handle + * + * @return INV_SUCCESS or non-zero error code + */ +int inv_mpu_close(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle) +{ + return 0; +} + +static int inv_mpu_lp_mode(void *mlsl_handle, + struct ext_slave_platform_data *pdata, int enable) +{ + unsigned char data; + int result = 0; + struct motion_int_data *mot_data = &motion_int_data; + pr_info("%s set lp mode: %d\n", __func__, enable); + if (enable) { + inv_serial_read(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, 2, + mot_data->pwr_mnt); + inv_serial_read(mlsl_handle, pdata->address, + MPUREG_CONFIG, 1, &mot_data->cfg); + inv_serial_read(mlsl_handle, pdata->address, + MPUREG_ACCEL_CONFIG, 1, + &mot_data->accel_cfg); + inv_serial_read(mlsl_handle, pdata->address, + MPUREG_INT_ENABLE, 1, + &mot_data->int_cfg); + + /* initialize */ + data = 0x01; + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, data); + msleep(50); + /* mpu& accel config */ + data = mot_data->cfg; + data &= 0xF8; + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_CONFIG, data); + data = mot_data->accel_cfg; + data &= 0xF8; + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_CONFIG, data); + /* 3) set motion thr & dur */ + data = 0x40; + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_INT_ENABLE, data); + data = 0x02; + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_DUR, data); + data = 0x5; + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_THR, data); + /* set HPF */ + usleep_range(5000, 5000); + data = 0x7; + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_CONFIG, data); + + /* Steps to setup the lower power mode for PWM-2 register */ + data = mot_data->pwr_mnt[1]; + data |= (BITS_LPA_WAKE_10HZ); + data |= 0x07; + data &= ~(BIT_STBY_ZA); + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, data); + data = mot_data->pwr_mnt[0]; + data |= 0x20; /* Set the cycle bit to be 1. LOW POWER MODE */ + data &= ~0x08; /* Clear the temp disp bit. */ + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, data & ~BIT_SLEEP); + } else { + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_CONFIG, mot_data->cfg); + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_CONFIG, + mot_data->accel_cfg); + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_INT_ENABLE, + mot_data->int_cfg); + data = 0xff; + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_DUR, data); + data = 0xff; + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_ACCEL_MOT_THR, data); + inv_serial_read(mlsl_handle, pdata->address, + MPUREG_INT_ENABLE, 1, &data); + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_1, + mot_data->pwr_mnt[0]); + inv_serial_single_write(mlsl_handle, pdata->address, + MPUREG_PWR_MGMT_2, + mot_data->pwr_mnt[1]); + } + + mot_data->is_set = enable; + + return result; +} + +/** + * @brief resume the MPU device and all the other sensor + * devices from their low power state. + * + * @mldl_cfg + * pointer to the configuration structure + * @gyro_handle + * the main file handle to the MPU device. + * @accel_handle + * an handle to the accelerometer device, if sitting + * onto a separate bus. Can match mlsl_handle if + * the accelerometer device operates on the same + * primary bus of MPU. + * @compass_handle + * an handle to the compass device, if sitting + * onto a separate bus. Can match mlsl_handle if + * the compass device operates on the same + * primary bus of MPU. + * @pressure_handle + * an handle to the pressure sensor device, if sitting + * onto a separate bus. Can match mlsl_handle if + * the pressure sensor device operates on the same + * primary bus of MPU. + * @resume_gyro + * whether resuming the gyroscope device is + * actually needed (if the device supports low power + * mode of some sort). + * @resume_accel + * whether resuming the accelerometer device is + * actually needed (if the device supports low power + * mode of some sort). + * @resume_compass + * whether resuming the compass device is + * actually needed (if the device supports low power + * mode of some sort). + * @resume_pressure + * whether resuming the pressure sensor device is + * actually needed (if the device supports low power + * mode of some sort). + * @return INV_SUCCESS or a non-zero error code. + */ +int inv_mpu_resume(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle, + unsigned long sensors) +{ + int result = INV_SUCCESS; + int ii; + bool resume_slave[EXT_SLAVE_NUM_TYPES]; + bool resume_dmp = sensors & INV_DMP_PROCESSOR; + void *slave_handle[EXT_SLAVE_NUM_TYPES]; + resume_slave[EXT_SLAVE_TYPE_GYROSCOPE] = + (sensors & (INV_X_GYRO | INV_Y_GYRO | INV_Z_GYRO)); + resume_slave[EXT_SLAVE_TYPE_ACCEL] = + sensors & INV_THREE_AXIS_ACCEL; + resume_slave[EXT_SLAVE_TYPE_COMPASS] = + sensors & INV_THREE_AXIS_COMPASS; + resume_slave[EXT_SLAVE_TYPE_PRESSURE] = + sensors & INV_THREE_AXIS_PRESSURE; + + slave_handle[EXT_SLAVE_TYPE_GYROSCOPE] = gyro_handle; + slave_handle[EXT_SLAVE_TYPE_ACCEL] = accel_handle; + slave_handle[EXT_SLAVE_TYPE_COMPASS] = compass_handle; + slave_handle[EXT_SLAVE_TYPE_PRESSURE] = pressure_handle; + pr_info("Sensors set: %lu\n", sensors); + + mldl_print_cfg(mldl_cfg); + + /* Skip the Gyro since slave[EXT_SLAVE_TYPE_GYROSCOPE] is NULL */ + for (ii = EXT_SLAVE_TYPE_ACCEL; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (resume_slave[ii] && + ((!mldl_cfg->slave[ii]) || + (!mldl_cfg->slave[ii]->resume))) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + } + + if ((resume_slave[EXT_SLAVE_TYPE_GYROSCOPE] || resume_dmp) + && ((mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_SUSPENDED) || + (mldl_cfg->inv_mpu_state->status & MPU_GYRO_NEEDS_CONFIG))) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = dmp_stop(mldl_cfg, gyro_handle); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = gyro_resume(mldl_cfg, gyro_handle, sensors); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!mldl_cfg->slave[ii] || + !mldl_cfg->pdata_slave[ii] || + !resume_slave[ii] || + !(mldl_cfg->inv_mpu_state->status & (1 << ii))) + continue; + + if (EXT_SLAVE_BUS_SECONDARY == + mldl_cfg->pdata_slave[ii]->bus) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, + true); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + result = mldl_cfg->slave[ii]->resume(slave_handle[ii], + mldl_cfg->slave[ii], + mldl_cfg->pdata_slave[ii]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status &= ~(1 << ii); + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (resume_dmp && + !(mldl_cfg->inv_mpu_state->status & (1 << ii)) && + mldl_cfg->pdata_slave[ii] && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata_slave[ii]->bus) { + result = mpu_set_slave(mldl_cfg, + gyro_handle, + mldl_cfg->slave[ii], + mldl_cfg->pdata_slave[ii], + mldl_cfg->slave[ii]->type); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + } + + /* Turn on the master i2c iterface if necessary */ + if (resume_dmp) { + result = mpu_set_i2c_bypass( + mldl_cfg, gyro_handle, + !(mldl_cfg->inv_mpu_state->i2c_slaves_enabled)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Now start */ + result = dmp_start(mldl_cfg, gyro_handle); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + mldl_cfg->inv_mpu_cfg->requested_sensors = sensors; + + return result; +} + +/** + * @brief suspend the MPU device and all the other sensor + * devices into their low power state. + * @mldl_cfg + * a pointer to the struct mldl_cfg internal data + * structure. + * @gyro_handle + * the main file handle to the MPU device. + * @accel_handle + * an handle to the accelerometer device, if sitting + * onto a separate bus. Can match gyro_handle if + * the accelerometer device operates on the same + * primary bus of MPU. + * @compass_handle + * an handle to the compass device, if sitting + * onto a separate bus. Can match gyro_handle if + * the compass device operates on the same + * primary bus of MPU. + * @pressure_handle + * an handle to the pressure sensor device, if sitting + * onto a separate bus. Can match gyro_handle if + * the pressure sensor device operates on the same + * primary bus of MPU. + * @accel + * whether suspending the accelerometer device is + * actually needed (if the device supports low power + * mode of some sort). + * @compass + * whether suspending the compass device is + * actually needed (if the device supports low power + * mode of some sort). + * @pressure + * whether suspending the pressure sensor device is + * actually needed (if the device supports low power + * mode of some sort). + * @return INV_SUCCESS or a non-zero error code. + */ +int inv_mpu_suspend(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle, + unsigned long sensors) +{ + int result = INV_SUCCESS; + int ii; + struct ext_slave_descr **slave = mldl_cfg->slave; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + bool suspend_dmp = ((sensors & INV_DMP_PROCESSOR) == INV_DMP_PROCESSOR); + bool suspend_slave[EXT_SLAVE_NUM_TYPES]; + void *slave_handle[EXT_SLAVE_NUM_TYPES]; + pr_info("Sensors unset: %lu\n", sensors); + suspend_slave[EXT_SLAVE_TYPE_GYROSCOPE] = + ((sensors & (INV_X_GYRO | INV_Y_GYRO | INV_Z_GYRO)) + == (INV_X_GYRO | INV_Y_GYRO | INV_Z_GYRO)); + suspend_slave[EXT_SLAVE_TYPE_ACCEL] = + ((sensors & INV_THREE_AXIS_ACCEL) == INV_THREE_AXIS_ACCEL); + suspend_slave[EXT_SLAVE_TYPE_COMPASS] = + ((sensors & INV_THREE_AXIS_COMPASS) == INV_THREE_AXIS_COMPASS); + suspend_slave[EXT_SLAVE_TYPE_PRESSURE] = + ((sensors & INV_THREE_AXIS_PRESSURE) == + INV_THREE_AXIS_PRESSURE); + + slave_handle[EXT_SLAVE_TYPE_GYROSCOPE] = gyro_handle; + slave_handle[EXT_SLAVE_TYPE_ACCEL] = accel_handle; + slave_handle[EXT_SLAVE_TYPE_COMPASS] = compass_handle; + slave_handle[EXT_SLAVE_TYPE_PRESSURE] = pressure_handle; + + if (suspend_dmp) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = dmp_stop(mldl_cfg, gyro_handle); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + /* Gyro */ + if (suspend_slave[EXT_SLAVE_TYPE_GYROSCOPE]) { + result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, false, + ((~sensors) & INV_ALL_SENSORS)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + bool is_suspended = mldl_cfg->inv_mpu_state->status & (1 << ii); + if (!slave[ii] || !pdata_slave[ii] || + is_suspended || !suspend_slave[ii]) + continue; + + if (EXT_SLAVE_BUS_SECONDARY == pdata_slave[ii]->bus) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + result = slave[ii]->suspend(slave_handle[ii], + slave[ii], + pdata_slave[ii]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (EXT_SLAVE_BUS_SECONDARY == pdata_slave[ii]->bus) { + result = mpu_set_slave(mldl_cfg, gyro_handle, + NULL, NULL, + slave[ii]->type); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + mldl_cfg->inv_mpu_state->status |= (1 << ii); + } + + /* Re-enable the i2c master if there are configured slaves and DMP */ + if (!suspend_dmp) { + result = mpu_set_i2c_bypass( + mldl_cfg, gyro_handle, + !(mldl_cfg->inv_mpu_state->i2c_slaves_enabled)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + mldl_cfg->inv_mpu_cfg->requested_sensors = (~sensors) & INV_ALL_SENSORS; + + if (mldl_cfg->inv_mpu_state->accel_reactive && + !mldl_cfg->inv_mpu_cfg->requested_sensors) { + inv_mpu_lp_mode(gyro_handle, + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL], + true); + } + + return result; +} + +int inv_mpu_slave_read(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result; + int bypass_result; + int remain_bypassed = true; + + if (NULL == slave || NULL == slave->read) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_CONFIGURATION); + return INV_ERROR_INVALID_CONFIGURATION; + } + + if ((EXT_SLAVE_BUS_SECONDARY == pdata->bus) + && (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_BYPASSED))) { + remain_bypassed = false; + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + result = slave->read(slave_handle, slave, pdata, data); + + if (!remain_bypassed) { + bypass_result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 0); + if (bypass_result) { + LOG_RESULT_LOCATION(bypass_result); + return bypass_result; + } + } + return result; +} + +int inv_mpu_slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_config *data, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + int remain_bypassed = true; + + if (NULL == slave || NULL == slave->config) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_CONFIGURATION); + return INV_ERROR_INVALID_CONFIGURATION; + } + + if (data->apply && (EXT_SLAVE_BUS_SECONDARY == pdata->bus) + && (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_BYPASSED))) { + remain_bypassed = false; + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + result = slave->config(slave_handle, slave, pdata, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (!remain_bypassed) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +int inv_mpu_get_slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_config *data, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + int remain_bypassed = true; + + if (NULL == slave || NULL == slave->get_config) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_CONFIGURATION); + return INV_ERROR_INVALID_CONFIGURATION; + } + + if (data->apply && (EXT_SLAVE_BUS_SECONDARY == pdata->bus) + && (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_BYPASSED))) { + remain_bypassed = false; + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + result = slave->get_config(slave_handle, slave, pdata, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (!remain_bypassed) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/mldl_cfg.h b/drivers/misc/inv_mpu/mldl_cfg.h new file mode 100644 index 00000000000..ccdc8c0b019 --- /dev/null +++ b/drivers/misc/inv_mpu/mldl_cfg.h @@ -0,0 +1,384 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +/** + * @addtogroup MLDL + * + * @{ + * @file mldl_cfg.h + * @brief The Motion Library Driver Layer Configuration header file. + */ + +#ifndef __MLDL_CFG_H__ +#define __MLDL_CFG_H__ + +#include "mltypes.h" +#include "mlsl.h" +#include +#include "mpu6050b1.h" + +#include "log.h" + +/************************************************************************* + * Sensors Bit definitions + *************************************************************************/ + +#define INV_X_GYRO (0x0001) +#define INV_Y_GYRO (0x0002) +#define INV_Z_GYRO (0x0004) +#define INV_DMP_PROCESSOR (0x0008) + +#define INV_X_ACCEL (0x0010) +#define INV_Y_ACCEL (0x0020) +#define INV_Z_ACCEL (0x0040) + +#define INV_X_COMPASS (0x0080) +#define INV_Y_COMPASS (0x0100) +#define INV_Z_COMPASS (0x0200) + +#define INV_X_PRESSURE (0x0300) +#define INV_Y_PRESSURE (0x0800) +#define INV_Z_PRESSURE (0x1000) + +#define INV_TEMPERATURE (0x2000) +#define INV_TIME (0x4000) + +#define INV_THREE_AXIS_GYRO (0x000F) +#define INV_THREE_AXIS_ACCEL (0x0070) +#define INV_THREE_AXIS_COMPASS (0x0380) +#define INV_THREE_AXIS_PRESSURE (0x1C00) + +#define INV_FIVE_AXIS (0x007B) +#define INV_SIX_AXIS_GYRO_ACCEL (0x007F) +#define INV_SIX_AXIS_ACCEL_COMPASS (0x03F0) +#define INV_NINE_AXIS (0x03FF) +#define INV_ALL_SENSORS (0x7FFF) + +#define MPL_PROD_KEY(ver, rev) (ver * 100 + rev) + +/* -------------------------------------------------------------------------- */ +struct mpu_ram { + __u16 length; + __u8 *ram; +}; + +struct mpu_gyro_cfg { + __u8 int_config; + __u8 ext_sync; + __u8 full_scale; + __u8 lpf; + __u8 clk_src; + __u8 divider; + __u8 dmp_enable; + __u8 fifo_enable; + __u8 dmp_cfg1; + __u8 dmp_cfg2; +}; + +/* Offset registers that can be calibrated */ +struct mpu_offsets { + __u8 tc[GYRO_NUM_AXES]; + __u16 gyro[GYRO_NUM_AXES]; +}; + +/* Chip related information that can be read and verified */ +struct mpu_chip_info { + __u8 addr; + __u8 product_revision; + __u8 silicon_revision; + __u8 product_id; + __u16 gyro_sens_trim; + /* Only used for MPU6050 */ + __u16 accel_sens_trim; +}; + + +struct inv_mpu_cfg { + __u32 requested_sensors; + __u8 ignore_system_suspend; +}; + +#define MPU_GYRO_IS_SUSPENDED (0x01 << EXT_SLAVE_TYPE_GYROSCOPE) +#define MPU_ACCEL_IS_SUSPENDED (0x01 << EXT_SLAVE_TYPE_ACCEL) +#define MPU_COMPASS_IS_SUSPENDED (0x01 << EXT_SLAVE_TYPE_COMPASS) +#define MPU_PRESSURE_IS_SUSPENDED (0x01 << EXT_SLAVE_TYPE_PRESSURE) +#define MPU_GYRO_IS_BYPASSED (0x10) +#define MPU_DMP_IS_SUSPENDED (0x20) +#define MPU_GYRO_NEEDS_CONFIG (0x40) +#define MPU_DEVICE_IS_SUSPENDED (0x80) + +/* Driver related state information */ +struct inv_mpu_state { + __u8 status; + /* 0-1 for 3050, bitfield of BIT_SLVx_DLY_EN, x = [0..4] */ + __u8 i2c_slaves_enabled; + bool accel_reactive; + bool use_accel_reactive; + bool reactive_factory; +}; + +/* Platform data for the MPU */ +struct mldl_cfg { + struct mpu_ram *mpu_ram; + struct mpu_gyro_cfg *mpu_gyro_cfg; + struct mpu_offsets *mpu_offsets; + struct mpu_chip_info *mpu_chip_info; + + /* MPU Related stored status and info */ + struct inv_mpu_cfg *inv_mpu_cfg; + struct inv_mpu_state *inv_mpu_state; + + /* Slave related information */ + struct ext_slave_descr *slave[EXT_SLAVE_NUM_TYPES]; + /* Platform Data */ + struct mpu_platform_data *pdata; + struct ext_slave_platform_data *pdata_slave[EXT_SLAVE_NUM_TYPES]; +}; + +/* -------------------------------------------------------------------------- */ + +int inv_mpu_open(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle); +int inv_mpu_close(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle); +int inv_mpu_resume(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle, + unsigned long sensors); +int inv_mpu_suspend(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle, + unsigned long sensors); +int inv_mpu_set_firmware(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, + const unsigned char *data, + int size); + +/* -------------------------------------------------------------------------- */ +/* Slave Read functions */ +int inv_mpu_slave_read(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data); +static inline int inv_mpu_read_accel(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, unsigned char *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_read( + mldl_cfg, gyro_handle, accel_handle, + mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL], + data); +} + +static inline int inv_mpu_read_compass(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *compass_handle, + unsigned char *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_read( + mldl_cfg, gyro_handle, compass_handle, + mldl_cfg->slave[EXT_SLAVE_TYPE_COMPASS], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_COMPASS], + data); +} + +static inline int inv_mpu_read_pressure(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *pressure_handle, + unsigned char *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_read( + mldl_cfg, gyro_handle, pressure_handle, + mldl_cfg->slave[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_PRESSURE], + data); +} + +int gyro_config(void *mlsl_handle, + struct mldl_cfg *mldl_cfg, + struct ext_slave_config *data); + +/* Slave Config functions */ +int inv_mpu_slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_config *data, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); +static inline int inv_mpu_config_accel(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_config( + mldl_cfg, gyro_handle, accel_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL]); +} + +static inline int inv_mpu_config_compass(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *compass_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_config( + mldl_cfg, gyro_handle, compass_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_COMPASS], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_COMPASS]); +} + +static inline int inv_mpu_config_pressure(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *pressure_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_config( + mldl_cfg, gyro_handle, pressure_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_PRESSURE]); +} + +int gyro_get_config(void *mlsl_handle, + struct mldl_cfg *mldl_cfg, + struct ext_slave_config *data); + +/* Slave get config functions */ +int inv_mpu_get_slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_config *data, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + +static inline int inv_mpu_get_accel_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_get_slave_config( + mldl_cfg, gyro_handle, accel_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL]); +} + +static inline int inv_mpu_get_compass_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *compass_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg || !(mldl_cfg->pdata)) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_get_slave_config( + mldl_cfg, gyro_handle, compass_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_COMPASS], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_COMPASS]); +} + +static inline int inv_mpu_get_pressure_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *pressure_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg || !(mldl_cfg->pdata)) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_get_slave_config( + mldl_cfg, gyro_handle, pressure_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_PRESSURE]); +} + +/* -------------------------------------------------------------------------- */ + +static inline +long inv_mpu_get_sampling_rate_hz(struct mpu_gyro_cfg *gyro_cfg) +{ + if (((gyro_cfg->lpf) == 0) || ((gyro_cfg->lpf) == 7)) + return 8000L / (gyro_cfg->divider + 1); + else + return 1000L / (gyro_cfg->divider + 1); +} + +static inline +long inv_mpu_get_sampling_period_us(struct mpu_gyro_cfg *gyro_cfg) +{ + if (((gyro_cfg->lpf) == 0) || ((gyro_cfg->lpf) == 7)) + return (long) (1000000L * (gyro_cfg->divider + 1)) / 8000L; + else + return (long) (1000000L * (gyro_cfg->divider + 1)) / 1000L; +} + +#endif /* __MLDL_CFG_H__ */ + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/mldl_print_cfg.c b/drivers/misc/inv_mpu/mldl_print_cfg.c new file mode 100644 index 00000000000..78d40904ec5 --- /dev/null +++ b/drivers/misc/inv_mpu/mldl_print_cfg.c @@ -0,0 +1,138 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +/** + * @addtogroup MLDL + * + * @{ + * @file mldl_print_cfg.c + * @brief The Motion Library Driver Layer. + */ + +#include +#include "mldl_cfg.h" +#include "mlsl.h" +#include + +#include "log.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "mldl_print_cfg:" + +#undef MPL_LOG_NDEBUG +#define MPL_LOG_NDEBUG 1 + +void mldl_print_cfg(struct mldl_cfg *mldl_cfg) +{ + struct mpu_gyro_cfg *mpu_gyro_cfg = mldl_cfg->mpu_gyro_cfg; + struct mpu_offsets *mpu_offsets = mldl_cfg->mpu_offsets; + struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info; + struct inv_mpu_cfg *inv_mpu_cfg = mldl_cfg->inv_mpu_cfg; + struct inv_mpu_state *inv_mpu_state = mldl_cfg->inv_mpu_state; + struct ext_slave_descr **slave = mldl_cfg->slave; + struct mpu_platform_data *pdata = mldl_cfg->pdata; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + /* mpu_gyro_cfg */ + MPL_LOGV("int_config = %02x\n", mpu_gyro_cfg->int_config); + MPL_LOGV("ext_sync = %02x\n", mpu_gyro_cfg->ext_sync); + MPL_LOGV("full_scale = %02x\n", mpu_gyro_cfg->full_scale); + MPL_LOGV("lpf = %02x\n", mpu_gyro_cfg->lpf); + MPL_LOGV("clk_src = %02x\n", mpu_gyro_cfg->clk_src); + MPL_LOGV("divider = %02x\n", mpu_gyro_cfg->divider); + MPL_LOGV("dmp_enable = %02x\n", mpu_gyro_cfg->dmp_enable); + MPL_LOGV("fifo_enable = %02x\n", mpu_gyro_cfg->fifo_enable); + MPL_LOGV("dmp_cfg1 = %02x\n", mpu_gyro_cfg->dmp_cfg1); + MPL_LOGV("dmp_cfg2 = %02x\n", mpu_gyro_cfg->dmp_cfg2); + /* mpu_offsets */ + MPL_LOGV("tc[0] = %02x\n", mpu_offsets->tc[0]); + MPL_LOGV("tc[1] = %02x\n", mpu_offsets->tc[1]); + MPL_LOGV("tc[2] = %02x\n", mpu_offsets->tc[2]); + MPL_LOGV("gyro[0] = %04x\n", mpu_offsets->gyro[0]); + MPL_LOGV("gyro[1] = %04x\n", mpu_offsets->gyro[1]); + MPL_LOGV("gyro[2] = %04x\n", mpu_offsets->gyro[2]); + + /* mpu_chip_info */ + MPL_LOGV("addr = %02x\n", mldl_cfg->mpu_chip_info->addr); + + MPL_LOGV("silicon_revision = %02x\n", mpu_chip_info->silicon_revision); + MPL_LOGV("product_revision = %02x\n", mpu_chip_info->product_revision); + MPL_LOGV("product_id = %02x\n", mpu_chip_info->product_id); + MPL_LOGV("gyro_sens_trim = %02x\n", mpu_chip_info->gyro_sens_trim); + MPL_LOGV("accel_sens_trim = %02x\n", mpu_chip_info->accel_sens_trim); + + MPL_LOGV("requested_sensors = %04x\n", inv_mpu_cfg->requested_sensors); + MPL_LOGV("ignore_system_suspend= %04x\n", + inv_mpu_cfg->ignore_system_suspend); + MPL_LOGV("status = %04x\n", inv_mpu_state->status); + MPL_LOGV("i2c_slaves_enabled= %04x\n", + inv_mpu_state->i2c_slaves_enabled); + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!slave[ii]) + continue; + MPL_LOGV("SLAVE %d:\n", ii); + MPL_LOGV(" suspend = %02x\n", (int)slave[ii]->suspend); + MPL_LOGV(" resume = %02x\n", (int)slave[ii]->resume); + MPL_LOGV(" read = %02x\n", (int)slave[ii]->read); + MPL_LOGV(" type = %02x\n", slave[ii]->type); + MPL_LOGV(" reg = %02x\n", slave[ii]->read_reg); + MPL_LOGV(" len = %02x\n", slave[ii]->read_len); + MPL_LOGV(" endian = %02x\n", slave[ii]->endian); + MPL_LOGV(" range.mantissa= %02x\n", + slave[ii]->range.mantissa); + MPL_LOGV(" range.fraction= %02x\n", + slave[ii]->range.fraction); + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + continue; + MPL_LOGV("PDATA_SLAVE[%d]\n", ii); + MPL_LOGV(" irq = %02x\n", pdata_slave[ii]->irq); + MPL_LOGV(" adapt_num = %02x\n", pdata_slave[ii]->adapt_num); + MPL_LOGV(" bus = %02x\n", pdata_slave[ii]->bus); + MPL_LOGV(" address = %02x\n", pdata_slave[ii]->address); + MPL_LOGV(" orientation=\n" + " %2d %2d %2d\n" + " %2d %2d %2d\n" + " %2d %2d %2d\n", + pdata_slave[ii]->orientation[0], + pdata_slave[ii]->orientation[1], + pdata_slave[ii]->orientation[2], + pdata_slave[ii]->orientation[3], + pdata_slave[ii]->orientation[4], + pdata_slave[ii]->orientation[5], + pdata_slave[ii]->orientation[6], + pdata_slave[ii]->orientation[7], + pdata_slave[ii]->orientation[8]); + } + + MPL_LOGV("pdata->int_config = %02x\n", pdata->int_config); + MPL_LOGV("pdata->level_shifter = %02x\n", pdata->level_shifter); + MPL_LOGV("pdata->orientation =\n" + " %2d %2d %2d\n" + " %2d %2d %2d\n" + " %2d %2d %2d\n", + pdata->orientation[0], pdata->orientation[1], + pdata->orientation[2], pdata->orientation[3], + pdata->orientation[4], pdata->orientation[5], + pdata->orientation[6], pdata->orientation[7], + pdata->orientation[8]); +} diff --git a/drivers/misc/inv_mpu/mldl_print_cfg.h b/drivers/misc/inv_mpu/mldl_print_cfg.h new file mode 100644 index 00000000000..2e1911440cc --- /dev/null +++ b/drivers/misc/inv_mpu/mldl_print_cfg.h @@ -0,0 +1,38 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +/** + * @defgroup + * @brief + * + * @{ + * @file mldl_print_cfg.h + * @brief + * + * + */ +#ifndef __MLDL_PRINT_CFG__ +#define __MLDL_PRINT_CFG__ + +#include "mldl_cfg.h" + + +void mldl_print_cfg(struct mldl_cfg *mldl_cfg); + +#endif /* __MLDL_PRINT_CFG__ */ diff --git a/drivers/misc/inv_mpu/mlsl-kernel.c b/drivers/misc/inv_mpu/mlsl-kernel.c new file mode 100644 index 00000000000..330a8bd4e9a --- /dev/null +++ b/drivers/misc/inv_mpu/mlsl-kernel.c @@ -0,0 +1,421 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +#include "mlsl.h" +#include +#include +#include "log.h" +#include "mpu6050b1.h" + +static int inv_i2c_write(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned int len, unsigned char const *data) +{ + struct i2c_msg msgs[1]; + int res; + + if (!data || !i2c_adap) { + LOG_RESULT_LOCATION(-EINVAL); + return -EINVAL; + } + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = (unsigned char *)data; + msgs[0].len = len; + + res = i2c_transfer(i2c_adap, msgs, 1); + if (res < 1) { + if (res == 0) + res = -EIO; + LOG_RESULT_LOCATION(res); + return res; + } else + return 0; +} + +static int inv_i2c_write_register(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned char reg, unsigned char value) +{ + unsigned char data[2]; + + data[0] = reg; + data[1] = value; + return inv_i2c_write(i2c_adap, address, 2, data); +} + +static int inv_i2c_read(struct i2c_adapter *i2c_adap, + unsigned char address, unsigned char reg, + unsigned int len, unsigned char *data) +{ + struct i2c_msg msgs[2]; + int res; + + if (!data || !i2c_adap) { + LOG_RESULT_LOCATION(-EINVAL); + return -EINVAL; + } + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = ® + msgs[0].len = 1; + + msgs[1].addr = address; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = data; + msgs[1].len = len; + + res = i2c_transfer(i2c_adap, msgs, 2); + if (res < 2) { + if (res >= 0) + res = -EIO; + LOG_RESULT_LOCATION(res); + return res; + } else + return 0; +} + +static int mpu_memory_read(struct i2c_adapter *i2c_adap, + unsigned char mpu_addr, + unsigned short mem_addr, + unsigned int len, unsigned char *data) +{ + unsigned char bank[2]; + unsigned char addr[2]; + unsigned char buf; + + struct i2c_msg msgs[4]; + int res; + + if (!data || !i2c_adap) { + LOG_RESULT_LOCATION(-EINVAL); + return -EINVAL; + } + + bank[0] = MPUREG_BANK_SEL; + bank[1] = mem_addr >> 8; + + addr[0] = MPUREG_MEM_START_ADDR; + addr[1] = mem_addr & 0xFF; + + buf = MPUREG_MEM_R_W; + + /* write message */ + msgs[0].addr = mpu_addr; + msgs[0].flags = 0; + msgs[0].buf = bank; + msgs[0].len = sizeof(bank); + + msgs[1].addr = mpu_addr; + msgs[1].flags = 0; + msgs[1].buf = addr; + msgs[1].len = sizeof(addr); + + msgs[2].addr = mpu_addr; + msgs[2].flags = 0; + msgs[2].buf = &buf; + msgs[2].len = 1; + + msgs[3].addr = mpu_addr; + msgs[3].flags = I2C_M_RD; + msgs[3].buf = data; + msgs[3].len = len; + + res = i2c_transfer(i2c_adap, msgs, 4); + if (res != 4) { + if (res >= 0) + res = -EIO; + LOG_RESULT_LOCATION(res); + return res; + } else + return 0; +} + +static int mpu_memory_write(struct i2c_adapter *i2c_adap, + unsigned char mpu_addr, + unsigned short mem_addr, + unsigned int len, unsigned char const *data) +{ + unsigned char bank[2]; + unsigned char addr[2]; + unsigned char buf[513]; + + struct i2c_msg msgs[3]; + int res; + + if (!data || !i2c_adap) { + LOG_RESULT_LOCATION(-EINVAL); + return -EINVAL; + } + if (len >= (sizeof(buf) - 1)) { + LOG_RESULT_LOCATION(-ENOMEM); + return -ENOMEM; + } + + bank[0] = MPUREG_BANK_SEL; + bank[1] = mem_addr >> 8; + + addr[0] = MPUREG_MEM_START_ADDR; + addr[1] = mem_addr & 0xFF; + + buf[0] = MPUREG_MEM_R_W; + memcpy(buf + 1, data, len); + + /* write message */ + msgs[0].addr = mpu_addr; + msgs[0].flags = 0; + msgs[0].buf = bank; + msgs[0].len = sizeof(bank); + + msgs[1].addr = mpu_addr; + msgs[1].flags = 0; + msgs[1].buf = addr; + msgs[1].len = sizeof(addr); + + msgs[2].addr = mpu_addr; + msgs[2].flags = 0; + msgs[2].buf = (unsigned char *)buf; + msgs[2].len = len + 1; + + res = i2c_transfer(i2c_adap, msgs, 3); + if (res != 3) { + if (res >= 0) + res = -EIO; + LOG_RESULT_LOCATION(res); + return res; + } else + return 0; +} + +int inv_serial_single_write( + void *sl_handle, + unsigned char slave_addr, + unsigned char register_addr, + unsigned char data) +{ + return inv_i2c_write_register((struct i2c_adapter *)sl_handle, + slave_addr, register_addr, data); +} +EXPORT_SYMBOL(inv_serial_single_write); + +int inv_serial_write( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char const *data) +{ + int result; + const unsigned short data_length = length - 1; + const unsigned char start_reg_addr = data[0]; + unsigned char i2c_write[SERIAL_MAX_TRANSFER_SIZE + 1]; + unsigned short bytes_written = 0; + + while (bytes_written < data_length) { + unsigned short this_len = min(SERIAL_MAX_TRANSFER_SIZE, + data_length - bytes_written); + if (bytes_written == 0) { + result = inv_i2c_write((struct i2c_adapter *) + sl_handle, slave_addr, + 1 + this_len, data); + } else { + /* manually increment register addr between chunks */ + i2c_write[0] = start_reg_addr + bytes_written; + memcpy(&i2c_write[1], &data[1 + bytes_written], + this_len); + result = inv_i2c_write((struct i2c_adapter *) + sl_handle, slave_addr, + 1 + this_len, i2c_write); + } + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_written += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_write); + +int inv_serial_read( + void *sl_handle, + unsigned char slave_addr, + unsigned char register_addr, + unsigned short length, + unsigned char *data) +{ + int result; + unsigned short bytes_read = 0; + + if ((slave_addr & 0x7E) == DEFAULT_MPU_SLAVEADDR + && (register_addr == MPUREG_FIFO_R_W || + register_addr == MPUREG_MEM_R_W)) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + while (bytes_read < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_read); + result = inv_i2c_read((struct i2c_adapter *)sl_handle, + slave_addr, register_addr + bytes_read, + this_len, &data[bytes_read]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_read += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_read); + +int inv_serial_write_mem( + void *sl_handle, + unsigned char slave_addr, + unsigned short mem_addr, + unsigned short length, + unsigned char const *data) +{ + int result; + unsigned short bytes_written = 0; + + if ((mem_addr & 0xFF) + length > MPU_MEM_BANK_SIZE) { + pr_err("memory read length (%d B) extends beyond its" + " limits (%d) if started at location %d\n", length, + MPU_MEM_BANK_SIZE, mem_addr & 0xFF); + return INV_ERROR_INVALID_PARAMETER; + } + while (bytes_written < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_written); + result = mpu_memory_write((struct i2c_adapter *)sl_handle, + slave_addr, mem_addr + bytes_written, + this_len, &data[bytes_written]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_written += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_write_mem); + +int inv_serial_read_mem( + void *sl_handle, + unsigned char slave_addr, + unsigned short mem_addr, + unsigned short length, + unsigned char *data) +{ + int result; + unsigned short bytes_read = 0; + + if ((mem_addr & 0xFF) + length > MPU_MEM_BANK_SIZE) { + printk + ("memory read length (%d B) extends beyond its limits (%d) " + "if started at location %d\n", length, + MPU_MEM_BANK_SIZE, mem_addr & 0xFF); + return INV_ERROR_INVALID_PARAMETER; + } + while (bytes_read < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_read); + result = + mpu_memory_read((struct i2c_adapter *)sl_handle, + slave_addr, mem_addr + bytes_read, + this_len, &data[bytes_read]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_read += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_read_mem); + +int inv_serial_write_fifo( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char const *data) +{ + int result; + unsigned char i2c_write[SERIAL_MAX_TRANSFER_SIZE + 1]; + unsigned short bytes_written = 0; + + if (length > FIFO_HW_SIZE) { + printk(KERN_ERR + "maximum fifo write length is %d\n", FIFO_HW_SIZE); + return INV_ERROR_INVALID_PARAMETER; + } + while (bytes_written < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_written); + i2c_write[0] = MPUREG_FIFO_R_W; + memcpy(&i2c_write[1], &data[bytes_written], this_len); + result = inv_i2c_write((struct i2c_adapter *)sl_handle, + slave_addr, this_len + 1, i2c_write); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_written += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_write_fifo); + +int inv_serial_read_fifo( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char *data) +{ + int result; + unsigned short bytes_read = 0; + + if (length > FIFO_HW_SIZE) { + printk(KERN_ERR + "maximum fifo read length is %d\n", FIFO_HW_SIZE); + return INV_ERROR_INVALID_PARAMETER; + } + while (bytes_read < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_read); + result = inv_i2c_read((struct i2c_adapter *)sl_handle, + slave_addr, MPUREG_FIFO_R_W, this_len, + &data[bytes_read]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_read += this_len; + } + + return 0; +} +EXPORT_SYMBOL(inv_serial_read_fifo); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/mlsl.h b/drivers/misc/inv_mpu/mlsl.h new file mode 100644 index 00000000000..3fc6be9248f --- /dev/null +++ b/drivers/misc/inv_mpu/mlsl.h @@ -0,0 +1,193 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +#ifndef __MLSL_H__ +#define __MLSL_H__ + +/** + * @defgroup MLSL + * @brief Motion Library - Serial Layer. + * The Motion Library System Layer provides the Motion Library + * with the communication interface to the hardware. + * + * The communication interface is assumed to support serial + * transfers in burst of variable length up to + * SERIAL_MAX_TRANSFER_SIZE. + * The default value for SERIAL_MAX_TRANSFER_SIZE is 128 bytes. + * Transfers of length greater than SERIAL_MAX_TRANSFER_SIZE, will + * be subdivided in smaller transfers of length <= + * SERIAL_MAX_TRANSFER_SIZE. + * The SERIAL_MAX_TRANSFER_SIZE definition can be modified to + * overcome any host processor transfer size limitation down to + * 1 B, the minimum. + * An higher value for SERIAL_MAX_TRANSFER_SIZE will favor + * performance and efficiency while requiring higher resource usage + * (mostly buffering). A smaller value will increase overhead and + * decrease efficiency but allows to operate with more resource + * constrained processor and master serial controllers. + * The SERIAL_MAX_TRANSFER_SIZE definition can be found in the + * mlsl.h header file and master serial controllers. + * The SERIAL_MAX_TRANSFER_SIZE definition can be found in the + * mlsl.h header file. + * + * @{ + * @file mlsl.h + * @brief The Motion Library System Layer. + * + */ + +#include "mltypes.h" +#include + + +/* acceleration data */ +struct acc_data { + s16 x; + s16 y; + s16 z; +}; + +/* + * NOTE : to properly support Yamaha compass reads, + * the max transfer size should be at least 9 B. + * Length in bytes, typically a power of 2 >= 2 + */ +#define SERIAL_MAX_TRANSFER_SIZE 128 + + +/** + * inv_serial_single_write() - used to write a single byte of data. + * @sl_handle pointer to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @register_addr Register address to write. + * @data Single byte of data to write. + * + * It is called by the MPL to write a single byte of data to the MPU. + * + * returns INV_SUCCESS if successful, a non-zero error code otherwise. + */ +int inv_serial_single_write( + void *sl_handle, + unsigned char slave_addr, + unsigned char register_addr, + unsigned char data); + +/** + * inv_serial_write() - used to write multiple bytes of data to registers. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @register_addr Register address to write. + * @length Length of burst of data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS if successful, a non-zero error code otherwise. + */ +int inv_serial_write( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char const *data); + +/** + * inv_serial_read() - used to read multiple bytes of data from registers. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @register_addr Register address to read. + * @length Length of burst of data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_read( + void *sl_handle, + unsigned char slave_addr, + unsigned char register_addr, + unsigned short length, + unsigned char *data); + +/** + * inv_serial_read_mem() - used to read multiple bytes of data from the memory. + * This should be sent by I2C or SPI. + * + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @mem_addr The location in the memory to read from. + * @length Length of burst data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_read_mem( + void *sl_handle, + unsigned char slave_addr, + unsigned short mem_addr, + unsigned short length, + unsigned char *data); + +/** + * inv_serial_write_mem() - used to write multiple bytes of data to the memory. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @mem_addr The location in the memory to write to. + * @length Length of burst data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_write_mem( + void *sl_handle, + unsigned char slave_addr, + unsigned short mem_addr, + unsigned short length, + unsigned char const *data); + +/** + * inv_serial_read_fifo() - used to read multiple bytes of data from the fifo. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @length Length of burst of data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_read_fifo( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char *data); + +/** + * inv_serial_write_fifo() - used to write multiple bytes of data to the fifo. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @length Length of burst of data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_write_fifo( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char const *data); + +/** + * @} + */ +#endif /* __MLSL_H__ */ diff --git a/drivers/misc/inv_mpu/mltypes.h b/drivers/misc/inv_mpu/mltypes.h new file mode 100644 index 00000000000..a249f93be3e --- /dev/null +++ b/drivers/misc/inv_mpu/mltypes.h @@ -0,0 +1,234 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +/** + * @defgroup MLERROR + * @brief Definition of the error codes used within the MPL and + * returned to the user. + * Every function tries to return a meaningful error code basing + * on the occuring error condition. The error code is numeric. + * + * The available error codes and their associated values are: + * - (0) INV_SUCCESS + * - (32) INV_ERROR + * - (22 / EINVAL) INV_ERROR_INVALID_PARAMETER + * - (1 / EPERM) INV_ERROR_FEATURE_NOT_ENABLED + * - (36) INV_ERROR_FEATURE_NOT_IMPLEMENTED + * - (38) INV_ERROR_DMP_NOT_STARTED + * - (39) INV_ERROR_DMP_STARTED + * - (40) INV_ERROR_NOT_OPENED + * - (41) INV_ERROR_OPENED + * - (19 / ENODEV) INV_ERROR_INVALID_MODULE + * - (12 / ENOMEM) INV_ERROR_MEMORY_EXAUSTED + * - (44) INV_ERROR_DIVIDE_BY_ZERO + * - (45) INV_ERROR_ASSERTION_FAILURE + * - (46) INV_ERROR_FILE_OPEN + * - (47) INV_ERROR_FILE_READ + * - (48) INV_ERROR_FILE_WRITE + * - (49) INV_ERROR_INVALID_CONFIGURATION + * - (52) INV_ERROR_SERIAL_CLOSED + * - (53) INV_ERROR_SERIAL_OPEN_ERROR + * - (54) INV_ERROR_SERIAL_READ + * - (55) INV_ERROR_SERIAL_WRITE + * - (56) INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED + * - (57) INV_ERROR_SM_TRANSITION + * - (58) INV_ERROR_SM_IMPROPER_STATE + * - (62) INV_ERROR_FIFO_OVERFLOW + * - (63) INV_ERROR_FIFO_FOOTER + * - (64) INV_ERROR_FIFO_READ_COUNT + * - (65) INV_ERROR_FIFO_READ_DATA + * - (72) INV_ERROR_MEMORY_SET + * - (82) INV_ERROR_LOG_MEMORY_ERROR + * - (83) INV_ERROR_LOG_OUTPUT_ERROR + * - (92) INV_ERROR_OS_BAD_PTR + * - (93) INV_ERROR_OS_BAD_HANDLE + * - (94) INV_ERROR_OS_CREATE_FAILED + * - (95) INV_ERROR_OS_LOCK_FAILED + * - (102) INV_ERROR_COMPASS_DATA_OVERFLOW + * - (103) INV_ERROR_COMPASS_DATA_UNDERFLOW + * - (104) INV_ERROR_COMPASS_DATA_NOT_READY + * - (105) INV_ERROR_COMPASS_DATA_ERROR + * - (107) INV_ERROR_CALIBRATION_LOAD + * - (108) INV_ERROR_CALIBRATION_STORE + * - (109) INV_ERROR_CALIBRATION_LEN + * - (110) INV_ERROR_CALIBRATION_CHECKSUM + * - (111) INV_ERROR_ACCEL_DATA_OVERFLOW + * - (112) INV_ERROR_ACCEL_DATA_UNDERFLOW + * - (113) INV_ERROR_ACCEL_DATA_NOT_READY + * - (114) INV_ERROR_ACCEL_DATA_ERROR + * + * The available warning codes and their associated values are: + * - (115) INV_WARNING_MOTION_RACE + * - (116) INV_WARNING_QUAT_TRASHED + * + * @{ + * @file mltypes.h + * @} + */ + +#ifndef MLTYPES_H +#define MLTYPES_H + +#include +#include + + + + +/*--------------------------- + * ML Defines + *--------------------------*/ + +#ifndef NULL +#define NULL 0 +#endif + +/* - ML Errors. - */ +#define ERROR_NAME(x) (#x) +#define ERROR_CHECK_FIRST(first, x) \ + { if (INV_SUCCESS == first) first = x; } + +#define INV_SUCCESS (0) +/* Generic Error code. Proprietary Error Codes only */ +#define INV_ERROR_BASE (0x20) +#define INV_ERROR (INV_ERROR_BASE) + +/* Compatibility and other generic error codes */ +#define INV_ERROR_INVALID_PARAMETER (EINVAL) +#define INV_ERROR_FEATURE_NOT_ENABLED (EPERM) +#define INV_ERROR_FEATURE_NOT_IMPLEMENTED (INV_ERROR_BASE + 4) +#define INV_ERROR_DMP_NOT_STARTED (INV_ERROR_BASE + 6) +#define INV_ERROR_DMP_STARTED (INV_ERROR_BASE + 7) +#define INV_ERROR_NOT_OPENED (INV_ERROR_BASE + 8) +#define INV_ERROR_OPENED (INV_ERROR_BASE + 9) +#define INV_ERROR_INVALID_MODULE (ENODEV) +#define INV_ERROR_MEMORY_EXAUSTED (ENOMEM) +#define INV_ERROR_DIVIDE_BY_ZERO (INV_ERROR_BASE + 12) +#define INV_ERROR_ASSERTION_FAILURE (INV_ERROR_BASE + 13) +#define INV_ERROR_FILE_OPEN (INV_ERROR_BASE + 14) +#define INV_ERROR_FILE_READ (INV_ERROR_BASE + 15) +#define INV_ERROR_FILE_WRITE (INV_ERROR_BASE + 16) +#define INV_ERROR_INVALID_CONFIGURATION (INV_ERROR_BASE + 17) + +/* Serial Communication */ +#define INV_ERROR_SERIAL_CLOSED (INV_ERROR_BASE + 20) +#define INV_ERROR_SERIAL_OPEN_ERROR (INV_ERROR_BASE + 21) +#define INV_ERROR_SERIAL_READ (INV_ERROR_BASE + 22) +#define INV_ERROR_SERIAL_WRITE (INV_ERROR_BASE + 23) +#define INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED (INV_ERROR_BASE + 24) + +/* SM = State Machine */ +#define INV_ERROR_SM_TRANSITION (INV_ERROR_BASE + 25) +#define INV_ERROR_SM_IMPROPER_STATE (INV_ERROR_BASE + 26) + +/* Fifo */ +#define INV_ERROR_FIFO_OVERFLOW (INV_ERROR_BASE + 30) +#define INV_ERROR_FIFO_FOOTER (INV_ERROR_BASE + 31) +#define INV_ERROR_FIFO_READ_COUNT (INV_ERROR_BASE + 32) +#define INV_ERROR_FIFO_READ_DATA (INV_ERROR_BASE + 33) + +/* Memory & Registers, Set & Get */ +#define INV_ERROR_MEMORY_SET (INV_ERROR_BASE + 40) + +#define INV_ERROR_LOG_MEMORY_ERROR (INV_ERROR_BASE + 50) +#define INV_ERROR_LOG_OUTPUT_ERROR (INV_ERROR_BASE + 51) + +/* OS interface errors */ +#define INV_ERROR_OS_BAD_PTR (INV_ERROR_BASE + 60) +#define INV_ERROR_OS_BAD_HANDLE (INV_ERROR_BASE + 61) +#define INV_ERROR_OS_CREATE_FAILED (INV_ERROR_BASE + 62) +#define INV_ERROR_OS_LOCK_FAILED (INV_ERROR_BASE + 63) + +/* Compass errors */ +#define INV_ERROR_COMPASS_DATA_OVERFLOW (INV_ERROR_BASE + 70) +#define INV_ERROR_COMPASS_DATA_UNDERFLOW (INV_ERROR_BASE + 71) +#define INV_ERROR_COMPASS_DATA_NOT_READY (INV_ERROR_BASE + 72) +#define INV_ERROR_COMPASS_DATA_ERROR (INV_ERROR_BASE + 73) + +/* Load/Store calibration */ +#define INV_ERROR_CALIBRATION_LOAD (INV_ERROR_BASE + 75) +#define INV_ERROR_CALIBRATION_STORE (INV_ERROR_BASE + 76) +#define INV_ERROR_CALIBRATION_LEN (INV_ERROR_BASE + 77) +#define INV_ERROR_CALIBRATION_CHECKSUM (INV_ERROR_BASE + 78) + +/* Accel errors */ +#define INV_ERROR_ACCEL_DATA_OVERFLOW (INV_ERROR_BASE + 79) +#define INV_ERROR_ACCEL_DATA_UNDERFLOW (INV_ERROR_BASE + 80) +#define INV_ERROR_ACCEL_DATA_NOT_READY (INV_ERROR_BASE + 81) +#define INV_ERROR_ACCEL_DATA_ERROR (INV_ERROR_BASE + 82) + +/* No Motion Warning States */ +#define INV_WARNING_MOTION_RACE (INV_ERROR_BASE + 83) +#define INV_WARNING_QUAT_TRASHED (INV_ERROR_BASE + 84) +#define INV_WARNING_GYRO_MAG (INV_ERROR_BASE + 85) + +#ifdef INV_USE_LEGACY_NAMES +#define ML_SUCCESS INV_SUCCESS +#define ML_ERROR INV_ERROR +#define ML_ERROR_INVALID_PARAMETER INV_ERROR_INVALID_PARAMETER +#define ML_ERROR_FEATURE_NOT_ENABLED INV_ERROR_FEATURE_NOT_ENABLED +#define ML_ERROR_FEATURE_NOT_IMPLEMENTED INV_ERROR_FEATURE_NOT_IMPLEMENTED +#define ML_ERROR_DMP_NOT_STARTED INV_ERROR_DMP_NOT_STARTED +#define ML_ERROR_DMP_STARTED INV_ERROR_DMP_STARTED +#define ML_ERROR_NOT_OPENED INV_ERROR_NOT_OPENED +#define ML_ERROR_OPENED INV_ERROR_OPENED +#define ML_ERROR_INVALID_MODULE INV_ERROR_INVALID_MODULE +#define ML_ERROR_MEMORY_EXAUSTED INV_ERROR_MEMORY_EXAUSTED +#define ML_ERROR_DIVIDE_BY_ZERO INV_ERROR_DIVIDE_BY_ZERO +#define ML_ERROR_ASSERTION_FAILURE INV_ERROR_ASSERTION_FAILURE +#define ML_ERROR_FILE_OPEN INV_ERROR_FILE_OPEN +#define ML_ERROR_FILE_READ INV_ERROR_FILE_READ +#define ML_ERROR_FILE_WRITE INV_ERROR_FILE_WRITE +#define ML_ERROR_INVALID_CONFIGURATION INV_ERROR_INVALID_CONFIGURATION +#define ML_ERROR_SERIAL_CLOSED INV_ERROR_SERIAL_CLOSED +#define ML_ERROR_SERIAL_OPEN_ERROR INV_ERROR_SERIAL_OPEN_ERROR +#define ML_ERROR_SERIAL_READ INV_ERROR_SERIAL_READ +#define ML_ERROR_SERIAL_WRITE INV_ERROR_SERIAL_WRITE +#define ML_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED \ + INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED +#define ML_ERROR_SM_TRANSITION INV_ERROR_SM_TRANSITION +#define ML_ERROR_SM_IMPROPER_STATE INV_ERROR_SM_IMPROPER_STATE +#define ML_ERROR_FIFO_OVERFLOW INV_ERROR_FIFO_OVERFLOW +#define ML_ERROR_FIFO_FOOTER INV_ERROR_FIFO_FOOTER +#define ML_ERROR_FIFO_READ_COUNT INV_ERROR_FIFO_READ_COUNT +#define ML_ERROR_FIFO_READ_DATA INV_ERROR_FIFO_READ_DATA +#define ML_ERROR_MEMORY_SET INV_ERROR_MEMORY_SET +#define ML_ERROR_LOG_MEMORY_ERROR INV_ERROR_LOG_MEMORY_ERROR +#define ML_ERROR_LOG_OUTPUT_ERROR INV_ERROR_LOG_OUTPUT_ERROR +#define ML_ERROR_OS_BAD_PTR INV_ERROR_OS_BAD_PTR +#define ML_ERROR_OS_BAD_HANDLE INV_ERROR_OS_BAD_HANDLE +#define ML_ERROR_OS_CREATE_FAILED INV_ERROR_OS_CREATE_FAILED +#define ML_ERROR_OS_LOCK_FAILED INV_ERROR_OS_LOCK_FAILED +#define ML_ERROR_COMPASS_DATA_OVERFLOW INV_ERROR_COMPASS_DATA_OVERFLOW +#define ML_ERROR_COMPASS_DATA_UNDERFLOW INV_ERROR_COMPASS_DATA_UNDERFLOW +#define ML_ERROR_COMPASS_DATA_NOT_READY INV_ERROR_COMPASS_DATA_NOT_READY +#define ML_ERROR_COMPASS_DATA_ERROR INV_ERROR_COMPASS_DATA_ERROR +#define ML_ERROR_CALIBRATION_LOAD INV_ERROR_CALIBRATION_LOAD +#define ML_ERROR_CALIBRATION_STORE INV_ERROR_CALIBRATION_STORE +#define ML_ERROR_CALIBRATION_LEN INV_ERROR_CALIBRATION_LEN +#define ML_ERROR_CALIBRATION_CHECKSUM INV_ERROR_CALIBRATION_CHECKSUM +#define ML_ERROR_ACCEL_DATA_OVERFLOW INV_ERROR_ACCEL_DATA_OVERFLOW +#define ML_ERROR_ACCEL_DATA_UNDERFLOW INV_ERROR_ACCEL_DATA_UNDERFLOW +#define ML_ERROR_ACCEL_DATA_NOT_READY INV_ERROR_ACCEL_DATA_NOT_READY +#define ML_ERROR_ACCEL_DATA_ERROR INV_ERROR_ACCEL_DATA_ERROR +#endif + +/* For Linux coding compliance */ + +#endif /* MLTYPES_H */ diff --git a/drivers/misc/inv_mpu/mpu-dev.c b/drivers/misc/inv_mpu/mpu-dev.c new file mode 100644 index 00000000000..761125c5b17 --- /dev/null +++ b/drivers/misc/inv_mpu/mpu-dev.c @@ -0,0 +1,2581 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpuirq.h" +#include "slaveirq.h" +#include "mlsl.h" +#include "mldl_cfg.h" +#include + +#include "accel/mpu6050.h" +#include "mpu-dev.h" + +#ifdef CONFIG_INPUT_YAS_MAGNETOMETER +#include "compass/yas530_ext.h" +#endif +#ifdef CONFIG_SENSORS_AK8975 +#include "compass/ak89753.h" +#endif +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#define MAG_VENDOR "AKM" +#define MAG_PART_ID "AK8963C" +#define MPU_VENDOR "INVENSENSE" +#define MPU_PART_ID "MPU-6050" + +#define MPU_EARLY_SUSPEND_IN_DRIVER 1 + +#define CALIBRATION_FILE_PATH "/efs/calibration_data" +#define CALIBRATION_DATA_AMOUNT 100 + +struct acc_data cal_data = {0, 0, 0}; + +/* Platform data for the MPU */ +struct mpu_private_data { + struct miscdevice dev; + struct i2c_client *client; + + /* mldl_cfg data */ + struct mldl_cfg mldl_cfg; + struct mpu_ram mpu_ram; + struct mpu_gyro_cfg mpu_gyro_cfg; + struct mpu_offsets mpu_offsets; + struct mpu_chip_info mpu_chip_info; + struct inv_mpu_cfg inv_mpu_cfg; + struct inv_mpu_state inv_mpu_state; + + struct mutex mutex; + wait_queue_head_t mpu_event_wait; + struct completion completion; + struct timer_list timeout; + struct notifier_block nb; + struct mpuirq_data mpu_pm_event; + int response_timeout; /* In seconds */ + unsigned long event; + int pid; + struct module *slave_modules[EXT_SLAVE_NUM_TYPES]; + struct { + atomic_t enable; + unsigned char is_activated; + unsigned char turned_by_mpu_accel; + } mpu_accel; + + struct hrtimer activate_timer; + int activate_timeout; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif +}; + +static struct i2c_client *this_client; + +#define IDEAL_X 0 +#define IDEAL_Y 0 +#define IDEAL_Z 1024 + +struct mpu_private_data *mpu_private_data; + +void mpu_accel_enable_set(int enable) +{ + + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + if (enable) { + mpu->mpu_accel.is_activated = !(mldl_cfg->inv_mpu_state->status + & MPU_ACCEL_IS_SUSPENDED); + + (void)inv_mpu_resume(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_THREE_AXIS_ACCEL); + + mpu->mpu_accel.turned_by_mpu_accel + = 1; + } else { + if (!mpu->mpu_accel.is_activated && + mpu->mpu_accel.turned_by_mpu_accel) { + (void)inv_mpu_suspend(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_THREE_AXIS_ACCEL); + mpu->mpu_accel.turned_by_mpu_accel = 0; + } + } + atomic_set(&mpu->mpu_accel.enable, enable); +} + +int read_accel_raw_xyz(struct acc_data *acc) +{ + s16 x, y, z; + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int retval = 0; + unsigned char data[6]; + + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int cal_div = (mldl_cfg->mpu_chip_info->accel_sens_trim) / 1024; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + + retval = inv_serial_read(slave_adapter[EXT_SLAVE_TYPE_ACCEL], + 0x68, 0x3B, 6, data); + + x = (s16)((data[0] << 8) | data[1]) / cal_div; + y = (s16)((data[2] << 8) | data[3]) / cal_div; + z = (s16)((data[4] << 8) | data[5]) / cal_div; + + acc->x = x; + acc->y = y; + acc->z = z; + + return 0; +} + +static int accel_open_calibration(void) +{ + struct file *cal_filp = NULL; + int err = 0; + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("%s: Can't open calibration file\n", __func__); + set_fs(old_fs); + err = PTR_ERR(cal_filp); + return err; + } + + err = cal_filp->f_op->read(cal_filp, + (char *)&cal_data, 3 * sizeof(s16), &cal_filp->f_pos); + if (err != 3 * sizeof(s16)) { + pr_err("%s: Can't read the cal data from file\n", __func__); + err = -EIO; + } + + printk(KERN_INFO"%s: (%u,%u,%u)\n", __func__, + cal_data.x, cal_data.y, cal_data.z); + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return err; +} + +static int accel_do_calibrate(int enable) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct acc_data data = { 0, }; + struct file *cal_filp = NULL; + + int sum[3] = { 0, }; + int err = 0; + int i; + mm_segment_t old_fs; + + int cal_div = (mldl_cfg->mpu_chip_info->accel_sens_trim) / 1024; + int ideal_z = IDEAL_Z * mldl_cfg->pdata->orientation[8]; + + /*mutex_lock(&mpu->mutex);*/ + mpu_accel_enable_set(1); + mdelay(1); + + for (i = 0; i < CALIBRATION_DATA_AMOUNT; i++) { + err = read_accel_raw_xyz(&data); + if (err < 0) { + pr_err("%s: accel_read_accel_raw_xyz() " + "failed in the %dth loop\n", __func__, i); + return err; + } + + sum[0] += data.x; + sum[1] += data.y; + sum[2] += data.z; + } + + mpu_accel_enable_set(0); + mdelay(1); + /*mutex_unlock(&mpu->mutex);*/ + + if (enable) { + cal_data.x = ((sum[0] / CALIBRATION_DATA_AMOUNT) - IDEAL_X) + * cal_div; + cal_data.y = ((sum[1] / CALIBRATION_DATA_AMOUNT) - IDEAL_Y) + * cal_div; + cal_data.z = ((sum[2] / CALIBRATION_DATA_AMOUNT) - ideal_z) + * cal_div; + } else { + cal_data.x = 0; + cal_data.y = 0; + cal_data.z = 0; + } + + printk(KERN_INFO "%s: cal data (%d,%d,%d)\n", __func__, + cal_data.x, cal_data.y, cal_data.z); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("%s: Can't open calibration file\n", __func__); + set_fs(old_fs); + err = PTR_ERR(cal_filp); + return err; + } + + err = cal_filp->f_op->write(cal_filp, + (char *)&cal_data, 3 * sizeof(s16), &cal_filp->f_pos); + if (err != 3 * sizeof(s16)) { + pr_err("%s: Can't write the cal data to file\n", __func__); + err = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return err; +} + +static void mpu_pm_timeout(u_long data) +{ + struct mpu_private_data *mpu = (struct mpu_private_data *)data; + struct i2c_client *client = mpu->client; + dev_dbg(&client->adapter->dev, "%s\n", __func__); + complete(&mpu->completion); +} + + +static int mpu_early_notifier_callback(struct mpu_private_data *mpu, + unsigned long event, void *unused) +{ + struct i2c_client *client = mpu->client; + struct timeval event_time; + dev_dbg(&client->adapter->dev, "%s: %ld\n", __func__, event); + + /* Prevent the file handle from being closed before we initialize + the completion event */ + printk(KERN_INFO"[%s] event = %lu\n", __func__, event); + mutex_lock(&mpu->mutex); + if (!(mpu->pid) || + (event != PM_SUSPEND_PREPARE && event != PM_POST_SUSPEND)) { + mutex_unlock(&mpu->mutex); + return NOTIFY_OK; + } + + if (event == PM_SUSPEND_PREPARE) + mpu->event |= MPU_PM_EVENT_SUSPEND_PREPARE; + if (event == PM_POST_SUSPEND) + mpu->event |= MPU_PM_EVENT_POST_SUSPEND; + + do_gettimeofday(&event_time); + mpu->mpu_pm_event.interruptcount++; + mpu->mpu_pm_event.irqtime = + (((long long)event_time.tv_sec) << 32) + event_time.tv_usec; + mpu->mpu_pm_event.data_type = MPUIRQ_DATA_TYPE_PM_EVENT; + mpu->mpu_pm_event.data = mpu->event; + + if (mpu->response_timeout > 0) { + mpu->timeout.expires = jiffies + mpu->response_timeout * HZ; + add_timer(&mpu->timeout); + } + INIT_COMPLETION(mpu->completion); + mutex_unlock(&mpu->mutex); + + wake_up_interruptible(&mpu->mpu_event_wait); + wait_for_completion(&mpu->completion); + del_timer_sync(&mpu->timeout); + dev_dbg(&client->adapter->dev, "%s: %ld DONE\n", __func__, event); + return NOTIFY_OK; +} + +static int mpu_dev_open(struct inode *inode, struct file *file) +{ + struct mpu_private_data *mpu = + container_of(file->private_data, struct mpu_private_data, dev); + struct i2c_client *client = mpu->client; + int result; + int ii; + dev_dbg(&client->adapter->dev, "%s\n", __func__); + dev_dbg(&client->adapter->dev, "current->pid %d\n", current->pid); + + accel_open_calibration(); + + result = mutex_lock_interruptible(&mpu->mutex); + if (mpu->pid) { + mutex_unlock(&mpu->mutex); + return -EBUSY; + } + mpu->pid = current->pid; + + /* Reset the sensors to the default */ + if (result) { + dev_err(&client->adapter->dev, + "%s: mutex_lock_interruptible returned %d\n", + __func__, result); + return result; + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) + __module_get(mpu->slave_modules[ii]); + + mutex_unlock(&mpu->mutex); + return 0; +} + +/* close function - called when the "file" /dev/mpu is closed in userspace */ +static int mpu_release(struct inode *inode, struct file *file) +{ + struct mpu_private_data *mpu = + container_of(file->private_data, struct mpu_private_data, dev); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int result = 0; + int ii; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + mldl_cfg->inv_mpu_cfg->requested_sensors = 0; + result = inv_mpu_suspend(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_ALL_SENSORS); + mpu->pid = 0; + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) + module_put(mpu->slave_modules[ii]); + + mutex_unlock(&mpu->mutex); + complete(&mpu->completion); + dev_dbg(&client->adapter->dev, "mpu_release\n"); + + return result; +} + +/* read function called when from /dev/mpu is read. Read from the FIFO */ +static ssize_t mpu_read(struct file *file, + char __user *buf, size_t count, loff_t *offset) +{ + struct mpu_private_data *mpu = + container_of(file->private_data, struct mpu_private_data, dev); + struct i2c_client *client = mpu->client; + size_t len = sizeof(mpu->mpu_pm_event) + sizeof(unsigned long); + int err; + + if (!mpu->event && (!(file->f_flags & O_NONBLOCK))) + wait_event_interruptible(mpu->mpu_event_wait, mpu->event); + + if (!mpu->event || !buf + || count < sizeof(mpu->mpu_pm_event)) + return 0; + + err = copy_to_user(buf, &mpu->mpu_pm_event, sizeof(mpu->mpu_pm_event)); + if (err) { + dev_err(&client->adapter->dev, + "Copy to user returned %d\n", err); + return -EFAULT; + } + mpu->event = 0; + return len; +} + +static unsigned int mpu_poll(struct file *file, struct poll_table_struct *poll) +{ + struct mpu_private_data *mpu = + container_of(file->private_data, struct mpu_private_data, dev); + int mask = 0; + + poll_wait(file, &mpu->mpu_event_wait, poll); + if (mpu->event) + mask |= POLLIN | POLLRDNORM; + return mask; +} + +static int mpu_dev_ioctl_get_ext_slave_platform_data( + struct i2c_client *client, + struct ext_slave_platform_data __user *arg) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct ext_slave_platform_data *pdata_slave; + struct ext_slave_platform_data local_pdata_slave; + + if (copy_from_user(&local_pdata_slave, arg, sizeof(local_pdata_slave))) + return -EFAULT; + + if (local_pdata_slave.type >= EXT_SLAVE_NUM_TYPES) + return -EINVAL; + + pdata_slave = mpu->mldl_cfg.pdata_slave[local_pdata_slave.type]; + /* All but private data and irq_data */ + if (!pdata_slave) + return -ENODEV; + if (copy_to_user(arg, pdata_slave, sizeof(*pdata_slave))) + return -EFAULT; + return 0; +} + +static int mpu_dev_ioctl_get_mpu_platform_data( + struct i2c_client *client, + struct mpu_platform_data __user *arg) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mpu_platform_data *pdata = mpu->mldl_cfg.pdata; + + if (copy_to_user(arg, pdata, sizeof(*pdata))) + return -EFAULT; + return 0; +} + +static int mpu_dev_ioctl_get_ext_slave_descr( + struct i2c_client *client, + struct ext_slave_descr __user *arg) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct ext_slave_descr *slave; + struct ext_slave_descr local_slave; + + if (copy_from_user(&local_slave, arg, sizeof(local_slave))) + return -EFAULT; + + if (local_slave.type >= EXT_SLAVE_NUM_TYPES) + return -EINVAL; + + slave = mpu->mldl_cfg.slave[local_slave.type]; + /* All but private data and irq_data */ + if (!slave) + return -ENODEV; + if (copy_to_user(arg, slave, sizeof(*slave))) + return -EFAULT; + return 0; +} + + +/** + * slave_config() - Pass a requested slave configuration to the slave sensor + * + * @adapter the adaptor to use to communicate with the slave + * @mldl_cfg the mldl configuration structuer + * @slave pointer to the slave descriptor + * @usr_config The configuration to pass to the slave sensor + * + * returns 0 or non-zero error code + */ +static int inv_mpu_config(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + struct ext_slave_config __user *usr_config) +{ + int retval = 0; + struct ext_slave_config config; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + if (config.len && config.data) { + void *data; + data = kmalloc(config.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)config.data, config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = gyro_config(gyro_adapter, mldl_cfg, &config); + kfree(config.data); + return retval; +} + +static int inv_mpu_get_config(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + struct ext_slave_config __user *usr_config) +{ + int retval = 0; + struct ext_slave_config config; + void *user_data; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + user_data = config.data; + if (config.len && config.data) { + void *data; + data = kmalloc(config.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)config.data, config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = gyro_get_config(gyro_adapter, mldl_cfg, &config); + if (!retval) + retval = copy_to_user((unsigned char __user *)user_data, + config.data, config.len); + kfree(config.data); + return retval; +} + +static int slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + void *slave_adapter, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config __user *usr_config) +{ + int retval = 0; + struct ext_slave_config config; + if ((!slave) || (!slave->config)) + return -ENODEV; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + if (config.len && config.data) { + void *data; + data = kmalloc(config.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)config.data, config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = inv_mpu_slave_config(mldl_cfg, gyro_adapter, slave_adapter, + &config, slave, pdata); + kfree(config.data); + return retval; +} + +static int slave_get_config(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + void *slave_adapter, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config __user *usr_config) +{ + int retval = 0; + struct ext_slave_config config; + void *user_data; + if (!(slave) || !(slave->get_config)) + return -ENODEV; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + user_data = config.data; + if (config.len && config.data) { + void *data; + data = kmalloc(config.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)config.data, config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = inv_mpu_get_slave_config(mldl_cfg, gyro_adapter, + slave_adapter, &config, slave, pdata); + if (retval) { + kfree(config.data); + return retval; + } + retval = copy_to_user((unsigned char __user *)user_data, + config.data, config.len); + kfree(config.data); + return retval; +} + +static int inv_slave_read(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + void *slave_adapter, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + void __user *usr_data) +{ + int retval; + unsigned char *data; + data = kzalloc(slave->read_len, GFP_KERNEL); + if (!data) + return -EFAULT; + + retval = inv_mpu_slave_read(mldl_cfg, gyro_adapter, slave_adapter, + slave, pdata, data); + + if ((!retval) && + (copy_to_user((unsigned char __user *)usr_data, + data, slave->read_len))) + retval = -EFAULT; + + kfree(data); + return retval; +} + +static int mpu_handle_mlsl(void *sl_handle, + unsigned char addr, + unsigned int cmd, + struct mpu_read_write __user *usr_msg) +{ + int retval = 0; + struct mpu_read_write msg; + unsigned char *user_data; + retval = copy_from_user(&msg, usr_msg, sizeof(msg)); + if (retval) + return -EFAULT; + + user_data = msg.data; + if (msg.length && msg.data) { + unsigned char *data; + data = kmalloc(msg.length, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)msg.data, msg.length); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + msg.data = data; + } else { + return -EPERM; + } + + switch (cmd) { + case MPU_READ: + retval = inv_serial_read(sl_handle, addr, + (unsigned char)msg.address, msg.length, msg.data); + break; + case MPU_WRITE: + retval = inv_serial_write(sl_handle, addr, + msg.length, msg.data); + break; + case MPU_READ_MEM: + retval = inv_serial_read_mem(sl_handle, addr, + msg.address, msg.length, msg.data); + break; + case MPU_WRITE_MEM: + retval = inv_serial_write_mem(sl_handle, addr, + msg.address, msg.length, + msg.data); + break; + case MPU_READ_FIFO: + retval = inv_serial_read_fifo(sl_handle, addr, + msg.length, msg.data); + break; + case MPU_WRITE_FIFO: + retval = inv_serial_write_fifo(sl_handle, addr, + msg.length, msg.data); + break; + + }; + if (retval) { + dev_err(&((struct i2c_adapter *)sl_handle)->dev, + "%s: i2c %d error %d\n", + __func__, cmd, retval); + kfree(msg.data); + return retval; + } + retval = copy_to_user((unsigned char __user *)user_data, + msg.data, msg.length); + kfree(msg.data); + return retval; +} + +static enum hrtimer_restart mpu_actiavte_sensors_callback(struct hrtimer *timer) +{ + struct mpu_private_data *mpu = mpu_private_data; + + struct i2c_client *client = mpu->client; + struct timeval event_time; + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + /* Prevent the file handle from being closed before we initialize + the completion event */ + + mpu->event |= MPU_KN_EVENT_ENABLE_SENSORS; + + do_gettimeofday(&event_time); + mpu->mpu_pm_event.interruptcount++; + mpu->mpu_pm_event.irqtime = + (((long long)event_time.tv_sec) << 32) + event_time.tv_usec; + mpu->mpu_pm_event.data_type = MPUIRQ_DATA_TYPE_PM_EVENT; + mpu->mpu_pm_event.data = mpu->event; + + wake_up_interruptible(&mpu->mpu_event_wait); + + return HRTIMER_NORESTART; +} + +static long mpu_dev_ioctl_activate_sensors(struct mpu_private_data *mpu) +{ + ktime_t ktime; + struct i2c_client *client = mpu->client; + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + hrtimer_cancel(&mpu->activate_timer); + + ktime = ktime_set(mpu->activate_timeout / 1000, + (mpu->activate_timeout % 1000) * 1000000); + return hrtimer_start(&mpu->activate_timer, ktime, HRTIMER_MODE_REL); +} + +/* ioctl - I/O control */ +static long mpu_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mpu_private_data *mpu = + container_of(file->private_data, struct mpu_private_data, dev); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int retval = 0; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_descr **slave = mldl_cfg->slave; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + retval = mutex_lock_interruptible(&mpu->mutex); + if (retval) { + dev_err(&client->adapter->dev, + "%s: mutex_lock_interruptible returned %d\n", + __func__, retval); + return retval; + } + + switch (cmd) { + case MPU_GET_EXT_SLAVE_PLATFORM_DATA: + retval = mpu_dev_ioctl_get_ext_slave_platform_data( + client, + (struct ext_slave_platform_data __user *)arg); + break; + case MPU_GET_MPU_PLATFORM_DATA: + retval = mpu_dev_ioctl_get_mpu_platform_data( + client, + (struct mpu_platform_data __user *)arg); + break; + case MPU_GET_EXT_SLAVE_DESCR: + retval = mpu_dev_ioctl_get_ext_slave_descr( + client, + (struct ext_slave_descr __user *)arg); + break; + case MPU_READ: + case MPU_WRITE: + case MPU_READ_MEM: + case MPU_WRITE_MEM: + case MPU_READ_FIFO: + case MPU_WRITE_FIFO: + retval = mpu_handle_mlsl( + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + mldl_cfg->mpu_chip_info->addr, cmd, + (struct mpu_read_write __user *)arg); + break; + case MPU_CONFIG_GYRO: + retval = inv_mpu_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + (struct ext_slave_config __user *)arg); + break; + case MPU_CONFIG_ACCEL: + retval = slave_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave[EXT_SLAVE_TYPE_ACCEL], + pdata_slave[EXT_SLAVE_TYPE_ACCEL], + (struct ext_slave_config __user *)arg); + break; + case MPU_CONFIG_COMPASS: + retval = slave_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave[EXT_SLAVE_TYPE_COMPASS], + pdata_slave[EXT_SLAVE_TYPE_COMPASS], + (struct ext_slave_config __user *)arg); + break; + case MPU_CONFIG_PRESSURE: + retval = slave_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + slave[EXT_SLAVE_TYPE_PRESSURE], + pdata_slave[EXT_SLAVE_TYPE_PRESSURE], + (struct ext_slave_config __user *)arg); + break; + case MPU_GET_CONFIG_GYRO: + retval = inv_mpu_get_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + (struct ext_slave_config __user *)arg); + break; + case MPU_GET_CONFIG_ACCEL: + retval = slave_get_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave[EXT_SLAVE_TYPE_ACCEL], + pdata_slave[EXT_SLAVE_TYPE_ACCEL], + (struct ext_slave_config __user *)arg); + break; + case MPU_GET_CONFIG_COMPASS: + retval = slave_get_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave[EXT_SLAVE_TYPE_COMPASS], + pdata_slave[EXT_SLAVE_TYPE_COMPASS], + (struct ext_slave_config __user *)arg); + break; + case MPU_GET_CONFIG_PRESSURE: + retval = slave_get_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + slave[EXT_SLAVE_TYPE_PRESSURE], + pdata_slave[EXT_SLAVE_TYPE_PRESSURE], + (struct ext_slave_config __user *)arg); + break; + case MPU_SUSPEND: + retval = inv_mpu_suspend( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + arg); + break; + case MPU_RESUME: + retval = inv_mpu_resume( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + arg); + break; + case MPU_PM_EVENT_HANDLED: + dev_dbg(&client->adapter->dev, "%s: %d\n", __func__, cmd); + complete(&mpu->completion); + break; + case MPU_READ_ACCEL: + retval = inv_slave_read( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave[EXT_SLAVE_TYPE_ACCEL], + pdata_slave[EXT_SLAVE_TYPE_ACCEL], + (unsigned char __user *)arg); + break; + case MPU_READ_COMPASS: + retval = inv_slave_read( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave[EXT_SLAVE_TYPE_COMPASS], + pdata_slave[EXT_SLAVE_TYPE_COMPASS], + (unsigned char __user *)arg); + break; + case MPU_READ_PRESSURE: + retval = inv_slave_read( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + slave[EXT_SLAVE_TYPE_PRESSURE], + pdata_slave[EXT_SLAVE_TYPE_PRESSURE], + (unsigned char __user *)arg); + break; + case MPU_GET_REQUESTED_SENSORS: + if (copy_to_user( + (__u32 __user *)arg, + &mldl_cfg->inv_mpu_cfg->requested_sensors, + sizeof(mldl_cfg->inv_mpu_cfg->requested_sensors))) + retval = -EFAULT; + break; + case MPU_SET_REQUESTED_SENSORS: + mldl_cfg->inv_mpu_cfg->requested_sensors = arg; + break; + case MPU_GET_IGNORE_SYSTEM_SUSPEND: + if (copy_to_user( + (unsigned char __user *)arg, + &mldl_cfg->inv_mpu_cfg->ignore_system_suspend, + sizeof(mldl_cfg->inv_mpu_cfg->ignore_system_suspend))) + retval = -EFAULT; + break; + case MPU_SET_IGNORE_SYSTEM_SUSPEND: + mldl_cfg->inv_mpu_cfg->ignore_system_suspend = arg; + break; + case MPU_GET_MLDL_STATUS: + if (copy_to_user( + (unsigned char __user *)arg, + &mldl_cfg->inv_mpu_state->status, + sizeof(mldl_cfg->inv_mpu_state->status))) + retval = -EFAULT; + break; + case MPU_GET_I2C_SLAVES_ENABLED: + if (copy_to_user( + (unsigned char __user *)arg, + &mldl_cfg->inv_mpu_state->i2c_slaves_enabled, + sizeof(mldl_cfg->inv_mpu_state->i2c_slaves_enabled))) + retval = -EFAULT; + break; + case MPU_READ_ACCEL_OFFSET: + { + retval = copy_to_user((signed short __user *)arg, + &cal_data, sizeof(cal_data)); + if (INV_SUCCESS != retval) + dev_err(&client->adapter->dev, + "%s: cmd %x, arg %lu\n", __func__, cmd, arg); + } + break; + case MPU_ACTIVATE_SENSORS: + mpu_dev_ioctl_activate_sensors(mpu); + break; + default: + dev_err(&client->adapter->dev, + "%s: Unknown cmd %x, arg %lu\n", + __func__, cmd, arg); + retval = -EINVAL; + }; + + mutex_unlock(&mpu->mutex); + dev_dbg(&client->adapter->dev, "%s: %08x, %08lx, %d\n", + __func__, cmd, arg, retval); + + if (retval > 0) + retval = -retval; + + return retval; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +void mpu_dev_early_suspend(struct early_suspend *h) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(this_client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + printk(KERN_INFO"[@@@@@%s@@@@@]\n", __func__); + + mpu_early_notifier_callback(mpu, PM_SUSPEND_PREPARE, NULL); + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = this_client->adapter; + mutex_lock(&mpu->mutex); + if (!mldl_cfg->inv_mpu_cfg->ignore_system_suspend) { + (void)inv_mpu_suspend(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_ALL_SENSORS); + } + mutex_unlock(&mpu->mutex); +} + +void mpu_dev_early_resume(struct early_suspend *h) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(this_client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + printk(KERN_INFO"[@@@@@%s@@@@@]\n", __func__); + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = this_client->adapter; + + mutex_lock(&mpu->mutex); + if (mpu->pid && !mldl_cfg->inv_mpu_cfg->ignore_system_suspend) { + (void)inv_mpu_resume(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->inv_mpu_cfg->requested_sensors); + } + mutex_unlock(&mpu->mutex); + mpu_early_notifier_callback(mpu, PM_POST_SUSPEND, NULL); +} +#endif + + +void mpu_shutdown(struct i2c_client *client) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + (void)inv_mpu_suspend(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_ALL_SENSORS); + mutex_unlock(&mpu->mutex); + dev_dbg(&client->adapter->dev, "%s\n", __func__); +} + +int mpu_dev_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + printk(KERN_INFO"@@@@@%s@@@@@\n", __func__); + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + if (!mldl_cfg->inv_mpu_cfg->ignore_system_suspend) { + dev_dbg(&client->adapter->dev, + "%s: suspending on event %d\n", __func__, mesg.event); + (void)inv_mpu_suspend(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_ALL_SENSORS); + } else { + dev_dbg(&client->adapter->dev, + "%s: Already suspended %d\n", __func__, mesg.event); + } + mutex_unlock(&mpu->mutex); + + if (mldl_cfg->pdata->poweron) + mldl_cfg->pdata->poweron(0); + return 0; +} + +int mpu_dev_resume(struct i2c_client *client) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + printk(KERN_INFO"@@@@@%s@@@@@\n", __func__); + + if (mldl_cfg->pdata->poweron) + mldl_cfg->pdata->poweron(1); + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + if (mpu->pid && !mldl_cfg->inv_mpu_cfg->ignore_system_suspend) { + (void)inv_mpu_resume(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->inv_mpu_cfg->requested_sensors); + dev_dbg(&client->adapter->dev, + "%s for pid %d\n", __func__, mpu->pid); + } + mutex_unlock(&mpu->mutex); + return 0; +} + +/* define which file operations are supported */ +static const struct file_operations mpu_fops = { + .owner = THIS_MODULE, + .read = mpu_read, + .poll = mpu_poll, + .unlocked_ioctl = mpu_dev_ioctl, + .open = mpu_dev_open, + .release = mpu_release, +}; + +int inv_mpu_register_slave(struct module *slave_module, + struct i2c_client *slave_client, + struct ext_slave_platform_data *slave_pdata, + struct ext_slave_descr *(*get_slave_descr)(void)) +{ + struct mpu_private_data *mpu = mpu_private_data; + struct mldl_cfg *mldl_cfg; + struct ext_slave_descr *slave_descr; + struct ext_slave_platform_data **pdata_slave; + char *irq_name = NULL; + int result = 0; + + if (!slave_client || !slave_pdata || !get_slave_descr) + return -EINVAL; + + if (!mpu) { + dev_err(&slave_client->adapter->dev, + "%s: Null mpu_private_data\n", __func__); + return -EINVAL; + } + mldl_cfg = &mpu->mldl_cfg; + pdata_slave = mldl_cfg->pdata_slave; + slave_descr = get_slave_descr(); + + if (!slave_descr) { + dev_err(&slave_client->adapter->dev, + "%s: Null ext_slave_descr\n", __func__); + return -EINVAL; + } + + mutex_lock(&mpu->mutex); + if (mpu->pid) { + mutex_unlock(&mpu->mutex); + return -EBUSY; + } + + if (pdata_slave[slave_descr->type]) { + result = -EBUSY; + goto out_unlock_mutex; + } + + slave_pdata->address = slave_client->addr; + slave_pdata->irq = slave_client->irq; + slave_pdata->adapt_num = i2c_adapter_id(slave_client->adapter); + + dev_info(&slave_client->adapter->dev, + "%s: +%s Type %d: Addr: %2x IRQ: %2d, Adapt: %2d\n", + __func__, + slave_descr->name, + slave_descr->type, + slave_pdata->address, + slave_pdata->irq, + slave_pdata->adapt_num); + + switch (slave_descr->type) { + case EXT_SLAVE_TYPE_ACCEL: + irq_name = "accelirq"; + break; + case EXT_SLAVE_TYPE_COMPASS: + irq_name = "compassirq"; + break; + case EXT_SLAVE_TYPE_PRESSURE: + irq_name = "pressureirq"; + break; + default: + irq_name = "none"; + }; + if (slave_descr->type == EXT_SLAVE_TYPE_COMPASS + && slave_descr->init) { + int retry_cnt = 3; +#if defined(CONFIG_MPU_SENSORS_AK8975_411) + unsigned int reset = mldl_cfg->pdata->reset; +#endif + do { + retry_cnt--; + + result = slave_descr->init(slave_client->adapter, + slave_descr, slave_pdata); + if (result) { + dev_err(&slave_client->adapter->dev, + "%s init failed %d, cnt %d\n", + slave_descr->name, result, retry_cnt); +#if defined(CONFIG_MPU_SENSORS_AK8975_411) + gpio_direction_output(reset, 0); + usleep_range(30, 30); + gpio_set_value_cansleep(reset, 1); + usleep_range(30, 30); +#endif + } else { + break; + } + } while (retry_cnt); + if (result) { + dev_err(&slave_client->adapter->dev, + "%s init failed %d, cnt %d\n", + slave_descr->name, result, retry_cnt); + goto out_unlock_mutex; + } + + } else { + if (slave_descr->init) { + result = slave_descr->init(slave_client->adapter, + slave_descr, + slave_pdata); + if (result) { + dev_err(&slave_client->adapter->dev, + "%s init failed %d\n", + slave_descr->name, result); + goto out_unlock_mutex; + } + } + } + + if (slave_descr->type == EXT_SLAVE_TYPE_ACCEL && + slave_descr->id == ACCEL_ID_MPU6050 && + slave_descr->config) { + /* pass a reference to the mldl_cfg data + structure to the mpu6050 accel "class" */ + struct ext_slave_config config; + config.key = MPU_SLAVE_CONFIG_INTERNAL_REFERENCE; + config.len = sizeof(struct mldl_cfg *); + config.apply = true; + config.data = mldl_cfg; + result = slave_descr->config( + slave_client->adapter, slave_descr, + slave_pdata, &config); + if (result) { + LOG_RESULT_LOCATION(result); + goto out_slavedescr_exit; + } + } + pdata_slave[slave_descr->type] = slave_pdata; + mpu->slave_modules[slave_descr->type] = slave_module; + mldl_cfg->slave[slave_descr->type] = slave_descr; + + goto out_unlock_mutex; + +out_slavedescr_exit: + if (slave_descr->exit) + slave_descr->exit(slave_client->adapter, + slave_descr, slave_pdata); +out_unlock_mutex: + mutex_unlock(&mpu->mutex); + + if (!result && irq_name && (slave_pdata->irq > 0)) { + int warn_result; + dev_info(&slave_client->adapter->dev, + "Installing %s irq using %d\n", + irq_name, + slave_pdata->irq); + warn_result = slaveirq_init(slave_client->adapter, + slave_pdata, irq_name); + if (warn_result) + dev_warn(&slave_client->adapter->dev, + "%s irq assigned error: %d\n", + slave_descr->name, warn_result); + } else { + dev_warn(&slave_client->adapter->dev, + "%s irq not assigned: %d %d %d\n", + slave_descr->name, + result, (int)irq_name, slave_pdata->irq); + } + + return result; +} +EXPORT_SYMBOL(inv_mpu_register_slave); + +void inv_mpu_unregister_slave(struct i2c_client *slave_client, + struct ext_slave_platform_data *slave_pdata, + struct ext_slave_descr *(*get_slave_descr)(void)) +{ + struct mpu_private_data *mpu = mpu_private_data; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct ext_slave_descr *slave_descr; + int result; + + if (!slave_client || !slave_pdata || !get_slave_descr) + return; + + dev_info(&slave_client->adapter->dev, "%s\n", __func__); + + if (slave_pdata->irq) + slaveirq_exit(slave_pdata); + + slave_descr = get_slave_descr(); + if (!slave_descr) + return; + + mutex_lock(&mpu->mutex); + + if (slave_descr->exit) { + result = slave_descr->exit(slave_client->adapter, + slave_descr, + slave_pdata); + if (result) + dev_err(&slave_client->adapter->dev, + "Accel exit failed %d\n", result); + } + mldl_cfg->slave[slave_descr->type] = NULL; + mldl_cfg->pdata_slave[slave_descr->type] = NULL; + mpu->slave_modules[slave_descr->type] = NULL; + + mutex_unlock(&mpu->mutex); + +} +EXPORT_SYMBOL(inv_mpu_unregister_slave); + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static const struct i2c_device_id mpu_id[] = { + {"mpu3050", 0}, + {"mpu6050", 0}, + {"mpu6050_no_accel", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, mpu_id); + +static int mpu3050_factory_on(struct i2c_client *client) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(this_client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int prev_gyro_suspended = 0; + + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + printk(KERN_INFO"@@@@@ %s : %d @@@@@\n", __func__, __LINE__); + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + if (1) { + (void)inv_mpu_resume(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->inv_mpu_cfg->requested_sensors); + } + mutex_unlock(&mpu->mutex); + return prev_gyro_suspended; +} + +static ssize_t mpu3050_power_on(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count = 0; + + dev_dbg(dev, "this_client = %d\n", (int)this_client); + count = sprintf(buf, "%d\n", (this_client != NULL ? 1 : 0)); + + return count; +} + +static ssize_t mpu3050_get_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count = 0; + short int temperature = 0; + unsigned char data[2]; + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(this_client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = this_client->adapter; + + mpu3050_factory_on(this_client); + + /*MPUREG_TEMP_OUT_H, 27 0x1b */ + /*MPUREG_TEMP_OUT_L, 28 0x1c */ + /* TEMP_OUT_H/L: 16-bit temperature data (2's complement data format) */ + inv_serial_read(slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + DEFAULT_MPU_SLAVEADDR, MPUREG_TEMP_OUT_H, 2, data); + temperature = (short) (((data[0]) << 8) | data[1]); + temperature = (((temperature + 521) / 340) + 35); + printk(KERN_INFO"read temperature = %d\n", temperature); + + count = sprintf(buf, "%d\n", temperature); + + return count; +} + +static ssize_t mpu3050_acc_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + s16 x, y, z, temp; + int count = 0; + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int retval = 0; + unsigned char data[6]; + + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + + retval = inv_serial_read(slave_adapter[EXT_SLAVE_TYPE_ACCEL], + 0x68, 0x3B, 6, data); + + x = (s16)(((data[0] << 8) | data[1]) - cal_data.x);/*CAL_DIV;*/ + y = (s16)(((data[2] << 8) | data[3]) - cal_data.y);/*CAL_DIV;*/ + z = (s16)(((data[4] << 8) | data[5]) - cal_data.z);/*CAL_DIV;*/ + + + if (mldl_cfg->pdata->orientation[0]) { + x *= mldl_cfg->pdata->orientation[0]; + y *= mldl_cfg->pdata->orientation[4]; + } else { + temp = x*mldl_cfg->pdata->orientation[1]; + x = y*mldl_cfg->pdata->orientation[3]; + y = temp; + } + z *= mldl_cfg->pdata->orientation[8]; + + + count = sprintf(buf, "%d, %d, %d\n", x, y, z); + + return count; + +} + +static ssize_t accel_calibration_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + + int count = 0; + int ret = 1; + + printk(buf, "%d %d %d\n", + cal_data.x, cal_data.y, cal_data.z); + + if (!cal_data.x && !cal_data.y && !cal_data.z) + ret = -1; + + count = sprintf(buf, "%d %d %d %d\n", ret, cal_data.x, + cal_data.y, cal_data.z); + + return count; +} + +static ssize_t accel_calibration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err; + int enable = 0; + + err = kstrtoint(buf, 10, &enable); + + if (err) { + pr_err("ERROR: %s got bad char\n", __func__); + return -EINVAL; + } + + err = accel_do_calibrate(enable); + if (err < 0) { + pr_err("%s: accel_do_calibrate() failed\n", __func__); + return err; + } + + return size; +} + +static int mpu_alert_factory_on(struct i2c_client *client) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(this_client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int prev_gyro_suspended = 0; + + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + printk(KERN_INFO"@@@@@ %s : %d @@@@@\n", __func__, __LINE__); + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + inv_mpu_resume(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_THREE_AXIS_ACCEL); + mutex_unlock(&mpu->mutex); + + return prev_gyro_suspended; +} + +static ssize_t accel_reactive_alert_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err = 0; + bool onoff = false, factory_test = false; + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *slave_adapter; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + + unsigned char reg_data = 0; + + slave_adapter = + i2c_get_adapter(pdata_slave[EXT_SLAVE_TYPE_ACCEL]->adapt_num); + + + if (sysfs_streq(buf, "1")) { + onoff = true; + } else if (sysfs_streq(buf, "0")) { + onoff = false; + } else if (sysfs_streq(buf, "2")) { + onoff = true; + factory_test = true; + + err = inv_serial_read(slave_adapter, 0x68, + MPUREG_INT_ENABLE, sizeof(reg_data), ®_data); + if (err) + pr_err("%s: read INT failed\n", __func__); + reg_data |= BIT_RAW_RDY_EN; + err = inv_serial_single_write(slave_adapter, 0x68, + MPUREG_INT_ENABLE, + reg_data); + if (err) + pr_err("%s: i2c write INT reg failed\n", __func__); + err = inv_serial_read(slave_adapter, 0x68, + MPUREG_INT_ENABLE, sizeof(reg_data), ®_data); + if (err) + pr_err("%s: read INT failed\n", __func__); + mpu_alert_factory_on(this_client); + err = inv_serial_single_write(slave_adapter, 0x68, + MPUREG_SMPLRT_DIV, + (unsigned char)19); + if (err) + pr_err("%s: set_DIV\n", __func__); + } else { + pr_err("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + if (onoff && !mldl_cfg->inv_mpu_state->accel_reactive) { + pr_info("reactive alert is on.\n"); + enable_irq_wake(client->irq); + + } else if (!onoff && mldl_cfg->inv_mpu_state->accel_reactive) { + pr_info("reactive alert is off.\n"); + disable_irq_wake(client->irq); + err = inv_serial_read(slave_adapter, 0x68, + MPUREG_INT_ENABLE, sizeof(reg_data), ®_data); + if (err) + pr_err("%s: read INT failed\n", __func__); + reg_data &= ~BIT_MOT_EN; + err = inv_serial_single_write(slave_adapter, 0x68, + MPUREG_INT_ENABLE, + reg_data); + if (err) + pr_err("%s: i2c write INT reg failed\n", __func__); + } + + mldl_cfg->inv_mpu_state->use_accel_reactive = onoff; + mldl_cfg->inv_mpu_state->accel_reactive = onoff; + mldl_cfg->inv_mpu_state->reactive_factory = factory_test; + return count; +} + + +static ssize_t accel_reactive_alert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + + if (mldl_cfg->inv_mpu_state->use_accel_reactive && + !mldl_cfg->inv_mpu_state->accel_reactive) + return sprintf(buf, "%d\n", 1); + else + return sprintf(buf, "%d\n", 0); +} + +static ssize_t mpu_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", MPU_VENDOR); +} + +static ssize_t mpu_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", MPU_PART_ID); +} + +#if defined(CONFIG_MPU_SENSORS_AK8975_411) +static int akm8975_wait_for_data_ready(struct i2c_adapter *sl_adapter) +{ + int err; + u8 buf; + int count = 10; + + while (1) { + msleep(20); + err = inv_serial_read(sl_adapter, 0x0C, + AK8975_REG_ST1, sizeof(buf), &buf); + if (err) { + pr_err("%s: read data over i2c failed\n", __func__); + return -EIO; + } + + if (buf&0x1) + break; + + count--; + if (!count) + break; + } + return 0; + +} + +static ssize_t ak8975_adc(struct device *dev, + struct device_attribute *attr, char *strbuf) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + + + u8 buf[8]; + s16 x, y, z; + int err, success; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + if (pdata_slave[EXT_SLAVE_TYPE_COMPASS] == NULL) + return snprintf(strbuf, PAGE_SIZE, "%s, %d, %d, %d\n", + "NG", 0, 0, 0); + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_COMPASS] = client->adapter; + + mutex_lock(&mpu->mutex); + + /* start ADC conversion */ + err = inv_serial_single_write(slave_adapter[EXT_SLAVE_TYPE_COMPASS], + 0x0C, AK8975_REG_CNTL, + AK8975_MODE_SNG_MEASURE); + + if (err) + pr_err("ak8975_adc write err:%d\n", err); + + /* wait for ADC conversion to complete */ + + err = akm8975_wait_for_data_ready + (slave_adapter[EXT_SLAVE_TYPE_COMPASS]); + if (err) { + pr_err("%s: wait for data ready failed\n", __func__); + return err; + } + + msleep(20);/*msleep(10);*/ + /* get the value and report it */ + err = inv_serial_read(slave_adapter[EXT_SLAVE_TYPE_COMPASS], 0x0C, + AK8975_REG_ST1, sizeof(buf), buf); + + if (err) { + pr_err("%s: read data over i2c failed %d\n", __func__, err); + mutex_unlock(&mpu->mutex); + return -EIO; + } + mutex_unlock(&mpu->mutex); + + /* buf[0] is status1, buf[7] is status2 */ + if ((buf[0] == 0) | (buf[7] == 1)) + success = 0; + else + success = 1; + + x = buf[1] | (buf[2] << 8); + y = buf[3] | (buf[4] << 8); + z = buf[5] | (buf[6] << 8); + + pr_err("%s: raw x = %d, y = %d, z = %d\n", __func__, x, y, z); + + return snprintf(strbuf, PAGE_SIZE, "%s,%d,%d,%d\n", + (success ? "OK" : "NG"), x, y, z); +} + +static ssize_t ak8975_check_cntl(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + + int ii, err; + u8 data; + + if (pdata_slave[EXT_SLAVE_TYPE_COMPASS] == NULL) + return snprintf(buf, PAGE_SIZE, "%s\n", "NG"); + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_COMPASS] = client->adapter; + mutex_lock(&mpu->mutex); + err = inv_serial_single_write(slave_adapter[EXT_SLAVE_TYPE_COMPASS], + 0x0C, AK8975_REG_CNTL, + AK8975_MODE_POWER_DOWN); + + if (err) { + pr_err("ak8975_adc write err:%d\n", err); + mutex_unlock(&mpu->mutex); + return -EIO; + } + err = inv_serial_read(slave_adapter[EXT_SLAVE_TYPE_COMPASS], 0x0C, + AK8975_REG_CNTL, sizeof(data), &data); + if (err) { + pr_err("%s: read data over i2c failed %d\n", __func__, err); + mutex_unlock(&mpu->mutex); + return -EIO; + } + mutex_unlock(&mpu->mutex); + + return snprintf(buf, PAGE_SIZE, "%s\n", + data == AK8975_MODE_POWER_DOWN ? "OK" : "NG"); + +} + +static ssize_t akm8975_rawdata_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + + short x = 0, y = 0, z = 0; + int err; + u8 data[8]; + + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_COMPASS] = client->adapter; + + + mutex_lock(&mpu->mutex); + err = inv_serial_single_write(slave_adapter[EXT_SLAVE_TYPE_COMPASS], + 0x0C, AK8975_REG_CNTL, + AK8975_MODE_SNG_MEASURE); + + if (err) { + pr_err("ak8975_adc write err:%d\n", err); + mutex_unlock(&mpu->mutex); + goto done; + + } + + err = akm8975_wait_for_data_ready + (slave_adapter[EXT_SLAVE_TYPE_COMPASS]); + if (err) { + mutex_unlock(&mpu->mutex); + goto done; + } + + /* get the value and report it */ + err = inv_serial_read(slave_adapter[EXT_SLAVE_TYPE_COMPASS], 0x0C, + AK8975_REG_ST1, sizeof(data), data); + + if (err) { + pr_err("%s: read data over i2c failed %d\n", __func__, err); + mutex_unlock(&mpu->mutex); + return -EIO; + } + + mutex_unlock(&mpu->mutex); + + if (err) { + pr_err("%s: failed to read %d bytes of mag data\n", + __func__, sizeof(data)); + goto done; + } + + if (data[0] & 0x01) { + x = (data[2] << 8) + data[1]; + y = (data[4] << 8) + data[3]; + z = (data[6] << 8) + data[5]; + } else + pr_err("%s: invalid raw data(st1 = %d)\n", + __func__, data[0] & 0x01); + +done: + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", x, y, z); +} + +struct ak8975_config { + char asa[COMPASS_NUM_AXES]; /* axis sensitivity adjustment */ +}; + +struct ak8975_private_data { + struct ak8975_config init; +}; +static ssize_t ak8975c_get_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int success; + + struct ak8975_private_data *private_data; + if (pdata_slave[EXT_SLAVE_TYPE_COMPASS] == NULL) + return snprintf(buf, PAGE_SIZE, "%s\n", "NG"); + + private_data = + (struct ak8975_private_data *) + pdata_slave[EXT_SLAVE_TYPE_COMPASS]->private_data; + if ((private_data->init.asa[0] == 0) | + (private_data->init.asa[0] == 0xff) | + (private_data->init.asa[1] == 0) | + (private_data->init.asa[1] == 0xff) | + (private_data->init.asa[2] == 0) | + (private_data->init.asa[2] == 0xff)) + success = 0; + else + success = 1; + + return snprintf(buf, PAGE_SIZE, "%s\n", (success ? "OK" : "NG")); + +} + +int ak8975c_selftest(struct i2c_adapter *slave_adapter, + struct ak8975_private_data *private_data, int *sf) +{ + int err; + u8 data; + u8 buf[6]; + int count = 20; + s16 x, y, z; + + /* set ATSC self test bit to 1 */ + err = inv_serial_single_write(slave_adapter, 0x0C, + AK8975_REG_ASTC, 0x40); + + /* start self test */ + err = inv_serial_single_write(slave_adapter, 0x0C, + AK8975_REG_CNTL, AK8975_MODE_SELF_TEST); + + /* wait for data ready */ + while (1) { + msleep(20); + err = inv_serial_read(slave_adapter, 0x0C, + AK8975_REG_ST1, sizeof(data), &data); + + if (data == 1) + break; + count--; + if (!count) + break; + } + err = inv_serial_read(slave_adapter, 0x0C, + AK8975_REG_HXL, sizeof(buf), buf); + + /* set ATSC self test bit to 0 */ + err = inv_serial_single_write(slave_adapter, 0x0C, + AK8975_REG_ASTC, 0x00); + + x = buf[0] | (buf[1] << 8); + y = buf[2] | (buf[3] << 8); + z = buf[4] | (buf[5] << 8); + + /* Hadj = (H*(Asa+128))/256 */ + x = (x*(private_data->init.asa[0] + 128)) >> 8; + y = (y*(private_data->init.asa[1] + 128)) >> 8; + z = (z*(private_data->init.asa[2] + 128)) >> 8; + + pr_info("%s: self test x = %d, y = %d, z = %d\n", + __func__, x, y, z); + if ((x >= -200) && (x <= 200)) + pr_info("%s: x passed self test, expect -200<=x<=200\n", + __func__); + else + pr_info("%s: x failed self test, expect -200<=x<=200\n", + __func__); + if ((y >= -200) && (y <= 200)) + pr_info("%s: y passed self test, expect -200<=y<=200\n", + __func__); + else + pr_info("%s: y failed self test, expect -200<=y<=200\n", + __func__); + if ((z >= -3200) && (z <= -800)) + pr_info("%s: z passed self test, expect -3200<=z<=-800\n", + __func__); + else + pr_info("%s: z failed self test, expect -3200<=z<=-800\n", + __func__); + + sf[0] = x; + sf[1] = y; + sf[2] = z; + + if (((x >= -200) && (x <= 200)) && + ((y >= -200) && (y <= 200)) && + ((z >= -3200) && (z <= -800))) + return 1; + else + return 0; + + +} + +static ssize_t ak8975c_get_selftest(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + struct ak8975_private_data *private_data; + + int ii, success; + int sf[3] = {0,}; + int retry = 3; + + if (pdata_slave[EXT_SLAVE_TYPE_COMPASS] == NULL) + return snprintf(buf, PAGE_SIZE, "%d, %d, %d, %d\n", + 0, 0, 0, 0); + + private_data = + (struct ak8975_private_data *) + pdata_slave[EXT_SLAVE_TYPE_COMPASS]->private_data; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_COMPASS] = client->adapter; + do { + retry--; + success = ak8975c_selftest( + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + private_data, sf); + if (success) + break; + } while (retry > 0); + + return snprintf(buf, PAGE_SIZE, "%d, %d, %d, %d\n", + success, sf[0], sf[1], sf[2]); +} + +static ssize_t akm_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", MAG_VENDOR); +} + +static ssize_t akm_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", MAG_PART_ID); +} +#endif + +static DEVICE_ATTR(power_on, S_IRUGO, mpu3050_power_on, NULL); + +static DEVICE_ATTR(temperature, S_IRUGO, mpu3050_get_temp, NULL); + +static DEVICE_ATTR(calibration, S_IRUGO|S_IWUSR|S_IWGRP, + accel_calibration_show, accel_calibration_store); + +static DEVICE_ATTR(raw_data, S_IRUGO, mpu3050_acc_read, NULL); + +static DEVICE_ATTR(reactive_alert, S_IRUGO|S_IWUSR|S_IWGRP, + accel_reactive_alert_show, + accel_reactive_alert_store); + +static DEVICE_ATTR(vendor, S_IRUGO, mpu_vendor_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, mpu_name_show, NULL); + + +#if defined(CONFIG_MPU_SENSORS_AK8975_411) +static DEVICE_ATTR(adc, S_IRUGO, ak8975_adc, NULL); + +static DEVICE_ATTR(dac, S_IRUGO, + ak8975_check_cntl, NULL); +static DEVICE_ATTR(status, S_IRUGO, + ak8975c_get_status, NULL); +static DEVICE_ATTR(selftest, S_IRUGO, + ak8975c_get_selftest, NULL); + +static struct device_attribute dev_attr_mag_rawdata = + __ATTR(raw_data, S_IRUGO, + akm8975_rawdata_show, NULL); + +static struct device_attribute dev_attr_mag_vendor = + __ATTR(vendor, S_IRUGO, + akm_vendor_show, NULL); + +static struct device_attribute dev_attr_mag_name = + __ATTR(name, S_IRUGO, + akm_name_show, NULL); +#endif + +static struct device_attribute *gyro_sensor_attrs[] = { + &dev_attr_power_on, + &dev_attr_temperature, + &dev_attr_vendor, + &dev_attr_name, +/* &dev_attr_selftest,*/ + NULL, +}; + +static struct device_attribute *accel_sensor_attrs[] = { + &dev_attr_raw_data, + &dev_attr_calibration, + &dev_attr_reactive_alert, + &dev_attr_vendor, + &dev_attr_name, + NULL, +}; + +#if defined(CONFIG_MPU_SENSORS_AK8975_411) +static struct device_attribute *magnetic_sensor_attrs[] = { + &dev_attr_adc, + &dev_attr_mag_rawdata, + &dev_attr_dac, + &dev_attr_status, + &dev_attr_selftest, + &dev_attr_mag_vendor, + &dev_attr_mag_name, + NULL, +}; +#endif + +static struct device *gsensorcal; + + +static struct device *gyro_sensor_device; +static struct device *accel_sensor_device; + +#if defined(CONFIG_MPU_SENSORS_AK8975_411) +static struct device *magnetic_sensor_device; +#endif + +int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid) +{ + struct mpu_platform_data *pdata; + struct mpu_private_data *mpu; + struct mldl_cfg *mldl_cfg; + int res = 0; + int ii = 0; + + dev_info(&client->adapter->dev, "%s: %d\n", __func__, ii++); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + res = -ENODEV; + goto out_check_functionality_failed; + } + + mpu = kzalloc(sizeof(struct mpu_private_data), GFP_KERNEL); + if (!mpu) { + res = -ENOMEM; + goto out_alloc_data_failed; + } + mldl_cfg = &mpu->mldl_cfg; + mldl_cfg->mpu_ram = &mpu->mpu_ram; + mldl_cfg->mpu_gyro_cfg = &mpu->mpu_gyro_cfg; + mldl_cfg->mpu_offsets = &mpu->mpu_offsets; + mldl_cfg->mpu_chip_info = &mpu->mpu_chip_info; + mldl_cfg->inv_mpu_cfg = &mpu->inv_mpu_cfg; + mldl_cfg->inv_mpu_state = &mpu->inv_mpu_state; + + mldl_cfg->mpu_ram->length = MPU_MEM_NUM_RAM_BANKS * MPU_MEM_BANK_SIZE; + mldl_cfg->mpu_ram->ram = kzalloc(mldl_cfg->mpu_ram->length, GFP_KERNEL); + if (!mldl_cfg->mpu_ram->ram) { + res = -ENOMEM; + goto out_alloc_ram_failed; + } + mpu_private_data = mpu; + i2c_set_clientdata(client, mpu); + this_client = client; + mpu->client = client; + + init_waitqueue_head(&mpu->mpu_event_wait); + mutex_init(&mpu->mutex); + init_completion(&mpu->completion); + + mpu->response_timeout = 1; /* Seconds */ + mpu->timeout.function = mpu_pm_timeout; + mpu->timeout.data = (u_long) mpu; + init_timer(&mpu->timeout); + + mpu->activate_timeout = 10; + hrtimer_init(&mpu->activate_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + mpu->activate_timer.function = mpu_actiavte_sensors_callback; + + pdata = (struct mpu_platform_data *)client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for mpu\n"); + goto out_whoami_failed; + } + mldl_cfg->pdata = pdata; + if (mldl_cfg->pdata->poweron) + mldl_cfg->pdata->poweron(1); + + mldl_cfg->mpu_chip_info->addr = client->addr; + res = inv_mpu_open(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL); + + if (res) { + dev_err(&client->adapter->dev, + "Unable to open %s %d\n", MPU_NAME, res); + res = -ENODEV; + goto out_whoami_failed; + } + + mpu->dev.minor = MISC_DYNAMIC_MINOR; + mpu->dev.name = "mpu"; + mpu->dev.fops = &mpu_fops; + res = misc_register(&mpu->dev); + if (res < 0) { + dev_err(&client->adapter->dev, + "ERROR: misc_register returned %d\n", res); + goto out_misc_register_failed; + } + + if (client->irq) { + dev_info(&client->adapter->dev, + "Installing irq using %d\n", client->irq); + res = mpuirq_init(client, mldl_cfg); + if (res) + goto out_mpuirq_failed; + } else { + dev_warn(&client->adapter->dev, + "Missing %s IRQ\n", MPU_NAME); + } + if (!strcmp(mpu_id[1].name, devid->name)) { + /* Special case to re-use the inv_mpu_register_slave */ + struct ext_slave_platform_data *slave_pdata; + slave_pdata = kzalloc(sizeof(*slave_pdata), GFP_KERNEL); + if (!slave_pdata) { + res = -ENOMEM; + goto out_slave_pdata_kzalloc_failed; + } + slave_pdata->bus = EXT_SLAVE_BUS_PRIMARY; + for (ii = 0; ii < 9; ii++) + slave_pdata->orientation[ii] = pdata->orientation[ii]; + res = inv_mpu_register_slave( + NULL, client, + slave_pdata, + mpu6050_get_slave_descr); + if (res) { + /* if inv_mpu_register_slave fails there are no pointer + references to the memory allocated to slave_pdata */ + kfree(slave_pdata); + goto out_slave_pdata_kzalloc_failed; + } + } + +#ifdef CONFIG_INPUT_YAS_MAGNETOMETER + { + __s8 orientation[9] = { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + }; + /* Special case to re-use the inv_mpu_register_slave */ + struct ext_slave_platform_data *slave_pdata; + slave_pdata = kzalloc(sizeof(*slave_pdata), GFP_KERNEL); + if (!slave_pdata) { + res = -ENOMEM; + goto out_slave_pdata_kzalloc_failed; + } + slave_pdata->bus = EXT_SLAVE_BUS_PRIMARY; + for (ii = 0; ii < 9; ii++) + slave_pdata->orientation[ii] = orientation[ii]; + res = inv_mpu_register_slave( + NULL, client, + slave_pdata, + yas530_ext_get_slave_descr); + if (res) { + /* if inv_mpu_register_slave fails there are no pointer + references to the memory allocated to slave_pdata */ + kfree(slave_pdata); + goto out_slave_pdata_kzalloc_failed; + } + } +#endif /*CONFIG_INPUT_YAS_MAGNETOMETER*/ + + + res = sensors_register(gyro_sensor_device, NULL, + gyro_sensor_attrs, "gyro_sensor"); + if (res) { + printk(KERN_ERR + "%s: cound not register gyro sensor device(%d).\n", + __func__, res); + } + + res = sensors_register(accel_sensor_device, NULL, + accel_sensor_attrs, "accelerometer_sensor"); + if (res) { + printk(KERN_ERR + "%s: cound not register accelerometer sensor device(%d).\n", + __func__, res); + goto out_sensor_register_failed; + } + +#if defined(CONFIG_MPU_SENSORS_AK8975_411) + res = sensors_register(magnetic_sensor_device, NULL, + magnetic_sensor_attrs, "magnetic_sensor"); + if (res) { + printk(KERN_ERR + "%s: cound not register magnetic sensor device(%d).\n", + __func__, res); + goto out_sensor_register_failed; + } +#endif + + gsensorcal = device_create(sec_class, NULL, 0, mpu, "gsensorcal"); + if (IS_ERR(gsensorcal)) + printk(KERN_ERR "Failed to create device!"); + + if (device_create_file(gsensorcal, &dev_attr_calibration) < 0) { + printk(KERN_ERR "Failed to create device file(%s)!\n", + dev_attr_calibration.attr.name); + goto out_gsensorcal_failed; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + mpu->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1; + mpu->early_suspend.suspend = mpu_dev_early_suspend; + mpu->early_suspend.resume = mpu_dev_early_resume; + register_early_suspend(&mpu->early_suspend); +#endif + + return res; + +out_gsensorcal_failed: +out_sensor_register_failed: +out_slave_pdata_kzalloc_failed: + if (client->irq) + mpuirq_exit(); +out_mpuirq_failed: + misc_deregister(&mpu->dev); +out_misc_register_failed: + inv_mpu_close(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL); +out_whoami_failed: + kfree(mldl_cfg->mpu_ram->ram); + mpu_private_data = NULL; +out_alloc_ram_failed: + kfree(mpu); +out_alloc_data_failed: +out_check_functionality_failed: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, res); + return res; + +} + +static int mpu_remove(struct i2c_client *client) +{ + struct mpu_private_data *mpu = i2c_get_clientdata(client); + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_close(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE]); + + if (mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL] && + (mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL]->id == + ACCEL_ID_MPU6050)) { + struct ext_slave_platform_data *slave_pdata = + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL]; + inv_mpu_unregister_slave( + client, + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL], + mpu6050_get_slave_descr); + kfree(slave_pdata); + } + + if (client->irq) + mpuirq_exit(); + + misc_deregister(&mpu->dev); + + + kfree(mpu->mldl_cfg.mpu_ram->ram); + kfree(mpu); + + return 0; +} + +static struct i2c_driver mpu_driver = { + .class = I2C_CLASS_HWMON, + .probe = mpu_probe, + .remove = mpu_remove, + .id_table = mpu_id, + .driver = { + .owner = THIS_MODULE, + .name = MPU_NAME, + }, + .address_list = normal_i2c, + .shutdown = mpu_shutdown, /* optional */ + .suspend = mpu_dev_suspend, /* optional */ + .resume = mpu_dev_resume, /* optional */ + +}; + +static int __init mpu_init(void) +{ + int res = i2c_add_driver(&mpu_driver); + pr_info("%s: Probe name %s\n", __func__, MPU_NAME); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit mpu_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&mpu_driver); +} + +module_init(mpu_init); +module_exit(mpu_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("User space character device interface for MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS(MPU_NAME); diff --git a/drivers/misc/inv_mpu/mpu-dev.h b/drivers/misc/inv_mpu/mpu-dev.h new file mode 100644 index 00000000000..cf05161cf5d --- /dev/null +++ b/drivers/misc/inv_mpu/mpu-dev.h @@ -0,0 +1,43 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + + +#ifndef __MPU_DEV_H__ +#define __MPU_DEV_H__ + +#include +#include +#include + +int inv_mpu_register_slave(struct module *slave_module, + struct i2c_client *client, + struct ext_slave_platform_data *pdata, + struct ext_slave_descr *(*slave_descr)(void)); + +void inv_mpu_unregister_slave(struct i2c_client *client, + struct ext_slave_platform_data *pdata, + struct ext_slave_descr *(*slave_descr)(void)); + +extern struct class *sec_class; +extern struct class *sensors_class; +extern int sensors_register(struct device *dev, void * drvdata, + struct device_attribute *attributes[], char *name); +/* extern signed short gAccelOffset[3];*/ + +#endif diff --git a/drivers/misc/inv_mpu/mpu6050b1.h b/drivers/misc/inv_mpu/mpu6050b1.h new file mode 100644 index 00000000000..c486784856c --- /dev/null +++ b/drivers/misc/inv_mpu/mpu6050b1.h @@ -0,0 +1,437 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +/** + * @defgroup + * @brief + * + * @{ + * @file mpu6050.h + * @brief + */ + +#ifndef __MPU_H_ +#error Do not include this file directly. Include mpu.h instead. +#endif + +#ifndef __MPU6050B1_H_ +#define __MPU6050B1_H_ + + +#define MPU_NAME "mpu6050" +#define DEFAULT_MPU_SLAVEADDR 0x68 +extern struct acc_data cal_data; + + +/*==== MPU6050B1 REGISTER SET ====*/ +enum { + MPUREG_XG_OFFS_TC = 0, /* 0x00, 0 */ + MPUREG_YG_OFFS_TC, /* 0x01, 1 */ + MPUREG_ZG_OFFS_TC, /* 0x02, 2 */ + MPUREG_X_FINE_GAIN, /* 0x03, 3 */ + MPUREG_Y_FINE_GAIN, /* 0x04, 4 */ + MPUREG_Z_FINE_GAIN, /* 0x05, 5 */ + MPUREG_XA_OFFS_H, /* 0x06, 6 */ + MPUREG_XA_OFFS_L, /* 0x07, 7 */ + MPUREG_YA_OFFS_H, /* 0x08, 8 */ + MPUREG_YA_OFFS_L, /* 0x09, 9 */ + MPUREG_ZA_OFFS_H, /* 0x0a, 10 */ + MPUREG_ZA_OFFS_L, /* 0x0B, 11 */ + MPUREG_PRODUCT_ID, /* 0x0c, 12 */ + MPUREG_0D_RSVD, /* 0x0d, 13 */ + MPUREG_0E_RSVD, /* 0x0e, 14 */ + MPUREG_0F_RSVD, /* 0x0f, 15 */ + MPUREG_10_RSVD, /* 0x00, 16 */ + MPUREG_11_RSVD, /* 0x11, 17 */ + MPUREG_12_RSVD, /* 0x12, 18 */ + MPUREG_XG_OFFS_USRH, /* 0x13, 19 */ + MPUREG_XG_OFFS_USRL, /* 0x14, 20 */ + MPUREG_YG_OFFS_USRH, /* 0x15, 21 */ + MPUREG_YG_OFFS_USRL, /* 0x16, 22 */ + MPUREG_ZG_OFFS_USRH, /* 0x17, 23 */ + MPUREG_ZG_OFFS_USRL, /* 0x18, 24 */ + MPUREG_SMPLRT_DIV, /* 0x19, 25 */ + MPUREG_CONFIG, /* 0x1A, 26 */ + MPUREG_GYRO_CONFIG, /* 0x1b, 27 */ + MPUREG_ACCEL_CONFIG, /* 0x1c, 28 */ + MPUREG_ACCEL_FF_THR, /* 0x1d, 29 */ + MPUREG_ACCEL_FF_DUR, /* 0x1e, 30 */ + MPUREG_ACCEL_MOT_THR, /* 0x1f, 31 */ + MPUREG_ACCEL_MOT_DUR, /* 0x20, 32 */ + MPUREG_ACCEL_ZRMOT_THR, /* 0x21, 33 */ + MPUREG_ACCEL_ZRMOT_DUR, /* 0x22, 34 */ + MPUREG_FIFO_EN, /* 0x23, 35 */ + MPUREG_I2C_MST_CTRL, /* 0x24, 36 */ + MPUREG_I2C_SLV0_ADDR, /* 0x25, 37 */ + MPUREG_I2C_SLV0_REG, /* 0x26, 38 */ + MPUREG_I2C_SLV0_CTRL, /* 0x27, 39 */ + MPUREG_I2C_SLV1_ADDR, /* 0x28, 40 */ + MPUREG_I2C_SLV1_REG, /* 0x29, 41 */ + MPUREG_I2C_SLV1_CTRL, /* 0x2a, 42 */ + MPUREG_I2C_SLV2_ADDR, /* 0x2B, 43 */ + MPUREG_I2C_SLV2_REG, /* 0x2c, 44 */ + MPUREG_I2C_SLV2_CTRL, /* 0x2d, 45 */ + MPUREG_I2C_SLV3_ADDR, /* 0x2E, 46 */ + MPUREG_I2C_SLV3_REG, /* 0x2f, 47 */ + MPUREG_I2C_SLV3_CTRL, /* 0x30, 48 */ + MPUREG_I2C_SLV4_ADDR, /* 0x31, 49 */ + MPUREG_I2C_SLV4_REG, /* 0x32, 50 */ + MPUREG_I2C_SLV4_DO, /* 0x33, 51 */ + MPUREG_I2C_SLV4_CTRL, /* 0x34, 52 */ + MPUREG_I2C_SLV4_DI, /* 0x35, 53 */ + MPUREG_I2C_MST_STATUS, /* 0x36, 54 */ + MPUREG_INT_PIN_CFG, /* 0x37, 55 */ + MPUREG_INT_ENABLE, /* 0x38, 56 */ + MPUREG_DMP_INT_STATUS, /* 0x39, 57 */ + MPUREG_INT_STATUS, /* 0x3A, 58 */ + MPUREG_ACCEL_XOUT_H, /* 0x3B, 59 */ + MPUREG_ACCEL_XOUT_L, /* 0x3c, 60 */ + MPUREG_ACCEL_YOUT_H, /* 0x3d, 61 */ + MPUREG_ACCEL_YOUT_L, /* 0x3e, 62 */ + MPUREG_ACCEL_ZOUT_H, /* 0x3f, 63 */ + MPUREG_ACCEL_ZOUT_L, /* 0x40, 64 */ + MPUREG_TEMP_OUT_H, /* 0x41, 65 */ + MPUREG_TEMP_OUT_L, /* 0x42, 66 */ + MPUREG_GYRO_XOUT_H, /* 0x43, 67 */ + MPUREG_GYRO_XOUT_L, /* 0x44, 68 */ + MPUREG_GYRO_YOUT_H, /* 0x45, 69 */ + MPUREG_GYRO_YOUT_L, /* 0x46, 70 */ + MPUREG_GYRO_ZOUT_H, /* 0x47, 71 */ + MPUREG_GYRO_ZOUT_L, /* 0x48, 72 */ + MPUREG_EXT_SLV_SENS_DATA_00, /* 0x49, 73 */ + MPUREG_EXT_SLV_SENS_DATA_01, /* 0x4a, 74 */ + MPUREG_EXT_SLV_SENS_DATA_02, /* 0x4b, 75 */ + MPUREG_EXT_SLV_SENS_DATA_03, /* 0x4c, 76 */ + MPUREG_EXT_SLV_SENS_DATA_04, /* 0x4d, 77 */ + MPUREG_EXT_SLV_SENS_DATA_05, /* 0x4e, 78 */ + MPUREG_EXT_SLV_SENS_DATA_06, /* 0x4F, 79 */ + MPUREG_EXT_SLV_SENS_DATA_07, /* 0x50, 80 */ + MPUREG_EXT_SLV_SENS_DATA_08, /* 0x51, 81 */ + MPUREG_EXT_SLV_SENS_DATA_09, /* 0x52, 82 */ + MPUREG_EXT_SLV_SENS_DATA_10, /* 0x53, 83 */ + MPUREG_EXT_SLV_SENS_DATA_11, /* 0x54, 84 */ + MPUREG_EXT_SLV_SENS_DATA_12, /* 0x55, 85 */ + MPUREG_EXT_SLV_SENS_DATA_13, /* 0x56, 86 */ + MPUREG_EXT_SLV_SENS_DATA_14, /* 0x57, 87 */ + MPUREG_EXT_SLV_SENS_DATA_15, /* 0x58, 88 */ + MPUREG_EXT_SLV_SENS_DATA_16, /* 0x59, 89 */ + MPUREG_EXT_SLV_SENS_DATA_17, /* 0x5a, 90 */ + MPUREG_EXT_SLV_SENS_DATA_18, /* 0x5B, 91 */ + MPUREG_EXT_SLV_SENS_DATA_19, /* 0x5c, 92 */ + MPUREG_EXT_SLV_SENS_DATA_20, /* 0x5d, 93 */ + MPUREG_EXT_SLV_SENS_DATA_21, /* 0x5e, 94 */ + MPUREG_EXT_SLV_SENS_DATA_22, /* 0x5f, 95 */ + MPUREG_EXT_SLV_SENS_DATA_23, /* 0x60, 96 */ + MPUREG_ACCEL_INTEL_STATUS, /* 0x61, 97 */ + MPUREG_62_RSVD, /* 0x62, 98 */ + MPUREG_I2C_SLV0_DO, /* 0x63, 99 */ + MPUREG_I2C_SLV1_DO, /* 0x64, 100 */ + MPUREG_I2C_SLV2_DO, /* 0x65, 101 */ + MPUREG_I2C_SLV3_DO, /* 0x66, 102 */ + MPUREG_I2C_MST_DELAY_CTRL, /* 0x67, 103 */ + MPUREG_SIGNAL_PATH_RESET, /* 0x68, 104 */ + MPUREG_ACCEL_INTEL_CTRL, /* 0x69, 105 */ + MPUREG_USER_CTRL, /* 0x6A, 106 */ + MPUREG_PWR_MGMT_1, /* 0x6B, 107 */ + MPUREG_PWR_MGMT_2, /* 0x6C, 108 */ + MPUREG_BANK_SEL, /* 0x6D, 109 */ + MPUREG_MEM_START_ADDR, /* 0x6E, 100 */ + MPUREG_MEM_R_W, /* 0x6F, 111 */ + MPUREG_DMP_CFG_1, /* 0x70, 112 */ + MPUREG_DMP_CFG_2, /* 0x71, 113 */ + MPUREG_FIFO_COUNTH, /* 0x72, 114 */ + MPUREG_FIFO_COUNTL, /* 0x73, 115 */ + MPUREG_FIFO_R_W, /* 0x74, 116 */ + MPUREG_WHOAMI, /* 0x75, 117 */ + + NUM_OF_MPU_REGISTERS /* = 0x76, 118 */ +}; + +/*==== MPU6050B1 MEMORY ====*/ +enum MPU_MEMORY_BANKS { + MEM_RAM_BANK_0 = 0, + MEM_RAM_BANK_1, + MEM_RAM_BANK_2, + MEM_RAM_BANK_3, + MEM_RAM_BANK_4, + MEM_RAM_BANK_5, + MEM_RAM_BANK_6, + MEM_RAM_BANK_7, + MEM_RAM_BANK_8, + MEM_RAM_BANK_9, + MEM_RAM_BANK_10, + MEM_RAM_BANK_11, + MPU_MEM_NUM_RAM_BANKS, + MPU_MEM_OTP_BANK_0 = 16 +}; + + +/*==== MPU6050B1 parameters ====*/ + +#define NUM_REGS (NUM_OF_MPU_REGISTERS) +#define START_SENS_REGS (0x3B) +#define NUM_SENS_REGS (0x60 - START_SENS_REGS + 1) + +/*---- MPU Memory ----*/ +#define NUM_BANKS (MPU_MEM_NUM_RAM_BANKS) +#define BANK_SIZE (256) +#define MEM_SIZE (NUM_BANKS * BANK_SIZE) +#define MPU_MEM_BANK_SIZE (BANK_SIZE) /*alternative name */ + +#define FIFO_HW_SIZE (1024) + +#define NUM_EXT_SLAVES (4) + + +/*==== BITS FOR MPU6050B1 ====*/ +/*---- MPU6050B1 'XG_OFFS_TC' register (0, 1, 2) ----*/ +#define BIT_PU_SLEEP_MODE 0x80 +#define BITS_XG_OFFS_TC 0x7E +#define BIT_OTP_BNK_VLD 0x01 + +#define BIT_I2C_MST_VDDIO 0x80 +#define BITS_YG_OFFS_TC 0x7E +#define BITS_ZG_OFFS_TC 0x7E +/*---- MPU6050B1 'FIFO_EN' register (23) ----*/ +#define BIT_TEMP_OUT 0x80 +#define BIT_GYRO_XOUT 0x40 +#define BIT_GYRO_YOUT 0x20 +#define BIT_GYRO_ZOUT 0x10 +#define BIT_ACCEL 0x08 +#define BIT_SLV_2 0x04 +#define BIT_SLV_1 0x02 +#define BIT_SLV_0 0x01 +/*---- MPU6050B1 'CONFIG' register (1A) ----*/ +/*NONE 0xC0 */ +#define BITS_EXT_SYNC_SET 0x38 +#define BITS_DLPF_CFG 0x07 +/*---- MPU6050B1 'GYRO_CONFIG' register (1B) ----*/ +/* voluntarily modified label from BITS_FS_SEL to + * BITS_GYRO_FS_SEL to avoid confusion with MPU + */ +#define BITS_GYRO_FS_SEL 0x18 +/*NONE 0x07 */ +/*---- MPU6050B1 'ACCEL_CONFIG' register (1C) ----*/ +#define BITS_ACCEL_FS_SEL 0x18 +#define BITS_ACCEL_HPF 0x07 +/*---- MPU6050B1 'I2C_MST_CTRL' register (24) ----*/ +#define BIT_MULT_MST_EN 0x80 +#define BIT_WAIT_FOR_ES 0x40 +#define BIT_SLV_3_FIFO_EN 0x20 +#define BIT_I2C_MST_PSR 0x10 +#define BITS_I2C_MST_CLK 0x0F +/*---- MPU6050B1 'I2C_SLV?_ADDR' register (27,2A,2D,30) ----*/ +#define BIT_I2C_READ 0x80 +#define BIT_I2C_WRITE 0x00 +#define BITS_I2C_ADDR 0x7F +/*---- MPU6050B1 'I2C_SLV?_CTRL' register (27,2A,2D,30) ----*/ +#define BIT_SLV_ENABLE 0x80 +#define BIT_SLV_BYTE_SW 0x40 +#define BIT_SLV_REG_DIS 0x20 +#define BIT_SLV_GRP 0x10 +#define BITS_SLV_LENG 0x0F +/*---- MPU6050B1 'I2C_SLV4_ADDR' register (31) ----*/ +#define BIT_I2C_SLV4_RNW 0x80 +/*---- MPU6050B1 'I2C_SLV4_CTRL' register (34) ----*/ +#define BIT_I2C_SLV4_EN 0x80 +#define BIT_SLV4_DONE_INT_EN 0x40 +#define BIT_SLV4_REG_DIS 0x20 +#define MASK_I2C_MST_DLY 0x1F +/*---- MPU6050B1 'I2C_MST_STATUS' register (36) ----*/ +#define BIT_PASS_THROUGH 0x80 +#define BIT_I2C_SLV4_DONE 0x40 +#define BIT_I2C_LOST_ARB 0x20 +#define BIT_I2C_SLV4_NACK 0x10 +#define BIT_I2C_SLV3_NACK 0x08 +#define BIT_I2C_SLV2_NACK 0x04 +#define BIT_I2C_SLV1_NACK 0x02 +#define BIT_I2C_SLV0_NACK 0x01 +/*---- MPU6050B1 'INT_PIN_CFG' register (37) ----*/ +#define BIT_ACTL 0x80 +#define BIT_ACTL_LOW 0x80 +#define BIT_ACTL_HIGH 0x00 +#define BIT_OPEN 0x40 +#define BIT_LATCH_INT_EN 0x20 +#define BIT_INT_ANYRD_2CLEAR 0x10 +#define BIT_ACTL_FSYNC 0x08 +#define BIT_FSYNC_INT_EN 0x04 +#define BIT_BYPASS_EN 0x02 +#define BIT_CLKOUT_EN 0x01 +/*---- MPU6050B1 'INT_ENABLE' register (38) ----*/ +#define BIT_FF_EN 0x80 +#define BIT_MOT_EN 0x40 +#define BIT_ZMOT_EN 0x20 +#define BIT_FIFO_OVERFLOW_EN 0x10 +#define BIT_I2C_MST_INT_EN 0x08 +#define BIT_PLL_RDY_EN 0x04 +#define BIT_DMP_INT_EN 0x02 +#define BIT_RAW_RDY_EN 0x01 +/*---- MPU6050B1 'DMP_INT_STATUS' register (39) ----*/ +/*NONE 0x80 */ +/*NONE 0x40 */ +#define BIT_DMP_INT_5 0x20 +#define BIT_DMP_INT_4 0x10 +#define BIT_DMP_INT_3 0x08 +#define BIT_DMP_INT_2 0x04 +#define BIT_DMP_INT_1 0x02 +#define BIT_DMP_INT_0 0x01 +/*---- MPU6050B1 'INT_STATUS' register (3A) ----*/ +#define BIT_FF_INT 0x80 +#define BIT_MOT_INT 0x40 +#define BIT_ZMOT_INT 0x20 +#define BIT_FIFO_OVERFLOW_INT 0x10 +#define BIT_I2C_MST_INT 0x08 +#define BIT_PLL_RDY_INT 0x04 +#define BIT_DMP_INT 0x02 +#define BIT_RAW_DATA_RDY_INT 0x01 +/*---- MPU6050B1 'MPUREG_I2C_MST_DELAY_CTRL' register (0x67) ----*/ +#define BIT_DELAY_ES_SHADOW 0x80 +#define BIT_SLV4_DLY_EN 0x10 +#define BIT_SLV3_DLY_EN 0x08 +#define BIT_SLV2_DLY_EN 0x04 +#define BIT_SLV1_DLY_EN 0x02 +#define BIT_SLV0_DLY_EN 0x01 +/*---- MPU6050B1 'BANK_SEL' register (6D) ----*/ +#define BIT_PRFTCH_EN 0x40 +#define BIT_CFG_USER_BANK 0x20 +#define BITS_MEM_SEL 0x1f +/*---- MPU6050B1 'USER_CTRL' register (6A) ----*/ +#define BIT_DMP_EN 0x80 +#define BIT_FIFO_EN 0x40 +#define BIT_I2C_MST_EN 0x20 +#define BIT_I2C_IF_DIS 0x10 +#define BIT_DMP_RST 0x08 +#define BIT_FIFO_RST 0x04 +#define BIT_I2C_MST_RST 0x02 +#define BIT_SIG_COND_RST 0x01 +/*---- MPU6050B1 'PWR_MGMT_1' register (6B) ----*/ +#define BIT_H_RESET 0x80 +#define BIT_SLEEP 0x40 +#define BIT_CYCLE 0x20 +#define BIT_PD_PTAT 0x08 +#define BITS_CLKSEL 0x07 +/*---- MPU6050B1 'PWR_MGMT_2' register (6C) ----*/ +#define BITS_LPA_WAKE_CTRL 0xC0 +#define BITS_LPA_WAKE_1HZ 0x00 +#define BITS_LPA_WAKE_2HZ 0x40 +#define BITS_LPA_WAKE_10HZ 0x80 +#define BITS_LPA_WAKE_40HZ 0xC0 +#define BIT_STBY_XA 0x20 +#define BIT_STBY_YA 0x10 +#define BIT_STBY_ZA 0x08 +#define BIT_STBY_XG 0x04 +#define BIT_STBY_YG 0x02 +#define BIT_STBY_ZG 0x01 + +#define ACCEL_MOT_THR_LSB (32) /* mg */ +#define ACCEL_MOT_DUR_LSB (1) +#define ACCEL_ZRMOT_THR_LSB_CONVERSION(mg) ((mg * 1000) / 255) +#define ACCEL_ZRMOT_DUR_LSB (64) + +/*----------------------------------------------------------------------------*/ +/*---- Alternative names to take care of conflicts with current mpu3050.h ----*/ +/*----------------------------------------------------------------------------*/ + +/*-- registers --*/ +#define MPUREG_DLPF_FS_SYNC MPUREG_CONFIG /* 0x1A */ + +#define MPUREG_PWR_MGM MPUREG_PWR_MGMT_1 /* 0x6B */ +#define MPUREG_FIFO_EN1 MPUREG_FIFO_EN /* 0x23 */ +#define MPUREG_INT_CFG MPUREG_INT_ENABLE /* 0x38 */ +#define MPUREG_X_OFFS_USRH MPUREG_XG_OFFS_USRH /* 0x13 */ +#define MPUREG_WHO_AM_I MPUREG_WHOAMI /* 0x75 */ +#define MPUREG_23_RSVD MPUREG_EXT_SLV_SENS_DATA_00 /* 0x49 */ + +/*-- bits --*/ +/* 'USER_CTRL' register */ +#define BIT_AUX_IF_EN BIT_I2C_MST_EN +#define BIT_AUX_RD_LENG BIT_I2C_MST_EN +#define BIT_IME_IF_RST BIT_I2C_MST_RST +#define BIT_GYRO_RST BIT_SIG_COND_RST +/* 'INT_ENABLE' register */ +#define BIT_RAW_RDY BIT_RAW_DATA_RDY_INT +#define BIT_MPU_RDY_EN BIT_PLL_RDY_EN +/* 'INT_STATUS' register */ +#define BIT_INT_STATUS_FIFO_OVERLOW BIT_FIFO_OVERFLOW_INT + +/*---- MPU6050 Silicon Revisions ----*/ +#define MPU_SILICON_REV_A2 1 /* MPU6050A2 Device */ +#define MPU_SILICON_REV_B1 2 /* MPU6050B1 Device */ + +/*---- MPU6050 notable product revisions ----*/ +#define MPU_PRODUCT_KEY_B1_E1_5 105 +#define MPU_PRODUCT_KEY_B2_F1 431 + +/*---- structure containing control variables used by MLDL ----*/ +/*---- MPU clock source settings ----*/ +/*---- MPU filter selections ----*/ +enum mpu_filter { + MPU_FILTER_256HZ_NOLPF2 = 0, + MPU_FILTER_188HZ, + MPU_FILTER_98HZ, + MPU_FILTER_42HZ, + MPU_FILTER_20HZ, + MPU_FILTER_10HZ, + MPU_FILTER_5HZ, + MPU_FILTER_2100HZ_NOLPF, + NUM_MPU_FILTER +}; + +enum mpu_fullscale { + MPU_FS_250DPS = 0, + MPU_FS_500DPS, + MPU_FS_1000DPS, + MPU_FS_2000DPS, + NUM_MPU_FS +}; + +enum mpu_clock_sel { + MPU_CLK_SEL_INTERNAL = 0, + MPU_CLK_SEL_PLLGYROX, + MPU_CLK_SEL_PLLGYROY, + MPU_CLK_SEL_PLLGYROZ, + MPU_CLK_SEL_PLLEXT32K, + MPU_CLK_SEL_PLLEXT19M, + MPU_CLK_SEL_RESERVED, + MPU_CLK_SEL_STOP, + NUM_CLK_SEL +}; + +enum mpu_ext_sync { + MPU_EXT_SYNC_NONE = 0, + MPU_EXT_SYNC_TEMP, + MPU_EXT_SYNC_GYROX, + MPU_EXT_SYNC_GYROY, + MPU_EXT_SYNC_GYROZ, + MPU_EXT_SYNC_ACCELX, + MPU_EXT_SYNC_ACCELY, + MPU_EXT_SYNC_ACCELZ, + NUM_MPU_EXT_SYNC +}; + +#define MPUREG_CONFIG_VALUE(ext_sync, lpf) \ + ((ext_sync << 3) | lpf) + +#define MPUREG_GYRO_CONFIG_VALUE(x_st, y_st, z_st, full_scale) \ + ((x_st ? 0x80 : 0) | \ + (y_st ? 0x70 : 0) | \ + (z_st ? 0x60 : 0) | \ + (full_scale << 3)) + +#endif /* __MPU6050_H_ */ diff --git a/drivers/misc/inv_mpu/mpuirq.c b/drivers/misc/inv_mpu/mpuirq.c new file mode 100644 index 00000000000..04f4be1a684 --- /dev/null +++ b/drivers/misc/inv_mpu/mpuirq.c @@ -0,0 +1,317 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mpuirq.h" +#include "mldl_cfg.h" + +#define MPUIRQ_NAME "mpuirq" + +/* function which gets accel data and sends it to MPU */ + +DECLARE_WAIT_QUEUE_HEAD(mpuirq_wait); + +struct mpuirq_dev_data { + struct i2c_client *mpu_client; + struct miscdevice *dev; + int irq; + int pid; + int accel_divider; + int data_ready; + int timeout; + struct delayed_work reactive_work; + struct mldl_cfg *mldl_dev_cfg; + struct wake_lock reactive_wake_lock; +}; + +static struct mpuirq_dev_data mpuirq_dev_data; +static struct mpuirq_data mpuirq_data; +static char *interface = MPUIRQ_NAME; +static int mpuirq_logcount = 51; + +static int mpuirq_open(struct inode *inode, struct file *file) +{ + dev_dbg(mpuirq_dev_data.dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + mpuirq_dev_data.pid = current->pid; + file->private_data = &mpuirq_dev_data; + return 0; +} + +/* close function - called when the "file" /dev/mpuirq is closed in userspace */ +static int mpuirq_release(struct inode *inode, struct file *file) +{ + dev_dbg(mpuirq_dev_data.dev->this_device, "mpuirq_release\n"); + return 0; +} + +/* read function called when from /dev/mpuirq is read */ +static ssize_t mpuirq_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int len, err; + struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data; + + if (!mpuirq_dev_data.data_ready && + mpuirq_dev_data.timeout && (!(file->f_flags & O_NONBLOCK))) { + wait_event_interruptible_timeout(mpuirq_wait, + mpuirq_dev_data.data_ready, + mpuirq_dev_data.timeout); + } + + if (mpuirq_dev_data.data_ready && NULL != buf + && count >= sizeof(mpuirq_data)) { + err = copy_to_user(buf, &mpuirq_data, sizeof(mpuirq_data)); + mpuirq_data.data_type = 0; + } else { + return 0; + } + if (err != 0) { + dev_err(p_mpuirq_dev_data->dev->this_device, + "Copy to user returned %d\n", err); + return -EFAULT; + } + mpuirq_dev_data.data_ready = 0; + len = sizeof(mpuirq_data); + return len; +} + +unsigned int mpuirq_poll(struct file *file, struct poll_table_struct *poll) +{ + int mask = 0; + + poll_wait(file, &mpuirq_wait, poll); + if (mpuirq_dev_data.data_ready) + mask |= POLLIN | POLLRDNORM; + return mask; +} + +/* ioctl - I/O control */ +static long mpuirq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int data; + + switch (cmd) { + case MPUIRQ_SET_TIMEOUT: + mpuirq_dev_data.timeout = arg; + break; + + case MPUIRQ_GET_INTERRUPT_CNT: + data = mpuirq_data.interruptcount - 1; + if (mpuirq_data.interruptcount > 1) + mpuirq_data.interruptcount = 1; + + if (copy_to_user((int *)arg, &data, sizeof(int))) + return -EFAULT; + break; + case MPUIRQ_GET_IRQ_TIME: + if (copy_to_user((int *)arg, &mpuirq_data.irqtime, + sizeof(mpuirq_data.irqtime))) + return -EFAULT; + mpuirq_data.irqtime = 0; + break; + case MPUIRQ_SET_FREQUENCY_DIVIDER: + mpuirq_dev_data.accel_divider = arg; + break; + default: + retval = -EINVAL; + } + return retval; +} + +static irqreturn_t mpuirq_handler(int irq, void *dev_id) +{ + static int mycount; + struct timeval irqtime; + struct mldl_cfg *mldl_cfg = dev_id; + mycount++; + + mpuirq_data.interruptcount++; + + if (mpuirq_logcount++ > 51) { + pr_info("mpuirq_handler: every 50'th\n"); + mpuirq_logcount = 0; + } + /* wake up (unblock) for reading data from userspace */ + /* and ignore first interrupt generated in module init */ + mpuirq_dev_data.data_ready = 1; + + do_gettimeofday(&irqtime); + mpuirq_data.irqtime = (((long long)irqtime.tv_sec) << 32); + mpuirq_data.irqtime += irqtime.tv_usec; + mpuirq_data.data_type = MPUIRQ_DATA_TYPE_MPU_IRQ; + mpuirq_data.data = 0; + + if (!mldl_cfg->inv_mpu_state->use_accel_reactive) + wake_up_interruptible(&mpuirq_wait); + if (mldl_cfg->inv_mpu_state->accel_reactive) + schedule_delayed_work(&mpuirq_dev_data.reactive_work, + msecs_to_jiffies(20)); + + return IRQ_HANDLED; + +} + +static void reactive_work_func(struct work_struct *work) +{ + struct mldl_cfg *mldl_cfg = mpuirq_dev_data.mldl_dev_cfg; + + int err = 0; + unsigned char reg_data = 0; + + struct i2c_adapter *slave_adapter; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + slave_adapter = + i2c_get_adapter(pdata_slave[EXT_SLAVE_TYPE_ACCEL]->adapt_num); + + err = inv_serial_read(slave_adapter, 0x68, + MPUREG_INT_STATUS, 1, ®_data); + if (err) + pr_err("%s i2c err\n", __func__); + if ((reg_data & BIT_MOT_EN) || + ((reg_data & BIT_RAW_RDY_EN) && + mldl_cfg->inv_mpu_state->reactive_factory)) { + if (mldl_cfg->inv_mpu_state->accel_reactive) + disable_irq_wake(mpuirq_dev_data.irq); + + pr_info("Reactive Alert\n"); + mldl_cfg->inv_mpu_state->accel_reactive = false; + mldl_cfg->inv_mpu_state->reactive_factory = false; + wake_lock_timeout(&mpuirq_dev_data.reactive_wake_lock, + msecs_to_jiffies(2000)); + err = inv_serial_read(slave_adapter, 0x68, + MPUREG_INT_ENABLE, sizeof(reg_data), ®_data); + if (err) + pr_err("%s: read INT reg failed\n", __func__); + reg_data &= ~BIT_MOT_EN; + err = inv_serial_single_write(slave_adapter, 0x68, + MPUREG_INT_ENABLE, + reg_data); + if (err) + pr_err("%s: write INT reg failed\n", __func__); + } +} + +/* define which file operations are supported */ +const struct file_operations mpuirq_fops = { + .owner = THIS_MODULE, + .read = mpuirq_read, + .poll = mpuirq_poll, + + .unlocked_ioctl = mpuirq_ioctl, + .open = mpuirq_open, + .release = mpuirq_release, +}; + +static struct miscdevice mpuirq_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = MPUIRQ_NAME, + .fops = &mpuirq_fops, +}; + +int mpuirq_init(struct i2c_client *mpu_client, struct mldl_cfg *mldl_cfg) +{ + + int res; + + mpuirq_dev_data.mpu_client = mpu_client; + mpuirq_dev_data.mldl_dev_cfg = mldl_cfg; + + dev_info(&mpu_client->adapter->dev, + "Module Param interface = %s\n", interface); + + mpuirq_dev_data.irq = mpu_client->irq; + mpuirq_dev_data.pid = 0; + mpuirq_dev_data.accel_divider = -1; + mpuirq_dev_data.data_ready = 0; + mpuirq_dev_data.timeout = 0; + mpuirq_dev_data.dev = &mpuirq_device; + + wake_lock_init(&mpuirq_dev_data.reactive_wake_lock, WAKE_LOCK_SUSPEND, + "reactive_wake_lock"); + + if (mpuirq_dev_data.irq) { + unsigned long flags; + + INIT_DELAYED_WORK(&mpuirq_dev_data.reactive_work, + reactive_work_func); + if (BIT_ACTL_LOW == ((mldl_cfg->pdata->int_config) & BIT_ACTL)) + flags = IRQF_TRIGGER_FALLING; + else + flags = IRQF_TRIGGER_RISING; + + flags |= IRQF_SHARED; + res = request_threaded_irq(mpuirq_dev_data.irq, NULL, + mpuirq_handler, flags, interface, mldl_cfg); + if (res) { + dev_err(&mpu_client->adapter->dev, + "myirqtest: cannot register IRQ %d\n", + mpuirq_dev_data.irq); + } else { + res = misc_register(&mpuirq_device); + if (res < 0) { + dev_err(&mpu_client->adapter->dev, + "misc_register returned %d\n", res); + free_irq(mpuirq_dev_data.irq, + &mpuirq_dev_data.irq); + } + } + } else { + res = 0; + } + + return res; +} + +void mpuirq_exit(void) +{ + if (mpuirq_dev_data.irq > 0) + free_irq(mpuirq_dev_data.irq, &mpuirq_dev_data.irq); + wake_lock_destroy(&mpuirq_dev_data.reactive_wake_lock); + + dev_info(mpuirq_device.this_device, "Unregistering %s\n", MPUIRQ_NAME); + misc_deregister(&mpuirq_device); + + return; +} + +module_param(interface, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(interface, "The Interface name"); diff --git a/drivers/misc/inv_mpu/mpuirq.h b/drivers/misc/inv_mpu/mpuirq.h new file mode 100644 index 00000000000..33480711f79 --- /dev/null +++ b/drivers/misc/inv_mpu/mpuirq.h @@ -0,0 +1,36 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +#ifndef __MPUIRQ__ +#define __MPUIRQ__ + +#include +#include +#include +#include "mldl_cfg.h" + +#define MPUIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x40, unsigned long) +#define MPUIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x41, unsigned long) +#define MPUIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x42, struct timeval) +#define MPUIRQ_SET_FREQUENCY_DIVIDER _IOW(MPU_IOCTL, 0x43, unsigned long) + +void mpuirq_exit(void); +int mpuirq_init(struct i2c_client *mpu_client, struct mldl_cfg *mldl_cfg); + +#endif diff --git a/drivers/misc/inv_mpu/slaveirq.c b/drivers/misc/inv_mpu/slaveirq.c new file mode 100644 index 00000000000..fdabcdd7a8d --- /dev/null +++ b/drivers/misc/inv_mpu/slaveirq.c @@ -0,0 +1,266 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "slaveirq.h" +#include "mldl_cfg.h" + +/* function which gets slave data and sends it to SLAVE */ + +struct slaveirq_dev_data { + struct miscdevice dev; + struct i2c_client *slave_client; + struct mpuirq_data data; + wait_queue_head_t slaveirq_wait; + int irq; + int pid; + int data_ready; + int timeout; +}; + +/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28 + * drivers: misc: pass miscdevice pointer via file private data + */ +static int slaveirq_open(struct inode *inode, struct file *file) +{ + /* Device node is availabe in the file->private_data, this is + * exactly what we want so we leave it there */ + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + + dev_dbg(data->dev.this_device, + "%s current->pid %d\n", __func__, current->pid); + data->pid = current->pid; + return 0; +} + +static int slaveirq_release(struct inode *inode, struct file *file) +{ + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + dev_dbg(data->dev.this_device, "slaveirq_release\n"); + return 0; +} + +/* read function called when from /dev/slaveirq is read */ +static ssize_t slaveirq_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int len, err; + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + + if (!data->data_ready && data->timeout && + !(file->f_flags & O_NONBLOCK)) { + wait_event_interruptible_timeout(data->slaveirq_wait, + data->data_ready, + data->timeout); + } + + if (data->data_ready && NULL != buf && count >= sizeof(data->data)) { + err = copy_to_user(buf, &data->data, sizeof(data->data)); + data->data.data_type = 0; + } else { + return 0; + } + if (err != 0) { + dev_err(data->dev.this_device, + "Copy to user returned %d\n", err); + return -EFAULT; + } + data->data_ready = 0; + len = sizeof(data->data); + return len; +} + +static unsigned int slaveirq_poll(struct file *file, + struct poll_table_struct *poll) +{ + int mask = 0; + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + + poll_wait(file, &data->slaveirq_wait, poll); + if (data->data_ready) + mask |= POLLIN | POLLRDNORM; + return mask; +} + +/* ioctl - I/O control */ +static long slaveirq_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int tmp; + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + + switch (cmd) { + case SLAVEIRQ_SET_TIMEOUT: + data->timeout = arg; + break; + + case SLAVEIRQ_GET_INTERRUPT_CNT: + tmp = data->data.interruptcount - 1; + if (data->data.interruptcount > 1) + data->data.interruptcount = 1; + + if (copy_to_user((int *)arg, &tmp, sizeof(int))) + return -EFAULT; + break; + case SLAVEIRQ_GET_IRQ_TIME: + if (copy_to_user((int *)arg, &data->data.irqtime, + sizeof(data->data.irqtime))) + return -EFAULT; + data->data.irqtime = 0; + break; + default: + retval = -EINVAL; + } + return retval; +} + +static irqreturn_t slaveirq_handler(int irq, void *dev_id) +{ + struct slaveirq_dev_data *data = (struct slaveirq_dev_data *)dev_id; + static int mycount; + struct timeval irqtime; + mycount++; + + data->data.interruptcount++; + + /* wake up (unblock) for reading data from userspace */ + data->data_ready = 1; + + do_gettimeofday(&irqtime); + data->data.irqtime = (((long long)irqtime.tv_sec) << 32); + data->data.irqtime += irqtime.tv_usec; + data->data.data_type |= 1; + + wake_up_interruptible(&data->slaveirq_wait); + + return IRQ_HANDLED; + +} + +/* define which file operations are supported */ +static const struct file_operations slaveirq_fops = { + .owner = THIS_MODULE, + .read = slaveirq_read, + .poll = slaveirq_poll, + +#if HAVE_COMPAT_IOCTL + .compat_ioctl = slaveirq_ioctl, +#endif +#if HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = slaveirq_ioctl, +#endif + .open = slaveirq_open, + .release = slaveirq_release, +}; + +int slaveirq_init(struct i2c_adapter *slave_adapter, + struct ext_slave_platform_data *pdata, char *name) +{ + + int res; + struct slaveirq_dev_data *data; + + if (!pdata->irq) + return -EINVAL; + + pdata->irq_data = kzalloc(sizeof(*data), GFP_KERNEL); + data = (struct slaveirq_dev_data *)pdata->irq_data; + if (!data) + return -ENOMEM; + + data->dev.minor = MISC_DYNAMIC_MINOR; + data->dev.name = name; + data->dev.fops = &slaveirq_fops; + data->irq = pdata->irq; + data->pid = 0; + data->data_ready = 0; + data->timeout = 0; + + init_waitqueue_head(&data->slaveirq_wait); + + res = request_irq(data->irq, slaveirq_handler, + IRQF_TRIGGER_RISING | IRQF_SHARED, + data->dev.name, data); + + if (res) { + dev_err(&slave_adapter->dev, + "myirqtest: cannot register IRQ %d\n", data->irq); + goto out_request_irq; + } + + res = misc_register(&data->dev); + if (res < 0) { + dev_err(&slave_adapter->dev, + "misc_register returned %d\n", res); + goto out_misc_register; + } + + return res; + +out_misc_register: + free_irq(data->irq, data); +out_request_irq: + kfree(pdata->irq_data); + pdata->irq_data = NULL; + + return res; +} + +void slaveirq_exit(struct ext_slave_platform_data *pdata) +{ + struct slaveirq_dev_data *data = pdata->irq_data; + + if (!pdata->irq_data || data->irq <= 0) + return; + + dev_info(data->dev.this_device, "Unregistering %s\n", data->dev.name); + + free_irq(data->irq, data); + misc_deregister(&data->dev); + kfree(pdata->irq_data); + pdata->irq_data = NULL; +} diff --git a/drivers/misc/inv_mpu/slaveirq.h b/drivers/misc/inv_mpu/slaveirq.h new file mode 100644 index 00000000000..6926634ff94 --- /dev/null +++ b/drivers/misc/inv_mpu/slaveirq.h @@ -0,0 +1,36 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +#ifndef __SLAVEIRQ__ +#define __SLAVEIRQ__ + +#include + +#include +#include "mpuirq.h" + +#define SLAVEIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x50, unsigned long) +#define SLAVEIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x51, unsigned long) +#define SLAVEIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x52, unsigned long) + +void slaveirq_exit(struct ext_slave_platform_data *pdata); +int slaveirq_init(struct i2c_adapter *slave_adapter, + struct ext_slave_platform_data *pdata, char *name); + +#endif diff --git a/drivers/misc/inv_mpu/timerirq.c b/drivers/misc/inv_mpu/timerirq.c new file mode 100644 index 00000000000..90fd8c2ec39 --- /dev/null +++ b/drivers/misc/inv_mpu/timerirq.c @@ -0,0 +1,298 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mltypes.h" +#include "timerirq.h" + +/* function which gets timer data and sends it to TIMER */ +struct timerirq_data { + int pid; + int data_ready; + int run; + int timeout; + unsigned long period; + struct mpuirq_data data; + struct completion timer_done; + wait_queue_head_t timerirq_wait; + struct timer_list timer; + struct miscdevice *dev; +}; + +static struct miscdevice *timerirq_dev_data; + +static void timerirq_handler(unsigned long arg) +{ + struct timerirq_data *data = (struct timerirq_data *)arg; + struct timeval irqtime; + + data->data.interruptcount++; + + data->data_ready = 1; + + do_gettimeofday(&irqtime); + data->data.irqtime = (((long long)irqtime.tv_sec) << 32); + data->data.irqtime += irqtime.tv_usec; + data->data.data_type |= 1; + + dev_dbg(data->dev->this_device, + "%s, %lld, %ld\n", __func__, data->data.irqtime, + (unsigned long)data); + + wake_up_interruptible(&data->timerirq_wait); + + if (data->run) + mod_timer(&data->timer, + jiffies + msecs_to_jiffies(data->period)); + else + complete(&data->timer_done); +} + +static int start_timerirq(struct timerirq_data *data) +{ + dev_dbg(data->dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + + /* Timer already running... success */ + if (data->run) + return 0; + + /* Don't allow a period of 0 since this would fire constantly */ + if (!data->period) + return -EINVAL; + + data->run = true; + data->data_ready = false; + + init_completion(&data->timer_done); + setup_timer(&data->timer, timerirq_handler, (unsigned long)data); + + return mod_timer(&data->timer, + jiffies + msecs_to_jiffies(data->period)); +} + +static int stop_timerirq(struct timerirq_data *data) +{ + dev_dbg(data->dev->this_device, + "%s current->pid %lx\n", __func__, (unsigned long)data); + + if (data->run) { + data->run = false; + mod_timer(&data->timer, jiffies + 1); + wait_for_completion(&data->timer_done); + } + return 0; +} + +/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28 + * drivers: misc: pass miscdevice pointer via file private data + */ +static int timerirq_open(struct inode *inode, struct file *file) +{ + /* Device node is availabe in the file->private_data, this is + * exactly what we want so we leave it there */ + struct miscdevice *dev_data = file->private_data; + struct timerirq_data *data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev_data; + file->private_data = data; + data->pid = current->pid; + init_waitqueue_head(&data->timerirq_wait); + + dev_dbg(data->dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + return 0; +} + +static int timerirq_release(struct inode *inode, struct file *file) +{ + struct timerirq_data *data = file->private_data; + dev_dbg(data->dev->this_device, "timerirq_release\n"); + if (data->run) + stop_timerirq(data); + kfree(data); + return 0; +} + +/* read function called when from /dev/timerirq is read */ +static ssize_t timerirq_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int len, err; + struct timerirq_data *data = file->private_data; + + if (!data->data_ready && data->timeout && + !(file->f_flags & O_NONBLOCK)) { + wait_event_interruptible_timeout(data->timerirq_wait, + data->data_ready, + data->timeout); + } + + if (data->data_ready && NULL != buf && count >= sizeof(data->data)) { + err = copy_to_user(buf, &data->data, sizeof(data->data)); + data->data.data_type = 0; + } else { + return 0; + } + if (err != 0) { + dev_err(data->dev->this_device, + "Copy to user returned %d\n", err); + return -EFAULT; + } + data->data_ready = 0; + len = sizeof(data->data); + return len; +} + +static unsigned int timerirq_poll(struct file *file, + struct poll_table_struct *poll) +{ + int mask = 0; + struct timerirq_data *data = file->private_data; + + poll_wait(file, &data->timerirq_wait, poll); + if (data->data_ready) + mask |= POLLIN | POLLRDNORM; + return mask; +} + +/* ioctl - I/O control */ +static long timerirq_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int tmp; + struct timerirq_data *data = file->private_data; + + dev_dbg(data->dev->this_device, + "%s current->pid %d, %d, %ld\n", + __func__, current->pid, cmd, arg); + + if (!data) + return -EFAULT; + + switch (cmd) { + case TIMERIRQ_SET_TIMEOUT: + data->timeout = arg; + break; + case TIMERIRQ_GET_INTERRUPT_CNT: + tmp = data->data.interruptcount - 1; + if (data->data.interruptcount > 1) + data->data.interruptcount = 1; + + if (copy_to_user((int *)arg, &tmp, sizeof(int))) + return -EFAULT; + break; + case TIMERIRQ_START: + data->period = arg; + pr_info("TIMERIRQ_START : period=%lu", data->period); + retval = start_timerirq(data); + break; + case TIMERIRQ_STOP: + retval = stop_timerirq(data); + break; + default: + retval = -EINVAL; + } + return retval; +} + +/* define which file operations are supported */ +static const struct file_operations timerirq_fops = { + .owner = THIS_MODULE, + .read = timerirq_read, + .poll = timerirq_poll, + +#if HAVE_COMPAT_IOCTL + .compat_ioctl = timerirq_ioctl, +#endif +#if HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = timerirq_ioctl, +#endif + .open = timerirq_open, + .release = timerirq_release, +}; + +static int __init timerirq_init(void) +{ + + int res; + static struct miscdevice *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + timerirq_dev_data = data; + data->minor = MISC_DYNAMIC_MINOR; + data->name = "timerirq"; + data->fops = &timerirq_fops; + + res = misc_register(data); + if (res < 0) { + dev_err(data->this_device, "misc_register returned %d\n", res); + kfree(data); + return res; + } + + return res; +} + +module_init(timerirq_init); + +static void __exit timerirq_exit(void) +{ + struct miscdevice *data = timerirq_dev_data; + + dev_info(data->this_device, "Unregistering %s\n", data->name); + + misc_deregister(data); + kfree(data); + + timerirq_dev_data = NULL; +} + +module_exit(timerirq_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Timer IRQ device driver."); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("timerirq"); diff --git a/drivers/misc/inv_mpu/timerirq.h b/drivers/misc/inv_mpu/timerirq.h new file mode 100644 index 00000000000..f69f07a45a3 --- /dev/null +++ b/drivers/misc/inv_mpu/timerirq.h @@ -0,0 +1,30 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +#ifndef __TIMERIRQ__ +#define __TIMERIRQ__ + +#include + +#define TIMERIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x60, unsigned long) +#define TIMERIRQ_GET_INTERRUPT_CNT _IOW(MPU_IOCTL, 0x61, unsigned long) +#define TIMERIRQ_START _IOW(MPU_IOCTL, 0x62, unsigned long) +#define TIMERIRQ_STOP _IO(MPU_IOCTL, 0x63) + +#endif diff --git a/drivers/misc/pn544.c b/drivers/misc/pn544.c new file mode 100644 index 00000000000..dba60f762ba --- /dev/null +++ b/drivers/misc/pn544.c @@ -0,0 +1,458 @@ +/* + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_BUFFER_SIZE 512 + +#define NFC_DEBUG 0 +#define MAX_TRY_I2C_READ 10 +#define I2C_ADDR_READ_L 0x51 +#define I2C_ADDR_READ_H 0x57 + +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn544_device; + void (*conf_gpio) (void); + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int irq_gpio; + atomic_t irq_enabled; + atomic_t read_flag; + bool cancel_read; +}; + +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + + if (!gpio_get_value(pn544_dev->irq_gpio)) { +#if NFC_DEBUG + pr_err("%s, irq_gpio = %d\n", __func__, + gpio_get_value(pn544_dev->irq_gpio)); +#endif + return IRQ_HANDLED; + } + + /* Wake up waiting readers */ + atomic_set(&pn544_dev->read_flag, 1); + wake_up(&pn544_dev->read_wq); + + +#if NFC_DEBUG + pr_info("pn544 : call\n"); +#endif + + 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] = {0, }; + int ret = 0; + int readingWatchdog = 0; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes. irq=%s\n", __func__, count, + gpio_get_value(pn544_dev->irq_gpio) ? "1" : "0"); + +#if NFC_DEBUG + pr_info("pn544 : + r\n"); +#endif + + mutex_lock(&pn544_dev->read_mutex); + +wait_irq: + + if (!gpio_get_value(pn544_dev->irq_gpio)) { + atomic_set(&pn544_dev->read_flag, 0); + if (filp->f_flags & O_NONBLOCK) { + pr_info("%s : O_NONBLOCK\n", __func__); + ret = -EAGAIN; + goto fail; + } + +#if NFC_DEBUG + pr_info("pn544: wait_event_interruptible : in\n"); +#endif + + ret = wait_event_interruptible(pn544_dev->read_wq, + atomic_read(&pn544_dev->read_flag)); + +#if NFC_DEBUG + pr_info("pn544 : h\n"); +#endif + + if (pn544_dev->cancel_read) { + pn544_dev->cancel_read = false; + ret = -1; + goto fail; + } + + if (ret) + goto fail; + + } + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + + /* If bad frame(from 0x51 to 0x57) is received from pn65n, + * we need to read again after waiting that IRQ is down. + * if data is not ready, pn65n will send from 0x51 to 0x57. */ + if ((I2C_ADDR_READ_L <= tmp[0] && tmp[0] <= I2C_ADDR_READ_H) + && readingWatchdog < MAX_TRY_I2C_READ) { + pr_warn("%s: data is not ready yet.data = 0x%x, cnt=%d\n", + __func__, tmp[0], readingWatchdog); + usleep_range(2000, 2000); /* sleep 2ms to wait for IRQ */ + readingWatchdog++; + goto wait_irq; + } +#if NFC_DEBUG + pr_info("pn544: i2c_master_recv\n"); +#endif + mutex_unlock(&pn544_dev->read_mutex); + 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_err("%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] = {0, }; + int ret = 0, retry = 2; + + pn544_dev = filp->private_data; + +#if NFC_DEBUG + pr_info("pn544 : + w\n"); +#endif + + 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 */ + do { + retry--; + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret == count) + break; + usleep_range(6000, 10000); /* Retry, chip was in standby */ +#if NFC_DEBUG + pr_debug("%s : retry = %d\n", __func__, retry); +#endif + } while (retry); + +#if NFC_DEBUG + pr_info("pn544 : - w\n"); +#endif + + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + + return ret; +} + +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; +} + +static long pn544_dev_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct pn544_dev *pn544_dev = filp->private_data; + + switch (cmd) { + case PN544_SET_PWR: + if (arg == 2) { + /* power on with firmware download (requires hw reset) + */ + gpio_set_value_cansleep(pn544_dev->ven_gpio, 1); + gpio_set_value(pn544_dev->firm_gpio, 1); + usleep_range(10000, 10050); + gpio_set_value_cansleep(pn544_dev->ven_gpio, 0); + usleep_range(10000, 10050); + gpio_set_value_cansleep(pn544_dev->ven_gpio, 1); + usleep_range(10000, 10050); + if (atomic_read(&pn544_dev->irq_enabled) == 0) { + atomic_set(&pn544_dev->irq_enabled, 1); + enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); + } + pr_info("%s power on with firmware, irq=%d\n", __func__, + atomic_read(&pn544_dev->irq_enabled)); + } else if (arg == 1) { + /* power on */ + if (pn544_dev->conf_gpio) + pn544_dev->conf_gpio(); + gpio_set_value(pn544_dev->firm_gpio, 0); + gpio_set_value_cansleep(pn544_dev->ven_gpio, 1); + usleep_range(10000, 10050); + if (atomic_read(&pn544_dev->irq_enabled) == 0) { + atomic_set(&pn544_dev->irq_enabled, 1); + enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); + } + pr_info("%s power on, irq=%d\n", __func__, + atomic_read(&pn544_dev->irq_enabled)); + } else if (arg == 0) { + /* power off */ + gpio_set_value(pn544_dev->firm_gpio, 0); + gpio_set_value_cansleep(pn544_dev->ven_gpio, 0); + usleep_range(10000, 10050); + if (atomic_read(&pn544_dev->irq_enabled) == 0) { + atomic_set(&pn544_dev->irq_enabled, 1); + enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); + } + pr_info("%s power off, irq=%d\n", __func__, + atomic_read(&pn544_dev->irq_enabled)); + } else if (arg == 3) { + pr_info("%s Read Cancel\n", __func__); + pn544_dev->cancel_read = true; + atomic_set(&pn544_dev->read_flag, 1); + wake_up(&pn544_dev->read_wq); + } else { + pr_err("%s bad 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 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, +}; + +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 (client->dev.platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + platform_data = client->dev.platform_data; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } + + 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->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + + 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; + } + + pr_info("%s : IRQ num %d\n", __func__, client->irq); + + 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->conf_gpio = platform_data->conf_gpio; + pn544_dev->client = client; + + /* init mutex and queues */ + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + pn544_dev->pn544_device.name = "pn544"; + 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); + gpio_direction_input(pn544_dev->irq_gpio); + gpio_direction_output(pn544_dev->ven_gpio, 0); + gpio_direction_output(pn544_dev->firm_gpio, 0); + i2c_set_clientdata(client, pn544_dev); + ret = request_irq(client->irq, pn544_dev_irq_handler, + IRQF_TRIGGER_RISING, "pn544", pn544_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + disable_irq_nosync(pn544_dev->client->irq); + atomic_set(&pn544_dev->irq_enabled, 0); + + return 0; + +err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); +err_misc_register: + mutex_destroy(&pn544_dev->read_mutex); + kfree(pn544_dev); +err_exit: + gpio_free(platform_data->firm_gpio); +err_firm: + gpio_free(platform_data->ven_gpio); +err_ven: + gpio_free(platform_data->irq_gpio); + pr_err("[PN544] pn544_probe fail!\n"); + 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); + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev); + + return 0; +} + +static const struct i2c_device_id pn544_id[] = { + {"pn544", 0}, + {} +}; + +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .driver = { + .owner = THIS_MODULE, + .name = "pn544", + }, +}; + +/* + * 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/drivers/misc/sec_jack.c b/drivers/misc/sec_jack.c new file mode 100644 index 00000000000..e4b85108fb7 --- /dev/null +++ b/drivers/misc/sec_jack.c @@ -0,0 +1,670 @@ +/* + * headset/ear-jack device detection driver. + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "sec_jack:" +#define MAX_ZONE_LIMIT 10 +#if defined(CONFIG_MACH_AEGIS2) +#define SEND_KEY_CHECK_TIME_MS 65 +#else +#define SEND_KEY_CHECK_TIME_MS 60 +#endif +#define DET_CHECK_TIME_MS 100 +#define WAKE_LOCK_TIME (HZ * 5) +#define WAKE_LOCK_TIME_IN_SENDKEY (HZ * 1) +#define SUPPORT_PBA + +static bool recheck_jack; +#ifdef CONFIG_MACH_JAGUAR +static bool sendkey_irq_progress; +#endif + +struct sec_jack_info { + struct sec_jack_platform_data *pdata; + struct input_dev *input; + struct wake_lock det_wake_lock; + struct sec_jack_zone *zone; + int keypress_code; + bool send_key_pressed; + bool send_key_irq_enabled; + unsigned int cur_jack_type; + struct work_struct det_work; + struct work_struct sendkey_work; + struct delayed_work powerup_work; + bool is_ready; +}; + +static void set_send_key_state(struct sec_jack_info *hi, int state) +{ + struct sec_jack_platform_data *pdata = hi->pdata; + struct sec_jack_buttons_zone *btn_zones = pdata->buttons_zones; + int adc; + int i; + + adc = pdata->get_adc_value(); + pr_info(MODULE_NAME "%s adc=%d, state=%d\n", __func__, adc, state); + + if (state != 0) { + for (i = 0; i < pdata->num_buttons_zones; i++) + if (adc >= btn_zones[i].adc_low && + adc <= btn_zones[i].adc_high) { + hi->keypress_code = btn_zones[i].code; + input_report_key(hi->input, + btn_zones[i].code, state); + input_sync(hi->input); + switch_set_state(&switch_sendend, state); + hi->send_key_pressed = state; + pr_info(MODULE_NAME "%s: keycode=%d, is pressed\n", + __func__, btn_zones[i].code); + return; + } + } else { + input_report_key(hi->input, hi->keypress_code, state); + input_sync(hi->input); + switch_set_state(&switch_sendend, state); + hi->send_key_pressed = state; + } +} + +static void sec_jack_set_type(struct sec_jack_info *hi, int jack_type) +{ + struct sec_jack_platform_data *pdata = hi->pdata; + + /* this can happen during slow inserts where we think we identified + * the type but then we get another interrupt and do it again + */ + + if (jack_type == hi->cur_jack_type) { + pr_debug(MODULE_NAME "%s return, same type reason\n", __func__); + return; + } + + if (jack_type == SEC_HEADSET_4POLE) { + /* for a 4 pole headset, enable irq + for detecting send/end key presses */ + if (!hi->send_key_irq_enabled) { + pr_info(MODULE_NAME "%s send_int enabled\n", __func__); + enable_irq(pdata->send_int); + enable_irq_wake(pdata->send_int); + hi->send_key_irq_enabled = 1; + } + } else { + /* for all other jacks, disable send/end irq */ + if (hi->send_key_irq_enabled) { + pr_info(MODULE_NAME "%s send_int disabled\n", __func__); + disable_irq(pdata->send_int); + disable_irq_wake(pdata->send_int); + hi->send_key_irq_enabled = 0; + } + if (hi->send_key_pressed) { + set_send_key_state(hi, 0); +#ifdef CONFIG_MACH_JAGUAR + sendkey_irq_progress = false; +#endif + pr_info(MODULE_NAME "%s : BTN set released by jack switch to %d\n", + __func__, jack_type); + } + } + + pr_info(MODULE_NAME "%s : jack_type = %d\n", __func__, jack_type); + /* prevent suspend to allow user space to respond to switch */ + wake_lock_timeout(&hi->det_wake_lock, WAKE_LOCK_TIME); + + hi->cur_jack_type = jack_type; + switch_set_state(&switch_jack_detection, jack_type); + + /* micbias is left enabled for 4pole and disabled otherwise */ + pdata->set_micbias_state(hi->send_key_irq_enabled); + +} + +static void handle_jack_not_inserted(struct sec_jack_info *hi) +{ + sec_jack_set_type(hi, SEC_JACK_NO_DEVICE); + hi->pdata->set_micbias_state(false); +} + +static void determine_jack_type(struct sec_jack_info *hi) +{ + struct sec_jack_zone *zones = hi->pdata->zones; + int size = hi->pdata->num_zones; + int count[MAX_ZONE_LIMIT] = {0}; + int adc; + int i; + + while (hi->pdata->get_det_jack_state()) { + adc = hi->pdata->get_adc_value(); + pr_info(MODULE_NAME "determine_jack_type adc = %d\n", adc); + + /* determine the type of headset based on the + * adc value. An adc value can fall in various + * ranges or zones. Within some ranges, the type + * can be returned immediately. Within others, the + * value is considered unstable and we need to sample + * a few more types (up to the limit determined by + * the range) before we return the type for that range. + */ + for (i = 0; i < size; i++) { + if (adc <= zones[i].adc_high) { + if (++count[i] > zones[i].check_count) { + pr_debug(MODULE_NAME "determine_jack_type %d, %d, %d\n", + zones[i].adc_high, count[i], + zones[i].check_count); +#if defined(CONFIG_SAMSUNG_JACK_GNDLDET) + /* G plus L Detection */ + if (!hi->pdata->get_gnd_jack_state()) { +#else +#ifndef CONFIG_MACH_JAGUAR + if (recheck_jack == true && i == 3) { +#else + if (recheck_jack == true && i == 5) { +#endif +#endif + pr_debug(MODULE_NAME "something wrong connectoin!\n"); + handle_jack_not_inserted(hi); + recheck_jack = false; + return; + } + + sec_jack_set_type(hi, + zones[i].jack_type); + /* mic_bias remains enabled + * in race condition. + */ + if (hi->cur_jack_type != + SEC_HEADSET_4POLE) { + hi->pdata->set_micbias_state(false); + pr_info(MODULE_NAME "forced mic_bias disable\n"); + } + recheck_jack = false; + return; + } + msleep(zones[i].delay_ms); + break; + } + } + } + /* jack removed before detection complete */ + recheck_jack = false; + handle_jack_not_inserted(hi); +} + +#ifdef SUPPORT_PBA +static ssize_t key_state_onoff_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sec_jack_info *hi = dev_get_drvdata(dev); +#ifdef CONFIG_MACH_JAGUAR + struct sec_jack_platform_data *pdata = hi->pdata; +#endif + int value = 0; +#ifdef CONFIG_MACH_JAGUAR + int send_key_state = 0; +#endif +#ifndef CONFIG_MACH_JAGUAR + if (hi->send_key_pressed != true) + value = 0; + else + value = 1; +#else + send_key_state = pdata->get_send_key_state(); + pr_info(MODULE_NAME "%s : cur_jack_type=%d, send_key_state=%d.\n", + __func__, hi->cur_jack_type, send_key_state); + if ((hi->cur_jack_type != SEC_HEADSET_4POLE) || + (send_key_state != true)) + value = 0; + else + value = 1; +#endif + return sprintf(buf, "%d\n", value); +} + +static DEVICE_ATTR(key_state, 0664 , key_state_onoff_show, + NULL); + +static ssize_t earjack_state_onoff_show(struct device *dev, + struct device_attribute *attr, char *buf) + +{ + struct sec_jack_info *hi = dev_get_drvdata(dev); + int value = 0; + + if (hi->cur_jack_type == SEC_HEADSET_4POLE) + value = 1; + else + value = 0; + return sprintf(buf, "%d\n", value); +} + +static DEVICE_ATTR(state, 0664 , earjack_state_onoff_show, + NULL); + +static ssize_t select_jack_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + pr_info("%s : operate nothing\n", __func__); + return 0; +} + +static ssize_t select_jack_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct sec_jack_info *hi = dev_get_drvdata(dev); + struct sec_jack_platform_data *pdata = hi->pdata; + int value = 0; + + + sscanf(buf, "%d", &value); + pr_err("%s: User selection : 0X%x", __func__, value); + if (value == SEC_HEADSET_4POLE) { + pdata->set_micbias_state(true); + msleep(100); + } + + sec_jack_set_type(hi, value); + + return size; +} + +static DEVICE_ATTR(select_jack, 0664, select_jack_show, + select_jack_store); + +static ssize_t reselect_jack_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + pr_info("%s : operate nothing\n", __func__); + return 0; +} + +static ssize_t reselect_jack_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct sec_jack_info *hi = dev_get_drvdata(dev); +#if 0 + struct sec_jack_platform_data *pdata = hi->pdata; +#endif + int value = 0; + + + sscanf(buf, "%d", &value); + pr_err("%s: User selection : 0X%x", __func__, value); + + if (value == 1) { + recheck_jack = true; + determine_jack_type(hi); + } + + return size; +} + +static DEVICE_ATTR(reselect_jack, 0664, reselect_jack_show, + reselect_jack_store); +#endif + +static irqreturn_t sec_jack_send_key_irq_handler(int irq, void *handle) +{ + struct sec_jack_info *hi = (struct sec_jack_info *)handle; + + pr_info(MODULE_NAME "%s : irq is %d.\n", __func__, irq); + + if (hi->is_ready) + schedule_work(&hi->sendkey_work); + + return IRQ_HANDLED; +} + +static void sec_jack_send_key_work_func(struct work_struct *work) +{ + struct sec_jack_info *hi = + container_of(work, struct sec_jack_info, sendkey_work); + struct sec_jack_platform_data *pdata = hi->pdata; + int time_left_ms = SEND_KEY_CHECK_TIME_MS; + int send_key_state = 0; + + wake_lock_timeout(&hi->det_wake_lock, WAKE_LOCK_TIME_IN_SENDKEY); + /* debounce send/end key */ + while (time_left_ms > 0 && !hi->send_key_pressed) { + send_key_state = pdata->get_send_key_state(); + if (!send_key_state || !pdata->get_det_jack_state() || + hi->cur_jack_type != SEC_HEADSET_4POLE) { + /* button released or jack removed or more + * strangely a non-4pole headset + */ + pr_info(MODULE_NAME "%s : ignored button (%d %d %d)\n", + __func__, !send_key_state, + !pdata->get_det_jack_state(), + hi->cur_jack_type != + SEC_HEADSET_4POLE); + return; + } + usleep_range(10000, 10000); + time_left_ms -= 10; + } + + /* report state change of the send_end_key */ + if (hi->send_key_pressed != send_key_state) { +#ifdef CONFIG_MACH_JAGUAR + if (send_key_state) + sendkey_irq_progress = true; + else + sendkey_irq_progress = false; +#endif + set_send_key_state(hi, send_key_state); + pr_info(MODULE_NAME "%s : BTN is %s.\n", + __func__, + send_key_state ? "pressed" : "released"); + } + + return; +} + +static irqreturn_t sec_jack_det_irq_handler(int irq, void *handle) +{ + struct sec_jack_info *hi = (struct sec_jack_info *)handle; + + pr_info(MODULE_NAME "%s : ready = %d.\n", __func__, hi->is_ready); + + if (hi->is_ready) + schedule_work(&hi->det_work); + + return IRQ_HANDLED; +} + +static void sec_jack_det_work_func(struct work_struct *work) +{ + struct sec_jack_info *hi = + container_of(work, struct sec_jack_info, det_work); + + struct sec_jack_platform_data *pdata = hi->pdata; + int time_left_ms = DET_CHECK_TIME_MS; + + pr_debug(MODULE_NAME "%s\n", __func__); + + /* threaded irq can sleep */ + wake_lock_timeout(&hi->det_wake_lock, WAKE_LOCK_TIME); + +#ifdef CONFIG_MACH_JAGUAR + if ((hi->cur_jack_type == SEC_HEADSET_4POLE) && sendkey_irq_progress) { + pr_info(MODULE_NAME "%s / 120ms Delay\n", __func__); + usleep_range(120000, 120000); + + } else { + pr_info(MODULE_NAME "%s / No Delay\n", __func__); + sendkey_irq_progress = false; + } +#endif + + /* debounce headset jack. don't try to determine the type of + * headset until the detect state is true for a while. + */ + while (time_left_ms > 0) { + if (!pdata->get_det_jack_state()) { + /* jack not detected. */ + handle_jack_not_inserted(hi); + return; + } + usleep_range(10000, 10000); + time_left_ms -= 10; + } + + /* set mic bias to enable adc */ + pdata->set_micbias_state(true); + + /* to reduce noise in earjack when attaching */ + /* msleep(200); */ + + /* jack presence was detected the whole time, figure out which type */ + determine_jack_type(hi); + + return; +} + +static void sec_jack_powerup_work_func(struct work_struct *work) +{ + struct sec_jack_info *hi = + container_of(work, struct sec_jack_info, powerup_work.work); + + hi->is_ready = true; + sec_jack_det_irq_handler(hi->pdata->det_int, hi); + + return; +} + +static int sec_jack_probe(struct platform_device *pdev) +{ + struct sec_jack_info *hi; + struct sec_jack_platform_data *pdata = pdev->dev.platform_data; + int ret; + int sec_jack_keycode[] = {KEY_MEDIA, KEY_VOLUMEUP, KEY_VOLUMEDOWN}; + int i; + struct class *audio; + struct device *earjack; + + pr_info(MODULE_NAME "%s : Registering jack driver\n", __func__); + if (!pdata) { + pr_err("%s : pdata is NULL.\n", __func__); + return -ENODEV; + } + if (!pdata->get_adc_value || !pdata->get_det_jack_state || + !pdata->get_send_key_state || !pdata->zones || + !pdata->set_micbias_state || + pdata->num_zones > MAX_ZONE_LIMIT +#if defined(CONFIG_SAMSUNG_JACK_GNDLDET) + || !pdata->get_gnd_jack_state +#endif + ) { + pr_err("%s : need to check pdata\n", __func__); + return -ENODEV; + } + + hi = kzalloc(sizeof(struct sec_jack_info), GFP_KERNEL); + if (hi == NULL) { + pr_err("%s : Failed to allocate memory.\n", __func__); + return -ENOMEM; + } + + hi->is_ready = false; + hi->pdata = pdata; + hi->input = input_allocate_device(); + if (hi->input == NULL) { + ret = -ENOMEM; + pr_err("%s : Failed to allocate input device.\n", __func__); + goto err_request_input_dev; + } + + hi->input->name = "sec_jack"; + + for (i = 0 ; i < 3; i++) + input_set_capability(hi->input, EV_KEY, sec_jack_keycode[i]); + ret = input_register_device(hi->input); + + if (ret) { + pr_err("%s : Failed to register driver\n", __func__); + goto err_register_input_dev; + } + + ret = switch_dev_register(&switch_jack_detection); + if (ret < 0) { + pr_err("%s : Failed to register switch device\n", __func__); + goto err_switch_dev_register; + } + + ret = switch_dev_register(&switch_sendend); + if (ret < 0) { + pr_err("%s : Failed to register switch device\n", __func__); + goto err_switch_dev_register; + } + + wake_lock_init(&hi->det_wake_lock, WAKE_LOCK_SUSPEND, "sec_jack_det"); + +#ifdef SUPPORT_PBA + audio = class_create(THIS_MODULE, "audio"); + if (IS_ERR(audio)) + pr_err("Failed to create class(audio)!\n"); + + earjack = device_create(audio, NULL, 0, NULL, "earjack"); + if (IS_ERR(earjack)) + pr_err("Failed to create device(earjack)!\n"); + + ret = device_create_file(earjack, &dev_attr_key_state); + if (ret) + pr_err("Failed to create device file in sysfs entries(%s)!\n", + dev_attr_key_state.attr.name); + + ret = device_create_file(earjack, &dev_attr_state); + if (ret) + pr_err("Failed to create device file in sysfs entries(%s)!\n", + dev_attr_state.attr.name); + + ret = device_create_file(earjack, &dev_attr_select_jack); + if (ret) + pr_err("Failed to create device file in sysfs entries(%s)!\n", + dev_attr_select_jack.attr.name); + + ret = device_create_file(earjack, &dev_attr_reselect_jack); + if (ret) + pr_err("Failed to create device file in sysfs entries(%s)!\n", + dev_attr_reselect_jack.attr.name); +#endif + + INIT_WORK(&hi->det_work, sec_jack_det_work_func); + + ret = request_threaded_irq(pdata->det_int, NULL, + sec_jack_det_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, "sec_headset_detect", hi); + + if (ret) { + pr_err("%s : Failed to request_irq.\n", __func__); + goto err_request_detect_irq; + } + + /* to handle insert/removal when we're sleeping in a call */ + ret = enable_irq_wake(pdata->det_int); + if (ret) { + pr_err("%s : Failed to enable_irq_wake.\n", __func__); + goto err_enable_irq_wake; + } + + INIT_WORK(&hi->sendkey_work, sec_jack_send_key_work_func); + + ret = request_threaded_irq(pdata->send_int, NULL, + sec_jack_send_key_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "sec_headset_send_key", hi); + if (ret) { + pr_err("%s : Failed to request_irq.\n", __func__); + + goto err_request_send_key_irq; + } + + /* start with send/end interrupt disable. we only enable it + * when we detect a 4 pole headset + */ + disable_irq(pdata->send_int); + dev_set_drvdata(earjack, hi); + + /* call irq_thread forcely because of missing interrupt when booting. + * 2000ms delay is enough to waiting for adc driver registration. + */ + INIT_DELAYED_WORK(&hi->powerup_work, sec_jack_powerup_work_func); + schedule_delayed_work(&hi->powerup_work, msecs_to_jiffies(2000)); + + return 0; + +err_request_send_key_irq: + disable_irq_wake(pdata->det_int); +err_enable_irq_wake: + free_irq(pdata->det_int, hi); +err_request_detect_irq: + wake_lock_destroy(&hi->det_wake_lock); + switch_dev_unregister(&switch_jack_detection); + switch_dev_unregister(&switch_sendend); +err_switch_dev_register: + input_unregister_device(hi->input); +err_register_input_dev: + input_free_device(hi->input); +err_request_input_dev: + kfree(hi); + + return ret; +} + +static int sec_jack_remove(struct platform_device *pdev) +{ + + struct sec_jack_info *hi = dev_get_drvdata(&pdev->dev); + + pr_info(MODULE_NAME "%s :\n", __func__); + /* rebalance before free */ + if (hi->send_key_irq_enabled) + disable_irq_wake(hi->pdata->send_int); + else + enable_irq(hi->pdata->send_int); + free_irq(hi->pdata->send_int, hi); + disable_irq_wake(hi->pdata->det_int); + free_irq(hi->pdata->det_int, hi); + wake_lock_destroy(&hi->det_wake_lock); + switch_dev_unregister(&switch_jack_detection); + switch_dev_unregister(&switch_sendend); + input_unregister_device(hi->input); + kfree(hi); + + return 0; +} + +static struct platform_driver sec_jack_driver = { + .probe = sec_jack_probe, + .remove = sec_jack_remove, + .driver = { + .name = "sec_jack", + .owner = THIS_MODULE, + }, +}; +static int __init sec_jack_init(void) +{ + return platform_driver_register(&sec_jack_driver); +} + +static void __exit sec_jack_exit(void) +{ + platform_driver_unregister(&sec_jack_driver); +} + +module_init(sec_jack_init); +module_exit(sec_jack_exit); + +MODULE_AUTHOR("ms17.kim@samsung.com"); +MODULE_DESCRIPTION("Samsung Electronics Corp Ear-Jack detection driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/sec_misc.c b/drivers/misc/sec_misc.c new file mode 100644 index 00000000000..766823b2b15 --- /dev/null +++ b/drivers/misc/sec_misc.c @@ -0,0 +1,287 @@ +/* + * driver/misc/sec_misc.c + * + * driver supporting miscellaneous functions for Samsung P-series device + * + * COPYRIGHT(C) Samsung Electronics Co., Ltd. 2006-2011 All Right Reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MOVINAND_CHECKSUM +#define RORY_CONTROL + +static struct wake_lock sec_misc_wake_lock; + +#ifdef MOVINAND_CHECKSUM +unsigned char emmc_checksum_done; +unsigned char emmc_checksum_pass; +#endif + +static const struct file_operations sec_misc_fops = { + .owner = THIS_MODULE, + /* .read = sec_misc_read, + .ioctl = sec_misc_ioctl, + .open = sec_misc_open, + .release = sec_misc_release, */ +}; + +static struct miscdevice sec_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sec_misc", + .fops = &sec_misc_fops, +}; + +#ifdef MOVINAND_CHECKSUM +static ssize_t emmc_checksum_done_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, sizeof(buf), "%d\n", emmc_checksum_done); +} + +static ssize_t emmc_checksum_done_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int state; + + if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1)) + return -EINVAL; + + emmc_checksum_done = (unsigned char)state; + return size; +} + +static DEVICE_ATTR(emmc_checksum_done, S_IRUGO | S_IWUSR , + emmc_checksum_done_show, emmc_checksum_done_store); + +static ssize_t emmc_checksum_pass_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, sizeof(buf), "%d\n", emmc_checksum_pass); +} + +static ssize_t emmc_checksum_pass_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int state; + + if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1)) + return -EINVAL; + + emmc_checksum_pass = (unsigned char)state; + return size; +} + +static DEVICE_ATTR(emmc_checksum_pass, S_IRUGO | S_IWUSR , + emmc_checksum_pass_show, emmc_checksum_pass_store); +#endif /*MOVINAND_CHECKSUM*/ + + +#ifdef RORY_CONTROL +static ssize_t rory_control_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rory_control; + + sec_get_param(param_rory_control, &rory_control); + + return snprintf(buf, sizeof(buf), "%d\n", rory_control); +} + +static ssize_t rory_control_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int rory_control; + + sscanf(buf, "%i", &rory_control); + + pr_info("rory control store ..... %d\n", rory_control); + + /* write to param */ + sec_set_param(param_rory_control, &rory_control); + + return size; +} + +static DEVICE_ATTR(rory_control, S_IRUGO | S_IWUSR , + rory_control_show, rory_control_store); +#endif /*RORY_CONTROL*/ + +static unsigned int convert_debug_level_str(const char *str) +{ + if (strncasecmp(str, "0xA0A0", 6) == 0) + return KERNEL_SEC_DEBUG_LEVEL_LOW; + + if (strncasecmp(str, "0xB0B0", 6) == 0) + return KERNEL_SEC_DEBUG_LEVEL_MID; + + if (strncasecmp(str, "0xC0C0", 6) == 0) + return KERNEL_SEC_DEBUG_LEVEL_HIGH; + + return 0; +} +#if 0 +static void convert_debug_level_int(unsigned int val, char *str) +{ + if (val == KERNEL_SEC_DEBUG_LEVEL_LOW) { + strncpy(str, "0xA0A0", sizeof("0xA0A0")); + return; + } + + if (val == KERNEL_SEC_DEBUG_LEVEL_MID) { + strncpy(str, "0xB0B0", sizeof("0xB0B0")); + return; + } + + if (val == KERNEL_SEC_DEBUG_LEVEL_HIGH) { + strncpy(str, "0xC0C0", sizeof("0xC0C0")); + return; + } +} +#endif +static ssize_t debug_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buffer[7]; +// convert_debug_level_int(kernel_sec_get_debug_level(), buffer); + + return snprintf(buf, sizeof(buffer)+1, "%s\n", buffer); + +} + +static ssize_t debug_level_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int sec_debug_level = convert_debug_level_str(buf); + + if (sec_debug_level == 0) + return -EINVAL; + +// kernel_sec_set_debug_level(sec_debug_level); + + return size; + +} + +static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR , + debug_level_show, debug_level_store); + +#if defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_AEGIS2) +static ssize_t slideCount_show + (struct device *dev, struct device_attribute *attr, char *buf) +{ + int slideCount; + + sec_get_param(param_slideCount, &slideCount); + + return snprintf(buf, sizeof(buf), "%d\n", slideCount); +} + +static ssize_t slideCount_store + (struct device *dev, struct device_attribute *attr,\ + const char *buf, size_t size) +{ + int slideCount; + + sscanf(buf, "%i", &slideCount); + sec_set_param(param_slideCount, &slideCount); + + return size; +} +static DEVICE_ATTR(slideCount, S_IRUGO | S_IWUSR | S_IWGRP,\ + slideCount_show, slideCount_store); +#endif + +extern struct class *sec_class; +struct device *sec_misc_dev; + +static struct device_attribute *sec_misc_attrs[] = { + &dev_attr_emmc_checksum_done, + &dev_attr_emmc_checksum_pass, + &dev_attr_rory_control, + &dev_attr_debug_level, +#if defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_AEGIS2) + &dev_attr_slideCount, +#endif +}; + +static int __init sec_misc_init(void) +{ + int ret = 0; + int i; + + ret = misc_register(&sec_misc_device); + if (ret < 0) { + printk(KERN_ERR "misc_register failed!\n"); + goto failed_register_misc; + } + + sec_misc_dev = device_create(sec_class, NULL, 0, NULL, "sec_misc"); + if (IS_ERR(sec_misc_dev)) { + printk(KERN_ERR "failed to create device!\n"); + ret = -ENODEV; + goto failed_create_device; + } + + for (i = 0; i < ARRAY_SIZE(sec_misc_attrs) ; i++) { + ret = device_create_file(sec_misc_dev, sec_misc_attrs[i]); + if (ret < 0) { + pr_err("failed to create device file - %s\n", + dev_attr_emmc_checksum_done.attr.name); + goto failed_create_device_file; + } + } + + wake_lock_init(&sec_misc_wake_lock, WAKE_LOCK_SUSPEND, "sec_misc"); + + return 0; + +failed_create_device_file: + if (i) { + for (--i; i >= 0; i--) + device_remove_file(sec_misc_dev, sec_misc_attrs[i]); + } +failed_create_device: + misc_deregister(&sec_misc_device); +failed_register_misc: + return ret; +} + +static void __exit sec_misc_exit(void) +{ + wake_lock_destroy(&sec_misc_wake_lock); +} + +module_init(sec_misc_init); +module_exit(sec_misc_exit); + +/* Module information */ +MODULE_AUTHOR("Samsung"); +MODULE_DESCRIPTION("Samsung PX misc. driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/sec_param.c b/drivers/misc/sec_param.c new file mode 100644 index 00000000000..df169037dff --- /dev/null +++ b/drivers/misc/sec_param.c @@ -0,0 +1,256 @@ +/* + * drivers/misc/sec_param.c + * + * Copyright (c) 2011 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#define PARAM_RD 0 +#define PARAM_WR 1 + +#define SEC_PARAM_FILE_NAME "/dev/block/mmcblk0p10" /* parameter block */ +#define SEC_PARAM_FILE_SIZE 0xA00000 /* 10MB */ +#define SEC_PARAM_FILE_OFFSET (SEC_PARAM_FILE_SIZE - 0x100000) + +/* single global instance */ +sec_param_data *param_data; + +static bool param_sec_operation(void *value, int offset, + int size, int direction) +{ + /* Read from PARAM(parameter) partition */ + struct file *filp; + mm_segment_t fs; + int ret = true; + int flag = (direction == PARAM_WR) ? (O_RDWR | O_SYNC) : O_RDONLY; + + pr_debug("%s %x %x %d %d\n", __func__, (int) value, offset, size, direction); + + filp = filp_open(SEC_PARAM_FILE_NAME, flag, 0); + + if (IS_ERR(filp)) { + pr_err("%s: filp_open failed. (%ld)\n", + __func__, PTR_ERR(filp)); + return false; + } + + fs = get_fs(); + set_fs(get_ds()); + + ret = filp->f_op->llseek(filp, offset, SEEK_SET); + if (ret < 0) { + pr_err("%s FAIL LLSEEK\n", __func__); + ret = false; + goto param_sec_debug_out; + } + + if (direction == PARAM_RD) + ret = filp->f_op->read(filp, (char __user *)value, + size, &filp->f_pos); + else if (direction == PARAM_WR) + ret = filp->f_op->write(filp, (char __user *)value, + size, &filp->f_pos); + +param_sec_debug_out: + set_fs(fs); + filp_close(filp, NULL); + return ret; +} + +bool sec_open_param(void) +{ + int ret = true; + int offset = SEC_PARAM_FILE_OFFSET; + + if (param_data != NULL) + return true; + + param_data = kmalloc(sizeof(sec_param_data), GFP_KERNEL); + + ret = param_sec_operation(param_data, offset, + sizeof(sec_param_data), PARAM_RD); + + if (!ret) { + kfree(param_data); + param_data = NULL; + pr_err("%s PARAM OPEN FAIL\n", __func__); + return false; + } + + return ret; + +} +EXPORT_SYMBOL(sec_open_param); + +bool sec_get_param(sec_param_index index, void *value) +{ + int ret = true; + ret = sec_open_param(); + if (!ret) + return ret; + + switch (index) { + case param_index_debuglevel: + memcpy(value, &(param_data->debuglevel), sizeof(unsigned int)); + break; + case param_index_uartsel: + memcpy(value, &(param_data->uartsel), sizeof(unsigned int)); + break; + case param_rory_control: + memcpy(value, &(param_data->rory_control), + sizeof(unsigned int)); + break; + case param_index_movinand_checksum_done: + memcpy(value, &(param_data->movinand_checksum_done), + sizeof(unsigned int)); + break; + case param_index_movinand_checksum_pass: + memcpy(value, &(param_data->movinand_checksum_pass), + sizeof(unsigned int)); + break; +#if defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_AEGIS2) + case param_slideCount: + memcpy(value, &(param_data->slideCount), + sizeof(unsigned int)); + break; +#endif + default: + return false; + } + + return true; +} +EXPORT_SYMBOL(sec_get_param); + +bool sec_set_param(sec_param_index index, void *value) +{ + int ret = true; + int offset = SEC_PARAM_FILE_OFFSET; + + ret = sec_open_param(); + if (!ret) + return ret; + + switch (index) { + case param_index_debuglevel: + memcpy(&(param_data->debuglevel), + value, sizeof(unsigned int)); + break; + case param_index_uartsel: + memcpy(&(param_data->uartsel), + value, sizeof(unsigned int)); + break; + case param_rory_control: + memcpy(&(param_data->rory_control), + value, sizeof(unsigned int)); + break; + case param_index_movinand_checksum_done: + memcpy(&(param_data->movinand_checksum_done), + value, sizeof(unsigned int)); + break; + case param_index_movinand_checksum_pass: + memcpy(&(param_data->movinand_checksum_pass), + value, sizeof(unsigned int)); + break; +#if defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_AEGIS2) + case param_slideCount: + memcpy(&(param_data->slideCount), + value, sizeof(unsigned int)); + break; +#endif + default: + return false; + } + + return param_sec_operation(param_data, offset, + sizeof(sec_param_data), PARAM_WR); +} +EXPORT_SYMBOL(sec_set_param); + +/* ########################################################## + * # + * # SEC PARAM Driver sysfs file + * # 1. movinand_checksum_done_show + * # 2. movinand_checksum_pass_show + * ########################################################## + * */ +static struct class *sec_param_class; +struct device *sec_param_dev; + +static ssize_t movinand_checksum_done_show +(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret = 0; + + sec_get_param(param_index_movinand_checksum_done, &ret); + if (ret == 1 || ret == 0) { + pr_err("checksum is not in valuable range.\n"); + ret = 1; + } + return sprintf(buf, "%u\n", ret); +} +static DEVICE_ATTR(movinand_checksum_done, + 0664, movinand_checksum_done_show, NULL); + +static ssize_t movinand_checksum_pass_show +(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret = 0; + + sec_get_param(param_index_movinand_checksum_pass, &ret); + if (ret == 1 || ret == 0) { + pr_err("checksum is not in valuable range.\n"); + ret = 1; + } + return sprintf(buf, "%u\n", ret); +} +static DEVICE_ATTR(movinand_checksum_pass, + 0664, movinand_checksum_pass_show, NULL); + +int sec_param_sysfs_init(void) +{ + + int ret = 0; + + sec_param_class = class_create(THIS_MODULE, "sec_param"); + + if (IS_ERR(sec_param_class)) { + pr_err("Failed to create class(mdnie_class)!!\n"); + ret = -1; + } + + sec_param_dev = device_create(sec_param_class, + NULL, 0, NULL, "sec_param"); + + if (IS_ERR(sec_param_dev)) { + printk(KERN_ERR "Failed to create device(sec_param_dev)!!"); + ret = -1; + } + + if (device_create_file(sec_param_dev, + &dev_attr_movinand_checksum_done) < 0) { + pr_err("Failed to create device file!(%s)!\n", + dev_attr_movinand_checksum_done.attr.name); + ret = -1; + } + + if (device_create_file(sec_param_dev, + &dev_attr_movinand_checksum_pass) < 0) { + pr_err("Failed to create device file!(%s)!\n", + dev_attr_movinand_checksum_pass.attr.name); + ret = -1; + } + return ret; + +} +module_init(sec_param_sysfs_init); diff --git a/drivers/misc/stmpe811.c b/drivers/misc/stmpe811.c new file mode 100644 index 00000000000..bd96eb3d3cd --- /dev/null +++ b/drivers/misc/stmpe811.c @@ -0,0 +1,300 @@ +/* drivers/misc/stmpe811.c + * + * Copyright (C) 2011 Samsung Electronics Co, Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STMPE811_CHIP_ID 0x00 +#define STMPE811_ID_VER 0x02 +#define STMPE811_SYS_CTRL1 0x03 +#define STMPE811_SYS_CTRL2 0x04 +#define STMPE811_INT_CTRL 0x09 +#define STMPE811_INT_EN 0x0A +#define STMPE811_INT_STA 0x0B +#define STMPE811_ADC_INT_EN 0x0E +#define STMPE811_ADC_INT_STA 0x0F +#define STMPE811_ADC_CTRL1 0x20 +#define STMPE811_ADC_CTRL2 0x21 +#define STMPE811_ADC_CAPT 0x22 +#define STMPE811_ADC_DATA_CH0 0x30 +#define STMPE811_ADC_DATA_CH1 0x32 +#define STMPE811_ADC_DATA_CH2 0x34 +#define STMPE811_ADC_DATA_CH3 0x36 +#define STMPE811_ADC_DATA_CH4 0x38 +#define STMPE811_ADC_DATA_CH5 0x3A +#define STMPE811_ADC_DATA_CH6 0x3C +#define STMPE811_ADC_DATA_CH7 0x3E +#define STMPE811_GPIO_AF 0x17 +#define STMPE811_TSC_CTRL 0x40 + +struct stmpe811_adc_data { + struct i2c_client *client; + struct mutex adc_lock; + struct delayed_work init_work; +}; + +static struct stmpe811_adc_data *local_adc_data; + +s32 stmpe811_adc_get_value(u8 channel) +{ + struct stmpe811_adc_data *adc_data = local_adc_data; + struct i2c_client *client = adc_data->client; + + s32 w_data = 0; + int data_channel_addr = 0; + s32 ddata; + + mutex_lock(&adc_data->adc_lock); + /* delay stablization time */ + msleep(30); + i2c_smbus_write_byte_data(client, STMPE811_ADC_CAPT, 0xff); + msleep(30); + data_channel_addr = STMPE811_ADC_DATA_CH0 + (channel * 2); + + ddata = i2c_smbus_read_word_data(client, data_channel_addr); + if (ddata < 0) { + printk(KERN_INFO "%s: Failed to read ADC_DATA_CH(%d).\n", + __func__, channel); + mutex_unlock(&adc_data->adc_lock); + return ddata; + } + + w_data = ((ddata & 0xff) << 8 | (ddata >> 8)) & 0xfff; + printk(KERN_INFO "%s: ADC_DATA_CH(%d) = 0x%x, %d\n", + __func__, channel, w_data, w_data); + + mutex_unlock(&adc_data->adc_lock); + + return w_data; +} + +static ssize_t adc_test_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + + struct stmpe811_adc_data *adc_data = dev_get_drvdata(dev); + struct i2c_client *client = adc_data->client; + s32 ret; + + ret = stmpe811_adc_get_value(7); + if (ret < 0) { + dev_err(&client->dev, + "%s: err at read adc %d\n", __func__, ret); + return snprintf(buf, 9, "UNKNOWN\n"); + } + printk(KERN_INFO "%s: accessory adc[ch7]: %x\n", __func__, ret); + + if (ret > 0xe38 && ret < 0xed8) + return snprintf(buf, 3, "1c\n"); + + return snprintf(buf, 4, "%x\n", ret); +} + +static ssize_t usb_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + if (current_cable_type == 3) + return snprintf(buf, 22, "USB_STATE_CONFIGURED\n"); + + return snprintf(buf, 25, "USB_STATE_NOTCONFIGURED\n"); +} + +static DEVICE_ATTR(adc, S_IRUGO, adc_test_show, NULL); +static DEVICE_ATTR(usb_state, S_IRUGO, usb_state_show, NULL); + +static int stmpe811_adc_i2c_remove(struct i2c_client *client) +{ + struct stmpe811_adc_data *adc = i2c_get_clientdata(client); + mutex_destroy(&adc->adc_lock); + kfree(adc); + + return 0; +} + +static void stmpe811_reg_init(struct stmpe811_adc_data *data) +{ + struct stmpe811_adc_data *adc_data = data; + struct i2c_client *client = adc_data->client; + + int ret; + /* intialize stmpe811 control register */ + ret = i2c_smbus_read_word_data(client, STMPE811_CHIP_ID); + printk(KERN_INFO "%s: CHIP_ID: %x\n", __func__, ret); + + if (ret < 0) { + printk(KERN_ERR "%s: Failed to read STMPE811_CHIP_ID : 0x%x\n", + __func__, ret); + return; + } + /* soft rest */ + i2c_smbus_write_byte_data(client, STMPE811_SYS_CTRL1, 0x02); + msleep(20); + /* clock on:GPIO&ADC, off:TS&TSC */ + i2c_smbus_write_byte_data(client, STMPE811_SYS_CTRL2, 0x0a); + ret = i2c_smbus_read_byte_data(client, STMPE811_SYS_CTRL2); + printk(KERN_INFO "STMPE811_SYS_CTRL2 = 0x%x\n", ret); + /* disable interrupt */ + i2c_smbus_write_byte_data(client, STMPE811_INT_EN, 0x00); + ret = i2c_smbus_read_byte_data(client, STMPE811_INT_EN); + printk(KERN_INFO "STMPE811_INT_EN = 0x%x\n", ret); + /* adc conversion time:64, 12bit ADC oper, internal */ + i2c_smbus_write_byte_data(client, STMPE811_ADC_CTRL1, 0x3c); + ret = i2c_smbus_read_byte_data(client, STMPE811_ADC_CTRL1); + printk(KERN_INFO "STMPE811_ADC_CTRL1 = 0x%x\n", ret); + /* clock speed 6.5MHz */ + i2c_smbus_write_byte_data(client, STMPE811_ADC_CTRL2, 0x03); + ret = i2c_smbus_read_byte_data(client, STMPE811_ADC_CTRL2); + printk(KERN_INFO "STMPE811_ADC_CTRL2 = 0x%x\n", ret); + + /* It should be ADC settings. + * So the value should be 0x00 instead of 0xFF + * gpio 0-3 -> ADC + */ + i2c_smbus_write_byte_data(client, STMPE811_GPIO_AF, 0x00); + ret = i2c_smbus_read_byte_data(client, STMPE811_GPIO_AF); + printk(KERN_INFO "STMPE811_GPIO_AF = 0x%x\n", ret); + /* init Ch[0]=ADC_CHECK(battery), ch[3]=Accessory */ + i2c_smbus_write_byte_data(client, STMPE811_ADC_CAPT, 0x90); + + i2c_smbus_write_byte_data(client, STMPE811_TSC_CTRL, 0x00); + ret = i2c_smbus_read_byte_data(client, STMPE811_TSC_CTRL); + printk(KERN_INFO "STMPE811_TSC_CTRL = 0x%x\n", ret); + + pr_info("%s success\n", __func__); + +} + +static int stmpe811_adc_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct stmpe811_adc_data *adc_data; + struct device *sec_adc_dev; + + int ret; + + printk(KERN_INFO "%s: probe start!\n", __func__); + + if (!i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -EIO; + + adc_data = kzalloc(sizeof(struct stmpe811_adc_data), GFP_KERNEL); + if (adc_data == NULL) { + printk(KERN_ERR "failed to allocate memory\n"); + return -ENOMEM; + } + + adc_data->client = client; + i2c_set_clientdata(client, adc_data); + + mutex_init(&adc_data->adc_lock); + + local_adc_data = adc_data; + + /* set sysfs for adc test mode*/ + sec_adc_dev = device_create(sec_class, NULL, 0, NULL, "switch"); + if (IS_ERR(sec_adc_dev)) { + printk(KERN_ERR "%s: Failed to create device (switch)!\n", + __func__); + ret = PTR_ERR(sec_adc_dev); + goto err_create_device; + } + + ret = device_create_file(sec_adc_dev, &dev_attr_adc); + if (ret < 0) { + printk(KERN_ERR "failed to create device file(%s)!\n", + dev_attr_adc.attr.name); + goto err_create_file_adc; + } + + ret = device_create_file(sec_adc_dev, &dev_attr_usb_state); + if (ret < 0) { + printk(KERN_ERR "failed to create device file(%s)!\n", + dev_attr_usb_state.attr.name); + goto err_create_file_usb_state; + } + + dev_set_drvdata(sec_adc_dev, adc_data); + stmpe811_reg_init(adc_data); + + return 0; + +err_create_file_usb_state: + device_remove_file(sec_adc_dev, &dev_attr_usb_state); +err_create_file_adc: + device_remove_file(sec_adc_dev, &dev_attr_adc); +err_create_device: + if (client->irq) + free_irq(client->irq, adc_data); + + mutex_destroy(&adc_data->adc_lock); + i2c_set_clientdata(client, NULL); + kfree(adc_data); + return ret; +} + + +static const struct i2c_device_id stmpe811_id[] = { + {"stmpe811", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, stmpe811_adc_device_id); + + +static struct i2c_driver stmpe811_adc_i2c_driver = { + .driver = { + .name = "stmpe811", + .owner = THIS_MODULE, + }, + .probe = stmpe811_adc_i2c_probe, + .remove = stmpe811_adc_i2c_remove, + .id_table = stmpe811_id, +}; + +static int __init stmpe811_adc_init(void) +{ + return i2c_add_driver(&stmpe811_adc_i2c_driver); +} +module_init(stmpe811_adc_init); + +static void __exit stmpe811_adc_exit(void) +{ + i2c_del_driver(&stmpe811_adc_i2c_driver); +} + +module_exit(stmpe811_adc_exit); + +MODULE_AUTHOR("Samsung"); +MODULE_DESCRIPTION("Samsung STMPE811 ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8de8fbdda8a..60addd447b4 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -43,6 +43,9 @@ #include "mmc_ops.h" #include "sd_ops.h" #include "sdio_ops.h" +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) +#include "../host/msm_sdcc.h" +#endif /* * Background operations can take a long time, depending on the housekeeping @@ -2764,6 +2767,9 @@ int mmc_pm_notify(struct notifier_block *notify_block, struct mmc_host *host = container_of( notify_block, struct mmc_host, pm_notify); unsigned long flags; +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) + struct msmsdcc_host *msmhost = mmc_priv(host); +#endif int err = 0; switch (mode) { @@ -2815,7 +2821,13 @@ int mmc_pm_notify(struct notifier_block *notify_block, } host->rescan_disable = 0; spin_unlock_irqrestore(&host->lock, flags); - mmc_detect_change(host, 0); +#if defined(CONFIG_BCM4334) || defined(CONFIG_BCM4334_MODULE) + if (msmhost->pdev_id == 4) + printk(KERN_INFO"%s(): WLAN SKIP DETECT CHANGE\n", + __func__); + else +#endif + mmc_detect_change(host, 0); } diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 09383058608..b80467e1c14 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -5441,7 +5441,8 @@ static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev) struct mmc_platform_data *pdata; struct device_node *np = dev->of_node; u32 bus_width = 0, current_limit = 0; - u32 *clk_table, *sup_voltages; + u32 *clk_table =NULL; + u32 *sup_voltages=NULL; int clk_table_len, sup_volt_len, len; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -6330,6 +6331,11 @@ msmsdcc_runtime_suspend(struct device *dev) goto out; } + if (host->pdev_id == 4) { + host->mmc->pm_flags |= MMC_PM_KEEP_POWER; + printk(KERN_INFO "%s: Enter WIFI suspend\n", __func__); + } + pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__); if (mmc) { host->sdcc_suspending = 1; @@ -6393,6 +6399,10 @@ msmsdcc_runtime_resume(struct device *dev) if (host->plat->is_sdio_al_client) return 0; + if (host->pdev_id == 4) { + printk(KERN_INFO "%s: Enter WIFI resume\n", __func__); + } + pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__); if (mmc) { if (mmc->card && mmc_card_sdio(mmc->card) && diff --git a/drivers/motor/Kconfig b/drivers/motor/Kconfig new file mode 100644 index 00000000000..cdac34d0735 --- /dev/null +++ b/drivers/motor/Kconfig @@ -0,0 +1,13 @@ +# +# Immersion TouchSense Player driver configuration +# +menuconfig VIBETONZ + tristate "Vibetonz" + default n + help + Say Y to enable Vibetonz support. + +config MOTOR_DRV_MAX77693 + tristate "Maxim MAX77693 motor" + default n + depends on MFD_MAX77693 diff --git a/drivers/motor/Makefile b/drivers/motor/Makefile new file mode 100644 index 00000000000..c03c0461314 --- /dev/null +++ b/drivers/motor/Makefile @@ -0,0 +1,8 @@ +# +# makefile for tspdrv kernel module +# + +obj-$(CONFIG_VIBETONZ) += vibrator.o +obj-$(CONFIG_MOTOR_DRV_MAX77693) += max77693_haptic.o + +vibrator-objs +=tspdrv.o diff --git a/drivers/motor/VibeOSKernelLinuxHRTime.c b/drivers/motor/VibeOSKernelLinuxHRTime.c new file mode 100644 index 00000000000..c58b4c8ff56 --- /dev/null +++ b/drivers/motor/VibeOSKernelLinuxHRTime.c @@ -0,0 +1,254 @@ +/* +** ========================================================================= +** File: +** VibeOSKernelLinuxHRTime.c +** +** Description: +** High Resolution Time helper functions for Linux. +** +** Portions Copyright (c) 2010 Immersion Corporation. All Rights Reserved. +** +** This file contains Original Code and/or Modifications of Original Code +** as defined in and that are subject to the GNU Public License v2 - +** (the 'License'). You may not use this file except in compliance with the +** License. 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 or contact +** TouchSenseSales@immersion.com. +** +** The Original Code and all software distributed under the License are +** distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +** EXPRESS OR IMPLIED, AND IMMERSION HEREBY DISCLAIMS ALL SUCH WARRANTIES, +** INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +** FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see +** the License for the specific language governing rights and limitations +** under the License. +** ========================================================================= +*/ + +/* +** Kernel high-resolution software timer is used as an example but another type +** of timer (such as HW timer or standard software timer) +** might be used to achieve the 5ms required rate. +*/ + +#ifndef CONFIG_HIGH_RES_TIMERS +#warning "The Kernel does not have high resolution timers enabled."\ +"Either provide a non hr-timer implementation of VibeOSKernelLinuxTime."\ +"c or re-compile your kernel with CONFIG_HIGH_RES_TIMERS=y" +#endif + +#include +#include +#include +#define WATCHDOG_TIMEOUT 10 /* 10 timer cycles = 50ms */ + +/* Global variables */ +static bool g_btimerstarted; +static struct hrtimer g_tsptimer; +static ktime_t g_ktfivems; +static int g_nwatchdog_counter; + +static struct semaphore g_mutex; + +/* Forward declarations */ +static void VibeOSKernelLinuxStartTimer(void); +static void VibeOSKernelLinuxStopTimer(void); +static int VibeOSKernelProcessData(void *data); +#define VIBEOSKERNELPROCESSDATA + +static inline int VibeSemIsLocked(struct semaphore *lock) +{ + return (lock->count) != 1; +} + +static enum hrtimer_restart tsp_timer_interrupt(struct hrtimer *timer) +{ + /* Scheduling next timeout value right away */ + hrtimer_forward_now(timer, g_ktfivems); + + if (g_btimerstarted) + if (VibeSemIsLocked(&g_mutex)) + up(&g_mutex); + + return HRTIMER_RESTART; +} + +static int VibeOSKernelProcessData(void *data) +{ + int i; + int nactuator_not_playing = 0; + + for (i = 0; i < NUM_ACTUATORS; i++) { + actuator_samples_buffer *pcurrent_actuator_sample = + &(g_samples_buffer[i]); + + if (-1 == pcurrent_actuator_sample->nindex_playing_buffer) { + nactuator_not_playing++; + if ((NUM_ACTUATORS == nactuator_not_playing) && + ((++g_nwatchdog_counter) > WATCHDOG_TIMEOUT)) { + int8_t czero[1] = {0}; + + /* + ** Nothing to play for all actuators, + ** turn off the timer + ** when we reach the watchdog tick count limit + */ + ImmVibeSPI_ForceOut_SetSamples(i, 8, 1, czero); + ImmVibeSPI_ForceOut_AmpDisable(i); + VibeOSKernelLinuxStopTimer(); + + /* Reset watchdog counter */ + g_nwatchdog_counter = 0; + } + } else { + /* Play the current buffer */ + if (VIBE_E_FAIL == ImmVibeSPI_ForceOut_SetSamples( + pcurrent_actuator_sample->actuator_samples + [(int)pcurrent_actuator_sample->nindex_playing_buffer] + .nactuator_index, + pcurrent_actuator_sample->actuator_samples + [(int)pcurrent_actuator_sample->nindex_playing_buffer] + .nbit_depth, + pcurrent_actuator_sample->actuator_samples + [(int)pcurrent_actuator_sample->nindex_playing_buffer] + .nbuffer_size, + pcurrent_actuator_sample->actuator_samples + [(int)pcurrent_actuator_sample->nindex_playing_buffer] + .data_buffer)) { + /* VIBE_E_FAIL means NAK has been handled. + Schedule timer to restart 5 ms from now */ + hrtimer_forward_now(&g_tsptimer, g_ktfivems); + } + + pcurrent_actuator_sample->nindex_output_value += + pcurrent_actuator_sample->actuator_samples + [(int)pcurrent_actuator_sample->nindex_playing_buffer] + .nbuffer_size; + + if (pcurrent_actuator_sample->nindex_output_value >= + pcurrent_actuator_sample->actuator_samples + [(int)pcurrent_actuator_sample + ->nindex_playing_buffer] + .nbuffer_size) { + /* Reach the end of the current buffer */ + pcurrent_actuator_sample->actuator_samples + [(int)pcurrent_actuator_sample + ->nindex_playing_buffer] + .nbuffer_size = 0; + + /* Switch buffer */ + (pcurrent_actuator_sample + ->nindex_playing_buffer) ^= 1; + pcurrent_actuator_sample + ->nindex_output_value = 0; + + /* Finished playing, + disable amp for actuator (i) */ + if (g_bstoprequested) { + pcurrent_actuator_sample + ->nindex_playing_buffer = -1; + + ImmVibeSPI_ForceOut_AmpDisable(i); + } + } + } + } + + /* If finished playing, stop timer */ + if (g_bstoprequested) { + VibeOSKernelLinuxStopTimer(); + + /* Reset watchdog counter */ + g_nwatchdog_counter = 0; + + if (VibeSemIsLocked(&g_mutex)) + up(&g_mutex); + return 1; /* tell the caller this is the last iteration */ + } + + return 0; +} + +static void VibeOSKernelLinuxInitTimer(void) +{ + /* Get a 5,000,000ns = 5ms time value */ + g_ktfivems = ktime_set(0, 5000000); + hrtimer_init(&g_tsptimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + + /* Initialize a 5ms-timer with tsp_timer_interrupt + as timer callback (interrupt driven)*/ + g_tsptimer.function = tsp_timer_interrupt; + sema_init(&g_mutex, 1); /* initialize simaphore */ +} + +static void VibeOSKernelLinuxStartTimer(void) +{ + int i; + int res; + + /* Reset watchdog counter */ + g_nwatchdog_counter = 0; + + if (!g_btimerstarted) { + if (!VibeSemIsLocked(&g_mutex)) + res = down_interruptible(&g_mutex); /* start locked */ + + g_btimerstarted = true; + + /* Start the timer */ + hrtimer_start(&g_tsptimer, g_ktfivems, HRTIMER_MODE_REL); + + /* Don't block the write() function after the first sample + to allow the host sending the next samples with no delay */ + for (i = 0; i < NUM_ACTUATORS; i++) { + if ((g_samples_buffer[i] + .actuator_samples[0].nbuffer_size) || + (g_samples_buffer[i] + .actuator_samples[1].nbuffer_size)) { + g_samples_buffer[i].nindex_output_value = 0; + return; + } + } + } + + if (0 != VibeOSKernelProcessData(NULL)) + return; + + /* + ** Use interruptible version of down to be safe + ** (try to not being stuck here if the mutex is + ** not freed for any reason) + */ + /* wait for the mutex to be freed by the timer */ + res = down_interruptible(&g_mutex); + if (res != 0) + DbgOut((KERN_INFO + "tspdrv: down_interruptible interrupted by a signal.\n")); +} + +static void VibeOSKernelLinuxStopTimer(void) +{ + int i; + + if (g_btimerstarted) { + g_btimerstarted = false; + hrtimer_cancel(&g_tsptimer); + } + + /* Reset samples buffers */ + for (i = 0; i < NUM_ACTUATORS; i++) { + g_samples_buffer[i].nindex_playing_buffer = -1; + g_samples_buffer[i].actuator_samples[0].nbuffer_size = 0; + g_samples_buffer[i].actuator_samples[1].nbuffer_size = 0; + } + g_bstoprequested = false; + g_bisplaying = false; +} + +static void VibeOSKernelLinuxTerminateTimer(void) +{ + VibeOSKernelLinuxStopTimer(); + if (VibeSemIsLocked(&g_mutex)) + up(&g_mutex); +} diff --git a/drivers/motor/immvibespi.c b/drivers/motor/immvibespi.c new file mode 100644 index 00000000000..9d03d5e55a2 --- /dev/null +++ b/drivers/motor/immvibespi.c @@ -0,0 +1,344 @@ +/* +** ========================================================================= +** File: +** ImmVibeSPI.c +** +** Description: +** Device-dependent functions called by Immersion TSP API +** to control PWM duty cycle, amp enable/disable, save IVT file, etc... +** +** Portions Copyright (c) 2008-2010 Immersion Corporation. All Rights Reserved. +** +** This file contains Original Code and/or Modifications of Original Code +** as defined in and that are subject to the GNU Public License v2 - +** (the 'License'). You may not use this file except in compliance with the +** License. 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 or contact +** TouchSenseSales@immersion.com. +** +** The Original Code and all software distributed under the License are +** distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +** EXPRESS OR IMPLIED, AND IMMERSION HEREBY DISCLAIMS ALL SUCH WARRANTIES, +** INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +** FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see +** the License for the specific language governing rights and limitations +** under the License. +** ========================================================================= +*/ +#include +#include +#include "tspdrv.h" + +/* +** This SPI supports only one actuator. +*/ +#define NUM_ACTUATORS 1 +#define PWM_DUTY_MAX 213 /* 13MHz / (579 + 1) = 22.4kHz */ +#define PWM_DEVICE 1 + +static bool g_bampenabled; + +static int32_t vibe_set_pwm_freq(int nForce) +{ + /* Put the MND counter in reset mode for programming */ + HWIO_OUTM(GP_NS_REG, HWIO_GP_NS_REG_MNCNTR_EN_BMSK, 0); + HWIO_OUTM(GP_NS_REG, HWIO_GP_NS_REG_PRE_DIV_SEL_BMSK, + 3 << HWIO_GP_NS_REG_PRE_DIV_SEL_SHFT); + HWIO_OUTM(GP_NS_REG, HWIO_GP_NS_REG_SRC_SEL_BMSK, + 5 << HWIO_GP_NS_REG_SRC_SEL_SHFT); + HWIO_OUTM(GP_NS_REG, HWIO_GP_NS_REG_MNCNTR_MODE_BMSK, + 2 << HWIO_GP_NS_REG_MNCNTR_MODE_SHFT); + HWIO_OUTM(GP_MD_REG, HWIO_GP_MD_REG_M_VAL_BMSK, + g_nlra_gp_clk_m << HWIO_GP_MD_REG_M_VAL_SHFT); + if (nForce > 0) + g_nforce_32 = ((nForce * g_nlra_gp_clk_pwm_mul) >> 8) + 1; + else + g_nforce_32 = ((nForce * g_nlra_gp_clk_pwm_mul) >> 8) + + g_nlra_gp_clk_d; + /* printk(KERN_DEBUG "[tspdrv] g_nForce_32 : %d\n", g_nforce_32); */ + HWIO_OUTM(GP_MD_REG, HWIO_GP_MD_REG_D_VAL_BMSK, + (~((int16_t)g_nforce_32 << 1)) << HWIO_GP_MD_REG_D_VAL_SHFT); + HWIO_OUTM(GP_NS_REG, HWIO_GP_NS_REG_GP_N_VAL_BMSK, + ~(g_nlra_gp_clk_n - g_nlra_gp_clk_m) << HWIO_GP_NS_REG_GP_N_VAL_SHFT); + if (nForce > 0) { + HWIO_OUTM(GP_NS_REG, HWIO_GP_NS_REG_GP_CLK_INV_BMSK, + 1 << HWIO_GP_NS_REG_GP_CLK_INV_SHFT); + } else { + HWIO_OUTM(GP_NS_REG, HWIO_GP_NS_REG_GP_CLK_INV_BMSK, + 0 << HWIO_GP_NS_REG_GP_CLK_INV_SHFT); + } + HWIO_OUTM(GP_NS_REG, HWIO_GP_NS_REG_MNCNTR_EN_BMSK, + 1 << HWIO_GP_NS_REG_MNCNTR_EN_SHFT); + /* printk(KERN_DEBUG + "[tspdrv]%x, %x, %x\n", + (~((int16_t)g_nforce_32 << 1)) << HWIO_GP_MD_REG_D_VAL_SHFT, + ~(g_nlra_gp_clk_n - g_nlra_gp_clk_m) << HWIO_GP_NS_REG_GP_N_VAL_SHFT, + 1 << HWIO_GP_NS_REG_MNCNTR_EN_SHFT); */ + + return VIBE_S_SUCCESS; +} + +static int32_t vibe_pwm_onoff(u8 onoff) +{ + if (onoff) { + HWIO_OUTM(GP_NS_REG, + HWIO_GP_NS_REG_GP_CLK_BRANCH_ENA_BMSK, + 1<> 8; + break; + default: + /* Unexpected bit depth */ + return VIBE_E_FAIL; + } + + if (nforce == 0) { + /* Set 50% duty cycle or disable amp */ + ImmVibeSPI_ForceOut_AmpDisable(0); + vibe_pwm_onoff(0); + nforce = 0; + pre_nforce = 0; + } else { + if (nforce > 0) + nforce = 127 - nforce; + /* Map force from [-127, 127] to [0, PWM_DUTY_MAX] */ + /* printk(KERN_DEBUG "[tspdrv]nForce===%d\n", nforce); */ + if (pre_nforce != nforce) { + vibe_pwm_onoff(1); + vibe_set_pwm_freq(nforce); + ImmVibeSPI_ForceOut_AmpEnable(0); + pre_nforce = nforce; + } + } + return VIBE_S_SUCCESS; +} + +/* +** Called to get the device name (device name must be returned as ANSI char) +*/ +static int32_t ImmVibeSPI_Device_GetName( + u_int8_t nActuatorIndex, char *szDevName, int nSize) +{ + return VIBE_S_SUCCESS; +} + + diff --git a/drivers/motor/max77693_haptic.c b/drivers/motor/max77693_haptic.c new file mode 100644 index 00000000000..1e1a3d3e29d --- /dev/null +++ b/drivers/motor/max77693_haptic.c @@ -0,0 +1,166 @@ +/* + * haptic motor driver for max77693 - max77673_haptic.c + * + * Copyright (C) 2011 ByungChang Cha + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct max77693_haptic_data { + struct max77693_dev *max77693; + struct i2c_client *i2c; + struct i2c_client *pmic_i2c; + struct max77693_haptic_platform_data *pdata; + + spinlock_t lock; + bool running; +}; + +struct max77693_haptic_data *g_hap_data; + +static void max77693_haptic_i2c(struct max77693_haptic_data *hap_data, bool en) +{ + int ret; + u8 value = hap_data->pdata->reg2; + u8 lscnfg_val = 0x00; + + pr_debug("[VIB] %s %d\n", __func__, en); + + if (en) { + value |= MOTOR_EN; + lscnfg_val = 0x80; + } + + ret = max77693_update_reg(hap_data->pmic_i2c, MAX77693_PMIC_REG_LSCNFG, + lscnfg_val, 0x80); + if (ret) + pr_err("[VIB] i2c update error %d\n", ret); + + ret = max77693_write_reg(hap_data->i2c, + MAX77693_HAPTIC_REG_CONFIG2, value); + if (ret) + pr_err("[VIB] i2c write error %d\n", ret); +} + +#ifdef CONFIG_VIBETONZ +void max77693_vibtonz_en(bool en) +{ + if (g_hap_data == NULL) { + printk(KERN_ERR "[VIB] the motor is not ready!!!"); + return ; + } + + if (en) { + if (g_hap_data->running) + return; + + max77693_haptic_i2c(g_hap_data, true); + + g_hap_data->running = true; + } else { + if (!g_hap_data->running) + return; + + max77693_haptic_i2c(g_hap_data, false); + + g_hap_data->running = false; + } +} +EXPORT_SYMBOL(max77693_vibtonz_en); +#endif + +static int max77693_haptic_probe(struct platform_device *pdev) +{ + int error = 0; + struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); + struct max77693_platform_data *max77693_pdata + = dev_get_platdata(max77693->dev); + struct max77693_haptic_platform_data *pdata + = max77693_pdata->haptic_data; + struct max77693_haptic_data *hap_data; + + pr_debug("[VIB] ++ %s\n", __func__); + if (pdata == NULL) { + pr_err("%s: no pdata\n", __func__); + return -ENODEV; + } + + hap_data = kzalloc(sizeof(struct max77693_haptic_data), GFP_KERNEL); + if (!hap_data) + return -ENOMEM; + + platform_set_drvdata(pdev, hap_data); + g_hap_data = hap_data; + hap_data->max77693 = max77693; + hap_data->i2c = max77693->haptic; + hap_data->pmic_i2c = max77693->i2c; + hap_data->pdata = pdata; + + spin_lock_init(&(hap_data->lock)); + + pr_debug("[VIB] -- %s\n", __func__); + + return error; +} + +static int __devexit max77693_haptic_remove(struct platform_device *pdev) +{ + struct max77693_haptic_data *data = platform_get_drvdata(pdev); + kfree(data); + g_hap_data = NULL; + + return 0; +} + +static int max77693_haptic_suspend(struct platform_device *pdev, + pm_message_t state) +{ + return 0; +} +static int max77693_haptic_resume(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver max77693_haptic_driver = { + .probe = max77693_haptic_probe, + .remove = max77693_haptic_remove, + .suspend = max77693_haptic_suspend, + .resume = max77693_haptic_resume, + .driver = { + .name = "max77693-haptic", + .owner = THIS_MODULE, + }, +}; + +static int __init max77693_haptic_init(void) +{ + pr_debug("[VIB] %s\n", __func__); + return platform_driver_register(&max77693_haptic_driver); +} +module_init(max77693_haptic_init); + +static void __exit max77693_haptic_exit(void) +{ + platform_driver_unregister(&max77693_haptic_driver); +} +module_exit(max77693_haptic_exit); + +MODULE_AUTHOR("ByungChang Cha "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MAX77693 haptic driver"); diff --git a/drivers/motor/tspdrv.c b/drivers/motor/tspdrv.c new file mode 100644 index 00000000000..1b42c73858b --- /dev/null +++ b/drivers/motor/tspdrv.c @@ -0,0 +1,746 @@ +/* +** ========================================================================= +** File: +** tspdrv.c +** +** Description: +** TouchSense Kernel Module main entry-point. +** +** Portions Copyright (c) 2008-2010 Immersion Corporation. All Rights Reserved. +** +** This file contains Original Code and/or Modifications of Original Code +** as defined in and that are subject to the GNU Public License v2 - +** (the 'License'). You may not use this file except in compliance with the +** License. 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 or contact +** TouchSenseSales@immersion.com. +** +** The Original Code and all software distributed under the License are +** distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +** EXPRESS OR IMPLIED, AND IMMERSION HEREBY DISCLAIMS ALL SUCH WARRANTIES, +** INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +** FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see +** the License for the specific language governing rights and limitations +** under the License. +** ========================================================================= +*/ + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../staging/android/timed_output.h" + +#include "tspdrv.h" +#include +#include "immvibespi.c" + +#if defined(VIBE_DEBUG) && defined(VIBE_RECORD) +#include +#endif + +/* Device name and version information */ +/* DO NOT CHANGE - this is auto-generated */ +#define VERSION_STR " v3.4.55.7\n" +/* account extra space for future extra digits in version number */ +#define VERSION_STR_LEN 16 +/* initialized in tspdrv_probe */ +static char g_szdevice_name[(VIBE_MAX_DEVICE_NAME_LENGTH + + VERSION_STR_LEN) + * NUM_ACTUATORS]; +static size_t g_cchdevice_name; + +extern unsigned int system_rev; + +static struct wake_lock vib_wake_lock; + +/* Flag indicating whether the driver is in use */ +static char g_bisplaying; + +/* Buffer to store data sent to SPI */ +#define SPI_BUFFER_SIZE \ + (NUM_ACTUATORS * (VIBE_OUTPUT_SAMPLE_SIZE + SPI_HEADER_SIZE)) +static int g_bstoprequested; +static actuator_samples_buffer g_samples_buffer[NUM_ACTUATORS] = {{0} }; +static char g_cwrite_buffer[SPI_BUFFER_SIZE]; + +#define VIBE_TUNING +/* #define VIBE_ENABLE_SYSTEM_TIMER */ + +/* For QA purposes */ +#ifdef QA_TEST +#define FORCE_LOG_BUFFER_SIZE 128 +#define TIME_INCREMENT 5 +static int g_ntime; +static int g_nforcelog_index; +static int8_t g_nforcelog[FORCE_LOG_BUFFER_SIZE]; +#endif + +#ifdef IMPLEMENT_AS_CHAR_DRIVER +static int g_nmajor; +#endif + +/* Needs to be included after the global variables because it uses them */ +#ifdef CONFIG_HIGH_RES_TIMERS + #include "VibeOSKernelLinuxHRTime.c" +#else + #include "VibeOSKernelLinuxTime.c" +#endif + +/* timed_output */ +static void _set_vibetonz_work(struct work_struct *unused); + +static DECLARE_WORK(vibetonz_work, _set_vibetonz_work); + + +static struct hrtimer timer; +static int max_timeout = 10000; + +static int vibrator_value = -1; +static int vibrator_work; + +#define TEST_MODE_TIME 10000 + +struct vibrator_platform_data vibrator_drvdata; + +static int set_vibetonz(int timeout) +{ + int8_t strength; + if (!timeout) { + if (vibrator_drvdata.vib_model == HAPTIC_PWM) { + strength = 0; + ImmVibeSPI_ForceOut_SetSamples(0, 8, 1, &strength); + } else { /* HAPTIC_MOTOR */ + ImmVibeSPI_ForceOut_AmpDisable(0); + } + } else { + if (vibrator_drvdata.vib_model == HAPTIC_PWM) { + strength = 120; + /* 90% duty cycle */ + ImmVibeSPI_ForceOut_SetSamples(0, 8, 1, &strength); + } else { /* HAPTIC_MOTOR */ + ImmVibeSPI_ForceOut_AmpEnable(0); + } + } + + vibrator_value = timeout; + return 0; +} + +static void _set_vibetonz_work(struct work_struct *unused) +{ + set_vibetonz(vibrator_work); + + return; +} + +static enum hrtimer_restart vibetonz_timer_func(struct hrtimer *timer) +{ + /* set_vibetonz(0); */ + vibrator_work = 0; + schedule_work(&vibetonz_work); + + return HRTIMER_NORESTART; +} + +static int get_time_for_vibetonz(struct timed_output_dev *dev) +{ + int remaining; + + if (hrtimer_active(&timer)) { + ktime_t r = hrtimer_get_remaining(&timer); + remaining = ktime_to_ms(r);/*returning time in ms*/ + } else { + remaining = 0; + } + + if (vibrator_value == -1) + remaining = -1; + + return remaining; + +} + +static void enable_vibetonz_from_user(struct timed_output_dev *dev, int value) +{ + hrtimer_cancel(&timer); + + /* set_vibetonz(value); */ + vibrator_work = value; + schedule_work(&vibetonz_work); + + if (value > 0) { + if (value > max_timeout) + value = max_timeout; + + hrtimer_start(&timer, + ktime_set(value / 1000, (value % 1000) * 1000000), + HRTIMER_MODE_REL); + vibrator_value = 0; + } +} + +static struct timed_output_dev timed_output_vt = { + .name = "vibrator", + .get_time = get_time_for_vibetonz, + .enable = enable_vibetonz_from_user, +}; + +static void vibetonz_start(void) +{ + int ret = 0; + + hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + timer.function = vibetonz_timer_func; + + ret = timed_output_dev_register(&timed_output_vt); + + if (ret) + DbgOut((KERN_ERR + "tspdrv: timed_output_dev_register is fail\n")); +} + +/* File IO */ +static int open(struct inode *inode, struct file *file); +static int release(struct inode *inode, struct file *file); +static ssize_t read(struct file *file, char *buf, size_t count, loff_t *ppos); +static ssize_t write(struct file *file, const char *buf, size_t count, + loff_t *ppos); +#if HAVE_UNLOCKED_IOCTL +static long ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#endif +static const struct file_operations fops = { + .owner = THIS_MODULE, + .read = read, + .write = write, + .unlocked_ioctl = ioctl, + .open = open, + .release = release , + .llseek = default_llseek +}; + +#ifndef IMPLEMENT_AS_CHAR_DRIVER +static struct miscdevice miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = MODULE_NAME, + .fops = &fops +}; +#endif + +#ifdef VIBE_ENABLE_SYSTEM_TIMER +int vibetonz_clk_on(struct device *dev) +{ + struct clk *vibetonz_clk = NULL; + + vibetonz_clk = clk_get(dev, "timers"); + if (IS_ERR(vibetonz_clk)) { + DbgOut((KERN_ERR "tspdrv: failed to get clock for vibetonz\n")); + goto err_clk0; + } + clk_enable(vibetonz_clk); + clk_put(vibetonz_clk); + + return 0; + +err_clk0: + clk_put(vibetonz_clk); + return -EINVAL; +} + +int vibetonz_clk_off(struct device *dev) +{ + struct clk *vibetonz_clk = NULL; + + vibetonz_clk = clk_get(dev, "timers"); + if (IS_ERR(vibetonz_clk)) { + DbgOut((KERN_ERR "tspdrv: failed to get clock for vibetonz\n")); + goto err_clk0; + } + clk_disable(vibetonz_clk); + clk_put(vibetonz_clk); + + return 0; + +err_clk0: + clk_put(vibetonz_clk); + + return -EINVAL; +} +#else +int vibetonz_clk_on(struct device *dev) +{ + return -EINVAL; +} + +int vibetonz_clk_off(struct device *dev) +{ + return -EINVAL; +} +#endif /* VIBE_ENABLE_SYSTEM_TIMER */ + +static __devinit int tspdrv_probe(struct platform_device *pdev) +{ + struct vibrator_platform_data *pdata; + int ret, i; /* initialized below */ + + DbgOut((KERN_INFO "tspdrv: tspdrv_probe.\n")); + + /* This condition will be removed,after all board files changes done */ + if (pdev->dev.platform_data == NULL) { + vibrator_drvdata.is_pmic_vib_en = 0; +#if defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_VZW) || \ +defined(CONFIG_MACH_M2_SPR) || defined(CONFIG_MACH_M2_DCM) || \ +defined(CONFIG_MACH_M2_SKT) || defined(CONFIG_MACH_JAGUAR) || \ +defined(CONFIG_MACH_AEGIS2) || defined(CONFIG_MACH_COMANCHE) + vibrator_drvdata.vib_pwm_gpio = GPIO_VIB_PWM; + vibrator_drvdata.vib_en_gpio = GPIO_VIB_ON; + vibrator_drvdata.haptic_pwr_en_gpio = GPIO_HAPTIC_PWR_EN; + vibrator_drvdata.vib_model = HAPTIC_PWM; +#endif +#if defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_JASPER) || \ +defined(CONFIG_MACH_GOGH) || defined(CONFIG_MACH_ESPRESSO_ATT) + vibrator_drvdata.vib_pwm_gpio = GPIO_MOTOR_EN; + vibrator_drvdata.vib_en_gpio = GPIO_MOTOR_EN; + vibrator_drvdata.haptic_pwr_en_gpio = GPIO_MOTOR_EN; + vibrator_drvdata.vib_model = HAPTIC_MOTOR; +#endif +#ifdef CONFIG_MACH_M2_ATT + if (system_rev >= BOARD_REV04) { + vibrator_drvdata.vib_en_gpio = PM8921_GPIO_PM_TO_SYS(\ + PMIC_GPIO_VIB_ON); + vibrator_drvdata.is_pmic_vib_en = 1; + } + if (system_rev >= BOARD_REV08) { + vibrator_drvdata.haptic_pwr_en_gpio = PM8921_GPIO_PM_TO_SYS(\ + PMIC_GPIO_HAPTIC_PWR_EN); + vibrator_drvdata.is_pmic_haptic_pwr_en = 1; + } +#endif +#ifdef CONFIG_MACH_M2_VZW + if (system_rev >= BOARD_REV09) { + vibrator_drvdata.vib_en_gpio = PM8921_GPIO_PM_TO_SYS(\ + PMIC_GPIO_VIB_ON); + vibrator_drvdata.is_pmic_vib_en = 1; + } +#endif +#ifdef CONFIG_MACH_M2_SPR + if (system_rev >= BOARD_REV03) { + vibrator_drvdata.vib_en_gpio = PM8921_GPIO_PM_TO_SYS(\ + PMIC_GPIO_VIB_ON); + vibrator_drvdata.is_pmic_vib_en = 1; + } +#endif +#ifdef CONFIG_MACH_M2_DCM + if (system_rev >= BOARD_REV01) { + vibrator_drvdata.vib_en_gpio = PM8921_GPIO_PM_TO_SYS(\ + PMIC_GPIO_VIB_ON); + vibrator_drvdata.is_pmic_vib_en = 1; + } +#endif +#ifdef CONFIG_MACH_AEGIS2 + if (system_rev >= BOARD_REV01) { + vibrator_drvdata.vib_en_gpio = PM8921_GPIO_PM_TO_SYS(\ + PMIC_GPIO_VIB_ON); + vibrator_drvdata.is_pmic_vib_en = 1; + } +#endif + } else { + pdata = pdev->dev.platform_data; + vibrator_drvdata.vib_model = pdata->vib_model; + vibrator_drvdata.is_pmic_haptic_pwr_en = \ + pdata->is_pmic_haptic_pwr_en; + if (pdata->is_pmic_haptic_pwr_en) + vibrator_drvdata.haptic_pwr_en_gpio = \ + PM8921_GPIO_PM_TO_SYS(pdata->haptic_pwr_en_gpio); + else + vibrator_drvdata.haptic_pwr_en_gpio = \ + pdata->haptic_pwr_en_gpio; + if (pdata->vib_model == HAPTIC_PWM) { + vibrator_drvdata.vib_pwm_gpio = pdata->vib_pwm_gpio; + vibrator_drvdata.is_pmic_vib_en = \ + pdata->is_pmic_vib_en; + if (pdata->is_pmic_vib_en) + vibrator_drvdata.vib_en_gpio = \ + PM8921_GPIO_PM_TO_SYS(pdata->vib_en_gpio); + else + vibrator_drvdata.vib_en_gpio = \ + pdata->vib_en_gpio; + } + } +#ifdef IMPLEMENT_AS_CHAR_DRIVER + g_nmajor = register_chrdev(0, MODULE_NAME, &fops); + if (g_nmajor < 0) { + DbgOut((KERN_ERR "tspdrv: can't get major number.\n")); + ret = g_nmajor; + goto register_err; + } +#else + ret = misc_register(&miscdev); + if (ret) { + DbgOut((KERN_ERR "tspdrv: misc_register failed.\n")); + goto register_err; + } +#endif + + DbgRecorderInit(()); + + vibetonz_clk_on(&pdev->dev); + + ImmVibeSPI_ForceOut_Initialize(); + VibeOSKernelLinuxInitTimer(); + + /* Get and concatenate device name and initialize data buffer */ + g_cchdevice_name = 0; + for (i = 0; i < NUM_ACTUATORS; i++) { + char *szName = g_szdevice_name + g_cchdevice_name; + ImmVibeSPI_Device_GetName(i, + szName, VIBE_MAX_DEVICE_NAME_LENGTH); + + /* Append version information and get buffer length */ + strncat(szName, VERSION_STR, sizeof(VERSION_STR)); + g_cchdevice_name += strnlen(szName, sizeof(szName)); + + g_samples_buffer[i].nindex_playing_buffer = -1;/* Not playing */ + g_samples_buffer[i].actuator_samples[0].nbuffer_size = 0; + g_samples_buffer[i].actuator_samples[1].nbuffer_size = 0; + } + wake_lock_init(&vib_wake_lock, WAKE_LOCK_SUSPEND, "vib_present"); + + vibetonz_start(); + + return 0; + +register_err: +#ifdef IMPLEMENT_AS_CHAR_DRIVER + unregister_chrdev(g_nmajor, MODULE_NAME); +#else + misc_deregister(&miscdev); +#endif + + return ret; +} + +static int __devexit tspdrv_remove(struct platform_device *pdev) +{ + DbgOut((KERN_INFO "tspdrv: tspdrv_remove.\n")); + + DbgRecorderTerminate(()); + + VibeOSKernelLinuxTerminateTimer(); + ImmVibeSPI_ForceOut_Terminate(); + + wake_lock_destroy(&vib_wake_lock); + + return 0; +} + +static int open(struct inode *inode, struct file *file) +{ + DbgOut((KERN_INFO "tspdrv: open.\n")); + + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + return 0; +} + +static int release(struct inode *inode, struct file *file) +{ + DbgOut((KERN_INFO "tspdrv: release.\n")); + + /* + ** Reset force and stop timer when the driver is closed, to make sure + ** no dangling semaphore remains in the system, especially when the + ** driver is run outside of immvibed for testing purposes. + */ + VibeOSKernelLinuxStopTimer(); + + /* + ** Clear the variable used to store the magic number to prevent + ** unauthorized caller to write data. TouchSense service is the only + ** valid caller. + */ + file->private_data = (void *)NULL; + + module_put(THIS_MODULE); + + return 0; +} + +static ssize_t read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + const size_t nbufsize = + (g_cchdevice_name > (size_t)(*ppos)) ? + min(count, g_cchdevice_name - (size_t)(*ppos)) : 0; + + /* End of buffer, exit */ + if (0 == nbufsize) + return 0; + + if (0 != copy_to_user(buf, g_szdevice_name + (*ppos), nbufsize)) { + /* Failed to copy all the data, exit */ + DbgOut((KERN_ERR "tspdrv: copy_to_user failed.\n")); + return 0; + } + + /* Update file position and return copied buffer size */ + *ppos += nbufsize; + return nbufsize; +} + +static ssize_t write(struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + int i = 0; + + *ppos = 0; /* file position not used, always set to 0 */ + /* DbgOut((KERN_ERR "tspdrv: write....\n")); */ + + /* + ** Prevent unauthorized caller to write data. + ** TouchSense service is the only valid caller. + */ + if (file->private_data != (void *)TSPDRV_MAGIC_NUMBER) { + DbgOut((KERN_ERR "tspdrv: unauthorized write.\n")); + return 0; + } + + /* Copy immediately the input buffer */ + if (0 != copy_from_user(g_cwrite_buffer, buf, count)) { + /* Failed to copy all the data, exit */ + DbgOut((KERN_ERR "tspdrv: copy_from_user failed.\n")); + return 0; + } + + /* Check buffer size */ + if ((count <= SPI_HEADER_SIZE) || (count > SPI_BUFFER_SIZE)) { + DbgOut((KERN_ERR "tspdrv: invalid write buffer size.\n")); + return 0; + } + + while (i < count) { + int nindex_free_buffer; /* initialized below */ + + samples_buffer *pinput_buffer = + (samples_buffer *)(&g_cwrite_buffer[i]); + + if ((i + SPI_HEADER_SIZE) >= count) { + /* + ** Index is about to go beyond the buffer size. + ** (Should never happen). + */ + DbgOut((KERN_EMERG "tspdrv: invalid buffer index.\n")); + } + + /* Check bit depth */ + if (8 != pinput_buffer->nbit_depth) + DbgOut((KERN_WARNING + "tspdrv: invalid bit depth.Use default value(8).\n")); + + /* The above code not valid if SPI header size is not 3 */ +#if (SPI_HEADER_SIZE != 3) +#error "SPI_HEADER_SIZE expected to be 3" +#endif + + /* Check buffer size */ + if ((i + SPI_HEADER_SIZE + pinput_buffer->nbuffer_size) + > count) { + /* + ** Index is about to go beyond the buffer size. + ** (Should never happen). + */ + DbgOut((KERN_EMERG "tspdrv: invalid data size.\n")); + } + + /* Check actuator index */ + if (NUM_ACTUATORS <= pinput_buffer->nactuator_index) { + DbgOut((KERN_ERR "tspdrv: invalid actuator index.\n")); + i += (SPI_HEADER_SIZE + pinput_buffer->nbuffer_size); + continue; + } + + if (0 == g_samples_buffer[pinput_buffer->nactuator_index] + .actuator_samples[0].nbuffer_size) { + nindex_free_buffer = 0; + } else if (0 == g_samples_buffer[pinput_buffer->nactuator_index] + .actuator_samples[1].nbuffer_size) { + nindex_free_buffer = 1; + } else { + /* No room to store new samples */ + DbgOut((KERN_ERR + "tspdrv: no room to store new samples.\n")); + return 0; + } + + /* Store the data in the free buffer of the given actuator */ + memcpy( + &(g_samples_buffer[pinput_buffer->nactuator_index] + .actuator_samples[nindex_free_buffer]), + &g_cwrite_buffer[i], + (SPI_HEADER_SIZE + pinput_buffer->nbuffer_size)); + + /* If the no buffer is playing, prepare to play + ** g_samples_buffer[pinput_buffer->nactuator_index]. + ** actuator_samples[nindex_free_buffer] + */ + if (-1 == g_samples_buffer[pinput_buffer->nactuator_index] + .nindex_playing_buffer) { + g_samples_buffer[pinput_buffer->nactuator_index] + .nindex_playing_buffer = nindex_free_buffer; + g_samples_buffer[pinput_buffer->nactuator_index] + .nindex_output_value = 0; + } + + /* Increment buffer index */ + i += (SPI_HEADER_SIZE + pinput_buffer->nbuffer_size); + } + +#ifdef QA_TEST + g_nforcelog[g_nforcelog_index++] = g_cSPIBuffer[0]; + if (g_nforcelog_index >= FORCE_LOG_BUFFER_SIZE) { + for (i = 0; i < FORCE_LOG_BUFFER_SIZE; i++) { + printk(KERN_INFO "%d\t%d\n", g_ntime, g_nforcelog[i]); + g_ntime += TIME_INCREMENT; + } + g_nforcelog_index = 0; + } +#endif + + /* Start the timer after receiving new output force */ + g_bisplaying = true; + VibeOSKernelLinuxStartTimer(); + + return count; +} + +static long ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ +#ifdef QA_TEST + int i; +#endif + + /* DbgOut(KERN_INFO "tspdrv: ioctl cmd[0x%x].\n", cmd); */ + switch (cmd) { + case TSPDRV_STOP_KERNEL_TIMER: + /* + ** As we send one sample ahead of time, we need to finish + ** playing the last sample before stopping the timer. + ** So we just set a flag here. + */ + if (true == g_bisplaying) + g_bstoprequested = true; + +#ifdef VIBEOSKERNELPROCESSDATA + /* Last data processing to disable amp and stop timer */ + VibeOSKernelProcessData(NULL); +#endif + +#ifdef QA_TEST + if (g_nforcelog_index) { + for (i = 0; i < g_nforcelog_index; i++) { + printk(KERN_INFO "%d\t%d\n" + , g_ntime, g_nforcelog[i]); + g_ntime += TIME_INCREMENT; + } + } + g_ntime = 0; + g_nforcelog_index = 0; +#endif + break; + + case TSPDRV_MAGIC_NUMBER: + filp->private_data = (void *)TSPDRV_MAGIC_NUMBER; + break; + + case TSPDRV_ENABLE_AMP: + wake_lock(&vib_wake_lock); + ImmVibeSPI_ForceOut_AmpEnable(arg); + DbgRecorderReset((arg)); + DbgRecord((arg, ";------- TSPDRV_ENABLE_AMP ---------\n")); + break; + + case TSPDRV_DISABLE_AMP: + /* + ** Small fix for now to handle proper combination of + ** TSPDRV_STOP_KERNEL_TIMER and TSPDRV_DISABLE_AMP together + ** If a stop was requested, ignore the request as the amp + ** will be disabled by the timer proc when it's ready + */ + if (!g_bstoprequested) + ImmVibeSPI_ForceOut_AmpDisable(arg); + wake_unlock(&vib_wake_lock); + break; + + case TSPDRV_GET_NUM_ACTUATORS: + return NUM_ACTUATORS; + } + + return 0; +} + +static int suspend(struct platform_device *pdev, pm_message_t state) +{ + int ret; + + if (g_bisplaying) { + ret = -EBUSY; + } else { + /* Disable system timers */ + vibetonz_clk_off(&pdev->dev); + + ret = 0; + } + DbgOut(KERN_DEBUG "tspdrv: %s (%d).\n", __func__, ret); + return ret; +} + +static int resume(struct platform_device *pdev) +{ + /* Restart system timers */ + DbgOut(KERN_DEBUG "tspdrv: %s.\n", __func__); + return 0; +} + +static struct platform_driver tspdrv_driver = { + .probe = tspdrv_probe, + .remove = __devexit_p(tspdrv_remove), + .suspend = suspend, + .resume = resume, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init tspdrv_init(void) +{ + return platform_driver_register(&tspdrv_driver); +} + +static void __exit tspdrv_exit(void) +{ + platform_driver_unregister(&tspdrv_driver); +} + +late_initcall(tspdrv_init); +module_exit(tspdrv_exit); + +/* Module info */ +MODULE_AUTHOR("Immersion Corporation"); +MODULE_DESCRIPTION("TouchSense Kernel Module"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/motor/tspdrv.h b/drivers/motor/tspdrv.h new file mode 100644 index 00000000000..8fcdcdd32a1 --- /dev/null +++ b/drivers/motor/tspdrv.h @@ -0,0 +1,224 @@ +/* +** ========================================================================= +** File: +** tspdrv.h +** +** Description: +** Constants and type definitions for the TouchSense Kernel Module. +** +** Portions Copyright (c) 2008-2010 Immersion Corporation. All Rights Reserved. +** +** This file contains Original Code and/or Modifications of Original Code +** as defined in and that are subject to the GNU Public License v2 - +** (the 'License'). You may not use this file except in compliance with the +** License. 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 or contact +** TouchSenseSales@immersion.com. +** +** The Original Code and all software distributed under the License are +** distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +** EXPRESS OR IMPLIED, AND IMMERSION HEREBY DISCLAIMS ALL SUCH WARRANTIES, +** INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +** FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see +** the License for the specific language governing rights and limitations +** under the License. +** ========================================================================= +*/ + +#ifndef _TSPDRV_H +#define _TSPDRV_H +#define VIBE_DEBUG +#include +#include +#include + +#define PM8921_GPIO_BASE NR_GPIO_IRQS +#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE) + +extern struct vibrator_platform_data vibrator_drvdata; + +/* Constants */ +#define MODULE_NAME "tspdrv" +#define TSPDRV "/dev/"MODULE_NAME +#define TSPDRV_MAGIC_NUMBER 0x494D4D52 +#define TSPDRV_STOP_KERNEL_TIMER _IO(TSPDRV_MAGIC_NUMBER & 0xFF, 1) +/* +** Obsolete IOCTL command +** #define TSPDRV_IDENTIFY_CALLER _IO(TSPDRV_MAGIC_NUMBER & 0xFF, 2) +*/ +#define TSPDRV_ENABLE_AMP _IO(TSPDRV_MAGIC_NUMBER & 0xFF, 3) +#define TSPDRV_DISABLE_AMP _IO(TSPDRV_MAGIC_NUMBER & 0xFF, 4) +#define TSPDRV_GET_NUM_ACTUATORS _IO(TSPDRV_MAGIC_NUMBER & 0xFF, 5) +#define VIBE_MAX_DEVICE_NAME_LENGTH 64 +#define SPI_HEADER_SIZE 3 /* DO NOT CHANGE - SPI buffer header size */ + /* DO NOT CHANGE - maximum number of samples */ +#define VIBE_OUTPUT_SAMPLE_SIZE 50 + +/* Type definitions */ +#ifdef __KERNEL__ +typedef struct { + u_int8_t nactuator_index; /* 1st byte is actuator index */ + u_int8_t nbit_depth; /* 2nd byte is bit depth */ + u_int8_t nbuffer_size; /* 3rd byte is data size */ + u_int8_t data_buffer[VIBE_OUTPUT_SAMPLE_SIZE]; +} samples_buffer; + +typedef struct { + int8_t nindex_playing_buffer; + u_int8_t nindex_output_value; + /* Use 2 buffers to receive samples from user mode */ + samples_buffer actuator_samples[2]; +} actuator_samples_buffer; + +#endif + +/* Error and Return value codes */ +#define VIBE_S_SUCCESS 0 /* Success */ +#define VIBE_E_FAIL -4 /* Generic error */ + +#if defined(VIBE_RECORD) && defined(VIBE_DEBUG) + void _RecorderInit(void); + void _RecorderTerminate(void); + void _RecorderReset(int nActuator); + void _Record(int actuatorIndex, const char *format, ...); +#endif +#define VIBRATION_ON 1 +#define VIBRATION_OFF 0 + +/* GPIO definitions */ +#define VIB_PWM 70 +#define HAPTIC_PWR_EN 47 +#if defined(CONFIG_MACH_M2_DCM) +#define VIB_EN 65 +#else +#define VIB_EN 77 +#endif +#define PMIC_GPIO_VIB_ON 4 + +int32_t g_nforce_32; + +#define GP_CLK_M_DEFAULT 1 + + +#if defined(CONFIG_MACH_JAGUAR) +#define GP_CLK_N_DEFAULT 211/*About 177hz*/ +#elif defined(CONFIG_MACH_AEGIS2) +#define GP_CLK_N_DEFAULT 184/*About 204 Hz*/ +#else +#define GP_CLK_N_DEFAULT 183/*About 205 Hz*/ +#endif +#define GP_CLK_D_DEFAULT 91/* 50% duty cycle */ +#define IMM_PWM_MULTIPLIER 181/* Must be integer */ + +/* + * ** Global variables for LRA PWM M,N and D values. + * */ +int32_t g_nlra_gp_clk_m = GP_CLK_M_DEFAULT; +int32_t g_nlra_gp_clk_n = GP_CLK_N_DEFAULT; +int32_t g_nlra_gp_clk_d = GP_CLK_D_DEFAULT; +int32_t g_nlra_gp_clk_pwm_mul = IMM_PWM_MULTIPLIER; + +#define __inp(port) ioread8(port) + +#define __inpw(port) ioread16(port) + +#define __inpdw(port) ioread32(port) + +#define __outp(port, val) iowrite8(val, port) + +#define __outpw(port, val) iowrite16(val, port) + +#define __outpdw(port, val) iowrite32(val, port) + + +#define in_dword(addr) (__inpdw(addr)) +#define in_dword_masked(addr, mask) (__inpdw(addr) & (mask)) +#define out_dword(addr, val) __outpdw(addr, val) +#define out_dword_masked(io, mask, val, shadow) \ + (void) out_dword(io, \ + ((shadow & (unsigned int)(~(mask))) | ((unsigned int)((val) & (mask))))) +#define out_dword_masked_ns(io, mask, val, current_reg_content) \ + (void) out_dword(io, \ + ((current_reg_content & (unsigned int)(~(mask))) \ + | ((unsigned int)((val) & (mask))))) + +#define HWIO_GP_MD_REG_ADDR (MSM_CLK_CTL_BASE + 0x00002D00 + 32) +#define HWIO_GP_MD_REG_PHYS (MSM_CLK_CTL_PHYS + 0x00002D00 + 32) +#define HWIO_GP_MD_REG_RMSK 0xffffffff +#define HWIO_GP_MD_REG_SHFT 0 +#define HWIO_GP_MD_REG_IN \ + in_dword_masked(HWIO_GP_MD_REG_ADDR, HWIO_GP_MD_REG_RMSK) +#define HWIO_GP_MD_REG_INM(m) \ + in_dword_masked(HWIO_GP_MD_REG_ADDR, m) +#define HWIO_GP_MD_REG_OUT(v) \ + out_dword(HWIO_GP_MD_REG_ADDR, v) +#define HWIO_GP_MD_REG_OUTM(m, v)\ + out_dword_masked_ns(HWIO_GP_MD_REG_ADDR, m, v, HWIO_GP_MD_REG_IN) + +#define HWIO_GP_MD_REG_M_VAL_BMSK 0x00ff0000 +#define HWIO_GP_MD_REG_M_VAL_SHFT 0x10 +#define HWIO_GP_MD_REG_D_VAL_BMSK 0x00ff +#define HWIO_GP_MD_REG_D_VAL_SHFT 0 + +#define HWIO_GP_NS_REG_ADDR (MSM_CLK_CTL_BASE + 0x00002D24 + 32) +#define HWIO_GP_NS_REG_PHYS (MSM_CLK_CTL_PHYS + 0x00002D24 + 32) +#define HWIO_GP_NS_REG_RMSK 0xffffffff +#define HWIO_GP_NS_REG_SHFT 0 +#define HWIO_GP_NS_REG_IN \ + in_dword_masked(HWIO_GP_NS_REG_ADDR, HWIO_GP_NS_REG_RMSK) +#define HWIO_GP_NS_REG_INM(m) \ + in_dword_masked(HWIO_GP_NS_REG_ADDR, m) +#define HWIO_GP_NS_REG_OUT(v) \ + out_dword(HWIO_GP_NS_REG_ADDR, v) +#define HWIO_GP_NS_REG_OUTM(m, v) \ + out_dword_masked_ns(HWIO_GP_NS_REG_ADDR, m, v, HWIO_GP_NS_REG_IN) +#define HWIO_GP_NS_REG_GP_N_VAL_BMSK 0x00ff0000 +#define HWIO_GP_NS_REG_GP_N_VAL_SHFT 0x10 +#define HWIO_GP_NS_REG_GP_ROOT_ENA_BMSK 0x800 +#define HWIO_GP_NS_REG_GP_ROOT_ENA_SHFT 0xb +#define HWIO_GP_NS_REG_GP_CLK_INV_BMSK 0x400 +#define HWIO_GP_NS_REG_GP_CLK_INV_SHFT 0xa +#define HWIO_GP_NS_REG_GP_CLK_BRANCH_ENA_BMSK 0x200 +#define HWIO_GP_NS_REG_GP_CLK_BRANCH_ENA_SHFT 0x9 +#define HWIO_GP_NS_REG_MNCNTR_EN_BMSK 0x100 +#define HWIO_GP_NS_REG_MNCNTR_EN_SHFT 0x8 +#define HWIO_GP_NS_REG_MNCNTR_RST_BMSK 0x80 +#define HWIO_GP_NS_REG_MNCNTR_RST_SHFT 0x7 +#define HWIO_GP_NS_REG_MNCNTR_MODE_BMSK 0x60 +#define HWIO_GP_NS_REG_MNCNTR_MODE_SHFT 0x5 +#define HWIO_GP_NS_REG_PRE_DIV_SEL_BMSK 0x18 +#define HWIO_GP_NS_REG_PRE_DIV_SEL_SHFT 0x3 +#define HWIO_GP_NS_REG_SRC_SEL_BMSK 0x7 +#define HWIO_GP_NS_REG_SRC_SEL_SHFT 0 + +#define __msmhwio_outm(hwiosym, mask, val) HWIO_##hwiosym##_OUTM(mask, val) +#define HWIO_OUTM(hwiosym, mask, val) __msmhwio_outm(hwiosym, mask, val) + +/* Kernel Debug Macros */ +#ifdef __KERNEL__ + #ifdef VIBE_DEBUG + #define DbgOut(_x_, ...) printk(_x_, ##__VA_ARGS__) + #else /* VIBE_DEBUG */ + #define DbgOut(_x_) + #endif /* VIBE_DEBUG */ + + #if defined(VIBE_RECORD) && defined(VIBE_DEBUG) + #define DbgRecorderInit(_x_) _RecorderInit _x_ + #define DbgRecorderTerminate(_x_) _RecorderTerminate _x_ + #define DbgRecorderReset(_x_) _RecorderReset _x_ + #define DbgRecord(_x_) _Record _x_ + #else /* defined(VIBE_RECORD) && defined(VIBE_DEBUG) */ + #define DbgRecorderInit(_x_) + #define DbgRecorderTerminate(_x_) + #define DbgRecorderReset(_x_) + #define DbgRecord(_x_) + #endif /* defined(VIBE_RECORD) && defined(VIBE_DEBUG) */ +#endif /* __KERNEL__ */ + +#if defined(CONFIG_MOTOR_DRV_MAX77693) +extern void max77693_vibtonz_en(bool en); +#endif + +#endif /* _TSPDRV_H */ + diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 9392311b7ed..7aecbc39730 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -61,6 +61,9 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/ obj-$(CONFIG_BCMDHD) += bcmdhd/ +obj-$(CONFIG_BCM4334) += bcmdhd/ +obj-$(CONFIG_BCM4334) += btlock/ + obj-$(CONFIG_BRCMFMAC) += brcm80211/ obj-$(CONFIG_BRCMSMAC) += brcm80211/ diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig index 231ae187f40..3d06eeb3c0d 100644 --- a/drivers/net/wireless/bcmdhd/Kconfig +++ b/drivers/net/wireless/bcmdhd/Kconfig @@ -1,14 +1,37 @@ config BCMDHD - tristate "Broadcom 4329/30 wireless cards support" - depends on MMC + tristate "Broadcom 43xx wireless cards support" + depends on MMC + default m + ---help--- + This module adds support for wireless adapters based on + Broadcom 4329/30 chipset. + + This driver uses the kernel's wireless extensions subsystem. + + If you choose to build a module, it'll be called dhd. Say M if + unsure. + +config BCM4330 + bool "Broadcom 4330 wireless cards support" + depends on BCMDHD ---help--- This module adds support for wireless adapters based on - Broadcom 4329/30 chipset. + Broadcom 4330 chipset. - This driver uses the kernel's wireless extensions subsystem. +config BCM4334 + bool "Broadcom 4334 wireless cards support" + depends on BCMDHD + default y + ---help--- + This module adds support for wireless adapters based on + Broadcom 4334 chipset. - If you choose to build a module, it'll be called dhd. Say M if - unsure. +config BCM43241 + bool "Broadcom 43241 wireless cards support" + depends on BCMDHD + ---help--- + This module adds support for wireless adapters based on + Broadcom 43241 chipset. config BCMDHD_FW_PATH depends on BCMDHD @@ -45,3 +68,23 @@ config DHD_USE_SCHED_SCAN default n ---help--- Use CFG80211 sched scan + +config BROADCOM_WIFI_RESERVED_MEM + bool "BROADCOM Reserved memory for wifi device" + depends on (BCM4330 || BCM4334 || BCM43241) + ---help--- + This is a configuration for broadcom WLAN driver. + +config WLAN_REGION_CODE + int "---Region codes for Broadcom WiFi Driver" + depends on (BCM4330 || BCM4334 || BCM43241) + default 100 + ---help--- + This is a region code for Broadcom Wi-Fi featured functions. + - 100 : EUR OPEN + - 101 : EUR ORG + - 200 : KOR OPEN + - 201 : KOR SKT + - 202 : KOR KTT + - 203 : KOR LGT + - 300 : CHN OPEN diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index 7925661ce62..5acd2b0eeec 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -1,39 +1,217 @@ # bcmdhd -# -DDHDTHREAD -DDHD_GPL -DDHD_SCHED -DDHD_DEBUG -DSDTEST -DBDC -DTOE \ -# -DDHD_BCMEVENTS -DSHOW_EVENTS -DDONGLEOVERLAYS -DBCMDBG \ -# -DCUSTOMER_HW2 -DOOB_INTR_ONLY -DHW_OOB \ -# -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \ -# -DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ -# -DKEEP_ALIVE -DCSCAN -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \ -# -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \ - -DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DDHD_DEBUG -DSDTEST -DBDC -DTOE \ - -DDHD_BCMEVENTS -DSHOW_EVENTS -DPROP_TXSTATUS -DBCMDBG \ - -DCUSTOMER_HW2 -DOOB_INTR_ONLY -DHW_OOB \ - -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ - -DKEEP_ALIVE -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \ - -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \ - -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include - -DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ - dhd_linux_sched.o dhd_sdio.o bcmwifi_channels.o bcmevent.o hndpmu.o \ - bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \ - bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o - -obj-$(CONFIG_BCMDHD) += bcmdhd.o -bcmdhd-objs += $(DHDOFILES) -ifneq ($(CONFIG_WIRELESS_EXT),) -bcmdhd-objs += wl_iw.o -DHDCFLAGS += -DSOFTAP -DUSE_IW -endif -ifneq ($(CONFIG_CFG80211),) -bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_cfg80211.o -DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF -endif -EXTRA_CFLAGS = $(DHDCFLAGS) -ifeq ($(CONFIG_BCMDHD),m) +##################### +# SDIO Basic feature +##################### + +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ + -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ + -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ + -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ + -DEMBEDDED_PLATFORM -DPNO_SUPPORT + +################# +# Common feature +################# + +DHDCFLAGS += -DCUSTOMER_HW4 +DHDCFLAGS += -DBLOCK_IPV6_PACKET -DPASS_IPV4_SUSPEND +DHDCFLAGS += -DSUPPORT_DEEP_SLEEP +DHDCFLAGS += -DSIMPLE_MAC_PRINT + +# For p2p connection issue +DHDCFLAGS += -DWL_CFG80211_GON_COLLISION +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 + +# For Passing all multicast packets to host when not in suspend mode. +DHDCFLAGS += -DPASS_ALL_MCAST_PKTS + +# Early suspend +DHDCFLAGS += -DDHD_USE_EARLYSUSPEND + +DHDCFLAGS += -DSUPPORT_PM2_ONLY + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER + +DHDCFLAGS += -DROAM_ENABLE -DROAM_CHANNEL_CACHE -DROAM_API +DHDCFLAGS += -DDISABLE_FW_ROAM_SUSPEND +DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65 +DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15 + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +endif + +# For CCX +ifeq ($(CONFIG_BRCM_CCX),y) + DHDCFLAGS += -DBCMCCX +endif + +DHDCFLAGS += -DWL_CFG80211 + +# SoftAP +DHDCFLAGS += -DSUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DSUPPORT_SOFTAP_SINGL_DISASSOC +DHDCFLAGS += -DUSE_STAMAC_4SOFTAP + +# DPC priority +DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + +# WiFi turn off delay +DHDCFLAGS += -DWIFI_TURNOFF_DELAY=100 + +# WiFi Kernel thread type +DHDCFLAGS += -DUSE_KTHREAD_API + +############ +# JellyBean +############ +DHDCFLAGS += -DWL_ENABLE_P2P_IF +DHDCFLAGS += -DMULTIPLE_SUPPLICANT +DHDCFLAGS += -DWL_CFG80211_STA_EVENT + +######################### +# Chip dependent feature +######################### + +ifneq ($(CONFIG_BCM4334),) + DHDCFLAGS += -DBCM4334_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION + DHDCFLAGS += -DUSE_CID_CHECK -DCONFIG_CONTROL_PM + DHDCFLAGS += -DPROP_TXSTATUS + DHDCFLAGS += -DVSDB -DHT40_GO + DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DSDIO_CRC_ERROR_FIX + DHDCFLAGS += -DCUSTOM_SDIO_F2_BLKSIZE=128 + DHDCFLAGS += -DDHD_USE_IDLECOUNT + DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD + DHDCFLAGS += -DVSDB_DYNAMIC_F2_BLKSIZE -DSDIO_F2_BLKSIZE=512 -DVSDB_F2_BLKSIZE=64 + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=5 -DENABLE_BCN_LI_BCN_WAKEUP +# DHDCFLAGS += -DUSE_WEP_AUTH_SHARED_OPEN + DHDCFLAGS += -DROAM_AP_ENV_DETECTION + DHDCFLAGS += -DWES_SUPPORT + DHDCFLAGS += -DPASS_ARP_PACKET +endif + +ifneq ($(CONFIG_BCM4330),) + DHDCFLAGS += -DBCM4330_CHIP + DHDCFLAGS += -DMCAST_LIST_ACCUMULATION + DHDCFLAGS += -DCONFIG_CONTROL_PM + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=0 + DHDCFLAGS += -DPASS_ARP_PACKET +endif + +ifneq ($(CONFIG_BCM43241),) + DHDCFLAGS += -DBCM43241_CHIP -DHW_OOB + DHDCFLAGS += -DMCAST_LIST_ACCUMULATION + DHDCFLAGS += -DMIMO_ANT_SETTING -DCONFIG_CONTROL_PM + DHDCFLAGS += -DAMPDU_HOSTREORDER -DDHD_USE_IDLECOUNT + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=1 + DHDCFLAGS += -DPROP_TXSTATUS + DHDCFLAGS += -DVSDB -DHT40_GO + DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD + DHDCFLAGS += -DROAM_AP_ENV_DETECTION + ifeq ($(CONFIG_BCM43241),m) + DHDCFLAGS += -fno-pic + endif +endif + +############################# +# Platform dependent feature +############################# + +ifeq ($(CONFIG_SPI_SC8810),y) +DHDCFLAGS += -DREAD_MACADDR -DBCMSPI -DBCMSPI_ANDROID -DSPI_PIO_32BIT_RW -DSPI_PIO_RW_BIGENDIAN -DDISABLE_11N + +#Remove defines for SDMMC +DHDCFLAGS :=$(filter-out -DOOB_INTR_ONLY,$(DHDCFLAGS)) +DHDCFLAGS :=$(filter-out -DBCMLXSDMMC,$(DHDCFLAGS)) + +#Remove defines for JB +DHDCFLAGS :=$(filter-out -DWL_ENABLE_P2P_IF,$(DHDCFLAGS)) +DHDCFLAGS :=$(filter-out -DMULTIPLE_SUPPLICANT,$(DHDCFLAGS)) +DHDCFLAGS :=$(filter-out -DWL_CFG80211_STA_EVENT,$(DHDCFLAGS)) +endif + +#For INITIAL 2G scan features +ifneq ($(CONFIG_TARGET_LOCALE_KOR),y) + DHDCFLAGS += -DUSE_INITIAL_2G_SCAN +endif + +# For SLP feature +ifeq ($(CONFIG_SLP),y) + DHDCFLAGS += -DPLATFORM_SLP + DHDCFLAGS += -UWL_ENABLE_P2P_IF + DHDCFLAGS += -UMULTIPLE_SUPPLICANT + DHDCFLAGS += -UWL_CFG80211_STA_EVENT +endif + +# GGSM_WIFI_5GHz_CHANNELS feature is define for only GGSM model +ifeq ($(GGSM_WIFI_5GHz_CHANNELS),true) + DHDCFLAGS += -DCUSTOMER_SET_COUNTRY +endif + +############################################################## +# dhd_sec_feature.h + +REGION_CODE := 100 + +ifeq ($(CONFIG_TARGET_LOCALE_KOR),y) +REGION_CODE=200 +endif + +ifeq ($(CONFIG_MACH_U1_KOR_KT), y) +REGION_CODE=202 +endif + +ifeq ($(CONFIG_TARGET_LOCALE_CHN),y) +REGION_CODE=300 +endif + +ifeq ($(SEC_MODEL_NAME),U1) +ifeq ($(X_BUILD_LOCALE),EUR_ORG) +REGION_CODE=101 +endif +endif + +ifdef CONFIG_WLAN_REGION_CODE +REGION_CODE=$(CONFIG_WLAN_REGION_CODE) +endif + +DHDCFLAGS += -DWLAN_REGION_CODE=$(REGION_CODE) + +############################################################## + +######### +# Others +######### + EXTRA_LDFLAGS += --strip-debug + +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +DHDOFILES := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_common.o dhd_custom_gpio.o dhd_custom_sec.o \ + dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_sdio.o aiutils.o bcmevent.o \ + bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wldev_common.o wl_linux_mon.o wl_roam.o + +# For SPI projects +ifeq ($(CONFIG_SPI_SC8810),y) +DHDOFILES += bcmsdspi_linux.o bcmspibrcm.o +DHDOFILES :=$(filter-out bcmsdh_sdmmc.o,$(DHDOFILES)) +DHDOFILES :=$(filter-out bcmsdh_sdmmc_linux.o,$(DHDOFILES)) endif + +obj-$(CONFIG_BCMDHD) += dhd.o +dhd-objs += $(DHDOFILES) + diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c index f1db5a2b935..3ca17259e65 100644 --- a/drivers/net/wireless/bcmdhd/aiutils.c +++ b/drivers/net/wireless/bcmdhd/aiutils.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: aiutils.c 321247 2012-03-14 21:14:33Z $ + * $Id: aiutils.c 347614 2012-07-27 10:24:51Z $ */ #include #include @@ -231,17 +231,27 @@ ai_scan(si_t *sih, void *regs, uint devid) asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); if (asd == 0) { + do { asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, &sizel, &sizeh); if (asd != 0) br = TRUE; - else - if ((addrh != 0) || (sizeh != 0) || (sizel != SI_CORE_SIZE)) { - SI_ERROR(("First Slave ASD for core 0x%04x malformed " + else { + if (br == TRUE) { + break; + } + else if ((addrh != 0) || (sizeh != 0) || + (sizel != SI_CORE_SIZE)) { + SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 =" + "0x%x\n", addrh, sizeh, sizel)); + SI_ERROR(("First Slave ASD for" + "core 0x%04x malformed " "(0x%08x)\n", cid, asd)); goto error; } + } + } while (1); } sii->coresba[idx] = addrl; sii->coresba_size[idx] = sizel; diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c index cecea604942..e41c7387a8a 100644 --- a/drivers/net/wireless/bcmdhd/bcmevent.c +++ b/drivers/net/wireless/bcmdhd/bcmevent.c @@ -109,7 +109,7 @@ const bcmevent_name_t bcmevent_names[] = { { WLC_E_REASSOC_IND_NDIS, "REASSOC_IND_NDIS"}, { WLC_E_ACTION_FRAME_RX_NDIS, "WLC_E_ACTION_FRAME_RX_NDIS" }, { WLC_E_AUTH_REQ, "WLC_E_AUTH_REQ" }, -#endif +#endif #ifdef BCMWAPI_WAI { WLC_E_WAI_STA_EVENT, "WAI_STA_EVENT" }, { WLC_E_WAI_MSG, "WAI_MSG" }, diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c index 6e1a6b0e214..2f7c451c47b 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh.c 300445 2011-12-03 05:37:20Z $ + * $Id: bcmsdh.c 347614 2012-07-27 10:24:51Z $ */ /** @@ -45,6 +45,8 @@ #include /* SDIO Device and Protocol Specs */ +#include + #define SDIOH_API_ACCESS_RETRY_LIMIT 2 const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; @@ -362,9 +364,10 @@ bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length) } bcopy(cis, tmp_buf, length); for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) { - ptr += sprintf((char*)ptr, "%.2x ", *tmp_ptr & 0xff); + ptr += snprintf((char*)ptr, (cis + length - ptr - 4), + "%.2x ", *tmp_ptr & 0xff); if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) - ptr += sprintf((char *)ptr, "\n"); + ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n"); } MFREE(bcmsdh->osh, tmp_buf, length); } @@ -619,6 +622,17 @@ bcmsdh_waitlockfree(void *sdh) } +#ifdef BCMSPI /* 4329 gSPI won't have CIS reads. */ +int +bcmsdh_query_device(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | BCM4321_D11N2G_ID; + + return (bcmsdh->vendevid); +} +#else int bcmsdh_query_device(void *sdh) { @@ -626,6 +640,7 @@ bcmsdh_query_device(void *sdh) bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0; return (bcmsdh->vendevid); } +#endif /* else BCMSPI */ uint bcmsdh_query_iofnum(void *sdh) @@ -656,7 +671,13 @@ void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh) uint32 bcmsdh_get_dstatus(void *sdh) { +#ifdef BCMSPI + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + return sdioh_get_dstatus(sd); +#else return 0; +#endif /* BCMSPI */ } uint32 bcmsdh_cur_sbwad(void *sdh) @@ -672,9 +693,25 @@ bcmsdh_cur_sbwad(void *sdh) void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev) { +#ifdef BCMSPI + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + sdioh_chipinfo(sd, chip, chiprev); +#else return; +#endif /* BCMSPI */ } +#ifdef BCMSPI +void +bcmsdh_dwordmode(void *sdh, bool set) +{ + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + sdioh_dwordmode(sd, set); + return; +} +#endif /* BCMSPI */ int bcmsdh_sleep(void *sdh, bool enab) @@ -724,3 +761,32 @@ bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) return sdioh_gpioout(sd, gpio, enab); } + +#ifdef BCMSDIOH_TXGLOM +void +bcmsdh_glom_post(void *sdh, uint8 *frame, uint len) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + sdioh_glom_post(bcmsdh->sdioh, frame, len); +} + +void +bcmsdh_glom_clear(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + sdioh_glom_clear(bcmsdh->sdioh); +} + +uint +bcmsdh_set_mode(void *sdh, uint mode) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + return (sdioh_set_mode(bcmsdh->sdioh, mode)); +} + +bool +bcmsdh_glom_enabled(void) +{ + return (sdioh_glom_enabled()); +} +#endif /* BCMSDIOH_TXGLOM */ diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c index 79760eb2423..cd62e4b69ee 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_linux.c 312788 2012-02-03 23:06:32Z $ + * $Id: bcmsdh_linux.c 347638 2012-07-27 11:39:03Z $ */ /** @@ -41,13 +41,18 @@ #include #include -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) #include extern void dhdsdio_isr(void * args); #include #include #include -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ + +#if defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) +/* SLP_wakelock_alternative_code */ +struct device *pm_dev; +#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ /** * SDIO Host Controller info @@ -69,9 +74,9 @@ struct bcmsdh_hc { unsigned long oob_flags; /* OOB Host specifiction as edge and etc */ bool oob_irq_registered; bool oob_irq_enable_flag; -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) spinlock_t irq_lock; -#endif +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ }; static bcmsdh_hc_t *sdhcinfo = NULL; @@ -132,7 +137,7 @@ bcmsdh_chipmatch(uint16 vendor, uint16 device) } #if defined(BCMPLATFORM_BUS) -#if defined(BCMLXSDMMC) +#if defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID) /* forward declarations */ int bcmsdh_probe(struct device *dev); int bcmsdh_remove(struct device *dev); @@ -144,34 +149,37 @@ EXPORT_SYMBOL(bcmsdh_remove); /* forward declarations */ static int __devinit bcmsdh_probe(struct device *dev); static int __devexit bcmsdh_remove(struct device *dev); -#endif /* BCMLXSDMMC */ +#endif /* defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID) */ -#ifndef BCMLXSDMMC +#if !defined(BCMLXSDMMC) && !defined(BCMSPI_ANDROID) static -#endif /* BCMLXSDMMC */ +#endif /* !defined(BCMLXSDMMC) && !defined(BCMSPI_ANDROID) */ int bcmsdh_probe(struct device *dev) { osl_t *osh = NULL; bcmsdh_hc_t *sdhc = NULL; ulong regs = 0; bcmsdh_info_t *sdh = NULL; -#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) +#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) && !defined(BCMSPI_ANDROID) struct platform_device *pdev; struct resource *r; -#endif /* BCMLXSDMMC */ +#endif /* !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) && !defined(BCMSPI_ANDROID) */ int irq = 0; uint32 vendevid; unsigned long irq_flags = 0; +#if defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) + int ret = 0; +#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ -#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) +#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) && !defined(BCMSPI_ANDROID) pdev = to_platform_device(dev); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!r || irq == NO_IRQ) return -ENXIO; -#endif /* BCMLXSDMMC */ +#endif /* !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) && !defined(BCMSPI_ANDROID) */ -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) #ifdef HW_OOB irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; @@ -185,7 +193,7 @@ int bcmsdh_probe(struct device *dev) SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__)); return 1; } -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ /* allocate SDIO Host Controller state info */ if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) { SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__)); @@ -202,7 +210,7 @@ int bcmsdh_probe(struct device *dev) sdhc->dev = (void *)dev; -#ifdef BCMLXSDMMC +#if defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID) if (!(sdh = bcmsdh_attach(osh, (void *)0, (void **)®s, irq))) { SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__)); @@ -214,20 +222,27 @@ int bcmsdh_probe(struct device *dev) SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__)); goto err; } -#endif /* BCMLXSDMMC */ +#endif /* defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID) */ sdhc->sdh = sdh; sdhc->oob_irq = irq; sdhc->oob_flags = irq_flags; sdhc->oob_irq_registered = FALSE; /* to make sure.. */ sdhc->oob_irq_enable_flag = FALSE; -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) spin_lock_init(&sdhc->irq_lock); -#endif +#endif /* defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID) */ /* chain SDIO Host Controller info together */ sdhc->next = sdhcinfo; sdhcinfo = sdhc; +#if defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) + /* SLP_wakelock_alternative_code */ + pm_dev = sdhc->dev; + ret = device_init_wakeup(pm_dev, 1); + printf("%s : device_init_wakeup(pm_dev) enable, ret = %d\n", __func__, ret); +#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ + /* Read the vendor/device ID from the CIS */ vendevid = bcmsdh_query_device(sdh); /* try to attach to the target device */ @@ -252,15 +267,20 @@ int bcmsdh_probe(struct device *dev) return -ENODEV; } -#ifndef BCMLXSDMMC +#if !defined(BCMLXSDMMC) && !defined(BCMSPI_ANDROID) static -#endif /* BCMLXSDMMC */ +#endif /* !defined(BCMLXSDMMC) && !defined(BCMSPI_ANDROID) */ int bcmsdh_remove(struct device *dev) { bcmsdh_hc_t *sdhc, *prev; osl_t *osh; sdhc = sdhcinfo; +#if defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) + /* SLP_wakelock_alternative_code */ + device_init_wakeup(pm_dev, 0); + printf("%s : device_init_wakeup(pm_dev) disable\n", __func__); +#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ drvinfo.detach(sdhc->ch); bcmsdh_detach(sdhc->osh, sdhc->sdh); @@ -285,9 +305,9 @@ int bcmsdh_remove(struct device *dev) MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); osl_detach(osh); -#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) +#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) dev_set_drvdata(dev, NULL); -#endif /* !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) */ +#endif /* !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ return 0; } @@ -510,7 +530,11 @@ bcmsdh_pci_remove(struct pci_dev *pdev) #endif /* BCMLXSDMMC */ #endif /* BCMPLATFORM_BUS */ +#ifdef BCMSPI_ANDROID +extern int spi_function_init(void); +#else extern int sdio_function_init(void); +#endif /* BCMSPI_ANDROID */ extern int sdio_func_reg_notify(void* semaphore); extern void sdio_func_unreg_notify(void); @@ -535,8 +559,13 @@ bcmsdh_register(bcmsdh_driver_t *driver) drvinfo = *driver; #if defined(BCMPLATFORM_BUS) +#ifdef BCMSPI_ANDROID + SDLX_MSG(("Linux Kernel SPI Driver\n")); + error = spi_function_init(); +#else /* BCMSPI_ANDROID */ SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n")); error = sdio_function_init(); +#endif /* BCMSPI_ANDROID */ return error; #endif /* defined(BCMPLATFORM_BUS) */ @@ -555,7 +584,11 @@ bcmsdh_register(bcmsdh_driver_t *driver) return error; } +#ifdef BCMSPI_ANDROID +extern void spi_function_cleanup(void); +#else extern void sdio_function_cleanup(void); +#endif /* BCMSPI_ANDROID */ void bcmsdh_unregister(void) @@ -564,6 +597,9 @@ bcmsdh_unregister(void) if (bcmsdh_pci_driver.node.next) #endif +#ifdef BCMSPI_ANDROID + spi_function_cleanup(); +#endif /* BCMSPI_ANDROID */ #if defined(BCMLXSDMMC) sdio_function_cleanup(); #endif /* BCMLXSDMMC */ @@ -573,7 +609,7 @@ bcmsdh_unregister(void) #endif /* BCMPLATFORM_BUS */ } -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) void bcmsdh_oob_intr_set(bool enable) { static bool curstate = 1; @@ -627,7 +663,9 @@ int bcmsdh_register_oob_intr(void * dhdp) if (error) return -ENODEV; - enable_irq_wake(sdhcinfo->oob_irq); + error = enable_irq_wake(sdhcinfo->oob_irq); + if (error) + SDLX_MSG(("%s enable_irq_wake error=%d \n", __FUNCTION__, error)); sdhcinfo->oob_irq_registered = TRUE; sdhcinfo->oob_irq_enable_flag = TRUE; } @@ -644,7 +682,9 @@ void bcmsdh_set_irq(int flag) enable_irq(sdhcinfo->oob_irq); enable_irq_wake(sdhcinfo->oob_irq); } else { +#if !(defined(BCMSPI_ANDROID) && defined(CUSTOMER_HW4) && defined(CONFIG_NKERNEL)) disable_irq_wake(sdhcinfo->oob_irq); +#endif /* !defined(BCMSPI_ANDROID) */ disable_irq(sdhcinfo->oob_irq); } } @@ -660,7 +700,7 @@ void bcmsdh_unregister_oob_intr(void) sdhcinfo->oob_irq_registered = FALSE; } } -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ #if defined(BCMLXSDMMC) void *bcmsdh_get_drvdata(void) @@ -699,6 +739,11 @@ extern int sd_uhsimode; module_param(sd_uhsimode, int, 0); #endif +#ifdef BCMSDIOH_TXGLOM +extern uint sd_txglom; +module_param(sd_txglom, uint, 0); +#endif + #ifdef BCMSDH_MODULE EXPORT_SYMBOL(bcmsdh_attach); EXPORT_SYMBOL(bcmsdh_detach); diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c index afe4019a160..8137701bda7 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc.c 321372 2012-03-15 01:10:32Z $ + * $Id: bcmsdh_sdmmc.c 347640 2012-07-27 11:53:21Z $ */ #include @@ -62,9 +62,13 @@ extern int sdio_reset_comm(struct mmc_card *card); extern PBCMSDH_SDMMC_INSTANCE gInstance; -uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ -uint sd_f2_blocksize = 512; /* Default blocksize */ +#define DEFAULT_SDIO_F2_BLKSIZE 512 +#ifndef CUSTOM_SDIO_F2_BLKSIZE +#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE +#endif +uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ +uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ uint sd_power = 1; /* Default to SD Slot powered ON */ @@ -78,6 +82,7 @@ DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); #define DMA_ALIGN_MASK 0x03 +#define MMC_SDIO_ABORT_RETRY_LIMIT 5 int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); @@ -154,16 +159,22 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) gInstance->sd = sd; /* Claim host controller */ - sdio_claim_host(gInstance->func[1]); + if (gInstance->func[1]) { + sdio_claim_host(gInstance->func[1]); - sd->client_block_size[1] = 64; - err_ret = sdio_set_block_size(gInstance->func[1], 64); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); - } + sd->client_block_size[1] = 64; + err_ret = sdio_set_block_size(gInstance->func[1], 64); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); + } - /* Release host controller F1 */ - sdio_release_host(gInstance->func[1]); + /* Release host controller F1 */ + sdio_release_host(gInstance->func[1]); + } else { + sd_err(("%s:gInstance->func[1] is null\n", __FUNCTION__)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; + } if (gInstance->func[2]) { /* Claim host controller F2 */ @@ -178,6 +189,10 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) /* Release host controller F2 */ sdio_release_host(gInstance->func[2]); + } else { + sd_err(("%s:gInstance->func[2] is null\n", __FUNCTION__)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; } sdioh_sdmmc_card_enablefuncs(sd); @@ -510,6 +525,20 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, /* Now set it */ si->client_block_size[func] = blksize; +#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) + if (gInstance == NULL || gInstance->func[func] == NULL) { + sd_err(("%s: SDIO Device not present\n", __FUNCTION__)); + bcmerror = BCME_NORESOURCE; + break; + } + sdio_claim_host(gInstance->func[func]); + bcmerror = sdio_set_block_size(gInstance->func[func], blksize); + if (bcmerror) { + sd_err(("%s: Failed to set F%d blocksize to %d\n", __FUNCTION__, func, + blksize)); + } + sdio_release_host(gInstance->func[func]); +#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ break; } @@ -765,7 +794,9 @@ extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) { int err_ret; - +#if defined(MMC_SDIO_ABORT) + int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; +#endif sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); @@ -799,41 +830,53 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by #if defined(MMC_SDIO_ABORT) /* to allow abort command through F1 */ else if (regaddr == SDIOD_CCCR_IOABORT) { - sdio_claim_host(gInstance->func[func]); - /* - * this sdio_f0_writeb() can be replaced with another api - * depending upon MMC driver change. - * As of this time, this is temporaray one - */ - sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); - sdio_release_host(gInstance->func[func]); + while (sdio_abort_retry--) { + if (gInstance->func[func]) { + sdio_claim_host(gInstance->func[func]); + /* + * this sdio_f0_writeb() can be replaced with + * another api depending upon MMC driver change. + * As of this time, this is temporaray one + */ + sdio_writeb(gInstance->func[func], + *byte, regaddr, &err_ret); + sdio_release_host(gInstance->func[func]); + } + if (!err_ret) + break; + } } #endif /* MMC_SDIO_ABORT */ else if (regaddr < 0xF0) { sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); } else { /* Claim host controller, perform F0 write, and release */ - sdio_claim_host(gInstance->func[func]); - sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret); - sdio_release_host(gInstance->func[func]); + if (gInstance->func[func]) { + sdio_claim_host(gInstance->func[func]); + sdio_f0_writeb(gInstance->func[func], + *byte, regaddr, &err_ret); + sdio_release_host(gInstance->func[func]); + } } } else { /* Claim host controller, perform Fn write, and release */ - sdio_claim_host(gInstance->func[func]); - sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); - sdio_release_host(gInstance->func[func]); + if (gInstance->func[func]) { + sdio_claim_host(gInstance->func[func]); + sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); + sdio_release_host(gInstance->func[func]); + } } } else { /* CMD52 Read */ /* Claim host controller, perform Fn read, and release */ - sdio_claim_host(gInstance->func[func]); - - if (func == 0) { - *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret); - } else { - *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret); + if (gInstance->func[func]) { + sdio_claim_host(gInstance->func[func]); + if (func == 0) { + *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret); + } else { + *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret); + } + sdio_release_host(gInstance->func[func]); } - - sdio_release_host(gInstance->func[func]); } if (err_ret) { @@ -849,6 +892,9 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add uint32 *word, uint nbytes) { int err_ret = SDIOH_API_RC_FAIL; +#if defined(MMC_SDIO_ABORT) + int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; +#endif if (func == 0) { sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__)); @@ -885,8 +931,29 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add sdio_release_host(gInstance->func[func]); if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x", +#if defined(MMC_SDIO_ABORT) + /* Any error on CMD53 transaction should abort that function using function 0. */ + while (sdio_abort_retry--) { + if (gInstance->func[0]) { + sdio_claim_host(gInstance->func[0]); + /* + * this sdio_f0_writeb() can be replaced with another api + * depending upon MMC driver change. + * As of this time, this is temporaray one + */ + sdio_writeb(gInstance->func[0], + func, SDIOD_CCCR_IOABORT, &err_ret); + sdio_release_host(gInstance->func[0]); + } + if (!err_ret) + break; + } + if (err_ret) +#endif /* MMC_SDIO_ABORT */ + { + sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x\n", rw ? "Write" : "Read", err_ret)); + } } return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); @@ -1012,7 +1079,20 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, pkt_len -= xfred_len; xfred_len = 0; } - pkt_len = (pkt_len + 3) & 0xFFFFFFFC; + + /* Align Patch + * read or small packet(ex:BDC header) skip 32 byte align + * otherwise, padding DHD_SDALIGN for performance + */ + if (write == 0 || pkt_len < 32) + pkt_len = (pkt_len + 3) & 0xFFFFFFFC; + else if (pkt_len % DHD_SDALIGN) + pkt_len += DHD_SDALIGN - (pkt_len % DHD_SDALIGN); + +#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) + if (write && pkt_len > 64 && (pkt_len % 64) == 32) + pkt_len += 32; +#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ #ifdef CONFIG_MMC_MSM7X00A if ((pkt_len % 64) == 32) { sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); @@ -1300,6 +1380,8 @@ sdioh_start(sdioh_info_t *si, int stage) int ret; sdioh_info_t *sd = gInstance->sd; + if (!sd) return (0); + /* Need to do this stages as we can't enable the interrupt till downloading of the firmware is complete, other wise polling sdio access will come in way @@ -1325,16 +1407,18 @@ sdioh_start(sdioh_info_t *si, int stage) sd->use_client_ints = TRUE; sd->client_block_size[0] = 64; - /* Claim host controller */ - sdio_claim_host(gInstance->func[1]); + if (gInstance->func[1]) { + /* Claim host controller */ + sdio_claim_host(gInstance->func[1]); - sd->client_block_size[1] = 64; - if (sdio_set_block_size(gInstance->func[1], 64)) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); - } + sd->client_block_size[1] = 64; + if (sdio_set_block_size(gInstance->func[1], 64)) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); + } - /* Release host controller F1 */ - sdio_release_host(gInstance->func[1]); + /* Release host controller F1 */ + sdio_release_host(gInstance->func[1]); + } if (gInstance->func[2]) { /* Claim host controller F2 */ @@ -1356,8 +1440,10 @@ sdioh_start(sdioh_info_t *si, int stage) } else { #if !defined(OOB_INTR_ONLY) sdio_claim_host(gInstance->func[0]); - sdio_claim_irq(gInstance->func[2], IRQHandlerF2); - sdio_claim_irq(gInstance->func[1], IRQHandler); + if (gInstance->func[2]) + sdio_claim_irq(gInstance->func[2], IRQHandlerF2); + if (gInstance->func[1]) + sdio_claim_irq(gInstance->func[1], IRQHandler); sdio_release_host(gInstance->func[0]); #else /* defined(OOB_INTR_ONLY) */ #if defined(HW_OOB) @@ -1385,8 +1471,10 @@ sdioh_stop(sdioh_info_t *si) if (gInstance->func[0]) { #if !defined(OOB_INTR_ONLY) sdio_claim_host(gInstance->func[0]); - sdio_release_irq(gInstance->func[1]); - sdio_release_irq(gInstance->func[2]); + if (gInstance->func[1]) + sdio_release_irq(gInstance->func[1]); + if (gInstance->func[2]) + sdio_release_irq(gInstance->func[2]); sdio_release_host(gInstance->func[0]); #else /* defined(OOB_INTR_ONLY) */ #if defined(HW_OOB) diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c index 9d2b1d3067b..ed37e8c2c9b 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc_linux.c 312783 2012-02-03 22:53:56Z $ + * $Id: bcmsdh_sdmmc_linux.c 355594 2012-09-07 10:22:02Z $ */ #include @@ -109,31 +109,36 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, { int ret = 0; static struct sdio_func sdio_func_0; - sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); - sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class)); - sd_trace(("sdio_vendor: 0x%04x\n", func->vendor)); - sd_trace(("sdio_device: 0x%04x\n", func->device)); - sd_trace(("Function#: 0x%04x\n", func->num)); - - if (func->num == 1) { - sdio_func_0.num = 0; - sdio_func_0.card = func->card; - gInstance->func[0] = &sdio_func_0; - if(func->device == 0x4) { /* 4318 */ - gInstance->func[2] = NULL; - sd_trace(("NIC found, calling bcmsdh_probe...\n")); - ret = bcmsdh_probe(&func->dev); + + if (func) { + sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); + sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class)); + sd_trace(("sdio_vendor: 0x%04x\n", func->vendor)); + sd_trace(("sdio_device: 0x%04x\n", func->device)); + sd_trace(("Function#: 0x%04x\n", func->num)); + + if (func->num == 1) { + sdio_func_0.num = 0; + sdio_func_0.card = func->card; + gInstance->func[0] = &sdio_func_0; + if(func->device == 0x4) { /* 4318 */ + gInstance->func[2] = NULL; + sd_trace(("NIC found, calling bcmsdh_probe...\n")); + ret = bcmsdh_probe(&func->dev); + } } - } - gInstance->func[func->num] = func; + gInstance->func[func->num] = func; - if (func->num == 2) { -#ifdef WL_CFG80211 - wl_cfg80211_set_parent_dev(&func->dev); -#endif - sd_trace(("F2 found, calling bcmsdh_probe...\n")); - ret = bcmsdh_probe(&func->dev); + if (func->num == 2) { + #ifdef WL_CFG80211 + wl_cfg80211_set_parent_dev(&func->dev); + #endif + sd_trace(("F2 found, calling bcmsdh_probe...\n")); + ret = bcmsdh_probe(&func->dev); + } + } else { + ret = -ENODEV; } return ret; @@ -141,20 +146,22 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, static void bcmsdh_sdmmc_remove(struct sdio_func *func) { - sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); - sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); - sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); - sd_info(("sdio_device: 0x%04x\n", func->device)); - sd_info(("Function#: 0x%04x\n", func->num)); - - if (func->num == 2) { - sd_trace(("F2 found, calling bcmsdh_remove...\n")); - bcmsdh_remove(&func->dev); - } else if (func->num == 1) { - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); - gInstance->func[1] = NULL; + if (func) { + sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); + sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); + sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); + sd_info(("sdio_device: 0x%04x\n", func->device)); + sd_info(("Function#: 0x%04x\n", func->num)); + + if (func->num == 2) { + sd_trace(("F2 found, calling bcmsdh_remove...\n")); + bcmsdh_remove(&func->dev); + } else if (func->num == 1) { + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + gInstance->func[1] = NULL; + } } } @@ -185,10 +192,11 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev) if (func->num != 2) return 0; - sd_trace(("%s Enter\n", __FUNCTION__)); + sd_trace_hw4(("%s Enter\n", __FUNCTION__)); if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) return -EBUSY; + sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { @@ -202,10 +210,16 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev) sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); return ret; } + +#if !defined(CUSTOMER_HW4) #if defined(OOB_INTR_ONLY) bcmsdh_oob_intr_set(0); #endif /* defined(OOB_INTR_ONLY) */ +#endif /* !defined(CUSTOMER_HW4) */ dhd_mmc_suspend = TRUE; +#if defined(CUSTOMER_HW4) && defined(CONFIG_ARCH_TEGRA) + irq_set_irq_wake(390, 1); +#endif smp_mb(); return 0; @@ -213,16 +227,24 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev) static int bcmsdh_sdmmc_resume(struct device *pdev) { +#if !defined(CUSTOMER_HW4) #if defined(OOB_INTR_ONLY) struct sdio_func *func = dev_to_sdio_func(pdev); -#endif - sd_trace(("%s Enter\n", __FUNCTION__)); +#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(CUSTOMER_HW4) */ + sd_trace_hw4(("%s Enter\n", __FUNCTION__)); + dhd_mmc_suspend = FALSE; +#if !defined(CUSTOMER_HW4) #if defined(OOB_INTR_ONLY) if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata())) bcmsdh_oob_intr_set(1); #endif /* (OOB_INTR_ONLY) */ - +#endif /* !(CUSTOMER_HW4) */ +#if defined(CUSTOMER_HW4) && defined(CONFIG_ARCH_TEGRA) + if (func->num == 2) + irq_set_irq_wake(390, 0); +#endif smp_mb(); return 0; } @@ -291,6 +313,9 @@ sdioh_sdmmc_osinit(sdioh_info_t *sd) { struct sdos_info *sdos; + if (!sd) + return BCME_BADARG; + sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); sd->sdos_info = (void*)sdos; if (sdos == NULL) @@ -318,6 +343,9 @@ sdioh_interrupt_set(sdioh_info_t *sd, bool enable) ulong flags; struct sdos_info *sdos; + if (!sd) + return BCME_BADARG; + sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); sdos = (struct sdos_info *)sd->sdos_info; @@ -351,7 +379,7 @@ static int __init bcmsdh_module_init(void) { int error = 0; - sdio_function_init(); + error = sdio_function_init(); return error; } @@ -382,6 +410,10 @@ int sdio_function_init(void) return -ENOMEM; error = sdio_register_driver(&bcmsdh_sdmmc_driver); + if (error && gInstance) { + kfree(gInstance); + gInstance = 0; + } return error; } diff --git a/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c new file mode 100755 index 00000000000..2dbb1684b46 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c @@ -0,0 +1,420 @@ +/* + * Broadcom SPI Host Controller Driver - Linux Per-port + * + * Copyright (C) 1999-2012, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdspi_linux.c 355376 2012-09-06 13:23:59Z $ + */ + +#include +#include + +#include /* bcmsdh to/from specific controller APIs */ +#include /* to get msglevel bit values */ + +#ifndef BCMSPI_ANDROID +#include +#include /* SDIO Device and Protocol Specs */ +#include /* request_irq(), free_irq() */ +#include +#include + +extern uint sd_crc; +module_param(sd_crc, uint, 0); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define KERNEL26 +#endif + +struct sdos_info { + sdioh_info_t *sd; + spinlock_t lock; + wait_queue_head_t intr_wait_queue; +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define BLOCKABLE() (!in_atomic()) +#else +#define BLOCKABLE() (!in_interrupt()) +#endif + +/* Interrupt handler */ +static irqreturn_t +sdspi_isr(int irq, void *dev_id +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +, struct pt_regs *ptregs +#endif +) +{ + sdioh_info_t *sd; + struct sdos_info *sdos; + bool ours; + + sd = (sdioh_info_t *)dev_id; + sd->local_intrcount++; + + if (!sd->card_init_done) { + sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq)); + return IRQ_RETVAL(FALSE); + } else { + ours = spi_check_client_intr(sd, NULL); + + /* For local interrupts, wake the waiting process */ + if (ours && sd->got_hcint) { + sdos = (struct sdos_info *)sd->sdos_info; + wake_up_interruptible(&sdos->intr_wait_queue); + } + + return IRQ_RETVAL(ours); + } +} +#else /* !BCMSPI_ANDROID */ +#include +#include + +static struct spi_device *gBCMSPI = NULL; + +extern int bcmsdh_probe(struct device *dev); +extern int bcmsdh_remove(struct device *dev); + +static int bcmsdh_spi_probe(struct spi_device *spi_dev) +{ + int ret = 0; + + gBCMSPI = spi_dev; + +#ifdef SPI_PIO_32BIT_RW + spi_dev->bits_per_word = 32; +#else + spi_dev->bits_per_word = 8; +#endif /* SPI_PIO_32BIT_RW */ + ret = spi_setup(spi_dev); + + if (ret) { + sd_err(("bcmsdh_spi_probe: spi_setup fail with %d\n", ret)); + } + sd_err(("bcmsdh_spi_probe: spi_setup with %d, bits_per_word=%d\n", + ret, spi_dev->bits_per_word)); + ret = bcmsdh_probe(&spi_dev->dev); + + return ret; +} + +static int bcmsdh_spi_remove(struct spi_device *spi_dev) +{ + int ret = 0; + + ret = bcmsdh_remove(&spi_dev->dev); + gBCMSPI = NULL; + + return ret; +} + +static struct spi_driver bcmsdh_spi_driver = { + .probe = bcmsdh_spi_probe, + .remove = bcmsdh_spi_remove, + .driver = { + .name = "wlan_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, +}; + +/* + * module init +*/ +int spi_function_init(void) +{ + int error = 0; + sd_trace(("bcmsdh_gspi: %s Enter\n", __FUNCTION__)); + + error = spi_register_driver(&bcmsdh_spi_driver); + + return error; +} + +/* + * module cleanup +*/ +void spi_function_cleanup(void) +{ + sd_trace(("%s Enter\n", __FUNCTION__)); + spi_unregister_driver(&bcmsdh_spi_driver); +} +#endif /* !BCMSPI_ANDROID */ + +/* Register with Linux for interrupts */ +int +spi_register_irq(sdioh_info_t *sd, uint irq) +{ +#ifndef BCMSPI_ANDROID + sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq)); + if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) { + sd_err(("%s: request_irq() failed\n", __FUNCTION__)); + return ERROR; + } +#endif /* !BCMSPI_ANDROID */ + return SUCCESS; +} + +/* Free Linux irq */ +void +spi_free_irq(uint irq, sdioh_info_t *sd) +{ +#ifndef BCMSPI_ANDROID + free_irq(irq, sd); +#endif /* !BCMSPI_ANDROID */ +} + +/* Map Host controller registers */ +#ifndef BCMSPI_ANDROID +uint32 * +spi_reg_map(osl_t *osh, uintptr addr, int size) +{ + return (uint32 *)REG_MAP(addr, size); +} + +void +spi_reg_unmap(osl_t *osh, uintptr addr, int size) +{ + REG_UNMAP((void*)(uintptr)addr); +} +#endif /* !BCMSPI_ANDROID */ + +int +spi_osinit(sdioh_info_t *sd) +{ +#ifndef BCMSPI_ANDROID + struct sdos_info *sdos; + + sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); + sd->sdos_info = (void*)sdos; + if (sdos == NULL) + return BCME_NOMEM; + + sdos->sd = sd; + spin_lock_init(&sdos->lock); + init_waitqueue_head(&sdos->intr_wait_queue); +#endif /* !BCMSPI_ANDROID */ +return BCME_OK; +} + +void +spi_osfree(sdioh_info_t *sd) +{ +#ifndef BCMSPI_ANDROID + struct sdos_info *sdos; + ASSERT(sd && sd->sdos_info); + + sdos = (struct sdos_info *)sd->sdos_info; + MFREE(sd->osh, sdos, sizeof(struct sdos_info)); +#endif /* !BCMSPI_ANDROID */ +} + +/* Interrupt enable/disable */ +SDIOH_API_RC +sdioh_interrupt_set(sdioh_info_t *sd, bool enable) +{ +#ifndef BCMSPI_ANDROID + ulong flags; + struct sdos_info *sdos; + + sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); + + sdos = (struct sdos_info *)sd->sdos_info; + ASSERT(sdos); + + if (!(sd->host_init_done && sd->card_init_done)) { + sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { + sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + /* Ensure atomicity for enable/disable calls */ + spin_lock_irqsave(&sdos->lock, flags); + + sd->client_intr_enabled = enable; + if (enable && !sd->lockcount) + spi_devintr_on(sd); + else + spi_devintr_off(sd); + + spin_unlock_irqrestore(&sdos->lock, flags); +#endif /* !BCMSPI_ANDROID */ + + return SDIOH_API_RC_SUCCESS; +} + +/* Protect against reentrancy (disable device interrupts while executing) */ +void +spi_lock(sdioh_info_t *sd) +{ +#ifndef BCMSPI_ANDROID + ulong flags; + struct sdos_info *sdos; + + sdos = (struct sdos_info *)sd->sdos_info; + ASSERT(sdos); + + sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount)); + + spin_lock_irqsave(&sdos->lock, flags); + if (sd->lockcount) { + sd_err(("%s: Already locked!\n", __FUNCTION__)); + ASSERT(sd->lockcount == 0); + } + spi_devintr_off(sd); + sd->lockcount++; + spin_unlock_irqrestore(&sdos->lock, flags); +#endif /* !BCMSPI_ANDROID */ +} + +/* Enable client interrupt */ +void +spi_unlock(sdioh_info_t *sd) +{ +#ifndef BCMSPI_ANDROID + ulong flags; + struct sdos_info *sdos; + + sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled)); + ASSERT(sd->lockcount > 0); + + sdos = (struct sdos_info *)sd->sdos_info; + ASSERT(sdos); + + spin_lock_irqsave(&sdos->lock, flags); + if (--sd->lockcount == 0 && sd->client_intr_enabled) { + spi_devintr_on(sd); + } + spin_unlock_irqrestore(&sdos->lock, flags); +#endif /* !BCMSPI_ANDROID */ +} + +#ifndef BCMSPI_ANDROID +void spi_waitbits(sdioh_info_t *sd, bool yield) +{ +#ifndef BCMSDYIELD + ASSERT(!yield); +#endif + sd_trace(("%s: yield %d canblock %d\n", + __FUNCTION__, yield, BLOCKABLE())); + + /* Clear the "interrupt happened" flag and last intrstatus */ + sd->got_hcint = FALSE; + +#ifdef BCMSDYIELD + if (yield && BLOCKABLE()) { + struct sdos_info *sdos; + sdos = (struct sdos_info *)sd->sdos_info; + /* Wait for the indication, the interrupt will be masked when the ISR fires. */ + wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint)); + } else +#endif /* BCMSDYIELD */ + { + spi_spinbits(sd); + } + +} +#else /* !BCMSPI_ANDROID */ +int bcmgspi_dump = 0; /* Set to dump complete trace of all SPI bus transactions */ + +static void +hexdump(char *pfx, unsigned char *msg, int msglen) +{ + int i, col; + char buf[80]; + + ASSERT(strlen(pfx) + 49 <= sizeof(buf)); + + col = 0; + + for (i = 0; i < msglen; i++, col++) { + if (col % 16 == 0) + strcpy(buf, pfx); + sprintf(buf + strlen(buf), "%02x", msg[i]); + if ((col + 1) % 16 == 0) + printf("%s\n", buf); + else + sprintf(buf + strlen(buf), " "); + } + + if (col % 16 != 0) + printf("%s\n", buf); +} + +/* Send/Receive an SPI Packet */ +void +spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen) +{ + int write = 0; + int tx_len = 0; + struct spi_message msg; + struct spi_transfer t[2]; + + spi_message_init(&msg); + memset(t, 0, 2*sizeof(struct spi_transfer)); + + if (sd->wordlen == 2) +#if !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) + write = msg_out[2] & 0x80; +#else + write = msg_out[1] & 0x80; +#endif /* !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) */ + if (sd->wordlen == 4) +#if !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) + write = msg_out[0] & 0x80; +#else + write = msg_out[3] & 0x80; +#endif /* !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) */ + + if (bcmgspi_dump) { + hexdump(" OUT: ", msg_out, msglen); + } + + tx_len = write ? msglen-4 : 4; + + sd_trace(("spi_sendrecv: %s, wordlen %d, cmd : 0x%02x 0x%02x 0x%02x 0x%02x\n", + write ? "WR" : "RD", sd->wordlen, + msg_out[0], msg_out[1], msg_out[2], msg_out[3])); + + t[0].tx_buf = (char *)&msg_out[0]; + t[0].rx_buf = 0; + t[0].len = tx_len; + + spi_message_add_tail(&t[0], &msg); + + t[1].rx_buf = (char *)&msg_in[tx_len]; + t[1].tx_buf = 0; + t[1].len = msglen-tx_len; + + spi_message_add_tail(&t[1], &msg); + spi_sync(gBCMSPI, &msg); + + if (bcmgspi_dump) { + hexdump(" IN : ", msg_in, msglen); + } +} +#endif /* !BCMSPI_ANDROID */ diff --git a/drivers/net/wireless/bcmdhd/bcmspibrcm.c b/drivers/net/wireless/bcmdhd/bcmspibrcm.c new file mode 100755 index 00000000000..d5f5754af49 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/bcmspibrcm.c @@ -0,0 +1,1853 @@ +/* + * Broadcom BCMSDH to gSPI Protocol Conversion Layer + * + * Copyright (C) 1999-2012, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmspibrcm.c 355377 2012-09-06 13:25:35Z $ + */ + +#define HSMODE + +#include + +#include +#include +#include +#include +#include +#include +#include +#include /* SDIO device core hardware definitions. */ +#include + +#include /* bcmsdh to/from specific controller APIs */ +#include /* ioctl/iovars */ +#include /* SDIO Device and Protocol Specs */ + +#include + + +#include +#ifdef BCMSPI_ANDROID +extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); +#else +#include +#endif /* BCMSPI_ANDROID */ + +/* these are for the older cores... for newer cores we have control for each of them */ +#define F0_RESPONSE_DELAY 16 +#define F1_RESPONSE_DELAY 16 +#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY + + +#define GSPI_F0_RESP_DELAY 0 +#define GSPI_F1_RESP_DELAY F1_RESPONSE_DELAY +#define GSPI_F2_RESP_DELAY 0 +#define GSPI_F3_RESP_DELAY 0 + +#define CMDLEN 4 + +#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE) + +/* Globals */ +#if defined(DHD_DEBUG) +uint sd_msglevel = SDH_ERROR_VAL; +#else +uint sd_msglevel = 0; +#endif + +uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ +uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ +uint sd_f2_blocksize = 64; /* Default blocksize */ + + +uint sd_divisor = 2; +uint sd_power = 1; /* Default to SD Slot powered ON */ +uint sd_clock = 1; /* Default to SD Clock turned ON */ +uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ +uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ + +uint8 spi_outbuf[SPI_MAX_PKT_LEN]; +uint8 spi_inbuf[SPI_MAX_PKT_LEN]; + +/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits + * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. + */ +#define BUF2_PKT_LEN 128 +uint8 spi_outbuf2[BUF2_PKT_LEN]; +uint8 spi_inbuf2[BUF2_PKT_LEN]; + +#if !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) +#define SPISWAP_WD4(x) bcmswap32(x); +#define SPISWAP_WD2(x) (bcmswap16(x & 0xffff)) | \ + (bcmswap16((x & 0xffff0000) >> 16) << 16); +#else +#define SPISWAP_WD4(x) x; +#define SPISWAP_WD2(x) bcmswap32by16(x); +#endif + +/* Prototypes */ +static bool bcmspi_test_card(sdioh_info_t *sd); +static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); +static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); +static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen); +static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 *data); +static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 data); +static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, + uint8 *data); +static int bcmspi_driver_init(sdioh_info_t *sd); +static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data); +static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, + uint32 *data); +static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); +static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); + +/* + * Public entry points & extern's + */ +extern sdioh_info_t * +sdioh_attach(osl_t *osh, void *bar0, uint irq) +{ + sdioh_info_t *sd; + + sd_trace(("%s\n", __FUNCTION__)); + if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { + sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); + return NULL; + } + bzero((char *)sd, sizeof(sdioh_info_t)); + sd->osh = osh; + if (spi_osinit(sd) != 0) { + sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; + } + +#ifndef BCMSPI_ANDROID + sd->bar0 = bar0; +#endif /* !BCMSPI_ANDROID */ + sd->irq = irq; +#ifndef BCMSPI_ANDROID + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; + sd->intr_handler_valid = FALSE; +#endif /* !BCMSPI_ANDROID */ + + /* Set defaults */ + sd->use_client_ints = TRUE; + sd->sd_use_dma = FALSE; /* DMA Not supported */ + + /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit + * mode + */ + sd->wordlen = 2; + +#ifndef BCMSPI_ANDROID + if (!spi_hw_attach(sd)) { + sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } +#endif /* !BCMSPI_ANDROID */ + + if (bcmspi_driver_init(sd) != SUCCESS) { + sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); +#ifndef BCMSPI_ANDROID + spi_hw_detach(sd); +#endif /* !BCMSPI_ANDROID */ + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + if (spi_register_irq(sd, irq) != SUCCESS) { + sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); +#ifndef BCMSPI_ANDROID + spi_hw_detach(sd); +#endif /* !BCMSPI_ANDROID */ + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + sd_trace(("%s: Done\n", __FUNCTION__)); + + return sd; +} + +extern SDIOH_API_RC +sdioh_detach(osl_t *osh, sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if (sd) { + sd_err(("%s: detaching from hardware\n", __FUNCTION__)); + spi_free_irq(sd->irq, sd); +#ifndef BCMSPI_ANDROID + spi_hw_detach(sd); +#endif /* !BCMSPI_ANDROID */ + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + } + return SDIOH_API_RC_SUCCESS; +} + +/* Configure callback to client when we recieve client interrupt */ +extern SDIOH_API_RC +sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) +{ +#ifndef BCMSPI_ANDROID + sd_trace(("%s: Entering\n", __FUNCTION__)); + sd->intr_handler = fn; + sd->intr_handler_arg = argh; + sd->intr_handler_valid = TRUE; +#endif /* !BCMSPI_ANDROID */ + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_deregister(sdioh_info_t *sd) +{ +#ifndef BCMSPI_ANDROID + sd_trace(("%s: Entering\n", __FUNCTION__)); + sd->intr_handler_valid = FALSE; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; +#endif /* !BCMSPI_ANDROID */ + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) +{ +#ifndef BCMSPI_ANDROID + sd_trace(("%s: Entering\n", __FUNCTION__)); + *onoff = sd->client_intr_enabled; +#endif /* !BCMSPI_ANDROID */ + return SDIOH_API_RC_SUCCESS; +} + +#if defined(DHD_DEBUG) +extern bool +sdioh_interrupt_pending(sdioh_info_t *sd) +{ + return 0; +} +#endif + +extern SDIOH_API_RC +sdioh_query_device(sdioh_info_t *sd) +{ + /* Return a BRCM ID appropriate to the dongle class */ + return (sd->num_funcs > 1) ? BCM4329_D11N_ID : BCM4318_D11G_ID; +} + +/* Provide dstatus bits of spi-transaction for dhd layers. */ +extern uint32 +sdioh_get_dstatus(sdioh_info_t *sd) +{ + return sd->card_dstatus; +} + +extern void +sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) +{ + sd->chip = chip; + sd->chiprev = chiprev; +} + +extern void +sdioh_dwordmode(sdioh_info_t *sd, bool set) +{ + uint8 reg = 0; + int status; + + if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } + + if (set) { + reg |= DWORD_PKT_LEN_EN; + sd->dwordmode = TRUE; + sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ + } else { + reg &= ~DWORD_PKT_LEN_EN; + sd->dwordmode = FALSE; + sd->client_block_size[SPI_FUNC_2] = 2048; + } + + if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } +} + + +uint +sdioh_query_iofnum(sdioh_info_t *sd) +{ + return sd->num_funcs; +} + +/* IOVar table */ +enum { + IOV_MSGLEVEL = 1, + IOV_BLOCKMODE, + IOV_BLOCKSIZE, + IOV_DMA, + IOV_USEINTS, + IOV_NUMINTS, + IOV_NUMLOCALINTS, + IOV_HOSTREG, + IOV_DEVREG, + IOV_DIVISOR, + IOV_SDMODE, + IOV_HISPEED, + IOV_HCIREGS, + IOV_POWER, + IOV_CLOCK, + IOV_SPIERRSTATS, + IOV_RESP_DELAY_ALL +}; + +const bcm_iovar_t sdioh_iovars[] = { + {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, + {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ + {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, + {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, + {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, + {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, + {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, + {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, + {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, + {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, + {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, + {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, + {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +int +sdioh_iovar_op(sdioh_info_t *si, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + int32 int_val = 0; + bool bool_val; + uint32 actionid; +/* + sdioh_regs_t *regs; +*/ + + ASSERT(name); + ASSERT(len >= 0); + + /* Get must have return space; Set does not take qualifiers */ + ASSERT(set || (arg && len)); + ASSERT(!set || (!params && !plen)); + + sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); + + if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { + bcmerror = BCME_UNSUPPORTED; + goto exit; + } + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) + goto exit; + + /* Set up params so get and set can share the convenience variables */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + val_size = sizeof(int); + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + switch (actionid) { + case IOV_GVAL(IOV_MSGLEVEL): + int_val = (int32)sd_msglevel; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MSGLEVEL): + sd_msglevel = int_val; + break; + + case IOV_GVAL(IOV_BLOCKSIZE): + if ((uint32)int_val > si->num_funcs) { + bcmerror = BCME_BADARG; + break; + } + int_val = (int32)si->client_block_size[int_val]; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_DMA): + int_val = (int32)si->sd_use_dma; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DMA): + si->sd_use_dma = (bool)int_val; + break; + + case IOV_GVAL(IOV_USEINTS): + int_val = (int32)si->use_client_ints; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_USEINTS): + break; + + case IOV_GVAL(IOV_DIVISOR): + int_val = (uint32)sd_divisor; + bcopy(&int_val, arg, val_size); + break; + +#ifndef BCMSPI_ANDROID + case IOV_SVAL(IOV_DIVISOR): + sd_divisor = int_val; + if (!spi_start_clock(si, (uint16)sd_divisor)) { + sd_err(("%s: set clock failed\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + } + break; +#endif /* !BCMSPI_ANDROID */ + + case IOV_GVAL(IOV_POWER): + int_val = (uint32)sd_power; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_POWER): + sd_power = int_val; + break; + + case IOV_GVAL(IOV_CLOCK): + int_val = (uint32)sd_clock; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_CLOCK): + sd_clock = int_val; + break; + + case IOV_GVAL(IOV_SDMODE): + int_val = (uint32)sd_sdmode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDMODE): + sd_sdmode = int_val; + break; + + case IOV_GVAL(IOV_HISPEED): + int_val = (uint32)sd_hiok; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_HISPEED): + sd_hiok = int_val; + + if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { + sd_err(("%s: Failed changing highspeed mode to %d.\n", + __FUNCTION__, sd_hiok)); + bcmerror = BCME_ERROR; + return ERROR; + } + break; + + case IOV_GVAL(IOV_NUMINTS): + int_val = (int32)si->intrcount; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_NUMLOCALINTS): + int_val = (int32)si->local_intrcount; + bcopy(&int_val, arg, val_size); + break; + case IOV_GVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data; + + if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + + int_val = (int)data; + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data = (uint8)sd_ptr->value; + + if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + } + + + case IOV_GVAL(IOV_SPIERRSTATS): + { + bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); + break; + } + + case IOV_SVAL(IOV_SPIERRSTATS): + { + bzero(&si->spierrstats, sizeof(struct spierrstats_t)); + break; + } + + case IOV_GVAL(IOV_RESP_DELAY_ALL): + int_val = (int32)si->resp_delay_all; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RESP_DELAY_ALL): + si->resp_delay_all = (bool)int_val; + int_val = STATUS_ENABLE|INTR_WITH_STATUS; + if (si->resp_delay_all) + int_val |= RESP_DELAY_ALL; + else { + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, + F1_RESPONSE_DELAY) != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + } + + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) + != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } +exit: + + return bcmerror; +} + +extern SDIOH_API_RC +sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + SDIOH_API_RC status; + /* No lock needed since sdioh_request_byte does locking */ + status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + /* No lock needed since sdioh_request_byte does locking */ + SDIOH_API_RC status; + + if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { + uint8 dummy_data; + status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); + if (status) { + sd_err(("sdioh_cfg_read() failed.\n")); + return status; + } + } + + status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) +{ + uint32 count; + int offset; + uint32 cis_byte; + uint16 *cis = (uint16 *)cisd; + uint bar0 = SI_ENUM_BASE; + int status; + uint8 data; + + sd_trace(("%s: Func %d\n", __FUNCTION__, func)); + + spi_lock(sd); + + /* Set sb window address to 0x18000000 */ + data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); + if (status == SUCCESS) { + data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + if (status == SUCCESS) { + data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + offset = CC_SROM_OTP; /* OTP offset in chipcommon. */ + for (count = 0; count < length/2; count++) { + if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { + sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + *cis = (uint16)cis_byte; + cis++; + offset += 2; + } + + spi_unlock(sd); + + return (BCME_OK); +} + +extern SDIOH_API_RC +sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + spi_lock(sd); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + if (rw == SDIOH_READ) { + sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr)); + } else { + sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr, data)); + } + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) { + spi_unlock(sd); + return status; + } + + if (rw == SDIOH_READ) { + *byte = (uint8)data; + sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *byte)); + } + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus=0x%x\n", dstatus)); + + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, + uint32 *word, uint nbytes) +{ + int status; + + spi_lock(sd); + + if (rw == SDIOH_READ) + status = bcmspi_card_regread(sd, func, addr, nbytes, word); + else + status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); + + spi_unlock(sd); + return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + +extern SDIOH_API_RC +sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, + uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) +{ + int len; + int buflen = (int)buflen_u; + bool fifo = (fix_inc == SDIOH_DATA_FIX); + + spi_lock(sd); + + ASSERT(reg_width == 4); + ASSERT(buflen_u < (1 << 30)); + ASSERT(sd->client_block_size[func]); + + sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", + __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', + buflen_u, sd->r_cnt, sd->t_cnt, pkt)); + + /* Break buffer down into blocksize chunks. */ + while (buflen > 0) { + len = MIN(sd->client_block_size[func], buflen); + if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { + sd_err(("%s: bcmspi_card_buf %s failed\n", + __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); + spi_unlock(sd); + return SDIOH_API_RC_FAIL; + } + buffer += len; + buflen -= len; + if (!fifo) + addr += len; + } + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. + * Its main aim is to have simpler spi writes rather than recursive writes. + * e.g. When there is a need to program response delay on the fly after detecting the SPI-func + * this call will allow to program the response delay. + */ +static int +bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) +{ + uint32 cmd_arg; + uint32 datalen = 1; + uint32 hostlen; + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf2 = SPISWAP_WD4(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)spi_outbuf2 = SPISWAP_WD2(cmd_arg); + if (datalen & 0x1) + datalen++; + } else { + sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (datalen != 0) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD4(byte); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD2(byte); + } + } + + /* +4 for cmd, +4 for dstatus */ + hostlen = datalen + 8; + hostlen += (4 - (hostlen & 0x3)); + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +/* Program the response delay corresponding to the spi function */ +static int +bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) +{ + if (sd->resp_delay_all == FALSE) + return (BCME_OK); + + if (sd->prev_fun == func) + return (BCME_OK); + + if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) + return (BCME_OK); + + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); + + /* Remember function for which to avoid reprogramming resp-delay in next iteration */ + sd->prev_fun = func; + + return (BCME_OK); + +} + +#define GSPI_RESYNC_PATTERN 0x0 + +/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. + * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is + * synchronised and all queued resuests are cancelled. + */ +static int +bcmspi_resync_f1(sdioh_info_t *sd) +{ + uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + *(uint32 *)spi_outbuf2 = cmd_arg; + + /* for Write, put the data into the output buffer */ + *(uint32 *)&spi_outbuf2[CMDLEN] = data; + + /* +4 for cmd, +4 for dstatus */ + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +uint32 dstatus_count = 0; + +static int +bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) +{ + uint32 dstatus = sd->card_dstatus; + struct spierrstats_t *spierrstats = &sd->spierrstats; + int err = SUCCESS; + + sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); + + /* Store dstatus of last few gSPI transactions */ + spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; + spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; + dstatus_count++; + + if (sd->card_init_done == FALSE) + return err; + + if (dstatus & STATUS_DATA_NOT_AVAILABLE) { + spierrstats->dna++; + sd_trace(("Read data not available on F1 addr = 0x%x\n", + GFIELD(cmd_arg, SPI_REG_ADDR))); + /* Clear dna bit */ + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); + } + + if (dstatus & STATUS_UNDERFLOW) { + spierrstats->rdunderflow++; + sd_err(("FIFO underflow happened due to current F2 read command.\n")); + } + + if (dstatus & STATUS_OVERFLOW) { + spierrstats->wroverflow++; + sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); + bcmspi_resync_f1(sd); + sd_err(("Recovering from F1 FIFO overflow.\n")); + } + + if (dstatus & STATUS_F2_INTR) { + spierrstats->f2interrupt++; + sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_F3_INTR) { + spierrstats->f3interrupt++; + sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_HOST_CMD_DATA_ERR) { + spierrstats->hostcmddataerr++; + sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); + } + + if (dstatus & STATUS_F2_PKT_AVAILABLE) { + spierrstats->f2pktavailable++; + sd_trace(("Packet is available/ready in F2 TX FIFO\n")); + sd_trace(("Packet length = %d\n", sd->dwordmode ? + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); + } + + if (dstatus & STATUS_F3_PKT_AVAILABLE) { + spierrstats->f3pktavailable++; + sd_err(("Packet is available/ready in F3 TX FIFO\n")); + sd_err(("Packet length = %d\n", + (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); + } + + return err; +} + +extern int +sdioh_abort(sdioh_info_t *sd, uint func) +{ + return 0; +} + +int +sdioh_start(sdioh_info_t *sd, int stage) +{ + return SUCCESS; +} + +int +sdioh_stop(sdioh_info_t *sd) +{ + return SUCCESS; +} + +int +sdioh_waitlockfree(sdioh_info_t *sd) +{ + return SUCCESS; +} + + +/* + * Private/Static work routines + */ +static int +bcmspi_host_init(sdioh_info_t *sd) +{ + + /* Default power on mode */ + sd->sd_mode = SDIOH_MODE_SPI; + sd->polled_mode = TRUE; + sd->host_init_done = TRUE; + sd->card_init_done = FALSE; + sd->adapter_slot = 1; + + return (SUCCESS); +} + +static int +get_client_blocksize(sdioh_info_t *sd) +{ + uint32 regdata[2]; + int status; + + /* Find F1/F2/F3 max packet size */ + if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, + 8, regdata)) != SUCCESS) { + return status; + } + + sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", + regdata[0], regdata[1])); + + sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; + sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); + ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); + + sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; + sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); + ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); + + sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; + sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); + ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); + + return 0; +} + +static int +bcmspi_client_init(sdioh_info_t *sd) +{ + uint32 status_en_reg = 0; + sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); + +#ifndef BCMSPI_ANDROID +#ifdef HSMODE + if (!spi_start_clock(sd, (uint16)sd_divisor)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#else + /* Start at ~400KHz clock rate for initialization */ + if (!spi_start_clock(sd, 128)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* HSMODE */ +#endif /* !BCMSPI_ANDROID */ + + if (!bcmspi_host_device_init_adapt(sd)) { + sd_err(("bcmspi_host_device_init_adapt failed\n")); + return ERROR; + } + + if (!bcmspi_test_card(sd)) { + sd_err(("bcmspi_test_card failed\n")); + return ERROR; + } + + sd->num_funcs = SPI_MAX_IOFUNCS; + + get_client_blocksize(sd); + + /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ + bcmspi_resync_f1(sd); + + sd->dwordmode = FALSE; + + bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); + + sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); + status_en_reg |= INTR_WITH_STATUS; + + if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, + status_en_reg & 0xff) != SUCCESS) { + sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); + return ERROR; + } + +#ifndef HSMODE +#ifndef BCMSPI_ANDROID + /* After configuring for High-Speed mode, set the desired clock rate. */ + if (!spi_start_clock(sd, 4)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* !BCMSPI_ANDROID */ +#endif /* HSMODE */ + + /* check to see if the response delay needs to be programmed properly */ + { + uint32 f1_respdelay = 0; + bcmspi_card_regread(sd, 0, SPID_RESP_DELAY_F1, 1, &f1_respdelay); + if ((f1_respdelay == 0) || (f1_respdelay == 0xFF)) { + /* older sdiodevice core and has no separte resp delay for each of */ + sd_err(("older corerev < 4 so use the same resp delay for all funcs\n")); + sd->resp_delay_new = FALSE; + } + else { + /* older sdiodevice core and has no separte resp delay for each of */ + int ret_val; + sd->resp_delay_new = TRUE; + sd_err(("new corerev >= 4 so set the resp delay for each of the funcs\n")); + sd_trace(("resp delay for funcs f0(%d), f1(%d), f2(%d), f3(%d)\n", + GSPI_F0_RESP_DELAY, GSPI_F1_RESP_DELAY, + GSPI_F2_RESP_DELAY, GSPI_F3_RESP_DELAY)); + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F0, 1, + GSPI_F0_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F0\n", __FUNCTION__)); + return ERROR; + } + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F1, 1, + GSPI_F1_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F1\n", __FUNCTION__)); + return ERROR; + } + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F2, 1, + GSPI_F2_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); + return ERROR; + } + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F3, 1, + GSPI_F3_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); + return ERROR; + } + } + } + + + sd->card_init_done = TRUE; + + /* get the device rev to program the prop respdelays */ + + return SUCCESS; +} + +static int +bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, + 4, ®data)) != SUCCESS) + return status; + + sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); + + + if (hsmode == TRUE) { + sd_trace(("Attempting to enable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + sd_trace(("Device is already in High-Speed mode.\n")); + return status; + } else { + regdata |= HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) { + return status; + } + } + } else { + sd_trace(("Attempting to disable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + regdata &= ~HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) + return status; + } + else { + sd_trace(("Device is already in Low-Speed mode.\n")); + return status; + } + } +#ifndef BCMSPI_ANDROID + spi_controller_highspeed_mode(sd, hsmode); +#endif /* !BCMSPI_ANDROID */ + + return TRUE; +} + +#define bcmspi_find_curr_mode(sd) { \ + sd->wordlen = 2; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd->wordlen = 4; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd_trace(("Silicon testability issue: regdata = 0x%x." \ + " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ + OSL_DELAY(100000); \ +} + +#define INIT_ADAPT_LOOP 100 + +/* Adapt clock-phase-speed-bitwidth between host and device */ +static bool +bcmspi_host_device_init_adapt(sdioh_info_t *sd) +{ + uint32 wrregdata, regdata = 0; + int status; + int i; + + /* Due to a silicon testability issue, the first command from the Host + * to the device will get corrupted (first bit will be lost). So the + * Host should poll the device with a safe read request. ie: The Host + * should try to read F0 addr 0x14 using the Fixed address mode + * (This will prevent a unintended write command to be detected by device) + */ + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + /* If device was not power-cycled it will stay in 32bit mode with + * response-delay-all bit set. Alternate the iteration so that + * read either with or without response-delay for F0 to succeed. + */ + bcmspi_find_curr_mode(sd); + sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = TRUE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = FALSE; + } + + /* Bail out, device not detected */ + if (i == INIT_ADAPT_LOOP) + return FALSE; + + /* Softreset the spid logic */ + if ((sd->dwordmode) || (sd->wordlen == 4)) { + bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); + bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); + sd_trace(("reset reg read = 0x%x\n", regdata)); + sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, + sd->wordlen, sd->resp_delay_all)); + /* Restore default state after softreset */ + sd->wordlen = 2; + sd->dwordmode = FALSE; + } + + if (sd->wordlen == 4) { + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != + SUCCESS) + return FALSE; + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", + regdata)); + sd_trace(("Spid power was left on.\n")); + } else { + sd_err(("Spid power was left on but signature read failed." + " Value read = 0x%x\n", regdata)); + return FALSE; + } + } else { + sd->wordlen = 2; + +#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ + + wrregdata = (CTRL_REG_DEFAULT); + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); + +#ifndef HSMODE + wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); + wrregdata &= ~HIGH_SPEED_MODE; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); +#endif /* HSMODE */ + + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { + sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, + ®data)) != SUCCESS) + return FALSE; + } + OSL_DELAY(1000); + } + +#ifndef CUSTOMER_HW4 + /* Change to host controller intr-polarity of active-low */ + wrregdata &= ~INTR_POLARITY; +#else + /* Change to host controller intr-polarity of active-high */ + wrregdata |= INTR_POLARITY; +#endif + sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", + wrregdata)); + /* Change to 32bit mode */ + wrregdata |= WORD_LENGTH_32; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); + + /* Change command/data packaging in 32bit LE mode */ + sd->wordlen = 4; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); + sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); + } else { + sd_err(("Stale spid reg values read as it was kept powered. Value read =" + "0x%x\n", regdata)); + return FALSE; + } + } + + + return TRUE; +} + +static bool +bcmspi_test_card(sdioh_info_t *sd) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == (TEST_RO_DATA_32BIT_LE)) + sd_trace(("32bit LE regdata = 0x%x\n", regdata)); + else { + sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); + return FALSE; + } + + +#define RW_PATTERN1 0xA0A1A2A3 +#define RW_PATTERN2 0x4B5B6B7B + + regdata = RW_PATTERN1; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN1) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN1, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + regdata = RW_PATTERN2; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN2) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN2, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + return TRUE; +} + +static int +bcmspi_driver_init(sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if ((bcmspi_host_init(sd)) != SUCCESS) { + return ERROR; + } + + if (bcmspi_client_init(sd) != SUCCESS) { + return ERROR; + } + + return SUCCESS; +} + +/* Read device reg */ +static int +bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", + __FUNCTION__, cmd_arg, func, regaddr, regsize)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +static int +bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + + int status; + uint32 cmd_arg; + uint32 dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); + + sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", + __FUNCTION__, cmd_arg, func, regaddr, regsize)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) + return status; + + sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *data)); + + bcmspi_cmd_getdstatus(sd, &dstatus); + sd_trace(("dstatus =0x%x\n", dstatus)); + return SUCCESS; +} + +/* write a device register */ +static int +bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d data=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr, regsize, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus=0x%x\n", dstatus)); + + return SUCCESS; +} + +/* write a device register - 1 byte */ +static int +bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +void +bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) +{ + *dstatus_buffer = sd->card_dstatus; +} + +/* 'data' is of type uint32 whereas other buffers are of type uint8 */ +static int +bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen) +{ + uint32 i, j; + uint8 resp_delay = 0; + int err = SUCCESS; + uint32 hostlen; + uint32 spilen = 0; + uint32 dstatus_idx = 0; + uint16 templen, buslen, len, *ptr = NULL; + + sd_trace(("spi cmd = 0x%x\n", cmd_arg)); + + if (DWORDMODE_ON) { + spilen = GFIELD(cmd_arg, SPI_LEN); + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) || + (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1)) + dstatus_idx = spilen * 3; + + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + spilen = spilen << 2; + dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0; + /* convert len to mod16 size */ + spilen = ROUNDUP(spilen, 16); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } + } + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf = SPISWAP_WD4(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)spi_outbuf = SPISWAP_WD2(cmd_arg); + if (datalen & 0x1) + datalen++; + if (datalen < 4) + datalen = ROUNDUP(datalen, 4); + } else { + sd_err(("Host is %d bit spid, could not create SPI command.\n", + 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { + /* We send len field of hw-header always a mod16 size, both from host and dongle */ + if (DWORDMODE_ON) { + if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + /* ASSERT(*ptr == ~*(ptr + 1)); */ + templen = ROUNDUP(templen, 16); + *ptr = templen; + sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1)))); + } + } + + if (datalen != 0) { + for (i = 0; i < datalen/4; i++) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = + SPISWAP_WD4(data[i]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = + SPISWAP_WD2(data[i]); + } + } + } + } + + /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ + if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 0)) { + int func = GFIELD(cmd_arg, SPI_FUNCTION); + switch (func) { + case 0: + if (sd->resp_delay_new) + resp_delay = GSPI_F0_RESP_DELAY; + else + resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; + break; + case 1: + if (sd->resp_delay_new) + resp_delay = GSPI_F1_RESP_DELAY; + else + resp_delay = F1_RESPONSE_DELAY; + break; + case 2: + if (sd->resp_delay_new) + resp_delay = GSPI_F2_RESP_DELAY; + else + resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; + break; + default: + ASSERT(0); + break; + } + /* Program response delay */ + if (sd->resp_delay_new == FALSE) + bcmspi_prog_resp_delay(sd, func, resp_delay); + } + + /* +4 for cmd and +4 for dstatus */ + hostlen = datalen + 8 + resp_delay; + hostlen += dstatus_idx; +#ifdef BCMSPI_ANDROID + if (hostlen%4) { + sd_err(("Unaligned data len %d, hostlen %d\n", + datalen, hostlen)); +#endif /* BCMSPI_ANDROID */ + hostlen += (4 - (hostlen & 0x3)); +#ifdef BCMSPI_ANDROID + } +#endif /* BCMSPI_ANDROID */ + spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); + + /* for Read, get the data into the input buffer */ + if (datalen != 0) { + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ + for (j = 0; j < datalen/4; j++) { + if (sd->wordlen == 4) { /* 32bit spid */ + data[j] = SPISWAP_WD4(*(uint32 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + data[j] = SPISWAP_WD2(*(uint32 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay]); + } + } + + if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + buslen = len = ~(*(ptr + 1)); + buslen = ROUNDUP(buslen, 16); + /* populate actual len in hw-header */ + if (templen == buslen) + *ptr = len; + } + } + } + + /* Restore back the len field of the hw header */ + if (DWORDMODE_ON) { + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + ptr = (uint16 *)&data[0]; + *ptr = (uint16)(~*(ptr+1)); + } + } + + dstatus_idx += (datalen + CMDLEN + resp_delay); + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf[dstatus_idx]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf[dstatus_idx]); + } else { + sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", + 8 * sd->wordlen)); + return ERROR; + } + if (sd->card_dstatus == 0xffffffff) { + sd_err(("looks like not a GSPI device or device is not powered.\n")); + } + + err = bcmspi_update_stats(sd, cmd_arg); + + return err; + +} + +static int +bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data) +{ + int status; + uint32 cmd_arg; + bool write = rw == SDIOH_READ ? 0 : 1; + uint retries = 0; + + bool enable; + uint32 spilen; + + cmd_arg = 0; + + ASSERT(nbytes); + ASSERT(nbytes <= sd->client_block_size[func]); + + if (write) sd->t_cnt++; else sd->r_cnt++; + + if (func == 2) { + /* Frame len check limited by gSPI. */ + if ((nbytes > 2000) && write) { + sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); + } + /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ + /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ + if (write) { + uint32 dstatus; + /* check F2 ready with cached one */ + bcmspi_cmd_getdstatus(sd, &dstatus); + if ((dstatus & STATUS_F2_RX_READY) == 0) { + retries = WAIT_F2RXFIFORDY; + enable = 0; + while (retries-- && !enable) { + OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); + bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, + &dstatus); + if (dstatus & STATUS_F2_RX_READY) + enable = TRUE; + } + if (!enable) { + struct spierrstats_t *spierrstats = &sd->spierrstats; + spierrstats->f2rxnotready++; + sd_err(("F2 FIFO is not ready to receive data.\n")); + return ERROR; + } + sd_trace(("No of retries on F2 ready %d\n", + (WAIT_F2RXFIFORDY - retries))); + } + } + } + + /* F2 transfers happen on 0 addr */ + addr = (func == 2) ? 0 : addr; + + /* In pio mode buffer is read using fixed address fifo in func 1 */ + if ((func == 1) && (fifo)) + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); + else + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); + + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); + spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); + if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + /* convert len to mod4 size */ + spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } else + cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); + + if ((func == 2) && (fifo == 1)) { + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + } + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, nbytes)) != SUCCESS) { + sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, + (write ? "write" : "read"))); + return status; + } + + /* gSPI expects that hw-header-len is equal to spi-command-len */ + if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { + ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); + ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); + } + + if ((nbytes > 2000) && !write) { + sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); + } + + return SUCCESS; +} + +/* Reset and re-initialize the device */ +int +sdioh_sdio_reset(sdioh_info_t *si) +{ + si->card_init_done = FALSE; + return bcmspi_client_init(si); +} + +SDIOH_API_RC +sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) +{ + return SDIOH_API_RC_FAIL; +} + +SDIOH_API_RC +sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) +{ + return SDIOH_API_RC_FAIL; +} + +bool +sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) +{ + return FALSE; +} + +SDIOH_API_RC +sdioh_gpio_init(sdioh_info_t *sd) +{ + return SDIOH_API_RC_FAIL; +} diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c index 0d92efc6a62..06461956bdc 100644 --- a/drivers/net/wireless/bcmdhd/bcmutils.c +++ b/drivers/net/wireless/bcmdhd/bcmutils.c @@ -1695,10 +1695,17 @@ static const char *crypto_algo_names[] = { "AES_CCM", "AES_OCB_MSDU", "AES_OCB_MPDU", +#ifdef BCMCCX + "CKIP", + "CKIP_MMH", + "WEP_MMH", + "NALG" +#else "NALG" "UNDEF", "UNDEF", "UNDEF", +#endif /* BCMCCX */ #ifdef BCMWAPI_WPI "WAPI", #endif /* BCMWAPI_WPI */ diff --git a/drivers/net/wireless/bcmdhd/bcmwifi.c b/drivers/net/wireless/bcmdhd/bcmwifi.c index bc975e8be1b..70722170bdf 100644 --- a/drivers/net/wireless/bcmdhd/bcmwifi.c +++ b/drivers/net/wireless/bcmdhd/bcmwifi.c @@ -3,9 +3,9 @@ * Contents are wifi-specific, used by any kernel or app-level * software that might want wifi things as it grows. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2011, Broadcom Corporation * - * Unless you and Broadcom execute a separate written software license + * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the @@ -22,10 +22,10 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmwifi.c 309193 2012-01-19 00:03:57Z $ + * $Id: bcmwifi.c,v 1.31.8.1 2010-08-03 17:47:05 Exp $ */ -#include + #include #ifdef BCMDRIVER @@ -47,10 +47,6 @@ #include #endif -#ifndef D11AC_IOTYPES - - - @@ -88,7 +84,7 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf) chanspec_t -wf_chspec_aton(const char *a) +wf_chspec_aton(char *a) { char *endp = NULL; uint channel, band, bw, ctl_sb; @@ -161,7 +157,7 @@ wf_chspec_malformed(chanspec_t chanspec) return TRUE; - if (CHSPEC_IS20(chanspec)) { + if (CHSPEC_IS20_UNCOND(chanspec)) { if (!CHSPEC_SB_NONE(chanspec)) return TRUE; } else { @@ -221,658 +217,6 @@ wf_chspec_ctlchspec(chanspec_t chspec) return ctl_chspec; } -#else - - - - - - -static const char *wf_chspec_bw_str[] = -{ - "5", - "10", - "20", - "40", - "80", - "160", - "80+80", - "na" -}; - -static const uint8 wf_chspec_bw_mhz[] = -{5, 10, 20, 40, 80, 160, 160}; - -#define WF_NUM_BW \ - (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) - - -static const uint8 wf_5g_40m_chans[] = -{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; -#define WF_NUM_5G_40M_CHANS \ - (sizeof(wf_5g_40m_chans)/sizeof(uint8)) - - -static const uint8 wf_5g_80m_chans[] = -{42, 58, 106, 122, 138, 155}; -#define WF_NUM_5G_80M_CHANS \ - (sizeof(wf_5g_80m_chans)/sizeof(uint8)) - - -static const uint8 wf_5g_160m_chans[] = -{50, 114}; -#define WF_NUM_5G_160M_CHANS \ - (sizeof(wf_5g_160m_chans)/sizeof(uint8)) - - - -static uint -bw_chspec_to_mhz(chanspec_t chspec) -{ - uint bw; - - bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; - return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); -} - - -static uint8 -center_chan_to_edge(uint bw) -{ - - return (uint8)(((bw - 20) / 2) / 5); -} - - -static uint8 -channel_low_edge(uint center_ch, uint bw) -{ - return (uint8)(center_ch - center_chan_to_edge(bw)); -} - - -static int -channel_to_sb(uint center_ch, uint ctl_ch, uint bw) -{ - uint lowest = channel_low_edge(center_ch, bw); - uint sb; - - if ((ctl_ch - lowest) % 4) { - - return -1; - } - - sb = ((ctl_ch - lowest) / 4); - - - if (sb >= (bw / 20)) { - - return -1; - } - - return sb; -} - - -static uint8 -channel_to_ctl_chan(uint center_ch, uint bw, uint sb) -{ - return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); -} - - -static int -channel_80mhz_to_id(uint ch) -{ - uint i; - for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { - if (ch == wf_5g_80m_chans[i]) - return i; - } - - return -1; -} - - -char * -wf_chspec_ntoa(chanspec_t chspec, char *buf) -{ - const char *band; - uint ctl_chan; - - if (wf_chspec_malformed(chspec)) - return NULL; - - band = ""; - - - if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || - (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) - band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; - - - ctl_chan = wf_chspec_ctlchan(chspec); - - - if (CHSPEC_IS20(chspec)) { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); - } else if (!CHSPEC_IS8080(chspec)) { - const char *bw; - const char *sb = ""; - - bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; - -#ifdef CHANSPEC_NEW_40MHZ_FORMAT - - if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { - sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; - } - - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); -#else - - if (CHSPEC_IS40(chspec)) { - sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; - snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); - } else { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); - } -#endif - - } else { - - uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; - uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; - - - chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; - chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; - - - snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); - } - - return (buf); -} - -static int -read_uint(const char **p, unsigned int *num) -{ - unsigned long val; - char *endp = NULL; - - val = strtoul(*p, &endp, 10); - - if (endp == *p) - return 0; - - - *p = endp; - - *num = (unsigned int)val; - - return 1; -} - - -chanspec_t -wf_chspec_aton(const char *a) -{ - chanspec_t chspec; - uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; - uint num, ctl_ch; - uint ch1, ch2; - char c, sb_ul = '\0'; - int i; - - bw = 20; - chspec_sb = 0; - chspec_ch = ch1 = ch2 = 0; - - - if (!read_uint(&a, &num)) - return 0; - - - c = tolower(a[0]); - if (c == 'g') { - a ++; - - - if (num == 2) - chspec_band = WL_CHANSPEC_BAND_2G; - else if (num == 5) - chspec_band = WL_CHANSPEC_BAND_5G; - else - return 0; - - - if (!read_uint(&a, &ctl_ch)) - return 0; - - c = tolower(a[0]); - } - else { - - ctl_ch = num; - chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); - } - - if (c == '\0') { - - chspec_bw = WL_CHANSPEC_BW_20; - goto done_read; - } - - a ++; - - - if (c == 'u' || c == 'l') { - sb_ul = c; - chspec_bw = WL_CHANSPEC_BW_40; - goto done_read; - } - - - if (c != '/') - return 0; - - - if (!read_uint(&a, &bw)) - return 0; - - - if (bw == 20) { - chspec_bw = WL_CHANSPEC_BW_20; - } else if (bw == 40) { - chspec_bw = WL_CHANSPEC_BW_40; - } else if (bw == 80) { - chspec_bw = WL_CHANSPEC_BW_80; - } else if (bw == 160) { - chspec_bw = WL_CHANSPEC_BW_160; - } else { - return 0; - } - - - - c = tolower(a[0]); - - - if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { - if (c == 'u' || c == 'l') { - a ++; - sb_ul = c; - goto done_read; - } - } - - - if (c == '+') { - - static const char *plus80 = "80/"; - - - chspec_bw = WL_CHANSPEC_BW_8080; - - a ++; - - - for (i = 0; i < 3; i++) { - if (*a++ != *plus80++) { - return 0; - } - } - - - if (!read_uint(&a, &ch1)) - return 0; - - - if (a[0] != '-') - return 0; - a ++; - - - if (!read_uint(&a, &ch2)) - return 0; - } - -done_read: - - while (a[0] == ' ') { - a ++; - } - - - if (a[0] != '\0') - return 0; - - - - - if (sb_ul != '\0') { - if (sb_ul == 'l') { - chspec_ch = UPPER_20_SB(ctl_ch); - chspec_sb = WL_CHANSPEC_CTL_SB_LLL; - } else if (sb_ul == 'u') { - chspec_ch = LOWER_20_SB(ctl_ch); - chspec_sb = WL_CHANSPEC_CTL_SB_LLU; - } - } - - else if (chspec_bw == WL_CHANSPEC_BW_20) { - chspec_ch = ctl_ch; - chspec_sb = 0; - } - - else if (chspec_bw != WL_CHANSPEC_BW_8080) { - - const uint8 *center_ch = NULL; - int num_ch = 0; - int sb = -1; - - if (chspec_bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - } else { - return 0; - } - - for (i = 0; i < num_ch; i ++) { - sb = channel_to_sb(center_ch[i], ctl_ch, bw); - if (sb >= 0) { - chspec_ch = center_ch[i]; - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; - break; - } - } - - - if (sb < 0) { - return 0; - } - } - - else { - int ch1_id = 0, ch2_id = 0; - int sb; - - ch1_id = channel_80mhz_to_id(ch1); - ch2_id = channel_80mhz_to_id(ch2); - - - if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0) - return 0; - - - chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | - ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); - - - - - sb = channel_to_sb(ch1, ctl_ch, bw); - if (sb < 0) { - - sb = channel_to_sb(ch2, ctl_ch, bw); - if (sb < 0) { - - return 0; - } - - sb += 4; - } - - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; - } - - chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); - - if (wf_chspec_malformed(chspec)) - return 0; - - return chspec; -} - - -bool -wf_chspec_malformed(chanspec_t chanspec) -{ - uint chspec_bw = CHSPEC_BW(chanspec); - uint chspec_ch = CHSPEC_CHANNEL(chanspec); - - - if (CHSPEC_IS2G(chanspec)) { - - if (chspec_bw != WL_CHANSPEC_BW_20 && - chspec_bw != WL_CHANSPEC_BW_40) { - return TRUE; - } - } else if (CHSPEC_IS5G(chanspec)) { - if (chspec_bw == WL_CHANSPEC_BW_8080) { - uint ch1_id, ch2_id; - - - ch1_id = CHSPEC_CHAN1(chanspec); - ch2_id = CHSPEC_CHAN2(chanspec); - if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) - return TRUE; - - - if (ch2_id <= ch1_id) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || - chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { - - if (chspec_ch > MAXCHANNEL) { - return TRUE; - } - } else { - - return TRUE; - } - } else { - - return TRUE; - } - - - if (chspec_bw == WL_CHANSPEC_BW_20) { - if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_40) { - if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) - return TRUE; - } - - return FALSE; -} - - -bool -wf_chspec_valid(chanspec_t chanspec) -{ - uint chspec_bw = CHSPEC_BW(chanspec); - uint chspec_ch = CHSPEC_CHANNEL(chanspec); - - if (wf_chspec_malformed(chanspec)) - return FALSE; - - if (CHSPEC_IS2G(chanspec)) { - - if (chspec_bw == WL_CHANSPEC_BW_20) { - if (chspec_ch >= 1 && chspec_ch <= 14) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_40) { - if (chspec_ch >= 3 && chspec_ch <= 11) - return TRUE; - } - } else if (CHSPEC_IS5G(chanspec)) { - if (chspec_bw == WL_CHANSPEC_BW_8080) { - uint16 ch1, ch2; - - ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; - ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; - - - if (ch2 > ch1 + CH_80MHZ_APART) - return TRUE; - } else { - const uint8 *center_ch; - uint num_ch, i; - - if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - } else { - - return FALSE; - } - - - if (chspec_bw == WL_CHANSPEC_BW_20) { - - for (i = 0; i < num_ch; i ++) { - if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || - chspec_ch == (uint)UPPER_20_SB(center_ch[i])) - break; - } - - if (i == num_ch) { - - if (chspec_ch == 34 || chspec_ch == 38 || - chspec_ch == 42 || chspec_ch == 46) - i = 0; - } - } else { - - for (i = 0; i < num_ch; i ++) { - if (chspec_ch == center_ch[i]) - break; - } - } - - if (i < num_ch) { - - return TRUE; - } - } - } - - return FALSE; -} - - -uint8 -wf_chspec_ctlchan(chanspec_t chspec) -{ - uint center_chan; - uint bw_mhz; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - - - if (CHSPEC_IS20(chspec)) { - return CHSPEC_CHANNEL(chspec); - } else { - sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; - - if (CHSPEC_IS8080(chspec)) { - bw_mhz = 80; - - if (sb < 4) { - center_chan = CHSPEC_CHAN1(chspec); - } - else { - center_chan = CHSPEC_CHAN2(chspec); - sb -= 4; - } - - - center_chan = wf_5g_80m_chans[center_chan]; - } - else { - bw_mhz = bw_chspec_to_mhz(chspec); - center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; - } - - return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); - } -} - - -chanspec_t -wf_chspec_ctlchspec(chanspec_t chspec) -{ - chanspec_t ctl_chspec = chspec; - uint8 ctl_chan; - - ASSERT(!wf_chspec_malformed(chspec)); - - - if (!CHSPEC_IS20(chspec)) { - ctl_chan = wf_chspec_ctlchan(chspec); - ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; - ctl_chspec |= CHSPEC_BAND(chspec); - } - return ctl_chspec; -} - -#endif - - -extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) -{ - chanspec_t chspec40 = chspec; - uint center_chan; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - - if (CHSPEC_IS80(chspec)) { - center_chan = CHSPEC_CHANNEL(chspec); - sb = CHSPEC_CTL_SB(chspec); - - if (sb == WL_CHANSPEC_CTL_SB_UL) { - - sb = WL_CHANSPEC_CTL_SB_L; - center_chan += CH_20MHZ_APART; - } else if (sb == WL_CHANSPEC_CTL_SB_UU) { - - sb = WL_CHANSPEC_CTL_SB_U; - center_chan += CH_20MHZ_APART; - } else { - - - center_chan -= CH_20MHZ_APART; - } - - - chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | - sb | center_chan); - } - - return chspec40; -} - int wf_mhz2channel(uint freq, uint start_factor) diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index c3e05c9796c..94cbe912fe1 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd.h 329678 2012-04-26 08:51:32Z $ + * $Id: dhd.h 356711 2012-09-13 15:58:32Z $ */ /**************** @@ -58,6 +58,12 @@ int setScheduler(struct task_struct *p, int policy, struct sched_param *param); #include #include +#include + +#if defined(CUSTOMER_HW4_RELEASE) +/* Customer requirement */ +#undef CONFIG_WIRELESS_EXT +#endif /* Forward decls */ struct dhd_bus; @@ -71,24 +77,33 @@ enum dhd_bus_state { DHD_BUS_DATA /* Ready for frame transfers */ }; - +enum dhd_op_flags { /* Firmware requested operation mode */ -#define STA_MASK 0x0001 -#define HOSTAPD_MASK 0x0002 -#define WFD_MASK 0x0004 -#define SOFTAP_FW_MASK 0x0008 -#define P2P_GO_ENABLED 0x0010 -#define P2P_GC_ENABLED 0x0020 -#define CONCURENT_MASK 0x00F0 + DHD_FLAG_STA_MODE = BIT(0), /* STA only */ + DHD_FLAG_HOSTAP_MODE = BIT(1), /* SOFTAP only */ + DHD_FLAG_P2P_MODE = BIT(2), /* P2P Only */ + /* STA + P2P */ + DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), + DHD_FLAG_CONCURR_MULTI_CHAN_MODE = BIT(4), /* STA + P2P */ + /* Current P2P mode for P2P connection */ + DHD_FLAG_P2P_GC_MODE = BIT(5), + DHD_FLAG_P2P_GO_MODE = BIT(6), + DHD_FLAG_MBSS_MODE = BIT(7) /* MBSS in future */ +}; + +#define MANUFACTRING_FW "WLTEST" /* max sequential rxcntl timeouts to set HANG event */ +#ifndef MAX_CNTL_TIMEOUT #define MAX_CNTL_TIMEOUT 2 +#endif -#define DHD_SCAN_ACTIVE_TIME 40 /* ms : Embedded default Active setting from DHD Driver */ -#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD Driver */ +#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ +#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ +#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ #ifndef POWERUP_MAX_RETRY -#define POWERUP_MAX_RETRY (10) /* how many times we retry to power up the chip */ +#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ #endif #ifndef POWERUP_WAIT_MS #define POWERUP_WAIT_MS (2000) /* ms: time out in waiting wifi to come up */ @@ -115,7 +130,15 @@ enum dhd_prealloc_index { DHD_PREALLOC_PROT = 0, DHD_PREALLOC_RXBUF, DHD_PREALLOC_DATABUF, +#if defined(STATIC_WL_PRIV_STRUCT) + DHD_PREALLOC_OSL_BUF, + DHD_PREALLOC_WIPHY_ESCAN0 = 5, +#if defined(DUAL_ESCAN_RESULT_BUFFER) + DHD_PREALLOC_WIPHY_ESCAN1 +#endif +#else DHD_PREALLOC_OSL_BUF +#endif /* STATIC_WL_PRIV_STRUCT */ }; typedef enum { @@ -237,9 +260,6 @@ typedef struct dhd_pub { */ /* #define WL_ENABLE_P2P_IF 1 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) - struct wake_lock wakelock[WAKE_LOCK_MAX]; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ @@ -251,8 +271,12 @@ typedef struct dhd_pub { #ifdef PROP_TXSTATUS int wlfc_enabled; void* wlfc_state; +#endif +#ifdef ROAM_AP_ENV_DETECTION + bool roam_env_detection; #endif bool dongle_isolation; + bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ int hang_was_sent; int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ int txcnt_timeout; /* counter txcnt timeout to send HANG */ @@ -260,6 +284,9 @@ typedef struct dhd_pub { uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ #endif struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; +#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) + struct wake_lock pno_wakelock; +#endif } dhd_pub_t; @@ -271,19 +298,29 @@ typedef struct dhd_pub { SMP_RD_BARRIER_DEPENDS(); \ while (dhd_mmc_suspend && retry++ != b) { \ SMP_RD_BARRIER_DEPENDS(); \ - wait_event_interruptible_timeout(a, !dhd_mmc_suspend, HZ/100); \ + wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ } \ } while (0) #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) +#ifdef CUSTOMER_HW4 + #define DHD_PM_RESUME_RETURN_ERROR(a) do { \ + if (dhd_mmc_suspend) { \ + printf("%s[%d]: mmc is still in suspend state!!!\n", \ + __FUNCTION__, __LINE__); \ + return a; \ + } \ + } while (0) +#else #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0) +#endif /* CUSTOMER_HW4 */ #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); #define SPINWAIT_SLEEP(a, exp, us) do { \ uint countdown = (us) + 9999; \ while ((exp) && (countdown >= 10000)) { \ - wait_event_interruptible_timeout(a, FALSE, HZ/100); \ + wait_event_interruptible_timeout(a, FALSE, 1); \ countdown -= 10000; \ } \ } while (0) @@ -319,7 +356,8 @@ void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); extern int dhd_os_wake_lock(dhd_pub_t *pub); extern int dhd_os_wake_unlock(dhd_pub_t *pub); extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); -extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val); +extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); +extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) { @@ -342,10 +380,34 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ } +#ifdef DHD_DEBUG_WAKE_LOCK +#define DHD_OS_WAKE_LOCK(pub) \ + do { \ + printf("call wake_lock: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_lock(pub); \ + } while (0) +#define DHD_OS_WAKE_UNLOCK(pub) \ + do { \ + printf("call wake_unlock: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_unlock(pub); \ + } while (0) +#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) \ + do { \ + printf("call wake_lock_timeout: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_lock_timeout(pub); \ + } while (0) +#else #define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) #define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) #define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) -#define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub, val) dhd_os_wake_lock_timeout_enable(pub, val) +#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ + dhd_os_wake_lock_rx_timeout_enable(pub, val) +#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ + dhd_os_wake_lock_ctrl_timeout_enable(pub, val) +#endif /* DHD_DEBUG_WAKE_LOCK */ #define DHD_PACKET_TIMEOUT_MS 1000 #define DHD_EVENT_TIMEOUT_MS 1500 @@ -449,6 +511,8 @@ extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); +extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); +extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); #ifdef PNO_SUPPORT extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); @@ -463,22 +527,27 @@ extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); extern int dhd_dev_get_pno_status(struct net_device *dev); #endif /* PNO_SUPPORT */ +#ifdef PKT_FILTER_SUPPORT #define DHD_UNICAST_FILTER_NUM 0 #define DHD_BROADCAST_FILTER_NUM 1 #define DHD_MULTICAST4_FILTER_NUM 2 #define DHD_MULTICAST6_FILTER_NUM 3 -extern int net_os_set_packet_filter(struct net_device *dev, int val); +#define DHD_MDNS_FILTER_NUM 4 +extern void dhd_set_packet_filter(dhd_pub_t *dhd); +extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); +extern int net_os_enable_packet_filter(struct net_device *dev, int val); extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); +#endif /* PKT_FILTER_SUPPORT */ extern int dhd_get_dtim_skip(dhd_pub_t *dhd); -extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd); +extern bool dhd_support_sta_mode(dhd_pub_t *dhd); #ifdef DHD_DEBUG extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); #endif /* DHD_DEBUG */ -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr); -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ extern void dhd_os_sdtxlock(dhd_pub_t * pub); extern void dhd_os_sdtxunlock(dhd_pub_t * pub); @@ -495,6 +564,7 @@ extern int dhd_timeout_expired(dhd_timeout_t *tmo); extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); extern struct net_device * dhd_idx2net(void *pub, int ifidx); +extern int net_os_send_hang_message(struct net_device *dev); extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, wl_event_msg_t *, void **data_ptr); extern void wl_event_to_host_order(wl_event_msg_t * evt); @@ -529,8 +599,10 @@ extern uint dhd_bus_status(dhd_pub_t *dhdp); extern int dhd_bus_start(dhd_pub_t *dhdp); extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); -extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf); +extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); +extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); +extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); #if defined(KEEP_ALIVE) extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); @@ -540,7 +612,7 @@ extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); extern void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); extern void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); #endif /* ARP_OFFLOAD_SUPPORT */ - +extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); typedef enum cust_gpio_modes { WLAN_RESET_ON, @@ -595,7 +667,11 @@ extern uint dhd_radio_up; /* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ extern int dhd_idletime; +#ifdef DHD_USE_IDLECOUNT +#define DHD_IDLETIME_TICKS 5 +#else #define DHD_IDLETIME_TICKS 1 +#endif /* DHD_USE_IDLECOUNT */ /* SDIO Drive Strength */ extern uint dhd_sdiod_drive_strength; @@ -603,9 +679,37 @@ extern uint dhd_sdiod_drive_strength; /* Override to force tx queueing all the time */ extern uint dhd_force_tx_queueing; /* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ -#define KEEP_ALIVE_PERIOD 55000 +#define KEEP_ALIVE_PERIOD 28000 #define NULL_PKT_STR "null_pkt" +/* hooks for custom glom setting option via Makefile */ +#define DEFAULT_GLOM_VALUE -1 +#ifndef CUSTOM_GLOM_SETTING +#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE +#endif + +/* hooks for custom Roaming Trigger setting via Makefile */ +#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ +#define DEFAULT_ROAM_TRIGGER_SETTING -1 +#ifndef CUSTOM_ROAM_TRIGGER_SETTING +#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE +#endif + +/* hooks for custom Roaming Romaing setting via Makefile */ +#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ +#define DEFAULT_ROAM_DELTA_SETTING -1 +#ifndef CUSTOM_ROAM_DELTA_SETTING +#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE +#endif + + +/* hooks for custom dhd_dpc_prio setting option via Makefile */ +#define DEFAULT_DHP_DPC_PRIO 1 +#ifndef CUSTOM_DPC_PRIO_SETTING +#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO +#endif + + #ifdef SDTEST /* Echo packet generator (SDIO), pkts/s */ extern uint dhd_pktgen; @@ -621,6 +725,8 @@ extern uint dhd_pktgen_len; extern char fw_path[MOD_PARAM_PATHLEN]; extern char nv_path[MOD_PARAM_PATHLEN]; +#define MOD_PARAM_INFOLEN 512 + #ifdef SOFTAP extern char fw_path2[MOD_PARAM_PATHLEN]; #endif @@ -628,10 +734,20 @@ extern char fw_path2[MOD_PARAM_PATHLEN]; /* Flag to indicate if we should download firmware on driver load */ extern uint dhd_download_fw_on_driverload; +#if defined(WL_CFG80211) && defined(SUPPORT_DEEP_SLEEP) +/* Flags to indicate if we distingish power off policy when + * user set the memu "Keep Wi-Fi on during sleep" to "Never" + */ +extern int sleep_never; +int dhd_deepsleep(struct net_device *dev, int flag); +#endif /* WL_CFG80211 && SUPPORT_DEEP_SLEEP */ + /* For supporting multiple interfaces */ #define DHD_MAX_IFS 16 #define DHD_DEL_IF -0xe #define DHD_BAD_IF -0xf +#define WL_AUTO_ROAM_TRIGGER -75 + #ifdef PROP_TXSTATUS /* Please be mindful that total pkttag space is 32 octets only */ @@ -786,4 +902,11 @@ int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen); void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr); #endif /* ARP_OFFLOAD_SUPPORT */ +#if defined(CUSTOMER_HW4) && defined(RDWR_KORICS_MACADDR) +extern int +dhd_write_rdwr_korics_macaddr(struct dhd_info *dhd, struct ether_addr *mac); +#endif +#if defined(SUPPORT_MULTIPLE_REVISION) +extern int concate_revision(struct dhd_bus *bus, char *path, int path_len); +#endif /* SUPPORT_MULTIPLE_REVISION */ #endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_bus.h b/drivers/net/wireless/bcmdhd/dhd_bus.h index 36267719214..fcb4bbd65c8 100644 --- a/drivers/net/wireless/bcmdhd/dhd_bus.h +++ b/drivers/net/wireless/bcmdhd/dhd_bus.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_bus.h 313456 2012-02-07 22:03:40Z $ + * $Id: dhd_bus.h 347614 2012-07-27 10:24:51Z $ */ #ifndef _dhd_bus_h_ @@ -106,4 +106,6 @@ extern uint dhd_bus_hdrlen(struct dhd_bus *bus); extern int dhd_bus_reg_sdio_notify(void* semaphore); extern void dhd_bus_unreg_sdio_notify(void); +extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable); + #endif /* _dhd_bus_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c index abd08731cde..cd44b9246b4 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_cdc.c 328424 2012-04-19 05:23:09Z $ + * $Id: dhd_cdc.c 355825 2012-09-10 03:22:40Z $ * * BDC is like CDC, except it includes a header for data packets to convey * packet priority over the bus, and flags (e.g. to indicate checksum status @@ -49,7 +49,7 @@ #define RETRIES 2 /* # of retries to retrieve matching ioctl response */ -#define BUS_HEADER_LEN (16+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE +#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE * defined in dhd_sdio.c (amount of header tha might be added) * plus any space that might be needed for alignment padding. */ @@ -69,6 +69,12 @@ typedef struct dhd_wlfc_commit_info { } dhd_wlfc_commit_info_t; #endif /* PROP_TXSTATUS */ +#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) +extern uint sd_f2_blocksize; +extern int +dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size); +#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ + typedef struct dhd_prot { uint16 reqid; uint8 pending; @@ -113,12 +119,20 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); +#if defined(CUSTOMER_HW4) + DHD_OS_WAKE_LOCK(dhd); +#endif + do { ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); if (ret < 0) break; } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); +#if defined(CUSTOMER_HW4) + DHD_OS_WAKE_UNLOCK(dhd); +#endif + return ret; } @@ -152,6 +166,16 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uin memset(msg, 0, sizeof(cdc_ioctl_t)); +#ifdef BCMSPI + /* 11bit gSPI bus allows 2048bytes of max-data. We restrict 'len' + * value which is 8Kbytes for various 'get' commands to 2000. 48 bytes are + * left for sw headers and misc. + */ + if (len > 2000) { + DHD_ERROR(("dhdcdc_query_ioctl: len is truncated to 2000 bytes\n")); + len = 2000; + } +#endif /* BCMSPI */ msg->cmd = htol32(cmd); msg->len = htol32(len); msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); @@ -210,6 +234,10 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uin return ret; } +#ifdef CONFIG_CONTROL_PM +extern bool g_pm_control; +#endif + static int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) { @@ -233,6 +261,14 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 return -EIO; } +#ifdef CONFIG_CONTROL_PM + if ((g_pm_control == TRUE) && (cmd == WLC_SET_PM)) + { + DHD_ERROR(("SET PM ignored!!!!!!!!!!!!!!!!!!!!!!\n")); + goto done; + } +#endif + memset(msg, 0, sizeof(cdc_ioctl_t)); msg->cmd = htol32(cmd); @@ -680,6 +716,32 @@ dhd_wlfc_hanger_get_free_slot(void* hanger) return WLFC_HANGER_MAXITEMS; } +static int +dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + *gen = 0xff; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + + if (h) { + if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || + (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { + *gen = h->items[slot_id].gen; + } + else { + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + static int dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) { @@ -714,13 +776,14 @@ dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_f return BCME_NOTFOUND; if (h) { - if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { + if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { *pktout = h->items[slot_id].pkt; if (remove_from_hanger) { h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_FREE; h->items[slot_id].pkt = NULL; h->items[slot_id].identifier = 0; + h->items[slot_id].gen = 0xff; h->popped++; } } @@ -734,6 +797,29 @@ dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_f return rc; } +static int +dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + if (h) { + h->items[slot_id].gen = gen; + if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { + h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; + } + else + rc = BCME_BADARG; + } + else + rc = BCME_BADARG; + + return rc; +} + static int _dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) @@ -803,6 +889,12 @@ _dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) /* pull BDC header */ PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); + + if (PKTLEN(ctx->osh, pktbuf) < (h->dataOffset << 2)) { + WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); + return BCME_ERROR; + } /* pull wl-header */ PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); return BCME_OK; @@ -865,7 +957,15 @@ _dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, } else { /* remove header first */ - _dhd_wlfc_pullheader(ctx, p); + rc = _dhd_wlfc_pullheader(ctx, p); + if (rc != BCME_OK) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + /* free the hanger slot */ + dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); + PKTFREE(ctx->osh, p, TRUE); + rc = BCME_ERROR; + return rc; + } if (pkt_type == eWLFC_PKTTYPE_DELAYED) { /* delay-q packets are going to delay-q */ @@ -1063,6 +1163,8 @@ _dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); + WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); + entry->transit_count++; } else { hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); @@ -1073,7 +1175,6 @@ _dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); - WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { /* @@ -1111,14 +1212,20 @@ _dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, } } else { + int gen; + /* remove old header */ - _dhd_wlfc_pullheader(ctx, p); + rc = _dhd_wlfc_pullheader(ctx, p); + if (rc == BCME_OK) { + hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); - hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - /* push new header */ - _dhd_wlfc_pushheader(ctx, p, send_tim_update, - entry->traffic_lastreported_bmp, entry->mac_handle, htod); + WLFC_PKTFLAG_SET_GENERATION(htod, gen); + free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + /* push new header */ + _dhd_wlfc_pushheader(ctx, p, send_tim_update, + entry->traffic_lastreported_bmp, entry->mac_handle, htod); + } } *slot = hslot; return rc; @@ -1177,19 +1284,29 @@ _dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { p = pktq_mdeq(&entry->psq, /* higher precedence will be picked up first, - i.e. suppressed packets before delayed ones - */ - (NBITVAL((prec << 1) + 1) | NBITVAL((prec << 1))), - &pout); - if (p != NULL) { - /* did the packet come from suppress sub-queue? */ - if (pout == ((prec << 1) + 1)) { - /* - this packet was suppressed and was sent on the bus - previously; this already has a header - */ + * i.e. suppressed packets before delayed ones + */ + NBITVAL((prec << 1) + 1), &pout); *needs_hdr = 0; + + if (p == NULL) { + if (entry->suppressed == TRUE) { + if ((entry->suppr_transit_count <= + entry->suppress_count)) { + entry->suppressed = FALSE; + } else { + return NULL; + } + } + /* De-Q from delay Q */ + p = pktq_mdeq(&entry->psq, + NBITVAL((prec << 1)), + &pout); + *needs_hdr = 1; } + + if (p != NULL) { + /* did the packet come from suppress sub-queue? */ if (entry->requested_credit > 0) { entry->requested_credit--; #ifdef PROP_TXSTATUS_DEBUG @@ -1649,36 +1766,6 @@ dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) } } - /* packets from SENDQ are fresh and they'd need header and have no MAC entry */ - commit_info.needs_hdr = 1; - commit_info.mac_entry = NULL; - commit_info.pkt_type = eWLFC_PKTTYPE_NEW; - - for (; (credit_count > 0);) { - - commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac); - if (commit_info.p == NULL) - break; - - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent) { - (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac); - credit_count--; - } - } - else { - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n")); - return rc; - } - } - } - return BCME_OK; } @@ -1707,12 +1794,15 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) void* p; int fifo_id; + dhd_os_wlfc_block(dhd); if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { #ifdef PROP_TXSTATUS_DEBUG wlfc->stats.signal_only_pkts_freed++; #endif - /* is this a signal-only packet? */ - PKTFREE(wlfc->osh, txp, TRUE); + if (success) + /* is this a signal-only packet? */ + PKTFREE(wlfc->osh, txp, TRUE); + dhd_os_wlfc_unblock(dhd); return; } if (!success) { @@ -1747,6 +1837,7 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) PKTFREE(wlfc->osh, txp, TRUE); } + dhd_os_wlfc_unblock(dhd); return; } @@ -1793,10 +1884,16 @@ dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) return ret; } + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + if (!remove_from_hanger) { /* this packet was suppressed */ - - entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { + entry->suppressed = TRUE; + entry->suppress_count = pktq_mlen(&entry->psq, + NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); + entry->suppr_transit_count = entry->transit_count; + } entry->generation = WLFC_PKTID_GEN(status); } @@ -1863,6 +1960,7 @@ dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) } if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { + ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); if (ret != BCME_OK) { /* delay q is full, drop this packet */ @@ -1871,11 +1969,29 @@ dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) /* indicate failure and free the packet */ dhd_txcomplete(dhd, pktbuf, FALSE); + entry->transit_count--; + /* This packet is transmitted Successfully by + * dongle even after first suppress. + */ + if (entry->suppressed) { + entry->suppr_transit_count--; + } PKTFREE(wlfc->osh, pktbuf, TRUE); + } else { + /* Mark suppressed to avoid a double free during wlfc cleanup */ + dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, + WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); + entry->suppress_count++; } } else { dhd_txcomplete(dhd, pktbuf, TRUE); + entry->transit_count--; + + /* This packet is transmitted Successfully by dongle even after first suppress. */ + if (entry->suppressed) { + entry->suppr_transit_count--; + } /* free the packet */ PKTFREE(wlfc->osh, pktbuf, TRUE); } @@ -1924,6 +2040,19 @@ dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) return BCME_OK; } +static int +dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) +{ + uint32 timestamp; + + (void)dhd; + + bcopy(&value[2], ×tamp, sizeof(uint32)); + DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp)); + return BCME_OK; +} + + static int dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) { @@ -2188,6 +2317,9 @@ dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar (type == WLFC_CTL_TYPE_MACDESC_DEL)) dhd_wlfc_mac_table_update(dhd, value, type); + else if (type == WLFC_CTL_TYPE_TRANS_ID) + dhd_wlfc_dbg_senum_check(dhd, value); + else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { dhd_wlfc_interface_update(dhd, value, type); @@ -2210,6 +2342,7 @@ dhd_wlfc_init(dhd_pub_t *dhd) WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS | WLFC_FLAGS_CREDIT_STATUS_SIGNALS | + WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */ @@ -2285,7 +2418,9 @@ dhd_wlfc_enable(dhd_pub_t *dhd) wlfc->allow_credit_borrow = TRUE; wlfc->borrow_defer_timestamp = 0; - +#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) + dhdsdio_func_blocksize(dhd, 2, VSDB_F2_BLKSIZE); +#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ return BCME_OK; } @@ -2299,10 +2434,15 @@ dhd_wlfc_cleanup(dhd_pub_t *dhd) dhd->wlfc_state; wlfc_mac_descriptor_t* table; wlfc_hanger_t* h; - + int prec; + void *pkt = NULL; + struct pktq *txq = NULL; if (dhd->wlfc_state == NULL) return; - + /* flush bus->txq */ + txq = dhd_bus_txq(dhd->bus); + /* any in the hanger? */ + h = (wlfc_hanger_t*)wlfc->hanger; total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); /* search all entries, include nodes as well as interfaces */ table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; @@ -2321,11 +2461,41 @@ dhd_wlfc_cleanup(dhd_pub_t *dhd) /* release packets held in SENDQ */ if (wlfc->SENDQ.len) pktq_flush(wlfc->osh, &wlfc->SENDQ, TRUE, NULL, 0); - /* any in the hanger? */ - h = (wlfc_hanger_t*)wlfc->hanger; + for (prec = 0; prec < txq->num_prec; prec++) { + pkt = pktq_pdeq(txq, prec); + while (pkt) { + for (i = 0; i < h->max_items; i++) { + if (pkt == h->items[i].pkt) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { + PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + h->items[i].pkt = NULL; + h->items[i].identifier = 0; + } else if (h->items[i].state == + WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { + /* These are already freed from the psq */ + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } + break; + } + } + pkt = pktq_pdeq(txq, prec); + } + } + /* flush remained pkt in hanger queue, not in bus->txq */ for (i = 0; i < h->max_items; i++) { if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { - PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); + if (!dhd->hang_was_sent) { + PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); + } else { + printk("%s: Skip freeing skb %p\n", __func__, h->items[i].pkt); + } + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + h->items[i].pkt = NULL; + h->items[i].identifier = 0; + } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { + /* These are freed from the psq so no need to free again */ + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; } } return; @@ -2338,15 +2508,17 @@ dhd_wlfc_deinit(dhd_pub_t *dhd) athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) dhd->wlfc_state; - if (dhd->wlfc_state == NULL) + dhd_os_wlfc_block(dhd); + if (dhd->wlfc_state == NULL) { + dhd_os_wlfc_unblock(dhd); return; - + } #ifdef PROP_TXSTATUS_DEBUG { int i; wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; for (i = 0; i < h->max_items; i++) { - if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { + if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", __FUNCTION__, i, h->items[i].pkt, DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); @@ -2360,6 +2532,10 @@ dhd_wlfc_deinit(dhd_pub_t *dhd) /* free top structure */ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); dhd->wlfc_state = NULL; +#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) + dhdsdio_func_blocksize(dhd, 2, sd_f2_blocksize); +#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ + dhd_os_wlfc_unblock(dhd); return; } #endif /* PROP_TXSTATUS */ @@ -2369,8 +2545,10 @@ dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) { bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); #ifdef PROP_TXSTATUS + dhd_os_wlfc_block(dhdp); if (dhdp->wlfc_state) dhd_wlfc_dump(dhdp, strbuf); + dhd_os_wlfc_unblock(dhdp); #endif } @@ -2639,8 +2817,6 @@ dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reord *pkt_count = 0; return 0; } - cur_pkt = *pkt; - *pkt = NULL; flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; @@ -2657,6 +2833,9 @@ dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reord return 0; } + cur_pkt = *pkt; + *pkt = NULL; + ptr = dhd->reorder_bufs[flow_id]; if (flags & WLHOST_REORDERDATA_DEL_FLOW) { uint32 buf_size = sizeof(struct reorder_info); @@ -2668,6 +2847,7 @@ dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reord DHD_ERROR(("%s: received flags to cleanup, but no flow (%d) yet\n", __FUNCTION__, flow_id)); *pkt_count = 1; + *pkt = cur_pkt; return 0; } diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c index 556459076b1..e6a68371e89 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -80,8 +80,7 @@ s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) { dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); dhd->op_mode |= val; - WL_ERR(("Set : op_mode=%d\n", dhd->op_mode)); - + WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode)); #ifdef ARP_OFFLOAD_SUPPORT /* IF P2P is enabled, disable arpoe */ dhd_arp_offload_set(dhd, 0); @@ -94,10 +93,10 @@ s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl) { dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - dhd->op_mode &= ~CONCURENT_MASK; - WL_ERR(("Clean : op_mode=%d\n", dhd->op_mode)); + dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); + WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode)); -#ifdef ARP_OFFLOAD_SUPPORT +#if defined(ARP_OFFLOAD_SUPPORT) /* IF P2P is disabled, enable arpoe back for STA mode. */ dhd_arp_offload_set(dhd, dhd_arp_mode); dhd_arp_offload_enable(dhd, true); @@ -420,7 +419,7 @@ static void wl_cfg80211_bt_handler(struct work_struct *work) __FUNCTION__)); btcx_inf->bt_state = BT_DHCP_OPPR_WIN; mod_timer(&btcx_inf->timer, - jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000); + jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); btcx_inf->timer_on = 1; break; @@ -440,7 +439,7 @@ static void wl_cfg80211_bt_handler(struct work_struct *work) wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; mod_timer(&btcx_inf->timer, - jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000); + jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); btcx_inf->timer_on = 1; break; @@ -540,26 +539,20 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) #ifdef PKT_FILTER_SUPPORT dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - int i; #endif /* Figure out powermode 1 or o command */ strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { - - WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); + WL_TRACE_HW4(("%s: DHCP session starts\n", __FUNCTION__)); #ifdef PKT_FILTER_SUPPORT dhd->dhcp_in_progress = 1; - /* Disable packet filtering */ - if (dhd_pkt_filter_enable && dhd->early_suspended) { - WL_TRACE(("DHCP in progressing , disable packet filter!!!\n")); - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 0, dhd_master_mode); - } + if (dhd->early_suspended) { + WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n")); + dhd_enable_packet_filter(0, dhd); } #endif @@ -609,14 +602,12 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) #ifdef PKT_FILTER_SUPPORT dhd->dhcp_in_progress = 0; + WL_TRACE_HW4(("%s: DHCP is complete \n", __FUNCTION__)); /* Enable packet filtering */ - if (dhd_pkt_filter_enable && dhd->early_suspended) { - WL_TRACE(("DHCP is complete , enable packet filter!!!\n")); - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 1, dhd_master_mode); - } + if (dhd->early_suspended) { + WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); + dhd_enable_packet_filter(1, dhd); } #endif diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 580355401c0..dab96860b54 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c 327331 2012-04-13 01:42:33Z $ + * $Id: dhd_common.c 356374 2012-09-12 10:37:44Z $ */ #include #include @@ -93,6 +93,9 @@ extern int dhd_iscan_in_progress(void *h); void dhd_iscan_lock(void); void dhd_iscan_unlock(void); extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); +#if !defined(AP) && defined(WLP2P) +extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); +#endif bool ap_cfg_running = FALSE; bool ap_fw_loaded = FALSE; @@ -274,10 +277,30 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int le dhd_os_proto_block(dhd_pub); ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); - if (!ret) +#if defined(CUSTOMER_HW4) + if ((ret || ret == -ETIMEDOUT) && (dhd_pub->up)) +#else + if ((ret) && (dhd_pub->up)) +#endif /* CUSTOMER_HW4 */ + /* Send hang event only if dhd_open() was success */ dhd_os_check_hang(dhd_pub, ifindex, ret); dhd_os_proto_unblock(dhd_pub); + +#if defined(CUSTOMER_HW4) + if (ret < 0) { + if (ioc->cmd == WLC_GET_VAR) + DHD_ERROR(("%s: WLC_GET_VAR: %s, ret = %d\n", + __FUNCTION__, (char *)ioc->buf, ret)); + else if (ioc->cmd == WLC_SET_VAR) + DHD_ERROR(("%s: WLC_SET_VAR: %s, ret = %d\n", + __FUNCTION__, (char *)ioc->buf, ret)); + else + DHD_ERROR(("%s: WLC_IOCTL: cmd: %d, ret = %d\n", + __FUNCTION__, ioc->cmd, ret)); + } +#endif + return ret; } @@ -309,12 +332,15 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch break; case IOV_SVAL(IOV_MSGLEVEL): - dhd_msg_level = int_val; #ifdef WL_CFG80211 /* Enable DHD and WL logs in oneshot */ - if (dhd_msg_level & DHD_WL_VAL) - wl_cfg80211_enable_trace(dhd_msg_level); -#endif + if (int_val & DHD_WL_VAL2) + wl_cfg80211_enable_trace(TRUE, int_val & (~DHD_WL_VAL2)); + else if (int_val & DHD_WL_VAL) + wl_cfg80211_enable_trace(FALSE, WL_DBG_DBG); + if (!(int_val & DHD_WL_VAL2)) +#endif /* WL_CFG80211 */ + dhd_msg_level = int_val; break; case IOV_GVAL(IOV_BCMERRORSTR): bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); @@ -553,8 +579,7 @@ dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) if (pktq_pfull(q, prec)) eprec = prec; else if (pktq_full(q)) { - p = pktq_peek_tail(q, &eprec); - ASSERT(p); + pktq_peek_tail(q, &eprec); if (eprec > prec || eprec < 0) return FALSE; } @@ -574,8 +599,7 @@ dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) } /* Enqueue */ - p = pktq_penq(q, prec, pkt); - ASSERT(p); + pktq_penq(q, prec, pkt); return TRUE; } @@ -734,7 +758,7 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) datalen = ntoh32(event->datalen); /* debug dump of event messages */ - sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x", + snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", (uchar)event->addr.octet[0]&0xff, (uchar)event->addr.octet[1]&0xff, (uchar)event->addr.octet[2]&0xff, @@ -794,7 +818,7 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) else if (auth_type == DOT11_SHARED_KEY) auth_str = "Shared Key"; else { - sprintf(err_msg, "AUTH unknown: %d", (int)auth_type); + snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); auth_str = err_msg; } if (event_type == WLC_E_AUTH_IND) { @@ -1042,7 +1066,8 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, DHD_ERROR(("%s: ifidx %d for %s action %d\n", __FUNCTION__, ifevent->ifidx, event->ifname, ifevent->action)); - if (ifevent->action == WLC_E_IF_ADD) + if (ifevent->action == WLC_E_IF_ADD || + ifevent->action == WLC_E_IF_CHANGE) wl_cfg80211_notify_ifchange(); return (BCME_OK); } @@ -1172,9 +1197,11 @@ dhd_print_buf(void *pbuf, int len, int bytes_per_line) printf("\n"); #endif /* DHD_DEBUG */ } - +#ifndef strtoul #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#endif +#ifdef PKT_FILTER_SUPPORT /* Convert user's input in hex pattern to byte-size mask */ static int wl_pattern_atoh(char *src, char *dst) @@ -1410,6 +1437,7 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) if (buf) MFREE(dhd->osh, buf, BUF_SIZE); } +#endif /* PKT_FILTER_SUPPORT */ /* ========================== */ /* ==== ARP OFFLOAD SUPPORT = */ @@ -1738,7 +1766,7 @@ dhd_iscan_get_partial_result(void *dhdp, uint *scan_count) /* * returns = TRUE if associated, FALSE if not associated */ -bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf) +bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) { char bssid[6], zbuf[6]; int ret = -1; @@ -1753,6 +1781,9 @@ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf) DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); } + if (retval) + *retval = ret; + if (ret < 0) return FALSE; @@ -1785,7 +1816,7 @@ dhd_get_dtim_skip(dhd_pub_t *dhd) bcn_li_dtim = dhd->dtim_skip; /* Check if associated */ - if (dhd_is_associated(dhd, NULL) == FALSE) { + if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); goto exit; } @@ -1824,30 +1855,16 @@ dhd_get_dtim_skip(dhd_pub_t *dhd) return bcn_li_dtim; } -/* Check if HostAPD or WFD mode setup */ -bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd) +/* Check if the mode supports STA MODE */ +bool dhd_support_sta_mode(dhd_pub_t *dhd) { + #ifdef WL_CFG80211 -#ifndef WL_ENABLE_P2P_IF - /* To be back compatble with ICS MR1 release where p2p interface - * disable but wlan0 used for p2p - */ - if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) || - ((dhd->op_mode & WFD_MASK) == WFD_MASK)) { - return TRUE; - } - else -#else - /* concurent mode with p2p interface for wfd and wlan0 for sta */ - if (((dhd->op_mode & P2P_GO_ENABLED) == P2P_GO_ENABLED) || - ((dhd->op_mode & P2P_GC_ENABLED) == P2P_GC_ENABLED)) { - DHD_ERROR(("%s P2P enabled for mode=%d\n", __FUNCTION__, dhd->op_mode)); - return TRUE; - } + if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) + return FALSE; else -#endif /* WL_ENABLE_P2P_IF */ #endif /* WL_CFG80211 */ - return FALSE; + return TRUE; } #if defined(PNO_SUPPORT) @@ -1892,15 +1909,17 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) return ret; } - if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) +#ifndef WL_SCHED_SCAN + if (!dhd_support_sta_mode(dhd)) return (ret); memset(iovbuf, 0, sizeof(iovbuf)); - if ((pfn_enabled) && (dhd_is_associated(dhd, NULL) == TRUE)) { + if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) { DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__)); return ret; } +#endif /* !WL_SCHED_SCAN */ /* Enable/disable PNO */ if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { @@ -1934,14 +1953,17 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr)); - if ((!dhd) && (!ssids_local)) { - DHD_ERROR(("%s error exit\n", __FUNCTION__)); + if ((!dhd) || (!ssids_local)) { + DHD_ERROR(("%s error exit(%s %s)\n", __FUNCTION__, + (!dhd)?"dhd is null":"", (!ssids_local)?"ssid is null":"")); err = -1; return err; } - if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) - return (err); +#ifndef WL_SCHED_SCAN + if (!dhd_support_sta_mode(dhd)) + return err; +#endif /* !WL_SCHED_SCAN */ /* Check for broadcast ssid */ for (k = 0; k < nssid; k++) { @@ -2058,8 +2080,8 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd) int str_len; int res = -1; - if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) - return (res); + if (!dhd_support_sta_mode(dhd)) + return res; DHD_TRACE(("%s execution\n", __FUNCTION__)); @@ -2076,6 +2098,7 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd) mkeep_alive_pkt.keep_alive_id = 0; mkeep_alive_pkt.len_bytes = 0; buf_len += WL_MKEEP_ALIVE_FIXED_LEN; + bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no * guarantee that the buffer is properly aligned. @@ -2096,7 +2119,7 @@ int wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, int input_size, int *bytes_left) { - char* str = *list_str; + char* str; uint16 short_temp; uint32 int_temp; @@ -2104,6 +2127,7 @@ wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, DHD_ERROR(("%s error paramters\n", __FUNCTION__)); return -1; } + str = *list_str; /* Clean all dest bytes */ memset(dst, 0, dst_size); @@ -2145,13 +2169,14 @@ int wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, int channel_num, int *bytes_left) { - char* str = *list_str; + char* str; int idx = 0; if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { DHD_ERROR(("%s error paramters\n", __FUNCTION__)); return -1; } + str = *list_str; while (*bytes_left > 0) { @@ -2290,7 +2315,8 @@ wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) ssid[idx].SSID_len = 0; if (idx < max) { - bcm_strcpy_s((char*)ssid[idx].SSID, sizeof(ssid[idx].SSID), str); + bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); + strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); ssid[idx].SSID_len = strlen(str); } idx++; diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c index 9a9d182e6b8..9421e98dee2 100644 --- a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c @@ -20,7 +20,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * -* $Id: dhd_custom_gpio.c 291086 2011-10-21 01:17:24Z $ +* $Id: dhd_custom_gpio.c 353167 2012-08-24 22:11:30Z $ */ #include @@ -41,7 +41,7 @@ extern void bcm_wlan_power_off(int); extern void bcm_wlan_power_on(int); #endif /* CUSTOMER_HW */ -#if defined(CUSTOMER_HW2) +#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4) #ifdef CONFIG_WIFI_CONTROL_FUNC int wifi_set_power(int on, unsigned long msec); int wifi_get_irq_number(unsigned long *irq_flags_ptr); @@ -53,9 +53,9 @@ int wifi_get_irq_number(unsigned long *irq_flags_ptr) { return -1; } int wifi_get_mac_addr(unsigned char *buf) { return -1; } void *wifi_get_country_code(char *ccode) { return NULL; } #endif /* CONFIG_WIFI_CONTROL_FUNC */ -#endif /* CUSTOMER_HW2 */ +#endif /* CUSTOMER_HW2 || CUSTOMER_HW4 */ -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) #if defined(BCMLXSDMMC) extern int sdioh_mmc_irq(int irq); @@ -86,7 +86,7 @@ int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) { int host_oob_irq = 0; -#ifdef CUSTOMER_HW2 +#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4) host_oob_irq = wifi_get_irq_number(irq_flags_ptr); #else @@ -94,7 +94,7 @@ int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) if (dhd_oob_gpio_num < 0) { dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; } -#endif /* CUSTOMER_HW2 */ +#endif /* CUSTOMER_OOB_GPIO_NUM */ if (dhd_oob_gpio_num < 0) { WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", @@ -112,11 +112,11 @@ int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); gpio_direction_input(dhd_oob_gpio_num); #endif /* CUSTOMER_HW */ -#endif /* CUSTOMER_HW2 */ +#endif /* CUSTOMER_HW2 || CUSTOMER_HW4 */ return (host_oob_irq); } -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ /* Customer function to control hw specific wlan gpios */ void @@ -129,7 +129,7 @@ dhd_customer_gpio_wlan_ctrl(int onoff) #ifdef CUSTOMER_HW bcm_wlan_power_off(2); #endif /* CUSTOMER_HW */ -#ifdef CUSTOMER_HW2 +#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4) wifi_set_power(0, 0); #endif WL_ERROR(("=========== WLAN placed in RESET ========\n")); @@ -141,7 +141,7 @@ dhd_customer_gpio_wlan_ctrl(int onoff) #ifdef CUSTOMER_HW bcm_wlan_power_on(2); #endif /* CUSTOMER_HW */ -#ifdef CUSTOMER_HW2 +#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4) wifi_set_power(1, 0); #endif WL_ERROR(("=========== WLAN going back to live ========\n")); @@ -195,6 +195,7 @@ dhd_custom_get_mac_address(unsigned char *buf) } #endif /* GET_CUSTOM_MAC_ENABLE */ +#ifndef CUSTOMER_HW4 /* Customized Locale table : OPTIONAL feature */ const struct cntry_locales_custom translate_custom_table[] = { /* Table should be filled out based on custom platform regulatory requirement */ @@ -291,3 +292,4 @@ void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) return; #endif /* defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) */ } +#endif /* CUSTOMER_HW4 */ diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_sec.c b/drivers/net/wireless/bcmdhd/dhd_custom_sec.c new file mode 100644 index 00000000000..1683501ee7f --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_custom_sec.c @@ -0,0 +1,1197 @@ +/* + * Customer HW 4 dependant file + * + * Copyright (C) 1999-2012, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_custom_sec.c 334946 2012-05-24 20:38:00Z $ + */ +#ifdef CUSTOMER_HW4 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +struct dhd_info; +extern int _dhd_set_mac_address(struct dhd_info *dhd, + int ifidx, struct ether_addr *addr); + +struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ + char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ + int32 custom_locale_rev; /* Custom local revisin default -1 */ +}; + +/* Locale table for sec */ +const struct cntry_locales_custom translate_custom_table[] = { +#ifdef BCM4334_CHIP + {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ +#endif + {"AE", "AE", 1}, + {"AR", "AR", 1}, + {"AT", "AT", 1}, + {"AU", "AU", 2}, + {"BE", "BE", 1}, + {"BG", "BG", 1}, + {"BN", "BN", 1}, + {"CA", "CA", 2}, + {"CH", "CH", 1}, + {"CN", "CN", 0}, + {"CY", "CY", 1}, + {"CZ", "CZ", 1}, + {"DE", "DE", 3}, + {"DK", "DK", 1}, + {"EE", "EE", 1}, + {"ES", "ES", 1}, + {"FI", "FI", 1}, + {"FR", "FR", 1}, + {"GB", "GB", 1}, + {"GR", "GR", 1}, + {"HR", "HR", 1}, + {"HU", "HU", 1}, + {"IE", "IE", 1}, + {"IS", "IS", 1}, + {"IT", "IT", 1}, + {"JP", "JP", 5}, + {"KR", "KR", 24}, + {"KW", "KW", 1}, + {"LI", "LI", 1}, + {"LT", "LT", 1}, + {"LU", "LU", 1}, + {"LV", "LV", 1}, + {"MA", "MA", 1}, + {"MT", "MT", 1}, + {"MX", "MX", 1}, + {"NL", "NL", 1}, + {"NO", "NO", 1}, + {"PL", "PL", 1}, + {"PT", "PT", 1}, + {"PY", "PY", 1}, + {"RO", "RO", 1}, + {"SE", "SE", 1}, + {"SI", "SI", 1}, + {"SK", "SK", 1}, + {"TR", "TR", 7}, + {"UA", "UA", 2}, + {"TW", "TW", 2}, + {"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ + {"SD", "XZ", 11}, /* Universal if Country code is SUDAN */ + {"SY", "XZ", 11}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ + {"GL", "XZ", 11}, /* Universal if Country code is GREENLAND */ + {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ + {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ + {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ + {"PK", "XZ", 11}, /* Universal if Country code is PAKISTAN */ +#ifdef BCM4334_CHIP + {"RU", "RU", 5}, + {"SG", "SG", 4}, + {"US", "US", 46} +#endif +#ifdef BCM4330_CHIP + {"RU", "RU", 1}, + {"US", "US", 5} +#endif +}; + +/* Customized Locale convertor +* input : ISO 3166-1 country abbreviation +* output: customized cspec +*/ +void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) +{ + int size, i; + + size = ARRAYSIZE(translate_custom_table); + + if (cspec == 0) + return; + + if (size == 0) + return; + + for (i = 0; i < size; i++) { + if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { + memcpy(cspec->ccode, + translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = translate_custom_table[i].custom_locale_rev; + return; + } + } + return; +} + +#ifdef SLP_PATH +#define CIDINFO "/opt/etc/.cid.info" +#define PSMINFO "/opt/etc/.psm.info" +#define MACINFO "/opt/etc/.mac.info" +#define MACINFO_EFS NULL +#define REVINFO "/data/.rev" +#else +#define MACINFO "/data/.mac.info" +#define MACINFO_EFS "/efs/wifi/.mac.info" +#define NVMACINFO "/data/.nvmac.info" +#define REVINFO "/data/.rev" +#define CIDINFO "/data/.cid.info" +#define PSMINFO "/data/.psm.info" +#endif /* SLP_PATH */ + +#ifdef READ_MACADDR +int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac) +{ + struct file *fp = NULL; + char macbuffer[18] = {0}; + mm_segment_t oldfs = {0}; + char randommac[3] = {0}; + char buf[18] = {0}; + char *filepath_efs = MACINFO_EFS; +#ifdef CONFIG_TARGET_LOCALE_VZW + char *nvfilepath = "/data/misc/wifi/.nvmac.info"; +#else + char *nvfilepath = NVMACINFO; +#endif + int ret = 0; + + fp = filp_open(filepath_efs, O_RDONLY, 0); + if (IS_ERR(fp)) { +start_readmac: + /* File Doesn't Exist. Create and write mac addr. */ + fp = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); + if (IS_ERR(fp)) { + DHD_ERROR(("[WIFI] %s: File open error\n", filepath_efs)); + return -1; + } + oldfs = get_fs(); + set_fs(get_ds()); + + /* Generating the Random Bytes for 3 last octects of the MAC address */ + get_random_bytes(randommac, 3); + + sprintf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", + 0x00, 0x12, 0x34, randommac[0], randommac[1], randommac[2]); + DHD_ERROR(("[WIFI]The Random Generated MAC ID: %s\n", macbuffer)); + + if (fp->f_mode & FMODE_WRITE) { + ret = fp->f_op->write(fp, (const char *)macbuffer, + sizeof(macbuffer), &fp->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI]MAC address [%s] Failed to write into File: %s\n", + macbuffer, filepath_efs)); + else + DHD_ERROR(("[WIFI]MAC address [%s] written into File: %s\n", + macbuffer, filepath_efs)); + } + set_fs(oldfs); + /* Reading the MAC Address from .mac.info file + ( the existed file or just created file) + */ + ret = kernel_read(fp, 0, buf, 18); + } else { + /* Reading the MAC Address from + .mac.info file( the existed file or just created file) + */ + ret = kernel_read(fp, 0, buf, 18); +/* to prevent abnormal string display when mac address is displayed on the screen. */ + buf[17] = '\0'; + if (strncmp(buf, "00:00:00:00:00:00", 17) < 1) { + DHD_ERROR(("goto start_readmac \r\n")); + filp_close(fp, NULL); + goto start_readmac; + } + } + + if (ret) + sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + (unsigned int *)&(mac->octet[0]), (unsigned int *)&(mac->octet[1]), + (unsigned int *)&(mac->octet[2]), (unsigned int *)&(mac->octet[3]), + (unsigned int *)&(mac->octet[4]), (unsigned int *)&(mac->octet[5])); + else + DHD_ERROR(("dhd_bus_start: Reading from the '%s' returns 0 bytes\n", filepath_efs)); + + if (fp) + filp_close(fp, NULL); + + /* Writing Newly generated MAC ID to the Dongle */ + if (_dhd_set_mac_address(dhd, 0, mac) == 0) + DHD_INFO(("dhd_bus_start: MACID is overwritten\n")); + else + DHD_ERROR(("dhd_bus_start: _dhd_set_mac_address() failed\n")); + + return 0; +} +#endif /* READ_MACADDR */ + +#ifdef RDWR_MACADDR +static int g_imac_flag; + +enum { + MACADDR_NONE = 0, + MACADDR_MOD, + MACADDR_MOD_RANDOM, + MACADDR_MOD_NONE, + MACADDR_COB, + MACADDR_COB_RANDOM +}; + +int dhd_write_rdwr_macaddr(struct ether_addr *mac) +{ + char *filepath_data = MACINFO; + char *filepath_efs = MACINFO_EFS; + struct file *fp_mac = NULL; + char buf[18] = {0}; + mm_segment_t oldfs = {0}; + int ret = -1; + + if ((g_imac_flag != MACADDR_COB) && (g_imac_flag != MACADDR_MOD)) + return 0; + + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X\n", + mac->octet[0], mac->octet[1], mac->octet[2], + mac->octet[3], mac->octet[4], mac->octet[5]); + + /* /data/.mac.info will be created */ + fp_mac = filp_open(filepath_data, O_RDWR | O_CREAT, 0666); + if (IS_ERR(fp_mac)) { + DHD_ERROR(("[WIFI] %s: File open error\n", filepath_data)); + return -1; + } else { + oldfs = get_fs(); + set_fs(get_ds()); + + if (fp_mac->f_mode & FMODE_WRITE) { + ret = fp_mac->f_op->write(fp_mac, (const char *)buf, + sizeof(buf), &fp_mac->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI] Mac address [%s] Failed" + " to write into File: %s\n", buf, filepath_data)); + else + DHD_INFO(("[WIFI] Mac address [%s] written" + " into File: %s\n", buf, filepath_data)); + } + set_fs(oldfs); + filp_close(fp_mac, NULL); + } + /* /efs/wifi/.mac.info will be created */ + fp_mac = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); + if (IS_ERR(fp_mac)) { + DHD_ERROR(("[WIFI] %s: File open error\n", filepath_efs)); + return -1; + } else { + oldfs = get_fs(); + set_fs(get_ds()); + + if (fp_mac->f_mode & FMODE_WRITE) { + ret = fp_mac->f_op->write(fp_mac, (const char *)buf, + sizeof(buf), &fp_mac->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI] Mac address [%s] Failed" + " to write into File: %s\n", buf, filepath_efs)); + else + DHD_INFO(("[WIFI] Mac address [%s] written" + " into File: %s\n", buf, filepath_efs)); + } + set_fs(oldfs); + filp_close(fp_mac, NULL); + } + + return 0; + +} + +int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, + struct ether_addr *mac) +{ + struct file *fp_mac = NULL; + struct file *fp_nvm = NULL; + char macbuffer[18] = {0}; + char randommac[3] = {0}; + char buf[18] = {0}; + char *filepath_data = MACINFO; + char *filepath_efs = MACINFO_EFS; +#ifdef CONFIG_TARGET_LOCALE_NA + char *nvfilepath = "/data/misc/wifi/.nvmac.info"; +#else + char *nvfilepath = NVMACINFO; +#endif + char cur_mac[128] = {0}; + char dummy_mac[ETHER_ADDR_LEN] = {0x00, 0x90, 0x4C, 0xC5, 0x12, 0x38}; + char cur_macbuffer[18] = {0}; + int ret = -1; + + g_imac_flag = MACADDR_NONE; + + fp_nvm = filp_open(nvfilepath, O_RDONLY, 0); + if (IS_ERR(fp_nvm)) { /* file does not exist */ + + /* Create the .nvmac.info */ + fp_nvm = filp_open(nvfilepath, O_RDWR | O_CREAT, 0666); + if (!IS_ERR(fp_nvm)) + filp_close(fp_nvm, NULL); + + /* read MAC Address */ + strcpy(cur_mac, "cur_etheraddr"); + ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, cur_mac, + sizeof(cur_mac), 0, 0); + if (ret < 0) { + DHD_ERROR(("Current READ MAC error \r\n")); + memset(cur_mac, 0, ETHER_ADDR_LEN); + return -1; + } else { + DHD_ERROR(("MAC (OTP) : " + "[%02X:%02X:%02X:%02X:%02X:%02X] \r\n", + cur_mac[0], cur_mac[1], cur_mac[2], cur_mac[3], + cur_mac[4], cur_mac[5])); + } + + sprintf(cur_macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", + cur_mac[0], cur_mac[1], cur_mac[2], + cur_mac[3], cur_mac[4], cur_mac[5]); + + fp_mac = filp_open(filepath_data, O_RDONLY, 0); + if (IS_ERR(fp_mac)) { /* file does not exist */ + /* read mac is the dummy mac (00:90:4C:C5:12:38) */ + if (memcmp(cur_mac, dummy_mac, ETHER_ADDR_LEN) == 0) + g_imac_flag = MACADDR_MOD_RANDOM; + else if (strncmp(buf, "00:00:00:00:00:00", 17) == 0) + g_imac_flag = MACADDR_MOD_RANDOM; + else + g_imac_flag = MACADDR_MOD; + } else { + int is_zeromac; + + ret = kernel_read(fp_mac, 0, buf, 18); + filp_close(fp_mac, NULL); + buf[17] = '\0'; + + is_zeromac = strncmp(buf, "00:00:00:00:00:00", 17); + DHD_ERROR(("MAC (FILE): [%s] [%d] \r\n", + buf, is_zeromac)); + + if (is_zeromac == 0) { + DHD_ERROR(("Zero MAC detected." + " Trying Random MAC.\n")); + g_imac_flag = MACADDR_MOD_RANDOM; + } else { + sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + (unsigned int *)&(mac->octet[0]), + (unsigned int *)&(mac->octet[1]), + (unsigned int *)&(mac->octet[2]), + (unsigned int *)&(mac->octet[3]), + (unsigned int *)&(mac->octet[4]), + (unsigned int *)&(mac->octet[5])); + /* current MAC address is same as previous one */ + if (memcmp(cur_mac, mac->octet, ETHER_ADDR_LEN) == 0) { + g_imac_flag = MACADDR_NONE; + } else { /* change MAC address */ + if (_dhd_set_mac_address(dhd, 0, mac) == 0) { + DHD_INFO(("%s: MACID is" + " overwritten\n", __FUNCTION__)); + g_imac_flag = MACADDR_MOD; + } else { + DHD_ERROR(("%s: " + "_dhd_set_mac_address()" + " failed\n", __FUNCTION__)); + g_imac_flag = MACADDR_NONE; + } + } + } + } + fp_mac = filp_open(filepath_efs, O_RDONLY, 0); + if (IS_ERR(fp_mac)) { /* file does not exist */ + /* read mac is the dummy mac (00:90:4C:C5:12:38) */ + if (memcmp(cur_mac, dummy_mac, ETHER_ADDR_LEN) == 0) + g_imac_flag = MACADDR_MOD_RANDOM; + else if (strncmp(buf, "00:00:00:00:00:00", 17) == 0) + g_imac_flag = MACADDR_MOD_RANDOM; + else + g_imac_flag = MACADDR_MOD; + } else { + int is_zeromac; + + ret = kernel_read(fp_mac, 0, buf, 18); + filp_close(fp_mac, NULL); + buf[17] = '\0'; + + is_zeromac = strncmp(buf, "00:00:00:00:00:00", 17); + DHD_ERROR(("MAC (FILE): [%s] [%d] \r\n", + buf, is_zeromac)); + + if (is_zeromac == 0) { + DHD_ERROR(("Zero MAC detected." + " Trying Random MAC.\n")); + g_imac_flag = MACADDR_MOD_RANDOM; + } else { + sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + (unsigned int *)&(mac->octet[0]), + (unsigned int *)&(mac->octet[1]), + (unsigned int *)&(mac->octet[2]), + (unsigned int *)&(mac->octet[3]), + (unsigned int *)&(mac->octet[4]), + (unsigned int *)&(mac->octet[5])); + /* current MAC address is same as previous one */ + if (memcmp(cur_mac, mac->octet, ETHER_ADDR_LEN) == 0) { + g_imac_flag = MACADDR_NONE; + } else { /* change MAC address */ + if (_dhd_set_mac_address(dhd, 0, mac) == 0) { + DHD_INFO(("%s: MACID is" + " overwritten\n", __FUNCTION__)); + g_imac_flag = MACADDR_MOD; + } else { + DHD_ERROR(("%s: " + "_dhd_set_mac_address()" + " failed\n", __FUNCTION__)); + g_imac_flag = MACADDR_NONE; + } + } + } + } + } else { + /* COB type. only COB. */ + /* Reading the MAC Address from .nvmac.info file + * (the existed file or just created file) + */ + ret = kernel_read(fp_nvm, 0, buf, 18); + + /* to prevent abnormal string display when mac address + * is displayed on the screen. + */ + buf[17] = '\0'; + DHD_ERROR(("Read MAC : [%s] [%d] \r\n", buf, + strncmp(buf, "00:00:00:00:00:00", 17))); + if ((buf[0] == '\0') || + (strncmp(buf, "00:00:00:00:00:00", 17) == 0)) { + g_imac_flag = MACADDR_COB_RANDOM; + } else { + sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + (unsigned int *)&(mac->octet[0]), + (unsigned int *)&(mac->octet[1]), + (unsigned int *)&(mac->octet[2]), + (unsigned int *)&(mac->octet[3]), + (unsigned int *)&(mac->octet[4]), + (unsigned int *)&(mac->octet[5])); + /* Writing Newly generated MAC ID to the Dongle */ + if (_dhd_set_mac_address(dhd, 0, mac) == 0) { + DHD_INFO(("%s: MACID is overwritten\n", + __FUNCTION__)); + g_imac_flag = MACADDR_COB; + } else { + DHD_ERROR(("%s: _dhd_set_mac_address()" + " failed\n", __FUNCTION__)); + } + } + filp_close(fp_nvm, NULL); + } + + if ((g_imac_flag == MACADDR_COB_RANDOM) || + (g_imac_flag == MACADDR_MOD_RANDOM)) { + get_random_bytes(randommac, 3); + sprintf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", + 0x60, 0xd0, 0xa9, randommac[0], randommac[1], + randommac[2]); + DHD_ERROR(("[WIFI] The Random Generated MAC ID : %s\n", + macbuffer)); + sscanf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X", + (unsigned int *)&(mac->octet[0]), + (unsigned int *)&(mac->octet[1]), + (unsigned int *)&(mac->octet[2]), + (unsigned int *)&(mac->octet[3]), + (unsigned int *)&(mac->octet[4]), + (unsigned int *)&(mac->octet[5])); + if (_dhd_set_mac_address(dhd, 0, mac) == 0) { + DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); + g_imac_flag = MACADDR_COB; + } else { + DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", + __FUNCTION__)); + } + } + + return 0; +} +#endif /* RDWR_MACADDR */ + +#ifdef RDWR_KORICS_MACADDR +int dhd_write_rdwr_korics_macaddr(struct dhd_info *dhd, struct ether_addr *mac) +{ + struct file *fp = NULL; + char macbuffer[18] = {0}; + mm_segment_t oldfs = {0}; + char randommac[3] = {0}; + char buf[18] = {0}; + char *filepath_efs = MACINFO_EFS; + int is_zeromac = 0; + int ret = 0; + /* MAC address copied from efs/wifi.mac.info */ + fp = filp_open(filepath_efs, O_RDONLY, 0); + + if (IS_ERR(fp)) { + /* File Doesn't Exist. Create and write mac addr. */ + fp = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); + if (IS_ERR(fp)) { + DHD_ERROR(("[WIFI] %s: File open error\n", + filepath_efs)); + return -1; + } + + oldfs = get_fs(); + set_fs(get_ds()); + + /* Generating the Random Bytes for + * 3 last octects of the MAC address + */ + get_random_bytes(randommac, 3); + + sprintf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", + 0x60, 0xd0, 0xa9, randommac[0], + randommac[1], randommac[2]); + DHD_ERROR(("[WIFI] The Random Generated MAC ID : %s\n", + macbuffer)); + + if (fp->f_mode & FMODE_WRITE) { + ret = fp->f_op->write(fp, + (const char *)macbuffer, + sizeof(macbuffer), &fp->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI] Mac address [%s]" + " Failed to write into File:" + " %s\n", macbuffer, filepath_efs)); + else + DHD_ERROR(("[WIFI] Mac address [%s]" + " written into File: %s\n", + macbuffer, filepath_efs)); + } + set_fs(oldfs); + } else { + /* Reading the MAC Address from .mac.info file + * (the existed file or just created file) + */ + ret = kernel_read(fp, 0, buf, 18); + /* to prevent abnormal string display when mac address + * is displayed on the screen. + */ + buf[17] = '\0'; + /* Remove security log */ + /* DHD_ERROR(("Read MAC : [%s] [%d] \r\n", buf, + * strncmp(buf, "00:00:00:00:00:00", 17))); + */ + if ((buf[0] == '\0') || + (strncmp(buf, "00:00:00:00:00:00", 17) == 0)) { + is_zeromac = 1; + } + } + + if (ret) + sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + (unsigned int *)&(mac->octet[0]), + (unsigned int *)&(mac->octet[1]), + (unsigned int *)&(mac->octet[2]), + (unsigned int *)&(mac->octet[3]), + (unsigned int *)&(mac->octet[4]), + (unsigned int *)&(mac->octet[5])); + else + DHD_INFO(("dhd_bus_start: Reading from the" + " '%s' returns 0 bytes\n", filepath_efs)); + + if (fp) + filp_close(fp, NULL); + + if (!is_zeromac) { + /* Writing Newly generated MAC ID to the Dongle */ + if (_dhd_set_mac_address(dhd, 0, mac) == 0) + DHD_INFO(("dhd_bus_start: MACID is overwritten\n")); + else + DHD_ERROR(("dhd_bus_start: _dhd_set_mac_address() " + "failed\n")); + } else { + DHD_ERROR(("dhd_bus_start:Is ZeroMAC BypassWrite.mac.info!\n")); + } + + return 0; +} +#endif /* RDWR_KORICS_MACADDR */ + +#ifdef USE_CID_CHECK +static int dhd_write_cid_file(const char *filepath_efs, const char *buf, int buf_len) +{ + struct file *fp = NULL; + mm_segment_t oldfs = {0}; + int ret = 0; + + /* File is always created. */ + fp = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); + if (IS_ERR(fp)) { + DHD_ERROR(("[WIFI] %s: File open error\n", filepath_efs)); + return -1; + } else { + oldfs = get_fs(); + set_fs(get_ds()); + + if (fp->f_mode & FMODE_WRITE) { + ret = fp->f_op->write(fp, buf, buf_len, &fp->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI] Failed to write CIS[%s]" + " into '%s'\n", buf, filepath_efs)); + else + DHD_ERROR(("[WIFI] CID [%s] written into" + " '%s'\n", buf, filepath_efs)); + } + set_fs(oldfs); + } + filp_close(fp, NULL); + + return 0; +} + +#ifdef DUMP_CIS +static void dhd_dump_cis(const unsigned char *buf, int size) +{ + int i; + for (i = 0; i < size; i++) { + DHD_ERROR(("%02X ", buf[i])); + if ((i % 15) == 15) DHD_ERROR(("\n")); + } + DHD_ERROR(("\n")); +} +#endif /* DUMP_CIS */ + +#ifdef BCM4334_CHIP +#define CIS_CID_OFFSET 43 +#else +#define CIS_CID_OFFSET 31 +#endif /* BCM4334_CHIP */ + +int dhd_check_module_cid(dhd_pub_t *dhd) +{ + int ret = -1; +#ifdef BCM4334_CHIP + unsigned char cis_buf[250] = {0}; + const char *revfilepath = REVINFO; + int flag_b3 = 0; +#else + unsigned char cis_buf[128] = {0}; +#endif + const char *cidfilepath = CIDINFO; + + /* Try reading out from CIS */ + cis_rw_t *cish = (cis_rw_t *)&cis_buf[8]; + + cish->source = 0; + cish->byteoff = 0; + cish->nbytes = sizeof(cis_buf); + + strcpy(cis_buf, "cisdump"); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cis_buf, + sizeof(cis_buf), 0, 0); + if (ret < 0) { + DHD_TRACE(("%s: CIS reading failed, err=%d\n", + __FUNCTION__, ret)); + return ret; + } else { +#ifdef BCM4334_CHIP + unsigned char semco_id[4] = {0x00, 0x00, 0x33, 0x33}; + + /* for SHARP FEM(new) */ + unsigned char semco_id_sh[4] = {0x00, 0x00, 0xFB, 0x50}; + DHD_ERROR(("%s: CIS reading success, ret=%d\n", + __FUNCTION__, ret)); +#ifdef DUMP_CIS + dump_cis(cis_buf, 48); +#endif + if (memcmp(&cis_buf[CIS_CID_OFFSET], semco_id, 4) == 0) { + DHD_ERROR(("CID MATCH FOUND : Semco, " + "0x%02X 0x%02X 0x%02X 0x%02X\n", + cis_buf[CIS_CID_OFFSET], + cis_buf[CIS_CID_OFFSET+1], cis_buf[CIS_CID_OFFSET+2], + cis_buf[CIS_CID_OFFSET+3])); + dhd_write_cid_file(cidfilepath, "semco", 5); + } else if (memcmp(&cis_buf[CIS_CID_OFFSET], semco_id_sh, 4) == 0) { + DHD_ERROR(("CIS MATCH FOUND : Semco_sh, " + "0x%02X 0x%02X 0x%02X 0x%02X\n", + cis_buf[CIS_CID_OFFSET], + cis_buf[CIS_CID_OFFSET+1], cis_buf[CIS_CID_OFFSET+2], + cis_buf[CIS_CID_OFFSET+3])); + dhd_write_cid_file(cidfilepath, "semcosh", 7); + } else { + DHD_ERROR(("CID MATCH FOUND : Murata, " + "0x%02X 0x%02X 0x%02X 0x%02X\n", cis_buf[CIS_CID_OFFSET], + cis_buf[CIS_CID_OFFSET+1], cis_buf[CIS_CID_OFFSET+2], + cis_buf[CIS_CID_OFFSET+3])); + dhd_write_cid_file(cidfilepath, "murata", 6); + } + + /* Try reading out from OTP to distinguish B2 or B3 */ + memset(cis_buf, 0, sizeof(cis_buf)); + cish = (cis_rw_t *)&cis_buf[8]; + + cish->source = 0; + cish->byteoff = 0; + cish->nbytes = sizeof(cis_buf); + + strcpy(cis_buf, "otpdump"); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cis_buf, + sizeof(cis_buf), 0, 0); + if (ret < 0) { + DHD_ERROR(("%s: OTP reading failed, err=%d\n", + __FUNCTION__, ret)); + return ret; + } + + /* otp 33th character is identifier for 4334B3 */ + cis_buf[34] = '\0'; + flag_b3 = bcm_atoi(&cis_buf[33]); + if (flag_b3 & 0x1) { + DHD_ERROR(("REV MATCH FOUND : 4334B3, %c\n", cis_buf[33])); + dhd_write_cid_file(revfilepath, "4334B3", 6); + } + +#else /* BCM4330_CHIP */ + unsigned char murata_id[4] = {0x80, 0x06, 0x81, 0x00}; + unsigned char semco_ve[4] = {0x80, 0x02, 0x81, 0x99}; +#ifdef DUMP_CIS + dhd_dump_cis(cis_buf, 48); +#endif + if (memcmp(&cis_buf[CIS_CID_OFFSET], murata_id, 4) == 0) { + DHD_ERROR(("CID MATCH FOUND : Murata\n")); + dhd_write_cid_file(cidfilepath, "murata", 6); + } else if (memcmp(&cis_buf[CIS_CID_OFFSET], semco_ve, 4) + == 0) { + DHD_ERROR(("CID MATCH FOUND : Semco VE\n")); + dhd_write_cid_file(cidfilepath, "semcove", 7); + } else { + DHD_ERROR(("CID MISMATCH" + " 0x%02X 0x%02X 0x%02X 0x%02X\n", + cis_buf[CIS_CID_OFFSET], + cis_buf[CIS_CID_OFFSET + 1], + cis_buf[CIS_CID_OFFSET + 2], + cis_buf[CIS_CID_OFFSET + 3])); + dhd_write_cid_file(cidfilepath, "samsung", 7); + } +#endif /* BCM4334_CHIP */ + DHD_ERROR(("%s: CIS write success, err=%d\n", + __FUNCTION__, ret)); + } + + return ret; +} +#endif /* USE_CID_CHECK */ + +#ifdef GET_MAC_FROM_OTP +static int dhd_write_mac_file(const char *filepath, const char *buf, int buf_len) +{ + struct file *fp = NULL; + mm_segment_t oldfs = {0}; + int ret = 0; + + fp = filp_open(filepath, O_RDWR | O_CREAT, 0666); + /* File is always created. */ + if (IS_ERR(fp)) { + DHD_ERROR(("[WIFI] File open error\n")); + return -1; + } else { + oldfs = get_fs(); + set_fs(get_ds()); + + if (fp->f_mode & FMODE_WRITE) { + ret = fp->f_op->write(fp, buf, buf_len, &fp->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI] Failed to write CIS. \n")); + else + DHD_ERROR(("[WIFI] MAC written. \n")); + } + set_fs(oldfs); + } + filp_close(fp, NULL); + + return 0; +} + +#define CIS_MAC_OFFSET 33 + +int dhd_check_module_mac(dhd_pub_t *dhd, struct ether_addr *mac) +{ + int ret = -1; + unsigned char cis_buf[250] = {0}; + unsigned char mac_buf[20] = {0}; + unsigned char otp_mac_buf[20] = {0}; + const char *macfilepath = MACINFO_EFS; + + /* Try reading out from CIS */ + cis_rw_t *cish = (cis_rw_t *)&cis_buf[8]; + struct file *fp_mac = NULL; + + cish->source = 0; + cish->byteoff = 0; + cish->nbytes = sizeof(cis_buf); + + strcpy(cis_buf, "cisdump"); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cis_buf, + sizeof(cis_buf), 0, 0); + if (ret < 0) { + DHD_TRACE(("%s: CIS reading failed, err=%d\n", __func__, + ret)); + sprintf(otp_mac_buf, "%02X:%02X:%02X:%02X:%02X:%02X\n", + mac->octet[0], mac->octet[1], mac->octet[2], + mac->octet[3], mac->octet[4], mac->octet[5]); + DHD_ERROR(("%s: Check module mac by legacy FW : %02X:%02X:%02X\n", + __func__, mac->octet[0], mac->octet[4], mac->octet[5])); + } else { + unsigned char mac_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +#ifdef DUMP_CIS + dump_cis(cis_buf, 48); +#endif + mac_id[0] = cis_buf[CIS_MAC_OFFSET]; + mac_id[1] = cis_buf[CIS_MAC_OFFSET + 1]; + mac_id[2] = cis_buf[CIS_MAC_OFFSET + 2]; + mac_id[3] = cis_buf[CIS_MAC_OFFSET + 3]; + mac_id[4] = cis_buf[CIS_MAC_OFFSET + 4]; + mac_id[5] = cis_buf[CIS_MAC_OFFSET + 5]; + + sprintf(otp_mac_buf, "%02X:%02X:%02X:%02X:%02X:%02X\n", + mac_id[0], mac_id[1], mac_id[2], mac_id[3], mac_id[4], + mac_id[5]); + DHD_ERROR(("[WIFI]mac_id is setted from OTP \n")); + } + + fp_mac = filp_open(macfilepath, O_RDONLY, 0); + if (!IS_ERR(fp_mac)) { + DHD_ERROR(("[WIFI]Check Mac address in .mac.info \n")); + kernel_read(fp_mac, fp_mac->f_pos, mac_buf, sizeof(mac_buf)); + filp_close(fp_mac, NULL); + + if (strncmp(mac_buf, otp_mac_buf, 17) != 0) { + DHD_ERROR(("[WIFI]file MAC is wrong. Write OTP MAC in .mac.info \n")); + dhd_write_mac_file(macfilepath, otp_mac_buf, sizeof(otp_mac_buf)); + } + } + + return ret; +} +#endif /* GET_MAC_FROM_OTP */ + +#ifdef WRITE_MACADDR +int dhd_write_macaddr(struct ether_addr *mac) +{ + char *filepath_data = MACINFO; + char *filepath_efs = MACINFO_EFS; + + struct file *fp_mac = NULL; + char buf[18] = {0}; + mm_segment_t oldfs = {0}; + int ret = -1; + int retry_count = 0; + +startwrite: + + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X\n", + mac->octet[0], mac->octet[1], mac->octet[2], + mac->octet[3], mac->octet[4], mac->octet[5]); + + /* File will be created /data/.mac.info. */ + fp_mac = filp_open(filepath_data, O_RDWR | O_CREAT, 0666); + + if (IS_ERR(fp_mac)) { + DHD_ERROR(("[WIFI] %s: File open error\n", filepath_data)); + return -1; + } else { + oldfs = get_fs(); + set_fs(get_ds()); + + if (fp_mac->f_mode & FMODE_WRITE) { + ret = fp_mac->f_op->write(fp_mac, (const char *)buf, + sizeof(buf), &fp_mac->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI] Mac address [%s] Failed to" + " write into File: %s\n", buf, filepath_data)); + else + DHD_INFO(("[WIFI] Mac address [%s] written" + " into File: %s\n", buf, filepath_data)); + } + set_fs(oldfs); + filp_close(fp_mac, NULL); + } + /* check .mac.info file is 0 byte */ + fp_mac = filp_open(filepath_data, O_RDONLY, 0); + ret = kernel_read(fp_mac, 0, buf, 18); + + if ((ret == 0) && (retry_count++ < 3)) { + filp_close(fp_mac, NULL); + goto startwrite; + } + + filp_close(fp_mac, NULL); + /* end of /data/.mac.info */ + + if (filepath_efs == NULL) { + DHD_ERROR(("[WIFI]%s : no efs filepath", __func__)); + return 0; + } + + /* File will be created /efs/wifi/.mac.info. */ + fp_mac = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); + + if (IS_ERR(fp_mac)) { + DHD_ERROR(("[WIFI] %s: File open error\n", filepath_efs)); + return -1; + } else { + oldfs = get_fs(); + set_fs(get_ds()); + + if (fp_mac->f_mode & FMODE_WRITE) { + ret = fp_mac->f_op->write(fp_mac, (const char *)buf, + sizeof(buf), &fp_mac->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI] Mac address [%s] Failed to" + " write into File: %s\n", buf, filepath_efs)); + else + DHD_INFO(("[WIFI] Mac address [%s] written" + " into File: %s\n", buf, filepath_efs)); + } + set_fs(oldfs); + filp_close(fp_mac, NULL); + } + + /* check .mac.info file is 0 byte */ + fp_mac = filp_open(filepath_efs, O_RDONLY, 0); + ret = kernel_read(fp_mac, 0, buf, 18); + + if ((ret == 0) && (retry_count++ < 3)) { + filp_close(fp_mac, NULL); + goto startwrite; + } + + filp_close(fp_mac, NULL); + + return 0; +} +#endif /* WRITE_MACADDR */ + +#ifdef CONFIG_CONTROL_PM +extern bool g_pm_control; +void sec_control_pm(dhd_pub_t *dhd, uint *power_mode) +{ + struct file *fp = NULL; + char *filepath = PSMINFO; + mm_segment_t oldfs = {0}; + char power_val = 0; + char iovbuf[WL_EVENTING_MASK_LEN + 12]; + + g_pm_control = FALSE; + + fp = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp)) { + /* Enable PowerSave Mode */ + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, + sizeof(uint), TRUE, 0); + + fp = filp_open(filepath, O_RDWR | O_CREAT, 0666); + if (IS_ERR(fp) || (fp == NULL)) { + DHD_ERROR(("[%s, %d] /data/.psm.info open failed\n", + __FUNCTION__, __LINE__)); + return; + } else { + oldfs = get_fs(); + set_fs(get_ds()); + + if (fp->f_mode & FMODE_WRITE) { + power_val = '1'; + fp->f_op->write(fp, (const char *)&power_val, + sizeof(char), &fp->f_pos); + } + set_fs(oldfs); + } + } else { + if (fp == NULL) { + DHD_ERROR(("[%s, %d] /data/.psm.info open failed\n", + __FUNCTION__, __LINE__)); + return; + } + kernel_read(fp, fp->f_pos, &power_val, 1); + DHD_ERROR(("POWER_VAL = %c \r\n", power_val)); + + if (power_val == '0') { +#ifdef ROAM_ENABLE + uint roamvar = 1; +#endif + *power_mode = PM_OFF; + /* Disable PowerSave Mode */ + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, + sizeof(uint), TRUE, 0); + /* Turn off MPC in AP mode */ + bcm_mkiovar("mpc", (char *)power_mode, 4, + iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0); + g_pm_control = TRUE; +#ifdef ROAM_ENABLE + /* Roaming off of dongle */ + bcm_mkiovar("roam_off", (char *)&roamvar, 4, + iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0); +#endif + } else { + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, + sizeof(uint), TRUE, 0); + } + } + + if (fp) + filp_close(fp, NULL); +} +#endif /* CONFIG_CONTROL_PM */ +#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE +int dhd_customer_set_country(dhd_pub_t *dhd) +{ + struct file *fp = NULL; + char *filepath = "/data/.ccode.info"; + char iovbuf[WL_EVENTING_MASK_LEN + 12] = {0}; + char buffer[10] = {0}; + int ret = 0; + wl_country_t cspec; + int buf_len = 0; + char country_code[WLC_CNTRY_BUF_SZ]; + int country_rev; + int country_offset; + int country_code_size; + char country_rev_buf[WLC_CNTRY_BUF_SZ]; + fp = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp)) { + DHD_ERROR(("%s: %s open failed\n", __FUNCTION__, filepath)); + return -1; + } else { + if (kernel_read(fp, 0, buffer, sizeof(buffer))) { + memset(&cspec, 0, sizeof(cspec)); + memset(country_code, 0, sizeof(country_code)); + memset(country_rev_buf, 0, sizeof(country_rev_buf)); + country_offset = strcspn(buffer, " "); + country_code_size = country_offset; + if (country_offset != 0) { + strncpy(country_code, buffer, country_offset); + strncpy(country_rev_buf, buffer+country_offset+1, + strlen(buffer) - country_code_size + 1); + country_rev = bcm_atoi(country_rev_buf); + buf_len = bcm_mkiovar("country", (char *)&cspec, + sizeof(cspec), iovbuf, sizeof(iovbuf)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, buf_len, FALSE, 0); + memcpy((void *)&cspec, iovbuf, sizeof(cspec)); + if (!ret) { + DHD_ERROR(("%s: get country ccode:%s" + " country_abrev:%s rev:%d \n", + __FUNCTION__, cspec.ccode, + cspec.country_abbrev, cspec.rev)); + if ((strncmp(country_code, cspec.ccode, + WLC_CNTRY_BUF_SZ) != 0) || + (cspec.rev != country_rev)) { + strncpy(cspec.country_abbrev, + country_code, country_code_size); + strncpy(cspec.ccode, country_code, + country_code_size); + cspec.rev = country_rev; + DHD_ERROR(("%s: set country ccode:%s" + "country_abrev:%s rev:%d\n", + __FUNCTION__, cspec.ccode, + cspec.country_abbrev, cspec.rev)); + buf_len = bcm_mkiovar("country", (char *)&cspec, + sizeof(cspec), iovbuf, sizeof(iovbuf)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, + iovbuf, buf_len, TRUE, 0); + } + } + } else { + DHD_ERROR(("%s: set country %s failed code \n", + __FUNCTION__, country_code)); + ret = -1; + } + } else { + DHD_ERROR(("%s: Reading from the '%s' returns 0 bytes \n", + __FUNCTION__, filepath)); + ret = -1; + } + } + if (fp) + filp_close(fp, NULL); + + return ret; +} +#endif /* GLOBALCONFIG_WLAN_COUNTRY_CODE */ + +#ifdef MIMO_ANT_SETTING +int dhd_sel_ant_from_file(dhd_pub_t *dhd) +{ + struct file *fp = NULL; + int ret = -1; + uint32 ant_val = 0; + char *filepath = "/data/.ant.info"; + char iovbuf[WLC_IOCTL_SMLEN]; + + /* Read antenna settings from the file */ + fp = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp)) { + DHD_ERROR(("[WIFI] %s: File [%s] open error\n", __FUNCTION__, filepath)); + return ret; + } else { + ret = kernel_read(fp, 0, (char *)&ant_val, 4); + if (ret < 0) { + DHD_ERROR(("[WIFI] %s: File read error, ret=%d\n", __FUNCTION__, ret)); + filp_close(fp, NULL); + return ret; + } + + ant_val = bcm_atoi((char *)&ant_val); + + DHD_ERROR(("[WIFI] %s: ANT val = %d\n", __FUNCTION__, ant_val)); + filp_close(fp, NULL); + + /* Check value from the file */ + if (ant_val < 1 || ant_val > 3) { + DHD_ERROR(("[WIFI] %s: Invalid value %d read from the file %s\n", + __FUNCTION__, ant_val, filepath)); + return -1; + } + } + + /* Select Antenna */ + bcm_mkiovar("txchain", (char *)&ant_val, 4, iovbuf, sizeof(iovbuf)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + if (ret) { + DHD_ERROR(("[WIFI] %s: Fail to execute dhd_wl_ioctl_cmd(): txchain, ret=%d\n", + __FUNCTION__, ret)); + return ret; + } + + bcm_mkiovar("rxchain", (char *)&ant_val, 4, iovbuf, sizeof(iovbuf)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + if (ret) { + DHD_ERROR(("[WIFI] %s: Fail to execute dhd_wl_ioctl_cmd(): rxchain, ret=%d\n", + __FUNCTION__, ret)); + return ret; + } + + return 0; +} +#endif /* MIMO_ANTENNA_SETTING */ +#endif /* CUSTOMER_HW4 */ diff --git a/drivers/net/wireless/bcmdhd/dhd_dbg.h b/drivers/net/wireless/bcmdhd/dhd_dbg.h index 2b40d2738c9..314f0ee58c7 100644 --- a/drivers/net/wireless/bcmdhd/dhd_dbg.h +++ b/drivers/net/wireless/bcmdhd/dhd_dbg.h @@ -21,15 +21,21 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_dbg.h 308299 2012-01-14 01:36:58Z $ + * $Id: dhd_dbg.h 353490 2012-08-27 21:10:02Z $ */ #ifndef _dhd_dbg_ #define _dhd_dbg_ +#if !defined(CUSTOMER_HW4) +#define USE_NET_RATELIMIT net_ratelimit() +#else +#define USE_NET_RATELIMIT 1 +#endif + #if defined(DHD_DEBUG) -#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && (net_ratelimit())) \ +#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && USE_NET_RATELIMIT) \ printf args;} while (0) #define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) #define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) @@ -46,6 +52,12 @@ #define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) #define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) +#ifdef CUSTOMER_HW4 +#define DHD_TRACE_HW4 DHD_ERROR +#else +#define DHD_TRACE_HW4 DHD_TRACE +#endif + #define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) #define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) #define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) @@ -64,7 +76,7 @@ #else /* defined(BCMDBG) || defined(DHD_DEBUG) */ -#define DHD_ERROR(args) do {if (net_ratelimit()) printf args;} while (0) +#define DHD_ERROR(args) do {if (USE_NET_RATELIMIT) printf args;} while (0) #define DHD_TRACE(args) #define DHD_INFO(args) #define DHD_DATA(args) @@ -80,6 +92,12 @@ #define DHD_ARPOE(args) #define DHD_REORDER(args) +#ifdef CUSTOMER_HW4 +#define DHD_TRACE_HW4 DHD_ERROR +#else +#define DHD_TRACE_HW4 DHD_TRACE +#endif + #define DHD_ERROR_ON() 0 #define DHD_TRACE_ON() 0 #define DHD_INFO_ON() 0 diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 0d1ba9d92ee..8702a442813 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 329678 2012-04-26 08:51:32Z $ + * $Id: dhd_linux.c 358016 2012-09-20 22:36:51Z $ */ #include @@ -78,7 +78,6 @@ #define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ #define TSMAX 1000 /* max no. of timing record kept */ #define NUMBIN 34 - static uint32 tsidx = 0; static uint32 htsf_seqnum = 0; uint32 tsfsync; @@ -96,6 +95,21 @@ typedef struct histo_ { static histo_t vi_d1, vi_d2, vi_d3, vi_d4; #endif /* WLMEDIA_HTSF */ +#ifndef DTIM_COUNT +#define DTIM_COUNT 3 +#endif + +#if defined(PKT_FILTER_SUPPORT) +#if defined(BLOCK_IPV6_PACKET) +#define HEX_PREF_STR "0x" +#define UNI_FILTER_STR "010000000000" +#define ZERO_ADDR_STR "000000000000" +#define ETHER_TYPE_STR "0000" +#define IPV6_FILTER_STR "20" +#define ZERO_TYPE_STR "00" +#endif /* BLOCK_IPV6_PACKET */ +#endif /* PKT_FILTER_SUPPORT */ + #if defined(SOFTAP) extern bool ap_cfg_running; extern bool ap_fw_loaded; @@ -135,6 +149,9 @@ DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); #if defined(OOB_INTR_ONLY) extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); #endif /* defined(OOB_INTR_ONLY) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) +static void dhd_hang_process(struct work_struct *work); +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) MODULE_LICENSE("GPL v2"); #endif /* LinuxVer */ @@ -165,17 +182,51 @@ print_tainted() extern wl_iw_extra_params_t g_wl_iw_params; #endif /* defined(CONFIG_WIRELESS_EXT) */ -#if defined(CONFIG_HAS_EARLYSUSPEND) +#if defined(CUSTOMER_HW4) && defined(CONFIG_PARTIALSUSPEND_SLP) +#include +#define CONFIG_HAS_EARLYSUSPEND +#define DHD_USE_EARLYSUSPEND +#define register_early_suspend register_pre_suspend +#define unregister_early_suspend unregister_pre_suspend +#define early_suspend pre_suspend +#define EARLY_SUSPEND_LEVEL_BLANK_SCREEN 50 +#else +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) #include -extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ +#endif /* CUSTOMER_HW4 && CONFIG_PARTIALSUSPEND_SLP */ + extern int dhd_get_dtim_skip(dhd_pub_t *dhd); -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ #ifdef PKT_FILTER_SUPPORT extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); #endif +#ifdef READ_MACADDR +extern int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac); +#endif +#ifdef RDWR_MACADDR +extern int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, struct ether_addr *mac); +extern int dhd_write_rdwr_macaddr(struct ether_addr *mac); +#endif +#ifdef WRITE_MACADDR +extern int dhd_write_macaddr(struct ether_addr *mac); +#endif +#ifdef USE_CID_CHECK +extern int dhd_check_module_cid(dhd_pub_t *dhd); +#endif +#ifdef GET_MAC_FROM_OTP +extern int dhd_check_module_mac(dhd_pub_t *dhd, struct ether_addr *mac); +#endif +#ifdef MIMO_ANT_SETTING +extern int dhd_sel_ant_from_file(dhd_pub_t *dhd); +#endif + +#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE +int dhd_customer_set_country(dhd_pub_t *dhd); +#endif + /* Interface control information */ typedef struct dhd_if { struct dhd_info *info; /* back pointer to dhd_info */ @@ -222,6 +273,11 @@ static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; #endif /* WLMEDIA_HTSF */ +#if defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) +/* SLP_wakelock_alternative_code */ +extern struct device *pm_dev; +#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ + /* Local private structure (extension of pub) */ typedef struct dhd_info { #if defined(CONFIG_WIRELESS_EXT) @@ -257,11 +313,15 @@ typedef struct dhd_info { #endif /* DHDTHREAD */ bool dhd_tasklet_create; tsk_ctl_t thr_sysioc_ctl; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + struct work_struct work_hang; +#endif /* Wakelocks */ #if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) struct wake_lock wl_wifi; /* Wifi wakelock */ struct wake_lock wl_rxwake; /* Wifi rx wakelock */ + struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */ #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 @@ -269,10 +329,12 @@ typedef struct dhd_info { * calls and wifi_on or wifi_off */ struct mutex dhd_net_if_mutex; + struct mutex dhd_suspend_mutex; #endif spinlock_t wakelock_spinlock; int wakelock_counter; - int wakelock_timeout_enable; + int wakelock_rx_timeout_enable; + int wakelock_ctrl_timeout_enable; /* Thread to issue ioctl for multicast */ unsigned char set_macaddress; @@ -281,9 +343,9 @@ typedef struct dhd_info { atomic_t pend_8021x_cnt; dhd_attach_states_t dhd_state; -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) struct early_suspend early_suspend; -#endif /* CONFIG_HAS_EARLYSUSPEND */ +#endif /* CONFIG_HAS_EARLYSUSPEND && defined(DHD_USE_EARLYSUSPEND) */ #ifdef ARP_OFFLOAD_SUPPORT u32 pend_ipaddr; @@ -297,6 +359,8 @@ typedef struct dhd_info { #endif } dhd_info_t; +/* Flag to indicate if we should download firmware on driver load */ +uint dhd_download_fw_on_driverload = TRUE; /* Definitions to provide path to the firmware and nvram * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" @@ -304,13 +368,18 @@ typedef struct dhd_info { char firmware_path[MOD_PARAM_PATHLEN]; char nvram_path[MOD_PARAM_PATHLEN]; +/* information string to keep firmware, chio, cheip version info visiable from log */ +char info_string[MOD_PARAM_INFOLEN]; +module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); + int op_mode = 0; +int disable_proptx = 0; module_param(op_mode, int, 0644); extern int wl_control_wl_start(struct net_device *dev); -extern int net_os_send_hang_message(struct net_device *dev); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) struct semaphore dhd_registration_sem; struct semaphore dhd_chipup_sem; +int dhd_registration_check = FALSE; #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ @@ -322,12 +391,14 @@ module_param(dhd_sysioc, uint, 0); /* Error bits */ module_param(dhd_msg_level, int, 0); +/* Disable Prop tx */ +module_param(disable_proptx, int, 0644); /* load firmware and/or nvram values from the filesystem */ module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); -module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); +module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660); /* Watchdog interval */ -uint dhd_watchdog_ms = 0; +uint dhd_watchdog_ms = 10; module_param(dhd_watchdog_ms, uint, 0); #if defined(DHD_DEBUG) @@ -340,7 +411,7 @@ uint dhd_slpauto = TRUE; module_param(dhd_slpauto, uint, 0); /* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ -uint dhd_arp_mode = 0xb; +uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY | ARP_OL_SNOOP; module_param(dhd_arp_mode, uint, 0); /* ARP offload enable */ @@ -353,21 +424,24 @@ uint dhd_pkt_filter_enable = TRUE; module_param(dhd_pkt_filter_enable, uint, 0); #endif -/* Pkt filter init setup */ +/* Pkt filter init setup */ uint dhd_pkt_filter_init = 0; module_param(dhd_pkt_filter_init, uint, 0); /* Pkt filter mode control */ +#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER +uint dhd_master_mode = FALSE; +#else uint dhd_master_mode = TRUE; -module_param(dhd_master_mode, uint, 1); +#endif /* GAL_LITE_NAT_KEEPALIVE_FILTER */ +module_param(dhd_master_mode, uint, 0); #ifdef DHDTHREAD -/* Watchdog thread priority, -1 to use kernel timer */ -int dhd_watchdog_prio = 97; +int dhd_watchdog_prio = 0; module_param(dhd_watchdog_prio, int, 0); -/* DPC thread priority, -1 to use tasklet */ -int dhd_dpc_prio = 98; +/* DPC thread priority */ +int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; module_param(dhd_dpc_prio, int, 0); /* DPC thread priority, -1 to use tasklet */ @@ -375,7 +449,11 @@ extern int dhd_dongle_memsize; module_param(dhd_dongle_memsize, int, 0); #endif /* DHDTHREAD */ /* Control fw roaming */ +#ifdef BCMCCX +uint dhd_roam_disable = 0; +#else uint dhd_roam_disable = 0; +#endif /* BCMCCX */ /* Control radio state */ uint dhd_radio_up = 1; @@ -384,12 +462,6 @@ uint dhd_radio_up = 1; char iface_name[IFNAMSIZ] = {'\0'}; module_param_string(iface_name, iface_name, IFNAMSIZ, 0); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define BLOCKABLE() (!in_atomic()) -#else -#define BLOCKABLE() (!in_interrupt()) -#endif - /* The following are specific to the SDIO dongle */ /* IOCTL response timeout */ @@ -455,6 +527,8 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR ; static void dhd_net_if_lock_local(dhd_info_t *dhd); static void dhd_net_if_unlock_local(dhd_info_t *dhd); +static void dhd_suspend_lock(dhd_pub_t *dhdp); +static void dhd_suspend_unlock(dhd_pub_t *dhdp); #ifdef WLMEDIA_HTSF void htsf_update(dhd_info_t *dhd, void *data); @@ -472,6 +546,11 @@ static void dhd_dump_htsfhisto(histo_t *his, char *s); int dhd_monitor_init(void *dhd_pub); int dhd_monitor_uninit(void); +#ifdef CONFIG_CONTROL_PM +bool g_pm_control; +void sec_control_pm(dhd_pub_t *dhd, uint *); +#endif + #if defined(CONFIG_WIRELESS_EXT) struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); @@ -517,56 +596,102 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio static struct notifier_block dhd_sleep_pm_notifier = { .notifier_call = dhd_sleep_pm_callback, - .priority = 0 + .priority = 10 }; extern int register_pm_notifier(struct notifier_block *nb); extern int unregister_pm_notifier(struct notifier_block *nb); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) +void dhd_set_packet_filter(dhd_pub_t *dhd) +#ifdef PKT_FILTER_SUPPORT +{ + int i; + + DHD_TRACE(("%s: enter\n", __FUNCTION__)); + if (dhd_pkt_filter_enable) { + for (i = 0; i < dhd->pktfilter_count; i++) { + dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); + } + } +#endif +} + +void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) { #ifdef PKT_FILTER_SUPPORT - DHD_TRACE(("%s: %d\n", __FUNCTION__, value)); + int i; + + DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value)); /* 1 - Enable packet filter, only allow unicast packet to send up */ /* 0 - Disable packet filter */ - if (dhd_pkt_filter_enable && !dhd->dhcp_in_progress) { - int i; - + if (dhd_pkt_filter_enable && (!value || + (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) { for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); +#ifdef PASS_ARP_PACKET + if (value && (i == dhd->pktfilter_count -1) && + !(dhd->op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { + DHD_TRACE_HW4(("Do not turn on ARP white list pkt filter:" + "val %d, cnt %d, op_mode 0x%x\n", + value, i, dhd->op_mode)); + continue; + } +#endif dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], value, dhd_master_mode); } } -#endif +#endif /* PKT_FILTER_SUPPORT */ } -#if defined(CONFIG_HAS_EARLYSUSPEND) static int dhd_set_suspend(int value, dhd_pub_t *dhd) { +#ifndef SUPPORT_PM2_ONLY int power_mode = PM_MAX; +#endif /* wl_pkt_filter_enable_t enable_parm; */ char iovbuf[32]; - int bcn_li_dtim = 3; +#if !defined(CUSTOMER_HW4) + int bcn_li_dtim = DTIM_COUNT; +#endif +#ifndef DISABLE_FW_ROAM_SUSPEND uint roamvar = 1; +#endif +#ifdef ENABLE_BCN_LI_BCN_WAKEUP + int bcn_li_bcn; +#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ +#ifdef PASS_ALL_MCAST_PKTS + uint32 allmulti; +#endif /* PASS_ALL_MCAST_PKTS */ DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", __FUNCTION__, value, dhd->in_suspend)); + dhd_suspend_lock(dhd); if (dhd && dhd->up) { if (value && dhd->in_suspend) { #ifdef PKT_FILTER_SUPPORT dhd->early_suspended = 1; #endif /* Kernel suspended */ - DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); + DHD_ERROR(("%s: force extra Suspend setting\n", __FUNCTION__)); +#ifndef SUPPORT_PM2_ONLY dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); - +#endif +#ifdef PKT_FILTER_SUPPORT /* Enable packet filter, only allow unicast packet to send up */ - dhd_set_packet_filter(1, dhd); + if (!dhd->dhcp_in_progress) + dhd_enable_packet_filter(1, dhd); +#endif /* PKT_FILTER_SUPPORT */ +#ifdef PASS_ALL_MCAST_PKTS + allmulti = 0; + bcm_mkiovar("allmulti", (char *)&allmulti, + 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif /* PASS_ALL_MCAST_PKTS */ +#if !defined(CUSTOMER_HW4) /* If DTIM skip is set up as default, force it to wake * each third DTIM for better power savings. Note that * one side effect is a chance to miss BC/MC packet. @@ -575,70 +700,105 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - +#endif /* !defined(CUSTOMER_HW4) */ +#ifndef DISABLE_FW_ROAM_SUSPEND /* Disable firmware roaming during suspend */ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif +#ifdef ENABLE_BCN_LI_BCN_WAKEUP + bcn_li_bcn = 0; + bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, + 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ + } else { #ifdef PKT_FILTER_SUPPORT dhd->early_suspended = 0; #endif /* Kernel resumed */ - DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); + DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__)); +#ifndef SUPPORT_PM2_ONLY power_mode = PM_FAST; dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); - +#endif +#ifdef PKT_FILTER_SUPPORT /* disable pkt filter */ - dhd_set_packet_filter(0, dhd); + dhd_enable_packet_filter(0, dhd); +#endif /* PKT_FILTER_SUPPORT */ +#ifdef PASS_ALL_MCAST_PKTS + allmulti = 1; + bcm_mkiovar("allmulti", (char *)&allmulti, + 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif /* PASS_ALL_MCAST_PKTS */ +#if !defined(CUSTOMER_HW4) /* restore pre-suspend setting for dtim_skip */ bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif +#ifndef DISABLE_FW_ROAM_SUSPEND roamvar = dhd_roam_disable; bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif +#ifdef ENABLE_BCN_LI_BCN_WAKEUP + bcn_li_bcn = 1; + bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, + 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ + } } + dhd_suspend_unlock(dhd); return 0; } -static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val) +static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) { dhd_pub_t *dhdp = &dhd->pub; + int ret = 0; DHD_OS_WAKE_LOCK(dhdp); /* Set flag when early suspend was called */ dhdp->in_suspend = val; - if ((!dhdp->suspend_disable_flag) && (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) - dhd_set_suspend(val, dhdp); + if ((force || !dhdp->suspend_disable_flag) && + dhd_support_sta_mode(dhdp)) + { + ret = dhd_set_suspend(val, dhdp); + } + DHD_OS_WAKE_UNLOCK(dhdp); + return ret; } +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) static void dhd_early_suspend(struct early_suspend *h) { struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - - DHD_TRACE(("%s: enter\n", __FUNCTION__)); + DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); if (dhd) - dhd_suspend_resume_helper(dhd, 1); + dhd_suspend_resume_helper(dhd, 1, 0); } static void dhd_late_resume(struct early_suspend *h) { struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - - DHD_TRACE(("%s: enter\n", __FUNCTION__)); + DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); if (dhd) - dhd_suspend_resume_helper(dhd, 0); + dhd_suspend_resume_helper(dhd, 0, 0); } #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ @@ -660,7 +820,7 @@ dhd_timeout_start(dhd_timeout_t *tmo, uint usec) tmo->limit = usec; tmo->increment = 0; tmo->elapsed = 0; - tmo->tick = 1000000 / HZ; + tmo->tick = jiffies_to_usecs(1); } int @@ -686,16 +846,12 @@ dhd_timeout_expired(dhd_timeout_t *tmo) } else { wait_queue_head_t delay_wait; DECLARE_WAITQUEUE(wait, current); - int pending; init_waitqueue_head(&delay_wait); add_wait_queue(&delay_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); - pending = signal_pending(current); remove_wait_queue(&delay_wait, &wait); set_current_state(TASK_RUNNING); - if (pending) - return 1; /* Interrupted */ } return 0; @@ -802,22 +958,56 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) uint buflen; int ret; +#ifdef MCAST_LIST_ACCUMULATION + int i; + uint32 cnt_iface[DHD_MAX_IFS]; + cnt = 0; + allmulti = 0; + + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + dev = dhd->iflist[i]->net; +#else ASSERT(dhd && dhd->iflist[ifidx]); dev = dhd->iflist[ifidx]->net; +#endif /* MCAST_LIST_ACCUMULATION */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) netif_addr_lock_bh(dev); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) +#ifdef MCAST_LIST_ACCUMULATION + cnt_iface[i] = netdev_mc_count(dev); + cnt += cnt_iface[i]; +#else cnt = netdev_mc_count(dev); +#endif /* MCAST_LIST_ACCUMULATION */ +#else +#ifdef MCAST_LIST_ACCUMULATION + cnt += dev->mc_count; #else cnt = dev->mc_count; -#endif +#endif /* MCAST_LIST_ACCUMULATION */ +#endif /* LINUX_VERSION_CODE */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) netif_addr_unlock_bh(dev); #endif /* Determine initial value of allmulti flag */ +#ifdef MCAST_LIST_ACCUMULATION + allmulti |= (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; + } + } +#else allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; +#endif /* MCAST_LIST_ACCUMULATION */ + +#ifdef PASS_ALL_MCAST_PKTS +#ifdef PKT_FILTER_SUPPORT + if (!dhd->pub.early_suspended) +#endif /* PKT_FILTER_SUPPORT */ + allmulti = TRUE; +#endif /* PASS_ALL_MCAST_PKTS */ /* Send down the multicast list first. */ @@ -829,33 +1019,63 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) return; } - strcpy(bufp, "mcast_list"); + strncpy(bufp, "mcast_list", buflen - 1); + bufp[buflen - 1] = '\0'; bufp += strlen("mcast_list") + 1; cnt = htol32(cnt); memcpy(bufp, &cnt, sizeof(cnt)); bufp += sizeof(cnt); +#ifdef MCAST_LIST_ACCUMULATION + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + DHD_TRACE(("_dhd_set_multicast_list: ifidx %d\n", i)); + dev = dhd->iflist[i]->net; +#endif /* MCAST_LIST_ACCUMULATION */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) netif_addr_lock_bh(dev); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) netdev_for_each_mc_addr(ha, dev) { +#ifdef MCAST_LIST_ACCUMULATION + if (!cnt_iface[i]) +#else if (!cnt) +#endif /* MCAST_LIST_ACCUMULATION */ break; memcpy(bufp, ha->addr, ETHER_ADDR_LEN); bufp += ETHER_ADDR_LEN; +#ifdef MCAST_LIST_ACCUMULATION + DHD_TRACE(("_dhd_set_multicast_list: cnt " + "%d " MACDBG "\n", + cnt_iface[i], MAC2STRDBG(ha->addr))); + cnt_iface[i]--; +#else cnt--; +#endif /* MCAST_LIST_ACCUMULATION */ } #else - for (mclist = dev->mc_list; (mclist && (cnt > 0)); cnt--, mclist = mclist->next) { +#ifdef MCAST_LIST_ACCUMULATION + for (mclist = dev->mc_list; (mclist && (cnt_iface[i] > 0)); + cnt_iface[i]--, mclist = mclist->next) { +#else + for (mclist = dev->mc_list; (mclist && (cnt > 0)); + cnt--, mclist = mclist->next) { +#endif /* MCAST_LIST_ACCUMULATION */ memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); bufp += ETHER_ADDR_LEN; } -#endif +#endif /* LINUX_VERSION_CODE */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) netif_addr_unlock_bh(dev); #endif +#ifdef MCAST_LIST_ACCUMULATION + } + } +#endif /* MCAST_LIST_ACCUMULATION */ memset(&ioc, 0, sizeof(ioc)); ioc.cmd = WLC_SET_VAR; @@ -908,7 +1128,18 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ +#ifdef MCAST_LIST_ACCUMULATION + allmulti = 0; + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + dev = dhd->iflist[i]->net; + allmulti |= (dev->flags & IFF_PROMISC) ? TRUE : FALSE; + } + } +#else allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; +#endif /* MCAST_LIST_ACCUMULATION */ + allmulti = htol32(allmulti); memset(&ioc, 0, sizeof(ioc)); @@ -924,7 +1155,7 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) } } -static int +int _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) { char buf[32]; @@ -1038,14 +1269,19 @@ dhd_op_if(dhd_if_t *ifp) ifp->state = DHD_IF_DELETING; if (ifp->net != NULL) { DHD_TRACE(("\n%s: got 'DHD_IF_DEL' state\n", __FUNCTION__)); + netif_stop_queue(ifp->net); #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { - wl_cfg80211_notify_ifdel(ifp->net); + wl_cfg80211_ifdel_ops(ifp->net); } #endif - netif_stop_queue(ifp->net); unregister_netdev(ifp->net); ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ +#ifdef WL_CFG80211 + if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { + wl_cfg80211_notify_ifdel(); + } +#endif } break; case DHD_IF_DELETING: @@ -1085,12 +1321,16 @@ _dhd_sysioc_thread(void *data) bool in_ap = FALSE; unsigned long flags; #endif - +#ifndef USE_KTHREAD_API DAEMONIZE("dhd_sysioc"); complete(&tsk->completed); +#endif while (down_interruptible(&tsk->sema) == 0) { +#ifdef MCAST_LIST_ACCUMULATION + bool set_multicast = FALSE; +#endif /* MCAST_LIST_ACCUMULATION */ SMP_RD_BARRIER_DEPENDS(); if (tsk->terminated) { @@ -1131,16 +1371,33 @@ _dhd_sysioc_thread(void *data) continue; } #endif /* SOFTAP */ + if (dhd->pub.up == 0) + continue; if (dhd->iflist[i]->set_multicast) { dhd->iflist[i]->set_multicast = FALSE; +#ifdef MCAST_LIST_ACCUMULATION + set_multicast = TRUE; +#else _dhd_set_multicast_list(dhd, i); +#endif /* MCAST_LIST_ACCUMULATION */ + } if (dhd->set_macaddress == i+1) { dhd->set_macaddress = 0; - _dhd_set_mac_address(dhd, i, &dhd->macvalue); + if (_dhd_set_mac_address(dhd, i, &dhd->macvalue) == 0) { + DHD_INFO(( + "dhd_sysioc_thread: MACID is overwritten\n")); + } else { + DHD_ERROR(( + "dhd_sysioc_thread: _dhd_set_mac_address() failed\n")); + } } } } +#ifdef MCAST_LIST_ACCUMULATION + if (set_multicast) + _dhd_set_multicast_list(dhd, 0); +#endif /* MCAST_LIST_ACCUMULATION */ DHD_OS_WAKE_UNLOCK(&dhd->pub); dhd_net_if_unlock_local(dhd); @@ -1162,7 +1419,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr) if (ifidx == DHD_BAD_IF) return -1; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); dhd->set_macaddress = ifidx+1; up(&dhd->thr_sysioc_ctl.sema); @@ -1180,7 +1437,7 @@ dhd_set_multicast_list(struct net_device *dev) if (ifidx == DHD_BAD_IF) return; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); dhd->iflist[ifidx]->set_multicast = TRUE; up(&dhd->thr_sysioc_ctl.sema); } @@ -1200,7 +1457,6 @@ dhd_os_wlfc_unblock(dhd_pub_t *pub) { dhd_info_t *di = (dhd_info_t *)(pub->info); - (void)di; ASSERT(di != NULL); spin_unlock_bh(&di->wlfc_spinlock); return 1; @@ -1281,7 +1537,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) } else /* non-proptxstatus way */ - ret = dhd_bus_txdata(dhdp->bus, pktbuf); + ret = dhd_bus_txdata(dhdp->bus, pktbuf); #else ret = dhd_bus_txdata(dhdp->bus, pktbuf); #endif /* PROP_TXSTATUS */ @@ -1307,12 +1563,12 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) DHD_OS_WAKE_LOCK(&dhd->pub); /* Reject if down */ - if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) { + if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) { DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); netif_stop_queue(net); /* Send Event when bus down detected during data session */ - if (dhd->pub.busstate == DHD_BUS_DOWN) { + if (dhd->pub.up) { DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); net_os_send_hang_message(net); } @@ -1404,11 +1660,11 @@ dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - dhdp->txoff = state; ASSERT(dhd); if (ifidx == ALL_INTERFACES) { /* Flow control on all active interfaces */ + dhdp->txoff = state; for (i = 0; i < DHD_MAX_IFS; i++) { if (dhd->iflist[i]) { net = dhd->iflist[i]->net; @@ -1430,6 +1686,41 @@ dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) } } +#ifdef DHD_RX_DUMP +typedef struct { + uint16 type; + const char *str; +} PKTTYPE_INFO; + +static const PKTTYPE_INFO packet_type_info[] = +{ + { ETHER_TYPE_IP, "IP" }, + { ETHER_TYPE_ARP, "ARP" }, + { ETHER_TYPE_BRCM, "BRCM" }, + { ETHER_TYPE_802_1X, "802.1X" }, + { ETHER_TYPE_WAI, "WAPI" }, + { 0, ""} +}; + +static const char *_get_packet_type_str(uint16 type) +{ + int i; + int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; + + for (i = 0; i < n; i++) { + if (packet_type_info[i].type == type) + return packet_type_info[i].str; + } + + return packet_type_info[n].str; +} +#endif /* DHD_RX_DUMP */ + +#ifdef CUSTOMER_HW4 +extern int pkt_free; +extern int caller; +extern void *free_ptr; +#endif void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) { @@ -1441,10 +1732,17 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) int i; dhd_if_t *ifp; wl_event_msg_t event; - int tout = DHD_PACKET_TIMEOUT_MS; + int tout_rx = 0; + int tout_ctrl = 0; +#ifdef DHD_RX_DUMP +#ifdef DHD_RX_FULL_DUMP + int k; +#endif /* DHD_RX_FULL_DUMP */ + char *dump_data; + uint16 protocol; +#endif /* DHD_RX_DUMP */ - BCM_REFERENCE(tout); DHD_TRACE(("%s: Enter\n", __FUNCTION__)); for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { @@ -1462,14 +1760,17 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) /* Dropping packets before registering net device to avoid kernel panic */ - if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || - !dhd->pub.up) { +#ifndef PROP_TXSTATUS_VSDB + if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) { +#else + if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) { +#endif /* PROP_TXSTATUS_VSDB */ DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", __FUNCTION__)); PKTFREE(dhdp->osh, pktbuf, TRUE); continue; } -#endif +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ pnext = PKTNEXT(dhdp->osh, pktbuf); PKTSETNEXT(wl->sh.osh, pktbuf, NULL); @@ -1495,10 +1796,16 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) piggy-back on */ ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++; +#ifdef CUSTOMER_HW4 + /*if (numpkt == 1 && pkt_free && (free_ptr == pktbuf)) { + DHD_ERROR(("DHD TRACE2(FREE):%d %d %p\n", + pkt_free, caller, free_ptr)); + }*/ +#endif PKTFREE(dhdp->osh, pktbuf, TRUE); continue; } -#endif +#endif /* PROP_TXSTATUS */ skb = PKTTONATIVE(dhdp->osh, pktbuf); @@ -1514,6 +1821,46 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) eth = skb->data; len = skb->len; +#ifdef DHD_RX_DUMP + dump_data = skb->data; + protocol = (dump_data[12] << 8) | dump_data[13]; + DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol))); + +#ifdef DHD_RX_FULL_DUMP + if (protocol != ETHER_TYPE_BRCM) { + for (k = 0; k < skb->len; k++) { + DHD_ERROR(("%02X ", dump_data[k])); + if ((k & 15) == 15) + DHD_ERROR(("\n")); + } + DHD_ERROR(("\n")); + } +#endif /* DHD_RX_FULL_DUMP */ + + if (protocol != ETHER_TYPE_BRCM) { + if (dump_data[0] == 0xFF) { + DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__)); + + if ((dump_data[12] == 8) && + (dump_data[13] == 6)) { + DHD_ERROR(("%s: ARP %d\n", + __FUNCTION__, dump_data[0x15])); + } + } else if (dump_data[0] & 1) { + DHD_ERROR(("%s: MULTICAST: " MACDBG "\n", + __FUNCTION__, MAC2STRDBG(dump_data))); + } + + if (protocol == ETHER_TYPE_802_1X) { + DHD_ERROR(("ETHER_TYPE_802_1X: " + "ver %d, type %d, replay %d\n", + dump_data[14], dump_data[15], + dump_data[30])); + } + } + +#endif /* DHD_RX_DUMP */ + ifp = dhd->iflist[ifidx]; if (ifp == NULL) ifp = dhd->iflist[0]; @@ -1546,13 +1893,24 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) &event, &data); -#ifdef WLBTAMP wl_event_to_host_order(&event); + + if (!tout_ctrl) + tout_ctrl = DHD_PACKET_TIMEOUT_MS; + +#ifdef WLBTAMP if (event.event_type == WLC_E_BTA_HCI_EVENT) { dhd_bta_doevt(dhdp, data, event.datalen); } - tout = DHD_EVENT_TIMEOUT_MS; #endif /* WLBTAMP */ + +#if defined(PNO_SUPPORT) + if (event.event_type == WLC_E_PFN_NET_FOUND) { + tout_ctrl *= 2; + } +#endif /* PNO_SUPPORT */ + } else { + tout_rx = DHD_PACKET_TIMEOUT_MS; } ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); @@ -1585,7 +1943,9 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ } } - DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(dhdp, tout); + + DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); } void @@ -1685,11 +2045,12 @@ dhd_watchdog_thread(void *data) dhd_watchdog_prio:(MAX_RT_PRIO-1); setScheduler(current, SCHED_FIFO, ¶m); } - +#ifndef USE_KTHREAD_API DAEMONIZE("dhd_watchdog"); /* Run until signal received */ complete(&tsk->completed); +#endif while (1) if (down_interruptible (&tsk->sema) == 0) { @@ -1713,7 +2074,7 @@ dhd_watchdog_thread(void *data) /* Reschedule the watchdog */ if (dhd->wd_timer_valid) mod_timer(&dhd->timer, - jiffies + dhd_watchdog_ms * HZ / 1000); + jiffies + msecs_to_jiffies(dhd_watchdog_ms)); dhd_os_spin_unlock(&dhd->pub, flags); } dhd_os_sdunlock(&dhd->pub); @@ -1754,7 +2115,7 @@ static void dhd_watchdog(ulong data) /* Reschedule the watchdog */ if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); dhd_os_spin_unlock(&dhd->pub, flags); dhd_os_sdunlock(&dhd->pub); DHD_OS_WAKE_UNLOCK(&dhd->pub); @@ -1776,12 +2137,13 @@ dhd_dpc_thread(void *data) param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); setScheduler(current, SCHED_FIFO, ¶m); } - +#ifndef USE_KTHREAD_API DAEMONIZE("dhd_dpc"); /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ /* signal: thread has started */ complete(&tsk->completed); +#endif /* Run until signal received */ while (1) { @@ -1870,7 +2232,8 @@ dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) ioc.len = (uint)sizeof(buf); ioc.set = FALSE; - strcpy(buf, "toe_ol"); + strncpy(buf, "toe_ol", sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { /* Check for older dongle image that doesn't support toe_ol */ if (ret == -EIO) { @@ -1904,7 +2267,8 @@ dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) /* Set toe_ol as requested */ - strcpy(buf, "toe_ol"); + strncpy(buf, "toe_ol", sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32)); if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { @@ -1935,8 +2299,8 @@ dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - sprintf(info->driver, "wl"); - sprintf(info->version, "%lu", dhd->pub.drv_version); + snprintf(info->driver, sizeof(info->driver), "wl"); + snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); } struct ethtool_ops dhd_ethtool_ops = { @@ -1978,8 +2342,9 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) /* if dhd requested, identify ourselves */ if (strcmp(drvname, "?dhd") == 0) { - sprintf(info.driver, "dhd"); - strcpy(info.version, EPI_VERSION_STR); + snprintf(info.driver, sizeof(info.driver), "dhd"); + strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); + info.version[sizeof(info.version) - 1] = '\0'; } /* otherwise, require dongle to be up */ @@ -1990,11 +2355,11 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) /* finally, report dongle driver type */ else if (dhd->pub.iswl) - sprintf(info.driver, "wl"); + snprintf(info.driver, sizeof(info.driver), "wl"); else - sprintf(info.driver, "xx"); + snprintf(info.driver, sizeof(info.driver), "xx"); - sprintf(info.version, "%lu", dhd->pub.drv_version); + snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); if (copy_to_user(uaddr, &info, sizeof(info))) return -EFAULT; DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, @@ -2058,10 +2423,19 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) { + dhd_info_t * dhd; + if (!dhdp) return FALSE; - if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) && - (!dhdp->dongle_reset))) { + + dhd = (dhd_info_t *)dhdp->info; + if (dhd->thr_sysioc_ctl.thr_pid < 0) { + DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); + return FALSE; + } + + if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || + ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); net_os_send_hang_message(net); @@ -2087,7 +2461,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) /* send to dongle only if we are not waiting for reload already */ if (dhd->pub.hang_was_sent) { DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); DHD_OS_WAKE_UNLOCK(&dhd->pub); return OSL_ERROR(BCME_DONGLE_DOWN); } @@ -2135,7 +2509,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) /* Copy the ioc control structure part of ioctl request */ if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { - bcmerror = -BCME_BADADDR; + bcmerror = BCME_BADADDR; goto done; } @@ -2143,7 +2517,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) if (ioc.buf) { if (ioc.len == 0) { DHD_TRACE(("%s: ioc.len=0, returns BCME_BADARG \n", __FUNCTION__)); - bcmerror = -BCME_BADARG; + bcmerror = BCME_BADARG; goto done; } buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); @@ -2155,11 +2529,11 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) */ { if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) { - bcmerror = -BCME_NOMEM; + bcmerror = BCME_NOMEM; goto done; } if (copy_from_user(buf, ioc.buf, buflen)) { - bcmerror = -BCME_BADADDR; + bcmerror = BCME_BADADDR; goto done; } } @@ -2168,12 +2542,12 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) /* To differentiate between wl and dhd read 4 more byes */ if ((copy_from_user(&driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), sizeof(uint)) != 0)) { - bcmerror = -BCME_BADADDR; + bcmerror = BCME_BADADDR; goto done; } if (!capable(CAP_NET_ADMIN)) { - bcmerror = -BCME_EPERM; + bcmerror = BCME_EPERM; goto done; } @@ -2308,17 +2682,17 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd) #endif for (i = 1; i < DHD_MAX_IFS; i++) { + dhd_net_if_lock_local(dhd); if (dhd->iflist[i]) { DHD_TRACE(("Deleting IF: %d \n", i)); if ((dhd->iflist[i]->state != DHD_IF_DEL) && (dhd->iflist[i]->state != DHD_IF_DELETING)) { dhd->iflist[i]->state = DHD_IF_DEL; dhd->iflist[i]->idx = i; - dhd_net_if_lock_local(dhd); dhd_op_if(dhd->iflist[i]); - dhd_net_if_unlock_local(dhd); } } + dhd_net_if_unlock_local(dhd); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) @@ -2330,10 +2704,17 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd) } #endif /* WL_CFG80211 */ +#if defined(WL_CFG80211) && defined(SUPPORT_DEEP_SLEEP) +/* Flags to indicate if we distingish power off policy when + * user set the memu "Keep Wi-Fi on during sleep" to "Never" + */ +int sleep_never = 0; +#endif + static int dhd_stop(struct net_device *net) { - int ifidx; + int ifidx = 0; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); DHD_OS_WAKE_LOCK(&dhd->pub); DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); @@ -2343,6 +2724,10 @@ dhd_stop(struct net_device *net) ifidx = dhd_net2idx(dhd, net); BCM_REFERENCE(ifidx); + /* Set state and stop OS transmissions */ + netif_stop_queue(net); + dhd->pub.up = 0; + #ifdef WL_CFG80211 if (ifidx == 0) { wl_cfg80211_down(NULL); @@ -2359,24 +2744,37 @@ dhd_stop(struct net_device *net) #endif #ifdef PROP_TXSTATUS + dhd_os_wlfc_block(&dhd->pub); dhd_wlfc_cleanup(&dhd->pub); + dhd_os_wlfc_unblock(&dhd->pub); #endif - /* Set state and stop OS transmissions */ - dhd->pub.up = 0; - netif_stop_queue(net); /* Stop the protocol module */ dhd_prot_stop(&dhd->pub); + OLD_MOD_DEC_USE_COUNT; +exit: #if defined(WL_CFG80211) - if (ifidx == 0 && !dhd_download_fw_on_driverload) - wl_android_wifi_off(net); + if (ifidx == 0) { + if (!dhd_download_fw_on_driverload) + wl_android_wifi_off(net); +#ifdef SUPPORT_DEEP_SLEEP + else { + /* CSP#505233: Flags to indicate if we distingish + * power off policy when user set the memu + * "Keep Wi-Fi on during sleep" to "Never" + */ + if (sleep_never) { + dhd_deepsleep(net, 1); + sleep_never = 0; + } + } +#endif /* SUPPORT_DEEP_SLEEP */ + } #endif - dhd->pub.hang_was_sent = 0; dhd->pub.rxcnt_timeout = 0; dhd->pub.txcnt_timeout = 0; - OLD_MOD_DEC_USE_COUNT; -exit: + DHD_OS_WAKE_UNLOCK(&dhd->pub); return 0; } @@ -2385,28 +2783,53 @@ static int dhd_open(struct net_device *net) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - uint up = 0; #ifdef TOE uint32 toe_ol; #endif int ifidx; int32 ret = 0; + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_ERROR(("%s: Enter, net[%p]\n", __FUNCTION__, net)); /* Update FW path if it was changed */ - if ((firmware_path != NULL) && (firmware_path[0] != '\0')) { + if (strlen(firmware_path) != 0) { if (firmware_path[strlen(firmware_path)-1] == '\n') firmware_path[strlen(firmware_path)-1] = '\0'; - strcpy(fw_path, firmware_path); + strncpy(fw_path, firmware_path, sizeof(fw_path)-1); + fw_path[sizeof(fw_path)-1] = '\0'; +#if defined(SUPPORT_MULTIPLE_REVISION) + ret = concate_revision(dhd->pub.bus, fw_path, MOD_PARAM_PATHLEN); + if (ret != 0) { + DHD_ERROR(("%s: fail to concatnate revison \n", __FUNCTION__)); + goto exit; + } +#endif firmware_path[0] = '\0'; } + /* Update NVRAM path if it was changed */ + if (!dhd_download_fw_on_driverload && (strlen(nvram_path) != 0)) { + if (nvram_path[strlen(nvram_path)-1] == '\n') + nvram_path[strlen(nvram_path)-1] = '\0'; + strcpy(nv_path, nvram_path); + nvram_path[0] = '\0'; + } + + dhd->pub.dongle_trap_occured = 0; + dhd->pub.hang_was_sent = 0; #if !defined(WL_CFG80211) /* * Force start if ifconfig_up gets called before START command * We keep WEXT's wl_control_wl_start to provide backward compatibility * This should be removed in the future */ - wl_control_wl_start(net); + ret = wl_control_wl_start(net); + if (ret != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } + #endif ifidx = dhd_net2idx(dhd, net); @@ -2431,20 +2854,52 @@ dhd_open(struct net_device *net) if (!dhd_download_fw_on_driverload) { ret = wl_android_wifi_on(net); if (ret != 0) { - DHD_ERROR(("wl_android_wifi_on failed (%d)\n", ret)); + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; goto exit; } + } else { +#ifdef SUPPORT_DEEP_SLEEP + /* Flags to indicate if we distingish + * power off policy when user set the memu + * "Keep Wi-Fi on during sleep" to "Never" + */ + if (sleep_never) { + dhd_deepsleep(net, 0); + sleep_never = 0; + } +#endif /* SUPPORT_DEEP_SLEEP */ } #endif if (dhd->pub.busstate != DHD_BUS_DATA) { - /* try to bring up bus */ - if ((ret = dhd_bus_start(&dhd->pub)) != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - ret = -1; - goto exit; +#if defined(CUSTOMER_HW4) +#define WAIT_DHDBUS_READY 5 + /* Delay ifup until insmod completed in case of module type */ + if (dhd_download_fw_on_driverload) { + uint retry = 0; + + do { + OSL_DELAY(100*1000); + } while ((dhd->pub.busstate != DHD_BUS_DATA) && + (retry++ < WAIT_DHDBUS_READY)); + + if (dhd->pub.busstate != DHD_BUS_DATA) { + DHD_ERROR(("%s: call dev open before insmod complete!\n", + __FUNCTION__)); + ret = -1; + goto exit; + } } + else +#endif /* CUSTOMER_HW4 */ + /* try to bring up bus */ + if ((ret = dhd_bus_start(&dhd->pub)) != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } } @@ -2472,16 +2927,15 @@ dhd_open(struct net_device *net) netif_start_queue(net); dhd->pub.up = 1; - /* Fire a WLC_UP for primary interface to enable RF */ - if (ifidx == 0) - dhd_wl_ioctl_cmd(&dhd->pub, WLC_UP, (char *)&up, sizeof(up), TRUE, 0); - #ifdef BCMDBGFS dhd_dbg_init(&dhd->pub); #endif OLD_MOD_INC_USE_COUNT; exit: + if (ret) + dhd_stop(net); + DHD_OS_WAKE_UNLOCK(&dhd->pub); return ret; } @@ -2503,7 +2957,7 @@ int dhd_do_driver_init(struct net_device *net) DHD_TRACE(("Driver already Inititalized. Nothing to do")); return 0; } - + DHD_ERROR(("%s: call dhd_open\n", __FUNCTION__)); if (dhd_open(net) < 0) { DHD_ERROR(("Driver Init Failed \n")); return -1; @@ -2526,6 +2980,7 @@ dhd_osl_detach(osl_t *osh) } osl_detach(osh); #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + dhd_registration_check = FALSE; up(&dhd_registration_sem); #if defined(BCMLXSDMMC) up(&dhd_chipup_sem); @@ -2569,7 +3024,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, ifp->state = DHD_IF_ADD; ifp->idx = ifidx; ifp->bssidx = bssidx; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); up(&dhd->thr_sysioc_ctl.sema); } else ifp->net = (struct net_device *)handle; @@ -2597,7 +3052,7 @@ dhd_del_if(dhd_info_t *dhd, int ifidx) ifp->state = DHD_IF_DEL; ifp->idx = ifidx; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); up(&dhd->thr_sysioc_ctl.sema); } @@ -2639,10 +3094,21 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); /* updates firmware nvram path if it was provided as module parameters */ - if ((firmware_path != NULL) && (firmware_path[0] != '\0')) - strcpy(fw_path, firmware_path); - if ((nvram_path != NULL) && (nvram_path[0] != '\0')) - strcpy(nv_path, nvram_path); + if (strlen(firmware_path) != 0) { + strncpy(fw_path, firmware_path, sizeof(fw_path) - 1); + fw_path[sizeof(fw_path) - 1] = '\0'; + } + if (strlen(nvram_path) != 0) { + strncpy(nv_path, nvram_path, sizeof(nv_path) -1); + nv_path[sizeof(nv_path) -1] = '\0'; + } +#if defined(SUPPORT_MULTIPLE_REVISION) + if (strlen(fw_path) != 0 && + concate_revision(bus, fw_path, MOD_PARAM_PATHLEN) != 0) { + DHD_ERROR(("%s: fail to concatnate revison \n", __FUNCTION__)); + goto fail; + } +#endif /* Allocate etherdev, including space for private structure */ if (!(net = alloc_etherdev(sizeof(dhd)))) { @@ -2704,7 +3170,11 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #ifdef PROP_TXSTATUS spin_lock_init(&dhd->wlfc_spinlock); +#ifdef PROP_TXSTATUS_VSDB + dhd->pub.wlfc_enabled = FALSE; +#else dhd->pub.wlfc_enabled = TRUE; +#endif /* PROP_TXSTATUS_VSDB */ #endif /* PROP_TXSTATUS */ /* Initialize other structure content */ @@ -2719,13 +3189,19 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) /* Initialize Wakelock stuff */ spin_lock_init(&dhd->wakelock_spinlock); dhd->wakelock_counter = 0; - dhd->wakelock_timeout_enable = 0; + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; #ifdef CONFIG_HAS_WAKELOCK wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); + wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); +#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) + wake_lock_init(&dhd->pub.pno_wakelock, WAKE_LOCK_SUSPEND, "pno_wake_lock"); +#endif #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 mutex_init(&dhd->dhd_net_if_mutex); + mutex_init(&dhd->dhd_suspend_mutex); #endif dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; @@ -2775,7 +3251,11 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) if (dhd_dpc_prio >= 0) { /* Initialize watchdog thread */ +#ifdef USE_KTHREAD_API + PROC_START2(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); +#else PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0); +#endif } else { dhd->thr_wdt_ctl.thr_pid = -1; } @@ -2783,7 +3263,11 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) /* Set up the bottom half handler */ if (dhd_dpc_prio >= 0) { /* Initialize DPC thread */ +#ifdef USE_KTHREAD_API + PROC_START2(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); +#else PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0); +#endif } else { /* use tasklet for dpc */ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); @@ -2796,12 +3280,18 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #endif /* DHDTHREAD */ if (dhd_sysioc) { +#ifdef USE_KTHREAD_API + PROC_START2(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0, "dhd_sysioc"); +#else PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0); +#endif } else { dhd->thr_sysioc_ctl.thr_pid = -1; } dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) + INIT_WORK(&dhd->work_hang, dhd_hang_process); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ /* * Save the dhd_info into the priv */ @@ -2811,7 +3301,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) register_pm_notifier(&dhd_sleep_pm_notifier); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; dhd->early_suspend.suspend = dhd_early_suspend; dhd->early_suspend.resume = dhd_late_resume; @@ -2866,8 +3356,8 @@ dhd_bus_start(dhd_pub_t *dhdp) /* wake lock moved to dhdsdio_download_firmware */ if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, fw_path, nv_path))) { - DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", - __FUNCTION__, fw_path, nv_path)); + DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware or nvram path is wrong\n", + __FUNCTION__)); #ifdef DHDTHREAD if (dhd->threads_only) dhd_os_sdunlock(dhdp); @@ -2897,7 +3387,7 @@ dhd_bus_start(dhd_pub_t *dhdp) #endif /* DHDTHREAD */ return ret; } -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) /* Host registration for OOB interrupt */ if (bcmsdh_register_oob_intr(dhdp)) { /* deactivate timer and wait for the handler to finish */ @@ -2915,9 +3405,11 @@ dhd_bus_start(dhd_pub_t *dhdp) return -ENODEV; } +#ifndef BCMSPI_ANDROID /* Enable oob at firmware */ dhd_enable_oob_intr(dhd->pub.bus, TRUE); -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* !BCMSPI_ANDROID */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ /* If bus is not ready, can't come up */ if (dhd->pub.busstate != DHD_BUS_DATA) { @@ -2938,17 +3430,50 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ -#ifdef READ_MACADDR - dhd_read_macaddr(dhd); +#ifdef BCMSDIOH_TXGLOM + if ((dhd->pub.busstate == DHD_BUS_DATA) && bcmsdh_glom_enabled()) { + dhd_txglom_enable(dhdp, TRUE); + } #endif - /* Bus is ready, do any protocol initialization */ - if ((ret = dhd_prot_init(&dhd->pub)) < 0) - return ret; - +#ifdef CUSTOMER_HW4 +#ifdef USE_CID_CHECK + dhd_check_module_cid(dhdp); +#endif +#ifdef READ_MACADDR + dhd_read_macaddr(dhd, &dhd->pub.mac); +#endif +#ifdef RDWR_MACADDR + dhd_check_rdwr_macaddr(dhd, &dhd->pub, &dhd->pub.mac); +#endif +#ifdef RDWR_KORICS_MACADDR + dhd_write_rdwr_korics_macaddr(dhd, &dhd->pub.mac); +#endif +#else +#ifdef READ_MACADDR + dhd_read_macaddr(dhd); +#endif +#endif /* CUSTOMER_HW4 */ + + /* Bus is ready, do any protocol initialization */ + if ((ret = dhd_prot_init(&dhd->pub)) < 0) + return ret; + +#ifdef CUSTOMER_HW4 +#ifdef GET_MAC_FROM_OTP + dhd_check_module_mac(dhdp, &dhd->pub.mac); +#endif +#ifdef RDWR_MACADDR + dhd_write_rdwr_macaddr(&dhd->pub.mac); +#endif +#ifdef WRITE_MACADDR + dhd_write_macaddr(&dhd->pub.mac); +#endif +#else #ifdef WRITE_MACADDR dhd_write_macaddr(dhd->pub.mac.octet); #endif +#endif /* CUSTOMER_HW4 */ #ifdef ARP_OFFLOAD_SUPPORT if (dhd->pend_ipaddr) { @@ -2962,31 +3487,78 @@ dhd_bus_start(dhd_pub_t *dhdp) return 0; } +bool dhd_is_concurrent_mode(dhd_pub_t *dhd) +{ + if (!dhd) + return FALSE; + + if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) + return TRUE; + else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == + DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) + return TRUE; + else + return FALSE; +} + #if !defined(AP) && defined(WLP2P) -/* For Android ICS MR2 release, the concurrent mode is enabled by default and the firmware +/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware * would still be named as fw_bcmdhd_apsta. */ -static u32 -dhd_concurrent_fw(dhd_pub_t *dhd) +uint32 +dhd_get_concurrent_capabilites(dhd_pub_t *dhd) { - int ret = 0; + int32 ret = 0; char buf[WLC_IOCTL_SMLEN]; - - if ((!op_mode) && (strstr(fw_path, "_p2p") == NULL) && - (strstr(fw_path, "_apsta") == NULL)) { - /* Given path is for the STA firmware. Check whether P2P support is present in - * the firmware. If so, set mode as P2P (concurrent support). - */ + bool mchan_supported = FALSE; + /* if dhd->op_mode is already set for HOSTAP, + * that means we only will use the mode as it is + */ + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) + return 0; + memset(buf, 0, sizeof(buf)); + bcm_mkiovar("cap", 0, 0, buf, sizeof(buf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), + FALSE, 0)) < 0) { + DHD_ERROR(("%s: Get Capability failed (error=%d)\n", + __FUNCTION__, ret)); + return 0; + } + if (strstr(buf, "vsdb")) { + mchan_supported = TRUE; + } + if (strstr(buf, "p2p") == NULL) { + DHD_TRACE(("Chip does not support p2p\n")); + return 0; + } + else { + /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ memset(buf, 0, sizeof(buf)); bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) { - DHD_TRACE(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); - } else if (buf[0] == 1) { - DHD_TRACE(("%s: P2P is supported\n", __FUNCTION__)); - return 1; + DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); + return 0; + } + else { + if (buf[0] == 1) { + /* By default, chip supports single chan concurrency, + * now lets check for mchan + */ + ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; + if (mchan_supported) + ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; +#if defined(WL_ENABLE_P2P_IF) + /* For customer_hw4, although ICS, + * we still support concurrent mode + */ + return ret; +#else + return 0; +#endif + } } } return 0; @@ -2999,26 +3571,55 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) char eventmask[WL_EVENTING_MASK_LEN]; char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - uint power_mode = PM_OFF; /* PM_FAST; */ +#if !defined(WL_CFG80211) + uint up = 0; +#endif /* !defined(WL_CFG80211) */ + uint power_mode = PM_FAST; uint32 dongle_align = DHD_SDALIGN; - uint32 glom = 0; + uint32 glom = CUSTOM_GLOM_SETTING; +#if defined(VSDB) || defined(ROAM_ENABLE) + uint bcn_timeout = 8; +#else uint bcn_timeout = 4; +#endif +#ifdef ENABLE_BCN_LI_BCN_WAKEUP + uint32 bcn_li_bcn = 1; +#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ uint retry_max = 3; #if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; #endif - int scan_assoc_time = DHD_SCAN_ACTIVE_TIME; - int scan_unassoc_time = 40; + int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; + int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; int scan_passive_time = DHD_SCAN_PASSIVE_TIME; char buf[WLC_IOCTL_SMLEN]; char *ptr; uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ - uint16 chipID; +#ifdef ROAM_ENABLE + uint roamvar = 0; + int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; + int roam_scan_period[2] = {10, WLC_BAND_ALL}; +#ifdef ROAM_AP_ENV_DETECTION + int roam_env_mode = AP_ENV_INDETERMINATE; +#endif /* ROAM_AP_ENV_DETECTION */ + int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; +#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC + int roam_fullscan_period = 60; +#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ + int roam_fullscan_period = 120; +#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ +#else +#ifdef DISABLE_BUILTIN_ROAM + uint roamvar = 1; +#endif /* DISABLE_BUILTIN_ROAM */ +#endif /* ROAM_ENABLE */ + #if defined(SOFTAP) uint dtim = 1; #endif #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ + struct ether_addr p2p_ea; #endif #if defined(AP) || defined(WLP2P) @@ -3027,7 +3628,27 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef GET_CUSTOM_MAC_ENABLE struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ - +#ifdef OKC_SUPPORT + uint32 okc = 1; +#endif +#ifdef DISABLE_11N + uint32 nmode = 0; +#else +#ifdef AMPDU_HOSTREORDER + uint32 hostreorder = 1; +#endif +#endif /* DISABLE_11N */ +#if defined(VSDB) && defined(CUSTOMER_HW4) + int interference_mode = 3; +#endif +#ifdef PROP_TXSTATUS +#ifdef PROP_TXSTATUS_VSDB + dhd->wlfc_enabled = FALSE; + /* enable WLFC only if the firmware is VSDB */ +#else + dhd->wlfc_enabled = TRUE; +#endif /* PROP_TXSTATUS_VSDB */ +#endif /* PROP_TXSTATUS */ DHD_TRACE(("Enter %s\n", __FUNCTION__)); dhd->op_mode = 0; #ifdef GET_CUSTOM_MAC_ENABLE @@ -3040,6 +3661,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); return BCME_NOTUP; } + memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN); } else { #endif /* GET_CUSTOM_MAC_ENABLE */ /* Get the default device MAC address directly from firmware */ @@ -3057,13 +3679,23 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #endif /* GET_CUSTOM_MAC_ENABLE */ + + if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || + (op_mode == DHD_FLAG_HOSTAP_MODE)) { #ifdef SET_RANDOM_MAC_SOFTAP - if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) { uint rand_mac; - +#endif + dhd->op_mode = DHD_FLAG_HOSTAP_MODE; +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 0; +#endif +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = FALSE; +#endif +#ifdef SET_RANDOM_MAC_SOFTAP srandom32((uint)jiffies); rand_mac = random32(); - iovbuf[0] = 0x02; /* locally administered bit */ + iovbuf[0] = 0x02; /* locally administered bit */ iovbuf[1] = 0x1A; iovbuf[2] = 0x11; iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; @@ -3076,64 +3708,67 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); } else memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); - } #endif /* SET_RANDOM_MAC_SOFTAP */ +#if !defined(AP) && defined(WL_CFG80211) + /* Turn off MPC in AP mode */ + bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); + } +#endif - DHD_TRACE(("Firmware = %s\n", fw_path)); -#if !defined(AP) && defined(WLP2P) - /* Check if firmware with WFD support used */ - if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || (op_mode == 0x04) || - (dhd_concurrent_fw(dhd))) { - bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret)); - } else { - dhd->op_mode |= WFD_MASK; + } + else { + uint32 concurrent_mode = 0; + if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || + (op_mode == DHD_FLAG_P2P_MODE)) { #if defined(ARP_OFFLOAD_SUPPORT) arpoe = 0; -#endif /* (ARP_OFFLOAD_SUPPORT) */ +#endif #ifdef PKT_FILTER_SUPPORT dhd_pkt_filter_enable = FALSE; #endif + dhd->op_mode = DHD_FLAG_P2P_MODE; } - } -#endif - -#if !defined(AP) && defined(WL_CFG80211) - /* Check if firmware with HostAPD support used */ - if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) { - /* Turn off MPC in AP mode */ - bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); - } else { - dhd->op_mode |= HOSTAPD_MASK; + else + dhd->op_mode = DHD_FLAG_STA_MODE; +#if !defined(AP) && defined(WLP2P) + if ((concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { #if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif /* (ARP_OFFLOAD_SUPPORT) */ -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; + arpoe = 1; #endif + dhd->op_mode |= concurrent_mode; + } + + /* Check if we are enabling p2p */ + if (dhd->op_mode & DHD_FLAG_P2P_MODE) { + bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, + iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret)); } - } -#endif - if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) { - /* STA only operation mode */ - dhd->op_mode |= STA_MASK; -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = TRUE; -#endif + memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); + ETHER_SET_LOCALADDR(&p2p_ea); + bcm_mkiovar("p2p_da_override", (char *)&p2p_ea, + ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, + iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); + } else { + DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); + } + } +#else + (void)concurrent_mode; +#endif } - DHD_ERROR(("Firmware up: op_mode=%d, " - "Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - dhd->op_mode, - dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2], - dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5])); - + DHD_ERROR(("Firmware up: op_mode=0x%04x, " + "Broadcom Dongle Host Driver mac="MACDBG"\n", + dhd->op_mode, + MAC2STRDBG(dhd->mac.octet))); /* Set Country code */ if (dhd->dhd_cspec.ccode[0] != 0) { bcm_mkiovar("country", (char *)&dhd->dhd_cspec, @@ -3147,17 +3782,54 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); +#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) + /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ + bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ +#ifdef ROAM_ENABLE + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, + sizeof(roam_scan_period), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret)); + if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, + sizeof(roam_delta), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); + bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); +#ifdef ROAM_AP_ENV_DETECTION + if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) { + bcm_mkiovar("roam_env_detection", (char *)&roam_env_mode, + 4, iovbuf, sizeof(iovbuf)); + if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) == BCME_OK) + dhd->roam_env_detection = TRUE; + else + dhd->roam_env_detection = FALSE; + } +#endif /* ROAM_AP_ENV_DETECTION */ +#endif /* ROAM_ENABLE */ + +#ifdef OKC_SUPPORT + bcm_mkiovar("okc_enable", (char *)&okc, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif + +#ifdef CONFIG_CONTROL_PM + sec_control_pm(dhd, &power_mode); +#else /* Set PowerSave mode */ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); +#endif /* Match Host and Dongle rx alignment */ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - /* disable glom option for some chips */ - chipID = (uint16)dhd_bus_chip_id(dhd); - if ((chipID == BCM4330_CHIP_ID) || (chipID == BCM4329_CHIP_ID)) { - DHD_INFO(("%s disable glom for chipID=0x%X\n", __FUNCTION__, chipID)); + if (glom != DEFAULT_GLOM_VALUE) { + DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom)); bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); } @@ -3176,6 +3848,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif /* defined(AP) && !defined(WLP2P) */ +#if defined(CUSTOMER_HW4) && defined(MIMO_ANT_SETTING) + dhd_sel_ant_from_file(dhd); +#endif /* defined(CUSTOMER_HW4) && defined(MIMO_ANT_SETTING) */ + #if defined(SOFTAP) if (ap_fw_loaded == TRUE) { dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); @@ -3190,9 +3866,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(SOFTAP) if (ap_fw_loaded == FALSE) #endif - if ((res = dhd_keep_alive_onoff(dhd)) < 0) - DHD_ERROR(("%s set keeplive failed %d\n", - __FUNCTION__, res)); + if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { + if ((res = dhd_keep_alive_onoff(dhd)) < 0) + DHD_ERROR(("%s set keeplive failed %d\n", + __FUNCTION__, res)); + } } #endif /* defined(KEEP_ALIVE) */ @@ -3208,6 +3886,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) setbit(eventmask, WLC_E_SET_SSID); setbit(eventmask, WLC_E_PRUNE); setbit(eventmask, WLC_E_AUTH); + setbit(eventmask, WLC_E_ASSOC); setbit(eventmask, WLC_E_REASSOC); setbit(eventmask, WLC_E_REASSOC_IND); setbit(eventmask, WLC_E_DEAUTH); @@ -3222,8 +3901,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) setbit(eventmask, WLC_E_MIC_ERROR); setbit(eventmask, WLC_E_ASSOC_REQ_IE); setbit(eventmask, WLC_E_ASSOC_RESP_IE); +#ifndef WL_CFG80211 setbit(eventmask, WLC_E_PMKID_CACHE); setbit(eventmask, WLC_E_TXFAIL); +#endif setbit(eventmask, WLC_E_JOIN_START); setbit(eventmask, WLC_E_SCAN_COMPLETE); #ifdef WLMEDIA_HTSF @@ -3234,15 +3915,23 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* PNO_SUPPORT */ /* enable dongle roaming event */ setbit(eventmask, WLC_E_ROAM); +#ifdef BCMCCX + setbit(eventmask, WLC_E_ADDTS_IND); + setbit(eventmask, WLC_E_DELTS_IND); +#endif /* BCMCCX */ #ifdef WL_CFG80211 setbit(eventmask, WLC_E_ESCAN_RESULT); - if ((dhd->op_mode & WFD_MASK) == WFD_MASK) { + if (dhd->op_mode & DHD_FLAG_P2P_MODE) { setbit(eventmask, WLC_E_ACTION_FRAME_RX); setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE); setbit(eventmask, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE); - setbit(eventmask, WLC_E_P2P_PROBREQ_MSG); setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); } +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) + else { + setbit(eventmask, WLC_E_ACTION_FRAME_RX); + } +#endif /* WES_SUPPORT */ #endif /* WL_CFG80211 */ /* Write updated Event mask */ @@ -3275,23 +3964,79 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* ARP_OFFLOAD_SUPPORT */ #ifdef PKT_FILTER_SUPPORT - /* Setup defintions for pktfilter , enable in suspend */ - dhd->pktfilter_count = 4; + /* Setup default defintions for pktfilter , enable in suspend */ + dhd->pktfilter_count = 5; /* Setup filter to allow only unicast */ dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; dhd->pktfilter[1] = NULL; dhd->pktfilter[2] = NULL; dhd->pktfilter[3] = NULL; + /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ + dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; + +#ifdef CUSTOMER_HW4 +#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER + dhd->pktfilter_count = 4; + /* Setup filter to block broadcast and NAT Keepalive packets */ + dhd->pktfilter[0] = "100 0 0 0 0xffffff 0xffffff"; /* discard all broadcast packets */ + dhd->pktfilter[1] = "102 0 0 36 0xffffffff 0x11940009"; /* discard NAT Keepalive packets */ + dhd->pktfilter[2] = "104 0 0 38 0xffffffff 0x11940009"; /* discard NAT Keepalive packets */ + dhd->pktfilter[3] = NULL; +#else + /* Setup filter to allow only unicast */ +#if defined(BLOCK_IPV6_PACKET) + dhd->pktfilter[0] = "100 0 0 0 " + HEX_PREF_STR UNI_FILTER_STR ZERO_ADDR_STR ETHER_TYPE_STR IPV6_FILTER_STR + " " + HEX_PREF_STR ZERO_ADDR_STR ZERO_ADDR_STR ETHER_TYPE_STR ZERO_TYPE_STR; +#else + dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; +#endif /* BLOCK_IPV6_PACKET */ +#if defined(PASS_IPV4_SUSPEND) + dhd->pktfilter_count = 5; + dhd->pktfilter[4] = "104 0 0 0 0xFFFFFF 0x01005E"; +#endif +#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ +#ifdef PASS_ARP_PACKET + dhd->pktfilter[dhd->pktfilter_count++] = "105 0 0 12 0xFFFF 0x0806"; +#endif +#endif /* CUSTOMER_HW4 */ + #if defined(SOFTAP) if (ap_fw_loaded) { - int i; - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 0, dhd_master_mode); - } + dhd_enable_packet_filter(0, dhd); } #endif /* defined(SOFTAP) */ + dhd_set_packet_filter(dhd); #endif /* PKT_FILTER_SUPPORT */ +#ifdef DISABLE_11N + bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); +#else +#ifdef AMPDU_HOSTREORDER + bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, buf, sizeof(buf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); +#endif /* AMPDU_HOSTREORDER */ +#endif /* DISABLE_11N */ + +#if !defined(WL_CFG80211) + /* Force STA UP */ + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) { + DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret)); + goto done; + } +#endif + +#if defined(VSDB) && defined(CUSTOMER_HW4) + dhd_wl_ioctl_cmd(dhd, WLC_SET_INTERFERENCE_MODE, + (int *)&interference_mode, sizeof(int), TRUE, 0); +#endif + +#ifdef ENABLE_BCN_LI_BCN_WAKEUP + bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); @@ -3303,6 +4048,18 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcmstrtok(&ptr, "\n", 0); /* Print fw version info */ DHD_ERROR(("Firmware version = %s\n", buf)); + + dhd_set_version_info(dhd, buf); + + DHD_BLOG(buf, strlen(buf) + 1); + DHD_BLOG(dhd_version, strlen(dhd_version) + 1); + + /* Check and adjust IOCTL response timeout for Manufactring firmware */ + if (strstr(buf, MANUFACTRING_FW) != NULL) { + dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT * 10); + DHD_ERROR(("%s : adjust IOCTL response time for Manufactring Firmware\n", + __FUNCTION__)); + } } done: @@ -3448,13 +4205,16 @@ static int dhd_device_event(struct notifier_block *this, } #ifdef AOE_IP_ALIAS_SUPPORT - if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) { - DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", - __FUNCTION__)); - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); + if (!(dhd_pub->op_mode & DHD_FLAG_HOSTAP_MODE)) { + if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) { + /* 0x3a = ':' */ + DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", + __FUNCTION__)); + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); + } + else + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); } - else - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); #endif break; @@ -3463,17 +4223,21 @@ static int dhd_device_event(struct notifier_block *this, __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); dhd->pend_ipaddr = 0; #ifdef AOE_IP_ALIAS_SUPPORT - if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) { - DHD_ARPOE(("%s: primary interface is down, AOE clr all\n", - __FUNCTION__)); - dhd_aoe_hostip_clr(&dhd->pub); - dhd_aoe_arp_clr(&dhd->pub); - } else - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE); + if (!(dhd_pub->op_mode & DHD_FLAG_HOSTAP_MODE)) { + if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) { + /* 0x3a = ':' */ + DHD_ARPOE(("%s: primary interface is down," + " AOE clr all\n", __FUNCTION__)); + dhd_aoe_hostip_clr(&dhd->pub); + dhd_aoe_arp_clr(&dhd->pub); + } else + aoe_update_host_ipv4_table(dhd_pub, + ifa->ifa_address, FALSE); + } #else dhd_aoe_hostip_clr(&dhd->pub); dhd_aoe_arp_clr(&dhd->pub); -#endif +#endif /* AOE_IP_ALIAS_SUPPORT */ break; default: @@ -3494,7 +4258,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) int err = 0; uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; - DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); + DHD_ERROR(("%s: ifidx %d\n", __FUNCTION__, ifidx)); ASSERT(dhd && dhd->iflist[ifidx]); @@ -3525,6 +4289,8 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) #else net->netdev_ops = &dhd_ops_pri; #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) + memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); } else { /* * We have to use the primary MAC for virtual interfaces @@ -3566,10 +4332,13 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) goto fail; } printf("Broadcom Dongle Host Driver: register interface [%s]" - " MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + " MAC: "MACDBG"\n", net->name, - net->dev_addr[0], net->dev_addr[1], net->dev_addr[2], - net->dev_addr[3], net->dev_addr[4], net->dev_addr[5]); +#if defined(CUSTOMER_HW4) + MAC2STRDBG(dhd->pub.mac.octet)); +#else + MAC2STRDBG(net->dev_addr)); +#endif /* CUSTOMER_HW4 */ #if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211) wl_iw_iscan_set_scan_broadcast_prep(net, 1); @@ -3577,6 +4346,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) if (ifidx == 0) { + dhd_registration_check = TRUE; up(&dhd_registration_sem); } #endif @@ -3614,9 +4384,9 @@ dhd_bus_detach(dhd_pub_t *dhdp) dhd_bus_stop(dhd->pub.bus, TRUE); } -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) bcmsdh_unregister_oob_intr(); -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ } } } @@ -3637,6 +4407,7 @@ void dhd_detach(dhd_pub_t *dhdp) DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); + dhd->pub.up = 0; if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { /* Give sufficient time for threads to start running in case * dhd_attach() has failed @@ -3644,17 +4415,27 @@ void dhd_detach(dhd_pub_t *dhdp) osl_delay(1000*100); } + if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { + dhd_bus_detach(dhdp); + + if (dhdp->prot) + dhd_prot_detach(dhdp); + } + #ifdef ARP_OFFLOAD_SUPPORT unregister_inetaddr_notifier(&dhd_notifier); #endif /* ARP_OFFLOAD_SUPPORT */ -#if defined(CONFIG_HAS_EARLYSUSPEND) +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { if (dhd->early_suspend.suspend) unregister_early_suspend(&dhd->early_suspend); } #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + cancel_work_sync(&dhd->work_hang); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ #if defined(CONFIG_WIRELESS_EXT) if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { @@ -3663,7 +4444,7 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif /* defined(CONFIG_WIRELESS_EXT) */ - if (&dhd->thr_sysioc_ctl.thr_pid >= 0) { + if (dhd->thr_sysioc_ctl.thr_pid >= 0) { PROC_STOP(&dhd->thr_sysioc_ctl); } @@ -3673,31 +4454,33 @@ void dhd_detach(dhd_pub_t *dhdp) dhd_if_t *ifp; /* Cleanup virtual interfaces */ - for (i = 1; i < DHD_MAX_IFS; i++) + for (i = 1; i < DHD_MAX_IFS; i++) { + dhd_net_if_lock_local(dhd); if (dhd->iflist[i]) { dhd->iflist[i]->state = DHD_IF_DEL; dhd->iflist[i]->idx = i; dhd_op_if(dhd->iflist[i]); } + dhd_net_if_unlock_local(dhd); + } /* delete primary interface 0 */ ifp = dhd->iflist[0]; ASSERT(ifp); ASSERT(ifp->net); + if (ifp && ifp->net) { #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - if (ifp->net->open) + if (ifp->net->open) #else - if (ifp->net->netdev_ops == &dhd_ops_pri) + if (ifp->net->netdev_ops == &dhd_ops_pri) #endif - { - if (ifp->net) { + { unregister_netdev(ifp->net); free_netdev(ifp->net); ifp->net = NULL; + MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); + dhd->iflist[0] = NULL; } - MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); - dhd->iflist[0] = NULL; - } } @@ -3722,12 +4505,6 @@ void dhd_detach(dhd_pub_t *dhdp) #endif /* DHDTHREAD */ tasklet_kill(&dhd->tasklet); } - if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { - dhd_bus_detach(dhdp); - - if (dhdp->prot) - dhd_prot_detach(dhdp); - } #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { @@ -3744,9 +4521,16 @@ void dhd_detach(dhd_pub_t *dhdp) if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { #ifdef CONFIG_HAS_WAKELOCK + dhd->wakelock_counter = 0; + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; wake_lock_destroy(&dhd->wl_wifi); wake_lock_destroy(&dhd->wl_rxwake); + wake_lock_destroy(&dhd->wl_ctrlwake); +#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) + wake_lock_destroy(&dhdp->pno_wakelock); #endif +#endif /* CONFIG_HAS_WAKELOCK */ } } @@ -3833,8 +4617,10 @@ dhd_module_init(void) dhd_bus_reg_sdio_notify(&dhd_chipup_sem); dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); #if defined(CONFIG_WIFI_CONTROL_FUNC) - if (wl_android_wifictrl_func_add() < 0) + if (wl_android_wifictrl_func_add() < 0) { + dhd_bus_unreg_sdio_notify(); goto fail_1; + } #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { @@ -3884,9 +4670,11 @@ dhd_module_init(void) * It's needed to make sync up exit from dhd insmod and * Kernel MMC sdio device callback registration */ - if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) { + if ((down_timeout(&dhd_registration_sem, + msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) || + (dhd_registration_check != TRUE)) { error = -ENODEV; - DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__)); + DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__)); goto fail_2; } #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ @@ -3966,36 +4754,16 @@ int dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) { dhd_info_t * dhd = (dhd_info_t *)(pub->info); - DECLARE_WAITQUEUE(wait, current); - int timeout = dhd_ioctl_timeout_msec; + int timeout; /* Convert timeout in millsecond to jiffies */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(timeout); + timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = timeout * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * HZ / 1000; #endif - /* Wait until control frame is available */ - add_wait_queue(&dhd->ioctl_resp_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - /* Memory barrier to support multi-processing - * As the variable "condition", which points to dhd->rxlen (dhd_bus_rxctl[dhd_sdio.c]) - * Can be changed by another processor. - */ - smp_mb(); - while (!(*condition) && (!signal_pending(current) && timeout)) { - timeout = schedule_timeout(timeout); - smp_mb(); - } - - if (signal_pending(current)) - *pending = TRUE; - - set_current_state(TASK_RUNNING); - remove_wait_queue(&dhd->ioctl_resp_wait, &wait); - + timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); return timeout; } @@ -4005,7 +4773,7 @@ dhd_os_ioctl_resp_wake(dhd_pub_t *pub) dhd_info_t *dhd = (dhd_info_t *)(pub->info); if (waitqueue_active(&dhd->ioctl_resp_wait)) { - wake_up_interruptible(&dhd->ioctl_resp_wait); + wake_up(&dhd->ioctl_resp_wait); } return 0; @@ -4020,6 +4788,9 @@ dhd_os_wd_timer(void *bus, uint wdtick) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (!dhd) + return; + flags = dhd_os_spin_lock(pub); /* don't start the wd until fw is loaded */ @@ -4028,7 +4799,7 @@ dhd_os_wd_timer(void *bus, uint wdtick) return; } - /* Totally stop the timer */ + /* totally stop the timer */ if (!wdtick && dhd->wd_timer_valid == TRUE) { dhd->wd_timer_valid = FALSE; dhd_os_spin_unlock(pub, flags); @@ -4043,7 +4814,7 @@ dhd_os_wd_timer(void *bus, uint wdtick) if (wdtick) { dhd_watchdog_ms = (uint)wdtick; /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); dhd->wd_timer_valid = TRUE; } dhd_os_spin_unlock(pub, flags); @@ -4356,10 +5127,17 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) { #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) struct dhd_info *dhdinfo = dhd->info; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + int timeout = msecs_to_jiffies(2000); +#else + int timeout = 2 * HZ; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + dhd_os_sdunlock(dhd); - wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2); + wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); dhd_os_sdlock(dhd); -#endif +#endif return; } @@ -4368,7 +5146,7 @@ void dhd_wait_event_wakeup(dhd_pub_t *dhd) #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) struct dhd_info *dhdinfo = dhd->info; if (waitqueue_active(&dhdinfo->ctrl_wait)) - wake_up_interruptible(&dhdinfo->ctrl_wait); + wake_up(&dhdinfo->ctrl_wait); #endif return; } @@ -4380,6 +5158,13 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + if (flag == TRUE) { + /* Issue wl down command before resetting the chip */ + if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { + DHD_TRACE(("%s: wl down failed\n", __FUNCTION__)); + } + } + ret = dhd_bus_devreset(&dhd->pub, flag); if (ret) { DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); @@ -4401,16 +5186,21 @@ int net_os_set_suspend_disable(struct net_device *dev, int val) return ret; } -int net_os_set_suspend(struct net_device *dev, int val) +int net_os_set_suspend(struct net_device *dev, int val, int force) { int ret = 0; -#if defined(CONFIG_HAS_EARLYSUSPEND) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); if (dhd) { +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ret = dhd_set_suspend(val, &dhd->pub); +#else + ret = dhd_suspend_resume_helper(dhd, val, force); +#endif +#ifdef WL_CFG80211 + wl_cfg80211_update_power_mode(dev); +#endif } -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ return ret; } @@ -4424,13 +5214,16 @@ int net_os_set_dtim_skip(struct net_device *dev, int val) return 0; } +#ifdef PKT_FILTER_SUPPORT int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) { +#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); char *filterp = NULL; int ret = 0; - if (!dhd || (num == DHD_UNICAST_FILTER_NUM)) + if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || + (num == DHD_MDNS_FILTER_NUM)) return ret; if (num >= dhd->pub.pktfilter_count) return -EINVAL; @@ -4443,6 +5236,10 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) filterp = "102 0 0 0 0xFFFFFF 0x01005E"; break; case DHD_MULTICAST6_FILTER_NUM: +#if defined(BLOCK_IPV6_PACKET) +/* customer want to use NO IPV6 packets only */ + return ret; +#endif filterp = "103 0 0 0 0xFFFF 0x3333"; break; default: @@ -4450,10 +5247,14 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) } } dhd->pub.pktfilter[num] = filterp; + dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); return ret; +#else + return 0; +#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ } -int net_os_set_packet_filter(struct net_device *dev, int val) +int net_os_enable_packet_filter(struct net_device *dev, int val) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ret = 0; @@ -4465,20 +5266,25 @@ int net_os_set_packet_filter(struct net_device *dev, int val) */ if (dhd && dhd->pub.up) { if (dhd->pub.in_suspend) { - if (!val || (val && !dhd->pub.suspend_disable_flag)) - dhd_set_packet_filter(val, &dhd->pub); + if (!val || (val && !dhd->pub.suspend_disable_flag)) { + dhd_enable_packet_filter(val, &dhd->pub); + } } } return ret; } +#endif /* PKT_FILTER_SUPPORT */ - -void +int dhd_dev_init_ioctl(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - dhd_preinit_ioctls(&dhd->pub); +#if defined(USE_STAMAC_4SOFTAP) + /* Writing STA's MAC ID to the Dongle for SOFTAP */ + if (_dhd_set_mac_address(dhd, 0, &dhd->pub.mac) == 0) + DHD_INFO(("dhd_bus_start: MAC ID is overwritten\n")); +#endif + return dhd_preinit_ioctls(&dhd->pub); } #ifdef PNO_SUPPORT @@ -4523,34 +5329,75 @@ dhd_dev_get_pno_status(struct net_device *dev) #endif /* PNO_SUPPORT */ -int net_os_send_hang_message(struct net_device *dev) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) +static void dhd_hang_process(struct work_struct *work) { - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; + dhd_info_t *dhd; + struct net_device *dev; - if (dhd) { - if (!dhd->pub.hang_was_sent) { - dhd->pub.hang_was_sent = 1; -#if defined(CONFIG_WIRELESS_EXT) - ret = wl_iw_send_priv_event(dev, "HANG"); + dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang); + dev = dhd->iflist[0]->net; + + if (dev) { + rtnl_lock(); + dev_close(dev); + rtnl_unlock(); +#if defined(WL_WIRELESS_EXT) + wl_iw_send_priv_event(dev, "HANG"); #endif #if defined(WL_CFG80211) - ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); - dev_close(dev); - dev_open(dev); + wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); #endif + } +} + +int dhd_os_send_hang_message(dhd_pub_t *dhdp) +{ + int ret = 0; + if (dhdp) { + if (!dhdp->hang_was_sent) { + dhdp->hang_was_sent = 1; + schedule_work(&dhdp->info->work_hang); } } return ret; } -void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) +int net_os_send_hang_message(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; - if (dhd && dhd->pub.up) - memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); + if (dhd) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + ret = dhd_os_send_hang_message(&dhd->pub); +#else + ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); +#endif + return ret; } +#endif /* (OEM_ANDROID) */ + +void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + if (dhd && dhd->pub.up) { + memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); +#ifdef WL_CFG80211 + wl_update_wiphybands(NULL); +#endif + } +} +void dhd_bus_band_set(struct net_device *dev, uint band) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + if (dhd && dhd->pub.up) { +#ifdef WL_CFG80211 + wl_update_wiphybands(NULL); +#endif + } +} + void dhd_net_if_lock(struct net_device *dev) { @@ -4580,6 +5427,24 @@ static void dhd_net_if_unlock_local(dhd_info_t *dhd) #endif } +static void dhd_suspend_lock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_lock(&dhd->dhd_suspend_mutex); +#endif +} + +static void dhd_suspend_unlock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_unlock(&dhd->dhd_suspend_mutex); +#endif +} + unsigned long dhd_os_spin_lock(dhd_pub_t *pub) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); @@ -4605,13 +5470,13 @@ dhd_get_pend_8021x_cnt(dhd_info_t *dhd) return (atomic_read(&dhd->pend_8021x_cnt)); } -#define MAX_WAIT_FOR_8021X_TX 10 +#define MAX_WAIT_FOR_8021X_TX 25 int dhd_wait_pend8021x(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int timeout = 10 * HZ / 1000; + int timeout = msecs_to_jiffies(10); int ntimes = MAX_WAIT_FOR_8021X_TX; int pend = dhd_get_pend_8021x_cnt(dhd); @@ -4624,6 +5489,8 @@ dhd_wait_pend8021x(struct net_device *dev) } pend = dhd_get_pend_8021x_cnt(dhd); } + if (ntimes == 0) + DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__)); return pend; } @@ -4672,13 +5539,18 @@ int dhd_os_wake_lock_timeout(dhd_pub_t *pub) if (dhd) { spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - ret = dhd->wakelock_timeout_enable; + ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? + dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; #ifdef CONFIG_HAS_WAKELOCK - if (dhd->wakelock_timeout_enable) + if (dhd->wakelock_rx_timeout_enable) wake_lock_timeout(&dhd->wl_rxwake, - msecs_to_jiffies(dhd->wakelock_timeout_enable)); + msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); + if (dhd->wakelock_ctrl_timeout_enable) + wake_lock_timeout(&dhd->wl_ctrlwake, + msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); #endif - dhd->wakelock_timeout_enable = 0; + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); } return ret; @@ -4694,27 +5566,67 @@ int net_os_wake_lock_timeout(struct net_device *dev) return ret; } -int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val) +#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) +int net_os_wake_lock_timeout_for_pno(struct net_device *dev, int sec) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + wake_lock_timeout(&dhd->pub.pno_wakelock, HZ * sec); + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} +#endif + +int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (val > dhd->wakelock_rx_timeout_enable) + dhd->wakelock_rx_timeout_enable = val; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return 0; +} + +int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); unsigned long flags; if (dhd) { spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_timeout_enable) - dhd->wakelock_timeout_enable = val; + if (val > dhd->wakelock_ctrl_timeout_enable) + dhd->wakelock_ctrl_timeout_enable = val; spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); } return 0; } -int net_os_wake_lock_timeout_enable(struct net_device *dev, int val) +int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); + return ret; +} + +int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ret = 0; if (dhd) - ret = dhd_os_wake_lock_timeout_enable(&dhd->pub, val); + ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); return ret; } @@ -4729,7 +5641,10 @@ int dhd_os_wake_lock(dhd_pub_t *pub) #ifdef CONFIG_HAS_WAKELOCK if (!dhd->wakelock_counter) wake_lock(&dhd->wl_wifi); -#endif +#elif defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) + /* SLP_wakelock_alternative_code */ + pm_stay_awake(pm_dev); +#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ dhd->wakelock_counter++; ret = dhd->wakelock_counter; spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); @@ -4761,7 +5676,10 @@ int dhd_os_wake_unlock(dhd_pub_t *pub) #ifdef CONFIG_HAS_WAKELOCK if (!dhd->wakelock_counter) wake_unlock(&dhd->wl_wifi); -#endif +#elif defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) + /* SLP_wakelock_alternative_code */ + pm_relax(pm_dev); +#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ ret = dhd->wakelock_counter; } spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); @@ -4781,7 +5699,20 @@ int dhd_os_check_wakelock(void *dhdp) if (dhd && wake_lock_active(&dhd->wl_wifi)) return 1; -#endif +#elif defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) + /* SLP_wakelock_alternative_code */ + dhd_pub_t *pub = (dhd_pub_t *)dhdp; + dhd_info_t *dhd; + + if (!pub) + return 0; + dhd = (dhd_info_t *)(pub->info); + + DHD_ERROR(("%s : wakelock_count = %d\n", __func__, dhd->wakelock_counter)); + + if (dhd && (dhd->wakelock_counter > 0)) + return 1; +#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ return 0; } int net_os_wake_unlock(struct net_device *dev) @@ -4802,6 +5733,23 @@ int dhd_os_check_if_up(void *dhdp) return 0; return pub->up; } + +/* function to collect firmware, chip id and chip version info */ +void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) +{ + int i; + + i = snprintf(info_string, sizeof(info_string), + " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); + + if (!dhdp) + return; + + i = snprintf(&info_string[i], sizeof(info_string) - i, + "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), + dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); +} + int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) { int ifidx; @@ -4836,6 +5784,78 @@ bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) return dhd_check_hang(net, dhdp, ret); } +#if defined(WL_CFG80211) && defined(SUPPORT_DEEP_SLEEP) +#define MAX_TRY_CNT 5 /* Number of tries to disable deepsleep */ +int dhd_deepsleep(struct net_device *dev, int flag) +{ + char iovbuf[20]; + uint powervar = 0; + dhd_info_t *dhd; + dhd_pub_t *dhdp; + int cnt = 0; + int ret = 0; + + dhd = *(dhd_info_t **)netdev_priv(dev); + dhdp = &dhd->pub; + + switch (flag) { + case 1 : /* Deepsleep on */ + DHD_ERROR(("[WiFi] Deepsleep On\n")); + /* give some time to _dhd_sysioc_thread() before deepsleep */ + msleep(200); +#ifdef PKT_FILTER_SUPPORT + /* disable pkt filter */ + dhd_enable_packet_filter(0, dhdp); +#endif /* PKT_FILTER_SUPPORT */ + /* Disable MPC */ + powervar = 0; + memset(iovbuf, 0, sizeof(iovbuf)); + bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + /* Enable Deepsleep */ + powervar = 1; + memset(iovbuf, 0, sizeof(iovbuf)); + bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + break; + + case 0: /* Deepsleep Off */ + DHD_ERROR(("[WiFi] Deepsleep Off\n")); + + /* Disable Deepsleep */ + for (cnt = 0; cnt < MAX_TRY_CNT; cnt++) { + powervar = 0; + memset(iovbuf, 0, sizeof(iovbuf)); + bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + memset(iovbuf, 0, sizeof(iovbuf)); + bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), + FALSE, 0)) < 0) { + DHD_ERROR(("the error of dhd deepsleep status ret value :%d\n", + ret)); + } else { + if (!(*(int *)iovbuf)) { + DHD_ERROR(("deepsleep mode is 0, ok , count : %d\n", cnt)); + break; + } + } + } + + /* Enable MPC */ + powervar = 1; + memset(iovbuf, 0, sizeof(iovbuf)); + bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + break; + } + + return 0; +} +#endif /* SUPPORT_DEEP_SLEEP */ + #ifdef PROP_TXSTATUS extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea); @@ -4844,23 +5864,34 @@ extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); int dhd_wlfc_interface_event(struct dhd_info *dhd, ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) { - if (dhd->pub.wlfc_state == NULL) - return BCME_OK; + int ret = BCME_OK; - return dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); + dhd_os_wlfc_block(&dhd->pub); + if (dhd->pub.wlfc_state != NULL) + ret = dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); + dhd_os_wlfc_unblock(&dhd->pub); + return ret; } int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data) { - if (dhd->pub.wlfc_state == NULL) - return BCME_OK; + int ret = BCME_OK; - return dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); + dhd_os_wlfc_block(&dhd->pub); + if (dhd->pub.wlfc_state != NULL) + ret = dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); + dhd_os_wlfc_unblock(&dhd->pub); + return ret; } int dhd_wlfc_event(struct dhd_info *dhd) { - return dhd_wlfc_enable(&dhd->pub); + int ret; + + dhd_os_wlfc_block(&dhd->pub); + ret = dhd_wlfc_enable(&dhd->pub); + dhd_os_wlfc_unblock(&dhd->pub); + return ret; } #endif /* PROP_TXSTATUS */ @@ -5224,7 +6255,8 @@ dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) ioc.len = (uint)sizeof(buf); ioc.set = FALSE; - strcpy(buf, "tsf"); + strncpy(buf, "tsf", sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; s1 = dhd_get_htsf(dhd, 0); if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { if (ret == -EIO) { diff --git a/drivers/net/wireless/bcmdhd/dhd_proto.h b/drivers/net/wireless/bcmdhd/dhd_proto.h index e420166a95a..09d546809db 100644 --- a/drivers/net/wireless/bcmdhd/dhd_proto.h +++ b/drivers/net/wireless/bcmdhd/dhd_proto.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_proto.h 303834 2011-12-20 06:17:39Z $ + * $Id: dhd_proto.h 343390 2012-07-06 22:34:19Z $ */ #ifndef _dhd_proto_h_ @@ -34,7 +34,7 @@ #include #ifndef IOCTL_RESP_TIMEOUT -#define IOCTL_RESP_TIMEOUT 20000 /* In milli second */ +#define IOCTL_RESP_TIMEOUT 2000 /* In milli second default value for Production FW */ #endif /* IOCTL_RESP_TIMEOUT */ /* @@ -54,6 +54,10 @@ extern int dhd_prot_init(dhd_pub_t *dhdp); /* Stop protocol: sync w/dongle state. */ extern void dhd_prot_stop(dhd_pub_t *dhdp); +#ifdef PROP_TXSTATUS +extern int dhd_wlfc_init(dhd_pub_t *dhd); +extern void dhd_wlfc_deinit(dhd_pub_t *dhd); +#endif /* PROP_TXSTATUS */ /* Add any protocol-specific data header. * Caller must reserve prot_hdrlen prepend space. diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 0ec95d265f3..422ad034f5e 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 329638 2012-04-26 05:41:43Z $ + * $Id: dhd_sdio.c 357859 2012-09-20 06:34:26Z $ */ #include @@ -49,6 +49,9 @@ #include #include +#ifdef BCMSPI +#include +#endif /* BCMSPI */ #include #include #include @@ -94,8 +97,17 @@ #error DHD_FIRSTREAD is not a power of 2! #endif -/* Total length of frame header for dongle protocol */ +#ifdef BCMSDIOH_TXGLOM +/* Total length of TX frame header for dongle protocol */ +#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + SDPCM_SWHEADER_LEN) +/* Total length of RX frame for dongle protocol */ +#else +/* Total length of TX frame header for dongle protocol */ #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) +#endif + +#define SDPCM_HDRLEN_RX (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) + #ifdef SDTEST #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) #else @@ -138,12 +150,15 @@ #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ PKTFREE(bus->dhd->osh, pkt, FALSE); DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) extern void bcmsdh_set_irq(int flag); -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ #ifdef PROP_TXSTATUS extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) +DEFINE_MUTEX(_dhd_sdio_mutex_lock_); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ #ifdef DHD_DEBUG /* Device console log buffer state */ @@ -168,6 +183,8 @@ typedef struct dhd_console { #define MIN_RSRC_SR 0x3 #define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) +#define RCTL_MACPHY_DISABLE_MASK (1 << 26) +#define RCTL_LOGIC_DISABLE_MASK (1 << 27) #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ @@ -175,7 +192,7 @@ typedef struct dhd_console { #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) - +#define CC_PMUCC3 (0x3) /* Private data for SDIO bus interaction */ typedef struct dhd_bus { dhd_pub_t *dhd; @@ -314,11 +331,16 @@ typedef struct dhd_bus { uint f2rxdata; /* Number of frame data reads */ uint f2txdata; /* Number of f2 frame writes */ uint f1regdata; /* Number of f1 register accesses */ +#ifdef BCMSPI + bool dwordmode; +#endif /* BCMSPI */ uint8 *ctrl_frame_buf; uint32 ctrl_frame_len; bool ctrl_frame_stat; +#ifndef BCMSPI uint32 rxint_mode; /* rx interrupt mode */ +#endif /* BCMSPI */ bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram * Available with socram rev 16 * Remap region not DMA-able @@ -329,6 +351,16 @@ typedef struct dhd_bus { bool _srenab; bool readframes; bool reqbussleep; + uint32 resetinstr; + uint32 dongle_ram_base; +#ifdef BCMSDIOH_TXGLOM + void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */ + uint16 glom_cnt; /* Number of pkts in the glom array */ + uint16 glom_total_len; /* Total length of pkts in glom array */ + bool glom_enable; /* Flag to indicate whether tx glom is enabled/disabled */ + uint8 glom_mode; /* Glom mode - 0-copy mode, 1 - Multi-descriptor mode */ + uint32 glomsize; /* Glom size limitation */ +#endif } dhd_bus_t; /* clkstate */ @@ -367,8 +399,13 @@ static bool sd1idle; static bool retrydata; #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) +#if defined(SDIO_CRC_ERROR_FIX) +static uint watermark = 48; +static uint mesbusyctrl = 80; +#else static const uint watermark = 8; static const uint mesbusyctrl = 0; +#endif static const uint firstread = DHD_FIRSTREAD; #define HDATLEN (firstread - (SDPCM_HDRLEN)) @@ -379,9 +416,6 @@ static const uint retry_limit = 2; /* Force even SD lengths (some host controllers mess up on odd bytes) */ static bool forcealign; -/* Flag to indicate if we should download firmware on driver load */ -uint dhd_download_fw_on_driverload = TRUE; - #define ALIGNMENT 4 #if defined(OOB_INTR_ONLY) && defined(HW_OOB) @@ -420,6 +454,10 @@ static bool dhd_readahead; (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) +/* Number of pkts available in dongle for data RX */ +#define DATABUFCNT(bus) \ + ((uint8)(bus->tx_max - bus->tx_seq) - 1) + /* Macros to get register read/write status */ /* NOTE: these assume a local dhdsdio_bus_t *bus! */ #define R_SDREG(regvar, regaddr, retryvar) \ @@ -454,6 +492,7 @@ do { \ #define BUS_WAKE(bus) \ do { \ + bus->idlecount = 0; \ if ((bus)->sleeping) \ dhdsdio_bussleep((bus), FALSE); \ } while (0); @@ -479,6 +518,33 @@ do { \ #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ +#ifdef BCMSPI + +#define FRAME_AVAIL_MASK(bus) I_HMB_FRAME_IND + +#define DHD_BUS SPI_BUS + +/* check packet-available-interrupt in piggybacked dstatus */ +#define PKT_AVAILABLE(bus, intstatus) (bcmsdh_get_dstatus(bus->sdh) & STATUS_F2_PKT_AVAILABLE) + +#define HOSTINTMASK (I_HMB_FC_CHANGE | I_HMB_HOST_INT) + +#define GSPI_PR55150_BAILOUT \ +do { \ + uint32 dstatussw = bcmsdh_get_dstatus((void *)bus->sdh); \ + uint32 dstatushw = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, SPID_STATUS_REG, NULL); \ + uint32 intstatuserr = 0; \ + uint retries = 0; \ + \ + R_SDREG(intstatuserr, &bus->regs->intstatus, retries); \ + printf("dstatussw = 0x%x, dstatushw = 0x%x, intstatus = 0x%x\n", \ + dstatussw, dstatushw, intstatuserr); \ + \ + bus->nextlen = 0; \ + *finished = TRUE; \ +} while (0) + +#else /* BCMSDIO */ #define FRAME_AVAIL_MASK(bus) \ ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) @@ -491,6 +557,8 @@ do { \ #define GSPI_PR55150_BAILOUT +#endif /* BCMSPI */ + #ifdef SDTEST static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count); @@ -522,6 +590,10 @@ static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); +#ifdef BCMSDIOH_TXGLOM +static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len); +static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus); +#endif static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); static int _dhdsdio_download_firmware(dhd_bus_t *bus); @@ -567,6 +639,28 @@ dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) return err; } +#ifdef BCMSPI +static void +dhdsdio_wkwlan(dhd_bus_t *bus, bool on) +{ + int err; + uint32 regdata; + bcmsdh_info_t *sdh = bus->sdh; + + if (bus->sih->buscoretype == SDIOD_CORE_ID) { + /* wake up wlan function :WAKE_UP goes as ht_avail_request and alp_avail_request */ + regdata = bcmsdh_cfg_read_word(sdh, SDIO_FUNC_0, SPID_CONFIG, NULL); + DHD_INFO(("F0 REG0 rd = 0x%x\n", regdata)); + + if (on == TRUE) + regdata |= WAKE_UP; + else + regdata &= ~WAKE_UP; + + bcmsdh_cfg_write_word(sdh, SDIO_FUNC_0, SPID_CONFIG, regdata, &err); + } +} +#endif /* BCMSPI */ #ifdef USE_OOB_GPIO1 static int @@ -591,6 +685,7 @@ dhdsdio_oobwakeup_init(dhd_bus_t *bus) } #endif /* USE_OOB_GPIO1 */ +#ifndef BCMSPI /* * Query if FW is in SR mode */ @@ -604,6 +699,10 @@ dhdsdio_sr_cap(dhd_bus_t *bus) data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); bcmsdh_reg_write(bus->sdh, addr, 4, 3); core_capext = bcmsdh_reg_read(bus->sdh, data, 4); + } else if (bus->sih->chip == BCM4330_CHIP_ID) { + core_capext = FALSE; + } else if (bus->sih->chip == BCM4335_CHIP_ID) { + core_capext = TRUE; } else { core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK); @@ -611,16 +710,25 @@ dhdsdio_sr_cap(dhd_bus_t *bus) if (!(core_capext)) return FALSE; - min = bcmsdh_reg_read(bus->sdh, MIN_RSRC_ADDR, 4); - if (min == MIN_RSRC_SR) { - cap = TRUE; - - if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev < 3)) { - cap = FALSE; - - DHD_ERROR(("Only 4334 >= B2 supports SR: curr rev %d\n", - bus->sih->chiprev)); - } + if (bus->sih->chip == BCM4324_CHIP_ID) { + /* FIX: Should change to query SR control register instead */ + min = bcmsdh_reg_read(bus->sdh, MIN_RSRC_ADDR, 4); + if (min == MIN_RSRC_SR) + cap = TRUE; + } else if (bus->sih->chip == BCM4335_CHIP_ID) { + uint32 enabval = 0; + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); + enabval = bcmsdh_reg_read(bus->sdh, data, 4); + + if (enabval) + cap = TRUE; + } else { + data = bcmsdh_reg_read(bus->sdh, + SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4); + if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) + cap = TRUE; } return cap; @@ -668,6 +776,7 @@ dhdsdio_sr_init(dhd_bus_t *bus) return 0; } +#endif /* BCMSPI */ /* * FIX: Be sure KSO bit is enabled @@ -697,18 +806,55 @@ dhdsdio_clk_kso_init(dhd_bus_t *bus) return 0; } +#define KSO_DBG(x) +#define MAX_KSO_ATTEMPTS 64 static int dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) { - uint8 val = 0; + uint8 wr_val = 0, rd_val, cmp_val, bmask; int err = 0; + int try_cnt = 0; - /* Don't read here since sdio could be off so just write only */ - val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); + KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); - if (err) - DHD_TRACE(("%s: KSO toggle %d failed: %d\n", __FUNCTION__, on, err)); + wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); + + if (on) { + cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; + bmask = cmp_val; + + msleep(3); + + } else { + /* Put device to sleep, turn off KSO */ + cmp_val = 0; + bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; + } + + do { + rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); + if (((rd_val & bmask) == cmp_val) && !err) + break; + + KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); + OSL_DELAY(50); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); + + } while (try_cnt++ < MAX_KSO_ATTEMPTS); + + + if (try_cnt > 1) { + KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", + __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); + } + + if (try_cnt > MAX_KSO_ATTEMPTS) { + DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", + __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); + } return err; } @@ -877,7 +1023,8 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) do { err = dhdsdio_clk_kso_enab(bus, TRUE); - OSL_DELAY(10000); + if (err) + OSL_DELAY(10000); } while ((err != 0) && (++retry < 3)); if (err != 0) { @@ -892,7 +1039,7 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) /* Wait for device ready during transition to wake-up */ SPINWAIT((((csr = dhdsdio_sleepcsr_get(bus)) & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != - (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (10000)); + (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr)); @@ -923,15 +1070,17 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) static int dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) { +#define HT_AVAIL_ERROR_MAX 10 + static int ht_avail_error = 0; int err; uint8 clkctl, clkreq, devctl; bcmsdh_info_t *sdh; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) pendok = FALSE; -#endif +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ clkctl = 0; sdh = bus->sdh; @@ -948,12 +1097,26 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) /* Request HT Avail */ clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; +#ifdef BCMSPI + dhdsdio_wkwlan(bus, TRUE); +#endif /* BCMSPI */ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); if (err) { - DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); + ht_avail_error++; + if (ht_avail_error < HT_AVAIL_ERROR_MAX) { + DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + else if (ht_avail_error == HT_AVAIL_ERROR_MAX) { + dhd_os_send_hang_message(bus->dhd); + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ return BCME_ERROR; + } else { + ht_avail_error = 0; } if (pendok && @@ -1028,6 +1191,9 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) #endif /* defined (DHD_DEBUG) */ bus->activity = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ } else { clkreq = 0; if (bus->clkstate == CLK_PENDING) { @@ -1047,6 +1213,9 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) return BCME_ERROR; } } +#ifdef BCMSPI + dhdsdio_wkwlan(bus, FALSE); +#endif /* BCMSPI */ } return BCME_OK; } @@ -1055,6 +1224,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) static int dhdsdio_sdclk(dhd_bus_t *bus, bool on) { +#ifndef BCMSPI int err; int32 iovalue; @@ -1133,6 +1303,7 @@ dhdsdio_sdclk(dhd_bus_t *bus, bool on) } bus->clkstate = CLK_NONE; } +#endif /* BCMSPI */ return BCME_OK; } @@ -1153,6 +1324,9 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) if (target == CLK_AVAIL) { dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); bus->activity = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ } return ret; } @@ -1167,6 +1341,9 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) if (ret == BCME_OK) { dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); bus->activity = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ } break; @@ -1223,7 +1400,11 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) /* Going to sleep: set the alarm and turn off the lights... */ if (sleep) { /* Don't sleep if something is pending */ +#ifdef CUSTOMER_HW4 + if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes) +#else if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) +#endif /* CUSTOMER_HW4 */ return BCME_BUSY; @@ -1303,6 +1484,42 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) return err; } +#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) +int +dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size) +{ + int func_blk_size = function_num; + int bcmerr = 0; + int result; + + bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size, sizeof(int), &result, + sizeof(int), 0); + + if (bcmerr != BCME_OK) { + DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num)); + return BCME_ERROR; + } + + if (result != block_size) { + + DHD_ERROR(("%s: F%d Block size set from %d to %d\n", __FUNCTION__, + function_num, result, block_size)); + + func_blk_size = function_num << 16 | block_size; + bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size, sizeof(int32), + &result, sizeof(int32), 1); + + if (bcmerr != BCME_OK) { + DHD_ERROR(("%s: Set F2 Block size error\n", __FUNCTION__)); + return BCME_ERROR; + } + } + + return BCME_OK; + +} +#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ + #if defined(OOB_INTR_ONLY) void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) @@ -1337,7 +1554,7 @@ dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) /* Writes a HW/SW header into the packet and sends it. */ /* Assumes: (a) header space already there, (b) caller holds lock */ static int -dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) +dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only) { int ret; osl_t *osh; @@ -1348,6 +1565,10 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) bcmsdh_info_t *sdh; void *new; int i; + int pkt_cnt; +#ifdef BCMSDIOH_TXGLOM + uint8 *frame_tmp; +#endif #ifdef WLMEDIA_HTSF char *p; htsfts_t *htsf_ts; @@ -1378,7 +1599,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) #endif /* WLMEDIA_HTSF */ /* Add alignment padding, allocate new packet if needed */ - if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) { + if (!((uintptr)frame & 1) && (pad1 = ((uintptr)frame % DHD_SDALIGN))) { if (PKTHEADROOM(osh, pkt) < pad1) { DHD_INFO(("%s: insufficient headroom %d for %d pad1\n", __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1)); @@ -1416,6 +1637,77 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) *(uint16*)frame = htol16(len); *(((uint16*)frame) + 1) = htol16(~len); +#ifdef BCMSDIOH_TXGLOM + if (bus->glom_enable) { + uint32 hwheader1 = 0, hwheader2 = 0, act_len = len; + + /* Software tag: channel, sequence number, data offset */ + swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | + ((bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP) | + (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); + htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); + htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader)); + + if (queue_only) { + if (forcealign && (len & (ALIGNMENT - 1))) + len = ROUNDUP(len, ALIGNMENT); + /* Hardware extention tag */ + /* 2byte frame length, 1byte-, 1byte frame flag, + * 2byte-hdrlength, 2byte padlenght + */ + hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24); + hwheader2 = (len - act_len) << 16; + htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); + htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); + /* Post the frame pointer to sdio glom array */ + dhd_bcmsdh_glom_post(bus, frame, len); + /* Save the pkt pointer in bus glom array */ + bus->glom_pkt_arr[bus->glom_cnt] = pkt; + bus->glom_total_len += len; + bus->glom_cnt++; + return BCME_OK; + } else { + /* Raise len to next SDIO block to eliminate tail command */ + if (bus->roundup && bus->blocksize && + ((bus->glom_total_len + len) > bus->blocksize)) { + uint16 pad2 = bus->blocksize - + ((bus->glom_total_len + len) % bus->blocksize); + if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) { + len += pad2; + } else { + } + } else if ((bus->glom_total_len + len) % DHD_SDALIGN) { + len += DHD_SDALIGN + - ((bus->glom_total_len + len) % DHD_SDALIGN); + } + if (forcealign && (len & (ALIGNMENT - 1))) { + len = ROUNDUP(len, ALIGNMENT); + } + + /* Hardware extention tag */ + /* 2byte frame length, 1byte-, 1byte frame flag, + * 2byte-hdrlength, 2byte padlenght + */ + hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24); + hwheader2 = (len - act_len) << 16; + htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); + htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); + + /* Post the frame pointer to sdio glom array */ + dhd_bcmsdh_glom_post(bus, frame, len); + /* Save the pkt pointer in bus glom array */ + bus->glom_pkt_arr[bus->glom_cnt] = pkt; + bus->glom_cnt++; + bus->glom_total_len += len; + + /* Update the total length on the first pkt */ + frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]); + *(uint16*)frame_tmp = htol16(bus->glom_total_len); + *(((uint16*)frame_tmp) + 1) = htol16(~bus->glom_total_len); + } + } else +#endif /* BCMSDIOH_TXGLOM */ + { /* Software tag: channel, sequence number, data offset */ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); @@ -1435,6 +1727,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) } #endif +#ifndef BCMSPI /* Raise len to next SDIO block to eliminate tail command */ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { uint16 pad2 = bus->blocksize - (len % bus->blocksize); @@ -1446,6 +1739,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) } else if (len % DHD_SDALIGN) { len += DHD_SDALIGN - (len % DHD_SDALIGN); } +#endif /* BCMSPI */ /* Some controllers have trouble with odd bytes -- round to even */ if (forcealign && (len & (ALIGNMENT - 1))) { @@ -1458,6 +1752,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len)); #endif } + } do { ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, @@ -1469,11 +1764,15 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); } else if (ret < 0) { /* On failure, abort the command and terminate the frame */ - DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", + DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n", __FUNCTION__, ret)); bus->tx_sderrs++; bcmsdh_abort(sdh, SDIO_FUNC_2); +#ifdef BCMSPI + DHD_ERROR(("%s: gSPI transmit error. Check Overflow or F2-fifo-not-ready" + " counters.\n", __FUNCTION__)); +#endif /* BCMSPI */ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL); bus->f1regdata++; @@ -1490,13 +1789,43 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) } } if (ret == 0) { +#ifdef BCMSDIOH_TXGLOM + if (bus->glom_enable) { + bus->tx_seq = (bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP; + } else +#endif + { bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; } + } } while ((ret < 0) && retrydata && retries++ < TXRETRIES); done: + +#ifdef BCMSDIOH_TXGLOM + if (bus->glom_enable) { + dhd_bcmsdh_glom_clear(bus); + pkt_cnt = bus->glom_cnt; + } else +#endif + { + pkt_cnt = 1; + } /* restore pkt buffer pointer before calling tx complete routine */ + while (pkt_cnt) { +#ifdef BCMSDIOH_TXGLOM + uint32 doff; + if (bus->glom_enable) { + pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt]; + frame = (uint8*)PKTDATA(osh, pkt); + doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); + doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; + PKTPULL(osh, pkt, doff); + } else +#endif + { PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); + } #ifdef PROP_TXSTATUS if (bus->dhd->wlfc_state) { dhd_os_sdunlock(bus->dhd); @@ -1510,6 +1839,16 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) #ifdef PROP_TXSTATUS } +#endif + pkt_cnt--; + } + +#ifdef BCMSDIOH_TXGLOM + /* Reset the glom array */ + if (bus->glom_enable) { + bus->glom_cnt = 0; + bus->glom_total_len = 0; + } #endif return ret; } @@ -1520,7 +1859,13 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) int ret = BCME_ERROR; osl_t *osh; uint datalen, prec; - +#ifdef DHD_TX_DUMP + uint8 *dump_data; + uint16 protocol; +#ifdef DHD_TX_FULL_DUMP + int i; +#endif /* DHD_TX_FULL_DUMP */ +#endif /* DHD_TX_DUMP */ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); osh = bus->dhd->osh; @@ -1540,6 +1885,27 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) } #endif /* SDTEST */ +#ifdef DHD_TX_DUMP + dump_data = PKTDATA(osh, pkt); + dump_data += 4; /* skip 4 bytes header */ + protocol = (dump_data[12] << 8) | dump_data[13]; +#ifdef DHD_TX_FULL_DUMP + DHD_ERROR(("TX DUMP\n")); + + for (i = 0; i < (datalen - 4); i++) { + DHD_ERROR(("%02X ", dump_data[i])); + if ((i & 15) == 15) + printk("\n"); + } + DHD_ERROR(("\n")); + +#endif /* DHD_TX_FULL_DUMP */ + if (protocol == ETHER_TYPE_802_1X) { + DHD_ERROR(("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n", + dump_data[14], dump_data[15], dump_data[30])); + } +#endif /* DHD_TX_DUMP */ + /* Add space for the header */ PKTPUSH(osh, pkt, SDPCM_HDRLEN); ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); @@ -1615,10 +1981,10 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) /* Make sure back plane ht clk is on, no pending allowed */ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); #ifndef SDTEST - ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE); + ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE); #else ret = dhdsdio_txpkt(bus, pkt, - (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE); + (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE, FALSE); #endif if (ret) bus->dhd->tx_errors++; @@ -1652,6 +2018,10 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) uint cnt = 0; uint datalen; uint8 tx_prec_map; +#ifdef BCMSDIOH_TXGLOM + uint i; + uint8 glom_cnt; +#endif dhd_pub_t *dhd = bus->dhd; sdpcmd_regs_t *regs = bus->regs; @@ -1667,6 +2037,48 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) /* Send frames until the limit or some other event */ for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) { +#ifdef BCMSDIOH_TXGLOM + if (bus->glom_enable) { + glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize); + glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map)); + glom_cnt = MIN(glom_cnt, maxframes-cnt); + + /* Limiting the size to 2pkts in case of copy */ + if (bus->glom_mode == SDPCM_TXGLOM_CPY) + glom_cnt = MIN(glom_cnt, 5); + + if (glom_cnt == 0) + break; + datalen = 0; + for (i = 0; i < glom_cnt; i++) { + dhd_os_sdlock_txq(bus->dhd); + if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { + /* This case should not happen */ + DHD_ERROR(("No pkts in the queue for glomming\n")); + dhd_os_sdunlock_txq(bus->dhd); + break; + } + dhd_os_sdunlock_txq(bus->dhd); + + datalen += (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN); +#ifndef SDTEST + ret = dhdsdio_txpkt(bus, + pkt, + SDPCM_DATA_CHANNEL, + TRUE, + (i == (glom_cnt-1))? FALSE: TRUE); +#else + ret = dhdsdio_txpkt(bus, + pkt, + (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), + TRUE, + (i == (glom_cnt-1))? FALSE: TRUE); +#endif + } + cnt += i-1; + } else +#endif /* BCMSDIOH_TXGLOM */ + { dhd_os_sdlock_txq(bus->dhd); if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { dhd_os_sdunlock_txq(bus->dhd); @@ -1676,11 +2088,16 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN; #ifndef SDTEST - ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE); + ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE); #else - ret = dhdsdio_txpkt(bus, pkt, - (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE); + ret = dhdsdio_txpkt(bus, + pkt, + (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), + TRUE, + FALSE); #endif + } + if (ret) bus->dhd->tx_errors++; else @@ -1740,6 +2157,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) } doff += SDPCM_HDRLEN; +#ifndef BCMSPI /* Round send length to next SDIO block */ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { uint16 pad = bus->blocksize - (len % bus->blocksize); @@ -1748,6 +2166,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) } else if (len % DHD_SDALIGN) { len += DHD_SDALIGN - (len % DHD_SDALIGN); } +#endif /* BCMSPI */ /* Satisfy length-alignment requirements */ if (forcealign && (len & (ALIGNMENT - 1))) @@ -1768,12 +2187,33 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) *(uint16*)frame = htol16((uint16)msglen); *(((uint16*)frame) + 1) = htol16(~msglen); +#ifdef BCMSDIOH_TXGLOM + if (bus->glom_enable) { + uint32 hwheader1, hwheader2; + /* Software tag: channel, sequence number, data offset */ + swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) + | bus->tx_seq + | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); + htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); + htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + + SDPCM_HWEXT_LEN + sizeof(swheader)); + + hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24); + hwheader2 = (len - (msglen)) << 16; + htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); + htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); + + *(uint16*)frame = htol16(len); + *(((uint16*)frame) + 1) = htol16(~(len)); + } else +#endif /* BCMSDIOH_TXGLOM */ + { /* Software tag: channel, sequence number, data offset */ swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - + } if (!TXCTLOK(bus)) { DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", __FUNCTION__, bus->tx_max, bus->tx_seq)); @@ -1782,7 +2222,13 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) bus->ctrl_frame_buf = frame; bus->ctrl_frame_len = len; - dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); + if (!bus->dpc_sched) { + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + } + if (bus->ctrl_frame_stat) { + dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); + } if (bus->ctrl_frame_stat == FALSE) { DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); @@ -1824,6 +2270,11 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) bcmsdh_abort(sdh, SDIO_FUNC_2); +#ifdef BCMSPI + DHD_ERROR(("%s: Check Overflow or F2-fifo-not-ready counters." + " gSPI transmit error on control channel.\n", + __FUNCTION__)); +#endif /* BCMSPI */ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL); bus->f1regdata++; @@ -1889,17 +2340,24 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", __FUNCTION__, rxlen, msglen)); } else if (timeleft == 0) { +#ifdef DHD_DEBUG + uint32 status, retry = 0; + R_SDREG(status, &bus->regs->intstatus, retry); + DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n", + __FUNCTION__, status)); +#else DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); +#endif /* DHD_DEBUG */ #ifdef DHD_DEBUG - if (!SLPAUTO_ENAB(bus)) { dhd_os_sdlock(bus->dhd); dhdsdio_checkdied(bus, NULL, 0); dhd_os_sdunlock(bus->dhd); - } #endif /* DHD_DEBUG */ } else if (pending == TRUE) { - DHD_CTL(("%s: canceled\n", __FUNCTION__)); - return -ERESTARTSYS; + /* signal pending */ + DHD_ERROR(("%s: signal pending\n", __FUNCTION__)); + return -EINTR; + } else { DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); #ifdef DHD_DEBUG @@ -1923,6 +2381,9 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) return -ETIMEDOUT; + if (bus->dhd->dongle_trap_occured) + return -EREMOTEIO; + return rxlen ? (int)rxlen : -EIO; } @@ -1949,6 +2410,10 @@ enum { IOV_SDALIGN, IOV_DEVRESET, IOV_CPU, +#if defined(SDIO_CRC_ERROR_FIX) + IOV_WATERMARK, + IOV_MESBUSYCTRL, +#endif /* SDIO_CRC_ERROR_FIX */ #ifdef SDTEST IOV_PKTGEN, IOV_EXTLOOP, @@ -1967,8 +2432,10 @@ enum { IOV_DEVCAP, IOV_VARS, #ifdef SOFTAP - IOV_FWPATH + IOV_FWPATH, #endif + IOV_TXGLOMSIZE, + IOV_TXGLOMMODE }; const bcm_iovar_t dhdsdio_iovars[] = { @@ -2007,6 +2474,10 @@ const bcm_iovar_t dhdsdio_iovars[] = { {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, #endif /* SDTEST */ +#if defined(SDIO_CRC_ERROR_FIX) + {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 }, + {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 }, +#endif /* SDIO_CRC_ERROR_FIX */ {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 }, {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, {"kso", IOV_KSO, 0, IOVT_UINT32, 0 }, @@ -2014,6 +2485,8 @@ const bcm_iovar_t dhdsdio_iovars[] = { #ifdef SOFTAP {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, #endif + {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 }, + {"txglommode", IOV_TXGLOMMODE, 0, IOVT_UINT32, 0 }, {NULL, 0, 0, 0, 0 } }; @@ -2265,8 +2738,7 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) int rv, i; uint32 shaddr = 0; - shaddr = bus->ramsize - 4; - + shaddr = bus->dongle_ram_base + bus->ramsize - 4; i = 0; do { /* Read last word in memory to determine address of sdpcm_shared structure */ @@ -2486,6 +2958,7 @@ dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) } if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { + bus->dhd->dongle_trap_occured = TRUE; if ((bcmerror = dhdsdio_membytes(bus, FALSE, sdpcm_shared.trap_addr, (uint8*)&tr, sizeof(trap_t))) < 0) @@ -2639,7 +3112,8 @@ dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) if (bus->sih->chip == BCM4330_CHIP_ID) { uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; } - else if (bus->sih->chip == BCM4334_CHIP_ID) { + else if (bus->sih->chip == BCM4334_CHIP_ID || + bus->sih->chip == BCM43341_CHIP_ID) { if (enable) { /* Moved to PMU chipcontrol 1 from 4330 */ int_val &= ~gpio_sel; @@ -2935,6 +3409,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch else bus->use_rxchain = bool_val; break; +#ifndef BCMSPI case IOV_GVAL(IOV_ALIGNCTL): int_val = (int32)dhd_alignctl; bcopy(&int_val, arg, val_size); @@ -2943,6 +3418,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch case IOV_SVAL(IOV_ALIGNCTL): dhd_alignctl = bool_val; break; +#endif /* BCMSPI */ case IOV_GVAL(IOV_SDALIGN): int_val = DHD_SDALIGN; @@ -3107,6 +3583,33 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch break; #endif /* SDTEST */ +#if defined(SDIO_CRC_ERROR_FIX) + case IOV_GVAL(IOV_WATERMARK): + int_val = (int32)watermark; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_WATERMARK): + watermark = (uint)int_val; + watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark; + DHD_ERROR(("Setting watermark as 0x%x.\n", watermark)); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL); + break; + + case IOV_GVAL(IOV_MESBUSYCTRL): + int_val = (int32)mesbusyctrl; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MESBUSYCTRL): + mesbusyctrl = (uint)int_val; + mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) + ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; + DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl)); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, + ((uint8)mesbusyctrl | 0x80), NULL); + break; +#endif /* SDIO_CRC_ERROR_FIX */ case IOV_GVAL(IOV_DONGLEISOLATION): int_val = bus->dhd->dongle_isolation; @@ -3190,6 +3693,33 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch dhdsdio_devcap_set(bus, (uint8) int_val); break; +#ifdef BCMSDIOH_TXGLOM + case IOV_GVAL(IOV_TXGLOMSIZE): + int_val = (int32)bus->glomsize; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TXGLOMSIZE): + if (int_val > SDPCM_MAXGLOM_SIZE) { + bcmerror = BCME_ERROR; + } else { + bus->glomsize = (uint)int_val; + } + break; + case IOV_GVAL(IOV_TXGLOMMODE): + int_val = (int32)bus->glom_mode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TXGLOMMODE): + if ((int_val != SDPCM_TXGLOM_CPY) && (int_val != SDPCM_TXGLOM_MDESC)) { + bcmerror = BCME_RANGE; + } else { + if ((bus->glom_mode = bcmsdh_set_mode(bus->sdh, (uint)int_val)) != int_val) + bcmerror = BCME_ERROR; + } + break; +#endif /* BCMSDIOH_TXGLOM */ default: bcmerror = BCME_UNSUPPORTED; break; @@ -3222,6 +3752,8 @@ dhdsdio_write_vars(dhd_bus_t *bus) varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0; varaddr = (bus->ramsize - 4) - varsize; + varaddr += bus->dongle_ram_base; + if (bus->vars) { if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { @@ -3271,6 +3803,8 @@ dhdsdio_write_vars(dhd_bus_t *bus) phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; + phys_size += bus->dongle_ram_base; + /* adjust to the user specified RAM */ DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", phys_size, bus->ramsize)); @@ -3304,6 +3838,7 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) { uint retries; int bcmerror = 0; + int foundcr4 = 0; /* To enter download state, disable ARM and reset SOCRAM. * To exit download state, simply reset ARM (default is RAM boot). @@ -3313,11 +3848,16 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + foundcr4 = 1; + } else { DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); bcmerror = BCME_ERROR; goto fail; } + } + if (!foundcr4) { si_core_disable(bus->sih, 0); if (bcmsdh_regfail(bus->sdh)) { bcmerror = BCME_SDIO_ERROR; @@ -3350,6 +3890,19 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) } } } else { + /* For CR4, + * Halt ARM + * Remove ARM reset + * Read RAM base address [0x18_0000] + * [next] Download firmware + * [done at else] Populate the reset vector + * [done at else] Remove ARM halt + */ + /* Halt ARM & remove reset */ + si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); + } + } else { + if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); bcmerror = BCME_ERROR; @@ -3366,7 +3919,6 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); goto fail; } - /* Enable remap before ARM reset but after vars. * No backplane access in remap mode */ @@ -3381,13 +3933,40 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) } W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); bcmerror = BCME_ERROR; goto fail; } + } else { + /* cr4 has no socram, but tcm's */ + /* write vars */ + if ((bcmerror = dhdsdio_write_vars(bus))) { + DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); + goto fail; + } + + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && + !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); + + /* switch back to arm core again */ + if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + /* write address 0 with reset instruction */ + bcmerror = dhdsdio_membytes(bus, TRUE, 0, + (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); + + /* now remove reset and halt and continue to run CR4 */ + } si_core_reset(bus->sih, 0, 0); if (bcmsdh_regfail(bus->sdh)) { @@ -3520,7 +4099,7 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) { osl_t *osh; uint32 local_hostintmask; - uint8 saveclk; + uint8 saveclk, dat; uint retries; int err; if (!bus->dhd) @@ -3534,42 +4113,57 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) if (enforce_mutex) dhd_os_sdlock(bus->dhd); - BUS_WAKE(bus); + if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { + bus->dhd->busstate = DHD_BUS_DOWN; + bus->hostintmask = 0; + bcmsdh_intr_disable(bus->sdh); + } else { + BUS_WAKE(bus); - /* Change our idea of bus state */ - bus->dhd->busstate = DHD_BUS_DOWN; + if (KSO_ENAB(bus)) { + /* Mask the interrupt */ + dat = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, NULL); + dat &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, dat, NULL); + } - if (KSO_ENAB(bus)) { + /* Change our idea of bus state */ + bus->dhd->busstate = DHD_BUS_DOWN; - /* Enable clock for device interrupts */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (KSO_ENAB(bus)) { - /* Disable and clear interrupts at the chip level also */ - W_SDREG(0, &bus->regs->hostintmask, retries); - local_hostintmask = bus->hostintmask; - bus->hostintmask = 0; + /* Enable clock for device interrupts */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) { - DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); - } + /* Disable and clear interrupts at the chip level also */ + W_SDREG(0, &bus->regs->hostintmask, retries); + local_hostintmask = bus->hostintmask; + bus->hostintmask = 0; - /* Turn off the bus (F2), free any pending packets */ - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); + /* Force clocks on backplane to be sure F2 interrupt propagates */ + saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (!err) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); + } + if (err) { + DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); + } - /* Clear any pending interrupts now that F2 is disabled */ - W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); - } + /* Turn off the bus (F2), free any pending packets */ + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + bcmsdh_intr_disable(bus->sdh); +#ifndef BCMSPI + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); +#endif - /* Turn off the backplane clock (only) */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + /* Clear any pending interrupts now that F2 is disabled */ + W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); + } + + /* Turn off the backplane clock (only) */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } /* Clear the data packet queues */ pktq_flush(osh, &bus->txq, TRUE, NULL, 0); @@ -3595,6 +4189,33 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) dhd_os_sdunlock(bus->dhd); } +#ifdef BCMSDIOH_TXGLOM +void +dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) +{ + dhd_bus_t *bus = dhdp->bus; + + char buf[256]; + uint32 rxglom; + int32 ret; + + if (enable) { + rxglom = 1; + memset(buf, 0, sizeof(buf)); + bcm_mkiovar("bus:rxglom", + (void *)&rxglom, + 4, buf, sizeof(buf)); + ret = dhd_wl_ioctl_cmd(dhdp, + WLC_SET_VAR, buf, + sizeof(buf), TRUE, 0); + if (!(ret < 0)) { + bus->glom_enable = TRUE; + } + } else { + bus->glom_enable = FALSE; + } +} +#endif /* BCMSDIOH_TXGLOM */ int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) @@ -3604,7 +4225,11 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) uint retries = 0; uint8 ready, enable; int err, ret = 0; +#ifdef BCMSPI + uint32 dstatus = 0; /* gSPI device-status bits */ +#else /* BCMSPI */ uint8 saveclk; +#endif /* BCMSPI */ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -3619,9 +4244,33 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); if (bus->clkstate != CLK_AVAIL) { DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate)); + ret = -1; goto exit; } +#ifdef BCMSPI + /* fake "ready" for spi, wake-wlan would have already enabled F1 and F2 */ + ready = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); + enable = 0; + + /* Give the dongle some time to do its thing and set IOR2 */ + dhd_timeout_start(&tmo, WAIT_F2RXFIFORDY * WAIT_F2RXFIFORDY_DELAY * 1000); + while (!enable && !dhd_timeout_expired(&tmo)) { + dstatus = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, SPID_STATUS_REG, NULL); + if (dstatus & STATUS_F2_RX_READY) + enable = TRUE; + } + + if (enable) { + DHD_ERROR(("Took %u usec before dongle is ready\n", tmo.elapsed)); + enable = ready; + } else { + DHD_ERROR(("dstatus when timed out on f2-fifo not ready = 0x%x\n", dstatus)); + DHD_ERROR(("Waited %u usec, dongle is not ready\n", tmo.elapsed)); + ret = -1; + goto exit; + } +#else /* !BCMSPI */ /* Force clocks on backplane to be sure F2 interrupt propagates */ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); @@ -3631,6 +4280,7 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) } if (err) { DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); + ret = -1; goto exit; } @@ -3648,7 +4298,9 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) while (ready != enable && !dhd_timeout_expired(&tmo)) ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); - DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", +#endif /* !BCMSPI */ + + DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", __FUNCTION__, enable, ready, tmo.elapsed)); @@ -3662,14 +4314,27 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) /* Set up the interrupt mask and enable interrupts */ bus->hostintmask = HOSTINTMASK; /* corerev 4 could use the newer interrupt logic to detect the frames */ +#ifndef BCMSPI if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { bus->hostintmask &= ~I_HMB_FRAME_IND; bus->hostintmask |= I_XMTDATA_AVAIL; } +#endif /* BCMSPI */ W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); +#ifdef SDIO_CRC_ERROR_FIX + if (bus->blocksize < 512) { + mesbusyctrl = watermark = bus->blocksize / 4; + } +#endif /* SDIO_CRC_ERROR_FIX */ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err); +#ifdef SDIO_CRC_ERROR_FIX + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, + (uint8)mesbusyctrl|0x80, &err); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, + SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL); +#endif /* SDIO_CRC_ERROR_FIX */ /* Set bus state according to enable result */ dhdp->busstate = DHD_BUS_DATA; @@ -3687,6 +4352,7 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) } +#ifndef BCMSPI else { /* Disable F2 again */ @@ -3699,6 +4365,7 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) else bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); +#endif /* !BCMSPI */ /* If we didn't come up, turn off backplane clock */ if (dhdp->busstate != DHD_BUS_DATA) @@ -3875,6 +4542,11 @@ dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) dhd_os_ioctl_resp_wake(bus->dhd); } +#ifdef CUSTOMER_HW4 +int pkt_free; +int caller; +void *free_ptr; +#endif static uint8 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) { @@ -3882,7 +4554,10 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) uint8 *dptr, num = 0; uint16 sublen, check; - void *pfirst, *plast, *pnext, *save_pfirst; + void *pfirst, *plast, *pnext; + void * list_tail[DHD_MAX_IFS] = { NULL }; + void * list_head[DHD_MAX_IFS] = { NULL }; + uint8 idx; osl_t *osh = bus->dhd->osh; int errcode; @@ -3894,6 +4569,9 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) int ifidx = 0; bool usechain = bus->use_rxchain; +#ifdef CUSTOMER_HW4 + pkt_free = 0; +#endif /* If packets, issue read(s) and send up packet chain */ /* Return sequence numbers consumed? */ @@ -3917,8 +4595,8 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) sublen = ltoh16_ua(dptr); dlen -= sizeof(uint16); dptr += sizeof(uint16); - if ((sublen < SDPCM_HDRLEN) || - ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { + if ((sublen < SDPCM_HDRLEN_RX) || + ((num == 0) && (sublen < (2 * SDPCM_HDRLEN_RX)))) { DHD_ERROR(("%s: descriptor len %d bad: %d\n", __FUNCTION__, num, sublen)); pnext = NULL; @@ -4087,10 +4765,11 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__)); errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || - (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) { + } else if ((doff < SDPCM_HDRLEN_RX) || + (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN_RX))) { DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", - __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN)); + __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), + SDPCM_HDRLEN_RX)); errcode = -1; } @@ -4134,7 +4813,7 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) "len/check 0x%04x/0x%04x\n", __FUNCTION__, num, sublen, check)); errcode = -1; - } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { + } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN_RX)) { DHD_ERROR(("%s (subframe %d): length mismatch: " "len 0x%04x, expect 0x%04x\n", __FUNCTION__, num, sublen, dlen)); @@ -4144,9 +4823,9 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) DHD_ERROR(("%s (subframe %d): bad channel %d\n", __FUNCTION__, num, chan)); errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { + } else if ((doff < SDPCM_HDRLEN_RX) || (doff > sublen)) { DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n", - __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN)); + __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN_RX)); errcode = -1; } } @@ -4171,7 +4850,6 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) } /* Basic SD framing looks ok - process each packet (header) */ - save_pfirst = pfirst; bus->glom = NULL; plast = NULL; @@ -4211,25 +4889,18 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) reorder_info_len = sizeof(reorder_info_buf); if (PKTLEN(osh, pfirst) == 0) { +#ifdef CUSTOMER_HW4 + pkt_free = 1; + caller = 1; + free_ptr = pfirst; +#endif PKTFREE(bus->dhd->osh, pfirst, FALSE); - if (plast) { - PKTSETNEXT(osh, plast, pnext); - } else { - ASSERT(save_pfirst == pfirst); - save_pfirst = pnext; - } continue; } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, &reorder_info_len) != 0) { DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); bus->dhd->rx_errors++; PKTFREE(osh, pfirst, FALSE); - if (plast) { - PKTSETNEXT(osh, plast, pnext); - } else { - ASSERT(save_pfirst == pfirst); - save_pfirst = pnext; - } continue; } if (reorder_info_len) { @@ -4242,12 +4913,6 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) reorder_info_len, &ppfirst, &free_buf_count); if (free_buf_count == 0) { - if (plast) { - PKTSETNEXT(osh, plast, pnext); - } else { - ASSERT(save_pfirst == pfirst); - save_pfirst = pnext; - } continue; } else { @@ -4259,24 +4924,28 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) temp = PKTNEXT(osh, temp); } pfirst = temp; - if (plast) { - PKTSETNEXT(osh, plast, ppfirst); + if (list_tail[ifidx] == NULL) { + list_head[ifidx] = ppfirst; + list_tail[ifidx] = pfirst; } else { - /* first one in the chain */ - save_pfirst = ppfirst; + PKTSETNEXT(osh, list_tail[ifidx], ppfirst); + list_tail[ifidx] = pfirst; } - - PKTSETNEXT(osh, pfirst, pnext); - plast = pfirst; } num += (uint8)free_buf_count; } else { /* this packet will go up, link back into chain and count it */ - PKTSETNEXT(osh, pfirst, pnext); - plast = pfirst; + + if (list_tail[ifidx] == NULL) { + list_head[ifidx] = list_tail[ifidx] = pfirst; + } + else { + PKTSETNEXT(osh, list_tail[ifidx], pfirst); + list_tail[ifidx] = pfirst; + } num++; } #ifdef DHD_DEBUG @@ -4291,12 +4960,23 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) #endif /* DHD_DEBUG */ } dhd_os_sdunlock_rxq(bus->dhd); - if (num) { - dhd_os_sdunlock(bus->dhd); - dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num, 0); - dhd_os_sdlock(bus->dhd); - } + for (idx = 0; idx < DHD_MAX_IFS; idx++) { + if (list_head[idx]) { + void *temp; + uint8 cnt = 0; + temp = list_head[idx]; + do { + temp = PKTNEXT(osh, temp); + cnt++; + } while (temp); + if (cnt) { + dhd_os_sdunlock(bus->dhd); + dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); + dhd_os_sdlock(bus->dhd); + } + } + } bus->rxglomframes++; bus->rxglompkts += num; } @@ -4323,6 +5003,9 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) uint rxleft = 0; /* Remaining number of frames allowed */ int sdret; /* Return code from bcmsdh calls */ uint8 txmax; /* Maximum tx sequence offered */ +#ifdef BCMSPI + uint32 dstatus = 0; /* gSPI device status bits of */ +#endif /* BCMSPI */ bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ uint8 *rxbuf; int ifidx = 0; @@ -4335,6 +5018,9 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) bool sdtest = FALSE; /* To limit message spew from test mode */ #endif +#ifdef CUSTOMER_HW4 + pkt_free = 0; +#endif DHD_TRACE(("%s: Enter\n", __FUNCTION__)); bus->readframes = TRUE; @@ -4358,6 +5044,38 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) /* Not finished unless we encounter no more frames indication */ *finished = FALSE; +#ifdef BCMSPI + /* Get pktlen from gSPI device F0 reg. */ + if (bus->bus == SPI_BUS) { + /* Peek in dstatus bits and find out size to do rx-read. */ + dstatus = bcmsdh_get_dstatus(bus->sdh); + if (dstatus == 0) + DHD_ERROR(("%s:ZERO spi dstatus, a case observed in PR61352 hit !!!\n", + __FUNCTION__)); + + DHD_TRACE(("Device status from regread = 0x%x\n", dstatus)); + DHD_TRACE(("Device status from bit-reconstruction = 0x%x\n", + bcmsdh_get_dstatus((void *)bus->sdh))); + + if ((dstatus & STATUS_F2_PKT_AVAILABLE) && (((dstatus & STATUS_UNDERFLOW)) == 0)) { + bus->nextlen = ((dstatus & STATUS_F2_PKT_LEN_MASK) >> + STATUS_F2_PKT_LEN_SHIFT); + /* '0' size with pkt-available interrupt is eqvt to 2048 bytes */ + bus->nextlen = (bus->nextlen == 0) ? SPI_MAX_PKT_LEN : bus->nextlen; + if (bus->dwordmode) + bus->nextlen = bus->nextlen << 2; + DHD_TRACE(("Entering %s: length to be read from gSPI = %d\n", + __FUNCTION__, bus->nextlen)); + } else { + if (dstatus & STATUS_F2_PKT_AVAILABLE) + DHD_ERROR(("Underflow during %s.\n", __FUNCTION__)); + else + DHD_ERROR(("False pkt-available intr.\n")); + *finished = TRUE; + return (maxframes - rxleft); + } + } +#endif /* BCMSPI */ for (rxseq = bus->rx_seq, rxleft = maxframes; !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; @@ -4434,6 +5152,20 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) bus->f2rxdata++; ASSERT(sdret != BCME_PENDING); +#ifdef BCMSPI + if (bcmsdh_get_dstatus((void *)bus->sdh) & + STATUS_UNDERFLOW) { + bus->nextlen = 0; + *finished = TRUE; + DHD_ERROR(("%s: read %d control bytes failed " + "due to spi underflow\n", + __FUNCTION__, rdlen)); + /* dhd.rx_ctlerrs is higher level */ + bus->rxc_errors++; + dhd_os_sdunlock_rxq(bus->dhd); + continue; + } +#endif /* BCMSPI */ /* Control frame failures need retransmission */ if (sdret < 0) { @@ -4469,6 +5201,19 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) pkt, NULL, NULL); bus->f2rxdata++; ASSERT(sdret != BCME_PENDING); +#ifdef BCMSPI + if (bcmsdh_get_dstatus((void *)bus->sdh) & STATUS_UNDERFLOW) { + bus->nextlen = 0; + *finished = TRUE; + DHD_ERROR(("%s (nextlen): read %d bytes failed due " + "to spi underflow\n", + __FUNCTION__, rdlen)); + PKTFREE(bus->dhd->osh, pkt, FALSE); + bus->dhd->rx_errors++; + dhd_os_sdunlock_rxq(bus->dhd); + continue; + } +#endif /* BCMSPI */ if (sdret < 0) { DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n", @@ -4487,7 +5232,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) dhd_os_sdunlock_rxq(bus->dhd); /* Now check the header */ - bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN); + bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN_RX); /* Extract hardware header fields */ len = ltoh16_ua(bus->rxhdr); @@ -4519,7 +5264,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } /* Validate frame length */ - if (len < SDPCM_HDRLEN) { + if (len < SDPCM_HDRLEN_RX) { DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n", __FUNCTION__, len)); dhd_os_sdlock_rxq(bus->dhd); @@ -4530,6 +5275,21 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } /* Check for consistency with readahead info */ +#ifdef BCMSPI + if (bus->bus == SPI_BUS) { + if (bus->dwordmode) { + uint16 spilen; + if ((bus->sih->chip == BCM4329_CHIP_ID) && + (bus->sih->chiprev == 2)) + spilen = ROUNDUP(len, 16); + else + spilen = ROUNDUP(len, 4); + + len_consistent = (nextlen != spilen); + } else + len_consistent = (nextlen != len); + } else +#endif /* BCMSPI */ len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4)); if (len_consistent) { /* Mismatch, force retry w/normal header (may be >4K) */ @@ -4551,6 +5311,29 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); +#ifdef BCMSPI + /* Save the readahead length if there is one */ + if (bus->bus == SPI_BUS) { + /* Use reconstructed dstatus bits and find out readahead size */ + dstatus = bcmsdh_get_dstatus((void *)bus->sdh); + DHD_INFO(("Device status from bit-reconstruction = 0x%x\n", + bcmsdh_get_dstatus((void *)bus->sdh))); + if (dstatus & STATUS_F2_PKT_AVAILABLE) { + bus->nextlen = ((dstatus & STATUS_F2_PKT_LEN_MASK) >> + STATUS_F2_PKT_LEN_SHIFT); + bus->nextlen = (bus->nextlen == 0) ? + SPI_MAX_PKT_LEN : bus->nextlen; + if (bus->dwordmode) + bus->nextlen = bus->nextlen << 2; + DHD_INFO(("readahead len from gSPI = %d \n", + bus->nextlen)); + bus->dhd->rx_readahead_cnt ++; + } else { + bus->nextlen = 0; + *finished = TRUE; + } + } else { +#endif /* BCMSPI */ bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; if ((bus->nextlen << 4) > MAX_RX_DATASZ) { @@ -4561,6 +5344,9 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } bus->dhd->rx_readahead_cnt ++; +#ifdef BCMSPI + } +#endif /* BCMSPI */ /* Handle Flow Control */ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); @@ -4589,9 +5375,19 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) /* Check window for sanity */ if ((uint8)(txmax - bus->tx_seq) > 0x40) { +#ifdef BCMSPI + if ((bus->bus == SPI_BUS) && !(dstatus & STATUS_F2_RX_READY)) { + DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + __FUNCTION__, txmax, bus->tx_seq)); + txmax = bus->tx_seq + 2; + } else { +#endif /* BCMSPI */ DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", __FUNCTION__, txmax, bus->tx_seq)); txmax = bus->tx_max; +#ifdef BCMSPI + } +#endif /* BCMSPI */ } bus->tx_max = txmax; @@ -4599,7 +5395,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) if (DHD_BYTES_ON() && DHD_DATA_ON()) { prhex("Rx Data", rxbuf, len); } else if (DHD_HDRS_ON()) { - prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); + prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX); } #endif @@ -4632,9 +5428,9 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { + if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) { DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n", - __FUNCTION__, doff, len, SDPCM_HDRLEN)); + __FUNCTION__, doff, len, SDPCM_HDRLEN_RX)); dhd_os_sdlock_rxq(bus->dhd); PKTFREE2(); dhd_os_sdunlock_rxq(bus->dhd); @@ -4666,7 +5462,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) #ifdef DHD_DEBUG if (DHD_BYTES_ON() || DHD_HDRS_ON()) { - prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); + prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX); } #endif @@ -4690,7 +5486,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } /* Validate frame length */ - if (len < SDPCM_HDRLEN) { + if (len < SDPCM_HDRLEN_RX) { DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len)); continue; } @@ -4702,9 +5498,9 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { + if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) { DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n", - __FUNCTION__, doff, len, SDPCM_HDRLEN, seq)); + __FUNCTION__, doff, len, SDPCM_HDRLEN_RX, seq)); bus->rx_badhdr++; ASSERT(0); dhdsdio_rxfail(bus, FALSE, FALSE); @@ -4845,8 +5641,8 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } #endif PKTSETLEN(osh, pkt, len); - ASSERT(doff == SDPCM_HDRLEN); - PKTPULL(osh, pkt, SDPCM_HDRLEN); + ASSERT(doff == SDPCM_HDRLEN_RX); + PKTPULL(osh, pkt, SDPCM_HDRLEN_RX); bus->glomd = pkt; } else { DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__)); @@ -4869,6 +5665,11 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) if (PKTLEN(osh, pkt) == 0) { dhd_os_sdlock_rxq(bus->dhd); +#ifdef CUSTOMER_HW4 + pkt_free = 1; + caller = 0; + free_ptr = pkt; +#endif PKTFREE(bus->dhd->osh, pkt, FALSE); dhd_os_sdunlock_rxq(bus->dhd); continue; @@ -4957,6 +5758,7 @@ dhdsdio_hostmail(dhd_bus_t *bus) bus->sdpcm_ver, SDPCM_PROT_VERSION)); else DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver)); +#ifndef BCMSPI /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { @@ -4969,6 +5771,7 @@ dhdsdio_hostmail(dhd_bus_t *bus) val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); } +#endif /* BCMSPI */ #ifdef DHD_DEBUG /* Retrieve console state address now that firmware should have updated it */ @@ -5002,6 +5805,7 @@ dhdsdio_hostmail(dhd_bus_t *bus) if (hmb_data & HMB_DATA_FWHALT) { DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n")); dhdsdio_checkdied(bus, NULL, 0); + bus->dhd->busstate = DHD_BUS_DOWN; } #endif /* DHD_DEBUG */ @@ -5113,10 +5917,12 @@ dhdsdio_dpc(dhd_bus_t *bus) bus->fcstate = !!(newstatus & I_HMB_FC_STATE); if (newstatus) { bus->f1regdata++; +#ifndef BCMSPI if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && (newstatus == I_XMTDATA_AVAIL)) { } else +#endif /* BCMSPI */ W_SDREG(newstatus, ®s->intstatus, retries); } } @@ -5197,15 +6003,40 @@ dhdsdio_dpc(dhd_bus_t *bus) DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", __FUNCTION__, rxdone, framecnt)); bus->intdis = FALSE; -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) bcmsdh_oob_intr_set(1); -#endif /* (OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ bcmsdh_intr_enable(sdh); } +#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) + /* In case of SW-OOB(using edge trigger), + * Check interrupt status in the dongle again after enable irq on the host. + * and rechedule dpc if interrupt is pended in the dongle. + * There is a chance to miss OOB interrupt while irq is disabled on the host. + * No need to do this with HW-OOB(level trigger) + */ + R_SDREG(newstatus, ®s->intstatus, retries); + if (bcmsdh_regfail(bus->sdh)) + newstatus = 0; + if (newstatus & bus->hostintmask) { + bus->ipend = TRUE; + resched = TRUE; + } +#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { int ret, i; + uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; + + if (*frame_seq != bus->tx_seq) { + DHD_INFO(("%s IOCTL frame seq lag detected!" + " frm_seq:%d != bus->tx_seq:%d, corrected\n", + __FUNCTION__, *frame_seq, bus->tx_seq)); + *frame_seq = bus->tx_seq; + } + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, NULL, NULL, NULL); @@ -5250,13 +6081,16 @@ dhdsdio_dpc(dhd_bus_t *bus) txlimit -= framecnt; } /* Resched the DPC if ctrl cmd is pending on bus credit */ - if (bus->ctrl_frame_stat) + if (bus->ctrl_frame_stat) { + DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n", + __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate)); resched = TRUE; + } /* Resched if events or tx frames are pending, else await next interrupt */ /* On failed register access, all bets are off: no resched or interrupts */ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { - if ((bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & + if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { /* Bus failed because of KSO */ DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__)); @@ -5351,8 +6185,10 @@ dhdsdio_isr(void *arg) while (dhdsdio_dpc(bus)); DHD_OS_WAKE_UNLOCK(bus->dhd); #else + bus->dpc_sched = TRUE; dhd_sched_dpc(bus->dhd); + #endif } @@ -5373,7 +6209,7 @@ dhdsdio_pktgen_init(dhd_bus_t *bus) /* Default to per-watchdog burst with 10s print time */ bus->pktgen_freq = 1; - bus->pktgen_print = dhd_watchdog_ms ? 10000 / dhd_watchdog_ms : 0; + bus->pktgen_print = dhd_watchdog_ms ? (10000/dhd_watchdog_ms):0; bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; /* Default to echo mode */ @@ -5465,7 +6301,7 @@ dhdsdio_pktgen(dhd_bus_t *bus) #endif /* Send it */ - if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) { + if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) { bus->pktgen_fail++; if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) bus->pktgen_count = 0; @@ -5504,7 +6340,7 @@ dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count) *data++ = (bus->pktgen_maxlen >> 8); /* Send it */ - if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) + if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) bus->pktgen_fail++; } @@ -5549,7 +6385,7 @@ dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) case SDPCM_TEST_ECHOREQ: /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; - if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE) == 0) { + if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE) == 0) { bus->pktgen_sent++; } else { bus->pktgen_fail++; @@ -5658,12 +6494,21 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) /* Check device if no interrupts */ if (!bus->intr || (bus->intrcount == bus->lastintrs)) { +#ifndef BCMSPI if (!bus->dpc_sched) { uint8 devpend; devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTPEND, NULL); intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2); } +#else + if (!bus->dpc_sched) { + uint32 devpend; + devpend = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, + SPID_STATUS_REG, NULL); + intstatus = devpend & STATUS_F2_PKT_AVAILABLE; + } +#endif /* !BCMSPI */ /* If there is something, make like the ISR and schedule the DPC */ if (intstatus) { @@ -5710,8 +6555,27 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) #endif /* On idle timeout clear activity flag and/or turn off clock */ +#ifdef DHD_USE_IDLECOUNT + if (bus->activity) + bus->activity = FALSE; + else { + bus->idlecount++; + + if (bus->idlecount >= bus->idletime) { + DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); + + if (SLPAUTO_ENAB(bus)) { + if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) + dhd_os_wd_timer(bus->dhd, 0); + } else + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + + bus->idlecount = 0; + } + } +#else if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { - if (++bus->idlecount >= bus->idletime) { + if (++bus->idlecount > bus->idletime) { bus->idlecount = 0; if (bus->activity) { bus->activity = FALSE; @@ -5726,6 +6590,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) } } } +#endif /* DHD_USE_IDLECOUNT */ return bus->ipend; } @@ -5778,7 +6643,7 @@ dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) * sdpcm_sendup (RX) checks for virtual console input. */ if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) - dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE); + dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE, FALSE); done: if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { @@ -5845,6 +6710,8 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (chipid == BCM4334_CHIP_ID) return TRUE; + if (chipid == BCM43341_CHIP_ID) + return TRUE; if (chipid == BCM43239_CHIP_ID) return TRUE; if (chipid == BCM4324_CHIP_ID) @@ -5864,6 +6731,17 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + + if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { + DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); + } + else { + DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); + } + mutex_lock(&_dhd_sdio_mutex_lock_); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + /* Init global variables at run-time, not as part of the declaration. * This is required to support init/de-init of the driver. Initialization * of globals as part of the declaration results in non-deterministic @@ -5872,7 +6750,11 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, */ dhd_txbound = DHD_TXBOUND; dhd_rxbound = DHD_RXBOUND; +#ifdef BCMSPI + dhd_alignctl = FALSE; +#else dhd_alignctl = TRUE; +#endif /* BCMSPI */ sd1idle = TRUE; dhd_readahead = TRUE; retrydata = FALSE; @@ -5880,7 +6762,11 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, dhd_dongle_memsize = 0; dhd_txminmax = DHD_TXMINMAX; +#ifdef BCMSPI + forcealign = FALSE; +#else forcealign = TRUE; +#endif /* !BCMSPI */ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid)); @@ -5900,7 +6786,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, default: DHD_ERROR(("%s: unknown vendor: 0x%04x\n", __FUNCTION__, venid)); - return NULL; + goto forcereturn; } /* Check the Device ID and make sure it's one that we support */ @@ -5934,14 +6820,14 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, default: DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", __FUNCTION__, venid, devid)); - return NULL; + goto forcereturn; } if (osh == NULL) { /* Ask the OS interface part for an OSL handle */ if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) { DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__)); - return NULL; + goto forcereturn; } } @@ -6010,21 +6896,40 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, #endif /* GET_CUSTOM_MAC_ENABLE */ /* if firmware path present try to download and bring up bus */ - if (dhd_download_fw_on_driverload && (ret = dhd_bus_start(bus->dhd)) != 0) { - DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); - if (ret == BCME_NOTUP) - goto fail; + if (dhd_download_fw_on_driverload) { + if ((ret = dhd_bus_start(bus->dhd)) != 0) { + DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); + if (ret == BCME_NOTUP) + goto fail; } + } /* Ok, have the per-port tell the stack we're open for business */ if (dhd_net_attach(bus->dhd, 0) != 0) { DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); goto fail; } +#if defined(CUSTOMER_HW4) && defined(BCMHOST_XTAL_PU_TIME_MOD) + bcmsdh_reg_write(bus->sdh, 0x18000620, 2, 11); + bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x00F80001); +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_unlock(&_dhd_sdio_mutex_lock_); + DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + return bus; fail: dhdsdio_release(bus, osh); + +forcereturn: +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_unlock(&_dhd_sdio_mutex_lock_); + DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + return NULL; } @@ -6032,8 +6937,10 @@ static bool dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, uint16 devid) { +#ifndef BCMSPI int err = 0; uint8 clkctl = 0; +#endif /* !BCMSPI */ bus->alp_only = TRUE; bus->sih = NULL; @@ -6049,6 +6956,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, #endif /* DHD_DEBUG */ +#ifndef BCMSPI /* wake-wlan in gSPI will bring up the htavail/alpavail clocks. */ /* Force PLL off until si_attach() programs PLL control regs */ @@ -6064,12 +6972,15 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, goto fail; } +#endif /* !BCMSPI */ + #ifdef DHD_DEBUG if (DHD_INFO_ON()) { uint fn, numfn; uint8 *cis[SDIOD_MAX_IOFUNCS]; int err = 0; +#ifndef BCMSPI numfn = bcmsdh_query_iofnum(sdh); ASSERT(numfn <= SDIOD_MAX_IOFUNCS); @@ -6082,6 +6993,9 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL2, &err); OSL_DELAY(65); +#else + numfn = 0; /* internally func is hardcoded to 1 as gSPI has cis on F1 only */ +#endif /* !BCMSPI */ for (fn = 0; fn <= numfn; fn++) { if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { @@ -6139,17 +7053,28 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, /* Get info on the ARM and SOCRAM cores... */ if (!DHD_NOPMU(bus)) { if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || - (si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || + (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { bus->armrev = si_corerev(bus->sih); } else { DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); goto fail; } + + if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); goto fail; } - + } else { + /* cr4 has a different way to find the RAM size from TCM's */ + if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { + DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); + goto fail; + } + /* also populate base address */ + bus->dongle_ram_base = CR4_RAM_BASE; + } bus->ramsize = bus->orig_ramsize; if (dhd_dongle_memsize) dhd_dongle_setmemsize(bus, dhd_dongle_memsize); @@ -6170,6 +7095,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, /* Set core control so an SDIO reset does a backplane reset */ OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); +#ifndef BCMSPI bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && @@ -6182,6 +7108,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, val |= CC_XMTDATAAVAIL_CTRL; W_REG(osh, &bus->regs->corecontrol, val); } +#endif /* BCMSPI */ pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); @@ -6194,11 +7121,20 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, if ((bus->poll = (bool)dhd_poll)) bus->pollrate = 1; +#ifdef BCMSDIOH_TXGLOM + /* Setting default Glom mode */ + bus->glom_mode = SDPCM_TXGLOM_CPY; + /* Setting default Glom size */ + bus->glomsize = SDPCM_DEFGLOM_SIZE; +#endif + return TRUE; fail: - if (bus->sih != NULL) + if (bus->sih != NULL) { si_detach(bus->sih); + bus->sih = NULL; + } return FALSE; } @@ -6248,16 +7184,20 @@ dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) dhdsdio_pktgen_init(bus); #endif /* SDTEST */ +#ifndef BCMSPI /* Disable F2 to clear any intermediate frame state on the dongle */ bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); +#endif /* !BCMSPI */ bus->dhd->busstate = DHD_BUS_DOWN; bus->sleeping = FALSE; bus->rxflow = FALSE; bus->prev_rxlim_hit = 0; +#ifndef BCMSPI /* Done with backplane-dependent accesses, can drop clock... */ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); +#endif /* !BCMSPI */ /* ...and initialize clock/power states */ bus->clkstate = CLK_SDONLY; @@ -6319,6 +7259,15 @@ dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ret = dhdsdio_download_firmware(bus, osh, bus->sdh); +#ifdef BCMSPI +#ifdef GSPI_DWORD_MODE + /* Enable the dwordmode in gSPI before first F2 transaction */ + if ((bus->sih->chip == BCM4329_CHIP_ID) && (bus->sih->chiprev > 1)) { + bcmsdh_dwordmode(bus->sdh, TRUE); + bus->dwordmode = TRUE; + } +#endif /* GSPI_DWORD_MODE */ +#endif /* BCMSPI */ return ret; } @@ -6434,6 +7383,7 @@ dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool r dhdsdio_clkctl(bus, CLK_NONE, FALSE); } si_detach(bus->sih); + bus->sih = NULL; if (bus->vars && bus->varsz) MFREE(osh, bus->vars, bus->varsz); bus->vars = NULL; @@ -6447,6 +7397,17 @@ dhdsdio_disconnect(void *ptr) { dhd_bus_t *bus = (dhd_bus_t *)ptr; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + + if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { + DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); + } + else { + DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); + } + mutex_lock(&_dhd_sdio_mutex_lock_); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); if (bus) { @@ -6454,6 +7415,11 @@ dhdsdio_disconnect(void *ptr) dhdsdio_release(bus, bus->dhd->osh); } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_unlock(&_dhd_sdio_mutex_lock_); + DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); } @@ -6581,7 +7547,7 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) { int bcmerror = -1; int offset = 0; - uint len; + int len; void *image = NULL; uint8 *memblock = NULL, *memptr; @@ -6601,6 +7567,11 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) /* Download image */ while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { + if (len < 0) { + DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); + bcmerror = BCME_ERROR; + goto err; + } bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); if (bcmerror) { DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", @@ -6818,6 +7789,20 @@ dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle)); } +#ifdef BCMSDIOH_TXGLOM +static void +dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len) +{ + bcmsdh_glom_post(bus->sdh, frame, len); +} + +static void +dhd_bcmsdh_glom_clear(dhd_bus_t *bus) +{ + bcmsdh_glom_clear(bus->sdh); +} +#endif + uint dhd_bus_chip(struct dhd_bus *bus) { @@ -6863,16 +7848,19 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) /* Stop the bus, disable F2 */ dhd_bus_stop(bus, FALSE); -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) /* Clean up any pending IRQ */ bcmsdh_set_irq(FALSE); -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ /* Clean tx/rx buffer pointers, detach from the dongle */ dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); bus->dhd->dongle_reset = TRUE; bus->dhd->up = FALSE; +#ifdef BCMSDIOH_TXGLOM + dhd_txglom_enable(dhdp, FALSE); +#endif dhd_os_sdunlock(dhdp); DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); @@ -6903,10 +7891,12 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) /* Re-init bus, enable F2 transfer */ bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); if (bcmerror == BCME_OK) { -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) bcmsdh_set_irq(TRUE); +#ifndef BCMSPI_ANDROID dhd_enable_oob_intr(bus, TRUE); -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* !BCMSPI_ANDROID */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ bus->dhd->dongle_reset = FALSE; bus->dhd->up = TRUE; @@ -6916,7 +7906,12 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); #endif dhd_os_wd_timer(dhdp, dhd_watchdog_ms); - +#ifdef BCMSDIOH_TXGLOM + if ((dhdp->busstate == DHD_BUS_DATA) && + bcmsdh_glom_enabled()) { + dhd_txglom_enable(dhdp, TRUE); + } +#endif /* BCMSDIOH_TXGLOM */ DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); } else { dhd_bus_stop(bus, FALSE); @@ -6952,6 +7947,23 @@ uint dhd_bus_chip_id(dhd_pub_t *dhdp) return bus->sih->chip; } + +/* Get Chip Rev ID version */ +uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + + return bus->sih->chiprev; +} + +/* Get Chip Pkg ID version */ +uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + + return bus->sih->chippkg; +} + int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) { @@ -6960,3 +7972,65 @@ dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint si bus = dhdp->bus; return dhdsdio_membytes(bus, set, address, data, size); } +#if defined(SUPPORT_MULTIPLE_REVISION) +static int +concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len) +{ +#define REV_ID_ADDR 0x1E008F90 +#define BCM4334_B1_UNIQUE 0x30312E36 + + uint chipver; + uint32 unique_id; + uint8 data[4]; + char chipver_tag[4] = "_b0"; + + DHD_TRACE(("%s: BCM4334 Multiple Revision Check\n", __FUNCTION__)); + if (bus->sih->chip != BCM4334_CHIP_ID) { + DHD_ERROR(("%s:Chip is not BCM4334\n", __FUNCTION__)); + return -1; + } + chipver = bus->sih->chiprev; + if (chipver == 0x2) { + dhdsdio_membytes(bus, FALSE, REV_ID_ADDR, data, 4); + unique_id = load32_ua(data); + if (unique_id == BCM4334_B1_UNIQUE) + chipver = 0x01; + } + DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); + if (chipver == 1) { + DHD_ERROR(("----- CHIP bcm4334_B0 -----\n")); + chipver_tag[2] = '0'; + strcpy(chipver_tag, "_b0"); + } else if (chipver == 2) { + DHD_ERROR(("----- CHIP bcm4334_B1 -----\n")); + chipver_tag[2] = '1'; + } else if (chipver == 3) { + DHD_ERROR(("----- CHIP bcm4334_B2 -----\n")); + chipver_tag[2] = '2'; + strcpy(chipver_tag, "_b2"); + } + else { + DHD_ERROR(("----- Invalid chip version -----\n")); + return -1; + } + strcat(path, chipver_tag); +#undef REV_ID_ADDR +#undef BCM4334_B1_UNIQUE + return 0; +} + +int +concate_revision(dhd_bus_t *bus, char *path, int path_len) +{ + + if (!bus || !bus->sih) { + DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__)); + return -1; + } + if (bus->sih->chip == BCM4334_CHIP_ID) { + return concate_revision_bcm4334(bus, path, path_len); + } + DHD_ERROR(("REVISION SPECIFIC feature is not required\n")); + return -1; +} +#endif /* MULTIPLE_REVISION */ diff --git a/drivers/net/wireless/bcmdhd/dhd_sec_feature.h b/drivers/net/wireless/bcmdhd/dhd_sec_feature.h new file mode 100755 index 00000000000..147751642f2 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_sec_feature.h @@ -0,0 +1,123 @@ +/* + * Header file describing the internal (inter-module) DHD interfaces. + * + * Provides type definitions and function prototypes used to link the + * DHD OS, bus, and protocol modules. + * + * Copyright (C) 1999-2012, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_sec_feature.h 309548 2012-01-20 01:13:08Z $ + */ + +/* PROJECTS */ + +#if defined(CONFIG_MACH_SAMSUNG_ESPRESSO)\ + || defined(CONFIG_MACH_SAMSUNG_ESPRESSO_10) +#define READ_MACADDR +#define HW_OOB +#endif + +/* Q1 also uses this feature */ +#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS) +#ifdef CONFIG_MACH_Q1_BD +#define HW_OOB +#endif +#define USE_CID_CHECK +#define WRITE_MACADDR +#endif + +#ifdef CONFIG_ARCH_MSM7X30 +#define HW_OOB +#define READ_MACADDR +#endif + +#if defined CONFIG_MACH_GC1 || defined CONFIG_MACH_U1_NA_SPR +#undef USE_CID_CHECK +#define READ_MACADDR +#endif + +#ifdef CONFIG_MACH_P10 +#define READ_MACADDR +#endif + +#ifdef CONFIG_ARCH_MSM8960 +#undef WIFI_TURNOFF_DELAY +#define WIFI_TURNOFF_DELAY 200 +#endif + +/* REGION CODE */ + +#if (WLAN_REGION_CODE >= 100) && (WLAN_REGION_CODE < 200) /*EUR*/ +#if (WLAN_REGION_CODE == 101) /*EUR ORG*/ +/* GAN LITE NAT KEEPALIVE FILTER */ +#define GAN_LITE_NAT_KEEPALIVE_FILTER +#endif +#endif + +#if (WLAN_REGION_CODE >= 200) && (WLAN_REGION_CODE < 300) /* KOR */ +#undef USE_INITIAL_2G_SCAN_ORG +#ifndef ROAM_ENABLE +#define ROAM_ENABLE +#endif +#ifndef ROAM_API +#define ROAM_API +#endif +#ifndef ROAM_CHANNEL_CACHE +#define ROAM_CHANNEL_CACHE +#endif +#ifndef OKC_SUPPORT +#define OKC_SUPPORT +#endif + +#ifndef ROAM_AP_ENV_DETECTION +#define ROAM_AP_ENV_DETECTION +#endif + +#undef WRITE_MACADDR +#undef READ_MACADDR +#ifdef CONFIG_BCM4334 +#define READ_MACADDR +#else +#define RDWR_MACADDR +#endif + +#if (WLAN_REGION_CODE == 201) /* SKT */ +#endif + +#if (WLAN_REGION_CODE == 202) /* KTT */ +#define VLAN_MODE_OFF +#define KEEP_ALIVE_PACKET_PERIOD_30_SEC +#define FULL_ROAMING_SCAN_PERIOD_60_SEC +#endif + +#if (WLAN_REGION_CODE == 203) /* LGT */ +#endif +#endif + +#if (WLAN_REGION_CODE >= 300) && (WLAN_REGION_CODE < 400) /* CHN */ +#define BCMWAPI_WPI +#define BCMWAPI_WAI +#endif + +#if !defined(READ_MACADDR) && !defined(WRITE_MACADDR) && !defined(RDWR_KORICS_MACADDR) && !defined(RDWR_MACADDR) +#define GET_MAC_FROM_OTP +#endif + diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h index 09275a2824e..40873514771 100644 --- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h +++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h @@ -18,7 +18,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. -* $Id: dhd_wlfc.h 328424 2012-04-19 05:23:09Z $ +* $Id: dhd_wlfc.h 341930 2012-06-29 04:51:25Z $ * */ #ifndef __wlfc_host_driver_definitions_h__ @@ -29,7 +29,7 @@ #define WLFC_HANGER_ITEM_STATE_FREE 1 #define WLFC_HANGER_ITEM_STATE_INUSE 2 - +#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 #define WLFC_PKTID_HSLOT_MASK 0xffff /* allow 16 bits only */ #define WLFC_PKTID_HSLOT_SHIFT 8 @@ -68,7 +68,8 @@ typedef enum ewlfc_mac_entry_action { typedef struct wlfc_hanger_item { uint8 state; - uint8 pad[3]; + uint8 gen; + uint8 pad[2]; uint32 identifier; void* pkt; #ifdef PROP_TXSTATUS_DEBUG @@ -93,12 +94,14 @@ typedef struct wlfc_hanger { #define WLFC_STATE_CLOSE 2 #define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ -#define WLFC_PSQ_LEN 256 -#define WLFC_SENDQ_LEN 128 +#define WLFC_PSQ_LEN 2048 + +#define WLFC_SENDQ_LEN 256 -#define WLFC_FLOWCONTROL_HIWATER 128 -#define WLFC_FLOWCONTROL_LOWATER 64 + +#define WLFC_FLOWCONTROL_HIWATER (2048 - 256) +#define WLFC_FLOWCONTROL_LOWATER 256 typedef struct wlfc_mac_descriptor { @@ -124,6 +127,11 @@ typedef struct wlfc_mac_descriptor { /* 1= send on next opportunity */ uint8 send_tim_signal; uint8 mac_handle; + uint transit_count; + uint suppr_transit_count; + uint suppress_count; + uint8 suppressed; + #ifdef PROP_TXSTATUS_DEBUG uint32 dstncredit_sent_packets; uint32 dstncredit_acks; diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c index eeee5ea9888..ad9a9ca4645 100644 --- a/drivers/net/wireless/bcmdhd/hndpmu.c +++ b/drivers/net/wireless/bcmdhd/hndpmu.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: hndpmu.c 324060 2012-03-27 23:26:47Z $ + * $Id: hndpmu.c 357871 2012-09-20 07:17:35Z $ */ #include @@ -109,6 +109,13 @@ static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { /* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ +/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { + {3, 0x3}, + {2, 0x2}, + {1, 0x1}, + {0, 0x0} }; + #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) @@ -162,6 +169,11 @@ si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) str_mask = 0x00003800; str_shift = 11; break; + case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; + str_mask = 0x00001800; + str_shift = 11; + break; default: PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); @@ -169,7 +181,7 @@ si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) break; } - if (str_tab != NULL) { + if (str_tab != NULL && cc != NULL) { uint32 cc_data_temp; int i; diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd/include/Makefile old mode 100644 new mode 100755 index 42b3b689b56..eca939fbaa9 --- a/drivers/net/wireless/bcmdhd/include/Makefile +++ b/drivers/net/wireless/bcmdhd/include/Makefile @@ -10,7 +10,7 @@ # # Copyright 2005, Broadcom, Inc. # -# $Id: Makefile 241686 2011-02-19 00:22:45Z $ +# $Id: Makefile 241686 2011-02-19 00:22:45Z prakashd $ # SRCBASE := .. diff --git a/drivers/net/wireless/bcmdhd/include/bcm_android_types.h b/drivers/net/wireless/bcmdhd/include/bcm_android_types.h deleted file mode 100644 index fd8aea72539..00000000000 --- a/drivers/net/wireless/bcmdhd/include/bcm_android_types.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Android related remote wl declarations - * - * Copyright (C) 2012, Broadcom Corporation - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; - * the contents of this file may not be disclosed to third parties, copied - * or duplicated in any form, in whole or in part, without the prior - * written permission of Broadcom Corporation. - * $Id: bcm_android_types.h 241182 2011-02-17 21:50:03Z $ - * - */ -#ifndef _wlu_android_h -#define _wlu_android_h -#define __fd_mask unsigned long -typedef struct - { - -#ifdef __USE_XOPEN - __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS]; -# define __FDS_BITS(set) ((set)->fds_bits) -#else - __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS]; -# define __FDS_BITS(set) ((set)->__fds_bits) -#endif - } fd_set1; -#define fd_set fd_set1 - -#define htons(x) BCMSWAP16(x) -#define htonl(x) BCMSWAP32(x) -#define __FD_ZERO(s) \ - do { \ - unsigned int __i; \ - fd_set *__arr = (s); \ - for (__i = 0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) \ - __FDS_BITS(__arr)[__i] = 0; \ - } while (0) -#define __FD_SET(d, s) (__FDS_BITS (s)[__FDELT(d)] |= __FDMASK(d)) -#define __FD_CLR(d, s) (__FDS_BITS (s)[__FDELT(d)] &= ~__FDMASK(d)) -#define __FD_ISSET(d, s) ((__FDS_BITS (s)[__FDELT(d)] & __FDMASK(d)) != 0) -#define MCL_CURRENT 1 -#define MCL_FUTURE 2 -#endif diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h index 7b0f9b165b3..c7e06ff4481 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmdevs.h +++ b/drivers/net/wireless/bcmdhd/include/bcmdevs.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmdevs.h 327007 2012-04-11 22:45:50Z $ + * $Id: bcmdevs.h 329854 2012-04-27 01:42:28Z $ */ #ifndef _BCMDEVS_H @@ -149,6 +149,9 @@ #define BCM4334_D11N_ID 0x4380 #define BCM4334_D11N2G_ID 0x4381 #define BCM4334_D11N5G_ID 0x4382 +#define BCM43341_D11N_ID 0x4386 +#define BCM43341_D11N2G_ID 0x4387 +#define BCM43341_D11N5G_ID 0x4388 #define BCM4360_D11AC_ID 0x43a0 #define BCM4360_D11AC2G_ID 0x43a1 #define BCM4360_D11AC5G_ID 0x43a2 @@ -263,6 +266,8 @@ #define BCM4360_CHIP_ID 0x4360 #define BCM4352_CHIP_ID 0x4352 #define BCM43526_CHIP_ID 0xAA06 +#define BCM43341_CHIP_ID 43341 +#define BCM43342_CHIP_ID 43342 #define BCM4335_CHIP_ID 0x4335 @@ -449,6 +454,9 @@ +#define BCM943341WLABGS_SSID 0x062d + + #define GPIO_NUMPINS 32 diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h index 36c3604ca50..29657d7ab0f 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdbus.h 320190 2012-03-09 19:13:53Z $ + * $Id: bcmsdbus.h 347614 2012-07-27 10:24:51Z $ */ #ifndef _sdio_api_h_ @@ -46,6 +46,15 @@ #define SDIOH_DATA_PIO 0 /* PIO mode */ #define SDIOH_DATA_DMA 1 /* DMA mode */ +#ifdef BCMSDIOH_TXGLOM +/* Max number of glommed pkts */ +#define SDPCM_MAXGLOM_SIZE 10 +#define SDPCM_DEFGLOM_SIZE 3 + +#define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ +#define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ +#endif + typedef int SDIOH_API_RC; @@ -86,6 +95,18 @@ extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fi uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer, void *pkt); +#ifdef BCMSDIOH_TXGLOM +extern void sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, uint len); +extern void sdioh_glom_clear(sdioh_info_t *sd); +extern uint sdioh_set_mode(sdioh_info_t *sd, uint mode); +extern bool sdioh_glom_enabled(void); +#else +#define sdioh_glom_post(a, b, c) +#define sdioh_glom_clear(a) +#define sdioh_set_mode(a) (0) +#define sdioh_glom_enabled() (FALSE) +#endif + /* get cis data */ extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); @@ -116,6 +137,14 @@ extern int sdioh_sdio_reset(sdioh_info_t *si); void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); +#ifdef BCMSPI +/* Function to pass gSPI specific device-status bits to dhd. */ +extern uint32 sdioh_get_dstatus(sdioh_info_t *si); + +/* chipid and chiprev info for lower layers to control sw WAR's for hw bugs. */ +extern void sdioh_chipinfo(sdioh_info_t *si, uint32 chip, uint32 chiprev); +extern void sdioh_dwordmode(sdioh_info_t *si, bool set); +#endif /* BCMSPI */ #if defined(BCMSDIOH_STD) #define SDIOH_SLEEP_ENABLED diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd/include/bcmsdh.h index b1d9355f8bc..3348e844c89 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdh.h @@ -23,7 +23,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh.h 327460 2012-04-13 18:38:41Z $ + * $Id: bcmsdh.h 347614 2012-07-27 10:24:51Z $ */ /** @@ -145,6 +145,10 @@ extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, void *pkt, bcmsdh_cmplt_fn_t complete_fn, void *handle); +extern void bcmsdh_glom_post(void *sdh, uint8 *frame, uint len); +extern void bcmsdh_glom_clear(void *sdh); +extern uint bcmsdh_set_mode(void *sdh, uint mode); +extern bool bcmsdh_glom_enabled(void); /* Flags bits */ #define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */ #define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */ @@ -211,11 +215,11 @@ extern void bcmsdh_device_remove(void * sdh); extern int bcmsdh_reg_sdio_notify(void* semaphore); extern void bcmsdh_unreg_sdio_notify(void); -#if defined(OOB_INTR_ONLY) +#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) extern int bcmsdh_register_oob_intr(void * dhdp); extern void bcmsdh_unregister_oob_intr(void); extern void bcmsdh_oob_intr_set(bool enable); -#endif /* defined(OOB_INTR_ONLY) */ +#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ /* Function to pass device-status bits to DHD. */ extern uint32 bcmsdh_get_dstatus(void *sdh); @@ -226,6 +230,9 @@ extern uint32 bcmsdh_cur_sbwad(void *sdh); /* Function to pass chipid and rev to lower layers for controlling pr's */ extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); +#ifdef BCMSPI +extern void bcmsdh_dwordmode(void *sdh, bool set); +#endif /* BCMSPI */ extern int bcmsdh_sleep(void *sdh, bool enab); diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h index 80f39003ea4..25cd55b3706 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h @@ -21,19 +21,21 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc.h 313732 2012-02-08 19:49:00Z $ + * $Id: bcmsdh_sdmmc.h 355594 2012-09-07 10:22:02Z $ */ #ifndef __BCMSDH_SDMMC_H__ #define __BCMSDH_SDMMC_H__ -#define sd_err(x) +#define sd_err(x) do {printf x;} while (0) #define sd_trace(x) #define sd_info(x) #define sd_debug(x) #define sd_data(x) #define sd_ctrl(x) +#define sd_trace_hw4 sd_trace + #define sd_sync_dma(sd, read, nbytes) #define sd_init_dma(sd) #define sd_ack_intr(sd) diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h index 8acc0044d50..896686cfcf2 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdstd.h 324797 2012-03-30 11:02:00Z $ + * $Id: bcmsdstd.h 347614 2012-07-27 10:24:51Z $ */ #ifndef _BCM_SD_STD_H #define _BCM_SD_STD_H @@ -92,6 +92,18 @@ extern void sdstd_osfree(sdioh_info_t *sd); #define HC_INTR_RETUNING 0x1000 +#ifdef BCMSDIOH_TXGLOM +/* Setting the MAX limit to 10 */ +#define SDIOH_MAXGLOM_SIZE 10 + +typedef struct glom_buf { + uint32 count; /* Total number of pkts queued */ + void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */ + ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */ + uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */ +} glom_buf_t; +#endif + struct sdioh_info { uint cfg_bar; /* pci cfg address for bar */ uint32 caps; /* cached value of capabilities reg */ @@ -161,6 +173,10 @@ struct sdioh_info { volatile int sd3_tun_state; /* tuning state used for retuning check */ bool sd3_tuning_reqd; /* tuning requirement parameter */ uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ +#ifdef BCMSDIOH_TXGLOM + glom_buf_t glom_info; /* pkt information used for glomming */ + uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ +#endif }; #define DMA_MODE_NONE 0 diff --git a/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h index 0975dc8acda..2203b0de3de 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h +++ b/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h @@ -1,27 +1,52 @@ /* * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer * - * Copyright (C) 2012, Broadcom Corporation - * All Rights Reserved. + * Copyright (C) 1999-2012, Broadcom Corporation * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; - * the contents of this file may not be disclosed to third parties, copied - * or duplicated in any form, in whole or in part, without the prior - * written permission of Broadcom Corporation. + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: * - * $Id: bcmspibrcm.h 241182 2011-02-17 21:50:03Z $ + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmspibrcm.h 354176 2012-08-30 07:34:33Z $ */ #ifndef _BCM_SPI_BRCM_H #define _BCM_SPI_BRCM_H +#ifndef SPI_MAX_IOFUNCS +/* Maximum number of I/O funcs */ +#define SPI_MAX_IOFUNCS 4 +#endif /* global msglevel for debug messages - bitvals come from sdiovar.h */ +#if defined(DHD_DEBUG) +#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) +#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) +#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) +#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0) +#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) +#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0) +#else #define sd_err(x) #define sd_trace(x) #define sd_info(x) #define sd_debug(x) #define sd_data(x) #define sd_ctrl(x) +#endif #define sd_log(x) @@ -48,27 +73,31 @@ #define USE_MULTIBLOCK 0x4 struct sdioh_info { - uint cfg_bar; /* pci cfg address for bar */ + uint cfg_bar; /* pci cfg address for bar */ uint32 caps; /* cached value of capabilities reg */ +#ifndef BCMSPI_ANDROID void *bar0; /* BAR0 for PCI Device */ - osl_t *osh; /* osh handler */ +#endif /* !BCMSPI_ANDROID */ + osl_t *osh; /* osh handler */ void *controller; /* Pointer to SPI Controller's private data struct */ - - uint lockcount; /* nest count of spi_lock() calls */ +#ifndef BCMSPI_ANDROID + uint lockcount; /* nest count of spi_lock() calls */ bool client_intr_enabled; /* interrupt connnected flag */ bool intr_handler_valid; /* client driver interrupt handler valid */ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ void *intr_handler_arg; /* argument to call interrupt handler */ +#endif /* !BCMSPI_ANDROID */ bool initialized; /* card initialized */ uint32 target_dev; /* Target device ID */ uint32 intmask; /* Current active interrupts */ +#ifndef BCMSPI_ANDROID void *sdos_info; /* Pointer to per-OS private data */ - +#endif /* !BCMSPI_ANDROID */ uint32 controller_type; /* Host controller type */ uint8 version; /* Host Controller Spec Compliance Version */ - uint irq; /* Client irq */ - uint32 intrcount; /* Client interrupts */ - uint32 local_intrcount; /* Controller interrupts */ + uint irq; /* Client irq */ + uint32 intrcount; /* Client interrupts */ + uint32 local_intrcount; /* Controller interrupts */ bool host_init_done; /* Controller initted */ bool card_init_done; /* Client SDIO interface initted */ bool polled_mode; /* polling for command completion */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h index 29f8dd7f9bd..cbbd7efdf53 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmutils.h +++ b/drivers/net/wireless/bcmdhd/include/bcmutils.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmutils.h 328848 2012-04-21 00:43:57Z $ + * $Id: bcmutils.h 354184 2012-08-30 08:08:08Z $ */ #ifndef _bcmutils_h_ @@ -657,7 +657,13 @@ extern void *_bcmutils_dummy_fn; (ea).octet[3], \ (ea).octet[4], \ (ea).octet[5] - +#if !defined(SIMPLE_MAC_PRINT) +#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] +#else +#define MACDBG "%02x:%02x:%02x" +#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] +#endif /* SIMPLE_MAC_PRINT */ typedef struct bcm_bit_desc { uint32 bit; diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi.h b/drivers/net/wireless/bcmdhd/include/bcmwifi.h index f3f593f49cc..e5207e9c408 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmwifi.h +++ b/drivers/net/wireless/bcmdhd/include/bcmwifi.h @@ -3,9 +3,9 @@ * This header file housing the define and function prototype use by * both the wl driver, tools & Apps. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2011, Broadcom Corporation * - * Unless you and Broadcom execute a separate written software license + * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the @@ -23,9 +23,10 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmwifi.h 309193 2012-01-19 00:03:57Z $ + * $Id: bcmwifi.h 277737 2011-08-16 17:54:59Z $ */ + #ifndef _bcmwifi_h_ #define _bcmwifi_h_ @@ -37,20 +38,12 @@ typedef uint16 chanspec_t; #define CH_UPPER_SB 0x01 #define CH_LOWER_SB 0x02 #define CH_EWA_VALID 0x04 -#define CH_80MHZ_APART 16 -#define CH_40MHZ_APART 8 #define CH_20MHZ_APART 4 #define CH_10MHZ_APART 2 #define CH_5MHZ_APART 1 #define CH_MAX_2G_CHANNEL 14 +#define WLC_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL #define MAXCHANNEL 224 -#define CHSPEC_CTLOVLP(sp1, sp2, sep) ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep) - - -#undef D11AC_IOTYPES -#define D11AC_IOTYPES - -#ifndef D11AC_IOTYPES #define WL_CHANSPEC_CHAN_MASK 0x00ff #define WL_CHANSPEC_CHAN_SHIFT 0 @@ -74,6 +67,11 @@ typedef uint16 chanspec_t; #define INVCHANSPEC 255 +#define WF_CHAN_FACTOR_2_4_G 4814 +#define WF_CHAN_FACTOR_5_G 10000 +#define WF_CHAN_FACTOR_4_G 8000 + + #define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0) #define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ ((channel) + CH_10MHZ_APART) : 0) @@ -91,8 +89,8 @@ typedef uint16 chanspec_t; #define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) -#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) -#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) +#define CHSPEC_CTL_SB(chspec) (chspec & WL_CHANSPEC_CTL_SB_MASK) +#define CHSPEC_BW(chspec) (chspec & WL_CHANSPEC_BW_MASK) #ifdef WL11N_20MHZONLY @@ -112,6 +110,8 @@ typedef uint16 chanspec_t; #endif +#define CHSPEC_IS20_UNCOND(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) + #define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) #define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) #define CHSPEC_SB_NONE(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE) @@ -124,180 +124,6 @@ typedef uint16 chanspec_t; #define CHANSPEC_STR_LEN 8 -#else - -#define WL_CHANSPEC_CHAN_MASK 0x00ff -#define WL_CHANSPEC_CHAN_SHIFT 0 -#define WL_CHANSPEC_CHAN1_MASK 0x000f -#define WL_CHANSPEC_CHAN1_SHIFT 0 -#define WL_CHANSPEC_CHAN2_MASK 0x00f0 -#define WL_CHANSPEC_CHAN2_SHIFT 4 - -#define WL_CHANSPEC_CTL_SB_MASK 0x0700 -#define WL_CHANSPEC_CTL_SB_SHIFT 8 -#define WL_CHANSPEC_CTL_SB_LLL 0x0000 -#define WL_CHANSPEC_CTL_SB_LLU 0x0100 -#define WL_CHANSPEC_CTL_SB_LUL 0x0200 -#define WL_CHANSPEC_CTL_SB_LUU 0x0300 -#define WL_CHANSPEC_CTL_SB_ULL 0x0400 -#define WL_CHANSPEC_CTL_SB_ULU 0x0500 -#define WL_CHANSPEC_CTL_SB_UUL 0x0600 -#define WL_CHANSPEC_CTL_SB_UUU 0x0700 -#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL -#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU -#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU - -#define WL_CHANSPEC_BW_MASK 0x3800 -#define WL_CHANSPEC_BW_SHIFT 11 -#define WL_CHANSPEC_BW_5 0x0000 -#define WL_CHANSPEC_BW_10 0x0800 -#define WL_CHANSPEC_BW_20 0x1000 -#define WL_CHANSPEC_BW_40 0x1800 -#define WL_CHANSPEC_BW_80 0x2000 -#define WL_CHANSPEC_BW_160 0x2800 -#define WL_CHANSPEC_BW_8080 0x3000 - -#define WL_CHANSPEC_BAND_MASK 0xc000 -#define WL_CHANSPEC_BAND_SHIFT 14 -#define WL_CHANSPEC_BAND_2G 0x0000 -#define WL_CHANSPEC_BAND_3G 0x4000 -#define WL_CHANSPEC_BAND_4G 0x8000 -#define WL_CHANSPEC_BAND_5G 0xc000 -#define INVCHANSPEC 255 - - -#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ - ((channel) - CH_10MHZ_APART) : 0) -#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ - ((channel) + CH_10MHZ_APART) : 0) -#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) -#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) -#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) -#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ - (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ - ((channel) + CH_20MHZ_APART) : 0) -#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ - ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ - WL_CHANSPEC_BAND_5G)) -#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | \ - WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) -#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | \ - WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) - - -#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) -#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) -#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) -#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) -#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) -#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) - -#ifdef WL11N_20MHZONLY - -#define CHSPEC_IS10(chspec) 0 -#define CHSPEC_IS20(chspec) 1 -#ifndef CHSPEC_IS40 -#define CHSPEC_IS40(chspec) 0 -#endif -#ifndef CHSPEC_IS80 -#define CHSPEC_IS80(chspec) 0 -#endif -#ifndef CHSPEC_IS160 -#define CHSPEC_IS160(chspec) 0 -#endif -#ifndef CHSPEC_IS8080 -#define CHSPEC_IS8080(chspec) 0 -#endif - -#else - -#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) -#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) -#ifndef CHSPEC_IS40 -#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) -#endif -#ifndef CHSPEC_IS80 -#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) -#endif -#ifndef CHSPEC_IS160 -#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) -#endif -#ifndef CHSPEC_IS8080 -#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) -#endif - -#endif - -#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) -#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) -#define CHSPEC_SB_UPPER(chspec) \ - ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ - (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#define CHSPEC_SB_LOWER(chspec) \ - ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ - (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) - - -#define CHANSPEC_STR_LEN 20 - - - -#define WL_LCHANSPEC_CHAN_MASK 0x00ff -#define WL_LCHANSPEC_CHAN_SHIFT 0 - -#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 -#define WL_LCHANSPEC_CTL_SB_SHIFT 8 -#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 -#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 -#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 - -#define WL_LCHANSPEC_BW_MASK 0x0C00 -#define WL_LCHANSPEC_BW_SHIFT 10 -#define WL_LCHANSPEC_BW_10 0x0400 -#define WL_LCHANSPEC_BW_20 0x0800 -#define WL_LCHANSPEC_BW_40 0x0C00 - -#define WL_LCHANSPEC_BAND_MASK 0xf000 -#define WL_LCHANSPEC_BAND_SHIFT 12 -#define WL_LCHANSPEC_BAND_5G 0x1000 -#define WL_LCHANSPEC_BAND_2G 0x2000 - -#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) -#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) -#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) -#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) -#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) -#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) -#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) -#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) -#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) - -#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) - -#endif - - - - -#define WF_CHAN_FACTOR_2_4_G 4814 - - -#define WF_CHAN_FACTOR_5_G 10000 - - -#define WF_CHAN_FACTOR_4_G 8000 - #define WLC_MAXRATE 108 #define WLC_RATE_1M 2 @@ -319,24 +145,18 @@ typedef uint16 chanspec_t; extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); -extern chanspec_t wf_chspec_aton(const char *a); +extern chanspec_t wf_chspec_aton(char *a); extern bool wf_chspec_malformed(chanspec_t chanspec); -extern bool wf_chspec_valid(chanspec_t chanspec); - - extern uint8 wf_chspec_ctlchan(chanspec_t chspec); extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); -extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); - - extern int wf_mhz2channel(uint freq, uint start_factor); diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h index 03c44ad867d..11fff555a8f 100644 --- a/drivers/net/wireless/bcmdhd/include/dhdioctl.h +++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h @@ -25,7 +25,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhdioctl.h 327460 2012-04-13 18:38:41Z $ + * $Id: dhdioctl.h 354894 2012-09-04 12:34:07Z $ */ #ifndef _dhdioctl_h_ @@ -93,6 +93,7 @@ enum { #define DHD_ARPOE_VAL 0x4000 #define DHD_REORDER_VAL 0x8000 #define DHD_WL_VAL 0x10000 +#define DHD_WL_VAL2 0x20000 #ifdef SDTEST /* For pktgen iovar */ diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 8fcf87cb9e0..60f9838c514 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -19,7 +19,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 $ + * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 csm Exp $ * */ @@ -28,21 +28,29 @@ #define EPI_MAJOR_VERSION 1 -#define EPI_MINOR_VERSION 27 +#define EPI_MINOR_VERSION 28 -#define EPI_RC_NUMBER 0 +#define EPI_RC_NUMBER 13 -#define EPI_INCREMENTAL_NUMBER 0 +#define EPI_INCREMENTAL_NUMBER 1 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 27, 0, 0 +#define EPI_VERSION 1, 28, 13, 1 -#define EPI_VERSION_NUM 0x011b0000 +#define EPI_VERSION_NUM 0x011c0d01 -#define EPI_VERSION_DEV 1.27.0 +#define EPI_VERSION_DEV 1.28.13 +/* Driver Version String, ASCII, 32 chars max */ +#ifdef BCMINTERNAL +#define EPI_VERSION_STR "1.28.13.1 (r BCMINT)" +#else +#ifdef WLTEST +#define EPI_VERSION_STR "1.28.13.1 (r WLTEST)" +#else +#define EPI_VERSION_STR "1.28.13.1 (r)" +#endif +#endif /* BCMINTERNAL */ -#define EPI_VERSION_STR "1.27 (r329705)" - -#endif +#endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h index 257aaf642f8..5fd1dbd31b4 100644 --- a/drivers/net/wireless/bcmdhd/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linux_osl.h 326751 2012-04-10 20:13:19Z $ + * $Id: linux_osl.h 352246 2012-08-22 05:42:04Z $ */ #ifndef _linux_osl_h_ @@ -166,7 +166,7 @@ extern int osl_error(int bcmerror); #include #include -#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) #define printf(fmt, args...) printk(fmt , ## args) #include #include diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h index e59ac886f75..3c2a1683132 100644 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/include/linuxver.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linuxver.h 315203 2012-02-16 00:58:00Z $ + * $Id: linuxver.h 353905 2012-08-29 07:33:08Z $ */ #ifndef _linuxver_h_ @@ -95,18 +95,20 @@ #ifndef flush_scheduled_work #define flush_scheduled_work() flush_scheduled_tasks() #endif -#endif +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define DAEMONIZE(a) daemonize(a); \ allow_signal(SIGKILL); \ allow_signal(SIGTERM); -#else /* Linux 2.4 (w/o preemption patch) */ +#else +#define RAISE_RX_SOFTIRQ() \ + cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) #define DAEMONIZE(a) daemonize(); \ do { if (a) \ - strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ } while (0); -#endif /* LINUX_VERSION_CODE */ +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) #define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) @@ -162,6 +164,10 @@ typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); #endif +#ifdef CUSTOMER_HW4 +#include +#endif + #ifndef __exit #define __exit #endif @@ -512,11 +518,25 @@ typedef struct { (tsk_ctl)->parent = owner; \ (tsk_ctl)->terminated = FALSE; \ (tsk_ctl)->thr_pid = kernel_thread(thread_func, tsk_ctl, flags); \ + DBG_THR(("%s thr:%lx created\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ if ((tsk_ctl)->thr_pid > 0) \ wait_for_completion(&((tsk_ctl)->completed)); \ DBG_THR(("%s thr:%lx started\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ } +#ifdef USE_KTHREAD_API +#define PROC_START2(thread_func, owner, tsk_ctl, flags, name) \ +{ \ + sema_init(&((tsk_ctl)->sema), 0); \ + init_completion(&((tsk_ctl)->completed)); \ + (tsk_ctl)->parent = owner; \ + (tsk_ctl)->terminated = FALSE; \ + (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ + (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ + DBG_THR(("%s thr:%lx created\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ +} +#endif + #define PROC_STOP(tsk_ctl) \ { \ (tsk_ctl)->terminated = TRUE; \ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h index bd0942eb964..1632e7dcd67 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.11.h @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to 802.11 * - * $Id: 802.11.h 328824 2012-04-20 22:51:46Z $ + * $Id: 802.11.h 346820 2012-07-24 13:53:12Z $ */ #ifndef _802_11_H_ @@ -1734,6 +1734,7 @@ typedef struct vndr_ie vndr_ie_t; #define VNDR_IE_HDR_LEN 2 #define VNDR_IE_MIN_LEN 3 +#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) #define VNDR_IE_MAX_LEN 256 @@ -2037,11 +2038,11 @@ typedef enum vht_op_chan_width { } vht_op_chan_width_t; -#define VHT_MCS_MAP_GET_SS_IDX(numSpatialStreams) ((numSpatialStreams-1)*2) -#define VHT_MCS_MAP_GET_MCS_PER_SS(numSpatialStreams, mcsMap) \ - ((mcsMap >> VHT_MCS_MAP_GET_SS_IDX(numSpatialStreams)) & 0x3) -#define VHT_MCS_MAP_SET_MCS_PER_SS(numSpatialStreams, numMcs, mcsMap) \ - (mcsMap |= ((numMcs & 0x3) << VHT_MCS_MAP_GET_SS_IDX(numSpatialStreams))) +#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1)*2) +#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ + (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & 0x3) +#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ + ((mcsMap) |= (((numMcs) & 0x3) << VHT_MCS_MAP_GET_SS_IDX(nss))) #define WPA_OUI "\x00\x50\xF2" diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h index f391e68c110..c837f57c3bf 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h @@ -117,6 +117,12 @@ typedef BWL_PRE_PACKED_STRUCT struct tspec { #define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ #define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ #define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ +#ifdef BCMCCX +#define CCX_STATUS_ASSOC_DENIED_UNKNOWN 0xc8 /* unspecified QoS related failure */ +#define CCX_STATUS_ASSOC_DENIED_AP_POLICY 0xc9 /* TSPEC refused due to AP policy */ +#define CCX_STATUS_ASSOC_DENIED_NO_BW 0xca /* Assoc denied due to AP insufficient BW */ +#define CCX_STATUS_ASSOC_DENIED_BAD_PARAM 0xcb /* one or more TSPEC with invalid parameter */ +#endif /* BCMCCX */ /* 802.11e DELTS status code */ #define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h index 0a337f6420c..312074dc4bf 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h @@ -215,6 +215,9 @@ extern const int bcmevent_names_size; #define WLC_E_STATUS_11HQUIET 11 #define WLC_E_STATUS_SUPPRESS 12 #define WLC_E_STATUS_NOCHANS 13 +#ifdef BCMCCX +#define WLC_E_STATUS_CCXFASTRM 14 +#endif #define WLC_E_STATUS_CS_ABORT 15 #define WLC_E_STATUS_ERROR 16 @@ -247,11 +250,21 @@ extern const int bcmevent_names_size; #define WLC_E_RSN_MISMATCH 8 #define WLC_E_PRUNE_NO_COMMON_RATES 9 #define WLC_E_PRUNE_BASIC_RATES 10 +#ifdef BCMCCX +#define WLC_E_PRUNE_CCXFAST_PREVAP 11 +#endif #define WLC_E_PRUNE_CIPHER_NA 12 #define WLC_E_PRUNE_KNOWN_STA 13 +#ifdef BCMCCX +#define WLC_E_PRUNE_CCXFAST_DROAM 14 +#endif #define WLC_E_PRUNE_WDS_PEER 15 #define WLC_E_PRUNE_QBSS_LOAD 16 #define WLC_E_PRUNE_HOME_AP 17 +#ifdef BCMCCX +#define WLC_E_PRUNE_AP_BLOCKED 18 +#define WLC_E_PRUNE_NO_DIAG_SUPPORT 19 +#endif #define WLC_E_SUP_OTHER 0 diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/include/proto/p2p.h index 19493eb18b1..2b6fef6b7ac 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/p2p.h +++ b/drivers/net/wireless/bcmdhd/include/proto/p2p.h @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) * - * $Id: p2p.h 326276 2012-04-06 23:16:42Z $ + * $Id: p2p.h 357863 2012-09-20 06:40:47Z $ */ #ifndef _P2P_H_ @@ -376,7 +376,7 @@ typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; #define P2P_PAF_DEVDIS_RSP 6 #define P2P_PAF_PROVDIS_REQ 7 #define P2P_PAF_PROVDIS_RSP 8 - +#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ #define P2P_TYPE_MNREQ P2P_PAF_GON_REQ #define P2P_TYPE_MNRSP P2P_PAF_GON_RSP diff --git a/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd/include/proto/wpa.h index cc2ff5b315d..47bc354c0ba 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/wpa.h +++ b/drivers/net/wireless/bcmdhd/include/proto/wpa.h @@ -34,7 +34,7 @@ #include - +#include #define DOT11_RC_INVALID_WPA_IE 13 @@ -115,6 +115,15 @@ typedef BWL_PRE_PACKED_STRUCT struct #define WPA_CIPHER_WEP_104 5 #define WPA_CIPHER_BIP 6 #define WPA_CIPHER_TPK 7 +#ifdef BCMCCX +#define WPA_CIPHER_CKIP 8 +#define WPA_CIPHER_CKIP_MMH 9 +#define WPA_CIPHER_WEP_MMH 10 + +#define IS_CCX_CIPHER(cipher) ((cipher) == WPA_CIPHER_CKIP || \ + (cipher) == WPA_CIPHER_CKIP_MMH || \ + (cipher) == WPA_CIPHER_WEP_MMH) +#endif #ifdef BCMWAPI_WAI #define WAPI_CIPHER_NONE WPA_CIPHER_NONE diff --git a/drivers/net/wireless/bcmdhd/include/rwl_wifi.h b/drivers/net/wireless/bcmdhd/include/rwl_wifi.h deleted file mode 100644 index 187c2bc6337..00000000000 --- a/drivers/net/wireless/bcmdhd/include/rwl_wifi.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * RWL definitions of - * Broadcom 802.11bang Networking Device Driver - * - * Copyright (C) 2012, Broadcom Corporation - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; - * the contents of this file may not be disclosed to third parties, copied - * or duplicated in any form, in whole or in part, without the prior - * written permission of Broadcom Corporation. - * - * $Id: rwl_wifi.h 281527 2011-09-02 17:12:53Z $ - * - */ - -#ifndef _rwl_wifi_h_ -#define _rwl_wifi_h_ - -#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR) || defined(RFAWARE) - -#define RWL_ACTION_WIFI_CATEGORY 127 /* Vendor-specific category value for WiFi */ -#define RWL_WIFI_OUI_BYTE0 0x00 /* BRCM-specific public OUI */ -#define RWL_WIFI_OUI_BYTE1 0x90 -#define RWL_WIFI_OUI_BYTE2 0x4c -#define RWL_WIFI_ACTION_FRAME_SIZE sizeof(struct dot11_action_wifi_vendor_specific) -#define RWL_WIFI_FIND_MY_PEER 0x09 /* Used while finding server */ -#define RWL_WIFI_FOUND_PEER 0x0A /* Server response to the client */ -#define RWL_WIFI_DEFAULT 0x00 -#define RWL_ACTION_WIFI_FRAG_TYPE 0x55 /* Fragment indicator for receiver */ - -/* - * Information about the action frame data fields in the dot11_action_wifi_vendor_specific - * cdc structure (1 to 16). This does not include the status flag. Since this - * is not directly visible to the driver code, we can't use sizeof(struct cdc_ioctl). - * Hence Ref MAC address offset starts from byte 17. - * REF MAC ADDR (6 bytes (MAC Address len) from byte 17 to 22) - * DUT MAC ADDR (6 bytes after the REF MAC Address byte 23 to 28) - * unused (byte 29 to 49) - * REF/Client Channel offset (50) - * DUT/Server channel offset (51) - * --------------------------------------------------------------------------------------- - * cdc struct|REF MAC ADDR|DUT_MAC_ADDR|un used|REF Channel|DUT channel|Action frame Data| - * 1---------17-----------23-------------------50----------51----------52----------------1040 - * REF MAC addr after CDC struct without status flag (status flag not used by wifi) - */ - -#define RWL_REF_MAC_ADDRESS_OFFSET 17 -#define RWL_DUT_MAC_ADDRESS_OFFSET 23 -#define RWL_WIFI_CLIENT_CHANNEL_OFFSET 50 -#define RWL_WIFI_SERVER_CHANNEL_OFFSET 51 - -#ifdef WIFI_REFLECTOR -#include -#define REMOTE_FINDSERVER_CMD 16 -#define RWL_WIFI_ACTION_CMD "wifiaction" -#define RWL_WIFI_ACTION_CMD_LEN 11 /* With the NULL terminator */ -#define REMOTE_SET_CMD 1 -#define REMOTE_GET_CMD 2 -#define REMOTE_REPLY 4 -#define RWL_WIFI_DEFAULT_TYPE 0x00 -#define RWL_WIFI_DEFAULT_SUBTYPE 0x00 -#define RWL_ACTION_FRAME_DATA_SIZE 1024 /* fixed size for the wifi frame data */ -#define RWL_WIFI_CDC_HEADER_OFFSET 0 -#define RWL_WIFI_FRAG_DATA_SIZE 960 /* max size of the frag data */ -#define RWL_DEFAULT_WIFI_FRAG_COUNT 127 /* maximum fragment count */ -#define RWL_WIFI_RETRY 5 /* CMD retry count for wifi */ -#define RWL_WIFI_SEND 5 /* WIFI frame sent count */ -#define RWL_WIFI_SEND_DELAY 100 /* delay between two frames */ -#define MICROSEC_CONVERTOR_VAL 1000 -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif - -typedef struct rem_packet { - rem_ioctl_t rem_cdc; - uchar message [RWL_ACTION_FRAME_DATA_SIZE]; -} rem_packet_t; - -struct send_packet { - char command [RWL_WIFI_ACTION_CMD_LEN]; - dot11_action_wifi_vendor_specific_t response; -} PACKED; -typedef struct send_packet send_packet_t; - -#define REMOTE_SIZE sizeof(rem_ioctl_t) -#endif /* WIFI_REFLECTOR */ - -typedef struct rwl_request { - struct rwl_request* next_request; - struct dot11_action_wifi_vendor_specific action_frame; -} rwl_request_t; - - -#endif /* defined(RWL_WIFI) || defined(WIFI_REFLECTOR) */ -#endif /* _rwl_wifi_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h index 761bc887c94..5feb7430715 100644 --- a/drivers/net/wireless/bcmdhd/include/sbchipc.h +++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h @@ -5,7 +5,7 @@ * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, * GPIO interface, extbus, and support for serial and parallel flashes. * - * $Id: sbchipc.h 328358 2012-04-18 23:14:31Z $ + * $Id: sbchipc.h 347614 2012-07-27 10:24:51Z $ * * Copyright (C) 1999-2012, Broadcom Corporation * @@ -289,8 +289,13 @@ typedef volatile struct { uint32 pllcontrol_data; uint32 pmustrapopt; uint32 pmu_xtalfreq; - uint32 PAD[100]; + uint32 retention_ctl; + uint32 PAD[3]; + uint32 retention_grpidx; + uint32 retention_grpctl; + uint32 PAD[94]; uint16 sromotp[512]; +#ifdef NFLASH_SUPPORT uint32 nand_revision; uint32 nand_cmd_start; @@ -353,6 +358,16 @@ typedef volatile struct { uint32 nand_cache_data; uint32 nand_ctrl_config; uint32 nand_ctrl_status; +#endif + uint32 gci_corecaps0; + uint32 gci_corecaps1; + uint32 gci_corecaps2; + uint32 gci_corectrl; + uint32 gci_corestat; + uint32 PAD[11]; + uint32 gci_indirect_addr; + uint32 PAD[111]; + uint32 gci_chipctrl; } chipcregs_t; #endif @@ -399,6 +414,10 @@ typedef volatile struct { #define PMU_PLL_CONTROL_ADDR 0x660 #define PMU_PLL_CONTROL_DATA 0x664 #define CC_SROM_OTP 0x800 +#define CC_GCI_INDIRECT_ADDR_REG 0xC40 +#define CC_GCI_CHIP_CTRL_REG 0xE00 +#define CC_GCI_CC_OFFSET_2 2 +#define CC_GCI_CC_OFFSET_5 5 #ifdef NFLASH_SUPPORT @@ -2154,6 +2173,134 @@ typedef volatile struct { #define CCTRL_4360_UART_SEL 0x2 +#define RES4335_LPLDO_PO 0 +#define RES4335_PMU_BG_PU 1 +#define RES4335_PMU_SLEEP 2 +#define RES4335_RSVD_3 3 +#define RES4335_CBUCK_LPOM_PU 4 +#define RES4335_CBUCK_PFM_PU 5 +#define RES4335_RSVD_6 6 +#define RES4335_RSVD_7 7 +#define RES4335_LNLDO_PU 8 +#define RES4335_XTALLDO_PU 9 +#define RES4335_LDO3P3_PU 10 +#define RES4335_OTP_PU 11 +#define RES4335_XTAL_PU 12 +#define RES4335_SR_CLK_START 13 +#define RES4335_LQ_AVAIL 14 +#define RES4335_LQ_START 15 +#define RES4335_RSVD_16 16 +#define RES4335_WL_CORE_RDY 17 +#define RES4335_ILP_REQ 18 +#define RES4335_ALP_AVAIL 19 +#define RES4335_MINI_PMU 20 +#define RES4335_RADIO_PU 21 +#define RES4335_SR_CLK_STABLE 22 +#define RES4335_SR_SAVE_RESTORE 23 +#define RES4335_SR_PHY_PWRSW 24 +#define RES4335_SR_VDDM_PWRSW 25 +#define RES4335_SR_SUBCORE_PWRSW 26 +#define RES4335_SR_SLEEP 27 +#define RES4335_HT_START 28 +#define RES4335_HT_AVAIL 29 +#define RES4335_MACPHY_CLKAVAIL 30 + + +#define CST4335_SPROM_MASK 0x00000020 +#define CST4335_SFLASH_MASK 0x00000040 +#define CST4335_RES_INIT_MODE_SHIFT 7 +#define CST4335_RES_INIT_MODE_MASK 0x00000180 +#define CST4335_CHIPMODE_MASK 0xF +#define CST4335_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) +#define CST4335_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) +#define CST4335_CHIPMODE_USB20D(cs) (((cs) & (1 << 2)) != 0) +#define CST4335_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) + + +#define CCTRL1_4335_GPIO_SEL (1 << 0) +#define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) + + +#define CR4_RAM_BASE (0x180000) + + + + +#define CC_GCI_CHIPCTRL_00 (0) +#define CC_GCI_CHIPCTRL_01 (1) +#define CC_GCI_CHIPCTRL_02 (2) +#define CC_GCI_CHIPCTRL_03 (3) +#define CC_GCI_CHIPCTRL_04 (4) +#define CC_GCI_CHIPCTRL_05 (5) +#define CC_GCI_CHIPCTRL_06 (6) +#define CC_GCI_CHIPCTRL_07 (7) +#define CC_GCI_CHIPCTRL_08 (8) + +#define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) + + +#define CC4335_PIN_GPIO_00 (0) +#define CC4335_PIN_GPIO_01 (1) +#define CC4335_PIN_GPIO_02 (2) +#define CC4335_PIN_GPIO_03 (3) +#define CC4335_PIN_GPIO_04 (4) +#define CC4335_PIN_GPIO_05 (5) +#define CC4335_PIN_GPIO_06 (6) +#define CC4335_PIN_GPIO_07 (7) +#define CC4335_PIN_GPIO_08 (8) +#define CC4335_PIN_GPIO_09 (9) +#define CC4335_PIN_GPIO_10 (10) +#define CC4335_PIN_GPIO_11 (11) +#define CC4335_PIN_GPIO_12 (12) +#define CC4335_PIN_GPIO_13 (13) +#define CC4335_PIN_GPIO_14 (14) +#define CC4335_PIN_GPIO_15 (15) +#define CC4335_PIN_SDIO_CLK (16) +#define CC4335_PIN_SDIO_CMD (17) +#define CC4335_PIN_SDIO_DATA0 (18) +#define CC4335_PIN_SDIO_DATA1 (19) +#define CC4335_PIN_SDIO_DATA2 (20) +#define CC4335_PIN_SDIO_DATA3 (21) +#define CC4335_PIN_RF_SW_CTRL_0 (22) +#define CC4335_PIN_RF_SW_CTRL_1 (23) +#define CC4335_PIN_RF_SW_CTRL_2 (24) +#define CC4335_PIN_RF_SW_CTRL_3 (25) +#define CC4335_PIN_RF_SW_CTRL_4 (26) +#define CC4335_PIN_RF_SW_CTRL_5 (27) +#define CC4335_PIN_RF_SW_CTRL_6 (28) +#define CC4335_PIN_RF_SW_CTRL_7 (29) +#define CC4335_PIN_RF_SW_CTRL_8 (30) +#define CC4335_PIN_RF_SW_CTRL_9 (31) + + +#define CC4335_FNSEL_HWDEF (0) +#define CC4335_FNSEL_SAMEASPIN (1) +#define CC4335_FNSEL_GPIO0 (2) +#define CC4335_FNSEL_GPIO1 (3) +#define CC4335_FNSEL_GCI0 (4) +#define CC4335_FNSEL_GCI1 (5) +#define CC4335_FNSEL_UART (6) +#define CC4335_FNSEL_SFLASH (7) +#define CC4335_FNSEL_SPROM (8) +#define CC4335_FNSEL_MISC0 (9) +#define CC4335_FNSEL_MISC1 (10) +#define CC4335_FNSEL_MISC2 (11) +#define CC4335_FNSEL_IND (12) +#define CC4335_FNSEL_PDN (13) +#define CC4335_FNSEL_PUP (14) +#define CC4335_FNSEL_TRI (15) + + +#define GCIMASK(pos) (((uint32)0xF) << pos) + + +#define GCIPOSVAL(val, pos) ((((uint32)val) << pos) & GCIMASK(pos)) + + +#define MUXENAB4335_UART_MASK (0x0000000f) + + + #define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) & CST4360_MODE_USB) diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h index 4b5a1cf465f..0e9ad7d74ee 100644 --- a/drivers/net/wireless/bcmdhd/include/sbsdio.h +++ b/drivers/net/wireless/bcmdhd/include/sbsdio.h @@ -120,6 +120,7 @@ #define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */ #define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */ #define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */ +#define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ /* SBSDIO_FUNC1_CHIPCLKCSR */ @@ -164,7 +165,11 @@ /* direct(mapped) cis space */ #define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ +#ifdef BCMSPI +#define SBSDIO_CIS_SIZE_LIMIT 0x100 /* maximum bytes in one spi CIS */ +#else #define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */ +#endif /* !BCMSPI */ #define SBSDIO_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP CIS */ #define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */ diff --git a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h index 2c595356805..10c7401a81c 100644 --- a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h +++ b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sbsdpcmdev.h 241182 2011-02-17 21:50:03Z $ + * $Id: sbsdpcmdev.h 347614 2012-07-27 10:24:51Z $ */ #ifndef _sbsdpcmdev_h_ @@ -290,4 +290,6 @@ typedef volatile struct { /* HW frame tag */ #define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ +#define SDPCM_HWEXT_LEN 8 + #endif /* _sbsdpcmdev_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd/include/sdioh.h index e847a52babe..5517a718507 100644 --- a/drivers/net/wireless/bcmdhd/include/sdioh.h +++ b/drivers/net/wireless/bcmdhd/include/sdioh.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sdioh.h 299859 2011-12-01 03:53:27Z $ + * $Id: sdioh.h 347633 2012-07-27 11:02:02Z $ */ #ifndef _SDIOH_H @@ -89,6 +89,10 @@ #define SD3_PresetVal_SDR50 0x06a #define SD3_PresetVal_SDR104 0x06c #define SD3_PresetVal_DDR50 0x06e +/* SDIO3.0 Revx specific Registers */ +#define SD3_Tuning_Info_Register 0x0EC +#define SD3_WL_BT_reset_register 0x0F0 + /* preset value indices */ #define SD3_PRESETVAL_INITIAL_IX 0 diff --git a/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd/include/sdiovar.h index 83f82de2649..16a1c19184e 100644 --- a/drivers/net/wireless/bcmdhd/include/sdiovar.h +++ b/drivers/net/wireless/bcmdhd/include/sdiovar.h @@ -52,6 +52,29 @@ typedef struct sdreg { #define NUM_PREV_TRANSACTIONS 16 +#ifdef BCMSPI +/* Error statistics for gSPI */ +struct spierrstats_t { + uint32 dna; /* The requested data is not available. */ + uint32 rdunderflow; /* FIFO underflow happened due to current (F2, F3) rd command */ + uint32 wroverflow; /* FIFO underflow happened due to current (F1, F2, F3) wr command */ + + uint32 f2interrupt; /* OR of all F2 related intr status bits. */ + uint32 f3interrupt; /* OR of all F3 related intr status bits. */ + + uint32 f2rxnotready; /* F2 FIFO is not ready to receive data (FIFO empty) */ + uint32 f3rxnotready; /* F3 FIFO is not ready to receive data (FIFO empty) */ + + uint32 hostcmddataerr; /* Error in command or host data, detected by CRC/checksum + * (optional) + */ + uint32 f2pktavailable; /* Packet is available in F2 TX FIFO */ + uint32 f3pktavailable; /* Packet is available in F2 TX FIFO */ + + uint32 dstatus[NUM_PREV_TRANSACTIONS]; /* dstatus bits of last 16 gSPI transactions */ + uint32 spicmd[NUM_PREV_TRANSACTIONS]; +}; +#endif /* BCMSPI */ #include diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h index ac52bc1b84e..a797b3d1e71 100644 --- a/drivers/net/wireless/bcmdhd/include/siutils.h +++ b/drivers/net/wireless/bcmdhd/include/siutils.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: siutils.h 321982 2012-03-19 06:58:08Z $ + * $Id: siutils.h 347614 2012-07-27 10:24:51Z $ */ #ifndef _siutils_h_ @@ -125,6 +125,21 @@ typedef void (*gpio_handler_t)(uint32 stat, void *arg); +#define SI_CR4_CAP (0x04) +#define SI_CR4_BANKIDX (0x40) +#define SI_CR4_BANKINFO (0x44) + +#define ARMCR4_TCBBNB_MASK 0xf0 +#define ARMCR4_TCBBNB_SHIFT 4 +#define ARMCR4_TCBANB_MASK 0xf +#define ARMCR4_TCBANB_SHIFT 0 + +#define SICF_CPUHALT (0x0020) +#define ARMCR4_BSZ_MASK 0x3f +#define ARMCR4_BSZ_MULT 8192 + + + extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, void *sdh, char **vars, uint *varsz); extern si_t *si_kattach(osl_t *osh); @@ -310,4 +325,8 @@ extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); char *si_getnvramflvar(si_t *sih, const char *name); +extern uint32 si_tcm_size(si_t *sih); + +extern int si_set_sromctl(si_t *sih, uint32 value); +extern uint32 si_get_sromctl(si_t *sih); #endif diff --git a/drivers/net/wireless/bcmdhd/include/spid.h b/drivers/net/wireless/bcmdhd/include/spid.h index ccae9779cda..6d2d40319e2 100644 --- a/drivers/net/wireless/bcmdhd/include/spid.h +++ b/drivers/net/wireless/bcmdhd/include/spid.h @@ -1,15 +1,27 @@ /* * SPI device spec header file * - * Copyright (C) 2012, Broadcom Corporation - * All Rights Reserved. + * Copyright (C) 1999-2012, Broadcom Corporation * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; - * the contents of this file may not be disclosed to third parties, copied - * or duplicated in any form, in whole or in part, without the prior - * written permission of Broadcom Corporation. + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: * - * $Id: spid.h 241182 2011-02-17 21:50:03Z $ + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: spid.h 354172 2012-08-30 07:19:26Z $ */ #ifndef _SPI_H diff --git a/drivers/net/wireless/bcmdhd/include/usbrdl.h b/drivers/net/wireless/bcmdhd/include/usbrdl.h deleted file mode 100644 index c90dccdcfad..00000000000 --- a/drivers/net/wireless/bcmdhd/include/usbrdl.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Broadcom USB remote download definitions - * - * Copyright (C) 2012, Broadcom Corporation - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; - * the contents of this file may not be disclosed to third parties, copied - * or duplicated in any form, in whole or in part, without the prior - * written permission of Broadcom Corporation. - * - * $Id: usbrdl.h 296577 2011-11-16 03:09:51Z $ - */ - -#ifndef _USB_RDL_H -#define _USB_RDL_H - -/* Control messages: bRequest values */ -#define DL_GETSTATE 0 /* returns the rdl_state_t struct */ -#define DL_CHECK_CRC 1 /* currently unused */ -#define DL_GO 2 /* execute downloaded image */ -#define DL_START 3 /* initialize dl state */ -#define DL_REBOOT 4 /* reboot the device in 2 seconds */ -#define DL_GETVER 5 /* returns the bootrom_id_t struct */ -#define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset event - * to occur in 2 seconds. It is the responsibility - * of the downloaded code to clear this event - */ -#define DL_EXEC 7 /* jump to a supplied address */ -#define DL_RESETCFG 8 /* To support single enum on dongle - * - Not used by bootloader - */ -#define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup - * if resp unavailable - */ - -#define DL_HWCMD_MASK 0xfc /* Mask for hardware read commands: */ -#define DL_RDHW 0x10 /* Read a hardware address (Ctl-in) */ -#define DL_RDHW32 0x10 /* Read a 32 bit word */ -#define DL_RDHW16 0x11 /* Read 16 bits */ -#define DL_RDHW8 0x12 /* Read an 8 bit byte */ -#define DL_WRHW 0x14 /* Write a hardware address (Ctl-out) */ -#define DL_WRHW_BLK 0x13 /* Block write to hardware access */ - -#define DL_CMD_RDHW 1 /* read data from a backplane address */ -#define DL_CMD_WRHW 2 /* write data to a backplane address */ - -#ifndef LINUX_POSTMOGRIFY_REMOVAL -#define DL_JTCONF 0x15 /* Get JTAG configuration (Ctl_in) - * Set JTAG configuration (Ctl-out) - */ -#define DL_JTON 0x16 /* Turn on jtag master (Ctl-in) */ -#define DL_JTOFF 0x17 /* Turn on jtag master (Ctl-in) */ -#define DL_RDRJT 0x18 /* Read a JTAG register (Ctl-in) */ -#define DL_WRJT 0x19 /* Write a hardware address over JTAG (Ctl/Bulk-out) */ -#define DL_WRRJT 0x1a /* Write a JTAG register (Ctl/Bulk-out) */ -#define DL_JTRST 0x1b /* Reset jtag fsm on jtag DUT (Ctl-in) */ - -#define DL_RDJT 0x1c /* Read a hardware address over JTAG (Ctl-in) */ -#define DL_RDJT32 0x1c /* Read 32 bits */ -#define DL_RDJT16 0x1e /* Read 16 bits (sz = 4 - low bits) */ -#define DL_RDJT8 0x1f /* Read 8 bits */ - -#define DL_MRDJT 0x20 /* Multiple read over JTAG (Ctl-out+Bulk-in) */ -#define DL_MRDJT32 0x20 /* M-read 32 bits */ -#define DL_MRDJT16 0x22 /* M-read 16 bits (sz = 4 - low bits) */ -#define DL_MRDJT6 0x23 /* M-read 8 bits */ -#define DL_MRDIJT 0x24 /* M-read over JTAG (Ctl-out+Bulk-in) with auto-increment */ -#define DL_MRDIJT32 0x24 /* M-read 32 bits w/ai */ -#define DL_MRDIJT16 0x26 /* M-read 16 bits w/ai (sz = 4 - low bits) */ -#define DL_MRDIJT8 0x27 /* M-read 8 bits w/ai */ -#define DL_MRDDJT 0x28 /* M-read over JTAG (Ctl-out+Bulk-in) with auto-decrement */ -#define DL_MRDDJT32 0x28 /* M-read 32 bits w/ad */ -#define DL_MRDDJT16 0x2a /* M-read 16 bits w/ad (sz = 4 - low bits) */ -#define DL_MRDDJT8 0x2b /* M-read 8 bits w/ad */ -#define DL_MWRJT 0x2c /* Multiple write over JTAG (Bulk-out) */ -#define DL_MWRIJT 0x2d /* With auto-increment */ -#define DL_MWRDJT 0x2e /* With auto-decrement */ -#define DL_VRDJT 0x2f /* Vector read over JTAG (Bulk-out+Bulk-in) */ -#define DL_VWRJT 0x30 /* Vector write over JTAG (Bulk-out+Bulk-in) */ -#define DL_SCJT 0x31 /* Jtag scan (Bulk-out+Bulk-in) */ - -#define DL_CFRD 0x33 /* Reserved for dmamem use */ -#define DL_CFWR 0x34 /* Reserved for dmamem use */ -#define DL_GET_NVRAM 0x35 /* Query nvram parameter */ - -#define DL_DBGTRIG 0xFF /* Trigger bRequest type to aid debug */ - -#define DL_JTERROR 0x80000000 -#endif /* LINUX_POSTMOGRIFY_REMOVAL */ - -/* states */ -#define DL_WAITING 0 /* waiting to rx first pkt that includes the hdr info */ -#define DL_READY 1 /* hdr was good, waiting for more of the compressed image */ -#define DL_BAD_HDR 2 /* hdr was corrupted */ -#define DL_BAD_CRC 3 /* compressed image was corrupted */ -#define DL_RUNNABLE 4 /* download was successful, waiting for go cmd */ -#define DL_START_FAIL 5 /* failed to initialize correctly */ -#define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM value */ -#define DL_IMAGE_TOOBIG 7 /* download image too big (exceeds DATA_START for rdl) */ - -#define TIMEOUT 5000 /* Timeout for usb commands */ - -struct bcm_device_id { - char *name; - uint32 vend; - uint32 prod; -}; - -typedef struct { - uint32 state; - uint32 bytes; -} rdl_state_t; - -typedef struct { - uint32 chip; /* Chip id */ - uint32 chiprev; /* Chip rev */ - uint32 ramsize; /* Size of RAM */ - uint32 remapbase; /* Current remap base address */ - uint32 boardtype; /* Type of board */ - uint32 boardrev; /* Board revision */ -} bootrom_id_t; - -/* struct for backplane & jtag accesses */ -typedef struct { - uint32 cmd; /* tag to identify the cmd */ - uint32 addr; /* backplane address for write */ - uint32 len; /* length of data: 1, 2, 4 bytes */ - uint32 data; /* data to write */ -} hwacc_t; - -/* struct for backplane */ -typedef struct { - uint32 cmd; /* tag to identify the cmd */ - uint32 addr; /* backplane address for write */ - uint32 len; /* length of data: 1, 2, 4 bytes */ - uint8 data[1]; /* data to write */ -} hwacc_blk_t; - -#ifndef LINUX_POSTMOGRIFY_REMOVAL -typedef struct { - uint32 chip; /* Chip id */ - uint32 chiprev; /* Chip rev */ - uint32 ccrev; /* Chipcommon core rev */ - uint32 siclock; /* Backplane clock */ -} jtagd_id_t; - -/* Jtag configuration structure */ -typedef struct { - uint32 cmd; /* tag to identify the cmd */ - uint8 clkd; /* Jtag clock divisor */ - uint8 disgpio; /* Gpio to disable external driver */ - uint8 irsz; /* IR size for readreg/writereg */ - uint8 drsz; /* DR size for readreg/writereg */ - - uint8 bigend; /* Big endian */ - uint8 mode; /* Current mode */ - uint16 delay; /* Delay between jtagm "simple commands" */ - - uint32 retries; /* Number of retries for jtagm operations */ - uint32 ctrl; /* Jtag control reg copy */ - uint32 ir_lvbase; /* Bits to add to IR values in LV tap */ - uint32 dretries; /* Number of retries for dma operations */ -} jtagconf_t; - -/* struct for jtag scan */ -#define MAX_USB_IR_BITS 256 -#define MAX_USB_DR_BITS 3072 -#define USB_IR_WORDS (MAX_USB_IR_BITS / 32) -#define USB_DR_WORDS (MAX_USB_DR_BITS / 32) -typedef struct { - uint32 cmd; /* tag to identify the cmd */ - uint32 irsz; /* IR size in bits */ - uint32 drsz; /* DR size in bits */ - uint32 ts; /* Terminal state (def, pause, rti) */ - uint32 data[USB_IR_WORDS + USB_DR_WORDS]; /* IR & DR data */ -} scjt_t; -#endif /* LINUX_POSTMOGRIFY_REMOVAL */ - -/* struct for querying nvram params from bootloader */ -#define QUERY_STRING_MAX 32 -typedef struct { - uint32 cmd; /* tag to identify the cmd */ - char var[QUERY_STRING_MAX]; /* param name */ -} nvparam_t; - -typedef void (*exec_fn_t)(void *sih); - -#define USB_CTRL_IN (USB_TYPE_VENDOR | 0x80 | USB_RECIP_INTERFACE) -#define USB_CTRL_OUT (USB_TYPE_VENDOR | 0 | USB_RECIP_INTERFACE) - -#define USB_CTRL_EP_TIMEOUT 500 /* Timeout used in USB control_msg transactions. */ - -#define RDL_CHUNK 1500 /* size of each dl transfer */ - -/* bootloader makes special use of trx header "offsets" array */ -#define TRX_OFFSETS_DLFWLEN_IDX 0 /* Size of the fw; used in uncompressed case */ -#define TRX_OFFSETS_JUMPTO_IDX 1 /* RAM address for jumpto after download */ -#define TRX_OFFSETS_NVM_LEN_IDX 2 /* Length of appended NVRAM data */ - -#define TRX_OFFSETS_DLBASE_IDX 0 /* RAM start address for download */ - -#endif /* _USB_RDL_H */ diff --git a/drivers/net/wireless/bcmdhd/include/wlc_clm_rates.h b/drivers/net/wireless/bcmdhd/include/wlc_clm_rates.h deleted file mode 100644 index d9061bb8c5d..00000000000 --- a/drivers/net/wireless/bcmdhd/include/wlc_clm_rates.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates - * Copyright (C) 2012, Broadcom Corporation - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; - * the contents of this file may not be disclosed to third parties, copied - * or duplicated in any form, in whole or in part, without the prior - * written permission of Broadcom Corporation. - * - * $Id: wlc_clm_rates.h 252708 2011-04-12 06:45:56Z $ - */ - -#ifndef _WLC_CLM_RATES_H_ -#define _WLC_CLM_RATES_H_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef enum clm_rates { - /************ - * 1 chain * - ************ - */ - - /* 1 Stream */ - CLM_RATE_1X1_DSSS_1 = 0, - CLM_RATE_1X1_DSSS_2 = 1, - CLM_RATE_1X1_DSSS_5_5 = 2, - CLM_RATE_1X1_DSSS_11 = 3, - - CLM_RATE_1X1_OFDM_6 = 4, - CLM_RATE_1X1_OFDM_9 = 5, - CLM_RATE_1X1_OFDM_12 = 6, - CLM_RATE_1X1_OFDM_18 = 7, - CLM_RATE_1X1_OFDM_24 = 8, - CLM_RATE_1X1_OFDM_36 = 9, - CLM_RATE_1X1_OFDM_48 = 10, - CLM_RATE_1X1_OFDM_54 = 11, - - CLM_RATE_1X1_MCS0 = 12, - CLM_RATE_1X1_MCS1 = 13, - CLM_RATE_1X1_MCS2 = 14, - CLM_RATE_1X1_MCS3 = 15, - CLM_RATE_1X1_MCS4 = 16, - CLM_RATE_1X1_MCS5 = 17, - CLM_RATE_1X1_MCS6 = 18, - CLM_RATE_1X1_MCS7 = 19, - - CLM_RATE_1X1_VHT0SS1 = 12, - CLM_RATE_1X1_VHT1SS1 = 13, - CLM_RATE_1X1_VHT2SS1 = 14, - CLM_RATE_1X1_VHT3SS1 = 15, - CLM_RATE_1X1_VHT4SS1 = 16, - CLM_RATE_1X1_VHT5SS1 = 17, - CLM_RATE_1X1_VHT6SS1 = 18, - CLM_RATE_1X1_VHT7SS1 = 19, - CLM_RATE_1X1_VHT8SS1 = 20, - CLM_RATE_1X1_VHT9SS1 = 21, - - - /************ - * 2 chains * - ************ - */ - - /* 1 Stream expanded + 1 */ - CLM_RATE_1X2_DSSS_1 = 22, - CLM_RATE_1X2_DSSS_2 = 23, - CLM_RATE_1X2_DSSS_5_5 = 24, - CLM_RATE_1X2_DSSS_11 = 25, - - CLM_RATE_1X2_CDD_OFDM_6 = 26, - CLM_RATE_1X2_CDD_OFDM_9 = 27, - CLM_RATE_1X2_CDD_OFDM_12 = 28, - CLM_RATE_1X2_CDD_OFDM_18 = 29, - CLM_RATE_1X2_CDD_OFDM_24 = 30, - CLM_RATE_1X2_CDD_OFDM_36 = 31, - CLM_RATE_1X2_CDD_OFDM_48 = 32, - CLM_RATE_1X2_CDD_OFDM_54 = 33, - - CLM_RATE_1X2_CDD_MCS0 = 34, - CLM_RATE_1X2_CDD_MCS1 = 35, - CLM_RATE_1X2_CDD_MCS2 = 36, - CLM_RATE_1X2_CDD_MCS3 = 37, - CLM_RATE_1X2_CDD_MCS4 = 38, - CLM_RATE_1X2_CDD_MCS5 = 39, - CLM_RATE_1X2_CDD_MCS6 = 40, - CLM_RATE_1X2_CDD_MCS7 = 41, - - CLM_RATE_1X2_VHT0SS1 = 34, - CLM_RATE_1X2_VHT1SS1 = 35, - CLM_RATE_1X2_VHT2SS1 = 36, - CLM_RATE_1X2_VHT3SS1 = 37, - CLM_RATE_1X2_VHT4SS1 = 38, - CLM_RATE_1X2_VHT5SS1 = 39, - CLM_RATE_1X2_VHT6SS1 = 40, - CLM_RATE_1X2_VHT7SS1 = 41, - CLM_RATE_1X2_VHT8SS1 = 42, - CLM_RATE_1X2_VHT9SS1 = 43, - - /* 2 Streams */ - CLM_RATE_2X2_STBC_MCS0 = 44, - CLM_RATE_2X2_STBC_MCS1 = 45, - CLM_RATE_2X2_STBC_MCS2 = 46, - CLM_RATE_2X2_STBC_MCS3 = 47, - CLM_RATE_2X2_STBC_MCS4 = 48, - CLM_RATE_2X2_STBC_MCS5 = 49, - CLM_RATE_2X2_STBC_MCS6 = 50, - CLM_RATE_2X2_STBC_MCS7 = 51, - - CLM_RATE_2X2_STBC_VHT0SS1 = 44, - CLM_RATE_2X2_STBC_VHT1SS1 = 45, - CLM_RATE_2X2_STBC_VHT2SS1 = 46, - CLM_RATE_2X2_STBC_VHT3SS1 = 47, - CLM_RATE_2X2_STBC_VHT4SS1 = 48, - CLM_RATE_2X2_STBC_VHT5SS1 = 49, - CLM_RATE_2X2_STBC_VHT6SS1 = 50, - CLM_RATE_2X2_STBC_VHT7SS1 = 51, - CLM_RATE_2X2_STBC_VHT8SS1 = 52, - CLM_RATE_2X2_STBC_VHT9SS1 = 53, - - CLM_RATE_2X2_SDM_MCS8 = 54, - CLM_RATE_2X2_SDM_MCS9 = 55, - CLM_RATE_2X2_SDM_MCS10 = 56, - CLM_RATE_2X2_SDM_MCS11 = 57, - CLM_RATE_2X2_SDM_MCS12 = 58, - CLM_RATE_2X2_SDM_MCS13 = 59, - CLM_RATE_2X2_SDM_MCS14 = 60, - CLM_RATE_2X2_SDM_MCS15 = 61, - - CLM_RATE_2X2_VHT0SS2 = 54, - CLM_RATE_2X2_VHT1SS2 = 55, - CLM_RATE_2X2_VHT2SS2 = 56, - CLM_RATE_2X2_VHT3SS2 = 57, - CLM_RATE_2X2_VHT4SS2 = 58, - CLM_RATE_2X2_VHT5SS2 = 59, - CLM_RATE_2X2_VHT6SS2 = 60, - CLM_RATE_2X2_VHT7SS2 = 61, - CLM_RATE_2X2_VHT8SS2 = 62, - CLM_RATE_2X2_VHT9SS2 = 63, - - - /************ - * 3 chains * - ************ - */ - - /* 1 Stream expanded + 2 */ - CLM_RATE_1X3_DSSS_1 = 64, - CLM_RATE_1X3_DSSS_2 = 65, - CLM_RATE_1X3_DSSS_5_5 = 66, - CLM_RATE_1X3_DSSS_11 = 67, - - CLM_RATE_1X3_CDD_OFDM_6 = 68, - CLM_RATE_1X3_CDD_OFDM_9 = 69, - CLM_RATE_1X3_CDD_OFDM_12 = 70, - CLM_RATE_1X3_CDD_OFDM_18 = 71, - CLM_RATE_1X3_CDD_OFDM_24 = 72, - CLM_RATE_1X3_CDD_OFDM_36 = 73, - CLM_RATE_1X3_CDD_OFDM_48 = 74, - CLM_RATE_1X3_CDD_OFDM_54 = 75, - - CLM_RATE_1X3_CDD_MCS0 = 76, - CLM_RATE_1X3_CDD_MCS1 = 77, - CLM_RATE_1X3_CDD_MCS2 = 78, - CLM_RATE_1X3_CDD_MCS3 = 79, - CLM_RATE_1X3_CDD_MCS4 = 80, - CLM_RATE_1X3_CDD_MCS5 = 81, - CLM_RATE_1X3_CDD_MCS6 = 82, - CLM_RATE_1X3_CDD_MCS7 = 83, - - CLM_RATE_1X3_VHT0SS1 = 76, - CLM_RATE_1X3_VHT1SS1 = 77, - CLM_RATE_1X3_VHT2SS1 = 78, - CLM_RATE_1X3_VHT3SS1 = 79, - CLM_RATE_1X3_VHT4SS1 = 80, - CLM_RATE_1X3_VHT5SS1 = 81, - CLM_RATE_1X3_VHT6SS1 = 82, - CLM_RATE_1X3_VHT7SS1 = 83, - CLM_RATE_1X3_VHT8SS1 = 84, - CLM_RATE_1X3_VHT9SS1 = 85, - - /* 2 Streams expanded + 1 */ - CLM_RATE_2X3_STBC_MCS0 = 86, - CLM_RATE_2X3_STBC_MCS1 = 87, - CLM_RATE_2X3_STBC_MCS2 = 88, - CLM_RATE_2X3_STBC_MCS3 = 89, - CLM_RATE_2X3_STBC_MCS4 = 90, - CLM_RATE_2X3_STBC_MCS5 = 91, - CLM_RATE_2X3_STBC_MCS6 = 92, - CLM_RATE_2X3_STBC_MCS7 = 93, - - CLM_RATE_2X3_STBC_VHT0SS1 = 86, - CLM_RATE_2X3_STBC_VHT1SS1 = 87, - CLM_RATE_2X3_STBC_VHT2SS1 = 88, - CLM_RATE_2X3_STBC_VHT3SS1 = 89, - CLM_RATE_2X3_STBC_VHT4SS1 = 90, - CLM_RATE_2X3_STBC_VHT5SS1 = 91, - CLM_RATE_2X3_STBC_VHT6SS1 = 92, - CLM_RATE_2X3_STBC_VHT7SS1 = 93, - CLM_RATE_2X3_STBC_VHT8SS1 = 94, - CLM_RATE_2X3_STBC_VHT9SS1 = 95, - - CLM_RATE_2X3_SDM_MCS8 = 96, - CLM_RATE_2X3_SDM_MCS9 = 97, - CLM_RATE_2X3_SDM_MCS10 = 98, - CLM_RATE_2X3_SDM_MCS11 = 99, - CLM_RATE_2X3_SDM_MCS12 = 100, - CLM_RATE_2X3_SDM_MCS13 = 101, - CLM_RATE_2X3_SDM_MCS14 = 102, - CLM_RATE_2X3_SDM_MCS15 = 103, - - CLM_RATE_2X3_VHT0SS2 = 96, - CLM_RATE_2X3_VHT1SS2 = 97, - CLM_RATE_2X3_VHT2SS2 = 98, - CLM_RATE_2X3_VHT3SS2 = 99, - CLM_RATE_2X3_VHT4SS2 = 100, - CLM_RATE_2X3_VHT5SS2 = 101, - CLM_RATE_2X3_VHT6SS2 = 102, - CLM_RATE_2X3_VHT7SS2 = 103, - CLM_RATE_2X3_VHT8SS2 = 104, - CLM_RATE_2X3_VHT9SS2 = 105, - - /* 3 Streams */ - CLM_RATE_3X3_SDM_MCS16 = 106, - CLM_RATE_3X3_SDM_MCS17 = 107, - CLM_RATE_3X3_SDM_MCS18 = 108, - CLM_RATE_3X3_SDM_MCS19 = 109, - CLM_RATE_3X3_SDM_MCS20 = 110, - CLM_RATE_3X3_SDM_MCS21 = 111, - CLM_RATE_3X3_SDM_MCS22 = 112, - CLM_RATE_3X3_SDM_MCS23 = 113, - - CLM_RATE_3X3_VHT0SS3 = 106, - CLM_RATE_3X3_VHT1SS3 = 107, - CLM_RATE_3X3_VHT2SS3 = 108, - CLM_RATE_3X3_VHT3SS3 = 109, - CLM_RATE_3X3_VHT4SS3 = 110, - CLM_RATE_3X3_VHT5SS3 = 111, - CLM_RATE_3X3_VHT6SS3 = 112, - CLM_RATE_3X3_VHT7SS3 = 113, - CLM_RATE_3X3_VHT8SS3 = 114, - CLM_RATE_3X3_VHT9SS3 = 115, - - /* Number of rate codes */ - CLM_NUMRATES = 116, - } clm_rates_t; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* _WLC_CLM_RATES_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/wlc_extlog_idstr.h b/drivers/net/wireless/bcmdhd/include/wlc_extlog_idstr.h deleted file mode 100644 index 95f616a5fc7..00000000000 --- a/drivers/net/wireless/bcmdhd/include/wlc_extlog_idstr.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * EXTLOG Module log ID to log Format String mapping table - * - * Copyright (C) 2012, Broadcom Corporation - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; - * the contents of this file may not be disclosed to third parties, copied - * or duplicated in any form, in whole or in part, without the prior - * written permission of Broadcom Corporation. - * - * $Id: wlc_extlog_idstr.h 241182 2011-02-17 21:50:03Z $ - */ -#ifndef _WLC_EXTLOG_IDSTR_H_ -#define _WLC_EXTLOG_IDSTR_H_ - -#include "wlioctl.h" - -/* Strings corresponding to the IDs defined in wlioctl.h - * This file is only included by the apps and not included by the external driver - * Formats of pre-existing ids should NOT be changed - */ -log_idstr_t extlog_fmt_str[ ] = { - {FMTSTR_DRIVER_UP_ID, 0, LOG_ARGTYPE_NULL, - "Driver is Up\n"}, - - {FMTSTR_DRIVER_DOWN_ID, 0, LOG_ARGTYPE_NULL, - "Driver is Down\n"}, - - {FMTSTR_SUSPEND_MAC_FAIL_ID, 0, LOG_ARGTYPE_INT, - "wlc_suspend_mac_and_wait() failed with psmdebug 0x%08x\n"}, - - {FMTSTR_NO_PROGRESS_ID, 0, LOG_ARGTYPE_INT, - "No Progress on TX for %d seconds\n"}, - - {FMTSTR_RFDISABLE_ID, 0, LOG_ARGTYPE_INT, - "Detected a change in RF Disable Input 0x%x\n"}, - - {FMTSTR_REG_PRINT_ID, 0, LOG_ARGTYPE_STR_INT, - "Register %s = 0x%x\n"}, - - {FMTSTR_EXPTIME_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Strong RF interference detected\n"}, - - {FMTSTR_JOIN_START_ID, FMTSTRF_USER, LOG_ARGTYPE_STR, - "Searching for networks with ssid %s\n"}, - - {FMTSTR_JOIN_COMPLETE_ID, FMTSTRF_USER, LOG_ARGTYPE_STR, - "Successfully joined network with BSSID %s\n"}, - - {FMTSTR_NO_NETWORKS_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "No networks found. Please check if the network exists and is in range\n"}, - - {FMTSTR_SECURITY_MISMATCH_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "AP rejected due to security mismatch. Change the security settings and try again...\n"}, - - {FMTSTR_RATE_MISMATCH_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "AP rejected due to rate mismatch\n"}, - - {FMTSTR_AP_PRUNED_ID, 0, LOG_ARGTYPE_INT, - "AP rejected due to reason %d\n"}, - - {FMTSTR_KEY_INSERTED_ID, 0, LOG_ARGTYPE_INT, - "Inserting keys for algorithm %d\n"}, - - {FMTSTR_DEAUTH_ID, FMTSTRF_USER, LOG_ARGTYPE_STR_INT, - "Received Deauth from %s with Reason %d\n"}, - - {FMTSTR_DISASSOC_ID, FMTSTRF_USER, LOG_ARGTYPE_STR_INT, - "Received Disassoc from %s with Reason %d\n"}, - - {FMTSTR_LINK_UP_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Link Up\n"}, - - {FMTSTR_LINK_DOWN_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Link Down\n"}, - - {FMTSTR_RADIO_HW_OFF_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Radio button is turned OFF. Please turn it on...\n"}, - - {FMTSTR_RADIO_HW_ON_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Hardware Radio button is turned ON\n"}, - - {FMTSTR_EVENT_DESC_ID, 0, LOG_ARGTYPE_INT_STR, - "Generated event id %d: (result status) is (%s)\n"}, - - {FMTSTR_PNP_SET_POWER_ID, 0, LOG_ARGTYPE_INT, - "Device going into power state %d\n"}, - - {FMTSTR_RADIO_SW_OFF_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Software Radio is disabled. Please enable it through the UI...\n"}, - - {FMTSTR_RADIO_SW_ON_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Software Radio is enabled\n"}, - - {FMTSTR_PWD_MISMATCH_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Potential passphrase mismatch. Please try a different one...\n"}, - - {FMTSTR_FATAL_ERROR_ID, 0, LOG_ARGTYPE_INT, - "Fatal Error: intstatus 0x%x\n"}, - - {FMTSTR_AUTH_FAIL_ID, 0, LOG_ARGTYPE_STR_INT, - "Authentication to %s Failed with status %d\n"}, - - {FMTSTR_ASSOC_FAIL_ID, 0, LOG_ARGTYPE_STR_INT, - "Association to %s Failed with status %d\n"}, - - {FMTSTR_IBSS_FAIL_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Unable to start IBSS since PeerNet is already active\n"}, - - {FMTSTR_EXTAP_FAIL_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, - "Unable to start Ext-AP since PeerNet is already active\n"}, - - {FMTSTR_MAX_ID, 0, 0, "\0"} -}; - -#endif /* _WLC_EXTLOG_IDSTR_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h index 82f29d1b14f..1c8cc018dda 100644 --- a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h +++ b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h @@ -18,7 +18,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. -* $Id: wlfc_proto.h 328114 2012-04-18 00:02:46Z $ +* $Id: wlfc_proto.h 347585 2012-07-27 09:02:53Z $ * */ #ifndef __wlfc_proto_definitions_h__ @@ -96,6 +96,7 @@ #define WLFC_CTL_TYPE_NIC_PRD_START 15 #define WLFC_CTL_TYPE_NIC_PRD_END 16 #define WLFC_CTL_TYPE_AF_TXS 17 +#define WLFC_CTL_TYPE_TRANS_ID 18 #define WLFC_CTL_TYPE_FILLER 255 @@ -225,5 +226,7 @@ #define WLHOST_REORDERDATA_CURIDX_VALID 0x04 #define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 #define WLHOST_REORDERDATA_NEW_HOLE 0x10 +/* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ +#define WLFC_CTL_TRANS_ID_LEN 6 #endif /* __wlfc_proto_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index c25f7944c0e..33811a17f5c 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wlioctl.h 328096 2012-04-17 23:07:20Z $ + * $Id: wlioctl.h 357627 2012-09-19 12:42:22Z $ */ #ifndef _wlioctl_h_ @@ -43,6 +43,8 @@ #include #endif /* LINUX_POSTMOGRIFY_REMOVAL */ +#include + /* LINUX_POSTMOGRIFY_REMOVAL: undefined during compile phase, so its * a no-op for most cases. For hybrid and other open source releases, * its defined during a second pass and mogrified out for distribution. @@ -822,6 +824,29 @@ typedef struct wl_rm_rep { } wl_rm_rep_t; #define WL_RM_REP_FIXED_LEN 8 +#ifdef BCMCCX + +#define LEAP_USER_MAX 32 +#define LEAP_DOMAIN_MAX 32 +#define LEAP_PASSWORD_MAX 32 + +typedef struct wl_leap_info { + wlc_ssid_t ssid; + uint8 user_len; + uchar user[LEAP_USER_MAX]; + uint8 password_len; + uchar password[LEAP_PASSWORD_MAX]; + uint8 domain_len; + uchar domain[LEAP_DOMAIN_MAX]; +} wl_leap_info_t; + +typedef struct wl_leap_list { + uint32 buflen; + uint32 version; + uint32 count; + wl_leap_info_t leap_info[1]; +} wl_leap_list_t; +#endif /* BCMCCX */ typedef enum sup_auth_status { /* Basic supplicant authentication states */ @@ -856,7 +881,14 @@ typedef enum sup_auth_status { #define CRYPTO_ALGO_AES_CCM 4 #define CRYPTO_ALGO_AES_OCB_MSDU 5 #define CRYPTO_ALGO_AES_OCB_MPDU 6 +#if !defined(BCMCCX) #define CRYPTO_ALGO_NALG 7 +#else +#define CRYPTO_ALGO_CKIP 7 +#define CRYPTO_ALGO_CKIP_MMH 8 +#define CRYPTO_ALGO_WEP_MMH 9 +#define CRYPTO_ALGO_NALG 10 +#endif #ifdef BCMWAPI_WPI #define CRYPTO_ALGO_SMS4 11 #endif /* BCMWAPI_WPI */ @@ -871,8 +903,13 @@ typedef enum sup_auth_status { #define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ #define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ +#if defined(BCMCCX) +#define WL_CKIP_KP (1 << 4) /* CMIC */ +#define WL_CKIP_MMH (1 << 5) /* CKIP */ +#else #define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ #define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ +#endif #define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ typedef struct wl_wsec_key { @@ -913,6 +950,10 @@ typedef struct { #define TKIP_ENABLED 0x0002 #define AES_ENABLED 0x0004 #define WSEC_SWFLAG 0x0008 +#ifdef BCMCCX +#define CKIP_KP_ENABLED 0x0010 +#define CKIP_MIC_ENABLED 0x0020 +#endif /* BCMCCX */ #define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */ #ifdef BCMWAPI_WPI #define SMS4_ENABLED 0x0100 @@ -923,11 +964,27 @@ typedef struct { #define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) #define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) +#ifdef BCMCCX +#define WSEC_CKIP_KP_ENABLED(wsec) ((wsec) & CKIP_KP_ENABLED) +#define WSEC_CKIP_MIC_ENABLED(wsec) ((wsec) & CKIP_MIC_ENABLED) +#define WSEC_CKIP_ENABLED(wsec) ((wsec) & (CKIP_KP_ENABLED|CKIP_MIC_ENABLED)) + +#ifdef BCMWAPI_WPI +#define WSEC_ENABLED(wsec) \ + ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | \ + CKIP_MIC_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define WSEC_ENABLED(wsec) \ + ((wsec) & \ + (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | CKIP_MIC_ENABLED)) +#endif /* BCMWAPI_WPI */ +#else /* defined BCMCCX */ #ifdef BCMWAPI_WPI #define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) #else /* BCMWAPI_WPI */ #define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) #endif /* BCMWAPI_WPI */ +#endif /* BCMCCX */ #define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) #ifdef BCMWAPI_WAI #define WSEC_SMS4_ENABLED(wsec) ((wsec) & SMS4_ENABLED) @@ -944,6 +1001,10 @@ typedef struct { #define WPA_AUTH_NONE 0x0001 /* none (IBSS) */ #define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */ #define WPA_AUTH_PSK 0x0004 /* Pre-shared key */ +#if defined(BCMCCX) +#define WPA_AUTH_CCKM 0x0008 /* CCKM */ +#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ +#endif /* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ #define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ #define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ @@ -1715,7 +1776,15 @@ typedef struct { /* WLC_GET_AUTH, WLC_SET_AUTH values */ #define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ #define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ -#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ +#ifdef BCM4330_CHIP +#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ +#else +/* BCM4334(Phoenex branch) value changed to 3 */ +#define WL_AUTH_OPEN_SHARED 3 /* try open, then shared if open failed w/rc 13 */ +#endif +#ifdef USE_WEP_AUTH_SHARED_OPEN +#define WL_AUTH_SHARED_OPEN 4 /* try shared, then open if shared failed w/rc 13 */ +#endif /* USE_WEP_AUTH_SHARED_OPEN */ #endif /* LINUX_POSTMOGRIFY_REMOVAL */ /* Bit masks for radio disabled status - returned by WL_GET_RADIO */ @@ -1913,6 +1982,10 @@ typedef struct wl_po { /* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ #define WLC_SGI_ALL 0x02 +#define DHD_SCAN_ACTIVE_TIME 40 /* ms : Embedded default Active setting from DHD */ +#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms : def. Unassoc Active setting from DHD */ +#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ + #define LISTEN_INTERVAL 10 /* interference mitigation options */ #define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ @@ -1923,6 +1996,12 @@ typedef struct wl_po { #define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ #define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ +/* AP environment */ +#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ +#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ +#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ +#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ + typedef struct wl_aci_args { int enter_aci_thresh; /* Trigger level to start detecting ACI */ int exit_aci_thresh; /* Trigger level to exit ACI mode */ @@ -3612,6 +3691,13 @@ typedef struct wme_max_bandwidth { #define TSPEC_UNKNOWN 3 /* TSPEC unknown */ #define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ +#ifdef BCMCCX +/* "wlan_reason" iovar interface */ +#define WL_WLAN_ASSOC_REASON_NORMAL_NETWORK 0 /* normal WLAN network setup */ +#define WL_WLAN_ASSOC_REASON_ROAM_FROM_CELLULAR_NETWORK 1 /* roam from Cellular network */ +#define WL_WLAN_ASSOC_REASON_ROAM_FROM_LAN 2 /* roam from LAN */ +#define WL_WLAN_ASSOC_REASON_MAX 2 /* largest value allowed */ +#endif /* BCMCCX */ /* Software feature flag defines used by wlfeatureflag */ #ifdef WLAFTERBURNER diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c index ef9c733742a..d03a095f5fe 100644 --- a/drivers/net/wireless/bcmdhd/linux_osl.c +++ b/drivers/net/wireless/bcmdhd/linux_osl.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linux_osl.c 311099 2012-01-27 14:46:59Z $ + * $Id: linux_osl.c 355147 2012-09-05 15:03:49Z $ */ #define LINUX_PORT @@ -48,6 +48,11 @@ #define BCM_MEM_FILENAME_LEN 24 #ifdef CONFIG_DHD_USE_STATIC_BUF +#define DHD_SKB_HDRSIZE 336 +#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) +#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) +#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) + #define STATIC_BUF_MAX_NUM 16 #define STATIC_BUF_SIZE (PAGE_SIZE*2) #define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) @@ -61,12 +66,22 @@ typedef struct bcm_static_buf { static bcm_static_buf_t *bcm_static_buf = 0; #define STATIC_PKT_MAX_NUM 8 +#if defined(ENHANCED_STATIC_BUF) +#define STATIC_PKT_4PAGE_NUM 1 +#define DHD_SKB_MAX_BUFSIZE DHD_SKB_4PAGE_BUFSIZE +#else +#define STATIC_PKT_4PAGE_NUM 0 +#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE +#endif typedef struct bcm_static_pkt { struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM]; struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM]; +#ifdef ENHANCED_STATIC_BUF + struct sk_buff *skb_16k; +#endif struct semaphore osl_pkt_sem; - unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2]; + unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM]; } bcm_static_pkt_t; static bcm_static_pkt_t *bcm_static_skb = 0; @@ -173,8 +188,15 @@ osl_t * osl_attach(void *pdev, uint bustype, bool pkttag) { osl_t *osh; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + gfp_t flags; + flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; + osh = kmalloc(sizeof(osl_t), flags); +#else osh = kmalloc(sizeof(osl_t), GFP_ATOMIC); +#endif + ASSERT(osh); bzero(osh, sizeof(osl_t)); @@ -230,8 +252,9 @@ osl_attach(void *pdev, uint bustype, bool pkttag) bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); - bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16); - for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++) + bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)* + (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM)); + for (i = 0; i < (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM); i++) bcm_static_skb->pkt_use[i] = 0; sema_init(&bcm_static_skb->osl_pkt_sem, 1); @@ -265,7 +288,7 @@ osl_detach(osl_t *osh) static struct sk_buff *osl_alloc_skb(unsigned int len) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) - gfp_t flags = GFP_ATOMIC; + gfp_t flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; return __dev_alloc_skb(len, flags); #else @@ -347,7 +370,14 @@ osl_ctfpool_replenish(osl_t *osh, uint thresh) int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + gfp_t flags; + + flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; + osh->ctfpool = kmalloc(sizeof(ctfpool_t), flags); +#else osh->ctfpool = kmalloc(sizeof(ctfpool_t), GFP_ATOMIC); +#endif ASSERT(osh->ctfpool); bzero(osh->ctfpool, sizeof(ctfpool_t)); @@ -631,14 +661,16 @@ osl_pktget_static(osl_t *osh, uint len) int i = 0; struct sk_buff *skb; - if (len > (PAGE_SIZE*2)) { - printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len); + + if (len > DHD_SKB_MAX_BUFSIZE) { + printk("osl_pktget_static: Do we really need this big skb??" + " len=%d\n", len); return osl_pktget(osh, len); } down(&bcm_static_skb->osl_pkt_sem); - if (len <= PAGE_SIZE) { + if (len <= DHD_SKB_1PAGE_BUFSIZE) { for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { if (bcm_static_skb->pkt_use[i] == 0) break; @@ -646,31 +678,50 @@ osl_pktget_static(osl_t *osh, uint len) if (i != STATIC_PKT_MAX_NUM) { bcm_static_skb->pkt_use[i] = 1; - up(&bcm_static_skb->osl_pkt_sem); + skb = bcm_static_skb->skb_4k[i]; skb->tail = skb->data + len; skb->len = len; + + up(&bcm_static_skb->osl_pkt_sem); return skb; } } + if (len <= DHD_SKB_2PAGE_BUFSIZE) { - for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { - if (bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] == 0) - break; + for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { + if (bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] + == 0) + break; + } + + if (i != STATIC_PKT_MAX_NUM) { + bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 1; + skb = bcm_static_skb->skb_8k[i]; + skb->tail = skb->data + len; + skb->len = len; + + up(&bcm_static_skb->osl_pkt_sem); + return skb; + } } - if (i != STATIC_PKT_MAX_NUM) { - bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] = 1; - up(&bcm_static_skb->osl_pkt_sem); - skb = bcm_static_skb->skb_8k[i]; +#if defined(ENHANCED_STATIC_BUF) + if (bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] == 0) { + bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 1; + + skb = bcm_static_skb->skb_16k; skb->tail = skb->data + len; skb->len = len; + + up(&bcm_static_skb->osl_pkt_sem); return skb; } +#endif up(&bcm_static_skb->osl_pkt_sem); - printk("%s: all static pkt in use!\n", __FUNCTION__); + printk("osl_pktget_static: all static pkt in use!\n"); return osl_pktget(osh, len); } @@ -678,10 +729,14 @@ void osl_pktfree_static(osl_t *osh, void *p, bool send) { int i; + if (!bcm_static_skb) { + osl_pktfree(osh, p, send); + return; + } + down(&bcm_static_skb->osl_pkt_sem); for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { if (p == bcm_static_skb->skb_4k[i]) { - down(&bcm_static_skb->osl_pkt_sem); bcm_static_skb->pkt_use[i] = 0; up(&bcm_static_skb->osl_pkt_sem); return; @@ -690,14 +745,22 @@ osl_pktfree_static(osl_t *osh, void *p, bool send) for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { if (p == bcm_static_skb->skb_8k[i]) { - down(&bcm_static_skb->osl_pkt_sem); bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0; up(&bcm_static_skb->osl_pkt_sem); return; } } +#ifdef ENHANCED_STATIC_BUF + if (p == bcm_static_skb->skb_16k) { + bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM*2] = 0; + up(&bcm_static_skb->osl_pkt_sem); + return; + } +#endif + up(&bcm_static_skb->osl_pkt_sem); - return osl_pktfree(osh, p, send); + osl_pktfree(osh, p, send); + return; } #endif @@ -790,6 +853,9 @@ void * osl_malloc(osl_t *osh, uint size) { void *addr; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + gfp_t flags; +#endif if (osh) @@ -829,7 +895,12 @@ osl_malloc(osl_t *osh, uint size) original: #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; + if ((addr = kmalloc(size, flags)) == NULL) { +#else if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { +#endif if (osh) osh->failed++; return (NULL); @@ -979,11 +1050,19 @@ osl_pktdup(osl_t *osh, void *skb) { void * p; unsigned long irqflags; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + gfp_t flags; +#endif PKTCTFMAP(osh, skb); - if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; + if ((p = skb_clone((struct sk_buff *)skb, flags)) == NULL) +#else + if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL) +#endif return NULL; #ifdef CTFPOOL diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c index dcd0e389bb7..db108b8c4b2 100644 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd/siutils.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: siutils.c 328733 2012-04-20 14:49:55Z $ + * $Id: siutils.c 347632 2012-07-27 11:00:35Z $ */ #include @@ -44,6 +44,9 @@ #include #include #include +#ifdef BCMSPI +#include +#endif /* BCMSPI */ #include "siutils_priv.h" @@ -106,7 +109,7 @@ si_kattach(osl_t *osh) static bool ksii_attached = FALSE; if (!ksii_attached) { - void *regs; + void *regs = NULL; regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, @@ -176,6 +179,24 @@ si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); } +#ifdef BCMSPI + /* Avoid backplane accesses before wake-wlan (i.e. htavail) for spi. + * F1 read accesses may return correct data but with data-not-available dstatus bit set. + */ + if (BUSTYPE(bustype) == SPI_BUS) { + + int err; + uint32 regdata; + /* wake up wlan function :WAKE_UP goes as HT_AVAIL request in hardware */ + regdata = bcmsdh_cfg_read_word(sdh, SDIO_FUNC_0, SPID_CONFIG, NULL); + SI_MSG(("F0 REG0 rd = 0x%x\n", regdata)); + regdata |= WAKE_UP; + + bcmsdh_cfg_write_word(sdh, SDIO_FUNC_0, SPID_CONFIG, regdata, &err); + + OSL_DELAY(100000); + } +#endif /* BCMSPI */ return TRUE; } @@ -1927,6 +1948,70 @@ si_socram_size(si_t *sih) return memsize; } + +/* Return the TCM-RAM size of the ARMCR4 core. */ +uint32 +si_tcm_size(si_t *sih) +{ + si_info_t *sii; + uint origidx; + uint intr_val = 0; + uint8 *regs; + bool wasup; + uint32 corecap; + uint memsize = 0; + uint32 nab = 0; + uint32 nbb = 0; + uint32 totb = 0; + uint32 bxinfo = 0; + uint32 idx = 0; + uint32 *arm_cap_reg; + uint32 *arm_bidx; + uint32 *arm_binfo; + + sii = SI_INFO(sih); + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to CR4 core */ + if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0))) + goto done; + + /* Get info for determining size. If in reset, come out of reset, + * but remain in halt + */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT); + + arm_cap_reg = (uint32 *)(regs + SI_CR4_CAP); + corecap = R_REG(sii->osh, arm_cap_reg); + + nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; + nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; + totb = nab + nbb; + + arm_bidx = (uint32 *)(regs + SI_CR4_BANKIDX); + arm_binfo = (uint32 *)(regs + SI_CR4_BANKINFO); + for (idx = 0; idx < totb; idx++) { + W_REG(sii->osh, arm_bidx, idx); + + bxinfo = R_REG(sii->osh, arm_binfo); + memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + uint32 si_socram_srmem_size(si_t *sih) { @@ -2344,6 +2429,9 @@ si_is_sprom_available(si_t *sih) case BCM4324_CHIP_ID: return ((sih->chipst & CST4324_SPROM_MASK) && !(sih->chipst & CST4324_SFLASH_MASK)); + case BCM4335_CHIP_ID: + return ((sih->chipst & CST4335_SPROM_MASK) && + !(sih->chipst & CST4335_SFLASH_MASK)); case BCM43131_CHIP_ID: case BCM43217_CHIP_ID: case BCM43227_CHIP_ID: @@ -2354,3 +2442,46 @@ si_is_sprom_available(si_t *sih) return TRUE; } } + + +uint32 si_get_sromctl(si_t *sih) +{ + chipcregs_t *cc; + uint origidx; + uint32 sromctl; + osl_t *osh; + + osh = si_osh(sih); + origidx = si_coreidx(sih); + cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT((uintptr)cc); + + sromctl = R_REG(osh, &cc->sromcontrol); + + /* return to the original core */ + si_setcoreidx(sih, origidx); + return sromctl; +} + +int si_set_sromctl(si_t *sih, uint32 value) +{ + chipcregs_t *cc; + uint origidx; + osl_t *osh; + + osh = si_osh(sih); + origidx = si_coreidx(sih); + cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT((uintptr)cc); + + /* get chipcommon rev */ + if (si_corerev(sih) < 32) + return BCME_UNSUPPORTED; + + W_REG(osh, &cc->sromcontrol, value); + + /* return to the original core */ + si_setcoreidx(sih, origidx); + return BCME_OK; + +} diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 850694f86f9..63b45877a8f 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_android.c 323797 2012-03-27 01:27:20Z $ + * $Id: wl_android.c 358186 2012-09-21 14:36:14Z $ */ #include @@ -67,15 +67,38 @@ #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" #define CMD_BTCOEXMODE "BTCOEXMODE" #define CMD_SETSUSPENDOPT "SETSUSPENDOPT" +#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" #define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" #define CMD_SETFWPATH "SETFWPATH" #define CMD_SETBAND "SETBAND" #define CMD_GETBAND "GETBAND" #define CMD_COUNTRY "COUNTRY" #define CMD_P2P_SET_NOA "P2P_SET_NOA" +#if !defined WL_ENABLE_P2P_IF +#define CMD_P2P_GET_NOA "P2P_GET_NOA" +#endif #define CMD_P2P_SET_PS "P2P_SET_PS" #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" +#if defined(SUPPORT_HIDDEN_AP) +/* Hostapd private command */ +#define CMD_SET_HAPD_MAX_NUM_STA "HAPD_MAX_NUM_STA" +#define CMD_SET_HAPD_SSID "HAPD_SSID" +#define CMD_SET_HAPD_HIDE_SSID "HAPD_HIDE_SSID" +#endif +#if defined(SUPPORT_AUTO_CHANNEL) +#define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL" +#endif +#if defined(SUPPORT_SOFTAP_SINGL_DISASSOC) +#define CMD_HAPD_STA_DISASSOC "HAPD_STA_DISASSOC" +#endif + +/* CCX Private Commands */ +#ifdef BCMCCX +#define CMD_GETCCKM_RN "get cckm_rn" +#define CMD_SETCCKM_KRK "set cckm_krk" +#define CMD_GET_ASSOC_RES_IES "get assoc_res_ies" +#endif #ifdef PNO_SUPPORT #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" @@ -100,6 +123,76 @@ typedef struct cmd_tlv { } cmd_tlv_t; #endif /* PNO_SUPPORT */ +#ifdef OKC_SUPPORT +#define CMD_OKC_SET_PMK "SET_PMK" +#define CMD_OKC_ENABLE "OKC_ENABLE" +#endif + +#ifdef ROAM_API +#define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER" +#define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER" +#define CMD_ROAMDELTA_SET "SETROAMDELTA" +#define CMD_ROAMDELTA_GET "GETROAMDELTA" +#define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD" +#define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD" +#define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD" +#define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD" +#define CMD_COUNTRYREV_SET "SETCOUNTRYREV" +#define CMD_COUNTRYREV_GET "GETCOUNTRYREV" +#endif /* ROAM_API */ + +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) +#define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL" +#define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL" +#define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS" +#define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS" + +#define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME" +#define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME" +#define CMD_GETSCANHOMETIME "GETSCANHOMETIME" +#define CMD_SETSCANHOMETIME "SETSCANHOMETIME" +#define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME" +#define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME" +#define CMD_GETSCANNPROBES "GETSCANNPROBES" +#define CMD_SETSCANNPROBES "SETSCANNPROBES" + +#define CMD_SENDACTIONFRAME "SENDACTIONFRAME" +#define CMD_REASSOC "REASSOC" + +#define CMD_GETWESMODE "GETWESMODE" +#define CMD_SETWESMODE "SETWESMODE" + +#define CMD_GETOKCMODE "GETOKCMODE" +#define CMD_SETOKCMODE "SETOKCMODE" + +#define ANDROID_WIFI_MAX_ROAM_SCAN_CHANNELS 100 + +typedef struct android_wifi_reassoc_params { + unsigned char bssid[18]; + int channel; +} android_wifi_reassoc_params_t; + +#define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params) + +#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040 + +typedef struct android_wifi_af_params { + unsigned char bssid[18]; + int channel; + int dwell_time; + int len; + unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE]; +} android_wifi_af_params_t; + +#define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params) +#endif /* WES_SUPPORT */ +#ifdef SUPPORT_AMPDU_MPDU_CMD +#define CMD_AMPDU_MPDU "AMPDU_MPDU" +#endif /* SUPPORT_AMPDU_MPDU_CMD */ +#ifdef CUSTOMER_HW4 +#define CMD_CHANGE_RL "CHANGE_RL" +#define CMD_RESTORE_RL "RESTORE_RL" +#endif /* CUSTOMER_HW4 */ typedef struct android_wifi_priv_cmd { char *buf; int used_len; @@ -110,11 +203,16 @@ typedef struct android_wifi_priv_cmd { * Extern function declarations (TODO: move them to dhd_linux.h) */ void dhd_customer_gpio_wlan_ctrl(int onoff); -uint dhd_dev_reset(struct net_device *dev, uint8 flag); -void dhd_dev_init_ioctl(struct net_device *dev); +int dhd_dev_reset(struct net_device *dev, uint8 flag); +int dhd_dev_init_ioctl(struct net_device *dev); #ifdef WL_CFG80211 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command); +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) +int wl_cfg80211_set_wes_mode(int mode); +int wl_cfg80211_get_wes_mode(void); +int wl_cfg80211_get_ioctl_version(void); +#endif #else int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { return 0; } @@ -124,19 +222,29 @@ int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) { return 0; } int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) { return 0; } -#endif +#endif /* WL_CFG80211 */ extern int dhd_os_check_if_up(void *dhdp); extern void *bcmsdh_get_drvdata(void); -#ifdef PROP_TXSTATUS +#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) extern int dhd_wlfc_init(dhd_pub_t *dhd); extern void dhd_wlfc_deinit(dhd_pub_t *dhd); #endif +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) +/* wl_roam.c */ +extern int get_roamscan_mode(struct net_device *dev, int *mode); +extern int set_roamscan_mode(struct net_device *dev, int mode); +extern int get_roamscan_channel_list(struct net_device *dev, unsigned char channels[]); +extern int set_roamscan_channel_list(struct net_device *dev, unsigned char n, + unsigned char channels[], int ioctl_ver); +#endif + extern bool ap_fw_loaded; -#ifdef CUSTOMER_HW2 +#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4) extern char iface_name[IFNAMSIZ]; #endif - +#undef WIFI_TURNOFF_DELAY +#define WIFI_TURNOFF_DELAY 0 /** * Local (static) functions and variables */ @@ -198,19 +306,45 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command, int int ret_now; int ret = 0; - suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; +#ifdef CUSTOMER_HW4 + if (!dhd_download_fw_on_driverload) { +#endif /* CUSTOMER_HW4 */ + suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; + + if (suspend_flag != 0) + suspend_flag = 1; + ret_now = net_os_set_suspend_disable(dev, suspend_flag); + + if (ret_now != suspend_flag) { + if (!(ret = net_os_set_suspend(dev, ret_now, 1))) + DHD_INFO(("%s: Suspend Flag %d -> %d\n", + __FUNCTION__, ret_now, suspend_flag)); + else + DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); + } +#ifdef CUSTOMER_HW4 + } +#endif /* CUSTOMER_HW4 */ + return ret; +} + +static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) +{ + int ret = 0; + +#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) + int suspend_flag; + + suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; if (suspend_flag != 0) suspend_flag = 1; - ret_now = net_os_set_suspend_disable(dev, suspend_flag); - if (ret_now != suspend_flag) { - if (!(ret = net_os_set_suspend(dev, ret_now))) - DHD_INFO(("%s: Suspend Flag %d -> %d\n", - __FUNCTION__, ret_now, suspend_flag)); - else - DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); - } + if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) + DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag)); + else + DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); +#endif return ret; } @@ -227,6 +361,645 @@ static int wl_android_get_band(struct net_device *dev, char *command, int total_ return bytes_written; } +#ifdef ROAM_API +int wl_android_set_roam_trigger( + struct net_device *dev, char* command, int total_len) +{ + int roam_trigger[2]; + + sscanf(command, "%*s %10d", &roam_trigger[0]); + roam_trigger[1] = WLC_BAND_ALL; + + return wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), 1); +} + +static int wl_android_get_roam_trigger( + struct net_device *dev, char *command, int total_len) +{ + int bytes_written; + int roam_trigger[2] = {0, 0}; + + roam_trigger[1] = WLC_BAND_2G; + if (wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), 0)) { + roam_trigger[1] = WLC_BAND_5G; + if (wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), 0)) + return -1; + } + + bytes_written = snprintf(command, total_len, "%s %d", + CMD_ROAMTRIGGER_GET, roam_trigger[0]); + + return bytes_written; +} + +int wl_android_set_roam_delta( + struct net_device *dev, char* command, int total_len) +{ + int roam_delta[2]; + + sscanf(command, "%*s %10d", &roam_delta[0]); + roam_delta[1] = WLC_BAND_ALL; + + return wldev_ioctl(dev, WLC_SET_ROAM_DELTA, roam_delta, + sizeof(roam_delta), 1); +} + +static int wl_android_get_roam_delta( + struct net_device *dev, char *command, int total_len) +{ + int bytes_written; + int roam_delta[2] = {0, 0}; + + roam_delta[1] = WLC_BAND_2G; + if (wldev_ioctl(dev, WLC_GET_ROAM_DELTA, roam_delta, + sizeof(roam_delta), 0)) { + roam_delta[1] = WLC_BAND_5G; + if (wldev_ioctl(dev, WLC_GET_ROAM_DELTA, roam_delta, + sizeof(roam_delta), 0)) + return -1; + } + + bytes_written = snprintf(command, total_len, "%s %d", + CMD_ROAMDELTA_GET, roam_delta[0]); + + return bytes_written; +} + +int wl_android_set_roam_scan_period( + struct net_device *dev, char* command, int total_len) +{ + int roam_scan_period = 0; + + sscanf(command, "%*s %10d", &roam_scan_period); + return wldev_ioctl(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period, + sizeof(roam_scan_period), 1); +} + +static int wl_android_get_roam_scan_period( + struct net_device *dev, char *command, int total_len) +{ + int bytes_written; + int roam_scan_period = 0; + + if (wldev_ioctl(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period, + sizeof(roam_scan_period), 0)) + return -1; + + bytes_written = snprintf(command, total_len, "%s %d", + CMD_ROAMSCANPERIOD_GET, roam_scan_period); + + return bytes_written; +} + +int wl_android_set_full_roam_scan_period( + struct net_device *dev, char* command, int total_len) +{ + int error = 0; + int full_roam_scan_period = 0; + char smbuf[WLC_IOCTL_SMLEN]; + + sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period); + WL_TRACE(("%s: fullroamperiod = %d\n", __func__, full_roam_scan_period)); + + error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period, + sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL); + if (error) { + DHD_ERROR(("Failed to set full roam scan period, error = %d\n", error)); + } + + return error; +} + +static int wl_android_get_full_roam_scan_period( + struct net_device *dev, char *command, int total_len) +{ + int error; + int bytes_written; + int full_roam_scan_period = 0; + + error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period); + + if (error) { + DHD_ERROR(("%s: get full roam scan period failed code %d\n", + __func__, error)); + return -1; + } else { + DHD_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period)); + } + + bytes_written = snprintf(command, total_len, "%s %d", + CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period); + + return bytes_written; +} + +int wl_android_set_country_rev( + struct net_device *dev, char* command, int total_len) +{ + int error = 0; + wl_country_t cspec = {{0}, 0, {0} }; + char country_code[WLC_CNTRY_BUF_SZ]; + char smbuf[WLC_IOCTL_SMLEN]; + int rev = 0; + + memset(country_code, 0, sizeof(country_code)); + sscanf(command+sizeof("SETCOUNTRYREV"), "%10s %10d", country_code, &rev); + WL_TRACE(("%s: country_code = %s, rev = %d\n", __FUNCTION__, + country_code, rev)); + + memcpy(cspec.country_abbrev, country_code, sizeof(country_code)); + memcpy(cspec.ccode, country_code, sizeof(country_code)); + cspec.rev = rev; + + error = wldev_iovar_setbuf(dev, "country", (char *)&cspec, + sizeof(cspec), smbuf, sizeof(smbuf), NULL); + + if (error) { + DHD_ERROR(("%s: set country '%s/%d' failed code %d\n", + __FUNCTION__, cspec.ccode, cspec.rev, error)); + } else { + dhd_bus_country_set(dev, &cspec); + DHD_INFO(("%s: set country '%s/%d'\n", + __FUNCTION__, cspec.ccode, cspec.rev)); + } + + return error; +} + +static int wl_android_get_country_rev( + struct net_device *dev, char *command, int total_len) +{ + int error; + int bytes_written; + char smbuf[WLC_IOCTL_SMLEN]; + wl_country_t cspec; + + error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf, + sizeof(smbuf), NULL); + + if (error) { + DHD_ERROR(("%s: get country failed code %d\n", + __FUNCTION__, error)); + return -1; + } else { + memcpy(&cspec, smbuf, sizeof(cspec)); + DHD_INFO(("%s: get country '%c%c %d'\n", + __FUNCTION__, cspec.ccode[0], cspec.ccode[1], cspec.rev)); + } + + bytes_written = snprintf(command, total_len, "%s %c%c %d", + CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev); + + return bytes_written; +} +#endif /* ROAM_API */ + +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) +int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int bytes_written = 0; + int mode = 0; + + error = get_roamscan_mode(dev, &mode); + if (error) { + DHD_ERROR(("%s: Failed to get Scan Control, error = %d\n", __FUNCTION__, error)); + return -1; + } + + bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode); + + return bytes_written; +} + +int wl_android_set_roam_scan_control(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int mode = 0; + + if (sscanf(command, "%*s %d", &mode) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + error = set_roamscan_mode(dev, mode); + if (error) { + DHD_ERROR(("%s: Failed to set Scan Control %d, error = %d\n", + __FUNCTION__, mode, error)); + return -1; + } + + return 0; +} + +int wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len) +{ + int bytes_written = 0; + unsigned char channels[ANDROID_WIFI_MAX_ROAM_SCAN_CHANNELS] = {0}; + int channel_cnt = 0; + char channel_info[10 + (ANDROID_WIFI_MAX_ROAM_SCAN_CHANNELS * 3)] = {0}; + int channel_info_len = 0; + int i = 0; + + channel_cnt = get_roamscan_channel_list(dev, channels); + + channel_info_len += sprintf(&channel_info[channel_info_len], "%d ", channel_cnt); + for (i = 0; i < channel_cnt; i++) { + channel_info_len += sprintf(&channel_info[channel_info_len], "%d ", channels[i]); + + if (channel_info_len > (sizeof(channel_info) - 10)) + break; + } + channel_info_len += sprintf(&channel_info[channel_info_len], "%s", "\0"); + + bytes_written = snprintf(command, total_len, "%s %s", + CMD_GETROAMSCANCHANNELS, channel_info); + return bytes_written; +} + +int wl_android_set_roam_scan_channels(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1); + int ioctl_version = wl_cfg80211_get_ioctl_version(); + error = set_roamscan_channel_list(dev, p[0], &p[1], ioctl_version); + if (error) { + DHD_ERROR(("%s: Failed to set Scan Channels %d, error = %d\n", + __FUNCTION__, p[0], error)); + return -1; + } + + return 0; +} + +int wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int bytes_written = 0; + int time = 0; + + error = wldev_ioctl(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time), 0); + if (error) { + DHD_ERROR(("%s: Failed to get Scan Channel Time, error = %d\n", + __FUNCTION__, error)); + return -1; + } + + bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time); + + return bytes_written; +} + +int wl_android_set_scan_channel_time(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int time = 0; + + if (sscanf(command, "%*s %d", &time) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + error = wldev_ioctl(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time), 1); + if (error) { + DHD_ERROR(("%s: Failed to set Scan Channel Time %d, error = %d\n", + __FUNCTION__, time, error)); + return -1; + } + + return 0; +} + +int wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int bytes_written = 0; + int time = 0; + + error = wldev_ioctl(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time), 0); + if (error) { + DHD_ERROR(("Failed to get Scan Home Time, error = %d\n", error)); + return -1; + } + + bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time); + + return bytes_written; +} + +int wl_android_set_scan_home_time(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int time = 0; + + if (sscanf(command, "%*s %d", &time) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + error = wldev_ioctl(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time), 1); + if (error) { + DHD_ERROR(("%s: Failed to set Scan Home Time %d, error = %d\n", + __FUNCTION__, time, error)); + return -1; + } + + return 0; +} + +int wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int bytes_written = 0; + int time = 0; + + error = wldev_iovar_getint(dev, "scan_home_away_time", &time); + if (error) { + DHD_ERROR(("%s: Failed to get Scan Home Away Time, error = %d\n", + __FUNCTION__, error)); + return -1; + } + + bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time); + + return bytes_written; +} + +int wl_android_set_scan_home_away_time(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int time = 0; + + if (sscanf(command, "%*s %d", &time) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + error = wldev_iovar_setint(dev, "scan_home_away_time", time); + if (error) { + DHD_ERROR(("%s: Failed to set Scan Home Away Time %d, error = %d\n", + __FUNCTION__, time, error)); + return -1; + } + + return 0; +} + +int wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int bytes_written = 0; + int num = 0; + + error = wldev_ioctl(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num), 0); + if (error) { + DHD_ERROR(("%s: Failed to get Scan NProbes, error = %d\n", __FUNCTION__, error)); + return -1; + } + + bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num); + + return bytes_written; +} + +int wl_android_set_scan_nprobes(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int num = 0; + + if (sscanf(command, "%*s %d", &num) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + error = wldev_ioctl(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num), 1); + if (error) { + DHD_ERROR(("%s: Failed to set Scan NProbes %d, error = %d\n", + __FUNCTION__, num, error)); + return -1; + } + + return 0; +} + +int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len) +{ + int error = -1; + android_wifi_af_params_t *params = NULL; + wl_action_frame_t *action_frame = NULL; + wl_af_params_t *af_params = NULL; + char *smbuf = NULL; + struct ether_addr tmp_bssid; + int tmp_channel = 0; + + params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1); + if (params == NULL) { + DHD_ERROR(("%s: Invalid params \n", __FUNCTION__)); + goto send_action_frame_out; + } + + smbuf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); + if (smbuf == NULL) { + DHD_ERROR(("%s: failed to allocated memory %d bytes\n", + __FUNCTION__, WLC_IOCTL_MAXLEN)); + goto send_action_frame_out; + } + + af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); + if (af_params == NULL) + { + DHD_ERROR(("%s: unable to allocate frame\n", __FUNCTION__)); + goto send_action_frame_out; + } + + memset(&tmp_bssid, 0, ETHER_ADDR_LEN); + if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) { + memset(&tmp_bssid, 0, ETHER_ADDR_LEN); + + error = wldev_ioctl(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN, false); + if (error) { + memset(&tmp_bssid, 0, ETHER_ADDR_LEN); + DHD_ERROR(("%s: failed to get bssid, error=%d\n", __FUNCTION__, error)); + goto send_action_frame_out; + } + } + + if (params->channel < 0) { + struct channel_info ci; + error = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci), false); + if (error) { + DHD_ERROR(("%s: failed to get channel, error=%d\n", __FUNCTION__, error)); + goto send_action_frame_out; + } + + tmp_channel = ci.hw_channel; + } + else { + tmp_channel = params->channel; + } + + af_params->channel = tmp_channel; + af_params->dwell_time = params->dwell_time; + memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN); + action_frame = &af_params->action_frame; + + action_frame->packetId = 0; + memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN); + action_frame->len = params->len; + memcpy(action_frame->data, params->data, action_frame->len); + + error = wldev_iovar_setbuf(dev, "actframe", af_params, + sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL); + if (error) { + DHD_ERROR(("%s: failed to set action frame, error=%d\n", __FUNCTION__, error)); + } + +send_action_frame_out: + if (af_params) + kfree(af_params); + + if (smbuf) + kfree(smbuf); + + if (error) + return -1; + else + return 0; +} + +int wl_android_reassoc(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + android_wifi_reassoc_params_t *params = NULL; + uint band; + chanspec_t channel; + u32 params_size; + wl_reassoc_params_t reassoc_params; + + params = (android_wifi_reassoc_params_t *)(command + strlen(CMD_REASSOC) + 1); + if (params == NULL) { + DHD_ERROR(("%s: Invalid params \n", __FUNCTION__)); + return -1; + } + + memset(&reassoc_params, 0, WL_REASSOC_PARAMS_FIXED_SIZE); + + if (bcm_ether_atoe((const char *)params->bssid, + (struct ether_addr *)&reassoc_params.bssid) == 0) { + DHD_ERROR(("%s: Invalid bssid \n", __FUNCTION__)); + return -1; + } + + if (params->channel < 0) { + DHD_ERROR(("%s: Invalid Channel \n", __FUNCTION__)); + return -1; + } + + reassoc_params.chanspec_num = 1; + + channel = params->channel; +#ifdef D11AC_IOTYPES + if (wl_cfg80211_get_ioctl_version() == 1) { + band = ((channel <= CH_MAX_2G_CHANNEL) ? + WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G); + reassoc_params.chanspec_list[0] = channel | + band | WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE; + } + else { + band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); + reassoc_params.chanspec_list[0] = channel | band | WL_LCHANSPEC_BW_20; + } +#else + band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); + reassoc_params.chanspec_list[0] = channel | + band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; +#endif /* D11AC_IOTYPES */ + params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t); + + error = wldev_ioctl(dev, WLC_REASSOC, &reassoc_params, params_size, true); + if (error) { + DHD_ERROR(("%s: failed to reassoc, error=%d\n", __FUNCTION__, error)); + } + + if (error) + return -1; + else + return 0; +} + +int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len) +{ + int bytes_written = 0; + int mode = 0; + + mode = wl_cfg80211_get_wes_mode(); + + bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode); + + return bytes_written; +} + +int wl_android_set_wes_mode(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int mode = 0; + + if (sscanf(command, "%*s %d", &mode) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + error = wl_cfg80211_set_wes_mode(mode); + if (error) { + DHD_ERROR(("%s: Failed to set WES Mode %d, error = %d\n", + __FUNCTION__, mode, error)); + return -1; + } + + return 0; +} + +int wl_android_get_okc_mode(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int bytes_written = 0; + int mode = 0; + + error = wldev_iovar_getint(dev, "okc_enable", &mode); + if (error) { + DHD_ERROR(("%s: Failed to get OKC Mode, error = %d\n", __FUNCTION__, error)); + return -1; + } + + bytes_written = snprintf(command, total_len, "%s %d", CMD_GETOKCMODE, mode); + + return bytes_written; +} + +int wl_android_set_okc_mode(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int mode = 0; + + if (sscanf(command, "%*s %d", &mode) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + error = wldev_iovar_setint(dev, "okc_enable", mode); + if (error) { + DHD_ERROR(("%s: Failed to set OKC Mode %d, error = %d\n", + __FUNCTION__, mode, error)); + return -1; + } + + return error; +} +#endif /* WES_SUPPORT */ + #ifdef PNO_SUPPORT static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) { @@ -348,6 +1121,90 @@ static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, i return bytes_written; } +#ifdef BCMCCX +static int wl_android_get_cckm_rn(struct net_device *dev, char *command) +{ + int error, rn; + + WL_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name)); + + error = wldev_iovar_getint(dev, "cckm_rn", &rn); + if (unlikely(error)) { + WL_ERR(("wl_android_get_cckm_rn error (%d)\n", error)); + return -1; + } + memcpy(command, &rn, sizeof(int)); + + return sizeof(int); +} + +static int wl_android_set_cckm_krk(struct net_device *dev, char *command) +{ + int error; + unsigned char key[16]; + static char iovar_buf[WLC_IOCTL_MEDLEN]; + + WL_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name)); + + memset(iovar_buf, 0, sizeof(iovar_buf)); + memcpy(key, command+strlen("set cckm_krk")+1, 16); + + error = wldev_iovar_setbuf(dev, "cckm_krk", key, sizeof(key), + iovar_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(error)) + { + WL_ERR((" cckm_krk set error (%d)\n", error)); + return -1; + } + return 0; +} + +static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command) +{ + int error; + u8 buf[WL_ASSOC_INFO_MAX]; + wl_assoc_info_t assoc_info; + u32 resp_ies_len = 0; + int bytes_written = 0; + + WL_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name)); + + error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf, WL_ASSOC_INFO_MAX, NULL); + if (unlikely(error)) { + WL_ERR(("could not get assoc info (%d)\n", error)); + return -1; + } + + memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t)); + assoc_info.req_len = htod32(assoc_info.req_len); + assoc_info.resp_len = htod32(assoc_info.resp_len); + assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.resp_len) { + resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + } + + /* first 4 bytes are ie len */ + memcpy(command, &resp_ies_len, sizeof(u32)); + bytes_written = sizeof(u32); + + /* get the association resp IE's if there are any */ + if (resp_ies_len) { + error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0, + buf, WL_ASSOC_INFO_MAX, NULL); + if (unlikely(error)) { + WL_ERR(("could not get assoc resp_ies (%d)\n", error)); + return -1; + } + + memcpy(command+sizeof(u32), buf, resp_ies_len); + bytes_written += resp_ies_len; + } + return bytes_written; +} + +#endif /* BCMCCX */ + /** * Global function definitions (declared in wl_android.h) */ @@ -380,8 +1237,11 @@ int wl_android_wifi_on(struct net_device *dev) } ret = dhd_dev_reset(dev, FALSE); sdioh_start(NULL, 1); - dhd_dev_init_ioctl(dev); -#ifdef PROP_TXSTATUS + if (!ret) { + if (dhd_dev_init_ioctl(dev) < 0) + ret = -EFAULT; + } +#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) dhd_wlfc_init(bcmsdh_get_drvdata()); #endif g_wifi_on = TRUE; @@ -405,10 +1265,10 @@ int wl_android_wifi_off(struct net_device *dev) dhd_net_if_lock(dev); if (g_wifi_on) { -#ifdef PROP_TXSTATUS +#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) dhd_wlfc_deinit(bcmsdh_get_drvdata()); #endif - dhd_dev_reset(dev, 1); + ret = dhd_dev_reset(dev, TRUE); sdioh_stop(NULL); dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); g_wifi_on = FALSE; @@ -434,8 +1294,238 @@ static int wl_android_set_fwpath(struct net_device *net, char *command, int tota return 0; } +#if defined(SUPPORT_HIDDEN_AP) +static int +wl_android_set_max_num_sta(struct net_device *dev, const char* string_num) +{ + int max_assoc; + + max_assoc = bcm_atoi(string_num); + DHD_INFO(("%s : HAPD_MAX_NUM_STA = %d\n", __FUNCTION__, max_assoc)); + wldev_iovar_setint(dev, "maxassoc", max_assoc); + return 1; +} + +static int +wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid) +{ + wlc_ssid_t ssid; + s32 ret; + + ssid.SSID_len = strlen(hapd_ssid); + bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len); + DHD_INFO(("%s: HAPD_SSID = %s\n", __FUNCTION__, ssid.SSID)); + ret = wldev_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t), true); + if (ret < 0) { + DHD_ERROR(("%s : WLC_SET_SSID Error:%d\n", __FUNCTION__, ret)); + } + return 1; + +} + +static int +wl_android_set_hide_ssid(struct net_device *dev, const char* string_num) +{ + int hide_ssid; + int enable = 0; + + hide_ssid = bcm_atoi(string_num); + DHD_INFO(("%s: HAPD_HIDE_SSID = %d\n", __FUNCTION__, hide_ssid)); + if (hide_ssid) + enable = 1; + wldev_iovar_setint(dev, "closednet", enable); + return 1; +} +#endif /* SUPPORT_HIDDEN_AP */ + +#if defined(SUPPORT_AUTO_CHANNEL) +static int +wl_android_set_auto_channel(struct net_device *dev, const char* string_num, + char* command, int total_len) +{ + int channel; + int chosen = 0; + int retry = 0; + int ret = 0; + + /* Restrict channel to 1 - 7: 2GHz, 20MHz BW, No SB */ + u32 req_buf[8] = {7, 0x2B01, 0x2B02, 0x2B03, 0x2B04, 0x2B05, 0x2B06, + 0x2B07}; + + /* Auto channel select */ + wl_uint32_list_t request; + + channel = bcm_atoi(string_num); + DHD_INFO(("%s : HAPD_AUTO_CHANNEL = %d\n", __FUNCTION__, channel)); + + if (channel == 20) + ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, (void *)&req_buf, + sizeof(req_buf), true); + else { /* channel == 0 */ + request.count = htod32(0); + ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, (void *)&request, + sizeof(request), true); + } + + if (ret < 0) { + DHD_ERROR(("%s: can't start auto channel scan, err = %d\n", + __FUNCTION__, ret)); + channel = 0; + goto done; + } + + /* Wait for auto channel selection, max 2500 ms */ + bcm_mdelay(500); + + retry = 10; + while (retry--) { + ret = wldev_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), + false); + if (ret < 0 || dtoh32(chosen) == 0) { + DHD_INFO(("%s: %d tried, ret = %d, chosen = %d\n", + __FUNCTION__, (10 - retry), ret, chosen)); + bcm_mdelay(200); + } + else { + channel = (u16)chosen & 0x00FF; + DHD_ERROR(("%s: selected channel = %d\n", __FUNCTION__, channel)); + break; + } + } + + if (retry == 0) { + DHD_ERROR(("%s: auto channel timed out, failed\n", __FUNCTION__)); + channel = 0; + } + +done: + snprintf(command, 4, "%d", channel); + DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); + + return 4; +} +#endif /* SUPPORT_AUTO_CHANNEL */ + +#if defined(SUPPORT_SOFTAP_SINGL_DISASSOC) +static int +wl_android_sta_diassoc(struct net_device *dev, const char* straddr) +{ + scb_val_t scbval; + + DHD_INFO(("%s: deauth STA %s\n", __FUNCTION__, straddr)); + + /* Unspecified reason */ + scbval.val = htod32(1); + bcm_ether_atoe(straddr, &scbval.ea); + + DHD_INFO(("%s: deauth STA: "MACDBG "\n", __FUNCTION__, + MAC2STRDBG(scbval.ea.octet))); + + wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, + sizeof(scb_val_t), true); + + return 1; +} +#endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */ + +#ifdef OKC_SUPPORT + +static int +wl_android_set_pmk(struct net_device *dev, char *command, int total_len) +{ + uchar pmk[33]; + int error = 0; + char smbuf[WLC_IOCTL_SMLEN]; +#ifdef OKC_DEBUG + int i = 0; +#endif + + bzero(pmk, sizeof(pmk)); + memcpy((char *)pmk, command + strlen("SET_PMK "), 32); + error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL); + if (error) { + DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error)); + } +#ifdef OKC_DEBUG + DHD_ERROR(("PMK is ")); + for (i = 0; i < 32; i++) + DHD_ERROR(("%02X ", pmk[i])); + + DHD_ERROR(("\n")); +#endif + return error; +} + +static int +wl_android_okc_enable(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + char okc_enable = 0; + + okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0'; + error = wldev_iovar_setint(dev, "okc_enable", okc_enable); + if (error) { + DHD_ERROR(("Failed to %s OKC, error = %d\n", + okc_enable ? "enable" : "disable", error)); + } + + return error; +} + +#endif /* OKC_ SUPPORT */ +#ifdef CUSTOMER_HW4 +static int +wl_android_ch_res_rl(struct net_device *dev, bool change) +{ + int error = 0; + s32 srl = 7; + s32 lrl = 4; + printk("%s enter\n", __FUNCTION__); + if (change) { + srl = 4; + lrl = 2; + } + error = wldev_ioctl(dev, WLC_SET_SRL, &srl, sizeof(s32), true); + if (error) { + DHD_ERROR(("Failed to set SRL, error = %d\n", error)); + } + error = wldev_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(s32), true); + if (error) { + DHD_ERROR(("Failed to set LRL, error = %d\n", error)); + } + return error; +} +#endif /* CUSTOMER_HW4 */ + +#ifdef SUPPORT_AMPDU_MPDU_CMD +/* CMD_AMPDU_MPDU */ +static int +wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num) +{ + int err = 0; + int ampdu_mpdu; + + ampdu_mpdu = bcm_atoi(string_num); + + if (ampdu_mpdu > 32) { + DHD_ERROR(("%s : ampdu_mpdu MAX value is 32.\n", __FUNCTION__)); + return -1; + } + + DHD_ERROR(("%s : ampdu_mpdu = %d\n", __FUNCTION__, ampdu_mpdu)); + err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu); + if (err < 0) { + DHD_ERROR(("%s : ampdu_mpdu set error. %d\n", __FUNCTION__, err)); + return -1; + } + + return 0; +} +#endif /* SUPPORT_AMPDU_MPDU_CMD */ + int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) { +#define PRIVATE_COMMAND_MAX_LEN 8192 int ret = 0; char *command = NULL; int bytes_written = 0; @@ -451,6 +1541,11 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) ret = -EFAULT; goto exit; } + if (priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) + { + DHD_ERROR(("%s: too long priavte command\n", __FUNCTION__)); + ret = -EINVAL; + } command = kmalloc(priv_cmd.total_len, GFP_KERNEL); if (!command) { @@ -462,12 +1557,15 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) ret = -EFAULT; goto exit; } - DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { DHD_INFO(("%s, Received regular START command\n", __FUNCTION__)); +#ifdef SUPPORT_DEEP_SLEEP + sleep_never = 1; +#else bytes_written = wl_android_wifi_on(net); +#endif /* SUPPORT_DEEP_SLEEP */ } else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) { bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len); @@ -481,7 +1579,11 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) } if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) { +#ifdef SUPPORT_DEEP_SLEEP + sleep_never = 1; +#else bytes_written = wl_android_wifi_off(net); +#endif /* SUPPORT_DEEP_SLEEP */ } else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { /* TBD: SCAN-ACTIVE */ @@ -495,11 +1597,12 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len); } +#ifdef PKT_FILTER_SUPPORT else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) { - bytes_written = net_os_set_packet_filter(net, 1); + bytes_written = net_os_enable_packet_filter(net, 1); } else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) { - bytes_written = net_os_set_packet_filter(net, 0); + bytes_written = net_os_enable_packet_filter(net, 0); } else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) { int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; @@ -509,6 +1612,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); } +#endif /* PKT_FILTER_SUPPORT */ else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { /* TBD: BTCOEXSCAN-START */ } @@ -516,30 +1620,152 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) /* TBD: BTCOEXSCAN-STOP */ } else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { +#ifdef WL_CFG80211 + bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command); +#else +#ifdef PKT_FILTER_SUPPORT uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; if (mode == 1) - net_os_set_packet_filter(net, 0); /* DHCP starts */ + net_os_enable_packet_filter(net, 0); /* DHCP starts */ else - net_os_set_packet_filter(net, 1); /* DHCP ends */ -#ifdef WL_CFG80211 - bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command); -#endif + net_os_enable_packet_filter(net, 1); /* DHCP ends */ +#endif /* PKT_FILTER_SUPPORT */ +#endif /* WL_CFG80211 */ } else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); } + else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { + bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; +#ifdef WL_HOST_BAND_MGMT + if (wl_cfg80211_set_band(net, band) < 0) { + bytes_written = -1; + goto exit; + } + if (band == WLC_BAND_AUTO) + bytes_written = wldev_set_band(net, band); +#else bytes_written = wldev_set_band(net, band); +#endif /* WL_HOST_BAND_MGMT */ } else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); } +#ifdef WL_CFG80211 +#ifndef CUSTOMER_SET_COUNTRY + /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { char *country_code = command + strlen(CMD_COUNTRY) + 1; bytes_written = wldev_set_country(net, country_code); } +#endif +#endif /* WL_CFG80211 */ +#ifdef ROAM_API + else if (strnicmp(command, CMD_ROAMTRIGGER_SET, + strlen(CMD_ROAMTRIGGER_SET)) == 0) { + bytes_written = wl_android_set_roam_trigger(net, command, + priv_cmd.total_len); + } else if (strnicmp(command, CMD_ROAMTRIGGER_GET, + strlen(CMD_ROAMTRIGGER_GET)) == 0) { + bytes_written = wl_android_get_roam_trigger(net, command, + priv_cmd.total_len); + } else if (strnicmp(command, CMD_ROAMDELTA_SET, + strlen(CMD_ROAMDELTA_SET)) == 0) { + bytes_written = wl_android_set_roam_delta(net, command, + priv_cmd.total_len); + } else if (strnicmp(command, CMD_ROAMDELTA_GET, + strlen(CMD_ROAMDELTA_GET)) == 0) { + bytes_written = wl_android_get_roam_delta(net, command, + priv_cmd.total_len); + } else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET, + strlen(CMD_ROAMSCANPERIOD_SET)) == 0) { + bytes_written = wl_android_set_roam_scan_period(net, command, + priv_cmd.total_len); + } else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET, + strlen(CMD_ROAMSCANPERIOD_GET)) == 0) { + bytes_written = wl_android_get_roam_scan_period(net, command, + priv_cmd.total_len); + } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET, + strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) { + bytes_written = wl_android_set_full_roam_scan_period(net, command, + priv_cmd.total_len); + } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET, + strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) { + bytes_written = wl_android_get_full_roam_scan_period(net, command, + priv_cmd.total_len); + } else if (strnicmp(command, CMD_COUNTRYREV_SET, + strlen(CMD_COUNTRYREV_SET)) == 0) { + bytes_written = wl_android_set_country_rev(net, command, + priv_cmd.total_len); + wl_update_wiphybands(NULL); + } else if (strnicmp(command, CMD_COUNTRYREV_GET, + strlen(CMD_COUNTRYREV_GET)) == 0) { + bytes_written = wl_android_get_country_rev(net, command, + priv_cmd.total_len); + } +#endif /* ROAM_API */ +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) + else if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) { + bytes_written = wl_android_get_roam_scan_control(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) { + bytes_written = wl_android_set_roam_scan_control(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) { + bytes_written = wl_android_get_roam_scan_channels(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) { + bytes_written = wl_android_set_roam_scan_channels(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) { + bytes_written = wl_android_send_action_frame(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) { + bytes_written = wl_android_reassoc(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) { + bytes_written = wl_android_get_scan_channel_time(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) { + bytes_written = wl_android_set_scan_channel_time(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) { + bytes_written = wl_android_get_scan_home_time(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) { + bytes_written = wl_android_set_scan_home_time(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) { + bytes_written = wl_android_get_scan_home_away_time(net, command, + priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) { + bytes_written = wl_android_set_scan_home_away_time(net, command, + priv_cmd.total_len); + } + else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) { + bytes_written = wl_android_get_scan_nprobes(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) { + bytes_written = wl_android_set_scan_nprobes(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) { + bytes_written = wl_android_get_wes_mode(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) { + bytes_written = wl_android_set_wes_mode(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_GETOKCMODE, strlen(CMD_GETOKCMODE)) == 0) { + bytes_written = wl_android_get_okc_mode(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETOKCMODE, strlen(CMD_SETOKCMODE)) == 0) { + bytes_written = wl_android_set_okc_mode(net, command, priv_cmd.total_len); + } +#endif /* WES_SUPPORT */ #ifdef PNO_SUPPORT else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { bytes_written = dhd_dev_pno_reset(net); @@ -560,6 +1786,11 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip); } +#if !defined WL_ENABLE_P2P_IF + else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { + bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); + } +#endif /* WL_ENABLE_P2P_IF */ else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { int skip = strlen(CMD_P2P_SET_PS) + 1; bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, @@ -573,6 +1804,68 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) priv_cmd.total_len - skip, *(command + skip - 2) - '0'); } #endif /* WL_CFG80211 */ +#if defined(SUPPORT_AUTO_CHANNEL) + else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL, + strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) { + int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 3; + bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command, + priv_cmd.total_len); + } +#endif +#if defined(SUPPORT_HIDDEN_AP) + else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA, + strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) { + int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3; + wl_android_set_max_num_sta(net, (const char*)command+skip); + } + else if (strnicmp(command, CMD_SET_HAPD_SSID, + strlen(CMD_SET_HAPD_SSID)) == 0) { + int skip = strlen(CMD_SET_HAPD_SSID) + 3; + wl_android_set_ssid(net, (const char*)command+skip); + } + else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID, + strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) { + int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3; + wl_android_set_hide_ssid(net, (const char*)command+skip); + } +#endif /* SUPPORT_HIDDEN_AP */ +#if defined(SUPPORT_SOFTAP_SINGL_DISASSOC) + else if (strnicmp(command, CMD_HAPD_STA_DISASSOC, + strlen(CMD_HAPD_STA_DISASSOC)) == 0) { + int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1; + wl_android_sta_diassoc(net, (const char*)command+skip); + } +#endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */ +#ifdef OKC_SUPPORT + else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) + bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) + bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); +#endif /* OKC_SUPPORT */ +#ifdef BCMCCX + else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) { + bytes_written = wl_android_get_cckm_rn(net, command); + } + else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) { + bytes_written = wl_android_set_cckm_krk(net, command); + } + else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) { + bytes_written = wl_android_get_assoc_res_ies(net, command); + } +#endif /* BCMCCX */ +#ifdef SUPPORT_AMPDU_MPDU_CMD + /* CMD_AMPDU_MPDU */ + else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) { + int skip = strlen(CMD_AMPDU_MPDU) + 1; + bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip); + } +#endif /* SUPPORT_AMPDU_MPDU_CMD */ +#ifdef CUSTOMER_HW4 + else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0) + bytes_written = wl_android_ch_res_rl(net, true); + else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0) + bytes_written = wl_android_ch_res_rl(net, false); +#endif /* CUSTOMER_HW4 */ else { DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); snprintf(command, 3, "OK"); @@ -611,15 +1904,16 @@ int wl_android_init(void) { int ret = 0; + dhd_msg_level |= DHD_ERROR_VAL; #ifdef ENABLE_INSMOD_NO_FW_LOAD dhd_download_fw_on_driverload = FALSE; #endif /* ENABLE_INSMOD_NO_FW_LOAD */ -#ifdef CUSTOMER_HW2 +#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4) if (!iface_name[0]) { memset(iface_name, 0, IFNAMSIZ); bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); } -#endif /* CUSTOMER_HW2 */ +#endif /* CUSTOMER_HW2 || CUSTOMER_HW4 */ return ret; } @@ -782,7 +2076,7 @@ static int wifi_remove(struct platform_device *pdev) DHD_ERROR(("## %s\n", __FUNCTION__)); wifi_control_data = wifi_ctrl; - wifi_set_power(0, 0); /* Power Off */ + wifi_set_power(0, WIFI_TURNOFF_DELAY); /* Power Off */ wifi_set_carddetect(0); /* CardDetect (1->0) */ up(&wifi_control_sem); @@ -830,10 +2124,15 @@ static struct platform_driver wifi_device_legacy = { static int wifi_add_dev(void) { + int ret = 0; DHD_TRACE(("## Calling platform_driver_register\n")); - platform_driver_register(&wifi_device); - platform_driver_register(&wifi_device_legacy); - return 0; + + ret = platform_driver_register(&wifi_device); + if (ret) + return ret; + + ret = platform_driver_register(&wifi_device_legacy); + return ret; } static void wifi_del_dev(void) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 40f1b2ce488..e248edbd82e 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 328984 2012-04-23 14:08:37Z $ + * $Id: wl_cfg80211.c 359682 2012-09-28 20:23:14Z $ */ #include @@ -54,12 +54,17 @@ #include #include #include - #include #include #include #include +#ifdef WL11U +#ifndef WL_ENABLE_P2P_IF +#error "You should enable WL_ENABLE_P2P_IF and Only supported in JB" +#endif +#endif /* WL11U */ + #ifdef BCMWAPI_WPI /* these items should evetually go into wireless.h of the linux system headfile dir */ #ifndef IW_ENCODE_ALG_SM4 @@ -93,19 +98,41 @@ #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) #endif /* BCMWAPI_WPI */ - static struct device *cfg80211_parent_dev = NULL; -static int vsdb_supported = 0; struct wl_priv *wlcfg_drv_priv = NULL; - +#ifdef CUSTOMER_HW4 +u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_P2P_ACTION; +#else u32 wl_dbg_level = WL_DBG_ERR; +#endif -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" #define MAX_WAIT_TIME 1500 -#define WL_SCAN_ACTIVE_TIME 40 /* ms : Embedded default Active setting from DHD Driver */ -#define WL_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD Driver */ -#define WL_FRAME_LEN 300 + +#ifdef VSDB +/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */ +#define DEFAULT_SLEEP_TIME_VSDB 200 +#define OFF_CHAN_TIME_THRESHOLD_MS 200 + +/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */ +#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) \ + do { \ + if (wl_get_drv_status(wl, CONNECTED, wl_to_prmry_ndev(wl)) || \ + wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { \ + msleep(DEFAULT_SLEEP_TIME_VSDB); \ + } \ + } while (0) +#else /* VSDB */ +/* if not VSDB, do nothing */ +#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) +#endif /* VSDB */ + +#ifdef WL_CFG80211_SYNC_GON +#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl) \ + (wl_get_drv_status_all(wl, SENDING_ACT_FRM) || \ + wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) +#else +#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl) wl_get_drv_status_all(wl, SENDING_ACT_FRM) +#endif /* WL_CFG80211_SYNC_GON */ #define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL @@ -120,24 +147,16 @@ u32 wl_dbg_level = WL_DBG_ERR; * All the chnages in world regulatory domain are to be done here. */ static const struct ieee80211_regdomain brcm_regdom = { - .n_reg_rules = 5, + .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { /* IEEE 802.11b/g, channels 1..11 */ - REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), - /* IEEE 802.11b/g, channels 12..13. No HT40 - * channel fits here. - */ - REG_RULE(2467-10, 2472+10, 20, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS), + REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), + /* If any */ /* IEEE 802.11 channel 14 - Only JP enables * this and for 802.11b only */ - REG_RULE(2484-10, 2484+10, 20, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS | - NL80211_RRF_NO_OFDM), + REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), /* IEEE 802.11a, channel 36..64 */ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), /* IEEE 802.11a, channel 100..165 */ @@ -178,6 +197,19 @@ static const struct ieee80211_regdomain brcm_regdom = { #define WPS_CONFIG_VIRT_DISPLAY 0x2008 #define WPS_CONFIG_PHY_DISPLAY 0x4008 +#define PM_BLOCK 1 +#define PM_ENABLE 0 + +#ifdef BCMCCX +#ifndef WLAN_AKM_SUITE_CCKM +#define WLAN_AKM_SUITE_CCKM 0x000FAC04 +#endif +#define DOT11_LEAP_AUTH 0x80 /* LEAP auth frame paylod constants */ +#endif /* BCMCCX */ + +#ifndef RSSI_OFFSET +#define RSSI_OFFSET 0 +#endif /* * cfg80211_ops api/callback list */ @@ -223,6 +255,10 @@ static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx); static s32 wl_cfg80211_resume(struct wiphy *wiphy); +static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct net_device *dev, u64 cookie); +static s32 wl_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *ndev, u8* mac_addr); #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); #else @@ -269,6 +305,8 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); +static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, + enum wl_status state, bool set); /* * register/deregister parent device */ @@ -323,6 +361,13 @@ static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size); static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); static u32 wl_get_ielen(struct wl_priv *wl); +#ifdef WL11U +bcm_tlv_t * +wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); +static s32 +wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, + uint8 ie_id, uint8 *data, uint8 data_len); +#endif /* WL11U */ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev); static void wl_free_wdev(struct wl_priv *wl); @@ -331,6 +376,7 @@ static s32 wl_inform_bss(struct wl_priv *wl); static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi); static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev); static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); +static s32 wl_cfg80211_40MHz_to_20MHz_Channel(chanspec_t chspec); static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, const u8 *mac_addr, @@ -360,7 +406,6 @@ static __used bool wl_is_ibssstarter(struct wl_priv *wl); */ static s32 __wl_cfg80211_up(struct wl_priv *wl); static s32 __wl_cfg80211_down(struct wl_priv *wl); -static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e); static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev); static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e); @@ -368,7 +413,6 @@ static void wl_link_up(struct wl_priv *wl); static void wl_link_down(struct wl_priv *wl); static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype); static void wl_init_conf(struct wl_conf *conf); -static s32 wl_update_wiphybands(struct wl_priv *wl); /* * iscan handler @@ -415,6 +459,15 @@ int dhd_monitor_init(void *dhd_pub); int dhd_monitor_uninit(void); int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); +#ifdef ROAM_CHANNEL_CACHE +void reset_roam_cache(void); +void add_roam_cache(wl_bss_info_t *bi); +int get_roam_channel_list(int target_chan, + chanspec_t *channels, const wlc_ssid_t *ssid, int ioctl_ver); +void print_roam_cache(void); +void set_roam_band(int band); +#endif + #define CHECK_SYS_UP(wlpriv) \ do { \ @@ -432,6 +485,11 @@ do { \ extern int dhd_wait_pend8021x(struct net_device *dev); +#ifdef PROP_TXSTATUS_VSDB +extern int disable_proptx; +extern int dhd_wlfc_init(dhd_pub_t *dhd); +extern void dhd_wlfc_deinit(dhd_pub_t *dhd); +#endif /* PROP_TXSTATUS_VSDB */ #if (WL_DBG_LEVEL > 0) #define WL_DBG_ESTR_MAX 50 @@ -569,6 +627,10 @@ static const u32 __wl_cipher_suites[] = { #endif }; +#ifdef WL_CFG80211_GON_COLLISION +#define BLOCK_GON_REQ_MAX_NUM 5 +#endif /* WL_CFG80211_GON_COLLISION */ + /* IOCtl version read from targeted driver */ static int ioctl_version; @@ -787,22 +849,31 @@ static void swap_key_to_BE(struct wl_wsec_key *key) key->iv_initialized = dtoh32(key->iv_initialized); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) /* For debug: Dump the contents of the encoded wps ie buffe */ static void -wl_validate_wps_ie(char *wps_ie, bool *pbc) +wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) { #define WPS_IE_FIXED_LEN 6 - u16 len = (u16) wps_ie[TLV_LEN_OFF]; - u8 *subel = wps_ie+ WPS_IE_FIXED_LEN; + u16 len; + u8 *subel = NULL; u16 subelt_id; u16 subelt_len; u16 val; u8 *valptr = (uint8*) &val; + if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) { + WL_ERR(("invalid argument : NULL\n")); + return; + } + len = (u16)wps_ie[TLV_LEN_OFF]; + if (len > wps_ie_len) { + WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len)); + return; + } WL_DBG(("wps_ie len=%d\n", len)); - len -= 4; /* for the WPS IE's OUI, oui_type fields */ - + subel = wps_ie + WPS_IE_FIXED_LEN; while (len >= 4) { /* must have attr id, attr len fields */ valptr[0] = *subel++; valptr[1] = *subel++; @@ -862,52 +933,89 @@ wl_validate_wps_ie(char *wps_ie, bool *pbc) subel += subelt_len; } } +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ + +static s32 +wl_cfg80211_40MHz_to_20MHz_Channel(chanspec_t chspec) +{ + u32 channel = chspec & WL_CHANSPEC_CHAN_MASK; + + /* If chspec is not for 40MHz. Do nothing */ + if (!(chspec & WL_CHANSPEC_BW_40)) + return channel; + + if ((channel < 0) || (channel > MAXCHANNEL)) + return -1; + + switch (channel) { + /* 5G Channels */ + case 38: + case 46: + case 151: + case 159: + if (chspec & WL_CHANSPEC_CTL_SB_LOWER) + channel = channel - CH_10MHZ_APART; + else if (chspec & WL_CHANSPEC_CTL_SB_UPPER) + channel = channel + CH_10MHZ_APART; + break; + default: + /* Mhz adjustment not required. Use as is */ + WL_ERR(("Unsupported channel: %d \n", channel)); + } + + return channel; +} static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) { - if (vsdb_supported) { + chanspec_t chspec; + int err = 0; + struct wl_priv *wl = wiphy_priv(wiphy); + struct net_device *dev = wl_to_prmry_ndev(wl); + struct ether_addr bssid; + struct wl_bss_info *bss = NULL; + + if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { + /* STA interface is not associated. So start the new interface on a temp + * channel . Later proper channel will be applied by the above framework + * via set_channel (cfg80211 API). + */ + WL_DBG(("Not associated. Return a temp channel. \n")); return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); } - else { - chanspec_t chspec; - int err = 0; - struct wl_priv *wl = wiphy_priv(wiphy); - struct net_device *dev = wl_to_prmry_ndev(wl); - struct ether_addr bssid; - struct wl_bss_info *bss = NULL; - - if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { - /* STA interface is not associated. So start the new interface on a temp - * channel . Later proper channel will be applied by the above framework - * via set_channel (cfg80211 API). - */ - WL_DBG(("Not associated. Return a temp channel. \n")); - return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); - } - *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); - if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, - sizeof(WL_EXTRA_BUF_MAX), false))) { - WL_ERR(("Failed to get associated bss info, use temp channel \n")); - chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); - } - else { - bss = (struct wl_bss_info *) (wl->extra_buf + 4); - chspec = bss->chanspec; - WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec)); - } - return chspec; + *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); + if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, + WL_EXTRA_BUF_MAX, false))) { + WL_ERR(("Failed to get associated bss info, use temp channel \n")); + chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); + } + else { + bss = (struct wl_bss_info *) (wl->extra_buf + 4); + chspec = bss->chanspec; + if (chspec & WL_CHANSPEC_BW_40) { + uint32 channel = wl_cfg80211_40MHz_to_20MHz_Channel(chspec); + chspec = wl_ch_host_to_driver(channel); + } + + WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec)); } + return chspec; } static struct net_device* wl_cfg80211_add_monitor_if(char *name) { +#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) + WL_INFO(("wl_cfg80211_add_monitor_if: No more support monitor interface\n")); + return ERR_PTR(-EOPNOTSUPP); +#else struct net_device* ndev = NULL; dhd_add_monitor(name, &ndev); WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); return ndev; +#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ } static struct net_device * @@ -919,15 +1027,26 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, s32 timeout = -1; s32 wlif_type = -1; s32 mode = 0; -#if defined(WL_ENABLE_P2P_IF) + s32 val = 0; s32 dhd_mode = 0; -#endif /* (WL_ENABLE_P2P_IF) */ chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *_ndev; struct ether_addr primary_mac; int (*net_attach)(void *dhdp, int ifidx); bool rollback_lock = false; +#ifdef PROP_TXSTATUS_VSDB + s32 up = 1; + dhd_pub_t *dhd; +#endif /* PROP_TXSTATUS_VSDB */ + + if (!wl) + return ERR_PTR(-EINVAL); + +#ifdef PROP_TXSTATUS_VSDB + dhd = (dhd_pub_t *)(wl->pub); +#endif /* PROP_TXSTATUS_VSDB */ + /* Use primary I/F for sending cmds down to firmware */ _ndev = wl_to_prmry_ndev(wl); @@ -963,8 +1082,6 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, WL_ERR(("name is NULL\n")); return NULL; } - if (wl->iface_cnt == IFACE_MAX_CNT) - return ERR_PTR(-ENOMEM); if (wl->p2p_supported && (wlif_type != -1)) { if (wl_get_p2p_status(wl, IF_DELETING)) { /* wait till IF_DEL is complete @@ -992,7 +1109,20 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, WL_ERR(("timeount < 0, return -EAGAIN\n")); return ERR_PTR(-EAGAIN); } + /* It should be now be safe to put this check here since we are sure + * by now netdev_notifier (unregister) would have been called + */ + if (wl->iface_cnt == IFACE_MAX_CNT) + return ERR_PTR(-ENOMEM); } + +#ifdef PROP_TXSTATUS_VSDB + if (!dhd) + return ERR_PTR(-ENODEV); +#endif /* PROP_TXSTATUS_VSDB */ + if (!wl->p2p || !wl->p2p->vir_ifname) + return ERR_PTR(-ENODEV); + if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { p2p_on(wl) = true; wl_cfgp2p_set_firm_p2p(wl); @@ -1005,8 +1135,17 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); - wldev_iovar_setint(_ndev, "mpc", 0); wl_notify_escan_complete(wl, _ndev, true, true); +#ifdef PROP_TXSTATUS_VSDB + if (!wl->wlfc_on && !disable_proptx) { + dhd->wlfc_enabled = true; + dhd_wlfc_init(dhd); + err = wldev_ioctl(_ndev, WLC_UP, &up, sizeof(s32), true); + if (err < 0) + WL_ERR(("WLC_UP return err:%d\n", err)); + wl->wlfc_on = true; + } +#endif /* PROP_TXSTATUS_VSDB */ /* In concurrency case, STA may be already associated in a particular channel. * so retrieve the current channel of primary interface and then start the virtual @@ -1018,6 +1157,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, * bss: "wl p2p_ifadd" */ wl_set_p2p_status(wl, IF_ADD); + if (wlif_type == WL_P2P_IF_GO) + wldev_iovar_setint(_ndev, "mpc", 0); err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); if (unlikely(err)) { @@ -1053,16 +1194,23 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, rollback_lock = true; } if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) { - wl_alloc_netinfo(wl, _ndev, vwdev, mode); +#ifdef CUSTOMER_HW4 + wl_alloc_netinfo(wl, _ndev, vwdev, mode, PM_BLOCK); +#else + wl_alloc_netinfo(wl, _ndev, vwdev, mode, PM_ENABLE); +#endif /* CUSTOMER_HW4 */ + val = 1; + /* Disable firmware roaming for P2P interface */ + wldev_iovar_setint(_ndev, "roam_off", val); WL_ERR((" virtual interface(%s) is " "created net attach done\n", wl->p2p->vir_ifname)); -#if defined(WL_ENABLE_P2P_IF) + if (mode == WL_MODE_AP) + wl_set_drv_status(wl, CONNECTED, _ndev); if (type == NL80211_IFTYPE_P2P_CLIENT) - dhd_mode = P2P_GC_ENABLED; + dhd_mode = DHD_FLAG_P2P_GC_MODE; else if (type == NL80211_IFTYPE_P2P_GO) - dhd_mode = P2P_GO_ENABLED; + dhd_mode = DHD_FLAG_P2P_GO_MODE; DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode)); -#endif /* (WL_ENABLE_P2P_IF) */ } else { /* put back the rtnl_lock again */ if (rollback_lock) @@ -1079,9 +1227,18 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, WL_ERR((" virtual interface(%s) is not created \n", wl->p2p->vir_ifname)); memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); wl->p2p->vif_created = false; +#ifdef PROP_TXSTATUS_VSDB + if (dhd->wlfc_enabled && wl->wlfc_on) { + dhd->wlfc_enabled = false; + dhd_wlfc_deinit(dhd); + wl->wlfc_on = false; + } +#endif /* PROP_TXSTATUS_VSDB */ } } fail: + if (wlif_type == WL_P2P_IF_GO) + wldev_iovar_setint(_ndev, "mpc", 1); return ERR_PTR(-ENODEV); } @@ -1103,12 +1260,44 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) if (wl->p2p_supported) { memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); + + /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases + */ + WL_DBG(("P2P: GO_NEG_PHASE status cleared ")); + wl_clr_p2p_status(wl, GO_NEG_PHASE); if (wl->p2p->vif_created) { if (wl_get_drv_status(wl, SCANNING, dev)) { wl_notify_escan_complete(wl, dev, true, true); } wldev_iovar_setint(dev, "mpc", 1); + + /* for GC */ + if (wl_get_drv_status(wl, DISCONNECTING, dev) && + (wl_get_mode_by_netdev(wl, dev) != WL_MODE_AP)) { + WL_ERR(("Wait for Link Down event for GC !\n")); + wait_for_completion_timeout + (&wl->iface_disable, msecs_to_jiffies(500)); + } wl_set_p2p_status(wl, IF_DELETING); + DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl)); + + /* for GO */ + if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); + /* disable interface before bsscfg free */ + ret = wl_cfgp2p_ifdisable(wl, &p2p_mac); + /* if fw doesn't support "ifdis", + do not wait for link down of ap mode + */ + if (ret == 0) { + WL_ERR(("Wait for Link Down event for GO !!!\n")); + wait_for_completion_timeout(&wl->iface_disable, + msecs_to_jiffies(500)); + } else { + msleep(300); + } + } + /* delete interface after link down */ ret = wl_cfgp2p_ifdel(wl, &p2p_mac); /* Firmware could not delete the interface so we will not get WLC_E_IF * event for cleaning the dhd virtual nw interace @@ -1123,16 +1312,12 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) "HANG Notification sent to %s\n", ret, ndev->name)); wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED); } - - /* Wait for any pending scan req to get aborted from the sysioc context */ + /* Wait for IF_DEL operation to be finished in firmware */ timeout = wait_event_interruptible_timeout(wl->netif_change_event, - (wl_get_p2p_status(wl, IF_DELETING) == false), + (wl->p2p->vif_created == false), msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) { + if (timeout > 0 && (wl->p2p->vif_created == false)) { WL_DBG(("IFDEL operation done\n")); -#if defined(WL_ENABLE_P2P_IF) - DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl)); -#endif /* (WL_ENABLE_P2P_IF)) */ } else { WL_ERR(("IFDEL didn't complete properly\n")); } @@ -1153,8 +1338,8 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, s32 mode = 0; chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); - - WL_DBG(("Enter \n")); + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + WL_DBG(("Enter type %d\n", type)); switch (type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: @@ -1180,7 +1365,8 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, default: return -EINVAL; } - + if (!dhd) + return -EINVAL; if (ap) { wl_set_mode_by_netdev(wl, ndev, mode); if (wl->p2p_supported && wl->p2p->vif_created) { @@ -1195,7 +1381,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, */ chspec = wl_cfg80211_get_shared_freq(wiphy); - wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT; + wlif_type = WL_P2P_IF_GO; WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", ndev->name, ap, infra, type)); wl_set_p2p_status(wl, IF_CHANGING); @@ -1205,8 +1391,12 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, (wl_get_p2p_status(wl, IF_CHANGED) == true), msecs_to_jiffies(MAX_WAIT_TIME)); wl_set_mode_by_netdev(wl, ndev, mode); + dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE; + dhd->op_mode |= DHD_FLAG_P2P_GO_MODE; wl_clr_p2p_status(wl, IF_CHANGING); wl_clr_p2p_status(wl, IF_CHANGED); + if (mode == WL_MODE_AP) + wl_set_drv_status(wl, CONNECTED, ndev); } else if (ndev == wl_to_prmry_ndev(wl) && !wl_get_drv_status(wl, AP_CREATED, ndev)) { wl_set_drv_status(wl, AP_CREATING, ndev); @@ -1219,6 +1409,8 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, WL_ERR(("Cannot change the interface for GO or SOFTAP\n")); return -EINVAL; } + } else { + WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA")); } ndev->ieee80211_ptr->iftype = type; @@ -1255,12 +1447,26 @@ wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, } s32 -wl_cfg80211_notify_ifdel(struct net_device *ndev) +wl_cfg80211_notify_ifdel(void) +{ + struct wl_priv *wl = wlcfg_drv_priv; + + WL_DBG(("Enter \n")); + wl_clr_p2p_status(wl, IF_DELETING); + wake_up_interruptible(&wl->netif_change_event); + return 0; +} + +s32 +wl_cfg80211_ifdel_ops(struct net_device *ndev) { struct wl_priv *wl = wlcfg_drv_priv; bool rollback_lock = false; s32 index = 0; - if (!ndev || !ndev->name) { +#ifdef PROP_TXSTATUS_VSDB + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); +#endif /* PROP_TXSTATUS_VSDB */ + if (!ndev || (strlen(ndev->name) == 0)) { WL_ERR(("net is NULL\n")); return 0; } @@ -1290,9 +1496,15 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) wl->p2p->vif_created = false; wl_cfgp2p_clear_management_ie(wl, index); - wl_clr_p2p_status(wl, IF_DELETING); WL_DBG(("index : %d\n", index)); - +#ifdef PROP_TXSTATUS_VSDB + if (dhd->wlfc_enabled && wl->wlfc_on) { + dhd->wlfc_enabled = false; + dhd_wlfc_deinit(dhd); + wl->wlfc_on = false; + } +#endif /* PROP_TXSTATUS_VSDB */ + wl_clr_drv_status(wl, CONNECTED, ndev); } /* Wake up any waiting thread */ wake_up_interruptible(&wl->netif_change_event); @@ -1332,15 +1544,71 @@ wl_cfg80211_notify_ifchange(void) return 0; } +/* Find listen channel */ +static s32 wl_find_listen_channel(struct wl_priv *wl, + u8 *ie, u32 ie_len) +{ + wifi_p2p_ie_t *p2p_ie; + u8 *end, *pos; + s32 listen_channel; + + p2p_ie = wl_cfgp2p_find_p2pie(ie, ie_len); + + if (p2p_ie == NULL) + return 0; + + pos = p2p_ie->subelts; + end = p2p_ie->subelts + (p2p_ie->len - 4); + + CFGP2P_DBG((" found p2p ie ! lenth %d \n", + p2p_ie->len)); + + while (pos < end) { + uint16 attr_len; + if (pos + 2 >= end) { + CFGP2P_DBG((" -- Invalid P2P attribute")); + return 0; + } + attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0])); + + if (pos + 3 + attr_len > end) { + CFGP2P_DBG(("P2P: Attribute underflow " + "(len=%u left=%d)", + attr_len, (int) (end - pos - 3))); + return 0; + } + + /* if Listen Channel att id is 6 and the vailue is valid, + * return the listen channel + */ + if (pos[0] == 6) { + /* listen channel subel length format + * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num) + */ + listen_channel = pos[1 + 2 + 3 + 1]; + + if (listen_channel == SOCIAL_CHAN_1 || + listen_channel == SOCIAL_CHAN_2 || + listen_channel == SOCIAL_CHAN_3) { + CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel)); + return listen_channel; + } + } + pos += 3 + attr_len; + } + return 0; +} + static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) { u32 n_ssids; u32 n_channels; u16 channel; chanspec_t chanspec; - s32 i, offset; + s32 i = 0, j = 0, offset; char *ptr; wlc_ssid_t ssid; + struct wl_priv *wl = wlcfg_drv_priv; memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); params->bss_type = DOT11_BSSTYPE_ANY; @@ -1377,33 +1645,45 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req for (i = 0; i < n_channels; i++) { chanspec = 0; channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); - if (request->channels[i]->band == IEEE80211_BAND_2GHZ) + /* SKIP DFS channels for Secondary interface */ + if ((wl->escan_info.ndev != wl_to_prmry_ndev(wl)) && + (request->channels[i]->flags & + (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) + continue; + + if (request->channels[i]->band == IEEE80211_BAND_2GHZ) { +#ifdef WL_HOST_BAND_MGMT + if (wl->curr_band == WLC_BAND_5G) { + WL_DBG(("In 5G only mode, omit 2G channel:%d\n", channel)); + continue; + } +#endif /* WL_HOST_BAND_MGMT */ chanspec |= WL_CHANSPEC_BAND_2G; - else - chanspec |= WL_CHANSPEC_BAND_5G; - - if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40) { - chanspec |= WL_CHANSPEC_BW_20; - chanspec |= WL_CHANSPEC_CTL_SB_NONE; } else { - chanspec |= WL_CHANSPEC_BW_40; - if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40PLUS) - chanspec |= WL_CHANSPEC_CTL_SB_LOWER; - else - chanspec |= WL_CHANSPEC_CTL_SB_UPPER; +#ifdef WL_HOST_BAND_MGMT + if (wl->curr_band == WLC_BAND_2G) { + WL_DBG(("In 2G only mode, omit 5G channel:%d\n", channel)); + continue; + } +#endif /* WL_HOST_BAND_MGMT */ + chanspec |= WL_CHANSPEC_BAND_5G; } - params->channel_list[i] = channel; - params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK; - params->channel_list[i] |= chanspec; + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + params->channel_list[j] = channel; + params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK; + params->channel_list[j] |= chanspec; WL_SCAN(("Chan : %d, Channel spec: %x \n", - channel, params->channel_list[i])); - params->channel_list[i] = wl_chspec_host_to_driver(params->channel_list[i]); + channel, params->channel_list[j])); + params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]); + j++; } } else { WL_SCAN(("Scanning all channels\n")); } - + n_channels = j; /* Copy ssid array if applicable */ WL_SCAN(("### List of SSIDs to scan ###\n")); if (n_ssids > 0) { @@ -1429,6 +1709,10 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req params->channel_num = htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); + + if (n_channels == 1 && wl_get_drv_status_all(wl, CONNECTED)) { + params->active_time = WL_SCAN_CONNECT_DWELL_TIME_MS; + } } static s32 @@ -1438,30 +1722,30 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, u32 n_ssids; s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)); - struct wl_iscan_params *params; + struct wl_iscan_params *params = NULL; s32 err = 0; - if (request != NULL) { - n_channels = request->n_channels; - n_ssids = request->n_ssids; - /* Allocate space for populating ssids in wl_iscan_params struct */ - if (n_channels % 2) - /* If n_channels is odd, add a padd of u16 */ - params_size += sizeof(u16) * (n_channels + 1); - else - params_size += sizeof(u16) * n_channels; - - /* Allocate space for populating ssids in wl_iscan_params struct */ - params_size += sizeof(struct wlc_ssid) * n_ssids; + if (request == NULL) { + err = -EINVAL; + goto done; } + n_channels = request->n_channels; + n_ssids = request->n_ssids; + /* Allocate space for populating ssids in wl_iscan_params struct */ + if (n_channels % 2) + /* If n_channels is odd, add a padd of u16 */ + params_size += sizeof(u16) * (n_channels + 1); + else + params_size += sizeof(u16) * n_channels; + + /* Allocate space for populating ssids in wl_iscan_params struct */ + params_size += sizeof(struct wlc_ssid) * n_ssids; params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); if (!params) { err = -ENOMEM; goto done; } - - if (request != NULL) - wl_scan_prep(¶ms->params, request); + wl_scan_prep(¶ms->params, request); params->version = htod32(ISCAN_REQ_VERSION); params->action = htod16(action); @@ -1481,8 +1765,10 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, WL_ERR(("error (%d)\n", err)); } } - kfree(params); + done: + if (params) + kfree(params); return err; } @@ -1497,14 +1783,14 @@ static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request passive_scan = wl->active_scan ? 0 : 1; err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan), false); + &passive_scan, sizeof(passive_scan), true); if (unlikely(err)) { WL_DBG(("error (%d)\n", err)); return err; } wl->iscan_kickstart = true; wl_run_iscan(iscan, request, WL_SCAN_ACTION_START); - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); iscan->timer_on = 1; return err; @@ -1527,6 +1813,12 @@ wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) return err; } + +#ifdef USE_INITIAL_2G_SCAN +#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40 +static bool g_first_broadcast_scan = TRUE; +#endif /* USE_INITIAL_2G_SCAN */ + static s32 wl_run_escan(struct wl_priv *wl, struct net_device *ndev, struct cfg80211_scan_request *request, uint16 action) @@ -1536,7 +1828,6 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, u32 n_ssids; s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); wl_escan_params_t *params = NULL; - struct cfg80211_scan_request *scan_request = wl->scan_request; u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)]; u32 num_chans = 0; s32 channel; @@ -1546,14 +1837,50 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, u16 *default_chan_list = NULL; wl_uint32_list_t *list; struct net_device *dev = NULL; - WL_DBG(("Enter \n")); +#ifdef USE_INITIAL_2G_SCAN + bool is_first_init_2g_scan = false; +#endif /* USE_INITIAL_2G_SCAN */ + WL_DBG(("Enter \n")); - if (!wl->p2p_supported || ((ndev == wl_to_prmry_ndev(wl)) && - !p2p_scan(wl))) { + if (!request || !wl) { + err = -EINVAL; + goto exit; + } + if (!wl->p2p_supported || !p2p_scan(wl)) { /* LEGACY SCAN TRIGGER */ WL_SCAN((" LEGACY E-SCAN START\n")); +#ifdef USE_INITIAL_2G_SCAN + if (ndev == wl_to_prmry_ndev(wl) && g_first_broadcast_scan == true) { + j = 0; + if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { + list = (wl_uint32_list_t *) chan_buf; + n_valid_chan = dtoh32(list->count); + for (i = 0; i < n_valid_chan && request->n_channels > j; + i++) { +#if defined(BCM4334_CHIP) + request->channels[i]->flags |= + IEEE80211_CHAN_NO_HT40; +#endif + + WL_SCAN(("list->element[%d]=%d\n", + i, list->element[i])); + if (list->element[i] > CH_MAX_2G_CHANNEL) + break; + j++; + } + request->n_channels = j; + + WL_SCAN(("request->n_channels=%d\n", request->n_channels)); + g_first_broadcast_scan = false; + is_first_init_2g_scan = true; + } + } + +#endif /* USE_INITIAL_2G_SCAN */ + + /* if scan request is not empty parse scan request paramters */ if (request != NULL) { n_channels = request->n_channels; n_ssids = request->n_ssids; @@ -1566,18 +1893,27 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, /* Allocate space for populating ssids in wl_iscan_params struct */ params_size += sizeof(struct wlc_ssid) * n_ssids; - } + } params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); if (params == NULL) { err = -ENOMEM; goto exit; } + wl_scan_prep(¶ms->params, request); + +#ifdef USE_INITIAL_2G_SCAN + /* Override active_time to reduce scan time if it's first bradcast scan. */ + if (is_first_init_2g_scan) + params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; +#endif /* USE_INITIAL_2G_SCAN */ - if (request != NULL) - wl_scan_prep(¶ms->params, request); params->version = htod32(ESCAN_REQ_VERSION); params->action = htod16(action); +#if defined(DUAL_ESCAN_RESULT_BUFFER) + params->sync_id = wl->escan_info.cur_sync_id; +#else params->sync_id = htod16(0x1234); +#endif if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { WL_ERR(("ioctl buffer length not sufficient\n")); kfree(params); @@ -1594,8 +1930,8 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, /* P2P SCAN TRIGGER */ s32 _freq = 0; n_nodfs = 0; - if (scan_request && scan_request->n_channels) { - num_chans = scan_request->n_channels; + if (request && request->n_channels) { + num_chans = request->n_channels; WL_SCAN((" chann number : %d\n", num_chans)); default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), GFP_KERNEL); @@ -1609,18 +1945,33 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, n_valid_chan = dtoh32(list->count); for (i = 0; i < num_chans; i++) { - _freq = scan_request->channels[i]->center_freq; +#ifdef WL_HOST_BAND_MGMT + int channel_band = 0; +#endif /* WL_HOST_BAND_MGMT */ + _freq = request->channels[i]->center_freq; channel = ieee80211_frequency_to_channel(_freq); - /* remove DFS channels */ - if (channel < 52 || channel > 140) { - for (j = 0; j < n_valid_chan; j++) { - /* allows only supported channel on - * current reguatory - */ - if (channel == (dtoh32(list->element[j]))) - default_chan_list[n_nodfs++] = - channel; - } +#ifdef WL_HOST_BAND_MGMT + channel_band = (channel > CH_MAX_2G_CHANNEL) ? + WLC_BAND_5G : WLC_BAND_2G; + if ((wl->curr_band != WLC_BAND_AUTO) && + (wl->curr_band != channel_band) && + !IS_P2P_SOCIAL_CHANNEL(channel)) + continue; +#endif /* WL_HOST_BAND_MGMT */ + + /* ignore DFS channels */ + if (request->channels[i]->flags & + (IEEE80211_CHAN_RADAR + | IEEE80211_CHAN_PASSIVE_SCAN)) + continue; + + for (j = 0; j < n_valid_chan; j++) { + /* allows only supported channel on + * current reguatory + */ + if (channel == (dtoh32(list->element[j]))) + default_chan_list[n_nodfs++] = + channel; } } @@ -1666,22 +2017,30 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, s32 passive_scan; wl_scan_results_t *results; WL_SCAN(("Enter \n")); + mutex_lock(&wl->usr_sync); +#if defined(DUAL_ESCAN_RESULT_BUFFER) + results = (wl_scan_results_t *) wl->escan_info.escan_buf[wl->escan_info.cur_sync_id%2]; +#else + results = (wl_scan_results_t *) wl->escan_info.escan_buf; +#endif + results->version = 0; + results->count = 0; + results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; + wl->escan_info.ndev = ndev; wl->escan_info.wiphy = wiphy; wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; passive_scan = wl->active_scan ? 0 : 1; err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan), false); + &passive_scan, sizeof(passive_scan), true); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); - return err; + goto exit; } - results = (wl_scan_results_t *) wl->escan_info.escan_buf; - results->version = 0; - results->count = 0; - results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; err = wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START); +exit: + mutex_unlock(&wl->usr_sync); return err; } @@ -1694,15 +2053,20 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ssid *ssids; struct wl_scan_req *sr = wl_to_sr(wl); struct ether_addr primary_mac; - wpa_ie_fixed_t *wps_ie; s32 passive_scan; bool iscan_req; bool escan_req = false; bool p2p_ssid; +#ifdef WL11U + bcm_tlv_t *interworking_ie; + u32 ie_len; +#endif s32 err = 0; + s32 bssidx = -1; s32 i; - u32 wpsie_len = 0; - u8 wpsie[IE_MAX_LEN]; + + unsigned long flags; + static s32 busy_count = 0; /* If scan req comes for p2p0, send it over primary I/F * Scan results will be delivered corresponding to cfg80211_scan_request @@ -1711,10 +2075,20 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ndev = wl_to_prmry_ndev(wl); } + if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl)) { + WL_ERR(("Sending Action Frames. Try it again.\n")); + return -EAGAIN; + } + WL_DBG(("Enter wiphy (%p)\n", wiphy)); if (wl_get_drv_status_all(wl, SCANNING)) { - WL_ERR(("Scanning already\n")); - return -EAGAIN; + if (wl->scan_request == NULL) { + wl_clr_drv_status_all(wl, SCANNING); + WL_DBG(("<<<<<<<<<<>>>>>>>>>>\n")); + } else { + WL_ERR(("Scanning already\n")); + return -EAGAIN; + } } if (wl_get_drv_status(wl, SCAN_ABORTING, ndev)) { WL_ERR(("Scanning being aborted\n")); @@ -1724,9 +2098,15 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); return -EOPNOTSUPP; } +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL)) { + WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n")); + wl_notify_escan_complete(wl, ndev, true, true); + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ /* Arm scan timeout timer */ - mod_timer(&wl->scan_timeout, jiffies + WL_SCAN_TIMER_INTERVAL_MS * HZ / 1000); + mod_timer(&wl->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); iscan_req = false; if (request) { /* scan bss */ ssids = request->ssids; @@ -1736,7 +2116,8 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, escan_req = true; p2p_ssid = false; for (i = 0; i < request->n_ssids; i++) { - if (ssids[i].ssid_len && IS_P2P_SSID(ssids[i].ssid)) { + if (ssids[i].ssid_len && + IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { p2p_ssid = true; break; } @@ -1752,6 +2133,8 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); } + wl_clr_p2p_status(wl, GO_NEG_PHASE); + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); p2p_scan(wl) = true; } } else { @@ -1763,8 +2146,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, /* If Netdevice is not equals to primary and p2p is on * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. */ - if (p2p_on(wl) && (ndev != wl_to_prmry_ndev(wl))) - p2p_scan(wl) = true; if (p2p_scan(wl) == false) { if (wl_get_p2p_status(wl, DISCOVERY_ON)) { @@ -1778,24 +2159,40 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } } if (!wl->p2p_supported || !p2p_scan(wl)) { - if (ndev == wl_to_prmry_ndev(wl)) { - /* find the WPSIE */ - memset(wpsie, 0, sizeof(wpsie)); - if ((wps_ie = wl_cfgp2p_find_wpsie( - (u8 *)request->ie, - request->ie_len)) != NULL) { - wpsie_len = - wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; - memcpy(wpsie, wps_ie, wpsie_len); - } else { - wpsie_len = 0; - } - err = wl_cfgp2p_set_management_ie(wl, ndev, -1, - VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len); + bssidx = wl_cfgp2p_find_idx(wl, ndev); + +#ifdef WL11U + if ((interworking_ie = wl_cfg80211_find_interworking_ie( + (u8 *)request->ie, request->ie_len)) != NULL) { + ie_len = interworking_ie->len; + + err = wl_cfg80211_add_iw_ie(wl, ndev, bssidx, + VNDR_IE_CUSTOM_FLAG, interworking_ie->id, + interworking_ie->data, interworking_ie->len); + if (unlikely(err)) { goto scan_out; } + } else if (wl->iw_ie_len != 0) { + /* we have to clear IW IE and disable gratuitous APR */ + wl_cfg80211_add_iw_ie(wl, ndev, bssidx, + VNDR_IE_CUSTOM_FLAG, + DOT11_MNG_INTERWORKING_ID, + 0, 0); + + wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, + bssidx); + /* we don't care about error */ + } +#endif /* WL11U */ + err = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, + VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, + request->ie_len); + + if (unlikely(err)) { + goto scan_out; } + } } } @@ -1808,15 +2205,19 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (iscan_req) { err = wl_do_iscan(wl, request); if (likely(!err)) - return err; + goto scan_success; else goto scan_out; } else if (escan_req) { if (wl->p2p_supported) { if (p2p_on(wl) && p2p_scan(wl)) { + /* find my listen channel */ + wl->afx_hdl->my_listen_chan = + wl_find_listen_channel(wl, (u8 *)request->ie, + request->ie_len); err = wl_cfgp2p_enable_discovery(wl, ndev, - request->ie, request->ie_len); + request->ie, request->ie_len); if (unlikely(err)) { goto scan_out; @@ -1825,7 +2226,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } err = wl_do_escan(wl, wiphy, ndev, request); if (likely(!err)) - return err; + goto scan_success; else goto scan_out; @@ -1845,7 +2246,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, WL_SCAN(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len)); passive_scan = wl->active_scan ? 0 : 1; err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan), false); + &passive_scan, sizeof(passive_scan), true); if (unlikely(err)) { WL_SCAN(("WLC_SET_PASSIVE_SCAN error (%d)\n", err)); goto scan_out; @@ -1863,11 +2264,55 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } } +scan_success: + + busy_count = 0; + return 0; scan_out: + + if (err == BCME_BUSY || err == BCME_NOTREADY) { + WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY)); + err = -EBUSY; + } + +#define SCAN_EBUSY_RETRY_LIMIT 10 + if (err == -EBUSY) { + if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) { + struct ether_addr bssid; + s32 ret = 0; + busy_count = 0; + WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n", + wl_get_drv_status(wl, SCANNING, ndev), + wl_get_drv_status(wl, SCAN_ABORTING, ndev), + wl_get_drv_status(wl, CONNECTING, ndev), + wl_get_drv_status(wl, CONNECTED, ndev), + wl_get_drv_status(wl, DISCONNECTING, ndev), + wl_get_drv_status(wl, AP_CREATING, ndev), + wl_get_drv_status(wl, AP_CREATED, ndev), + wl_get_drv_status(wl, SENDING_ACT_FRM, ndev), + wl_get_drv_status(wl, SENDING_ACT_FRM, ndev))); + + bzero(&bssid, sizeof(bssid)); + if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID, + &bssid, ETHER_ADDR_LEN, false)) == 0) + WL_ERR(("FW is connected with " MACDBG "/n", + MAC2STRDBG(bssid.octet))); + else + WL_ERR(("GET BSSID failed with %d\n", ret)); + + wl_cfg80211_disconnect(wiphy, ndev, DOT11_RC_DISASSOC_LEAVING); + } + } else { + busy_count = 0; + } wl_clr_drv_status(wl, SCANNING, ndev); + if (timer_pending(&wl->scan_timeout)) + del_timer_sync(&wl->scan_timeout); + spin_lock_irqsave(&wl->cfgdrv_lock, flags); wl->scan_request = NULL; + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); return err; } @@ -1920,7 +2365,7 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); retry = htod32(retry); - err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), false); + err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true); if (unlikely(err)) { WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); return err; @@ -2008,7 +2453,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, } /* wait 4 secons till scan done.... */ - schedule_timeout_interruptible(4 * HZ); + schedule_timeout_interruptible(msecs_to_jiffies(4000)); if (rollback_lock) rtnl_lock(); bss = cfg80211_get_ibss(wiphy, NULL, @@ -2038,7 +2483,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - sizeof(join_params), false); + sizeof(join_params), true); if (unlikely(err)) { WL_ERR(("Error (%d)\n", err)); return err; @@ -2067,9 +2512,17 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) s32 bssidx = wl_cfgp2p_find_idx(wl, dev); if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) - val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; + val = WPA_AUTH_PSK | +#ifdef BCMCCX + WPA_AUTH_CCKM | +#endif + WPA_AUTH_UNSPECIFIED; else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) - val = WPA2_AUTH_PSK| WPA2_AUTH_UNSPECIFIED; + val = WPA2_AUTH_PSK| +#ifdef BCMCCX + WPA2_AUTH_CCKM | +#endif + WPA2_AUTH_UNSPECIFIED; else val = WPA_AUTH_DISABLED; @@ -2128,21 +2581,29 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) s32 bssidx = wl_cfgp2p_find_idx(wl, dev); switch (sme->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: - val = 0; + val = WL_AUTH_OPEN_SYSTEM; WL_DBG(("open system\n")); break; case NL80211_AUTHTYPE_SHARED_KEY: - val = 1; + val = WL_AUTH_SHARED_KEY; WL_DBG(("shared key\n")); break; case NL80211_AUTHTYPE_AUTOMATIC: - val = 2; +#ifdef USE_WEP_AUTH_SHARED_OPEN + val = WL_AUTH_SHARED_OPEN; +#else + val = WL_AUTH_OPEN_SHARED; +#endif /* USE_WEP_AUTH_SHARED_OPEN */ WL_DBG(("automatic\n")); break; +#ifdef BCMCCX case NL80211_AUTHTYPE_NETWORK_EAP: WL_DBG(("network eap\n")); + val = DOT11_LEAP_AUTH; + break; +#endif default: - val = 2; + val = WL_AUTH_OPEN_SHARED; WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); break; } @@ -2228,7 +2689,11 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); if (is_wps_conn(sme)) { - err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + if (sme->privacy) + err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + else + /* WPS-2.0 allows no security */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); } else { #ifdef BCMWAPI_WPI if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) { @@ -2270,7 +2735,11 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) WL_ERR(("could not get wpa_auth (%d)\n", err)); return err; } - if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { + if (val & (WPA_AUTH_PSK | +#ifdef BCMCCX + WPA_AUTH_CCKM | +#endif + WPA_AUTH_UNSPECIFIED)) { switch (sme->crypto.akm_suites[0]) { case WLAN_AKM_SUITE_8021X: val = WPA_AUTH_UNSPECIFIED; @@ -2278,12 +2747,21 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) case WLAN_AKM_SUITE_PSK: val = WPA_AUTH_PSK; break; +#ifdef BCMCCX + case WLAN_AKM_SUITE_CCKM: + val = WPA_AUTH_CCKM; + break; +#endif default: WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group)); return -EINVAL; } - } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { + } else if (val & (WPA2_AUTH_PSK | +#ifdef BCMCCX + WPA2_AUTH_CCKM | +#endif + WPA2_AUTH_UNSPECIFIED)) { switch (sme->crypto.akm_suites[0]) { case WLAN_AKM_SUITE_8021X: val = WPA2_AUTH_UNSPECIFIED; @@ -2291,6 +2769,11 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) case WLAN_AKM_SUITE_PSK: val = WPA2_AUTH_PSK; break; +#ifdef BCMCCX + case WLAN_AKM_SUITE_CCKM: + val = WPA2_AUTH_CCKM; + break; +#endif default: WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group)); @@ -2393,9 +2876,9 @@ wl_set_set_sharedkey(struct net_device *dev, WL_ERR(("WLC_SET_KEY error (%d)\n", err)); return err; } - if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { + if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { WL_DBG(("set auth_type to shared key\n")); - val = 1; /* shared key */ + val = WL_AUTH_SHARED_KEY; /* shared key */ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); if (unlikely(err)) { WL_ERR(("set auth failed (%d)\n", err)); @@ -2407,6 +2890,15 @@ wl_set_set_sharedkey(struct net_device *dev, return err; } +#ifdef ESCAN_RESULT_PATCH +static u8 connect_req_bssid[6]; +static u8 broad_bssid[6]; +#endif + +#ifdef ROAM_CHANNEL_CACHE +#define MAX_ROAM_CACHE_NUM 100 +#endif + static s32 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) @@ -2416,101 +2908,148 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, wl_extjoin_params_t *ext_join_params; struct wl_join_params join_params; size_t join_params_size; +#ifdef ROAM_AP_ENV_DETECTION + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); +#endif /* ROAM_AP_ENV_DETECTION */ s32 err = 0; wpa_ie_fixed_t *wpa_ie; - wpa_ie_fixed_t *wps_ie; bcm_tlv_t *wpa2_ie; u8* wpaie = 0; u32 wpaie_len = 0; - u32 wpsie_len = 0; u32 chan_cnt = 0; - u8 wpsie[IE_MAX_LEN]; struct ether_addr bssid; +#ifdef ROAM_CHANNEL_CACHE + chanspec_t chanspec_list[MAX_ROAM_CACHE_NUM]; +#endif + int ret; + WL_DBG(("In\n")); + + if (unlikely(!sme->ssid)) { + WL_ERR(("Invalid ssid\n")); + return -EOPNOTSUPP; + } + CHECK_SYS_UP(wl); /* * Cancel ongoing scan to sync up with sme state machine of cfg80211. */ +#if (defined(BCM4334_CHIP) || !defined(ESCAN_RESULT_PATCH)) if (wl->scan_request) { wl_notify_escan_complete(wl, dev, true, true); } +#endif +#ifdef WL_CFG80211_GON_COLLISION + /* init block gon req count */ + wl->block_gon_req_tx_count = 0; + wl->block_gon_req_rx_count = 0; +#endif /* WL_CFG80211_GON_COLLISION */ +#ifdef ESCAN_RESULT_PATCH + if (sme->bssid) { + memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); + } + else { + bzero(connect_req_bssid, ETHER_ADDR_LEN); + } + bzero(broad_bssid, ETHER_ADDR_LEN); +#endif + + bzero(&bssid, sizeof(bssid)); + if (!wl_get_drv_status(wl, CONNECTED, dev)&& + (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { + if (!ETHER_ISNULLADDR(&bssid)) { + scb_val_t scbval; + wl_set_drv_status(wl, DISCONNECTING, dev); + scbval.val = DOT11_RC_DISASSOC_LEAVING; + memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + + WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n", + MAC2STRDBG(bssid.octet))); + err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), true); + if (unlikely(err)) { + wl_clr_drv_status(wl, DISCONNECTING, dev); + WL_ERR(("error (%d)\n", err)); + return err; + } + while (wl_get_drv_status(wl, DISCONNECTING, dev)) { + WL_ERR(("Waiting for disconnection terminated.\n")); + msleep(20); + } + } else + WL_DBG(("Currently not associated!\n")); + } + /* Clean BSSID */ bzero(&bssid, sizeof(bssid)); - wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID); + if (!wl_get_drv_status(wl, DISCONNECTING, dev)) + wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID); - if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) { + if (p2p_is_on(wl) && (dev != wl_to_prmry_ndev(wl))) { /* we only allow to connect using virtual interface in case of P2P */ - if (p2p_is_on(wl) && is_wps_conn(sme)) { - WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n", - wl_cfgp2p_find_idx(wl, dev), sme->ie_len)); - /* Have to apply WPS IE + P2P IE in assoc req frame */ - wl_cfgp2p_set_management_ie(wl, dev, - wl_cfgp2p_find_idx(wl, dev), VNDR_IE_PRBREQ_FLAG, - wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie, - wl_to_p2p_bss_saved_ie(wl, - P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len); wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); - } else if (p2p_is_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) { - /* This is the connect req after WPS is done [credentials exchanged] - * currently identified with WPA_VERSION_2 . - * Update the previously set IEs with - * the newly received IEs from Supplicant. This will remove the WPS IE from - * the Assoc Req. - */ - WL_DBG(("ASSOC2 p2p index : %d sme->ie_len %d\n", - wl_cfgp2p_find_idx(wl, dev), sme->ie_len)); - wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), - VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); - } - } else if (dev == wl_to_prmry_ndev(wl)) { - /* find the RSN_IE */ - if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, - DOT11_MNG_RSN_ID)) != NULL) { - WL_DBG((" WPA2 IE is found\n")); - } - /* find the WPA_IE */ - if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, - sme->ie_len)) != NULL) { - WL_DBG((" WPA IE is found\n")); - } - if (wpa_ie != NULL || wpa2_ie != NULL) { - wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; - wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; - wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; - wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, - wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); - } else { - wldev_iovar_setbuf(dev, "wpaie", NULL, 0, - wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); - } + /* find the RSN_IE */ + if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE is found\n")); + } + /* find the WPA_IE */ + if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, + sme->ie_len)) != NULL) { + WL_DBG((" WPA IE is found\n")); + } + if (wpa_ie != NULL || wpa2_ie != NULL) { + wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; + wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; + wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; + wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); + } else { + wldev_iovar_setbuf(dev, "wpaie", NULL, 0, + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); + } - /* find the WPSIE */ - memset(wpsie, 0, sizeof(wpsie)); - if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)sme->ie, - sme->ie_len)) != NULL) { - wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN; - memcpy(wpsie, wps_ie, wpsie_len); - } else { - wpsie_len = 0; - } - err = wl_cfgp2p_set_management_ie(wl, dev, -1, - VNDR_IE_ASSOCREQ_FLAG, wpsie, wpsie_len); - if (unlikely(err)) { - return err; - } + err = wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), + VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len); + if (unlikely(err)) { + return err; + } } - if (unlikely(!sme->ssid)) { - WL_ERR(("Invalid ssid\n")); - return -EOPNOTSUPP; +#ifdef ROAM_AP_ENV_DETECTION + if (dhd->roam_env_detection && (wldev_iovar_setint(dev, "roam_env_detection", + AP_ENV_DETECT_NOT_USED) == BCME_OK)) { + s32 roam_trigger[2] = {WL_AUTO_ROAM_TRIGGER, WLC_BAND_ALL}; + err = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), true); + if (unlikely(err)) { + WL_ERR((" failed to restore roam_trigger for auto env detection\n")); + } } +#endif /* ROAM_AP_ENV_DETECTION */ if (chan) { +#ifdef ROAM_CHANNEL_CACHE + wlc_ssid_t ssid; + int band; + + err = wldev_get_band(dev, &band); + if (!err) { + set_roam_band(band); + } + + wl->channel = ieee80211_frequency_to_channel(chan->center_freq); + memcpy(ssid.SSID, sme->ssid, sme->ssid_len); + ssid.SSID_len = sme->ssid_len; + chan_cnt = get_roam_channel_list(wl->channel, chanspec_list, &ssid, ioctl_version); +#else wl->channel = ieee80211_frequency_to_channel(chan->center_freq); chan_cnt = 1; - WL_DBG(("channel (%d), center_req (%d)\n", wl->channel, - chan->center_freq)); +#endif /* ROAM_CHANNEL_CACHE */ + WL_DBG(("channel (%d), center_req (%d), %d channels\n", wl->channel, + chan->center_freq, chan_cnt)); } else wl->channel = 0; #ifdef BCMWAPI_WPI @@ -2578,14 +3117,15 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); - /* Set up join scan parameters */ - ext_join_params->scan.scan_type = -1; - ext_join_params->scan.nprobes = 2; /* increate dwell time to receive probe response or detect Beacon * from target AP at a noisy air only during connect command */ - ext_join_params->scan.active_time = WL_SCAN_ACTIVE_TIME*3; - ext_join_params->scan.passive_time = WL_SCAN_PASSIVE_TIME*3; + ext_join_params->scan.active_time = WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS; + ext_join_params->scan.passive_time = WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS; + /* Set up join scan parameters */ + ext_join_params->scan.scan_type = -1; + ext_join_params->scan.nprobes + = (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS); ext_join_params->scan.home_time = -1; if (sme->bssid) @@ -2594,6 +3134,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN); ext_join_params->assoc.chanspec_num = chan_cnt; if (chan_cnt) { +#ifdef ROAM_CHANNEL_CACHE + memcpy(ext_join_params->assoc.chanspec_list, chanspec_list, + sizeof(chanspec_t) * chan_cnt); +#else u16 channel, band, bw, ctl_sb; chanspec_t chspec; channel = wl->channel; @@ -2606,6 +3150,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ext_join_params->assoc.chanspec_list[0] |= chspec; ext_join_params->assoc.chanspec_list[0] = wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); +#endif /* ROAM_CHANNEL_CACHE */ } ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { @@ -2673,9 +3218,12 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, /* * Cancel ongoing scan to sync up with sme state machine of cfg80211. */ +#if (defined(BCM4334_CHIP) || !defined(ESCAN_RESULT_PATCH)) + /* Let scan aborted by F/W */ if (wl->scan_request) { wl_notify_escan_complete(wl, dev, true, true); } +#endif /* ESCAN_RESULT_PATCH */ wl_set_drv_status(wl, DISCONNECTING, dev); scbval.val = reason_code; memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); @@ -2814,7 +3362,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, if (key.len == 0) { /* key delete */ swap_key_from_BE(&key); - wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { WL_ERR(("key delete error (%d)\n", err)); @@ -2879,10 +3427,9 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } swap_key_from_BE(&key); -#if defined(CONFIG_WIRELESS_EXT) + /* need to guarantee EAPOL 4/4 send out before set key */ dhd_wait_pend8021x(dev); -#endif - wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); @@ -3006,6 +3553,10 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, s32 bssidx = wl_cfgp2p_find_idx(wl, dev); WL_DBG(("Enter\n")); +#ifndef IEEE80211W + if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) + return -EINVAL; +#endif CHECK_SYS_UP(wl); memset(&key, 0, sizeof(key)); @@ -3016,7 +3567,7 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("key index (%d)\n", key_idx)); /* Set the new key/index */ swap_key_from_BE(&key); - wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { if (err == -EINVAL) { @@ -3118,7 +3669,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(wl); if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, - ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); + ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_SMLEN, &wl->ioctl_buf_sync); if (err < 0) { WL_ERR(("GET STA INFO failed, %d\n", err)); return err; @@ -3141,16 +3692,19 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, sta->idle * 1000)); #endif } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { + get_pktcnt_t pktcnt; u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); if (!wl_get_drv_status(wl, CONNECTED, dev) || - (dhd_is_associated(dhd, NULL) == FALSE)) { + (dhd_is_associated(dhd, NULL, &err) == FALSE)) { WL_ERR(("NOT assoc\n")); + if (err == -ERESTARTSYS) + return err; err = -ENODEV; - goto get_station_err; + return err; } if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { - WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n", - MAC2STR(mac), MAC2STR(curmacp))); + WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n", + MAC2STRDBG(mac), MAC2STRDBG(curmacp))); } /* Report the current tx rate */ @@ -3172,13 +3726,24 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("Could not get rssi (%d)\n", err)); goto get_station_err; } - rssi = dtoh32(scb_val.val); + rssi = dtoh32(scb_val.val) + RSSI_OFFSET; sinfo->filled |= STATION_INFO_SIGNAL; sinfo->signal = rssi; WL_DBG(("RSSI %d dBm\n", rssi)); - + err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt, + sizeof(pktcnt), false); + if (!err) { + sinfo->filled |= (STATION_INFO_RX_PACKETS | + STATION_INFO_RX_DROP_MISC | + STATION_INFO_TX_PACKETS | + STATION_INFO_TX_FAILED); + sinfo->rx_packets = pktcnt.rx_good_pkt; + sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt; + sinfo->tx_packets = pktcnt.tx_good_pkt; + sinfo->tx_failed = pktcnt.tx_bad_pkt; + } get_station_err: - if (err) { + if (err && (err != -ERESTARTSYS)) { /* Disconnect due to zero BSSID or error to get RSSI */ WL_ERR(("force cfg80211_disconnected\n")); wl_clr_drv_status(wl, CONNECTED, dev); @@ -3190,6 +3755,24 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, return err; } +/* Function to update sta power save mode for Kernel wifi stack */ +int wl_cfg80211_update_power_mode(struct net_device *dev) +{ + int pm = -1; + int err; + + err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), false); + if (err || (pm == -1)) { + WL_ERR(("error (%d)\n", err)); + } else { + pm = (pm == PM_OFF) ? false : true; + WL_DBG(("%s: %d\n", __func__, pm)); + if (dev->ieee80211_ptr) + dev->ieee80211_ptr->ps = pm; + } + return err; +} + static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, s32 timeout) @@ -3197,17 +3780,27 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, s32 pm; s32 err = 0; struct wl_priv *wl = wiphy_priv(wiphy); + struct net_info *_net_info = wl_get_netinfo_by_netdev(wl, dev); +#ifndef SUPPORT_PM2_ONLY + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); +#endif CHECK_SYS_UP(wl); - if (wl->p2p_net == dev) { + if (wl->p2p_net == dev || _net_info == NULL) { return err; } - pm = PM_OFF; /* enabled ? PM_FAST : PM_OFF; */ + /* android has special hooks to change pm when kernel suspended */ +#ifndef SUPPORT_PM2_ONLY + pm = enabled ? ((dhd->in_suspend) ? PM_MAX : PM_FAST) : PM_OFF; +#else + pm = enabled ? PM_FAST : PM_OFF; +#endif + /* Do not enable the power save after assoc if it is p2p interface */ - if (wl->p2p && wl->p2p->vif_created) { - WL_DBG(("Do not enable the power save for p2p interfaces even after assoc\n")); + if (_net_info->pm_block || wl->vsdb_mode) { + WL_DBG(("Do not enable the power save\n")); pm = PM_OFF; } pm = htod32(pm); @@ -3388,7 +3981,7 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(wl); memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); - memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); + memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", &pmkid.pmkid[0].BSSID)); @@ -3490,17 +4083,21 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, s32 err = BCME_OK; struct wl_priv *wl = wiphy_priv(wiphy); - WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex)); + + WL_DBG(("Enter, ifindex: %d, channel: %d, duration ms (%d) SCANNING ?? %s \n", + dev->ifindex, ieee80211_frequency_to_channel(channel->center_freq), + duration, (wl_get_drv_status(wl, SCANNING, ndev)) ? "YES":"NO")); if (wl->p2p_net == dev) { ndev = wl_to_prmry_ndev(wl); } else { ndev = dev; } - +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST if (wl_get_drv_status(wl, SCANNING, ndev)) { wl_notify_escan_complete(wl, ndev, true, true); } +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ target_channel = ieee80211_frequency_to_channel(channel->center_freq); memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel)); @@ -3509,28 +4106,85 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, if (id == 0) id = ++wl->last_roc_id; *cookie = id; - cfg80211_ready_on_channel(dev, *cookie, channel, - channel_type, duration, GFP_KERNEL); - if (wl->p2p && !wl->p2p->on) { - get_primary_mac(wl, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (wl_get_drv_status(wl, SCANNING, ndev)) { + struct timer_list *_timer; + WL_DBG(("scan is running. go to fake listen state\n")); + + wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); + + if (timer_pending(&wl->p2p->listen_timer)) { + WL_DBG(("cancel current listen timer \n")); + del_timer_sync(&wl->p2p->listen_timer); + } + + _timer = &wl->p2p->listen_timer; + wl_clr_p2p_status(wl, LISTEN_EXPIRED); + + INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0); + + err = BCME_OK; + goto exit; + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +#ifdef WL_CFG80211_SYNC_GON + if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { + /* do not enter listen mode again if we are in listen mode already for next af. + * remain on channel completion will be returned by waiting next af completion. + */ +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); +#else + wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + goto exit; + } +#endif /* WL_CFG80211_SYNC_GON */ + if (wl->p2p && !wl->p2p->on) { /* In case of p2p_listen command, supplicant send remain_on_channel * without turning on P2P */ - + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); p2p_on(wl) = true; - err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0); + } + if (p2p_is_on(wl)) { + err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0); if (unlikely(err)) { goto exit; } +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + err = wl_cfgp2p_discover_listen(wl, target_channel, duration); + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (err == BCME_OK) { + wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); + } else { + /* if failed, firmware may be internal scanning state. + * so other scan request shall not abort it + */ + wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant + * and expire timer will send a completion to the upper layer + */ + err = BCME_OK; } - if (p2p_is_on(wl)) - wl_cfgp2p_discover_listen(wl, target_channel, duration); - exit: + if (err == BCME_OK) { + WL_INFO(("Success\n")); + cfg80211_ready_on_channel(dev, *cookie, channel, + channel_type, duration, GFP_KERNEL); + } else { + WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); + } return err; } @@ -3542,214 +4196,572 @@ wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev WL_DBG((" enter ) netdev_ifidx: %d \n", dev->ifindex)); return err; } -static s32 -wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl) -{ - wl_af_params_t *tx_act_frm; - struct net_device *dev = wl->afx_hdl->dev; - if (!p2p_is_on(wl)) - return -1; - if (dev == wl->p2p_net) { - dev = wl_to_prmry_ndev(wl); - } - - tx_act_frm = wl->afx_hdl->pending_tx_act_frm; - WL_DBG(("Sending the action frame\n")); - wl->afx_hdl->pending_tx_act_frm = NULL; - if (tx_act_frm != NULL) { - /* Suspend P2P discovery's search-listen to prevent it from - * starting a scan or changing the channel. - */ - wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev); - wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); - wl_notify_escan_complete(wl, dev, true, true); - wl_cfgp2p_discover_enable_search(wl, false); - tx_act_frm->channel = wl->afx_hdl->peer_chan; - wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev, - tx_act_frm, wl->afx_hdl->bssidx)) ? false : true; - } - return 0; -} static void wl_cfg80211_afx_handler(struct work_struct *work) { struct afx_hdl *afx_instance; struct wl_priv *wl = wlcfg_drv_priv; + s32 ret = BCME_OK; + afx_instance = container_of(work, struct afx_hdl, work); - if (afx_instance != NULL) { - wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev, - wl->afx_hdl->bssidx, 0); + if (afx_instance != NULL && wl->afx_hdl->is_active) { + if (wl->afx_hdl->is_listen && wl->afx_hdl->my_listen_chan) { + ret = wl_cfgp2p_discover_listen(wl, wl->afx_hdl->my_listen_chan, + (100 * (1 + (random32() % 3)))); /* 100ms ~ 300ms */ + } else { + ret = wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev, + wl->afx_hdl->bssidx, wl->afx_hdl->peer_listen_chan); + } + if (unlikely(ret != BCME_OK)) { + WL_ERR(("ERROR occurred! returned value is (%d)\n", ret)); + if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) + complete(&wl->act_frm_scan); + } } } -static bool -wl_cfg80211_send_at_common_channel(struct wl_priv *wl, - struct net_device *dev, - wl_af_params_t *af_params) +static s32 +wl_cfg80211_af_searching_channel(struct wl_priv *wl, struct net_device *dev) { + u32 max_retry = WL_CHANNEL_SYNC_RETRY; + + if (dev == NULL) + return -1; + WL_DBG((" enter ) \n")); - /* initialize afx_hdl */ - wl->afx_hdl->pending_tx_act_frm = af_params; - wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev); - wl->afx_hdl->dev = dev; - wl->afx_hdl->retry = 0; - wl->afx_hdl->peer_chan = WL_INVALID; - wl->afx_hdl->ack_recv = false; - memcpy(wl->afx_hdl->pending_tx_dst_addr.octet, - af_params->action_frame.da.octet, - sizeof(wl->afx_hdl->pending_tx_dst_addr.octet)); - /* Loop to wait until we have sent the pending tx action frame or the + + wl_set_drv_status(wl, FINDING_COMMON_CHANNEL, dev); + wl->afx_hdl->is_active = TRUE; + + /* Loop to wait until we find a peer's channel or the * pending action frame tx is cancelled. */ - while ((wl->afx_hdl->retry < WL_CHANNEL_SYNC_RETRY) && + while ((wl->afx_hdl->retry < max_retry) && (wl->afx_hdl->peer_chan == WL_INVALID)) { - wl_set_drv_status(wl, SENDING_ACT_FRM, dev); + wl->afx_hdl->is_listen = FALSE; wl_set_drv_status(wl, SCANNING, dev); WL_DBG(("Scheduling the action frame for sending.. retry %d\n", wl->afx_hdl->retry)); - /* Do find_peer_for_action */ + /* search peer on peer's listen channel */ schedule_work(&wl->afx_hdl->work); - wait_for_completion(&wl->act_frm_scan); + wait_for_completion_timeout(&wl->act_frm_scan, + msecs_to_jiffies(MAX_WAIT_TIME)); + + if ((wl->afx_hdl->peer_chan != WL_INVALID) || + !(wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev))) + break; + + if (wl->afx_hdl->my_listen_chan) { + WL_DBG(("Scheduling Listen peer in my listen channel = %d\n", + wl->afx_hdl->my_listen_chan)); + /* listen on my listen channel */ + wl->afx_hdl->is_listen = TRUE; + schedule_work(&wl->afx_hdl->work); + wait_for_completion_timeout(&wl->act_frm_scan, + msecs_to_jiffies(MAX_WAIT_TIME)); + } + if (!wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev)) + break; wl->afx_hdl->retry++; + + WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); } - if (wl->afx_hdl->peer_chan != WL_INVALID) - wl_cfg80211_send_pending_tx_act_frm(wl); - else { - WL_ERR(("Couldn't find the peer after %d retries\n", - wl->afx_hdl->retry)); - } - wl->afx_hdl->dev = NULL; - wl->afx_hdl->bssidx = WL_INVALID; - wl_clr_drv_status(wl, SENDING_ACT_FRM, dev); - if (wl->afx_hdl->ack_recv) - return true; /* ACK */ - else - return false; /* NO ACK */ + + wl->afx_hdl->is_active = FALSE; + + wl_clr_drv_status(wl, SCANNING, dev); + wl_clr_drv_status(wl, FINDING_COMMON_CHANNEL, dev); + + return (wl->afx_hdl->peer_chan); } -static s32 -wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, - struct ieee80211_channel *channel, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8* buf, size_t len, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) - bool no_cck, +struct p2p_config_af_params { + s32 max_tx_retry; /* max tx retry count if tx no ack */ + /* To make sure to send successfully action frame, we have to turn off mpc + * 0: off, 1: on, (-1): do nothing + */ + s32 mpc_onoff; +#ifdef WL_CFG80211_GON_COLLISION + /* drop tx go nego request if go nego collision occurs */ + bool drop_tx_req; #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) - bool dont_wait_for_ack, +#ifdef WL_CFG80211_SYNC_GON + bool extra_listen; #endif - u64 *cookie) + bool search_channel; /* 1: search peer's channel to send af */ +}; + +static s32 +wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, + wl_action_frame_t *action_frame, wl_af_params_t *af_params, + struct p2p_config_af_params *config_af_params) { - wl_action_frame_t *action_frame; - wl_af_params_t *af_params; - wifi_p2p_ie_t *p2p_ie; - wpa_ie_fixed_t *wps_ie; - scb_val_t scb_val; - wifi_wfd_ie_t *wfd_ie; - const struct ieee80211_mgmt *mgmt; - struct wl_priv *wl = wiphy_priv(wiphy); - struct net_device *dev = NULL; s32 err = BCME_OK; - s32 bssidx = 0; - u32 p2pie_len = 0; - u32 wpsie_len = 0; - u32 wfdie_len = 0; - u32 id; - u32 retry = 0; - bool ack = false; - wifi_p2p_pub_act_frame_t *act_frm = NULL; - wifi_p2p_action_frame_t *p2p_act_frm = NULL; - wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; - s8 eabuf[ETHER_ADDR_STR_LEN]; + struct wl_priv *wl = wiphy_priv(wiphy); + wifi_p2p_pub_act_frame_t *act_frm = + (wifi_p2p_pub_act_frame_t *) (action_frame->data); - WL_DBG(("Enter \n")); + /* initialize default value */ +#ifdef WL_CFG80211_GON_COLLISION + config_af_params->drop_tx_req = false; +#endif +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = true; +#endif + config_af_params->search_channel = false; + config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; + config_af_params->mpc_onoff = -1; - if (ndev == wl->p2p_net) { - dev = wl_to_prmry_ndev(wl); - } else { - /* If TX req is for any valid ifidx. Use as is */ - dev = ndev; - } + switch (act_frm->subtype) { + case P2P_PAF_GON_REQ: { + WL_DBG(("P2P: GO_NEG_PHASE status set \n")); + wl_set_p2p_status(wl, GO_NEG_PHASE); - /* find bssidx based on ndev */ - bssidx = wl_cfgp2p_find_idx(wl, dev); - if (bssidx == -1) { + config_af_params->mpc_onoff = 0; + config_af_params->search_channel = true; + wl->next_af_subtype = act_frm->subtype + 1; - WL_ERR(("Can not find the bssidx for dev( %p )\n", dev)); - return -ENODEV; + /* increase dwell time to wait for RESP frame */ + af_params->dwell_time = WL_MED_DWELL_TIME; + +#ifdef WL_CFG80211_GON_COLLISION + config_af_params->drop_tx_req = true; +#endif /* WL_CFG80211_GON_COLLISION */ + break; } - if (p2p_is_on(wl)) { - /* Suspend P2P discovery search-listen to prevent it from changing the - * channel. - */ - if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) { - WL_ERR(("Can not disable discovery mode\n")); - return -EFAULT; - } + case P2P_PAF_GON_RSP: { + wl->next_af_subtype = act_frm->subtype + 1; + /* increase dwell time to wait for CONF frame */ + af_params->dwell_time = WL_MED_DWELL_TIME; + break; } - *cookie = 0; - id = wl->send_action_id++; - if (id == 0) - id = wl->send_action_id++; - *cookie = id; - mgmt = (const struct ieee80211_mgmt *)buf; - if (ieee80211_is_mgmt(mgmt->frame_control)) { - if (ieee80211_is_probe_resp(mgmt->frame_control)) { - s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; - s32 ie_len = len - ie_offset; - if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len)) - != NULL) { - /* Total length of P2P Information Element */ - p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); - } - if ((wfd_ie = wl_cfgp2p_find_wfdie((u8 *)(buf + ie_offset), ie_len)) - != NULL) { - /* Total length of WFD Information Element */ - wfdie_len = wfd_ie->len + sizeof(wfd_ie->len) + sizeof(wfd_ie->id); - } - if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len)) - != NULL) { - /* Order of Vendor IE is 1) WPS IE + - * 2) P2P IE created by supplicant - * So, it is ok to find start address of WPS IE - * to save IEs - */ - wpsie_len = wps_ie->length + sizeof(wps_ie->length) + - sizeof(wps_ie->tag); - wl_cfgp2p_set_management_ie(wl, dev, bssidx, - VNDR_IE_PRBRSP_FLAG, - (u8 *)wps_ie, wpsie_len + p2pie_len + wfdie_len); - } - cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); - goto exit; - } else if (ieee80211_is_disassoc(mgmt->frame_control) || - ieee80211_is_deauth(mgmt->frame_control)) { - memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); - scb_val.val = mgmt->u.disassoc.reason_code; - wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, - sizeof(scb_val_t), true); - WL_DBG(("Disconnect STA : %s\n", - bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf))); - cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); - goto exit; + case P2P_PAF_GON_CONF: { + /* If we reached till GO Neg confirmation reset the filter */ + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); + wl_clr_p2p_status(wl, GO_NEG_PHASE); + + /* turn on mpc again if go nego is done */ + config_af_params->mpc_onoff = 1; + + /* minimize dwell time */ + af_params->dwell_time = WL_MIN_DWELL_TIME; + +#ifdef WL_CFG80211_GON_COLLISION + /* if go nego formation done, clear it */ + wl->block_gon_req_tx_count = 0; + wl->block_gon_req_rx_count = 0; +#endif /* WL_CFG80211_GON_COLLISION */ +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + } + case P2P_PAF_INVITE_REQ: { + config_af_params->search_channel = true; + wl->next_af_subtype = act_frm->subtype + 1; - } else if (ieee80211_is_action(mgmt->frame_control)) { - /* Abort the dwell time of any previous off-channel - * action frame that may be still in effect. Sending - * off-channel action frames relies on the driver's - * scan engine. If a previous off-channel action frame - * tx is still in progress (including the dwell time), - * then this new action frame will not be sent out. - */ - wl_notify_escan_complete(wl, dev, true, true); + /* increase dwell time */ + af_params->dwell_time = WL_MED_DWELL_TIME; + break; + } + case P2P_PAF_INVITE_RSP: + /* minimize dwell time */ + af_params->dwell_time = WL_MIN_DWELL_TIME; +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + case P2P_PAF_DEVDIS_REQ: { + config_af_params->search_channel = true; + wl->next_af_subtype = act_frm->subtype + 1; + /* maximize dwell time to wait for RESP frame */ + af_params->dwell_time = WL_LONG_DWELL_TIME; + break; + } + case P2P_PAF_DEVDIS_RSP: + /* minimize dwell time */ + af_params->dwell_time = WL_MIN_DWELL_TIME; +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + case P2P_PAF_PROVDIS_REQ: { + if (IS_PROV_DISC_WITHOUT_GROUP_ID(&act_frm->elts[0], + action_frame->len)) { + config_af_params->search_channel = true; } - } else { - WL_ERR(("Driver only allows MGMT packet type\n")); - goto exit; + config_af_params->mpc_onoff = 0; + wl->next_af_subtype = act_frm->subtype + 1; + /* increase dwell time to wait for RESP frame */ + af_params->dwell_time = WL_MED_DWELL_TIME; + break; + } + case P2P_PAF_PROVDIS_RSP: { + wl->next_af_subtype = P2P_PAF_GON_REQ; + /* increase dwell time to MED level */ + af_params->dwell_time = WL_MED_DWELL_TIME; +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + } + default: + WL_DBG(("Unknown p2p pub act frame subtype: %d\n", + act_frm->subtype)); + err = BCME_BADARG; + } + return err; +} + + +static bool +wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, + struct net_device *ndev, wl_af_params_t *af_params, + wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) +{ + struct wl_priv *wl = wiphy_priv(wiphy); + bool ack = false; + u8 category, action; + s32 tx_retry; + struct p2p_config_af_params config_af_params; +#ifdef VSDB + ulong off_chan_started_jiffies = 0; +#endif + +#ifdef WL11U + if (!af_params || !action_frame || (!p2p_is_on(wl) && !wl->wl11u)) +#else + if (!af_params || !action_frame || !p2p_is_on(wl)) + return false; +#endif + + wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len); + + category = action_frame->data[DOT11_ACTION_CAT_OFF]; + action = action_frame->data[DOT11_ACTION_ACT_OFF]; + + /* initialize variables */ + tx_retry = 0; + wl->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; + config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY; + config_af_params.mpc_onoff = -1; + config_af_params.search_channel = false; +#ifdef WL_CFG80211_GON_COLLISION + config_af_params.drop_tx_req = false; +#endif +#ifdef WL_CFG80211_SYNC_GON + config_af_params.extra_listen = false; +#endif + + /* config parameters */ + /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */ + if (category == DOT11_ACTION_CAT_PUBLIC) { + if ((action == P2P_PUB_AF_ACTION) && + (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) { + /* p2p public action frame process */ + if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy, + action_frame, af_params, &config_af_params)) { + WL_DBG(("Unknown subtype.\n")); + } + +#ifdef WL_CFG80211_GON_COLLISION + if (config_af_params.drop_tx_req) { + if (wl->block_gon_req_tx_count) { + /* drop gon req tx action frame */ + WL_DBG(("Drop gon req tx action frame: count %d\n", + wl->block_gon_req_tx_count)); + goto exit; + } + } +#endif /* WL_CFG80211_GON_COLLISION */ + } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) { + /* service discovery process */ + if (action == P2PSD_ACTION_ID_GAS_IREQ || + action == P2PSD_ACTION_ID_GAS_IREQ) { + /* configure service discovery query frame */ + + config_af_params.search_channel = true; + + /* save next af suptype to cancel remained dwell time */ + wl->next_af_subtype = action + 1; + + af_params->dwell_time = WL_MED_DWELL_TIME; + } else if (action == P2PSD_ACTION_ID_GAS_IRESP || + action == P2PSD_ACTION_ID_GAS_IRESP) { + /* configure service discovery response frame */ + af_params->dwell_time = WL_MIN_DWELL_TIME; + } else { + WL_DBG(("Unknown action type: %d\n", action)); + } + } else { + WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n", + category, action, action_frame_len)); + } + } else if (category == P2P_AF_CATEGORY) { + /* do not configure anything. it will be sent with a default configuration */ + } else { + WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n", + category, action)); + } + + /* To make sure to send successfully action frame, we have to turn off mpc */ + if (config_af_params.mpc_onoff == 0) { + wldev_iovar_setint(dev, "mpc", 0); + } + + /* validate channel and p2p ies */ + if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) && + wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { + config_af_params.search_channel = true; + } else { + config_af_params.search_channel = false; + } + +#ifdef WL11U + if (ndev == wl_to_prmry_ndev(wl)) + config_af_params.search_channel = false; +#endif /* WL11U */ + +#ifdef VSDB + /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ + if (wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { + msleep(50); + } +#endif + + /* if scan is ongoing, abort current scan. */ + if (wl_get_drv_status_all(wl, SCANNING)) { + wl_notify_escan_complete(wl, ndev, true, true); + } + + /* set status and destination address before sending af */ + if (wl->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { + /* set this status to cancel the remained dwell time in rx process */ + wl_set_drv_status(wl, WAITING_NEXT_ACT_FRM, dev); + } + wl_set_drv_status(wl, SENDING_ACT_FRM, dev); + memcpy(wl->afx_hdl->tx_dst_addr.octet, + af_params->action_frame.da.octet, + sizeof(wl->afx_hdl->tx_dst_addr.octet)); + + /* save af_params for rx process */ + wl->afx_hdl->pending_tx_act_frm = af_params; + + /* search peer's channel */ + if (config_af_params.search_channel) { + /* initialize afx_hdl */ + wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev); + wl->afx_hdl->dev = dev; + wl->afx_hdl->retry = 0; + wl->afx_hdl->peer_chan = WL_INVALID; + + if (wl_cfg80211_af_searching_channel(wl, dev) == WL_INVALID) { + WL_ERR(("couldn't find peer's channel.\n")); + goto exit; + } + + /* Suspend P2P discovery's search-listen to prevent it from + * starting a scan or changing the channel. + */ + wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); +/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary */ +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_notify_escan_complete(wl, dev, true, true); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + wl_cfgp2p_discover_enable_search(wl, false); + + /* update channel */ + af_params->channel = wl->afx_hdl->peer_chan; + } + +#ifdef VSDB + off_chan_started_jiffies = jiffies; +#endif /* VSDB */ + + /* Now send a tx action frame */ + ack = wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx) ? false : true; + + /* if failed, retry it. tx_retry_max value is configure by .... */ + while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) { +#ifdef VSDB + if (af_params->channel) { + if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) > + OFF_CHAN_TIME_THRESHOLD_MS) { + WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); + off_chan_started_jiffies = jiffies; + } + } +#endif /* VSDB */ + ack = wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx) ? + false : true; + } + if (ack == false) { + WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry)); + } +exit: + /* Clear SENDING_ACT_FRM after all sending af is done */ + wl_clr_drv_status(wl, SENDING_ACT_FRM, dev); + +#ifdef WL_CFG80211_SYNC_GON + /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. + * if we coundn't get the next action response frame and dongle does not keep + * the dwell time, go to listen state again to get next action response frame. + */ + if (ack && config_af_params.extra_listen && +#ifdef WL_CFG80211_GON_COLLISION + !wl->block_gon_req_tx_count && +#endif /* WL_CFG80211_GON_COLLISION */ + wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM) && + wl->af_sent_channel == wl->afx_hdl->my_listen_chan) { + s32 extar_listen_time; + + extar_listen_time = af_params->dwell_time - + jiffies_to_msecs(jiffies - wl->af_tx_sent_jiffies); + + if (extar_listen_time > 50) { + wl_set_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, dev); + WL_DBG(("Wait more time! actual af time:%d," + "calculated extar listen:%d\n", + af_params->dwell_time, extar_listen_time)); + if (wl_cfgp2p_discover_listen(wl, wl->af_sent_channel, + extar_listen_time + 100) == BCME_OK) { + wait_for_completion_timeout(&wl->wait_next_af, + msecs_to_jiffies(extar_listen_time + 100 + 300)); + } + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, dev); + } + } +#endif /* WL_CFG80211_SYNC_GON */ + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, dev); + + if (wl->afx_hdl->pending_tx_act_frm) + wl->afx_hdl->pending_tx_act_frm = NULL; + + WL_INFO(("-- sending Action Frame is %s, listen chan: %d\n", + (ack) ? "Succeeded!!":"Failed!!", wl->afx_hdl->my_listen_chan)); + +#ifdef WL_CFG80211_GON_COLLISION + if (wl->block_gon_req_tx_count) { + wl->block_gon_req_tx_count--; + /* if ack is ture, supplicant will wait more time(100ms). + * so we will return it as a success to get more time . + */ + ack = true; + } +#endif /* WL_CFG80211_GON_COLLISION */ + + /* if all done, turn mpc on again */ + if (config_af_params.mpc_onoff == 1) { + wldev_iovar_setint(dev, "mpc", 1); + } + + return ack; +} + +static s32 +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, + struct ieee80211_channel *channel, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8* buf, size_t len, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) + bool no_cck, +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) + bool dont_wait_for_ack, +#endif + u64 *cookie) +{ + wl_action_frame_t *action_frame; + wl_af_params_t *af_params; + scb_val_t scb_val; + const struct ieee80211_mgmt *mgmt; + struct wl_priv *wl = wiphy_priv(wiphy); + struct net_device *dev = NULL; + s32 err = BCME_OK; + s32 bssidx = 0; + u32 id; + bool ack = false; + s8 eabuf[ETHER_ADDR_STR_LEN]; + + WL_DBG(("Enter \n")); + + if (ndev == wl->p2p_net) { + dev = wl_to_prmry_ndev(wl); + } else { + /* If TX req is for any valid ifidx. Use as is */ + dev = ndev; + } + + /* find bssidx based on ndev */ + bssidx = wl_cfgp2p_find_idx(wl, dev); + if (bssidx == -1) { + + WL_ERR(("Can not find the bssidx for dev( %p )\n", dev)); + return -ENODEV; + } + if (p2p_is_on(wl)) { + /* Suspend P2P discovery search-listen to prevent it from changing the + * channel. + */ + if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) { + WL_ERR(("Can not disable discovery mode\n")); + return -EFAULT; + } + } + *cookie = 0; + id = wl->send_action_id++; + if (id == 0) + id = wl->send_action_id++; + *cookie = id; + mgmt = (const struct ieee80211_mgmt *)buf; + if (ieee80211_is_mgmt(mgmt->frame_control)) { + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + s32 ie_len = len - ie_offset; + if (dev == wl_to_prmry_ndev(wl)) + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + wl_cfgp2p_set_management_ie(wl, dev, bssidx, + VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); + cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); + goto exit; + } else if (ieee80211_is_disassoc(mgmt->frame_control) || + ieee80211_is_deauth(mgmt->frame_control)) { + memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); + scb_val.val = mgmt->u.disassoc.reason_code; + err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t), true); + if (err < 0) + WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err)); + WL_DBG(("Disconnect STA : %s scb_val.val %d\n", + bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), + scb_val.val)); + wl_delay(400); + cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); + goto exit; + + } else if (ieee80211_is_action(mgmt->frame_control)) { + /* Abort the dwell time of any previous off-channel + * action frame that may be still in effect. Sending + * off-channel action frames relies on the driver's + * scan engine. If a previous off-channel action frame + * tx is still in progress (including the dwell time), + * then this new action frame will not be sent out. + */ +/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary. + * And previous off-channel action frame must be ended before new af tx. + */ +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_notify_escan_complete(wl, dev, true, true); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + } + + } else { + WL_ERR(("Driver only allows MGMT packet type\n")); + goto exit; } af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); @@ -3777,98 +4789,23 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, af_params->channel = ieee80211_frequency_to_channel(channel->center_freq); - if (channel->band == IEEE80211_BAND_5GHZ) { - WL_DBG(("5GHz channel %d", af_params->channel)); - err = wldev_ioctl(dev, WLC_SET_CHANNEL, - &af_params->channel, sizeof(af_params->channel), true); - if (err < 0) { - WL_ERR(("WLC_SET_CHANNEL error %d\n", err)); - } - } + /* Save listen_chan for searching common channel */ + wl->afx_hdl->peer_listen_chan = af_params->channel; + WL_DBG(("channel from upper layer %d\n", wl->afx_hdl->peer_listen_chan)); - /* Add the dwell time + /* Add the default dwell time * Dwell time to stay off-channel to wait for a response action frame * after transmitting an GO Negotiation action frame */ af_params->dwell_time = WL_DWELL_TIME; memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); - if (wl_cfgp2p_is_pub_action(action_frame->data, action_frame->len)) { - act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); - WL_DBG(("P2P PUB action_frame->len: %d chan %d category %d subtype %d\n", - action_frame->len, af_params->channel, - act_frm->category, act_frm->subtype)); - } else if (wl_cfgp2p_is_p2p_action(action_frame->data, action_frame->len)) { - p2p_act_frm = (wifi_p2p_action_frame_t *) (action_frame->data); - WL_DBG(("P2P action_frame->len: %d chan %d category %d subtype %d\n", - action_frame->len, af_params->channel, - p2p_act_frm->category, p2p_act_frm->subtype)); - } else if (wl_cfgp2p_is_gas_action(action_frame->data, action_frame->len)) { - sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) (action_frame->data); - WL_DBG(("Service Discovery action_frame->len: %d chan %d category %d action %d\n", - action_frame->len, af_params->channel, - sd_act_frm->category, sd_act_frm->action)); - - } - wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len); - /* - * To make sure to send successfully action frame, we have to turn off mpc - */ - - if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) || - (act_frm->subtype == P2P_PAF_GON_RSP) || - (act_frm->subtype == P2P_PAF_GON_CONF) || - (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) { - wldev_iovar_setint(dev, "mpc", 0); - } - - if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) { - af_params->dwell_time = WL_LONG_DWELL_TIME; - } else if (act_frm && - (act_frm->subtype == P2P_PAF_PROVDIS_REQ || - act_frm->subtype == P2P_PAF_PROVDIS_RSP || - act_frm->subtype == P2P_PAF_GON_RSP)) { - af_params->dwell_time = WL_MED_DWELL_TIME; - } - - if (IS_P2P_SOCIAL(af_params->channel) && - (IS_P2P_PUB_ACT_REQ(act_frm, action_frame->len) || - IS_GAS_REQ(sd_act_frm, action_frame->len)) && - wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { - /* channel offload require P2P IE for Probe request - * otherwise, we will use wl_cfgp2p_tx_action_frame directly. - * channel offload for action request frame - */ - - /* channel offload for action request frame */ - ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params); - } else { - ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; - if (!ack) { - if (wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { - /* if the NO ACK occurs, the peer device will be on - * listen channel of the peer - * So, we have to find the peer and send action frame on - * that channel. - */ - ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params); - } else { - for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) { - ack = (wl_cfgp2p_tx_action_frame(wl, dev, - af_params, bssidx)) ? false : true; - if (ack) - break; - } - } - - } + ack = wl_cfg80211_send_action_frame(wiphy, dev, ndev, af_params, + action_frame, action_frame->len, bssidx); - } cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); - if (act_frm && act_frm->subtype == P2P_PAF_GON_CONF) { - wldev_iovar_setint(dev, "mpc", 1); - } + kfree(af_params); exit: return err; @@ -3920,20 +4857,75 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { - s32 channel; + s32 _chan; +#ifdef HT40_GO + s32 center_chan; + chanspec_t chspec = 0; +#endif s32 err = BCME_OK; struct wl_priv *wl = wiphy_priv(wiphy); if (wl->p2p_net == dev) { dev = wl_to_prmry_ndev(wl); } - channel = ieee80211_frequency_to_channel(chan->center_freq); - WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", - dev->ifindex, channel_type, channel)); - err = wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), true); + _chan = ieee80211_frequency_to_channel(chan->center_freq); + WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", + dev->ifindex, channel_type, _chan)); + +#ifdef NOT_YET + switch (channel_type) { + case NL80211_CHAN_HT40MINUS: + /* secondary channel is below the control channel */ + chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_UPPER); + break; + case NL80211_CHAN_HT40PLUS: + /* secondary channel is above the control channel */ + chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_LOWER); + break; + default: + chspec = CH20MHZ_CHSPEC(channel); + + } +#endif /* NOT_YET */ +#ifdef HT40_GO + switch (_chan) { + /* adjust channel to center of 40MHz band */ + case 40: + case 48: + case 153: + case 161: + if (_chan <= (MAXCHANNEL - CH_20MHZ_APART)) + center_chan = _chan - CH_10MHZ_APART; + chspec = CH40MHZ_CHSPEC(center_chan, WL_CHANSPEC_CTL_SB_UPPER); + break; + case 36: + case 44: + case 149: + case 157: + if (_chan <= (MAXCHANNEL - CH_20MHZ_APART)) + center_chan = _chan + CH_10MHZ_APART; + chspec = CH40MHZ_CHSPEC(center_chan, WL_CHANSPEC_CTL_SB_LOWER); + break; + default: + chspec = CH20MHZ_CHSPEC(_chan); + break; + } + + chspec = wl_chspec_host_to_driver(chspec); + if ((err = wldev_iovar_setint(dev, "chanspec", chspec)) == BCME_BADCHAN) { + err = wldev_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), true); + if (err < 0) { + WL_ERR(("WLC_SET_CHANNEL error %d" + "chip may not be supporting this channel\n", err)); + } + } +#else + err = wldev_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), true); if (err < 0) { - WL_ERR(("WLC_SET_CHANNEL error %d chip may not be supporting this channel\n", err)); + WL_ERR(("WLC_SET_CHANNEL error %d" + "chip may not be supporting this channel\n", err)); } +#endif /* HT40_GO */ return err; } @@ -3974,10 +4966,14 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) u32 pval = 0; u32 gval = 0; u32 wpa_auth = 0; - u8* tmp; wpa_suite_mcast_t *mcast; wpa_suite_ucast_t *ucast; wpa_suite_auth_key_mgmt_t *mgmt; + + u16 suite_count; + u8 rsn_cap[2]; + u32 wme_bss_disable; + if (wpa2ie == NULL) goto exit; @@ -3985,8 +4981,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) len = wpa2ie->len; /* check the mcast cipher */ mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; - tmp = mcast->oui; - switch (tmp[DOT11_OUI_LEN]) { + switch (mcast->type) { case WPA_CIPHER_NONE: gval = 0; break; @@ -4009,12 +5004,13 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) WL_ERR(("No Security Info\n")); break; } - len -= WPA_SUITE_LEN; + if ((len -= WPA_SUITE_LEN) <= 0) + return BCME_BADLEN; + /* check the unicast cipher */ ucast = (wpa_suite_ucast_t *)&mcast[1]; - ltoh16_ua(&ucast->count); - tmp = ucast->list[0].oui; - switch (tmp[DOT11_OUI_LEN]) { + suite_count = ltoh16_ua(&ucast->count); + switch (ucast->list[0].type) { case WPA_CIPHER_NONE: pval = 0; break; @@ -4036,13 +5032,15 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) default: WL_ERR(("No Security Info\n")); } + if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0) + return BCME_BADLEN; + /* FOR WPS , set SEC_OW_ENABLED */ wsec = (pval | gval | SES_OW_ENABLED); /* check the AKM */ - mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1]; - ltoh16_ua(&mgmt->count); - tmp = (u8 *)&mgmt->list[0]; - switch (tmp[DOT11_OUI_LEN]) { + mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; + suite_count = ltoh16_ua(&mgmt->count); + switch (mgmt->list[0].type) { case RSN_AKM_NONE: wpa_auth = WPA_AUTH_NONE; break; @@ -4055,6 +5053,27 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) default: WL_ERR(("No Key Mgmt Info\n")); } + + if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { + rsn_cap[0] = *(u8 *)&mgmt->list[suite_count]; + rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1); + + if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) { + wme_bss_disable = 0; + } else { + wme_bss_disable = 1; + } + + /* set wme_bss_disable to sync RSN Capabilities */ + err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx); + if (err < 0) { + WL_ERR(("wme_bss_disable error %d\n", err)); + return BCME_ERROR; + } + } else { + WL_DBG(("There is no RSN Capabilities. remained len %d\n", len)); + } + /* set auth */ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); if (err < 0) { @@ -4223,122 +5242,188 @@ wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) return 0; } -#if 0 static s32 -wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info) +wl_cfg80211_bcn_validate_sec( + struct net_device *dev, + struct parsed_ies *ies, + u32 dev_role, + s32 bssidx) { - s32 err = BCME_OK; - bcm_tlv_t *ssid_ie; - wlc_ssid_t ssid; - struct wl_priv *wl = wiphy_priv(wiphy); - struct wl_join_params join_params; - wpa_ie_fixed_t *wps_ie; - wpa_ie_fixed_t *wpa_ie; - bcm_tlv_t *wpa2_ie; - wifi_p2p_ie_t *p2p_ie; - wifi_wfd_ie_t *wfd_ie; - bool is_bssup = false; - bool update_bss = false; - bool pbc = false; - u16 wpsie_len = 0; - u16 p2pie_len = 0; - u32 wfdie_len = 0; - u8 beacon_ie[IE_MAX_LEN]; - s32 ie_offset = 0; - s32 bssidx = 0; - s32 infra = 1; - s32 join_params_size = 0; - s32 ap = 0; - WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", - info->interval, info->dtim_period, info->head_len, info->tail_len)); + struct wl_priv *wl = wlcfg_drv_priv; - if (wl->p2p_net == dev) { - dev = wl_to_prmry_ndev(wl); - } + if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) { + /* For P2P GO, the sec type is WPA2-PSK */ + WL_DBG(("P2P GO: validating wpa2_ie")); + if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0) + return BCME_ERROR; + + } else if (dev_role == NL80211_IFTYPE_AP) { + + WL_DBG(("SoftAP: validating security")); + /* If wpa2_ie or wpa_ie is present validate it */ + if ((ies->wpa2_ie || ies->wpa_ie) && + ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || + wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) { + wl->ap_info->security_mode = false; + return BCME_ERROR; + } - bssidx = wl_cfgp2p_find_idx(wl, dev); - if (p2p_is_on(wl) && - (bssidx == wl_to_p2p_bss_bssidx(wl, - P2PAPI_BSSCFG_CONNECTION))) { - memset(beacon_ie, 0, sizeof(beacon_ie)); - /* We don't need to set beacon for P2P_GO, - * but need to parse ssid from beacon_parameters - * because there is no way to set ssid - */ - ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; - /* find the SSID */ - if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], - info->head_len - ie_offset, - DOT11_MNG_SSID_ID)) != NULL) { - memcpy(wl->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len); - wl->p2p->ssid.SSID_len = ssid_ie->len; - WL_DBG(("SSID (%s) in Head \n", ssid_ie->data)); + wl->ap_info->security_mode = true; + if (wl->ap_info->rsn_ie) { + kfree(wl->ap_info->rsn_ie); + wl->ap_info->rsn_ie = NULL; + } + if (wl->ap_info->wpa_ie) { + kfree(wl->ap_info->wpa_ie); + wl->ap_info->wpa_ie = NULL; + } + if (wl->ap_info->wps_ie) { + kfree(wl->ap_info->wps_ie); + wl->ap_info->wps_ie = NULL; + } + if (ies->wpa_ie != NULL) { + /* WPAIE */ + wl->ap_info->rsn_ie = NULL; + wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, + ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else if (ies->wpa2_ie != NULL) { + /* RSNIE */ + wl->ap_info->wpa_ie = NULL; + wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, + ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } - } else { - WL_ERR(("No SSID in beacon \n")); + if (!ies->wpa2_ie && !ies->wpa_ie) { + wl_validate_opensecurity(dev, bssidx); + wl->ap_info->security_mode = false; } - /* find the WPSIE */ - if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) { - wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; - /* - * Should be compared with saved ie before saving it - */ - wl_validate_wps_ie((char *) wps_ie, &pbc); - memcpy(beacon_ie, wps_ie, wpsie_len); - } else { - WL_ERR(("No WPSIE in beacon \n")); + if (ies->wps_ie) { + wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); } + } + return 0; - /* find the P2PIE */ - if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) { - /* Total length of P2P Information Element */ - p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); - memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len); +} - } else { - WL_ERR(("No P2PIE in beacon \n")); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +static s32 wl_cfg80211_bcn_set_params( + struct cfg80211_ap_settings *info, + struct net_device *dev, + u32 dev_role, s32 bssidx) +{ + struct wl_priv *wl = wlcfg_drv_priv; + s32 err = BCME_OK; + + WL_DBG(("interval (%d) \ndtim_period (%d) \n", + info->beacon_interval, info->dtim_period)); + + if (info->beacon_interval) { + if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, + &info->beacon_interval, sizeof(s32), true)) < 0) { + WL_ERR(("Beacon Interval Set Error, %d\n", err)); + return err; } + } - /* find the WFD IEs */ - if ((wfd_ie = wl_cfgp2p_find_wfdie((u8 *)info->tail, info->tail_len)) != NULL) { - /* Total length of P2P Information Element */ - wfdie_len = wfd_ie->len + sizeof(wfd_ie->len) + sizeof(wfd_ie->id); - if ((wpsie_len + p2pie_len + wfdie_len) < IE_MAX_LEN) { - memcpy(&beacon_ie[wpsie_len + p2pie_len], wfd_ie, wfdie_len); - } else { - WL_ERR(("Found WFD IE but there is no space, (%d)(%d)(%d)\n", - wpsie_len, p2pie_len, wfdie_len)); - wfdie_len = 0; - } - } else { - WL_ERR(("No WFDIE in beacon \n")); + if (info->dtim_period) { + if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, + &info->dtim_period, sizeof(s32), true)) < 0) { + WL_ERR(("DTIM Interval Set Error, %d\n", err)); + return err; } - /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); - wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, - beacon_ie, wpsie_len + p2pie_len + wfdie_len); + } - /* find the RSN_IE */ - if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, - DOT11_MNG_RSN_ID)) != NULL) { - WL_DBG((" WPA2 IE is found\n")); + if ((info->ssid) && (info->ssid_len > 0) && + (info->ssid_len <= 32)) { + WL_DBG(("SSID (%s) len:%d \n", info->ssid, info->ssid_len)); + if (dev_role == NL80211_IFTYPE_AP) { + /* Store the hostapd SSID */ + memset(wl->hostapd_ssid.SSID, 0x00, 32); + memcpy(wl->hostapd_ssid.SSID, info->ssid, info->ssid_len); + wl->hostapd_ssid.SSID_len = info->ssid_len; + } else { + /* P2P GO */ + memset(wl->p2p->ssid.SSID, 0x00, 32); + memcpy(wl->p2p->ssid.SSID, info->ssid, info->ssid_len); + wl->p2p->ssid.SSID_len = info->ssid_len; } + } + + if (info->hidden_ssid) { + if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) + WL_ERR(("failed to set hidden : %d\n", err)); + WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid)); + } + + return err; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ + +static s32 +wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies) +{ + s32 err = BCME_OK; + + memset(ies, 0, sizeof(struct parsed_ies)); + + /* find the WPSIE */ + if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) { + WL_DBG(("WPSIE in beacon \n")); + ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; + } else { + WL_ERR(("No WPSIE in beacon \n")); + } + + /* find the RSN_IE */ + if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE found\n")); + ies->wpa2_ie_len = ies->wpa2_ie->len; + } + + /* find the WPA_IE */ + if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) { + WL_DBG((" WPA found\n")); + ies->wpa_ie_len = ies->wpa_ie->length; + } + + return err; + +} + +static s32 +wl_cfg80211_bcn_bringup_ap( + struct net_device *dev, + struct parsed_ies *ies, + u32 dev_role, s32 bssidx) +{ + struct wl_priv *wl = wlcfg_drv_priv; + struct wl_join_params join_params; + bool is_bssup = false; + s32 infra = 1; + s32 join_params_size = 0; + s32 ap = 1; + s32 err = BCME_OK; + + WL_DBG(("Enter dev_role: %d\n", dev_role)); + + /* Common code for SoftAP and P2P GO */ + wldev_iovar_setint(dev, "mpc", 0); + + if (dev_role == NL80211_IFTYPE_P2P_GO) { is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); + if (!is_bssup && (ies->wpa2_ie != NULL)) { - if (!is_bssup && (wpa2_ie != NULL)) { - wldev_iovar_setint(dev, "mpc", 0); - if ((err = wl_validate_wpa2ie(dev, wpa2_ie, bssidx)) < 0) { - WL_ERR(("WPA2 IE parsing error")); - goto exit; - } err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); if (err < 0) { WL_ERR(("SET INFRA error %d\n", err)); goto exit; } + err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid, sizeof(wl->p2p->ssid), wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); @@ -4346,230 +5431,523 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("GO SSID setting error %d\n", err)); goto exit; } + if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) { WL_ERR(("GO Bring up error %d\n", err)); goto exit; } + } else + WL_DBG(("Bss is already up\n")); + } else if ((dev_role == NL80211_IFTYPE_AP) && + (wl_get_drv_status(wl, AP_CREATING, dev))) { + /* Device role SoftAP */ + err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); + if (err < 0) { + WL_ERR(("WLC_DOWN error %d\n", err)); + goto exit; } - } else if (wl_get_drv_status(wl, AP_CREATING, dev)) { - ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; - ap = 1; - /* find the SSID */ - if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], - info->head_len - ie_offset, - DOT11_MNG_SSID_ID)) != NULL) { - memset(&ssid, 0, sizeof(wlc_ssid_t)); - memcpy(ssid.SSID, ssid_ie->data, ssid_ie->len); - WL_DBG(("SSID is (%s) in Head \n", ssid.SSID)); - ssid.SSID_len = ssid_ie->len; - wldev_iovar_setint(dev, "mpc", 0); - wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); - wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { - WL_ERR(("setting AP mode failed %d \n", err)); - return err; - } - /* find the RSN_IE */ - if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, - DOT11_MNG_RSN_ID)) != NULL) { - WL_DBG((" WPA2 IE is found\n")); - } - /* find the WPA_IE */ - if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail, - info->tail_len)) != NULL) { - WL_DBG((" WPA IE is found\n")); - } - if ((wpa_ie != NULL || wpa2_ie != NULL)) { - if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 || - wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) { - wl->ap_info->security_mode = false; - return BCME_ERROR; + err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + goto exit; + } + if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { + WL_ERR(("setting AP mode failed %d \n", err)); + goto exit; + } + + err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + goto exit; + } + + memset(&join_params, 0, sizeof(join_params)); + /* join parameters starts with ssid */ + join_params_size = sizeof(join_params.ssid); + memcpy(join_params.ssid.SSID, wl->hostapd_ssid.SSID, + wl->hostapd_ssid.SSID_len); + join_params.ssid.SSID_len = htod32(wl->hostapd_ssid.SSID_len); + + /* create softap */ + if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, + join_params_size, true)) == 0) { + WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID)); + wl_clr_drv_status(wl, AP_CREATING, dev); + wl_set_drv_status(wl, AP_CREATED, dev); + } + } + + +exit: + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +s32 +wl_cfg80211_parse_set_ies( + struct net_device *dev, + struct cfg80211_beacon_data *info, + struct parsed_ies *ies, + u32 dev_role, + s32 bssidx) +{ + struct wl_priv *wl = wlcfg_drv_priv; + struct parsed_ies prb_ies; + s32 err = BCME_OK; + + memset(ies, 0, sizeof(struct parsed_ies)); + memset(&prb_ies, 0, sizeof(struct parsed_ies)); + + /* Parse Beacon IEs */ + if (wl_cfg80211_parse_ies((u8 *)info->tail, + info->tail_len, ies) < 0) { + WL_ERR(("Beacon get IEs failed \n")); + err = -EINVAL; + goto fail; + } + + /* Set Beacon IEs to FW */ + if ((err = wl_cfgp2p_set_management_ie(wl, dev, bssidx, + VNDR_IE_BEACON_FLAG, (u8 *)info->tail, + info->tail_len)) < 0) { + WL_ERR(("Set Beacon IE Failed \n")); + } else { + WL_DBG(("Applied Vndr IEs for Beacon \n")); + } + + /* Parse Probe Response IEs */ + if (wl_cfg80211_parse_ies((u8 *)info->proberesp_ies, + info->proberesp_ies_len, &prb_ies) < 0) { + WL_ERR(("PRB RESP get IEs failed \n")); + err = -EINVAL; + goto fail; + } + + /* Set Probe Response IEs to FW */ + if ((err = wl_cfgp2p_set_management_ie(wl, dev, bssidx, + VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies, + info->proberesp_ies_len)) < 0) { + WL_ERR(("Set Probe Resp IE Failed \n")); + } else { + WL_DBG(("Applied Vndr IEs for Probe Resp \n")); + } + +fail: + + return err; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ + +static s32 wl_cfg80211_hostapd_sec( + struct net_device *dev, + struct parsed_ies *ies, + s32 bssidx) +{ + bool update_bss = 0; + struct wl_priv *wl = wlcfg_drv_priv; + + + if (ies->wps_ie) { + if (wl->ap_info->wps_ie && + memcmp(wl->ap_info->wps_ie, ies->wps_ie, ies->wps_ie_len)) { + WL_DBG((" WPS IE is changed\n")); + kfree(wl->ap_info->wps_ie); + wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); + } else if (wl->ap_info->wps_ie == NULL) { + WL_DBG((" WPS IE is added\n")); + wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); + } + if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) { + if (!wl->ap_info->security_mode) { + /* change from open mode to security mode */ + update_bss = true; + if (ies->wpa_ie != NULL) { + wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, + ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else { + wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, + ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); } - wl->ap_info->security_mode = true; - if (wl->ap_info->rsn_ie) { + } else if (wl->ap_info->wpa_ie) { + /* change from WPA2 mode to WPA mode */ + if (ies->wpa_ie != NULL) { + update_bss = true; kfree(wl->ap_info->rsn_ie); wl->ap_info->rsn_ie = NULL; - } - if (wl->ap_info->wpa_ie) { - kfree(wl->ap_info->wpa_ie); - wl->ap_info->wpa_ie = NULL; - } - if (wl->ap_info->wps_ie) { - kfree(wl->ap_info->wps_ie); - wl->ap_info->wps_ie = NULL; - } - if (wpa_ie != NULL) { - /* WPAIE */ - wl->ap_info->rsn_ie = NULL; - wl->ap_info->wpa_ie = kmemdup(wpa_ie, - wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } else { - /* RSNIE */ + wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, + ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else if (memcmp(wl->ap_info->rsn_ie, + ies->wpa2_ie, ies->wpa2_ie->len + + WPA_RSN_IE_TAG_FIXED_LEN)) { + update_bss = true; + kfree(wl->ap_info->rsn_ie); + wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, + ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); wl->ap_info->wpa_ie = NULL; - wl->ap_info->rsn_ie = kmemdup(wpa2_ie, - wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } - } else { - wl_validate_opensecurity(dev, bssidx); - wl->ap_info->security_mode = false; - } - /* find the WPSIE */ - if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, - info->tail_len)) != NULL) { - wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN; - /* - * Should be compared with saved ie before saving it - */ - wl_validate_wps_ie((char *) wps_ie, &pbc); - memcpy(beacon_ie, wps_ie, wpsie_len); - wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, - beacon_ie, wpsie_len); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); - /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); - } else { - WL_DBG(("No WPSIE in beacon \n")); - } - if (info->interval) { - if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, - &info->interval, sizeof(s32), true)) < 0) { - WL_ERR(("Beacon Interval Set Error, %d\n", err)); - return err; } } - if (info->dtim_period) { - if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, - &info->dtim_period, sizeof(s32), true)) < 0) { - WL_ERR(("DTIM Interval Set Error, %d\n", err)); - return err; + if (update_bss) { + wl->ap_info->security_mode = true; + wl_cfgp2p_bss(wl, dev, bssidx, 0); + if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || + wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) { + return BCME_ERROR; } - } - err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); - if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); - return err; - } - memset(&join_params, 0, sizeof(join_params)); - /* join parameters starts with ssid */ - join_params_size = sizeof(join_params.ssid); - memcpy(join_params.ssid.SSID, ssid.SSID, ssid.SSID_len); - join_params.ssid.SSID_len = htod32(ssid.SSID_len); - /* create softap */ - if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - join_params_size, true)) == 0) { - wl_clr_drv_status(wl, AP_CREATING, dev); - wl_set_drv_status(wl, AP_CREATED, dev); + wl_cfgp2p_bss(wl, dev, bssidx, 1); } } - } else if (wl_get_drv_status(wl, AP_CREATED, dev)) { - ap = 1; - /* find the WPSIE */ - if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) { - wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; - /* - * Should be compared with saved ie before saving it - */ - wl_validate_wps_ie((char *) wps_ie, &pbc); - memcpy(beacon_ie, wps_ie, wpsie_len); - wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, - beacon_ie, wpsie_len); - if (wl->ap_info->wps_ie && - memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) { - WL_DBG((" WPS IE is changed\n")); - kfree(wl->ap_info->wps_ie); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); - /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); - } else if (wl->ap_info->wps_ie == NULL) { - WL_DBG((" WPS IE is added\n")); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); - /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); - } - /* find the RSN_IE */ - if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, - DOT11_MNG_RSN_ID)) != NULL) { - WL_DBG((" WPA2 IE is found\n")); - } - /* find the WPA_IE */ - if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail, - info->tail_len)) != NULL) { - WL_DBG((" WPA IE is found\n")); - } - if ((wpa_ie != NULL || wpa2_ie != NULL)) { - if (!wl->ap_info->security_mode) { - /* change from open mode to security mode */ - update_bss = true; - if (wpa_ie != NULL) { - wl->ap_info->wpa_ie = kmemdup(wpa_ie, - wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } else { - wl->ap_info->rsn_ie = kmemdup(wpa2_ie, - wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } - } else if (wl->ap_info->wpa_ie) { - /* change from WPA mode to WPA2 mode */ - if (wpa2_ie != NULL) { - update_bss = true; - kfree(wl->ap_info->wpa_ie); - wl->ap_info->rsn_ie = kmemdup(wpa2_ie, - wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - wl->ap_info->wpa_ie = NULL; - } - else if (memcmp(wl->ap_info->wpa_ie, - wpa_ie, wpa_ie->length + - WPA_RSN_IE_TAG_FIXED_LEN)) { - kfree(wl->ap_info->wpa_ie); - update_bss = true; - wl->ap_info->wpa_ie = kmemdup(wpa_ie, - wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - wl->ap_info->rsn_ie = NULL; - } - } else { - /* change from WPA2 mode to WPA mode */ - if (wpa_ie != NULL) { - update_bss = true; - kfree(wl->ap_info->rsn_ie); - wl->ap_info->rsn_ie = NULL; - wl->ap_info->wpa_ie = kmemdup(wpa_ie, - wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } else if (memcmp(wl->ap_info->rsn_ie, - wpa2_ie, wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) { - update_bss = true; - kfree(wl->ap_info->rsn_ie); - wl->ap_info->rsn_ie = kmemdup(wpa2_ie, - wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - wl->ap_info->wpa_ie = NULL; - } - } - if (update_bss) { - wl->ap_info->security_mode = true; - wl_cfgp2p_bss(wl, dev, bssidx, 0); - if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 || - wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) { - return BCME_ERROR; - } - wl_cfgp2p_bss(wl, dev, bssidx, 1); - } - } + } else { + WL_ERR(("No WPSIE in beacon \n")); + } + return 0; +} + +static s32 +wl_cfg80211_del_station( + struct wiphy *wiphy, + struct net_device *ndev, + u8* mac_addr) +{ + struct net_device *dev; + struct wl_priv *wl = wiphy_priv(wiphy); + scb_val_t scb_val; + s8 eabuf[ETHER_ADDR_STR_LEN]; + + WL_DBG(("Entry\n")); + if (mac_addr == NULL) { + WL_DBG(("mac_addr is NULL ignore it\n")); + return 0; + } + + if (ndev == wl->p2p_net) { + dev = wl_to_prmry_ndev(wl); + } else { + dev = ndev; + } + + if (p2p_is_on(wl)) { + /* Suspend P2P discovery search-listen to prevent it from changing the + * channel. + */ + if ((wl_cfgp2p_discover_enable_search(wl, false)) < 0) { + WL_ERR(("Can not disable discovery mode\n")); + return -EFAULT; + } + } + + memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN); + scb_val.val = DOT11_RC_DEAUTH_LEAVING; + if (wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t), true)) + WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON failed\n")); + WL_DBG(("Disconnect STA : %s scb_val.val %d\n", + bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf), + scb_val.val)); + wl_delay(400); + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +static s32 +wl_cfg80211_start_ap( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *info) +{ + struct wl_priv *wl = wiphy_priv(wiphy); + s32 err = BCME_OK; + struct parsed_ies ies; + s32 bssidx = 0; + u32 dev_role = 0; + + WL_DBG(("Enter \n")); + if (dev == wl_to_prmry_ndev(wl)) { + WL_DBG(("Start AP req on primary iface: Softap\n")); + dev_role = NL80211_IFTYPE_AP; + } else if (dev == wl->p2p_net) { + /* Group Add request on p2p0 */ + WL_DBG(("Start AP req on P2P iface: GO\n")); + dev = wl_to_prmry_ndev(wl); + dev_role = NL80211_IFTYPE_P2P_GO; + } + + bssidx = wl_cfgp2p_find_idx(wl, dev); + if (p2p_is_on(wl) && + (bssidx == wl_to_p2p_bss_bssidx(wl, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + WL_DBG(("Start AP req on P2P connection iface\n")); + } + + if ((err = wl_cfg80211_bcn_set_params(info, dev, + dev_role, bssidx)) < 0) { + WL_ERR(("Beacon params set failed \n")); + goto fail; + } + + /* Set IEs to FW */ + if ((err = wl_cfg80211_parse_set_ies(dev, &info->beacon, + &ies, dev_role, bssidx) < 0)) { + WL_ERR(("Set IEs failed \n")); + goto fail; + } + + if ((wl_cfg80211_bcn_validate_sec(dev, &ies, + dev_role, bssidx)) < 0) + { + WL_ERR(("Beacon set security failed \n")); + goto fail; + } + + if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, + dev_role, bssidx)) < 0) { + WL_ERR(("Beacon bring up AP/GO failed \n")); + goto fail; + } + + WL_DBG(("** AP/GO Created **\n")); + +fail: + if (err) { + WL_ERR(("ADD/SET beacon failed\n")); + wldev_iovar_setint(dev, "mpc", 1); + } + + return err; +} + +static s32 +wl_cfg80211_stop_ap( + struct wiphy *wiphy, + struct net_device *dev) +{ + int err = 0; + u32 dev_role = 0; + int infra = 0; + int ap = 0; + s32 bssidx = 0; + struct wl_priv *wl = wiphy_priv(wiphy); + + WL_DBG(("Enter \n")); + if (dev == wl_to_prmry_ndev(wl)) { + dev_role = NL80211_IFTYPE_AP; + } else if (dev == wl->p2p_net) { + /* Group Add request on p2p0 */ + dev = wl_to_prmry_ndev(wl); + dev_role = NL80211_IFTYPE_P2P_GO; + } + bssidx = wl_cfgp2p_find_idx(wl, dev); + if (p2p_is_on(wl) && + (bssidx == wl_to_p2p_bss_bssidx(wl, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + } + + if (dev_role == NL80211_IFTYPE_AP) { + /* SoftAp on primary Interface. + * Shut down AP and turn on MPC + */ + err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + err = -ENOTSUPP; + goto exit; + } + if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { + WL_ERR(("setting AP mode failed %d \n", err)); + err = -ENOTSUPP; + goto exit; + } + + err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + err = -EINVAL; + goto exit; + } + + wl_clr_drv_status(wl, AP_CREATED, dev); + /* Turn on the MPC */ + wldev_iovar_setint(dev, "mpc", 1); + } else { + WL_DBG(("Stopping P2P GO \n")); + } + +exit: + return err; +} +static s32 +wl_cfg80211_change_beacon( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *info) +{ + s32 err = BCME_OK; + struct wl_priv *wl = wiphy_priv(wiphy); + struct parsed_ies ies; + u32 dev_role = 0; + s32 bssidx = 0; + + WL_DBG(("Enter \n")); + + if (dev == wl_to_prmry_ndev(wl)) { + dev_role = NL80211_IFTYPE_AP; + } else if (dev == wl->p2p_net) { + /* Group Add request on p2p0 */ + dev = wl_to_prmry_ndev(wl); + dev_role = NL80211_IFTYPE_P2P_GO; + } + + bssidx = wl_cfgp2p_find_idx(wl, dev); + if (p2p_is_on(wl) && + (bssidx == wl_to_p2p_bss_bssidx(wl, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + } + + /* Set IEs to FW */ + if ((err = wl_cfg80211_parse_set_ies(dev, info, + &ies, dev_role, bssidx) < 0)) { + WL_ERR(("Set IEs failed \n")); + goto fail; + } + + if (dev_role == NL80211_IFTYPE_AP) { + if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { + WL_ERR(("Hostapd update sec failed \n")); + err = -EINVAL; + goto fail; + } + } + +fail: + return err; +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ +static s32 +wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + s32 err = BCME_OK; + struct wl_priv *wl = wiphy_priv(wiphy); + s32 ie_offset = 0; + s32 bssidx = 0; + u32 dev_role = NL80211_IFTYPE_AP; + struct parsed_ies ies; + bcm_tlv_t *ssid_ie; + bool pbc = 0; + WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", + info->interval, info->dtim_period, info->head_len, info->tail_len)); + + if (dev == wl_to_prmry_ndev(wl)) { + dev_role = NL80211_IFTYPE_AP; + } else if (dev == wl->p2p_net) { + /* Group Add request on p2p0 */ + dev = wl_to_prmry_ndev(wl); + dev_role = NL80211_IFTYPE_P2P_GO; + } + + bssidx = wl_cfgp2p_find_idx(wl, dev); + if (p2p_is_on(wl) && + (bssidx == wl_to_p2p_bss_bssidx(wl, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + } + + ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + /* find the SSID */ + if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], + info->head_len - ie_offset, + DOT11_MNG_SSID_ID)) != NULL) { + if (dev_role == NL80211_IFTYPE_AP) { + /* Store the hostapd SSID */ + memset(&wl->hostapd_ssid.SSID[0], 0x00, 32); + memcpy(&wl->hostapd_ssid.SSID[0], ssid_ie->data, ssid_ie->len); + wl->hostapd_ssid.SSID_len = ssid_ie->len; } else { - WL_ERR(("No WPSIE in beacon \n")); + /* P2P GO */ + memset(&wl->p2p->ssid.SSID[0], 0x00, 32); + memcpy(wl->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len); + wl->p2p->ssid.SSID_len = ssid_ie->len; } } -exit: - if (err) + + if (wl_cfg80211_parse_ies((u8 *)info->tail, + info->tail_len, &ies) < 0) { + WL_ERR(("Beacon get IEs failed \n")); + err = -EINVAL; + goto fail; + } + + if (wl_cfgp2p_set_management_ie(wl, dev, bssidx, + VNDR_IE_BEACON_FLAG, (u8 *)info->tail, + info->tail_len) < 0) { + WL_ERR(("Beacon set IEs failed \n")); + goto fail; + } else { + WL_DBG(("Applied Vndr IEs for Beacon \n")); + } + if (!wl_cfgp2p_bss_isup(dev, bssidx) && + (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx) < 0)) + { + WL_ERR(("Beacon set security failed \n")); + goto fail; + } + + /* Set BI and DTIM period */ + if (info->interval) { + if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, + &info->interval, sizeof(s32), true)) < 0) { + WL_ERR(("Beacon Interval Set Error, %d\n", err)); + return err; + } + } + if (info->dtim_period) { + if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, + &info->dtim_period, sizeof(s32), true)) < 0) { + WL_ERR(("DTIM Interval Set Error, %d\n", err)); + return err; + } + } + + if (wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx) < 0) { + WL_ERR(("Beacon bring up AP/GO failed \n")); + goto fail; + } + + if (wl_get_drv_status(wl, AP_CREATED, dev)) { + /* Soft AP already running. Update changed params */ + if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { + WL_ERR(("Hostapd update sec failed \n")); + err = -EINVAL; + goto fail; + } + } + + /* Enable Probe Req filter */ + if (((dev_role == NL80211_IFTYPE_P2P_GO) || + (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) { + wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); + if (pbc) + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + } + + WL_DBG(("** ADD/SET beacon done **\n")); + +fail: + if (err) { + WL_ERR(("ADD/SET beacon failed\n")); wldev_iovar_setint(dev, "mpc", 1); + } return err; + } -#endif +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ static struct cfg80211_ops wl_cfg80211_ops = { .add_virtual_intf = wl_cfg80211_add_virtual_iface, @@ -4601,10 +5979,20 @@ static struct cfg80211_ops wl_cfg80211_ops = { .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, .change_bss = wl_cfg80211_change_bss, .set_channel = wl_cfg80211_set_channel, -#if 0 +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) .set_beacon = wl_cfg80211_add_set_beacon, .add_beacon = wl_cfg80211_add_set_beacon, -#endif +#else + .change_beacon = wl_cfg80211_change_beacon, + .start_ap = wl_cfg80211_start_ap, + .stop_ap = wl_cfg80211_stop_ap, +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ +#ifdef WL_SCHED_SCAN + .sched_scan_start = wl_cfg80211_sched_scan_start, + .sched_scan_stop = wl_cfg80211_sched_scan_stop, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ + .del_station = wl_cfg80211_del_station, + .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, }; s32 wl_mode_to_nl80211_iftype(s32 mode) @@ -4642,7 +6030,10 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) - | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR); +#if !(defined(WLP2P) && defined(WL_ENABLE_P2P_IF)) + | BIT(NL80211_IFTYPE_MONITOR) +#endif + | BIT(NL80211_IFTYPE_AP); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; @@ -4662,9 +6053,29 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | #endif WIPHY_FLAG_4ADDR_STATION; + /* If driver advertises FW_ROAM, the supplicant wouldn't + * send the BSSID & Freq in the connect command allowing the + * the driver to choose the AP to connect to. But unless we + * support ROAM_CACHE in firware this will delay the ASSOC as + * as the FW need to do a full scan before attempting to connect + * So that feature will just increase assoc. The better approach + * to let Supplicant to provide channel info and FW letter may roam + * if needed so DON'T advertise that featur eto Supplicant. + */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; +/* wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; */ +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) + wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_OFFCHAN_TX; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) + /* From 3.4 kernel ownards AP_SME flag can be advertised + * to remove the patch from supplicant + */ + wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; #endif + WL_DBG(("Registering custom regulatory)\n")); wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); @@ -4705,18 +6116,27 @@ static s32 wl_inform_bss(struct wl_priv *wl) bss_list = wl->bss_list; WL_DBG(("scanned AP count (%d)\n", bss_list->count)); +#ifdef ROAM_CHANNEL_CACHE + reset_roam_cache(); +#endif bi = next_bss(bss_list, bi); for_each_bss(bss_list, bi, i) { +#ifdef ROAM_CHANNEL_CACHE + add_roam_cache(bi); +#endif err = wl_inform_single_bss(wl, bi); if (unlikely(err)) break; } +#ifdef ROAM_CHANNEL_CACHE + /* print_roam_cache(); */ +#endif return err; } static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) { - struct wiphy *wiphy = wiphy_from_scan(wl); + struct wiphy *wiphy = wl_to_wiphy(wl); struct ieee80211_mgmt *mgmt; struct ieee80211_channel *channel; struct ieee80211_supported_band *band; @@ -4728,13 +6148,15 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) s32 signal; u32 freq; s32 err = 0; + gfp_t aflags; if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { WL_DBG(("Beacon is larger than buffer. Discarding\n")); return err; } + aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - - sizeof(u8) + WL_BSS_INFO_MAX, GFP_KERNEL); + - sizeof(u8) + WL_BSS_INFO_MAX, aflags); if (unlikely(!notif_bss_info)) { WL_ERR(("notif_bss_info alloc failed\n")); return -ENOMEM; @@ -4752,7 +6174,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) kfree(notif_bss_info); return -EINVAL; } - notif_bss_info->rssi = dtoh16(bi->RSSI); + notif_bss_info->rssi = dtoh16(bi->RSSI) + RSSI_OFFSET; memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); mgmt_type = wl->active_scan ? IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; @@ -4778,8 +6200,17 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) #else freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); #endif + if (freq == 0) { + WL_ERR(("Invalid channel, fail to chcnage channel to freq\n")); + kfree(notif_bss_info); + return -EINVAL; + } channel = ieee80211_get_channel(wiphy, freq); - + if (unlikely(!channel)) { + WL_ERR(("ieee80211_get_channel error\n")); + kfree(notif_bss_info); + return -EINVAL; + } WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM" "mgmt_type %d frame_len %d\n", bi->SSID, notif_bss_info->rssi, notif_bss_info->channel, @@ -4787,27 +6218,23 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) notif_bss_info->frame_len)); signal = notif_bss_info->rssi * 100; - -#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) - if (wl->p2p_net && wl->scan_request && - ((wl->scan_request->dev == wl->p2p_net) || - (wl->scan_request->dev == wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)))) { + if (!mgmt->u.probe_resp.timestamp) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) + struct timespec ts; + get_monotonic_boottime(&ts); + mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) + + ts.tv_nsec / 1000; #else - if (p2p_is_on(wl) && (p2p_scan(wl) || - (wl->scan_request->dev == wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)))) { + struct timeval tv; + do_gettimeofday(&tv); + mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000) + + tv.tv_usec; #endif - /* find the P2PIE, if we do not find it, we will discard this frame */ - wifi_p2p_ie_t * p2p_ie; - if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)beacon_proberesp->variable, - wl_get_ielen(wl))) == NULL) { - WL_ERR(("Couldn't find P2PIE in probe response/beacon\n")); - kfree(notif_bss_info); - return err; - } } + cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, - le16_to_cpu(notif_bss_info->frame_len), signal, GFP_KERNEL); + le16_to_cpu(notif_bss_info->frame_len), signal, aflags); if (unlikely(!cbss)) { WL_ERR(("cfg80211_inform_bss_frame error\n")); kfree(notif_bss_info); @@ -4816,7 +6243,6 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) cfg80211_put_bss(cbss); kfree(notif_bss_info); - return err; } @@ -4850,10 +6276,17 @@ static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e) event == WLC_E_DISASSOC_IND || event == WLC_E_DISASSOC || event == WLC_E_DEAUTH) { +#if (WL_DBG_LEVEL > 0) + WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); +#endif /* (WL_DBG_LEVEL > 0) */ return true; } else if (event == WLC_E_LINK) { - if (!(flags & WLC_EVENT_MSG_LINK)) + if (!(flags & WLC_EVENT_MSG_LINK)) { +#if (WL_DBG_LEVEL > 0) + WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); +#endif /* (WL_DBG_LEVEL > 0) */ return true; + } } return false; @@ -4892,7 +6325,7 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, u8 bsscfgidx = e->bsscfgidx; s32 freq; s32 channel; - u8 body[WL_FRAME_LEN]; + u8 *body = NULL; u16 fc = 0; struct ieee80211_supported_band *band; @@ -4904,22 +6337,41 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, struct station_info sinfo; #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !WL_CFG80211_STA_EVENT */ + WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason)); + /* if link down, bsscfg is disabled. */ + if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS && + wl_get_p2p_status(wl, IF_DELETING) && (ndev != wl_to_prmry_ndev(wl))) { + WL_INFO(("AP mode link down !! \n")); + complete(&wl->iface_disable); + return 0; + } #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) - memset(body, 0, sizeof(body)); + body = kzalloc(len, GFP_KERNEL); + WL_DBG(("Enter \n")); + if (!len && (event == WLC_E_DEAUTH)) { + len = 2; /* reason code field */ + data = &reason; + } + if (len) { + body = kzalloc(len, GFP_KERNEL); + + if (body == NULL) { + WL_ERR(("wl_notify_connect_status: Failed to allocate body\n")); + return WL_INVALID; + } + } memset(&bssid, 0, ETHER_ADDR_LEN); WL_DBG(("Enter event %d ndev %p\n", event, ndev)); - if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) + if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) { + kfree(body); return WL_INVALID; - - if (len > WL_FRAME_LEN) { - WL_ERR(("Received frame length %d from dongle is greater than" - " allocated body buffer len %d", len, WL_FRAME_LEN)); - goto exit; } - memcpy(body, data, len); + if (len) + memcpy(body, data, len); + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", - NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); + NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync); memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); switch (event) { @@ -4942,8 +6394,10 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, fc = 0; goto exit; } - if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) + if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { + kfree(body); return err; + } channel = dtoh32(ci.hw_channel); if (channel <= CH_MAX_2G_CHANNEL) @@ -4952,6 +6406,8 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, band = wiphy->bands[IEEE80211_BAND_5GHZ]; if (!band) { WL_ERR(("No valid band")); + if (body) + kfree(body); return -EINVAL; } #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) @@ -4968,16 +6424,30 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, isfree = true; if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ } else if (event == WLC_E_DISASSOC_IND) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ } exit: if (isfree) kfree(mgmt_frame); + if (body) + kfree(body); return err; #else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ sinfo.filled = 0; @@ -5000,6 +6470,27 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, return err; } +static s32 +wl_get_auth_assoc_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e) +{ + u32 reason = ntoh32(e->reason); + u32 event = ntoh32(e->event_type); + struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC); + WL_DBG(("event type : %d, reason : %d\n", event, reason)); + if (sec) { + switch (event) { + case WLC_E_ASSOC: + case WLC_E_AUTH: + sec->auth_assoc_res_status = reason; + default: + break; + } + } else + WL_ERR(("sec is NULL\n")); + return 0; +} + static s32 wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -5013,11 +6504,13 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, } else { WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", ntoh32(e->event_type), ntoh32(e->status), ndev)); + if (event == WLC_E_ASSOC || event == WLC_E_AUTH) { + wl_get_auth_assoc_status(wl, ndev, e); + return err; + } if (wl_is_linkup(wl, e, ndev)) { wl_link_up(wl); act = true; - wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); - wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); if (wl_is_ibssmode(wl, ndev)) { printk("cfg80211_ibss_joined\n"); cfg80211_ibss_joined(ndev, (s8 *)&e->addr, @@ -5025,13 +6518,16 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, WL_DBG(("joined in IBSS network\n")); } else { if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) { - printk("wl_bss_connect_done succeeded\n"); + printk("wl_bss_connect_done succeeded with " MACDBG "\n", + MAC2STRDBG((u8*)(&e->addr))); wl_bss_connect_done(wl, ndev, e, data, true); WL_DBG(("joined in BSS network \"%s\"\n", ((struct wlc_ssid *) wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID)); } } + wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); + wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); } else if (wl_is_linkdown(wl, e)) { if (wl->scan_request) { @@ -5045,7 +6541,22 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl_get_drv_status(wl, CONNECTED, ndev)) { scb_val_t scbval; u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); - printk("link down, call cfg80211_disconnected\n"); + s32 reason = 0; + if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) + reason = ntoh32(e->reason); + /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ + reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; + + printk("link down if %s may call cfg80211_disconnected. " + "event : %d, reason=%d from " MACDBG "\n", + ndev->name, event, ntoh32(e->reason), + MAC2STRDBG((u8*)(&e->addr))); + if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) { + WL_ERR(("BSSID of event is not the connected BSSID" + "(ignore it) cur: " MACDBG " event: " MACDBG"\n", + MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr)))); + return 0; + } wl_clr_drv_status(wl, CONNECTED, ndev); if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) { /* To make sure disconnect, explictly send dissassoc @@ -5055,22 +6566,36 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); - wldev_ioctl(ndev, WLC_DISASSOC, &scbval, + err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); - cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + if (err < 0) { + WL_ERR(("WLC_DISASSOC error %d\n", err)); + err = 0; + } + cfg80211_disconnected(ndev, reason, NULL, 0, GFP_KERNEL); wl_link_down(wl); wl_init_prof(wl, ndev); } } else if (wl_get_drv_status(wl, CONNECTING, ndev)) { printk("link down, during connecting\n"); - wl_bss_connect_done(wl, ndev, e, data, false); +#ifdef ESCAN_RESULT_PATCH + if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) || + (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) || + (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0)) + /* In case this event comes while associating another AP */ +#endif /* ESCAN_RESULT_PATCH */ + wl_bss_connect_done(wl, ndev, e, data, false); } wl_clr_drv_status(wl, DISCONNECTING, ndev); + /* if link down, bsscfg is diabled */ + if (ndev != wl_to_prmry_ndev(wl)) + complete(&wl->iface_disable); + } else if (wl_is_nonetwork(wl, e)) { - printk("connect failed event=%d e->status 0x%x\n", - event, (int)ntoh32(e->status)); + printk("connect failed event=%d e->status %d e->reason %d \n", + event, (int)ntoh32(e->status), (int)ntoh32(e->reason)); /* Clean up any pending scan request */ if (wl->scan_request) { if (wl->escan_on) { @@ -5183,9 +6708,19 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, size_t *join_params_size) { +#ifndef ROAM_CHANNEL_CACHE chanspec_t chanspec = 0; - +#endif if (ch != 0) { +#ifdef ROAM_CHANNEL_CACHE + int n_channels; + + n_channels = get_roam_channel_list(ch, join_params->params.chanspec_list, + &join_params->ssid, ioctl_version); + join_params->params.chanspec_num = htod32(n_channels); + *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(chanspec_t); +#else join_params->params.chanspec_num = 1; join_params->params.chanspec_list[0] = ch; @@ -5208,9 +6743,10 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, join_params->params.chanspec_num = htod32(join_params->params.chanspec_num); - WL_DBG(("%s join_params->params.chanspec_list[0]= %X\n", - __FUNCTION__, join_params->params.chanspec_list[0])); - +#endif /* ROAM_CHANNEL_CACHE */ + WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n", + join_params->params.chanspec_list[0], + join_params->params.chanspec_num)); } } @@ -5224,6 +6760,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) s32 dtim_period; size_t ie_len; u8 *ie; + u8 *ssidie; u8 *curbssid; s32 err = 0; struct wiphy *wiphy; @@ -5254,6 +6791,13 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) err = -EIO; goto update_bss_info_out; } + + ie = ((u8 *)bi) + bi->ie_offset; + ie_len = bi->ie_length; + ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie, ie_len); + if (ssidie && ssidie[1] == bi->SSID_len && !ssidie[2] && bi->SSID[0]) + memcpy(ssidie + 2, bi->SSID, bi->SSID_len); + err = wl_inform_single_bss(wl, bi); if (unlikely(err)) goto update_bss_info_out; @@ -5307,8 +6851,14 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); wl_update_bss_info(wl, ndev); wl_update_pmklist(ndev, wl->pmk_list, err); + printk("wl_bss_roaming_done succeeded to " MACDBG "\n", + MAC2STRDBG((u8*)(&e->addr))); + cfg80211_roamed(ndev, -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) + NULL, /* struct cfg80211_bss *bss */ +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) NULL, #endif curbssid, @@ -5326,13 +6876,41 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data, bool completed) { struct wl_connect_info *conn_info = wl_to_conn(wl); + struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC); +#ifdef ROAM_AP_ENV_DETECTION + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); +#endif /* ROAM_AP_ENV_DETECTION */ s32 err = 0; u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); - + if (!sec) { + WL_ERR(("sec is NULL\n")); + return -ENODEV; + } WL_DBG((" enter\n")); +#ifdef ESCAN_RESULT_PATCH + if (wl_get_drv_status(wl, CONNECTED, ndev)) { + if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) { + WL_ERR((" Connected event of connected device e=%d s=%d, ignore it\n", + ntoh32(e->event_type), ntoh32(e->status))); + return err; + } + } + if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 && + memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) { + WL_DBG(("copy bssid\n")); + memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); + } + +#if defined(BCM4334_CHIP) + if (wl->scan_request) { + wl_notify_escan_complete(wl, ndev, true, true); + } +#endif +#else if (wl->scan_request) { wl_notify_escan_complete(wl, ndev, true, true); } +#endif /* ESCAN_RESULT_PATCH */ if (wl_get_drv_status(wl, CONNECTING, ndev)) { wl_clr_drv_status(wl, CONNECTING, ndev); if (completed) { @@ -5342,6 +6920,11 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, wl_update_bss_info(wl, ndev); wl_update_pmklist(ndev, wl->pmk_list, err); wl_set_drv_status(wl, CONNECTED, ndev); +#ifdef ROAM_AP_ENV_DETECTION + if (dhd->roam_env_detection) + wldev_iovar_setint(ndev, "roam_env_detection", + AP_ENV_INDETERMINATE); +#endif /* ROAM_AP_ENV_DETECTION */ } cfg80211_connect_result(ndev, curbssid, @@ -5349,7 +6932,10 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, conn_info->req_ie_len, conn_info->resp_ie, conn_info->resp_ie_len, - completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT, + completed ? WLAN_STATUS_SUCCESS : + (sec->auth_assoc_res_status) ? + sec->auth_assoc_res_status : + WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); if (completed) WL_INFO(("Report connect result - connection succeeded\n")); @@ -5378,7 +6964,29 @@ wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, return 0; } +#if 0 +#ifdef PNO_SUPPORT +static s32 +wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + WL_ERR((">>> PNO Event\n")); +#ifndef WL_SCHED_SCAN + mutex_lock(&wl->usr_sync); + /* TODO: Use cfg80211_sched_scan_results(wiphy); */ + cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + mutex_unlock(&wl->usr_sync); +#else + /* If cfg80211 scheduled scan is supported, report the pno results via sched + * scan results + */ + wl_notify_sched_scan_results(wl, ndev, e, data); +#endif /* WL_SCHED_SCAN */ + return 0; +} +#endif /* PNO_SUPPORT */ +#endif static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -5431,11 +7039,11 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, del_timer_sync(&wl->scan_timeout); spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (wl->scan_request) { - WL_DBG(("cfg80211_scan_done\n")); cfg80211_scan_done(wl->scan_request, false); wl->scan_request = NULL; } spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + WL_DBG(("cfg80211_scan_done\n")); mutex_unlock(&wl->usr_sync); return err; } @@ -5476,10 +7084,131 @@ wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN); bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN); bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN); - bcopy((const char*)pbody, offset, prebody_len); + if ((pbody != NULL) && prebody_len) + bcopy((const char*)pbody, offset, prebody_len); *body_len = totlen; return err; } + +#ifdef WL_CFG80211_GON_COLLISION +static void +wl_gon_req_collision(struct wl_priv *wl, wl_action_frame_t *tx_act_frm, + wifi_p2p_pub_act_frame_t *rx_act_frm, struct net_device *ndev, + struct ether_addr sa, struct ether_addr da) +{ + if (wl->afx_hdl->pending_tx_act_frm == NULL) + return; + + if (tx_act_frm && + wl_cfgp2p_is_pub_action(tx_act_frm->data, tx_act_frm->len)) { + wifi_p2p_pub_act_frame_t *pact_frm; + + pact_frm = (wifi_p2p_pub_act_frame_t *)tx_act_frm->data; + + if (!(pact_frm->subtype == P2P_PAF_GON_REQ && + rx_act_frm->subtype == P2P_PAF_GON_REQ)) { + return; + } + } + + WL_ERR((" GO NEGO Request COLLISION !!! \n")); + + /* if sa(peer) addr is less than da(my) addr, + * my device will process peer's gon request and block to send my gon req. + * + * if not (sa addr > da addr), + * my device will process gon request and drop gon req of peer. + */ + if (memcmp(sa.octet, da.octet, ETHER_ADDR_LEN) < 0) { + /* block to send tx gon request */ + wl->block_gon_req_tx_count = BLOCK_GON_REQ_MAX_NUM; + WL_ERR((" block to send gon req tx !!!\n")); + + /* if we are finding a common channel for sending af, + * do not scan more to block to send current gon req + */ + if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { + wl_clr_drv_status(wl, FINDING_COMMON_CHANNEL, ndev); + complete(&wl->act_frm_scan); + } + } else { + /* drop gon request of peer to process gon request by my device. */ + WL_ERR((" drop to receive gon req rx !!! \n")); + wl->block_gon_req_rx_count = BLOCK_GON_REQ_MAX_NUM; + } + + return; +} +#endif /* WL_CFG80211_GON_COLLISION */ + +void +wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev) +{ + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM) && + (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || + wl_get_p2p_status(wl, ACTION_TX_NOACK))) { + WL_DBG(("*** Wake UP ** abort actframe iovar\n")); + /* if channel is not zero, "actfame" uses off channel scan. + * So abort scan for off channel completion. + */ + if (wl->af_sent_channel) + /* wl_cfg80211_scan_abort(wl, ndev); */ + wl_notify_escan_complete(wl, + (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); + } +#ifdef WL_CFG80211_SYNC_GON + else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { + WL_DBG(("*** Wake UP ** abort listen for next af frame\n")); + /* So abort scan to cancel listen */ + wl_notify_escan_complete(wl, + (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); + } +#endif /* WL_CFG80211_SYNC_GON */ +} + +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) +static int wes_mode = 0; +int wl_cfg80211_set_wes_mode(int mode) +{ + wes_mode = mode; + return 0; +} + +int wl_cfg80211_get_wes_mode(void) +{ + return wes_mode; +} + +bool wl_cfg80211_is_wes(void *frame, u32 frame_len) +{ + unsigned char *data; + + if (frame == NULL) { + WL_ERR(("%s: Invalid frame \n", __FUNCTION__)); + return false; + } + + if (frame_len < 4) { + WL_ERR(("%s: Invalid frame length [%d] \n", __FUNCTION__, frame_len)); + return false; + } + + data = frame; + + if (memcmp(data, "\x7f\x00\x00\xf0", 4) == 0) { + WL_DBG(("%s: Receive WES VS Action Frame \n", __FUNCTION__)); + return true; + } + + return false; +} + +int wl_cfg80211_get_ioctl_version(void) +{ + return ioctl_version; +} +#endif /* WES_SUPPORT */ + static s32 wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -5527,9 +7256,11 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, #endif if (event == WLC_E_ACTION_FRAME_RX) { wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr", - NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); + NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync); - wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + if (err < 0) + WL_ERR(("WLC_GET_BSSID error %d\n", err)); memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, &mgmt_frame, &mgmt_frame_len, @@ -5553,8 +7284,69 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + if (sd_act_frm && wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) { + if (wl->next_af_subtype == sd_act_frm->action) { + WL_DBG(("We got a right next frame of SD!(%d)\n", + sd_act_frm->action)); + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, + (ndev == wl->p2p_net) ? + wl_to_prmry_ndev(wl) : ndev); + + /* Stop waiting for next AF. */ + wl_stop_wait_next_action_frame(wl, ndev); + } + } (void) sd_act_frm; + } else { + /* + * if we got normal action frame and ndev is p2p0, + * we have to change ndev from p2p0 to wlan0 + */ +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) + if (wl_cfg80211_is_wes(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN) && wes_mode == 0) { + /* Ignore WES VS Action frame */ + goto exit; + } +#endif /* WES_SUPPORT */ + if (wl->p2p_net == ndev) + ndev = wl_to_prmry_ndev(wl); + } + + if (act_frm) { +#ifdef WL_CFG80211_GON_COLLISION + if (act_frm->subtype == P2P_PAF_GON_REQ) { + wl_gon_req_collision(wl, + &wl->afx_hdl->pending_tx_act_frm->action_frame, + act_frm, ndev, e->addr, da); + + if (wl->block_gon_req_rx_count) { + WL_ERR(("drop frame GON Req Rx : count (%d)\n", + wl->block_gon_req_rx_count)); + wl->block_gon_req_rx_count--; + goto exit; + } + } else if (act_frm->subtype == P2P_PAF_GON_CONF) { + /* if go formation done, clear it */ + wl->block_gon_req_tx_count = 0; + wl->block_gon_req_rx_count = 0; + } +#endif /* WL_CFG80211_GON_COLLISION */ + + if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) { + if (wl->next_af_subtype == act_frm->subtype) { + WL_DBG(("We got a right next frame!(%d)\n", + act_frm->subtype)); + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, + (ndev == wl->p2p_net) ? + wl_to_prmry_ndev(wl) : ndev); + + /* Stop waiting for next AF. */ + wl_stop_wait_next_action_frame(wl, ndev); + } + } } + wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], mgmt_frame_len - DOT11_MGMT_HDR_LEN); /* @@ -5564,18 +7356,60 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { wldev_iovar_setint(dev, "mpc", 1); } + if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); + wl_clr_p2p_status(wl, GO_NEG_PHASE); + } } else { mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); + + /* wpa supplicant use probe request event for restarting another GON Req. + * but it makes GON Req repetition. + * so if src addr of prb req is same as my target device, + * do not send probe request event during sending action frame. + */ + if (event == WLC_E_P2P_PROBREQ_MSG) { + WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ? + "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG")); + +#ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX + if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl) && + !memcmp(wl->afx_hdl->tx_dst_addr.octet, e->addr.octet, + ETHER_ADDR_LEN)) { + if (wl->afx_hdl->pending_tx_act_frm && + wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { + s32 channel = CHSPEC_CHANNEL(hton16(rxframe->channel)); + WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n", + channel)); + wl->afx_hdl->peer_chan = channel; + complete(&wl->act_frm_scan); + } + } +#endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */ + + /* Filter any P2P probe reqs arriving during the + * GO-NEG Phase + */ + if (wl->p2p && + wl_get_p2p_status(wl, GO_NEG_PHASE)) { + WL_DBG(("Filtering P2P probe_req while " + "being in GO-Neg state\n")); + return 0; + } + } } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ WL_DBG(("%s: mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", __func__, mgmt_frame_len, ntoh32(e->datalen), channel, freq)); - +exit: if (isfree) kfree(mgmt_frame); -exit: return 0; } @@ -5604,6 +7438,8 @@ static void wl_init_event_handler(struct wl_priv *wl) memset(wl->evt_handler, 0, sizeof(wl->evt_handler)); wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; + wl->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; + wl->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status; wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status; wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; @@ -5671,12 +7507,36 @@ static s32 wl_init_priv_mem(struct wl_priv *wl) WL_ERR(("sta info alloc failed\n")); goto init_priv_mem_out; } + +#if defined(STATIC_WL_PRIV_STRUCT) + wl->conn_info = (void *)kzalloc(sizeof(*wl->conn_info), GFP_KERNEL); + if (unlikely(!wl->conn_info)) { + WL_ERR(("wl->conn_info alloc failed\n")); + goto init_priv_mem_out; + } + wl->ie = (void *)kzalloc(sizeof(*wl->ie), GFP_KERNEL); + if (unlikely(!wl->ie)) { + WL_ERR(("wl->ie alloc failed\n")); + goto init_priv_mem_out; + } +#if defined(DUAL_ESCAN_RESULT_BUFFER) + wl->escan_info.escan_buf[0] = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN0, 0); + bzero(wl->escan_info.escan_buf[0], ESCAN_BUF_SIZE); + wl->escan_info.escan_buf[1] = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN1, 0); + bzero(wl->escan_info.escan_buf[1], ESCAN_BUF_SIZE); +#else + wl->escan_info.escan_buf = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN0, 0); + bzero(wl->escan_info.escan_buf, ESCAN_BUF_SIZE); +#endif /* DUAL_ESCAN_RESULT_BUFFER */ +#endif /* STATIC_WL_PRIV_STRUCT */ wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL); if (unlikely(!wl->afx_hdl)) { WL_ERR(("afx hdl alloc failed\n")); goto init_priv_mem_out; } else { init_completion(&wl->act_frm_scan); + init_completion(&wl->wait_next_af); + INIT_WORK(&wl->afx_hdl->work, wl_cfg80211_afx_handler); } return 0; @@ -5707,6 +7567,18 @@ static void wl_deinit_priv_mem(struct wl_priv *wl) wl->pmk_list = NULL; kfree(wl->sta_info); wl->sta_info = NULL; +#if defined(STATIC_WL_PRIV_STRUCT) + kfree(wl->conn_info); + wl->conn_info = NULL; + kfree(wl->ie); + wl->ie = NULL; +#if defined(DUAL_ESCAN_RESULT_BUFFER) + wl->escan_info.escan_buf[0] = NULL; + wl->escan_info.escan_buf[1] = NULL; +#else + wl->escan_info.escan_buf = NULL; +#endif +#endif /* STATIC_WL_PRIV_STRUCT */ if (wl->afx_hdl) { cancel_work_sync(&wl->afx_hdl->work); kfree(wl->afx_hdl); @@ -5729,7 +7601,12 @@ static s32 wl_create_event_handler(struct wl_priv *wl) /* Do not use DHD in cfg driver */ wl->event_tsk.thr_pid = -1; + +#ifdef USE_KTHREAD_API + PROC_START2(wl_event_handler, wl, &wl->event_tsk, 0, "wl_event_handler"); +#else PROC_START(wl_event_handler, wl, &wl->event_tsk, 0); +#endif if (wl->event_tsk.thr_pid < 0) ret = -ENOMEM; return ret; @@ -5845,7 +7722,7 @@ static s32 wl_iscan_pending(struct wl_priv *wl) s32 err = 0; /* Reschedule the timer */ - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); iscan->timer_on = 1; return err; @@ -5861,7 +7738,7 @@ static s32 wl_iscan_inprogress(struct wl_priv *wl) wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); mutex_unlock(&wl->usr_sync); /* Reschedule the timer */ - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); iscan->timer_on = 1; return err; @@ -5974,11 +7851,24 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, struct net_device *dev = ndev; struct wireless_dev *wdev = dev->ieee80211_ptr; struct wl_priv *wl = wlcfg_drv_priv; + int refcnt = 0; WL_DBG(("Enter \n")); if (!wdev || !wl || dev == wl_to_prmry_ndev(wl)) return NOTIFY_DONE; switch (state) { + case NETDEV_DOWN: + while (work_pending(&wdev->cleanup_work) && refcnt < 100) { + if (refcnt%5 == 0) + WL_ERR(("%s : [NETDEV_DOWN] work_pending (%d th)\n", + __FUNCTION__, refcnt)); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(100); + set_current_state(TASK_RUNNING); + refcnt++; + } + break; + case NETDEV_UNREGISTER: /* after calling list_del_rcu(&wdev->list) */ wl_dealloc_netinfo(wl, ndev); @@ -6015,6 +7905,12 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, WL_DBG(("Enter \n")); + if (wl->escan_info.ndev != ndev) + { + WL_ERR(("ndev is different %p %p\n", wl->escan_info.ndev, ndev)); + return err; + } + if (wl->scan_request) { if (wl->scan_request->dev == wl->p2p_net) dev = wl_to_prmry_ndev(wl); @@ -6022,18 +7918,18 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, dev = wl->scan_request->dev; } else { - WL_ERR(("wl->scan_request is NULL may be internal scan." + WL_DBG(("wl->scan_request is NULL may be internal scan." "doing scan_abort for ndev %p primary %p p2p_net %p", ndev, wl_to_prmry_ndev(wl), wl->p2p_net)); dev = ndev; } - if (fw_abort) { + if (fw_abort && !in_atomic()) { /* Our scan params only need space for 1 channel and 0 ssids */ params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); if (params == NULL) { WL_ERR(("scan params allocation failed \n")); err = -ENOMEM; - } else if (!in_atomic()) { + } else { /* Do a scan abort to stop the driver's scan engine */ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); if (err < 0) { @@ -6043,6 +7939,22 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, } if (timer_pending(&wl->scan_timeout)) del_timer_sync(&wl->scan_timeout); +#if defined(ESCAN_RESULT_PATCH) + if (likely(wl->scan_request)) { +#if defined(DUAL_ESCAN_RESULT_BUFFER) + u8 temp_id = wl->escan_info.cur_sync_id; + if (aborted) + wl->bss_list = + (wl_scan_results_t *)wl->escan_info.escan_buf[(temp_id+1)%2]; + else + wl->bss_list = + (wl_scan_results_t *)wl->escan_info.escan_buf[(temp_id)%2]; +#else + wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; +#endif + wl_inform_bss(wl); + } +#endif /* ESCAN_RESULT_PATCH */ spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (likely(wl->scan_request)) { cfg80211_scan_done(wl->scan_request, aborted); @@ -6068,12 +7980,15 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_escan_result_t *escan_result; wl_bss_info_t *bss = NULL; wl_scan_results_t *list; + wifi_p2p_ie_t * p2p_ie; u32 bi_length; u32 i; u8 *p2p_dev_addr = NULL; WL_DBG((" enter event type : %d, status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); + + mutex_lock(&wl->usr_sync); /* P2P SCAN is coming from primary interface */ if (wl_get_p2p_status(wl, SCANNING)) { if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) @@ -6084,11 +7999,20 @@ static s32 wl_escan_handler(struct wl_priv *wl, } if (!ndev || !wl->escan_on || !wl_get_drv_status(wl, SCANNING, ndev)) { +#if defined(DUAL_ESCAN_RESULT_BUFFER) + WL_ERR(("escan is not ready ndev %p wl->escan_on %d" + " drv_status 0x%x e_type %d e_states %d\n", + ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev), + ntoh32(e->event_type), ntoh32(e->status))); +#else WL_ERR(("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n", ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev))); - return err; +#endif + goto exit; } - +#if defined(DUAL_ESCAN_RESULT_BUFFER) + escan_result = (wl_escan_result_t *) data; +#endif if (status == WLC_E_STATUS_PARTIAL) { WL_INFO(("WLC_E_STATUS_PARTIAL \n")); escan_result = (wl_escan_result_t *) data; @@ -6110,21 +8034,30 @@ static s32 wl_escan_handler(struct wl_priv *wl, WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } +#if defined(DUAL_ESCAN_RESULT_BUFFER) + if (escan_result->sync_id != wl->escan_info.cur_sync_id) { + WL_ERR(("Escan sync id mismatch: status %d " + "cur_sync_id %d coming_sync_id %d\n", + status, wl->escan_info.cur_sync_id, escan_result->sync_id)); + goto exit; + } +#endif if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { - WL_ERR(("Ignoring IBSS result\n")); + WL_DBG(("Ignoring IBSS result\n")); goto exit; } } - if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { + if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); if (p2p_dev_addr && !memcmp(p2p_dev_addr, - wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) { + wl->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) { s32 channel = CHSPEC_CHANNEL( wl_chspec_driver_to_host(bi->chanspec)); - WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel)); + WL_DBG(("ACTION FRAME SCAN : Peer " MACDBG " found, channel : %d\n", + MAC2STRDBG(wl->afx_hdl->tx_dst_addr.octet), channel)); wl_clr_p2p_status(wl, SCANNING); wl->afx_hdl->peer_chan = channel; complete(&wl->act_frm_scan); @@ -6132,12 +8065,47 @@ static s32 wl_escan_handler(struct wl_priv *wl, } } else { + int cur_len = 0; +#if defined(DUAL_ESCAN_RESULT_BUFFER) + list = (wl_scan_results_t *) + wl->escan_info.escan_buf[wl->escan_info.cur_sync_id%2]; +#else list = (wl_scan_results_t *)wl->escan_info.escan_buf; - if (bi_length > ESCAN_BUF_SIZE - list->buflen) { - WL_ERR(("Buffer is too small: ignoring\n")); - goto exit; +#endif +#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) + if (wl->p2p_net && wl->scan_request && + wl->scan_request->dev == wl->p2p_net) { +#else + if (p2p_is_on(wl) && p2p_scan(wl)) { +#endif +#ifdef WL_HOST_BAND_MGMT + s32 channel = 0; + s32 channel_band = 0; +#endif /* WL_HOST_BAND_MGMT */ + /* p2p scan && allow only probe response */ + if (bi->flags & WL_BSS_FLAGS_FROM_BEACON) + goto exit; + if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, + bi->ie_length)) == NULL) { + WL_ERR(("Couldn't find P2PIE in probe" + " response/beacon\n")); + goto exit; + } +#ifdef WL_HOST_BAND_MGMT + channel = CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); + channel_band = (channel > CH_MAX_2G_CHANNEL) ? + WLC_BAND_5G : WLC_BAND_2G; + + + if ((wl->curr_band == WLC_BAND_5G) && + (channel_band == WLC_BAND_2G)) { + /* Avoid sending the GO results in band conflict */ + if (wl_cfgp2p_retreive_p2pattrib(p2p_ie, + P2P_SEID_GROUP_ID) != NULL) + goto exit; + } +#endif /* WL_HOST_BAND_MGMT */ } -#define WLC_BSS_RSSI_ON_CHANNEL 0x0002 for (i = 0; i < list->count; i++) { bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) : list->bss_info; @@ -6147,87 +8115,338 @@ static s32 wl_escan_handler(struct wl_priv *wl, == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) && bi->SSID_len == bss->SSID_len && !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { - if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == - (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) { + + /* do not allow beacon data to update + *the data recd from a probe response + */ + if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) && + (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) + goto exit; + + WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d" + " flags 0x%x, new: RSSI %d flags 0x%x\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), i, + bss->RSSI, bss->flags, bi->RSSI, bi->flags)); + + if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == + (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) { /* preserve max RSSI if the measurements are * both on-channel or both off-channel */ - bss->RSSI = MAX(bss->RSSI, bi->RSSI); - } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && - (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { + WL_SCAN(("%s("MACDBG"), same onchan" + ", RSSI: prev %d new %d\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + bss->RSSI, bi->RSSI)); + bi->RSSI = MAX(bss->RSSI, bi->RSSI); + } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && + (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { /* preserve the on-channel rssi measurement * if the new measurement is off channel */ - bss->RSSI = bi->RSSI; - bss->flags |= WLC_BSS_RSSI_ON_CHANNEL; + WL_SCAN(("%s("MACDBG"), prev onchan" + ", RSSI: prev %d new %d\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + bss->RSSI, bi->RSSI)); + bi->RSSI = bss->RSSI; + bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; } + if (dtoh32(bss->length) != bi_length) { + u32 prev_len = dtoh32(bss->length); + + WL_SCAN(("bss info replacement" + " is occured(bcast:%d->probresp%d)\n", + bss->ie_length, bi->ie_length)); + WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + prev_len, bi_length)); + + if (list->buflen - prev_len + bi_length + > ESCAN_BUF_SIZE) { + WL_ERR(("Buffer is too small: keep the" + " previous result of this AP\n")); + /* Only update RSSI */ + bss->RSSI = bi->RSSI; + bss->flags |= (bi->flags + & WL_BSS_FLAGS_RSSI_ONCHANNEL); + goto exit; + } + if (i < list->count - 1) { + /* memory copy required by this case only */ + memmove((u8 *)bss + bi_length, + (u8 *)bss + prev_len, + list->buflen - cur_len - prev_len); + } + list->buflen -= prev_len; + list->buflen += bi_length; + } + list->version = dtoh32(bi->version); + memcpy((u8 *)bss, (u8 *)bi, bi_length); goto exit; } + cur_len += dtoh32(bss->length); } + if (bi_length > ESCAN_BUF_SIZE - list->buflen) { + WL_ERR(("Buffer is too small: ignoring\n")); + goto exit; + } +#if defined(DUAL_ESCAN_RESULT_BUFFER) + memcpy(&(wl->escan_info.escan_buf[wl->escan_info.cur_sync_id%2] + [list->buflen]), bi, bi_length); +#else memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length); +#endif list->version = dtoh32(bi->version); list->buflen += bi_length; list->count++; - } } else if (status == WLC_E_STATUS_SUCCESS) { wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { +#if defined(DUAL_ESCAN_RESULT_BUFFER) + if (escan_result->sync_id != wl->escan_info.cur_sync_id) + WL_ERR(("Escan sync id mismatch: status %d " + "cur_sync_id %d coming_sync_id %d\n", + status, wl->escan_info.cur_sync_id, escan_result->sync_id)); +#endif + if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { WL_INFO(("ACTION FRAME SCAN DONE\n")); wl_clr_p2p_status(wl, SCANNING); wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); } else if (likely(wl->scan_request)) { - mutex_lock(&wl->usr_sync); WL_INFO(("ESCAN COMPLETED\n")); +#if defined(DUAL_ESCAN_RESULT_BUFFER) + wl->bss_list = (wl_scan_results_t *) + wl->escan_info.escan_buf[wl->escan_info.cur_sync_id%2]; +#else wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; +#endif wl_inform_bss(wl); wl_notify_escan_complete(wl, ndev, false, false); - mutex_unlock(&wl->usr_sync); } +#if defined(DUAL_ESCAN_RESULT_BUFFER) + wl->escan_info.cur_sync_id++; +#endif } else if (status == WLC_E_STATUS_ABORT) { wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { +#if defined(DUAL_ESCAN_RESULT_BUFFER) + if (escan_result->sync_id != wl->escan_info.cur_sync_id) + WL_ERR(("Escan sync id mismatch: status %d " + "cur_sync_id %d coming_sync_id %d\n", + status, wl->escan_info.cur_sync_id, escan_result->sync_id)); +#endif + if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { WL_INFO(("ACTION FRAME SCAN DONE\n")); wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); wl_clr_p2p_status(wl, SCANNING); if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); } else if (likely(wl->scan_request)) { - mutex_lock(&wl->usr_sync); WL_INFO(("ESCAN ABORTED\n")); +#if defined(DUAL_ESCAN_RESULT_BUFFER) + wl->bss_list = (wl_scan_results_t *) + wl->escan_info.escan_buf[(wl->escan_info.cur_sync_id+1)%2]; +#else wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; +#endif wl_inform_bss(wl); wl_notify_escan_complete(wl, ndev, true, false); - mutex_unlock(&wl->usr_sync); } +#if defined(DUAL_ESCAN_RESULT_BUFFER) + wl->escan_info.cur_sync_id += 2; +#endif } - else { + else if (status == WLC_E_STATUS_NEWSCAN) + { + escan_result = (wl_escan_result_t *) data; + WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", wl->scan_request)); + WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, + escan_result->bss_count)); + } else { WL_ERR(("unexpected Escan Event %d : abort\n", status)); wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { +#if defined(DUAL_ESCAN_RESULT_BUFFER) + if (escan_result->sync_id != wl->escan_info.cur_sync_id) + WL_ERR(("Escan sync id mismatch: status %d " + "cur_sync_id %d coming_sync_id %d\n", + status, wl->escan_info.cur_sync_id, escan_result->sync_id)); +#endif + if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { WL_INFO(("ACTION FRAME SCAN DONE\n")); wl_clr_p2p_status(wl, SCANNING); wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); } else if (likely(wl->scan_request)) { - mutex_lock(&wl->usr_sync); +#if defined(DUAL_ESCAN_RESULT_BUFFER) + wl->bss_list = (wl_scan_results_t *) + wl->escan_info.escan_buf[(wl->escan_info.cur_sync_id+1)%2]; +#else wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; +#endif wl_inform_bss(wl); wl_notify_escan_complete(wl, ndev, true, false); - mutex_unlock(&wl->usr_sync); } +#if defined(DUAL_ESCAN_RESULT_BUFFER) + wl->escan_info.cur_sync_id += 2; +#endif } exit: + mutex_unlock(&wl->usr_sync); + return err; +} +static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, + enum wl_status state, bool set) +{ + s32 pm = PM_FAST; + s32 err = BCME_OK; + u32 chan = 0; + u32 chanspec = 0; + u32 prev_chan = 0; + u32 connected_cnt = 0; + struct net_info *iter, *next; + struct net_device *primary_dev = wl_to_prmry_ndev(wl); + if (set) { /* set */ + switch (state) { + case WL_STATUS_CONNECTED: { + if ((connected_cnt = wl_get_drv_status_all(wl, CONNECTED)) > 1) { + pm = PM_OFF; + WL_INFO(("Do not enable the power save for VSDB mode\n")); + } else if (_net_info->pm_block) { + pm = PM_OFF; + } else { + pm = PM_FAST; + } + for_each_ndev(wl, iter, next) { + if ((connected_cnt == 1) && (iter->ndev != _net_info->ndev)) + continue; + chanspec = 0; + chan = 0; + if (wl_get_drv_status(wl, CONNECTED, iter->ndev)) { + if (wldev_iovar_getint(iter->ndev, "chanspec", + (s32 *)&chanspec) == BCME_OK) { + chan = CHSPEC_CHANNEL(chanspec); + if (CHSPEC_IS40(chanspec)) { + if (CHSPEC_SB_UPPER(chanspec)) + chan += CH_10MHZ_APART; + else + chan -= CH_10MHZ_APART; + } + wl_update_prof(wl, iter->ndev, NULL, + &chan, WL_PROF_CHAN); + } + if ((wl_get_mode_by_netdev(wl, iter->ndev) + == WL_MODE_BSS)) { + pm = htod32(pm); + WL_DBG(("power save %s\n", + (pm ? "enabled" : "disabled"))); + err = wldev_ioctl(iter->ndev, WLC_SET_PM, + &pm, sizeof(pm), true); + if (unlikely(err)) { + if (err == -ENODEV) + WL_DBG(("net_device" + " is not ready\n")); + else + WL_ERR(("error" + " (%d)\n", err)); + break; + } else { + wl_cfg80211_update_power_mode(iter->ndev); + } + } + if (connected_cnt > 1) { + if (!prev_chan && chan) + prev_chan = chan; + else if (prev_chan && (prev_chan != chan)) { + wl->vsdb_mode = true; + } + if (wl->roamoff_on_concurrent) { + if ((err = wldev_iovar_getint(iter->ndev, + "roam_off", (s32 *)&iter->roam_off)) + == BCME_OK) { + if ((err = + wldev_iovar_setint(iter->ndev, + "roam_off", 1)) != + BCME_OK) { + WL_ERR((" failed to set " + "roam_off : %d\n", err)); + } + } else + WL_ERR(("failed to get" + " roam_off : %d\n", err)); + } + } + } + } + if (wl_get_mode_by_netdev(wl, _net_info->ndev) == WL_MODE_AP) { + if (wl_add_remove_eventmsg(primary_dev, + WLC_E_P2P_PROBREQ_MSG, false)) + WL_ERR((" failed to unset" + " WLC_E_P2P_PROPREQ_MSG\n")); + } + break; + } + default: + break; + } + } else { /* clear */ + switch (state) { + case WL_STATUS_CONNECTED: { + chan = 0; + /* clear chan information when the net device is disconnected */ + wl_update_prof(wl, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); + if (wl_get_drv_status_all(wl, CONNECTED) == 1) { + wl->vsdb_mode = false; + for_each_ndev(wl, iter, next) { + if (wl_get_drv_status(wl, CONNECTED, iter->ndev) && + (wl_get_mode_by_netdev(wl, iter->ndev) + == WL_MODE_BSS)) { + if (wl_get_netinfo_by_netdev(wl, + iter->ndev)->pm_block) + pm = PM_OFF; + else + pm = PM_FAST; + pm = htod32(pm); + WL_DBG(("power save %s\n", + (pm ? "enabled" : "disabled"))); + err = wldev_ioctl(iter->ndev, + WLC_SET_PM, &pm, sizeof(pm), true); + if (unlikely(err)) { + if (err == -ENODEV) + WL_DBG(("net_device" + " is not ready\n")); + else + WL_ERR(("error" + " (%d)\n", err)); + break; + } else { + wl_cfg80211_update_power_mode(iter->ndev); + } + } + } + } + if (wl->roamoff_on_concurrent) { + for_each_ndev(wl, iter, next) { + if ((iter->roam_off != WL_INVALID) && + ((err = wldev_iovar_setint(iter->ndev, "roam_off", + iter->roam_off)) == BCME_OK)) { + iter->roam_off = WL_INVALID; + } else if (err) + WL_ERR((" failed to set roam_off : %d\n", err)); + } + } + break; + } + default: + break; + } + } return err; } - static s32 wl_init_scan(struct wl_priv *wl) { struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); @@ -6252,6 +8471,9 @@ static s32 wl_init_scan(struct wl_priv *wl) } else if (wl->escan_on) { wl->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; +#if defined(DUAL_ESCAN_RESULT_BUFFER) + wl->escan_info.cur_sync_id = 0; +#endif } /* Init scan_timeout timer */ init_timer(&wl->scan_timeout); @@ -6275,9 +8497,16 @@ static s32 wl_init_priv(struct wl_priv *wl) wl->iscan_kickstart = false; wl->active_scan = true; wl->rf_blocked = false; + wl->vsdb_mode = false; + wl->wlfc_on = false; + wl->roamoff_on_concurrent = true; + /* register interested state */ + set_bit(WL_STATUS_CONNECTED, &wl->interrested_state); spin_lock_init(&wl->cfgdrv_lock); mutex_init(&wl->ioctl_buf_sync); init_waitqueue_head(&wl->netif_change_event); + init_completion(&wl->send_af_done); + init_completion(&wl->iface_disable); wl_init_eq(wl); err = wl_init_priv_mem(wl); if (err) @@ -6356,7 +8585,11 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) return -ENODEV; } wl = wlcfg_drv_priv; - if (wl && !wl_get_drv_status(wl, READY, ndev)) { + if (unlikely(!wl)) { + WL_ERR(("wl is invaild\n")); + return -EINVAL; + } + if (!wl_get_drv_status(wl, READY, ndev)) { if (wl->wdev && wl_cfgp2p_supported(wl, ndev)) { #if !defined(WL_ENABLE_P2P_IF) @@ -6372,8 +8605,9 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) /* Update MAC addr for p2p0 interface here. */ memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); wl->p2p_net->dev_addr[0] |= 0x02; - printk("%s: p2p_dev_addr="MACSTR "\n", - wl->p2p_net->name, MAC2STR(wl->p2p_net->dev_addr)); + WL_ERR(("%s: p2p_dev_addr="MACDBG "\n", + wl->p2p_net->name, + MAC2STRDBG(wl->p2p_net->dev_addr))); } else { WL_ERR(("p2p_net not yet populated." " Couldn't update the MAC Address for p2p0 \n")); @@ -6383,8 +8617,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) wl->p2p_supported = true; } - } else - return -ENODEV; + } wl_set_drv_status(wl, READY, ndev); fail: return err; @@ -6423,7 +8656,8 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) ndev->ieee80211_ptr = wdev; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; - err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS); + wl->state_notifier = wl_notifier_change_state; + err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS, PM_ENABLE); if (err) { WL_ERR(("Failed to alloc net_info (%d)\n", err)); goto cfg80211_attach_out; @@ -6478,12 +8712,15 @@ void wl_cfg80211_detach(void *para) wl_cfg80211_btcoex_deinit(wl); #endif + wl_setup_rfkill(wl, FALSE); + if (wl->p2p_supported) { + WL_ERR(("wl_cfgp2p_down() is not called yet\n")); + wl_cfgp2p_down(wl); + } + #if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) wl_cfg80211_detach_p2p(); #endif - wl_setup_rfkill(wl, FALSE); - if (wl->p2p_supported) - wl_cfgp2p_deinit_priv(wl); wl_deinit_priv(wl); wlcfg_drv_priv = NULL; wl_cfg80211_clear_parent_dev(); @@ -6545,8 +8782,12 @@ static s32 wl_event_handler(void *data) tsk_ctl_t *tsk = (tsk_ctl_t *)data; wl = (struct wl_priv *)tsk->parent; +#ifndef USE_KTHREAD_API DAEMONIZE("dhd_cfg80211_event"); complete(&tsk->completed); +#else + WL_ERR(("tsk Enter, tsk = 0x%08x\n", (unsigned int)tsk)); +#endif while (down_interruptible (&tsk->sema) == 0) { SMP_RD_BARRIER_DEPENDS(); @@ -6585,6 +8826,10 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) u32 event_type = ntoh32(e->event_type); struct wl_priv *wl = wlcfg_drv_priv; +#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) + int pno_wakelock_timeout = 10; /* 10 second */ +#endif + #if (WL_DBG_LEVEL > 0) s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? wl_dbg_estr[event_type] : (s8 *) "Unknown"; @@ -6592,6 +8837,9 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) #endif /* (WL_DBG_LEVEL > 0) */ if (event_type == WLC_E_PFN_NET_FOUND) { +#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) + net_os_wake_lock_timeout_for_pno(ndev, pno_wakelock_timeout); +#endif WL_DBG((" PNOEVENT: PNO_NET_FOUND\n")); } else if (event_type == WLC_E_PFN_NET_LOST) { @@ -6724,13 +8972,14 @@ static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 ift return 0; } -static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) +s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) { s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; s8 eventmask[WL_EVENTING_MASK_LEN]; s32 err = 0; - + if (!ndev) + return -ENODEV; /* Setup event_msgs */ bcm_mkiovar("event_msgs", NULL, 0, iovbuf, sizeof(iovbuf)); @@ -6758,70 +9007,229 @@ static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) } +static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) +{ + struct net_device *dev = wl_to_prmry_ndev(wl); + struct ieee80211_channel *band_chan_arr = NULL; + wl_uint32_list_t *list; + u32 i, j, index, n_2g, n_5g, band, channel, array_size; + u32 *n_cnt = NULL; + chanspec_t c = 0; + s32 err = BCME_OK; + bool update; + bool ht40_allowed; + u8 *pbuf = NULL; + +#define LOCAL_BUF_LEN 1024 + pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); + + if (pbuf == NULL) { + WL_ERR(("failed to allocate local buf\n")); + return -ENOMEM; + } + list = (wl_uint32_list_t *)(void *) pbuf; + list->count = htod32(WL_NUMCHANSPECS); + + + err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, + 0, pbuf, LOCAL_BUF_LEN, 0, &wl->ioctl_buf_sync); + if (err != 0) { + WL_ERR(("get chanspecs failed with %d\n", err)); + kfree(pbuf); + return err; + } +#undef LOCAL_BUF_LEN + + list = (wl_uint32_list_t *)(void *)pbuf; + band = array_size = n_2g = n_5g = 0; + for (i = 0; i < dtoh32(list->count); i++) { + index = 0; + update = false; + ht40_allowed = false; + c = (chanspec_t)dtoh32(list->element[i]); + c = wl_chspec_driver_to_host(c); + channel = CHSPEC_CHANNEL(c); + if (CHSPEC_IS40(c)) { + if (CHSPEC_SB_UPPER(c)) + channel += CH_10MHZ_APART; + else + channel -= CH_10MHZ_APART; + } + if (CHSPEC_IS2G(c) && channel <= CH_MAX_2G_CHANNEL) { + band_chan_arr = __wl_2ghz_channels; + array_size = ARRAYSIZE(__wl_2ghz_channels); + n_cnt = &n_2g; + band = IEEE80211_BAND_2GHZ; + ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; + } else if (CHSPEC_IS5G(c) && channel > CH_MAX_2G_CHANNEL) { + band_chan_arr = __wl_5ghz_a_channels; + array_size = ARRAYSIZE(__wl_5ghz_a_channels); + n_cnt = &n_5g; + band = IEEE80211_BAND_5GHZ; + ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; + } else { + WL_ERR(("Invalid channel Sepc. 0x%x.\n", c)); + continue; + } + for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { + if (band_chan_arr[j].hw_value == channel) { + update = true; + break; + } + } + if (update) + index = j; + else + index = *n_cnt; + if (index < array_size) { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) + band_chan_arr[index].center_freq = + ieee80211_channel_to_frequency(channel); +#else + band_chan_arr[index].center_freq = + ieee80211_channel_to_frequency(channel, band); +#endif + band_chan_arr[index].hw_value = channel; + + if (CHSPEC_IS40(c) && ht40_allowed) { + /* assuming the order is HT20, HT40 Upper, + HT40 lower from chanspecs + */ + u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; + if (CHSPEC_SB_UPPER(c)) { + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags &= + ~IEEE80211_CHAN_NO_HT40; + band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; + } else { + /* It should be one of + IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS + */ + band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags |= + IEEE80211_CHAN_NO_HT40MINUS; + } + } else { + band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; + if (band == IEEE80211_BAND_2GHZ) + channel |= WL_CHANSPEC_BAND_2G; + else + channel |= WL_CHANSPEC_BAND_5G; + channel |= WL_CHANSPEC_BW_20; + channel = wl_chspec_host_to_driver(channel); + err = wldev_iovar_getint(dev, "per_chan_info", &channel); + if (!err) { + if (channel & WL_CHAN_RADAR) + band_chan_arr[index].flags |= + (IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IBSS); + if (channel & WL_CHAN_PASSIVE) + band_chan_arr[index].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + } + } + if (!update) + (*n_cnt)++; + } + + } + __wl_band_2ghz.n_channels = n_2g; + __wl_band_5ghz_a.n_channels = n_5g; + kfree(pbuf); + return err; +} + s32 wl_update_wiphybands(struct wl_priv *wl) { struct wiphy *wiphy; + struct net_device *dev; u32 bandlist[3]; u32 nband = 0; u32 i = 0; s32 err = 0; - int nmode = 0; - int bw_40 = 0; - int index = 0; + s32 index = 0; + s32 nmode = 0; + bool rollback_lock = false; + s32 bw_cap = 0; + s32 cur_band = -1; + if (wl == NULL) { + wl = wlcfg_drv_priv; + mutex_lock(&wl->usr_sync); + rollback_lock = true; + } + dev = wl_to_prmry_ndev(wl); - WL_DBG(("Entry")); memset(bandlist, 0, sizeof(bandlist)); - err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist, + err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist, sizeof(bandlist), false); + if (unlikely(err)) { + WL_ERR(("error real bandlist (%d)\n", err)); + goto end_bands; + } + err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band, + sizeof(s32), false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); - return err; + goto end_bands; } - wiphy = wl_to_wiphy(wl); - nband = bandlist[0]; - wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; - err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "nmode", &nmode); + err = wldev_iovar_getint(dev, "nmode", &nmode); if (unlikely(err)) { WL_ERR(("error reading nmode (%d)\n", err)); - } - else { - /* For nmodeonly check bw cap */ - err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "mimo_bw_cap", &bw_40); + } else { + /* For nmodeonly check bw cap */ + err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); if (unlikely(err)) { - WL_ERR(("error get mimo_bw_cap (%d)\n", err)); + WL_ERR(("error get mimo_bw_cap (%d)\n", err)); } } - for (i = 1; i <= nband && i < sizeof(bandlist)/sizeof(u32); i++) { + err = wl_construct_reginfo(wl, bw_cap); + if (err) { + WL_ERR(("wl_construct_reginfo() fails err=%d\n", err)); + if (err != BCME_UNSUPPORTED) + goto end_bands; + err = 0; + } + wiphy = wl_to_wiphy(wl); + nband = bandlist[0]; + wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; + for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { index = -1; - if (bandlist[i] == WLC_BAND_5G) { + if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) { wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; index = IEEE80211_BAND_5GHZ; - } else if (bandlist[i] == WLC_BAND_2G) { + if (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G) + wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + } + else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; index = IEEE80211_BAND_2GHZ; + if (bw_cap == WLC_N_BW_40ALL) + wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; } if ((index >= 0) && nmode) { - wiphy->bands[index]->ht_cap.cap = - IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40 - | IEEE80211_HT_CAP_MAX_AMSDU; + wiphy->bands[index]->ht_cap.cap |= + (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); wiphy->bands[index]->ht_cap.ht_supported = TRUE; wiphy->bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; wiphy->bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + /* An HT shall support all EQM rates for one spatial stream */ + wiphy->bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; } - if ((index >= 0) && bw_40) { - wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; - } } wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); - return err; + end_bands: + if (rollback_lock) + mutex_unlock(&wl->usr_sync); + return err; } static s32 __wl_cfg80211_up(struct wl_priv *wl) @@ -6847,6 +9255,15 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl) err = dhd_monitor_init(wl->pub); err = wl_invoke_iscan(wl); + +#ifdef WL_HOST_BAND_MGMT + /* By default the curr_band is initialized to BAND_AUTO */ + if (wl_cfg80211_set_band(ndev, WLC_BAND_AUTO) < 0) { + WL_ERR(("roam_band set failed\n")); + err = -1; + } +#endif /* WL_HOST_BAND_MGMT */ + wl_set_drv_status(wl, READY, ndev); return err; } @@ -6857,11 +9274,16 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) unsigned long flags; struct net_info *iter, *next; struct net_device *ndev = wl_to_prmry_ndev(wl); - +#ifdef WL_ENABLE_P2P_IF +#if !defined(CUSTOMER_HW4) + struct net_device *p2p_net = wl->p2p_net; +#endif /* !defined(CUSTOMER_HW4) */ +#endif /* WL_ENABLE_P2P_IF */ WL_DBG(("In\n")); /* Check if cfg80211 interface is already down */ if (!wl_get_drv_status(wl, READY, ndev)) return err; /* it is even not ready */ + for_each_ndev(wl, iter, next) wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); @@ -6871,6 +9293,8 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; } + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + for_each_ndev(wl, iter, next) { wl_clr_drv_status(wl, READY, iter->ndev); wl_clr_drv_status(wl, SCANNING, iter->ndev); @@ -6883,8 +9307,10 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) } wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; - spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); - +#if !defined(CUSTOMER_HW4) + if (p2p_net) + dev_close(p2p_net); +#endif DNGL_FUNC(dhd_cfg80211_down, (wl)); wl_flush_eq(wl); wl_link_down(wl); @@ -6900,6 +9326,7 @@ s32 wl_cfg80211_up(void *para) struct wl_priv *wl; s32 err = 0; int val = 1; + dhd_pub_t *dhd; (void)para; WL_DBG(("In\n")); @@ -6917,15 +9344,19 @@ s32 wl_cfg80211_up(void *para) return BCME_VERSION; } ioctl_version = val; - WL_ERR(("WLC_GET_VERSION=%d\n", ioctl_version)); + WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version)); mutex_lock(&wl->usr_sync); - wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); + dhd = (dhd_pub_t *)(wl->pub); + if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { + err = wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); + if (unlikely(err)) + return err; + } err = __wl_cfg80211_up(wl); - if (err) + if (unlikely(err)) WL_ERR(("__wl_cfg80211_up failed\n")); mutex_unlock(&wl->usr_sync); - return err; } @@ -6979,6 +9410,8 @@ static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item) break; case WL_PROF_SSID: rptr = &profile->ssid; + case WL_PROF_CHAN: + rptr = &profile->channel; break; } spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); @@ -7025,12 +9458,17 @@ wl_update_prof(struct wl_priv *wl, struct net_device *ndev, case WL_PROF_DTIMPERIOD: profile->dtim_period = *(u8 *)data; break; + case WL_PROF_CHAN: + profile->channel = *(u32*)data; default: - WL_ERR(("unsupported item (%d)\n", item)); err = -EOPNOTSUPP; break; } spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + + if (err == EOPNOTSUPP) + WL_ERR(("unsupported item (%d)\n", item)); + return err; } @@ -7150,8 +9588,7 @@ static void wl_init_eq_lock(struct wl_priv *wl) static void wl_delay(u32 ms) { - if (ms < 1000 / HZ) { - cond_resched(); + if (in_atomic() || (ms < jiffies_to_msecs(1))) { mdelay(ms); } else { msleep(ms); @@ -7206,17 +9643,44 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, { struct wl_priv *wl; struct net_device *ndev = NULL; + struct ether_addr primary_mac; s32 ret = 0; s32 bssidx = 0; s32 pktflag = 0; wl = wlcfg_drv_priv; - if (wl->p2p && wl->p2p->vif_created) { - ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); - bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION); - } else if (wl_get_drv_status(wl, AP_CREATING, net) || + + if (wl_get_drv_status(wl, AP_CREATING, net) || wl_get_drv_status(wl, AP_CREATED, net)) { ndev = net; bssidx = 0; + } else if (wl->p2p) { + if (net == wl->p2p_net) { + net = wl_to_prmry_ndev(wl); + } + if (!wl->p2p->on) { + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, + &wl->p2p->int_addr); + /* In case of p2p_listen command, supplicant send remain_on_channel + * without turning on P2P + */ + + p2p_on(wl) = true; + ret = wl_cfgp2p_enable_discovery(wl, net, NULL, 0); + + if (unlikely(ret)) { + goto exit; + } + } + if (net != wl_to_prmry_ndev(wl)) { + if (wl_get_mode_by_netdev(wl, net) == WL_MODE_AP) { + ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION); + } + } else { + ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + } } if (ndev != NULL) { switch (type) { @@ -7233,7 +9697,7 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, if (pktflag) ret = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, pktflag, buf, len); } - +exit: return ret; } @@ -7309,7 +9773,7 @@ static void wl_cfg80211_clear_parent_dev(void) static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac) { wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL, - 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync); + 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, 0, &wl->ioctl_buf_sync); memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN); } @@ -7326,7 +9790,116 @@ int wl_cfg80211_do_driver_init(struct net_device *net) return 0; } -void wl_cfg80211_enable_trace(int level) +void wl_cfg80211_enable_trace(bool set, u32 level) +{ + if (set) + wl_dbg_level = level & WL_DBG_LEVEL; + else + wl_dbg_level |= (WL_DBG_LEVEL & level); +} + +#ifdef WL11U +bcm_tlv_t * +wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) { + return (bcm_tlv_t *)ie; + } + return NULL; +} + + +static s32 +wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, + uint8 ie_id, uint8 *data, uint8 data_len) +{ + s32 err = BCME_OK; + s32 buf_len; + s32 iecount; + ie_setbuf_t *ie_setbuf; + + if (ie_id != DOT11_MNG_INTERWORKING_ID) + return BCME_UNSUPPORTED; + + /* Validate the pktflag parameter */ + if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | + VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | + VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| + VNDR_IE_CUSTOM_FLAG))) { + WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag)); + return -1; + } + + /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ + pktflag = htod32(pktflag); + + buf_len = sizeof(ie_setbuf_t) + data_len - 1; + ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); + + if (!ie_setbuf) { + WL_ERR(("Error allocating buffer for IE\n")); + return -ENOMEM; + } + + if (wl->iw_ie_len == data_len && !memcmp(wl->iw_ie, data, data_len)) { + WL_ERR(("Previous IW IE is equals to current IE\n")); + return err; + } + + strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); + ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); + memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); + + /* Now, add the IE to the buffer */ + ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; + + /* if already set with previous values, delete it first */ + if (wl->iw_ie_len != 0) { + WL_DBG(("Different IW_IE was already set. clear first\n")); + + ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; + + err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); + + if (err != BCME_OK) + return err; + } + + ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; + memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); + + err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); + + if (err == BCME_OK) { + memcpy(wl->iw_ie, data, data_len); + wl->iw_ie_len = data_len; + wl->wl11u = TRUE; + + err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); + } + + kfree(ie_setbuf); + return err; +} +#endif /* WL11U */ + +static s32 +wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct net_device *dev, u64 cookie) { - wl_dbg_level |= WL_DBG_DBG; + /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION + * is passed with CMD_FRAME. This callback is supposed to cancel + * the OFFCHANNEL Wait. Since we are already taking care of that + * with the tx_mgmt logic, do nothing here. + */ + + return 0; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index edf8a300daa..35a4f0580f8 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.h 316895 2012-02-24 00:05:41Z $ + * $Id: wl_cfg80211.h 358186 2012-09-21 14:36:14Z $ */ #ifndef _wl_cfg80211_h_ @@ -52,6 +52,7 @@ struct wl_ibss; #define dtohchanspec(i) i #define WL_DBG_NONE 0 +#define WL_DBG_P2P_ACTION (1 << 5) #define WL_DBG_TRACE (1 << 4) #define WL_DBG_SCAN (1 << 3) #define WL_DBG_DBG (1 << 2) @@ -61,20 +62,31 @@ struct wl_ibss; /* 0 invalidates all debug messages. default is 1 */ #define WL_DBG_LEVEL 0xFF +#if defined(DHD_DEBUG) #define WL_ERR(args) \ do { \ if (wl_dbg_level & WL_DBG_ERR) { \ - printk(KERN_ERR "CFG80211-ERROR) %s : ", __func__); \ + printk(KERN_INFO "CFG80211-INFO2) %s : ", __func__); \ printk args; \ } \ } while (0) +#else /* defined(DHD_DEBUG) */ +#define WL_ERR(args) \ +do { \ + if ((wl_dbg_level & WL_DBG_ERR) && net_ratelimit()) { \ + printk(KERN_INFO "CFG80211-INFO2) %s : ", __func__); \ + printk args; \ + } \ +} while (0) +#endif /* defined(DHD_DEBUG) */ + #ifdef WL_INFO #undef WL_INFO #endif #define WL_INFO(args) \ do { \ if (wl_dbg_level & WL_DBG_INFO) { \ - printk(KERN_ERR "CFG80211-INFO) %s : ", __func__); \ + printk(KERN_INFO "CFG80211-INFO) %s : ", __func__); \ printk args; \ } \ } while (0) @@ -84,7 +96,7 @@ do { \ #define WL_SCAN(args) \ do { \ if (wl_dbg_level & WL_DBG_SCAN) { \ - printk(KERN_ERR "CFG80211-SCAN) %s :", __func__); \ + printk(KERN_INFO "CFG80211-SCAN) %s :", __func__); \ printk args; \ } \ } while (0) @@ -94,15 +106,29 @@ do { \ #define WL_TRACE(args) \ do { \ if (wl_dbg_level & WL_DBG_TRACE) { \ - printk(KERN_ERR "CFG80211-TRACE) %s :", __func__); \ + printk(KERN_INFO "CFG80211-TRACE) %s :", __func__); \ printk args; \ } \ } while (0) +#ifdef WL_TRACE_HW4 +#undef WL_TRACE_HW4 +#endif +#ifdef CUSTOMER_HW4 +#define WL_TRACE_HW4(args) \ +do { \ + if (wl_dbg_level & WL_DBG_ERR) { \ + printk(KERN_INFO "CFG80211-TRACE) %s : ", __func__); \ + printk args; \ + } \ +} while (0) +#else +#define WL_TRACE_HW4 WL_TRACE +#endif /* CUSTOMER_HW4 */ #if (WL_DBG_LEVEL > 0) #define WL_DBG(args) \ do { \ if (wl_dbg_level & WL_DBG_DBG) { \ - printk(KERN_ERR "CFG80211-DEBUG) %s :", __func__); \ + printk(KERN_DEBUG "CFG80211-DEBUG) %s :", __func__); \ printk args; \ } \ } while (0) @@ -114,7 +140,7 @@ do { \ #define WL_SCAN_RETRY_MAX 3 #define WL_NUM_PMKIDS_MAX MAXPMKID #define WL_SCAN_BUF_MAX (1024 * 8) -#define WL_TLV_INFO_MAX 1024 +#define WL_TLV_INFO_MAX 1500 #define WL_SCAN_IE_LEN_MAX 2048 #define WL_BSS_INFO_MAX 2048 #define WL_ASSOC_INFO_MAX 512 @@ -126,14 +152,25 @@ do { \ #define WL_AP_MAX 256 #define WL_FILE_NAME_MAX 256 #define WL_DWELL_TIME 200 -#define WL_MED_DWELL_TIME 400 +#define WL_MED_DWELL_TIME 400 +#define WL_MIN_DWELL_TIME 100 #define WL_LONG_DWELL_TIME 1000 #define IFACE_MAX_CNT 2 +#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 +#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 +#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 +#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 +#define WL_AF_TX_MAX_RETRY 5 #define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */ #define WL_CHANNEL_SYNC_RETRY 5 #define WL_INVALID -1 +/* Bring down SCB Timeout to 20secs from 60secs default */ +#ifndef WL_SCB_TIMEOUT +#define WL_SCB_TIMEOUT 20 +#endif + /* driver status */ enum wl_status { WL_STATUS_READY = 0, @@ -144,7 +181,33 @@ enum wl_status { WL_STATUS_DISCONNECTING, WL_STATUS_AP_CREATING, WL_STATUS_AP_CREATED, - WL_STATUS_SENDING_ACT_FRM + /* whole sending action frame procedure: + * includes a) 'finding common channel' for public action request frame + * and b) 'sending af via 'actframe' iovar' + */ + WL_STATUS_SENDING_ACT_FRM, + /* find a peer to go to a common channel before sending public action req frame */ + WL_STATUS_FINDING_COMMON_CHANNEL, + /* waiting for next af to sync time of supplicant. + * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN + */ + WL_STATUS_WAITING_NEXT_ACT_FRM, +#ifdef WL_CFG80211_SYNC_GON + /* go to listen state to wait for next af after SENDING_ACT_FRM */ + WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN, +#endif /* WL_CFG80211_SYNC_GON */ + /* it will be set when upper layer requests listen and succeed in setting listen mode. + * if set, other scan request can abort current listen state + */ + WL_STATUS_REMAINING_ON_CHANNEL, +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + /* it's fake listen state to keep current scan state. + * it will be set when upper layer requests listen but scan is running. then just run + * a expire timer without actual listen state. + * if set, other scan request does not need to abort scan. + */ + WL_STATUS_FAKE_REMAINING_ON_CHANNEL +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ }; /* wi-fi mode */ @@ -161,6 +224,7 @@ enum wl_prof_list { WL_PROF_SEC, WL_PROF_IBSS, WL_PROF_BAND, + WL_PROF_CHAN, WL_PROF_BSSID, WL_PROF_ACT, WL_PROF_BEACONINT, @@ -245,6 +309,7 @@ struct wl_security { u32 cipher_pairwise; u32 cipher_group; u32 wpa_auth; + u32 auth_assoc_res_status; }; /* ibss information for currently joined ibss network */ @@ -260,6 +325,7 @@ struct wl_ibss { struct wl_profile { u32 mode; s32 band; + u32 channel; struct wlc_ssid ssid; struct wl_security sec; struct wl_ibss ibss; @@ -274,7 +340,9 @@ struct net_info { struct wireless_dev *wdev; struct wl_profile profile; s32 mode; + s32 roam_off; unsigned long sme_state; + bool pm_block; struct list_head list; /* list of all net_info structure */ }; typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl); @@ -329,15 +397,33 @@ struct wl_pmk_list { struct escan_info { u32 escan_state; +#if defined(STATIC_WL_PRIV_STRUCT) +#ifndef CONFIG_DHD_USE_STATIC_BUF +#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF +#endif +#if defined(DUAL_ESCAN_RESULT_BUFFER) + u8 *escan_buf[2]; +#else + u8 *escan_buf; +#endif +#else +#if defined(DUAL_ESCAN_RESULT_BUFFER) + u8 escan_buf[2][ESCAN_BUF_SIZE]; +#else u8 escan_buf[ESCAN_BUF_SIZE]; +#endif +#endif /* STATIC_WL_PRIV_STRUCT */ +#if defined(DUAL_ESCAN_RESULT_BUFFER) + u8 cur_sync_id; +#endif struct wiphy *wiphy; struct net_device *ndev; }; struct ap_info { /* Structure to hold WPS, WPA IEs for a AP */ - u8 probe_res_ie[IE_MAX_LEN]; - u8 beacon_ie[IE_MAX_LEN]; + u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN]; + u8 beacon_ie[VNDR_IES_MAX_BUF_LEN]; u32 probe_res_ie_len; u32 beacon_ie_len; u8 *wpa_ie; @@ -361,23 +447,41 @@ struct btcoex_info { struct sta_info { /* Structure to hold WPS IE for a STA */ - u8 probe_req_ie[IE_MAX_LEN]; - u8 assoc_req_ie[IE_MAX_LEN]; + u8 probe_req_ie[VNDR_IES_BUF_LEN]; + u8 assoc_req_ie[VNDR_IES_BUF_LEN]; u32 probe_req_ie_len; u32 assoc_req_ie_len; }; struct afx_hdl { wl_af_params_t *pending_tx_act_frm; - struct ether_addr pending_tx_dst_addr; + struct ether_addr tx_dst_addr; struct net_device *dev; struct work_struct work; u32 bssidx; u32 retry; s32 peer_chan; + s32 peer_listen_chan; /* search channel: configured by upper layer */ + s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */ + bool is_listen; bool ack_recv; + bool is_active; +}; + +struct parsed_ies { + wpa_ie_fixed_t *wps_ie; + u32 wps_ie_len; + wpa_ie_fixed_t *wpa_ie; + u32 wpa_ie_len; + bcm_tlv_t *wpa2_ie; + u32 wpa2_ie_len; }; +#ifdef WL11U +/* Max length of Interworking element */ +#define IW_IES_MAX_BUF_LEN 9 +#endif + /* private data of cfg80211 interface */ struct wl_priv { struct wireless_dev *wdev; /* representing wl cfg80211 device */ @@ -393,6 +497,8 @@ struct wl_priv { spinlock_t eq_lock; /* for event queue synchronization */ spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ struct completion act_frm_scan; + struct completion iface_disable; + struct completion wait_next_af; struct mutex usr_sync; /* maily for up/down synchronization */ struct wl_scan_results *bss_list; struct wl_scan_results *scan_results; @@ -400,17 +506,31 @@ struct wl_priv { /* scan request object for internal purpose */ struct wl_scan_req *scan_req_int; /* information element object for internal purpose */ +#if defined(STATIC_WL_PRIV_STRUCT) + struct wl_ie *ie; +#else struct wl_ie ie; +#endif struct wl_iscan_ctrl *iscan; /* iscan controller */ /* association information container */ +#if defined(STATIC_WL_PRIV_STRUCT) + struct wl_connect_info *conn_info; +#else struct wl_connect_info conn_info; +#endif struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ tsk_ctl_t event_tsk; /* task of main event handler thread */ void *pub; u32 iface_cnt; u32 channel; /* current channel */ + u32 af_sent_channel; /* channel action frame is sent */ + /* next af subtype to cancel the remained dwell time in rx process */ + u8 next_af_subtype; +#ifdef WL_CFG80211_SYNC_GON + ulong af_tx_sent_jiffies; +#endif /* WL_CFG80211_SYNC_GON */ bool iscan_on; /* iscan on/off switch */ bool iscan_kickstart; /* indicate iscan already started */ bool escan_on; /* escan on/off switch */ @@ -423,7 +543,10 @@ struct wl_priv { bool pwr_save; bool roam_on; /* on/off switch for self-roaming */ bool scan_tried; /* indicates if first scan attempted */ - u8 *ioctl_buf; /* ioctl buffer */ + bool wlfc_on; + bool vsdb_mode; + bool roamoff_on_concurrent; + u8 *ioctl_buf; /* ioctl buffer */ struct mutex ioctl_buf_sync; u8 *escan_ioctl_buf; u8 *extra_buf; /* maily to grab assoc information */ @@ -435,6 +558,7 @@ struct wl_priv { u64 send_action_id; u64 last_roc_id; wait_queue_head_t netif_change_event; + struct completion send_af_done; struct afx_hdl *afx_hdl; struct ap_info *ap_info; struct sta_info *sta_info; @@ -442,6 +566,26 @@ struct wl_priv { bool p2p_supported; struct btcoex_info *btcoex_info; struct timer_list scan_timeout; /* Timer for catch scan event timeout */ +#ifdef WL_CFG80211_GON_COLLISION + u8 block_gon_req_tx_count; + u8 block_gon_req_rx_count; +#endif /* WL_CFG80211_GON_COLLISION */ + s32(*state_notifier) (struct wl_priv *wl, + struct net_info *_net_info, enum wl_status state, bool set); + unsigned long interrested_state; + wlc_ssid_t hostapd_ssid; +#ifdef WL11U + bool wl11u; + u8 iw_ie[IW_IES_MAX_BUF_LEN]; + u32 iw_ie_len; +#endif /* WL11U */ + bool sched_scan_running; /* scheduled scan req status */ +#ifdef WL_SCHED_SCAN + struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ +#endif /* WL_SCHED_SCAN */ +#ifdef WL_HOST_BAND_MGMT + u8 curr_band; +#endif /* WL_HOST_BAND_MGMT */ }; @@ -452,7 +596,7 @@ static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct } static inline s32 wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev, - struct wireless_dev * wdev, s32 mode) + struct wireless_dev * wdev, s32 mode, bool pm_block) { struct net_info *_net_info; s32 err = 0; @@ -465,6 +609,8 @@ wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev, _net_info->mode = mode; _net_info->ndev = ndev; _net_info->wdev = wdev; + _net_info->pm_block = pm_block; + _net_info->roam_off = WL_INVALID; wl->iface_cnt++; list_add(&_net_info->list, &wl->net_list); } @@ -501,7 +647,7 @@ wl_delete_all_netinfo(struct wl_priv *wl) } wl->iface_cnt = 0; } -static inline bool +static inline u32 wl_get_status_all(struct wl_priv *wl, s32 status) { @@ -512,7 +658,28 @@ wl_get_status_all(struct wl_priv *wl, s32 status) test_bit(status, &_net_info->sme_state)) cnt++; } - return cnt? true: false; + return cnt; +} +static inline void +wl_set_status_all(struct wl_priv *wl, s32 status, u32 op) +{ + struct net_info *_net_info, *next; + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + switch (op) { + case 1: + return; /* set all status is not allowed */ + case 2: + clear_bit(status, &_net_info->sme_state); + if (wl->state_notifier && + test_bit(status, &(wl->interrested_state))) + wl->state_notifier(wl, _net_info, status, false); + break; + case 4: + return; /* change all status is not allowed */ + default: + return; /* unknown operation */ + } + } } static inline void wl_set_status_by_netdev(struct wl_priv *wl, s32 status, @@ -526,9 +693,15 @@ wl_set_status_by_netdev(struct wl_priv *wl, s32 status, switch (op) { case 1: set_bit(status, &_net_info->sme_state); + if (wl->state_notifier && + test_bit(status, &(wl->interrested_state))) + wl->state_notifier(wl, _net_info, status, true); break; case 2: clear_bit(status, &_net_info->sme_state); + if (wl->state_notifier && + test_bit(status, &(wl->interrested_state))) + wl->state_notifier(wl, _net_info, status, false); break; case 4: change_bit(status, &_net_info->sme_state); @@ -588,14 +761,30 @@ wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev) } return NULL; } +static inline struct net_info * +wl_get_netinfo_by_netdev(struct wl_priv *wl, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return _net_info; + } + return NULL; +} #define wl_to_wiphy(w) (w->wdev->wiphy) #define wl_to_prmry_ndev(w) (w->wdev->netdev) #define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) #define wl_to_sr(w) (w->scan_req_int) +#if defined(STATIC_WL_PRIV_STRUCT) +#define wl_to_ie(w) (w->ie) +#define wl_to_conn(w) (w->conn_info) +#else #define wl_to_ie(w) (&w->ie) +#define wl_to_conn(w) (&w->conn_info) +#endif #define iscan_to_wl(i) ((struct wl_priv *)(i->data)) #define wl_to_iscan(w) (w->iscan) -#define wl_to_conn(w) (&w->conn_info) #define wiphy_from_scan(w) (w->escan_info.wiphy) #define wl_get_drv_status_all(wl, stat) \ (wl_get_status_all(wl, WL_STATUS_ ## stat)) @@ -605,6 +794,8 @@ wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev) (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 1)) #define wl_clr_drv_status(wl, stat, ndev) \ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 2)) +#define wl_clr_drv_status_all(wl, stat) \ + (wl_set_status_all(wl, WL_STATUS_ ## stat, 2)) #define wl_chg_drv_status(wl, stat, ndev) \ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 4)) @@ -636,7 +827,7 @@ extern s32 wl_cfg80211_down(void *para); extern s32 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, void* _net_attach); extern s32 wl_cfg80211_ifdel_ops(struct net_device *net); -extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev); +extern s32 wl_cfg80211_notify_ifdel(void); extern s32 wl_cfg80211_is_progress_ifadd(void); extern s32 wl_cfg80211_is_progress_ifchange(void); extern s32 wl_cfg80211_is_progress_ifadd(void); @@ -651,8 +842,12 @@ extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); extern s32 wl_mode_to_nl80211_iftype(s32 mode); int wl_cfg80211_do_driver_init(struct net_device *net); -void wl_cfg80211_enable_trace(int level); +void wl_cfg80211_enable_trace(bool set, u32 level); +extern s32 wl_update_wiphybands(struct wl_priv *wl); extern s32 wl_cfg80211_if_is_group_owner(void); extern chanspec_t wl_ch_host_to_driver(u16 channel); - +extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); +extern void wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev); +extern s32 wl_cfg80211_set_band(struct net_device *ndev, int band); +extern int wl_cfg80211_update_power_mode(struct net_device *dev); #endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index eb76fd0078d..7a9cbea04d3 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfgp2p.c 321498 2012-03-15 12:54:13Z $ + * $Id: wl_cfgp2p.c 358702 2012-09-25 06:48:56Z $ * */ #include @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -47,18 +48,20 @@ #include static s8 scanparambuf[WLC_IOCTL_SMLEN]; - +static s8 g_mgmt_ie_buf[2048]; static bool wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); -static s32 -wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, - s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete); +static u32 +wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, + s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd); static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); static int wl_cfgp2p_if_open(struct net_device *net); static int wl_cfgp2p_if_stop(struct net_device *net); +static s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, + bool notify); static const struct net_device_ops wl_cfgp2p_if_ops = { .ndo_open = wl_cfgp2p_if_open, @@ -105,6 +108,46 @@ bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) return false; } + +/* +* Currently Action frame just pass to P2P interface regardless real dst. +* but GAS Action can be used for Hotspot2.0 as well +* Need to distingush that it's for P2P or HS20 +*/ +#ifdef WL11U +#define GAS_RESP_LEN 2 +#define DOUBLE_TLV_BODY_OFF 4 +#define GAS_RESP_OFFSET 4 +#define GAS_CRESP_OFFSET 5 + +bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len) +{ + bcm_tlv_t *ie = (bcm_tlv_t *)data; + u8 *frame = NULL; + u16 id, flen; + + /* Skipped first ANQP Element, if frame has anqp elemnt */ + ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID); + + if (ie == NULL) + return false; + + frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN; + id = ((u16) (((frame)[1] << 8) | (frame)[0])); + flen = ((u16) (((frame)[3] << 8) | (frame)[2])); + + /* If the contents match the OUI and the type */ + if (flen >= WFA_OUI_LEN + 1 && + id == P2PSD_GAS_NQP_INFOID && + !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) && + subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) { + return true; + } + + return false; +} +#endif /* WL11U */ + bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) { @@ -119,6 +162,22 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) return false; +#ifdef WL11U + if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP) + return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, + (u8 *)sd_act_frm->query_data + GAS_RESP_OFFSET, + frame_len); + + else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) + return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, + (u8 *)sd_act_frm->query_data + GAS_CRESP_OFFSET, + frame_len); + else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ) + return true; + else + return false; +#else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || @@ -126,7 +185,7 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) return true; else return false; - +#endif /* WLC11U */ } void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) { @@ -140,43 +199,43 @@ void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) pact_frm = (wifi_p2p_pub_act_frame_t *)frame; switch (pact_frm->subtype) { case P2P_PAF_GON_REQ: - CFGP2P_DBG(("%s P2P Group Owner Negotiation Req Frame\n", + CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame\n", (tx)? "TX": "RX")); break; case P2P_PAF_GON_RSP: - CFGP2P_DBG(("%s P2P Group Owner Negotiation Rsp Frame\n", + CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame\n", (tx)? "TX": "RX")); break; case P2P_PAF_GON_CONF: - CFGP2P_DBG(("%s P2P Group Owner Negotiation Confirm Frame\n", + CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame\n", (tx)? "TX": "RX")); break; case P2P_PAF_INVITE_REQ: - CFGP2P_DBG(("%s P2P Invitation Request Frame\n", + CFGP2P_ACTION(("%s P2P Invitation Request Frame\n", (tx)? "TX": "RX")); break; case P2P_PAF_INVITE_RSP: - CFGP2P_DBG(("%s P2P Invitation Response Frame\n", + CFGP2P_ACTION(("%s P2P Invitation Response Frame\n", (tx)? "TX": "RX")); break; case P2P_PAF_DEVDIS_REQ: - CFGP2P_DBG(("%s P2P Device Discoverability Request Frame\n", + CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame\n", (tx)? "TX": "RX")); break; case P2P_PAF_DEVDIS_RSP: - CFGP2P_DBG(("%s P2P Device Discoverability Response Frame\n", + CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame\n", (tx)? "TX": "RX")); break; case P2P_PAF_PROVDIS_REQ: - CFGP2P_DBG(("%s P2P Provision Discovery Request Frame\n", + CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame\n", (tx)? "TX": "RX")); break; case P2P_PAF_PROVDIS_RSP: - CFGP2P_DBG(("%s P2P Provision Discovery Response Frame\n", + CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame\n", (tx)? "TX": "RX")); break; default: - CFGP2P_DBG(("%s Unknown P2P Public Action Frame\n", + CFGP2P_ACTION(("%s Unknown P2P Public Action Frame\n", (tx)? "TX": "RX")); } @@ -185,23 +244,23 @@ void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) act_frm = (wifi_p2p_action_frame_t *)frame; switch (act_frm->subtype) { case P2P_AF_NOTICE_OF_ABSENCE: - CFGP2P_DBG(("%s P2P Notice of Absence Frame\n", + CFGP2P_ACTION(("%s P2P Notice of Absence Frame\n", (tx)? "TX": "RX")); break; case P2P_AF_PRESENCE_REQ: - CFGP2P_DBG(("%s P2P Presence Request Frame\n", + CFGP2P_ACTION(("%s P2P Presence Request Frame\n", (tx)? "TX": "RX")); break; case P2P_AF_PRESENCE_RSP: - CFGP2P_DBG(("%s P2P Presence Response Frame\n", + CFGP2P_ACTION(("%s P2P Presence Response Frame\n", (tx)? "TX": "RX")); break; case P2P_AF_GO_DISC_REQ: - CFGP2P_DBG(("%s P2P Discoverability Request Frame\n", + CFGP2P_ACTION(("%s P2P Discoverability Request Frame\n", (tx)? "TX": "RX")); break; default: - CFGP2P_DBG(("%s Unknown P2P Action Frame\n", + CFGP2P_ACTION(("%s Unknown P2P Action Frame\n", (tx)? "TX": "RX")); } @@ -209,29 +268,28 @@ void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; switch (sd_act_frm->action) { case P2PSD_ACTION_ID_GAS_IREQ: - CFGP2P_DBG(("%s P2P GAS Initial Request\n", + CFGP2P_ACTION(("%s P2P GAS Initial Request\n", (tx)? "TX" : "RX")); break; case P2PSD_ACTION_ID_GAS_IRESP: - CFGP2P_DBG(("%s P2P GAS Initial Response\n", + CFGP2P_ACTION(("%s P2P GAS Initial Response\n", (tx)? "TX" : "RX")); break; case P2PSD_ACTION_ID_GAS_CREQ: - CFGP2P_DBG(("%s P2P GAS Comback Request\n", + CFGP2P_ACTION(("%s P2P GAS Comback Request\n", (tx)? "TX" : "RX")); break; case P2PSD_ACTION_ID_GAS_CRESP: - CFGP2P_DBG(("%s P2P GAS Comback Response\n", + CFGP2P_ACTION(("%s P2P GAS Comback Response\n", (tx)? "TX" : "RX")); break; default: - CFGP2P_DBG(("%s Unknown P2P GAS Frame\n", + CFGP2P_ACTION(("%s Unknown P2P GAS Frame\n", (tx)? "TX" : "RX")); } } - } /* @@ -274,7 +332,6 @@ wl_cfgp2p_init_priv(struct wl_priv *wl) wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL; wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0; - spin_lock_init(&wl->p2p->timer_lock); return BCME_OK; } @@ -306,13 +363,19 @@ wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) wldev_iovar_getint(ndev, "apsta", &val); if (val == 0) { val = 1; - wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); + ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); + if (ret < 0) { + CFGP2P_ERR(("WLC_DOWN error %d\n", ret)); + return ret; + } wldev_iovar_setint(ndev, "apsta", val); - wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); + ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); + if (ret < 0) { + CFGP2P_ERR(("WLC_UP error %d\n", ret)); + return ret; + } } - val = 1; - /* Disable firmware roaming for P2P */ - wldev_iovar_setint(ndev, "roam_off", val); + /* In case of COB type, firmware has default mac address * After Initializing firmware, we have to set current mac address to * firmware for P2P device address @@ -338,23 +401,52 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, { wl_p2p_if_t ifreq; s32 err; + u32 scb_timeout = WL_SCB_TIMEOUT; struct net_device *ndev = wl_to_prmry_ndev(wl); ifreq.type = if_type; ifreq.chspec = chspec; memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); - CFGP2P_DBG(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n", - ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2], - ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5], + CFGP2P_DBG(("---wl p2p_ifadd "MACDBG" %s %u\n", + MAC2STRDBG(ifreq.addr.octet), (if_type == WL_P2P_IF_GO) ? "go" : "client", (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); + + if (unlikely(err < 0)) + printk("'wl p2p_ifadd' error %d\n", err); + else if (if_type == WL_P2P_IF_GO) { + err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); + if (unlikely(err < 0)) + printk("'wl scb_timeout' error %d\n", err); + } return err; } +/* Disable a P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to create + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac) +{ + s32 ret; + struct net_device *netdev = wl_to_prmry_ndev(wl); + + CFGP2P_INFO(("------primary idx %d : wl p2p_ifdis "MACDBG"\n", + netdev->ifindex, MAC2STRDBG(mac->octet))); + ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac), + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); + if (unlikely(ret < 0)) { + printk("'wl p2p_ifdis' error %d\n", ret); + } + return ret; +} + /* Delete a P2P BSS. * Parameters: * @mac : MAC address of the BSS to create @@ -366,9 +458,8 @@ wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac) s32 ret; struct net_device *netdev = wl_to_prmry_ndev(wl); - CFGP2P_INFO(("------primary idx %d : wl p2p_ifdel %02x:%02x:%02x:%02x:%02x:%02x\n", - netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2], - mac->octet[3], mac->octet[4], mac->octet[5])); + CFGP2P_INFO(("------primary idx %d : wl p2p_ifdel "MACDBG"\n", + netdev->ifindex, MAC2STRDBG(mac->octet))); ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); if (unlikely(ret < 0)) { @@ -388,23 +479,29 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, { wl_p2p_if_t ifreq; s32 err; + u32 scb_timeout = WL_SCB_TIMEOUT; + struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); ifreq.type = if_type; ifreq.chspec = chspec; memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); - CFGP2P_INFO(("---wl p2p_ifchange %02x:%02x:%02x:%02x:%02x:%02x %s %u\n", - ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2], - ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5], - (if_type == WL_P2P_IF_GO) ? "go" : "client", - (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); + CFGP2P_INFO(("---wl p2p_ifchange "MACDBG" %s %u" + " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet), + (if_type == WL_P2P_IF_GO) ? "go" : "client", + (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT, + ifreq.chspec)); err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); if (unlikely(err < 0)) { printk("'wl p2p_ifupd' error %d\n", err); + } else if (if_type == WL_P2P_IF_GO) { + err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); + if (unlikely(err < 0)) + printk("'wl scb_timeout' error %d\n", err); } return err; } @@ -423,15 +520,13 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index) u8 getbuf[64]; struct net_device *dev = wl_to_prmry_ndev(wl); - CFGP2P_INFO(("---wl p2p_if %02x:%02x:%02x:%02x:%02x:%02x\n", - mac->octet[0], mac->octet[1], mac->octet[2], - mac->octet[3], mac->octet[4], mac->octet[5])); + CFGP2P_INFO(("---wl p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet))); ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL); if (ret == 0) { - memcpy(index, getbuf, sizeof(index)); + memcpy(index, getbuf, sizeof(s32)); CFGP2P_INFO(("---wl p2p_if ==> %d\n", *index)); } @@ -471,7 +566,7 @@ wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, struct net_device *dev; CFGP2P_DBG(("enter\n")); - if (unlikely(bssidx >= P2PAPI_BSSCFG_MAX)) { + if (unlikely(bssidx == WL_INVALID || bssidx >= P2PAPI_BSSCFG_MAX)) { CFGP2P_ERR((" %d index out of range\n", bssidx)); return -1; } @@ -600,6 +695,8 @@ wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len) { s32 ret = BCME_OK; + s32 bssidx = (wl_to_prmry_ndev(wl) == dev) ? + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) : wl_cfgp2p_find_idx(wl, dev); if (wl_get_p2p_status(wl, DISCOVERY_ON)) { CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n")); goto set_ie; @@ -624,13 +721,15 @@ wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, CFGP2P_ERR((" wsec error %d\n", ret)); } set_ie: - ret = wl_cfgp2p_set_management_ie(wl, dev, - wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE), - VNDR_IE_PRBREQ_FLAG, ie, ie_len); - - if (unlikely(ret < 0)) { - CFGP2P_ERR(("set probreq ie occurs error %d\n", ret)); - goto exit; + if (ie_len) { + ret = wl_cfgp2p_set_management_ie(wl, dev, + bssidx, + VNDR_IE_PRBREQ_FLAG, ie, ie_len); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("set probreq ie occurs error %d\n", ret)); + goto exit; + } } exit: return ret; @@ -690,11 +789,13 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, wlc_ssid_t ssid; /* Scan parameters */ #define P2PAPI_SCAN_NPROBES 1 -#define P2PAPI_SCAN_DWELL_TIME_MS 50 +#define P2PAPI_SCAN_DWELL_TIME_MS 80 #define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 #define P2PAPI_SCAN_HOME_TIME_MS 60 +#define P2PAPI_SCAN_NPROBS_TIME_MS 30 +#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 + struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); - wl_set_p2p_status(wl, SCANNING); /* Allocate scan params which need space for 3 channels and 0 ssids */ eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)) + @@ -724,10 +825,15 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, * we have to set ssid to P2P WILDCARD because * we just do broadcast scan unless setting SSID */ - strcpy(ssid.SSID, WL_P2P_WILDCARD_SSID); + strncpy(ssid.SSID, WL_P2P_WILDCARD_SSID, sizeof(ssid.SSID) - 1); + ssid.SSID[sizeof(ssid.SSID) - 1] = 0; ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN); wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); } + else { + CFGP2P_ERR((" invalid search state %d\n", search_state)); + return -1; + } /* Fill in the P2P scan structure at the start of the iovar param block */ @@ -745,14 +851,33 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, if (ssid.SSID_len) memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); - eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES); eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); - if (wl_get_drv_status_all(wl, CONNECTED)) - eparams->params.active_time = htod32(-1); - else if (num_chans == 3) + + /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by + * the supplicant + */ + if ((num_chans == SOCIAL_CHAN_CNT) || (num_chans == SOCIAL_CHAN_CNT + 1)) eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); + else if (num_chans == AF_PEER_SEARCH_CNT) + eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); + else if (wl_get_drv_status_all(wl, CONNECTED)) + eparams->params.active_time = -1; else eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); + eparams->params.nprobes = htod32((eparams->params.active_time / + P2PAPI_SCAN_NPROBS_TIME_MS)); + + /* Override scan params to find a peer for a connection */ + if (num_chans == 1) { + eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + eparams->params.nprobes = htod32(eparams->params.active_time / + WL_SCAN_JOIN_PROBE_INTERVAL_MS); + } + + if (eparams->params.nprobes <= 0) + eparams->params.nprobes = 1; + CFGP2P_DBG(("nprobes # %d, active_time %d\n", + eparams->params.nprobes, eparams->params.active_time)); eparams->params.passive_time = htod32(-1); eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); @@ -762,7 +887,11 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, } eparams->version = htod32(ESCAN_REQ_VERSION); eparams->action = htod16(action); +#if defined(DUAL_ESCAN_RESULT_BUFFER) + eparams->sync_id = wl->escan_info.cur_sync_id; +#else eparams->sync_id = htod16(0x1234); +#endif CFGP2P_INFO(("SCAN CHANNELS : ")); for (i = 0; i < num_chans; i++) { @@ -774,6 +903,8 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan", memblk, memsize, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); + if (ret == BCME_OK) + wl_set_p2p_status(wl, SCANNING); return ret; } @@ -791,13 +922,13 @@ wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, s32 ret = 0; u32 chan_cnt = 0; u16 *default_chan_list = NULL; - if (!p2p_is_on(wl)) + if (!p2p_is_on(wl) || ndev == NULL || bssidx == WL_INVALID) return -BCME_ERROR; CFGP2P_ERR((" Enter\n")); if (bssidx == P2PAPI_BSSCFG_PRIMARY) bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); if (channel) - chan_cnt = 1; + chan_cnt = AF_PEER_SEARCH_CNT; else chan_cnt = SOCIAL_CHAN_CNT; default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL); @@ -807,13 +938,17 @@ wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, goto exit; } if (channel) { - default_chan_list[0] = channel; + u32 i; + /* insert same channel to the chan_list */ + for (i = 0; i < chan_cnt; i++) { + default_chan_list[i] = channel; + } } else { default_chan_list[0] = SOCIAL_CHAN_1; default_chan_list[1] = SOCIAL_CHAN_2; default_chan_list[2] = SOCIAL_CHAN_3; } - ret = wl_cfgp2p_escan(wl, ndev, true, SOCIAL_CHAN_CNT, + ret = wl_cfgp2p_escan(wl, ndev, true, chan_cnt, default_chan_list, WL_P2P_DISC_ST_SEARCH, WL_SCAN_ACTION_START, bssidx); kfree(default_chan_list); @@ -834,6 +969,64 @@ wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, #define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ #define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) + +static s32 +wl_cfgp2p_parse_vndr_ies(u8 *parse, u32 len, + struct parsed_vndr_ies *vndr_ies) +{ + s32 err = BCME_OK; + vndr_ie_t *vndrie; + bcm_tlv_t *ie; + struct parsed_vndr_ie_info *parsed_info; + u32 count = 0; + s32 remained_len; + + remained_len = (s32)len; + memset(vndr_ies, 0, sizeof(*vndr_ies)); + + WL_INFO(("---> len %d\n", len)); + ie = (bcm_tlv_t *) parse; + if (!bcm_valid_tlv(ie, remained_len)) + ie = NULL; + while (ie) { + if (count >= MAX_VNDR_IE_NUMBER) + break; + if (ie->id == DOT11_MNG_VS_ID) { + vndrie = (vndr_ie_t *) ie; + /* len should be bigger than OUI length + one data length at least */ + if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) { + CFGP2P_ERR(("%s: invalid vndr ie. length is too small %d\n", + __FUNCTION__, vndrie->len)); + goto end; + } + /* if wpa or wme ie, do not add ie */ + if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) && + ((vndrie->data[0] == WPA_OUI_TYPE) || + (vndrie->data[0] == WME_OUI_TYPE))) { + CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n")); + goto end; + } + + parsed_info = &vndr_ies->ie_info[count++]; + + /* save vndr ie information */ + parsed_info->ie_ptr = (char *)vndrie; + parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN); + memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t)); + + vndr_ies->count = count; + + CFGP2P_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x \n", + parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1], + parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0])); + } +end: + ie = bcm_next_tlv(ie, &remained_len); + } + return err; +} + + /* Delete and Set a management vndr ie to firmware * Parameters: * @wl : wl_private data @@ -850,21 +1043,26 @@ s32 wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) { - /* Vendor-specific Information Element ID */ -#define VNDR_SPEC_ELEMENT_ID 0xdd s32 ret = BCME_OK; - u32 pos; - u8 *ie_buf; + u8 *curr_ie_buf = NULL; u8 *mgmt_ie_buf = NULL; u32 mgmt_ie_buf_len = 0; u32 *mgmt_ie_len = 0; - u8 ie_id, ie_len; - u8 delete = 0; + u32 del_add_ie_buf_len = 0; + u32 total_ie_buf_len = 0; + u32 parsed_ie_buf_len = 0; + struct parsed_vndr_ies old_vndr_ies; + struct parsed_vndr_ies new_vndr_ies; + s32 i; + u8 *ptr; + s32 remained_buf_len; + #define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie) #define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len) - if (p2p_is_on(wl) && bssidx != -1) { - if (bssidx == P2PAPI_BSSCFG_PRIMARY) - bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf)); + curr_ie_buf = g_mgmt_ie_buf; + CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag)); + if (wl->p2p != NULL) { switch (pktflag) { case VNDR_IE_PRBREQ_FLAG : mgmt_ie_buf = IE_TYPE(probe_req, bssidx); @@ -916,7 +1114,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss return -1; } bssidx = 0; - } else if (bssidx == -1 && wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) { + } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) { switch (pktflag) { case VNDR_IE_PRBREQ_FLAG : mgmt_ie_buf = wl->sta_info->probe_req_ie; @@ -944,59 +1142,109 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss CFGP2P_ERR(("extra IE size too big\n")); ret = -ENOMEM; } else { + /* parse and save new vndr_ie in curr_ie_buff before comparing it */ + if (vndr_ie && vndr_ie_len && curr_ie_buf) { + ptr = curr_ie_buf; + + wl_cfgp2p_parse_vndr_ies((u8*)vndr_ie, + vndr_ie_len, &new_vndr_ies); + + for (i = 0; i < new_vndr_ies.count; i++) { + struct parsed_vndr_ie_info *vndrie_info = + &new_vndr_ies.ie_info[i]; + + memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr, + vndrie_info->ie_len); + parsed_ie_buf_len += vndrie_info->ie_len; + } + } + if (mgmt_ie_buf != NULL) { - if (vndr_ie_len && (vndr_ie_len == *mgmt_ie_len) && - (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) { + if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && + (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { CFGP2P_INFO(("Previous mgmt IE is equals to current IE")); goto exit; } - pos = 0; - delete = 1; - ie_buf = (u8 *) mgmt_ie_buf; - while (pos < *mgmt_ie_len) { - ie_id = ie_buf[pos++]; - ie_len = ie_buf[pos++]; - if ((ie_id == DOT11_MNG_VS_ID) && - (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) || - wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0) || - wl_cfgp2p_is_wfd_ie(&ie_buf[pos-2], NULL, 0))) { - CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :" - "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos], - ie_buf[pos+1], ie_buf[pos+2])); - ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag, - ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, - ie_len-3, delete); - } - pos += ie_len; - } + /* parse old vndr_ie */ + wl_cfgp2p_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, + &old_vndr_ies); + + /* make a command to delete old ie */ + for (i = 0; i < old_vndr_ies.count; i++) { + struct parsed_vndr_ie_info *vndrie_info = + &old_vndr_ies.ie_info[i]; + + CFGP2P_INFO(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", + vndrie_info->vndrie.id, vndrie_info->vndrie.len, + vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2])); + + del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, + bssidx, pktflag, vndrie_info->vndrie.oui, + vndrie_info->vndrie.id, + vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, + vndrie_info->ie_len - VNDR_IE_FIXED_LEN, + "del"); + + curr_ie_buf += del_add_ie_buf_len; + total_ie_buf_len += del_add_ie_buf_len; + } } + *mgmt_ie_len = 0; /* Add if there is any extra IE */ - if (vndr_ie && vndr_ie_len) { - /* save the current IE in wl struct */ - memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len); - *mgmt_ie_len = vndr_ie_len; - pos = 0; - ie_buf = (u8 *) vndr_ie; - delete = 0; - while (pos < vndr_ie_len) { - ie_id = ie_buf[pos++]; - ie_len = ie_buf[pos++]; - if ((ie_id == DOT11_MNG_VS_ID) && - (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) || - wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0) || - wl_cfgp2p_is_wfd_ie(&ie_buf[pos-2], NULL, 0))) { - CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :" - "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos], - ie_buf[pos+1], ie_buf[pos+2])); - ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag, - ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, - ie_len-3, delete); + if (mgmt_ie_buf && parsed_ie_buf_len) { + ptr = mgmt_ie_buf; + + remained_buf_len = mgmt_ie_buf_len; + + /* make a command to add new ie */ + for (i = 0; i < new_vndr_ies.count; i++) { + struct parsed_vndr_ie_info *vndrie_info = + &new_vndr_ies.ie_info[i]; + + CFGP2P_INFO(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n", + vndrie_info->vndrie.id, vndrie_info->vndrie.len, + vndrie_info->ie_len - 2, + vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2])); + + del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, + bssidx, pktflag, vndrie_info->vndrie.oui, + vndrie_info->vndrie.id, + vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, + vndrie_info->ie_len - VNDR_IE_FIXED_LEN, + "add"); + + /* verify remained buf size before copy data */ + if (remained_buf_len >= vndrie_info->ie_len) { + remained_buf_len -= vndrie_info->ie_len; + } else { + CFGP2P_ERR(("no space in mgmt_ie_buf: pktflag = %d, " + "found vndr ies # = %d(cur %d), remained len %d, " + "cur mgmt_ie_len %d, new ie len = %d\n", + pktflag, new_vndr_ies.count, i, remained_buf_len, + *mgmt_ie_len, vndrie_info->ie_len)); + break; } - pos += ie_len; + + /* save the parsed IE in wl struct */ + memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, + vndrie_info->ie_len); + *mgmt_ie_len += vndrie_info->ie_len; + + curr_ie_buf += del_add_ie_buf_len; + total_ie_buf_len += del_add_ie_buf_len; } } + if (total_ie_buf_len) { + ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, + total_ie_buf_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &wl->ioctl_buf_sync); + if (ret) + CFGP2P_ERR(("vndr ie set error : %d\n", ret)); + } } #undef IE_TYPE #undef IE_TYPE_LEN @@ -1041,8 +1289,8 @@ wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u { /* If the contents match the OUI and the type */ if (ie[TLV_LEN_OFF] >= oui_len + 1 && - !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && - type == ie[TLV_BODY_OFF + oui_len]) { + !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && + type == ie[TLV_BODY_OFF + oui_len]) { return TRUE; } @@ -1109,15 +1357,13 @@ wl_cfgp2p_find_wfdie(u8 *parse, u32 len) } return NULL; } -static s32 -wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, - s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete) +static u32 +wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, + s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd) { - s32 err = BCME_OK; - s32 buf_len; + vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */ s32 iecount; - - vndr_ie_setbuf_t *ie_setbuf; + u32 data_offset; /* Validate the pktflag parameter */ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | @@ -1127,36 +1373,41 @@ wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 p return -1; } - buf_len = sizeof(vndr_ie_setbuf_t) + data_len - 1; - ie_setbuf = (vndr_ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); - - CFGP2P_INFO((" ie_id : %02x, data length : %d\n", ie_id, data_len)); - if (!ie_setbuf) { + /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ + strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1); + hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - CFGP2P_ERR(("Error allocating buffer for IE\n")); - return -ENOMEM; - } - if (delete) - strcpy(ie_setbuf->cmd, "del"); - else - strcpy(ie_setbuf->cmd, "add"); - /* Buffer contains only 1 IE */ + /* Set the IE count - the buffer contains only 1 IE */ iecount = htod32(1); - memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int)); + memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32)); + + /* Copy packet flags that indicate which packets will contain this IE */ pktflag = htod32(pktflag); - memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag, - &pktflag, sizeof(uint32)); - ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; - ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len - = (uchar)(data_len + VNDR_IE_MIN_LEN); - memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3); - memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len); - err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len, - wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); + memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, + sizeof(u32)); + + /* Add the IE ID to the buffer */ + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; + + /* Add the IE length to the buffer */ + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = + (uint8) VNDR_IE_MIN_LEN + datalen; + + /* Add the IE OUI to the buffer */ + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0]; + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1]; + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2]; + + /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */ + memcpy(iebuf, &hdr, sizeof(hdr) - 1); + + /* Copy the IE data to the IE buffer */ + data_offset = + (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] - + (u8*)&hdr; + memcpy(iebuf + data_offset, data, datalen); + return data_offset + datalen; - CFGP2P_INFO(("vndr_ie iovar returns %d\n", err)); - kfree(ie_setbuf); - return err; } /* @@ -1198,17 +1449,59 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) { s32 ret = BCME_OK; - + struct net_device *netdev; + if (!wl || !wl->p2p) + return BCME_ERROR; + if (wl->p2p_net == ndev) { + netdev = wl_to_prmry_ndev(wl); + } else { + netdev = ndev; + } CFGP2P_DBG((" Enter\n")); if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) { wl_set_p2p_status(wl, LISTEN_EXPIRED); if (timer_pending(&wl->p2p->listen_timer)) { - spin_lock_bh(&wl->p2p->timer_lock); del_timer_sync(&wl->p2p->listen_timer); - spin_unlock_bh(&wl->p2p->timer_lock); } - cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, &wl->remain_on_chan, - wl->remain_on_chan_type, GFP_KERNEL); + + if (wl->afx_hdl->is_listen == TRUE && + wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { + WL_DBG(("Listen DONE for action frame\n")); + complete(&wl->act_frm_scan); + } +#ifdef WL_CFG80211_SYNC_GON + else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, netdev); + WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n", + jiffies_to_msecs(jiffies - wl->af_tx_sent_jiffies))); + + if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, netdev); + + complete(&wl->wait_next_af); + } +#endif /* WL_CFG80211_SYNC_GON */ + +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL)) { +#else + if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL) || + wl_get_drv_status_all(wl, FAKE_REMAINING_ON_CHANNEL)) { +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + WL_DBG(("Listen DONE for ramain on channel expired\n")); + wl_clr_drv_status(wl, REMAINING_ON_CHANNEL, netdev); +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_clr_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, netdev); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + if (ndev && (ndev->ieee80211_ptr != NULL)) { + cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, + &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); + } + } + if (wl_add_remove_eventmsg(wl_to_prmry_ndev(wl), + WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) { + CFGP2P_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); + } } else wl_clr_p2p_status(wl, LISTEN_EXPIRED); @@ -1221,17 +1514,43 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, * We can't report cfg80211_remain_on_channel_expired from Timer ISR context, * so lets do it from thread context. */ -static void +void wl_cfgp2p_listen_expired(unsigned long data) { wl_event_msg_t msg; struct wl_priv *wl = (struct wl_priv *) data; - CFGP2P_DBG((" Enter\n")); + bzero(&msg, sizeof(wl_event_msg_t)); msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); - wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL); + wl_cfg80211_event(wl->p2p_net ? wl->p2p_net : + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL); +} +/* + * Routine for cancelling the P2P LISTEN + */ +static s32 +wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, + bool notify) +{ + WL_DBG(("Enter \n")); + /* Irrespective of whether timer is running or not, reset + * the LISTEN state. + */ +#ifdef NOT_YET + wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); +#endif /* NOT_YET */ + if (timer_pending(&wl->p2p->listen_timer)) { + del_timer_sync(&wl->p2p->listen_timer); + if (notify) + if (ndev && ndev->ieee80211_ptr) { + cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, + &wl->remain_on_chan, wl->remain_on_chan_type, + GFP_KERNEL); + } + } + return 0; } - /* * Do a P2P Listen on the given channel for the given duration. * A listen consists of sitting idle and responding to P2P probe requests @@ -1246,18 +1565,13 @@ wl_cfgp2p_listen_expired(unsigned long data) s32 wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) { -#define INIT_TIMER(timer, func, duration, extra_delay) \ - do { \ - init_timer(timer); \ - timer->function = func; \ - timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ - timer->data = (unsigned long) wl; \ - add_timer(timer); \ - } while (0); - +#define EXTRA_DELAY_TIME 100 s32 ret = BCME_OK; struct timer_list *_timer; - CFGP2P_DBG((" Enter Channel : %d, Duration : %d\n", channel, duration_ms)); + s32 extra_delay; + struct net_device *netdev = wl_to_prmry_ndev(wl); + + CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms)); if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) { CFGP2P_ERR((" Discovery is not set, so we have noting to do\n")); @@ -1269,19 +1583,36 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) CFGP2P_DBG(("previous LISTEN is not completed yet\n")); goto exit; - } else + } +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + else wl_clr_p2p_status(wl, LISTEN_EXPIRED); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) { + CFGP2P_ERR((" failed to set WLC_E_P2P_PROPREQ_MSG\n")); + } - wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, + ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); _timer = &wl->p2p->listen_timer; /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , - * otherwise we will wait up to duration_ms + 200ms + * otherwise we will wait up to duration_ms + 100ms + duration / 10 */ - INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, 200); + if (ret == BCME_OK) { + extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10); + } else { + /* if failed to set listen, it doesn't need to wait whole duration. */ + duration_ms = 100 + duration_ms / 20; + extra_delay = 0; + } + + INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_clr_p2p_status(wl, LISTEN_EXPIRED); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -#undef INIT_TIMER +#undef EXTRA_DELAY_TIME exit: return ret; } @@ -1331,15 +1662,19 @@ wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); if (status == WLC_E_STATUS_SUCCESS) { wl_set_p2p_status(wl, ACTION_TX_COMPLETED); + CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n")); } else { wl_set_p2p_status(wl, ACTION_TX_NOACK); - CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); + CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); + wl_stop_wait_next_action_frame(wl, ndev); } } else { CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," "status : %d\n", status)); - wake_up_interruptible(&wl->netif_change_event); + + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) + complete(&wl->send_af_done); } return ret; } @@ -1369,6 +1704,11 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, if (bssidx == P2PAPI_BSSCFG_PRIMARY) bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + wl->af_sent_channel = af_params->channel; +#ifdef WL_CFG80211_SYNC_GON + wl->af_tx_sent_jiffies = jiffies; +#endif /* WL_CFG80211_SYNC_GON */ + ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); @@ -1377,9 +1717,8 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, CFGP2P_ERR((" sending action frame is failed\n")); goto exit; } - timeout = wait_event_interruptible_timeout(wl->netif_change_event, - (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)), - msecs_to_jiffies(MAX_WAIT_TIME)); + + timeout = wait_for_completion_timeout(&wl->send_af_done, msecs_to_jiffies(MAX_WAIT_TIME)); if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) { CFGP2P_INFO(("tx action frame operation is completed\n")); @@ -1388,6 +1727,10 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, ret = BCME_ERROR; CFGP2P_INFO(("tx action frame operation is failed\n")); } + /* clear status bit for action tx */ + wl_clr_p2p_status(wl, ACTION_TX_COMPLETED); + wl_clr_p2p_status(wl, ACTION_TX_NOACK); + exit: CFGP2P_INFO((" via act frame iovar : status = %d\n", ret)); #undef MAX_WAIT_TIME @@ -1550,8 +1893,10 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev) s32 wl_cfgp2p_down(struct wl_priv *wl) { - if (timer_pending(&wl->p2p->listen_timer)) - del_timer_sync(&wl->p2p->listen_timer); + + wl_cfgp2p_cancel_listen(wl, + wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE); + wl_cfgp2p_deinit_priv(wl); return 0; } @@ -1570,7 +1915,7 @@ wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, in wl->p2p->noa.desc[0].start = 0; - sscanf(buf, "%d %d %d", &count, &start, &duration); + sscanf(buf, "%10d %10d %10d", &count, &start, &duration); CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n", count, start, duration)); if (count != -1) @@ -1659,7 +2004,7 @@ wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, in } /* We have to convert the buffer data into ASCII strings */ for (i = 0; i < len; i++) { - sprintf(buf, "%02x", _buf[i]); + snprintf(buf, 3, "%02x", _buf[i]); buf += 2; } buf[i*2] = '\0'; @@ -1680,7 +2025,7 @@ wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int CFGP2P_DBG((" Enter\n")); if (wl->p2p && wl->p2p->vif_created) { - sscanf(buf, "%d %d %d", &legacy_ps, &ps, &ctw); + sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw); CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw)); if (ctw != -1) { wl->p2p->ops.ctw = ctw; @@ -1697,10 +2042,16 @@ wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int } if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) { +#ifdef SUPPORT_PM2_ONLY + if (legacy_ps == PM_MAX) + legacy_ps = PM_FAST; +#endif ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true); if (unlikely(ret)) { CFGP2P_ERR(("error (%d)\n", ret)); + } else { + wl_cfg80211_update_power_mode(ndev); } } else @@ -1803,6 +2154,19 @@ wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) return ptr; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +static void +wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) +{ + snprintf(info->driver, sizeof(info->driver), "p2p"); + snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0)); +} + +struct ethtool_ops cfgp2p_ethtool_ops = { + .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + s32 wl_cfgp2p_register_ndev(struct wl_priv *wl) { @@ -1812,16 +2176,16 @@ wl_cfgp2p_register_ndev(struct wl_priv *wl) uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; /* Allocate etherdev, including space for private structure */ - if (!(net = alloc_etherdev(sizeof(wl)))) { + if (!(net = alloc_etherdev(sizeof(struct wl_priv *)))) { CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); goto fail; } - strcpy(net->name, "p2p%d"); + strncpy(net->name, "p2p%d", sizeof(net->name) - 1); net->name[IFNAMSIZ - 1] = '\0'; /* Copy the reference to wl_priv */ - memcpy((void *)netdev_priv(net), &wl, sizeof(wl)); + memcpy((void *)netdev_priv(net), &wl, sizeof(struct wl_priv *)); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ASSERT(!net->open); @@ -1849,6 +2213,10 @@ wl_cfgp2p_register_ndev(struct wl_priv *wl) net->ieee80211_ptr = wdev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + net->ethtool_ops = &cfgp2p_ethtool_ops; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy)); /* Associate p2p0 network interface with new wdev */ @@ -1934,32 +2302,49 @@ static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd static int wl_cfgp2p_if_open(struct net_device *net) { + extern struct wl_priv *wlcfg_drv_priv; struct wireless_dev *wdev = net->ieee80211_ptr; - - if (!wdev) + struct wl_priv *wl = NULL; + wl = wlcfg_drv_priv; + if (!wdev || !wl || !wl->p2p) return -EINVAL; - + WL_TRACE(("Enter\n")); /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, * do it here. This will make sure that in concurrent mode, supplicant * is not dependent on a particular order of interface initialization. * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N * -iwlan0. */ - wl_cfg80211_do_driver_init(net); - wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)); + wl_cfg80211_do_driver_init(net); return 0; } static int wl_cfgp2p_if_stop(struct net_device *net) { + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = NULL; + unsigned long flags; struct wireless_dev *wdev = net->ieee80211_ptr; - + int clear_flag = 0; if (!wdev) return -EINVAL; + WL_TRACE(("Enter\n")); + wl = wlcfg_drv_priv; + if (!wl) + return -EINVAL; + spin_lock_irqsave(&wl->cfgdrv_lock, flags); + if (wl->scan_request && wl->scan_request->dev == net) { + cfg80211_scan_done(wl->scan_request, true); + wl->scan_request = NULL; + clear_flag = 1; + } + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + if (clear_flag) + wl_clr_drv_status(wl, SCANNING, net); wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| BIT(NL80211_IFTYPE_P2P_GO))); diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index 427cb4a11bd..31b8dab7266 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfgp2p.h 316197 2012-02-21 13:16:39Z $ + * $Id: wl_cfgp2p.h 358702 2012-09-25 06:48:56Z $ */ #ifndef _wl_cfgp2p_h_ #define _wl_cfgp2p_h_ @@ -43,14 +43,18 @@ typedef enum { P2PAPI_BSSCFG_MAX } p2p_bsscfg_type_t; -#define IE_MAX_LEN 300 +/* vendor ies max buffer length for probe response or beacon */ +#define VNDR_IES_MAX_BUF_LEN 1400 +/* normal vendor ies buffer length */ +#define VNDR_IES_BUF_LEN 512 + /* Structure to hold all saved P2P and WPS IEs for a BSSCFG */ struct p2p_saved_ie { - u8 p2p_probe_req_ie[IE_MAX_LEN]; - u8 p2p_probe_res_ie[IE_MAX_LEN]; - u8 p2p_assoc_req_ie[IE_MAX_LEN]; - u8 p2p_assoc_res_ie[IE_MAX_LEN]; - u8 p2p_beacon_ie[IE_MAX_LEN]; + u8 p2p_probe_req_ie[VNDR_IES_BUF_LEN]; + u8 p2p_probe_res_ie[VNDR_IES_MAX_BUF_LEN]; + u8 p2p_assoc_req_ie[VNDR_IES_BUF_LEN]; + u8 p2p_assoc_res_ie[VNDR_IES_BUF_LEN]; + u8 p2p_beacon_ie[VNDR_IES_MAX_BUF_LEN]; u32 p2p_probe_req_ie_len; u32 p2p_probe_res_ie_len; u32 p2p_assoc_req_ie_len; @@ -78,7 +82,19 @@ struct p2p_info { wl_p2p_sched_t noa; wl_p2p_ops_t ops; wlc_ssid_t ssid; - spinlock_t timer_lock; +}; + +#define MAX_VNDR_IE_NUMBER 5 + +struct parsed_vndr_ie_info { + char *ie_ptr; + u32 ie_len; /* total length including id & length field */ + vndr_ie_t vndrie; +}; + +struct parsed_vndr_ies { + u32 count; + struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; }; /* dongle status */ @@ -93,7 +109,8 @@ enum wl_cfgp2p_status { WLP2P_STATUS_LISTEN_EXPIRED, WLP2P_STATUS_ACTION_TX_COMPLETED, WLP2P_STATUS_ACTION_TX_NOACK, - WLP2P_STATUS_SCANNING + WLP2P_STATUS_SCANNING, + WLP2P_STATUS_GO_NEG_PHASE }; @@ -116,31 +133,46 @@ enum wl_cfgp2p_status { /* dword align allocation */ #define WLC_IOCTL_MAXLEN 8192 -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" #define CFGP2P_ERR(args) \ do { \ if (wl_dbg_level & WL_DBG_ERR) { \ - printk(KERN_ERR "CFGP2P-ERROR) %s : ", __func__); \ + printk(KERN_INFO "CFGP2P-INFO2) %s : ", __func__); \ printk args; \ } \ } while (0) #define CFGP2P_INFO(args) \ do { \ if (wl_dbg_level & WL_DBG_INFO) { \ - printk(KERN_ERR "CFGP2P-INFO) %s : ", __func__); \ + printk(KERN_INFO "CFGP2P-INFO) %s : ", __func__); \ printk args; \ } \ } while (0) #define CFGP2P_DBG(args) \ do { \ if (wl_dbg_level & WL_DBG_DBG) { \ - printk(KERN_ERR "CFGP2P-DEBUG) %s :", __func__); \ + printk(KERN_DEBUG "CFGP2P-DEBUG) %s :", __func__); \ printk args; \ } \ } while (0) +#define CFGP2P_ACTION(args) \ + do { \ + if (wl_dbg_level & WL_DBG_P2P_ACTION) { \ + printk(KERN_DEBUG "CFGP2P-ACTION) %s :", __func__); \ + printk args; \ + } \ + } while (0) +#define INIT_TIMER(timer, func, duration, extra_delay) \ + do { \ + init_timer(timer); \ + timer->function = func; \ + timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ + timer->data = (unsigned long) wl; \ + add_timer(timer); \ + } while (0); +extern void +wl_cfgp2p_listen_expired(unsigned long data); extern bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); extern bool @@ -162,6 +194,8 @@ extern s32 wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, chanspec_t chspec); extern s32 +wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac); +extern s32 wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac); extern s32 wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, chanspec_t chspec); @@ -265,20 +299,36 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl); #define SOCIAL_CHAN_1 1 #define SOCIAL_CHAN_2 6 #define SOCIAL_CHAN_3 11 +#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ + (channel == SOCIAL_CHAN_2) || \ + (channel == SOCIAL_CHAN_3)) #define SOCIAL_CHAN_CNT 3 +#define AF_PEER_SEARCH_CNT 2 #define WL_P2P_WILDCARD_SSID "DIRECT-" #define WL_P2P_WILDCARD_SSID_LEN 7 #define WL_P2P_INTERFACE_PREFIX "p2p" #define WL_P2P_TEMP_CHAN 11 +/* If the provision discovery is for JOIN operations, + * then we need not do an internal scan to find GO. + */ +#define IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len) \ + (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL) #define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) -#define IS_P2P_PUB_ACT_REQ(frame, len) (wl_cfgp2p_is_pub_action(frame, len) && \ - ((frame->subtype == P2P_PAF_GON_REQ) || \ - (frame->subtype == P2P_PAF_INVITE_REQ) || \ - (frame->subtype == P2P_PAF_PROVDIS_REQ))) +#define IS_P2P_PUB_ACT_REQ(frame, p2p_ie, len) \ + (wl_cfgp2p_is_pub_action(frame, len) && \ + ((frame->subtype == P2P_PAF_GON_REQ) || \ + (frame->subtype == P2P_PAF_INVITE_REQ) || \ + ((frame->subtype == P2P_PAF_PROVDIS_REQ) && \ + IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len)))) +#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \ + ((subtype == P2P_PAF_GON_CONF) || \ + (subtype == P2P_PAF_INVITE_RSP) || \ + (subtype == P2P_PAF_PROVDIS_RSP))) #define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) -#define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0) +#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \ + (len == WL_P2P_WILDCARD_SSID_LEN)) #endif /* _wl_cfgp2p_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index be080250ce5..6855314c4cc 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_iw.c 312290 2012-02-02 02:52:18Z $ + * $Id: wl_iw.c 352251 2012-08-22 06:08:38Z $ */ #if defined(USE_IW) @@ -260,6 +260,7 @@ dev_iw_iovar_setbuf( iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); ASSERT(iolen); + BCM_REFERENCE(iolen); return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen)); } @@ -1227,7 +1228,7 @@ wl_iw_iscan_set_scan( wl_iw_set_event_mask(dev); wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START); - iscan->timer.expires = jiffies + iscan->timer_ms*HZ/1000; + iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); add_timer(&iscan->timer); iscan->timer_on = 1; @@ -1393,6 +1394,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, wpa_snprintf_hex(buf + 10, 2+1, &(ie->len), 1); wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len); event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf); + kfree(buf); #endif break; } @@ -1625,7 +1627,7 @@ wl_iw_iscan_get_scan( event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); - if (bi->rateset.count) { + if (bi->rateset.count <= sizeof(bi->rateset.rates)) { if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) return -E2BIG; @@ -3610,11 +3612,11 @@ wl_iw_iscan_get(iscan_info_t *iscan) static void wl_iw_send_scan_complete(iscan_info_t *iscan) { union iwreq_data wrqu; - char extra[IW_CUSTOM_MAX + 1]; memset(&wrqu, 0, sizeof(wrqu)); - memset(extra, 0, sizeof(extra)); - wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, extra); + + + wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); } static int @@ -3652,7 +3654,7 @@ _iscan_sysioc_thread(void *data) rtnl_unlock(); #endif - iscan->timer.expires = jiffies + iscan->timer_ms*HZ/1000; + iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); add_timer(&iscan->timer); iscan->timer_on = 1; break; @@ -3664,7 +3666,7 @@ _iscan_sysioc_thread(void *data) case WL_SCAN_RESULTS_PENDING: WL_TRACE(("iscanresults pending\n")); - iscan->timer.expires = jiffies + iscan->timer_ms*HZ/1000; + iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); add_timer(&iscan->timer); iscan->timer_on = 1; break; diff --git a/drivers/net/wireless/bcmdhd/wl_roam.c b/drivers/net/wireless/bcmdhd/wl_roam.c new file mode 100644 index 00000000000..42464a2bdb2 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/wl_roam.c @@ -0,0 +1,288 @@ +/* + * Linux roam cache + * + * Copyright (C) 1999-2012, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_roam.c 334946 2012-05-24 20:38:00Z $ + */ + +#include +#include +#include +#include + +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) +#include + +#define WL_ERROR(x) printk x +#endif + +#define WL_DBG(x) + +#define MAX_ROAM_CACHE 100 + +typedef struct { + chanspec_t chanspec; + int ssid_len; + char ssid[36]; +} roam_channel_cache; + +static int n_roam_cache = 0; +static int roam_band = WLC_BAND_AUTO; +static roam_channel_cache roam_cache[MAX_ROAM_CACHE]; +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) +static int roamscan_mode = 0; +#endif + +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) +int get_roamscan_mode(struct net_device *dev, int *mode) +{ + *mode = roamscan_mode; + + return 0; +} + +int set_roamscan_mode(struct net_device *dev, int mode) +{ + int error = 0; + roamscan_mode = mode; + n_roam_cache = 0; + + error = wldev_iovar_setint(dev, "roamscan_mode", mode); + if (error) { + WL_ERROR(("Failed to set roamscan mode to %d, error = %d\n", mode, error)); + } + + return error; +} + +int get_roamscan_channel_list(struct net_device *dev, unsigned char channels[]) +{ + int n = 0; + + if (roamscan_mode) { + for (n = 0; n < n_roam_cache; n++) { + channels[n] = roam_cache[n].chanspec & WL_CHANSPEC_CHAN_MASK; + + WL_DBG(("%s: channel[%d] - [%02d] \n", __FUNCTION__, n, channels[n])); + } + } + + return n; +} + +int set_roamscan_channel_list(struct net_device *dev, + unsigned char n, unsigned char channels[], int ioctl_ver) +{ + int i; + int error; + struct { + int n; + chanspec_t channels[20]; + } channel_list; + char iobuf[200]; + uint band2G, band5G, bw; + roamscan_mode = 1; + + if (n > 20) + n = 20; + +#ifdef D11AC_IOTYPES + if (ioctl_ver == 1) { + /* legacy chanspec */ + band2G = WL_LCHANSPEC_BAND_2G; + band5G = WL_LCHANSPEC_BAND_5G; + bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE; + } else { + band2G = WL_CHANSPEC_BAND_2G; + band5G = WL_CHANSPEC_BAND_5G; + bw = WL_CHANSPEC_BW_20; + } +#else + band2G = WL_CHANSPEC_BAND_2G; + band5G = WL_CHANSPEC_BAND_5G; + bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; +#endif /* D11AC_IOTYPES */ + + for (i = 0; i < n; i++) { + chanspec_t chanspec; + + if (channels[i] <= 14) { + chanspec = band2G | bw | channels[i]; + } else { + chanspec = band5G | bw | channels[i]; + } + roam_cache[i].chanspec = chanspec; + channel_list.channels[i] = chanspec; + + WL_DBG(("%s: channel[%d] - [%02d] \n", __FUNCTION__, i, channels[i])); + } + + n_roam_cache = n; + channel_list.n = n; + + error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list, + sizeof(channel_list), iobuf, sizeof(iobuf), NULL); + if (error) { + WL_ERROR(("Failed to set roamscan channels, error = %d\n", error)); + } + + return error; +} +#endif /* WES_SUPPORT */ + +void set_roam_band(int band) +{ + roam_band = band; +} + +void reset_roam_cache(void) +{ +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) + if (roamscan_mode) + return; +#endif + + n_roam_cache = 0; +} + +void add_roam_cache(wl_bss_info_t *bi) +{ + int i; + uint8 channel; + +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) + if (roamscan_mode) + return; +#endif + + if (n_roam_cache == MAX_ROAM_CACHE) + return; + + for (i = 0; i < n_roam_cache; i++) { + if ((roam_cache[i].ssid_len == bi->SSID_len) && + (roam_cache[i].chanspec == bi->chanspec) && + (memcmp(roam_cache[i].ssid, bi->SSID, bi->SSID_len) == 0)) { + /* identical one found, just return */ + return; + } + } + + roam_cache[n_roam_cache].ssid_len = bi->SSID_len; + channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch; + roam_cache[n_roam_cache].chanspec = + WL_CHANSPEC_BW_20 | + (channel <= 14 ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G) | + channel; + memcpy(roam_cache[n_roam_cache].ssid, bi->SSID, bi->SSID_len); + + n_roam_cache++; +} + +int get_roam_channel_list(int target_chan, + chanspec_t *channels, const wlc_ssid_t *ssid, int ioctl_ver) +{ + int i, n = 1; + uint band, band2G, band5G, bw; + +#ifdef D11AC_IOTYPES + if (ioctl_ver == 1) { + /* legacy chanspec */ + band2G = WL_LCHANSPEC_BAND_2G; + band5G = WL_LCHANSPEC_BAND_5G; + bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE; + } else { + band2G = WL_CHANSPEC_BAND_2G; + band5G = WL_CHANSPEC_BAND_5G; + bw = WL_CHANSPEC_BW_20; + } +#else + band2G = WL_CHANSPEC_BAND_2G; + band5G = WL_CHANSPEC_BAND_5G; + bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; +#endif /* D11AC_IOTYPES */ + + if (target_chan <= 14) + band = band2G; + else + band = band5G; + *channels = (target_chan & WL_CHANSPEC_CHAN_MASK) | band | bw; + WL_DBG((" %s: %02d 0x%04X\n", __FUNCTION__, target_chan, *channels)); + ++channels; + +#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) + if (roamscan_mode) { + for (i = 0; i < n_roam_cache; i++) { + if ((roam_cache[i].chanspec & WL_CHANSPEC_CHAN_MASK) != target_chan) { + *channels = roam_cache[i].chanspec & WL_CHANSPEC_CHAN_MASK; + WL_DBG((" %s: %02d\n", __FUNCTION__, *channels)); + if (*channels <= 14) + *channels |= band2G | bw; + else + *channels |= band5G | bw; + + channels++; + n++; + } + } + + return n; + } +#endif /* WES_SUPPORT */ + + for (i = 0; i < n_roam_cache; i++) { + chanspec_t ch = roam_cache[i].chanspec; + if ((roam_cache[i].ssid_len == ssid->SSID_len) && + ((ch & WL_CHANSPEC_CHAN_MASK) != target_chan) && + ((roam_band == WLC_BAND_AUTO) || + ((roam_band == WLC_BAND_2G) && CHSPEC_IS2G(ch)) || + ((roam_band == WLC_BAND_5G) && CHSPEC_IS5G(ch))) && + (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) { + /* match found, add it */ + *channels = ch & WL_CHANSPEC_CHAN_MASK; + if (*channels <= 14) + *channels |= band2G | bw; + else + *channels |= band5G | bw; + + WL_DBG((" %s: %02d 0x%04X\n", __FUNCTION__, + ch & WL_CHANSPEC_CHAN_MASK, *channels)); + + channels++; n++; + } + } + + return n; +} + + +void print_roam_cache(void) +{ + int i; + + WL_DBG((" %d cache\n", n_roam_cache)); + + for (i = 0; i < n_roam_cache; i++) { + roam_cache[i].ssid[roam_cache[i].ssid_len] = 0; + WL_DBG(("0x%02X %02d %s\n", roam_cache[i].chanspec, + roam_cache[i].ssid_len, roam_cache[i].ssid)); + } +} diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c index f83df791e13..8e0ed4dcf60 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/bcmdhd/wldev_common.c @@ -105,7 +105,10 @@ s32 wldev_iovar_setbuf( mutex_lock(buf_sync); } iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); - ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + if (iovar_len > 0) + ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + else + ret = BCME_BUFTOOSHORT; if (buf_sync) mutex_unlock(buf_sync); return ret; @@ -220,7 +223,12 @@ s32 wldev_iovar_setbuf_bsscfg( mutex_lock(buf_sync); } iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); - ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + if (iovar_len > 0) + ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + else { + ret = BCME_BUFTOOSHORT; + } + if (buf_sync) { mutex_unlock(buf_sync); } @@ -319,7 +327,9 @@ int wldev_set_band( int error = -1; if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { - error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), 1); + error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true); + if (!error) + dhd_bus_band_set(dev, band); } return error; } @@ -343,26 +353,26 @@ int wldev_set_country( if ((error < 0) || (strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) { bzero(&scbval, sizeof(scb_val_t)); - error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), 1); + error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); if (error < 0) { WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", __FUNCTION__, error)); return error; } - } - cspec.rev = -1; - memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); - memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); - get_customized_country_code((char *)&cspec.country_abbrev, &cspec); - error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), - smbuf, sizeof(smbuf), NULL); - if (error < 0) { - WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", + cspec.rev = -1; + memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); + memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); + get_customized_country_code((char *)&cspec.country_abbrev, &cspec); + error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), + smbuf, sizeof(smbuf), NULL); + if (error < 0) { + WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", + __FUNCTION__, country_code, cspec.ccode, cspec.rev)); + return error; + } + dhd_bus_country_set(dev, &cspec); + WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - return error; } - dhd_bus_country_set(dev, &cspec); - WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); return 0; } diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h index 16a071f5e5a..099e83fa89b 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -85,6 +85,7 @@ s32 wldev_iovar_setint_bsscfg( extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec); extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec); +extern void dhd_bus_band_set(struct net_device *dev, uint band); extern int wldev_set_country(struct net_device *dev, char *country_code); extern int net_os_wake_lock(struct net_device *dev); extern int net_os_wake_unlock(struct net_device *dev); @@ -92,10 +93,12 @@ extern int net_os_wake_lock_timeout(struct net_device *dev); extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); extern int net_os_set_dtim_skip(struct net_device *dev, int val); extern int net_os_set_suspend_disable(struct net_device *dev, int val); -extern int net_os_set_suspend(struct net_device *dev, int val); +extern int net_os_set_suspend(struct net_device *dev, int val, int force); extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left); - +#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) +int net_os_wake_lock_timeout_for_pno(struct net_device *dev, int sec); +#endif /* Get the link speed from dongle, speed is in kpbs */ int wldev_get_link_speed(struct net_device *dev, int *plink_speed); diff --git a/drivers/net/wireless/btlock/Kconfig b/drivers/net/wireless/btlock/Kconfig new file mode 100644 index 00000000000..2e5853b2fbe --- /dev/null +++ b/drivers/net/wireless/btlock/Kconfig @@ -0,0 +1,5 @@ +config BCM4334 + tristate "Bluetooth Lock driver" + default m + help + say M to compile it as module. \ No newline at end of file diff --git a/drivers/net/wireless/btlock/Makefile b/drivers/net/wireless/btlock/Makefile new file mode 100644 index 00000000000..d416af1c54a --- /dev/null +++ b/drivers/net/wireless/btlock/Makefile @@ -0,0 +1 @@ +obj-m += btlock.o \ No newline at end of file diff --git a/drivers/net/wireless/btlock/btlock.c b/drivers/net/wireless/btlock/btlock.c new file mode 100644 index 00000000000..55290668df5 --- /dev/null +++ b/drivers/net/wireless/btlock/btlock.c @@ -0,0 +1,140 @@ +/************************************************************************************ + * + * Copyright (C) 2009-2011 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNOppU General Public License, version 2, as published by + * the Free Software Foundation (the "GPL"). + * + * 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. + * + * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php, + * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + ************************************************************************************/ +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Wenbin Yu "); +MODULE_DESCRIPTION("User level driver support for BT lock"); +MODULE_SUPPORTED_DEVICE("btlock"); +MODULE_LICENSE("GPL"); + +#define BTLOCK_NAME "btlock" +#define BTLOCK_MINOR 224 + +#define PR(msg, ...) printk(KERN_DEBUG "#### %s " msg, current->comm, ##__VA_ARGS__) + +struct btlock { + int lock; + int cookie; +}; + +static struct semaphore lock; +static int owner_cookie; + +static int btlock_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int btlock_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t btlock_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + struct btlock lock_para; + ssize_t ret = 0; + char cookie_msg[5] = {0}; + char owner_msg[5] = {0}; + + if (count < sizeof(struct btlock)) + return -EINVAL; + + if (copy_from_user(&lock_para, buffer, sizeof(struct btlock))) + return -EFAULT; + + memcpy(cookie_msg, &lock_para.cookie, sizeof(lock_para.cookie)); + if (lock_para.lock == 0) { + if (owner_cookie == lock_para.cookie) { + owner_cookie = 0; + up(&lock); + PR("lock released, cookie: %s\n", cookie_msg); + } else + memcpy(owner_msg, &owner_cookie, sizeof(owner_cookie)); + PR("release, cookie_mismatch:%s, owner:%s\n", cookie_msg, + owner_cookie == 0 ? "NULL" : owner_msg); + } else if (lock_para.lock == 1) { + if (down_killable(&lock)) { + PR("killed\n"); + return -ERESTARTSYS; + } + owner_cookie = lock_para.cookie; + PR("lock acquired, %s\n", cookie_msg); + } else if (lock_para.lock == 2) { + if (down_trylock(&lock) != 0) { + PR("try failed\n"); + return -ERESTARTSYS; + } else { + PR("try success\n"); + owner_cookie = lock_para.cookie; + } + } + + return ret; +} + +static long btlock_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static const struct file_operations btlock_fops = { + .owner = THIS_MODULE, + .open = btlock_open, + .release = btlock_release, + .write = btlock_write, + .unlocked_ioctl = btlock_unlocked_ioctl, +}; + +static struct miscdevice btlock_misc = { + .name = BTLOCK_NAME, + .minor = BTLOCK_MINOR, + .fops = &btlock_fops, +}; + + +static int __init btlock_init(void) +{ + int ret; + + PR("init\n"); + + ret = misc_register(&btlock_misc); + if (ret != 0) { + PR("Error: failed to register Misc driver, ret = %d\n", ret); + return ret; + } + + sema_init(&lock, 1); + return ret; +} + +static void __exit btlock_exit(void) +{ + PR("btlock_exit:\n"); + + misc_deregister(&btlock_misc); +} + +module_init(btlock_init); +module_exit(btlock_exit); diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 5bcdf7d4d45..8003e67c01f 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -415,6 +415,55 @@ config PM8921_BMS help Say Y here to enable support for pm8921 chip bms subdevice +config PM8921_SEC_CHARGER + bool "samsung charger driver" + default n + help + Say Y here to enable support for samsung charging driver. + PM8921-charger driver is default. + But Samsung need modification to adjust verification spec. + So Samsung charging dirver is seperated. + +config BATTERY_CTIA + bool "change cut off temp" + default n + help + Say Y here to change cut off charging current only usa model + beacause of CTIA. + +config BATTERY_SEC + bool "Enable SEC battery driver" + default n + help + Say Y here to enable support for batteries with SEC features. + +config SAMSUNG_LPM_MODE + bool "Off charging mode support in sec battery driver" + default n + help + Say Y to include support for sec off charging support + +config WIRELESS_CHARGING + bool "Enable wireless charging" + default n + help + Say Y here to enable support for wireless charging + +config BATTERY_SAMSUNG_STRETTO + tristate "samsung battery driver for STRETTO" + help + Say Y here to enable support for batteries + with MAX77693 (I2C) chips. + MAX77693 have Charger,Fuelgauge, MUIC etc. + This is samsung battery driver for STRETTO +config BATTERY_BCL + tristate "Battery Current Limit driver" + help + Say Y here to enable support for battery current limit + device. The BCL driver will poll BMS if + thermal daemon enables BCL. + It will notify thermal daemon if IBat crosses Imax threshold. + config CHARGER_SMB347 tristate "Summit Microelectronics SMB347 Battery Charger" depends on I2C diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 007d75bce4a..9007e5d46f5 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -55,6 +55,13 @@ obj-$(CONFIG_BATTERY_BQ27541) += bq27541_fuelgauger.o obj-$(CONFIG_SMB137B_CHARGER) += smb137b.o obj-$(CONFIG_PM8XXX_CCADC) += pm8xxx-ccadc.o obj-$(CONFIG_PM8921_BMS) += pm8921-bms.o -obj-$(CONFIG_PM8921_CHARGER) += pm8921-charger.o +obj-$(CONFIG_PM8921_SEC_CHARGER) += pm8921-sec-charger.o +obj-$(CONFIG_BATTERY_SEC) += sec_battery.o +obj-$(CONFIG_QPNP_BMS) += qpnp-bms.o +#obj-$(CONFIG_PM8921_CHARGER) += pm8921-charger.o +obj-$(CONFIG_QPNP_CHARGER) += qpnp-charger.o obj-$(CONFIG_LTC4088_CHARGER) += ltc4088-charger.o -obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o +obj-$(CONFIG_CHARGER_SMB347) += smb347_charger.o +obj-$(CONFIG_BQ51051B_CHARGER) += bq51051b_charger.o +obj-$(CONFIG_BATTERY_TEMP_CONTROL) += battery_temp_ctrl.o +obj-$(CONFIG_BATTERY_BCL) += battery_current_limit.o diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index c284143cfcd..496d26aa868 100644 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -20,6 +20,11 @@ #include #include #include +#include +#include +#ifdef CONFIG_SEC_DEBUG_FUELGAUGE_LOG +#include +#endif #define MAX17040_VCELL_MSB 0x02 #define MAX17040_VCELL_LSB 0x03 @@ -34,146 +39,405 @@ #define MAX17040_CMD_MSB 0xFE #define MAX17040_CMD_LSB 0xFF -#define MAX17040_DELAY 1000 -#define MAX17040_BATTERY_FULL 95 +#define MAX17048_STATUS_REG 0x1A +#define MAX17048_VALRT_REG 0x14 + +#define MAX17040_LONG_DELAY 30000 /* msec */ +#define LOG_DELTA_VOLTAGE (150 * 1000) /* 150 mV */ +#define MAX17040_FAST_DELAY 500 /* msec */ +#define FAST_LOG_COUNT 60 /* 30 sec */ + +static ssize_t sec_fg_show_property(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t sec_fg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +extern int system_rev; + +#define MAX17040_CHECK_LOW_VCELL_SOC 2 +#define MAX17040_LOW_AVGVCELL 3350000 + +#define ADC_SAMPLE_COUNT 10 +struct sample_info { + unsigned int cnt; + int total; + int average; + int adc_arr[ADC_SAMPLE_COUNT]; + int index; +}; struct max17040_chip { struct i2c_client *client; struct delayed_work work; struct power_supply battery; struct max17040_platform_data *pdata; + struct wake_lock lowbat_wake_lock; + struct mutex mutex; - /* State Of Connect */ - int online; /* battery voltage */ int vcell; - /* battery capacity */ + int prevcell; + int avgvcell; + /* normal soc (adjust) */ int soc; - /* State Of Charge */ - int status; + /* raw soc */ + int raw_soc; + /* work interval */ + unsigned int fg_interval; + /* log count */ + unsigned int fast_log_count; + /* current temperature */ + int temperature; + /* current rcomp */ + u16 rcomp; + /* new rcomp */ + u16 new_rcomp; + /* adjust full soc */ + int full_soc; + int batt_type; + int chg_state; + bool is_wakelock_active; + + struct sample_info sample; }; -static int max17040_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) +static int is_max17048; +static void check_using_max17048(void) { - struct max17040_chip *chip = container_of(psy, - struct max17040_chip, battery); - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = chip->status; - break; - case POWER_SUPPLY_PROP_ONLINE: - val->intval = chip->online; - break; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = chip->vcell; - break; - case POWER_SUPPLY_PROP_CAPACITY: - val->intval = chip->soc; - break; - default: - return -EINVAL; +#if defined(CONFIG_MACH_JAGUAR) + if (system_rev < 0x03) { + is_max17048 = 0; + return; } - return 0; +#elif defined(CONFIG_MACH_M2_VZW) + if (system_rev < 0x02) { + is_max17048 = 0; + return; + } +#endif + is_max17048 = 1; } + static int max17040_write_reg(struct i2c_client *client, int reg, u8 value) { + struct max17040_chip *chip = i2c_get_clientdata(client); int ret; + mutex_lock(&chip->mutex); + ret = i2c_smbus_write_byte_data(client, reg, value); if (ret < 0) dev_err(&client->dev, "%s: err %d\n", __func__, ret); + mutex_unlock(&chip->mutex); + return ret; } static int max17040_read_reg(struct i2c_client *client, int reg) { + struct max17040_chip *chip = i2c_get_clientdata(client); int ret; + mutex_lock(&chip->mutex); + ret = i2c_smbus_read_byte_data(client, reg); if (ret < 0) dev_err(&client->dev, "%s: err %d\n", __func__, ret); + mutex_unlock(&chip->mutex); + return ret; } +static int max17040_read_word(struct i2c_client *client, int reg) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + int ret; + + mutex_lock(&chip->mutex); + + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + mutex_unlock(&chip->mutex); + + return ret; +} + +static void max17040_dump_regs(struct i2c_client *client) +{ + int i; + int data; + char *str = NULL; + + str = kzalloc(sizeof(char)*1024, GFP_KERNEL); + if (!str) + return; + + for (i = 0x2; i < 0x1c; i += 2) { + data = max17040_read_word(client, i); + sprintf(str+strlen(str), "%04xh,", data); + } + + data = max17040_read_word(client, 0xff); + sprintf(str+strlen(str), "%04xh,", data); + + dev_info(&client->dev, "%s", str); + + kfree(str); +} + static void max17040_reset(struct i2c_client *client) { - max17040_write_reg(client, MAX17040_CMD_MSB, 0x54); - max17040_write_reg(client, MAX17040_CMD_LSB, 0x00); + struct max17040_chip *chip = i2c_get_clientdata(client); + u16 reset_cmd = 0x5400; + + if (is_max17048) { + mutex_lock(&chip->mutex); + i2c_smbus_write_word_data(client, MAX17040_CMD_MSB, + reset_cmd); + mutex_unlock(&chip->mutex); + } else { + max17040_write_reg(client, MAX17040_CMD_MSB, 0x54); + max17040_write_reg(client, MAX17040_CMD_LSB, 0x00); + } +} + +static int max17040_get_average_vcell(struct i2c_client *client) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + unsigned int cnt = 0; + int total = 0; + int average = 0; + int index = 0; + + cnt = chip->sample.cnt; + total = chip->sample.total; + + if (cnt < ADC_SAMPLE_COUNT) { + chip->sample.adc_arr[cnt] = chip->vcell; + chip->sample.index = cnt; + chip->sample.cnt = ++cnt; + + total += chip->vcell; + average = total / cnt; + } else { + index = chip->sample.index; + if (++index >= ADC_SAMPLE_COUNT) + index = 0; + + total = total - + chip->sample.adc_arr[index] + chip->vcell; + average = total / ADC_SAMPLE_COUNT; + + chip->sample.adc_arr[index] = chip->vcell; + chip->sample.index = index; + } + + chip->sample.total = total; + chip->sample.average = average; + + return average; } static void max17040_get_vcell(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; + u8 data[2]; + int temp; - msb = max17040_read_reg(client, MAX17040_VCELL_MSB); - lsb = max17040_read_reg(client, MAX17040_VCELL_LSB); + if (is_max17048) { + temp = max17040_read_word(client, MAX17040_VCELL_MSB); + data[0] = temp & 0xff; + data[1] = temp >> 8; + } else { + data[0] = max17040_read_reg(client, MAX17040_VCELL_MSB); + data[1] = max17040_read_reg(client, MAX17040_VCELL_LSB); + } + chip->prevcell = chip->vcell; + chip->vcell = ((data[0] << 4) + (data[1] >> 4)) * 1250; + if (chip->prevcell == 0) + chip->prevcell = chip->vcell; - chip->vcell = (msb << 4) + (lsb >> 4); + chip->avgvcell = max17040_get_average_vcell(client); } static void max17040_get_soc(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; + u8 data[2]; + int temp; + + unsigned int soc, psoc, temp_soc, empty_soc, full_soc; + u64 psoc64 = 0; + u64 data64[2] = {0, 0}; + u32 divisor = 10000000; + + if (is_max17048) { + temp = max17040_read_word(client, MAX17040_SOC_MSB); + data[0] = temp & 0xff; + data[1] = temp >> 8; + } else { + data[0] = max17040_read_reg(client, MAX17040_SOC_MSB); + data[1] = max17040_read_reg(client, MAX17040_SOC_LSB); + } - msb = max17040_read_reg(client, MAX17040_SOC_MSB); - lsb = max17040_read_reg(client, MAX17040_SOC_LSB); + if (chip->batt_type) { /* 4.35V battery */ + data64[0] = data[0]; + data64[1] = data[1]; + pr_debug("soc[0] = %lld, soc[1] = %lld\n", + data64[0], data64[1]); + + /* TempSOC = ((SOC1 * 256) + SOC2) * 0.001953125 */ + psoc64 = ((data64[0]*256 + data64[1]) * 1953125); + psoc64 = div_u64(psoc64, divisor); + psoc = psoc64 & 0xffff; + } else { /* NORMAL (4.2V) */ + psoc = data[0] * 100 + (data[1] * 100) / 256; + } + chip->raw_soc = psoc; + + + /* calculate adjust soc [[ */ + if ((chip->batt_type == BATT_TYPE_D2_ACTIVE) || + (chip->batt_type == BATT_TYPE_D2_HIGH) || + (chip->batt_type == BATT_TYPE_GOGH)) { + empty_soc = 150; + full_soc = FULL_SOC_DEFAULT; + } else if (chip->batt_type == BATT_TYPE_AEGIS2) { + empty_soc = 110; + full_soc = FULL_SOC_DEFAULT; + } else { + empty_soc = EMPTY_SOC; + full_soc = chip->full_soc; + } + + /* D2_HIGH, D2_ACTIVE : AdjSOC = ((pSOC - 0.8) * 100) / (100-0.8) */ + /* Jaguar : AdjSOC = ((pSOC - 0.3) * 100) / (100-0.3) */ + if (psoc > empty_soc) { + temp_soc = ((psoc - empty_soc) * 10000)/(full_soc - empty_soc); + pr_debug("[battery] temp_soc = %d, psoc = .8%d\n", + temp_soc, psoc); + } else + temp_soc = 0; - chip->soc = msb; + soc = temp_soc/100; + /* ]] calculate adjust soc */ + + soc = min(soc, (uint)100); + chip->soc = soc; } static void max17040_get_version(struct i2c_client *client) { - u8 msb; - u8 lsb; + u8 data[2]; + int temp; + pr_info("%s :\n", __func__); + + if (is_max17048) { + temp = max17040_read_word(client, MAX17040_VER_MSB); + data[0] = temp & 0xff; + data[1] = temp >> 8; + } else { + data[0] = max17040_read_reg(client, MAX17040_VER_MSB); + data[1] = max17040_read_reg(client, MAX17040_VER_LSB); + } + dev_info(&client->dev, + "MAX17040 Fuel-Gauge Ver %d%d\n", data[0], data[0]); +} - msb = max17040_read_reg(client, MAX17040_VER_MSB); - lsb = max17040_read_reg(client, MAX17040_VER_LSB); +static u16 max17040_get_rcomp(struct i2c_client *client) +{ + u8 data[2]; + int temp; + u16 ret = 0; + + if (is_max17048) { + temp = max17040_read_word(client, MAX17040_RCOMP_MSB); + data[0] = temp & 0xff; /* RCOMP (0Ch) */ + data[1] = temp >> 8; /* Alert Threshold (0Dh) */ + } else { + data[0] = max17040_read_reg(client, MAX17040_RCOMP_MSB); + data[1] = max17040_read_reg(client, MAX17040_RCOMP_LSB); + } + + ret = (u16)(data[0]<<8 | data[1]); + /* pr_info("MAX17040 Fuel-Gauge RCOMP 0x%x%x\n", msb, lsb); */ + pr_info("%s : current rcomp = 0x%x(%x)\n", __func__, ret, data[0]); - dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb); + return ret; } -static void max17040_get_online(struct i2c_client *client) +static void max17040_set_rcomp(struct i2c_client *client, u16 new_rcomp) { struct max17040_chip *chip = i2c_get_clientdata(client); - if (chip->pdata->battery_online) - chip->online = chip->pdata->battery_online(); - else - chip->online = 1; + mutex_lock(&chip->mutex); + + /* + pr_info("%s : new rcomp = 0x%x(%d)\n", __func__, + new_rcomp, new_rcomp>>8); + */ + + i2c_smbus_write_word_data(client, MAX17040_RCOMP_MSB, + swab16(new_rcomp)); + + mutex_unlock(&chip->mutex); } -static void max17040_get_status(struct i2c_client *client) +static u16 max17048_get_register_word(struct i2c_client *client, int reg) +{ + int temp; + u16 ret = 0; + + temp = max17040_read_word(client, reg); + ret = swab16(temp); + + pr_info("%s : reg(%xh) : 0x%x\n", + __func__, reg, ret); + + return ret; +} + +static void max17048_set_register_word(struct i2c_client *client, + int reg, u16 reg_value) { struct max17040_chip *chip = i2c_get_clientdata(client); - if (!chip->pdata->charger_online || !chip->pdata->charger_enable) { - chip->status = POWER_SUPPLY_STATUS_UNKNOWN; - return; - } + mutex_lock(&chip->mutex); - if (chip->pdata->charger_online()) { - if (chip->pdata->charger_enable()) - chip->status = POWER_SUPPLY_STATUS_CHARGING; - else - chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING; + i2c_smbus_write_word_data(client, reg, + swab16(reg_value)); + + mutex_unlock(&chip->mutex); +} + + +static void max17040_adjust_fullsoc(struct i2c_client *client) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + int prev_full_soc = chip->full_soc; + + if (chip->raw_soc < FULL_SOC_LOW) { + chip->full_soc = FULL_SOC_LOW; + } else if (chip->raw_soc > FULL_SOC_HIGH) { + chip->full_soc = (FULL_SOC_HIGH - FULL_KEEP_SOC); } else { - chip->status = POWER_SUPPLY_STATUS_DISCHARGING; + if (chip->raw_soc > (FULL_SOC_LOW + FULL_KEEP_SOC)) + chip->full_soc = chip->raw_soc - FULL_KEEP_SOC; + else + chip->full_soc = FULL_SOC_LOW; } - if (chip->soc > MAX17040_BATTERY_FULL) - chip->status = POWER_SUPPLY_STATUS_FULL; + if (prev_full_soc != chip->full_soc) + pr_info("%s : full_soc = %d\n", __func__, chip->full_soc); } static void max17040_work(struct work_struct *work) @@ -184,10 +448,30 @@ static void max17040_work(struct work_struct *work) max17040_get_vcell(chip->client); max17040_get_soc(chip->client); - max17040_get_online(chip->client); - max17040_get_status(chip->client); + pr_info("%s : VCELL:%dmV, AVGVCELL:%dmV\n", __func__, + chip->vcell/1000, chip->avgvcell/1000); + pr_info("%s : Raw SOC:%d%%, SOC:%d%%\n", __func__, + chip->raw_soc, chip->soc); + pr_info("%s : CONFIG:0x%04x, RATE:0x%04x\n", __func__, + max17040_read_word(chip->client, MAX17040_RCOMP_MSB), + max17040_read_word(chip->client, 0x16)); + pr_info("%s : STATUS:0x%04x, temperature:%d\n", __func__, + max17040_read_word(chip->client, 0x1a), + chip->temperature); + + max17040_dump_regs(chip->client); + + if ((chip->soc >= 5) && (chip->is_wakelock_active)) { + pr_info("%s : unlock lowbat_wake lock, charging\n", __func__); + chip->is_wakelock_active = false; + wake_unlock(&chip->lowbat_wake_lock); + } + +#ifdef CONFIG_SEC_DEBUG_FUELGAUGE_LOG + sec_debug_fuelgauge_log(chip->vcell, (unsigned short)chip->soc, 0); +#endif - schedule_delayed_work(&chip->work, MAX17040_DELAY); + schedule_delayed_work(&chip->work, msecs_to_jiffies(chip->fg_interval)); } static enum power_supply_property max17040_battery_props[] = { @@ -197,16 +481,347 @@ static enum power_supply_property max17040_battery_props[] = { POWER_SUPPLY_PROP_CAPACITY, }; +#define SEC_FG_ATTR(_name) \ +{ \ + .attr = { .name = #_name, \ + .mode = 0664, \ + }, \ + .show = sec_fg_show_property, \ + .store = sec_fg_store, \ +} + +static struct device_attribute sec_fg_attrs[] = { + SEC_FG_ATTR(fg_reset_soc), + SEC_FG_ATTR(fg_read_soc), + SEC_FG_ATTR(fg_read_rcomp), + SEC_FG_ATTR(fg_read_fsoc), +}; + +enum { + FG_RESET_SOC = 0, + FG_READ_SOC, + FG_READ_RCOMP, + FG_READ_FSOC, +}; + +static ssize_t sec_fg_show_property(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct max17040_chip *chip = container_of(psy, + struct max17040_chip, + battery); + + int i = 0; + const ptrdiff_t off = attr - sec_fg_attrs; + + switch (off) { + case FG_READ_SOC: + max17040_get_soc(chip->client); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + chip->soc); + break; + case FG_READ_RCOMP: + chip->rcomp = max17040_get_rcomp(chip->client); + i += scnprintf(buf + i, PAGE_SIZE - i, "0x%04x\n", + chip->rcomp); + break; + case FG_READ_FSOC: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + chip->full_soc); + break; + default: + i = -EINVAL; + } + + return i; +} + +static ssize_t sec_fg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct max17040_chip *chip = container_of(psy, + struct max17040_chip, + battery); + + int x = 0; + int ret = 0; + const ptrdiff_t off = attr - sec_fg_attrs; + + switch (off) { + case FG_RESET_SOC: + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 1) + max17040_reset(chip->client); + ret = count; + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int fuelgauge_create_attrs(struct device *dev) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(sec_fg_attrs); i++) { + rc = device_create_file(dev, &sec_fg_attrs[i]); + if (rc) + goto fg_attrs_failed; + } + goto succeed; + +fg_attrs_failed: + while (i--) + device_remove_file(dev, &sec_fg_attrs[i]); +succeed: + return rc; +} + +static irqreturn_t max17040_int_work_func(int irq, void *max_chip) +{ + struct max17040_chip *chip = max_chip; +#if 0 + u8 data[2]; +#endif + u16 ret = 0; + + pr_info("[ALERT] %s\n", __func__); + + wake_lock(&chip->lowbat_wake_lock); + chip->is_wakelock_active = true; + + max17040_get_soc(chip->client); + max17040_get_vcell(chip->client); + max17040_get_rcomp(chip->client); + + pr_info("[ALERT] vcell(%d), soc(%d)\n", chip->vcell, chip->soc); + pr_info("[ALERT] STATUS reg :\n"); + max17048_get_register_word(chip->client, MAX17048_STATUS_REG); + pr_info("[ALERT] VALRT reg :\n"); + max17048_get_register_word(chip->client, MAX17048_VALRT_REG); + + if (chip->soc >= 5) { + max17048_set_register_word(chip->client, + MAX17048_VALRT_REG, 0x00ff); + max17048_get_register_word(chip->client, MAX17048_VALRT_REG); + + chip->is_wakelock_active = false; + wake_unlock(&chip->lowbat_wake_lock); + } else { + if (chip->pdata->low_batt_cb) + chip->pdata->low_batt_cb(); + } + + /* clear ALRT bit, rewrite low batt thrshld */ + ret = max17040_get_rcomp(chip->client); + ret = ((ret & 0xff00) | 0x1c); + max17040_set_rcomp(chip->client, ret); + max17040_get_rcomp(chip->client); + + return IRQ_HANDLED; +} + +static void max17040_rcomp_update(struct i2c_client *client, + int temp, int chg_state) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + int starting_rcomp = 0; + int temp_cohot; + int temp_cocold; + int new_rcomp = 0; + int rcomp0 = 0; + + if ((chip->batt_type == BATT_TYPE_D2_ACTIVE) ||\ + (chip->batt_type == BATT_TYPE_JAGUAR) ||\ + (chip->batt_type == BATT_TYPE_AEGIS2) ||\ + (chip->batt_type == BATT_TYPE_GOGH)) { + temp_cohot = -300; /* Cohot (-0.3) */ + temp_cocold = -6075; /* Cocold (-6.075) */ + } else { /* Jaguar, D2_HIGH */ + temp_cohot = 0; /* Cohot (0) */ + temp_cocold = -11050; /* Cocold (-11.05) */ + } + + if (chip->batt_type) { /* normal battery(4.2V) is 0 */ + + /* set up RCOMP value */ + if (chip->batt_type == BATT_TYPE_D2_HIGH) { + if (chg_state == POWER_SUPPLY_STATUS_CHARGING) + chip->pdata->rcomp_value = 0x701d; + else + chip->pdata->rcomp_value = 0xa01d; + } else if (chip->batt_type == BATT_TYPE_D2_ACTIVE) { + if (chg_state == POWER_SUPPLY_STATUS_CHARGING) + chip->pdata->rcomp_value = 0x851c; + else + chip->pdata->rcomp_value = 0x6d1c; + } else if (chip->batt_type == BATT_TYPE_GOGH) { + if (chg_state == POWER_SUPPLY_STATUS_CHARGING) + chip->pdata->rcomp_value = 0x701c; + else + chip->pdata->rcomp_value = 0x691c; + } + + starting_rcomp = (int)(chip->pdata->rcomp_value >> 8); + + /*if (temp > RCOMP0_TEMP) + new_rcomp = + starting_rcomp + + (((temp-20) * temp_cohot) / 1000);*/ + if (temp < RCOMP0_TEMP) + new_rcomp = + starting_rcomp + + (((temp-20) * temp_cocold) / 1000); + else + new_rcomp = starting_rcomp; + + if (new_rcomp > 255) + new_rcomp = 255; + chip->new_rcomp = ((u8)new_rcomp << 8) | (chip->rcomp&0xFF); + + if (chip->rcomp != chip->new_rcomp) { + pr_info("%s : temp(%d), rcomp 0x%x -> 0x%x (%d)\n", + __func__, temp, + chip->rcomp, + chip->new_rcomp, + chip->new_rcomp>>8); + chip->rcomp = chip->new_rcomp; + max17040_set_rcomp(client, chip->new_rcomp); + } + } else { + + rcomp0 = (int)(chip->pdata->rcomp_value >> 8); + rcomp0 *= 10; + + if (temp < RCOMP0_TEMP) { + new_rcomp = (rcomp0 + 50*(RCOMP0_TEMP-temp))/10; + new_rcomp = max(new_rcomp, 0); + new_rcomp = min(new_rcomp, 255); + chip->new_rcomp + = ((u8)new_rcomp << 8) | (chip->rcomp&0xFF); + } else if (temp > RCOMP0_TEMP) { + new_rcomp = (rcomp0 - 18*(temp-RCOMP0_TEMP))/10; + new_rcomp = max(new_rcomp, 0); + new_rcomp = min(new_rcomp, 255); + chip->new_rcomp + = ((u8)new_rcomp << 8) | (chip->rcomp&0xFF); + } else + chip->new_rcomp = chip->pdata->rcomp_value; + + if (chip->rcomp != chip->new_rcomp) { + pr_info("%s : 0x%x -> 0x%x (%d)\n", __func__, + chip->rcomp, + chip->new_rcomp, + chip->new_rcomp>>8); + } + } +} + +static int max17040_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max17040_chip *chip = container_of(psy, + struct max17040_chip, battery); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = 1; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + max17040_get_vcell(chip->client); + val->intval = chip->vcell; + break; + case POWER_SUPPLY_PROP_CAPACITY: + switch (val->intval) { + case 0: /*normal soc */ + max17040_get_soc(chip->client); + val->intval = chip->soc; + break; + case 1: /*raw soc */ + max17040_get_soc(chip->client); + val->intval = chip->raw_soc; + break; + case 2: /*rcomp */ + val->intval = chip->rcomp; + break; + case 3: /*full soc */ + val->intval = chip->full_soc; + break; + } + break; + default: + return -EINVAL; + } + return 0; +} + +static int max17040_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct max17040_chip *chip = container_of(psy, + struct max17040_chip, battery); + + switch (psp) { + case POWER_SUPPLY_PROP_TEMP: + chip->temperature = val->intval; + pr_debug("%s: current temperature = %d\n", + __func__, chip->temperature); + if (chip->batt_type) + max17040_rcomp_update(chip->client, + chip->temperature, chip->chg_state); + break; + case POWER_SUPPLY_PROP_STATUS: + chip->chg_state = val->intval; + switch (val->intval) { + case POWER_SUPPLY_STATUS_FULL: + pr_info("%s: charger full state!\n", __func__); + /* adjust full soc */ + max17040_adjust_fullsoc(chip->client); + break; + case POWER_SUPPLY_STATUS_CHARGING: + case POWER_SUPPLY_STATUS_DISCHARGING: + pr_debug("%s: charger state!(%d)\n", + __func__, chip->chg_state); + max17040_rcomp_update(chip->client, + chip->temperature, chip->chg_state); + break; + default: + return -EINVAL; + } + break; + case POWER_SUPPLY_PROP_FUELGAUGE_STATE: + pr_info("%s: fuelgauge reset\n", __func__); + max17040_reset(chip->client); + break; + default: + return -EINVAL; + } + return 0; +} + static int __devinit max17040_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct max17040_chip *chip; - int ret; + int ret = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) return -EIO; + pr_info("%s: MAX17043 driver Loading!\n", __func__); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @@ -214,36 +829,115 @@ static int __devinit max17040_probe(struct i2c_client *client, chip->client = client; chip->pdata = client->dev.platform_data; + if (!chip->pdata) { + pr_err("%s: no fuel gauge platform data\n", __func__); + goto err_kfree; + } + + chip->fg_interval = MAX17040_LONG_DELAY; + chip->fast_log_count = 0; + chip->temperature = RCOMP0_TEMP; + chip->full_soc = FULL_SOC_DEFAULT; + chip->prevcell = chip->vcell = 0; + chip->chg_state = POWER_SUPPLY_STATUS_DISCHARGING; + i2c_set_clientdata(client, chip); - chip->battery.name = "battery"; - chip->battery.type = POWER_SUPPLY_TYPE_BATTERY; - chip->battery.get_property = max17040_get_property; - chip->battery.properties = max17040_battery_props; - chip->battery.num_properties = ARRAY_SIZE(max17040_battery_props); + mutex_init(&chip->mutex); + + chip->pdata->hw_init(); /* important */ + + check_using_max17048(); + + max17040_get_version(client); + chip->rcomp = max17040_get_rcomp(client); + + if (chip->pdata->check_batt_type) + chip->batt_type = chip->pdata->check_batt_type(); + else + chip->batt_type = BATT_TYPE_NORMAL; + + if (chip->batt_type) { + chip->pdata->rcomp_value = chip->rcomp; + pr_info("[max17048] using RCOMP (0x%x)\n", + chip->pdata->rcomp_value); + } else { + chip->pdata->rcomp_value = 0xe71f; + pr_info("[max17048] using 4.2V battery\n"); + } + + chip->rcomp = chip->pdata->rcomp_value; + chip->new_rcomp = chip->pdata->rcomp_value; + max17040_set_rcomp(client, chip->new_rcomp); + chip->rcomp = max17040_get_rcomp(client); + + chip->battery.name = "fuelgauge", + chip->battery.type = POWER_SUPPLY_TYPE_BATTERY, + chip->battery.get_property = max17040_get_property, + chip->battery.set_property = max17040_set_property, + chip->battery.properties = max17040_battery_props, + chip->battery.num_properties = ARRAY_SIZE(max17040_battery_props), + chip->is_wakelock_active = false; ret = power_supply_register(&client->dev, &chip->battery); if (ret) { dev_err(&client->dev, "failed: power supply register\n"); - kfree(chip); - return ret; + goto err_psy_register; } - max17040_reset(client); - max17040_get_version(client); + wake_lock_init(&chip->lowbat_wake_lock, WAKE_LOCK_SUSPEND, + "fuelgague-lowbat"); + + ret = request_threaded_irq(chip->client->irq, NULL, + max17040_int_work_func, IRQF_TRIGGER_FALLING, + "max17040", chip); + if (ret) { + pr_err("%s : Failed to request fuelgauge irq\n", __func__); + goto err_request_irq; + } + + ret = enable_irq_wake(chip->client->irq); + if (ret) { + pr_err("%s : Failed to enable fuelgauge irq wake\n", __func__); + goto err_irq_wake; + } + + /* update rcomp test */ + /* + static int itemp; + for (itemp=100; itemp>-100; itemp--) { + max17040_rcomp_update(client, itemp); + } + */ + + /* create fuelgauge attributes */ + fuelgauge_create_attrs(chip->battery.dev); INIT_DELAYED_WORK_DEFERRABLE(&chip->work, max17040_work); - schedule_delayed_work(&chip->work, MAX17040_DELAY); + schedule_delayed_work(&chip->work, 0); return 0; + +err_irq_wake: + free_irq(chip->client->irq, NULL); +err_request_irq: + wake_lock_destroy(&chip->lowbat_wake_lock); + power_supply_unregister(&chip->battery); +err_psy_register: + mutex_destroy(&chip->mutex); +err_kfree: + kfree(chip); + return ret; } static int __devexit max17040_remove(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); + wake_lock_destroy(&chip->lowbat_wake_lock); power_supply_unregister(&chip->battery); cancel_delayed_work(&chip->work); + mutex_destroy(&chip->mutex); kfree(chip); return 0; } @@ -255,6 +949,9 @@ static int max17040_suspend(struct i2c_client *client, { struct max17040_chip *chip = i2c_get_clientdata(client); + if (chip->is_wakelock_active) + wake_unlock(&chip->lowbat_wake_lock); + cancel_delayed_work(&chip->work); return 0; } @@ -263,7 +960,7 @@ static int max17040_resume(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - schedule_delayed_work(&chip->work, MAX17040_DELAY); + schedule_delayed_work(&chip->work, 0); return 0; } @@ -290,7 +987,18 @@ static struct i2c_driver max17040_i2c_driver = { .resume = max17040_resume, .id_table = max17040_id, }; -module_i2c_driver(max17040_i2c_driver); + +static int __init max17040_init(void) +{ + return i2c_add_driver(&max17040_i2c_driver); +} +module_init(max17040_init); + +static void __exit max17040_exit(void) +{ + i2c_del_driver(&max17040_i2c_driver); +} +module_exit(max17040_exit); MODULE_AUTHOR("Minkyu Kang "); MODULE_DESCRIPTION("MAX17040 Fuel Gauge"); diff --git a/drivers/power/pm8921-sec-charger.c b/drivers/power/pm8921-sec-charger.c new file mode 100644 index 00000000000..171b0cbd12e --- /dev/null +++ b/drivers/power/pm8921-sec-charger.c @@ -0,0 +1,4214 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define CHG_BUCK_CLOCK_CTRL 0x14 + +#define PBL_ACCESS1 0x04 +#define PBL_ACCESS2 0x05 +#define SYS_CONFIG_1 0x06 +#define SYS_CONFIG_2 0x07 +#define CHG_CNTRL 0x204 +#define CHG_IBAT_MAX 0x205 +#define CHG_TEST 0x206 +#define CHG_BUCK_CTRL_TEST1 0x207 +#define CHG_BUCK_CTRL_TEST2 0x208 +#define CHG_BUCK_CTRL_TEST3 0x209 +#define COMPARATOR_OVERRIDE 0x20A +#define PSI_TXRX_SAMPLE_DATA_0 0x20B +#define PSI_TXRX_SAMPLE_DATA_1 0x20C +#define PSI_TXRX_SAMPLE_DATA_2 0x20D +#define PSI_TXRX_SAMPLE_DATA_3 0x20E +#define PSI_CONFIG_STATUS 0x20F +#define CHG_IBAT_SAFE 0x210 +#define CHG_ITRICKLE 0x211 +#define CHG_CNTRL_2 0x212 +#define CHG_VBAT_DET 0x213 +#define CHG_VTRICKLE 0x214 +#define CHG_ITERM 0x215 +#define CHG_CNTRL_3 0x216 +#define CHG_VIN_MIN 0x217 +#define CHG_TWDOG 0x218 +#define CHG_TTRKL_MAX 0x219 +#define CHG_TEMP_THRESH 0x21A +#define CHG_TCHG_MAX 0x21B +#define USB_OVP_CONTROL 0x21C +#define DC_OVP_CONTROL 0x21D +#define USB_OVP_TEST 0x21E +#define DC_OVP_TEST 0x21F +#define CHG_VDD_MAX 0x220 +#define CHG_VDD_SAFE 0x221 +#define CHG_VBAT_BOOT_THRESH 0x222 +#define USB_OVP_TRIM 0x355 +#define BUCK_CONTROL_TRIM1 0x356 +#define BUCK_CONTROL_TRIM2 0x357 +#define BUCK_CONTROL_TRIM3 0x358 +#define BUCK_CONTROL_TRIM4 0x359 +#define CHG_DEFAULTS_TRIM 0x35A +#define CHG_ITRIM 0x35B +#define CHG_TTRIM 0x35C +#define CHG_COMP_OVR 0x20A + +/* lmh_add for disable bms */ +#define BMS_CONTROL 0x224 +#define EN_BMS_BIT BIT(7) + +/* check EOC every 10 seconds */ +#define EOC_CHECK_PERIOD_MS 10000 +/* check for USB unplug every 200 msecs */ +#define UNPLUG_CHECK_WAIT_PERIOD_MS 200 + +enum chg_fsm_state { + FSM_STATE_OFF_0 = 0, + FSM_STATE_BATFETDET_START_12 = 12, + FSM_STATE_BATFETDET_END_16 = 16, + FSM_STATE_ON_CHG_HIGHI_1 = 1, + FSM_STATE_ATC_2A = 2, + FSM_STATE_ATC_2B = 18, + FSM_STATE_ON_BAT_3 = 3, + FSM_STATE_ATC_FAIL_4 = 4 , + FSM_STATE_DELAY_5 = 5, + FSM_STATE_ON_CHG_AND_BAT_6 = 6, + FSM_STATE_FAST_CHG_7 = 7, + FSM_STATE_TRKL_CHG_8 = 8, + FSM_STATE_CHG_FAIL_9 = 9, + FSM_STATE_EOC_10 = 10, + FSM_STATE_ON_CHG_VREGOK_11 = 11, + FSM_STATE_ATC_PAUSE_13 = 13, + FSM_STATE_FAST_CHG_PAUSE_14 = 14, + FSM_STATE_TRKL_CHG_PAUSE_15 = 15, + FSM_STATE_START_BOOT = 20, + FSM_STATE_FLCB_VREGOK = 21, + FSM_STATE_FLCB = 22, +}; + +struct fsm_state_to_batt_status { + enum chg_fsm_state fsm_state; + int batt_state; +}; + +static struct fsm_state_to_batt_status map[] = { + {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN}, + {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN}, + {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN}, + /* + * for CHG_HIGHI_1 report NOT_CHARGING if battery missing, + * too hot/cold, charger too hot + */ + {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL}, + {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING}, + {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING}, + {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING}, + {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING}, + {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN }, + {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING}, + {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING}, + {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING}, + {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING}, + {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL}, + {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING}, + {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING}, + {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING}, + {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING}, + {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING}, + {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING}, + {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING}, +}; + +enum chg_regulation_loop { + VDD_LOOP = BIT(3), + BAT_CURRENT_LOOP = BIT(2), + INPUT_CURRENT_LOOP = BIT(1), + INPUT_VOLTAGE_LOOP = BIT(0), + CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP + | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP, +}; + +enum pmic_chg_interrupts { + USBIN_VALID_IRQ = 0, + USBIN_OV_IRQ, + BATT_INSERTED_IRQ, + VBATDET_LOW_IRQ, + USBIN_UV_IRQ, + VBAT_OV_IRQ, + CHGWDOG_IRQ, + VCP_IRQ, + ATCDONE_IRQ, + ATCFAIL_IRQ, + CHGDONE_IRQ, + CHGFAIL_IRQ, + CHGSTATE_IRQ, + LOOP_CHANGE_IRQ, + FASTCHG_IRQ, + TRKLCHG_IRQ, + BATT_REMOVED_IRQ, + BATTTEMP_HOT_IRQ, + CHGHOT_IRQ, + BATTTEMP_COLD_IRQ, + CHG_GONE_IRQ, + BAT_TEMP_OK_IRQ, + COARSE_DET_LOW_IRQ, + VDD_LOOP_IRQ, + VREG_OV_IRQ, + VBATDET_IRQ, + BATFET_IRQ, + PSI_IRQ, + DCIN_VALID_IRQ, + DCIN_OV_IRQ, + DCIN_UV_IRQ, + PM_CHG_MAX_INTS, +}; + +struct bms_notify { + int is_battery_full; + int is_charging; + struct work_struct work; +}; + +/** + * struct pm8921_chg_chip -device information + * @dev: device pointer to access the parent + * @usb_present: present status of usb + * @dc_present: present status of dc + * @usb_charger_current: usb current to charge the battery with used when + * the usb path is enabled or charging is resumed + * @safety_time: max time for which charging will happen + * @update_time: how frequently the userland needs to be updated + * @max_voltage_mv: the max volts the batt should be charged up to + * @min_voltage_mv: the min battery voltage before turning the FETon + * @cool_temp_dc: the cool temp threshold in deciCelcius + * @warm_temp_dc: the warm temp threshold in deciCelcius + * @resume_voltage_delta: the voltage delta from vdd max at which the + * battery should resume charging + * @term_current: The charging based term current + * + */ +struct pm8921_chg_chip { + struct device *dev; + unsigned int usb_present; + unsigned int dc_present; + unsigned int usb_charger_current; + unsigned int max_bat_chg_current; + unsigned int pmic_chg_irq[PM_CHG_MAX_INTS]; + unsigned int safety_time; + unsigned int ttrkl_time; + unsigned int update_time; + unsigned int max_voltage_mv; + unsigned int min_voltage_mv; + unsigned int cool_temp_dc; + unsigned int warm_temp_dc; + unsigned int temp_check_period; + unsigned int cool_bat_chg_current; + unsigned int warm_bat_chg_current; + unsigned int cool_bat_voltage; + unsigned int warm_bat_voltage; + unsigned int is_bat_cool; + unsigned int is_bat_warm; + unsigned int resume_voltage_delta; + unsigned int term_current; + unsigned int vbat_channel; + unsigned int batt_temp_channel; + unsigned int batt_id_channel; + struct power_supply usb_psy; + struct power_supply ac_psy; + struct power_supply *ext_psy; + struct power_supply batt_psy; + struct dentry *dent; + struct bms_notify bms_notify; + bool keep_btm_on_suspend; + bool ext_charging; + bool ext_charge_done; + DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS); + struct work_struct battery_id_valid_work; + int64_t batt_id_min; + int64_t batt_id_max; + int trkl_voltage; + int weak_voltage; + int trkl_current; + int weak_current; + int vin_min; + unsigned int *thermal_mitigation; + int thermal_levels; + struct delayed_work update_heartbeat_work; + struct delayed_work eoc_work; + struct delayed_work unplug_wrkarnd_restore_work; + struct delayed_work unplug_check_work; + struct wake_lock unplug_wrkarnd_restore_wake_lock; + struct wake_lock eoc_wake_lock; + enum pm8921_chg_cold_thr cold_thr; + enum pm8921_chg_hot_thr hot_thr; + + /* samsung add variable */ + enum cable_type_t cable_type; + bool charging_enabled; + unsigned int charging_status; + unsigned int batt_present; + unsigned int batt_soc; + unsigned int batt_curr; + unsigned int batt_vcell; + unsigned int batt_temp; + unsigned int batt_temp_adc; + unsigned int batt_is_full; + unsigned int batt_is_recharging; + unsigned int test_value; + struct pm8921_reg chg_reg; + struct pm8921_irq chg_irq; + struct proc_dir_entry *entry; + int (*get_cable_type)(void); +}; + +static int charging_disabled; +static int thermal_mitigation; + +static struct pm8921_chg_chip *the_chip; + +static struct pm8xxx_adc_arb_btm_param btm_config; + +static void handle_cable_insertion_removal(struct pm8921_chg_chip *chip); +static void batt_status_update(struct pm8921_chg_chip *chip); +static ssize_t sec_bat_show_property(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t sec_bat_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + + +static int TEST_iUSBIN; +static int TEST_iBAT; + +static int is_pm8921_sec_charger_using(void) +{ +#if defined(CONFIG_MACH_JAGUAR) + if (system_rev >= 0xD) + return 0; +#elif defined(CONFIG_MACH_M2_ATT) + if (system_rev >= 0x4) + return 0; +#elif defined(CONFIG_MACH_M2_SPR) + if (system_rev >= 0x3) + return 0; +#elif defined(CONFIG_MACH_M2_VZW) + if (system_rev >= 0x9) + return 0; +#elif defined(CONFIG_MACH_M2_SKT) + if (system_rev >= 0x4) + return 0; +#elif defined(CONFIG_MACH_GOGH) + if (system_rev >= 0x1) + return 0; +#elif defined(CONFIG_MACH_INFINITE) + if (system_rev >= 0x1) + return 0; +#elif defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + if (system_rev >= 0x1) + return 0; +#elif defined(CONFIG_MACH_AEGIS2) + if (system_rev >= 0x1) + return 0; +#elif defined(CONFIG_MACH_JASPER) + if (system_rev >= 0x2) + return 0; +#elif defined(CONFIG_MACH_APEXQ) + if (system_rev >= 0x1) + return 0; +#elif defined(CONFIG_MACH_COMANCHE) + if (system_rev >= 0x1) + return 0; +#elif defined(CONFIG_MACH_EXPRESS) + return 0; +#elif defined(CONFIG_MACH_ACCELERATE) + return 0; +#elif defined(CONFIG_MACH_ESPRESSO_VZW) + return 0; +#elif defined(CONFIG_MACH_ESPRESSO_SPR) + return 0; +#elif defined(CONFIG_MACH_ESPRESSO_ATT) + return 0; +#elif defined(CONFIG_MACH_ESPRESSO10_VZW) + return 0; +#elif defined(CONFIG_MACH_ESPRESSO10_SPR) + return 0; +#elif defined(CONFIG_MACH_ESPRESSO10_ATT) + return 0; +#elif defined(CONFIG_MACH_STRETTO) + return 0; +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) + return 0; +#endif + return 1; +} + +static int sec_bat_get_fuelgauge_data(struct pm8921_chg_chip *chip, int type) +{ +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) + struct power_supply *psy = power_supply_get_by_name("fuelgauge"); + union power_supply_propval value; + + if (!psy) { + dev_err(chip->dev, "%s: fail to get fuel gauge ps\n", __func__); + return -ENODEV; + } + + switch (type) { + case FG_T_VCELL: + value.intval = 0; /*vcell */ + psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &value); + break; + case FG_T_SOC: + value.intval = 0; /*normal soc */ + psy->get_property(psy, POWER_SUPPLY_PROP_CAPACITY, &value); + break; + case FG_T_PSOC: + value.intval = 1; /*raw soc */ + psy->get_property(psy, POWER_SUPPLY_PROP_CAPACITY, &value); + break; + case FG_T_RCOMP: + value.intval = 2; /*rcomp */ + psy->get_property(psy, POWER_SUPPLY_PROP_CAPACITY, &value); + break; + case FG_T_FSOC: + value.intval = 3; /*full soc */ + psy->get_property(psy, POWER_SUPPLY_PROP_CAPACITY, &value); + break; + default: + return -ENODEV; + } + + return value.intval; + +#else + return -ENODEV; +#endif +} + +static int sec_bat_set_fuelgauge_data(struct pm8921_chg_chip *chip, int type) +{ +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) + struct power_supply *psy = power_supply_get_by_name("fuelgauge"); + union power_supply_propval value; + + if (!psy) { + dev_err(chip->dev, "%s: fail to get fuel gauge ps\n", __func__); + return -ENODEV; + } + switch (type) { + case FG_RESET: + psy->set_property(psy, + POWER_SUPPLY_PROP_FUELGAUGE_STATE, &value); + break; + default: + return -ENODEV; + } + return value.intval; +#else + return -ENODEV; +#endif +} + +static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr, + u8 mask, u8 val) +{ + int rc; + u8 reg; + + rc = pm8xxx_readb(chip->dev->parent, addr, ®); + if (rc) { + pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc); + return rc; + } + reg &= ~mask; + reg |= val & mask; + rc = pm8xxx_writeb(chip->dev->parent, addr, reg); + if (rc) { + pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc); + return rc; + } + return 0; +} + +#define CAPTURE_FSM_STATE_CMD 0xC2 +#define READ_BANK_7 0x70 +#define READ_BANK_4 0x40 +static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip) +{ + u8 temp; + int err, ret = 0; + + temp = CAPTURE_FSM_STATE_CMD; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return err; + } + + temp = READ_BANK_7; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return err; + } + + err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp); + if (err) { + pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err); + return err; + } + /* get the lower 4 bits */ + ret = temp & 0xF; + + temp = READ_BANK_4; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return err; + } + + err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp); + if (err) { + pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err); + return err; + } + /* get the upper 1 bit */ + ret |= (temp & 0x1) << 4; + return ret; +} + +#define READ_BANK_6 0x60 +static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip) +{ + u8 temp; + int err; + + temp = READ_BANK_6; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return err; + } + + err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp); + if (err) { + pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err); + return err; + } + + /* return the lower 4 bits */ + return temp & CHG_ALL_LOOPS; +} + +#define CHG_USB_SUSPEND_BIT BIT(2) +static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable) +{ + return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT, + enable ? CHG_USB_SUSPEND_BIT : 0); +} + +#define CHG_EN_BIT BIT(7) +static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable) +{ + return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT, + enable ? CHG_EN_BIT : 0); +} + +#define CHG_FAILED_CLEAR BIT(0) +#define ATC_FAILED_CLEAR BIT(1) +static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear) +{ + int rc; + + rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR, + clear ? ATC_FAILED_CLEAR : 0); + rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR, + clear ? CHG_FAILED_CLEAR : 0); + return rc; +} + +#define CHG_CHARGE_DIS_BIT BIT(1) +static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable) +{ + return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT, + disable ? CHG_CHARGE_DIS_BIT : 0); +} + +#ifdef QUALCOMM_POWERSUPPLY_PROPERTY +static bool pm_is_chg_charge_dis_bit_set(struct pm8921_chg_chip *chip) +{ + u8 temp = 0; + int rc; + + rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp); + if (rc < 0) + pr_err("%s: pm8xxx_readb failed!(%d)\n", __func__, rc); + + return !!(temp & CHG_CHARGE_DIS_BIT); +} +#endif + +#define PM8921_CHG_V_MIN_MV 3240 +#define PM8921_CHG_V_STEP_MV 20 +#define PM8921_CHG_VDDMAX_MAX 4500 +#define PM8921_CHG_VDDMAX_MIN 3400 +#define PM8921_CHG_V_MASK 0x7F +static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage) +{ + u8 temp; + + if (voltage < PM8921_CHG_VDDMAX_MIN + || voltage > PM8921_CHG_VDDMAX_MAX) { + pr_err("bad mV=%d asked to set\n", voltage); + return -EINVAL; + } + temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV; + pr_debug("voltage=%d setting %02x\n", voltage, temp); + return pm_chg_masked_write(chip, CHG_VDD_MAX, PM8921_CHG_V_MASK, temp); +} + +static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage) +{ + u8 temp; + int rc; + + rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp); + if (rc) { + pr_err("rc = %d while reading vdd max\n", rc); + *voltage = 0; + return rc; + } + temp &= PM8921_CHG_V_MASK; + *voltage = (int)temp * PM8921_CHG_V_STEP_MV + PM8921_CHG_V_MIN_MV; + return 0; +} + +#define PM8921_CHG_VDDSAFE_MIN 3400 +#define PM8921_CHG_VDDSAFE_MAX 4500 +static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage) +{ + u8 temp; + + if (voltage < PM8921_CHG_VDDSAFE_MIN + || voltage > PM8921_CHG_VDDSAFE_MAX) { + pr_err("bad mV=%d asked to set\n", voltage); + return -EINVAL; + } + temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV; + pr_debug("voltage=%d setting %02x\n", voltage, temp); + return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp); +} + +#define PM8921_CHG_VBATDET_MIN 3240 +#define PM8921_CHG_VBATDET_MAX 5780 +static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage) +{ + u8 temp; + + if (voltage < PM8921_CHG_VBATDET_MIN + || voltage > PM8921_CHG_VBATDET_MAX) { + pr_err("bad mV=%d asked to set\n", voltage); + return -EINVAL; + } + temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV; + pr_debug("voltage=%d setting %02x\n", voltage, temp); + return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp); +} + +#define PM8921_CHG_VINMIN_MIN_MV 3800 +#define PM8921_CHG_VINMIN_STEP_MV 100 +#define PM8921_CHG_VINMIN_USABLE_MAX 6500 +#define PM8921_CHG_VINMIN_USABLE_MIN 4300 +#define PM8921_CHG_VINMIN_MASK 0x1F +static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage) +{ + u8 temp; + + if (voltage < PM8921_CHG_VINMIN_USABLE_MIN + || voltage > PM8921_CHG_VINMIN_USABLE_MAX) { + pr_err("bad mV=%d asked to set\n", voltage); + return -EINVAL; + } + temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV; + pr_debug("voltage=%d setting %02x\n", voltage, temp); + return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK, + temp); +} + +static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip) +{ + u8 temp; + int rc, voltage_mv; + + rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp); + temp &= PM8921_CHG_VINMIN_MASK; + + voltage_mv = PM8921_CHG_VINMIN_MIN_MV + + (int)temp * PM8921_CHG_VINMIN_STEP_MV; + + return voltage_mv; +} + +#define PM8921_CHG_IBATMAX_MIN 325 +#define PM8921_CHG_IBATMAX_MAX 2000 +#define PM8921_CHG_I_MIN_MA 225 +#define PM8921_CHG_I_STEP_MA 50 +#define PM8921_CHG_I_MASK 0x3F +static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current) +{ + u8 temp; + + if (chg_current < PM8921_CHG_IBATMAX_MIN + || chg_current > PM8921_CHG_IBATMAX_MAX) { + pr_err("bad mA=%d asked to set\n", chg_current); + return -EINVAL; + } + temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA; + return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp); +} + +static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *chg_current) +{ + u8 temp; + int rc; + + if (TEST_iBAT != 0) + return TEST_iBAT; + + rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp); + if (rc) { + pr_err("rc = %d while reading ibat max\n", rc); + *chg_current = 0; + return rc; + } + temp &= PM8921_CHG_I_MASK; + *chg_current = (int)temp * PM8921_CHG_I_STEP_MA + PM8921_CHG_I_MIN_MA; + return 0; +} + +#define PM8921_CHG_IBATSAFE_MIN 225 +#define PM8921_CHG_IBATSAFE_MAX 3375 +static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current) +{ + u8 temp; + + if (chg_current < PM8921_CHG_IBATSAFE_MIN + || chg_current > PM8921_CHG_IBATSAFE_MAX) { + pr_err("bad mA=%d asked to set\n", chg_current); + return -EINVAL; + } + temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA; + return pm_chg_masked_write(chip, CHG_IBAT_SAFE, + PM8921_CHG_I_MASK, temp); +} + +#define PM8921_CHG_ITERM_MIN_MA 50 +#define PM8921_CHG_ITERM_MAX_MA 200 +#define PM8921_CHG_ITERM_STEP_MA 10 +#define PM8921_CHG_ITERM_MASK 0xF +static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current) +{ + u8 temp; + + if (chg_current < PM8921_CHG_ITERM_MIN_MA + || chg_current > PM8921_CHG_ITERM_MAX_MA) { + pr_err("bad mA=%d asked to set\n", chg_current); + return -EINVAL; + } + + temp = (chg_current - PM8921_CHG_ITERM_MIN_MA) + / PM8921_CHG_ITERM_STEP_MA; + return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK, + temp); +} + +static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current) +{ + u8 temp; + int rc; + + rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp); + if (rc) { + pr_err("err=%d reading CHG_ITEM\n", rc); + *chg_current = 0; + return rc; + } + temp &= PM8921_CHG_ITERM_MASK; + *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA + + PM8921_CHG_ITERM_MIN_MA; + return 0; +} + +struct usb_ma_limit_entry { + int usb_ma; + u8 chg_iusb_value; +}; + +static struct usb_ma_limit_entry usb_ma_table[] = { + {100, 0}, + {500, 1}, + {700, 2}, + {850, 3}, + {900, 4}, + {1100, 5}, + {1300, 6}, + {1500, 7}, +}; + +#define PM8921_CHG_IUSB_MASK 0x1C +#define PM8921_CHG_IUSB_MAX 7 +#define PM8921_CHG_IUSB_MIN 0 +static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val) +{ + u8 temp; + + if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) { + pr_err("bad mA=%d asked to set\n", reg_val); + return -EINVAL; + } + temp = reg_val << 2; + return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK, + temp); +} + +static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *reg_val) +{ + u8 temp; + int rc; + + if (TEST_iUSBIN != 0) + return TEST_iUSBIN; + + rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp); + if (rc) { + pr_err("rc = %d while reading iusb max\n", rc); + *reg_val = 0; + return rc; + } + + temp &= PM8921_CHG_IUSB_MASK; + temp = temp >> 2; + *reg_val = usb_ma_table[(int)temp].usb_ma; + return 0; +} + +#define PM8921_CHG_WD_MASK 0x1F +static int pm_chg_disable_wd(struct pm8921_chg_chip *chip) +{ + /* writing 0 to the wd timer disables it */ + return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0); +} + +#define PM8921_CHG_TCHG_MASK 0x7F +#define PM8921_CHG_TCHG_MIN 4 +#define PM8921_CHG_TCHG_MAX 512 +#define PM8921_CHG_TCHG_STEP 4 +static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes) +{ + u8 temp; + + if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) { + pr_err("bad max minutes =%d asked to set\n", minutes); + return -EINVAL; + } + + temp = (minutes - 1)/PM8921_CHG_TCHG_STEP; + return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK, + temp); +} + +#define PM8921_CHG_TTRKL_MASK 0x1F +#define PM8921_CHG_TTRKL_MIN 1 +#define PM8921_CHG_TTRKL_MAX 64 +static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes) +{ + u8 temp; + + if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) { + pr_err("bad max minutes =%d asked to set\n", minutes); + return -EINVAL; + } + + temp = minutes - 1; + return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK, + temp); +} + +#define PM8921_CHG_VTRKL_MIN_MV 2050 +#define PM8921_CHG_VTRKL_MAX_MV 2800 +#define PM8921_CHG_VTRKL_STEP_MV 50 +#define PM8921_CHG_VTRKL_SHIFT 4 +#define PM8921_CHG_VTRKL_MASK 0xF0 +static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts) +{ + u8 temp; + + if (millivolts < PM8921_CHG_VTRKL_MIN_MV + || millivolts > PM8921_CHG_VTRKL_MAX_MV) { + pr_err("bad voltage = %dmV asked to set\n", millivolts); + return -EINVAL; + } + + temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV; + temp = temp << PM8921_CHG_VTRKL_SHIFT; + return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK, + temp); +} + +#define PM8921_CHG_VWEAK_MIN_MV 2100 +#define PM8921_CHG_VWEAK_MAX_MV 3600 +#define PM8921_CHG_VWEAK_STEP_MV 100 +#define PM8921_CHG_VWEAK_MASK 0x0F +static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts) +{ + u8 temp; + + if (millivolts < PM8921_CHG_VWEAK_MIN_MV + || millivolts > PM8921_CHG_VWEAK_MAX_MV) { + pr_err("bad voltage = %dmV asked to set\n", millivolts); + return -EINVAL; + } + + temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV; + return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK, + temp); +} + +#define PM8921_CHG_ITRKL_MIN_MA 50 +#define PM8921_CHG_ITRKL_MAX_MA 200 +#define PM8921_CHG_ITRKL_MASK 0x0F +#define PM8921_CHG_ITRKL_STEP_MA 10 +static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps) +{ + u8 temp; + + if (milliamps < PM8921_CHG_ITRKL_MIN_MA + || milliamps > PM8921_CHG_ITRKL_MAX_MA) { + pr_err("bad current = %dmA asked to set\n", milliamps); + return -EINVAL; + } + + temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA; + + return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK, + temp); +} + +#define PM8921_CHG_IWEAK_MIN_MA 325 +#define PM8921_CHG_IWEAK_MAX_MA 525 +#define PM8921_CHG_IWEAK_SHIFT 7 +#define PM8921_CHG_IWEAK_MASK 0x80 +static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps) +{ + u8 temp; + + if (milliamps < PM8921_CHG_IWEAK_MIN_MA + || milliamps > PM8921_CHG_IWEAK_MAX_MA) { + pr_err("bad current = %dmA asked to set\n", milliamps); + return -EINVAL; + } + + if (milliamps < PM8921_CHG_IWEAK_MAX_MA) + temp = 0; + else + temp = 1; + + temp = temp << PM8921_CHG_IWEAK_SHIFT; + return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK, + temp); +} + +#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1) +#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1 +#ifdef QUALCOMM_POWERSUPPLY_PROPERTY +static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip, + enum pm8921_chg_cold_thr cold_thr) +{ + u8 temp; + + temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT; + temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD; + return pm_chg_masked_write(chip, CHG_CNTRL_2, + PM8921_CHG_BATT_TEMP_THR_COLD, + temp); +} +#endif +#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0) +#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0 +#ifdef QUALCOMM_TEMPERATURE_CONTROL +static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip, + enum pm8921_chg_hot_thr hot_thr) +{ + u8 temp; + + temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT; + temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT; + return pm_chg_masked_write(chip, CHG_CNTRL_2, + PM8921_CHG_BATT_TEMP_THR_HOT, + temp); +} +#endif +static int64_t read_battery_id(struct pm8921_chg_chip *chip) +{ + int rc; + struct pm8xxx_adc_chan_result result; + + rc = pm8xxx_adc_read(chip->batt_id_channel, &result); + if (rc) { + pr_err("error reading batt id channel = %d, rc = %d\n", + chip->vbat_channel, rc); + return rc; + } + pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical, + result.measurement); + return result.physical; +} + +static int is_battery_valid(struct pm8921_chg_chip *chip) +{ + int64_t rc; + + if (chip->batt_id_min == 0 && chip->batt_id_max == 0) + return 1; + + rc = read_battery_id(chip); + if (rc < 0) { + pr_err("error reading batt id channel = %d, rc = %lld\n", + chip->vbat_channel, rc); + /* assume battery id is valid when adc error happens */ + return 1; + } + + if (rc < chip->batt_id_min || rc > chip->batt_id_max) { + pr_err("batt_id phy =%lld is not valid\n", rc); + return 0; + } + return 1; +} + +static void check_battery_valid(struct pm8921_chg_chip *chip) +{ + if (is_battery_valid(chip) == 0) { + pr_err("batt_id not valid, disabling charging\n"); + chip->batt_present = 0; + pm_chg_auto_enable(chip, 0); + pm_chg_usb_suspend_enable(chip, 1); + } else { + chip->batt_present = 1; + /*pm_chg_auto_enable(chip, !charging_disabled);*/ + } +} + +static void battery_id_valid(struct work_struct *work) +{ + struct pm8921_chg_chip *chip = container_of(work, + struct pm8921_chg_chip, battery_id_valid_work); + + check_battery_valid(chip); +} + +static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt) +{ + if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) { + dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]); + enable_irq(chip->pmic_chg_irq[interrupt]); + } +} + +static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt) +{ + if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) { + dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]); + disable_irq_nosync(chip->pmic_chg_irq[interrupt]); + } +} + +static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt) +{ + return test_bit(interrupt, chip->enabled_irqs); +} + +static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id) +{ + return pm8xxx_read_irq_stat(chip->dev->parent, + chip->pmic_chg_irq[irq_id]); +} + +/* Treat OverVoltage/UnderVoltage as source missing */ +static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip) +{ + return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ); +} + +/* Treat OverVoltage/UnderVoltage as source missing */ +static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip) +{ + return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ); +} + +static bool is_ext_charging(struct pm8921_chg_chip *chip) +{ + union power_supply_propval ret = {0,}; + + if (!chip->ext_psy) + return false; + if (chip->ext_psy->get_property(chip->ext_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &ret)) + return false; + if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE) + return ret.intval; + + return false; +} + +static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip) +{ + union power_supply_propval ret = {0,}; + + if (!chip->ext_psy) + return false; + if (chip->ext_psy->get_property(chip->ext_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &ret)) + return false; + if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE) + return true; + + return false; +} + +static int is_battery_charging(int fsm_state) +{ + if (is_ext_charging(the_chip)) + return 1; + + switch (fsm_state) { + case FSM_STATE_ATC_2A: + case FSM_STATE_ATC_2B: + case FSM_STATE_ON_CHG_AND_BAT_6: + case FSM_STATE_FAST_CHG_7: + case FSM_STATE_TRKL_CHG_8: + return 1; + } + return 0; +} +#if 0 +static void bms_notify(struct work_struct *work) +{ + struct bms_notify *n = container_of(work, struct bms_notify, work); + + if (n->is_charging) + pm8921_bms_charging_began(); + else{ + pm8921_bms_charging_end(n->is_battery_full); + n->is_battery_full = 0; + } +} +#endif +static void bms_notify_check(struct pm8921_chg_chip *chip) +{ + int fsm_state, new_is_charging; + + fsm_state = pm_chg_get_fsm_state(chip); + new_is_charging = is_battery_charging(fsm_state); + + if (chip->bms_notify.is_charging ^ new_is_charging) { + chip->bms_notify.is_charging = new_is_charging; + schedule_work(&(chip->bms_notify.work)); + } +} + +static enum power_supply_property pm_power_props[] = { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, +}; + +static char *pm_power_supplied_to[] = { + "battery", +}; + +static int pm_power_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct pm8921_chg_chip *chip; + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + case POWER_SUPPLY_PROP_ONLINE: +#ifdef QUALCOMM_POWERSUPPLY_PROPERTY + if (psy->type == POWER_SUPPLY_TYPE_USB || + psy->type == POWER_SUPPLY_TYPE_USB_DCP || + psy->type == POWER_SUPPLY_TYPE_USB_CDP || + psy->type == POWER_SUPPLY_TYPE_USB_ACA) { + chip = container_of(psy, struct pm8921_chg_chip, + usb_psy); + if (pm_is_chg_charge_dis_bit_set(chip)) + val->intval = 0; + else + val->intval = is_usb_chg_plugged_in(chip); + } + break; +#else + if (psy->type == POWER_SUPPLY_TYPE_MAINS) { + chip = container_of(psy, struct pm8921_chg_chip, + ac_psy); + if (chip->charging_status == + POWER_SUPPLY_STATUS_DISCHARGING && + chip->cable_type != CABLE_TYPE_NONE) { + val->intval = CABLE_TYPE_NONE; + } else { + val->intval = + ((chip->cable_type == CABLE_TYPE_AC) || + (chip->cable_type == CABLE_TYPE_MISC) ? 1 : 0); + } + } + if (psy->type == POWER_SUPPLY_TYPE_USB || + psy->type == POWER_SUPPLY_TYPE_USB_DCP || + psy->type == POWER_SUPPLY_TYPE_USB_CDP || + psy->type == POWER_SUPPLY_TYPE_USB_ACA) { + chip = container_of(psy, struct pm8921_chg_chip, + usb_psy); + if (chip->charging_status == + POWER_SUPPLY_STATUS_DISCHARGING && + chip->cable_type != CABLE_TYPE_NONE) { + val->intval = CABLE_TYPE_NONE; + } else { + val->intval = (chip->cable_type == + CABLE_TYPE_USB ? 1 : 0); + } + } + break; +#endif + default: + return -EINVAL; + } + return 0; +} + +static enum power_supply_property msm_batt_power_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_ENERGY_FULL, +}; + +static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip) +{ + int rc; +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) + rc = sec_bat_get_fuelgauge_data(chip, FG_T_VCELL); + pr_debug("MAX17042 : mvolts= %d\n", rc); + return rc; +#else + struct pm8xxx_adc_chan_result result; + + rc = pm8xxx_adc_read(chip->vbat_channel, &result); + if (rc) { + pr_err("error reading adc channel = %d, rc = %d\n", + chip->vbat_channel, rc); + return rc; + } + pr_debug("PM8921 ADC : mvolts phy = %lld meas = 0x%llx\n", + result.physical, result.measurement); + return (int)result.physical; +#endif +} +#ifndef CONFIG_BATTERY_MAX17040 +static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip) +{ + unsigned int current_voltage_uv = get_prop_battery_uvolts(chip); + unsigned int current_voltage_mv = current_voltage_uv / 1000; + unsigned int low_voltage = chip->min_voltage_mv; + unsigned int high_voltage = chip->max_voltage_mv; + + if (current_voltage_mv <= low_voltage) + return 0; + else if (current_voltage_mv >= high_voltage) + return 100; + else + return (current_voltage_mv - low_voltage) * 100 + / (high_voltage - low_voltage); +} +#endif +static int get_prop_batt_capacity(struct pm8921_chg_chip *chip) +{ +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) + chip->batt_soc = sec_bat_get_fuelgauge_data(chip, FG_T_SOC); +#elif defined(CONFIG_PM8921_BMS) + int percent_soc = pm8921_bms_get_percent_charge(); + + if (percent_soc == -ENXIO) + percent_soc = voltage_based_capacity(chip); + + chip->batt_soc = percent_soc; +#endif + if (chip->batt_soc <= 10) + pr_warn("low battery charge = %d%%\n", chip->batt_soc); + + return chip->batt_soc; +} + +#define AVG_CNT 15 +static int get_prop_batt_current(struct pm8921_chg_chip *chip) +{ + int result_ua, rc; + int data[AVG_CNT+2]; + int min[2] = {0, 0}; + int max[2] = {0, 0}; + int i, sum = 0; + +#if defined(CONFIG_PM8921_BMS) + rc = pm8921_bms_get_battery_current(&result_ua); + if (rc == -ENXIO) { + pr_err("unable to get bms current rc = %d\n", rc); + rc = pm8xxx_ccadc_get_battery_current(&result_ua); + } + + if (rc) { + pr_err("unable to get ccadc current rc = %d\n", rc); + return rc; + } else { + pr_info("BMS bat current rc = %d\n", result_ua); + return result_ua; + } + +#elif defined(CONFIG_PM8XXX_CCADC) + for (i = 0; i < (AVG_CNT+2); i++) { + rc = pm8xxx_ccadc_get_battery_current(&result_ua); + if (rc) { + pr_err("ccadc unable to get batt curr rc = %d\n", rc); + return rc; + } + + if (i == 0) { + min[1] = result_ua; + max[1] = result_ua; + } else { + if (min[1] > result_ua) { + min[0] = i; + min[1] = result_ua; + } + if (max[1] < result_ua) { + max[0] = i; + max[1] = result_ua; + } + } + data[i] = result_ua; + pr_debug("data[%d] = %d, min[%d] = %d max[%d] = %d\n", + i, data[i], min[0], min[1], max[0], max[1]); + } + for (i = 0; i < AVG_CNT; i++) { + if (i != min[0] && i != max[0]) + sum = sum + data[i]; + } + pr_debug("ccadc sum = %d\n", sum); + result_ua = sum / AVG_CNT; + pr_debug("CCADC batt current rc = %d\n", result_ua); +#endif + return result_ua; +} + +static int get_prop_batt_fcc(struct pm8921_chg_chip *chip) +{ +#if defined(CONFIG_PM8921_BMS) + int rc; + + rc = pm8921_bms_get_fcc(); + if (rc < 0) + pr_err("unable to get batt fcc rc = %d\n", rc); + return rc; +#else + return -ENXIO; +#endif +} + +static int get_prop_batt_health(struct pm8921_chg_chip *chip) +{ + int temp; + + temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ); + if (temp) + return POWER_SUPPLY_HEALTH_OVERHEAT; + + temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ); + if (temp) + return POWER_SUPPLY_HEALTH_COLD; + + return POWER_SUPPLY_HEALTH_GOOD; +} + +static int get_prop_batt_present(struct pm8921_chg_chip *chip) +{ + return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ); +} + +static int get_prop_charge_type(struct pm8921_chg_chip *chip) +{ + int temp; + + if (!get_prop_batt_present(chip)) + return POWER_SUPPLY_CHARGE_TYPE_NONE; + + if (is_ext_trickle_charging(chip)) + return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + + if (is_ext_charging(chip)) + return POWER_SUPPLY_CHARGE_TYPE_FAST; + + temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ); + if (temp) + return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + + temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ); + if (temp) + return POWER_SUPPLY_CHARGE_TYPE_FAST; + + return POWER_SUPPLY_CHARGE_TYPE_NONE; +} + +static int get_prop_batt_status(struct pm8921_chg_chip *chip) +{ + int batt_state = POWER_SUPPLY_STATUS_DISCHARGING; + int fsm_state = pm_chg_get_fsm_state(chip); + int i; + + if (chip->ext_psy) { + if (chip->ext_charge_done) + return POWER_SUPPLY_STATUS_FULL; + if (chip->ext_charging) + return POWER_SUPPLY_STATUS_CHARGING; + } + + for (i = 0; i < ARRAY_SIZE(map); i++) + if (map[i].fsm_state == fsm_state) + batt_state = map[i].batt_state; + + if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) { + if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ) + || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ) + || pm_chg_get_rt_status(chip, CHGHOT_IRQ) + || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ)) + pr_info("batt_in : %d, temp_ok : %d, hot_irq :%d\n", + pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ), + pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ), + pm_chg_get_rt_status(chip, CHGHOT_IRQ)); + batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING; + } + chip->charging_status = batt_state; + return batt_state; +} + +static int get_prop_batt_temp(struct pm8921_chg_chip *chip) +{ + int rc; + int i, array_size, data, temp = 0; + struct pm8xxx_adc_chan_result result; + + rc = pm8xxx_adc_mpp_config_read(TEMP_GPIO, TEMP_ADC_CHNNEL, &result); + if (rc) { + pr_err("error reading mpp %d, rc = %d\n", TEMP_GPIO, rc); + return rc; + } + data = (int)result.physical / 1000; + + array_size = ARRAY_SIZE(temper_table); + for (i = 0; i < (array_size - 1); i++) { + if (i == 0) { + if (data >= temper_table[0][0]) { + temp = temper_table[0][1]; + break; + } else if (data <= temper_table[array_size-1][0]) { + temp = temper_table[array_size-1][1]; + break; + } + } + + if (temper_table[i][0] > data && temper_table[i+1][0] <= data) { + temp = temper_table[i+1][1] - + (temper_table[i+1][1]-temper_table[i][1]) * + (temper_table[i+1][0] - data)/ + (temper_table[i+1][0]-temper_table[i][0]); + break; + } + } + pr_debug("temp=%d, batt_temp phy = %lld meas = 0x%llx\n", + temp, result.physical, result.measurement); + chip->batt_temp = temp; + chip->batt_temp_adc = (int)result.measurement; + + return chip->batt_temp; +} + +static int pm_batt_power_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip, + batt_psy); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = get_prop_batt_status(chip); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = get_prop_charge_type(chip); + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = get_prop_batt_health(chip); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = get_prop_batt_present(chip); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = chip->max_voltage_mv * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = chip->min_voltage_mv * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = get_prop_battery_uvolts(chip); + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = chip->batt_soc; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = get_prop_batt_current(chip); + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = chip->batt_temp; + break; + case POWER_SUPPLY_PROP_ENERGY_FULL: + val->intval = get_prop_batt_fcc(chip) * 1000; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int pm_batt_power_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip, + batt_psy); + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + /* cable is attached or detached. called by usb switch ic */ + pr_info("cable was changed(%d)\n", val->intval); + switch (val->intval) { + case POWER_SUPPLY_TYPE_BATTERY: + chip->cable_type = CABLE_TYPE_NONE; + break; + case POWER_SUPPLY_TYPE_MAINS: + chip->cable_type = CABLE_TYPE_AC; + break; + case POWER_SUPPLY_TYPE_USB: + chip->cable_type = CABLE_TYPE_USB; + break; + case POWER_SUPPLY_TYPE_MISC: + chip->cable_type = CABLE_TYPE_MISC; + break; + case POWER_SUPPLY_TYPE_CARDOCK: + chip->cable_type = CABLE_TYPE_CARDOCK; + break; + case POWER_SUPPLY_TYPE_UARTOFF: + chip->cable_type = CABLE_TYPE_UARTOFF; + break; + default: + return -EINVAL; + } + handle_cable_insertion_removal(chip); + break; + default: + return -EINVAL; + } + return 0; +} + +static void (*notify_vbus_state_func_ptr)(int); +static int usb_chg_current; +static DEFINE_SPINLOCK(vbus_lock); + +int pm8921_charger_register_vbus_sn(void (*callback)(int)) +{ + pr_info("%p\n", callback); + notify_vbus_state_func_ptr = callback; + return 0; +} +EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn); + +/* this is passed to the hsusb via platform_data msm_otg_pdata */ +void pm8921_charger_unregister_vbus_sn(void (*callback)(int)) +{ + pr_debug("%p\n", callback); + notify_vbus_state_func_ptr = NULL; +} +EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn); + +static void notify_usb_of_the_plugin_event(int plugin) +{ + plugin = !!plugin; + if (notify_vbus_state_func_ptr) { + pr_debug("notifying plugin\n"); + (*notify_vbus_state_func_ptr) (plugin); + } else { + pr_debug("unable to notify plugin\n"); + } +} + +/* assumes vbus_lock is held */ +static void __pm8921_charger_vbus_draw(unsigned int mA) +{ + int i, rc; + pr_info("%d mA\n", mA); + + if (mA > 0 && mA <= 2) { + usb_chg_current = 0; + rc = pm_chg_iusbmax_set(the_chip, + usb_ma_table[0].chg_iusb_value); + if (rc) { + pr_err("unable to set iusb to %d rc = %d\n", + usb_ma_table[0].chg_iusb_value, rc); + } + rc = pm_chg_usb_suspend_enable(the_chip, 1); + if (rc) + pr_err("fail to set suspend bit rc=%d\n", rc); + } else { + rc = pm_chg_usb_suspend_enable(the_chip, 0); + if (rc) + pr_err("fail to reset suspend bit rc=%d\n", rc); + for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) { + if (usb_ma_table[i].usb_ma <= mA) + break; + } + if (i < 0) + i = 0; + rc = pm_chg_iusbmax_set(the_chip, + usb_ma_table[i].chg_iusb_value); + if (rc) { + pr_err("unable to set iusb to %d rc = %d\n", + usb_ma_table[i].chg_iusb_value, rc); + } + } +} + +/* USB calls these to tell us how much max usb current the system can draw */ +void pm8921_charger_vbus_draw(unsigned int mA) +{ + unsigned long flags; + + pr_info("Enter charge=%d\n", mA); + spin_lock_irqsave(&vbus_lock, flags); + if (the_chip) { + __pm8921_charger_vbus_draw(mA); + } else { + /* + * called before pmic initialized, + * save this value and use it at probe + */ + usb_chg_current = mA; + pr_info("not initialized the_chip, usb_chg_current=%d\n", + usb_chg_current); + } + spin_unlock_irqrestore(&vbus_lock, flags); +} +EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw); + +int pm8921_charger_enable(bool enable) +{ + int rc; + pr_info("[CHG] %s\n", __func__); + + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + enable = !!enable; + rc = pm_chg_auto_enable(the_chip, enable); + if (rc) + pr_err("Failed rc=%d\n", rc); + return rc; +} +EXPORT_SYMBOL(pm8921_charger_enable); + +int pm8921_is_usb_chg_plugged_in(void) +{ + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + return is_usb_chg_plugged_in(the_chip); +} +EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in); + +int pm8921_is_dc_chg_plugged_in(void) +{ + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + return is_dc_chg_plugged_in(the_chip); +} +EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in); + +int pm8921_is_battery_present(void) +{ + pr_info("[CHG] %s\n", __func__); + + + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + return get_prop_batt_present(the_chip); +} +EXPORT_SYMBOL(pm8921_is_battery_present); + +/* + * Disabling the charge current limit causes current + * current limits to have no monitoring. An adequate charger + * capable of supplying high current while sustaining VIN_MIN + * is required if the limiting is disabled. + */ +int pm8921_disable_input_current_limit(bool disable) +{ + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + if (disable) { + pr_warn("Disabling input current limit!\n"); + + return pm8xxx_writeb(the_chip->dev->parent, + CHG_BUCK_CTRL_TEST3, 0xF2); + } + return 0; +} +EXPORT_SYMBOL(pm8921_disable_input_current_limit); + +int pm8921_set_max_battery_charge_current(int ma) +{ + pr_info("charging current = %dmA\n", ma); + + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + return pm_chg_ibatmax_set(the_chip, ma); +} +EXPORT_SYMBOL(pm8921_set_max_battery_charge_current); + +int pm8921_disable_source_current(bool disable) +{ + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + if (disable) + pr_warn("current drawn from chg=0, battery provides current\n"); + return pm_chg_charge_dis(the_chip, disable); +} +EXPORT_SYMBOL(pm8921_disable_source_current); + +int pm8921_regulate_input_voltage(int voltage) +{ + int rc; + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + rc = pm_chg_vinmin_set(the_chip, voltage); + + if (rc == 0) + the_chip->vin_min = voltage; + + return rc; +} + +#define USB_OV_THRESHOLD_MASK 0x60 +#define USB_OV_THRESHOLD_SHIFT 5 +int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov) +{ + u8 temp; + + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + + if (ov > PM_USB_OV_7V) { + pr_err("limiting to over voltage threshold to 7volts\n"); + ov = PM_USB_OV_7V; + } + + temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT); + + return pm_chg_masked_write(the_chip, USB_OVP_CONTROL, + USB_OV_THRESHOLD_MASK, temp); +} +EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold); + +#define USB_DEBOUNCE_TIME_MASK 0x06 +#define USB_DEBOUNCE_TIME_SHIFT 1 +int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms) +{ + u8 temp; + + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + + if (ms > PM_USB_DEBOUNCE_80P5MS) { + pr_err("limiting debounce to 80.5ms\n"); + ms = PM_USB_DEBOUNCE_80P5MS; + } + + temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT); + + return pm_chg_masked_write(the_chip, USB_OVP_CONTROL, + USB_DEBOUNCE_TIME_MASK, temp); +} +EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis); + +#define USB_OVP_DISABLE_MASK 0x80 +int pm8921_usb_ovp_disable(int disable) +{ + u8 temp = 0; + + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + + if (disable) + temp = USB_OVP_DISABLE_MASK; + + return pm_chg_masked_write(the_chip, USB_OVP_CONTROL, + USB_OVP_DISABLE_MASK, temp); +} + +bool pm8921_is_battery_charging(int *source) +{ + int fsm_state, is_charging, dc_present, usb_present; + pr_info("[CHG] %s\n", __func__); + + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + fsm_state = pm_chg_get_fsm_state(the_chip); + is_charging = is_battery_charging(fsm_state); + if (is_charging == 0) { + *source = PM8921_CHG_SRC_NONE; + return is_charging; + } + + if (source == NULL) + return is_charging; + + /* the battery is charging, the source is requested, find it */ + dc_present = is_dc_chg_plugged_in(the_chip); + usb_present = is_usb_chg_plugged_in(the_chip); + + if (dc_present && !usb_present) + *source = PM8921_CHG_SRC_DC; + + if (usb_present && !dc_present) + *source = PM8921_CHG_SRC_USB; + + if (usb_present && dc_present) + /* + * The system always chooses dc for charging since it has + * higher priority. + */ + *source = PM8921_CHG_SRC_DC; + + return is_charging; +} +EXPORT_SYMBOL(pm8921_is_battery_charging); + +int pm8921_batt_temperature(void) +{ + if (!the_chip) { + pr_err("called before init\n"); + return -EINVAL; + } + return get_prop_batt_temp(the_chip); +} + +static void handle_cable_insertion_removal(struct pm8921_chg_chip *chip) +{ + int usb_present = 0; + pr_info("batt_present = %d\n", chip->batt_present); + + switch (chip->cable_type) { + case CABLE_TYPE_NONE: + usb_present = 0; + chip->charging_enabled = 0; + pm8921_charger_vbus_draw(VUBS_IN_CURR_NONE); + break; + case CABLE_TYPE_USB: + if (chip->batt_present) { + usb_present = 1; + chip->charging_enabled = 1; + pm8921_charger_vbus_draw(VBUS_IN_CURR_USB); + pm8921_set_max_battery_charge_current(BATT_IN_CURR_USB); + } + break; + case CABLE_TYPE_AC: + case CABLE_TYPE_MISC: + if (chip->batt_present) { + usb_present = 1; + chip->charging_enabled = 1; + if (TEST_iUSBIN != 0 || TEST_iBAT != 0) { + pm8921_charger_vbus_draw(TEST_iUSBIN); + pm8921_set_max_battery_charge_current( + TEST_iBAT); + } else { + pm8921_charger_vbus_draw(VBUS_IN_CURR_TA); + pm8921_set_max_battery_charge_current( + BATT_IN_CURR_TA); + } + } + break; + default: + break; + } + + if (chip->usb_present ^ usb_present) { + chip->usb_present = usb_present; + power_supply_changed(&chip->usb_psy); + power_supply_changed(&chip->batt_psy); + } +} + +static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip) +{ + int usb_present, cabletype = 0; + + usb_present = is_usb_chg_plugged_in(chip); + cabletype = chip->get_cable_type(); + notify_usb_of_the_plugin_event(usb_present); + + if ((cabletype != CABLE_TYPE_AC) && (cabletype != CABLE_TYPE_USB) + && (cabletype != CABLE_TYPE_CARDOCK)) { + if (usb_present) { + pr_info("jig 5v inserted\n"); + chip->cable_type = CABLE_TYPE_MISC; + handle_cable_insertion_removal(chip); + } else { + pr_info("jig 5v removed\n"); + chip->cable_type = CABLE_TYPE_NONE; + handle_cable_insertion_removal(chip); + } + } + +#if defined(CONFIG_PM8921_BMS) + bms_notify_check(chip); +#endif +} + +static void handle_stop_ext_chg(struct pm8921_chg_chip *chip) +{ + if (!chip->ext_psy) { + pr_debug("external charger not registered.\n"); + return; + } + + if (!chip->ext_charging) { + pr_debug("already not charging.\n"); + return; + } + + power_supply_set_charge_type(chip->ext_psy, + POWER_SUPPLY_CHARGE_TYPE_NONE); + pm8921_disable_source_current(false); /* release BATFET */ + chip->ext_charging = false; + chip->ext_charge_done = false; + bms_notify_check(chip); +} + +static void handle_start_ext_chg(struct pm8921_chg_chip *chip) +{ + int dc_present; + int batt_present; + int batt_temp_ok; + int vbat_ov; + unsigned long delay = + round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS)); + + if (!chip->ext_psy) { + pr_debug("external charger not registered.\n"); + return; + } + + if (chip->ext_charging) { + pr_debug("already charging.\n"); + return; + } + + dc_present = is_dc_chg_plugged_in(the_chip); + batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ); + batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ); + + if (!dc_present) { + pr_warn("%s. dc not present.\n", __func__); + return; + } + if (!batt_present) { + pr_warn("%s. battery not present.\n", __func__); + return; + } + if (!batt_temp_ok) { + pr_warn("%s. battery temperature not ok.\n", __func__); + return; + } + pm8921_disable_source_current(true); /* Force BATFET=ON */ + vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ); + if (vbat_ov) { + pr_warn("%s. battery over voltage.\n", __func__); + return; + } + + power_supply_set_charge_type(chip->ext_psy, + POWER_SUPPLY_CHARGE_TYPE_FAST); + chip->ext_charging = true; + chip->ext_charge_done = false; + bms_notify_check(chip); + /* Start BMS */ + schedule_delayed_work(&chip->eoc_work, delay); + wake_lock(&chip->eoc_wake_lock); +} + +#define WRITE_BANK_4 0xC0 +static void unplug_wrkarnd_restore_worker(struct work_struct *work) +{ + u8 temp; + int rc; + struct delayed_work *dwork = to_delayed_work(work); + struct pm8921_chg_chip *chip = container_of(dwork, + struct pm8921_chg_chip, + unplug_wrkarnd_restore_work); + + pr_debug("restoring vin_min to %d mV\n", chip->vin_min); + rc = pm_chg_vinmin_set(the_chip, chip->vin_min); + + temp = WRITE_BANK_4 | 0xA; + rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp); + if (rc) { + pr_err("Error %d writing %d to addr %d\n", rc, + temp, CHG_BUCK_CTRL_TEST3); + } + wake_unlock(&chip->unplug_wrkarnd_restore_wake_lock); +} +static irqreturn_t usbin_valid_irq_handler(int irq, void *data) +{ + pr_info("USB valid irq\n"); + handle_usb_insertion_removal(data); + return IRQ_HANDLED; +} + +static irqreturn_t usbin_ov_irq_handler(int irq, void *data) +{ + pr_err("USB OverVoltage\n"); + return IRQ_HANDLED; +} + +static irqreturn_t batt_inserted_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + int status; + pr_info("Battery inserted irq\n"); + + status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ); + schedule_work(&chip->battery_id_valid_work); + handle_start_ext_chg(chip); + pr_debug("battery present=%d", status); + power_supply_changed(&chip->batt_psy); + return IRQ_HANDLED; +} +#if !defined(CONFIG_BATTERY_MAX17040) && \ + !defined(CONFIG_BATTERY_MAX17042) +/* + * this interrupt used to restart charging a battery. + * + * Note: When DC-inserted the VBAT can't go low. + * VPH_PWR is provided by the ext-charger. + * After End-Of-Charging from DC, charging can be resumed only + * if DC is removed and then inserted after the battery was in use. + * Therefore the handle_start_ext_chg() is not called. + */ +static irqreturn_t vbatdet_low_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + int high_transition; + + high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ); + + if (high_transition) { + /* enable auto charging */ + pm_chg_auto_enable(chip, !charging_disabled); + pr_info("batt fell below resume voltage %s\n", + charging_disabled ? "" : "charger enabled"); + } + pr_info("fsm_state=%d\n", pm_chg_get_fsm_state(data)); + + power_supply_changed(&chip->batt_psy); + power_supply_changed(&chip->usb_psy); + + return IRQ_HANDLED; +} +#endif +static irqreturn_t usbin_uv_irq_handler(int irq, void *data) +{ + pr_err("USB UnderVoltage\n"); + return IRQ_HANDLED; +} + +static irqreturn_t vbat_ov_irq_handler(int irq, void *data) +{ + pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data)); + return IRQ_HANDLED; +} + +static irqreturn_t chgwdog_irq_handler(int irq, void *data) +{ + pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data)); + return IRQ_HANDLED; +} + +static irqreturn_t vcp_irq_handler(int irq, void *data) +{ + pr_warning("VCP triggered BATDET forced on\n"); + pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data)); + return IRQ_HANDLED; +} + +static irqreturn_t atcdone_irq_handler(int irq, void *data) +{ + pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data)); + return IRQ_HANDLED; +} + +static irqreturn_t atcfail_irq_handler(int irq, void *data) +{ + pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data)); + return IRQ_HANDLED; +} + +static irqreturn_t chgdone_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + + pr_info("state_changed_to=%d\n", pm_chg_get_fsm_state(data)); + + handle_stop_ext_chg(chip); + + power_supply_changed(&chip->batt_psy); + power_supply_changed(&chip->usb_psy); + + chip->batt_is_full = 1; +#ifdef CONFIG_PM8921_BMS + chip->bms_notify.is_battery_full = 1; + bms_notify_check(chip); +#endif + + return IRQ_HANDLED; +} + +static irqreturn_t chgfail_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + int ret; + + ret = pm_chg_failed_clear(chip, 1); + if (ret) + pr_err("Failed to write CHG_FAILED_CLEAR bit\n"); + + pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n", + get_prop_batt_present(chip), + pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ), + pm_chg_get_fsm_state(data)); + + power_supply_changed(&chip->batt_psy); + power_supply_changed(&chip->usb_psy); + return IRQ_HANDLED; +} + +static irqreturn_t chgstate_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + + pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data)); + power_supply_changed(&chip->batt_psy); + power_supply_changed(&chip->usb_psy); + +#ifdef CONFIG_PM8921_BMS + bms_notify_check(chip); +#endif + return IRQ_HANDLED; +} + +#define VIN_ACTIVE_BIT BIT(0) +#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200 +#define VIN_MIN_INCREASE_MV 100 +static void unplug_check_worker(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct pm8921_chg_chip *chip = container_of(dwork, + struct pm8921_chg_chip, unplug_check_work); + u8 reg_loop; + int ibat, usb_chg_plugged_in; + + usb_chg_plugged_in = is_usb_chg_plugged_in(chip); + if (!usb_chg_plugged_in) { + pr_debug("Stopping Unplug Check Worker since USB is removed" + "reg_loop = %d, fsm = %d ibat = %d\n", + pm_chg_get_regulation_loop(chip), + pm_chg_get_fsm_state(chip), + get_prop_batt_current(chip) + ); + return; + } + reg_loop = pm_chg_get_regulation_loop(chip); + pr_debug("reg_loop=0x%x\n", reg_loop); + + if (reg_loop & VIN_ACTIVE_BIT) { + ibat = get_prop_batt_current(chip); + + pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n", + ibat, pm_chg_get_fsm_state(chip), reg_loop); + if (ibat > 0) { + int err; + u8 temp; + + temp = WRITE_BANK_4 | 0xE; + err = pm8xxx_writeb(chip->dev->parent, + CHG_BUCK_CTRL_TEST3, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, + temp, CHG_BUCK_CTRL_TEST3); + } + + pm_chg_vinmin_set(chip, + chip->vin_min + VIN_MIN_INCREASE_MV); + + wake_lock(&chip->unplug_wrkarnd_restore_wake_lock); + schedule_delayed_work( + &chip->unplug_wrkarnd_restore_work, + round_jiffies_relative(usecs_to_jiffies + (UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US))); + } + } + + schedule_delayed_work(&chip->unplug_check_work, + round_jiffies_relative(msecs_to_jiffies + (UNPLUG_CHECK_WAIT_PERIOD_MS))); +} + +static irqreturn_t loop_change_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + + pr_debug("fsm_state=%d reg_loop=0x%x\n", + pm_chg_get_fsm_state(data), + pm_chg_get_regulation_loop(data)); + unplug_check_worker(&(chip->unplug_check_work.work)); + return IRQ_HANDLED; +} + +static irqreturn_t fastchg_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + int high_transition; + pr_info("[CHG] %s\n", __func__); + + high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ); + if (high_transition && !delayed_work_pending(&chip->eoc_work)) { + wake_lock(&chip->eoc_wake_lock); + schedule_delayed_work(&chip->eoc_work, + round_jiffies_relative(msecs_to_jiffies + (EOC_CHECK_PERIOD_MS))); + } + power_supply_changed(&chip->batt_psy); +#ifdef CONFIG_PM8921_BMS + bms_notify_check(chip); +#endif + return IRQ_HANDLED; +} + +static irqreturn_t trklchg_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + pr_info("[CHG] %s\n", __func__); + + power_supply_changed(&chip->batt_psy); + return IRQ_HANDLED; +} + +static irqreturn_t batt_removed_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + int status; + pr_info("[CHG] %s\n", __func__); + + status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ); + pr_debug("battery present=%d state=%d", !status, + pm_chg_get_fsm_state(data)); + handle_stop_ext_chg(chip); + power_supply_changed(&chip->batt_psy); + return IRQ_HANDLED; +} + +static irqreturn_t batttemp_hot_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + pr_info("[CHG] %s\n", __func__); + + handle_stop_ext_chg(chip); + power_supply_changed(&chip->batt_psy); + return IRQ_HANDLED; +} + +static irqreturn_t chghot_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + + pr_info("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data)); + power_supply_changed(&chip->batt_psy); + power_supply_changed(&chip->usb_psy); + handle_stop_ext_chg(chip); + return IRQ_HANDLED; +} + +static irqreturn_t batttemp_cold_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + + pr_info("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data)); + handle_stop_ext_chg(chip); + + power_supply_changed(&chip->batt_psy); + power_supply_changed(&chip->usb_psy); + return IRQ_HANDLED; +} + +static irqreturn_t chg_gone_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + + pr_info("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data)); + power_supply_changed(&chip->batt_psy); + power_supply_changed(&chip->usb_psy); + return IRQ_HANDLED; +} +/* + * + * bat_temp_ok_irq_handler - is edge triggered, hence it will + * fire for two cases: + * + * If the interrupt line switches to high temperature is okay + * and thus charging begins. + * If bat_temp_ok is low this means the temperature is now + * too hot or cold, so charging is stopped. + * + */ +static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data) +{ + int bat_temp_ok; + struct pm8921_chg_chip *chip = data; + + bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ); + + pr_debug("batt_temp_ok = %d fsm_state%d\n", + bat_temp_ok, pm_chg_get_fsm_state(data)); + + if (bat_temp_ok) + handle_start_ext_chg(chip); + else + handle_stop_ext_chg(chip); + + power_supply_changed(&chip->batt_psy); + power_supply_changed(&chip->usb_psy); + bms_notify_check(chip); + return IRQ_HANDLED; +} + +static irqreturn_t coarse_det_low_irq_handler(int irq, void *data) +{ + pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data)); + return IRQ_HANDLED; +} + +static irqreturn_t vdd_loop_irq_handler(int irq, void *data) +{ + pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data)); + return IRQ_HANDLED; +} + +static irqreturn_t vreg_ov_irq_handler(int irq, void *data) +{ + pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data)); + return IRQ_HANDLED; +} + +static irqreturn_t vbatdet_irq_handler(int irq, void *data) +{ + pr_info("fsm_state=%d\n", pm_chg_get_fsm_state(data)); + return IRQ_HANDLED; +} + +static irqreturn_t batfet_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + + pr_info("vreg ov\n"); + power_supply_changed(&chip->batt_psy); + return IRQ_HANDLED; +} + +static irqreturn_t dcin_valid_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + int dc_present; + + dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ); + if (chip->ext_psy) + power_supply_set_online(chip->ext_psy, dc_present); + chip->dc_present = dc_present; + if (dc_present) + handle_start_ext_chg(chip); + else + handle_stop_ext_chg(chip); + return IRQ_HANDLED; +} + +static irqreturn_t dcin_ov_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + + handle_stop_ext_chg(chip); + return IRQ_HANDLED; +} + +static irqreturn_t dcin_uv_irq_handler(int irq, void *data) +{ + struct pm8921_chg_chip *chip = data; + + handle_stop_ext_chg(chip); + + return IRQ_HANDLED; +} +static int __pm_batt_external_power_changed_work(struct device *dev, void *data) +{ + struct power_supply *psy = &the_chip->batt_psy; + struct power_supply *epsy = dev_get_drvdata(dev); + int i, dcin_irq; + + /* Only search for external supply if none is registered */ + if (!the_chip->ext_psy) { + dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ]; + for (i = 0; i < epsy->num_supplicants; i++) { + if (!strncmp(epsy->supplied_to[i], psy->name, 7)) { + if (!strncmp(epsy->name, "dc", 2)) { + the_chip->ext_psy = epsy; + dcin_valid_irq_handler(dcin_irq, + the_chip); + } + } + } + } + return 0; +} + +static void pm_batt_external_power_changed(struct power_supply *psy) +{ + /* Only look for an external supply if it hasn't been registered */ + if (!the_chip->ext_psy) + class_for_each_device(power_supply_class, NULL, psy, + __pm_batt_external_power_changed_work); +} + +static int +pm8921_get_register(struct pm8921_chg_chip *chip, int reg, u8 *reg_val) +{ + u8 temp; + int rc; + + rc = pm8xxx_readb(chip->dev->parent, reg, &temp); + if (rc) { + pr_err("rc = %d while reading reg(%d)\n", reg, rc); + *reg_val = 0; + return rc; + } + + *reg_val = temp; + return 0; +} + +static void pm8921_read_registers(struct pm8921_chg_chip *chip) +{ + struct pm8921_reg *reg = &chip->chg_reg; + struct pm8921_irq *irq = &chip->chg_irq; + /* read register */ + pm8921_get_register(chip, CHG_CNTRL, ®->chg_cntrl); + pm8921_get_register(chip, CHG_CNTRL_2, ®->chg_cntrl_2); + pm8921_get_register(chip, CHG_CNTRL_3, ®->chg_cntrl_3); + pm8921_get_register(chip, PBL_ACCESS1, ®->pbl_access1); + pm8921_get_register(chip, PBL_ACCESS2, ®->pbl_access2); + pm8921_get_register(chip, SYS_CONFIG_1, ®->sys_config_1); + pm8921_get_register(chip, SYS_CONFIG_2, ®->sys_config_2); + pm8921_get_register(chip, CHG_VDD_MAX, ®->chg_vdd_max); + pm8921_get_register(chip, CHG_VDD_SAFE, ®->chg_vdd_safe); + pm8921_get_register(chip, CHG_IBAT_MAX, ®->chg_ibat_max); + pm8921_get_register(chip, CHG_IBAT_SAFE, ®->chg_ibat_safe); + pm8921_get_register(chip, CHG_ITERM, ®->chg_iterm); + + /* read irq */ + irq->usbin_valid = pm_chg_get_rt_status(chip, USBIN_VALID_IRQ); + irq->usbin_ov = pm_chg_get_rt_status(chip, USBIN_OV_IRQ); + irq->usbin_uv = pm_chg_get_rt_status(chip, USBIN_UV_IRQ); + irq->batttemp_hot = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ); + irq->batttemp_cold = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ); + irq->batt_inserted = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ); + irq->trklchg = pm_chg_get_rt_status(chip, TRKLCHG_IRQ); + irq->fastchg = pm_chg_get_rt_status(chip, FASTCHG_IRQ); + irq->batfet = pm_chg_get_rt_status(chip, BATFET_IRQ); + irq->batt_removed = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ); + irq->vcp = pm_chg_get_rt_status(chip, VCP_IRQ); + irq->bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ); + + /* read vcell */ +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) + chip->batt_vcell = sec_bat_get_fuelgauge_data(chip, FG_T_VCELL); +#endif +} + +/** + * update_heartbeat - internal function to update userspace + * per update_time minutes + * + */ +static void update_heartbeat(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct pm8921_chg_chip *chip = container_of(dwork, + struct pm8921_chg_chip, update_heartbeat_work); + + batt_status_update(chip); + pm8921_read_registers(chip); + + power_supply_changed(&chip->batt_psy); + schedule_delayed_work(&chip->update_heartbeat_work, + round_jiffies_relative(msecs_to_jiffies + (chip->update_time))); +} + +enum { + CHG_IN_PROGRESS, + CHG_NOT_IN_PROGRESS, + CHG_FINISHED, +}; +static void batt_status_update(struct pm8921_chg_chip *chip) +{ + chip->batt_temp = get_prop_batt_temp(chip); + chip->batt_curr = get_prop_batt_current(chip) / 1000; + chip->batt_soc = get_prop_batt_capacity(chip); + chip->batt_vcell = get_prop_battery_uvolts(chip)/1000; + + pr_info("curr=%d, soc=%d, vcell=%d\n", + chip->batt_curr, chip->batt_soc, chip->batt_vcell); + + /* recharging */ + if (chip->batt_is_full && + !chip->batt_is_recharging && + chip->batt_vcell < + (chip->max_voltage_mv - chip->resume_voltage_delta)) { + pr_info("recharging start+++\n"); + chip->batt_is_recharging = 1; + pm_chg_auto_enable(chip, 1); + pm_chg_usb_suspend_enable(chip, 0); + } else { + chip->batt_is_recharging = 0; + } +} + +/** + * eoc_worker - internal function to check if battery EOC + * has happened + * + * If all conditions favouring, if the charge current is + * less than the term current for three consecutive times + * an EOC has happened. + * The wakelock is released if there is no need to reshedule + * - this happens when the battery is removed or EOC has + * happened + */ +#define CONSECUTIVE_COUNT 3 +#define VBAT_TOLERANCE_MV 70 +#define CHG_DISABLE_MSLEEP 100 +static int is_charging_finished(struct pm8921_chg_chip *chip) +{ + int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low; + int ichg_meas_ma, iterm_programmed; + int regulation_loop, fast_chg, vcp; + int rc; + static int last_vbat_programmed = -EINVAL; + + if (!is_ext_charging(chip)) { + /* return if the battery is not being fastcharged */ + fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ); + pr_debug("fast_chg = %d\n", fast_chg); + if (fast_chg == 0) + return CHG_NOT_IN_PROGRESS; + + vcp = pm_chg_get_rt_status(chip, VCP_IRQ); + pr_debug("vcp = %d\n", vcp); + if (vcp == 1) + return CHG_IN_PROGRESS; + + vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ); + pr_debug("vbatdet_low = %d\n", vbatdet_low); + if (vbatdet_low == 1) + return CHG_IN_PROGRESS; + + /* reset count if battery is hot/cold */ + rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ); + pr_debug("batt_temp_ok = %d\n", rc); + if (rc == 0) + return CHG_IN_PROGRESS; + + /* reset count if battery voltage is less than vddmax */ + vbat_meas_uv = get_prop_battery_uvolts(chip); + if (vbat_meas_uv < 0) + return CHG_IN_PROGRESS; + vbat_meas_mv = vbat_meas_uv / 1000; + + rc = pm_chg_vddmax_get(chip, &vbat_programmed); + if (rc) { + pr_err("couldnt read vddmax rc = %d\n", rc); + return CHG_IN_PROGRESS; + } + pr_debug("vddmax = %d vbat_meas_mv=%d\n", + vbat_programmed, vbat_meas_mv); + if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV) + return CHG_IN_PROGRESS; + + if (last_vbat_programmed == -EINVAL) + last_vbat_programmed = vbat_programmed; + if (last_vbat_programmed != vbat_programmed) { + /* vddmax changed, reset and check again */ + pr_debug("vddmax = %d last_vdd_max=%d\n", + vbat_programmed, last_vbat_programmed); + last_vbat_programmed = vbat_programmed; + return CHG_IN_PROGRESS; + } + + /* + * TODO if charging from an external charger + * check SOC instead of regulation loop + */ + regulation_loop = pm_chg_get_regulation_loop(chip); + if (regulation_loop < 0) { + pr_err("couldnt read the regulation loop err=%d\n", + regulation_loop); + return CHG_IN_PROGRESS; + } + pr_debug("regulation_loop=%d\n", regulation_loop); + + if (regulation_loop != 0 && regulation_loop != VDD_LOOP) + return CHG_IN_PROGRESS; + } /* !is_ext_charging */ + + /* reset count if battery chg current is more than iterm */ + rc = pm_chg_iterm_get(chip, &iterm_programmed); + if (rc) { + pr_err("couldnt read iterm rc = %d\n", rc); + return CHG_IN_PROGRESS; + } + + ichg_meas_ma = (get_prop_batt_current(chip)) / 1000; + pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n", + iterm_programmed, ichg_meas_ma); + /* + * ichg_meas_ma < 0 means battery is drawing current + * ichg_meas_ma > 0 means battery is providing current + */ + if (ichg_meas_ma > 0) + return CHG_IN_PROGRESS; + + if (ichg_meas_ma * -1 > iterm_programmed) + return CHG_IN_PROGRESS; + + return CHG_FINISHED; +} + +static void eoc_worker(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct pm8921_chg_chip *chip = container_of(dwork, + struct pm8921_chg_chip, eoc_work); + static int count; + int end = is_charging_finished(chip); + + if (end == CHG_NOT_IN_PROGRESS) { + /* enable fastchg irq */ + count = 0; + wake_unlock(&chip->eoc_wake_lock); + return; + } + + if (end == CHG_FINISHED) + count++; + else + count = 0; + + if (count == CONSECUTIVE_COUNT) { + count = 0; + pr_info("End of Charging\n"); + + pm_chg_auto_enable(chip, 0); + + if (is_ext_charging(chip)) + chip->ext_charge_done = true; + + if (chip->is_bat_warm || chip->is_bat_cool) + chip->bms_notify.is_battery_full = 0; + else + chip->bms_notify.is_battery_full = 1; + /* declare end of charging by invoking chgdone interrupt */ + chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip); + wake_unlock(&chip->eoc_wake_lock); + } else { + pr_debug("EOC count = %d\n", count); + schedule_delayed_work(&chip->eoc_work, + round_jiffies_relative(msecs_to_jiffies + (EOC_CHECK_PERIOD_MS))); + } +} + +static void btm_configure_work(struct work_struct *work) +{ + int rc; + + rc = pm8xxx_adc_btm_configure(&btm_config); + if (rc) + pr_err("failed to configure btm rc=%d", rc); +} + +DECLARE_WORK(btm_config_work, btm_configure_work); + +static void set_appropriate_battery_current(struct pm8921_chg_chip *chip) +{ + unsigned int chg_current = chip->max_bat_chg_current; + + if (chip->is_bat_cool) + chg_current = min(chg_current, chip->cool_bat_chg_current); + + if (chip->is_bat_warm) + chg_current = min(chg_current, chip->warm_bat_chg_current); + + if (thermal_mitigation != 0 && chip->thermal_mitigation != 0) + chg_current = min(chg_current, + chip->thermal_mitigation[thermal_mitigation]); + + pm_chg_ibatmax_set(the_chip, chg_current); +} + +#define TEMP_HYSTERISIS_DEGC 2 +#ifdef QUALCOMM_TEMPERATURE_CONTROL +static void battery_cool(bool enter) +{ + pr_debug("enter = %d\n", enter); + if (enter == the_chip->is_bat_cool) + return; + the_chip->is_bat_cool = enter; + if (enter) { + btm_config.low_thr_temp = + the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC; + set_appropriate_battery_current(the_chip); + pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage); + pm_chg_vbatdet_set(the_chip, + the_chip->cool_bat_voltage + - the_chip->resume_voltage_delta); + } else { + btm_config.low_thr_temp = the_chip->cool_temp_dc; + set_appropriate_battery_current(the_chip); + pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv); + pm_chg_vbatdet_set(the_chip, + the_chip->max_voltage_mv + - the_chip->resume_voltage_delta); + } + schedule_work(&btm_config_work); +} + +static void battery_warm(bool enter) +{ + pr_debug("enter = %d\n", enter); + if (enter == the_chip->is_bat_warm) + return; + the_chip->is_bat_warm = enter; + if (enter) { + btm_config.high_thr_temp = + the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC; + set_appropriate_battery_current(the_chip); + pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage); + pm_chg_vbatdet_set(the_chip, + the_chip->warm_bat_voltage + - the_chip->resume_voltage_delta); + } else { + btm_config.high_thr_temp = the_chip->warm_temp_dc; + set_appropriate_battery_current(the_chip); + pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv); + pm_chg_vbatdet_set(the_chip, + the_chip->max_voltage_mv + - the_chip->resume_voltage_delta); + } + schedule_work(&btm_config_work); +} +#endif +#ifdef QUALCOMM_TEMPERATURE_CONTROL +static int configure_btm(struct pm8921_chg_chip *chip) +{ + int rc; + + btm_config.btm_warm_fn = battery_warm; + btm_config.btm_cool_fn = battery_cool; + btm_config.low_thr_temp = chip->cool_temp_dc; + btm_config.high_thr_temp = chip->warm_temp_dc; + btm_config.interval = chip->temp_check_period; + rc = pm8xxx_adc_btm_configure(&btm_config); + if (rc) + pr_err("failed to configure btm rc = %d\n", rc); + rc = pm8xxx_adc_btm_start(); + if (rc) + pr_err("failed to start btm rc = %d\n", rc); + + return rc; +} +#endif +/** + * set_disable_status_param - + * + * Internal function to disable battery charging and also disable drawing + * any current from the source. The device is forced to run on a battery + * after this. + */ +static int set_disable_status_param(const char *val, struct kernel_param *kp) +{ + int ret; + struct pm8921_chg_chip *chip = the_chip; + + ret = param_set_int(val, kp); + if (ret) { + pr_err("error setting value %d\n", ret); + return ret; + } + pr_info("factory set disable param to %d\n", charging_disabled); + if (chip) { + pm_chg_auto_enable(chip, !charging_disabled); + pm_chg_charge_dis(chip, charging_disabled); + } + return 0; +} +module_param_call(disabled, set_disable_status_param, param_get_uint, + &charging_disabled, 0644); + +/** + * set_thermal_mitigation_level - + * + * Internal function to control battery charging current to reduce + * temperature + */ +static int set_therm_mitigation_level(const char *val, struct kernel_param *kp) +{ + int ret; + struct pm8921_chg_chip *chip = the_chip; + + ret = param_set_int(val, kp); + if (ret) { + pr_err("error setting value %d\n", ret); + return ret; + } + + if (!chip) { + pr_err("called before init\n"); + return -EINVAL; + } + + if (!chip->thermal_mitigation) { + pr_err("no thermal mitigation\n"); + return -EINVAL; + } + + if (thermal_mitigation < 0 + || thermal_mitigation >= chip->thermal_levels) { + pr_err("out of bound level selected\n"); + return -EINVAL; + } + + set_appropriate_battery_current(chip); + return ret; +} +module_param_call(thermal_mitigation, set_therm_mitigation_level, + param_get_uint, + &thermal_mitigation, 0644); + +static void free_irqs(struct pm8921_chg_chip *chip) +{ + int i; + + for (i = 0; i < PM_CHG_MAX_INTS; i++) + if (chip->pmic_chg_irq[i]) { + free_irq(chip->pmic_chg_irq[i], chip); + chip->pmic_chg_irq[i] = 0; + } +} + +/* determines the initial present states */ +static void __devinit determine_initial_state(struct pm8921_chg_chip *chip) +{ + unsigned long flags; + + chip->dc_present = !!is_dc_chg_plugged_in(chip); + chip->usb_present = !!is_usb_chg_plugged_in(chip); + + notify_usb_of_the_plugin_event(chip->usb_present); + if (chip->usb_present) { + schedule_delayed_work(&chip->unplug_check_work, + round_jiffies_relative(msecs_to_jiffies + (UNPLUG_CHECK_WAIT_PERIOD_MS))); + } + + pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ); + pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ); + pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ); + pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ); + pm8921_chg_enable_irq(chip, USBIN_OV_IRQ); + pm8921_chg_enable_irq(chip, USBIN_UV_IRQ); + pm8921_chg_enable_irq(chip, DCIN_OV_IRQ); + pm8921_chg_enable_irq(chip, DCIN_UV_IRQ); + pm8921_chg_enable_irq(chip, CHGFAIL_IRQ); + pm8921_chg_enable_irq(chip, FASTCHG_IRQ); + pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ); +#ifdef QUALCOMM_TEMPERATURE_CONTROL + pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ); +#endif + + spin_lock_irqsave(&vbus_lock, flags); + if (usb_chg_current) { + /* reissue a vbus draw call */ + __pm8921_charger_vbus_draw(usb_chg_current); + fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip); + } + spin_unlock_irqrestore(&vbus_lock, flags); + +#ifdef CONFIG_PM8921_BMS + int fsm_state; + fsm_state = pm_chg_get_fsm_state(chip); + pr_info("fsm_state=%d\n", fsm_state); + if (is_battery_charging(fsm_state)) { + chip->bms_notify.is_charging = 1; + pm8921_bms_charging_began(); + } +#endif + + check_battery_valid(chip); + + pr_debug("usb = %d, dc = %d batt = %d\n", + chip->usb_present, + chip->dc_present, + get_prop_batt_present(chip)); +} + +struct pm_chg_irq_init_data { + unsigned int irq_id; + char *name; + unsigned long flags; + irqreturn_t (*handler)(int, void *); +}; + +#define CHG_IRQ(_id, _flags, _handler) \ +{ \ + .irq_id = _id, \ + .name = #_id, \ + .flags = _flags, \ + .handler = _handler, \ +} +struct pm_chg_irq_init_data chg_irq_data[] = { + CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + usbin_valid_irq_handler), + CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler), + CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + batt_inserted_irq_handler), +#if !defined(CONFIG_BATTERY_MAX17040) && \ + !defined(CONFIG_BATTERY_MAX17042) + CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + vbatdet_low_irq_handler), +#endif + CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + usbin_uv_irq_handler), + CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler), + CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler), + CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler), + CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler), + CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler), + CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler), + CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler), + CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler), + CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler), + CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + fastchg_irq_handler), + CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler), + CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING, + batt_removed_irq_handler), + CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING, + batttemp_hot_irq_handler), + CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler), + CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING, + batttemp_cold_irq_handler), + CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING, chg_gone_irq_handler), + CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + bat_temp_ok_irq_handler), + CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING, + coarse_det_low_irq_handler), + CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler), + CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler), + CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler), + CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + batfet_irq_handler), + CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + dcin_valid_irq_handler), + CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + dcin_ov_irq_handler), + CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler), +}; + +static int __devinit request_irqs(struct pm8921_chg_chip *chip, + struct platform_device *pdev) +{ + struct resource *res; + int ret, i; + + ret = 0; + bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS); + + for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + chg_irq_data[i].name); + if (res == NULL) { + pr_err("couldn't find %s\n", chg_irq_data[i].name); + goto err_out; + } + chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start; + ret = request_threaded_irq(res->start, NULL, + chg_irq_data[i].handler, + chg_irq_data[i].flags, + chg_irq_data[i].name, chip); + if (ret < 0) { + pr_err("couldn't request %d (%s) %d\n", res->start, + chg_irq_data[i].name, ret); + chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0; + goto err_out; + } + pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id); + } + return 0; + +err_out: + free_irqs(chip); + return -EINVAL; +} + +static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip) +{ + int err; + u8 temp; + + temp = 0xD1; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD3; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD1; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD5; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + udelay(183); + + temp = 0xD1; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD0; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + udelay(32); + + temp = 0xD1; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD3; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } +} + +static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip) +{ + int err; + u8 temp; + + temp = 0xD1; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD0; + err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } +} + +#define ENUM_TIMER_STOP_BIT BIT(1) +#define BOOT_DONE_BIT BIT(6) +#define CHG_BATFET_ON_BIT BIT(3) +#define CHG_VCP_EN BIT(0) +#define CHG_BAT_TEMP_DIS_BIT BIT(2) +#define SAFE_CURRENT_MA 1500 +#define VREF_BATT_THERM_FORCE_ON BIT(7) +static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip) +{ + int rc; + + rc = pm_chg_masked_write(chip, SYS_CONFIG_2, + BOOT_DONE_BIT, BOOT_DONE_BIT); + if (rc) { + pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc); + return rc; + } + + rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv); + if (rc) { + pr_err("Failed to set safe voltage to %d rc=%d\n", + chip->max_voltage_mv, rc); + return rc; + } + rc = pm_chg_vbatdet_set(chip, + chip->max_voltage_mv + - chip->resume_voltage_delta); + if (rc) { + pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n", + chip->max_voltage_mv - chip->resume_voltage_delta, rc); + return rc; + } + + rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv); + if (rc) { + pr_err("Failed to set max voltage to %d rc=%d\n", + chip->max_voltage_mv, rc); + return rc; + } + rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA); + if (rc) { + pr_err("Failed to set max voltage to %d rc=%d\n", + SAFE_CURRENT_MA, rc); + return rc; + } + + rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current); + if (rc) { + pr_err("Failed to set max current to 400 rc=%d\n", rc); + return rc; + } + + rc = pm_chg_iterm_set(chip, chip->term_current); + if (rc) { + pr_err("Failed to set term current to %d rc=%d\n", + chip->term_current, rc); + return rc; + } + + /* Disable the ENUM TIMER */ + rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT, + ENUM_TIMER_STOP_BIT); + if (rc) { + pr_err("Failed to set enum timer stop rc=%d\n", rc); + return rc; + } + + /* init with the lowest USB current */ + rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value); + if (rc) { + pr_err("Failed to set usb max to %d rc=%d\n", + usb_ma_table[0].chg_iusb_value, rc); + return rc; + } + + if (chip->safety_time != 0) { + rc = pm_chg_tchg_max_set(chip, chip->safety_time); + if (rc) { + pr_err("Failed to set max time to %d minutes rc=%d\n", + chip->safety_time, rc); + return rc; + } + } + + if (chip->ttrkl_time != 0) { + rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time); + if (rc) { + pr_err("Failed to set trkl time to %d minutes rc=%d\n", + chip->safety_time, rc); + return rc; + } + } + + if (chip->vin_min != 0) { + rc = pm_chg_vinmin_set(chip, chip->vin_min); + if (rc) { + pr_err("Failed to set vin min to %d mV rc=%d\n", + chip->vin_min, rc); + return rc; + } + } else { + chip->vin_min = pm_chg_vinmin_get(chip); + } + + rc = pm_chg_disable_wd(chip); + if (rc) { + pr_err("Failed to disable wd rc=%d\n", rc); + return rc; + } + + /* switch to a 3.2Mhz for the buck */ + rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15); + if (rc) { + pr_err("Failed to switch buck clk rc=%d\n", rc); + return rc; + } + + if (chip->trkl_voltage != 0) { /* ATC on step A */ + rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage); + if (rc) { + pr_err("Failed to set trkl voltage to %dmv rc=%d\n", + chip->trkl_voltage, rc); + return rc; + } + } + + if (chip->weak_voltage != 0) { /* ATC on step B or SW VTrkl */ + rc = pm_chg_vweak_set(chip, chip->weak_voltage); + if (rc) { + pr_err("Failed to set weak voltage to %dmv rc=%d\n", + chip->weak_voltage, rc); + return rc; + } + } + + if (chip->trkl_current != 0) { /* ATC A Itrkl or SW ITrkl 50~200 */ + rc = pm_chg_itrkl_set(chip, chip->trkl_current); + if (rc) { + pr_err("Failed to set trkl current to %dmA rc=%d\n", + chip->trkl_voltage, rc); + return rc; + } + } + + if (chip->weak_current != 0) { /* ATC B ITrkl 325~525 */ + rc = pm_chg_iweak_set(chip, chip->weak_current); + if (rc) { + pr_err("Failed to set weak current to %dmA rc=%d\n", + chip->weak_current, rc); + return rc; + } + } + +#ifdef QUALCOMM_TEMPERATURE_CONTROL + rc = pm_chg_masked_write(chip, CHG_CNTRL_2, + CHG_BAT_TEMP_DIS_BIT, 0); + if (rc) { + pr_err("Failed to enable temp control chg rc=%d\n", rc); + return rc; + } + + rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr); + if (rc) { + pr_err("Failed to set cold config %d rc=%d\n", + chip->cold_thr, rc); + } + + rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr); + if (rc) { + pr_err("Failed to set hot config %d rc=%d\n", + chip->hot_thr, rc); + } +#else + /* sec don't use temperature control function */ + rc = pm_chg_masked_write(chip, CHG_CNTRL_2, + CHG_BAT_TEMP_DIS_BIT, 1); + if (rc) { + pr_err("Failed to enable temp control chg rc=%d\n", rc); + return rc; + } +#endif + + /* Workarounds for die 1.1 and 1.0 */ + if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) { + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1); + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE); + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8); + + /* software workaround for correct battery_id detection */ + pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF); + pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF); + pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF); + pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF); + pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D); + udelay(100); + pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C); + } + + /* Workarounds for die 3.0 */ + if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0) + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC); + + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9); + + /* Disable EOC FSM processing */ + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91); + + pm8921_chg_force_19p2mhz_clk(chip); + + rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, + VREF_BATT_THERM_FORCE_ON); + if (rc) + pr_err("Failed to Force Vref therm rc=%d\n", rc); + + rc = pm_chg_charge_dis(chip, charging_disabled); + if (rc) { + pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc); + return rc; + } + + rc = pm_chg_auto_enable(chip, !charging_disabled); + if (rc) { + pr_err("Failed to enable charging rc=%d\n", rc); + return rc; + } + + return 0; +} + +static int get_rt_status(void *data, u64 * val) +{ + int i = (int)data; + int ret; + + /* global irq number is passed in via data */ + ret = pm_chg_get_rt_status(the_chip, i); + *val = ret; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n"); + +static int get_fsm_status(void *data, u64 * val) +{ + u8 temp; + + temp = pm_chg_get_fsm_state(the_chip); + *val = temp; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n"); + +static int get_reg_loop(void *data, u64 * val) +{ + u8 temp; + + if (!the_chip) { + pr_err("%s called before init\n", __func__); + return -EINVAL; + } + temp = pm_chg_get_regulation_loop(the_chip); + *val = temp; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n"); + +static int get_reg(void *data, u64 * val) +{ + int addr = (int)data; + int ret; + u8 temp; + + ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp); + if (ret) { + pr_err("pm8xxx_readb to %x value =%d errored = %d\n", + addr, temp, ret); + return -EAGAIN; + } + *val = temp; + return 0; +} + +static int set_reg(void *data, u64 val) +{ + int addr = (int)data; + int ret; + u8 temp; + + temp = (u8) val; + ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp); + if (ret) { + pr_err("pm8xxx_writeb to %x value =%d errored = %d\n", + addr, temp, ret); + return -EAGAIN; + } + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n"); + +enum { + BAT_WARM_ZONE, + BAT_COOL_ZONE, +}; +static int get_warm_cool(void *data, u64 * val) +{ + if (!the_chip) { + pr_err("%s called before init\n", __func__); + return -EINVAL; + } + if ((int)data == BAT_WARM_ZONE) + *val = the_chip->is_bat_warm; + if ((int)data == BAT_COOL_ZONE) + *val = the_chip->is_bat_cool; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n"); + +static void create_debugfs_entries(struct pm8921_chg_chip *chip) +{ + int i; + + chip->dent = debugfs_create_dir("pm8921_chg", NULL); + + if (IS_ERR(chip->dent)) { + pr_err("pmic charger couldnt create debugfs dir\n"); + return; + } + + debugfs_create_file("CHG_CNTRL", 0644, chip->dent, + (void *)CHG_CNTRL, ®_fops); + debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent, + (void *)CHG_CNTRL_2, ®_fops); + debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent, + (void *)CHG_CNTRL_3, ®_fops); + debugfs_create_file("PBL_ACCESS1", 0644, chip->dent, + (void *)PBL_ACCESS1, ®_fops); + debugfs_create_file("PBL_ACCESS2", 0644, chip->dent, + (void *)PBL_ACCESS2, ®_fops); + debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent, + (void *)SYS_CONFIG_1, ®_fops); + debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent, + (void *)SYS_CONFIG_2, ®_fops); + debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent, + (void *)CHG_VDD_MAX, ®_fops); + debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent, + (void *)CHG_VDD_SAFE, ®_fops); + debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent, + (void *)CHG_VBAT_DET, ®_fops); + debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent, + (void *)CHG_IBAT_MAX, ®_fops); + debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent, + (void *)CHG_IBAT_SAFE, ®_fops); + debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent, + (void *)CHG_VIN_MIN, ®_fops); + debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent, + (void *)CHG_VTRICKLE, ®_fops); + debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent, + (void *)CHG_ITRICKLE, ®_fops); + debugfs_create_file("CHG_ITERM", 0644, chip->dent, + (void *)CHG_ITERM, ®_fops); + debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent, + (void *)CHG_TCHG_MAX, ®_fops); + debugfs_create_file("CHG_TWDOG", 0644, chip->dent, + (void *)CHG_TWDOG, ®_fops); + debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent, + (void *)CHG_TEMP_THRESH, ®_fops); + debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent, + (void *)CHG_COMP_OVR, ®_fops); + debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent, + (void *)CHG_BUCK_CTRL_TEST1, ®_fops); + debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent, + (void *)CHG_BUCK_CTRL_TEST2, ®_fops); + debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent, + (void *)CHG_BUCK_CTRL_TEST3, ®_fops); + debugfs_create_file("CHG_TEST", 0644, chip->dent, + (void *)CHG_TEST, ®_fops); + + debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL, + &fsm_fops); + + debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL, + ®_loop_fops); + + debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent, + (void *)BAT_WARM_ZONE, &warm_cool_fops); + debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent, + (void *)BAT_COOL_ZONE, &warm_cool_fops); + + for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) { + if (chip->pmic_chg_irq[chg_irq_data[i].irq_id]) + debugfs_create_file(chg_irq_data[i].name, 0444, + chip->dent, + (void *)chg_irq_data[i].irq_id, + &rt_fops); + } +} + +#define SEC_BATTERY_ATTR(_name) \ +{ \ + .attr = { .name = #_name, \ + .mode = S_IRUGO | S_IWUSR | S_IWGRP, \ + /*.owner = THIS_MODULE */}, \ + .show = sec_bat_show_property, \ + .store = sec_bat_store, \ +} + +static struct device_attribute sec_battery_attrs[] = { + SEC_BATTERY_ATTR(batt_vol), + SEC_BATTERY_ATTR(batt_read_adj_soc), + SEC_BATTERY_ATTR(batt_read_raw_soc), + SEC_BATTERY_ATTR(batt_temp), + SEC_BATTERY_ATTR(batt_temp_adc), + SEC_BATTERY_ATTR(batt_type), + SEC_BATTERY_ATTR(batt_charging_enable), + SEC_BATTERY_ATTR(batt_charging_source), + SEC_BATTERY_ATTR(batt_reset_soc), + SEC_BATTERY_ATTR(batt_usbin_curr), + SEC_BATTERY_ATTR(batt_chg_curr), + SEC_BATTERY_ATTR(charger_register), + SEC_BATTERY_ATTR(charger_register_irq), + SEC_BATTERY_ATTR(system_revision), + SEC_BATTERY_ATTR(test_value), +}; + +enum { + BATT_VOL = 0, + BATT_READ_ADJ_SOC, + BATT_READ_RAW_SOC, + BATT_TEMP, + BATT_TEMP_ADC, + BATT_TYPE, + BATT_CHARGING_ENABLE, + BATT_CHARGING_SOURCE, + BATT_RESET_SOC, + BATT_USBIN_CURR, + BATT_CHG_CURR, + CHARGER_REGISTER, + CHARGER_REGISTER_IRQ, + SYSTEM_REVISION, + TEST_VALUE, +}; + +static ssize_t sec_bat_show_property(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pm8921_chg_chip *chip = dev_get_drvdata(dev->parent); + int i = 0, val = 0; + const ptrdiff_t off = attr - sec_battery_attrs; + + switch (off) { +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) + case BATT_VOL: + val = sec_bat_get_fuelgauge_data(chip, FG_T_VCELL); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_READ_ADJ_SOC: + val = sec_bat_get_fuelgauge_data(chip, FG_T_SOC); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_READ_RAW_SOC: + val = sec_bat_get_fuelgauge_data(chip, FG_T_PSOC); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; +#endif + case BATT_TEMP: + pm8921_batt_temperature(); + val = chip->batt_temp; + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_TEMP_ADC: + pm8921_batt_temperature(); + val = chip->batt_temp_adc; + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_CHARGING_ENABLE: + val = (chip->charging_enabled) ? 1 : 0; + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_TYPE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", "SDI_SDI"); + break; + case BATT_CHARGING_SOURCE: + val = chip->cable_type; + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_USBIN_CURR: + if (pm_chg_iusbmax_get(chip, &val)) + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", "error"); + else + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_CHG_CURR: + if (pm_chg_ibatmax_get(chip, &val)) + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", "error"); + else + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case CHARGER_REGISTER: + i += scnprintf(buf + i, PAGE_SIZE - i, + "0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + chip->chg_reg.chg_cntrl, chip->chg_reg.chg_cntrl_2, + chip->chg_reg.chg_cntrl_3, chip->chg_reg.pbl_access1, + chip->chg_reg.pbl_access2, chip->chg_reg.sys_config_1, + chip->chg_reg.sys_config_2, chip->chg_reg.chg_vdd_max, + chip->chg_reg.chg_vdd_safe, chip->chg_reg.chg_ibat_max, + chip->chg_reg.chg_ibat_safe, chip->chg_reg.chg_iterm); + break; + case CHARGER_REGISTER_IRQ: + i += scnprintf(buf + i, PAGE_SIZE - i, + "%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", + chip->chg_irq.usbin_valid, chip->chg_irq.usbin_ov, + chip->chg_irq.usbin_uv, chip->chg_irq.batttemp_hot, + chip->chg_irq.batttemp_cold, + chip->chg_irq.batt_inserted, + chip->chg_irq.trklchg, chip->chg_irq.fastchg, + chip->chg_irq.batfet, chip->chg_irq.batt_removed, + chip->chg_irq.vcp, chip->chg_irq.bat_temp_ok); + break; + case SYSTEM_REVISION: + val = system_rev; + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case TEST_VALUE: + val = chip->test_value; + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + default: + i = -EINVAL; + } + + return i; +} + +static ssize_t sec_bat_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret = 0, x = 0; + const ptrdiff_t off = attr - sec_battery_attrs; + struct pm8921_chg_chip *chip = dev_get_drvdata(dev->parent); + + switch (off) { + case BATT_CHARGING_ENABLE: + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 0) /* charging enable */ + pm_chg_usb_suspend_enable(chip, 0); + else if (x == 1) /* charging disable */ + pm_chg_usb_suspend_enable(chip, 1); + else if (x == 2) /* charging enable */ + pm_chg_charge_dis(chip, 0); + else if (x == 3) /* charging disable */ + pm_chg_charge_dis(chip, 1); + else if (x == 4) /* charging enable */ + pm_chg_auto_enable(chip, 1); + else if (x == 5) /* charging disable */ + pm_chg_auto_enable(chip, 0); + ret = count; + } + break; + case BATT_CHARGING_SOURCE: + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 0) { + chip->cable_type = CABLE_TYPE_NONE; + handle_cable_insertion_removal(chip); + } else if (x == 1) { + chip->cable_type = CABLE_TYPE_USB; + handle_cable_insertion_removal(chip); + } else if (x == 2) { + chip->cable_type = CABLE_TYPE_AC; + handle_cable_insertion_removal(chip); + } else { + pr_err("error BATT_CHARGING_ENABLE : Invalid input\n"); + } + ret = count; + } + break; + case BATT_RESET_SOC: + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 1) { +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) + sec_bat_set_fuelgauge_data(chip, FG_RESET); +#endif + ret = count; + } + } + break; + case BATT_USBIN_CURR: + if (sscanf(buf, "%d\n", &x) == 1) { + /* pm8921_charger_vbus_draw(x); */ + TEST_iUSBIN = x; + ret = count; + } + break; + case BATT_CHG_CURR: + if (sscanf(buf, "%d\n", &x) == 1) { + /* pm8921_set_max_battery_charge_current(x); */ + TEST_iBAT = x; + ret = count; + } + break; + case TEST_VALUE: + if (sscanf(buf, "%d\n", &x) == 1) { + chip->test_value = (unsigned int)x; + ret = count; + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int sec_bat_create_attrs(struct device *dev) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(sec_battery_attrs); i++) { + rc = device_create_file(dev, &sec_battery_attrs[i]); + if (rc) + goto sec_attrs_failed; + } + goto succeed; + +sec_attrs_failed: + while (i--) + device_remove_file(dev, &sec_battery_attrs[i]); +succeed: + return rc; +} + +static int +pm8921_bat_read_proc(char *buf, char **start, off_t offset, + int count, int *eof, void *data) +{ + struct pm8921_chg_chip *chip = data; + struct timespec cur_time; + ktime_t ktime; + int len = 0; + + ktime = alarm_get_elapsed_realtime(); + cur_time = ktime_to_timespec(ktime); + + len = sprintf(buf, "%lu\t%d\t%d\t%d\t%d\t%d", + cur_time.tv_sec, + chip->batt_vcell, + chip->batt_soc, + chip->batt_temp, + chip->cable_type, + chip->charging_enabled); + + return len; +} +static int pm8921_charger_suspend_noirq(struct device *dev) +{ + int rc; + struct pm8921_chg_chip *chip = dev_get_drvdata(dev); + + rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0); + if (rc) + pr_err("Failed to Force Vref therm off rc=%d\n", rc); + pm8921_chg_set_hw_clk_switching(chip); + return 0; +} + +static int pm8921_charger_resume_noirq(struct device *dev) +{ + int rc; + struct pm8921_chg_chip *chip = dev_get_drvdata(dev); + + pm8921_chg_force_19p2mhz_clk(chip); + + rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, + VREF_BATT_THERM_FORCE_ON); + if (rc) + pr_err("Failed to Force Vref therm on rc=%d\n", rc); + return 0; +} + + +static int pm8921_charger_resume(struct device *dev) +{ + int rc; + struct pm8921_chg_chip *chip = dev_get_drvdata(dev); + + if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0) + && !(chip->keep_btm_on_suspend)) { + rc = pm8xxx_adc_btm_configure(&btm_config); + if (rc) + pr_err("couldn't reconfigure btm rc=%d\n", rc); + + rc = pm8xxx_adc_btm_start(); + if (rc) + pr_err("couldn't restart btm rc=%d\n", rc); + } + if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) { + disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]); + pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ); + } + return 0; +} + +static int pm8921_charger_suspend(struct device *dev) +{ + int rc; + struct pm8921_chg_chip *chip = dev_get_drvdata(dev); + + if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0) + && !(chip->keep_btm_on_suspend)) { + rc = pm8xxx_adc_btm_end(); + if (rc) + pr_err("Failed to disable BTM on suspend rc=%d\n", rc); + } + + if (is_usb_chg_plugged_in(chip)) { + pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ); + enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]); + } + return 0; +} + +#define ATC_ON_BIT BIT(7) +static void pm8921_sec_charger_disable(struct pm8921_chg_chip *chip) +{ + int rc; + pr_debug("disable pm8921 charger\n"); + + rc = pm_chg_vweak_set(chip, 2500); + if (rc) { + pr_err("Failed to set weak voltage to %dmv rc=%d\n", + chip->weak_voltage, rc); + return; + } + + /*SW Trickle Charging mode */ + rc = pm_chg_masked_write(chip, CHG_CNTRL_2, + ATC_ON_BIT, 0); + if (rc) { + pr_err("Failed to set ATC off rc=%d\n", rc); + return; + } + + /* sec don't use temperature control function */ + rc = pm_chg_masked_write(chip, CHG_CNTRL_2, + CHG_BAT_TEMP_DIS_BIT, 1); + if (rc) { + pr_err("Failed to enable temp control chg rc=%d\n", rc); + return; + } + + /* Workarounds for die 1.1 and 1.0 */ + if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) { + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1); + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE); + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8); + + /* software workaround for correct battery_id detection */ + pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF); + pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF); + pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF); + pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF); + pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D); + udelay(100); + pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C); + } + + /* Workarounds for die 3.0 */ + if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0) + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC); + + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9); + + /* Disable EOC FSM processing */ + pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91); + + /* Disable Charging */ + charging_disabled = 1; + rc = pm_chg_charge_dis(chip, charging_disabled); + if (rc) { + pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc); + return; + } + + rc = pm_chg_auto_enable(chip, !charging_disabled); + if (rc) { + pr_err("Failed to enable charging rc=%d\n", rc); + return; + } + + /* Disable BMS */ +#ifndef CONFIG_PM8921_BMS + rc = pm_chg_masked_write(chip, BMS_CONTROL, EN_BMS_BIT, 0); + if (rc) + pr_err("failed to disable bms addr = %d %d", BMS_CONTROL, rc); +#endif +} + +static int __devinit pm8921_charger_probe(struct platform_device *pdev) +{ + int rc = 0; + struct pm8921_chg_chip *chip; + const struct pm8921_charger_platform_data *pdata + = pdev->dev.platform_data; + + if (!pdata) { + pr_err("missing platform data\n"); + return -EINVAL; + } + + chip = kzalloc(sizeof(struct pm8921_chg_chip), + GFP_KERNEL); + if (!chip) { + pr_err("Cannot allocate pm_chg_chip\n"); + return -ENOMEM; + } + + chip->dev = &pdev->dev; + + if (!is_pm8921_sec_charger_using()) { + pm8921_sec_charger_disable(chip); + pr_info("driver Loading SKIP!!!\n"); + rc = -EINVAL; + goto free_chip; + } + chip->safety_time = pdata->safety_time; + chip->ttrkl_time = pdata->ttrkl_time; + chip->update_time = pdata->update_time; + chip->max_voltage_mv = pdata->max_voltage; + chip->min_voltage_mv = pdata->min_voltage; + chip->resume_voltage_delta = pdata->resume_voltage_delta; + chip->term_current = pdata->term_current; + chip->vbat_channel = pdata->charger_cdata.vbat_channel; + chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel; + chip->batt_id_channel = pdata->charger_cdata.batt_id_channel; + chip->batt_id_min = pdata->batt_id_min; + chip->batt_id_max = pdata->batt_id_max; + chip->cool_temp_dc = pdata->cool_temp * 10; + chip->warm_temp_dc = pdata->warm_temp * 10; + chip->temp_check_period = pdata->temp_check_period; + chip->max_bat_chg_current = pdata->max_bat_chg_current; + chip->cool_bat_chg_current = pdata->cool_bat_chg_current; + chip->warm_bat_chg_current = pdata->warm_bat_chg_current; + chip->cool_bat_voltage = pdata->cool_bat_voltage; + chip->warm_bat_voltage = pdata->warm_bat_voltage; + chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend; + chip->trkl_voltage = pdata->trkl_voltage; + chip->weak_voltage = pdata->weak_voltage; + chip->trkl_current = pdata->trkl_current; + chip->weak_current = pdata->weak_current; + chip->vin_min = pdata->vin_min; + chip->thermal_mitigation = pdata->thermal_mitigation; + chip->thermal_levels = pdata->thermal_levels; + + chip->cold_thr = pdata->cold_thr; + chip->hot_thr = pdata->hot_thr; + + chip->get_cable_type = pdata->get_cable_type; + + chip->batt_soc = 100; +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) + chip->batt_temp = RCOMP0_TEMP*10; +#endif + + rc = pm8921_chg_hw_init(chip); + if (rc) { + pr_err("couldn't init hardware rc=%d\n", rc); + goto free_chip; + } + + chip->usb_psy.name = "usb", + chip->usb_psy.type = POWER_SUPPLY_TYPE_USB, + chip->usb_psy.supplied_to = pm_power_supplied_to, + chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to), + chip->usb_psy.properties = pm_power_props, + chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props), + chip->usb_psy.get_property = pm_power_get_property, + + chip->ac_psy.name = "ac", + chip->ac_psy.type = POWER_SUPPLY_TYPE_MAINS, + chip->ac_psy.supplied_to = pm_power_supplied_to, + chip->ac_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to), + chip->ac_psy.properties = pm_power_props, + chip->ac_psy.num_properties = ARRAY_SIZE(pm_power_props), + chip->ac_psy.get_property = pm_power_get_property, + + chip->batt_psy.name = "battery", + chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY, + chip->batt_psy.properties = msm_batt_power_props, + chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props), + chip->batt_psy.get_property = pm_batt_power_get_property, + chip->batt_psy.set_property = pm_batt_power_set_property, + chip->batt_psy.external_power_changed = pm_batt_external_power_changed, + + rc = power_supply_register(chip->dev, &chip->usb_psy); + if (rc < 0) { + pr_err("power_supply_register usb failed rc = %d\n", rc); + goto free_chip; + } + + rc = power_supply_register(chip->dev, &chip->ac_psy); + if (rc < 0) { + pr_err("power_supply_register ac failed rc = %d\n", rc); + goto unregister_usb; + } + + rc = power_supply_register(chip->dev, &chip->batt_psy); + if (rc < 0) { + pr_err("power_supply_register batt failed rc = %d\n", rc); + goto unregister_ac; + } + + platform_set_drvdata(pdev, chip); + the_chip = chip; + pr_info("battery register supply end\n"); + + wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc"); + wake_lock_init(&chip->unplug_wrkarnd_restore_wake_lock, + WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd"); + INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker); + INIT_DELAYED_WORK(&chip->unplug_wrkarnd_restore_work, + unplug_wrkarnd_restore_worker); + INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker); + + rc = request_irqs(chip, pdev); + if (rc) { + pr_err("couldn't register interrupts rc=%d\n", rc); + goto unregister_batt; + } + + enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]); + enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]); + enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]); +#if !defined(CONFIG_BATTERY_MAX17040) && \ + !defined(CONFIG_BATTERY_MAX17042) + enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]); +#endif +#ifdef QUALCOMM_TEMPERATURE_CONTROL + enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]); + /* + * if both the cool_temp_dc and warm_temp_dc are zero the device doesnt + * care for jeita compliance + */ + if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)) { + rc = configure_btm(chip); + if (rc) { + pr_err("couldn't register with btm rc=%d\n", rc); + goto free_irq; + } + } +#endif + + create_debugfs_entries(chip); + /* create sec detail attributes */ + rc = sec_bat_create_attrs(chip->batt_psy.dev); + if (rc) { + pr_err("couldn't create attrs rc=%d\n", rc); + goto unregister_batt; + } + + chip->entry = create_proc_entry("batt_info_proc", S_IRUGO, NULL); + if (!chip->entry) { + pr_err("failed to create proc_entry.\n"); + } else { + chip->entry->read_proc = pm8921_bat_read_proc; + chip->entry->data = (struct pm8921_chg_chip *)chip; + } + +#ifdef CONFIG_PM8921_BMS + pr_info("CONFIG_PM8921_BMS enabled\n"); + INIT_WORK(&chip->bms_notify.work, bms_notify); +#else + rc = pm_chg_masked_write(chip, BMS_CONTROL, EN_BMS_BIT, 0); + if (rc) + pr_err("failed to disable bms addr = %d %d", BMS_CONTROL, rc); + + pr_info("CONFIG_PM8921_BMS disabled\n"); +#endif + INIT_WORK(&chip->battery_id_valid_work, battery_id_valid); + + /* determine what state the charger is in */ + determine_initial_state(chip); + + if (chip->update_time) { + INIT_DELAYED_WORK(&chip->update_heartbeat_work, + update_heartbeat); + schedule_delayed_work(&chip->update_heartbeat_work, 0); + } + + handle_usb_insertion_removal(chip); + + pr_info("battery probe end\n"); + return 0; + +#ifdef QUALCOMM_TEMPERATURE_CONTROL +free_irq: + free_irqs(chip); +#endif +unregister_batt: + power_supply_unregister(&chip->batt_psy); +unregister_ac: + power_supply_unregister(&chip->ac_psy); +unregister_usb: + power_supply_unregister(&chip->usb_psy); +free_chip: + kfree(chip); + return rc; +} + +static int __devexit pm8921_charger_remove(struct platform_device *pdev) +{ + struct pm8921_chg_chip *chip = platform_get_drvdata(pdev); + + remove_proc_entry("batt_info_proc", NULL); + + free_irqs(chip); + platform_set_drvdata(pdev, NULL); + the_chip = NULL; + kfree(chip); + return 0; +} +static const struct dev_pm_ops pm8921_pm_ops = { + .suspend = pm8921_charger_suspend, + .suspend_noirq = pm8921_charger_suspend_noirq, + .resume_noirq = pm8921_charger_resume_noirq, + .resume = pm8921_charger_resume, +}; +static struct platform_driver pm8921_charger_driver = { + .probe = pm8921_charger_probe, + .remove = __devexit_p(pm8921_charger_remove), + .driver = { + .name = PM8921_CHARGER_DEV_NAME, + .owner = THIS_MODULE, + .pm = &pm8921_pm_ops, + }, +}; + +static int __init pm8921_charger_init(void) +{ + return platform_driver_register(&pm8921_charger_driver); +} + +static void __exit pm8921_charger_exit(void) +{ + platform_driver_unregister(&pm8921_charger_driver); +} + +late_initcall(pm8921_charger_init); +module_exit(pm8921_charger_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PMIC8921 charger/battery driver"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME); diff --git a/drivers/power/sec_battery.c b/drivers/power/sec_battery.c new file mode 100644 index 00000000000..438473a64c5 --- /dev/null +++ b/drivers/power/sec_battery.c @@ -0,0 +1,2932 @@ +/* + * sec_battery.c + * Samsung Mobile Battery Driver + * + * Copyright (C) 2011 Samsung Electronics + * + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FG_T_SOC 0 +#define FG_T_VCELL 1 +#define FG_T_PSOC 2 +#define FG_T_RCOMP 3 +#define FG_T_FSOC 4 + +#define BATT_STATUS_MISSING 0 +#define BATT_STATUS_PRESENT 1 +#define BATT_STATUS_UNKNOWN 2 + +#ifdef CONFIG_BATTERY_CTIA +#define USE_CALL (0x1 << 0) +#define USE_VIDEO (0x1 << 1) +#define USE_MUSIC (0x1 << 2) +#define USE_BROWSER (0x1 << 3) +#define USE_HOTSPOT (0x1 << 4) +#define USE_CAMERA (0x1 << 5) +#define USE_DATA_CALL (0x1 << 6) +#define USE_GPS (0x1 << 7) +#define USE_LTE (0x1 << 8) +#define USE_WIFI (0x1 << 9) +#endif /*CONFIG_BATTERY_CTIA*/ + +#define TOTAL_EVENT_TIME (10 * 60) /* 10 minites */ + +static int is_charging_disabled; + +enum cable_type_t { + CABLE_TYPE_NONE = 0, + CABLE_TYPE_USB, + CABLE_TYPE_AC, + CABLE_TYPE_MISC, + CABLE_TYPE_CARDOCK, + CABLE_TYPE_UARTOFF, + CABLE_TYPE_JIG, + CABLE_TYPE_UNKNOWN, + CABLE_TYPE_CDP, + CABLE_TYPE_SMART_DOCK, +#ifdef CONFIG_WIRELESS_CHARGING + CABLE_TYPE_WPC = 10, +#endif + +}; + +enum batt_full_t { + BATT_NOT_FULL = 0, + BATT_FULL, +}; + +enum { + BAT_NOT_DETECTED, + BAT_DETECTED +}; + +static ssize_t sec_bat_show_property(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t sec_bat_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +struct battest_info { + int rechg_count; + int full_count; + int test_value; + int test_esuspend; + bool is_rechg_state; +}; + +struct sec_temperature_spec { + int event_block; + int high_block; + int high_recovery; + int low_block; + int low_recovery; +}; + +struct sec_bat_info { + struct device *dev; + + char *fuel_gauge_name; + char *charger_name; + + struct power_supply psy_bat; + struct power_supply psy_usb; + struct power_supply psy_ac; + + struct wake_lock vbus_wake_lock; + struct wake_lock cable_wake_lock; + struct wake_lock monitor_wake_lock; + struct wake_lock test_wake_lock; + struct wake_lock measure_wake_lock; + +#if defined(CONFIG_BATTERY_CTIA) + struct alarm event_alarm; +#endif /*CONFIG_BATTERY_CTIA*/ + struct alarm alarm; + + enum cable_type_t cable_type; + enum cable_type_t prev_cable; + enum batt_full_t batt_full_status; + + int batt_temp; + int batt_temp_high_cnt; + int batt_temp_low_cnt; + int high_recovery_wpc; + unsigned int batt_health; + unsigned int batt_vcell; + unsigned int batt_soc; + unsigned int batt_raw_soc; + unsigned int batt_full_soc; + unsigned int batt_presoc; + unsigned int measure_interval; + int charging_status; + int otg_state; + int current_avg; + unsigned int batt_temp_adc; + unsigned int batt_temp_radc; + unsigned int batt_current_adc; + unsigned int present; + struct battest_info test_info; + struct workqueue_struct *monitor_wqueue; + struct work_struct monitor_work; + struct delayed_work cable_work; + struct delayed_work measure_work; + struct delayed_work otg_work; + struct early_suspend bat_early_suspend; + struct sec_temperature_spec tspec; + struct proc_dir_entry *entry; + + unsigned long charging_start_time; + unsigned long charging_passed_time; + unsigned int iterm; + unsigned int abs_time; + unsigned int normal_abs_time; + unsigned int wpc_abs_time; + unsigned int rechg_time; + unsigned int vrechg; + unsigned int vmax; + unsigned int recharging_status; + unsigned int is_top_off; + unsigned int hw_rev; + unsigned int voice_call_state; + unsigned int full_cond_voltage; + unsigned int full_cond_count; + unsigned int initial_check_count; + + bool charging_enabled; + bool is_timeout_chgstop; + bool is_esus_state; + bool lpm_chg_mode; + bool slate_mode; + bool is_rechg_triggered; + bool dcin_intr_triggered; + u16 batt_rcomp; + unsigned int slow_polling; + +#ifdef CONFIG_WIRELESS_CHARGING + bool wc_status; + int wpc_charging_current; +#endif +#if defined(CONFIG_BATTERY_CTIA) + ktime_t cur_time; + unsigned int batt_use; + unsigned int batt_use_wait; +#endif /*CONFIG_BATTERY_CTIA*/ + ktime_t cur_monitor_time; +#if defined(CONFIG_TARGET_LOCALE_USA) + bool ui_full_charge_status; + bool cable_uart_off; +#endif + unsigned int batt_int_irq; + unsigned int batt_int; + bool batt_int_irq_use; + bool factory_mode; + bool check_full_state; + unsigned int check_full_state_cnt; +}; + +static char *supply_list[] = { + "battery", +}; + +static enum power_supply_property sec_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_TECHNOLOGY, +}; + +static enum power_supply_property sec_power_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +#if defined(CONFIG_CHARGER_SMB347) && \ + defined(CONFIG_WIRELESS_CHARGING) +enum { + INPUT_NONE, + INPUT_DCIN, + INPUT_USBIN, +}; +#endif + +static void sec_bat_monitoring_alarm(struct sec_bat_info *info, + int sec) +{ + ktime_t low_interval = ktime_set(sec - 10, 0); + ktime_t slack = ktime_set(20, 0); + ktime_t next; + + next = ktime_add(info->cur_monitor_time, low_interval); + alarm_start_range(&info->alarm, next, ktime_add(next, slack)); +} + +static void sec_bat_monitor_queue(struct alarm *alarm) +{ + struct sec_bat_info *info = + container_of(alarm, struct sec_bat_info, alarm); + + queue_delayed_work(info->monitor_wqueue, &info->measure_work, 0); + + queue_work(info->monitor_wqueue, &info->monitor_work); +} + +static int sec_bat_check_vf(struct sec_bat_info *info) +{ + int health = info->batt_health; + + if (info->present == BATT_STATUS_MISSING && !(info->factory_mode)) + health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + else + health = POWER_SUPPLY_HEALTH_GOOD; + + /* update health */ + if (health != info->batt_health) { + if (health == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE || + health == POWER_SUPPLY_HEALTH_DEAD) { + info->batt_health = health; + pr_info("%s : vf error update\n", __func__); + } else if (info->batt_health != POWER_SUPPLY_HEALTH_OVERHEAT && + info->batt_health != POWER_SUPPLY_HEALTH_COLD && + health == POWER_SUPPLY_HEALTH_GOOD) { + info->batt_health = health; + pr_info("%s : recovery form vf error\n", __func__); + } + } + + return 0; +} +#if 0 +static int sec_bat_check_detbat(struct sec_bat_info *info) +{ + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + union power_supply_propval value; + static int cnt; + int vf_state = BAT_DETECTED; + int ret = 0; + + if (!psy) { + dev_err(info->dev, "%s: fail to get charger ps\n", __func__); + return -ENODEV; + } + + ret = psy->get_property(psy, POWER_SUPPLY_PROP_PRESENT, &value); + if (ret < 0) { + dev_err(info->dev, "%s: fail to get status(%d)\n", + __func__, ret); + return -ENODEV; + } + + if ((info->cable_type != CABLE_TYPE_NONE) && + (value.intval == BAT_NOT_DETECTED)) { + if (cnt <= BAT_DET_COUNT) + cnt++; + if (cnt >= BAT_DET_COUNT) + vf_state = BAT_NOT_DETECTED; + else + vf_state = BAT_DETECTED; + } else { + vf_state = BAT_DETECTED; + cnt = 0; + } + + if (info->present == BATT_STATUS_PRESENT + && vf_state == BAT_NOT_DETECTED) { + pr_info("%s : detbat state(->%d) changed\n", + __func__, vf_state); + info->present = BATT_STATUS_MISSING; + cancel_work_sync(&info->monitor_work); + queue_work(info->monitor_wqueue, &info->monitor_work); + } else if (info->present == BATT_STATUS_MISSING + && vf_state == BAT_DETECTED) { + pr_info("%s : detbat state(->%d) changed\n", + __func__, vf_state); + info->present = BATT_STATUS_PRESENT; + cancel_work_sync(&info->monitor_work); + queue_work(info->monitor_wqueue, &info->monitor_work); + } + + return value.intval; +} +#endif +static int sec_bat_set_fuelgauge_reset(struct sec_bat_info *info) +{ +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) + struct power_supply *psy = power_supply_get_by_name("fuelgauge"); + union power_supply_propval value; + + if (!psy) { + pr_err("%s: fail to get fuel gauge ps\n", __func__); + return -ENODEV; + } + + psy->set_property(psy, + POWER_SUPPLY_PROP_FUELGAUGE_STATE, &value); + + return value.intval; +#else + return -ENODEV; +#endif +} + +static int sec_bat_get_fuelgauge_data(struct sec_bat_info *info, int type) +{ + struct power_supply *psy + = power_supply_get_by_name(info->fuel_gauge_name); + union power_supply_propval value; + + if (!psy) { + dev_err(info->dev, "%s: fail to get fuel gauge ps\n", __func__); + return -ENODEV; + } + + switch (type) { + case FG_T_VCELL: + value.intval = 0; /*vcell */ + psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &value); + break; + case FG_T_SOC: + value.intval = 0; /*normal soc */ + psy->get_property(psy, POWER_SUPPLY_PROP_CAPACITY, &value); +#if defined(CONFIG_TARGET_LOCALE_USA) + /* According to the SAMSUMG inner charger charging concept, + Full charging process should be divided into 2 phase + as 1st UI full charging, 2nd real full charging. + This is for the 1st UI Full charging. + */ + if (info->ui_full_charge_status && + info->charging_status == POWER_SUPPLY_STATUS_CHARGING) + value.intval = 100; +#endif + break; + case FG_T_PSOC: + value.intval = 1; /*raw soc */ + psy->get_property(psy, POWER_SUPPLY_PROP_CAPACITY, &value); + break; + case FG_T_RCOMP: + value.intval = 2; /*rcomp */ + psy->get_property(psy, POWER_SUPPLY_PROP_CAPACITY, &value); + break; + case FG_T_FSOC: + value.intval = 3; /*full soc */ + psy->get_property(psy, POWER_SUPPLY_PROP_CAPACITY, &value); + break; + default: + return -ENODEV; + } + + return value.intval; +} + +static int sec_bat_get_property(struct power_supply *ps, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_bat_info *info = container_of(ps, struct sec_bat_info, + psy_bat); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (info->test_info.test_value == 999) { + pr_info("%s : test case : %d\n", __func__, + info->test_info.test_value); + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + } else if (info->is_timeout_chgstop && + info->charging_status == POWER_SUPPLY_STATUS_FULL) { + /* + new concept : in case of time-out charging stop, + Do not update FULL for UI, + Use same time-out value + for first charing and re-charging + */ + val->intval = POWER_SUPPLY_STATUS_CHARGING; + } else if (info->recharging_status) { + val->intval = POWER_SUPPLY_STATUS_FULL; + } else { +#if defined(CONFIG_TARGET_LOCALE_USA) + if (info->ui_full_charge_status && + info->charging_status == + POWER_SUPPLY_STATUS_CHARGING) { + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + } +#endif + val->intval = info->charging_status; + } + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = info->batt_health; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = info->present; + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = info->batt_temp; + break; + case POWER_SUPPLY_PROP_ONLINE: + if (info->charging_status == POWER_SUPPLY_STATUS_DISCHARGING && + info->cable_type != CABLE_TYPE_NONE) { + val->intval = CABLE_TYPE_NONE; + } else + val->intval = info->cable_type; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = sec_bat_get_fuelgauge_data(info, FG_T_VCELL); + if (val->intval == -1) + return -EINVAL; + break; + case POWER_SUPPLY_PROP_CAPACITY: + if (!info->is_timeout_chgstop && + info->charging_status == POWER_SUPPLY_STATUS_FULL) { + val->intval = 100; + break; + } +#if defined(CONFIG_TARGET_LOCALE_USA) + if (info->ui_full_charge_status && + info->charging_status == POWER_SUPPLY_STATUS_CHARGING) { + val->intval = 100; + break; + } +#endif + val->intval = info->batt_soc; + if (val->intval == -1) + return -EINVAL; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + default: + return -EINVAL; + } + return 0; +} + +static int sec_bat_handle_charger_topoff(struct sec_bat_info *info) +{ + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + struct power_supply *psy_fg = + power_supply_get_by_name(info->fuel_gauge_name); + union power_supply_propval value; + int ret = 0; + + if (!psy || !psy_fg) { + pr_err("%s: fail to get charger ps\n", __func__); + return -ENODEV; + } + + if (info->batt_full_status == BATT_NOT_FULL) { + info->charging_status = POWER_SUPPLY_STATUS_FULL; + info->batt_full_status = BATT_FULL; + info->recharging_status = false; + info->charging_passed_time = 0; + info->charging_start_time = 0; +#if defined(CONFIG_TARGET_LOCALE_USA) + info->ui_full_charge_status = false; +#endif + /* disable charging */ + value.intval = POWER_SUPPLY_STATUS_DISCHARGING; + ret = psy->set_property(psy, + POWER_SUPPLY_PROP_STATUS, &value); + info->charging_enabled = false; + /* notify full state to fuel guage */ + value.intval = POWER_SUPPLY_STATUS_FULL; + ret = psy_fg->set_property(psy_fg, POWER_SUPPLY_PROP_STATUS, + &value); + } + return ret; +} + +static int sec_bat_is_charging(struct sec_bat_info *info) +{ + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + union power_supply_propval value; + int ret; + + if (!psy) { + dev_err(info->dev, "%s: fail to get charger ps\n", __func__); + return -ENODEV; + } + + ret = psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &value); + if (ret < 0) { + dev_err(info->dev, "%s: fail to get status(%d)\n", __func__, + ret); + return ret; + } + + return value.intval; +} + +static int sec_bat_is_invalid_bmd(struct sec_bat_info *info) +{ + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + union power_supply_propval value; + int ret; + + if (!psy) { + dev_err(info->dev, "%s: fail to get charger ps\n", __func__); + return -ENODEV; + } + + ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &value); + if (ret < 0) { + dev_err(info->dev, "%s: fail to get online status(%d)\n", + __func__, ret); + return ret; + } + + pr_debug("%s : retun value = %d\n", __func__, value.intval); + return value.intval; +} + +static void sec_otg_work(struct work_struct *work) +{ + struct sec_bat_info *info = + container_of(work, struct sec_bat_info, otg_work.work); + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + union power_supply_propval val_type; + + if (!psy) { + dev_err(info->dev, "%s: fail to get charger ps\n", __func__); + return; + } + + val_type.intval = info->otg_state; + psy->set_property(psy, POWER_SUPPLY_PROP_OTG, &val_type); +} + +static int sec_bat_set_property(struct power_supply *ps, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sec_bat_info *info = container_of(ps, struct sec_bat_info, + psy_bat); + + int chg_status = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + chg_status = sec_bat_is_charging(info); + pr_info("%s: %d\n", __func__, chg_status); + + if (val->intval & POWER_SUPPLY_STATUS_FULL) { + if (val->intval & POWER_SUPPLY_STATUS_CHARGING) { + pr_info("%s: re-charging!!\n", __func__); + if (info->charging_status != + POWER_SUPPLY_STATUS_FULL) { + if (info->batt_vcell >= + info->full_cond_voltage) + info->charging_status = + POWER_SUPPLY_STATUS_FULL; + else { + pr_info("%s: skip re-charging process!!\n", + __func__); + info->charging_status = + POWER_SUPPLY_STATUS_CHARGING; + info->charging_enabled = true; + cancel_work_sync(&info->monitor_work); + queue_work(info->monitor_wqueue, + &info->monitor_work); + return 0; + } + } + info->recharging_status = false; + info->is_rechg_triggered = true; + info->test_info.is_rechg_state = true; + info->test_info.rechg_count = 0; + } else if (val->intval & + POWER_SUPPLY_STATUS_DISCHARGING) { + pr_info("%s: full-charging!!\n", __func__); + } else { + pr_err("%s: unknown chg intr state!!\n", + __func__); + return -EINVAL; + } + cancel_work_sync(&info->monitor_work); + queue_work(info->monitor_wqueue, + &info->monitor_work); + } else { + if (val->intval & POWER_SUPPLY_STATUS_CHARGING) { + info->dcin_intr_triggered = true; + pr_info("%s: charger inserted!!\n", __func__); + } else if (val->intval & + POWER_SUPPLY_STATUS_DISCHARGING) { + info->dcin_intr_triggered = false; + pr_info("%s: charger removed!!\n", __func__); + } else { + pr_err("%s: unknown chg intr state!!\n", + __func__); + return -EINVAL; + } + cancel_delayed_work(&info->measure_work); + queue_delayed_work(info->monitor_wqueue, + &info->measure_work, HZ); + } +/* + if (val->intval == POWER_SUPPLY_STATUS_CHARGING) { + pr_info("%s: charger inserted!!\n", __func__); + info->dcin_intr_triggered = true; + cancel_delayed_work(&info->measure_work); + queue_delayed_work(info->monitor_wqueue, + &info->measure_work, HZ); + } else if (val->intval == POWER_SUPPLY_STATUS_DISCHARGING) { + pr_info("%s: charger removed!!\n", __func__); + info->dcin_intr_triggered = false; + cancel_delayed_work(&info->measure_work); + queue_delayed_work(info->monitor_wqueue, + &info->measure_work, HZ); + } else { + pr_err("%s: unknown chg intr state!!\n", __func__); + return -EINVAL; + } +*/ + break; + + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: + dev_info(info->dev, "%s: lowbatt intr\n", __func__); + if (val->intval != POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL) + return -EINVAL; + queue_work(info->monitor_wqueue, &info->monitor_work); + break; + case POWER_SUPPLY_PROP_ONLINE: + /* cable is attached or detached. called by usb switch ic */ + dev_info(info->dev, "%s: cable was changed(%d), prev(%d)\n", + __func__, val->intval, info->prev_cable); + switch (val->intval) { + case POWER_SUPPLY_TYPE_BATTERY: + info->cable_type = CABLE_TYPE_NONE; +#if defined(CONFIG_TARGET_LOCALE_USA) + info->cable_uart_off = false; +#endif + break; + case POWER_SUPPLY_TYPE_MAINS: + info->cable_type = CABLE_TYPE_AC; + break; + case POWER_SUPPLY_TYPE_USB: + info->cable_type = CABLE_TYPE_USB; + break; + case POWER_SUPPLY_TYPE_MISC: + info->cable_type = CABLE_TYPE_MISC; + break; + case POWER_SUPPLY_TYPE_CARDOCK: + info->cable_type = CABLE_TYPE_CARDOCK; + break; + case POWER_SUPPLY_TYPE_UARTOFF: + info->cable_type = CABLE_TYPE_UARTOFF; +#if defined(CONFIG_TARGET_LOCALE_USA) + info->cable_uart_off = true; +#endif + break; +#ifdef CONFIG_WIRELESS_CHARGING + case POWER_SUPPLY_TYPE_WPC: + info->cable_type = CABLE_TYPE_WPC; + info->wc_status = true; + break; +#endif + case POWER_SUPPLY_TYPE_USB_CDP: + info->cable_type = CABLE_TYPE_CDP; + break; + case POWER_SUPPLY_TYPE_SMART_DOCK: + info->cable_type = CABLE_TYPE_SMART_DOCK; + break; + default: + return -EINVAL; + } + if (info->prev_cable != info->cable_type) { + queue_delayed_work(info->monitor_wqueue, + &info->cable_work, 0); + } + + if (info->cable_type && + !info->charging_enabled && + (info->charging_status + != POWER_SUPPLY_STATUS_FULL) && + (info->batt_health + == POWER_SUPPLY_HEALTH_GOOD)) { + queue_delayed_work(info->monitor_wqueue, + &info->cable_work, 0); + } + info->prev_cable = info->cable_type; + break; + case POWER_SUPPLY_PROP_OTG: + info->otg_state = val->intval; + queue_delayed_work(info->monitor_wqueue, &info->otg_work, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int sec_usb_get_property(struct power_supply *ps, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_bat_info *info = container_of(ps, struct sec_bat_info, + psy_usb); + + if (psp != POWER_SUPPLY_PROP_ONLINE) + return -EINVAL; + + /* Set enable=1 only if the USB charger is connected */ + if (info->cable_type == CABLE_TYPE_USB || + info->cable_type == CABLE_TYPE_CDP) + val->intval = 1; + else + val->intval = 0; + + return 0; +} + +static int sec_ac_get_property(struct power_supply *ps, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sec_bat_info *info = container_of(ps, struct sec_bat_info, + psy_ac); + + if (psp != POWER_SUPPLY_PROP_ONLINE) + return -EINVAL; + + /* Set enable=1 only if the AC charger is connected */ + if (info->charging_status == POWER_SUPPLY_STATUS_DISCHARGING && + info->cable_type != CABLE_TYPE_NONE) { + val->intval = 0; + } else { + if (info->cable_type == CABLE_TYPE_MISC || + info->cable_type == CABLE_TYPE_UARTOFF || + info->cable_type == CABLE_TYPE_CARDOCK) { + if (!info->dcin_intr_triggered) + val->intval = 0; + else + val->intval = 1; + } else { + /* org */ + val->intval = (info->cable_type == CABLE_TYPE_AC) || +#ifdef CONFIG_WIRELESS_CHARGING + (info->cable_type == CABLE_TYPE_WPC) || +#endif + (info->cable_type == CABLE_TYPE_UNKNOWN); + } + } + pr_debug("%s : cable type = %d, return val = %d\n", + __func__, info->cable_type, val->intval); + return 0; +} + +#ifdef ADJUST_RCOMP_WITH_TEMPER +static int sec_fg_update_temper(struct sec_bat_info *info) +{ + struct power_supply *psy + = power_supply_get_by_name(info->fuel_gauge_name); + union power_supply_propval value; + int ret; + + if (!psy) { + pr_err("%s: fail to get fuelgauge ps\n", __func__); + return -ENODEV; + } + + /* Notify temperature to fuel gauge */ + if (info->fuel_gauge_name) { + value.intval = info->batt_temp / 10; + ret = psy->set_property(psy, POWER_SUPPLY_PROP_TEMP, &value); + if (ret) { + dev_err(info->dev, "%s: fail to set temperature(%d)\n", + __func__, ret); + return ret; + } + } + return 0; +} +#endif + +static int pm8921_get_temperature_adc(struct sec_bat_info *info) +{ + int rc = 0; + struct pm8xxx_adc_chan_result result = {0, 0, 0, 0}; + + rc = pm8xxx_adc_mpp_config_read(TEMP_GPIO, TEMP_ADC_CHNNEL, &result); + if (rc) { + pr_err("error reading mpp %d, rc = %d\n", TEMP_GPIO, rc); + return rc; + } + pr_debug("batt_temp phy = %lld meas = 0x%llx\n", + result.physical, result.measurement); + + info->batt_temp = (int)result.physical; + info->batt_temp_adc = (int)result.measurement; + +#ifdef ADJUST_RCOMP_WITH_TEMPER + sec_fg_update_temper(info); +#endif + + return info->batt_temp; +} + +static int sec_bat_check_temper_adc(struct sec_bat_info *info) +{ + int rescale_adc = 0; + int health = info->batt_health; + int high_recovery = info->tspec.high_recovery; + + pm8921_get_temperature_adc(info); + + rescale_adc = info->batt_temp; + + if (info->test_info.test_value == 1) { + pr_info("%s : test case : %d\n", __func__, + info->test_info.test_value); + rescale_adc = info->tspec.high_block + 1; + if (info->cable_type == CABLE_TYPE_NONE) + rescale_adc = info->tspec.high_recovery - 1; + info->batt_temp = rescale_adc; + } + + if (info->cable_type == CABLE_TYPE_NONE || + info->test_info.test_value == 999) { + info->batt_temp_high_cnt = 0; + info->batt_temp_low_cnt = 0; + health = POWER_SUPPLY_HEALTH_GOOD; + goto skip_hupdate; + } +#ifdef CONFIG_WIRELESS_CHARGING + if ((info->high_recovery_wpc) && + (info->cable_type == CABLE_TYPE_WPC)) { + high_recovery = info->high_recovery_wpc; + } else { + high_recovery = info->tspec.high_recovery; + } +#endif + +#if defined(CONFIG_BATTERY_CTIA) + if (info->batt_use) { + if (rescale_adc >= info->tspec.event_block) { + if (health != POWER_SUPPLY_HEALTH_OVERHEAT) + if (info->batt_temp_high_cnt + <= TEMP_BLOCK_COUNT) + info->batt_temp_high_cnt++; + } else if (rescale_adc <= high_recovery && + rescale_adc >= info->tspec.low_recovery) { + if (health == POWER_SUPPLY_HEALTH_OVERHEAT || + health == POWER_SUPPLY_HEALTH_COLD) { + info->batt_temp_high_cnt = 0; + info->batt_temp_low_cnt = 0; + } + } else if (rescale_adc <= info->tspec.low_block) { + if (health != POWER_SUPPLY_HEALTH_COLD) + if (info->batt_temp_low_cnt + <= TEMP_BLOCK_COUNT) + info->batt_temp_low_cnt++; + } + } else { + if (rescale_adc >= info->tspec.high_block) { + if (health != POWER_SUPPLY_HEALTH_OVERHEAT) + if (info->batt_temp_high_cnt + <= TEMP_BLOCK_COUNT) + info->batt_temp_high_cnt++; + } else if (rescale_adc <= high_recovery && + rescale_adc >= info->tspec.low_recovery) { + if (health == POWER_SUPPLY_HEALTH_OVERHEAT + || health == POWER_SUPPLY_HEALTH_COLD) { + info->batt_temp_high_cnt = 0; + info->batt_temp_low_cnt = 0; + } + } else if (rescale_adc <= info->tspec.low_block) { + if (health != POWER_SUPPLY_HEALTH_COLD) + if (info->batt_temp_low_cnt + <= TEMP_BLOCK_COUNT) + info->batt_temp_low_cnt++; + } + + } +#else + if (rescale_adc >= info->tspec.high_block) { + if (health != POWER_SUPPLY_HEALTH_OVERHEAT) + if (info->batt_temp_high_cnt <= TEMP_BLOCK_COUNT) + info->batt_temp_high_cnt++; + } else if (rescale_adc <= high_recovery && + rescale_adc >= info->tspec.low_recovery) { + if (health == POWER_SUPPLY_HEALTH_OVERHEAT || + health == POWER_SUPPLY_HEALTH_COLD) { + info->batt_temp_high_cnt = 0; + info->batt_temp_low_cnt = 0; + } + } else if (rescale_adc <= info->tspec.low_block) { + if (health != POWER_SUPPLY_HEALTH_COLD) + if (info->batt_temp_low_cnt <= TEMP_BLOCK_COUNT) + info->batt_temp_low_cnt++; + } +#endif + if (info->batt_temp_high_cnt >= TEMP_BLOCK_COUNT) { + health = POWER_SUPPLY_HEALTH_OVERHEAT; + wake_lock_timeout(&info->monitor_wake_lock, 10 * HZ); + } else if (info->batt_temp_low_cnt >= TEMP_BLOCK_COUNT) { + health = POWER_SUPPLY_HEALTH_COLD; + wake_lock_timeout(&info->monitor_wake_lock, 10 * HZ); + } else { + health = POWER_SUPPLY_HEALTH_GOOD; + } +skip_hupdate: + if (info->batt_health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE && + info->batt_health != POWER_SUPPLY_HEALTH_DEAD && + health != info->batt_health) { + info->batt_health = health; + cancel_work_sync(&info->monitor_work); + queue_work(info->monitor_wqueue, &info->monitor_work); + } + + return 0; +} + +static void check_chgcurrent(struct sec_bat_info *info) +{ + pr_debug("[battery] charging current doesn't exist\n"); +} + +static void sec_check_chgcurrent(struct sec_bat_info *info) +{ + static int cnt; + static int cnt_ui; + bool is_full_condition = false; + + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + union power_supply_propval value; + int ret; + + if (!psy) { + dev_err(info->dev, "%s: fail to get charger ps\n", __func__); + return; + } + + if (info->charging_enabled) { + check_chgcurrent(info); + if (info->batt_vcell >= info->full_cond_voltage) { + /* check full state with SMB charger register */ + ret = + psy->get_property(psy, + POWER_SUPPLY_PROP_CHARGE_FULL, + &value); + if (ret < 0) { + dev_err(info->dev, + "%s: fail to get charge full(%d)\n", + __func__, ret); + return; + } + + if (info->test_info.test_value == 3) { + value.intval = 0; + info->batt_current_adc = + CURRENT_OF_FULL_CHG + 1; + } + + info->is_top_off = value.intval; + + if (info->batt_current_adc == 0) { + if (info->is_top_off == 1 && + info->batt_presoc >= 99) { + if (is_full_condition == false) + wake_lock_timeout( + &info->monitor_wake_lock, + 10 * HZ); + is_full_condition = true; + pr_info + ("%s : is_top_off (%d)\n", + __func__, + info->batt_current_adc); + } else + is_full_condition = false; + + } else { + /* adc data is ok */ +#if defined(CONFIG_TARGET_LOCALE_USA) + if (info->charging_status != + POWER_SUPPLY_STATUS_FULL + && info->batt_current_adc <= + CURRENT_OF_FULL_CHG_UI + && !info->ui_full_charge_status) { + cnt_ui++; + if (cnt_ui >= info->full_cond_count) { + info->ui_full_charge_status = + true; + cnt_ui = 0; + power_supply_changed(&info-> + psy_bat); + } + } +#endif /* CONFIG_TARGET_LOCALE_USA */ +/* +//[Jaguar, D2] disable until ADC ready to get charging current + if (info->batt_current_adc <= + CURRENT_OF_FULL_CHG) { + is_full_condition = true; + } else { + is_full_condition = false; + } +*/ + } + if (is_full_condition) { + cnt++; + pr_info("%s : full state? %d, %d\n", __func__, + info->batt_current_adc, cnt); + if (cnt >= info->full_cond_count) { + pr_info("%s : full state!! %d/%d\n", + __func__, cnt, + info->full_cond_count); + sec_bat_handle_charger_topoff(info); + cnt = 0; + } + } + } else { + cnt = 0; + cnt_ui = 0; + } + } else { + cnt = 0; + cnt_ui = 0; + info->batt_current_adc = 0; + } + info->test_info.full_count = cnt; +} + +static int sec_check_recharging(struct sec_bat_info *info) +{ + int cnt = 0; + int ret = 0; + + if (info->charging_status != POWER_SUPPLY_STATUS_FULL || + info->recharging_status != false) { + return 0; + } + + for (cnt = 0; cnt < 4; cnt++) { + info->batt_vcell = sec_bat_get_fuelgauge_data(info, FG_T_VCELL); + if ((info->batt_vcell > info->vrechg) || + (info->charging_status != POWER_SUPPLY_STATUS_FULL)) + return 0; + else { + pr_info("%s : cnt = %d\n", __func__, cnt); + mdelay(5000); + } + } + if (cnt == 4) { + ret = 1; + info->test_info.is_rechg_state = true; + pr_info("if rechg(%d), cnt(%d)\n", ret, cnt); + } else + ret = 0; + pr_info("[BAT] rechg(%d), cnt(%d)\n", ret, cnt); + + info->test_info.rechg_count = cnt; + return ret; +} + +static int sec_bat_notify_vcell2charger(struct sec_bat_info *info) +{ + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + union power_supply_propval val_vcell; + int ret; + + if (!psy) { + dev_err(info->dev, "%s: fail to get charger ps\n", __func__); + return -ENODEV; + } + + /* Notify Voltage Now */ + val_vcell.intval = info->batt_vcell; + ret = psy->set_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &val_vcell); + if (ret) { + dev_err(info->dev, "%s: fail to notify vcell now(%d)\n", + __func__, ret); + return ret; + } + + return 0; +} + +static void sec_bat_update_info(struct sec_bat_info *info) +{ + info->batt_presoc = info->batt_soc; + info->batt_raw_soc = sec_bat_get_fuelgauge_data(info, FG_T_PSOC); + info->batt_soc = sec_bat_get_fuelgauge_data(info, FG_T_SOC); + info->batt_vcell = sec_bat_get_fuelgauge_data(info, FG_T_VCELL); + info->batt_rcomp = sec_bat_get_fuelgauge_data(info, FG_T_RCOMP); + info->batt_full_soc = sec_bat_get_fuelgauge_data(info, FG_T_FSOC); + sec_bat_notify_vcell2charger(info); +} + +static int sec_bat_enable_charging(struct sec_bat_info *info, bool enable) +{ + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + union power_supply_propval val_type, val_chg_current, val_topoff, + val_vcell; + int ret; + + ktime_t current_time; + struct timespec ts; + + current_time = alarm_get_elapsed_realtime(); + ts = ktime_to_timespec(current_time); + + if (!psy) { + dev_err(info->dev, "%s: fail to get charger ps\n", __func__); + return -ENODEV; + } + + info->batt_full_status = BATT_NOT_FULL; + + if (enable) { + switch (info->cable_type) { + case CABLE_TYPE_USB: + val_type.intval = POWER_SUPPLY_STATUS_CHARGING; + val_chg_current.intval = 500; + info->current_avg = -1; + break; + case CABLE_TYPE_AC: + case CABLE_TYPE_CARDOCK: + case CABLE_TYPE_UARTOFF: + case CABLE_TYPE_CDP: + case CABLE_TYPE_SMART_DOCK: + val_type.intval = POWER_SUPPLY_STATUS_CHARGING; + val_chg_current.intval = 900; + info->current_avg = 0; + break; +#ifdef CONFIG_WIRELESS_CHARGING + case CABLE_TYPE_WPC: + val_type.intval = POWER_SUPPLY_STATUS_CHARGING; + val_chg_current.intval = info->wpc_charging_current; + if (info->wpc_charging_current == 700) + info->current_avg = 0; + else + info->current_avg = -1; + break; +#endif + case CABLE_TYPE_MISC: + val_type.intval = POWER_SUPPLY_STATUS_CHARGING; + val_chg_current.intval = 700; + info->current_avg = -1; + break; + case CABLE_TYPE_UNKNOWN: + val_type.intval = POWER_SUPPLY_STATUS_CHARGING; + val_chg_current.intval = 900; + info->current_avg = 0; + break; + default: + dev_err(info->dev, "%s: Invalid func use\n", __func__); + return -EINVAL; + } + + /* Set charging current */ + ret = psy->set_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, + &val_chg_current); + if (ret) { + dev_err(info->dev, "%s: fail to set charging cur(%d)\n", + __func__, ret); + return ret; + } + + /* Set topoff current */ + val_topoff.intval = info->iterm; + ret = psy->set_property(psy, POWER_SUPPLY_PROP_CHARGE_FULL, + &val_topoff); + if (ret) { + dev_err(info->dev, "%s: fail to set topoff val(%d)\n", + __func__, ret); + return ret; + } + + /* Notify Voltage Now */ + info->batt_vcell = sec_bat_get_fuelgauge_data(info, FG_T_VCELL); + val_vcell.intval = info->batt_vcell; + ret = psy->set_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, + &val_vcell); + if (ret) { + dev_err(info->dev, "%s: fail to notify vcell now(%d)\n", + __func__, ret); + return ret; + } + + info->charging_start_time = ts.tv_sec; + } else { + /* Disable charging */ + val_type.intval = POWER_SUPPLY_STATUS_DISCHARGING; + info->charging_passed_time = 0; + info->charging_start_time = 0; + info->current_avg = -1; + + /* Double check recharging */ + info->recharging_status = false; + } + + ret = psy->set_property(psy, POWER_SUPPLY_PROP_STATUS, &val_type); + if (ret) { + dev_err(info->dev, "%s: fail to set charging status(%d)\n", + __func__, ret); + return ret; + } + + if (info->present == BATT_STATUS_MISSING) { + pr_info("[battery] battery is missing, suspend SMB347 charger\n"); + psy->set_property(psy, POWER_SUPPLY_PROP_PRESENT, &val_type); + } + + info->charging_enabled = enable; + + return 0; +} + +#ifdef ADJUST_RCOMP_WITH_CHARGING_STATUS +static int sec_fg_update_rcomp(struct sec_bat_info *info) +{ + struct power_supply *psy + = power_supply_get_by_name(info->fuel_gauge_name); + union power_supply_propval value; + int ret; + + if (!psy) { + pr_err("%s: fail to get fuelgauge ps\n", __func__); + return -ENODEV; + } + + if (info->fuel_gauge_name) { + value.intval = info->charging_status; + ret = psy->set_property(psy, + POWER_SUPPLY_PROP_STATUS, &value); + if (ret) { + dev_err(info->dev, "%s: fail to set status(%d)\n", + __func__, ret); + return ret; + } + } + return 0; +} +#endif + +static void sec_bat_handle_unknown_disable(struct sec_bat_info *info) +{ + pr_info(" %s : cable_type = %d\n", __func__, info->cable_type); + + if (info->present == BATT_STATUS_MISSING) + return; + + info->batt_full_status = BATT_NOT_FULL; + info->recharging_status = false; + info->test_info.is_rechg_state = false; + info->charging_start_time = 0; +#if defined(CONFIG_TARGET_LOCALE_USA) + info->ui_full_charge_status = false; +#endif +#ifdef CONFIG_WIRELESS_CHARGING + info->wc_status = false; +#endif + info->charging_status = POWER_SUPPLY_STATUS_DISCHARGING; + info->is_timeout_chgstop = false; +#ifdef ADJUST_RCOMP_WITH_CHARGING_STATUS + sec_fg_update_rcomp(info); +#endif + sec_bat_enable_charging(info, false); + + power_supply_changed(&info->psy_bat); +} + +static void sec_bat_cable_work(struct work_struct *work) +{ + struct sec_bat_info *info = container_of(work, struct sec_bat_info, + cable_work.work); + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + union power_supply_propval val_input; + int ret = 0; + u8 pok_cnt = 0; + + wake_lock(&info->cable_wake_lock); + + if ((info->present == BATT_STATUS_MISSING) + && (info->cable_type != CABLE_TYPE_NONE)) { + pr_info("[battery] VF is open, do not care cable_work\n"); + info->batt_health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + psy->set_property(psy, POWER_SUPPLY_PROP_PRESENT, &val_input); + queue_work(info->monitor_wqueue, &info->monitor_work); + goto cable_skip; + } + + switch (info->cable_type) { + case CABLE_TYPE_NONE: +#if defined(CONFIG_CHARGER_SMB347) && \ + defined(CONFIG_WIRELESS_CHARGING) + /* check charger state*/ + ret = psy->get_property(psy, + POWER_SUPPLY_PROP_WIRELESS_CHARGING, + &val_input); + if (!ret) { + if (info->wc_status == false && + val_input.intval == INPUT_DCIN) { + info->wc_status = true; + info->cable_type = CABLE_TYPE_WPC; + ret = psy->set_property(psy, + POWER_SUPPLY_PROP_WIRELESS_CHARGING, + &val_input); + if (ret < 0) + pr_err("%s : failed to set charger state(%d)\n", + __func__, ret); + queue_delayed_work(info->monitor_wqueue, + &info->cable_work, + msecs_to_jiffies(500)); + pr_info("cable none : power source is dcin. retry cable work!!!\n"); + return; + } + } else + pr_err("%s : failed to get input source(%d)\n", + __func__, ret); +#endif + /* TODO : check DCIN state again */ + while (1) { + if ((sec_bat_is_charging(info) + == POWER_SUPPLY_STATUS_CHARGING) + && info->dcin_intr_triggered + && !info->slate_mode) { + pok_cnt++; + if (pok_cnt >= 2) { + pr_info("cable none : vdcin ok, skip!!!\n"); + wake_unlock(&info->cable_wake_lock); + return; + } + msleep(300); + } else { + pr_info("cable none : vdcin nok, cable is removed.\n"); + break; + } + } + +/* if (info->batt_int_irq_use) { + info->present = BATT_STATUS_PRESENT; + info->batt_health = POWER_SUPPLY_HEALTH_GOOD; + disable_irq_nosync(info->batt_int_irq); + }*/ + wake_lock_timeout(&info->vbus_wake_lock, 5 * HZ); + cancel_delayed_work(&info->measure_work); + info->batt_full_status = BATT_NOT_FULL; + info->recharging_status = false; + info->test_info.is_rechg_state = false; + info->charging_start_time = 0; + info->charging_status = POWER_SUPPLY_STATUS_DISCHARGING; + info->is_timeout_chgstop = false; + info->dcin_intr_triggered = false; +#if defined(CONFIG_TARGET_LOCALE_USA) + info->ui_full_charge_status = false; +#endif +#ifdef CONFIG_WIRELESS_CHARGING + info->wc_status = false; +#endif + sec_bat_enable_charging(info, false); + info->measure_interval = MEASURE_DSG_INTERVAL; + queue_delayed_work(info->monitor_wqueue, &info->measure_work, + HZ / 2); + break; + case CABLE_TYPE_MISC: + case CABLE_TYPE_CARDOCK: + case CABLE_TYPE_UARTOFF: + if (!info->dcin_intr_triggered && !info->lpm_chg_mode) { + wake_lock_timeout(&info->vbus_wake_lock, 5 * HZ); + pr_info("%s : dock inserted, but dcin nok skip charging!\n", + __func__); + sec_bat_enable_charging(info, true); + info->charging_enabled = false; + break; + } + case CABLE_TYPE_UNKNOWN: + case CABLE_TYPE_USB: + case CABLE_TYPE_AC: + case CABLE_TYPE_CDP: + case CABLE_TYPE_SMART_DOCK: +#if defined(CONFIG_CHARGER_SMB347) && \ + defined(CONFIG_WIRELESS_CHARGING) + case CABLE_TYPE_WPC: + /* set input state */ + ret = psy->get_property(psy, + POWER_SUPPLY_PROP_WIRELESS_CHARGING, + &val_input); + if (!ret) { + if (info->wc_status == true && + val_input.intval != INPUT_DCIN) { + info->wc_status = false; + ret = psy->set_property(psy, + POWER_SUPPLY_PROP_WIRELESS_CHARGING, + &val_input); + if (ret < 0) + pr_err("%s : failed to set input source(%d)\n", + __func__, ret); + } + } else + pr_err("%s : failed to get input source(%d)\n", + __func__, ret); +#endif + +/* + if (((info->cable_type == CABLE_TYPE_AC) || + (info->cable_type == CABLE_TYPE_USB)) && + (info->batt_int != 0)) { + enable_irq(info->batt_int_irq); + info->batt_int_irq_use = 1; + info->present = + !gpio_get_value_cansleep(info->batt_int); + } +*/ + + wake_lock_timeout(&info->vbus_wake_lock, 5 * HZ); + cancel_delayed_work(&info->measure_work); + info->charging_status = POWER_SUPPLY_STATUS_CHARGING; + sec_bat_enable_charging(info, true); + info->measure_interval = MEASURE_CHG_INTERVAL; + queue_delayed_work(info->monitor_wqueue, &info->measure_work, + HZ / 2); + queue_work(info->monitor_wqueue, &info->monitor_work); + break; + default: + dev_err(info->dev, "%s: Invalid cable type\n", __func__); + break; + } + +cable_skip: +#ifdef ADJUST_RCOMP_WITH_CHARGING_STATUS + sec_fg_update_rcomp(info); +#endif + power_supply_changed(&info->psy_ac); + power_supply_changed(&info->psy_usb); + power_supply_changed(&info->psy_bat); + + wake_unlock(&info->cable_wake_lock); +} + +static void sec_bat_charging_time_management(struct sec_bat_info *info) +{ + unsigned long charging_time=0; + ktime_t current_time; + struct timespec ts; + + current_time = alarm_get_elapsed_realtime(); + ts = ktime_to_timespec(current_time); + + /* If timeout_chgstop is already set, then re-start charging */ + if (info->is_timeout_chgstop) { + info->is_timeout_chgstop = false; + if (info->charging_status == POWER_SUPPLY_STATUS_FULL) + info->recharging_status = true; + sec_bat_enable_charging(info, true); + pr_info("%s: [BATT] chgstop is cancelled\n", + __func__); + } + + if (info->charging_start_time == 0) { + pr_debug("%s: charging_start_time=0\n", __func__); + return; + } + + if (info->charging_enabled) { + if (ts.tv_sec >= info->charging_start_time) + charging_time = ts.tv_sec - info->charging_start_time; + else + charging_time = 0xFFFFFFFF - info->charging_start_time + + ts.tv_sec; + + info->charging_passed_time = charging_time; + } + + switch (info->charging_status) { + case POWER_SUPPLY_STATUS_FULL: + if (charging_time > info->rechg_time && + info->recharging_status == true) { + sec_bat_enable_charging(info, false); + info->recharging_status = false; + info->is_timeout_chgstop = true; + pr_info("%s: [BATT]Recharging timer expired\n", + __func__); + } + break; + case POWER_SUPPLY_STATUS_CHARGING: + if (charging_time > info->abs_time) { + sec_bat_enable_charging(info, false); + info->charging_status = POWER_SUPPLY_STATUS_FULL; + info->is_timeout_chgstop = true; + + pr_info("%s: [BATT]Charging timer expired\n", + __func__); + } + break; + default: + info->is_timeout_chgstop = false; + return; + } + + dev_dbg(info->dev, "[BATT]Time past : %lu secs, Spec : %d, %d\n", + charging_time, + info->abs_time, info->rechg_time); + + return; +} + +static void sec_bat_monitor_work(struct work_struct *work) +{ + int i; + struct sec_bat_info *info = container_of(work, struct sec_bat_info, + monitor_work); + struct power_supply *psy_fg = + power_supply_get_by_name(info->fuel_gauge_name); + struct power_supply *psy_smb = + power_supply_get_by_name(info->charger_name); + + union power_supply_propval value; + struct timespec ts; + int ret = 0; + + wake_lock(&info->monitor_wake_lock); + + if (!psy_fg) { + pr_err("%s: fail to get charger ps\n", __func__); + goto monitoring_skip; + } + + pm8921_enable_batt_therm(1); + /* check battery 5 times */ + for (i = 0; i < 5; i++) { + msleep(500); + info->present = !gpio_get_value_cansleep(info->batt_int); + + /* If the battery is missing, then check more */ + if (info->present) { + i++; + break; + } + } + pm8921_enable_batt_therm(0); + pr_info("%s: battery check is %s (%d time%c)\n", + __func__, info->present ? "present" : "absent", + i, (i == 1) ? ' ' : 's'); + + if ((info->present == BATT_STATUS_MISSING) + && (info->cable_type != CABLE_TYPE_NONE)) { + pr_info("[battery] battery is missing, suspend SMB347 charger\n"); + psy_smb->set_property(psy_smb, + POWER_SUPPLY_PROP_PRESENT, &value); + } + +#ifdef CONFIG_WIRELESS_CHARGING + if (info->wpc_abs_time && + (info->cable_type == CABLE_TYPE_WPC)) { + info->abs_time = info->wpc_abs_time; + pr_debug("[battery] wpc abs time (%d)\n", info->abs_time); + } else { + info->abs_time = info->normal_abs_time; + pr_debug("[battery] normal abs time (%d)\n", + info->abs_time); + } +#endif + + sec_bat_charging_time_management(info); + + sec_bat_update_info(info); + sec_bat_check_vf(info); + sec_check_chgcurrent(info); + +#ifdef ADJUST_RCOMP_WITH_TEMPER + sec_fg_update_temper(info); +#endif + pr_info("[battery] level(%d), vcell(%d), therm(%d)\n", + info->batt_soc, info->batt_vcell, info->batt_temp); + pr_info("[battery] cable_type(%d), chg_status(%d), health(%d)\n", + info->cable_type, info->charging_status, info->batt_health); + pr_info("[battery] timeout_chgstp(%d), chg_enabled(%d), rechg_status(%d)\n", + info->is_timeout_chgstop, info->charging_enabled, + info->recharging_status); + + if (sec_check_recharging(info)) { + pr_info("%s : rechg triggered!\n", __func__); + info->is_rechg_triggered = true; + } + + switch (info->charging_status) { + case POWER_SUPPLY_STATUS_FULL: + /* notify full state to fuel guage */ + info->check_full_state = true; + if (!info->is_timeout_chgstop) { + value.intval = POWER_SUPPLY_STATUS_FULL; + ret = + psy_fg->set_property(psy_fg, + POWER_SUPPLY_PROP_STATUS, + &value); + } + + if (info->is_rechg_triggered && + info->recharging_status == false) { + info->recharging_status = true; + sec_bat_enable_charging(info, true); + info->is_rechg_triggered = false; + + dev_info(info->dev, + "%s: Start Recharging, Vcell = %d\n", __func__, + info->batt_vcell); + } + /* break; */ + case POWER_SUPPLY_STATUS_CHARGING: + if (info->batt_health == POWER_SUPPLY_HEALTH_OVERHEAT + || info->batt_health == POWER_SUPPLY_HEALTH_COLD) { + sec_bat_enable_charging(info, false); + info->charging_status = + POWER_SUPPLY_STATUS_NOT_CHARGING; + info->test_info.is_rechg_state = false; + + pr_info("%s: Not charging\n", __func__); + } else if (info->batt_health == + POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) { + sec_bat_enable_charging(info, false); + info->charging_status = + POWER_SUPPLY_STATUS_NOT_CHARGING; + info->test_info.is_rechg_state = false; + pr_info("%s: Not charging (VF err!)\n", + __func__); + } + break; + case POWER_SUPPLY_STATUS_DISCHARGING: + dev_dbg(info->dev, "%s: Discharging\n", __func__); + if ((info->batt_health == + POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) && + (info->cable_type != CABLE_TYPE_NONE)) { + sec_bat_enable_charging(info, false); + info->charging_status = + POWER_SUPPLY_STATUS_NOT_CHARGING; + info->test_info.is_rechg_state = false; + pr_info("%s: Not charging (VF err!)\n", + __func__); + } + break; + case POWER_SUPPLY_STATUS_NOT_CHARGING: + if (info->batt_health == POWER_SUPPLY_HEALTH_GOOD) { + dev_info(info->dev, "%s: recover health state\n", + __func__); + if (info->cable_type != CABLE_TYPE_NONE) { + sec_bat_enable_charging(info, true); + info->charging_status + = POWER_SUPPLY_STATUS_CHARGING; + } else + info->charging_status + = POWER_SUPPLY_STATUS_DISCHARGING; + } + break; + default: + pr_err("%s: Undefined Battery Status\n", __func__); + goto monitoring_skip; + } + + /* check default charger state, and set again */ + if (sec_bat_is_charging(info) == POWER_SUPPLY_STATUS_CHARGING && + info->charging_enabled) { + if (sec_bat_is_invalid_bmd(info)) { + pr_info("%s : default charger state, set again\n", + __func__); + queue_delayed_work(info->monitor_wqueue, + &info->cable_work, 0); + } + } + + if (info->check_full_state == true && + info->charging_status == POWER_SUPPLY_STATUS_DISCHARGING) { + if (info->check_full_state_cnt <= 1) { + info->batt_soc = 100; + info->check_full_state_cnt++; + } else { + if (info->batt_presoc > info->batt_soc) { + info->batt_soc = info->batt_presoc - 1; + } else { + info->check_full_state = false; + info->check_full_state_cnt = 0; + } + } + } + + if (info->batt_soc != info->batt_presoc) + pr_info("[fg] p:%d, s1:%d, s2:%d, v:%d, t:%d\n", + info->batt_raw_soc, info->batt_soc, info->batt_presoc, + info->batt_vcell, info->batt_temp_radc); + + power_supply_changed(&info->psy_bat); + +monitoring_skip: + info->cur_monitor_time = alarm_get_elapsed_realtime(); + ts = ktime_to_timespec(info->cur_monitor_time); + + sec_bat_monitoring_alarm(info, CHARGING_ALARM_INTERVAL); + wake_unlock(&info->monitor_wake_lock); + + return; +} + +static void sec_bat_measure_work(struct work_struct *work) +{ + struct sec_bat_info *info = + container_of(work, struct sec_bat_info, measure_work.work); + unsigned long flags; + bool isFirstCheck = false; + + wake_lock(&info->measure_wake_lock); + + sec_bat_check_temper_adc(info); + /* sec_bat_check_detbat(info); */ + + /* check dcin */ + if ((sec_bat_is_charging(info) == POWER_SUPPLY_STATUS_CHARGING) && + (info->charging_status == POWER_SUPPLY_STATUS_DISCHARGING)) { + pr_info + ("%s : dcin ok, but not charging, set cable type again!\n", + __func__); + if (0 == is_charging_disabled) { + local_irq_save(flags); + if (info->cable_type == CABLE_TYPE_NONE) { +#if defined(CONFIG_TARGET_LOCALE_USA) + if (info->cable_uart_off) + info->cable_type = CABLE_TYPE_UARTOFF; + else +#endif + info->cable_type = CABLE_TYPE_UNKNOWN; + } + + local_irq_restore(flags); + queue_delayed_work(info->monitor_wqueue, + &info->cable_work, HZ); + } + } else + if ((sec_bat_is_charging(info) == POWER_SUPPLY_STATUS_DISCHARGING) + && (info->charging_status != POWER_SUPPLY_STATUS_DISCHARGING)) { + pr_info("%s : dcin nok, but still charging, just disable charging!\n", + __func__); + local_irq_save(flags); + if (info->cable_type == CABLE_TYPE_UNKNOWN || +#ifdef CONFIG_WIRELESS_CHARGING + info->cable_type == CABLE_TYPE_WPC || +#endif + info->cable_type == CABLE_TYPE_UARTOFF) + info->cable_type = CABLE_TYPE_NONE; + local_irq_restore(flags); + sec_bat_handle_unknown_disable(info); + } + + if (info->charging_enabled && + (((0 < info->batt_temp_high_cnt) + && (info->batt_temp_high_cnt < TEMP_BLOCK_COUNT)) + || ((0 < info->batt_temp_low_cnt) + && (info->batt_temp_low_cnt < TEMP_BLOCK_COUNT)))) { + isFirstCheck = true; + } else { + isFirstCheck = false; + } + + if (info->initial_check_count) { + info->initial_check_count--; + queue_delayed_work(info->monitor_wqueue, &info->measure_work, + HZ); + } else if (isFirstCheck) { + queue_delayed_work(info->monitor_wqueue, &info->measure_work, + HZ); + } else { + queue_delayed_work(info->monitor_wqueue, &info->measure_work, + msecs_to_jiffies(info->measure_interval)); + } + wake_unlock(&info->measure_wake_lock); +} + +/* +static irqreturn_t batt_removal_handler(int irq, struct sec_bat_info *info) +{ + struct power_supply *psy = power_supply_get_by_name(info->charger_name); + union power_supply_propval value; + int ret = 0; + + if (!psy) { + pr_err("%s: fail to get charger ps\n", __func__); + return -ENODEV; + } + + ret = gpio_get_value_cansleep(info->batt_int); + pr_info("%s, %d\n", __func__, ret); + + if (ret < 0) { + pr_err("%s batt_in gpio failed ret=%d\n", + __func__, ret); + goto err; + } + + info->present = ret ? 0 : 1; + if (ret) + psy->set_property(psy, POWER_SUPPLY_PROP_PRESENT, &value); +err: + return IRQ_HANDLED; +} +*/ + +#define SEC_BATTERY_ATTR(_name) \ +{ \ + .attr = { .name = #_name, \ + .mode = 0664, \ + /*.owner = THIS_MODULE */}, \ + .show = sec_bat_show_property, \ + .store = sec_bat_store, \ +} + +static struct device_attribute sec_battery_attrs[] = { + SEC_BATTERY_ATTR(batt_vol), + SEC_BATTERY_ATTR(batt_read_adj_soc), + SEC_BATTERY_ATTR(batt_vfocv), + SEC_BATTERY_ATTR(batt_vf_adc), + SEC_BATTERY_ATTR(batt_temp), + SEC_BATTERY_ATTR(batt_temp_adc), + SEC_BATTERY_ATTR(batt_temp_radc), + SEC_BATTERY_ATTR(batt_charging_source), + SEC_BATTERY_ATTR(batt_lp_charging), + SEC_BATTERY_ATTR(batt_type), + SEC_BATTERY_ATTR(batt_full_check), + SEC_BATTERY_ATTR(batt_temp_check), + SEC_BATTERY_ATTR(batt_temp_adc_spec), + SEC_BATTERY_ATTR(batt_test_value), + SEC_BATTERY_ATTR(batt_current_adc), + SEC_BATTERY_ATTR(batt_esus_test), + SEC_BATTERY_ATTR(sys_rev), + SEC_BATTERY_ATTR(fg_psoc), + SEC_BATTERY_ATTR(batt_reset_soc), +#ifdef CONFIG_WIRELESS_CHARGING + SEC_BATTERY_ATTR(wc_status), + SEC_BATTERY_ATTR(wc_adc), +#endif +#if !defined(CONFIG_BATTERY_CTIA) + SEC_BATTERY_ATTR(talk_wcdma), + SEC_BATTERY_ATTR(talk_gsm), + SEC_BATTERY_ATTR(data_call), + SEC_BATTERY_ATTR(camera), + SEC_BATTERY_ATTR(browser), +#endif + SEC_BATTERY_ATTR(charging_enable), +#if defined(CONFIG_BATTERY_CTIA) + SEC_BATTERY_ATTR(talk_wcdma), + SEC_BATTERY_ATTR(talk_gsm), + SEC_BATTERY_ATTR(call), + SEC_BATTERY_ATTR(video), + SEC_BATTERY_ATTR(music), + SEC_BATTERY_ATTR(browser), + SEC_BATTERY_ATTR(hotspot), + SEC_BATTERY_ATTR(camera), + SEC_BATTERY_ATTR(data_call), + SEC_BATTERY_ATTR(gps), + SEC_BATTERY_ATTR(lte), + SEC_BATTERY_ATTR(wifi), + SEC_BATTERY_ATTR(batt_use), +#endif /*CONFIG_BATTERY_CTIA*/ + SEC_BATTERY_ATTR(batt_slate_mode), + SEC_BATTERY_ATTR(current_avg), + SEC_BATTERY_ATTR(factory_mode), +}; + +enum { + BATT_VOL = 0, + BATT_SOC, + BATT_VFOCV, + BATT_VFADC, + BATT_TEMP, + BATT_TEMP_ADC, + BATT_TEMP_RADC, + BATT_CHARGING_SOURCE, + BATT_LP_CHARGING, + BATT_TYPE, + BATT_FULL_CHECK, + BATT_TEMP_CHECK, + BATT_TEMP_ADC_SPEC, + BATT_TEST_VALUE, + BATT_CURRENT_ADC, + BATT_ESUS_TEST, + BATT_SYSTEM_REV, + BATT_FG_PSOC, + BATT_RESET_SOC, +#ifdef CONFIG_WIRELESS_CHARGING + BATT_WC_STATUS, + BATT_WC_ADC, +#endif +#if !defined(CONFIG_BATTERY_CTIA) + BATT_WCDMA_CALL, + BATT_GSM_CALL, + BATT_DATACALL, + BATT_CAMERA, + BATT_BROWSER, +#endif + BATT_CHARGING_ENABLE, +#if defined(CONFIG_BATTERY_CTIA) + BATT_WCDMA_CALL, + BATT_GSM_CALL, + BATT_CALL, + BATT_VIDEO, + BATT_MUSIC, + BATT_BROWSER, + BATT_HOTSPOT, + BATT_CAMERA, + BATT_DATA_CALL, + BATT_GPS, + BATT_LTE, + BATT_WIFI, + BATT_USE, +#endif /*CONFIG_BATTERY_CTIA*/ + BATT_SLATE_MODE, + BATT_CURR_AVG, + BATT_FACTORY, +}; + +#if defined(CONFIG_BATTERY_CTIA) +static void sec_bat_program_alarm(struct sec_bat_info *info, + int seconds) +{ + ktime_t low_interval = ktime_set(seconds - 10, 0); + ktime_t slack = ktime_set(20, 0); + ktime_t next; + + next = ktime_add(info->cur_time, low_interval); + alarm_start_range(&info->event_alarm, next, ktime_add(next, slack)); +} + +static void sec_bat_use_timer_func(struct alarm *alarm) +{ + struct sec_bat_info *info = + container_of(alarm, struct sec_bat_info, event_alarm); + info->batt_use &= (~info->batt_use_wait); + pr_info("/BATT_USE/ timer expired (0x%x)\n", info->batt_use); +} + +static void sec_bat_use_module(struct sec_bat_info *info, + int module, int enable) +{ + struct timespec ts; + + /* ignore duplicated deactivation of same event */ + if (!enable && (info->batt_use == info->batt_use_wait)) { + pr_info("/BATT_USE/ ignore duplicated same event\n"); + return; + } + + /*del_timer_sync(&info->bat_use_timer);*/ + alarm_cancel(&info->event_alarm); + info->batt_use &= (~info->batt_use_wait); + + if (enable) { + info->batt_use_wait = 0; + info->batt_use |= module; + + /* debug msg */ + if (module == USE_CALL) + pr_info("/BATT_USE/ call 0x%x\n", info->batt_use); + else if (module == USE_VIDEO) + pr_info("/BATT_USE/ video 0x%x\n", info->batt_use); + else if (module == USE_MUSIC) + pr_info("/BATT_USE/ music 0x%x\n", info->batt_use); + else if (module == USE_BROWSER) + pr_info("/BATT_USE/ browser 0x%x\n", info->batt_use); + else if (module == USE_HOTSPOT) + pr_info("/BATT_USE/ hotspot 0x%x\n", info->batt_use); + else if (module == USE_CAMERA) + pr_info("/BATT_USE/ camera 0x%x\n", info->batt_use); + else if (module == USE_DATA_CALL) + pr_info("/BATT_USE/ datacall 0x%x\n", info->batt_use); + else if (module == USE_LTE) + pr_info("/BATT_USE/ lte 0x%x\n", info->batt_use); + else if (module == USE_WIFI) + pr_info("/BATT_USE/ wifi 0x%x\n", info->batt_use); + } else { + if (info->batt_use == 0) { + pr_info("/BATT_USE/ nothing to clear\n"); + return; /* nothing to clear */ + } + info->batt_use_wait = module; + info->cur_time = alarm_get_elapsed_realtime(); + ts = ktime_to_timespec(info->cur_time); + + sec_bat_program_alarm(info, TOTAL_EVENT_TIME); + pr_info("/BATT_USE/ start timer (curr 0x%x, wait 0x%x)\n", + info->batt_use, info->batt_use_wait); + } +} + +#endif /*CONFIG_BATTERY_CTIA*/ + +static ssize_t sec_bat_show_property(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sec_bat_info *info = dev_get_drvdata(dev->parent); + int i = 0, val = 0; + const ptrdiff_t off = attr - sec_battery_attrs; + + switch (off) { + case BATT_VOL: + val = sec_bat_get_fuelgauge_data(info, FG_T_VCELL); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_SOC: + val = sec_bat_get_fuelgauge_data(info, FG_T_SOC); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_VFOCV: + /* max17048 doesn't have VFOCV register */ + pr_err("skip! MAX17048 doesn't have VFOCV register.\n"); + break; + case BATT_VFADC: + /* read batt_id */ + break; + case BATT_TEMP: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", info->batt_temp); + break; + case BATT_TEMP_ADC: + pm8921_get_temperature_adc(info); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + info->batt_temp_adc); + break; + case BATT_TEMP_RADC: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + info->batt_temp_radc); + break; + case BATT_CHARGING_SOURCE: + val = info->cable_type; + /*val = 2; // for lpm test */ + if (info->lpm_chg_mode && + info->cable_type != CABLE_TYPE_NONE && + info->charging_status == POWER_SUPPLY_STATUS_DISCHARGING) { + val = CABLE_TYPE_NONE; + } + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; + case BATT_LP_CHARGING: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + poweroff_charging); + break; + case BATT_TYPE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", "SDI_SDI"); + break; + case BATT_FULL_CHECK: + /* new concept : in case of time-out charging stop, + Do not update FULL for UI, + Use same time-out value for first charing and re-charging + */ + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->is_timeout_chgstop == false && + info->charging_status == + POWER_SUPPLY_STATUS_FULL) + ? 1 : 0); + break; + case BATT_TEMP_CHECK: + i += scnprintf(buf + i, PAGE_SIZE - i, + "%d\n", info->batt_health); + break; + case BATT_TEMP_ADC_SPEC: + i += scnprintf(buf + i, PAGE_SIZE - i, + "(HIGH: %d / %d, LOW: %d / %d)\n", + info->tspec.high_block, + info->tspec.high_recovery, + info->tspec.low_block, + info->tspec.low_recovery); + break; + case BATT_TEST_VALUE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + info->test_info.test_value); + break; + case BATT_CURRENT_ADC: + check_chgcurrent(info); +#ifdef CONFIG_WIRELESS_CHARGING + i += scnprintf(buf + i, PAGE_SIZE - i, + "%d\n", + (info->wc_status == false) ? + info->batt_current_adc : 0); +#else + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + info->batt_current_adc); +#endif + break; + case BATT_ESUS_TEST: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + info->test_info.test_esuspend); + break; + case BATT_SYSTEM_REV: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", info->hw_rev); + break; + case BATT_FG_PSOC: + val = sec_bat_get_fuelgauge_data(info, FG_T_PSOC); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + break; +#if defined(CONFIG_BATTERY_CTIA) + case BATT_WCDMA_CALL: + case BATT_GSM_CALL: + case BATT_CALL: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & USE_CALL) ? 1 : 0); + break; + case BATT_VIDEO: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & USE_VIDEO) ? 1 : 0); + break; + case BATT_MUSIC: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & USE_MUSIC) ? 1 : 0); + break; + case BATT_BROWSER: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & USE_BROWSER) ? 1 : 0); + break; + case BATT_HOTSPOT: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & USE_HOTSPOT) ? 1 : 0); + break; + case BATT_CAMERA: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & USE_CAMERA) ? 1 : 0); + break; + case BATT_DATA_CALL: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & USE_DATA_CALL) ? 1 : 0); + break; + case BATT_GPS: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & USE_GPS) ? 1 : 0); + break; + case BATT_LTE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & USE_GPS) ? 1 : 0); + break; + case BATT_WIFI: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + (info->batt_use & BATT_WIFI) ? 1 : 0); + break; + case BATT_USE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + info->batt_use); + break; +#endif + case BATT_CHARGING_ENABLE: + { + int val = (info->charging_enabled) ? 1 : 0; + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); + } + break; +#ifdef CONFIG_WIRELESS_CHARGING + case BATT_WC_STATUS: + i += scnprintf(buf + i, PAGE_SIZE - i, + "%d\n", + (info->wc_status == true) ? + 1 : 0); + break; + case BATT_WC_ADC: + check_chgcurrent(info); + i += scnprintf(buf + i, PAGE_SIZE - i, + "%d\n", + (info->wc_status == true) ? + info->batt_current_adc : 0); + break; +#endif + case BATT_SLATE_MODE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + info->slate_mode); + break; + case BATT_CURR_AVG: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + info->current_avg); + break; + default: + i = -EINVAL; + } + + return i; +} + +static ssize_t sec_bat_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret = 0, x = 0; + const ptrdiff_t off = attr - sec_battery_attrs; + struct sec_bat_info *info = dev_get_drvdata(dev->parent); + + switch (off) { + case BATT_ESUS_TEST: /* early_suspend test */ + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 0) { + info->test_info.test_esuspend = 0; + wake_lock_timeout(&info->test_wake_lock, + 5 * HZ); + cancel_delayed_work(&info->measure_work); + info->measure_interval = MEASURE_DSG_INTERVAL; + queue_delayed_work(info->monitor_wqueue, + &info->measure_work, 0); + } else { + info->test_info.test_esuspend = 1; + wake_lock(&info->test_wake_lock); + cancel_delayed_work(&info->measure_work); + info->measure_interval = MEASURE_CHG_INTERVAL; + queue_delayed_work(info->monitor_wqueue, + &info->measure_work, 0); + } + ret = count; + } + break; + case BATT_TEST_VALUE: + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 0) + info->test_info.test_value = 0; + else if (x == 1) { + /* for temp warning event */ + info->test_info.test_value = 1; + } else if (x == 2) { + /* + // for full event + info->test_info.test_value = 2; + */ + /* disable full test interface. */ + info->test_info.test_value = 0; + } else if (x == 3) { + /* for abs time event */ + info->test_info.test_value = 3; + } else if (x == 999) { + /* for pop-up disable */ + info->test_info.test_value = 999; + if ((info->batt_health == + POWER_SUPPLY_HEALTH_OVERHEAT) + || (info->batt_health == + POWER_SUPPLY_HEALTH_COLD)) { + info->batt_health = + POWER_SUPPLY_HEALTH_GOOD; + queue_work(info->monitor_wqueue, + &info->monitor_work); + } + } else + info->test_info.test_value = 0; + pr_info("%s : test case : %d\n", __func__, + info->test_info.test_value); + ret = count; + } + break; + case BATT_RESET_SOC: + pr_info("battery reset soc\n"); + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 1) { + sec_bat_set_fuelgauge_reset(info); + ret = count; + } + } + break; + +#if !defined(CONFIG_BATTERY_CTIA) + case BATT_WCDMA_CALL: + case BATT_GSM_CALL: + if (sscanf(buf, "%d\n", &x) == 1) { + info->voice_call_state = x; + pr_info("%s : voice call = %d, %d\n", __func__, + x, info->voice_call_state); + } + break; + case BATT_DATACALL: + if (sscanf(buf, "%d\n", &x) == 1) + dev_dbg(info->dev, "%s : data call = %d\n", __func__, + x); + break; + case BATT_CAMERA: + if (sscanf(buf, "%d\n", &x) == 1) + ret = count; + break; + case BATT_BROWSER: + if (sscanf(buf, "%d\n", &x) == 1) + ret = count; + break; +#endif + case BATT_CHARGING_ENABLE: + { + pr_info("%s : BATT_CHARGING_ENABLE buf=[%s]\n", + __func__, buf); + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 0) { + is_charging_disabled = 1; + info->cable_type = CABLE_TYPE_NONE; + queue_delayed_work(info->monitor_wqueue, + &info->cable_work, + 0); + } else if (x == 1) { + is_charging_disabled = 0; + info->cable_type = CABLE_TYPE_UNKNOWN; + queue_delayed_work(info->monitor_wqueue, + &info->cable_work, + 0); + } else + pr_info("%s:Invalid\n", __func__); + ret = count; + } + } + break; +#if defined(CONFIG_BATTERY_CTIA) + case BATT_WCDMA_CALL: + case BATT_GSM_CALL: + case BATT_CALL: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_CALL, x); + ret = count; + } + pr_debug("[BAT]:%s: camera = %d\n", __func__, x); + break; + case BATT_VIDEO: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_VIDEO, x); + ret = count; + } + pr_debug("[BAT]:%s: mp3 = %d\n", __func__, x); + break; + case BATT_MUSIC: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_MUSIC, x); + ret = count; + } + pr_debug("[BAT]:%s: video = %d\n", __func__, x); + break; + case BATT_BROWSER: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_BROWSER, x); + ret = count; + } + pr_debug("[BAT]:%s: voice call 2G = %d\n", __func__, x); + break; + case BATT_HOTSPOT: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_HOTSPOT, x); + ret = count; + } + pr_debug("[BAT]:%s: voice call 3G = %d\n", __func__, x); + break; + case BATT_CAMERA: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_CAMERA, x); + ret = count; + } + pr_debug("[BAT]:%s: data call = %d\n", __func__, x); + break; + case BATT_DATA_CALL: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_DATA_CALL, x); + ret = count; + } + pr_debug("[BAT]:%s: wifi = %d\n", __func__, x); + break; + case BATT_GPS: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_GPS, x); + ret = count; + } + break; + case BATT_LTE: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_LTE, x); + ret = count; + } + pr_debug("[BAT]:%s: gps = %d\n", __func__, x); + break; + case BATT_WIFI: + if (sscanf(buf, "%d\n", &x) == 1) { + sec_bat_use_module(info, USE_WIFI, x); + ret = count; + } + pr_debug("[BAT]:%s: gps = %d\n", __func__, x); + break; +#endif + case BATT_SLATE_MODE: + { + pr_info("%s : BATT_SLATE_MODE %s\n", + __func__, buf); + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 1) { + info->slate_mode = true; + is_charging_disabled = 1; + info->cable_type = CABLE_TYPE_NONE; + queue_delayed_work(info->monitor_wqueue, + &info->cable_work, + 0); + } else if (x == 0) { + info->slate_mode = false; + is_charging_disabled = 0; + info->cable_type = CABLE_TYPE_UNKNOWN; + queue_delayed_work(info->monitor_wqueue, + &info->cable_work, + 0); + } else + pr_info("%s:Invalid\n", __func__); + ret = count; + } + } + break; + case BATT_FACTORY: + if (sscanf(buf, "%d\n", &x) == 1) { + if (x) + info->factory_mode = true; + else + info->factory_mode = false; + ret = count; + } + pr_info("[battery]:%s: factory mode = %d\n", __func__, x); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int sec_bat_create_attrs(struct device *dev) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(sec_battery_attrs); i++) { + rc = device_create_file(dev, &sec_battery_attrs[i]); + if (rc) + goto sec_attrs_failed; + } + goto succeed; + +sec_attrs_failed: + while (i--) + device_remove_file(dev, &sec_battery_attrs[i]); +succeed: + return rc; +} + +static int sec_bat_read_proc(char *buf, char **start, + off_t offset, int count, int *eof, void *data) +{ + struct sec_bat_info *info = data; + struct timespec cur_time; + ktime_t ktime; + int len = 0; + + ktime = alarm_get_elapsed_realtime(); + cur_time = ktime_to_timespec(ktime); + + len = sprintf(buf, + "%lu, %u, %u, %u, %u, %d, %u, %d, %d, %d, %u, %u, %u, %d, %u, %u, 0x%04x, %u, %lu\n", + cur_time.tv_sec, info->batt_raw_soc, + info->batt_soc, info->batt_vcell, + info->batt_current_adc, info->charging_enabled, + info->batt_full_status, + info->test_info.full_count, info->test_info.rechg_count, + info->test_info.is_rechg_state, info->recharging_status, + info->batt_temp_radc, info->batt_health, info->charging_status, + info->present, info->cable_type, info->batt_rcomp, + info->batt_full_soc, info->charging_passed_time); + return len; +} + +static void sec_bat_early_suspend(struct early_suspend *handle) +{ + struct sec_bat_info *info = container_of(handle, struct sec_bat_info, + bat_early_suspend); + + pr_info("%s[BATT]...\n", __func__); + info->is_esus_state = true; + + return; +} + +static void sec_bat_late_resume(struct early_suspend *handle) +{ + struct sec_bat_info *info = container_of(handle, struct sec_bat_info, + bat_early_suspend); + + pr_info("%s[BATT]...\n", __func__); + info->is_esus_state = false; + + return; +} + +static __devinit int sec_bat_probe(struct platform_device *pdev) +{ + struct sec_bat_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct sec_bat_info *info; + int ret = 0; + + if (!pdata->sec_battery_using()) { + pr_info("%s: SEC Battery driver Loading SKIP!!!\n", __func__); + return -EINVAL; + } + pr_info("%s: SEC Battery Driver Loading\n", __func__); + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + platform_set_drvdata(pdev, info); + + info->dev = &pdev->dev; + if (!pdata->fuel_gauge_name || !pdata->charger_name) { + dev_err(info->dev, "%s: no fuel gauge or charger name\n", + __func__); + goto err_kfree; + } + pr_info("[battery] enable Vref_batt_therm\n"); + pm8921_enable_batt_therm(1); + + info->fuel_gauge_name = pdata->fuel_gauge_name; + info->charger_name = pdata->charger_name; + info->hw_rev = system_rev; + info->present = BATT_STATUS_UNKNOWN; + info->current_avg = -1; + + info->psy_bat.name = "battery", + info->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, + info->psy_bat.properties = sec_battery_props, + info->psy_bat.num_properties = ARRAY_SIZE(sec_battery_props), + info->psy_bat.get_property = sec_bat_get_property, + info->psy_bat.set_property = sec_bat_set_property, + info->psy_usb.name = "usb", + info->psy_usb.type = POWER_SUPPLY_TYPE_USB, + info->psy_usb.supplied_to = supply_list, + info->psy_usb.num_supplicants = ARRAY_SIZE(supply_list), + info->psy_usb.properties = sec_power_props, + info->psy_usb.num_properties = ARRAY_SIZE(sec_power_props), + info->psy_usb.get_property = sec_usb_get_property, + info->psy_ac.name = "ac", + info->psy_ac.type = POWER_SUPPLY_TYPE_MAINS, + info->psy_ac.supplied_to = supply_list, + info->psy_ac.num_supplicants = ARRAY_SIZE(supply_list), + info->psy_ac.properties = sec_power_props, + info->psy_ac.num_properties = ARRAY_SIZE(sec_power_props), + info->psy_ac.get_property = sec_ac_get_property; + + wake_lock_init(&info->vbus_wake_lock, WAKE_LOCK_SUSPEND, + "vbus_present"); + wake_lock_init(&info->monitor_wake_lock, WAKE_LOCK_SUSPEND, + "sec-battery-monitor"); + wake_lock_init(&info->cable_wake_lock, WAKE_LOCK_SUSPEND, + "sec-battery-cable"); + wake_lock_init(&info->test_wake_lock, WAKE_LOCK_SUSPEND, + "bat_esus_test"); + wake_lock_init(&info->measure_wake_lock, WAKE_LOCK_SUSPEND, + "sec-battery-measure"); + + info->batt_health = POWER_SUPPLY_HEALTH_GOOD; + info->charging_status = sec_bat_is_charging(info); + pr_info("%s: initial charging_status = %d\n", __func__, + info->charging_status); + + if (info->charging_status == POWER_SUPPLY_STATUS_CHARGING) { + info->cable_type = CABLE_TYPE_UNKNOWN; + info->prev_cable = CABLE_TYPE_NONE; + } else { + info->charging_status = POWER_SUPPLY_STATUS_DISCHARGING; + info->cable_type = CABLE_TYPE_NONE; + info->prev_cable = CABLE_TYPE_NONE; + } + + info->batt_vcell = sec_bat_get_fuelgauge_data(info, FG_T_VCELL); + info->batt_soc = sec_bat_get_fuelgauge_data(info, FG_T_SOC); + info->batt_temp = RCOMP0_TEMP * 10; + info->recharging_status = false; + info->is_timeout_chgstop = false; + info->is_esus_state = false; + info->is_rechg_triggered = false; + info->dcin_intr_triggered = false; +#if defined(CONFIG_TARGET_LOCALE_USA) + info->ui_full_charge_status = false; +#endif + info->initial_check_count = INIT_CHECK_COUNT; + + info->charging_start_time = 0; + info->slate_mode = false; + info->factory_mode = false; + info->check_full_state = false; + info->check_full_state_cnt = 0; + +#ifdef CONFIG_WIRELESS_CHARGING + info->wpc_charging_current = pdata->wpc_charging_current; +#endif /*CONFIG_WIRELESS_CHARGING*/ + + if (poweroff_charging) + info->lpm_chg_mode = true; + else + info->lpm_chg_mode = false; + + if ((poweroff_charging) && (pdata->lpm_high_block != 0)) { + info->tspec.high_block = pdata->lpm_high_block; + info->tspec.high_recovery = pdata->lpm_high_recovery; + info->tspec.low_block = pdata->lpm_low_block; + info->tspec.low_recovery = pdata->lpm_low_recovery; + } else { + if (pdata->high_block != 0) { + info->tspec.event_block = pdata->event_block; + info->tspec.high_block = pdata->high_block; + info->tspec.high_recovery = pdata->high_recovery; + info->tspec.low_block = pdata->low_block; + info->tspec.low_recovery = pdata->low_recovery; + } else { + info->tspec.event_block = DEFAULT_HIGH_BLOCK_TEMP; + info->tspec.high_block = DEFAULT_HIGH_BLOCK_TEMP; + info->tspec.high_recovery = DEFAULT_HIGH_RECOVER_TEMP; + info->tspec.low_block = DEFAULT_LOW_BLOCK_TEMP; + info->tspec.low_recovery = DEFAULT_LOW_RECOVER_TEMP; + } + } + + if (pdata->high_recovery_wpc) + info->high_recovery_wpc = pdata->high_recovery_wpc; + else + info->high_recovery_wpc = 0; + + if (info->charging_status == POWER_SUPPLY_STATUS_CHARGING) + info->measure_interval = MEASURE_CHG_INTERVAL; + else + info->measure_interval = MEASURE_DSG_INTERVAL; + + if (!pdata->recharge_voltage) { + if (pdata->check_batt_type) { + if (pdata->check_batt_type()) { + pdata->max_voltage = 4350 * 1000; + pdata->recharge_voltage = 4280 * 1000; + } + } + } + + if (pdata->max_voltage != 0) { + info->vmax = pdata->max_voltage; + info->full_cond_count = FULL_CHG_COND_COUNT; + info->full_cond_voltage = + pdata->max_voltage - 100000; + } else { + info->vmax = DEFAULT_MAX_VOLTAGE; + info->full_cond_count = FULL_CHG_COND_COUNT; + info->full_cond_voltage = FULL_CHARGE_COND_VOLTAGE; + } + + if (pdata->recharge_voltage != 0) + info->vrechg = pdata->recharge_voltage; + else + info->vrechg = DEFAULT_RECHG_VOLTAGE; + + if (pdata->charge_duration != 0 && + pdata->recharge_duration != 0) { + info->abs_time = pdata->charge_duration; + info->normal_abs_time = pdata->charge_duration; + info->rechg_time = pdata->recharge_duration; + } else { + info->abs_time = DEFAULT_CHG_TIME; + info->normal_abs_time = DEFAULT_CHG_TIME; + info->rechg_time = DEFAULT_RECHG_TIME; + } + + if (pdata->wpc_charge_duration != 0) + info->wpc_abs_time = pdata->wpc_charge_duration; + else + info->wpc_abs_time = 0; + + if (pdata->iterm != 0) + info->iterm = pdata->iterm; + else + info->iterm = DEFAULT_TERMINATION_CURRENT; + + ret = power_supply_register(&pdev->dev, &info->psy_bat); + if (ret) { + dev_err(info->dev, "%s: failed to register psy_bat\n", + __func__); + goto err_wakelock_free; + } + + ret = power_supply_register(&pdev->dev, &info->psy_usb); + if (ret) { + dev_err(info->dev, "%s: failed to register psy_usb\n", + __func__); + goto err_supply_unreg_bat; + } + + ret = power_supply_register(&pdev->dev, &info->psy_ac); + if (ret) { + dev_err(info->dev, "%s: failed to register psy_ac\n", __func__); + goto err_supply_unreg_usb; + } + + /* create sec detail attributes */ + ret = sec_bat_create_attrs(info->psy_bat.dev); + if (ret) { + dev_err(info->dev, "%s: failed to create attrs\n", + __func__); + goto err_supply_unreg_ac; + } + + info->entry = create_proc_entry("batt_info_proc", S_IRUGO, NULL); + if (!info->entry) + dev_err(info->dev, "%s: failed to create proc_entry\n", + __func__); + else { + info->entry->read_proc = sec_bat_read_proc; + info->entry->data = (struct sec_bat_info *)info; + } + + info->monitor_wqueue = create_freezable_workqueue(dev_name(&pdev->dev)); + if (!info->monitor_wqueue) { + dev_err(info->dev, "%s: fail to create workqueue\n", __func__); + goto err_supply_unreg_ac; + } + +#if defined(CONFIG_BATTERY_CTIA) + alarm_init(&info->event_alarm, + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + sec_bat_use_timer_func); +#endif /*CONFIG_BATTERY_CTIA*/ + alarm_init(&info->alarm, + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + sec_bat_monitor_queue); + + if (pdata->batt_int != 0) { + info->batt_int = pdata->batt_int; + info->batt_int_irq = gpio_to_irq(pdata->batt_int); + ret = enable_irq_wake(info->batt_int_irq); + if (ret) { + pr_err("%s : Failed to enable_irq_wake[%d]\r\n", + __func__, info->batt_int_irq); + } + +/* ret = request_threaded_irq( + info->batt_int_irq, NULL, + batt_removal_handler, + (IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING), + "battery removal", info); + + if (ret) { + pr_err("%s : Failed to request batt_int irq\n", + __func__); + goto err_request_irq; + } + disable_irq(info->batt_int_irq); +*/ + } + + info->bat_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1; + info->bat_early_suspend.suspend = sec_bat_early_suspend; + info->bat_early_suspend.resume = sec_bat_late_resume; + register_early_suspend(&info->bat_early_suspend); + + INIT_WORK(&info->monitor_work, sec_bat_monitor_work); + INIT_DELAYED_WORK_DEFERRABLE(&info->cable_work, sec_bat_cable_work); + + INIT_DELAYED_WORK_DEFERRABLE(&info->measure_work, sec_bat_measure_work); + + INIT_DELAYED_WORK_DEFERRABLE(&info->otg_work, sec_otg_work); + + pdata->get_cable_type(); + + queue_delayed_work(info->monitor_wqueue, &info->measure_work, 0); + queue_work(info->monitor_wqueue, &info->monitor_work); + + return 0; +#if 0 +err_request_irq: + destroy_workqueue(info->monitor_wqueue); +#endif +err_supply_unreg_ac: + power_supply_unregister(&info->psy_ac); +err_supply_unreg_usb: + power_supply_unregister(&info->psy_usb); +err_supply_unreg_bat: + power_supply_unregister(&info->psy_bat); +err_wakelock_free: + wake_lock_destroy(&info->vbus_wake_lock); + wake_lock_destroy(&info->monitor_wake_lock); + wake_lock_destroy(&info->cable_wake_lock); + wake_lock_destroy(&info->test_wake_lock); + wake_lock_destroy(&info->measure_wake_lock); + +err_kfree: + kfree(info); + + return ret; +} + +static int __devexit sec_bat_remove(struct platform_device *pdev) +{ + struct sec_bat_info *info = platform_get_drvdata(pdev); + + remove_proc_entry("batt_info_proc", NULL); + + flush_workqueue(info->monitor_wqueue); + destroy_workqueue(info->monitor_wqueue); + + cancel_delayed_work(&info->cable_work); + cancel_delayed_work(&info->measure_work); + cancel_delayed_work(&info->otg_work); + + power_supply_unregister(&info->psy_bat); + power_supply_unregister(&info->psy_usb); + power_supply_unregister(&info->psy_ac); + + wake_lock_destroy(&info->vbus_wake_lock); + wake_lock_destroy(&info->monitor_wake_lock); + wake_lock_destroy(&info->cable_wake_lock); + wake_lock_destroy(&info->test_wake_lock); + wake_lock_destroy(&info->measure_wake_lock); + +#if defined(CONFIG_BATTERY_CTIA) + alarm_cancel(&info->event_alarm); +#endif /*CONFIG_BATTERY_CTIA*/ + alarm_cancel(&info->alarm); + kfree(info); + + return 0; +} + +static int sec_bat_suspend(struct device *dev) +{ + struct sec_bat_info *info = dev_get_drvdata(dev); + pr_info("[BATT] battery suspend!##\n"); + cancel_work_sync(&info->monitor_work); + cancel_delayed_work(&info->cable_work); + cancel_delayed_work(&info->measure_work); + cancel_delayed_work(&info->otg_work); + /*add alarm monitoring */ + info->cur_monitor_time = alarm_get_elapsed_realtime(); + + if (info->cable_type == CABLE_TYPE_NONE) { + sec_bat_monitoring_alarm(info, ALARM_INTERVAL); + info->slow_polling = 1; + } else { + sec_bat_monitoring_alarm(info, CHARGING_ALARM_INTERVAL); + } + + return 0; +} + +static void sec_bat_resume(struct device *dev) +{ + struct sec_bat_info *info = dev_get_drvdata(dev); + pr_info("[BATT] battery resume!##\n"); + if (info->slow_polling) + info->slow_polling = 0; + + queue_delayed_work(info->monitor_wqueue, &info->measure_work, 0); + + queue_work(info->monitor_wqueue, &info->monitor_work); +} + +static const struct dev_pm_ops sec_bat_pm_ops = { + .prepare = sec_bat_suspend, + .complete = sec_bat_resume, +}; + +static struct platform_driver sec_bat_driver = { + .driver = { + .name = "sec-battery", + .owner = THIS_MODULE, + .pm = &sec_bat_pm_ops, + }, + .probe = sec_bat_probe, + .remove = __devexit_p(sec_bat_remove), +}; + +static int __init sec_bat_init(void) +{ + return platform_driver_register(&sec_bat_driver); +} + +static void __exit sec_bat_exit(void) +{ + platform_driver_unregister(&sec_bat_driver); +} + +late_initcall(sec_bat_init); +module_exit(sec_bat_exit); + +MODULE_DESCRIPTION("SEC battery driver"); +MODULE_AUTHOR(""); +MODULE_AUTHOR(""); +MODULE_AUTHOR(""); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/smb347_charger.c b/drivers/power/smb347_charger.c new file mode 100644 index 00000000000..80273b7f280 --- /dev/null +++ b/drivers/power/smb347_charger.c @@ -0,0 +1,1840 @@ +/* + * SMB347-charger.c + * SMB347 charger interface driver + * + * Copyright (C) 2011 Samsung Electronics + * + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Slave address */ +#define SMB347_SLAVE_ADDR 0x0C + +/* SMB347 Registers. */ +#define SMB347_CHARGE_CURRENT 0X00 +#define SMB347_INPUT_CURRENTLIMIT 0X01 +#define SMB347_VARIOUS_FUNCTIONS 0X02 +#define SMB347_FLOAT_VOLTAGE 0X03 +#define SMB347_CHARGE_CONTROL 0X04 +#define SMB347_STAT_TIMERS_CONTROL 0x05 +#define SMB347_PIN_ENABLE_CONTROL 0x06 +#define SMB347_THERM_CONTROL_A 0x07 +#define SMB347_SYSOK_USB30_SELECTION 0x08 +#define SMB347_OTHER_CONTROL_A 0x09 +#define SMB347_OTG_TLIM_THERM_CONTROL 0x0A +#define SMB347_LIMIT_CELL_TEMPERATURE_MONITOR 0x0B +#define SMB347_FAULT_INTERRUPT 0x0C +#define SMB347_STATUS_INTERRUPT 0x0D +#define SMB347_I2C_BUS_SLAVE_ADDR 0x0E + +#define SMB347_COMMAND_A 0x30 +#define SMB347_COMMAND_B 0x31 +#define SMB347_COMMAND_C 0x33 +#define SMB347_INTERRUPT_STATUS_A 0x35 +#define SMB347_INTERRUPT_STATUS_B 0x36 +#define SMB347_INTERRUPT_STATUS_C 0x37 +#define SMB347_INTERRUPT_STATUS_D 0x38 +#define SMB347_INTERRUPT_STATUS_E 0x39 +#define SMB347_INTERRUPT_STATUS_F 0x3A +#define SMB347_STATUS_A 0x3B +#define SMB347_STATUS_B 0x3C +#define SMB347_STATUS_C 0x3D +#define SMB347_STATUS_D 0x3E +#define SMB347_STATUS_E 0x3F + +/* Status register C */ +#define SMB347_CHARGING_ENABLE (1 << 0) +#define SMB347_CHARGING_STATUS (1 << 5) +#define SMB347_CHARGER_ERROR (1 << 6) + +/* fast charging current defines */ +#define FAST_700mA 700 +#define FAST_900mA 900 +#define FAST_1200mA 1200 +#define FAST_1500mA 1500 +#define FAST_1800mA 1800 +#define FAST_2000mA 2000 +#define FAST_2200mA 2200 +#define FAST_2500mA 2500 + +/* input current limit defines */ +#define ICL_300mA 300 +#define ICL_500mA 500 +#define ICL_700mA 700 +#define ICL_900mA 900 +#define ICL_1200mA 1200 +#define ICL_1500mA 1500 +#define ICL_1800mA 1800 +#define ICL_2000mA 2000 +#define ICL_2200mA 2200 +#define ICL_2500mA 2500 + +#undef SMB347_DEBUG + +enum { + BAT_NOT_DETECTED, + BAT_DETECTED +}; + +enum { + CHG_MODE_NONE, + CHG_MODE_AC, + CHG_MODE_USB, + CHG_MODE_MISC, + CHG_MODE_UNKNOWN +}; + +enum { + OTG_DISABLE, + OTG_ENABLE +}; + +enum { + INPUT_NONE, + INPUT_DCIN, + INPUT_USBIN, +}; + +struct smb347_chip { + struct i2c_client *client; + struct delayed_work work; + struct power_supply psy_bat; + struct smb347_platform_data *pdata; + struct mutex mutex; + + int chg_mode; + unsigned int batt_vcell; + int chg_set_current; /* fast charging current */ + int chg_icl; /* input current limit */ + int lpm_chg_mode; + unsigned int float_voltage; /* float voltage */ + int aicl_current; + int aicl_status; + int otg_check; + int input_source; + int ovp_state; +}; + +static enum power_supply_property smb347_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, +}; + +static int smb347_disable_charging(struct i2c_client *client); +static int smb347_verA5; + +static int smb347_write_reg(struct i2c_client *client, int reg, u8 value) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + int ret; + + mutex_lock(&chip->mutex); + + ret = i2c_smbus_write_byte_data(client, reg, value); + + if (ret < 0) { + pr_err("%s: err %d, try again!, reg[0x%x]\n", __func__, ret, + reg); + ret = i2c_smbus_write_byte_data(client, reg, value); + if (ret < 0) + pr_err("%s: err %d, reg=0x%x\n", __func__, ret, reg); + } + + mutex_unlock(&chip->mutex); + + return ret; +} + +static int smb347_read_reg(struct i2c_client *client, int reg) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + int ret; + + mutex_lock(&chip->mutex); + + ret = i2c_smbus_read_byte_data(client, reg); + + if (ret < 0) { + pr_err("%s: err %d, try again!\n", __func__, ret); + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) + pr_err("%s: err %d\n", __func__, ret); + } + + mutex_unlock(&chip->mutex); + + return ret; +} + +#ifdef SMB347_DEBUG +static void smb347_print_reg(struct i2c_client *client, int reg) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + int data = 0; + + mutex_lock(&chip->mutex); + + data = i2c_smbus_read_byte_data(client, reg); + + if (data < 0) + pr_err("%s: err %d\n", __func__, data); + else + pr_info("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + + mutex_unlock(&chip->mutex); +} + +static void smb347_print_all_regs(struct i2c_client *client) +{ + smb347_print_reg(client, 0x00); + smb347_print_reg(client, 0x01); + smb347_print_reg(client, 0x02); + smb347_print_reg(client, 0x03); + smb347_print_reg(client, 0x04); + smb347_print_reg(client, 0x05); + smb347_print_reg(client, 0x06); + smb347_print_reg(client, 0x07); + smb347_print_reg(client, 0x08); + smb347_print_reg(client, 0x09); + smb347_print_reg(client, 0x0A); + smb347_print_reg(client, 0x30); + smb347_print_reg(client, 0x31); + smb347_print_reg(client, 0x32); + smb347_print_reg(client, 0x33); + smb347_print_reg(client, 0x34); + smb347_print_reg(client, 0x35); + smb347_print_reg(client, 0x36); + smb347_print_reg(client, 0x37); + smb347_print_reg(client, 0x38); + smb347_print_reg(client, 0x39); + smb347_print_reg(client, 0x3A); + smb347_print_reg(client, 0x3B); + smb347_print_reg(client, 0x3C); + smb347_print_reg(client, 0x3D); + smb347_print_reg(client, 0x3E); + smb347_print_reg(client, 0x3F); +} +#endif + +static void check_smb347_version(void) +{ +#if defined(CONFIG_MACH_M2_ATT) + if (system_rev >= 0x6) + smb347_verA5 = 1; +#elif defined(CONFIG_MACH_M2_SPR) + if (system_rev >= 0x6) + smb347_verA5 = 1; +#elif defined(CONFIG_MACH_M2_VZW) + if (system_rev >= 0xd) + smb347_verA5 = 1; +#elif defined(CONFIG_MACH_M2_SKT) + if (system_rev >= 0x7) + smb347_verA5 = 1; +#elif defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + if (system_rev >= 0x3) + smb347_verA5 = 1; +#elif defined(CONFIG_MACH_JAGUAR) + if (system_rev >= 0xf) + smb347_verA5 = 1; +#elif defined(CONFIG_MACH_AEGIS2) + if (system_rev >= 0x4) + smb347_verA5 = 1; +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) + smb347_verA5 = 1; +#else + smb347_verA5 = 0; +#endif +} + +static void smb347_allow_volatile_writes(struct i2c_client *client) +{ + int val, reg; + u8 data; + + /* Allow volatile writes to CONFIG registers */ + reg = SMB347_COMMAND_A; + val = smb347_read_reg(client, reg); + if ((val >= 0) && !(val & 0x80)) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + data |= (0x1 << 7); + if (smb347_write_reg(client, reg, data) < 0) + pr_err("%s : error!\n", __func__); + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) data; + pr_debug("%s : => reg (0x%x) = 0x%x\n", __func__, reg, + data); + } + } +} + +static void smb347_set_command_reg(struct i2c_client *client) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + int val, reg; + u8 data; + + reg = SMB347_COMMAND_B; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + if (chip->chg_mode == CHG_MODE_AC || + chip->chg_mode == CHG_MODE_MISC || + chip->chg_mode == CHG_MODE_UNKNOWN) { + /* CommandB : High-current mode */ + data = 0x03; + } else if (chip->chg_mode == CHG_MODE_USB) { + /* CommandB : USB5 */ + data = 0x02; + } else { + /* CommandB : USB1 */ + data = 0x00; + } + if (smb347_write_reg(client, reg, data) < 0) + pr_err("%s : error!\n", __func__); + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) data; + pr_debug("%s : => reg (0x%x) = 0x%x\n", __func__, reg, + data); + } + } +} + +static void smb347_enter_suspend(struct i2c_client *client) +{ + u8 data = 0; + + pr_info("%s: ENTER SUSPEND\n", __func__); + smb347_write_reg(client, SMB347_COMMAND_A, 0x80); + smb347_write_reg(client, SMB347_PIN_ENABLE_CONTROL, 0x18); + data = (data | 0x4); + smb347_write_reg(client, SMB347_COMMAND_A, data); +} +static int smb347_get_current_input_source(struct i2c_client *client) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + int val, val2 = 0; + + val = smb347_read_reg(client, SMB347_INTERRUPT_STATUS_F); + /* + if (val >= 0) + val |= !gpio_get_value(chip->pdata->inok); + else + val = !gpio_get_value(chip->pdata->inok); + */ + if (val & 0x01) { + val = ((smb347_read_reg(client, SMB347_STATUS_E) & 0x80) >> 7) + + INPUT_DCIN; + } else { + pr_info("%s : power is not ok(%d)\n", __func__, val); + val = INPUT_NONE; + } + + val2 = smb347_read_reg(client, SMB347_INTERRUPT_STATUS_E); + if (val2 & 0x04) { + pr_info("%s:OVP cut off input power\n", __func__); + chip->ovp_state = 1; + } + + return val; +} + +static void smb347_charger_function_conrol(struct i2c_client *client) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + int val, reg; + u8 data, set_data; + + smb347_allow_volatile_writes(client); + + /* Charge curr : Fast-chg 1500mA */ + /* Pre-charge curr 250mA, Term curr 200mA */ + smb347_write_reg(client, SMB347_CHARGE_CURRENT, 0x7C); + + /* Input current limit */ + reg = SMB347_INPUT_CURRENTLIMIT; + val = smb347_read_reg(client, reg); + + chip->input_source = smb347_get_current_input_source(chip->client); + + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + +#ifdef CONFIG_WIRELESS_CHARGING + if (chip->input_source == INPUT_DCIN) { + pr_info("[battery] INPUT_DCIN\n"); + data &= 0x0f; + if (chip->chg_mode == CHG_MODE_MISC) { + pr_info("[battery] wpc 700mA\n"); + data |= 0x20; + } else { + pr_info("[battery] wpc 500mA\n"); + data |= 0x10; + } + } +#endif /*CONFIG_WIRELESS_CHARGING*/ + + pr_info("[battery] INPUT_USBIN\n"); + data &= 0xf0; + if (chip->chg_mode == CHG_MODE_AC) { + /* 900mA limit */ + set_data = smb347_verA5 ? 0x4 : 0x3; + } else if (chip->chg_mode == CHG_MODE_MISC) + set_data = 0x2; /* 700mA limit */ + else + set_data = 0x1; /* 500mA limit */ + + data |= set_data; + + pr_info("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + /* this can be changed with top-off setting */ + if (smb347_write_reg(client, reg, data) < 0) + pr_err("%s : error!\n", __func__); + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : charging_current=> reg(0x%x)= 0x%x\n", + __func__, reg, data); + } + } + + reg = SMB347_VARIOUS_FUNCTIONS; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + +#ifdef CONFIG_WIRELESS_CHARGING + if (chip->input_source == INPUT_DCIN) { + /* disable AICL, MaxSystemVolt = Vflt + 0.1V */ + data &= (0xCF); + /* enable VCHG */ + data |= 0x1; + } else { + pr_debug("%s : reg (0x%x) = 0x%x\n", + __func__, reg, data); + data |= 0x11; /* Enable AICL, VCHG */ + data &= (0xdf); /* Max System voltage =Vflt + 0.1v */ + } +#else + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + data |= 0x11; /* Enable AICL, VCHG */ + data &= (0xdf); /* Max System voltage =Vflt + 0.1v */ +#endif + if (smb347_write_reg(client, reg, data) < 0) + pr_err("%s : error!\n", __func__); + } + + /* Float voltage : 4.36V Vprechg : 2.4V */ + smb347_write_reg(client, SMB347_FLOAT_VOLTAGE, 0x2B); + + /* Charge control (Auto Recharge) + * Automatic Recharge Disabled , Current Termination Enabled, + * BMD disable, Recharge Threshold =50mV, + * APSD enable */ + smb347_write_reg(client, SMB347_CHARGE_CONTROL, 0x2C); + /* smb347_write_reg(client, SMB347_CHARGE_CONTROL, 0x84); */ + + /* STAT, Timer control : STAT active low, Complete time out 1527min. */ + smb347_write_reg(client, SMB347_STAT_TIMERS_CONTROL, 0x1A); + +#ifdef CONFIG_MACH_JAGUAR + /* Pin enable control : Charger enable control EN Pin - Active Low */ + /* : USB5/1/HC or USB9/1.5/HC Control - Pin Control */ + /* : USB5/1/HC Input state - Tri-state Input */ + if (smb347_verA5) { + smb347_write_reg(client, SMB347_PIN_ENABLE_CONTROL, 0x01); + pr_debug("[battery]%s A5 battery is using\n", + __func__); + } else { + smb347_write_reg(client, SMB347_PIN_ENABLE_CONTROL, 0x60); + pr_debug("[battery]%s A5 battery is not using\n", + __func__); + } +#else + /* Pin enable control : Register - Active High */ + /* : USB5/1/HC or USB9/1.5/HC Control - Register Control */ + /* : USB5/1/HC Input state - Tri-State Input*/ + smb347_write_reg(client, SMB347_PIN_ENABLE_CONTROL, 0x01); +#endif /* CONFIG_MACH_JAGUAR */ + + /* Therm control : Therm monitor disable */ + smb347_write_reg(client, SMB347_THERM_CONTROL_A, 0x3F); + + /* USB selection : USB2.0(100mA/500mA), INOK polarity Active low */ + smb347_write_reg(client, SMB347_SYSOK_USB30_SELECTION, 0x08); + + /* Other control, Low batt detection disable */ + smb347_write_reg(client, SMB347_OTHER_CONTROL_A, 0x00); + + /* OTG tlim therm control UVLO 2.7V current limit 100mA*/ + smb347_write_reg(client, SMB347_OTG_TLIM_THERM_CONTROL, 0x30); + + /* Limit cell temperature */ + smb347_write_reg(client, SMB347_LIMIT_CELL_TEMPERATURE_MONITOR, 0x01); + + /* Fault interrupt : Clear */ + smb347_write_reg(client, SMB347_FAULT_INTERRUPT, 0x00); + + /* STATUS ingerrupt : Clear (Auto Recharg) */ + smb347_write_reg(client, SMB347_STATUS_INTERRUPT, 0x02); + /* smb347_write_reg(client, SMB347_STATUS_INTERRUPT, 0x00); */ + +} + +static int smb347_watchdog_control(struct i2c_client *client, bool enable) +{ + return 0; +} + +static int smb347_check_charging_status(struct i2c_client *client) +{ + int val, reg; + u8 data = 0; + int ret = -1; + + reg = SMB347_STATUS_C; /* SMB328A_BATTERY_CHARGING_STATUS_C */ + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + + ret = (data & (0x3 << 1)) >> 1; + pr_debug("%s : status = 0x%x\n", __func__, data); + } + + return ret; +} + +static bool smb347_check_is_charging(struct i2c_client *client) +{ + int val, reg; + u8 data = 0; + bool ret = false; + + reg = SMB347_STATUS_C; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + + if (data & 0x1) + ret = true; /* charger enabled */ + } + + return ret; +} + +static bool smb347_check_bat_full(struct i2c_client *client) +{ + int val, reg; + bool ret = false; + + reg = SMB347_STATUS_C; + val = smb347_read_reg(client, reg); + if (val >= 0) { + /* At least one charge cycle terminated */ + /*Charge current < Termination Current */ + if (val & SMB347_CHARGING_STATUS) + ret = true; /* full */ + } + + return ret; +} + +/* vf check */ +static bool smb347_check_bat_missing(struct i2c_client *client) +{ + int val, reg; + u8 data = 0; + bool ret = false; + + /* SMB328A_BATTERY_CHARGING_STATUS_B */ + reg = SMB347_INTERRUPT_STATUS_B; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + + if (data & (0x1 << 4)) { + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, + data); + pr_info("%s: Battery Missing\n", __func__); + ret = true; /* missing battery */ + } + } + + return ret; +} + +/* whether valid dcin or not */ +static bool smb347_check_vdcin(struct i2c_client *client) +{ + int val, reg; + u8 data = 0; + bool ret = false; + + reg = SMB347_INTERRUPT_STATUS_F; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + + if (data & (0x1)) + ret = true; + } + return ret; + +} + +static bool smb347_check_bmd_disabled(struct i2c_client *client) +{ + bool ret = false; + return ret; +} + +static int smb347_chg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct smb347_chip *chip = container_of(psy, + struct smb347_chip, psy_bat); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (smb347_check_vdcin(chip->client)) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + break; + case POWER_SUPPLY_PROP_PRESENT: + if (smb347_check_bat_missing(chip->client)) + val->intval = BAT_NOT_DETECTED; + else + val->intval = BAT_DETECTED; + break; + case POWER_SUPPLY_PROP_ONLINE: + pr_debug("%s : check bmd available\n", __func__); + /* check VF check available */ + if (smb347_check_bmd_disabled(chip->client)) + val->intval = 1; + else + val->intval = 0; + pr_debug("smb347_check_bmd_disabled is %d\n", val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + if (smb347_check_bat_full(chip->client)) + val->intval = 1; + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + switch (smb347_check_charging_status(chip->client)) { + case 0: + val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + case 1: + val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + break; + case 2: + val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + case 3: + val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + default: + pr_err("%s : get charge type error!\n", __func__); + return -EINVAL; + } + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + if (smb347_check_is_charging(chip->client)) + val->intval = 1; + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_CURRENT_ADJ: + pr_debug("%s : get charging current\n", __func__); + if (chip->chg_set_current != 0) + val->intval = chip->chg_set_current; + else + return -EINVAL; + break; +#ifdef CONFIG_WIRELESS_CHARGING + case POWER_SUPPLY_PROP_WIRELESS_CHARGING: + if (!chip->pdata->smb347_inok_using || + (chip->pdata->smb347_inok_using && + !chip->pdata->smb347_inok_using())) { + pr_err("%s : skip checking inok\n", __func__); + return -EINVAL; + } + val->intval = smb347_get_current_input_source(chip->client); + break; +#endif + default: + return -EINVAL; + } + return 0; +} + +static int smb347_set_top_off(struct i2c_client *client, int top_off) +{ + int val, reg, set_val = 0; + u8 data; + + smb347_allow_volatile_writes(client); + + /* set termination current */ + reg = SMB347_CHARGE_CURRENT; + if (top_off == 37) + set_val = 0; + else if (top_off >= 50 && top_off <= 250) + set_val = top_off / 50; + else if (top_off == 500) + set_val = 6; + else if (top_off == 600) + set_val = 7; + + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + data &= ~(0x7 << 0); + data |= (set_val << 0); + if (smb347_write_reg(client, reg, data) < 0) { + pr_err("%s : error!\n", __func__); + return -1; + } + data = smb347_read_reg(client, reg); + pr_info("%s : => reg (0x%x) = 0x%x\n", __func__, reg, data); + } + return 0; +} + +static int smb347_set_charging_current(struct i2c_client *client, + int chg_current) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + + pr_info("%s : %d\n", __func__, chg_current); + + if (chg_current < 450 || chg_current > 1200) + return -EINVAL; + + chip->chg_set_current = chg_current; + + if (chg_current == 500) { + chip->chg_mode = CHG_MODE_USB; + } else if (chg_current == 900) { + chip->chg_mode = CHG_MODE_AC; + } else if (chg_current == 700) { + chip->chg_mode = CHG_MODE_MISC; + } else if (chg_current == 450) { + chip->chg_mode = CHG_MODE_UNKNOWN; + } else { + pr_err("%s : error! invalid setting current (%d)\n", + __func__, chg_current); + chip->chg_mode = CHG_MODE_NONE; + chip->chg_set_current = 0; + return -1; + } + + return 0; +} + +static int smb347_set_fast_current(struct i2c_client *client, int fast_current) +{ + int val, reg, set_val = 0; + u8 data; + + smb347_allow_volatile_writes(client); + switch (fast_current) { + case FAST_700mA: + set_val = 0x0; + break; + case FAST_900mA: + set_val = 0x1; + break; + case FAST_1200mA: + set_val = 0x2; + break; + case FAST_1500mA: + set_val = 0x3; + break; + case FAST_1800mA: + set_val = 0x4; + break; + case FAST_2000mA: + set_val = 0x5; + break; + case FAST_2200mA: + set_val = 0x6; + break; + case FAST_2500mA: + set_val = 7; + break; + default: + set_val = 0; + break; + } + + reg = SMB347_CHARGE_CURRENT; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x, set_val = 0x%x\n", + __func__, reg, data, set_val); + data &= ~(0x7 << 5); + data |= (set_val << 5); + pr_debug("%s : write data = 0x%x\n", __func__, data); + if (smb347_write_reg(client, reg, data) < 0) { + pr_err("%s : error!\n", __func__); + return -1; + } + data = smb347_read_reg(client, reg); + pr_debug("%s : => reg (0x%x) = 0x%x\n", __func__, reg, data); + } + + return 0; +} + +static int smb347_set_input_current_limit(struct i2c_client *client, + int input_current) +{ + int val, reg, data; + + smb347_allow_volatile_writes(client); + + if (input_current < ICL_300mA || input_current > ICL_2500mA) { + pr_err("%s: invalid input_current set value(%d)\n", + __func__, input_current); + return -EINVAL; + } + + switch (input_current) { + case ICL_300mA: + val = 0x20; + break; + case ICL_500mA: + val = 0x21; + break; + case ICL_700mA: + val = 0x22; + break; + case ICL_900mA: + val = 0x23; + break; + case ICL_1200mA: + val = 0x24; + break; + case ICL_1500mA: + val = 0x25; + break; + case ICL_1800mA: + val = 0x26; + break; + case ICL_2000mA: + val = 0x27; + break; + case ICL_2200mA: + val = 0x28; + break; + case ICL_2500mA: + val = 0x29; + break; + default: + val = 7; + break; + } + + reg = SMB347_INPUT_CURRENTLIMIT; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x, set_val = 0x%x\n", + __func__, reg, data, input_current); + data &= ~(0xff); + data |= val; + pr_debug("%s : write data = 0x%x\n", __func__, data); + if (smb347_write_reg(client, reg, data) < 0) { + pr_err("%s : error!\n", __func__); + return -1; + } + data = smb347_read_reg(client, reg); + pr_debug("%s : => reg (0x%x) = 0x%x\n", __func__, reg, data); + } + + return 0; +} + +static int smb347_adjust_charging_current(struct i2c_client *client, + int chg_current) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + int ret = 0; + + pr_debug("%s :\n", __func__); + + if (chg_current < 500 || chg_current > 1200) + return -EINVAL; + + chip->chg_set_current = chg_current; + + switch (chg_current) { + case FAST_700mA: + case FAST_900mA: + case FAST_1200mA: + case FAST_1500mA: + case FAST_1800mA: + case FAST_2000mA: + case FAST_2200mA: + case FAST_2500mA: + ret = smb347_set_fast_current(client, chg_current); + break; + default: + pr_err("%s : error! invalid setting current (%d)\n", + __func__, chg_current); + chip->chg_set_current = 0; + return -EINVAL; + } + + return ret; +} + +static int smb347_get_input_current_limit(struct i2c_client *client) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + int val, reg = 0; + u8 data = 0; + + pr_debug("%s :\n", __func__); + + reg = SMB347_INPUT_CURRENTLIMIT; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + +#ifdef CONFIG_WIRELESS_CHARGING + if (smb347_get_current_input_source(chip->client) + == INPUT_DCIN) { + data &= (0xf << 4); + data >>= 4; + } else +#endif + data &= 0xf; + + if (data > 9) { + pr_err("%s: invalid icl value(%d)\n", __func__, data); + return -EINVAL; + } + + switch (data) { + case 0: + chip->chg_icl = ICL_300mA; + break; + case 1: + chip->chg_icl = ICL_500mA; + break; + case 2: + chip->chg_icl = ICL_700mA; + break; + case 3: + chip->chg_icl = ICL_900mA; + break; + case 4: + chip->chg_icl = ICL_1200mA; + break; + case 5: + chip->chg_icl = ICL_1500mA; + break; + case 6: + chip->chg_icl = ICL_1800mA; + break; + case 7: + chip->chg_icl = ICL_2000mA; + break; + case 8: + chip->chg_icl = ICL_2200mA; + break; + case 9: + chip->chg_icl = ICL_2500mA; + break; + default: + chip->chg_icl = ICL_300mA; + break; + } + + pr_debug("%s : get icl = %d, data = %d\n", + __func__, chip->chg_icl, data); + } else { + pr_err("%s: get icl failed\n", __func__); + chip->chg_icl = 0; + return -EINVAL; + } + + return 0; +} + +static int smb347_get_AICL_status(struct i2c_client *client) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + int val, reg = 0; + u8 data = 0; + + pr_debug("%s :\n", __func__); + + reg = SMB347_STATUS_E; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + dev_dbg(&client->dev, "%s : reg (0x%x) = 0x%x\n", + __func__, reg, data); + + chip->aicl_status = (data >> 4) & 0x1; + + data &= 0xf; + if (data <= 3) + chip->aicl_current = (data + 1) * 200 + 100; + else if (data >= 4 && data <= 6) + chip->aicl_current = (data - 3) * 300 + 900; + else if (data == 7) + chip->aicl_current = ICL_2000mA; + else if (data == 8) + chip->aicl_current = ICL_2200mA; + else + chip->aicl_current = ICL_2500mA; + + dev_dbg(&client->dev, + "%s : get aicl = %d, status = %d, data = %d\n", + __func__, chip->aicl_current, chip->aicl_status, data); + } else { + pr_err("%s: get aicl failed\n", __func__); + chip->aicl_current = 0; + return -EINVAL; + } + + return 0; +} + +static int smb347_enable_otg(struct i2c_client *client) +{ + /* TODO later */ + int val, reg; + u8 data; + struct smb347_chip *chip = i2c_get_clientdata(client); + dev_info(&client->dev, "%s\n", __func__); + reg = SMB347_COMMAND_A; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + + data |= (0x1 << 4); /* "1" turn on the otg 5v */ + if (smb347_write_reg(client, reg, data) < 0) { + pr_err("%s : error!\n", __func__); + return -1; + } + data = smb347_read_reg(client, reg); + pr_info("%s : => reg (0x%x) = 0x%x\n", __func__, reg, data); + chip->otg_check = OTG_ENABLE; + } + return 0; +} + +static int smb347_disable_otg(struct i2c_client *client) +{ + /* TODO later */ + int val, reg; + u8 data; + struct smb347_chip *chip = i2c_get_clientdata(client); + dev_info(&client->dev, "%s\n", __func__); + reg = SMB347_COMMAND_A; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + + data &= ~(0x1 << 4); /* "0" turn off the otg 5v */ + if (smb347_write_reg(client, reg, data) < 0) { + pr_err("%s : error!\n", __func__); + return -1; + } + data = smb347_read_reg(client, reg); + pr_info("%s : => reg (0x%x) = 0x%x\n", __func__, reg, data); + chip->otg_check = OTG_DISABLE; + } + return 0; +} + +static int smb347_enable_charging(struct i2c_client *client) +{ + int val, reg; + u8 data; + struct smb347_chip *chip = i2c_get_clientdata(client); + + pr_debug("%s :\n", __func__); + + /* register control */ + reg = SMB347_COMMAND_A; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + if (chip->chg_mode == CHG_MODE_AC || + chip->chg_mode == CHG_MODE_MISC || + chip->chg_mode == CHG_MODE_UNKNOWN) + data = 0x82; + else if (chip->chg_mode == CHG_MODE_USB) + data = 0x82; + else + data = 0x80; + if (smb347_write_reg(client, reg, data) < 0) { + pr_err("%s : error!\n", __func__); + return -1; + } + data = smb347_read_reg(client, reg); + pr_debug("%s : => reg (0x%x) = 0x%x\n", __func__, reg, data); + } +#ifdef CONFIG_MACH_JAGUAR + gpio_set_value_cansleep(chip->pdata->enable, 0); +#endif + return 0; +} + +static int smb347_disable_charging(struct i2c_client *client) +{ + int val, reg; + u8 data; + struct smb347_chip *chip = i2c_get_clientdata(client); + + pr_debug("%s :\n", __func__); + + /* register control */ + reg = SMB347_COMMAND_A; + val = smb347_read_reg(client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, data); + data = 0x80; + if (smb347_write_reg(client, reg, data) < 0) { + pr_err("%s : error!\n", __func__); + return -1; + } + data = smb347_read_reg(client, reg); + pr_debug("%s : => reg (0x%x) = 0x%x\n", __func__, reg, data); + } + + chip->chg_mode = CHG_MODE_NONE; + chip->chg_set_current = 0; + chip->chg_icl = 0; + +#ifdef CONFIG_MACH_JAGUAR + gpio_set_value_cansleep(chip->pdata->enable, 1); +#endif + return 0; +} + +static int smb347_chg_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct smb347_chip *chip = container_of(psy, + struct smb347_chip, psy_bat); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CURRENT_NOW: + /* step1) Set charging current */ + ret = smb347_set_charging_current(chip->client, val->intval); + smb347_set_command_reg(chip->client); + smb347_charger_function_conrol(chip->client); + smb347_get_input_current_limit(chip->client); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + /* step2) Set top-off current */ + if (val->intval < 37 || val->intval > 600) { + pr_err("%s: invalid topoff current(%d)\n", + __func__, val->intval); + return -EINVAL; + } + ret = smb347_set_top_off(chip->client, val->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + /* step3) Notify Vcell Now */ + chip->batt_vcell = val->intval; + pr_debug("%s : vcell(%d)\n", __func__, chip->batt_vcell); + ret = 0; + break; + case POWER_SUPPLY_PROP_STATUS: + /* step4) Enable/Disable charging */ + if (val->intval == POWER_SUPPLY_STATUS_CHARGING) { + ret = smb347_enable_charging(chip->client); + smb347_watchdog_control(chip->client, true); + } else { + ret = smb347_disable_charging(chip->client); + smb347_watchdog_control(chip->client, false); + } + break; + case POWER_SUPPLY_PROP_OTG: + if (val->intval == POWER_SUPPLY_CAPACITY_OTG_ENABLE) { + smb347_charger_function_conrol(chip->client); + ret = smb347_enable_otg(chip->client); + mdelay(5); + /*UVLO 2.7V current limit 500mA*/ + smb347_write_reg(chip->client, + SMB347_OTG_TLIM_THERM_CONTROL, 0x38); + } else + ret = smb347_disable_otg(chip->client); + break; + case POWER_SUPPLY_PROP_CURRENT_ADJ: + pr_info("%s : adjust charging current from %d to %d\n", + __func__, chip->chg_set_current, val->intval); + if (chip->chg_mode == CHG_MODE_AC) { + ret = + smb347_adjust_charging_current(chip->client, + val->intval); + } else { + pr_info + ("%s : not AC mode, skip fast current adjusting\n", + __func__); + } + break; +#ifdef CONFIG_WIRELESS_CHARGING + case POWER_SUPPLY_PROP_WIRELESS_CHARGING: + pr_info("%s : set input source type(%d)\n", + __func__, val->intval); + chip->input_source = val->intval; + break; +#endif + case POWER_SUPPLY_PROP_PRESENT: + pr_info("%s : Battery is removed. Cut off charging.\n", + __func__); + smb347_enter_suspend(chip->client); + + break; + default: + return -EINVAL; + } + +#ifdef SMB347_DEBUG + smb347_print_all_regs(chip->client); +#endif + return ret; +} + +static ssize_t sec_smb347_show_property(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t sec_smb347_store_property(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +#define SEC_SMB347_ATTR(_name)\ +{\ + .attr = { .name = #_name, \ + .mode = 0664, \ + /* .owner = THIS_MODULE */ }, \ + .show = sec_smb347_show_property, \ + .store = sec_smb347_store_property, \ +} + +static struct device_attribute sec_smb347_attrs[] = { + SEC_SMB347_ATTR(smb_read_3Dh), + SEC_SMB347_ATTR(smb_wr_icl), + SEC_SMB347_ATTR(smb_wr_fast), + SEC_SMB347_ATTR(smb_read_fv), + SEC_SMB347_ATTR(smb_read_aicl), +#ifdef CONFIG_WIRELESS_CHARGING + SEC_SMB347_ATTR(smb_input_source), + SEC_SMB347_ATTR(smb_inok), +#endif +}; + +enum { + SMB_READ_3DH = 0, + SMB_WR_ICL, + SMB_WR_FAST, + SMB_READ_FV, + SMB_READ_AICL, +#ifdef CONFIG_WIRELESS_CHARGING + SMB_INPUT_SOURCE, + SMB_INOK, +#endif +}; + +static ssize_t sec_smb347_show_property(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct smb347_chip *chip = container_of(psy, + struct smb347_chip, + psy_bat); + + int i = 0; + const ptrdiff_t off = attr - sec_smb347_attrs; + int val, reg; + u8 data = 0; + + switch (off) { + case SMB_READ_3DH: + reg = SMB347_STATUS_C; + val = smb347_read_reg(chip->client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, + data); + i += scnprintf(buf + i, PAGE_SIZE - i, + "0x%x (bit6 : %d)\n", data, + (data & 0x40) >> 6); + } else { + i = -EINVAL; + } + break; + case SMB_WR_ICL: + reg = SMB347_INPUT_CURRENTLIMIT; + val = smb347_read_reg(chip->client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, + data); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d (0x%x)\n", + chip->chg_icl, data); + } else { + i = -EINVAL; + } + break; + case SMB_WR_FAST: + reg = SMB347_CHARGE_CURRENT; + val = smb347_read_reg(chip->client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, + data); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d (0x%x)\n", + chip->chg_set_current, data); + } else { + i = -EINVAL; + } + break; + case SMB_READ_FV: + reg = SMB347_FLOAT_VOLTAGE; + val = smb347_read_reg(chip->client, reg); + if (val >= 0) { + data = (u8) val; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, + data); + i += scnprintf(buf + i, PAGE_SIZE - i, "0x%x (%dmV)\n", + data, 3500 + ((data & 0x3F) * 20)); + } else { + i = -EINVAL; + } + break; + case SMB_READ_AICL: + val = smb347_get_AICL_status(chip->client); + if (val >= 0) { + i += scnprintf(buf + i, PAGE_SIZE - i, "%dmA (%d)\n", + chip->aicl_current, chip->aicl_status); + } else { + i = -EINVAL; + } + break; +#ifdef CONFIG_WIRELESS_CHARGING + case SMB_INPUT_SOURCE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + chip->input_source); + break; + case SMB_INOK: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + gpio_get_value(chip->pdata->inok)); + break; +#endif + default: + i = -EINVAL; + } + + return i; +} + +static ssize_t sec_smb347_store_property(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct smb347_chip *chip = container_of(psy, + struct smb347_chip, + psy_bat); + + int x = 0; + int ret = 0; + const ptrdiff_t off = attr - sec_smb347_attrs; + + switch (off) { + case SMB_WR_ICL: + if (sscanf(buf, "%d\n", &x) == 1) { + if (chip->chg_mode == CHG_MODE_AC) { + ret = + smb347_set_input_current_limit(chip->client, + x); + } else { + pr_info + ("%s : not AC mode, skip icl adjusting\n", + __func__); + ret = count; + } + } + break; + case SMB_WR_FAST: + if (sscanf(buf, "%d\n", &x) == 1) { + if (chip->chg_mode == CHG_MODE_AC) { + ret = smb347_adjust_charging_current + (chip->client, x); + } else { + pr_info("%s : not AC mode, skip SMB_WR_FAST\n", + __func__); + ret = count; + } + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int smb347_create_attrs(struct device *dev) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(sec_smb347_attrs); i++) { + rc = device_create_file(dev, &sec_smb347_attrs[i]); + if (rc) + goto smb347_attrs_failed; + } + goto succeed; + +smb347_attrs_failed: + while (i--) + device_remove_file(dev, &sec_smb347_attrs[i]); +succeed: + return rc; +} + +static irqreturn_t smb347_int_work_func(int irq, void *smb_chip) +{ + struct smb347_chip *chip = smb_chip; + int val, reg; + u8 chg_status = 0; + + pr_debug("%s\n", __func__); + + reg = SMB347_INTERRUPT_STATUS_B; + val = smb347_read_reg(chip->client, reg); + if (val >= 0 && + val & 0x20) { + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, val); + pr_info("%s : Battery Missing!!!\n", __func__); + smb347_enter_suspend(chip->client); + return IRQ_HANDLED; + } + + reg = SMB347_STATUS_C; + val = smb347_read_reg(chip->client, reg); + if (val >= 0) { + if (val & 0x01) + chg_status = POWER_SUPPLY_STATUS_CHARGING; + else + chg_status = POWER_SUPPLY_STATUS_DISCHARGING; + pr_debug("%s : reg (0x%x) = 0x%x\n", __func__, reg, val); + } + + if (chip->pdata->chg_intr_trigger) + chip->pdata->chg_intr_trigger((int)(chg_status)); + + /* + u8 intr_a = 0; + u8 intr_b = 0; + + reg = SMB347_INTERRUPT_STATUS_A; + val = smb347_read_reg(chip->client, reg); + if (val >= 0) { + intr_a = (u8)val; + pr_info("%s : reg (0x%x) = 0x%x\n", __func__, reg, intr_a); + } + reg = SMB347_INTERRUPT_STATUS_B; + val = smb347_read_reg(chip->client, reg); + if (val >= 0) { + intr_b = (u8)val; + pr_info("%s : reg (0x%x) = 0x%x\n", __func__, reg, intr_b); + } + + reg = SMB347_INTERRUPT_STATUS_C; + val = smb347_read_reg(chip->client, reg); + if (val >= 0) { + intr_c = (u8) val; + pr_info("%s : reg (0x%x) = 0x%x\n", __func__, reg, intr_c); + } + + reg = SMB347_STATUS_C; + val = smb347_read_reg(chip->client, reg); + if (val >= 0) { + chg_status = (u8) val; + pr_info("%s : reg (0x%x) = 0x%x\n", __func__, reg, chg_status); + } + + if (chip->pdata->chg_intr_trigger) + chip->pdata->chg_intr_trigger((int)(chg_status & 0x1)); +*/ + return IRQ_HANDLED; +} + +static void smb347_AICL_enable(struct i2c_client *client, bool en) +{ + int reg, val; + u8 data; + + smb347_allow_volatile_writes(client); + + reg = SMB347_VARIOUS_FUNCTIONS; + val = smb347_read_reg(client, reg); + + if (val >= 0) { + data = (u8) val; + } else { + pr_err("%s: fail to read SMB347 02h reg\n", __func__); + return; + } + + if (en) { + pr_info("%s : enable AICL\n", __func__); + data |= 0x10; /* Enable AICL*/ + + } else { + pr_info("%s : disable AICL\n", __func__); + /* clear BIT4 (disable AICL) */ + data &= (0xEF); + } + if (smb347_write_reg(client, reg, data) < 0) + pr_err("%s : error!\n", __func__); + +} + +static irqreturn_t smb347_inok_work_func(int irq, void *smb_chip) +{ + struct smb347_chip *chip = smb_chip; + struct power_supply *psy = power_supply_get_by_name("battery"); + union power_supply_propval value; + int input_source = 0; + int cable_type = 0; + int ret = 0; + + if (psy) { + /* check usbin or dcin status */ + /* 0 : no dcin, 1: DCIN, 2: USBIN */ + input_source = smb347_get_current_input_source(chip->client); + switch (input_source) { + case INPUT_NONE: + ret = smb347_read_reg(chip->client, + SMB347_INTERRUPT_STATUS_E); + if (ret & 0x04) { + pr_info("%s: OVP cut off input power\n", + __func__); + chip->ovp_state = 1; + } else { + pr_debug("%s: OVP isn't set\n", __func__); + chip->ovp_state = 0; + } + + if (chip->input_source == INPUT_DCIN) { + /* AICL enable */ + smb347_AICL_enable(chip->client, true); + + value.intval = POWER_SUPPLY_TYPE_BATTERY; + ret = psy->set_property(psy, + POWER_SUPPLY_PROP_ONLINE, &value); + if (ret < 0) + pr_err("%s : failed to set power_suppy online property(%d)\n", + __func__, ret); + } else if (chip->input_source == INPUT_USBIN) { + ret = psy->get_property(psy, + POWER_SUPPLY_PROP_PRESENT, &value); + + if (ret < 0) + pr_err("%s : failed present(%d)\n", + __func__, ret); + + if (value.intval) { + value.intval = + POWER_SUPPLY_TYPE_BATTERY; + ret = psy->set_property(psy, + POWER_SUPPLY_PROP_ONLINE, &value); + if (ret < 0) + pr_err("%s : failed(%d)\n", + __func__, ret); + } + } + pr_info("%s : no input source(%d --> %d)\n", + __func__, chip->input_source, input_source); + break; + case INPUT_DCIN: + /* AICL disable */ + smb347_AICL_enable(chip->client, false); +#ifdef CONFIG_WIRELESS_CHARGING + value.intval = POWER_SUPPLY_TYPE_WPC; + ret = psy->set_property(psy, + POWER_SUPPLY_PROP_ONLINE, &value); + if (ret < 0) + pr_err("%s : failed to set power_suppy online property(%d)\n", + __func__, ret); +#endif + break; + case INPUT_USBIN: + if (chip->pdata->smb347_get_cable) { + if (chip->ovp_state) { + cable_type = + chip->pdata->smb347_get_cable(); + pr_info("%s: Recovery OVP, restart charging (%d)\n", + __func__, cable_type); + } + } + chip->ovp_state = 0; + break; + default: + pr_err("%s : failed to read input source type(%d)\n", + __func__, chip->input_source); + return IRQ_HANDLED; + } + chip->input_source = input_source; + } else + pr_err("%s : failed to get battery psy\n", __func__); + + return IRQ_HANDLED; +} + +static int __devinit smb347_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct smb347_chip *chip; + int ret = 0; + int value = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + return -EIO; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->client = client; + chip->pdata = client->dev.platform_data; + if (!chip->pdata) { + pr_err("%s: no charger platform data\n", __func__); + goto err_kfree; + } + + if (!chip->pdata->smb347_using()) { + pr_info("%s: SMB347 driver Loading SKIP!!!\n", __func__); + ret = -EINVAL; + goto err_kfree; + } + check_smb347_version(); + pr_info("%s: SMB347 driver Loading!\n", __func__); + + i2c_set_clientdata(client, chip); + + chip->pdata->hw_init(); /* important */ + chip->chg_mode = CHG_MODE_NONE; + chip->chg_set_current = 0; + chip->chg_icl = 0; + chip->float_voltage = 0; + chip->ovp_state = 0; + + if (poweroff_charging) { + chip->lpm_chg_mode = 1; + pr_info("%s : is lpm charging mode (%d)\n", + __func__, chip->lpm_chg_mode); + } + mutex_init(&chip->mutex); + + chip->psy_bat.name = "sec-charger", + chip->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, + chip->psy_bat.properties = smb347_battery_props, + chip->psy_bat.num_properties = ARRAY_SIZE(smb347_battery_props), + chip->psy_bat.get_property = smb347_chg_get_property, + chip->psy_bat.set_property = smb347_chg_set_property, + ret = power_supply_register(&client->dev, &chip->psy_bat); + if (ret) { + pr_err("Failed to register power supply psy_bat\n"); + goto err_psy_register; + } + + /* Vdcin polarity setting */ + value = smb347_read_reg(client, SMB347_SYSOK_USB30_SELECTION); + value = (value | 0x1); + ret = + smb347_write_reg(client, SMB347_SYSOK_USB30_SELECTION, value); + if (ret < 0) { + pr_err("%s: INOK polarity setting error!\n", __func__); + } + + ret = + request_threaded_irq(chip->client->irq, NULL, smb347_int_work_func, + IRQF_TRIGGER_FALLING, "smb347", chip); + if (ret) { + pr_err("%s : Failed to request smb347 charger irq\n", __func__); + goto err_request_irq; + } + + ret = enable_irq_wake(chip->client->irq); + if (ret) { + pr_err("%s : Failed to enable smb347 charger irq wake\n", + __func__); + goto err_irq_wake; + } + if (chip->pdata->smb347_inok_using) { + if (chip->pdata->smb347_inok_using()) { + ret = request_threaded_irq( + MSM_GPIO_TO_INT(chip->pdata->inok), + NULL, + smb347_inok_work_func, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "smb347 inok", + chip); + + if (ret) { + pr_err("%s : Failed to request smb347 charger inok irq\n", + __func__); + goto err_irq_wake; + } + + ret = enable_irq_wake( + MSM_GPIO_TO_INT(chip->pdata->inok)); + if (ret) { + pr_err("%s : Failed to enable smb347 charger inok irq wake\n", + __func__); + goto err_irq_wake2; + } + } + } + +#ifdef CONFIG_WIRELESS_CHARGING + if (smb347_get_current_input_source(chip->client) == INPUT_DCIN) { + pr_info("[battery] SMB347 driver detect DCIN\n"); + if (chip->pdata->smb347_wpc_cb) + chip->pdata->smb347_wpc_cb(); + } +#endif + +#ifdef SMB347_DEBUG + smb347_print_all_regs(client); +#endif + + smb347_create_attrs(chip->psy_bat.dev); + + return 0; +err_irq_wake2: + free_irq(MSM_GPIO_TO_INT(chip->pdata->inok), NULL); +err_irq_wake: + free_irq(chip->client->irq, NULL); +err_request_irq: + power_supply_unregister(&chip->psy_bat); +err_psy_register: + mutex_destroy(&chip->mutex); +err_kfree: + kfree(chip); + return ret; +} + +static int __devexit smb347_remove(struct i2c_client *client) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + + power_supply_unregister(&chip->psy_bat); + mutex_destroy(&chip->mutex); + kfree(chip); + return 0; +} + +static int smb347_suspend(struct i2c_client *client, pm_message_t state) +{ + return 0; +} + +static int smb347_resume(struct i2c_client *client) +{ + return 0; +} + +static void smb347_shutdown(struct i2c_client *client) +{ + struct smb347_chip *chip = i2c_get_clientdata(client); + if (chip != NULL) { + if (chip->otg_check == OTG_ENABLE) + smb347_disable_otg(chip->client); + } +} + +static const struct i2c_device_id smb347_id[] = { + {"smb347", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, smb347_id); + +static struct i2c_driver smb347_i2c_driver = { + .driver = { + .name = "smb347", + }, + .probe = smb347_probe, + .remove = __devexit_p(smb347_remove), + .suspend = smb347_suspend, + .resume = smb347_resume, + .shutdown = smb347_shutdown, + .id_table = smb347_id, +}; + +static int __init smb347_init(void) +{ + return i2c_add_driver(&smb347_i2c_driver); +} + +module_init(smb347_init); + +static void __exit smb347_exit(void) +{ + i2c_del_driver(&smb347_i2c_driver); +} + +module_exit(smb347_exit); + +MODULE_DESCRIPTION("SMB347 charger control driver"); +MODULE_AUTHOR(""); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 75d89400c12..8b7bfee8822 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ enum { struct max8952_data { struct i2c_client *client; struct device *dev; + struct mutex mutex; struct max8952_platform_data *pdata; struct regulator_dev *rdev; @@ -77,12 +79,13 @@ static int max8952_voltage(struct max8952_data *max8952, u8 mode) static int max8952_list_voltage(struct regulator_dev *rdev, unsigned int selector) { - struct max8952_data *max8952 = rdev_get_drvdata(rdev); + int ret; if (rdev_get_id(rdev) != 0) return -EINVAL; - return max8952_voltage(max8952, selector); + ret = MAX8952_DCDC_VMIN + selector * MAX8952_DCDC_STEP; + return ret; } static int max8952_is_enabled(struct regulator_dev *rdev) @@ -130,6 +133,41 @@ static int max8952_get_voltage(struct regulator_dev *rdev) return max8952_voltage(max8952, vid); } +/*lmh_add, New set_voltage func. for camera ISP core power setting*/ +static int _max8952_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + + int set_val, uV = min_uV; + int lim_min_uV, lim_max_uV; + + lim_min_uV = max8952->pdata->reg_data.constraints.min_uV; + lim_max_uV = max8952->pdata->reg_data.constraints.max_uV; + + + if (uV < lim_min_uV && max_uV >= lim_min_uV) + uV = lim_min_uV; + + if (uV < lim_min_uV || uV > lim_max_uV) { + pr_err("request v=[%d, %d] is outside possible v=[%d, %d]\n", + min_uV, max_uV, lim_min_uV, lim_max_uV); + return -EINVAL; + } + + set_val = (uV-MAX8952_DCDC_VMIN) / MAX8952_DCDC_STEP; + *selector = set_val & 0x3f; + + max8952_write_reg(max8952, MAX8952_REG_MODE3, + (max8952_read_reg(max8952, + MAX8952_REG_MODE3) & 0xC0) | (*selector)); + + pr_info("%s voltage is enabled to %d mV by selector value [%d]\n", + max8952->pdata->reg_data.constraints.name, uV/1000, *selector); + return 0; +} +/*end lmh_add, New set_voltage func. for camera ISP core power setting*/ +#if 0 static int max8952_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { @@ -162,21 +200,21 @@ static int max8952_set_voltage(struct regulator_dev *rdev, return 0; } - +#endif static struct regulator_ops max8952_ops = { .list_voltage = max8952_list_voltage, .is_enabled = max8952_is_enabled, .enable = max8952_enable, .disable = max8952_disable, .get_voltage = max8952_get_voltage, - .set_voltage = max8952_set_voltage, + .set_voltage = _max8952_set_voltage, .set_suspend_disable = max8952_disable, }; static struct regulator_desc regulator = { .name = "MAX8952_VOUT", .id = 0, - .n_voltages = MAX8952_NUM_DVS_MODE, + .n_voltages = 1 << 6, .ops = &max8952_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, @@ -206,8 +244,9 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, max8952->client = client; max8952->dev = &client->dev; max8952->pdata = pdata; + mutex_init(&max8952->mutex); - max8952->rdev = regulator_register(®ulator, max8952->dev, + max8952->rdev = regulator_register(®ulator, &client->dev, &pdata->reg_data, max8952, NULL); if (IS_ERR(max8952->rdev)) { @@ -220,32 +259,14 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, max8952->vid0 = (pdata->default_mode % 2) == 1; max8952->vid1 = ((pdata->default_mode >> 1) % 2) == 1; - if (gpio_is_valid(pdata->gpio_en)) { - if (!gpio_request(pdata->gpio_en, "MAX8952 EN")) - gpio_direction_output(pdata->gpio_en, max8952->en); - else - err = 1; - } else - err = 2; - - if (err) { - dev_info(max8952->dev, "EN gpio invalid: assume that EN" - "is always High\n"); - max8952->en = 1; - pdata->gpio_en = -1; /* Mark invalid */ - } - - err = 0; - if (gpio_is_valid(pdata->gpio_vid0) && - gpio_is_valid(pdata->gpio_vid1)) { - if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0")) + gpio_is_valid(pdata->gpio_vid1)) { + if (!gpio_request(pdata->gpio_vid0, "MAX8952_VID0")) gpio_direction_output(pdata->gpio_vid0, - (pdata->default_mode) % 2); + (pdata->default_mode) % 2); else err = 1; - - if (!gpio_request(pdata->gpio_vid1, "MAX8952 VID1")) + if (!gpio_request(pdata->gpio_vid1, "MAX8952_VID1")) gpio_direction_output(pdata->gpio_vid1, (pdata->default_mode >> 1) % 2); else { @@ -253,8 +274,9 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, gpio_free(pdata->gpio_vid0); err = 2; } + } - } else + else err = 3; if (err) { @@ -265,10 +287,8 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, /* Mark invalid */ pdata->gpio_vid0 = -1; pdata->gpio_vid1 = -1; - /* Disable Pulldown of EN only */ max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60); - dev_err(max8952->dev, "DVS modes disabled because VID0 and VID1" " do not have proper controls.\n"); } else { @@ -283,22 +303,24 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x0); } - max8952_write_reg(max8952, MAX8952_REG_MODE0, - (max8952_read_reg(max8952, - MAX8952_REG_MODE0) & 0xC0) | - (pdata->dvs_mode[0] & 0x3F)); - max8952_write_reg(max8952, MAX8952_REG_MODE1, - (max8952_read_reg(max8952, - MAX8952_REG_MODE1) & 0xC0) | - (pdata->dvs_mode[1] & 0x3F)); - max8952_write_reg(max8952, MAX8952_REG_MODE2, - (max8952_read_reg(max8952, - MAX8952_REG_MODE2) & 0xC0) | - (pdata->dvs_mode[2] & 0x3F)); - max8952_write_reg(max8952, MAX8952_REG_MODE3, - (max8952_read_reg(max8952, - MAX8952_REG_MODE3) & 0xC0) | - (pdata->dvs_mode[3] & 0x3F)); + if (pdata->dvs_mode) { + max8952_write_reg(max8952, MAX8952_REG_MODE0, + (max8952_read_reg(max8952, + MAX8952_REG_MODE0) & 0xC0) | + (pdata->dvs_mode[0] & 0x3F)); + max8952_write_reg(max8952, MAX8952_REG_MODE1, + (max8952_read_reg(max8952, + MAX8952_REG_MODE1) & 0xC0) | + (pdata->dvs_mode[1] & 0x3F)); + max8952_write_reg(max8952, MAX8952_REG_MODE2, + (max8952_read_reg(max8952, + MAX8952_REG_MODE2) & 0xC0) | + (pdata->dvs_mode[2] & 0x3F)); + max8952_write_reg(max8952, MAX8952_REG_MODE3, + (max8952_read_reg(max8952, + MAX8952_REG_MODE3) & 0xC0) | + (pdata->dvs_mode[3] & 0x3F)); + } max8952_write_reg(max8952, MAX8952_REG_SYNC, (max8952_read_reg(max8952, MAX8952_REG_SYNC) & 0x3F) | @@ -308,7 +330,6 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, ((pdata->ramp_speed & 0x7) << 5)); i2c_set_clientdata(client, max8952); - return 0; err_reg: @@ -326,7 +347,6 @@ static int __devexit max8952_pmic_remove(struct i2c_client *client) gpio_free(pdata->gpio_vid0); gpio_free(pdata->gpio_vid1); - gpio_free(pdata->gpio_en); kfree(max8952); return 0; @@ -349,6 +369,7 @@ static struct i2c_driver max8952_pmic_driver = { static int __init max8952_pmic_init(void) { + pr_info("MAX8952 loading!!\n"); return i2c_add_driver(&max8952_pmic_driver); } subsys_initcall(max8952_pmic_init); diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig new file mode 100644 index 00000000000..f6699de0eac --- /dev/null +++ b/drivers/sensors/Kconfig @@ -0,0 +1,13 @@ + +menuconfig NEW_SENSORS + bool "Sensors Support" + help + Say Y to enable Sensors support. This allows control of supported + Sensors. + +if NEW_SENSORS + +source "drivers/sensors/core/Kconfig" + +endif + diff --git a/drivers/sensors/Makefile b/drivers/sensors/Makefile new file mode 100644 index 00000000000..ddb565ff053 --- /dev/null +++ b/drivers/sensors/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the kernel Sensor device drivers. +# + +# Object files in subdirectories + +obj-$(CONFIG_SENSORS_CORE) +=core/ diff --git a/drivers/sensors/core/Kconfig b/drivers/sensors/core/Kconfig new file mode 100644 index 00000000000..de4c23dba5f --- /dev/null +++ b/drivers/sensors/core/Kconfig @@ -0,0 +1,10 @@ +# +# Sensors core device. +# + +config SENSORS_CORE + tristate "Sensors core" + help + Say Y here to enable debugging messages for power supply class + and drivers. + diff --git a/drivers/sensors/core/Makefile b/drivers/sensors/core/Makefile new file mode 100644 index 00000000000..de0e5a70786 --- /dev/null +++ b/drivers/sensors/core/Makefile @@ -0,0 +1,5 @@ + + + +obj-$(CONFIG_SENSORS_CORE) += sensors_core.o + diff --git a/drivers/sensors/core/sensors_core.c b/drivers/sensors/core/sensors_core.c new file mode 100644 index 00000000000..2f3b87ab58c --- /dev/null +++ b/drivers/sensors/core/sensors_core.c @@ -0,0 +1,105 @@ +/* /driver/sensors/core/sensors_core.c + * Copyright (C) 2011 Samsung Electronics. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 + + +struct class *sensors_class; +EXPORT_SYMBOL_GPL(sensors_class); + + +/** + * Create sysfs interface + */ +static void set_sensor_attr(struct device *dev, + struct device_attribute *attributes[]) +{ + int i; + + for (i = 0 ; attributes[i] != NULL ; i++) { + if ((device_create_file(dev, attributes[i])) < 0) + pr_err("Create_dev_file fail(attributes[%d] )\n", i); + } +} + +int sensors_register(struct device *dev, void * drvdata, + struct device_attribute *attributes[], char *name) +{ + int ret = 0; + + if (!sensors_class) { + sensors_class = class_create(THIS_MODULE, "sensors"); + if (IS_ERR(sensors_class)) + return PTR_ERR(sensors_class); + } + + + dev = device_create(sensors_class, NULL, 0, drvdata, "%s", name); + + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + pr_err("[SENSORS CORE] device_create failed! [%d]\n", ret); + return ret; + } + + set_sensor_attr(dev, attributes); + + + return 0; +} +EXPORT_SYMBOL_GPL(sensors_register); + +void sensors_unregister(struct device *dev) +{ + /* TODO : Unregister device */ +} +EXPORT_SYMBOL_GPL(sensors_unregister); + +static int __init sensors_class_init(void) +{ + pr_debug("[SENSORS CORE] sensors_class_init\n"); + sensors_class = class_create(THIS_MODULE, "sensors"); + + if (IS_ERR(sensors_class)) + return PTR_ERR(sensors_class); + + sensors_class->dev_uevent = NULL; + + return 0; +} + +static void __exit sensors_class_exit(void) +{ + class_destroy(sensors_class); +} + + +/* exported for the APM Power driver, APM emulation */ + +subsys_initcall(sensors_class_init); +module_exit(sensors_class_exit); + +MODULE_DESCRIPTION("Universal sensors core class"); +MODULE_AUTHOR("Ryunkyun Park "); +MODULE_LICENSE("GPL"); + diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c index cf0f8fb4fd8..b353b65847f 100644 --- a/drivers/staging/android/ram_console.c +++ b/drivers/staging/android/ram_console.c @@ -68,7 +68,7 @@ static int __devinit ram_console_probe(struct platform_device *pdev) ram_console_zone = prz; ram_console.data = prz; - + console_verbose(); register_console(&ram_console); return 0; diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 52ea9e15a7c..67af59c683c 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -962,7 +962,7 @@ static int acm_function_bind_config(struct android_usb_function *f, { char *name; char buf[32], *b; - int err = -1, i; + int err = 0, i; static int acm_initialized, ports; if (acm_initialized) @@ -975,7 +975,7 @@ static int acm_function_bind_config(struct android_usb_function *f, while (b) { name = strsep(&b, ","); - if (name) { + if (name[0]) { err = acm_init_port(ports, name); if (err) { pr_err("acm: Cannot open port '%s'", name); diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c index 556ae99487f..9b5beb940fd 100644 --- a/drivers/usb/otg/msm_otg.c +++ b/drivers/usb/otg/msm_otg.c @@ -10,7 +10,6 @@ * GNU General Public License for more details. * */ - #include #include #include @@ -1092,9 +1091,9 @@ static int msm_otg_notify_chg_type(struct msm_otg *motg) motg->chg_type == USB_ACA_C_CHARGER)) charger_type = POWER_SUPPLY_TYPE_USB_ACA; else - charger_type = POWER_SUPPLY_TYPE_UNKNOWN; - - return pm8921_set_usb_power_supply_type(charger_type); + charger_type = POWER_SUPPLY_TYPE_BATTERY; + return 0; +// return pm8921_set_usb_power_supply_type(charger_type); } static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA) @@ -2232,17 +2231,26 @@ static void msm_otg_init_sm(struct msm_otg *motg) else clear_bit(B_SESS_VLD, &motg->inputs); } else if (pdata->otg_control == OTG_PMIC_CONTROL) { - if (pdata->pmic_id_irq) { + if (otgsc & OTGSC_ID) { if (msm_otg_read_pmic_id_state(motg)) set_bit(ID, &motg->inputs); else clear_bit(ID, &motg->inputs); } - /* - * VBUS initial state is reported after PMIC - * driver initialization. Wait for it. - */ - wait_for_completion(&pmic_vbus_init); + if (pdata->smb347s) { + pr_info("msm_otg_init_sm, smb347s\n"); + if (otgsc & OTGSC_BSV) + set_bit(B_SESS_VLD, &motg->inputs); + else + clear_bit(B_SESS_VLD, &motg->inputs); + } else { + pr_info("msm_otg_init_sm, PM8921\n"); + /* + * VBUS initial state is reported after PMIC + * driver initialization. Wait for it. + */ + wait_for_completion(&pmic_vbus_init); + } } break; case USB_HOST: @@ -2312,6 +2320,12 @@ static void msm_otg_sm_work(struct work_struct *w) otg->phy->state = OTG_STATE_A_IDLE; work = 1; } else if (test_bit(B_SESS_VLD, &motg->inputs)) { +#ifdef CONFIG_USB_SWITCH_FSA9485 + if (motg->chg_state != USB_CHG_STATE_DETECTED) { + motg->chg_type = USB_SDP_CHARGER; + motg->chg_state = USB_CHG_STATE_DETECTED; + } +#endif pr_debug("b_sess_vld\n"); switch (motg->chg_state) { case USB_CHG_STATE_UNDEFINED: @@ -3007,21 +3021,36 @@ static irqreturn_t msm_otg_irq(int irq, void *data) return ret; } -static void msm_otg_set_vbus_state(int online) +void msm_otg_set_vbus_state(int online) { static bool init; struct msm_otg *motg = the_msm_otg; struct usb_otg *otg = motg->phy.otg; - /* In A Host Mode, ignore received BSV interrupts */ - if (otg->phy->state >= OTG_STATE_A_IDLE) - return; - + /* Ignore received BSV interrupts, if ID pin is GND */ + pr_info("%s: %d", __func__, online); +#if 0 + if (!test_bit(ID, &motg->inputs)) { + /* + * state machine work waits for initial VBUS + * completion in UNDEFINED state. Process + * the initial VBUS event in ID_GND state. + */ + if (init) { + dev_info(motg->phy.dev, "msm_otg_set_vbus_state(1): on working\n"); + return; + } + } +#endif if (online) { - pr_debug("PMIC: BSV set\n"); + if (otg->phy->state > OTG_STATE_B_IDLE) { + dev_info(motg->phy.dev, "msm_otg_set_vbus_state(1): on working\n"); + return; + } + pr_info("PMIC: BSV set\n"); set_bit(B_SESS_VLD, &motg->inputs); } else { - pr_debug("PMIC: BSV clear\n"); + pr_info("PMIC: BSV clear\n"); clear_bit(B_SESS_VLD, &motg->inputs); } @@ -3029,7 +3058,6 @@ static void msm_otg_set_vbus_state(int online) init = true; complete(&pmic_vbus_init); pr_debug("PMIC: BSV init complete\n"); - return; } if (test_bit(MHL, &motg->inputs) || @@ -3042,7 +3070,44 @@ static void msm_otg_set_vbus_state(int online) motg->sm_work_pending = true; else queue_work(system_nrt_wq, &motg->sm_work); + return; +} +EXPORT_SYMBOL_GPL(msm_otg_set_vbus_state); + +void msm_otg_set_charging_state(bool enable) +{ + struct msm_otg *motg = the_msm_otg; + static bool charging; + + if (charging == enable) + return; + else + charging = enable; + + pr_info("%s enable=%d\n", __func__, enable); + + if (enable) { + motg->chg_type = USB_DCP_CHARGER; + motg->chg_state = USB_CHG_STATE_DETECTED; + schedule_work(&motg->sm_work); + } else { + motg->chg_state = USB_CHG_STATE_UNDEFINED; + motg->chg_type = USB_INVALID_CHARGER; + } +} +EXPORT_SYMBOL_GPL(msm_otg_set_charging_state); + +void msm_otg_set_id_state(bool enable) +{ + struct msm_otg *motg = the_msm_otg; + struct usb_phy *phy = &motg->phy; + + if (atomic_read(&motg->in_lpm)) { + pr_info("msm_otg_set_id_state : in LPM\n"); + pm_runtime_resume(phy->dev); + } } +EXPORT_SYMBOL_GPL(msm_otg_set_id_state); static void msm_pmic_id_status_w(struct work_struct *w) { @@ -3980,7 +4045,7 @@ static int msm_otg_pm_suspend(struct device *dev) int ret = 0; struct msm_otg *motg = dev_get_drvdata(dev); - dev_dbg(dev, "OTG PM suspend\n"); + dev_info(dev, "OTG PM suspend\n"); atomic_set(&motg->pm_suspended, 1); ret = msm_otg_suspend(motg); diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig index 1c160716c53..dd87c20fbb7 100644 --- a/drivers/video/msm/Kconfig +++ b/drivers/video/msm/Kconfig @@ -1,4 +1,4 @@ - +source "drivers/video/msm/mhl_v2/Kconfig" source "drivers/video/msm/vidc/Kconfig" config FB_MSM @@ -216,6 +216,16 @@ config FB_MSM_MIPI_DSI_NT35516 bool select FB_MSM_MIPI_DSI +config FB_MSM_MIPI_DSI_SAMSUNG_OLED + bool + select FB_MSM_MIPI_DSI + default n + +config SAMSUNG_CMC624 + bool "Support for integrated LCD controller in msm8960" + depends on FB && ARCH_MSM + default n + config FB_MSM_MIPI_DSI_TC358764_DSI2LVDS bool select FB_MSM_MIPI_DSI @@ -362,6 +372,22 @@ config FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT select FB_MSM_MIPI_DSI_RENESAS default n +config FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT + bool + select FB_MSM_MIPI_DSI_SAMSUNG_OLED + default n + +config FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + bool + select FB_MSM_MIPI_DSI_SAMSUNG_OLED + default n + +config FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + bool + select FB_MSM_MIPI_DSI_SAMSUNG_OLED + default n + + config FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT bool select FB_MSM_MIPI_DSI_NT35510 @@ -550,6 +576,9 @@ config FB_MSM_MIPI_PANEL_DETECT select FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA select FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT select FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT + select FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT + select FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + select FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT select FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT select FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT @@ -695,6 +724,18 @@ config FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL bool "MIPI Renesas Command FWVGA PT Panel" select FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT +config FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL + bool "MIPI SAMSUNG OLED CMD QHD PT Panel" + select FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT + +config FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT_PANEL + bool "MIPI SAMSUNG OLED VIDEO HD PT Panel" + select FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + +config FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL + bool "MIPI SAMSUNG OLED VIDEO WVGA PT Panel" + select FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + config FB_MSM_MIPI_CHIMEI_WXGA_PANEL bool "MIPI Chimei WXGA PT Panel" select FB_MSM_MIPI_CHIMEI_WXGA @@ -779,6 +820,10 @@ config FB_MSM_SECONDARY_PANEL_NONE No secondary panel endchoice +config MIPI_SAMSUNG_ESD_REFRESH + bool "Samsung ESD Recovery Driver" + default n + config FB_MSM_LCDC_DSUB depends on FB_MSM_LCDC_SAMSUNG_WSVGA && FB_MSM_MDP40 && FB_MSM_LCDC_HW bool "External DSUB support" diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile index e49e2ba0b62..280986c697c 100644 --- a/drivers/video/msm/Makefile +++ b/drivers/video/msm/Makefile @@ -1,3 +1,4 @@ +#EXTRA_CFLAGS += -DDEBUG ifeq ($(CONFIG_FB_MSM_MDSS),y) obj-y += mdss/ else @@ -14,6 +15,10 @@ obj-$(CONFIG_DEBUG_FS) += mdp_debugfs.o ifeq ($(CONFIG_FB_MSM_MDP40),y) obj-y += mdp4_util.o +obj-$(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) += mdp4_video_enhance.o +obj-$(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) += mdp4_video_enhance.o +obj-$(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) += mdp4_video_enhance.o +obj-$(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT) += mdp4_video_enhance.o else obj-y += mdp_hw_init.o obj-y += mdp_ppp.o @@ -79,6 +84,7 @@ obj-$(CONFIG_FB_MSM_MIPI_DSI_TOSHIBA) += mipi_toshiba.o obj-$(CONFIG_FB_MSM_MIPI_DSI_NOVATEK) += mipi_novatek.o obj-$(CONFIG_FB_MSM_MIPI_DSI_ORISE) += mipi_orise.o obj-$(CONFIG_FB_MSM_MIPI_DSI_RENESAS) += mipi_renesas.o +obj-$(CONFIG_FB_MSM_MIPI_DSI_SAMSUNG_OLED) += mipi_samsung_oled.o obj-$(CONFIG_FB_MSM_MIPI_DSI_TRULY) += mipi_truly.o obj-$(CONFIG_FB_MSM_MIPI_DSI_NT35510) += mipi_NT35510.o obj-$(CONFIG_FB_MSM_MIPI_DSI_NT35516) += mipi_truly_tft540960_1_e.o @@ -118,6 +124,9 @@ obj-$(CONFIG_FB_MSM_MDDI_ORISE) += mddi_orise.o obj-$(CONFIG_FB_MSM_MDDI_QUICKVX) += mddi_quickvx.o endif +# ESD Recovery +obj-$(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) += mipi_samsung_esd_refresh.o + ifeq ($(CONFIG_FB_MSM_MIPI_PANEL_DETECT),y) obj-y += mipi_toshiba_video_wvga_pt.o mipi_toshiba_video_wsvga_pt.o mipi_toshiba_video_wuxga.o obj-y += mipi_novatek_video_qhd_pt.o mipi_novatek_cmd_qhd_pt.o @@ -139,6 +148,7 @@ obj-$(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT) += mipi_novatek_cmd_qhd_pt.o obj-$(CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT) += mipi_renesas_video_fwvga_pt.o obj-$(CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT) += mipi_renesas_cmd_fwvga_pt.o obj-$(CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT) += mipi_renesas_video_fwvga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) += mipi_samsung_oled_cmd_qhd_pt.o smart_mtp_s6e39a0x02.o obj-$(CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT) += mipi_truly_video_wvga_pt.o obj-$(CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT) += mipi_NT35510_cmd_wvga_pt.o obj-$(CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT) += mipi_NT35510_video_wvga_pt.o @@ -147,6 +157,10 @@ obj-$(CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT) += mipi_truly_tft540960_1_e_video obj-$(CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO) += mipi_simulator_video.o obj-$(CONFIG_FB_MSM_MIPI_CHIMEI_WXGA) += mipi_chimei_wxga_pt.o obj-$(CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA) += mipi_chimei_wuxga.o +obj-$(CONFIG_SAMSUNG_CMC624) += samsung_cmc624.o cmc624_sysfs.o +obj-$(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) += mipi_samsung_oled_video_hd_pt.o smart_mtp_s6e8aa0x01.o +obj-$(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) += mipi_samsung_oled_video_wvga_pt.o smart_mtp_s6e63m0.o +obj-$(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT) += mipi_samsung_tft_video_wxga_pt.o endif obj-$(CONFIG_FB_MSM_LCDC_PANEL) += lcdc_panel.o @@ -173,7 +187,7 @@ obj-$(CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335) += lcdc_truly_ips3p2335.o obj-$(CONFIG_FB_MSM_TVOUT) += tvout_msm.o -ccflags-y := -I$(src)/mhl +ccflags-y := -I$(src) obj-$(CONFIG_FB_MSM_HDMI_MHL_8334) += mhl-8334.o mhl-8334-objs += mhl/mhl_8334.o mhl-8334-objs += mhl/mhl_i2c_utils.o @@ -193,5 +207,6 @@ endif obj-$(CONFIG_MSM_VIDC_1080P) += vidc/ obj-$(CONFIG_MSM_VIDC_720P) += vidc/ +obj-$(CONFIG_VIDEO_MHL_V2) += mhl_v2/ clean: rm *.o .*cmd diff --git a/drivers/video/msm/cmc624.h b/drivers/video/msm/cmc624.h new file mode 100644 index 00000000000..82aa2e52ad1 --- /dev/null +++ b/drivers/video/msm/cmc624.h @@ -0,0 +1,102 @@ +struct cmc624RegisterSet { + unsigned int RegAddr; + unsigned int Data; +}; + +enum eLcd_mDNIe_UI { + mDNIe_UI_MODE, + mDNIe_VIDEO_MODE, + mDNIe_VIDEO_WARM_MODE, + mDNIe_VIDEO_COLD_MODE, + mDNIe_CAMERA_MODE, + mDNIe_NAVI, + mDNIe_GALLERY_MODE, + mDNIe_DMB_MODE, + mDNIe_VT_MODE, + mDNIe_BROWSER_ON_MODE, + MAX_mDNIe_MODE, +}; + +enum SCENARIO_COLOR_TONE { + COLOR_TONE_1 = 40, + COLOR_TONE_2, + COLOR_TONE_3, + COLOR_TONE_MAX, +}; + +enum eCurrent_Temp { + TEMP_STANDARD = 0, + TEMP_WARM, + TEMP_COLD, + MAX_TEMP_MODE, +}; + +enum eBackground_Mode { + DYNAMIC_MODE = 0, + STANDARD_MODE, + MOVIE_MODE, + NATURAL_MODE, + MAX_BACKGROUND_MODE, +}; + +enum eCabc_Mode { + CABC_OFF_MODE = 0, + CABC_ON_MODE, + MAX_CABC_MODE, +}; + +enum eOutdoor_Mode { + OUTDOOR_OFF_MODE = 0, + OUTDOOR_ON_MODE, + MAX_OUTDOOR_MODE, +}; + +enum eNegative_Mode { + NEGATIVE_OFF_MODE = 0, + NEGATIVE_ON_MODE, + MAX_NEGATIVE_MODE, +}; + +enum mDNIe_mode_CABC_type { + mode_type_CABC_none, + mode_type_CABC_on, + mode_type_CABC_off, +}; + +struct str_sub_unit { + char *name; + const struct cmc624RegisterSet *value; + int size; +}; + +struct str_sub_tuning { +/* Array Index 0 : cabc off tuning value +Array Index 1 : cabc on tunning value */ + struct str_sub_unit value[MAX_CABC_MODE]; +}; + +#define TUNE_FLAG_CABC_AUTO 0 +#define TUNE_FLAG_CABC_ALWAYS_OFF 1 +#define TUNE_FLAG_CABC_ALWAYS_ON 2 + + +struct str_main_unit { + char *name; + int flag; + const struct cmc624RegisterSet *tune; + unsigned char *plut; + int size; +}; + +struct str_main_tuning { +/* Array Index 0 : cabc off tuning value +Array Index 1 : cabc on tunning value */ + struct str_main_unit value[MAX_CABC_MODE]; +}; + +extern struct cmc624_state_type cmc624_state; +#define NUM_ITEM_POWER_LUT 9 +#define NUM_POWER_LUT 2 + + +#define NUM_ITEM_POWER_LUT 9 diff --git a/drivers/video/msm/cmc624_sysfs.c b/drivers/video/msm/cmc624_sysfs.c new file mode 100644 index 00000000000..1275587cc74 --- /dev/null +++ b/drivers/video/msm/cmc624_sysfs.c @@ -0,0 +1,514 @@ +/* + * ===================================================================== + * + * Filename: cmc624_sysfs.c + * + * Description: SYSFS Node control driver + * + * Version: 1.0 + * Created: 2011 05/30 15:04:45 + * Revision: none + * Compiler: arm-linux-gcc + * + * Author: Park Gyu Tae (), + * Company: Samsung Electronics + * + * ===================================================================== + +Copyright (C) 2011, Samsung Electronics. All rights reserved. + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "msm_fb.h" +#include +#include +#include +#include "samsung_cmc624.h" +static struct class *mdnie_class; +struct device *tune_cmc624_dev; +struct device *tune_mdnie_dev_cmc; + +#define FALSE 0 +#define TRUE 1 +#define DUMP_CMC624_REGISTER 0 +/* ########################################################## + * # + * # LCD POWER on / Off Sysfs node + * # + * ##########################################################*/ + +static ssize_t lcd_power_file_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + pr_debug("called %s\n", __func__); + return sprintf(buf, "%u\n", cmc624_state.suspended); +} +static ssize_t lcd_power_file_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int value; + + sscanf(buf, "%d", &value); + + pr_debug("[lcd_power] in lcd_power_file_cmd_store," \ + " input value = %d\n", value); + + if ((cmc624_state.suspended == TRUE) && (value == 1)) { + samsung_cmc624_on(value); + pr_debug("[lcd_power on] <= value : %d\n", value); + cmc624_state.suspended = FALSE; + } else if ((cmc624_state.suspended == FALSE) && (value == 0)) { + samsung_cmc624_on(value); + pr_debug("[lcd_power off] <= value : %d\n", value); + cmc624_state.suspended = TRUE; + } else + pr_debug("[lcd_power] lcd is already = %d\n", + cmc624_state.suspended); + + return size; +} + +static DEVICE_ATTR(lcd_power, 0664, lcd_power_file_cmd_show, + lcd_power_file_cmd_store); + +/* ########################################################## + * # + * # LCD Type Sysfs node + * # + * ##########################################################*/ +static const char lcdtype_name[][64] = { + "SEC_LTN089AL03-802", + }; + +static ssize_t lcdtype_file_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + pr_debug("type: %s\n", lcdtype_name[0]); + + return sprintf(buf, lcdtype_name[0]); +} + +static DEVICE_ATTR(lcdtype, 0664, lcdtype_file_cmd_show, NULL); + +/* ########################################################## + * # + * # Scenario change Sysfs node + * # + * ##########################################################*/ +static ssize_t scenario_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + pr_debug("[CMC624:info] : %s called\n", __func__); + return sprintf(buf, "Current Scenario Mode : %d\n", + cmc624_state.scenario); +} + + +static ssize_t scenario_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + int value; + + sscanf(buf, "%d", &value); + pr_debug("[CMC624:INFO] set scenario mode : %d\n", value); + + if (value < mDNIe_UI_MODE || ((value >= MAX_mDNIe_MODE) + && (value < COLOR_TONE_1)) || value >= COLOR_TONE_MAX) { + pr_debug("[CMC624:ERROR] : wrong scenario mode value : %d\n", + value); + return size; + } + + if (cmc624_state.suspended == TRUE) { + if (value >= COLOR_TONE_1) + cmc624_state.browser_scenario = value; + else + cmc624_state.scenario = value; + return size; + } + if (value >= COLOR_TONE_1) + ret = apply_browser_tune_value(value, 0); + else + ret = apply_main_tune_value(value, cmc624_state.background, + cmc624_state.cabc_mode, 0); + + if (ret != 0) + pr_debug("[CMC624:ERROR] ERROR : set main tune value faild\n"); + + return size; +} +static DEVICE_ATTR(scenario, 0664, scenario_show, scenario_store); + +/* ########################################################## + * # + * # Tuning Sysfs node + * # + * ##########################################################*/ +#define MAX_FILE_NAME 128 +static int tuning_enable; +static char tuning_filename[MAX_FILE_NAME]; +static ssize_t tuning_show(struct device *dev, + struct device_attribute *attr, char *buf) + +{ + int ret = 0; + ret = sprintf(buf, "Tunned File Name : %s\n", tuning_filename); + + return ret; +} + + +static ssize_t tuning_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + memset(tuning_filename, 0, sizeof(tuning_filename)); + sprintf(tuning_filename, "%s%s", TUNING_FILE_PATH, buf); + + pr_debug("[CMC624:INFO]:%s:%s\n", __func__, tuning_filename); + + if (load_tuning_data(tuning_filename) <= 0) { + pr_debug("[CMC624:ERROR]:load_tunig_data() failed\n"); + return size; + } + tuning_enable = 1; + return size; +} + +static DEVICE_ATTR(tuning, 0664, tuning_show, tuning_store); + +/* ########################################################## + * # + * # MDNIE OVE Sysfs node + * # + * ##########################################################*/ +static ssize_t outdoor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Current OVE Value : %s\n", + (cmc624_state.outdoor == 0) ? "Disabled" : "Enabled"); +} + + +static ssize_t outdoor_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + int value; + + sscanf(buf, "%d", &value); + pr_debug("[CMC624:INFO] set outdoor : %d\n", value); + + if (value < OUTDOOR_OFF_MODE || value >= MAX_OUTDOOR_MODE) { + pr_debug("[CMC624:ERROR] : wrong outdoor mode value : %d\n", + value); + return size; + } + + if (cmc624_state.suspended == TRUE) { + cmc624_state.outdoor = value; + return size; + } + + ret = apply_sub_tune_value(cmc624_state.temperature, value, + cmc624_state.cabc_mode, 0); + if (ret != 0) + pr_debug("[CMC624:ERROR] ERROR : set sub tune value faild\n"); + + return size; +} + +static DEVICE_ATTR(outdoor, 0664, outdoor_show, outdoor_store); + +/* ########################################################## + * # + * # MDNIE NEGATIVE Sysfs node + * # + * ##########################################################*/ +static ssize_t negative_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Current negative Value : %s\n", + (cmc624_state.negative == 0) ? "Disabled" : "Enabled"); +} + +static ssize_t negative_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + int value; + + sscanf(buf, "%d", &value); + pr_debug("[CMC624:INFO] set negative : %d\n", value); + + if (value < NEGATIVE_OFF_MODE || value >= MAX_NEGATIVE_MODE) { + pr_debug("[CMC624:ERROR] : wrong negative mode value : %d\n", + value); + return size; + } + + if (cmc624_state.suspended == TRUE) { + cmc624_state.negative = value; + return size; + } + ret = apply_negative_tune_value(value, cmc624_state.cabc_mode); + if (ret != 0) + pr_debug("[CMC624:ERROR] ERROR : set negative value faild\n"); + + return size; +} + +static DEVICE_ATTR(negative, 0664, negative_show, negative_store); + + +/* ########################################################## + * # + * # MDNIE Temprature Sysfs node + * # + * ##########################################################*/ +static ssize_t mdnie_temp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const char temp_name[MAX_TEMP_MODE][16] = { + "STANDARD", + "WARM", + "COLD", + }; + + if (cmc624_state.temperature >= MAX_TEMP_MODE) { + pr_debug("[CMC624:ERROR] : wrong color temperature mode value : %d\n", + cmc624_state.temperature); + return 0; + } + + return sprintf(buf, "Current Color Temperature Mode : %s\n", + temp_name[cmc624_state.temperature]); +} + + +static ssize_t mdnie_temp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + int value; + + sscanf(buf, "%d", &value); + pr_debug("[CMC624:INFO] set color temperature : %d\n", value); + + if (value < TEMP_STANDARD || value >= MAX_TEMP_MODE) { + pr_debug("[CMC624:ERROR] : wrong color temperature mode value :%d\n" + , value); + return size; + } + + if (cmc624_state.suspended == TRUE) { + cmc624_state.temperature = value; + return size; + } + ret = apply_sub_tune_value(value, cmc624_state.outdoor, + cmc624_state.cabc_mode, 0); + if (ret != 0) + pr_debug("[CMC624:ERROR] ERROR : set sub tune value faild\n"); + return size; +} + +static DEVICE_ATTR(mdnie_temp, 0664, mdnie_temp_show, mdnie_temp_store); + +/* ########################################################## + * # + * # MDNIE BG Sysfs node + * # + * ##########################################################*/ + +/* ########################################################## + * # + * # 0. Dynamic + * # 1. Standard + * # 2. Video + * # 3. Natural + * # + * ##########################################################*/ + +static ssize_t mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const char background_name[MAX_BACKGROUND_MODE][16] = { + "STANDARD", + "DYNAMIC", + "MOVIE", + "NATURAL", + }; + + if (cmc624_state.background >= MAX_BACKGROUND_MODE) { + pr_debug("[CMC624:ERROR] : Undefined Background Mode : %d\n", + cmc624_state.background); + return 0; + } + pr_debug("%s, cmc624_state.backgroudn : %d\n", + __func__, cmc624_state.background); + return sprintf(buf, "Current Background Mode : %s\n", + background_name[cmc624_state.background]); +} +static ssize_t mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + int value; + + sscanf(buf, "%d", &value); + pr_debug("[CMC624:INFO] set background mode : %d\n", value); + + if (value < DYNAMIC_MODE || value >= MAX_BACKGROUND_MODE) { + pr_debug("[CMC624:ERROR] : wrong backgound mode value : %d\n", + value); + return size; + } + + if (cmc624_state.suspended == TRUE) { + cmc624_state.background = value; + return size; + } + ret = apply_main_tune_value(cmc624_state.scenario, value, + cmc624_state.cabc_mode, 0); + if (ret != 0) + pr_debug("[CMC624:ERROR] ERROR : set main tune value faild\n"); + return size; +} + + +static DEVICE_ATTR(mode, 0664, mode_show, mode_store); + +#if DUMP_CMC624_REGISTER +/* ########################################################## + * # + * # MDNIE DUMP Sysfs node + * # - dump cmc624 register + * ##########################################################*/ +static ssize_t mdnie_dump_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + pr_debug("##################################\n"); + pr_debug(" CMC624 Register DUMP\n"); + pr_debug("##################################\n"); + + dump_cmc624_register(); + + return 0; +} +static ssize_t mdnie_dump_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + int value; + pr_debug("[CMC624:INFO] dump\n"); + return size; +} + +static DEVICE_ATTR(mdnie_dump, 0664, mdnie_dump_show, mdnie_dump_store); +#endif + +int cmc624_sysfs_init(void) +{ + + int ret = 0; + /* 1. CLASS Create + * 2. Device Create + * 3. node create + * - bypass on/off node + * - cabc on/off node + * - lcd_power node + * - scenario node + * - tuning node + * - mdnie_outdoor node + * - mdnie_bg node*/ + mdnie_class = class_create(THIS_MODULE, "mdnie"); + if (IS_ERR(mdnie_class)) { + pr_debug("Failed to create class(mdnie_class)!!\n"); + ret = -1; + } + tune_mdnie_dev_cmc = device_create(mdnie_class, NULL, 0, NULL, "mdnie"); + if (IS_ERR(tune_mdnie_dev_cmc)) { + pr_debug("Failed to create device(tune_mdnie_dev_cmc)!!"); + ret = -1; + } + if (device_create_file(tune_mdnie_dev_cmc, + &dev_attr_lcd_power) < 0) { + pr_debug("Failed to create device file!(%s)!\n",\ + dev_attr_lcd_power.attr.name); + ret = -1; + } + if (device_create_file(tune_mdnie_dev_cmc, &dev_attr_lcdtype) < 0) { + pr_debug("Failed to create device file!(%s)!\n",\ + dev_attr_lcdtype.attr.name); + ret = -1; + } + if (device_create_file(tune_mdnie_dev_cmc, &dev_attr_scenario) < 0) { + pr_debug("Failed to create device file!(%s)!\n",\ + dev_attr_scenario.attr.name); + ret = -1; + } + if (device_create_file(tune_mdnie_dev_cmc, &dev_attr_tuning) < 0) { + pr_debug("Failed to create device file(%s)!\n",\ + dev_attr_tuning.attr.name); + ret = -1; + } + if (device_create_file(tune_mdnie_dev_cmc, &dev_attr_outdoor) < 0) { + pr_debug("[CMC624:ERROR] device_crate_filed(%s)\n",\ + dev_attr_outdoor.attr.name); + ret = -1; + } + if (device_create_file(tune_mdnie_dev_cmc, &dev_attr_negative) < 0) { + pr_debug("[CMC624:ERROR] device_create_file(%s)\n",\ + dev_attr_negative.attr.name); + ret = -1; + } + if (device_create_file(tune_mdnie_dev_cmc, &dev_attr_mdnie_temp) < 0) { + pr_debug("[CMC624:ERROR] device_crate_filed(%s)\n",\ + dev_attr_mdnie_temp.attr.name); + ret = -1; + } + if (device_create_file(tune_mdnie_dev_cmc, &dev_attr_mode) < 0) { + pr_debug("[CMC624:ERROR] device_crate_filed(%s)\n",\ + dev_attr_mode.attr.name); + ret = -1; + } +#if DUMP_CMC624_REGISTER + if (device_create_file(tune_mdnie_dev_cmc, &dev_attr_mdnie_dump) < 0) { + pr_debug("[CMC624:ERROR] device_crate_filed(%s)\n"\ + , dev_attr_mdnie_dump.attr.name); + ret = -1; + } +#endif + return 0; +} diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c index e4fd7d6ad55..741d4724f99 100644 --- a/drivers/video/msm/hdmi_msm.c +++ b/drivers/video/msm/hdmi_msm.c @@ -91,6 +91,7 @@ static void hdmi_msm_turn_on(void); static int hdmi_msm_audio_off(void); static int hdmi_msm_read_edid(void); static void hdmi_msm_hpd_off(void); +static int hdmi_msm_hpd_on(void); static boolean hdmi_msm_is_dvi_mode(void); #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT @@ -771,6 +772,28 @@ static void hdmi_msm_turn_on(void); static int hdmi_msm_audio_off(void); static int hdmi_msm_read_edid(void); static void hdmi_msm_hpd_off(void); +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) \ + || defined(CONFIG_VIDEO_MHL_TAB_V2) +void mhl_hpd_handler(bool state) +{ + pr_info("mhl_hpd_handler with state as %d\n", state); + hdmi_msm_state->mhl_hpd_state = state; +// hdmi_msm_state->hpd_cable_chg_detected = TRUE; +// hdmi_msm_state->hpd_on_offline = state; + +// if (state && hdmi_msm_state->boot_completion) { + /*To make sure that the previous + disconnect event handling is completed.*/ + if (state) { + msleep(20); + hdmi_msm_hpd_on(); + } +// } else if (!hdmi_msm_state->boot_completion) { +// pr_err("hdmi_msm_state->boot_completion = %d\n", +// hdmi_msm_state->boot_completion); +// } +} +#endif static bool hdmi_ready(void) { @@ -4515,6 +4538,12 @@ static int hdmi_msm_power_off(struct platform_device *pdev) /* Set HPD cable sense polarity */ hdmi_msm_hpd_polarity_setup(); +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) \ + || defined(CONFIG_VIDEO_MHL_TAB_V2) + if (hdmi_msm_state->mhl_hpd_state) + hdmi_msm_hpd_on(); + +#endif return ret; } @@ -4647,6 +4676,10 @@ static int __devinit hdmi_msm_probe(struct platform_device *pdev) goto error; } +#ifdef CONFIG_SAMSUNG_HDMI_ENABLE_POWER + if (hdmi_msm_state->pd->hdmi_enable) + hdmi_msm_state->pd->hdmi_enable(); +#endif if (!hdmi_msm_state->pd->cec_power) { DEV_ERR("Init FAILED: cec_power function missing\n"); rc = -ENODEV; @@ -4785,7 +4818,11 @@ static int hdmi_msm_hpd_feature(int on) DEV_INFO("%s: %d\n", __func__, on); if (on) { - rc = hdmi_msm_hpd_on(); +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) \ + || defined(CONFIG_VIDEO_MHL_TAB_V2) + if (hdmi_msm_state->mhl_hpd_state) +#endif + rc = hdmi_msm_hpd_on(); } else { if (external_common_state->hpd_state) { external_common_state->hpd_state = 0; diff --git a/drivers/video/msm/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h index ed8c568f230..b627e48b256 100644 --- a/drivers/video/msm/hdmi_msm.h +++ b/drivers/video/msm/hdmi_msm.h @@ -103,7 +103,10 @@ struct hdmi_msm_state_type { struct clk *hdmi_s_pclk; void __iomem *qfprom_io; void __iomem *hdmi_io; - +#if defined(CONFIG_VIDEO_MHL_V1) || defined(CONFIG_VIDEO_MHL_V2) || \ + defined(CONFIG_VIDEO_MHL_TAB_V2) + boolean mhl_hpd_state; +#endif struct external_common_state_type common; boolean is_mhl_enabled; struct completion hpd_event_processed; diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 30e0ea8b049..bf728cba5a4 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -534,8 +534,7 @@ int mdp_hist_lut_config(struct mdp_hist_lut_data *data) } DEFINE_MUTEX(mdp_lut_push_sem); -static int mdp_lut_i; - +int mdp_lut_i; static int mdp_lut_hw_update(struct fb_cmap *cmap) { int i; @@ -566,8 +565,8 @@ static int mdp_lut_hw_update(struct fb_cmap *cmap) return 0; } -static int mdp_lut_push; -static int mdp_lut_push_i; +int mdp_lut_push; +int mdp_lut_push_i; static int mdp_lut_update_nonlcdc(struct fb_info *info, struct fb_cmap *cmap) { int ret; diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h index 046e161eec5..8ca2ae13dff 100644 --- a/drivers/video/msm/mdp.h +++ b/drivers/video/msm/mdp.h @@ -48,6 +48,10 @@ extern struct mdp_csc_cfg_data csc_cfg_matrix[]; extern struct workqueue_struct *mdp_hist_wq; extern uint32 mdp_intr_mask; +extern int mdp_lut_i; +extern int mdp_lut_push; +extern int mdp_lut_push_i; +extern struct mutex mdp_lut_push_sem; #define MDP4_REVISION_V1 0 #define MDP4_REVISION_V2 1 diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h index 7a2efc53c9b..81f9312979a 100644 --- a/drivers/video/msm/mdp4.h +++ b/drivers/video/msm/mdp4.h @@ -466,6 +466,18 @@ void mdp4_isr_read(int); void mdp4_clear_lcdc(void); void mdp4_mixer_blend_init(int mixer_num); void mdp4_vg_qseed_init(int vg_num); +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT) +void mdp4_vg_qseed_init_DMB(int vg_num); +void mdp4_vg_qseed_init_VideoPlay(int vg_num); +#endif void mdp4_vg_csc_update(struct mdp_csc *p); irqreturn_t mdp4_isr(int irq, void *ptr); void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe); @@ -931,6 +943,26 @@ int mdp4_qseed_access_cfg(struct mdp_qseed_cfg *cfg, uint32_t base); u32 mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num); void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num); void mdp4_free_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num); +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +void set_esd_disable(void); +void set_esd_enable(void); +boolean get_esd_refresh_stat(void); +#endif + +extern int play_speed_1_5; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) || \ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) +extern boolean camera_mode; +#endif + +#if defined(CONFIG_SAMSUNG_CMC624) +extern boolean video_mode; +void cmc_timing_generator_reset(void) ; +void mipi_samsung_oled_display_fast_init(void); +void pull_ldi_reset_down(void); +void pull_ldi_reset_up(void); +bool samsung_has_cmc624(void); +#endif int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg); void mdp4_overlay_iommu_pipe_free(int ndx, int all); diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c index c6c3068f1b5..73086a8e846 100644 --- a/drivers/video/msm/mdp4_util.c +++ b/drivers/video/msm/mdp4_util.c @@ -1254,6 +1254,561 @@ static uint32 vg_qseed_table2[] = { 0x0f800ffa, 0x0f4f0337, 0x0f6d0ffe, 0x0f57033e }; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT) +static uint32 vg_qseed_table2_DMB[] = { + 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008, + 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020, + 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e, + 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060, + 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087, + 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1, + 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd, + 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109, + 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135, + 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160, + 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187, + 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac, + 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb, + 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3, + 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5, + 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff, + + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + + 0x02000000, 0x00000000, 0x01fc0ff9, 0x0ffe000d, + 0x01f60ff3, 0x0ffb001c, 0x01ef0fed, 0x0ff9002b, + 0x01e60fe8, 0x0ff6003c, 0x01dc0fe4, 0x0ff3004d, + 0x01d00fe0, 0x0ff1005f, 0x01c30fde, 0x0fee0071, + 0x01b50fdb, 0x0feb0085, 0x01a70fd9, 0x0fe80098, + 0x01960fd8, 0x0fe600ac, 0x01850fd7, 0x0fe300c1, + 0x01730fd7, 0x0fe100d5, 0x01610fd7, 0x0fdf00e9, + 0x014e0fd8, 0x0fdd00fd, 0x013b0fd8, 0x0fdb0112, + 0x01250fda, 0x0fda0127, 0x01120fdb, 0x0fd8013b, + 0x00fd0fdd, 0x0fd8014e, 0x00e90fdf, 0x0fd70161, + 0x00d50fe1, 0x0fd70173, 0x00c10fe3, 0x0fd70185, + 0x00ac0fe6, 0x0fd80196, 0x00980fe8, 0x0fd901a7, + 0x00850feb, 0x0fdb01b5, 0x00710fee, 0x0fde01c3, + 0x005f0ff1, 0x0fe001d0, 0x004d0ff3, 0x0fe401dc, + 0x003c0ff6, 0x0fe801e6, 0x002b0ff9, 0x0fed01ef, + 0x001c0ffb, 0x0ff301f6, 0x000d0ffe, 0x0ff901fc, + + 0x020f0034, 0x0f7a0043, 0x01e80023, 0x0fa8004d, + 0x01d30016, 0x0fbe0059, 0x01c6000a, 0x0fc90067, + 0x01bd0000, 0x0fce0075, 0x01b50ff7, 0x0fcf0085, + 0x01ae0fee, 0x0fcf0095, 0x01a70fe6, 0x0fcd00a6, + 0x019d0fe0, 0x0fcb00b8, 0x01940fd9, 0x0fc900ca, + 0x01890fd4, 0x0fc700dc, 0x017d0fcf, 0x0fc600ee, + 0x01700fcc, 0x0fc40100, 0x01620fc9, 0x0fc40111, + 0x01540fc6, 0x0fc30123, 0x01430fc5, 0x0fc40134, + 0x01340fc4, 0x0fc50143, 0x01230fc3, 0x0fc60154, + 0x01110fc4, 0x0fc90162, 0x01000fc4, 0x0fcc0170, + 0x00ee0fc6, 0x0fcf017d, 0x00dc0fc7, 0x0fd40189, + 0x00ca0fc9, 0x0fd90194, 0x00b80fcb, 0x0fe0019d, + 0x00a60fcd, 0x0fe601a7, 0x00950fcf, 0x0fee01ae, + 0x00850fcf, 0x0ff701b5, 0x00750fce, 0x000001bd, + 0x00670fc9, 0x000a01c6, 0x00590fbe, 0x001601d3, + 0x004d0fa8, 0x002301e8, 0x00430f7a, 0x0034020f, + + 0x015c005e, 0x0fde0068, 0x015c0054, 0x0fdd0073, + 0x015b004b, 0x0fdc007e, 0x015a0042, 0x0fdb0089, + 0x01590039, 0x0fda0094, 0x01560030, 0x0fda00a0, + 0x01530028, 0x0fda00ab, 0x014f0020, 0x0fda00b7, + 0x014a0019, 0x0fdb00c2, 0x01450011, 0x0fdc00ce, + 0x013e000b, 0x0fde00d9, 0x01390004, 0x0fdf00e4, + 0x01310ffe, 0x0fe200ef, 0x01290ff9, 0x0fe400fa, + 0x01200ff4, 0x0fe80104, 0x01180fef, 0x0feb010e, + 0x010e0feb, 0x0fef0118, 0x01040fe8, 0x0ff40120, + 0x00fa0fe4, 0x0ff90129, 0x00ef0fe2, 0x0ffe0131, + 0x00e40fdf, 0x00040139, 0x00d90fde, 0x000b013e, + 0x00ce0fdc, 0x00110145, 0x00c20fdb, 0x0019014a, + 0x00b70fda, 0x0020014f, 0x00ab0fda, 0x00280153, + 0x00a00fda, 0x00300156, 0x00940fda, 0x00390159, + 0x00890fdb, 0x0042015a, 0x007e0fdc, 0x004b015b, + 0x00730fdd, 0x0054015c, 0x00680fde, 0x005e015c, + + 0x01300068, 0x0ff80070, 0x01300060, 0x0ff80078, + 0x012f0059, 0x0ff80080, 0x012d0052, 0x0ff80089, + 0x012b004b, 0x0ff90091, 0x01290044, 0x0ff9009a, + 0x0126003d, 0x0ffa00a3, 0x01220037, 0x0ffb00ac, + 0x011f0031, 0x0ffc00b4, 0x011a002b, 0x0ffe00bd, + 0x01150026, 0x000000c5, 0x010f0021, 0x000200ce, + 0x010a001c, 0x000400d6, 0x01030018, 0x000600df, + 0x00fd0014, 0x000900e6, 0x00f60010, 0x000c00ee, + 0x00ee000c, 0x001000f6, 0x00e60009, 0x001400fd, + 0x00df0006, 0x00180103, 0x00d60004, 0x001c010a, + 0x00ce0002, 0x0021010f, 0x00c50000, 0x00260115, + 0x00bd0ffe, 0x002b011a, 0x00b40ffc, 0x0031011f, + 0x00ac0ffb, 0x00370122, 0x00a30ffa, 0x003d0126, + 0x009a0ff9, 0x00440129, 0x00910ff9, 0x004b012b, + 0x00890ff8, 0x0052012d, 0x00800ff8, 0x0059012f, + 0x00780ff8, 0x00600130, 0x00700ff8, 0x00680130, + + 0x01050079, 0x0003007f, 0x01040073, 0x00030086, + 0x0103006d, 0x0004008c, 0x01030066, 0x00050092, + 0x01010060, 0x00060099, 0x0100005a, 0x0007009f, + 0x00fe0054, 0x000900a5, 0x00fa004f, 0x000b00ac, + 0x00f80049, 0x000d00b2, 0x00f50044, 0x000f00b8, + 0x00f2003f, 0x001200bd, 0x00ef0039, 0x001500c3, + 0x00ea0035, 0x001800c9, 0x00e60030, 0x001c00ce, + 0x00e3002b, 0x001f00d3, 0x00dd0027, 0x002300d9, + 0x00d90023, 0x002700dd, 0x00d3001f, 0x002b00e3, + 0x00ce001c, 0x003000e6, 0x00c90018, 0x003500ea, + 0x00c30015, 0x003900ef, 0x00bd0012, 0x003f00f2, + 0x00b8000f, 0x004400f5, 0x00b2000d, 0x004900f8, + 0x00ac000b, 0x004f00fa, 0x00a50009, 0x005400fe, + 0x009f0007, 0x005a0100, 0x00990006, 0x00600101, + 0x00920005, 0x00660103, 0x008c0004, 0x006d0103, + 0x00860003, 0x00730104, 0x007f0003, 0x00790105, + + 0x00cf0088, 0x001d008c, 0x00ce0084, 0x0020008e, + 0x00cd0080, 0x00210092, 0x00cd007b, 0x00240094, + 0x00ca0077, 0x00270098, 0x00c90073, 0x0029009b, + 0x00c8006f, 0x002c009d, 0x00c6006b, 0x002f00a0, + 0x00c50067, 0x003200a2, 0x00c30062, 0x003600a5, + 0x00c0005f, 0x003900a8, 0x00c0005b, 0x003b00aa, + 0x00be0057, 0x003e00ad, 0x00ba0054, 0x004200b0, + 0x00b90050, 0x004500b2, 0x00b7004c, 0x004900b4, + 0x00b40049, 0x004c00b7, 0x00b20045, 0x005000b9, + 0x00b00042, 0x005400ba, 0x00ad003e, 0x005700be, + 0x00aa003b, 0x005b00c0, 0x00a80039, 0x005f00c0, + 0x00a50036, 0x006200c3, 0x00a20032, 0x006700c5, + 0x00a0002f, 0x006b00c6, 0x009d002c, 0x006f00c8, + 0x009b0029, 0x007300c9, 0x00980027, 0x007700ca, + 0x00940024, 0x007b00cd, 0x00920021, 0x008000cd, + 0x008e0020, 0x008400ce, 0x008c001d, 0x008800cf, + + 0x008e0083, 0x006b0084, 0x008d0083, 0x006c0084, + 0x008d0082, 0x006d0084, 0x008d0081, 0x006d0085, + 0x008d0080, 0x006e0085, 0x008c007f, 0x006f0086, + 0x008b007f, 0x00700086, 0x008b007e, 0x00710086, + 0x008b007d, 0x00720086, 0x008a007d, 0x00730086, + 0x008a007c, 0x00730087, 0x008a007b, 0x00740087, + 0x0089007b, 0x00750087, 0x008a0079, 0x00750088, + 0x008a0078, 0x00760088, 0x008a0077, 0x00770088, + 0x00880077, 0x0077008a, 0x00880076, 0x0078008a, + 0x00880075, 0x0079008a, 0x00870075, 0x007b0089, + 0x00870074, 0x007b008a, 0x00870073, 0x007c008a, + 0x00860073, 0x007d008a, 0x00860072, 0x007d008b, + 0x00860071, 0x007e008b, 0x00860070, 0x007f008b, + 0x0086006f, 0x007f008c, 0x0085006e, 0x0080008d, + 0x0085006d, 0x0081008d, 0x0084006d, 0x0082008d, + 0x0084006c, 0x0083008d, 0x0084006b, 0x0083008e, + + 0x023c0fe2, 0x00000fe2, 0x023a0fdb, 0x00000feb, + 0x02360fd3, 0x0fff0ff8, 0x022e0fcf, 0x0ffc0007, + 0x02250fca, 0x0ffa0017, 0x021a0fc6, 0x0ff70029, + 0x020c0fc4, 0x0ff4003c, 0x01fd0fc1, 0x0ff10051, + 0x01eb0fc0, 0x0fed0068, 0x01d80fc0, 0x0fe9007f, + 0x01c30fc1, 0x0fe50097, 0x01ac0fc2, 0x0fe200b0, + 0x01960fc3, 0x0fdd00ca, 0x017e0fc5, 0x0fd900e4, + 0x01650fc8, 0x0fd500fe, 0x014b0fcb, 0x0fd20118, + 0x01330fcd, 0x0fcd0133, 0x01180fd2, 0x0fcb014b, + 0x00fe0fd5, 0x0fc80165, 0x00e40fd9, 0x0fc5017e, + 0x00ca0fdd, 0x0fc30196, 0x00b00fe2, 0x0fc201ac, + 0x00970fe5, 0x0fc101c3, 0x007f0fe9, 0x0fc001d8, + 0x00680fed, 0x0fc001eb, 0x00510ff1, 0x0fc101fd, + 0x003c0ff4, 0x0fc4020c, 0x00290ff7, 0x0fc6021a, + 0x00170ffa, 0x0fca0225, 0x00070ffc, 0x0fcf022e, + 0x0ff80fff, 0x0fd30236, 0x0feb0000, 0x0fdb023a, + + 0x02780fc4, 0x00000fc4, 0x02770fbc, 0x0fff0fce, + 0x02710fb5, 0x0ffe0fdc, 0x02690fb0, 0x0ffa0fed, + 0x025f0fab, 0x0ff70fff, 0x02500fa8, 0x0ff30015, + 0x02410fa6, 0x0fef002a, 0x022f0fa4, 0x0feb0042, + 0x021a0fa4, 0x0fe5005d, 0x02040fa5, 0x0fe10076, + 0x01eb0fa7, 0x0fdb0093, 0x01d20fa9, 0x0fd600af, + 0x01b80fab, 0x0fd000cd, 0x019d0faf, 0x0fca00ea, + 0x01810fb2, 0x0fc50108, 0x01620fb7, 0x0fc10126, + 0x01440fbb, 0x0fbb0146, 0x01260fc1, 0x0fb70162, + 0x01080fc5, 0x0fb20181, 0x00ea0fca, 0x0faf019d, + 0x00cd0fd0, 0x0fab01b8, 0x00af0fd6, 0x0fa901d2, + 0x00930fdb, 0x0fa701eb, 0x00760fe1, 0x0fa50204, + 0x005d0fe5, 0x0fa4021a, 0x00420feb, 0x0fa4022f, + 0x002a0fef, 0x0fa60241, 0x00150ff3, 0x0fa80250, + 0x0fff0ff7, 0x0fab025f, 0x0fed0ffa, 0x0fb00269, + 0x0fdc0ffe, 0x0fb50271, 0x0fce0fff, 0x0fbc0277, + + 0x02a00fb0, 0x00000fb0, 0x029e0fa8, 0x0fff0fbb, + 0x02980fa1, 0x0ffd0fca, 0x028f0f9c, 0x0ff90fdc, + 0x02840f97, 0x0ff50ff0, 0x02740f94, 0x0ff10007, + 0x02640f92, 0x0fec001e, 0x02500f91, 0x0fe70038, + 0x023a0f91, 0x0fe00055, 0x02220f92, 0x0fdb0071, + 0x02080f95, 0x0fd4008f, 0x01ec0f98, 0x0fce00ae, + 0x01cf0f9b, 0x0fc700cf, 0x01b10f9f, 0x0fc100ef, + 0x01920fa4, 0x0fbb010f, 0x01710faa, 0x0fb50130, + 0x01520fae, 0x0fae0152, 0x01300fb5, 0x0faa0171, + 0x010f0fbb, 0x0fa40192, 0x00ef0fc1, 0x0f9f01b1, + 0x00cf0fc7, 0x0f9b01cf, 0x00ae0fce, 0x0f9801ec, + 0x008f0fd4, 0x0f950208, 0x00710fdb, 0x0f920222, + 0x00550fe0, 0x0f91023a, 0x00380fe7, 0x0f910250, + 0x001e0fec, 0x0f920264, 0x00070ff1, 0x0f940274, + 0x0ff00ff5, 0x0f970284, 0x0fdc0ff9, 0x0f9c028f, + 0x0fca0ffd, 0x0fa10298, 0x0fbb0fff, 0x0fa8029e, + + 0x02c80f9c, 0x00000f9c, 0x02c70f94, 0x0ffe0fa7, + 0x02c10f8c, 0x0ffc0fb7, 0x02b70f87, 0x0ff70fcb, + 0x02aa0f83, 0x0ff30fe0, 0x02990f80, 0x0fee0ff9, + 0x02870f7f, 0x0fe80012, 0x02720f7e, 0x0fe2002e, + 0x025a0f7e, 0x0fdb004d, 0x02400f80, 0x0fd5006b, + 0x02230f84, 0x0fcd008c, 0x02050f87, 0x0fc700ad, + 0x01e60f8b, 0x0fbf00d0, 0x01c60f90, 0x0fb700f3, + 0x01a30f96, 0x0fb00117, 0x01800f9c, 0x0faa013a, + 0x015d0fa2, 0x0fa2015f, 0x013a0faa, 0x0f9c0180, + 0x01170fb0, 0x0f9601a3, 0x00f30fb7, 0x0f9001c6, + 0x00d00fbf, 0x0f8b01e6, 0x00ad0fc7, 0x0f870205, + 0x008c0fcd, 0x0f840223, 0x006b0fd5, 0x0f800240, + 0x004d0fdb, 0x0f7e025a, 0x002e0fe2, 0x0f7e0272, + 0x00120fe8, 0x0f7f0287, 0x0ff90fee, 0x0f800299, + 0x0fe00ff3, 0x0f8302aa, 0x0fcb0ff7, 0x0f8702b7, + 0x0fb70ffc, 0x0f8c02c1, 0x0fa70ffe, 0x0f9402c7, + + 0x02f00f88, 0x00000f88, 0x02ee0f80, 0x0ffe0f94, + 0x02e70f78, 0x0ffc0fa5, 0x02dd0f73, 0x0ff60fba, + 0x02ce0f6f, 0x0ff20fd1, 0x02be0f6c, 0x0feb0feb, + 0x02aa0f6b, 0x0fe50006, 0x02940f6a, 0x0fde0024, + 0x02790f6c, 0x0fd60045, 0x025e0f6e, 0x0fcf0065, + 0x023f0f72, 0x0fc60089, 0x021d0f77, 0x0fbf00ad, + 0x01fd0f7b, 0x0fb600d2, 0x01da0f81, 0x0fad00f8, + 0x01b50f87, 0x0fa6011e, 0x018f0f8f, 0x0f9e0144, + 0x016b0f95, 0x0f95016b, 0x01440f9e, 0x0f8f018f, + 0x011e0fa6, 0x0f8701b5, 0x00f80fad, 0x0f8101da, + 0x00d20fb6, 0x0f7b01fd, 0x00ad0fbf, 0x0f77021d, + 0x00890fc6, 0x0f72023f, 0x00650fcf, 0x0f6e025e, + 0x00450fd6, 0x0f6c0279, 0x00240fde, 0x0f6a0294, + 0x00060fe5, 0x0f6b02aa, 0x0feb0feb, 0x0f6c02be, + 0x0fd10ff2, 0x0f6f02ce, 0x0fba0ff6, 0x0f7302dd, + 0x0fa50ffc, 0x0f7802e7, 0x0f940ffe, 0x0f8002ee, + + 0x03180f74, 0x00000f74, 0x03160f6b, 0x0ffe0f81, + 0x030e0f64, 0x0ffb0f93, 0x03030f5f, 0x0ff50fa9, + 0x02f40f5b, 0x0ff00fc1, 0x02e20f58, 0x0fe90fdd, + 0x02cd0f57, 0x0fe20ffa, 0x02b60f57, 0x0fda0019, + 0x02990f59, 0x0fd1003d, 0x027b0f5c, 0x0fc90060, + 0x02590f61, 0x0fc00086, 0x02370f66, 0x0fb700ac, + 0x02130f6b, 0x0fae00d4, 0x01ee0f72, 0x0fa400fc, + 0x01c70f79, 0x0f9b0125, 0x019f0f81, 0x0f93014d, + 0x01760f89, 0x0f890178, 0x014d0f93, 0x0f81019f, + 0x01250f9b, 0x0f7901c7, 0x00fc0fa4, 0x0f7201ee, + 0x00d40fae, 0x0f6b0213, 0x00ac0fb7, 0x0f660237, + 0x00860fc0, 0x0f610259, 0x00600fc9, 0x0f5c027b, + 0x003d0fd1, 0x0f590299, 0x00190fda, 0x0f5702b6, + 0x0ffa0fe2, 0x0f5702cd, 0x0fdd0fe9, 0x0f5802e2, + 0x0fc10ff0, 0x0f5b02f4, 0x0fa90ff5, 0x0f5f0303, + 0x0f930ffb, 0x0f64030e, 0x0f810ffe, 0x0f6b0316, + + 0x03400f60, 0x00000f60, 0x033e0f57, 0x0ffe0f6d, + 0x03370f4f, 0x0ffa0f80, 0x032a0f4b, 0x0ff30f98, + 0x031a0f46, 0x0fee0fb2, 0x03070f44, 0x0fe60fcf, + 0x02f10f44, 0x0fde0fed, 0x02d70f44, 0x0fd6000f, + 0x02b80f46, 0x0fcc0036, 0x02990f4a, 0x0fc3005a, + 0x02750f4f, 0x0fb90083, 0x02500f55, 0x0fb000ab, + 0x022a0f5b, 0x0fa500d6, 0x02020f63, 0x0f9a0101, + 0x01d80f6b, 0x0f91012c, 0x01ae0f74, 0x0f870157, + 0x01840f7c, 0x0f7c0184, 0x01570f87, 0x0f7401ae, + 0x012c0f91, 0x0f6b01d8, 0x01010f9a, 0x0f630202, + 0x00d60fa5, 0x0f5b022a, 0x00ab0fb0, 0x0f550250, + 0x00830fb9, 0x0f4f0275, 0x005a0fc3, 0x0f4a0299, + 0x00360fcc, 0x0f4602b8, 0x000f0fd6, 0x0f4402d7, + 0x0fed0fde, 0x0f4402f1, 0x0fcf0fe6, 0x0f440307, + 0x0fb20fee, 0x0f46031a, 0x0f980ff3, 0x0f4b032a, + 0x0f800ffa, 0x0f4f0337, 0x0f6d0ffe, 0x0f57033e, + + 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008, + 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020, + 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e, + 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060, + 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087, + 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1, + 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd, + 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109, + 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135, + 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160, + 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187, + 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac, + 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb, + 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3, + 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5, + 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff, + + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + + 0x02000000, 0x00000000, 0x01fc0ff9, 0x0ffe000d, + 0x01f60ff3, 0x0ffb001c, 0x01ef0fed, 0x0ff9002b, + 0x01e60fe8, 0x0ff6003c, 0x01dc0fe4, 0x0ff3004d, + 0x01d00fe0, 0x0ff1005f, 0x01c30fde, 0x0fee0071, + 0x01b50fdb, 0x0feb0085, 0x01a70fd9, 0x0fe80098, + 0x01960fd8, 0x0fe600ac, 0x01850fd7, 0x0fe300c1, + 0x01730fd7, 0x0fe100d5, 0x01610fd7, 0x0fdf00e9, + 0x014e0fd8, 0x0fdd00fd, 0x013b0fd8, 0x0fdb0112, + 0x01250fda, 0x0fda0127, 0x01120fdb, 0x0fd8013b, + 0x00fd0fdd, 0x0fd8014e, 0x00e90fdf, 0x0fd70161, + 0x00d50fe1, 0x0fd70173, 0x00c10fe3, 0x0fd70185, + 0x00ac0fe6, 0x0fd80196, 0x00980fe8, 0x0fd901a7, + 0x00850feb, 0x0fdb01b5, 0x00710fee, 0x0fde01c3, + 0x005f0ff1, 0x0fe001d0, 0x004d0ff3, 0x0fe401dc, + 0x003c0ff6, 0x0fe801e6, 0x002b0ff9, 0x0fed01ef, + 0x001c0ffb, 0x0ff301f6, 0x000d0ffe, 0x0ff901fc, + + 0x020f0034, 0x0f7a0043, 0x01e80023, 0x0fa8004d, + 0x01d30016, 0x0fbe0059, 0x01c6000a, 0x0fc90067, + 0x01bd0000, 0x0fce0075, 0x01b50ff7, 0x0fcf0085, + 0x01ae0fee, 0x0fcf0095, 0x01a70fe6, 0x0fcd00a6, + 0x019d0fe0, 0x0fcb00b8, 0x01940fd9, 0x0fc900ca, + 0x01890fd4, 0x0fc700dc, 0x017d0fcf, 0x0fc600ee, + 0x01700fcc, 0x0fc40100, 0x01620fc9, 0x0fc40111, + 0x01540fc6, 0x0fc30123, 0x01430fc5, 0x0fc40134, + 0x01340fc4, 0x0fc50143, 0x01230fc3, 0x0fc60154, + 0x01110fc4, 0x0fc90162, 0x01000fc4, 0x0fcc0170, + 0x00ee0fc6, 0x0fcf017d, 0x00dc0fc7, 0x0fd40189, + 0x00ca0fc9, 0x0fd90194, 0x00b80fcb, 0x0fe0019d, + 0x00a60fcd, 0x0fe601a7, 0x00950fcf, 0x0fee01ae, + 0x00850fcf, 0x0ff701b5, 0x00750fce, 0x000001bd, + 0x00670fc9, 0x000a01c6, 0x00590fbe, 0x001601d3, + 0x004d0fa8, 0x002301e8, 0x00430f7a, 0x0034020f, + + 0x015c005e, 0x0fde0068, 0x015c0054, 0x0fdd0073, + 0x015b004b, 0x0fdc007e, 0x015a0042, 0x0fdb0089, + 0x01590039, 0x0fda0094, 0x01560030, 0x0fda00a0, + 0x01530028, 0x0fda00ab, 0x014f0020, 0x0fda00b7, + 0x014a0019, 0x0fdb00c2, 0x01450011, 0x0fdc00ce, + 0x013e000b, 0x0fde00d9, 0x01390004, 0x0fdf00e4, + 0x01310ffe, 0x0fe200ef, 0x01290ff9, 0x0fe400fa, + 0x01200ff4, 0x0fe80104, 0x01180fef, 0x0feb010e, + 0x010e0feb, 0x0fef0118, 0x01040fe8, 0x0ff40120, + 0x00fa0fe4, 0x0ff90129, 0x00ef0fe2, 0x0ffe0131, + 0x00e40fdf, 0x00040139, 0x00d90fde, 0x000b013e, + 0x00ce0fdc, 0x00110145, 0x00c20fdb, 0x0019014a, + 0x00b70fda, 0x0020014f, 0x00ab0fda, 0x00280153, + 0x00a00fda, 0x00300156, 0x00940fda, 0x00390159, + 0x00890fdb, 0x0042015a, 0x007e0fdc, 0x004b015b, + 0x00730fdd, 0x0054015c, 0x00680fde, 0x005e015c, + + 0x01300068, 0x0ff80070, 0x01300060, 0x0ff80078, + 0x012f0059, 0x0ff80080, 0x012d0052, 0x0ff80089, + 0x012b004b, 0x0ff90091, 0x01290044, 0x0ff9009a, + 0x0126003d, 0x0ffa00a3, 0x01220037, 0x0ffb00ac, + 0x011f0031, 0x0ffc00b4, 0x011a002b, 0x0ffe00bd, + 0x01150026, 0x000000c5, 0x010f0021, 0x000200ce, + 0x010a001c, 0x000400d6, 0x01030018, 0x000600df, + 0x00fd0014, 0x000900e6, 0x00f60010, 0x000c00ee, + 0x00ee000c, 0x001000f6, 0x00e60009, 0x001400fd, + 0x00df0006, 0x00180103, 0x00d60004, 0x001c010a, + 0x00ce0002, 0x0021010f, 0x00c50000, 0x00260115, + 0x00bd0ffe, 0x002b011a, 0x00b40ffc, 0x0031011f, + 0x00ac0ffb, 0x00370122, 0x00a30ffa, 0x003d0126, + 0x009a0ff9, 0x00440129, 0x00910ff9, 0x004b012b, + 0x00890ff8, 0x0052012d, 0x00800ff8, 0x0059012f, + 0x00780ff8, 0x00600130, 0x00700ff8, 0x00680130, + + 0x01050079, 0x0003007f, 0x01040073, 0x00030086, + 0x0103006d, 0x0004008c, 0x01030066, 0x00050092, + 0x01010060, 0x00060099, 0x0100005a, 0x0007009f, + 0x00fe0054, 0x000900a5, 0x00fa004f, 0x000b00ac, + 0x00f80049, 0x000d00b2, 0x00f50044, 0x000f00b8, + 0x00f2003f, 0x001200bd, 0x00ef0039, 0x001500c3, + 0x00ea0035, 0x001800c9, 0x00e60030, 0x001c00ce, + 0x00e3002b, 0x001f00d3, 0x00dd0027, 0x002300d9, + 0x00d90023, 0x002700dd, 0x00d3001f, 0x002b00e3, + 0x00ce001c, 0x003000e6, 0x00c90018, 0x003500ea, + 0x00c30015, 0x003900ef, 0x00bd0012, 0x003f00f2, + 0x00b8000f, 0x004400f5, 0x00b2000d, 0x004900f8, + 0x00ac000b, 0x004f00fa, 0x00a50009, 0x005400fe, + 0x009f0007, 0x005a0100, 0x00990006, 0x00600101, + 0x00920005, 0x00660103, 0x008c0004, 0x006d0103, + 0x00860003, 0x00730104, 0x007f0003, 0x00790105, + + 0x00cf0088, 0x001d008c, 0x00ce0084, 0x0020008e, + 0x00cd0080, 0x00210092, 0x00cd007b, 0x00240094, + 0x00ca0077, 0x00270098, 0x00c90073, 0x0029009b, + 0x00c8006f, 0x002c009d, 0x00c6006b, 0x002f00a0, + 0x00c50067, 0x003200a2, 0x00c30062, 0x003600a5, + 0x00c0005f, 0x003900a8, 0x00c0005b, 0x003b00aa, + 0x00be0057, 0x003e00ad, 0x00ba0054, 0x004200b0, + 0x00b90050, 0x004500b2, 0x00b7004c, 0x004900b4, + 0x00b40049, 0x004c00b7, 0x00b20045, 0x005000b9, + 0x00b00042, 0x005400ba, 0x00ad003e, 0x005700be, + 0x00aa003b, 0x005b00c0, 0x00a80039, 0x005f00c0, + 0x00a50036, 0x006200c3, 0x00a20032, 0x006700c5, + 0x00a0002f, 0x006b00c6, 0x009d002c, 0x006f00c8, + 0x009b0029, 0x007300c9, 0x00980027, 0x007700ca, + 0x00940024, 0x007b00cd, 0x00920021, 0x008000cd, + 0x008e0020, 0x008400ce, 0x008c001d, 0x008800cf, + + 0x008e0083, 0x006b0084, 0x008d0083, 0x006c0084, + 0x008d0082, 0x006d0084, 0x008d0081, 0x006d0085, + 0x008d0080, 0x006e0085, 0x008c007f, 0x006f0086, + 0x008b007f, 0x00700086, 0x008b007e, 0x00710086, + 0x008b007d, 0x00720086, 0x008a007d, 0x00730086, + 0x008a007c, 0x00730087, 0x008a007b, 0x00740087, + 0x0089007b, 0x00750087, 0x008a0079, 0x00750088, + 0x008a0078, 0x00760088, 0x008a0077, 0x00770088, + 0x00880077, 0x0077008a, 0x00880076, 0x0078008a, + 0x00880075, 0x0079008a, 0x00870075, 0x007b0089, + 0x00870074, 0x007b008a, 0x00870073, 0x007c008a, + 0x00860073, 0x007d008a, 0x00860072, 0x007d008b, + 0x00860071, 0x007e008b, 0x00860070, 0x007f008b, + 0x0086006f, 0x007f008c, 0x0085006e, 0x0080008d, + 0x0085006d, 0x0081008d, 0x0084006d, 0x0082008d, + 0x0084006c, 0x0083008d, 0x0084006b, 0x0083008e, + + 0x023c0fe2, 0x00000fe2, 0x023a0fdb, 0x00000feb, + 0x02360fd3, 0x0fff0ff8, 0x022e0fcf, 0x0ffc0007, + 0x02250fca, 0x0ffa0017, 0x021a0fc6, 0x0ff70029, + 0x020c0fc4, 0x0ff4003c, 0x01fd0fc1, 0x0ff10051, + 0x01eb0fc0, 0x0fed0068, 0x01d80fc0, 0x0fe9007f, + 0x01c30fc1, 0x0fe50097, 0x01ac0fc2, 0x0fe200b0, + 0x01960fc3, 0x0fdd00ca, 0x017e0fc5, 0x0fd900e4, + 0x01650fc8, 0x0fd500fe, 0x014b0fcb, 0x0fd20118, + 0x01330fcd, 0x0fcd0133, 0x01180fd2, 0x0fcb014b, + 0x00fe0fd5, 0x0fc80165, 0x00e40fd9, 0x0fc5017e, + 0x00ca0fdd, 0x0fc30196, 0x00b00fe2, 0x0fc201ac, + 0x00970fe5, 0x0fc101c3, 0x007f0fe9, 0x0fc001d8, + 0x00680fed, 0x0fc001eb, 0x00510ff1, 0x0fc101fd, + 0x003c0ff4, 0x0fc4020c, 0x00290ff7, 0x0fc6021a, + 0x00170ffa, 0x0fca0225, 0x00070ffc, 0x0fcf022e, + 0x0ff80fff, 0x0fd30236, 0x0feb0000, 0x0fdb023a, + + 0x02780fc4, 0x00000fc4, 0x02770fbc, 0x0fff0fce, + 0x02710fb5, 0x0ffe0fdc, 0x02690fb0, 0x0ffa0fed, + 0x025f0fab, 0x0ff70fff, 0x02500fa8, 0x0ff30015, + 0x02410fa6, 0x0fef002a, 0x022f0fa4, 0x0feb0042, + 0x021a0fa4, 0x0fe5005d, 0x02040fa5, 0x0fe10076, + 0x01eb0fa7, 0x0fdb0093, 0x01d20fa9, 0x0fd600af, + 0x01b80fab, 0x0fd000cd, 0x019d0faf, 0x0fca00ea, + 0x01810fb2, 0x0fc50108, 0x01620fb7, 0x0fc10126, + 0x01440fbb, 0x0fbb0146, 0x01260fc1, 0x0fb70162, + 0x01080fc5, 0x0fb20181, 0x00ea0fca, 0x0faf019d, + 0x00cd0fd0, 0x0fab01b8, 0x00af0fd6, 0x0fa901d2, + 0x00930fdb, 0x0fa701eb, 0x00760fe1, 0x0fa50204, + 0x005d0fe5, 0x0fa4021a, 0x00420feb, 0x0fa4022f, + 0x002a0fef, 0x0fa60241, 0x00150ff3, 0x0fa80250, + 0x0fff0ff7, 0x0fab025f, 0x0fed0ffa, 0x0fb00269, + 0x0fdc0ffe, 0x0fb50271, 0x0fce0fff, 0x0fbc0277, + + 0x02a00fb0, 0x00000fb0, 0x029e0fa8, 0x0fff0fbb, + 0x02980fa1, 0x0ffd0fca, 0x028f0f9c, 0x0ff90fdc, + 0x02840f97, 0x0ff50ff0, 0x02740f94, 0x0ff10007, + 0x02640f92, 0x0fec001e, 0x02500f91, 0x0fe70038, + 0x023a0f91, 0x0fe00055, 0x02220f92, 0x0fdb0071, + 0x02080f95, 0x0fd4008f, 0x01ec0f98, 0x0fce00ae, + 0x01cf0f9b, 0x0fc700cf, 0x01b10f9f, 0x0fc100ef, + 0x01920fa4, 0x0fbb010f, 0x01710faa, 0x0fb50130, + 0x01520fae, 0x0fae0152, 0x01300fb5, 0x0faa0171, + 0x010f0fbb, 0x0fa40192, 0x00ef0fc1, 0x0f9f01b1, + 0x00cf0fc7, 0x0f9b01cf, 0x00ae0fce, 0x0f9801ec, + 0x008f0fd4, 0x0f950208, 0x00710fdb, 0x0f920222, + 0x00550fe0, 0x0f91023a, 0x00380fe7, 0x0f910250, + 0x001e0fec, 0x0f920264, 0x00070ff1, 0x0f940274, + 0x0ff00ff5, 0x0f970284, 0x0fdc0ff9, 0x0f9c028f, + 0x0fca0ffd, 0x0fa10298, 0x0fbb0fff, 0x0fa8029e, + + 0x02c80f9c, 0x00000f9c, 0x02c70f94, 0x0ffe0fa7, + 0x02c10f8c, 0x0ffc0fb7, 0x02b70f87, 0x0ff70fcb, + 0x02aa0f83, 0x0ff30fe0, 0x02990f80, 0x0fee0ff9, + 0x02870f7f, 0x0fe80012, 0x02720f7e, 0x0fe2002e, + 0x025a0f7e, 0x0fdb004d, 0x02400f80, 0x0fd5006b, + 0x02230f84, 0x0fcd008c, 0x02050f87, 0x0fc700ad, + 0x01e60f8b, 0x0fbf00d0, 0x01c60f90, 0x0fb700f3, + 0x01a30f96, 0x0fb00117, 0x01800f9c, 0x0faa013a, + 0x015d0fa2, 0x0fa2015f, 0x013a0faa, 0x0f9c0180, + 0x01170fb0, 0x0f9601a3, 0x00f30fb7, 0x0f9001c6, + 0x00d00fbf, 0x0f8b01e6, 0x00ad0fc7, 0x0f870205, + 0x008c0fcd, 0x0f840223, 0x006b0fd5, 0x0f800240, + 0x004d0fdb, 0x0f7e025a, 0x002e0fe2, 0x0f7e0272, + 0x00120fe8, 0x0f7f0287, 0x0ff90fee, 0x0f800299, + 0x0fe00ff3, 0x0f8302aa, 0x0fcb0ff7, 0x0f8702b7, + 0x0fb70ffc, 0x0f8c02c1, 0x0fa70ffe, 0x0f9402c7, + + 0x02f00f88, 0x00000f88, 0x02ee0f80, 0x0ffe0f94, + 0x02e70f78, 0x0ffc0fa5, 0x02dd0f73, 0x0ff60fba, + 0x02ce0f6f, 0x0ff20fd1, 0x02be0f6c, 0x0feb0feb, + 0x02aa0f6b, 0x0fe50006, 0x02940f6a, 0x0fde0024, + 0x02790f6c, 0x0fd60045, 0x025e0f6e, 0x0fcf0065, + 0x023f0f72, 0x0fc60089, 0x021d0f77, 0x0fbf00ad, + 0x01fd0f7b, 0x0fb600d2, 0x01da0f81, 0x0fad00f8, + 0x01b50f87, 0x0fa6011e, 0x018f0f8f, 0x0f9e0144, + 0x016b0f95, 0x0f95016b, 0x01440f9e, 0x0f8f018f, + 0x011e0fa6, 0x0f8701b5, 0x00f80fad, 0x0f8101da, + 0x00d20fb6, 0x0f7b01fd, 0x00ad0fbf, 0x0f77021d, + 0x00890fc6, 0x0f72023f, 0x00650fcf, 0x0f6e025e, + 0x00450fd6, 0x0f6c0279, 0x00240fde, 0x0f6a0294, + 0x00060fe5, 0x0f6b02aa, 0x0feb0feb, 0x0f6c02be, + 0x0fd10ff2, 0x0f6f02ce, 0x0fba0ff6, 0x0f7302dd, + 0x0fa50ffc, 0x0f7802e7, 0x0f940ffe, 0x0f8002ee, + + 0x03180f74, 0x00000f74, 0x03160f6b, 0x0ffe0f81, + 0x030e0f64, 0x0ffb0f93, 0x03030f5f, 0x0ff50fa9, + 0x02f40f5b, 0x0ff00fc1, 0x02e20f58, 0x0fe90fdd, + 0x02cd0f57, 0x0fe20ffa, 0x02b60f57, 0x0fda0019, + 0x02990f59, 0x0fd1003d, 0x027b0f5c, 0x0fc90060, + 0x02590f61, 0x0fc00086, 0x02370f66, 0x0fb700ac, + 0x02130f6b, 0x0fae00d4, 0x01ee0f72, 0x0fa400fc, + 0x01c70f79, 0x0f9b0125, 0x019f0f81, 0x0f93014d, + 0x01760f89, 0x0f890178, 0x014d0f93, 0x0f81019f, + 0x01250f9b, 0x0f7901c7, 0x00fc0fa4, 0x0f7201ee, + 0x00d40fae, 0x0f6b0213, 0x00ac0fb7, 0x0f660237, + 0x00860fc0, 0x0f610259, 0x00600fc9, 0x0f5c027b, + 0x003d0fd1, 0x0f590299, 0x00190fda, 0x0f5702b6, + 0x0ffa0fe2, 0x0f5702cd, 0x0fdd0fe9, 0x0f5802e2, + 0x0fc10ff0, 0x0f5b02f4, 0x0fa90ff5, 0x0f5f0303, + 0x0f930ffb, 0x0f64030e, 0x0f810ffe, 0x0f6b0316, + + 0x03400f60, 0x00000f60, 0x033e0f57, 0x0ffe0f6d, + 0x03370f4f, 0x0ffa0f80, 0x032a0f4b, 0x0ff30f98, + 0x031a0f46, 0x0fee0fb2, 0x03070f44, 0x0fe60fcf, + 0x02f10f44, 0x0fde0fed, 0x02d70f44, 0x0fd6000f, + 0x02b80f46, 0x0fcc0036, 0x02990f4a, 0x0fc3005a, + 0x02750f4f, 0x0fb90083, 0x02500f55, 0x0fb000ab, + 0x022a0f5b, 0x0fa500d6, 0x02020f63, 0x0f9a0101, + 0x01d80f6b, 0x0f91012c, 0x01ae0f74, 0x0f870157, + 0x01840f7c, 0x0f7c0184, 0x01570f87, 0x0f7401ae, + 0x012c0f91, 0x0f6b01d8, 0x01010f9a, 0x0f630202, + 0x00d60fa5, 0x0f5b022a, 0x00ab0fb0, 0x0f550250, + 0x00830fb9, 0x0f4f0275, 0x005a0fc3, 0x0f4a0299, + 0x00360fcc, 0x0f4602b8, 0x000f0fd6, 0x0f4402d7, + 0x0fed0fde, 0x0f4402f1, 0x0fcf0fe6, 0x0f440307, + 0x0fb20fee, 0x0f46031a, 0x0f980ff3, 0x0f4b032a, + 0x0f800ffa, 0x0f4f0337, 0x0f6d0ffe, 0x0f57033e +}; +#endif #define MDP4_QSEED_TABLE0_OFF 0x8100 #define MDP4_QSEED_TABLE1_OFF 0x8200 @@ -1309,6 +1864,78 @@ void mdp4_vg_qseed_init(int vp_num) } +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_BOEOT_TFT_VIDEO_WSVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_TFT_VIDEO_WXGA_PT) +void mdp4_vg_qseed_init_VideoPlay(int vp_num) +{ + uint32 *off; + int i, voff; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + voff = MDP4_VIDEO_OFF * vp_num; + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE1_OFF); + for (i = 0; i < (sizeof(vg_qseed_table1) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table1[i]); + off++; + if (!((uint32)off & 0x3FF)) + wmb(); + } + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE2_OFF); + for (i = 0; i < (sizeof(vg_qseed_table2) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table2[i]); + off++; + if (!((uint32)off & 0x3FF)) + wmb(); + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + +} + +void mdp4_vg_qseed_init_DMB(int vp_num) +{ + uint32 *off; + int i, voff; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + voff = MDP4_VIDEO_OFF * vp_num; + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE1_OFF); + for (i = 0; i < (sizeof(vg_qseed_table1) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table1[i]); + off++; + if (!((uint32)off & 0x3FF)) + wmb(); + } + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE2_OFF); + for (i = 0; i < (sizeof(vg_qseed_table2_DMB) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table2_DMB[i]); + off++; + if (!((uint32)off & 0x3FF)) + wmb(); + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + +} +#endif + void mdp4_mixer_blend_init(mixer_num) { unsigned char *overlay_base; diff --git a/drivers/video/msm/mdp4_video_enhance.c b/drivers/video/msm/mdp4_video_enhance.c new file mode 100644 index 00000000000..fea021df2a6 --- /dev/null +++ b/drivers/video/msm/mdp4_video_enhance.c @@ -0,0 +1,880 @@ +/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdp4_video_enhance.h" +#include "mdp4_video_tuning.h" +#include "msm_fb.h" +#include "mdp.h" +#include "mdp4.h" + +#define MDP4_VIDEO_ENHANCE_TUNING +#define VIDEO_ENHANCE_DEBUG + +#ifdef VIDEO_ENHANCE_DEBUG +#define DPRINT(x...) printk(KERN_ERR "mdnie " x) +#else +#define DPRINT(x...) +#endif + +#define MAX_LUT_SIZE 256 + +unsigned int mDNIe_data[MAX_LUT_SIZE * 3]; + +int play_speed_1_5; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) || \ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) +boolean camera_mode; +#endif + +int mDNIe_data_sharpness; + +enum Lcd_mDNIe_UI { + mDNIe_UI_MODE, + mDNIe_VIDEO_MODE, + mDNIe_CAMERA_MODE, + mDNIe_NAVI, + mDNIe_GALLERY, + mDNIe_BYPASS, + mDNIe_DMB_MODE, +#ifdef BROWSER_COLOR_TONE_SET + mDNIe_BROWSER_TONE1 = 40, + mDNIe_BROWSER_TONE2, + mDNIe_BROWSER_TONE3, +#endif +}; + +enum Lcd_mDNIe_User_Set { + mDNIe_DYNAMIC, + mDNIe_STANDARD, + mDNIe_MOVIE, +}; + +enum Lcd_mDNIe_Negative { + mDNIe_NEGATIVE_OFF = 0, + mDNIe_NEGATIVE_ON, +}; + +static struct class *mdnie_class; +struct device *tune_mdnie_dev; + +enum Lcd_mDNIe_UI current_mDNIe_Mode = mDNIe_UI_MODE; +enum Lcd_mDNIe_Negative current_Negative_Mode = mDNIe_NEGATIVE_OFF; + +static bool g_mdine_enable ; + +#ifdef MDP4_VIDEO_ENHANCE_TUNING +#define MAX_FILE_NAME 128 +#define TUNING_FILE_PATH "/sdcard/tuning/" + +static int tuning_enable ; +static char tuning_filename[MAX_FILE_NAME]; + +static int load_tuning_data(char *filename); +static int parse_text(char *src, int len); +#endif + +#ifdef MDP4_VIDEO_ENHANCE_TUNING +static int parse_text(char *src, int len) +{ + int i, count, ret; + int index = 0; + int j = 0; + char *str_line[300]; + char *sstart; + char *c; + unsigned int data1, data2, data3; + int sharpvalue; + + c = src; + count = 0; + sstart = c; + sharpvalue = 0; + + for (i = 0; i < len; i++, c++) { + char a = *c; + if (a == '\r' || a == '\n') { + if (c > sstart) { + str_line[count] = sstart; + count++; + } + *c = '\0'; + sstart = c + 1; + } + } + + if (c > sstart) { + str_line[count] = sstart; + count++; + } + + ret = sscanf(str_line[0], "%d\n", &sharpvalue); + DPRINT("sharp ret %d, sharpvalue %d\n", ret, sharpvalue); + mDNIe_data_sharpness = sharpvalue; + + for (i = 1; i < count; i++) { + DPRINT("line:%d, [start]%s[end]\n", i, str_line[i]); + ret = + sscanf(str_line[i], "0x%x, 0x%x, 0x%x\n", &data1, &data2, + &data3); + DPRINT("Result => [0x%2x 0x%2x 0x%2x] %s\n", data1, data2, + data3, (ret == 3) ? "Ok" : "Not available"); + DPRINT("ret => %d\n", ret); + if (ret == 3) { + mDNIe_data[j++] = data1; + mDNIe_data[j++] = data2; + mDNIe_data[j++] = data3; + index++; + } + } + return index; +} + +static int load_tuning_data(char *filename) +{ + struct file *filp; + char *dp; + long l; + loff_t pos; + int ret, num; + mm_segment_t fs; + + DPRINT("[CMC623:INFO]:%s called loading file name : [%s]\n", __func__, + filename); + + fs = get_fs(); + set_fs(get_ds()); + + filp = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(filp)) { + printk(KERN_ERR "[CMC623:ERROR]:File open failed\n"); + return -1; + } + + l = filp->f_path.dentry->d_inode->i_size; + DPRINT("[CMC623:INFO]: Loading File Size : %ld(bytes)", l); + + dp = kmalloc(l + 10, GFP_KERNEL); + if (dp == NULL) { + DPRINT + ("[CMC623:ERROR]:Can't not alloc memory"\ + "for tuning file load\n"); + filp_close(filp, current->files); + return -1; + } + pos = 0; + memset(dp, 0, l); + DPRINT("[CMC623:INFO] : before vfs_read()\n"); + ret = vfs_read(filp, (char __user *)dp, l, &pos); + DPRINT("[CMC623:INFO] : after vfs_read()\n"); + + if (ret != l) { + DPRINT("[CMC623:ERROR] : vfs_read() filed ret : %d\n", ret); + kfree(dp); + filp_close(filp, current->files); + return -1; + } + + filp_close(filp, current->files); + + set_fs(fs); + num = parse_text(dp, l); + + if (!num) { + DPRINT("[CMC623:ERROR]:Nothing to parse\n"); + kfree(dp); + return -1; + } + + DPRINT("[CMC623:INFO] : Loading Tuning Value's Count : %d", num); + lut_tune(num, mDNIe_data); + sharpness_tune(mDNIe_data_sharpness); + + kfree(dp); + return num; +} + +static ssize_t tuning_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + ret = sprintf(buf, "Tunned File Name : %s\n", tuning_filename); + + return ret; +} + +static ssize_t tuning_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + char *pt; + memset(tuning_filename, 0, sizeof(tuning_filename)); + sprintf(tuning_filename, "%s%s", TUNING_FILE_PATH, buf); + + pt = tuning_filename; + while (*pt) { + if (*pt == '\r' || *pt == '\n') { + *pt = 0; + break; + } + pt++; + } + DPRINT("[CMC623:INFO]:%s:%s\n", __func__, tuning_filename); + + if (load_tuning_data(tuning_filename) <= 0) { + DPRINT("[CMC623:ERROR]:load_tunig_data() failed\n"); + return size; + } + tuning_enable = 1; + return size; +} + +static DEVICE_ATTR(tuning, 0664, tuning_show, tuning_store); + +#endif + +void free_cmap(struct fb_cmap *cmap) +{ + kfree(cmap->red); + kfree(cmap->green); + kfree(cmap->blue); +} + + +void lut_tune(int num, unsigned int *pLutTable) +{ + __u16 *r, *g, *b, i; + int j; + struct fb_info *info; + struct fb_cmap test_cmap; + struct fb_cmap *cmap; + struct msm_fb_data_type *mfd; + uint32_t out; + + /*for final assignment*/ + u16 r_1, g_1, b_1; + + info = registered_fb[0]; + + cmap = &test_cmap; + /*===================================== + * cmap allocation + =====================================*/ + cmap->red = 0; + cmap->green = 0; + cmap->blue = 0; + cmap->transp = 0; + cmap->start = 0; + cmap->len = num; /*MAX_LUT_SIZE;//LUT has 256 entries*/ + cmap->red = kmalloc(cmap->len * sizeof(__u16), GFP_KERNEL); + if (!cmap->red) { + printk(KERN_ERR "can't malloc cmap!"); + goto fail_rest; + } + + cmap->green = kmalloc(cmap->len * sizeof(__u16), GFP_KERNEL); + if (!cmap->green) { + printk(KERN_ERR "can't malloc cmap!"); + goto fail_rest; + } + + cmap->blue = kmalloc(cmap->len * sizeof(__u16), GFP_KERNEL); + if (!cmap->blue) { + printk(KERN_ERR "can't malloc cmap!"); + goto fail_rest; + } + r = cmap->red; + g = cmap->green; + b = cmap->blue; + + j = 0; + DPRINT("cmap->len %d\n", cmap->len); + /* Assigning the cmap */ + for (i = 0; i < cmap->len; i++) { + *r++ = pLutTable[j++]; + *g++ = pLutTable[j++]; + *b++ = pLutTable[j++]; + } + + /*instead of an ioctl */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + j = 0; + for (i = 0; i < cmap->len; i++) { + r_1 = pLutTable[j++]; + g_1 = pLutTable[j++]; + b_1 = pLutTable[j++]; + +#ifdef CONFIG_FB_MSM_MDP40 + MDP_OUTP(MDP_BASE + 0x94800 + +#else + MDP_OUTP(MDP_BASE + 0x93800 + +#endif + (0x400 * mdp_lut_i) + cmap->start * 4 + i * 4, + ((g_1 & 0xff) | + ((b_1 & 0xff) << 8) | ((r_1 & 0xff) << 16))); + } + + mfd = (struct msm_fb_data_type *) registered_fb[0]->par; + if (mfd->panel.type == MIPI_CMD_PANEL) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mutex_lock(&mdp_lut_push_sem); + mdp_lut_push = 1; + mdp_lut_push_i = mdp_lut_i; + mutex_unlock(&mdp_lut_push_sem); + } else { + /*mask off non LUT select bits*/ + out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7); + MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } + + mdp_lut_i = (mdp_lut_i + 1)%2; +fail_rest: + free_cmap(cmap); + /*close(fb);*/ +} + +void sharpness_tune(int num) +{ + char *vg_base; + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + vg_base = MDP_BASE + MDP4_VIDEO_BASE; + outpdw(vg_base + 0x8200, mdp4_ss_table_value((int8_t) num, 0)); + outpdw(vg_base + 0x8204, mdp4_ss_table_value((int8_t) num, 1)); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +int s3c_mdnie_start() +{ + g_mdine_enable = 1; + return 0; +} + +int s3c_mdnie_off() +{ + g_mdine_enable = 0; + return 0; +} + +void mDNIe_Set_Mode(enum Lcd_mDNIe_UI mode) +{ + unsigned int *pLut; + int sharpvalue = 0; + static int isSetDMBMode; + + DPRINT("[mdnie set] mDNIe_Set_Mode\n"); + if (!g_mdine_enable) { + printk(KERN_ERR + "[mDNIE WARNING] mDNIE engine is OFF. So you cannot set mDnie Mode correctly.\n"); + return; + } + + play_speed_1_5 = 0; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + video_mode = FALSE; + camera_mode = FALSE; +#endif + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + camera_mode = FALSE; +#endif + + switch (mode) { + case mDNIe_UI_MODE: + if (isSetDMBMode == 1) { + mdp4_vg_qseed_init_VideoPlay(0); + /*mdp4_vg_qseed_init_VideoPlay(1);*/ + isSetDMBMode = 0; + } + pLut = UI_LUT; + sharpvalue = SHARPNESS_BYPASS; + break; + + case mDNIe_VIDEO_MODE: + /*case mDNIe_VIDEO_WARM_MODE:*/ + /*case mDNIe_VIDEO_COLD_MODE:*/ + if (isSetDMBMode == 1) { + mdp4_vg_qseed_init_VideoPlay(0); + /*mdp4_vg_qseed_init_VideoPlay(1);*/ + isSetDMBMode = 0; + } + pLut = VIDEO_LUT; + sharpvalue = SHARPNESS_VIDEO; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + video_mode = TRUE; +#endif + break; + + case mDNIe_CAMERA_MODE: + pLut = BYPASS_LUT; + sharpvalue = SHARPNESS_BYPASS; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) || \ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + camera_mode = TRUE; +#endif + break; + + case mDNIe_NAVI: + pLut = BYPASS_LUT; + sharpvalue = SHARPNESS_BYPASS; + break; + + case mDNIe_GALLERY: + pLut = GALLERY_LUT; + sharpvalue = SHARPNESS_BYPASS; + break; + case mDNIe_BYPASS: + pLut = BYPASS_LUT; + sharpvalue = SHARPNESS_BYPASS; + break; + + case mDNIe_DMB_MODE: /*warm, clod not distinguish*/ + if (isSetDMBMode == 0) { + mdp4_vg_qseed_init_DMB(0); + /*mdp4_vg_qseed_init_DMB(1);*/ + isSetDMBMode = 1; + } + pLut = DMB_LUT; + sharpvalue = SHARPNESS_DMB; + break; + +#ifdef BROWSER_COLOR_TONE_SET + case mDNIe_BROWSER_TONE1: + pLut = BROWSER_TONE1_LUT; + sharpvalue = SHARPNESS_BYPASS; + break; + case mDNIe_BROWSER_TONE2: + pLut = BROWSER_TONE2_LUT; + sharpvalue = SHARPNESS_BYPASS; + break; + case mDNIe_BROWSER_TONE3: + pLut = BROWSER_TONE3_LUT; + sharpvalue = SHARPNESS_BYPASS; + break; +#endif + default: + pLut = BYPASS_LUT; + sharpvalue = SHARPNESS_BYPASS; + break; + } + + lut_tune(MAX_LUT_SIZE, pLut); + sharpness_tune(sharpvalue); + + current_mDNIe_Mode = mode; + +#ifdef CONFIG_FB_S3C_MDNIE_TUNINGMODE_FOR_BACKLIGHT + pre_val = -1; +#endif /* CONFIG_FB_S3C_MDNIE_TUNINGMODE_FOR_BACKLIGHT */ + DPRINT("[mDNIe] mDNIe_Set_Mode : Current_mDNIe_mode (%d)\n", + current_mDNIe_Mode); + DPRINT("[mDNIe] Sharpness value : (%d)\n", sharpvalue); +} + +void mDNIe_set_negative(enum Lcd_mDNIe_Negative negative) +{ + unsigned int *pLut; + int sharpvalue = 0; + + if (negative == 0) { + DPRINT("[mdnie set] mDNIe_Set_mDNIe_Mode = %d\n", + current_mDNIe_Mode); + + mDNIe_Set_Mode(current_mDNIe_Mode); + return; + } else { + DPRINT("[mdnie set] mDNIe_Set_Negative = %d\n", negative); + pLut = NEGATIVE_LUT; + sharpvalue = SHARPNESS_NEGATIVE; + lut_tune(MAX_LUT_SIZE, pLut); + sharpness_tune(sharpvalue); + } + DPRINT("[mdnie set] mDNIe_Set_Negative END\n"); +} + +int is_negativeMode_on(void) +{ + pr_info("is negative Mode On = %d\n", current_Negative_Mode); + if (current_Negative_Mode) + mDNIe_set_negative(current_Negative_Mode); + else + return 0; + return 1; +} +void is_play_speed_1_5(int enable) +{ + play_speed_1_5 = enable; +} + +static ssize_t scenario_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int mdnie_ui = 0; + + DPRINT("called %s\n", __func__); + + switch (current_mDNIe_Mode) { + case mDNIe_UI_MODE: + default: + mdnie_ui = 0; + break; + + case mDNIe_VIDEO_MODE: + mdnie_ui = 1; + break; + + case mDNIe_CAMERA_MODE: + mdnie_ui = 2; + break; + + case mDNIe_NAVI: + mdnie_ui = 3; + break; + + case mDNIe_GALLERY: + mdnie_ui = 4; + break; + + case mDNIe_BYPASS: + mdnie_ui = 5; + break; + +#if defined(CONFIG_TDMB) || defined(CONFIG_TDMB_MODULE) + case mDNIe_DMB_MODE: + mdnie_ui = mDNIe_DMB_MODE; + break; +#endif +#ifdef BROWSER_COLOR_TONE_SET + case mDNIe_BROWSER_TONE1: + mdnie_ui = mDNIe_BROWSER_TONE1; + break; + case mDNIe_BROWSER_TONE2: + mdnie_ui = mDNIe_BROWSER_TONE2; + break; + case mDNIe_BROWSER_TONE3: + mdnie_ui = mDNIe_BROWSER_TONE3; + break; +#endif + } + return sprintf(buf, "%u\n", mdnie_ui); +} + +static ssize_t scenario_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int value; + + sscanf(buf, "%d", &value); + + switch (value) { + case SIG_MDNIE_UI_MODE: + current_mDNIe_Mode = mDNIe_UI_MODE; + break; + + case SIG_MDNIE_VIDEO_MODE: + current_mDNIe_Mode = mDNIe_VIDEO_MODE; + break; + + case SIG_MDNIE_CAMERA_MODE: + current_mDNIe_Mode = mDNIe_CAMERA_MODE; + break; + + case SIG_MDNIE_NAVI: + current_mDNIe_Mode = mDNIe_NAVI; + break; + + case SIG_MDNIE_GALLERY: + current_mDNIe_Mode = mDNIe_GALLERY; + break; + + case SIG_MDNIE_BYPASS: + current_mDNIe_Mode = mDNIe_BYPASS; + break; + + case SIG_MDNIE_DMB_MODE: + current_mDNIe_Mode = mDNIe_DMB_MODE; + break; + + +#ifdef BROWSER_COLOR_TONE_SET + case SIG_MDNIE_BROWSER_TONE1: + current_mDNIe_Mode = mDNIe_BROWSER_TONE1; + break; + case SIG_MDNIE_BROWSER_TONE2: + current_mDNIe_Mode = mDNIe_BROWSER_TONE2; + break; + case SIG_MDNIE_BROWSER_TONE3: + current_mDNIe_Mode = mDNIe_BROWSER_TONE3; + break; +#endif + + default: + printk(KERN_ERR + "scenario_store value is wrong : value(%d)\n", + value); + break; + } + if (current_Negative_Mode) { + DPRINT("[mdnie set] already negative mode = %d\n", + current_Negative_Mode); + } else { + DPRINT("[mdnie set] in scenario_store, input value = %d\n", + value); + mDNIe_Set_Mode(current_mDNIe_Mode); + } + return size; +} +static DEVICE_ATTR(scenario, 0664, scenario_show, + scenario_store); + +static ssize_t mdnieset_user_select_file_cmd_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int mdnie_ui = 0; + DPRINT("called %s\n", __func__); + return sprintf(buf, "%u\n", mdnie_ui); + +} + +static ssize_t mdnieset_user_select_file_cmd_store(struct device *dev, + struct device_attribute + *attr, const char *buf, + size_t size) +{ + int value; + + sscanf(buf, "%d", &value); + DPRINT + ("[mdnie set]inmdnieset_user_select_file_cmd_store, input value = %d\n", + value); + + return size; +} + +static DEVICE_ATTR(mdnieset_user_select_file_cmd, 0664, + mdnieset_user_select_file_cmd_show, + mdnieset_user_select_file_cmd_store); + +static ssize_t mdnieset_init_file_cmd_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char temp[15]; + DPRINT("called %s\n", __func__); + sprintf(temp, "mdnieset_init_file_cmd_show\n"); + strcat(buf, temp); + return strlen(buf); +} + +static ssize_t mdnieset_init_file_cmd_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int value; + + sscanf(buf, "%d", &value); + DPRINT("mdnieset_init_file_cmd_store : value(%d)\n", value); + switch (value) { + case 0: + current_mDNIe_Mode = mDNIe_UI_MODE; + break; + + default: + printk(KERN_ERR + "mdnieset_init_file_cmd_store value is wrong : value(%d)\n", + value); + break; + } + mDNIe_Set_Mode(current_mDNIe_Mode); + + return size; +} + +static DEVICE_ATTR(mdnieset_init_file_cmd, 0664, mdnieset_init_file_cmd_show, + mdnieset_init_file_cmd_store); + +static ssize_t outdoor_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + DPRINT("called %s\n", __func__); + return sprintf(buf, "0\n"); +} + +static ssize_t outdoor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int value; + + sscanf(buf, "%d", &value); + + DPRINT + ("[mdnie set]inmdnieset_outdoor_file_cmd_store, input value = %d\n", + value); + + return size; +} + +static DEVICE_ATTR(outdoor, 0664, + outdoor_show, + outdoor_store); + +static ssize_t negative_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + DPRINT("called %s\n", __func__); + return sprintf(buf, "0\n"); +} + +static ssize_t negative_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int value; + + sscanf(buf, "%d", &value); + + DPRINT + ("[mdnie set]negative_store, input value = %d\n", + value); + pr_info("[negative] value = %d\n", value); + if (value == 0) + current_Negative_Mode = mDNIe_NEGATIVE_OFF; + else + current_Negative_Mode = mDNIe_NEGATIVE_ON; + mDNIe_set_negative(current_Negative_Mode); + return size; +} +static DEVICE_ATTR(negative, 0664, + negative_show, + negative_store); + +static ssize_t playspeed_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + DPRINT("called %s\n", __func__); + return sprintf(buf, "%d\n", play_speed_1_5); +} + +static ssize_t playspeed_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int value; + sscanf(buf, "%d", &value); + + DPRINT("[Play Speed Set]play speed value = %d\n", value); + + is_play_speed_1_5(value); + return size; +} +static DEVICE_ATTR(playspeed, 0664, + playspeed_show, + playspeed_store); + +void init_mdnie_class(void) +{ + mdnie_class = class_create(THIS_MODULE, "mdnie"); + if (IS_ERR(mdnie_class)) + pr_err("Failed to create class(mdnie)!\n"); + + tune_mdnie_dev = + device_create(mdnie_class, NULL, 0, NULL, + "mdnie"); + if (IS_ERR(tune_mdnie_dev)) + pr_err("Failed to create device(mdnie)!\n"); + + if (device_create_file + (tune_mdnie_dev, &dev_attr_scenario) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_scenario.attr.name); + + if (device_create_file + (tune_mdnie_dev, + &dev_attr_mdnieset_user_select_file_cmd) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_mdnieset_user_select_file_cmd.attr.name); + + if (device_create_file + (tune_mdnie_dev, &dev_attr_mdnieset_init_file_cmd) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_mdnieset_init_file_cmd.attr.name); + +/* mdnieset_outdoor_class = class_create(THIS_MODULE, "mdnieset_outdoor"); + if (IS_ERR(mdnieset_outdoor_class)) + pr_err("Failed to create class( + mdnieset_outdoor_class)!\n"); + + switch_mdnieset_outdoor_dev = + device_create(mdnieset_outdoor_class, NULL, 0, NULL, + "outdoor"); + if (IS_ERR(switch_mdnieset_outdoor_dev)) + pr_err + ("Failed to create device( + switch_mdnieset_outdoor_dev)!\n"); */ + + if (device_create_file + (tune_mdnie_dev, &dev_attr_outdoor) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_outdoor.attr.name); + + if (device_create_file + (tune_mdnie_dev, &dev_attr_negative) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_negative.attr.name); + + if (device_create_file + (tune_mdnie_dev, &dev_attr_playspeed) < 0) + pr_err("Failed to create device file(%s)!=n", + dev_attr_playspeed.attr.name); + +#ifdef MDP4_VIDEO_ENHANCE_TUNING + if (device_create_file(tune_mdnie_dev, &dev_attr_tuning) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_tuning.attr.name); + } +#endif + + s3c_mdnie_start(); + sharpness_tune(0); +} diff --git a/drivers/video/msm/mdp4_video_enhance.h b/drivers/video/msm/mdp4_video_enhance.h new file mode 100644 index 00000000000..f273aaf82b4 --- /dev/null +++ b/drivers/video/msm/mdp4_video_enhance.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * +*/ +#ifndef _MDP4_VIDEO_ENHANCE_H_ +#define _MDP4_VIDEO_ENHANCE_H_ + +#define BROWSER_COLOR_TONE_SET + +#define SIG_MDNIE_UI_MODE 0 +#define SIG_MDNIE_VIDEO_MODE 1 +/*#define SIG_MDNIE_VIDEO_WARM_MODE 2*/ +/*#define SIG_MDNIE_VIDEO_COLD_MODE 3*/ +#define SIG_MDNIE_CAMERA_MODE 4 +#define SIG_MDNIE_NAVI 5 +#define SIG_MDNIE_GALLERY 6 +#define SIG_MDNIE_VT 7 +#define SIG_MDNIE_BYPASS 8 + +#define SIG_MDNIE_DYNAMIC 0 +#define SIG_MDNIE_STANDARD 1 +#define SIG_MDNIE_MOVIE 2 + +/*#if defined(CONFIG_TDMB) || defined(CONFIG_TDMB_MODULE)*/ +#define SIG_MDNIE_DMB_MODE 20 +/*#define SIG_MDNIE_DMB_WARM_MODE 21 +#define SIG_MDNIE_DMB_COLD_MODE 22 +#endif*/ + +#ifdef CONFIG_TARGET_LOCALE_NTT +#define SIG_MDNIE_ISDBT_MODE 30 +#define SIG_MDNIE_ISDBT_WARM_MODE 31 +#define SIG_MDNIE_ISDBT_COLD_MODE 32 +#endif + +#ifdef BROWSER_COLOR_TONE_SET +#define SIG_MDNIE_BROWSER_TONE1 40 +#define SIG_MDNIE_BROWSER_TONE2 41 +#define SIG_MDNIE_BROWSER_TONE3 42 +#endif +void init_mdnie_class(void); +void lut_tune(int num, unsigned int *pLutTable); +void sharpness_tune(int num); +int is_negativeMode_on(void); +int s3c_mdnie_start(void); +int s3c_mdnie_off(void); + +#endif /*_MDP4_VIDEO_ENHANCE_H_*/ diff --git a/drivers/video/msm/mdp4_video_tuning.h b/drivers/video/msm/mdp4_video_tuning.h new file mode 100644 index 00000000000..0d1e88d44e6 --- /dev/null +++ b/drivers/video/msm/mdp4_video_tuning.h @@ -0,0 +1,2124 @@ +/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef _MDP4_VIDEO_TUNING_H_ +#define _MDP4_VIDEO_TUNING_H_ +#define SHARPNESS_DMB 52 +#define SHARPNESS_VIDEO -127 +#define SHARPNESS_BYPASS 0 +#define SHARPNESS_NEGATIVE 0 + +#define DMB_LUT DMB_TUNE +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) +#define GALLERY_LUT DARKGAMMA_LUT +#define VIDEO_LUT DARKGAMMA_LUT +#else +#define GALLERY_LUT BYPASS_LUT +#define VIDEO_LUT BYPASS_LUT +#endif +#define NEGATIVE_LUT NEGATIVE_TUNE +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL) +#define UI_LUT DARKGAMMA_LUT +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) +#define UI_LUT UI_LUT +#else +#define UI_LUT BYPASS_LUT +#endif + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT_PANEL) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) +static unsigned int DARKGAMMA_LUT[] = { +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x01, 0x01, 0x01, +0x03, 0x03, 0x03, +0x05, 0x05, 0x05, +0x07, 0x07, 0x07, +0x09, 0x09, 0x09, +0x0B, 0x0B, 0x0B, +0x0D, 0x0D, 0x0D, +0x0E, 0x0E, 0x0E, +0x0F, 0x0F, 0x0F, +0x10, 0x10, 0x10, +0x11, 0x11, 0x11, +0x12, 0x12, 0x12, +0x13, 0x13, 0x13, +0x14, 0x14, 0x14, +0x15, 0x15, 0x15, +0x16, 0x16, 0x16, +0x17, 0x17, 0x17, +0x18, 0x18, 0x18, +0x19, 0x19, 0x19, +0x1A, 0x1A, 0x1A, +0x1B, 0x1B, 0x1B, +0x1C, 0x1C, 0x1C, +0x1D, 0x1D, 0x1D, +0x1E, 0x1E, 0x1E, +0x1F, 0x1F, 0x1F, +0x20, 0x20, 0x20, +0x21, 0x21, 0x21, +0x22, 0x22, 0x22, +0x23, 0x23, 0x23, +0x24, 0x24, 0x24, +0x25, 0x25, 0x25, +0x26, 0x26, 0x26, +0x27, 0x27, 0x27, +0x28, 0x28, 0x28, +0x29, 0x29, 0x29, +0x2A, 0x2A, 0x2A, +0x2B, 0x2B, 0x2B, +0x2C, 0x2C, 0x2C, +0x2D, 0x2D, 0x2D, +0x2E, 0x2E, 0x2E, +0x2F, 0x2F, 0x2F, +0x30, 0x30, 0x30, +0x31, 0x31, 0x31, +0x32, 0x32, 0x32, +0x33, 0x33, 0x33, +0x34, 0x34, 0x34, +0x35, 0x35, 0x35, +0x36, 0x36, 0x36, +0x37, 0x37, 0x37, +0x38, 0x38, 0x38, +0x39, 0x39, 0x39, +0x3A, 0x3A, 0x3A, +0x3B, 0x3B, 0x3B, +0x3C, 0x3C, 0x3C, +0x3D, 0x3D, 0x3D, +0x3E, 0x3E, 0x3E, +0x3F, 0x3F, 0x3F, +0x40, 0x40, 0x40, +0x41, 0x41, 0x41, +0x42, 0x42, 0x42, +0x43, 0x43, 0x43, +0x44, 0x44, 0x44, +0x45, 0x45, 0x45, +0x46, 0x46, 0x46, +0x47, 0x47, 0x47, +0x48, 0x48, 0x48, +0x49, 0x49, 0x49, +0x4A, 0x4A, 0x4A, +0x4B, 0x4B, 0x4B, +0x4C, 0x4C, 0x4C, +0x4D, 0x4D, 0x4D, +0x4E, 0x4E, 0x4E, +0x4F, 0x4F, 0x4F, +0x50, 0x50, 0x50, +0x51, 0x51, 0x51, +0x52, 0x52, 0x52, +0x53, 0x53, 0x53, +0x54, 0x54, 0x54, +0x55, 0x55, 0x55, +0x56, 0x56, 0x56, +0x57, 0x57, 0x57, +0x58, 0x58, 0x58, +0x59, 0x59, 0x59, +0x5A, 0x5A, 0x5A, +0x5B, 0x5B, 0x5B, +0x5C, 0x5C, 0x5C, +0x5D, 0x5D, 0x5D, +0x5E, 0x5E, 0x5E, +0x5F, 0x5F, 0x5F, +0x60, 0x60, 0x60, +0x61, 0x61, 0x61, +0x62, 0x62, 0x62, +0x63, 0x63, 0x63, +0x64, 0x64, 0x64, +0x65, 0x65, 0x65, +0x66, 0x66, 0x66, +0x67, 0x67, 0x67, +0x68, 0x68, 0x68, +0x69, 0x69, 0x69, +0x6A, 0x6A, 0x6A, +0x6B, 0x6B, 0x6B, +0x6C, 0x6C, 0x6C, +0x6D, 0x6D, 0x6D, +0x6E, 0x6E, 0x6E, +0x6F, 0x6F, 0x6F, +0x70, 0x70, 0x70, +0x71, 0x71, 0x71, +0x72, 0x72, 0x72, +0x73, 0x73, 0x73, +0x74, 0x74, 0x74, +0x75, 0x75, 0x75, +0x76, 0x76, 0x76, +0x77, 0x77, 0x77, +0x78, 0x78, 0x78, +0x79, 0x79, 0x79, +0x7A, 0x7A, 0x7A, +0x7B, 0x7B, 0x7B, +0x7C, 0x7C, 0x7C, +0x7D, 0x7D, 0x7D, +0x7E, 0x7E, 0x7E, +0x7F, 0x7F, 0x7F, +0x80, 0x80, 0x80, +0x81, 0x81, 0x81, +0x82, 0x82, 0x82, +0x83, 0x83, 0x83, +0x84, 0x84, 0x84, +0x85, 0x85, 0x85, +0x86, 0x86, 0x86, +0x87, 0x87, 0x87, +0x88, 0x88, 0x88, +0x89, 0x89, 0x89, +0x8A, 0x8A, 0x8A, +0x8B, 0x8B, 0x8B, +0x8C, 0x8C, 0x8C, +0x8D, 0x8D, 0x8D, +0x8E, 0x8E, 0x8E, +0x8F, 0x8F, 0x8F, +0x90, 0x90, 0x90, +0x91, 0x91, 0x91, +0x92, 0x92, 0x92, +0x93, 0x93, 0x93, +0x94, 0x94, 0x94, +0x95, 0x95, 0x95, +0x96, 0x96, 0x96, +0x97, 0x97, 0x97, +0x98, 0x98, 0x98, +0x99, 0x99, 0x99, +0x9A, 0x9A, 0x9A, +0x9B, 0x9B, 0x9B, +0x9C, 0x9C, 0x9C, +0x9D, 0x9D, 0x9D, +0x9E, 0x9E, 0x9E, +0x9F, 0x9F, 0x9F, +0xA0, 0xA0, 0xA0, +0xA1, 0xA1, 0xA1, +0xA2, 0xA2, 0xA2, +0xA3, 0xA3, 0xA3, +0xA4, 0xA4, 0xA4, +0xA5, 0xA5, 0xA5, +0xA6, 0xA6, 0xA6, +0xA7, 0xA7, 0xA7, +0xA8, 0xA8, 0xA8, +0xA9, 0xA9, 0xA9, +0xAA, 0xAA, 0xAA, +0xAB, 0xAB, 0xAB, +0xAC, 0xAC, 0xAC, +0xAD, 0xAD, 0xAD, +0xAE, 0xAE, 0xAE, +0xAF, 0xAF, 0xAF, +0xB0, 0xB0, 0xB0, +0xB1, 0xB1, 0xB1, +0xB2, 0xB2, 0xB2, +0xB3, 0xB3, 0xB3, +0xB4, 0xB4, 0xB4, +0xB5, 0xB5, 0xB5, +0xB6, 0xB6, 0xB6, +0xB7, 0xB7, 0xB7, +0xB8, 0xB8, 0xB8, +0xB9, 0xB9, 0xB9, +0xBA, 0xBA, 0xBA, +0xBB, 0xBB, 0xBB, +0xBC, 0xBC, 0xBC, +0xBD, 0xBD, 0xBD, +0xBE, 0xBE, 0xBE, +0xBF, 0xBF, 0xBF, +0xC0, 0xC0, 0xC0, +0xC1, 0xC1, 0xC1, +0xC2, 0xC2, 0xC2, +0xC3, 0xC3, 0xC3, +0xC4, 0xC4, 0xC4, +0xC5, 0xC5, 0xC5, +0xC6, 0xC6, 0xC6, +0xC7, 0xC7, 0xC7, +0xC8, 0xC8, 0xC8, +0xC9, 0xC9, 0xC9, +0xCA, 0xCA, 0xCA, +0xCB, 0xCB, 0xCB, +0xCC, 0xCC, 0xCC, +0xCD, 0xCD, 0xCD, +0xCE, 0xCE, 0xCE, +0xCF, 0xCF, 0xCF, +0xD0, 0xD0, 0xD0, +0xD1, 0xD1, 0xD1, +0xD2, 0xD2, 0xD2, +0xD3, 0xD3, 0xD3, +0xD4, 0xD4, 0xD4, +0xD5, 0xD5, 0xD5, +0xD6, 0xD6, 0xD6, +0xD7, 0xD7, 0xD7, +0xD8, 0xD8, 0xD8, +0xD9, 0xD9, 0xD9, +0xDA, 0xDA, 0xDA, +0xDB, 0xDB, 0xDB, +0xDC, 0xDC, 0xDC, +0xDD, 0xDD, 0xDD, +0xDE, 0xDE, 0xDE, +0xDF, 0xDF, 0xDF, +0xE0, 0xE0, 0xE0, +0xE1, 0xE1, 0xE1, +0xE2, 0xE2, 0xE2, +0xE3, 0xE3, 0xE3, +0xE4, 0xE4, 0xE4, +0xE5, 0xE5, 0xE5, +0xE6, 0xE6, 0xE6, +0xE7, 0xE7, 0xE7, +0xE8, 0xE8, 0xE8, +0xE9, 0xE9, 0xE9, +0xEA, 0xEA, 0xEA, +0xEB, 0xEB, 0xEB, +0xEC, 0xEC, 0xEC, +0xED, 0xED, 0xED, +0xEE, 0xEE, 0xEE, +0xEF, 0xEF, 0xEF, +0xF0, 0xF0, 0xF0, +0xF1, 0xF1, 0xF1, +0xF2, 0xF2, 0xF2, +0xF3, 0xF3, 0xF3, +0xF4, 0xF4, 0xF4, +0xF5, 0xF5, 0xF5, +0xF6, 0xF6, 0xF6, +0xF7, 0xF7, 0xF7, +0xF8, 0xF8, 0xF8, +0xF9, 0xF9, 0xF9, +0xFA, 0xFA, 0xFA, +0xFB, 0xFB, 0xFB, +0xFC, 0xFC, 0xFC, +0xFD, 0xFD, 0xFD, +0xFE, 0xFE, 0xFE, +0xFF, 0xFF, 0xFF +}; +#endif + + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) +static unsigned int UI_LUT[] = { +0x00, 0x00, 0x00, +0x01, 0x01, 0x01, +0x02, 0x02, 0x02, +0x02, 0x02, 0x02, +0x03, 0x03, 0x03, +0x04, 0x04, 0x04, +0x05, 0x05, 0x05, +0x05, 0x05, 0x05, +0x06, 0x06, 0x06, +0x07, 0x07, 0x07, +0x08, 0x08, 0x08, +0x08, 0x08, 0x08, +0x09, 0x09, 0x09, +0x0A, 0x0A, 0x0A, +0x0B, 0x0B, 0x0B, +0x0B, 0x0B, 0x0B, +0x0C, 0x0C, 0x0C, +0x0D, 0x0D, 0x0D, +0x0E, 0x0E, 0x0E, +0x0E, 0x0E, 0x0E, +0x0F, 0x0F, 0x0F, +0x10, 0x10, 0x10, +0x11, 0x11, 0x11, +0x11, 0x11, 0x11, +0x12, 0x12, 0x12, +0x13, 0x13, 0x13, +0x14, 0x14, 0x14, +0x14, 0x14, 0x14, +0x15, 0x15, 0x15, +0x16, 0x16, 0x16, +0x17, 0x17, 0x17, +0x17, 0x17, 0x17, +0x18, 0x18, 0x18, +0x19, 0x19, 0x19, +0x1A, 0x1A, 0x1A, +0x1B, 0x1B, 0x1B, +0x1C, 0x1C, 0x1C, +0x1D, 0x1D, 0x1D, +0x1F, 0x1F, 0x1F, +0x20, 0x20, 0x20, +0x21, 0x21, 0x21, +0x22, 0x22, 0x22, +0x23, 0x23, 0x23, +0x24, 0x24, 0x24, +0x26, 0x26, 0x26, +0x27, 0x27, 0x27, +0x28, 0x28, 0x28, +0x29, 0x29, 0x29, +0x2A, 0x2A, 0x2A, +0x2B, 0x2B, 0x2B, +0x2C, 0x2C, 0x2C, +0x2D, 0x2D, 0x2D, +0x2F, 0x2F, 0x2F, +0x30, 0x30, 0x30, +0x31, 0x31, 0x31, +0x32, 0x32, 0x32, +0x33, 0x33, 0x33, +0x34, 0x34, 0x34, +0x35, 0x35, 0x35, +0x36, 0x36, 0x36, +0x38, 0x38, 0x38, +0x39, 0x39, 0x39, +0x3A, 0x3A, 0x3A, +0x3B, 0x3B, 0x3B, +0x3C, 0x3C, 0x3C, +0x3D, 0x3D, 0x3D, +0x3E, 0x3E, 0x3E, +0x3F, 0x3F, 0x3F, +0x41, 0x41, 0x41, +0x42, 0x42, 0x42, +0x43, 0x43, 0x43, +0x44, 0x44, 0x44, +0x45, 0x45, 0x45, +0x46, 0x46, 0x46, +0x47, 0x47, 0x47, +0x48, 0x48, 0x48, +0x4A, 0x4A, 0x4A, +0x4B, 0x4B, 0x4B, +0x4C, 0x4C, 0x4C, +0x4D, 0x4D, 0x4D, +0x4E, 0x4E, 0x4E, +0x4F, 0x4F, 0x4F, +0x50, 0x50, 0x50, +0x51, 0x51, 0x51, +0x53, 0x53, 0x53, +0x54, 0x54, 0x54, +0x55, 0x55, 0x55, +0x56, 0x56, 0x56, +0x57, 0x57, 0x57, +0x58, 0x58, 0x58, +0x59, 0x59, 0x59, +0x5A, 0x5A, 0x5A, +0x5C, 0x5C, 0x5C, +0x5D, 0x5D, 0x5D, +0x5E, 0x5E, 0x5E, +0x5F, 0x5F, 0x5F, +0x60, 0x60, 0x60, +0x61, 0x61, 0x61, +0x62, 0x62, 0x62, +0x63, 0x63, 0x63, +0x65, 0x65, 0x65, +0x66, 0x66, 0x66, +0x67, 0x67, 0x67, +0x68, 0x68, 0x68, +0x69, 0x69, 0x69, +0x6A, 0x6A, 0x6A, +0x6B, 0x6B, 0x6B, +0x6C, 0x6C, 0x6C, +0x6E, 0x6E, 0x6E, +0x6F, 0x6F, 0x6F, +0x70, 0x70, 0x70, +0x71, 0x71, 0x71, +0x72, 0x72, 0x72, +0x73, 0x73, 0x73, +0x74, 0x74, 0x74, +0x75, 0x75, 0x75, +0x77, 0x77, 0x77, +0x78, 0x78, 0x78, +0x79, 0x79, 0x79, +0x7A, 0x7A, 0x7A, +0x7B, 0x7B, 0x7B, +0x7C, 0x7C, 0x7C, +0x7D, 0x7D, 0x7D, +0x7E, 0x7E, 0x7E, +0x80, 0x80, 0x80, +0x81, 0x81, 0x81, +0x82, 0x82, 0x82, +0x83, 0x83, 0x83, +0x84, 0x84, 0x84, +0x85, 0x85, 0x85, +0x86, 0x86, 0x86, +0x87, 0x87, 0x87, +0x89, 0x89, 0x89, +0x8A, 0x8A, 0x8A, +0x8B, 0x8B, 0x8B, +0x8C, 0x8C, 0x8C, +0x8D, 0x8D, 0x8D, +0x8E, 0x8E, 0x8E, +0x8F, 0x8F, 0x8F, +0x90, 0x90, 0x90, +0x92, 0x92, 0x92, +0x93, 0x93, 0x93, +0x94, 0x94, 0x94, +0x95, 0x95, 0x95, +0x96, 0x96, 0x96, +0x97, 0x97, 0x97, +0x98, 0x98, 0x98, +0x99, 0x99, 0x99, +0x9B, 0x9B, 0x9B, +0x9C, 0x9C, 0x9C, +0x9D, 0x9D, 0x9D, +0x9E, 0x9E, 0x9E, +0x9F, 0x9F, 0x9F, +0xA0, 0xA0, 0xA0, +0xA1, 0xA1, 0xA1, +0xA2, 0xA2, 0xA2, +0xA4, 0xA4, 0xA4, +0xA5, 0xA5, 0xA5, +0xA6, 0xA6, 0xA6, +0xA7, 0xA7, 0xA7, +0xA8, 0xA8, 0xA8, +0xA9, 0xA9, 0xA9, +0xAA, 0xAA, 0xAA, +0xAB, 0xAB, 0xAB, +0xAD, 0xAD, 0xAD, +0xAE, 0xAE, 0xAE, +0xAF, 0xAF, 0xAF, +0xB0, 0xB0, 0xB0, +0xB1, 0xB1, 0xB1, +0xB2, 0xB2, 0xB2, +0xB3, 0xB3, 0xB3, +0xB4, 0xB4, 0xB4, +0xB6, 0xB6, 0xB6, +0xB7, 0xB7, 0xB7, +0xB8, 0xB8, 0xB8, +0xB9, 0xB9, 0xB9, +0xBA, 0xBA, 0xBA, +0xBB, 0xBB, 0xBB, +0xBC, 0xBC, 0xBC, +0xBD, 0xBD, 0xBD, +0xBF, 0xBF, 0xBF, +0xC0, 0xC0, 0xC0, +0xC1, 0xC1, 0xC1, +0xC2, 0xC2, 0xC2, +0xC3, 0xC3, 0xC3, +0xC4, 0xC4, 0xC4, +0xC5, 0xC5, 0xC5, +0xC6, 0xC6, 0xC6, +0xC8, 0xC8, 0xC8, +0xC9, 0xC9, 0xC9, +0xCA, 0xCA, 0xCA, +0xCB, 0xCB, 0xCB, +0xCC, 0xCC, 0xCC, +0xCD, 0xCD, 0xCD, +0xCE, 0xCE, 0xCE, +0xCF, 0xCF, 0xCF, +0xD0, 0xD0, 0xD0, +0xD1, 0xD1, 0xD1, +0xD2, 0xD2, 0xD2, +0xD3, 0xD3, 0xD3, +0xD4, 0xD4, 0xD4, +0xD5, 0xD5, 0xD5, +0xD6, 0xD6, 0xD6, +0xD7, 0xD7, 0xD7, +0xD8, 0xD8, 0xD8, +0xD9, 0xD9, 0xD9, +0xDA, 0xDA, 0xDA, +0xDB, 0xDB, 0xDB, +0xDC, 0xDC, 0xDC, +0xDD, 0xDD, 0xDD, +0xDE, 0xDE, 0xDE, +0xDF, 0xDF, 0xDF, +0xE0, 0xE0, 0xE0, +0xE0, 0xE0, 0xE0, +0xE1, 0xE1, 0xE1, +0xE2, 0xE2, 0xE2, +0xE3, 0xE3, 0xE3, +0xE4, 0xE4, 0xE4, +0xE5, 0xE5, 0xE5, +0xE6, 0xE6, 0xE6, +0xE7, 0xE7, 0xE7, +0xE7, 0xE7, 0xE7, +0xE8, 0xE8, 0xE8, +0xE9, 0xE9, 0xE9, +0xEA, 0xEA, 0xEA, +0xEB, 0xEB, 0xEB, +0xEC, 0xEC, 0xEC, +0xEC, 0xEC, 0xEC, +0xED, 0xED, 0xED, +0xEE, 0xEE, 0xEE, +0xEF, 0xEF, 0xEF, +0xEF, 0xEF, 0xEF, +0xF0, 0xF0, 0xF0, +0xF1, 0xF1, 0xF1, +0xF2, 0xF2, 0xF2, +0xF2, 0xF2, 0xF2, +0xF3, 0xF3, 0xF3, +0xF4, 0xF4, 0xF4, +0xF5, 0xF5, 0xF5, +0xF5, 0xF5, 0xF5, +0xF6, 0xF6, 0xF6, +0xF7, 0xF7, 0xF7, +0xF7, 0xF7, 0xF7, +0xF8, 0xF8, 0xF8, +0xF9, 0xF9, 0xF9, +0xF9, 0xF9, 0xF9, +0xFA, 0xFA, 0xFA, +0xFB, 0xFB, 0xFB, +0xFB, 0xFB, 0xFB, +0xFC, 0xFC, 0xFC, +0xFD, 0xFD, 0xFD, +0xFD, 0xFD, 0xFD, +0xFE, 0xFE, 0xFE, +0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, +}; +#endif + +static unsigned int BYPASS_LUT[] = { +0x00, 0x00, 0x00, +0x01, 0x01, 0x01, +0x02, 0x02, 0x02, +0x03, 0x03, 0x03, +0x04, 0x04, 0x04, +0x05, 0x05, 0x05, +0x06, 0x06, 0x06, +0x07, 0x07, 0x07, +0x08, 0x08, 0x08, +0x09, 0x09, 0x09, +0x0A, 0x0A, 0x0A, +0x0B, 0x0B, 0x0B, +0x0C, 0x0C, 0x0C, +0x0D, 0x0D, 0x0D, +0x0E, 0x0E, 0x0E, +0x0F, 0x0F, 0x0F, +0x10, 0x10, 0x10, +0x11, 0x11, 0x11, +0x12, 0x12, 0x12, +0x13, 0x13, 0x13, +0x14, 0x14, 0x14, +0x15, 0x15, 0x15, +0x16, 0x16, 0x16, +0x17, 0x17, 0x17, +0x18, 0x18, 0x18, +0x19, 0x19, 0x19, +0x1A, 0x1A, 0x1A, +0x1B, 0x1B, 0x1B, +0x1C, 0x1C, 0x1C, +0x1D, 0x1D, 0x1D, +0x1E, 0x1E, 0x1E, +0x1F, 0x1F, 0x1F, +0x20, 0x20, 0x20, +0x21, 0x21, 0x21, +0x22, 0x22, 0x22, +0x23, 0x23, 0x23, +0x24, 0x24, 0x24, +0x25, 0x25, 0x25, +0x26, 0x26, 0x26, +0x27, 0x27, 0x27, +0x28, 0x28, 0x28, +0x29, 0x29, 0x29, +0x2A, 0x2A, 0x2A, +0x2B, 0x2B, 0x2B, +0x2C, 0x2C, 0x2C, +0x2D, 0x2D, 0x2D, +0x2E, 0x2E, 0x2E, +0x2F, 0x2F, 0x2F, +0x30, 0x30, 0x30, +0x31, 0x31, 0x31, +0x32, 0x32, 0x32, +0x33, 0x33, 0x33, +0x34, 0x34, 0x34, +0x35, 0x35, 0x35, +0x36, 0x36, 0x36, +0x37, 0x37, 0x37, +0x38, 0x38, 0x38, +0x39, 0x39, 0x39, +0x3A, 0x3A, 0x3A, +0x3B, 0x3B, 0x3B, +0x3C, 0x3C, 0x3C, +0x3D, 0x3D, 0x3D, +0x3E, 0x3E, 0x3E, +0x3F, 0x3F, 0x3F, +0x40, 0x40, 0x40, +0x41, 0x41, 0x41, +0x42, 0x42, 0x42, +0x43, 0x43, 0x43, +0x44, 0x44, 0x44, +0x45, 0x45, 0x45, +0x46, 0x46, 0x46, +0x47, 0x47, 0x47, +0x48, 0x48, 0x48, +0x49, 0x49, 0x49, +0x4A, 0x4A, 0x4A, +0x4B, 0x4B, 0x4B, +0x4C, 0x4C, 0x4C, +0x4D, 0x4D, 0x4D, +0x4E, 0x4E, 0x4E, +0x4F, 0x4F, 0x4F, +0x50, 0x50, 0x50, +0x51, 0x51, 0x51, +0x52, 0x52, 0x52, +0x53, 0x53, 0x53, +0x54, 0x54, 0x54, +0x55, 0x55, 0x55, +0x56, 0x56, 0x56, +0x57, 0x57, 0x57, +0x58, 0x58, 0x58, +0x59, 0x59, 0x59, +0x5A, 0x5A, 0x5A, +0x5B, 0x5B, 0x5B, +0x5C, 0x5C, 0x5C, +0x5D, 0x5D, 0x5D, +0x5E, 0x5E, 0x5E, +0x5F, 0x5F, 0x5F, +0x60, 0x60, 0x60, +0x61, 0x61, 0x61, +0x62, 0x62, 0x62, +0x63, 0x63, 0x63, +0x64, 0x64, 0x64, +0x65, 0x65, 0x65, +0x66, 0x66, 0x66, +0x67, 0x67, 0x67, +0x68, 0x68, 0x68, +0x69, 0x69, 0x69, +0x6A, 0x6A, 0x6A, +0x6B, 0x6B, 0x6B, +0x6C, 0x6C, 0x6C, +0x6D, 0x6D, 0x6D, +0x6E, 0x6E, 0x6E, +0x6F, 0x6F, 0x6F, +0x70, 0x70, 0x70, +0x71, 0x71, 0x71, +0x72, 0x72, 0x72, +0x73, 0x73, 0x73, +0x74, 0x74, 0x74, +0x75, 0x75, 0x75, +0x76, 0x76, 0x76, +0x77, 0x77, 0x77, +0x78, 0x78, 0x78, +0x79, 0x79, 0x79, +0x7A, 0x7A, 0x7A, +0x7B, 0x7B, 0x7B, +0x7C, 0x7C, 0x7C, +0x7D, 0x7D, 0x7D, +0x7E, 0x7E, 0x7E, +0x7F, 0x7F, 0x7F, +0x80, 0x80, 0x80, +0x81, 0x81, 0x81, +0x82, 0x82, 0x82, +0x83, 0x83, 0x83, +0x84, 0x84, 0x84, +0x85, 0x85, 0x85, +0x86, 0x86, 0x86, +0x87, 0x87, 0x87, +0x88, 0x88, 0x88, +0x89, 0x89, 0x89, +0x8A, 0x8A, 0x8A, +0x8B, 0x8B, 0x8B, +0x8C, 0x8C, 0x8C, +0x8D, 0x8D, 0x8D, +0x8E, 0x8E, 0x8E, +0x8F, 0x8F, 0x8F, +0x90, 0x90, 0x90, +0x91, 0x91, 0x91, +0x92, 0x92, 0x92, +0x93, 0x93, 0x93, +0x94, 0x94, 0x94, +0x95, 0x95, 0x95, +0x96, 0x96, 0x96, +0x97, 0x97, 0x97, +0x98, 0x98, 0x98, +0x99, 0x99, 0x99, +0x9A, 0x9A, 0x9A, +0x9B, 0x9B, 0x9B, +0x9C, 0x9C, 0x9C, +0x9D, 0x9D, 0x9D, +0x9E, 0x9E, 0x9E, +0x9F, 0x9F, 0x9F, +0xA0, 0xA0, 0xA0, +0xA1, 0xA1, 0xA1, +0xA2, 0xA2, 0xA2, +0xA3, 0xA3, 0xA3, +0xA4, 0xA4, 0xA4, +0xA5, 0xA5, 0xA5, +0xA6, 0xA6, 0xA6, +0xA7, 0xA7, 0xA7, +0xA8, 0xA8, 0xA8, +0xA9, 0xA9, 0xA9, +0xAA, 0xAA, 0xAA, +0xAB, 0xAB, 0xAB, +0xAC, 0xAC, 0xAC, +0xAD, 0xAD, 0xAD, +0xAE, 0xAE, 0xAE, +0xAF, 0xAF, 0xAF, +0xB0, 0xB0, 0xB0, +0xB1, 0xB1, 0xB1, +0xB2, 0xB2, 0xB2, +0xB3, 0xB3, 0xB3, +0xB4, 0xB4, 0xB4, +0xB5, 0xB5, 0xB5, +0xB6, 0xB6, 0xB6, +0xB7, 0xB7, 0xB7, +0xB8, 0xB8, 0xB8, +0xB9, 0xB9, 0xB9, +0xBA, 0xBA, 0xBA, +0xBB, 0xBB, 0xBB, +0xBC, 0xBC, 0xBC, +0xBD, 0xBD, 0xBD, +0xBE, 0xBE, 0xBE, +0xBF, 0xBF, 0xBF, +0xC0, 0xC0, 0xC0, +0xC1, 0xC1, 0xC1, +0xC2, 0xC2, 0xC2, +0xC3, 0xC3, 0xC3, +0xC4, 0xC4, 0xC4, +0xC5, 0xC5, 0xC5, +0xC6, 0xC6, 0xC6, +0xC7, 0xC7, 0xC7, +0xC8, 0xC8, 0xC8, +0xC9, 0xC9, 0xC9, +0xCA, 0xCA, 0xCA, +0xCB, 0xCB, 0xCB, +0xCC, 0xCC, 0xCC, +0xCD, 0xCD, 0xCD, +0xCE, 0xCE, 0xCE, +0xCF, 0xCF, 0xCF, +0xD0, 0xD0, 0xD0, +0xD1, 0xD1, 0xD1, +0xD2, 0xD2, 0xD2, +0xD3, 0xD3, 0xD3, +0xD4, 0xD4, 0xD4, +0xD5, 0xD5, 0xD5, +0xD6, 0xD6, 0xD6, +0xD7, 0xD7, 0xD7, +0xD8, 0xD8, 0xD8, +0xD9, 0xD9, 0xD9, +0xDA, 0xDA, 0xDA, +0xDB, 0xDB, 0xDB, +0xDC, 0xDC, 0xDC, +0xDD, 0xDD, 0xDD, +0xDE, 0xDE, 0xDE, +0xDF, 0xDF, 0xDF, +0xE0, 0xE0, 0xE0, +0xE1, 0xE1, 0xE1, +0xE2, 0xE2, 0xE2, +0xE3, 0xE3, 0xE3, +0xE4, 0xE4, 0xE4, +0xE5, 0xE5, 0xE5, +0xE6, 0xE6, 0xE6, +0xE7, 0xE7, 0xE7, +0xE8, 0xE8, 0xE8, +0xE9, 0xE9, 0xE9, +0xEA, 0xEA, 0xEA, +0xEB, 0xEB, 0xEB, +0xEC, 0xEC, 0xEC, +0xED, 0xED, 0xED, +0xEE, 0xEE, 0xEE, +0xEF, 0xEF, 0xEF, +0xF0, 0xF0, 0xF0, +0xF1, 0xF1, 0xF1, +0xF2, 0xF2, 0xF2, +0xF3, 0xF3, 0xF3, +0xF4, 0xF4, 0xF4, +0xF5, 0xF5, 0xF5, +0xF6, 0xF6, 0xF6, +0xF7, 0xF7, 0xF7, +0xF8, 0xF8, 0xF8, +0xF9, 0xF9, 0xF9, +0xFA, 0xFA, 0xFA, +0xFB, 0xFB, 0xFB, +0xFC, 0xFC, 0xFC, +0xFD, 0xFD, 0xFD, +0xFE, 0xFE, 0xFE, +0xFF, 0xFF, 0xFF, +}; + +static unsigned int BROWSER_TONE1_LUT[] = { +0x00, 0x00, 0x00, +0x01, 0x01, 0x01, +0x01, 0x01, 0x01, +0x02, 0x02, 0x02, +0x03, 0x03, 0x03, +0x03, 0x04, 0x04, +0x04, 0x04, 0x04, +0x05, 0x05, 0x05, +0x05, 0x06, 0x06, +0x06, 0x06, 0x07, +0x07, 0x07, 0x07, +0x08, 0x08, 0x08, +0x08, 0x09, 0x09, +0x09, 0x09, 0x0A, +0x0A, 0x0A, 0x0A, +0x0A, 0x0B, 0x0B, +0x0B, 0x0B, 0x0C, +0x0C, 0x0C, 0x0D, +0x0C, 0x0D, 0x0D, +0x0D, 0x0E, 0x0E, +0x0E, 0x0E, 0x0F, +0x0E, 0x0F, 0x0F, +0x0F, 0x10, 0x10, +0x10, 0x11, 0x11, +0x10, 0x11, 0x12, +0x11, 0x12, 0x12, +0x12, 0x13, 0x13, +0x13, 0x13, 0x14, +0x13, 0x14, 0x15, +0x14, 0x15, 0x15, +0x15, 0x16, 0x16, +0x15, 0x16, 0x17, +0x16, 0x17, 0x18, +0x17, 0x18, 0x18, +0x17, 0x18, 0x19, +0x18, 0x19, 0x1A, +0x19, 0x1A, 0x1B, +0x19, 0x1B, 0x1B, +0x1A, 0x1B, 0x1C, +0x1B, 0x1C, 0x1D, +0x1B, 0x1D, 0x1D, +0x1C, 0x1D, 0x1E, +0x1D, 0x1E, 0x1F, +0x1E, 0x1F, 0x20, +0x1E, 0x20, 0x20, +0x1F, 0x20, 0x21, +0x20, 0x21, 0x22, +0x20, 0x22, 0x23, +0x21, 0x22, 0x23, +0x22, 0x23, 0x24, +0x22, 0x24, 0x25, +0x23, 0x25, 0x26, +0x24, 0x25, 0x26, +0x24, 0x26, 0x27, +0x25, 0x27, 0x28, +0x26, 0x27, 0x29, +0x26, 0x28, 0x29, +0x27, 0x29, 0x2A, +0x28, 0x2A, 0x2B, +0x28, 0x2A, 0x2B, +0x29, 0x2B, 0x2C, +0x2A, 0x2C, 0x2D, +0x2B, 0x2C, 0x2E, +0x2B, 0x2D, 0x2E, +0x2C, 0x2E, 0x2F, +0x2D, 0x2F, 0x30, +0x2D, 0x2F, 0x31, +0x2E, 0x30, 0x31, +0x2F, 0x31, 0x32, +0x2F, 0x32, 0x33, +0x30, 0x32, 0x34, +0x31, 0x33, 0x34, +0x31, 0x34, 0x35, +0x32, 0x34, 0x36, +0x33, 0x35, 0x37, +0x33, 0x36, 0x37, +0x34, 0x37, 0x38, +0x35, 0x37, 0x39, +0x36, 0x38, 0x3A, +0x36, 0x39, 0x3A, +0x37, 0x39, 0x3B, +0x38, 0x3A, 0x3C, +0x38, 0x3B, 0x3C, +0x39, 0x3C, 0x3D, +0x3A, 0x3C, 0x3E, +0x3A, 0x3D, 0x3F, +0x3B, 0x3E, 0x3F, +0x3C, 0x3E, 0x40, +0x3C, 0x3F, 0x41, +0x3D, 0x40, 0x42, +0x3E, 0x41, 0x42, +0x3E, 0x41, 0x43, +0x3F, 0x42, 0x44, +0x40, 0x43, 0x45, +0x41, 0x43, 0x45, +0x41, 0x44, 0x46, +0x42, 0x45, 0x47, +0x43, 0x46, 0x48, +0x43, 0x46, 0x48, +0x44, 0x47, 0x49, +0x45, 0x48, 0x4A, +0x45, 0x48, 0x4A, +0x46, 0x49, 0x4B, +0x47, 0x4A, 0x4C, +0x47, 0x4B, 0x4D, +0x48, 0x4B, 0x4D, +0x49, 0x4C, 0x4E, +0x49, 0x4D, 0x4F, +0x4A, 0x4E, 0x50, +0x4B, 0x4E, 0x50, +0x4B, 0x4F, 0x51, +0x4C, 0x50, 0x52, +0x4D, 0x50, 0x53, +0x4E, 0x51, 0x53, +0x4E, 0x52, 0x54, +0x4F, 0x53, 0x55, +0x50, 0x53, 0x56, +0x50, 0x54, 0x56, +0x51, 0x55, 0x57, +0x52, 0x55, 0x58, +0x52, 0x56, 0x58, +0x53, 0x57, 0x59, +0x54, 0x58, 0x5A, +0x54, 0x58, 0x5B, +0x55, 0x59, 0x5B, +0x56, 0x5A, 0x5C, +0x56, 0x5A, 0x5D, +0x57, 0x5B, 0x5E, +0x58, 0x5C, 0x5E, +0x59, 0x5D, 0x5F, +0x59, 0x5D, 0x60, +0x5A, 0x5E, 0x61, +0x5B, 0x5F, 0x61, +0x5B, 0x5F, 0x62, +0x5C, 0x60, 0x63, +0x5D, 0x61, 0x64, +0x5D, 0x62, 0x64, +0x5E, 0x62, 0x65, +0x5F, 0x63, 0x66, +0x5F, 0x64, 0x66, +0x60, 0x64, 0x67, +0x61, 0x65, 0x68, +0x61, 0x66, 0x69, +0x62, 0x67, 0x69, +0x63, 0x67, 0x6A, +0x64, 0x68, 0x6B, +0x64, 0x69, 0x6C, +0x65, 0x69, 0x6C, +0x66, 0x6A, 0x6D, +0x66, 0x6B, 0x6E, +0x67, 0x6C, 0x6F, +0x68, 0x6C, 0x6F, +0x68, 0x6D, 0x70, +0x69, 0x6E, 0x71, +0x6A, 0x6F, 0x72, +0x6A, 0x6F, 0x72, +0x6B, 0x70, 0x73, +0x6C, 0x71, 0x74, +0x6C, 0x71, 0x74, +0x6D, 0x72, 0x75, +0x6E, 0x73, 0x76, +0x6E, 0x74, 0x77, +0x6F, 0x74, 0x77, +0x70, 0x75, 0x78, +0x71, 0x76, 0x79, +0x71, 0x76, 0x7A, +0x72, 0x77, 0x7A, +0x73, 0x78, 0x7B, +0x73, 0x79, 0x7C, +0x74, 0x79, 0x7D, +0x75, 0x7A, 0x7D, +0x75, 0x7B, 0x7E, +0x76, 0x7B, 0x7F, +0x77, 0x7C, 0x80, +0x77, 0x7D, 0x80, +0x78, 0x7E, 0x81, +0x79, 0x7E, 0x82, +0x79, 0x7F, 0x82, +0x7A, 0x80, 0x83, +0x7B, 0x80, 0x84, +0x7C, 0x81, 0x85, +0x7C, 0x82, 0x85, +0x7D, 0x83, 0x86, +0x7E, 0x83, 0x87, +0x7E, 0x84, 0x88, +0x7F, 0x85, 0x88, +0x80, 0x85, 0x89, +0x80, 0x86, 0x8A, +0x81, 0x87, 0x8B, +0x82, 0x88, 0x8B, +0x82, 0x88, 0x8C, +0x83, 0x89, 0x8D, +0x84, 0x8A, 0x8E, +0x84, 0x8B, 0x8E, +0x85, 0x8B, 0x8F, +0x86, 0x8C, 0x90, +0x87, 0x8D, 0x91, +0x87, 0x8D, 0x91, +0x88, 0x8E, 0x92, +0x89, 0x8F, 0x93, +0x89, 0x90, 0x93, +0x8A, 0x90, 0x94, +0x8B, 0x91, 0x95, +0x8B, 0x92, 0x96, +0x8C, 0x92, 0x96, +0x8D, 0x93, 0x97, +0x8D, 0x94, 0x98, +0x8E, 0x95, 0x99, +0x8F, 0x95, 0x99, +0x8F, 0x96, 0x9A, +0x90, 0x97, 0x9B, +0x91, 0x97, 0x9C, +0x91, 0x98, 0x9C, +0x92, 0x99, 0x9D, +0x93, 0x9A, 0x9E, +0x94, 0x9A, 0x9F, +0x94, 0x9B, 0x9F, +0x95, 0x9C, 0xA0, +0x96, 0x9C, 0xA1, +0x96, 0x9D, 0xA1, +0x97, 0x9E, 0xA2, +0x98, 0x9F, 0xA3, +0x98, 0x9F, 0xA4, +0x99, 0xA0, 0xA4, +0x9A, 0xA1, 0xA5, +0x9A, 0xA1, 0xA6, +0x9B, 0xA2, 0xA7, +0x9C, 0xA3, 0xA7, +0x9C, 0xA4, 0xA8, +0x9D, 0xA4, 0xA9, +0x9E, 0xA5, 0xAA, +0x9F, 0xA6, 0xAA, +0x9F, 0xA6, 0xAB, +0xA0, 0xA7, 0xAC, +0xA1, 0xA8, 0xAD, +0xA1, 0xA9, 0xAD, +0xA2, 0xA9, 0xAE, +0xA3, 0xAA, 0xAF, +0xA3, 0xAB, 0xAF, +0xA4, 0xAC, 0xB0, +0xA5, 0xAC, 0xB1, +0xA5, 0xAD, 0xB2, +0xA6, 0xAE, 0xB2, +0xA7, 0xAE, 0xB3, +0xA7, 0xAF, 0xB4, +0xA8, 0xB0, 0xB5, +0xA9, 0xB1, 0xB5, +0xAA, 0xB1, 0xB6, +0xAA, 0xB2, 0xB7, +0xAB, 0xB3, 0xB8, +0xAC, 0xB3, 0xB8, +0xAC, 0xB4, 0xB9, +0xAD, 0xB5, 0xBA, +0xAE, 0xB6, 0xBB, +0xAE, 0xB6, 0xBB, +0xAF, 0xB7, 0xBC, +}; + +static unsigned int BROWSER_TONE2_LUT[] = { +0x00, 0x00, 0x00, +0x01, 0x01, 0x01, +0x01, 0x01, 0x01, +0x02, 0x02, 0x02, +0x03, 0x03, 0x03, +0x03, 0x03, 0x03, +0x04, 0x04, 0x04, +0x04, 0x05, 0x05, +0x05, 0x05, 0x06, +0x06, 0x06, 0x06, +0x06, 0x07, 0x07, +0x07, 0x07, 0x08, +0x08, 0x08, 0x08, +0x08, 0x09, 0x09, +0x09, 0x09, 0x0A, +0x09, 0x0A, 0x0A, +0x0A, 0x0B, 0x0B, +0x0B, 0x0B, 0x0C, +0x0B, 0x0C, 0x0D, +0x0C, 0x0D, 0x0D, +0x0D, 0x0D, 0x0E, +0x0D, 0x0E, 0x0F, +0x0E, 0x0E, 0x0F, +0x0E, 0x0F, 0x10, +0x0F, 0x10, 0x11, +0x10, 0x10, 0x11, +0x10, 0x11, 0x12, +0x11, 0x12, 0x13, +0x12, 0x12, 0x14, +0x12, 0x13, 0x14, +0x13, 0x14, 0x15, +0x13, 0x14, 0x16, +0x14, 0x15, 0x16, +0x15, 0x16, 0x17, +0x15, 0x16, 0x18, +0x16, 0x17, 0x18, +0x17, 0x18, 0x19, +0x17, 0x18, 0x1A, +0x18, 0x19, 0x1B, +0x18, 0x1A, 0x1B, +0x19, 0x1A, 0x1C, +0x1A, 0x1B, 0x1D, +0x1A, 0x1C, 0x1D, +0x1B, 0x1C, 0x1E, +0x1C, 0x1D, 0x1F, +0x1C, 0x1E, 0x1F, +0x1D, 0x1E, 0x20, +0x1D, 0x1F, 0x21, +0x1E, 0x20, 0x22, +0x1F, 0x20, 0x22, +0x1F, 0x21, 0x23, +0x20, 0x22, 0x24, +0x21, 0x22, 0x24, +0x21, 0x23, 0x25, +0x22, 0x24, 0x26, +0x23, 0x24, 0x26, +0x23, 0x25, 0x27, +0x24, 0x26, 0x28, +0x24, 0x26, 0x28, +0x25, 0x27, 0x29, +0x26, 0x28, 0x2A, +0x26, 0x28, 0x2B, +0x27, 0x29, 0x2B, +0x28, 0x2A, 0x2C, +0x28, 0x2A, 0x2D, +0x29, 0x2B, 0x2D, +0x29, 0x2B, 0x2E, +0x2A, 0x2C, 0x2F, +0x2B, 0x2D, 0x2F, +0x2B, 0x2D, 0x30, +0x2C, 0x2E, 0x31, +0x2D, 0x2F, 0x32, +0x2D, 0x2F, 0x32, +0x2E, 0x30, 0x33, +0x2E, 0x31, 0x34, +0x2F, 0x31, 0x34, +0x30, 0x32, 0x35, +0x30, 0x33, 0x36, +0x31, 0x33, 0x36, +0x32, 0x34, 0x37, +0x32, 0x35, 0x38, +0x33, 0x35, 0x39, +0x33, 0x36, 0x39, +0x34, 0x37, 0x3A, +0x35, 0x37, 0x3B, +0x35, 0x38, 0x3B, +0x36, 0x39, 0x3C, +0x37, 0x39, 0x3D, +0x37, 0x3A, 0x3D, +0x38, 0x3B, 0x3E, +0x38, 0x3B, 0x3F, +0x39, 0x3C, 0x40, +0x3A, 0x3D, 0x40, +0x3A, 0x3D, 0x41, +0x3B, 0x3E, 0x42, +0x3C, 0x3F, 0x42, +0x3C, 0x3F, 0x43, +0x3D, 0x40, 0x44, +0x3D, 0x41, 0x44, +0x3E, 0x41, 0x45, +0x3F, 0x42, 0x46, +0x3F, 0x43, 0x47, +0x40, 0x43, 0x47, +0x41, 0x44, 0x48, +0x41, 0x45, 0x49, +0x42, 0x45, 0x49, +0x43, 0x46, 0x4A, +0x43, 0x46, 0x4B, +0x44, 0x47, 0x4B, +0x44, 0x48, 0x4C, +0x45, 0x48, 0x4D, +0x46, 0x49, 0x4D, +0x46, 0x4A, 0x4E, +0x47, 0x4A, 0x4F, +0x48, 0x4B, 0x50, +0x48, 0x4C, 0x50, +0x49, 0x4C, 0x51, +0x49, 0x4D, 0x52, +0x4A, 0x4E, 0x52, +0x4B, 0x4E, 0x53, +0x4B, 0x4F, 0x54, +0x4C, 0x50, 0x54, +0x4D, 0x50, 0x55, +0x4D, 0x51, 0x56, +0x4E, 0x52, 0x57, +0x4E, 0x52, 0x57, +0x4F, 0x53, 0x58, +0x50, 0x54, 0x59, +0x50, 0x54, 0x59, +0x51, 0x55, 0x5A, +0x52, 0x56, 0x5B, +0x52, 0x56, 0x5B, +0x53, 0x57, 0x5C, +0x53, 0x58, 0x5D, +0x54, 0x58, 0x5E, +0x55, 0x59, 0x5E, +0x55, 0x5A, 0x5F, +0x56, 0x5A, 0x60, +0x57, 0x5B, 0x60, +0x57, 0x5C, 0x61, +0x58, 0x5C, 0x62, +0x58, 0x5D, 0x62, +0x59, 0x5E, 0x63, +0x5A, 0x5E, 0x64, +0x5A, 0x5F, 0x65, +0x5B, 0x60, 0x65, +0x5C, 0x60, 0x66, +0x5C, 0x61, 0x67, +0x5D, 0x62, 0x67, +0x5D, 0x62, 0x68, +0x5E, 0x63, 0x69, +0x5F, 0x63, 0x69, +0x5F, 0x64, 0x6A, +0x60, 0x65, 0x6B, +0x61, 0x65, 0x6B, +0x61, 0x66, 0x6C, +0x62, 0x67, 0x6D, +0x63, 0x67, 0x6E, +0x63, 0x68, 0x6E, +0x64, 0x69, 0x6F, +0x64, 0x69, 0x70, +0x65, 0x6A, 0x70, +0x66, 0x6B, 0x71, +0x66, 0x6B, 0x72, +0x67, 0x6C, 0x72, +0x68, 0x6D, 0x73, +0x68, 0x6D, 0x74, +0x69, 0x6E, 0x75, +0x69, 0x6F, 0x75, +0x6A, 0x6F, 0x76, +0x6B, 0x70, 0x77, +0x6B, 0x71, 0x77, +0x6C, 0x71, 0x78, +0x6D, 0x72, 0x79, +0x6D, 0x73, 0x79, +0x6E, 0x73, 0x7A, +0x6E, 0x74, 0x7B, +0x6F, 0x75, 0x7C, +0x70, 0x75, 0x7C, +0x70, 0x76, 0x7D, +0x71, 0x77, 0x7E, +0x72, 0x77, 0x7E, +0x72, 0x78, 0x7F, +0x73, 0x79, 0x80, +0x73, 0x79, 0x80, +0x74, 0x7A, 0x81, +0x75, 0x7B, 0x82, +0x75, 0x7B, 0x83, +0x76, 0x7C, 0x83, +0x77, 0x7D, 0x84, +0x77, 0x7D, 0x85, +0x78, 0x7E, 0x85, +0x78, 0x7E, 0x86, +0x79, 0x7F, 0x87, +0x7A, 0x80, 0x87, +0x7A, 0x80, 0x88, +0x7B, 0x81, 0x89, +0x7C, 0x82, 0x8A, +0x7C, 0x82, 0x8A, +0x7D, 0x83, 0x8B, +0x7D, 0x84, 0x8C, +0x7E, 0x84, 0x8C, +0x7F, 0x85, 0x8D, +0x7F, 0x86, 0x8E, +0x80, 0x86, 0x8E, +0x81, 0x87, 0x8F, +0x81, 0x88, 0x90, +0x82, 0x88, 0x90, +0x83, 0x89, 0x91, +0x83, 0x8A, 0x92, +0x84, 0x8A, 0x93, +0x84, 0x8B, 0x93, +0x85, 0x8C, 0x94, +0x86, 0x8C, 0x95, +0x86, 0x8D, 0x95, +0x87, 0x8E, 0x96, +0x88, 0x8E, 0x97, +0x88, 0x8F, 0x97, +0x89, 0x90, 0x98, +0x89, 0x90, 0x99, +0x8A, 0x91, 0x9A, +0x8B, 0x92, 0x9A, +0x8B, 0x92, 0x9B, +0x8C, 0x93, 0x9C, +0x8D, 0x94, 0x9C, +0x8D, 0x94, 0x9D, +0x8E, 0x95, 0x9E, +0x8E, 0x96, 0x9E, +0x8F, 0x96, 0x9F, +0x90, 0x97, 0xA0, +0x90, 0x98, 0xA1, +0x91, 0x98, 0xA1, +0x92, 0x99, 0xA2, +0x92, 0x9A, 0xA3, +0x93, 0x9A, 0xA3, +0x93, 0x9B, 0xA4, +0x94, 0x9B, 0xA5, +0x95, 0x9C, 0xA5, +0x95, 0x9D, 0xA6, +0x96, 0x9D, 0xA7, +0x97, 0x9E, 0xA8, +0x97, 0x9F, 0xA8, +0x98, 0x9F, 0xA9, +0x98, 0xA0, 0xAA, +0x99, 0xA1, 0xAA, +0x9A, 0xA1, 0xAB, +0x9A, 0xA2, 0xAC, +0x9B, 0xA3, 0xAC, +0x9C, 0xA3, 0xAD, +0x9C, 0xA4, 0xAE, +0x9D, 0xA5, 0xAF, +0x9D, 0xA5, 0xAF, +0x9E, 0xA6, 0xB0, +0x9F, 0xA7, 0xB1, +0x9F, 0xA7, 0xB1, +0xA0, 0xA8, 0xB2, +}; + +static unsigned int BROWSER_TONE3_LUT[] = { +0x00, 0x00, 0x00, +0x01, 0x01, 0x01, +0x01, 0x01, 0x01, +0x02, 0x02, 0x02, +0x02, 0x02, 0x03, +0x03, 0x03, 0x03, +0x03, 0x04, 0x04, +0x04, 0x04, 0x04, +0x05, 0x05, 0x05, +0x05, 0x05, 0x06, +0x06, 0x06, 0x06, +0x06, 0x07, 0x07, +0x07, 0x07, 0x08, +0x07, 0x08, 0x08, +0x08, 0x08, 0x09, +0x09, 0x09, 0x0A, +0x09, 0x0A, 0x0A, +0x0A, 0x0A, 0x0B, +0x0A, 0x0B, 0x0C, +0x0B, 0x0B, 0x0C, +0x0B, 0x0C, 0x0D, +0x0C, 0x0D, 0x0D, +0x0D, 0x0D, 0x0E, +0x0D, 0x0E, 0x0F, +0x0E, 0x0E, 0x0F, +0x0E, 0x0F, 0x10, +0x0F, 0x10, 0x11, +0x0F, 0x10, 0x11, +0x10, 0x11, 0x12, +0x10, 0x11, 0x13, +0x11, 0x12, 0x13, +0x12, 0x13, 0x14, +0x12, 0x13, 0x14, +0x13, 0x14, 0x15, +0x13, 0x14, 0x16, +0x14, 0x15, 0x16, +0x14, 0x16, 0x17, +0x15, 0x16, 0x18, +0x16, 0x17, 0x18, +0x16, 0x17, 0x19, +0x17, 0x18, 0x1A, +0x17, 0x19, 0x1A, +0x18, 0x19, 0x1B, +0x18, 0x1A, 0x1B, +0x19, 0x1A, 0x1C, +0x1A, 0x1B, 0x1D, +0x1A, 0x1C, 0x1D, +0x1B, 0x1C, 0x1E, +0x1B, 0x1D, 0x1F, +0x1C, 0x1D, 0x1F, +0x1C, 0x1E, 0x20, +0x1D, 0x1F, 0x21, +0x1E, 0x1F, 0x21, +0x1E, 0x20, 0x22, +0x1F, 0x20, 0x23, +0x1F, 0x21, 0x23, +0x20, 0x22, 0x24, +0x20, 0x22, 0x24, +0x21, 0x23, 0x25, +0x22, 0x23, 0x26, +0x22, 0x24, 0x26, +0x23, 0x25, 0x27, +0x23, 0x25, 0x28, +0x24, 0x26, 0x28, +0x24, 0x26, 0x29, +0x25, 0x27, 0x2A, +0x26, 0x28, 0x2A, +0x26, 0x28, 0x2B, +0x27, 0x29, 0x2B, +0x27, 0x29, 0x2C, +0x28, 0x2A, 0x2D, +0x28, 0x2B, 0x2D, +0x29, 0x2B, 0x2E, +0x2A, 0x2C, 0x2F, +0x2A, 0x2C, 0x2F, +0x2B, 0x2D, 0x30, +0x2B, 0x2E, 0x31, +0x2C, 0x2E, 0x31, +0x2C, 0x2F, 0x32, +0x2D, 0x2F, 0x32, +0x2D, 0x30, 0x33, +0x2E, 0x31, 0x34, +0x2F, 0x31, 0x34, +0x2F, 0x32, 0x35, +0x30, 0x32, 0x36, +0x30, 0x33, 0x36, +0x31, 0x34, 0x37, +0x31, 0x34, 0x38, +0x32, 0x35, 0x38, +0x33, 0x35, 0x39, +0x33, 0x36, 0x3A, +0x34, 0x37, 0x3A, +0x34, 0x37, 0x3B, +0x35, 0x38, 0x3B, +0x35, 0x38, 0x3C, +0x36, 0x39, 0x3D, +0x37, 0x3A, 0x3D, +0x37, 0x3A, 0x3E, +0x38, 0x3B, 0x3F, +0x38, 0x3B, 0x3F, +0x39, 0x3C, 0x40, +0x39, 0x3D, 0x41, +0x3A, 0x3D, 0x41, +0x3B, 0x3E, 0x42, +0x3B, 0x3E, 0x42, +0x3C, 0x3F, 0x43, +0x3C, 0x40, 0x44, +0x3D, 0x40, 0x44, +0x3D, 0x41, 0x45, +0x3E, 0x41, 0x46, +0x3F, 0x42, 0x46, +0x3F, 0x43, 0x47, +0x40, 0x43, 0x48, +0x40, 0x44, 0x48, +0x41, 0x44, 0x49, +0x41, 0x45, 0x4A, +0x42, 0x46, 0x4A, +0x43, 0x46, 0x4B, +0x43, 0x47, 0x4B, +0x44, 0x47, 0x4C, +0x44, 0x48, 0x4D, +0x45, 0x49, 0x4D, +0x45, 0x49, 0x4E, +0x46, 0x4A, 0x4F, +0x47, 0x4A, 0x4F, +0x47, 0x4B, 0x50, +0x48, 0x4C, 0x51, +0x48, 0x4C, 0x51, +0x49, 0x4D, 0x52, +0x49, 0x4D, 0x52, +0x4A, 0x4E, 0x53, +0x4A, 0x4F, 0x54, +0x4B, 0x4F, 0x54, +0x4C, 0x50, 0x55, +0x4C, 0x50, 0x56, +0x4D, 0x51, 0x56, +0x4D, 0x52, 0x57, +0x4E, 0x52, 0x58, +0x4E, 0x53, 0x58, +0x4F, 0x53, 0x59, +0x50, 0x54, 0x59, +0x50, 0x55, 0x5A, +0x51, 0x55, 0x5B, +0x51, 0x56, 0x5B, +0x52, 0x56, 0x5C, +0x52, 0x57, 0x5D, +0x53, 0x58, 0x5D, +0x54, 0x58, 0x5E, +0x54, 0x59, 0x5F, +0x55, 0x59, 0x5F, +0x55, 0x5A, 0x60, +0x56, 0x5B, 0x61, +0x56, 0x5B, 0x61, +0x57, 0x5C, 0x62, +0x58, 0x5C, 0x62, +0x58, 0x5D, 0x63, +0x59, 0x5E, 0x64, +0x59, 0x5E, 0x64, +0x5A, 0x5F, 0x65, +0x5A, 0x5F, 0x66, +0x5B, 0x60, 0x66, +0x5C, 0x61, 0x67, +0x5C, 0x61, 0x68, +0x5D, 0x62, 0x68, +0x5D, 0x62, 0x69, +0x5E, 0x63, 0x69, +0x5E, 0x64, 0x6A, +0x5F, 0x64, 0x6B, +0x60, 0x65, 0x6B, +0x60, 0x65, 0x6C, +0x61, 0x66, 0x6D, +0x61, 0x67, 0x6D, +0x62, 0x67, 0x6E, +0x62, 0x68, 0x6F, +0x63, 0x68, 0x6F, +0x64, 0x69, 0x70, +0x64, 0x6A, 0x71, +0x65, 0x6A, 0x71, +0x65, 0x6B, 0x72, +0x66, 0x6B, 0x72, +0x66, 0x6C, 0x73, +0x67, 0x6D, 0x74, +0x67, 0x6D, 0x74, +0x68, 0x6E, 0x75, +0x69, 0x6E, 0x76, +0x69, 0x6F, 0x76, +0x6A, 0x70, 0x77, +0x6A, 0x70, 0x78, +0x6B, 0x71, 0x78, +0x6B, 0x71, 0x79, +0x6C, 0x72, 0x79, +0x6D, 0x73, 0x7A, +0x6D, 0x73, 0x7B, +0x6E, 0x74, 0x7B, +0x6E, 0x74, 0x7C, +0x6F, 0x75, 0x7D, +0x6F, 0x76, 0x7D, +0x70, 0x76, 0x7E, +0x71, 0x77, 0x7F, +0x71, 0x77, 0x7F, +0x72, 0x78, 0x80, +0x72, 0x79, 0x80, +0x73, 0x79, 0x81, +0x73, 0x7A, 0x82, +0x74, 0x7A, 0x82, +0x75, 0x7B, 0x83, +0x75, 0x7C, 0x84, +0x76, 0x7C, 0x84, +0x76, 0x7D, 0x85, +0x77, 0x7D, 0x86, +0x77, 0x7E, 0x86, +0x78, 0x7F, 0x87, +0x79, 0x7F, 0x88, +0x79, 0x80, 0x88, +0x7A, 0x80, 0x89, +0x7A, 0x81, 0x89, +0x7B, 0x82, 0x8A, +0x7B, 0x82, 0x8B, +0x7C, 0x83, 0x8B, +0x7D, 0x83, 0x8C, +0x7D, 0x84, 0x8D, +0x7E, 0x85, 0x8D, +0x7E, 0x85, 0x8E, +0x7F, 0x86, 0x8F, +0x7F, 0x86, 0x8F, +0x80, 0x87, 0x90, +0x81, 0x88, 0x90, +0x81, 0x88, 0x91, +0x82, 0x89, 0x92, +0x82, 0x89, 0x92, +0x83, 0x8A, 0x93, +0x83, 0x8B, 0x94, +0x84, 0x8B, 0x94, +0x84, 0x8C, 0x95, +0x85, 0x8C, 0x96, +0x86, 0x8D, 0x96, +0x86, 0x8E, 0x97, +0x87, 0x8E, 0x97, +0x87, 0x8F, 0x98, +0x88, 0x8F, 0x99, +0x88, 0x90, 0x99, +0x89, 0x91, 0x9A, +0x8A, 0x91, 0x9B, +0x8A, 0x92, 0x9B, +0x8B, 0x92, 0x9C, +0x8B, 0x93, 0x9D, +0x8C, 0x94, 0x9D, +0x8C, 0x94, 0x9E, +0x8D, 0x95, 0x9F, +0x8E, 0x95, 0x9F, +0x8E, 0x96, 0xA0, +0x8F, 0x97, 0xA0, +0x8F, 0x97, 0xA1, +0x90, 0x98, 0xA2, +0x90, 0x98, 0xA2, +0x91, 0x99, 0xA3, +}; + +static unsigned int DMB_TUNE[] = { + 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0B, + 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, + 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, + 0x0E, 0x0E, 0x0E, + 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, + 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, + 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, + 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, + 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, + 0x18, 0x18, 0x18, + 0x19, 0x19, 0x19, + 0x1A, 0x1A, 0x1A, + 0x1B, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1C, + 0x1D, 0x1D, 0x1D, + 0x1F, 0x1F, 0x1F, + 0x20, 0x20, 0x20, + 0x21, 0x21, 0x21, + 0x22, 0x22, 0x22, + 0x23, 0x23, 0x23, + 0x24, 0x24, 0x24, + 0x26, 0x26, 0x26, + 0x27, 0x27, 0x27, + 0x28, 0x28, 0x28, + 0x29, 0x29, 0x29, + 0x2A, 0x2A, 0x2A, + 0x2B, 0x2B, 0x2B, + 0x2C, 0x2C, 0x2C, + 0x2D, 0x2D, 0x2D, + 0x2F, 0x2F, 0x2F, + 0x30, 0x30, 0x30, + 0x31, 0x31, 0x31, + 0x32, 0x32, 0x32, + 0x33, 0x33, 0x33, + 0x34, 0x34, 0x34, + 0x35, 0x35, 0x35, + 0x36, 0x36, 0x36, + 0x38, 0x38, 0x38, + 0x39, 0x39, 0x39, + 0x3A, 0x3A, 0x3A, + 0x3B, 0x3B, 0x3B, + 0x3C, 0x3C, 0x3C, + 0x3D, 0x3D, 0x3D, + 0x3E, 0x3E, 0x3E, + 0x3F, 0x3F, 0x3F, + 0x41, 0x41, 0x41, + 0x42, 0x42, 0x42, + 0x43, 0x43, 0x43, + 0x44, 0x44, 0x44, + 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, + 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, + 0x4A, 0x4A, 0x4A, + 0x4B, 0x4B, 0x4B, + 0x4C, 0x4C, 0x4C, + 0x4D, 0x4D, 0x4D, + 0x4E, 0x4E, 0x4E, + 0x4F, 0x4F, 0x4F, + 0x50, 0x50, 0x50, + 0x51, 0x51, 0x51, + 0x53, 0x53, 0x53, + 0x54, 0x54, 0x54, + 0x55, 0x55, 0x55, + 0x56, 0x56, 0x56, + 0x57, 0x57, 0x57, + 0x58, 0x58, 0x58, + 0x59, 0x59, 0x59, + 0x5A, 0x5A, 0x5A, + 0x5C, 0x5C, 0x5C, + 0x5D, 0x5D, 0x5D, + 0x5E, 0x5E, 0x5E, + 0x5F, 0x5F, 0x5F, + 0x60, 0x60, 0x60, + 0x61, 0x61, 0x61, + 0x62, 0x62, 0x62, + 0x63, 0x63, 0x63, + 0x65, 0x65, 0x65, + 0x66, 0x66, 0x66, + 0x67, 0x67, 0x67, + 0x68, 0x68, 0x68, + 0x69, 0x69, 0x69, + 0x6A, 0x6A, 0x6A, + 0x6B, 0x6B, 0x6B, + 0x6C, 0x6C, 0x6C, + 0x6E, 0x6E, 0x6E, + 0x6F, 0x6F, 0x6F, + 0x70, 0x70, 0x70, + 0x71, 0x71, 0x71, + 0x72, 0x72, 0x72, + 0x73, 0x73, 0x73, + 0x74, 0x74, 0x74, + 0x75, 0x75, 0x75, + 0x77, 0x77, 0x77, + 0x78, 0x78, 0x78, + 0x79, 0x79, 0x79, + 0x7A, 0x7A, 0x7A, + 0x7B, 0x7B, 0x7B, + 0x7C, 0x7C, 0x7C, + 0x7D, 0x7D, 0x7D, + 0x7E, 0x7E, 0x7E, + 0x80, 0x80, 0x80, + 0x81, 0x81, 0x81, + 0x82, 0x82, 0x82, + 0x83, 0x83, 0x83, + 0x84, 0x84, 0x84, + 0x85, 0x85, 0x85, + 0x86, 0x86, 0x86, + 0x87, 0x87, 0x87, + 0x89, 0x89, 0x89, + 0x8A, 0x8A, 0x8A, + 0x8B, 0x8B, 0x8B, + 0x8C, 0x8C, 0x8C, + 0x8D, 0x8D, 0x8D, + 0x8E, 0x8E, 0x8E, + 0x8F, 0x8F, 0x8F, + 0x90, 0x90, 0x90, + 0x92, 0x92, 0x92, + 0x93, 0x93, 0x93, + 0x94, 0x94, 0x94, + 0x95, 0x95, 0x95, + 0x96, 0x96, 0x96, + 0x97, 0x97, 0x97, + 0x98, 0x98, 0x98, + 0x99, 0x99, 0x99, + 0x9B, 0x9B, 0x9B, + 0x9C, 0x9C, 0x9C, + 0x9D, 0x9D, 0x9D, + 0x9E, 0x9E, 0x9E, + 0x9F, 0x9F, 0x9F, + 0xA0, 0xA0, 0xA0, + 0xA1, 0xA1, 0xA1, + 0xA2, 0xA2, 0xA2, + 0xA4, 0xA4, 0xA4, + 0xA5, 0xA5, 0xA5, + 0xA6, 0xA6, 0xA6, + 0xA7, 0xA7, 0xA7, + 0xA8, 0xA8, 0xA8, + 0xA9, 0xA9, 0xA9, + 0xAA, 0xAA, 0xAA, + 0xAB, 0xAB, 0xAB, + 0xAD, 0xAD, 0xAD, + 0xAE, 0xAE, 0xAE, + 0xAF, 0xAF, 0xAF, + 0xB0, 0xB0, 0xB0, + 0xB1, 0xB1, 0xB1, + 0xB2, 0xB2, 0xB2, + 0xB3, 0xB3, 0xB3, + 0xB4, 0xB4, 0xB4, + 0xB6, 0xB6, 0xB6, + 0xB7, 0xB7, 0xB7, + 0xB8, 0xB8, 0xB8, + 0xB9, 0xB9, 0xB9, + 0xBA, 0xBA, 0xBA, + 0xBB, 0xBB, 0xBB, + 0xBC, 0xBC, 0xBC, + 0xBD, 0xBD, 0xBD, + 0xBF, 0xBF, 0xBF, + 0xC0, 0xC0, 0xC0, + 0xC1, 0xC1, 0xC1, + 0xC2, 0xC2, 0xC2, + 0xC3, 0xC3, 0xC3, + 0xC4, 0xC4, 0xC4, + 0xC5, 0xC5, 0xC5, + 0xC6, 0xC6, 0xC6, + 0xC8, 0xC8, 0xC8, + 0xC9, 0xC9, 0xC9, + 0xCA, 0xCA, 0xCA, + 0xCB, 0xCB, 0xCB, + 0xCC, 0xCC, 0xCC, + 0xCD, 0xCD, 0xCD, + 0xCE, 0xCE, 0xCE, + 0xCF, 0xCF, 0xCF, + 0xD0, 0xD0, 0xD0, + 0xD1, 0xD1, 0xD1, + 0xD2, 0xD2, 0xD2, + 0xD3, 0xD3, 0xD3, + 0xD4, 0xD4, 0xD4, + 0xD5, 0xD5, 0xD5, + 0xD6, 0xD6, 0xD6, + 0xD7, 0xD7, 0xD7, + 0xD8, 0xD8, 0xD8, + 0xD9, 0xD9, 0xD9, + 0xDA, 0xDA, 0xDA, + 0xDB, 0xDB, 0xDB, + 0xDC, 0xDC, 0xDC, + 0xDD, 0xDD, 0xDD, + 0xDE, 0xDE, 0xDE, + 0xDF, 0xDF, 0xDF, + 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, + 0xE1, 0xE1, 0xE1, + 0xE2, 0xE2, 0xE2, + 0xE3, 0xE3, 0xE3, + 0xE4, 0xE4, 0xE4, + 0xE5, 0xE5, 0xE5, + 0xE6, 0xE6, 0xE6, + 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, + 0xE8, 0xE8, 0xE8, + 0xE9, 0xE9, 0xE9, + 0xEA, 0xEA, 0xEA, + 0xEB, 0xEB, 0xEB, + 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, + 0xED, 0xED, 0xED, + 0xEE, 0xEE, 0xEE, + 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, + 0xF0, 0xF0, 0xF0, + 0xF1, 0xF1, 0xF1, + 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, + 0xF3, 0xF3, 0xF3, + 0xF4, 0xF4, 0xF4, + 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, + 0xF6, 0xF6, 0xF6, + 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, + 0xF8, 0xF8, 0xF8, + 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, + 0xFA, 0xFA, 0xFA, + 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, + 0xFC, 0xFC, 0xFC, + 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, + 0xFE, 0xFE, 0xFE, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, +}; +static unsigned int NEGATIVE_TUNE[] = { + 0xFF, 0xFF, 0xFF, + 0xFE, 0xFE, 0xFE, + 0xFD, 0xFD, 0xFD, + 0xFC, 0xFC, 0xFC, + 0xFB, 0xFB, 0xFB, + 0xFA, 0xFA, 0xFA, + 0xF9, 0xF9, 0xF9, + 0xF8, 0xF8, 0xF8, + 0xF7, 0xF7, 0xF7, + 0xF6, 0xF6, 0xF6, + 0xF5, 0xF5, 0xF5, + 0xF4, 0xF4, 0xF4, + 0xF3, 0xF3, 0xF3, + 0xF2, 0xF2, 0xF2, + 0xF1, 0xF1, 0xF1, + 0xF0, 0xF0, 0xF0, + 0xEF, 0xEF, 0xEF, + 0xEE, 0xEE, 0xEE, + 0xED, 0xED, 0xED, + 0xEC, 0xEC, 0xEC, + 0xEB, 0xEB, 0xEB, + 0xEA, 0xEA, 0xEA, + 0xE9, 0xE9, 0xE9, + 0xE8, 0xE8, 0xE8, + 0xE7, 0xE7, 0xE7, + 0xE6, 0xE6, 0xE6, + 0xE5, 0xE5, 0xE5, + 0xE4, 0xE4, 0xE4, + 0xE3, 0xE3, 0xE3, + 0xE2, 0xE2, 0xE2, + 0xE1, 0xE1, 0xE1, + 0xE0, 0xE0, 0xE0, + 0xDF, 0xDF, 0xDF, + 0xDE, 0xDE, 0xDE, + 0xDD, 0xDD, 0xDD, + 0xDC, 0xDC, 0xDC, + 0xDB, 0xDB, 0xDB, + 0xDA, 0xDA, 0xDA, + 0xD9, 0xD9, 0xD9, + 0xD8, 0xD8, 0xD8, + 0xD7, 0xD7, 0xD7, + 0xD6, 0xD6, 0xD6, + 0xD5, 0xD5, 0xD5, + 0xD4, 0xD4, 0xD4, + 0xD3, 0xD3, 0xD3, + 0xD2, 0xD2, 0xD2, + 0xD1, 0xD1, 0xD1, + 0xD0, 0xD0, 0xD0, + 0xCF, 0xCF, 0xCF, + 0xCE, 0xCE, 0xCE, + 0xCD, 0xCD, 0xCD, + 0xCC, 0xCC, 0xCC, + 0xCB, 0xCB, 0xCB, + 0xCA, 0xCA, 0xCA, + 0xC9, 0xC9, 0xC9, + 0xC8, 0xC8, 0xC8, + 0xC7, 0xC7, 0xC7, + 0xC6, 0xC6, 0xC6, + 0xC5, 0xC5, 0xC5, + 0xC4, 0xC4, 0xC4, + 0xC3, 0xC3, 0xC3, + 0xC2, 0xC2, 0xC2, + 0xC1, 0xC1, 0xC1, + 0xC0, 0xC0, 0xC0, + 0xBF, 0xBF, 0xBF, + 0xBE, 0xBE, 0xBE, + 0xBD, 0xBD, 0xBD, + 0xBC, 0xBC, 0xBC, + 0xBB, 0xBB, 0xBB, + 0xBA, 0xBA, 0xBA, + 0xB9, 0xB9, 0xB9, + 0xB8, 0xB8, 0xB8, + 0xB7, 0xB7, 0xB7, + 0xB6, 0xB6, 0xB6, + 0xB5, 0xB5, 0xB5, + 0xB4, 0xB4, 0xB4, + 0xB3, 0xB3, 0xB3, + 0xB2, 0xB2, 0xB2, + 0xB1, 0xB1, 0xB1, + 0xB0, 0xB0, 0xB0, + 0xAF, 0xAF, 0xAF, + 0xAE, 0xAE, 0xAE, + 0xAD, 0xAD, 0xAD, + 0xAC, 0xAC, 0xAC, + 0xAB, 0xAB, 0xAB, + 0xAA, 0xAA, 0xAA, + 0xA9, 0xA9, 0xA9, + 0xA8, 0xA8, 0xA8, + 0xA7, 0xA7, 0xA7, + 0xA6, 0xA6, 0xA6, + 0xA5, 0xA5, 0xA5, + 0xA4, 0xA4, 0xA4, + 0xA3, 0xA3, 0xA3, + 0xA2, 0xA2, 0xA2, + 0xA1, 0xA1, 0xA1, + 0xA0, 0xA0, 0xA0, + 0x9F, 0x9F, 0x9F, + 0x9E, 0x9E, 0x9E, + 0x9D, 0x9D, 0x9D, + 0x9C, 0x9C, 0x9C, + 0x9B, 0x9B, 0x9B, + 0x9A, 0x9A, 0x9A, + 0x99, 0x99, 0x99, + 0x98, 0x98, 0x98, + 0x97, 0x97, 0x97, + 0x96, 0x96, 0x96, + 0x95, 0x95, 0x95, + 0x94, 0x94, 0x94, + 0x93, 0x93, 0x93, + 0x92, 0x92, 0x92, + 0x91, 0x91, 0x91, + 0x90, 0x90, 0x90, + 0x8F, 0x8F, 0x8F, + 0x8E, 0x8E, 0x8E, + 0x8D, 0x8D, 0x8D, + 0x8C, 0x8C, 0x8C, + 0x8B, 0x8B, 0x8B, + 0x8A, 0x8A, 0x8A, + 0x89, 0x89, 0x89, + 0x88, 0x88, 0x88, + 0x87, 0x87, 0x87, + 0x86, 0x86, 0x86, + 0x85, 0x85, 0x85, + 0x84, 0x84, 0x84, + 0x83, 0x83, 0x83, + 0x82, 0x82, 0x82, + 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, + 0x7F, 0x7F, 0x7F, + 0x7E, 0x7E, 0x7E, + 0x7D, 0x7D, 0x7D, + 0x7C, 0x7C, 0x7C, + 0x7B, 0x7B, 0x7B, + 0x7A, 0x7A, 0x7A, + 0x79, 0x79, 0x79, + 0x78, 0x78, 0x78, + 0x77, 0x77, 0x77, + 0x76, 0x76, 0x76, + 0x75, 0x75, 0x75, + 0x74, 0x74, 0x74, + 0x73, 0x73, 0x73, + 0x72, 0x72, 0x72, + 0x71, 0x71, 0x71, + 0x70, 0x70, 0x70, + 0x6F, 0x6F, 0x6F, + 0x6E, 0x6E, 0x6E, + 0x6D, 0x6D, 0x6D, + 0x6C, 0x6C, 0x6C, + 0x6B, 0x6B, 0x6B, + 0x6A, 0x6A, 0x6A, + 0x69, 0x69, 0x69, + 0x68, 0x68, 0x68, + 0x67, 0x67, 0x67, + 0x66, 0x66, 0x66, + 0x65, 0x65, 0x65, + 0x64, 0x64, 0x64, + 0x63, 0x63, 0x63, + 0x62, 0x62, 0x62, + 0x61, 0x61, 0x61, + 0x60, 0x60, 0x60, + 0x5F, 0x5F, 0x5F, + 0x5E, 0x5E, 0x5E, + 0x5D, 0x5D, 0x5D, + 0x5C, 0x5C, 0x5C, + 0x5B, 0x5B, 0x5B, + 0x5A, 0x5A, 0x5A, + 0x59, 0x59, 0x59, + 0x58, 0x58, 0x58, + 0x57, 0x57, 0x57, + 0x56, 0x56, 0x56, + 0x55, 0x55, 0x55, + 0x54, 0x54, 0x54, + 0x53, 0x53, 0x53, + 0x52, 0x52, 0x52, + 0x51, 0x51, 0x51, + 0x50, 0x50, 0x50, + 0x4F, 0x4F, 0x4F, + 0x4E, 0x4E, 0x4E, + 0x4D, 0x4D, 0x4D, + 0x4C, 0x4C, 0x4C, + 0x4B, 0x4B, 0x4B, + 0x4A, 0x4A, 0x4A, + 0x49, 0x49, 0x49, + 0x48, 0x48, 0x48, + 0x47, 0x47, 0x47, + 0x46, 0x46, 0x46, + 0x45, 0x45, 0x45, + 0x44, 0x44, 0x44, + 0x43, 0x43, 0x43, + 0x42, 0x42, 0x42, + 0x41, 0x41, 0x41, + 0x40, 0x40, 0x40, + 0x3F, 0x3F, 0x3F, + 0x3E, 0x3E, 0x3E, + 0x3D, 0x3D, 0x3D, + 0x3C, 0x3C, 0x3C, + 0x3B, 0x3B, 0x3B, + 0x3A, 0x3A, 0x3A, + 0x39, 0x39, 0x39, + 0x38, 0x38, 0x38, + 0x37, 0x37, 0x37, + 0x36, 0x36, 0x36, + 0x35, 0x35, 0x35, + 0x34, 0x34, 0x34, + 0x33, 0x33, 0x33, + 0x32, 0x32, 0x32, + 0x31, 0x31, 0x31, + 0x30, 0x30, 0x30, + 0x2F, 0x2F, 0x2F, + 0x2E, 0x2E, 0x2E, + 0x2D, 0x2D, 0x2D, + 0x2C, 0x2C, 0x2C, + 0x2B, 0x2B, 0x2B, + 0x2A, 0x2A, 0x2A, + 0x29, 0x29, 0x29, + 0x28, 0x28, 0x28, + 0x27, 0x27, 0x27, + 0x26, 0x26, 0x26, + 0x25, 0x25, 0x25, + 0x24, 0x24, 0x24, + 0x23, 0x23, 0x23, + 0x22, 0x22, 0x22, + 0x21, 0x21, 0x21, + 0x20, 0x20, 0x20, + 0x1F, 0x1F, 0x1F, + 0x1E, 0x1E, 0x1E, + 0x1D, 0x1D, 0x1D, + 0x1C, 0x1C, 0x1C, + 0x1B, 0x1B, 0x1B, + 0x1A, 0x1A, 0x1A, + 0x19, 0x19, 0x19, + 0x18, 0x18, 0x18, + 0x17, 0x17, 0x17, + 0x16, 0x16, 0x16, + 0x15, 0x15, 0x15, + 0x14, 0x14, 0x14, + 0x13, 0x13, 0x13, + 0x12, 0x12, 0x12, + 0x11, 0x11, 0x11, + 0x10, 0x10, 0x10, + 0x0F, 0x0F, 0x0F, + 0x0E, 0x0E, 0x0E, + 0x0D, 0x0D, 0x0D, + 0x0C, 0x0C, 0x0C, + 0x0B, 0x0B, 0x0B, + 0x0A, 0x0A, 0x0A, + 0x09, 0x09, 0x09, + 0x08, 0x08, 0x08, + 0x07, 0x07, 0x07, + 0x06, 0x06, 0x06, + 0x05, 0x05, 0x05, + 0x04, 0x04, 0x04, + 0x03, 0x03, 0x03, + 0x02, 0x02, 0x02, + 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, +}; +void init_mdnie_class(void); + +#endif /*_MDP4_VIDEO_TUNING_H_*/ diff --git a/drivers/video/msm/mdp4_wfd_writeback_util.h b/drivers/video/msm/mdp4_wfd_writeback_util.h index 582d198b2d5..69e48c49cd6 100644 --- a/drivers/video/msm/mdp4_wfd_writeback_util.h +++ b/drivers/video/msm/mdp4_wfd_writeback_util.h @@ -13,9 +13,9 @@ #ifndef _WRITEBACK_UTIL_H_ #define _WRITEBACK_UTIL_H_ - +#ifndef DEBUG #define DEBUG - +#endif #ifdef DEBUG #define WRITEBACK_MSG_INFO(fmt...) pr_info(fmt) #define WRITEBACK_MSG_WARN(fmt...) pr_warning(fmt) diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c index 1a29677f084..b743e9179c7 100644 --- a/drivers/video/msm/mhl/mhl_8334.c +++ b/drivers/video/msm/mhl/mhl_8334.c @@ -32,7 +32,7 @@ #include #include -#include "msm_fb.h" +#include "../msm_fb.h" #include "external_common.h" #include "hdmi_msm.h" #include "mhl_i2c_utils.h" diff --git a/drivers/video/msm/mhl_v2/Kconfig b/drivers/video/msm/mhl_v2/Kconfig new file mode 100644 index 00000000000..1275ed68410 --- /dev/null +++ b/drivers/video/msm/mhl_v2/Kconfig @@ -0,0 +1,21 @@ +# +# Copyright (c) 2011 Samsung Electronics Co., Ltd. +# http://www.samsung.com/ +# Aakash Manik +# aakash.manik@samsung.com + + +config VIDEO_MHL_V2 + bool "Samsung Mobile HD Link Interface" + depends on MSM_VIDC && ARCH_MSM + default n + +config MHL_D3_SUPPORT + bool "Support D3 mode in mhl" + default n + +config MHL_NEW_CBUS_MSC_CMD + bool "Read DCAP for distinguish TA and USB" + default n + ---help--- + This is a MHL v2 driver customized for Qualcomm MSM8960 based chipsets. diff --git a/drivers/video/msm/mhl_v2/Makefile b/drivers/video/msm/mhl_v2/Makefile new file mode 100644 index 00000000000..c9330f0b3ff --- /dev/null +++ b/drivers/video/msm/mhl_v2/Makefile @@ -0,0 +1,10 @@ +# drivers/video/msm/mhl_v2/Makefile +# +# Copyright (c) 2010 Samsung Electronics Co., Ltd. +# http://www.samsung.com/ +# Aakash Manik +# aakash.manik@samsung.com + + + +obj-$(CONFIG_VIDEO_MHL_V2) += sii9234.o \ diff --git a/drivers/video/msm/mhl_v2/sii9234.c b/drivers/video/msm/mhl_v2/sii9234.c new file mode 100644 index 00000000000..0c5357cc286 --- /dev/null +++ b/drivers/video/msm/mhl_v2/sii9234.c @@ -0,0 +1,3202 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * + * Authors: Adam Hampson + * Erik Gilling + * + * Additional contributions by : Shankar Bandal + * Dharam Kumar + * + * 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 "sii9234_driver.h" + +static int en_irq; +#undef __SII9234_MUTEX_DEBUG__ +#ifdef __SII9234_MUTEX_DEBUG__ + +static int g_mutex_cnt; +static int g_cbus_mutex_cnt; +#define sii9234_mutex_lock(prm) \ + do { \ + pr_debug("%s(%d)mutex++:%d\n", __func__, __LINE__,\ + ++g_mutex_cnt); mutex_lock(prm); pr_debug("%s(%d)mutex--:%d\n",\ + __func__, __LINE__, g_mutex_cnt);\ + } while (0) +#define sii9234_mutex_unlock(prm) \ + do { \ + pr_debug("%s(%d) mutex_unlock:%d\n", __func__, __LINE__,\ + --g_mutex_cnt); mutex_unlock(prm); \ + } while (0) +#define sii9234_cbus_mutex_lock(prm) \ + do { \ + pr_debug("%s(%d) cbus mutex++:%d\n", __func__, __LINE__,\ + ++g_cbus_mutex_cnt); mutex_lock(prm);\ + pr_debug("%s(%d) cbus mutex--:%d\n",\ + __func__, __LINE__, g_cbus_mutex_cnt);\ + } while (0) +#define sii9234_cbus_mutex_unlock(prm) \ + do { \ + pr_debug("%s(%d) cbus mutex_unlock:%d\n",\ + __func__, __LINE__, --g_cbus_mutex_cnt); mutex_unlock(prm);\ + } while (0) +#else +#define sii9234_mutex_lock(prm) mutex_lock(prm); +#define sii9234_mutex_unlock(prm) mutex_unlock(prm); +#define sii9234_cbus_mutex_lock(prm) mutex_lock(prm); +#define sii9234_cbus_mutex_unlock(prm) mutex_unlock(prm); +#endif +#define sii9234_enable_irq() \ + do { \ + if (atomic_read(&sii9234->is_irq_enabled) == false) { \ + atomic_set(&sii9234->is_irq_enabled, true); \ + enable_irq(sii9234->pdata->mhl_tx_client->irq); \ + pr_debug("%s():enable_irq(%d)\n", __func__, ++en_irq);\ + } else { \ + pr_debug("%s():irq is already enabled(%d)\n", __func__,\ + en_irq); \ + } \ + } while (0) + +#define sii9234_disable_irq() \ + do { \ + if (atomic_read(&sii9234->is_irq_enabled) == true) { \ + atomic_set(&sii9234->is_irq_enabled, false); \ + disable_irq_nosync(sii9234->pdata->mhl_tx_client->irq);\ + pr_debug("%s():disable_irq(%d)\n", __func__, --en_irq);\ + } else { \ + pr_debug("%s():irq is already disable(%d)\n", __func__,\ + en_irq); \ + } \ + } while (0) + +#ifdef CONFIG_MHL_SWING_LEVEL +#include +#endif +#undef __CONFIG_RSEN_LOST_PATCH__ +#undef __CONFIG_USE_TIMER__ +static u8 sii9234_tmds_control(struct sii9234_data *sii9234, bool enable); +static bool cbus_command_request(struct sii9234_data *sii9234, + enum cbus_command command, + u8 offset, u8 data); +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD +static void cbus_command_response(struct sii9234_data *sii9234); +#endif +static irqreturn_t sii9234_irq_thread(int irq, void *data); + +static struct cbus_packet cbus_pkt_buf[CBUS_PKT_BUF_COUNT]; + +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD +LIST_HEAD(g_msc_packet_list); +static int g_list_cnt; +static struct workqueue_struct *sii9234_msc_wq; +#endif + +#ifdef CONFIG_MHL_D3_SUPPORT +static void goto_d3(struct work_struct *work); +#endif +#ifdef __CONFIG_USE_TIMER__ +static int cbus_command_abort_state; +#endif +static int sii9234_callback_sched; +static int d3_mode_rgnd_state; +#ifdef CONFIG_MHL_SWING_LEVEL + +static ssize_t sii9234_swing_test_show(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + return sprintf(buf, "mhl_show_value : 0x%x\n", + sii9234->pdata->swing_level); + +} +static ssize_t sii9234_swing_test_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + + char temp[4] = { 0, }; + const char *p = buf; + int data, clk; + unsigned int value; + + while (*p != '\0') { + if (!isspace(*p)) + strncat(temp, p, 1); + p++; + } + + if (strlen(temp) != 2) + return -EINVAL; + + kstrtoul(temp, 10, &value); + data = value / 10; + clk = value % 10; + sii9234->pdata->swing_level = 0xc0; + sii9234->pdata->swing_level = sii9234->pdata->swing_level + | (data << 3) | clk; + sprintf(buf, "mhl_store_value : 0x%x\n", sii9234->pdata->swing_level); + return size; +} + +static CLASS_ATTR(swing, 0664, + sii9234_swing_test_show, sii9234_swing_test_store); +#endif +u8 mhl_onoff_ex(bool onoff) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + + if (!sii9234 || !sii9234->pdata) { + pr_info("mhl_onoff_ex: getting resource is failed\n"); + return 2; + } + if (sii9234->pdata->power_state == onoff) { + pr_info("mhl_onoff_ex: mhl already %s\n", onoff ? "on" : "off"); + return 2; + } + + sii9234->pdata->power_state = onoff; /*save power state*/ + + if (sii9234->pdata->mhl_sel) + sii9234->pdata->mhl_sel(onoff); + + if (onoff) { + if (sii9234->pdata->hw_onoff) + sii9234->pdata->hw_onoff(1); + + if (sii9234->pdata->hw_reset) + sii9234->pdata->hw_reset(); +#ifdef CONFIG_MHL_D3_SUPPORT + detached_status = 0; + d3_mode_rgnd_state = 0; + goto_d3(NULL); + return 2; +#else + sii9234_detection_callback(NULL); +#endif + } else { + sii9234_cancel_callback(); + + if (sii9234->pdata->hw_onoff) + sii9234->pdata->hw_onoff(0); + } + + return sii9234->rgnd; +} +EXPORT_SYMBOL(mhl_onoff_ex); + +static int mhl_tx_write_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 value) +{ + int ret; + ret = i2c_smbus_write_byte_data(sii9234->pdata->mhl_tx_client, offset, + value); + if (ret < 0) + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, value); + return ret; +} + +static int mhl_tx_read_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 *value) +{ + int ret; + + if (!value) + return -EINVAL; + + ret = i2c_smbus_write_byte(sii9234->pdata->mhl_tx_client, offset); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + + ret = i2c_smbus_read_byte(sii9234->pdata->mhl_tx_client); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + + *value = ret & 0x000000FF; + + return 0; +} + +static int mhl_tx_set_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 mask) +{ + int ret; + u8 value; + + ret = mhl_tx_read_reg(sii9234, offset, &value); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, mask); + return ret; + } + + value |= mask; + + return mhl_tx_write_reg(sii9234, offset, value); +} + +static int mhl_tx_clear_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 mask) +{ + int ret; + u8 value; + + ret = mhl_tx_read_reg(sii9234, offset, &value); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, mask); + return ret; + } + + value &= ~mask; + + ret = mhl_tx_write_reg(sii9234, offset, value); + if (ret < 0) + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, mask); + return ret; +} + +static int tpi_write_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 value) +{ + int ret = 0; + ret = i2c_smbus_write_byte_data(sii9234->pdata->tpi_client, offset, + value); + if (ret < 0) + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, value); + return ret; +} + +static int tpi_read_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 *value) +{ + int ret; + + if (!value) + return -EINVAL; + + ret = i2c_smbus_write_byte(sii9234->pdata->tpi_client, offset); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + + ret = i2c_smbus_read_byte(sii9234->pdata->tpi_client); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + *value = ret & 0x000000FF; + + return 0; +} + +static int hdmi_rx_write_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 value) +{ + int ret; + ret = i2c_smbus_write_byte_data(sii9234->pdata->hdmi_rx_client, offset, + value); + if (ret < 0) + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, value); + return ret; +} + +static int cbus_write_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 value) +{ + return i2c_smbus_write_byte_data(sii9234->pdata->cbus_client, offset, + value); +} + +static int cbus_read_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 *value) +{ + int ret; + + if (!value) + return -EINVAL; + + ret = i2c_smbus_write_byte(sii9234->pdata->cbus_client, offset); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + + ret = i2c_smbus_read_byte(sii9234->pdata->cbus_client); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x)\n", __func__, offset); + return ret; + } + + *value = ret & 0x000000FF; + + return 0; +} + +static int cbus_set_reg(struct sii9234_data *sii9234, unsigned int offset, + u8 mask) +{ + int ret; + u8 value; + + ret = cbus_read_reg(sii9234, offset, &value); + if (ret < 0) { + pr_err("[ERROR] sii9234 : %s(0x%02x, 0x%02x)\n", __func__, + offset, mask); + return ret; + } + + value |= mask; + + return cbus_write_reg(sii9234, offset, value); +} + +static int mhl_wake_toggle(struct sii9234_data *sii9234, + unsigned long high_period, + unsigned long low_period) +{ + int ret; + + /* These bits are not documented. */ + ret = mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL7_REG, (1<<7) | (1<<6)); + if (ret < 0) + return ret; + + usleep_range(high_period * USEC_PER_MSEC, high_period * USEC_PER_MSEC); + + ret = mhl_tx_clear_reg(sii9234, MHL_TX_DISC_CTRL7_REG, (1<<7) | (1<<6)); + if (ret < 0) + return ret; + + usleep_range(low_period * USEC_PER_MSEC, low_period * USEC_PER_MSEC); + + return 0; +} + +static int mhl_send_wake_pulses(struct sii9234_data *sii9234) +{ + int ret; + + ret = mhl_wake_toggle(sii9234, T_SRC_WAKE_PULSE_WIDTH_1, + T_SRC_WAKE_PULSE_WIDTH_1); + if (ret < 0) + return ret; + + ret = mhl_wake_toggle(sii9234, T_SRC_WAKE_PULSE_WIDTH_1, + T_SRC_WAKE_PULSE_WIDTH_2); + if (ret < 0) + return ret; + + ret = mhl_wake_toggle(sii9234, T_SRC_WAKE_PULSE_WIDTH_1, + T_SRC_WAKE_PULSE_WIDTH_1); + if (ret < 0) + return ret; + + ret = mhl_wake_toggle(sii9234, T_SRC_WAKE_PULSE_WIDTH_1, + T_SRC_WAKE_TO_DISCOVER); + if (ret < 0) + return ret; + + return 0; +} + +static int sii9234_cbus_reset(struct sii9234_data *sii9234) +{ + int ret; + u8 idx; + /* Reset CBUS */ + ret = mhl_tx_set_reg(sii9234, MHL_TX_SRST, 0x03); + if (ret < 0) + return ret; + + msleep(T_SRC_CBUS_DEGLITCH); + + ret = mhl_tx_clear_reg(sii9234, MHL_TX_SRST, 0x03); + if (ret < 0) + return ret; + + for (idx = 0; idx < 4; idx++) { + /* Enable WRITE_STAT interrupt for writes to all + 4 MSC Status registers.*/ + ret = cbus_write_reg(sii9234, 0xE0 + idx, 0xF2); + if (ret < 0) + return ret; + + /*Enable SET_INT interrupt for writes to all + 4 MSC Interrupt registers.*/ + ret = cbus_write_reg(sii9234, 0xF0 + idx, 0xF2); + if (ret < 0) + return ret; + } + + return 0; + +} + +/* require to chek mhl imformation of samsung in cbus_init_register*/ +static int sii9234_cbus_init(struct sii9234_data *sii9234) +{ + u8 value; + int ret; + + ret = cbus_write_reg(sii9234, 0x07, 0xF2); + if (ret < 0) + goto i2c_error_exit; + + ret = cbus_write_reg(sii9234, 0x40, 0x03); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x42, 0x06); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x36, 0x0C); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x3D, 0xFD); + if (ret < 0) + goto i2c_error_exit; + + ret = cbus_write_reg(sii9234, 0x1C, 0x01); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x1D, 0x0F); + if (ret < 0) + goto i2c_error_exit; + + ret = cbus_write_reg(sii9234, 0x44, 0x02); + if (ret < 0) + goto i2c_error_exit; + + /* Setup our devcap*/ + ret = cbus_write_reg(sii9234, 0x80, 0x00);/*To meet cts 6.3.10.1 spec*/ + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x81, 0x11);/*mhl version 1.1*/ + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x82, 0x02); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x83, 0x01);/*adopter_id 0x141*/ + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x84, 0x41);/*adopter_id 0x141*/ + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x85, 0x01);/*ONLY SUPP_RGB444*/ + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x86, 0x01); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x87, 0); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x88, (1<<7)); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x89, 0x0F); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x8A, (1<<0) | (1<<1) | (1<<2)); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x8B, 0); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x8C, 0); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x8D, 16); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x8E, 0x33); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x8F, 0); + if (ret < 0) + goto i2c_error_exit; + + ret = cbus_read_reg(sii9234, 0x31, &value); + if (ret < 0) + goto i2c_error_exit; + value |= 0x0C; + ret = cbus_write_reg(sii9234, 0x31, value); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, 0x30, 0x01); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_read_reg(sii9234, 0x3C, &value); + if (ret < 0) + goto i2c_error_exit; + value &= ~0x38; + value |= 0x30; + ret = cbus_write_reg(sii9234, 0x3C, value); + if (ret < 0) + goto i2c_error_exit; + + ret = cbus_read_reg(sii9234, 0x22, &value); + if (ret < 0) + goto i2c_error_exit; + value &= ~0x0F; + value |= 0x0D; + ret = cbus_write_reg(sii9234, 0x22, value); + if (ret < 0) + goto i2c_error_exit; + + ret = cbus_read_reg(sii9234, 0x2E, &value); + if (ret < 0) + goto i2c_error_exit; + value |= 0x15; + ret = cbus_write_reg(sii9234, 0x2E, value); + if (ret < 0) + goto i2c_error_exit; + + ret = cbus_write_reg(sii9234, CBUS_INTR1_ENABLE_REG, 0); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, CBUS_INTR2_ENABLE_REG, 0); + if (ret < 0) + goto i2c_error_exit; + + return 0; +i2c_error_exit: + pr_err("[ERROR] %s()\n", __func__); + return ret; +} + +static void cbus_req_abort_error(struct sii9234_data *sii9234) +{ + u8 abort_reason = 0; + + pr_debug("sii9234: MSC Request Aborted:"); + + cbus_read_reg(sii9234, MSC_REQ_ABORT_REASON_REG, &abort_reason); + + if (abort_reason) { + if (abort_reason & BIT_MSC_XFR_ABORT) { + cbus_read_reg(sii9234, MSC_REQ_ABORT_REASON_REG, + &abort_reason); + pr_cont("ABORT_REASON_REG = %d\n", abort_reason); + cbus_write_reg(sii9234, MSC_REQ_ABORT_REASON_REG, 0xff); + } + if (abort_reason & BIT_MSC_ABORT) { + cbus_read_reg(sii9234, BIT_MSC_ABORT, &abort_reason); + pr_cont("BIT_MSC_ABORT = %d\n", abort_reason); + cbus_write_reg(sii9234, BIT_MSC_ABORT, 0xff); + } + if (abort_reason & ABORT_BY_PEER) + pr_cont(" Peer Sent an ABORT"); + if (abort_reason & UNDEF_CMD) + pr_cont(" Undefined Opcode"); + if (abort_reason & TIMEOUT) + pr_cont(" Requestor Translation layer Timeout"); + if (abort_reason & PROTO_ERROR) + pr_cont(" Protocol Error"); + if (abort_reason & MAX_FAIL) { + u8 msc_retry_thr_val = 0; + pr_cont(" Retry Threshold exceeded"); + cbus_read_reg(sii9234, + MSC_RETRY_FAIL_LIM_REG, + &msc_retry_thr_val); + pr_cont("Retry Threshold value is:%d", + msc_retry_thr_val); + } + } + pr_cont("\n"); +} + +static void cbus_resp_abort_error(struct sii9234_data *sii9234) +{ + u8 abort_reason = 0; + + pr_debug("sii9234: MSC Response Aborted:"); + cbus_read_reg(sii9234, MSC_RESP_ABORT_REASON_REG, &abort_reason); + cbus_write_reg(sii9234, MSC_RESP_ABORT_REASON_REG, 0xff); + if (abort_reason) { + if (abort_reason & ABORT_BY_PEER) + pr_cont(" Peer Sent an ABORT"); + if (abort_reason & UNDEF_CMD) + pr_cont(" Undefined Opcode"); + if (abort_reason & TIMEOUT) + pr_cont(" Requestor Translation layer Timeout"); + } + pr_cont("\n"); +} + +static void force_usb_id_switch_open(struct sii9234_data *sii9234) +{ + /*Disable CBUS discovery*/ + mhl_tx_clear_reg(sii9234, MHL_TX_DISC_CTRL1_REG, (1<<0)); + /*Force USB ID switch to open*/ + mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL6_REG, USB_ID_OVR); + + mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL3_REG, 0x86); + /*Force upstream HPD to 0 when not in MHL mode.*/ + mhl_tx_clear_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<4) | (1<<5)); +} + +static void release_usb_id_switch_open(struct sii9234_data *sii9234) +{ + msleep(T_SRC_CBUS_FLOAT); + /* clear USB ID switch to open*/ + mhl_tx_clear_reg(sii9234, MHL_TX_DISC_CTRL6_REG, USB_ID_OVR); + /* Enable CBUS discovery*/ + mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL1_REG, (1<<0)); +} + +static bool cbus_ddc_abort_error(struct sii9234_data *sii9234) +{ + u8 val1, val2; + + /* clear the ddc abort counter */ + cbus_write_reg(sii9234, 0x29, 0xFF); + cbus_read_reg(sii9234, 0x29, &val1); + usleep_range(3000, 4000); + cbus_read_reg(sii9234, 0x29, &val2); + if (val2 > (val1 + 50)) { + pr_debug("Applying DDC Abort Safety(SWA 18958)\n)"); + mhl_tx_set_reg(sii9234, MHL_TX_SRST, (1<<3)); + mhl_tx_clear_reg(sii9234, MHL_TX_SRST, (1<<3)); + force_usb_id_switch_open(sii9234); + release_usb_id_switch_open(sii9234); + mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL1_REG, 0xD0); + sii9234_tmds_control(sii9234, false); + /* Disconnect and notify to OTG */ + return true; + } + pr_debug("sii9234: DDC abort interrupt\n"); + + return false; +} + +#ifdef CONFIG_SII9234_RCP +static void rcp_uevent_report(struct sii9234_data *sii9234, u8 key) +{ + if (!sii9234->input_dev) { + pr_err("%s: sii9234->input_dev is NULL & " + "skip rcp_report\n", __func__); + return; + } + + pr_info("rcp_uevent_report key: %d\n", key); + input_report_key(sii9234->input_dev, (unsigned int)key+1, 1); + input_report_key(sii9234->input_dev, (unsigned int)key+1, 0); + input_sync(sii9234->input_dev); +} + +/* + * is_rcp_code_valid: Validdates the recevied RCP key, + * valid key is 1 to 1 map to fwk keylayer file sii9234_rcp.kl + * located at (/system/usr/keylayout/sii9234_rcp.kl). + * + * New key support needs to be update is_rcp_key_code_valid at + * driver side and /system/usr/keylayout/sii9234_rcp.kl at fwk side. + */ + +static int is_rcp_key_code_valid(u8 key) +{ + switch (key+1) { + /*should resemble /system/usr/keylayout/sii9234_rcp.kl*/ + case 1: /* ENTER WAKE_DROPPED*/ + case 2: /* DPAD_UP WAKE_DROPPED*/ + case 3: /* DPAD_DOWN WAKE_DROPPED*/ + case 4: /* DPAD_LEFT WAKE_DROPPED*/ + case 5: /* DPAD_RIGHT WAKE_DROPPED*/ + case 10: /* MENU WAKE_DROPPED*/ + case 14: /* BACK WAKE_DROPPED*/ + case 33: /* 0 */ + case 34: /* 1 */ + case 35: /* 2 */ + case 36: /* 3 */ + case 37: /* 4 */ + case 38: /* 5 */ + case 39: /* 6 */ + case 40: /* 7 */ + case 41: /* 8 */ + case 42: /* 9 */ + case 43: /* ENTER*/ + case 45: /* DEL */ + case 69: /* MEDIA_PLAY_PAUSE WAKE*/ + case 70: /* MEDIA_STOP WAKE*/ + case 71: /* MEDIA_PAUSE WAKE*/ + case 73: /* MEDIA_REWIND WAKE*/ + case 74: /* MEDIA_FAST_FORWARD WAKE*/ + case 76: /* MEDIA_NEXT WAKE*/ + case 77: /* MEDIA_PREVIOUS WAKE*/ + return 1; + default: + return 0; + } + +} + +static void cbus_process_rcp_key(struct sii9234_data *sii9234, u8 key) +{ + + if (is_rcp_key_code_valid(key)) { + /* Report the key */ + rcp_uevent_report(sii9234, key); + /* Send the RCP ack */ + cbus_command_request(sii9234, CBUS_MSC_MSG, + MSG_RCPK, key); + + } else { + sii9234->error_key = key; + /* + * Send a RCPE(RCP Error Message) to Peer followed by + * RCPK with old key-code so that initiator(TV) can + * recognize failed key code.error code = 0x01 means + * Ineffective key code was received. + * See Table 21.(PRM)for details. + */ + cbus_command_request(sii9234, CBUS_MSC_MSG, MSG_RCPE, 0x01); + } +} +#endif + +static void cbus_process_rap_key(struct sii9234_data *sii9234, u8 key) +{ + if (CBUS_MSC_RAP_CONTENT_ON == key) + sii9234_tmds_control(sii9234, true); + else if (CBUS_MSC_RAP_CONTENT_OFF == key) + sii9234_tmds_control(sii9234, false); +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + cbus_command_request(sii9234, CBUS_MSC_MSG, MSG_RAPK, 0x00); +#else + sii9234_enqueue_msc_work(sii9234, CBUS_MSC_MSG, MSG_RAPK, 0x00, 0x0); +#endif +} + +/* + * Incoming MSC_MSG : RCP/RAP/RCPK/RCPE/RAPK commands + * + * Process RCP key codes and the send supported keys to userspace. + * If a key is not supported then an error ack is sent to the peer. Note + * that by default all key codes are supported. + * + * An alternate method might be to decide the validity of the key in the + * driver itself. However, the driver does not have any criteria to which + * to make this decision. + */ +static void cbus_handle_msc_msg(struct sii9234_data *sii9234) +{ + u8 cmd_code, key; + + + mutex_lock(&sii9234->cbus_lock); + if (sii9234->state != STATE_ESTABLISHED) { + pr_debug("sii9234: invalid MHL state\n"); + mutex_unlock(&sii9234->cbus_lock); + return ; + } + + cbus_read_reg(sii9234, CBUS_MSC_MSG_CMD_IN_REG, &cmd_code); + cbus_read_reg(sii9234, CBUS_MSC_MSG_DATA_IN_REG, &key); + + pr_info("sii9234: cmd_code:%d, key:%d\n", cmd_code, key); + + switch (cmd_code) { + case MSG_RCP: + pr_debug("sii9234: RCP Arrived. KEY CODE:%d\n", key); + mutex_unlock(&sii9234->cbus_lock); + cbus_process_rcp_key(sii9234, key); + return; + case MSG_RAP: + pr_debug("sii9234: RAP Arrived\n"); + mutex_unlock(&sii9234->cbus_lock); + cbus_process_rap_key(sii9234, key); + return; + case MSG_RCPK: + pr_debug("sii9234: RCPK Arrived\n"); + break; + case MSG_RCPE: + pr_debug("sii9234: RCPE Arrived\n"); + break; + case MSG_RAPK: + pr_debug("sii9234: RAPK Arrived\n"); + break; + default: + pr_debug("sii9234: MAC error\n"); + mutex_unlock(&sii9234->cbus_lock); +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + cbus_command_request(sii9234, CBUS_GET_MSC_ERR_CODE, 0, 0); +#else + sii9234_enqueue_msc_work(sii9234, + CBUS_GET_MSC_ERR_CODE, 0, 0, 0x0); +#endif + return; + } + mutex_unlock(&sii9234->cbus_lock); +} + +void mhl_path_enable(struct sii9234_data *sii9234, bool path_en) +{ + pr_debug("sii9234: mhl_path_enable MHL_STATUS_PATH_ENABLED," + " path_en=%d !!!\n", path_en); + + if (path_en) + sii9234->mhl_status_value.linkmode |= MHL_STATUS_PATH_ENABLED; + else + sii9234->mhl_status_value.linkmode &= ~MHL_STATUS_PATH_ENABLED; +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + cbus_command_request(sii9234, CBUS_WRITE_STAT, + CBUS_LINK_CONTROL_2_REG, sii9234->mhl_status_value.linkmode); +#else + sii9234_enqueue_msc_work(sii9234, CBUS_WRITE_STAT, + CBUS_LINK_CONTROL_2_REG, + sii9234->mhl_status_value.linkmode, 0x0); +#endif +} + +#if 0 +static void cbus_handle_wrt_burst_recd(struct sii9234_data *sii9234) +{ + pr_debug("sii9234: CBUS WRT_BURST_RECD\n"); +} +#endif +static void cbus_handle_wrt_stat_recd(struct sii9234_data *sii9234) +{ + u8 status_reg0, status_reg1; + + pr_debug("sii9234: CBUS WRT_STAT_RECD\n"); + + /* + * The two MHL status registers need to read to ensure that the MSC is + * ready to receive the READ_DEVCAP command. + * The READ_DEVCAP command is need to determine the dongle power state + * and whether RCP, RCPE, RCPK, RAP, and RAPE are supported. + * + * Note that this is not documented properly in the PRM. + */ + + cbus_read_reg(sii9234, CBUS_MHL_STATUS_REG_0, &status_reg0); + cbus_write_reg(sii9234, CBUS_MHL_STATUS_REG_0, 0xFF); + cbus_read_reg(sii9234, CBUS_MHL_STATUS_REG_1, &status_reg1); + cbus_write_reg(sii9234, CBUS_MHL_STATUS_REG_1, 0xFF); + + pr_debug("sii9234: STATUS_REG0 : [%d];STATUS_REG1 : [%d]\n", + status_reg0, status_reg1); + + if (!(sii9234->mhl_status_value.linkmode & MHL_STATUS_PATH_ENABLED) && + (MHL_STATUS_PATH_ENABLED & status_reg1)) { + mhl_path_enable(sii9234, true); + } else if ((sii9234->mhl_status_value.linkmode + & MHL_STATUS_PATH_ENABLED) && + !(MHL_STATUS_PATH_ENABLED & status_reg1)) { + mhl_path_enable(sii9234, false); + } + + if (status_reg0 & MHL_STATUS_DCAP_READY) { + pr_debug("sii9234: DEV CAP READY\n"); +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + cbus_command_request(sii9234, CBUS_READ_DEVCAP, + DEVCAP_DEV_CAT, 0x00); + cbus_command_request(sii9234, CBUS_READ_DEVCAP, + DEVCAP_DEV_FEATURE_FLAG, 0x00); +#else + sii9234_enqueue_msc_work(sii9234, CBUS_READ_DEVCAP, + DEVCAP_DEV_CAT, 0x00, 0x0); + sii9234_enqueue_msc_work(sii9234, CBUS_READ_DEVCAP, + DEVCAP_DEV_FEATURE_FLAG, 0x00, 0x0); + sii9234_enqueue_msc_work(sii9234, CBUS_READ_DEVCAP, + DEVCAP_DEVICE_ID_H, 0x0, 0x0); + sii9234_enqueue_msc_work(sii9234, CBUS_READ_DEVCAP, + DEVCAP_DEVICE_ID_L, 0x0, 0x0); + sii9234_enqueue_msc_work(sii9234, CBUS_READ_DEVCAP, + DEVCAP_RESERVED, 0x0, 0x0); +#endif + } +} + +static void cbus_handle_set_int_recd(struct sii9234_data *sii9234) +{ + u8 intr_reg0, intr_reg1, value; + + /* read and clear interrupt*/ + cbus_read_reg(sii9234, CBUS_MHL_INTR_REG_0, &intr_reg0); + cbus_write_reg(sii9234, CBUS_MHL_INTR_REG_0, intr_reg0); + + cbus_read_reg(sii9234, CBUS_MHL_INTR_REG_1, &intr_reg1); + cbus_write_reg(sii9234, CBUS_MHL_INTR_REG_1, intr_reg1); + + pr_debug("sii9234: INTR_REG0 : [%d]; INTR_REG1 : [%d]\n", + intr_reg0, intr_reg1); + + if (intr_reg0 & MHL_INT_DCAP_CHG) { +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + pr_debug("sii9234: MHL_INT_DCAP_CHG\n"); + cbus_command_request(sii9234, CBUS_READ_DEVCAP, + DEVCAP_DEV_CAT, 0x00); + cbus_command_request(sii9234, CBUS_READ_DEVCAP, + DEVCAP_DEV_FEATURE_FLAG, 0x00); +#endif + } + + if (intr_reg0 & MHL_INT_DSCR_CHG) + pr_debug("sii9234: MHL_INT_DSCR_CHG\n"); + + if (intr_reg0 & MHL_INT_REQ_WRT) { + pr_debug("sii9234: MHL_INT_REQ_WRT\n"); +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + cbus_command_request(sii9234, CBUS_SET_INT, + MHL_RCHANGE_INT, MHL_INT_GRT_WRT); +#else + sii9234_enqueue_msc_work(sii9234, CBUS_SET_INT, + MHL_RCHANGE_INT, MHL_INT_GRT_WRT, 0x0); +#endif + } + + if (intr_reg0 & MHL_INT_GRT_WRT) + pr_debug("sii9234: MHL_INT_GRT_WRT\n"); + + if (intr_reg1 & MHL_INT_EDID_CHG) { + /* Enable Overriding HPD OUT */ + mhl_tx_set_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<4)); + + /* + * As per HDMI specification to indicate EDID change + * in TV (or sink), we need to toggle HPD line. + */ + + /* HPD OUT = Low */ + mhl_tx_clear_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<5)); + + /* A SET_HPD command shall not follow a CLR_HPD command + * within less than THPD_WIDTH(50ms). + */ + msleep(T_HPD_WIDTH); + + /* HPD OUT = High */ + mhl_tx_set_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<5)); + + /* Disable Overriding of HPD OUT */ + mhl_tx_clear_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<4)); + } + + /* clear SET_INT_RECD interrupt */ + cbus_read_reg(sii9234, CBUS_MHL_INTR_REG_2, &value); + cbus_write_reg(sii9234, CBUS_MHL_INTR_REG_2, value); + + cbus_read_reg(sii9234, CBUS_MHL_INTR_REG_3, &value); + cbus_write_reg(sii9234, CBUS_MHL_INTR_REG_3, value); +} + +static int sii9234_power_init(struct sii9234_data *sii9234) +{ + int ret; + + /* Force the SiI9234 into the D0 state. */ + ret = tpi_write_reg(sii9234, TPI_DPD_REG, 0x3F); + if (ret < 0) + return ret; + + /* Enable TxPLL Clock */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_TMDS_CLK_EN_REG, 0x01); + if (ret < 0) + return ret; + + /* Enable Tx Clock Path & Equalizer*/ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_TMDS_CH_EN_REG, 0x15); + if (ret < 0) + return ret; + + /* Power Up TMDS*/ + ret = mhl_tx_write_reg(sii9234, 0x08, 0x35); + if (ret < 0) + return ret; + + return ret; +} + +static int sii9234_hdmi_init(struct sii9234_data *sii9234) +{ + int ret = 0; + /* Analog PLL Control + * bits 5:4 = 2b00 as per characterization team. + */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1); + if (ret < 0) + goto i2c_error_exit; + + /* PLL Calrefsel */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_PLL_CALREFSEL_REG, 0x03); + if (ret < 0) + goto i2c_error_exit; + + /* VCO Cal */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_PLL_VCOCAL_REG, 0x20); + if (ret < 0) + goto i2c_error_exit; + + /* Auto EQ */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_EQ_DATA0_REG, 0x8A); + if (ret < 0) + goto i2c_error_exit; + + /* Auto EQ */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_EQ_DATA1_REG, 0x6A); + if (ret < 0) + goto i2c_error_exit; + + /* Auto EQ */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_EQ_DATA2_REG, 0xAA); + if (ret < 0) + goto i2c_error_exit; + + /* Auto EQ */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_EQ_DATA3_REG, 0xCA); + if (ret < 0) + goto i2c_error_exit; + + /* Auto EQ */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_EQ_DATA4_REG, 0xEA); + if (ret < 0) + goto i2c_error_exit; + + /* Manual zone */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_TMDS_ZONE_CTRL_REG, 0xA0); + if (ret < 0) + goto i2c_error_exit; + + /* PLL Mode Value */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_TMDS_MODE_CTRL_REG, 0x00); + if (ret < 0) + goto i2c_error_exit; + + ret = mhl_tx_write_reg(sii9234, MHL_TX_TMDS_CCTRL, 0x34); + if (ret < 0) + goto i2c_error_exit; + + ret = hdmi_rx_write_reg(sii9234, 0x45, 0x44); + if (ret < 0) + goto i2c_error_exit; + + /* Rx PLL BW ~ 4MHz */ + ret = hdmi_rx_write_reg(sii9234, 0x31, 0x0A); + if (ret < 0) + goto i2c_error_exit; + + /* Analog PLL Control + * bits 5:4 = 2b00 as per characterization team. + */ + ret = hdmi_rx_write_reg(sii9234, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1); + if (ret < 0) + goto i2c_error_exit; + + return ret; + +i2c_error_exit: + pr_err("[ERROR] %s()\n", __func__); + return ret; +} + +static int sii9234_mhl_tx_ctl_int(struct sii9234_data *sii9234) +{ + int ret = 0; + + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL1_REG, 0xD0); + if (ret < 0) + goto i2c_error_exit; +#ifdef __CONFIG_RSEN_LOST_PATCH__ + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL2_REG, 0xC0); + if (ret < 0) + goto i2c_error_exit; +#else + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL2_REG, 0xFC); + if (ret < 0) + goto i2c_error_exit; +#endif + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL4_REG, + sii9234->pdata->swing_level); + if (ret < 0) + goto i2c_error_exit; + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL7_REG, 0x0C); + if (ret < 0) + goto i2c_error_exit; + + return ret; + +i2c_error_exit: + pr_err("[ERROR] %s()\n", __func__); + return ret; +} + +static void sii9234_power_down(struct sii9234_data *sii9234) +{ + sii9234_disable_irq(); + if (sii9234->claimed) { + if (sii9234->pdata->vbus_present) +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD + sii9234->pdata->vbus_present(false , 0); +#else + sii9234->pdata->vbus_present(false); +#endif + } + + sii9234->state = STATE_DISCONNECTED; + sii9234->claimed = false; + + tpi_write_reg(sii9234, TPI_DPD_REG, 0); + /*turn on&off hpd festure for only QCT HDMI*/ + mhl_hpd_handler(false); +} + +int rsen_state_timer_out(struct sii9234_data *sii9234) +{ + int ret = 0; + u8 value; + + ret = mhl_tx_read_reg(sii9234, MHL_TX_SYSSTAT_REG, &value); + if (ret < 0) + goto err_exit; + sii9234->rsen = value & RSEN_STATUS; + + if (value & RSEN_STATUS) { + pr_info("sii9234: MHL cable connected.. RESN High\n"); + } else { + pr_info("sii9234: RSEN lost\n"); + msleep(T_SRC_RXSENSE_DEGLITCH); + ret = mhl_tx_read_reg(sii9234, MHL_TX_SYSSTAT_REG, &value); + if (ret < 0) + goto err_exit; + + pr_info("sys_stat: %x ~\n", value); + if ((value & RSEN_STATUS) == 0) { + pr_info("RSEN Really LOW ~\n"); + /*To meet CTS 3.3.22.2 spec*/ + sii9234_tmds_control(sii9234, false); + force_usb_id_switch_open(sii9234); + release_usb_id_switch_open(sii9234); + ret = -1; + goto err_exit; + } else + pr_info("sii9234: RSEN recovery\n"); + + } + return ret; + +err_exit: + /*turn off mhl and change usb_sel to usb*/ +#ifdef CONFIG_MHL_D3_SUPPORT + goto_d3(NULL); +#else + mhl_onoff_ex(0); +#endif + return ret; +} +#ifdef CONFIG_MHL_D3_SUPPORT +static void goto_d3(struct work_struct *work) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + int ret; + u8 value; + + pr_debug("sii9234: detection started d3\n"); + sii9234_callback_sched = 0; + + sii9234->mhl_status_value.linkmode = MHL_STATUS_CLK_MODE_NORMAL; + sii9234->rgnd = RGND_UNKNOWN; + sii9234->state = STATE_DISCONNECTED; + sii9234->rsen = false; + memset(cbus_pkt_buf, 0x00, sizeof(cbus_pkt_buf)); + + ret = sii9234_power_init(sii9234); + if (ret < 0) + goto unhandled; + ret = sii9234_hdmi_init(sii9234); + if (ret < 0) + goto unhandled; + ret = sii9234_mhl_tx_ctl_int(sii9234); + if (ret < 0) + goto unhandled; + + /* Enable HDCP Compliance safety*/ + ret = mhl_tx_write_reg(sii9234, 0x2B, 0x01); + if (ret < 0) + goto unhandled; + /* CBUS discovery cycle time for each drive and float = 150us*/ + ret = mhl_tx_read_reg(sii9234, MHL_TX_DISC_CTRL1_REG, &value); + if (ret < 0) + goto unhandled; + + value &= ~(1<<3); + value |= (1<<2); + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL1_REG, value); + if (ret < 0) + goto unhandled; + + /* Clear bit 6 (reg_skip_rgnd) */ + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL2_REG, + (1<<7) /* Reserved Bit */ | + 2 << ATT_THRESH_SHIFT | DEGLITCH_TIME_50MS); + if (ret < 0) + goto unhandled; + /* Changed from 66 to 65 for 94[1:0] = 01 = 5k reg_cbusmhl_pup_sel */ + /* 1.8V CBUS VTH & GND threshold */ + /*To meet CTS 3.3.7.2 spec*/ + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL5_REG, 0x77); + if (ret < 0) + goto unhandled; + /* set bit 2 and 3, which is Initiator Timeout */ + ret = cbus_read_reg(sii9234, CBUS_LINK_CONTROL_2_REG, &value); + if (ret < 0) + goto unhandled; + value |= 0x0C; + + ret = cbus_write_reg(sii9234, CBUS_LINK_CONTROL_2_REG, value); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL6_REG, 0xA0); + if (ret < 0) + goto unhandled; + /* RGND & single discovery attempt (RGND blocking) */ + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL6_REG, BLOCK_RGND_INT | + DVRFLT_SEL | SINGLE_ATT); + if (ret < 0) + goto unhandled; + /* Use VBUS path of discovery state machine*/ + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL8_REG, 0); + if (ret < 0) + goto unhandled; + ret = mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL6_REG, USB_ID_OVR); + if (ret < 0) + goto unhandled; + + /* To allow RGND engine to operate correctly. + * When moving the chip from D2 to D0 (power up, init regs) + * the values should be + * 94[1:0] = 01 reg_cbusmhl_pup_sel[1:0] should be set for 5k + * 93[7:6] = 10 reg_cbusdisc_pup_sel[1:0] should be + * set for 10k (default) + * 93[5:4] = 00 reg_cbusidle_pup_sel[1:0] = open (default) + */ + ret = mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL3_REG, 0xA6); + if (ret < 0) + goto unhandled; + /* change from CC to 8C to match 5K*/ + /*To meet CTS 3.3.72 spec*/ + ret = mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL4_REG, 0x8C); + if (ret < 0) + goto unhandled; + + /* Configure the interrupt as active high */ + ret = mhl_tx_clear_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<2) | (1<<1)); + if (ret < 0) + goto unhandled; + + msleep(25); + + /* release usb_id switch */ + ret = mhl_tx_clear_reg(sii9234, MHL_TX_DISC_CTRL6_REG, USB_ID_OVR); + if (ret < 0) + goto unhandled; + + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL1_REG, 0x27); + if (ret < 0) + goto unhandled; + + ret = sii9234_cbus_reset(sii9234); + if (ret < 0) + goto unhandled; + ret = sii9234_cbus_init(sii9234); + if (ret < 0) + goto unhandled; + + /* Enable Auto soft reset on SCDT = 0*/ + ret = mhl_tx_write_reg(sii9234, 0x05, 0x04); + if (ret < 0) + goto unhandled; + + /* HDMI Transcode mode enable*/ + ret = mhl_tx_write_reg(sii9234, 0x0D, 0x1C); + if (ret < 0) + goto unhandled; + + ret = mhl_tx_write_reg(sii9234, MHL_TX_INTR4_ENABLE_REG, + RGND_READY_MASK | CBUS_LKOUT_MASK | + MHL_DISC_FAIL_MASK | MHL_EST_MASK); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, MHL_TX_INTR1_ENABLE_REG, + (1<<5) | (1<<6)); + if (ret < 0) + goto unhandled; + /* this point is very importand before megsure RGND impedance*/ + force_usb_id_switch_open(sii9234); + ret = mhl_tx_clear_reg(sii9234, MHL_TX_DISC_CTRL4_REG, + (1<<7) | (1<<6) | (1<<5) | (1<<4)); + if (ret < 0) + goto unhandled; + ret = mhl_tx_clear_reg(sii9234, MHL_TX_DISC_CTRL5_REG, (1<<1) | (1<<0)); + if (ret < 0) + goto unhandled; + release_usb_id_switch_open(sii9234); + /*end of this*/ + /* Force upstream HPD to 0 when not in MHL mode */ + ret = mhl_tx_clear_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<5)); + if (ret < 0) + goto unhandled; + ret = mhl_tx_set_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<4)); + if (ret < 0) + goto unhandled; + + + ret = hdmi_rx_write_reg(sii9234, 0x01, 0x03); + if (ret < 0) + goto unhandled; + ret = tpi_read_reg(sii9234, 0x3D, &value); + if (ret < 0) + goto unhandled; + value &= ~BIT0; + ret = tpi_write_reg(sii9234, 0x3D, value); + if (ret < 0) + goto unhandled; + pr_info("sii9234 : go_to d3 mode!!!\n"); + if (sii9234_callback_sched == 1) + pr_info("debug_message\n"); + else + sii9234_enable_irq(); + +unhandled: + if (detached_status == 1) + pr_info("already mhl_state off\n"); +} +#endif +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD +void sii9234_process_msc_work(struct work_struct *work) +{ + u8 value; + int ret; + struct msc_packet *p_msc_pkt, *scratch; + struct sii9234_data *sii9234 = container_of(work, + struct sii9234_data, + msc_work); + /*Do not process msc untill STATE_ESTABLISHED*/ + if (sii9234->state != STATE_ESTABLISHED) + return; + + mutex_lock(&sii9234->cbus_lock); + mutex_lock(&sii9234->lock); + + pr_debug("%s() - start\n", __func__); + + list_for_each_entry_safe(p_msc_pkt, scratch, + &g_msc_packet_list, p_msc_packet_list) { + + pr_debug("[MSC] %s() command(0x%x), offset(0x%x), data_1(0x%x), data_2(0x%x)\n", + __func__, p_msc_pkt->command, p_msc_pkt->offset, + p_msc_pkt->data_1, p_msc_pkt->data_2); + + /* msc request */ + ret = sii9234_msc_req_locked(sii9234, p_msc_pkt); + if (ret < 0) { + pr_info("%s(): msc_req_locked error %d\n", + __func__, ret); + goto exit; + } + + /* MSC_REQ_DONE received */ + switch (p_msc_pkt->command) { + case CBUS_MSC_MSG: + if ((p_msc_pkt->offset == MSG_RCPE) && + (p_msc_pkt->data_2 == 0x01)) { + sii9234_enqueue_msc_work( + sii9234, CBUS_MSC_MSG, + MSG_RCPK, MSG_RCPK, + 0x0); + } + break; + case CBUS_WRITE_STAT: + break; + case CBUS_SET_INT: + if ((p_msc_pkt->offset == MHL_RCHANGE_INT) && + (p_msc_pkt->data_1 == MHL_INT_DSCR_CHG)) { + /* + *Write burst final step + *Req->GRT->Write->DSCR + */ + pr_debug("sii9234: MHL_RCHANGE_INT &" + "MHL_INT_DSCR_CHG\n"); + } else if ((p_msc_pkt->offset == MHL_RCHANGE_INT) && + (p_msc_pkt->data_1 == MHL_INT_DCAP_CHG)) { + pr_debug("sii9234: MHL_RCHANGE_INT &" + "MHL_INT_DCAP_CHG\n"); + sii9234->cbus_pkt.command = CBUS_IDLE; + sii9234_enqueue_msc_work(sii9234, + CBUS_WRITE_STAT, + MHL_STATUS_REG_CONNECTED_RDY, + MHL_STATUS_DCAP_READY, 0x0); + } + break; + case CBUS_WRITE_BURST: + sii9234_enqueue_msc_work(sii9234, CBUS_SET_INT, + MHL_RCHANGE_INT, + MHL_INT_DSCR_CHG, 0x0); + break; + case CBUS_READ_DEVCAP: + ret = cbus_read_reg(sii9234, + CBUS_MSC_FIRST_DATA_IN_REG, &value); + if (ret < 0) + break; + switch (p_msc_pkt->offset) { + case DEVCAP_DEV_STATE: + pr_debug("sii9234: DEVCAP_DEV_STATE\n"); + break; + case DEVCAP_MHL_VERSION: + sii9234->devcap.mhl_ver = value; + pr_debug("sii9234: MHL_VERSION: %X\n", value); + break; + case DEVCAP_DEV_CAT: + if (value & MHL_DEV_CATEGORY_POW_BIT) + pr_debug("sii9234: CAT=POWERED"); + else + pr_debug("sii9234: CAT=UNPOWERED"); + break; + case DEVCAP_ADOPTER_ID_H: + sii9234->devcap.adopter_id = + (value & 0xFF) << 0x8; + pr_debug("sii9234: DEVCAP_ADOPTER_ID_H = %X\n", + value); + break; + case DEVCAP_ADOPTER_ID_L: + sii9234->devcap.adopter_id |= value & 0xFF; + pr_debug("sii9234: DEVCAP_ADOPTER_ID_L = %X\n", + value); + break; + case DEVCAP_VID_LINK_MODE: + sii9234->devcap.vid_link_mode = 0x3F & value; + pr_debug("sii9234: MHL_CAP_VID_LINK_MODE = %d\n", + sii9234->devcap.vid_link_mode); + break; + case DEVCAP_AUD_LINK_MODE: + sii9234->devcap.aud_link_mode = 0x03 & value; + pr_debug("sii9234: DEVCAP_AUD_LINK_MODE =%d\n", + sii9234->devcap.aud_link_mode); + break; + case DEVCAP_VIDEO_TYPE: + sii9234->devcap.video_type = 0x8F & value; + pr_debug("sii9234: DEVCAP_VIDEO_TYPE =%d\n", + sii9234->devcap.video_type); + break; + case DEVCAP_LOG_DEV_MAP: + sii9234->devcap.log_dev_map = value; + pr_debug("sii9234: DEVCAP_LOG_DEV_MAP =%d\n", + sii9234->devcap.log_dev_map); + break; + case DEVCAP_BANDWIDTH: + sii9234->devcap.bandwidth = value; + pr_debug("sii9234: DEVCAP_BANDWIDTH =%d\n", + sii9234->devcap.bandwidth); + break; + case DEVCAP_DEV_FEATURE_FLAG: + if ((value & MHL_FEATURE_RCP_SUPPORT) == 0) + pr_debug("sii9234: FEATURE_FLAG=RCP"); + + if ((value & MHL_FEATURE_RAP_SUPPORT) == 0) + pr_debug("sii9234: FEATURE_FLAG=RAP\n"); + + if ((value & MHL_FEATURE_SP_SUPPORT) == 0) + pr_debug("sii9234: FEATURE_FLAG=SP\n"); + break; + case DEVCAP_DEVICE_ID_H: + sii9234->devcap.device_id = + (value & 0xFF) << 0x8; + pr_info("sii9234: DEVICE_ID_H=0x%x\n", value); + break; + case DEVCAP_DEVICE_ID_L: + sii9234->devcap.device_id |= value & 0xFF; + pr_info("sii9234: DEVICE_ID_L=0x%x\n", value); + break; + case DEVCAP_SCRATCHPAD_SIZE: + sii9234->devcap.scratchpad_size = value; + pr_debug("sii9234: DEVCAP_SCRATCHPAD_SIZE =%d\n", + sii9234->devcap.scratchpad_size); + break; + case DEVCAP_INT_STAT_SIZE: + sii9234->devcap.int_stat_size = value; + pr_debug("sii9234: DEVCAP_INT_STAT_SIZE =%d\n", + sii9234->devcap.int_stat_size); + break; + case DEVCAP_RESERVED: + sii9234->dcap_ready_status = 1; + sii9234->devcap.reserved_data = value; + pr_info("sii9234: DEVCAP_RESERVED : %d\n", + value); + wake_up(&sii9234->wq); + break; + default: + pr_debug("sii9234: DEVCAP DEFAULT\n"); + break; + } + break; + default: + break; + } + + list_del(&p_msc_pkt->p_msc_packet_list); + pr_debug("[MSC] %s() free item , addr = 0x%x, cnt=%d\n", + __func__, (unsigned int)p_msc_pkt, --g_list_cnt); + kfree(p_msc_pkt); + } +exit: + mutex_unlock(&sii9234->lock); + mutex_unlock(&sii9234->cbus_lock); +} + +static int sii9234_enqueue_msc_work(struct sii9234_data *sii9234, u8 command, + u8 offset, u8 data_1, u8 data_2) +{ + struct msc_packet *packet_item; + + packet_item = kmalloc(sizeof(struct msc_packet), GFP_KERNEL); + if (!packet_item) { + pr_err("[ERROR] %s() kmalloc error\n", __func__); + return -ENOMEM; + } else + pr_debug("[MSC] %s() add item, addr = 0x%x, cnt=%d\n", + __func__, (unsigned int)packet_item, ++g_list_cnt); + + packet_item->command = command; + packet_item->offset = offset; + packet_item->data_1 = data_1; + packet_item->data_2 = data_2; + + pr_debug("[MSC] %s() command(0x%x), offset(0x%x), data_1(0x%x), data_2(0x%x)\n", + __func__, command, offset, data_1, data_2); + list_add_tail(&packet_item->p_msc_packet_list, &g_msc_packet_list); + + pr_debug("[MSC] %s() msc work schedule\n", __func__); + queue_work(sii9234_msc_wq, &(sii9234->msc_work)); + + return 0; +} + +/* Must call with sii9234->lock held */ +static int sii9234_msc_req_locked(struct sii9234_data *sii9234, + struct msc_packet *msc_pkt) +{ + int ret; + u8 start_command; + + + init_completion(&sii9234->msc_complete); + + cbus_write_reg(sii9234, CBUS_MSC_OFFSET_REG, msc_pkt->offset); + if (msc_pkt->command == CBUS_MSC_MSG) + msc_pkt->data_1 = msc_pkt->offset; + cbus_write_reg(sii9234, CBUS_MSC_FIRST_DATA_OUT_REG, msc_pkt->data_1); + + switch (msc_pkt->command) { + case CBUS_SET_INT: + case CBUS_WRITE_STAT: + start_command = START_BIT_WRITE_STAT_INT; + break; + case CBUS_MSC_MSG: + cbus_write_reg(sii9234, CBUS_MSC_SECOND_DATA_OUT_REG, + msc_pkt->data_2); + cbus_write_reg(sii9234, CBUS_MSC_OFFSET_REG, msc_pkt->command); + + start_command = START_BIT_MSC_MSG; + break; + case CBUS_READ_DEVCAP: + start_command = START_BIT_READ_DEVCAP; + break; + case CBUS_WRITE_BURST: + start_command = START_BIT_WRITE_BURST; + break; + case CBUS_GET_STATE: + case CBUS_GET_VENDOR_ID: + case CBUS_SET_HPD: + case CBUS_CLR_HPD: + case CBUS_GET_MSC_ERR_CODE: + case CBUS_GET_SC3_ERR_CODE: + case CBUS_GET_SC1_ERR_CODE: + case CBUS_GET_DDC_ERR_CODE: + cbus_write_reg(sii9234, CBUS_MSC_OFFSET_REG, msc_pkt->command); + start_command = START_BIT_MSC_RESERVED; + break; + default: + pr_err("[ERROR] %s() invalid msc command(%d)\n", + __func__, msc_pkt->command); + return -EINVAL; + } + + cbus_write_reg(sii9234, CBUS_MSC_COMMAND_START_REG, start_command); + + mutex_unlock(&sii9234->lock); + ret = wait_for_completion_timeout(&sii9234->msc_complete, + msecs_to_jiffies(300)); + if (ret == 0) + printk(KERN_ERR "[ERROR] %s() MSC_REQ_DONE timeout\n", + __func__); + + mutex_lock(&sii9234->lock); + + return ret ? 0 : -EIO; +} +#endif /* CONFIG_MHL_NEW_CBUS_MSC_CMD end */ + + +static void mhl_cbus_write_stat_worker(struct work_struct *p) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + cbus_command_request(sii9234, CBUS_WRITE_STAT, CBUS_LINK_CONTROL_2_REG, + sii9234->mhl_status_value.linkmode); +#else + sii9234_enqueue_msc_work(sii9234, CBUS_WRITE_STAT, + CBUS_LINK_CONTROL_2_REG, + sii9234->mhl_status_value.linkmode, 0x0); +#endif + return; +} +static void sii9234_detection_callback(struct work_struct *work) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + int ret; + u8 value; + int handled = 0; + + pr_debug("sii9234: detection started\n"); + + sii9234_mutex_lock(&sii9234->lock); + sii9234_callback_sched = 1; + sii9234->mhl_status_value.linkmode = MHL_STATUS_CLK_MODE_NORMAL; + sii9234->rgnd = RGND_UNKNOWN; + sii9234->state = STATE_DISCONNECTED; + sii9234->rsen = false; + sii9234->dcap_ready_status = 0; + memset(cbus_pkt_buf, 0x00, sizeof(cbus_pkt_buf)); + ret = sii9234_power_init(sii9234); + if (ret < 0) { + pr_err("[ERROR] %s() - sii9234_power_init\n", __func__); + goto unhandled; + } + + ret = sii9234_cbus_reset(sii9234); + if (ret < 0) { + pr_err("[ERROR] %s() - sii9234_cbus_reset\n", __func__); + goto unhandled; + } + + ret = sii9234_hdmi_init(sii9234); + if (ret < 0) { + pr_err("[ERROR] %s() - sii9234_hdmi_init\n", __func__); + goto unhandled; + } + + ret = sii9234_mhl_tx_ctl_int(sii9234); + if (ret < 0) { + pr_err("[ERROR] %s() - sii9234_mhl_tx_ctl_int\n", __func__); + goto unhandled; + } + + /* Enable HDCP Compliance safety*/ + ret = mhl_tx_write_reg(sii9234, 0x2B, 0x01); + if (ret < 0) { + pr_err("[ERROR] %s() - mhl_tx_write_reg 0x2B\n", __func__); + goto unhandled; + } + + /* CBUS discovery cycle time for each drive and float = 150us*/ + ret = mhl_tx_read_reg(sii9234, MHL_TX_DISC_CTRL1_REG, &value); + if (ret < 0) { + pr_err("[ERROR] %s() - MHL_TX_DISC_CTRL1_REG\n", __func__); + goto unhandled; + } + + value &= ~(1<<3); + value |= (1<<2); + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL1_REG, value); + if (ret < 0) { + pr_err("[ERROR] %s() - MHL_TX_DISC_CTRL1_REG\n", __func__); + goto unhandled; + } + + /* Clear bit 6 (reg_skip_rgnd) */ + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL2_REG, + (1<<7) /* Reserved Bit */ | + 2 << ATT_THRESH_SHIFT | + DEGLITCH_TIME_50MS); + if (ret < 0) { + pr_err("[ERROR] %s() - Clear bit 6\n", __func__); + goto unhandled; + } + + /* Changed from 66 to 65 for 94[1:0] = 01 = 5k reg_cbusmhl_pup_sel */ + /* 1.8V CBUS VTH & GND threshold */ + /*To meet CTS 3.3.7.2 spec*/ + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL5_REG, 0x77); + if (ret < 0) { + pr_err("[ERROR] %s() - MHL_TX_DISC_CTRL5_REG\n", __func__); + goto unhandled; + } + + /* set bit 2 and 3, which is Initiator Timeout */ + ret = cbus_read_reg(sii9234, CBUS_LINK_CONTROL_2_REG, &value); + if (ret < 0) { + pr_err("[ERROR] %s()-read CBUS_LINK_CONTROL_2_REG\n", __func__); + goto unhandled; + } + + value |= 0x0C; + + ret = cbus_write_reg(sii9234, CBUS_LINK_CONTROL_2_REG, value); + if (ret < 0) { + pr_err("[ERROR]%s()-write CBUS_LINK_CONTROL_2_REG\n", __func__); + goto unhandled; + } + + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL6_REG, 0xA0); + if (ret < 0) { + pr_err("[ERROR] %s() -write MHL_TX_MHLTX_CTL6_REG\n", __func__); + goto unhandled; + } + + /* RGND & single discovery attempt (RGND blocking) */ + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL6_REG, BLOCK_RGND_INT | + DVRFLT_SEL | SINGLE_ATT); + if (ret < 0) { + pr_err("[ERROR] %s()-write MHL_TX_DISC_CTRL6_REG\n", __func__); + goto unhandled; + } + + /* Use VBUS path of discovery state machine*/ + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL8_REG, 0); + if (ret < 0) { + pr_err("[ERROR] %s()-write MHL_TX_DISC_CTRL8_REG\n", __func__); + goto unhandled; + } + + ret = mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL6_REG, USB_ID_OVR); + if (ret < 0) { + pr_err("[ERROR] %s() - set MHL_TX_DISC_CTRL6_REG\n", __func__); + goto unhandled; + } + + /* To allow RGND engine to operate correctly. + * When moving the chip from D2 to D0 (power up, init regs) + * the values should be + * 94[1:0] = 01 reg_cbusmhl_pup_sel[1:0] should be set for 5k + * 93[7:6] = 10 reg_cbusdisc_pup_sel[1:0] should be + * set for 10k (default) + * 93[5:4] = 00 reg_cbusidle_pup_sel[1:0] = open (default) + */ + ret = mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL3_REG, 0x86); + if (ret < 0) { + pr_err("[ERROR] %s() - set MHL_TX_DISC_CTRL3_REG\n", __func__); + goto unhandled; + } + + /* change from CC to 8C to match 5K*/ + /*To meet CTS 3.3.72 spec*/ + ret = mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL4_REG, 0x8C); + if (ret < 0) { + pr_err("[ERROR] %s() - set MHL_TX_DISC_CTRL4_REG\n", __func__); + goto unhandled; + } + + /* Force upstream HPD to 0 when not in MHL mode */ + ret = mhl_tx_clear_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<5)); + if (ret < 0) { + pr_err("[ERROR] %s() - clear MHL_TX_INT_CTRL_REG\n", __func__); + goto unhandled; + } + ret = mhl_tx_set_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<4)); + if (ret < 0) { + pr_err("[ERROR] %s() - set MHL_TX_INT_CTRL_REG\n", __func__); + goto unhandled; + } + + /* Configure the interrupt as active high */ + ret = mhl_tx_clear_reg(sii9234, MHL_TX_INT_CTRL_REG, (1<<2) | (1<<1)); + if (ret < 0) { + pr_err("[ERROR] %s() - clear MHL_TX_INT_CTRL_REG\n", __func__); + goto unhandled; + } + + msleep(25); + + /* release usb_id switch */ + ret = mhl_tx_clear_reg(sii9234, MHL_TX_DISC_CTRL6_REG, USB_ID_OVR); + if (ret < 0) { + pr_err("[ERROR] %s() - clear MHL_TX_DISC_CTRL6_REG\n", + __func__); + goto unhandled; + } + + ret = sii9234_cbus_init(sii9234); + if (ret < 0) + goto unhandled; + ret = mhl_tx_write_reg(sii9234, MHL_TX_DISC_CTRL1_REG, 0x27); + if (ret < 0) + goto unhandled; + + /* Enable Auto soft reset on SCDT = 0*/ + ret = mhl_tx_write_reg(sii9234, 0x05, 0x04); + + if (ret < 0) + goto unhandled; + + /* HDMI Transcode mode enable*/ + ret = mhl_tx_write_reg(sii9234, 0x0D, 0x1C); + if (ret < 0) + goto unhandled; + + ret = mhl_tx_write_reg(sii9234, MHL_TX_INTR4_ENABLE_REG, + RGND_READY_MASK | CBUS_LKOUT_MASK | + MHL_DISC_FAIL_MASK | MHL_EST_MASK); + if (ret < 0) + goto unhandled; + + ret = mhl_tx_write_reg(sii9234, MHL_TX_INTR1_ENABLE_REG, + (1<<5) | (1<<6)); + if (ret < 0) + goto unhandled; + +/* this point is very importand before megsure RGND impedance*/ + force_usb_id_switch_open(sii9234); + ret = mhl_tx_clear_reg(sii9234, MHL_TX_DISC_CTRL4_REG, + (1<<7) | (1<<6) | (1<<5) | (1<<4)); + if (ret < 0) + goto unhandled; + ret = mhl_tx_clear_reg(sii9234, MHL_TX_DISC_CTRL5_REG, (1<<1) | (1<<0)); + if (ret < 0) + goto unhandled; + release_usb_id_switch_open(sii9234); +/*end of this*/ + pr_debug("sii9234: waiting for RGND measurement\n"); + sii9234_enable_irq(); + + /* SiI9244 Programmer's Reference Section 2.4.3 + * State : RGND Ready + */ + sii9234_mutex_unlock(&sii9234->lock); +#ifndef CONFIG_MHL_D3_SUPPORT + ret = wait_event_timeout(sii9234->wq, + ((sii9234->rgnd != RGND_UNKNOWN) || + mhl_state_is_error(sii9234->state)), + msecs_to_jiffies(T_WAIT_TIMEOUT_RGND_INT*1.5)); + + sii9234_mutex_lock(&sii9234->lock); + if (ret == 0 || mhl_state_is_error(sii9234->state)) + goto unhandled; + + if (sii9234->rgnd != RGND_1K) + goto unhandled; + sii9234_mutex_unlock(&sii9234->lock); +#endif + pr_debug("sii9234: waiting for detection\n"); + ret = wait_event_timeout(sii9234->wq, + sii9234->state != STATE_DISCONNECTED, + msecs_to_jiffies(T_WAIT_TIMEOUT_DISC_INT*2)); + sii9234_mutex_lock(&sii9234->lock); + if (ret == 0) { + pr_err("[ERROR] %s() - wait detection\n", __func__); + goto unhandled; + } + + if (sii9234->state == STATE_DISCOVERY_FAILED) { + handled = -1; + pr_err("[ERROR] %s() - state == STATE_DISCOVERY_FAILED\n", + __func__); + goto unhandled; + } + + if (mhl_state_is_error(sii9234->state)) + goto unhandled; + + sii9234_mutex_unlock(&sii9234->lock); + pr_info("sii9234: Established & start to moniter RSEN\n"); + /*CTS 3.3.14.3 Discovery;Sink Never Drives MHL+/- HIGH*/ + /*MHL SPEC 8.2.1.1.1;Transition SRC4-SRC7*/ + if (rsen_state_timer_out(sii9234) < 0) + return; + + sii9234->claimed = true; + + sii9234_mutex_lock(&sii9234->lock); + ret = cbus_write_reg(sii9234, + CBUS_INTR1_ENABLE_REG, + MSC_RESP_ABORT_MASK | + MSC_REQ_ABORT_MASK | + MSC_REQ_DONE_MASK | + MSC_MSG_RECD_MASK | + CBUS_DDC_ABORT_MASK); + if (ret < 0) + goto unhandled; + + ret = cbus_write_reg(sii9234, + CBUS_INTR2_ENABLE_REG, + WRT_STAT_RECD_MASK | + SET_INT_RECD_MASK); + if (ret < 0) + goto unhandled; + + sii9234_mutex_unlock(&sii9234->lock); +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD + ret = wait_event_timeout(sii9234->wq, + sii9234->dcap_ready_status, + msecs_to_jiffies(500)); + if (ret == 0) { + /*UNKNOWN*/ + sii9234->vbus_owner = 0; + pr_info("dcap_timeout err, dcap_staus:%d\n", + sii9234->dcap_ready_status); + } else { + /*SAMSUNG DEVICE_ID 0x1134:dongle, 0x1234:dock*/ + if (sii9234->devcap.device_id == SS_MHL_DONGLE_DEV_ID || + sii9234->devcap.device_id == SS_MHL_DOCK_DEV_ID) + sii9234->vbus_owner = sii9234->devcap.reserved_data; + else + sii9234->vbus_owner = 0; + } + pr_info("device_id:0x%4x, vbus_owner:%d\n", + sii9234->devcap.device_id, sii9234->vbus_owner); +#else + /*UNKNOWN*/ + sii9234->vbus_owner = 0; +#endif + /*send some data for VBUS SRC such a TA or USB or UNKNOWN*/ + if (sii9234->pdata->vbus_present) +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD + sii9234->pdata->vbus_present(true , sii9234->vbus_owner); +#else + sii9234->pdata->vbus_present(true); +#endif + + return; + +unhandled: + pr_info("sii9234: Detection failed"); + if (sii9234->state == STATE_DISCONNECTED) { + pr_cont(" (timeout)"); + mutex_unlock(&sii9234->lock); +#ifndef CONFIG_MHL_D3_SUPPORT + mhl_onoff_ex(0); +#endif + return; + } else if (sii9234->state == STATE_DISCOVERY_FAILED) + pr_cont(" (discovery failed)"); + else if (sii9234->state == STATE_CBUS_LOCKOUT) + pr_cont(" (cbus_lockout)"); + pr_cont("\n"); + + /*mhl spec: 8.3.3, if discovery failed, must retry discovering*/ + if ((sii9234->state == STATE_DISCOVERY_FAILED) && + (sii9234->rgnd == RGND_1K)) { + pr_cont("Discovery failed but RGND_1K impedence" + " restart detection_callback"); +#ifdef CONFIG_MHL_D3_SUPPORT + INIT_WORK(&sii9234->rgnd_work, goto_d3); + sii9234_disable_irq(); + + schedule_work(&sii9234->rgnd_work); +#else + INIT_WORK(&sii9234->redetect_work, sii9234_detection_callback); + sii9234_disable_irq(); + + if (sii9234->pdata->hw_reset) + sii9234->pdata->hw_reset(); + + schedule_work(&sii9234->redetect_work); +#endif + } + + sii9234_mutex_unlock(&sii9234->lock); + + return; +} + +static void sii9234_cancel_callback(void) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + + sii9234_mutex_lock(&sii9234->lock); + sii9234_power_down(sii9234); + sii9234_mutex_unlock(&sii9234->lock); +} + +static void save_cbus_pkt_to_buffer(struct sii9234_data *sii9234) +{ + int index; + + for (index = 0; index < CBUS_PKT_BUF_COUNT; index++) + if (sii9234->cbus_pkt_buf[index].status == false) + break; + + if (index == CBUS_PKT_BUF_COUNT) { + pr_debug("sii9234: Error save_cbus_pkt Buffer Full\n"); + index -= 1; /*adjust index*/ + } + + pr_debug("sii9234: save_cbus_pkt_to_buffer index = %d\n", index); + memcpy(&sii9234->cbus_pkt_buf[index], &sii9234->cbus_pkt, + sizeof(struct cbus_packet)); + sii9234->cbus_pkt_buf[index].status = true; +} +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD +static void cbus_command_response(struct sii9234_data *sii9234) +{ + u8 value, offset = 0; + + mutex_lock(&sii9234->cbus_lock); + pr_debug("sii9234: cbus_command_response\n"); + + switch (sii9234->cbus_pkt.command) { + case CBUS_MSC_MSG: + pr_debug("sii9234: cbus_command_response Received" + " ACK for CBUS_MSC_MSG\n"); +#ifdef CONFIG_SII9234_RCP + if (sii9234->cbus_pkt.data[0] == MSG_RCPE && + sii9234->cbus_pkt.data[1] == 0x01) { + sii9234->cbus_pkt.command = CBUS_IDLE; + mutex_unlock(&sii9234->cbus_lock); + cbus_command_request(sii9234, CBUS_MSC_MSG, MSG_RCPK, + sii9234->error_key); + return; + } +#endif + break; + case CBUS_WRITE_STAT: + pr_debug("sii9234: cbus_command_response" + "CBUS_WRITE_STAT\n"); + cbus_read_reg(sii9234, CBUS_MSC_FIRST_DATA_IN_REG, + &sii9234->cbus_pkt.data[0]); + break; + case CBUS_SET_INT: + pr_debug("sii9234: cbus_command_response CBUS_SET_INT\n"); + if (sii9234->cbus_pkt.offset == MHL_RCHANGE_INT && + sii9234->cbus_pkt.data[0] == MHL_INT_DSCR_CHG) { + /*Write burst final step... Req->GRT->Write->DSCR*/ + pr_debug("sii9234: MHL_RCHANGE_INT &" + "MHL_INT_DSCR_CHG\n"); + } else if (sii9234->cbus_pkt.offset == MHL_RCHANGE_INT && + sii9234->cbus_pkt.data[0] == MHL_INT_DCAP_CHG) { + pr_debug("sii9234: MHL_RCHANGE_INT &" + "MHL_INT_DCAP_CHG\n"); + sii9234->cbus_pkt.command = CBUS_IDLE; + mutex_unlock(&sii9234->cbus_lock); + cbus_command_request(sii9234, CBUS_WRITE_STAT, + MHL_STATUS_REG_CONNECTED_RDY, + MHL_STATUS_DCAP_READY); + return; + } + break; + case CBUS_WRITE_BURST: + pr_debug("sii9234: cbus_command_response" + "MHL_WRITE_BURST\n"); + sii9234->cbus_pkt.command = CBUS_IDLE; + mutex_unlock(&sii9234->cbus_lock); + cbus_command_request(sii9234, CBUS_SET_INT, + MHL_RCHANGE_INT, MHL_INT_DSCR_CHG); + return; + case CBUS_READ_DEVCAP: + pr_debug("sii9234: cbus_command_response" + " CBUS_READ_DEVCAP\n"); + cbus_read_reg(sii9234, CBUS_MSC_FIRST_DATA_IN_REG, + &value); + switch (sii9234->cbus_pkt.offset) { + case DEVCAP_MHL_VERSION: + sii9234->devcap.mhl_ver = value; + pr_debug("sii9234: MHL_VERSION: %X\n", value); + break; + case DEVCAP_DEV_CAT: + if (value & MHL_DEV_CATEGORY_POW_BIT) + pr_debug("sii9234: CAT=POWERED"); + else + pr_debug("sii9234: CAT=UNPOWERED"); + break; + case DEVCAP_ADOPTER_ID_H: + sii9234->devcap.adopter_id = (value & 0xFF) << 0x8; + pr_debug("sii9234: DEVCAP_ADOPTER_ID_H = %X\n", value); + break; + case DEVCAP_ADOPTER_ID_L: + sii9234->devcap.adopter_id |= value & 0xFF; + pr_debug("sii9234: DEVCAP_ADOPTER_ID_L = %X\n", value); + break; + case DEVCAP_VID_LINK_MODE: + sii9234->devcap.vid_link_mode = 0x3F & value; + pr_debug("sii9234: MHL_CAP_VID_LINK_MODE = %d\n", + sii9234->devcap.vid_link_mode); + break; + case DEVCAP_AUD_LINK_MODE: + sii9234->devcap.aud_link_mode = 0x03 & value; + pr_debug("sii9234: DEVCAP_AUD_LINK_MODE =%d\n", + sii9234->devcap.aud_link_mode); + break; + case DEVCAP_VIDEO_TYPE: + sii9234->devcap.video_type = 0x8F & value; + pr_debug("sii9234: DEVCAP_VIDEO_TYPE =%d\n", + sii9234->devcap.video_type); + break; + case DEVCAP_LOG_DEV_MAP: + sii9234->devcap.log_dev_map = value; + pr_debug("sii9234: DEVCAP_LOG_DEV_MAP =%d\n", + sii9234->devcap.log_dev_map); + break; + case DEVCAP_BANDWIDTH: + sii9234->devcap.bandwidth = value; + pr_debug("sii9234: DEVCAP_BANDWIDTH =%d\n", + sii9234->devcap.bandwidth); + break; + case DEVCAP_DEV_FEATURE_FLAG: + if ((value & MHL_FEATURE_RCP_SUPPORT) == 0) + pr_debug("sii9234: FEATURE_FLAG=RCP"); + + if ((value & MHL_FEATURE_RAP_SUPPORT) == 0) + pr_debug("sii9234: FEATURE_FLAG=RAP\n"); + + if ((value & MHL_FEATURE_SP_SUPPORT) == 0) + pr_debug("sii9234: FEATURE_FLAG=SP\n"); + break; + case DEVCAP_DEVICE_ID_H: + sii9234->devcap.device_id = (value & 0xFF) << 0x8; + pr_info("sii9234: DEVICE_ID_H=0x%x\n", value); + offset = DEVCAP_DEVICE_ID_L; + break; + case DEVCAP_DEVICE_ID_L: + sii9234->devcap.device_id |= value & 0xFF; + pr_info("sii9234: DEVICE_ID_L=0x%x\n", value); + break; + case DEVCAP_SCRATCHPAD_SIZE: + sii9234->devcap.scratchpad_size = value; + pr_debug("sii9234: DEVCAP_SCRATCHPAD_SIZE =%d\n", + sii9234->devcap.scratchpad_size); + break; + case DEVCAP_INT_STAT_SIZE: + sii9234->devcap.int_stat_size = value; + pr_debug("sii9234: DEVCAP_INT_STAT_SIZE =%d\n", + sii9234->devcap.int_stat_size); + break; + case DEVCAP_RESERVED: + pr_info("sii9234: DEVCAP_RESERVED : %d\n", value); + break; + case DEVCAP_DEV_STATE: + pr_debug("sii9234: DEVCAP_DEV_STATE\n"); + break; + default: + pr_debug("sii9234: DEVCAP DEFAULT\n"); + break; + } + + break; + default: + pr_debug("sii9234: error: cbus_command_response" + "cannot handle...\n"); + } + + sii9234->cbus_pkt.command = CBUS_IDLE; + mutex_unlock(&sii9234->cbus_lock); + + if (offset) + cbus_command_request(sii9234, CBUS_READ_DEVCAP, + offset, 0x00); +} +#endif +#ifdef DEBUG_MHL +static void cbus_command_response_dbg_msg(struct sii9234_data *sii9234, + u8 index) +{ + /*Added to debugcbus_pkt_buf*/ + pr_info("sii9234: cbus_pkt_buf[index].command = %d," + "sii9234->cbus_pkt.command = %d\n", + sii9234->cbus_pkt_buf[index].command, + sii9234->cbus_pkt.command); + pr_info("sii9234: cbus_pkt_buf[index].data[0] = %d," + "sii9234->cbus_pkt.data[0] = %d\n", + sii9234->cbus_pkt_buf[index].data[0], + sii9234->cbus_pkt.data[0]); + + pr_info("sii9234: cbus_pkt_buf[index].data[1] = %d," + "sii9234->cbus_pkt.data[1] = %d\n", + sii9234->cbus_pkt_buf[index].data[1], + sii9234->cbus_pkt.data[1]); + pr_info("sii9234: cbus_pkt_buf[index].offset = %d," + "sii9234->cbus_pkt.offset = %d\n", + sii9234->cbus_pkt_buf[index].offset, + sii9234->cbus_pkt.offset); +} +#endif +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD +static void cbus_command_response_all(struct sii9234_data *sii9234) +{ + u8 index; + struct cbus_packet cbus_pkt_process_buf[CBUS_PKT_BUF_COUNT]; + pr_debug("sii9234: cbus_command_response_all for All requests\n"); + + /*take bkp of cbus_pkt_buf*/ + memcpy(cbus_pkt_process_buf, sii9234->cbus_pkt_buf, + sizeof(cbus_pkt_process_buf)); + + /*clear cbus_pkt_buf to hold next request*/ + memset(sii9234->cbus_pkt_buf, 0x00, sizeof(sii9234->cbus_pkt_buf)); + + /*process all previous requests*/ + for (index = 0; index < CBUS_PKT_BUF_COUNT; index++) { + if (cbus_pkt_process_buf[index].status == true) { + memcpy(&sii9234->cbus_pkt, &cbus_pkt_process_buf[index], + sizeof(struct cbus_packet)); + cbus_command_response(sii9234); +#ifdef DEBUG_MHL + /*print cbus_cmd messg*/ + cbus_command_response_dbg_msg(sii9234, index); +#endif + } + } +} +#endif +static bool cbus_command_request(struct sii9234_data *sii9234, + enum cbus_command command, u8 offset, u8 data) +{ + u8 start_bit = 0; + + mutex_lock(&sii9234->cbus_lock); + if (sii9234->state != STATE_ESTABLISHED) { + pr_debug("sii9234: cbus_command_request without establish\n"); + pr_debug("sii9234: ==> command:0x%X, offset:0x%X", + command, offset); + mutex_unlock(&sii9234->cbus_lock); + return -EINVAL; + } + + sii9234->cbus_pkt.command = command; + sii9234->cbus_pkt.offset = offset; + + if (command == CBUS_MSC_MSG) + sii9234->cbus_pkt.data[0] = offset; + else + sii9234->cbus_pkt.data[0] = data; + + pr_debug("sii9234: cbus_command_request Sending MSC_MSG SubCommand=%d" + ",key-code=%d\n", sii9234->cbus_pkt.offset, + sii9234->cbus_pkt.data[0]); + + cbus_write_reg(sii9234, CBUS_MSC_OFFSET_REG, + sii9234->cbus_pkt.offset); + cbus_write_reg(sii9234, CBUS_MSC_FIRST_DATA_OUT_REG, + sii9234->cbus_pkt.data[0]); + + switch (sii9234->cbus_pkt.command) { + case CBUS_SET_INT: + pr_debug("sii9234: cbus_command_request" + "CBUS_SET_INT\n"); + start_bit = START_BIT_WRITE_STAT_INT; + break; + case CBUS_WRITE_STAT: + pr_debug("sii9234: cbus_command_request" + "CBUS_WRITE_STAT\n"); + start_bit = START_BIT_WRITE_STAT_INT; + break; + case CBUS_MSC_MSG: + /*treat offset as data[0] in case of CBUS_MSC_MSG*/ + sii9234->cbus_pkt.data[0] = offset; + sii9234->cbus_pkt.data[1] = data; + pr_debug("sii9234: cbus_command_request CBUS_MSC_MSG" + "SubCommand=%d,key-code=%d\n", + sii9234->cbus_pkt.data[0], + sii9234->cbus_pkt.data[1]); + + cbus_write_reg(sii9234, CBUS_MSC_SECOND_DATA_OUT_REG, + sii9234->cbus_pkt.data[1]); + cbus_write_reg(sii9234, CBUS_MSC_OFFSET_REG, + sii9234->cbus_pkt.command); + start_bit = START_BIT_MSC_MSG; + break; + case CBUS_READ_DEVCAP: + pr_debug("sii9234: cbus_command_request CBUS_READ_DEVCAP\n"); + start_bit = START_BIT_READ_DEVCAP; + break; + case CBUS_WRITE_BURST: + pr_debug("sii9234: cbus_command_request CBUS_WRITE_BURST\n"); + start_bit = START_BIT_WRITE_BURST; + break; + case CBUS_GET_STATE: + case CBUS_GET_VENDOR_ID: + case CBUS_SET_HPD: + case CBUS_CLR_HPD: + case CBUS_GET_MSC_ERR_CODE: + case CBUS_GET_SC3_ERR_CODE: + case CBUS_GET_SC1_ERR_CODE: + case CBUS_GET_DDC_ERR_CODE: + cbus_write_reg(sii9234, CBUS_MSC_OFFSET_REG, + sii9234->cbus_pkt.command); + start_bit = START_BIT_MSC_RESERVED; + break; + default: + pr_debug("sii9234: error send cbus command fail\n"); + mutex_unlock(&sii9234->cbus_lock); + return false; + } + + pr_debug("sii9234: startbit = %d\n", start_bit); + cbus_write_reg(sii9234, CBUS_MSC_COMMAND_START_REG, start_bit); + save_cbus_pkt_to_buffer(sii9234); + mutex_unlock(&sii9234->cbus_lock); + + return true; +} + +static u8 sii9234_tmds_control(struct sii9234_data *sii9234, bool enable) +{ + u8 ret; + + if (enable) { +#ifdef __CONFIG_RSEN_LOST_PATCH__ + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL2_REG, 0xFC); + if (ret < 0) + return ret; +#endif + ret = mhl_tx_set_reg(sii9234, MHL_TX_TMDS_CCTRL, (1<<4)); + if (ret < 0) + return ret; + pr_debug("sii9234: MHL HPD High, enabled TMDS\n"); + ret = mhl_tx_set_reg(sii9234, MHL_TX_INT_CTRL_REG, + (1<<4) | (1<<5)); + if (ret < 0) + return ret; + } else { + ret = mhl_tx_clear_reg(sii9234, MHL_TX_TMDS_CCTRL, (1<<4)); + if (ret < 0) + return ret; + pr_debug("sii9234 MHL HPD low, disabled TMDS\n"); + ret = mhl_tx_clear_reg(sii9234, MHL_TX_INT_CTRL_REG, + (1<<4) | (1<<5)); + if (ret < 0) + return ret; +#ifdef __CONFIG_RSEN_LOST_PATCH__ + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL2_REG, 0xC0); + if (ret < 0) + return ret; +#endif + } + + return ret; +} + +static irqreturn_t sii9234_irq_thread(int irq, void *data) +{ + struct sii9234_data *sii9234 = data; + int ret; + u8 intr1, intr4, value = 0x0; + u8 intr1_en, intr4_en = 0x0; + bool release_otg = false; + u8 cbus_intr1, cbus_intr2 = 0x0; + u8 mhl_poweroff = 0; + void (*cbus_resp_callback)(struct sii9234_data *) = NULL; + + if (!sii9234) { + pr_err("%s: sii9234 is NULL & skipp this rutine\n", __func__); + return IRQ_HANDLED; + } + + d3_mode_rgnd_state = 1; + msleep(30); + sii9234_mutex_lock(&sii9234->lock); + + ret = mhl_tx_read_reg(sii9234, MHL_TX_INTR1_REG, &intr1); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d read MHL_TX_INTR1_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + ret = mhl_tx_read_reg(sii9234, MHL_TX_INTR4_REG, &intr4); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d read MHL_TX_INTR4_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + + ret = mhl_tx_read_reg(sii9234, MHL_TX_INTR1_ENABLE_REG, &intr1_en); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d read MHL_TX_INTR1_ENABLE_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + ret = mhl_tx_read_reg(sii9234, MHL_TX_INTR4_ENABLE_REG, &intr4_en); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d read MHL_TX_INTR4_ENABLE_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + + ret = cbus_read_reg(sii9234, CBUS_INT_STATUS_1_REG, &cbus_intr1); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d read CBUS_INT_STATUS_1_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + ret = cbus_read_reg(sii9234, CBUS_INT_STATUS_2_REG, &cbus_intr2); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d read CBUS_INT_STATUS_2_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + + pr_debug("sii9234: irq %02x/%02x %02x/%02x %02x/%02x\n", + intr1, intr1_en, + intr4, intr4_en, + cbus_intr1, cbus_intr2); + + if (intr4 & RGND_READY_INT) { +#ifdef CONFIG_MHL_D3_SUPPORT + if (sii9234_callback_sched == 0) { + pr_info("rgnd interrupt debug\n"); + INIT_WORK(&sii9234->rgnd_work, + sii9234_detection_callback); + sii9234_disable_irq(); + if (sii9234->pdata->hw_reset) + sii9234->pdata->hw_reset(); + schedule_work(&sii9234->rgnd_work); + goto err_exit; + } +#endif + ret = mhl_tx_read_reg(sii9234, MHL_TX_STAT2_REG, &value); + if (ret < 0) { + dev_err(&sii9234->pdata->mhl_tx_client->dev, + "STAT2 reg, err %d\n", ret); + goto err_exit; + } + + switch (value & RGND_INTP_MASK) { + case RGND_INTP_OPEN: + pr_info("sii9234: RGND Open\n"); + sii9234->rgnd = RGND_OPEN; + break; + case RGND_INTP_1K: + pr_info("sii9234: RGND 1K\n"); + /* After applying RGND patch, there is some issue + about discovry failure + This point is add to fix that problem*/ + ret = mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL4_REG, + 0x8C); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d write MHL_TX_DISC_CTRL4_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + ret = mhl_tx_write_reg(sii9234, + MHL_TX_DISC_CTRL5_REG, 0x77); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d write MHL_TX_DISC_CTRL5_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + ret = mhl_tx_set_reg(sii9234, + MHL_TX_DISC_CTRL6_REG, 0x05); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d write MHL_TX_DISC_CTRL6_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + usleep_range(T_SRC_VBUS_CBUS_TO_STABLE * USEC_PER_MSEC, + T_SRC_VBUS_CBUS_TO_STABLE * USEC_PER_MSEC); + /* end of this*/ + pr_debug("sii9234: %s() send wakeup pulse\n", __func__); + ret = mhl_send_wake_pulses(sii9234); + if (ret < 0) { + pr_err("[ERROR] sii9234: sending wake pulses error\n"); + goto err_exit; + } + sii9234->rgnd = RGND_1K; + break; + + case RGND_INTP_2K: + pr_info("sii9234: RGND 2K\n"); + sii9234->rgnd = RGND_2K; + break; + case RGND_INTP_SHORT: + pr_info("sii9234: RGND Short\n"); + sii9234->rgnd = RGND_SHORT; + break; + }; + + if (sii9234->rgnd != RGND_1K) { + mhl_poweroff = 1; /*Power down mhl chip */ + goto err_exit; + } + } + + if (intr4 & CBUS_LKOUT_INT) { /* 1<<4 */ + pr_debug("%s(): CBUS Lockout Interrupt\n", __func__); + sii9234->state = STATE_CBUS_LOCKOUT; + } + + if (intr4 & MHL_DISC_FAIL_INT) { /* 1<<3 */ + printk(KERN_ERR "[ERROR] %s(): MHL_DISC_FAIL_INT\n", __func__); + sii9234->state = STATE_DISCOVERY_FAILED; + goto err_exit; + } + + if (intr4 & MHL_EST_INT) { + pr_debug("sii9234: mhl est interrupt %d\n", value); + + /* discovery override */ + ret = mhl_tx_write_reg(sii9234, MHL_TX_MHLTX_CTL1_REG, 0x10); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d write MHL_TX_MHLTX_CTRL1_REG failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + + /* increase DDC translation layer timer (byte mode) */ + ret = cbus_write_reg(sii9234, 0x07, 0x32); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d cbus_write_reg failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + ret = cbus_set_reg(sii9234, 0x44, 1 << 1); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d cbus_set_reg failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + + /* Keep the discovery enabled. Need RGND interrupt */ + ret = mhl_tx_set_reg(sii9234, MHL_TX_DISC_CTRL1_REG, (1<<0)); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d mhl_tx_set_reg failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + + sii9234->state = STATE_ESTABLISHED; +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + cbus_command_request(sii9234, CBUS_SET_INT, + MHL_RCHANGE_INT, MHL_INT_DCAP_CHG); +#else + sii9234_enqueue_msc_work(sii9234, CBUS_SET_INT, + MHL_RCHANGE_INT, MHL_INT_DCAP_CHG, 0x0); +#endif + + ret = mhl_tx_write_reg(sii9234, MHL_TX_INTR1_ENABLE_REG, + RSEN_CHANGE_INT_MASK | HPD_CHANGE_INT_MASK); + } + + if (intr1 & HPD_CHANGE_INT) { + ret = cbus_read_reg(sii9234, MSC_REQ_ABORT_REASON_REG, &value); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s():%d cbus_read_reg failed !\n", + __func__, __LINE__); + goto i2c_error_exit; + } + + if (value & SET_HPD_DOWNSTREAM) { + pr_info("%s() hpd high\n", __func__); + /* Downstream HPD High */ + + /* Do we need to send HPD upstream using + * Register 0x79(page0)? Is HPD need to be overriden?? + * TODO: See if we need code for overriding HPD OUT + * as per Page 0,0x79 Register + */ + sii9234->mhl_status_value.sink_hpd = true; +#ifdef __CONFIG_USE_TIMER__ + if (cbus_command_abort_state == 1) { + pr_info("cbus_command_mod_timer\n"); + mod_timer(&sii9234->cbus_command_timer, + jiffies + 2*HZ); + cbus_command_abort_state = 0; + } else +#endif +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + cbus_command_request(sii9234, CBUS_WRITE_STAT, + CBUS_LINK_CONTROL_2_REG, + sii9234->mhl_status_value.linkmode); +#else + sii9234_enqueue_msc_work(sii9234, CBUS_WRITE_STAT, + CBUS_LINK_CONTROL_2_REG, + sii9234->mhl_status_value.linkmode, 0x0); +#endif + /* Enable TMDS */ + sii9234_tmds_control(sii9234, true); + /*turn on&off hpd festure for only QCT HDMI*/ + mhl_hpd_handler(true); + + } else { + pr_info("sii9234: hpd low\n"); + /*Downstream HPD Low*/ + + /* Similar to above comments. + * TODO:Do we need to override HPD OUT value + * and do we need to disable TMDS here? + */ + sii9234->mhl_status_value.sink_hpd = false; + /* Disable TMDS */ + sii9234_tmds_control(sii9234, false); + } + } + + if (intr1 & RSEN_CHANGE_INT) { + /* work_around code to handle worng interrupt*/ + if (sii9234->rgnd != RGND_1K) { + pr_err("[ERROR] sii9234: Err RSEN_HIGH without RGND_1K" + "rgnd=%d\n", sii9234->rgnd); + goto err_exit2; + } + ret = mhl_tx_read_reg(sii9234, MHL_TX_SYSSTAT_REG, &value); + if (ret < 0) { + pr_err("[ERROR] sii9234: MHL_TX_SYSSTAT_REG read error\n"); + goto err_exit2; + } + sii9234->rsen = value & RSEN_STATUS; + + if (value & RSEN_STATUS) { + pr_info("%s(): MHL cable connected.. RSEN High\n", + __func__); + } else { + pr_info("%s(): RSEN lost -\n", __func__); + /* Once RSEN loss is confirmed,we need to check + * based on cable status and chip power status,whether + * it is SINK Loss(HDMI cable not connected, TV Off) + * or MHL cable disconnection + * TODO: Define the below mhl_disconnection() + */ +#ifdef __CONFIG_USE_TIMER__ + del_timer(&sii9234->cbus_command_timer); +#endif + msleep(T_SRC_RXSENSE_DEGLITCH); + ret = mhl_tx_read_reg(sii9234, MHL_TX_SYSSTAT_REG, + &value); + if (ret < 0) { + printk(KERN_ERR + "[ERROR] %s() read MHL_TX_SYSSTAT_REG\n", + __func__); + goto i2c_error_exit; + } + pr_cont(" sys_stat: %x\n", value); + + if ((value & RSEN_STATUS) == 0) { + printk(KERN_INFO + "%s() RSEN Really LOW ~\n", __func__); + /*To meet CTS 3.3.22.2 spec*/ + sii9234_tmds_control(sii9234, false); + force_usb_id_switch_open(sii9234); + release_usb_id_switch_open(sii9234); + mhl_poweroff = 1; /*Power down mhl chip */ + goto err_exit; + } else + pr_info("sii9234: RSEN recovery ~\n"); + } + } + + /* + * Process CBUS interrupts only when MHL connection has been + * established + */ + if (sii9234->state == STATE_ESTABLISHED) { + + if (cbus_intr1 & MSC_RESP_ABORT) + cbus_resp_abort_error(sii9234); + + if (cbus_intr1 & MSC_REQ_ABORT) { +#ifdef __CONFIG_USE_TIMER__ + cbus_write_reg(sii9234, + CBUS_INTR1_ENABLE_REG, 0); + cbus_req_abort_error(sii9234); + cbus_write_reg(sii9234, CBUS_INTR1_ENABLE_REG, 0xFF); + cbus_command_abort_state = 1; +#else + cbus_req_abort_error(sii9234); +#endif + } + if ((cbus_intr1 & CBUS_DDC_ABORT) || + (cbus_intr1 & MSC_RESP_ABORT)) { + pr_debug("sii9234: CBUS DDC abort\n"); + if (cbus_ddc_abort_error(sii9234)) { + if (sii9234->claimed == true) + release_otg = true; + sii9234_power_down(sii9234); + } + } + + if (cbus_intr1 & MSC_REQ_DONE) { + pr_debug("sii9234: CBUS cmd ACK Received\n"); +#ifndef CONFIG_MHL_NEW_CBUS_MSC_CMD + cbus_resp_callback = cbus_command_response_all; +#else + complete(&sii9234->msc_complete); +#endif + } +#ifdef CONFIG_SII9234_RCP + if (cbus_intr1 & MSC_MSG_RECD) { + pr_debug("sii9234: MSC MSG Received\n"); + cbus_handle_msc_msg(sii9234); + } +#endif + + /* ignore WRT_STAT_RECD interrupt when we get HPD CHANGE */ + if (cbus_intr2 & WRT_STAT_RECD && intr1 == 0) + cbus_handle_wrt_stat_recd(sii9234); + + if (cbus_intr2 & SET_INT_RECD) + cbus_handle_set_int_recd(sii9234); + } + +err_exit: + pr_debug("sii9234: wake_up\n"); + wake_up(&sii9234->wq); +err_exit2: + ret = mhl_tx_write_reg(sii9234, MHL_TX_INTR1_REG, intr1); + if (ret < 0) + goto i2c_error_exit; + ret = mhl_tx_write_reg(sii9234, MHL_TX_INTR4_REG, intr4); + if (ret < 0) + goto i2c_error_exit; + + ret = cbus_write_reg(sii9234, CBUS_INT_STATUS_1_REG, cbus_intr1); + if (ret < 0) + goto i2c_error_exit; + ret = cbus_write_reg(sii9234, CBUS_INT_STATUS_2_REG, cbus_intr2); + if (ret < 0) + goto i2c_error_exit; + + sii9234_mutex_unlock(&sii9234->lock); + + if (cbus_resp_callback) + cbus_resp_callback(sii9234); + + if (mhl_poweroff) { +#ifdef CONFIG_MHL_D3_SUPPORT + if (sii9234_callback_sched != 0) { + sii9234_disable_irq(); + goto_d3(NULL); + } +#else + mhl_onoff_ex(0); +#endif + } + return IRQ_HANDLED; +i2c_error_exit: + sii9234_mutex_unlock(&sii9234->lock); + pr_info("%s(): i2c error exit\n", __func__); + pr_debug("sii9234: wake_up\n"); + wake_up(&sii9234->wq); + return IRQ_HANDLED; +} +static void mhl_cbus_command_timer(unsigned long data) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + schedule_work(&sii9234->mhl_cbus_write_stat_work); +} +#ifdef MHL_SS_FACTORY +#define SII_ID 0x92 +static ssize_t sysfs_check_mhl_command(struct class *class, struct class_attribute *attr, + char *buf) + +{ + int size; + u8 sii_id = 0; + struct sii9234_data *sii9234 = dev_get_drvdata(sii9244_mhldev); + + if (sii9234->pdata->hw_onoff) + sii9234->pdata->hw_onoff(1); + + if (sii9234->pdata->hw_reset) + sii9234->pdata->hw_reset(); + + mhl_tx_read_reg(sii9234, MHL_TX_IDH_REG, &sii_id); + pr_info("sel_show sii_id: %X\n", sii_id); + + if (sii9234->pdata->hw_onoff) + sii9234->pdata->hw_onoff(0); + + size = snprintf(buf, 10, "%d\n", sii_id == SII_ID ? 1 : 0); + + return size; + +} + +static CLASS_ATTR(test_result, 0664 , sysfs_check_mhl_command, NULL); +#endif /*MHL_SS_FACTORY*/ + +#ifdef CONFIG_PM +static int sii9234_mhl_tx_suspend(struct device *dev) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(dev); + + /*set config_gpio for mhl*/ + if (sii9234->pdata->gpio_cfg) + sii9234->pdata->gpio_cfg(); + + return 0; +} + +static int sii9234_mhl_tx_resume(struct device *dev) +{ + struct sii9234_data *sii9234 = dev_get_drvdata(dev); + + /*set config_gpio for mhl*/ + if (sii9234->pdata->gpio_cfg) + sii9234->pdata->gpio_cfg(); + + return 0; +} + +static const struct dev_pm_ops sii9234_pm_ops = { + .suspend = sii9234_mhl_tx_suspend, + .resume = sii9234_mhl_tx_resume, +}; +#endif + +static int __devinit sii9234_mhl_tx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct sii9234_data *sii9234; +#ifdef CONFIG_SII9234_RCP + struct input_dev *input; +#endif + int ret; +#ifdef MHL_SS_FACTORY + struct class *sec_mhl; +#endif + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + sii9234 = kzalloc(sizeof(struct sii9234_data), GFP_KERNEL); + if (!sii9234) { + dev_err(&client->dev, "failed to allocate driver data\n"); + return -ENOMEM; + } +#ifdef CONFIG_SII9234_RCP + input = input_allocate_device(); + if (!input) { + dev_err(&client->dev, "failed to allocate input device.\n"); + ret = -ENOMEM; + goto err_exit0; + } +#endif + + sii9234->pdata = client->dev.platform_data; + if (!sii9234->pdata) { + ret = -EINVAL; + goto err_exit1; + } + sii9234->pdata->mhl_tx_client = client; + + init_waitqueue_head(&sii9234->wq); + mutex_init(&sii9234->lock); + mutex_init(&sii9234->cbus_lock); + INIT_WORK(&sii9234->mhl_cbus_write_stat_work, + mhl_cbus_write_stat_worker); + i2c_set_clientdata(client, sii9234); + client->irq = sii9234->pdata->get_irq(); + sii9244_mhldev = &client->dev; + ret = request_threaded_irq(client->irq, NULL, sii9234_irq_thread, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "sii9234", sii9234); + if (ret < 0) + goto err_exit1; + + atomic_set(&sii9234->is_irq_enabled, false); + disable_irq(client->irq); + if (sii9234->pdata->swing_level == 0) + sii9234->pdata->swing_level = 0xEB; +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD + sii9234_msc_wq = create_singlethread_workqueue("sii9234_msc_wq"); + if (!sii9234_msc_wq) { + printk(KERN_ERR + "[ERROR] %s() workqueue create fail\n", __func__); + ret = -ENOMEM; + goto err_class; + } + INIT_WORK(&sii9234->msc_work, sii9234_process_msc_work); +#endif + +#ifdef MHL_SS_FACTORY + pr_info("create mhl sysfile\n"); + + sec_mhl = class_create(THIS_MODULE, "mhl"); + if (IS_ERR(sec_mhl)) { + pr_err("Failed to create class(sec_mhl)!\n"); + goto err_class; + } + + ret = class_create_file(sec_mhl, &class_attr_test_result); + if (ret) { + pr_err("[ERROR] Failed to create device file in sysfs entries!\n"); + goto err_exit2a; + } +#endif +#ifdef CONFIG_MHL_SWING_LEVEL + pr_info("create mhl sysfile\n"); + + ret = class_create_file(sec_mhl, &class_attr_swing); + if (ret) { + pr_err("[ERROR] failed to create swing sysfs file\n"); + goto err_exit2b; + } +#endif + + sii9234->cbus_pkt.command = CBUS_IDLE; + sii9234->cbus_pkt.offset = DEVCAP_DEV_STATE; + init_timer(&sii9234->cbus_command_timer); + sii9234->cbus_command_timer.function = + mhl_cbus_command_timer; + sii9234->cbus_command_timer.data = (unsigned int)NULL; + sii9234->cbus_command_timer.expires = 0xffffffffL; + add_timer(&sii9234->cbus_command_timer); +#ifdef CONFIG_SII9234_RCP + /* indicate that we generate key events */ + set_bit(EV_KEY, input->evbit); + bitmap_fill(input->keybit, KEY_MAX); + + sii9234->input_dev = input; + input_set_drvdata(input, sii9234); + input->name = "sii9234_rcp"; + input->id.bustype = BUS_I2C; + + ret = input_register_device(input); + if (ret < 0) { + dev_err(&client->dev, "fail to register input device\n"); + goto err_exit2c; + } +#endif + + return 0; + +err_exit2c: +#ifdef CONFIG_MHL_SWING_LEVEL + class_remove_file(sec_mhl, &class_attr_swing); +err_exit2b: +#ifdef MHL_SS_FACTORY + class_destroy(sec_mhl); +#endif +#endif +err_exit2a: +#if defined(MHL_SS_FACTORY) || defined(CONFIG_MHL_SWING_LEVEL) + class_destroy(sec_mhl); +#endif +err_class: + free_irq(client->irq, sii9234); +err_exit1: +#ifdef CONFIG_SII9234_RCP + input_free_device(input); +#endif +err_exit0: + kfree(sii9234); + return ret; +} + +static int __devinit sii9234_tpi_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sii9234_platform_data *pdata = client->dev.platform_data; + if (!pdata) + return -EINVAL; + pdata->tpi_client = client; + return 0; +} + +static int __devinit sii9234_hdmi_rx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sii9234_platform_data *pdata = client->dev.platform_data; + if (!pdata) + return -EINVAL; + + pdata->hdmi_rx_client = client; + return 0; +} + +static int __devinit sii9234_cbus_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sii9234_platform_data *pdata = client->dev.platform_data; + if (!pdata) + return -EINVAL; + + pdata->cbus_client = client; + return 0; +} + +static int __devexit sii9234_mhl_tx_remove(struct i2c_client *client) +{ + return 0; +} + +static int __devexit sii9234_tpi_remove(struct i2c_client *client) +{ + return 0; +} + +static int __devexit sii9234_hdmi_rx_remove(struct i2c_client *client) +{ + return 0; +} + +static int __devexit sii9234_cbus_remove(struct i2c_client *client) +{ + return 0; +} + +static const struct i2c_device_id sii9234_mhl_tx_id[] = { + {"sii9234_mhl_tx", 0}, + {} +}; + +static const struct i2c_device_id sii9234_tpi_id[] = { + {"sii9234_tpi", 0}, + {} +}; + +static const struct i2c_device_id sii9234_hdmi_rx_id[] = { + {"sii9234_hdmi_rx", 0}, + {} +}; + +static const struct i2c_device_id sii9234_cbus_id[] = { + {"sii9234_cbus", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, sii9234_mhl_tx_id); +MODULE_DEVICE_TABLE(i2c, sii9234_tpi_id); +MODULE_DEVICE_TABLE(i2c, sii9234_hdmi_rx_id); +MODULE_DEVICE_TABLE(i2c, sii9234_cbus_id); + +static struct i2c_driver sii9234_mhl_tx_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sii9234_mhl_tx", +#ifdef CONFIG_PM + .pm = &sii9234_pm_ops, +#endif + }, + .id_table = sii9234_mhl_tx_id, + .probe = sii9234_mhl_tx_i2c_probe, + .remove = __devexit_p(sii9234_mhl_tx_remove), + .command = NULL, +}; + +static struct i2c_driver sii9234_tpi_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sii9234_tpi", + }, + .id_table = sii9234_tpi_id, + .probe = sii9234_tpi_i2c_probe, + .remove = __devexit_p(sii9234_tpi_remove), +}; + +static struct i2c_driver sii9234_hdmi_rx_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sii9234_hdmi_rx", + }, + .id_table = sii9234_hdmi_rx_id, + .probe = sii9234_hdmi_rx_i2c_probe, + .remove = __devexit_p(sii9234_hdmi_rx_remove), +}; + +static struct i2c_driver sii9234_cbus_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sii9234_cbus", + }, + .id_table = sii9234_cbus_id, + .probe = sii9234_cbus_i2c_probe, + .remove = __devexit_p(sii9234_cbus_remove), +}; + +static int __init sii9234_init(void) +{ + int ret; + + ret = i2c_add_driver(&sii9234_mhl_tx_i2c_driver); + if (ret < 0) + return ret; + + ret = i2c_add_driver(&sii9234_tpi_i2c_driver); + if (ret < 0) + goto err_exit1; + + ret = i2c_add_driver(&sii9234_hdmi_rx_i2c_driver); + if (ret < 0) + goto err_exit2; + + ret = i2c_add_driver(&sii9234_cbus_i2c_driver); + if (ret < 0) + goto err_exit3; + + return 0; + +err_exit3: + i2c_del_driver(&sii9234_hdmi_rx_i2c_driver); +err_exit2: + i2c_del_driver(&sii9234_tpi_i2c_driver); +err_exit1: + i2c_del_driver(&sii9234_mhl_tx_i2c_driver); + pr_err("i2c_add_driver fail\n"); + return ret; +} + +static void __exit sii9234_exit(void) +{ + i2c_del_driver(&sii9234_cbus_i2c_driver); + i2c_del_driver(&sii9234_hdmi_rx_i2c_driver); + i2c_del_driver(&sii9234_tpi_i2c_driver); + i2c_del_driver(&sii9234_mhl_tx_i2c_driver); +} + +module_init(sii9234_init); +module_exit(sii9234_exit); diff --git a/drivers/video/msm/mhl_v2/sii9234_driver.h b/drivers/video/msm/mhl_v2/sii9234_driver.h new file mode 100644 index 00000000000..a36c83c5069 --- /dev/null +++ b/drivers/video/msm/mhl_v2/sii9234_driver.h @@ -0,0 +1,517 @@ +/* + * opyright (C) 2011 Samsung Electronics + * + * Authors: Adam Hampson + * Erik Gilling + * + * Additional contributions by : Shankar Bandal + * Dharam Kumar + * + * 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 _SII9234_DRIVER_H_ +#define _SII9234_DRIVER_H_ + +#ifndef CONFIG_SII9234_RCP +#define CONFIG_SII9234_RCP 1 +#include +#endif + +/*Flag for MHL Factory test*/ +#define MHL_SS_FACTORY 1 + + +#define T_WAIT_TIMEOUT_RGND_INT 2000 +#define T_WAIT_TIMEOUT_DISC_INT 1000 +#define T_WAIT_TIMEOUT_RSEN_INT 200 + +#define T_SRC_VBUS_CBUS_TO_STABLE 200 +#define T_SRC_WAKE_PULSE_WIDTH_1 19 +#define T_SRC_WAKE_PULSE_WIDTH_2 60 +#define T_SRC_WAKE_TO_DISCOVER 500 +#define T_SRC_VBUS_CBUS_T0_STABLE 500 + +#define T_SRC_CBUS_FLOAT 100 +#define T_HPD_WIDTH 100 +#define T_SRC_RXSENSE_DEGLITCH 110 +#define T_SRC_CBUS_DEGLITCH 2 + +/* MHL TX Addr 0x72 Registers */ +#define MHL_TX_IDL_REG 0x02 +#define MHL_TX_IDH_REG 0x03 +#define MHL_TX_REV_REG 0x04 +#define MHL_TX_SRST 0x05 +#define MHL_TX_INTR1_REG 0x71 +#define MHL_TX_INTR2_REG 0x72 /* Not Documented */ +#define MHL_TX_INTR3_REG 0x73 /* Not Documented */ +#define MHL_TX_INTR4_REG 0x74 +#define MHL_TX_INTR1_ENABLE_REG 0x75 +#define MHL_TX_INTR2_ENABLE_REG 0x76 /* Not Documented */ +#define MHL_TX_INTR3_ENABLE_REG 0x77 /* Not Documented */ +#define MHL_TX_INTR4_ENABLE_REG 0x78 +#define MHL_TX_INT_CTRL_REG 0x79 +#define MHL_TX_TMDS_CCTRL 0x80 + +#define MHL_TX_DISC_CTRL1_REG 0x90 +#define MHL_TX_DISC_CTRL2_REG 0x91 +#define MHL_TX_DISC_CTRL3_REG 0x92 +#define MHL_TX_DISC_CTRL4_REG 0x93 + +#define MHL_TX_DISC_CTRL5_REG 0x94 +#define MHL_TX_DISC_CTRL6_REG 0x95 +#define MHL_TX_DISC_CTRL7_REG 0x96 +#define MHL_TX_DISC_CTRL8_REG 0x97 +#define MHL_TX_STAT1_REG 0x98 +#define MHL_TX_STAT2_REG 0x99 + +#define MHL_TX_MHLTX_CTL1_REG 0xA0 +#define MHL_TX_MHLTX_CTL2_REG 0xA1 +#define MHL_TX_MHLTX_CTL4_REG 0xA3 +#define MHL_TX_MHLTX_CTL6_REG 0xA5 +#define MHL_TX_MHLTX_CTL7_REG 0xA6 + +/* MHL TX SYS STAT Registers */ +#define MHL_TX_SYSSTAT_REG 0x09 + +/* MHL TX SYS STAT Register Bits */ +#define RSEN_STATUS (1<<2) + +/* MHL TX INTR4 Register Bits */ +#define RGND_READY_INT (1<<6) +#define VBUS_LOW_INT (1<<5) +#define CBUS_LKOUT_INT (1<<4) +#define MHL_DISC_FAIL_INT (1<<3) +#define MHL_EST_INT (1<<2) + +/* MHL TX INTR4_ENABLE 0x78 Register Bits */ +#define RGND_READY_MASK (1<<6) +#define CBUS_LKOUT_MASK (1<<4) +#define MHL_DISC_FAIL_MASK (1<<3) +#define MHL_EST_MASK (1<<2) + +/* MHL TX INTR1 Register Bits*/ +#define HPD_CHANGE_INT (1<<6) +#define RSEN_CHANGE_INT (1<<5) + +/* MHL TX INTR1_ENABLE 0x75 Register Bits*/ +#define HPD_CHANGE_INT_MASK (1<<6) +#define RSEN_CHANGE_INT_MASK (1<<5) + +/* CBUS_INT_1_ENABLE: CBUS Transaction Interrupt #1 Mask */ +#define CBUS_INTR1_ENABLE_REG 0x09 +#define CBUS_INTR2_ENABLE_REG 0x1F + +/* CBUS Interrupt Status Registers*/ +#define CBUS_INT_STATUS_1_REG 0x08 +#define CBUS_INT_STATUS_2_REG 0x1E + +/* CBUS INTR1 STATUS Register bits */ +#define MSC_RESP_ABORT (1<<6) +#define MSC_REQ_ABORT (1<<5) +#define MSC_REQ_DONE (1<<4) +#define MSC_MSG_RECD (1<<3) +#define CBUS_DDC_ABORT (1<<2) + +/* CBUS INTR1 STATUS 0x09 Enable Mask*/ +#define MSC_RESP_ABORT_MASK (1<<6) +#define MSC_REQ_ABORT_MASK (1<<5) +#define MSC_REQ_DONE_MASK (1<<4) +#define MSC_MSG_RECD_MASK (1<<3) +#define CBUS_DDC_ABORT_MASK (1<<2) + +/* CBUS INTR2 STATUS Register bits */ +#define WRT_STAT_RECD (1<<3) +#define SET_INT_RECD (1<<2) +#define WRT_BURST_RECD (1<<0) + +/* CBUS INTR2 STATUS 0x1F Enable Mask*/ +#define WRT_STAT_RECD_MASK (1<<3) +#define SET_INT_RECD_MASK (1<<2) +#define WRT_BURST_RECD_MASK (1<<0) + +#define MHL_INT_EDID_CHG (1<<1) + +#define MHL_RCHANGE_INT 0x20 +#define MHL_DCHANGE_INT 0x21 +#define MHL_INT_DCAP_CHG (1<<0) +#define MHL_INT_DSCR_CHG (1<<1) +#define MHL_INT_REQ_WRT (1<<2) +#define MHL_INT_GRT_WRT (1<<3) + +/* CBUS Control Registers*/ +/* Retry count for all MSC commands*/ +#define MSC_RETRY_FAIL_LIM_REG 0x1D + +#define MSC_REQ_ABORT_REASON_REG 0x0D +#define MSC_RESP_ABORT_REASON_REG 0x0E + +/* MSC Requestor/Responder Abort Reason Register bits*/ +#define ABORT_BY_PEER (1<<7) +#define UNDEF_CMD (1<<3) +#define TIMEOUT (1<<2) +#define PROTO_ERROR (1<<1) +#define MAX_FAIL (1<<0) + +#define REG_CBUS_INTR_STATUS 0x08 +/* Responder aborted DDC command at translation layer */ +#define BIT_DDC_ABORT (1<<2) +/* Responder sent a VS_MSG packet (response data or command.) */ +#define BIT_MSC_MSG_RCV (1<<3) + /* Responder sent ACK packet (not VS_MSG) */ +#define BIT_MSC_XFR_DONE (1<<4) + /* Command send aborted on TX side */ +#define BIT_MSC_XFR_ABORT (1<<5) +#define BIT_MSC_ABORT (1<<6) + +/* Set HPD came from Downstream, */ +#define SET_HPD_DOWNSTREAM (1<<6) + +/* MHL TX DISC1 Register Bits */ +#define DISC_EN (1<<0) + +/* MHL TX DISC2 Register Bits */ +#define SKIP_GND (1<<6) +#define ATT_THRESH_SHIFT 0x04 +#define ATT_THRESH_MASK (0x03 << ATT_THRESH_SHIFT) +#define USB_D_OEN (1<<3) +#define DEGLITCH_TIME_MASK 0x07 +#define DEGLITCH_TIME_2MS 0 +#define DEGLITCH_TIME_4MS 1 +#define DEGLITCH_TIME_8MS 2 +#define DEGLITCH_TIME_16MS 3 +#define DEGLITCH_TIME_40MS 4 +#define DEGLITCH_TIME_50MS 5 +#define DEGLITCH_TIME_60MS 6 +#define DEGLITCH_TIME_128MS 7 + +#define DISC_CTRL3_COMM_IMME (1<<7) +#define DISC_CTRL3_FORCE_MHL (1<<6) +#define DISC_CTRL3_FORCE_USB (1<<4) +#define DISC_CTRL3_USB_EN (1<<3) + +/* MHL TX DISC4 0x93 Register Bits*/ +#define CBUS_DISC_PUP_SEL_SHIFT 6 +#define CBUS_DISC_PUP_SEL_MASK (3< +#include "msm_fb_def.h" +#include "msm_fb.h" #include #ifdef BIT diff --git a/drivers/video/msm/mipi_samsung_esd_refresh.c b/drivers/video/msm/mipi_samsung_esd_refresh.c new file mode 100644 index 00000000000..b08fd141647 --- /dev/null +++ b/drivers/video/msm/mipi_samsung_esd_refresh.c @@ -0,0 +1,406 @@ +/* + * Samsung Mipi ESD refresh driver. + * + * Author: Krishna Kishor Jha + * Copyright (C) 2012, Samsung Electronics. All rights reserved. + * + * 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 "mipi_samsung_esd_refresh.h" + +static struct mipi_controls mipi_control; +static struct esd_data_t *esd_enable; +static irqreturn_t sec_esd_irq_handler(int irq, void *handle); + +#ifdef READ_REGISTER_ESD +static struct completion esd_completion; +#endif + +#if LP11_RECOVERY +static void lcd_LP11_signal(void) +{ + uint32 dsi_lane_ctrl, dsi_video_mode_ctrl; + + dsi_lane_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x00A8); + dsi_video_mode_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x00C); + MIPI_OUTP(MIPI_DSI_BASE + 0x000C, dsi_video_mode_ctrl | 0x11110000); + MIPI_OUTP(MIPI_DSI_BASE + 0x00A8, dsi_lane_ctrl & 0x0FFFFFFF); + wmb(); + msleep(20); + MIPI_OUTP(MIPI_DSI_BASE + 0x00A8, dsi_lane_ctrl); + MIPI_OUTP(MIPI_DSI_BASE + 0x000C, dsi_video_mode_ctrl); + wmb(); +} + +static void lcd_esd_seq(struct esd_data_t *p_esd_data) +{ + lcd_LP11_signal(); + msleep(500); + lcd_LP11_signal(); + msleep(2000); + lcd_LP11_signal(); +} +#else + +static void lcd_esd_seq(struct esd_data_t *p_esd_data) +{ + + struct msm_fb_data_type *mfd; + struct msm_fb_panel_data *pdata; + mfd = platform_get_drvdata(mipi_control.mipi_dev); + if (mfd->panel_power_on) { +#ifndef ESD_DEBUG + /* threaded irq can sleep */ + wake_lock_timeout(&p_esd_data->det_wake_lock, WAKE_LOCK_TIME); +#endif + p_esd_data->refresh_ongoing = true; + set_esd_refresh(true); + p_esd_data->esd_ignore = true; + + mfd->fbi->fbops->fb_blank(FB_BLANK_VSYNC_SUSPEND, mfd->fbi); + + pr_info("Mipi ESD Turn off comple..........\n"); + msleep(100); + mfd->fbi->fbops->fb_blank(FB_BLANK_UNBLANK, mfd->fbi); + mfd->fbi->fbops->fb_pan_display(&mfd->fbi->var, mfd->fbi); + + pr_info("Mipi ESD Turn On complete...........\n"); + + p_esd_data->refresh_ongoing = false; + set_esd_refresh(false); + p_esd_data->esd_processed_count++; + + /* Restore brightness */ + pdata = mipi_control.mipi_dev->dev.platform_data; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) || \ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) + reset_gamma_level(); +#endif + pdata->set_backlight(mfd); + + } else { + pr_err("Panel is Off Skip ESD Sequence\n"); + } + +#ifdef READ_REGISTER_ESD + complete(&esd_completion); +#endif + +} +#endif + +static void sec_esd_work_func(struct work_struct *work) +{ + struct esd_data_t *p_esd_data = + container_of(work, struct esd_data_t, det_work); + p_esd_data->esd_count++; + if (p_esd_data->esd_count <= ESD_EXCEPT_CNT) + pr_info("%s : %d ignore Cnt(%d)\n", __func__, + p_esd_data->esd_count, ESD_EXCEPT_CNT); + else if (p_esd_data->esd_ignore) + pr_info("%s : %d ignore FLAG,esd_processed:%d\n", + __func__, p_esd_data->esd_count, + p_esd_data->esd_processed_count); + else { + lcd_esd_seq(p_esd_data); + } + p_esd_data->esd_irq_enable = true; + return; +} + +#ifdef ESD_DEBUG +static ssize_t mipi_samsung_esd_check_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct esd_data_t *p_esd_data = dev_get_drvdata(dev); + char temp[20]; + + snprintf(temp, 20, "ESD Status:%d\n", p_esd_data->refresh_ongoing); + strncat(buf, temp, 20); + return strnlen(buf, 20); +} + +static ssize_t mipi_samsung_esd_check_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct esd_data_t *p_esd_data = dev_get_drvdata(dev); + + sec_esd_irq_handler(0, p_esd_data); + return 1; +} + +static DEVICE_ATTR(esd_check, S_IRUGO , mipi_samsung_esd_check_show,\ + mipi_samsung_esd_check_store); +#endif + +static irqreturn_t sec_esd_irq_handler(int irq, void *handle) +{ + struct esd_data_t *p_esd_data = (struct esd_data_t *) handle; + struct msm_fb_data_type *mfd; + + if (!mipi_control.mipi_dev) + return IRQ_HANDLED; + else + mfd = platform_get_drvdata(mipi_control.mipi_dev); + + if (!mfd->panel_power_on || p_esd_data->refresh_ongoing + || p_esd_data->esd_irq_enable == false) { + /* Panel is not powered ON So bogus ESD/ + ESD Already executing*/ + return IRQ_HANDLED; + } +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + /* ESD occurred during Wakeup/Suspend, So ignore */ + if (mfd->resume_state) + return IRQ_HANDLED; +#endif + p_esd_data->esd_irq_enable = false; + schedule_work(&p_esd_data->det_work); + + return IRQ_HANDLED; +} + +#ifdef READ_REGISTER_ESD +void esd_execute(void) +{ + if (esd_enable->esd_irq_enable) { + + if (work_busy(&esd_enable->det_work)) + pr_info("%s ESD work queue is working", __func__); + else { + pr_info("%s start", __func__); + + INIT_COMPLETION(esd_completion); + + schedule_work(&esd_enable->det_work); + + wait_for_completion_timeout(&esd_completion, 10 * HZ); + + pr_info("%s end", __func__); + } + } else + pr_info("%s ESD is armed from ISR", __func__); +} +#endif + +void register_mipi_dev(struct platform_device *mipi_dev) +{ + mipi_control.mipi_dev = mipi_dev; +} +static void set_esd_enable_work_func(struct work_struct *work) +{ + pr_info("%s is called\n", __func__); + esd_enable->esd_ignore = false; + +} + +void set_esd_enable(void) +{ + pr_info("%s is called\n", __func__); + if (!esd_enable) { + pr_err("ESD Driver data is NULL!!\n"); + return; + } + + schedule_delayed_work(&esd_enable->esd_enable_delay,\ + msecs_to_jiffies(500)); +} +void set_esd_disable(void) +{ + pr_info("%s is called\n", __func__); + if (esd_enable->refresh_ongoing) { + pr_err("ESD refresh isr is on going!!\n"); + return; + } + if (!esd_enable) { + pr_err("ESD Driver data is NULL!!\n"); + return; + } + cancel_delayed_work(&esd_enable->esd_enable_delay); + esd_enable->esd_ignore = true; + + if (!list_empty(&(esd_enable->det_work.entry))) { + cancel_work_sync(&(esd_enable->det_work)); + pr_info("%s cancel_work_sync\n", __func__); + } +} + +static void mipi_samsung_esd_early_suspend(struct early_suspend *h) +{ + pr_info("Early Suspend:ESD IRQ is disabled\n"); + disable_irq(esd_enable->pdata->esd_gpio_irq); +} + +static void mipi_samsung_esd_late_resume(struct early_suspend *h) +{ + pr_info("Late Resume:ESD IRQ is enabled\n"); + enable_irq(esd_enable->pdata->esd_gpio_irq); + +} + +static int __devinit mipi_esd_refresh_probe(struct platform_device *pdev) +{ + struct esd_data_t *p_esd_data; + struct sec_esd_platform_data *pdata = pdev->dev.platform_data; + unsigned int irq_type; +#ifdef ESD_DEBUG + struct device *esd_device; +#endif + int ret = 0; + if (pdata == NULL) { + pr_err("ESD Platform data is Null !!!!!\n"); + return -1; + } +#ifndef ESD_DEBUG + if (pdata->esd_gpio_irq == -1) { + /* Do nothing ESD not supported in this revision */ + return 0; + } +#endif +#if defined(CONFIG_HAS_EARLYSUSPEND) + mipi_control.early_suspend.suspend = mipi_samsung_esd_early_suspend; + mipi_control.early_suspend.resume = mipi_samsung_esd_late_resume; + mipi_control.early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 5; + register_early_suspend(&mipi_control.early_suspend); +#endif + +#if defined(CONFIG_MACH_GOGH) || defined(CONFIG_MACH_INFINITE) + if (system_rev > 0x01) + irq_type = IRQF_TRIGGER_FALLING; + else { + /* Gogh 0.1rev has ESD protection chip irq + trigger is low.....HIGH...low */ + irq_type = IRQF_TRIGGER_RISING; + } +#else + /* ESD irq through VGH, irq trigger is HIGH....low....HIGH */ + irq_type = IRQF_TRIGGER_FALLING; +#endif + + +#ifdef READ_REGISTER_ESD + init_completion(&esd_completion); +#endif + + p_esd_data = kzalloc(sizeof(struct esd_data_t), GFP_KERNEL); + if (p_esd_data == NULL) { + pr_err("%s : Failed to allocate memory.\n", __func__); + return -ENOMEM; + } + esd_enable = p_esd_data; + p_esd_data->pdata = pdata; + p_esd_data->esd_count = 0; + p_esd_data->esd_ignore = false; + p_esd_data->esd_irq_enable = true; + p_esd_data->esd_processed_count = 0; + + wake_lock_init(&p_esd_data->det_wake_lock, + WAKE_LOCK_SUSPEND, "esd_det"); + + INIT_WORK(&p_esd_data->det_work, sec_esd_work_func); + INIT_DELAYED_WORK(&p_esd_data->esd_enable_delay,\ + set_esd_enable_work_func); + dev_set_drvdata(&pdev->dev, p_esd_data); +#ifdef ESD_DEBUG + esd_device = device_create(sec_class, NULL, 0, p_esd_data, "sec_esd"); + if (IS_ERR(esd_device)) { + pr_err("Failed to create device for the factory test\n"); + ret = -ENODEV; + } + + ret = sysfs_create_file(&esd_device->kobj, + &dev_attr_esd_check.attr); + if (ret) { + pr_err("sysfs create fail-%s\n", + dev_attr_esd_check.attr.name); + } +#endif + ret = request_threaded_irq(pdata->esd_gpio_irq, NULL, + sec_esd_irq_handler, + irq_type | + IRQF_ONESHOT, "esd_detect", p_esd_data); + if (ret) { + pr_err("%s : Failed to request_irq.:ret=%d", __func__, ret); + goto err_request_detect_irq; + } +#if defined(CONFIG_SAMSUNG_CMC624) + if (samsung_has_cmc624()) { + ret = request_threaded_irq(pdata->esd_gpio_cmc_irq, NULL, + sec_esd_irq_handler, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, "esd_detect2", p_esd_data); + if (ret) { + pr_err("%s:Fail to request_irq.:ret=%d", __func__, ret); + goto err_request_detect_irq2; + } + } +#endif + set_esd_disable(); + return 0; + +#if defined(CONFIG_SAMSUNG_CMC624) +err_request_detect_irq2: + free_irq(pdata->esd_gpio_irq, p_esd_data); +#endif + +err_request_detect_irq: + wake_lock_destroy(&p_esd_data->det_wake_lock); + kfree(p_esd_data); + esd_enable = NULL; + dev_set_drvdata(&pdev->dev, NULL); + + return -1; +} + +static int sec_esd_remove(struct platform_device *pdev) +{ + + struct esd_data_t *p_esd_data = dev_get_drvdata(&pdev->dev); + free_irq(p_esd_data->pdata->esd_gpio_irq, p_esd_data); + disable_irq_wake(p_esd_data->pdata->esd_gpio_irq); +#if defined(CONFIG_SAMSUNG_CMC624) + free_irq(p_esd_data->pdata->esd_gpio_cmc_irq, p_esd_data); + disable_irq_wake(p_esd_data->pdata->esd_gpio_cmc_irq); +#endif + wake_lock_destroy(&p_esd_data->det_wake_lock); + kfree(p_esd_data); + return 0; +} + +static struct platform_driver samsung_esd_refresh_driver = { + .probe = mipi_esd_refresh_probe, + .remove = sec_esd_remove, + .driver = { + .name = "samsung_mipi_esd_refresh", + }, +}; + +static void __exit samsung_mipi_esd_refresh_exit(void) +{ + platform_driver_unregister(&samsung_esd_refresh_driver); +} + +static int __init samsung_mipi_esd_refresh_init(void) +{ + return platform_driver_register(&samsung_esd_refresh_driver); +} + +MODULE_DESCRIPTION("Samsung ESD refresh driver"); +MODULE_AUTHOR("Krishna Kishor Jha "); +MODULE_LICENSE("GPL"); +module_init(samsung_mipi_esd_refresh_init); +module_exit(samsung_mipi_esd_refresh_exit); diff --git a/drivers/video/msm/mipi_samsung_esd_refresh.h b/drivers/video/msm/mipi_samsung_esd_refresh.h new file mode 100644 index 00000000000..a65f55618e1 --- /dev/null +++ b/drivers/video/msm/mipi_samsung_esd_refresh.h @@ -0,0 +1,88 @@ +/* + * Samsung Mipi ESD refresh driver. + * + * Author: Krishna Kishor Jha + * Copyright (C) 2012, Samsung Electronics. All rights reserved. + * + * 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 __MIPI_SAMSUNG_ESD_REFRESH_H_ +#define __MIPI_SAMSUNG_ESD_REFRESH_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_fb.h" +#include "mipi_dsi.h" + +#define WAKE_LOCK_TIME (10 * HZ) /* 1 sec */ +#define ESD_EXCEPT_CNT 0 +#define LP11_RECOVERY 0 + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) +#define READ_REGISTER_ESD +#endif + +extern void set_esd_refresh(boolean status); +extern struct class *sec_class; + +struct esd_data_t { + struct sec_esd_platform_data *pdata; + struct wake_lock det_wake_lock; + struct work_struct det_work; + int esd_count; + struct delayed_work esd_enable_delay; + boolean esd_ignore; + boolean refresh_ongoing; + boolean esd_irq_enable; + unsigned int esd_processed_count; +}; +struct mipi_controls { + struct platform_device *mipi_dev; +#if defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif +}; +#if defined(CONFIG_SAMSUNG_CMC624) +bool samsung_has_cmc624(void); +#endif +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) || \ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) +extern void reset_gamma_level(void); +#endif +void register_mipi_dev(struct platform_device *mipi_dev); +extern void set_esd_enable(void); +extern void set_esd_disable(void); + +#ifdef READ_REGISTER_ESD +void esd_execute(void); +#endif + +#endif /* __MIPI_SAMSUNG_ESD_REFRESH_H_*/ diff --git a/drivers/video/msm/mipi_samsung_oled.c b/drivers/video/msm/mipi_samsung_oled.c new file mode 100644 index 00000000000..7347b766830 --- /dev/null +++ b/drivers/video/msm/mipi_samsung_oled.c @@ -0,0 +1,1653 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include "mipi_samsung_oled.h" +#include "mdp4.h" +#ifdef CONFIG_SAMSUNG_CMC624 +#include "samsung_cmc624.h" +#endif +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +#include "mipi_samsung_esd_refresh.h" +#endif +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) +#include "mdp4_video_enhance.h" +#endif + +static struct mipi_samsung_driver_data msd; +static struct pm_qos_request pm_qos_req; +static unsigned int recovery_boot_mode; + +#define WA_FOR_FACTORY_MODE +#define READ_MTP_ONCE + +#ifdef READ_REGISTER_ESD +#define ESD_INTERVAL 3 +#endif + +unsigned char bypass_lcd_id; +static char elvss_value; +int is_lcd_connected = 1; + +#ifdef USE_READ_ID +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT +static DEFINE_MUTEX(mipi_lp_mutex); +char samsung_manufacture_id1_cmd[8] = { + 0x00, 0x00, 0x09, 0x40, 0xda, 0x00, 0x06, 0xA0}; +char samsung_manufacture_id2_cmd[8] = { + 0x00, 0x00, 0x09, 0x40, 0xdb, 0x00, 0x06, 0xA0}; +char samsung_manufacture_id3_cmd[8] = { + 0x00, 0x00, 0x09, 0x40, 0xdc, 0x00, 0x06, 0xA0}; +#else +static char manufacture_id1[2] = {0xDA, 0x00}; /* DTYPE_DCS_READ */ +static char manufacture_id2[2] = {0xDB, 0x00}; /* DTYPE_DCS_READ */ +static char manufacture_id3[2] = {0xDC, 0x00}; /* DTYPE_DCS_READ */ + +static struct dsi_cmd_desc samsung_manufacture_id1_cmd = { + DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(manufacture_id1), manufacture_id1}; +static struct dsi_cmd_desc samsung_manufacture_id2_cmd = { + DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(manufacture_id2), manufacture_id2}; +static struct dsi_cmd_desc samsung_manufacture_id3_cmd = { + DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(manufacture_id3), manufacture_id3}; +#endif + +static uint32 mipi_samsung_manufacture_id(struct msm_fb_data_type *mfd) +{ + struct dsi_buf *rp, *tp; +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + char *cmd_lp; +#else + struct dsi_cmd_desc *cmd; +#endif + uint32 id; + + tp = &msd.samsung_tx_buf; + rp = &msd.samsung_rx_buf; + mipi_dsi_buf_init(rp); + mipi_dsi_buf_init(tp); + +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + cmd_lp = &samsung_manufacture_id1_cmd; + mipi_dsi_cmds_rx_lp(mfd, tp, rp, cmd_lp, 1); +#else + cmd = &samsung_manufacture_id1_cmd; + mipi_dsi_cmds_rx(mfd, tp, rp, cmd, 1); +#endif + pr_info("%s: manufacture_id1=%x\n", __func__, *rp->data); + id = *((uint32 *)rp->data); + id <<= 8; + + mipi_dsi_buf_init(rp); + mipi_dsi_buf_init(tp); + +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + cmd_lp = &samsung_manufacture_id2_cmd; + mipi_dsi_cmds_rx_lp(mfd, tp, rp, cmd_lp, 1); +#else + cmd = &samsung_manufacture_id2_cmd; + mipi_dsi_cmds_rx(mfd, tp, rp, cmd, 1); +#endif + pr_info("%s: manufacture_id2=%x\n", __func__, *rp->data); + bypass_lcd_id = *rp->data; + id |= *((uint32 *)rp->data); + id <<= 8; + + mipi_dsi_buf_init(rp); + mipi_dsi_buf_init(tp); +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + cmd_lp = &samsung_manufacture_id3_cmd; + mipi_dsi_cmds_rx_lp(mfd, tp, rp, cmd_lp, 1); +#else + cmd = &samsung_manufacture_id3_cmd; + mipi_dsi_cmds_rx(mfd, tp, rp, cmd, 1); +#endif + pr_info("%s: manufacture_id3=%x\n", __func__, *rp->data); + elvss_value = *rp->data; + id |= *((uint32 *)rp->data); + + pr_info("%s: manufacture_id=%x\n", __func__, id); + +#ifdef FACTORY_TEST + if (id == 0x00) { + pr_info("Lcd is not connected\n"); + is_lcd_connected = 0; + } +#endif + return id; +} +#endif +unsigned char bypass_LCD_Id(void){ + return bypass_lcd_id; +} +bool Is_4_8LCD_bypass(void){ + if ((bypass_lcd_id == 0x20) || (bypass_lcd_id == 0x40) || + (bypass_lcd_id == 0x60)) + return true; + else + return false; +} + +bool Is_4_65LCD_bypass(void){ +#if defined(CONFIG_MACH_STRETTO) || defined(CONFIG_MACH_SUPERIORLTE_SKT) + return true; +#else + if (bypass_lcd_id == 0xAE) + return true; + else + return false; +#endif +} + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) +unsigned int get_lcd_manufacture_id(void) +{ + return msd.mpd->manufacture_id; +} +#endif + +#if defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) +/* +* EA8868 has HW limitation. EA8868 deosn't have +* global parameter to set read address point. +*/ +static void read_reg(char srcReg, int srcLength, char *destBuffer, + const int isUseMutex, struct msm_fb_data_type *pMFD) +{ + /* + * EA8868 has 3 bank MTP register + * Each bank has 7 byte MTP data. + */ + char ea8868_read_address[] = {0xD3, 0xD4, 0xE0}; + const int one_read_size = 7; + + /* second byte is read address set */ + static char reg_set_read_register[] = { 0xFD, 0x00 }; + static struct dsi_cmd_desc ea8868_read_pos_cmd = { + DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(reg_set_read_register), + reg_set_read_register }; + + /* first byte = read buffer register */ + static char read_reg[2] = { 0xFE, 0x00 }; + static struct dsi_cmd_desc ea8868_read_reg_cmd = { + DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(read_reg), read_reg }; + + /* first byte is size of Register */ + static char packet_size[] = { 0x04, 0 }; + static struct dsi_cmd_desc ea8868_packet_size_cmd = { + DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, + sizeof(packet_size), packet_size }; + + int readed_size, rx_cnt; + int show_cnt = 0; + + int read_addr_cnt; + char show_buffer[256] = {0,}; + int show_buffer_pos = 0; + + for (read_addr_cnt = 0; read_addr_cnt < sizeof(ea8868_read_address); + read_addr_cnt++) { + readed_size = 0; + + /* set read register address */ + reg_set_read_register[1] = ea8868_read_address[read_addr_cnt]; + mipi_dsi_buf_init(&msd.samsung_tx_buf); + mipi_dsi_cmds_tx(&msd.samsung_tx_buf, + &(ea8868_read_pos_cmd), 1); + + /*set maxpacket size */ + packet_size[0] = (char)one_read_size; + mipi_dsi_buf_init(&msd.samsung_tx_buf); + mipi_dsi_cmds_tx(&msd.samsung_tx_buf, + &(ea8868_packet_size_cmd), 1); + + mipi_dsi_buf_init(&msd.samsung_tx_buf); + mipi_dsi_buf_init(&msd.samsung_rx_buf); + readed_size = + mipi_dsi_cmds_rx(pMFD, &msd.samsung_tx_buf, + &msd.samsung_rx_buf, + &ea8868_read_reg_cmd, one_read_size); + + for (rx_cnt = 0; rx_cnt < readed_size; rx_cnt++, show_cnt++) { + if (destBuffer != NULL && show_cnt < srcLength) + destBuffer[show_cnt] = + msd.samsung_rx_buf.data[rx_cnt]; + } + } + + /* only LSB is available */ + destBuffer[14] = 0x01; + + /* for debug */ + show_buffer_pos += + snprintf(show_buffer, 256, "read_reg : "); + + for (read_addr_cnt = 0; read_addr_cnt < srcLength;) { + show_buffer_pos += + snprintf(show_buffer + show_buffer_pos, 256, + "%02x ", destBuffer[read_addr_cnt]); + + read_addr_cnt++; + + if (read_addr_cnt % 7 == 0) + show_buffer_pos += + snprintf(show_buffer + show_buffer_pos, 256, ". "); + } + + pr_info("%s\n", show_buffer); +} + + +#else +static void read_reg(char srcReg, int srcLength, char *destBuffer, + const int isUseMutex, struct msm_fb_data_type *pMFD) +{ +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + const int one_read_size = 7; +#else + const int one_read_size = 4; +#endif + const int loop_limit = 16; + /* first byte = read-register */ + static char read_reg[2] = { 0xFF, 0x00 }; + static struct dsi_cmd_desc s6e8aa0_read_reg_cmd = { + DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(read_reg), read_reg }; + /* first byte is size of Register */ + static char packet_size[] = { 0x04, 0 }; + static struct dsi_cmd_desc s6e8aa0_packet_size_cmd = { + DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, sizeof(packet_size), packet_size }; + + /* second byte is Read-position */ + static char reg_read_pos[] = { 0xB0, 0x00 }; + static struct dsi_cmd_desc s6e8aa0_read_pos_cmd = { + DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(reg_read_pos), + reg_read_pos }; + + int read_pos; + int readed_size; + int show_cnt; + + int i, j; + char show_buffer[256]; + int show_buffer_pos = 0; + + read_reg[0] = srcReg; + + show_buffer_pos += + snprintf(show_buffer, 256, "read_reg : %X[%d] : ", + srcReg, srcLength); + + read_pos = 0; + readed_size = 0; + + packet_size[0] = (char)srcLength; + mipi_dsi_buf_init(&msd.samsung_tx_buf); + mipi_dsi_cmds_tx(&msd.samsung_tx_buf, &(s6e8aa0_packet_size_cmd), 1); + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + msleep(20); +#endif + + show_cnt = 0; + for (j = 0; j < loop_limit; j++) { + reg_read_pos[1] = read_pos; + if (mipi_dsi_cmds_tx + (&msd.samsung_tx_buf, &(s6e8aa0_read_pos_cmd), + 1) < 1) { + show_buffer_pos += + snprintf(show_buffer + show_buffer_pos, 256, + "Tx command FAILED"); + break; + } +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + msleep(20); +#endif + mipi_dsi_buf_init(&msd.samsung_tx_buf); + mipi_dsi_buf_init(&msd.samsung_rx_buf); + readed_size = + mipi_dsi_cmds_rx(pMFD, &msd.samsung_tx_buf, + &msd.samsung_rx_buf, &s6e8aa0_read_reg_cmd, + one_read_size); + for (i = 0; i < readed_size; i++, show_cnt++) { + show_buffer_pos += + snprintf(show_buffer + show_buffer_pos, 256, "%02x ", + msd.samsung_rx_buf.data[i]); + if (destBuffer != NULL && show_cnt < srcLength) { + destBuffer[show_cnt] = + msd.samsung_rx_buf.data[i]; + } + } + show_buffer_pos += snprintf(show_buffer + + show_buffer_pos, 256, "."); + read_pos += readed_size; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + msleep(20); + + if (read_pos >= srcLength) + break; +#else + if (read_pos > srcLength) + break; +#endif + } + + if (j == loop_limit) + show_buffer_pos += + snprintf(show_buffer + show_buffer_pos, 256, "Overrun"); + + pr_info("%s\n", show_buffer); +} +#endif + +static int mipi_samsung_disp_send_cmd(struct msm_fb_data_type *mfd, + enum mipi_samsung_cmd_list cmd, + unsigned char lock) +{ + struct dsi_cmd_desc *cmd_desc; + int cmd_size = 0; + + pm_qos_update_request(&pm_qos_req, + msm_cpuidle_get_deep_idle_latency()); +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + mutex_lock(&mipi_lp_mutex); +#endif + if (lock) + mutex_lock(&mfd->dma->ov_mutex); + + switch (cmd) { +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + case PANEL_READY_TO_ON_FAST: + if (Is_4_65LCD_cmc() || Is_4_65LCD_bypass()) { /*4.65 LCD_ID*/ + pr_info("Select 4.65 = %x\n", LCD_Get_Value()); + cmd_desc = msd.mpd->ready_to_on_fast.cmd; + cmd_size = msd.mpd->ready_to_on_fast.size; + } else { + pr_info("Select 4.8 = %x\n", LCD_Get_Value()); + cmd_desc = msd.mpd->ready_to_on_4_8_fast.cmd; + cmd_size = msd.mpd->ready_to_on_4_8_fast.size; + } + break; +#endif + case PANEL_READY_TO_ON: +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + if (Is_4_65LCD_cmc() || Is_4_65LCD_bypass()) { /*4.65 LCD_ID*/ + pr_info("Select 4.65 = %x(%x)\n", LCD_Get_Value(), + bypass_LCD_Id()); + cmd_desc = msd.mpd->ready_to_on.cmd; + cmd_size = msd.mpd->ready_to_on.size; + } else { /* 4.8 LCD_ID*/ + pr_info("Select 4.8 = %x(%x)\n", LCD_Get_Value(), + bypass_LCD_Id()); + cmd_desc = msd.mpd->ready_to_on_4_8.cmd; + cmd_size = msd.mpd->ready_to_on_4_8.size; + } +#else + cmd_desc = msd.mpd->ready_to_on.cmd; + cmd_size = msd.mpd->ready_to_on.size; +#endif + break; + case PANEL_READY_TO_OFF: + cmd_desc = msd.mpd->ready_to_off.cmd; + cmd_size = msd.mpd->ready_to_off.size; + break; + case PANEL_ON: + cmd_desc = msd.mpd->on.cmd; + cmd_size = msd.mpd->on.size; + break; + case PANEL_OFF: + cmd_desc = msd.mpd->off.cmd; + cmd_size = msd.mpd->off.size; + break; + case PANEL_LATE_ON: + cmd_desc = msd.mpd->late_on.cmd; + cmd_size = msd.mpd->late_on.size; + break; + case PANEL_EARLY_OFF: + cmd_desc = msd.mpd->early_off.cmd; + cmd_size = msd.mpd->early_off.size; + break; + case PANEL_GAMMA_UPDATE: + cmd_desc = msd.mpd->gamma_update.cmd; + cmd_size = msd.mpd->gamma_update.size; + break; + case MTP_READ_ENABLE: + cmd_desc = msd.mpd->mtp_read_enable.cmd; + cmd_size = msd.mpd->mtp_read_enable.size; + break; +#ifdef USE_ACL + case PANEL_ACL_ON: + cmd_desc = msd.mpd->acl_on.cmd; + cmd_size = msd.mpd->acl_on.size; + msd.mpd->ldi_acl_stat = true; + break; + case PANEL_ACL_OFF: + cmd_desc = msd.mpd->acl_off.cmd; + cmd_size = msd.mpd->acl_off.size; + msd.mpd->ldi_acl_stat = false; + break; + case PANEL_ACL_UPDATE: + cmd_desc = msd.mpd->acl_update.cmd; + cmd_size = msd.mpd->acl_update.size; + break; +#endif +#ifdef USE_ELVSS + case PANEL_ELVSS_UPDATE: +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + if (Is_4_65LCD_cmc() || Is_4_65LCD_bypass()) { /*4.65 LCD_ID*/ + msd.mpd->set_elvss(mfd->bl_level); + cmd_desc = msd.mpd->elvss_update.cmd; + cmd_size = msd.mpd->elvss_update.size; + } + else { /* 4.8 LCD_ID*/ + msd.mpd->set_elvss_4_8(mfd->bl_level); + cmd_desc = msd.mpd->elvss_update_4_8.cmd; + cmd_size = msd.mpd->elvss_update_4_8.size; + } +#else + msd.mpd->set_elvss(mfd->bl_level); + cmd_desc = msd.mpd->elvss_update.cmd; + cmd_size = msd.mpd->elvss_update.size; +#endif + break; +#endif +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + case PANEL_BRIGHT_CTRL: + cmd_desc = msd.mpd->combined_ctrl.cmd; + cmd_size = msd.mpd->combined_ctrl.size; + break; +#endif + default: + goto unknown_command; + ; + } + + if (!cmd_size) + goto unknown_command; + + if (lock) { + mipi_dsi_mdp_busy_wait(); + /* Added to resolved cmd loss during dimming factory test */ + mdelay(1); + + mipi_dsi_cmds_tx(&msd.samsung_tx_buf, cmd_desc, cmd_size); + + mutex_unlock(&mfd->dma->ov_mutex); + } else { + mipi_dsi_mdp_busy_wait(); + /* Added to resolved cmd loss during dimming factory test */ + mdelay(1); + mipi_dsi_cmds_tx(&msd.samsung_tx_buf, cmd_desc, cmd_size); + } + +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + mutex_unlock(&mipi_lp_mutex); +#endif + pm_qos_update_request(&pm_qos_req, PM_QOS_DEFAULT_VALUE); + + return 0; + +unknown_command: + if (lock) + mutex_unlock(&mfd->dma->ov_mutex); + +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + mutex_unlock(&mipi_lp_mutex); +#endif + pm_qos_update_request(&pm_qos_req, PM_QOS_DEFAULT_VALUE); + + return 0; +} + +static unsigned char first_on; + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) +static int find_mtp(struct msm_fb_data_type *mfd, char * mtp) +{ +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + char first_mtp[MTP_DATA_SIZE_S6E63M0]; + char second_mtp[MTP_DATA_SIZE_S6E63M0]; + char third_mtp[MTP_DATA_SIZE_S6E63M0]; + int mtp_size = MTP_DATA_SIZE_S6E63M0; +#elif defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + char first_mtp[MTP_DATA_SIZE_EA8868]; + char second_mtp[MTP_DATA_SIZE_EA8868]; + char third_mtp[MTP_DATA_SIZE_EA8868]; + int mtp_size = MTP_DATA_SIZE_EA8868; +#else + /* + * s6e8aa0x01 & s6e39a0x02 has same MTP length. + */ + char first_mtp[MTP_DATA_SIZE]; + char second_mtp[MTP_DATA_SIZE]; + char third_mtp[MTP_DATA_SIZE]; + int mtp_size = MTP_DATA_SIZE; +#endif + int correct_mtp; + + pr_info("first time mpt read\n"); + read_reg(MTP_REGISTER, mtp_size, first_mtp, FALSE, mfd); + + pr_info("second time mpt read\n"); + read_reg(MTP_REGISTER, mtp_size, second_mtp, FALSE, mfd); + + if (memcmp(first_mtp, second_mtp, mtp_size) != 0) { + pr_info("third time mpt read\n"); + read_reg(MTP_REGISTER, mtp_size, third_mtp, FALSE, mfd); + + if (memcmp(first_mtp, third_mtp, mtp_size) == 0) { + pr_info("MTP data is used from first read mtp"); + memcpy(mtp, first_mtp, mtp_size); + correct_mtp = 1; + } else if (memcmp(second_mtp, third_mtp, mtp_size) == 0) { + pr_info("MTP data is used from second read mtp"); + memcpy(mtp, second_mtp, mtp_size); + correct_mtp = 2; + } else { + pr_info("MTP data is used 0 read mtp"); + memset(mtp, 0, mtp_size); + correct_mtp = 0; + } + } else { + pr_info("MTP data is used from first read mtp"); + memcpy(mtp, first_mtp, mtp_size); + correct_mtp = 1; + } + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + /* + * checking V1 MTP value. V0 value must be 0. + */ + if ((mtp[0] != 0) || (mtp[7] != 0) || (mtp[14] != 0)) { + memset(mtp, 0, mtp_size); + correct_mtp = 0; + } +#endif + return correct_mtp; +} +#else +static int find_mtp(struct msm_fb_data_type *mfd, char * mtp) +{ + return 0; +} +#endif +static int mipi_samsung_disp_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + static int boot_on; +#endif + + mfd = platform_get_drvdata(pdev); + if (unlikely(!mfd)) + return -ENODEV; + if (unlikely(mfd->key != MFD_KEY)) + return -EINVAL; + + mipi = &mfd->panel_info.mipi; + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) + mipi_samsung_disp_send_cmd(mfd, MTP_READ_ENABLE, false); +#endif + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + if (boot_on == 0) + mipi_samsung_disp_send_cmd(mfd, MTP_READ_ENABLE, false); +#endif + +#ifdef USE_READ_ID +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + if (boot_on == 0) + msd.mpd->manufacture_id = mipi_samsung_manufacture_id(mfd); +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) + msd.mpd->manufacture_id = mipi_samsung_manufacture_id(mfd); +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + if (!samsung_has_cmc624()) + msd.mpd->manufacture_id = mipi_samsung_manufacture_id(mfd); + else + msd.mpd->manufacture_id = LCD_Get_Value(); +#endif +#endif + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) + if (!msd.dstat.is_elvss_loaded) { + read_reg(ELVSS_REGISTER, ELVSS_DATA_SIZE, + msd.mpd->lcd_elvss_data, + FALSE, mfd); /* read ELVSS data */ + msd.dstat.is_elvss_loaded = true; + } + + + if (!msd.dstat.is_smart_dim_loaded) { + /* Load MTP Data */ + int i; + read_reg(MTP_REGISTER, MTP_DATA_SIZE, + (u8 *)&(msd.mpd->smart_s6e39a0x02.MTP), + FALSE, mfd); + for (i = 0; i < MTP_DATA_SIZE; i++) { + pr_info("%s MTP DATA[%d] : %02x\n", __func__, i, + ((char *)&(msd.mpd->smart_s6e39a0x02.MTP))[i]); + } + + smart_dimming_init(&(msd.mpd->smart_s6e39a0x02)); +#ifdef READ_MTP_ONCE + msd.dstat.is_smart_dim_loaded = true; +#else + msd.dstat.is_smart_dim_loaded = false; +#endif + msd.dstat.gamma_mode = GAMMA_SMART; + } +#endif +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + if (!msd.dstat.is_elvss_loaded) { + if (!samsung_has_cmc624()) + msd.mpd->lcd_elvss_data[0] = elvss_value; + else + msd.mpd->lcd_elvss_data[0] = LCD_ID3(); + + msd.dstat.is_elvss_loaded = true; + } + + if (!msd.dstat.is_smart_dim_loaded) { + /*Load MTP Data*/ + char pBuffer[256] = {0,}; + int i; + struct SMART_DIM *psmart; + char *mtp_data; + int mtp_cnt; + + psmart = &(msd.mpd->smart_s6e8aa0x01); + mtp_data = (char *)&(msd.mpd->smart_s6e8aa0x01.MTP); + + if (samsung_has_cmc624()) { + memcpy(mtp_data, mtp_read_data, GAMMA_SET_MAX); + pr_info("%s This board support CMC", __func__); + } else { + mtp_cnt = find_mtp(mfd, mtp_data); + pr_info("%s MTP is determined : %d", __func__, mtp_cnt); + } + + + for (i = 0; i < MTP_DATA_SIZE; i++) + snprintf(pBuffer + strnlen(pBuffer, 256), 256, " %02x", + mtp_data[i]); + pr_info("MTP: %s", pBuffer); + + psmart->plux_table = msd.mpd->lux_table; + psmart->lux_table_max = msd.mpd->lux_table_max_cnt; + + if (samsung_has_cmc624()) + psmart->ldi_revision = LCD_Get_Value(); + else + psmart->ldi_revision = bypass_LCD_Id(); + + smart_dimming_init(psmart); + + msd.dstat.is_smart_dim_loaded = true; + msd.dstat.gamma_mode = GAMMA_SMART; + } + + if (msd.mpd->gamma_initial && boot_on == 0) { + msd.mpd->smart_s6e8aa0x01.brightness_level = 180; + generate_gamma(&msd.mpd->smart_s6e8aa0x01, + &(msd.mpd->gamma_initial[2]), GAMMA_SET_MAX); + + if (recovery_boot_mode == 0) + boot_on = 1; + } else { + get_min_lux_table(&(msd.mpd->gamma_initial[2]), + GAMMA_SET_MAX); + reset_gamma_level(); + } +#endif + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + if (!msd.dstat.is_smart_dim_loaded) { + /* Load MTP Data */ + int i, mtp_cnt, err_cnt; + char *mtp_data = (char *)&(msd.mpd->smart_s6e63m0.MTP); + + for (err_cnt = 0; err_cnt < 10; err_cnt++) { + mtp_cnt = find_mtp(mfd, mtp_data); + + if (mtp_cnt != 0) + break; + } + + pr_info("%s MTP is determined:%d err_cnt:%d", + __func__, mtp_cnt, err_cnt); + + for (i = 0; i < MTP_DATA_SIZE_S6E63M0; i++) { + pr_info("%s MTP DATA[%d] : %02x\n", __func__, i, + mtp_data[i]); + } + + smart_dimming_init(&(msd.mpd->smart_s6e63m0)); + + msd.dstat.is_smart_dim_loaded = true; + msd.dstat.gamma_mode = GAMMA_SMART; + } + + if (msd.mpd->gamma_initial && boot_on == 0) { + msd.mpd->smart_s6e63m0.brightness_level = 140; + generate_gamma(&msd.mpd->smart_s6e63m0, + &(msd.mpd->gamma_initial[2]), GAMMA_SET_MAX); + + if (recovery_boot_mode == 0) + boot_on = 1; + + } else { + msd.mpd->smart_s6e63m0.brightness_level = 30; + generate_gamma(&msd.mpd->smart_s6e63m0, + &(msd.mpd->gamma_initial[2]), GAMMA_SET_MAX); + reset_gamma_level(); + } +#endif + +#if defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + if (!msd.dstat.is_smart_dim_loaded) { + /* Load MTP Data */ + int i, mtp_cnt, err_cnt; + char *mtp_data = (char *)&(msd.mpd->smart_ea8868.MTP); + + if (bypass_lcd_id == 0x4a) { + for (err_cnt = 0; err_cnt < 10; err_cnt++) { + mtp_cnt = find_mtp(mfd, mtp_data); + + if (mtp_cnt != 0) + break; + } + + pr_info("%s MTP is determined:%d err_cnt:%d", + __func__, mtp_cnt, err_cnt); + + for (i = 0; i < MTP_DATA_SIZE_EA8868; i++) { + pr_info("%s MTP DATA[%d] : %02x\n", + __func__, i, mtp_data[i]); + } + } else { + pr_info("%s MTP is not used LDI_ID: 0x%x", + __func__, bypass_lcd_id); + memset(mtp_data, 0x0, MTP_DATA_SIZE_EA8868); + } + + smart_dimming_init(&(msd.mpd->smart_ea8868)); + + msd.dstat.is_smart_dim_loaded = true; + msd.dstat.gamma_mode = GAMMA_SMART; + } + + if (msd.mpd->gamma_initial && boot_on == 0) { + msd.mpd->smart_ea8868.brightness_level = 180; + generate_gamma(&msd.mpd->smart_ea8868, + &(msd.mpd->gamma_initial[1]), GAMMA_SET_MAX); + + if (recovery_boot_mode == 0) + boot_on = 1; + } else { + msd.mpd->smart_ea8868.brightness_level = get_gamma_lux(); + generate_gamma(&msd.mpd->smart_ea8868, + &(msd.mpd->gamma_initial[1]), GAMMA_SET_MAX); + reset_gamma_level(); + } +#endif + + if (unlikely(first_on)) { + first_on = false; + return 0; + } + + mipi_samsung_disp_send_cmd(mfd, PANEL_READY_TO_ON, false); + if (mipi->mode == DSI_VIDEO_MODE) + mipi_samsung_disp_send_cmd(mfd, PANEL_ON, false); + +#if !defined(CONFIG_HAS_EARLYSUSPEND) + mipi_samsung_disp_send_cmd(mfd, PANEL_LATE_ON, false); +#endif +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +#if defined(CONFIG_MACH_JAGUAR) + if (system_rev >= 16) + set_esd_enable(); + if (msd.esd_refresh == true) + mipi_samsung_disp_send_cmd(mfd, PANEL_LATE_ON, false); +#else + set_esd_enable(); +#endif +#endif + +#ifdef READ_REGISTER_ESD + queue_delayed_work(msd.mpd->esd_workqueue, + &(msd.mpd->esd_work), ESD_INTERVAL * HZ); + wake_lock(&(msd.mpd->esd_wake_lock)); +#endif + + return 0; +} + +static int mipi_samsung_disp_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + +#ifdef READ_REGISTER_ESD + cancel_delayed_work(&(msd.mpd->esd_work)); +#endif + +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +#if defined(CONFIG_MACH_JAGUAR) + if (system_rev >= 16) + set_esd_disable(); +#else + set_esd_disable(); +#endif + +#endif + mfd = platform_get_drvdata(pdev); + if (unlikely(!mfd)) + return -ENODEV; + if (unlikely(mfd->key != MFD_KEY)) + return -EINVAL; + + mipi_samsung_disp_send_cmd(mfd, PANEL_READY_TO_OFF, false); + mipi_samsung_disp_send_cmd(mfd, PANEL_OFF, false); + + msd.mpd->ldi_acl_stat = false; + + return 0; +} + +static void __devinit mipi_samsung_disp_shutdown(struct platform_device *pdev) +{ + static struct mipi_dsi_platform_data *mipi_dsi_pdata; + + if (pdev->id != 0) + return; + + mipi_dsi_pdata = pdev->dev.platform_data; + if (mipi_dsi_pdata == NULL) { + pr_err("LCD Power off failure: No Platform Data\n"); + return; + } + +/* Power off Seq:2: Sleepout mode->ResetLow -> delay 120ms->VCI,VDD off */ + if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save) { + mipi_dsi_pdata->lcd_rst_down(); + mdelay(120); + pr_info("LCD POWER OFF\n"); + } + +} +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +void set_esd_refresh(boolean stat) +{ + msd.esd_refresh = stat; +} +boolean get_esd_refresh_stat(void) +{ + return msd.esd_refresh; +} +#endif + +static void mipi_samsung_disp_backlight(struct msm_fb_data_type *mfd) +{ + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) + mfd->backlight_ctrl_ongoing = TRUE; +#else + mfd->backlight_ctrl_ongoing = FALSE; +#endif + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) +if (msd.mpd->prepare_brightness_control_cmd_array) { + int cmds_sent; + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + if (!samsung_has_cmc624()) + cmds_sent = msd.mpd->prepare_brightness_control_cmd_array( + bypass_LCD_Id(), mfd->bl_level); + else + cmds_sent = msd.mpd->prepare_brightness_control_cmd_array( + LCD_Get_Value(), mfd->bl_level); +#else + cmds_sent = msd.mpd->prepare_brightness_control_cmd_array( + 0, mfd->bl_level); +#endif + pr_debug("cmds_sent: %x\n", cmds_sent); + if (cmds_sent < 0) + goto end; + + mipi_samsung_disp_send_cmd(mfd, PANEL_BRIGHT_CTRL, true); + goto end; +} +#endif + +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) + if (msd.esd_refresh == true) + goto end; +#endif + pr_info("mipi_samsung_disp_backlight %d\n", mfd->bl_level); + if (!msd.mpd->set_gamma || !mfd->panel_power_on ||\ + mfd->resume_state == MIPI_SUSPEND_STATE) + goto end; + + if (msd.mpd->set_gamma(mfd->bl_level, msd.dstat.gamma_mode) < 0) + goto end; + + pr_info("mipi_samsung_disp_backlight %d\n", mfd->bl_level); + mipi_samsung_disp_send_cmd(mfd, PANEL_GAMMA_UPDATE, true); + +#ifdef USE_ELVSS +if (msd.mpd->set_elvss) + mipi_samsung_disp_send_cmd(mfd, PANEL_ELVSS_UPDATE, true); +#endif + +#ifdef USE_ACL +if (msd.mpd->set_acl && msd.dstat.acl_on && msd.mpd->set_acl(mfd->bl_level)) + mipi_samsung_disp_send_cmd(mfd, PANEL_ACL_OFF, true); + +if (msd.mpd->set_acl && msd.dstat.acl_on && !msd.mpd->set_acl(mfd->bl_level)) { +#if !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) + mipi_samsung_disp_send_cmd(mfd, PANEL_ACL_ON, true); +#endif + mipi_samsung_disp_send_cmd(mfd, PANEL_ACL_UPDATE, true); +} +#endif + +end: +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) + mfd->backlight_ctrl_ongoing = FALSE; +#endif + return; +} + +#if defined(CONFIG_HAS_EARLYSUSPEND) +static void mipi_samsung_disp_early_suspend(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd; + pr_info("%s", __func__); + +#ifdef READ_REGISTER_ESD + mfd = platform_get_drvdata(msd.msm_pdev); + if (unlikely(!mfd)) { + pr_info("%s NO PDEV.\n", __func__); + return; + } + if (unlikely(mfd->key != MFD_KEY)) { + pr_info("%s MFD_KEY is not matched.\n", __func__); + return; + } + + mfd->resume_state = MIPI_SUSPEND_STATE; + cancel_delayed_work_sync(&(msd.mpd->esd_work)); + wake_unlock(&(msd.mpd->esd_wake_lock)); + +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) + set_esd_disable(); +#endif +#else +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) + set_esd_disable(); +#endif + + mfd = platform_get_drvdata(msd.msm_pdev); + if (unlikely(!mfd)) { + pr_info("%s NO PDEV.\n", __func__); + return; + } + if (unlikely(mfd->key != MFD_KEY)) { + pr_info("%s MFD_KEY is not matched.\n", __func__); + return; + } +#endif + +#if !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) && \ + !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) && \ + !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + + mipi_samsung_disp_send_cmd(mfd, PANEL_EARLY_OFF, true); +#else + mipi_samsung_disp_send_cmd(mfd, PANEL_READY_TO_OFF, true); +#endif + mfd->resume_state = MIPI_SUSPEND_STATE; +} + +static void mipi_samsung_disp_late_resume(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + is_negativeMode_on(); +#endif + mfd = platform_get_drvdata(msd.msm_pdev); + if (unlikely(!mfd)) { + pr_info("%s NO PDEV.\n", __func__); + return; + } + if (unlikely(mfd->key != MFD_KEY)) { + pr_info("%s MFD_KEY is not matched.\n", __func__); + return; + } + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + reset_gamma_level(); + mfd->resume_state = MIPI_RESUME_STATE; + mipi_samsung_disp_backlight(mfd); +#endif + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + mfd->resume_state = MIPI_RESUME_STATE; +#endif + +#if !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) && \ + !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) && \ + !defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) && \ + !defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + mipi_samsung_disp_send_cmd(mfd, PANEL_LATE_ON, true); +#endif + pr_info("%s", __func__); +} +#endif + +#if defined(CONFIG_LCD_CLASS_DEVICE) +#ifdef WA_FOR_FACTORY_MODE +static ssize_t mipi_samsung_disp_get_power(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct msm_fb_data_type *mfd; + int rc; + + mfd = platform_get_drvdata(msd.msm_pdev); + if (unlikely(!mfd)) + return -ENODEV; + if (unlikely(mfd->key != MFD_KEY)) + return -EINVAL; + + rc = snprintf((char *)buf, sizeof(buf), "%d\n", mfd->panel_power_on); + pr_info("mipi_samsung_disp_get_power(%d)\n", mfd->panel_power_on); + + return rc; +} + +static ssize_t mipi_samsung_disp_set_power(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct msm_fb_data_type *mfd; + unsigned int power; + + mfd = platform_get_drvdata(msd.msm_pdev); + + if (sscanf(buf, "%u", &power) != 1) + return -EINVAL; + + if (power == mfd->panel_power_on) + return 0; + + if (power) { + mfd->fbi->fbops->fb_blank(FB_BLANK_UNBLANK, mfd->fbi); + mfd->fbi->fbops->fb_pan_display(&mfd->fbi->var, mfd->fbi); + mipi_samsung_disp_send_cmd(mfd, PANEL_LATE_ON, true); + mipi_samsung_disp_backlight(mfd); + } else { + mfd->fbi->fbops->fb_blank(FB_BLANK_POWERDOWN, mfd->fbi); + } + + pr_info("mipi_samsung_disp_set_power\n"); + + return size; +} +#else +static int mipi_samsung_disp_get_power(struct lcd_device *dev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(msd.msm_pdev); + if (unlikely(!mfd)) + return -ENODEV; + if (unlikely(mfd->key != MFD_KEY)) + return -EINVAL; + + pr_info("mipi_samsung_disp_get_power(%d)\n", mfd->panel_power_on); + + return mfd->panel_power_on; +} + +static int mipi_samsung_disp_set_power(struct lcd_device *dev, int power) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(msd.msm_pdev); + + if (power == mfd->panel_power_on) + return 0; + + if (power) { + mfd->fbi->fbops->fb_blank(FB_BLANK_UNBLANK, mfd->fbi); + mfd->fbi->fbops->fb_pan_display(&mfd->fbi->var, mfd->fbi); + mipi_samsung_disp_send_cmd(mfd, PANEL_LATE_ON, true); + mipi_samsung_disp_backlight(mfd); + } else { + mfd->fbi->fbops->fb_blank(FB_BLANK_POWERDOWN, mfd->fbi); + } + + pr_info("mipi_samsung_disp_set_power\n"); + return 0; +} +#endif + +static ssize_t mipi_samsung_disp_lcdtype_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char temp[20]; + + snprintf(temp, strnlen(msd.mpd->panel_name, 20) + 1, + msd.mpd->panel_name); + strncat(buf, temp, 20); + return strnlen(buf, 20); +} + +static ssize_t mipi_samsung_disp_gamma_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rc; + + rc = snprintf((char *)buf, sizeof(buf), "%d\n", msd.dstat.gamma_mode); + pr_info("gamma_mode: %d\n", *buf); + + return rc; +} + +static ssize_t mipi_samsung_disp_gamma_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + if (sysfs_streq(buf, "1") && !msd.dstat.gamma_mode) { + /* 1.9 gamma */ + msd.dstat.gamma_mode = GAMMA_1_9; + } else if (sysfs_streq(buf, "0") && msd.dstat.gamma_mode) { + /* 2.2 gamma */ + msd.dstat.gamma_mode = GAMMA_2_2; + } else { + pr_info("%s: Invalid argument!!", __func__); + } + + return size; +} + +static ssize_t mipi_samsung_disp_acl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rc; + + rc = snprintf((char *)buf, sizeof(buf), "%d\n", msd.dstat.acl_on); + pr_info("acl status: %d\n", *buf); + + return rc; +} + +static ssize_t mipi_samsung_disp_acl_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(msd.msm_pdev); + + if (!mfd->panel_power_on) { + pr_info("%s: panel is off state. updating state value.\n", + __func__); + if (sysfs_streq(buf, "1") && !msd.dstat.acl_on) + msd.dstat.acl_on = true; + else if (sysfs_streq(buf, "0") && msd.dstat.acl_on) + msd.dstat.acl_on = false; + else + pr_info("%s: Invalid argument!!", __func__); + } else { + if (sysfs_streq(buf, "1") && !msd.dstat.acl_on) { + if (msd.mpd->set_acl(mfd->bl_level)) + mipi_samsung_disp_send_cmd( + mfd, PANEL_ACL_OFF, true); + else { + mipi_samsung_disp_send_cmd( + mfd, PANEL_ACL_ON, true); + mipi_samsung_disp_send_cmd( + mfd, PANEL_ACL_UPDATE, true); +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + if (samsung_has_cmc624()) + cabc_onoff_ctrl(1); +#endif + } + msd.dstat.acl_on = true; + } else if (sysfs_streq(buf, "0") && msd.dstat.acl_on) { + mipi_samsung_disp_send_cmd(mfd, PANEL_ACL_OFF, true); + msd.dstat.acl_on = false; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + if (samsung_has_cmc624()) + cabc_onoff_ctrl(0); +#endif + } else { + pr_info("%s: Invalid argument!!", __func__); + } + } + + return size; +} + +static ssize_t mipi_samsung_auto_brightness_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rc; + + rc = snprintf((char *)buf, sizeof(buf), "%d\n", + msd.dstat.auto_brightness); + pr_info("auot_brightness: %d\n", *buf); + + return rc; +} + +static ssize_t mipi_samsung_auto_brightness_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + if (sysfs_streq(buf, "1")) + msd.dstat.auto_brightness = 1; + else if (sysfs_streq(buf, "0")) + msd.dstat.auto_brightness = 0; + else + pr_info("%s: Invalid argument!!", __func__); + + return size; +} + +#ifdef CONFIG_SAMSUNG_CMC624 +void mipi_samsung_oled_display_fast_init() +{ + struct msm_fb_data_type *mfd; + if (samsung_has_cmc624()) + msd.mpd->prepare_fast_cmd_array(LCD_Get_Value()); + else + msd.mpd->prepare_fast_cmd_array(bypass_LCD_Id()); + mfd = platform_get_drvdata(msd.msm_pdev); + mipi_samsung_disp_send_cmd(mfd, PANEL_READY_TO_ON_FAST, false); + mipi_samsung_disp_send_cmd(mfd, PANEL_ON, false); +} +#endif + +static struct lcd_ops mipi_samsung_disp_props = { +#ifdef WA_FOR_FACTORY_MODE + .get_power = NULL, + .set_power = NULL, +#else + .get_power = mipi_samsung_disp_get_power, + .set_power = mipi_samsung_disp_set_power, +#endif +}; + +#ifdef WA_FOR_FACTORY_MODE +static DEVICE_ATTR(lcd_power, S_IRUGO | S_IWUSR, + mipi_samsung_disp_get_power, + mipi_samsung_disp_set_power); +#endif +static DEVICE_ATTR(lcd_type, S_IRUGO, mipi_samsung_disp_lcdtype_show, NULL); +static DEVICE_ATTR(gamma_mode, S_IRUGO | S_IWUSR | S_IWGRP, + mipi_samsung_disp_gamma_mode_show, + mipi_samsung_disp_gamma_mode_store); +static DEVICE_ATTR(power_reduce, S_IRUGO | S_IWUSR | S_IWGRP, + mipi_samsung_disp_acl_show, + mipi_samsung_disp_acl_store); +static DEVICE_ATTR(auto_brightness, S_IRUGO | S_IWUSR | S_IWGRP, + mipi_samsung_auto_brightness_show, + mipi_samsung_auto_brightness_store); + +#endif + + +#ifdef READ_REGISTER_ESD +#define ID_E5H_IDLE 0x80 +#define ID_E5H_IDLE_2 0x84 +#define ID_E5H_IDLE_3 0x81 +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) +char error_id2_cmd[8] = { + 0x00, 0x00, 0x09, 0x40, 0xE5, 0x00, 0x06, 0xA0}; +#else +static char error_id2[2] = {0xE5, 0x00}; /* DTYPE_DCS_READ */ + +static struct dsi_cmd_desc error_id2_cmd = { + DTYPE_DCS_READ, 1, 0, 1, 0, sizeof(error_id2), error_id2}; +#endif +static char error_buf[2]; + +static void read_error_register(struct msm_fb_data_type *mfd) +{ + struct dsi_buf *rp, *tp; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + char *cmd_lp; +#else + struct dsi_cmd_desc *cmd; +#endif + + pm_qos_update_request(&pm_qos_req, + msm_cpuidle_get_deep_idle_latency()); + +#if CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + mutex_lock(&mipi_lp_mutex); +#endif + mutex_lock(&mfd->dma->ov_mutex); + + mipi_dsi_mdp_busy_wait(); + + tp = &msd.samsung_tx_buf; + rp = &msd.samsung_rx_buf; + + mipi_dsi_buf_init(rp); + mipi_dsi_buf_init(tp); + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + cmd_lp = &error_id2_cmd; + mipi_dsi_cmds_rx_lp(mfd, tp, rp, cmd_lp, 1); + error_buf[0] = *rp->data; + mipi_dsi_cmds_rx_lp(mfd, tp, rp, cmd_lp, 1); + + pr_debug("############ error buf E5 = %x\n", error_buf[0]); +#else + cmd = &error_id2_cmd; + mipi_dsi_cmds_rx(mfd, tp, rp, cmd, 1); + error_buf[0] = *rp->data; + pr_debug("############ error buf E5 %x\n", error_buf[0]); +#endif + + mutex_unlock(&mfd->dma->ov_mutex); +#if CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT + mutex_unlock(&mipi_lp_mutex); +#endif + pm_qos_update_request(&pm_qos_req, PM_QOS_DEFAULT_VALUE); +} + +static void esd_test_work_func(struct work_struct *work) +{ + static unsigned int esd_cnt; + struct msm_fb_data_type *mfd; + mfd = platform_get_drvdata(msd.msm_pdev); + + if (unlikely(!mfd)) { + pr_info("%s NO PDEV.\n", __func__); + return; + } + return; + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + read_error_register(mfd); + pr_info("%s E5H=0x%x esd_cnt:%d\n", __func__, error_buf[0], esd_cnt); +#else + read_error_register(mfd); + pr_info("%s end E5H=0x%x\n", __func__, + error_buf[0]); +#endif + if (ID_E5H_IDLE != error_buf[0]) { + if ((ID_E5H_IDLE_2 != error_buf[0]) && \ + (error_buf[0] != ID_E5H_IDLE_3)) { + pr_info("%s: E5H=%x 0AH=%x\n", __func__, + error_buf[0], error_buf[2]); + esd_execute(); + + esd_cnt++; + } + } + + if (mfd->resume_state != MIPI_SUSPEND_STATE) + queue_delayed_work(msd.mpd->esd_workqueue, + &(msd.mpd->esd_work), ESD_INTERVAL * HZ); + +} +#endif + +static int __devinit mipi_samsung_disp_probe(struct platform_device *pdev) +{ + int ret; + struct platform_device *msm_fb_added_dev; +#if defined(CONFIG_LCD_CLASS_DEVICE) + struct lcd_device *lcd_device; +#endif +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) + struct backlight_device *bd = NULL; +#endif + msd.dstat.acl_on = false; + + if (pdev->id == 0) { + msd.mipi_samsung_disp_pdata = pdev->dev.platform_data; +#ifdef CONFIG_SAMSUNG_CMC624 + if (samsung_has_cmc624()) { + printk(KERN_DEBUG "Is_There_cmc624 : CMC624 is there!!!!"); + samsung_cmc624_init(); + first_on = false; + } else { + printk(KERN_DEBUG "Is_There_cmc624 : CMC624 is not there!!!!"); + first_on = false; + } +#else + first_on = false; +#endif + return 0; + } + + msm_fb_added_dev = msm_fb_add_device(pdev); + +#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_LCD_CLASS_DEVICE) + msd.msm_pdev = msm_fb_added_dev; +#endif + +#if defined(CONFIG_HAS_EARLYSUSPEND) + msd.early_suspend.suspend = mipi_samsung_disp_early_suspend; + msd.early_suspend.resume = mipi_samsung_disp_late_resume; + msd.early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 10; + register_early_suspend(&msd.early_suspend); + +#endif + +#if defined(CONFIG_LCD_CLASS_DEVICE) + lcd_device = lcd_device_register("panel", &pdev->dev, NULL, + &mipi_samsung_disp_props); + + if (IS_ERR(lcd_device)) { + ret = PTR_ERR(lcd_device); + printk(KERN_ERR "lcd : failed to register device\n"); + return ret; + } + +#ifdef WA_FOR_FACTORY_MODE + sysfs_remove_file(&lcd_device->dev.kobj, + &dev_attr_lcd_power.attr); + + ret = sysfs_create_file(&lcd_device->dev.kobj, + &dev_attr_lcd_power.attr); + if (ret) { + pr_info("sysfs create fail-%s\n", + dev_attr_lcd_power.attr.name); + } +#endif + + ret = sysfs_create_file(&lcd_device->dev.kobj, + &dev_attr_lcd_type.attr); + if (ret) { + pr_info("sysfs create fail-%s\n", + dev_attr_lcd_type.attr.name); + } + + ret = sysfs_create_file(&lcd_device->dev.kobj, + &dev_attr_gamma_mode.attr); + if (ret) { + pr_info("sysfs create fail-%s\n", + dev_attr_gamma_mode.attr.name); + } + + ret = sysfs_create_file(&lcd_device->dev.kobj, + &dev_attr_power_reduce.attr); + if (ret) { + pr_info("sysfs create fail-%s\n", + dev_attr_power_reduce.attr.name); + } +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) + bd = backlight_device_register("panel", &lcd_device->dev, + NULL, NULL, NULL); + if (IS_ERR(bd)) { + ret = PTR_ERR(bd); + pr_info("backlight : failed to register device\n"); + return ret; + } + + ret = sysfs_create_file(&bd->dev.kobj, + &dev_attr_auto_brightness.attr); + if (ret) { + pr_info("sysfs create fail-%s\n", + dev_attr_auto_brightness.attr.name); + } +#endif +#endif +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_QHD_PT) \ + || defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + /* mdnie sysfs create */ + init_mdnie_class(); +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + if (samsung_has_cmc624()) { + ret = cmc624_sysfs_init(); + if (ret < 0) + pr_debug("CMC624 sysfs initialize FAILED\n"); + } else + init_mdnie_class(); +#endif + +#ifdef READ_REGISTER_ESD + msd.mpd->esd_workqueue = create_singlethread_workqueue("esd_workqueue"); + + if (!msd.mpd->esd_workqueue) { + pr_info("esd_workqueue create fail\n"); + return -ENOMEM; + } + + INIT_DELAYED_WORK(&(msd.mpd->esd_work), esd_test_work_func); + + wake_lock_init(&(msd.mpd->esd_wake_lock), + WAKE_LOCK_SUSPEND, "esd_workqueue_lock"); +#endif + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mipi_samsung_disp_probe, + .driver = { + .name = "mipi_samsung_oled", + }, + .shutdown = mipi_samsung_disp_shutdown +}; + +static struct msm_fb_panel_data samsung_panel_data = { + .on = mipi_samsung_disp_on, + .off = mipi_samsung_disp_off, + .set_backlight = mipi_samsung_disp_backlight, +}; + +static int ch_used[3]; + +int mipi_samsung_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel, + struct mipi_panel_data *mpd) +{ + struct platform_device *pdev = NULL; + int ret = 0; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + ch_used[channel] = TRUE; + + pdev = platform_device_alloc("mipi_samsung_oled", + (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + samsung_panel_data.panel_info = *pinfo; + msd.mpd = mpd; + if (!msd.mpd) { + printk(KERN_ERR + "%s: get mipi_panel_data failed!\n", __func__); + goto err_device_put; + } + mpd->msd = &msd; + ret = platform_device_add_data(pdev, &samsung_panel_data, + sizeof(samsung_panel_data)); + if (ret) { + printk(KERN_ERR + "%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + printk(KERN_ERR + "%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return ret; + +err_device_put: + platform_device_put(pdev); + return ret; +} + + +static int __init current_boot_mode(char *mode) +{ + /* + * 1 is recovery booting + * 0 is normal booting + */ + + if (strncmp(mode, "1", 1) == 0) + recovery_boot_mode = 1; + else + recovery_boot_mode = 0; + + pr_debug("%s %s", __func__, recovery_boot_mode == 1 ? + "recovery" : "normal"); + return 1; +} +__setup("androidboot.boot_recovery=", current_boot_mode); + +static int __init mipi_samsung_disp_init(void) +{ + mipi_dsi_buf_alloc(&msd.samsung_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&msd.samsung_rx_buf, DSI_BUF_SIZE); + + pm_qos_add_request(&pm_qos_req, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + + return platform_driver_register(&this_driver); +} +module_init(mipi_samsung_disp_init); diff --git a/drivers/video/msm/mipi_samsung_oled.h b/drivers/video/msm/mipi_samsung_oled.h new file mode 100644 index 00000000000..292d0f06b4b --- /dev/null +++ b/drivers/video/msm/mipi_samsung_oled.h @@ -0,0 +1,250 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "mipi_dsi.h" +#include + +#ifndef MIPI_SAMSUNG_OLED_H +#define MIPI_SAMSUNG_OLED_H + +#define USE_ACL +#define USE_ELVSS +#include "smart_dimming.h" + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) +#include "smart_mtp_s6e63m0.h" +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) +#include "smart_mtp_s6e8aa0x01.h" +#elif defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) +#include "smart_mtp_s6e39a0x02.h" +#elif defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) +#include "smart_mtp_ea8868.h" +#endif + +#define SmartDimming_useSampleValue +#define SmartDimming_CANDELA_UPPER_LIMIT (300) +#define MTP_DATA_SIZE (24) +#define MTP_DATA_SIZE_S6E63M0 (21) +#define MTP_DATA_SIZE_EA8868 (21) +#define ELVSS_DATA_SIZE (24) +#define MTP_REGISTER (0xD3) +#define ELVSS_REGISTER (0xD4) +#if defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) +#define SmartDimming_GammaUpdate_Pos (1) +#else +#define SmartDimming_GammaUpdate_Pos (2) +#endif +#define DIMMING_BL (20) + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) ||\ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) ||\ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) || \ + defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) +#define USE_READ_ID +#endif +enum mipi_samsung_cmd_list { +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + PANEL_READY_TO_ON_FAST, +#endif + PANEL_READY_TO_ON, + PANEL_READY_TO_OFF, + PANEL_ON, + PANEL_OFF, + PANEL_LATE_ON, + PANEL_EARLY_OFF, + PANEL_GAMMA_UPDATE, + PANEL_ELVSS_UPDATE, + PANEL_ACL_ON, + PANEL_ACL_OFF, + PANEL_ACL_UPDATE, + MTP_READ_ENABLE, + PANEL_BRIGHT_CTRL, +}; + +enum gamma_mode_list { + GAMMA_2_2 = 0, + GAMMA_1_9 = 1, + GAMMA_SMART = 2, +}; + +enum { + MIPI_RESUME_STATE, + MIPI_SUSPEND_STATE, +}; + +struct cmd_set { + struct dsi_cmd_desc *cmd; + int size; +}; + +struct gamma_table { + char *table; + int table_cnt; + int data_size; +}; + +struct mipi_panel_data { + const char panel_name[20]; + struct cmd_set ready_to_on; +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + struct cmd_set ready_to_on_4_8; + struct cmd_set ready_to_on_4_8_fast; + struct cmd_set ready_to_on_fast; +#endif + struct cmd_set ready_to_off; + struct cmd_set on; + struct cmd_set off; + struct cmd_set late_on; + struct cmd_set early_off; + struct cmd_set gamma_update; + struct cmd_set elvss_update; + struct cmd_set mtp_read_enable; +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + struct cmd_set elvss_update_4_8; +#endif + struct cmd_set acl_update; +#ifdef USE_ACL + struct cmd_set acl_on; + struct cmd_set acl_off; + boolean ldi_acl_stat; +#endif + struct str_smart_dim smart; + signed char lcd_current_cd_idx; + unsigned char lcd_mtp_data[MTP_DATA_SIZE+16] ; + unsigned char lcd_elvss_data[ELVSS_DATA_SIZE+16]; + unsigned char *gamma_smartdim; + unsigned char *gamma_initial; +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + unsigned char *gamma_smartdim_4_8; + int *lux_table; + int lux_table_max_cnt; + struct SMART_DIM smart_s6e8aa0x01; +#endif +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) ||\ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) ||\ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) || \ + defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + unsigned int manufacture_id; +#endif +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) + struct SMART_DIM smart_s6e63m0; +#endif +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) + struct SMART_DIM smart_s6e39a0x02; +#endif +#if defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + struct SMART_DIM smart_ea8868; +#endif + + int (*set_gamma)(int bl_level, enum gamma_mode_list gamma_mode); + int (*set_acl)(int bl_level); + int (*set_elvss)(int bl_level); +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) \ + || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + int (*prepare_brightness_control_cmd_array)(int lcd_type, int bl_level); + struct cmd_set combined_ctrl; +#endif +#ifdef CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT + int (*set_elvss_4_8)(int bl_level); + void (*prepare_fast_cmd_array)(int lcd_type); + +#endif + struct mipi_samsung_driver_data *msd; + struct workqueue_struct *esd_workqueue; + struct delayed_work esd_work; + struct wake_lock esd_wake_lock; +}; +struct display_status { + unsigned char acl_on; + unsigned char gamma_mode; /* 1: 1.9 gamma, 0: 2.2 gamma */ + unsigned char is_smart_dim_loaded; + unsigned char is_elvss_loaded; + unsigned char auto_brightness; +}; +struct mipi_samsung_driver_data { + struct dsi_buf samsung_tx_buf; + struct dsi_buf samsung_rx_buf; + struct msm_panel_common_pdata *mipi_samsung_disp_pdata; + struct mipi_panel_data *mpd; + struct display_status dstat; +#if defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif +#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_LCD_CLASS_DEVICE) + struct platform_device *msm_pdev; +#endif +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) + boolean esd_refresh; +#endif +}; +#if defined(CONFIG_MIPI_SAMSUNG_ESD_REFRESH) +extern void set_esd_refresh(boolean stat); +#endif + +struct dsi_cmd_desc_LCD { + int lux; + char strID[8]; + struct dsi_cmd_desc *cmd; +}; +int mipi_samsung_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel, + struct mipi_panel_data *mpd); + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) ||\ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) ||\ + defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) ||\ + defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) + +void reset_gamma_level(void); +unsigned char bypass_LCD_Id(void); +#endif + +#if defined(CONFIG_FB_MSM_MIPI_MAGNA_OLED_VIDEO_WVGA_PT) +int get_gamma_lux(void); +#endif + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) +extern u8 mtp_read_data[]; +bool Is_4_8LCD_bypass(void); +bool Is_4_65LCD_bypass(void); +#endif + +#if defined(CONFIG_MACH_APEXQ) +extern int poweroff_charging; +#endif + +#if defined(CONFIG_SAMSUNG_CMC624) +extern int cmc_fast_reset; +#endif +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT) +int mipi_dsi_cmds_rx_lp(struct msm_fb_data_type *mfd, + struct dsi_buf *tp, struct dsi_buf *rp, + char *cmds, int rlen); +#endif +#endif /* MIPI_SAMSUNG_OLED_H */ diff --git a/drivers/video/msm/mipi_samsung_oled_cmd_qhd_pt.c b/drivers/video/msm/mipi_samsung_oled_cmd_qhd_pt.c new file mode 100644 index 00000000000..5f18fa252fe --- /dev/null +++ b/drivers/video/msm/mipi_samsung_oled_cmd_qhd_pt.c @@ -0,0 +1,1115 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_fb.h" +#include "mipi_samsung_oled.h" + +static struct msm_panel_info pinfo; +#define MAX_GAMMA_VALUE 25 +static struct mipi_panel_data mipi_pd; + +/* + * GAMMA TABLE 2.2 Temporary... + */ +static char gamma_2_2[][26] = { + {0xFA, /* 70 cd */ + 0x02, 0x10, 0x10, 0x10, 0xD1, 0x34, 0xD0, 0xD6, 0xBA, 0xDC, + 0xE0, 0xD9, 0xE2, 0xC2, 0xC0, 0xBF, 0xD4, 0xD5, 0xD0, 0x00, + 0x73, 0x00, 0x59, 0x00, 0x82}, + + {0xFA, /* 80 cd */ + 0x02, 0x10, 0x10, 0x10, 0xD7, 0x39, 0xD6, 0xD6, 0xBF, 0xDD, + 0xE1, 0xDA, 0xE2, 0xC0, 0xBF, 0xBD, 0xD3, 0xD5, 0xCF, 0x00, + 0x78, 0x00, 0x5D, 0x00, 0x88}, + + {0xFA, /* 90 cd */ + 0x02, 0x10, 0x10, 0x10, 0xD7, 0x39, 0xD5, 0xD5, 0xBF, 0xDC, + 0xDF, 0xDA, 0xE0, 0xC1, 0xC0, 0xBD, 0xD2, 0xD4, 0xCF, 0x00, + 0x7C, 0x00, 0x60, 0x00, 0x8C}, + + {0xFA, /* 100 cd */ + 0x02, 0x10, 0x10, 0x10, 0xDD, 0x3A, 0xE3, 0xD7, 0xC5, 0xDD, + 0xDF, 0xDA, 0xDF, 0xC0, 0xBF, 0xBC, 0xD0, 0xD3, 0xCD, 0x00, + 0x81, 0x00, 0x64, 0x00, 0x92}, + + {0xFA, /* 110 cd */ + 0x02, 0x10, 0x10, 0x10, 0xE1, 0x43, 0xE2, 0xD6, 0xC5, 0xDC, + 0xDE, 0xDA, 0xDF, 0xBF, 0xBF, 0xBB, 0xD0, 0xD3, 0xCD, 0x00, + 0x85, 0x00, 0x67, 0x00, 0x96}, + + {0xFA, /* 120 cd */ + 0x02, 0x10, 0x10, 0x10, 0xE5, 0x48, 0xE4, 0xD5, 0xC5, 0xDB, + 0xDE, 0xDA, 0xDD, 0xBE, 0xBF, 0xBB, 0xD0, 0xD2, 0xCC, 0x00, + 0x88, 0x00, 0x6A, 0x00, 0x9A}, + + {0xFA, /* 130 cd */ + 0x02, 0x10, 0x10, 0x10, 0xE6, 0x4D, 0xE3, 0xD5, 0xC5, 0xDA, + 0xDD, 0xDA, 0xDD, 0xBE, 0xBE, 0xBA, 0xCE, 0xD1, 0xCA, 0x00, + 0x8C, 0x00, 0x6D, 0x00, 0x9F}, + + {0xFA, /* 140 cd */ + 0x02, 0x10, 0x10, 0x10, 0xE8, 0x51, 0xE4, 0xD6, 0xC9, 0xDB, + 0xDC, 0xD9, 0xDC, 0xBE, 0xBF, 0xBA, 0xCD, 0xD0, 0xC9, 0x00, + 0x90, 0x00, 0x70, 0x00, 0xA3}, + + {0xFA, /* 150 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEA, 0x57, 0xE9, 0xD6, 0xC9, 0xDA, + 0xDD, 0xDA, 0xDC, 0xBC, 0xBE, 0xB8, 0xCE, 0xD0, 0xCA, 0x00, + 0x92, 0x00, 0x72, 0x00, 0xA6}, + + {0xFA, /* 160 cd */ + 0x02, 0x10, 0x10, 0x10, 0xF0, 0x61, 0xEE, 0xD5, 0xC9, 0xD9, + 0xDD, 0xDA, 0xDB, 0xBC, 0xBE, 0xB9, 0xCC, 0xCF, 0xC8, 0x00, + 0x96, 0x00, 0x75, 0x00, 0xAA}, + + {0xFA, /* 170 cd */ + 0x02, 0x10, 0x10, 0x10, 0xF1, 0x81, 0xEE, 0xD4, 0xC9, 0xD9, + 0xDD, 0xDB, 0xDB, 0xBB, 0xBD, 0xB7, 0xCC, 0xCE, 0xC8, 0x00, + 0x99, 0x00, 0x78, 0x00, 0xAE}, + + {0xFA, /* 180 cd */ + 0x02, 0x10, 0x10, 0x10, 0xF0, 0x8C, 0xED, 0xD5, 0xCA, 0xD8, + 0xDC, 0xDB, 0xDC, 0xBB, 0xBD, 0xB7, 0xCB, 0xCD, 0xC5, 0x00, + 0x9C, 0x00, 0x7A, 0x00, 0xB2}, + + {0xFA, /* 190 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0x90, 0xEC, 0xD4, 0xC9, 0xD7, + 0xDD, 0xDB, 0xDB, 0xBA, 0xBD, 0xB7, 0xCA, 0xCD, 0xC5, 0x00, + 0x9F, 0x00, 0x7C, 0x00, 0xB5}, + + {0xFA, /* 200 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0x8F, 0xED, 0xD2, 0xC7, 0xD5, + 0xDC, 0xDA, 0xDA, 0xBA, 0xBB, 0xB5, 0xCA, 0xCC, 0xC4, 0x00, + 0xA0, 0x00, 0x7F, 0x00, 0xBB}, + + {0xFA, /* 210 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEF, 0x96, 0xEF, 0xD1, 0xC7, 0xD3, + 0xDB, 0xD9, 0xD9, 0xB9, 0xBB, 0xB4, 0xCA, 0xCC, 0xC6, 0x00, + 0xA3, 0x00, 0x81, 0x00, 0xBD}, + + {0xFA, /* 220 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0x99, 0xEE, 0xD3, 0xC8, 0xD3, + 0xDB, 0xD9, 0xD9, 0xB8, 0xBB, 0xB4, 0xC9, 0xCC, 0xC4, 0x00, + 0xA6, 0x00, 0x83, 0x00, 0xC1}, + + {0xFA, /* 230 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEE, 0xA3, 0xEF, 0xD2, 0xC9, 0xD3, + 0xDB, 0xD9, 0xD9, 0xB9, 0xBA, 0xB3, 0xC8, 0xCC, 0xC4, 0x00, + 0xA8, 0x00, 0x85, 0x00, 0xC4}, + + {0xFA, /* 240 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0xA4, 0xEE, 0xD2, 0xC9, 0xD3, + 0xDC, 0xD9, 0xD9, 0xB7, 0xBA, 0xB3, 0xC8, 0xCB, 0xC2, 0x00, + 0xAB, 0x00, 0x87, 0x00, 0xC8}, + + {0xFA, /* 250 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0xA8, 0xEF, 0xD2, 0xC8, 0xD2, + 0xDA, 0xD9, 0xD8, 0xB7, 0xB9, 0xB2, 0xC8, 0xCB, 0xC2, 0x00, + 0xAD, 0x00, 0x89, 0x00, 0xCB}, + + {0xFA, /* 260 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEB, 0xB2, 0xEF, 0xD2, 0xC9, 0xD3, + 0xDB, 0xDA, 0xD9, 0xB6, 0xB9, 0xBA, 0xC7, 0xCA, 0xC1, 0x00, + 0xB0, 0x00, 0x8B, 0x00, 0xCE}, + + {0xFA, /* 270 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEC, 0xB0, 0xEF, 0xD1, 0xC9, 0xD2, + 0xDB, 0xDA, 0xD9, 0xB7, 0xB9, 0xB1, 0xC6, 0xC9, 0xC0, 0x00, + 0xB2, 0x00, 0x8D, 0x00, 0xD1}, + + {0xFA, /* 280 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0xB6, 0xF0, 0xD1, 0xC9, 0xD2, + 0xDB, 0xDA, 0xD9, 0xB6, 0xB8, 0xAF, 0xC7, 0xCA, 0xC2, 0x00, + 0xB4, 0x00, 0x8F, 0x00, 0xD3}, + + {0xFA, /* 290 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEC, 0xB7, 0xEE, 0xD0, 0xC8, 0xD1, + 0xDB, 0xDA, 0xD9, 0xB6, 0xB8, 0xB0, 0xC5, 0xC9, 0xC1, 0x00, + 0xB7, 0x00, 0x91, 0x00, 0xD5}, + + {0xFA, /* 300 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEC, 0xB7, 0xEF, 0xD1, 0xCA, 0xD1, + 0xDB, 0xDA, 0xD8, 0xB5, 0xB8, 0xB0, 0xC5, 0xC8, 0xBF, 0x00, + 0xB9, 0x00, 0x93, 0x00, 0xD9}, +}; + +/* + * GAMMA TABLE 1.9 Temporary... + */ +static char gamma_1_9[][26] = { + {0xFA, /* 70 cd */ + 0x02, 0x10, 0x10, 0x10, 0xD1, 0x34, 0xD0, 0xD6, 0xBA, 0xDC, + 0xE0, 0xD9, 0xE2, 0xC2, 0xC0, 0xBF, 0xD4, 0xD5, 0xD0, 0x00, + 0x73, 0x00, 0x59, 0x00, 0x82}, + + {0xFA, /* 80 cd */ + 0x02, 0x10, 0x10, 0x10, 0xD7, 0x39, 0xD6, 0xD6, 0xBF, 0xDD, + 0xE1, 0xDA, 0xE2, 0xC0, 0xBF, 0xBD, 0xD3, 0xD5, 0xCF, 0x00, + 0x78, 0x00, 0x5D, 0x00, 0x88}, + + {0xFA, /* 90 cd */ + 0x02, 0x10, 0x10, 0x10, 0xD7, 0x39, 0xD5, 0xD5, 0xBF, 0xDC, + 0xDF, 0xDA, 0xE0, 0xC1, 0xC0, 0xBD, 0xD2, 0xD4, 0xCF, 0x00, + 0x7C, 0x00, 0x60, 0x00, 0x8C}, + + {0xFA, /* 100 cd */ + 0x02, 0x10, 0x10, 0x10, 0xDD, 0x3A, 0xE3, 0xD7, 0xC5, 0xDD, + 0xDF, 0xDA, 0xDF, 0xC0, 0xBF, 0xBC, 0xD0, 0xD3, 0xCD, 0x00, + 0x81, 0x00, 0x64, 0x00, 0x92}, + + {0xFA, /* 110 cd */ + 0x02, 0x10, 0x10, 0x10, 0xE1, 0x43, 0xE2, 0xD6, 0xC5, 0xDC, + 0xDE, 0xDA, 0xDF, 0xBF, 0xBF, 0xBB, 0xD0, 0xD3, 0xCD, 0x00, + 0x85, 0x00, 0x67, 0x00, 0x96}, + + {0xFA, /* 120 cd */ + 0x02, 0x10, 0x10, 0x10, 0xE5, 0x48, 0xE4, 0xD5, 0xC5, 0xDB, + 0xDE, 0xDA, 0xDD, 0xBE, 0xBF, 0xBB, 0xD0, 0xD2, 0xCC, 0x00, + 0x88, 0x00, 0x6A, 0x00, 0x9A}, + + {0xFA, /* 130 cd */ + 0x02, 0x10, 0x10, 0x10, 0xE6, 0x4D, 0xE3, 0xD5, 0xC5, 0xDA, + 0xDD, 0xDA, 0xDD, 0xBE, 0xBE, 0xBA, 0xCE, 0xD1, 0xCA, 0x00, + 0x8C, 0x00, 0x6D, 0x00, 0x9F}, + + {0xFA, /* 140 cd */ + 0x02, 0x10, 0x10, 0x10, 0xE8, 0x51, 0xE4, 0xD6, 0xC9, 0xDB, + 0xDC, 0xD9, 0xDC, 0xBE, 0xBF, 0xBA, 0xCD, 0xD0, 0xC9, 0x00, + 0x90, 0x00, 0x70, 0x00, 0xA3}, + + {0xFA, /* 150 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEA, 0x57, 0xE9, 0xD6, 0xC9, 0xDA, + 0xDD, 0xDA, 0xDC, 0xBC, 0xBE, 0xB8, 0xCE, 0xD0, 0xCA, 0x00, + 0x92, 0x00, 0x72, 0x00, 0xA6}, + + {0xFA, /* 160 cd */ + 0x02, 0x10, 0x10, 0x10, 0xF0, 0x61, 0xEE, 0xD5, 0xC9, 0xD9, + 0xDD, 0xDA, 0xDB, 0xBC, 0xBE, 0xB9, 0xCC, 0xCF, 0xC8, 0x00, + 0x96, 0x00, 0x75, 0x00, 0xAA}, + + {0xFA, /* 170 cd */ + 0x02, 0x10, 0x10, 0x10, 0xF1, 0x81, 0xEE, 0xD4, 0xC9, 0xD9, + 0xDD, 0xDB, 0xDB, 0xBB, 0xBD, 0xB7, 0xCC, 0xCE, 0xC8, 0x00, + 0x99, 0x00, 0x78, 0x00, 0xAE}, + + {0xFA, /* 180 cd */ + 0x02, 0x10, 0x10, 0x10, 0xF0, 0x8C, 0xED, 0xD5, 0xCA, 0xD8, + 0xDC, 0xDB, 0xDC, 0xBB, 0xBD, 0xB7, 0xCB, 0xCD, 0xC5, 0x00, + 0x9C, 0x00, 0x7A, 0x00, 0xB2}, + + {0xFA, /* 190 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0x90, 0xEC, 0xD4, 0xC9, 0xD7, + 0xDD, 0xDB, 0xDB, 0xBA, 0xBD, 0xB7, 0xCA, 0xCD, 0xC5, 0x00, + 0x9F, 0x00, 0x7C, 0x00, 0xB5}, + + {0xFA, /* 200 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0x8F, 0xED, 0xD2, 0xC7, 0xD5, + 0xDC, 0xDA, 0xDA, 0xBA, 0xBB, 0xB5, 0xCA, 0xCC, 0xC4, 0x00, + 0xA0, 0x00, 0x7F, 0x00, 0xBB}, + + {0xFA, /* 210 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEF, 0x96, 0xEF, 0xD1, 0xC7, 0xD3, + 0xDB, 0xD9, 0xD9, 0xB9, 0xBB, 0xB4, 0xCA, 0xCC, 0xC6, 0x00, + 0xA3, 0x00, 0x81, 0x00, 0xBD}, + + {0xFA, /* 220 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0x99, 0xEE, 0xD3, 0xC8, 0xD3, + 0xDB, 0xD9, 0xD9, 0xB8, 0xBB, 0xB4, 0xC9, 0xCC, 0xC4, 0x00, + 0xA6, 0x00, 0x83, 0x00, 0xC1}, + + {0xFA, /* 230 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEE, 0xA3, 0xEF, 0xD2, 0xC9, 0xD3, + 0xDB, 0xD9, 0xD9, 0xB9, 0xBA, 0xB3, 0xC8, 0xCC, 0xC4, 0x00, + 0xA8, 0x00, 0x85, 0x00, 0xC4}, + + {0xFA, /* 240 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0xA4, 0xEE, 0xD2, 0xC9, 0xD3, + 0xDC, 0xD9, 0xD9, 0xB7, 0xBA, 0xB3, 0xC8, 0xCB, 0xC2, 0x00, + 0xAB, 0x00, 0x87, 0x00, 0xC8}, + + {0xFA, /* 250 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0xA8, 0xEF, 0xD2, 0xC8, 0xD2, + 0xDA, 0xD9, 0xD8, 0xB7, 0xB9, 0xB2, 0xC8, 0xCB, 0xC2, 0x00, + 0xAD, 0x00, 0x89, 0x00, 0xCB}, + + {0xFA, /* 260 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEB, 0xB2, 0xEF, 0xD2, 0xC9, 0xD3, + 0xDB, 0xDA, 0xD9, 0xB6, 0xB9, 0xBA, 0xC7, 0xCA, 0xC1, 0x00, + 0xB0, 0x00, 0x8B, 0x00, 0xCE}, + + {0xFA, /* 270 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEC, 0xB0, 0xEF, 0xD1, 0xC9, 0xD2, + 0xDB, 0xDA, 0xD9, 0xB7, 0xB9, 0xB1, 0xC6, 0xC9, 0xC0, 0x00, + 0xB2, 0x00, 0x8D, 0x00, 0xD1}, + + {0xFA, /* 280 cd */ + 0x02, 0x10, 0x10, 0x10, 0xED, 0xB6, 0xF0, 0xD1, 0xC9, 0xD2, + 0xDB, 0xDA, 0xD9, 0xB6, 0xB8, 0xAF, 0xC7, 0xCA, 0xC2, 0x00, + 0xB4, 0x00, 0x8F, 0x00, 0xD3}, + + {0xFA, /* 290 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEC, 0xB7, 0xEE, 0xD0, 0xC8, 0xD1, + 0xDB, 0xDA, 0xD9, 0xB6, 0xB8, 0xB0, 0xC5, 0xC9, 0xC1, 0x00, + 0xB7, 0x00, 0x91, 0x00, 0xD5}, + + {0xFA, /* 300 cd */ + 0x02, 0x10, 0x10, 0x10, 0xEC, 0xB7, 0xEF, 0xD1, 0xCA, 0xD1, + 0xDB, 0xDA, 0xD8, 0xB5, 0xB8, 0xB0, 0xC5, 0xC8, 0xBF, 0x00, + 0xB9, 0x00, 0x93, 0x00, 0xD9}, +}; + + +/* + * [1] ETC Condition Set 1 + */ +static char etc_cond_set_1_1[] = { + 0xF0, + 0x5A, 0x5A +}; +static char etc_cond_set_1_2[] = { + 0xF1, + 0x5A, 0x5A +}; +static char etc_cond_set_1_3[] = { + 0xFC, + 0x5A, 0x5A +}; + +/* + * [2] Gamma Condition Set + */ +static char gamma_cond_set[] = { + 0xFA, /* 70 cd */ + 0x02, 0x58, 0x42, 0x56, 0xa8, + 0xc3, 0xae, 0xbd, 0xc6, 0xc2, 0xae, + 0xbe, 0xaf, 0x99, 0xa4, 0x99, 0xac, + 0xb3, 0xa8, 0x00, 0xc1, 0x00, 0xb7, + 0x00, 0xdf +}; +static char gamma_set_update[] = { + 0xFA, + 0x03 +}; + +/* + * [3] Panel Condition Set + */ +static char panel_cond_set1[] = { + 0xF8, + 0x27, 0x27, 0x08, 0x08, 0x4E, + 0xAA, 0x5E, 0x8A, 0x10, 0x3F, + 0x10, 0x10, 0x00 +}; +static char panel_cond_set2[] = { + 0xF7, + 0x03 +}; +static char panel_cond_set3[] = { + 0xB3, + 0x63, 0x02, 0xC3, 0x32, 0xFF +}; + +/* + * [4] ETC Condition Set 2 + */ +static char etc_cond_set_2_1[] = { + 0xF6, + 0x00, 0x84, 0x09 +}; +static char etc_cond_set_2_2[] = { + 0xB0, + 0x09 +}; +static char etc_cond_set_2_3[] = { + 0xD5, + 0x64 +}; +static char etc_cond_set_2_4[] = { + 0xB0, + 0x0B +}; +static char etc_cond_set_2_5[] = { + 0xD5, + 0xA4, 0x7E, 0x20 +}; +static char etc_cond_set_2_6[] = { + 0xB0, + 0x08 +}; +static char etc_cond_set_2_7[] = { +/* FDh is hidden command */ + 0xFD, + 0xF8 +}; +static char etc_cond_set_2_8[] = { + 0xB0, + 0x04 +}; +static char etc_cond_set_2_9[] = { + 0xF2, + 0x4D +}; + +static char etc_cond_set_2_10[] = { + 0xB0, + 0x05 +}; +static char etc_cond_set_2_11[] = { + 0xFD, + 0x1F +}; + +static char etc_cond_set_2_12[] = { + 0xB1, + 0x01, 0x00, 0x16 +}; + +static char etc_cond_set_2_13[] = { + 0xB2, + 0x15, 0x15, 0x15, 0x15 +}; +static char etc_cond_set_2_14[] = { 0x11, /* no param */ }; + +/* + * [5] Memory window setting 1 + */ +static char memory_window_set_1_1[] = { + 0x2A, + 0x00, 0x00, 0x02, 0x57 +}; +static char memory_window_set_1_2[] = { + 0x2B, + 0x00, 0x00, 0x03, 0xFF +}; +static char memory_window_set_1_3[] = { 0x2C, /* no param */ }; + +/* + * [6] Memory window setting 2 + */ +static char memory_window_set_2_1[] = { 0x35, /* no param */ }; +static char memory_window_set_2_2[] = { + 0x2A, + 0x00, 0x1E, 0x02, 0x39 +}; +static char memory_window_set_2_3[] = { + 0x2B, + 0x00, 0x00, 0x03, 0xBF +}; +static char memory_window_set_2_4[] = { + 0xD1, + 0x8A +}; + +/* + * [7] ACL ON/OFF setting + */ +#ifdef USE_ACL +static char acl_cond_set[] = { + /* + * There is LDI defect on acl process. + * So setting 0xC1 register all zero instead of + * setting 0xC0 register to 0x00 + */ + 0xC1, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +static char acl_const_set[] = { + /* + * There is LDI defect on acl process. + * So setting 0xC1 register all zero instead of + * setting 0xC0 register to 0x00 + */ + 0xC1, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +static char acl_on[] = { + 0xC0, + 0x01 +}; + +static char acl_off[] = { + /* + * There is LDI defect on acl process. + * So setting 0xC1 register all zero instead of + * setting 0xC0 register to 0x00 + */ + 0xC1, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#endif +#ifdef USE_ELVSS +static char each_elvss_cond_set[] = { 0xB2, 0x15, 0x15, 0x15, 0x15}; +#endif +enum { + GAMMA_30CD, + GAMMA_40CD, + GAMMA_50CD, + GAMMA_60CD, + GAMMA_70CD, + GAMMA_80CD, + GAMMA_90CD, + GAMMA_100CD, + GAMMA_110CD, + GAMMA_120CD, + GAMMA_130CD, + GAMMA_140CD, + GAMMA_150CD, + GAMMA_160CD, + GAMMA_170CD, + GAMMA_180CD, + GAMMA_190CD, + GAMMA_200CD, + GAMMA_210CD, + GAMMA_220CD, + GAMMA_230CD, + GAMMA_240CD, + GAMMA_250CD, + GAMMA_300CD, +}; + +static int lux_tbl_acl[] = { + 30, 40, 50, 60, 70, 80, + 90, 100, 110, 120, 130, 140, + 150, 160, 170, 180, 190, 200, + 210, 220, 230, 240, 250, 300 +}; + +static char gamma_cond_300cd[] = { + 0x58, 0x42, 0x56, 0xAA, + 0xC8, 0xAE, 0xB5, 0xC1, 0xBE, + 0xB4, 0xC0, 0xB2, 0x93, 0x9F, + 0x93, 0xA6, 0xAD, 0xA2, 0x00, + 0xE9, 0x00, 0xDB, 0x01, 0x0F +}; + +static char GAMMA_SmartDimming_COND_SET[] = { + 0xFA, + 0x02, 0x4A, 0x01, 0x4D, 0x7A, + 0x5D, 0xA5, 0x9C, 0xCA, 0xA4, + 0xBD, 0xDC, 0xBE, 0x93, 0xBD, + 0x95, 0xBA, 0xD2, 0xB7, 0x00, + 0x81, 0x00, 0x75, 0x00, 0xA5, +}; + +static char prepare_mtp_read1[] = { + 0xF0, + 0x5A, 0x5A +}; + +static char prepare_mtp_read2[] = { + 0xF1, + 0x5A, 0x5A +}; + +#ifdef USE_ACL +static struct dsi_cmd_desc samsung_panel_acl_on_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(acl_const_set), acl_const_set}, +}; + +static struct dsi_cmd_desc samsung_panel_acl_off_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(acl_off), acl_off}, +}; +static struct dsi_cmd_desc samsung_panel_acl_update_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(acl_cond_set), acl_cond_set} + , +}; +#endif + +/* + * Display On, Stand-by Off Command + */ +static char all_pixel_off[] = { 0x22, /* no param */ }; +static char normal_mode_on[] = { 0x13, /* no parm */ }; +static char display_on[] = { 0x29, /* no param */ }; +static char display_off[] = { 0x28, /* no param */ }; +static char sleep_in[] = { 0x10, /* no param */ }; + +static struct dsi_cmd_desc samsung_mtp_read_cmds[] = { + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(prepare_mtp_read1), prepare_mtp_read1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(prepare_mtp_read2), prepare_mtp_read2}, +}; + +static struct dsi_cmd_desc samsung_panel_ready_to_on_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_1_1), etc_cond_set_1_1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_1_2), etc_cond_set_1_2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_1_3), etc_cond_set_1_3}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_cond_set), gamma_cond_set}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_set1), panel_cond_set1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_set2), panel_cond_set2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_set3), panel_cond_set3}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_1), etc_cond_set_2_1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_2), etc_cond_set_2_2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_3), etc_cond_set_2_3}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_4), etc_cond_set_2_4}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_5), etc_cond_set_2_5}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_6), etc_cond_set_2_6}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_7), etc_cond_set_2_7}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_8), etc_cond_set_2_8}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_9), etc_cond_set_2_9}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_10), etc_cond_set_2_10}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_11), etc_cond_set_2_11}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_12), etc_cond_set_2_12}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_13), etc_cond_set_2_13}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set_2_14), etc_cond_set_2_14}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 120, + sizeof(memory_window_set_1_1), memory_window_set_1_1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(memory_window_set_1_2), memory_window_set_1_2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 1, + sizeof(memory_window_set_1_3), memory_window_set_1_3}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(memory_window_set_2_1), memory_window_set_2_1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(memory_window_set_2_2), memory_window_set_2_2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(memory_window_set_2_3), memory_window_set_2_3}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(memory_window_set_2_4), memory_window_set_2_4}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(acl_const_set), acl_const_set}, +}; + +static struct dsi_cmd_desc samsung_panel_ready_to_off_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(display_off), display_off}, +}; + +static struct dsi_cmd_desc samsung_panel_on_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(display_on), display_on}, +}; + +static struct dsi_cmd_desc samsung_panel_off_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(sleep_in), sleep_in}, +}; + +static struct dsi_cmd_desc samsung_panel_late_on_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(normal_mode_on), normal_mode_on}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 5, + sizeof(display_on), display_on}, +}; + +static struct dsi_cmd_desc samsung_panel_early_off_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(all_pixel_off), all_pixel_off}, +}; + +static struct dsi_cmd_desc samsung_panel_gamma_update_cmds[2] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_2_2[0]), gamma_2_2[0]}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update}, +}; + +static struct dsi_cmd_desc samsung_panel_elvss_update_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(each_elvss_cond_set), each_elvss_cond_set} + , +}; + +#define LCD_ELVSS_DELTA_300CD (0) +#define LCD_ELVSS_DELTA_200CD (0x08) +#define LCD_ELVSS_DELTA_160CD (0x0B) +#define LCD_ELVSS_DELTA_100CD (0x10) +#define LCD_ELVSS_RESULT_LIMIT (0x29) +static int GET_EACH_ELVSS_ID[] = { + LCD_ELVSS_DELTA_100CD,/* 0 = 30_dimming,*/ + LCD_ELVSS_DELTA_100CD,/* 1 = 40*/ + LCD_ELVSS_DELTA_100CD,/* 2 = 50*/ + LCD_ELVSS_DELTA_100CD,/* 3 = 60,*/ + LCD_ELVSS_DELTA_100CD,/* 4 = 70,*/ + LCD_ELVSS_DELTA_100CD,/* 5 = 80,*/ + LCD_ELVSS_DELTA_100CD,/* 6 = 90,*/ + LCD_ELVSS_DELTA_100CD,/* 7 = 100,*/ + LCD_ELVSS_DELTA_160CD,/* 8 = 110,*/ + LCD_ELVSS_DELTA_160CD,/* 9 = 120,*/ + LCD_ELVSS_DELTA_160CD,/* 10 = 130,*/ + LCD_ELVSS_DELTA_160CD,/* 11 = 140,*/ + LCD_ELVSS_DELTA_160CD,/* 12 = 150,*/ + LCD_ELVSS_DELTA_160CD,/* 13 = 160,*/ + LCD_ELVSS_DELTA_200CD,/* 14 = 170,*/ + LCD_ELVSS_DELTA_200CD,/* 15 = 180,*/ + LCD_ELVSS_DELTA_200CD,/* 16 = 190,*/ + LCD_ELVSS_DELTA_200CD,/* 17 = 200,*/ + LCD_ELVSS_DELTA_300CD,/* 18 = 210,*/ + LCD_ELVSS_DELTA_300CD,/* 19 = 220,*/ + LCD_ELVSS_DELTA_300CD,/* 20 = 230,*/ + LCD_ELVSS_DELTA_300CD,/* 21 = 240,*/ + LCD_ELVSS_DELTA_300CD,/* 22 = 250,*/ + LCD_ELVSS_DELTA_300CD/* 23= 300,*/ +}; + + +#define LCD_ELVSS_DEFAULT_100CD (0x25) +#define LCD_ELVSS_DEFAULT_160CD (0x20) +#define LCD_ELVSS_DEFAULT_200CD (0x1D) +#define LCD_ELVSS_DEFAULT_300CD (0x15) +static int GET_DEFAULT_ELVSS_ID[] = { + LCD_ELVSS_DEFAULT_100CD,/* 0 = 30_dimming,*/ + LCD_ELVSS_DEFAULT_100CD,/* 1 = 40*/ + LCD_ELVSS_DEFAULT_100CD,/* 2 = 50*/ + LCD_ELVSS_DEFAULT_100CD,/* 3 = 60,*/ + LCD_ELVSS_DEFAULT_100CD,/* 4 = 70,*/ + LCD_ELVSS_DEFAULT_100CD,/* 5 = 80,*/ + LCD_ELVSS_DEFAULT_100CD,/* 6 = 90,*/ + LCD_ELVSS_DEFAULT_100CD,/* 7 = 100,*/ + LCD_ELVSS_DEFAULT_160CD,/* 8 = 110,*/ + LCD_ELVSS_DEFAULT_160CD,/* 9 = 120,*/ + LCD_ELVSS_DEFAULT_160CD,/* 10 = 130,*/ + LCD_ELVSS_DEFAULT_160CD,/* 11 = 140,*/ + LCD_ELVSS_DEFAULT_160CD,/* 12 = 150,*/ + LCD_ELVSS_DEFAULT_160CD,/* 13 = 160,*/ + LCD_ELVSS_DEFAULT_200CD,/* 14 = 170,*/ + LCD_ELVSS_DEFAULT_200CD,/* 15 = 180,*/ + LCD_ELVSS_DEFAULT_200CD,/* 16 = 190,*/ + LCD_ELVSS_DEFAULT_200CD,/* 17 = 200,*/ + LCD_ELVSS_DEFAULT_300CD,/* 18 = 210,*/ + LCD_ELVSS_DEFAULT_300CD,/* 19 = 220,*/ + LCD_ELVSS_DEFAULT_300CD,/* 20 = 230,*/ + LCD_ELVSS_DEFAULT_300CD,/* 21 = 240,*/ + LCD_ELVSS_DEFAULT_300CD,/* 22 = 250,*/ + LCD_ELVSS_DEFAULT_300CD/* 23 = 300,*/ +}; + + +/********************* ACL *******************/ +static char ACL_COND_SET_50[] = { + 0xC1, 0x05, 0x0A, 0x0F, 0x16, 0x1B, 0x21, 0x26, 0x2A, 0x2F, 0x35, 0x3A, + 0x3F, 0x44, 0x49, 0x49, 0x00, }; +static char ACL_COND_SET_40[] = { + 0xC1, 0x03, 0x07, 0x0D, 0x12, 0x16, 0x1A, 0x1D, 0x21, 0x25, 0x28, 0x2D, + 0x31, 0x35, 0x38, 0x38, 0x00, }; +static char ACL_COND_SET_33[] = { + 0xC1, 0x03, 0x05, 0x0A, 0x0F, 0x12, 0x16, 0x18, 0x1B, 0x1E, 0x21, 0x25, + 0x2A, 0x2B, 0x2E, 0x2E, 0x00, }; +static char ACL_COND_SET_20[] = { + 0xC1, 0x02, 0x04, 0x06, 0x09, 0x0B, 0x0F, 0x10, 0x11, 0x12, 0x14, 0x17, + 0x18, 0x1A, 0x1B, 0x1B, 0x00, }; +static char ACL_COND_SET_0[] = { + 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, }; + +static struct dsi_cmd_desc DSI_CMD_ACL_50 = { +DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(ACL_COND_SET_50), ACL_COND_SET_50 }; +static struct dsi_cmd_desc DSI_CMD_ACL_40 = { +DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(ACL_COND_SET_40), ACL_COND_SET_40 }; +static struct dsi_cmd_desc DSI_CMD_ACL_33 = { +DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(ACL_COND_SET_33), ACL_COND_SET_33 }; +static struct dsi_cmd_desc DSI_CMD_ACL_20 = { +DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(ACL_COND_SET_20), ACL_COND_SET_20 }; +static struct dsi_cmd_desc DSI_CMD_ACL_0 = { +DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(ACL_COND_SET_0), ACL_COND_SET_0 }; +static struct dsi_cmd_desc_LCD lcd_acl_table[] = { + {30, "30", &DSI_CMD_ACL_0}, + {30, "40", &DSI_CMD_ACL_0}, + {40, "50", &DSI_CMD_ACL_40}, + {40, "60", &DSI_CMD_ACL_40}, + {40, "70", &DSI_CMD_ACL_40}, + {40, "80", &DSI_CMD_ACL_40}, + {40, "90", &DSI_CMD_ACL_40}, + {40, "100", &DSI_CMD_ACL_40}, + {40, "110", &DSI_CMD_ACL_40}, + {40, "120", &DSI_CMD_ACL_40}, + {40, "130", &DSI_CMD_ACL_40}, + {40, "140", &DSI_CMD_ACL_40}, + {40, "150", &DSI_CMD_ACL_40}, + {40, "160", &DSI_CMD_ACL_40}, + {40, "170", &DSI_CMD_ACL_40}, + {40, "180", &DSI_CMD_ACL_40}, + {40, "190", &DSI_CMD_ACL_40}, + {40, "200", &DSI_CMD_ACL_40}, + {40, "210", &DSI_CMD_ACL_40}, + {40, "220", &DSI_CMD_ACL_40}, + {40, "230", &DSI_CMD_ACL_40}, + {40, "240", &DSI_CMD_ACL_40}, + {40, "250", &DSI_CMD_ACL_40}, + {50, "300", &DSI_CMD_ACL_50}, +}; + +static int get_candela_index(int bl_level) +{ + int backlightlevel; + + /* brightness setting from platform is from 0 to 255 + * But in this driver, brightness is only supported from 0 to 24 */ + + switch (bl_level) { + case 0 ... 29: + if (mipi_pd.msd->dstat.auto_brightness == 1) + backlightlevel = GAMMA_40CD; /* 1 */ + else + backlightlevel = GAMMA_30CD; /* 0*/ + break; + case 30 ... 49: + backlightlevel = GAMMA_40CD; /* 1 */ + break; + case 50 ... 59: + backlightlevel = GAMMA_50CD; /* 3 */ + break; + case 60 ... 69: + backlightlevel = GAMMA_60CD; /* 4 */ + break; + case 70 ... 79: + backlightlevel = GAMMA_70CD; /* 5 */ + break; + case 80 ... 89: + backlightlevel = GAMMA_80CD; /* 6 */ + break; + case 90 ... 99: + backlightlevel = GAMMA_90CD; /* 8 */ + break; + case 100 ... 109: + backlightlevel = GAMMA_100CD; /* 9 */ + break; + case 110 ... 119: + backlightlevel = GAMMA_110CD; /* 10 */ + break; + case 120 ... 125: + backlightlevel = GAMMA_120CD; /* 11 */ + break; + case 126 ... 129: + backlightlevel = GAMMA_130CD; /* 11 */ + break; + case 130 ... 135: + backlightlevel = GAMMA_140CD; /* 12 */ + break; + case 136 ... 139: + backlightlevel = GAMMA_150CD; /* 12 */ + break; + case 140 ... 149: + backlightlevel = GAMMA_160CD; /* 13 */ + break; + case 150 ... 159: + backlightlevel = GAMMA_170CD; /* 14 */ + break; + case 160 ... 169: + backlightlevel = GAMMA_180CD; /* 15 */ + break; + case 170 ... 179: + backlightlevel = GAMMA_190CD; /* 15 */ + break; + case 180 ... 189: + backlightlevel = GAMMA_200CD; /* 15 */ + break; + case 190 ... 199: + backlightlevel = GAMMA_210CD; /* 16 */ + break; + case 200 ... 219: + backlightlevel = GAMMA_220CD; /* 19 */ + break; + case 220 ... 239: + backlightlevel = GAMMA_230CD; /* 20 */ + break; + case 240 ... 249: + backlightlevel = GAMMA_240CD; /* 21 */ + break; + case 250 ... 254: + backlightlevel = GAMMA_250CD; /* 22 */ + break; + case 255: + if (mipi_pd.msd->dstat.auto_brightness == 1) + backlightlevel = GAMMA_300CD; /* 23 */ + else + backlightlevel = GAMMA_250CD; /* 22 */ + break; + default: + backlightlevel = GAMMA_40CD; /* 1 */ + break; + } + return backlightlevel; +} + + + +static int set_acl_on_level(int bl_level) +{ + int cd; + cd = get_candela_index(bl_level); + + if (!lcd_acl_table[cd].lux) + return 1; + + if (lcd_acl_table[cd].lux) { + samsung_panel_acl_update_cmds[0].dlen = + lcd_acl_table[cd].cmd->dlen; + samsung_panel_acl_update_cmds[0].payload = + lcd_acl_table[cd].cmd->payload; + } + return 0; +} + +static int set_elvss_level(int bl_level) +{ + unsigned char calc_elvss; + int cd; + int elvss_pulse; + + cd = get_candela_index(bl_level); + elvss_pulse = mipi_pd.lcd_elvss_data[0] & 0x3F; + if (elvss_pulse == 0) + calc_elvss = GET_DEFAULT_ELVSS_ID[cd]; + else + calc_elvss = elvss_pulse + GET_EACH_ELVSS_ID[cd]; + + pr_debug("%s: elvss_pulse=%x,calc_elvss = %x\n", __func__, elvss_pulse, + calc_elvss); + if (calc_elvss > LCD_ELVSS_RESULT_LIMIT) + calc_elvss = LCD_ELVSS_RESULT_LIMIT; + each_elvss_cond_set[1] = calc_elvss; + each_elvss_cond_set[2] = calc_elvss; + each_elvss_cond_set[3] = calc_elvss; + each_elvss_cond_set[4] = calc_elvss; + + return 0; +} + +void reset_gamma_level(void) +{ + pr_info("reset_gamma_level\n"); + mipi_pd.lcd_current_cd_idx = -1; +} +static int set_gamma_level(int bl_level, enum gamma_mode_list gamma_mode) +{ + int cd; + int *lux_tbl = lux_tbl_acl; + + cd = get_candela_index(bl_level); + if (mipi_pd.lcd_current_cd_idx == cd) { + pr_debug("mipi_pd.lcd_current_cd_idx :%d cd:%d\n", + mipi_pd.lcd_current_cd_idx, cd); + return -1; + } + else + mipi_pd.lcd_current_cd_idx = cd; + + if (gamma_mode == GAMMA_2_2) { + samsung_panel_gamma_update_cmds[0].dlen = sizeof(gamma_2_2[cd]); + samsung_panel_gamma_update_cmds[0].payload = gamma_2_2[cd]; + } else if (gamma_mode == GAMMA_1_9) { + samsung_panel_gamma_update_cmds[0].dlen = sizeof(gamma_1_9[cd]); + samsung_panel_gamma_update_cmds[0].payload = gamma_1_9[cd]; + } else { + /* SMART Dimming gamma_lux; */ + char pBuffer[256]; + int i; + int gamma_lux; + + gamma_lux = lux_tbl[cd]; + + if (gamma_lux > SmartDimming_CANDELA_UPPER_LIMIT) + gamma_lux = SmartDimming_CANDELA_UPPER_LIMIT; + + /* Set Minimum Lux for Dimm */ + + for (i = SmartDimming_GammaUpdate_Pos; + i < sizeof(GAMMA_SmartDimming_COND_SET); i++) + GAMMA_SmartDimming_COND_SET[i] = 0; + mipi_pd.smart_s6e39a0x02.brightness_level = gamma_lux; + generate_gamma(&mipi_pd.smart_s6e39a0x02, + &(GAMMA_SmartDimming_COND_SET[2]), GAMMA_SET_MAX); + samsung_panel_gamma_update_cmds[0].dlen = + sizeof(GAMMA_SmartDimming_COND_SET); + samsung_panel_gamma_update_cmds[0].payload = + GAMMA_SmartDimming_COND_SET; + pBuffer[0] = 0; + for (i = 0; i < sizeof(GAMMA_SmartDimming_COND_SET); i++) { + snprintf(pBuffer + strnlen(pBuffer, 256), 256, " %02x", + GAMMA_SmartDimming_COND_SET[i]); + } + pr_info("SD: %03d %s\n", gamma_lux, pBuffer); + pr_debug("bl_level:%d,cd:%d:Candela:%d\n", bl_level, cd, + gamma_lux); + } + + return 0; +} + +static struct mipi_panel_data mipi_pd = { + .panel_name = "SMD_AMS429QC01\n", + .ready_to_on = {samsung_panel_ready_to_on_cmds + , ARRAY_SIZE(samsung_panel_ready_to_on_cmds)}, + .ready_to_off = {samsung_panel_ready_to_off_cmds + , ARRAY_SIZE(samsung_panel_ready_to_off_cmds)}, + .on = {samsung_panel_on_cmds + , ARRAY_SIZE(samsung_panel_on_cmds)}, + .off = {samsung_panel_off_cmds + , ARRAY_SIZE(samsung_panel_off_cmds)}, + .late_on = {samsung_panel_late_on_cmds + , ARRAY_SIZE(samsung_panel_late_on_cmds)}, + .early_off = {samsung_panel_early_off_cmds + , ARRAY_SIZE(samsung_panel_early_off_cmds)}, + .gamma_update = {samsung_panel_gamma_update_cmds + , ARRAY_SIZE(samsung_panel_gamma_update_cmds)}, +#ifdef USE_ACL + .acl_on = {samsung_panel_acl_on_cmds + , ARRAY_SIZE(samsung_panel_acl_on_cmds)}, + .acl_off = {samsung_panel_acl_off_cmds + , ARRAY_SIZE(samsung_panel_acl_off_cmds)}, + .acl_update = { + samsung_panel_acl_update_cmds, + ARRAY_SIZE(samsung_panel_acl_update_cmds)}, +#endif +#ifdef USE_ELVSS + .elvss_update = { + samsung_panel_elvss_update_cmds, + ARRAY_SIZE(samsung_panel_elvss_update_cmds)}, +#endif + .set_elvss = set_elvss_level, + .set_acl = set_acl_on_level, + .set_gamma = set_gamma_level, + .gamma_smartdim = gamma_cond_300cd, + .lcd_current_cd_idx = -1, + .mtp_read_enable = {samsung_mtp_read_cmds + , ARRAY_SIZE(samsung_mtp_read_cmds)}, +}; + +static struct mipi_dsi_phy_ctrl dsi_command_mode_phy_db = { + /* DSI_BIT_CLK at 410MHz, 2 lane, RGB888 */ + {0x0F, 0x0a, 0x04, 0x00, 0x20}, /* regulator */ + /* timing */ + {0xAD, 0x8B, 0x19, 0x00, 0x93, 0x96, 0x1C, 0x8D, + 0x1C, 0x03, 0x04, 0xa0}, + /* phy ctrl */ + {0x5f, 0x00, 0x00, 0x10}, + /* strength */ + {0xff, 0x00, 0x06, 0x00}, + /* pll control */ + {0x0, 0x7f, 0x1, 0x1a, 0x00, 0x50, 0x48, 0x63, + 0x41, 0x0f, 0x01, + 0x00, 0x14, 0x03, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01}, +}; + +static int __init mipi_cmd_samsung_oled_qhd_pt_init(void) +{ + int ret; + + +#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT + if (msm_fb_detect_client("mipi_cmd_samsung_oled_qhd")) + return 0; +#endif + + pinfo.xres = 540; + pinfo.yres = 960; + pinfo.mode2_xres = 0; + pinfo.mode2_yres = 0; + pinfo.mode2_bpp = 0; + /* + * + * Panel's Horizontal input timing requirement is to + * include dummy(pad) data of 200 clk in addition to + * width and porch/sync width values + */ + pinfo.mipi.xres_pad = 0; + pinfo.mipi.yres_pad = 0; + + pinfo.type = MIPI_CMD_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 32; + pinfo.lcdc.h_back_porch = 0; + pinfo.lcdc.h_front_porch = 0; + pinfo.lcdc.h_pulse_width = 0; + pinfo.lcdc.v_back_porch = 0x2; + pinfo.lcdc.v_front_porch = 0x4D; + pinfo.lcdc.v_pulse_width = 0x1; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 255; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + pinfo.clk_rate = 410000000; + pinfo.lcd.v_back_porch = pinfo.lcdc.v_back_porch; + pinfo.lcd.v_front_porch = pinfo.lcdc.v_front_porch; + pinfo.lcd.v_pulse_width = pinfo.lcdc.v_pulse_width; + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.hw_vsync_mode = TRUE; + pinfo.lcd.refx100 = 4024; /* adjust refx100 to prevent tearing */ + pinfo.mipi.mode = DSI_CMD_MODE; + pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.t_clk_post = 0x19; + pinfo.mipi.t_clk_pre = 0x2E; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.te_sel = 1; /* TE from vsycn gpio */ + pinfo.mipi.interleave_max = 1; + pinfo.mipi.insert_dcs_cmd = TRUE; + pinfo.mipi.wr_mem_continue = 0x3c; + pinfo.mipi.wr_mem_start = 0x2c; + pinfo.mipi.dsi_phy_db = &dsi_command_mode_phy_db; + + ret = mipi_samsung_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WVGA_PT, + &mipi_pd); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} +module_init(mipi_cmd_samsung_oled_qhd_pt_init); diff --git a/drivers/video/msm/mipi_samsung_oled_video_hd_pt.c b/drivers/video/msm/mipi_samsung_oled_video_hd_pt.c new file mode 100644 index 00000000000..783c2658288 --- /dev/null +++ b/drivers/video/msm/mipi_samsung_oled_video_hd_pt.c @@ -0,0 +1,1696 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_fb.h" +#include "mipi_samsung_oled.h" +#ifdef CONFIG_SAMSUNG_CMC624 +#include "samsung_cmc624.h" +#endif + +static struct msm_panel_info pinfo; +static struct mipi_panel_data mipi_pd; + +#define MAX_GAMMA_VALUE 25 +#define FAST_INIT_MAX_CMDS ARRAY_SIZE(samsung_panel_ready_to_on_cmds_4_8_fast) +/* + * [1] Level2 / MTP key Enable + */ +static char mtp_key_enable1[] = { + 0xF0, + 0x5A, 0x5A +}; +static char mtp_key_enable2[] = { + 0xF1, + 0x5A, 0x5A +}; + +/* + * [2] Panel Condition Set + */ + /* FOR 4.65 inch */ +#if defined(CONFIG_MACH_ACCELERATE) +static char panel_cond_set[] = { + 0xF8, + 0x19, 0x35, 0x00, 0x00, 0x00, + 0x93, 0x00, 0x3C, 0x7D, 0x08, + 0x27, 0x7D, 0x3F, 0x10, 0x08, + 0x00, 0x20, 0x04, 0x08, 0x6E, + 0x08, 0x00, 0x00, 0x02, 0x08, + 0x08, 0x23, 0x23, 0xC0, 0xC1, + 0x01, 0x81, 0xC1, 0x00, 0xC1, + 0xF6, 0xF6, 0xC1 +}; +#elif defined(CONFIG_MACH_STRETTO) +static char panel_cond_set[] = { + 0xF8, + 0x3D, 0x35, 0x00, 0x00, 0x00, + 0x93, 0x00, 0x3C, 0x7D, 0x08, + 0x27, 0x7D, 0x3F, 0x00, 0x00, + 0x00, 0x20, 0x04, 0x08, 0x6E, + 0x00, 0x00, 0x00, 0x02, 0x08, + 0x08, 0x23, 0x23, 0xC0, 0xC8, + 0x08, 0x48, 0xC1, 0x00, 0xC1, + 0xFF, 0xFF, 0xC8 +}; +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) +static char panel_cond_set[] = { + 0xF8, + 0x3D, 0x35, 0x00, 0x00, 0x00, + 0x93, 0x00, 0x3C, 0x7D, 0x08, + 0x27, 0x7D, 0x3F, 0x00, 0x00, + 0x00, 0x20, 0x04, 0x08, 0x6E, + 0x00, 0x00, 0x00, 0x02, 0x08, + 0x08, 0x23, 0x23, 0xC0, 0xC8, + 0x08, 0x48, 0xC1, 0x00, 0xC1, + 0xFF, 0xFF, 0xC8 +}; +#else +static char panel_cond_set[] = { + 0xF8, + 0x3D, 0x32, 0x00, 0x00, 0x00, + 0x8D, 0x00, 0x39, 0x78, 0x08, + 0x26, 0x78, 0x3C, 0x00, 0x00, + 0x00, 0x20, 0x04, 0x08, 0x69, + 0x00, 0x00, 0x00, 0x02, 0x07, + 0x07, 0x21, 0x21, 0xC0, 0xC8, + 0x08, 0x48, 0xC1, 0x00, 0xC1, + 0xFF, 0xFF, 0xC8 +}; +#endif +/* FOR 4.8 inch */ +#ifdef CONFIG_MIPI_CLK_487 +static char panel_cond_set_4_8[] = { + 0xF8, + 0x19, 0x33, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x3B, 0x7A, 0x0F, + 0x26, 0x08, 0x6B, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x08, 0x6B, + 0x00, 0x00, 0x00, 0x00, 0x07, + 0x07, 0x22, 0x35, 0xC0, 0xC1, + 0x01, 0x81, 0xC1, 0x00, 0xC3, + 0xF6, 0xF6, 0xC1 +}; +#elif defined(CONFIG_MACH_K2_KDI) +static char panel_cond_set_4_8[] = { + 0xF8, + 0x3D, 0x35, 0x00, 0x00, 0x00, + 0x94, 0x00, 0x3C, 0x7D, 0x10, + 0x27, 0x08, 0x6E, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x08, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x08, + 0x08, 0x23, 0x37, 0xC0, 0xC8, + 0x08, 0x48, 0xC1, 0x00, 0xC3, + 0xFF, 0xFF, 0xC8 +}; +#else +static char panel_cond_set_4_8[] = { + 0xF8, + 0x19, 0x35, 0x00, 0x00, 0x00, + 0x94, 0x00, 0x3C, 0x7D, 0x10, + 0x27, 0x08, 0x6E, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x08, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x08, + 0x08, 0x23, 0x37, 0xC0, 0xC1, + 0x01, 0x81, 0xC1, 0x00, 0xC3, + 0xF6, 0xF6, 0xC1 +}; +#endif +/* + * [2] Display Condition Set + */ +static char display_cond_set[] = { + 0xF2, + 0x80, 0x03, 0x0D +}; + +static char display_cond_set_cmc[] = { + 0xF2, + 0x80, 0x03, 0x0D +}; + +#if defined(CONFIG_MACH_STRETTO) +static char display_cond_set_none_cmc[] = { + 0xF2, + 0x80, 0x03, 0x0D +}; +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) +static char display_cond_set_none_cmc[] = { + 0xF2, + 0x80, 0x03, 0x0D +}; +#else +static char display_cond_set_none_cmc[] = { + 0xF2, + 0x80, 0x03, 0x35 +}; +#endif + +/* + * [3] Gamma Condition Set + */ + + +/* 300 cd +static char gamma_cond_set[] = { + 0xFA, + 0x01, 0x7A, 0x39, 0x87, 0xBD, + 0xD7, 0xA7, 0xAE, 0xC2, 0xA1, + 0xBE, 0xCD, 0xB6, 0x8B, 0x9E, + 0x82, 0xA6, 0xB2, 0xA1, 0x00, + 0xD8, 0x00, 0xC0, 0x00, 0xF7 +}; +*/ +/* For 4.65 inch */ +#if defined(CONFIG_MACH_STRETTO) +static char gamma_cond_set[] = { + 0xFA, + 0x01, 0x5F, 0x2E, 0x67, 0xAA, 0xC6, + 0xAC, 0xB0, 0xC8, 0xBB, 0xBE, 0xCB, + 0xBD, 0x97, 0xA5, 0x91, 0xAF, 0xB8, + 0xAB, 0x00, 0xC2, 0x00, 0xBA, 0x00, 0xE2 +}; +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) +static char gamma_cond_set[] = { + 0xFA, + 0x01, 0x5F, 0x2E, 0x67, 0xAA, 0xC6, + 0xAC, 0xB0, 0xC8, 0xBB, 0xBE, 0xCB, + 0xBD, 0x97, 0xA5, 0x91, 0xAF, 0xB8, + 0xAB, 0x00, 0xC2, 0x00, 0xBA, 0x00, 0xE2 +}; +#else +static char gamma_cond_set[] = { + 0xFA, + 0x01, 0x4A, 0x01, 0x4D, 0x85, 0xAD, + 0xA4, 0xA1, 0xCD, 0xA7, 0xBD, 0xDA, + 0xBD, 0x95, 0xBD, 0x95, 0xB7, 0xCE, + 0xB5, 0x00, 0x8F, 0x00, 0x82, 0x00, 0xB8, +}; +#endif +/* For 4.8 inch */ +static char gamma_cond_set_4_8[] = { + 0xFA, + 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static char gamma_set_update[] = { + 0xF7, + 0x03, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +/* + * [4] ETC Condition Set + */ +static char etc_cond_set1[] = { + 0xF6, + 0x00, 0x02, 0x00 +}; +/* For 4.65 inch */ +static char etc_cond_set2[] = { + 0xB6, + 0x0C, 0x02, 0x03, 0x32, 0xFF, + 0x44, 0x44, 0xC0, 0x00 +}; +/* For 4.8 inch */ +static char etc_cond_set2_4_8[] = { + 0xB6, + 0x0C, 0x02, 0x03, 0x32, 0xC0, + 0x44, 0x44, 0xC0, 0x00 +}; +/* For 4.65 inch */ +#if defined(CONFIG_MACH_STRETTO) +static char etc_cond_set3[] = { + 0xD9, + 0x14, 0x40, 0x0C, 0xCB, 0xCE, + 0x6E, 0xC4, 0x07, 0x40, 0x41, + 0xD0, 0x00, 0x60, 0x19 +}; +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) +static char etc_cond_set3[] = { + 0xD9, + 0x14, 0x40, 0x0C, 0xCB, 0xCE, + 0x6E, 0xC4, 0x07, 0x40, 0x41, + 0xD0, 0x00, 0x60, 0x19 +}; +#else +static char etc_cond_set3[] = { + 0xD9, + 0x14, 0x40, 0x0C, 0xCB, 0xCE, + 0x6E, 0xC4, 0x07, 0x40, 0x40, + 0xD0, 0x00, 0x60, 0x19 +}; +#endif +/* For 4.8 inch */ +static char etc_cond_set3_4_8[] = { + 0xD9, + 0x14, 0x40, 0x0C, 0xCB, 0xCE, + 0x6E, 0xC4, 0x07, 0x40, 0x41, + 0xC1, 0x00, 0x60, 0x19 +}; +static char etc_cond_set4[] = { + 0xE1, + 0x10, 0x1C, 0x17, 0x08, 0x1D +}; +static char etc_cond_set5[] = { + 0xE2, + 0xED, 0x07, 0xC3, 0x13, 0x0D, + 0x03 +}; +static char etc_cond_set6[] = { + 0xE3, + 0x40 +}; +static char etc_cond_set7[] = { + 0xE4, + 0x00, 0x0, 0x14, 0x80, 0x00, + 0x00, 0x00 +}; +/* For 4.65 inch */ +static char etc_cond_set8[] = { + 0xF4, + 0xCF, 0x0A, 0x12, 0x10, 0x1E, + 0x33, 0x02 +}; +/* For 4.8 inch */ +static char etc_cond_set8_4_8[] = { + 0xF4, + 0xCF, 0x0A, 0x15, 0x10, 0x19, + 0x33, 0x02 +}; + +static char oled_gamma_7500K[] = { + 0xFA, + 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +#ifdef USE_ELVSS +static char elvss_cond_set[] = { + 0xB1, 0x04, 0x00, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#endif + +#ifdef USE_ACL +static char acl_on[] = { + 0xC0, + 0x01, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +static char acl_set_zero[] = { + 0xC1, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +static char acl_off[] = { + 0xC1, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#endif + +enum { + GAMMA_20CD, + GAMMA_30CD, + GAMMA_40CD, + GAMMA_50CD, + GAMMA_60CD, + GAMMA_70CD, + GAMMA_80CD, + GAMMA_90CD, + GAMMA_100CD, + GAMMA_110CD, + GAMMA_120CD, + GAMMA_130CD, + GAMMA_140CD, + GAMMA_150CD, + GAMMA_160CD, + GAMMA_170CD, + GAMMA_180CD, + GAMMA_190CD, + GAMMA_200CD, + GAMMA_210CD, + GAMMA_220CD, + GAMMA_230CD, + GAMMA_240CD, + GAMMA_250CD, + GAMMA_260CD, + GAMMA_270CD, + GAMMA_280CD, + GAMMA_290CD, + GAMMA_300CD, +}; + +static int lux_tbl_acl[] = { + 20, 30, 40, 50, 60, + 70, 80, 90, 100, 110, + 120, 130, 140, 150, 160, + 170, 180, 190, 200, 210, + 220, 230, 240, 250, 260, + 270, 280, 290, 300 +}; + + +/* 4.65" gamma table A1-line*/ +static char gamma_cond_300cd[] = { + 0x5F, 0x2E, 0x67, 0xAA, + 0xC6, 0xAC, 0xB0, 0xC8, 0xBB, + 0xBE, 0xCB, 0xBD, 0x97, 0xA5, + 0x91, 0xAF, 0xB8, 0xAB, 0x00, + 0xC2, 0x00, 0xBA, 0x00, 0xE2 +}; + +static char gamma_cond_300cd_4_8[] = { + 0x43, 0x14, 0x45, 0xAD, + 0xBE, 0xA9, 0xB0, 0xC3, 0xAF, + 0xC1, 0xCD, 0xC0, 0x95, 0xA2, + 0x91, 0xAC, 0xB5, 0xAA, 0x00, + 0xB0, 0x00, 0xA0, 0x00, 0xCC +}; + +#if defined(CONFIG_MACH_STRETTO) +static char GAMMA_SmartDimming_COND_SET[] = { + 0xFA, + 0x01, 0x5F, 0x2E, 0x67, 0xAA, + 0xC6, 0xAC, 0xB0, 0xC8, 0xBB, + 0xBE, 0xCB, 0xBD, 0x97, 0xA5, + 0x91, 0xAF, 0xB8, 0xAB, 0x00, + 0xC2, 0x00, 0xBA, 0x00, 0xE2, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) +static char GAMMA_SmartDimming_COND_SET[] = { + 0xFA, + 0x01, 0x5F, 0x2E, 0x67, 0xAA, + 0xC6, 0xAC, 0xB0, 0xC8, 0xBB, + 0xBE, 0xCB, 0xBD, 0x97, 0xA5, + 0x91, 0xAF, 0xB8, 0xAB, 0x00, + 0xC2, 0x00, 0xBA, 0x00, 0xE2, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#else +static char GAMMA_SmartDimming_COND_SET[] = { + 0xFA, + 0x01, 0x4A, 0x01, 0x4D, 0x7A, + 0x5D, 0xA5, 0x9C, 0xCA, 0xA4, + 0xBD, 0xDC, 0xBE, 0x93, 0xBD, + 0x95, 0xBA, 0xD2, 0xB7, 0x00, + 0x81, 0x00, 0x75, 0x00, 0xA5, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#endif + +#if defined(CONFIG_MACH_K2_KDI) +static char panel_cond_aid_ref[] = { + 0xF8, + 0x3D, 0x35, 0x00, 0x00, 0x00, + 0x94, 0x00, 0x3C, 0x7D, 0x10, + 0x27, 0x08, 0x6E, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x08, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x08, + 0x08, 0x23, 0x37, 0xC0, 0xC8, + 0x08, 0x48, 0xC1, 0x00, 0xC3, + 0xFF, 0xFF, 0xC8, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#else +static char panel_cond_aid_ref[] = { + 0xF8, + 0x19, 0x35, 0x00, 0x00, 0x00, + 0x94, 0x00, 0x3C, 0x7D, 0x10, + 0x27, 0x08, 0x6E, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x08, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x08, + 0x08, 0x23, 0x37, 0xC0, 0xC1, + 0x01, 0x81, 0xC1, 0x00, 0xC3, + 0xF6, 0xF6, 0xC1, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#endif + +static char etc_cond_set3_aid_ref[] = { + 0xD9, + 0x14, 0x40, 0x0C, 0xCB, 0xCE, + 0x6E, 0xC4, 0x07, 0xC0, 0x41, + 0xC1, 0x00, 0x60, 0x19, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +/* + * Display On, Stand-by Off Command + */ +static char all_pixel_off[] = { 0x22, /* no param */ }; +static char normal_mode_on[] = { 0x13, /* no parm */ }; +static char display_on[] = { 0x29, /* no param */ }; +static char display_off[] = { 0x28, /* no param */ }; +static char sleep_in[] = { 0x10, /* no param */ }; +static char sleep_out[] = { 0x11, /* no param */ }; + +/* For 4.65 inch */ +static struct dsi_cmd_desc samsung_panel_ready_to_on_cmds[] = { +/*+ condition for non CMC624 +*/ + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(mtp_key_enable1), mtp_key_enable1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(mtp_key_enable2), mtp_key_enable2}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(sleep_out), sleep_out}, +/*- condition for non CMC624 -*/ + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_set), panel_cond_set}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(display_cond_set), display_cond_set}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(gamma_cond_set), gamma_cond_set}, + {DTYPE_GEN_WRITE1, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set1), etc_cond_set1}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set2), etc_cond_set2}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set3), etc_cond_set3}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set4), etc_cond_set4}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set5), etc_cond_set5}, + {DTYPE_GEN_WRITE1, 1, 0, 0, 0, + sizeof(etc_cond_set6), etc_cond_set6}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set7), etc_cond_set7}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 120, + sizeof(etc_cond_set8), etc_cond_set8}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_set_zero), acl_set_zero}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on} +}; +/* For 4.8 inch */ +static struct dsi_cmd_desc samsung_panel_ready_to_on_cmds_4_8[] = { +/*+ condition for non CMC624 +*/ + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(mtp_key_enable1), mtp_key_enable1}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(mtp_key_enable2), mtp_key_enable2}, + + {DTYPE_GEN_WRITE, 1, 0, 0, 10, + sizeof(sleep_out), sleep_out}, +/*- condition for non CMC624 -*/ + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_set_4_8), panel_cond_set_4_8}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(display_cond_set), display_cond_set}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(gamma_cond_set_4_8), gamma_cond_set_4_8}, + {DTYPE_GEN_WRITE1, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set1), etc_cond_set1}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set2_4_8), etc_cond_set2_4_8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set3_4_8), etc_cond_set3_4_8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 120, + sizeof(etc_cond_set8_4_8), etc_cond_set8_4_8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(elvss_cond_set), elvss_cond_set}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_set_zero), acl_set_zero}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on} +}; + +static struct dsi_cmd_desc samsung_panel_ready_to_on_cmds_4_8_fast[] = { +/*+ condition for non CMC624 +*/ + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(mtp_key_enable1), mtp_key_enable1}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(mtp_key_enable2), mtp_key_enable2}, + + {DTYPE_GEN_WRITE, 1, 0, 0, 10, + sizeof(sleep_out), sleep_out}, +/*- condition for non CMC624 -*/ + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_aid_ref), panel_cond_aid_ref}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(display_cond_set), display_cond_set}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(GAMMA_SmartDimming_COND_SET), + GAMMA_SmartDimming_COND_SET}, + {DTYPE_GEN_WRITE1, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set1), etc_cond_set1}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set2_4_8), etc_cond_set2_4_8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set3_aid_ref), etc_cond_set3_aid_ref}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set8_4_8), etc_cond_set8_4_8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(elvss_cond_set), elvss_cond_set}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_set_zero), acl_set_zero}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on}, +/* Will be initialized dyanamically from prepare_fast_init_cmd_array()*/ + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(NULL), NULL}, +}; + +/* For 4.65 inch */ +static struct dsi_cmd_desc samsung_panel_ready_to_on_cmds_fast[] = { +/*+ condition for non CMC624 +*/ + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(mtp_key_enable1), mtp_key_enable1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(mtp_key_enable2), mtp_key_enable2}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(sleep_out), sleep_out}, +/*- condition for non CMC624 -*/ + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_set), panel_cond_set}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(display_cond_set), display_cond_set}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(GAMMA_SmartDimming_COND_SET), + GAMMA_SmartDimming_COND_SET}, + {DTYPE_GEN_WRITE1, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set1), etc_cond_set1}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set2), etc_cond_set2}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set3), etc_cond_set3}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set4), etc_cond_set4}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set5), etc_cond_set5}, + {DTYPE_GEN_WRITE1, 1, 0, 0, 0, + sizeof(etc_cond_set6), etc_cond_set6}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set7), etc_cond_set7}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set8), etc_cond_set8}, + + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_set_zero), acl_set_zero}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on}, +/* Will be initialized dyanamically from prepare_fast_init_cmd_array()*/ + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(NULL), NULL}, +}; + +static struct dsi_cmd_desc samsung_panel_ready_to_off_cmds[] = { + {DTYPE_GEN_WRITE, 1, 0, 0, 0, + sizeof(display_off), display_off}, +}; + +static struct dsi_cmd_desc samsung_panel_on_cmds[] = { + {DTYPE_GEN_WRITE, 1, 0, 0, 0, + sizeof(display_on), display_on}, +}; + +static struct dsi_cmd_desc samsung_panel_off_cmds[] = { + {DTYPE_GEN_WRITE, 1, 0, 0, 0, + sizeof(sleep_in), sleep_in}, +}; + +static struct dsi_cmd_desc samsung_panel_late_on_cmds[] = { + {DTYPE_GEN_WRITE, 1, 0, 0, 0, + sizeof(normal_mode_on), normal_mode_on}, + {DTYPE_GEN_WRITE, 1, 0, 0, 5, + sizeof(display_on), display_on}, +}; + +static struct dsi_cmd_desc samsung_panel_early_off_cmds[] = { + {DTYPE_GEN_WRITE, 1, 0, 0, 0, + sizeof(all_pixel_off), all_pixel_off}, +}; + +#if defined(AID_OPERATION_4_8_INCH) +static struct dsi_cmd_desc samsung_panel_gamma_update_cmds[4] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 1, + sizeof(oled_gamma_7500K), oled_gamma_7500K} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_aid_ref), panel_cond_aid_ref} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set3_aid_ref), etc_cond_set3_aid_ref} + , + {DTYPE_GEN_WRITE1, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update} + , +}; +#else +static struct dsi_cmd_desc samsung_panel_gamma_update_cmds[2] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 1, + sizeof(oled_gamma_7500K), oled_gamma_7500K} + , + {DTYPE_GEN_WRITE1, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update} + , +}; +#endif + +#ifdef USE_ACL +/********************* ACL *******************/ +static char ACL_COND_SET_50[] = { + 0xC1, + 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, + 0x02, 0xCF, 0x00, 0x00, 0x04, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x09, 0x10, 0x18, 0x1F, 0x27, + 0x2E, 0x36, 0x3D, 0x45, 0x4C, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#if defined(CONFIG_MACH_STRETTO) +static char ACL_COND_SET_40[] = { + 0xC1, + 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, + 0x02, 0xCF, 0x00, 0x00, 0x04, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x07, 0x0D, 0x12, 0x18, 0x1E, + 0x24, 0x2A, 0x2F, 0x35, 0x3B, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#elif defined(CONFIG_MACH_SUPERIORLTE_SKT) +static char ACL_COND_SET_40[] = { + 0xC1, + 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, + 0x02, 0xCF, 0x00, 0x00, 0x04, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x07, 0x0D, 0x12, 0x18, 0x1E, + 0x24, 0x2A, 0x2F, 0x35, 0x3B, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#else +static char ACL_COND_SET_40[] = { + 0xC1, + 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, + 0x02, 0xCF, 0x00, 0x00, 0x04, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x07, 0x0C, 0x12, 0x17, 0x1D, + 0x23, 0x28, 0x2E, 0x33, 0x39, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#endif +static char ACL_COND_SET_33[] = { + 0xC1, + 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, + 0x02, 0xCF, 0x00, 0x00, 0x04, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x06, 0x0A, 0x0F, 0x14, 0x19, + 0x1D, 0x22, 0x27, 0x2B, 0x30, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#if 0 +static char ACL_COND_SET_20[] = { + 0xC1, + 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, + 0x02, 0xCF, 0x00, 0x00, 0x04, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x07, 0x0A, 0x0D, 0x10, + 0x12, 0x15, 0x18, 0x1B, 0x1E, + /* adding 8 byte padding*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +#endif +static struct dsi_cmd_desc DSI_CMD_ACL_50 = { +DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(ACL_COND_SET_50), ACL_COND_SET_50 }; +static struct dsi_cmd_desc DSI_CMD_ACL_40 = { +DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(ACL_COND_SET_40), ACL_COND_SET_40 }; +static struct dsi_cmd_desc DSI_CMD_ACL_33 = { +DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(ACL_COND_SET_33), ACL_COND_SET_33 }; +#if 0 +static struct dsi_cmd_desc DSI_CMD_ACL_20 = { +DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(ACL_COND_SET_20), ACL_COND_SET_20 }; +#endif +static struct dsi_cmd_desc_LCD lcd_acl_table[] = { + {0, "20", NULL}, + {0, "30", NULL}, + {0, "40", NULL}, + {40, "50", &DSI_CMD_ACL_40}, + {40, "60", &DSI_CMD_ACL_40}, + {40, "70", &DSI_CMD_ACL_40}, + {40, "80", &DSI_CMD_ACL_40}, + {40, "90", &DSI_CMD_ACL_40}, + {40, "100", &DSI_CMD_ACL_40}, + {40, "110", &DSI_CMD_ACL_40}, + {40, "120", &DSI_CMD_ACL_40}, + {40, "130", &DSI_CMD_ACL_40}, + {40, "140", &DSI_CMD_ACL_40}, + {40, "150", &DSI_CMD_ACL_40}, + {40, "160", &DSI_CMD_ACL_40}, + {40, "170", &DSI_CMD_ACL_40}, + {40, "180", &DSI_CMD_ACL_40}, + {40, "190", &DSI_CMD_ACL_40}, + {40, "200", &DSI_CMD_ACL_40}, + {40, "210", &DSI_CMD_ACL_40}, + {40, "220", &DSI_CMD_ACL_40}, + {40, "230", &DSI_CMD_ACL_40}, + {40, "240", &DSI_CMD_ACL_40}, + {40, "250", &DSI_CMD_ACL_40}, + {40, "260", &DSI_CMD_ACL_40}, + {40, "270", &DSI_CMD_ACL_40}, + {40, "280", &DSI_CMD_ACL_40}, + {40, "290", &DSI_CMD_ACL_40}, + {50, "300", &DSI_CMD_ACL_50}, +}; + +static struct dsi_cmd_desc_LCD lcd_acl_table_4_8[] = { + {0, "20", NULL}, + {33, "30", &DSI_CMD_ACL_33}, + {40, "40", &DSI_CMD_ACL_40}, + {40, "50", &DSI_CMD_ACL_40}, + {40, "60", &DSI_CMD_ACL_40}, + {40, "70", &DSI_CMD_ACL_40}, + {40, "80", &DSI_CMD_ACL_40}, + {40, "90", &DSI_CMD_ACL_40}, + {40, "100", &DSI_CMD_ACL_40}, + {40, "110", &DSI_CMD_ACL_40}, + {40, "120", &DSI_CMD_ACL_40}, + {40, "130", &DSI_CMD_ACL_40}, + {40, "140", &DSI_CMD_ACL_40}, + {40, "150", &DSI_CMD_ACL_40}, + {40, "160", &DSI_CMD_ACL_40}, + {40, "170", &DSI_CMD_ACL_40}, + {40, "180", &DSI_CMD_ACL_40}, + {40, "190", &DSI_CMD_ACL_40}, + {40, "200", &DSI_CMD_ACL_40}, + {40, "210", &DSI_CMD_ACL_40}, + {40, "220", &DSI_CMD_ACL_40}, + {40, "230", &DSI_CMD_ACL_40}, + {40, "240", &DSI_CMD_ACL_40}, + {40, "250", &DSI_CMD_ACL_40}, + {40, "260", &DSI_CMD_ACL_40}, + {40, "270", &DSI_CMD_ACL_40}, + {40, "280", &DSI_CMD_ACL_40}, + {40, "290", &DSI_CMD_ACL_40}, + {40, "300", &DSI_CMD_ACL_40}, +}; + + +static struct dsi_cmd_desc samsung_panel_acl_on_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_set_zero), acl_set_zero}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on} +}; + +static struct dsi_cmd_desc samsung_panel_acl_off_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_off), acl_off}, +}; +static struct dsi_cmd_desc samsung_panel_acl_update_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(ACL_COND_SET_40), ACL_COND_SET_40} + , +}; +#endif + +static struct dsi_cmd_desc samsung_panel_elvss_update_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(elvss_cond_set), elvss_cond_set}, +}; + +static struct dsi_cmd_desc samsung_panel_elvss_update_cmds_4_8[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(elvss_cond_set), elvss_cond_set}, +}; + +/********************* ELVSS *******************/ +#define LCD_ELVSS_DELTA_300CD (0) +#define LCD_ELVSS_DELTA_200CD (0x08) +#define LCD_ELVSS_DELTA_160CD (0x0D) +#define LCD_ELVSS_DELTA_100CD (0x11) +#define LCD_ELVSS_RESULT_LIMIT (0x9F) +static int GET_ELVSS_ID[] = { + LCD_ELVSS_DELTA_100CD,/* 0 = 20_dimming,*/ + LCD_ELVSS_DELTA_100CD,/* 1 = 30*/ + LCD_ELVSS_DELTA_100CD,/* 2 = 40*/ + LCD_ELVSS_DELTA_100CD,/* 3 = 50,*/ + LCD_ELVSS_DELTA_100CD,/* 4 = 60,*/ + LCD_ELVSS_DELTA_100CD,/* 5 = 70,*/ + LCD_ELVSS_DELTA_100CD,/* 6 = 80,*/ + LCD_ELVSS_DELTA_100CD,/* 7 = 90,*/ + LCD_ELVSS_DELTA_100CD,/* 8 = 100,*/ + LCD_ELVSS_DELTA_160CD,/* 9 = 110,*/ + LCD_ELVSS_DELTA_160CD,/* 10 = 120,*/ + LCD_ELVSS_DELTA_160CD,/* 11 = 130,*/ + LCD_ELVSS_DELTA_160CD,/* 12 = 140,*/ + LCD_ELVSS_DELTA_160CD,/* 13 = 150,*/ + LCD_ELVSS_DELTA_160CD,/* 14 = 160,*/ + LCD_ELVSS_DELTA_200CD,/* 15 = 170,*/ + LCD_ELVSS_DELTA_200CD,/* 16 = 180,*/ + LCD_ELVSS_DELTA_200CD,/* 17 = 190,*/ + LCD_ELVSS_DELTA_200CD,/* 18 = 200,*/ + LCD_ELVSS_DELTA_300CD,/* 19 = 210,*/ + LCD_ELVSS_DELTA_300CD,/* 20 = 220,*/ + LCD_ELVSS_DELTA_300CD,/* 21 = 230,*/ + LCD_ELVSS_DELTA_300CD,/* 22 = 240,*/ + LCD_ELVSS_DELTA_300CD,/* 23 = 250,*/ + LCD_ELVSS_DELTA_300CD,/* 24 = 260,*/ + LCD_ELVSS_DELTA_300CD,/* 25 = 270,*/ + LCD_ELVSS_DELTA_300CD,/* 26 = 280,*/ + LCD_ELVSS_DELTA_300CD,/* 27 = 290,*/ + LCD_ELVSS_DELTA_300CD/* 28 = 300,*/ +}; + +#define LCD_ELVSS_DEFAULT_100CD (0x9F) +#define LCD_ELVSS_DEFAULT_160CD (0x9F) +#define LCD_ELVSS_DEFAULT_200CD (0x9F) +#define LCD_ELVSS_DEFAULT_300CD (0x95) +static int GET_DEFAULT_ELVSS_ID[] = { + LCD_ELVSS_DELTA_100CD,/* 0 = 20_dimming,*/ + LCD_ELVSS_DELTA_100CD,/* 1 = 30*/ + LCD_ELVSS_DELTA_100CD,/* 2 = 40*/ + LCD_ELVSS_DELTA_100CD,/* 3 = 50,*/ + LCD_ELVSS_DELTA_100CD,/* 4 = 60,*/ + LCD_ELVSS_DELTA_100CD,/* 5 = 70,*/ + LCD_ELVSS_DELTA_100CD,/* 6 = 80,*/ + LCD_ELVSS_DELTA_100CD,/* 7 = 90,*/ + LCD_ELVSS_DELTA_100CD,/* 8 = 100,*/ + LCD_ELVSS_DELTA_160CD,/* 9 = 110,*/ + LCD_ELVSS_DELTA_160CD,/* 10 = 120,*/ + LCD_ELVSS_DELTA_160CD,/* 11 = 130,*/ + LCD_ELVSS_DELTA_160CD,/* 12 = 140,*/ + LCD_ELVSS_DELTA_160CD,/* 13 = 150,*/ + LCD_ELVSS_DELTA_160CD,/* 14 = 160,*/ + LCD_ELVSS_DELTA_200CD,/* 15 = 170,*/ + LCD_ELVSS_DELTA_200CD,/* 16 = 180,*/ + LCD_ELVSS_DELTA_200CD,/* 17 = 190,*/ + LCD_ELVSS_DELTA_200CD,/* 18 = 200,*/ + LCD_ELVSS_DELTA_300CD,/* 19 = 210,*/ + LCD_ELVSS_DELTA_300CD,/* 20 = 220,*/ + LCD_ELVSS_DELTA_300CD,/* 21 = 230,*/ + LCD_ELVSS_DELTA_300CD,/* 22 = 240,*/ + LCD_ELVSS_DELTA_300CD,/* 23 = 250,*/ + LCD_ELVSS_DELTA_300CD,/* 24 = 260,*/ + LCD_ELVSS_DELTA_300CD,/* 25 = 270,*/ + LCD_ELVSS_DELTA_300CD,/* 26 = 280,*/ + LCD_ELVSS_DELTA_300CD,/* 27 = 290,*/ + LCD_ELVSS_DELTA_300CD/* 28 = 300,*/ +}; + +#define LCD_ELVSS_RESULT_LIMIT_4_8 (0x9F) +static int GET_ELVSS_ID_4_8[] = { + 0x0C,/* 0 = 20_dimming,*/ + 0x0C,/* 1 = 30*/ + 0x0C,/* 2 = 40*/ + 0x0C,/* 3 = 50,*/ + 0x0C,/* 4 = 60,*/ + 0x0C,/* 5 = 70,*/ + 0x0C,/* 6 = 80,*/ + 0x0C,/* 7 = 90,*/ + 0x0C,/* 8 = 100,*/ + 0x0C,/* 9 = 110,*/ + 0x0B,/* 10= 120,*/ + 0x0A,/* 11= 130,*/ + 0x09,/* 12= 140,*/ + 0x08,/* 13= 150,*/ + 0x07,/* 14= 160,*/ + 0x06,/* 15= 170,*/ + 0x05,/* 16= 180,*/ + 0x05,/* 17= 190,*/ + 0x09,/* 18= 200,*/ + 0x08,/* 19= 210,*/ + 0x07,/* 20= 220,*/ + 0x06,/* 21= 230,*/ + 0x06,/* 22= 240,*/ + 0x05,/* 23= 250,*/ + 0x04,/* 24= 260,*/ + 0x03,/* 25= 270,*/ + 0x02,/* 26= 280,*/ + 0x01,/* 27= 290,*/ + 0x00/* 28= 300,*/ +}; + + +static int get_candela_index(int bl_level) +{ + int backlightlevel; + + /* brightness setting from platform is from 0 to 255 + * But in this driver, brightness is only supported from 0 to 24 */ + + switch (bl_level) { + case 0 ... 20: + backlightlevel = GAMMA_20CD; + break; + case 21 ... 39: + backlightlevel = GAMMA_30CD; + break; + case 40 ... 49: + backlightlevel = GAMMA_40CD; + break; + case 50 ... 59: + backlightlevel = GAMMA_50CD; + break; + case 60 ... 69: + backlightlevel = GAMMA_60CD; + break; + case 70 ... 79: + backlightlevel = GAMMA_70CD; + break; + case 80 ... 89: + backlightlevel = GAMMA_80CD; + break; + case 90 ... 99: + backlightlevel = GAMMA_90CD; + break; + case 100 ... 109: + backlightlevel = GAMMA_100CD; + break; + case 110 ... 119: + backlightlevel = GAMMA_110CD; + break; + case 120 ... 129: + backlightlevel = GAMMA_120CD; + break; + case 130 ... 139: + backlightlevel = GAMMA_130CD; + break; + case 140 ... 149: + backlightlevel = GAMMA_140CD; + break; + case 150 ... 159: + backlightlevel = GAMMA_150CD; + break; + case 160 ... 169: + backlightlevel = GAMMA_160CD; + break; + case 170 ... 179: + backlightlevel = GAMMA_170CD; + break; + case 180 ... 189: + backlightlevel = GAMMA_180CD; + break; + case 190 ... 199: + backlightlevel = GAMMA_190CD; + break; + case 200 ... 209: + backlightlevel = GAMMA_200CD; + break; + case 210 ... 214: + backlightlevel = GAMMA_210CD; + break; + + case 215 ... 219: + backlightlevel = GAMMA_210CD; + break; + case 220 ... 224: + backlightlevel = GAMMA_220CD; + break; + case 225 ... 229: + backlightlevel = GAMMA_220CD; + break; + case 230 ... 234: + backlightlevel = GAMMA_230CD; + break; + case 235 ... 239: + backlightlevel = GAMMA_230CD; + break; + case 240 ... 244: + backlightlevel = GAMMA_240CD; + break; + case 245 ... 249: + backlightlevel = GAMMA_240CD; + break; + case 250 ... 254: + backlightlevel = GAMMA_250CD; + break; + case 255: + if (mipi_pd.msd->dstat.auto_brightness == 1) + backlightlevel = GAMMA_300CD; + else + backlightlevel = GAMMA_250CD; + break; + default: + backlightlevel = GAMMA_20CD; + break; + } + return backlightlevel; +} + + +static struct dsi_cmd_desc combined_ctrl[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(oled_gamma_7500K), oled_gamma_7500K} + , +#ifdef AID_OPERATION_4_8_INCH + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_aid_ref), panel_cond_aid_ref} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set3_aid_ref), etc_cond_set3_aid_ref} + , +#endif + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(elvss_cond_set), elvss_cond_set} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(ACL_COND_SET_40), ACL_COND_SET_40} + , +}; + +static int set_acl_on_level(int bl_level) +{ + int cd; + cd = get_candela_index(bl_level); + + if (Is_4_65LCD_cmc() || Is_4_65LCD_bypass()) { /*4.65 LCD_ID*/ + if (!lcd_acl_table[cd].lux) + return 1; + + samsung_panel_acl_update_cmds[0].dlen = + lcd_acl_table[cd].cmd->dlen; + samsung_panel_acl_update_cmds[0].payload = + lcd_acl_table[cd].cmd->payload; + } else { /*4.8 LCD_ID*/ + if (!lcd_acl_table_4_8[cd].lux) + return 1; + + samsung_panel_acl_update_cmds[0].dlen = + lcd_acl_table_4_8[cd].cmd->dlen; + samsung_panel_acl_update_cmds[0].payload = + lcd_acl_table_4_8[cd].cmd->payload; + } + return 0; +} + +static int is_acl_para_change(int bl_level) +{ + int cd = get_candela_index(bl_level); + int change = 0; + + if (!lcd_acl_table_4_8[cd].lux) + return 0; + + change = memcmp(samsung_panel_acl_update_cmds[0].payload, + lcd_acl_table_4_8[cd].cmd->payload, + lcd_acl_table_4_8[cd].cmd->dlen); + return change; +} + +static int set_elvss_level(int bl_level) +{ + unsigned char calc_elvss; + int cd; + unsigned char elvss_pulse; + cd = get_candela_index(bl_level); + elvss_pulse = mipi_pd.lcd_elvss_data[0]; + + if (elvss_pulse == 0) + calc_elvss = GET_DEFAULT_ELVSS_ID[cd]; + else + calc_elvss = elvss_pulse + GET_ELVSS_ID[cd]; + + pr_debug("%s: elvss_pulse=%x,calc_elvss = %x\n", __func__, elvss_pulse, + calc_elvss); + if (calc_elvss > LCD_ELVSS_RESULT_LIMIT) + calc_elvss = LCD_ELVSS_RESULT_LIMIT; + + if (elvss_cond_set[2] == calc_elvss) + return 1; + + elvss_cond_set[2] = calc_elvss; + + return 0; +} + +static int set_elvss_level_4_8(int bl_level) +{ + unsigned char calc_elvss; + int cd; + unsigned char elvss_pulse; + cd = get_candela_index(bl_level); + elvss_pulse = mipi_pd.lcd_elvss_data[0]; + + calc_elvss = elvss_pulse + GET_ELVSS_ID_4_8[cd]; + + pr_debug("%s: elvss_pulse=%x,calc_elvss = %x\n", __func__, elvss_pulse, + calc_elvss); + if (calc_elvss > LCD_ELVSS_RESULT_LIMIT_4_8) + calc_elvss = LCD_ELVSS_RESULT_LIMIT_4_8; + + if (elvss_cond_set[2] == calc_elvss) + return 1; + + elvss_cond_set[2] = calc_elvss; + + return 0; +} + +void reset_gamma_level(void) +{ + pr_info("reset_gamma_level\n"); + mipi_pd.lcd_current_cd_idx = -1; + + mipi_pd.ldi_acl_stat = false; + elvss_cond_set[2] = 0x00; + +#ifdef AID_OPERATION_4_8_INCH + panel_cond_aid_ref[1] = 0xff; + panel_cond_aid_ref[18] = 0xff; + etc_cond_set3_aid_ref[9] = 0xff; +#endif +} + +#ifdef AID_OPERATION_4_8_INCH +#if defined(AID_CASE_1) +/* +* only smart dimmg range : 300CD ~ 190CD +* AOR fix range : 180CD ~ 110CD +* AOR adjust range : 100CD ~ 20CD +*/ +#define aid_ratio_index 18 +static int aid_below_110_ratio_table[10][2] = { +/* CD RATIO */ + {20, 0x88}, + {30, 0x7A}, + {40, 0x6C}, + {50, 0x5E}, + {60, 0x50}, + {70, 0x41}, + {80, 0x32}, + {90, 0x22}, + {100, 0x12}, + /* upper 110CD */ + {110, 0x42}, +}; +static int aid_operation(int lux) +{ + int index; + int ratio; + static int aid_status; + char panel_cond_aid_ref_1 = panel_cond_aid_ref[1] ; + char panel_cond_aid_ref_18 = panel_cond_aid_ref[18]; + char etc_cond_set3_aid_ref_9 = etc_cond_set3_aid_ref[9]; + int no_change = 0; + + if (Is_4_65LCD_cmc() || Is_4_65LCD_bypass()) { /*4.65 LCD_ID*/ + memcpy(panel_cond_aid_ref, + panel_cond_set, sizeof(panel_cond_set)); + memcpy(etc_cond_set3_aid_ref, + etc_cond_set3, sizeof(etc_cond_set3)); + pr_info("%s LCD is 4.65 inch", __func__); + } else {/* 4.8 LCD_ID*/ + if (lux == 0) { +#if defined(CONFIG_MACH_K2_KDI) + panel_cond_aid_ref[1] = 0x3D; +#else + panel_cond_aid_ref[1] = 0x19; +#endif + panel_cond_aid_ref[18] = 0x04; + etc_cond_set3_aid_ref[9] = 0x40; + aid_status = 0; + } else if (lux >= 190) { +#if defined(CONFIG_MACH_K2_KDI) + panel_cond_aid_ref[1] = 0x3D; +#else + panel_cond_aid_ref[1] = 0x19; +#endif + panel_cond_aid_ref[18] = 0x04; + etc_cond_set3_aid_ref[9] = 0xC0; + aid_status = 0; + } else if (lux >= 110) { + ratio = aid_below_110_ratio_table[9][1]; + +#if defined(CONFIG_MACH_K2_KDI) + panel_cond_aid_ref[1] = 0x3D; +#else + panel_cond_aid_ref[1] = 0x59; +#endif + panel_cond_aid_ref[18] = ratio; + etc_cond_set3_aid_ref[9] = 0xC0; + aid_status = 1; + } else { + index = (lux / 10) - 2; + ratio = aid_below_110_ratio_table[index][1]; + +#if defined(CONFIG_MACH_K2_KDI) + panel_cond_aid_ref[1] = 0x3D; +#else + panel_cond_aid_ref[1] = 0x59; +#endif + panel_cond_aid_ref[18] = ratio; + etc_cond_set3_aid_ref[9] = 0xC0; + aid_status = 1; + } + pr_debug("%s brightness_level : %d adi_status:%d", __func__, + lux, aid_status); + } + no_change = (panel_cond_aid_ref_1 == panel_cond_aid_ref[1]) + && (panel_cond_aid_ref_18 == panel_cond_aid_ref[18]) + && (etc_cond_set3_aid_ref_9 == etc_cond_set3_aid_ref[9]); + + return !no_change; +} +#endif +#endif + +static int set_gamma_level(int bl_level, enum gamma_mode_list gamma_mode) +{ + int cd; + int *lux_tbl = lux_tbl_acl; + int aid_change = 0; + + cd = get_candela_index(bl_level); + + if (mipi_pd.lcd_current_cd_idx == cd) { + pr_debug("mipi_pd.lcd_current_cd_idx :%d cd:%d bl_level:%d\n", + mipi_pd.lcd_current_cd_idx, cd, bl_level); + return -1; + } else + mipi_pd.lcd_current_cd_idx = cd; + + if (gamma_mode == GAMMA_SMART) { + + /* SMART Dimming gamma_lux; */ + char pBuffer[256]; + int i; + int gamma_lux; + + gamma_lux = lux_tbl[cd]; + + if (gamma_lux > SmartDimming_CANDELA_UPPER_LIMIT) + gamma_lux = SmartDimming_CANDELA_UPPER_LIMIT; + + for (i = SmartDimming_GammaUpdate_Pos; + i < sizeof(GAMMA_SmartDimming_COND_SET); i++) + GAMMA_SmartDimming_COND_SET[i] = 0; + + mipi_pd.smart_s6e8aa0x01.brightness_level = gamma_lux; + generate_gamma(&mipi_pd.smart_s6e8aa0x01, + &(GAMMA_SmartDimming_COND_SET[2]), GAMMA_SET_MAX); + +#ifdef AID_OPERATION_4_8_INCH + aid_change = aid_operation(gamma_lux); +#endif + + samsung_panel_gamma_update_cmds[0].dlen = + sizeof(GAMMA_SmartDimming_COND_SET); + samsung_panel_gamma_update_cmds[0].payload = + GAMMA_SmartDimming_COND_SET; + pBuffer[0] = 0; + for (i = 0; i < sizeof(GAMMA_SmartDimming_COND_SET); i++) { + snprintf(pBuffer + strnlen(pBuffer, 256), 256, " %02x", + GAMMA_SmartDimming_COND_SET[i]); + } + pr_debug("SD: %03d %s\n", gamma_lux, pBuffer); + pr_info("bl_level:%d,cd:%d:Candela:%d aid_change:%d\n", + bl_level, cd, gamma_lux, aid_change); + } + return aid_change; +} + +static void prepare_fast_init_cmd_array(int lcd_type) +{ + + if (!mipi_pd.ldi_acl_stat) { + /* dont send acl commands if acl is off */ + mipi_pd.ready_to_on_4_8_fast.size = FAST_INIT_MAX_CMDS - 2; + return; + } + + if (lcd_type == 0x20 || lcd_type == 0x40 || lcd_type == 0x60) { + samsung_panel_ready_to_on_cmds_4_8_fast[FAST_INIT_MAX_CMDS-1] + .payload = samsung_panel_acl_update_cmds[0].payload; + samsung_panel_ready_to_on_cmds_4_8_fast[FAST_INIT_MAX_CMDS-1] + .dlen = samsung_panel_acl_update_cmds[0].dlen; + } else { + samsung_panel_ready_to_on_cmds_fast[FAST_INIT_MAX_CMDS-1] + .payload = samsung_panel_acl_update_cmds[0].payload; + samsung_panel_ready_to_on_cmds_fast[FAST_INIT_MAX_CMDS-1] + .dlen = samsung_panel_acl_update_cmds[0].dlen; + } + mipi_pd.ready_to_on_4_8_fast.size = FAST_INIT_MAX_CMDS; + return; +} + +static int prepare_brightness_control_cmd_array(int lcd_type, int bl_level) +{ + int cmd_size = 0, aid_change = 0; + unsigned char cmds_send_flag = 0; + + aid_change = set_gamma_level(bl_level, + mipi_pd.msd->dstat.gamma_mode); + if (aid_change < 0) + return -1; + /* Prepare the list */ + cmds_send_flag |= aid_change << 0; + if (lcd_type == 0x20 || lcd_type == 0x40 || lcd_type == 0x60) { + if (!set_elvss_level_4_8(bl_level)) + cmds_send_flag |= 1<<1; + } else { + if (!set_elvss_level(bl_level)) + cmds_send_flag |= 1<<1; + } + if (mipi_pd.msd->dstat.acl_on) { + int acl_change = is_acl_para_change(bl_level); + int acl_30_40_case = set_acl_on_level(bl_level); + if (acl_30_40_case && + mipi_pd.ldi_acl_stat == true) { + + cmds_send_flag |= 1<<2; + mipi_pd.ldi_acl_stat = false; + } + if (!acl_30_40_case) { + if (mipi_pd.ldi_acl_stat == false) { + + cmds_send_flag |= 0x3<<3; + mipi_pd.ldi_acl_stat = true; + + } else if (acl_change) + cmds_send_flag |= 1<<4; + } + } + + if (cmds_send_flag & 0x4) { /* acl off */ + + combined_ctrl[cmd_size].payload = acl_off; + combined_ctrl[cmd_size].dlen = sizeof(acl_off); + cmd_size++; + } + + if (cmds_send_flag & 0x10) { /* acl update */ + + combined_ctrl[cmd_size].payload = + samsung_panel_acl_update_cmds[0].payload; + combined_ctrl[cmd_size].dlen = + samsung_panel_acl_update_cmds[0].dlen; + cmd_size++; + } + + combined_ctrl[cmd_size].payload = + samsung_panel_gamma_update_cmds[0].payload; + combined_ctrl[cmd_size].dlen = + samsung_panel_gamma_update_cmds[0].dlen; + cmd_size++; + + combined_ctrl[cmd_size].payload = gamma_set_update; + combined_ctrl[cmd_size].dlen = sizeof(gamma_set_update); + cmd_size++; + + if (cmds_send_flag & 0x1) { + /* aid change */ + combined_ctrl[cmd_size].payload = panel_cond_aid_ref; + combined_ctrl[cmd_size].dlen = sizeof(panel_cond_aid_ref); + cmd_size++; + + combined_ctrl[cmd_size].payload = etc_cond_set3_aid_ref; + combined_ctrl[cmd_size].dlen = sizeof(etc_cond_set3_aid_ref); + cmd_size++; + } + + if (cmds_send_flag & 0x2) { /* elvss change */ + + combined_ctrl[cmd_size].payload = + samsung_panel_elvss_update_cmds[0].payload; + combined_ctrl[cmd_size].dlen = + samsung_panel_elvss_update_cmds[0].dlen; + cmd_size++; + } + + mipi_pd.combined_ctrl.size = cmd_size; + return cmds_send_flag; +} +static struct mipi_panel_data mipi_pd = { + .panel_name = "SMD_AMS465GS0x\n", + .ready_to_on = {samsung_panel_ready_to_on_cmds + , ARRAY_SIZE(samsung_panel_ready_to_on_cmds)}, + .ready_to_on_4_8 = {samsung_panel_ready_to_on_cmds_4_8 + , ARRAY_SIZE(samsung_panel_ready_to_on_cmds_4_8)}, + .ready_to_off = {samsung_panel_ready_to_off_cmds + , ARRAY_SIZE(samsung_panel_ready_to_off_cmds)}, + .on = {samsung_panel_on_cmds + , ARRAY_SIZE(samsung_panel_on_cmds)}, + .off = {samsung_panel_off_cmds + , ARRAY_SIZE(samsung_panel_off_cmds)}, + .late_on = {samsung_panel_late_on_cmds + , ARRAY_SIZE(samsung_panel_late_on_cmds)}, + .early_off = {samsung_panel_early_off_cmds + , ARRAY_SIZE(samsung_panel_early_off_cmds)}, + .gamma_update = {samsung_panel_gamma_update_cmds, + ARRAY_SIZE(samsung_panel_gamma_update_cmds)}, + #ifdef USE_ELVSS + .elvss_update = { + samsung_panel_elvss_update_cmds, + ARRAY_SIZE(samsung_panel_elvss_update_cmds)}, + .elvss_update_4_8 = { + samsung_panel_elvss_update_cmds_4_8, + ARRAY_SIZE(samsung_panel_elvss_update_cmds_4_8)}, +#endif +#ifdef USE_ACL + .acl_on = {samsung_panel_acl_on_cmds + , ARRAY_SIZE(samsung_panel_acl_on_cmds)}, + .acl_off = {samsung_panel_acl_off_cmds + , ARRAY_SIZE(samsung_panel_acl_off_cmds)}, + .acl_update = { + samsung_panel_acl_update_cmds, + ARRAY_SIZE(samsung_panel_acl_update_cmds)}, +#endif + .set_gamma = set_gamma_level, + .gamma_initial = gamma_cond_set_4_8, + .gamma_smartdim = gamma_cond_300cd, + .gamma_smartdim_4_8 = gamma_cond_300cd_4_8, + .set_acl = set_acl_on_level, + .set_elvss_4_8 = set_elvss_level_4_8, + .set_elvss = set_elvss_level, + .lcd_current_cd_idx = -1, + .lux_table = lux_tbl_acl, + .lux_table_max_cnt = ARRAY_SIZE(lux_tbl_acl), + .ready_to_on_4_8_fast = {samsung_panel_ready_to_on_cmds_4_8_fast + , ARRAY_SIZE(samsung_panel_ready_to_on_cmds_4_8_fast)}, + .ready_to_on_fast = {samsung_panel_ready_to_on_cmds_fast + , ARRAY_SIZE(samsung_panel_ready_to_on_cmds_fast)}, + .combined_ctrl = {combined_ctrl, ARRAY_SIZE(combined_ctrl)}, + .prepare_brightness_control_cmd_array = + prepare_brightness_control_cmd_array, + .prepare_fast_cmd_array = + prepare_fast_init_cmd_array, +}; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* DSI_BIT_CLK at 500MHz, 4 lane, RGB888 */ + {0x0F, 0x0a, 0x04, 0x00, 0x20}, /* regulator */ + /* timing */ + {0xB8, 0x8E, 0x1F, 0x00, 0x97, 0x99, 0x22, 0x90, + 0x23, 0x03, 0x04, 0xa0}, + /* phy ctrl */ + {0x5f, 0x00, 0x00, 0x10}, + /* strength */ + {0xff, 0x00, 0x06, 0x00}, + /* pll control */ + {0x0, 0x7f, 0x1, 0x1a, 0x00, 0x50, 0x48, 0x63, + 0x31, 0x0F, 0x03,/* 4 lane */ + 0x00, 0x14, 0x03, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01}, +}; + +static int __init mipi_cmd_samsung_oled_qhd_pt_init(void) +{ + int ret; + + +#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT + if (msm_fb_detect_client("mipi_cmd_samsung_oled_qhd")) + return 0; +#endif + pinfo.xres = 720; + pinfo.yres = 1280; + pinfo.height = 107; + pinfo.width = 60; + pinfo.mode2_xres = 0; + pinfo.mode2_yres = 0; + pinfo.mode2_bpp = 0; + + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + + if (samsung_has_cmc624()) { + pinfo.lcdc.h_front_porch = 158; + pinfo.lcdc.h_back_porch = 160; + } else { + pinfo.lcdc.h_front_porch = 278; + pinfo.lcdc.h_back_porch = 30; + } + + pinfo.lcdc.h_pulse_width = 2; + + pinfo.lcdc.v_back_porch = 2; + + if (samsung_has_cmc624()) + pinfo.lcdc.v_front_porch = 13; + else + pinfo.lcdc.v_front_porch = 53; + pinfo.lcdc.v_pulse_width = 1; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0x0; /* blue => black */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 255; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + pinfo.lcd.blt_ctrl = 1; + + if (samsung_has_cmc624()) + pinfo.clk_rate = 483000000; + else +#ifdef CONFIG_MIPI_CLK_500 + pinfo.clk_rate = 500000000; +#elif defined(CONFIG_MIPI_CLK_487) + pinfo.clk_rate = 487000000; +#else + pinfo.clk_rate = 499500000; +#endif + + pinfo.lcd.v_back_porch = pinfo.lcdc.v_back_porch; + pinfo.lcd.v_front_porch = pinfo.lcdc.v_front_porch; + pinfo.lcd.v_pulse_width = pinfo.lcdc.v_pulse_width; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = TRUE; + + if (samsung_has_cmc624()) + pinfo.mipi.hbp_power_stop = TRUE; + else + pinfo.mipi.hbp_power_stop = FALSE; + + pinfo.mipi.hsa_power_stop = TRUE; + pinfo.mipi.eof_bllp_power_stop = TRUE; + pinfo.mipi.bllp_power_stop = TRUE; + pinfo.mipi.traffic_mode = DSI_BURST_MODE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.data_lane2 = TRUE; + pinfo.mipi.data_lane3 = TRUE; + pinfo.mipi.t_clk_post = 0x19; + pinfo.mipi.t_clk_pre = 0x30; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + pinfo.mipi.esc_byte_ratio = 4; + + /* + * To support NONE CMC & HAS CMC + * some kind of parameter changing + */ + if (samsung_has_cmc624()) { + panel_cond_set_4_8[28] = 0x35; + panel_cond_aid_ref[28] = 0x35; + memcpy(display_cond_set, display_cond_set_cmc, + sizeof(display_cond_set)); + } else { + panel_cond_set_4_8[28] = 0x37; + panel_cond_aid_ref[28] = 0x37; + memcpy(display_cond_set, display_cond_set_none_cmc, + sizeof(display_cond_set)); + } + + ret = mipi_samsung_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WVGA_PT, + &mipi_pd); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} +module_init(mipi_cmd_samsung_oled_qhd_pt_init); diff --git a/drivers/video/msm/mipi_samsung_oled_video_wvga_pt.c b/drivers/video/msm/mipi_samsung_oled_video_wvga_pt.c new file mode 100644 index 00000000000..ef6e4787008 --- /dev/null +++ b/drivers/video/msm/mipi_samsung_oled_video_wvga_pt.c @@ -0,0 +1,1113 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_fb.h" +#include "mipi_samsung_oled.h" + +#define MAX_GAMMA_VALUE 25 +#define GEN_GAMMA_MAX 21 + +static struct msm_panel_info pinfo; +struct mipi_panel_data mipi_pd; + +/* testkey */ +static char test_key1[3] = { + 0xF0, + 0x5A, 0x5A +}; +static char test_key2[3] = { + 0xF1, + 0x5A, 0x5A +}; + +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) + +/* + * Panel Condition Set + */ +static char panel_cond_set1[] = { + 0xF8, 0x01, + 0x2C, 0x2C, 0x07, 0x07, 0x5F, + 0xB3, 0x6D, 0x97, 0x1D, 0x3A, + 0x0F, 0x00, 0x00 +}; +static char display_cond_set1[] = { + 0xF2, + 0x02, 0x9, 0x69, 0x14, 0x10, +}; +#if defined(CONFIG_MACH_COMANCHE) +static char display_cond_set2[] = { + 0xF7, + 0x03, 0x00, 0x00, +}; +#else +static char display_cond_set2[] = { + 0xF7, + 0x00, 0x00, 0x00, +}; +#endif +/* GAMMA SET FROM SMD */ +#if defined(CONFIG_MACH_AEGIS2) +static char gamma_set_cmd1[] = { + 0xFA, + 0x02, 0x18, 0x08, 0x24, 0x70, + 0x6E, 0x4E, 0xBC, 0xC0, 0xAF, + 0xB3, 0xB8, 0xA5, 0xC5, 0xC7, + 0xBB, 0x00, 0xB9, 0x00, 0xBB, + 0x00, 0xFC +}; +#elif defined(CONFIG_MACH_COMANCHE) +static char gamma_set_cmd1[] = { + 0xFA, /* 180CD */ + 0x02, 0x18, 0x08, 0x24, 0x38, + 0x45, 0x15, 0xB8, 0xBE, 0xAD, + 0xAE, 0xB6, 0xA2, 0xC5, 0xC9, + 0xBB, 0x00, 0x8F, 0x00, 0x8C, + 0x00, 0xC3, +}; +#else +static char gamma_set_cmd1[23] = { + 0xFA, /* 110 cd, from smart dimm algo */ + 0x02, 0x31, 0x00, 0x4F, 0x13, + 0x60, 0x01, 0xAF, 0xCD, 0xA6, + 0xAC, 0xC7, 0x98, 0xC4, 0xCF, + 0xB6, 0x00, 0x74, 0x00, 0x6B, + 0x00, 0x8A +}; +#endif + + + +static char gamma_set_update[] = { + 0xFA, + 0x03 +}; +static char etc_cond_set1[] = { + 0xF6, 0x00, 0x8E, 0x0F +}; +static char etc_cond_set2[] = { + 0xB3, 0x6C +}; +static char etc_cond_set3[] = { + 0xB5, + 0x2C, 0x12, 0x0C, 0x0A, 0x10, + 0x0E, 0x17, 0x13, 0x1F, 0x1A, + 0x2A, 0x24, 0x1F, 0x1B, 0x1A, + 0x17, 0x2B, 0x26, 0x22, 0x20, + 0x3A, 0x34, 0x30, 0x2C, 0x29, + 0x26, 0x25, 0x23, 0x21, 0x20, + 0x1E, 0x1E +}; +static char etc_cond_set4[] = { + 0xB6, + 0x00, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x44, 0x44, 0x55, 0x55, + 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66 +}; +static char etc_cond_set5[] = { + 0xB7, + 0x2C, 0x12, 0x0C, 0x0A, 0x10, + 0x0E, 0x17, 0x13, 0x1F, 0x1A, + 0x2A, 0x24, 0x1F, 0x1B, 0x1A, + 0x17, 0x2B, 0x26, 0x22, 0x20, + 0x3A, 0x34, 0x30, 0x2C, 0x29, + 0x26, 0x25, 0x23, 0x21, 0x20, + 0x1E, 0x1E +}; + + +static char etc_cond_set6[] = { + 0xB8, + 0x00, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x44, 0x44, 0x55, 0x55, + 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66 +}; + +static char etc_cond_set7[] = { + 0xB9, + 0x2C, 0x12, 0x0C, 0x0A, 0x10, + 0x0E, 0x17, 0x13, 0x1F, 0x1A, + 0x2A, 0x24, 0x1F, 0x1B, 0x1A, + 0x17, 0x2B, 0x26, 0x22, 0x20, + 0x3A, 0x34, 0x30, 0x2C, 0x29, + 0x26, 0x25, 0x23, 0x21, 0x20, + 0x1E, 0x1E +}; + +static char etc_cond_set8[] = { + 0xBA, + 0x00, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x44, 0x44, 0x55, 0x55, + 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66 +}; +#else + +static char test_key3[3] = { + 0xFC, + 0x5A, 0x5A +}; + +/* GAMMA SET FROM SMD */ +static char gamma_set_cmd1[23] = { + 0xFA, + 0x00, 0x18, 0x08, 0x24, 0x80, + 0x6E, 0x5F, 0xC1, 0xC6, 0xB6, + 0xBC, 0xC0, 0xAE, 0xCC, 0xD0, + 0xC2, 0x00, 0x8F, 0x00, 0x8D, + 0x00, 0xC2 +}; + + +static char gamma_set_cmd2[6] = { + 0xF2, + 0x02, 0x03, 0x1C, 0x0E, 0x10 +}; +static char gamma_set_cmd3[2] = { + 0xFA, + 0x01 +}; +static char gamma_set_cmd4[2] = { + 0xF7, + 0x00 +}; +static char gamma_set_cmd5[4] = { + 0xF6, + 0x00, 0x8E, 0x07 +}; +static char gamma_set_cmd6[6] = { + 0xF2, + 0x02, 0x0B, 0x1C, 0x10, 0x10 +}; + +/* pEntilE SMD spEC. CoDE + * RB3 63 C0 32 02 + */ +static char pentile_cmd1[4] = { + 0xB4, + 0x00, 0x00, 0x00 +}; +static char pentile_cmd2[33] = { + 0xB5, + 0x2C, 0x12, 0x0C, 0x0A, 0x10, + 0x0E, 0x17, 0x13, 0x1F, 0x1A, + 0x2A, 0x24, 0x1F, 0x1B, 0x1A, + 0x17, 0x2B, 0x26, 0x22, 0x20, + 0x3A, 0x34, 0x30, 0x2C, 0x29, + 0x26, 0x25, 0x23, 0x21, 0x20, + 0x1E, 0x1E +}; +static char pentile_cmd3[17] = { + 0xB6, + 0x00, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x44, 0x44, 0x55, 0x55, + 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66 +}; +static char pentile_cmd4[33] = { + 0xB7, + 0x2C, 0x12, 0x0C, 0x0A, 0x10, + 0x0E, 0x17, 0x13, 0x1F, 0x1A, + 0x2A, 0x24, 0x1F, 0x1B, 0x1A, + 0x17, 0x2B, 0x26, 0x22, 0x20, + 0x3A, 0x34, 0x30, 0x2C, 0x29, + 0x26, 0x25, 0x23, 0x21, 0x20, + 0x1E, 0x1E +}; +static char pentile_cmd5[17] = { + 0xB8, + 0x00, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x44, 0x44, 0x55, 0x55, + 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66 +}; +static char pentile_cmd6[33] = { + 0xB9, + 0x2C, 0x12, 0x0C, 0x0A, 0x10, + 0x0E, 0x17, 0x13, 0x1F, 0x1A, + 0x2A, 0x24, 0x1F, 0x1B, 0x1A, + 0x17, 0x2B, 0x26, 0x22, 0x20, + 0x3A, 0x34, 0x30, 0x2C, 0x29, + 0x26, 0x25, 0x23, 0x21, 0x20, + 0x1E, 0x1E +}; +static char pentile_cmd7[17] = { + 0xBA, + 0x00, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x44, 0x44, 0x55, 0x55, + 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66 +}; +#endif + +static char all_pixel_off[] = { 0x22, /* no param */ }; +static char normal_mode_on[] = { 0x13, /* no parm */ }; +static char sleep_in[2] = { 0x10, /* no param */ }; +static char sleep_out[2] = { 0x11, /* no param */ }; +static char display_on[2] = { 0x29, /* no param */ }; +static char display_off[2] = { 0x28, /* no param */ }; + +static char acl_on[] = { + 0xC0, + 0x01 +}; + +static char acl_off[] = { + 0xC0, + 0x00 +}; + +static char elvss_cond_set[] = { + 0xB2, + 0x10, 0x10, 0x10, 0x10 +}; + +static char elvss_on[] = { + 0xB1, + 0x0B, +}; + +enum { + GAMMA_30CD, + GAMMA_40CD, + GAMMA_50CD, + GAMMA_60CD, + GAMMA_70CD, + GAMMA_80CD, + GAMMA_90CD, + GAMMA_100CD, + GAMMA_110CD, + GAMMA_120CD, + GAMMA_130CD, + GAMMA_140CD, + GAMMA_150CD, + GAMMA_160CD, + GAMMA_170CD, + GAMMA_180CD, + GAMMA_190CD, + GAMMA_200CD, + GAMMA_210CD, + GAMMA_220CD, + GAMMA_230CD, + GAMMA_240CD, + GAMMA_250CD, + GAMMA_300CD, +}; + +static int lux_tbl_acl[] = { + 30, 40, 50, 60, 70, 80, + 90, 100, 110, 120, 130, 140, + 150, 160, 170, 180, 190, 200, + 210, 220, 230, 240, 250, 300 +}; + + +static char GAMMA_SmartDimming_COND_SET[] = { + 0xFA, /* 180 cd */ + 0x02, 0x18, 0x08, 0x24, 0x7B, 0x6D, + 0x5B, 0xC0, 0xC5, 0xB3, 0xBA, 0xBE, + 0xAD, 0xCA, 0xCE, 0xBF, 0x00, 0x99, + 0x00, 0x97, 0x00, 0xD0, +}; + +static char prepare_mtp_read1[] = { + 0xF0, + 0x5A, 0x5A +}; + +static char prepare_mtp_read2[] = { + 0xF1, + 0x5A, 0x5A +}; + +static char contention_error_remove[] = { + 0xD5, + 0xE7, 0x14, 0x60, 0x17, 0x0A, + 0x49, 0xC3, 0x8F, 0x19, 0x64, + 0x91, 0x84, 0x76, 0x20, 0x43, + 0x00, +}; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) + +static struct dsi_cmd_desc samsung_display_on_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(test_key1), test_key1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(test_key2), test_key2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 10, + sizeof(sleep_out), sleep_out}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(prepare_mtp_read1), prepare_mtp_read1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(prepare_mtp_read2), prepare_mtp_read2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(contention_error_remove), contention_error_remove}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(panel_cond_set1), panel_cond_set1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(display_cond_set1), display_cond_set1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(display_cond_set2), display_cond_set2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_cmd1), gamma_set_cmd1}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set1), etc_cond_set1}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set2), etc_cond_set2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set3), etc_cond_set3}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set4), etc_cond_set4}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set5), etc_cond_set5}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set6), etc_cond_set6}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(etc_cond_set7), etc_cond_set7}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 120, + sizeof(etc_cond_set8), etc_cond_set8}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 0, + sizeof(display_on), display_on}, +}; +static struct dsi_cmd_desc samsung_panel_ready_to_off_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(display_off), display_off}, +}; + +static struct dsi_cmd_desc samsung_panel_on_cmds[] = { + {DTYPE_GEN_WRITE, 1, 0, 0, 0, + sizeof(display_on), display_on}, +}; + +static struct dsi_cmd_desc samsung_panel_off_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 120, + sizeof(sleep_in), sleep_in}, +}; + +static struct dsi_cmd_desc samsung_panel_late_on_cmds[] = { + {DTYPE_GEN_WRITE, 1, 0, 0, 0, + sizeof(normal_mode_on), normal_mode_on}, + {DTYPE_GEN_WRITE, 1, 0, 0, 5, + sizeof(display_on), display_on}, +}; + +static struct dsi_cmd_desc samsung_panel_early_off_cmds[] = { + {DTYPE_GEN_WRITE, 1, 0, 0, 0, + sizeof(all_pixel_off), all_pixel_off}, +}; +static struct dsi_cmd_desc samsung_mtp_read_cmds[] = { + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(prepare_mtp_read1), prepare_mtp_read1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(prepare_mtp_read2), prepare_mtp_read2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 120, + sizeof(sleep_out), sleep_out}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(contention_error_remove), contention_error_remove}, +}; +/********************* ACL *******************/ +static char ACL_COND_SET_50[] = { + 0xC1, + 0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, + 0xDF, 0x00, 0x00, 0x03, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x0F, 0x16, 0x1D, 0x24, 0x2A, + 0x31, 0x38, 0x3F, 0x46, +}; +static char ACL_COND_SET_40[] = { + 0xC1, + 0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, + 0xDF, 0x00, 0x00, 0x03, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, + 0x06, 0x0C, 0x11, 0x16, 0x1C, 0x21, + 0x26, 0x2B, 0x31, 0x36, +}; + +static struct dsi_cmd_desc DSI_CMD_ACL_50 = { + DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(ACL_COND_SET_50), ACL_COND_SET_50 }; +static struct dsi_cmd_desc DSI_CMD_ACL_40 = { + DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(ACL_COND_SET_40), ACL_COND_SET_40 }; + +static struct dsi_cmd_desc_LCD lcd_acl_table[] = { + {0, "30", NULL}, + {0, "40", NULL}, + {40, "50", &DSI_CMD_ACL_40}, + {40, "60", &DSI_CMD_ACL_40}, + {40, "70", &DSI_CMD_ACL_40}, + {40, "80", &DSI_CMD_ACL_40}, + {40, "90", &DSI_CMD_ACL_40}, + {40, "100", &DSI_CMD_ACL_40}, + {40, "110", &DSI_CMD_ACL_40}, + {40, "120", &DSI_CMD_ACL_40}, + {40, "130", &DSI_CMD_ACL_40}, + {40, "140", &DSI_CMD_ACL_40}, + {40, "150", &DSI_CMD_ACL_40}, + {40, "160", &DSI_CMD_ACL_40}, + {40, "170", &DSI_CMD_ACL_40}, + {40, "180", &DSI_CMD_ACL_40}, + {40, "190", &DSI_CMD_ACL_40}, + {40, "200", &DSI_CMD_ACL_40}, + {40, "210", &DSI_CMD_ACL_40}, + {40, "220", &DSI_CMD_ACL_40}, + {40, "230", &DSI_CMD_ACL_40}, + {40, "240", &DSI_CMD_ACL_40}, + {40, "250", &DSI_CMD_ACL_40}, + {50, "300", &DSI_CMD_ACL_50}, +}; + +static struct dsi_cmd_desc samsung_panel_acl_on_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on}, +}; + +static struct dsi_cmd_desc samsung_panel_acl_off_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(acl_off), acl_off}, +}; +static struct dsi_cmd_desc samsung_panel_acl_update_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(ACL_COND_SET_40), ACL_COND_SET_40}, +}; + +static struct dsi_cmd_desc samsung_panel_gamma_update_cmds[2] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_cmd1), gamma_set_cmd1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_update), gamma_set_update}, +}; + +static struct dsi_cmd_desc samsung_panel_elvss_update_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(elvss_on), elvss_on}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(elvss_cond_set), elvss_cond_set}, +}; + +/********************* ELVSS *******************/ +#define LCD_ELVSS_DELTA_300CD (0) +#define LCD_ELVSS_DELTA_200CD (0x07) +#define LCD_ELVSS_DELTA_160CD (0x09) +#define LCD_ELVSS_DELTA_100CD (0x0D) +#if defined(CONFIG_MACH_COMANCHE) +#define LCD_ELVSS_RESULT_LIMIT (0x1F) +#else +#define LCD_ELVSS_RESULT_LIMIT (0x29) +#endif +static int GET_ELVSS_ID[] = { + LCD_ELVSS_DELTA_100CD,/* 0 = 30_dimming,*/ + LCD_ELVSS_DELTA_100CD,/* 1 = 40*/ + LCD_ELVSS_DELTA_100CD,/* 2 = 50*/ + LCD_ELVSS_DELTA_100CD,/* 3 = 60,*/ + LCD_ELVSS_DELTA_100CD,/* 4 = 70,*/ + LCD_ELVSS_DELTA_100CD,/* 5 = 80,*/ + LCD_ELVSS_DELTA_100CD,/* 6 = 90,*/ + LCD_ELVSS_DELTA_100CD,/* 7 = 100,*/ + LCD_ELVSS_DELTA_160CD,/* 8 = 110,*/ + LCD_ELVSS_DELTA_160CD,/* 9 = 120,*/ + LCD_ELVSS_DELTA_160CD,/* 10 = 130,*/ + LCD_ELVSS_DELTA_160CD,/* 11 = 140,*/ + LCD_ELVSS_DELTA_160CD,/* 12 = 150,*/ + LCD_ELVSS_DELTA_160CD,/* 13 = 160,*/ + LCD_ELVSS_DELTA_200CD,/* 14 = 170,*/ + LCD_ELVSS_DELTA_200CD,/* 15 = 180,*/ + LCD_ELVSS_DELTA_200CD,/* 16 = 190,*/ + LCD_ELVSS_DELTA_200CD,/* 17 = 200,*/ + LCD_ELVSS_DELTA_300CD,/* 18 = 210,*/ + LCD_ELVSS_DELTA_300CD,/* 19 = 220,*/ + LCD_ELVSS_DELTA_300CD,/* 20 = 230,*/ + LCD_ELVSS_DELTA_300CD,/* 21 = 240,*/ + LCD_ELVSS_DELTA_300CD,/* 22 = 250,*/ + LCD_ELVSS_DELTA_300CD/* 23 = 300,*/ +}; + +#define LCD_ELVSS_DEFAULT_100CD (0x1D) +#define LCD_ELVSS_DEFAULT_160CD (0x17) +#define LCD_ELVSS_DEFAULT_200CD (0x14) +#define LCD_ELVSS_DEFAULT_300CD (0x10) +static int GET_DEFAULT_ELVSS_ID[] = { + LCD_ELVSS_DEFAULT_100CD,/* 0 = 30_dimming,*/ + LCD_ELVSS_DEFAULT_100CD,/* 1 = 40*/ + LCD_ELVSS_DEFAULT_100CD,/* 2 = 50*/ + LCD_ELVSS_DEFAULT_100CD,/* 3 = 60,*/ + LCD_ELVSS_DEFAULT_100CD,/* 4 = 70,*/ + LCD_ELVSS_DEFAULT_100CD,/* 5 = 80,*/ + LCD_ELVSS_DEFAULT_100CD,/* 6 = 90,*/ + LCD_ELVSS_DEFAULT_100CD,/* 7 = 100,*/ + LCD_ELVSS_DEFAULT_160CD,/* 8 = 110,*/ + LCD_ELVSS_DEFAULT_160CD,/* 9 = 120,*/ + LCD_ELVSS_DEFAULT_160CD,/* 10 = 130,*/ + LCD_ELVSS_DEFAULT_160CD,/* 11 = 140,*/ + LCD_ELVSS_DEFAULT_160CD,/* 12 = 150,*/ + LCD_ELVSS_DEFAULT_160CD,/* 13 = 160,*/ + LCD_ELVSS_DEFAULT_200CD,/* 14 = 170,*/ + LCD_ELVSS_DEFAULT_200CD,/* 15 = 180,*/ + LCD_ELVSS_DEFAULT_200CD,/* 16 = 190,*/ + LCD_ELVSS_DEFAULT_200CD,/* 17 = 200,*/ + LCD_ELVSS_DEFAULT_300CD,/* 18 = 210,*/ + LCD_ELVSS_DEFAULT_300CD,/* 19 = 220,*/ + LCD_ELVSS_DEFAULT_300CD,/* 20 = 230,*/ + LCD_ELVSS_DEFAULT_300CD,/* 21 = 240,*/ + LCD_ELVSS_DEFAULT_300CD,/* 22 = 250,*/ + LCD_ELVSS_DEFAULT_300CD/* 23 = 300,*/ +}; + +static int get_candela_index(int bl_level) +{ + int backlightlevel; + + /* brightness setting from platform is from 0 to 255 + * But in this driver, brightness is only supported from 0 to 24 */ + + switch (bl_level) { + case 0 ... 39: + backlightlevel = GAMMA_30CD; /* 0*/ + break; + case 40 ... 49: + backlightlevel = GAMMA_40CD; /* 1 */ + break; + case 50 ... 59: + backlightlevel = GAMMA_50CD; /* 2 */ + break; + case 60 ... 69: + backlightlevel = GAMMA_60CD; /* 3 */ + break; + case 70 ... 79: + backlightlevel = GAMMA_70CD; /* 4 */ + break; + case 80 ... 89: + backlightlevel = GAMMA_80CD; /* 5 */ + break; + case 90 ... 99: + backlightlevel = GAMMA_90CD; /* 6 */ + break; + case 100 ... 109: + backlightlevel = GAMMA_100CD; /* 7 */ + break; + case 110 ... 119: + backlightlevel = GAMMA_110CD; /* 8 */ + break; + case 120 ... 129: + backlightlevel = GAMMA_120CD; /* 9 */ + break; + case 130 ... 139: + backlightlevel = GAMMA_130CD; /* 10 */ + break; + case 140 ... 149: + backlightlevel = GAMMA_140CD; /* 11 */ + break; + case 150 ... 159: + backlightlevel = GAMMA_150CD; /* 12 */ + break; + case 160 ... 169: + backlightlevel = GAMMA_160CD; /* 13 */ + break; + case 170 ... 179: + backlightlevel = GAMMA_170CD; /* 14 */ + break; + case 180 ... 189: + backlightlevel = GAMMA_180CD; /* 15 */ + break; + case 190 ... 199: + backlightlevel = GAMMA_190CD; /* 16 */ + break; + case 200 ... 209: +#if defined(CONFIG_MACH_APEXQ) + if (poweroff_charging) + backlightlevel = GAMMA_210CD; /* 17 */ + else + backlightlevel = GAMMA_200CD; /* 17 */ +#else + backlightlevel = GAMMA_200CD; /* 17 */ +#endif + break; + case 210 ... 219: + backlightlevel = GAMMA_210CD; /* 18 */ + break; + case 220 ... 229: + backlightlevel = GAMMA_220CD; /* 10 */ + break; + case 230 ... 239: + backlightlevel = GAMMA_230CD; /* 20 */ + break; + case 240 ... 249: + backlightlevel = GAMMA_240CD; /* 21 */ + break; + case 250 ... 254: + backlightlevel = GAMMA_250CD; /* 22 */ + break; + case 255: + if (mipi_pd.msd->dstat.auto_brightness == 1) + backlightlevel = GAMMA_300CD; /* 23 */ + else + backlightlevel = GAMMA_250CD; /* 22 */ + break; + default: + backlightlevel = GAMMA_40CD; /* 1 */ + break; + } + return backlightlevel; +} + +static int set_acl_on_level(int bl_level) +{ + int cd; + cd = get_candela_index(bl_level); + + if (!lcd_acl_table[cd].lux) + return 1; + + if (lcd_acl_table[cd].lux) { + samsung_panel_acl_update_cmds[0].dlen = + lcd_acl_table[cd].cmd->dlen; + samsung_panel_acl_update_cmds[0].payload = + lcd_acl_table[cd].cmd->payload; + } + return 0; +} + +static int set_elvss_level(int bl_level) +{ + unsigned char calc_elvss; + int cd; + int id3; + int id2 = (mipi_pd.manufacture_id>>8) & 0xFF; + + cd = get_candela_index(bl_level); + id3 = mipi_pd.manufacture_id & 0xFF; + + if ((id2 == 0xA4) || (id2 == 0xB4)) + calc_elvss = id3 + GET_ELVSS_ID[cd]; + else + calc_elvss = GET_DEFAULT_ELVSS_ID[cd]; + + pr_debug("%s: ID2=%x, ID3=%x, calc_elvss = %x\n", __func__, id2, id3, + calc_elvss); + + /* + * COMANCHE DC-DC : STOD13CM + * AEGIS2 DC-DC : STOD13AS + * APEXQ DC-DC : STOD13AS + */ + if (calc_elvss > LCD_ELVSS_RESULT_LIMIT) + calc_elvss = LCD_ELVSS_RESULT_LIMIT; + + if (elvss_cond_set[2] == calc_elvss) + return 1; + + elvss_cond_set[1] = calc_elvss; + elvss_cond_set[2] = calc_elvss; + elvss_cond_set[3] = calc_elvss; + elvss_cond_set[4] = calc_elvss; + + return 0; +} + +void reset_gamma_level(void) +{ + pr_info("reset_gamma_level\n"); + mipi_pd.lcd_current_cd_idx = -1; + mipi_pd.ldi_acl_stat = false; + elvss_cond_set[2] = 0x00; +} + +static int set_gamma_level(int bl_level, enum gamma_mode_list gamma_mode) +{ + int cd; + int *lux_tbl = lux_tbl_acl; + + cd = get_candela_index(bl_level); + + if (mipi_pd.lcd_current_cd_idx == cd) + return -1; + else + mipi_pd.lcd_current_cd_idx = cd; + + pr_debug(" Gamma mode: %d\n", gamma_mode); + + if (gamma_mode == GAMMA_SMART) { + + /* SMART Dimming gamma_lux; */ + char pBuffer[256]; + int i; + int gamma_lux; + + gamma_lux = lux_tbl[cd]; + + if (gamma_lux > SmartDimming_CANDELA_UPPER_LIMIT) + gamma_lux = SmartDimming_CANDELA_UPPER_LIMIT; + + mipi_pd.smart_s6e63m0.brightness_level = gamma_lux; + + for (i = SmartDimming_GammaUpdate_Pos; + i < sizeof(GAMMA_SmartDimming_COND_SET); i++) + GAMMA_SmartDimming_COND_SET[i] = 0; + generate_gamma(&(mipi_pd.smart_s6e63m0), + GAMMA_SmartDimming_COND_SET + + SmartDimming_GammaUpdate_Pos, + GEN_GAMMA_MAX); + + samsung_panel_gamma_update_cmds[0].dlen = + sizeof(GAMMA_SmartDimming_COND_SET); + samsung_panel_gamma_update_cmds[0].payload = + GAMMA_SmartDimming_COND_SET; + pBuffer[0] = 0; + for (i = 0; i < sizeof(GAMMA_SmartDimming_COND_SET); i++) { + snprintf(pBuffer + strnlen(pBuffer, 256), 256, " %02x", + GAMMA_SmartDimming_COND_SET[i]); + } + pr_debug("SD: %03d %s\n", gamma_lux, pBuffer); + pr_info("bl_level:%d,cd:%d:Candela:%d\n", bl_level, cd, + gamma_lux); + } + + return 0; +} + +static int is_acl_para_change(int bl_level) +{ + int cd = get_candela_index(bl_level); + int change = 0; + + if (!lcd_acl_table[cd].lux) + return 0; + + change = memcmp(samsung_panel_acl_update_cmds[0].payload, + lcd_acl_table[cd].cmd->payload, + lcd_acl_table[cd].cmd->dlen); + return change; +} + +static struct dsi_cmd_desc combined_ctrl[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 5, + sizeof(GAMMA_SmartDimming_COND_SET), + GAMMA_SmartDimming_COND_SET} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 5, + sizeof(gamma_set_update), gamma_set_update} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(elvss_cond_set), elvss_cond_set} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(elvss_on), elvss_on} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_on), acl_on} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(acl_off), acl_off} + , + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(ACL_COND_SET_40), ACL_COND_SET_40} + , +}; + +static int prepare_brightness_control_cmd_array(int lcd_type, int bl_level) +{ + int cmd_size = 0, gamma_change = 0; + unsigned char cmds_send_flag = 0; + + gamma_change = set_gamma_level(bl_level, + mipi_pd.msd->dstat.gamma_mode); + if (gamma_change < 0) + return -1; + + /* Prepare the list */ + if (!set_elvss_level(bl_level)) + cmds_send_flag |= 1<<0; + + if (mipi_pd.msd->dstat.acl_on) { + int acl_change = is_acl_para_change(bl_level); + int acl_30_40_case = set_acl_on_level(bl_level); + if (acl_30_40_case && + mipi_pd.ldi_acl_stat == true) { + + cmds_send_flag |= 1<<1; + mipi_pd.ldi_acl_stat = false; + } + if (!acl_30_40_case) { + if (mipi_pd.ldi_acl_stat == false) { + + cmds_send_flag |= 0x3<<2; + mipi_pd.ldi_acl_stat = true; + + } else if (acl_change) + cmds_send_flag |= 1<<3; + } + } + combined_ctrl[cmd_size].payload = + samsung_panel_gamma_update_cmds[0].payload; + combined_ctrl[cmd_size].dlen = + samsung_panel_gamma_update_cmds[0].dlen; + cmd_size++; + + combined_ctrl[cmd_size].payload = gamma_set_update; + combined_ctrl[cmd_size].dlen = sizeof(gamma_set_update); + cmd_size++; + + if (cmds_send_flag & 0x1) { /* elvss change */ + + combined_ctrl[cmd_size].payload = + samsung_panel_elvss_update_cmds[0].payload; + combined_ctrl[cmd_size].dlen = + samsung_panel_elvss_update_cmds[0].dlen; + cmd_size++; + + combined_ctrl[cmd_size].payload = + samsung_panel_elvss_update_cmds[1].payload; + combined_ctrl[cmd_size].dlen = + samsung_panel_elvss_update_cmds[1].dlen; + cmd_size++; + } + if (cmds_send_flag & 0x2) { /* acl off */ + + combined_ctrl[cmd_size].payload = acl_off; + combined_ctrl[cmd_size].dlen = sizeof(acl_off); + cmd_size++; + } + if (cmds_send_flag & 0x4) { /* acl on */ + + combined_ctrl[cmd_size].payload = acl_on; + combined_ctrl[cmd_size].dlen = sizeof(acl_on); + cmd_size++; + } + if (cmds_send_flag & 0x8) { /* acl update */ + + combined_ctrl[cmd_size].payload = + samsung_panel_acl_update_cmds[0].payload; + combined_ctrl[cmd_size].dlen = + samsung_panel_acl_update_cmds[0].dlen; + cmd_size++; + } + mipi_pd.combined_ctrl.size = cmd_size; + return cmds_send_flag; +} + +struct mipi_panel_data mipi_pd = { + .panel_name = "SMD_AMS397GEXX\n", + .ready_to_on = {samsung_display_on_cmds + , ARRAY_SIZE(samsung_display_on_cmds)}, + .ready_to_off = {samsung_panel_ready_to_off_cmds + , ARRAY_SIZE(samsung_panel_ready_to_off_cmds)}, + .on = {samsung_panel_on_cmds + , ARRAY_SIZE(samsung_panel_on_cmds)}, + .off = {samsung_panel_off_cmds + , ARRAY_SIZE(samsung_panel_off_cmds)}, + .late_on = {samsung_panel_late_on_cmds + , ARRAY_SIZE(samsung_panel_late_on_cmds)}, + .early_off = {samsung_panel_early_off_cmds + , ARRAY_SIZE(samsung_panel_early_off_cmds)}, + .acl_on = {samsung_panel_acl_on_cmds + , ARRAY_SIZE(samsung_panel_acl_on_cmds)}, + .acl_off = {samsung_panel_acl_off_cmds + , ARRAY_SIZE(samsung_panel_acl_off_cmds)}, + .acl_update = {samsung_panel_acl_update_cmds, + ARRAY_SIZE(samsung_panel_acl_update_cmds)}, + .set_acl = set_acl_on_level, + .elvss_update = {samsung_panel_elvss_update_cmds, + ARRAY_SIZE(samsung_panel_elvss_update_cmds)}, + .set_elvss = set_elvss_level, + .gamma_update = {samsung_panel_gamma_update_cmds, + ARRAY_SIZE(samsung_panel_gamma_update_cmds)}, + .set_gamma = set_gamma_level, + .lcd_current_cd_idx = -1, + .mtp_read_enable = {samsung_mtp_read_cmds + , ARRAY_SIZE(samsung_mtp_read_cmds)}, + .combined_ctrl = {combined_ctrl, ARRAY_SIZE(combined_ctrl)}, + .prepare_brightness_control_cmd_array = + prepare_brightness_control_cmd_array, + .gamma_initial = gamma_set_cmd1, +}; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { +/* regulator */ + {0x03, 0x0a, 0x04, 0x00, 0x20}, + /* timing */ + {0x5B, 0x28, 0x0C, 0x00, 0x33, 0x3A, 0x10, 0x2C, 0x14, 0x03, 0x04}, + /* phy ctrl */ + {0x5f, 0x00, 0x00, 0x10}, + /* strength */ + {0xee, 0x02, 0x86, 0x00}, + /* pll control */ + {0x0, 0x7f, 0x31, 0xda, 0x00, 0x50, 0x48, 0x63, + 0x41, 0x0f, 0x01, + 0x00, 0x14, 0x03, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 }, +}; +#else +static struct dsi_cmd_desc samsung_display_on_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(test_key1), test_key1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(test_key2), test_key2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(test_key3), test_key3}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_cmd1), gamma_set_cmd1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_cmd2), gamma_set_cmd2}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 0, + sizeof(gamma_set_cmd3), gamma_set_cmd3}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 0, + sizeof(gamma_set_cmd4), gamma_set_cmd4}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_cmd5), gamma_set_cmd5}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(gamma_set_cmd6), gamma_set_cmd6}, + + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(pentile_cmd1), pentile_cmd1}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(pentile_cmd2), pentile_cmd2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(pentile_cmd3), pentile_cmd3}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(pentile_cmd4), pentile_cmd4}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(pentile_cmd5), pentile_cmd5}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(pentile_cmd6), pentile_cmd6}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, + sizeof(pentile_cmd7), pentile_cmd7}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 120, + sizeof(sleep_out), sleep_out}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 0, + sizeof(display_on), display_on}, +}; + +static struct dsi_cmd_desc samsung_display_off_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 0, + sizeof(display_off), display_off}, + {DTYPE_DCS_WRITE, 1, 0, 0, 120, + sizeof(sleep_in), sleep_in}, +}; +static struct dsi_cmd_desc samsung_display_acl_on_cmds[] = { +}; + +static struct dsi_cmd_desc samsung_display_acl_off_cmds[] = { +}; + +struct mipi_panel mipi_pd = { + {samsung_display_on_cmds, ARRAY_SIZE(samsung_display_on_cmds)}, + {samsung_display_off_cmds, ARRAY_SIZE(samsung_display_off_cmds)}, +}; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* regulator */ + {0x03, 0x0a, 0x04, 0x00, 0x20}, + /* timing */ + {0xAB, 0x8A, 0x18, 0x00, 0x92, 0x97, 0x1C, 0x8C, + 0x1B, 0x03, 0x04, 0xa0}, + /* phy ctrl */ + {0x5f, 0x00, 0x00, 0x10}, + /* strength */ + {0xff, 0x00, 0x06, 0x00}, + /* pll control */ + {0x0, 0x7B, 0x1, 0x1a, 0x00, 0x50, 0x48, 0x63, + 0x41, 0xf, 0x7, + 0x00, 0x14, 0x03, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 }, +}; +#endif + + +static int __init mipi_video_samsung_oled_wvga_pt_init(void) +{ + int ret; + +#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT + if (msm_fb_detect_client("mipi_video_samsung_oled_wvga")) + return 0; +#endif + + pinfo.xres = 480; + pinfo.yres = 800; + /* + * + * Panel's Horizontal input timing requirement is to + * include dummy(pad) data of 200 clk in addition to + * width and porch/sync width values + */ + pinfo.lcdc.xres_pad = 0; + pinfo.lcdc.yres_pad = 2; + + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_WVGA_PT_PANEL) + pinfo.bpp = 24; +#else + pinfo.bpp = 32; +#endif + pinfo.lcdc.h_back_porch = 16; /* 64 */ + pinfo.lcdc.h_front_porch = 16; /* 64 */ + pinfo.lcdc.h_pulse_width = 4; + pinfo.lcdc.v_back_porch = 7; /* 4 */ + pinfo.lcdc.v_front_porch = 105; + pinfo.lcdc.v_pulse_width = 2; /* 2 */ + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff;/* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 255; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.clk_rate = 343500000; + pinfo.mipi.mode = DSI_VIDEO_MODE; + + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = FALSE; + pinfo.mipi.hbp_power_stop = FALSE; + pinfo.mipi.hsa_power_stop = FALSE; + pinfo.mipi.eof_bllp_power_stop = TRUE; + pinfo.mipi.bllp_power_stop = TRUE; + pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + /*pinfo.mipi.tx_eot_append = TRUE;*/ + + pinfo.mipi.t_clk_post = 0x19; + pinfo.mipi.t_clk_pre = 0x2D; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + pinfo.mipi.esc_byte_ratio = 1; + + + ret = mipi_samsung_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WVGA_PT, + &mipi_pd); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_samsung_oled_wvga_pt_init); diff --git a/drivers/video/msm/mipi_samsung_tft_video_wxga_pt.c b/drivers/video/msm/mipi_samsung_tft_video_wxga_pt.c new file mode 100644 index 00000000000..6831b94a340 --- /dev/null +++ b/drivers/video/msm/mipi_samsung_tft_video_wxga_pt.c @@ -0,0 +1,165 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_tc358764_dsi2lvds.h" + +static struct msm_panel_info pinfo; + +static struct dsi2lvds_panel_data dsi2lvds_pd = { + .panel_name = "SMD_LTL101AL06\n", +}; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* DSIPHY_REGULATOR_CTRL */ + .regulator = {0x03, 0x0a, 0x04, 0x00, 0x20}, /* common 8960 */ + /* DSIPHY_CTRL */ + .ctrl = {0x5f, 0x00, 0x00, 0x10}, /* common 8960 */ + /* DSIPHY_STRENGTH_CTRL */ + .strength = {0xff, 0x00, 0x06, 0x00}, /* common 8960 */ + /* DSIPHY_TIMING_CTRL */ + .timing = { 0x66, 0x2B, 0xD, /* panel specific */ + 0, /* DSIPHY_TIMING_CTRL_3 = 0 */ + 0x37, 0x3D, 0x12, 0x2F, 0x17, 0x03, 0x04}, /* panel specific */ + + /* DSIPHY_PLL_CTRL */ + .pll = { 0x00, /* common 8960 */ + /* VCO */ +#if defined(CONFIG_MACH_ESPRESSO10_ATT) + 0x0E, 0x30, 0xC0, /* panel specific */ +#else + 0x40, 0x01, 0x19, +#endif + 0x00, 0x50, 0x48, 0x63, + 0x77, 0x88, 0x99, /* Auto update by dsi-mipi driver */ + 0x00, 0x14, 0x03, 0x00, 0x02, /* common 8960 */ + 0x00, 0x20, 0x00, 0x01 }, /* common 8960 */ +}; + + +static int __init mipi_video_samsung_tft_wxga_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_samsung_tft_wxga")) + return 0; + + /* Landscape */ + pinfo.xres = 1280; + pinfo.yres = 800; + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; /* Primary Display */ + pinfo.wait_cycle = 0; + pinfo.bpp = 24; /* RGB888 = 24 bits-per-pixel */ + pinfo.fb_num = 2; /* using two frame buffers */ + + /* bitclk */ +#if defined(CONFIG_MACH_ESPRESSO10_ATT) + pinfo.clk_rate = 451200000; +#else + pinfo.clk_rate = 333350000; +#endif + /* + * this panel is operated by DE, + * vsycn and hsync are ignored + */ + +#if defined(CONFIG_MACH_ESPRESSO10_ATT) + pinfo.lcdc.h_front_porch = 120;/* thfp */ + pinfo.lcdc.h_back_porch = 120; /* thb */ + pinfo.lcdc.h_pulse_width = 2; /* thpw */ + + pinfo.lcdc.v_front_porch = 8; /* tvfp */ + pinfo.lcdc.v_back_porch = 7; /* tvb */ + pinfo.lcdc.v_pulse_width = 2; /* tvpw */ +#else + pinfo.lcdc.h_front_porch = 50;/* thfp */ + pinfo.lcdc.h_back_porch = 50; /* thb */ + pinfo.lcdc.h_pulse_width = 570; /* thpw */ + + pinfo.lcdc.v_front_porch = 8; /* tvfp */ + pinfo.lcdc.v_back_porch = 7; /* tvb */ + pinfo.lcdc.v_pulse_width = 30; /* tvpw */ +#endif + pinfo.lcdc.border_clr = 0; /* black */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + + pinfo.lcdc.hsync_skew = 0; + + /* Backlight levels - controled via PMIC pwm gpio */ + pinfo.bl_max = 255; + pinfo.bl_min = 1; + + /* mipi - general */ + pinfo.mipi.vc = 0; /* virtual channel */ + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.tx_eot_append = true; + pinfo.mipi.t_clk_post = 4; /* Calculated */ + pinfo.mipi.t_clk_pre = 16; /* Calculated */ + + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + + /* Four lanes are recomended for 1366x768 at 60 frames per second */ + pinfo.mipi.frame_rate = 60; /* 60 frames per second */ + pinfo.mipi.data_lane0 = true; + pinfo.mipi.data_lane1 = true; + pinfo.mipi.data_lane2 = true; + pinfo.mipi.data_lane3 = true; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + /* + * Note: The CMI panel input is RGB888, + * thus the DSI-to-LVDS bridge output is RGB888. + * This parameter selects the DSI-Core output to the bridge. + */ + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + + /* mipi - video mode */ + pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT; + pinfo.mipi.pulse_mode_hsa_he = false; /* sync mode */ + + pinfo.mipi.hfp_power_stop = false; + pinfo.mipi.hbp_power_stop = false; + pinfo.mipi.hsa_power_stop = false; + pinfo.mipi.eof_bllp_power_stop = false; + pinfo.mipi.bllp_power_stop = false; + + /* mipi - command mode */ + pinfo.mipi.te_sel = 0; + pinfo.mipi.interleave_max = 1; + /* The bridge supports only Generic Read/Write commands */ + pinfo.mipi.insert_dcs_cmd = false; + pinfo.mipi.wr_mem_continue = 0; + pinfo.mipi.wr_mem_start = 0; + pinfo.mipi.stream = false; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + /* + * toshiba d2l chip does not need max_pkt_szie dcs cmd + * client reply len is directly configure through + * RDPKTLN register (0x0404) + */ + pinfo.mipi.no_max_pkt_size = 1; + pinfo.mipi.force_clk_lane_hs = 1; + + + ret = mipi_tc358764_dsi2lvds_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_QHD_PT, &dsi2lvds_pd); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_samsung_tft_wxga_pt_init); diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c index 944dde04a50..d569636d8b2 100644 --- a/drivers/video/msm/msm_dss_io_8960.c +++ b/drivers/video/msm/msm_dss_io_8960.c @@ -633,6 +633,12 @@ void cont_splash_clk_ctrl(int enable) { static int cont_splash_clks_enabled; if (enable && !cont_splash_clks_enabled) { + if (clk_set_rate(dsi_byte_div_clk, 1) < 0) /* divided by 1 */ + pr_err("%s: dsi_byte_div_clk - " + "clk_set_rate failed\n", __func__); + if (clk_set_rate(dsi_esc_clk, 2) < 0) /* divided by 2 */ + pr_err("%s: dsi_esc_clk - " + "clk_set_rate failed\n", __func__); clk_prepare_enable(dsi_byte_div_clk); clk_prepare_enable(dsi_esc_clk); cont_splash_clks_enabled = 1; @@ -648,6 +654,12 @@ void mipi_dsi_prepare_clocks(void) clk_prepare(amp_pclk); clk_prepare(dsi_m_pclk); clk_prepare(dsi_s_pclk); + if (clk_set_rate(dsi_byte_div_clk, 1) < 0) /* divided by 1 */ + pr_err("%s: dsi_byte_div_clk - " + "clk_set_rate failed\n", __func__); + if (clk_set_rate(dsi_esc_clk, 2) < 0) /* divided by esc */ + pr_err("%s: dsi_esc_clk - " /* clk ratio */ + "clk_set_rate failed\n", __func__); clk_prepare(dsi_byte_div_clk); clk_prepare(dsi_esc_clk); } diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index e07c43b2eba..a3ec88263f4 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -90,7 +90,7 @@ u32 msm_fb_debug_enabled; u32 msm_fb_msg_level = 7; /* Setting mddi_msg_level to 8 prints out ALL messages */ -u32 mddi_msg_level = 5; +u32 mddi_msg_level = 7; extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK]; extern unsigned long mdp_timer_duration; @@ -1404,6 +1404,10 @@ static int msm_fb_register(struct msm_fb_data_type *mfd) var->xres = panel_info->xres; var->yres = panel_info->yres; var->xres_virtual = panel_info->xres; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + var->height = panel_info->height;/* height of picture in mm */ + var->width = panel_info->width;/* width of picture in mm */ +#endif var->yres_virtual = panel_info->yres * mfd->fb_page + ((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page; var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */ diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h index 4b6f41f76c0..91537644d07 100644 --- a/drivers/video/msm/msm_fb.h +++ b/drivers/video/msm/msm_fb.h @@ -194,6 +194,8 @@ struct msm_fb_data_type { u32 mdp_rev; u32 writeback_state; bool writeback_active_cnt; + boolean resume_state; + boolean backlight_ctrl_ongoing; int cont_splash_done; void *cpu_pm_hdl; u32 acq_fen_cnt; diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h index c6e5d6341b4..47a3482d00b 100644 --- a/drivers/video/msm/msm_fb_panel.h +++ b/drivers/video/msm/msm_fb_panel.h @@ -153,6 +153,10 @@ struct lvds_panel_info { struct msm_panel_info { __u32 xres; __u32 yres; +#if defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_HD_PT) + __u32 height; + __u32 width; +#endif __u32 bpp; __u32 mode2_xres; __u32 mode2_yres; diff --git a/drivers/video/msm/samsung_cmc624.c b/drivers/video/msm/samsung_cmc624.c new file mode 100644 index 00000000000..0d88094e0cf --- /dev/null +++ b/drivers/video/msm/samsung_cmc624.c @@ -0,0 +1,1790 @@ +/* + * Copyright (C) 2011, Samsung Electronics. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. +*/ +#ifndef DEBUG +#define DEBUG /* uncomment if you want debugging output */ +#endif +#include +#include +#include "msm_fb.h" +#include +#include +#include +#include "samsung_cmc624.h" + +#define PM8921_GPIO_BASE NR_GPIO_IRQS +#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE) + +/* + * V_IMA_1.8V VREG_L3A + * DISPLAY_3.3V VREG_L8A + * V_IMA_1.2V GPIO LCD_PWR_EN + * LCD_VOUT GPIO LCD_PWR_EN +*/ +/* +static struct regulator *v_ima_1_8v; +static struct regulator *display_3_3v; +*/ + +#define LCD_PWR_EN 70 + +struct cmc624_data { + struct i2c_client *client; +}; + +static struct cmc624_data *p_cmc624_data; +static struct i2c_client *g_client; +#define I2C_M_WR 0 /* for i2c */ +#define I2c_M_RD 1 /* for i2c */ +unsigned long last_cmc624_Bank = 0xffff; +unsigned long last_cmc624_Algorithm = 0xffff; +static struct cmc624RegisterSet cmc624_TuneSeq[CMC624_MAX_SETTINGS]; +static int cmc624_TuneSeqLen; +#define CMC624_BRIGHTNESS_MAX_LEVEL 1600 + + +struct cmc624_state_type cmc624_state = { + .cabc_mode = CABC_OFF_MODE, + .brightness = 42, + .suspended = 0, + .scenario = mDNIe_UI_MODE, + .browser_scenario = COLOR_TONE_1, + .background = STANDARD_MODE, + .temperature = TEMP_STANDARD, + .outdoor = OUTDOOR_OFF_MODE, + .sub_tune = NULL, + .main_tune = NULL, + .negative = NEGATIVE_OFF_MODE, +}; + +u16 gIDs[3] = { 0, }; +boolean video_mode; + +static DEFINE_MUTEX(tuning_mutex); +/* +* functions for I2C transactions +*/ +unsigned char cmc624_Power_LUT[NUM_POWER_LUT][NUM_ITEM_POWER_LUT] = { + {0x42, 0x47, 0x3E, 0x52, 0x42, 0x3F, 0x3A, 0x37, 0x3F}, + {0x38, 0x3d, 0x34, 0x48, 0x38, 0x35, 0x30, 0x2d, 0x35}, +}; + +static int is_cmc624_on; +/* ############################################################### + * # + * # TUNE VALUE + * # + * ############################################################### */ +unsigned char cmc624_default_plut[NUM_ITEM_POWER_LUT] = { + 0x42, 0x47, 0x3E, 0x52, 0x42, 0x3F, 0x3A, 0x37, 0x3F +}; + +unsigned char cmc624_video_plut[NUM_ITEM_POWER_LUT] = { + 0x38, 0x3d, 0x34, 0x48, 0x38, 0x35, 0x30, 0x2d, 0x35 +}; + +const struct str_sub_tuning sub_tune_value[MAX_TEMP_MODE][MAX_OUTDOOR_MODE] = { + { + { + .value[CABC_OFF_MODE] = {.name = + "STANDARD, OUTDOOR:OFF, CABC:OFF", .value = + NULL, .size = 0}, + .value[CABC_ON_MODE] = {.name = + "STANDARD, OUTDOOR:OFF, CABC:ON", .value = + NULL, .size = 0} + }, + { + .value[CABC_OFF_MODE] = {.name = + "STANDARD, OUTDOOR:ON, CABC:OFF", .value = + ove_cabcoff, .size = ARRAY_SIZE(ove_cabcoff)}, + .value[CABC_ON_MODE] = {.name = + "STANDARD, OUTDOOR:ON, CABC:ON", .value = + ove_cabcoff, .size = ARRAY_SIZE(ove_cabcoff)} + } + }, + { + { + .value[CABC_OFF_MODE] = {.name = + "WARM, OUTDOOR:OFF, CABC:OFF", .value = + warm_cabcoff, .size = + ARRAY_SIZE(warm_cabcoff)}, + .value[CABC_ON_MODE] = {.name = + "WARM, OUTDOOR:OFF, CABC:ON", + .value = warm_cabcoff, + .size = ARRAY_SIZE(warm_cabcoff)} + }, + { + .value[CABC_OFF_MODE] = {.name = + "WARM, OUTDOOR:ON, CABC:OFF", + .value = warm_ove_cabcoff, .size = + ARRAY_SIZE(warm_ove_cabcoff)}, + .value[CABC_ON_MODE] = {.name = + "WARM, OUTDOOR:ON, CABC:ON", + .value = warm_ove_cabcoff, .size = + ARRAY_SIZE(warm_ove_cabcoff)} + } + }, + { + { + .value[CABC_OFF_MODE] = {.name = + "COLD, OUTDOOR:OFF, CABC:OFF", .value = + cold_cabcoff, .size = + ARRAY_SIZE(cold_cabcoff)}, + .value[CABC_ON_MODE] = {.name = + "COLD, OUTDOOR:OFF, CABC:ON", .value = + cold_cabcoff, .size = ARRAY_SIZE(cold_cabcoff)} + }, + { + .value[CABC_OFF_MODE] = {.name = + "COLD, OUTDOOR:ON, CABC:OFF", .value = + cold_ove_cabcoff, .size = + ARRAY_SIZE(cold_ove_cabcoff)}, + .value[CABC_ON_MODE] = {.name = + "COLD, OUTDOOR:ON, CABC:ON", .value = + cold_ove_cabcoff, .size = + ARRAY_SIZE(cold_ove_cabcoff)} + } + }, +}; + +const struct str_main_tuning tune_value[MAX_BACKGROUND_MODE][MAX_mDNIe_MODE] = { + {{.value[CABC_OFF_MODE] = { + .name = "DYN_UI_OFF", .flag = 0, .tune = + dynamic_ui_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(dynamic_ui_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "DYN_UI_ON", .flag = 0, .tune = + dynamic_ui_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(dynamic_ui_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "DYN_VIDEO_OFF", .flag = 0, .tune = + dynamic_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(dynamic_video_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "DYN_VIDEO_ON", + .flag = 0, .tune = + dynamic_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(dynamic_video_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "DYN_VIDEO_W_OFF", .flag = 0, .tune = + dynamic_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(dynamic_video_cabcoff)}, + .value[CABC_ON_MODE] = { + .name = "DYN_VIDEO_W_ON", .flag = 0, .tune = + dynamic_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(dynamic_video_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "DYN_VIDEO_C_OFF", .flag = 0, .tune = + dynamic_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(dynamic_video_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "DYN_VIDEO_C_ON", + .flag = 0, .tune = + dynamic_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(dynamic_video_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "DYN_CAMERA_OFF", .flag = + TUNE_FLAG_CABC_ALWAYS_OFF, .tune = + camera_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(camera_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "DYN_CAMERA_ON", + .flag = TUNE_FLAG_CABC_ALWAYS_OFF, .tune = + camera_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(camera_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "DYN_NAVI_OFF", .flag = 0, .tune = + NULL, .plut = NULL, .size = 0}, + .value[CABC_ON_MODE] = {.name = "DYN_NAVI_ON", + .flag = 0, .tune = + NULL, .plut = NULL, .size = 0} }, + {.value[CABC_OFF_MODE] = { + .name = "DYN_GALLERY_OFF", .flag = 0, .tune = + dynamic_gallery_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(dynamic_gallery_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "DYN_GALLERY_ON", + .flag = 0, .tune = + dynamic_gallery_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(dynamic_gallery_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "DYN_DMB_OFF", .flag = 0, .tune = + dynamic_dmb_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(dynamic_dmb_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "DYN_DMB_ON", + .flag = 0, .tune = + dynamic_dmb_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(dynamic_dmb_cabcoff)} } }, + {{.value[CABC_OFF_MODE] = { + .name = "STD_UI_OFF", .flag = 0, .tune = + standard_ui_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(standard_ui_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "STD_UI_ON", + .flag = 0, .tune = + standard_ui_cabcon, .plut = NULL, .size = + ARRAY_SIZE(standard_ui_cabcon)} }, + {.value[CABC_OFF_MODE] = { + .name = "STD_VIDEO_OFF", .flag = 0, .tune = + standard_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_video_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "STD_VIDEO_ON", + .flag = 0, .tune = + standard_video_cabcon, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_video_cabcon)} }, + {.value[CABC_OFF_MODE] = { + .name = "STD_VIDEO_W_OFF", .flag = 0, .tune = + standard_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_video_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "STD_VIDEO_W_ON", + .flag = 0, .tune = + standard_video_cabcon, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_video_cabcon)} }, + {.value[CABC_OFF_MODE] = { + .name = "STD_VIDEO_C_OFF", .flag = 0, .tune = + standard_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_video_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "STD_VIDEO_C_ON", + .flag = 0, .tune = + standard_video_cabcon, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_video_cabcon)} }, + {.value[CABC_OFF_MODE] = { + .name = "STD_CAMERA_OFF", .flag = + TUNE_FLAG_CABC_ALWAYS_OFF, .tune = + camera_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(camera_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "STD_CAMERA_ON", .flag = + TUNE_FLAG_CABC_ALWAYS_OFF, .tune = + camera_cabcon, .plut = NULL, .size = + ARRAY_SIZE(camera_cabcon)} }, + {.value[CABC_OFF_MODE] = { + .name = "STD_NAVI_OFF", .flag = 0, .tune = + NULL, .plut = NULL, .size = 0}, + .value[CABC_ON_MODE] = {.name = "STD_NAVI_ON", + .flag = 0, .tune = + NULL, .plut = NULL, .size = 0} }, + {.value[CABC_OFF_MODE] = { + .name = "STD_GALLERY_OFF", .flag = 0, .tune = + standard_gallery_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(standard_gallery_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "STD_GALLERY_ON", + .flag = 0, .tune = + standard_gallery_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(standard_gallery_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "STD_DMB_OFF", .flag = 0, .tune = + standard_dmb_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_dmb_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "STD_DMB_ON", .flag = 0, .tune = + standard_dmb_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_dmb_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "STD_VTCALL_OFF", .flag = 0, .tune = + standard_vtcall_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_vtcall_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "STD_VTCALL_ON", .flag = 0, + .tune = standard_vtcall_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(standard_vtcall_cabcoff)} } }, + {{.value[CABC_OFF_MODE] = { + .name = "NAT_UI_OFF", .flag = 0, .tune = + natural_ui_cabcoff, .plut = + NULL , .size = ARRAY_SIZE(natural_ui_cabcoff) }, + .value[CABC_ON_MODE] = { + .name = "NAT_UI_ON", .flag = 0, .tune = + natural_ui_cabcoff, .plut = + NULL, .size = + ARRAY_SIZE(natural_ui_cabcoff) } }, + {.value[CABC_OFF_MODE] = { + .name = "NAT_VIDEO_OFF", .flag = 0, .tune = + natural_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(natural_video_cabcoff) }, + .value[CABC_ON_MODE] = { + .name = "NAT_VIDEO_ON", .flag = 0, .tune = + natural_video_cabcoff, .plut = + cmc624_video_plut , .size = + ARRAY_SIZE(natural_video_cabcoff) } }, + {.value[CABC_OFF_MODE] = { + .name = "NAT_VIDEO_W_OFF", .flag = 0, .tune = + natural_video_cabcoff, .plut = + cmc624_video_plut , .size = + ARRAY_SIZE(natural_video_cabcoff) }, + .value[CABC_ON_MODE] = { + .name = "NAT_VIDEO_W_ON", .flag = 0, .tune = + natural_video_cabcoff, .plut = + cmc624_video_plut , .size = + ARRAY_SIZE(natural_video_cabcoff) } }, + {.value[CABC_OFF_MODE] = { + .name = "NAT_VIDEO_C_OFF", .flag = 0, .tune = + natural_video_cabcoff, .plut = + cmc624_video_plut , .size = + ARRAY_SIZE(natural_video_cabcoff) }, + .value[CABC_ON_MODE] = { + .name = "NAT_VIDEO_C_ON", .flag = 0, .tune = + natural_video_cabcoff, .plut = + cmc624_video_plut , .size = + ARRAY_SIZE(natural_video_cabcoff) } }, + {.value[CABC_OFF_MODE] = { + .name = "NAT_CAMERA_OFF", .flag = + TUNE_FLAG_CABC_ALWAYS_OFF, .tune = + camera_cabcoff, .plut = NULL , .size = + ARRAY_SIZE(camera_cabcoff)}, + .value[CABC_ON_MODE] = { + .name = "NAT_CAMERA_ON", .flag = + TUNE_FLAG_CABC_ALWAYS_OFF, .tune = + camera_cabcoff, .plut = NULL , .size = + ARRAY_SIZE(camera_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "NAT_NAVI_OFF", .flag = 0, .tune = + NULL, .plut = NULL , .size = + 0}, + .value[CABC_ON_MODE] = { + .name = "NAT_NAVI_ON", .flag = 0, .tune = + NULL, .plut = NULL , .size = + 0} }, + {.value[CABC_OFF_MODE] = { + .name = "NAT_GALLERY_OFF", .flag = 0, .tune = + natural_gallery_cabcoff, .plut = NULL , .size = + ARRAY_SIZE(natural_gallery_cabcoff) }, + .value[CABC_ON_MODE] = { + .name = "NAT_GALLERY_ON", .flag = 0, .tune = + natural_gallery_cabcoff, .plut = NULL , .size = + ARRAY_SIZE(natural_gallery_cabcoff) } }, + {.value[CABC_OFF_MODE] = { + .name = "NAT_DMB_OFF", .flag = 0, .tune = + natural_dmb_cabcoff, .plut = cmc624_video_plut , + .size = ARRAY_SIZE(natural_dmb_cabcoff) }, + .value[CABC_ON_MODE] = { + .name = "NAT_DMB_ON", .flag = 0, .tune = + natural_dmb_cabcoff, .plut = cmc624_video_plut , + .size = ARRAY_SIZE(natural_dmb_cabcoff) } } }, + {{.value[CABC_OFF_MODE] = { + .name = "MOV_UI_OFF", .flag = 0, .tune = + movie_ui_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(movie_ui_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "MOV_UI_ON", .flag = 0, .tune = + movie_ui_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(movie_ui_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "MOV_VIDEO_OFF", .flag = 0, .tune = + movie_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(movie_video_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "MOV_VIDEO_ON", + .flag = 0, .tune = + movie_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(movie_video_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "MOV_VIDEO_W_OFF", .flag = 0, .tune = + movie_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(movie_video_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "MOV_VIDEO_W_ON", + .flag = 0, .tune = + movie_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(movie_video_cabcoff)} }, + {.value[CABC_OFF_MODE] = { + .name = "MOV_VIDEO_C_OFF", .flag = 0, .tune = + movie_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(movie_video_cabcoff) }, + .value[CABC_ON_MODE] = {.name = "MOV_VIDEO_C_ON", + .flag = 0, .tune = + movie_video_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(movie_video_cabcoff) } }, + {.value[CABC_OFF_MODE] = { + .name = "MOV_CAMERA_OFF", .flag = + TUNE_FLAG_CABC_ALWAYS_OFF, .tune = + camera_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(camera_cabcoff)}, + .value[CABC_ON_MODE] = {.name = "MOV_CAMERA_ON", .flag = + TUNE_FLAG_CABC_ALWAYS_OFF, .tune = + camera_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(camera_cabcoff) } }, + {.value[CABC_OFF_MODE] = { + .name = "MOV_NAVI_OFF", .flag = 0, .tune = + NULL, .plut = NULL, .size = 0}, + .value[CABC_ON_MODE] = {.name = "MOV_NAVI_ON", + .flag = 0, .tune = + NULL, .plut = NULL, .size = 0} }, + {.value[CABC_OFF_MODE] = { + .name = "MOV_GALLERY_OFF", .flag = 0, .tune = + movie_gallery_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(movie_gallery_cabcoff) }, + .value[CABC_ON_MODE] = { + .name = "MOV_GALLERY_ON", .flag = 0, .tune = + movie_gallery_cabcoff, .plut = NULL, .size = + ARRAY_SIZE(movie_gallery_cabcoff) } }, + {.value[CABC_OFF_MODE] = { + .name = "MOV_DMB_OFF", .flag = 0, .tune = + movie_dmb_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(movie_dmb_cabcoff) }, + .value[CABC_ON_MODE] = { + .name = "MOV_DMB_ON", .flag = 0, .tune = + movie_dmb_cabcoff, .plut = + cmc624_video_plut, .size = + ARRAY_SIZE(movie_dmb_cabcoff) } } } +}; +const struct str_sub_tuning browser_tune_value[COLOR_TONE_MAX] = { +/* browser tone*/ + { + .value[CABC_OFF_MODE] = {.name = + "BROWSER_TONE1,CABC:OFF", + .value = browser_tone1_tune, .size = + ARRAY_SIZE(browser_tone1_tune)}, + .value[CABC_ON_MODE] = {.name = + "BROWSER_TONE1,CABC:ON", + .value = browser_tone1_tune, .size = + ARRAY_SIZE(browser_tone1_tune)} + }, + { + .value[CABC_OFF_MODE] = {.name = + "BROWSER_TONE2,CABC:OFF", + .value = browser_tone2_tune, .size = + ARRAY_SIZE(browser_tone2_tune)}, + .value[CABC_ON_MODE] = {.name = + "BROWSER_TONE2,CABC:ON", + .value = browser_tone2_tune, .size = + ARRAY_SIZE(browser_tone2_tune)} + }, + { + .value[CABC_OFF_MODE] = {.name = + "BROWSER_TONE3,CABC:OFF", + .value = browser_tone3_tune, .size = + ARRAY_SIZE(browser_tone3_tune)}, + .value[CABC_ON_MODE] = {.name = + "BROWSER_TONE3,CABC:ON", + .value = browser_tone3_tune, .size = + ARRAY_SIZE(browser_tone3_tune)} + }, +}; +const struct str_sub_tuning negative_tune_value = { + .value[CABC_OFF_MODE] = {.name = + "NEGATIVE_TONE : CABC:OFF", + .value = cmc624_tune_tone_reversal, .size = + ARRAY_SIZE(cmc624_tune_tone_reversal)}, + .value[CABC_ON_MODE] = {.name = + "NEGATIVE_TONE : CABC:ON", + .value = cmc624_tune_tone_reversal, .size = + ARRAY_SIZE(cmc624_tune_tone_reversal)} +}; +/* end of TUNE VALUE + * ########################################################## */ + +bool cmc624_I2cWrite16(unsigned char Addr, unsigned long Data) +{ + int err = -1000; + struct i2c_msg msg[1]; + unsigned char data[3]; + + if (!p_cmc624_data) { + pr_info("p_cmc624_data is NULL\n"); + return -ENODEV; + } + + if (!is_cmc624_on) { + pr_info("cmc624 power down..\n"); + return -ENODEV; + } + g_client = p_cmc624_data->client; + + if ((g_client == NULL)) { + pr_info("cmc624_I2cWrite16 g_client is NULL\n"); + return -ENODEV; + } + + if (!g_client->adapter) { + pr_info("cmc624_I2cWrite16 g_client->adapter is NULL\n"); + return -ENODEV; + } +#if defined(CONFIG_TARGET_LOCALE_KOR_SKT)\ + || defined(CONFIG_TARGET_LOCALE_KOR_LGU) + if (Addr == 0x0000) { + if (Data == last_cmc624_Bank) + return 0; + last_cmc624_Bank = Data; + } else if (Addr == 0x0001 && last_cmc624_Bank == 0) { + last_cmc624_Algorithm = Data; + } +#endif + + data[0] = Addr; + data[1] = ((Data >> 8) & 0xFF); + data[2] = (Data) & 0xFF; + msg->addr = g_client->addr; + msg->flags = I2C_M_WR; + msg->len = 3; + msg->buf = data; + + err = i2c_transfer(g_client->adapter, msg, 1); + + if (err >= 0) { + /*pr_info("%s %d i2c transfer OK\n", __func__, __LINE__); */ + return 0; + } + + pr_info("%s i2c transfer error:%d(a:%d)\n", __func__, err, Addr); + return err; +} + +int cmc624_I2cRead16(u8 reg, u16 *val) +{ + int err; + struct i2c_msg msg[2]; + u8 regaddr = reg; + u8 data[2]; + + if (!p_cmc624_data) { + pr_err("%s p_cmc624_data is NULL\n", __func__); + return -ENODEV; + } + g_client = p_cmc624_data->client; + + if ((g_client == NULL)) { + pr_err("%s g_client is NULL\n", __func__); + return -ENODEV; + } + + if (!g_client->adapter) { + pr_err("%s g_client->adapter is NULL\n", __func__); + return -ENODEV; + } + + if (regaddr == 0x0001) { + *val = last_cmc624_Algorithm; + return 0; + } + + msg[0].addr = g_client->addr; + msg[0].flags = I2C_M_WR; + msg[0].len = 1; + msg[0].buf = ®addr; + msg[1].addr = g_client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = &data[0]; + err = i2c_transfer(g_client->adapter, &msg[0], 2); + + if (err >= 0) { + *val = (data[0] << 8) | data[1]; + return 0; + } + /* add by inter.park */ + pr_err("%s %d i2c transfer error: %d\n", __func__, __LINE__, err); + + return err; +} + +/*##################################################### + * CMC624 Backlight Control function + ##################################################### +*/ + +/* value: 0 ~ 1600*/ + +int Islcdonoff(void) +{ + /*return 0;*/ + return cmc624_state.suspended; /* tmps solution*/ +} + +/*value: 0 ~ 100*/ +static void cmc624_manual_pwm_brightness(int value) +{ + pr_debug("[CMC624:INFO]: %s value : %d\n", __func__, value); + return; +} + +/* value: 0 ~ 1600*/ +void cmc624_pwm_brightness(int value) +{ + pr_debug("[CMC624:Info] : %s : value : %d\n", __func__, value); + return; +} + +void cmc624_pwm_brightness_bypass(int value) +{ + int data; + pr_debug("%s : BL brightness level = %d\n", __func__, value); + + if (value < 0) + data = 0; + else if (value > 1600) + data = 1600; + else + data = value; + + if (data < 16) + data = 1; + /* Range of data 0~1600, min value 0~15 is same as 0 */ + else + data = data >> 4; + + cmc624_state.brightness = data; + cmc624_manual_pwm_brightness(data); +} + +#define VALUE_FOR_1600 16 +void set_backlight_pwm(int level) +{ + + mutex_lock(&tuning_mutex); + if (!Islcdonoff()) { + if (cmc624_state.main_tune == NULL) { + /* + * struct cmc624_state_type cmc624_state = { + * .cabc_mode = CABC_ON_MODE, + * .brightness = 42, + * .suspended = 0, + * .scenario = mDNIe_UI_MODE, + * .background = STANDARD_MODE, + * .temperature = TEMP_STANDARD, + * .outdoor = OUTDOOR_OFF_MODE, + * .sub_tune = NULL, + * .main_tune = NULL, + *}; + */ + pr_info + ("===================================\n"); + pr_info + ("[CMC624] cmc624_state.main_tune is NULL?...\n"); + pr_info("[CMC624] DUMP :\n"); + pr_info("[CMC624] cabc_mode : %d\n", + cmc624_state.cabc_mode); + pr_info("[CMC624] brightness : %d\n", + cmc624_state.brightness); + pr_info("[CMC624] suspended : %d\n", + cmc624_state.suspended); + pr_info("[CMC624] scenario : %d\n", + cmc624_state.scenario); + pr_info("[CMC624] background : %d\n", + cmc624_state.background); + pr_info("[CMC624] temperature : %d\n", + cmc624_state.temperature); + pr_info("[CMC624] outdoor : %d\n", + cmc624_state.outdoor); + pr_info + ("===================================\n"); + mutex_unlock(&tuning_mutex); + return; + } + if (cmc624_state.cabc_mode == CABC_OFF_MODE || + (cmc624_state.main_tune->flag & TUNE_FLAG_CABC_ALWAYS_OFF)) + cmc624_manual_pwm_brightness(level); + else + cmc624_pwm_brightness(level * VALUE_FOR_1600); + } + mutex_unlock(&tuning_mutex); +} + +/*##################################################### + * CMC624 common function + * + * void bypass_onoff_ctrl(int value); + * void cabc_onoff_ctrl(int value); + * int set_mdnie_scenario_mode(unsigned int mode); + * int load_tuning_data(char *filename); + * int apply_main_tune_value(enum eLcd_mDNIe_UI ui, + * enum eBackground_Mode bg, enum eCabc_Mode cabc, int force); + * int apply_sub_tune_value(enum eCurrent_Temp temp, + * enum eOutdoor_Mode ove, enum eCabc_Mode cabc, int force); + ##################################################### +*/ + +void bypass_onoff_ctrl(int value) +{ + pr_debug("[CMC624:Info] : %s : value : %d\n", __func__, value); + return; +} + +void cabc_onoff_ctrl(int value) +{ + + if (apply_main_tune_value + (cmc624_state.scenario, cmc624_state.background, value, 0) != 0) { + pr_debug("[CMC624:ERROR]:%s: apply main tune value faile\n", + __func__); + return; + } +} + +static int cmc624_set_tune_value(const struct cmc624RegisterSet *value, + int array_size) +{ + int ret = 0; + unsigned int num; + unsigned int i = 0; + + mutex_lock(&tuning_mutex); + + num = array_size; + + for (i = 0; i < num; i++) { + ret = cmc624_I2cWrite16(value[i].RegAddr, value[i].Data); + if (ret != 0) { + pr_debug + ("[CMC624:ERROR]:cmc624_I2cWrite16 failed : %d\n", + ret); + goto set_error; + } + } + + set_error: + mutex_unlock(&tuning_mutex); + return ret; +} + +static struct cmc624RegisterSet cmc624_TuneSeq[CMC624_MAX_SETTINGS]; +static int parse_text(char *src, int len) +{ + int i, count, ret; + int index = 0; + char *str_line[CMC624_MAX_SETTINGS]; + char *sstart; + char *c; + unsigned int data1, data2; + + c = src; + count = 0; + sstart = c; + + for (i = 0; i < len; i++, c++) { + char a = *c; + if (a == '\r' || a == '\n') { + if (c > sstart) { + str_line[count] = sstart; + count++; + } + *c = '\0'; + sstart = c + 1; + } + } + + if (c > sstart) { + str_line[count] = sstart; + count++; + } + + for (i = 0; i < count; i++) { + ret = sscanf(str_line[i], "0x%x,0x%x\n", &data1, &data2); + pr_debug("Result => [0x%2x 0x%4x] %s\n", data1, data2, + (ret == 2) ? "Ok" : "Not available"); + if (ret == 2) { + cmc624_TuneSeq[index].RegAddr = (unsigned char)data1; + cmc624_TuneSeq[index++].Data = (unsigned long)data2; + } + } + return index; +} + +bool cmc624_tune(unsigned long num) +{ + unsigned int i; + + pr_debug("[CMC624:INFO] Start tuning CMC624\n"); + + for (i = 0; i < num; i++) { + pr_debug("[CMC624:Tuning][%2d] : reg : 0x%2x, data: 0x%4x\n", + i + 1, cmc624_TuneSeq[i].RegAddr, + cmc624_TuneSeq[i].Data); + + if (cmc624_I2cWrite16 + (cmc624_TuneSeq[i].RegAddr, cmc624_TuneSeq[i].Data) != 0) { + pr_err("[CMC624:ERROR] : I2CWrite failed\n"); + return 0; + } + pr_debug("[CMC624:Tunig] : Write Done\n"); + + if (cmc624_TuneSeq[i].RegAddr == CMC624_REG_SWRESET + && cmc624_TuneSeq[i].Data == 0xffff) { + mdelay(3); + } + } + pr_debug("[CMC624:INFO] End tuning CMC624\n"); + return 1; +} + +int load_tuning_data(char *filename) +{ + struct file *filp; + char *dp; + long l; + loff_t pos; + int ret; + mm_segment_t fs; + + pr_debug("[CMC624:INFO]:%s called loading file name : %s\n", __func__, + filename); + cmc624_TuneSeqLen = 0; + + fs = get_fs(); + set_fs(get_ds()); + + filp = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(filp)) { + pr_debug("[CMC624:ERROR]:File open failed\n"); + return -1; + } + + l = filp->f_path.dentry->d_inode->i_size; + pr_debug("[CMC624:INFO]: Loading File Size : %ld(bytes)", l); + + dp = kmalloc(l + 10, GFP_KERNEL); + if (dp == NULL) { + pr_debug( + "[CMC624:ERROR]:Can't not alloc memory for tuning file load\n"); + filp_close(filp, current->files); + return -1; + } + pos = 0; + memset(dp, 0, l); + pr_debug("[CMC624:INFO] : before vfs_read()\n"); + ret = vfs_read(filp, (char __user *)dp, l, &pos); + pr_debug("[CMC624:INFO] : after vfs_read()\n"); + + if (ret != l) { + pr_debug("[CMC624:ERROR] : vfs_read() filed ret : %d\n", ret); + kfree(dp); + filp_close(filp, current->files); + return -1; + } + + filp_close(filp, current->files); + + set_fs(fs); + cmc624_TuneSeqLen = parse_text(dp, l); + + if (!cmc624_TuneSeqLen) { + pr_debug("[CMC624:ERROR]:Nothing to parse\n"); + kfree(dp); + return -1; + } + + pr_debug("[CMC624:INFO] : Loading Tuning Value's Count : %d", + cmc624_TuneSeqLen); + cmc624_tune(cmc624_TuneSeqLen); + + kfree(dp); + return cmc624_TuneSeqLen; +} +#define SUB_TUNE 0 +#define MAIN_TUNE 1 +#define BROW_TUNE 2 +int init_tune_flag[3] = {0,}; + +int apply_sub_tune_value(enum eCurrent_Temp temp, enum eOutdoor_Mode outdoor, + enum eCabc_Mode cabc, int force) +{ + int register_size; + if (cmc624_state.negative == 1) { + cmc624_state.temperature = temp; + cmc624_state.outdoor = outdoor; + return 0; + } + +/* + if(tuning_enable){ + pr_debug("[CMC624:INFO]:%s:Tuning mode Enabled\n", __func__); + return 0; + } +*/ + + if (force == 0) { + if ((cmc624_state.temperature == temp) + && (cmc624_state.outdoor == outdoor)) { + pr_debug( + "[CMC624:INFO]:%s:already setted temp : %d, over : %d\n" + , __func__, temp, outdoor); + return 1; + } + } + pr_debug("=================================================\n"); + pr_debug(" CMC624 Mode Change.sub tune\n"); + pr_debug("==================================================\n"); + pr_debug("[CMC624:INFO]:%s:curr sub tune : %s\n", __func__, + sub_tune_value[cmc624_state.temperature][cmc624_state.outdoor]. + value[cmc624_state.cabc_mode].name); + pr_debug("[CMC624:INFO]:%s: sub tune : %s\n", __func__, + sub_tune_value[temp][outdoor].value[cabc].name); + + if ((outdoor == OUTDOOR_OFF_MODE) || (temp == TEMP_STANDARD)) { + pr_debug("[CMC624:INFO]:%s:set default main tune\n", __func__); + register_size = + tune_value[cmc624_state.background] + [cmc624_state.scenario]. + value[cmc624_state.cabc_mode].size; + if (cmc624_set_tune_value(tune_value[cmc624_state.background] + [cmc624_state.scenario]. + value[cmc624_state.cabc_mode].tune, + register_size) != 0) { + pr_debug("[CMC624:ERROR]:%s: set tune value falied\n",\ + __func__); + return -1; + } + + if ((outdoor != OUTDOOR_OFF_MODE) || (temp != TEMP_STANDARD)) + goto set_sub_tune; + } else { +set_sub_tune: + register_size = sub_tune_value[temp][outdoor].value[cabc].size; + if (cmc624_set_tune_value + (sub_tune_value[temp][outdoor].value[cabc].value, + register_size)) { + pr_debug("[CMC624:ERROR]:%s: set tune value falied\n",\ + __func__); + return -1; + } + } + cmc624_state.temperature = temp; + cmc624_state.outdoor = outdoor; + return 0; +} + +void cmc_timing_generator_reset(void) +{ + mutex_lock(&tuning_mutex); + /* Switch off cmc timing generator */ + cmc624_I2cWrite16(0x00, 0x0003); + cmc624_I2cWrite16(0x80, 0x0000); + cmc624_I2cWrite16(0x00, 0x0002); + cmc624_I2cWrite16(0x52, 0x0000); + + /* Switch on cmc timing generator */ + cmc624_I2cWrite16(0x00, 0x0003); + cmc624_I2cWrite16(0x80, 0x0001); + cmc624_I2cWrite16(0x00, 0x0002); + cmc624_I2cWrite16(0x52, 0x0001); + mutex_unlock(&tuning_mutex); +} + +int apply_main_tune_value(enum eLcd_mDNIe_UI ui, enum eBackground_Mode bg, + enum eCabc_Mode cabc, int force) +{ + enum eCurrent_Temp temp = 0; + if (cmc624_state.negative == 1) { + cmc624_state.scenario = ui; + cmc624_state.background = bg; + cmc624_state.cabc_mode = cabc; + return 0; + } + pr_debug("==================================================\n"); + pr_debug(" CMC624 Mode Change. Main tune\n"); + pr_debug("==================================================\n"); + + if (force == 0) { + if ((cmc624_state.scenario == ui) + && (cmc624_state.background == bg) + && (cmc624_state.cabc_mode == cabc)) { + pr_debug( + "[CMC624:INFO]:%s:already setted ui : %d, bg : %d\n", + __func__, ui, bg); + return 0; + } + } + if (cmc624_state.scenario == mDNIe_BROWSER_ON_MODE) + ui = mDNIe_UI_MODE; + pr_debug("[CMC624:INFO]:%s:curr main tune : %s\n", __func__, + tune_value[cmc624_state.background][cmc624_state.scenario]. + value[cmc624_state.cabc_mode].name); + pr_debug("[CMC624:INFO]:%s: main tune : %s\n", __func__, + tune_value[bg][ui].value[cabc].name); + +if (ui == mDNIe_VIDEO_MODE || + ui == mDNIe_VIDEO_WARM_MODE || + ui == mDNIe_VIDEO_COLD_MODE) + video_mode = true; +else + video_mode = false; + + if ((ui == mDNIe_VIDEO_MODE) || (ui == mDNIe_DMB_MODE)) { + if (apply_sub_tune_value\ + (temp, cmc624_state.outdoor, cabc, 0) != 1) + goto rest_set; + } + + pr_debug("[CMC624:INFO]:%s set, size : %d\n",\ + tune_value[bg][ui].value[cabc].name,\ + tune_value[bg][ui].value[cabc].size); + + if (cmc624_set_tune_value + (tune_value[bg][ui].value[cabc].tune, + tune_value[bg][ui].value[cabc].size) != 0) { + pr_err("[CMC624:ERROR]:%s: set tune value falied\n", __func__); + return -1; + } + if ((ui == mDNIe_VIDEO_WARM_MODE) || (ui == mDNIe_VIDEO_COLD_MODE)) { + if (ui == mDNIe_VIDEO_WARM_MODE) + temp = TEMP_WARM; + else if (ui == mDNIe_VIDEO_COLD_MODE) + temp = TEMP_COLD; + if (apply_sub_tune_value(temp, cmc624_state.outdoor, cabc, 0) + != 0) { + pr_debug( + "[CMC624:ERROR]:%s:apply_sub_tune_value() faield\n", + __func__); + } + } + +rest_set: + + cmc624_state.scenario = ui; + cmc624_state.background = bg; + cmc624_state.cabc_mode = cabc; + cmc624_state.main_tune = &tune_value[bg][ui].value[cabc]; + + if (ui == mDNIe_UI_MODE) { + cmc624_state.temperature = TEMP_STANDARD; + cmc624_state.outdoor = OUTDOOR_OFF_MODE; + } + + if (ui == mDNIe_VIDEO_WARM_MODE) + cmc624_state.temperature = TEMP_WARM; + else if (ui == mDNIe_VIDEO_COLD_MODE) + cmc624_state.temperature = TEMP_COLD; + set_backlight_pwm(cmc624_state.brightness); + return 0; +} + +int apply_browser_tune_value(enum SCENARIO_COLOR_TONE browser_mode, int force) +{ + browser_mode -= COLOR_TONE_1; + + if (cmc624_state.negative == 1) { + cmc624_state.browser_scenario = browser_mode; + cmc624_state.scenario = mDNIe_BROWSER_ON_MODE; + return 0; + } + pr_debug("==================================================\n"); + pr_debug(" CMC624 Mode Change. brower tune\n"); + pr_debug("==================================================\n"); + + if (!init_tune_flag[BROW_TUNE]) + init_tune_flag[MAIN_TUNE] = 0; init_tune_flag[SUB_TUNE] = 0;\ + init_tune_flag[BROW_TUNE] = 1; force = 1; + + if ((force == 0) && (cmc624_state.browser_scenario == browser_mode)) { + pr_debug( + "[CMC624:INFO]:%s:already setted browser tone : %d\n", + __func__ , browser_mode); + return 0; + } + pr_debug("[CMC624:INFO]:%s curr browser tune : %s\n", __func__, + browser_tune_value[cmc624_state.browser_scenario]. + value[cmc624_state.cabc_mode].name); + pr_debug("[CMC624:INFO]:%s browser tune : %s\n", __func__, + browser_tune_value[browser_mode]. + value[cmc624_state.cabc_mode].name); + pr_debug("[CMC624:INFO]:%s set, size : %d\n",\ + browser_tune_value[browser_mode]. + value[cmc624_state.cabc_mode].name, + browser_tune_value[browser_mode].\ + value[cmc624_state.cabc_mode].size); + if (cmc624_set_tune_value(browser_tune_value[browser_mode].\ + value[cmc624_state.cabc_mode].value,\ + browser_tune_value[browser_mode].\ + value[cmc624_state.cabc_mode].size) != 0) { + pr_err("[CMC624:ERROR]:%s: set tune value falied\n", __func__); + return -1; + } + cmc624_state.browser_scenario = browser_mode; + cmc624_state.scenario = mDNIe_BROWSER_ON_MODE; + return 0; +} +int apply_negative_tune_value( + enum eNegative_Mode negative_mode, enum eCabc_Mode cabc) { + int register_size; + + pr_debug("==================================================\n"); + pr_debug(" CMC624 Negative Change.\n"); + pr_debug("==================================================\n"); + + if (negative_mode == 0) { + cmc624_state.negative = negative_mode; + apply_main_tune_value(cmc624_state.scenario, + cmc624_state.background, cmc624_state.cabc_mode, 1); + pr_info("[CMC624:INFO]:%s:negative setted disalbe : %d\n", + __func__, negative_mode); + return 0; + } + register_size = negative_tune_value.value[cabc].size; + if (cmc624_set_tune_value( + negative_tune_value.value[cabc].value, register_size) + != 0) { + pr_err("[CMC624:ERROR]:%s:set tune value falied\n", __func__); + return -1; + } + cmc624_state.negative = negative_mode; + return 0; +} +void samsung_test_tune_dmb(void) +{ + int i = 0; + + pr_info("[%s]\n", __func__); + for (i = 0; i < ARRAY_SIZE(cmc624_tune_dmb_test); i++) { + if (cmc624_I2cWrite16 + (cmc624_tune_dmb_test[i].RegAddr, + cmc624_tune_dmb_test[i].Data)) { + pr_err("why return false??!!!\n"); + } + } +} + +#define LDI_MTP_ADDR 0xd3 +#define LDI_ID_ADDR 0xd1 +u8 mtp_read_data[24]; +u8 id_buffer[8]; +unsigned char LCD_ID; +unsigned char LCD_ELVSS_ID3; +static void read_ldi_reg(unsigned long src_add, unsigned char *read_data, + unsigned char read_length) +{ + int i; + u16 data = 0; + /* LP Operation2 (Read IDs) */ + /* cmc624_I2cWrite16( 0x00, 0x0003 ); */ + cmc624_I2cWrite16(0xaa, read_length); + + cmc624_I2cWrite16(0x02, 0x1100); + /* GENERIC WRITE 1 PARA */ + cmc624_I2cWrite16(0x04, 0x00b0); + /* WRITE B0 */ + cmc624_I2cWrite16(0x02, 0x1501); + /* GENERIC READ 1 PARA */ + cmc624_I2cWrite16(0x04, src_add); + /* WRITE d1/ d3 (Address of MTP) */ + + if (src_add == LDI_ID_ADDR) + pr_info("Read IDs from D1h\n"); + else + pr_info("READ Bright Gamma Offset from MTP(D3h)\n"); + + for (i = 0; i < read_length; i++) { + cmc624_I2cRead16(0x08, &data); /* Read Data Valid Register */ + + if ((data & 0x1000) != 0x1000) + pr_info("[%d] invalid data %x!!!\n", i, data); + /* Data Valid Check 0x1000? */ + else + pr_info("[%d] 0x08 data %x!!!\n", i, data); + /* Data Valid Check 0x1000? */ + cmc624_I2cRead16(0x06, &data); + /* Read Nst Parameter */ + read_data[i] = data; /*Store Nst Parameter */ + pr_info("[%d] IDs = %x\n", i, read_data[i]); + + } + if (read_length == 8) { + LCD_ID = read_data[1]; + LCD_ELVSS_ID3 = read_data[2]; + } + + cmc624_I2cRead16(0x08, &data); + /* Read Data Valid Register */ + if ((data & 0x1000) != 0x1000) + pr_info("End of read IDs %x!!!\n", data); + /* Data Valid Check 0x1000? */ + else + pr_info("0x08 data %x!!!\n", data); + /* Data Valid Check 0x1000? */ +} + +unsigned char LCD_Get_Value(void){ + return LCD_ID; +} + +bool Is_4_8LCD_cmc(void){ + if ((LCD_ID == 0x20) || (LCD_ID == 0x40) || (LCD_ID == 0x60)) + return true; + else + return false; +} + +bool Is_4_65LCD_cmc(void){ + if (LCD_ID == 0xAE) + return true; + else + return false; +} + +unsigned char LCD_ID3(void){ + return LCD_ELVSS_ID3; +} + +/* ################# END of SYSFS Function ############################# */ + +static bool CMC624_SetUp(void) +{ + u16 data = 0; + int i = 0; + static int bInit, bRead; + + mutex_lock(&tuning_mutex); + if (!bInit) { + + for (i = 0; i < ARRAY_SIZE(cmc624_init); i++) { + if (cmc624_I2cWrite16 + (cmc624_init[i].RegAddr, cmc624_init[i].Data)) { + pr_err("why return false??!!!\n"); + mutex_unlock(&tuning_mutex); + return FALSE; + } + if (cmc624_init[i].RegAddr == 0x3E + && cmc624_init[i].Data == 0x2223) { + mdelay(1); + } + } + mdelay(5); + if (!bRead) { + bRead = 1; + pr_info("CMC Init Sequence 2 Start....\n"); + read_ldi_reg(LDI_ID_ADDR, id_buffer, 8); + read_ldi_reg(LDI_MTP_ADDR, mtp_read_data, 24); + } + cmc624_I2cRead16(0x00, &data); + pr_info("0x00 data %x!!!\n", data); + cmc624_I2cRead16(0x82, &data); + pr_info("0x82 data %x!!!\n", data); + cmc624_I2cRead16(0x83, &data); + pr_info("0x83 data %x!!!\n", data); + cmc624_I2cRead16(0xC2, &data); + pr_info("0xC2 data %x!!!\n", data); + cmc624_I2cRead16(0xC3, &data); + pr_info("0xC3 data %x!!!\n", data); + + /*CONV */ + cmc624_I2cWrite16(0x00, 0x0003); /* BANK 3 */ + cmc624_I2cWrite16(0x01, 0x0001); /* MIPI TO MIPI */ + + cmc624_I2cWrite16(0x00, 0x0002); /* BANK 2 */ + cmc624_I2cWrite16(0x52, 0x0001); /* RGB IF ENABLE */ + + cmc624_I2cWrite16(0x00, 0x0003); /* BANK 3 goooooood */ + + } else { + + pr_info("cmc624_init3!!!\n"); + + for (i = 0; i < ARRAY_SIZE(cmc624_wakeup); i++) { + if (cmc624_I2cWrite16 + (cmc624_wakeup[i].RegAddr, cmc624_wakeup[i].Data)) { + mutex_unlock(&tuning_mutex); + pr_err("why return false??!!!\n"); + return FALSE; + } + } + } +/* samsung_test_tune_dmb(); */ + mutex_unlock(&tuning_mutex); + + return TRUE; +} + +void samsung_get_id(unsigned char *buf) +{ + buf[0] = (unsigned char)gIDs[0] & 0xff; + buf[1] = (unsigned char)gIDs[1] & 0xff; + buf[2] = (unsigned char)gIDs[2] & 0xff; + + pr_info("[%s] IDs = %x%x%x\n", __func__, buf[0], buf[1], buf[2]); +} + +void Check_Prog(void) +{ + u16 bank = 0; + u16 data = 0; + + pr_info("++++++%s++++\n", __func__); + mutex_lock(&tuning_mutex); + cmc624_I2cWrite16(0x00, 0x0003); /* BANK 3 */ + + cmc624_I2cRead16(0x00, &data); /* Read Nst Parameter */ + pr_info("0x00 data %x!!!\n", data); + cmc624_I2cRead16(0x82, &data); /* Read Nst Parameter */ + pr_info("0x82 data %x!!!\n", data); + cmc624_I2cRead16(0x83, &data); /* Read Nst Parameter */ + pr_info("0x83 data %x!!!\n", data); + cmc624_I2cRead16(0xC2, &data); /* Read Nst Parameter */ + pr_info("0xC2 data %x!!!\n", data); + cmc624_I2cRead16(0xC3, &data); /* Read Nst Parameter */ + pr_info("0xC3 data %x!!!\n", data); + + cmc624_I2cRead16(0x01, &data); + cmc624_I2cRead16(0x00, &bank); + pr_info("[bank %d] 0x01 data %x!!!\n", bank, data); + + cmc624_I2cWrite16(0x00, 0x0002); /* BANK 2 */ + cmc624_I2cRead16(0x52, &data); + cmc624_I2cRead16(0x00, &bank); + pr_info("[bank %d] 0x52 data %x!!!\n", bank, data); + + cmc624_I2cWrite16(0x00, 0x0005); /* BANK 5 */ + cmc624_I2cRead16(0x0B, &data); + cmc624_I2cRead16(0x00, &bank); + pr_info("[bank %d] 0x0B data %x!!!\n", bank, data); + + mutex_unlock(&tuning_mutex); + pr_info("-----%s-----\n", __func__); +} + +void change_mon_clk(void) +{ + pr_info("++++++%s++++\n", __func__); + cmc624_I2cWrite16(0x00, 0x0002); /* BANK 2 */ + cmc624_I2cWrite16(0x3F, 0x0107); + pr_info("-----%s-----\n", __func__); +} + +int samsung_cmc624_on(int enable) +{ + + int ret = 0; + + pr_info("[LCD] %s:enable:%d\n", __func__, enable); + + if (enable) { + + pr_info("CMC Init Sequence!\n"); + is_cmc624_on = 1; + CMC624_SetUp(); + cmc624_state.suspended = 0; + if (cmc624_state.negative == 0) { + apply_main_tune_value(cmc624_state.scenario,\ + cmc624_state.background,\ + cmc624_state.cabc_mode, 1); + } else + apply_negative_tune_value(cmc624_state.negative,\ + cmc624_state.cabc_mode); + + msleep(10); +#ifdef TIMER_DEBUG + timer_init(); +#endif + + } else { + is_cmc624_on = 0; + cmc624_state.suspended = 1; + } + + return ret; + +} + +int samsung_cmc624_bypass_mode(void) +{ + int ret; + gpio_set_value(IMA_SLEEP, 1); + ret = gpio_get_value(IMA_SLEEP); + pr_debug("%s, IMA_SLEEP : %d\n", __func__, ret); + udelay(20); + + gpio_set_value(IMA_nRST, 0); + ret = gpio_get_value(IMA_nRST); + pr_debug("%s, IMA_nRST : %d\n", __func__, ret); + msleep(4); + gpio_set_value(IMA_nRST, 1); + ret = gpio_get_value(IMA_nRST); + pr_debug("%s, IMA_nRST : %d\n", __func__, ret); + + return ret; + +} + +int samsung_cmc624_normal_mode(void) +{ + int ret; + + gpio_set_value(IMA_SLEEP, 1); + ret = gpio_get_value(IMA_SLEEP); + pr_debug("%s, IMA_SLEEP : %d\n", __func__, ret); + udelay(20); + + gpio_set_value(IMA_nRST, 0); + ret = gpio_get_value(IMA_nRST); + pr_debug("%s, IMA_nRST : %d\n", __func__, ret); + msleep(4); + gpio_set_value(IMA_nRST, 1); + ret = gpio_get_value(IMA_nRST); + pr_debug("%s, IMA_nRST : %d\n", __func__, ret); + + return ret; + +} + +/* Platform Range : 0 ~ 255 + * CMC624 Range : 0 ~ 100 + * User Platform Range : + * - MIN : 30 + * - MAX : 255 + * if under 30, CMC624 val : 2% + * if 30, CMC624 val : 3% + * if default, CMC624 val : 49% + * if 255, CMC624 val : 100% + */ + +#define DIMMING_BRIGHTNESS_VALUE 20 +#define MINIMUM_BRIGHTNESS_VALUE 30 +#define MAXIMUM_BRIGHTNESS_VALUE 255 +#define DEFAULT_BRIGHTNESS_VALUE 144 +#define QUATER_BRIGHTNESS_VALUE 87 + +#define DIMMING_CMC624_VALUE 1 +#define MINIMUM_CMC624_VALUE 1 /* 0% progress bar */ +#define MAXIMUM_CMC624_VALUE 100 /* 100% progress bar */ +#define DEFAULT_CMC624_VALUE 49 /* 50% progress bar */ +#define QUATER_CMC624_VALUE 9 /* 25% progress bar */ + +#define QUATER_DEFAUT_MAGIC_VALUE 3 +#define UNDER_DEFAULT_MAGIC_VALUE 52 +#define OVER_DEFAULT_MAGIC_VALUE 17 + +#if defined(CONFIG_MACH_P4_LTE) && defined(CONFIG_TARGET_LOCALE_JPN_NTT) +void cmc624_manual_brightness(int bl_lvl) +{ + /* Platform Range : 0 ~ 255 + * CMC624 Range : 0 ~ 100 + * User Platform Range : + * - MIN : 30 + * - MAX : 255 + * + * if 30, CMC624 val : 5 + * if 255, CMC624 val : 100 + * */ + int value; + + if (bl_lvl < 30) { + value = bl_lvl / 6; + } else if (bl_lvl <= 255) { + value = ((95 * bl_lvl) / 225) - 7; + } else { + pr_debug("[CMC624] Wrong Backlight scope!!!!!! [%d]\n", + bl_lvl); + value = 50; + } + + if (value < 0 || value > 100) + pr_debug("[CMC624] Wrong value scope [%d]\n", value); + pr_debug("[CMC624] BL : %d Value : %d\n", bl_lvl, value); + set_backlight_pwm(value); + cmc624_state.brightness = value; +} + +#else +void cmc624_manual_brightness(int bl_lvl) +{ + int value; + + if (bl_lvl < MINIMUM_BRIGHTNESS_VALUE) { + if (bl_lvl == 0) + value = 0; + else + value = DIMMING_CMC624_VALUE; + } else if (bl_lvl <= QUATER_BRIGHTNESS_VALUE) { + value = + ((QUATER_CMC624_VALUE - + MINIMUM_CMC624_VALUE) * bl_lvl / + (QUATER_BRIGHTNESS_VALUE - MINIMUM_BRIGHTNESS_VALUE)) - + QUATER_DEFAUT_MAGIC_VALUE; + } else if (bl_lvl <= DEFAULT_BRIGHTNESS_VALUE) { + value = + ((DEFAULT_CMC624_VALUE - + QUATER_CMC624_VALUE) * bl_lvl / + (DEFAULT_BRIGHTNESS_VALUE - QUATER_BRIGHTNESS_VALUE)) - + UNDER_DEFAULT_MAGIC_VALUE; + } else if (bl_lvl <= MAXIMUM_BRIGHTNESS_VALUE) { + value = + ((MAXIMUM_CMC624_VALUE - + DEFAULT_CMC624_VALUE) * bl_lvl / + (MAXIMUM_BRIGHTNESS_VALUE - DEFAULT_BRIGHTNESS_VALUE)) - + OVER_DEFAULT_MAGIC_VALUE; + } else { + pr_debug("[CMC624] Wrong Backlight scope!!!!!! [%d]\n", + bl_lvl); + value = 50; + } + + if (value < 0 || value > 100) + pr_debug("[CMC624] Wrong value scope [%d]\n", value); + value = 50; + pr_debug("[CMC624] BL : %d Value : %d\n", bl_lvl, value); + set_backlight_pwm(value); + cmc624_state.brightness = value; +} +#endif + +#if defined(CONFIG_TARGET_LOCALE_KOR_SKT)\ + || defined(CONFIG_TARGET_LOCALE_KOR_LGU) +void cmc624_Set_Region_Ext(int enable, int hStart, int hEnd, int vStart, + int vEnd) +{ + u16 data = 0; + + mutex_lock(&tuning_mutex); + + cmc624_I2cWrite16(0x0000, 0x0000); + cmc624_I2cRead16(0x0001, &data); + + data &= 0x00ff; + + if (enable) { + cmc624_I2cWrite16(0x00, 0x0000); /*BANK 0*/ + cmc624_I2cWrite16(0x0c, 0x5555); /*ROI on */ + cmc624_I2cWrite16(0x0d, 0x1555); /*ROI on */ + cmc624_I2cWrite16(0x0e, hStart); /*ROI x start 0 */ + cmc624_I2cWrite16(0x0f, hEnd); /*ROI x end 1279 */ + cmc624_I2cWrite16(0x10, vStart + 1); /*ROI y start 1 */ + cmc624_I2cWrite16(0x11, vEnd + 1); /*ROI y end 800 */ + cmc624_I2cWrite16(0xff, 0x0000); /*Mask Release */ + } else { + cmc624_I2cWrite16(0x00, 0x0000); /*BANK 0 */ + cmc624_I2cWrite16(0x0c, 0x0000); /*ROI off */ + cmc624_I2cWrite16(0x0d, 0x0000); /*ROI off */ + cmc624_I2cWrite16(0xff, 0x0000); /*Mask Release */ + } + + mutex_unlock(&tuning_mutex); + + cmc624_current_region_enable = enable; +} +EXPORT_SYMBOL(cmc624_Set_Region_Ext); + +#endif + +int samsung_gpio_init(void) +{ + int status; + + struct pm_gpio lvds_cfg = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + }; + + struct pm_gpio backlight_cfg = { + .direction = PM_GPIO_DIR_OUT, + .pull = PM_GPIO_PULL_NO, + .vin_sel = 2, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 0, + }; + int gpio_lvds = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_LVDS_nSHDN); + int gpio_backlight = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BACKLIGHT_RST); + if (pm8xxx_gpio_config(gpio_lvds, &lvds_cfg)) + pr_err("%s PMIC_GPIO_LVDS_nSHDN config failed\n", __func__); + status = + gpio_request(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_LVDS_nSHDN), + "LVDS_nSHDN"); + if (status) + pr_debug(KERN_ERR "%s: LVS_nSHDN gpio" + " %d request failed\n", __func__, + PMIC_GPIO_LVDS_nSHDN); + + if (pm8xxx_gpio_config(gpio_backlight, &backlight_cfg)) + pr_err("%s PMIC_GPIO_BACKLIGHT_RST config failed\n", __func__); + status = + gpio_request(PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_BACKLIGHT_RST), + "BACKLIGHT_EN"); + if (status) + pr_debug(KERN_ERR "%s: BACKLIGHT_EN gpio" + " %d request failed\n", __func__, + PMIC_GPIO_BACKLIGHT_RST); + return status; + +} + +int samsung_lvds_on(int enable) +{ + int status; + + if (enable) + status = + gpio_direction_output(PM8921_GPIO_PM_TO_SYS + (PMIC_GPIO_LVDS_nSHDN), + PMIC_GPIO_LCD_LEVEL_HIGH); + else + status = + gpio_direction_output(PM8921_GPIO_PM_TO_SYS + (PMIC_GPIO_LVDS_nSHDN), + PMIC_GPIO_LCD_LEVEL_LOW); + + status = + gpio_get_value_cansleep(PM8921_GPIO_PM_TO_SYS + (PMIC_GPIO_LVDS_nSHDN)); + + pr_debug("gpio_get_value result. LVDS_nSHDN : %d\n", status); + + return (unsigned int)status; + +} + +int samsung_backlight_en(int enable) +{ + int status; + + if (enable) + status = + gpio_direction_output(PM8921_GPIO_PM_TO_SYS + (PMIC_GPIO_BACKLIGHT_RST), + PMIC_GPIO_LCD_LEVEL_HIGH); + else + status = + gpio_direction_output(PM8921_GPIO_PM_TO_SYS + (PMIC_GPIO_BACKLIGHT_RST), + PMIC_GPIO_LCD_LEVEL_LOW); + status = + gpio_get_value_cansleep(PM8921_GPIO_PM_TO_SYS + (PMIC_GPIO_BACKLIGHT_RST)); + pr_debug("gpio_get_value. BACKLIGHT_EN : %d\n", status); + + return (unsigned int)status; +} + +static int cmc624_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cmc624_data *data; + + pr_info("%s +\n", __func__); + pr_debug("==============================\n"); + pr_debug("cmc624 attach START!!!\n"); + pr_debug("==============================\n"); + + data = kzalloc(sizeof(struct cmc624_data), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + data->client = client; + i2c_set_clientdata(client, data); + + dev_info(&client->dev, "cmc624 i2c probe success!!!\n"); + + p_cmc624_data = data; + + pr_debug("==============================\n"); + pr_debug("CMC624 SYSFS INIT!!!\n"); + pr_debug("==============================\n"); + pr_info("%s -\n", __func__); + + return 0; +} + +static int __devexit cmc624_i2c_remove(struct i2c_client *client) +{ + struct cmc624_data *data = i2c_get_clientdata(client); + + i2c_set_clientdata(client, NULL); + + kfree(data); + + dev_info(&client->dev, "cmc624 i2c remove success!!!\n"); + + return 0; +} + +void cmc624_shutdown(struct i2c_client *client) +{ + pr_debug("-0- %s called -0-\n", __func__); +} + +static const struct i2c_device_id cmc624[] = { + {"cmc624", 0}, +}; + +MODULE_DEVICE_TABLE(i2c, cmc624); + +struct i2c_driver cmc624_i2c_driver = { + .driver = { + .name = "cmc624", + .owner = THIS_MODULE, + }, + .probe = cmc624_i2c_probe, + .remove = __devexit_p(cmc624_i2c_remove), + .id_table = cmc624, + .shutdown = cmc624_shutdown, +}; + +int samsung_cmc624_init(void) +{ + int ret; + + /* register I2C driver for CMC624 */ + + pr_debug("\n"); + ret = i2c_add_driver(&cmc624_i2c_driver); + pr_debug("cmc624_init Return value (%d)\n", ret); + pr_debug("\n"); + + return 0; + +} +bool samsung_has_cmc624(void) +{ +#ifdef CONFIG_MACH_M2_ATT + if ((system_rev >= 11) && (system_rev != 13)) + return false; + else + return true; +#elif defined(CONFIG_MACH_M2_SPR) + if (system_rev >= 11) + return false; + else + return true; +#elif defined(CONFIG_MACH_M2_VZW) + if ((system_rev == 4) || (system_rev >= 14)) + return false; + else + return true; +#elif defined(CONFIG_MACH_M2_SKT) + if (system_rev >= 10) + return false; + else + return true; +#elif defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + if (system_rev >= 5) + return false; + else + return true; +#else + return false; +#endif +} +EXPORT_SYMBOL(samsung_has_cmc624); + +/* Module information */ +MODULE_AUTHOR("Samsung Electronics"); +MODULE_DESCRIPTION("samsung CMC624 image converter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/msm/samsung_cmc624.h b/drivers/video/msm/samsung_cmc624.h new file mode 100644 index 00000000000..f6cb71ef812 --- /dev/null +++ b/drivers/video/msm/samsung_cmc624.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2011, Samsung Electronics. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. +*/ + +#include "cmc624.h" +#include "samsung_cmc624_tune.h" + +#define CMC624_INITSEQ cmc624_init +/*#define CMC624_INITSEQ cmc624_bypass*/ +#define CMC624_MAX_SETTINGS 100 +#define TUNING_FILE_PATH "/sdcard/tuning/" + +#define PMIC_GPIO_LVDS_nSHDN 18 /* LVDS_nSHDN GPIO on PM8058 is 19 */ +#define PMIC_GPIO_BACKLIGHT_RST 36 /* LVDS_nSHDN GPIO on PM8058 is 37 */ +#define PMIC_GPIO_LCD_LEVEL_HIGH 1 +#define PMIC_GPIO_LCD_LEVEL_LOW 0 + +#define IMA_PWR_EN 70 +#define IMA_nRST 72 +#define IMA_SLEEP 103 +#define IMA_CMC_EN 104 +#define MLCD_ON 128 +#define IMA_I2C_SDA 156 +#define IMA_I2C_SCL 157 + +#define CMC624_FAILSAFE 106 +#define P8LTE_LCDON 1 +#define P8LTE_LCDOFF 0 + +/* BYPASS Mode OFF */ +#define BYPASS_MODE_ON 0 + +struct cmc624_state_type { + enum eCabc_Mode cabc_mode; + unsigned int brightness; + unsigned int suspended; + enum eLcd_mDNIe_UI scenario; + enum SCENARIO_COLOR_TONE browser_scenario; + enum eBackground_Mode background; +/*This value must reset to 0 (standard value) when change scenario*/ + enum eCurrent_Temp temperature; + enum eOutdoor_Mode outdoor; + enum eNegative_Mode negative; + const struct str_sub_unit *sub_tune; + const struct str_main_unit *main_tune; +}; + +/* CMC624 function */ +int cmc624_sysfs_init(void); +void bypass_onoff_ctrl(int value); +void cabc_onoff_ctrl(int value); +void set_backlight_pwm(int level); +int load_tuning_data(char *filename); +int apply_main_tune_value(enum eLcd_mDNIe_UI ui, enum eBackground_Mode bg, + enum eCabc_Mode cabc, int force); +int apply_sub_tune_value(enum eCurrent_Temp temp, enum eOutdoor_Mode ove, + enum eCabc_Mode cabc, int force); +int apply_browser_tune_value(enum SCENARIO_COLOR_TONE browser_mode, int force); +int apply_negative_tune_value(enum eNegative_Mode negative_mode, + enum eCabc_Mode cabc); +void dump_cmc624_register(void); +int samsung_cmc624_init(void); +/*int samsung_cmc624_setup(void);*/ +int samsung_cmc624_on(int enable); +int samsung_cmc624_bypass_mode(void); +int samsung_cmc624_normal_mode(void); +int samsung_lvds_on(int enable); +int samsung_backlight_en(int enable); +void cmc624_manual_brightness(int bl_lvl); +bool samsung_has_cmc624(void); +void samsung_get_id(unsigned char *buf); +void Check_Prog(void); +void change_mon_clk(void); +void cmc624_Set_Region_Ext(int enable, int hStart, int hEnd, int vStart, + int vEnd); +unsigned char LCD_Get_Value(void); +unsigned char LCD_ID3(void); +bool Is_4_8LCD_cmc(void); +bool Is_4_65LCD_cmc(void); +extern struct cmc624_state_type cmc624_state; diff --git a/drivers/video/msm/samsung_cmc624_tune.h b/drivers/video/msm/samsung_cmc624_tune.h new file mode 100644 index 00000000000..8f507203f4f --- /dev/null +++ b/drivers/video/msm/samsung_cmc624_tune.h @@ -0,0 +1,1342 @@ +#ifndef CMC624_REG_HEADER +#define CMC624_REG_HEADER +#endif + +#define CMC624_SERVICE_EXTEND + +/** CMC624 registers **/ + +/* SFR Bank selection */ +#define CMC624_REG_SELBANK 0x00 + +/* A stage configuration */ +#define CMC624_REG_DNRHDTROVE 0x01 +#define CMC624_REG_DITHEROFF 0x06 +#define CMC624_REG_CLKCONT 0x10 +#define CMC624_REG_CLKGATINGOFF 0x0a +#define CMC624_REG_INPUTIFCON 0x24 +#define CMC624_REG_CLKMONCONT 0x11 +#define CMC624_REG_HDRTCEOFF 0x3a +#define CMC624_REG_I2C 0x0d +#define CMC624_REG_BSTAGE 0x0e +#define CMC624_REG_CABCCTRL 0x7c +#define CMC624_REG_PWMCTRL 0xb4 +#define CMC624_REG_OVEMAX 0x54 + +/* A stage image size */ +#define CMC624_REG_1280 0x22 +#define CMC624_REG_800 0x23 + +/* B stage image size */ +#define CMC624_REG_SCALERINPH 0x09 +#define CMC624_REG_SCALERINPV 0x0a +#define CMC624_REG_SCALEROUTH 0x0b +#define CMC624_REG_SCALEROUTV 0x0c + +/* EDRAM configuration */ +#define CMC624_REG_EDRBFOUT40 0x01 +#define CMC624_REG_EDRAUTOREF 0x06 +#define CMC624_REG_EDRACPARAMTIM 0x07 + +/* Vsync Calibartion */ +#define CMC624_REG_CALVAL10 0x65 + +/* tcon output polarity */ +#define CMC624_REG_TCONOUTPOL 0x68 + +/* tcon RGB configuration */ +#define CMC624_REG_TCONRGB1 0x6c +#define CMC624_REG_TCONRGB2 0x6d +#define CMC624_REG_TCONRGB3 0x6e + +/* Reg update */ +#define CMC624_REG_REGMASK 0x28 +#define CMC624_REG_SWRESET 0x09 +#define CMC624_REG_RGBIFEN 0x26 + +/*////////////////////////////////////////////////////////*/ +/* CMC624 Register Setting*/ +/*////////////////////////////////////////////////////////*/ +static const struct cmc624RegisterSet cmc624_init[] = { + /* CLOCK_TOP */ + {0x00, 0x0002}, /* BANK 2*/ + /* S.PLL DISEN, NORMAL, P = 4 (Fout = 420MHz)*/ + {0x30, 0x0004}, + /* S = 2, M = 175 (Fout = 420MHz)*/ + {0x31, 0x20AF}, + /* S.PLL EN, NORMAL, P = 4 (Fout = 420MHz)*/ + {0x30, 0x1004}, + /* CLOCK DIVIDER VALUE (I2C = 15[28MHz], A = 5)*/ + {0x3A, 0x0F05}, + {0x3B, 0x040D}, /* CLOCK DIVIDER VALUE (M1 = 4, M2 = 13)*/ + {0x3C, 0x1203}, /* CLOCK DIVIDER VALUE (B = 18, P = 3)*/ + {0x3D, 0x0400}, /* CLOCK DIVIDER VALUE (PWM = 1024)*/ + {0x39, 0x007F}, /* CLOCK DIVIDER ENABLE*/ + {0x3E, 0x2223}, /* CLOCK MUX SEL*/ + + {0x00, 0x0000}, /* BANK 0*/ + {0xFD, 0x0000}, /* MODULE REG MASK RELEASE*/ + {0xFE, 0x0004}, /* MODULE REG MASK RELEASE*/ + + {0xFF, 0x0000}, /* REG MASK RELEASE*/ + + /* INPUT IF*/ + {0x00, 0x0002}, /* BANK 2*/ + /* RGB BOTTOM ALIGNMENT, VSYNC/HSYNC LOW ACTIVE, DE HIHG ACTIVE*/ + {0x50, 0x0061}, + /* TCON*/ + {0x00, 0x0002}, /* BANK 2*/ + {0x60, 0x5400}, /* TCON VSYNC DELAY*/ + {0x63, 0x0810}, /* OUTPUT COLOR MAP, TCON OUTPUT POL(LLH)*/ + {0x67, 0x0002}, /* VSYNC PULSE WIDTH = 2*/ + {0x68, 0x0040}, /* HSYNC PULSE WIDTH = 64*/ + {0x69, 0x0001}, /* VBP = 1*/ + {0x6A, 0x000D}, /* VFP = 13*/ + {0x6B, 0x0032}, /* HBP = 50*/ + {0x6C, 0x00C8}, /* HFP = 200*/ + {0x66, 0x8000}, /* CDC*/ + + /* IP*/ + {0x00, 0x0000}, /* BANK 0*/ + {0x01, 0x0077}, /* HSYNC/DE MASK RELEASE*/ + {0x03, 0x02D0}, /* WIDTH = 720 */ + {0x04, 0x0500}, /* HEIGHT = 1280*/ + {0x08, 0x0000}, /* ALGO MODULE OFF*/ + {0x09, 0x0000}, /* ALGO MODULE OFF*/ + {0x0A, 0x0000}, /* ALGO MODULE OFF*/ + + /* CONV*/ + {0x00, 0x0003}, /* BANK 3*/ + {0x01, 0x0000}, /* I2C TO MIPI*/ + {0x43, 0x8000}, /* M_BAND_CTL*/ + {0x42, 0x4649}, /* M_PLL SETTING (Fout = 482.40MHz)*/ + {0x41, 0x8000}, /* M_PLL SETTING & M_PLL ENABLE*/ + {0x44, 0x000A}, /* S_HSSETTLE*/ + {0x40, 0x0030}, /* M/S CLOCK LANE ENABLE*/ + + {0x00, 0x0000}, /* BANK 0*/ + {0xFD, 0xFFFF}, /* MODULE REG MASK RELEASE*/ + {0xFE, 0xFFFF}, /* MODULE REG MASK RELEASE*/ + {0xFF, 0x0000}, /* MASK RELEASE*/ + + /* DSI HOST*/ + {0x00, 0x0003}, /* BANK 3*/ + {0x84, 0xFFFF}, /* INTERRUPT ENABLE*/ + {0x85, 0x1FEF}, /* INTERRUPT ENABLE*/ + /* DSI FUNCTION (CMD 8 BIT DATA, RGB888, + CMD VC 0, VIDEO VC 0, 4 LANE)*/ + {0x86, 0x6204}, + {0x88, 0xFFFF}, /* HIGH SPEED RECEIVE TIMEOUT*/ + {0x89, 0x00FF}, /* HIGH SPEED RECEIVE TIMEOUT*/ + {0x8A, 0xFFFF}, /* LOW POWER RECEIVE TIMEOUT*/ + {0x8B, 0x00FF}, /* LOW POWER RECEIVE TIMEOUT*/ + {0x8C, 0x001F}, /* TURN AROUND TIMEOUT*/ + {0x8E, 0x00FF}, /* DEVICE RESET TIMER*/ + {0x90, 0x02D0}, /* HORIZANTAL RESOLUTION = 720 */ + {0x91, 0x0500}, /* VERTICAL RESOLUTION = 1280*/ + + {0x94, 0x0030}, /* HORIZANTAL SYNC PADDING COUNT*/ + {0x96, 0x0026}, /* HORIZANTAL BACK PORCH COUNT*/ + {0x98, 0x0096}, /* HORIZANTAL FRONT FORCH COUNT*/ + {0x9A, 0x021C}, /* HORIZANTAL ACTIVE AREA*/ + + {0x9C, 0x0002}, /* VERTICAL SYNC PADDING COUNT*/ + {0x9E, 0x0001}, /* VERTICAL BACK PORCH COUNT*/ + {0xA0, 0x000D}, /* VERTICAL FRONT FORCH COUNT*/ + {0xA8, 0x0d07}, /* MASTER INIT TIME*/ + {0xAC, 0x0002}, /* VIDEO MODE FORMAT = NON BURST SYNC EVENT*/ + /* VSYNC, HSYNC, COLOR MODE, SHUT DOWN POLARITY*/ + {0xB0, 0x0008}, + + {0xB4, 0x0004}, /* LP EQUIVALENT BYTECLK*/ + /* HIGH SPEED <-> LOW POWER SWITCHING COUNTER FOR DATA LANE*/ + {0xA2, 0x0014}, + /* HIGH SPEED -> LOW POWER SWITCHING COUNTER FOR CLOCK LANE*/ + {0xB2, 0x000B}, + /* HIGH SPEED <- LOW POWER SWITCHING COUNTER FOR CLOCK LANE*/ + {0xB3, 0x001C}, + + {0x80, 0x0001}, /* DEVICE READY*/ + {0xA4, 0x0002}, /* COLOR MODE OFF, DPI ON*/ + + /* DSI DEVICE*/ + {0x00, 0x0003}, /* BANK 3*/ + {0xC4, 0xFFFF}, /* INTERRUPT ENABLE*/ + {0xC5, 0x01FF}, /* INTERRUPT ENABLE*/ + {0xC6, 0x0064}, /* DSI FUNCTION : BURST & NON BURST SYNC EVENT*/ + {0xC8, 0xFFFF}, /* HIGH SPEED RECEIVE TIMEOUT*/ + {0xC9, 0xFFFF}, /* HIGH SPEED RECEIVE TIMEOUT*/ + {0xCA, 0x005E}, /* LOW POWER RECEIVE TIMEOUT*/ + {0xCB, 0x0000}, /* LOW POWER RECEIVE TIMEOUT*/ + {0xCC, 0x0025}, /* TURN AROUND TIMEOUT*/ + {0xCE, 0x07D0}, /* DEVICE RESET TIMER*/ + {0xD2, 0x0000}, /* CRC, ECC, EOT ENABLE*/ + {0xD4, 0x0040}, /* HSYNC COUNT = 64*/ + {0xD5, 0x0002}, /* VSYNC COUNT = 2*/ + {0xC0, 0x0001}, /* DEVICE READY*/ + + /* LP Operation*/ + {0x00, 0x0003}, /* BANK 3*/ + {0x07, 0x1000}, /* Interrupt Mask, Data Valid Only*/ + + /* LP Operation1 (Write Auto Pow On)*/ + {0x03, 0x0003}, /* Write Length*/ + {0x02, 0x1301}, /* LP enable, Generic Long Write, VC=0*/ + {0x05, 0x00F0}, /* F0h*/ + {0x05, 0x005A}, /* 5Ah*/ + {0x05, 0x005A}, /* 5Ah*/ + + /* LP Operation2 (Write Auto Pow On)*/ + {0x03, 0x0003}, /* Write Length*/ + {0x02, 0x1301}, /* LP enable, Generic Long Write, VC=0*/ + {0x05, 0x00F1}, /* F0h*/ + {0x05, 0x005A}, /* 5Ah*/ + {0x05, 0x005A}, /* 5Ah*/ + + /* LP Operation2 (Write Sleep Out)*/ + {0x03, 0x0001}, /* Write Length*/ + {0x02, 0x0000}, /* LP enable, DCS Write*/ + {0x04, 0x0011}, /* SLEEP_OUT*/ +}; + +static const struct cmc624RegisterSet cmc624_wakeup[] = { + /* CLOCK_TOP*/ + {0x00, 0x0002}, /* BANK 2*/ + {0x30, 0x0004}, /* S.PLL DISEN, NORMAL, P = 4 (Fout = 420MHz)*/ + {0x31, 0x20AF}, /* S = 2, M = 175 (Fout = 420MHz)*/ + {0x30, 0x1004}, /* S.PLL EN, NORMAL, P = 4 (Fout = 420MHz)*/ + /* CLOCK DIVIDER VALUE (I2C = 15[28MHz], A = 5)*/ + {0x3A, 0x0F05}, + {0x3B, 0x0418}, /* CLOCK DIVIDER VALUE (M1 = 4, M2 = 24)*/ + {0x3C, 0x1203}, /* CLOCK DIVIDER VALUE (B = 18, P = 3)*/ + {0x3D, 0x0400}, /* CLOCK DIVIDER VALUE (PWM = 1024)*/ + {0x39, 0x007F}, /* CLOCK DIVIDER ENABLE*/ + {0x3E, 0x2223}, /* CLOCK MUX SEL*/ + + {0x00, 0x0000}, /* BANK 0*/ + {0xFD, 0x0000}, /* MODULE REG MASK RELEASE*/ + {0xFE, 0x0004}, /* MODULE REG MASK RELEASE*/ + + {0xFF, 0x0000}, /* REG MASK RELEASE*/ + + /* INPUT IF*/ + {0x00, 0x0002}, /* BANK 2*/ + /* RGB BOTTOM ALIGNMENT, VSYNC/HSYNC LOW ACTIVE, DE HIHG ACTIVE*/ + {0x50, 0x0021}, + + /* TCON*/ + {0x00, 0x0002}, /* BANK 2*/ + {0x60, 0x5400}, /* TCON VSYNC DELAY*/ + {0x63, 0x0310}, /* OUTPUT COLOR MAP, TCON OUTPUT POL(LLH)*/ + {0x67, 0x0002}, /* VSYNC PULSE WIDTH = 2*/ + {0x68, 0x0040}, /* HSYNC PULSE WIDTH = 64*/ + {0x69, 0x0003}, /* VBP = 3*/ + {0x6A, 0x000D}, /* VFP = 13*/ + {0x6B, 0x008C}, /* HBP = 140*/ + {0x6C, 0x0092}, /* HFP = 146*/ + {0x66, 0x8000}, /* CDC*/ + + /* IP*/ + {0x00, 0x0000}, /* BANK 0*/ + {0x01, 0x0077}, /* HSYNC/DE MASK RELEASE*/ + {0x03, 0x0500}, /* WIDTH = 1280*/ + {0x04, 0x0320}, /* HEIGHT = 800*/ + {0x08, 0x0000}, /* ALGO MODULE OFF*/ + {0x09, 0x0000}, /* ALGO MODULE OFF*/ + {0x0A, 0x0000}, /* ALGO MODULE OFF*/ + + /* CONV*/ + {0x00, 0x0003}, /* BANK 3*/ + {0x01, 0x0001}, /* MIPI TO MIPI*/ + {0x43, 0x8000}, /* M_BAND_CTL*/ + {0x42, 0x4641}, /* M_PLL SETTING (Fout = 480MHz)*/ + {0x41, 0x8000}, /* M_PLL SETTING & M_PLL ENABLE*/ + {0x44, 0x000A}, /* S_HSSETTLE*/ + {0x40, 0x0030}, /* M/S CLOCK LANE ENABLE*/ + + {0x00, 0x0000}, /* BANK 0*/ + {0xFD, 0xFFFF}, /* MODULE REG MASK RELEASE*/ + {0xFE, 0xFFFF}, /* MODULE REG MASK RELEASE*/ + {0xFF, 0x0000}, /* MASK RELEASE*/ + + /* DSI HOST*/ + {0x00, 0x0003}, /* BANK 3*/ + {0x84, 0xFFFF}, /* INTERRUPT ENABLE*/ + {0x85, 0x1FEF}, /* INTERRUPT ENABLE*/ + /* DSI FUNCTION (CMD 8 BIT DATA, RGB888, + CMD VC 0, VIDEO VC 0, 4 LANE)*/ + {0x86, 0x6204}, + {0x88, 0xFFFF}, /* HIGH SPEED RECEIVE TIMEOUT*/ + {0x89, 0x00FF}, /* HIGH SPEED RECEIVE TIMEOUT*/ + {0x8A, 0xFFFF}, /* LOW POWER RECEIVE TIMEOUT*/ + {0x8B, 0x00FF}, /* LOW POWER RECEIVE TIMEOUT*/ + {0x8C, 0x001F}, /* TURN AROUND TIMEOUT*/ + {0x8E, 0x00FF}, /* DEVICE RESET TIMER*/ + {0x90, 0x0500}, /* HORIZANTAL RESOLUTION = 1280*/ + {0x91, 0x0320}, /* VERTICAL RESOLUTION = 800*/ + + {0x94, 0x0030}, /* HORIZANTAL SYNC PADDING COUNT*/ + {0x96, 0x0069}, /* HORIZANTAL BACK PORCH COUNT*/ + {0x98, 0x006E}, /* HORIZANTAL FRONT FORCH COUNT*/ + {0x9A, 0x03C0}, /* HORIZANTAL ACTIVE AREA*/ + + {0x9C, 0x0002}, /* VERTICAL SYNC PADDING COUNT*/ + {0x9E, 0x0003}, /* VERTICAL BACK PORCH COUNT*/ + {0xA0, 0x000D}, /* VERTICAL FRONT FORCH COUNT*/ + {0xA8, 0x0d07}, /* MASTER INIT TIME*/ + {0xAC, 0x0002}, /* VIDEO MODE FORMAT = NON BURST SYNC EVENT*/ + /* VSYNC, HSYNC, COLOR MODE, SHUT DOWN POLARITY*/ + {0xB0, 0x0008}, + + {0xB4, 0x000A}, /* LP EQUIVALENT BYTECLK*/ + /* HIGH SPEED <-> LOW POWER SWITCHING COUNTER FOR DATA LANE*/ + {0xA2, 0x0014}, + /* HIGH SPEED -> LOW POWER SWITCHING COUNTER FOR CLOCK LANE*/ + {0xB2, 0x000B}, + /* HIGH SPEED <- LOW POWER SWITCHING COUNTER FOR CLOCK LANE*/ + {0xB3, 0x001C}, + + {0x80, 0x0001}, /* DEVICE READY*/ + {0xA4, 0x0002}, /* COLOR MODE OFF, DPI ON*/ + + /* DSI DEVICE*/ + {0x00, 0x0003}, /* BANK 3*/ + {0xC4, 0xFFFF}, /* INTERRUPT ENABLE*/ + {0xC5, 0x01FF}, /* INTERRUPT ENABLE*/ + {0xC6, 0x0064}, /* DSI FUNCTION : BURST & NON BURST SYNC EVENT*/ + {0xC8, 0xFFFF}, /* HIGH SPEED RECEIVE TIMEOUT*/ + {0xC9, 0x0FFF}, /* HIGH SPEED RECEIVE TIMEOUT*/ + {0xCA, 0x005E}, /* LOW POWER RECEIVE TIMEOUT*/ + {0xCB, 0x0000}, /* LOW POWER RECEIVE TIMEOUT*/ + {0xCC, 0x0025}, /* TURN AROUND TIMEOUT*/ + {0xCE, 0x07D0}, /* DEVICE RESET TIMER*/ + {0xD2, 0x0000}, /* CRC, ECC, EOT ENABLE*/ + {0xD4, 0x0040}, /* HSYNC COUNT = 64*/ + {0xD5, 0x0002}, /* VSYNC COUNT = 2*/ + {0xC0, 0x0001}, /* DEVICE READY*/ + + {0x00, 0x0002}, /* BANK 2*/ + {0x52, 0x0001}, /* RGB IF ENABLE*/ + + {0x3f, 0x011B}, /* MON_CLK : TXBYTECLKHS (60MHz)*/ + +}; + +static const struct cmc624RegisterSet cmc624_bypass[] = { + {0x0000, 0x0000}, /* BANK 0*/ + {0x0008, 0x0000}, /* SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /* MCM off*/ + {0x000a, 0x0000}, /* UC off*/ + {0x0030, 0x0000}, /* FA cs1 | de8 hdr2 fa1 */ + {0x00ff, 0x0000}, /* Mask Release */ + +}; + +static const struct cmc624RegisterSet standard_video_cabcoff[] = { + /* start D2 standard video */ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0030}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0060}, /*DE pe*/ + {0x00b3, 0x0060}, /*DE pf*/ + {0x00b4, 0x0060}, /*DE pb*/ + {0x00b5, 0x0060}, /*DE ne*/ + {0x00b6, 0x0060}, /*DE nf*/ + {0x00b7, 0x0060}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1204}, /*CS weight grayTH*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /* end */ +}; +static const struct cmc624RegisterSet standard_video_cabcon[] = { + /*start D2 standard video lowpower*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0230}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0060}, /*DE pe*/ + {0x00b3, 0x0060}, /*DE pf*/ + {0x00b4, 0x0060}, /*DE pb*/ + {0x00b5, 0x0060}, /*DE ne*/ + {0x00b6, 0x0060}, /*DE nf*/ + {0x00b7, 0x0060}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1604}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xf000}, /*SCR RrCr*/ + {0x0072, 0x00f0}, /*SCR RgCg*/ + {0x0073, 0x00f0}, /*SCR RbCb*/ + {0x0074, 0x00f0}, /*SCR GrMr*/ + {0x0075, 0xf000}, /*SCR GgMg*/ + {0x0076, 0x00f0}, /*SCR GbMb*/ + {0x0077, 0x00f0}, /*SCR BrYr*/ + {0x0078, 0x00f0}, /*SCR BgYg*/ + {0x0079, 0xf000}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00ff}, /*SCR KgWg*/ + {0x007c, 0x00ff}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; + +static const struct cmc624RegisterSet standard_dmb_cabcoff[] = { + /*start P8 standard dmb*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0036}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0080, 0x1001}, /*NR col con ring bl*/ + {0x0081, 0x3f04}, /*NR blRedTH maxmin*/ + {0x0082, 0x1006}, /*NR edgeTH blDecTH*/ + {0x0083, 0x3f04}, /*NR conRedTH maxmin*/ + {0x0090, 0x0430}, /*WIENER br*/ + {0x0091, 0x0040}, /*WIENER hf*/ + {0x0092, 0x1000}, /*WIENER lf*/ + {0x00b2, 0x0100}, /*DE pe*/ + {0x00b3, 0x0100}, /*DE pf*/ + {0x00b4, 0x0100}, /*DE pb*/ + {0x00b5, 0x0100}, /*DE ne*/ + {0x00b6, 0x0100}, /*DE nf*/ + {0x00b7, 0x0100}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0010}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1804}, /*CS weight grayTH*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; + +static const struct cmc624RegisterSet standard_ui_cabcoff[] = { + /*start D2 standard ui */ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0030}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0020}, /*DE pe*/ + {0x00b3, 0x0020}, /*DE pf*/ + {0x00b4, 0x0020}, /*DE pb*/ + {0x00b5, 0x0020}, /*DE ne*/ + {0x00b6, 0x0020}, /*DE nf*/ + {0x00b7, 0x0020}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1604}, /*CS weight grayTH*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; +static const struct cmc624RegisterSet standard_ui_cabcon[] = { + /*start D2 standard ui lowpower*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0230}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0020}, /*DE pe*/ + {0x00b3, 0x0020}, /*DE pf*/ + {0x00b4, 0x0020}, /*DE pb*/ + {0x00b5, 0x0020}, /*DE ne*/ + {0x00b6, 0x0020}, /*DE nf*/ + {0x00b7, 0x0020}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1a04}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xf000}, /*SCR RrCr*/ + {0x0072, 0x00f0}, /*SCR RgCg*/ + {0x0073, 0x00f0}, /*SCR RbCb*/ + {0x0074, 0x00f0}, /*SCR GrMr*/ + {0x0075, 0xf000}, /*SCR GgMg*/ + {0x0076, 0x00f0}, /*SCR GbMb*/ + {0x0077, 0x00f0}, /*SCR BrYr*/ + {0x0078, 0x00f0}, /*SCR BgYg*/ + {0x0079, 0xf000}, /*SCR BbYb*/ + {0x007a, 0x00f0}, /*SCR KrWr*/ + {0x007b, 0x00f0}, /*SCR KgWg*/ + {0x007c, 0x00f0}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; + +static const struct cmc624RegisterSet standard_gallery_cabcoff[] = { + /* start D2 standard gallery */ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0030}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0060}, /*DE pe*/ + {0x00b3, 0x0060}, /*DE pf*/ + {0x00b4, 0x0060}, /*DE pb*/ + {0x00b5, 0x0060}, /*DE ne*/ + {0x00b6, 0x0060}, /*DE nf*/ + {0x00b7, 0x0060}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1204}, /*CS weight grayTH*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/* end */ +}; + +static const struct cmc624RegisterSet standard_vtcall_cabcoff[] = { + /* start D2 standard vtcall */ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0032}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0080, 0x1111}, /*NR col con ring bl*/ + {0x0081, 0x3f04}, /*NR blRedTH maxmin*/ + {0x0082, 0x1006}, /*NR edgeTH blDecTH*/ + {0x0083, 0x3f04}, /*NR conRedTH maxmin*/ + {0x00b2, 0x00c0}, /*DE pe*/ + {0x00b3, 0x00c0}, /*DE pf*/ + {0x00b4, 0x00c0}, /*DE pb*/ + {0x00b5, 0x00c0}, /*DE ne*/ + {0x00b6, 0x00c0}, /*DE nf*/ + {0x00b7, 0x00c0}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0010}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1804}, /*CS weight grayTH*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /* end */ +}; + +static const struct cmc624RegisterSet movie_video_cabcoff[] = { +/*start P8 movie video*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0200}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd9a9}, /*SCR RrCr*/ + {0x0072, 0x35ff}, /*SCR RgCg*/ + {0x0073, 0x2bf2}, /*SCR RbCb*/ + {0x0074, 0x9fff}, /*SCR GrMr*/ + {0x0075, 0xff3f}, /*SCR GgMg*/ + {0x0076, 0x58ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00fa}, /*SCR BgYg*/ + {0x0079, 0xff5f}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00f8}, /*SCR KgWg*/ + {0x007c, 0x00f1}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet movie_dmb_cabcoff[] = { +/*start P8 movie dmb*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0232}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0080, 0x1001}, /*NR col con ring bl*/ + {0x0081, 0x3f04}, /*NR blRedTH maxmin*/ + {0x0082, 0x1004}, /*NR edgeTH blDecTH*/ + {0x0083, 0x3f04}, /*NR conRedTH maxmin*/ + {0x00b2, 0x0080}, /*DE pe*/ + {0x00b3, 0x0080}, /*DE pf*/ + {0x00b4, 0x0080}, /*DE pb*/ + {0x00b5, 0x0080}, /*DE ne*/ + {0x00b6, 0x0080}, /*DE nf*/ + {0x00b7, 0x0080}, /*DE nb*/ + /*0x00b8, 0x1000, //DE max ratio*/ + {0x00b9, 0x0010}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1404}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd5af}, /*SCR RrCr*/ + {0x0072, 0x37ff}, /*SCR RgCg*/ + {0x0073, 0x30fb}, /*SCR RbCb*/ + {0x0074, 0xa5fe}, /*SCR GrMr*/ + {0x0075, 0xff4d}, /*SCR GgMg*/ + {0x0076, 0x63ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00f7}, /*SCR BgYg*/ + {0x0079, 0xff69}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00f8}, /*SCR KgWg*/ + {0x007c, 0x00f0}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; + +static const struct cmc624RegisterSet movie_ui_cabcoff[] = { +/*start P8 movie ui*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0200}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd9a9}, /*SCR RrCr*/ + {0x0072, 0x35ff}, /*SCR RgCg*/ + {0x0073, 0x2bf2}, /*SCR RbCb*/ + {0x0074, 0x9fff}, /*SCR GrMr*/ + {0x0075, 0xff3f}, /*SCR GgMg*/ + {0x0076, 0x58ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00fa}, /*SCR BgYg*/ + {0x0079, 0xff5f}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00f8}, /*SCR KgWg*/ + {0x007c, 0x00f1}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet movie_gallery_cabcoff[] = { +/*start P8 movie gallery*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0200}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd9a9}, /*SCR RrCr*/ + {0x0072, 0x35ff}, /*SCR RgCg*/ + {0x0073, 0x2bf2}, /*SCR RbCb*/ + {0x0074, 0x9fff}, /*SCR GrMr*/ + {0x0075, 0xff3f}, /*SCR GgMg*/ + {0x0076, 0x58ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00fa}, /*SCR BgYg*/ + {0x0079, 0xff5f}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00f8}, /*SCR KgWg*/ + {0x007c, 0x00f1}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet movie_vtcall_cabcoff[] = { + /*start P8 movie vtcall*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0232}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0080, 0x1111}, /*NR col con ring bl*/ + {0x0081, 0x3f04}, /*NR blRedTH maxmin*/ + {0x0082, 0x1006}, /*NR edgeTH blDecTH*/ + {0x0083, 0x3f04}, /*NR conRedTH maxmin*/ + {0x00b2, 0x0080}, /*DE pe*/ + {0x00b3, 0x0080}, /*DE pf*/ + {0x00b4, 0x0080}, /*DE pb*/ + {0x00b5, 0x0080}, /*DE ne*/ + {0x00b6, 0x0080}, /*DE nf*/ + {0x00b7, 0x0080}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0010}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1404}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd9a9}, /*SCR RrCr*/ + {0x0072, 0x35ff}, /*SCR RgCg*/ + {0x0073, 0x2bf2}, /*SCR RbCb*/ + {0x0074, 0x9fff}, /*SCR GrMr*/ + {0x0075, 0xff3f}, /*SCR GgMg*/ + {0x0076, 0x58ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00fa}, /*SCR BgYg*/ + {0x0079, 0xff5f}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00f8}, /*SCR KgWg*/ + {0x007c, 0x00f1}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet natural_video_cabcoff[] = { +/*start D2 natural video*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0230}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0060}, /*DE pe*/ + {0x00b3, 0x0060}, /*DE pf*/ + {0x00b4, 0x0060}, /*DE pb*/ + {0x00b5, 0x0060}, /*DE ne*/ + {0x00b6, 0x0060}, /*DE nf*/ + {0x00b7, 0x0060}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1804}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd9a9}, /*SCR RrCr*/ + {0x0072, 0x35ff}, /*SCR RgCg*/ + {0x0073, 0x2bf2}, /*SCR RbCb*/ + {0x0074, 0x9fff}, /*SCR GrMr*/ + {0x0075, 0xff3f}, /*SCR GgMg*/ + {0x0076, 0x58ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00fa}, /*SCR BgYg*/ + {0x0079, 0xff5f}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00fa}, /*SCR KgWg*/ + {0x007c, 0x00f8}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet natural_dmb_cabcoff[] = { +/*start P8 natural dmb*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0232}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0080, 0x1001}, /*NR col con ring bl*/ + {0x0081, 0x3f04}, /*NR blRedTH maxmin*/ + {0x0082, 0x1004}, /*NR edgeTH blDecTH*/ + {0x0083, 0x3f04}, /*NR conRedTH maxmin*/ + {0x00b2, 0x00c0}, /*DE pe*/ + {0x00b3, 0x00c0}, /*DE pf*/ + {0x00b4, 0x00c0}, /*DE pb*/ + {0x00b5, 0x00c0}, /*DE ne*/ + {0x00b6, 0x00c0}, /*DE nf*/ + {0x00b7, 0x00c0}, /*DE nb*/ + /*0x00b8, 0x1000, //DE max ratio*/ + {0x00b9, 0x0010}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1804}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd5af}, /*SCR RrCr*/ + {0x0072, 0x37ff}, /*SCR RgCg*/ + {0x0073, 0x30fb}, /*SCR RbCb*/ + {0x0074, 0xa5fe}, /*SCR GrMr*/ + {0x0075, 0xff4d}, /*SCR GgMg*/ + {0x0076, 0x63ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00f7}, /*SCR BgYg*/ + {0x0079, 0xff69}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00fa}, /*SCR KgWg*/ + {0x007c, 0x00f8}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet natural_ui_cabcoff[] = { +/*start D2 natural ui*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0230}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0020}, /*DE pe*/ + {0x00b3, 0x0020}, /*DE pf*/ + {0x00b4, 0x0020}, /*DE pb*/ + {0x00b5, 0x0020}, /*DE ne*/ + {0x00b6, 0x0020}, /*DE nf*/ + {0x00b7, 0x0020}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1804}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd9a9}, /*SCR RrCr*/ + {0x0072, 0x35ff}, /*SCR RgCg*/ + {0x0073, 0x2bf2}, /*SCR RbCb*/ + {0x0074, 0x9fff}, /*SCR GrMr*/ + {0x0075, 0xff3f}, /*SCR GgMg*/ + {0x0076, 0x58ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00fa}, /*SCR BgYg*/ + {0x0079, 0xff5f}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00fa}, /*SCR KgWg*/ + {0x007c, 0x00f8}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet natural_gallery_cabcoff[] = { +/*start D2 natural gallery*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0230}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0060}, /*DE pe*/ + {0x00b3, 0x0060}, /*DE pf*/ + {0x00b4, 0x0060}, /*DE pb*/ + {0x00b5, 0x0060}, /*DE ne*/ + {0x00b6, 0x0060}, /*DE nf*/ + {0x00b7, 0x0060}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1804}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd9a9}, /*SCR RrCr*/ + {0x0072, 0x35ff}, /*SCR RgCg*/ + {0x0073, 0x2bf2}, /*SCR RbCb*/ + {0x0074, 0x9fff}, /*SCR GrMr*/ + {0x0075, 0xff3f}, /*SCR GgMg*/ + {0x0076, 0x58ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00fa}, /*SCR BgYg*/ + {0x0079, 0xff5f}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00fa}, /*SCR KgWg*/ + {0x007c, 0x00f8}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet natural_vtcall_cabcoff[] = { + /* start D2 natural vtcall */ + {0x0000, 0x0000}, /*BANK 0 */ + {0x0008, 0x0232}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0080, 0x1111}, /*NR col con ring bl*/ + {0x0081, 0x3f04}, /*NR blRedTH maxmin*/ + {0x0082, 0x1006}, /*NR edgeTH blDecTH*/ + {0x0083, 0x3f04}, /*NR conRedTH maxmin*/ + {0x00b2, 0x00c0}, /*DE pe*/ + {0x00b3, 0x00c0}, /*DE pf*/ + {0x00b4, 0x00c0}, /*DE pb*/ + {0x00b5, 0x00c0}, /*DE ne*/ + {0x00b6, 0x00c0}, /*DE nf*/ + {0x00b7, 0x00c0}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0010}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1804}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xd9a9}, /*SCR RrCr*/ + {0x0072, 0x35ff}, /*SCR RgCg*/ + {0x0073, 0x2bf2}, /*SCR RbCb*/ + {0x0074, 0x9fff}, /*SCR GrMr*/ + {0x0075, 0xff3f}, /*SCR GgMg*/ + {0x0076, 0x58ff}, /*SCR GbMb*/ + {0x0077, 0x00ff}, /*SCR BrYr*/ + {0x0078, 0x00fa}, /*SCR BgYg*/ + {0x0079, 0xff5f}, /*SCR BbYb*/ + {0x007a, 0x00ff}, /*SCR KrWr*/ + {0x007b, 0x00fa}, /*SCR KgWg*/ + {0x007c, 0x00f8}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; + +static const struct cmc624RegisterSet dynamic_video_cabcoff[] = { +/*start P8 dynamic video*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0130}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0080}, /*DE pe*/ + {0x00b3, 0x0080}, /*DE pf*/ + {0x00b4, 0x0080}, /*DE pb*/ + {0x00b5, 0x0080}, /*DE ne*/ + {0x00b6, 0x0080}, /*DE nf*/ + {0x00b7, 0x0080}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1404}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x003f, 0x0080}, /*CC chsel strength*/ + {0x0040, 0x0000}, /*CC lut r 0*/ + {0x0041, 0x0d93}, /*CC lut r 16 144 */ + {0x0042, 0x1aa5}, /*CC lut r 32 160*/ + {0x0043, 0x29b7}, /*CC lut r 48 176*/ + {0x0044, 0x39c8}, /*CC lut r 64 192*/ + {0x0045, 0x4bd8}, /*CC lut r 80 208*/ + {0x0046, 0x5de6}, /*CC lut r 96 224*/ + {0x0047, 0x6ff4}, /*CC lut r 112 240*/ + {0x0048, 0x81ff}, /*CC lut r 128 255*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet dynamic_dmb_cabcoff[] = { +/*start P8 dynamic dmb*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0132}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0080, 0x1001}, /*NR col con ring bl*/ + {0x0081, 0x3f04}, /*NR blRedTH maxmin*/ + {0x0082, 0x1004}, /*NR edgeTH blDecTH*/ + {0x0083, 0x3f04}, /*NR conRedTH maxmin*/ + {0x00b2, 0x00e0}, /*DE pe*/ + {0x00b3, 0x00e0}, /*DE pf*/ + {0x00b4, 0x00e0}, /*DE pb*/ + {0x00b5, 0x00e0}, /*DE ne*/ + {0x00b6, 0x00e0}, /*DE nf*/ + {0x00b7, 0x00e0}, /*DE nb*/ + /*0x00b8, 0x1000, //DE max ratio*/ + {0x00b9, 0x0010}, /*DE min ratio*/ + {0x00c0, 0x0808}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x2804}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x003f, 0x0080}, /*CC chsel strength*/ + {0x0040, 0x0000}, /*CC lut r 0*/ + {0x0041, 0x0d93}, /*CC lut r 16 144*/ + {0x0042, 0x1aa5}, /*CC lut r 32 160*/ + {0x0043, 0x29b7}, /*CC lut r 48 176*/ + {0x0044, 0x39c8}, /*CC lut r 64 192*/ + {0x0045, 0x4bd8}, /*CC lut r 80 208*/ + {0x0046, 0x5de6}, /*CC lut r 96 224*/ + {0x0047, 0x6ff4}, /*CC lut r 112 240*/ + {0x0048, 0x81ff}, /*CC lut r 128 255*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet dynamic_ui_cabcoff[] = { +/*start P8 dynamic ui*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0130}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0040}, /*DE pe*/ + {0x00b3, 0x0040}, /*DE pf*/ + {0x00b4, 0x0040}, /*DE pb*/ + {0x00b5, 0x0040}, /*DE ne*/ + {0x00b6, 0x0040}, /*DE nf*/ + {0x00b7, 0x0040}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1804}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x003f, 0x0080}, /*CC chsel strength*/ + {0x0040, 0x0000}, /*CC lut r 0*/ + {0x0041, 0x0d93}, /*CC lut r 16 144 */ + {0x0042, 0x1aa5}, /*CC lut r 32 160*/ + {0x0043, 0x29b7}, /*CC lut r 48 176*/ + {0x0044, 0x39c8}, /*CC lut r 64 192*/ + {0x0045, 0x4bd8}, /*CC lut r 80 208*/ + {0x0046, 0x5de6}, /*CC lut r 96 224*/ + {0x0047, 0x6ff4}, /*CC lut r 112 240*/ + {0x0048, 0x81ff}, /*CC lut r 128 255*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet dynamic_gallery_cabcoff[] = { +/*start P8 dynamic gallery*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0130}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0080}, /*DE pe*/ + {0x00b3, 0x0080}, /*DE pf*/ + {0x00b4, 0x0080}, /*DE pb*/ + {0x00b5, 0x0080}, /*DE ne*/ + {0x00b6, 0x0080}, /*DE nf*/ + {0x00b7, 0x0080}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1404}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x003f, 0x0080}, /*CC chsel strength*/ + {0x0040, 0x0000}, /*CC lut r 0*/ + {0x0041, 0x0d93}, /*CC lut r 16 144 */ + {0x0042, 0x1aa5}, /*CC lut r 32 160*/ + {0x0043, 0x29b7}, /*CC lut r 48 176*/ + {0x0044, 0x39c8}, /*CC lut r 64 192*/ + {0x0045, 0x4bd8}, /*CC lut r 80 208*/ + {0x0046, 0x5de6}, /*CC lut r 96 224*/ + {0x0047, 0x6ff4}, /*CC lut r 112 240*/ + {0x0048, 0x81ff}, /*CC lut r 128 255*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet dynamic_vtcall_cabcoff[] = { +/*start P8 dynamic vtcall*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0132}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0080, 0x1111}, /*NR col con ring bl*/ + {0x0081, 0x3f04}, /*NR blRedTH maxmin*/ + {0x0082, 0x1006}, /*NR edgeTH blDecTH*/ + {0x0083, 0x3f04}, /*NR conRedTH maxmin*/ + {0x00b2, 0x00e0}, /*DE pe*/ + {0x00b3, 0x00e0}, /*DE pf*/ + {0x00b4, 0x00e0}, /*DE pb*/ + {0x00b5, 0x00e0}, /*DE ne*/ + {0x00b6, 0x00e0}, /*DE nf*/ + {0x00b7, 0x00e0}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0010}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x2004}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x003f, 0x0080}, /*CC chsel strength*/ + {0x0040, 0x0000}, /*CC lut r 0*/ + {0x0041, 0x0d93}, /*CC lut r 16 144*/ + {0x0042, 0x1aa5}, /*CC lut r 32 160*/ + {0x0043, 0x29b7}, /*CC lut r 48 176*/ + {0x0044, 0x39c8}, /*CC lut r 64 192*/ + {0x0045, 0x4bd8}, /*CC lut r 80 208*/ + {0x0046, 0x5de6}, /*CC lut r 96 224*/ + {0x0047, 0x6ff4}, /*CC lut r 112 240*/ + {0x0048, 0x81ff}, /*CC lut r 128 255*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet camera_cabcoff[] = { + /*start D2 camera*/ + {0x0000, 0x0000}, /*BANK 0 */ + {0x0008, 0x0030}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0060}, /*DE pe*/ + {0x00b3, 0x0060}, /*DE pf*/ + {0x00b4, 0x0060}, /*DE pb*/ + {0x00b5, 0x0060}, /*DE ne*/ + {0x00b6, 0x0060}, /*DE nf*/ + {0x00b7, 0x0060}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1204}, /*CS weight grayTH*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; +static const struct cmc624RegisterSet camera_cabcon[] = { + /* start D2 camera lowpower*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0230}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0060}, /*DE pe*/ + {0x00b3, 0x0060}, /*DE pf*/ + {0x00b4, 0x0060}, /*DE pb*/ + {0x00b5, 0x0060}, /*DE ne*/ + {0x00b6, 0x0060}, /*DE nf*/ + {0x00b7, 0x0060}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg ry*/ + {0x00c1, 0x1010}, /*CS hg gc*/ + {0x00c2, 0x1010}, /*CS hg bm*/ + {0x00c3, 0x1204}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xf800}, /*SCR RrCr*/ + {0x0072, 0x00f8}, /*SCR RgCg*/ + {0x0073, 0x00f8}, /*SCR RbCb*/ + {0x0074, 0x00f8}, /*SCR GrMr*/ + {0x0075, 0xf800}, /*SCR GgMg*/ + {0x0076, 0x00f8}, /*SCR GbMb*/ + {0x0077, 0x00f8}, /*SCR BrYr*/ + {0x0078, 0x00f8}, /*SCR BgYg*/ + {0x0079, 0xf800}, /*SCR BbYb*/ + {0x007a, 0x00f8}, /*SCR KrWr*/ + {0x007b, 0x00f8}, /*SCR KgWg*/ + {0x007c, 0x00f8}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /* end*/ +}; + +static const struct cmc624RegisterSet camera_ove[] = { +/*start P8 camera outdoor*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0030}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0001}, /*UC*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x00b2, 0x0060}, /*DE pe*/ + {0x00b3, 0x0060}, /*DE pf*/ + {0x00b4, 0x0060}, /*DE pb*/ + {0x00b5, 0x0060}, /*DE ne*/ + {0x00b6, 0x0060}, /*DE nf*/ + {0x00b7, 0x0060}, /*DE nb*/ + {0x00b8, 0x1000}, /*DE max ratio*/ + {0x00b9, 0x0100}, /*DE min ratio*/ + {0x00c0, 0x1010}, /*CS hg RY*/ + {0x00c1, 0x1010}, /*CS hg GC*/ + {0x00c2, 0x1010}, /*CS hg BM*/ + {0x00c3, 0x1204}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x00e0, 0x01c0}, /*UC y*/ + {0x00e1, 0x01ff}, /*UC cs*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet cold_ove_cabcoff[] = { + /*start P8 cold outdoor*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0009, 0x0001}, /*MCM*/ + {0x000a, 0x0001}, /*UC*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0001, 0x0064}, /*MCM 10000K*/ + {0x0006, 0xf8f8}, /*MCM LSF4 LSF5*/ + {0x0009, 0x908d}, /*MCM 5cb 1cr W*/ + {0x000b, 0x7c7c}, /*MCM 4cr 5cr W*/ + {0x000e, 0x8080}, /*MCM 5cb 1cr K*/ + {0x0010, 0x8080}, /*MCM 4cr 5cr K*/ + {0x00e0, 0x01c0}, /*UC y*/ + {0x00e1, 0x01ff}, /*UC cs*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; + +static const struct cmc624RegisterSet cold_cabcoff[] = { + /*start P8 cold*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0009, 0x0001}, /*MCM*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0001, 0x0064}, /*MCM 10000K*/ + {0x0006, 0xf8f8}, /*MCM LSF4 LSF5*/ + {0x0009, 0x908d}, /*MCM 5cb 1cr W*/ + {0x000b, 0x7c7c}, /*MCM 4cr 5cr W*/ + {0x000e, 0x8080}, /*MCM 5cb 1cr K*/ + {0x0010, 0x8080}, /*MCM 4cr 5cr K*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; + +static const struct cmc624RegisterSet warm_ove_cabcoff[] = { + /*start P8 warm outdoor*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0009, 0x0001}, /*MCM*/ + {0x000a, 0x0001}, /*UC*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0001, 0x0028}, /*MCM 4000K*/ + {0x0004, 0x64ff}, /*MCM CT5 LSF1*/ + {0x0007, 0x7676}, /*MCM 1cb 2cb W*/ + {0x0009, 0x908d}, /*MCM 5cb 1cr W*/ + {0x000c, 0x8080}, /*MCM 1cb 2cb K*/ + {0x000e, 0x8080}, /*MCM 5cb 1cr K*/ + {0x00e0, 0x01c0}, /*UC y*/ + {0x00e1, 0x01ff}, /*UC cs*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; + +static const struct cmc624RegisterSet warm_cabcoff[] = { + /*start P8 warm*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0009, 0x0001}, /*MCM*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0001, 0x0028}, /*MCM 4000K*/ + {0x0004, 0x64ff}, /*MCM CT5 LSF1*/ + {0x0007, 0x7676}, /*MCM 1cb 2cb W*/ + {0x0009, 0x908d}, /*MCM 5cb 1cr W*/ + {0x000c, 0x8080}, /*MCM 1cb 2cb K*/ + {0x000e, 0x8080}, /*MCM 5cb 1cr K*/ + {0x0011, 0x8080}, /*MCM gray axis*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet ove_cabcoff[] = { +/*start P8 outdoor*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0001}, /*UC*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x00e0, 0x01c0}, /*US y*/ + {0x00e1, 0x01ff}, /*UC cs*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet browser_tone1_tune[] = { +/*start P8 browser tone 1*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0200}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xaf00}, /*SCR RrCr*/ + {0x0072, 0x00b7}, /*SCR RgCg*/ + {0x0073, 0x00bc}, /*SCR RbCb*/ + {0x0074, 0x00af}, /*SCR GrMr*/ + {0x0075, 0xb700}, /*SCR GgMg*/ + {0x0076, 0x00bc}, /*SCR GbMb*/ + {0x0077, 0x00af}, /*SCR BrYr*/ + {0x0078, 0x00b7}, /*SCR BgYg*/ + {0x0079, 0xbc00}, /*SCR BbYb*/ + {0x007a, 0x00af}, /*SCR KrWr*/ + {0x007b, 0x00b7}, /*SCR KgWg*/ + {0x007c, 0x00bc}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet browser_tone2_tune[] = { +/*start P8 browser tone 2*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0200}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0xa000}, /*SCR RrCr*/ + {0x0072, 0x00a8}, /*SCR RgCg*/ + {0x0073, 0x00b2}, /*SCR RbCb*/ + {0x0074, 0x00a0}, /*SCR GrMr*/ + {0x0075, 0xa800}, /*SCR GgMg*/ + {0x0076, 0x00b2}, /*SCR GbMb*/ + {0x0077, 0x00a0}, /*SCR BrYr*/ + {0x0078, 0x00a8}, /*SCR BgYg*/ + {0x0079, 0xb200}, /*SCR BbYb*/ + {0x007a, 0x00a0}, /*SCR KrWr*/ + {0x007b, 0x00a8}, /*SCR KgWg*/ + {0x007c, 0x00b2}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet browser_tone3_tune[] = { +/*start P8 browser tone 3*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0200}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0x9100}, /*SCR RrCr*/ + {0x0072, 0x0099}, /*SCR RgCg*/ + {0x0073, 0x00a3}, /*SCR RbCb*/ + {0x0074, 0x0091}, /*SCR GrMr*/ + {0x0075, 0x9900}, /*SCR GgMg*/ + {0x0076, 0x00a3}, /*SCR GbMb*/ + {0x0077, 0x0091}, /*SCR BrYr*/ + {0x0078, 0x0099}, /*SCR BgYg*/ + {0x0079, 0xa300}, /*SCR BbYb*/ + {0x007a, 0x0091}, /*SCR KrWr*/ + {0x007b, 0x0099}, /*SCR KgWg*/ + {0x007c, 0x00a3}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ +/*end*/ +}; + +static const struct cmc624RegisterSet cmc624_tune_dmb_test[] = { + /*start P8 dmb test*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0136}, /*CC CS DE*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0082, 0x1005}, /*edgeTH BLDecTH*/ + {0x0083, 0x3f00}, /*ConRedTH maxmin*/ + {0x0090, 0x0420}, /*Wiener Br*/ + {0x0091, 0x0500}, /*Wiener hf*/ + {0x00b2, 0x00a0}, /*DE pe*/ + {0x00b3, 0x0030}, /*DE pf*/ + {0x00b4, 0x0028}, /*DE pb*/ + {0x00b5, 0x00a0}, /*DE ne*/ + {0x00b6, 0x0030}, /*DE nf*/ + {0x00b7, 0x0028}, /*DE nb*/ + {0x00c0, 0x1010}, /*hg RY*/ + {0x00c1, 0x1010}, /*hg GC*/ + {0x00c2, 0x1010}, /*hg BM*/ + {0x00c3, 0x1804}, /*CS weight grayTH*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x003f, 0x0080}, /*CC chsel strength*/ + {0x0040, 0x0000}, + {0x0041, 0x1090}, /*0x0c96,*/ + {0x0042, 0x20a0}, /*0x18a8,*/ + {0x0043, 0x30b0}, /*0x2aba,*/ + {0x0044, 0x40c0}, /*0x3ccc,*/ + {0x0045, 0x50d0}, /*0x4edc,*/ + {0x0046, 0x60e0}, /*0x60ea,*/ + {0x0047, 0x70F0}, /*0x72f6,*/ + {0x0048, 0x80ff}, /*0x84ff,*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; +static const struct cmc624RegisterSet cmc624_tune_tone_reversal[] = { + /*start D2 tone reversal*/ + {0x0000, 0x0000}, /*BANK 0*/ + {0x0008, 0x0200}, /*SCR2 CC1 | CS2 DE1 | LoG8 WIENER4 NR2 HDR1*/ + {0x0009, 0x0000}, /*MCM off*/ + {0x000a, 0x0000}, /*UC off*/ + {0x0030, 0x0000}, /*FA cs1 de8 hdr2 fa1*/ + {0x0000, 0x0001}, /*BANK 1*/ + {0x0071, 0x00ff}, /*SCR RrCr*/ + {0x0072, 0xff00}, /*SCR RgCg*/ + {0x0073, 0xff00}, /*SCR RbCb*/ + {0x0074, 0xff00}, /*SCR GrMr*/ + {0x0075, 0x00ff}, /*SCR GgMg*/ + {0x0076, 0xff00}, /*SCR GbMb*/ + {0x0077, 0xff00}, /*SCR BrYr*/ + {0x0078, 0xff00}, /*SCR BgYg*/ + {0x0079, 0x00ff}, /*SCR BbYb*/ + {0x007a, 0xff00}, /*SCR KrWr*/ + {0x007b, 0xff00}, /*SCR KgWg*/ + {0x007c, 0xff00}, /*SCR KbWb*/ + {0x00ff, 0x0000}, /*Mask Release*/ + /*end*/ +}; diff --git a/drivers/video/msm/smart_dimming.h b/drivers/video/msm/smart_dimming.h new file mode 100644 index 00000000000..05d5cd7c8d0 --- /dev/null +++ b/drivers/video/msm/smart_dimming.h @@ -0,0 +1,112 @@ +/* + * ================================================================= + * + * Filename: smart_dimming.h + * + * Description: cmc624, lvds control driver + * + * Author: Krishna Kishor Jha, + * Company: Samsung Electronics + * + * ================================================================ + */ +/* + +Copyright (C) 2011, Samsung Electronics. All rights reserved. + +* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * +*/ + +#ifndef __SMART_DIMMING_H__ +#define __SMART_DIMMING_H__ + +#include +#include +#include +#include +#include +#include + + +enum { + CI_RED = 0, + CI_GREEN = 1, + CI_BLUE = 2, + CI_MAX = 3, +}; + +enum { + IV_1 = 0, + IV_15 = 1, + IV_35 = 2, + IV_59 = 3, + IV_87 = 4, + IV_171 = 5, + IV_255 = 6, + IV_MAX = 7, + IV_TABLE_MAX = 8, +}; + +enum { + AD_IV0 = 0, + AD_IV1 = 1, + AD_IV15 = 2, + AD_IV35 = 3, + AD_IV59 = 4, + AD_IV87 = 5, + AD_IV171 = 6, + AD_IV255 = 7, + AD_IVMAX = 8, +}; + +#define MAX_GRADATION 300 + +struct str_voltage_entry { + u32 v[CI_MAX]; +}; + +struct str_table_info { + u8 st; + u8 et; + u8 count; + u8 *offset_table; + u32 rv; +}; + +struct str_flookup_table { + u16 entry; + u16 count; +}; + +struct str_smart_dim { + s16 mtp[CI_MAX][IV_MAX]; + struct str_voltage_entry ve[256]; + u8 *default_gamma; + struct str_table_info t_info[IV_TABLE_MAX]; + struct str_flookup_table *flooktbl; + u32 *g22_tbl; + u32 *g300_gra_tbl; + u32 adjust_volt[CI_MAX][AD_IVMAX]; + s16 adjust_mtp[CI_MAX][IV_MAX]; + +}; + +int init_table_info(struct str_smart_dim *smart, unsigned char *srcGammaTable); +u8 calc_voltage_table(struct str_smart_dim *smart, const u8 * mtp); +u32 calc_gamma_table(struct str_smart_dim *smart, u32 gv, u8 result[]); + +#endif diff --git a/drivers/video/msm/smart_mtp_2p2_gamma.h b/drivers/video/msm/smart_mtp_2p2_gamma.h new file mode 100644 index 00000000000..b94efa7f1a8 --- /dev/null +++ b/drivers/video/msm/smart_mtp_2p2_gamma.h @@ -0,0 +1,2138 @@ +/* + * ================================================================= + * + * Filename: smart_mtp_2p2_gamma.h + * + * Description: Smart dimming algorithm implementation + * + * Author: jb09.kim + * Company: Samsung Electronics + * + * ================================================================ + */ +/* + +Copyright (C) 2012, Samsung Electronics. All rights reserved. + +* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * +*/ + +#ifndef _SMART_MTP_2P2_GAMMA_H_ +#define _SMART_MTP_2P2_GAMMA_H_ + +/* +* index : 0 ~ 255 +* ((index/255)^2.2)*16384 +*/ +int candela_coeff_2p2[] = { +0, +0, +0, +1, +2, +3, +4, +6, +8, +10, +13, +16, +20, +23, +28, +32, +37, +42, +48, +54, +61, +67, +75, +82, +90, +99, +108, +117, +127, +137, +148, +159, +170, +182, +195, +207, +221, +234, +249, +263, +278, +294, +310, +326, +343, +361, +379, +397, +416, +435, +455, +475, +496, +517, +539, +561, +584, +607, +630, +654, +679, +704, +730, +756, +783, +810, +838, +866, +894, +924, +953, +984, +1014, +1046, +1077, +1110, +1142, +1176, +1210, +1244, +1279, +1314, +1350, +1387, +1424, +1461, +1499, +1538, +1577, +1617, +1657, +1698, +1739, +1781, +1824, +1866, +1910, +1954, +1999, +2044, +2089, +2136, +2182, +2230, +2278, +2326, +2375, +2425, +2475, +2526, +2577, +2629, +2681, +2734, +2788, +2842, +2896, +2951, +3007, +3064, +3121, +3178, +3236, +3295, +3354, +3414, +3474, +3535, +3597, +3659, +3721, +3785, +3849, +3913, +3978, +4044, +4110, +4177, +4244, +4312, +4380, +4450, +4519, +4590, +4660, +4732, +4804, +4877, +4950, +5024, +5098, +5173, +5249, +5325, +5402, +5480, +5558, +5637, +5716, +5796, +5876, +5957, +6039, +6121, +6204, +6288, +6372, +6457, +6542, +6628, +6715, +6802, +6890, +6978, +7067, +7157, +7247, +7338, +7429, +7522, +7614, +7708, +7802, +7896, +7992, +8087, +8184, +8281, +8379, +8477, +8576, +8676, +8776, +8877, +8978, +9080, +9183, +9287, +9391, +9495, +9601, +9707, +9813, +9920, +10028, +10137, +10246, +10355, +10466, +10577, +10688, +10801, +10914, +11027, +11141, +11256, +11372, +11488, +11605, +11722, +11840, +11959, +12078, +12198, +12319, +12440, +12562, +12685, +12808, +12932, +13057, +13182, +13308, +13434, +13561, +13689, +13818, +13947, +14077, +14207, +14338, +14470, +14602, +14736, +14869, +15004, +15139, +15274, +15411, +15548, +15686, +15824, +15963, +16103, +16243, +16384, +}; + +/* +* index : 0 ~ 255 +* ((index/255)^2.15)*16384 +*/ +int candela_coeff_2p15[] = { +0 , +0 , +0 , +1 , +2 , +3 , +5 , +7 , +10 , +12 , +16 , +19 , +23 , +27 , +32 , +37 , +43 , +49 , +55 , +62 , +69 , +76 , +84 , +93 , +102 , +111 , +121 , +131 , +142 , +153 , +165 , +177 , +189 , +202 , +215 , +229 , +243 , +258 , +273 , +289 , +305 , +322 , +339 , +357 , +375 , +393 , +412 , +432 , +452 , +472 , +493 , +515 , +537 , +559 , +582 , +606 , +629 , +654 , +679 , +704 , +730 , +757 , +783 , +811 , +839 , +867 , +896 , +926 , +956 , +986 , +1017 , +1048 , +1080 , +1113 , +1146 , +1180 , +1214 , +1248 , +1283 , +1319 , +1355 , +1392 , +1429 , +1467 , +1505 , +1544 , +1583 , +1623 , +1663 , +1704 , +1746 , +1788 , +1830 , +1873 , +1917 , +1961 , +2006 , +2051 , +2096 , +2143 , +2190 , +2237 , +2285 , +2333 , +2382 , +2432 , +2482 , +2532 , +2584 , +2635 , +2688 , +2740 , +2794 , +2848 , +2902 , +2957 , +3013 , +3069 , +3125 , +3183 , +3240 , +3299 , +3358 , +3417 , +3477 , +3538 , +3599 , +3660 , +3723 , +3786 , +3849 , +3913 , +3977 , +4042 , +4108 , +4174 , +4241 , +4308 , +4376 , +4445 , +4514 , +4583 , +4653 , +4724 , +4796 , +4867 , +4940 , +5013 , +5087 , +5161 , +5235 , +5311 , +5387 , +5463 , +5540 , +5618 , +5696 , +5775 , +5854 , +5934 , +6015 , +6096 , +6178 , +6260 , +6343 , +6426 , +6510 , +6595 , +6680 , +6766 , +6852 , +6939 , +7027 , +7115 , +7203 , +7293 , +7383 , +7473 , +7564 , +7656 , +7748 , +7841 , +7934 , +8028 , +8123 , +8218 , +8314 , +8410 , +8507 , +8605 , +8703 , +8802 , +8901 , +9001 , +9102 , +9203 , +9305 , +9407 , +9510 , +9614 , +9718 , +9823 , +9928 , +10034 , +10141 , +10248 , +10356 , +10464 , +10573 , +10683 , +10793 , +10903 , +11015 , +11127 , +11240 , +11353 , +11467 , +11581 , +11696 , +11812 , +11928 , +12045 , +12162 , +12280 , +12399 , +12518 , +12638 , +12759 , +12880 , +13002 , +13124 , +13247 , +13371 , +13495 , +13620 , +13745 , +13871 , +13998 , +14125 , +14253 , +14382 , +14511 , +14641 , +14771 , +14902 , +15034 , +15166 , +15299 , +15432 , +15566 , +15701 , +15836 , +15972 , +16109 , +16246 , +16384 , +}; + +/* +* index : 0 ~ 255 +* ((index/255)^2.1)*16384 +*/ +int candela_coeff_2p1[] = { +0 , +0 , +1 , +1 , +3 , +4 , +6 , +9 , +11 , +15 , +18 , +22 , +27 , +32 , +37 , +43 , +49 , +56 , +63 , +70 , +78 , +87 , +95 , +105 , +115 , +125 , +136 , +147 , +158 , +170 , +183 , +196 , +210 , +224 , +238 , +253 , +268 , +284 , +301 , +318 , +335 , +353 , +371 , +390 , +409 , +429 , +449 , +470 , +491 , +513 , +535 , +558 , +581 , +605 , +629 , +654 , +679 , +705 , +731 , +758 , +785 , +813 , +841 , +870 , +899 , +929 , +959 , +990 , +1021 , +1053 , +1085 , +1118 , +1151 , +1185 , +1219 , +1254 , +1289 , +1325 , +1362 , +1399 , +1436 , +1474 , +1512 , +1551 , +1591 , +1631 , +1672 , +1713 , +1754 , +1796 , +1839 , +1882 , +1926 , +1970 , +2015 , +2060 , +2106 , +2152 , +2199 , +2247 , +2294 , +2343 , +2392 , +2441 , +2491 , +2542 , +2593 , +2645 , +2697 , +2750 , +2803 , +2857 , +2911 , +2966 , +3021 , +3077 , +3134 , +3191 , +3248 , +3306 , +3365 , +3424 , +3484 , +3544 , +3605 , +3666 , +3728 , +3790 , +3853 , +3917 , +3981 , +4045 , +4110 , +4176 , +4242 , +4309 , +4376 , +4444 , +4513 , +4582 , +4651 , +4721 , +4792 , +4863 , +4935 , +5007 , +5080 , +5153 , +5227 , +5301 , +5376 , +5452 , +5528 , +5605 , +5682 , +5759 , +5838 , +5917 , +5996 , +6076 , +6157 , +6238 , +6319 , +6401 , +6484 , +6568 , +6651 , +6736 , +6821 , +6906 , +6992 , +7079 , +7166 , +7254 , +7342 , +7431 , +7521 , +7611 , +7701 , +7793 , +7884 , +7976 , +8069 , +8163 , +8257 , +8351 , +8446 , +8542 , +8638 , +8735 , +8832 , +8930 , +9029 , +9128 , +9227 , +9327 , +9428 , +9529 , +9631 , +9734 , +9837 , +9940 , +10044 , +10149 , +10254 , +10360 , +10467 , +10574 , +10681 , +10789 , +10898 , +11007 , +11117 , +11227 , +11338 , +11450 , +11562 , +11675 , +11788 , +11902 , +12016 , +12131 , +12247 , +12363 , +12480 , +12597 , +12715 , +12833 , +12952 , +13072 , +13192 , +13313 , +13434 , +13556 , +13679 , +13802 , +13925 , +14049 , +14174 , +14300 , +14425 , +14552 , +14679 , +14807 , +14935 , +15064 , +15193 , +15323 , +15454 , +15585 , +15717 , +15849 , +15982 , +16115 , +16249 , +16384 , +}; + +/* +* index : 0 ~ 255 +* 300 is max CANDELA +* (300*((index/255)^2.2))*16384 +*/ + +int curve_2p2[] = { +0 , +25 , +115 , +280 , +528 , +862 , +1287 , +1807 , +2424 , +3141 , +3960 , +4884 , +5915 , +7054 , +8303 , +9663 , +11138 , +12727 , +14432 , +16255 , +18197 , +20259 , +22442 , +24748 , +27177 , +29730 , +32410 , +35215 , +38149 , +41210 , +44402 , +47723 , +51175 , +54760 , +58477 , +62328 , +66313 , +70433 , +74689 , +79081 , +83611 , +88279 , +93085 , +98031 , +103116 , +108343 , +113710 , +119219 , +124871 , +130666 , +136605 , +142687 , +148915 , +155288 , +161807 , +168473 , +175285 , +182245 , +189353 , +196610 , +204016 , +211571 , +219277 , +227133 , +235140 , +243299 , +251610 , +260073 , +268690 , +277459 , +286383 , +295461 , +304693 , +314081 , +323624 , +333324 , +343180 , +353192 , +363362 , +373690 , +384175 , +394819 , +405622 , +416585 , +427707 , +438988 , +450431 , +462034 , +473798 , +485724 , +497812 , +510061 , +522474 , +535049 , +547788 , +560691 , +573757 , +586988 , +600384 , +613944 , +627670 , +641562 , +655619 , +669844 , +684234 , +698792 , +713517 , +728410 , +743470 , +758699 , +774097 , +789663 , +805399 , +821304 , +837379 , +853624 , +870040 , +886626 , +903383 , +920311 , +937411 , +954683 , +972127 , +989744 , +1007533 , +1025495 , +1043630 , +1061939 , +1080422 , +1099079 , +1117910 , +1136916 , +1156097 , +1175452 , +1194984 , +1214691 , +1234574 , +1254633 , +1274869 , +1295281 , +1315870 , +1336637 , +1357581 , +1378703 , +1400003 , +1421481 , +1443138 , +1464973 , +1486987 , +1509181 , +1531554 , +1554106 , +1576839 , +1599752 , +1622845 , +1646119 , +1669574 , +1693210 , +1717027 , +1741026 , +1765206 , +1789569 , +1814114 , +1838841 , +1863751 , +1888844 , +1914120 , +1939580 , +1965223 , +1991050 , +2017061 , +2043257 , +2069636 , +2096201 , +2122950 , +2149885 , +2177005 , +2204310 , +2231801 , +2259478 , +2287341 , +2315391 , +2343627 , +2372050 , +2400660 , +2429457 , +2458442 , +2487614 , +2516974 , +2546522 , +2576258 , +2606183 , +2636296 , +2666598 , +2697089 , +2727769 , +2758639 , +2789698 , +2820947 , +2852386 , +2884015 , +2915834 , +2947844 , +2980045 , +3012436 , +3045019 , +3077793 , +3110758 , +3143915 , +3177264 , +3210805 , +3244538 , +3278464 , +3312582 , +3346893 , +3381396 , +3416093 , +3450984 , +3486067 , +3521345 , +3556816 , +3592481 , +3628340 , +3664394 , +3700642 , +3737085 , +3773723 , +3810556 , +3847584 , +3884808 , +3922227 , +3959842 , +3997652 , +4035659 , +4073862 , +4112262 , +4150858 , +4189651 , +4228641 , +4267827 , +4307212 , +4346793 , +4386572 , +4426549 , +4466724 , +4507096 , +4547668 , +4588437 , +4629405 , +4670572 , +4711937 , +4753502 , +4795266 , +4837229 , +4879391 , +4921754 , +}; + +/* +* index : 0 ~ 255 +* 300 is max CANDELA +* (300*((index/255)^2.15))*16384 +*/ + +int curve_2p15[] = { +0 , +33 , +146 , +349 , +648 , +1048 , +1551 , +2160 , +2878 , +3708 , +4650 , +5708 , +6882 , +8174 , +9586 , +11119 , +12774 , +14553 , +16456 , +18484 , +20639 , +22922 , +25333 , +27874 , +30545 , +33347 , +36280 , +39347 , +42547 , +45881 , +49350 , +52955 , +56696 , +60574 , +64589 , +68743 , +73035 , +77466 , +82038 , +86750 , +91603 , +96597 , +101734 , +107013 , +112435 , +118001 , +123711 , +129566 , +135565 , +141710 , +148001 , +154439 , +161023 , +167754 , +174633 , +181660 , +188836 , +196160 , +203634 , +211257 , +219031 , +226955 , +235029 , +243255 , +251633 , +260162 , +268843 , +277677 , +286665 , +295805 , +305099 , +314547 , +324149 , +333906 , +343818 , +353884 , +364107 , +374485 , +385020 , +395711 , +406559 , +417564 , +428726 , +440046 , +451523 , +463159 , +474954 , +486907 , +499020 , +511291 , +523722 , +536314 , +549065 , +561976 , +575049 , +588282 , +601676 , +615232 , +628950 , +642829 , +656871 , +671075 , +685441 , +699971 , +714663 , +729519 , +744539 , +759722 , +775070 , +790582 , +806258 , +822099 , +838105 , +854276 , +870613 , +887115 , +903784 , +920618 , +937618 , +954785 , +972119 , +989620 , +1007287 , +1025123 , +1043125 , +1061296 , +1079634 , +1098140 , +1116815 , +1135658 , +1154670 , +1173851 , +1193201 , +1212721 , +1232410 , +1252268 , +1272297 , +1292495 , +1312864 , +1333404 , +1354114 , +1374994 , +1396046 , +1417269 , +1438663 , +1460229 , +1481967 , +1503876 , +1525958 , +1548211 , +1570638 , +1593236 , +1616008 , +1638953 , +1662070 , +1685361 , +1708825 , +1732463 , +1756275 , +1780261 , +1804421 , +1828755 , +1853263 , +1877946 , +1902804 , +1927837 , +1953045 , +1978428 , +2003986 , +2029720 , +2055630 , +2081716 , +2107977 , +2134415 , +2161029 , +2187820 , +2214787 , +2241931 , +2269252 , +2296751 , +2324426 , +2352279 , +2380309 , +2408517 , +2436902 , +2465466 , +2494208 , +2523128 , +2552226 , +2581503 , +2610959 , +2640593 , +2670407 , +2700400 , +2730571 , +2760923 , +2791453 , +2822164 , +2853054 , +2884124 , +2915374 , +2946805 , +2978415 , +3010206 , +3042178 , +3074331 , +3106664 , +3139179 , +3171874 , +3204751 , +3237809 , +3271049 , +3304471 , +3338074 , +3371859 , +3405826 , +3439976 , +3474307 , +3508821 , +3543518 , +3578397 , +3613460 , +3648705 , +3684133 , +3719744 , +3755539 , +3791516 , +3827678 , +3864023 , +3900552 , +3937265 , +3974162 , +4011243 , +4048508 , +4085958 , +4123592 , +4161411 , +4199415 , +4237603 , +4275976 , +4314535 , +4353278 , +4392207 , +4431322 , +4470622 , +4510107 , +4549779 , +4589636 , +4629679 , +4669909 , +4710324 , +4750926 , +4791715 , +4832690 , +4873852 , +4915200 , +}; + +/* +* index : 0 ~ 255 +* 300 is max CANDELA +* (300*((index/255)^2.1))*16384 +*/ + +int curve_2p1[] = { +0 , +43 , +186 , +436 , +798 , +1275 , +1870 , +2585 , +3422 , +4382 , +5468 , +6679 , +8018 , +9486 , +11083 , +12811 , +14671 , +16663 , +18788 , +21047 , +23441 , +25970 , +28635 , +31437 , +34376 , +37453 , +40668 , +44022 , +47516 , +51150 , +54924 , +58839 , +62896 , +67094 , +71435 , +75919 , +80546 , +85316 , +90230 , +95289 , +100492 , +105841 , +111335 , +116974 , +122760 , +128692 , +134772 , +140998 , +147371 , +153893 , +160562 , +167380 , +174347 , +181462 , +188727 , +196141 , +203705 , +211419 , +219283 , +227298 , +235464 , +243781 , +252249 , +260869 , +269640 , +278564 , +287640 , +296868 , +306250 , +315784 , +325471 , +335312 , +345307 , +355455 , +365758 , +376214 , +386826 , +397592 , +408513 , +419589 , +430820 , +442207 , +453749 , +465448 , +477302 , +489313 , +501480 , +513804 , +526284 , +538922 , +551717 , +564669 , +577778 , +591046 , +604471 , +618054 , +631795 , +645695 , +659753 , +673970 , +688346 , +702881 , +717575 , +732428 , +747441 , +762613 , +777945 , +793438 , +809090 , +824902 , +840875 , +857008 , +873302 , +889757 , +906373 , +923150 , +940088 , +957188 , +974449 , +991872 , +1009456 , +1027203 , +1045111 , +1063182 , +1081415 , +1099810 , +1118369 , +1137089 , +1155973 , +1175020 , +1194230 , +1213603 , +1233139 , +1252839 , +1272702 , +1292730 , +1312921 , +1333276 , +1353795 , +1374478 , +1395326 , +1416338 , +1437515 , +1458856 , +1480362 , +1502034 , +1523870 , +1545871 , +1568037 , +1590369 , +1612867 , +1635530 , +1658358 , +1681353 , +1704513 , +1727839 , +1751332 , +1774991 , +1798816 , +1822807 , +1846965 , +1871290 , +1895782 , +1920440 , +1945266 , +1970258 , +1995418 , +2020744 , +2046239 , +2071900 , +2097730 , +2123727 , +2149892 , +2176224 , +2202725 , +2229393 , +2256230 , +2283235 , +2310409 , +2337751 , +2365261 , +2392940 , +2420788 , +2448804 , +2476990 , +2505344 , +2533868 , +2562561 , +2591423 , +2620454 , +2649655 , +2679026 , +2708566 , +2738276 , +2768155 , +2798205 , +2828424 , +2858814 , +2889374 , +2920104 , +2951004 , +2982075 , +3013316 , +3044728 , +3076310 , +3108064 , +3139988 , +3172083 , +3204349 , +3236786 , +3269395 , +3302174 , +3335125 , +3368247 , +3401541 , +3435007 , +3468644 , +3502453 , +3536433 , +3570586 , +3604910 , +3639407 , +3674075 , +3708916 , +3743929 , +3779115 , +3814473 , +3850003 , +3885706 , +3921582 , +3957631 , +3993852 , +4030246 , +4066813 , +4103554 , +4140467 , +4177554 , +4214813 , +4252246 , +4289853 , +4327633 , +4365587 , +4403714 , +4442015 , +4480489 , +4519138 , +4557960 , +4596957 , +4636127 , +4675472 , +4714991 , +4754684 , +4794551 , +4834593 , +4874809 , +4915200 , +}; + +int s6e63m0_candela_coeff[] = { +0 , +0 , +0 , +0 , +0 , +0 , +0 , +0 , +0 , +0 , +0 , +0 , +1 , +1 , +1 , +2 , +2 , +3 , +4 , +5 , +6 , +8 , +11 , +13 , +16 , +20 , +24 , +29 , +35 , +41 , +49 , +58 , +67 , +78 , +89 , +103 , +118 , +135 , +153 , +173 , +199 , +223 , +238 , +252 , +272 , +291 , +308 , +326 , +340 , +360 , +382 , +402 , +419 , +443 , +467 , +494 , +516 , +538 , +568 , +592 , +615 , +640 , +670 , +693 , +718 , +748 , +780 , +812 , +836 , +869 , +901 , +929 , +961 , +991 , +1025 , +1063 , +1096 , +1130 , +1164 , +1199 , +1235 , +1274 , +1316 , +1350 , +1394 , +1435 , +1473 , +1515 , +1553 , +1596 , +1640 , +1680 , +1720 , +1761 , +1806 , +1854 , +1902 , +1944 , +1992 , +2042 , +2087 , +2141 , +2188 , +2236 , +2291 , +2339 , +2388 , +2437 , +2488 , +2538 , +2590 , +2645 , +2699 , +2759 , +2815 , +2867 , +2924 , +2982 , +3036 , +3095 , +3158 , +3220 , +3283 , +3341 , +3403 , +3468 , +3534 , +3592 , +3659 , +3722 , +3785 , +3857 , +3922 , +3987 , +4053 , +4120 , +4188 , +4260 , +4329 , +4405 , +4478 , +4551 , +4625 , +4695 , +4769 , +4844 , +4916 , +4989 , +5062 , +5135 , +5206 , +5282 , +5366 , +5445 , +5522 , +5604 , +5686 , +5764 , +5844 , +5923 , +6004 , +6085 , +6167 , +6249 , +6332 , +6419 , +6505 , +6593 , +6680 , +6764 , +6854 , +6943 , +7030 , +7113 , +7196 , +7284 , +7379 , +7472 , +7566 , +7660 , +7752 , +7847 , +7943 , +8036 , +8130 , +8224 , +8319 , +8416 , +8514 , +8618 , +8719 , +8815 , +8916 , +9019 , +9117 , +9216 , +9316 , +9421 , +9530 , +9637 , +9742 , +9853 , +9962 , +10066 , +10173 , +10284 , +10391 , +10500 , +10610 , +10721 , +10831 , +10937 , +11050 , +11161 , +11268 , +11375 , +11495 , +11610 , +11724 , +11840 , +11956 , +12073 , +12183 , +12300 , +12420 , +12540 , +12665 , +12786 , +12907 , +13028 , +13149 , +13271 , +13394 , +13521 , +13644 , +13770 , +13894 , +14021 , +14147 , +14271 , +14395 , +14527 , +14661 , +14795 , +14930 , +15066 , +15199 , +15331 , +15465 , +15596 , +15727 , +15859 , +15991 , +16124 , +16258 , +16384 , +}; + +int s6e63m0_curve_2p2[] = { +0 , +1 , +3 , +7 , +12 , +20 , +30 , +43 , +57 , +74 , +94 , +116 , +181 , +261 , +357 , +470 , +638 , +873 , +1149 , +1505 , +1948 , +2462 , +3187 , +4014 , +4947 , +5998 , +7322 , +8790 , +10406 , +12406 , +14785 , +17393 , +20233 , +23309 , +26624 , +30843 , +35530 , +40580 , +45998 , +51943 , +59567 , +66992 , +71281 , +75715 , +81627 , +87360 , +92307 , +97789 , +101994 , +107916 , +114544 , +120609 , +125563 , +132753 , +139989 , +148171 , +154830 , +161459 , +170491 , +177474 , +184610 , +191900 , +200851 , +208025 , +215268 , +224525 , +233995 , +243502 , +250903 , +260832 , +270407 , +278624 , +288448 , +297172 , +307582 , +318888 , +328847 , +338973 , +349266 , +359728 , +370358 , +382346 , +394839 , +405107 , +418139 , +430542 , +442024 , +454514 , +466020 , +478816 , +491918 , +503929 , +516097 , +528425 , +541772 , +556091 , +570614 , +583274 , +597584 , +612685 , +626209 , +642334 , +656324 , +670784 , +687212 , +701724 , +716402 , +731246 , +746256 , +761433 , +776925 , +793649 , +809625 , +827588 , +844406 , +860145 , +877239 , +894489 , +910729 , +928472 , +947330 , +966066 , +985002 , +1002167 , +1020903 , +1040415 , +1060129 , +1077595 , +1097643 , +1116505 , +1135562 , +1157162 , +1176573 , +1196160 , +1215924 , +1235865 , +1256295 , +1278087 , +1298760 , +1321576 , +1343524 , +1365222 , +1387352 , +1408362 , +1430792 , +1453323 , +1474871 , +1496592 , +1518486 , +1540554 , +1561718 , +1584466 , +1609667 , +1633642 , +1656693 , +1681320 , +1705704 , +1729303 , +1753078 , +1777031 , +1801161 , +1825469 , +1849954 , +1874618 , +1899643 , +1925558 , +1951427 , +1977817 , +2003972 , +2029340 , +2056321 , +2083012 , +2108920 , +2133761 , +2158798 , +2185215 , +2213663 , +2241712 , +2269787 , +2298149 , +2325479 , +2354122 , +2383050 , +2410925 , +2438977 , +2467207 , +2495613 , +2524928 , +2554282 , +2585355 , +2615560 , +2644608 , +2674730 , +2705583 , +2735171 , +2764934 , +2794872 , +2826365 , +2859063 , +2891124 , +2922619 , +2955919 , +2988470 , +3019761 , +3052021 , +3085226 , +3117156 , +3150042 , +3183115 , +3216377 , +3249187 , +3281038 , +3314853 , +3348429 , +3380335 , +3412468 , +3448603 , +3482883 , +3517348 , +3551998 , +3586833 , +3621854 , +3654959 , +3690035 , +3725943 , +3761880 , +3799549 , +3835852 , +3871969 , +3908271 , +3944757 , +3981429 , +4018286 , +4056410 , +4093256 , +4130995 , +4168337 , +4206323 , +4244164 , +4281201 , +4318413 , +4358189 , +4398275 , +4438561 , +4479048 , +4519735 , +4559566 , +4599306 , +4639620 , +4678786 , +4718131 , +4757656 , +4797361 , +4837246 , +4877311 , +4915200 , +}; +#endif /* START_MTP_2P2_GAMMA_H */ diff --git a/drivers/video/msm/smart_mtp_s6e8aa0x01.c b/drivers/video/msm/smart_mtp_s6e8aa0x01.c new file mode 100644 index 00000000000..da014fdf0bd --- /dev/null +++ b/drivers/video/msm/smart_mtp_s6e8aa0x01.c @@ -0,0 +1,1592 @@ +/* + * ================================================================= + * + * Filename: smart_mtp_s6e8aa0x01.c + * + * Description: Smart dimming algorithm implementation + * + * Author: jb09.kim + * Company: Samsung Electronics + * + * ================================================================ + */ +/* + +Copyright (C) 2012, Samsung Electronics. All rights reserved. + +* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * +*/ + +#include "smart_mtp_s6e8aa0x01.h" +#include "smart_mtp_2p2_gamma.h" + +/* +#define SMART_DIMMING_DEBUG +*/ + +static char max_lux_table[GAMMA_SET_MAX]; +static char min_lux_table[GAMMA_SET_MAX]; + +/* +* To support different center cell gamma setting +*/ +static char V1_300CD_R; +static char V1_300CD_G; +static char V1_300CD_B; + +static char V15_300CD_R; +static char V15_300CD_G; +static char V15_300CD_B; + +static char V35_300CD_R; +static char V35_300CD_G; +static char V35_300CD_B; + +static char V59_300CD_R; +static char V59_300CD_G; +static char V59_300CD_B; + +static char V87_300CD_R; +static char V87_300CD_G; +static char V87_300CD_B; + +static char V171_300CD_R; +static char V171_300CD_G; +static char V171_300CD_B; + +static char V255_300CD_R_MSB; +static char V255_300CD_R_LSB; + +static char V255_300CD_G_MSB; +static char V255_300CD_G_LSB; + +static char V255_300CD_B_MSB; +static char V255_300CD_B_LSB; + +static int char_to_int(char data1) +{ + int cal_data; + + if (data1 & 0x80) + cal_data = 0xffffff00 | data1; + else + cal_data = data1; + + return cal_data; +} + +#define v255_coefficient 100 +#define v255_denominator 600 +static int v255_adjustment(struct SMART_DIM *pSmart) +{ + unsigned long long result_1, result_2, result_3, result_4; + int add_mtp; + int LSB; + int v255_value; + + v255_value = (V255_300CD_R_MSB << 8) | (V255_300CD_R_LSB); + LSB = char_to_int(pSmart->MTP.R_OFFSET.OFFSET_255_LSB); + add_mtp = LSB + v255_value; + result_1 = result_2 = (v255_coefficient+add_mtp) << BIT_SHIFT; + do_div(result_2, v255_denominator); + result_3 = (S6E8AA0X01_VREG0_REF * result_2) >> BIT_SHIFT; + result_4 = S6E8AA0X01_VREG0_REF - result_3; + pSmart->RGB_OUTPUT.R_VOLTAGE.level_255 = result_4; + pSmart->RGB_OUTPUT.R_VOLTAGE.level_0 = S6E8AA0X01_VREG0_REF; + + v255_value = (V255_300CD_G_MSB << 8) | (V255_300CD_G_LSB); + LSB = char_to_int(pSmart->MTP.G_OFFSET.OFFSET_255_LSB); + add_mtp = LSB + v255_value; + result_1 = result_2 = (v255_coefficient+add_mtp) << BIT_SHIFT; + do_div(result_2, v255_denominator); + result_3 = (S6E8AA0X01_VREG0_REF * result_2) >> BIT_SHIFT; + result_4 = S6E8AA0X01_VREG0_REF - result_3; + pSmart->RGB_OUTPUT.G_VOLTAGE.level_255 = result_4; + pSmart->RGB_OUTPUT.G_VOLTAGE.level_0 = S6E8AA0X01_VREG0_REF; + + v255_value = (V255_300CD_B_MSB << 8) | (V255_300CD_B_LSB); + LSB = char_to_int(pSmart->MTP.B_OFFSET.OFFSET_255_LSB); + add_mtp = LSB + v255_value; + result_1 = result_2 = (v255_coefficient+add_mtp) << BIT_SHIFT; + do_div(result_2, v255_denominator); + result_3 = (S6E8AA0X01_VREG0_REF * result_2) >> BIT_SHIFT; + result_4 = S6E8AA0X01_VREG0_REF - result_3; + pSmart->RGB_OUTPUT.B_VOLTAGE.level_255 = result_4; + pSmart->RGB_OUTPUT.B_VOLTAGE.level_0 = S6E8AA0X01_VREG0_REF; + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s V255 RED:%d GREEN:%d BLUE:%d\n", __func__, + pSmart->RGB_OUTPUT.R_VOLTAGE.level_255, + pSmart->RGB_OUTPUT.G_VOLTAGE.level_255, + pSmart->RGB_OUTPUT.B_VOLTAGE.level_255); +#endif + + return 0; +} + +static void v255_hexa(int *index, struct SMART_DIM *pSmart, char *str) +{ + unsigned long long result_1, result_2, result_3; + + result_1 = S6E8AA0X01_VREG0_REF - + (pSmart->GRAY.TABLE[index[V255_INDEX]].R_Gray); + + result_2 = result_1 * v255_denominator; + do_div(result_2, S6E8AA0X01_VREG0_REF); + result_3 = result_2 - v255_coefficient; + str[18] = (result_3 & 0xff00) >> 8; + str[19] = result_3 & 0xff; + + result_1 = S6E8AA0X01_VREG0_REF - + (pSmart->GRAY.TABLE[index[V255_INDEX]].G_Gray); + result_2 = result_1 * v255_denominator; + do_div(result_2, S6E8AA0X01_VREG0_REF); + result_3 = result_2 - v255_coefficient; + str[20] = (result_3 & 0xff00) >> 8; + str[21] = result_3 & 0xff; + + result_1 = S6E8AA0X01_VREG0_REF - + (pSmart->GRAY.TABLE[index[V255_INDEX]].B_Gray); + result_2 = result_1 * v255_denominator; + do_div(result_2, S6E8AA0X01_VREG0_REF); + result_3 = result_2 - v255_coefficient; + str[22] = (result_3 & 0xff00) >> 8; + str[23] = result_3 & 0xff; + +} + +#define v1_coefficient 5 +#define v1_denominator 600 +static int v1_adjustment(struct SMART_DIM *pSmart) +{ + unsigned long long result_1, result_2, result_3, result_4; + int add_mtp; + int LSB; + + LSB = char_to_int(pSmart->MTP.R_OFFSET.OFFSET_1); + add_mtp = LSB + V1_300CD_R; + result_1 = result_2 = (v1_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v1_denominator); + result_3 = (S6E8AA0X01_VREG0_REF * result_2) >> BIT_SHIFT; + result_4 = S6E8AA0X01_VREG0_REF - result_3; + pSmart->RGB_OUTPUT.R_VOLTAGE.level_1 = result_4; + + LSB = char_to_int(pSmart->MTP.G_OFFSET.OFFSET_1); + add_mtp = LSB + V1_300CD_G; + result_1 = result_2 = (v1_coefficient+add_mtp) << BIT_SHIFT; + do_div(result_2, v1_denominator); + result_3 = (S6E8AA0X01_VREG0_REF * result_2) >> BIT_SHIFT; + result_4 = S6E8AA0X01_VREG0_REF - result_3; + pSmart->RGB_OUTPUT.G_VOLTAGE.level_1 = result_4; + + LSB = char_to_int(pSmart->MTP.B_OFFSET.OFFSET_1); + add_mtp = LSB + V1_300CD_B; + result_1 = result_2 = (v1_coefficient+add_mtp) << BIT_SHIFT; + do_div(result_2, v1_denominator); + result_3 = (S6E8AA0X01_VREG0_REF * result_2) >> BIT_SHIFT; + result_4 = S6E8AA0X01_VREG0_REF - result_3; + pSmart->RGB_OUTPUT.B_VOLTAGE.level_1 = result_4; + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s V1 RED:%d GREEN:%d BLUE:%d\n", __func__, + pSmart->RGB_OUTPUT.R_VOLTAGE.level_1, + pSmart->RGB_OUTPUT.G_VOLTAGE.level_1, + pSmart->RGB_OUTPUT.B_VOLTAGE.level_1); +#endif + + return 0; + +} + +static void v1_hexa(int *index, struct SMART_DIM *pSmart, char *str) +{ + str[0] = pSmart->MTP.R_OFFSET.OFFSET_1 + V1_300CD_R; + str[1] = pSmart->MTP.G_OFFSET.OFFSET_1 + V1_300CD_G; + str[2] = pSmart->MTP.B_OFFSET.OFFSET_1 + V1_300CD_B; +} + + +#define v171_coefficient 65 +#define v171_denominator 320 +static int v171_adjustment(struct SMART_DIM *pSmart) +{ + unsigned long long result_1, result_2, result_3, result_4; + int add_mtp; + int LSB; + + LSB = char_to_int(pSmart->MTP.R_OFFSET.OFFSET_171); + add_mtp = LSB + V171_300CD_R; + result_1 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.R_VOLTAGE.level_255); + result_2 = (v171_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v171_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.R_VOLTAGE.level_171 = result_4; + + LSB = char_to_int(pSmart->MTP.G_OFFSET.OFFSET_171); + add_mtp = LSB + V171_300CD_G; + result_1 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.G_VOLTAGE.level_255); + result_2 = (v171_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v171_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.G_VOLTAGE.level_171 = result_4; + + LSB = char_to_int(pSmart->MTP.B_OFFSET.OFFSET_171); + add_mtp = LSB + V171_300CD_B; + result_1 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.B_VOLTAGE.level_255); + result_2 = (v171_coefficient+add_mtp) << BIT_SHIFT; + do_div(result_2, v171_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.B_VOLTAGE.level_171 = result_4; + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s V171 RED:%d GREEN:%d BLUE:%d\n", __func__, + pSmart->RGB_OUTPUT.R_VOLTAGE.level_171, + pSmart->RGB_OUTPUT.G_VOLTAGE.level_171, + pSmart->RGB_OUTPUT.B_VOLTAGE.level_171); +#endif + + return 0; + +} + +static void v171_hexa(int *index, struct SMART_DIM *pSmart, char *str) +{ + unsigned long long result_1, result_2, result_3; + + result_1 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V171_INDEX]].R_Gray); + result_2 = result_1 * v171_denominator; + result_3 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V255_INDEX]].R_Gray); + do_div(result_2, result_3); + str[15] = (result_2 - v171_coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V171_INDEX]].G_Gray); + result_2 = result_1 * v171_denominator; + result_3 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V255_INDEX]].G_Gray); + do_div(result_2, result_3); + str[16] = (result_2 - v171_coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V171_INDEX]].B_Gray); + result_2 = result_1 * v171_denominator; + result_3 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V255_INDEX]].B_Gray); + do_div(result_2, result_3); + str[17] = (result_2 - v171_coefficient) & 0xff; + +} + + +#define v87_coefficient 65 +#define v87_denominator 320 +static int v87_adjustment(struct SMART_DIM *pSmart) +{ + unsigned long long result_1, result_2, result_3, result_4; + int add_mtp; + int LSB; + + LSB = char_to_int(pSmart->MTP.R_OFFSET.OFFSET_87); + add_mtp = LSB + V87_300CD_R; + result_1 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.R_VOLTAGE.level_171); + result_2 = (v87_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v87_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.R_VOLTAGE.level_87 = result_4; + + LSB = char_to_int(pSmart->MTP.G_OFFSET.OFFSET_87); + add_mtp = LSB + V87_300CD_G; + result_1 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.G_VOLTAGE.level_171); + result_2 = (v87_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v87_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.G_VOLTAGE.level_87 = result_4; + + LSB = char_to_int(pSmart->MTP.B_OFFSET.OFFSET_87); + add_mtp = LSB + V87_300CD_B; + result_1 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.B_VOLTAGE.level_171); + result_2 = (v87_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v87_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.B_VOLTAGE.level_87 = result_4; + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s V87 RED:%d GREEN:%d BLUE:%d\n", __func__, + pSmart->RGB_OUTPUT.R_VOLTAGE.level_87, + pSmart->RGB_OUTPUT.G_VOLTAGE.level_87, + pSmart->RGB_OUTPUT.B_VOLTAGE.level_87); +#endif + + return 0; + +} + +static void v87_hexa(int *index, struct SMART_DIM *pSmart, char *str) +{ + unsigned long long result_1, result_2, result_3; + + result_1 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V87_INDEX]].R_Gray); + result_2 = result_1 * v87_denominator; + result_3 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V171_INDEX]].R_Gray); + do_div(result_2, result_3); + str[12] = (result_2 - v87_coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V87_INDEX]].G_Gray); + result_2 = result_1 * v87_denominator; + result_3 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V171_INDEX]].G_Gray); + do_div(result_2, result_3); + str[13] = (result_2 - v87_coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V87_INDEX]].B_Gray); + result_2 = result_1 * v87_denominator; + result_3 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V171_INDEX]].B_Gray); + do_div(result_2, result_3); + str[14] = (result_2 - v87_coefficient) & 0xff; +} + + +#define v59_coefficient 65 +#define v59_denominator 320 +static int v59_adjustment(struct SMART_DIM *pSmart) +{ + unsigned long long result_1, result_2, result_3, result_4; + int add_mtp; + int LSB; + + LSB = char_to_int(pSmart->MTP.R_OFFSET.OFFSET_59); + add_mtp = LSB + V59_300CD_R; + result_1 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.R_VOLTAGE.level_87); + result_2 = (v59_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v59_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.R_VOLTAGE.level_59 = result_4; + + LSB = char_to_int(pSmart->MTP.G_OFFSET.OFFSET_59); + add_mtp = LSB + V59_300CD_G; + result_1 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.G_VOLTAGE.level_87); + result_2 = (v59_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v59_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.G_VOLTAGE.level_59 = result_4; + + LSB = char_to_int(pSmart->MTP.B_OFFSET.OFFSET_59); + add_mtp = LSB + V59_300CD_B; + result_1 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.B_VOLTAGE.level_87); + result_2 = (v59_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v59_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.B_VOLTAGE.level_59 = result_4; + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s V59 RED:%d GREEN:%d BLUE:%d\n", __func__, + pSmart->RGB_OUTPUT.R_VOLTAGE.level_59, + pSmart->RGB_OUTPUT.G_VOLTAGE.level_59, + pSmart->RGB_OUTPUT.B_VOLTAGE.level_59); +#endif + + return 0; + +} + + +static void v59_hexa(int *index, struct SMART_DIM *pSmart, char *str) +{ + unsigned long long result_1, result_2, result_3; + + result_1 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V59_INDEX]].R_Gray); + result_2 = result_1 * v59_denominator; + result_3 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V87_INDEX]].R_Gray); + do_div(result_2, result_3); + str[9] = (result_2 - v59_coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V59_INDEX]].G_Gray); + result_2 = result_1 * v59_denominator; + result_3 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V87_INDEX]].G_Gray); + do_div(result_2, result_3); + str[10] = (result_2 - v59_coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V59_INDEX]].B_Gray); + result_2 = result_1 * v59_denominator; + result_3 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V87_INDEX]].B_Gray); + do_div(result_2, result_3); + str[11] = (result_2 - v59_coefficient) & 0xff; + +} + + +#define v35_coefficient 65 +#define v35_denominator 320 +static int v35_adjustment(struct SMART_DIM *pSmart) +{ + unsigned long long result_1, result_2, result_3, result_4; + int add_mtp; + int LSB; + + LSB = char_to_int(pSmart->MTP.R_OFFSET.OFFSET_35); + add_mtp = LSB + V35_300CD_R; + result_1 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.R_VOLTAGE.level_59); + result_2 = (v35_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v35_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.R_VOLTAGE.level_35 = result_4; + + LSB = char_to_int(pSmart->MTP.G_OFFSET.OFFSET_35); + add_mtp = LSB + V35_300CD_G; + result_1 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.G_VOLTAGE.level_59); + result_2 = (v35_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v35_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.G_VOLTAGE.level_35 = result_4; + + LSB = char_to_int(pSmart->MTP.B_OFFSET.OFFSET_35); + add_mtp = LSB + V35_300CD_B; + result_1 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.B_VOLTAGE.level_59); + result_2 = (v35_coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v35_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.B_VOLTAGE.level_35 = result_4; + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s V35 RED:%d GREEN:%d BLUE:%d\n", __func__, + pSmart->RGB_OUTPUT.R_VOLTAGE.level_35, + pSmart->RGB_OUTPUT.G_VOLTAGE.level_35, + pSmart->RGB_OUTPUT.B_VOLTAGE.level_35); +#endif + + return 0; + +} + +static void v35_hexa(int *index, struct SMART_DIM *pSmart, char *str) +{ + unsigned long long result_1, result_2, result_3; + + result_1 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V35_INDEX]].R_Gray); + result_2 = result_1 * v35_denominator; + result_3 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V59_INDEX]].R_Gray); + do_div(result_2, result_3); + str[6] = (result_2 - v35_coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V35_INDEX]].G_Gray); + result_2 = result_1 * v35_denominator; + result_3 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V59_INDEX]].G_Gray); + do_div(result_2, result_3); + str[7] = (result_2 - v35_coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V35_INDEX]].B_Gray); + result_2 = result_1 * v35_denominator; + result_3 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V59_INDEX]].B_Gray); + do_div(result_2, result_3); + str[8] = (result_2 - v35_coefficient) & 0xff; + +} + +#define v15_Coefficient 20 +#define v15_denominator 320 +static int v15_adjustment(struct SMART_DIM *pSmart) +{ + unsigned long long result_1, result_2, result_3, result_4; + int add_mtp; + int LSB; + + LSB = char_to_int(pSmart->MTP.R_OFFSET.OFFSET_15); + add_mtp = LSB + V15_300CD_R; + result_1 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.R_VOLTAGE.level_35); + result_2 = (v15_Coefficient+add_mtp) << BIT_SHIFT; + do_div(result_2, v15_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.R_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.R_VOLTAGE.level_15 = result_4; + + LSB = char_to_int(pSmart->MTP.G_OFFSET.OFFSET_15); + add_mtp = LSB + V15_300CD_G; + result_1 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.G_VOLTAGE.level_35); + result_2 = (v15_Coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v15_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.G_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.G_VOLTAGE.level_15 = result_4; + + LSB = char_to_int(pSmart->MTP.B_OFFSET.OFFSET_15); + add_mtp = LSB + V15_300CD_B; + result_1 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) + - (pSmart->RGB_OUTPUT.B_VOLTAGE.level_35); + result_2 = (v15_Coefficient + add_mtp) << BIT_SHIFT; + do_div(result_2, v15_denominator); + result_3 = (result_1 * result_2) >> BIT_SHIFT; + result_4 = (pSmart->RGB_OUTPUT.B_VOLTAGE.level_1) - result_3; + pSmart->RGB_OUTPUT.B_VOLTAGE.level_15 = result_4; + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s V15 RED:%d GREEN:%d BLUE:%d\n", __func__, + pSmart->RGB_OUTPUT.R_VOLTAGE.level_15, + pSmart->RGB_OUTPUT.G_VOLTAGE.level_15, + pSmart->RGB_OUTPUT.B_VOLTAGE.level_15); +#endif + + return 0; + +} + +static void v15_hexa(int *index, struct SMART_DIM *pSmart, char *str) +{ + unsigned long long result_1, result_2, result_3; + + result_1 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V15_INDEX]].R_Gray); + result_2 = result_1 * v15_denominator; + result_3 = (pSmart->GRAY.TABLE[1].R_Gray) + - (pSmart->GRAY.TABLE[index[V35_INDEX]].R_Gray); + do_div(result_2, result_3); + str[3] = (result_2 - v15_Coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V15_INDEX]].G_Gray); + result_2 = result_1 * v15_denominator; + result_3 = (pSmart->GRAY.TABLE[1].G_Gray) + - (pSmart->GRAY.TABLE[index[V35_INDEX]].G_Gray); + do_div(result_2, result_3); + str[4] = (result_2 - v15_Coefficient) & 0xff; + + result_1 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V15_INDEX]].B_Gray); + result_2 = result_1 * v15_denominator; + result_3 = (pSmart->GRAY.TABLE[1].B_Gray) + - (pSmart->GRAY.TABLE[index[V35_INDEX]].B_Gray); + do_div(result_2, result_3); + str[5] = (result_2 - v15_Coefficient) & 0xff; +} + + + +/*V0, V1,V15,V35,V59,V87,V171,V255*/ +int S6E8AA0X01_ARRAY[S6E8AA0X01_MAX] = {0, 1, 15, 35, 59, 87, 171, 255}; + +int non_linear_V1toV15[] = { +47, 42, 37, 32, 27, +23, 19, 15, 12, 9, +6, 4, 2 +}; +#define V1toV15_denominator 52 + +int non_linear_V15toV35[] = { +66, 62, 58, 54, 50, +46, 42, 38, 34, 30, +27, 24, 21, 18, 15, +12, 9, 6, 3, +}; +#define V15toV35_denominator 70 + +#define V35toV59_Coefficient 23 +#define V35toV59_Multiple 1 +#define V35toV59_denominator 24 + +#define V59toV87_Coefficient 27 +#define V59toV87_Multiple 1 +#define V59toV87_denominator 28 + +#define V87toV171_Coefficient 83 +#define V87toV171_Multiple 1 +#define V87toV171_denominator 84 + +#define V171toV255_Coefficient 83 +#define V171toV255_Multiple 1 +#define V171toV255_denominator 84 + +static int cal_gray_scale_linear(int up, int low, int coeff, +int mul, int deno, int cnt) +{ + unsigned long long result_1, result_2, result_3, result_4; + + result_1 = up - low; + result_2 = (result_1 * (coeff - (cnt * mul))) << BIT_SHIFT; + do_div(result_2, deno); + result_3 = result_2 >> BIT_SHIFT; + result_4 = low + result_3; + + return (int)result_4; +} + +static int cal_gray_scale_non_linear(int up, int low, +int *table, int deno, int cnt) +{ + unsigned long long result_1, result_2, result_3, result_4; + + result_1 = up - low; + result_2 = (result_1 * (table[cnt])) << BIT_SHIFT; + do_div(result_2, deno); + result_3 = result_2 >> BIT_SHIFT; + result_4 = low + result_3; + + return (int)result_4; +} + + +static int generate_gray_scale(struct SMART_DIM *pSmart) +{ + int cnt = 0, cal_cnt = 0; + int array_index = 0; + struct GRAY_VOLTAGE *ptable = (struct GRAY_VOLTAGE *) + (&(pSmart->GRAY.TABLE)); + + for (cnt = 0; cnt < S6E8AA0X01_MAX; cnt++) { + pSmart->GRAY.TABLE[S6E8AA0X01_ARRAY[cnt]].R_Gray = + ((int *)&(pSmart->RGB_OUTPUT.R_VOLTAGE))[cnt]; + + pSmart->GRAY.TABLE[S6E8AA0X01_ARRAY[cnt]].G_Gray = + ((int *)&(pSmart->RGB_OUTPUT.G_VOLTAGE))[cnt]; + + pSmart->GRAY.TABLE[S6E8AA0X01_ARRAY[cnt]].B_Gray = + ((int *)&(pSmart->RGB_OUTPUT.B_VOLTAGE))[cnt]; + } + + /* + below codes use hard coded value. + So it is possible to modify on each model. + V0, V1, V15, V35, V59, V87, V171, V255 + */ + for (cnt = 0; cnt < S6E8AA0X01_GRAY_SCALE_MAX; cnt++) { + + if (cnt == S6E8AA0X01_ARRAY[0]) { + /* 0 */ + array_index = 0; + } else if (cnt == S6E8AA0X01_ARRAY[1]) { + /* 1 */ + cal_cnt = 0; + } else if ((cnt > S6E8AA0X01_ARRAY[1]) && + (cnt < S6E8AA0X01_ARRAY[2])) { + /* 2 ~ 14 */ + array_index = 2; + + pSmart->GRAY.TABLE[cnt].R_Gray = + cal_gray_scale_non_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].R_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].R_Gray, + non_linear_V1toV15, V1toV15_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].G_Gray = + cal_gray_scale_non_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].G_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].G_Gray, + non_linear_V1toV15, V1toV15_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].B_Gray = + cal_gray_scale_non_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].B_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].B_Gray, + non_linear_V1toV15, V1toV15_denominator, cal_cnt); + + cal_cnt++; + } else if (cnt == S6E8AA0X01_ARRAY[2]) { + /* 15 */ + cal_cnt = 0; + } else if ((cnt > S6E8AA0X01_ARRAY[2]) && + (cnt < S6E8AA0X01_ARRAY[3])) { + /* 16 ~ 34 */ + array_index = 3; + + pSmart->GRAY.TABLE[cnt].R_Gray = + cal_gray_scale_non_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].R_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].R_Gray, + non_linear_V15toV35, V15toV35_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].G_Gray = + cal_gray_scale_non_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].G_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].G_Gray, + non_linear_V15toV35, V15toV35_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].B_Gray = + cal_gray_scale_non_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].B_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].B_Gray, + non_linear_V15toV35, V15toV35_denominator, cal_cnt); + + cal_cnt++; + } else if (cnt == S6E8AA0X01_ARRAY[3]) { + /* 35 */ + cal_cnt = 0; + } else if ((cnt > S6E8AA0X01_ARRAY[3]) && + (cnt < S6E8AA0X01_ARRAY[4])) { + /* 35 ~ 58 */ + array_index = 4; + + pSmart->GRAY.TABLE[cnt].R_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].R_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].R_Gray, + V35toV59_Coefficient, V35toV59_Multiple, + V35toV59_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].G_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].G_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].G_Gray, + V35toV59_Coefficient, V35toV59_Multiple, + V35toV59_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].B_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].B_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].B_Gray, + V35toV59_Coefficient, V35toV59_Multiple, + V35toV59_denominator , cal_cnt); + + cal_cnt++; + } else if (cnt == S6E8AA0X01_ARRAY[4]) { + /* 59 */ + cal_cnt = 0; + } else if ((cnt > S6E8AA0X01_ARRAY[4]) && + (cnt < S6E8AA0X01_ARRAY[5])) { + /* 60 ~ 86 */ + array_index = 5; + + pSmart->GRAY.TABLE[cnt].R_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].R_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].R_Gray, + V59toV87_Coefficient, V59toV87_Multiple, + V59toV87_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].G_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].G_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].G_Gray, + V59toV87_Coefficient, V59toV87_Multiple, + V59toV87_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].B_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].B_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].B_Gray, + V59toV87_Coefficient, V59toV87_Multiple, + V59toV87_denominator, cal_cnt); + cal_cnt++; + + } else if (cnt == S6E8AA0X01_ARRAY[5]) { + /* 87 */ + cal_cnt = 0; + } else if ((cnt > S6E8AA0X01_ARRAY[5]) && + (cnt < S6E8AA0X01_ARRAY[6])) { + /* 88 ~ 170 */ + array_index = 6; + + pSmart->GRAY.TABLE[cnt].R_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].R_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].R_Gray, + V87toV171_Coefficient, V87toV171_Multiple, + V87toV171_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].G_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].G_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].G_Gray, + V87toV171_Coefficient, V87toV171_Multiple, + V87toV171_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].B_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].B_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].B_Gray, + V87toV171_Coefficient, V87toV171_Multiple, + V87toV171_denominator, cal_cnt); + cal_cnt++; + + } else if (cnt == S6E8AA0X01_ARRAY[6]) { + /* 171 */ + cal_cnt = 0; + } else if ((cnt > S6E8AA0X01_ARRAY[6]) && + (cnt < S6E8AA0X01_ARRAY[7])) { + /* 172 ~ 254 */ + array_index = 7; + + pSmart->GRAY.TABLE[cnt].R_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].R_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].R_Gray, + V171toV255_Coefficient, V171toV255_Multiple, + V171toV255_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].G_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].G_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].G_Gray, + V171toV255_Coefficient, V171toV255_Multiple, + V171toV255_denominator, cal_cnt); + + pSmart->GRAY.TABLE[cnt].B_Gray = cal_gray_scale_linear( + ptable[S6E8AA0X01_ARRAY[array_index-1]].B_Gray, + ptable[S6E8AA0X01_ARRAY[array_index]].B_Gray, + V171toV255_Coefficient, V171toV255_Multiple, + V171toV255_denominator, cal_cnt); + + cal_cnt++; + } else { + if (cnt == S6E8AA0X01_ARRAY[7]) { + pr_info("%s end\n", __func__); + } else { + pr_err("%s fail cnt:%d\n", __func__, cnt); + return -1; + } + } + + } + +#ifdef SMART_DIMMING_DEBUG + for (cnt = 0; cnt < S6E8AA0X01_GRAY_SCALE_MAX; cnt++) { + pr_info("%s %d R:%d G:%d B:%d\n", __func__, cnt, + pSmart->GRAY.TABLE[cnt].R_Gray, + pSmart->GRAY.TABLE[cnt].G_Gray, + pSmart->GRAY.TABLE[cnt].B_Gray); + } +#endif + + return 0; +} + +/* +* Because of AID operation & display quality. +* Three type of gamma curve is used. +* gamma_curve_change_point is changing point illumination. +* 300CD ~ 260CD use 2.2 gamma curve +* 250CD ~ 190CD use 2.15 gamma curve +* below 190CD use 2.1 gamma curve +* +* only smart dimmg range : 300CD ~ 190CD +* AOR fix range : 180CD ~ 110CD +* AOR adjust range : 100CD ~ 20CD +*/ +#define GAMMA_CURVE_2P2 1 +#define GAMMA_CURVE_2P15 2 +#define GAMMA_CURVE_2P1 3 +#define AOR_FIX_CD 180 +#define AOR_ADJUST_CD 110 +#define AOR_MUL_COFF 23720 /* 1.4477381 * 16384 */ +#define AOR_ADD_COFF 190718 /* 11.6404762 * 16384 */ +#define AOR_ADD_COMPENSATION 1 + +static int translate_table_188_to182[4] = {250, 234, 214, 201}; +static int gamma_curve_change_point[3] = {300, 260, 190}; +static int aid_compensation_cd[4] = {300, 190, 180, 110}; + +static int searching_function(long long candela, int *index, int gamma_curve) +{ + long long delta_1 = 0, delta_2 = 0; + int cnt; + + /* + * This searching_functin should be changed with improved + searcing algorithm to reduce searching time. + */ + *index = -1; + + for (cnt = 0; cnt < (S6E8AA0X01_GRAY_SCALE_MAX-1); cnt++) { + if (gamma_curve == GAMMA_CURVE_2P2) { + delta_1 = candela - curve_2p2[cnt]; + delta_2 = candela - curve_2p2[cnt+1]; + } else if (gamma_curve == GAMMA_CURVE_2P15) { + delta_1 = candela - curve_2p15[cnt]; + delta_2 = candela - curve_2p15[cnt+1]; + } else { + delta_1 = candela - curve_2p1[cnt]; + delta_2 = candela - curve_2p1[cnt+1]; + } + + if (delta_2 < 0) { + *index = (delta_1 + delta_2) <= 0 ? cnt : cnt+1; + break; + } + + if (delta_1 == 0) { + *index = cnt; + break; + } + + if (delta_2 == 0) { + *index = cnt+1; + break; + } + } + + if (*index == -1) + return -1; + else + return 0; +} + + +/* -1 means V1 */ +#define S6E8AA0X01_TABLE_MAX (S6E8AA0X01_MAX-1) +void(*Make_hexa[S6E8AA0X01_TABLE_MAX])(int*, struct SMART_DIM*, char*) = { + v255_hexa, + v171_hexa, + v87_hexa, + v59_hexa, + v35_hexa, + v15_hexa, + v1_hexa +}; + + +#ifdef AID_OPERATION_4_8_INCH +#if defined(AID_CASE_1) +static int below_110cd_v15_adding[9][4] = { +/* CD R G B */ + {20, -33, -53, 62}, + {30, -44, -53, 32}, + {40, -44, -53, 14}, + {50, -44, -53, 0}, + {60, -27, -32, 0}, + {70, -17, -20, 0}, + {80, -10, -12, 0}, + {90, -6, -7, 0}, + {100, -2, -3, 0}, +}; + +static int below_110cd_v35_adding[9][4] = { +/* CD R G B */ + {20, -15, -12, 0}, + {30, 0, 0, 0}, + {40, 0, 0, 0}, + {50, 0, 0, 0}, + {60, 0, 0, 0}, + {70, 0, 0, 0}, + {80, 0, 0, 0}, + {90, 0, 0, 0}, + {100, 0, 0, 0}, +}; + +static void gamma_init(struct SMART_DIM *pSmart, char *str, int size) +{ + long long candela_level[S6E8AA0X01_TABLE_MAX] = {-1, }; + int bl_index[S6E8AA0X01_TABLE_MAX] = {-1, }; + + long long temp_cal_data = 0; + int bl_level, cnt; + int level_255_temp = 0; + int level_255_temp_MSB = 0; + int point_index; + unsigned int aid_bl_level; + int index; + + bl_level = pSmart->brightness_level; + + /*calculate candela level */ + if (bl_level >= gamma_curve_change_point[1]) { + /* upper 260CD */ + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) { + point_index = S6E8AA0X01_ARRAY[cnt+1]; + temp_cal_data = + ((long long)(candela_coeff_2p2[point_index])) * + ((long long)(bl_level)); + candela_level[cnt] = temp_cal_data; + } +#ifdef SMART_DIMMING_DEBUG + pr_info("\nupper 260CD LUX:%d\n", bl_level); +#endif + } else if ((bl_level < gamma_curve_change_point[1]) && + (bl_level >= gamma_curve_change_point[2])) { + /* 260CD ~ 190CD */ + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) { + point_index = S6E8AA0X01_ARRAY[cnt+1]; + temp_cal_data = + ((long long)(candela_coeff_2p15[point_index])) * + ((long long)(bl_level)); + candela_level[cnt] = temp_cal_data; + } +#ifdef SMART_DIMMING_DEBUG + pr_info("\n260CD ~ 190CD LUX:%d\n", bl_level); +#endif + } else { + /*below 190CD */ + if ((bl_level < (AOR_FIX_CD + 10)) && + (bl_level >= AOR_ADJUST_CD)) { + /* 180CD ~ 110CD*/ + if (bl_level <= 180) { + aid_bl_level = ((AOR_MUL_COFF * bl_level) + + AOR_ADD_COFF) >> BIT_SHIFT; + aid_bl_level += AOR_ADD_COMPENSATION; + } else if (bl_level <= 182) + aid_bl_level = translate_table_188_to182[0]; + else if (bl_level <= 184) + aid_bl_level = translate_table_188_to182[1]; + else if (bl_level <= 186) + aid_bl_level = translate_table_188_to182[2]; + else + aid_bl_level = translate_table_188_to182[3]; + } else { + /* 100CD ~ 20CD */ + aid_bl_level = AOR_ADJUST_CD; + } + + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) { + point_index = S6E8AA0X01_ARRAY[cnt+1]; + temp_cal_data = + ((long long)(candela_coeff_2p1[point_index])) * + ((long long)(aid_bl_level)); + candela_level[cnt] = temp_cal_data; + } + +#ifdef SMART_DIMMING_DEBUG + pr_info("\nbelow 190CD LUX:%d AID_LUX:%d\n", + bl_level, (int)aid_bl_level); +#endif + } + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s candela_1:%llu candela_15:%llu candela_35:%llu " + "candela_59:%llu candela_171:%llu candela_171:%llu " + "candela_255:%llu\n", __func__, candela_level[0], + candela_level[1], candela_level[2], candela_level[3], + candela_level[4], candela_level[5], candela_level[6]); +#endif + + /*calculate brightness level*/ + if (bl_level >= gamma_curve_change_point[1]) { + /* upper 260CD */ + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) { + if (searching_function(candela_level[cnt], + &(bl_index[cnt]), GAMMA_CURVE_2P2)) { + pr_info("%s searching functioin error cnt:%d\n", + __func__, cnt); + } + } + } else if ((bl_level < gamma_curve_change_point[1]) && + (bl_level >= gamma_curve_change_point[2])) { + /* 260CD ~ 190CD */ + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) { + if (searching_function(candela_level[cnt], + &(bl_index[cnt]), GAMMA_CURVE_2P2)) { + pr_info("%s searching functioin error cnt:%d\n", + __func__, cnt); + } + } + + /* + * 190CD compensation + * V15, V35, V59, V87 level + 1 + */ + if (bl_level == 190) { + bl_index[1] += 1; + bl_index[2] += 1; + bl_index[3] += 1; + bl_index[4] += 1; + } + } else { + /*below 190CD */ + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) { + if (searching_function(candela_level[cnt], + &(bl_index[cnt]), GAMMA_CURVE_2P2)) { + pr_info("%s searching functioin error cnt:%d\n", + __func__, cnt); + } + } + } + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s bl_index_1:%d bl_index_15:%d bl_index_35:%d bl_index_59:%d " + "bl_index_87:%d bl_index_171:%d bl_index_255:%d\n", __func__, + bl_index[0], bl_index[1], bl_index[2], bl_index[3], + bl_index[4], bl_index[5], bl_index[6]); +#endif + + /*Generate Gamma table*/ + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) + (void)Make_hexa[cnt](bl_index , pSmart, str); + + /*subtration MTP_OFFSET value from generated gamma table*/ + if (bl_level < aid_compensation_cd[3]) { + /* below 110CD */ + index = (bl_level / 10) - 2; + str[3] = str[3] + below_110cd_v15_adding[index][1]; + str[4] = str[4] + below_110cd_v15_adding[index][2]; + str[5] = str[5] + below_110cd_v15_adding[index][3]; + + str[6] = str[6] + below_110cd_v35_adding[index][1]; + str[7] = str[7] + below_110cd_v35_adding[index][2]; + str[8] = str[8] + below_110cd_v35_adding[index][3]; + } else if ((bl_level <= aid_compensation_cd[2]) && + (bl_level >= aid_compensation_cd[3])) { + /* 180CD ~ 110CD */ + str[3] = str[3] + 1; + str[4] = str[4] - 1; + str[5] = str[5] + 5; + } + + str[3] -= pSmart->MTP.R_OFFSET.OFFSET_15; + str[4] -= pSmart->MTP.G_OFFSET.OFFSET_15; + str[5] -= pSmart->MTP.B_OFFSET.OFFSET_15; + + str[6] -= pSmart->MTP.R_OFFSET.OFFSET_35; + str[7] -= pSmart->MTP.G_OFFSET.OFFSET_35; + str[8] -= pSmart->MTP.B_OFFSET.OFFSET_35; + + str[9] -= pSmart->MTP.R_OFFSET.OFFSET_59; + str[10] -= pSmart->MTP.G_OFFSET.OFFSET_59; + str[11] -= pSmart->MTP.B_OFFSET.OFFSET_59; + + str[12] -= pSmart->MTP.R_OFFSET.OFFSET_87; + str[13] -= pSmart->MTP.G_OFFSET.OFFSET_87; + str[14] -= pSmart->MTP.B_OFFSET.OFFSET_87; + + str[15] -= pSmart->MTP.R_OFFSET.OFFSET_171; + str[16] -= pSmart->MTP.G_OFFSET.OFFSET_171; + str[17] -= pSmart->MTP.B_OFFSET.OFFSET_171; + + level_255_temp = (str[18] << 8) | str[19] ; + level_255_temp -= pSmart->MTP.R_OFFSET.OFFSET_255_LSB; + level_255_temp_MSB = level_255_temp / 256; + str[18] = level_255_temp_MSB & 0xff; + str[19] = level_255_temp & 0xff; + + level_255_temp = (str[20] << 8) | str[21] ; + level_255_temp -= pSmart->MTP.G_OFFSET.OFFSET_255_LSB; + level_255_temp_MSB = level_255_temp / 256; + str[20] = level_255_temp_MSB & 0xff; + str[21] = level_255_temp & 0xff; + + level_255_temp = (str[22] << 8) | str[23] ; + level_255_temp -= pSmart->MTP.B_OFFSET.OFFSET_255_LSB; + level_255_temp_MSB = level_255_temp / 256; + str[22] = level_255_temp_MSB & 0xff; + str[23] = level_255_temp & 0xff; + +} +#endif +#endif + +static void pure_gamma_init(struct SMART_DIM *pSmart, char *str, int size) +{ + long long candela_level[S6E8AA0X01_TABLE_MAX] = {-1, }; + int bl_index[S6E8AA0X01_TABLE_MAX] = {-1, }; + + long long temp_cal_data = 0; + int bl_level, cnt; + int level_255_temp = 0; + int level_255_temp_MSB = 0; + int point_index; + + bl_level = pSmart->brightness_level; + + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) { + point_index = S6E8AA0X01_ARRAY[cnt+1]; + temp_cal_data = + ((long long)(candela_coeff_2p2[point_index])) * + ((long long)(bl_level)); + candela_level[cnt] = temp_cal_data; + } + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s candela_1:%llu candela_15:%llu candela_35:%llu " + "candela_59:%llu candela_171:%llu candela_171:%llu " + "candela_255:%llu\n", __func__, candela_level[0], + candela_level[1], candela_level[2], candela_level[3], + candela_level[4], candela_level[5], candela_level[6]); +#endif + + /*calculate brightness level*/ + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) { + if (searching_function(candela_level[cnt], + &(bl_index[cnt]), GAMMA_CURVE_2P2)) { + pr_info("%s searching functioin error cnt:%d\n", + __func__, cnt); + } + } + +#ifdef SMART_DIMMING_DEBUG + pr_info("%s bl_index_1:%d bl_index_15:%d bl_index_35:%d bl_index_59:%d " + "bl_index_87:%d bl_index_171:%d bl_index_255:%d\n", __func__, + bl_index[0], bl_index[1], bl_index[2], bl_index[3], + bl_index[4], bl_index[5], bl_index[6]); +#endif + + /*Generate Gamma table*/ + for (cnt = 0; cnt < S6E8AA0X01_TABLE_MAX; cnt++) + (void)Make_hexa[cnt](bl_index , pSmart, str); + + /*subtration MTP_OFFSET value from generated gamma table*/ + str[3] -= pSmart->MTP.R_OFFSET.OFFSET_15; + str[4] -= pSmart->MTP.G_OFFSET.OFFSET_15; + str[5] -= pSmart->MTP.B_OFFSET.OFFSET_15; + + str[6] -= pSmart->MTP.R_OFFSET.OFFSET_35; + str[7] -= pSmart->MTP.G_OFFSET.OFFSET_35; + str[8] -= pSmart->MTP.B_OFFSET.OFFSET_35; + + str[9] -= pSmart->MTP.R_OFFSET.OFFSET_59; + str[10] -= pSmart->MTP.G_OFFSET.OFFSET_59; + str[11] -= pSmart->MTP.B_OFFSET.OFFSET_59; + + str[12] -= pSmart->MTP.R_OFFSET.OFFSET_87; + str[13] -= pSmart->MTP.G_OFFSET.OFFSET_87; + str[14] -= pSmart->MTP.B_OFFSET.OFFSET_87; + + str[15] -= pSmart->MTP.R_OFFSET.OFFSET_171; + str[16] -= pSmart->MTP.G_OFFSET.OFFSET_171; + str[17] -= pSmart->MTP.B_OFFSET.OFFSET_171; + + level_255_temp = (str[18] << 8) | str[19] ; + level_255_temp -= pSmart->MTP.R_OFFSET.OFFSET_255_LSB; + level_255_temp_MSB = level_255_temp / 256; + str[18] = level_255_temp_MSB & 0xff; + str[19] = level_255_temp & 0xff; + + level_255_temp = (str[20] << 8) | str[21] ; + level_255_temp -= pSmart->MTP.G_OFFSET.OFFSET_255_LSB; + level_255_temp_MSB = level_255_temp / 256; + str[20] = level_255_temp_MSB & 0xff; + str[21] = level_255_temp & 0xff; + + level_255_temp = (str[22] << 8) | str[23] ; + level_255_temp -= pSmart->MTP.B_OFFSET.OFFSET_255_LSB; + level_255_temp_MSB = level_255_temp / 256; + str[22] = level_255_temp_MSB & 0xff; + str[23] = level_255_temp & 0xff; + +} + +static void set_max_lux_table(void) +{ + max_lux_table[0] = V1_300CD_R; + max_lux_table[1] = V1_300CD_G; + max_lux_table[2] = V1_300CD_B; + + max_lux_table[3] = V15_300CD_R; + max_lux_table[4] = V15_300CD_G; + max_lux_table[5] = V15_300CD_B; + + max_lux_table[6] = V35_300CD_R; + max_lux_table[7] = V35_300CD_G; + max_lux_table[8] = V35_300CD_B; + + max_lux_table[9] = V59_300CD_R; + max_lux_table[10] = V59_300CD_G; + max_lux_table[11] = V59_300CD_B; + + max_lux_table[12] = V87_300CD_R; + max_lux_table[13] = V87_300CD_G; + max_lux_table[14] = V87_300CD_B; + + max_lux_table[15] = V171_300CD_R; + max_lux_table[16] = V171_300CD_G; + max_lux_table[17] = V171_300CD_B; + + max_lux_table[18] = V255_300CD_R_MSB; + max_lux_table[19] = V255_300CD_R_LSB; + + max_lux_table[20] = V255_300CD_G_MSB; + max_lux_table[21] = V255_300CD_G_LSB; + + max_lux_table[22] = V255_300CD_B_MSB; + max_lux_table[23] = V255_300CD_B_LSB; + +} + +static void set_min_lux_table(struct SMART_DIM *psmart) +{ + psmart->brightness_level = MIN_CANDELA; + pure_gamma_init(psmart, min_lux_table, GAMMA_SET_MAX); +} + +void get_min_lux_table(char *str, int size) +{ + memcpy(str, min_lux_table, size); +} + +void generate_gamma(struct SMART_DIM *psmart, char *str, int size) +{ + int lux_loop; + struct illuminance_table *ptable = (struct illuminance_table *) + (&(psmart->gen_table)); + + /* searching already generated gamma table */ + for (lux_loop = 0; lux_loop < psmart->lux_table_max; lux_loop++) { + if (ptable[lux_loop].lux == psmart->brightness_level) { + memcpy(str, &(ptable[lux_loop].gamma_setting), size); + break; + } + } + + /* searching fail... Setting 300CD value on gamma table */ + if (lux_loop == psmart->lux_table_max) { + pr_info("%s searching fail lux : %d\n", __func__, + psmart->brightness_level); + memcpy(str, max_lux_table, size); + } + +#ifdef SMART_DIMMING_DEBUG + if (lux_loop != psmart->lux_table_max) + pr_info("%s searching ok index : %d lux : %d", __func__, + lux_loop, ptable[lux_loop].lux); +#endif +} + +static void gamma_cell_determine(int ldi_revision) +{ + pr_info("%s ldi_revision:%d", __func__, ldi_revision); + +#if defined(CONFIG_MACH_STRETTO) || defined(CONFIG_MACH_SUPERIORLTE_SKT) + if (ldi_revision == 0xAE) { + V1_300CD_R = V1_300CD_R_AE; + V1_300CD_G = V1_300CD_G_AE; + V1_300CD_B = V1_300CD_B_AE; + + V15_300CD_R = V15_300CD_R_AE; + V15_300CD_G = V15_300CD_G_AE; + V15_300CD_B = V15_300CD_B_AE; + + V35_300CD_R = V35_300CD_R_AE; + V35_300CD_G = V35_300CD_G_AE; + V35_300CD_B = V35_300CD_B_AE; + + V59_300CD_R = V59_300CD_R_AE; + V59_300CD_G = V59_300CD_G_AE; + V59_300CD_B = V59_300CD_B_AE; + + V87_300CD_R = V87_300CD_R_AE; + V87_300CD_G = V87_300CD_G_AE; + V87_300CD_B = V87_300CD_B_AE; + + V171_300CD_R = V171_300CD_R_AE; + V171_300CD_G = V171_300CD_G_AE; + V171_300CD_B = V171_300CD_B_AE; + + V255_300CD_R_MSB = V255_300CD_R_MSB_AE; + V255_300CD_R_LSB = V255_300CD_R_LSB_AE; + + V255_300CD_G_MSB = V255_300CD_G_MSB_AE; + V255_300CD_G_LSB = V255_300CD_G_LSB_AE; + + V255_300CD_B_MSB = V255_300CD_B_MSB_AE; + V255_300CD_B_LSB = V255_300CD_B_LSB_AE; + + return; + } +#endif + if (ldi_revision == 0x60) { + V1_300CD_R = V1_300CD_R_60; + V1_300CD_G = V1_300CD_G_60; + V1_300CD_B = V1_300CD_B_60; + + V15_300CD_R = V15_300CD_R_60; + V15_300CD_G = V15_300CD_G_60; + V15_300CD_B = V15_300CD_B_60; + + V35_300CD_R = V35_300CD_R_60; + V35_300CD_G = V35_300CD_G_60; + V35_300CD_B = V35_300CD_B_60; + + V59_300CD_R = V59_300CD_R_60; + V59_300CD_G = V59_300CD_G_60; + V59_300CD_B = V59_300CD_B_60; + + V87_300CD_R = V87_300CD_R_60; + V87_300CD_G = V87_300CD_G_60; + V87_300CD_B = V87_300CD_B_60; + + V171_300CD_R = V171_300CD_R_60; + V171_300CD_G = V171_300CD_G_60; + V171_300CD_B = V171_300CD_B_60; + + V255_300CD_R_MSB = V255_300CD_R_MSB_60; + V255_300CD_R_LSB = V255_300CD_R_LSB_60; + + V255_300CD_G_MSB = V255_300CD_G_MSB_60; + V255_300CD_G_LSB = V255_300CD_G_LSB_60; + + V255_300CD_B_MSB = V255_300CD_B_MSB_60; + V255_300CD_B_LSB = V255_300CD_B_LSB_60; + + } else if (ldi_revision == 0x40) { + V1_300CD_R = V1_300CD_R_40; + V1_300CD_G = V1_300CD_G_40; + V1_300CD_B = V1_300CD_B_40; + + V15_300CD_R = V15_300CD_R_40; + V15_300CD_G = V15_300CD_G_40; + V15_300CD_B = V15_300CD_B_40; + + V35_300CD_R = V35_300CD_R_40; + V35_300CD_G = V35_300CD_G_40; + V35_300CD_B = V35_300CD_B_40; + + V59_300CD_R = V59_300CD_R_40; + V59_300CD_G = V59_300CD_G_40; + V59_300CD_B = V59_300CD_B_40; + + V87_300CD_R = V87_300CD_R_40; + V87_300CD_G = V87_300CD_G_40; + V87_300CD_B = V87_300CD_B_40; + + V171_300CD_R = V171_300CD_R_40; + V171_300CD_G = V171_300CD_G_40; + V171_300CD_B = V171_300CD_B_40; + + V255_300CD_R_MSB = V255_300CD_R_MSB_40; + V255_300CD_R_LSB = V255_300CD_R_LSB_40; + + V255_300CD_G_MSB = V255_300CD_G_MSB_40; + V255_300CD_G_LSB = V255_300CD_G_LSB_40; + + V255_300CD_B_MSB = V255_300CD_B_MSB_40; + V255_300CD_B_LSB = V255_300CD_B_LSB_40; + + } else { + V1_300CD_R = V1_300CD_R_20; + V1_300CD_G = V1_300CD_G_20; + V1_300CD_B = V1_300CD_B_20; + + V15_300CD_R = V15_300CD_R_20; + V15_300CD_G = V15_300CD_G_20; + V15_300CD_B = V15_300CD_B_20; + + V35_300CD_R = V35_300CD_R_20; + V35_300CD_G = V35_300CD_G_20; + V35_300CD_B = V35_300CD_B_20; + + V59_300CD_R = V59_300CD_R_20; + V59_300CD_G = V59_300CD_G_20; + V59_300CD_B = V59_300CD_B_20; + + V87_300CD_R = V87_300CD_R_20; + V87_300CD_G = V87_300CD_G_20; + V87_300CD_B = V87_300CD_B_20; + + V171_300CD_R = V171_300CD_R_20; + V171_300CD_G = V171_300CD_G_20; + V171_300CD_B = V171_300CD_B_20; + + V255_300CD_R_MSB = V255_300CD_R_MSB_20; + V255_300CD_R_LSB = V255_300CD_R_LSB_20; + + V255_300CD_G_MSB = V255_300CD_G_MSB_20; + V255_300CD_G_LSB = V255_300CD_G_LSB_20; + + V255_300CD_B_MSB = V255_300CD_B_MSB_20; + V255_300CD_B_LSB = V255_300CD_B_LSB_20; + } +} + +int smart_dimming_init(struct SMART_DIM *psmart) +{ + int lux_loop; +#ifdef SMART_DIMMING_DEBUG + int cnt; + char pBuffer[256]; + memset(pBuffer, 0x00, 256); +#endif + gamma_cell_determine(psmart->ldi_revision); + set_max_lux_table(); + + v255_adjustment(psmart); + v1_adjustment(psmart); + v171_adjustment(psmart); + v87_adjustment(psmart); + v59_adjustment(psmart); + v35_adjustment(psmart); + v15_adjustment(psmart); + + if (generate_gray_scale(psmart)) { + pr_info(KERN_ERR "lcd smart dimming fail generate_gray_scale\n"); + return -1; + } + + /*Generating lux_table*/ + for (lux_loop = 0; lux_loop < psmart->lux_table_max; lux_loop++) { + /* To set brightness value */ + psmart->brightness_level = psmart->plux_table[lux_loop]; + /* To make lux table index*/ + psmart->gen_table[lux_loop].lux = psmart->plux_table[lux_loop]; + +#ifdef AID_OPERATION_4_8_INCH + gamma_init(psmart, + (char *)(&(psmart->gen_table[lux_loop].gamma_setting)), + GAMMA_SET_MAX); +#else + pure_gamma_init(psmart, + (char *)(&(psmart->gen_table[lux_loop].gamma_setting)), + GAMMA_SET_MAX); +#endif + } + + /* set 300CD max gamma table */ + memcpy(&(psmart->gen_table[lux_loop-1].gamma_setting), + max_lux_table, GAMMA_SET_MAX); + + set_min_lux_table(psmart); + +#ifdef SMART_DIMMING_DEBUG + for (lux_loop = 0; lux_loop < psmart->lux_table_max; lux_loop++) { + for (cnt = 0; cnt < GAMMA_SET_MAX; cnt++) + snprintf(pBuffer + strnlen(pBuffer, 256), 256, " %d", + psmart->gen_table[lux_loop].gamma_setting[cnt]); + + pr_info("lux : %d %s", psmart->plux_table[lux_loop], pBuffer); + memset(pBuffer, 0x00, 256); + } + + for (lux_loop = 0; lux_loop < psmart->lux_table_max; lux_loop++) { + for (cnt = 0; cnt < GAMMA_SET_MAX; cnt++) + snprintf(pBuffer + strnlen(pBuffer, 256), 256, + " 0x%02x", + psmart->gen_table[lux_loop].gamma_setting[cnt]); + + pr_info("lux : %d %s", psmart->plux_table[lux_loop], pBuffer); + memset(pBuffer, 0x00, 256); + } +#endif + + return 0; +} + diff --git a/drivers/video/msm/smart_mtp_s6e8aa0x01.h b/drivers/video/msm/smart_mtp_s6e8aa0x01.h new file mode 100644 index 00000000000..a792fd6c99c --- /dev/null +++ b/drivers/video/msm/smart_mtp_s6e8aa0x01.h @@ -0,0 +1,321 @@ +/* + * ================================================================= + * + * Filename: smart_mtp_s6e8aa0x01.h + * + * Description: Smart dimming algorithm implementation + * + * Author: jb09.kim + * Company: Samsung Electronics + * + * ================================================================ + */ +/* + +Copyright (C) 2012, Samsung Electronics. All rights reserved. + +* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * +*/ +#ifndef _SMART_MTP_S6E8AA0X01_H_ +#define _SMART_MTP_S6E8AA0X01_H_ + +#include +#include +#include +#include +#include +#include +#include + + +#if defined(CONFIG_MACH_STRETTO) || defined(CONFIG_MACH_SUPERIORLTE_SKT) +/* +* STRETTO/SUPERIORLTE_SKT: 4.65 inch / no AID +*/ +#else +/* +* 4.8 inch model use AID function +* CASE#1 is used for now. +*/ +#define AID_OPERATION_4_8_INCH +#define AID_CASE_1 + + +/* +* To set default AID algorithm +*/ +#if !defined(AID_CASE_1) && !defined(AID_CASE_2) && !defined(AID_CASE_3) +#define AID_CASE_1 +#endif +#endif + +#define LUMINANCE_MAX 35 +#define GAMMA_SET_MAX 24 +#define BIT_SHIFT 14 +/* + it means BIT_SHIFT is 14. pow(2,BIT_SHIFT) is 16384. + BIT_SHIFT is used for right bit shfit +*/ +#define BIT_SHFIT_MUL 16384 + +#define S6E8AA0X01_GRAY_SCALE_MAX 256 + +/*4.713*16384 */ +#define S6E8AA0X01_VREG0_REF 77218 + +/*V0,V1,V15,V35,V59,V87,V177,V255*/ +#define S6E8AA0X01_MAX 8 + +/* PANEL DEPENDENT THINGS */ +#define MAX_CANDELA 300 +#define MIN_CANDELA 20 + +/* +* ID 0x20 +*/ +#define V1_300CD_R_20 0x43 +#define V1_300CD_G_20 0x14 +#define V1_300CD_B_20 0x45 + +#define V15_300CD_R_20 0xAD +#define V15_300CD_G_20 0xBE +#define V15_300CD_B_20 0xA9 + +#define V35_300CD_R_20 0xB0 +#define V35_300CD_G_20 0xC3 +#define V35_300CD_B_20 0xAF + +#define V59_300CD_R_20 0xC1 +#define V59_300CD_G_20 0xCD +#define V59_300CD_B_20 0xC0 + +#define V87_300CD_R_20 0x95 +#define V87_300CD_G_20 0xA2 +#define V87_300CD_B_20 0x91 + +#define V171_300CD_R_20 0xAC +#define V171_300CD_G_20 0xB5 +#define V171_300CD_B_20 0xAA + +#define V255_300CD_R_MSB_20 0x00 +#define V255_300CD_R_LSB_20 0xB0 + +#define V255_300CD_G_MSB_20 0x00 +#define V255_300CD_G_LSB_20 0xA0 + +#define V255_300CD_B_MSB_20 0x00 +#define V255_300CD_B_LSB_20 0xCC + +/* +* ID 0x40 +*/ +#define V1_300CD_R_40 0x44 +#define V1_300CD_G_40 0x0F +#define V1_300CD_B_40 0x42 + +#define V15_300CD_R_40 0xAB +#define V15_300CD_G_40 0xC1 +#define V15_300CD_B_40 0xAC + +#define V35_300CD_R_40 0xAF +#define V35_300CD_G_40 0xC8 +#define V35_300CD_B_40 0xB3 + +#define V59_300CD_R_40 0xC2 +#define V59_300CD_G_40 0xD0 +#define V59_300CD_B_40 0xC1 + +#define V87_300CD_R_40 0x97 +#define V87_300CD_G_40 0xA9 +#define V87_300CD_B_40 0x95 + +#define V171_300CD_R_40 0xB3 +#define V171_300CD_G_40 0xBE +#define V171_300CD_B_40 0xB3 + +#define V255_300CD_R_MSB_40 0x00 +#define V255_300CD_R_LSB_40 0x9C + +#define V255_300CD_G_MSB_40 0x00 +#define V255_300CD_G_LSB_40 0x85 + +#define V255_300CD_B_MSB_40 0x00 +#define V255_300CD_B_LSB_40 0xB2 + +/* +* ID 0x60 +*/ +#define V1_300CD_R_60 0x3F +#define V1_300CD_G_60 0x12 +#define V1_300CD_B_60 0x41 + +#define V15_300CD_R_60 0xB4 +#define V15_300CD_G_60 0xCB +#define V15_300CD_B_60 0xB0 + +#define V35_300CD_R_60 0xB2 +#define V35_300CD_G_60 0xC4 +#define V35_300CD_B_60 0xB2 + +#define V59_300CD_R_60 0xC4 +#define V59_300CD_G_60 0xCF +#define V59_300CD_B_60 0xC2 + +#define V87_300CD_R_60 0x9A +#define V87_300CD_G_60 0xA7 +#define V87_300CD_B_60 0x97 + +#define V171_300CD_R_60 0xB2 +#define V171_300CD_G_60 0xBA +#define V171_300CD_B_60 0xB0 + +#define V255_300CD_R_MSB_60 0x00 +#define V255_300CD_R_LSB_60 0xA0 + +#define V255_300CD_G_MSB_60 0x00 +#define V255_300CD_G_LSB_60 0x98 + +#define V255_300CD_B_MSB_60 0x00 +#define V255_300CD_B_LSB_60 0xB7 + +#if defined(CONFIG_MACH_STRETTO) || defined(CONFIG_MACH_SUPERIORLTE_SKT) +/* +* ID 0xAE +*/ +#define V1_300CD_R_AE 0x5F +#define V1_300CD_G_AE 0x2E +#define V1_300CD_B_AE 0x67 + +#define V15_300CD_R_AE 0xAA +#define V15_300CD_G_AE 0xC6 +#define V15_300CD_B_AE 0xAC + +#define V35_300CD_R_AE 0xB0 +#define V35_300CD_G_AE 0xC8 +#define V35_300CD_B_AE 0xBB + +#define V59_300CD_R_AE 0xBE +#define V59_300CD_G_AE 0xCB +#define V59_300CD_B_AE 0xBD + +#define V87_300CD_R_AE 0x97 +#define V87_300CD_G_AE 0xA5 +#define V87_300CD_B_AE 0x91 + +#define V171_300CD_R_AE 0xAF +#define V171_300CD_G_AE 0xB8 +#define V171_300CD_B_AE 0xAB + +#define V255_300CD_R_MSB_AE 0x00 +#define V255_300CD_R_LSB_AE 0xC2 + +#define V255_300CD_G_MSB_AE 0x00 +#define V255_300CD_G_LSB_AE 0xBA + +#define V255_300CD_B_MSB_AE 0x00 +#define V255_300CD_B_LSB_AE 0xE2 +#endif + +/* PANEL DEPENDENT THINGS END*/ + + +enum { + V1_INDEX = 0, + V15_INDEX = 1, + V35_INDEX = 2, + V59_INDEX = 3, + V87_INDEX = 4, + V171_INDEX = 5, + V255_INDEX = 6, +}; + +struct GAMMA_LEVEL { + int level_0; + int level_1; + int level_15; + int level_35; + int level_59; + int level_87; + int level_171; + int level_255; +} __packed; + +struct RGB_OUTPUT_VOLTARE { + struct GAMMA_LEVEL R_VOLTAGE; + struct GAMMA_LEVEL G_VOLTAGE; + struct GAMMA_LEVEL B_VOLTAGE; +} __packed; + +struct GRAY_VOLTAGE { + /* + This voltage value use 14bit right shit + it means voltage is divied by 16384. + */ + int R_Gray; + int G_Gray; + int B_Gray; +} __packed; + +struct GRAY_SCALE { + struct GRAY_VOLTAGE TABLE[S6E8AA0X01_GRAY_SCALE_MAX]; +} __packed; + +struct MTP_SET { + char OFFSET_1; + char OFFSET_15; + char OFFSET_35; + char OFFSET_59; + char OFFSET_87; + char OFFSET_171; + char OFFSET_255_MSB; + char OFFSET_255_LSB; +} __packed; + +struct MTP_OFFSET { + /* + MTP_OFFSET is consist of 22 byte. + First byte is dummy and 21 byte is useful. + */ + struct MTP_SET R_OFFSET; + struct MTP_SET G_OFFSET; + struct MTP_SET B_OFFSET; +} __packed; + +struct illuminance_table { + int lux; + char gamma_setting[GAMMA_SET_MAX]; +} __packed; + +struct SMART_DIM { + struct MTP_OFFSET MTP; + struct RGB_OUTPUT_VOLTARE RGB_OUTPUT; + struct GRAY_SCALE GRAY; + + /* Because of AID funtion, below members are added*/ + int lux_table_max; + int *plux_table; + struct illuminance_table gen_table[LUMINANCE_MAX]; + + int brightness_level; + int ldi_revision; +} __packed; + +void generate_gamma(struct SMART_DIM *smart_dim, char *str, int size); +int smart_dimming_init(struct SMART_DIM *psmart); +void get_min_lux_table(char *str, int size); + +#endif diff --git a/include/linux/charging_temperature_data.h b/include/linux/charging_temperature_data.h new file mode 100644 index 00000000000..db31292a400 --- /dev/null +++ b/include/linux/charging_temperature_data.h @@ -0,0 +1,195 @@ +/* + * charging_temperature_data.h + * + * header file supporting temperature functions for Samsung device + * + * COPYRIGHT(C) Samsung Electronics Co., Ltd. 2012-2017 All Right Reserved. + * + * 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. + */ +#include +#ifndef __CHARGING_TEMPERATURE_DATA_H +#define __CHARGING_TEMPERATURE_DATA_H __FILE__ + +#define DEFAULT_HIGH_BLOCK_TEMP 650 +#define DEFAULT_HIGH_RECOVER_TEMP 430 +#define DEFAULT_LOW_BLOCK_TEMP -50 +#define DEFAULT_LOW_RECOVER_TEMP 0 + +#if defined(CONFIG_MACH_JAGUAR) +static const int temp_table[][2] = { + {26250, 800}, + {26583, 750}, + {26979, 700}, + {27429, 650}, + {27941, 600}, + {28523, 550}, + {29170, 500}, + {29875, 450}, + {30684, 400}, + {31705, 350}, + {32726, 300}, + {33747, 250}, + {34768, 200}, + {35789, 150}, + {36810, 100}, + {37837, 50}, + {38710, 0}, + {39539, -50}, + {40269, -100}, + {41099, -150}, + {41859, -200}, +}; + +#elif defined(CONFIG_MACH_M2_ATT) +static const int temp_table[][2] = { + {26465, 800}, + {26749, 750}, + {27017, 700}, + {27414, 650}, + {27870, 600}, + {28424, 550}, + {29350, 500}, + {29831, 450}, + {30595, 400}, + {31561, 350}, + {32603, 300}, + {33647, 250}, + {34655, 200}, + {35741, 150}, + {36747, 100}, + {37755, 50}, + {38605, 0}, + {39412, -50}, + {40294, -100}, + {40845, -150}, + {41353, -200}, +}; + +#elif defined(CONFIG_MACH_M2_SPR) +static const struct pm8xxx_adc_map_pt temp_table[] = { + {26385, 800}, + {26787, 750}, + {27136, 700}, + {27540, 650}, + {28031, 600}, + {28601, 550}, + {29255, 500}, + {29568, 450}, + {30967, 400}, + {31880, 350}, + {32846, 300}, + {33694, 250}, + {34771, 200}, + {35890, 150}, + {37045, 100}, + {38144, 50}, + {39097, 0}, + {39885, -50}, + {40595, -100}, + {41190, -150}, + {41954, -200}, +}; + +#elif defined(CONFIG_MACH_M2_VZW) +static const int temp_table[][2] = { + {26537, 800}, + {26849, 750}, + {27211, 700}, + {27627, 650}, + {28117, 600}, + {28713, 550}, + {29403, 500}, + {30205, 450}, + {31075, 400}, + {32026, 350}, + {33014, 300}, + {34117, 250}, + {35115, 200}, + {36121, 150}, + {37212, 100}, + {38190, 50}, + {39006, 0}, + {39813, -50}, + {40490, -100}, + {41084, -150}, + {41537, -200}, +}; + +#elif defined(CONFIG_MACH_GOGH) || defined(CONFIG_MACH_INFINITE) +static const int temp_table[][2] = { + {26478, 800}, + {27123, 700}, + {27985, 600}, + {29180, 500}, + {30704, 400}, + {32510, 300}, + {34595, 200}, + {36722, 100}, + {38530, 0}, + {40142, -100}, + {41321, -200}, +}; + +#elif defined(CONFIG_MACH_AEGIS2) +static const int temp_table[][2] = { + {27401, 650}, + {27790, 600}, + {28378, 550}, + {29190, 500}, + {29770, 450}, + {30676, 400}, + {31446, 350}, + {32493, 300}, + {33608, 250}, + {34631, 200}, + {35773, 150}, + {36814, 100}, + {37778, 50}, + {38570, 0}, + {39425, -50}, + {40253, -100}, + {40886, -150}, + {41328, -200}, + {41656, -250}, +}; + +#else +static const int temp_table[][2] = { + {26250, 800}, + {26583, 750}, + {26979, 700}, + {27429, 650}, + {27941, 600}, + {28523, 550}, + {29170, 500}, + {29875, 450}, + {30684, 400}, + {31705, 350}, + {32726, 300}, + {33747, 250}, + {34768, 200}, + {35789, 150}, + {36810, 100}, + {37837, 50}, + {38710, 0}, + {39539, -50}, + {40269, -100}, + {41099, -150}, + {41859, -200}, +}; +#endif + +#endif /* __CHARGING_TEMPERATURE_DATA_H */ diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index a7e977ff4ab..63edfe7e584 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -26,6 +26,7 @@ struct gpio_keys_platform_data { int (*enable)(struct device *dev); void (*disable)(struct device *dev); const char *name; /* input device name */ + unsigned int keyled; /* keyled enable for gpio keys */ }; - +extern struct class *sec_class; #endif diff --git a/include/linux/i2c/cm36651.h b/include/linux/i2c/cm36651.h new file mode 100644 index 00000000000..d9b41081d74 --- /dev/null +++ b/include/linux/i2c/cm36651.h @@ -0,0 +1,32 @@ +/* + * driver/sensor/cm36651.c + * Copyright (c) 2011 SAMSUNG ELECTRONICS + * + * 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. + */ + +#ifndef __LINUX_CM36651_H +#define __CM36651_H__ + +struct cm36651_platform_data { + void (*cm36651_led_on) (int); + void (*cm36651_power_on) (int); + int irq; /* proximity-sensor irq gpio */ + unsigned char threshold; +}; +extern struct class *sensors_class; + +#endif diff --git a/include/linux/i2c/cypress_touchkey.h b/include/linux/i2c/cypress_touchkey.h new file mode 100644 index 00000000000..54b135dcc98 --- /dev/null +++ b/include/linux/i2c/cypress_touchkey.h @@ -0,0 +1,54 @@ +/* + * cypress_touchkey.h - Platform data for cypress touchkey driver + * + * Copyright (C) 2011 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __LINUX_CYPRESS_TOUCHKEY_H +#define __LINUX_CYPRESS_TOUCHKEY_H +extern struct class *sec_class; +extern int ISSP_main(void); +extern int touch_is_pressed; +struct cypress_touchkey_platform_data { + unsigned gpio_int; + unsigned gpio_led_en; + const u8 *touchkey_keycode; + void (*power_onoff) (int); + bool skip_fw_update; + bool touchkey_order; +}; + +#if defined(CONFIG_KEYBOARD_CYPRESS_TOUCH) +#if defined(CONFIG_MACH_EXPRESS) +#define CYPRESS_DIFF_MENU 0x0A +#define CYPRESS_DIFF_BACK 0x0C +#define CYPRESS_DIFF_HOME 0 +#define CYPRESS_DIFF_RECENT 0 +#define CYPRESS_RAW_DATA_MENU 0x0E +#define CYPRESS_RAW_DATA_BACK 0x10 +#define CYPRESS_RAW_DATA_HOME 0 +#define CYPRESS_RAW_DATA_RECENT 0 +#define CYPRESS_IDAC_MENU 0x06 +#define CYPRESS_IDAC_BACK 0x07 + +#elif defined(CONFIG_MACH_AEGIS2) +#define CYPRESS_DIFF_BACK 0x10 +#define CYPRESS_DIFF_HOME 0x0E +#define CYPRESS_DIFF_RECENT 0x0C +#define CYPRESS_DIFF_MENU 0x0A + +#define CYPRESS_RAW_DATA_BACK 0x18 +#define CYPRESS_RAW_DATA_HOME 0x16 +#define CYPRESS_RAW_DATA_RECENT 0x14 +#define CYPRESS_RAW_DATA_MENU 0x12 + + +#endif +#endif + +#endif /* __LINUX_CYPRESS_TOUCHKEY_H */ diff --git a/include/linux/i2c/fsa9485.h b/include/linux/i2c/fsa9485.h new file mode 100644 index 00000000000..ec37debbc7c --- /dev/null +++ b/include/linux/i2c/fsa9485.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 Samsung Electronics + * Minkyu Kang + * Wonguk Jeong + * + * 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 _FSA9485_H_ +#define _FSA9485_H_ + +enum { + FSA9485_DETACHED, + FSA9485_ATTACHED +}; + +enum { + FSA9485_DETACHED_DOCK = 0, + FSA9485_ATTACHED_DESK_DOCK, + FSA9485_ATTACHED_CAR_DOCK, +}; + +#define UART_SEL_SW 58 + +struct fsa9485_platform_data { + void (*cfg_gpio) (void); + void (*otg_cb) (bool attached); + void (*usb_cb) (bool attached); + void (*uart_cb) (bool attached); + void (*charger_cb) (bool attached); + void (*jig_cb) (bool attached); + void (*mhl_cb) (bool attached); + void (*reset_cb) (void); + void (*set_init_flag) (void); + void (*mhl_sel) (bool onoff); + void (*dock_cb) (int attached); + int (*dock_init) (void); + void (*usb_cdp_cb) (bool attached); + void (*smartdock_cb) (bool attached); + void (*audio_dock_cb) (bool attached); +}; + +enum { + SWITCH_PORT_AUTO = 0, + SWITCH_PORT_USB, + SWITCH_PORT_AUDIO, + SWITCH_PORT_UART, + SWITCH_PORT_VAUDIO, + SWITCH_PORT_USB_OPEN, + SWITCH_PORT_ALL_OPEN, +}; + +extern void fsa9485_manual_switching(int path); +extern void fsa9485_otg_detach(void); +extern struct class *sec_class; + +#endif /* _FSA9485_H_ */ diff --git a/include/linux/input.h b/include/linux/input.h index d4cdb02c9de..41e74a2560f 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -816,6 +816,9 @@ struct input_keymap_entry { #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ #define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ +#define ABS_MT_ANGLE 0x3c /* touch angle */ +#define ABS_MT_PALM 0x3d /* palm touch */ + #ifdef __KERNEL__ /* Implementation details, userspace should not care about these */ diff --git a/include/linux/input/bmp180.h b/include/linux/input/bmp180.h new file mode 100644 index 00000000000..e024e735d06 --- /dev/null +++ b/include/linux/input/bmp180.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 Samsung Electronics. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 + */ + +#ifndef _BMP180_H +#define _BMP180_H + +/* Register definitions */ +#define BMP180_TAKE_MEAS_REG 0xf4 +#define BMP180_READ_MEAS_REG_U 0xf6 +#define BMP180_READ_MEAS_REG_L 0xf7 +#define BMP180_READ_MEAS_REG_XL 0xf8 + +/* + * Bytes defined by the spec to take measurements + * Temperature will take 4.5ms before EOC + */ +#define BMP180_MEAS_TEMP 0x2e +/* 4.5ms wait for measurement */ +#define BMP180_MEAS_PRESS_OVERSAMP_0 0x34 +/* 7.5ms wait for measurement */ +#define BMP180_MEAS_PRESS_OVERSAMP_1 0x74 +/* 13.5ms wait for measurement */ +#define BMP180_MEAS_PRESS_OVERSAMP_2 0xb4 +/* 25.5ms wait for measurement */ +#define BMP180_MEAS_PRESS_OVERSAMP_3 0xf4 + +/* + * EEPROM registers each is a two byte value so there is + * an upper byte and a lower byte + */ +#define BMP180_EEPROM_AC1_U 0xaa +#define BMP180_EEPROM_AC1_L 0xab +#define BMP180_EEPROM_AC2_U 0xac +#define BMP180_EEPROM_AC2_L 0xad +#define BMP180_EEPROM_AC3_U 0xae +#define BMP180_EEPROM_AC3_L 0xaf +#define BMP180_EEPROM_AC4_U 0xb0 +#define BMP180_EEPROM_AC4_L 0xb1 +#define BMP180_EEPROM_AC5_U 0xb2 +#define BMP180_EEPROM_AC5_L 0xb3 +#define BMP180_EEPROM_AC6_U 0xb4 +#define BMP180_EEPROM_AC6_L 0xb5 +#define BMP180_EEPROM_B1_U 0xb6 +#define BMP180_EEPROM_B1_L 0xb7 +#define BMP180_EEPROM_B2_U 0xb8 +#define BMP180_EEPROM_B2_L 0xb9 +#define BMP180_EEPROM_MB_U 0xba +#define BMP180_EEPROM_MB_L 0xbb +#define BMP180_EEPROM_MC_U 0xbc +#define BMP180_EEPROM_MC_L 0xbd +#define BMP180_EEPROM_MD_U 0xbe +#define BMP180_EEPROM_MD_L 0xbf + +#define I2C_TRIES 5 +#define AUTO_INCREMENT 0x80 + +#define DELAY_LOWBOUND (10 * NSEC_PER_MSEC) +#define DELAY_UPBOUND (500 * NSEC_PER_MSEC) +#define DELAY_DEFAULT (200 * NSEC_PER_MSEC) + +#define PRESSURE_MAX 125000 +#define PRESSURE_MIN 95000 +#define PRESSURE_FUZZ 5 +#define PRESSURE_FLAT 5 + +#define FACTORY_TEST +#ifdef FACTORY_TEST +#define TEMP_MAX 3000 +#define TEMP_MIN -3000 +#define SEA_LEVEL_MAX 999999 +#define SEA_LEVEL_MIN -1 +#endif + +struct bmp_i2c_platform_data { + void (*power_on) (int); +}; +extern int sensors_register(struct device *dev, void * drvdata, + struct device_attribute *attributes[], char *name); + +#endif /* _AS5011_H */ diff --git a/include/linux/ion.h b/include/linux/ion.h index 7fee5ff0cfd..c56faa460ab 100644 --- a/include/linux/ion.h +++ b/include/linux/ion.h @@ -515,6 +515,13 @@ struct ion_allocation_data { struct ion_handle *handle; }; + +struct ion_allocation_data_compat { + size_t len; + size_t align; + unsigned int flags; + struct ion_handle *handle; +}; /** * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair * @handle: a handle @@ -550,6 +557,19 @@ struct ion_custom_data { unsigned int cmd; unsigned long arg; }; + +struct ion_flush_data { + struct ion_handle *handle; + int fd; + void *vaddr; + unsigned int offset; + unsigned int length; +}; +struct ion_flag_data { + struct ion_handle *handle; + unsigned long flags; +}; + #define ION_IOC_MAGIC 'I' /** @@ -561,6 +581,9 @@ struct ion_custom_data { #define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ struct ion_allocation_data) + +#define ION_IOC_ALLOC_COMPAT _IOWR(ION_IOC_MAGIC, 0, \ + struct ion_allocation_data_compat) /** * DOC: ION_IOC_FREE - free memory * @@ -597,6 +620,7 @@ struct ion_custom_data { * filed set to the corresponding opaque handle. */ #define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) +#define ION_IOC_IMPORT_COMPAT _IOWR(ION_IOC_MAGIC, 5, int) /** * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl @@ -606,5 +630,13 @@ struct ion_custom_data { */ #define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) +#define ION_IOC_CLEAN_CACHES_COMPAT _IOWR(ION_IOC_MAGIC, 7, \ + struct ion_flush_data) +#define ION_IOC_INV_CACHES_COMPAT _IOWR(ION_IOC_MAGIC, 8, \ + struct ion_flush_data) +#define ION_IOC_CLEAN_INV_CACHES_COMPAT _IOWR(ION_IOC_MAGIC, 9, \ + struct ion_flush_data) +#define ION_IOC_GET_FLAGS_COMPAT _IOWR(ION_IOC_MAGIC, 10, \ + struct ion_flag_data) #endif /* _LINUX_ION_H */ diff --git a/include/linux/kexec.h b/include/linux/kexec.h index af84a25ef6b..664791ff62c 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -110,6 +110,9 @@ struct kimage { #define KEXEC_TYPE_DEFAULT 0 #define KEXEC_TYPE_CRASH 1 unsigned int preserve_context : 1; +#ifdef CONFIG_KEXEC_HARDBOOT + unsigned int hardboot : 1; +#endif #ifdef ARCH_HAS_KIMAGE_ARCH struct kimage_arch arch; @@ -178,6 +181,9 @@ extern struct kimage *kexec_crash_image; #define KEXEC_ON_CRASH 0x00000001 #define KEXEC_PRESERVE_CONTEXT 0x00000002 +#ifdef CONFIG_KEXEC_HARDBOOT +#define KEXEC_HARDBOOT 0x00000004 +#endif #define KEXEC_ARCH_MASK 0xffff0000 /* These values match the ELF architecture values. @@ -196,10 +202,14 @@ extern struct kimage *kexec_crash_image; #define KEXEC_ARCH_MIPS ( 8 << 16) /* List of defined/legal kexec flags */ -#ifndef CONFIG_KEXEC_JUMP -#define KEXEC_FLAGS KEXEC_ON_CRASH -#else +#if defined(CONFIG_KEXEC_JUMP) && defined(CONFIG_KEXEC_HARDBOOT) +#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT | KEXEC_HARDBOOT) +#elif defined(CONFIG_KEXEC_JUMP) #define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT) +#elif defined(CONFIG_KEXEC_HARDBOOT) +#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_HARDBOOT) +#else +#define KEXEC_FLAGS (KEXEC_ON_CRASH) #endif #define VMCOREINFO_BYTES (4096) diff --git a/include/linux/leds-pm8xxx.h b/include/linux/leds-pm8xxx.h index f6430275b5c..5b9acd8042f 100644 --- a/include/linux/leds-pm8xxx.h +++ b/include/linux/leds-pm8xxx.h @@ -55,6 +55,30 @@ enum pm8xxx_led_modes { PM8XXX_LED_MODE_DTEST4 }; +enum pm8xxx_led_pats { + PM8XXX_LED_PAT1_RED = 0, + PM8XXX_LED_PAT1_GREEN, + PM8XXX_LED_PAT2_RED, + PM8XXX_LED_PAT2_GREEN, + PM8XXX_LED_PAT3_RED, + PM8XXX_LED_PAT3_GREEN, + PM8XXX_LED_PAT3_BLUE, + PM8XXX_LED_PAT4_RED, + PM8XXX_LED_PAT4_GREEN, + PM8XXX_LED_PAT5_RED, + PM8XXX_LED_PAT5_GREEN, + PM8XXX_LED_PAT5_BLUE, + PM8XXX_LED_PAT6_GREEN, + PM8XXX_LED_PAT6_BLUE, + PM8XXX_LED_PAT7_RED, + PM8XXX_LED_PAT7_GREEN, + PM8XXX_LED_PAT7_BLUE, + PM8XXX_LED_PAT8_RED, + PM8XXX_LED_PAT8_GREEN, + PM8XXX_LED_PAT8_BLUE, + PM8XXX_LED_KB_LED, +}; + /* current boost limit */ enum wled_current_bost_limit { WLED_CURR_LIMIT_105mA, @@ -136,5 +160,7 @@ struct pm8xxx_led_platform_data { struct pm8xxx_led_config *configs; u32 num_configs; int use_pwm; + void (*led_power_on)(int); }; +extern struct class *sec_class; #endif /* __LEDS_PM8XXX_H__ */ diff --git a/include/linux/max17040_battery.h b/include/linux/max17040_battery.h index ad97b06cf93..c53ab29128b 100644 --- a/include/linux/max17040_battery.h +++ b/include/linux/max17040_battery.h @@ -14,6 +14,51 @@ struct max17040_platform_data { int (*battery_online)(void); int (*charger_online)(void); int (*charger_enable)(void); + int (*low_batt_cb)(void); + void (*hw_init)(void); + int (*check_batt_type)(void); + u16 rcomp_value; }; +#define BATT_TYPE_NORMAL 0 /* 4.2V battery */ +#define BATT_TYPE_JAGUAR 1 /* 4.35V, new active battery */ +#define BATT_TYPE_D2_HIGH 2 /* 4.35V battery */ +#define BATT_TYPE_D2_ACTIVE 3 /* 4.35V, new active battery */ +#define BATT_TYPE_AEGIS2 4 /* 4.35V, new active battery */ +#define BATT_TYPE_GOGH 5 /* 4.35V, new active battery */ +#define BATT_TYPE_INFINITE 5 /* 4.35V, new active battery */ + +/* fuelgauge tuning */ +/* SOC accuracy depends on RCOMP and Adjusted SOC Method(below values) */ +/* you should fix these values for your MODEL */ +#if defined(CONFIG_MACH_JAGUAR) +#define EMPTY_COND_SOC 100 +#define EMPTY_SOC 30 +#define FULL_SOC_DEFAULT 9800 +#define FULL_SOC_LOW 9700 +#define FULL_SOC_HIGH 10000 +#define FULL_KEEP_SOC 50 +#define RCOMP0_TEMP 20 /* 'C */ +#elif defined(CONFIG_MACH_M2_ATT) || defined(CONFIG_MACH_M2_SPR) || \ + defined(CONFIG_MACH_M2_VZW) || defined(CONFIG_MACH_M2_SKT) || \ + defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_GOGH) || \ + defined(CONFIG_MACH_JASPER) || defined(CONFIG_MACH_AEGIS2) || \ + defined(CONFIG_MACH_INFINITE) || defined(CONFIG_MACH_K2_KDI) +#define EMPTY_COND_SOC 100 +#define EMPTY_SOC 30 +#define FULL_SOC_DEFAULT 9860 +#define FULL_SOC_LOW 9760 +#define FULL_SOC_HIGH 10000 +#define FULL_KEEP_SOC 50 +#define RCOMP0_TEMP 20 /* 'C */ +#else +#define EMPTY_COND_SOC 100 +#define EMPTY_SOC 20 +#define FULL_SOC_DEFAULT 9400 +#define FULL_SOC_LOW 9300 +#define FULL_SOC_HIGH 9650 +#define FULL_KEEP_SOC 50 +#define RCOMP0_TEMP 20 /* 'C */ +#endif + #endif diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h index 785a33aa26c..69a871b1062 100644 --- a/include/linux/mfd/pm8xxx/pm8921-charger.h +++ b/include/linux/mfd/pm8xxx/pm8921-charger.h @@ -145,6 +145,7 @@ enum pm8921_chg_led_src_config { */ struct pm8921_charger_platform_data { struct pm8xxx_charger_core_data charger_cdata; + unsigned int safety_time; unsigned int ttrkl_time; unsigned int update_time; unsigned int max_voltage; @@ -181,6 +182,7 @@ struct pm8921_charger_platform_data { enum pm8921_chg_hot_thr hot_thr; int rconn_mohm; enum pm8921_chg_led_src_config led_src_config; + int eoc_check_soc; int battery_less_hardware; int btc_override; int btc_override_cold_degc; @@ -188,6 +190,9 @@ struct pm8921_charger_platform_data { int btc_delay_ms; int btc_panic_if_cant_stop_chg; int stop_chg_upon_expiry; +#ifdef CONFIG_PM8921_SEC_CHARGER + int (*get_cable_type)(void); +#endif }; enum pm8921_charger_source { diff --git a/include/linux/mfd/pm8xxx/pm8921-sec-charger.h b/include/linux/mfd/pm8xxx/pm8921-sec-charger.h new file mode 100644 index 00000000000..1eb63fd2100 --- /dev/null +++ b/include/linux/mfd/pm8xxx/pm8921-sec-charger.h @@ -0,0 +1,116 @@ +/* + * include/linux/mfd/pm8xxx/pm8921-sec-charger.h + * + * Copyright (c) 2011 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __PM8XXX_SEC_CHARGER_H +#define __PM8XXX_SEC_CHARGER_H + +/******************************************* +** Feature definition +********************************************/ +#undef QUALCOMM_TEMPERATURE_CONTROL +#undef QUALCOMM_POWERSUPPLY_PROPERTY + +/******************************************* +** Other definition +*******************************************/ +#if defined(CONFIG_BATTERY_MAX17040) || \ + defined(CONFIG_BATTERY_MAX17042) +#define RCOMP0_TEMP 20 /* 'C */ + +#define FG_T_SOC 0 +#define FG_T_VCELL 1 +#define FG_T_PSOC 2 +#define FG_T_RCOMP 3 +#define FG_T_FSOC 4 +#define FG_RESET 5 +#endif + +enum cable_type_t { + CABLE_TYPE_NONE = 0, + CABLE_TYPE_USB, + CABLE_TYPE_AC, + CABLE_TYPE_MISC, + CABLE_TYPE_CARDOCK, + CABLE_TYPE_UARTOFF, + CABLE_TYPE_JIG, + CABLE_TYPE_UNKNOWN, + CABLE_TYPE_CDP, + CABLE_TYPE_SMART_DOCK, +#ifdef CONFIG_WIRELESS_CHARGING + CABLE_TYPE_WPC = 10, +#endif +}; + +#define VUBS_IN_CURR_NONE 2 +#define VBUS_IN_CURR_USB 500 +#define BATT_IN_CURR_USB 475 +#define VBUS_IN_CURR_TA 1100 +#define BATT_IN_CURR_TA 1025 +#ifdef CONFIG_WIRELESS_CHARGING +#define VBUS_IN_CURR_WPC 700 +#define BATT_IN_CURR_WPC 675 +#endif + +#define TEMP_GPIO PM8XXX_AMUX_MPP_7 +#define TEMP_ADC_CHNNEL ADC_MPP_1_AMUX6 + +static const int temper_table[][2] = { + {1600, -200}, + {1550, -150}, + {1500, -100}, + {1400, -50}, + {1300, 0}, + {1150, 100}, + {1050, 150}, + {950, 200}, + {850, 250}, + {750, 300}, + {650, 350}, + {600, 400}, + {500, 450}, + {400, 500}, + {330, 550}, + {300, 600}, +}; + +/******************************************* +** for Debug screen +*****************************************/ +struct pm8921_reg { + u8 chg_cntrl; + u8 chg_cntrl_2; + u8 chg_cntrl_3; + u8 pbl_access1; + u8 pbl_access2; + u8 sys_config_1; + u8 sys_config_2; + u8 chg_vdd_max; + u8 chg_vdd_safe; + u8 chg_ibat_max; + u8 chg_ibat_safe; + u8 chg_iterm; +}; +struct pm8921_irq { + int usbin_valid; + int usbin_ov; + int usbin_uv; + int batttemp_hot; + int batttemp_cold; + int batt_inserted; + int trklchg; + int fastchg; + int batfet; + int batt_removed; + int vcp; + int bat_temp_ok; +}; + + +#endif diff --git a/include/linux/mfd/pm8xxx/pm8xxx-adc.h b/include/linux/mfd/pm8xxx/pm8xxx-adc.h index f40633a0d29..71d030f32ac 100644 --- a/include/linux/mfd/pm8xxx/pm8xxx-adc.h +++ b/include/linux/mfd/pm8xxx/pm8xxx-adc.h @@ -95,6 +95,9 @@ enum pm8xxx_adc_channels { ADC_MPP_2_ATEST_5, ADC_MPP_2_ATEST_6, ADC_MPP_2_ATEST_7, +#ifdef CONFIG_SAMSUNG_JACK + ADC_MPP_1_AMUX6_SCALE_DEFAULT, +#endif ADC_CHANNEL_MAX_NUM, }; @@ -216,6 +219,7 @@ enum pm8xxx_adc_scale_fn_type { ADC_SCALE_PA_THERM, ADC_SCALE_PMIC_THERM, ADC_SCALE_XOTHERM, + ADC_SCALE_SEC_BOARD_THERM, ADC_SCALE_NONE, }; @@ -399,6 +403,22 @@ int32_t pm8xxx_adc_scale_batt_id(int32_t adc_code, const struct pm8xxx_adc_properties *adc_prop, const struct pm8xxx_adc_chan_properties *chan_prop, struct pm8xxx_adc_chan_result *chan_rslt); + +/** + * pm8xxx_adc_sec_board_therm_default() - Scales the pre-calibrated digital output + * of an ADC to the ADC reference and compensates for the + * gain and offset. + * @adc_code: pre-calibrated digital ouput of the ADC. + * @adc_prop: adc properties of the pm8xxx adc such as bit resolution, + * reference voltage. + * @chan_prop: individual channel properties to compensate the i/p scaling, + * slope and offset. + * @chan_rslt: physical result to be stored. + */ +int32_t pm8xxx_adc_sec_board_therm_default(int32_t adc_code, + const struct pm8xxx_adc_properties *adc_prop, + const struct pm8xxx_adc_chan_properties *chan_prop, + struct pm8xxx_adc_chan_result *chan_rslt); #else static inline int32_t pm8xxx_adc_scale_default(int32_t adc_code, const struct pm8xxx_adc_properties *adc_prop, @@ -430,6 +450,12 @@ static inline int32_t pm8xxx_adc_scale_batt_id(int32_t adc_code, const struct pm8xxx_adc_chan_properties *chan_prop, struct pm8xxx_adc_chan_result *chan_rslt) { return -ENXIO; } + +int32_t pm8xxx_adc_sec_board_therm_default(int32_t adc_code, + const struct pm8xxx_adc_properties *adc_prop, + const struct pm8xxx_adc_chan_properties *chan_prop, + struct pm8xxx_adc_chan_result *chan_rslt) +{ return -ENXIO; } #endif /** @@ -600,5 +626,5 @@ static inline uint32_t pm8xxx_adc_btm_configure( struct pm8xxx_adc_arb_btm_param *param) { return -ENXIO; } #endif - +int pm8921_enable_batt_therm(u8 en); #endif /* PM8XXX_ADC_H */ diff --git a/include/linux/mfd/wcd9310/Kbuild b/include/linux/mfd/wcd9310/Kbuild new file mode 100644 index 00000000000..2702ec6d0ce --- /dev/null +++ b/include/linux/mfd/wcd9310/Kbuild @@ -0,0 +1 @@ +header-y += registers.h diff --git a/include/linux/mfd/wcd9310/core.h b/include/linux/mfd/wcd9310/core.h new file mode 100644 index 00000000000..bebc84031ac --- /dev/null +++ b/include/linux/mfd/wcd9310/core.h @@ -0,0 +1,149 @@ +/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __MFD_TABLA_CORE_H__ +#define __MFD_TABLA_CORE_H__ + +#include +#include + +#define TABLA_NUM_IRQ_REGS 3 + +#define TABLA_SLIM_NUM_PORT_REG 3 + +#define TABLA_INTERFACE_TYPE_SLIMBUS 0x00 +#define TABLA_INTERFACE_TYPE_I2C 0x01 + +#define TABLA_VERSION_1_0 0 +#define TABLA_VERSION_1_1 1 +#define TABLA_VERSION_2_0 2 +#define TABLA_IS_1_X(ver) \ + (((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0) +#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0) + +enum { + TABLA_IRQ_SLIMBUS = 0, + TABLA_IRQ_MBHC_REMOVAL, + TABLA_IRQ_MBHC_SHORT_TERM, + TABLA_IRQ_MBHC_PRESS, + TABLA_IRQ_MBHC_RELEASE, + TABLA_IRQ_MBHC_POTENTIAL, + TABLA_IRQ_MBHC_INSERTION, + TABLA_IRQ_BG_PRECHARGE, + TABLA_IRQ_PA1_STARTUP, + TABLA_IRQ_PA2_STARTUP, + TABLA_IRQ_PA3_STARTUP, + TABLA_IRQ_PA4_STARTUP, + TABLA_IRQ_PA5_STARTUP, + TABLA_IRQ_MICBIAS1_PRECHARGE, + TABLA_IRQ_MICBIAS2_PRECHARGE, + TABLA_IRQ_MICBIAS3_PRECHARGE, + TABLA_IRQ_HPH_PA_OCPL_FAULT, + TABLA_IRQ_HPH_PA_OCPR_FAULT, + TABLA_IRQ_EAR_PA_OCPL_FAULT, + TABLA_IRQ_HPH_L_PA_STARTUP, + TABLA_IRQ_HPH_R_PA_STARTUP, + TABLA_IRQ_EAR_PA_STARTUP, + TABLA_NUM_IRQS, +}; + +enum tabla_pm_state { + TABLA_PM_SLEEPABLE, + TABLA_PM_AWAKE, + TABLA_PM_ASLEEP, +}; + +struct tabla { + struct device *dev; + struct slim_device *slim; + struct slim_device *slim_slave; + struct mutex io_lock; + struct mutex xfer_lock; + struct mutex irq_lock; + u8 version; + + unsigned int irq_base; + unsigned int irq; + u8 irq_masks_cur[TABLA_NUM_IRQ_REGS]; + u8 irq_masks_cache[TABLA_NUM_IRQ_REGS]; + u8 irq_level[TABLA_NUM_IRQ_REGS]; + + int reset_gpio; + + int (*read_dev)(struct tabla *tabla, unsigned short reg, + int bytes, void *dest, bool interface_reg); + int (*write_dev)(struct tabla *tabla, unsigned short reg, + int bytes, void *src, bool interface_reg); + + struct regulator_bulk_data *supplies; + + enum tabla_pm_state pm_state; + struct mutex pm_lock; + /* pm_wq notifies change of pm_state */ + wait_queue_head_t pm_wq; + struct wake_lock wlock; + int wlock_holders; +}; + +int tabla_reg_read(struct tabla *tabla, unsigned short reg); +int tabla_reg_write(struct tabla *tabla, unsigned short reg, u8 val); +int tabla_interface_reg_read(struct tabla *tabla, unsigned short reg); +int tabla_interface_reg_write(struct tabla *tabla, unsigned short reg, u8 val); +int tabla_bulk_read(struct tabla *tabla, unsigned short reg, int count, + u8 *buf); +int tabla_bulk_write(struct tabla *tabla, unsigned short reg, int count, + u8 *buf); +int tabla_irq_init(struct tabla *tabla); +void tabla_irq_exit(struct tabla *tabla); +int tabla_get_logical_addresses(u8 *pgd_la, u8 *inf_la); +int tabla_get_intf_type(void); + +bool tabla_lock_sleep(struct tabla *tabla); +void tabla_unlock_sleep(struct tabla *tabla); +enum tabla_pm_state tabla_pm_cmpxchg(struct tabla *tabla, enum tabla_pm_state o, + enum tabla_pm_state n); + +static inline int tabla_request_irq(struct tabla *tabla, int irq, + irq_handler_t handler, const char *name, + void *data) +{ + if (!tabla->irq_base) + return -EINVAL; + return request_threaded_irq(tabla->irq_base + irq, NULL, handler, + IRQF_TRIGGER_RISING, name, + data); +} +static inline void tabla_free_irq(struct tabla *tabla, int irq, void *data) +{ + if (!tabla->irq_base) + return; + free_irq(tabla->irq_base + irq, data); +} +static inline void tabla_enable_irq(struct tabla *tabla, int irq) +{ + if (!tabla->irq_base) + return; + enable_irq(tabla->irq_base + irq); +} +static inline void tabla_disable_irq(struct tabla *tabla, int irq) +{ + if (!tabla->irq_base) + return; + disable_irq_nosync(tabla->irq_base + irq); +} +static inline void tabla_disable_irq_sync(struct tabla *tabla, int irq) +{ + if (!tabla->irq_base) + return; + disable_irq(tabla->irq_base + irq); +} +#endif diff --git a/include/linux/mfd/wcd9310/pdata.h b/include/linux/mfd/wcd9310/pdata.h new file mode 100644 index 00000000000..1d15d663a52 --- /dev/null +++ b/include/linux/mfd/wcd9310/pdata.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __MFD_TABLA_PDATA_H__ + +#define __MFD_TABLA_PDATA_H__ + +#include + +#define TABLA_LDOH_1P95_V 0x0 +#define TABLA_LDOH_2P35_V 0x1 +#define TABLA_LDOH_2P75_V 0x2 +#define TABLA_LDOH_2P85_V 0x3 + +#define TABLA_CFILT1_SEL 0x0 +#define TABLA_CFILT2_SEL 0x1 +#define TABLA_CFILT3_SEL 0x2 + +#define MAX_AMIC_CHANNEL 7 + +#define TABLA_OCP_300_MA 0x0 +#define TABLA_OCP_350_MA 0x2 +#define TABLA_OCP_365_MA 0x3 +#define TABLA_OCP_150_MA 0x4 +#define TABLA_OCP_190_MA 0x6 +#define TABLA_OCP_220_MA 0x7 + +#define TABLA_DCYCLE_255 0x0 +#define TABLA_DCYCLE_511 0x1 +#define TABLA_DCYCLE_767 0x2 +#define TABLA_DCYCLE_1023 0x3 +#define TABLA_DCYCLE_1279 0x4 +#define TABLA_DCYCLE_1535 0x5 +#define TABLA_DCYCLE_1791 0x6 +#define TABLA_DCYCLE_2047 0x7 +#define TABLA_DCYCLE_2303 0x8 +#define TABLA_DCYCLE_2559 0x9 +#define TABLA_DCYCLE_2815 0xA +#define TABLA_DCYCLE_3071 0xB +#define TABLA_DCYCLE_3327 0xC +#define TABLA_DCYCLE_3583 0xD +#define TABLA_DCYCLE_3839 0xE +#define TABLA_DCYCLE_4095 0xF + +struct tabla_amic { + /*legacy mode, txfe_enable and txfe_buff take 7 input + * each bit represent the channel / TXFE number + * and numbered as below + * bit 0 = channel 1 / TXFE1_ENABLE / TXFE1_BUFF + * bit 1 = channel 2 / TXFE2_ENABLE / TXFE2_BUFF + * ... + * bit 7 = channel 7 / TXFE7_ENABLE / TXFE7_BUFF + */ + u8 legacy_mode:MAX_AMIC_CHANNEL; + u8 txfe_enable:MAX_AMIC_CHANNEL; + u8 txfe_buff:MAX_AMIC_CHANNEL; + u8 use_pdata:MAX_AMIC_CHANNEL; +}; + +/* Each micbias can be assigned to one of three cfilters + * Vbatt_min >= .15V + ldoh_v + * ldoh_v >= .15v + cfiltx_mv + * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv + * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv + * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv + * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv + */ + +struct tabla_micbias_setting { + u8 ldoh_v; + u32 cfilt1_mv; /* in mv */ + u32 cfilt2_mv; /* in mv */ + u32 cfilt3_mv; /* in mv */ + u8 bias1_cfilt_sel; + u8 bias2_cfilt_sel; + u8 bias3_cfilt_sel; + u8 bias4_cfilt_sel; +}; + +struct tabla_ocp_setting { + unsigned int use_pdata:1; /* 0 - use sys default as recommended */ + unsigned int num_attempts:4; /* up to 15 attempts */ + unsigned int run_time:4; /* in duty cycle */ + unsigned int wait_time:4; /* in duty cycle */ + unsigned int hph_ocp_limit:3; /* Headphone OCP current limit */ +}; + +#define MAX_REGULATOR 6 +/* + * format : TABLA__CUR_MAX + * + * from Tabla objective spec +*/ + +#define WCD9XXX_CDC_VDDA_CP_CUR_MAX 500000 +#define WCD9XXX_CDC_VDDA_RX_CUR_MAX 20000 +#define WCD9XXX_CDC_VDDA_TX_CUR_MAX 20000 +#define WCD9XXX_VDDIO_CDC_CUR_MAX 5000 + +#define WCD9XXX_VDDD_CDC_D_CUR_MAX 5000 +#define WCD9XXX_VDDD_CDC_A_CUR_MAX 5000 + +struct wcd9310_regulator { + const char *name; + int min_uV; + int max_uV; + int optimum_uA; + struct regulator *regulator; +}; + +struct tabla_pdata { + int irq; + int irq_base; + int num_irqs; + int reset_gpio; + struct tabla_amic amic_settings; + struct slim_device slimbus_slave_device; + struct tabla_micbias_setting micbias; + struct tabla_ocp_setting ocp; + struct wcd9310_regulator regulator[MAX_REGULATOR]; +}; + +#endif diff --git a/include/linux/mfd/wcd9310/registers.h b/include/linux/mfd/wcd9310/registers.h new file mode 100644 index 00000000000..4be371cc016 --- /dev/null +++ b/include/linux/mfd/wcd9310/registers.h @@ -0,0 +1,1073 @@ +#ifndef TABLA_CODEC_DIGITAL_H + +#define TABLA_CODEC_DIGITAL_H + +#define TABLA_A_CHIP_CTL (0x00) +#define TABLA_A_CHIP_CTL__POR (0x00000000) +#define TABLA_A_CHIP_STATUS (0x01) +#define TABLA_A_CHIP_STATUS__POR (0x00000000) +#define TABLA_A_CHIP_ID_BYTE_0 (0x04) +#define TABLA_A_CHIP_ID_BYTE_0__POR (0x00000000) +#define TABLA_A_CHIP_ID_BYTE_1 (0x05) +#define TABLA_A_CHIP_ID_BYTE_1__POR (0x00000000) +#define TABLA_A_CHIP_ID_BYTE_2 (0x06) +#define TABLA_A_CHIP_ID_BYTE_2__POR (0x00000000) +#define TABLA_A_CHIP_ID_BYTE_3 (0x07) +#define TABLA_A_CHIP_ID_BYTE_3__POR (0x00000001) +#define TABLA_A_CHIP_VERSION (0x08) +#define TABLA_A_CHIP_VERSION__POR (0x00000020) +#define TABLA_A_SB_VERSION (0x09) +#define TABLA_A_SB_VERSION__POR (0x00000010) +#define TABLA_A_SLAVE_ID_1 (0x0C) +#define TABLA_A_SLAVE_ID_1__POR (0x00000077) +#define TABLA_A_SLAVE_ID_2 (0x0D) +#define TABLA_A_SLAVE_ID_2__POR (0x00000066) +#define TABLA_A_SLAVE_ID_3 (0x0E) +#define TABLA_A_SLAVE_ID_3__POR (0x00000055) +#define TABLA_A_PIN_CTL_OE0 (0x10) +#define TABLA_A_PIN_CTL_OE0__POR (0x00000000) +#define TABLA_A_PIN_CTL_OE1 (0x11) +#define TABLA_A_PIN_CTL_OE1__POR (0x00000000) +#define TABLA_A_PIN_CTL_DATA0 (0x12) +#define TABLA_A_PIN_CTL_DATA0__POR (0x00000000) +#define TABLA_A_PIN_CTL_DATA1 (0x13) +#define TABLA_A_PIN_CTL_DATA1__POR (0x00000000) +#define TABLA_A_HDRIVE_GENERIC (0x18) +#define TABLA_A_HDRIVE_GENERIC__POR (0x00000000) +#define TABLA_A_HDRIVE_OVERRIDE (0x19) +#define TABLA_A_HDRIVE_OVERRIDE__POR (0x00000008) +#define TABLA_A_ANA_CSR_WAIT_STATE (0x20) +#define TABLA_A_ANA_CSR_WAIT_STATE__POR (0x00000044) +#define TABLA_A_PROCESS_MONITOR_CTL0 (0x40) +#define TABLA_A_PROCESS_MONITOR_CTL0__POR (0x00000080) +#define TABLA_A_PROCESS_MONITOR_CTL1 (0x41) +#define TABLA_A_PROCESS_MONITOR_CTL1__POR (0x00000000) +#define TABLA_A_PROCESS_MONITOR_CTL2 (0x42) +#define TABLA_A_PROCESS_MONITOR_CTL2__POR (0x00000000) +#define TABLA_A_PROCESS_MONITOR_CTL3 (0x43) +#define TABLA_A_PROCESS_MONITOR_CTL3__POR (0x00000001) +#define TABLA_A_QFUSE_CTL (0x48) +#define TABLA_A_QFUSE_CTL__POR (0x00000000) +#define TABLA_A_QFUSE_STATUS (0x49) +#define TABLA_A_QFUSE_STATUS__POR (0x00000000) +#define TABLA_A_QFUSE_DATA_OUT0 (0x4A) +#define TABLA_A_QFUSE_DATA_OUT0__POR (0x00000000) +#define TABLA_A_QFUSE_DATA_OUT1 (0x4B) +#define TABLA_A_QFUSE_DATA_OUT1__POR (0x00000000) +#define TABLA_A_QFUSE_DATA_OUT2 (0x4C) +#define TABLA_A_QFUSE_DATA_OUT2__POR (0x00000000) +#define TABLA_A_QFUSE_DATA_OUT3 (0x4D) +#define TABLA_A_QFUSE_DATA_OUT3__POR (0x00000000) +#define TABLA_A_CDC_CTL (0x80) +#define TABLA_A_CDC_CTL__POR (0x00000000) +#define TABLA_A_LEAKAGE_CTL (0x88) +#define TABLA_A_LEAKAGE_CTL__POR (0x00000004) +#define TABLA_A_INTR_MODE (0x90) +#define TABLA_A_INTR_MODE__POR (0x00000000) +#define TABLA_A_INTR_MASK0 (0x94) +#define TABLA_A_INTR_MASK0__POR (0x000000ff) +#define TABLA_A_INTR_MASK1 (0x95) +#define TABLA_A_INTR_MASK1__POR (0x000000ff) +#define TABLA_A_INTR_MASK2 (0x96) +#define TABLA_A_INTR_MASK2__POR (0x000000ff) +#define TABLA_A_INTR_STATUS0 (0x98) +#define TABLA_A_INTR_STATUS0__POR (0x00000000) +#define TABLA_A_INTR_STATUS1 (0x99) +#define TABLA_A_INTR_STATUS1__POR (0x00000000) +#define TABLA_A_INTR_STATUS2 (0x9A) +#define TABLA_A_INTR_STATUS2__POR (0x00000000) +#define TABLA_A_INTR_CLEAR0 (0x9C) +#define TABLA_A_INTR_CLEAR0__POR (0x00000000) +#define TABLA_A_INTR_CLEAR1 (0x9D) +#define TABLA_A_INTR_CLEAR1__POR (0x00000000) +#define TABLA_A_INTR_CLEAR2 (0x9E) +#define TABLA_A_INTR_CLEAR2__POR (0x00000000) +#define TABLA_A_INTR_LEVEL0 (0xA0) +#define TABLA_A_INTR_LEVEL0__POR (0x00000001) +#define TABLA_A_INTR_LEVEL1 (0xA1) +#define TABLA_A_INTR_LEVEL1__POR (0x00000000) +#define TABLA_A_INTR_LEVEL2 (0xA2) +#define TABLA_A_INTR_LEVEL2__POR (0x00000000) +#define TABLA_A_INTR_TEST0 (0xA4) +#define TABLA_A_INTR_TEST0__POR (0x00000000) +#define TABLA_A_INTR_TEST1 (0xA5) +#define TABLA_A_INTR_TEST1__POR (0x00000000) +#define TABLA_A_INTR_TEST2 (0xA6) +#define TABLA_A_INTR_TEST2__POR (0x00000000) +#define TABLA_A_INTR_SET0 (0xA8) +#define TABLA_A_INTR_SET0__POR (0x00000000) +#define TABLA_A_INTR_SET1 (0xA9) +#define TABLA_A_INTR_SET1__POR (0x00000000) +#define TABLA_A_INTR_SET2 (0xAA) +#define TABLA_A_INTR_SET2__POR (0x00000000) +#define TABLA_A_CDC_TX_I2S_SCK_MODE (0xC0) +#define TABLA_A_CDC_TX_I2S_SCK_MODE__POR (0x00000000) +#define TABLA_A_CDC_TX_I2S_WS_MODE (0xC1) +#define TABLA_A_CDC_TX_I2S_WS_MODE__POR (0x00000000) +#define TABLA_A_CDC_DMIC_DATA0_MODE (0xC4) +#define TABLA_A_CDC_DMIC_DATA0_MODE__POR (0x00000000) +#define TABLA_A_CDC_DMIC_CLK0_MODE (0xC5) +#define TABLA_A_CDC_DMIC_CLK0_MODE__POR (0x00000000) +#define TABLA_A_CDC_DMIC_DATA1_MODE (0xC6) +#define TABLA_A_CDC_DMIC_DATA1_MODE__POR (0x00000000) +#define TABLA_A_CDC_DMIC_CLK1_MODE (0xC7) +#define TABLA_A_CDC_DMIC_CLK1_MODE__POR (0x00000000) +#define TABLA_A_CDC_RX_I2S_SCK_MODE (0xC8) +#define TABLA_A_CDC_RX_I2S_SCK_MODE__POR (0x00000000) +#define TABLA_A_CDC_RX_I2S_WS_MODE (0xC9) +#define TABLA_A_CDC_RX_I2S_WS_MODE__POR (0x00000000) +#define TABLA_A_CDC_DMIC_DATA2_MODE (0xCA) +#define TABLA_A_CDC_DMIC_DATA2_MODE__POR (0x00000000) +#define TABLA_A_CDC_DMIC_CLK2_MODE (0xCB) +#define TABLA_A_CDC_DMIC_CLK2_MODE__POR (0x00000000) +#define TABLA_A_CDC_INTR_MODE (0xCC) +#define TABLA_A_CDC_INTR_MODE__POR (0x00000000) +#define TABLA_A_BIAS_REF_CTL (0x0100) +#define TABLA_A_BIAS_REF_CTL__POR (0x0000001C) +#define TABLA_A_BIAS_CENTRAL_BG_CTL (0x0101) +#define TABLA_A_BIAS_CENTRAL_BG_CTL__POR (0x00000050) +#define TABLA_A_BIAS_PRECHRG_CTL (0x0102) +#define TABLA_A_BIAS_PRECHRG_CTL__POR (0x00000007) +#define TABLA_A_BIAS_CURR_CTL_1 (0x0103) +#define TABLA_A_BIAS_CURR_CTL_1__POR (0x00000052) +#define TABLA_A_BIAS_CURR_CTL_2 (0x0104) +#define TABLA_A_BIAS_CURR_CTL_2__POR (0x00000000) +#define TABLA_A_BIAS_CONFIG_MODE_BG_CTL (0x0105) +#define TABLA_A_BIAS_CONFIG_MODE_BG_CTL__POR (0x00000016) +#define TABLA_A_BIAS_BG_STATUS (0x0106) +#define TABLA_A_BIAS_BG_STATUS__POR (0x00000000) +#define TABLA_A_CLK_BUFF_EN1 (0x0108) +#define TABLA_A_CLK_BUFF_EN1__POR (0x00000004) +#define TABLA_A_CLK_BUFF_EN2 (0x0109) +#define TABLA_A_CLK_BUFF_EN2__POR (0x00000002) +#define TABLA_A_LDO_H_MODE_1 (0x0110) +#define TABLA_A_LDO_H_MODE_1__POR (0x00000065) +#define TABLA_A_LDO_H_MODE_2 (0x0111) +#define TABLA_A_LDO_H_MODE_2__POR (0x000000A8) +#define TABLA_A_LDO_H_LOOP_CTL (0x0112) +#define TABLA_A_LDO_H_LOOP_CTL__POR (0x0000006B) +#define TABLA_A_LDO_H_COMP_1 (0x0113) +#define TABLA_A_LDO_H_COMP_1__POR (0x00000084) +#define TABLA_A_LDO_H_COMP_2 (0x0114) +#define TABLA_A_LDO_H_COMP_2__POR (0x000000E0) +#define TABLA_A_LDO_H_BIAS_1 (0x0115) +#define TABLA_A_LDO_H_BIAS_1__POR (0x0000006D) +#define TABLA_A_LDO_H_BIAS_2 (0x0116) +#define TABLA_A_LDO_H_BIAS_2__POR (0x000000A5) +#define TABLA_A_LDO_H_BIAS_3 (0x0117) +#define TABLA_A_LDO_H_BIAS_3__POR (0x00000060) +#define TABLA_A_LDO_L_MODE_1 (0x0118) +#define TABLA_A_LDO_L_MODE_1__POR (0x00000028) +#define TABLA_A_LDO_L_MODE_2 (0x0119) +#define TABLA_A_LDO_L_MODE_2__POR (0x000000A8) +#define TABLA_A_LDO_L_LOOP_CTL (0x011A) +#define TABLA_A_LDO_L_LOOP_CTL__POR (0x0000006D) +#define TABLA_A_LDO_L_COMP_1 (0x011B) +#define TABLA_A_LDO_L_COMP_1__POR (0x00000031) +#define TABLA_A_LDO_L_COMP_2 (0x011C) +#define TABLA_A_LDO_L_COMP_2__POR (0x000000A0) +#define TABLA_A_LDO_L_BIAS_1 (0x011D) +#define TABLA_A_LDO_L_BIAS_1__POR (0x0000006D) +#define TABLA_A_LDO_L_BIAS_2 (0x011E) +#define TABLA_A_LDO_L_BIAS_2__POR (0x00000065) +#define TABLA_A_LDO_L_BIAS_3 (0x011F) +#define TABLA_A_LDO_L_BIAS_3__POR (0x00000050) +#define TABLA_A_MICB_CFILT_1_CTL (0x0128) +#define TABLA_A_MICB_CFILT_1_CTL__POR (0x00000040) +#define TABLA_A_MICB_CFILT_1_VAL (0x0129) +#define TABLA_A_MICB_CFILT_1_VAL__POR (0x00000080) +#define TABLA_A_MICB_CFILT_1_PRECHRG (0x012A) +#define TABLA_A_MICB_CFILT_1_PRECHRG__POR (0x00000038) +#define TABLA_A_MICB_1_CTL (0x012B) +#define TABLA_A_MICB_1_CTL__POR (0x00000016) +#define TABLA_A_MICB_1_INT_RBIAS (0x012C) +#define TABLA_A_MICB_1_INT_RBIAS__POR (0x00000000) +#define TABLA_A_MICB_1_MBHC (0x012D) +#define TABLA_A_MICB_1_MBHC__POR (0x00000001) +#define TABLA_A_MICB_CFILT_2_CTL (0x012E) +#define TABLA_A_MICB_CFILT_2_CTL__POR (0x00000040) +#define TABLA_A_MICB_CFILT_2_VAL (0x012F) +#define TABLA_A_MICB_CFILT_2_VAL__POR (0x00000080) +#define TABLA_A_MICB_CFILT_2_PRECHRG (0x0130) +#define TABLA_A_MICB_CFILT_2_PRECHRG__POR (0x00000038) +#define TABLA_A_MICB_2_CTL (0x0131) +#define TABLA_A_MICB_2_CTL__POR (0x00000016) +#define TABLA_A_MICB_2_INT_RBIAS (0x0132) +#define TABLA_A_MICB_2_INT_RBIAS__POR (0x00000000) +#define TABLA_A_MICB_2_MBHC (0x0133) +#define TABLA_A_MICB_2_MBHC__POR (0x00000000) +#define TABLA_A_MICB_CFILT_3_CTL (0x0134) +#define TABLA_A_MICB_CFILT_3_CTL__POR (0x00000040) +#define TABLA_A_MICB_CFILT_3_VAL (0x0135) +#define TABLA_A_MICB_CFILT_3_VAL__POR (0x00000080) +#define TABLA_A_MICB_CFILT_3_PRECHRG (0x0136) +#define TABLA_A_MICB_CFILT_3_PRECHRG__POR (0x00000038) +#define TABLA_A_MICB_3_CTL (0x0137) +#define TABLA_A_MICB_3_CTL__POR (0x00000016) +#define TABLA_A_MICB_3_INT_RBIAS (0x0138) +#define TABLA_A_MICB_3_INT_RBIAS__POR (0x00000000) +#define TABLA_A_MICB_3_MBHC (0x0139) +#define TABLA_A_MICB_3_MBHC__POR (0x00000000) +#define TABLA_1_A_MICB_4_CTL (0x013A) +#define TABLA_2_A_MICB_4_CTL (0x013D) +#define TABLA_A_MICB_4_CTL__POR (0x00000016) +#define TABLA_1_A_MICB_4_INT_RBIAS (0x013B) +#define TABLA_2_A_MICB_4_INT_RBIAS (0x013E) +#define TABLA_A_MICB_4_INT_RBIAS__POR (0x00000000) +#define TABLA_1_A_MICB_4_MBHC (0x013C) +#define TABLA_2_A_MICB_4_MBHC (0x013F) +#define TABLA_A_MICB_4_MBHC__POR (0x00000001) +#define TABLA_A_TX_COM_BIAS (0x014C) +#define TABLA_A_TX_COM_BIAS__POR (0x000000E0) +#define TABLA_A_MBHC_SCALING_MUX_1 (0x014E) +#define TABLA_A_MBHC_SCALING_MUX_1__POR (0x00000000) +#define TABLA_A_MBHC_SCALING_MUX_2 (0x014F) +#define TABLA_A_MBHC_SCALING_MUX_2__POR (0x00000080) +#define TABLA_A_TX_SUP_SWITCH_CTRL_1 (0x0151) +#define TABLA_A_TX_SUP_SWITCH_CTRL_1__POR (0x00000000) +#define TABLA_A_TX_SUP_SWITCH_CTRL_2 (0x0152) +#define TABLA_A_TX_SUP_SWITCH_CTRL_2__POR (0x00000080) +#define TABLA_A_TX_1_2_EN (0x0153) +#define TABLA_A_TX_1_2_EN__POR (0x00000000) +#define TABLA_A_TX_1_2_TEST_EN (0x0154) +#define TABLA_A_TX_1_2_TEST_EN__POR (0x000000CC) +#define TABLA_A_TX_1_2_ADC_CH1 (0x0155) +#define TABLA_A_TX_1_2_ADC_CH1__POR (0x00000044) +#define TABLA_A_TX_1_2_ADC_CH2 (0x0156) +#define TABLA_A_TX_1_2_ADC_CH2__POR (0x00000044) +#define TABLA_A_TX_1_2_ATEST_REFCTRL (0x0157) +#define TABLA_A_TX_1_2_ATEST_REFCTRL__POR (0x00000000) +#define TABLA_A_TX_1_2_TEST_CTL (0x0158) +#define TABLA_A_TX_1_2_TEST_CTL__POR (0x00000038) +#define TABLA_A_TX_1_2_TEST_BLOCK_EN (0x0159) +#define TABLA_A_TX_1_2_TEST_BLOCK_EN__POR (0x000000FF) +#define TABLA_A_TX_1_2_TXFE_CLKDIV (0x015A) +#define TABLA_A_TX_1_2_TXFE_CLKDIV__POR (0x000000EE) +#define TABLA_A_TX_1_2_SAR_ERR_CH1 (0x015B) +#define TABLA_A_TX_1_2_SAR_ERR_CH1__POR (0x00000000) +#define TABLA_A_TX_1_2_SAR_ERR_CH2 (0x015C) +#define TABLA_A_TX_1_2_SAR_ERR_CH2__POR (0x00000000) +#define TABLA_A_TX_3_4_EN (0x015D) +#define TABLA_A_TX_3_4_EN__POR (0x00000000) +#define TABLA_A_TX_3_4_TEST_EN (0x015E) +#define TABLA_A_TX_3_4_TEST_EN__POR (0x000000CC) +#define TABLA_A_TX_3_4_ADC_CH3 (0x015F) +#define TABLA_A_TX_3_4_ADC_CH3__POR (0x00000044) +#define TABLA_A_TX_3_4_ADC_CH4 (0x0160) +#define TABLA_A_TX_3_4_ADC_CH4__POR (0x00000044) +#define TABLA_A_TX_3_4_ATEST_REFCTRL (0x0161) +#define TABLA_A_TX_3_4_ATEST_REFCTRL__POR (0x00000000) +#define TABLA_A_TX_3_4_TEST_CTL (0x0162) +#define TABLA_A_TX_3_4_TEST_CTL__POR (0x00000038) +#define TABLA_A_TX_3_4_TEST_BLOCK_EN (0x0163) +#define TABLA_A_TX_3_4_TEST_BLOCK_EN__POR (0x000000FF) +#define TABLA_A_TX_3_4_TXFE_CKDIV (0x0164) +#define TABLA_A_TX_3_4_TXFE_CKDIV__POR (0x000000EE) +#define TABLA_A_TX_3_4_SAR_ERR_CH3 (0x0165) +#define TABLA_A_TX_3_4_SAR_ERR_CH3__POR (0x00000000) +#define TABLA_A_TX_3_4_SAR_ERR_CH4 (0x0166) +#define TABLA_A_TX_3_4_SAR_ERR_CH4__POR (0x00000000) +#define TABLA_A_TX_5_6_EN (0x0167) +#define TABLA_A_TX_5_6_EN__POR (0x00000000) +#define TABLA_A_TX_5_6_TEST_EN (0x0168) +#define TABLA_A_TX_5_6_TEST_EN__POR (0x000000CC) +#define TABLA_A_TX_5_6_ADC_CH5 (0x0169) +#define TABLA_A_TX_5_6_ADC_CH5__POR (0x00000044) +#define TABLA_A_TX_5_6_ADC_CH6 (0x016A) +#define TABLA_A_TX_5_6_ADC_CH6__POR (0x00000044) +#define TABLA_A_TX_5_6_ATEST_REFCTRL (0x016B) +#define TABLA_A_TX_5_6_ATEST_REFCTRL__POR (0x00000000) +#define TABLA_A_TX_5_6_TEST_CTL (0x016C) +#define TABLA_A_TX_5_6_TEST_CTL__POR (0x00000038) +#define TABLA_A_TX_5_6_TEST_BLOCK_EN (0x016D) +#define TABLA_A_TX_5_6_TEST_BLOCK_EN__POR (0x000000FF) +#define TABLA_A_TX_5_6_TXFE_CKDIV (0x016E) +#define TABLA_A_TX_5_6_TXFE_CKDIV__POR (0x000000EE) +#define TABLA_A_TX_5_6_SAR_ERR_CH5 (0x016F) +#define TABLA_A_TX_5_6_SAR_ERR_CH5__POR (0x00000000) +#define TABLA_A_TX_5_6_SAR_ERR_CH6 (0x0170) +#define TABLA_A_TX_5_6_SAR_ERR_CH6__POR (0x00000000) +#define TABLA_A_TX_7_MBHC_EN (0x0171) +#define TABLA_A_TX_7_MBHC_EN__POR (0x0000000C) +#define TABLA_A_TX_7_MBHC_ATEST_REFCTRL (0x0172) +#define TABLA_A_TX_7_MBHC_ATEST_REFCTRL__POR (0x00000000) +#define TABLA_A_TX_7_MBHC_ADC (0x0173) +#define TABLA_A_TX_7_MBHC_ADC__POR (0x00000044) +#define TABLA_A_TX_7_MBHC_TEST_CTL (0x0174) +#define TABLA_A_TX_7_MBHC_TEST_CTL__POR (0x00000038) +#define TABLA_A_TX_7_MBHC_SAR_ERR (0x0175) +#define TABLA_A_TX_7_MBHC_SAR_ERR__POR (0x00000000) +#define TABLA_A_TX_7_TXFE_CLKDIV (0x0176) +#define TABLA_A_TX_7_TXFE_CLKDIV__POR (0x0000001C) +#define TABLA_A_AUX_COM_CTL (0x0180) +#define TABLA_A_AUX_COM_CTL__POR (0x00000034) +#define TABLA_A_AUX_COM_ATEST (0x0181) +#define TABLA_A_AUX_COM_ATEST__POR (0x00000000) +#define TABLA_A_AUX_L_EN (0x0182) +#define TABLA_A_AUX_L_EN__POR (0x00000000) +#define TABLA_A_AUX_L_GAIN (0x0183) +#define TABLA_A_AUX_L_GAIN__POR (0x0000001F) +#define TABLA_A_AUX_L_PA_CONN (0x0184) +#define TABLA_A_AUX_L_PA_CONN__POR (0x00000000) +#define TABLA_A_AUX_L_PA_CONN_INV (0x0185) +#define TABLA_A_AUX_L_PA_CONN_INV__POR (0x00000000) +#define TABLA_A_AUX_R_EN (0x0186) +#define TABLA_A_AUX_R_EN__POR (0x00000000) +#define TABLA_A_AUX_R_GAIN (0x0187) +#define TABLA_A_AUX_R_GAIN__POR (0x0000001F) +#define TABLA_A_AUX_R_PA_CONN (0x0188) +#define TABLA_A_AUX_R_PA_CONN__POR (0x00000000) +#define TABLA_A_AUX_R_PA_CONN_INV (0x0189) +#define TABLA_A_AUX_R_PA_CONN_INV__POR (0x00000000) +#define TABLA_A_CP_EN (0x0192) +#define TABLA_A_CP_EN__POR (0x000000E6) +#define TABLA_A_CP_CLK (0x0193) +#define TABLA_A_CP_CLK__POR (0x00000029) +#define TABLA_A_CP_STATIC (0x0194) +#define TABLA_A_CP_STATIC__POR (0x00000010) +#define TABLA_A_CP_DCC1 (0x0195) +#define TABLA_A_CP_DCC1__POR (0x00000052) +#define TABLA_A_CP_DCC3 (0x0196) +#define TABLA_A_CP_DCC3__POR (0x00000001) +#define TABLA_A_CP_ATEST (0x0197) +#define TABLA_A_CP_ATEST__POR (0x00000000) +#define TABLA_A_CP_DTEST (0x0198) +#define TABLA_A_CP_DTEST__POR (0x00000000) +#define TABLA_A_RX_COM_TIMER_DIV (0x019E) +#define TABLA_A_RX_COM_TIMER_DIV__POR (0x000000E8) +#define TABLA_A_RX_COM_OCP_CTL (0x019F) +#define TABLA_A_RX_COM_OCP_CTL__POR (0x0000001F) +#define TABLA_A_RX_COM_OCP_COUNT (0x01A0) +#define TABLA_A_RX_COM_OCP_COUNT__POR (0x00000077) +#define TABLA_A_RX_COM_DAC_CTL (0x01A1) +#define TABLA_A_RX_COM_DAC_CTL__POR (0x00000000) +#define TABLA_A_RX_COM_BIAS (0x01A2) +#define TABLA_A_RX_COM_BIAS__POR (0x00000000) +#define TABLA_A_RX_HPH_BIAS_PA (0x01A6) +#define TABLA_A_RX_HPH_BIAS_PA__POR (0x000000AA) +#define TABLA_A_RX_HPH_BIAS_LDO (0x01A7) +#define TABLA_A_RX_HPH_BIAS_LDO__POR (0x00000086) +#define TABLA_A_RX_HPH_BIAS_CNP (0x01A8) +#define TABLA_A_RX_HPH_BIAS_CNP__POR (0x0000008A) +#define TABLA_A_RX_HPH_BIAS_WG (0x01A9) +#define TABLA_A_RX_HPH_BIAS_WG__POR (0x00000060) +#define TABLA_A_RX_HPH_OCP_CTL (0x01AA) +#define TABLA_A_RX_HPH_OCP_CTL__POR (0x000000E8) +#define TABLA_A_RX_HPH_CNP_EN (0x01AB) +#define TABLA_A_RX_HPH_CNP_EN__POR (0x00000080) +#define TABLA_A_RX_HPH_CNP_WG_CTL (0x01AC) +#define TABLA_A_RX_HPH_CNP_WG_CTL__POR (0x000000DC) +#define TABLA_A_RX_HPH_CNP_WG_TIME (0x01AD) +#define TABLA_A_RX_HPH_CNP_WG_TIME__POR (0x00000028) +#define TABLA_A_RX_HPH_L_GAIN (0x01AE) +#define TABLA_A_RX_HPH_L_GAIN__POR (0x00000000) +#define TABLA_A_RX_HPH_L_TEST (0x01AF) +#define TABLA_A_RX_HPH_L_TEST__POR (0x00000001) +#define TABLA_A_RX_HPH_L_PA_CTL (0x01B0) +#define TABLA_A_RX_HPH_L_PA_CTL__POR (0x00000040) +#define TABLA_A_RX_HPH_L_DAC_CTL (0x01B1) +#define TABLA_A_RX_HPH_L_DAC_CTL__POR (0x00000000) +#define TABLA_A_RX_HPH_L_ATEST (0x01B2) +#define TABLA_A_RX_HPH_L_ATEST__POR (0x00000000) +#define TABLA_A_RX_HPH_L_STATUS (0x01B3) +#define TABLA_A_RX_HPH_L_STATUS__POR (0x00000004) +#define TABLA_A_RX_HPH_R_GAIN (0x01B4) +#define TABLA_A_RX_HPH_R_GAIN__POR (0x00000000) +#define TABLA_A_RX_HPH_R_TEST (0x01B5) +#define TABLA_A_RX_HPH_R_TEST__POR (0x00000001) +#define TABLA_A_RX_HPH_R_PA_CTL (0x01B6) +#define TABLA_A_RX_HPH_R_PA_CTL__POR (0x00000040) +#define TABLA_A_RX_HPH_R_DAC_CTL (0x01B7) +#define TABLA_A_RX_HPH_R_DAC_CTL__POR (0x00000000) +#define TABLA_A_RX_HPH_R_ATEST (0x01B8) +#define TABLA_A_RX_HPH_R_ATEST__POR (0x00000000) +#define TABLA_A_RX_HPH_R_STATUS (0x01B9) +#define TABLA_A_RX_HPH_R_STATUS__POR (0x00000004) +#define TABLA_A_RX_EAR_BIAS_PA (0x01BA) +#define TABLA_A_RX_EAR_BIAS_PA__POR (0x000000AA) +#define TABLA_A_RX_EAR_BIAS_CMBUFF (0x01BB) +#define TABLA_A_RX_EAR_BIAS_CMBUFF__POR (0x000000A0) +#define TABLA_A_RX_EAR_EN (0x01BC) +#define TABLA_A_RX_EAR_EN__POR (0x00000000) +#define TABLA_A_RX_EAR_GAIN (0x01BD) +#define TABLA_A_RX_EAR_GAIN__POR (0x00000008) +#define TABLA_A_RX_EAR_CMBUFF (0x01BE) +#define TABLA_A_RX_EAR_CMBUFF__POR (0x00000000) +#define TABLA_A_RX_EAR_ICTL (0x01BF) +#define TABLA_A_RX_EAR_ICTL__POR (0x00000040) +#define TABLA_A_RX_EAR_CCOMP (0x01C0) +#define TABLA_A_RX_EAR_CCOMP__POR (0x00000008) +#define TABLA_A_RX_EAR_VCM (0x01C1) +#define TABLA_A_RX_EAR_VCM__POR (0x00000000) +#define TABLA_A_RX_EAR_CNP (0x01C2) +#define TABLA_A_RX_EAR_CNP__POR (0x00000080) +#define TABLA_A_RX_EAR_ATEST (0x01C3) +#define TABLA_A_RX_EAR_ATEST__POR (0x00000000) +#define TABLA_A_RX_EAR_STATUS (0x01C5) +#define TABLA_A_RX_EAR_STATUS__POR (0x00000004) +#define TABLA_A_RX_LINE_BIAS_PA (0x01C6) +#define TABLA_A_RX_LINE_BIAS_PA__POR (0x000000AA) +#define TABLA_A_RX_LINE_BIAS_DAC (0x01C7) +#define TABLA_A_RX_LINE_BIAS_DAC__POR (0x000000A0) +#define TABLA_A_RX_LINE_BIAS_CNP (0x01C8) +#define TABLA_A_RX_LINE_BIAS_CNP__POR (0x0000003A) +#define TABLA_A_RX_LINE_COM (0x01C9) +#define TABLA_A_RX_LINE_COM__POR (0x00000000) +#define TABLA_A_RX_LINE_CNP_EN (0x01CA) +#define TABLA_A_RX_LINE_CNP_EN__POR (0x00000080) +#define TABLA_A_RX_LINE_CNP_WG_CTL (0x01CB) +#define TABLA_A_RX_LINE_CNP_WG_CTL__POR (0x0000001C) +#define TABLA_A_RX_LINE_CNP_WG_TIME (0x01CC) +#define TABLA_A_RX_LINE_CNP_WG_TIME__POR (0x00000064) +#define TABLA_A_RX_LINE_1_GAIN (0x01CD) +#define TABLA_A_RX_LINE_1_GAIN__POR (0x00000000) +#define TABLA_A_RX_LINE_1_TEST (0x01CE) +#define TABLA_A_RX_LINE_1_TEST__POR (0x00000000) +#define TABLA_A_RX_LINE_1_DAC_CTL (0x01CF) +#define TABLA_A_RX_LINE_1_DAC_CTL__POR (0x0000000C) +#define TABLA_A_RX_LINE_1_STATUS (0x01D0) +#define TABLA_A_RX_LINE_1_STATUS__POR (0x00000000) +#define TABLA_A_RX_LINE_2_GAIN (0x01D1) +#define TABLA_A_RX_LINE_2_GAIN__POR (0x00000000) +#define TABLA_A_RX_LINE_2_TEST (0x01D2) +#define TABLA_A_RX_LINE_2_TEST__POR (0x00000000) +#define TABLA_A_RX_LINE_2_DAC_CTL (0x01D3) +#define TABLA_A_RX_LINE_2_DAC_CTL__POR (0x0000000C) +#define TABLA_A_RX_LINE_2_STATUS (0x01D4) +#define TABLA_A_RX_LINE_2_STATUS__POR (0x00000000) +#define TABLA_A_RX_LINE_3_GAIN (0x01D5) +#define TABLA_A_RX_LINE_3_GAIN__POR (0x00000000) +#define TABLA_A_RX_LINE_3_TEST (0x01D6) +#define TABLA_A_RX_LINE_3_TEST__POR (0x00000000) +#define TABLA_A_RX_LINE_3_DAC_CTL (0x01D7) +#define TABLA_A_RX_LINE_3_DAC_CTL__POR (0x0000000C) +#define TABLA_A_RX_LINE_3_STATUS (0x01D8) +#define TABLA_A_RX_LINE_3_STATUS__POR (0x00000000) +#define TABLA_A_RX_LINE_4_GAIN (0x01D9) +#define TABLA_A_RX_LINE_4_GAIN__POR (0x00000000) +#define TABLA_A_RX_LINE_4_TEST (0x01DA) +#define TABLA_A_RX_LINE_4_TEST__POR (0x00000000) +#define TABLA_A_RX_LINE_4_DAC_CTL (0x01DB) +#define TABLA_A_RX_LINE_4_DAC_CTL__POR (0x0000000C) +#define TABLA_A_RX_LINE_4_STATUS (0x01DC) +#define TABLA_A_RX_LINE_4_STATUS__POR (0x00000000) +#define TABLA_A_RX_LINE_5_GAIN (0x01DD) +#define TABLA_A_RX_LINE_5_GAIN__POR (0x00000000) +#define TABLA_A_RX_LINE_5_TEST (0x01DE) +#define TABLA_A_RX_LINE_5_TEST__POR (0x00000000) +#define TABLA_A_RX_LINE_5_DAC_CTL (0x01DF) +#define TABLA_A_RX_LINE_5_DAC_CTL__POR (0x0000000C) +#define TABLA_A_RX_LINE_5_STATUS (0x01E0) +#define TABLA_A_RX_LINE_5_STATUS__POR (0x00000000) +#define TABLA_A_RX_LINE_CNP_DBG (0x01EC) +#define TABLA_A_RX_LINE_CNP_DBG__POR (0x00000000) +#define TABLA_A_MBHC_HPH (0x01ED) +#define TABLA_A_MBHC_HPH__POR (0x00000048) +#define TABLA_A_CONFIG_MODE_FREQ (0x01F7) +#define TABLA_A_CONFIG_MODE_FREQ__POR (0x00000047) +#define TABLA_A_CONFIG_MODE_TEST (0x01F8) +#define TABLA_A_CONFIG_MODE_TEST__POR (0x0000000A) +#define TABLA_A_CONFIG_MODE_STATUS (0x01F9) +#define TABLA_A_CONFIG_MODE_STATUS__POR (0x0000001C) +#define TABLA_A_CONFIG_MODE_TUNER (0x01FA) +#define TABLA_A_CONFIG_MODE_TUNER__POR (0x00000000) +#define TABLA_A_CDC_ANC1_CTL (0x00000200) +#define TABLA_A_CDC_ANC1_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_CTL (0x00000280) +#define TABLA_A_CDC_ANC2_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC1_SHIFT (0x00000201) +#define TABLA_A_CDC_ANC1_SHIFT__POR (0x00000000) +#define TABLA_A_CDC_ANC2_SHIFT (0x00000281) +#define TABLA_A_CDC_ANC2_SHIFT__POR (0x00000000) +#define TABLA_A_CDC_ANC1_FILT1_B1_CTL (0x00000202) +#define TABLA_A_CDC_ANC1_FILT1_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_FILT1_B1_CTL (0x00000282) +#define TABLA_A_CDC_ANC2_FILT1_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC1_FILT1_B2_CTL (0x00000203) +#define TABLA_A_CDC_ANC1_FILT1_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_FILT1_B2_CTL (0x00000283) +#define TABLA_A_CDC_ANC2_FILT1_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC1_FILT1_B3_CTL (0x00000204) +#define TABLA_A_CDC_ANC1_FILT1_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_FILT1_B3_CTL (0x00000284) +#define TABLA_A_CDC_ANC2_FILT1_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC1_FILT1_B4_CTL (0x00000205) +#define TABLA_A_CDC_ANC1_FILT1_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_FILT1_B4_CTL (0x00000285) +#define TABLA_A_CDC_ANC2_FILT1_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC1_FILT2_B1_CTL (0x00000206) +#define TABLA_A_CDC_ANC1_FILT2_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_FILT2_B1_CTL (0x00000286) +#define TABLA_A_CDC_ANC2_FILT2_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC1_FILT2_B2_CTL (0x00000207) +#define TABLA_A_CDC_ANC1_FILT2_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_FILT2_B2_CTL (0x00000287) +#define TABLA_A_CDC_ANC2_FILT2_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC1_FILT2_B3_CTL (0x00000208) +#define TABLA_A_CDC_ANC1_FILT2_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_FILT2_B3_CTL (0x00000288) +#define TABLA_A_CDC_ANC2_FILT2_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC1_SPARE (0x00000209) +#define TABLA_A_CDC_ANC1_SPARE__POR (0x00000000) +#define TABLA_A_CDC_ANC2_SPARE (0x00000289) +#define TABLA_A_CDC_ANC2_SPARE__POR (0x00000000) +#define TABLA_A_CDC_ANC1_FILT3_CTL (0x0000020A) +#define TABLA_A_CDC_ANC1_FILT3_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_FILT3_CTL (0x0000028A) +#define TABLA_A_CDC_ANC2_FILT3_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC1_FILT4_CTL (0x0000020B) +#define TABLA_A_CDC_ANC1_FILT4_CTL__POR (0x00000000) +#define TABLA_A_CDC_ANC2_FILT4_CTL (0x0000028B) +#define TABLA_A_CDC_ANC2_FILT4_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX1_VOL_CTL_TIMER (0x00000220) +#define TABLA_A_CDC_TX1_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX2_VOL_CTL_TIMER (0x00000228) +#define TABLA_A_CDC_TX2_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX3_VOL_CTL_TIMER (0x00000230) +#define TABLA_A_CDC_TX3_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX4_VOL_CTL_TIMER (0x00000238) +#define TABLA_A_CDC_TX4_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX5_VOL_CTL_TIMER (0x00000240) +#define TABLA_A_CDC_TX5_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX6_VOL_CTL_TIMER (0x00000248) +#define TABLA_A_CDC_TX6_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX7_VOL_CTL_TIMER (0x00000250) +#define TABLA_A_CDC_TX7_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX8_VOL_CTL_TIMER (0x00000258) +#define TABLA_A_CDC_TX8_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX9_VOL_CTL_TIMER (0x00000260) +#define TABLA_A_CDC_TX9_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX10_VOL_CTL_TIMER (0x00000268) +#define TABLA_A_CDC_TX10_VOL_CTL_TIMER__POR (0x00000000) +#define TABLA_A_CDC_TX1_VOL_CTL_GAIN (0x00000221) +#define TABLA_A_CDC_TX1_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX2_VOL_CTL_GAIN (0x00000229) +#define TABLA_A_CDC_TX2_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX3_VOL_CTL_GAIN (0x00000231) +#define TABLA_A_CDC_TX3_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX4_VOL_CTL_GAIN (0x00000239) +#define TABLA_A_CDC_TX4_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX5_VOL_CTL_GAIN (0x00000241) +#define TABLA_A_CDC_TX5_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX6_VOL_CTL_GAIN (0x00000249) +#define TABLA_A_CDC_TX6_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX7_VOL_CTL_GAIN (0x00000251) +#define TABLA_A_CDC_TX7_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX8_VOL_CTL_GAIN (0x00000259) +#define TABLA_A_CDC_TX8_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX9_VOL_CTL_GAIN (0x00000261) +#define TABLA_A_CDC_TX9_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX10_VOL_CTL_GAIN (0x00000269) +#define TABLA_A_CDC_TX10_VOL_CTL_GAIN__POR (0x00000000) +#define TABLA_A_CDC_TX1_VOL_CTL_CFG (0x00000222) +#define TABLA_A_CDC_TX1_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX2_VOL_CTL_CFG (0x0000022A) +#define TABLA_A_CDC_TX2_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX3_VOL_CTL_CFG (0x00000232) +#define TABLA_A_CDC_TX3_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX4_VOL_CTL_CFG (0x0000023A) +#define TABLA_A_CDC_TX4_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX5_VOL_CTL_CFG (0x00000242) +#define TABLA_A_CDC_TX5_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX6_VOL_CTL_CFG (0x0000024A) +#define TABLA_A_CDC_TX6_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX7_VOL_CTL_CFG (0x00000252) +#define TABLA_A_CDC_TX7_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX8_VOL_CTL_CFG (0x0000025A) +#define TABLA_A_CDC_TX8_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX9_VOL_CTL_CFG (0x00000262) +#define TABLA_A_CDC_TX9_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX10_VOL_CTL_CFG (0x0000026A) +#define TABLA_A_CDC_TX10_VOL_CTL_CFG__POR (0x00000000) +#define TABLA_A_CDC_TX1_MUX_CTL (0x00000223) +#define TABLA_A_CDC_TX1_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX2_MUX_CTL (0x0000022B) +#define TABLA_A_CDC_TX2_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX3_MUX_CTL (0x00000233) +#define TABLA_A_CDC_TX3_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX4_MUX_CTL (0x0000023B) +#define TABLA_A_CDC_TX4_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX5_MUX_CTL (0x00000243) +#define TABLA_A_CDC_TX5_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX6_MUX_CTL (0x0000024B) +#define TABLA_A_CDC_TX6_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX7_MUX_CTL (0x00000253) +#define TABLA_A_CDC_TX7_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX8_MUX_CTL (0x0000025B) +#define TABLA_A_CDC_TX8_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX9_MUX_CTL (0x00000263) +#define TABLA_A_CDC_TX9_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX10_MUX_CTL (0x0000026B) +#define TABLA_A_CDC_TX10_MUX_CTL__POR (0x00000008) +#define TABLA_A_CDC_TX1_CLK_FS_CTL (0x00000224) +#define TABLA_A_CDC_TX1_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX2_CLK_FS_CTL (0x0000022C) +#define TABLA_A_CDC_TX2_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX3_CLK_FS_CTL (0x00000234) +#define TABLA_A_CDC_TX3_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX4_CLK_FS_CTL (0x0000023C) +#define TABLA_A_CDC_TX4_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX5_CLK_FS_CTL (0x00000244) +#define TABLA_A_CDC_TX5_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX6_CLK_FS_CTL (0x0000024C) +#define TABLA_A_CDC_TX6_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX7_CLK_FS_CTL (0x00000254) +#define TABLA_A_CDC_TX7_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX8_CLK_FS_CTL (0x0000025C) +#define TABLA_A_CDC_TX8_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX9_CLK_FS_CTL (0x00000264) +#define TABLA_A_CDC_TX9_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX10_CLK_FS_CTL (0x0000026C) +#define TABLA_A_CDC_TX10_CLK_FS_CTL__POR (0x00000003) +#define TABLA_A_CDC_TX1_DMIC_CTL (0x00000225) +#define TABLA_A_CDC_TX1_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX2_DMIC_CTL (0x0000022D) +#define TABLA_A_CDC_TX2_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX3_DMIC_CTL (0x00000235) +#define TABLA_A_CDC_TX3_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX4_DMIC_CTL (0x0000023D) +#define TABLA_A_CDC_TX4_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX5_DMIC_CTL (0x00000245) +#define TABLA_A_CDC_TX5_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX6_DMIC_CTL (0x0000024D) +#define TABLA_A_CDC_TX6_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX7_DMIC_CTL (0x00000255) +#define TABLA_A_CDC_TX7_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX8_DMIC_CTL (0x0000025D) +#define TABLA_A_CDC_TX8_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX9_DMIC_CTL (0x00000265) +#define TABLA_A_CDC_TX9_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_TX10_DMIC_CTL (0x0000026D) +#define TABLA_A_CDC_TX10_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_SRC1_PDA_CFG (0x000002A0) +#define TABLA_A_CDC_SRC1_PDA_CFG__POR (0x00000000) +#define TABLA_A_CDC_SRC2_PDA_CFG (0x000002A8) +#define TABLA_A_CDC_SRC2_PDA_CFG__POR (0x00000000) +#define TABLA_A_CDC_SRC1_FS_CTL (0x000002A1) +#define TABLA_A_CDC_SRC1_FS_CTL__POR (0x0000001b) +#define TABLA_A_CDC_SRC2_FS_CTL (0x000002A9) +#define TABLA_A_CDC_SRC2_FS_CTL__POR (0x0000001b) +#define TABLA_A_CDC_RX1_B1_CTL (0x000002B0) +#define TABLA_A_CDC_RX1_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX2_B1_CTL (0x000002B8) +#define TABLA_A_CDC_RX2_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX3_B1_CTL (0x000002C0) +#define TABLA_A_CDC_RX3_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX4_B1_CTL (0x000002C8) +#define TABLA_A_CDC_RX4_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX5_B1_CTL (0x000002D0) +#define TABLA_A_CDC_RX5_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX6_B1_CTL (0x000002D8) +#define TABLA_A_CDC_RX6_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX7_B1_CTL (0x000002E0) +#define TABLA_A_CDC_RX7_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX1_B2_CTL (0x000002B1) +#define TABLA_A_CDC_RX1_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX2_B2_CTL (0x000002B9) +#define TABLA_A_CDC_RX2_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX3_B2_CTL (0x000002C1) +#define TABLA_A_CDC_RX3_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX4_B2_CTL (0x000002C9) +#define TABLA_A_CDC_RX4_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX5_B2_CTL (0x000002D1) +#define TABLA_A_CDC_RX5_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX6_B2_CTL (0x000002D9) +#define TABLA_A_CDC_RX6_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX7_B2_CTL (0x000002E1) +#define TABLA_A_CDC_RX7_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX1_B3_CTL (0x000002B2) +#define TABLA_A_CDC_RX1_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX2_B3_CTL (0x000002BA) +#define TABLA_A_CDC_RX2_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX3_B3_CTL (0x000002C2) +#define TABLA_A_CDC_RX3_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX4_B3_CTL (0x000002CA) +#define TABLA_A_CDC_RX4_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX5_B3_CTL (0x000002D2) +#define TABLA_A_CDC_RX5_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX6_B3_CTL (0x000002DA) +#define TABLA_A_CDC_RX6_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX7_B3_CTL (0x000002E2) +#define TABLA_A_CDC_RX7_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX1_B4_CTL (0x000002B3) +#define TABLA_A_CDC_RX1_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX2_B4_CTL (0x000002BB) +#define TABLA_A_CDC_RX2_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX3_B4_CTL (0x000002C3) +#define TABLA_A_CDC_RX3_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX4_B4_CTL (0x000002CB) +#define TABLA_A_CDC_RX4_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX5_B4_CTL (0x000002D3) +#define TABLA_A_CDC_RX5_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX6_B4_CTL (0x000002DB) +#define TABLA_A_CDC_RX6_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX7_B4_CTL (0x000002E3) +#define TABLA_A_CDC_RX7_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX1_B5_CTL (0x000002B4) +#define TABLA_A_CDC_RX1_B5_CTL__POR (0x00000060) +#define TABLA_A_CDC_RX2_B5_CTL (0x000002BC) +#define TABLA_A_CDC_RX2_B5_CTL__POR (0x00000060) +#define TABLA_A_CDC_RX3_B5_CTL (0x000002C4) +#define TABLA_A_CDC_RX3_B5_CTL__POR (0x00000060) +#define TABLA_A_CDC_RX4_B5_CTL (0x000002CC) +#define TABLA_A_CDC_RX4_B5_CTL__POR (0x00000060) +#define TABLA_A_CDC_RX5_B5_CTL (0x000002D4) +#define TABLA_A_CDC_RX5_B5_CTL__POR (0x00000060) +#define TABLA_A_CDC_RX6_B5_CTL (0x000002DC) +#define TABLA_A_CDC_RX6_B5_CTL__POR (0x00000060) +#define TABLA_A_CDC_RX7_B5_CTL (0x000002E4) +#define TABLA_A_CDC_RX7_B5_CTL__POR (0x00000060) +#define TABLA_A_CDC_RX1_B6_CTL (0x000002B5) +#define TABLA_A_CDC_RX1_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX2_B6_CTL (0x000002BD) +#define TABLA_A_CDC_RX2_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX3_B6_CTL (0x000002C5) +#define TABLA_A_CDC_RX3_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX4_B6_CTL (0x000002CD) +#define TABLA_A_CDC_RX4_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX5_B6_CTL (0x000002D5) +#define TABLA_A_CDC_RX5_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX6_B6_CTL (0x000002DD) +#define TABLA_A_CDC_RX6_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX7_B6_CTL (0x000002E5) +#define TABLA_A_CDC_RX7_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX1_VOL_CTL_B1_CTL (0x000002B6) +#define TABLA_A_CDC_RX1_VOL_CTL_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX2_VOL_CTL_B1_CTL (0x000002BE) +#define TABLA_A_CDC_RX2_VOL_CTL_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX3_VOL_CTL_B1_CTL (0x000002C6) +#define TABLA_A_CDC_RX3_VOL_CTL_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX4_VOL_CTL_B1_CTL (0x000002CE) +#define TABLA_A_CDC_RX4_VOL_CTL_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX5_VOL_CTL_B1_CTL (0x000002D6) +#define TABLA_A_CDC_RX5_VOL_CTL_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX6_VOL_CTL_B1_CTL (0x000002DE) +#define TABLA_A_CDC_RX6_VOL_CTL_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX7_VOL_CTL_B1_CTL (0x000002E6) +#define TABLA_A_CDC_RX7_VOL_CTL_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX1_VOL_CTL_B2_CTL (0x000002B7) +#define TABLA_A_CDC_RX1_VOL_CTL_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX2_VOL_CTL_B2_CTL (0x000002BF) +#define TABLA_A_CDC_RX2_VOL_CTL_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX3_VOL_CTL_B2_CTL (0x000002C7) +#define TABLA_A_CDC_RX3_VOL_CTL_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX4_VOL_CTL_B2_CTL (0x000002CF) +#define TABLA_A_CDC_RX4_VOL_CTL_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX5_VOL_CTL_B2_CTL (0x000002D7) +#define TABLA_A_CDC_RX5_VOL_CTL_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX6_VOL_CTL_B2_CTL (0x000002DF) +#define TABLA_A_CDC_RX6_VOL_CTL_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_RX7_VOL_CTL_B2_CTL (0x000002E7) +#define TABLA_A_CDC_RX7_VOL_CTL_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_ANC_RESET_CTL (0x00000300) +#define TABLA_A_CDC_CLK_ANC_RESET_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_RX_RESET_CTL (0x00000301) +#define TABLA_A_CDC_CLK_RX_RESET_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_TX_RESET_B1_CTL (0x00000302) +#define TABLA_A_CDC_CLK_TX_RESET_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_TX_RESET_B2_CTL (0x00000303) +#define TABLA_A_CDC_CLK_TX_RESET_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_DMIC_CTL (0x00000304) +#define TABLA_A_CDC_CLK_DMIC_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_RX_I2S_CTL (0x00000305) +#define TABLA_A_CDC_CLK_RX_I2S_CTL__POR (0x00000003) +#define TABLA_A_CDC_CLK_TX_I2S_CTL (0x00000306) +#define TABLA_A_CDC_CLK_TX_I2S_CTL__POR (0x00000003) +#define TABLA_A_CDC_CLK_OTHR_RESET_CTL (0x00000307) +#define TABLA_A_CDC_CLK_OTHR_RESET_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL (0x00000308) +#define TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL (0x00000309) +#define TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_OTHR_CTL (0x0000030A) +#define TABLA_A_CDC_CLK_OTHR_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_RDAC_CLK_EN_CTL (0x0000030B) +#define TABLA_A_CDC_CLK_RDAC_CLK_EN_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_ANC_CLK_EN_CTL (0x0000030C) +#define TABLA_A_CDC_CLK_ANC_CLK_EN_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_RX_B1_CTL (0x0000030D) +#define TABLA_A_CDC_CLK_RX_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_RX_B2_CTL (0x0000030E) +#define TABLA_A_CDC_CLK_RX_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_MCLK_CTL (0x0000030F) +#define TABLA_A_CDC_CLK_MCLK_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_PDM_CTL (0x00000310) +#define TABLA_A_CDC_CLK_PDM_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLK_SD_CTL (0x00000311) +#define TABLA_A_CDC_CLK_SD_CTL__POR (0x00000000) +#define TABLA_A_CDC_CLSG_FREQ_THRESH_B1_CTL (0x00000320) +#define TABLA_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR (0x00000007) +#define TABLA_A_CDC_CLSG_FREQ_THRESH_B2_CTL (0x00000321) +#define TABLA_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR (0x00000013) +#define TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL (0x00000322) +#define TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR (0x00000053) +#define TABLA_A_CDC_CLSG_FREQ_THRESH_B4_CTL (0x00000323) +#define TABLA_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR (0x0000007f) +#define TABLA_A_CDC_CLSG_GAIN_THRESH_CTL (0x00000324) +#define TABLA_A_CDC_CLSG_GAIN_THRESH_CTL__POR (0x00000026) +#define TABLA_A_CDC_CLSG_TIMER_B1_CFG (0x00000325) +#define TABLA_A_CDC_CLSG_TIMER_B1_CFG__POR (0x0000000a) +#define TABLA_A_CDC_CLSG_TIMER_B2_CFG (0x00000326) +#define TABLA_A_CDC_CLSG_TIMER_B2_CFG__POR (0x00000000) +#define TABLA_A_CDC_CLSG_CTL (0x00000327) +#define TABLA_A_CDC_CLSG_CTL__POR (0x00000013) +#define TABLA_A_CDC_IIR1_GAIN_B1_CTL (0x00000340) +#define TABLA_A_CDC_IIR1_GAIN_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_GAIN_B1_CTL (0x00000350) +#define TABLA_A_CDC_IIR2_GAIN_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_GAIN_B2_CTL (0x00000341) +#define TABLA_A_CDC_IIR1_GAIN_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_GAIN_B2_CTL (0x00000351) +#define TABLA_A_CDC_IIR2_GAIN_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_GAIN_B3_CTL (0x00000342) +#define TABLA_A_CDC_IIR1_GAIN_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_GAIN_B3_CTL (0x00000352) +#define TABLA_A_CDC_IIR2_GAIN_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_GAIN_B4_CTL (0x00000343) +#define TABLA_A_CDC_IIR1_GAIN_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_GAIN_B4_CTL (0x00000353) +#define TABLA_A_CDC_IIR2_GAIN_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_GAIN_B5_CTL (0x00000344) +#define TABLA_A_CDC_IIR1_GAIN_B5_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_GAIN_B5_CTL (0x00000354) +#define TABLA_A_CDC_IIR2_GAIN_B5_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_GAIN_B6_CTL (0x00000345) +#define TABLA_A_CDC_IIR1_GAIN_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_GAIN_B6_CTL (0x00000355) +#define TABLA_A_CDC_IIR2_GAIN_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_GAIN_B7_CTL (0x00000346) +#define TABLA_A_CDC_IIR1_GAIN_B7_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_GAIN_B7_CTL (0x00000356) +#define TABLA_A_CDC_IIR2_GAIN_B7_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_GAIN_B8_CTL (0x00000347) +#define TABLA_A_CDC_IIR1_GAIN_B8_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_GAIN_B8_CTL (0x00000357) +#define TABLA_A_CDC_IIR2_GAIN_B8_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_CTL (0x00000348) +#define TABLA_A_CDC_IIR1_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_CTL (0x00000358) +#define TABLA_A_CDC_IIR2_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_GAIN_TIMER_CTL (0x00000349) +#define TABLA_A_CDC_IIR1_GAIN_TIMER_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_GAIN_TIMER_CTL (0x00000359) +#define TABLA_A_CDC_IIR2_GAIN_TIMER_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_COEF_B1_CTL (0x0000034A) +#define TABLA_A_CDC_IIR1_COEF_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_COEF_B1_CTL (0x0000035A) +#define TABLA_A_CDC_IIR2_COEF_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_COEF_B2_CTL (0x0000034B) +#define TABLA_A_CDC_IIR1_COEF_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_COEF_B2_CTL (0x0000035B) +#define TABLA_A_CDC_IIR2_COEF_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_COEF_B3_CTL (0x0000034C) +#define TABLA_A_CDC_IIR1_COEF_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_COEF_B3_CTL (0x0000035C) +#define TABLA_A_CDC_IIR2_COEF_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_COEF_B4_CTL (0x0000034D) +#define TABLA_A_CDC_IIR1_COEF_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_COEF_B4_CTL (0x0000035D) +#define TABLA_A_CDC_IIR2_COEF_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR1_COEF_B5_CTL (0x0000034E) +#define TABLA_A_CDC_IIR1_COEF_B5_CTL__POR (0x00000000) +#define TABLA_A_CDC_IIR2_COEF_B5_CTL (0x0000035E) +#define TABLA_A_CDC_IIR2_COEF_B5_CTL__POR (0x00000000) +#define TABLA_A_CDC_TOP_GAIN_UPDATE (0x00000360) +#define TABLA_A_CDC_TOP_GAIN_UPDATE__POR (0x00000000) +#define TABLA_A_CDC_DEBUG_B1_CTL (0x00000368) +#define TABLA_A_CDC_DEBUG_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_DEBUG_B2_CTL (0x00000369) +#define TABLA_A_CDC_DEBUG_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_DEBUG_B3_CTL (0x0000036A) +#define TABLA_A_CDC_DEBUG_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_DEBUG_B4_CTL (0x0000036B) +#define TABLA_A_CDC_DEBUG_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_DEBUG_B5_CTL (0x0000036C) +#define TABLA_A_CDC_DEBUG_B5_CTL__POR (0x00000000) +#define TABLA_A_CDC_DEBUG_B6_CTL (0x0000036D) +#define TABLA_A_CDC_DEBUG_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX1_B1_CTL (0x00000380) +#define TABLA_A_CDC_CONN_RX1_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX1_B2_CTL (0x00000381) +#define TABLA_A_CDC_CONN_RX1_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX1_B3_CTL (0x00000382) +#define TABLA_A_CDC_CONN_RX1_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX2_B1_CTL (0x00000383) +#define TABLA_A_CDC_CONN_RX2_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX2_B2_CTL (0x00000384) +#define TABLA_A_CDC_CONN_RX2_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX2_B3_CTL (0x00000385) +#define TABLA_A_CDC_CONN_RX2_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX3_B1_CTL (0x00000386) +#define TABLA_A_CDC_CONN_RX3_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX3_B2_CTL (0x00000387) +#define TABLA_A_CDC_CONN_RX3_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX3_B3_CTL (0x00000388) +#define TABLA_A_CDC_CONN_RX3_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX4_B1_CTL (0x00000389) +#define TABLA_A_CDC_CONN_RX4_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX4_B2_CTL (0x0000038A) +#define TABLA_A_CDC_CONN_RX4_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX5_B1_CTL (0x0000038B) +#define TABLA_A_CDC_CONN_RX5_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX5_B2_CTL (0x0000038C) +#define TABLA_A_CDC_CONN_RX5_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX6_B1_CTL (0x0000038D) +#define TABLA_A_CDC_CONN_RX6_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX6_B2_CTL (0x0000038E) +#define TABLA_A_CDC_CONN_RX6_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX7_B1_CTL (0x0000038F) +#define TABLA_A_CDC_CONN_RX7_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX7_B2_CTL (0x00000390) +#define TABLA_A_CDC_CONN_RX7_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_ANC_B1_CTL (0x00000391) +#define TABLA_A_CDC_CONN_ANC_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_ANC_B2_CTL (0x00000392) +#define TABLA_A_CDC_CONN_ANC_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_B1_CTL (0x00000393) +#define TABLA_A_CDC_CONN_TX_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_B2_CTL (0x00000394) +#define TABLA_A_CDC_CONN_TX_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_B3_CTL (0x00000395) +#define TABLA_A_CDC_CONN_TX_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_B4_CTL (0x00000396) +#define TABLA_A_CDC_CONN_TX_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_EQ1_B1_CTL (0x00000397) +#define TABLA_A_CDC_CONN_EQ1_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_EQ1_B2_CTL (0x00000398) +#define TABLA_A_CDC_CONN_EQ1_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_EQ1_B3_CTL (0x00000399) +#define TABLA_A_CDC_CONN_EQ1_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_EQ1_B4_CTL (0x0000039A) +#define TABLA_A_CDC_CONN_EQ1_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_EQ2_B1_CTL (0x0000039B) +#define TABLA_A_CDC_CONN_EQ2_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_EQ2_B2_CTL (0x0000039C) +#define TABLA_A_CDC_CONN_EQ2_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_EQ2_B3_CTL (0x0000039D) +#define TABLA_A_CDC_CONN_EQ2_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_EQ2_B4_CTL (0x0000039E) +#define TABLA_A_CDC_CONN_EQ2_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_SRC1_B1_CTL (0x0000039F) +#define TABLA_A_CDC_CONN_SRC1_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_SRC1_B2_CTL (0x000003A0) +#define TABLA_A_CDC_CONN_SRC1_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_SRC2_B1_CTL (0x000003A1) +#define TABLA_A_CDC_CONN_SRC2_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_SRC2_B2_CTL (0x000003A2) +#define TABLA_A_CDC_CONN_SRC2_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B1_CTL (0x000003A3) +#define TABLA_A_CDC_CONN_TX_SB_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B2_CTL (0x000003A4) +#define TABLA_A_CDC_CONN_TX_SB_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B3_CTL (0x000003A5) +#define TABLA_A_CDC_CONN_TX_SB_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B4_CTL (0x000003A6) +#define TABLA_A_CDC_CONN_TX_SB_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B5_CTL (0x000003A7) +#define TABLA_A_CDC_CONN_TX_SB_B5_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B6_CTL (0x000003A8) +#define TABLA_A_CDC_CONN_TX_SB_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B7_CTL (0x000003A9) +#define TABLA_A_CDC_CONN_TX_SB_B7_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B8_CTL (0x000003AA) +#define TABLA_A_CDC_CONN_TX_SB_B8_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B9_CTL (0x000003AB) +#define TABLA_A_CDC_CONN_TX_SB_B9_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B10_CTL (0x000003AC) +#define TABLA_A_CDC_CONN_TX_SB_B10_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_TX_SB_B11_CTL (0x000003AD) +#define TABLA_A_CDC_CONN_TX_SB_B11_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX_SB_B1_CTL (0x000003AE) +#define TABLA_A_CDC_CONN_RX_SB_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_RX_SB_B2_CTL (0x000003AF) +#define TABLA_A_CDC_CONN_RX_SB_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_CLSG_CTL (0x000003B0) +#define TABLA_A_CDC_CONN_CLSG_CTL__POR (0x00000000) +#define TABLA_A_CDC_CONN_SPARE (0x000003B1) +#define TABLA_A_CDC_CONN_SPARE__POR (0x00000000) +#define TABLA_A_CDC_MBHC_EN_CTL (0x000003C0) +#define TABLA_A_CDC_MBHC_EN_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_FEATURE_B1_CFG (0x000003C1) +#define TABLA_A_CDC_MBHC_FEATURE_B1_CFG__POR (0x00000000) +#define TABLA_A_CDC_MBHC_FEATURE_B2_CFG (0x000003C2) +#define TABLA_A_CDC_MBHC_FEATURE_B2_CFG__POR (0x00000006) +#define TABLA_A_CDC_MBHC_TIMER_B1_CTL (0x000003C3) +#define TABLA_A_CDC_MBHC_TIMER_B1_CTL__POR (0x00000003) +#define TABLA_A_CDC_MBHC_TIMER_B2_CTL (0x000003C4) +#define TABLA_A_CDC_MBHC_TIMER_B2_CTL__POR (0x00000009) +#define TABLA_A_CDC_MBHC_TIMER_B3_CTL (0x000003C5) +#define TABLA_A_CDC_MBHC_TIMER_B3_CTL__POR (0x0000001e) +#define TABLA_A_CDC_MBHC_TIMER_B4_CTL (0x000003C6) +#define TABLA_A_CDC_MBHC_TIMER_B4_CTL__POR (0x00000045) +#define TABLA_A_CDC_MBHC_TIMER_B5_CTL (0x000003C7) +#define TABLA_A_CDC_MBHC_TIMER_B5_CTL__POR (0x00000004) +#define TABLA_A_CDC_MBHC_TIMER_B6_CTL (0x000003C8) +#define TABLA_A_CDC_MBHC_TIMER_B6_CTL__POR (0x00000078) +#define TABLA_A_CDC_MBHC_B1_STATUS (0x000003C9) +#define TABLA_A_CDC_MBHC_B1_STATUS__POR (0x00000000) +#define TABLA_A_CDC_MBHC_B2_STATUS (0x000003CA) +#define TABLA_A_CDC_MBHC_B2_STATUS__POR (0x00000000) +#define TABLA_A_CDC_MBHC_B3_STATUS (0x000003CB) +#define TABLA_A_CDC_MBHC_B3_STATUS__POR (0x00000000) +#define TABLA_A_CDC_MBHC_B4_STATUS (0x000003CC) +#define TABLA_A_CDC_MBHC_B4_STATUS__POR (0x00000000) +#define TABLA_A_CDC_MBHC_B5_STATUS (0x000003CD) +#define TABLA_A_CDC_MBHC_B5_STATUS__POR (0x00000000) +#define TABLA_A_CDC_MBHC_B1_CTL (0x000003CE) +#define TABLA_A_CDC_MBHC_B1_CTL__POR (0x000000c0) +#define TABLA_A_CDC_MBHC_B2_CTL (0x000003CF) +#define TABLA_A_CDC_MBHC_B2_CTL__POR (0x0000005d) +#define TABLA_A_CDC_MBHC_VOLT_B1_CTL (0x000003D0) +#define TABLA_A_CDC_MBHC_VOLT_B1_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_VOLT_B2_CTL (0x000003D1) +#define TABLA_A_CDC_MBHC_VOLT_B2_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_VOLT_B3_CTL (0x000003D2) +#define TABLA_A_CDC_MBHC_VOLT_B3_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_VOLT_B4_CTL (0x000003D3) +#define TABLA_A_CDC_MBHC_VOLT_B4_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_VOLT_B5_CTL (0x000003D4) +#define TABLA_A_CDC_MBHC_VOLT_B5_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_VOLT_B6_CTL (0x000003D5) +#define TABLA_A_CDC_MBHC_VOLT_B6_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_VOLT_B7_CTL (0x000003D6) +#define TABLA_A_CDC_MBHC_VOLT_B7_CTL__POR (0x000000ff) +#define TABLA_A_CDC_MBHC_VOLT_B8_CTL (0x000003D7) +#define TABLA_A_CDC_MBHC_VOLT_B8_CTL__POR (0x00000007) +#define TABLA_A_CDC_MBHC_VOLT_B9_CTL (0x000003D8) +#define TABLA_A_CDC_MBHC_VOLT_B9_CTL__POR (0x000000ff) +#define TABLA_A_CDC_MBHC_VOLT_B10_CTL (0x000003D9) +#define TABLA_A_CDC_MBHC_VOLT_B10_CTL__POR (0x0000007f) +#define TABLA_A_CDC_MBHC_VOLT_B11_CTL (0x000003DA) +#define TABLA_A_CDC_MBHC_VOLT_B11_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_VOLT_B12_CTL (0x000003DB) +#define TABLA_A_CDC_MBHC_VOLT_B12_CTL__POR (0x00000080) +#define TABLA_A_CDC_MBHC_CLK_CTL (0x000003DC) +#define TABLA_A_CDC_MBHC_CLK_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_INT_CTL (0x000003DD) +#define TABLA_A_CDC_MBHC_INT_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_DEBUG_CTL (0x000003DE) +#define TABLA_A_CDC_MBHC_DEBUG_CTL__POR (0x00000000) +#define TABLA_A_CDC_MBHC_SPARE (0x000003DF) +#define TABLA_A_CDC_MBHC_SPARE__POR (0x00000000) + + +/* SLIMBUS Slave Registers */ +#define TABLA_SLIM_PGD_PORT_INT_EN0 (0x30) +#define TABLA_SLIM_PGD_PORT_INT_STATUS0 (0x34) +#define TABLA_SLIM_PGD_PORT_INT_CLR0 (0x38) +#define TABLA_SLIM_PGD_PORT_INT_SOURCE0 (0x60) + +/* Macros for Packing Register Writes into a U32 */ +#define TABLA_PACKED_REG_SIZE sizeof(u32) + +#define TABLA_CODEC_PACK_ENTRY(reg, mask, val) ((val & 0xff)|\ + ((mask & 0xff) << 8)|((reg & 0xffff) << 16)) + +#define TABLA_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \ + do { \ + ((reg) = ((packed >> 16) & (0xffff))); \ + ((mask) = ((packed >> 8) & (0xff))); \ + ((val) = ((packed) & (0xff))); \ + } while (0); + +#endif diff --git a/include/linux/mpu.h b/include/linux/mpu.h new file mode 100644 index 00000000000..b15ab05284b --- /dev/null +++ b/include/linux/mpu.h @@ -0,0 +1,483 @@ +/* + * + * Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + * + * 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, see . + * + */ + +#ifndef __MPU_H_ +#define __MPU_H_ + +#ifdef __KERNEL__ +#include +#endif + +#ifdef M_HW +#include "mpu6000.h" +#else +#include "mpu3050.h" +#endif + +/* Number of axes on each sensor */ +#define GYRO_NUM_AXES (3) +#define ACCEL_NUM_AXES (3) +#define COMPASS_NUM_AXES (3) + +/* IOCTL commands for /dev/mpu */ +#define MPU_SET_MPU_CONFIG (0x00) +#define MPU_SET_INT_CONFIG (0x01) +#define MPU_SET_EXT_SYNC (0x02) +#define MPU_SET_FULL_SCALE (0x03) +#define MPU_SET_LPF (0x04) +#define MPU_SET_CLK_SRC (0x05) +#define MPU_SET_DIVIDER (0x06) +#define MPU_SET_LEVEL_SHIFTER (0x07) +#define MPU_SET_DMP_ENABLE (0x08) +#define MPU_SET_FIFO_ENABLE (0x09) +#define MPU_SET_DMP_CFG1 (0x0a) +#define MPU_SET_DMP_CFG2 (0x0b) +#define MPU_SET_OFFSET_TC (0x0c) +#define MPU_SET_RAM (0x0d) + +#define MPU_SET_PLATFORM_DATA (0x0e) + +#define MPU_GET_MPU_CONFIG (0x80) +#define MPU_GET_INT_CONFIG (0x81) +#define MPU_GET_EXT_SYNC (0x82) +#define MPU_GET_FULL_SCALE (0x83) +#define MPU_GET_LPF (0x84) +#define MPU_GET_CLK_SRC (0x85) +#define MPU_GET_DIVIDER (0x86) +#define MPU_GET_LEVEL_SHIFTER (0x87) +#define MPU_GET_DMP_ENABLE (0x88) +#define MPU_GET_FIFO_ENABLE (0x89) +#define MPU_GET_DMP_CFG1 (0x8a) +#define MPU_GET_DMP_CFG2 (0x8b) +#define MPU_GET_OFFSET_TC (0x8c) +#define MPU_GET_RAM (0x8d) + +#define MPU_READ_REGISTER (0x40) +#define MPU_WRITE_REGISTER (0x41) +#define MPU_READ_MEMORY (0x42) +#define MPU_WRITE_MEMORY (0x43) + +#define MPU_SUSPEND (0x44) +#define MPU_RESUME (0x45) +#define MPU_READ_COMPASS (0x46) +#define MPU_READ_ACCEL (0x47) +#define MPU_READ_PRESSURE (0x48) + +#define MPU_CONFIG_ACCEL (0x20) +#define MPU_CONFIG_COMPASS (0x21) +#define MPU_CONFIG_PRESSURE (0x22) + +#define MPU_GET_CONFIG_ACCEL (0x28) +#define MPU_GET_CONFIG_COMPASS (0x29) +#define MPU_GET_CONFIG_PRESSURE (0x2a) + +/* Structure for the following IOCTL's: + MPU_SET_RAM + MPU_GET_RAM + MPU_READ_REGISTER + MPU_WRITE_REGISTER + MPU_READ_MEMORY + MPU_WRITE_MEMORY +*/ +struct mpu_read_write { + unsigned short address; + unsigned short length; + unsigned char *data; +}; + +struct mpuirq_data { + int interruptcount; + unsigned long long irqtime; + int data_type; + int data_size; + void *data; +}; +enum ext_slave_config_key { + MPU_SLAVE_CONFIG_ODR_SUSPEND, + MPU_SLAVE_CONFIG_ODR_RESUME, + MPU_SLAVE_CONFIG_FSR_SUSPEND, + MPU_SLAVE_CONFIG_FSR_RESUME, + MPU_SLAVE_CONFIG_MOT_THS, + MPU_SLAVE_CONFIG_NMOT_THS, + MPU_SLAVE_CONFIG_MOT_DUR, + MPU_SLAVE_CONFIG_NMOT_DUR, + MPU_SLAVE_CONFIG_IRQ_SUSPEND, + MPU_SLAVE_CONFIG_IRQ_RESUME, + MPU_SLAVE_CONFIG_NUM_CONFIG_KEYS, +}; + +/* For the MPU_SLAVE_CONFIG_IRQ_SUSPEND and MPU_SLAVE_CONFIG_IRQ_RESUME */ +enum ext_slave_config_irq_type { + MPU_SLAVE_IRQ_TYPE_NONE, + MPU_SLAVE_IRQ_TYPE_MOTION, + MPU_SLAVE_IRQ_TYPE_DATA_READY, +}; + +/* Structure for the following IOCTS's + * MPU_CONFIG_ACCEL + * MPU_CONFIG_COMPASS + * MPU_CONFIG_PRESSURE + * MPU_GET_CONFIG_ACCEL + * MPU_GET_CONFIG_COMPASS + * MPU_GET_CONFIG_PRESSURE + */ +struct ext_slave_config { + int key; + int len; + int apply; + void *data; +}; + +enum ext_slave_type { + EXT_SLAVE_TYPE_GYROSCOPE, + EXT_SLAVE_TYPE_ACCELEROMETER, + EXT_SLAVE_TYPE_COMPASS, + EXT_SLAVE_TYPE_PRESSURE, + /*EXT_SLAVE_TYPE_TEMPERATURE */ +}; + +enum ext_slave_id { + ID_INVALID = 0, + + ACCEL_ID_LIS331, + ACCEL_ID_LSM303, + ACCEL_ID_KXSD9, + ACCEL_ID_KXTF9, + ACCEL_ID_BMA150, + ACCEL_ID_BMA222, + ACCEL_ID_BMA250, + ACCEL_ID_ADI346, + ACCEL_ID_MMA8450, + ACCEL_ID_MMA845X, + ACCEL_ID_MPU6000, + ACCEL_ID_LIS3DH, + + COMPASS_ID_AKM, + COMPASS_ID_AMI30X, + COMPASS_ID_YAS529, + COMPASS_ID_YAS530, + COMPASS_ID_HMC5883, + COMPASS_ID_LSM303, + COMPASS_ID_MMC314X, + COMPASS_ID_MMC328X, /* MEMSIC328X */ + COMPASS_ID_HSCDTD002B, + COMPASS_ID_HSCDTD004A, + COMPASS_ID_AMS0303, + + PRESSURE_ID_BMA085, +}; + +enum ext_slave_endian { + EXT_SLAVE_BIG_ENDIAN, + EXT_SLAVE_LITTLE_ENDIAN, + EXT_SLAVE_FS8_BIG_ENDIAN, + EXT_SLAVE_FS16_BIG_ENDIAN, +}; + +enum ext_slave_bus { + EXT_SLAVE_BUS_INVALID = -1, + EXT_SLAVE_BUS_PRIMARY = 0, + EXT_SLAVE_BUS_SECONDARY = 1 +}; + + +/** + * struct ext_slave_platform_data - Platform data for mpu3050 slave devices + * + * @get_slave_descr: Function pointer to retrieve the struct ext_slave_descr + * for this slave + * @irq: the irq number attached to the slave if any. + * @adapt_num: the I2C adapter number. + * @bus: the bus the slave is attached to: enum ext_slave_bus + * @address: the I2C slave address of the slave device. + * @orientation: the mounting matrix of the device relative to MPU. + * @irq_data: private data for the slave irq handler + * @private_data: additional data, user customizable. Not touched by the MPU + * driver. + * + * The orientation matricies are 3x3 rotation matricies + * that are applied to the data to rotate from the mounting orientation to the + * platform orientation. The values must be one of 0, 1, or -1 and each row and + * column should have exactly 1 non-zero value. + */ +struct ext_slave_platform_data { + struct ext_slave_descr *(*get_slave_descr) (void); + int irq; + int adapt_num; + int bus; + unsigned char address; + signed char orientation[9]; + void *irq_data; + void *private_data; +}; + + +struct t_fix_pnt_range { + long mantissa; + long fraction; +}; + +/** + * struct ext_slave_descr - Description of the slave device for programming. + * + * @suspend: function pointer to put the device in suspended state + * @resume: function pointer to put the device in running state + * @read: function that reads the device data + * @init: function used to preallocate memory used by the driver + * @exit: function used to free memory allocated for the driver + * @config: function used to configure the device + * @get_config:function used to get the device's configuration + * + * @name: text name of the device + * @type: device type. enum ext_slave_type + * @id: enum ext_slave_id + * @reg: starting register address to retrieve data. + * @len: length in bytes of the sensor data. Should be 6. + * @endian: byte order of the data. enum ext_slave_endian + * @range: full scale range of the slave ouput: struct t_fix_pnt_range + * + * Defines the functions and information about the slave the mpu3050 needs to + * use the slave device. + */ +struct ext_slave_descr { + int (*init) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*exit) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*suspend) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*resume) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*read) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data); + int (*config) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *config); + int (*get_config) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *config); + + char *name; + unsigned char type; + unsigned char id; + unsigned char reg; + unsigned int len; + unsigned char endian; + struct t_fix_pnt_range range; +}; + +/** + * struct mpu3050_platform_data - Platform data for the mpu3050 driver + * @int_config: Bits [7:3] of the int config register. + * @orientation: Orientation matrix of the gyroscope + * @level_shifter: 0: VLogic, 1: VDD + * @accel: Accel platform data + * @compass: Compass platform data + * @pressure: Pressure platform data + * + * Contains platform specific information on how to configure the MPU3050 to + * work on this platform. The orientation matricies are 3x3 rotation matricies + * that are applied to the data to rotate from the mounting orientation to the + * platform orientation. The values must be one of 0, 1, or -1 and each row and + * column should have exactly 1 non-zero value. + */ +struct mpu3050_platform_data { + unsigned char int_config; + signed char orientation[MPU_NUM_AXES * MPU_NUM_AXES]; + unsigned char level_shifter; + struct ext_slave_platform_data accel; + struct ext_slave_platform_data compass; + struct ext_slave_platform_data pressure; +}; + + +/* + Accelerometer +*/ +#define get_accel_slave_descr NULL + +#ifdef CONFIG_MPU_SENSORS_ADXL346 /* ADI accelerometer */ +struct ext_slave_descr *adxl346_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr adxl346_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_BMA150 /* Bosch accelerometer */ +struct ext_slave_descr *bma150_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr bma150_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_BMA222 /* Bosch 222 accelerometer */ +struct ext_slave_descr *bma222_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr bma222_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_BMA250 /* Bosch 250 accelerometer */ +struct ext_slave_descr *bma250_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr bma250_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_KXSD9 /* Kionix accelerometer */ +struct ext_slave_descr *kxsd9_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr kxsd9_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_KXTF9 /* Kionix accelerometer */ +struct ext_slave_descr *kxtf9_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr kxtf9_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_LIS331DLH /* ST accelerometer */ +struct ext_slave_descr *lis331dlh_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr lis331dlh_get_slave_descr +#endif + + +#ifdef CONFIG_MPU_SENSORS_LIS3DH /* ST accelerometer */ +struct ext_slave_descr *lis3dh_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr lis3dh_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_LSM303DLHA /* ST accelerometer */ +struct ext_slave_descr *lsm303dlha_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr lsm303dlha_get_slave_descr +#endif + +/* MPU6000 Accel */ +#if defined(CONFIG_MPU_SENSORS_MPU6000) || \ + defined(CONFIG_MPU_SENSORS_MPU6000_MODULE) +struct ext_slave_descr *mantis_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr mantis_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_MMA8450 /* Freescale accelerometer */ +struct ext_slave_descr *mma8450_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr mma8450_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_MMA845X /* Freescale accelerometer */ +struct ext_slave_descr *mma845x_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr mma845x_get_slave_descr +#endif + + +/* + Compass +*/ +#define get_compass_slave_descr NULL + +#ifdef CONFIG_MPU_SENSORS_AK8975 /* AKM compass */ +struct ext_slave_descr *ak8975_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr ak8975_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_AMI30X /* AICHI Steel compass */ +struct ext_slave_descr *ami30x_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr ami30x_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_HMC5883 /* Honeywell compass */ +struct ext_slave_descr *hmc5883_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr hmc5883_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_MMC314X /* MEMSIC compass */ +struct ext_slave_descr *mmc314x_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr mmc314x_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_MMC328X /* MEMSIC compass */ +struct ext_slave_descr *mmc328x_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr mmc328x_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_LSM303DLHM /* ST compass */ +struct ext_slave_descr *lsm303dlhm_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr lsm303dlhm_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_YAS529 /* Yamaha compass */ +struct ext_slave_descr *yas529_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr yas529_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_YAS530 /* Yamaha compass */ +struct ext_slave_descr *yas530_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr yas530_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_HSCDTD002B /* Alps HSCDTD002B compass */ +struct ext_slave_descr *hscdtd002b_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr hscdtd002b_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_HSCDTD004A /* Alps HSCDTD004A compass */ +struct ext_slave_descr *hscdtd004a_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr hscdtd004a_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_AMS0303 /* Amotech ams0303 compass */ +struct ext_slave_descr *ams0303_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr ams0303_get_slave_descr +#endif + + +/* + Pressure +*/ +#define get_pressure_slave_descr NULL + +#ifdef CONFIG_MPU_SENSORS_BMA085 /* BMA pressure */ +struct ext_slave_descr *bma085_get_slave_descr(void); +#undef get_pressure_slave_descr +#define get_pressure_slave_descr bma085_get_slave_descr +#endif + +#endif /* __MPU_H_ */ + diff --git a/include/linux/mpu_411.h b/include/linux/mpu_411.h new file mode 100644 index 00000000000..a26125188fc --- /dev/null +++ b/include/linux/mpu_411.h @@ -0,0 +1,380 @@ +/* + $License: + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + + 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, see . + $ + */ + +#ifndef __MPU_H_ +#define __MPU_H_ + +#ifdef __KERNEL__ +#include +#include +#elif defined LINUX +#include +#include +#else +#include "mltypes.h" +#endif + +/* Number of axes on each sensor */ +#define GYRO_NUM_AXES (3) +#define ACCEL_NUM_AXES (3) +#define COMPASS_NUM_AXES (3) + +struct mpu_read_write { + /* Memory address or register address depending on ioctl */ + __u16 address; + __u16 length; + __u8 *data; +}; + +enum mpuirq_data_type { + MPUIRQ_DATA_TYPE_MPU_IRQ, + MPUIRQ_DATA_TYPE_SLAVE_IRQ, + MPUIRQ_DATA_TYPE_PM_EVENT, + MPUIRQ_DATA_TYPE_NUM_TYPES, +}; + +/* User space PM event notification */ +#define MPU_PM_EVENT_SUSPEND_PREPARE (0x1) +#define MPU_PM_EVENT_POST_SUSPEND (0x2) + +#define MPU_KN_EVENT_ENABLE_SENSORS (0x10) + +struct mpuirq_data { + __u32 interruptcount; + __u64 irqtime; + __u32 data_type; + __s32 data; +}; + +enum ext_slave_config_key { + MPU_SLAVE_CONFIG_ODR_SUSPEND, + MPU_SLAVE_CONFIG_ODR_RESUME, + MPU_SLAVE_CONFIG_FSR_SUSPEND, + MPU_SLAVE_CONFIG_FSR_RESUME, + MPU_SLAVE_CONFIG_MOT_THS, + MPU_SLAVE_CONFIG_NMOT_THS, + MPU_SLAVE_CONFIG_MOT_DUR, + MPU_SLAVE_CONFIG_NMOT_DUR, + MPU_SLAVE_CONFIG_IRQ_SUSPEND, + MPU_SLAVE_CONFIG_IRQ_RESUME, + MPU_SLAVE_WRITE_REGISTERS, + MPU_SLAVE_READ_REGISTERS, + MPU_SLAVE_CONFIG_INTERNAL_REFERENCE, + /* AMI 306 specific config keys */ + MPU_SLAVE_PARAM, + MPU_SLAVE_WINDOW, + MPU_SLAVE_READWINPARAMS, + MPU_SLAVE_SEARCHOFFSET, + /* AKM specific config keys */ + MPU_SLAVE_READ_SCALE, + /* MPU3050 and MPU6050 Keys */ + MPU_SLAVE_INT_CONFIG, + MPU_SLAVE_EXT_SYNC, + MPU_SLAVE_FULL_SCALE, + MPU_SLAVE_LPF, + MPU_SLAVE_CLK_SRC, + MPU_SLAVE_DIVIDER, + MPU_SLAVE_DMP_ENABLE, + MPU_SLAVE_FIFO_ENABLE, + MPU_SLAVE_DMP_CFG1, + MPU_SLAVE_DMP_CFG2, + MPU_SLAVE_TC, + MPU_SLAVE_GYRO, + MPU_SLAVE_ADDR, + MPU_SLAVE_PRODUCT_REVISION, + MPU_SLAVE_SILICON_REVISION, + MPU_SLAVE_PRODUCT_ID, + MPU_SLAVE_GYRO_SENS_TRIM, + MPU_SLAVE_ACCEL_SENS_TRIM, + MPU_SLAVE_RAM, + /* -------------------------- */ + MPU_SLAVE_CONFIG_NUM_CONFIG_KEYS +}; + +/* For the MPU_SLAVE_CONFIG_IRQ_SUSPEND and MPU_SLAVE_CONFIG_IRQ_RESUME */ +enum ext_slave_config_irq_type { + MPU_SLAVE_IRQ_TYPE_NONE, + MPU_SLAVE_IRQ_TYPE_MOTION, + MPU_SLAVE_IRQ_TYPE_DATA_READY, +}; + +/* Structure for the following IOCTS's + * MPU_CONFIG_GYRO + * MPU_CONFIG_ACCEL + * MPU_CONFIG_COMPASS + * MPU_CONFIG_PRESSURE + * MPU_GET_CONFIG_GYRO + * MPU_GET_CONFIG_ACCEL + * MPU_GET_CONFIG_COMPASS + * MPU_GET_CONFIG_PRESSURE + * + * @key one of enum ext_slave_config_key + * @len length of data pointed to by data + * @apply zero if communication with the chip is not necessary, false otherwise + * This flag can be used to select cached data or to refresh cashed data + * cache data to be pushed later or push immediately. If true and the + * slave is on the secondary bus the MPU will first enger bypass mode + * before calling the slaves .config or .get_config funcion + * @data pointer to the data to confgure or get + */ +struct ext_slave_config { + __u8 key; + __u16 len; + __u8 apply; + void *data; +}; + +enum ext_slave_type { + EXT_SLAVE_TYPE_GYROSCOPE, + EXT_SLAVE_TYPE_ACCEL, + EXT_SLAVE_TYPE_COMPASS, + EXT_SLAVE_TYPE_PRESSURE, + /*EXT_SLAVE_TYPE_TEMPERATURE */ + + EXT_SLAVE_NUM_TYPES +}; + +enum ext_slave_id { + ID_INVALID = 0, + + ACCEL_ID_LIS331, + ACCEL_ID_LSM303DLX, + ACCEL_ID_LIS3DH, + ACCEL_ID_KXSD9, + ACCEL_ID_KXTF9, + ACCEL_ID_BMA150, + ACCEL_ID_BMA222, + ACCEL_ID_BMA250, + ACCEL_ID_ADXL34X, + ACCEL_ID_MMA8450, + ACCEL_ID_MMA845X, + ACCEL_ID_MPU6050, + + COMPASS_ID_AK8975, + COMPASS_ID_AK8972, + COMPASS_ID_AMI30X, + COMPASS_ID_AMI306, + COMPASS_ID_YAS529, + COMPASS_ID_YAS530, + COMPASS_ID_HMC5883, + COMPASS_ID_LSM303DLH, + COMPASS_ID_LSM303DLM, + COMPASS_ID_MMC314X, + COMPASS_ID_HSCDTD002B, + COMPASS_ID_HSCDTD004A, + COMPASS_ID_YAS530_EXT, + PRESSURE_ID_BMA085, +}; + +enum ext_slave_endian { + EXT_SLAVE_BIG_ENDIAN, + EXT_SLAVE_LITTLE_ENDIAN, + EXT_SLAVE_FS8_BIG_ENDIAN, + EXT_SLAVE_FS16_BIG_ENDIAN, +}; + +enum ext_slave_bus { + EXT_SLAVE_BUS_INVALID = -1, + EXT_SLAVE_BUS_PRIMARY = 0, + EXT_SLAVE_BUS_SECONDARY = 1 +}; + + +/** + * struct ext_slave_platform_data - Platform data for mpu3050 and mpu6050 + * slave devices + * + * @type: the type of slave device based on the enum ext_slave_type + * definitions. + * @irq: the irq number attached to the slave if any. + * @adapt_num: the I2C adapter number. + * @bus: the bus the slave is attached to: enum ext_slave_bus + * @address: the I2C slave address of the slave device. + * @orientation: the mounting matrix of the device relative to MPU. + * @irq_data: private data for the slave irq handler + * @private_data: additional data, user customizable. Not touched by the MPU + * driver. + * + * The orientation matricies are 3x3 rotation matricies + * that are applied to the data to rotate from the mounting orientation to the + * platform orientation. The values must be one of 0, 1, or -1 and each row and + * column should have exactly 1 non-zero value. + */ +struct ext_slave_platform_data { + __u8 type; + __u32 irq; + __u32 adapt_num; + __u32 bus; + __u8 address; + __s8 orientation[9]; + void *irq_data; + void *private_data; +}; + +struct fix_pnt_range { + __s32 mantissa; + __s32 fraction; +}; + +static inline long range_fixedpoint_to_long_mg(struct fix_pnt_range rng) +{ + return (long)(rng.mantissa * 1000 + rng.fraction / 10); +} + +struct ext_slave_read_trigger { + __u8 reg; + __u8 value; +}; + +/** + * struct ext_slave_descr - Description of the slave device for programming. + * + * @suspend: function pointer to put the device in suspended state + * @resume: function pointer to put the device in running state + * @read: function that reads the device data + * @init: function used to preallocate memory used by the driver + * @exit: function used to free memory allocated for the driver + * @config: function used to configure the device + * @get_config:function used to get the device's configuration + * + * @name: text name of the device + * @type: device type. enum ext_slave_type + * @id: enum ext_slave_id + * @read_reg: starting register address to retrieve data. + * @read_len: length in bytes of the sensor data. Typically 6. + * @endian: byte order of the data. enum ext_slave_endian + * @range: full scale range of the slave ouput: struct fix_pnt_range + * @trigger: If reading data first requires writing a register this is the + * data to write. + * + * Defines the functions and information about the slave the mpu3050 and + * mpu6050 needs to use the slave device. + */ +struct ext_slave_descr { + int (*init) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*exit) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*suspend) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*resume) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*read) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + __u8 *data); + int (*config) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *config); + int (*get_config) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *config); + + char *name; + __u8 type; + __u8 id; + __u8 read_reg; + __u8 read_len; + __u8 endian; + struct fix_pnt_range range; + struct ext_slave_read_trigger *trigger; +}; + +/** + * struct mpu_platform_data - Platform data for the mpu driver + * @int_config: Bits [7:3] of the int config register. + * @level_shifter: 0: VLogic, 1: VDD + * @orientation: Orientation matrix of the gyroscope + * + * Contains platform specific information on how to configure the MPU3050 to + * work on this platform. The orientation matricies are 3x3 rotation matricies + * that are applied to the data to rotate from the mounting orientation to the + * platform orientation. The values must be one of 0, 1, or -1 and each row and + * column should have exactly 1 non-zero value. + */ +struct mpu_platform_data { + __u8 int_config; + __u8 level_shifter; + __s8 orientation[GYRO_NUM_AXES * GYRO_NUM_AXES]; + void (*poweron) (int); + int reset; +}; + +#if defined __KERNEL__ || defined LINUX +#define MPU_IOCTL (0x81) /* Magic number for MPU Iocts */ +/* IOCTL commands for /dev/mpu */ + +/*-------------------------------------------------------------------------- + * Deprecated, debugging only + */ +#define MPU_SET_MPU_PLATFORM_DATA \ + _IOWR(MPU_IOCTL, 0x01, struct mpu_platform_data) +#define MPU_SET_EXT_SLAVE_PLATFORM_DATA \ + _IOWR(MPU_IOCTL, 0x01, struct ext_slave_platform_data) +/*--------------------------------------------------------------------------*/ +#define MPU_GET_EXT_SLAVE_PLATFORM_DATA \ + _IOWR(MPU_IOCTL, 0x02, struct ext_slave_platform_data) +#define MPU_GET_MPU_PLATFORM_DATA \ + _IOWR(MPU_IOCTL, 0x02, struct mpu_platform_data) +#define MPU_GET_EXT_SLAVE_DESCR \ + _IOWR(MPU_IOCTL, 0x02, struct ext_slave_descr) + +#define MPU_READ _IOWR(MPU_IOCTL, 0x10, struct mpu_read_write) +#define MPU_WRITE _IOW(MPU_IOCTL, 0x10, struct mpu_read_write) +#define MPU_READ_MEM _IOWR(MPU_IOCTL, 0x11, struct mpu_read_write) +#define MPU_WRITE_MEM _IOW(MPU_IOCTL, 0x11, struct mpu_read_write) +#define MPU_READ_FIFO _IOWR(MPU_IOCTL, 0x12, struct mpu_read_write) +#define MPU_WRITE_FIFO _IOW(MPU_IOCTL, 0x12, struct mpu_read_write) + +#define MPU_READ_COMPASS _IOR(MPU_IOCTL, 0x12, __u8) +#define MPU_READ_ACCEL _IOR(MPU_IOCTL, 0x13, __u8) +#define MPU_READ_PRESSURE _IOR(MPU_IOCTL, 0x14, __u8) + +#define MPU_CONFIG_GYRO _IOW(MPU_IOCTL, 0x20, struct ext_slave_config) +#define MPU_CONFIG_ACCEL _IOW(MPU_IOCTL, 0x21, struct ext_slave_config) +#define MPU_CONFIG_COMPASS _IOW(MPU_IOCTL, 0x22, struct ext_slave_config) +#define MPU_CONFIG_PRESSURE _IOW(MPU_IOCTL, 0x23, struct ext_slave_config) + +#define MPU_GET_CONFIG_GYRO _IOWR(MPU_IOCTL, 0x20, struct ext_slave_config) +#define MPU_GET_CONFIG_ACCEL _IOWR(MPU_IOCTL, 0x21, struct ext_slave_config) +#define MPU_GET_CONFIG_COMPASS _IOWR(MPU_IOCTL, 0x22, struct ext_slave_config) +#define MPU_GET_CONFIG_PRESSURE _IOWR(MPU_IOCTL, 0x23, struct ext_slave_config) + +#define MPU_SUSPEND _IOW(MPU_IOCTL, 0x30, __u32) +#define MPU_RESUME _IOW(MPU_IOCTL, 0x31, __u32) +/* Userspace PM Event response */ +#define MPU_PM_EVENT_HANDLED _IO(MPU_IOCTL, 0x32) + +#define MPU_GET_REQUESTED_SENSORS _IOR(MPU_IOCTL, 0x40, __u8) +#define MPU_SET_REQUESTED_SENSORS _IOW(MPU_IOCTL, 0x40, __u8) +#define MPU_GET_IGNORE_SYSTEM_SUSPEND _IOR(MPU_IOCTL, 0x41, __u8) +#define MPU_SET_IGNORE_SYSTEM_SUSPEND _IOW(MPU_IOCTL, 0x41, __u8) +#define MPU_GET_MLDL_STATUS _IOR(MPU_IOCTL, 0x42, __u8) +#define MPU_GET_I2C_SLAVES_ENABLED _IOR(MPU_IOCTL, 0x43, __u8) +#define MPU_READ_ACCEL_OFFSET _IOR(MPU_IOCTL, 0x44, __u8) +#define MPU_ACTIVATE_SENSORS _IOW(MPU_IOCTL, 0x45, __u8) +#endif + +#endif /* __MPU_H_ */ diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h index edf240162f0..04643871b0c 100644 --- a/include/linux/msm_ion.h +++ b/include/linux/msm_ion.h @@ -84,6 +84,17 @@ enum cp_mem_usage { * Macro should be used with ion_heap_ids defined above. */ #define ION_HEAP(bit) (1 << (bit)) +#define ion_full_heap_mask (ION_HEAP(ION_CP_MM_HEAP_ID) | \ + ION_HEAP(ION_CP_MFC_HEAP_ID) | \ + ION_HEAP(ION_CP_WB_HEAP_ID) | \ + ION_HEAP(ION_CAMERA_HEAP_ID) | \ + ION_HEAP(ION_SF_HEAP_ID) | \ + ION_HEAP(ION_IOMMU_HEAP_ID) | \ + ION_HEAP(ION_QSECOM_HEAP_ID) | \ + ION_HEAP(ION_AUDIO_HEAP_ID) | \ + ION_HEAP(ION_MM_FIRMWARE_HEAP_ID) | \ + ION_HEAP(ION_SYSTEM_HEAP_ID) ) + #define ION_ADSP_HEAP_NAME "adsp" #define ION_VMALLOC_HEAP_NAME "vmalloc" @@ -266,6 +277,7 @@ static inline int msm_ion_unsecure_heap_2_0(int heap_id, * of the handle, p + offset through p + offset + length will have * the cache operations performed */ +/* struct ion_flush_data { struct ion_handle *handle; int fd; @@ -273,7 +285,7 @@ struct ion_flush_data { unsigned int offset; unsigned int length; }; - +*/ /* struct ion_flag_data - information about flags for this buffer * * @handle: handle to get flags from @@ -282,11 +294,12 @@ struct ion_flush_data { * Takes handle as an input and outputs the flags from the handle * in the flag field. */ +/* struct ion_flag_data { struct ion_handle *handle; unsigned long flags; }; - +*/ #define ION_IOC_MSM_MAGIC 'M' /** @@ -296,6 +309,7 @@ struct ion_flag_data { */ #define ION_IOC_CLEAN_CACHES _IOWR(ION_IOC_MSM_MAGIC, 0, \ struct ion_flush_data) + /** * DOC: ION_IOC_INV_CACHES - invalidate the caches * @@ -319,5 +333,4 @@ struct ion_flag_data { */ #define ION_IOC_GET_FLAGS _IOWR(ION_IOC_MSM_MAGIC, 3, \ struct ion_flag_data) - #endif diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h index d3bfdc2e9b4..7fde8d1a337 100644 --- a/include/linux/msm_mdp.h +++ b/include/linux/msm_mdp.h @@ -111,10 +111,12 @@ enum { MDP_Y_CBCR_H1V1, /* Y and CbCr, pseduo planer w/ Cb is in MSB */ MDP_YCRCB_H1V1, /* YCrCb interleave */ MDP_YCBCR_H1V1, /* YCbCr interleave */ - MDP_BGR_565, /* BGR 565 planer */ MDP_IMGTYPE_LIMIT, MDP_RGB_BORDERFILL, /* border fill pipe */ MDP_FB_FORMAT = MDP_IMGTYPE2_START, /* framebuffer format */ + MDP_BGR_565, /* BGR 565 planer */ + MDP_BGR_888, /* BGR 888 */ + MDP_Y_CBCR_H2V2_VENUS, MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */ }; diff --git a/include/linux/msm_rotator.h b/include/linux/msm_rotator.h index 17ae867e158..69fc14dfdea 100644 --- a/include/linux/msm_rotator.h +++ b/include/linux/msm_rotator.h @@ -41,6 +41,7 @@ struct msm_rotator_data_info { unsigned int version_key; struct msmfb_data src_chroma; struct msmfb_data dst_chroma; + struct mdp_buf_fence buf_fence; }; struct msm_rot_clocks { diff --git a/include/linux/platform_data/mms_ts.h b/include/linux/platform_data/mms_ts.h new file mode 100644 index 00000000000..db11c2a125a --- /dev/null +++ b/include/linux/platform_data/mms_ts.h @@ -0,0 +1,47 @@ +/* + * mms_ts.h - Platform data for Melfas MMS-series touch driver + * + * Copyright (C) 2011 Google Inc. + * Author: Dima Zavin + * + * + * 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. + * + */ + +#ifndef _LINUX_MMS_TOUCH_H +#define _LINUX_MMS_TOUCH_H + +struct tsp_callbacks { + void (*inform_charger)(struct tsp_callbacks *tsp_cb, bool mode); +}; + +struct mms_ts_platform_data { + int max_x; + int max_y; + + bool invert_x; + bool invert_y; + + int gpio_sda; + int gpio_scl; + int gpio_resetb; + int gpio_lcd_type; + int (*mux_fw_flash)(bool to_gpios); + void (*vdd_on)(bool); + int (*is_vdd_on)(void); + void (*register_cb)(struct tsp_callbacks *); + const char *fw_name; + bool use_touchkey; + const u8 *touchkey_keycode; + const u8 *config_fw_version; + int check_module_type; +}; +extern struct class *sec_class; +extern int poweroff_charging; +extern unsigned char LCD_Get_Value(void); +extern struct tsp_callbacks *charger_callbacks; +#endif /* _LINUX_MMS_TOUCH_H */ diff --git a/include/linux/pn544.h b/include/linux/pn544.h new file mode 100644 index 00000000000..6e45091690d --- /dev/null +++ b/include/linux/pn544.h @@ -0,0 +1,34 @@ +/* + * 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 + */ + +#define PN544_MAGIC 0xE9 + +/* + * PN544 power control via ioctl + * PN544_SET_PWR(0): power off + * PN544_SET_PWR(1): power on + * PN544_SET_PWR(>1): power on with firmware download enabled + */ +#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, unsigned int) + +struct pn544_i2c_platform_data { + void (*conf_gpio) (void); + unsigned int irq_gpio; + unsigned int ven_gpio; + unsigned int firm_gpio; +}; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index cb56293dc7b..77d1830d5d1 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -82,6 +82,12 @@ enum { POWER_SUPPLY_SCOPE_DEVICE, }; +/* for SAMSUNG OTG */ +enum { + POWER_SUPPLY_CAPACITY_OTG_ENABLE = 0, + POWER_SUPPLY_CAPACITY_OTG_DISABLE, +}; + enum power_supply_property { /* Properties of type `int' */ POWER_SUPPLY_PROP_STATUS = 0, @@ -124,6 +130,13 @@ enum power_supply_property { POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */ + POWER_SUPPLY_PROP_OTG, /* for SAMSUNG OTG */ + POWER_SUPPLY_TYPE_SMART_DOCK, /* for SAMSUNG Smart dock */ + POWER_SUPPLY_PROP_CURRENT_ADJ, /* for SAMSUNG Charging */ + POWER_SUPPLY_PROP_FUELGAUGE_STATE, /*for SAMSUNG fuelgauging */ +#ifdef CONFIG_WIRELESS_CHARGING + POWER_SUPPLY_PROP_WIRELESS_CHARGING, /* for SAMSUNG Wireless Charging */ +#endif POWER_SUPPLY_PROP_SCOPE, /* Properties of type `const char *' */ POWER_SUPPLY_PROP_MODEL_NAME, @@ -140,6 +153,20 @@ enum power_supply_type { POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */ POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */ POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */ +#ifdef CONFIG_WIRELESS_CHARGER + POWER_SUPPLY_TYPE_WIRELESS, +#endif + POWER_SUPPLY_TYPE_BMS, /* Battery Monitor System */ + POWER_SUPPLY_TYPE_MISC, + POWER_SUPPLY_TYPE_CARDOCK, + POWER_SUPPLY_TYPE_UARTOFF, +#ifdef CONFIG_WIRELESS_CHARGING + POWER_SUPPLY_TYPE_WPC, /* Wireless Charging should be 10 */ +#else + POWER_SUPPLY_TYPE_DUMMY, /* # 10 is assigned for wireless */ +#endif + POWER_SUPPLY_TYPE_OTG, + }; union power_supply_propval { diff --git a/include/linux/regulator/gpio-regulator.h b/include/linux/regulator/gpio-regulator.h index 19fbd267406..99e4b254139 100644 --- a/include/linux/regulator/gpio-regulator.h +++ b/include/linux/regulator/gpio-regulator.h @@ -17,7 +17,7 @@ * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. */ - +#include #ifndef __REGULATOR_GPIO_H #define __REGULATOR_GPIO_H diff --git a/include/linux/regulator/max8952.h b/include/linux/regulator/max8952.h index 45e42855ad0..52b7103a5e1 100644 --- a/include/linux/regulator/max8952.h +++ b/include/linux/regulator/max8952.h @@ -23,6 +23,9 @@ #define REGULATOR_MAX8952 #include +#define MAX8952_DCDC_VMIN 770000 /* uV */ +#define MAX8952_DCDC_STEP 10000 /* uV */ +#define MAX8952_DCDC_VMAX 1400000 /* uV */ enum { MAX8952_DVS_MODE0, diff --git a/include/linux/sec_battery.h b/include/linux/sec_battery.h new file mode 100644 index 00000000000..983ac9a2253 --- /dev/null +++ b/include/linux/sec_battery.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 Samsung Electronics, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __MACH_SEC_BATTERY_H +#define __MACH_SEC_BATTERY_H __FILE__ + +extern int poweroff_charging; + +struct sec_bat_adc_table_data { + int adc; + int temperature; +}; + +struct sec_bat_platform_data { + char *fuel_gauge_name; + char *charger_name; + int (*get_cable_type) (void); + int (*sec_battery_using) (void); + int (*check_batt_type) (void); + unsigned int iterm; + unsigned int charge_duration; + unsigned int wpc_charge_duration; + unsigned int recharge_duration; + unsigned int max_voltage; + unsigned int recharge_voltage; + int event_block; + int high_block; + int high_recovery; + int high_recovery_wpc; + int low_block; + int low_recovery; + int lpm_high_block; + int lpm_high_recovery; + int lpm_low_block; + int lpm_low_recovery; + int batt_int; + int wpc_charging_current; +}; + +#define ADJUST_RCOMP_WITH_CHARGING_STATUS +#define ADJUST_RCOMP_WITH_TEMPER + +#define POLLING_INTERVAL (40 * 1000) +#define MEASURE_DSG_INTERVAL (30 * 1000) +#define MEASURE_CHG_INTERVAL (30 * 1000) +#define ALARM_INTERVAL (5 * 60) +#define CHARGING_ALARM_INTERVAL (40) + +#define CURRENT_OF_FULL_CHG_UI 1800 /* 180mA */ +#define CURRENT_OF_FULL_CHG 1800 /* 180mA */ +#define RCOMP0_TEMP 20 /* 'C */ + +#define DEFAULT_CHG_TIME (6 * 60 * 60) /* 6hr */ +#define DEFAULT_RECHG_TIME (2 * 60 * 60) /* 2hr */ +#define DEFAULT_RECHG_VOLTAGE (4130 * 1000) /* 4.13 V */ +#define DEFAULT_MAX_VOLTAGE (4200 * 1000) /* 4.2 V */ +#define DEFAULT_TERMINATION_CURRENT 200 + +/* all count duration = (count - 1) * poll interval */ +#define RE_CHG_COND_COUNT 4 +#define TEMP_BLOCK_COUNT 2 +#define BAT_DET_COUNT 2 +#define FULL_CHG_COND_COUNT 2 +#define FULL_CHARGE_COND_VOLTAGE 4000000 +#define INIT_CHECK_COUNT 4 + +#define MAX_BATT_ADC_CHAN 3 + +#define TEMP_GPIO PM8XXX_AMUX_MPP_7 +#define TEMP_ADC_CHNNEL ADC_MPP_1_AMUX6 + +#define BATT_TYPE_NORMAL 0 /* 4.2V battery */ +#define BATT_TYPE_JAGUAR 1 /* 4.35V, new active battery */ +#define BATT_TYPE_D2_HIGH 2 /* 4.35V battery */ +#define BATT_TYPE_D2_ACTIVE 3 /* 4.35V, new active battery */ +#define BATT_TYPE_AEGIS2 4 /* 4.35V, new active battery */ + +#endif /* __MACH_SEC_BATTERY_H */ diff --git a/include/linux/sec_jack.h b/include/linux/sec_jack.h new file mode 100644 index 00000000000..36e0d40e155 --- /dev/null +++ b/include/linux/sec_jack.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 Samsung Electronics, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_SEC_HEADSET_H +#define __ASM_ARCH_SEC_HEADSET_H + +#ifdef __KERNEL__ + +extern struct switch_dev switch_jack_detection; +extern struct switch_dev switch_sendend; + +enum { + SEC_JACK_NO_DEVICE = 0x0, + SEC_HEADSET_4POLE = 0x01 << 0, + SEC_HEADSET_3POLE = 0x01 << 1, + SEC_TTY_DEVICE = 0x01 << 2, + SEC_FM_HEADSET = 0x01 << 3, + SEC_FM_SPEAKER = 0x01 << 4, + SEC_TVOUT_DEVICE = 0x01 << 5, + SEC_EXTRA_DOCK_SPEAKER = 0x01 << 6, + SEC_EXTRA_CAR_DOCK_SPEAKER = 0x01 << 7, + SEC_UNKNOWN_DEVICE = 0x01 << 8, +}; + +struct sec_jack_zone { + unsigned int adc_high; + unsigned int delay_ms; + unsigned int check_count; + unsigned int jack_type; +}; + +struct sec_jack_buttons_zone { + unsigned int code; + unsigned int adc_low; + unsigned int adc_high; +}; + +struct sec_jack_platform_data { +#if defined(CONFIG_SAMSUNG_JACK_GNDLDET) + int (*get_gnd_jack_state) (void); +#endif + int (*get_det_jack_state) (void); + int (*get_send_key_state) (void); + void (*set_micbias_state) (bool); + int (*get_adc_value) (void); + struct sec_jack_zone *zones; + struct sec_jack_buttons_zone *buttons_zones; + int num_zones; + int num_buttons_zones; + int det_int; + int send_int; +}; + +#endif + +#endif diff --git a/include/linux/sec_param.h b/include/linux/sec_param.h new file mode 100644 index 00000000000..2047e229a5f --- /dev/null +++ b/include/linux/sec_param.h @@ -0,0 +1,41 @@ +/* + * include/linux/sec_param.h + * + * Copyright (c) 2011 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +typedef struct _sec_param_data { + unsigned int debuglevel; + unsigned int uartsel; + unsigned int rory_control; + unsigned int movinand_checksum_done; + unsigned int movinand_checksum_pass; +#if defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_AEGIS2) + unsigned int slideCount; +#endif +#ifdef CONFIG_SEC_SSR_DEBUG_LEVEL_CHK + unsigned int cp_debuglevel; +#endif +} sec_param_data; + +typedef enum { + param_index_debuglevel, + param_index_uartsel, + param_rory_control, + param_index_movinand_checksum_done, + param_index_movinand_checksum_pass, +#if defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_AEGIS2) + param_slideCount, +#endif +#ifdef CONFIG_SEC_SSR_DEBUG_LEVEL_CHK + param_cp_debuglevel, +#endif +} sec_param_index; + +extern bool sec_open_param(void); +extern bool sec_get_param(sec_param_index index, void *value); +extern bool sec_set_param(sec_param_index index, void *value); diff --git a/include/linux/sii9234.h b/include/linux/sii9234.h new file mode 100644 index 00000000000..2aa11acbc1f --- /dev/null +++ b/include/linux/sii9234.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 Samsung Electronics, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _SII9234_H_ +#define _SII9234_H_ + +#ifdef __KERNEL__ + +struct sii9234_platform_data { + int (*get_irq)(void); + void (*hw_onoff)(bool); + void (*hw_reset)(void); + /*TBD*/ + int gpio; + void (*mhl_sel)(bool); + void (*gpio_cfg)(void); +#if defined(CONFIG_VIDEO_MHL_V2) || defined(CONFIG_VIDEO_MHL_TAB_V2) + int prio; + void (*enable)(bool enable); + void (*power)(int on); + void (*enable_vbus)(bool enable); +#ifdef CONFIG_MHL_NEW_CBUS_MSC_CMD + void (*vbus_present)(bool on , int mhl_charge); +#else + void (*vbus_present)(bool on); +#endif + u8 power_state; + struct i2c_client *mhl_tx_client; + struct i2c_client *tpi_client; + struct i2c_client *hdmi_rx_client; + struct i2c_client *cbus_client; +#endif + u32 swing_level; +}; + +extern u8 mhl_onoff_ex(bool on); + +#endif + +#endif diff --git a/include/linux/sii9234_rcp.h b/include/linux/sii9234_rcp.h new file mode 100644 index 00000000000..ebce0499dc3 --- /dev/null +++ b/include/linux/sii9234_rcp.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * + * Author: Dharam Kumar + * + * 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 __SII9234_RCP_H__ +#define __SII9234_RCP_H__ + +#define MAX_KEY_CODE 0x7F + +struct rcp_key { + char name[32]; + unsigned int valid:1; + u8 code; +}; + +/* + * List of All RCP key codes. By default,all keys are + * supported(all keys are send to platform).Userspace(Platform) need to decide + * how to act/process each received key. + */ + +const struct rcp_key code[MAX_KEY_CODE+1] = { + + {"SELECT", 1, 0x00}, + {"UP", 1, 0x01}, + {"DOWN", 1, 0x02}, + {"LEFT", 1, 0x03}, + {"RIGHT", 1, 0x04}, + {"RIGHT-UP", 1, 0x05}, + {"RIGHT-DOWN", 1, 0x06}, + {"LEFT-UP", 1, 0x07}, + {"LEFT-DOWN", 1, 0x08}, + {"ROOT-MENU", 1, 0x09}, + {"SETUP-MENU", 1, 0x0A}, + {"CONTENTS-MENU", 1, 0x0B}, + {"FAVORITE-MENU", 1, 0x0C}, + {"EXIT", 1, 0x0D}, + /* Reserved Block 0x0E-0x1F */ + {"RSVD", 1, 0x0E}, + {"RSVD", 1, 0x0F}, + {"RSVD", 1, 0x10}, + {"RSVD", 1, 0x11}, + {"RSVD", 1, 0x12}, + {"RSVD", 1, 0x13}, + {"RSVD", 1, 0x14}, + {"RSVD", 1, 0x15}, + {"RSVD", 1, 0x16}, + {"RSVD", 1, 0x17}, + {"RSVD", 1, 0x18}, + {"RSVD", 1, 0x19}, + {"RSVD", 1, 0x1A}, + {"RSVD", 1, 0x1B}, + {"RSVD", 1, 0x1C}, + {"RSVD", 1, 0x1D}, + {"RSVD", 1, 0x1E}, + {"RSVD", 1, 0x1F}, + /*Numeric Keys */ + {"NUM-0", 1, 0x20}, + {"NUM-1", 1, 0x21}, + {"NUM-2", 1, 0x22}, + {"NUM-3", 1, 0x23}, + {"NUM-4", 1, 0x24}, + {"NUM-5", 1, 0x25}, + {"NUM-6", 1, 0x26}, + {"NUM-7", 1, 0x27}, + {"NUM-8", 1, 0x28}, + {"CLEAR", 1, 0x2C}, + /* 0x2D-0x2F Reserved */ + {"RSVD", 1, 0x2D}, + {"RSVD", 1, 0x2E}, + {"RSVD", 1, 0x2F}, + + {"CHANNEL-UP", 1, 0x30}, + {"CHANNEL-DOWN", 1, 0x31}, + {"PREVIOUS-CHANNEL", 1, 0x32}, + {"SOUND-SELECT", 1, 0x33}, + {"INPUT-SELECT", 1, 0x34}, + {"SHOW-INFORMATION", 1, 0x35}, + {"HELP", 1, 0x36}, + {"PAGE-UP", 1, 0x37}, + {"PAGE-DOWN", 1, 0x38}, + /* 0x39-0x40 Reserved */ + {"RSVD", 1, 0x39}, + {"RSVD", 1, 0x3A}, + {"RSVD", 1, 0x3B}, + {"RSVD", 1, 0x3C}, + {"RSVD", 1, 0x3D}, + {"RSVD", 1, 0x3E}, + + {"VOLUME-UP", 1, 0x41}, + {"VOLUME-DOWN", 1, 0x42}, + {"MUTE", 1, 0x43}, + {"PLAY", 1, 0x44}, + {"STOP", 1, 0x45}, + {"PAUSE", 1, 0x46}, + {"RECORD", 1, 0x47}, + {"REWIND", 1, 0x48}, + {"FAST-FORWARD", 1, 0x49}, + {"EJECT", 1, 0x4A}, + {"FORWARD", 1, 0x4B}, + {"BACKWARD", 1, 0x4C}, + /*0x4D-0x4F Reserved */ + {"RSVD", 1, 0x4D}, + {"RSVD", 1, 0x4E}, + {"RSVD", 1, 0x4F}, + + {"ANGLE", 1, 0x50}, + {"SUB-PICTURE", 1, 0x51}, + /* 0x52-0x5F Reserved */ + {"RSVD", 1, 0x52}, + {"RSVD", 1, 0x53}, + {"RSVD", 1, 0x54}, + {"RSVD", 0, 0x55}, + {"RSVD", 1, 0x56}, + {"RSVD", 1, 0x57}, + {"RSVD", 1, 0x58}, + {"RSVD", 1, 0x59}, + {"RSVD", 1, 0x5A}, + {"RSVD", 1, 0x5B}, + {"RSVD", 1, 0x5C}, + {"RSVD", 1, 0x5D}, + + {"PLAY_FUNC", 1, 0x60}, + {"PAUSE_PLAY_FUNC", 1, 0x61}, + {"RECORD_FUNC", 1, 0x62}, + {"PAUSE_RECORD_FUNC", 1, 0x63}, + {"STOP_FUNC", 1, 0x64}, + {"MUTE_FUNC", 1, 0x65}, + {"RESTORE_VOLUME_FUNC", 1, 0x66}, + {"TUNE_FUNC", 1, 0x67}, + {"SELECT_MEDIA_FUNC", 1, 0x68}, + /* 0x69-0x70 Reserved */ + {"RSVD", 1, 0x69}, + {"RSVD", 1, 0x6A}, + {"RSVD", 1, 0x6B}, + {"RSVD", 1, 0x6C}, + {"RSVD", 1, 0x6D}, + {"RSVD", 1, 0x6E}, + {"RSVD", 1, 0x6F}, + {"RSVD", 1, 0x70}, + + {"F1", 1, 0x71}, + {"F2", 1, 0x72}, + {"F3", 1, 0x73}, + {"F4", 1, 0x74}, + {"F5", 1, 0x75}, + /* 0x76-0x7D Reserved */ + {"RSVD", 1, 0x76}, + {"RSVD", 1, 0x77}, + {"RSVD", 1, 0x78}, + {"RSVD", 1, 0x79}, + {"RSVD", 1, 0x7A}, + {"RSVD", 1, 0x7B}, + {"RSVD", 1, 0x7C}, + {"RSVD", 1, 0x7D}, + + {"VENDOR_SPECIFIC", 1, 0x7E}, + {"RSVD", 1, 0x7F} +}; + +#endif /* __SII9234_RCP_H__ */ diff --git a/include/linux/smb347_charger.h b/include/linux/smb347_charger.h new file mode 100644 index 00000000000..50d3531d0cc --- /dev/null +++ b/include/linux/smb347_charger.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * jongmyeong ko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SMB347_CHARGER_H_ +#define __SMB347_CHARGER_H_ + +struct smb347_platform_data { + void (*hw_init) (void); + int (*chg_intr_trigger) (int); + int enable; + int stat; + int (*smb347_using) (void); + unsigned int inok; + int (*smb347_inok_using) (void); +#ifdef CONFIG_WIRELESS_CHARGING + void (*smb347_wpc_cb) (void); +#endif + int (*smb347_get_cable) (void); +}; + +extern int poweroff_charging; + +#endif diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 61c946093dd..212fd130ed1 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -217,6 +217,7 @@ struct msm_otg_platform_data { bool core_clk_always_on_workaround; struct msm_bus_scale_pdata *bus_scale_table; const char *mhl_dev_name; + bool smb347s; }; /* Timeout (in msec) values (min - max) associated with OTG timers */ diff --git a/include/linux/vibrator.h b/include/linux/vibrator.h new file mode 100644 index 00000000000..cf6d9e45696 --- /dev/null +++ b/include/linux/vibrator.h @@ -0,0 +1,43 @@ +/* + * vibrator.h + * + * header file describing vibrator platform data for Samsung device + * + * COPYRIGHT(C) Samsung Electronics Co., Ltd. 2006-2011 All Right Reserved. + * + * 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. + */ + +#ifndef __VIBRATOR_H__ +#define __VIBRATOR_H__ + +enum vibrator_model { + NO_VIBRATOR, + HAPTIC_PWM, + HAPTIC_MOTOR,/* tspdrv flow will support this model as inbuilt */ +}; + +struct vibrator_platform_data { + unsigned int vib_pwm_gpio;/* gpio number for vibrator pwm */ + unsigned int haptic_pwr_en_gpio;/* gpio number of haptic power enable */ + unsigned int vib_en_gpio;/* gpio number of vibrator enable */ + unsigned int is_pmic_haptic_pwr_en; /* 1 -> pmic gpio used,\ + 0 -> msm gpio used */ + unsigned int is_pmic_vib_en; /* 1 -> pmic gpio used,\ + 0 -> msm gpio used */ + enum vibrator_model vib_model; +}; + +#endif diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 498a76221c1..e1c6ca429f3 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -2412,7 +2412,7 @@ struct v4l2_event { struct timespec timestamp; __u32 id; __u32 reserved[8]; -}; +} __attribute__((packed)); #define V4L2_EVENT_SUB_FL_SEND_INITIAL (1 << 0) #define V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK (1 << 1) diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h index d526cf7e87d..e928d163f8f 100644 --- a/include/media/msm_camera.h +++ b/include/media/msm_camera.h @@ -16,26 +16,44 @@ #ifdef MSM_CAMERA_BIONIC #include #endif -#include #include #include -#ifdef __KERNEL__ #include -#endif #ifdef MSM_CAMERA_GCC #include #else #include #endif -#include +#ifdef __KERNEL__ +#include +#endif -#define BIT(nr) (1UL << (nr)) +#define VFE_FRAME_NUM_MAX 0x00FFFFFF +#define ZERO_OUT_FRAME 0xFF000000 +#define CLEAR_FOCUS_BIT 0x7FFFFFFF +#define get_focus_bit(x) ({ \ + (x & 0x80000000) >> 31; \ +}) +#define get_frame_num(x) ({ \ + x & VFE_FRAME_NUM_MAX; \ +}) +#define get_focus_in_position(x) ({ \ + (x & 00000001) << 31; \ +}) +#define increment_frame_num(x) ({ \ + uint32_t num = get_frame_num(x); \ + num = num + 1; \ + (x & ZERO_OUT_FRAME) | num; \ +}) +#define decrement_frame_num(x) ({ \ + uint32_t num = get_frame_num(x); \ + num = num - 1; \ + (x & ZERO_OUT_FRAME) | num; \ +}) #define MSM_CAM_IOCTL_MAGIC 'm' -#define MAX_SERVER_PAYLOAD_LENGTH 8192 - #define MSM_CAM_IOCTL_GET_SENSOR_INFO \ _IOR(MSM_CAM_IOCTL_MAGIC, 1, struct msm_camsensor_info *) @@ -153,125 +171,64 @@ #define MSM_CAM_IOCTL_PUT_ST_FRAME \ _IOW(MSM_CAM_IOCTL_MAGIC, 39, struct msm_camera_st_frame *) +#define MSM_CAM_IOCTL_GET_CONFIG_INFO \ + _IOR(MSM_CAM_IOCTL_MAGIC, 40, struct msm_cam_config_dev_info *) + #define MSM_CAM_IOCTL_V4L2_EVT_NOTIFY \ - _IOW(MSM_CAM_IOCTL_MAGIC, 40, struct v4l2_event_and_payload) + _IOR(MSM_CAM_IOCTL_MAGIC, 41, struct v4l2_event *) #define MSM_CAM_IOCTL_SET_MEM_MAP_INFO \ - _IOR(MSM_CAM_IOCTL_MAGIC, 41, struct msm_mem_map_info *) + _IOR(MSM_CAM_IOCTL_MAGIC, 42, struct msm_mem_map_info *) #define MSM_CAM_IOCTL_ACTUATOR_IO_CFG \ - _IOW(MSM_CAM_IOCTL_MAGIC, 42, struct msm_actuator_cfg_data *) + _IOW(MSM_CAM_IOCTL_MAGIC, 43, struct msm_actuator_cfg_data *) #define MSM_CAM_IOCTL_MCTL_POST_PROC \ - _IOW(MSM_CAM_IOCTL_MAGIC, 43, struct msm_mctl_post_proc_cmd *) + _IOW(MSM_CAM_IOCTL_MAGIC, 44, struct msm_mctl_post_proc_cmd *) #define MSM_CAM_IOCTL_RESERVE_FREE_FRAME \ - _IOW(MSM_CAM_IOCTL_MAGIC, 44, struct msm_cam_evt_divert_frame *) + _IOW(MSM_CAM_IOCTL_MAGIC, 45, struct msm_cam_evt_divert_frame *) #define MSM_CAM_IOCTL_RELEASE_FREE_FRAME \ - _IOR(MSM_CAM_IOCTL_MAGIC, 45, struct msm_cam_evt_divert_frame *) + _IOR(MSM_CAM_IOCTL_MAGIC, 46, struct msm_cam_evt_divert_frame *) + +struct ioctl_native_cmd { + unsigned short mode; + unsigned short address; + unsigned short value_1; + unsigned short value_2; + unsigned short value_3; +}; #define MSM_CAM_IOCTL_PICT_PP_DIVERT_DONE \ - _IOR(MSM_CAM_IOCTL_MAGIC, 46, struct msm_pp_frame *) + _IOR(MSM_CAM_IOCTL_MAGIC, 47, struct msm_pp_frame *) #define MSM_CAM_IOCTL_SENSOR_V4l2_S_CTRL \ - _IOR(MSM_CAM_IOCTL_MAGIC, 47, struct v4l2_control) + _IOR(MSM_CAM_IOCTL_MAGIC, 48, struct v4l2_control) #define MSM_CAM_IOCTL_SENSOR_V4l2_QUERY_CTRL \ - _IOR(MSM_CAM_IOCTL_MAGIC, 48, struct v4l2_queryctrl) + _IOR(MSM_CAM_IOCTL_MAGIC, 49, struct v4l2_queryctrl) #define MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME \ - _IOW(MSM_CAM_IOCTL_MAGIC, 49, struct timeval *) + _IOW(MSM_CAM_IOCTL_MAGIC, 50, struct timeval *) #define MSM_CAM_IOCTL_SET_VFE_OUTPUT_TYPE \ - _IOW(MSM_CAM_IOCTL_MAGIC, 50, uint32_t *) - -#define MSM_CAM_IOCTL_MCTL_DIVERT_DONE \ - _IOR(MSM_CAM_IOCTL_MAGIC, 51, struct msm_cam_evt_divert_frame *) + _IOW(MSM_CAM_IOCTL_MAGIC, 51, uint32_t *) -#define MSM_CAM_IOCTL_GET_ACTUATOR_INFO \ - _IOW(MSM_CAM_IOCTL_MAGIC, 52, struct msm_actuator_cfg_data *) +#define MSM_CAM_IOCTL_GET_MCTL_INFO \ + _IOR(MSM_CAM_IOCTL_MAGIC, 52, struct msm_mctl_node_info *) -#define MSM_CAM_IOCTL_EEPROM_IO_CFG \ - _IOW(MSM_CAM_IOCTL_MAGIC, 53, struct msm_eeprom_cfg_data *) - -#define MSM_CAM_IOCTL_ISPIF_IO_CFG \ - _IOR(MSM_CAM_IOCTL_MAGIC, 54, struct ispif_cfg_data *) - -#define MSM_CAM_IOCTL_STATS_REQBUF \ - _IOR(MSM_CAM_IOCTL_MAGIC, 55, struct msm_stats_reqbuf *) - -#define MSM_CAM_IOCTL_STATS_ENQUEUEBUF \ - _IOR(MSM_CAM_IOCTL_MAGIC, 56, struct msm_stats_buf_info *) - -#define MSM_CAM_IOCTL_STATS_FLUSH_BUFQ \ - _IOR(MSM_CAM_IOCTL_MAGIC, 57, struct msm_stats_flush_bufq *) - -#define MSM_CAM_IOCTL_SET_MCTL_SDEV \ - _IOW(MSM_CAM_IOCTL_MAGIC, 58, struct msm_mctl_set_sdev_data *) - -#define MSM_CAM_IOCTL_UNSET_MCTL_SDEV \ - _IOW(MSM_CAM_IOCTL_MAGIC, 59, struct msm_mctl_set_sdev_data *) - -#define MSM_CAM_IOCTL_GET_INST_HANDLE \ - _IOR(MSM_CAM_IOCTL_MAGIC, 60, uint32_t *) - -#define MSM_CAM_IOCTL_STATS_UNREG_BUF \ - _IOR(MSM_CAM_IOCTL_MAGIC, 61, struct msm_stats_flush_bufq *) - -#define MSM_CAM_IOCTL_CSIC_IO_CFG \ - _IOWR(MSM_CAM_IOCTL_MAGIC, 62, struct csic_cfg_data *) - -#define MSM_CAM_IOCTL_CSID_IO_CFG \ - _IOWR(MSM_CAM_IOCTL_MAGIC, 63, struct csid_cfg_data *) - -#define MSM_CAM_IOCTL_CSIPHY_IO_CFG \ - _IOR(MSM_CAM_IOCTL_MAGIC, 64, struct csiphy_cfg_data *) - -#define MSM_CAM_IOCTL_OEM \ - _IOW(MSM_CAM_IOCTL_MAGIC, 65, struct sensor_cfg_data *) - -#define MSM_CAM_IOCTL_AXI_INIT \ - _IOWR(MSM_CAM_IOCTL_MAGIC, 66, uint8_t *) - -#define MSM_CAM_IOCTL_AXI_RELEASE \ - _IO(MSM_CAM_IOCTL_MAGIC, 67) +#define MSM_CAM_IOCTL_MCTL_DIVERT_DONE \ + _IOR(MSM_CAM_IOCTL_MAGIC, 53, struct msm_cam_evt_divert_frame *) #define MSM_CAM_IOCTL_V4L2_EVT_NATIVE_CMD \ - _IOWR(MSM_CAM_IOCTL_MAGIC, 68, struct msm_camera_v4l2_ioctl_t) + _IOWR(MSM_CAM_IOCTL_MAGIC, 54, struct ioctl_native_cmd *) #define MSM_CAM_IOCTL_V4L2_EVT_NATIVE_FRONT_CMD \ - _IOWR(MSM_CAM_IOCTL_MAGIC, 69, struct msm_camera_v4l2_ioctl_t) - -#define MSM_CAM_IOCTL_AXI_LOW_POWER_MODE \ - _IOWR(MSM_CAM_IOCTL_MAGIC, 70, uint8_t *) + _IOWR(MSM_CAM_IOCTL_MAGIC, 55, struct ioctl_native_cmd *) -#define MSM_CAM_IOCTL_INTF_MCTL_MAPPING_CFG \ - _IOR(MSM_CAM_IOCTL_MAGIC, 71, struct intf_mctl_mapping_cfg *) - -struct ioctl_native_cmd { - unsigned short mode; - unsigned short address; - unsigned short value_1; - unsigned short value_2; - unsigned short value_3; -}; - -struct v4l2_event_and_payload { - struct v4l2_event evt; - uint32_t payload_length; - uint32_t transaction_id; - void *payload; -}; - -struct msm_stats_reqbuf { - int num_buf; /* how many buffers requested */ - int stats_type; /* stats type */ -}; - -struct msm_stats_flush_bufq { - int stats_type; /* enum msm_stats_enum_type */ -}; +#define MCTL_CAM_IOCTL_SET_FOCUS \ + _IOW(MSM_CAM_IOCTL_MAGIC, 53, uint32_t) struct msm_mctl_pp_cmd { int32_t id; @@ -295,16 +252,6 @@ struct msm_mctl_post_proc_cmd { #define MSM_MAX_CAMERA_SENSORS 5 #define MAX_SENSOR_NAME 32 -#define MAX_CAM_NAME_SIZE 32 -#define MAX_ACT_MOD_NAME_SIZE 32 -#define MAX_ACT_NAME_SIZE 32 -#define NUM_ACTUATOR_DIR 2 -#define MAX_ACTUATOR_SCENARIO 8 -#define MAX_ACTUATOR_REGION 5 -#define MAX_ACTUATOR_INIT_SET 12 -#define MAX_ACTUATOR_TYPE_SIZE 32 -#define MAX_ACTUATOR_REG_TBL_SIZE 8 - #define MSM_MAX_CAMERA_CONFIGS 2 @@ -340,8 +287,6 @@ struct msm_ctrl_cmd { uint32_t timeout_ms; int resp_fd; /* FIXME: to be used by the kernel, pass-through for now */ int vnode_id; /* video dev id. Can we overload resp_fd? */ - int queue_idx; - uint32_t evt_id; uint32_t stream_type; /* used to pass value to qcamera server */ int config_ident; /*used as identifier for config node*/ }; @@ -352,7 +297,6 @@ struct msm_cam_evt_msg { unsigned int len; /* size in, number of bytes out */ uint32_t frame_id; void *data; - struct timespec timestamp; }; struct msm_pp_frame_sp { @@ -394,28 +338,6 @@ struct msm_pp_frame { struct msm_pp_frame_mp mp[MAX_PLANES]; }; int node_type; - uint32_t inst_handle; -}; - -struct msm_pp_crop { - uint32_t src_x; - uint32_t src_y; - uint32_t src_w; - uint32_t src_h; - uint32_t dst_x; - uint32_t dst_y; - uint32_t dst_w; - uint32_t dst_h; - uint8_t update_flag; -}; - -struct msm_mctl_pp_frame_cmd { - uint32_t cookie; - uint8_t vpe_output_action; - struct msm_pp_frame src_frame; - struct msm_pp_frame dest_frame; - struct msm_pp_crop crop; - int path; }; struct msm_cam_evt_divert_frame { @@ -423,8 +345,18 @@ struct msm_cam_evt_divert_frame { unsigned short op_mode; unsigned short inst_idx; unsigned short node_idx; + unsigned long phy_addr; + uint32_t phy_offset; + uint32_t y_off; + uint32_t cbcr_off; + int32_t fd; + uint32_t frame_id; + int path; + uint32_t length; + struct timeval timestamp; struct msm_pp_frame frame; int do_pp; + uint32_t vb; }; struct msm_mctl_pp_cmd_ack_event { @@ -448,6 +380,7 @@ struct msm_isp_event_ctrl { struct msm_cam_evt_divert_frame div_frame; struct msm_mctl_pp_event_info pp_event_info; } isp_data; + uint32_t evt_id; }; #define MSM_CAM_RESP_CTRL 0 @@ -540,44 +473,17 @@ struct msm_camera_cfg_cmd { #define CMD_AXI_CFG_ZSL 43 #define CMD_AXI_CFG_SNAP_VPE 44 #define CMD_AXI_CFG_SNAP_THUMB_VPE 45 - #define CMD_CONFIG_PING_ADDR 46 #define CMD_CONFIG_PONG_ADDR 47 #define CMD_CONFIG_FREE_BUF_ADDR 48 #define CMD_AXI_CFG_ZSL_ALL_CHNLS 49 #define CMD_AXI_CFG_VIDEO_ALL_CHNLS 50 #define CMD_VFE_BUFFER_RELEASE 51 -#define CMD_VFE_PROCESS_IRQ 52 -#define CMD_STATS_BG_ENABLE 53 -#define CMD_STATS_BF_ENABLE 54 -#define CMD_STATS_BHIST_ENABLE 55 -#define CMD_STATS_BG_BUF_RELEASE 56 -#define CMD_STATS_BF_BUF_RELEASE 57 -#define CMD_STATS_BHIST_BUF_RELEASE 58 -#define CMD_VFE_PIX_SOF_COUNT_UPDATE 59 -#define CMD_VFE_COUNT_PIX_SOF_ENABLE 60 - -#define CMD_AXI_CFG_PRIM BIT(8) -#define CMD_AXI_CFG_PRIM_ALL_CHNLS BIT(9) -#define CMD_AXI_CFG_SEC BIT(10) -#define CMD_AXI_CFG_SEC_ALL_CHNLS BIT(11) -#define CMD_AXI_CFG_TERT1 BIT(12) -#define CMD_AXI_CFG_TERT2 BIT(13) -#define CMD_AXI_CFG_TERT3 BIT(14) - -#define CMD_AXI_START 0xE1 -#define CMD_AXI_STOP 0xE2 -#define CMD_AXI_RESET 0xE3 -#define CMD_AXI_ABORT 0xE4 - - - -#define AXI_CMD_PREVIEW BIT(0) -#define AXI_CMD_CAPTURE BIT(1) -#define AXI_CMD_RECORD BIT(2) -#define AXI_CMD_ZSL BIT(3) -#define AXI_CMD_RAW_CAPTURE BIT(4) -#define AXI_CMD_LIVESHOT BIT(5) + +#define CMD_AXI_CFG_PRIM 0xF1 +#define CMD_AXI_CFG_PRIM_ALL_CHNLS 0xF2 +#define CMD_AXI_CFG_SEC 0xF4 +#define CMD_AXI_CFG_SEC_ALL_CHNLS 0xF8 /* vfe config command: config command(from config thread)*/ struct msm_vfe_cfg_cmd { @@ -617,10 +523,7 @@ struct camera_enable_cmd { #define MSM_PMEM_C2D 17 #define MSM_PMEM_MAINIMG_VPE 18 #define MSM_PMEM_THUMBNAIL_VPE 19 -#define MSM_PMEM_BAYER_GRID 20 -#define MSM_PMEM_BAYER_FOCUS 21 -#define MSM_PMEM_BAYER_HIST 22 -#define MSM_PMEM_MAX 23 +#define MSM_PMEM_MAX 20 #define STAT_AEAW 0 #define STAT_AEC 1 @@ -630,10 +533,7 @@ struct camera_enable_cmd { #define STAT_CS 5 #define STAT_IHIST 6 #define STAT_SKIN 7 -#define STAT_BG 8 -#define STAT_BF 9 -#define STAT_BHIST 10 -#define STAT_MAX 11 +#define STAT_MAX 8 #define FRAME_PREVIEW_OUTPUT1 0 #define FRAME_PREVIEW_OUTPUT2 1 @@ -642,37 +542,6 @@ struct camera_enable_cmd { #define FRAME_RAW_SNAPSHOT 4 #define FRAME_MAX 5 -enum msm_stats_enum_type { - MSM_STATS_TYPE_AEC, /* legacy based AEC */ - MSM_STATS_TYPE_AF, /* legacy based AF */ - MSM_STATS_TYPE_AWB, /* legacy based AWB */ - MSM_STATS_TYPE_RS, /* legacy based RS */ - MSM_STATS_TYPE_CS, /* legacy based CS */ - MSM_STATS_TYPE_IHIST, /* legacy based HIST */ - MSM_STATS_TYPE_SKIN, /* legacy based SKIN */ - MSM_STATS_TYPE_BG, /* Bayer Grids */ - MSM_STATS_TYPE_BF, /* Bayer Focus */ - MSM_STATS_TYPE_BHIST, /* Bayer Hist */ - MSM_STATS_TYPE_AE_AW, /* legacy stats for vfe 2.x*/ - MSM_STATS_TYPE_COMP, /* Composite stats */ - MSM_STATS_TYPE_MAX /* MAX */ -}; - -struct msm_stats_buf_info { - int type; /* msm_stats_enum_type */ - int fd; - void *vaddr; - uint32_t offset; - uint32_t len; - uint32_t y_off; - uint32_t cbcr_off; - uint32_t planar0_off; - uint32_t planar1_off; - uint32_t planar2_off; - uint8_t active; - int buf_idx; -}; - struct msm_pmem_info { int type; int fd; @@ -711,34 +580,24 @@ struct outputCfg { #define OUTPUT_ZSL_ALL_CHNLS 10 #define LAST_AXI_OUTPUT_MODE_ENUM = OUTPUT_ZSL_ALL_CHNLS -#define OUTPUT_PRIM BIT(8) -#define OUTPUT_PRIM_ALL_CHNLS BIT(9) -#define OUTPUT_SEC BIT(10) -#define OUTPUT_SEC_ALL_CHNLS BIT(11) -#define OUTPUT_TERT1 BIT(12) -#define OUTPUT_TERT2 BIT(13) -#define OUTPUT_TERT3 BIT(14) +#define OUTPUT_PRIM 0xF1 +#define OUTPUT_PRIM_ALL_CHNLS 0xF2 +#define OUTPUT_SEC 0xF4 +#define OUTPUT_SEC_ALL_CHNLS 0xF8 + #define MSM_FRAME_PREV_1 0 #define MSM_FRAME_PREV_2 1 #define MSM_FRAME_ENC 2 -#define OUTPUT_TYPE_P BIT(0) -#define OUTPUT_TYPE_T BIT(1) -#define OUTPUT_TYPE_S BIT(2) -#define OUTPUT_TYPE_V BIT(3) -#define OUTPUT_TYPE_L BIT(4) -#define OUTPUT_TYPE_ST_L BIT(5) -#define OUTPUT_TYPE_ST_R BIT(6) -#define OUTPUT_TYPE_ST_D BIT(7) -#define OUTPUT_TYPE_R BIT(8) -#define OUTPUT_TYPE_R1 BIT(9) -#define OUTPUT_TYPE_SAEC BIT(10) -#define OUTPUT_TYPE_SAFC BIT(11) -#define OUTPUT_TYPE_SAWB BIT(12) -#define OUTPUT_TYPE_IHST BIT(13) -#define OUTPUT_TYPE_CSTA BIT(14) -#define OUTPUT_TYPE_R2 BIT(15) +#define OUTPUT_TYPE_P (1<<0) +#define OUTPUT_TYPE_T (1<<1) +#define OUTPUT_TYPE_S (1<<2) +#define OUTPUT_TYPE_V (1<<3) +#define OUTPUT_TYPE_L (1<<4) +#define OUTPUT_TYPE_ST_L (1<<5) +#define OUTPUT_TYPE_ST_R (1<<6) +#define OUTPUT_TYPE_ST_D (1<<7) struct fd_roi_info { void *info; @@ -780,7 +639,6 @@ struct msm_frame { struct ion_allocation_data ion_alloc; struct ion_fd_data fd_data; - int ion_dev_fd; }; enum msm_st_frame_packing { @@ -839,7 +697,6 @@ struct msm_stats_buf { int length; struct ion_handle *handle; uint32_t frame_id; - int buf_idx; }; #define MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT 0 /* video capture mode in VIDIOC_S_PARM */ @@ -853,39 +710,10 @@ struct msm_stats_buf { /* extendedmode for the thumb nail image in VIDIOC_S_PARM */ #define MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL \ (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+4) -/* ISP_PIX_OUTPUT1: no pp, directly send output1 buf to user */ -#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT1 \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+5) -/* ISP_PIX_OUTPUT2: no pp, directly send output2 buf to user */ -#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT2 \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+6) -/* raw image type */ #define MSM_V4L2_EXT_CAPTURE_MODE_RAW \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+7) -/* RDI dump */ -#define MSM_V4L2_EXT_CAPTURE_MODE_RDI \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+8) -/* RDI dump 1 */ -#define MSM_V4L2_EXT_CAPTURE_MODE_RDI1 \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+9) -/* RDI dump 2 */ -#define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+10) -#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+11) -#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+12) -#define MSM_V4L2_EXT_CAPTURE_MODE_AF \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+13) -#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+14) -#define MSM_V4L2_EXT_CAPTURE_MODE_CS \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+15) -#define MSM_V4L2_EXT_CAPTURE_MODE_RS \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+16) -#define MSM_V4L2_EXT_CAPTURE_MODE_CSTA \ - (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+17) -#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18) + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+5) +#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+6) + #define MSM_V4L2_PID_MOTION_ISO V4L2_CID_PRIVATE_BASE #define MSM_V4L2_PID_EFFECT (V4L2_CID_PRIVATE_BASE+1) @@ -903,9 +731,10 @@ struct msm_stats_buf { #define MSM_V4L2_PID_CTRL_CMD (V4L2_CID_PRIVATE_BASE+13) #define MSM_V4L2_PID_EVT_SUB_INFO (V4L2_CID_PRIVATE_BASE+14) #define MSM_V4L2_PID_STROBE_FLASH (V4L2_CID_PRIVATE_BASE+15) -#define MSM_V4L2_PID_INST_HANDLE (V4L2_CID_PRIVATE_BASE+16) +#define MSM_V4L2_PID_MMAP_ENTRY (V4L2_CID_PRIVATE_BASE+16) #define MSM_V4L2_PID_MMAP_INST (V4L2_CID_PRIVATE_BASE+17) -#define MSM_V4L2_PID_PP_PLANE_INFO (V4L2_CID_PRIVATE_BASE+18) +#define MSM_V4L2_PID_PREVIEW_SIZE (V4L2_CID_PRIVATE_BASE+18) +#define MSM_V4L2_PID_PP_PLANE_INFO (V4L2_CID_PRIVATE_BASE+19) #define MSM_V4L2_PID_MAX MSM_V4L2_PID_PP_PLANE_INFO /* camera operation mode for video recording - two frame output queues */ @@ -938,8 +767,7 @@ struct msm_stats_buf { #define MSM_V4L2_CLOSE 11 #define MSM_V4L2_SET_CTRL_CMD 12 #define MSM_V4L2_EVT_SUB_MASK 13 -#define MSM_V4L2_PRIVATE_CMD 14 -#define MSM_V4L2_MAX 15 +#define MSM_V4L2_MAX 14 #define V4L2_CAMERA_EXIT 43 struct crop_info { @@ -991,49 +819,154 @@ struct msm_snapshot_pp_status { #define CFG_GET_3D_CALI_DATA 30 #define CFG_GET_CALIB_DATA 31 #define CFG_GET_OUTPUT_INFO 32 -#define CFG_GET_EEPROM_INFO 33 -#define CFG_GET_EEPROM_DATA 34 -#define CFG_SET_ACTUATOR_INFO 35 -#define CFG_GET_ACTUATOR_INFO 36 -/* TBD: QRD */ -#define CFG_SET_SATURATION 37 -#define CFG_SET_SHARPNESS 38 -#define CFG_SET_TOUCHAEC 39 -#define CFG_SET_AUTO_FOCUS 40 -#define CFG_SET_AUTOFLASH 41 -#define CFG_SET_EXPOSURE_COMPENSATION 42 -#define CFG_SET_ISO 43 -#define CFG_START_STREAM 44 -#define CFG_STOP_STREAM 45 -#define CFG_GET_CSI_PARAMS 46 -#define CFG_POWER_UP 47 -#define CFG_POWER_DOWN 48 -#define CFG_WRITE_I2C_ARRAY 49 -#define CFG_READ_I2C_ARRAY 50 -#define CFG_PCLK_CHANGE 51 -#define CFG_CONFIG_VREG_ARRAY 52 -#define CFG_CONFIG_CLK_ARRAY 53 -#define CFG_GPIO_OP 54 -#define CFG_SET_VISION_MODE 55 -#define CFG_SET_VISION_AE 56 -#define CFG_MAX 57 +#define CFG_GET_EEPROM_DATA 33 +#define CFG_SET_ACTUATOR_INFO 34 +#define CFG_GET_ACTUATOR_INFO 35 +#define CFG_MAX 36 #define MOVE_NEAR 0 #define MOVE_FAR 1 -#define SENSOR_PREVIEW_MODE 0 -#define SENSOR_SNAPSHOT_MODE 1 -#define SENSOR_RAW_SNAPSHOT_MODE 2 -#define SENSOR_HFR_60FPS_MODE 3 -#define SENSOR_HFR_90FPS_MODE 4 -#define SENSOR_HFR_120FPS_MODE 5 +#define CAMERA_MODE_INIT 0 +#define CAMERA_MODE_PREVIEW 1 +#define CAMERA_MODE_CAPTURE 2 +#define CAMERA_MODE_RECORDING 3 + +#define SENSOR_SNAPSHOT_MODE 0 +#define SENSOR_RAW_SNAPSHOT_MODE 1 +#define SENSOR_PREVIEW_MODE 2 +#define SENSOR_VIDEO_MODE 3 +#define SENSOR_HFR_60FPS_MODE 4 +#define SENSOR_HFR_90FPS_MODE 5 +#define SENSOR_HFR_120FPS_MODE 6 +#define SENSOR_INVALID_MODE 7 #define SENSOR_QTR_SIZE 0 #define SENSOR_FULL_SIZE 1 #define SENSOR_QVGA_SIZE 2 #define SENSOR_INVALID_SIZE 3 +#define CAMERA_EFFECT_OFF 0 +#define CAMERA_EFFECT_MONO 1 +#define CAMERA_EFFECT_NEGATIVE 2 +#define CAMERA_EFFECT_SOLARIZE 3 +#define CAMERA_EFFECT_SEPIA 4 +#define CAMERA_EFFECT_POSTERIZE 5 +#define CAMERA_EFFECT_WHITEBOARD 6 +#define CAMERA_EFFECT_BLACKBOARD 7 +#define CAMERA_EFFECT_AQUA 8 +#define CAMERA_EFFECT_EMBOSS 9 +#define CAMERA_EFFECT_SKETCH 10 +#define CAMERA_EFFECT_NEON 11 +#define CAMERA_EFFECT_WASHED 12 +#define CAMERA_EFFECT_VINTAGE_WARM 13 +#define CAMERA_EFFECT_VINTAGE_COLD 14 +#define CAMERA_EFFECT_POINT_COLOR_1 15 +#define CAMERA_EFFECT_POINT_COLOR_2 16 +#define CAMERA_EFFECT_POINT_COLOR_3 17 +#define CAMERA_EFFECT_POINT_COLOR_4 18 +#define CAMERA_EFFECT_MAX 19 + +#define CAMERA_WHITE_BALANCE_AUTO 1 +#define CAMERA_WHITE_BALANCE_INCANDESCENT 3 +#define CAMERA_WHITE_BALANCE_FLUORESCENT 4 +#define CAMERA_WHITE_BALANCE_DAYLIGHT 5 +#define CAMERA_WHITE_BALANCE_CLOUDY_DAYLIGHT 6 + +#define CAMERA_FLASH_OFF 0 +#define CAMERA_FLASH_ON 1 +#define CAMERA_FLASH_AUTO 2 +#define CAMERA_FLASH_TORCH 3 + +#define CAMERA_EV_M4 0 +#define CAMERA_EV_M3 1 +#define CAMERA_EV_M2 2 +#define CAMERA_EV_M1 3 +#define CAMERA_EV_DEFAULT 4 +#define CAMERA_EV_P1 5 +#define CAMERA_EV_P2 6 +#define CAMERA_EV_P3 7 +#define CAMERA_EV_P4 8 + +#define CAMERA_ISO_MODE_AUTO 0 +#define CAMERA_ISO_MODE_50 1 +#define CAMERA_ISO_MODE_100 2 +#define CAMERA_ISO_MODE_200 3 +#define CAMERA_ISO_MODE_400 4 +#define CAMERA_ISO_MODE_800 5 + +#define CAMERA_AVERAGE 0 +#define CAMERA_CENTER_WEIGHT 1 +#define CAMERA_SPOT 2 + +#define CAMERA_SCENE_AUTO 1 +#define CAMERA_SCENE_LANDSCAPE 2 +#define CAMERA_SCENE_BEACH 4 +#define CAMERA_SCENE_SUNSET 5 +#define CAMERA_SCENE_NIGHT 6 +#define CAMERA_SCENE_PORTRAIT 7 +#define CAMERA_SCENE_AGAINST_LIGHT 8 +#define CAMERA_SCENE_SPORT 9 +#define CAMERA_SCENE_CANDLE 12 +#define CAMERA_SCENE_FIRE 13 +#define CAMERA_SCENE_PARTY 14 +#define CAMERA_SCENE_TEXT 19 +#define CAMERA_SCENE_FALL 20 +#define CAMERA_SCENE_DAWN 21 + +#define CAMERA_AF_MACRO 1 +#define CAMERA_AF_AUTO 2 + +/*native cmd code*/ +#define EXT_CAM_AF 1 +#define EXT_CAM_FLASH_STATUS 2 +#define EXT_CAM_FLASH_MODE 3 +#define EXT_CAM_EV 4 +#define EXT_CAM_SCENE_MODE 5 +#define EXT_CAM_ISO 6 +#define EXT_CAM_METERING 7 +#define EXT_CAM_WB 8 +#define EXT_CAM_EFFECT 9 +#define EXT_CAM_FOCUS 10 +#define EXT_CAM_PREVIEW_SIZE 11 +#define EXT_CAM_MOVIE_MODE 12 +#define EXT_CAM_DTP_TEST 13 +#define EXT_CAM_SET_AF_STATUS 14 +#define EXT_CAM_GET_AF_STATUS 15 +#define EXT_CAM_GET_AF_RESULT 16 +#define EXT_CAM_SET_TOUCHAF_POS 17 +#define EXT_CAM_SET_AE_AWB 18 +#define EXT_CAM_START_CAPTURE 19 +#define EXT_CAM_QUALITY 20 +#define EXT_CAM_ZOOM 21 +#define EXT_CAM_FD_MODE 22 +#define EXT_CAM_SET_AF_STOP 23 +#define EXT_CAM_SET_ANTI_SHAKE 24 +#define EXT_CAM_SET_WDR 25 +#define EXT_CAM_SET_BEAUTY_SHOT 26 +#define EXT_CAM_EXIF 27 +#define EXT_CAM_SET_JPEG_SIZE 28 +#define EXT_CAM_SET_PREVIEW_SIZE 29 +#define EXT_CAM_SET_AF_MODE 30 +#define EXT_CAM_SET_FPS 31 +#define EXT_CAM_GET_FLASH_STATUS 32 +#define EXT_CAM_SET_HDR 33 +#define EXT_CAM_START_HDR 34 +#define EXT_CAM_START_AE_AWB_LOCK 35 +#define EXT_CAM_SET_VDIS 36 +#define EXT_CAM_VT_MODE 37 +#define EXT_CAM_GET_LUX 38 +#define EXT_CAM_SET_FACE_ZOOM 39 +#define EXT_CAM_SET_RECORD_SIZE 40 +#define EXT_CAM_GET_AE_AWB_LOCK 41 +#define EXT_CAM_UPDATE_FW 42 +#define EXT_CAM_ANTI_BANDING 43 +#define EXT_CAM_SAMSUNG_CAMERA 44 +#define EXT_CAM_SET_FLIP 45 +#define EXT_CAM_SET_LOW_LIGHT_MODE 46 +#define EXT_CAM_SET_LOW_LIGHT_SIZE 47 + /* QRD */ #define CAMERA_EFFECT_BW 10 #define CAMERA_EFFECT_BLUISH 12 @@ -1093,6 +1026,14 @@ struct msm_snapshot_pp_status { #define CAMERA_SETAE_AVERAGE 0 #define CAMERA_SETAE_CENWEIGHT 1 +#define CFG_SET_SATURATION 30 +#define CFG_SET_SHARPNESS 31 +#define CFG_SET_TOUCHAEC 32 +#define CFG_SET_AUTO_FOCUS 33 +#define CFG_SET_AUTOFLASH 34 +/* QRD */ +#define CFG_SET_EXPOSURE_COMPENSATION 35 + #define CAMERA_WB_AUTO 1 /* This list must match aeecamera.h */ #define CAMERA_WB_CUSTOM 2 #define CAMERA_WB_INCANDESCENT 3 @@ -1102,12 +1043,76 @@ struct msm_snapshot_pp_status { #define CAMERA_WB_TWILIGHT 7 #define CAMERA_WB_SHADE 8 +#define EXIF_SHUTTERSPEED 1 +#define EXIF_ISO 2 + #define CAMERA_EXPOSURE_COMPENSATION_LV0 12 #define CAMERA_EXPOSURE_COMPENSATION_LV1 6 #define CAMERA_EXPOSURE_COMPENSATION_LV2 0 #define CAMERA_EXPOSURE_COMPENSATION_LV3 -6 #define CAMERA_EXPOSURE_COMPENSATION_LV4 -12 +/* only for D2 : start*/ +enum msm_v4l2_AF_command { + MSM_V4L2_AF_SET_AUTO_FOCUS = 0, + MSM_V4L2_AF_SET_AUTO_FOCUS_MODE, + MSM_V4L2_AF_GET_AUTO_FOCUS, + MSM_V4L2_AF_GET_AUTO_FOCUS_RESULT, + MSM_V4L2_AF_SET_AUTO_FOCUS_DEFAULT_POSITION, + MSM_V4L2_AF_CANCEL_AUTO_FOCUS, + MSM_V4L2_CAF_FOCUS, + MSM_V4L2_AF_COMMAND_MAX +}; + +enum msm_v4l2_AF_status { + MSM_V4L2_AF_STATUS_IN_PROGRESS = 0, + MSM_V4L2_AF_STATUS_SUCCESS, + MSM_V4L2_AF_STATUS_FAIL, + MSM_V4L2_AF_STATUS_1ST_SUCCESS, + MSM_V4L2_AF_STATUS_RESTART, + MSM_V4L2_AF_STATUS_MAX +}; + +enum msm_v4l2_focusmode { + FOCUS_MODE_AUTO = 0, + FOCUS_MODE_MACRO, + FOCUS_MODE_FACEDETECT, + FOCUS_MODE_AUTO_DEFAULT, + FOCUS_MODE_MACRO_DEFAULT, + FOCUS_MODE_FACEDETECT_DEFAULT, + FOCUS_MODE_INFINITY, + FOCUS_MODE_FIXED, + FOCUS_MODE_CONTINOUS, + FOCUS_MODE_CONTINOUS_PICTURE, + FOCUS_MODE_CONTINOUS_PICTURE_MACRO, + FOCUS_MODE_CONTINOUS_VIDEO, + FOCUS_MODE_TOUCH, + FOCUS_MODE_MAX, + FOCUS_MODE_DEFAULT = (1 << 8), +}; + +enum msm_v4l2_face_zoom_mode { + FACE_ZOOM_STOP = 0, + FACE_ZOOM_START, +}; + +enum msm_v4l2_fw_control_mode { + CAM_FW_MODE_NONE = 0, + CAM_FW_MODE_VERSION, + CAM_FW_MODE_UPDATE, + CAM_FW_MODE_DUMP, + CAM_FW_MODE_MAX, +}; + +enum msm_v4l2_anti_banding_mode { + ANTI_BANDING_OFF = 0, + ANTI_BANDING_50HZ, + ANTI_BANDING_60HZ, + ANTI_BANDING_AUTO, + ANTI_BANDING_MAX, +}; +/* only for D2 : end*/ + enum msm_v4l2_saturation_level { MSM_V4L2_SATURATION_L0, MSM_V4L2_SATURATION_L1, @@ -1122,21 +1127,6 @@ enum msm_v4l2_saturation_level { MSM_V4L2_SATURATION_L10, }; -enum msm_v4l2_contrast_level { - MSM_V4L2_CONTRAST_L0, - MSM_V4L2_CONTRAST_L1, - MSM_V4L2_CONTRAST_L2, - MSM_V4L2_CONTRAST_L3, - MSM_V4L2_CONTRAST_L4, - MSM_V4L2_CONTRAST_L5, - MSM_V4L2_CONTRAST_L6, - MSM_V4L2_CONTRAST_L7, - MSM_V4L2_CONTRAST_L8, - MSM_V4L2_CONTRAST_L9, - MSM_V4L2_CONTRAST_L10, -}; - - enum msm_v4l2_exposure_level { MSM_V4L2_EXPOSURE_N2, MSM_V4L2_EXPOSURE_N1, @@ -1172,29 +1162,16 @@ enum msm_v4l2_iso_mode { }; enum msm_v4l2_wb_mode { - MSM_V4L2_WB_OFF, - MSM_V4L2_WB_AUTO , + MSM_V4L2_WB_MIN_MINUS_1, + MSM_V4L2_WB_AUTO = 1, MSM_V4L2_WB_CUSTOM, MSM_V4L2_WB_INCANDESCENT, MSM_V4L2_WB_FLUORESCENT, MSM_V4L2_WB_DAYLIGHT, MSM_V4L2_WB_CLOUDY_DAYLIGHT, -}; - -enum msm_v4l2_special_effect { - MSM_V4L2_EFFECT_OFF, - MSM_V4L2_EFFECT_MONO, - MSM_V4L2_EFFECT_NEGATIVE, - MSM_V4L2_EFFECT_SOLARIZE, - MSM_V4L2_EFFECT_SEPIA, - MSM_V4L2_EFFECT_POSTERAIZE, - MSM_V4L2_EFFECT_WHITEBOARD, - MSM_V4L2_EFFECT_BLACKBOARD, - MSM_V4L2_EFFECT_AQUA, - MSM_V4L2_EFFECT_EMBOSS, - MSM_V4L2_EFFECT_SKETCH, - MSM_V4L2_EFFECT_NEON, - MSM_V4L2_EFFECT_MAX, + MSM_V4L2_WB_TWILIGHT, + MSM_V4L2_WB_SHADE, + MSM_V4L2_WB_OFF, }; enum msm_v4l2_power_line_frequency { @@ -1204,14 +1181,6 @@ enum msm_v4l2_power_line_frequency { MSM_V4L2_POWER_LINE_AUTO, }; -#define CAMERA_ISO_TYPE_AUTO 0 -#define CAMEAR_ISO_TYPE_HJR 1 -#define CAMEAR_ISO_TYPE_100 2 -#define CAMERA_ISO_TYPE_200 3 -#define CAMERA_ISO_TYPE_400 4 -#define CAMEAR_ISO_TYPE_800 5 -#define CAMERA_ISO_TYPE_1600 6 - struct sensor_pict_fps { uint16_t prevfps; uint16_t pictfps; @@ -1317,31 +1286,9 @@ struct sensor_output_info_t { uint16_t num_info; }; -struct msm_sensor_exp_gain_info_t { - uint16_t coarse_int_time_addr; - uint16_t global_gain_addr; - uint16_t vert_offset; -}; - -struct msm_sensor_output_reg_addr_t { - uint16_t x_output; - uint16_t y_output; - uint16_t line_length_pclk; - uint16_t frame_length_lines; -}; - -struct sensor_driver_params_type { - struct msm_camera_i2c_reg_setting *init_settings; - uint16_t init_settings_size; - struct msm_camera_i2c_reg_setting *mode_settings; - uint16_t mode_settings_size; - struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr; - struct msm_camera_i2c_reg_setting *start_settings; - struct msm_camera_i2c_reg_setting *stop_settings; - struct msm_camera_i2c_reg_setting *groupon_settings; - struct msm_camera_i2c_reg_setting *groupoff_settings; - struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info; - struct msm_sensor_output_info_t *output_info; +struct sensor_eeprom_data_t { + void *eeprom_data; + uint16_t index; }; struct mirror_flip { @@ -1354,271 +1301,6 @@ struct cord { uint32_t y; }; -struct msm_eeprom_data_t { - void *eeprom_data; - uint16_t index; -}; - -struct msm_camera_csid_vc_cfg { - uint8_t cid; - uint8_t dt; - uint8_t decode_format; -}; - -struct csi_lane_params_t { - uint16_t csi_lane_assign; - uint8_t csi_lane_mask; - uint8_t csi_if; - uint8_t csid_core[2]; - uint8_t csi_phy_sel; -}; - -struct msm_camera_csid_lut_params { - uint8_t num_cid; - struct msm_camera_csid_vc_cfg *vc_cfg; -}; - -struct msm_camera_csid_params { - uint8_t lane_cnt; - uint16_t lane_assign; - uint8_t phy_sel; - struct msm_camera_csid_lut_params lut_params; -}; - -struct msm_camera_csiphy_params { - uint8_t lane_cnt; - uint8_t settle_cnt; - uint16_t lane_mask; - uint8_t combo_mode; -}; - -struct msm_camera_csi2_params { - struct msm_camera_csid_params csid_params; - struct msm_camera_csiphy_params csiphy_params; -}; - -enum msm_camera_csi_data_format { - CSI_8BIT, - CSI_10BIT, - CSI_12BIT, -}; - -struct msm_camera_csi_params { - enum msm_camera_csi_data_format data_format; - uint8_t lane_cnt; - uint8_t lane_assign; - uint8_t settle_cnt; - uint8_t dpcm_scheme; -}; - -enum csic_cfg_type_t { - CSIC_INIT, - CSIC_CFG, -}; - -struct csic_cfg_data { - enum csic_cfg_type_t cfgtype; - struct msm_camera_csi_params *csic_params; -}; - -enum csid_cfg_type_t { - CSID_INIT, - CSID_CFG, -}; - -struct csid_cfg_data { - enum csid_cfg_type_t cfgtype; - union { - uint32_t csid_version; - struct msm_camera_csid_params *csid_params; - } cfg; -}; - -enum csiphy_cfg_type_t { - CSIPHY_INIT, - CSIPHY_CFG, -}; - -struct csiphy_cfg_data { - enum csiphy_cfg_type_t cfgtype; - struct msm_camera_csiphy_params *csiphy_params; -}; - -#define CSI_EMBED_DATA 0x12 -#define CSI_RESERVED_DATA_0 0x13 -#define CSI_YUV422_8 0x1E -#define CSI_RAW8 0x2A -#define CSI_RAW10 0x2B -#define CSI_RAW12 0x2C -#define CSI_YUV420_Y_8 0x30 -#define CSI_YUV420_UV_8 0x31 -#define CSI_YUV420_JM_8 0x32 - -#define CSI_DECODE_6BIT 0 -#define CSI_DECODE_8BIT 1 -#define CSI_DECODE_10BIT 2 -#define CSI_DECODE_DPCM_10_8_10 5 - -#define ISPIF_STREAM(intf, action, vfe) (((intf)<> 24) : 0xFF) - -#define CLR_IMG_MODE(handle) (handle &= 0xFF00FFFF) -#define SET_IMG_MODE(handle, data) \ - (handle |= ((0x1 << 23) | ((data & 0x7F) << 16))) -#define GET_IMG_MODE(handle) \ - ((handle & 0x800000) ? ((handle & 0x7F0000) >> 16) : 0xFF) - -#define CLR_MCTLPP_INST_IDX(handle) (handle &= 0xFFFF00FF) -#define SET_MCTLPP_INST_IDX(handle, data) \ - (handle |= ((0x1 << 15) | ((data & 0x7F) << 8))) -#define GET_MCTLPP_INST_IDX(handle) \ - ((handle & 0x8000) ? ((handle & 0x7F00) >> 8) : 0xFF) - -#define CLR_VIDEO_INST_IDX(handle) (handle &= 0xFFFFFF00) -#define GET_VIDEO_INST_IDX(handle) \ - ((handle & 0x80) ? (handle & 0x7F) : 0xFF) -#define SET_VIDEO_INST_IDX(handle, data) \ - (handle |= (0x1 << 7) | (data & 0x7F)) - #endif /* __LINUX_MSM_CAMERA_H */ diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h index 19953ac695d..6636e94285e 100644 --- a/include/media/msm_isp.h +++ b/include/media/msm_isp.h @@ -59,19 +59,6 @@ #define MSG_ID_OUTPUT_PRIMARY 40 #define MSG_ID_OUTPUT_SECONDARY 41 #define MSG_ID_STATS_COMPOSITE 42 -#define MSG_ID_OUTPUT_TERTIARY1 43 -#define MSG_ID_STOP_LS_ACK 44 -#define MSG_ID_OUTPUT_TERTIARY2 45 -#define MSG_ID_STATS_BG 46 -#define MSG_ID_STATS_BF 47 -#define MSG_ID_STATS_BHIST 48 -#define MSG_ID_RDI0_UPDATE_ACK 49 -#define MSG_ID_RDI1_UPDATE_ACK 50 -#define MSG_ID_RDI2_UPDATE_ACK 51 -#define MSG_ID_PIX0_UPDATE_ACK 52 -#define MSG_ID_PREV_STOP_ACK 53 -#define MSG_ID_OUTPUT_TERTIARY3 54 - /* ISP command IDs */ #define VFE_CMD_DUMMY_0 0 @@ -212,35 +199,6 @@ #define VFE_CMD_SCALE_OUTPUT2_CONFIG 135 #define VFE_CMD_CAPTURE_RAW 136 #define VFE_CMD_STOP_LIVESHOT 137 -#define VFE_CMD_RECONFIG_VFE 138 -#define VFE_CMD_STATS_REQBUF 139 -#define VFE_CMD_STATS_ENQUEUEBUF 140 -#define VFE_CMD_STATS_FLUSH_BUFQ 141 -#define VFE_CMD_STATS_UNREGBUF 142 -#define VFE_CMD_STATS_BG_START 143 -#define VFE_CMD_STATS_BG_STOP 144 -#define VFE_CMD_STATS_BF_START 145 -#define VFE_CMD_STATS_BF_STOP 146 -#define VFE_CMD_STATS_BHIST_START 147 -#define VFE_CMD_STATS_BHIST_STOP 148 -#define VFE_CMD_RESET_2 149 -#define VFE_CMD_FOV_ENC_CFG 150 -#define VFE_CMD_FOV_VIEW_CFG 151 -#define VFE_CMD_FOV_ENC_UPDATE 152 -#define VFE_CMD_FOV_VIEW_UPDATE 153 -#define VFE_CMD_SCALER_ENC_CFG 154 -#define VFE_CMD_SCALER_VIEW_CFG 155 -#define VFE_CMD_SCALER_ENC_UPDATE 156 -#define VFE_CMD_SCALER_VIEW_UPDATE 157 -#define VFE_CMD_COLORXFORM_ENC_CFG 158 -#define VFE_CMD_COLORXFORM_VIEW_CFG 159 -#define VFE_CMD_COLORXFORM_ENC_UPDATE 160 -#define VFE_CMD_COLORXFORM_VIEW_UPDATE 161 -#define VFE_CMD_TEST_GEN_CFG 162 -#define VFE_CMD_SELECT_RDI 163 -#define VFE_CMD_SET_STATS_VER 164 -#define VFE_CMD_RGB_ALL_CFG 165 -#define VFE_CMD_RGB_ALL_UPDATE 166 struct msm_isp_cmd { int32_t id; @@ -260,6 +218,7 @@ struct msm_isp_cmd { #define VPE_CMD_OUTPUT_PLANE_CFG 9 #define VPE_CMD_INPUT_PLANE_UPDATE 10 #define VPE_CMD_SCALE_CFG_TYPE 11 +#define VPE_CMD_DIS_OFFSET_CFG 12 #define VPE_CMD_ZOOM 13 #define VPE_CMD_MAX 14 @@ -277,13 +236,14 @@ struct msm_isp_cmd { #define MCTL_PP_EVENT_CMD_ACK 1 #define VPE_OPERATION_MODE_CFG_LEN 4 +#define VPE_OPERATION_MODE_CFG_LEN_ZSL 8 #define VPE_INPUT_PLANE_CFG_LEN 24 #define VPE_OUTPUT_PLANE_CFG_LEN 20 +#define VPE_OUTPUT_PLANE_CFG_LEN_ZSL 24 #define VPE_INPUT_PLANE_UPDATE_LEN 12 #define VPE_SCALER_CONFIG_LEN 260 #define VPE_DIS_OFFSET_CFG_LEN 12 - #define CAPTURE_WIDTH 1280 #define IMEM_Y_SIZE (CAPTURE_WIDTH*16) #define IMEM_CBCR_SIZE (CAPTURE_WIDTH*8) @@ -299,6 +259,10 @@ struct msm_vpe_op_mode_cfg { uint8_t op_mode_cfg[VPE_OPERATION_MODE_CFG_LEN]; }; +struct msm_vpe_op_mode_cfg_zsl { + uint8_t op_mode_cfg[VPE_OPERATION_MODE_CFG_LEN_ZSL]; +}; + struct msm_vpe_input_plane_cfg { uint8_t input_plane_cfg[VPE_INPUT_PLANE_CFG_LEN]; }; @@ -307,6 +271,10 @@ struct msm_vpe_output_plane_cfg { uint8_t output_plane_cfg[VPE_OUTPUT_PLANE_CFG_LEN]; }; +struct msm_vpe_output_plane_cfg_zsl { + uint8_t output_plane_cfg[VPE_OUTPUT_PLANE_CFG_LEN_ZSL]; +}; + struct msm_vpe_input_plane_update_cfg { uint8_t input_plane_update_cfg[VPE_INPUT_PLANE_UPDATE_LEN]; }; @@ -315,6 +283,10 @@ struct msm_vpe_scaler_cfg { uint8_t scaler_cfg[VPE_SCALER_CONFIG_LEN]; }; +struct msm_vpe_dis_offset_cfg { + uint8_t dis_offset_cfg[VPE_DIS_OFFSET_CFG_LEN]; +}; + struct msm_vpe_flush_frame_buffer { uint32_t src_buf_handle; uint32_t dest_buf_handle; @@ -332,35 +304,41 @@ struct msm_mctl_pp_divert_pp { struct msm_vpe_clock_rate { uint32_t rate; }; - +struct msm_pp_crop { + uint32_t src_x; + uint32_t src_y; + uint32_t src_w; + uint32_t src_h; + uint32_t dst_x; + uint32_t dst_y; + uint32_t dst_w; + uint32_t dst_h; + uint8_t update_flag; +}; #define MSM_MCTL_PP_VPE_FRAME_ACK (1<<0) #define MSM_MCTL_PP_VPE_FRAME_TO_APP (1<<1) -#define VFE_OUTPUTS_MAIN_AND_PREVIEW BIT(0) -#define VFE_OUTPUTS_MAIN_AND_VIDEO BIT(1) -#define VFE_OUTPUTS_MAIN_AND_THUMB BIT(2) -#define VFE_OUTPUTS_THUMB_AND_MAIN BIT(3) -#define VFE_OUTPUTS_PREVIEW_AND_VIDEO BIT(4) -#define VFE_OUTPUTS_VIDEO_AND_PREVIEW BIT(5) -#define VFE_OUTPUTS_PREVIEW BIT(6) -#define VFE_OUTPUTS_VIDEO BIT(7) -#define VFE_OUTPUTS_RAW BIT(8) -#define VFE_OUTPUTS_JPEG_AND_THUMB BIT(9) -#define VFE_OUTPUTS_THUMB_AND_JPEG BIT(10) -#define VFE_OUTPUTS_RDI0 BIT(11) -#define VFE_OUTPUTS_RDI1 BIT(12) -#define VFE_OUTPUTS_RDI2 BIT(13) - -#define VFE_RDI_COMPOSITE (1 << 0) -#define VFE_RDI_NON_COMPOSITE (1 << 1) - -#define VFE_STATS_TYPE_LEGACY 0 -#define VFE_STATS_TYPE_BAYER (1 << 2) - -struct msm_frame_info { - uint32_t inst_handle; - uint32_t path; +struct msm_mctl_pp_frame_cmd { + uint32_t cookie; + uint8_t vpe_output_action; + uint32_t src_buf_handle; + uint32_t dest_buf_handle; + struct msm_pp_crop crop; + int path; + /* TBD: 3D related */ }; +#define VFE_OUTPUTS_MAIN_AND_PREVIEW BIT(0) +#define VFE_OUTPUTS_MAIN_AND_VIDEO BIT(1) +#define VFE_OUTPUTS_MAIN_AND_THUMB BIT(2) +#define VFE_OUTPUTS_THUMB_AND_MAIN BIT(3) +#define VFE_OUTPUTS_PREVIEW_AND_VIDEO BIT(4) +#define VFE_OUTPUTS_VIDEO_AND_PREVIEW BIT(5) +#define VFE_OUTPUTS_PREVIEW BIT(6) +#define VFE_OUTPUTS_VIDEO BIT(7) +#define VFE_OUTPUTS_RAW BIT(8) +#define VFE_OUTPUTS_JPEG_AND_THUMB BIT(9) +#define VFE_OUTPUTS_THUMB_AND_JPEG BIT(10) + #endif /*__MSM_ISP_H__*/ diff --git a/include/sound/a2220.h b/include/sound/a2220.h new file mode 100644 index 00000000000..9121d71ed0d --- /dev/null +++ b/include/sound/a2220.h @@ -0,0 +1,237 @@ +/* include/linux/a2220.h - a2220 voice processor driver + * + * Copyright (C) 2009 HTC Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __LINUX_A2220_H +#define __LINUX_A2220_H + +#include + +extern bool dualmic_enabled; + +struct a2220img { + unsigned char *buf; + unsigned img_size; +}; + +enum A2220_PathID { + A2220_PATH_SUSPEND, + A2220_PATH_INCALL_RECEIVER_NSON, + A2220_PATH_INCALL_RECEIVER_NSON_WB, + A2220_PATH_INCALL_RECEIVER_NSOFF, + A2220_PATH_INCALL_HEADSET, + A2220_PATH_INCALL_SPEAKER, + A2220_PATH_INCALL_BT, + A2220_PATH_VR_NO_NS_RECEIVER, + A2220_PATH_VR_NO_NS_HEADSET, + A2220_PATH_VR_NO_NS_SPEAKER, + A2220_PATH_VR_NO_NS_BT, + A2220_PATH_VR_NS_RECEIVER, + A2220_PATH_VR_NS_HEADSET, + A2220_PATH_VR_NS_SPEAKER, + A2220_PATH_VR_NS_BT, + A2220_PATH_RECORD_RECEIVER, + A2220_PATH_RECORD_HEADSET, + A2220_PATH_RECORD_SPEAKER, + A2220_PATH_RECORD_BT, + A2220_PATH_CAMCORDER, + A2220_PATH_INCALL_TTY, + A2220_PATH_PCMRESET, + A2220_PATH_FT_LOOPBACK, +#ifdef AUDIENCE_BYPASS + A2220_PATH_BYPASS_MULTIMEDIA, +#endif +}; + +/* noise suppression states */ +enum A2220_NS_states { + A2220_NS_STATE_AUTO, /* leave mode as selected by driver */ + A2220_NS_STATE_OFF, /* disable noise suppression */ + A2220_NS_STATE_CT, /* force close talk mode */ + A2220_NS_STATE_FT, /* force far talk mode */ + A2220_NS_NUM_STATES +}; + +/* indicates if a2220_set_config() performs a full configuration or only + * a voice processing algorithm configuration */ +/* IOCTLs for Audience A2220 */ +#define A2220_IOCTL_MAGIC 'u' + +#define A2220_BOOTUP_INIT _IOW(A2220_IOCTL_MAGIC, 0x01, struct a2220img *) +#define A2220_SET_CONFIG _IOW(A2220_IOCTL_MAGIC, 0x02, enum A2220_PathID) +#define A2220_SET_NS_STATE _IOW(A2220_IOCTL_MAGIC, 0x03, enum A2220_NS_states) +/* For Diag */ +#define A2220_SET_MIC_ONOFF _IOW(A2220_IOCTL_MAGIC, 0x50, unsigned) +#define A2220_SET_MICSEL_ONOFF _IOW(A2220_IOCTL_MAGIC, 0x51, unsigned) +#define A2220_READ_DATA _IOR(A2220_IOCTL_MAGIC, 0x52, unsigned) +#define A2220_WRITE_MSG _IOW(A2220_IOCTL_MAGIC, 0x53, unsigned) +#define A2220_SYNC_CMD _IO(A2220_IOCTL_MAGIC, 0x54) +#define A2220_SET_CMD_FILE _IOW(A2220_IOCTL_MAGIC, 0x55, unsigned) + +#ifdef __KERNEL__ + +/* A2220 Command codes */ +#define CtrlMode_LAL 0x0001 /* Level Active Low */ +#define CtrlMode_LAH 0x0002 /* Level Active High */ +#define CtrlMode_FE 0x0003 /* Falling Edge */ +#define CtrlMode_RE 0x0004 /* Rising Edge */ +#define A100_msg_Sync 0x80000000 +#define A100_msg_Sync_Ack 0x80000000 + +#define A100_msg_Reset 0x8002 +#define RESET_IMMEDIATE 0x0000 +#define RESET_DELAYED 0x0001 + +#define A100_msg_BootloadInitiate 0x8003 +#define A100_msg_GetDeviceParm 0x800B +#define A100_msg_SetDeviceParmID 0x800C +#define A100_msg_SetDeviceParm 0x800D + +/* Get/Set PCM Device Parameter ID List */ +/* PCM-0 */ +#define PCM0WordLength 0x0100 +#define PCM0DelFromFsTx 0x0101 +#define PCM0DelFromFsRx 0x0102 +#define PCM0LatchEdge 0x0103 +#define PCM0Endianness 0x0105 +#define PCM0TristateEnable 0x0107 + +/* PCM-1 */ +#define PCM1WordLength 0x0200 +#define PCM1DelFromFsTx 0x0201 +#define PCM1DelFromFsRx 0x0202 +#define PCM1LatchEdge 0x0203 +#define PCM1Endianness 0x0205 +#define PCM1TristateEnable 0x0207 +/* Possible setting values for PCM I/F */ +#define PCMWordLength_16bit 0x10 /* Default */ +#define PCMWordLength_24bit 0x18 +#define PCMWordLength_32bit 0x20 +#define PCMLatchEdge_Tx_F_Rx_R 0x00 /* Tx/Rx on falling/rising edge */ +#define PCMLatchEdge_Tx_R_Rx_F 0x03 /* Tx/Rx on falling/rising edge */ +#define PCMEndianness_Little 0x00 +#define PCMEndianness_Big 0x01 /* Default */ +#define PCMTristate_Disable 0x00 /* Default */ +#define PCMTristate_Enable 0x01 + +/* Get/Set ADC Device Parameter ID List */ +/* ADC-0 */ +#define ADC0Gain 0x0300 +#define ADC0Rate 0x0301 +#define ADC0CutoffFreq 0x0302 + +/* ADC-1 */ +#define ADC1Gain 0x0400 +#define ADC1Rate 0x0401 +#define ADC1CutoffFreq 0x0402 + +/* Possible setting values for ADC I/F */ +#define ADC_Gain_0db 0x00 +#define ADC_Gain_6db 0x01 +#define ADC_Gain_12db 0x02 +#define ADC_Gain_18db 0x03 +#define ADC_Gain_24db 0x04 /* Default */ +#define ADC_Gain_30db 0x05 +#define ADC_Rate_8kHz 0x00 /* Default */ +#define ADC_Rate_16kHz 0x01 +#define ADC_CutoffFreq_NO_DC_Filter 0x00 +#define ADC_CutoffFreq_59p68Hz 0x01 /* Default */ +#define ADC_CutoffFreq_7p46Hz 0x02 +#define ADC_CutoffFreq_3p73Hz 0x03 + +/* Set Power State */ +#define A100_msg_Sleep 0x80100001 + +/* Get/Set Algorithm Parameter command codes list */ +#define A100_msg_GetAlgorithmParm 0x8016 +#define A100_msg_SetAlgorithmParmID 0x8017 +#define A100_msg_SetAlgorithmParm 0x8018 +/* Get/Set Algorithm Parameter ID List (Transmit Feature) */ +#define AIS_Global_Supression_Level 0x0000 +#define Mic_Config 0x0002 +#define AEC_Mode 0x0003 +#define AEC_CNG 0x0023 +#define Output_AGC 0x0004 +#define Output_AGC_Target_Level 0x0005 +#define Output_AGC_Noise_Floor 0x0006 +#define Output_AGC_SNR_Improvement 0x0007 +#define Comfort_Noise 0x001A +#define Comfort_Noise_Level 0x001B + +/* Get/Set Algorithm Parameter ID List (Receive Feature) */ +#define Speaker_Volume 0x0012 +#define VEQ_Mode 0x0009 +#define VEQ_Max_FarEnd_Limiter_Level 0x000D +#define VEQ_Noise_Estimation_Adj 0x0025 +#define Receive_NS 0x000E +#define Receive_NS_Level 0x000F +#define SideTone 0x0015 +#define SideTone_Gain 0x0016 + +/* Audio Path Commands */ +/* Get/Set Transmit Digital Input Gain */ +#define A100_msg_GetTxDigitalInputGain 0x801A +#define A100_msg_SetTxDigitalInputGain 0x801B + +/* Get/Set Receive Digital Input Gain */ +#define A100_msg_GetRcvDigitalInputGain 0x8022 +#define A100_msg_SetRcvDigitalInputGain 0x8023 + +/* Get/Set Transmit Digital Output Gain */ +#define A100_msg_GetTxDigitalOutputGain 0x801D +#define A100_msg_SetTxDigitalOutputGain 0x8015 + +/* Bypass */ +#define A100_msg_Bypass 0x801C /* 0ff = 0x0000; on = 0x0001 (Default) */ +#define A2220_msg_VP_ON 0x801C0001 +#define A2220_msg_VP_OFF 0x801C0000 + +/* Diagnostic API Commands */ +#define A100_msg_GetMicRMS 0x8013 +#define A100_msg_GetMicPeak 0x8014 +#define DiagPath_Pri_Input_Mic 0x0000 +#define DiagPath_Sec_Input_Mic 0x0001 +#define DiagPath_Output_Mic 0x0002 +#define DiagPath_Far_End_Input 0x0003 +#define DiagPath_Far_End_Output 0x0004 +#define A100_msg_SwapInputCh 0x8019 +#define A100_msg_OutputKnownSig 0x801E + +#define A2220_msg_BOOT 0x0001 +#define A2220_msg_BOOT_ACK 0x01 + +/* general definitions */ +#define TIMEOUT 20 /* ms */ +#define RETRY_CNT 5 +#define POLLING_RETRY_CNT 3 +#define A2220_ERROR_CODE 0xffff +#define A2220_SLEEP 0 +#define A2220_ACTIVE 1 +#define A2220_CMD_FIFO_DEPTH 64 + +enum A2220_config_mode { + A2220_CONFIG_FULL, + A2220_CONFIG_VP +}; + +struct a2220_platform_data { + int (*a2220_hw_init)(void); + int gpio_reset; + int gpio_wakeup; +}; + + +#endif /* __KERNEL__ */ +#endif /* __LINUX_A2220_H */ + diff --git a/include/sound/soc-dsp.h b/include/sound/soc-dsp.h new file mode 100644 index 00000000000..df8437c0e19 --- /dev/null +++ b/include/sound/soc-dsp.h @@ -0,0 +1,124 @@ +/* + * linux/sound/soc-dsp.h -- ALSA SoC DSP + * + * Author: Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_SOC_DSP_H +#define __LINUX_SND_SOC_DSP_H + +#include + +struct snd_soc_dapm_widget; + +/* + * DSP trigger ordering. Triggering flexibility is required as some DSPs + * require triggering before/after their clients/hosts. + * + * i.e. some clients may want to manually order this call in their PCM + * trigger() whilst others will just use the regular core ordering. + */ +enum snd_soc_dsp_trigger { + SND_SOC_DSP_TRIGGER_PRE = 0, + SND_SOC_DSP_TRIGGER_POST, + SND_SOC_DSP_TRIGGER_BESPOKE, +}; + +/* + * The DSP Backend state. + */ +enum snd_soc_dsp_link_state { + SND_SOC_DSP_LINK_STATE_NEW = 0, /* newly created path */ + SND_SOC_DSP_LINK_STATE_FREE, /* path to be dismantled */ + SND_SOC_DSP_LINK_STATE_HW_PARAMS, /* path hw_params configured */ + SND_SOC_DSP_LINK_STATE_PREPARE, /* path is prepared */ + SND_SOC_DSP_LINK_STATE_START, /* path is started */ + SND_SOC_DSP_LINK_STATE_PAUSED, /* path is paused */ +}; + +struct snd_soc_dsp_params { + struct snd_soc_pcm_runtime *be; + struct snd_soc_pcm_runtime *fe; + enum snd_soc_dsp_link_state state; + struct list_head list_be; + struct list_head list_fe; + struct snd_pcm_hw_params params; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_state; +#endif +}; + +struct snd_soc_dsp_link { + bool capture; + bool playback; + enum snd_soc_dsp_trigger trigger[2]; +}; + +/* FE DSP PCM ops - called by soc-core */ +int soc_dsp_fe_dai_open(struct snd_pcm_substream *substream); +int soc_dsp_fe_dai_close(struct snd_pcm_substream *substream); +int soc_dsp_fe_dai_prepare(struct snd_pcm_substream *substream); +int soc_dsp_fe_dai_hw_free(struct snd_pcm_substream *substream); +int soc_dsp_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd); +int soc_dsp_fe_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); + +/* Backend DSP trigger. + * Can be called by core or components depending on trigger config. + */ +int soc_dsp_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd); + +/* Is this trigger() call required for this BE and stream */ +static inline int snd_soc_dsp_is_trigger_for_be(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, int stream) +{ + if (!fe->dpcm[stream].runtime_update) + return 1; + else if (be->dpcm[stream].runtime_update) + return 1; + else + return 0; +} + +/* Is this trigger() call required for this FE and stream */ +static inline int snd_soc_dsp_is_trigger_for_fe(struct snd_soc_pcm_runtime *fe, + int stream) +{ + return !fe->dpcm[stream].runtime_update; +} + +static inline int snd_soc_dsp_platform_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_platform *platform) +{ + if (platform->driver->ops->trigger) + return platform->driver->ops->trigger(substream, cmd); + return 0; +} + +/* Runtime update - open/close Backend DSP paths depending on mixer updates */ +int soc_dsp_runtime_update(struct snd_soc_dapm_widget *widget); + +/* Backend DSP suspend and resume */ +int soc_dsp_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute); +int soc_dsp_be_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe); +int soc_dsp_be_ac97_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe); +int soc_dsp_be_platform_suspend(struct snd_soc_pcm_runtime *fe); +int soc_dsp_be_cpu_dai_resume(struct snd_soc_pcm_runtime *fe); +int soc_dsp_be_ac97_cpu_dai_resume(struct snd_soc_pcm_runtime *fe); +int soc_dsp_be_platform_resume(struct snd_soc_pcm_runtime *fe); + +/* DAPM stream events for Backend DSP paths */ +int soc_dsp_dapm_stream_event(struct snd_soc_pcm_runtime *fe, + int dir, const char *stream, int event); + +static inline struct snd_pcm_substream *snd_soc_dsp_get_substream( + struct snd_soc_pcm_runtime *be, int stream) +{ + return be->pcm->streams[stream].substream; +} + +#endif diff --git a/include/trace/trace_msm_low_power.h b/include/trace/trace_msm_low_power.h new file mode 100644 index 00000000000..4e9da85690d --- /dev/null +++ b/include/trace/trace_msm_low_power.h @@ -0,0 +1,154 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM msm_low_power + +#if !defined(_TRACE_MSM_LOW_POWER_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MSM_LOW_POWER_H_ + +#include + +DECLARE_EVENT_CLASS(msm_pm_enter, + + TP_PROTO(unsigned int cpu, uint32_t latency, + uint32_t sleep_us, uint32_t wake_up), + + TP_ARGS(cpu, latency, sleep_us, wake_up), + + TP_STRUCT__entry( + __field(unsigned int, cpu) + __field(uint32_t, latency) + __field(uint32_t, sleep_us) + __field(uint32_t, wake_up) + ), + + TP_fast_assign( + __entry->cpu = cpu; + __entry->latency = latency; + __entry->sleep_us = sleep_us; + __entry->wake_up = wake_up; + ), + + TP_printk("cpu: %u latency: %uus sleep: %uus wake_up: %u", + __entry->cpu, + __entry->latency, + __entry->sleep_us, + __entry->wake_up) +); + +DEFINE_EVENT(msm_pm_enter, msm_pm_enter_pc, + + TP_PROTO(unsigned int cpu, uint32_t latency, + uint32_t sleep_us, uint32_t wake_up), + + TP_ARGS(cpu, latency, sleep_us, wake_up) +); + +DEFINE_EVENT(msm_pm_enter, msm_pm_enter_ret, + + TP_PROTO(unsigned int cpu, uint32_t latency, + uint32_t sleep_us, uint32_t wake_up), + + TP_ARGS(cpu, latency, sleep_us, wake_up) +); + +DEFINE_EVENT(msm_pm_enter, msm_pm_enter_spc, + + TP_PROTO(unsigned int cpu, uint32_t latency, + uint32_t sleep_us, uint32_t wake_up), + + TP_ARGS(cpu, latency, sleep_us, wake_up) +); + +DEFINE_EVENT(msm_pm_enter, msm_pm_enter_wfi, + + TP_PROTO(unsigned int cpu, uint32_t latency, + uint32_t sleep_us, uint32_t wake_up), + + TP_ARGS(cpu, latency, sleep_us, wake_up) +); + +DECLARE_EVENT_CLASS(msm_pm_exit, + + TP_PROTO(unsigned int cpu, bool success), + + TP_ARGS(cpu, success), + + TP_STRUCT__entry( + __field(unsigned int , cpu) + __field(int, success) + ), + + TP_fast_assign( + __entry->cpu = cpu; + __entry->success = success; + ), + + TP_printk("cpu:%u success:%d", + __entry->cpu, + __entry->success) +); + +DEFINE_EVENT(msm_pm_exit, msm_pm_exit_pc, + + TP_PROTO(unsigned int cpu, bool success), + + TP_ARGS(cpu, success) +); + +DEFINE_EVENT(msm_pm_exit, msm_pm_exit_ret, + + TP_PROTO(unsigned int cpu, bool success), + + TP_ARGS(cpu, success) +); + +DEFINE_EVENT(msm_pm_exit, msm_pm_exit_spc, + + TP_PROTO(unsigned int cpu, bool success), + + TP_ARGS(cpu, success) +); + +DEFINE_EVENT(msm_pm_exit, msm_pm_exit_wfi, + + TP_PROTO(unsigned int cpu, bool success), + + TP_ARGS(cpu, success) +); + +TRACE_EVENT(lpm_resources, + + TP_PROTO(uint32_t sleep_value , char *name), + + TP_ARGS(sleep_value, name), + + TP_STRUCT__entry( + __field(uint32_t , sleep_value) + __string(name, name) + ), + + TP_fast_assign( + __entry->sleep_value = sleep_value; + __assign_str(name, name); + ), + + TP_printk("name:%s sleep_value:%d", + __get_str(name), + __entry->sleep_value) +); +#endif +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace_msm_low_power +#include diff --git a/init/main.c b/init/main.c index 737ab05f4ad..38ed1cd0429 100644 --- a/init/main.c +++ b/init/main.c @@ -107,6 +107,9 @@ bool early_boot_irqs_disabled __read_mostly; enum system_states system_state __read_mostly; EXPORT_SYMBOL(system_state); +#ifdef CONFIG_SAMSUNG_LPM_MODE +int poweroff_charging; +#endif /* CONFIG_SAMSUNG_LPM_MODE */ /* * Boot command-line arguments */ @@ -402,6 +405,15 @@ static int __init do_early_param(char *param, char *val) } } /* We accept everything at this stage. */ + +#ifdef CONFIG_SAMSUNG_LPM_MODE + /* check power off charging */ + if ((strncmp(param, "androidboot.bootchg", 19) == 0)) { + if (strncmp(val, "true", 4) == 0) + poweroff_charging = 1; + } +#endif + return 0; } @@ -491,6 +503,7 @@ asmlinkage void __init start_kernel(void) * Interrupts are still disabled. Do necessary setups, then * enable them */ + tick_init(); boot_cpu_init(); page_address_init(); diff --git a/kernel/kexec.c b/kernel/kexec.c index 4e2e472f6ae..aef789344c2 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -1004,6 +1004,10 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, if (flags & KEXEC_PRESERVE_CONTEXT) image->preserve_context = 1; +#ifdef CONFIG_KEXEC_HARDBOOT + if (flags & KEXEC_HARDBOOT) + image->hardboot = 1; +#endif result = machine_kexec_prepare(image); if (result) goto out; diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c index 2583856fab3..b42fd5db5c3 100644 --- a/kernel/power/wakelock.c +++ b/kernel/power/wakelock.c @@ -31,7 +31,7 @@ enum { DEBUG_EXPIRE = 1U << 3, DEBUG_WAKE_LOCK = 1U << 4, }; -static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP; +static int debug_mask = DEBUG_SUSPEND | DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP; module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); #define WAKE_LOCK_TYPE_MASK (0x0f) diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py index 27e76a74f9d..4941f2c1067 100755 --- a/scripts/gcc-wrapper.py +++ b/scripts/gcc-wrapper.py @@ -43,6 +43,11 @@ "alignment.c:327", "mmu.c:602", "return_address.c:62", + "mdp4_video_enhance.c:164", + "extents.c:2091", + "msm_sdcc.c:5402", + "msm_sdcc.c:5402", + "msm_sdcc.c:5439", ]) # Capture the name of the object file, can find it. diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c index cb403711c64..5d5a76277fc 100644 --- a/sound/soc/codecs/wcd9310.c +++ b/sound/soc/codecs/wcd9310.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -365,6 +366,16 @@ struct tabla_priv { #endif }; +/*Add headset detect,sendend key sysfs for Samsung factorytest*/ +struct switch_dev switch_jack_detection = { + .name = "h2w", /* /sys/class/switch/h2w/state */ +}; + +/* To support samsung factory test */ +struct switch_dev switch_sendend = { + .name = "send_end", /* /sys/class/switch/send_end/state */ +}; + static const u32 comp_shift[] = { 0, 1, @@ -1990,6 +2001,24 @@ static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable) } } +static int tabla_codec_enable_ear_rx_bias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + pr_debug("%s %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tabla_enable_rx_bias(codec, 1); + break; + case SND_SOC_DAPM_POST_PMD: + msleep(40); + tabla_enable_rx_bias(codec, 0); + break; + } + return 0; +} + static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec, int enable) { @@ -3476,7 +3505,8 @@ static const struct snd_soc_dapm_route audio_map[] = { {"RX1 MIX2", NULL, "ANC1 MUX"}, {"RX2 MIX2", NULL, "ANC2 MUX"}, - {"CP", NULL, "RX_BIAS"}, + {"CP", NULL, "EAR_RX_BIAS"}, +// {"CP", NULL, "RX_BIAS"}, {"LINEOUT1 DAC", NULL, "RX_BIAS"}, {"LINEOUT2 DAC", NULL, "RX_BIAS"}, {"LINEOUT3 DAC", NULL, "RX_BIAS"}, @@ -3780,6 +3810,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"MIC BIAS3 Internal2", NULL, "LDO_H"}, {"MIC BIAS3 External", NULL, "LDO_H"}, {"MIC BIAS4 External", NULL, "LDO_H"}, + {"Main Mic Bias", NULL, "LDO_H"}, }; static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = { @@ -4508,7 +4539,7 @@ static int tabla_hw_params(struct snd_pcm_substream *substream, u32 compander_fs; int ret; - pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + pr_info("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, dai->name, dai->id, params_rate(params), params_channels(params)); @@ -5128,6 +5159,10 @@ static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = { tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("EAR_RX_BIAS", SND_SOC_NOPM, 0, 0, + tabla_codec_enable_ear_rx_bias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + /* TX */ SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL, @@ -5147,6 +5182,9 @@ static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = { SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0, tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("Main Mic Bias", 0, 0, 0, + 0, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0, tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), @@ -8372,7 +8410,7 @@ static int tabla_codec_probe(struct snd_soc_codec *codec) codec->control_data = dev_get_drvdata(codec->dev->parent); control = codec->control_data; - + pr_info("%s", __func__); tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL); if (!tabla) { dev_err(codec->dev, "Failed to allocate private data\n"); @@ -8705,7 +8743,7 @@ static const struct dev_pm_ops tabla_pm_ops = { static int __devinit tabla_probe(struct platform_device *pdev) { int ret = 0; - pr_err("tabla_probe\n"); + pr_info("tabla_probe\n"); if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla, tabla_dai, ARRAY_SIZE(tabla_dai)); diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile index 99302eb55d4..af4ca8915aa 100644 --- a/sound/soc/msm/Makefile +++ b/sound/soc/msm/Makefile @@ -62,7 +62,41 @@ obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o -snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o mpq8064.o apq8064-i2s.o +ifdef CONFIG_MACH_M2_ATT +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_M2_SKT +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_M2_SPR +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_M2_VZW +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_M2_DCM +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_K2_KDI +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_GOGH +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_INFINITE +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_JASPER +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_AEGIS2 +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_COMANCHE +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_EXPRESS +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_STRETTO +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_APEXQ +snd-soc-msm8960-objs := msm8960-jaguar.o +else ifdef CONFIG_MACH_SUPERIORLTE_SKT +snd-soc-msm8960-objs := msm8960-d2.o +else ifdef CONFIG_MACH_JAGUAR +snd-soc-msm8960-objs := msm8960-jaguar.o +else +snd-soc-msm8960-objs := msm8960-jaguar.o +endif obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o # Generic MSM drivers diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c index 81f8e026f95..aa397374b92 100644 --- a/sound/soc/msm/msm-pcm-routing.c +++ b/sound/soc/msm/msm-pcm-routing.c @@ -424,7 +424,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set) int session_type, path_type; u32 channels; - pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set); + pr_info("%s: reg %x val %x set %x\n", __func__, reg, val, set); if (val > MSM_FRONTEND_DAI_MM_MAX_ID) { /* recheck FE ID in the mixer control defined in this file */ @@ -2664,6 +2664,7 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream) u32 channels; bool playback, capture; + pr_info("%s: be_id = %x", __func__, be_id); if (be_id >= MSM_BACKEND_DAI_MAX) { pr_err("%s: unexpected be_id %d\n", __func__, be_id); return -EINVAL; diff --git a/sound/soc/msm/msm8960-d2.c b/sound/soc/msm/msm8960-d2.c new file mode 100644 index 00000000000..5617508753f --- /dev/null +++ b/sound/soc/msm/msm8960-d2.c @@ -0,0 +1,2339 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm-pcm-routing.h" +#include "../codecs/wcd9310.h" +#include +#include + +#ifndef GPIO_MAIN_MIC_BIAS +#define GPIO_MAIN_MIC_BIAS -1 +#endif + +/* 8960 machine driver */ + +#define PM8921_GPIO_BASE NR_GPIO_IRQS +#define PM8921_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS) +#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE) + +#define MSM8960_SPK_ON 1 +#define MSM8960_SPK_OFF 0 + +#define msm8960_SLIM_0_RX_MAX_CHANNELS 2 +#define msm8960_SLIM_0_TX_MAX_CHANNELS 4 + +#define BTSCO_RATE_8KHZ 8000 +#define BTSCO_RATE_16KHZ 16000 + +#define BOTTOM_SPK_AMP_POS 0x1 +#define BOTTOM_SPK_AMP_NEG 0x2 +#define TOP_SPK_AMP_POS 0x4 +#define TOP_SPK_AMP_NEG 0x8 + +#define GPIO_AUX_PCM_DOUT 63 +#define GPIO_AUX_PCM_DIN 64 +#define GPIO_AUX_PCM_SYNC 65 +#define GPIO_AUX_PCM_CLK 66 +#define GPIO_SPKR_I2S_MCLK 59 +#define GPIO_SPKR_I2S_RX_SCK 60 +#define GPIO_SPKR_I2S_RX_DOUT 61 +#define GPIO_SPKR_I2S_RX_WS 62 + +#define GPIO_SPKR_I2S_TX_SCK 55 +#define GPIO_SPKR_I2S_TX_WS 56 +#define GPIO_SPKR_I2S_TX_D0 57 +#define NO_OF_BITS_PER_SAMPLE 16 + +#define I2S_MCLK_RATE 12288000 +#define I2S_MIC_MCLK_RATE 1536000 + +#define TABLA_EXT_CLK_RATE 12288000 + +#define TABLA_MBHC_DEF_BUTTONS 3 +#define TABLA_MBHC_DEF_RLOADS 5 + +#define NUM_EXT_SPK_AMP_STATES 2 + +#define JACK_DETECT_GPIO 38 +#define JACK_DETECT_INT PM8921_GPIO_IRQ(PM8921_IRQ_BASE, JACK_DETECT_GPIO) +#define GPIO_DETECT_USED false + +extern int system_rev; +static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_SPK_EN); +static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_VPS_EN); +static int msm8960_spk_control; +static int msm8960_ext_bottom_spk_pamp; +static int msm8960_ext_top_spk_pamp; +static int msm8960_slim_0_rx_ch = 1; +static int msm8960_slim_0_tx_ch = 1; + +static int msm8960_btsco_rate = BTSCO_RATE_8KHZ; +static int msm8960_btsco_ch = 1; + +static struct clk *codec_clk; +static int clk_users; + +static int msm8960_audio_gpios_configured; + +static struct snd_soc_jack hs_jack; +static struct snd_soc_jack button_jack; +static struct snd_soc_jack volumedown_jack; +static struct snd_soc_jack volumeup_jack; + +static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable, + bool dapm); + +static struct tabla_mbhc_config mbhc_cfg = { + .headset_jack = &hs_jack, + .button_jack = &button_jack, + .read_fw_bin = false, + .calibration = NULL, + .micbias = TABLA_MICBIAS2, + .mclk_cb_fn = msm8960_enable_codec_ext_clk, + .mclk_rate = TABLA_EXT_CLK_RATE, + .gpio = 0, + .gpio_irq = 0, + .gpio_level_insert = 1, +}; + + +static int msm8960_i2s_rx_ch = 1; +static int msm8960_i2s_tx_ch = 1; +static int msm8960_i2s_spk_control; +/* static struct clk *rx_osr_clk; */ +static struct clk *rx_bit_clk; +static struct clk *tx_osr_clk; +static struct clk *tx_bit_clk; + +struct ext_amp_work { + struct delayed_work dwork; +}; + +static struct ext_amp_work ext_amp_dwork; + +/* Work queue for delaying the amp power on-off to +remove the static noise during SPK_PA enable */ +static void external_speaker_amp_work(struct work_struct *work) +{ + pr_info("%s :: Top Speaker Amp enable\n", __func__); + gpio_direction_output(top_spk_pamp_gpio, 1); + pr_info("%s: slepping 4 ms after turning on external " + " Top Speaker Ampl\n", __func__); + usleep_range(4000, 4000); +} + +static void msm8960_ext_spk_power_amp_on(u32 spk) +{ + if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) { + + if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) && + (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) { + + pr_info("%s() External Bottom Speaker Ampl already " + "turned on. spk = 0x%08x\n", __func__, spk); + return; + } + + msm8960_ext_bottom_spk_pamp |= spk; + + if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) && + (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) { + + pr_info("%s Enabling Bottom Speaker\n", __func__); + gpio_direction_output(bottom_spk_pamp_gpio, 1); + pr_info("%s: slepping 4 ms after turning on external " + " Bottom Speaker Ampl\n", __func__); + usleep_range(4000, 4000); + } + + } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) { + + if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) && + (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) { + + pr_info("%s() External Top Speaker Ampl already" + "turned on. spk = 0x%08x\n", __func__, spk); + return; + } + + msm8960_ext_top_spk_pamp |= spk; + + if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) && + (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) { + /* Delaying the amp power_on to remove the static noise + during SPK_PA enable */ + schedule_delayed_work( + &ext_amp_dwork.dwork, + msecs_to_jiffies(30)); + } + } else { + + pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n", + __func__, spk); + return; + } +} + +static void msm8960_ext_spk_power_amp_off(u32 spk) +{ + if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) { + + if (!msm8960_ext_bottom_spk_pamp) + return; + + pr_info("%s Disabling Bottom Speaker\n", __func__); + gpio_direction_output(bottom_spk_pamp_gpio, 0); + msm8960_ext_bottom_spk_pamp = 0; + + pr_info("%s: sleeping 4 ms after turning off external Bottom" + " Speaker Ampl\n", __func__); + + usleep_range(4000, 4000); + + } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) { + + if (!msm8960_ext_top_spk_pamp) + return; + gpio_direction_output(top_spk_pamp_gpio, 0); + pr_info("%s: slepping 4 ms after turning off external " + " Top Speaker Ampl\n", __func__); + msm8960_ext_top_spk_pamp = 0; + } else { + + pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n", + __func__, spk); + return; + } +} + +static void msm8960_ext_control(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = &codec->dapm; + mutex_lock(&dapm->codec->mutex); + + pr_info("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control); + if (msm8960_spk_control == MSM8960_SPK_ON || + msm8960_i2s_spk_control == MSM8960_SPK_ON) { + snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg"); + } else { + snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos"); + snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg"); + snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos"); + snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg"); + } + + snd_soc_dapm_sync(dapm); + mutex_unlock(&dapm->codec->mutex); +} + +static int msm8960_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control); + ucontrol->value.integer.value[0] = msm8960_spk_control; + return 0; +} +static int msm8960_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + pr_info("%s()\n", __func__); + if (msm8960_spk_control == ucontrol->value.integer.value[0]) + return 0; + + msm8960_spk_control = ucontrol->value.integer.value[0]; + msm8960_ext_control(codec); + return 1; +} +static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + pr_info("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event)); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (!strncmp(w->name, "Ext Spk Bottom Pos", 18)) + msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS); + else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18)) + msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG); + else if (!strncmp(w->name, "Ext Spk Top Pos", 15)) + msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_POS); + else if (!strncmp(w->name, "Ext Spk Top Neg", 15)) + msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_NEG); + else { + pr_err("%s() Invalid Speaker Widget = %s\n", + __func__, w->name); + return -EINVAL; + } + + } else { + if (!strncmp(w->name, "Ext Spk Bottom Pos", 18)) + msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS); + else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18)) + msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG); + else if (!strncmp(w->name, "Ext Spk Top Pos", 15)) + msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_POS); + else if (!strncmp(w->name, "Ext Spk Top Neg", 15)) + msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_NEG); + else { + pr_err("%s() Invalid Speaker Widget = %s\n", + __func__, w->name); + return -EINVAL; + } + } + return 0; +} + +static int msm8960_bias_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + pr_info("GPIO BIAS UP!!!%d\n", SND_SOC_DAPM_EVENT_ON(event)); +#if defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) + if (system_rev == BOARD_REV00) + gpio_direction_output(GPIO_MAIN_MIC_BIAS_REV00, + SND_SOC_DAPM_EVENT_ON(event)); + else if (system_rev == BOARD_REV01) + gpio_direction_output(GPIO_MAIN_MIC_BIAS_REV01, + SND_SOC_DAPM_EVENT_ON(event)); + else if (system_rev >= BOARD_REV02) + gpio_direction_output(GPIO_MAIN_MIC_BIAS_REV02, + SND_SOC_DAPM_EVENT_ON(event)); +#else + /* temporary code for old HW revision of JASPER */ + if (machine_is_JASPER() && system_rev < BOARD_REV04) { + gpio_direction_output(18, SND_SOC_DAPM_EVENT_ON(event)); + } else { + gpio_direction_output(GPIO_MAIN_MIC_BIAS, + SND_SOC_DAPM_EVENT_ON(event)); + } +#endif + return 0; +} + +/* Not used */ +/* +static int msm8960_cdc_cp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + pr_info("%s %d\n", __func__, SND_SOC_DAPM_EVENT_ON(event)); + gpio_direction_output(PM8921_GPIO_PM_TO_SYS(17), + SND_SOC_DAPM_EVENT_ON(event)); + return 0; +} +*/ + +static int msm8960_cdc_vps_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + pr_info("%s %d\n", __func__, SND_SOC_DAPM_EVENT_ON(event)); + gpio_direction_output(PM8921_GPIO_PM_TO_SYS(5), + SND_SOC_DAPM_EVENT_ON(event)); + return 0; +} + +static struct mutex cdc_mclk_mutex; + +static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable, + bool dapm) +{ + int r = 0; + pr_info("%s: enable = %d\n", __func__, enable); + + mutex_lock(&cdc_mclk_mutex); + if (enable) { + clk_users++; + pr_info("%s: clk_users = %d\n", __func__, clk_users); + if (clk_users == 1) { + codec_clk = clk_get(NULL, "i2s_spkr_osr_clk"); + if (codec_clk) { + clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE); + clk_enable(codec_clk); + tabla_mclk_enable(codec, 1, dapm); + } else { + pr_err("%s: Error setting Tabla MCLK\n", __func__); + clk_users--; + r = -EINVAL; + } + } + } else { + if (clk_users > 0) { + clk_users--; + pr_info("%s: clk_users = %d\n", __func__, clk_users); + if (clk_users == 0) { + pr_info("%s: disabling MCLK. clk_users = %d\n", + __func__, clk_users); + tabla_mclk_enable(codec, 0, dapm); + clk_disable(codec_clk); + clk_put(codec_clk); + } + } else { + pr_err("%s: Error releasing Tabla MCLK\n", __func__); + r = -EINVAL; + } + } + mutex_unlock(&cdc_mclk_mutex); + return r; +} + +static int msm8960_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + pr_info("%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return msm8960_enable_codec_ext_clk(w->codec, 1, true); + case SND_SOC_DAPM_POST_PMD: + return msm8960_enable_codec_ext_clk(w->codec, 0, true); + } + return 0; +} +static const struct snd_soc_dapm_widget msm8960_dapm_widgets_org[] = { + + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, + msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event), + SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event), + + SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event), + SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event), + + SND_SOC_DAPM_MIC("Handset Mic", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Sub Mic", NULL), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL), + SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("Digital Mic2", NULL), + SND_SOC_DAPM_MIC("Digital Mic3", NULL), + SND_SOC_DAPM_MIC("Digital Mic4", NULL), + SND_SOC_DAPM_MIC("Digital Mic5", NULL), + SND_SOC_DAPM_MIC("Digital Mic6", NULL), + +}; + +static const struct snd_soc_dapm_route common_audio_map_org[] = { + + {"EAR_RX_BIAS", NULL, "MCLK"}, + {"RX_BIAS", NULL, "MCLK"}, + {"LDO_H", NULL, "MCLK"}, + + /* Speaker path */ + {"Ext Spk Bottom Pos", NULL, "LINEOUT1"}, + {"Ext Spk Bottom Neg", NULL, "LINEOUT5"}, + + {"Ext Spk Top Pos", NULL, "LINEOUT3"}, + {"Ext Spk Top Neg", NULL, "LINEOUT4"}, + + /* Microphone path */ + /** + *Samsung uses AMIC4 for Handset sub Mic + *AMIC4 uses external MIC BIAS1 + */ + {"AMIC3", NULL, "MIC BIAS1 External"}, + {"MIC BIAS1 External", NULL, "Handset Mic"}, + + {"AMIC2", NULL, "MIC BIAS2 External"}, + {"MIC BIAS2 External", NULL, "Headset Mic"}, + + {"AMIC4", NULL, "MIC BIAS3 External"}, + {"MIC BIAS3 External", NULL, "Sub Mic"}, + + /** + * AMIC3 and AMIC4 inputs are connected to ANC microphones + * These mics are biased differently on CDP and FLUID + * routing entries below are based on bias arrangement + * on FLUID. + */ + { "AMIC3", NULL, "MIC BIAS1 External" }, + + {"HEADPHONE", NULL, "LDO_H"}, + + /** + * The digital Mic routes are setup considering + * fluid as default device. + */ + + /** + * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP. + * Digital Mic GM5 on CDP mainboard. + * Conncted to DMIC2 Input on Tabla codec. + */ + {"DMIC2", NULL, "MIC BIAS1 External"}, + {"MIC BIAS1 External", NULL, "Digital Mic1"}, + + /** + * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP. + * Digital Mic GM6 on CDP mainboard. + * Conncted to DMIC1 Input on Tabla codec. + */ + {"DMIC1", NULL, "MIC BIAS1 External"}, + {"MIC BIAS1 External", NULL, "Digital Mic2"}, + + /** + * Digital Mic3. Back Bottom Digital Mic on Fluid. + * Digital Mic GM1 on CDP mainboard. + * Conncted to DMIC4 Input on Tabla codec. + */ + {"DMIC4", NULL, "MIC BIAS3 External"}, + {"MIC BIAS3 External", NULL, "Digital Mic3"}, + + /** + * Digital Mic4. Back top Digital Mic on Fluid. + * Digital Mic GM2 on CDP mainboard. + * Conncted to DMIC3 Input on Tabla codec. + */ + {"DMIC3", NULL, "MIC BIAS3 External"}, + {"MIC BIAS3 External", NULL, "Digital Mic4"}, + + /** + * Digital Mic5. Front top Digital Mic on Fluid. + * Digital Mic GM3 on CDP mainboard. + * Conncted to DMIC5 Input on Tabla codec. + */ + {"DMIC5", NULL, "MIC BIAS4 External"}, + {"MIC BIAS4 External", NULL, "Digital Mic5"}, + + /* Tabla digital Mic6 - back bottom digital Mic on Liquid and + * bottom mic on CDP. FLUID/MTP do not have dmic6 installed. + */ + {"DMIC6", NULL, "MIC BIAS4 External"}, + {"MIC BIAS4 External", NULL, "Digital Mic6"}, +}; + +static const struct snd_soc_dapm_route comanche_audio_map_org[] = { + {"Ext Spk Top Pos", NULL, "LINEOUT2"} +}; + +static const struct snd_soc_dapm_route express_audio_map_org[] = { + {"Ext Spk Top Pos", NULL, "LINEOUT2"} +}; + +/* Main Main LDO is added */ +static const struct snd_soc_dapm_widget msm8960_dapm_widgets_rev00[] = { + + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, + msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event), + SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event), + + SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event), + SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event), + + SND_SOC_DAPM_MIC("Sub Mic", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL), + SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL), + SND_SOC_DAPM_MIC("Main Mic", msm8960_bias_event), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("Digital Mic2", NULL), + SND_SOC_DAPM_MIC("Digital Mic3", NULL), + SND_SOC_DAPM_MIC("Digital Mic4", NULL), + SND_SOC_DAPM_MIC("Digital Mic5", NULL), + SND_SOC_DAPM_MIC("Digital Mic6", NULL), + +}; + +static const struct snd_soc_dapm_route common_audio_map_rev00[] = { + + {"EAR_RX_BIAS", NULL, "MCLK"}, + {"RX_BIAS", NULL, "MCLK"}, + {"LDO_H", NULL, "MCLK"}, + + /* Speaker path */ + {"Ext Spk Bottom Pos", NULL, "LINEOUT1"}, + {"Ext Spk Bottom Neg", NULL, "LINEOUT5"}, + + {"Ext Spk Top Pos", NULL, "LINEOUT3"}, + {"Ext Spk Top Neg", NULL, "LINEOUT4"}, + + /* Microphone path */ + /** + *Samsung uses AMIC4 for Handset sub Mic + *AMIC4 uses external MIC BIAS1 + */ + {"AMIC4", NULL, "MIC BIAS1 External"}, + {"MIC BIAS1 External", NULL, "Sub Mic"}, + + {"AMIC2", NULL, "MIC BIAS2 External"}, + {"MIC BIAS2 External", NULL, "Headset Mic"}, + + /** + * AMIC3 and AMIC4 inputs are connected to ANC microphones + * These mics are biased differently on CDP and FLUID + * routing entries below are based on bias arrangement + * on FLUID. + */ + {"AMIC3", NULL, "Main Mic Bias"}, + {"Main Mic Bias", NULL, "Main Mic"}, + + {"HEADPHONE", NULL, "LDO_H"}, + + /** + * The digital Mic routes are setup considering + * fluid as default device. + */ + + /** + * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP. + * Digital Mic GM5 on CDP mainboard. + * Conncted to DMIC2 Input on Tabla codec. + */ + {"DMIC2", NULL, "MIC BIAS1 External"}, + {"MIC BIAS1 External", NULL, "Digital Mic1"}, + + /** + * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP. + * Digital Mic GM6 on CDP mainboard. + * Conncted to DMIC1 Input on Tabla codec. + */ + {"DMIC1", NULL, "MIC BIAS1 External"}, + {"MIC BIAS1 External", NULL, "Digital Mic2"}, + + /** + * Digital Mic3. Back Bottom Digital Mic on Fluid. + * Digital Mic GM1 on CDP mainboard. + * Conncted to DMIC4 Input on Tabla codec. + */ + {"DMIC4", NULL, "MIC BIAS3 External"}, + {"MIC BIAS3 External", NULL, "Digital Mic3"}, + + /** + * Digital Mic4. Back top Digital Mic on Fluid. + * Digital Mic GM2 on CDP mainboard. + * Conncted to DMIC3 Input on Tabla codec. + */ + {"DMIC3", NULL, "MIC BIAS3 External"}, + {"MIC BIAS3 External", NULL, "Digital Mic4"}, + + /** + * Digital Mic5. Front top Digital Mic on Fluid. + * Digital Mic GM3 on CDP mainboard. + * Conncted to DMIC5 Input on Tabla codec. + */ + {"DMIC5", NULL, "MIC BIAS4 External"}, + {"MIC BIAS4 External", NULL, "Digital Mic5"}, + + /* Tabla digital Mic6 - back bottom digital Mic on Liquid and + * bottom mic on CDP. FLUID/MTP do not have dmic6 installed. + */ + {"DMIC6", NULL, "MIC BIAS4 External"}, + {"MIC BIAS4 External", NULL, "Digital Mic6"}, +}; + + +/* VDD_CDC_RXTX , Third mic is added */ +static const struct snd_soc_dapm_widget msm8960_dapm_widgets_rev01[] = { + + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, + msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("VREG_CDC_RXTX", SND_SOC_NOPM, 0, 0, + msm8960_cdc_vps_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event), + SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event), + + SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event), + SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event), + + SND_SOC_DAPM_MIC("Sub Mic", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Third Mic", NULL), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL), + SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL), + SND_SOC_DAPM_MIC("Main Mic", msm8960_bias_event), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("Digital Mic2", NULL), + SND_SOC_DAPM_MIC("Digital Mic3", NULL), + SND_SOC_DAPM_MIC("Digital Mic4", NULL), + SND_SOC_DAPM_MIC("Digital Mic5", NULL), + SND_SOC_DAPM_MIC("Digital Mic6", NULL), + +}; + +static const struct snd_soc_dapm_route common_audio_map_rev01[] = { + + {"EAR_RX_BIAS", NULL, "MCLK"}, + {"RX_BIAS", NULL, "MCLK"}, + {"LDO_H", NULL, "MCLK"}, + + /* Speaker path */ + {"Ext Spk Bottom Pos", NULL, "LINEOUT1"}, + {"Ext Spk Bottom Neg", NULL, "LINEOUT5"}, + + {"Ext Spk Top Pos", NULL, "LINEOUT2"}, + {"Ext Spk Top Neg", NULL, "LINEOUT4"}, + + /* Microphone path */ + /** + *Samsung uses AMIC4 for Handset sub Mic + *AMIC4 uses external MIC BIAS1 + */ + {"AMIC4", NULL, "MIC BIAS1 External"}, + {"MIC BIAS1 External", NULL, "Sub Mic"}, + + {"AMIC5", NULL, "MIC BIAS3 External"}, + {"MIC BIAS3 External", NULL, "Third Mic"}, + + {"AMIC2", NULL, "MIC BIAS2 External"}, + {"MIC BIAS2 External", NULL, "Headset Mic"}, + + /** + * AMIC3 and AMIC4 inputs are connected to ANC microphones + * These mics are biased differently on CDP and FLUID + * routing entries below are based on bias arrangement + * on FLUID. + */ + {"AMIC3", NULL, "Main Mic Bias"}, + {"Main Mic Bias", NULL, "Main Mic"}, + + {"HEADPHONE", NULL, "LDO_H"}, + + /** + * The digital Mic routes are setup considering + * fluid as default device. + */ + + /** + * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP. + * Digital Mic GM5 on CDP mainboard. + * Conncted to DMIC2 Input on Tabla codec. + */ + {"DMIC2", NULL, "MIC BIAS1 External"}, + {"MIC BIAS1 External", NULL, "Digital Mic1"}, + + /** + * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP. + * Digital Mic GM6 on CDP mainboard. + * Conncted to DMIC1 Input on Tabla codec. + */ + {"DMIC1", NULL, "MIC BIAS1 External"}, + {"MIC BIAS1 External", NULL, "Digital Mic2"}, + + /** + * Digital Mic3. Back Bottom Digital Mic on Fluid. + * Digital Mic GM1 on CDP mainboard. + * Conncted to DMIC4 Input on Tabla codec. + */ + {"DMIC4", NULL, "MIC BIAS3 External"}, + {"MIC BIAS3 External", NULL, "Digital Mic3"}, + + /** + * Digital Mic4. Back top Digital Mic on Fluid. + * Digital Mic GM2 on CDP mainboard. + * Conncted to DMIC3 Input on Tabla codec. + */ + {"DMIC3", NULL, "MIC BIAS3 External"}, + {"MIC BIAS3 External", NULL, "Digital Mic4"}, + + /** + * Digital Mic5. Front top Digital Mic on Fluid. + * Digital Mic GM3 on CDP mainboard. + * Conncted to DMIC5 Input on Tabla codec. + */ + {"DMIC5", NULL, "MIC BIAS4 External"}, + {"MIC BIAS4 External", NULL, "Digital Mic5"}, + + /* Tabla digital Mic6 - back bottom digital Mic on Liquid and + * bottom mic on CDP. FLUID/MTP do not have dmic6 installed. + */ + {"DMIC6", NULL, "MIC BIAS4 External"}, + {"MIC BIAS4 External", NULL, "Digital Mic6"}, +}; + + +static const char *spk_function[] = {"Off", "On"}; +static const char *slim0_rx_ch_text[] = {"One", "Two"}; +static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"}; + +static const struct soc_enum msm8960_enum[] = { + SOC_ENUM_SINGLE_EXT(2, spk_function), + SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text), + SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text), +}; + +static const char *btsco_rate_text[] = {"8000", "16000"}; +static const struct soc_enum msm8960_btsco_enum[] = { + SOC_ENUM_SINGLE_EXT(2, btsco_rate_text), +}; + +static int msm8960_i2s_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: msm8960_i2s_rx_ch = %d\n", __func__, + msm8960_i2s_rx_ch); + ucontrol->value.integer.value[0] = msm8960_i2s_rx_ch - 1; + return 0; +} + +static int msm8960_i2s_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm8960_i2s_rx_ch = ucontrol->value.integer.value[0] + 1; + + pr_info("%s: msm8960_i2s_rx_ch = %d\n", __func__, + msm8960_i2s_rx_ch); + return 1; +} + +static int msm8960_i2s_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: msm8960_i2s_tx_ch = %d\n", __func__, + msm8960_i2s_tx_ch); + ucontrol->value.integer.value[0] = msm8960_i2s_tx_ch - 1; + return 0; +} + +static int msm8960_i2s_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm8960_i2s_tx_ch = ucontrol->value.integer.value[0] + 1; + + pr_info("%s: msm8960_i2s_tx_ch = %d\n", __func__, + msm8960_i2s_tx_ch); + return 1; +} + +static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: msm8960_slim_0_rx_ch = %d\n", __func__, + msm8960_slim_0_rx_ch); + ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1; + return 0; +} + +static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1; + + pr_info("%s: msm8960_slim_0_rx_ch = %d\n", __func__, + msm8960_slim_0_rx_ch); + return 1; +} + +static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: msm8960_slim_0_tx_ch = %d\n", __func__, + msm8960_slim_0_tx_ch); + ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1; + return 0; +} + +static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1; + + pr_info("%s: msm8960_slim_0_tx_ch = %d\n", __func__, + msm8960_slim_0_tx_ch); + return 1; +} + +static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: msm8960_btsco_rate = %d", __func__, + msm8960_btsco_rate); + ucontrol->value.integer.value[0] = msm8960_btsco_rate; + return 0; +} + +static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm8960_btsco_rate = BTSCO_RATE_8KHZ; + break; + case 1: + msm8960_btsco_rate = BTSCO_RATE_16KHZ; + break; + default: + msm8960_btsco_rate = BTSCO_RATE_8KHZ; + break; + } + pr_info("%s: msm8960_btsco_rate = %d\n", __func__, + msm8960_btsco_rate); + return 0; +} + +static int msm8960_i2s_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + pr_info("%s()\n", __func__); + if (msm8960_i2s_spk_control == ucontrol->value.integer.value[0]) + return 0; + + msm8960_i2s_spk_control = ucontrol->value.integer.value[0]; + msm8960_ext_control(codec); + return 1; +} + +static int msm8960_i2s_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control); + ucontrol->value.integer.value[0] = msm8960_i2s_spk_control; + return 0; +} + +static const struct snd_kcontrol_new tabla_msm8960_i2s_controls[] = { + SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_i2s_get_spk, + msm8960_i2s_set_spk), + SOC_ENUM_EXT("PRI_RX Channels", msm8960_enum[1], + msm8960_i2s_rx_ch_get, msm8960_i2s_rx_ch_put), + SOC_ENUM_EXT("PRI_TX Channels", msm8960_enum[2], + msm8960_i2s_tx_ch_get, msm8960_i2s_tx_ch_put), +}; + +static const struct snd_kcontrol_new tabla_msm8960_controls[] = { + SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk, + msm8960_set_spk), + SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1], + msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put), + SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2], + msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put), +}; + + +static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = { + SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0], + msm8960_btsco_rate_get, msm8960_btsco_rate_put), +}; +static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd) +{ + int err = 0; + struct snd_soc_platform *platform = rtd->platform; + + err = snd_soc_add_platform_controls(platform, + int_btsco_rate_mixer_controls, + ARRAY_SIZE(int_btsco_rate_mixer_controls)); + if (err < 0) + return err; + return 0; +} + +static void *def_tabla_mbhc_cal(void) +{ + void *tabla_cal; + struct tabla_mbhc_btn_detect_cfg *btn_cfg; + u16 *btn_low, *btn_high; + u8 *n_ready, *n_cic, *gain; + + tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS, + TABLA_MBHC_DEF_RLOADS), + GFP_KERNEL); + if (!tabla_cal) { + pr_err("%s: out of memory\n", __func__); + return NULL; + } + +#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y)) + S(t_ldoh, 100); + S(t_bg_fast_settle, 100); + S(t_shutdown_plug_rem, 255); + S(mbhc_nsa, 4); + S(mbhc_navg, 4); +#undef S +#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y)) + S(mic_current, TABLA_PID_MIC_5_UA); + S(hph_current, TABLA_PID_MIC_5_UA); + S(t_mic_pid, 100); + S(t_ins_complete, 250); + S(t_ins_retry, 200); +#undef S +#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y)) + S(v_no_mic, 590); + S(v_hs_max, 1650); +#undef S +#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y)) + S(c[0], 62); + S(c[1], 124); + S(nc, 1); + S(n_meas, 3); + S(mbhc_nsc, 11); + S(n_btn_meas, 4); + S(n_btn_con, 5); + S(num_btn, TABLA_MBHC_DEF_BUTTONS); + S(v_btn_press_delta_sta, 100); + S(v_btn_press_delta_cic, 50); +#undef S + btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal); + btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW); + btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH); + if (machine_is_M2_VZW() && system_rev >= BOARD_REV10) { + btn_low[0] = -105; + btn_high[0] = 65; + btn_low[1] = 66; + btn_high[1] = 260; + btn_low[2] = 261; + btn_high[2] = 500; + } else { + btn_low[0] = -100; + btn_high[0] = 75; + btn_low[1] = 76; + btn_high[1] = 200; + btn_low[2] = 201; + btn_high[2] = 500; + } + n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY); + n_ready[0] = 48; + n_ready[1] = 38; + n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC); + n_cic[0] = 60; + n_cic[1] = 47; + gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN); + gain[0] = 11; + gain[1] = 9; + + return tabla_cal; +} + +static int msm8960_i2s_audrx_init(struct snd_soc_pcm_runtime *rtd) +{ + int err; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + + pr_info("%s()\n", __func__); + err = snd_soc_add_codec_controls(codec, tabla_msm8960_i2s_controls, + ARRAY_SIZE(tabla_msm8960_i2s_controls)); + if (err < 0) { + pr_err("returning loc 1 err = %d\n", err); + return err; + } + rtd->pmdown_time = 0; + + if (machine_is_COMANCHE() || machine_is_EXPRESS() || + (machine_is_JASPER() && system_rev < BOARD_REV02)) + snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets_org, + ARRAY_SIZE(msm8960_dapm_widgets_org)); + else + snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets_rev01, + ARRAY_SIZE(msm8960_dapm_widgets_rev01)); + if (machine_is_COMANCHE() || machine_is_EXPRESS() || + (machine_is_JASPER() && system_rev < BOARD_REV02)) + snd_soc_dapm_add_routes(dapm, common_audio_map_org, + ARRAY_SIZE(common_audio_map_org)); + else + snd_soc_dapm_add_routes(dapm, common_audio_map_rev01, + ARRAY_SIZE(common_audio_map_rev01)); + + if (machine_is_COMANCHE()) + snd_soc_dapm_add_routes(dapm, comanche_audio_map_org, + ARRAY_SIZE(comanche_audio_map_org)); + + if (machine_is_EXPRESS()) + snd_soc_dapm_add_routes(dapm, express_audio_map_org, + ARRAY_SIZE(express_audio_map_org)); + + snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg"); + + snd_soc_dapm_sync(dapm); + + err = snd_soc_jack_new(codec, "Headset Jack", + (SND_JACK_HEADSET | SND_JACK_OC_HPHL | + SND_JACK_OC_HPHR), + &hs_jack); + if (err) { + pr_err("failed to create new jack\n"); + return err; + } + err = snd_soc_jack_new(codec, "Button Jack", + SND_JACK_BTN_0, &button_jack); + if (err) { + pr_err("failed to create new jack\n"); + return err; + } + err = snd_soc_jack_new(codec, "Volumeup Jack", + SND_JACK_BTN_1, &volumeup_jack); + if (err) { + pr_err("failed to create new jack\n"); + return err; + } + err = snd_soc_jack_new(codec, "Volumedown Jack", + SND_JACK_BTN_2, &volumedown_jack); + if (err) { + pr_err("failed to create new jack\n"); + return err; + } + /* BTN_1 button is mapped to VOLUME Up key type*/ + snd_jack_set_key(volumeup_jack.jack, + SND_JACK_BTN_1, KEY_VOLUMEUP); + /* BTN_2 button is mapped to VOLUME Down key type*/ + snd_jack_set_key(volumedown_jack.jack, + SND_JACK_BTN_2, KEY_VOLUMEDOWN); + + if (!(machine_is_M2_ATT() && system_rev >= BOARD_REV10) && + !(machine_is_M2_VZW() && system_rev >= BOARD_REV13) && + !(machine_is_M2_SPR() && system_rev >= BOARD_REV08) && + !(machine_is_AEGIS2() && system_rev >= BOARD_REV04) && + !(machine_is_JASPER() && system_rev >= BOARD_REV04) && + !(machine_is_COMANCHE() && system_rev >= BOARD_REV02) && + !(machine_is_GOGH() && system_rev >= BOARD_REV03) && + !(machine_is_EXPRESS() && system_rev >= BOARD_REV02)) { + /* using mbhc driver for earjack */ + tabla_hs_detect(codec, &mbhc_cfg); + } + + return 0; +} +#if 0 +static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd) +{ + int err; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + + struct pm_gpio jack_gpio_cfg = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_UP_1P5, + .function = PM_GPIO_FUNC_NORMAL, + .vin_sel = 2, + .inv_int_pol = 0, + }; + + pr_info("%s()\n", __func__); + + if (machine_is_msm8960_liquid()) { + top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS + (PMIC_GPIO_VPS_EN)); + bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS + (PMIC_GPIO_SPK_EN)); + } + + rtd->pmdown_time = 0; + + err = snd_soc_add_codec_controls(codec, tabla_msm8960_controls, + ARRAY_SIZE(tabla_msm8960_controls)); + if (err < 0) + return err; + + snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets_rev00, + ARRAY_SIZE(msm8960_dapm_widgets_rev00)); + if ((machine_is_M2_SKT() && system_rev >= BOARD_REV01)) { + snd_soc_dapm_add_routes(dapm, common_audio_map_rev00, + ARRAY_SIZE(common_audio_map_rev00)); + } else if (machine_is_M2_DCM()) { + snd_soc_dapm_add_routes(dapm, common_audio_map_rev00, + ARRAY_SIZE(common_audio_map_rev00)); + } else { + snd_soc_dapm_add_routes(dapm, common_audio_map_org, + ARRAY_SIZE(common_audio_map_org)); + } + + snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg"); + + snd_soc_dapm_sync(dapm); + + err = snd_soc_jack_new(codec, "Headset Jack", + (SND_JACK_HEADSET | SND_JACK_OC_HPHL | + SND_JACK_OC_HPHR), + &hs_jack); + if (err) { + pr_err("failed to create new jack\n"); + return err; + } + + err = snd_soc_jack_new(codec, "Button Jack", + SND_JACK_BTN_0, &button_jack); + if (err) { + pr_err("failed to create new jack\n"); + return err; + } + err = snd_soc_jack_new(codec, "Volumeup Jack", + SND_JACK_BTN_1, &volumeup_jack); + if (err) { + pr_err("failed to create new jack\n"); + return err; + } + err = snd_soc_jack_new(codec, "Volumedown Jack", + SND_JACK_BTN_2, &volumedown_jack); + if (err) { + pr_err("failed to create new jack\n"); + return err; + } + /* BTN_1 button is mapped to VOLUME Up key type*/ + snd_jack_set_key(volumeup_jack.jack, + SND_JACK_BTN_1, KEY_VOLUMEUP); + /* BTN_2 button is mapped to VOLUME Down key type*/ + snd_jack_set_key(volumedown_jack.jack, + SND_JACK_BTN_2, KEY_VOLUMEDOWN); + + if (((machine_is_M2_SKT() && system_rev < BOARD_REV08) || + (machine_is_M2_DCM() && system_rev < BOARD_REV03) || + (!machine_is_M2_SKT() && !machine_is_M2_DCM()))) { + /* using mbhc driver for earjack */ + if (GPIO_DETECT_USED) { + mbhc_cfg.gpio = PM8921_GPIO_PM_TO_SYS(JACK_DETECT_GPIO); + mbhc_cfg.gpio_irq = JACK_DETECT_INT; + } + + if (mbhc_cfg.gpio) { + err = pm8xxx_gpio_config(mbhc_cfg.gpio, &jack_gpio_cfg); + if (err) { + pr_err("%s: pm8xxx_gpio_config failed %d\n", __func__, + err); + return err; + } + } + err = tabla_hs_detect(codec, &mbhc_cfg); + } + + return 0; +} +static struct snd_soc_dsp_link lpa_fe_media = { + .playback = true, + .trigger = { + SND_SOC_DSP_TRIGGER_POST, + SND_SOC_DSP_TRIGGER_POST + }, +}; + +static struct snd_soc_dsp_link fe_media = { + .playback = true, + .capture = true, + .trigger = { + SND_SOC_DSP_TRIGGER_POST, + SND_SOC_DSP_TRIGGER_POST + }, +}; + +static struct snd_soc_dsp_link slimbus0_hl_media = { + .playback = true, + .capture = true, + .trigger = { + SND_SOC_DSP_TRIGGER_POST, + SND_SOC_DSP_TRIGGER_POST + }, +}; + +static struct snd_soc_dsp_link int_fm_hl_media = { + .playback = true, + .capture = true, + .trigger = { + SND_SOC_DSP_TRIGGER_POST, + SND_SOC_DSP_TRIGGER_POST + }, +}; +#endif +static int msm8960_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_info("%s()\n", __func__); + rate->min = rate->max = 48000; + channels->min = channels->max = msm8960_i2s_rx_ch; + + return 0; +} + +static int msm8960_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_info("%s()\n", __func__); + rate->min = rate->max = 48000; + channels->min = channels->max = msm8960_i2s_tx_ch; + + return 0; +} +#if 0 +static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_info("%s()\n", __func__); + rate->min = rate->max = 48000; + channels->min = channels->max = msm8960_slim_0_rx_ch; + + return 0; +} + +static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_info("%s()\n", __func__); + rate->min = rate->max = 48000; + channels->min = channels->max = msm8960_slim_0_tx_ch; + + return 0; +} +#endif +static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + pr_info("%s()\n", __func__); + rate->min = rate->max = 48000; + + return 0; +} + +static int msm8960_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_info("%s channels->min %u channels->max %u ()\n", __func__, + channels->min, channels->max); + rate->min = rate->max = 48000; + + return 0; +} + +static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = msm8960_btsco_rate; + channels->min = channels->max = msm8960_btsco_ch; + + return 0; +} +static int msm8960_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* PCM only supports mono output with 8khz sample rate */ + rate->min = rate->max = 8000; + channels->min = channels->max = 1; + + return 0; +} + +static int msm8960_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + pr_info("%s()\n", __func__); + rate->min = rate->max = 48000; + + return 0; +} + +int msm8960_aux_pcm_get_gpios(void) +{ + int ret = 0; + + pr_info("%s\n", __func__); + + ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT"); + if (ret < 0) { + pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT", + __func__, GPIO_AUX_PCM_DOUT); + goto fail_dout; + } + + ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN"); + if (ret < 0) { + pr_err("%s: Failed to request gpio(%d): AUX PCM DIN", + __func__, GPIO_AUX_PCM_DIN); + goto fail_din; + } + + ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC"); + if (ret < 0) { + pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC", + __func__, GPIO_AUX_PCM_SYNC); + goto fail_sync; + } + ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK"); + if (ret < 0) { + pr_err("%s: Failed to request gpio(%d): AUX PCM CLK", + __func__, GPIO_AUX_PCM_CLK); + goto fail_clk; + } + + gpio_tlmm_config(GPIO_CFG(GPIO_AUX_PCM_DOUT, 1, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_AUX_PCM_DIN, 1, GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_AUX_PCM_SYNC, 1, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_AUX_PCM_CLK, 1, GPIO_CFG_OUTPUT, + GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1); + + return 0; + +fail_clk: + gpio_free(GPIO_AUX_PCM_SYNC); +fail_sync: + gpio_free(GPIO_AUX_PCM_DIN); +fail_din: + gpio_free(GPIO_AUX_PCM_DOUT); +fail_dout: + + return ret; +} + +int msm8960_aux_pcm_free_gpios(void) +{ + gpio_tlmm_config(GPIO_CFG(GPIO_AUX_PCM_DOUT, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_AUX_PCM_DIN, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_AUX_PCM_SYNC, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + gpio_tlmm_config(GPIO_CFG(GPIO_AUX_PCM_CLK, 0, GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1); + + gpio_free(GPIO_AUX_PCM_DIN); + gpio_free(GPIO_AUX_PCM_DOUT); + gpio_free(GPIO_AUX_PCM_SYNC); + gpio_free(GPIO_AUX_PCM_CLK); + + return 0; +} +static int msm8960_cdc_i2s_rx_free_gpios(void) +{ + gpio_free(GPIO_SPKR_I2S_RX_SCK); + gpio_free(GPIO_SPKR_I2S_RX_DOUT); + gpio_free(GPIO_SPKR_I2S_RX_WS); + + return 0; +} + +static int msm8960_cdc_i2s_tx_free_gpios(void) +{ + gpio_free(GPIO_SPKR_I2S_TX_SCK); + gpio_free(GPIO_SPKR_I2S_TX_D0); + gpio_free(GPIO_SPKR_I2S_TX_WS); + + return 0; +} + +static int msm8660_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int rate = params_rate(params); + int bit_clk_set = 0; + pr_info("%s Codec Clock 0x%x ; Rx Bit Clock %x\n", __func__, + (unsigned int)codec_clk, (unsigned int)rx_bit_clk); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + bit_clk_set = I2S_MCLK_RATE / (rate * 2 * + NO_OF_BITS_PER_SAMPLE); + if (rx_bit_clk == NULL) { + pr_err("%s : Reconfiguring rx_bit_clk\n", __func__); + if (codec_clk == NULL) { + codec_clk = clk_get(NULL, "i2s_spkr_osr_clk"); + clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE); + clk_enable(codec_clk); + } + rx_bit_clk = clk_get(NULL, "i2s_spkr_bit_clk"); + clk_set_rate(rx_bit_clk, 8); + clk_enable(rx_bit_clk); + } + clk_set_rate(rx_bit_clk, bit_clk_set); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + bit_clk_set = I2S_MIC_MCLK_RATE / (rate * 2 * + NO_OF_BITS_PER_SAMPLE); + if (tx_bit_clk == NULL) { + pr_err("%s : Reconfiguring tx_bit_clk\n", __func__); + if (tx_osr_clk == NULL) { + tx_osr_clk = clk_get(NULL, "i2s_mic_osr_clk"); + clk_set_rate(tx_osr_clk, I2S_MIC_MCLK_RATE); + clk_enable(tx_osr_clk); + } + tx_bit_clk = clk_get(NULL, "i2s_mic_bit_clk"); + clk_set_rate(tx_bit_clk, 8); + clk_enable(tx_bit_clk); + } + clk_set_rate(tx_bit_clk, bit_clk_set); + } + return 1; +} + + +static void msm8960_i2s_shutdown(struct snd_pcm_substream *substream) +{ + pr_info("%s Codec Clock 0x%x ; Rx Bit Clock %x\n", __func__, + (unsigned int)codec_clk, (unsigned int)rx_bit_clk); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (rx_bit_clk) { + clk_disable(rx_bit_clk); + clk_put(rx_bit_clk); + clk_disable(codec_clk); + clk_put(codec_clk); + rx_bit_clk = NULL; + } + msm8960_cdc_i2s_rx_free_gpios(); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + if (tx_bit_clk) { + clk_disable(tx_bit_clk); + clk_put(tx_bit_clk); + clk_disable(tx_osr_clk); + clk_put(tx_osr_clk); + tx_bit_clk = NULL; + } + msm8960_cdc_i2s_tx_free_gpios(); + } +} + +int configure_i2s_rx_gpio(void) +{ + u8 ret = 0; + + ret = gpio_request(GPIO_SPKR_I2S_RX_SCK, "I2S_RX_SCK"); + if (ret) { + pr_err("%s: Failed to request gpio %d\n", __func__, + GPIO_SPKR_I2S_RX_SCK); + goto err; + } + ret = gpio_request(GPIO_SPKR_I2S_RX_DOUT, "I2S_RX_DOUT"); + if (ret) { + pr_err("%s: Failed to request gpio %d\n", __func__, + GPIO_SPKR_I2S_RX_DOUT); + goto err; + } + ret = gpio_request(GPIO_SPKR_I2S_RX_WS, "I2S_RX_WS"); + if (ret) { + pr_err("%s: Failed to request gpio %d\n", __func__, + GPIO_SPKR_I2S_RX_WS); + goto err; + } +err: + return ret; +} + +int configure_i2s_tx_gpio(void) +{ + u8 ret = 0; + + ret = gpio_request(GPIO_SPKR_I2S_TX_SCK, "I2S_RX_SCK"); + if (ret) { + pr_err("%s: Failed to request gpio %d\n", __func__, + GPIO_SPKR_I2S_TX_SCK); + goto err; + } + ret = gpio_request(GPIO_SPKR_I2S_TX_D0, "I2S_RX_DOUT"); + if (ret) { + pr_err("%s: Failed to request gpio %d\n", __func__, + GPIO_SPKR_I2S_TX_D0); + goto err; + } + ret = gpio_request(GPIO_SPKR_I2S_TX_WS, "I2S_RX_WS"); + if (ret) { + pr_err("%s: Failed to request gpio %d\n", __func__, + GPIO_SPKR_I2S_TX_WS); + goto err; + } +err: + return ret; +} + +static int msm8960_i2s_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + pr_info("%s\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + configure_i2s_rx_gpio(); + codec_clk = clk_get(NULL, "i2s_spkr_osr_clk"); + if (IS_ERR(codec_clk)) { + pr_err("%s Error getting i2s_spkr_osr_clk", __func__); + return -EBUSY; + } + clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE); + ret = clk_prepare_enable(codec_clk); + if (ret) { + pr_err("Unable to enable codec clock\n"); + clk_put(codec_clk); + return ret; + } + + rx_bit_clk = clk_get(NULL, "i2s_spkr_bit_clk"); + if (IS_ERR(rx_bit_clk)) { + pr_err("Failed to get i2s_spkr_bit_clk\n"); + clk_disable(codec_clk); + clk_put(codec_clk); + return -EBUSY; + } + clk_set_rate(rx_bit_clk, 8); + ret = clk_prepare_enable(rx_bit_clk); + if (ret) { + pr_err("Unable to enable bit_clk\n"); + clk_disable(codec_clk); + clk_put(codec_clk); + clk_put(rx_bit_clk); + return ret; + } + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + pr_err("set format for cpu dai failed\n"); + return ret; + } + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + pr_err("set format for codec dai failed\n"); + return ret; + } + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + configure_i2s_tx_gpio(); + + tx_osr_clk = clk_get(NULL, "i2s_mic_osr_clk"); + if (IS_ERR(tx_osr_clk)) { + pr_info("Failed to get i2s_mic_osr_clk\n"); + return -EBUSY; + } + /* Master clock OSR 256 */ + clk_set_rate(tx_osr_clk, I2S_MIC_MCLK_RATE); + ret = clk_prepare_enable(tx_osr_clk); + if (ret) { + pr_info("Unable to enable i2s_mic_osr_clk\n"); + clk_put(tx_osr_clk); + return ret; + } + tx_bit_clk = clk_get(NULL, "i2s_mic_bit_clk"); + if (IS_ERR(tx_bit_clk)) { + pr_info("Failed to get i2s_mic_bit_clk\n"); + clk_disable(tx_osr_clk); + clk_put(tx_osr_clk); + return -EBUSY; + } + clk_set_rate(tx_bit_clk, 8); + ret = clk_prepare_enable(tx_bit_clk); + if (ret) { + pr_info("Unable to enable i2s_mic_bit_clk\n"); + clk_put(tx_bit_clk); + clk_disable(tx_osr_clk); + clk_put(tx_osr_clk); + return ret; + } + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + + if (ret < 0) { + pr_err("set format for cpu dai failed\n"); + return ret; + } + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + pr_err("set format for codec dai failed\n"); + return ret; + } + } + return ret; +} + +/* Not used */ +#if 0 +static int msm8960_startup(struct snd_pcm_substream *substream) +{ + pr_info("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + return 0; +} + +static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + + pr_info("%s(): substream = %s\n", __func__, substream->name); + ret = msm8960_aux_pcm_get_gpios(); + if (ret < 0) { + pr_err("%s: Aux PCM GPIO request failed\n", __func__); + return -EINVAL; + } + return 0; +} + +static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream) +{ + + pr_info("%s(): substream = %s\n", __func__, substream->name); + msm8960_aux_pcm_free_gpios(); +} + +static void msm8960_shutdown(struct snd_pcm_substream *substream) +{ + pr_info("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); +} + +static struct snd_soc_ops msm8960_be_ops = { + .startup = msm8960_startup, + .shutdown = msm8960_shutdown, +}; +#endif +static struct snd_soc_ops msm8960_i2s_be_ops = { + .startup = msm8960_i2s_startup, + .shutdown = msm8960_i2s_shutdown, + .hw_params = msm8660_i2s_hw_params, +}; + +/* Not Used */ +/* +static struct snd_soc_ops msm8960_auxpcm_be_ops = { + .startup = msm8960_auxpcm_startup, + .shutdown = msm8960_auxpcm_shutdown, +}; +*/ + +static struct snd_soc_dai_link *msm8960_dai_list; +static struct snd_soc_dai_link msm8960_i2s_be_dai[] = { + { + .name = LPASS_BE_PRI_I2S_RX, + .stream_name = "Primary I2S Playback", + .cpu_dai_name = "msm-dai-q6.0", + .platform_name = "msm-pcm-routing", + .codec_name = "tabla_codec", + .codec_dai_name = "tabla_i2s_rx1", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_PRI_I2S_RX, + .init = &msm8960_i2s_audrx_init, + .be_hw_params_fixup = msm8960_i2s_rx_be_hw_params_fixup, + .ops = &msm8960_i2s_be_ops, + }, + { + .name = LPASS_BE_PRI_I2S_TX, + .stream_name = "Primary I2S Capture", + .cpu_dai_name = "msm-dai-q6.1", + .platform_name = "msm-pcm-routing", + .codec_name = "tabla_codec", + .codec_dai_name = "tabla_i2s_tx1", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_PRI_I2S_TX, + .be_hw_params_fixup = msm8960_i2s_tx_be_hw_params_fixup, + .ops = &msm8960_i2s_be_ops, + }, +}; +#if 0 +static struct snd_soc_dai_link msm8960_slimbus_be_dai[] = { + { + .name = LPASS_BE_SLIMBUS_0_RX, + .stream_name = "Slimbus Playback", + .cpu_dai_name = "msm-dai-q6.16384", + .platform_name = "msm-pcm-routing", + .codec_name = "tabla_codec", + .codec_dai_name = "tabla_rx1", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX, + .init = &msm8960_audrx_init, + .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup, + .ops = &msm8960_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_0_TX, + .stream_name = "Slimbus Capture", + .cpu_dai_name = "msm-dai-q6.16385", + .platform_name = "msm-pcm-routing", + .codec_name = "tabla_codec", + .codec_dai_name = "tabla_tx1", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX, + .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup, + .ops = &msm8960_be_ops, + }, +}; +#endif +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link msm8960_dai[] = { + /* FrontEnd DAI Links */ + { + .name = "MSM8960 Media1", + .stream_name = "MultiMedia1", + .cpu_dai_name = "MultiMedia1", + .platform_name = "msm-pcm-dsp", + .dynamic = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1 + }, + { + .name = "MSM8960 Media2", + .stream_name = "MultiMedia2", + .cpu_dai_name = "MultiMedia2", + .platform_name = "msm-multi-ch-pcm-dsp", + .dynamic = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2, + }, + { + .name = "Circuit-Switch Voice", + .stream_name = "CS-Voice", + .cpu_dai_name = "CS-VOICE", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_CS_VOICE, + }, + { + .name = "MSM VoIP", + .stream_name = "VoIP", + .cpu_dai_name = "VoIP", + .platform_name = "msm-voip-dsp", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_VOIP, + }, + { + .name = "MSM8960 LPA", + .stream_name = "LPA", + .cpu_dai_name = "MultiMedia3", + .platform_name = "msm-pcm-lpa", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3, + }, + /* Hostless PMC purpose */ + { + .name = "SLIMBUS_0 Hostless", + .stream_name = "SLIMBUS_0 Hostless", + .cpu_dai_name = "SLIMBUS0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "INT_FM Hostless", + .stream_name = "INT_FM Hostless", + .cpu_dai_name = "INT_FM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "MSM AFE-PCM RX", + .stream_name = "AFE-PROXY RX", + .cpu_dai_name = "msm-dai-q6.241", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .platform_name = "msm-pcm-afe", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + }, + { + .name = "MSM AFE-PCM TX", + .stream_name = "AFE-PROXY TX", + .cpu_dai_name = "msm-dai-q6.240", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .platform_name = "msm-pcm-afe", + .ignore_suspend = 1, + }, + { + .name = "MSM8960 Compr", + .stream_name = "COMPR", + .cpu_dai_name = "MultiMedia4", + .platform_name = "msm-compr-dsp", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4, + }, + { + .name = "AUXPCM Hostless", + .stream_name = "AUXPCM Hostless", + .cpu_dai_name = "AUXPCM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + /* HDMI Hostless */ + { + .name = "HDMI_RX_HOSTLESS", + .stream_name = "HDMI_RX_HOSTLESS", + .cpu_dai_name = "HDMI_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "VoLTE", + .stream_name = "VoLTE", + .cpu_dai_name = "VoLTE", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_VOLTE, + }, + { + .name = "SGLTE", + .stream_name = "SGLTE", + .cpu_dai_name = "SGLTE", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1,/* this dainlink has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .be_id = MSM_FRONTEND_DAI_SGLTE, + }, +#if 0 + { + .name = "MSM8960 LowLatency", + .stream_name = "MultiMedia5", + .cpu_dai_name = "MultiMedia5", + .platform_name = "msm-lowlatency-pcm-dsp", + .dynamic = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5, + }, +#endif + /* Backend BT/FM DAI Links */ + { + .name = LPASS_BE_INT_BT_SCO_RX, + .stream_name = "Internal BT-SCO Playback", + .cpu_dai_name = "msm-dai-q6.12288", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .init = &msm8960_btsco_init, + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX, + .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + }, + { + .name = LPASS_BE_INT_BT_SCO_TX, + .stream_name = "Internal BT-SCO Capture", + .cpu_dai_name = "msm-dai-q6.12289", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX, + .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup, + }, + { + .name = LPASS_BE_INT_FM_RX, + .stream_name = "Internal FM Playback", + .cpu_dai_name = "msm-dai-q6.12292", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_INT_FM_RX, + .be_hw_params_fixup = msm8960_be_hw_params_fixup, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + }, + { + .name = LPASS_BE_INT_FM_TX, + .stream_name = "Internal FM Capture", + .cpu_dai_name = "msm-dai-q6.12293", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_INT_FM_TX, + .be_hw_params_fixup = msm8960_be_hw_params_fixup, + }, + /* HDMI BACK END DAI Link */ + { + .name = LPASS_BE_HDMI, + .stream_name = "HDMI Playback", + .cpu_dai_name = "msm-dai-q6-hdmi.8", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_HDMI_RX, + .be_hw_params_fixup = msm8960_hdmi_be_hw_params_fixup, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + }, + /* Backend AFE DAI Links */ + { + .name = LPASS_BE_AFE_PCM_RX, + .stream_name = "AFE Playback", + .cpu_dai_name = "msm-dai-q6.224", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_AFE_PCM_RX, + .be_hw_params_fixup = msm8960_proxy_be_hw_params_fixup, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + }, + { + .name = LPASS_BE_AFE_PCM_TX, + .stream_name = "AFE Capture", + .cpu_dai_name = "msm-dai-q6.225", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_AFE_PCM_TX, + .be_hw_params_fixup = msm8960_proxy_be_hw_params_fixup, + }, + /* AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_AUXPCM_RX, + .stream_name = "AUX PCM Playback", + .cpu_dai_name = "msm-dai-q6.2", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_AUXPCM_RX, + .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup, +// .ops = &msm8960_auxpcm_be_ops, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_AUXPCM_TX, + .stream_name = "AUX PCM Capture", + .cpu_dai_name = "msm-dai-q6.3", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_AUXPCM_TX, + .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup, +// .ops = &msm8960_auxpcm_be_ops, + }, + /* Incall Music BACK END DAI Link */ + { + .name = LPASS_BE_VOICE_PLAYBACK_TX, + .stream_name = "Voice Farend Playback", + .cpu_dai_name = "msm-dai-q6.32773", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, + .be_hw_params_fixup = msm8960_be_hw_params_fixup, + }, + /* Incall Record Uplink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_TX, + .stream_name = "Voice Uplink Capture", + .cpu_dai_name = "msm-dai-q6.32772", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX, + .be_hw_params_fixup = msm8960_be_hw_params_fixup, + }, + /* Incall Record Downlink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_RX, + .stream_name = "Voice Downlink Capture", + .cpu_dai_name = "msm-dai-q6.32771", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX, + .be_hw_params_fixup = msm8960_be_hw_params_fixup, + .ignore_pmdown_time = 1, /* this dainlink has playback support */ + }, +}; + +struct snd_soc_card snd_soc_card_msm8960 = { + .name = "msm8960-snd-card", + .dai_link = msm8960_dai, + .num_links = ARRAY_SIZE(msm8960_dai), +}; + +static struct platform_device *msm8960_snd_device; + +static int msm8960_configure_audio_gpios(void) +{ + int ret; + + struct pm_gpio param = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_CMOS, + .output_value = 1, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S4, + .out_strength = PM_GPIO_STRENGTH_MED, + .function = PM_GPIO_FUNC_NORMAL, + }; +#if !defined(CONFIG_MACH_M2_DCM) && !defined(CONFIG_MACH_AEGIS2) \ + && !defined(CONFIG_MACH_K2_KDI) && !defined(CONFIG_MACH_EXPRESS) + ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH"); + if (ret) { + pr_err("%s: Failed to request gpio %d\n", __func__, + PM8921_GPIO_PM_TO_SYS(23)); + return ret; + } + + ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), ¶m); + if (ret) { + pr_err("%s: Failed to configure gpio %d\n", __func__, + PM8921_GPIO_PM_TO_SYS(23)); + return ret; + } + gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0); + + ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH"); + if (ret) { + pr_err("%s: Failed to request gpio %d\n", __func__, + PM8921_GPIO_PM_TO_SYS(35)); + gpio_free(PM8921_GPIO_PM_TO_SYS(23)); + return ret; + } + ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), ¶m); + if (ret) { + pr_err("%s: Failed to configure gpio %d\n", __func__, + PM8921_GPIO_PM_TO_SYS(35)); + return ret; + } + gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0); +#endif +#if !defined(CONFIG_MACH_AEGIS2) + ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP"); + if (ret) { + pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n", + __func__, bottom_spk_pamp_gpio); + } + ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, ¶m); + if (ret) { + pr_err("%s: Failed to configure Bottom Spk Ampl" + " gpio %u\n", __func__, bottom_spk_pamp_gpio); + return ret; + } else + gpio_direction_output(bottom_spk_pamp_gpio, 0); +#endif + ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP"); + if (ret) { + pr_err("%s: Error requesting TOP SPK AMP GPIO %u\n", + __func__, top_spk_pamp_gpio); + } + ret = pm8xxx_gpio_config(top_spk_pamp_gpio, ¶m); + if (ret) { + pr_err("%s: Failed to configure Top Spk Ampl" + " gpio %u\n", __func__, top_spk_pamp_gpio); + return ret; + } else + gpio_direction_output(top_spk_pamp_gpio, 0); + + return 0; +} + +static void msm8960_free_audio_gpios(void) +{ + if (msm8960_audio_gpios_configured) { +#if !defined(CONFIG_MACH_M2_DCM) && !defined(CONFIG_MACH_AEGIS2) \ + && !defined(CONFIG_MACH_K2_KDI) && !defined(CONFIG_MACH_EXPRESS) + gpio_free(PM8921_GPIO_PM_TO_SYS(23)); + gpio_free(PM8921_GPIO_PM_TO_SYS(35)); +#endif + gpio_free(top_spk_pamp_gpio); +#if !defined(CONFIG_MACH_AEGIS2) + gpio_free(bottom_spk_pamp_gpio); +#endif + } +} + +static int __init msm8960_audio_init(void) +{ + int ret; + msm8960_dai_list = kzalloc(sizeof(msm8960_dai) + + 2 * sizeof(struct snd_soc_dai_link), GFP_KERNEL); +/* + if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS) { + memcpy(msm8960_dai_list, msm8960_dai, sizeof(msm8960_dai)); + memcpy(&msm8960_dai_list[ARRAY_SIZE(msm8960_dai)], + msm8960_slimbus_be_dai, sizeof(msm8960_slimbus_be_dai)); + snd_soc_card_msm8960.dai_link = msm8960_dai_list; + snd_soc_card_msm8960.num_links = ARRAY_SIZE(msm8960_dai) + + ARRAY_SIZE(msm8960_slimbus_be_dai); + } else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C) { +*/ + memcpy(msm8960_dai_list, msm8960_dai, sizeof(msm8960_dai)); + memcpy(&msm8960_dai_list[ARRAY_SIZE(msm8960_dai)], + msm8960_i2s_be_dai, sizeof(msm8960_i2s_be_dai)); + snd_soc_card_msm8960.dai_link = msm8960_dai_list; + snd_soc_card_msm8960.num_links = ARRAY_SIZE(msm8960_dai) + + ARRAY_SIZE(msm8960_i2s_be_dai); +// } + + printk(KERN_INFO "%s: start", __func__); + mbhc_cfg.calibration = def_tabla_mbhc_cal(); + if (!mbhc_cfg.calibration) { + pr_err("Calibration data allocation failed\n"); + kfree(msm8960_dai_list); + return -ENOMEM; + } + + msm8960_snd_device = platform_device_alloc("soc-audio", 0); + if (!msm8960_snd_device) { + pr_err("Platform device allocation failed\n"); + kfree(mbhc_cfg.calibration); + kfree(msm8960_dai_list); + return -ENOMEM; + } + + platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960); + ret = platform_device_add(msm8960_snd_device); + if (ret) { + platform_device_put(msm8960_snd_device); + kfree(mbhc_cfg.calibration); + kfree(msm8960_dai_list); + return ret; + } + + if (msm8960_configure_audio_gpios()) { + pr_err("%s Fail to configure headset mic gpios\n", __func__); + msm8960_audio_gpios_configured = 0; + } else + msm8960_audio_gpios_configured = 1; + + mutex_init(&cdc_mclk_mutex); + + INIT_DELAYED_WORK(&ext_amp_dwork.dwork, + external_speaker_amp_work); + return ret; + +} +module_init(msm8960_audio_init); + +static void __exit msm8960_audio_exit(void) +{ + msm8960_free_audio_gpios(); + kfree(msm8960_dai_list); + platform_device_unregister(msm8960_snd_device); + kfree(mbhc_cfg.calibration); + mutex_destroy(&cdc_mclk_mutex); +} +module_exit(msm8960_audio_exit); + +MODULE_DESCRIPTION("ALSA SoC MSM8960"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c index aaebad5f6a2..63fda7b3547 100644 --- a/sound/soc/msm/qdsp6/q6afe.c +++ b/sound/soc/msm/qdsp6/q6afe.c @@ -349,7 +349,7 @@ int afe_q6_interface_prepare(void) { int ret = 0; - pr_debug("%s:", __func__); + pr_info("%s:", __func__); if (this_afe.apr == NULL) { this_afe.apr = apr_register("ADSP", "AFE", afe_callback, @@ -368,11 +368,11 @@ static void afe_send_cal_block(int32_t path, u16 port_id) int result = 0; struct acdb_cal_block cal_block; struct afe_port_cmd_set_param_no_payload afe_cal; - pr_debug("%s: path %d\n", __func__, path); + pr_info("%s: path %d\n", __func__, path); get_afe_cal(path, &cal_block); if (cal_block.cal_size <= 0) { - pr_debug("%s: No AFE cal to send!\n", __func__); + pr_info("%s: No AFE cal to send!\n", __func__); goto done; } @@ -398,7 +398,7 @@ static void afe_send_cal_block(int32_t path, u16 port_id) afe_cal.payload_size = cal_block.cal_size; afe_cal.payload_address = cal_block.cal_paddr; - pr_debug("%s: AFE cal sent for device port = %d, path = %d, " + pr_info("%s: AFE cal sent for device port = %d, path = %d, " "cal size = %d, cal addr = 0x%x\n", __func__, port_id, path, cal_block.cal_size, cal_block.cal_paddr); @@ -424,7 +424,7 @@ static void afe_send_cal_block(int32_t path, u16 port_id) void afe_send_cal(u16 port_id) { - pr_debug("%s\n", __func__); + pr_info("%s\n", __func__); if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) afe_send_cal_block(TX_CAL, port_id); @@ -447,7 +447,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, ret = -EINVAL; return ret; } - pr_debug("%s: %d %d\n", __func__, port_id, rate); + pr_info("%s: %d %d\n", __func__, port_id, rate); if ((port_id == RT_PROXY_DAI_001_RX) || (port_id == RT_PROXY_DAI_002_TX)) { @@ -520,7 +520,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, * is L-PCM, the AFE_PORT_AUDIO_IF_CONFIG is used * to make the backward compatible. */ - pr_debug("%s: afe_config->mi2s.format = %d\n", __func__, + pr_info("%s: afe_config->mi2s.format = %d\n", __func__, afe_config->mi2s.format); if (afe_config->mi2s.format == MSM_AFE_I2S_FORMAT_LPCM) config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG; diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index f56b3d675b2..f07848788de 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -225,7 +225,7 @@ int afe_q6_interface_prepare(void) { int ret = 0; - pr_debug("%s:", __func__); + pr_info("%s:", __func__); if (this_afe.apr == NULL) { this_afe.apr = apr_register("ADSP", "AFE", afe_callback, From 0fe22c884d7cb3ba14c25e1ba9b39c3ba1da6601 Mon Sep 17 00:00:00 2001 From: detule Date: Sat, 2 Mar 2013 20:27:51 -0500 Subject: [PATCH 2328/2357] M2: video: fix panel flicker introduced in rebase (CAF you cant sabotage us) Problem was introduced in Revert "mako: debug: disable lge_crash_handler" --- drivers/video/msm/msm_dss_io_8960.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c index d569636d8b2..2fee599e2ed 100644 --- a/drivers/video/msm/msm_dss_io_8960.c +++ b/drivers/video/msm/msm_dss_io_8960.c @@ -657,7 +657,8 @@ void mipi_dsi_prepare_clocks(void) if (clk_set_rate(dsi_byte_div_clk, 1) < 0) /* divided by 1 */ pr_err("%s: dsi_byte_div_clk - " "clk_set_rate failed\n", __func__); - if (clk_set_rate(dsi_esc_clk, 2) < 0) /* divided by esc */ + if (clk_set_rate(dsi_esc_clk, 2) < 0) /* divided by 2 */ + pr_err("%s: dsi_esc_clk - " /* clk ratio */ "clk_set_rate failed\n", __func__); clk_prepare(dsi_byte_div_clk); @@ -712,7 +713,7 @@ void mipi_dsi_clk_enable(void) if (clk_set_rate(dsi_byte_div_clk, 1) < 0) /* divided by 1 */ pr_err("%s: dsi_byte_div_clk - " "clk_set_rate failed\n", __func__); - if (clk_set_rate(dsi_esc_clk, esc_byte_ratio) < 0) /* divided by esc */ + if (clk_set_rate(dsi_esc_clk, 2) < 0) /* divided by 2 */ pr_err("%s: dsi_esc_clk - " /* clk ratio */ "clk_set_rate failed\n", __func__); mipi_dsi_pclk_ctrl(&dsi_pclk, 1); From f96ba4b5f7a49e8d505d8f4b6755d6ab9f5ac215 Mon Sep 17 00:00:00 2001 From: detule Date: Thu, 28 Feb 2013 10:09:10 -0500 Subject: [PATCH 2329/2357] M2: Revert "msm: display: sync point clean up" Can't do these header changes while userland lags behind us This reverts commit 3e3ba5ffc92a6a831b144ee151665751355ae530. Conflicts: drivers/video/msm/msm_fb.c drivers/video/msm/msm_fb.h include/linux/msm_mdp.h --- drivers/video/msm/msm_fb.c | 125 +++++++++++++++++++++++++++++-------- drivers/video/msm/msm_fb.h | 3 +- include/linux/msm_mdp.h | 1 + 3 files changed, 101 insertions(+), 28 deletions(-) mode change 100644 => 100755 drivers/video/msm/msm_fb.c diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c old mode 100644 new mode 100755 index a3ec88263f4..8d05b9a5c7a --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -452,10 +452,7 @@ static int msm_fb_probe(struct platform_device *pdev) pdev_list[pdev_list_cnt++] = pdev; msm_fb_create_sysfs(pdev); if (mfd->timeline == NULL) { - char timeline_name[MAX_TIMELINE_NAME_LEN]; - snprintf(timeline_name, sizeof(timeline_name), - "mdp_fb_%d", mfd->index); - mfd->timeline = sw_sync_timeline_create(timeline_name); + mfd->timeline = sw_sync_timeline_create("mdp-timeline"); if (mfd->timeline == NULL) { pr_err("%s: cannot create time line", __func__); return -ENOMEM; @@ -991,7 +988,17 @@ static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, if (ret) mfd->panel_power_on = curr_pwr_state; - msm_fb_release_timeline(mfd); + if (mfd->timeline) { + /* Adding 1 is enough when pan_display is still + * a blocking call and with mutex protection. + * But if it is an async call, we will still + * need to add 2. Adding 2 can be safer in + * order to signal all existing fences, and it + * is harmless. */ + sw_sync_timeline_inc(mfd->timeline, 2); + mfd->timeline_value+= 2; + } + mfd->op_enable = TRUE; } break; @@ -1792,7 +1799,7 @@ static int msm_fb_release(struct fb_info *info, int user) return ret; } -void msm_fb_wait_for_fence(struct msm_fb_data_type *mfd) +int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd) { int i, ret = 0; /* buf sync */ @@ -1813,13 +1820,8 @@ void msm_fb_wait_for_fence(struct msm_fb_data_type *mfd) } sync_fence_put(mfd->acq_fen[i]); } - if (ret < 0) { - while (i < mfd->acq_fen_cnt) { - sync_fence_put(mfd->acq_fen[i]); - i++; - } - } mfd->acq_fen_cnt = 0; + return ret; } int msm_fb_signal_timeline(struct msm_fb_data_type *mfd) { @@ -1835,18 +1837,6 @@ int msm_fb_signal_timeline(struct msm_fb_data_type *mfd) return 0; } -void msm_fb_release_timeline(struct msm_fb_data_type *mfd) -{ - mutex_lock(&mfd->sync_mutex); - if (mfd->timeline) { - sw_sync_timeline_inc(mfd->timeline, 2); - mfd->timeline_value += 2; - } - mfd->last_rel_fence = 0; - mfd->cur_rel_fence = 0; - mutex_unlock(&mfd->sync_mutex); -} - DEFINE_SEMAPHORE(msm_fb_pan_sem); static int msm_fb_pan_idle(struct msm_fb_data_type *mfd) { @@ -2030,7 +2020,10 @@ static int msm_fb_pan_display_sub(struct fb_var_screeninfo *var, if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { pr_err("%s: can't turn on display!\n", __func__); up(&msm_fb_pan_sem); - msm_fb_release_timeline(mfd); + if (mfd->timeline) { + sw_sync_timeline_inc(mfd->timeline, 2); + mfd->timeline_value+= 2; + } return -EINVAL; } } @@ -3646,7 +3639,6 @@ static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd, return ret; } - static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd, struct mdp_buf_sync *buf_sync) { @@ -3738,20 +3730,101 @@ static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd, return ret; } +static int buf_fence_process(struct msm_fb_data_type *mfd, + struct mdp_buf_fence *buf_fence) +{ + int i, fence_cnt = 0, ret; + struct sync_fence *fence; + + if ((buf_fence->acq_fen_fd_cnt == 0) || + (buf_fence->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) || + (mfd->timeline == NULL)) + return -EINVAL; + + mutex_lock(&mfd->sync_mutex); + for (i = 0; i < buf_fence->acq_fen_fd_cnt; i++) { + fence = sync_fence_fdget(buf_fence->acq_fen_fd[i]); + if (fence == NULL) { + pr_info("%s: null fence! i=%d fd=%d\n", __func__, i, + buf_fence->acq_fen_fd[i]); + ret = -EINVAL; + break; + } + mfd->acq_fen[i] = fence; + } + fence_cnt = i; + if (ret) + goto buf_fence_err_1; + mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline, + mfd->timeline_value + 2); + if (mfd->cur_rel_sync_pt == NULL) { + pr_err("%s: cannot create sync point", __func__); + ret = -ENOMEM; + goto buf_fence_err_1; + } + /* create fence */ + mfd->cur_rel_fence = sync_fence_create("mdp-fence", + mfd->cur_rel_sync_pt); + if (mfd->cur_rel_fence == NULL) { + sync_pt_free(mfd->cur_rel_sync_pt); + mfd->cur_rel_sync_pt = NULL; + pr_err("%s: cannot create fence", __func__); + ret = -ENOMEM; + goto buf_fence_err_1; + } + /* create fd */ + mfd->cur_rel_fen_fd = get_unused_fd_flags(0); + if (mfd->cur_rel_fen_fd < 0) { + pr_err("%s: get_unused_fd_flags failed", __func__); + ret = -EIO; + goto buf_fence_err_2; + } + sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd); + buf_fence->rel_fen_fd[0] = mfd->cur_rel_fen_fd; + /* Only one released fd for now, -1 indicates an end */ + buf_fence->rel_fen_fd[1] = -1; + mfd->acq_fen_cnt = buf_fence->acq_fen_fd_cnt; + mutex_unlock(&mfd->sync_mutex); + return ret; +buf_fence_err_2: + sync_fence_put(mfd->cur_rel_fence); + mfd->cur_rel_fence = NULL; + mfd->cur_rel_fen_fd = 0; +buf_fence_err_1: + for (i = 0; i < fence_cnt; i++) + sync_fence_put(mfd->acq_fen[i]); + mfd->acq_fen_cnt = 0; + mutex_unlock(&mfd->sync_mutex); + return ret; +} static int msmfb_display_commit(struct fb_info *info, unsigned long *argp) { int ret; + u32 copy_back = FALSE; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; struct mdp_display_commit disp_commit; + struct mdp_buf_fence *buf_fence; ret = copy_from_user(&disp_commit, argp, sizeof(disp_commit)); if (ret) { pr_err("%s:copy_from_user failed", __func__); return ret; } + buf_fence = &disp_commit.buf_fence; + if (buf_fence->acq_fen_fd_cnt > 0) + ret = buf_fence_process(mfd, buf_fence); + if ((!ret) && (buf_fence->rel_fen_fd[0] > 0)) + copy_back = TRUE; ret = msm_fb_pan_display_ex(info, &disp_commit); + if (copy_back) { + ret = copy_to_user(argp, + &disp_commit, sizeof(disp_commit)); + if (ret) + pr_err("%s:copy_to_user failed", __func__); + } return ret; } diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h index 91537644d07..06a4f6a4d67 100644 --- a/drivers/video/msm/msm_fb.h +++ b/drivers/video/msm/msm_fb.h @@ -242,9 +242,8 @@ int msm_fb_writeback_stop(struct fb_info *info); int msm_fb_writeback_terminate(struct fb_info *info); int msm_fb_detect_client(const char *name); int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp); -void msm_fb_wait_for_fence(struct msm_fb_data_type *mfd); +int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd); int msm_fb_signal_timeline(struct msm_fb_data_type *mfd); -void msm_fb_release_timeline(struct msm_fb_data_type *mfd); #ifdef CONFIG_FB_BACKLIGHT void msm_fb_config_backlight(struct msm_fb_data_type *mfd); #endif diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h index 7fde8d1a337..df1d8e0703c 100644 --- a/include/linux/msm_mdp.h +++ b/include/linux/msm_mdp.h @@ -581,6 +581,7 @@ struct mdp_display_commit { uint32_t flags; uint32_t wait_for_finish; struct fb_var_screeninfo var; + struct mdp_buf_fence buf_fence; }; struct mdp_page_protection { From 90ecbc36eeb535d0f7ada81df5cf73aca864b88f Mon Sep 17 00:00:00 2001 From: detule Date: Thu, 28 Feb 2013 10:18:19 -0500 Subject: [PATCH 2330/2357] M2: Revert "msm: display: Add data stuctures for MSM8974 target support" Can't do these header changes while userland lags behind us. This reverts commit d262b5e923284c66f79d8d7623223250058a5bea. --- include/linux/msm_mdp.h | 45 +++++++---------------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h index df1d8e0703c..4332388c627 100644 --- a/include/linux/msm_mdp.h +++ b/include/linux/msm_mdp.h @@ -278,10 +278,8 @@ struct msmfb_writeback_data { struct msmfb_img img; }; -#define MDP_PP_OPS_ENABLE 0x1 #define MDP_PP_OPS_READ 0x2 #define MDP_PP_OPS_WRITE 0x4 -#define MDP_PP_OPS_DISABLE 0x8 struct mdp_qseed_cfg { uint32_t table_num; @@ -295,19 +293,8 @@ struct mdp_qseed_cfg_data { struct mdp_qseed_cfg qseed_data; }; -struct mdp_sharp_cfg { - uint32_t flags; - uint32_t strength; - uint32_t edge_thr; - uint32_t smooth_thr; - uint32_t noise_thr; -}; - #define MDP_OVERLAY_PP_CSC_CFG 0x1 #define MDP_OVERLAY_PP_QSEED_CFG 0x2 -#define MDP_OVERLAY_PP_PA_CFG 0x4 -#define MDP_OVERLAY_PP_IGC_CFG 0x8 -#define MDP_OVERLAY_PP_SHARP_CFG 0x10 #define MDP_CSC_FLAG_ENABLE 0x1 #define MDP_CSC_FLAG_YUV_IN 0x2 @@ -328,28 +315,10 @@ struct mdp_csc_cfg_data { struct mdp_csc_cfg csc_data; }; -struct mdp_pa_cfg { - uint32_t flags; - uint32_t hue_adj; - uint32_t sat_adj; - uint32_t val_adj; - uint32_t cont_adj; -}; - -struct mdp_igc_lut_data { - uint32_t block; - uint32_t len, ops; - uint32_t *c0_c1_data; - uint32_t *c2_data; -}; - struct mdp_overlay_pp_params { uint32_t config_ops; struct mdp_csc_cfg csc_cfg; struct mdp_qseed_cfg qseed_cfg[2]; - struct mdp_pa_cfg pa_cfg; - struct mdp_igc_lut_data igc_cfg; - struct mdp_sharp_cfg sharp_cfg; }; struct mdp_overlay { @@ -464,6 +433,13 @@ enum { mdp_lut_max, }; +struct mdp_igc_lut_data { + uint32_t block; + uint32_t len, ops; + uint32_t *c0_c1_data; + uint32_t *c2_data; +}; + struct mdp_ar_gc_lut_data { uint32_t x_start; uint32_t slope; @@ -509,11 +485,6 @@ struct mdp_calib_config_data { uint32_t data; }; -struct mdp_pa_cfg_data { - uint32_t block; - struct mdp_pa_cfg pa_data; -}; - enum { mdp_op_pcc_cfg, mdp_op_csc_cfg, @@ -521,7 +492,6 @@ enum { mdp_op_qseed_cfg, mdp_bl_scale_cfg, mdp_op_calib_cfg, - mdp_op_pa_cfg, mdp_op_max, }; @@ -534,7 +504,6 @@ struct msmfb_mdp_pp { struct mdp_qseed_cfg_data qseed_cfg_data; struct mdp_bl_scale_data bl_scale_data; struct mdp_calib_config_data calib_cfg; - struct mdp_pa_cfg_data pa_cfg_data; } data; }; From 4cbdaff0532f62b174dbc88f9168f59cb0370f8b Mon Sep 17 00:00:00 2001 From: detule Date: Thu, 28 Feb 2013 15:27:30 -0500 Subject: [PATCH 2331/2357] M2: Revert "msm: vidc: Add a check for separate metadata buffers" Userland lags with metadata commits. This reverts commit 3883780c95fb50a2c1c24c748a4411c55f409f9c. --- drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c | 4 +- .../msm/vidc/1080p/ddl/vcd_ddl_metadata.c | 5 +- .../msm/vidc/1080p/ddl/vcd_ddl_metadata.h | 3 +- .../msm/vidc/1080p/ddl/vcd_ddl_properties.c | 7 --- .../1080p/resource_tracker/vcd_res_tracker.c | 9 +--- .../1080p/resource_tracker/vcd_res_tracker.h | 3 +- .../resource_tracker/vcd_res_tracker_api.h | 3 +- drivers/video/msm/vidc/common/dec/vdec.c | 47 ++----------------- include/linux/msm_vidc_dec.h | 3 -- include/media/msm/vcd_property.h | 2 - 10 files changed, 9 insertions(+), 77 deletions(-) diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c index 89186f626c2..8764ec443cd 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c @@ -204,9 +204,7 @@ u32 ddl_open(u32 **ddl_handle, u32 decoding) ddl->client_state = DDL_CLIENT_OPEN; ddl->codec_data.hdr.decoding = decoding; ddl->decoding = decoding; - if (!res_trk_check_for_sec_session() || - res_trk_get_enable_sec_metadata()) - ddl_set_default_meta_data_hdr(ddl); + ddl_set_default_meta_data_hdr(ddl); ddl_set_initial_default_values(ddl); *ddl_handle = (u32 *) ddl; } else { diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c index 7449a4aad75..e17dd009f03 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c @@ -14,7 +14,6 @@ #include "vcd_ddl.h" #include "vcd_ddl_shared_mem.h" #include "vcd_ddl_metadata.h" -#include "vcd_res_tracker_api.h" static u32 *ddl_metadata_hdr_entry(struct ddl_client_context *ddl, u32 meta_data) @@ -189,8 +188,6 @@ void ddl_set_default_decoder_metadata_buffer_size(struct ddl_decoder_data u32 flag = decoder->meta_data_enable_flag; u32 suffix = 0, size = 0; if (!flag) { - output_buf_req->meta_buffer_size = - DDL_SECURE_METADATA_DEFAULT_SIZE; decoder->suffix = 0; return; } @@ -496,7 +493,7 @@ void ddl_vidc_decode_set_metadata_output(struct ddl_decoder_data *decoder) align_physical_addr, decoder->dp_buf. dec_pic_buffers[loopc].vcd_frm.physical)); } - } else if (res_trk_get_enable_sec_metadata()) { + } else { *buffer++ = decoder->actual_output_buf_req.meta_buffer_size; for (loopc = 0; loopc < dpb; ++loopc) { *buffer++ = DDL_ADDR_OFFSET(ddl_context->dram_base_a, diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h index 8cee92f700d..e03a9b7d5e0 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,7 +19,6 @@ #define DDL_METADATA_EXTRAPAD_SIZE 256 #define DDL_METADATA_HDR_SIZE 20 #define DDL_METADATA_EXTRADATANONE_SIZE 24 -#define DDL_SECURE_METADATA_DEFAULT_SIZE 8192 #define DDL_METADATA_ALIGNSIZE(x) ((x) = (((x) + 0x7) & ~0x7)) #define DDL_METADATA_MANDATORY \ (VCD_METADATA_DATANONE | VCD_METADATA_QCOMFILLER) diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c index aef9ff5bfa9..b741d1ecd93 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c @@ -1314,13 +1314,6 @@ static u32 ddl_get_dec_property(struct ddl_client_context *ddl, vcd_status = VCD_S_SUCCESS; } break; - case VCD_I_ENABLE_SEC_METADATA: - if (sizeof(u32) == property_hdr->sz) { - *(u32 *)property_value = - res_trk_get_enable_sec_metadata(); - vcd_status = VCD_S_SUCCESS; - } - break; case VCD_I_DISABLE_DMX: if (sizeof(u32) == property_hdr->sz) { *(u32 *)property_value = decoder->dmx_disable; diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c index ff0de8074b5..453711c6292 100644 --- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c +++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -739,9 +739,6 @@ void res_trk_init(struct device *device, u32 irq) resource_context.vidc_platform_data->disable_dmx; resource_context.disable_fullhd = resource_context.vidc_platform_data->disable_fullhd; - resource_context.enable_sec_metadata = - resource_context.vidc_platform_data-> - enable_sec_metadata; #ifdef CONFIG_MSM_BUS_SCALING resource_context.vidc_bus_client_pdata = resource_context.vidc_platform_data-> @@ -900,10 +897,6 @@ u32 res_trk_get_disable_fullhd(void) { return resource_context.disable_fullhd; } -u32 res_trk_get_enable_sec_metadata(void) -{ - return resource_context.enable_sec_metadata; -} int res_trk_enable_iommu_clocks(void) { diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h index 2fa82acd533..a98023036ab 100644 --- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h +++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -53,7 +53,6 @@ struct res_trk_context { struct ion_client *res_ion_client; u32 disable_dmx; u32 disable_fullhd; - u32 enable_sec_metadata; enum ddl_mem_area res_mem_type; u32 mmu_clks_on; u32 secure_session; diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h index 15ffa96f935..ee876f48771 100644 --- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h +++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -34,7 +34,6 @@ unsigned int res_trk_get_ion_flags(void); u32 res_trk_get_enable_ion(void); u32 res_trk_is_cp_enabled(void); u32 res_trk_get_disable_fullhd(void); -u32 res_trk_get_enable_sec_metadata(void); struct ion_client *res_trk_get_ion_client(void); u32 res_trk_get_disable_dmx(void); u32 res_trk_get_min_dpb_count(void); diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c index a9785934ad3..3efc4d302b7 100644 --- a/drivers/video/msm/vidc/common/dec/vdec.c +++ b/drivers/video/msm/vidc/common/dec/vdec.c @@ -273,8 +273,7 @@ static void vid_dec_output_frame_done(struct video_client_ctx *client_ctx, (vcd_frame_data->flags & VCD_FRAME_FLAG_EOS)) { if (res_trk_check_for_sec_session() && - res_trk_get_enable_sec_metadata() && - event == VCD_EVT_RESP_OUTPUT_DONE) { + event == VCD_EVT_RESP_OUTPUT_DONE) { DBG("Buffer Index = %d", buffer_index); if (buffer_index != -1) { if (client_ctx->meta_addr_table[buffer_index]. @@ -736,22 +735,6 @@ static u32 vid_dec_get_progressive_only(struct video_client_ctx *client_ctx, return true; } -static u32 vid_dec_get_enable_secure_metadata(struct video_client_ctx - *client_ctx, u32 *enable_sec_metadata) -{ - - struct vcd_property_hdr vcd_property_hdr; - if (!client_ctx || !enable_sec_metadata) - return false; - vcd_property_hdr.prop_id = VCD_I_ENABLE_SEC_METADATA; - vcd_property_hdr.sz = sizeof(u32); - if (vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr, - enable_sec_metadata)) - return false; - else - return true; -} - static u32 vid_dec_get_disable_dmx_support(struct video_client_ctx *client_ctx, u32 *disable_dmx) { @@ -2259,23 +2242,6 @@ static long vid_dec_ioctl(struct file *file, break; } - case VDEC_IOCTL_GET_ENABLE_SEC_METADATA: - { - u32 enable_sec_metadata; - DBG("VDEC_IOCTL_GET_ENABLE_SEC_METADATA\n"); - if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg))) - return -EFAULT; - result = vid_dec_get_enable_secure_metadata(client_ctx, - &enable_sec_metadata); - if (result) { - if (copy_to_user(vdec_msg.out, &enable_sec_metadata, - sizeof(u32))) - return -EFAULT; - } else - return -EIO; - break; - } - case VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT: { u32 disable_dmx; @@ -2368,11 +2334,7 @@ static long vid_dec_ioctl(struct file *file, if (copy_from_user(&meta_buffers, vdec_msg.in, sizeof(meta_buffers))) return -EFAULT; - if (res_trk_get_enable_sec_metadata()) - result = - vid_dec_set_meta_buffers(client_ctx, &meta_buffers); - else - ERR("ERROR : Meta data is not enabled.\n"); + result = vid_dec_set_meta_buffers(client_ctx, &meta_buffers); if (!result) return -EIO; @@ -2381,10 +2343,7 @@ static long vid_dec_ioctl(struct file *file, case VDEC_IOCTL_FREE_META_BUFFERS: { DBG("VDEC_IOCTL_FREE_META_BUFFERS\n"); - if (res_trk_get_enable_sec_metadata()) - result = vid_dec_free_meta_buffers(client_ctx); - else - ERR("ERROR : Can't free. Meta data is not enabled.\n"); + result = vid_dec_free_meta_buffers(client_ctx); if (!result) return -EIO; break; diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h index cd363c5773b..cc864f04d2f 100644 --- a/include/linux/msm_vidc_dec.h +++ b/include/linux/msm_vidc_dec.h @@ -220,9 +220,6 @@ struct vdec_ioctl_msg { #define VDEC_IOCTL_FREE_META_BUFFERS \ _IO(VDEC_IOCTL_MAGIC, 40) -#define VDEC_IOCTL_GET_ENABLE_SEC_METADATA \ - _IOR(VDEC_IOCTL_MAGIC, 41, struct vdec_ioctl_msg) - enum vdec_picture { PICTURE_TYPE_I, PICTURE_TYPE_P, diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h index 5b832143f8b..ebdfb414b71 100644 --- a/include/media/msm/vcd_property.h +++ b/include/media/msm/vcd_property.h @@ -59,8 +59,6 @@ #define VCD_I_ENABLE_VUI_TIMING_INFO (VCD_START_BASE + 0x2B) #define VCD_I_SET_EXT_METABUFFER (VCD_START_BASE + 0x2C) #define VCD_I_FREE_EXT_METABUFFER (VCD_START_BASE + 0x2D) -#define VCD_I_ENABLE_SEC_METADATA (VCD_START_BASE + 0x2E) - #define VCD_START_REQ (VCD_START_BASE + 0x1000) #define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1) From 558aab62d0a6f81f92fd4a4a523760bede4a885f Mon Sep 17 00:00:00 2001 From: detule Date: Thu, 28 Feb 2013 15:28:18 -0500 Subject: [PATCH 2332/2357] M2: Revert "msm: vidc: Separate meta buffers support in secure mode" Userland lags with metadata commits. This reverts commit eb8179b17b0d31ab9ab4605bf4842acb30058102. Conflicts: drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c --- drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c | 8 +- drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h | 3 +- .../video/msm/vidc/1080p/ddl/vcd_ddl_helper.c | 4 +- .../msm/vidc/1080p/ddl/vcd_ddl_metadata.c | 31 +- .../msm/vidc/1080p/ddl/vcd_ddl_properties.c | 64 +-- drivers/video/msm/vidc/common/dec/vdec.c | 373 +----------------- include/linux/msm_vidc_dec.h | 22 -- include/media/msm/vcd_api.h | 3 +- include/media/msm/vcd_property.h | 21 +- include/media/msm/vidc_init.h | 13 +- 10 files changed, 19 insertions(+), 523 deletions(-) diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c index 8764ec443cd..bd870035254 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c @@ -88,13 +88,7 @@ u32 ddl_device_init(struct ddl_init_config *ddl_init_config, ddl_context->dram_base_a.align_virtual_addr; } if (!status) { - if (res_trk_get_enable_sec_metadata()) { - ddl_context->metadata_shared_input.mem_type = - DDL_CMD_MEM; - } else { - ddl_context->metadata_shared_input.mem_type = - DDL_FW_MEM; - } + ddl_context->metadata_shared_input.mem_type = DDL_FW_MEM; ptr = ddl_pmem_alloc(&ddl_context->metadata_shared_input, DDL_METADATA_TOTAL_INPUTBUFSIZE, DDL_LINEAR_BUFFER_ALIGN_BYTES); diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h index b47d9ac7936..7a1d5216746 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -188,7 +188,6 @@ struct ddl_dec_buffers{ struct ddl_buf_addr h264_nb_ip; struct ddl_buf_addr context; struct ddl_buf_addr extnuserdata; - struct ddl_buf_addr meta_hdr[DDL_MAX_BUFFER_COUNT]; }; struct ddl_enc_buffer_size{ u32 sz_cur_y; diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c index fda795c1a9a..33203702ebe 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -782,7 +782,7 @@ u32 ddl_allocate_dec_hw_buffers(struct ddl_client_context *ddl) } } if (buf_size.sz_extnuserdata > 0) { - dec_bufs->extnuserdata.mem_type = DDL_CMD_MEM; + dec_bufs->extnuserdata.mem_type = DDL_FW_MEM; ptr = ddl_pmem_alloc(&dec_bufs->extnuserdata, buf_size.sz_extnuserdata, DDL_KILO_BYTE(2)); if (!ptr) diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c index e17dd009f03..f70c47cd20e 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010, 2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -158,8 +158,7 @@ static u32 ddl_supported_metadata_flag(struct ddl_client_context *ddl) ddl->codec_data.decoder.codec.codec; flag |= (VCD_METADATA_CONCEALMB | VCD_METADATA_PASSTHROUGH | - VCD_METADATA_QPARRAY | - VCD_METADATA_SEPARATE_BUF); + VCD_METADATA_QPARRAY); if (codec == VCD_CODEC_H264) flag |= (VCD_METADATA_SEI | VCD_METADATA_VUI); else if (codec == VCD_CODEC_VC1 || @@ -250,9 +249,6 @@ void ddl_set_default_decoder_metadata_buffer_size(struct ddl_decoder_data DDL_METADATA_ALIGNSIZE(suffix); decoder->suffix = suffix; output_buf_req->sz += suffix; - output_buf_req->meta_buffer_size = suffix; - output_buf_req->meta_buffer_size = - (output_buf_req->meta_buffer_size + 8191) & (~8191); decoder->meta_data_offset = 0; DDL_MSG_LOW("metadata output buf size : %d", suffix); } @@ -468,14 +464,13 @@ u32 ddl_vidc_encode_set_metadata_output_buf(struct ddl_client_context *ddl) void ddl_vidc_decode_set_metadata_output(struct ddl_decoder_data *decoder) { struct ddl_context *ddl_context; - u32 loopc, yuv_size, dpb; + u32 loopc, yuv_size; u32 *buffer; - struct ddl_dec_buffers *dec_buffers = &decoder->hw_bufs; + if (!decoder->meta_data_enable_flag) { decoder->meta_data_offset = 0; return; } - dpb = decoder->dp_buf.no_of_dec_pic_buf; ddl_context = ddl_get_context(); yuv_size = ddl_get_yuv_buffer_size(&decoder->client_frame_size, &decoder->buf_format, !decoder->progressive_only, @@ -483,22 +478,15 @@ void ddl_vidc_decode_set_metadata_output(struct ddl_decoder_data *decoder) decoder->meta_data_offset = DDL_ALIGN_SIZE(yuv_size, DDL_LINEAR_BUF_ALIGN_GUARD_BYTES, DDL_LINEAR_BUF_ALIGN_MASK); buffer = (u32 *) decoder->meta_data_input.align_virtual_addr; + *buffer++ = decoder->suffix; DDL_MSG_LOW("Metadata offset & size : %d/%d", decoder->meta_data_offset, decoder->suffix); - if (!(decoder->meta_data_enable_flag & VCD_METADATA_SEPARATE_BUF)) { - *buffer++ = decoder->suffix; - for (loopc = 0; loopc < dpb; ++loopc) { - *buffer++ = (u32)(decoder->meta_data_offset + (u8 *) + for (loopc = 0; loopc < decoder->dp_buf.no_of_dec_pic_buf; + ++loopc) { + *buffer++ = (u32)(decoder->meta_data_offset + (u8 *) DDL_OFFSET(ddl_context->dram_base_a. align_physical_addr, decoder->dp_buf. dec_pic_buffers[loopc].vcd_frm.physical)); - } - } else { - *buffer++ = decoder->actual_output_buf_req.meta_buffer_size; - for (loopc = 0; loopc < dpb; ++loopc) { - *buffer++ = DDL_ADDR_OFFSET(ddl_context->dram_base_a, - dec_buffers->meta_hdr[loopc]); - } } } @@ -557,8 +545,7 @@ void ddl_process_decoder_metadata(struct ddl_client_context *ddl) DDL_MSG_LOW("data_len/metadata_offset : %d/%d", output_frame->data_len, decoder->meta_data_offset); output_frame->flags |= VCD_FRAME_FLAG_EXTRADATA; - if (!(decoder->meta_data_enable_flag & VCD_METADATA_SEPARATE_BUF) - && (output_frame->data_len != decoder->meta_data_offset)) { + if (output_frame->data_len != decoder->meta_data_offset) { qfiller = (u32 *)((u32)((output_frame->data_len + output_frame->offset + (u8 *) output_frame->virtual) + 3) & ~3); diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c index b741d1ecd93..86d88291c88 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -319,61 +319,6 @@ static u32 ddl_set_dec_property(struct ddl_client_context *ddl, } } break; - case VCD_I_SET_EXT_METABUFFER: - { - int index, buffer_size; - u8 *phys_addr; - u8 *virt_addr; - struct vcd_property_meta_buffer *meta_buffer = - (struct vcd_property_meta_buffer *) property_value; - DDL_MSG_LOW("Entered VCD_I_SET_EXT_METABUFFER Virt: %p,"\ - "Phys %p, fd: %d size: %d count: %d", - meta_buffer->kernel_virtual_addr, - meta_buffer->physical_addr, - meta_buffer->pmem_fd, - meta_buffer->size, meta_buffer->count); - if ((property_hdr->sz == sizeof(struct - vcd_property_meta_buffer)) && - (DDLCLIENT_STATE_IS(ddl, - DDL_CLIENT_WAIT_FOR_INITCODEC) || - DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_DPB) || - DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN))) { - phys_addr = meta_buffer->dev_addr; - virt_addr = meta_buffer->kernel_virtual_addr; - buffer_size = meta_buffer->size/meta_buffer->count; - - for (index = 0; index < meta_buffer->count; index++) { - ddl->codec_data.decoder.hw_bufs. - meta_hdr[index].align_physical_addr - = phys_addr; - ddl->codec_data.decoder.hw_bufs. - meta_hdr[index].align_virtual_addr - = virt_addr; - ddl->codec_data.decoder.hw_bufs. - meta_hdr[index].buffer_size - = buffer_size; - ddl->codec_data.decoder.hw_bufs. - meta_hdr[index].physical_base_addr - = phys_addr; - ddl->codec_data.decoder.hw_bufs. - meta_hdr[index].virtual_base_addr - = virt_addr; - - DDL_MSG_LOW("Meta Buffer: "\ - "Assigned %d buffer for " - "virt: %p, phys %p for " - "meta_buffers " - "of size: %d\n", - index, virt_addr, - phys_addr, buffer_size); - - phys_addr += buffer_size; - virt_addr += buffer_size; - } - vcd_status = VCD_S_SUCCESS; - } - } - break; case VCD_I_H264_MV_BUFFER: { int index, buffer_size; @@ -434,13 +379,6 @@ static u32 ddl_set_dec_property(struct ddl_client_context *ddl, vcd_status = VCD_S_SUCCESS; } break; - case VCD_I_FREE_EXT_METABUFFER: - { - memset(&decoder->hw_bufs.meta_hdr, 0, sizeof(struct - ddl_buf_addr) * DDL_MAX_BUFFER_COUNT); - vcd_status = VCD_S_SUCCESS; - } - break; case VCD_I_OUTPUT_ORDER: { if (sizeof(u32) == property_hdr->sz && diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c index 3efc4d302b7..c70dc31b4e3 100644 --- a/drivers/video/msm/vidc/common/dec/vdec.c +++ b/drivers/video/msm/vidc/common/dec/vdec.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -271,38 +271,6 @@ static void vid_dec_output_frame_done(struct video_client_ctx *client_ctx, &phy_addr, &pmem_fd, &file, &buffer_index) || (vcd_frame_data->flags & VCD_FRAME_FLAG_EOS)) { - - if (res_trk_check_for_sec_session() && - event == VCD_EVT_RESP_OUTPUT_DONE) { - DBG("Buffer Index = %d", buffer_index); - if (buffer_index != -1) { - if (client_ctx->meta_addr_table[buffer_index]. - kernel_vir_addr_iommu && - client_ctx-> - meta_addr_table[buffer_index]. - kernel_vir_addr) { - - memcpy(client_ctx-> - meta_addr_table[buffer_index]. - kernel_vir_addr_iommu, - client_ctx-> - meta_addr_table[buffer_index]. - kernel_vir_addr, - client_ctx->meta_buf_size); - DBG("Copying Meta Buffer from "\ - "secure memory" - "kernel_virt_iommu = %p " - "kernel_virt = %p", - client_ctx-> - meta_addr_table[buffer_index]. - kernel_vir_addr_iommu, - client_ctx-> - meta_addr_table[buffer_index]. - kernel_vir_addr); - } - } - } - /* Buffer address in user space */ vdec_msg->vdec_msg_info.msgdata.output_frame.bufferaddr = (u8 *) user_vaddr; @@ -870,263 +838,7 @@ static u32 vid_dec_set_idr_only_decoding(struct video_client_ctx *client_ctx) return false; return true; } -static u32 vid_dec_set_meta_buffers(struct video_client_ctx *client_ctx, - struct vdec_meta_buffers *meta_buffers) -{ - struct vcd_property_hdr vcd_property_hdr; - struct vcd_property_meta_buffer *vcd_meta_buffer = NULL; - struct msm_mapped_buffer *mapped_buffer = NULL; - struct msm_mapped_buffer *mapped_buffer_iommu = NULL; - u32 vcd_status = VCD_ERR_FAIL; - u32 len = 0, flags = 0, len_iommu = 0, flags_iommu = 0, buf_size = 0; - struct file *file, *file_iommu; - int rc = 0; - unsigned long ionflag = 0, ionflag_iommu = 0; - unsigned long buffer_size = 0, buffer_size_iommu = 0; - unsigned long iova = 0, iova_iommu = 0; - int index = -1, num_buffers = 0; - u8 *ker_vir_addr = NULL, *ker_vir_addr_iommu = NULL; - - if (!client_ctx || !meta_buffers) - return false; - - vcd_property_hdr.prop_id = VCD_I_SET_EXT_METABUFFER; - vcd_property_hdr.sz = sizeof(struct vcd_property_meta_buffer); - vcd_meta_buffer = &client_ctx->vcd_meta_buffer; - - memset(&client_ctx->vcd_meta_buffer, 0, - sizeof(struct vcd_property_meta_buffer)); - vcd_meta_buffer->size = meta_buffers->size; - vcd_meta_buffer->count = meta_buffers->count; - vcd_meta_buffer->pmem_fd = meta_buffers->pmem_fd; - vcd_meta_buffer->offset = meta_buffers->offset; - vcd_meta_buffer->pmem_fd_iommu = meta_buffers->pmem_fd_iommu; - - if (!vcd_get_ion_status()) { - if (get_pmem_file(vcd_meta_buffer->pmem_fd, - (unsigned long *) (&(vcd_meta_buffer-> - physical_addr)), - (unsigned long *) (&vcd_meta_buffer-> - kernel_virtual_addr), - (unsigned long *) (&len), &file)) { - ERR("%s(): get_pmem_file failed\n", __func__); - return false; - } - put_pmem_file(file); - flags = MSM_SUBSYSTEM_MAP_IOVA; - mapped_buffer = msm_subsystem_map_buffer( - (unsigned long)vcd_meta_buffer->physical_addr, - len, flags, vidc_mmu_subsystem, - sizeof(vidc_mmu_subsystem)/ - sizeof(unsigned int)); - if (IS_ERR(mapped_buffer)) { - pr_err("buffer map failed"); - return false; - } - vcd_meta_buffer->client_data = (void *) mapped_buffer; - vcd_meta_buffer->dev_addr = - (u8 *)mapped_buffer->iova[0]; - - if (get_pmem_file(vcd_meta_buffer->pmem_fd_iommu, - (unsigned long *) (&(vcd_meta_buffer-> - physical_addr_iommu)), - (unsigned long *) (&vcd_meta_buffer-> - kernel_virt_addr_iommu), - (unsigned long *) (&len_iommu), &file_iommu)) { - ERR("%s(): get_pmem_file failed\n", __func__); - return false; - } - put_pmem_file(file_iommu); - flags_iommu = MSM_SUBSYSTEM_MAP_IOVA; - mapped_buffer_iommu = msm_subsystem_map_buffer( - (unsigned long)vcd_meta_buffer->physical_addr_iommu, - len_iommu, flags_iommu, vidc_mmu_subsystem, - sizeof(vidc_mmu_subsystem)/ - sizeof(unsigned int)); - if (IS_ERR(mapped_buffer_iommu)) { - pr_err("buffer map failed"); - return false; - } - vcd_meta_buffer->client_data_iommu = - (void *) mapped_buffer_iommu; - vcd_meta_buffer->dev_addr_iommu = - (u8 *)mapped_buffer_iommu->iova[0]; - } else { - client_ctx->meta_buffer_ion_handle = ion_import_dma_buf( - client_ctx->user_ion_client, - vcd_meta_buffer->pmem_fd); - if (IS_ERR_OR_NULL(client_ctx->meta_buffer_ion_handle)) { - ERR("%s(): get_ION_handle failed\n", __func__); - goto import_ion_error; - } - rc = ion_handle_get_flags(client_ctx->user_ion_client, - client_ctx->meta_buffer_ion_handle, - &ionflag); - if (rc) { - ERR("%s():get_ION_flags fail\n", - __func__); - goto import_ion_error; - } - vcd_meta_buffer->kernel_virtual_addr = - (u8 *) ion_map_kernel( - client_ctx->user_ion_client, - client_ctx->meta_buffer_ion_handle); - if (!vcd_meta_buffer->kernel_virtual_addr) { - ERR("%s(): get_ION_kernel virtual addr failed\n", - __func__); - goto import_ion_error; - } - if (res_trk_check_for_sec_session() || - (res_trk_get_core_type() == (u32)VCD_CORE_720P)) { - rc = ion_phys(client_ctx->user_ion_client, - client_ctx->meta_buffer_ion_handle, - (unsigned long *) (&(vcd_meta_buffer-> - physical_addr)), &len); - if (rc) { - ERR("%s():get_ION_kernel physical addr fail\n", - __func__); - goto ion_map_error; - } - vcd_meta_buffer->client_data = NULL; - vcd_meta_buffer->dev_addr = (u8 *) - vcd_meta_buffer->physical_addr; - } else { - rc = ion_map_iommu(client_ctx->user_ion_client, - client_ctx->meta_buffer_ion_handle, - VIDEO_DOMAIN, VIDEO_MAIN_POOL, - SZ_4K, 0, (unsigned long *)&iova, - (unsigned long *)&buffer_size, - 0, 0); - if (rc || !iova) { - ERR("%s():get_ION_kernel physical addr fail,"\ - " rc = %d iova = 0x%lx\n", - __func__, rc, iova); - goto ion_map_error; - } - vcd_meta_buffer->physical_addr = (u8 *) iova; - vcd_meta_buffer->client_data = NULL; - vcd_meta_buffer->dev_addr = (u8 *) iova; - } - - client_ctx->meta_buffer_iommu_ion_handle = ion_import_dma_buf( - client_ctx->user_ion_client, - vcd_meta_buffer->pmem_fd_iommu); - if (IS_ERR_OR_NULL(client_ctx->meta_buffer_iommu_ion_handle)) { - ERR("%s(): get_ION_handle failed\n", __func__); - goto import_ion_error; - } - rc = ion_handle_get_flags(client_ctx->user_ion_client, - client_ctx-> - meta_buffer_iommu_ion_handle, - &ionflag_iommu); - if (rc) { - ERR("%s():get_ION_flags fail\n", - __func__); - goto import_ion_error; - } - vcd_meta_buffer->kernel_virt_addr_iommu = - (u8 *) ion_map_kernel( - client_ctx->user_ion_client, - client_ctx->meta_buffer_iommu_ion_handle); - if (!vcd_meta_buffer->kernel_virt_addr_iommu) { - ERR("%s(): get_ION_kernel virtual addr failed\n", - __func__); - goto import_ion_error; - } - if (res_trk_get_core_type() == (u32)VCD_CORE_720P) { - rc = ion_phys(client_ctx->user_ion_client, - client_ctx->meta_buffer_iommu_ion_handle, - (unsigned long *) (&(vcd_meta_buffer-> - physical_addr_iommu)), &len_iommu); - if (rc) { - ERR("%s():get_ION_kernel physical addr fail\n", - __func__); - goto ion_map_error_iommu; - } - vcd_meta_buffer->client_data_iommu = NULL; - vcd_meta_buffer->dev_addr_iommu = (u8 *) - vcd_meta_buffer->physical_addr_iommu; - } else { - rc = ion_map_iommu(client_ctx->user_ion_client, - client_ctx->meta_buffer_iommu_ion_handle, - VIDEO_DOMAIN, VIDEO_MAIN_POOL, - SZ_4K, 0, (unsigned long *)&iova_iommu, - (unsigned long *)&buffer_size_iommu, - 0, 0); - if (rc || !iova_iommu) { - ERR("%s():get_ION_kernel physical addr fail, "\ - "rc = %d iova = 0x%lx\n", - __func__, rc, iova); - goto ion_map_error_iommu; - } - vcd_meta_buffer->physical_addr_iommu = - (u8 *) iova_iommu; - vcd_meta_buffer->client_data_iommu = NULL; - vcd_meta_buffer->dev_addr_iommu = (u8 *) iova_iommu; - } - } - - /*fill the meta addr table*/ - num_buffers = vcd_meta_buffer->count; - buf_size = vcd_meta_buffer->size/num_buffers; - ker_vir_addr = vcd_meta_buffer->kernel_virtual_addr; - ker_vir_addr_iommu = vcd_meta_buffer->kernel_virt_addr_iommu; - client_ctx->meta_buf_size = buf_size; - for (index = 0; index < num_buffers; index++) { - client_ctx->meta_addr_table[index].kernel_vir_addr = - ker_vir_addr; - client_ctx->meta_addr_table[index].kernel_vir_addr_iommu = - ker_vir_addr_iommu; - DBG("[%d] kernel_virtual = %p kernel_vir_iommu = %p", - index, ker_vir_addr, ker_vir_addr_iommu); - ker_vir_addr += buf_size; - ker_vir_addr_iommu += buf_size; - } - - DBG("Meta Buffer: Virt: %p, Phys %p, fd: %d", - vcd_meta_buffer->kernel_virtual_addr, - vcd_meta_buffer->physical_addr, - vcd_meta_buffer->pmem_fd); - DBG("IOMMU Meta Buffer: Virt: %p, Phys %p, fd: %d", - vcd_meta_buffer->kernel_virt_addr_iommu, - vcd_meta_buffer->physical_addr_iommu, - vcd_meta_buffer->pmem_fd_iommu); - DBG("Meta_buffer: Dev addr %p", vcd_meta_buffer->dev_addr); - DBG("IOMMU Meta_buffer: Dev addr %p", - vcd_meta_buffer->dev_addr_iommu); - vcd_status = vcd_set_property(client_ctx->vcd_handle, - &vcd_property_hdr, - vcd_meta_buffer); - if (vcd_status) - return false; - else - return true; -ion_map_error_iommu: - if (vcd_meta_buffer->kernel_virt_addr_iommu) { - ion_unmap_kernel(client_ctx->user_ion_client, - client_ctx->meta_buffer_iommu_ion_handle); - vcd_meta_buffer->kernel_virt_addr_iommu = NULL; - } - if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_iommu_ion_handle)) { - ion_free(client_ctx->user_ion_client, - client_ctx->meta_buffer_iommu_ion_handle); - client_ctx->meta_buffer_iommu_ion_handle = NULL; - } -ion_map_error: - if (vcd_meta_buffer->kernel_virtual_addr) { - ion_unmap_kernel(client_ctx->user_ion_client, - client_ctx->meta_buffer_ion_handle); - vcd_meta_buffer->kernel_virtual_addr = NULL; - } - if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_ion_handle)) { - ion_free(client_ctx->user_ion_client, - client_ctx->meta_buffer_ion_handle); - client_ctx->meta_buffer_ion_handle = NULL; - } -import_ion_error: - return false; -} static u32 vid_dec_set_h264_mv_buffers(struct video_client_ctx *client_ctx, struct vdec_h264_mv *mv_data) { @@ -1306,65 +1018,6 @@ static u32 vid_dec_get_h264_mv_buffer_size(struct video_client_ctx *client_ctx, return true; } -static u32 vid_dec_free_meta_buffers(struct video_client_ctx *client_ctx) -{ - struct vcd_property_hdr vcd_property_hdr; - struct vcd_property_buffer_size meta_buffer_size; - u32 vcd_status = VCD_ERR_FAIL; - - if (!client_ctx) - return false; - if (client_ctx->vcd_meta_buffer.client_data) - msm_subsystem_unmap_buffer((struct msm_mapped_buffer *) - client_ctx->vcd_meta_buffer.client_data); - - if (client_ctx->vcd_meta_buffer.client_data_iommu) - msm_subsystem_unmap_buffer((struct msm_mapped_buffer *) - client_ctx->vcd_meta_buffer.client_data_iommu); - - vcd_property_hdr.prop_id = VCD_I_FREE_EXT_METABUFFER; - vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size); - - vcd_status = vcd_set_property(client_ctx->vcd_handle, - &vcd_property_hdr, &meta_buffer_size); - - if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_ion_handle)) { - ion_unmap_kernel(client_ctx->user_ion_client, - client_ctx->meta_buffer_ion_handle); - if (!res_trk_check_for_sec_session() && - (res_trk_get_core_type() != (u32)VCD_CORE_720P)) { - ion_unmap_iommu(client_ctx->user_ion_client, - client_ctx->meta_buffer_ion_handle, - VIDEO_DOMAIN, - VIDEO_MAIN_POOL); - } - ion_free(client_ctx->user_ion_client, - client_ctx->meta_buffer_ion_handle); - client_ctx->meta_buffer_ion_handle = NULL; - } - - if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_iommu_ion_handle)) { - ion_unmap_kernel(client_ctx->user_ion_client, - client_ctx->meta_buffer_iommu_ion_handle); - if (res_trk_check_for_sec_session() && - (res_trk_get_core_type() != (u32)VCD_CORE_720P)) { - ion_unmap_iommu(client_ctx->user_ion_client, - client_ctx->meta_buffer_iommu_ion_handle, - VIDEO_DOMAIN, - VIDEO_MAIN_POOL); - } - ion_free(client_ctx->user_ion_client, - client_ctx->meta_buffer_iommu_ion_handle); - client_ctx->meta_buffer_iommu_ion_handle = NULL; - } - - if (vcd_status) - return false; - else - return true; -} - - static u32 vid_dec_free_h264_mv_buffers(struct video_client_ctx *client_ctx) { struct vcd_property_hdr vcd_property_hdr; @@ -1432,7 +1085,6 @@ static u32 vid_dec_get_buffer_req(struct video_client_ctx *client_ctx, vdec_buf_req->buffer_size = vcd_buf_req.sz; vdec_buf_req->alignment = vcd_buf_req.align; vdec_buf_req->buf_poolid = vcd_buf_req.buf_pool_id; - vdec_buf_req->meta_buffer_size = vcd_buf_req.meta_buffer_size; return true; } @@ -2325,29 +1977,6 @@ static long vid_dec_ioctl(struct file *file, return -EIO; break; } - case VDEC_IOCTL_SET_META_BUFFERS: - { - struct vdec_meta_buffers meta_buffers; - DBG("VDEC_IOCTL_SET_META_BUFFERS\n"); - if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg))) - return -EFAULT; - if (copy_from_user(&meta_buffers, vdec_msg.in, - sizeof(meta_buffers))) - return -EFAULT; - result = vid_dec_set_meta_buffers(client_ctx, &meta_buffers); - - if (!result) - return -EIO; - break; - } - case VDEC_IOCTL_FREE_META_BUFFERS: - { - DBG("VDEC_IOCTL_FREE_META_BUFFERS\n"); - result = vid_dec_free_meta_buffers(client_ctx); - if (!result) - return -EIO; - break; - } case VDEC_IOCTL_SET_H264_MV_BUFFER: { struct vdec_h264_mv mv_data; diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h index cc864f04d2f..3c99562a6e3 100644 --- a/include/linux/msm_vidc_dec.h +++ b/include/linux/msm_vidc_dec.h @@ -78,7 +78,6 @@ #define VDEC_EXTRADATA_EXT_DATA 0x0800 #define VDEC_EXTRADATA_USER_DATA 0x1000 -#define VDEC_EXTRADATA_EXT_BUFFER 0x2000 #define VDEC_CMDBASE 0x800 #define VDEC_CMD_SET_INTF_VERSION (VDEC_CMDBASE) @@ -214,12 +213,6 @@ struct vdec_ioctl_msg { #define VDEC_IOCTL_SET_PERF_CLK \ _IOR(VDEC_IOCTL_MAGIC, 38, struct vdec_ioctl_msg) -#define VDEC_IOCTL_SET_META_BUFFERS \ - _IOW(VDEC_IOCTL_MAGIC, 39, struct vdec_ioctl_msg) - -#define VDEC_IOCTL_FREE_META_BUFFERS \ - _IO(VDEC_IOCTL_MAGIC, 40) - enum vdec_picture { PICTURE_TYPE_I, PICTURE_TYPE_P, @@ -243,7 +236,6 @@ struct vdec_allocatorproperty { size_t buffer_size; uint32_t alignment; uint32_t buf_poolid; - size_t meta_buffer_size; }; struct vdec_bufferpayload { @@ -534,11 +526,6 @@ struct vdec_aspectratioinfo { uint32_t par_height; }; -struct vdec_sep_metadatainfo { - void __user *metabufaddr; - uint32_t size; -}; - struct vdec_output_frameinfo { void __user *bufferaddr; size_t offset; @@ -551,7 +538,6 @@ struct vdec_output_frameinfo { struct vdec_framesize framesize; enum vdec_interlaced_format interlaced_format; struct vdec_aspectratioinfo aspect_ratio_info; - struct vdec_sep_metadatainfo metadata_info; }; union vdec_msgdata { @@ -585,12 +571,4 @@ struct vdec_mv_buff_size{ int alignment; }; -struct vdec_meta_buffers { - size_t size; - int count; - int pmem_fd; - int pmem_fd_iommu; - int offset; -}; - #endif /* end of macro _VDECDECODER_H_ */ diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h index 7472fb21a9f..7104028e1d6 100644 --- a/include/media/msm/vcd_api.h +++ b/include/media/msm/vcd_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -100,7 +100,6 @@ struct vcd_buffer_requirement { size_t sz; u32 align; u32 buf_pool_id; - size_t meta_buffer_size; }; struct vcd_init_config { diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h index ebdfb414b71..5b739c1cf60 100644 --- a/include/media/msm/vcd_property.h +++ b/include/media/msm/vcd_property.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -57,8 +57,7 @@ #define VCD_I_SET_TURBO_CLK (VCD_START_BASE + 0x29) #define VCD_I_ENABLE_DELIMITER_FLAG (VCD_START_BASE + 0x2A) #define VCD_I_ENABLE_VUI_TIMING_INFO (VCD_START_BASE + 0x2B) -#define VCD_I_SET_EXT_METABUFFER (VCD_START_BASE + 0x2C) -#define VCD_I_FREE_EXT_METABUFFER (VCD_START_BASE + 0x2D) + #define VCD_START_REQ (VCD_START_BASE + 0x1000) #define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1) @@ -119,7 +118,6 @@ enum vcd_perf_level { #define VCD_METADATA_EXT_DATA 0x0800 #define VCD_METADATA_USER_DATA 0x1000 -#define VCD_METADATA_SEPARATE_BUF 0x2000 struct vcd_property_meta_data_enable { u32 meta_data_enable_flag; @@ -387,19 +385,4 @@ struct vcd_property_vui_timing_info_enable { u32 vui_timing_info; }; -struct vcd_property_meta_buffer { - u8 *kernel_virtual_addr; - u8 *physical_addr; - u32 size; - u32 count; - int pmem_fd; - u32 offset; - u8 *dev_addr; - void *client_data; - u8 *kernel_virt_addr_iommu; - u8 *physical_addr_iommu; - int pmem_fd_iommu; - u8 *dev_addr_iommu; - void *client_data_iommu; -}; #endif diff --git a/include/media/msm/vidc_init.h b/include/media/msm/vidc_init.h index 4cbd4a605fd..f7d4e587aa7 100644 --- a/include/media/msm/vidc_init.h +++ b/include/media/msm/vidc_init.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,7 +19,6 @@ #define VIDC_MAX_NUM_CLIENTS 4 #define MAX_VIDEO_NUM_OF_BUFF 100 -#define MAX_META_BUFFERS 32 enum buffer_dir { BUFFER_TYPE_INPUT, @@ -38,11 +37,6 @@ struct buf_addr_table { void *client_data; }; -struct meta_buffer_addr_table { - u8 *kernel_vir_addr; - u8 *kernel_vir_addr_iommu; -}; - struct video_client_ctx { void *vcd_handle; u32 num_of_input_buffers; @@ -55,22 +49,17 @@ struct video_client_ctx { wait_queue_head_t msg_wait; struct completion event; struct vcd_property_h264_mv_buffer vcd_h264_mv_buffer; - struct vcd_property_meta_buffer vcd_meta_buffer; struct vcd_property_enc_recon_buffer recon_buffer[4]; u32 event_status; u32 seq_header_set; u32 stop_msg; u32 stop_called; u32 stop_sync_cb; - size_t meta_buf_size; struct ion_client *user_ion_client; struct ion_handle *seq_hdr_ion_handle; struct ion_handle *h264_mv_ion_handle; struct ion_handle *recon_buffer_ion_handle[4]; - struct ion_handle *meta_buffer_ion_handle; - struct ion_handle *meta_buffer_iommu_ion_handle; u32 dmx_disable; - struct meta_buffer_addr_table meta_addr_table[MAX_META_BUFFERS]; }; void __iomem *vidc_get_ioaddr(void); From 9c351fbf79507e39ee9c3f451f7b830bb0ca2c84 Mon Sep 17 00:00:00 2001 From: Uma Maheshwari Bhiram Date: Mon, 4 Mar 2013 11:02:36 -0800 Subject: [PATCH 2333/2357] Revert "wcnss: Add support for nv bin download at coldboot" This reverts commit 8c8778cb99adcf82d36a156761478462110d1714. Change-Id: I8802851f2a04310bbf94d3129ba1c9fc8a4987d5 Signed-off-by: Uma Maheshwari Bhiram --- drivers/net/wireless/wcnss/wcnss_riva.c | 33 +--- drivers/net/wireless/wcnss/wcnss_wlan.c | 212 +----------------------- include/linux/wcnss_wlan.h | 1 - 3 files changed, 17 insertions(+), 229 deletions(-) diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c index c4cc8e9bc56..25d9b5d3937 100644 --- a/drivers/net/wireless/wcnss/wcnss_riva.c +++ b/drivers/net/wireless/wcnss/wcnss_riva.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,9 +44,6 @@ static DEFINE_SEMAPHORE(riva_power_on_lock); #define RIVA_PMU_CFG_IRIS_XO_MODE 0x6 #define RIVA_PMU_CFG_IRIS_XO_MODE_48 (3 << 1) -#define RIVA_SPARE_OUT (msm_riva_base + 0x0b4) -#define NVBIN_DLND_BIT BIT(25) - #define VREG_NULL_CONFIG 0x0000 #define VREG_GET_REGULATOR_MASK 0x0001 #define VREG_SET_VOLTAGE_MASK 0x0002 @@ -99,16 +96,6 @@ static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on) goto fail; } - /* power on thru SSR should not set NV bit, - * during SSR, NV bin is downloaded by WLAN driver - */ - if (!wcnss_cold_boot_done()) { - pr_debug("wcnss: Indicate NV bin download\n"); - reg = readl_relaxed(RIVA_SPARE_OUT); - reg |= NVBIN_DLND_BIT; - writel_relaxed(reg, RIVA_SPARE_OUT); - } - /* Enable IRIS XO */ rc = clk_prepare_enable(cxo); if (rc) { @@ -148,15 +135,15 @@ static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on) wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id); if (IS_ERR(wlan_clock)) { rc = PTR_ERR(wlan_clock); - pr_err("Failed to get MSM_XO_TCXO_A2 voter (%d)\n", - rc); + pr_err("Failed to get MSM_XO_TCXO_A2 voter" + " (%d)\n", rc); goto fail; } rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON); if (rc < 0) { - pr_err("Configuring MSM_XO_MODE_ON failed (%d)\n", - rc); + pr_err("Configuring MSM_XO_MODE_ON failed" + " (%d)\n", rc); goto msm_xo_vote_fail; } } @@ -164,8 +151,8 @@ static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on) if (wlan_clock != NULL && !use_48mhz_xo) { rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF); if (rc < 0) - pr_err("Configuring MSM_XO_MODE_OFF failed (%d)\n", - rc); + pr_err("Configuring MSM_XO_MODE_OFF failed" + " (%d)\n", rc); } } @@ -372,11 +359,7 @@ int req_riva_power_on_lock(char *driver_name) node = kmalloc(sizeof(struct host_driver), GFP_KERNEL); if (!node) goto err; - if (strlcpy(node->name, driver_name, sizeof(node->name)) - >= sizeof(node->name)) { - kfree(node); - goto err; - } + strncpy(node->name, driver_name, sizeof(node->name)); mutex_lock(&list_lock); /* Lock when the first request is added */ diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 3bc8d89a580..b30ed4567bf 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -11,7 +11,6 @@ */ #include -#include #include #include #include @@ -35,7 +34,6 @@ /* module params */ #define WCNSS_CONFIG_UNSPECIFIED (-1) - static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED; module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present"); @@ -56,16 +54,13 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_CTRL_MSG_START 0x01000000 #define WCNSS_VERSION_REQ (WCNSS_CTRL_MSG_START + 0) #define WCNSS_VERSION_RSP (WCNSS_CTRL_MSG_START + 1) -#define WCNSS_NVBIN_DNLD_REQ (WCNSS_CTRL_MSG_START + 2) -#define WCNSS_NVBIN_DNLD_RSP (WCNSS_CTRL_MSG_START + 3) - #define VALID_VERSION(version) \ ((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0) struct smd_msg_hdr { - unsigned int msg_type; - unsigned int msg_len; + unsigned int type; + unsigned int len; }; struct wcnss_version { @@ -76,57 +71,6 @@ struct wcnss_version { unsigned char revision; }; -#define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" - -/* - * On SMD channel 4K of maximum data can be transferred, including message - * header, so NV fragment size as next multiple of 1Kb is 3Kb. - */ -#define NV_FRAGMENT_SIZE 3072 - -/* Macro to find the total number fragments of the NV bin Image */ -#define TOTALFRAGMENTS(x) (((x % NV_FRAGMENT_SIZE) == 0) ? \ - (x / NV_FRAGMENT_SIZE) : ((x / NV_FRAGMENT_SIZE) + 1)) - -struct nvbin_dnld_req_params { - /* - * Fragment sequence number of the NV bin Image. NV Bin Image - * might not fit into one message due to size limitation of - * the SMD channel FIFO so entire NV blob is chopped into - * multiple fragments starting with seqeunce number 0. The - * last fragment is indicated by marking is_last_fragment field - * to 1. At receiving side, NV blobs would be concatenated - * together without any padding bytes in between. - */ - unsigned short frag_number; - - /* - * When set to 1 it indicates that no more fragments will - * be sent. Receiver shall send back response message after - * last fragment. - */ - unsigned short is_last_fragment; - - /* NV Image size (number of bytes) */ - unsigned int nvbin_buffer_size; - - /* - * Following the 'nvbin_buffer_size', there should be - * nvbin_buffer_size bytes of NV bin Image i.e. - * uint8[nvbin_buffer_size]. - */ -}; - -struct nvbin_dnld_req_msg { - /* - * Note: The length specified in nvbin_dnld_req_msg messages - * should be hdr.msg_len = sizeof(nvbin_dnld_req_msg) + - * nvbin_buffer_size. - */ - struct smd_msg_hdr hdr; - struct nvbin_dnld_req_params dnld_req_params; -}; - static struct { struct platform_device *pdev; void *pil; @@ -137,7 +81,6 @@ static struct { const struct dev_pm_ops *pm_ops; int triggered; int smd_channel_ready; - int cold_boot_done; smd_channel_t *smd_ch; unsigned char wcnss_version[WCNSS_VERSION_LEN]; unsigned int serial_number; @@ -146,7 +89,6 @@ static struct { struct wcnss_wlan_config wlan_config; struct delayed_work wcnss_work; struct work_struct wcnssctrl_version_work; - struct work_struct wcnssctrl_nvbin_dnld_work; struct work_struct wcnssctrl_rx_work; struct wake_lock wcnss_wake_lock; void __iomem *msm_wcnss_base; @@ -622,16 +564,6 @@ void wcnss_allow_suspend() } EXPORT_SYMBOL(wcnss_allow_suspend); -int wcnss_cold_boot_done(void) -{ - if (penv) - return penv->cold_boot_done; - else - return -ENODEV; -} -EXPORT_SYMBOL(wcnss_cold_boot_done); - - static int wcnss_smd_tx(void *data, int len) { int ret = 0; @@ -639,7 +571,7 @@ static int wcnss_smd_tx(void *data, int len) ret = smd_write_avail(penv->smd_ch); if (ret < len) { pr_err("wcnss: no space available for smd frame\n"); - return -ENOSPC; + ret = -ENOSPC; } ret = smd_write(penv->smd_ch, data, len); if (ret < len) { @@ -674,7 +606,7 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) phdr = (struct smd_msg_hdr *)buf; - switch (phdr->msg_type) { + switch (phdr->type) { case WCNSS_VERSION_RSP: pversion = (struct wcnss_version *)buf; @@ -687,22 +619,10 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) "%02x%02x%02x%02x", pversion->major, pversion->minor, pversion->version, pversion->revision); pr_info("wcnss: version %s\n", penv->wcnss_version); - /* - * schedule work to download nvbin to riva ccpu, - * only if riva major >= 1 and minor >= 4. - */ - if ((pversion->major >= 1) && (pversion->minor >= 4)) { - pr_info("wcnss: schedule dnld work for riva\n"); - schedule_work(&penv->wcnssctrl_nvbin_dnld_work); - } - break; - - case WCNSS_NVBIN_DNLD_RSP: - pr_info("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu\n"); break; default: - pr_err("wcnss: invalid message type %d\n", phdr->msg_type); + pr_err("wcnss: invalid message type %d\n", phdr->type); } return; } @@ -712,126 +632,15 @@ static void wcnss_send_version_req(struct work_struct *worker) struct smd_msg_hdr smd_msg; int ret = 0; - smd_msg.msg_type = WCNSS_VERSION_REQ; - smd_msg.msg_len = sizeof(smd_msg); - ret = wcnss_smd_tx(&smd_msg, smd_msg.msg_len); + smd_msg.type = WCNSS_VERSION_REQ; + smd_msg.len = sizeof(smd_msg); + ret = wcnss_smd_tx(&smd_msg, smd_msg.len); if (ret < 0) pr_err("wcnss: smd tx failed\n"); return; } -static void wcnss_nvbin_dnld_req(struct work_struct *worker) -{ - int ret = 0; - struct nvbin_dnld_req_msg *dnld_req_msg; - unsigned short total_fragments = 0; - unsigned short count = 0; - unsigned short retry_count = 0; - unsigned short cur_frag_size = 0; - unsigned char *outbuffer = NULL; - const void *nv_blob_addr = NULL; - unsigned int nv_blob_size = 0; - const struct firmware *nv = NULL; - struct device *dev = NULL; - - dev = wcnss_wlan_get_device(); - - ret = request_firmware(&nv, NVBIN_FILE, dev); - - if (ret || !nv || !nv->data || !nv->size) { - pr_err("wcnss: wcnss_nvbin_dnld_req: request_firmware failed for %s\n", - NVBIN_FILE); - return; - } - - /* - * First 4 bytes in nv blob is validity bitmap. - * We cannot validate nv, so skip those 4 bytes. - */ - nv_blob_addr = nv->data + 4; - nv_blob_size = nv->size - 4; - - total_fragments = TOTALFRAGMENTS(nv_blob_size); - - pr_info("wcnss: NV bin size: %d, total_fragments: %d\n", - nv_blob_size, total_fragments); - - /* get buffer for nv bin dnld req message */ - outbuffer = kmalloc((sizeof(struct nvbin_dnld_req_msg) + - NV_FRAGMENT_SIZE), GFP_KERNEL); - - if (NULL == outbuffer) { - pr_err("wcnss: wcnss_nvbin_dnld_req: failed to get buffer\n"); - goto err_free_nv; - } - - dnld_req_msg = (struct nvbin_dnld_req_msg *)outbuffer; - - dnld_req_msg->hdr.msg_type = WCNSS_NVBIN_DNLD_REQ; - - for (count = 0; count < total_fragments; count++) { - dnld_req_msg->dnld_req_params.frag_number = count; - - if (count == (total_fragments - 1)) { - /* last fragment, take care of boundry condition */ - cur_frag_size = nv_blob_size % NV_FRAGMENT_SIZE; - if (!cur_frag_size) - cur_frag_size = NV_FRAGMENT_SIZE; - - dnld_req_msg->dnld_req_params.is_last_fragment = 1; - } else { - cur_frag_size = NV_FRAGMENT_SIZE; - dnld_req_msg->dnld_req_params.is_last_fragment = 0; - } - - dnld_req_msg->dnld_req_params.nvbin_buffer_size = - cur_frag_size; - - dnld_req_msg->hdr.msg_len = - sizeof(struct nvbin_dnld_req_msg) + cur_frag_size; - - /* copy NV fragment */ - memcpy((outbuffer + sizeof(struct nvbin_dnld_req_msg)), - (nv_blob_addr + count * NV_FRAGMENT_SIZE), - cur_frag_size); - - ret = wcnss_smd_tx(outbuffer, dnld_req_msg->hdr.msg_len); - - retry_count = 0; - while ((ret == -ENOSPC) && (retry_count <= 3)) { - pr_debug("wcnss: wcnss_nvbin_dnld_req: smd tx failed, ENOSPC\n"); - pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n", - count, dnld_req_msg->hdr.msg_len, - total_fragments, retry_count); - - /* wait and try again */ - msleep(20); - retry_count++; - ret = wcnss_smd_tx(outbuffer, - dnld_req_msg->hdr.msg_len); - } - - if (ret < 0) { - pr_err("wcnss: wcnss_nvbin_dnld_req: smd tx failed\n"); - pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n", - count, dnld_req_msg->hdr.msg_len, - total_fragments, retry_count); - goto err_dnld; - } - } - -err_dnld: - /* free buffer */ - kfree(outbuffer); - -err_free_nv: - /* release firmware */ - release_firmware(nv); - - return; -} - static int wcnss_trigger_config(struct platform_device *pdev) { @@ -902,7 +711,6 @@ wcnss_trigger_config(struct platform_device *pdev) INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler); INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req); - INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_req); wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss"); @@ -912,8 +720,6 @@ wcnss_trigger_config(struct platform_device *pdev) goto fail_wake; } - penv->cold_boot_done = 1; - return 0; fail_wake: diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index eaf7ed383dc..44ad73e4217 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -53,7 +53,6 @@ void wcnss_allow_suspend(void); void wcnss_prevent_suspend(void); void wcnss_ssr_boot_notify(void); void wcnss_reset_intr(void); -int wcnss_cold_boot_done(void); #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev) #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data)) From d5b9a6bfff5fa05e25a44833ecdeca78a3915707 Mon Sep 17 00:00:00 2001 From: Ravi Aravamudhan Date: Mon, 4 Mar 2013 13:24:02 -0800 Subject: [PATCH 2334/2357] diag: Bring Diag up to date Diag on the A-Family mainline is out of date. This change brings the diag code up to date. This includes reducing the error message frequency and the latest msg SSIDs, log codes and event IDs. Change-Id: Ibfce8ea52e25044df32bdff419d457ad296c6fc1 CRs-Fixed: 455623 Signed-off-by: Ravi Aravamudhan --- drivers/char/diag/diagfwd_hsic.c | 8 ++++++-- include/linux/diagchar.h | 9 ++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c index aa55578fb5f..616c49881eb 100644 --- a/drivers/char/diag/diagfwd_hsic.c +++ b/drivers/char/diag/diagfwd_hsic.c @@ -45,6 +45,7 @@ static void diag_read_hsic_work_fn(struct work_struct *work) struct diag_hsic_dev *hsic_struct = container_of(work, struct diag_hsic_dev, diag_read_hsic_work); int index = hsic_struct->id; + static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1); if (!diag_hsic[index].hsic_ch) { pr_err("DIAG in %s: diag_hsic[index].hsic_ch == 0\n", __func__); @@ -103,7 +104,8 @@ static void diag_read_hsic_work_fn(struct work_struct *work) diagmem_free(driver, buf_in_hsic, index+POOL_TYPE_HSIC); - pr_err_ratelimited("diag: Error initiating HSIC read, err: %d\n", + if (__ratelimit(&rl)) + pr_err("diag: Error initiating HSIC read, err: %d\n", err); /* * An error occurred, discontinue queuing @@ -132,6 +134,7 @@ static void diag_hsic_read_complete_callback(void *ctxt, char *buf, { int err = -2; int index = (int)ctxt; + static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1); if (!diag_hsic[index].hsic_ch) { /* @@ -164,7 +167,8 @@ static void diag_hsic_read_complete_callback(void *ctxt, char *buf, if (err) { diagmem_free(driver, buf, index + POOL_TYPE_HSIC); - pr_err_ratelimited("diag: In %s, error calling diag_device_write, err: %d\n", + if (__ratelimit(&rl)) + pr_err("diag: In %s, error calling diag_device_write, err: %d\n", __func__, err); } } diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index d3ee879d1b7..7a5ab0d4112 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -112,10 +112,10 @@ the appropriate macros. */ /* This needs to be modified manually now, when we add a new RANGE of SSIDs to the msg_mask_tbl */ #define MSG_MASK_TBL_CNT 24 -#define EVENT_LAST_ID 0x099F +#define EVENT_LAST_ID 0x09AB #define MSG_SSID_0 0 -#define MSG_SSID_0_LAST 93 +#define MSG_SSID_0_LAST 94 #define MSG_SSID_1 500 #define MSG_SSID_1_LAST 506 #define MSG_SSID_2 1000 @@ -278,6 +278,9 @@ static const uint32_t msg_bld_masks_0[] = { MSG_LVL_LOW, MSG_LVL_MED, MSG_LVL_LOW, + MSG_LVL_LOW, + MSG_LVL_LOW, + MSG_LVL_HIGH, MSG_LVL_LOW }; @@ -713,7 +716,7 @@ static const uint32_t msg_bld_masks_22[] = { /* LOG CODES */ #define LOG_0 0x0 -#define LOG_1 0x1750 +#define LOG_1 0x1755 #define LOG_2 0x0 #define LOG_3 0x0 #define LOG_4 0x4910 From 0ff6fc84650c31797a4f3ab758ad44ce91112562 Mon Sep 17 00:00:00 2001 From: detule Date: Mon, 4 Mar 2013 08:53:48 -0500 Subject: [PATCH 2335/2357] M2: sound: add gpio acquire/free on auxpcm init; --- sound/soc/msm/msm8960-d2.c | 44 ++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/sound/soc/msm/msm8960-d2.c b/sound/soc/msm/msm8960-d2.c index 5617508753f..5da9a5013cc 100644 --- a/sound/soc/msm/msm8960-d2.c +++ b/sound/soc/msm/msm8960-d2.c @@ -105,6 +105,7 @@ static struct snd_soc_jack hs_jack; static struct snd_soc_jack button_jack; static struct snd_soc_jack volumedown_jack; static struct snd_soc_jack volumeup_jack; +static atomic_t auxpcm_rsc_ref; static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable, bool dapm); @@ -932,9 +933,12 @@ static const struct snd_kcontrol_new tabla_msm8960_controls[] = { msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put), SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2], msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put), + SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0], + msm8960_btsco_rate_get, msm8960_btsco_rate_put), }; +#if 0 static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = { SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0], msm8960_btsco_rate_get, msm8960_btsco_rate_put), @@ -951,7 +955,7 @@ static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd) return err; return 0; } - +#endif static void *def_tabla_mbhc_cal(void) { void *tabla_cal; @@ -1702,21 +1706,15 @@ static int msm8960_i2s_startup(struct snd_pcm_substream *substream) return ret; } -/* Not used */ -#if 0 -static int msm8960_startup(struct snd_pcm_substream *substream) -{ - pr_info("%s(): substream = %s stream = %d\n", __func__, - substream->name, substream->stream); - return 0; -} - static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream) { int ret = 0; - pr_info("%s(): substream = %s\n", __func__, substream->name); - ret = msm8960_aux_pcm_get_gpios(); + pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n", + __func__, substream->name, atomic_read(&auxpcm_rsc_ref)); + if (atomic_inc_return(&auxpcm_rsc_ref) == 1) + ret = msm8960_aux_pcm_get_gpios(); + if (ret < 0) { pr_err("%s: Aux PCM GPIO request failed\n", __func__); return -EINVAL; @@ -1726,9 +1724,19 @@ static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream) static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream) { + pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n", + __func__, substream->name, atomic_read(&auxpcm_rsc_ref)); + if (atomic_dec_return(&auxpcm_rsc_ref) == 0) + msm8960_aux_pcm_free_gpios(); +} - pr_info("%s(): substream = %s\n", __func__, substream->name); - msm8960_aux_pcm_free_gpios(); +/* Not used */ +#if 0 +static int msm8960_startup(struct snd_pcm_substream *substream) +{ + pr_info("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + return 0; } static void msm8960_shutdown(struct snd_pcm_substream *substream) @@ -1749,12 +1757,11 @@ static struct snd_soc_ops msm8960_i2s_be_ops = { }; /* Not Used */ -/* + static struct snd_soc_ops msm8960_auxpcm_be_ops = { .startup = msm8960_auxpcm_startup, .shutdown = msm8960_auxpcm_shutdown, }; -*/ static struct snd_soc_dai_link *msm8960_dai_list; static struct snd_soc_dai_link msm8960_i2s_be_dai[] = { @@ -2022,7 +2029,6 @@ static struct snd_soc_dai_link msm8960_dai[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-rx", - .init = &msm8960_btsco_init, .no_pcm = 1, .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX, .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup, @@ -2110,7 +2116,7 @@ static struct snd_soc_dai_link msm8960_dai[] = { .no_pcm = 1, .be_id = MSM_BACKEND_DAI_AUXPCM_RX, .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup, -// .ops = &msm8960_auxpcm_be_ops, + .ops = &msm8960_auxpcm_be_ops, .ignore_pmdown_time = 1, }, { @@ -2123,7 +2129,7 @@ static struct snd_soc_dai_link msm8960_dai[] = { .no_pcm = 1, .be_id = MSM_BACKEND_DAI_AUXPCM_TX, .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup, -// .ops = &msm8960_auxpcm_be_ops, + .ops = &msm8960_auxpcm_be_ops, }, /* Incall Music BACK END DAI Link */ { From 1e965ebd19003304580597c7439174c07853c325 Mon Sep 17 00:00:00 2001 From: detule Date: Mon, 4 Mar 2013 20:08:55 -0500 Subject: [PATCH 2336/2357] M2: mach-msm: auxpcm: fix auxpcm platform data for M2 --- arch/arm/mach-msm/devices-8960.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c index aec5522d55a..a16adcfa2ce 100644 --- a/arch/arm/mach-msm/devices-8960.c +++ b/arch/arm/mach-msm/devices-8960.c @@ -2523,20 +2523,21 @@ struct msm_dai_auxpcm_pdata auxpcm_pdata = { .mode_8k = { .mode = AFE_PCM_CFG_MODE_PCM, .sync = AFE_PCM_CFG_SYNC_INT, - .frame = AFE_PCM_CFG_FRM_32BPF, + .frame = AFE_PCM_CFG_FRM_256BPF, .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD, .slot = 0, .data = AFE_PCM_CFG_CDATAOE_MASTER, - .pcm_clk_rate = 256000, + .pcm_clk_rate = 2048000, }, .mode_16k = { .mode = AFE_PCM_CFG_MODE_PCM, .sync = AFE_PCM_CFG_SYNC_INT, - .frame = AFE_PCM_CFG_FRM_32BPF, + .frame = AFE_PCM_CFG_FRM_256BPF, .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD, .slot = 0, .data = AFE_PCM_CFG_CDATAOE_MASTER, - .pcm_clk_rate = 512000, + .pcm_clk_rate = 2048000, + } }; From 796e47e9ad52859a6e5d6aae479816a3e6c17a7a Mon Sep 17 00:00:00 2001 From: detule Date: Mon, 4 Mar 2013 20:43:50 -0500 Subject: [PATCH 2337/2357] M2: Revert "M2: sound: add debugging prints" This reverts commit 9f49a47fba774c0964404d5ef644850d9e8bce56. Conflicts: sound/soc/msm/msm8960-d2.c --- sound/soc/msm/msm-pcm-routing.c | 3 +- sound/soc/msm/msm8960-d2.c | 168 ++++++++++++++++---------------- sound/soc/msm/qdsp6/q6afe.c | 14 +-- sound/soc/msm/qdsp6v2/q6afe.c | 2 +- 4 files changed, 93 insertions(+), 94 deletions(-) diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c index aa397374b92..81f8e026f95 100644 --- a/sound/soc/msm/msm-pcm-routing.c +++ b/sound/soc/msm/msm-pcm-routing.c @@ -424,7 +424,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set) int session_type, path_type; u32 channels; - pr_info("%s: reg %x val %x set %x\n", __func__, reg, val, set); + pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set); if (val > MSM_FRONTEND_DAI_MM_MAX_ID) { /* recheck FE ID in the mixer control defined in this file */ @@ -2664,7 +2664,6 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream) u32 channels; bool playback, capture; - pr_info("%s: be_id = %x", __func__, be_id); if (be_id >= MSM_BACKEND_DAI_MAX) { pr_err("%s: unexpected be_id %d\n", __func__, be_id); return -EINVAL; diff --git a/sound/soc/msm/msm8960-d2.c b/sound/soc/msm/msm8960-d2.c index 5da9a5013cc..0723a4fd477 100644 --- a/sound/soc/msm/msm8960-d2.c +++ b/sound/soc/msm/msm8960-d2.c @@ -142,9 +142,9 @@ static struct ext_amp_work ext_amp_dwork; remove the static noise during SPK_PA enable */ static void external_speaker_amp_work(struct work_struct *work) { - pr_info("%s :: Top Speaker Amp enable\n", __func__); + pr_debug("%s :: Top Speaker Amp enable\n", __func__); gpio_direction_output(top_spk_pamp_gpio, 1); - pr_info("%s: slepping 4 ms after turning on external " + pr_debug("%s: slepping 4 ms after turning on external " " Top Speaker Ampl\n", __func__); usleep_range(4000, 4000); } @@ -156,7 +156,7 @@ static void msm8960_ext_spk_power_amp_on(u32 spk) if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) && (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) { - pr_info("%s() External Bottom Speaker Ampl already " + pr_debug("%s() External Bottom Speaker Ampl already " "turned on. spk = 0x%08x\n", __func__, spk); return; } @@ -166,9 +166,9 @@ static void msm8960_ext_spk_power_amp_on(u32 spk) if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) && (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) { - pr_info("%s Enabling Bottom Speaker\n", __func__); + pr_debug("%s Enabling Bottom Speaker\n", __func__); gpio_direction_output(bottom_spk_pamp_gpio, 1); - pr_info("%s: slepping 4 ms after turning on external " + pr_debug("%s: slepping 4 ms after turning on external " " Bottom Speaker Ampl\n", __func__); usleep_range(4000, 4000); } @@ -178,7 +178,7 @@ static void msm8960_ext_spk_power_amp_on(u32 spk) if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) && (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) { - pr_info("%s() External Top Speaker Ampl already" + pr_debug("%s() External Top Speaker Ampl already" "turned on. spk = 0x%08x\n", __func__, spk); return; } @@ -208,11 +208,11 @@ static void msm8960_ext_spk_power_amp_off(u32 spk) if (!msm8960_ext_bottom_spk_pamp) return; - pr_info("%s Disabling Bottom Speaker\n", __func__); + pr_debug("%s Disabling Bottom Speaker\n", __func__); gpio_direction_output(bottom_spk_pamp_gpio, 0); msm8960_ext_bottom_spk_pamp = 0; - pr_info("%s: sleeping 4 ms after turning off external Bottom" + pr_debug("%s: sleeping 4 ms after turning off external Bottom" " Speaker Ampl\n", __func__); usleep_range(4000, 4000); @@ -222,7 +222,7 @@ static void msm8960_ext_spk_power_amp_off(u32 spk) if (!msm8960_ext_top_spk_pamp) return; gpio_direction_output(top_spk_pamp_gpio, 0); - pr_info("%s: slepping 4 ms after turning off external " + pr_debug("%s: slepping 4 ms after turning off external " " Top Speaker Ampl\n", __func__); msm8960_ext_top_spk_pamp = 0; } else { @@ -238,7 +238,7 @@ static void msm8960_ext_control(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = &codec->dapm; mutex_lock(&dapm->codec->mutex); - pr_info("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control); + pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control); if (msm8960_spk_control == MSM8960_SPK_ON || msm8960_i2s_spk_control == MSM8960_SPK_ON) { snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos"); @@ -259,7 +259,7 @@ static void msm8960_ext_control(struct snd_soc_codec *codec) static int msm8960_get_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pr_info("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control); + pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control); ucontrol->value.integer.value[0] = msm8960_spk_control; return 0; } @@ -268,7 +268,7 @@ static int msm8960_set_spk(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); if (msm8960_spk_control == ucontrol->value.integer.value[0]) return 0; @@ -279,7 +279,7 @@ static int msm8960_set_spk(struct snd_kcontrol *kcontrol, static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - pr_info("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event)); + pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event)); if (SND_SOC_DAPM_EVENT_ON(event)) { if (!strncmp(w->name, "Ext Spk Bottom Pos", 18)) @@ -317,7 +317,7 @@ static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w, static int msm8960_bias_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - pr_info("GPIO BIAS UP!!!%d\n", SND_SOC_DAPM_EVENT_ON(event)); + pr_debug("GPIO BIAS UP!!!%d\n", SND_SOC_DAPM_EVENT_ON(event)); #if defined(CONFIG_MACH_M2_DCM) || defined(CONFIG_MACH_K2_KDI) if (system_rev == BOARD_REV00) gpio_direction_output(GPIO_MAIN_MIC_BIAS_REV00, @@ -345,7 +345,7 @@ static int msm8960_bias_event(struct snd_soc_dapm_widget *w, static int msm8960_cdc_cp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - pr_info("%s %d\n", __func__, SND_SOC_DAPM_EVENT_ON(event)); + pr_debug("%s %d\n", __func__, SND_SOC_DAPM_EVENT_ON(event)); gpio_direction_output(PM8921_GPIO_PM_TO_SYS(17), SND_SOC_DAPM_EVENT_ON(event)); return 0; @@ -355,7 +355,7 @@ static int msm8960_cdc_cp_event(struct snd_soc_dapm_widget *w, static int msm8960_cdc_vps_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - pr_info("%s %d\n", __func__, SND_SOC_DAPM_EVENT_ON(event)); + pr_debug("%s %d\n", __func__, SND_SOC_DAPM_EVENT_ON(event)); gpio_direction_output(PM8921_GPIO_PM_TO_SYS(5), SND_SOC_DAPM_EVENT_ON(event)); return 0; @@ -372,7 +372,7 @@ static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable, mutex_lock(&cdc_mclk_mutex); if (enable) { clk_users++; - pr_info("%s: clk_users = %d\n", __func__, clk_users); + pr_debug("%s: clk_users = %d\n", __func__, clk_users); if (clk_users == 1) { codec_clk = clk_get(NULL, "i2s_spkr_osr_clk"); if (codec_clk) { @@ -388,9 +388,9 @@ static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable, } else { if (clk_users > 0) { clk_users--; - pr_info("%s: clk_users = %d\n", __func__, clk_users); + pr_debug("%s: clk_users = %d\n", __func__, clk_users); if (clk_users == 0) { - pr_info("%s: disabling MCLK. clk_users = %d\n", + pr_debug("%s: disabling MCLK. clk_users = %d\n", __func__, clk_users); tabla_mclk_enable(codec, 0, dapm); clk_disable(codec_clk); @@ -408,7 +408,7 @@ static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable, static int msm8960_mclk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - pr_info("%s: event = %d\n", __func__, event); + pr_debug("%s: event = %d\n", __func__, event); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -794,7 +794,7 @@ static const struct soc_enum msm8960_btsco_enum[] = { static int msm8960_i2s_rx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pr_info("%s: msm8960_i2s_rx_ch = %d\n", __func__, + pr_debug("%s: msm8960_i2s_rx_ch = %d\n", __func__, msm8960_i2s_rx_ch); ucontrol->value.integer.value[0] = msm8960_i2s_rx_ch - 1; return 0; @@ -805,7 +805,7 @@ static int msm8960_i2s_rx_ch_put(struct snd_kcontrol *kcontrol, { msm8960_i2s_rx_ch = ucontrol->value.integer.value[0] + 1; - pr_info("%s: msm8960_i2s_rx_ch = %d\n", __func__, + pr_debug("%s: msm8960_i2s_rx_ch = %d\n", __func__, msm8960_i2s_rx_ch); return 1; } @@ -813,7 +813,7 @@ static int msm8960_i2s_rx_ch_put(struct snd_kcontrol *kcontrol, static int msm8960_i2s_tx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pr_info("%s: msm8960_i2s_tx_ch = %d\n", __func__, + pr_debug("%s: msm8960_i2s_tx_ch = %d\n", __func__, msm8960_i2s_tx_ch); ucontrol->value.integer.value[0] = msm8960_i2s_tx_ch - 1; return 0; @@ -824,7 +824,7 @@ static int msm8960_i2s_tx_ch_put(struct snd_kcontrol *kcontrol, { msm8960_i2s_tx_ch = ucontrol->value.integer.value[0] + 1; - pr_info("%s: msm8960_i2s_tx_ch = %d\n", __func__, + pr_debug("%s: msm8960_i2s_tx_ch = %d\n", __func__, msm8960_i2s_tx_ch); return 1; } @@ -832,7 +832,7 @@ static int msm8960_i2s_tx_ch_put(struct snd_kcontrol *kcontrol, static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pr_info("%s: msm8960_slim_0_rx_ch = %d\n", __func__, + pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__, msm8960_slim_0_rx_ch); ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1; return 0; @@ -843,7 +843,7 @@ static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol, { msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1; - pr_info("%s: msm8960_slim_0_rx_ch = %d\n", __func__, + pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__, msm8960_slim_0_rx_ch); return 1; } @@ -851,7 +851,7 @@ static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol, static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pr_info("%s: msm8960_slim_0_tx_ch = %d\n", __func__, + pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__, msm8960_slim_0_tx_ch); ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1; return 0; @@ -862,7 +862,7 @@ static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol, { msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1; - pr_info("%s: msm8960_slim_0_tx_ch = %d\n", __func__, + pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__, msm8960_slim_0_tx_ch); return 1; } @@ -870,7 +870,7 @@ static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol, static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pr_info("%s: msm8960_btsco_rate = %d", __func__, + pr_debug("%s: msm8960_btsco_rate = %d", __func__, msm8960_btsco_rate); ucontrol->value.integer.value[0] = msm8960_btsco_rate; return 0; @@ -890,7 +890,7 @@ static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol, msm8960_btsco_rate = BTSCO_RATE_8KHZ; break; } - pr_info("%s: msm8960_btsco_rate = %d\n", __func__, + pr_debug("%s: msm8960_btsco_rate = %d\n", __func__, msm8960_btsco_rate); return 0; } @@ -900,7 +900,7 @@ static int msm8960_i2s_set_spk(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); if (msm8960_i2s_spk_control == ucontrol->value.integer.value[0]) return 0; @@ -912,7 +912,7 @@ static int msm8960_i2s_set_spk(struct snd_kcontrol *kcontrol, static int msm8960_i2s_get_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pr_info("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control); + pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control); ucontrol->value.integer.value[0] = msm8960_i2s_spk_control; return 0; } @@ -1038,7 +1038,7 @@ static int msm8960_i2s_audrx_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); err = snd_soc_add_codec_controls(codec, tabla_msm8960_i2s_controls, ARRAY_SIZE(tabla_msm8960_i2s_controls)); if (err < 0) { @@ -1139,7 +1139,7 @@ static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd) .inv_int_pol = 0, }; - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); if (machine_is_msm8960_liquid()) { top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS @@ -1275,7 +1275,7 @@ static int msm8960_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); rate->min = rate->max = 48000; channels->min = channels->max = msm8960_i2s_rx_ch; @@ -1291,7 +1291,7 @@ static int msm8960_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); rate->min = rate->max = 48000; channels->min = channels->max = msm8960_i2s_tx_ch; @@ -1307,7 +1307,7 @@ static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); rate->min = rate->max = 48000; channels->min = channels->max = msm8960_slim_0_rx_ch; @@ -1323,7 +1323,7 @@ static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); rate->min = rate->max = 48000; channels->min = channels->max = msm8960_slim_0_tx_ch; @@ -1336,7 +1336,7 @@ static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); rate->min = rate->max = 48000; return 0; @@ -1351,7 +1351,7 @@ static int msm8960_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - pr_info("%s channels->min %u channels->max %u ()\n", __func__, + pr_debug("%s channels->min %u channels->max %u ()\n", __func__, channels->min, channels->max); rate->min = rate->max = 48000; @@ -1394,7 +1394,7 @@ static int msm8960_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - pr_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); rate->min = rate->max = 48000; return 0; @@ -1404,7 +1404,7 @@ int msm8960_aux_pcm_get_gpios(void) { int ret = 0; - pr_info("%s\n", __func__); + pr_debug("%s\n", __func__); ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT"); if (ret < 0) { @@ -1620,64 +1620,64 @@ static int msm8960_i2s_startup(struct snd_pcm_substream *substream) pr_info("%s\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { configure_i2s_rx_gpio(); - codec_clk = clk_get(NULL, "i2s_spkr_osr_clk"); - if (IS_ERR(codec_clk)) { - pr_err("%s Error getting i2s_spkr_osr_clk", __func__); - return -EBUSY; - } - clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE); - ret = clk_prepare_enable(codec_clk); - if (ret) { - pr_err("Unable to enable codec clock\n"); - clk_put(codec_clk); - return ret; - } + codec_clk = clk_get(NULL, "i2s_spkr_osr_clk"); + if (IS_ERR(codec_clk)) { + pr_err("%s Error getting i2s_spkr_osr_clk", __func__); + return -EBUSY; + } + clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE); + ret = clk_prepare_enable(codec_clk); + if (ret) { + pr_err("Unable to enable codec clock\n"); + clk_put(codec_clk); + return ret; + } - rx_bit_clk = clk_get(NULL, "i2s_spkr_bit_clk"); - if (IS_ERR(rx_bit_clk)) { - pr_err("Failed to get i2s_spkr_bit_clk\n"); - clk_disable(codec_clk); - clk_put(codec_clk); - return -EBUSY; - } - clk_set_rate(rx_bit_clk, 8); - ret = clk_prepare_enable(rx_bit_clk); - if (ret) { - pr_err("Unable to enable bit_clk\n"); - clk_disable(codec_clk); - clk_put(codec_clk); - clk_put(rx_bit_clk); - return ret; - } - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) { - pr_err("set format for cpu dai failed\n"); - return ret; - } + rx_bit_clk = clk_get(NULL, "i2s_spkr_bit_clk"); + if (IS_ERR(rx_bit_clk)) { + pr_err("Failed to get i2s_spkr_bit_clk\n"); + clk_disable(codec_clk); + clk_put(codec_clk); + return -EBUSY; + } + clk_set_rate(rx_bit_clk, 8); + ret = clk_prepare_enable(rx_bit_clk); + if (ret) { + pr_err("Unable to enable bit_clk\n"); + clk_disable(codec_clk); + clk_put(codec_clk); + clk_put(rx_bit_clk); + return ret; + } + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + pr_err("set format for cpu dai failed\n"); + return ret; + } ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) { - pr_err("set format for codec dai failed\n"); - return ret; - } + if (ret < 0) { + pr_err("set format for codec dai failed\n"); + return ret; + } } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { configure_i2s_tx_gpio(); tx_osr_clk = clk_get(NULL, "i2s_mic_osr_clk"); if (IS_ERR(tx_osr_clk)) { - pr_info("Failed to get i2s_mic_osr_clk\n"); + pr_debug("Failed to get i2s_mic_osr_clk\n"); return -EBUSY; } /* Master clock OSR 256 */ clk_set_rate(tx_osr_clk, I2S_MIC_MCLK_RATE); ret = clk_prepare_enable(tx_osr_clk); if (ret) { - pr_info("Unable to enable i2s_mic_osr_clk\n"); + pr_debug("Unable to enable i2s_mic_osr_clk\n"); clk_put(tx_osr_clk); return ret; } tx_bit_clk = clk_get(NULL, "i2s_mic_bit_clk"); if (IS_ERR(tx_bit_clk)) { - pr_info("Failed to get i2s_mic_bit_clk\n"); + pr_debug("Failed to get i2s_mic_bit_clk\n"); clk_disable(tx_osr_clk); clk_put(tx_osr_clk); return -EBUSY; @@ -1685,7 +1685,7 @@ static int msm8960_i2s_startup(struct snd_pcm_substream *substream) clk_set_rate(tx_bit_clk, 8); ret = clk_prepare_enable(tx_bit_clk); if (ret) { - pr_info("Unable to enable i2s_mic_bit_clk\n"); + pr_debug("Unable to enable i2s_mic_bit_clk\n"); clk_put(tx_bit_clk); clk_disable(tx_osr_clk); clk_put(tx_osr_clk); @@ -1741,7 +1741,7 @@ static int msm8960_startup(struct snd_pcm_substream *substream) static void msm8960_shutdown(struct snd_pcm_substream *substream) { - pr_info("%s(): substream = %s stream = %d\n", __func__, + pr_debug("%s(): substream = %s stream = %d\n", __func__, substream->name, substream->stream); } diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c index 63fda7b3547..aaebad5f6a2 100644 --- a/sound/soc/msm/qdsp6/q6afe.c +++ b/sound/soc/msm/qdsp6/q6afe.c @@ -349,7 +349,7 @@ int afe_q6_interface_prepare(void) { int ret = 0; - pr_info("%s:", __func__); + pr_debug("%s:", __func__); if (this_afe.apr == NULL) { this_afe.apr = apr_register("ADSP", "AFE", afe_callback, @@ -368,11 +368,11 @@ static void afe_send_cal_block(int32_t path, u16 port_id) int result = 0; struct acdb_cal_block cal_block; struct afe_port_cmd_set_param_no_payload afe_cal; - pr_info("%s: path %d\n", __func__, path); + pr_debug("%s: path %d\n", __func__, path); get_afe_cal(path, &cal_block); if (cal_block.cal_size <= 0) { - pr_info("%s: No AFE cal to send!\n", __func__); + pr_debug("%s: No AFE cal to send!\n", __func__); goto done; } @@ -398,7 +398,7 @@ static void afe_send_cal_block(int32_t path, u16 port_id) afe_cal.payload_size = cal_block.cal_size; afe_cal.payload_address = cal_block.cal_paddr; - pr_info("%s: AFE cal sent for device port = %d, path = %d, " + pr_debug("%s: AFE cal sent for device port = %d, path = %d, " "cal size = %d, cal addr = 0x%x\n", __func__, port_id, path, cal_block.cal_size, cal_block.cal_paddr); @@ -424,7 +424,7 @@ static void afe_send_cal_block(int32_t path, u16 port_id) void afe_send_cal(u16 port_id) { - pr_info("%s\n", __func__); + pr_debug("%s\n", __func__); if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) afe_send_cal_block(TX_CAL, port_id); @@ -447,7 +447,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, ret = -EINVAL; return ret; } - pr_info("%s: %d %d\n", __func__, port_id, rate); + pr_debug("%s: %d %d\n", __func__, port_id, rate); if ((port_id == RT_PROXY_DAI_001_RX) || (port_id == RT_PROXY_DAI_002_TX)) { @@ -520,7 +520,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, * is L-PCM, the AFE_PORT_AUDIO_IF_CONFIG is used * to make the backward compatible. */ - pr_info("%s: afe_config->mi2s.format = %d\n", __func__, + pr_debug("%s: afe_config->mi2s.format = %d\n", __func__, afe_config->mi2s.format); if (afe_config->mi2s.format == MSM_AFE_I2S_FORMAT_LPCM) config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG; diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index f07848788de..f56b3d675b2 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -225,7 +225,7 @@ int afe_q6_interface_prepare(void) { int ret = 0; - pr_info("%s:", __func__); + pr_debug("%s:", __func__); if (this_afe.apr == NULL) { this_afe.apr = apr_register("ADSP", "AFE", afe_callback, From 3f9ae630c0407b134c9cd6416e23733d86c4303d Mon Sep 17 00:00:00 2001 From: detule Date: Mon, 4 Mar 2013 20:56:52 -0500 Subject: [PATCH 2338/2357] M2: Revert "M2_SPR: ram_console: console_verbose()" This reverts commit f2834924456f801c6b71fb0ace654944a3d24ae2. --- drivers/staging/android/ram_console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c index b353b65847f..cf0f8fb4fd8 100644 --- a/drivers/staging/android/ram_console.c +++ b/drivers/staging/android/ram_console.c @@ -68,7 +68,7 @@ static int __devinit ram_console_probe(struct platform_device *pdev) ram_console_zone = prz; ram_console.data = prz; - console_verbose(); + register_console(&ram_console); return 0; From 858f871ed9d2e8e34506513d05bc9847641f1fab Mon Sep 17 00:00:00 2001 From: Ashwini Rao Date: Mon, 4 Mar 2013 12:15:57 -0800 Subject: [PATCH 2339/2357] msm: camera: Fix the composite stats buffer handling. Currently we configure composite stats in HFR mode. In composite stats mode, the stats buffers are not getting dequeued and dispatched properly. Hence the stats are not processed properly in HFR mode, resulting in dark preview in camcorder HFR mode. Fix this by correcting the buffer handling logic in case of composite stats. CRs-Fixed: 452197 Change-Id: I98be1160001deea72d0fa31e0e804d523fd72c20 Signed-off-by: Ashwini Rao Signed-off-by: Kiran Kumar H N --- drivers/media/video/msm/msm_isp.c | 20 ++--- drivers/media/video/msm/vfe/msm_vfe32.c | 108 +++++++++++++++++++++--- 2 files changed, 104 insertions(+), 24 deletions(-) diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c index cf831f4c621..5b2cf7cb082 100644 --- a/drivers/media/video/msm/msm_isp.c +++ b/drivers/media/video/msm/msm_isp.c @@ -389,18 +389,14 @@ static int msm_isp_notify_vfe(struct msm_cam_media_controller *pmctl, struct msm_stats_buf *stats_buf = NULL; isp_event->isp_data.isp_msg.msg_id = MSG_ID_STATS_COMPOSITE; - stats->aec.buff = msm_pmem_stats_ptov_lookup(pmctl, - stats->aec.buff, &(stats->aec.fd)); - stats->awb.buff = msm_pmem_stats_ptov_lookup(pmctl, - stats->awb.buff, &(stats->awb.fd)); - stats->af.buff = msm_pmem_stats_ptov_lookup(pmctl, - stats->af.buff, &(stats->af.fd)); - stats->ihist.buff = msm_pmem_stats_ptov_lookup(pmctl, - stats->ihist.buff, &(stats->ihist.fd)); - stats->rs.buff = msm_pmem_stats_ptov_lookup(pmctl, - stats->rs.buff, &(stats->rs.fd)); - stats->cs.buff = msm_pmem_stats_ptov_lookup(pmctl, - stats->cs.buff, &(stats->cs.fd)); + CDBG("%s: aec (%d, %x) awb (%d, %x) af (%d, %x) ", __func__, + stats->aec.fd, (uint32_t)stats->aec.buff, + stats->awb.fd, (uint32_t)stats->awb.buff, + stats->af.fd, (uint32_t)stats->af.buff); + CDBG("%s: rs (%d, %x) cs(%d, %x) ihist(%d, %x)", __func__, + stats->rs.fd, (uint32_t)stats->rs.buff, + stats->cs.fd, (uint32_t)stats->cs.buff, + stats->ihist.fd, (uint32_t)stats->ihist.buff); stats_buf = kmalloc(sizeof(struct msm_stats_buf), GFP_ATOMIC); if (!stats_buf) { diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c index a962c945033..8497902df85 100644 --- a/drivers/media/video/msm/vfe/msm_vfe32.c +++ b/drivers/media/video/msm/vfe/msm_vfe32.c @@ -4847,7 +4847,9 @@ static void vfe_send_comp_stats_msg( struct vfe32_ctrl_type *vfe32_ctrl, uint32_t status_bits) { struct msm_stats_buf msgStats; - uint32_t temp; + uint32_t stats_type; + int rc = 0; + void *vaddr = NULL; msgStats.frame_id = vfe32_ctrl->share_ctrl->vfeFrameId; if (vfe32_ctrl->simultaneous_sof_stat) @@ -4855,21 +4857,102 @@ static void vfe_send_comp_stats_msg( msgStats.status_bits = status_bits; - msgStats.aec.buff = vfe32_ctrl->aecbgStatsControl.bufToRender; - msgStats.awb.buff = vfe32_ctrl->awbStatsControl.bufToRender; - msgStats.af.buff = vfe32_ctrl->afbfStatsControl.bufToRender; + if (status_bits & VFE_IRQ_STATUS0_STATS_AEC_BG) { + stats_type = (!vfe32_use_bayer_stats(vfe32_ctrl)) ? + MSM_STATS_TYPE_AEC : MSM_STATS_TYPE_BG; + rc = vfe32_ctrl->stats_ops.dispatch( + vfe32_ctrl->stats_ops.stats_ctrl, stats_type, + vfe32_ctrl->aecbgStatsControl.bufToRender, + &msgStats.buf_idx, &vaddr, &msgStats.aec.fd, + vfe32_ctrl->stats_ops.client); + if (rc == 0) + msgStats.aec.buff = (uint32_t)vaddr; + else + CDBG("%s: Could not dispatch AEC/BG stats buffer %d", + __func__, stats_type); + } else { + msgStats.aec.buff = 0; + } + + if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) { + rc = vfe32_ctrl->stats_ops.dispatch( + vfe32_ctrl->stats_ops.stats_ctrl, MSM_STATS_TYPE_AWB, + vfe32_ctrl->awbStatsControl.bufToRender, + &msgStats.buf_idx, &vaddr, &msgStats.awb.fd, + vfe32_ctrl->stats_ops.client); + if (rc == 0) + msgStats.awb.buff = (uint32_t)vaddr; + else + CDBG("%s: Could not dispatch AWB stats buffer", + __func__); + } else { + msgStats.awb.buff = 0; + } + + if (status_bits & VFE_IRQ_STATUS0_STATS_AF_BF) { + stats_type = (!vfe32_use_bayer_stats(vfe32_ctrl)) ? + MSM_STATS_TYPE_AF : MSM_STATS_TYPE_BF; + rc = vfe32_ctrl->stats_ops.dispatch( + vfe32_ctrl->stats_ops.stats_ctrl, stats_type, + vfe32_ctrl->afbfStatsControl.bufToRender, + &msgStats.buf_idx, &vaddr, &msgStats.af.fd, + vfe32_ctrl->stats_ops.client); + if (rc == 0) + msgStats.af.buff = (uint32_t)vaddr; + else + CDBG("%s: Could not dispatch AF/BF stats buffer %d", + __func__, stats_type); + } else { + msgStats.af.buff = 0; + } + + if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) { + rc = vfe32_ctrl->stats_ops.dispatch( + vfe32_ctrl->stats_ops.stats_ctrl, MSM_STATS_TYPE_IHIST, + vfe32_ctrl->ihistStatsControl.bufToRender, + &msgStats.buf_idx, &vaddr, &msgStats.ihist.fd, + vfe32_ctrl->stats_ops.client); + if (rc == 0) + msgStats.ihist.buff = (uint32_t)vaddr; + else + CDBG("%s: Could not dispatch IHIST stats buffer", + __func__); + } else { + msgStats.ihist.buff = 0; + } - msgStats.ihist.buff = vfe32_ctrl->ihistStatsControl.bufToRender; - msgStats.rs.buff = vfe32_ctrl->rsStatsControl.bufToRender; - msgStats.cs.buff = vfe32_ctrl->csStatsControl.bufToRender; + if (status_bits & VFE_IRQ_STATUS0_STATS_RS) { + rc = vfe32_ctrl->stats_ops.dispatch( + vfe32_ctrl->stats_ops.stats_ctrl, MSM_STATS_TYPE_RS, + vfe32_ctrl->rsStatsControl.bufToRender, + &msgStats.buf_idx, &vaddr, &msgStats.rs.fd, + vfe32_ctrl->stats_ops.client); + if (rc == 0) + msgStats.rs.buff = (uint32_t)vaddr; + else + CDBG("%s: Could not dispatch RS stats buffer", + __func__); + } else { + msgStats.rs.buff = 0; + } - temp = msm_camera_io_r( - vfe32_ctrl->share_ctrl->vfebase + VFE_STATS_AWB_SGW_CFG); - msgStats.awb_ymin = (0xFF00 & temp) >> 8; + if (status_bits & VFE_IRQ_STATUS0_STATS_CS) { + rc = vfe32_ctrl->stats_ops.dispatch( + vfe32_ctrl->stats_ops.stats_ctrl, MSM_STATS_TYPE_CS, + vfe32_ctrl->csStatsControl.bufToRender, + &msgStats.buf_idx, &vaddr, &msgStats.cs.fd, + vfe32_ctrl->stats_ops.client); + if (rc == 0) + msgStats.cs.buff = (uint32_t)vaddr; + else + CDBG("%s: Could not dispatch CS stats buffer", + __func__); + } else { + msgStats.cs.buff = 0; + } v4l2_subdev_notify(&vfe32_ctrl->subdev, - NOTIFY_VFE_MSG_COMP_STATS, - &msgStats); + NOTIFY_VFE_MSG_COMP_STATS, &msgStats); } static void vfe32_process_stats_ae_bg_irq(struct vfe32_ctrl_type *vfe32_ctrl) @@ -5158,6 +5241,7 @@ static void vfe32_process_stats_irq( struct vfe32_ctrl_type *vfe32_ctrl, uint32_t irqstatus) { uint32_t status_bits = VFE_COM_STATUS & irqstatus; + if ((vfe32_ctrl->hfr_mode != HFR_MODE_OFF) && (vfe32_ctrl->share_ctrl->vfeFrameId % vfe32_ctrl->hfr_mode != 0)) { From d8796595eb51bb1babd8d82fe03386d6f8f66b28 Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Mon, 7 Jan 2013 12:40:03 -0800 Subject: [PATCH 2340/2357] ASoC: wcd9xxx: Fix MBHC irq handler deadlock scenario There is a chance to encounter deadlock when either electrical mbhc irq or mechanical mbhc irq releases resource lock to let polling thread finish its job. This is due to the possibility of one irq handler can preempt already running the other type of irq handler. Introduce a new mutex to avoid this preemption. CRs-fixed: 428653 Change-Id: Idf24c62224026c9c061de12c31e248c05b47de9d Signed-off-by: Joonwoo Park --- drivers/mfd/wcd9xxx-irq.c | 20 ++++++++++++++++++++ include/linux/mfd/wcd9xxx/core.h | 3 +++ sound/soc/codecs/wcd9310.c | 7 ++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c index 4c40c9e8da2..fde658b4ed0 100644 --- a/drivers/mfd/wcd9xxx-irq.c +++ b/drivers/mfd/wcd9xxx-irq.c @@ -151,21 +151,35 @@ void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx) } EXPORT_SYMBOL_GPL(wcd9xxx_unlock_sleep); +void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx) +{ + mutex_lock(&wcd9xxx->nested_irq_lock); +} + +void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx) +{ + mutex_unlock(&wcd9xxx->nested_irq_lock); +} + static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit) { if ((irqbit <= TABLA_IRQ_MBHC_INSERTION) && (irqbit >= TABLA_IRQ_MBHC_REMOVAL)) { + wcd9xxx_nested_irq_lock(wcd9xxx); wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 + BIT_BYTE(irqbit), BYTE_BIT_MASK(irqbit)); if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MODE, 0x02); handle_nested_irq(wcd9xxx->irq_base + irqbit); + wcd9xxx_nested_irq_unlock(wcd9xxx); } else { + wcd9xxx_nested_irq_lock(wcd9xxx); handle_nested_irq(wcd9xxx->irq_base + irqbit); wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 + BIT_BYTE(irqbit), BYTE_BIT_MASK(irqbit)); if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MODE, 0x02); + wcd9xxx_nested_irq_unlock(wcd9xxx); } } @@ -223,6 +237,7 @@ int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx) unsigned int i, cur_irq; mutex_init(&wcd9xxx->irq_lock); + mutex_init(&wcd9xxx->nested_irq_lock); if (!wcd9xxx->irq) { dev_warn(wcd9xxx->dev, @@ -235,6 +250,9 @@ int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx) dev_err(wcd9xxx->dev, "No interrupt base specified, no interrupts\n"); return 0; + mutex_destroy(&wcd9xxx->nested_irq_lock); + mutex_destroy(&wcd9xxx->irq_lock); + mutex_destroy(&wcd9xxx->nested_irq_lock); } /* Mask the individual interrupt sources */ for (i = 0, cur_irq = wcd9xxx->irq_base; i < TABLA_NUM_IRQS; i++, @@ -296,6 +314,7 @@ int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx) if (ret) mutex_destroy(&wcd9xxx->irq_lock); + mutex_destroy(&wcd9xxx->nested_irq_lock); return ret; } @@ -308,4 +327,5 @@ void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx) device_init_wakeup(wcd9xxx->dev, 0); } mutex_destroy(&wcd9xxx->irq_lock); + mutex_destroy(&wcd9xxx->nested_irq_lock); } diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h index 508bf3bb55e..f83187d3154 100644 --- a/include/linux/mfd/wcd9xxx/core.h +++ b/include/linux/mfd/wcd9xxx/core.h @@ -129,6 +129,7 @@ struct wcd9xxx { struct mutex io_lock; struct mutex xfer_lock; struct mutex irq_lock; + struct mutex nested_irq_lock; u8 version; unsigned int irq_base; @@ -177,6 +178,8 @@ int wcd9xxx_get_intf_type(void); bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx); void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx); +void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx); +void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx); enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx, enum wcd9xxx_pm_state o, enum wcd9xxx_pm_state n); diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c index cb403711c64..5dc08b37343 100644 --- a/sound/soc/codecs/wcd9310.c +++ b/sound/soc/codecs/wcd9310.c @@ -121,7 +121,9 @@ struct tabla_codec_dai_data { #define TABLA_MBHC_GND_MIC_SWAP_THRESHOLD 2 -#define TABLA_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0) +#define TABLA_ACQUIRE_LOCK(x) do { \ + mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \ +} while (0) #define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0) static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); @@ -7528,6 +7530,7 @@ static void tabla_hs_gpio_handler(struct snd_soc_codec *codec) { bool insert; struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec); + struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent); bool is_removed = false; pr_debug("%s: enter\n", __func__); @@ -7537,6 +7540,7 @@ static void tabla_hs_gpio_handler(struct snd_soc_codec *codec) usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US, TABLA_GPIO_IRQ_DEBOUNCE_TIME_US); + wcd9xxx_nested_irq_lock(core); TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock); /* cancel pending button press */ @@ -7608,6 +7612,7 @@ static void tabla_hs_gpio_handler(struct snd_soc_codec *codec) tabla->in_gpio_handler = false; TABLA_RELEASE_LOCK(tabla->codec_resource_lock); + wcd9xxx_nested_irq_unlock(core); pr_debug("%s: leave\n", __func__); } From 6279ddfeff6893aeb970374a110990cc829a18d2 Mon Sep 17 00:00:00 2001 From: Sameer Thalappil Date: Thu, 8 Nov 2012 13:41:04 -0800 Subject: [PATCH 2341/2357] wcnss: Log CCPU registers in reset interrupt API Reset interrupt is sent to Riva when host drivers fail to communicate with Riva over SMD. So logging these CCPU registers helps to know the failure reason at Riva. Change-Id: Icccf6a5b0644fd75137602cc96b25dc8d392260a CRs-Fixed: 418813 Signed-off-by: Sameer Thalappil --- drivers/net/wireless/wcnss/wcnss_wlan.c | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index b30ed4567bf..ddde0064b6f 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -46,6 +46,13 @@ static DEFINE_SPINLOCK(reg_spinlock); #define RIVA_SSR_BIT BIT(23) #define RIVA_SUSPEND_BIT BIT(24) +#define MSM_RIVA_CCU_BASE 0x03200800 + +#define CCU_INVALID_ADDR_OFFSET 0x100 +#define CCU_LAST_ADDR0_OFFSET 0x104 +#define CCU_LAST_ADDR1_OFFSET 0x108 +#define CCU_LAST_ADDR2_OFFSET 0x10c + #define WCNSS_CTRL_CHANNEL "WCNSS_CTRL" #define WCNSS_MAX_FRAME_SIZE 500 #define WCNSS_VERSION_LEN 30 @@ -162,9 +169,45 @@ static ssize_t wcnss_version_show(struct device *dev, static DEVICE_ATTR(wcnss_version, S_IRUSR, wcnss_version_show, NULL); + +/* wcnss_reset_intr() is invoked when host drivers fails to + * communicate with WCNSS over SMD; so logging these registers + * helps to know WCNSS failure reason */ +static void wcnss_log_ccpu_regs(void) +{ + void __iomem *ccu_base; + void __iomem *ccu_reg; + u32 reg = 0; + + ccu_base = ioremap(MSM_RIVA_CCU_BASE, SZ_512); + if (!ccu_base) { + pr_err("%s: ioremap WCNSS CCU reg failed\n", __func__); + return; + } + + ccu_reg = ccu_base + CCU_INVALID_ADDR_OFFSET; + reg = readl_relaxed(ccu_reg); + pr_info("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg); + + ccu_reg = ccu_base + CCU_LAST_ADDR0_OFFSET; + reg = readl_relaxed(ccu_reg); + pr_info("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg); + + ccu_reg = ccu_base + CCU_LAST_ADDR1_OFFSET; + reg = readl_relaxed(ccu_reg); + pr_info("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg); + + ccu_reg = ccu_base + CCU_LAST_ADDR2_OFFSET; + reg = readl_relaxed(ccu_reg); + pr_info("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg); + + iounmap(ccu_base); +} + /* interface to reset Riva by sending the reset interrupt */ void wcnss_reset_intr(void) { + wcnss_log_ccpu_regs(); wmb(); __raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8); } From 68f4437a66ef62b04ca86c35b2c297f46d3ec64f Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Fri, 1 Mar 2013 18:25:05 -0800 Subject: [PATCH 2342/2357] power: pm8921-charger: get rid of using LPM The LPM is causing a lot of regression on various test cases 1. Writes to charger have become complex 2. There is uncertainty about whether battery insertion/removal could be detected reliably. LPM was introduced to prevent lockups from happening when the charger was running in hw based clock switching while it was suspended. UVLO lockups were not seen if the charger was running from 19.2Mhz. Instead activate LPM mode only while the system is suspended and always force 19.2Mhz when not suspended. This way we avoid the complexities with writes, can detect battery insertion/removal as long as the system is not suspended and more importantly fix the UVLO issue since we will never be running in hw clk switching mode. Change-Id: I94510311b503c21ec659a96982010435abdbcfaf Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/pm8921-charger.c | 468 +++++++-------------------------- 1 file changed, 102 insertions(+), 366 deletions(-) diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c index 0c8a483aca6..5f50d3139d7 100644 --- a/drivers/power/pm8921-charger.c +++ b/drivers/power/pm8921-charger.c @@ -255,12 +255,9 @@ struct pm8921_chg_chip { struct dentry *dent; struct bms_notify bms_notify; int *usb_trim_table; - struct regulator *vreg_xoadc; bool ext_charging; bool ext_charge_done; bool iusb_fine_res; - bool final_kickstart; - bool lockup_lpm_wrkarnd; DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS); struct work_struct battery_id_valid_work; int64_t batt_id_min; @@ -311,7 +308,6 @@ static int thermal_mitigation; static struct pm8921_chg_chip *the_chip; -static DEFINE_SPINLOCK(lpm_lock); #define LPM_ENABLE_BIT BIT(2) static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable) { @@ -340,66 +336,11 @@ static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable) static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg) { int rc; - unsigned long flags = 0; - u8 temp; - - /* Disable LPM */ - if (chip->lockup_lpm_wrkarnd) { - spin_lock_irqsave(&lpm_lock, flags); - - /* - * This delay is to prevent exit out of 32khz mode within - * 200uS. It could be that chg was removed just few uS before - * this gets called. - */ - udelay(200); - /* no clks */ - temp = 0xD1; - rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (rc) { - pr_err("Error %d writing %d to CHG_TEST\n", rc, temp); - goto release_lpm_lock; - } - - /* force 19.2Mhz before reading */ - temp = 0xD3; - rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (rc) { - pr_err("Error %d writing %d to CHG_TEST\n", rc, temp); - goto release_lpm_lock; - } - - rc = pm8xxx_writeb(chip->dev->parent, addr, reg); - if (rc) { - pr_err("failed: addr=%03X, rc=%d\n", addr, rc); - goto release_lpm_lock; - } - - /* no clks */ - temp = 0xD1; - rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (rc) { - pr_err("Error %d writing %d to CHG_TEST\n", rc, temp); - goto release_lpm_lock; - } - /* switch to hw clk selection */ - temp = 0xD0; - rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (rc) { - pr_err("Error %d writing %d to CHG_TEST\n", rc, temp); - goto release_lpm_lock; - } - - udelay(200); + rc = pm8xxx_writeb(chip->dev->parent, addr, reg); + if (rc) + pr_err("failed: addr=%03X, rc=%d\n", addr, rc); -release_lpm_lock: - spin_unlock_irqrestore(&lpm_lock, flags); - } else { - rc = pm8xxx_writeb(chip->dev->parent, addr, reg); - if (rc) - pr_err("failed: addr=%03X, rc=%d\n", addr, rc); - } return rc; } @@ -430,23 +371,6 @@ static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id) chip->pmic_chg_irq[irq_id]); } -static int is_chg_on_bat(struct pm8921_chg_chip *chip) -{ - return !(pm_chg_get_rt_status(chip, DCIN_VALID_IRQ) - || pm_chg_get_rt_status(chip, USBIN_VALID_IRQ)); -} - -static void pm8921_chg_bypass_bat_gone_debounce(struct pm8921_chg_chip *chip, - int bypass) -{ - int rc; - - rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, bypass ? 0x89 : 0x88); - if (rc) { - pr_err("Failed to set bypass bit to %d rc=%d\n", bypass, rc); - } -} - /* Treat OverVoltage/UnderVoltage as source missing */ static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip) { @@ -469,35 +393,8 @@ static int is_batfet_closed(struct pm8921_chg_chip *chip) static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip) { u8 temp; - unsigned long flags = 0; int err = 0, ret = 0; - if (chip->lockup_lpm_wrkarnd) { - spin_lock_irqsave(&lpm_lock, flags); - - /* - * This delay is to prevent exit out of 32khz mode within - * 200uS. It could be that chg was removed just few uS before - * this gets called. - */ - udelay(200); - /* no clks */ - temp = 0xD1; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to CHG_TEST\n", err, temp); - goto err_out; - } - - /* force 19.2Mhz before reading */ - temp = 0xD3; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to CHG_TEST\n", err, temp); - goto err_out; - } - } - temp = CAPTURE_FSM_STATE_CMD; err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); if (err) { @@ -535,29 +432,7 @@ static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip) /* get the upper 1 bit */ ret |= (temp & 0x1) << 4; - if (chip->lockup_lpm_wrkarnd) { - /* no clks */ - temp = 0xD1; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to CHG_TEST\n", err, temp); - goto err_out; - } - - /* switch to hw clk selection */ - temp = 0xD0; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to CHG_TEST\n", err, temp); - goto err_out; - } - - udelay(200); - } - err_out: - if (chip->lockup_lpm_wrkarnd) - spin_unlock_irqrestore(&lpm_lock, flags); if (err) return err; @@ -568,35 +443,8 @@ static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip) static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip) { u8 temp, data; - unsigned long flags = 0; int err = 0; - if (chip->lockup_lpm_wrkarnd) { - spin_lock_irqsave(&lpm_lock, flags); - - /* - * This delay is to prevent exit out of 32khz mode within - * 200uS. It could be that chg was removed just few uS before - * this gets called. - */ - udelay(200); - /* no clks */ - temp = 0xD1; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to CHG_TEST\n", err, temp); - goto err_out; - } - - /* force 19.2Mhz before reading */ - temp = 0xD3; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to CHG_TEST\n", err, temp); - goto err_out; - } - } - temp = READ_BANK_6; err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); if (err) { @@ -610,29 +458,7 @@ static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip) goto err_out; } - if (chip->lockup_lpm_wrkarnd) { - /* no clks */ - temp = 0xD1; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to CHG_TEST\n", err, temp); - goto err_out; - } - - /* switch to hw clk selection */ - temp = 0xD0; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to CHG_TEST\n", err, temp); - goto err_out; - } - - udelay(200); - } - err_out: - if (chip->lockup_lpm_wrkarnd) - spin_unlock_irqrestore(&lpm_lock, flags); if (err) return err; @@ -2388,96 +2214,9 @@ int pm8921_batt_temperature(void) return get_prop_batt_temp(the_chip); } -static int __pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip) -{ - int err; - u8 temp; - - - temp = 0xD1; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); - return err; - } - - temp = 0xD3; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); - return err; - } - - temp = 0xD1; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); - return err; - } - - temp = 0xD5; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); - return err; - } - - /* Wait a few clock cycles before re-enabling hw clock switching */ - udelay(183); - - temp = 0xD1; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); - return err; - } - - temp = 0xD0; - err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp); - if (err) { - pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); - return err; - } - - /* Wait for few clock cycles before re-enabling LPM */ - udelay(32); - - return 0; -} - -static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip) -{ - int err; - unsigned long flags = 0; - - spin_lock_irqsave(&lpm_lock, flags); - err = pm8921_chg_set_lpm(chip, 0); - if (err) { - pr_err("Error settig LPM rc=%d\n", err); - goto kick_err; - } - - __pm8921_apply_19p2mhz_kickstart(chip); - -kick_err: - err = pm8921_chg_set_lpm(chip, 1); - if (err) - pr_err("Error settig LPM rc=%d\n", err); - - spin_unlock_irqrestore(&lpm_lock, flags); - - return err; -} - static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip) { - int usb_present, rc = 0; - - if (chip->lockup_lpm_wrkarnd) { - rc = pm8921_apply_19p2mhz_kickstart(chip); - if (rc) - pr_err("Failed to apply kickstart rc=%d\n", rc); - } + int usb_present; pm_chg_failed_clear(chip, 1); usb_present = is_usb_chg_plugged_in(chip); @@ -2487,11 +2226,6 @@ static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip) power_supply_changed(&chip->usb_psy); power_supply_changed(&chip->batt_psy); pm8921_bms_calibrate_hkadc(); - - /* Enable/disable bypass if charger is on battery */ - if (chip->lockup_lpm_wrkarnd) - pm8921_chg_bypass_bat_gone_debounce(chip, - is_chg_on_bat(chip)); } if (usb_present) { schedule_delayed_work(&chip->unplug_check_work, @@ -2507,10 +2241,6 @@ static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip) static void handle_stop_ext_chg(struct pm8921_chg_chip *chip) { - if (chip->lockup_lpm_wrkarnd) - /* Enable bypass if charger is on battery */ - pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip)); - if (!chip->ext_psy) { pr_debug("external charger not registered.\n"); return; @@ -2540,10 +2270,6 @@ static void handle_start_ext_chg(struct pm8921_chg_chip *chip) unsigned long delay = round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS)); - /* Disable bypass if charger connected and not running on bat */ - if (chip->lockup_lpm_wrkarnd) - pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip)); - if (!chip->ext_psy) { pr_debug("external charger not registered.\n"); return; @@ -3025,28 +2751,12 @@ static void unplug_check_worker(struct work_struct *work) pm_chg_get_fsm_state(chip), get_prop_batt_current(chip) ); - if (chip->lockup_lpm_wrkarnd) { - rc = pm8921_apply_19p2mhz_kickstart(chip); - if (rc) - pr_err("Failed kickstart rc=%d\n", rc); - - /* - * Make sure kickstart happens at least 200 ms - * after charger has been removed. - */ - if (chip->final_kickstart) { - chip->final_kickstart = false; - goto check_again_later; - } - } return; } else { goto check_again_later; } } - chip->final_kickstart = true; - /* AICL only for usb wall charger */ if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 && !chip->disable_aicl) { @@ -3339,11 +3049,6 @@ static irqreturn_t dcin_valid_irq_handler(int irq, void *data) else handle_stop_ext_chg(chip); } else { - if (chip->lockup_lpm_wrkarnd) - /* if no external supply call bypass debounce here */ - pm8921_chg_bypass_bat_gone_debounce(chip, - is_chg_on_bat(chip)); - if (dc_present) schedule_delayed_work(&chip->unplug_check_work, msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS)); @@ -4175,6 +3880,91 @@ static int __devinit request_irqs(struct pm8921_chg_chip *chip, return -EINVAL; } +static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip) +{ + int err; + u8 temp; + + temp = 0xD1; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD3; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD1; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD5; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + udelay(183); + + temp = 0xD1; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD0; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + udelay(32); + + temp = 0xD1; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD3; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } +} + +static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip) +{ + int err; + u8 temp; + + temp = 0xD1; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } + + temp = 0xD0; + err = pm_chg_write(chip, CHG_TEST, temp); + if (err) { + pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST); + return; + } +} + #define VREF_BATT_THERM_FORCE_ON BIT(7) static void detect_battery_removal(struct pm8921_chg_chip *chip) { @@ -4206,15 +3996,8 @@ static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip) u8 subrev; int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES; - spin_lock_init(&lpm_lock); - - if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) { - rc = __pm8921_apply_19p2mhz_kickstart(chip); - if (rc) { - pr_err("Failed to apply kickstart rc=%d\n", rc); - return rc; - } - } + /* forcing 19p2mhz before accessing any charger registers */ + pm8921_chg_force_19p2mhz_clk(chip); detect_battery_removal(chip); @@ -4462,45 +4245,6 @@ static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip) return rc; } - if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) { - /* Clear kickstart */ - rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0); - if (rc) { - pr_err("Failed to clear kickstart rc=%d\n", rc); - return rc; - } - - /* From here the lpm_workaround will be active */ - chip->lockup_lpm_wrkarnd = true; - - /* Enable LPM */ - pm8921_chg_set_lpm(chip, 1); - } - - if (chip->lockup_lpm_wrkarnd) { - chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc"); - if (IS_ERR(chip->vreg_xoadc)) - return -ENODEV; - - rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000); - if (rc < 0) { - pr_err("Failed to set configure HPM rc=%d\n", rc); - return rc; - } - - rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000); - if (rc) { - pr_err("Failed to set L14 voltage rc=%d\n", rc); - return rc; - } - - rc = regulator_enable(chip->vreg_xoadc); - if (rc) { - pr_err("Failed to enable L14 rc=%d\n", rc); - return rc; - } - } - return 0; } @@ -4751,19 +4495,16 @@ static int pm8921_charger_suspend_noirq(struct device *dev) int rc; struct pm8921_chg_chip *chip = dev_get_drvdata(dev); - if (chip->lockup_lpm_wrkarnd) { - rc = regulator_disable(chip->vreg_xoadc); - if (rc) - pr_err("Failed to disable L14 rc=%d\n", rc); - - rc = pm8921_apply_19p2mhz_kickstart(chip); - if (rc) - pr_err("Failed to apply kickstart rc=%d\n", rc); - } - rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0); if (rc) pr_err("Failed to Force Vref therm off rc=%d\n", rc); + + rc = pm8921_chg_set_lpm(chip, 1); + if (rc) + pr_err("Failed to set lpm rc=%d\n", rc); + + pm8921_chg_set_hw_clk_switching(chip); + return 0; } @@ -4772,15 +4513,11 @@ static int pm8921_charger_resume_noirq(struct device *dev) int rc; struct pm8921_chg_chip *chip = dev_get_drvdata(dev); - if (chip->lockup_lpm_wrkarnd) { - rc = regulator_enable(chip->vreg_xoadc); - if (rc) - pr_err("Failed to enable L14 rc=%d\n", rc); + pm8921_chg_force_19p2mhz_clk(chip); - rc = pm8921_apply_19p2mhz_kickstart(chip); - if (rc) - pr_err("Failed to apply kickstart rc=%d\n", rc); - } + rc = pm8921_chg_set_lpm(chip, 0); + if (rc) + pr_err("Failed to set lpm rc=%d\n", rc); rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, VREF_BATT_THERM_FORCE_ON); @@ -5011,7 +4748,6 @@ static int __devexit pm8921_charger_remove(struct platform_device *pdev) { struct pm8921_chg_chip *chip = platform_get_drvdata(pdev); - regulator_put(chip->vreg_xoadc); free_irqs(chip); platform_set_drvdata(pdev, NULL); the_chip = NULL; From 131eb4b687fb412ab619a5baaca75f6823b3e78e Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Mon, 26 Nov 2012 19:47:18 -0800 Subject: [PATCH 2343/2357] net: usb: Add MUX support in embedded rmnet driver Due to limited number of HSIC endpoints, to support more than existing number of control and data channels, driver needs to MUX all the data channels as well as the control channels into one HSIC interface. MUX support is enabled on PID 0x9075. MUX header is added to IP/control packet based on the channel id while transmitting to mdm device. Similarly, while receiving driver removes and parses the MUX header and based on channel id it forwards IP/control packet to appropriate network interface/control channel. Change-Id: If37c672347ab47be6e02d4efd33a70c46486b5f1 Signed-off-by: Hemant Kumar --- .../net/usb/{rmnet_usb_ctrl.h => rmnet_usb.h} | 51 ++- drivers/net/usb/rmnet_usb_ctrl.c | 248 ++++++++---- drivers/net/usb/rmnet_usb_data.c | 360 ++++++++++++++---- drivers/net/usb/usbnet.c | 18 +- include/linux/usb/usbnet.h | 5 + 5 files changed, 508 insertions(+), 174 deletions(-) rename drivers/net/usb/{rmnet_usb_ctrl.h => rmnet_usb.h} (71%) diff --git a/drivers/net/usb/rmnet_usb_ctrl.h b/drivers/net/usb/rmnet_usb.h similarity index 71% rename from drivers/net/usb/rmnet_usb_ctrl.h rename to drivers/net/usb/rmnet_usb.h index 57ea8ba1286..b895969f949 100644 --- a/drivers/net/usb/rmnet_usb_ctrl.h +++ b/drivers/net/usb/rmnet_usb.h @@ -10,8 +10,8 @@ * GNU General Public License for more details. */ -#ifndef __RMNET_USB_CTRL_H -#define __RMNET_USB_CTRL_H +#ifndef __RMNET_USB_H +#define __RMNET_USB_H #include #include @@ -20,8 +20,36 @@ #include #define MAX_RMNET_DEVS 4 +#define MAX_RMNET_INSTS_PER_DEV 17 +#define TOTAL_RMNET_DEV_COUNT (MAX_RMNET_DEVS * MAX_RMNET_INSTS_PER_DEV) + #define CTRL_DEV_MAX_LEN 10 +#define RMNET_CTRL_DEV_OPEN 0 +#define RMNET_CTRL_DEV_READY 1 +#define RMNET_CTRL_DEV_MUX_EN 2 + +/*MUX header bit masks*/ +#define MUX_CTRL_MASK 0x1 +#define MUX_PAD_SHIFT 0x2 + +/*max padding bytes for n byte alignment*/ +#define MAX_PAD_BYTES(n) (n-1) + +/* + *MUX Header Format + *BIT 0 : Mux type 0: Data, 1: control + *BIT 1: Reserved + *BIT 2-7: Pad bytes + *BIT 8-15: Mux ID + *BIT 16-31: PACKET_LEN_WITH_PADDING (Bytes) + */ +struct mux_hdr { + __u8 padding_info; + __u8 mux_id; + __le16 pkt_len_w_padding; +} __packed; + struct rmnet_ctrl_dev { /*for debugging purpose*/ @@ -29,6 +57,10 @@ struct rmnet_ctrl_dev { struct cdev cdev; struct device *devicep; + unsigned ch_id; + + /*to identify the usb device*/ + unsigned id; struct usb_interface *intf; unsigned int int_pipe; @@ -49,15 +81,7 @@ struct rmnet_ctrl_dev { struct workqueue_struct *wq; struct work_struct get_encap_work; - unsigned is_opened; - - bool is_connected; - - /* - * track first resp available from mdm when it boots up - * to avoid bigger timeout value used by qmuxd - */ - bool resp_available; + unsigned long status; bool claimed; @@ -78,6 +102,8 @@ struct rmnet_ctrl_dev { unsigned int zlp_cnt; }; +extern struct workqueue_struct *usbnet_wq; + extern int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *); extern int rmnet_usb_ctrl_suspend(struct rmnet_ctrl_dev *dev); extern int rmnet_usb_ctrl_init(int num_devs, int insts_per_dev); @@ -85,7 +111,8 @@ extern void rmnet_usb_ctrl_exit(int num_devs, int insts_per_dev); extern int rmnet_usb_ctrl_probe(struct usb_interface *intf, struct usb_host_endpoint *int_in, unsigned long rmnet_devnum, - struct rmnet_ctrl_dev **ctrldev); + unsigned long *data); extern void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *); +extern void rmnet_usb_ctrl_cleanup(struct rmnet_ctrl_dev *dev); #endif /* __RMNET_USB_H*/ diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c index cea56a795e7..42c95a66358 100644 --- a/drivers/net/usb/rmnet_usb_ctrl.c +++ b/drivers/net/usb/rmnet_usb_ctrl.c @@ -19,7 +19,7 @@ #include #include #include -#include "rmnet_usb_ctrl.h" +#include "rmnet_usb.h" static char *rmnet_dev_names[MAX_RMNET_DEVS] = {"hsicctl"}; module_param_array(rmnet_dev_names, charp, NULL, S_IRUGO | S_IWUSR); @@ -106,6 +106,7 @@ static dev_t ctrldev_num[MAX_RMNET_DEVS]; struct ctrl_pkt { size_t data_size; void *data; + void *ctxt; }; struct ctrl_pkt_list_elem { @@ -115,18 +116,56 @@ struct ctrl_pkt_list_elem { static void resp_avail_cb(struct urb *); -static int is_dev_connected(struct rmnet_ctrl_dev *dev) +static int rmnet_usb_ctrl_dmux(struct ctrl_pkt_list_elem *clist) { - if (dev) { - mutex_lock(&dev->dev_lock); - if (!dev->is_connected) { - mutex_unlock(&dev->dev_lock); - return 0; - } - mutex_unlock(&dev->dev_lock); - return 1; + struct mux_hdr *hdr; + size_t pad_len; + size_t total_len; + unsigned int mux_id; + + hdr = (struct mux_hdr *)clist->cpkt.data; + pad_len = hdr->padding_info >> MUX_PAD_SHIFT; + if (pad_len > MAX_PAD_BYTES(4)) { + pr_err_ratelimited("%s: Invalid pad len %d\n", __func__, + pad_len); + return -EINVAL; } - return 0; + + mux_id = hdr->mux_id; + if (!mux_id || mux_id > insts_per_dev) { + pr_err_ratelimited("%s: Invalid mux id %d\n", __func__, mux_id); + return -EINVAL; + } + + total_len = le16_to_cpu(hdr->pkt_len_w_padding); + if (!total_len || !(total_len - pad_len)) { + pr_err_ratelimited("%s: Invalid pkt length %d\n", __func__, + total_len); + return -EINVAL; + } + + clist->cpkt.data_size = total_len - pad_len; + + return mux_id - 1; +} + +static void rmnet_usb_ctrl_mux(unsigned int id, struct ctrl_pkt *cpkt) +{ + struct mux_hdr *hdr; + size_t len; + size_t pad_len = 0; + + hdr = (struct mux_hdr *)cpkt->data; + hdr->mux_id = id + 1; + len = cpkt->data_size - sizeof(struct mux_hdr) - MAX_PAD_BYTES(4); + + /*add padding if len is not 4 byte aligned*/ + pad_len = ALIGN(len, 4) - len; + + hdr->pkt_len_w_padding = cpu_to_le16(len + pad_len); + hdr->padding_info = (pad_len << MUX_PAD_SHIFT) | MUX_CTRL_MASK; + + cpkt->data_size = sizeof(struct mux_hdr) + hdr->pkt_len_w_padding; } static void get_encap_work(struct work_struct *w) @@ -136,6 +175,9 @@ static void get_encap_work(struct work_struct *w) container_of(w, struct rmnet_ctrl_dev, get_encap_work); int status; + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) + return; + udev = interface_to_usbdev(dev->intf); status = usb_autopm_get_interface(dev->intf); @@ -225,11 +267,6 @@ static void notification_available_cb(struct urb *urb) usb_mark_last_busy(udev); queue_work(dev->wq, &dev->get_encap_work); - if (!dev->resp_available) { - dev->resp_available = true; - wake_up(&dev->open_wait_queue); - } - return; default: dev_err(dev->devicep, @@ -252,9 +289,9 @@ static void resp_avail_cb(struct urb *urb) { struct usb_device *udev; struct ctrl_pkt_list_elem *list_elem = NULL; - struct rmnet_ctrl_dev *dev = urb->context; + struct rmnet_ctrl_dev *rx_dev, *dev = urb->context; void *cpkt; - int status = 0; + int ch_id, status = 0; size_t cpkt_size = 0; udev = interface_to_usbdev(dev->intf); @@ -264,7 +301,6 @@ static void resp_avail_cb(struct urb *urb) switch (urb->status) { case 0: /*success*/ - dev->get_encap_resp_cnt++; break; /*do not resubmit*/ @@ -309,11 +345,27 @@ static void resp_avail_cb(struct urb *urb) } memcpy(list_elem->cpkt.data, cpkt, cpkt_size); list_elem->cpkt.data_size = cpkt_size; - spin_lock(&dev->rx_lock); - list_add_tail(&list_elem->list, &dev->rx_list); - spin_unlock(&dev->rx_lock); - wake_up(&dev->read_wait_queue); + rx_dev = dev; + + if (test_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status)) { + ch_id = rmnet_usb_ctrl_dmux(list_elem); + if (ch_id < 0) { + kfree(list_elem->cpkt.data); + kfree(list_elem); + goto resubmit_int_urb; + } + + rx_dev = &ctrl_devs[dev->id][ch_id]; + } + + rx_dev->get_encap_resp_cnt++; + + spin_lock(&rx_dev->rx_lock); + list_add_tail(&list_elem->list, &rx_dev->rx_list); + spin_unlock(&rx_dev->rx_lock); + + wake_up(&rx_dev->read_wait_queue); resubmit_int_urb: /*check if it is already submitted in resume*/ @@ -378,7 +430,7 @@ static int rmnet_usb_ctrl_write_cmd(struct rmnet_ctrl_dev *dev) { struct usb_device *udev; - if (!is_dev_connected(dev)) + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) return -ENODEV; udev = interface_to_usbdev(dev->intf); @@ -393,7 +445,8 @@ static int rmnet_usb_ctrl_write_cmd(struct rmnet_ctrl_dev *dev) static void ctrl_write_callback(struct urb *urb) { - struct rmnet_ctrl_dev *dev = urb->context; + struct ctrl_pkt *cpkt = urb->context; + struct rmnet_ctrl_dev *dev = cpkt->ctxt; if (urb->status) { dev->tx_ctrl_err_cnt++; @@ -404,18 +457,19 @@ static void ctrl_write_callback(struct urb *urb) kfree(urb->setup_packet); kfree(urb->transfer_buffer); usb_free_urb(urb); + kfree(cpkt); usb_autopm_put_interface_async(dev->intf); } -static int rmnet_usb_ctrl_write(struct rmnet_ctrl_dev *dev, char *buf, - size_t size) +static int rmnet_usb_ctrl_write(struct rmnet_ctrl_dev *dev, + struct ctrl_pkt *cpkt, size_t size) { int result; struct urb *sndurb; struct usb_ctrlrequest *out_ctlreq; struct usb_device *udev; - if (!is_dev_connected(dev)) + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) return -ENETRESET; udev = interface_to_usbdev(dev->intf); @@ -439,12 +493,12 @@ static int rmnet_usb_ctrl_write(struct rmnet_ctrl_dev *dev, char *buf, out_ctlreq->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; out_ctlreq->wValue = 0; out_ctlreq->wIndex = dev->intf->cur_altsetting->desc.bInterfaceNumber; - out_ctlreq->wLength = cpu_to_le16(size); + out_ctlreq->wLength = cpu_to_le16(cpkt->data_size); usb_fill_control_urb(sndurb, udev, usb_sndctrlpipe(udev, 0), - (unsigned char *)out_ctlreq, (void *)buf, size, - ctrl_write_callback, dev); + (unsigned char *)out_ctlreq, (void *)cpkt->data, + cpkt->data_size, ctrl_write_callback, cpkt); result = usb_autopm_get_interface(dev->intf); if (result < 0) { @@ -487,16 +541,15 @@ static int rmnet_ctl_open(struct inode *inode, struct file *file) if (!dev) return -ENODEV; - if (dev->is_opened) + if (test_bit(RMNET_CTRL_DEV_OPEN, &dev->status)) goto already_opened; - /*block open to get first response available from mdm*/ - if (dev->mdm_wait_timeout && !dev->resp_available) { + if (dev->mdm_wait_timeout && + !test_bit(RMNET_CTRL_DEV_READY, &dev->status)) { retval = wait_event_interruptible_timeout( - dev->open_wait_queue, - dev->resp_available, - msecs_to_jiffies(dev->mdm_wait_timeout * - 1000)); + dev->open_wait_queue, + test_bit(RMNET_CTRL_DEV_READY, &dev->status), + msecs_to_jiffies(dev->mdm_wait_timeout * 1000)); if (retval == 0) { dev_err(dev->devicep, "%s: Timeout opening %s\n", __func__, dev->name); @@ -508,15 +561,13 @@ static int rmnet_ctl_open(struct inode *inode, struct file *file) } } - if (!dev->resp_available) { + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) { dev_dbg(dev->devicep, "%s: Connection timedout opening %s\n", __func__, dev->name); return -ETIMEDOUT; } - mutex_lock(&dev->dev_lock); - dev->is_opened = 1; - mutex_unlock(&dev->dev_lock); + set_bit(RMNET_CTRL_DEV_OPEN, &dev->status); file->private_data = dev; @@ -551,9 +602,7 @@ static int rmnet_ctl_release(struct inode *inode, struct file *file) } spin_unlock_irqrestore(&dev->rx_lock, flag); - mutex_lock(&dev->dev_lock); - dev->is_opened = 0; - mutex_unlock(&dev->dev_lock); + clear_bit(RMNET_CTRL_DEV_OPEN, &dev->status); time = usb_wait_anchor_empty_timeout(&dev->tx_submitted, UNLINK_TIMEOUT_MS); @@ -575,7 +624,7 @@ static unsigned int rmnet_ctl_poll(struct file *file, poll_table *wait) return POLLERR; poll_wait(file, &dev->read_wait_queue, wait); - if (!is_dev_connected(dev)) { + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) { dev_dbg(dev->devicep, "%s: Device not connected\n", __func__); return POLLERR; @@ -592,6 +641,7 @@ static ssize_t rmnet_ctl_read(struct file *file, char __user *buf, size_t count, { int retval = 0; int bytes_to_read; + unsigned int hdr_len = 0; struct rmnet_ctrl_dev *dev; struct ctrl_pkt_list_elem *list_elem = NULL; unsigned long flags; @@ -603,7 +653,7 @@ static ssize_t rmnet_ctl_read(struct file *file, char __user *buf, size_t count, DBG("%s: Read from %s\n", __func__, dev->name); ctrl_read: - if (!is_dev_connected(dev)) { + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) { dev_dbg(dev->devicep, "%s: Device not connected\n", __func__); return -ENETRESET; @@ -613,8 +663,8 @@ static ssize_t rmnet_ctl_read(struct file *file, char __user *buf, size_t count, spin_unlock_irqrestore(&dev->rx_lock, flags); retval = wait_event_interruptible(dev->read_wait_queue, - !list_empty(&dev->rx_list) || - !is_dev_connected(dev)); + !list_empty(&dev->rx_list) || + !test_bit(RMNET_CTRL_DEV_READY, &dev->status)); if (retval < 0) return retval; @@ -632,7 +682,10 @@ static ssize_t rmnet_ctl_read(struct file *file, char __user *buf, size_t count, } spin_unlock_irqrestore(&dev->rx_lock, flags); - if (copy_to_user(buf, list_elem->cpkt.data, bytes_to_read)) { + if (test_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status)) + hdr_len = sizeof(struct mux_hdr); + + if (copy_to_user(buf, list_elem->cpkt.data + hdr_len, bytes_to_read)) { dev_err(dev->devicep, "%s: copy_to_user failed for %s\n", __func__, dev->name); @@ -655,7 +708,10 @@ static ssize_t rmnet_ctl_write(struct file *file, const char __user * buf, size_t size, loff_t *pos) { int status; + size_t total_len; void *wbuf; + void *actual_data; + struct ctrl_pkt *cpkt; struct rmnet_ctrl_dev *dev = file->private_data; if (!dev) @@ -664,26 +720,46 @@ static ssize_t rmnet_ctl_write(struct file *file, const char __user * buf, if (size <= 0) return -EINVAL; - if (!is_dev_connected(dev)) + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) return -ENETRESET; DBG("%s: Writing %i bytes on %s\n", __func__, size, dev->name); - wbuf = kmalloc(size , GFP_KERNEL); + total_len = size; + + if (test_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status)) + total_len += sizeof(struct mux_hdr) + MAX_PAD_BYTES(4); + + wbuf = kmalloc(total_len , GFP_KERNEL); if (!wbuf) return -ENOMEM; - status = copy_from_user(wbuf , buf, size); + cpkt = kmalloc(sizeof(struct ctrl_pkt), GFP_KERNEL); + if (!cpkt) { + kfree(wbuf); + return -ENOMEM; + } + actual_data = cpkt->data = wbuf; + cpkt->data_size = total_len; + cpkt->ctxt = dev; + + if (test_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status)) { + actual_data = wbuf + sizeof(struct mux_hdr); + rmnet_usb_ctrl_mux(dev->ch_id, cpkt); + } + + status = copy_from_user(actual_data, buf, size); if (status) { dev_err(dev->devicep, "%s: Unable to copy data from userspace %d\n", __func__, status); kfree(wbuf); + kfree(cpkt); return status; } DUMP_BUFFER("Write: ", size, buf); - status = rmnet_usb_ctrl_write(dev, wbuf, size); + status = rmnet_usb_ctrl_write(dev, cpkt, size); if (status == size) return size; @@ -783,10 +859,18 @@ static const struct file_operations ctrldev_fops = { .poll = rmnet_ctl_poll, }; +void rmnet_usb_ctrl_cleanup(struct rmnet_ctrl_dev *dev) +{ + if (dev) { + usb_free_urb(dev->inturb); + kfree(dev->intbuf); + } +} + int rmnet_usb_ctrl_probe(struct usb_interface *intf, struct usb_host_endpoint *int_in, unsigned long rmnet_devnum, - struct rmnet_ctrl_dev **ctrldev) + unsigned long *data) { struct rmnet_ctrl_dev *dev = NULL; u16 wMaxPacketSize; @@ -811,34 +895,16 @@ int rmnet_usb_ctrl_probe(struct usb_interface *intf, dev->int_pipe = usb_rcvintpipe(udev, int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - mutex_lock(&dev->dev_lock); dev->intf = intf; - /*TBD: for now just update CD status*/ - dev->cbits_tolocal = ACM_CTRL_CD; + dev->id = rmnet_devnum; - /*send DTR high to modem*/ - dev->cbits_tomdm = ACM_CTRL_DTR; - mutex_unlock(&dev->dev_lock); - - dev->resp_available = false; dev->snd_encap_cmd_cnt = 0; dev->get_encap_resp_cnt = 0; dev->resp_avail_cnt = 0; dev->tx_ctrl_err_cnt = 0; dev->set_ctrl_line_state_cnt = 0; - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - USB_CDC_REQ_SET_CONTROL_LINE_STATE, - (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE), - dev->cbits_tomdm, - dev->intf->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, USB_CTRL_SET_TIMEOUT); - if (ret < 0) - return ret; - - dev->set_ctrl_line_state_cnt++; - dev->inturb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->inturb) { dev_err(dev->devicep, "Error allocating int urb\n"); @@ -875,11 +941,23 @@ int rmnet_usb_ctrl_probe(struct usb_interface *intf, usb_mark_last_busy(udev); ret = rmnet_usb_ctrl_start_rx(dev); - if (!ret) - dev->is_connected = true; + if (ret) { + usb_free_urb(dev->inturb); + kfree(dev->intbuf); + return ret; + } dev->claimed = true; - *ctrldev = dev; + + /*mux info is passed to data parameter*/ + if (*data) + set_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status); + + *data = (unsigned long)dev; + + set_bit(RMNET_CTRL_DEV_READY, &dev->status); + wake_up(&dev->open_wait_queue); + return 0; } @@ -887,11 +965,12 @@ void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *dev) { dev->claimed = false; + clear_bit(RMNET_CTRL_DEV_READY, &dev->status); + mutex_lock(&dev->dev_lock); /*TBD: for now just update CD status*/ dev->cbits_tolocal = ~ACM_CTRL_CD; dev->cbits_tomdm = ~ACM_CTRL_DTR; - dev->is_connected = false; mutex_unlock(&dev->dev_lock); wake_up(&dev->read_wait_queue); @@ -938,7 +1017,9 @@ static ssize_t rmnet_usb_ctrl_read_stats(struct file *file, char __user *ubuf, "mdm_wait_timeout: %u\n" "zlp_cnt: %u\n" "get_encap_failure_cnt %u\n" - "dev opened: %s\n", + "RMNET_CTRL_DEV_MUX_EN: %d\n" + "RMNET_CTRL_DEV_OPEN: %d\n" + "RMNET_CTRL_DEV_READY: %d\n", dev, dev->name, dev->snd_encap_cmd_cnt, dev->resp_avail_cnt, @@ -950,7 +1031,12 @@ static ssize_t rmnet_usb_ctrl_read_stats(struct file *file, char __user *ubuf, dev->mdm_wait_timeout, dev->zlp_cnt, dev->get_encap_failure_cnt, - dev->is_opened ? "OPEN" : "CLOSE"); + test_bit(RMNET_CTRL_DEV_MUX_EN, + &dev->status), + test_bit(RMNET_CTRL_DEV_OPEN, + &dev->status), + test_bit(RMNET_CTRL_DEV_READY, + &dev->status)); } } @@ -1059,6 +1145,8 @@ int rmnet_usb_ctrl_init(int no_rmnet_devs, int no_rmnet_insts_per_dev) return -ENOMEM; } + dev->ch_id = n; + mutex_init(&dev->dev_lock); spin_lock_init(&dev->rx_lock); init_waitqueue_head(&dev->read_wait_queue); diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c index c5861f7c6e4..5f0d342ea03 100644 --- a/drivers/net/usb/rmnet_usb_data.c +++ b/drivers/net/usb/rmnet_usb_data.c @@ -17,13 +17,36 @@ #include #include #include +#include #include #include -#include "rmnet_usb_ctrl.h" +#include "rmnet_usb.h" #define RMNET_DATA_LEN 2000 -#define HEADROOM_FOR_QOS 8 +#define RMNET_HEADROOM_W_MUX (sizeof(struct mux_hdr) + \ + sizeof(struct QMI_QOS_HDR_S)) +#define RMNET_HEADROOM sizeof(struct QMI_QOS_HDR_S) +#define RMNET_TAILROOM MAX_PAD_BYTES(4); + +static unsigned int no_rmnet_devs = 1; +module_param(no_rmnet_devs, uint, S_IRUGO | S_IWUSR); + +unsigned int no_rmnet_insts_per_dev = 4; +module_param(no_rmnet_insts_per_dev, uint, S_IRUGO | S_IWUSR); + +/* + * To support mux on multiple devices, bit position represents device + * and value represnts if mux is enabled or disabled. + * e.g. bit 0: mdm over HSIC, bit1: mdm over hsusb + */ +static unsigned long mux_enabled; +module_param(mux_enabled, ulong, S_IRUGO | S_IWUSR); + +static unsigned int no_fwd_rmnet_links; +module_param(no_fwd_rmnet_links, uint, S_IRUGO | S_IWUSR); + +struct usbnet *unet_list[TOTAL_RMNET_DEV_COUNT]; /* net device name prefixes, indexed by driver_info->data */ static const char * const rmnet_names[] = { @@ -31,6 +54,11 @@ static const char * const rmnet_names[] = { "rmnet2_usb%d", }; +/* net device reverse link name prefixes, indexed by driver_info->data */ +static const char * const rev_rmnet_names[] = { + "rev_rmnet_usb%d", + "rev_rmnet2_usb%d", +}; static int data_msg_dbg_mask; enum { @@ -86,12 +114,6 @@ static DEVICE_ATTR(dbg_mask, 0644, dbg_mask_show, dbg_mask_store); #define DBG1(x...) DBG(DEBUG_MASK_LVL1, x) #define DBG2(x...) DBG(DEBUG_MASK_LVL2, x) -static unsigned int no_rmnet_devs = 1; -module_param(no_rmnet_devs, uint, S_IRUGO | S_IWUSR); - -static unsigned int no_rmnet_insts_per_dev = 4; -module_param(no_rmnet_insts_per_dev, uint, S_IRUGO | S_IWUSR); - static int rmnet_data_start(void); static bool rmnet_data_init; @@ -120,43 +142,82 @@ static struct kernel_param_ops rmnet_init_ops = { module_param_cb(rmnet_data_init, &rmnet_init_ops, &rmnet_data_init, S_IRUGO | S_IWUSR); -static void rmnet_usb_setup(struct net_device *); +static void rmnet_usb_setup(struct net_device *, int mux_enabled); static int rmnet_ioctl(struct net_device *, struct ifreq *, int); static int rmnet_usb_suspend(struct usb_interface *iface, pm_message_t message) { - struct usbnet *unet; + struct usbnet *unet = usb_get_intfdata(iface); struct rmnet_ctrl_dev *dev; + int i, n, rdev_cnt, unet_id; + int retval = 0; - unet = usb_get_intfdata(iface); + rdev_cnt = unet->data[4] ? no_rmnet_insts_per_dev : 1; - dev = (struct rmnet_ctrl_dev *)unet->data[1]; + for (n = 0; n < rdev_cnt; n++) { + unet_id = n + unet->driver_info->data * no_rmnet_insts_per_dev; + unet = + unet->data[4] ? unet_list[unet_id] : usb_get_intfdata(iface); - if (work_busy(&dev->get_encap_work)) - return -EBUSY; + dev = (struct rmnet_ctrl_dev *)unet->data[1]; + spin_lock_irq(&unet->txq.lock); + if (work_busy(&dev->get_encap_work) || unet->txq.qlen) { + spin_unlock_irq(&unet->txq.lock); + retval = -EBUSY; + goto abort_suspend; + } - if (usbnet_suspend(iface, message)) - return -EBUSY; + set_bit(EVENT_DEV_ASLEEP, &unet->flags); + spin_unlock_irq(&unet->txq.lock); + } - usb_kill_anchored_urbs(&dev->rx_submitted); + for (n = 0; n < rdev_cnt; n++) { + unet_id = n + unet->driver_info->data * no_rmnet_insts_per_dev; + unet = + unet->data[4] ? unet_list[unet_id] : usb_get_intfdata(iface); + + dev = (struct rmnet_ctrl_dev *)unet->data[1]; + usb_kill_anchored_urbs(&dev->rx_submitted); + netif_device_detach(unet->net); + usbnet_terminate_urbs(unet); + netif_device_attach(unet->net); + } return 0; + +abort_suspend: + for (i = 0; i < n; i++) { + unet_id = i + unet->driver_info->data * no_rmnet_insts_per_dev; + unet = + unet->data[4] ? unet_list[unet_id] : usb_get_intfdata(iface); + spin_lock_irq(&unet->txq.lock); + clear_bit(EVENT_DEV_ASLEEP, &unet->flags); + spin_unlock_irq(&unet->txq.lock); + } + return retval; } static int rmnet_usb_resume(struct usb_interface *iface) { - int retval = 0; - struct usbnet *unet; + struct usbnet *unet = usb_get_intfdata(iface); struct rmnet_ctrl_dev *dev; + int n, rdev_cnt, unet_id; - unet = usb_get_intfdata(iface); + rdev_cnt = unet->data[4] ? no_rmnet_insts_per_dev : 1; - dev = (struct rmnet_ctrl_dev *)unet->data[1]; + for (n = 0; n < rdev_cnt; n++) { + unet_id = n + unet->driver_info->data * no_rmnet_insts_per_dev; + unet = + unet->data[4] ? unet_list[unet_id] : usb_get_intfdata(iface); - usbnet_resume(iface); - retval = rmnet_usb_ctrl_start_rx(dev); + dev = (struct rmnet_ctrl_dev *)unet->data[1]; + rmnet_usb_ctrl_start_rx(dev); + usb_set_intfdata(iface, unet); + unet->suspend_count = 1; + usbnet_resume(iface); + } - return retval; + return 0; } static int rmnet_usb_bind(struct usbnet *usbnet, struct usb_interface *iface) @@ -169,6 +230,9 @@ static int rmnet_usb_bind(struct usbnet *usbnet, struct usb_interface *iface) int status = 0; int i; int numends; + bool mux; + + mux = test_bit(info->data, &mux_enabled); numends = iface->cur_altsetting->desc.bNumEndpoints; for (i = 0; i < numends; i++) { @@ -199,13 +263,71 @@ static int rmnet_usb_bind(struct usbnet *usbnet, struct usb_interface *iface) usbnet->status = int_in; /*change name of net device to rmnet_usbx here*/ - strlcpy(usbnet->net->name, rmnet_names[info->data], IFNAMSIZ); - - /*TBD: update rx_urb_size, curently set to eth frame len by usbnet*/ + if (mux && (info->in > no_fwd_rmnet_links)) + strlcpy(usbnet->net->name, rev_rmnet_names[info->data], + IFNAMSIZ); + else + strlcpy(usbnet->net->name, rmnet_names[info->data], + IFNAMSIZ); + + if (mux) + usbnet->rx_urb_size = usbnet->hard_mtu + sizeof(struct mux_hdr) + + MAX_PAD_BYTES(4); out: return status; } +static int rmnet_usb_data_dmux(struct sk_buff *skb, struct urb *rx_urb) +{ + struct mux_hdr *hdr; + size_t pad_len; + size_t total_len; + unsigned int mux_id; + + hdr = (struct mux_hdr *)skb->data; + mux_id = hdr->mux_id; + if (!mux_id || mux_id > no_rmnet_insts_per_dev) { + pr_err_ratelimited("%s: Invalid data channel id %u.\n", + __func__, mux_id); + return -EINVAL; + } + + pad_len = hdr->padding_info >> MUX_PAD_SHIFT; + if (pad_len > MAX_PAD_BYTES(4)) { + pr_err_ratelimited("%s: Invalid pad len %d\n", + __func__, pad_len); + return -EINVAL; + } + + total_len = le16_to_cpu(hdr->pkt_len_w_padding); + if (!total_len || !(total_len - pad_len)) { + pr_err_ratelimited("%s: Invalid pkt length %d\n", __func__, + total_len); + return -EINVAL; + } + + skb->data = (unsigned char *)(hdr + 1); + rx_urb->actual_length = total_len - pad_len; + + return mux_id - 1; +} + +static void rmnet_usb_data_mux(struct sk_buff *skb, unsigned int id) +{ + struct mux_hdr *hdr; + size_t len; + + hdr = (struct mux_hdr *)skb_push(skb, sizeof(struct mux_hdr)); + hdr->mux_id = id + 1; + len = skb->len - sizeof(struct mux_hdr); + + /*add padding if len is not 4 byte aligned*/ + skb_put(skb, ALIGN(len, 4) - len); + + hdr->pkt_len_w_padding = cpu_to_le16(skb->len - sizeof(struct mux_hdr)); + hdr->padding_info = (ALIGN(len, 4) - len) << MUX_PAD_SHIFT; +} + static struct sk_buff *rmnet_usb_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { @@ -219,6 +341,9 @@ static struct sk_buff *rmnet_usb_tx_fixup(struct usbnet *dev, qmih->flow_id = skb->mark; } + if (dev->data[4]) + rmnet_usb_data_mux(skb, dev->data[3]); + DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n", dev->net->name, dev->net->stats.tx_packets, skb->len, skb->mark); @@ -247,10 +372,35 @@ static __be16 rmnet_ip_type_trans(struct sk_buff *skb, return protocol; } -static int rmnet_usb_rx_fixup(struct usbnet *dev, - struct sk_buff *skb) +static void rmnet_usb_rx_complete(struct urb *rx_urb) { + struct sk_buff *skb = (struct sk_buff *) rx_urb->context; + struct skb_data *entry = (struct skb_data *) skb->cb; + struct usbnet *dev = entry->dev; + unsigned int unet_offset; + unsigned int unet_id; + int mux_id; + + unet_offset = dev->driver_info->data * no_rmnet_insts_per_dev; + + if (!rx_urb->status && dev->data[4]) { + mux_id = rmnet_usb_data_dmux(skb, rx_urb); + if (mux_id < 0) { + /*resubmit urb and free skb in rx_complete*/ + rx_urb->status = -EINVAL; + } else { + /*map urb to actual network iface based on mux id*/ + unet_id = unet_offset + mux_id; + skb->dev = unet_list[unet_id]->net; + entry->dev = unet_list[unet_id]; + } + } + rx_complete(rx_urb); +} + +static int rmnet_usb_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ if (test_bit(RMNET_MODE_LLP_IP, &dev->data[0])) skb->protocol = rmnet_ip_type_trans(skb, dev->net); else /*set zero for eth mode*/ @@ -311,7 +461,6 @@ static const struct net_device_ops rmnet_usb_ops_ip = { .ndo_validate_addr = 0, }; - static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct usbnet *unet = netdev_priv(dev); @@ -347,7 +496,6 @@ static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) dev->mtu = prev_mtu; dev->addr_len = 0; dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); - dev->needed_headroom = HEADROOM_FOR_QOS; dev->netdev_ops = &rmnet_usb_ops_ip; clear_bit(RMNET_MODE_LLP_ETH, &unet->data[0]); set_bit(RMNET_MODE_LLP_IP, &unet->data[0]); @@ -406,7 +554,7 @@ static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return rc; } -static void rmnet_usb_setup(struct net_device *dev) +static void rmnet_usb_setup(struct net_device *dev, int mux_enabled) { /* Using Ethernet mode by default */ dev->netdev_ops = &rmnet_usb_ops_ether; @@ -414,7 +562,15 @@ static void rmnet_usb_setup(struct net_device *dev) /* set this after calling ether_setup */ dev->mtu = RMNET_DATA_LEN; - dev->needed_headroom = HEADROOM_FOR_QOS; + if (mux_enabled) { + dev->needed_headroom = RMNET_HEADROOM_W_MUX; + + /*max pad bytes for 4 byte alignment*/ + dev->needed_tailroom = RMNET_TAILROOM; + } else { + dev->needed_headroom = RMNET_HEADROOM; + } + random_ether_addr(dev->dev_addr); dev->watchdog_timeo = 1000; /* 10 seconds? */ } @@ -444,7 +600,6 @@ static int rmnet_usb_data_status(struct seq_file *s, void *unused) seq_printf(s, "tx errors: %lu\n", unet->net->stats.tx_errors); seq_printf(s, "tx packets: %lu\n", unet->net->stats.tx_packets); seq_printf(s, "tx bytes: %lu\n", unet->net->stats.tx_bytes); - seq_printf(s, "suspend count: %d\n", unet->suspend_count); seq_printf(s, "EVENT_DEV_OPEN: %d\n", test_bit(EVENT_DEV_OPEN, &unet->flags)); seq_printf(s, "EVENT_TX_HALT: %d\n", @@ -499,8 +654,10 @@ static void rmnet_usb_data_debugfs_cleanup(struct usbnet *unet) { struct dentry *root = (struct dentry *)unet->data[2]; - debugfs_remove_recursive(root); - unet->data[2] = 0; + if (root) { + debugfs_remove_recursive(root); + unet->data[2] = 0; + } } static int rmnet_usb_probe(struct usb_interface *iface, @@ -510,6 +667,10 @@ static int rmnet_usb_probe(struct usb_interface *iface, struct driver_info *info = (struct driver_info *)prod->driver_info; struct usb_device *udev; int status = 0; + unsigned int i, unet_id, rdev_cnt, n = 0; + bool mux; + + udev = interface_to_usbdev(iface); if (iface->num_altsetting != 1) { dev_err(&iface->dev, "%s invalid num_altsetting %u\n", @@ -518,34 +679,63 @@ static int rmnet_usb_probe(struct usb_interface *iface, goto out; } - status = usbnet_probe(iface, prod); - if (status < 0) { - dev_err(&iface->dev, "usbnet_probe failed %d\n", status); - goto out; - } - unet = usb_get_intfdata(iface); + mux = test_bit(info->data, &mux_enabled); + rdev_cnt = mux ? no_rmnet_insts_per_dev : 1; + info->in = 0; + + for (n = 0; n < rdev_cnt; n++) { + + /* Use this filed to increment device count this will be + * used by bind to determin the forward link and reverse + * link network interface names. + */ + info->in++; + status = usbnet_probe(iface, prod); + if (status < 0) { + dev_err(&iface->dev, "usbnet_probe failed %d\n", + status); + goto out; + } - /*set rmnet operation mode to eth by default*/ - set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]); + unet_id = n + info->data * no_rmnet_insts_per_dev; - /*update net device*/ - rmnet_usb_setup(unet->net); + unet_list[unet_id] = unet = usb_get_intfdata(iface); - /*create /sys/class/net/rmnet_usbx/dbg_mask*/ - status = device_create_file(&unet->net->dev, &dev_attr_dbg_mask); - if (status) - goto out; + /*store mux id for later access*/ + unet->data[3] = n; - status = rmnet_usb_ctrl_probe(iface, unet->status, info->data, - (struct rmnet_ctrl_dev **)&unet->data[1]); - if (status) - goto out; + /*save mux info for control and usbnet devices*/ + unet->data[1] = unet->data[4] = mux; + + /*set rmnet operation mode to eth by default*/ + set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]); - status = rmnet_usb_data_debugfs_init(unet); - if (status) - dev_dbg(&iface->dev, "mode debugfs file is not available\n"); + /*update net device*/ + rmnet_usb_setup(unet->net, mux); - udev = unet->udev; + /*create /sys/class/net/rmnet_usbx/dbg_mask*/ + status = device_create_file(&unet->net->dev, + &dev_attr_dbg_mask); + if (status) { + free_netdev(unet->net); + usb_put_dev(udev); + goto out; + } + + status = rmnet_usb_ctrl_probe(iface, unet->status, info->data, + &unet->data[1]); + if (status) { + device_remove_file(&unet->net->dev, &dev_attr_dbg_mask); + free_netdev(unet->net); + usb_put_dev(udev); + goto out; + } + + status = rmnet_usb_data_debugfs_init(unet); + if (status) + dev_dbg(&iface->dev, + "mode debugfs file is not available\n"); + } usb_enable_autosuspend(udev); @@ -559,52 +749,67 @@ static int rmnet_usb_probe(struct usb_interface *iface, pm_runtime_set_autosuspend_delay(&udev->parent->dev, 200); } + return 0; + out: + for (i = 0; i < n; i++) { + unet_id = i + info->data * no_rmnet_insts_per_dev; + rmnet_usb_ctrl_cleanup( + (struct rmnet_ctrl_dev *)unet_list[unet_id]->data[1]); + device_remove_file(&unet_list[unet_id]->net->dev, + &dev_attr_dbg_mask); + free_netdev(unet_list[unet_id]->net); + usb_put_dev(udev); + } + return status; } static void rmnet_usb_disconnect(struct usb_interface *intf) { - struct usbnet *unet; + struct usbnet *unet = usb_get_intfdata(intf); struct rmnet_ctrl_dev *dev; + unsigned int n, rdev_cnt, unet_id; - unet = usb_get_intfdata(intf); - if (!unet) { - dev_err(&intf->dev, "%s:data device not found\n", __func__); - return; - } + rdev_cnt = unet->data[4] ? no_rmnet_insts_per_dev : 1; device_set_wakeup_enable(&unet->udev->dev, 0); - rmnet_usb_data_debugfs_cleanup(unet); - dev = (struct rmnet_ctrl_dev *)unet->data[1]; - if (!dev) { - dev_err(&intf->dev, "%s:ctrl device not found\n", __func__); - return; + for (n = 0; n < rdev_cnt; n++) { + unet_id = n + unet->driver_info->data * no_rmnet_insts_per_dev; + unet = + unet->data[4] ? unet_list[unet_id] : usb_get_intfdata(intf); + device_remove_file(&unet->net->dev, &dev_attr_dbg_mask); + + dev = (struct rmnet_ctrl_dev *)unet->data[1]; + rmnet_usb_ctrl_disconnect(dev); + unet->data[0] = 0; + unet->data[1] = 0; + rmnet_usb_data_debugfs_cleanup(unet); + usb_set_intfdata(intf, unet); + usbnet_disconnect(intf); + unet_list[unet_id] = NULL; } - unet->data[0] = 0; - unet->data[1] = 0; - rmnet_usb_ctrl_disconnect(dev); - device_remove_file(&unet->net->dev, &dev_attr_dbg_mask); - usbnet_disconnect(intf); } -static const struct driver_info rmnet_info = { +static struct driver_info rmnet_info = { .description = "RmNET net device", .flags = FLAG_SEND_ZLP, .bind = rmnet_usb_bind, .tx_fixup = rmnet_usb_tx_fixup, .rx_fixup = rmnet_usb_rx_fixup, + .rx_complete = rmnet_usb_rx_complete, .manage_power = rmnet_usb_manage_power, .data = 0, }; -static const struct driver_info rmnet_usb_info = { +static struct driver_info rmnet_usb_info = { .description = "RmNET net device", .flags = FLAG_SEND_ZLP, .bind = rmnet_usb_bind, .tx_fixup = rmnet_usb_tx_fixup, .rx_fixup = rmnet_usb_rx_fixup, + .rx_complete = rmnet_usb_rx_complete, .manage_power = rmnet_usb_manage_power, .data = 1, }; @@ -643,6 +848,9 @@ static const struct usb_device_id vidpids[] = { { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x904c, 8), .driver_info = (unsigned long)&rmnet_info, }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9075, 6), /*mux over hsic mdm*/ + .driver_info = (unsigned long)&rmnet_info, + }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9079, 5), .driver_info = (unsigned long)&rmnet_usb_info, }, diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index e9130f6757e..d7c5df17f03 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -87,7 +87,7 @@ static u8 node_id [ETH_ALEN]; static const char driver_name [] = "usbnet"; -static struct workqueue_struct *usbnet_wq; +struct workqueue_struct *usbnet_wq; static DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup); @@ -344,12 +344,11 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent); /*-------------------------------------------------------------------------*/ -static void rx_complete (struct urb *urb); - static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) { struct sk_buff *skb; struct skb_data *entry; + usb_complete_t complete_fn; int retval = 0; unsigned long lockflags; size_t size = dev->rx_urb_size; @@ -370,8 +369,13 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) entry->dev = dev; entry->length = 0; + if (dev->driver_info->rx_complete) + complete_fn = dev->driver_info->rx_complete; + else + complete_fn = rx_complete; + usb_fill_bulk_urb (urb, dev->udev, dev->in, - skb->data, size, rx_complete, skb); + skb->data, size, complete_fn, skb); spin_lock_irqsave (&dev->rxq.lock, lockflags); @@ -445,7 +449,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) /*-------------------------------------------------------------------------*/ -static void rx_complete (struct urb *urb) +void rx_complete(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; @@ -531,6 +535,7 @@ static void rx_complete (struct urb *urb) } netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n"); } +EXPORT_SYMBOL_GPL(rx_complete); static void intr_complete (struct urb *urb) { @@ -666,7 +671,7 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); /*-------------------------------------------------------------------------*/ // precondition: never called in_interrupt -static void usbnet_terminate_urbs(struct usbnet *dev) +void usbnet_terminate_urbs(struct usbnet *dev) { DECLARE_WAITQUEUE(wait, current); int temp; @@ -691,6 +696,7 @@ static void usbnet_terminate_urbs(struct usbnet *dev) dev->wait = NULL; remove_wait_queue(&unlink_wakeup, &wait); } +EXPORT_SYMBOL_GPL(usbnet_terminate_urbs); int usbnet_stop (struct net_device *net) { diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 72f5c960be1..642c4fe0b8a 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -131,6 +131,9 @@ struct driver_info { /* link reset handling, called from defer_kevent */ int (*link_reset)(struct usbnet *); + /*in case if usbnet wrapper wants to override rx_complete()*/ + void (*rx_complete) (struct urb *); + /* fixup rx packet (strip framing) */ int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); @@ -228,5 +231,7 @@ extern u32 usbnet_get_msglevel(struct net_device *); extern void usbnet_set_msglevel(struct net_device *, u32); extern void usbnet_get_drvinfo(struct net_device *, struct ethtool_drvinfo *); extern int usbnet_nway_reset(struct net_device *net); +extern void usbnet_terminate_urbs(struct usbnet *dev); +extern void rx_complete(struct urb *urb); #endif /* __LINUX_USB_USBNET_H */ From cde3cfe40538aab4b417fe603cad10a1cbdbd63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20H=C3=A4nel?= Date: Tue, 4 Sep 2012 12:28:40 +0200 Subject: [PATCH 2344/2357] mobicore: New branch incorporating QC code review suggestions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Solved various naming issues, removed comments. Many of the changes already present in master. Signed-off-by: Lukas Hänel Change-Id: I7c068154e5af5ae40dc2675afb67a5f6835d9d05 [hnamgund@codeaurora: align platform.h with other branches, reformat commit text, resolve trivial merge conflicts] Signed-off-by: Hariprasad Dhalinarasimha Acked-by: Tony Hamilton --- drivers/gud/Kconfig | 6 +- drivers/gud/mobicore_driver/build_tag.h | 8 +- drivers/gud/mobicore_driver/logging.c | 234 +- drivers/gud/mobicore_driver/main.c | 2408 +++++++---------- drivers/gud/mobicore_driver/mc_drv_module.h | 231 +- .../mobicore_driver/mc_drv_module_android.h | 18 +- .../mobicore_driver/mc_drv_module_fastcalls.h | 116 +- .../mobicore_driver/mc_drv_module_linux_api.h | 187 -- .../platforms/msm8960_surf_std/platform.h | 34 +- .../public/mc_drv_module_api.h | 202 +- .../mobicore_driver/public/mc_kernel_api.h | 113 +- drivers/gud/mobicore_driver/public/version.h | 11 +- drivers/gud/mobicore_kernelapi/clientlib.c | 678 +++-- drivers/gud/mobicore_kernelapi/common.h | 92 +- drivers/gud/mobicore_kernelapi/connection.c | 129 +- drivers/gud/mobicore_kernelapi/connection.h | 147 +- drivers/gud/mobicore_kernelapi/device.c | 158 +- drivers/gud/mobicore_kernelapi/device.h | 137 +- .../gud/mobicore_kernelapi/include/mcinq.h | 100 +- .../gud/mobicore_kernelapi/include/mcuuid.h | 27 +- drivers/gud/mobicore_kernelapi/main.c | 79 +- .../public/mobicore_driver_api.h | 580 ++-- .../public/mobicore_driver_cmd.h | 52 +- drivers/gud/mobicore_kernelapi/session.c | 163 +- drivers/gud/mobicore_kernelapi/session.h | 159 +- drivers/gud/mobicore_kernelapi/wsm.h | 34 +- 26 files changed, 2477 insertions(+), 3626 deletions(-) delete mode 100644 drivers/gud/mobicore_driver/mc_drv_module_linux_api.h diff --git a/drivers/gud/Kconfig b/drivers/gud/Kconfig index 3a241b76516..929ba01debb 100644 --- a/drivers/gud/Kconfig +++ b/drivers/gud/Kconfig @@ -3,7 +3,6 @@ # config MOBICORE_SUPPORT tristate "Linux MobiCore Support" - #depends on ARM_TRUSTZONE ---help--- Enable Linux Kernel MobiCore Support @@ -12,14 +11,14 @@ config MOBICORE_DEBUG depends on MOBICORE_SUPPORT ---help--- Enable Debug mode in the MobiCore Driver. - It enables printing information about mobicore operations + It enables printing information about MobiCore operations config MOBICORE_VERBOSE bool "MobiCore Module verbose debug mode" depends on MOBICORE_DEBUG ---help--- Enable Verbose Debug mode in the MobiCore Driver. - It enables printing extra information about mobicore operations + It enables printing extra information about MobiCore operations Beware: this is only useful for debuging deep in the driver because it prints too much logs @@ -29,4 +28,3 @@ config MOBICORE_API depends on MOBICORE_SUPPORT ---help--- Enable Linux Kernel MobiCore API - diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/mobicore_driver/build_tag.h index 43541bbe275..79404fdf4c9 100644 --- a/drivers/gud/mobicore_driver/build_tag.h +++ b/drivers/gud/mobicore_driver/build_tag.h @@ -1,6 +1,5 @@ -/** - * - * +/* + * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,4 +25,5 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define MOBICORE_COMPONENT_BUILD_TAG "*** GC_MSM8960_Release_V010 ###" +#define MOBICORE_COMPONENT_BUILD_TAG \ + "*** Build by haenellu@n500956-ubuntu, svn@r19078 ###" diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/mobicore_driver/logging.c index eb44c8ad7ee..a1da6e2bcbf 100644 --- a/drivers/gud/mobicore_driver/logging.c +++ b/drivers/gud/mobicore_driver/logging.c @@ -1,108 +1,102 @@ -/** MobiCore driver module.(interface to the secure world SWD) - * @addtogroup MCD_MCDIMPL_KMOD_LOGGING MobiCore Driver Logging Subsystem. - * @ingroup MCD_MCDIMPL_KMOD - * @{ - * @file +/* * MobiCore Driver Logging Subsystem. + * * The logging subsytem provides the interface between the Mobicore trace * buffer and the Linux log * - * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include +#include +#include +#include +#include +#include + #include "mc_drv_module.h" -#include "mc_drv_module_linux_api.h" #include "mc_drv_module_fastcalls.h" /* Default len of the log ring buffer 256KB*/ -#define LOG_BUF_SIZE (64 * PAGE_SIZE) +#define LOG_BUF_SIZE (64 * PAGE_SIZE) /* Max Len of a log line for printing */ -#define LOG_LINE_SIZE 256 +#define LOG_LINE_SIZE 256 static uint32_t log_size = LOG_BUF_SIZE; + module_param(log_size, uint, 0); -MODULE_PARM_DESC(log_size, " Size of the MobiCore log ringbuffer " - "(or 256KB default)."); +MODULE_PARM_DESC(log_size, " Size of the log ringbuffer (or 256KB default)."); -/*----------------------------------------------------------------------------*/ /* Definitions for log version 2 */ -#define LOG_TYPE_MASK (0x0007) -#define LOG_TYPE_CHAR 0 -#define LOG_TYPE_INTEGER 1 +#define LOG_TYPE_MASK (0x0007) +#define LOG_TYPE_CHAR 0 +#define LOG_TYPE_INTEGER 1 /* Field length */ -#define LOG_LENGTH_MASK (0x00F8) -#define LOG_LENGTH_SHIFT 3 +#define LOG_LENGTH_MASK (0x00F8) +#define LOG_LENGTH_SHIFT 3 /* Extra attributes */ -#define LOG_EOL (0x0100) -#define LOG_INTEGER_DECIMAL (0x0200) -#define LOG_INTEGER_SIGNED (0x0400) +#define LOG_EOL (0x0100) +#define LOG_INTEGER_DECIMAL (0x0200) +#define LOG_INTEGER_SIGNED (0x0400) struct logmsg_struct { - /* Type and format of data */ - uint16_t ctrl; - /* Unique value for each event source */ - uint16_t source; - /* Value, if any */ - uint32_t log_data; + uint16_t ctrl; /* Type and format of data */ + uint16_t source; /* Unique value for each event source */ + uint32_t log_data; /* Value, if any */ }; -/** MobiCore log previous position */ -static uint32_t log_pos; -/** MobiCore log buffer structure */ -static struct mc_trace_buf *log_buf; -/** Log Thread task structure */ -struct task_struct *log_thread; -/** Log Line buffer */ -static char *log_line; - -static void log_msg(struct logmsg_struct *msg); +static uint32_t log_pos; /* MobiCore log previous position */ +static struct mc_trace_buf *log_buf; /* MobiCore log buffer structure */ +struct task_struct *log_thread; /* Log Thread task structure */ +static char *log_line; /* Log Line buffer */ +static uint32_t log_line_len; /* Log Line buffer current len */ -/*----------------------------------------------------------------------------*/ static void log_eol(void) { if (!strnlen(log_line, LOG_LINE_SIZE)) return; - printk(KERN_INFO "%s\n", log_line); + dev_info(mcd, "%s\n", log_line); + log_line_len = 0; log_line[0] = 0; } -/*----------------------------------------------------------------------------*/ -/** - * Put a char to the log line if there is enough space if not then also - * output the line. Assume nobody else is updating the line! */ + +/* + * Collect chars in log_line buffer and output the buffer when it is full. + * No locking needed because only "mobicore_log" thread updates this buffer. + */ static void log_char(char ch) { - uint32_t len; if (ch == '\n' || ch == '\r') { log_eol(); return; } - if (strnlen(log_line, LOG_LINE_SIZE) >= LOG_LINE_SIZE - 1) { - printk(KERN_INFO "%s\n", log_line); + if (log_line_len >= LOG_LINE_SIZE - 1) { + dev_info(mcd, "%s\n", log_line); + log_line_len = 0; log_line[0] = 0; } - len = strnlen(log_line, LOG_LINE_SIZE); - log_line[len] = ch; - log_line[len + 1] = 0; + log_line[log_line_len] = ch; + log_line[log_line_len + 1] = 0; + log_line_len++; } -/*----------------------------------------------------------------------------*/ -/** - * Put a string to the log line if there is enough space if not then also - * output the line. Assume nobody else is updating the line! */ +/* + * Put a string to the log line. + */ static void log_str(const char *s) { int i; + for (i = 0; i < strnlen(s, LOG_LINE_SIZE); i++) log_char(s[i]); } -/*----------------------------------------------------------------------------*/ static uint32_t process_v1log(void) { char *last_char = log_buf->buff + log_buf->write_pos; @@ -116,44 +110,28 @@ static uint32_t process_v1log(void) return buff - log_buf->buff; } -/*----------------------------------------------------------------------------*/ -static uint32_t process_v2log(void) -{ - char *last_msg = log_buf->buff + log_buf->write_pos; - char *buff = log_buf->buff + log_pos; - while (buff != last_msg) { - log_msg((struct logmsg_struct *)buff); - buff += sizeof(struct logmsg_struct); - /* Wrap around */ - if (buff + sizeof(struct logmsg_struct) > - (char *)log_buf + log_size) - buff = log_buf->buff; - } - return buff - log_buf->buff; -} - -static const uint8_t HEX2ASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; +static const uint8_t HEX2ASCII[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; -/*----------------------------------------------------------------------------*/ static void dbg_raw_nro(uint32_t format, uint32_t value) { int digits = 1; uint32_t base = (format & LOG_INTEGER_DECIMAL) ? 10 : 16; int width = (format & LOG_LENGTH_MASK) >> LOG_LENGTH_SHIFT; - int negative = FALSE; + int negative = 0; uint32_t digit_base = 1; if ((format & LOG_INTEGER_SIGNED) != 0 && ((signed int)value) < 0) { - negative = TRUE; - value = (uint32_t)(-(signed int)value); - width--; + negative = 1; + value = (uint32_t)(-(signed int)value); + width--; } /* Find length and divider to get largest digit */ while (value / digit_base >= base) { - digit_base *= base; - digits++; + digit_base *= base; + digits++; } if (width > digits) { @@ -175,11 +153,11 @@ static void dbg_raw_nro(uint32_t format, uint32_t value) } } -/*----------------------------------------------------------------------------*/ static void log_msg(struct logmsg_struct *msg) { unsigned char msgtxt[5]; int mpos = 0; + switch (msg->ctrl & LOG_TYPE_MASK) { case LOG_TYPE_CHAR: { uint32_t ch; @@ -203,13 +181,23 @@ static void log_msg(struct logmsg_struct *msg) log_eol(); } -/*----------------------------------------------------------------------------*/ -static int log_worker(void *p) +static uint32_t process_v2log(void) { - if (log_buf == NULL) - return -EFAULT; + char *last_msg = log_buf->buff + log_buf->write_pos; + char *buff = log_buf->buff + log_pos; + while (buff != last_msg) { + log_msg((struct logmsg_struct *)buff); + buff += sizeof(struct logmsg_struct); + /* Wrap around */ + if ((buff + sizeof(struct logmsg_struct)) > + ((char *)log_buf + log_size)) + buff = log_buf->buff; + } + return buff - log_buf->buff; +} - /* The thread should have never started */ +static int log_worker(void *p) +{ if (log_buf == NULL) return -EFAULT; @@ -225,22 +213,22 @@ static int log_worker(void *p) log_pos = process_v2log(); break; default: - MCDRV_DBG_ERROR("Unknown Mobicore log data " - "version %d logging disabled.", - log_buf->version); + MCDRV_DBG_ERROR(mcd, "Unknown Mobicore log data"); + MCDRV_DBG_ERROR(mcd, "version %d logging disabled.", + log_buf->version); log_pos = log_buf->write_pos; - /* Stop the thread as we have no idea what - * happens next */ + /* + * Stop the thread as we have no idea what + * happens next + */ return -EFAULT; } } - MCDRV_DBG("Logging thread stopped!"); + MCDRV_DBG(mcd, "Logging thread stopped!"); return 0; } - -/*----------------------------------------------------------------------------*/ -/** +/* * Wakeup the log reader thread * This should be called from the places where calls into MobiCore have * generated some logs(eg, yield, SIQ...) @@ -253,9 +241,8 @@ void mobicore_log_read(void) wake_up_process(log_thread); } -/*----------------------------------------------------------------------------*/ -/** - * Setup mobicore kernel log. It assumes it's running on CORE 0! +/* + * Setup MobiCore kernel log. It assumes it's running on CORE 0! * The fastcall will complain is that is not the case! */ long mobicore_log_setup(void *data) @@ -263,64 +250,77 @@ long mobicore_log_setup(void *data) unsigned long phys_log_buf; union fc_generic fc_log; + long ret; log_pos = 0; log_buf = NULL; log_thread = NULL; log_line = NULL; + log_line_len = 0; /* Sanity check for the log size */ if (log_size < PAGE_SIZE) return -EFAULT; else - log_size = - get_nr_of_pages_for_buffer(NULL, log_size) * PAGE_SIZE; + log_size = PAGE_ALIGN(log_size); log_line = kzalloc(LOG_LINE_SIZE, GFP_KERNEL); if (IS_ERR(log_line)) { - MCDRV_DBG_ERROR("failed to allocate log line!"); + MCDRV_DBG_ERROR(mcd, "failed to allocate log line!"); return -ENOMEM; } log_thread = kthread_create(log_worker, NULL, "mobicore_log"); if (IS_ERR(log_thread)) { - MCDRV_DBG_ERROR("mobicore log thread creation failed!"); - return -EFAULT; + MCDRV_DBG_ERROR(mcd, "MobiCore log thread creation failed!"); + ret = -EFAULT; + goto mobicore_log_setup_log_line; } - log_pos = 0; + /* + * We are going to map this buffer into virtual address space in SWd. + * To reduce complexity there, we use a contiguous buffer. + */ log_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - size_to_order(log_size)); + get_order(log_size)); if (!log_buf) { - MCDRV_DBG_ERROR("Failed to get page for logger!"); - return -ENOMEM; + MCDRV_DBG_ERROR(mcd, "Failed to get page for logger!"); + ret = -ENOMEM; + goto mobicore_log_setup_kthread; } phys_log_buf = virt_to_phys(log_buf); memset(&fc_log, 0, sizeof(fc_log)); - fc_log.as_in.cmd = MC_FC_NWD_TRACE; + fc_log.as_in.cmd = MC_FC_NWD_TRACE; fc_log.as_in.param[0] = phys_log_buf; fc_log.as_in.param[1] = log_size; - MCDRV_DBG("fc_log virt=%p phys=%p ", log_buf, (void *)phys_log_buf); + MCDRV_DBG(mcd, "fc_log virt=%p phys=%p ", + log_buf, (void *)phys_log_buf); mc_fastcall(&fc_log); - MCDRV_DBG("fc_log out ret=0x%08x", fc_log.as_out.ret); + MCDRV_DBG(mcd, "fc_log out ret=0x%08x", fc_log.as_out.ret); + /* If the setup failed we must free the memory allocated */ if (fc_log.as_out.ret) { - MCDRV_DBG_ERROR("MobiCore shared traces setup failed!"); - kthread_stop(log_thread); - free_pages((unsigned long)log_buf, size_to_order(log_size)); - + MCDRV_DBG_ERROR(mcd, "MobiCore shared traces setup failed!"); + free_pages((unsigned long)log_buf, get_order(log_size)); log_buf = NULL; - log_thread = NULL; - return -EIO; + ret = -EIO; + goto mobicore_log_setup_kthread; } - MCDRV_DBG("fc_log Logger version %u\n", log_buf->version); + MCDRV_DBG(mcd, "fc_log Logger version %u\n", log_buf->version); return 0; + +mobicore_log_setup_kthread: + kthread_stop(log_thread); + log_thread = NULL; +mobicore_log_setup_log_line: + kfree(log_line); + log_line = NULL; + return ret; } -/*----------------------------------------------------------------------------*/ -/** +/* * Free kernel log componenets. * ATTN: We can't free the log buffer because it's also in use by MobiCore and * even if the module is unloaded MobiCore is still running. diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c index 8a8ea1e2e9e..bc47d8e3599 100644 --- a/drivers/gud/mobicore_driver/main.c +++ b/drivers/gud/mobicore_driver/main.c @@ -1,8 +1,6 @@ -/** MobiCore driver module.(interface to the secure world SWD) - * @addtogroup MCD_MCDIMPL_KMOD_IMPL - * @{ - * @file +/* * MobiCore Driver Kernel Module. + * * This module is written as a Linux device driver. * This driver represents the command proxy on the lowest layer, from the * secure world to the non secure world, and vice versa. @@ -12,16 +10,22 @@ * The access to the driver is possible with a file descriptor, * which has to be created by the fd = open(/dev/mobicore) command. * - * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include +#include +#include +#include +#include +#include +#include #include + #include "mc_drv_module.h" -#include "mc_drv_module_linux_api.h" #include "mc_drv_module_android.h" #include "mc_drv_module_fastcalls.h" #include "public/mc_kernel_api.h" @@ -29,89 +33,101 @@ /* Initial value for the daemon sempahore signaling */ #define DAEMON_SEM_VAL 0 -/** MobiCore interrupt context data */ +/* Define a MobiCore device structure for use with dev_debug() etc */ +struct device_driver mcd_debug_name = { + .name = "mcdrvkmod" +}; + +struct device mcd_debug_subname = { + .init_name = "", /* Set to 'mcd' at mc_init() time */ + .driver = &mcd_debug_name +}; + +struct device *mcd = &mcd_debug_subname; + +/* MobiCore interrupt context data */ static struct mc_drv_kmod_ctx mc_drv_kmod_ctx; -/** MobiCore MCI information */ +/* MobiCore MCI information */ static uint32_t mci_base; + /* -############################################################################# -## -## Convenience functions for Linux API functions -## -#############################################################################*/ + * ############################################################################# + * ## + * ## Convenience functions for Linux API functions + * ## + * ############################################################################# + */ static int goto_cpu0(void); static int goto_all_cpu(void) __attribute__ ((unused)); - -/*----------------------------------------------------------------------------*/ -static void init_and_add_to_list( - struct list_head *item, - struct list_head *list_head -) +static void init_and_add_to_list(struct list_head *item, + struct list_head *list_head) { INIT_LIST_HEAD(item); list_add(item, list_head); } -/*----------------------------------------------------------------------------*/ -/** check if CPU supports the ARM TrustZone Security Extensions - * @return int TRUE or FALSE */ -static int has_security_extensions( - void -) +/* + * check if CPU supports the ARM TrustZone Security Extensions + */ +static bool has_security_extensions(void) { u32 fea = 0; + asm volatile( "mrc p15, 0, %[fea], cr0, cr1, 0" : [fea]"=r" (fea)); - MCDRV_DBG_VERBOSE("CPU Features: 0x%X", fea); + MCDRV_DBG_VERBOSE(mcd, "CPU Features: 0x%X", fea); - /* If the CPU features ID has 0 for security features then the CPU + /* + * If the CPU features ID has 0 for security features then the CPU * doesn't support TrustZone at all! */ if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0) - return 0; + return false; - return 1; + return true; } -/*----------------------------------------------------------------------------*/ -/** check if running in secure mode - * @return int TRUE or FALSE */ -static int is_secure_mode( - void -) +/* + * check if running in secure mode + */ +static bool is_secure_mode(void) { - u32 cpsr = 0, nsacr = 0; + u32 cpsr = 0; + u32 nsacr = 0; + asm volatile( "mrc p15, 0, %[nsacr], cr1, cr1, 2\n" "mrs %[cpsr], cpsr\n" : [nsacr]"=r" (nsacr), [cpsr]"=r"(cpsr)); - MCDRV_DBG_VERBOSE("CPRS.M = set to 0x%X\n", cpsr & ARM_CPSR_MASK); - MCDRV_DBG_VERBOSE("SCR.NS = set to 0x%X\n", nsacr); + MCDRV_DBG_VERBOSE(mcd, "CPRS.M = set to 0x%X\n", cpsr & MODE_MASK); + MCDRV_DBG_VERBOSE(mcd, "SCR.NS = set to 0x%X\n", nsacr); - /* If the NSACR contains the reset value(=0) then most likely we are + /* + * If the NSACR contains the reset value(=0) then most likely we are * running in Secure MODE. * If the cpsr mode is set to monitor mode then we cannot load! */ - if (nsacr == 0 || ((cpsr & ARM_CPSR_MASK) == ARM_MONITOR_MODE)) - return 1; + if (nsacr == 0 || ((cpsr & MODE_MASK) == ARM_MONITOR_MODE)) + return true; - return 0; + return false; } -/*----------------------------------------------------------------------------*/ -/** check if userland caller is privileged (aka has "root" access rights). - @return int TRUE or FALSE */ -static int is_userland_caller_privileged( - void -) { - /* For some platforms we cannot run the Daemon as root - for Android +/* + * check if userland caller is privileged (aka has "root" access rights). + * return int 1 or 0 + */ +static int is_userland_caller_privileged(void) +{ + /* + * For some platforms we cannot run the Daemon as root - for Android * compliance tests it is not allowed, thus we assume the daemon is ran * as the system user. * In Android the system user for daemons has no particular capabilities @@ -121,89 +137,72 @@ static int is_userland_caller_privileged( * the Android source tree for all UIDs and their meaning: * http://android-dls.com/wiki/index.php?title=Android_UIDs_and_GIDs */ -#ifdef MC_ANDROID_UID_CHECK +#if defined(CONFIG_ANDROID) && defined(MC_ANDROID_UID_CHECK) return current_euid() <= AID_SYSTEM; #else - /* capable should cover all possibilities, root or sudo, uid checking - * was not very reliable */ + /* + * capable should cover all possibilities, root or sudo, uid checking + * was not very reliable + */ return capable(CAP_SYS_ADMIN); #endif } - - -/*----------------------------------------------------------------------------*/ -static void unlock_page_from_used_l2_table( - struct page *page -){ - /* REV axh: check if we should do this. */ +static void unlock_page_from_used_l2_table(struct page *page) +{ SetPageDirty(page); - - /* release page, old api was page_cache_release() */ ClearPageReserved(page); put_page(page); } -/*----------------------------------------------------------------------------*/ /* convert L2 PTE to page pointer */ -static struct page *l2_pte_to_page( - pte_t pte -) { - void *phys_page_addr = (void *)((unsigned int)pte & PAGE_MASK); - unsigned int pfn = addr_to_pfn(phys_page_addr); - struct page *page = pfn_to_page(pfn); +static struct page *l2_pte_to_page(pte_t pte) +{ + void *phys_page_addr = (void *)((unsigned int)pte & PAGE_MASK); + unsigned int pfn = (unsigned int)phys_page_addr >> PAGE_SHIFT; + struct page *page = pfn_to_page(pfn); + return page; } -/*----------------------------------------------------------------------------*/ /* convert page pointer to L2 PTE */ -static pte_t page_to_l2_pte( - struct page *page -) +static pte_t page_to_l2_pte(struct page *page) { - unsigned int pfn = page_to_pfn(page); - void *phys_addr = pfn_to_addr(pfn); - pte_t pte = (pte_t)((unsigned int)phys_addr & PAGE_MASK); + unsigned int pfn = page_to_pfn(page); + void *phys_addr = (void *)(pfn << PAGE_SHIFT); + pte_t pte = (pte_t)((unsigned int)phys_addr & PAGE_MASK); + return pte; } - -/*----------------------------------------------------------------------------*/ -static inline int lock_user_pages( - struct task_struct *task, - void *virt_start_page_addr, - int nr_of_pages, - struct page **pages -) +static inline int lock_user_pages(struct task_struct *task, + void *virt_start_page_addr, int nr_of_pages, + struct page **pages) { - int ret = 0; - int locked_pages = 0; - unsigned int i; + int ret = 0; + int locked_pages = 0; + unsigned int i; do { - /* lock user pages, must hold the mmap_sem to do this. */ down_read(&(task->mm->mmap_sem)); - locked_pages = get_user_pages( - task, - task->mm, - (unsigned long)virt_start_page_addr, - nr_of_pages, - 1, /* write access */ - 0, /* they say drivers should always - pass 0 here..... */ - pages, - NULL); /* we don't need the VMAs */ + locked_pages = + get_user_pages(task, + task->mm, + (unsigned long)virt_start_page_addr, + nr_of_pages, + 1, + 0, + pages, + NULL); up_read(&(task->mm->mmap_sem)); - /* could as lock all pages? */ + /* check if we could lock all pages. */ if (locked_pages != nr_of_pages) { - MCDRV_DBG_ERROR( - "get_user_pages() failed, " - "locked_pages=%d\n", - locked_pages); + MCDRV_DBG_ERROR(mcd, + "get_user_pages() err, locked_pages=%d", + locked_pages); ret = -ENOMEM; - /* check if an error has been returned. */ if (locked_pages < 0) { ret = locked_pages; locked_pages = 0; @@ -215,8 +214,7 @@ static inline int lock_user_pages( for (i = 0; i < nr_of_pages; i++) flush_dcache_page(pages[i]); - } while (FALSE); - + } while (0); if (ret != 0) { /* release all locked pages. */ @@ -230,49 +228,38 @@ static inline int lock_user_pages( } /* -############################################################################# -## -## Driver implementation functions -## -#############################################################################*/ -/*----------------------------------------------------------------------------*/ + * ############################################################################# + * ## + * ## Driver implementation functions + * ## + * ############################################################################# + */ + /* check if caller is MobiCore Daemon */ -static unsigned int is_caller_mc_daemon( - struct mc_instance *instance -) +static unsigned int is_caller_mc_daemon(struct mc_instance *instance) { - return ((instance != NULL) - && (mc_drv_kmod_ctx.daemon_inst == instance)); + return ((instance != NULL) && + (mc_drv_kmod_ctx.daemon_inst == instance)); } - -/*----------------------------------------------------------------------------*/ /* Get process context from file pointer */ -static struct mc_instance *get_instance( - struct file *file -) { +static struct mc_instance *get_instance(struct file *file) +{ MCDRV_ASSERT(file != NULL); return (struct mc_instance *)(file->private_data); } - -/*----------------------------------------------------------------------------*/ /* Get a unique ID */ -static unsigned int get_mc_kmod_unique_id( - void -) +static unsigned int get_mc_kmod_unique_id(void) { return (unsigned int)atomic_inc_return( - &(mc_drv_kmod_ctx.unique_counter)); + &(mc_drv_kmod_ctx.unique_counter)); } - -/*----------------------------------------------------------------------------*/ /* Get kernel pointer to shared L2 table given a per-process reference */ static struct l2table *get_l2_table_kernel_virt( - struct mc_used_l2_table *used_l2table -) + struct mc_used_l2_table *used_l2table) { MCDRV_ASSERT(used_l2table != NULL); MCDRV_ASSERT(used_l2table->set != NULL); @@ -280,11 +267,8 @@ static struct l2table *get_l2_table_kernel_virt( return &(used_l2table->set->kernel_virt->table[used_l2table->idx]); } -/*----------------------------------------------------------------------------*/ /* Get physical address of a shared L2 table given a per-process reference */ -static struct l2table *get_l2_table_phys( - struct mc_used_l2_table *used_l2table -) +static struct l2table *get_l2_table_phys(struct mc_used_l2_table *used_l2table) { MCDRV_ASSERT(used_l2table != NULL); MCDRV_ASSERT(used_l2table->set != NULL); @@ -292,30 +276,22 @@ static struct l2table *get_l2_table_phys( return &(used_l2table->set->phys->table[used_l2table->idx]); } -/*----------------------------------------------------------------------------*/ static unsigned int is_in_use_used_l2_table( - struct mc_used_l2_table *used_l2table -) + struct mc_used_l2_table *used_l2table) { return ((used_l2table->flags & - (MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP - | MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC)) != 0); + (MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP | + MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC)) != 0); } - - -/*----------------------------------------------------------------------------*/ static struct mc_used_l2_table *find_used_l2_table_by_handle( - unsigned int handle -) { - struct mc_used_l2_table *used_l2table; - struct mc_used_l2_table *used_l2table_with_handle = NULL; - - list_for_each_entry( - used_l2table, - &(mc_drv_kmod_ctx.mc_used_l2_tables), - list - ) { + unsigned int handle) +{ + struct mc_used_l2_table *used_l2table; + struct mc_used_l2_table *used_l2table_with_handle = NULL; + + list_for_each_entry(used_l2table, + &(mc_drv_kmod_ctx.mc_used_l2_tables), list) { if (handle == used_l2table->handle) { used_l2table_with_handle = used_l2table; break; @@ -326,29 +302,28 @@ static struct mc_used_l2_table *find_used_l2_table_by_handle( } /* -############################################################################# -## -## L2 Table Pool -## -#############################################################################*/ - -/*----------------------------------------------------------------------------*/ + * ############################################################################# + * ## + * ## L2 Table Pool + * ## + * ############################################################################# + */ static struct mc_used_l2_table *allocate_used_l2_table( - struct mc_instance *instance -) { - int ret = 0; - struct mc_l2_table_store *l2table_store = NULL; - struct mc_l2_tables_set *l2table_set = NULL; - struct mc_used_l2_table *used_l2table = NULL; - struct page *page; - unsigned int i = 0; + struct mc_instance *instance) +{ + int ret = 0; + struct mc_l2_table_store *l2table_store = NULL; + struct mc_l2_tables_set *l2table_set = NULL; + struct mc_used_l2_table *used_l2table = NULL; + struct page *page; + unsigned int i = 0; do { /* allocate a WSM L2 descriptor */ - used_l2table = kmalloc(sizeof(*used_l2table), GFP_KERNEL); + used_l2table = kmalloc(sizeof(*used_l2table), GFP_KERNEL); if (used_l2table == NULL) { ret = -ENOMEM; - MCDRV_DBG_ERROR("out of memory\n"); + MCDRV_DBG_ERROR(mcd, "out of memory\n"); break; } /* clean */ @@ -357,21 +332,20 @@ static struct mc_used_l2_table *allocate_used_l2_table( used_l2table->owner = instance; /* add to global list. */ - init_and_add_to_list( - &(used_l2table->list), - &(mc_drv_kmod_ctx.mc_used_l2_tables)); + init_and_add_to_list(&(used_l2table->list), + &(mc_drv_kmod_ctx.mc_used_l2_tables)); /* walk though list to find free set. */ - list_for_each_entry( - l2table_set, - &(mc_drv_kmod_ctx.mc_l2_tables_sets), - list - ) { + list_for_each_entry(l2table_set, + &(mc_drv_kmod_ctx.mc_l2_tables_sets), + list) { for (i = 0; i < MC_DRV_KMOD_L2_TABLE_PER_PAGES; i++) { if ((l2table_set->usage_bitmap & (1U << i)) == 0) { - /* found a set, - l2table_set and i are set. */ + /* + * found a set, + * l2table_set and i are set. + */ l2table_store = l2table_set->kernel_virt; break; @@ -379,7 +353,7 @@ static struct mc_used_l2_table *allocate_used_l2_table( } if (l2table_store != NULL) break; - } /* end while */ + } /* end list_for_each_entry() */ if (l2table_store == NULL) { l2table_store = (struct mc_l2_table_store *) @@ -389,9 +363,11 @@ static struct mc_used_l2_table *allocate_used_l2_table( break; } - /* Actually, locking is not necessary, because kernel - memory is not supposed to get swapped out. But - we play safe.... */ + /* + * Actually, locking is not necessary, because kernel + * memory is not supposed to get swapped out. But we + * play safe.... + */ page = virt_to_page(l2table_store); SetPageReserved(page); @@ -411,8 +387,8 @@ static struct mc_used_l2_table *allocate_used_l2_table( /* init add to list. */ init_and_add_to_list( - &(l2table_set->list), - &(mc_drv_kmod_ctx.mc_l2_tables_sets)); + &(l2table_set->list), + &(mc_drv_kmod_ctx.mc_l2_tables_sets)); /* use first table */ i = 0; @@ -425,32 +401,24 @@ static struct mc_used_l2_table *allocate_used_l2_table( used_l2table->set = l2table_set; used_l2table->idx = i; - MCDRV_DBG_VERBOSE( - "chunkPhys=%p,idx=%d\n", - l2table_set->phys, i); + MCDRV_DBG_VERBOSE(mcd, "chunkPhys=%p,idx=%d\n", + l2table_set->phys, i); - } while (FALSE); + } while (0); - if (ret != 0) { - if (used_l2table != NULL) { - /* remove from list */ - list_del(&(l2table_set->list)); - /* free memory */ - kfree(used_l2table); - used_l2table = NULL; - } + if (ret != 0 && used_l2table != NULL) { + list_del(&(l2table_set->list)); + kfree(used_l2table); + used_l2table = NULL; } return used_l2table; } -/*----------------------------------------------------------------------------*/ -static void free_used_l2_table( - struct mc_used_l2_table *used_l2table -) +static void free_used_l2_table(struct mc_used_l2_table *used_l2table) { - struct mc_l2_tables_set *l2table_set; - unsigned int idx; + struct mc_l2_tables_set *l2table_set; + unsigned int idx; MCDRV_ASSERT(used_l2table != NULL); @@ -470,98 +438,99 @@ static void free_used_l2_table( MCDRV_ASSERT(l2table_set->kernel_virt != NULL); free_page((unsigned long)l2table_set->kernel_virt); - /* remove from list */ list_del(&(l2table_set->list)); - - /* free memory */ kfree(l2table_set); } return; } - - -/*----------------------------------------------------------------------------*/ -/** +/* * Create a L2 table in a WSM container that has been allocates previously. * - * @param task pointer to task owning WSM - * @param wsm_buffer user space WSM start - * @param wsm_len WSM length - * @param used_l2table Pointer to L2 table details + * task pointer to task owning WSM + * wsm_buffer user space WSM start + * wsm_len WSM length + * used_l2table Pointer to L2 table details */ -static int map_buffer_into_used_l2_table( - struct task_struct *task, - void *wsm_buffer, - unsigned int wsm_len, - struct mc_used_l2_table *used_l2table -) +static int map_buffer_into_used_l2_table(struct task_struct *task, + void *wsm_buffer, unsigned int wsm_len, + struct mc_used_l2_table *used_l2table) { - int ret = 0; - unsigned int i, nr_of_pages; - void *virt_addr_page; - struct page *page; - struct l2table *l2table; - struct page **l2table_as_array_of_pointers_to_page; + int ret = 0; + unsigned int i, nr_of_pages; + struct page *page; + struct l2table *l2table; + struct page **l2table_as_array_of_pointers_to_page; + void *virt_addr_page; /* start addr of the 4 KiB page of wsm_buffer */ + unsigned int offset; /* page offset in wsm buffer */ /* task can be null when called from kernel space */ MCDRV_ASSERT(wsm_buffer != NULL); MCDRV_ASSERT(wsm_len != 0); MCDRV_ASSERT(used_l2table != NULL); - MCDRV_DBG_VERBOSE("WSM addr=0x%p, len=0x%08x\n", wsm_buffer, wsm_len); + MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x\n", + wsm_buffer, wsm_len); - /* Check if called from kernel space wsm_buffer is actually - * vmalloced or not */ + /* + * Check if called from kernel space wsm_buffer is actually + * vmalloced or not + */ if (task == NULL && !is_vmalloc_addr(wsm_buffer)) { - MCDRV_DBG_ERROR("WSM addr is not a vmalloc address"); + MCDRV_DBG_ERROR(mcd, "WSM addr is not a vmalloc address"); return -EINVAL; } l2table = get_l2_table_kernel_virt(used_l2table); - /* We use the memory for the L2 table to hold the pointer - and convert them later. This works, as everything comes - down to a 32 bit value. */ + /* + * We use the memory for the L2 table to hold the pointer + * and convert them later. This works, as everything comes + * down to a 32 bit value. + */ l2table_as_array_of_pointers_to_page = (struct page **)l2table; do { /* no size > 1Mib supported */ if (wsm_len > SZ_1M) { - MCDRV_DBG_ERROR("size > 1 MiB\n"); + MCDRV_DBG_ERROR(mcd, "size > 1 MiB\n"); ret = -EINVAL; break; } /* calculate page usage */ - virt_addr_page = get_page_start(wsm_buffer); - nr_of_pages = get_nr_of_pages_for_buffer(wsm_buffer, wsm_len); + virt_addr_page = (void *) + (((unsigned long)(wsm_buffer)) & PAGE_MASK); + offset = (unsigned int) + (((unsigned long)(wsm_buffer)) & (~PAGE_MASK)); + nr_of_pages = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE; - - MCDRV_DBG_VERBOSE("virt addr pageStart=0x%p,pages=%d\n", + MCDRV_DBG_VERBOSE(mcd, "virt addr page start=0x%p, pages=%d\n", virt_addr_page, nr_of_pages); /* L2 table can hold max 1MiB in 256 pages. */ if ((nr_of_pages*PAGE_SIZE) > SZ_1M) { - MCDRV_DBG_ERROR("WSM paged exceed 1 MiB\n"); + MCDRV_DBG_ERROR(mcd, "WSM paged exceed 1 MiB\n"); ret = -EINVAL; break; } /* Request comes from user space */ if (task != NULL) { - /* lock user page in memory, so they do not get swapped - * out. - * REV axh: - * Kernel 2.6.27 added a new get_user_pages_fast() - * function, maybe it is called fast_gup() in some - * versions. - * handle user process doing a fork(). - * Child should not get things. - * http://osdir.com/ml/linux-media/2009-07/msg00813.html - * http://lwn.net/Articles/275808/ */ + /* + * lock user page in memory, so they do not get swapped + * out. + * REV axh: + * Kernel 2.6.27 added a new get_user_pages_fast() + * function, maybe it is called fast_gup() in some + * versions. + * handle user process doing a fork(). + * Child should not get things. + * http://osdir.com/ml/linux-media/2009-07/msg00813.html + * http://lwn.net/Articles/275808/ + */ ret = lock_user_pages( task, @@ -569,7 +538,8 @@ static int map_buffer_into_used_l2_table( nr_of_pages, l2table_as_array_of_pointers_to_page); if (ret != 0) { - MCDRV_DBG_ERROR("lock_user_pages() failed\n"); + MCDRV_DBG_ERROR(mcd, + "lock_user_pages() failed\n"); break; } } @@ -579,15 +549,16 @@ static int map_buffer_into_used_l2_table( for (i = 0; i < nr_of_pages; i++) { page = vmalloc_to_page(uaddr); if (!page) { - MCDRV_DBG_ERROR( - "vmalloc_to_Page()" - " failed to map address\n"); + MCDRV_DBG_ERROR(mcd, + "failed to map addr"); ret = -EINVAL; break; } get_page(page); - /* Lock the page in memory, it can't be swapped - * out */ + /* + * Lock the page in memory, it can't be swapped + * out + */ SetPageReserved(page); l2table_as_array_of_pointers_to_page[i] = page; uaddr += PAGE_SIZE; @@ -597,39 +568,46 @@ static int map_buffer_into_used_l2_table( used_l2table->nr_of_pages = nr_of_pages; used_l2table->flags |= MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP; - /* create L2 Table entries. used_l2table->table contains a list - of page pointers here. For a proper cleanup we have to ensure - that the following code either works and used_l2table contains - a valid L2 table - or fails and used_l2table->table contains the - list of page pointers. Any mixed contents will make cleanup - difficult.*/ - + /* + * create L2 Table entries. + * used_l2table->table contains a list of page pointers here. + * For a proper cleanup we have to ensure that the following + * code either works and used_l2table contains a valid L2 table + * - or fails and used_l2table->table contains the list of page + * pointers. + * Any mixed contents will make cleanup difficult. + */ for (i = 0; i < nr_of_pages; i++) { pte_t pte; page = l2table_as_array_of_pointers_to_page[i]; - /* create L2 table entry, see ARM MMU docu for details - about flags stored in the lowest 12 bits. As a side - reference, the Article "ARM's multiply-mapped memory - mess" found in the collection at at - http://lwn.net/Articles/409032/ is also worth reading.*/ + /* + * create L2 table entry, see ARM MMU docu for details + * about flags stored in the lowest 12 bits. + * As a side reference, the Article + * "ARM's multiply-mapped memory mess" + * found in the collection at + * http://lwn.net/Articles/409032/ + * is also worth reading. + */ pte = page_to_l2_pte(page) - | L2_FLAG_AP1 | L2_FLAG_AP0 - | L2_FLAG_C | L2_FLAG_B - | L2_FLAG_SMALL | L2_FLAG_SMALL_XN - /* Linux uses different mappings for SMP systems(the + | PTE_EXT_AP1 | PTE_EXT_AP0 + | PTE_CACHEABLE | PTE_BUFFERABLE + | PTE_TYPE_SMALL | PTE_TYPE_EXT + /* + * Linux uses different mappings for SMP systems(the * sharing flag is set for the pte. In order not to * confuse things too much in Mobicore make sure the * shared buffers have the same flags. * This should also be done in SWD side */ #ifdef CONFIG_SMP - | L2_FLAG_S | L2_FLAG_SMALL_TEX0 + | PTE_EXT_SHARED | PTE_EXT_TEX(1) #endif ; l2table->table_entries[i] = pte; - MCDRV_DBG_VERBOSE("L2 entry %d: 0x%08x\n", i, + MCDRV_DBG_VERBOSE(mcd, "L2 entry %d: 0x%08x\n", i, (unsigned int)(pte)); } @@ -637,33 +615,29 @@ static int map_buffer_into_used_l2_table( while (i < 255) l2table->table_entries[i++] = (pte_t)0; - } while (FALSE); + } while (0); return ret; } - -/*----------------------------------------------------------------------------*/ -/** +/* * Remove a L2 table in a WSM container. Afterwards the container may be * released. * - * @param used_l2table Pointer to L2 table details + * used_l2table Pointer to L2 table details */ - static void unmap_buffers_from_used_l2_table( - struct mc_used_l2_table *used_l2table -) + struct mc_used_l2_table *used_l2table) { - unsigned int i; - struct l2table *l2table; + unsigned int i; + struct l2table *l2table; MCDRV_ASSERT(used_l2table != NULL); /* this should not happen, as we have no empty tables. */ MCDRV_ASSERT(!is_in_use_used_l2_table(used_l2table)); /* found the table, now release the resources. */ - MCDRV_DBG_VERBOSE("clear L2 table, phys_base=%p, nr_of_pages=%d\n", + MCDRV_DBG_VERBOSE(mcd, "clear L2 table, phys_base=%p, nr_of_pages=%d\n", get_l2_table_phys(used_l2table), used_l2table->nr_of_pages); @@ -684,21 +658,19 @@ static void unmap_buffers_from_used_l2_table( return; } - /* -############################################################################# -## -## Helper functions -## -#############################################################################*/ -/*----------------------------------------------------------------------------*/ -#define FREE_FROM_SWD TRUE -#define FREE_FROM_NWD FALSE -/** Delete a used l2 table. */ -static void delete_used_l2_table( - struct mc_used_l2_table *used_l2table, - unsigned int is_swd -) + * ############################################################################# + * ## + * ## Helper functions + * ## + * ############################################################################# + */ +#define FREE_FROM_SWD 1 +#define FREE_FROM_NWD 0 + +/* Delete a used l2 table. */ +static void delete_used_l2_table(struct mc_used_l2_table *used_l2table, + unsigned int is_swd) { if (is_swd) { used_l2table->flags &= @@ -711,98 +683,79 @@ static void delete_used_l2_table( /* release if Nwd and Swd/MC do no longer use it. */ if (is_in_use_used_l2_table(used_l2table)) { - MCDRV_DBG_WARN( - "WSM L2 table still in use: physBase=%p, " - "nr_of_pages=%d\n", - get_l2_table_phys(used_l2table), - used_l2table->nr_of_pages); + MCDRV_DBG_WARN(mcd, + "WSM L2 table still in use: %p, nr_of_pages=%d", + get_l2_table_phys(used_l2table), + used_l2table->nr_of_pages); } else { unmap_buffers_from_used_l2_table(used_l2table); free_used_l2_table(used_l2table); list_del(&(used_l2table->list)); - kfree(used_l2table); } return; } -/*----------------------------------------------------------------------------*/ -/** Allocate L2 table and map buffer into it. That is, create respective table - entries. Must hold Semaphore mc_drv_kmod_ctx.wsm_l2_sem */ -static struct mc_used_l2_table *new_used_l2_table( - struct mc_instance *instance, - struct task_struct *task, - void *wsm_buffer, - unsigned int wsm_len -) { - int ret = 0; - struct mc_used_l2_table *used_l2table; +/* + * Allocate L2 table and map buffer into it. + * That is, create respective table entries. + * Must hold Semaphore mc_drv_kmod_ctx.wsm_l2_sem + */ +static struct mc_used_l2_table *new_used_l2_table(struct mc_instance *instance, + struct task_struct *task, + void *wsm_buffer, + unsigned int wsm_len) +{ + int ret = 0; + struct mc_used_l2_table *used_l2table; do { used_l2table = allocate_used_l2_table(instance); if (used_l2table == NULL) { - MCDRV_DBG_ERROR( - "allocate_used_l2_table() failed\n"); + MCDRV_DBG_ERROR(mcd, + "allocate_used_l2_table() failed\n"); break; } /* create the L2 page for the WSM */ - ret = map_buffer_into_used_l2_table( - task, - wsm_buffer, - wsm_len, - used_l2table); + ret = map_buffer_into_used_l2_table(task, + wsm_buffer, + wsm_len, + used_l2table); if (ret != 0) { - MCDRV_DBG_ERROR( - "map_buffer_into_used_l2_table() failed\n"); + MCDRV_DBG_ERROR(mcd, + "map_buffer_into_used_l2_table() err"); delete_used_l2_table(used_l2table, FREE_FROM_NWD); used_l2table = NULL; break; } - } while (FALSE); - + } while (0); return used_l2table; } /* -############################################################################# -## -## IoCtl handler -## -#############################################################################*/ - -/** - * Map a virtual memory buffer structure to Mobicore - * @param instance - * @param addr address of the buffer(NB it must be kernel virtual!) - * @param len buffer length - * @param handle pointer to handle - * @param phys_wsm_l2_table pointer to physical L2 table(?) - * - * @return 0 if no error - * + * ############################################################################# + * ## + * ## IoCtl handler + * ## + * ############################################################################# */ -/*----------------------------------------------------------------------------*/ -int mobicore_map_vmem( - struct mc_instance *instance, - void *addr, - uint32_t len, - uint32_t *handle, - void **phys_wsm_l2_table -) + +int mobicore_map_vmem(struct mc_instance *instance, void *addr, uint32_t len, + uint32_t *handle, void **phys_wsm_l2_table) { int ret = 0; struct mc_used_l2_table *used_l2table = NULL; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { if (len == 0) { - MCDRV_DBG_ERROR("len=0 is not supported!\n"); + MCDRV_DBG_ERROR(mcd, "len=0 is not supported!\n"); ret = -EINVAL; break; } @@ -810,21 +763,22 @@ int mobicore_map_vmem( /* try to get the semaphore */ ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); if (ret != 0) { - MCDRV_DBG_ERROR("down_interruptible() failed with %d\n", + MCDRV_DBG_ERROR(mcd, + "down_interruptible() failed with %d\n", ret); ret = -ERESTARTSYS; break; } do { - used_l2table = new_used_l2_table( - instance, - NULL, - addr, - len); + used_l2table = new_used_l2_table(instance, + NULL, + addr, + len); if (used_l2table == NULL) { - MCDRV_DBG_ERROR("new_used_l2_table() failed\n"); + MCDRV_DBG_ERROR(mcd, + "new_used_l2_table() failed\n"); ret = -EINVAL; break; } @@ -833,65 +787,55 @@ int mobicore_map_vmem( *handle = used_l2table->handle; *phys_wsm_l2_table = (void *)get_l2_table_phys(used_l2table); - MCDRV_DBG_VERBOSE("handle: %d, phys=%p\n", + MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=%p\n", *handle, (void *)(*phys_wsm_l2_table)); - } while (FALSE); + } while (0); /* release semaphore */ up(&(mc_drv_kmod_ctx.wsm_l2_sem)); - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } EXPORT_SYMBOL(mobicore_map_vmem); -/*----------------------------------------------------------------------------*/ -/** - * - * @param instance - * @param arg - * - * @return 0 if no error - * - */ + static int handle_ioctl_app_register_wsm_l2( - struct mc_instance *instance, - union mc_ioctl_app_reg_wsm_l2_params *user_params -) + struct mc_instance *instance, + union mc_ioctl_app_reg_wsm_l2_params *user_params) { - int ret = 0; - union mc_ioctl_app_reg_wsm_l2_params params; - struct mc_used_l2_table *used_l2table = NULL; - struct pid *pid_struct = NULL; - struct task_struct *task = current; + int ret = 0; + union mc_ioctl_app_reg_wsm_l2_params params; + struct mc_used_l2_table *used_l2table = NULL; + struct pid *pid_struct = NULL; + struct task_struct *task = current; + void *phys_wsm_l2_table; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { - /* get use parameters */ - ret = copy_from_user( - &(params.in), - &(user_params->in), - sizeof(params.in)); + /* get user parameters */ + ret = copy_from_user(&(params.in), &(user_params->in), + sizeof(params.in)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_from_user() failed\n"); + MCDRV_DBG_ERROR(mcd, "copy_from_user() failed\n"); break; } /* daemon can do this for another task. */ if (params.in.pid != 0) { - MCDRV_DBG_ERROR("pid != 0 unsupported\n"); + MCDRV_DBG_ERROR(mcd, "pid != 0 unsupported\n"); ret = -EINVAL; break; } if (params.in.len == 0) { - MCDRV_DBG_ERROR("len=0 is not supported!\n"); + MCDRV_DBG_ERROR(mcd, "len=0 is not supported!\n"); ret = -EINVAL; break; } @@ -899,7 +843,8 @@ static int handle_ioctl_app_register_wsm_l2( /* try to get the semaphore */ ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); if (ret != 0) { - MCDRV_DBG_ERROR("down_interruptible() failed with %d\n", + MCDRV_DBG_ERROR(mcd, + "down_interruptible() failed with %d\n", ret); ret = -ERESTARTSYS; break; @@ -913,7 +858,8 @@ static int handle_ioctl_app_register_wsm_l2( params.in.len); if (used_l2table == NULL) { - MCDRV_DBG_ERROR("new_used_l2_table() failed\n"); + MCDRV_DBG_ERROR(mcd, + "new_used_l2_table() failed\n"); ret = -EINVAL; break; } @@ -926,81 +872,68 @@ static int handle_ioctl_app_register_wsm_l2( /* set response */ memset(¶ms.out, 0, sizeof(params.out)); params.out.handle = used_l2table->handle; - /* TODO: return the physical address for daemon only, - otherwise set NULL */ + params.out.phys_wsm_l2_table = (uint32_t)get_l2_table_phys(used_l2table); - MCDRV_DBG_VERBOSE("handle: %d, phys=%p\n", - params.out.handle, - (void *)(params.out.phys_wsm_l2_table)); + phys_wsm_l2_table = + (void *)(params.out.phys_wsm_l2_table); + MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=%p\n", + params.out.handle, + phys_wsm_l2_table); /* copy L2Table to user space */ - ret = copy_to_user( - &(user_params->out), - &(params.out), - sizeof(params.out)); + ret = copy_to_user(&(user_params->out), + &(params.out), + sizeof(params.out)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_to_user() failed\n"); + MCDRV_DBG_ERROR(mcd, "copy_to_user() failed\n"); - /* free the table again, as app does not know - about anything. */ + /* + * free the table again, + * app does not know anything about it. + */ if (is_caller_mc_daemon(instance)) { used_l2table->flags &= ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC; } delete_used_l2_table(used_l2table, - FREE_FROM_NWD); + FREE_FROM_NWD); used_l2table = NULL; break; } - } while (FALSE); + } while (0); /* release semaphore */ up(&(mc_drv_kmod_ctx.wsm_l2_sem)); - } while (FALSE); - - + } while (0); /* release PID struct reference */ if (pid_struct != NULL) put_pid(pid_struct); - - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } - -/*----------------------------------------------------------------------------*/ -/** - * Unmap a virtual memory buffer from mobicore - * @param instance - * @param handle - * - * @return 0 if no error - * - */ -int mobicore_unmap_vmem( - struct mc_instance *instance, - uint32_t handle -) +int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle) { int ret = 0; struct mc_used_l2_table *used_l2table = NULL; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { /* try to get the semaphore */ ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); if (ret != 0) { - MCDRV_DBG_ERROR("processOpenSession() failed with %d\n", + MCDRV_DBG_ERROR(mcd, + "processOpenSession() failed with %d\n", ret); ret = -ERESTARTSYS; break; @@ -1010,13 +943,14 @@ int mobicore_unmap_vmem( used_l2table = find_used_l2_table_by_handle(handle); if (used_l2table == NULL) { ret = -EINVAL; - MCDRV_DBG_ERROR("entry not found\n"); + MCDRV_DBG_ERROR(mcd, "entry not found\n"); break; } if (instance != used_l2table->owner) { ret = -EINVAL; - MCDRV_DBG_ERROR("instance does no own it\n"); + MCDRV_DBG_ERROR(mcd, + "instance does no own it\n"); break; } @@ -1024,53 +958,43 @@ int mobicore_unmap_vmem( delete_used_l2_table(used_l2table, FREE_FROM_NWD); used_l2table = NULL; /* there are no out parameters */ - } while (FALSE); + } while (0); /* release semaphore */ up(&(mc_drv_kmod_ctx.wsm_l2_sem)); - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } EXPORT_SYMBOL(mobicore_unmap_vmem); -/*----------------------------------------------------------------------------*/ -/** - * - * @param instance - * @param arg - * - * @return 0 if no error - * - */ + static int handle_ioctl_app_unregister_wsm_l2( - struct mc_instance *instance, - struct mc_ioctl_app_unreg_wsm_l2_params *user_params -) + struct mc_instance *instance, + struct mc_ioctl_app_unreg_wsm_l2_params *user_params) { - int ret = 0; - struct mc_ioctl_app_unreg_wsm_l2_params params; - struct mc_used_l2_table *used_l2table = NULL; + int ret = 0; + struct mc_ioctl_app_unreg_wsm_l2_params params; + struct mc_used_l2_table *used_l2table = NULL; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { - ret = copy_from_user( - &(params.in), - &(user_params->in), - sizeof(params.in)); + ret = copy_from_user(&(params.in), &(user_params->in), + sizeof(params.in)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_from_user\n"); + MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); break; } /* try to get the semaphore */ ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); if (ret != 0) { - MCDRV_DBG_ERROR("down_interruptible() failed with %d\n", + MCDRV_DBG_ERROR(mcd, + "down_interruptible() failed with %d\n", ret); ret = -ERESTARTSYS; break; @@ -1079,7 +1003,7 @@ static int handle_ioctl_app_unregister_wsm_l2( do { /* daemon can do this for another task. */ if (params.in.pid != 0) { - MCDRV_DBG_ERROR("pid != 0 unsupported\n"); + MCDRV_DBG_ERROR(mcd, "pid != 0 unsupported\n"); ret = -EINVAL; break; } @@ -1088,18 +1012,21 @@ static int handle_ioctl_app_unregister_wsm_l2( find_used_l2_table_by_handle(params.in.handle); if (used_l2table == NULL) { ret = -EINVAL; - MCDRV_DBG_ERROR("entry not found\n"); + MCDRV_DBG_ERROR(mcd, "entry not found\n"); break; } if (is_caller_mc_daemon(instance)) { - /* if daemon does this, we have to release the - MobiCore lock. */ + /* + * if daemon does this, we have to release the + * MobiCore lock. + */ used_l2table->flags &= ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC; } else if (instance != used_l2table->owner) { ret = -EINVAL; - MCDRV_DBG_ERROR("instance does no own it\n"); + MCDRV_DBG_ERROR(mcd, + "instance does no own it\n"); break; } @@ -1109,52 +1036,48 @@ static int handle_ioctl_app_unregister_wsm_l2( /* there are no out parameters */ - } while (FALSE); + } while (0); /* release semaphore */ up(&(mc_drv_kmod_ctx.wsm_l2_sem)); - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } - -/*----------------------------------------------------------------------------*/ static int handle_ioctl_daemon_lock_wsm_l2( - struct mc_instance *instance, - struct mc_ioctl_daemon_lock_wsm_l2_params *user_params -) + struct mc_instance *instance, + struct mc_ioctl_daemon_lock_wsm_l2_params *user_params) { - int ret = 0; - struct mc_ioctl_daemon_lock_wsm_l2_params params; - struct mc_used_l2_table *used_l2table = NULL; + int ret = 0; + struct mc_ioctl_daemon_lock_wsm_l2_params params; + struct mc_used_l2_table *used_l2table = NULL; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR("caller not MobiCore Daemon\n"); + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); ret = -EFAULT; break; } - ret = copy_from_user( - &(params.in), - &(user_params->in), - sizeof(params.in)); + ret = copy_from_user(&(params.in), &(user_params->in), + sizeof(params.in)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_from_user\n"); + MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); break; } /* try to get the semaphore */ ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); if (ret != 0) { - MCDRV_DBG_ERROR("down_interruptible() failed with %d\n", + MCDRV_DBG_ERROR(mcd, + "down_interruptible() failed with %d\n", ret); ret = -ERESTARTSYS; break; @@ -1165,19 +1088,20 @@ static int handle_ioctl_daemon_lock_wsm_l2( find_used_l2_table_by_handle(params.in.handle); if (used_l2table == NULL) { ret = -EINVAL; - MCDRV_DBG_ERROR("entry not found\n"); + MCDRV_DBG_ERROR(mcd, "entry not found\n"); break; } if (instance != used_l2table->owner) { ret = -EINVAL; - MCDRV_DBG_ERROR("instance does no own it\n"); + MCDRV_DBG_ERROR(mcd, + "instance does no own it\n"); break; } /* lock entry */ if ((used_l2table->flags & - MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) != 0) { - MCDRV_DBG_WARN("entry already locked\n"); + MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) != 0) { + MCDRV_DBG_WARN(mcd, "entry already locked\n"); } used_l2table->flags |= MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC; @@ -1188,12 +1112,10 @@ static int handle_ioctl_daemon_lock_wsm_l2( (uint32_t)get_l2_table_phys(used_l2table); /* copy to user space */ - ret = copy_to_user( - &(user_params->out), - &(params.out), - sizeof(params.out)); + ret = copy_to_user(&(user_params->out), &(params.out), + sizeof(params.out)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_to_user() failed\n"); + MCDRV_DBG_ERROR(mcd, "copy_to_user() failed\n"); /* undo, as userspace did not get it. */ used_l2table->flags |= @@ -1201,53 +1123,49 @@ static int handle_ioctl_daemon_lock_wsm_l2( break; } - } while (FALSE); + } while (0); /* release semaphore */ up(&(mc_drv_kmod_ctx.wsm_l2_sem)); - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } - -/*----------------------------------------------------------------------------*/ static int handle_ioctl_daemon_unlock_wsm_l2( - struct mc_instance *instance, - struct mc_ioctl_daemon_unlock_wsm_l2_params *user_params -) + struct mc_instance *instance, + struct mc_ioctl_daemon_unlock_wsm_l2_params *user_params) { - int ret = 0; - struct mc_ioctl_daemon_unlock_wsm_l2_params params; - struct mc_used_l2_table *used_l2table = NULL; + int ret = 0; + struct mc_ioctl_daemon_unlock_wsm_l2_params params; + struct mc_used_l2_table *used_l2table = NULL; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR("caller not MobiCore Daemon\n"); + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); ret = -EFAULT; break; } - ret = copy_from_user( - &(params.in), - &(user_params->in), - sizeof(params.in)); + ret = copy_from_user(&(params.in), &(user_params->in), + sizeof(params.in)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_from_user\n"); + MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); break; } /* try to get the semaphore */ ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); if (ret != 0) { - MCDRV_DBG_ERROR("down_interruptible() failed with %d\n", - ret); + MCDRV_DBG_ERROR(mcd, + "down_interruptible() failed with %d\n", + ret); ret = -ERESTARTSYS; break; } @@ -1257,19 +1175,21 @@ static int handle_ioctl_daemon_unlock_wsm_l2( find_used_l2_table_by_handle(params.in.handle); if (used_l2table == NULL) { ret = -EINVAL; - MCDRV_DBG_ERROR("entry not found\n"); + MCDRV_DBG_ERROR(mcd, "entry not found\n"); break; } if (instance != used_l2table->owner) { ret = -EINVAL; - MCDRV_DBG_ERROR("instance does no own it\n"); + MCDRV_DBG_ERROR(mcd, + "instance does no own it\n"); break; } /* lock entry */ if ((used_l2table->flags & - MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) == 0) { - MCDRV_DBG_WARN("entry is not locked locked\n"); + MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) == 0) { + MCDRV_DBG_WARN(mcd, + "entry is not locked locked\n"); } /* free table (if no further locks exist) */ @@ -1278,51 +1198,35 @@ static int handle_ioctl_daemon_unlock_wsm_l2( /* there are no out parameters */ - } while (FALSE); + } while (0); - } while (FALSE); + } while (0); - - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } -/*----------------------------------------------------------------------------*/ -/** Clears the reserved bit of each page and frees the pages */ -static inline void free_continguous_pages( - void *addr, - unsigned int size -) +/* Clears the reserved bit of each page and frees the pages */ +static inline void free_continguous_pages(void *addr, unsigned int order) { struct page *page = virt_to_page(addr); int i; - for (i = 0; i < size; i++) { - MCDRV_DBG_VERBOSE("free page at 0x%p\n", page); + + for (i = 0; i < (1 << order); i++) { + MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p\n", page); ClearPageReserved(page); page++; } - /* REV luh: see man kmalloc */ - free_pages((unsigned long)addr, size_to_order(size)); + MCDRV_DBG(mcd, "freeing addr:%p, order:%x\n", addr, order); + free_pages((unsigned long)addr, order); } -/*----------------------------------------------------------------------------*/ -/** - * Free a WSM buffer allocated with mobicore_allocate_wsm - * @param instance - * @param handle handle of the buffer - * - * @return 0 if no error - * - */ -int mobicore_free( - struct mc_instance *instance, - uint32_t handle -) +int mobicore_free(struct mc_instance *instance, uint32_t handle) { int ret = 0; unsigned int i; - struct mc_contg_buffer *contg_buffer; + struct mc_contg_buffer *contg_buffer; do { /* search for the given address in the contg_buffers list */ @@ -1332,64 +1236,49 @@ int mobicore_free( break; } if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) { - MCDRV_DBG_ERROR("contigous buffer not found\n"); + MCDRV_DBG_ERROR(mcd, "contigous buffer not found\n"); ret = -EFAULT; break; } - MCDRV_DBG_VERBOSE("phys_addr=0x%p, virt_addr=0x%p\n", - contg_buffer->phys_addr, - contg_buffer->virt_kernel_addr); + MCDRV_DBG_VERBOSE(mcd, "phys_addr=0x%p, virt_addr=0x%p\n", + contg_buffer->phys_addr, + contg_buffer->virt_kernel_addr); free_continguous_pages(contg_buffer->virt_kernel_addr, - contg_buffer->num_pages); + contg_buffer->order); memset(contg_buffer, 0, sizeof(*contg_buffer)); /* there are no out parameters */ - } while (FALSE); - + } while (0); return ret; } EXPORT_SYMBOL(mobicore_free); -/*----------------------------------------------------------------------------*/ -/** - * - * @param instance - * @param arg - * - * @return 0 if no error - * - */ -static int handle_ioctl_free( - struct mc_instance *instance, - union mc_ioctl_free_params *user_params -) +static int handle_ioctl_free(struct mc_instance *instance, + union mc_ioctl_free_params *user_params) { - int ret = 0; - union mc_ioctl_free_params params; - + int ret = 0; + union mc_ioctl_free_params params; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { - ret = copy_from_user( - &(params.in), - &(user_params->in), - sizeof(params.in)); + ret = copy_from_user(&(params.in), &(user_params->in), + sizeof(params.in)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_from_user\n"); + MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); break; } /* daemon can do this for another task. */ if (params.in.pid != 0) { - MCDRV_DBG_ERROR("pid != 0 unsupported\n"); + MCDRV_DBG_ERROR(mcd, "pid != 0 unsupported\n"); ret = -EINVAL; break; } @@ -1398,127 +1287,98 @@ static int handle_ioctl_free( /* there are no out parameters */ - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } - -/*----------------------------------------------------------------------------*/ -/** - * - * @param instance - * @param arg - * - * @return 0 if no error - * - */ -static int handle_ioctl_info( - struct mc_instance *instance, - union mc_ioctl_info_params *user_params -) +static int handle_ioctl_info(struct mc_instance *instance, + union mc_ioctl_info_params *user_params) { - int ret = 0; - union mc_ioctl_info_params params; - union mc_fc_info fc_info; - + int ret = 0; + union mc_ioctl_info_params params; + union mc_fc_info fc_info; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { /* only the MobiCore Daemon is allowed to call this function */ if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR("caller not MobiCore Daemon\n"); + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); ret = -EFAULT; break; } - ret = copy_from_user( - &(params.in), - &(user_params->in), - sizeof(params.in)); + ret = copy_from_user(&(params.in), &(user_params->in), + sizeof(params.in)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_from_user\n"); + MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); break; } - memset(&fc_info, 0, sizeof(fc_info)); - fc_info.as_in.cmd = MC_FC_INFO; + fc_info.as_in.cmd = MC_FC_INFO; fc_info.as_in.ext_info_id = params.in.ext_info_id; - MCDRV_DBG( - "fc_info in cmd=0x%08x, ext_info_id=0x%08x " - "rfu=(0x%08x, 0x%08x)\n", - fc_info.as_in.cmd, - fc_info.as_in.ext_info_id, - fc_info.as_in.rfu[0], - fc_info.as_in.rfu[1]); + MCDRV_DBG(mcd, + "fc_info in cmd=0x%08x, ext_info_id=0x%08x " + "rfu=(0x%08x, 0x%08x)\n", + fc_info.as_in.cmd, + fc_info.as_in.ext_info_id, + fc_info.as_in.rfu[0], + fc_info.as_in.rfu[1]); mc_fastcall(&(fc_info.as_generic)); - MCDRV_DBG( - "fc_info out resp=0x%08x, ret=0x%08x " - "state=0x%08x, ext_info=0x%08x\n", - fc_info.as_out.resp, - fc_info.as_out.ret, - fc_info.as_out.state, - fc_info.as_out.ext_info); + MCDRV_DBG(mcd, + "fc_info out resp=0x%08x, ret=0x%08x " + "state=0x%08x, ext_info=0x%08x\n", + fc_info.as_out.resp, + fc_info.as_out.ret, + fc_info.as_out.state, + fc_info.as_out.ext_info); ret = convert_fc_ret(fc_info.as_out.ret); if (ret != 0) break; memset(&(params.out), 0, sizeof(params.out)); - params.out.state = fc_info.as_out.state; + params.out.state = fc_info.as_out.state; params.out.ext_info = fc_info.as_out.ext_info; - ret = copy_to_user( - &(user_params->out), - &(params.out), - sizeof(params.out)); + ret = copy_to_user(&(user_params->out), &(params.out), + sizeof(params.out)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_to_user\n"); + MCDRV_DBG_ERROR(mcd, "copy_to_user\n"); break; } - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } -/*----------------------------------------------------------------------------*/ -/** - * - * @param instance - * @param arg - * - * @return 0 if no error - * - */ -static int handle_ioctl_yield( - struct mc_instance *instance -) +static int handle_ioctl_yield(struct mc_instance *instance) { - int ret = 0; - union mc_fc_s_yield fc_s_yield; + int ret = 0; + union mc_fc_s_yield fc_s_yield; MCDRV_ASSERT(instance != NULL); /* avoid putting debug output here, as we do this very often */ - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { /* only the MobiCore Daemon is allowed to call this function */ if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR("caller not MobiCore Daemon\n"); + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); ret = -EFAULT; break; } @@ -1530,37 +1390,31 @@ static int handle_ioctl_yield( if (ret != 0) break; - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } -/*----------------------------------------------------------------------------*/ -/** +/* * handle ioctl and call common notify * - * @param instance - * @param arg - * - * @return 0 if no error + * returns 0 if no error * */ -static int handle_ioctl_nsiq( - struct mc_instance *instance, - unsigned long arg -) +static int handle_ioctl_nsiq(struct mc_instance *instance, unsigned long arg) { - int ret = 0; + int ret = 0; MCDRV_ASSERT(instance != NULL); /* avoid putting debug output here, as we do this very often */ - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); + /* only the MobiCore Daemon is allowed to call this function */ if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR("caller not MobiCore Daemon\n"); + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); return -EFAULT; } @@ -1572,145 +1426,60 @@ static int handle_ioctl_nsiq( ret = convert_fc_ret(fc_nsiq.as_out.ret); if (ret != 0) break; - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } -/*----------------------------------------------------------------------------*/ -/** - * - * @param instance - * @param arg - * - * @return 0 if no error - * - */ -static int handle_ioctl_dump_status( - struct mc_instance *instance, - unsigned long arg -) +static int handle_ioctl_init(struct mc_instance *instance, + union mc_ioctl_init_params *user_params) { - int ret = 0; - int i = 0; - union mc_fc_info fc_info; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); - - do { - /* anybody with root access can do this. */ - if (!is_userland_caller_privileged()) { - MCDRV_DBG_ERROR("caller must have root privileges\n"); - ret = -EFAULT; - break; - } - - /* loop ext_info */ - while (TRUE) { - memset(&fc_info, 0, sizeof(fc_info)); - fc_info.as_in.cmd = MC_FC_INFO; - fc_info.as_in.ext_info_id = i; - - MCDRV_DBG( - "fc_info in cmd=0x%08x, ext_info_id=0x%08x " - "rfu=(0x%08x, 0x%08x)\n", - fc_info.as_in.cmd, - fc_info.as_in.ext_info_id, - fc_info.as_in.rfu[0], - fc_info.as_in.rfu[1]); - - mc_fastcall(&(fc_info.as_generic)); - - MCDRV_DBG( - "fc_info out resp=0x%08x, ret=0x%08x " - "state=0x%08x, ext_info=0x%08x\n", - fc_info.as_out.resp, - fc_info.as_out.ret, - fc_info.as_out.state, - fc_info.as_out.ext_info); - - ret = convert_fc_ret(fc_info.as_out.ret); - if (ret != 0) - break; - - MCDRV_DBG("state=%08X, idx=%02d: ext_info=%08X\n", - fc_info.as_out.state, - i, - fc_info.as_out.ext_info); - i++; - }; - - if (ret != 0) - break; - - - } while (FALSE); - - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); - - return ret; -} - -/*----------------------------------------------------------------------------*/ -/** - * - * @param instance - * @param arg - * - * @return 0 if no error - * - */ -static int handle_ioctl_init( - struct mc_instance *instance, - union mc_ioctl_init_params *user_params -) -{ - int ret = 0; - union mc_ioctl_init_params params; - union mc_fc_init fc_init; + int ret = 0; + union mc_ioctl_init_params params; + union mc_fc_init fc_init; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { /* only the MobiCore Daemon is allowed to call this function */ if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR("caller not MobiCore Daemon\n"); + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); ret = -EFAULT; break; } - ret = copy_from_user( - &(params.in), - &(user_params->in), - sizeof(params.in)); + ret = copy_from_user(&(params.in), &(user_params->in), + sizeof(params.in)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_from_user failed\n"); + MCDRV_DBG_ERROR(mcd, "copy_from_user failed\n"); break; } memset(&fc_init, 0, sizeof(fc_init)); - fc_init.as_in.cmd = MC_FC_INIT; + fc_init.as_in.cmd = MC_FC_INIT; /* base address of mci buffer 4KB aligned */ - fc_init.as_in.base = (uint32_t)params.in.base; + fc_init.as_in.base = (uint32_t)params.in.base; /* notification buffer start/length [16:16] [start, length] */ - fc_init.as_in.nq_info = (params.in.nq_offset << 16) - | (params.in.nq_length & 0xFFFF); + fc_init.as_in.nq_info = (params.in.nq_offset << 16) | + (params.in.nq_length & 0xFFFF); /* mcp buffer start/length [16:16] [start, length] */ - fc_init.as_in.mcp_info = (params.in.mcp_offset << 16) - | (params.in.mcp_length & 0xFFFF); + fc_init.as_in.mcp_info = (params.in.mcp_offset << 16) | + (params.in.mcp_length & 0xFFFF); - /* Set KMOD notification queue to start of MCI - mciInfo was already set up in mmap */ + /* + * Set KMOD notification queue to start of MCI + * mciInfo was already set up in mmap + */ if (!mci_base) { - MCDRV_DBG_ERROR("No MCI set yet.\n"); + MCDRV_DBG_ERROR(mcd, "No MCI set yet.\n"); return -EFAULT; } - MCDRV_DBG("in cmd=0x%08x, base=0x%08x, " + MCDRV_DBG(mcd, + "in cmd=0x%08x, base=0x%08x, " "nq_info=0x%08x, mcp_info=0x%08x\n", fc_init.as_in.cmd, fc_init.as_in.base, @@ -1719,7 +1488,8 @@ static int handle_ioctl_init( mc_fastcall(&(fc_init.as_generic)); - MCDRV_DBG("out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n", + MCDRV_DBG(mcd, + "out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n", fc_init.as_out.resp, fc_init.as_out.ret, fc_init.as_out.rfu[0], @@ -1731,97 +1501,19 @@ static int handle_ioctl_init( /* no ioctl response parameters */ - } while (FALSE); - - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); - - return ret; -} - -/*----------------------------------------------------------------------------*/ -/** - * - * @param instance - * @param arg - * - * @return 0 if no error - * - */ -static int handle_ioctl_fc_execute( - struct mc_instance *instance, - union mc_ioctl_fc_execute_params *user_params -) -{ - int ret = 0; - union mc_ioctl_fc_execute_params params; - union fc_generic fc_params; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); - - do { - /* only the MobiCore Daemon is allowed to call this function */ - if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR("caller not MobiCore Daemon\n"); - ret = -EFAULT; - break; - } - - ret = copy_from_user( - &(params.in), - &(user_params->in), - sizeof(params.in)); - if (ret != 0) { - MCDRV_DBG_ERROR("copy_from_user failed\n"); - break; - } - - fc_params.as_in.cmd = -4;/*FC_EXECUTE */ - fc_params.as_in.param[0] = params.in.phys_start_addr; - fc_params.as_in.param[1] = params.in.length; - fc_params.as_in.param[2] = 0; - - MCDRV_DBG("in cmd=0x%08x, startAddr=0x%08x, length=0x%08x\n", - fc_params.as_in.cmd, - fc_params.as_in.param[0], - fc_params.as_in.param[1]); - - mc_fastcall(&fc_params); - - MCDRV_DBG("out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n", - fc_params.as_out.resp, - fc_params.as_out.ret, - fc_params.as_out.param[0], - fc_params.as_out.param[1]); - - ret = convert_fc_ret(fc_params.as_out.ret); - if (ret != 0) - break; - - /* no ioctl response parameters */ - - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } -/*----------------------------------------------------------------------------*/ #define MC_MAKE_VERSION(major, minor) \ (((major & 0x0000ffff) << 16) | (minor & 0x0000ffff)) -/** - * - * @param instance - * @param arg - * - * @return 0 if no error - * - */ + static int handle_ioctl_get_version( - struct mc_instance *instance, - struct mc_ioctl_get_version_params *user_params -) + struct mc_instance *instance, + struct mc_ioctl_get_version_params *user_params) { int ret = 0; struct mc_ioctl_get_version_params params = { @@ -1832,42 +1524,27 @@ static int handle_ioctl_get_version( }; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { - MCDRV_DBG("mcDrvModuleApi version is %i.%i\n", - MCDRVMODULEAPI_VERSION_MAJOR, - MCDRVMODULEAPI_VERSION_MINOR); + MCDRV_DBG(mcd, "mcDrvModuleApi version is %i.%i\n", + MCDRVMODULEAPI_VERSION_MAJOR, + MCDRVMODULEAPI_VERSION_MINOR); /* no ioctl response parameters */ - ret = copy_to_user( - &(user_params->out), - &(params.out), - sizeof(params.out)); + ret = copy_to_user(&(user_params->out), &(params.out), + sizeof(params.out)); if (ret != 0) - MCDRV_DBG_ERROR("copy_to_user() failed\n"); + MCDRV_DBG_ERROR(mcd, "copy_to_user() failed\n"); - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } -/*----------------------------------------------------------------------------*/ -/** - * This function will be called from user space as ioctl(...). - * @param file pointer to file - * @param cmd command - * @param arg arguments - * - * @return int 0 for OK and an errno in case of error - */ -static long mc_kernel_module_ioctl( - struct file *file, - unsigned int cmd, - unsigned long arg -) +static long mc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret; struct mc_instance *instance = get_instance(file); @@ -1875,145 +1552,102 @@ static long mc_kernel_module_ioctl( MCDRV_ASSERT(instance != NULL); switch (cmd) { - /*--------------------------------------------------------------------*/ - case MC_DRV_KMOD_IOCTL_DUMP_STATUS: - ret = handle_ioctl_dump_status( - instance, - arg); - break; - - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_FC_INIT: - ret = handle_ioctl_init( - instance, - (union mc_ioctl_init_params *)arg); + ret = handle_ioctl_init(instance, + (union mc_ioctl_init_params *)arg); break; - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_FC_INFO: - ret = handle_ioctl_info( - instance, - (union mc_ioctl_info_params *)arg); + ret = handle_ioctl_info(instance, + (union mc_ioctl_info_params *)arg); break; - - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_FC_YIELD: - ret = handle_ioctl_yield( - instance); + ret = handle_ioctl_yield(instance); break; - - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_FC_NSIQ: - ret = handle_ioctl_nsiq( - instance, - arg); + ret = handle_ioctl_nsiq(instance, arg); break; - - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2: ret = handle_ioctl_daemon_lock_wsm_l2( instance, (struct mc_ioctl_daemon_lock_wsm_l2_params *)arg); break; - - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2: ret = handle_ioctl_daemon_unlock_wsm_l2( instance, (struct mc_ioctl_daemon_unlock_wsm_l2_params *)arg); break; - - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_FREE: /* called by ClientLib */ - ret = handle_ioctl_free( - instance, - (union mc_ioctl_free_params *)arg); + ret = handle_ioctl_free(instance, + (union mc_ioctl_free_params *)arg); break; - - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2: /* called by ClientLib */ ret = handle_ioctl_app_register_wsm_l2( instance, (union mc_ioctl_app_reg_wsm_l2_params *)arg); break; - - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2: /* called by ClientLib */ ret = handle_ioctl_app_unregister_wsm_l2( instance, (struct mc_ioctl_app_unreg_wsm_l2_params *)arg); break; - - /*--------------------------------------------------------------------*/ - case MC_DRV_KMOD_IOCTL_FC_EXECUTE: - ret = handle_ioctl_fc_execute( - instance, - (union mc_ioctl_fc_execute_params *)arg); - break; - - /*--------------------------------------------------------------------*/ case MC_DRV_KMOD_IOCTL_GET_VERSION: ret = handle_ioctl_get_version( instance, (struct mc_ioctl_get_version_params *)arg); break; - - /*--------------------------------------------------------------------*/ default: - MCDRV_DBG_ERROR("unsupported cmd=%d\n", cmd); + MCDRV_DBG_ERROR(mcd, "unsupported cmd=%d\n", cmd); ret = -EFAULT; break; - } /* end switch(cmd) */ #ifdef MC_MEM_TRACES mobicore_log_read(); #endif - return (int)ret; + return (long)ret; } - -/*----------------------------------------------------------------------------*/ /** - * This function will be called from user space as read(...). + * mc_read() - This will be called from user space as read(...) + * @file: file pointer + * @buffer: buffer where to copy to(userspace) + * @buffer_len: number of requested data + * @pos: not used + * * The read function is blocking until a interrupt occurs. In that case the * event counter is copied into user space and the function is finished. - * @param *file - * @param *buffer buffer where to copy to(userspace) - * @param buffer_len number of requested data - * @param *pos not used - * @return ssize_t ok case: number of copied data - * error case: return errno + * + * If OK this function returns the number of copied data otherwise it returns + * errno */ -static ssize_t mc_kernel_module_read( - struct file *file, - char *buffer, - size_t buffer_len, - loff_t *pos -) +static ssize_t mc_read(struct file *file, char *buffer, + size_t buffer_len, loff_t *pos) { - int ret = 0, ssiq_counter; + int ret = 0; + int ssiq_counter; + int ctx_counter; size_t retLen = 0; struct mc_instance *instance = get_instance(file); MCDRV_ASSERT(instance != NULL); /* avoid debug output on non-error, because this is call quite often */ - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { /* only the MobiCore Daemon is allowed to call this function */ if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR("caller not MobiCore Daemon\n"); + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); ret = -EFAULT; break; } if (buffer_len < sizeof(unsigned int)) { - MCDRV_DBG_ERROR("invalid length\n"); + MCDRV_DBG_ERROR(mcd, "invalid length\n"); ret = (ssize_t)(-EINVAL); break; } @@ -2021,16 +1655,20 @@ static ssize_t mc_kernel_module_read( for (;;) { if (down_interruptible( &mc_drv_kmod_ctx.daemon_ctx.sem)) { - MCDRV_DBG_VERBOSE("read interrupted\n"); + MCDRV_DBG_VERBOSE(mcd, "read interrupted\n"); ret = (ssize_t)-ERESTARTSYS; break; } ssiq_counter = atomic_read( &(mc_drv_kmod_ctx.ssiq_ctx.counter)); - MCDRV_DBG_VERBOSE("ssiq_counter=%i, ctx.counter=%i\n", - ssiq_counter, - mc_drv_kmod_ctx.daemon_ctx.ssiq_counter); + ctx_counter = + mc_drv_kmod_ctx.daemon_ctx.ssiq_counter; + + MCDRV_DBG_VERBOSE(mcd, + "ssiq_counter=%i, ctx.counter=%i\n", + ssiq_counter, + ctx_counter); if (ssiq_counter != mc_drv_kmod_ctx.daemon_ctx.ssiq_counter) { @@ -2044,98 +1682,80 @@ static ssize_t mc_kernel_module_read( /* end loop if non-blocking */ if ((file->f_flags & O_NONBLOCK) != 0) { - MCDRV_DBG_ERROR("non-blocking read\n"); + MCDRV_DBG_ERROR(mcd, "non-blocking read\n"); ret = (ssize_t)(-EAGAIN); break; } if (signal_pending(current) != 0) { - MCDRV_DBG_VERBOSE("received signal.\n"); + MCDRV_DBG_VERBOSE(mcd, "received signal.\n"); ret = (ssize_t)(-ERESTARTSYS); break; } } - /* we are here if an event occurred or we had an - error.*/ + /* + * we are here if an event occurred + * or if we had an error. + */ if (ret != 0) break; /* read data and exit loop */ - ret = copy_to_user( - buffer, - &(mc_drv_kmod_ctx.daemon_ctx.ssiq_counter), - sizeof(unsigned int)); - + ret = copy_to_user(buffer, + &(mc_drv_kmod_ctx.daemon_ctx.ssiq_counter), + sizeof(unsigned int)); if (ret != 0) { - MCDRV_DBG_ERROR("copy_to_user failed\n"); + MCDRV_DBG_ERROR(mcd, "copy_to_user failed\n"); ret = (ssize_t)(-EFAULT); break; } retLen = sizeof(s32); - } while (FALSE); + } while (0); /* avoid debug on non-error. */ if (ret == 0) ret = (size_t)retLen; else - MCDRV_DBG("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG(mcd, "exit with %d/0x%08X\n", ret, ret); return (ssize_t)ret; } -/*----------------------------------------------------------------------------*/ -/** - * Allocate WSM for given instance - * - * @param instance instance - * @param requested_size size of the WSM - * @param handle pointer where the handle will be saved - * @param virt_kernel_addr pointer for the kernel virtual address - * @param phys_addr pointer for the physical address - * - * @return error code or 0 for success - */ -int mobicore_allocate_wsm( - struct mc_instance *instance, - unsigned long requested_size, - uint32_t *handle, - void **virt_kernel_addr, - void **phys_addr -) +int mobicore_allocate_wsm(struct mc_instance *instance, + unsigned long requested_size, uint32_t *handle, + void **virt_kernel_addr, void **phys_addr) { - unsigned int i; - unsigned int order; - unsigned long allocated_size; - int ret = 0; - struct mc_contg_buffer *contg_buffer = 0; - void *virt_kernel_addr_stack; - void *phys_addr_stack; + unsigned int i; + unsigned int order; + unsigned long allocated_size; + int ret = 0; + struct mc_contg_buffer *contg_buffer = 0; + void *kaddr_buffer; + void *paddr_buffer; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG("%s (size=%ld)\n", __func__, requested_size); - - order = size_to_order(requested_size); - if (order == INVALID_ORDER) { - MCDRV_DBG_ERROR( - "size to order converting failed for size %ld\n", - requested_size); - return INVALID_ORDER; - } + MCDRV_DBG(mcd, "%s (size=%ld)\n", __func__, requested_size); - allocated_size = (1< order %d --> %ld (2^n pages)\n", + MCDRV_DBG(mcd, "size %ld -> order %d --> %ld (2^n pages)\n", requested_size, order, allocated_size); do { - /* Usual Wsm request, allocate contigous buffer. */ - /* search for a free entry in the wsm buffer list - * REV axh: serialize this over multiple instances. */ + /* + * Usual Wsm request, allocate contigous buffer. + * search for a free entry in the wsm buffer list + */ for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) { contg_buffer = &(instance->contg_buffers[i]); if (contg_buffer->handle == 0) { @@ -2144,334 +1764,291 @@ int mobicore_allocate_wsm( } } if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) { - MCDRV_DBG_ERROR("no free contigous buffer\n"); + MCDRV_DBG_ERROR(mcd, "no free contigous buffer\n"); ret = -EFAULT; break; } /* Common code for all allocation paths */ - virt_kernel_addr_stack = (void *)__get_free_pages( - GFP_USER | __GFP_COMP, + kaddr_buffer = (void *)__get_free_pages(GFP_USER | __GFP_COMP, order); - if (virt_kernel_addr_stack == NULL) { - MCDRV_DBG_ERROR("get_free_pages failed\n"); + if (kaddr_buffer == NULL) { + MCDRV_DBG_ERROR(mcd, "get_free_pages failed\n"); ret = -ENOMEM; break; } /* Get physical address to instance data */ - phys_addr_stack = (void *)virt_to_phys(virt_kernel_addr_stack); - /* TODO: check for INVALID_ADDRESS? */ - - MCDRV_DBG( - "allocated phys=0x%p - 0x%p, " - "size=%ld, kernel_virt=0x%p, handle=%d\n", - phys_addr_stack, - (void *)((unsigned int)phys_addr_stack+allocated_size), - allocated_size, - virt_kernel_addr_stack, - contg_buffer->handle); - - /* Usual Wsm request, allocate contg_buffer. - * Also, we never free a persistent Tci */ - contg_buffer->phys_addr = phys_addr_stack; - contg_buffer->virt_kernel_addr = virt_kernel_addr_stack; - contg_buffer->virt_user_addr = virt_kernel_addr_stack; - contg_buffer->num_pages = (1U << order); + paddr_buffer = (void *)virt_to_phys(kaddr_buffer); + + MCDRV_DBG(mcd, + "allocated phys=0x%p - 0x%p, " + "size=%ld, kernel_virt=0x%p, handle=%d\n", + paddr_buffer, + (void *)((unsigned int)paddr_buffer+allocated_size), + allocated_size, + kaddr_buffer, + contg_buffer->handle); + + /* + * Usual Wsm request, allocate contg_buffer. + * Also, we never free a persistent Tci + */ + contg_buffer->phys_addr = paddr_buffer; + contg_buffer->virt_kernel_addr = kaddr_buffer; + contg_buffer->virt_user_addr = kaddr_buffer; + contg_buffer->order = order; *handle = contg_buffer->handle; - *virt_kernel_addr = virt_kernel_addr_stack; - *phys_addr = phys_addr_stack; + *virt_kernel_addr = kaddr_buffer; + *phys_addr = paddr_buffer; - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("%s: exit with 0x%08X\n", __func__, ret); + MCDRV_DBG_VERBOSE(mcd, "%s: exit with 0x%08X\n", __func__, ret); return ret; } EXPORT_SYMBOL(mobicore_allocate_wsm); - -/*----------------------------------------------------------------------------*/ /** - * This function will be called from user space as address = mmap(...). - * - * @param file - * @param vmarea - * vmarea.pg_offset != 0 is mapping of MCI is requested + * mc_mmap() - Called from user space as address = mmap(...). + * @file: file pointer + * @vmarea: vmarea.pg_offset != 0 is mapping of MCI is requested * - * @return 0 if OK or -ENOMEM in case of error. + * This function returns either 0 or -ENOMEM in case of error. */ -static int mc_kernel_module_mmap( - struct file *file, - struct vm_area_struct *vmarea -) +static int mc_mmap(struct file *file, struct vm_area_struct *vmarea) { - unsigned int i; - unsigned int order; - void *virt_kernel_addr_stack = 0; - void *phys_addr = 0; - unsigned long requested_size = - vmarea->vm_end - vmarea->vm_start; - unsigned long allocated_size; - int ret = 0; - struct mc_contg_buffer *contg_buffer = 0; - unsigned int handle = 0; - struct mc_instance *instance = get_instance(file); - unsigned int request = vmarea->vm_pgoff * 4096; -#if defined(DEBUG) - bool release = false; -#else - bool release = true; -#endif + int ret = 0; + unsigned int i; + struct mc_instance *instance = get_instance(file); + unsigned int request = vmarea->vm_pgoff * 4096; + unsigned long requested_size = vmarea->vm_end - vmarea->vm_start; + unsigned int order; + unsigned long allocated_size; + void *kaddr_buffer = 0; + void *paddr_buffer = 0; + unsigned int pfn; + struct mc_contg_buffer *contg_buffer = 0; + unsigned int uq_handle_buffer = 0; + bool allocate_buffer = false; MCDRV_ASSERT(instance != NULL); - MCDRV_DBG("enter (vmaStart=0x%p, size=%ld, request=0x%x, mci=0x%x)\n", + MCDRV_DBG(mcd, + "enter (vma start=0x%p, size=%ld, request=0x%x, mci=0x%x)\n", (void *)vmarea->vm_start, requested_size, request, mci_base); - order = size_to_order(requested_size); - if (order == INVALID_ORDER) { - MCDRV_DBG_ERROR( - "size to order converting failed for size %ld\n", - requested_size); - return -ENOMEM; + if (requested_size == 0) { + MCDRV_DBG_ERROR(mcd, "cannot allocate size 0\n"); + ret = -ENOMEM; + goto mc_mmap_end; } + order = get_order(requested_size); + allocated_size = (1 << order)*PAGE_SIZE; - allocated_size = (1< order %d --> %ld (2^n pages)\n", + MCDRV_DBG(mcd, + "size %ld -> order %d --> %ld (2^n pages)\n", requested_size, order, allocated_size); - do { - /* Daemon tries to get an existing MCI */ - if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base != 0)) { - MCDRV_DBG("Request MCI, it is at (%x)\n", mci_base); + switch (request) { - if (!is_caller_mc_daemon(instance)) { - ret = -EPERM; - break; - } - virt_kernel_addr_stack = (void *)mci_base; - phys_addr = - (void *)virt_to_phys(virt_kernel_addr_stack); + /* Daemon tries to get the MCI - the MobiCore Interface buffer */ + case MC_DRV_KMOD_MMAP_MCI: + if (!is_caller_mc_daemon(instance)) { + ret = -EPERM; + goto mc_mmap_end; + } + + if (mci_base == 0) { + allocate_buffer = true; } else { - /* Usual Wsm request, allocate buffer. */ - if (request == MC_DRV_KMOD_MMAP_WSM) { - /* search for a free entry in the buffer list - REV axh: serialize this over multiple instances. - */ - for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; - i++) { - contg_buffer = - &(instance->contg_buffers[i]); - if (contg_buffer->handle == 0) { - contg_buffer->handle = - get_mc_kmod_unique_id(); - break; - } - } - if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) { - MCDRV_DBG_ERROR( - "no free contigous buffer\n"); - ret = -EFAULT; - break; - } - } else { - if (request <= MC_DRV_KMOD_MMAP_PERSISTENTWSM - || release) { - /* Special Wsm request - --> only Daemon is allowed */ - if (!is_caller_mc_daemon(instance)) { - ret = -EPERM; - break; - } - } - } - if (request <= MC_DRV_KMOD_MMAP_PERSISTENTWSM) { - /* Common code for all allocation paths - * get physical address, */ - virt_kernel_addr_stack = - (void *)__get_free_pages( - GFP_USER | __GFP_COMP, - order); - if (virt_kernel_addr_stack == NULL) { - MCDRV_DBG_ERROR( - "get_free_pages failed\n"); - ret = -ENOMEM; - break; - } - if (request == MC_DRV_KMOD_MMAP_WSM) - handle = contg_buffer->handle; - /* Get physical address to instance data */ - /* TODO: check for INVALID_ADDRESS? */ - phys_addr = (void *)virt_to_phys( - virt_kernel_addr_stack); - } else { -#if defined(DEBUG) - phys_addr = (void *)request; - virt_kernel_addr_stack = phys_to_virt(request); -#endif - } + MCDRV_DBG(mcd, + "Request MCI, it is at (%x)\n", mci_base); + + kaddr_buffer = (void *)mci_base; + paddr_buffer = (void *)virt_to_phys(kaddr_buffer); + allocate_buffer = false; } - /* Common code for all mmap calls: - * map page to user - * store data in page */ - - MCDRV_DBG("allocated phys=0x%p - 0x%p, " - "size=%ld, kernel_virt=0x%p, handle=%d\n", - phys_addr, - (void *)((unsigned int)phys_addr+allocated_size), - allocated_size, virt_kernel_addr_stack, handle); - - vmarea->vm_flags |= VM_RESERVED; - /* convert Kernel address to User Address. Kernel address begins - at PAGE_OFFSET, user Address range is below PAGE_OFFSET. - Remapping the area is always done, so multiple mappings - of one region are possible. Now remap kernel address - space into user space */ - ret = (int)remap_pfn_range( - vmarea, - (vmarea->vm_start), - addr_to_pfn(phys_addr), - requested_size, - vmarea->vm_page_prot); - if (ret != 0) { - MCDRV_DBG_ERROR("remapPfnRange failed\n"); - - /* free allocated pages when mmap fails, however, do not - do it, when daemon tried to get an MCI that - existed */ - if (!((request == MC_DRV_KMOD_MMAP_MCI) && - (mci_base != 0))) - free_continguous_pages(virt_kernel_addr_stack, - (1U << order)); - break; + break; + /* Usual Wsm request, find free buffer slot. */ + case MC_DRV_KMOD_MMAP_WSM: + /* search for a free slot in the buffer list. */ + for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) { + contg_buffer = &(instance->contg_buffers[i]); + if (contg_buffer->handle == 0) + break; } - - /* Usual Wsm request, allocate contg_buffer. - When requesting Mci, we do not associate the page with - the process. - Note: we also never free the Mci - Also, we never free a persistent Tci */ - if (request == MC_DRV_KMOD_MMAP_WSM) { - contg_buffer->phys_addr = phys_addr; - contg_buffer->virt_kernel_addr = virt_kernel_addr_stack; - contg_buffer->virt_user_addr = - (void *)(vmarea->vm_start); - contg_buffer->num_pages = (1U << order); + if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) { + MCDRV_DBG_WARN(mcd, + "no free slot for wsm buffer avail\n"); + ret = -EFAULT; + goto mc_mmap_end; } - - /* set response in allocated buffer */ - { - struct mc_mmap_resp *mmap_resp = - (struct mc_mmap_resp *)virt_kernel_addr_stack; - /* TODO: do this for daemon only, otherwise set NULL */ - mmap_resp->phys_addr = (uint32_t)phys_addr; - mmap_resp->handle = handle; - if ((request == MC_DRV_KMOD_MMAP_MCI) && - (mci_base != 0)) { - mmap_resp->is_reused = 1; - } else - mmap_resp->is_reused = 0; + uq_handle_buffer = + contg_buffer->handle = get_mc_kmod_unique_id(); + allocate_buffer = true; + break; + /* Special Wsm request that is not bound to a process. */ + case MC_DRV_KMOD_MMAP_PERSISTENTWSM: + if (!is_caller_mc_daemon(instance)) { + ret = -EPERM; + goto mc_mmap_end; } + allocate_buffer = true; + break; + default: +#if defined(DEBUG) + /* + * In debug version, allow mapping of arbitry physical memory to + * a process to allow testing of TZASC/XPU memory protection set + * up by SWd. + */ + paddr_buffer = (void *)request; + kaddr_buffer = phys_to_virt(request); + allocate_buffer = false; +#else + ret = -EPERM; + goto mc_mmap_end; +#endif + break; + } /* switch(request) */ - /* store MCI pointer */ - if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base == 0)) { - mci_base = (uint32_t)virt_kernel_addr_stack; - MCDRV_DBG("MCI base set to 0x%x\n", mci_base); + /* Allocate memory */ + if (allocate_buffer) { + kaddr_buffer = (void *)__get_free_pages(GFP_USER | __GFP_COMP, + order); + if (kaddr_buffer == NULL) { + MCDRV_DBG_WARN(mcd, + "no contiguous region available.\n"); + ret = -ENOMEM; + goto mc_mmap_end; } - } while (FALSE); + paddr_buffer = (void *)virt_to_phys(kaddr_buffer); + } - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + /* + * Common code for all mmap calls: + * map page to user + * store data in page + */ - return (int)ret; + MCDRV_DBG(mcd, + "alloc phys=0x%p - 0x%p, sz=%ld, kernel_virt=0x%p, hndl=%d\n", + paddr_buffer, + (void *)((unsigned int)paddr_buffer+allocated_size), + allocated_size, kaddr_buffer, uq_handle_buffer); + + vmarea->vm_flags |= VM_RESERVED; + + /* + * Convert kernel address to user address. Kernel address begins + * at PAGE_OFFSET, user address range is below PAGE_OFFSET. + * Remapping the area is always done, so multiple mappings + * of one region are possible. Now remap kernel address + * space into user space + */ + pfn = (unsigned int)paddr_buffer >> PAGE_SHIFT; + ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn, + requested_size, vmarea->vm_page_prot); + if (ret != 0) { + MCDRV_DBG_WARN(mcd, "remap_pfn_range failed\n"); + + if (allocate_buffer) + free_continguous_pages(kaddr_buffer, order); + + goto mc_mmap_end; + } + + /* Usual wsm request, store reference to buffer for later freeing. */ + if (request == MC_DRV_KMOD_MMAP_WSM) { + contg_buffer->phys_addr = paddr_buffer; + contg_buffer->virt_kernel_addr = kaddr_buffer; + contg_buffer->virt_user_addr = (void *)(vmarea->vm_start); + contg_buffer->order = order; + } + + /* set response in allocated buffer */ + { + struct mc_mmap_resp *mmap_resp = + (struct mc_mmap_resp *)kaddr_buffer; + mmap_resp->phys_addr = (uint32_t)paddr_buffer; + mmap_resp->handle = uq_handle_buffer; + mmap_resp->is_reused = (request == MC_DRV_KMOD_MMAP_MCI) && + (mci_base != 0); + } + + /* store MCI pointer */ + if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base == 0)) { + mci_base = (uint32_t)kaddr_buffer; + MCDRV_DBG(mcd, "MCI base set to 0x%x\n", mci_base); + } + +mc_mmap_end: + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); + + return ret; } -#ifdef CONFIG_SMP -/*----------------------------------------------------------------------------*/ /** - * Force migration of current task to CPU0(where the monitor resides) + * goto_cpu0() - Force migration of current task to CPU0 * - * @return Error code or 0 for success + * Returns either an error code or 0 for success */ -static int goto_cpu0( - void -) +static int goto_cpu0(void) { - int ret = 0; - struct cpumask mask = CPU_MASK_CPU0; - - MCDRV_DBG_VERBOSE("System has %d CPU's, we are on CPU #%d\n" - "\tBinding this process to CPU #0.\n" - "\tactive mask is %lx, setting it to mask=%lx\n", - nr_cpu_ids, - raw_smp_processor_id(), - cpu_active_mask->bits[0], - mask.bits[0]); + int ret = 0; + struct cpumask mask = CPU_MASK_CPU0; + + MCDRV_DBG_VERBOSE(mcd, "System has %d CPU's, we are on CPU #%d\n", + nr_cpu_ids, raw_smp_processor_id()); + MCDRV_DBG_VERBOSE(mcd, "\tBinding this process to CPU #0.\n"); + MCDRV_DBG_VERBOSE(mcd, "\tactive mask is %lx, setting it to mask=%lx\n", + cpu_active_mask->bits[0], + mask.bits[0]); + ret = set_cpus_allowed_ptr(current, &mask); if (ret != 0) - MCDRV_DBG_ERROR("set_cpus_allowed_ptr=%d.\n", ret); - MCDRV_DBG_VERBOSE("And now we are on CPU #%d\n", - raw_smp_processor_id()); + MCDRV_DBG_ERROR(mcd, "set_cpus_allowed_ptr=%d.\n", ret); + + MCDRV_DBG_VERBOSE(mcd, "And now we are on CPU #%d\n", + raw_smp_processor_id()); return ret; } -/*----------------------------------------------------------------------------*/ /** - * Restore CPU mask for current to ALL Cpus(reverse of goto_cpu0) + * goto_all_cpu() - Restore CPU mask for current to ALL Cpus * - * @return Error code or 0 for success + * Returns either an error code or 0 for success */ -static int goto_all_cpu( - void -) +static int goto_all_cpu(void) { - int ret = 0; + int ret = 0; + struct cpumask mask = CPU_MASK_ALL; - struct cpumask mask = CPU_MASK_ALL; + MCDRV_DBG_VERBOSE(mcd, "System has %d CPU's, we are on CPU #%d\n", + nr_cpu_ids, raw_smp_processor_id()); + MCDRV_DBG_VERBOSE(mcd, "\tBinding this process to CPU #0.\n"); + MCDRV_DBG_VERBOSE(mcd, "\tactive mask is %lx, setting it to mask=%lx\n", + cpu_active_mask->bits[0], mask.bits[0]); - MCDRV_DBG_VERBOSE("System has %d CPU's, we are on CPU #%d\n" - "\tBinding this process to CPU #0.\n" - "\tactive mask is %lx, setting it to mask=%lx\n", - nr_cpu_ids, - raw_smp_processor_id(), - cpu_active_mask->bits[0], - mask.bits[0]); ret = set_cpus_allowed_ptr(current, &mask); if (ret != 0) - MCDRV_DBG_ERROR("set_cpus_allowed_ptr=%d.\n", ret); - MCDRV_DBG_VERBOSE("And now we are on CPU #%d\n", - raw_smp_processor_id()); + MCDRV_DBG_ERROR(mcd, "set_cpus_allowed_ptr=%d.\n", ret); - return ret; -} + MCDRV_DBG_VERBOSE(mcd, "And now we are on CPU #%d\n", + raw_smp_processor_id()); -#else -static int goto_cpu0(void) -{ - return 0; + return ret; } -static int goto_all_cpu(void) +struct mc_instance *mobicore_open(void) { - return 0; -} -#endif - -/*----------------------------------------------------------------------------*/ -/** - * Initialize a new mobicore API instance object - * - * @return Instance or NULL if no allocation was possible. - */ -struct mc_instance *mobicore_open( - void -) { - struct mc_instance *instance; - pid_t pid_vnr; + struct mc_instance *instance; + pid_t pid_vnr; instance = kzalloc(sizeof(*instance), GFP_KERNEL); if (instance == NULL) @@ -2480,9 +2057,11 @@ struct mc_instance *mobicore_open( /* get a unique ID for this instance (PIDs are not unique) */ instance->handle = get_mc_kmod_unique_id(); - /* get the PID of the calling process. We avoid using + /* + * get the PID of the calling process. We avoid using * current->pid directly, as 2.6.24 introduced PID - * namespaces. See also http://lwn.net/Articles/259217 */ + * namespaces. See also http://lwn.net/Articles/259217 + */ pid_vnr = task_pid_vnr(current); instance->pid_vnr = pid_vnr; @@ -2490,59 +2069,62 @@ struct mc_instance *mobicore_open( } EXPORT_SYMBOL(mobicore_open); -/*----------------------------------------------------------------------------*/ /** - * This function will be called from user space as fd = open(...). + * mc_open() - Called from user space as fd = open(...) + * @inode: file inode + * @file: file pointer + * * A set of internal instance data are created and initialized. * - * @param inode - * @param file - * @return 0 if OK or -ENOMEM if no allocation was possible. + * This function returns either 0 or -ENOMEM in case of error. */ -static int mc_kernel_module_open( - struct inode *inode, - struct file *file -) +static int mc_open(struct inode *inode, struct file *file) { - struct mc_instance *instance; - int ret = 0; + struct mc_instance *instance; + int ret = 0; - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { instance = mobicore_open(); if (instance == NULL) return -ENOMEM; - /* check if Daemon. We simply assume that the first to open us - with root privileges must be the daemon. */ - if ((is_userland_caller_privileged()) - && (mc_drv_kmod_ctx.daemon_inst == NULL)) { - MCDRV_DBG("accept this as MobiCore Daemon\n"); + /* + * check if Daemon. We simply assume that the first to open us + * with root privileges must be the daemon. + */ + if ((is_userland_caller_privileged()) && + (mc_drv_kmod_ctx.daemon_inst == NULL)) { + MCDRV_DBG(mcd, "accept this as MobiCore Daemon\n"); - /* Set the caller's CPU mask to CPU0*/ + /* Set the caller's CPU mask to CPU0 */ ret = goto_cpu0(); if (ret != 0) { mobicore_release(instance); file->private_data = NULL; - MCDRV_DBG("changing core failed!\n"); + MCDRV_DBG(mcd, "changing core failed!\n"); break; } mc_drv_kmod_ctx.daemon_inst = instance; sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem, - DAEMON_SEM_VAL); + DAEMON_SEM_VAL); /* init ssiq event counter */ mc_drv_kmod_ctx.daemon_ctx.ssiq_counter = atomic_read( &(mc_drv_kmod_ctx.ssiq_ctx.counter)); #ifdef MC_MEM_TRACES - /* The traces have to be setup on CPU-0 since we must - * do a fastcall to MobiCore. */ + /* + * The traces have to be setup on CPU-0 since we must + * do a fastcall to MobiCore. + */ if (!mci_base) - /* Do the work only if MCI base is not - * initialized properly */ + /* + * Do the work only if MCI base is not + * initialized properly + */ work_on_cpu(0, mobicore_log_setup, NULL); #endif } @@ -2550,25 +2132,15 @@ static int mc_kernel_module_open( /* store instance data reference */ file->private_data = instance; - /* TODO axh: link all instances to allow clean up? */ + } while (0); - } while (FALSE); - - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return (int)ret; } -/*----------------------------------------------------------------------------*/ -/** - * Release a mobicore instance object and all objects related to it - * @param instance instance - * @return 0 if Ok or -E ERROR - */ -int mobicore_release( - struct mc_instance *instance -) +int mobicore_release(struct mc_instance *instance) { int ret = 0; int i; @@ -2578,29 +2150,32 @@ int mobicore_release( /* try to get the semaphore */ ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); if (ret != 0) { - MCDRV_DBG_ERROR( - "down_interruptible() failed with %d\n", ret); - /* TODO: can be block here? */ + MCDRV_DBG_ERROR(mcd, + "down_interruptible() failed %d\n", + ret); + ret = -ERESTARTSYS; } else { /* Check if some WSM is still in use. */ list_for_each_entry_safe( - used_l2table, - used_l2table_temp, - &(mc_drv_kmod_ctx.mc_used_l2_tables), - list + used_l2table, used_l2table_temp, + &(mc_drv_kmod_ctx.mc_used_l2_tables), + list ) { if (used_l2table->owner == instance) { MCDRV_DBG_WARN( + mcd, "trying to release WSM L2: " "physBase=%p ,nr_of_pages=%d\n", get_l2_table_phys(used_l2table), used_l2table->nr_of_pages); - /* unlock app usage and free if MobiCore - does not use it */ + /* + * unlock app usage and free if MobiCore + * does not use it + */ delete_used_l2_table(used_l2table, - FREE_FROM_NWD); + FREE_FROM_NWD); } } /* end while */ @@ -2608,7 +2183,6 @@ int mobicore_release( up(&(mc_drv_kmod_ctx.wsm_l2_sem)); } - /* release all mapped data */ for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) { struct mc_contg_buffer *contg_buffer = @@ -2617,89 +2191,79 @@ int mobicore_release( if (contg_buffer->virt_user_addr != 0) { free_continguous_pages( contg_buffer->virt_kernel_addr, - contg_buffer->num_pages); + contg_buffer->order); } } /* release instance context */ kfree(instance); - } while (FALSE); + } while (0); return ret; } EXPORT_SYMBOL(mobicore_release); -/*----------------------------------------------------------------------------*/ /** - * This function will be called from user space as close(...). - * The instance data are freed and the associated memory pages are unreserved. + * mc_release() - Called from user space as close(...) + * @inode: file inode + * @file: file pointer * - * @param inode - * @param file + * The instance data are freed and the associated memory pages are unreserved. * - * @return 0 + * Returns either an error code or 0 on success */ -static int mc_kernel_module_release( - struct inode *inode, - struct file *file -) +static int mc_release(struct inode *inode, struct file *file) { - int ret = 0; - struct mc_instance *instance = get_instance(file); + int ret = 0; + struct mc_instance *instance = get_instance(file); - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); do { /* check if daemon closes us. */ if (is_caller_mc_daemon(instance)) { - /* TODO: cleanup? - * mc_drv_kmod_ctx.mc_used_l2_tables remains */ - MCDRV_DBG_WARN("WARNING: MobiCore Daemon died\n"); + MCDRV_DBG_WARN(mcd, "WARNING: MobiCore Daemon died\n"); mc_drv_kmod_ctx.daemon_inst = NULL; } ret = mobicore_release(instance); - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - return (int)ret; + return ret; } - -/*----------------------------------------------------------------------------*/ /** - * This function represents the interrupt function of the mcDrvModule. - * It signals by incrementing of an event counter and the start of the read - * waiting queue, the read function a interrupt has occurred. + * mc_intr_ssiq() - The interrupt function of the mcDrvModule + * @intr: Interrupt number + * @context: pointer to registered device data * - * @param intr - * @param *context pointer to registered device data + * This function signals an interrupt by incrementing of an event counter + * and the start of the read waiting queue * - * @return IRQ_HANDLED + * Returns either IRQ_HANDLED or IRQ_NONE */ -static irqreturn_t mc_kernel_module_intr_ssiq( - int intr, - void *context -) +static irqreturn_t mc_intr_ssiq(int intr, void *context) { - irqreturn_t ret = IRQ_NONE; + irqreturn_t ret = IRQ_NONE; /* we know the context. */ MCDRV_ASSERT(&mc_drv_kmod_ctx == context); do { if (intr != MC_INTR_SSIQ) { - /* this should not happen, as we did no register for any - other interrupt. For debugging, we print a - message, but continue */ - MCDRV_DBG_WARN( - "unknown interrupt %d, expecting only %d\n", - intr, MC_INTR_SSIQ); + /* + * this should not happen, as we did no register for any + * other interrupt. For debugging, we print a message, + * but continue + */ + MCDRV_DBG_WARN(mcd, + "unknown int %d, expecting only %d\n", + intr, MC_INTR_SSIQ); } - MCDRV_DBG_VERBOSE("received interrupt %d\n", - intr); + MCDRV_DBG_VERBOSE(mcd, "received interrupt %d\n", intr); /* increment interrupt event counter */ atomic_inc(&(mc_drv_kmod_ctx.ssiq_ctx.counter)); @@ -2707,89 +2271,77 @@ static irqreturn_t mc_kernel_module_intr_ssiq( /* signal the daemon */ up(&mc_drv_kmod_ctx.daemon_ctx.sem); - ret = IRQ_HANDLED; - } while (FALSE); + } while (0); return ret; } -/*----------------------------------------------------------------------------*/ -/** function table structure of this device driver. */ -static const struct file_operations mc_kernel_module_file_operations = { - .owner = THIS_MODULE, /**< driver owner */ - .open = mc_kernel_module_open, /**< driver open function */ - .release = mc_kernel_module_release, /**< driver release function*/ - .unlocked_ioctl = mc_kernel_module_ioctl, /**< driver ioctl function */ - .mmap = mc_kernel_module_mmap, /**< driver mmap function */ - .read = mc_kernel_module_read, /**< driver read function */ +/* function table structure of this device driver. */ +static const struct file_operations mc_file_operations = { + .owner = THIS_MODULE, /*< driver owner */ + .open = mc_open, /*< driver open function */ + .release = mc_release, /*< driver rel function*/ + .unlocked_ioctl = mc_ioctl, /*< driver ioctl function */ + .mmap = mc_mmap, /*< driver mmap function */ + .read = mc_read, /*< driver read function */ }; -/*----------------------------------------------------------------------------*/ -/** registration structure as miscdevice. */ -static struct miscdevice mc_kernel_module_device = { - .name = MC_DRV_MOD_DEVNODE, /**< device name */ - .minor = MISC_DYNAMIC_MINOR, /**< device minor number */ - /** device interface function structure */ - .fops = &mc_kernel_module_file_operations, +/* registration structure as miscdevice. */ +static struct miscdevice mc_device = { + .name = MC_DRV_MOD_DEVNODE, /*< device name */ + .minor = MISC_DYNAMIC_MINOR, /*< device minor number */ + /* device interface function structure */ + .fops = &mc_file_operations, }; - -/*----------------------------------------------------------------------------*/ -/** - * This function is called the kernel during startup or by a insmod command. - * This device is installed and registered as miscdevice, then interrupt and - * queue handling is set up - * - * @return 0 for no error or -EIO if registration fails - */ -static int __init mc_kernel_module_init( - void -) +static int __init mc_init(void) { int ret = 0; - MCDRV_DBG("enter (Build " __TIMESTAMP__ ")\n"); - MCDRV_DBG("mcDrvModuleApi version is %i.%i\n", - MCDRVMODULEAPI_VERSION_MAJOR, - MCDRVMODULEAPI_VERSION_MINOR); + dev_set_name(mcd, "mcd"); + + MCDRV_DBG(mcd, "enter (Build " __TIMESTAMP__ ")\n"); + MCDRV_DBG(mcd, "mcDrvModuleApi version is %i.%i\n", + MCDRVMODULEAPI_VERSION_MAJOR, + MCDRVMODULEAPI_VERSION_MINOR); #ifdef MOBICORE_COMPONENT_BUILD_TAG - MCDRV_DBG("%s\n", MOBICORE_COMPONENT_BUILD_TAG); + MCDRV_DBG(mcd, "%s\n", MOBICORE_COMPONENT_BUILD_TAG); #endif do { - /* Hardware does not support ARM TrustZone - -> Cannot continue! */ - if (!has_security_extensions()) { - MCDRV_DBG_ERROR( - "Hardware does't support ARM TrustZone!\n"); + /* + * Hardware does not support ARM TrustZone + * -> Cannot continue! + */ + if (has_security_extensions() == false) { + MCDRV_DBG_ERROR(mcd, + "HW does't support ARM TrustZone!\n"); ret = -ENODEV; break; } /* Running in secure mode -> Cannot load the driver! */ - if (is_secure_mode()) { - MCDRV_DBG_ERROR("Running in secure MODE!\n"); + if (is_secure_mode() == true) { + MCDRV_DBG_ERROR(mcd, "Running in secure MODE!\n"); ret = -ENODEV; break; } sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem, DAEMON_SEM_VAL); + /* set up S-SIQ interrupt handler */ - ret = request_irq( - MC_INTR_SSIQ, - mc_kernel_module_intr_ssiq, - IRQF_TRIGGER_RISING, - MC_DRV_MOD_DEVNODE, + ret = request_irq(MC_INTR_SSIQ, mc_intr_ssiq, + IRQF_TRIGGER_RISING, MC_DRV_MOD_DEVNODE, &mc_drv_kmod_ctx); if (ret != 0) { - MCDRV_DBG_ERROR("interrupt request failed\n"); + MCDRV_DBG_ERROR(mcd, "interrupt request failed\n"); break; } - ret = misc_register(&mc_kernel_module_device); + ret = misc_register(&mc_device); if (ret != 0) { - MCDRV_DBG_ERROR("device register failed\n"); + MCDRV_DBG_ERROR(mcd, "device register failed\n"); break; } @@ -2804,66 +2356,52 @@ static int __init mc_kernel_module_init( sema_init(&(mc_drv_kmod_ctx.wsm_l2_sem), 1); - /* initialize unique number counter which we can use for - handles. It is limited to 2^32, but this should be - enough to be roll-over safe for us. We start with 1 - instead of 0. */ + /* + * initialize unique number counter which we can use for + * handles. It is limited to 2^32, but this should be + * enough to be roll-over safe for us. We start with 1 + * instead of 0. + */ atomic_set(&(mc_drv_kmod_ctx.unique_counter), 1); mci_base = 0; - MCDRV_DBG("initialized\n"); + MCDRV_DBG(mcd, "initialized\n"); ret = 0; - } while (FALSE); + } while (0); - MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret); + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - return (int)ret; + return ret; } - - -/*----------------------------------------------------------------------------*/ -/** - * This function removes this device driver from the Linux device manager . - */ -static void __exit mc_kernel_module_exit( - void -) +static void __exit mc_exit(void) { struct mc_used_l2_table *used_l2table; - MCDRV_DBG_VERBOSE("enter\n"); + MCDRV_DBG_VERBOSE(mcd, "enter\n"); mobicore_log_free(); /* Check if some WSM is still in use. */ - list_for_each_entry( - used_l2table, - &(mc_drv_kmod_ctx.mc_used_l2_tables), - list - ) { - MCDRV_DBG_WARN( - "WSM L2 still in use: physBase=%p ,nr_of_pages=%d\n", - get_l2_table_phys(used_l2table), - used_l2table->nr_of_pages); - } /* end while */ + list_for_each_entry(used_l2table, &(mc_drv_kmod_ctx.mc_used_l2_tables), + list) { + MCDRV_DBG_WARN(mcd, + "WSM L2 in use: physBase=%p ,nr_of_pages=%d\n", + get_l2_table_phys(used_l2table), + used_l2table->nr_of_pages); + } /* end list_for_each_entry */ free_irq(MC_INTR_SSIQ, &mc_drv_kmod_ctx); - misc_deregister(&mc_kernel_module_device); - MCDRV_DBG_VERBOSE("exit"); + misc_deregister(&mc_device); + MCDRV_DBG_VERBOSE(mcd, "exit"); } - -/*----------------------------------------------------------------------------*/ /* Linux Driver Module Macros */ -module_init(mc_kernel_module_init); -module_exit(mc_kernel_module_exit); +module_init(mc_init); +module_exit(mc_exit); MODULE_AUTHOR("Giesecke & Devrient GmbH"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MobiCore driver"); - -/** @} */ - diff --git a/drivers/gud/mobicore_driver/mc_drv_module.h b/drivers/gud/mobicore_driver/mc_drv_module.h index 8b402d6ff37..c540c940858 100644 --- a/drivers/gud/mobicore_driver/mc_drv_module.h +++ b/drivers/gud/mobicore_driver/mc_drv_module.h @@ -1,107 +1,110 @@ -/** - * Header file of MobiCore Driver Kernel Module. +/* + * MobiCore Driver Kernel Module. * - * @addtogroup MCD_MCDIMPL_KMOD_IMPL - * @{ * Internal structures of the McDrvModule - * @file * - * Header file the MobiCore Driver Kernel Module, - * its internal structures and defines. - * - * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef _MC_DRV_KMOD_H_ -#define _MC_DRV_KMOD_H_ +#ifndef _MC_DRV_MODULE_H +#define _MC_DRV_MODULE_H + +#include +#include -#include "mc_drv_module_linux_api.h" #include "public/mc_drv_module_api.h" -/** Platform specific settings */ -#include "platform.h" -/** ARM Specific masks and modes */ -#define ARM_CPSR_MASK 0x1F -#define ARM_MONITOR_MODE 0b10110 -#define ARM_SECURITY_EXTENSION_MASK 0x30 +/* Platform specific settings */ +#include "platform.h" -/** - * Number of page table entries in one L2 table. This is ARM specific, an - * L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each. +/* + * ARM Trustzone specific masks and modes + * Vanilla Linux is unaware of TrustZone extension. + * I.e. arch/arm/include/asm/ptrace.h does not define monitor mode. + * Also TZ bits in cpuid is not defined, ARM port uses magic numbers, + * see arch/arm/kernel/setup.c */ -#define MC_ARM_L2_TABLE_ENTRIES 256 - -/** Maximum number of contiguous buffer allocations for one driver instance. */ -#define MC_DRV_KMOD_CONTG_BUFFER_MAX 16 - -/** Number of pages for L2 tables. There are 4 table in each page. */ -#define MC_DRV_KMOD_L2_TABLE_PER_PAGES 4 - -/** ARM level 2 (L2) table with 256 entries. Size: 1k */ -struct l2table { - pte_t table_entries[MC_ARM_L2_TABLE_ENTRIES]; -}; +#define ARM_MONITOR_MODE (0b10110) +#define ARM_SECURITY_EXTENSION_MASK 0x30 -#define INVALID_ADDRESS ((void *)(-1)) - -/** ARM L2 PTE bits */ -#define L2_FLAG_SMALL_XN (1U << 0) -#define L2_FLAG_SMALL (1U << 1) -#define L2_FLAG_B (1U << 2) -#define L2_FLAG_C (1U << 3) -#define L2_FLAG_AP0 (1U << 4) -#define L2_FLAG_AP1 (1U << 5) -#define L2_FLAG_SMALL_TEX0 (1U << 6) -#define L2_FLAG_SMALL_TEX1 (1U << 7) -#define L2_FLAG_SMALL_TEX2 (1U << 8) -#define L2_FLAG_APX (1U << 9) -#define L2_FLAG_S (1U << 10) -#define L2_FLAG_NG (1U << 11) - -/** +/* * Contiguous buffer allocated to TLCs. * These buffers are uses as world shared memory (wsm) and shared with * secure world. * The virtual kernel address is added for a simpler search algorithm. */ struct mc_contg_buffer { - unsigned int handle; /* unique handle */ - void *virt_user_addr; /**< virtual User start address */ - void *virt_kernel_addr; /**< virtual Kernel start address */ - void *phys_addr; /**< physical start address */ - unsigned int num_pages; /**< number of pages */ + unsigned int handle; /* unique handle */ + void *virt_user_addr; /* virtual User start address */ + + /* virtual kernel start address */ + void *virt_kernel_addr; + + void *phys_addr; /* physical start address */ + unsigned int order; /* order of number of pages */ }; -/** Instance data for MobiCore Daemon and TLCs. */ +/* + * Maximum number of contiguous buffer allocations that one process can get via + * mmap + */ +#define MC_DRV_KMOD_CONTG_BUFFER_MAX 16 + +/* Instance data for MobiCore Daemon and TLCs. */ struct mc_instance { - /** unique handle */ + /* unique handle */ unsigned int handle; - /** process that opened this instance */ + /* process that opened this instance */ pid_t pid_vnr; - /** buffer list for mmap generated address space and - its virtual client address */ + + /* + * buffer list for mmap generated address space and its virtual client + * address + */ struct mc_contg_buffer contg_buffers[MC_DRV_KMOD_CONTG_BUFFER_MAX]; }; -/** Store for four L2 tables in one 4kb page*/ +/* + * MobiCore specific page tables for world shared memory. + * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level. + * MobiCore uses the default ARM format. + * + * Number of page table entries in one L2 table. This is ARM specific, an + * L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each. + */ +#define MC_ARM_L2_TABLE_ENTRIES 256 + +/* ARM level 2 (L2) table with 256 entries. Size: 1k */ +struct l2table { + pte_t table_entries[MC_ARM_L2_TABLE_ENTRIES]; +}; + +/* Number of pages for L2 tables. There are 4 table in each page. */ +#define MC_DRV_KMOD_L2_TABLE_PER_PAGES 4 + +/* Store for four L2 tables in one 4kb page*/ struct mc_l2_table_store { struct l2table table[MC_DRV_KMOD_L2_TABLE_PER_PAGES]; }; -/** Usage and maintenance information about mc_l2_table_store */ +/* Usage and maintenance information about mc_l2_table_store */ struct mc_l2_tables_set { struct list_head list; - unsigned int usage_bitmap; /**< usage bitmap */ - struct mc_l2_table_store *kernel_virt; /**< kernel virtual address */ - struct mc_l2_table_store *phys; /**< physical address */ - struct page *page; /**< pointer to page struct */ + unsigned int usage_bitmap; /* usage bitmap */ + + /* kernel virtual address */ + struct mc_l2_table_store *kernel_virt; + struct mc_l2_table_store *phys; /* physical address */ + + /* pointer to page struct */ + struct page *page; }; -/** +/* * L2 table allocated to the Daemon or a TLC describing a world shared buffer. * When users map a malloc()ed area into SWd, a L2 table is allocated. * In addition, the area of maximum 1MB virtual address space is mapped into @@ -110,116 +113,116 @@ struct mc_l2_tables_set { struct mc_used_l2_table { struct list_head list; - /** handle as communicated to user mode */ + /* handle as communicated to user mode */ unsigned int handle; unsigned int flags; - /** owner of this L2 table */ + /* owner of this L2 table */ struct mc_instance *owner; - /** set describing where our L2 table is stored */ + /* set describing where our L2 table is stored */ struct mc_l2_tables_set *set; - /** index into L2 table set */ + /* index into L2 table set */ unsigned int idx; - /** size of buffer */ + /* size of buffer */ unsigned int nr_of_pages; }; #define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP (1U << 0) #define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC (1U << 1) - -/** MobiCore S-SIQ interrupt context data. */ +/* MobiCore S-SIQ interrupt context data. */ struct mc_ssiq_ctx { - /** S-SIQ interrupt counter */ + /* S-SIQ interrupt counter */ atomic_t counter; }; -/** MobiCore Daemon context data. */ +/* MobiCore Daemon context data. */ struct mc_daemon_ctx { - /** event semaphore */ + /* event semaphore */ struct semaphore sem; struct fasync_struct *async_queue; - /** event counter */ + /* event counter */ unsigned int ssiq_counter; }; -/** MobiCore Driver Kernel Module context data. */ +/* MobiCore Driver Kernel Module context data. */ struct mc_drv_kmod_ctx { - /** ever incrementing counter */ + /* ever incrementing counter */ atomic_t unique_counter; - /** S-SIQ interrupt context */ + /* S-SIQ interrupt context */ struct mc_ssiq_ctx ssiq_ctx; - /** MobiCore Daemon context */ + /* MobiCore Daemon context */ struct mc_daemon_ctx daemon_ctx; - /** pointer to instance of daemon */ + /* pointer to instance of daemon */ struct mc_instance *daemon_inst; - /** Backing store for L2 tables */ + /* Backing store for L2 tables */ struct list_head mc_l2_tables_sets; - /** Bookkeeping for used L2 tables */ + /* Bookkeeping for used L2 tables */ struct list_head mc_used_l2_tables; - /** semaphore to synchronize access to above lists */ + /* semaphore to synchronize access to above lists */ struct semaphore wsm_l2_sem; }; -/** MobiCore internal trace buffer structure. */ +/* MobiCore internal trace buffer structure. */ struct mc_trace_buf { - uint32_t version; /**< version of trace buffer */ - uint32_t length; /**< length of allocated buffer(includes header) */ - uint32_t write_pos; /**< last write position */ - char buff[1]; /**< start of the log buffer */ + uint32_t version; /* version of trace buffer */ + uint32_t length; /* len of allocated buffer(includes header) */ + uint32_t write_pos; /* last write position */ + char buff[1]; /* start of the log buffer */ }; -/*** MobiCore internal trace log setup. */ +/* MobiCore internal trace log setup. */ void mobicore_log_read(void); long mobicore_log_setup(void *); void mobicore_log_free(void); -#define MCDRV_DBG_ERROR(txt, ...) \ - printk(KERN_ERR "mcDrvKMod [%d] %s() ### ERROR: " txt, \ +/* Found in main.c */ +extern struct device *mcd; + +#define MCDRV_DBG_ERROR(dev, txt, ...) \ + dev_err(dev, "[%d] %s() ### ERROR: " txt, \ task_pid_vnr(current), \ __func__, \ ##__VA_ARGS__) /* dummy function helper macro. */ -#define DUMMY_FUNCTION() do {} while (0) +#define DUMMY_FUNCTION() do {} while (0) #if defined(DEBUG) - -/* #define DEBUG_VERBOSE */ #if defined(DEBUG_VERBOSE) -#define MCDRV_DBG_VERBOSE MCDRV_DBG +#define MCDRV_DBG_VERBOSE MCDRV_DBG #else -#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() +#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() #endif -#define MCDRV_DBG(txt, ...) \ - printk(KERN_INFO "mcDrvKMod [%d on CPU%d] %s(): " txt, \ - task_pid_vnr(current), \ - raw_smp_processor_id(), \ - __func__, \ - ##__VA_ARGS__) +#define MCDRV_DBG(dev, txt, ...) \ + dev_info(dev, "[%d on CPU%d] %s(): " txt, \ + task_pid_vnr(current), \ + raw_smp_processor_id(), \ + __func__, \ + ##__VA_ARGS__) -#define MCDRV_DBG_WARN(txt, ...) \ - printk(KERN_WARNING "mcDrvKMod [%d] %s() WARNING: " txt, \ - task_pid_vnr(current), \ - __func__, \ - ##__VA_ARGS__) +#define MCDRV_DBG_WARN(dev, txt, ...) \ + dev_warn(dev, "[%d] %s() WARNING: " txt, \ + task_pid_vnr(current), \ + __func__, \ + ##__VA_ARGS__) #define MCDRV_ASSERT(cond) \ do { \ if (unlikely(!(cond))) { \ - panic("mcDrvKMod Assertion failed: %s:%d\n", \ - __FILE__, __LINE__); \ + panic("Assertion failed: %s:%d\n", \ + __FILE__, __LINE__); \ } \ } while (0) @@ -233,6 +236,4 @@ void mobicore_log_free(void); #endif /* [not] defined(DEBUG) */ - -#endif /* _MC_DRV_KMOD_H_ */ -/** @} */ +#endif /* _MC_DRV_MODULE_H */ diff --git a/drivers/gud/mobicore_driver/mc_drv_module_android.h b/drivers/gud/mobicore_driver/mc_drv_module_android.h index 319509f3445..d6f216138ef 100644 --- a/drivers/gud/mobicore_driver/mc_drv_module_android.h +++ b/drivers/gud/mobicore_driver/mc_drv_module_android.h @@ -1,14 +1,9 @@ -/** +/* * Header file of MobiCore Driver Kernel Module. * - * @addtogroup MobiCore_Driver_Kernel_Module - * @{ * Android specific defines - * @file * - * Android specific defines - * - * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,11 +13,14 @@ #ifndef _MC_DRV_MODULE_ANDROID_H_ #define _MC_DRV_MODULE_ANDROID_H_ -/* Defines needed to identify the Daemon in Android systems +#ifdef CONFIG_ANDROID +/* + * Defines needed to identify the Daemon in Android systems * For the full list see: * platform_system_core/include/private/android_filesystem_config.h in the * Android source tree */ + /* traditional unix root user */ #define AID_ROOT 0 /* system server */ @@ -33,5 +31,7 @@ /* first app user */ #define AID_APP 10000 +#endif /* CONFIG_ANDROID */ + #endif /* _MC_DRV_MODULE_ANDROID_H_ */ -/** @} */ + diff --git a/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h b/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h index d0580432491..0d4f92c1cc1 100644 --- a/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h +++ b/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h @@ -1,60 +1,51 @@ -/** +/* * Header file of MobiCore Driver Kernel Module. * - * @addtogroup MobiCore_Driver_Kernel_Module - * @{ - * Internal structures of the McDrvModule - * @file - * * MobiCore Fast Call interface * - * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef _MC_DRV_MODULE_FC_H_ -#define _MC_DRV_MODULE_FC_H_ +#ifndef _MC_DRV_MODULE_FASTCALLS_H_ +#define _MC_DRV_MODULE_FASTCALLS_H_ #include "mc_drv_module.h" -/** +/* * MobiCore SMCs */ enum mc_smc_codes { - MC_SMC_N_YIELD = 0x3, /**< Yield to switch from NWd to SWd. */ - MC_SMC_N_SIQ = 0x4 /**< SIQ to switch from NWd to SWd. */ + MC_SMC_N_YIELD = 0x3, /* Yield to switch from NWd to SWd. */ + MC_SMC_N_SIQ = 0x4 /* SIQ to switch from NWd to SWd. */ }; -/** +/* * MobiCore fast calls. See MCI documentation */ enum mc_fast_call_codes { - MC_FC_INIT = -1, - MC_FC_INFO = -2, - MC_FC_POWER = -3, - MC_FC_DUMP = -4, - MC_FC_NWD_TRACE = -31 /**< Mem trace setup fastcall */ + MC_FC_INIT = -1, + MC_FC_INFO = -2, + MC_FC_POWER = -3, + MC_FC_DUMP = -4, + MC_FC_NWD_TRACE = -31 /* Mem trace setup fastcall */ }; -/** +/* * return code for fast calls */ enum mc_fast_calls_result { - MC_FC_RET_OK = 0, - MC_FC_RET_ERR_INVALID = 1, - MC_FC_RET_ERR_ALREADY_INITIALIZED = 5 + MC_FC_RET_OK = 0, + MC_FC_RET_ERR_INVALID = 1, + MC_FC_RET_ERR_ALREADY_INITIALIZED = 5 }; +/* structure wrappers for specific fastcalls */ - -/*------------------------------------------------------------------------------ - structure wrappers for specific fastcalls -------------------------------------------------------------------------------*/ - -/** generic fast call parameters */ +/* generic fast call parameters */ union fc_generic { struct { uint32_t cmd; @@ -67,8 +58,7 @@ union fc_generic { } as_out; }; - -/** fast call init */ +/* fast call init */ union mc_fc_init { union fc_generic as_generic; struct { @@ -84,8 +74,7 @@ union mc_fc_init { } as_out; }; - -/** fast call info parameters */ +/* fast call info parameters */ union mc_fc_info { union fc_generic as_generic; struct { @@ -101,8 +90,7 @@ union mc_fc_info { } as_out; }; - -/** fast call S-Yield parameters */ +/* fast call S-Yield parameters */ union mc_fc_s_yield { union fc_generic as_generic; struct { @@ -116,8 +104,7 @@ union mc_fc_s_yield { } as_out; }; - -/** fast call N-SIQ parameters */ +/* fast call N-SIQ parameters */ union mc_fc_nsiq { union fc_generic as_generic; struct { @@ -131,30 +118,27 @@ union mc_fc_nsiq { } as_out; }; - -/*----------------------------------------------------------------------------*/ /** - * fast call to MobiCore + * mc_fastcall() - fast call to MobiCore * - * @param fc_generic pointer to fast call data + * @fc_generic: pointer to fast call data */ -static inline void mc_fastcall( - union fc_generic *fc_generic -) +static inline void mc_fastcall(union fc_generic *fc_generic) { MCDRV_ASSERT(fc_generic != NULL); - /* We only expect to make smc calls on CPU0 otherwise something wrong - * will happen */ + + /* + * We only expect to make smc calls on CPU0 otherwise something wrong + * will happen + */ MCDRV_ASSERT(raw_smp_processor_id() == 0); + + /* Required by an old version of MobiCore, subject to be removed. */ mb(); #ifdef MC_SMC_FASTCALL { int ret = 0; - MCDRV_DBG("Going into SCM()"); ret = smc_fastcall((void *)fc_generic, sizeof(*fc_generic)); - MCDRV_DBG("Coming from SCM, scm_call=%i, resp=%d/0x%x\n", - ret, - fc_generic->as_out.resp, fc_generic->as_out.resp); } #else { @@ -165,14 +149,18 @@ static inline void mc_fastcall( register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2]; /* one of the famous preprocessor hacks to stingitize things.*/ -#define __STR2(x) #x +#define __STR2(x) (#x) #define __STR(x) __STR2(x) - /* compiler does not support certain instructions - "SMC": secure monitor call.*/ + /* + * Compiler does not support certain instructions + * "SMC": secure monitor call + */ #define ASM_ARM_SMC 0xE1600070 - /* "BPKT": debugging breakpoint. We keep this, as is comes - quite handy for debugging. */ + /* + * "BPKT": debugging breakpoint. + * We keep this, as is comes quite handy for debugging. + */ #define ASM_ARM_BPKT 0xE1200070 #define ASM_THUMB_BPKT 0xBE00 @@ -191,37 +179,27 @@ static inline void mc_fastcall( #endif } - -/*----------------------------------------------------------------------------*/ -/** +/* * convert fast call return code to linux driver module error code - * */ -static inline int convert_fc_ret( - uint32_t sret -) +static inline int convert_fc_ret(uint32_t sret) { - int ret = -EFAULT; + int ret = -EFAULT; switch (sret) { - case MC_FC_RET_OK: ret = 0; break; - case MC_FC_RET_ERR_INVALID: ret = -EINVAL; break; - case MC_FC_RET_ERR_ALREADY_INITIALIZED: ret = -EBUSY; break; - default: break; - } /* end switch( sret ) */ + } return ret; } -#endif /* _MC_DRV_MODULE_FC_H_ */ -/** @} */ +#endif /* _MC_DRV_MODULE_FASTCALLS_H_ */ diff --git a/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h b/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h deleted file mode 100644 index b2a99f17355..00000000000 --- a/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h +++ /dev/null @@ -1,187 +0,0 @@ -/** - * Header file of MobiCore Driver Kernel Module. - * - * @addtogroup MobiCore_Driver_Kernel_Module - * @{ - * Wrapper for Linux API - * @file - * - * Some convenient wrappers for memory functions - * - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _MC_DRV_MODULE_LINUX_API_H_ -#define _MC_DRV_MODULE_LINUX_API_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* make some nice types */ -#if !defined(TRUE) -#define TRUE (1 == 1) -#endif - -#if !defined(FALSE) -#define FALSE (1 != 1) -#endif - - -/* Linux GCC modifiers */ -#if !defined(__init) -#warning "missing definition: __init" -/* define a dummy */ -#define __init -#endif - - -#if !defined(__exit) -#warning "missing definition: __exit" -/* define a dummy */ -#define __exit -#endif - - -#if !defined(__must_check) -#warning "missing definition: __must_check" -/* define a dummy */ -#define __must_check -#endif - - -#if !defined(__user) -#warning "missing definition: __user" -/* define a dummy */ -#define __user -#endif - -#define INVALID_ORDER ((unsigned int)(-1)) - -/*----------------------------------------------------------------------------*/ -/* get start address of the 4 KiB page where the given addres is located in. */ -static inline void *get_page_start( - void *addr -) -{ - return (void *)(((unsigned long)(addr)) & PAGE_MASK); -} - -/*----------------------------------------------------------------------------*/ -/* get offset into the 4 KiB page where the given addres is located in. */ -static inline unsigned int get_offset_in_page( - void *addr -) -{ - return (unsigned int)(((unsigned long)(addr)) & (~PAGE_MASK)); -} - -/*----------------------------------------------------------------------------*/ -/* get number of pages for a given buffer. */ -static inline unsigned int get_nr_of_pages_for_buffer( - void *addr_start, /* may be null */ - unsigned int len -) -{ - /* calculate used number of pages. Example: - offset+size newSize+PAGE_SIZE-1 nr_of_pages - 0 4095 0 - 1 4096 1 - 4095 8190 1 - 4096 8191 1 - 4097 8192 2 */ - - return (get_offset_in_page(addr_start) + len + PAGE_SIZE-1) / PAGE_SIZE; -} - - -/*----------------------------------------------------------------------------*/ -/** - * convert a given size to page order, which is equivalent to finding log_2(x). - * The maximum for order was 5 in Linux 2.0 corresponding to 32 pages. - * Later versions allow 9 corresponding to 512 pages, which is 2 MB on - * most platforms). Anyway, the bigger order is, the more likely it is - * that the allocation will fail. - * Size 0 1 4097 8193 12289 24577 28673 40961 61441 - * Pages - 1 2 3 4 7 8 15 16 - * Order INVALID_ORDER 0 1 1 2 2 3 3 4 - * - * @param size - * @return order - */ -static inline unsigned int size_to_order( - unsigned int size -) -{ - unsigned int order = INVALID_ORDER; - - if (size != 0) { - /* ARMv5 as a CLZ instruction which count the leading zeros of - the binary representation of a value. It return a value - between 0 and 32. - Value 0 1 2 3 4 5 6 7 8 9 10 ... - CLZ 32 31 30 30 29 29 29 29 28 28 28 ... - - We have excluded Size==0 before, so this is safe. */ - order = __builtin_clz( - get_nr_of_pages_for_buffer(NULL, size)); - - /* there is a size overflow in get_nr_of_pages_for_buffer when - * the size is too large */ - if (unlikely(order > 31)) - return INVALID_ORDER; - order = 31 - order; - - /* above algorithm rounds down: clz(5)=2 instead of 3 */ - /* quick correction to fix it: */ - if (((1<> PAGE_SHIFT; -} - - -/*----------------------------------------------------------------------------*/ -/* return the address of a page frame number */ -static inline void *pfn_to_addr( - unsigned int pfn -) -{ - /* there is no real API for this */ - return (void *)(pfn << PAGE_SHIFT); -} - -#endif /* _MC_DRV_MODULE_LINUX_API_H_ */ -/** @} */ diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h index 070222e39f9..9efa0263cb0 100644 --- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h +++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h @@ -1,32 +1,23 @@ -/** - * Header file of MobiCore Driver Kernel Module Platform - * specific structures - * - * @addtogroup MobiCore_Driver_Kernel_Module - * @{ - * Internal structures of the McDrvModule - * @file - * - * Header file the MobiCore Driver Kernel Module, +/* + * Header file for the MobiCore Driver Kernel Module, * its internal structures and defines. * - * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef _MC_DRV_PLATFORM_H_ -#define _MC_DRV_PLATFORM_H_ +#ifndef _MC_PLATFORM_H_ +#define _MC_PLATFORM_H_ -/** MobiCore Interrupt for Qualcomm */ +/* MobiCore Interrupt for Qualcomm */ #define MC_INTR_SSIQ 280 -/** Use SMC for fastcalls */ +/* Use SMC for fastcalls */ #define MC_SMC_FASTCALL - /*--------------- Implementation -------------- */ #include /* from following file */ @@ -34,17 +25,16 @@ #define SCM_CMD_MOBICORE 1 extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, - void *resp_buf, size_t resp_len); + void *resp_buf, size_t resp_len); static inline int smc_fastcall(void *fc_generic, size_t size) { return scm_call(SCM_SVC_MOBICORE, SCM_CMD_MOBICORE, - fc_generic, size, - fc_generic, size); + fc_generic, size, + fc_generic, size); } -/** Enable mobicore mem traces */ +/* Enable mobicore mem traces */ #define MC_MEM_TRACES -#endif /* _MC_DRV_PLATFORM_H_ */ -/** @} */ +#endif /* _MC_PLATFORM_H_ */ diff --git a/drivers/gud/mobicore_driver/public/mc_drv_module_api.h b/drivers/gud/mobicore_driver/public/mc_drv_module_api.h index 59366f35f2a..fc6f69fb03e 100644 --- a/drivers/gud/mobicore_driver/public/mc_drv_module_api.h +++ b/drivers/gud/mobicore_driver/public/mc_drv_module_api.h @@ -1,10 +1,4 @@ -/** @addtogroup MCD_MCDIMPL_KMOD_API Mobicore Driver Module API - * @ingroup MCD_MCDIMPL_KMOD - * @{ - * Interface to Mobicore Driver Kernel Module. - * @file - * - *

Introduction

+/* * The MobiCore Driver Kernel Module is a Linux device driver, which represents * the command proxy on the lowest layer to the secure world (Swd). Additional * services like memory allocation via mmap and generation of a L2 tables for @@ -16,15 +10,7 @@ * The MobiCore Driver Kernel Module must be installed via * "insmod mcDrvModule.ko". * - * - *

Version history

- * - * - * - * - *
DateVersionChanges
2010-05-250.1Initial Release
- * - * + * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,65 +37,64 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _MC_DRV_MODULEAPI_H_ -#define _MC_DRV_MODULEAPI_H_ +#ifndef _MC_DRV_MODULE_API_H_ +#define _MC_DRV_MODULE_API_H_ #include "version.h" -#define MC_DRV_MOD_DEVNODE "mobicore" -#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/" MC_DRV_MOD_DEVNODE +#define MC_DRV_MOD_DEVNODE "mobicore" +#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/" MC_DRV_MOD_DEVNODE -/** +/* * Data exchange structure of the MC_DRV_MODULE_INIT ioctl command. * INIT request data to SWD */ union mc_ioctl_init_params { struct { - /** base address of mci buffer 4KB align */ - uint32_t base; - /** notification buffer start/length [16:16] [start, length] */ - uint32_t nq_offset; - /** length of notification queue */ - uint32_t nq_length; - /** mcp buffer start/length [16:16] [start, length] */ - uint32_t mcp_offset; - /** length of mcp buffer */ - uint32_t mcp_length; + /* base address of mci buffer 4KB align */ + uint32_t base; + /* notification buffer start/length [16:16] [start, length] */ + uint32_t nq_offset; + /* length of notification queue */ + uint32_t nq_length; + /* mcp buffer start/length [16:16] [start, length] */ + uint32_t mcp_offset; + /* length of mcp buffer */ + uint32_t mcp_length; } in; struct { /* nothing */ } out; }; - -/** +/* * Data exchange structure of the MC_DRV_MODULE_INFO ioctl command. * INFO request data to the SWD */ union mc_ioctl_info_params { struct { - uint32_t ext_info_id; /**< extended info ID */ + uint32_t ext_info_id; /* extended info ID */ } in; struct { - uint32_t state; /**< state */ - uint32_t ext_info; /**< extended info */ + uint32_t state; /* state */ + uint32_t ext_info; /* extended info */ } out; }; -/** - * Mmap allocates and maps contiguous memory into a process. +/* + * mmap allocates and maps contiguous memory into a process. * We use the third parameter, void *offset, to distinguish between some cases * offset = MC_DRV_KMOD_MMAP_WSM usual operation, pages are registered in - device structure and freed later. + * device structure and freed later. * offset = MC_DRV_KMOD_MMAP_MCI get Instance of MCI, allocates or mmaps - the MCI to daemon + * the MCI to daemon * offset = MC_DRV_KMOD_MMAP_PERSISTENTWSM special operation, without - registration of pages + * registration of pages * * In mmap(), the offset specifies which of several device I/O pages is - * requested. Linux only transfers the page number, i.e. the upper 20 bits to - * kernel module. Therefore we define our special offsets as multiples of page - * size. + * requested. Linux only transfers the page number, i.e. the upper 20 bits to + * kernel module. Therefore we define our special offsets as multiples of page + * size. */ enum mc_mmap_memtype { MC_DRV_KMOD_MMAP_WSM = 0, @@ -118,54 +103,52 @@ enum mc_mmap_memtype { }; struct mc_mmap_resp { - uint32_t handle; /**< WSN handle */ - uint32_t phys_addr; /**< physical address of WSM (or NULL) */ - bool is_reused; /**< if WSM memory was reused, or new allocated */ + uint32_t handle; /* WSN handle */ + uint32_t phys_addr; /* physical address of WSM (or NULL) */ + bool is_reused; /* if WSM memory was reused, or new allocated */ }; -/** +/* * Data exchange structure of the MC_DRV_KMOD_IOCTL_FREE ioctl command. */ union mc_ioctl_free_params { struct { - uint32_t handle; /**< driver handle */ - uint32_t pid; /**< process id */ + uint32_t handle;/* driver handle */ + uint32_t pid; /* process id */ } in; struct { /* nothing */ } out; }; - -/** - * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 command. - * - * Allocates a physical L2 table and maps the buffer into this page. - * Returns the physical address of the L2 table. - * The page alignment will be created and the appropriated pSize and pOffsetL2 - * will be modified to the used values. +/* + * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 + * command. */ union mc_ioctl_app_reg_wsm_l2_params { struct { - uint32_t buffer; /**< base address of the virtual address */ - uint32_t len; /**< size of the virtual address space */ - uint32_t pid; /**< process id */ + uint32_t buffer; /* base address of the virtual address */ + uint32_t len; /* size of the virtual address space */ + uint32_t pid; /* process id */ } in; struct { - uint32_t handle; /**< driver handle for locked memory */ - uint32_t phys_wsm_l2_table; /* physical address of the L2 table */ + /* driver handle for locked memory */ + uint32_t handle; + + /* physical address of the L2 table */ + uint32_t phys_wsm_l2_table; } out; }; -/** +/* * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2 * command. */ struct mc_ioctl_app_unreg_wsm_l2_params { struct { - uint32_t handle; /**< driver handle for locked memory */ - uint32_t pid; /**< process id */ + uint32_t handle; /* driver handle for locked memory */ + uint32_t pid; /* process id */ } in; struct { /* nothing */ @@ -173,12 +156,12 @@ struct mc_ioctl_app_unreg_wsm_l2_params { }; -/** +/* * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 command. */ struct mc_ioctl_daemon_lock_wsm_l2_params { struct { - uint32_t handle; /**< driver handle for locked memory */ + uint32_t handle; /* driver handle for locked memory */ } in; struct { uint32_t phys_wsm_l2_table; @@ -186,90 +169,72 @@ struct mc_ioctl_daemon_lock_wsm_l2_params { }; -/** +/* * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2 * command. */ struct mc_ioctl_daemon_unlock_wsm_l2_params { struct { - uint32_t handle; /**< driver handle for locked memory */ - } in; - struct { - /* nothing */ - } out; -}; - -/** - * Data exchange structure of the MC_DRV_MODULE_FC_EXECUTE ioctl command. - */ -union mc_ioctl_fc_execute_params { - struct { - /**< base address of mobicore binary */ - uint32_t phys_start_addr; - /**< length of DDR area */ - uint32_t length; + uint32_t handle; /* driver handle for locked memory */ } in; struct { /* nothing */ } out; }; -/** +/* * Data exchange structure of the MC_DRV_MODULE_GET_VERSION ioctl command. */ struct mc_ioctl_get_version_params { struct { - uint32_t kernel_module_version; + uint32_t kernel_module_version; } out; }; -/* @defgroup Mobicore_Driver_Kernel_Module_Interface IOCTL */ - - - - -/* TODO: use IOCTL macros like _IOWR. See Documentation/ioctl/ioctl-number.txt, - Documentation/ioctl/ioctl-decoding.txt */ -/** - * defines for the ioctl mobicore driver module function call from user space. +/* + * defines for the ioctl MobiCore driver module function call from user space. */ enum mc_kmod_ioctl { /* * get detailed MobiCore Status + * internal, unsupported */ - MC_DRV_KMOD_IOCTL_DUMP_STATUS = 200, + MC_DRV_KMOD_IOCTL_DUMP_STATUS = 200, /* * initialize MobiCore */ - MC_DRV_KMOD_IOCTL_FC_INIT = 201, + MC_DRV_KMOD_IOCTL_FC_INIT = 201, /* * get MobiCore status */ - MC_DRV_KMOD_IOCTL_FC_INFO = 202, + MC_DRV_KMOD_IOCTL_FC_INFO = 202, - /** + /* * ioctl parameter to send the YIELD command to the SWD. * Only possible in Privileged Mode. * ioctl(fd, MC_DRV_MODULE_YIELD) */ - MC_DRV_KMOD_IOCTL_FC_YIELD = 203, - /** + MC_DRV_KMOD_IOCTL_FC_YIELD = 203, + + /* * ioctl parameter to send the NSIQ signal to the SWD. * Only possible in Privileged Mode * ioctl(fd, MC_DRV_MODULE_NSIQ) */ - MC_DRV_KMOD_IOCTL_FC_NSIQ = 204, - /** + MC_DRV_KMOD_IOCTL_FC_NSIQ = 204, + + /* * ioctl parameter to tzbsp to start Mobicore binary from DDR. * Only possible in Privileged Mode * ioctl(fd, MC_DRV_KMOD_IOCTL_FC_EXECUTE) + * internal, unsupported */ - MC_DRV_KMOD_IOCTL_FC_EXECUTE = 205, + MC_DRV_KMOD_IOCTL_FC_EXECUTE = 205, - /** + /* * Free's memory which is formerly allocated by the driver's mmap * command. The parameter must be this mmaped address. * The internal instance data regarding to this address are deleted as @@ -278,34 +243,35 @@ enum mc_kmod_ioctl { * Usage: ioctl(fd, MC_DRV_MODULE_FREE, &address) with address beeing of * type long address */ - MC_DRV_KMOD_IOCTL_FREE = 218, + MC_DRV_KMOD_IOCTL_FREE = 218, - /** + /* * Creates a L2 Table of the given base address and the size of the * data. * Parameter: mc_ioctl_app_reg_wsm_l2_params */ - MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 = 220, + MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 = 220, - /** + /* * Frees the L2 table created by a MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 * ioctl. * Parameter: mc_ioctl_app_unreg_wsm_l2_params */ MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2 = 221, + /* + * Locked memory is still in use by SWd. + * internal, unsupported + */ + MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 = 222, + MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2 = 223, - /* TODO: comment this. */ - MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 = 222, - MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2 = 223, - - /** + /* * Return kernel driver version. * Parameter: mc_ioctl_get_version_params */ - MC_DRV_KMOD_IOCTL_GET_VERSION = 224, + MC_DRV_KMOD_IOCTL_GET_VERSION = 224, }; -#endif /* _MC_DRV_MODULEAPI_H_ */ -/** @} */ +#endif /* _MC_DRV_MODULE_API_H_ */ diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/mobicore_driver/public/mc_kernel_api.h index fdfc61876aa..6408776e1d5 100644 --- a/drivers/gud/mobicore_driver/public/mc_kernel_api.h +++ b/drivers/gud/mobicore_driver/public/mc_kernel_api.h @@ -1,100 +1,79 @@ -/** @addtogroup MCD_MCDIMPL_KMOD_KAPI Mobicore Driver Module API inside Kernel. - * @ingroup MCD_MCDIMPL_KMOD - * @{ +/* * Interface to Mobicore Driver Kernel Module inside Kernel. - * @file * - * Interface to be used by module MobiCoreKernelAPI. - * - * + * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef _MOBICORE_KERNELMODULE_API_H_ -#define _MOBICORE_KERNELMODULE_API_H_ +#ifndef _MC_KERNEL_API_H_ +#define _MC_KERNEL_API_H_ struct mc_instance; /** - * Initialize a new mobicore API instance object + * mobicore_open() - Initialize a new MobiCore API instance object * - * @return Instance or NULL if no allocation was possible. + * Returns a MobiCore Instance or NULL if no allocation was possible. */ -struct mc_instance *mobicore_open( - void -); +struct mc_instance *mobicore_open(void); /** - * Release a mobicore instance object and all objects related to it - * @param instance instance - * @return 0 if Ok or -E ERROR + * mobicore_release() - Release a MobiCore instance object + * @instance: MobiCore instance + * + * Returns 0 if Ok or -E ERROR */ -int mobicore_release( - struct mc_instance *instance -); +int mobicore_release(struct mc_instance *instance); /** - * Free a WSM buffer allocated with mobicore_allocate_wsm - * @param instance - * @param handle handle of the buffer - * - * @return 0 if no error + * mobicore_allocate_wsm() - Allocate MobiCore WSM + * @instance: instance data for MobiCore Daemon and TLCs + * @requested_size: memory size requested in bytes + * @handle: pointer to handle + * @kernel_virt_addr: virtual user start address + * @phys_addr: physical start address * + * Returns 0 if OK */ -int mobicore_allocate_wsm( - struct mc_instance *instance, - unsigned long requested_size, - uint32_t *handle, - void **kernel_virt_addr, - void **phys_addr -); +int mobicore_allocate_wsm(struct mc_instance *instance, + unsigned long requested_size, + uint32_t *handle, + void **kernel_virt_addr, + void **phys_addr); /** - * Free a WSM buffer allocated with mobicore_allocate_wsm - * @param instance - * @param handle handle of the buffer - * - * @return 0 if no error + * mobicore_free() - Free a WSM buffer allocated with mobicore_allocate_wsm + * @instance: instance data for MobiCore Daemon and TLCs + * @handle: handle of the buffer * + * Returns 0 if OK */ -int mobicore_free( - struct mc_instance *instance, - uint32_t handle -); +int mobicore_free(struct mc_instance *instance, uint32_t handle); /** - * Map a virtual memory buffer structure to Mobicore - * @param instance - * @param addr address of the buffer(NB it must be kernel virtual!) - * @param len buffer length - * @param handle pointer to handle - * @param phys_wsm_l2_table pointer to physical L2 table(?) - * - * @return 0 if no error + * mobicore_map_vmem() - Map a virtual memory buffer structure to Mobicore + * @instance: instance data for MobiCore Daemon and TLCs + * @addr: address of the buffer (NB it must be kernel virtual!) + * @len: buffer length (in bytes) + * @handle: unique handle + * @phys_wsm_l2_table: pointer for physical address of L2 table * + * Returns 0 if no error */ -int mobicore_map_vmem( - struct mc_instance *instance, - void *addr, - uint32_t len, - uint32_t *handle, - void **phys_wsm_l2_table -); +int mobicore_map_vmem(struct mc_instance *instance, void *addr, + uint32_t len, uint32_t *handle, + void **phys_wsm_l2_table); /** - * Unmap a virtual memory buffer from mobicore - * @param instance - * @param handle - * - * @return 0 if no error + * mobicore_unmap_vmem() - Unmap a virtual memory buffer from MobiCore + * @instance: instance data for MobiCore Daemon and TLCs + * @handle: unique handle * + * Returns 0 if no error */ -int mobicore_unmap_vmem( - struct mc_instance *instance, - uint32_t handle -); -#endif /* _MOBICORE_KERNELMODULE_API_H_ */ -/** @} */ +int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle); + +#endif /* _MC_KERNEL_API_H_ */ diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/mobicore_driver/public/version.h index 9b2dbcadb9d..d0d272c2ba1 100644 --- a/drivers/gud/mobicore_driver/public/version.h +++ b/drivers/gud/mobicore_driver/public/version.h @@ -1,6 +1,5 @@ -/** @addtogroup MCD_MCDIMPL_KMOD - * @{ - * +/* + * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,10 +26,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _MC_DRV_VERSION_H_ -#define _MC_DRV_VERSION_H_ +#ifndef _VERSION_H_ +#define _VERSION_H_ #define MCDRVMODULEAPI_VERSION_MAJOR 0 #define MCDRVMODULEAPI_VERSION_MINOR 1 -#endif /* _MC_DRV_VERSION_H_ */ +#endif /* _VERSION_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/mobicore_kernelapi/clientlib.c index 13826f281b2..264e7aaf2b5 100644 --- a/drivers/gud/mobicore_kernelapi/clientlib.c +++ b/drivers/gud/mobicore_kernelapi/clientlib.c @@ -1,7 +1,7 @@ -/** +/* * MobiCore KernelApi module * - * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -25,10 +25,8 @@ /* device list */ LIST_HEAD(devices); -/*----------------------------------------------------------------------------*/ -static struct mcore_device_t *resolve_device_id( - uint32_t device_id -) { +static struct mcore_device_t *resolve_device_id(uint32_t device_id) +{ struct mcore_device_t *tmp; struct list_head *pos; @@ -41,19 +39,13 @@ static struct mcore_device_t *resolve_device_id( return NULL; } - -/*----------------------------------------------------------------------------*/ -static void add_device( - struct mcore_device_t *device -) { +static void add_device(struct mcore_device_t *device) +{ list_add_tail(&(device->list), &devices); } - -/*----------------------------------------------------------------------------*/ -static bool remove_device( - uint32_t device_id -) { +static bool remove_device(uint32_t device_id) +{ struct mcore_device_t *tmp; struct list_head *pos, *q; @@ -68,22 +60,18 @@ static bool remove_device( return false; } - -/*----------------------------------------------------------------------------*/ -enum mc_result mc_open_device( - uint32_t device_id -) { +enum mc_result mc_open_device(uint32_t device_id) +{ enum mc_result mc_result = MC_DRV_OK; struct connection *dev_con = NULL; - MCDRV_DBG_VERBOSE("===%s()===", __func__); - - /* Enter critical section */ + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { struct mcore_device_t *device = resolve_device_id(device_id); if (device != NULL) { - MCDRV_DBG_ERROR("Device %d already opened", device_id); + MCDRV_DBG_ERROR(mc_kapi, + "Device %d already opened", device_id); mc_result = MC_DRV_ERR_INVALID_OPERATION; break; } @@ -92,6 +80,7 @@ enum mc_result mc_open_device( dev_con = connection_new(); if (!connection_connect(dev_con, MC_DAEMON_PID)) { MCDRV_DBG_ERROR( + mc_kapi, "Could not setup netlink connection to PID %u", MC_DAEMON_PID); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; @@ -100,12 +89,11 @@ enum mc_result mc_open_device( /* Forward device open to the daemon and read result */ struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device = { - /* C++ does not support C99 designated initializers */ - /* .header = */ { - /* .command_id = */ MC_DRV_CMD_OPEN_DEVICE + { + MC_DRV_CMD_OPEN_DEVICE }, - /* .payload = */ { - /* .device_id = */ device_id + { + device_id } }; @@ -114,8 +102,9 @@ enum mc_result mc_open_device( &mc_drv_cmd_open_device, sizeof(struct mc_drv_cmd_open_device_t)); if (len < 0) { - MCDRV_DBG_ERROR("CMD_OPEN_DEVICE writeCmd failed " - "ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_OPEN_DEVICE writeCmd failed %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } @@ -126,14 +115,16 @@ enum mc_result mc_open_device( &rsp_header, sizeof(rsp_header)); if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR("CMD_OPEN_DEVICE readRsp failed " - "ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_OPEN_DEVICE readRsp failed %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR("CMD_OPEN_DEVICE failed, respId=%d", - rsp_header.response_id); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_OPEN_DEVICE failed, respId=%d", + rsp_header.response_id); switch (rsp_header.response_id) { case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR: mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; @@ -154,8 +145,9 @@ enum mc_result mc_open_device( device = mcore_device_create(device_id, dev_con); if (!mcore_device_open(device, MC_DRV_MOD_DEVNODE_FULLPATH)) { mcore_device_cleanup(device); - MCDRV_DBG_ERROR("could not open device file: %s", - MC_DRV_MOD_DEVNODE_FULLPATH); + MCDRV_DBG_ERROR(mc_kapi, + "could not open device file: %s", + MC_DRV_MOD_DEVNODE_FULLPATH); mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE; break; } @@ -167,25 +159,20 @@ enum mc_result mc_open_device( if (mc_result != MC_DRV_OK) connection_cleanup(dev_con); - /* Exit critical section */ - return mc_result; } EXPORT_SYMBOL(mc_open_device); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_close_device( - uint32_t device_id -) { +enum mc_result mc_close_device(uint32_t device_id) +{ enum mc_result mc_result = MC_DRV_OK; - MCDRV_DBG_VERBOSE("===%s()===", __func__); + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - /* Enter critical section */ do { struct mcore_device_t *device = resolve_device_id(device_id); if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } @@ -193,15 +180,15 @@ enum mc_result mc_close_device( /* Return if not all sessions have been closed */ if (mcore_device_has_sessions(device)) { - MCDRV_DBG_ERROR("cannot close with sessions pending"); + MCDRV_DBG_ERROR(mc_kapi, + "cannot close with sessions pending"); mc_result = MC_DRV_ERR_SESSION_PENDING; break; } struct mc_drv_cmd_close_device_t mc_drv_cmd_close_device = { - /* C++ does not support C99 designated initializers */ - /* .header = */ { - /* .command_id = */ MC_DRV_CMD_CLOSE_DEVICE + { + MC_DRV_CMD_CLOSE_DEVICE } }; int len = connection_write_data( @@ -210,8 +197,9 @@ enum mc_result mc_close_device( sizeof(struct mc_drv_cmd_close_device_t)); /* ignore error, but log details */ if (len < 0) { - MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE writeCmd failed " - "ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_CLOSE_DEVICE writeCmd failed %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; } @@ -221,15 +209,17 @@ enum mc_result mc_close_device( &rsp_header, sizeof(rsp_header)); if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE readResp failed " - " ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_CLOSE_DEVICE readResp failed %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE failed, respId=%d", - rsp_header.response_id); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_CLOSE_DEVICE failed, respId=%d", + rsp_header.response_id); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } @@ -238,44 +228,37 @@ enum mc_result mc_close_device( } while (false); - /* Exit critical section */ - return mc_result; } EXPORT_SYMBOL(mc_close_device); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_open_session( - struct mc_session_handle *session, - const struct mc_uuid_t *uuid, - uint8_t *tci, - uint32_t len -) { +enum mc_result mc_open_session(struct mc_session_handle *session, + const struct mc_uuid_t *uuid, + uint8_t *tci, uint32_t len) +{ enum mc_result mc_result = MC_DRV_OK; - MCDRV_DBG_VERBOSE("===%s()===", __func__); - - /* Enter critical section */ + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { if (session == NULL) { - MCDRV_DBG_ERROR("Session is null"); + MCDRV_DBG_ERROR(mc_kapi, "Session is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } if (uuid == NULL) { - MCDRV_DBG_ERROR("UUID is null"); + MCDRV_DBG_ERROR(mc_kapi, "UUID is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } if (tci == NULL) { - MCDRV_DBG_ERROR("TCI is null"); + MCDRV_DBG_ERROR(mc_kapi, "TCI is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } if (len > MC_MAX_TCI_LEN) { - MCDRV_DBG_ERROR("TCI length is longer than %d", - MC_MAX_TCI_LEN); + MCDRV_DBG_ERROR(mc_kapi, "TCI length is longer than %d", + MC_MAX_TCI_LEN); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } @@ -284,7 +267,7 @@ enum mc_result mc_open_session( struct mcore_device_t *device = resolve_device_id(session->device_id); if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } @@ -294,40 +277,40 @@ enum mc_result mc_open_session( struct wsm *wsm = mcore_device_find_contiguous_wsm(device, tci); if (wsm == NULL) { - MCDRV_DBG_ERROR("Could not resolve TCI phy address "); + MCDRV_DBG_ERROR(mc_kapi, + "Could not resolve TCI phy address "); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } if (wsm->len < len) { - MCDRV_DBG_ERROR("length is more than allocated TCI"); + MCDRV_DBG_ERROR(mc_kapi, + "length is more than allocated TCI"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } /* Prepare open session command */ struct mc_drv_cmd_open_session_t cmdOpenSession = { - /* C++ does not support C99 designated initializers */ - /* .header = */ { - /* .command_id = */ MC_DRV_CMD_OPEN_SESSION + { + MC_DRV_CMD_OPEN_SESSION }, - /* .payload = */ { - /* .device_id = */ session->device_id, - /* .uuid = */ *uuid, - /* .tci = */ (uint32_t)wsm->phys_addr, - /* .len = */ len + { + session->device_id, + *uuid, + (uint32_t)wsm->phys_addr, + len } }; /* Transmit command data */ - - int len = connection_write_data( - dev_con, + int len = connection_write_data(dev_con, &cmdOpenSession, sizeof(cmdOpenSession)); if (len != sizeof(cmdOpenSession)) { - MCDRV_DBG_ERROR("CMD_OPEN_SESSION writeData failed " - "ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_OPEN_SESSION writeData failed %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } @@ -336,20 +319,21 @@ enum mc_result mc_open_session( /* read header first */ struct mc_drv_response_header_t rsp_header; - len = connection_read_datablock( - dev_con, - &rsp_header, - sizeof(rsp_header)); + len = connection_read_datablock(dev_con, + &rsp_header, + sizeof(rsp_header)); if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR("CMD_OPEN_SESSION readResp failed " - " ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_OPEN_SESSION readResp failed %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR("CMD_OPEN_SESSION failed, respId=%d", - rsp_header.response_id); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_OPEN_SESSION failed, respId=%d", + rsp_header.response_id); switch (rsp_header.response_id) { case MC_DRV_RSP_TRUSTLET_NOT_FOUND: mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE; @@ -366,14 +350,15 @@ enum mc_result mc_open_session( /* read payload */ struct mc_drv_rsp_open_session_payload_t - rsp_open_session_payload; + rsp_open_session_payload; len = connection_read_datablock( dev_con, &rsp_open_session_payload, sizeof(rsp_open_session_payload)); if (len != sizeof(rsp_open_session_payload)) { - MCDRV_DBG_ERROR("CMD_OPEN_SESSION readPayload failed " - "ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_OPEN_SESSION readPayload fail %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } @@ -383,9 +368,10 @@ enum mc_result mc_open_session( /* Set up second channel for notifications */ struct connection *session_connection = connection_new(); - /*TODO: no real need to connect here? */ + if (!connection_connect(session_connection, MC_DAEMON_PID)) { MCDRV_DBG_ERROR( + mc_kapi, "Could not setup netlink connection to PID %u", MC_DAEMON_PID); connection_cleanup(session_connection); @@ -393,42 +379,38 @@ enum mc_result mc_open_session( break; } - /*TODO CONTINOUE HERE !!!! FIX RW RETURN HANDLING!!!! */ - /* Write command to use channel for notifications */ struct mc_drv_cmd_nqconnect_t cmd_nqconnect = { - /* C++ does not support C99 designated initializers */ - /* .header = */ { - /* .command_id = */ MC_DRV_CMD_NQ_CONNECT + { + MC_DRV_CMD_NQ_CONNECT }, - /* .payload = */ { - /* .device_id = */ session->device_id, - /* .session_id = */ session->session_id, - /* .device_session_id = */ + { + session->device_id, + session->session_id, rsp_open_session_payload.device_session_id, - /* .session_magic = */ - rsp_open_session_payload.session_magic + rsp_open_session_payload.session_magic } }; connection_write_data(session_connection, - &cmd_nqconnect, - sizeof(cmd_nqconnect)); + &cmd_nqconnect, + sizeof(cmd_nqconnect)); /* Read command response, header first */ - len = connection_read_datablock( - session_connection, - &rsp_header, - sizeof(rsp_header)); + len = connection_read_datablock(session_connection, + &rsp_header, + sizeof(rsp_header)); if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR("CMD_NQ_CONNECT readRsp failed " - "ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_NQ_CONNECT readRsp failed %d", + len); connection_cleanup(session_connection); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR("CMD_NQ_CONNECT failed, respId=%d", + MCDRV_DBG_ERROR(mc_kapi, + "CMD_NQ_CONNECT failed, respId=%d", rsp_header.response_id); connection_cleanup(session_connection); mc_result = MC_DRV_ERR_NQ_FAILED; @@ -438,84 +420,78 @@ enum mc_result mc_open_session( /* there is no payload. */ /* Session established, new session object must be created */ - mcore_device_create_new_session( - device, - session->session_id, - session_connection); + mcore_device_create_new_session(device, + session->session_id, + session_connection); } while (false); - /* Exit critical section */ - return mc_result; } EXPORT_SYMBOL(mc_open_session); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_close_session( - struct mc_session_handle *session -) { +enum mc_result mc_close_session(struct mc_session_handle *session) +{ enum mc_result mc_result = MC_DRV_OK; - MCDRV_DBG_VERBOSE("===%s()===", __func__); - - /* Enter critical section */ + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { if (session == NULL) { - MCDRV_DBG_ERROR("Session is null"); + MCDRV_DBG_ERROR(mc_kapi, "Session is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } - struct mcore_device_t *device = + struct mcore_device_t *device = resolve_device_id(session->device_id); if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } - struct connection *dev_con = device->connection; + struct connection *dev_con = device->connection; + + struct session *nq_session = + mcore_device_resolve_session_id(device, + session->session_id); - struct session *nq_session = - mcore_device_resolve_session_id(device, session->session_id); if (nq_session == NULL) { - MCDRV_DBG_ERROR("Session not found"); + MCDRV_DBG_ERROR(mc_kapi, "Session not found"); mc_result = MC_DRV_ERR_UNKNOWN_SESSION; break; } /* Write close session command */ struct mc_drv_cmd_close_session_t cmd_close_session = { - /* C++ does not support C99 designated initializers */ - /* .header = */ { - /* .command_id = */ MC_DRV_CMD_CLOSE_SESSION + { + MC_DRV_CMD_CLOSE_SESSION }, - /* .payload = */ { - /* .session_id = */ session->session_id, + { + session->session_id, } }; - connection_write_data( - dev_con, - &cmd_close_session, - sizeof(cmd_close_session)); + connection_write_data(dev_con, + &cmd_close_session, + sizeof(cmd_close_session)); /* Read command response */ struct mc_drv_response_header_t rsp_header; - int len = connection_read_datablock( - dev_con, - &rsp_header, - sizeof(rsp_header)); + int len = connection_read_datablock(dev_con, + &rsp_header, + sizeof(rsp_header)); if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR("CMD_CLOSE_SESSION readRsp failed " - "ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_CLOSE_SESSION readRsp failed %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR("CMD_CLOSE_SESSION failed, respId=%d", - rsp_header.response_id); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_CLOSE_SESSION failed, respId=%d", + rsp_header.response_id); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } @@ -525,23 +501,19 @@ enum mc_result mc_close_session( } while (false); - /* Exit critical section */ - return mc_result; } EXPORT_SYMBOL(mc_close_session); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_notify( - struct mc_session_handle *session -) { +enum mc_result mc_notify(struct mc_session_handle *session) +{ enum mc_result mc_result = MC_DRV_OK; - MCDRV_DBG_VERBOSE("===%s()===", __func__); + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { if (session == NULL) { - MCDRV_DBG_ERROR("Session is null"); + MCDRV_DBG_ERROR(mc_kapi, "Session is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } @@ -549,7 +521,7 @@ enum mc_result mc_notify( struct mcore_device_t *device = resolve_device_id(session->device_id); if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } @@ -558,25 +530,23 @@ enum mc_result mc_notify( struct session *nqsession = mcore_device_resolve_session_id(device, session->session_id); if (nqsession == NULL) { - MCDRV_DBG_ERROR("Session not found"); + MCDRV_DBG_ERROR(mc_kapi, "Session not found"); mc_result = MC_DRV_ERR_UNKNOWN_SESSION; break; } struct mc_drv_cmd_notify_t cmd_notify = { - /* C++ does not support C99 designated initializers */ - /* .header = */ { - /* .command_id = */ MC_DRV_CMD_NOTIFY + { + MC_DRV_CMD_NOTIFY }, - /* .payload = */ { - /* .session_id = */ session->session_id, + { + session->session_id } }; - connection_write_data( - dev_con, - &cmd_notify, - sizeof(cmd_notify)); + connection_write_data(dev_con, + &cmd_notify, + sizeof(cmd_notify)); /* Daemon will not return a response */ @@ -586,14 +556,12 @@ enum mc_result mc_notify( } EXPORT_SYMBOL(mc_notify); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_wait_notification( - struct mc_session_handle *session, - int32_t timeout -) { +enum mc_result mc_wait_notification(struct mc_session_handle *session, + int32_t timeout) +{ enum mc_result mc_result = MC_DRV_OK; - MCDRV_DBG_VERBOSE("===%s()===", __func__); + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { if (session == NULL) { @@ -601,18 +569,19 @@ enum mc_result mc_wait_notification( break; } - struct mcore_device_t *device = + struct mcore_device_t *device = resolve_device_id(session->device_id); if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } - struct session *nq_session = - mcore_device_resolve_session_id(device, session->session_id); + struct session *nq_session = + mcore_device_resolve_session_id(device, + session->session_id); if (nq_session == NULL) { - MCDRV_DBG_ERROR("Session not found"); + MCDRV_DBG_ERROR(mc_kapi, "Session not found"); mc_result = MC_DRV_ERR_UNKNOWN_SESSION; break; } @@ -624,22 +593,26 @@ enum mc_result mc_wait_notification( /* Read notification queue till it's empty */ for (;;) { struct notification notification; - ssize_t num_read = connection_read_data( - nqconnection, - ¬ification, - sizeof(notification), - timeout); - /* Exit on timeout in first run. Later runs have + ssize_t num_read = + connection_read_data(nqconnection, + ¬ification, + sizeof(notification), + timeout); + /* + * Exit on timeout in first run. Later runs have * timeout set to 0. - * -2 means, there is no more data. */ + * -2 means, there is no more data. + */ if (count == 0 && num_read == -2) { - MCDRV_DBG_ERROR("read timeout"); + MCDRV_DBG_ERROR(mc_kapi, "read timeout"); mc_result = MC_DRV_ERR_TIMEOUT; break; } - /* After first notification the queue will be + /* + * After first notification the queue will be * drained, Thus we set no timeout for the - * following reads */ + * following reads + */ timeout = 0; if (num_read != sizeof(struct notification)) { @@ -647,28 +620,33 @@ enum mc_result mc_wait_notification( /* failure in first read, notify it */ mc_result = MC_DRV_ERR_NOTIFICATION; MCDRV_DBG_ERROR( + mc_kapi, "read notification failed, " "%i bytes received", (int)num_read); break; } else { - /* Read of the n-th notification - failed/timeout. We don't tell the - caller, as we got valid notifications - before. */ + /* + * Read of the n-th notification + * failed/timeout. We don't tell the + * caller, as we got valid notifications + * before. + */ mc_result = MC_DRV_OK; break; } } count++; - MCDRV_DBG_VERBOSE("readNq count=%d, SessionID=%d, " - "Payload=%d", count, - notification.session_id, notification.payload); + MCDRV_DBG_VERBOSE(mc_kapi, + "count=%d, SessionID=%d, Payload=%d", + count, + notification.session_id, + notification.payload); if (notification.payload != 0) { /* Session end point died -> store exit code */ session_set_error_info(nq_session, - notification.payload); + notification.payload); mc_result = MC_DRV_INFO_NOTIFICATION; break; @@ -681,24 +659,17 @@ enum mc_result mc_wait_notification( } EXPORT_SYMBOL(mc_wait_notification); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_malloc_wsm( - uint32_t device_id, - uint32_t align, - uint32_t len, - uint8_t **wsm, - uint32_t wsm_flags -) { +enum mc_result mc_malloc_wsm(uint32_t device_id, uint32_t align, uint32_t len, + uint8_t **wsm, uint32_t wsm_flags) +{ enum mc_result mc_result = MC_DRV_ERR_UNKNOWN; - MCDRV_DBG_VERBOSE("===%s()===", __func__); - - /* Enter critical section */ + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { struct mcore_device_t *device = resolve_device_id(device_id); if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } @@ -710,7 +681,7 @@ enum mc_result mc_malloc_wsm( struct wsm *wsm_stack = mcore_device_allocate_contiguous_wsm(device, len); if (wsm_stack == NULL) { - MCDRV_DBG_ERROR("Allocation of WSM failed"); + MCDRV_DBG_ERROR(mc_kapi, "Allocation of WSM failed"); mc_result = MC_DRV_ERR_NO_FREE_MEMORY; break; } @@ -720,31 +691,24 @@ enum mc_result mc_malloc_wsm( } while (false); - /* Exit critical section */ - return mc_result; } EXPORT_SYMBOL(mc_malloc_wsm); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_free_wsm( - uint32_t device_id, - uint8_t *wsm -) { +enum mc_result mc_free_wsm(uint32_t device_id, uint8_t *wsm) +{ enum mc_result mc_result = MC_DRV_ERR_UNKNOWN; struct mcore_device_t *device; - MCDRV_DBG_VERBOSE("===%s()===", __func__); - - /* Enter critical section */ + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { /* Get the device associated wit the given session */ device = resolve_device_id(device_id); if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } @@ -753,14 +717,15 @@ enum mc_result mc_free_wsm( struct wsm *wsm_stack = mcore_device_find_contiguous_wsm(device, wsm); if (wsm_stack == NULL) { - MCDRV_DBG_ERROR("unknown address"); + MCDRV_DBG_ERROR(mc_kapi, "unknown address"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } /* Free the given virtual address */ if (!mcore_device_free_contiguous_wsm(device, wsm_stack)) { - MCDRV_DBG_ERROR("Free of virtual address failed"); + MCDRV_DBG_ERROR(mc_kapi, + "Free of virtual address failed"); mc_result = MC_DRV_ERR_FREE_MEMORY_FAILED; break; } @@ -768,130 +733,123 @@ enum mc_result mc_free_wsm( } while (false); - /* Exit critical section */ - return mc_result; } EXPORT_SYMBOL(mc_free_wsm); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_map( - struct mc_session_handle *session_handle, - void *buf, - uint32_t buf_len, - struct mc_bulk_map *map_info -) { +enum mc_result mc_map(struct mc_session_handle *session_handle, void *buf, + uint32_t buf_len, struct mc_bulk_map *map_info) +{ enum mc_result mc_result = MC_DRV_ERR_UNKNOWN; - MCDRV_DBG_VERBOSE("===%s()===", __func__); - - /* Enter critical section */ + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { if (session_handle == NULL) { - MCDRV_DBG_ERROR("session_handle is null"); + MCDRV_DBG_ERROR(mc_kapi, "session_handle is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } if (map_info == NULL) { - MCDRV_DBG_ERROR("map_info is null"); + MCDRV_DBG_ERROR(mc_kapi, "map_info is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } if (buf == NULL) { - MCDRV_DBG_ERROR("buf is null"); + MCDRV_DBG_ERROR(mc_kapi, "buf is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } /* Determine device the session belongs to */ - struct mcore_device_t *device = resolve_device_id( - session_handle->device_id); + struct mcore_device_t *device = + resolve_device_id(session_handle->device_id); + if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } struct connection *dev_con = device->connection; /* Get session */ - struct session *session = - mcore_device_resolve_session_id(device, - session_handle->session_id); + uint32_t session_id = session_handle->session_id; + struct session *session = + mcore_device_resolve_session_id(device, + session_id); if (session == NULL) { - MCDRV_DBG_ERROR("Session not found"); + MCDRV_DBG_ERROR(mc_kapi, "Session not found"); mc_result = MC_DRV_ERR_UNKNOWN_SESSION; break; } - /* Register mapped bulk buffer to Kernel Module and keep mapped - bulk buffer in mind */ - struct bulk_buffer_descriptor *bulk_buf = session_add_bulk_buf( - session, buf, buf_len); + /* + * Register mapped bulk buffer to Kernel Module and keep mapped + * bulk buffer in mind + */ + struct bulk_buffer_descriptor *bulk_buf = + session_add_bulk_buf(session, buf, buf_len); if (bulk_buf == NULL) { - MCDRV_DBG_ERROR("Error mapping bulk buffer"); + MCDRV_DBG_ERROR(mc_kapi, "Error mapping bulk buffer"); mc_result = MC_DRV_ERR_BULK_MAPPING; break; } /* Prepare map command */ struct mc_drv_cmd_map_bulk_mem_t mc_drv_cmd_map_bulk_mem = { - /* C++ does not support C99 designated initializers */ - /* .header = */ { - /* .command_id = */ MC_DRV_CMD_MAP_BULK_BUF + { + MC_DRV_CMD_MAP_BULK_BUF }, - /* .payload = */ { - /* .session_id = */ session->session_id, - /* .phys_addr_l2; = */ - (uint32_t)bulk_buf->phys_addr_wsm_l2, - /* .offset_payload = */ - (uint32_t)(bulk_buf->virt_addr) & 0xFFF, - /* .len_bulk_mem = */ bulk_buf->len + { + session->session_id, + (uint32_t)bulk_buf->phys_addr_wsm_l2, + (uint32_t)(bulk_buf->virt_addr) & 0xFFF, + bulk_buf->len } }; /* Transmit map command to MobiCore device */ - connection_write_data( - dev_con, - &mc_drv_cmd_map_bulk_mem, - sizeof(mc_drv_cmd_map_bulk_mem)); + connection_write_data(dev_con, + &mc_drv_cmd_map_bulk_mem, + sizeof(mc_drv_cmd_map_bulk_mem)); /* Read command response */ struct mc_drv_response_header_t rsp_header; - int len = connection_read_datablock( - dev_con, - &rsp_header, - sizeof(rsp_header)); + int len = connection_read_datablock(dev_con, + &rsp_header, + sizeof(rsp_header)); if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF readRsp failed, " - "ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_MAP_BULK_BUF readRsp failed %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF failed, respId=%d", - rsp_header.response_id); - /* REV We ignore Daemon Error code because client cannot - handle it anyhow. */ + MCDRV_DBG_ERROR(mc_kapi, + "CMD_MAP_BULK_BUF failed, respId=%d", + rsp_header.response_id); + mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - /* Unregister mapped bulk buffer from Kernel Module and - remove mapped bulk buffer from session maintenance */ + /* + * Unregister mapped bulk buffer from Kernel Module and + * remove mapped bulk buffer from session maintenance + */ if (!session_remove_bulk_buf(session, buf)) { /* Removing of bulk buffer not possible */ - MCDRV_DBG_ERROR("Unregistering of bulk memory" - "from Kernel Module failed"); + MCDRV_DBG_ERROR(mc_kapi, + "Unreg of bulk memory failed"); } break; } struct mc_drv_rsp_map_bulk_mem_payload_t rsp_map_bulk_mem_payload; - connection_read_datablock( - dev_con, - &rsp_map_bulk_mem_payload, - sizeof(rsp_map_bulk_mem_payload)); + connection_read_datablock(dev_con, + &rsp_map_bulk_mem_payload, + sizeof(rsp_map_bulk_mem_payload)); /* Set mapping info for Trustlet */ map_info->secure_virt_addr = @@ -901,37 +859,30 @@ enum mc_result mc_map( } while (false); - /* Exit critical section */ - return mc_result; } EXPORT_SYMBOL(mc_map); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_unmap( - struct mc_session_handle *session_handle, - void *buf, - struct mc_bulk_map *map_info -) { +enum mc_result mc_unmap(struct mc_session_handle *session_handle, void *buf, + struct mc_bulk_map *map_info) +{ enum mc_result mc_result = MC_DRV_ERR_UNKNOWN; - MCDRV_DBG_VERBOSE("===%s()===", __func__); - - /* Enter critical section */ + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { if (session_handle == NULL) { - MCDRV_DBG_ERROR("session_handle is null"); + MCDRV_DBG_ERROR(mc_kapi, "session_handle is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } if (map_info == NULL) { - MCDRV_DBG_ERROR("map_info is null"); + MCDRV_DBG_ERROR(mc_kapi, "map_info is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } if (buf == NULL) { - MCDRV_DBG_ERROR("buf is null"); + MCDRV_DBG_ERROR(mc_kapi, "buf is null"); mc_result = MC_DRV_ERR_INVALID_PARAMETER; break; } @@ -940,79 +891,74 @@ enum mc_result mc_unmap( struct mcore_device_t *device = resolve_device_id(session_handle->device_id); if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } - struct connection *dev_con = device->connection; + struct connection *dev_con = device->connection; /* Get session */ + uint32_t session_id = session_handle->session_id; struct session *session = mcore_device_resolve_session_id(device, - session_handle->session_id); + session_id); if (session == NULL) { - MCDRV_DBG_ERROR("Session not found"); + MCDRV_DBG_ERROR(mc_kapi, "Session not found"); mc_result = MC_DRV_ERR_UNKNOWN_SESSION; break; } /* Prepare unmap command */ struct mc_drv_cmd_unmap_bulk_mem_t cmd_unmap_bulk_mem = { - /* .header = */ { - /* .command_id = */ - MC_DRV_CMD_UNMAP_BULK_BUF + { + MC_DRV_CMD_UNMAP_BULK_BUF }, - /* .payload = */ { - /* .session_id = */ session->session_id, - /* .secure_virtual_adr = */ - (uint32_t)(map_info->secure_virt_addr), - /* .len_bulk_mem = - map_info->secure_virt_len*/ + { + session->session_id, + (uint32_t)(map_info->secure_virt_addr) } }; - connection_write_data( - dev_con, - &cmd_unmap_bulk_mem, - sizeof(cmd_unmap_bulk_mem)); + connection_write_data(dev_con, + &cmd_unmap_bulk_mem, + sizeof(cmd_unmap_bulk_mem)); /* Read command response */ struct mc_drv_response_header_t rsp_header; - int len = connection_read_datablock( - dev_con, - &rsp_header, - sizeof(rsp_header)); + int len = connection_read_datablock(dev_con, + &rsp_header, + sizeof(rsp_header)); if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF readRsp failed, " - "ret=%d", len); + MCDRV_DBG_ERROR(mc_kapi, + "CMD_UNMAP_BULK_BUF readRsp failed %d", + len); mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF failed, respId=%d", - rsp_header.response_id); - /* REV We ignore Daemon Error code because client - cannot handle it anyhow. */ + MCDRV_DBG_ERROR(mc_kapi, + "CMD_UNMAP_BULK_BUF failed, respId=%d", + rsp_header.response_id); + mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; break; } struct mc_drv_rsp_unmap_bulk_mem_payload_t rsp_unmap_bulk_mem_payload; - connection_read_datablock( - dev_con, - &rsp_unmap_bulk_mem_payload, - sizeof(rsp_unmap_bulk_mem_payload)); - - /* REV axh: what about check the payload? */ - - /* Unregister mapped bulk buffer from Kernel Module and - * remove mapped bulk buffer from session maintenance */ + connection_read_datablock(dev_con, + &rsp_unmap_bulk_mem_payload, + sizeof(rsp_unmap_bulk_mem_payload)); + + /* + * Unregister mapped bulk buffer from Kernel Module and + * remove mapped bulk buffer from session maintenance + */ if (!session_remove_bulk_buf(session, buf)) { /* Removing of bulk buffer not possible */ - MCDRV_DBG_ERROR("Unregistering of bulk memory from " - "Kernel Module failed"); + MCDRV_DBG_ERROR(mc_kapi, + "Unregistering of bulk memory failed"); mc_result = MC_DRV_ERR_BULK_UNMAPPING; break; } @@ -1021,20 +967,16 @@ enum mc_result mc_unmap( } while (false); - /* Exit critical section */ - return mc_result; } EXPORT_SYMBOL(mc_unmap); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_get_session_error_code( - struct mc_session_handle *session, - int32_t *last_error -) { +enum mc_result mc_get_session_error_code(struct mc_session_handle *session, + int32_t *last_error) +{ enum mc_result mc_result = MC_DRV_OK; - MCDRV_DBG_VERBOSE("===%s()===", __func__); + MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); do { if (session == NULL || last_error == NULL) { @@ -1044,23 +986,24 @@ enum mc_result mc_get_session_error_code( /* Get device */ struct mcore_device_t *device = - resolve_device_id(session->device_id); + resolve_device_id(session->device_id); if (device == NULL) { - MCDRV_DBG_ERROR("Device not found"); + MCDRV_DBG_ERROR(mc_kapi, "Device not found"); mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; break; } /* Get session */ + uint32_t session_id = session->session_id; struct session *nqsession = - mcore_device_resolve_session_id(device, session->session_id); + mcore_device_resolve_session_id(device, + session_id); if (nqsession == NULL) { - MCDRV_DBG_ERROR("Session not found"); + MCDRV_DBG_ERROR(mc_kapi, "Session not found"); mc_result = MC_DRV_ERR_UNKNOWN_SESSION; break; } - /* get session error code from session */ *last_error = session_get_last_err(nqsession); } while (false); @@ -1069,24 +1012,17 @@ enum mc_result mc_get_session_error_code( } EXPORT_SYMBOL(mc_get_session_error_code); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_driver_ctrl( - enum mc_driver_ctrl param, - uint8_t *data, - uint32_t len -) { - MCDRV_DBG_WARN("not implemented"); +enum mc_result mc_driver_ctrl(enum mc_driver_ctrl param, uint8_t *data, + uint32_t len) +{ + MCDRV_DBG_WARN(mc_kapi, "not implemented"); return MC_DRV_ERR_NOT_IMPLEMENTED; } EXPORT_SYMBOL(mc_driver_ctrl); -/*----------------------------------------------------------------------------*/ -enum mc_result mc_manage( - uint32_t device_id, - uint8_t *data, - uint32_t len -) { - MCDRV_DBG_WARN("not implemented"); +enum mc_result mc_manage(uint32_t device_id, uint8_t *data, uint32_t len) +{ + MCDRV_DBG_WARN(mc_kapi, "not implemented"); return MC_DRV_ERR_NOT_IMPLEMENTED; } EXPORT_SYMBOL(mc_manage); diff --git a/drivers/gud/mobicore_kernelapi/common.h b/drivers/gud/mobicore_kernelapi/common.h index 2a734748704..8e7452012bf 100644 --- a/drivers/gud/mobicore_kernelapi/common.h +++ b/drivers/gud/mobicore_kernelapi/common.h @@ -1,97 +1,71 @@ -/** +/* + * Common data types for use by the MobiCore Kernel API Driver * - * Common data types - * - * + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef COMMON_H -#define COMMON_H +#ifndef _MC_KAPI_COMMON_H +#define _MC_KAPI_COMMON_H #include "connection.h" #include "mcinq.h" -void mcapi_insert_connection( - struct connection *connection -); - -void mcapi_remove_connection( - uint32_t seq -); - -unsigned int mcapi_unique_id( - void -); +void mcapi_insert_connection(struct connection *connection); +void mcapi_remove_connection(uint32_t seq); +unsigned int mcapi_unique_id(void); +#define MC_DAEMON_PID 0xFFFFFFFF +#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/mobicore" -#define MC_DAEMON_PID 0xFFFFFFFF -#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/mobicore" +/* dummy function helper macro */ +#define DUMMY_FUNCTION() do {} while (0) -/* dummy function helper macro. */ -#define DUMMY_FUNCTION() do {} while (0) +/* Found in main.c */ +extern struct device *mc_kapi; -#define MCDRV_ERROR(txt, ...) \ - printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \ - __func__, \ - ##__VA_ARGS__) +#define MCDRV_ERROR(dev, txt, ...) \ + dev_err(dev, "%s() ### ERROR: " txt, __func__, ##__VA_ARGS__) #if defined(DEBUG) - -/* #define DEBUG_VERBOSE */ #if defined(DEBUG_VERBOSE) -#define MCDRV_DBG_VERBOSE MCDRV_DBG +#define MCDRV_DBG_VERBOSE MCDRV_DBG #else -#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() +#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() #endif -#define MCDRV_DBG(txt, ...) \ - printk(KERN_INFO "mcKernelApi %s(): " txt, \ - __func__, \ - ##__VA_ARGS__) - -#define MCDRV_DBG_WARN(txt, ...) \ - printk(KERN_WARNING "mcKernelApi %s() WARNING: " txt, \ - __func__, \ - ##__VA_ARGS__) +#define MCDRV_DBG(dev, txt, ...) \ + dev_info(dev, "%s(): " txt, __func__, ##__VA_ARGS__) -#define MCDRV_DBG_ERROR(txt, ...) \ - printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \ - __func__, \ - ##__VA_ARGS__) +#define MCDRV_DBG_WARN(dev, txt, ...) \ + dev_warn(dev, "%s() WARNING: " txt, __func__, ##__VA_ARGS__) +#define MCDRV_DBG_ERROR(dev, txt, ...) \ + dev_err(dev, "%s() ### ERROR: " txt, __func__, ##__VA_ARGS__) #define MCDRV_ASSERT(cond) \ do { \ if (unlikely(!(cond))) { \ - panic("mcKernelApi Assertion failed: %s:%d\n", \ - __FILE__, __LINE__); \ + panic("mc_kernelapi Assertion failed: %s:%d\n", \ + __FILE__, __LINE__); \ } \ } while (0) #elif defined(NDEBUG) -#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() -#define MCDRV_DBG(...) DUMMY_FUNCTION() -#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION() -#define MCDRV_DBG_ERROR(...) DUMMY_FUNCTION() +#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() +#define MCDRV_DBG(...) DUMMY_FUNCTION() +#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION() +#define MCDRV_DBG_ERROR(...) DUMMY_FUNCTION() -#define MCDRV_ASSERT(...) DUMMY_FUNCTION() +#define MCDRV_ASSERT(...) DUMMY_FUNCTION() #else #error "Define DEBUG or NDEBUG" #endif /* [not] defined(DEBUG_MCMODULE) */ +#define assert(expr) MCDRV_ASSERT(expr) -#define LOG_I MCDRV_DBG_VERBOSE -#define LOG_W MCDRV_DBG_WARN -#define LOG_E MCDRV_DBG_ERROR - - -#define assert(expr) MCDRV_ASSERT(expr) - -#endif /* COMMON_H */ - -/** @} */ +#endif /* _MC_KAPI_COMMON_H */ diff --git a/drivers/gud/mobicore_kernelapi/connection.c b/drivers/gud/mobicore_kernelapi/connection.c index 9048ae87a5a..50473492d62 100644 --- a/drivers/gud/mobicore_kernelapi/connection.c +++ b/drivers/gud/mobicore_kernelapi/connection.c @@ -1,10 +1,7 @@ -/** @addtogroup MCD_MCDIMPL_DAEMON_SRV - * @{ - * @file - * +/* * Connection data. * - * + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,37 +23,29 @@ /* Define the initial state of the Data Available Semaphore */ #define SEM_NO_DATA_AVAILABLE 0 -/*----------------------------------------------------------------------------*/ -struct connection *connection_new( - void -) { - struct connection *conn = kzalloc(sizeof(struct connection), - GFP_KERNEL); +struct connection *connection_new(void) +{ + struct connection *conn; + + conn = kzalloc(sizeof(*conn), GFP_KERNEL); conn->sequence_magic = mcapi_unique_id(); mutex_init(&conn->data_lock); - /* No data available */ sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE); mcapi_insert_connection(conn); return conn; } -/*----------------------------------------------------------------------------*/ -struct connection *connection_create( - int socket_descriptor, - pid_t dest -) { +struct connection *connection_create(int socket_descriptor, pid_t dest) +{ struct connection *conn = connection_new(); conn->peer_pid = dest; return conn; } - -/*----------------------------------------------------------------------------*/ -void connection_cleanup( - struct connection *conn -) { +void connection_cleanup(struct connection *conn) +{ if (!conn) return; @@ -66,26 +55,20 @@ void connection_cleanup( kfree(conn); } - -/*----------------------------------------------------------------------------*/ -bool connection_connect( - struct connection *conn, - pid_t dest -) { +bool connection_connect(struct connection *conn, pid_t dest) +{ /* Nothing to connect */ conn->peer_pid = dest; return true; } -/*----------------------------------------------------------------------------*/ -size_t connection_readDataMsg( - struct connection *conn, - void *buffer, - uint32_t len -) { +size_t connection_read_data_msg(struct connection *conn, void *buffer, + uint32_t len) +{ size_t ret = -1; - MCDRV_DBG_VERBOSE("reading connection data %u, connection data left %u", - len, conn->data_len); + MCDRV_DBG_VERBOSE(mc_kapi, + "reading connection data %u, connection data left %u", + len, conn->data_len); /* trying to read more than the left data */ if (len > conn->data_len) { ret = conn->data_len; @@ -98,80 +81,75 @@ size_t connection_readDataMsg( conn->data_start += len; } - if (conn->data_len == 0) { + if (conn->data_len == 0) { conn->data_start = NULL; kfree_skb(conn->skb); conn->skb = NULL; } - MCDRV_DBG_VERBOSE("read %u", ret); + MCDRV_DBG_VERBOSE(mc_kapi, "read %u", ret); return ret; } -/*----------------------------------------------------------------------------*/ -size_t connection_read_datablock( - struct connection *conn, - void *buffer, - uint32_t len -) { +size_t connection_read_datablock(struct connection *conn, void *buffer, + uint32_t len) +{ return connection_read_data(conn, buffer, len, -1); } - -/*----------------------------------------------------------------------------*/ -size_t connection_read_data( - struct connection *conn, - void *buffer, - uint32_t len, - int32_t timeout -) { +size_t connection_read_data(struct connection *conn, void *buffer, uint32_t len, + int32_t timeout) +{ size_t ret = 0; MCDRV_ASSERT(buffer != NULL); MCDRV_ASSERT(conn->socket_descriptor != NULL); - MCDRV_DBG_VERBOSE("read data len = %u for PID = %u", - len, conn->sequence_magic); + MCDRV_DBG_VERBOSE(mc_kapi, "read data len = %u for PID = %u", + len, conn->sequence_magic); do { - /* Wait until data is available or timeout - msecs_to_jiffies(-1) -> wait forever for the sem */ + /* + * Wait until data is available or timeout + * msecs_to_jiffies(-1) -> wait forever for the sem + */ if (down_timeout(&(conn->data_available_sem), - msecs_to_jiffies(timeout))) { - MCDRV_DBG_VERBOSE("Timeout reading the data sem"); + msecs_to_jiffies(timeout))) { + MCDRV_DBG_VERBOSE(mc_kapi, + "Timeout reading the data sem"); ret = -2; break; } if (mutex_lock_interruptible(&(conn->data_lock))) { - MCDRV_DBG_ERROR("interrupted reading the data sem"); + MCDRV_DBG_ERROR(mc_kapi, + "interrupted reading the data sem"); ret = -1; break; } + /* Have data, use it */ if (conn->data_len > 0) - ret = connection_readDataMsg(conn, buffer, len); + ret = connection_read_data_msg(conn, buffer, len); - mutex_unlock(&(conn->data_lock)); + mutex_unlock(&(conn->data_lock)); /* There is still some data left */ if (conn->data_len > 0) up(&conn->data_available_sem); + } while (0); return ret; } -/*----------------------------------------------------------------------------*/ -size_t connection_write_data( - struct connection *conn, - void *buffer, - uint32_t len -) { +size_t connection_write_data(struct connection *conn, void *buffer, + uint32_t len) +{ struct sk_buff *skb = NULL; struct nlmsghdr *nlh; int ret = 0; - MCDRV_DBG_VERBOSE("buffer length %u from pid %u\n", - len, conn->sequence_magic); + MCDRV_DBG_VERBOSE(mc_kapi, "buffer length %u from pid %u\n", + len, conn->sequence_magic); do { skb = nlmsg_new(NLMSG_SPACE(len), GFP_KERNEL); if (!skb) { @@ -180,7 +158,7 @@ size_t connection_write_data( } nlh = nlmsg_put(skb, 0, conn->sequence_magic, 2, - NLMSG_LENGTH(len), NLM_F_REQUEST); + NLMSG_LENGTH(len), NLM_F_REQUEST); if (!nlh) { ret = -1; break; @@ -188,7 +166,7 @@ size_t connection_write_data( memcpy(NLMSG_DATA(nlh), buffer, len); netlink_unicast(conn->socket_descriptor, skb, - conn->peer_pid, MSG_DONTWAIT); + conn->peer_pid, MSG_DONTWAIT); ret = len; } while (0); @@ -198,15 +176,13 @@ size_t connection_write_data( return ret; } -int connection_process( - struct connection *conn, - struct sk_buff *skb -) +int connection_process(struct connection *conn, struct sk_buff *skb) { int ret = 0; do { if (mutex_lock_interruptible(&(conn->data_lock))) { - MCDRV_DBG_ERROR("Interrupted getting data semaphore!"); + MCDRV_DBG_ERROR(mc_kapi, + "Interrupted getting data semaphore!"); ret = -1; break; } @@ -226,4 +202,3 @@ int connection_process( } while (0); return ret; } -/** @} */ diff --git a/drivers/gud/mobicore_kernelapi/connection.h b/drivers/gud/mobicore_kernelapi/connection.h index 0b468e6c7b4..da99828337c 100644 --- a/drivers/gud/mobicore_kernelapi/connection.h +++ b/drivers/gud/mobicore_kernelapi/connection.h @@ -1,122 +1,57 @@ -/** @addtogroup MCD_MCDIMPL_DAEMON_SRV - * @{ - * @file - * +/* * Connection data. * - * + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef CONNECTION_H_ -#define CONNECTION_H_ +#ifndef _MC_KAPI_CONNECTION_H_ +#define _MC_KAPI_CONNECTION_H_ #include #include #include -#define MAX_PAYLOAD_SIZE 128 - struct connection { - struct sock *socket_descriptor; /**< Netlink socket */ - uint32_t sequence_magic; /**< Random? magic to match requests/answers */ - - struct nlmsghdr *data_msg; - uint32_t data_len; /**< How much connection data is left */ - void *data_start; /**< Start pointer of remaining data */ - struct sk_buff *skb; - - struct mutex data_lock; /**< Data protection lock */ - struct semaphore data_available_sem; /**< Data protection semaphore */ - - pid_t self_pid; /**< PID address used for local connection */ - pid_t peer_pid; /**< Remote PID for connection */ - - struct list_head list; /**< The list param for using the kernel lists*/ + /* Netlink socket */ + struct sock *socket_descriptor; + /* Random? magic to match requests/answers */ + uint32_t sequence_magic; + + struct nlmsghdr *data_msg; + /* How much connection data is left */ + uint32_t data_len; + /* Start pointer of remaining data */ + void *data_start; + struct sk_buff *skb; + + /* Data protection lock */ + struct mutex data_lock; + /* Data protection semaphore */ + struct semaphore data_available_sem; + + /* PID address used for local connection */ + pid_t self_pid; + /* Remote PID for connection */ + pid_t peer_pid; + + /* The list param for using the kernel lists */ + struct list_head list; }; -struct connection *connection_new( - void -); - -struct connection *connection_create( - int socket_descriptor, - pid_t dest -); - -void connection_cleanup( - struct connection *conn -); - -/** - * Connect to destination. - * - * @param Destination pointer. - * @return true on success. - */ -bool connection_connect( - struct connection *conn, - pid_t dest -); - - -/** - * Read bytes from the connection. - * - * @param buffer Pointer to destination buffer. - * @param len Number of bytes to read. - * @return Number of bytes read. - */ -size_t connection_read_datablock( - struct connection *conn, - void *buffer, - uint32_t len -); -/** - * Read bytes from the connection. - * - * @param buffer Pointer to destination buffer. - * @param len Number of bytes to read. - * @param timeout Timeout in milliseconds - * @return Number of bytes read. - * @return -1 if select() failed (returned -1) - * @return -2 if no data available, i.e. timeout - */ -size_t connection_read_data( - struct connection *conn, - void *buffer, - uint32_t len, - int32_t timeout -); - -/** - * Write bytes to the connection. - * - * @param buffer Pointer to source buffer. - * @param len Number of bytes to read. - * @return Number of bytes written. - */ -size_t connection_write_data( - struct connection *conn, - void *buffer, - uint32_t len -); - -/** - * Write bytes to the connection. - * - * @param buffer Pointer to source buffer. - * @param len Number of bytes to read. - * @return Number of bytes written. - */ -int connection_process( - struct connection *conn, - struct sk_buff *skb -); - -#endif /* CONNECTION_H_ */ - -/** @} */ +struct connection *connection_new(void); +struct connection *connection_create(int socket_descriptor, pid_t dest); +void connection_cleanup(struct connection *conn); +bool connection_connect(struct connection *conn, pid_t dest); +size_t connection_read_datablock(struct connection *conn, void *buffer, + uint32_t len); +size_t connection_read_data(struct connection *conn, void *buffer, + uint32_t len, int32_t timeout); +size_t connection_write_data(struct connection *conn, void *buffer, + uint32_t len); +int connection_process(struct connection *conn, struct sk_buff *skb); + +#endif /* _MC_KAPI_CONNECTION_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/device.c b/drivers/gud/mobicore_kernelapi/device.c index dbeee6a8119..e3eb41e0eae 100644 --- a/drivers/gud/mobicore_kernelapi/device.c +++ b/drivers/gud/mobicore_kernelapi/device.c @@ -1,12 +1,9 @@ -/** @addtogroup MCD_IMPL_LIB - * @{ - * @file - * - * Client library device management. +/* + * MobiCore client library device management. * * Device and Trustlet Session management Funtions. * - * + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -14,21 +11,19 @@ */ #include #include +#include #include "mc_kernel_api.h" #include "public/mobicore_driver_api.h" #include "device.h" #include "common.h" -/*----------------------------------------------------------------------------*/ -struct wsm *wsm_create( - void *virt_addr, - uint32_t len, - uint32_t handle, - void *phys_addr /*= NULL this may be unknown, so is can be omitted.*/ - ) +struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle, + void *phys_addr) { - struct wsm *wsm = kzalloc(sizeof(struct wsm), GFP_KERNEL); + struct wsm *wsm; + + wsm = kzalloc(sizeof(*wsm), GFP_KERNEL); wsm->virt_addr = virt_addr; wsm->len = len; wsm->handle = handle; @@ -36,14 +31,12 @@ struct wsm *wsm_create( return wsm; } +struct mcore_device_t *mcore_device_create(uint32_t device_id, + struct connection *connection) +{ + struct mcore_device_t *dev; -/*----------------------------------------------------------------------------*/ -struct mcore_device_t *mcore_device_create( - uint32_t device_id, - struct connection *connection -) { - struct mcore_device_t *dev = - kzalloc(sizeof(struct mcore_device_t), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); dev->device_id = device_id; dev->connection = connection; @@ -53,17 +46,16 @@ struct mcore_device_t *mcore_device_create( return dev; } - -/*----------------------------------------------------------------------------*/ -void mcore_device_cleanup( - struct mcore_device_t *dev -) { +void mcore_device_cleanup(struct mcore_device_t *dev) +{ struct session *tmp; struct wsm *wsm; struct list_head *pos, *q; - /* Delete all session objects. Usually this should not be needed - * as closeDevice()requires that all sessions have been closed before.*/ + /* + * Delete all session objects. Usually this should not be needed + * as close_device() requires that all sessions have been closed before. + */ list_for_each_safe(pos, q, &dev->session_vector) { tmp = list_entry(pos, struct session, list); list_del(pos); @@ -73,7 +65,6 @@ void mcore_device_cleanup( /* Free all allocated WSM descriptors */ list_for_each_safe(pos, q, &dev->wsm_l2_vector) { wsm = list_entry(pos, struct wsm, list); - /* mcKMod_free(dev->instance, wsm->handle); */ list_del(pos); kfree(wsm); } @@ -83,56 +74,41 @@ void mcore_device_cleanup( kfree(dev); } - -/*----------------------------------------------------------------------------*/ -bool mcore_device_open( - struct mcore_device_t *dev, - const char *deviceName -) { +bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName) +{ dev->instance = mobicore_open(); return (dev->instance != NULL); } - -/*----------------------------------------------------------------------------*/ -void mcore_device_close( - struct mcore_device_t *dev -) { +void mcore_device_close(struct mcore_device_t *dev) +{ mobicore_release(dev->instance); } - -/*----------------------------------------------------------------------------*/ -bool mcore_device_has_sessions( - struct mcore_device_t *dev -) { +bool mcore_device_has_sessions(struct mcore_device_t *dev) +{ return !list_empty(&dev->session_vector); } - -/*----------------------------------------------------------------------------*/ -bool mcore_device_create_new_session( - struct mcore_device_t *dev, - uint32_t session_id, - struct connection *connection -) { +bool mcore_device_create_new_session(struct mcore_device_t *dev, + uint32_t session_id, + struct connection *connection) +{ /* Check if session_id already exists */ if (mcore_device_resolve_session_id(dev, session_id)) { - MCDRV_DBG_ERROR(" session %u already exists", session_id); + MCDRV_DBG_ERROR(mc_kapi, + " session %u already exists", session_id); return false; } - struct session *session = session_create(session_id, dev->instance, - connection); + struct session *session = + session_create(session_id, dev->instance, connection); list_add_tail(&(session->list), &(dev->session_vector)); return true; } - -/*----------------------------------------------------------------------------*/ -bool mcore_device_remove_session( - struct mcore_device_t *dev, - uint32_t session_id -) { +bool mcore_device_remove_session(struct mcore_device_t *dev, + uint32_t session_id) +{ bool ret = false; struct session *tmp; struct list_head *pos, *q; @@ -149,17 +125,13 @@ bool mcore_device_remove_session( return ret; } - -/*----------------------------------------------------------------------------*/ -struct session *mcore_device_resolve_session_id( - struct mcore_device_t *dev, - uint32_t session_id -) { - struct session *ret = NULL; +struct session *mcore_device_resolve_session_id(struct mcore_device_t *dev, + uint32_t session_id) +{ + struct session *ret = NULL; struct session *tmp; struct list_head *pos; - /* Get session for session_id */ list_for_each(pos, &dev->session_vector) { tmp = list_entry(pos, struct session, list); @@ -171,26 +143,20 @@ struct session *mcore_device_resolve_session_id( return ret; } - -/*----------------------------------------------------------------------------*/ -struct wsm *mcore_device_allocate_contiguous_wsm( - struct mcore_device_t *dev, - uint32_t len -) { +struct wsm *mcore_device_allocate_contiguous_wsm(struct mcore_device_t *dev, + uint32_t len) +{ struct wsm *wsm = NULL; do { if (len == 0) break; /* Allocate shared memory */ - void *virt_addr; - uint32_t handle; - void *phys_addr; - int ret = mobicore_allocate_wsm(dev->instance, - len, - &handle, - &virt_addr, - &phys_addr); + void *virt_addr; + uint32_t handle; + void *phys_addr; + int ret = mobicore_allocate_wsm(dev->instance, len, &handle, + &virt_addr, &phys_addr); if (ret != 0) break; @@ -201,16 +167,12 @@ struct wsm *mcore_device_allocate_contiguous_wsm( } while (0); - /* Return pointer to the allocated memory */ return wsm; } - -/*----------------------------------------------------------------------------*/ -bool mcore_device_free_contiguous_wsm( - struct mcore_device_t *dev, - struct wsm *wsm -) { +bool mcore_device_free_contiguous_wsm(struct mcore_device_t *dev, + struct wsm *wsm) +{ bool ret = false; struct wsm *tmp; struct list_head *pos; @@ -224,8 +186,9 @@ bool mcore_device_free_contiguous_wsm( } if (ret) { - MCDRV_DBG_VERBOSE("freeWsm virt_addr=0x%p, handle=%d", - wsm->virt_addr, wsm->handle); + MCDRV_DBG_VERBOSE(mc_kapi, + "freeWsm virt_addr=0x%p, handle=%d", + wsm->virt_addr, wsm->handle); /* ignore return code */ mobicore_free(dev->instance, wsm->handle); @@ -236,12 +199,9 @@ bool mcore_device_free_contiguous_wsm( return ret; } - -/*----------------------------------------------------------------------------*/ -struct wsm *mcore_device_find_contiguous_wsm( - struct mcore_device_t *dev, - void *virt_addr -) { +struct wsm *mcore_device_find_contiguous_wsm(struct mcore_device_t *dev, + void *virt_addr) +{ struct wsm *wsm; struct list_head *pos; @@ -253,5 +213,3 @@ struct wsm *mcore_device_find_contiguous_wsm( return NULL; } - -/** @} */ diff --git a/drivers/gud/mobicore_kernelapi/device.h b/drivers/gud/mobicore_kernelapi/device.h index f40d9936714..8a38b505917 100644 --- a/drivers/gud/mobicore_kernelapi/device.h +++ b/drivers/gud/mobicore_kernelapi/device.h @@ -1,19 +1,16 @@ -/** @addtogroup MCD_IMPL_LIB - * @{ - * @file - * - * Client library device management. +/* + * MobiCore client library device management. * * Device and Trustlet Session management Functions. * - * + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef DEVICE_H_ -#define DEVICE_H_ +#ifndef _MC_KAPI_DEVICE_H_ +#define _MC_KAPI_DEVICE_H_ #include @@ -21,119 +18,37 @@ #include "session.h" #include "wsm.h" - struct mcore_device_t { - struct list_head session_vector; /**< MobiCore Trustlet session - associated with the device */ - struct list_head wsm_l2_vector; /**< WSM L2 Table */ + /* MobiCore Trustlet session associated with the device */ + struct list_head session_vector; + struct list_head wsm_l2_vector; - uint32_t device_id; /**< Device identifier */ - struct connection *connection; /**< The device connection */ - struct mc_instance *instance; /**< MobiCore Driver instance */ + uint32_t device_id; /* Device identifier */ + struct connection *connection; /* The device connection */ + struct mc_instance *instance; /* MobiCore Driver instance */ - struct list_head list; /**< The list param for using the kernel lists*/ + /* The list param for using the kernel lists */ + struct list_head list; }; struct mcore_device_t *mcore_device_create( - uint32_t device_id, - struct connection *connection -); - -void mcore_device_cleanup( - struct mcore_device_t *dev -); - -/** - * Open the device. - * @param deviceName Name of the kernel modules device file. - * @return true if the device has been opened successfully - */ -bool mcore_device_open( - struct mcore_device_t *dev, - const char *deviceName -); - -/** - * Closes the device. - */ -void mcore_device_close( - struct mcore_device_t *dev -); - -/** - * Check if the device has open sessions. - * @return true if the device has one or more open sessions. - */ -bool mcore_device_has_sessions( - struct mcore_device_t *dev -); - -/** - * Add a session to the device. - * @param session_id session ID - * @param connection session connection - */ + uint32_t device_id, struct connection *connection); +void mcore_device_cleanup(struct mcore_device_t *dev); +bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName); +void mcore_device_close(struct mcore_device_t *dev); +bool mcore_device_has_sessions(struct mcore_device_t *dev); bool mcore_device_create_new_session( - struct mcore_device_t *dev, - uint32_t session_id, - struct connection *connection -); - -/** - * Remove the specified session from the device. - * The session object will be destroyed and all resources associated with it - * will be freed. - * - * @param session_id Session of the session to remove. - * @return true if a session has been found and removed. - */ + struct mcore_device_t *dev, uint32_t session_id, + struct connection *connection); bool mcore_device_remove_session( - struct mcore_device_t *dev, - uint32_t session_id -); - -/** - * Get as session object for a given session ID. - * @param session_id Identified of a previously opened session. - * @return Session object if available or NULL if no session has been found. - */ + struct mcore_device_t *dev, uint32_t session_id); struct session *mcore_device_resolve_session_id( - struct mcore_device_t *dev, - uint32_t session_id -); - -/** - * Allocate a block of contiguous WSM. - * @param len The virtual address to be registered. - * @return The virtual address of the allocated memory or NULL if no memory - * is available. - */ + struct mcore_device_t *dev, uint32_t session_id); struct wsm *mcore_device_allocate_contiguous_wsm( - struct mcore_device_t *dev, - uint32_t len -); - -/** - * Unregister a vaddr from a device. - * @param vaddr The virtual address to be registered. - * @param paddr The physical address to be registered. - */ + struct mcore_device_t *dev, uint32_t len); bool mcore_device_free_contiguous_wsm( - struct mcore_device_t *dev, - struct wsm *wsm -); - -/** - * Get a WSM object for a given virtual address. - * @param vaddr The virtual address which has been allocate with mc_malloc_wsm() - * in advance. - * @return the WSM object or NULL if no address has been found. - */ + struct mcore_device_t *dev, struct wsm *wsm); struct wsm *mcore_device_find_contiguous_wsm( - struct mcore_device_t *dev, - void *virt_addr -); - -#endif /* DEVICE_H_ */ + struct mcore_device_t *dev, void *virt_addr); -/** @} */ +#endif /* _MC_KAPI_DEVICE_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/mobicore_kernelapi/include/mcinq.h index 3cb82be8a32..85f037fc639 100644 --- a/drivers/gud/mobicore_kernelapi/include/mcinq.h +++ b/drivers/gud/mobicore_kernelapi/include/mcinq.h @@ -1,7 +1,7 @@ -/** @addtogroup NQ - * @{ +/* * Notifications inform the MobiCore runtime environment that information is * pending in a WSM buffer. + * * The Trustlet Connector (TLC) and the corresponding trustlet also utilize * this buffer to notify each other about new data within the * Trustlet Connector Interface (TCI). @@ -16,10 +16,9 @@ * So if, e.g., the TLC in the normal world wants to notify his trustlet * about new data in the TLC buffer * - * @file * Notification queue declarations. * - * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,81 +44,74 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef NQ_H_ -#define NQ_H_ +#ifndef _MCINQ_H_ +#define _MCINQ_H_ + +/* Minimum and maximum count of elements in the notification queue */ +#define MIN_NQ_ELEM 1 /* Minimum notification queue elements. */ +#define MAX_NQ_ELEM 64 /* Maximum notification queue elements. */ -/** \name NQ Size Defines - * Minimum and maximum count of elements in the notification queue. - * @{ */ -#define MIN_NQ_ELEM 1 /**< Minimum notification queue elements. */ -#define MAX_NQ_ELEM 64 /**< Maximum notification queue elements. */ -/** @} */ +/* Minimum notification length (in bytes). */ +#define MIN_NQ_LEN (MIN_NQ_ELEM * sizeof(notification)) -/** \name NQ Length Defines - * Minimum and maximum notification queue length. - * @{ */ -/**< Minimum notification length (in bytes). */ -#define MIN_NQ_LEN (MIN_NQ_ELEM * sizeof(notification)) -/**< Maximum notification length (in bytes). */ -#define MAX_NQ_LEN (MAX_NQ_ELEM * sizeof(notification)) -/** @} */ +/* Maximum notification length (in bytes). */ +#define MAX_NQ_LEN (MAX_NQ_ELEM * sizeof(notification)) -/** \name Session ID Defines - * Standard Session IDs. - * @{ */ -/**< MCP session ID is used when directly communicating with the MobiCore - * (e.g. for starting and stopping of trustlets). */ -#define SID_MCP 0 -/**< Invalid session id is returned in case of an error. */ -#define SID_INVALID 0xffffffff -/** @} */ +/* + * MCP session ID is used when directly communicating with the MobiCore + * (e.g. for starting and stopping of trustlets). + */ +#define SID_MCP 0 +/* Invalid session id is returned in case of an error. */ +#define SID_INVALID 0xffffffff -/** Notification data structure. */ +/* Notification data structure. */ struct notification { - uint32_t session_id; /**< Session ID. */ - int32_t payload; /**< Additional notification information. */ + uint32_t session_id; /* Session ID. */ + int32_t payload; /* Additional notification info */ }; -/** Notification payload codes. +/* + * Notification payload codes. * 0 indicated a plain simple notification, * a positive value is a termination reason from the task, * a negative value is a termination reason from MobiCore. * Possible negative values are given below. */ enum notification_payload { - /**< task terminated, but exit code is invalid */ - ERR_INVALID_EXIT_CODE = -1, - /**< task terminated due to session end, no exit code available */ - ERR_SESSION_CLOSE = -2, - /**< task terminated due to invalid operation */ - ERR_INVALID_OPERATION = -3, - /**< session ID is unknown */ - ERR_INVALID_SID = -4, - /**< session is not active */ - ERR_SID_NOT_ACTIVE = -5 + /* task terminated, but exit code is invalid */ + ERR_INVALID_EXIT_CODE = -1, + /* task terminated due to session end, no exit code available */ + ERR_SESSION_CLOSE = -2, + /* task terminated due to invalid operation */ + ERR_INVALID_OPERATION = -3, + /* session ID is unknown */ + ERR_INVALID_SID = -4, + /* session is not active */ + ERR_SID_NOT_ACTIVE = -5 }; -/** Declaration of the notification queue header. - * layout as specified in the data structure specification. +/* + * Declaration of the notification queue header. + * Layout as specified in the data structure specification. */ struct notification_queue_header { - uint32_t write_cnt; /**< Write counter. */ - uint32_t read_cnt; /**< Read counter. */ - uint32_t queue_size; /**< Queue size. */ + uint32_t write_cnt; /* Write counter. */ + uint32_t read_cnt; /* Read counter. */ + uint32_t queue_size; /* Queue size. */ }; -/** Queue struct which defines a queue object. +/* + * Queue struct which defines a queue object. * The queue struct is accessed by the queue type of * function. elementCnt must be a power of two and the power needs * to be smaller than power of uint32_t (obviously 32). */ struct notification_queue { - /**< Queue header. */ + /* Queue header. */ struct notification_queue_header hdr; - /**< Notification elements. */ + /* Notification elements. */ struct notification notification[MIN_NQ_ELEM]; } ; -#endif /** NQ_H_ */ - -/** @} */ +#endif /* _MCINQ_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/include/mcuuid.h b/drivers/gud/mobicore_kernelapi/include/mcuuid.h index b72acb8a002..6da9437725c 100644 --- a/drivers/gud/mobicore_kernelapi/include/mcuuid.h +++ b/drivers/gud/mobicore_kernelapi/include/mcuuid.h @@ -1,7 +1,5 @@ -/** - * @addtogroup MC_UUID mcUuid - Universally Unique Identifier. - * - * +/* + * <-- Copyright Giesecke & Devrient GmbH 2011-2012 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,21 +25,19 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * @ingroup MC_DATA_TYPES - * @{ */ -#ifndef MC_UUID_H_ -#define MC_UUID_H_ +#ifndef _MCUUID_H_ +#define _MCUUID_H_ #define UUID_TYPE -/** Universally Unique Identifier (UUID) according to ISO/IEC 11578. */ +/* Universally Unique Identifier (UUID) according to ISO/IEC 11578. */ struct mc_uuid_t { - uint8_t value[16]; /**< Value of the UUID. */ + uint8_t value[16]; /* Value of the UUID. */ }; -/** UUID value used as free marker in service provider containers. */ +/* UUID value used as free marker in service provider containers. */ #define MC_UUID_FREE_DEFINE \ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } @@ -50,7 +46,7 @@ static const struct mc_uuid_t MC_UUID_FREE = { MC_UUID_FREE_DEFINE }; -/** Reserved UUID. */ +/* Reserved UUID. */ #define MC_UUID_RESERVED_DEFINE \ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } @@ -59,7 +55,7 @@ static const struct mc_uuid_t MC_UUID_RESERVED = { MC_UUID_RESERVED_DEFINE }; -/** UUID for system applications. */ +/* UUID for system applications. */ #define MC_UUID_SYSTEM_DEFINE \ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE } @@ -68,7 +64,4 @@ static const struct mc_uuid_t MC_UUID_SYSTEM = { MC_UUID_SYSTEM_DEFINE }; -#endif /* MC_UUID_H_ */ - -/** @} */ - +#endif /* _MCUUID_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/mobicore_kernelapi/main.c index 62997f725e6..53eb66d5880 100644 --- a/drivers/gud/mobicore_kernelapi/main.c +++ b/drivers/gud/mobicore_kernelapi/main.c @@ -1,7 +1,7 @@ -/** +/* * MobiCore KernelApi module * - * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -29,23 +30,27 @@ struct mc_kernelapi_ctx { atomic_t counter; }; -struct mc_kernelapi_ctx *mod_ctx; /* = NULL; */ +struct mc_kernelapi_ctx *mod_ctx; + +/* Define a MobiCore Kernel API device structure for use with dev_debug() etc */ +struct device_driver mc_kernel_api_name = { + .name = "mckernelapi" +}; + +struct device mc_kernel_api_subname = { + .init_name = "", /* Set to 'mcapi' at mcapi_init() time */ + .driver = &mc_kernel_api_name +}; + +struct device *mc_kapi = &mc_kernel_api_subname; -/*----------------------------------------------------------------------------*/ /* get a unique ID */ -unsigned int mcapi_unique_id( - void -) +unsigned int mcapi_unique_id(void) { - return (unsigned int)atomic_inc_return( - &(mod_ctx->counter)); + return (unsigned int)atomic_inc_return(&(mod_ctx->counter)); } - -/*----------------------------------------------------------------------------*/ -static struct connection *mcapi_find_connection( - uint32_t seq -) +static struct connection *mcapi_find_connection(uint32_t seq) { struct connection *tmp; struct list_head *pos; @@ -60,24 +65,21 @@ static struct connection *mcapi_find_connection( return NULL; } -/*----------------------------------------------------------------------------*/ -void mcapi_insert_connection( - struct connection *connection -) +void mcapi_insert_connection(struct connection *connection) { list_add_tail(&(connection->list), &(mod_ctx->peers)); connection->socket_descriptor = mod_ctx->sk; } -void mcapi_remove_connection( - uint32_t seq -) +void mcapi_remove_connection(uint32_t seq) { struct connection *tmp; struct list_head *pos, *q; - /* Delete all session objects. Usually this should not be needed as - closeDevice() requires that all sessions have been closed before.*/ + /* + * Delete all session objects. Usually this should not be needed as + * closeDevice() requires that all sessions have been closed before. + */ list_for_each_safe(pos, q, &mod_ctx->peers) { tmp = list_entry(pos, struct connection, list); if (tmp->sequence_magic == seq) { @@ -87,11 +89,7 @@ void mcapi_remove_connection( } } -/*----------------------------------------------------------------------------*/ -static int mcapi_process( - struct sk_buff *skb, - struct nlmsghdr *nlh -) +static int mcapi_process(struct sk_buff *skb, struct nlmsghdr *nlh) { struct connection *c; int length; @@ -102,13 +100,14 @@ static int mcapi_process( pid = nlh->nlmsg_pid; length = nlh->nlmsg_len; seq = nlh->nlmsg_seq; - MCDRV_DBG_VERBOSE("nlmsg len %d type %d pid 0x%X seq %d\n", - length, nlh->nlmsg_type, pid, seq); + MCDRV_DBG_VERBOSE(mc_kapi, "nlmsg len %d type %d pid 0x%X seq %d\n", + length, nlh->nlmsg_type, pid, seq); do { c = mcapi_find_connection(seq); if (!c) { - MCDRV_ERROR("Invalid incomming connection - seq=%u!", - seq); + MCDRV_ERROR(mc_kapi, + "Invalid incomming connection - seq=%u!", + seq); ret = -1; break; } @@ -121,10 +120,7 @@ static int mcapi_process( return ret; } -/*----------------------------------------------------------------------------*/ -static void mcapi_callback( - struct sk_buff *skb -) +static void mcapi_callback(struct sk_buff *skb) { struct nlmsghdr *nlh = nlmsg_hdr(skb); int len = skb->len; @@ -141,19 +137,20 @@ static void mcapi_callback( } } -/*----------------------------------------------------------------------------*/ static int __init mcapi_init(void) { - printk(KERN_INFO "Mobicore API module initialized!\n"); + dev_set_name(mc_kapi, "mcapi"); + + dev_info(mc_kapi, "Mobicore API module initialized!\n"); mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL); /* start kernel thread */ mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0, - mcapi_callback, NULL, THIS_MODULE); + mcapi_callback, NULL, THIS_MODULE); if (!mod_ctx->sk) { - MCDRV_ERROR("register of recieve handler failed"); + MCDRV_ERROR(mc_kapi, "register of recieve handler failed"); return -EFAULT; } @@ -163,7 +160,7 @@ static int __init mcapi_init(void) static void __exit mcapi_exit(void) { - printk(KERN_INFO "Unloading Mobicore API module.\n"); + dev_info(mc_kapi, "Unloading Mobicore API module.\n"); if (mod_ctx->sk != NULL) { netlink_kernel_release(mod_ctx->sk); diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h index ccfb2e5e9de..112df1da920 100644 --- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h +++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h @@ -1,21 +1,10 @@ -/** - * @defgroup MCD_API MobiCore Driver API - * @addtogroup MCD_API - * @{ - * - * @if DOXYGEN_MCDRV_API - * @mainpage MobiCore Driver API. - * @endif - * +/* * MobiCore Driver API. * * The MobiCore (MC) Driver API provides access functions to the MobiCore * runtime environment and the contained Trustlets. * - * @image html DoxyOverviewDrvApi500x.png - * @image latex DoxyOverviewDrvApi500x.png "MobiCore Overview" width=12cm - * - * + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -41,278 +30,272 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MCDRIVER_H_ -#define MCDRIVER_H_ +#ifndef _MOBICORE_DRIVER_API_H_ +#define _MOBICORE_DRIVER_API_H_ #define __MC_CLIENT_LIB_API #include "mcuuid.h" -/** +/* * Return values of MobiCore driver functions. */ enum mc_result { - /**< Function call succeeded. */ - MC_DRV_OK = 0, - /**< No notification available. */ - MC_DRV_NO_NOTIFICATION = 1, - /**< Error during notification on communication level. */ - MC_DRV_ERR_NOTIFICATION = 2, - /**< Function not implemented. */ - MC_DRV_ERR_NOT_IMPLEMENTED = 3, - /**< No more resources available. */ - MC_DRV_ERR_OUT_OF_RESOURCES = 4, - /**< Driver initialization failed. */ - MC_DRV_ERR_INIT = 5, - /**< Unknown error. */ - MC_DRV_ERR_UNKNOWN = 6, - /**< The specified device is unknown. */ - MC_DRV_ERR_UNKNOWN_DEVICE = 7, - /**< The specified session is unknown.*/ - MC_DRV_ERR_UNKNOWN_SESSION = 8, - /**< The specified operation is not allowed. */ - MC_DRV_ERR_INVALID_OPERATION = 9, - /**< The response header from the MC is invalid. */ - MC_DRV_ERR_INVALID_RESPONSE = 10, - /**< Function call timed out. */ - MC_DRV_ERR_TIMEOUT = 11, - /**< Can not allocate additional memory. */ - MC_DRV_ERR_NO_FREE_MEMORY = 12, - /**< Free memory failed. */ - MC_DRV_ERR_FREE_MEMORY_FAILED = 13, - /**< Still some open sessions pending. */ - MC_DRV_ERR_SESSION_PENDING = 14, - /**< MC daemon not reachable */ - MC_DRV_ERR_DAEMON_UNREACHABLE = 15, - /**< The device file of the kernel module could not be opened. */ - MC_DRV_ERR_INVALID_DEVICE_FILE = 16, - /**< Invalid parameter. */ + /* Function call succeeded. */ + MC_DRV_OK = 0, + /* No notification available. */ + MC_DRV_NO_NOTIFICATION = 1, + /* Error during notification on communication level. */ + MC_DRV_ERR_NOTIFICATION = 2, + /* Function not implemented. */ + MC_DRV_ERR_NOT_IMPLEMENTED = 3, + /* No more resources available. */ + MC_DRV_ERR_OUT_OF_RESOURCES = 4, + /* Driver initialization failed. */ + MC_DRV_ERR_INIT = 5, + /* Unknown error. */ + MC_DRV_ERR_UNKNOWN = 6, + /* The specified device is unknown. */ + MC_DRV_ERR_UNKNOWN_DEVICE = 7, + /* The specified session is unknown.*/ + MC_DRV_ERR_UNKNOWN_SESSION = 8, + /* The specified operation is not allowed. */ + MC_DRV_ERR_INVALID_OPERATION = 9, + /* The response header from the MC is invalid. */ + MC_DRV_ERR_INVALID_RESPONSE = 10, + /* Function call timed out. */ + MC_DRV_ERR_TIMEOUT = 11, + /* Can not allocate additional memory. */ + MC_DRV_ERR_NO_FREE_MEMORY = 12, + /* Free memory failed. */ + MC_DRV_ERR_FREE_MEMORY_FAILED = 13, + /* Still some open sessions pending. */ + MC_DRV_ERR_SESSION_PENDING = 14, + /* MC daemon not reachable */ + MC_DRV_ERR_DAEMON_UNREACHABLE = 15, + /* The device file of the kernel module could not be opened. */ + MC_DRV_ERR_INVALID_DEVICE_FILE = 16, + /* Invalid parameter. */ MC_DRV_ERR_INVALID_PARAMETER = 17, - /**< Unspecified error from Kernel Module*/ - MC_DRV_ERR_KERNEL_MODULE = 18, - /**< Error during mapping of additional bulk memory to session. */ - MC_DRV_ERR_BULK_MAPPING = 19, - /**< Error during unmapping of additional bulk memory to session. */ - MC_DRV_ERR_BULK_UNMAPPING = 20, - /**< Notification received, exit code available. */ - MC_DRV_INFO_NOTIFICATION = 21, - /**< Set up of NWd connection failed. */ - MC_DRV_ERR_NQ_FAILED = 22 + /* Unspecified error from Kernel Module*/ + MC_DRV_ERR_KERNEL_MODULE = 18, + /* Error during mapping of additional bulk memory to session. */ + MC_DRV_ERR_BULK_MAPPING = 19, + /* Error during unmapping of additional bulk memory to session. */ + MC_DRV_ERR_BULK_UNMAPPING = 20, + /* Notification received, exit code available. */ + MC_DRV_INFO_NOTIFICATION = 21, + /* Set up of NWd connection failed. */ + MC_DRV_ERR_NQ_FAILED = 22 }; - -/** +/* * Driver control command. */ enum mc_driver_ctrl { - MC_CTRL_GET_VERSION = 1 /**< Return the driver version */ + /* Return the driver version */ + MC_CTRL_GET_VERSION = 1 }; - -/** Structure of Session Handle, includes the Session ID and the Device ID the +/* + * Structure of Session Handle, includes the Session ID and the Device ID the * Session belongs to. * The session handle will be used for session-based MobiCore communication. * It will be passed to calls which address a communication end point in the * MobiCore environment. */ struct mc_session_handle { - uint32_t session_id; /**< MobiCore session ID */ - uint32_t device_id; /**< Device ID the session belongs to */ + uint32_t session_id; /* MobiCore session ID */ + uint32_t device_id; /* Device ID the session belongs to */ }; -/** Information structure about additional mapped Bulk buffer between the +/* + * Information structure about additional mapped Bulk buffer between the * Trustlet Connector (Nwd) and the Trustlet (Swd). This structure is * initialized from a Trustlet Connector by calling mc_map(). * In order to use the memory within a Trustlet the Trustlet Connector has to * inform the Trustlet with the content of this structure via the TCI. */ struct mc_bulk_map { - /**< The virtual address of the Bulk buffer regarding the address space + /* The virtual address of the Bulk buffer regarding the address space * of the Trustlet, already includes a possible offset! */ void *secure_virt_addr; - uint32_t secure_virt_len; /**< Length of the mapped Bulk buffer */ + uint32_t secure_virt_len; /* Length of the mapped Bulk buffer */ }; - -/**< The default device ID */ +/* The default device ID */ #define MC_DEVICE_ID_DEFAULT 0 -/**< Wait infinite for a response of the MC. */ +/* Wait infinite for a response of the MC. */ #define MC_INFINITE_TIMEOUT ((int32_t)(-1)) -/**< Do not wait for a response of the MC. */ +/* Do not wait for a response of the MC. */ #define MC_NO_TIMEOUT 0 -/**< TCI/DCI must not exceed 1MiB */ +/* TCI/DCI must not exceed 1MiB */ #define MC_MAX_TCI_LEN 0x100000 - - -/** Open a new connection to a MobiCore device. - * - * mc_open_device() initializes all device specific resources required to - * communicate with an MobiCore instance located on the specified device in the - * system. If the device does not exist the function will return - * MC_DRV_ERR_UNKNOWN_DEVICE. - * - * @param [in] device_id Identifier for the MobiCore device to be used. - * MC_DEVICE_ID_DEFAULT refers to the default device. - * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_ERR_INVALID_OPERATION if device already opened. - * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device_id is unknown. - * @return MC_DRV_ERR_INVALID_DEVICE_FILE if kernel module under - * /dev/mobicore cannot be opened - * - * Uses a Mutex. +/** + * mc_open_device() - Open a new connection to a MobiCore device. + * @device_id: Identifier for the MobiCore device to be used. + * MC_DEVICE_ID_DEFAULT refers to the default device. + * + * Initializes all device specific resources required to communicate with a + * MobiCore instance located on the specified device in the system. If the + * device does not exist the function will return MC_DRV_ERR_UNKNOWN_DEVICE. + * + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_ERR_INVALID_OPERATION: device already opened + * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon + * MC_DRV_ERR_UNKNOWN_DEVICE: device_id unknown + * MC_DRV_ERR_INVALID_DEVICE_FILE: kernel module under /dev/mobicore + * cannot be opened */ -__MC_CLIENT_LIB_API enum mc_result mc_open_device( - uint32_t device_id -); +__MC_CLIENT_LIB_API enum mc_result mc_open_device(uint32_t device_id); -/** Close the connection to a MobiCore device. +/** + * mc_close_device() - Close the connection to a MobiCore device. + * @device_id: Identifier for the MobiCore device. + * * When closing a device, active sessions have to be closed beforehand. * Resources associated with the device will be released. * The device may be opened again after it has been closed. * - * @param [in] device_id Identifier for the MobiCore device. * MC_DEVICE_ID_DEFAULT refers to the default device. * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid. - * @return MC_DRV_ERR_SESSION_PENDING when a session is still open. - * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur. - * - * Uses a Mutex. + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid + * MC_DRV_ERR_SESSION_PENDING: a session is still open + * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur */ -__MC_CLIENT_LIB_API enum mc_result mc_close_device( - uint32_t device_id -); +__MC_CLIENT_LIB_API enum mc_result mc_close_device(uint32_t device_id); -/** Open a new session to a Trustlet. The trustlet with the given UUID has - * to be available in the flash filesystem. +/** + * mc_open_session() - Open a new session to a Trustlet. + * @session: On success, the session data will be returned + * @uuid: UUID of the Trustlet to be opened + * @tci: TCI buffer for communicating with the trustlet + * @tci_len: Length of the TCI buffer. Maximum allowed value + * is MC_MAX_TCI_LEN + * + * The trustlet with the given UUID has to be available in the flash filesystem. * * Write MCP open message to buffer and notify MobiCore about the availability * of a new command. + * * Waits till the MobiCore responses with the new session ID (stored in the MCP * buffer). * - * @param [in,out] session On success, the session data will be returned. * Note that session.device_id has to be the device id of an opened device. - * @param [in] uuid UUID of the Trustlet to be opened. - * @param [in] tci TCI buffer for communicating with the trustlet. - * @param [in] tci_len Length of the TCI buffer. Maximum allowed value - * is MC_MAX_TCI_LEN. - * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid. - * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon socket occur. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when daemon returns an error. - * - * Uses a Mutex. + * + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_INVALID_PARAMETER: session parameter is invalid + * MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid + * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon socket occur + * MC_DRV_ERR_NQ_FAILED: daemon returns an error */ __MC_CLIENT_LIB_API enum mc_result mc_open_session( - struct mc_session_handle *session, - const struct mc_uuid_t *uuid, - uint8_t *tci, - uint32_t tci_len -); + struct mc_session_handle *session, const struct mc_uuid_t *uuid, + uint8_t *tci, uint32_t tci_len); -/** Close a Trustlet session. +/** + * mc_close_session() - Close a Trustlet session. + * @session: Session to be closed. * * Closes the specified MobiCore session. The call will block until the * session has been closed. * - * @pre Device device_id has to be opened in advance. + * Device device_id has to be opened in advance. * - * @param [in] session Session to be closed. - * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid. - * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid. - * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur. - * @return MC_DRV_ERR_INVALID_DEVICE_FILE when daemon cannot open trustlet file. - * - * Uses a Mutex. + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_INVALID_PARAMETER: session parameter is invalid + * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid + * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid + * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur + * MC_DRV_ERR_INVALID_DEVICE_FILE: daemon cannot open trustlet file */ __MC_CLIENT_LIB_API enum mc_result mc_close_session( - struct mc_session_handle *session -); + struct mc_session_handle *session); -/** Notify a session. +/** + * mc_notify() - Notify a session. + * @session: The session to be notified. + * * Notifies the session end point about available message data. * If the session parameter is correct, notify will always succeed. * Corresponding errors can only be received by mc_wait_notification(). - * @pre A session has to be opened in advance. * - * @param session The session to be notified. + * A session has to be opened in advance. * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid. - * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid. + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_INVALID_PARAMETER: session parameter is invalid + * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid + * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid */ -__MC_CLIENT_LIB_API enum mc_result mc_notify( - struct mc_session_handle *session -); +__MC_CLIENT_LIB_API enum mc_result mc_notify(struct mc_session_handle *session); -/** Wait for a notification. +/** + * mc_wait_notification() - Wait for a notification. + * @session: The session the notification should correspond to. + * @timeout: Time in milliseconds to wait + * (MC_NO_TIMEOUT : direct return, > 0 : milliseconds, + * MC_INFINITE_TIMEOUT : wait infinitely) * * Wait for a notification issued by the MobiCore for a specific session. * The timeout parameter specifies the number of milliseconds the call will wait * for a notification. + * * If the caller passes 0 as timeout value the call will immediately return. * If timeout value is below 0 the call will block until a notification for the - session has been received. + * session has been received. + * + * If timeout is below 0, call will block. * - * @attention if timeout is below 0, call will block: * Caller has to trust the other side to send a notification to wake him up * again. * - * @param [in] session The session the notification should correspond to. - * @param [in] timeout Time in milliseconds to wait - * (MC_NO_TIMEOUT : direct return, > 0 : milliseconds, - * MC_INFINITE_TIMEOUT : wait infinitely) - * - * @return MC_DRV_OK if notification is available. - * @return MC_DRV_ERR_TIMEOUT if no notification arrived in time. - * @return MC_DRV_INFO_NOTIFICATION if a problem with the session was - * encountered. Get more details with mc_get_session_error_code(). - * @return MC_DRV_ERR_NOTIFICATION if a problem with the socket occurred. - * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid. - * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid. + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_ERR_TIMEOUT: no notification arrived in time + * MC_DRV_INFO_NOTIFICATION: a problem with the session was + * encountered. Get more details with + * mc_get_session_error_code() + * MC_DRV_ERR_NOTIFICATION: a problem with the socket occurred + * MC_DRV_INVALID_PARAMETER: a parameter is invalid + * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid + * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid */ __MC_CLIENT_LIB_API enum mc_result mc_wait_notification( - struct mc_session_handle *session, - int32_t timeout -); + struct mc_session_handle *session, int32_t timeout); /** - * Allocate a block of world shared memory (WSM). + * mc_malloc_wsm() - Allocate a block of world shared memory (WSM). + * @device_id: The ID of an opened device to retrieve the WSM from. + * @align: The alignment (number of pages) of the memory block + * (e.g. 0x00000001 for 4kb). + * @len: Length of the block in bytes. + * @wsm: Virtual address of the world shared memory block. + * @wsm_flags: Platform specific flags describing the memory to + * be allocated. + * * The MC driver allocates a contiguous block of memory which can be used as * WSM. * This implicates that the allocated memory is aligned according to the * alignment parameter. - * Always returns a buffer of size WSM_SIZE aligned to 4K. - * - * @param [in] device_id The ID of an opened device to retrieve the WSM from. - * @param [in] align The alignment (number of pages) of the memory block - * (e.g. 0x00000001 for 4kb). - * @param [in] len Length of the block in bytes. - * @param [out] wsm Virtual address of the world shared memory block. - * @param [in] wsm_flags Platform specific flags describing the memory to - * be allocated. * - * @attention: align and wsm_flags are currently ignored + * Always returns a buffer of size WSM_SIZE aligned to 4K. * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid. - * @return MC_DRV_ERR_NO_FREE_MEMORY if no more contiguous memory is available - * in this size or for this process. + * Align and wsm_flags are currently ignored * - * Uses a Mutex. + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_INVALID_PARAMETER: a parameter is invalid + * MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid + * MC_DRV_ERR_NO_FREE_MEMORY: no more contiguous memory is + * available in this size or for this + * process */ __MC_CLIENT_LIB_API enum mc_result mc_malloc_wsm( uint32_t device_id, @@ -323,161 +306,140 @@ __MC_CLIENT_LIB_API enum mc_result mc_malloc_wsm( ); /** - * Free a block of world shared memory (WSM). + * mc_free_wsm() - Free a block of world shared memory (WSM). + * @device_id: The ID to which the given address belongs + * @wsm: Address of WSM block to be freed + * * The MC driver will free a block of world shared memory (WSM) previously * allocated with mc_malloc_wsm(). The caller has to assure that the address * handed over to the driver is a valid WSM address. * - * @param [in] device_id The ID to which the given address belongs. - * @param [in] wsm Address of WSM block to be freed. - * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid. - * @return MC_DRV_ERR_FREE_MEMORY_FAILED on failures. - * - * Uses a Mutex. + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_INVALID_PARAMETER: a parameter is invalid + * MC_DRV_ERR_UNKNOWN_DEVICE: when device id is invalid + * MC_DRV_ERR_FREE_MEMORY_FAILED: on failure */ -__MC_CLIENT_LIB_API enum mc_result mc_free_wsm( - uint32_t device_id, - uint8_t *wsm -); +__MC_CLIENT_LIB_API enum mc_result mc_free_wsm(uint32_t device_id, + uint8_t *wsm); /** - * Map additional bulk buffer between a Trustlet Connector (TLC) and - * the Trustlet (TL) for a session. + *mc_map() - Map additional bulk buffer between a Trustlet Connector (TLC) + * and the Trustlet (TL) for a session + * @session: Session handle with information of the device_id and + * the session_id. The given buffer is mapped to the + * session specified in the sessionHandle + * @buf: Virtual address of a memory portion (relative to TLC) + * to be shared with the Trustlet, already includes a + * possible offset! + * @len: length of buffer block in bytes. + * @map_info: Information structure about the mapped Bulk buffer + * between the TLC (Nwd) and the TL (Swd). + * * Memory allocated in user space of the TLC can be mapped as additional * communication channel (besides TCI) to the Trustlet. Limitation of the * Trustlet memory structure apply: only 6 chunks can be mapped with a maximum * chunk size of 1 MiB each. * - * @attention It is up to the application layer (TLC) to inform the Trustlet + * It is up to the application layer (TLC) to inform the Trustlet * about the additional mapped bulk memory. * - * @param [in] session Session handle with information of the device_id and - * the session_id. The - * given buffer is mapped to the session specified in the sessionHandle. - * @param [in] buf Virtual address of a memory portion (relative to TLC) - * to be shared with the Trustlet, already includes a possible offset! - * @param [in] len length of buffer block in bytes. - * @param [out] map_info Information structure about the mapped Bulk buffer - * between the TLC (Nwd) and - * the TL (Swd). - * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid. - * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid. - * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur. - * @return MC_DRV_ERR_BULK_MAPPING when buf is already uses as bulk buffer or - * when registering the buffer failed. - * - * Uses a Mutex. + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_INVALID_PARAMETER: a parameter is invalid + * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid + * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid + * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur + * MC_DRV_ERR_BULK_MAPPING: buf is already uses as bulk buffer or + * when registering the buffer failed */ __MC_CLIENT_LIB_API enum mc_result mc_map( - struct mc_session_handle *session, - void *buf, - uint32_t len, - struct mc_bulk_map *map_info -); + struct mc_session_handle *session, void *buf, uint32_t len, + struct mc_bulk_map *map_info); /** - * Remove additional mapped bulk buffer between Trustlet Connector (TLC) - * and the Trustlet (TL) for a session. - * - * @attention The bulk buffer will immediately be unmapped from the session - * context. - * @attention The application layer (TLC) must inform the TL about unmapping - * of the additional bulk memory before calling mc_unmap! - * - * @param [in] session Session handle with information of the device_id and - * the session_id. The given buffer is unmapped from the session specified - * in the sessionHandle. - * @param [in] buf Virtual address of a memory portion (relative to TLC) - * shared with the TL, already includes a possible offset! - * @param [in] map_info Information structure about the mapped Bulk buffer - * between the TLC (Nwd) and - * the TL (Swd). - * @attention The clientlib currently ignores the len field in map_info. - * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid. - * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid. - * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur. - * @return MC_DRV_ERR_BULK_UNMAPPING when buf was not registered earlier - * or when unregistering failed. - * - * Uses a Mutex. + * mc_unmap() - Remove additional mapped bulk buffer between Trustlet Connector + * (TLC) and the Trustlet (TL) for a session + * @session: Session handle with information of the device_id and + * the session_id. The given buffer is unmapped from the + * session specified in the sessionHandle. + * @buf: Virtual address of a memory portion (relative to TLC) + * shared with the TL, already includes a possible offset! + * @map_info: Information structure about the mapped Bulk buffer + * between the TLC (Nwd) and the TL (Swd) + * + * The bulk buffer will immediately be unmapped from the session context. + * + * The application layer (TLC) must inform the TL about unmapping of the + * additional bulk memory before calling mc_unmap! + * + * The clientlib currently ignores the len field in map_info. + * + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_INVALID_PARAMETER: a parameter is invalid + * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid + * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid + * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur + * MC_DRV_ERR_BULK_UNMAPPING: buf was not registered earlier + * or when unregistering failed */ __MC_CLIENT_LIB_API enum mc_result mc_unmap( - struct mc_session_handle *session, - void *buf, - struct mc_bulk_map *map_info -); - + struct mc_session_handle *session, void *buf, + struct mc_bulk_map *map_info); /** - * @attention: Not implemented. - * Execute driver specific command. - * mc_driver_ctrl() can be used to execute driver specific commands. - * Besides the control command MC_CTRL_GET_VERSION commands are implementation - * specific. - * Please refer to the corresponding specification of the driver manufacturer. + * mc_driver_ctrl() - Execute driver specific command. + * @param: Command ID of the command to be executed + * @data: Command data and response depending on command + * @len: Length of the data block + * + * Can be used to execute driver specific commands. Besides the control command + * MC_CTRL_GET_VERSION commands are implementation specific. * - * @param [in] param Command ID of the command to be executed. - * @param [in, out] data Command data and response depending on command. - * @param [in] len Length of the data block. + * Please refer to the corresponding specification of the driver manufacturer. * - * @return MC_DRV_ERR_NOT_IMPLEMENTED. + * Return codes: + * MC_DRV_ERR_NOT_IMPLEMENTED. */ __MC_CLIENT_LIB_API enum mc_result mc_driver_ctrl( - enum mc_driver_ctrl param, - uint8_t *data, - uint32_t len -); + enum mc_driver_ctrl param, uint8_t *data, uint32_t len); /** - * @attention: Not implemented. - * Execute application management command. - * mc_manage() shall be used to exchange application management commands with - * the MobiCore. - * The MobiCore Application Management Protocol is described in [MCAMP]. + * mc_manage() - Execute application management command. + * @device_id: Identifier for the MobiCore device to be used. + * NULL refers to the default device. + * @data: Command data/response data depending on command + * @len: Length of the data block * - * @param [in] device_id Identifier for the MobiCore device to be used. - * NULL refers to the default device. - * @param [in, out] data Command data/response data depending on command. - * @param [in] len Length of the data block. + * Shall be used to exchange application management commands with the MobiCore. + * The MobiCore Application Management Protocol is described in [MCAMP]. * - * @return MC_DRV_ERR_NOT_IMPLEMENTED. + * Return codes: + * MC_DRV_ERR_NOT_IMPLEMENTED. */ __MC_CLIENT_LIB_API enum mc_result mc_manage( - uint32_t device_id, - uint8_t *data, - uint32_t len -); + uint32_t device_id, uint8_t *data, uint32_t len); /** - * Get additional error information of the last error that occured on a session. + * mc_get_session_error_code() - Get additional error information of the last + * error that occured on a session. + * @session: Session handle with information of the device_id and + * the session_id + * @last_error: >0 Trustlet has terminated itself with this value, + * <0 Trustlet is dead because of an error within the + * MobiCore (e.g. Kernel exception). See also MCI + * definition. + * * After the request the stored error code will be deleted. * - * @param [in] session Session handle with information of the device_id and - * the session_id. - * @param [out] last_error >0 Trustlet has terminated itself with this value, - * <0 Trustlet is dead because of an error within the MobiCore - * (e.g. Kernel exception). - * See also MCI definition. - * - * @return MC_DRV_OK if operation has been successfully completed. - * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid. - * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid. - * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid. + * Return codes: + * MC_DRV_OK: operation completed successfully + * MC_DRV_INVALID_PARAMETER: a parameter is invalid + * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid + * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid */ __MC_CLIENT_LIB_API enum mc_result mc_get_session_error_code( - struct mc_session_handle *session, - int32_t *last_error -); - -#endif /** MCDRIVER_H_ */ + struct mc_session_handle *session, int32_t *last_error); -/** @} */ +#endif /* _MOBICORE_DRIVER_API_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h index 9ff798927dc..3e62fdd8f72 100644 --- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h +++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h @@ -1,8 +1,5 @@ -/** @addtogroup MCD_MCDIMPL_DAEMON - * @{ - * @file - * - * +/* + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,11 +25,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MCDAEMON_H_ -#define MCDAEMON_H_ - - - +#ifndef _MOBICORE_DRIVER_CMD_H_ +#define _MOBICORE_DRIVER_CMD_H_ #include "mcuuid.h" @@ -64,19 +58,17 @@ enum mc_drv_rsp_t { struct mc_drv_command_header_t { - uint32_t command_id; + uint32_t command_id; }; struct mc_drv_response_header_t { - uint32_t response_id; + uint32_t response_id; }; -#define MC_DEVICE_ID_DEFAULT 0 /**< The default device ID */ - +#define MC_DEVICE_ID_DEFAULT 0 /* The default device ID */ -/*****************************************************************************/ struct mc_drv_cmd_open_device_payload_t { - uint32_t device_id; + uint32_t device_id; }; struct mc_drv_cmd_open_device_t { @@ -94,13 +86,13 @@ struct mc_drv_rsp_open_device_t { struct mc_drv_rsp_open_device_payload_t payload; }; - -/*****************************************************************************/ struct mc_drv_cmd_close_device_t { struct mc_drv_command_header_t header; - /* no payload here because close has none. - If we use an empty struct, C++ will count it as 4 bytes. - This will write too much into the socket at write(cmd,sizeof(cmd)) */ + /* + * no payload here because close has none. + * If we use an empty struct, C++ will count it as 4 bytes. + * This will write too much into the socket at write(cmd,sizeof(cmd)) + */ }; @@ -113,8 +105,6 @@ struct mc_drv_rsp_close_device_t { struct mc_drv_rsp_close_device_payload_t payload; }; - -/*****************************************************************************/ struct mc_drv_cmd_open_session_payload_t { uint32_t device_id; struct mc_uuid_t uuid; @@ -141,8 +131,6 @@ struct mc_drv_rsp_open_session_t { struct mc_drv_rsp_open_session_payload_t payload; }; - -/*****************************************************************************/ struct mc_drv_cmd_close_session_payload_t { uint32_t session_id; }; @@ -162,8 +150,6 @@ struct mc_drv_rsp_close_session_t { struct mc_drv_rsp_close_session_payload_t payload; }; - -/*****************************************************************************/ struct mc_drv_cmd_notify_payload_t { uint32_t session_id; }; @@ -183,8 +169,6 @@ struct mc_drv_rsp_notify_t { struct mc_drv_rsp_notify_payload_t payload; }; - -/*****************************************************************************/ struct mc_drv_cmd_map_bulk_mem_payload_t { uint32_t session_id; uint32_t phys_addr_l2; @@ -209,8 +193,6 @@ struct mc_drv_rsp_map_bulk_mem_t { struct mc_drv_rsp_map_bulk_mem_payload_t payload; }; - -/*****************************************************************************/ struct mc_drv_cmd_unmap_bulk_mem_payload_t { uint32_t session_id; uint32_t secure_virtual_adr; @@ -234,8 +216,6 @@ struct mc_drv_rsp_unmap_bulk_mem_t { struct mc_drv_rsp_unmap_bulk_mem_payload_t payload; }; - -/*****************************************************************************/ struct mc_drv_cmd_nqconnect_payload_t { uint32_t device_id; uint32_t session_id; @@ -258,8 +238,6 @@ struct mc_drv_rsp_nqconnect_t { struct mc_drv_rsp_nqconnect_payload_t payload; }; - -/*****************************************************************************/ union mc_drv_command_t { struct mc_drv_command_header_t header; struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device; @@ -284,6 +262,4 @@ union mc_drv_response_t { struct mc_drv_rsp_unmap_bulk_mem_t mc_drv_rsp_unmap_bulk_mem; }; -#endif /* MCDAEMON_H_ */ - -/** @} */ +#endif /* _MOBICORE_DRIVER_CMD_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/session.c b/drivers/gud/mobicore_kernelapi/session.c index e62b4b3efc7..eb752898bed 100644 --- a/drivers/gud/mobicore_kernelapi/session.c +++ b/drivers/gud/mobicore_kernelapi/session.c @@ -1,7 +1,5 @@ -/** @addtogroup MCD_IMPL_LIB - * @{ - * @file - * +/* + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -9,39 +7,35 @@ */ #include #include +#include #include "mc_kernel_api.h" #include "public/mobicore_driver_api.h" #include "session.h" -/*****************************************************************************/ struct bulk_buffer_descriptor *bulk_buffer_descriptor_create( - void *virt_addr, - uint32_t len, - uint32_t handle, - void *phys_addr_wsm_l2 -) { - struct bulk_buffer_descriptor *desc = - kzalloc(sizeof(struct bulk_buffer_descriptor), GFP_KERNEL); + void *virt_addr, uint32_t len, uint32_t handle, void *phys_addr_wsm_l2) +{ + struct bulk_buffer_descriptor *desc; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); desc->virt_addr = virt_addr; desc->len = len; desc->handle = handle; desc->phys_addr_wsm_l2 = phys_addr_wsm_l2; + return desc; } -/*****************************************************************************/ struct session *session_create( - uint32_t session_id, - void *instance, - struct connection *connection -) { - struct session *session = - kzalloc(sizeof(struct session), GFP_KERNEL); + uint32_t session_id, void *instance, struct connection *connection) +{ + struct session *session; + + session = kzalloc(sizeof(*session), GFP_KERNEL); session->session_id = session_id; session->instance = instance; session->notification_connection = connection; - session->session_info.last_error = SESSION_ERR_NO; session->session_info.state = SESSION_STATE_INITIAL; @@ -49,29 +43,31 @@ struct session *session_create( return session; } - -/*****************************************************************************/ -void session_cleanup( - struct session *session -) { - struct bulk_buffer_descriptor *bulk_buf_descr; +void session_cleanup(struct session *session) +{ + struct bulk_buffer_descriptor *bulk_buf_descr; struct list_head *pos, *q; + unsigned int phys_addr_wsm_l2; /* Unmap still mapped buffers */ list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) { bulk_buf_descr = list_entry(pos, struct bulk_buffer_descriptor, list); - MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, " - "handle= %d", - (unsigned int)bulk_buf_descr->phys_addr_wsm_l2, - bulk_buf_descr->handle); + phys_addr_wsm_l2 = + (unsigned int)bulk_buf_descr->phys_addr_wsm_l2; + + MCDRV_DBG_VERBOSE(mc_kapi, + "Phys Addr of L2 Table = 0x%X, handle= %d", + phys_addr_wsm_l2, + bulk_buf_descr->handle); /* ignore any error, as we cannot do anything in this case. */ int ret = mobicore_unmap_vmem(session->instance, - bulk_buf_descr->handle); + bulk_buf_descr->handle); if (ret != 0) - MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret); + MCDRV_DBG_ERROR(mc_kapi, + "mobicore_unmap_vmem failed: %d", ret); list_del(pos); kfree(bulk_buf_descr); @@ -82,36 +78,27 @@ void session_cleanup( kfree(session); } - -/*****************************************************************************/ -void session_set_error_info( - struct session *session, - int32_t err -) { +void session_set_error_info(struct session *session, int32_t err) +{ session->session_info.last_error = err; } - -/*****************************************************************************/ -int32_t session_get_last_err( - struct session *session -) { +int32_t session_get_last_err(struct session *session) +{ return session->session_info.last_error; } - -/*****************************************************************************/ -struct bulk_buffer_descriptor *session_add_bulk_buf( - struct session *session, - void *buf, - uint32_t len -) { +struct bulk_buffer_descriptor *session_add_bulk_buf(struct session *session, + void *buf, uint32_t len) +{ struct bulk_buffer_descriptor *bulk_buf_descr = NULL; - struct bulk_buffer_descriptor *tmp; + struct bulk_buffer_descriptor *tmp; struct list_head *pos; - /* Search bulk buffer descriptors for existing vAddr - At the moment a virtual address can only be added one time */ + /* + * Search bulk buffer descriptors for existing vAddr + * At the moment a virtual address can only be added one time + */ list_for_each(pos, &session->bulk_buffer_descriptors) { tmp = list_entry(pos, struct bulk_buffer_descriptor, list); if (tmp->virt_addr == buf) @@ -119,55 +106,50 @@ struct bulk_buffer_descriptor *session_add_bulk_buf( } do { - /* Prepare the interface structure for memory registration in - Kernel Module */ - void *l2_table_phys; - uint32_t handle; + /* + * Prepare the interface structure for memory registration in + * Kernel Module + */ + void *l2_table_phys; + uint32_t handle; - int ret = mobicore_map_vmem(session->instance, - buf, - len, - &handle, - &l2_table_phys); + int ret = mobicore_map_vmem(session->instance, buf, len, + &handle, &l2_table_phys); if (ret != 0) { - MCDRV_DBG_ERROR("mobicore_map_vmem failed, ret=%d", + MCDRV_DBG_ERROR(mc_kapi, + "mobicore_map_vmem failed, ret=%d", ret); break; } - MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, " - "handle=%d", - (unsigned int)l2_table_phys, - handle); + MCDRV_DBG_VERBOSE(mc_kapi, + "Phys Addr of L2 Table = 0x%X, handle=%d", + (unsigned int)l2_table_phys, handle); /* Create new descriptor */ - bulk_buf_descr = bulk_buffer_descriptor_create( - buf, - len, - handle, - l2_table_phys); + bulk_buf_descr = bulk_buffer_descriptor_create(buf, len, + handle, + l2_table_phys); /* Add to vector of descriptors */ list_add_tail(&(bulk_buf_descr->list), - &(session->bulk_buffer_descriptors)); + &(session->bulk_buffer_descriptors)); } while (0); return bulk_buf_descr; } - -/*****************************************************************************/ -bool session_remove_bulk_buf( - struct session *session, - void *virt_addr -) { +bool session_remove_bulk_buf(struct session *session, void *virt_addr) +{ bool ret = true; - struct bulk_buffer_descriptor *bulk_buf_descr = NULL; - struct bulk_buffer_descriptor *tmp; + struct bulk_buffer_descriptor *bulk_buf_descr = NULL; + struct bulk_buffer_descriptor *tmp; struct list_head *pos, *q; + unsigned int phys_addr_wsm_l2; - MCDRV_DBG_VERBOSE("Virtual Address = 0x%X", (unsigned int) virt_addr); + MCDRV_DBG_VERBOSE(mc_kapi, "Virtual Address = 0x%X", + (unsigned int) virt_addr); /* Search and remove bulk buffer descriptor */ list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) { @@ -180,23 +162,24 @@ bool session_remove_bulk_buf( } if (bulk_buf_descr == NULL) { - MCDRV_DBG_ERROR("Virtual Address not found"); + MCDRV_DBG_ERROR(mc_kapi, "Virtual Address not found"); ret = false; } else { - MCDRV_DBG_VERBOSE("WsmL2 phys=0x%X, handle=%d", - (unsigned int)bulk_buf_descr->phys_addr_wsm_l2, - bulk_buf_descr->handle); + phys_addr_wsm_l2 = + (unsigned int)bulk_buf_descr->phys_addr_wsm_l2; + + MCDRV_DBG_VERBOSE(mc_kapi, "WsmL2 phys=0x%X, handle=%d", + phys_addr_wsm_l2, bulk_buf_descr->handle); /* ignore any error, as we cannot do anything */ int ret = mobicore_unmap_vmem(session->instance, - bulk_buf_descr->handle); + bulk_buf_descr->handle); if (ret != 0) - MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret); + MCDRV_DBG_ERROR(mc_kapi, + "mobicore_unmap_vmem failed: %d", ret); kfree(bulk_buf_descr); } return ret; } - -/** @} */ diff --git a/drivers/gud/mobicore_kernelapi/session.h b/drivers/gud/mobicore_kernelapi/session.h index 9a537402733..430dd3562ea 100644 --- a/drivers/gud/mobicore_kernelapi/session.h +++ b/drivers/gud/mobicore_kernelapi/session.h @@ -1,14 +1,12 @@ -/** @addtogroup MCD_IMPL_LIB - * @{ - * @file - * +/* + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef SESSION_H_ -#define SESSION_H_ +#ifndef _MC_KAPI_SESSION_H_ +#define _MC_KAPI_SESSION_H_ #include "common.h" @@ -17,23 +15,27 @@ struct bulk_buffer_descriptor { - void *virt_addr;/**< The virtual address of the Bulk buffer*/ - uint32_t len; /**< Length of the Bulk buffer*/ + void *virt_addr; /* The VA of the Bulk buffer */ + uint32_t len; /* Length of the Bulk buffer */ uint32_t handle; - void *phys_addr_wsm_l2; /**< The physical address of the - L2 table of the Bulk buffer*/ - struct list_head list; /**< The list param for using the kernel lists*/ + + /* The physical address of the L2 table of the Bulk buffer*/ + void *phys_addr_wsm_l2; + + /* The list param for using the kernel lists*/ + struct list_head list; }; struct bulk_buffer_descriptor *bulk_buffer_descriptor_create( - void *virt_addr, - uint32_t len, - uint32_t handle, - void *phys_addr_wsm_l2 + void *virt_addr, + uint32_t len, + uint32_t handle, + void *phys_addr_wsm_l2 ); -/** Session states. - * At the moment not used !!. +/* + * Session states. + * At the moment not used !! */ enum session_state { SESSION_STATE_INITIAL, @@ -41,96 +43,89 @@ enum session_state { SESSION_STATE_TRUSTLET_DEAD }; -#define SESSION_ERR_NO 0 /**< No session error */ +#define SESSION_ERR_NO 0 /* No session error */ -/** Session information structure. +/* + * Session information structure. * The information structure is used to hold the state of the session, which * will limit further actions for the session. * Also the last error code will be stored till it's read. */ struct session_information { - enum session_state state; /**< Session state */ - int32_t last_error; /**< Last error of session */ + enum session_state state; /* Session state */ + int32_t last_error; /* Last error of session */ }; struct session { struct mc_instance *instance; - /**< Descriptors of additional bulk buffer of a session */ - struct list_head bulk_buffer_descriptors; - /**< Informations about session */ - struct session_information session_info; - uint32_t session_id; - struct connection *notification_connection; + /* Descriptors of additional bulk buffer of a session */ + struct list_head bulk_buffer_descriptors; - /**< The list param for using the kernel lists*/ - struct list_head list; + /* Informations about session */ + struct session_information session_info; + + uint32_t session_id; + struct connection *notification_connection; + + /* The list param for using the kernel lists */ + struct list_head list; }; struct session *session_create( - uint32_t session_id, - void *instance, - struct connection *connection + uint32_t session_id, + void *instance, + struct connection *connection ); -void session_cleanup( - struct session *session -); +void session_cleanup(struct session *session); /** - * Add address information of additional bulk buffer memory to session and - * register virtual memory in kernel module. - * - * @attention The virtual address can only be added one time. If the virtual - * address already exist, NULL is returned. - * - * @param buf The virtual address of bulk buffer. - * @param len Length of bulk buffer. - * - * @return On success the actual Bulk buffer descriptor with all address - * information is retured, NULL if an error occurs. - */ + * session_add_bulk_buf() - Add address information of additional bulk + * buffer memory to session and register virtual + * memory in kernel module + * @session: Session information structure + * @buf: The virtual address of bulk buffer. + * @len: Length of bulk buffer. + * + * The virtual address can only be added one time. If the virtual + * address already exist, NULL is returned. + * + * On success the actual Bulk buffer descriptor with all address information + * is retured, NULL if an error occurs. + */ struct bulk_buffer_descriptor *session_add_bulk_buf( - struct session *session, - void *buf, - uint32_t len -); + struct session *session, void *buf, uint32_t len); /** - * Remove address information of additional bulk buffer memory from session and - * unregister virtual memory in kernel module - * - * @param buf The virtual address of the bulk buffer. - * - * @return true on success. - */ -bool session_remove_bulk_buf( - struct session *session, - void *buf -); + * session_remove_bulk_buf() - Remove address information of additional bulk + * buffer memory from session and unregister + * virtual memory in kernel module + * @session: Session information structure + * @buf: The virtual address of the bulk buffer + * + * Returns true on success + */ +bool session_remove_bulk_buf(struct session *session, void *buf); /** - * Set additional error information of the last error that occured. - * - * @param errorCode The actual error. - */ -void session_set_error_info( - struct session *session, - int32_t err -); + * session_set_error_info() - Set additional error information of the last + * error that occured. + * @session: Session information structure + * @err: The actual error + */ +void session_set_error_info(struct session *session, int32_t err); /** - * Get additional error information of the last error that occured. - * - * @attention After request the information is set to SESSION_ERR_NO. - * - * @return Last stored error code or SESSION_ERR_NO. - */ -int32_t session_get_last_err( - struct session *session -); - -#endif /* SESSION_H_ */ + * session_get_last_err() - Get additional error information of the last + * error that occured. + * @session: Session information structure + * + * After request the information is set to SESSION_ERR_NO. + * + * Returns the last stored error code or SESSION_ERR_NO + */ +int32_t session_get_last_err(struct session *session); -/** @} */ +#endif /* _MC_KAPI_SESSION_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/wsm.h b/drivers/gud/mobicore_kernelapi/wsm.h index 6877c53768b..f8a107c2240 100644 --- a/drivers/gud/mobicore_kernelapi/wsm.h +++ b/drivers/gud/mobicore_kernelapi/wsm.h @@ -1,35 +1,33 @@ -/** @addtogroup MCD_MCDIMPL_DAEMON_SRV - * @{ - * @file - * +/* * World shared memory definitions. * - * + * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef WSM_H_ -#define WSM_H_ +#ifndef _MC_KAPI_WSM_H_ +#define _MC_KAPI_WSM_H_ #include "common.h" #include struct wsm { - void *virt_addr; - uint32_t len; - uint32_t handle; - void *phys_addr; - struct list_head list; + void *virt_addr; + uint32_t len; + uint32_t handle; + void *phys_addr; + struct list_head list; }; struct wsm *wsm_create( - void *virt_addr, - uint32_t len, - uint32_t handle, - void *phys_addr /*= NULL this may be unknown, so is can be omitted.*/ + void *virt_addr, + uint32_t len, + uint32_t handle, + + /* NULL this may be unknown, so is can be omitted */ + void *phys_addr ); -#endif /* WSM_H_ */ -/** @} */ +#endif /* _MC_KAPI_WSM_H_ */ From 8372b91dd4e6c215cc6c9bde98ea03dde25eb647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20H=C3=A4nel?= Date: Wed, 7 Nov 2012 13:17:39 +0900 Subject: [PATCH 2345/2357] mobicore: MobiCore 1.2 kernel module Changes to MC11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split up of /dev/mobicore into daemon and TLC part /dev/mobicore-user. Refactored memory management to use locking and refcounting. Use new data structures for managing world shared memory. Split up functionality into different source files. Shorter names for various identifiers. Signed-off-by: Lukas Hänel Change-Id: I6e239c061403500b74707feca31785237158f93b [hnamgund@codeaurora.org: Drop executable permission for arm.h, drop changes to platform.h to align with other branches, reformat commit text] Signed-off-by: Hariprasad Dhalinarasimha Acked-by: Tony Hamilton --- drivers/gud/Makefile | 8 +- drivers/gud/mobicore_driver/api.c | 114 + drivers/gud/mobicore_driver/arm.h | 72 + drivers/gud/mobicore_driver/build_tag.h | 4 +- drivers/gud/mobicore_driver/debug.h | 65 + drivers/gud/mobicore_driver/fastcall.h | 157 + drivers/gud/mobicore_driver/logging.c | 25 +- drivers/gud/mobicore_driver/logging.h | 27 + drivers/gud/mobicore_driver/main.c | 2827 +++++------------ drivers/gud/mobicore_driver/main.h | 144 + drivers/gud/mobicore_driver/mc_drv_module.h | 239 -- .../mobicore_driver/mc_drv_module_android.h | 37 - .../mobicore_driver/mc_drv_module_fastcalls.h | 205 -- drivers/gud/mobicore_driver/mem.c | 696 ++++ drivers/gud/mobicore_driver/mem.h | 127 + drivers/gud/mobicore_driver/ops.c | 143 + drivers/gud/mobicore_driver/ops.h | 30 + drivers/gud/mobicore_driver/pm.h | 17 + .../public/mc_drv_module_api.h | 277 -- .../mobicore_driver/public/mc_kernel_api.h | 27 +- drivers/gud/mobicore_driver/public/mc_linux.h | 209 ++ drivers/gud/mobicore_driver/public/version.h | 8 +- drivers/gud/mobicore_kernelapi/clientlib.c | 11 + drivers/gud/mobicore_kernelapi/common.h | 2 + drivers/gud/mobicore_kernelapi/connection.c | 2 +- drivers/gud/mobicore_kernelapi/connection.h | 1 + drivers/gud/mobicore_kernelapi/device.c | 4 +- drivers/gud/mobicore_kernelapi/device.h | 4 +- .../gud/mobicore_kernelapi/include/mcinq.h | 6 +- drivers/gud/mobicore_kernelapi/main.c | 4 +- .../public/mobicore_driver_api.h | 14 +- .../public/mobicore_driver_cmd.h | 2 + drivers/gud/mobicore_kernelapi/session.c | 44 +- drivers/gud/mobicore_kernelapi/session.h | 29 +- 34 files changed, 2716 insertions(+), 2865 deletions(-) create mode 100644 drivers/gud/mobicore_driver/api.c create mode 100644 drivers/gud/mobicore_driver/arm.h create mode 100644 drivers/gud/mobicore_driver/debug.h create mode 100644 drivers/gud/mobicore_driver/fastcall.h create mode 100644 drivers/gud/mobicore_driver/logging.h create mode 100644 drivers/gud/mobicore_driver/main.h delete mode 100644 drivers/gud/mobicore_driver/mc_drv_module.h delete mode 100644 drivers/gud/mobicore_driver/mc_drv_module_android.h delete mode 100644 drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h create mode 100644 drivers/gud/mobicore_driver/mem.c create mode 100644 drivers/gud/mobicore_driver/mem.h create mode 100644 drivers/gud/mobicore_driver/ops.c create mode 100644 drivers/gud/mobicore_driver/ops.h create mode 100644 drivers/gud/mobicore_driver/pm.h delete mode 100644 drivers/gud/mobicore_driver/public/mc_drv_module_api.h create mode 100644 drivers/gud/mobicore_driver/public/mc_linux.h diff --git a/drivers/gud/Makefile b/drivers/gud/Makefile index ea212c523bd..3a16bb7ab01 100644 --- a/drivers/gud/Makefile +++ b/drivers/gud/Makefile @@ -6,7 +6,11 @@ GUD_ROOT_FOLDER := drivers/gud obj-$(CONFIG_MOBICORE_API) += mckernelapi.o obj-$(CONFIG_MOBICORE_SUPPORT) += mcdrvmodule.o -mcdrvmodule-objs := mobicore_driver/logging.o mobicore_driver/main.o +mcdrvmodule-objs := mobicore_driver/logging.o \ + mobicore_driver/ops.o \ + mobicore_driver/mem.o \ + mobicore_driver/api.o \ + mobicore_driver/main.o mckernelapi-objs := mobicore_kernelapi/main.o \ mobicore_kernelapi/clientlib.o \ @@ -15,7 +19,7 @@ mckernelapi-objs := mobicore_kernelapi/main.o \ mobicore_kernelapi/connection.o # Release mode by default -ccflags-y := -DNDEBUG +ccflags-y := -DNDEBUG -include $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/build_tag.h ccflags-y += -Wno-declaration-after-statement ccflags-$(CONFIG_MOBICORE_DEBUG) += -DDEBUG diff --git a/drivers/gud/mobicore_driver/api.c b/drivers/gud/mobicore_driver/api.c new file mode 100644 index 00000000000..2506bc2b1bc --- /dev/null +++ b/drivers/gud/mobicore_driver/api.c @@ -0,0 +1,114 @@ +/* MobiCore driver module.(interface to the secure world SWD) + * MobiCore Driver Kernel Module. + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + +#include "main.h" +#include "mem.h" +#include "debug.h" + + +/* + * Map a virtual memory buffer structure to Mobicore + * @param instance + * @param addr address of the buffer(NB it must be kernel virtual!) + * @param len buffer length + * @param handle pointer to handle + * @param phys_wsm_l2_table pointer to physical L2 table(?) + * + * @return 0 if no error + * + */ +int mobicore_map_vmem(struct mc_instance *instance, void *addr, + uint32_t len, uint32_t *handle, uint32_t *phys) +{ + return mc_register_wsm_l2(instance, (uint32_t)addr, len, + handle, phys); +} +EXPORT_SYMBOL(mobicore_map_vmem); + +/* + * Unmap a virtual memory buffer from mobicore + * @param instance + * @param handle + * + * @return 0 if no error + * + */ +int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle) +{ + return mc_unregister_wsm_l2(instance, handle); +} +EXPORT_SYMBOL(mobicore_unmap_vmem); + +/* + * Free a WSM buffer allocated with mobicore_allocate_wsm + * @param instance + * @param handle handle of the buffer + * + * @return 0 if no error + * + */ +int mobicore_free_wsm(struct mc_instance *instance, uint32_t handle) +{ + return mc_free_buffer(instance, handle); +} +EXPORT_SYMBOL(mobicore_free_wsm); + + +/* + * Allocate WSM for given instance + * + * @param instance instance + * @param requested_size size of the WSM + * @param handle pointer where the handle will be saved + * @param virt_kernel_addr pointer for the kernel virtual address + * @param phys_addr pointer for the physical address + * + * @return error code or 0 for success + */ +int mobicore_allocate_wsm(struct mc_instance *instance, + unsigned long requested_size, uint32_t *handle, void **virt_kernel_addr, + void **phys_addr) +{ + struct mc_buffer *buffer = NULL; + + /* Setup the WSM buffer structure! */ + if (mc_get_buffer(instance, &buffer, requested_size)) + return -EFAULT; + + *handle = buffer->handle; + *phys_addr = buffer->phys; + *virt_kernel_addr = buffer->addr; + return 0; +} +EXPORT_SYMBOL(mobicore_allocate_wsm); + +/* + * Initialize a new mobicore API instance object + * + * @return Instance or NULL if no allocation was possible. + */ +struct mc_instance *mobicore_open(void) +{ + return mc_alloc_instance(); +} +EXPORT_SYMBOL(mobicore_open); + +/* + * Release a mobicore instance object and all objects related to it + * @param instance instance + * @return 0 if Ok or -E ERROR + */ +int mobicore_release(struct mc_instance *instance) +{ + return mc_release_instance(instance); +} +EXPORT_SYMBOL(mobicore_release); + diff --git a/drivers/gud/mobicore_driver/arm.h b/drivers/gud/mobicore_driver/arm.h new file mode 100644 index 00000000000..0cddc0c41ff --- /dev/null +++ b/drivers/gud/mobicore_driver/arm.h @@ -0,0 +1,72 @@ +/* + * MobiCore driver module.(interface to the secure world SWD) + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MC_ARM_H_ +#define _MC_ARM_H_ + +#include "debug.h" + +/* + * ARM Trustzone specific masks and modes + * Vanilla Linux is unaware of TrustZone extension. + * I.e. arch/arm/include/asm/ptrace.h does not define monitor mode. + * Also TZ bits in cpuid are not defined, ARM port uses magic numbers, + * see arch/arm/kernel/setup.c + */ +#define ARM_MONITOR_MODE (0b10110) +#define ARM_SECURITY_EXTENSION_MASK (0x30) + +/* check if CPU supports the ARM TrustZone Security Extensions */ +inline bool has_security_extensions(void) +{ + u32 fea = 0; + asm volatile( + "mrc p15, 0, %[fea], cr0, cr1, 0" : + [fea]"=r" (fea)); + + MCDRV_DBG_VERBOSE(mcd, "CPU Features: 0x%X", fea); + + /* + * If the CPU features ID has 0 for security features then the CPU + * doesn't support TrustZone at all! + */ + if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0) + return false; + + return true; +} + +/* check if running in secure mode */ +inline bool is_secure_mode(void) +{ + u32 cpsr = 0; + u32 nsacr = 0; + + asm volatile( + "mrc p15, 0, %[nsacr], cr1, cr1, 2\n" + "mrs %[cpsr], cpsr\n" : + [nsacr]"=r" (nsacr), + [cpsr]"=r"(cpsr)); + + MCDRV_DBG_VERBOSE(mcd, "CPRS.M = set to 0x%X\n", cpsr & MODE_MASK); + MCDRV_DBG_VERBOSE(mcd, "SCR.NS = set to 0x%X\n", nsacr); + + /* + * If the NSACR contains the reset value(=0) then most likely we are + * running in Secure MODE. + * If the cpsr mode is set to monitor mode then we cannot load! + */ + if (nsacr == 0 || ((cpsr & MODE_MASK) == ARM_MONITOR_MODE)) + return true; + + return false; +} + +#endif /* _MC_ARM_H_ */ diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/mobicore_driver/build_tag.h index 79404fdf4c9..a6898f12df1 100644 --- a/drivers/gud/mobicore_driver/build_tag.h +++ b/drivers/gud/mobicore_driver/build_tag.h @@ -1,5 +1,5 @@ /* - * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> + * <-- Copyright Giesecke & Devrient GmbH 2012-2012 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,4 +26,4 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define MOBICORE_COMPONENT_BUILD_TAG \ - "*** Build by haenellu@n500956-ubuntu, svn@r19078 ###" + "*** GC_MSM8960_Release_V013 ###" diff --git a/drivers/gud/mobicore_driver/debug.h b/drivers/gud/mobicore_driver/debug.h new file mode 100644 index 00000000000..f16660589aa --- /dev/null +++ b/drivers/gud/mobicore_driver/debug.h @@ -0,0 +1,65 @@ +/* + * MobiCore driver module.(interface to the secure world SWD) + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MC_DEBUG_H_ +#define _MC_DEBUG_H_ +/* Found in main.c */ +extern struct device *mcd; + +#define MCDRV_DBG_ERROR(dev, txt, ...) \ + dev_err(dev, "[%d] %s() ### ERROR: " txt, \ + task_pid_vnr(current), \ + __func__, \ + ##__VA_ARGS__) + +/* dummy function helper macro. */ +#define DUMMY_FUNCTION() do {} while (0) + +#if defined(DEBUG) + +/* #define DEBUG_VERBOSE */ +#if defined(DEBUG_VERBOSE) +#define MCDRV_DBG_VERBOSE MCDRV_DBG +#else +#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() +#endif + +#define MCDRV_DBG(dev, txt, ...) \ + dev_info(dev, "[%d on CPU%d] %s(): " txt, \ + task_pid_vnr(current), \ + raw_smp_processor_id(), \ + __func__, \ + ##__VA_ARGS__) + +#define MCDRV_DBG_WARN(dev, txt, ...) \ + dev_warn(dev, "[%d] %s() WARNING: " txt, \ + task_pid_vnr(current), \ + __func__, \ + ##__VA_ARGS__) + +#define MCDRV_ASSERT(cond) \ + do { \ + if (unlikely(!(cond))) { \ + panic("Assertion failed: %s:%d\n", \ + __FILE__, __LINE__); \ + } \ + } while (0) + +#else + +#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() +#define MCDRV_DBG(...) DUMMY_FUNCTION() +#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION() + +#define MCDRV_ASSERT(...) DUMMY_FUNCTION() + +#endif /* [not] defined(DEBUG) */ + +#endif /* _MC_DEBUG_H_ */ diff --git a/drivers/gud/mobicore_driver/fastcall.h b/drivers/gud/mobicore_driver/fastcall.h new file mode 100644 index 00000000000..9f360c15803 --- /dev/null +++ b/drivers/gud/mobicore_driver/fastcall.h @@ -0,0 +1,157 @@ +/* + * Header file of MobiCore Driver Kernel Module. + * + * MobiCore Fast Call interface + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MC_FASTCALL_H_ +#define _MC_FASTCALL_H_ + +#include "debug.h" + +/* + * MobiCore SMCs + */ +#define MC_SMC_N_YIELD 0x3 /* Yield to switch from NWd to SWd. */ +#define MC_SMC_N_SIQ 0x4 /* SIQ to switch from NWd to SWd. */ + +/* + * MobiCore fast calls. See MCI documentation + */ +#define MC_FC_INIT -1 +#define MC_FC_INFO -2 +#define MC_FC_POWER -3 +#define MC_FC_DUMP -4 +#define MC_FC_NWD_TRACE -31 /* Mem trace setup fastcall */ + + +/* + * return code for fast calls + */ +#define MC_FC_RET_OK 0 +#define MC_FC_RET_ERR_INVALID 1 +#define MC_FC_RET_ERR_ALREADY_INITIALIZED 5 + + +/* structure wrappers for specific fastcalls */ + +/* generic fast call parameters */ +union fc_generic { + struct { + uint32_t cmd; + uint32_t param[3]; + } as_in; + struct { + uint32_t resp; + uint32_t ret; + uint32_t param[2]; + } as_out; +}; + +/* fast call init */ +union mc_fc_init { + union fc_generic as_generic; + struct { + uint32_t cmd; + uint32_t base; + uint32_t nq_info; + uint32_t mcp_info; + } as_in; + struct { + uint32_t resp; + uint32_t ret; + uint32_t rfu[2]; + } as_out; +}; + +/* fast call info parameters */ +union mc_fc_info { + union fc_generic as_generic; + struct { + uint32_t cmd; + uint32_t ext_info_id; + uint32_t rfu[2]; + } as_in; + struct { + uint32_t resp; + uint32_t ret; + uint32_t state; + uint32_t ext_info; + } as_out; +}; + +/* + * _smc() - fast call to MobiCore + * + * @data: pointer to fast call data + */ +static inline long _smc(void *data) +{ + union fc_generic fc_generic; + memcpy(&fc_generic, data, sizeof(union fc_generic)); + if (data == NULL) + return -EPERM; +#ifdef MC_SMC_FASTCALL + { + int ret = 0; + ret = smc_fastcall(data, sizeof(union fc_generic)); + } +#else + { + /* SVC expect values in r0-r3 */ + register u32 reg0 __asm__("r0") = fc_generic.as_in.cmd; + register u32 reg1 __asm__("r1") = fc_generic.as_in.param[0]; + register u32 reg2 __asm__("r2") = fc_generic.as_in.param[1]; + register u32 reg3 __asm__("r3") = fc_generic.as_in.param[2]; + + __asm__ volatile ( +#ifdef MC_ARCH_EXTENSION_SEC + /* This pseudo op is supported and required from + * binutils 2.21 on */ + ".arch_extension sec\n" +#endif + "smc 0\n" + : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3) + ); + + /* set response */ + fc_generic.as_out.resp = reg0; + fc_generic.as_out.ret = reg1; + fc_generic.as_out.param[0] = reg2; + fc_generic.as_out.param[1] = reg3; + memcpy(data, &fc_generic, sizeof(union fc_generic)); + } +#endif + return 0; +} + +/* + * convert fast call return code to linux driver module error code + */ +static inline int convert_fc_ret(uint32_t sret) +{ + int ret = -EFAULT; + + switch (sret) { + case MC_FC_RET_OK: + ret = 0; + break; + case MC_FC_RET_ERR_INVALID: + ret = -EINVAL; + break; + case MC_FC_RET_ERR_ALREADY_INITIALIZED: + ret = -EBUSY; + break; + default: + break; + } + return ret; +} + +#endif /* _MC_FASTCALL_H_ */ diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/mobicore_driver/logging.c index a1da6e2bcbf..089b91cf2bc 100644 --- a/drivers/gud/mobicore_driver/logging.c +++ b/drivers/gud/mobicore_driver/logging.c @@ -1,7 +1,7 @@ /* * MobiCore Driver Logging Subsystem. * - * The logging subsytem provides the interface between the Mobicore trace + * The logging subsystem provides the interface between the Mobicore trace * buffer and the Linux log * * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> @@ -17,10 +17,12 @@ #include #include -#include "mc_drv_module.h" -#include "mc_drv_module_fastcalls.h" +#include "main.h" +#include "debug.h" +#include "ops.h" +#include "logging.h" -/* Default len of the log ring buffer 256KB*/ +/* Default length of the log ring buffer 256KB*/ #define LOG_BUF_SIZE (64 * PAGE_SIZE) /* Max Len of a log line for printing */ @@ -29,7 +31,7 @@ static uint32_t log_size = LOG_BUF_SIZE; module_param(log_size, uint, 0); -MODULE_PARM_DESC(log_size, " Size of the log ringbuffer (or 256KB default)."); +MODULE_PARM_DESC(log_size, "Size of the MobiCore log ringbuffer(256KB def)"); /* Definitions for log version 2 */ #define LOG_TYPE_MASK (0x0007) @@ -53,7 +55,7 @@ static uint32_t log_pos; /* MobiCore log previous position */ static struct mc_trace_buf *log_buf; /* MobiCore log buffer structure */ struct task_struct *log_thread; /* Log Thread task structure */ static char *log_line; /* Log Line buffer */ -static uint32_t log_line_len; /* Log Line buffer current len */ +static uint32_t log_line_len; /* Log Line buffer current length */ static void log_eol(void) { @@ -196,6 +198,7 @@ static uint32_t process_v2log(void) return buff - log_buf->buff; } +/* log_worker() - Worker thread processing the log_buf buffer. */ static int log_worker(void *p) { if (log_buf == NULL) @@ -214,8 +217,6 @@ static int log_worker(void *p) break; default: MCDRV_DBG_ERROR(mcd, "Unknown Mobicore log data"); - MCDRV_DBG_ERROR(mcd, "version %d logging disabled.", - log_buf->version); log_pos = log_buf->write_pos; /* * Stop the thread as we have no idea what @@ -229,7 +230,7 @@ static int log_worker(void *p) } /* - * Wakeup the log reader thread + * Wake up the log reader thread * This should be called from the places where calls into MobiCore have * generated some logs(eg, yield, SIQ...) */ @@ -245,10 +246,11 @@ void mobicore_log_read(void) * Setup MobiCore kernel log. It assumes it's running on CORE 0! * The fastcall will complain is that is not the case! */ -long mobicore_log_setup(void *data) +long mobicore_log_setup(void) { unsigned long phys_log_buf; union fc_generic fc_log; + struct sched_param param = { .sched_priority = 1 }; long ret; log_pos = 0; @@ -276,6 +278,7 @@ long mobicore_log_setup(void *data) goto mobicore_log_setup_log_line; } + sched_setscheduler(log_thread, SCHED_IDLE, ¶m); /* * We are going to map this buffer into virtual address space in SWd. * To reduce complexity there, we use a contiguous buffer. @@ -321,7 +324,7 @@ long mobicore_log_setup(void *data) } /* - * Free kernel log componenets. + * Free kernel log components. * ATTN: We can't free the log buffer because it's also in use by MobiCore and * even if the module is unloaded MobiCore is still running. */ diff --git a/drivers/gud/mobicore_driver/logging.h b/drivers/gud/mobicore_driver/logging.h new file mode 100644 index 00000000000..ec7587f8441 --- /dev/null +++ b/drivers/gud/mobicore_driver/logging.h @@ -0,0 +1,27 @@ +/* + * MobiCore driver module.(interface to the secure world SWD) + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MC_LOGGING_H_ +#define _MC_LOGGING_H_ + +/* MobiCore internal trace buffer structure. */ +struct mc_trace_buf { + uint32_t version; /* version of trace buffer */ + uint32_t length; /* length of allocated buffer(includes header) */ + uint32_t write_pos; /* last write position */ + char buff[1]; /* start of the log buffer */ +}; + +/* MobiCore internal trace log setup. */ +void mobicore_log_read(void); +long mobicore_log_setup(void); +void mobicore_log_free(void); + +#endif /* _MC_LOGGING_H_ */ diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c index bc47d8e3599..1a745b3e226 100644 --- a/drivers/gud/mobicore_driver/main.c +++ b/drivers/gud/mobicore_driver/main.c @@ -1,14 +1,14 @@ /* * MobiCore Driver Kernel Module. * - * This module is written as a Linux device driver. * This driver represents the command proxy on the lowest layer, from the * secure world to the non secure world, and vice versa. - * This driver is located in the non secure world (Linux). + * This driver offers IOCTL commands, for access to the secure world, and has * the interface from the secure world to the normal world. * The access to the driver is possible with a file descriptor, - * which has to be created by the fd = open(/dev/mobicore) command. + * which has to be created by the fd = open(/dev/mobicore) command or + * fd = open(/dev/mobicore-user) * * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> * @@ -21,17 +21,22 @@ #include #include #include -#include #include #include +#include +#include +#include +#include -#include "mc_drv_module.h" -#include "mc_drv_module_android.h" -#include "mc_drv_module_fastcalls.h" -#include "public/mc_kernel_api.h" +#include "main.h" +#include "fastcall.h" -/* Initial value for the daemon sempahore signaling */ -#define DAEMON_SEM_VAL 0 +#include "arm.h" +#include "mem.h" +#include "ops.h" +#include "pm.h" +#include "debug.h" +#include "logging.h" /* Define a MobiCore device structure for use with dev_debug() etc */ struct device_driver mcd_debug_name = { @@ -46,1573 +51,723 @@ struct device mcd_debug_subname = { struct device *mcd = &mcd_debug_subname; /* MobiCore interrupt context data */ -static struct mc_drv_kmod_ctx mc_drv_kmod_ctx; - -/* MobiCore MCI information */ -static uint32_t mci_base; - -/* - * ############################################################################# - * ## - * ## Convenience functions for Linux API functions - * ## - * ############################################################################# - */ -static int goto_cpu0(void); -static int goto_all_cpu(void) __attribute__ ((unused)); +struct mc_context ctx; -static void init_and_add_to_list(struct list_head *item, - struct list_head *list_head) +/* Get process context from file pointer */ +static struct mc_instance *get_instance(struct file *file) { - INIT_LIST_HEAD(item); - - list_add(item, list_head); + return (struct mc_instance *)(file->private_data); } -/* - * check if CPU supports the ARM TrustZone Security Extensions - */ -static bool has_security_extensions(void) +/* Get a unique ID */ +unsigned int get_unique_id(void) { - u32 fea = 0; - - asm volatile( - "mrc p15, 0, %[fea], cr0, cr1, 0" : - [fea]"=r" (fea)); - - MCDRV_DBG_VERBOSE(mcd, "CPU Features: 0x%X", fea); + return (unsigned int)atomic_inc_return(&ctx.unique_counter); +} - /* - * If the CPU features ID has 0 for security features then the CPU - * doesn't support TrustZone at all! - */ - if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0) - return false; +/* Clears the reserved bit of each page and frees the pages */ +static inline void free_continguous_pages(void *addr, unsigned int order) +{ + int i; + struct page *page = virt_to_page(addr); + for (i = 0; i < (1<handle == 0) + return -EINVAL; - asm volatile( - "mrc p15, 0, %[nsacr], cr1, cr1, 2\n" - "mrs %[cpsr], cpsr\n" : - [nsacr]"=r" (nsacr), - [cpsr]"=r"(cpsr)); + if (buffer->addr == 0) + return -EINVAL; - MCDRV_DBG_VERBOSE(mcd, "CPRS.M = set to 0x%X\n", cpsr & MODE_MASK); - MCDRV_DBG_VERBOSE(mcd, "SCR.NS = set to 0x%X\n", nsacr); + if (!atomic_dec_and_test(&buffer->usage)) { - /* - * If the NSACR contains the reset value(=0) then most likely we are - * running in Secure MODE. - * If the cpsr mode is set to monitor mode then we cannot load! - */ - if (nsacr == 0 || ((cpsr & MODE_MASK) == ARM_MONITOR_MODE)) - return true; + MCDRV_DBG_VERBOSE(mcd, "Could not free buffer h=%u", + buffer->handle); + return 0; + } - return false; -} + MCDRV_DBG(mcd, "handle=%u phys_addr=0x%p, virt_addr=0x%p\n", + buffer->handle, buffer->phys, buffer->addr); -/* - * check if userland caller is privileged (aka has "root" access rights). - * return int 1 or 0 - */ -static int is_userland_caller_privileged(void) -{ - /* - * For some platforms we cannot run the Daemon as root - for Android - * compliance tests it is not allowed, thus we assume the daemon is ran - * as the system user. - * In Android the system user for daemons has no particular capabilities - * other than a fixed UID: AID_SYSTEM 1000 - * The actual number is guaranteed to be the same in all Android systems - * so we will take it for granted: see android_filesystem_config.h in - * the Android source tree for all UIDs and their meaning: - * http://android-dls.com/wiki/index.php?title=Android_UIDs_and_GIDs - */ -#if defined(CONFIG_ANDROID) && defined(MC_ANDROID_UID_CHECK) - return current_euid() <= AID_SYSTEM; -#else - /* - * capable should cover all possibilities, root or sudo, uid checking - * was not very reliable - */ - return capable(CAP_SYS_ADMIN); -#endif -} + list_del(&buffer->list); -static void unlock_page_from_used_l2_table(struct page *page) -{ - SetPageDirty(page); - ClearPageReserved(page); - put_page(page); + free_continguous_pages(buffer->addr, buffer->order); + kfree(buffer); + return 0; } -/* convert L2 PTE to page pointer */ -static struct page *l2_pte_to_page(pte_t pte) +static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle, + uint32_t *phys, uint32_t *len) { - void *phys_page_addr = (void *)((unsigned int)pte & PAGE_MASK); - unsigned int pfn = (unsigned int)phys_page_addr >> PAGE_SHIFT; - struct page *page = pfn_to_page(pfn); + int ret = 0; + struct mc_buffer *buffer; - return page; -} + if (WARN(!instance, "No instance data available")) + return -EFAULT; -/* convert page pointer to L2 PTE */ -static pte_t page_to_l2_pte(struct page *page) -{ - unsigned int pfn = page_to_pfn(page); - void *phys_addr = (void *)(pfn << PAGE_SHIFT); - pte_t pte = (pte_t)((unsigned int)phys_addr & PAGE_MASK); + if (WARN_ON(!is_daemon(instance))) { + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); + return -EPERM; + } - return pte; -} + mutex_lock(&instance->lock); -static inline int lock_user_pages(struct task_struct *task, - void *virt_start_page_addr, int nr_of_pages, - struct page **pages) -{ - int ret = 0; - int locked_pages = 0; - unsigned int i; - - do { - /* lock user pages, must hold the mmap_sem to do this. */ - down_read(&(task->mm->mmap_sem)); - locked_pages = - get_user_pages(task, - task->mm, - (unsigned long)virt_start_page_addr, - nr_of_pages, - 1, - 0, - pages, - NULL); - up_read(&(task->mm->mmap_sem)); - - /* check if we could lock all pages. */ - if (locked_pages != nr_of_pages) { - MCDRV_DBG_ERROR(mcd, - "get_user_pages() err, locked_pages=%d", - locked_pages); - ret = -ENOMEM; - if (locked_pages < 0) { - ret = locked_pages; - locked_pages = 0; - } - break; - } + mutex_lock(&ctx.bufs_lock); - /* do cache maintenance on locked pages. */ - for (i = 0; i < nr_of_pages; i++) - flush_dcache_page(pages[i]); + /* search for the given handle in the buffers list */ + list_for_each_entry(buffer, &ctx.cont_bufs, list) { + if (buffer->handle == handle) { + *phys = (uint32_t)buffer->phys; + *len = buffer->len; + goto found; + } + } - } while (0); + /* Couldn't find the buffer */ + ret = -EINVAL; - if (ret != 0) { - /* release all locked pages. */ - MCDRV_ASSERT(locked_pages >= 0); - for (i = 0; i < locked_pages; i++) - put_page(pages[i]); - } +found: + mutex_unlock(&ctx.bufs_lock); + mutex_unlock(&instance->lock); return ret; - } /* - * ############################################################################# - * ## - * ## Driver implementation functions - * ## - * ############################################################################# + * __free_buffer - Free a WSM buffer allocated with mobicore_allocate_wsm + * + * @instance + * @handle handle of the buffer + * + * Returns 0 if no error + * */ - -/* check if caller is MobiCore Daemon */ -static unsigned int is_caller_mc_daemon(struct mc_instance *instance) -{ - return ((instance != NULL) && - (mc_drv_kmod_ctx.daemon_inst == instance)); -} - -/* Get process context from file pointer */ -static struct mc_instance *get_instance(struct file *file) +static int __free_buffer(struct mc_instance *instance, uint32_t handle) { - MCDRV_ASSERT(file != NULL); - - return (struct mc_instance *)(file->private_data); -} + int ret = 0; + struct mc_buffer *buffer; -/* Get a unique ID */ -static unsigned int get_mc_kmod_unique_id(void) -{ - return (unsigned int)atomic_inc_return( - &(mc_drv_kmod_ctx.unique_counter)); -} + if (WARN(!instance, "No instance data available")) + return -EFAULT; -/* Get kernel pointer to shared L2 table given a per-process reference */ -static struct l2table *get_l2_table_kernel_virt( - struct mc_used_l2_table *used_l2table) -{ - MCDRV_ASSERT(used_l2table != NULL); - MCDRV_ASSERT(used_l2table->set != NULL); - MCDRV_ASSERT(used_l2table->set->kernel_virt != NULL); - return &(used_l2table->set->kernel_virt->table[used_l2table->idx]); -} + mutex_lock(&ctx.bufs_lock); + /* search for the given handle in the buffers list */ + list_for_each_entry(buffer, &ctx.cont_bufs, list) { + if (buffer->handle == handle) + goto del_buffer; + } + ret = -EINVAL; + goto err; -/* Get physical address of a shared L2 table given a per-process reference */ -static struct l2table *get_l2_table_phys(struct mc_used_l2_table *used_l2table) -{ - MCDRV_ASSERT(used_l2table != NULL); - MCDRV_ASSERT(used_l2table->set != NULL); - MCDRV_ASSERT(used_l2table->set->phys != NULL); - return &(used_l2table->set->phys->table[used_l2table->idx]); +del_buffer: + ret = free_buffer(buffer); +err: + mutex_unlock(&ctx.bufs_lock); + return ret; } -static unsigned int is_in_use_used_l2_table( - struct mc_used_l2_table *used_l2table) +int mc_free_buffer(struct mc_instance *instance, uint32_t handle) { - return ((used_l2table->flags & - (MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP | - MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC)) != 0); -} + int ret = 0; -static struct mc_used_l2_table *find_used_l2_table_by_handle( - unsigned int handle) -{ - struct mc_used_l2_table *used_l2table; - struct mc_used_l2_table *used_l2table_with_handle = NULL; + if (WARN(!instance, "No instance data available")) + return -EFAULT; - list_for_each_entry(used_l2table, - &(mc_drv_kmod_ctx.mc_used_l2_tables), list) { - if (handle == used_l2table->handle) { - used_l2table_with_handle = used_l2table; - break; - } - } + mutex_lock(&instance->lock); - return used_l2table_with_handle; + ret = __free_buffer(instance, handle); + mutex_unlock(&instance->lock); + return ret; } -/* - * ############################################################################# - * ## - * ## L2 Table Pool - * ## - * ############################################################################# - */ -static struct mc_used_l2_table *allocate_used_l2_table( - struct mc_instance *instance) + +int mc_get_buffer(struct mc_instance *instance, + struct mc_buffer **buffer, unsigned long len) { + struct mc_buffer *cbuffer = NULL; + void *addr = 0; + void *phys = 0; + unsigned int order; + unsigned long allocated_size; int ret = 0; - struct mc_l2_table_store *l2table_store = NULL; - struct mc_l2_tables_set *l2table_set = NULL; - struct mc_used_l2_table *used_l2table = NULL; - struct page *page; - unsigned int i = 0; - - do { - /* allocate a WSM L2 descriptor */ - used_l2table = kmalloc(sizeof(*used_l2table), GFP_KERNEL); - if (used_l2table == NULL) { - ret = -ENOMEM; - MCDRV_DBG_ERROR(mcd, "out of memory\n"); - break; - } - /* clean */ - memset(used_l2table, 0, sizeof(*used_l2table)); - used_l2table->handle = get_mc_kmod_unique_id(); - used_l2table->owner = instance; - - /* add to global list. */ - init_and_add_to_list(&(used_l2table->list), - &(mc_drv_kmod_ctx.mc_used_l2_tables)); - - /* walk though list to find free set. */ - list_for_each_entry(l2table_set, - &(mc_drv_kmod_ctx.mc_l2_tables_sets), - list) { - for (i = 0; i < MC_DRV_KMOD_L2_TABLE_PER_PAGES; i++) { - if ((l2table_set->usage_bitmap & (1U << i)) - == 0) { - /* - * found a set, - * l2table_set and i are set. - */ - l2table_store = - l2table_set->kernel_virt; - break; - } - } - if (l2table_store != NULL) - break; - } /* end list_for_each_entry() */ - - if (l2table_store == NULL) { - l2table_store = (struct mc_l2_table_store *) - get_zeroed_page(GFP_KERNEL); - if (l2table_store == NULL) { - ret = -ENOMEM; - break; - } - /* - * Actually, locking is not necessary, because kernel - * memory is not supposed to get swapped out. But we - * play safe.... - */ - page = virt_to_page(l2table_store); - SetPageReserved(page); - - /* allocate a descriptor */ - l2table_set = kmalloc(sizeof(*l2table_set), GFP_KERNEL); - if (l2table_set == NULL) { - kfree(l2table_store); - ret = -ENOMEM; - break; - } - /* initialize */ - memset(l2table_set, 0, sizeof(*l2table_set)); + if (WARN(!instance, "No instance data available")) + return -EFAULT; - l2table_set->kernel_virt = l2table_store; - l2table_set->page = page; - l2table_set->phys = (void *)virt_to_phys(l2table_store); + if (len == 0) { + MCDRV_DBG_WARN(mcd, "cannot allocate size 0\n"); + return -ENOMEM; + } - /* init add to list. */ - init_and_add_to_list( - &(l2table_set->list), - &(mc_drv_kmod_ctx.mc_l2_tables_sets)); + order = get_order(len); + if (order > MAX_ORDER) { + MCDRV_DBG_WARN(mcd, "Buffer size too large\n"); + return -ENOMEM; + } + allocated_size = (1 << order) * PAGE_SIZE; - /* use first table */ - i = 0; - } + if (mutex_lock_interruptible(&instance->lock)) + return -ERESTARTSYS; - /* set set usage */ - l2table_set->usage_bitmap |= (1U << i); + /* allocate a new buffer. */ + cbuffer = kzalloc(sizeof(struct mc_buffer), GFP_KERNEL); - /* set set reference */ - used_l2table->set = l2table_set; - used_l2table->idx = i; + if (cbuffer == NULL) { + MCDRV_DBG_WARN(mcd, + "MMAP_WSM request: could not allocate buffer\n"); + ret = -ENOMEM; + goto unlock_instance; + } + mutex_lock(&ctx.bufs_lock); - MCDRV_DBG_VERBOSE(mcd, "chunkPhys=%p,idx=%d\n", - l2table_set->phys, i); + MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)\n", + len, order, allocated_size); - } while (0); + addr = (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order); - if (ret != 0 && used_l2table != NULL) { - list_del(&(l2table_set->list)); - kfree(used_l2table); - used_l2table = NULL; + if (addr == NULL) { + MCDRV_DBG_WARN(mcd, "get_free_pages failed\n"); + ret = -ENOMEM; + goto err; } + phys = (void *)virt_to_phys(addr); + cbuffer->handle = get_unique_id(); + cbuffer->phys = phys; + cbuffer->addr = addr; + cbuffer->order = order; + cbuffer->len = len; + cbuffer->instance = instance; + /* Refcount +1 because the TLC is requesting it */ + atomic_set(&cbuffer->usage, 1); + + INIT_LIST_HEAD(&cbuffer->list); + list_add(&cbuffer->list, &ctx.cont_bufs); - return used_l2table; + MCDRV_DBG(mcd, + "allocated phys=0x%p - 0x%p, size=%ld, kvirt=0x%p, h=%d\n", + phys, (void *)((unsigned int)phys+allocated_size), + allocated_size, addr, cbuffer->handle); + *buffer = cbuffer; + goto unlock; + +err: + kfree(cbuffer); +unlock: + mutex_unlock(&ctx.bufs_lock); +unlock_instance: + mutex_unlock(&instance->lock); + return ret; } -static void free_used_l2_table(struct mc_used_l2_table *used_l2table) +/* + * __lock_buffer() - Locks a contiguous buffer - +1 refcount. + * Assumes the instance lock is already taken! + */ +static int __lock_buffer(struct mc_instance *instance, uint32_t handle) { - struct mc_l2_tables_set *l2table_set; - unsigned int idx; - - MCDRV_ASSERT(used_l2table != NULL); + int ret = 0; + struct mc_buffer *buffer; - l2table_set = used_l2table->set; - MCDRV_ASSERT(l2table_set != NULL); + if (WARN(!instance, "No instance data available")) + return -EFAULT; - /* clean usage flag */ - idx = used_l2table->idx; - MCDRV_ASSERT(idx < MC_DRV_KMOD_L2_TABLE_PER_PAGES); - l2table_set->usage_bitmap &= ~(1U << idx); + if (WARN_ON(!is_daemon(instance))) { + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); + return -EPERM; + } - /* if nobody uses this set, we can release it. */ - if (l2table_set->usage_bitmap == 0) { - MCDRV_ASSERT(l2table_set->page != NULL); - ClearPageReserved(l2table_set->page); + mutex_lock(&ctx.bufs_lock); + /* search for the given handle in the buffers list */ + list_for_each_entry(buffer, &ctx.cont_bufs, list) { + if (buffer->handle == handle) { + atomic_inc(&buffer->usage); + goto unlock; + } + } + ret = -EINVAL; - MCDRV_ASSERT(l2table_set->kernel_virt != NULL); - free_page((unsigned long)l2table_set->kernel_virt); +unlock: + mutex_unlock(&ctx.bufs_lock); + return ret; +} - list_del(&(l2table_set->list)); - kfree(l2table_set); +void *get_mci_base_phys(unsigned int len) +{ + if (ctx.mci_base.phys) { + return ctx.mci_base.phys; + } else { + unsigned int order = get_order(len); + ctx.mcp = NULL; + ctx.mci_base.order = order; + ctx.mci_base.addr = + (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order); + if (ctx.mci_base.addr == NULL) { + MCDRV_DBG_WARN(mcd, "get_free_pages failed\n"); + memset(&ctx.mci_base, 0, sizeof(ctx.mci_base)); + return NULL; + } + ctx.mci_base.phys = (void *)virt_to_phys(ctx.mci_base.addr); + return ctx.mci_base.phys; } - - return; } /* - * Create a L2 table in a WSM container that has been allocates previously. - * - * task pointer to task owning WSM - * wsm_buffer user space WSM start - * wsm_len WSM length - * used_l2table Pointer to L2 table details + * Create a l2 table from a virtual memory buffer which can be vmalloc + * or user space virtual memory */ -static int map_buffer_into_used_l2_table(struct task_struct *task, - void *wsm_buffer, unsigned int wsm_len, - struct mc_used_l2_table *used_l2table) +int mc_register_wsm_l2(struct mc_instance *instance, + uint32_t buffer, uint32_t len, + uint32_t *handle, uint32_t *phys) { int ret = 0; - unsigned int i, nr_of_pages; - struct page *page; - struct l2table *l2table; - struct page **l2table_as_array_of_pointers_to_page; - void *virt_addr_page; /* start addr of the 4 KiB page of wsm_buffer */ - unsigned int offset; /* page offset in wsm buffer */ - - /* task can be null when called from kernel space */ - MCDRV_ASSERT(wsm_buffer != NULL); - MCDRV_ASSERT(wsm_len != 0); - MCDRV_ASSERT(used_l2table != NULL); + struct mc_l2_table *table = NULL; + struct task_struct *task = current; - MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x\n", - wsm_buffer, wsm_len); + if (WARN(!instance, "No instance data available")) + return -EFAULT; - /* - * Check if called from kernel space wsm_buffer is actually - * vmalloced or not - */ - if (task == NULL && !is_vmalloc_addr(wsm_buffer)) { - MCDRV_DBG_ERROR(mcd, "WSM addr is not a vmalloc address"); + if (len == 0) { + MCDRV_DBG_ERROR(mcd, "len=0 is not supported!\n"); return -EINVAL; } - l2table = get_l2_table_kernel_virt(used_l2table); - /* - * We use the memory for the L2 table to hold the pointer - * and convert them later. This works, as everything comes - * down to a 32 bit value. - */ - l2table_as_array_of_pointers_to_page = (struct page **)l2table; - - do { + table = mc_alloc_l2_table(instance, task, (void *)buffer, len); - /* no size > 1Mib supported */ - if (wsm_len > SZ_1M) { - MCDRV_DBG_ERROR(mcd, "size > 1 MiB\n"); - ret = -EINVAL; - break; - } + if (IS_ERR(table)) { + MCDRV_DBG_ERROR(mcd, "new_used_l2_table() failed\n"); + return -EINVAL; + } - /* calculate page usage */ - virt_addr_page = (void *) - (((unsigned long)(wsm_buffer)) & PAGE_MASK); - offset = (unsigned int) - (((unsigned long)(wsm_buffer)) & (~PAGE_MASK)); - nr_of_pages = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE; - - MCDRV_DBG_VERBOSE(mcd, "virt addr page start=0x%p, pages=%d\n", - virt_addr_page, - nr_of_pages); - - /* L2 table can hold max 1MiB in 256 pages. */ - if ((nr_of_pages*PAGE_SIZE) > SZ_1M) { - MCDRV_DBG_ERROR(mcd, "WSM paged exceed 1 MiB\n"); - ret = -EINVAL; - break; - } + /* set response */ + *handle = table->handle; + /* WARNING: daemon shouldn't know this either, but live with it */ + if (is_daemon(instance)) + *phys = (uint32_t)table->phys; + else + *phys = 0; - /* Request comes from user space */ - if (task != NULL) { - /* - * lock user page in memory, so they do not get swapped - * out. - * REV axh: - * Kernel 2.6.27 added a new get_user_pages_fast() - * function, maybe it is called fast_gup() in some - * versions. - * handle user process doing a fork(). - * Child should not get things. - * http://osdir.com/ml/linux-media/2009-07/msg00813.html - * http://lwn.net/Articles/275808/ - */ - - ret = lock_user_pages( - task, - virt_addr_page, - nr_of_pages, - l2table_as_array_of_pointers_to_page); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, - "lock_user_pages() failed\n"); - break; - } - } - /* Request comes from kernel space(vmalloc buffer) */ - else { - void *uaddr = wsm_buffer; - for (i = 0; i < nr_of_pages; i++) { - page = vmalloc_to_page(uaddr); - if (!page) { - MCDRV_DBG_ERROR(mcd, - "failed to map addr"); - ret = -EINVAL; - break; - } - get_page(page); - /* - * Lock the page in memory, it can't be swapped - * out - */ - SetPageReserved(page); - l2table_as_array_of_pointers_to_page[i] = page; - uaddr += PAGE_SIZE; - } - } + MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=%p\n", + *handle, (void *)*phys); - used_l2table->nr_of_pages = nr_of_pages; - used_l2table->flags |= MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP; + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - /* - * create L2 Table entries. - * used_l2table->table contains a list of page pointers here. - * For a proper cleanup we have to ensure that the following - * code either works and used_l2table contains a valid L2 table - * - or fails and used_l2table->table contains the list of page - * pointers. - * Any mixed contents will make cleanup difficult. - */ - for (i = 0; i < nr_of_pages; i++) { - pte_t pte; - page = l2table_as_array_of_pointers_to_page[i]; - - /* - * create L2 table entry, see ARM MMU docu for details - * about flags stored in the lowest 12 bits. - * As a side reference, the Article - * "ARM's multiply-mapped memory mess" - * found in the collection at - * http://lwn.net/Articles/409032/ - * is also worth reading. - */ - pte = page_to_l2_pte(page) - | PTE_EXT_AP1 | PTE_EXT_AP0 - | PTE_CACHEABLE | PTE_BUFFERABLE - | PTE_TYPE_SMALL | PTE_TYPE_EXT - /* - * Linux uses different mappings for SMP systems(the - * sharing flag is set for the pte. In order not to - * confuse things too much in Mobicore make sure the - * shared buffers have the same flags. - * This should also be done in SWD side - */ -#ifdef CONFIG_SMP - | PTE_EXT_SHARED | PTE_EXT_TEX(1) -#endif - ; + return ret; +} - l2table->table_entries[i] = pte; - MCDRV_DBG_VERBOSE(mcd, "L2 entry %d: 0x%08x\n", i, - (unsigned int)(pte)); - } +int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle) +{ + int ret = 0; - /* ensure rest of table is empty */ - while (i < 255) - l2table->table_entries[i++] = (pte_t)0; + if (WARN(!instance, "No instance data available")) + return -EFAULT; - } while (0); + /* free table (if no further locks exist) */ + mc_free_l2_table(instance, handle); return ret; } - -/* - * Remove a L2 table in a WSM container. Afterwards the container may be - * released. - * - * used_l2table Pointer to L2 table details - */ -static void unmap_buffers_from_used_l2_table( - struct mc_used_l2_table *used_l2table) +/* Lock the object from handle, it could be a WSM l2 table or a cont buffer! */ +static int mc_lock_handle(struct mc_instance *instance, uint32_t handle) { - unsigned int i; - struct l2table *l2table; - - MCDRV_ASSERT(used_l2table != NULL); - /* this should not happen, as we have no empty tables. */ - MCDRV_ASSERT(!is_in_use_used_l2_table(used_l2table)); - - /* found the table, now release the resources. */ - MCDRV_DBG_VERBOSE(mcd, "clear L2 table, phys_base=%p, nr_of_pages=%d\n", - get_l2_table_phys(used_l2table), - used_l2table->nr_of_pages); - - l2table = get_l2_table_kernel_virt(used_l2table); - - /* release all locked user space pages */ - for (i = 0; i < used_l2table->nr_of_pages; i++) { - /* convert physical entries from L2 table to page pointers */ - pte_t pte = get_l2_table_kernel_virt(used_l2table)-> - table_entries[i]; - struct page *page = l2_pte_to_page(pte); - unlock_page_from_used_l2_table(page); - } + int ret = 0; - /* remember that all pages have been freed */ - used_l2table->nr_of_pages = 0; + if (WARN(!instance, "No instance data available")) + return -EFAULT; - return; -} + if (WARN_ON(!is_daemon(instance))) { + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); + return -EPERM; + } -/* - * ############################################################################# - * ## - * ## Helper functions - * ## - * ############################################################################# - */ -#define FREE_FROM_SWD 1 -#define FREE_FROM_NWD 0 + mutex_lock(&instance->lock); + ret = mc_lock_l2_table(instance, handle); -/* Delete a used l2 table. */ -static void delete_used_l2_table(struct mc_used_l2_table *used_l2table, - unsigned int is_swd) -{ - if (is_swd) { - used_l2table->flags &= - ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC; - } else { - used_l2table->flags &= - ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP; - used_l2table->owner = NULL; + /* Handle was not a l2 table but a cont buffer */ + if (ret == -EINVAL) { + /* Call the non locking variant! */ + ret = __lock_buffer(instance, handle); } - /* release if Nwd and Swd/MC do no longer use it. */ - if (is_in_use_used_l2_table(used_l2table)) { - MCDRV_DBG_WARN(mcd, - "WSM L2 table still in use: %p, nr_of_pages=%d", - get_l2_table_phys(used_l2table), - used_l2table->nr_of_pages); - } else { - unmap_buffers_from_used_l2_table(used_l2table); - free_used_l2_table(used_l2table); + mutex_unlock(&instance->lock); - list_del(&(used_l2table->list)); - kfree(used_l2table); - } - return; + return ret; } -/* - * Allocate L2 table and map buffer into it. - * That is, create respective table entries. - * Must hold Semaphore mc_drv_kmod_ctx.wsm_l2_sem - */ -static struct mc_used_l2_table *new_used_l2_table(struct mc_instance *instance, - struct task_struct *task, - void *wsm_buffer, - unsigned int wsm_len) +static int mc_unlock_handle(struct mc_instance *instance, uint32_t handle) { int ret = 0; - struct mc_used_l2_table *used_l2table; - do { - used_l2table = allocate_used_l2_table(instance); - if (used_l2table == NULL) { - MCDRV_DBG_ERROR(mcd, - "allocate_used_l2_table() failed\n"); - break; - } + if (WARN(!instance, "No instance data available")) + return -EFAULT; - /* create the L2 page for the WSM */ - ret = map_buffer_into_used_l2_table(task, - wsm_buffer, - wsm_len, - used_l2table); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, - "map_buffer_into_used_l2_table() err"); - delete_used_l2_table(used_l2table, FREE_FROM_NWD); - used_l2table = NULL; - break; - } + if (WARN_ON(!is_daemon(instance))) { + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); + return -EPERM; + } - } while (0); + mutex_lock(&instance->lock); + ret = mc_free_l2_table(instance, handle); - return used_l2table; -} + /* Not a l2 table, then it must be a buffer */ + if (ret == -EINVAL) { + /* Call the non locking variant! */ + ret = __free_buffer(instance, handle); + } + mutex_unlock(&instance->lock); -/* - * ############################################################################# - * ## - * ## IoCtl handler - * ## - * ############################################################################# - */ + return ret; +} -int mobicore_map_vmem(struct mc_instance *instance, void *addr, uint32_t len, - uint32_t *handle, void **phys_wsm_l2_table) +static uint32_t mc_find_wsm_l2(struct mc_instance *instance, uint32_t handle) { - int ret = 0; - struct mc_used_l2_table *used_l2table = NULL; - MCDRV_ASSERT(instance != NULL); - - MCDRV_DBG_VERBOSE(mcd, "enter\n"); + uint32_t ret = 0; - do { - if (len == 0) { - MCDRV_DBG_ERROR(mcd, "len=0 is not supported!\n"); - ret = -EINVAL; - break; - } - - /* try to get the semaphore */ - ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, - "down_interruptible() failed with %d\n", - ret); - ret = -ERESTARTSYS; - break; - } + if (WARN(!instance, "No instance data available")) + return 0; - do { - used_l2table = new_used_l2_table(instance, - NULL, - addr, - len); - - if (used_l2table == NULL) { - MCDRV_DBG_ERROR(mcd, - "new_used_l2_table() failed\n"); - ret = -EINVAL; - break; - } + if (WARN_ON(!is_daemon(instance))) { + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); + return 0; + } - /* set response */ - *handle = used_l2table->handle; - *phys_wsm_l2_table = - (void *)get_l2_table_phys(used_l2table); - MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=%p\n", - *handle, - (void *)(*phys_wsm_l2_table)); + mutex_lock(&instance->lock); + ret = mc_find_l2_table(instance, handle); + mutex_unlock(&instance->lock); - } while (0); + return ret; +} - /* release semaphore */ - up(&(mc_drv_kmod_ctx.wsm_l2_sem)); +static int mc_clean_wsm_l2(struct mc_instance *instance) +{ + if (WARN(!instance, "No instance data available")) + return -EFAULT; - } while (0); + if (WARN_ON(!is_daemon(instance))) { + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); + return -EPERM; + } - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); + mc_clean_l2_tables(); - return ret; + return 0; } -EXPORT_SYMBOL(mobicore_map_vmem); -static int handle_ioctl_app_register_wsm_l2( - struct mc_instance *instance, - union mc_ioctl_app_reg_wsm_l2_params *user_params) +static int mc_fd_mmap(struct file *file, struct vm_area_struct *vmarea) { + struct mc_instance *instance = get_instance(file); + unsigned long len = vmarea->vm_end - vmarea->vm_start; + void *paddr = (void *)(vmarea->vm_pgoff << PAGE_SHIFT); + unsigned int pfn; + struct mc_buffer *buffer = 0; int ret = 0; - union mc_ioctl_app_reg_wsm_l2_params params; - struct mc_used_l2_table *used_l2table = NULL; - struct pid *pid_struct = NULL; - struct task_struct *task = current; - void *phys_wsm_l2_table; - MCDRV_ASSERT(instance != NULL); - - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - - do { - /* get user parameters */ - ret = copy_from_user(&(params.in), &(user_params->in), - sizeof(params.in)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_from_user() failed\n"); - break; - } + MCDRV_DBG(mcd, "enter (vma start=0x%p, size=%ld, mci=%p)\n", + (void *)vmarea->vm_start, len, ctx.mci_base.phys); - /* daemon can do this for another task. */ - if (params.in.pid != 0) { - MCDRV_DBG_ERROR(mcd, "pid != 0 unsupported\n"); - ret = -EINVAL; - break; - } - if (params.in.len == 0) { - MCDRV_DBG_ERROR(mcd, "len=0 is not supported!\n"); - ret = -EINVAL; - break; - } + if (WARN(!instance, "No instance data available")) + return -EFAULT; - /* try to get the semaphore */ - ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, - "down_interruptible() failed with %d\n", - ret); - ret = -ERESTARTSYS; - break; + if (len == 0) { + MCDRV_DBG_ERROR(mcd, "cannot allocate size 0\n"); + return -ENOMEM; + } + if (paddr) { + mutex_lock(&ctx.bufs_lock); + + /* search for the buffer list. */ + list_for_each_entry(buffer, &ctx.cont_bufs, list) { + if (buffer->phys == paddr) + goto found; + else + break; } + /* Nothing found return */ + mutex_unlock(&ctx.bufs_lock); + return -EINVAL; - do { - used_l2table = new_used_l2_table( - instance, - task, - (void *)(params.in.buffer), - params.in.len); - - if (used_l2table == NULL) { - MCDRV_DBG_ERROR(mcd, - "new_used_l2_table() failed\n"); - ret = -EINVAL; - break; - } - - /* if the daemon does this, we set the MC lock */ - if (is_caller_mc_daemon(instance)) - used_l2table->flags |= - MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC; - - /* set response */ - memset(¶ms.out, 0, sizeof(params.out)); - params.out.handle = used_l2table->handle; - - params.out.phys_wsm_l2_table = - (uint32_t)get_l2_table_phys(used_l2table); - - phys_wsm_l2_table = - (void *)(params.out.phys_wsm_l2_table); - - MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=%p\n", - params.out.handle, - phys_wsm_l2_table); - - /* copy L2Table to user space */ - ret = copy_to_user(&(user_params->out), - &(params.out), - sizeof(params.out)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_to_user() failed\n"); - - /* - * free the table again, - * app does not know anything about it. - */ - if (is_caller_mc_daemon(instance)) { - used_l2table->flags &= - ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC; - } - delete_used_l2_table(used_l2table, - FREE_FROM_NWD); - used_l2table = NULL; - break; - } - - } while (0); - - /* release semaphore */ - up(&(mc_drv_kmod_ctx.wsm_l2_sem)); +found: + vmarea->vm_flags |= VM_RESERVED; + /* + * Convert kernel address to user address. Kernel address begins + * at PAGE_OFFSET, user address range is below PAGE_OFFSET. + * Remapping the area is always done, so multiple mappings + * of one region are possible. Now remap kernel address + * space into user space + */ + pfn = (unsigned int)paddr >> PAGE_SHIFT; + ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn, + buffer->len, vmarea->vm_page_prot); + mutex_unlock(&ctx.bufs_lock); + } else { + if (!is_daemon(instance)) + return -EPERM; - } while (0); + paddr = get_mci_base_phys(len); + if (!paddr) + return -EFAULT; - /* release PID struct reference */ - if (pid_struct != NULL) - put_pid(pid_struct); + vmarea->vm_flags |= VM_RESERVED; + /* + * Convert kernel address to user address. Kernel address begins + * at PAGE_OFFSET, user address range is below PAGE_OFFSET. + * Remapping the area is always done, so multiple mappings + * of one region are possible. Now remap kernel address + * space into user space + */ + pfn = (unsigned int)paddr >> PAGE_SHIFT; + ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn, len, + vmarea->vm_page_prot); + } MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; } -int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle) +static inline int ioctl_check_pointer(unsigned int cmd, int __user *uarg) { - int ret = 0; - struct mc_used_l2_table *used_l2table = NULL; + int err = 0; + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd)); + if (err) + return -EFAULT; - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE(mcd, "enter\n"); + return 0; +} - do { - /* try to get the semaphore */ - ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, - "processOpenSession() failed with %d\n", - ret); - ret = -ERESTARTSYS; - break; - } - - do { - used_l2table = find_used_l2_table_by_handle(handle); - if (used_l2table == NULL) { - ret = -EINVAL; - MCDRV_DBG_ERROR(mcd, "entry not found\n"); - break; - } - - if (instance != used_l2table->owner) { - ret = -EINVAL; - MCDRV_DBG_ERROR(mcd, - "instance does no own it\n"); - break; - } - - /* free table (if no further locks exist) */ - delete_used_l2_table(used_l2table, FREE_FROM_NWD); - used_l2table = NULL; - /* there are no out parameters */ - } while (0); - /* release semaphore */ - up(&(mc_drv_kmod_ctx.wsm_l2_sem)); - - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; -} -EXPORT_SYMBOL(mobicore_unmap_vmem); - -static int handle_ioctl_app_unregister_wsm_l2( - struct mc_instance *instance, - struct mc_ioctl_app_unreg_wsm_l2_params *user_params) +/* + * mc_fd_user_ioctl() - Will be called from user space as ioctl(..) + * @file pointer to file + * @cmd command + * @arg arguments + * + * Returns 0 for OK and an errno in case of error + */ +static long mc_fd_user_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { - int ret = 0; - struct mc_ioctl_app_unreg_wsm_l2_params params; - struct mc_used_l2_table *used_l2table = NULL; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - - do { - ret = copy_from_user(&(params.in), &(user_params->in), - sizeof(params.in)); + struct mc_instance *instance = get_instance(file); + int __user *uarg = (int __user *)arg; + int ret = -EINVAL; - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); - break; - } + if (WARN(!instance, "No instance data available")) + return -EFAULT; - /* try to get the semaphore */ - ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, - "down_interruptible() failed with %d\n", - ret); - ret = -ERESTARTSYS; - break; - } + if (ioctl_check_pointer(cmd, uarg)) + return -EFAULT; - do { - /* daemon can do this for another task. */ - if (params.in.pid != 0) { - MCDRV_DBG_ERROR(mcd, "pid != 0 unsupported\n"); - ret = -EINVAL; - break; - } + switch (cmd) { + case MC_IO_FREE: + ret = mc_free_buffer(instance, (uint32_t)arg); + break; - used_l2table = - find_used_l2_table_by_handle(params.in.handle); - if (used_l2table == NULL) { - ret = -EINVAL; - MCDRV_DBG_ERROR(mcd, "entry not found\n"); - break; - } + case MC_IO_REG_WSM:{ + struct mc_ioctl_reg_wsm reg; + if (copy_from_user(®, uarg, sizeof(reg))) + return -EFAULT; - if (is_caller_mc_daemon(instance)) { - /* - * if daemon does this, we have to release the - * MobiCore lock. - */ - used_l2table->flags &= - ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC; - } else if (instance != used_l2table->owner) { - ret = -EINVAL; - MCDRV_DBG_ERROR(mcd, - "instance does no own it\n"); - break; + ret = mc_register_wsm_l2(instance, reg.buffer, + reg.len, ®.handle, ®.table_phys); + if (!ret) { + if (copy_to_user(uarg, ®, sizeof(reg))) { + ret = -EFAULT; + mc_unregister_wsm_l2(instance, reg.handle); } - - /* free table (if no further locks exist) */ - delete_used_l2_table(used_l2table, FREE_FROM_NWD); - used_l2table = NULL; - - /* there are no out parameters */ - - } while (0); - - /* release semaphore */ - up(&(mc_drv_kmod_ctx.wsm_l2_sem)); - - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; -} - -static int handle_ioctl_daemon_lock_wsm_l2( - struct mc_instance *instance, - struct mc_ioctl_daemon_lock_wsm_l2_params *user_params) -{ - int ret = 0; - struct mc_ioctl_daemon_lock_wsm_l2_params params; - struct mc_used_l2_table *used_l2table = NULL; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - - do { - if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); - ret = -EFAULT; - break; } + break; + } + case MC_IO_UNREG_WSM: + ret = mc_unregister_wsm_l2(instance, (uint32_t)arg); + break; - ret = copy_from_user(&(params.in), &(user_params->in), - sizeof(params.in)); - - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); - break; - } - /* try to get the semaphore */ - ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); - if (ret != 0) { + case MC_IO_VERSION: + ret = put_user(mc_get_version(), uarg); + if (ret) MCDRV_DBG_ERROR(mcd, - "down_interruptible() failed with %d\n", - ret); - ret = -ERESTARTSYS; - break; - } - - do { - used_l2table = - find_used_l2_table_by_handle(params.in.handle); - if (used_l2table == NULL) { - ret = -EINVAL; - MCDRV_DBG_ERROR(mcd, "entry not found\n"); - break; - } - if (instance != used_l2table->owner) { - ret = -EINVAL; - MCDRV_DBG_ERROR(mcd, - "instance does no own it\n"); - break; - } - - /* lock entry */ - if ((used_l2table->flags & - MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) != 0) { - MCDRV_DBG_WARN(mcd, "entry already locked\n"); - } - used_l2table->flags |= - MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC; - - /* prepare response */ - memset(&(params.out), 0, sizeof(params.out)); - params.out.phys_wsm_l2_table = - (uint32_t)get_l2_table_phys(used_l2table); - - /* copy to user space */ - ret = copy_to_user(&(user_params->out), &(params.out), - sizeof(params.out)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_to_user() failed\n"); - - /* undo, as userspace did not get it. */ - used_l2table->flags |= - MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC; - break; - } - - } while (0); - - /* release semaphore */ - up(&(mc_drv_kmod_ctx.wsm_l2_sem)); - - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; -} + "IOCTL_GET_VERSION failed to put data"); + break; -static int handle_ioctl_daemon_unlock_wsm_l2( - struct mc_instance *instance, - struct mc_ioctl_daemon_unlock_wsm_l2_params *user_params) -{ - int ret = 0; - struct mc_ioctl_daemon_unlock_wsm_l2_params params; - struct mc_used_l2_table *used_l2table = NULL; + case MC_IO_MAP_WSM:{ + struct mc_ioctl_map map; + struct mc_buffer *buffer = 0; + if (copy_from_user(&map, uarg, sizeof(map))) + return -EFAULT; - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE(mcd, "enter\n"); + /* Setup the WSM buffer structure! */ + if (mc_get_buffer(instance, &buffer, map.len)) + return -EFAULT; - do { - if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); + map.handle = buffer->handle; + map.phys_addr = (unsigned long)buffer->phys; + map.reused = 0; + if (copy_to_user(uarg, &map, sizeof(map))) ret = -EFAULT; - break; - } - - ret = copy_from_user(&(params.in), &(user_params->in), - sizeof(params.in)); - - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); - break; - } - /* try to get the semaphore */ - ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, - "down_interruptible() failed with %d\n", - ret); - ret = -ERESTARTSYS; - break; - } - - do { - used_l2table = - find_used_l2_table_by_handle(params.in.handle); - if (used_l2table == NULL) { - ret = -EINVAL; - MCDRV_DBG_ERROR(mcd, "entry not found\n"); - break; - } - if (instance != used_l2table->owner) { - ret = -EINVAL; - MCDRV_DBG_ERROR(mcd, - "instance does no own it\n"); - break; - } - - /* lock entry */ - if ((used_l2table->flags & - MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) == 0) { - MCDRV_DBG_WARN(mcd, - "entry is not locked locked\n"); - } - - /* free table (if no further locks exist) */ - delete_used_l2_table(used_l2table, FREE_FROM_SWD); - used_l2table = NULL; - - /* there are no out parameters */ - - } while (0); - - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; -} - -/* Clears the reserved bit of each page and frees the pages */ -static inline void free_continguous_pages(void *addr, unsigned int order) -{ - struct page *page = virt_to_page(addr); - int i; - for (i = 0; i < (1 << order); i++) { - MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p\n", page); - ClearPageReserved(page); - page++; + ret = 0; + break; } - MCDRV_DBG(mcd, "freeing addr:%p, order:%x\n", addr, order); - free_pages((unsigned long)addr, order); -} - -int mobicore_free(struct mc_instance *instance, uint32_t handle) -{ - int ret = 0; - unsigned int i; - struct mc_contg_buffer *contg_buffer; - - do { - /* search for the given address in the contg_buffers list */ - for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) { - contg_buffer = &(instance->contg_buffers[i]); - if (contg_buffer->handle == handle) - break; - } - if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) { - MCDRV_DBG_ERROR(mcd, "contigous buffer not found\n"); - ret = -EFAULT; - break; - } - - MCDRV_DBG_VERBOSE(mcd, "phys_addr=0x%p, virt_addr=0x%p\n", - contg_buffer->phys_addr, - contg_buffer->virt_kernel_addr); - - free_continguous_pages(contg_buffer->virt_kernel_addr, - contg_buffer->order); - - memset(contg_buffer, 0, sizeof(*contg_buffer)); - - /* there are no out parameters */ - - } while (0); - - return ret; -} -EXPORT_SYMBOL(mobicore_free); - -static int handle_ioctl_free(struct mc_instance *instance, - union mc_ioctl_free_params *user_params) -{ - int ret = 0; - union mc_ioctl_free_params params; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - - do { - ret = copy_from_user(&(params.in), &(user_params->in), - sizeof(params.in)); - - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); - break; - } - - /* daemon can do this for another task. */ - if (params.in.pid != 0) { - MCDRV_DBG_ERROR(mcd, "pid != 0 unsupported\n"); - ret = -EINVAL; - break; - } - - ret = mobicore_free(instance, params.in.handle); - - /* there are no out parameters */ - - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; - -} - -static int handle_ioctl_info(struct mc_instance *instance, - union mc_ioctl_info_params *user_params) -{ - int ret = 0; - union mc_ioctl_info_params params; - union mc_fc_info fc_info; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - - do { - /* only the MobiCore Daemon is allowed to call this function */ - if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); - ret = -EFAULT; - break; - } - - ret = copy_from_user(&(params.in), &(user_params->in), - sizeof(params.in)); - - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_from_user\n"); - break; - } - - memset(&fc_info, 0, sizeof(fc_info)); - fc_info.as_in.cmd = MC_FC_INFO; - fc_info.as_in.ext_info_id = params.in.ext_info_id; - - MCDRV_DBG(mcd, - "fc_info in cmd=0x%08x, ext_info_id=0x%08x " - "rfu=(0x%08x, 0x%08x)\n", - fc_info.as_in.cmd, - fc_info.as_in.ext_info_id, - fc_info.as_in.rfu[0], - fc_info.as_in.rfu[1]); - - mc_fastcall(&(fc_info.as_generic)); - - MCDRV_DBG(mcd, - "fc_info out resp=0x%08x, ret=0x%08x " - "state=0x%08x, ext_info=0x%08x\n", - fc_info.as_out.resp, - fc_info.as_out.ret, - fc_info.as_out.state, - fc_info.as_out.ext_info); - - ret = convert_fc_ret(fc_info.as_out.ret); - if (ret != 0) - break; - - memset(&(params.out), 0, sizeof(params.out)); - params.out.state = fc_info.as_out.state; - params.out.ext_info = fc_info.as_out.ext_info; - - ret = copy_to_user(&(user_params->out), &(params.out), - sizeof(params.out)); - - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_to_user\n"); - break; - } - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; -} - -static int handle_ioctl_yield(struct mc_instance *instance) -{ - int ret = 0; - union mc_fc_s_yield fc_s_yield; - - MCDRV_ASSERT(instance != NULL); - - /* avoid putting debug output here, as we do this very often */ - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - - do { - /* only the MobiCore Daemon is allowed to call this function */ - if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); - ret = -EFAULT; - break; - } - - memset(&fc_s_yield, 0, sizeof(fc_s_yield)); - fc_s_yield.as_in.cmd = MC_SMC_N_YIELD; - mc_fastcall(&(fc_s_yield.as_generic)); - ret = convert_fc_ret(fc_s_yield.as_out.ret); - if (ret != 0) - break; + default: + MCDRV_DBG_ERROR(mcd, "unsupported cmd=%d\n", cmd); + ret = -ENOIOCTLCMD; + break; - } while (0); + } /* end switch(cmd) */ - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); +#ifdef MC_MEM_TRACES + mobicore_log_read(); +#endif - return ret; + return (int)ret; } -/* - * handle ioctl and call common notify - * - * returns 0 if no error - * - */ -static int handle_ioctl_nsiq(struct mc_instance *instance, unsigned long arg) +static long mc_fd_admin_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { - int ret = 0; - - MCDRV_ASSERT(instance != NULL); + struct mc_instance *instance = get_instance(file); + int __user *uarg = (int __user *)arg; + int ret = -EINVAL; - /* avoid putting debug output here, as we do this very often */ - MCDRV_DBG_VERBOSE(mcd, "enter\n"); + if (WARN(!instance, "No instance data available")) + return -EFAULT; - /* only the MobiCore Daemon is allowed to call this function */ - if (!is_caller_mc_daemon(instance)) { + if (WARN_ON(!is_daemon(instance))) { MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); - return -EFAULT; + return -EPERM; } - do { - union mc_fc_nsiq fc_nsiq; - memset(&fc_nsiq, 0, sizeof(fc_nsiq)); - fc_nsiq.as_in.cmd = MC_SMC_N_SIQ; - mc_fastcall(&(fc_nsiq.as_generic)); - ret = convert_fc_ret(fc_nsiq.as_out.ret); - if (ret != 0) - break; - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; -} - -static int handle_ioctl_init(struct mc_instance *instance, - union mc_ioctl_init_params *user_params) -{ - int ret = 0; - union mc_ioctl_init_params params; - union mc_fc_init fc_init; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE(mcd, "enter\n"); + if (ioctl_check_pointer(cmd, uarg)) + return -EFAULT; - do { - /* only the MobiCore Daemon is allowed to call this function */ - if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); - ret = -EFAULT; - break; + if (ctx.mcp) { + while (ctx.mcp->flags.sleep_mode.SleepReq) { + ctx.daemon = current; + set_current_state(TASK_INTERRUPTIBLE); + /* Back off daemon for a while */ + schedule_timeout(msecs_to_jiffies(DAEMON_BACKOFF_TIME)); + set_current_state(TASK_RUNNING); } + } - ret = copy_from_user(&(params.in), &(user_params->in), - sizeof(params.in)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_from_user failed\n"); - break; + switch (cmd) { + case MC_IO_INIT: { + struct mc_ioctl_init init; + ctx.mcp = NULL; + if (!ctx.mci_base.phys) { + MCDRV_DBG_ERROR(mcd, + "Cannot init MobiCore without MCI!"); + return -EINVAL; } - - memset(&fc_init, 0, sizeof(fc_init)); - - fc_init.as_in.cmd = MC_FC_INIT; - /* base address of mci buffer 4KB aligned */ - fc_init.as_in.base = (uint32_t)params.in.base; - /* notification buffer start/length [16:16] [start, length] */ - fc_init.as_in.nq_info = (params.in.nq_offset << 16) | - (params.in.nq_length & 0xFFFF); - /* mcp buffer start/length [16:16] [start, length] */ - fc_init.as_in.mcp_info = (params.in.mcp_offset << 16) | - (params.in.mcp_length & 0xFFFF); - - /* - * Set KMOD notification queue to start of MCI - * mciInfo was already set up in mmap - */ - if (!mci_base) { - MCDRV_DBG_ERROR(mcd, "No MCI set yet.\n"); + if (copy_from_user(&init, uarg, sizeof(init))) return -EFAULT; - } - MCDRV_DBG(mcd, - "in cmd=0x%08x, base=0x%08x, " - "nq_info=0x%08x, mcp_info=0x%08x\n", - fc_init.as_in.cmd, - fc_init.as_in.base, - fc_init.as_in.nq_info, - fc_init.as_in.mcp_info); - - mc_fastcall(&(fc_init.as_generic)); - - MCDRV_DBG(mcd, - "out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n", - fc_init.as_out.resp, - fc_init.as_out.ret, - fc_init.as_out.rfu[0], - fc_init.as_out.rfu[1]); - - ret = convert_fc_ret(fc_init.as_out.ret); - if (ret != 0) - break; - - /* no ioctl response parameters */ - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; -} + ctx.mcp = ctx.mci_base.addr + init.mcp_offset; + ret = mc_init((uint32_t)ctx.mci_base.phys, init.nq_offset, + init.nq_length, init.mcp_offset, init.mcp_length); + break; + } + case MC_IO_INFO: { + struct mc_ioctl_info info; + if (copy_from_user(&info, uarg, sizeof(info))) + return -EFAULT; -#define MC_MAKE_VERSION(major, minor) \ - (((major & 0x0000ffff) << 16) | (minor & 0x0000ffff)) + ret = mc_info(info.ext_info_id, &info.state, + &info.ext_info); -static int handle_ioctl_get_version( - struct mc_instance *instance, - struct mc_ioctl_get_version_params *user_params) -{ - int ret = 0; - struct mc_ioctl_get_version_params params = { - { - MC_MAKE_VERSION(MCDRVMODULEAPI_VERSION_MAJOR, - MCDRVMODULEAPI_VERSION_MINOR) + if (!ret) { + if (copy_to_user(uarg, &info, sizeof(info))) + ret = -EFAULT; } - }; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - - do { - MCDRV_DBG(mcd, "mcDrvModuleApi version is %i.%i\n", - MCDRVMODULEAPI_VERSION_MAJOR, - MCDRVMODULEAPI_VERSION_MINOR); - - /* no ioctl response parameters */ - ret = copy_to_user(&(user_params->out), &(params.out), - sizeof(params.out)); - if (ret != 0) - MCDRV_DBG_ERROR(mcd, "copy_to_user() failed\n"); - - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; -} - -static long mc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret; - struct mc_instance *instance = get_instance(file); - - MCDRV_ASSERT(instance != NULL); - - switch (cmd) { - case MC_DRV_KMOD_IOCTL_FC_INIT: - ret = handle_ioctl_init(instance, - (union mc_ioctl_init_params *)arg); break; - case MC_DRV_KMOD_IOCTL_FC_INFO: - ret = handle_ioctl_info(instance, - (union mc_ioctl_info_params *)arg); + } + case MC_IO_YIELD: + ret = mc_yield(); break; - case MC_DRV_KMOD_IOCTL_FC_YIELD: - ret = handle_ioctl_yield(instance); + + case MC_IO_NSIQ: + ret = mc_nsiq(); break; - case MC_DRV_KMOD_IOCTL_FC_NSIQ: - ret = handle_ioctl_nsiq(instance, arg); + + case MC_IO_LOCK_WSM: { + ret = mc_lock_handle(instance, (uint32_t)arg); break; - case MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2: - ret = handle_ioctl_daemon_lock_wsm_l2( - instance, - (struct mc_ioctl_daemon_lock_wsm_l2_params *)arg); + } + case MC_IO_UNLOCK_WSM: + ret = mc_unlock_handle(instance, (uint32_t)arg); break; - case MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2: - ret = handle_ioctl_daemon_unlock_wsm_l2( - instance, - (struct mc_ioctl_daemon_unlock_wsm_l2_params *)arg); + case MC_IO_CLEAN_WSM: + ret = mc_clean_wsm_l2(instance); break; - case MC_DRV_KMOD_IOCTL_FREE: - /* called by ClientLib */ - ret = handle_ioctl_free(instance, - (union mc_ioctl_free_params *)arg); + case MC_IO_RESOLVE_WSM: { + uint32_t handle, phys; + if (get_user(handle, uarg)) + return -EFAULT; + phys = mc_find_wsm_l2(instance, handle); + if (!phys) + return -EFAULT; + ret = put_user(phys, uarg); break; - case MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2: - /* called by ClientLib */ - ret = handle_ioctl_app_register_wsm_l2( - instance, - (union mc_ioctl_app_reg_wsm_l2_params *)arg); + } + case MC_IO_RESOLVE_CONT_WSM: { + struct mc_ioctl_resolv_cont_wsm cont_wsm; + uint32_t phys = 0, len = 0; + if (copy_from_user(&cont_wsm, uarg, sizeof(cont_wsm))) + return -EFAULT; + ret = mc_find_cont_wsm(instance, cont_wsm.handle, &phys, &len); + if (!ret) { + cont_wsm.phys = phys; + cont_wsm.length = len; + if (copy_to_user(uarg, &cont_wsm, sizeof(cont_wsm))) + ret = -EFAULT; + } break; - case MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2: - /* called by ClientLib */ - ret = handle_ioctl_app_unregister_wsm_l2( - instance, - (struct mc_ioctl_app_unreg_wsm_l2_params *)arg); + } + case MC_IO_MAP_MCI:{ + struct mc_ioctl_map map; + if (copy_from_user(&map, uarg, sizeof(map))) + return -EFAULT; + + map.reused = (ctx.mci_base.phys != 0); + map.phys_addr = (unsigned long)get_mci_base_phys(map.len); + if (!map.phys_addr) { + MCDRV_DBG_ERROR(mcd, "Failed to setup MCI buffer!"); + return -EFAULT; + } + + if (copy_to_user(uarg, &map, sizeof(map))) + ret = -EFAULT; + ret = 0; break; - case MC_DRV_KMOD_IOCTL_GET_VERSION: - ret = handle_ioctl_get_version( - instance, - (struct mc_ioctl_get_version_params *)arg); + } + case MC_IO_MAP_PWSM:{ break; + } + + /* The rest is handled commonly by user IOCTL */ default: - MCDRV_DBG_ERROR(mcd, "unsupported cmd=%d\n", cmd); - ret = -EFAULT; - break; + ret = mc_fd_user_ioctl(file, cmd, arg); } /* end switch(cmd) */ #ifdef MC_MEM_TRACES mobicore_log_read(); #endif - return (long)ret; + return (int)ret; } -/** - * mc_read() - This will be called from user space as read(...) +/* + * mc_fd_read() - This will be called from user space as read(...) * @file: file pointer * @buffer: buffer where to copy to(userspace) * @buffer_len: number of requested data @@ -1624,679 +779,270 @@ static long mc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) * If OK this function returns the number of copied data otherwise it returns * errno */ -static ssize_t mc_read(struct file *file, char *buffer, - size_t buffer_len, loff_t *pos) +static ssize_t mc_fd_read(struct file *file, char *buffer, size_t buffer_len, + loff_t *pos) { - int ret = 0; - int ssiq_counter; - int ctx_counter; - size_t retLen = 0; + int ret = 0, ssiq_counter; struct mc_instance *instance = get_instance(file); - MCDRV_ASSERT(instance != NULL); + if (WARN(!instance, "No instance data available")) + return -EFAULT; /* avoid debug output on non-error, because this is call quite often */ MCDRV_DBG_VERBOSE(mcd, "enter\n"); - do { - /* only the MobiCore Daemon is allowed to call this function */ - if (!is_caller_mc_daemon(instance)) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); - ret = -EFAULT; - break; - } - - if (buffer_len < sizeof(unsigned int)) { - MCDRV_DBG_ERROR(mcd, "invalid length\n"); - ret = (ssize_t)(-EINVAL); - break; - } - - for (;;) { - if (down_interruptible( - &mc_drv_kmod_ctx.daemon_ctx.sem)) { - MCDRV_DBG_VERBOSE(mcd, "read interrupted\n"); - ret = (ssize_t)-ERESTARTSYS; - break; - } - - ssiq_counter = atomic_read( - &(mc_drv_kmod_ctx.ssiq_ctx.counter)); - ctx_counter = - mc_drv_kmod_ctx.daemon_ctx.ssiq_counter; - - MCDRV_DBG_VERBOSE(mcd, - "ssiq_counter=%i, ctx.counter=%i\n", - ssiq_counter, - ctx_counter); - - if (ssiq_counter != - mc_drv_kmod_ctx.daemon_ctx.ssiq_counter) { - /* read data and exit loop without - error */ - mc_drv_kmod_ctx.daemon_ctx.ssiq_counter = - ssiq_counter; - ret = 0; - break; - } - - /* end loop if non-blocking */ - if ((file->f_flags & O_NONBLOCK) != 0) { - MCDRV_DBG_ERROR(mcd, "non-blocking read\n"); - ret = (ssize_t)(-EAGAIN); - break; - } - - if (signal_pending(current) != 0) { - MCDRV_DBG_VERBOSE(mcd, "received signal.\n"); - ret = (ssize_t)(-ERESTARTSYS); - break; - } - - } - - /* - * we are here if an event occurred - * or if we had an error. - */ - if (ret != 0) - break; - - /* read data and exit loop */ - ret = copy_to_user(buffer, - &(mc_drv_kmod_ctx.daemon_ctx.ssiq_counter), - sizeof(unsigned int)); - - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_to_user failed\n"); - ret = (ssize_t)(-EFAULT); - break; - } - - retLen = sizeof(s32); - - } while (0); - - /* avoid debug on non-error. */ - if (ret == 0) - ret = (size_t)retLen; - else - MCDRV_DBG(mcd, "exit with %d/0x%08X\n", ret, ret); - - return (ssize_t)ret; -} - -int mobicore_allocate_wsm(struct mc_instance *instance, - unsigned long requested_size, uint32_t *handle, - void **virt_kernel_addr, void **phys_addr) -{ - unsigned int i; - unsigned int order; - unsigned long allocated_size; - int ret = 0; - struct mc_contg_buffer *contg_buffer = 0; - void *kaddr_buffer; - void *paddr_buffer; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG(mcd, "%s (size=%ld)\n", __func__, requested_size); - - if (requested_size == 0) { - MCDRV_DBG_ERROR(mcd, "cannot allocate size 0\n"); - return -ENOMEM; + /* only the MobiCore Daemon is allowed to call this function */ + if (WARN_ON(!is_daemon(instance))) { + MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n"); + return -EPERM; } - order = get_order(requested_size); - allocated_size = (1 << order)*PAGE_SIZE; - MCDRV_DBG(mcd, "size %ld -> order %d --> %ld (2^n pages)\n", - requested_size, order, allocated_size); + if (buffer_len < sizeof(unsigned int)) { + MCDRV_DBG_ERROR(mcd, "invalid length\n"); + return -EINVAL; + } - do { - /* - * Usual Wsm request, allocate contigous buffer. - * search for a free entry in the wsm buffer list - */ - for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) { - contg_buffer = &(instance->contg_buffers[i]); - if (contg_buffer->handle == 0) { - contg_buffer->handle = get_mc_kmod_unique_id(); - break; - } - } - if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) { - MCDRV_DBG_ERROR(mcd, "no free contigous buffer\n"); - ret = -EFAULT; - break; + for (;;) { + if (wait_for_completion_interruptible(&ctx.isr_comp)) { + MCDRV_DBG_VERBOSE(mcd, "read interrupted\n"); + return -ERESTARTSYS; } - /* Common code for all allocation paths */ - kaddr_buffer = (void *)__get_free_pages(GFP_USER | __GFP_COMP, - order); - if (kaddr_buffer == NULL) { - MCDRV_DBG_ERROR(mcd, "get_free_pages failed\n"); - ret = -ENOMEM; + ssiq_counter = atomic_read(&ctx.isr_counter); + MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i\n", + ssiq_counter, ctx.evt_counter); + + if (ssiq_counter != ctx.evt_counter) { + /* read data and exit loop without error */ + ctx.evt_counter = ssiq_counter; + ret = 0; break; } - /* Get physical address to instance data */ - paddr_buffer = (void *)virt_to_phys(kaddr_buffer); - - MCDRV_DBG(mcd, - "allocated phys=0x%p - 0x%p, " - "size=%ld, kernel_virt=0x%p, handle=%d\n", - paddr_buffer, - (void *)((unsigned int)paddr_buffer+allocated_size), - allocated_size, - kaddr_buffer, - contg_buffer->handle); - - /* - * Usual Wsm request, allocate contg_buffer. - * Also, we never free a persistent Tci - */ - contg_buffer->phys_addr = paddr_buffer; - contg_buffer->virt_kernel_addr = kaddr_buffer; - contg_buffer->virt_user_addr = kaddr_buffer; - contg_buffer->order = order; - *handle = contg_buffer->handle; - *virt_kernel_addr = kaddr_buffer; - *phys_addr = paddr_buffer; - - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "%s: exit with 0x%08X\n", __func__, ret); - - return ret; -} -EXPORT_SYMBOL(mobicore_allocate_wsm); - -/** - * mc_mmap() - Called from user space as address = mmap(...). - * @file: file pointer - * @vmarea: vmarea.pg_offset != 0 is mapping of MCI is requested - * - * This function returns either 0 or -ENOMEM in case of error. - */ -static int mc_mmap(struct file *file, struct vm_area_struct *vmarea) -{ - int ret = 0; - unsigned int i; - struct mc_instance *instance = get_instance(file); - unsigned int request = vmarea->vm_pgoff * 4096; - unsigned long requested_size = vmarea->vm_end - vmarea->vm_start; - unsigned int order; - unsigned long allocated_size; - void *kaddr_buffer = 0; - void *paddr_buffer = 0; - unsigned int pfn; - struct mc_contg_buffer *contg_buffer = 0; - unsigned int uq_handle_buffer = 0; - bool allocate_buffer = false; - - MCDRV_ASSERT(instance != NULL); - MCDRV_DBG(mcd, - "enter (vma start=0x%p, size=%ld, request=0x%x, mci=0x%x)\n", - (void *)vmarea->vm_start, - requested_size, - request, - mci_base); - - if (requested_size == 0) { - MCDRV_DBG_ERROR(mcd, "cannot allocate size 0\n"); - ret = -ENOMEM; - goto mc_mmap_end; - } - order = get_order(requested_size); - allocated_size = (1 << order)*PAGE_SIZE; - - MCDRV_DBG(mcd, - "size %ld -> order %d --> %ld (2^n pages)\n", - requested_size, order, allocated_size); - - switch (request) { - - /* Daemon tries to get the MCI - the MobiCore Interface buffer */ - case MC_DRV_KMOD_MMAP_MCI: - if (!is_caller_mc_daemon(instance)) { - ret = -EPERM; - goto mc_mmap_end; + /* end loop if non-blocking */ + if (file->f_flags & O_NONBLOCK) { + MCDRV_DBG_ERROR(mcd, "non-blocking read\n"); + return -EAGAIN; } - if (mci_base == 0) { - allocate_buffer = true; - } else { - MCDRV_DBG(mcd, - "Request MCI, it is at (%x)\n", mci_base); - - kaddr_buffer = (void *)mci_base; - paddr_buffer = (void *)virt_to_phys(kaddr_buffer); - allocate_buffer = false; + if (signal_pending(current)) { + MCDRV_DBG_VERBOSE(mcd, "received signal.\n"); + return -ERESTARTSYS; } - break; - /* Usual Wsm request, find free buffer slot. */ - case MC_DRV_KMOD_MMAP_WSM: - /* search for a free slot in the buffer list. */ - for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) { - contg_buffer = &(instance->contg_buffers[i]); - if (contg_buffer->handle == 0) - break; - } - if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) { - MCDRV_DBG_WARN(mcd, - "no free slot for wsm buffer avail\n"); - ret = -EFAULT; - goto mc_mmap_end; - } - uq_handle_buffer = - contg_buffer->handle = get_mc_kmod_unique_id(); - allocate_buffer = true; - break; - /* Special Wsm request that is not bound to a process. */ - case MC_DRV_KMOD_MMAP_PERSISTENTWSM: - if (!is_caller_mc_daemon(instance)) { - ret = -EPERM; - goto mc_mmap_end; - } - allocate_buffer = true; - break; - default: -#if defined(DEBUG) - /* - * In debug version, allow mapping of arbitry physical memory to - * a process to allow testing of TZASC/XPU memory protection set - * up by SWd. - */ - paddr_buffer = (void *)request; - kaddr_buffer = phys_to_virt(request); - allocate_buffer = false; -#else - ret = -EPERM; - goto mc_mmap_end; -#endif - break; - } /* switch(request) */ - - /* Allocate memory */ - if (allocate_buffer) { - kaddr_buffer = (void *)__get_free_pages(GFP_USER | __GFP_COMP, - order); - if (kaddr_buffer == NULL) { - MCDRV_DBG_WARN(mcd, - "no contiguous region available.\n"); - ret = -ENOMEM; - goto mc_mmap_end; - } - paddr_buffer = (void *)virt_to_phys(kaddr_buffer); } - /* - * Common code for all mmap calls: - * map page to user - * store data in page - */ - - MCDRV_DBG(mcd, - "alloc phys=0x%p - 0x%p, sz=%ld, kernel_virt=0x%p, hndl=%d\n", - paddr_buffer, - (void *)((unsigned int)paddr_buffer+allocated_size), - allocated_size, kaddr_buffer, uq_handle_buffer); - - vmarea->vm_flags |= VM_RESERVED; + /* read data and exit loop */ + ret = copy_to_user(buffer, &ctx.evt_counter, sizeof(unsigned int)); - /* - * Convert kernel address to user address. Kernel address begins - * at PAGE_OFFSET, user address range is below PAGE_OFFSET. - * Remapping the area is always done, so multiple mappings - * of one region are possible. Now remap kernel address - * space into user space - */ - pfn = (unsigned int)paddr_buffer >> PAGE_SHIFT; - ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn, - requested_size, vmarea->vm_page_prot); if (ret != 0) { - MCDRV_DBG_WARN(mcd, "remap_pfn_range failed\n"); - - if (allocate_buffer) - free_continguous_pages(kaddr_buffer, order); - - goto mc_mmap_end; - } - - /* Usual wsm request, store reference to buffer for later freeing. */ - if (request == MC_DRV_KMOD_MMAP_WSM) { - contg_buffer->phys_addr = paddr_buffer; - contg_buffer->virt_kernel_addr = kaddr_buffer; - contg_buffer->virt_user_addr = (void *)(vmarea->vm_start); - contg_buffer->order = order; - } - - /* set response in allocated buffer */ - { - struct mc_mmap_resp *mmap_resp = - (struct mc_mmap_resp *)kaddr_buffer; - mmap_resp->phys_addr = (uint32_t)paddr_buffer; - mmap_resp->handle = uq_handle_buffer; - mmap_resp->is_reused = (request == MC_DRV_KMOD_MMAP_MCI) && - (mci_base != 0); - } - - /* store MCI pointer */ - if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base == 0)) { - mci_base = (uint32_t)kaddr_buffer; - MCDRV_DBG(mcd, "MCI base set to 0x%x\n", mci_base); + MCDRV_DBG_ERROR(mcd, "copy_to_user failed\n"); + return -EFAULT; } -mc_mmap_end: - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); + ret = sizeof(unsigned int); - return ret; + return (ssize_t)ret; } -/** - * goto_cpu0() - Force migration of current task to CPU0 +/* + * Initialize a new mobicore API instance object * - * Returns either an error code or 0 for success + * @return Instance or NULL if no allocation was possible. */ -static int goto_cpu0(void) +struct mc_instance *mc_alloc_instance(void) { - int ret = 0; - struct cpumask mask = CPU_MASK_CPU0; + struct mc_instance *instance; - MCDRV_DBG_VERBOSE(mcd, "System has %d CPU's, we are on CPU #%d\n", - nr_cpu_ids, raw_smp_processor_id()); - MCDRV_DBG_VERBOSE(mcd, "\tBinding this process to CPU #0.\n"); - MCDRV_DBG_VERBOSE(mcd, "\tactive mask is %lx, setting it to mask=%lx\n", - cpu_active_mask->bits[0], - mask.bits[0]); + instance = kzalloc(sizeof(*instance), GFP_KERNEL); + if (instance == NULL) + return NULL; - ret = set_cpus_allowed_ptr(current, &mask); - if (ret != 0) - MCDRV_DBG_ERROR(mcd, "set_cpus_allowed_ptr=%d.\n", ret); + /* get a unique ID for this instance (PIDs are not unique) */ + instance->handle = get_unique_id(); - MCDRV_DBG_VERBOSE(mcd, "And now we are on CPU #%d\n", - raw_smp_processor_id()); + mutex_init(&instance->lock); - return ret; + return instance; } -/** - * goto_all_cpu() - Restore CPU mask for current to ALL Cpus - * - * Returns either an error code or 0 for success +/* + * Release a mobicore instance object and all objects related to it + * @instance: instance + * Returns 0 if Ok or -E ERROR */ -static int goto_all_cpu(void) +int mc_release_instance(struct mc_instance *instance) { - int ret = 0; - struct cpumask mask = CPU_MASK_ALL; + struct mc_buffer *buffer, *tmp; - MCDRV_DBG_VERBOSE(mcd, "System has %d CPU's, we are on CPU #%d\n", - nr_cpu_ids, raw_smp_processor_id()); - MCDRV_DBG_VERBOSE(mcd, "\tBinding this process to CPU #0.\n"); - MCDRV_DBG_VERBOSE(mcd, "\tactive mask is %lx, setting it to mask=%lx\n", - cpu_active_mask->bits[0], mask.bits[0]); - - ret = set_cpus_allowed_ptr(current, &mask); - if (ret != 0) - MCDRV_DBG_ERROR(mcd, "set_cpus_allowed_ptr=%d.\n", ret); - - MCDRV_DBG_VERBOSE(mcd, "And now we are on CPU #%d\n", - raw_smp_processor_id()); + if (WARN(!instance, "No instance data available")) + return -EFAULT; - return ret; -} + mutex_lock(&instance->lock); + mc_clear_l2_tables(instance); -struct mc_instance *mobicore_open(void) -{ - struct mc_instance *instance; - pid_t pid_vnr; + mutex_lock(&ctx.bufs_lock); + /* release all mapped data */ - instance = kzalloc(sizeof(*instance), GFP_KERNEL); - if (instance == NULL) - return NULL; + /* Check if some buffers are orphaned. */ + list_for_each_entry_safe(buffer, tmp, &ctx.cont_bufs, list) { + if (buffer->instance == instance) { + buffer->instance = NULL; + free_buffer(buffer); + } + } + mutex_unlock(&ctx.bufs_lock); - /* get a unique ID for this instance (PIDs are not unique) */ - instance->handle = get_mc_kmod_unique_id(); + mutex_unlock(&instance->lock); - /* - * get the PID of the calling process. We avoid using - * current->pid directly, as 2.6.24 introduced PID - * namespaces. See also http://lwn.net/Articles/259217 - */ - pid_vnr = task_pid_vnr(current); - instance->pid_vnr = pid_vnr; + /* release instance context */ + kfree(instance); - return instance; + return 0; } -EXPORT_SYMBOL(mobicore_open); -/** - * mc_open() - Called from user space as fd = open(...) - * @inode: file inode - * @file: file pointer - * +/* + * mc_fd_user_open() - Will be called from user space as fd = open(...) * A set of internal instance data are created and initialized. * - * This function returns either 0 or -ENOMEM in case of error. + * @inode + * @file + * Returns 0 if OK or -ENOMEM if no allocation was possible. */ -static int mc_open(struct inode *inode, struct file *file) +static int mc_fd_user_open(struct inode *inode, struct file *file) { struct mc_instance *instance; - int ret = 0; MCDRV_DBG_VERBOSE(mcd, "enter\n"); - do { - instance = mobicore_open(); - if (instance == NULL) - return -ENOMEM; - - /* - * check if Daemon. We simply assume that the first to open us - * with root privileges must be the daemon. - */ - if ((is_userland_caller_privileged()) && - (mc_drv_kmod_ctx.daemon_inst == NULL)) { - MCDRV_DBG(mcd, "accept this as MobiCore Daemon\n"); - - /* Set the caller's CPU mask to CPU0 */ - ret = goto_cpu0(); - if (ret != 0) { - mobicore_release(instance); - file->private_data = NULL; - MCDRV_DBG(mcd, "changing core failed!\n"); - break; - } - - mc_drv_kmod_ctx.daemon_inst = instance; - sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem, - DAEMON_SEM_VAL); - /* init ssiq event counter */ - mc_drv_kmod_ctx.daemon_ctx.ssiq_counter = - atomic_read( - &(mc_drv_kmod_ctx.ssiq_ctx.counter)); - -#ifdef MC_MEM_TRACES - /* - * The traces have to be setup on CPU-0 since we must - * do a fastcall to MobiCore. - */ - if (!mci_base) - /* - * Do the work only if MCI base is not - * initialized properly - */ - work_on_cpu(0, mobicore_log_setup, NULL); -#endif - } - - /* store instance data reference */ - file->private_data = instance; - - } while (0); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); + instance = mc_alloc_instance(); + if (instance == NULL) + return -ENOMEM; - return (int)ret; + /* store instance data reference */ + file->private_data = instance; + return 0; } -int mobicore_release(struct mc_instance *instance) +static int mc_fd_admin_open(struct inode *inode, struct file *file) { - int ret = 0; - int i; - struct mc_used_l2_table *used_l2table, *used_l2table_temp; - - do { - /* try to get the semaphore */ - ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem)); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, - "down_interruptible() failed %d\n", - ret); - - ret = -ERESTARTSYS; - } else { - /* Check if some WSM is still in use. */ - list_for_each_entry_safe( - used_l2table, used_l2table_temp, - &(mc_drv_kmod_ctx.mc_used_l2_tables), - list - ) { - if (used_l2table->owner == instance) { - MCDRV_DBG_WARN( - mcd, - "trying to release WSM L2: " - "physBase=%p ,nr_of_pages=%d\n", - get_l2_table_phys(used_l2table), - used_l2table->nr_of_pages); - - /* - * unlock app usage and free if MobiCore - * does not use it - */ - delete_used_l2_table(used_l2table, - FREE_FROM_NWD); - } - } /* end while */ - - /* release semaphore */ - up(&(mc_drv_kmod_ctx.wsm_l2_sem)); - } + struct mc_instance *instance; - /* release all mapped data */ - for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) { - struct mc_contg_buffer *contg_buffer = - &(instance->contg_buffers[i]); + /* + * The daemon is already set so we can't allow anybody else to open + * the admin interface. + */ + if (ctx.daemon_inst) { + MCDRV_DBG_ERROR(mcd, "Daemon is already connected"); + return -EPERM; + } + /* Setup the usual variables */ + if (mc_fd_user_open(inode, file)) + return -ENOMEM; + instance = get_instance(file); - if (contg_buffer->virt_user_addr != 0) { - free_continguous_pages( - contg_buffer->virt_kernel_addr, - contg_buffer->order); - } - } + MCDRV_DBG(mcd, "accept this as MobiCore Daemon\n"); - /* release instance context */ - kfree(instance); - } while (0); + ctx.daemon_inst = instance; + ctx.daemon = current; + instance->admin = true; + init_completion(&ctx.isr_comp); + /* init ssiq event counter */ + ctx.evt_counter = atomic_read(&(ctx.isr_counter)); - return ret; + return 0; } -EXPORT_SYMBOL(mobicore_release); -/** - * mc_release() - Called from user space as close(...) - * @inode: file inode - * @file: file pointer - * +/* + * mc_fd_release() - This function will be called from user space as close(...) * The instance data are freed and the associated memory pages are unreserved. * - * Returns either an error code or 0 on success + * @inode + * @file + * + * Returns 0 */ -static int mc_release(struct inode *inode, struct file *file) +static int mc_fd_release(struct inode *inode, struct file *file) { int ret = 0; struct mc_instance *instance = get_instance(file); - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - - do { - /* check if daemon closes us. */ - if (is_caller_mc_daemon(instance)) { - MCDRV_DBG_WARN(mcd, "WARNING: MobiCore Daemon died\n"); - mc_drv_kmod_ctx.daemon_inst = NULL; - } + if (WARN(!instance, "No instance data available")) + return -EFAULT; - ret = mobicore_release(instance); + /* check if daemon closes us. */ + if (is_daemon(instance)) { + MCDRV_DBG_WARN(mcd, "WARNING: MobiCore Daemon died\n"); + ctx.daemon_inst = NULL; + ctx.daemon = NULL; + } - } while (0); + ret = mc_release_instance(instance); + /* + * ret is quite irrelevant here as most apps don't care about the + * return value from close() and it's quite difficult to recover + */ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - return ret; + return (int)ret; } -/** - * mc_intr_ssiq() - The interrupt function of the mcDrvModule - * @intr: Interrupt number - * @context: pointer to registered device data - * - * This function signals an interrupt by incrementing of an event counter - * and the start of the read waiting queue - * - * Returns either IRQ_HANDLED or IRQ_NONE +/* + * This function represents the interrupt function of the mcDrvModule. + * It signals by incrementing of an event counter and the start of the read + * waiting queue, the read function a interrupt has occurred. */ -static irqreturn_t mc_intr_ssiq(int intr, void *context) +static irqreturn_t mc_ssiq_isr(int intr, void *context) { - irqreturn_t ret = IRQ_NONE; - - /* we know the context. */ - MCDRV_ASSERT(&mc_drv_kmod_ctx == context); - - do { - if (intr != MC_INTR_SSIQ) { - /* - * this should not happen, as we did no register for any - * other interrupt. For debugging, we print a message, - * but continue - */ - MCDRV_DBG_WARN(mcd, - "unknown int %d, expecting only %d\n", - intr, MC_INTR_SSIQ); - } - MCDRV_DBG_VERBOSE(mcd, "received interrupt %d\n", intr); + /* increment interrupt event counter */ + atomic_inc(&(ctx.isr_counter)); - /* increment interrupt event counter */ - atomic_inc(&(mc_drv_kmod_ctx.ssiq_ctx.counter)); + /* signal the daemon */ + complete(&ctx.isr_comp); - /* signal the daemon */ - up(&mc_drv_kmod_ctx.daemon_ctx.sem); - - ret = IRQ_HANDLED; + return IRQ_HANDLED; +} - } while (0); +/* function table structure of this device driver. */ +static const struct file_operations mc_admin_fops = { + .owner = THIS_MODULE, + .open = mc_fd_admin_open, + .release = mc_fd_release, + .unlocked_ioctl = mc_fd_admin_ioctl, + .mmap = mc_fd_mmap, + .read = mc_fd_read, +}; - return ret; -} +static struct miscdevice mc_admin_device = { + .name = MC_ADMIN_DEVNODE, + .mode = (S_IRWXU), + .minor = MISC_DYNAMIC_MINOR, + .fops = &mc_admin_fops, +}; /* function table structure of this device driver. */ -static const struct file_operations mc_file_operations = { - .owner = THIS_MODULE, /*< driver owner */ - .open = mc_open, /*< driver open function */ - .release = mc_release, /*< driver rel function*/ - .unlocked_ioctl = mc_ioctl, /*< driver ioctl function */ - .mmap = mc_mmap, /*< driver mmap function */ - .read = mc_read, /*< driver read function */ +static const struct file_operations mc_user_fops = { + .owner = THIS_MODULE, + .open = mc_fd_user_open, + .release = mc_fd_release, + .unlocked_ioctl = mc_fd_user_ioctl, + .mmap = mc_fd_mmap, }; -/* registration structure as miscdevice. */ -static struct miscdevice mc_device = { - .name = MC_DRV_MOD_DEVNODE, /*< device name */ - .minor = MISC_DYNAMIC_MINOR, /*< device minor number */ - /* device interface function structure */ - .fops = &mc_file_operations, +static struct miscdevice mc_user_device = { + .name = MC_USER_DEVNODE, + .mode = (S_IRWXU | S_IRWXG | S_IRWXO), + .minor = MISC_DYNAMIC_MINOR, + .fops = &mc_user_fops, }; -static int __init mc_init(void) +/* + * This function is called the kernel during startup or by a insmod command. + * This device is installed and registered as miscdevice, then interrupt and + * queue handling is set up + */ +static int __init mobicore_init(void) { int ret = 0; @@ -2309,99 +1055,110 @@ static int __init mc_init(void) #ifdef MOBICORE_COMPONENT_BUILD_TAG MCDRV_DBG(mcd, "%s\n", MOBICORE_COMPONENT_BUILD_TAG); #endif - do { - /* - * Hardware does not support ARM TrustZone - * -> Cannot continue! - */ - if (has_security_extensions() == false) { - MCDRV_DBG_ERROR(mcd, - "HW does't support ARM TrustZone!\n"); - ret = -ENODEV; - break; - } - - /* Running in secure mode -> Cannot load the driver! */ - if (is_secure_mode() == true) { - MCDRV_DBG_ERROR(mcd, "Running in secure MODE!\n"); - ret = -ENODEV; - break; - } + /* Hardware does not support ARM TrustZone -> Cannot continue! */ + if (!has_security_extensions()) { + MCDRV_DBG_ERROR(mcd, + "Hardware doesn't support ARM TrustZone!\n"); + return -ENODEV; + } - sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem, DAEMON_SEM_VAL); + /* Running in secure mode -> Cannot load the driver! */ + if (is_secure_mode()) { + MCDRV_DBG_ERROR(mcd, "Running in secure MODE!\n"); + return -ENODEV; + } - /* set up S-SIQ interrupt handler */ - ret = request_irq(MC_INTR_SSIQ, mc_intr_ssiq, - IRQF_TRIGGER_RISING, MC_DRV_MOD_DEVNODE, - &mc_drv_kmod_ctx); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "interrupt request failed\n"); - break; - } + init_completion(&ctx.isr_comp); + /* set up S-SIQ interrupt handler */ + ret = request_irq(MC_INTR_SSIQ, mc_ssiq_isr, IRQF_TRIGGER_RISING, + MC_ADMIN_DEVNODE, &ctx); + if (ret != 0) { + MCDRV_DBG_ERROR(mcd, "interrupt request failed\n"); + goto error; + } - ret = misc_register(&mc_device); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "device register failed\n"); - break; - } +#ifdef MC_PM_RUNTIME + ret = mc_pm_initialize(&ctx); + if (ret != 0) { + MCDRV_DBG_ERROR(mcd, "Power Management init failed!\n"); + goto free_isr; + } +#endif - /* initialize event counter for signaling of an IRQ to zero */ - atomic_set(&(mc_drv_kmod_ctx.ssiq_ctx.counter), 0); + ret = misc_register(&mc_admin_device); + if (ret != 0) { + MCDRV_DBG_ERROR(mcd, "admin device register failed\n"); + goto free_isr; + } - /* init list for WSM L2 chunks. */ - INIT_LIST_HEAD(&(mc_drv_kmod_ctx.mc_l2_tables_sets)); + ret = misc_register(&mc_user_device); + if (ret != 0) { + MCDRV_DBG_ERROR(mcd, "user device register failed\n"); + goto free_admin; + } - /* L2 table descriptor list. */ - INIT_LIST_HEAD(&(mc_drv_kmod_ctx.mc_used_l2_tables)); +#ifdef MC_MEM_TRACES + mobicore_log_setup(); +#endif - sema_init(&(mc_drv_kmod_ctx.wsm_l2_sem), 1); + /* initialize event counter for signaling of an IRQ to zero */ + atomic_set(&ctx.isr_counter, 0); - /* - * initialize unique number counter which we can use for - * handles. It is limited to 2^32, but this should be - * enough to be roll-over safe for us. We start with 1 - * instead of 0. - */ - atomic_set(&(mc_drv_kmod_ctx.unique_counter), 1); + ret = mc_init_l2_tables(); - mci_base = 0; - MCDRV_DBG(mcd, "initialized\n"); + /* + * initialize unique number counter which we can use for + * handles. It is limited to 2^32, but this should be + * enough to be roll-over safe for us. We start with 1 + * instead of 0. + */ + atomic_set(&ctx.unique_counter, 1); - ret = 0; + /* init list for contiguous buffers */ + INIT_LIST_HEAD(&ctx.cont_bufs); - } while (0); + /* init lock for the buffers list */ + mutex_init(&ctx.bufs_lock); - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); + memset(&ctx.mci_base, 0, sizeof(ctx.mci_base)); + MCDRV_DBG(mcd, "initialized\n"); + return 0; +free_admin: + misc_deregister(&mc_admin_device); +free_isr: + free_irq(MC_INTR_SSIQ, &ctx); +error: return ret; } -static void __exit mc_exit(void) +/* + * This function removes this device driver from the Linux device manager . + */ +static void __exit mobicore_exit(void) { - struct mc_used_l2_table *used_l2table; - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - +#ifdef MC_MEM_TRACES mobicore_log_free(); +#endif - /* Check if some WSM is still in use. */ - list_for_each_entry(used_l2table, &(mc_drv_kmod_ctx.mc_used_l2_tables), - list) { - MCDRV_DBG_WARN(mcd, - "WSM L2 in use: physBase=%p ,nr_of_pages=%d\n", - get_l2_table_phys(used_l2table), - used_l2table->nr_of_pages); - } /* end list_for_each_entry */ + mc_release_l2_tables(); + +#ifdef MC_PM_RUNTIME + mc_pm_free(); +#endif - free_irq(MC_INTR_SSIQ, &mc_drv_kmod_ctx); + free_irq(MC_INTR_SSIQ, &ctx); - misc_deregister(&mc_device); + misc_deregister(&mc_admin_device); + misc_deregister(&mc_user_device); MCDRV_DBG_VERBOSE(mcd, "exit"); } /* Linux Driver Module Macros */ -module_init(mc_init); -module_exit(mc_exit); +module_init(mobicore_init); +module_exit(mobicore_exit); MODULE_AUTHOR("Giesecke & Devrient GmbH"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MobiCore driver"); + diff --git a/drivers/gud/mobicore_driver/main.h b/drivers/gud/mobicore_driver/main.h new file mode 100644 index 00000000000..e23c51618c6 --- /dev/null +++ b/drivers/gud/mobicore_driver/main.h @@ -0,0 +1,144 @@ +/* + * Header file of MobiCore Driver Kernel Module. + * + * Internal structures of the McDrvModule + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MC_MAIN_H_ +#define _MC_MAIN_H_ + +#include +#include +#include +#include + +#include "public/mc_linux.h" +/* Platform specific settings */ +#include "platform.h" + +#define MC_VERSION(major, minor) \ + (((major & 0x0000ffff) << 16) | (minor & 0x0000ffff)) + +/* Instance data for MobiCore Daemon and TLCs. */ +struct mc_instance { + /* Instance lock */ + struct mutex lock; + /* unique handle */ + unsigned int handle; + bool admin; +}; + +/* + * Contiguous buffer allocated to TLCs. + * These buffers are uses as world shared memory (wsm) and shared with + * secure world. + * The virtual kernel address is added for a simpler search algorithm. + */ +struct mc_buffer { + struct list_head list; + /* unique handle */ + unsigned int handle; + /* Number of references kept to this buffer */ + atomic_t usage; + /* virtual Kernel start address */ + void *addr; + /* physical start address */ + void *phys; + /* order of number of pages */ + unsigned int order; + uint32_t len; + struct mc_instance *instance; +}; + +/* MobiCore Driver Kernel Module context data. */ +struct mc_context { + /* MobiCore MCI information */ + struct mc_buffer mci_base; + /* MobiCore MCP buffer */ + struct mc_mcp_buffer *mcp; + /* event completion */ + struct completion isr_comp; + /* isr event counter */ + unsigned int evt_counter; + atomic_t isr_counter; + /* ever incrementing counter */ + atomic_t unique_counter; + /* pointer to instance of daemon */ + struct mc_instance *daemon_inst; + /* pointer to instance of daemon */ + struct task_struct *daemon; + /* General list of contiguous buffers allocated by the kernel */ + struct list_head cont_bufs; + /* Lock for the list of contiguous buffers */ + struct mutex bufs_lock; +}; + +struct mc_sleep_mode { + uint16_t SleepReq; + uint16_t ReadyToSleep; +}; + +/* MobiCore is idle. No scheduling required. */ +#define SCHEDULE_IDLE 0 +/* MobiCore is non idle, scheduling is required. */ +#define SCHEDULE_NON_IDLE 1 + +/* MobiCore status flags */ +struct mc_flags { + /* + * Scheduling hint: if <> SCHEDULE_IDLE, MobiCore should + * be scheduled by the NWd + */ + uint32_t schedule; + /* State of sleep protocol */ + struct mc_sleep_mode sleep_mode; + /* Reserved for future use: Must not be interpreted */ + uint32_t rfu[2]; +}; + +/* MCP buffer structure */ +struct mc_mcp_buffer { + /* MobiCore Flags */ + struct mc_flags flags; + uint32_t rfu; /* MCP message buffer - ignore */ +}; + +unsigned int get_unique_id(void); + +/* check if caller is MobiCore Daemon */ +static inline bool is_daemon(struct mc_instance *instance) +{ + if (!instance) + return false; + return instance->admin; +} + + +/* Initialize a new mobicore API instance object */ +struct mc_instance *mc_alloc_instance(void); +/* Release a mobicore instance object and all objects related to it */ +int mc_release_instance(struct mc_instance *instance); + +/* + * mc_register_wsm_l2() - Create a L2 table from a virtual memory buffer which + * can be vmalloc or user space virtual memory + */ +int mc_register_wsm_l2(struct mc_instance *instance, + uint32_t buffer, uint32_t len, + uint32_t *handle, uint32_t *phys); +/* Unregister the buffer mapped above */ +int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle); + +/* Allocate one mc_buffer of contiguous space */ +int mc_get_buffer(struct mc_instance *instance, + struct mc_buffer **buffer, unsigned long len); +/* Free the buffer allocated above */ +int mc_free_buffer(struct mc_instance *instance, uint32_t handle); + +#endif /* _MC_MAIN_H_ */ diff --git a/drivers/gud/mobicore_driver/mc_drv_module.h b/drivers/gud/mobicore_driver/mc_drv_module.h deleted file mode 100644 index c540c940858..00000000000 --- a/drivers/gud/mobicore_driver/mc_drv_module.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * MobiCore Driver Kernel Module. - * - * Internal structures of the McDrvModule - * - * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _MC_DRV_MODULE_H -#define _MC_DRV_MODULE_H - -#include -#include - -#include "public/mc_drv_module_api.h" - -/* Platform specific settings */ -#include "platform.h" - -/* - * ARM Trustzone specific masks and modes - * Vanilla Linux is unaware of TrustZone extension. - * I.e. arch/arm/include/asm/ptrace.h does not define monitor mode. - * Also TZ bits in cpuid is not defined, ARM port uses magic numbers, - * see arch/arm/kernel/setup.c - */ -#define ARM_MONITOR_MODE (0b10110) -#define ARM_SECURITY_EXTENSION_MASK 0x30 - -/* - * Contiguous buffer allocated to TLCs. - * These buffers are uses as world shared memory (wsm) and shared with - * secure world. - * The virtual kernel address is added for a simpler search algorithm. - */ -struct mc_contg_buffer { - unsigned int handle; /* unique handle */ - void *virt_user_addr; /* virtual User start address */ - - /* virtual kernel start address */ - void *virt_kernel_addr; - - void *phys_addr; /* physical start address */ - unsigned int order; /* order of number of pages */ -}; - -/* - * Maximum number of contiguous buffer allocations that one process can get via - * mmap - */ -#define MC_DRV_KMOD_CONTG_BUFFER_MAX 16 - -/* Instance data for MobiCore Daemon and TLCs. */ -struct mc_instance { - /* unique handle */ - unsigned int handle; - /* process that opened this instance */ - pid_t pid_vnr; - - /* - * buffer list for mmap generated address space and its virtual client - * address - */ - struct mc_contg_buffer contg_buffers[MC_DRV_KMOD_CONTG_BUFFER_MAX]; -}; - -/* - * MobiCore specific page tables for world shared memory. - * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level. - * MobiCore uses the default ARM format. - * - * Number of page table entries in one L2 table. This is ARM specific, an - * L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each. - */ -#define MC_ARM_L2_TABLE_ENTRIES 256 - -/* ARM level 2 (L2) table with 256 entries. Size: 1k */ -struct l2table { - pte_t table_entries[MC_ARM_L2_TABLE_ENTRIES]; -}; - -/* Number of pages for L2 tables. There are 4 table in each page. */ -#define MC_DRV_KMOD_L2_TABLE_PER_PAGES 4 - -/* Store for four L2 tables in one 4kb page*/ -struct mc_l2_table_store { - struct l2table table[MC_DRV_KMOD_L2_TABLE_PER_PAGES]; -}; - -/* Usage and maintenance information about mc_l2_table_store */ -struct mc_l2_tables_set { - struct list_head list; - unsigned int usage_bitmap; /* usage bitmap */ - - /* kernel virtual address */ - struct mc_l2_table_store *kernel_virt; - struct mc_l2_table_store *phys; /* physical address */ - - /* pointer to page struct */ - struct page *page; -}; - -/* - * L2 table allocated to the Daemon or a TLC describing a world shared buffer. - * When users map a malloc()ed area into SWd, a L2 table is allocated. - * In addition, the area of maximum 1MB virtual address space is mapped into - * the L2 table and a handle for this table is returned to the user. - */ -struct mc_used_l2_table { - struct list_head list; - - /* handle as communicated to user mode */ - unsigned int handle; - unsigned int flags; - - /* owner of this L2 table */ - struct mc_instance *owner; - - /* set describing where our L2 table is stored */ - struct mc_l2_tables_set *set; - - /* index into L2 table set */ - unsigned int idx; - - /* size of buffer */ - unsigned int nr_of_pages; -}; - -#define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP (1U << 0) -#define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC (1U << 1) - -/* MobiCore S-SIQ interrupt context data. */ -struct mc_ssiq_ctx { - /* S-SIQ interrupt counter */ - atomic_t counter; -}; - -/* MobiCore Daemon context data. */ -struct mc_daemon_ctx { - /* event semaphore */ - struct semaphore sem; - struct fasync_struct *async_queue; - /* event counter */ - unsigned int ssiq_counter; -}; - -/* MobiCore Driver Kernel Module context data. */ -struct mc_drv_kmod_ctx { - - /* ever incrementing counter */ - atomic_t unique_counter; - - /* S-SIQ interrupt context */ - struct mc_ssiq_ctx ssiq_ctx; - - /* MobiCore Daemon context */ - struct mc_daemon_ctx daemon_ctx; - - /* pointer to instance of daemon */ - struct mc_instance *daemon_inst; - - /* Backing store for L2 tables */ - struct list_head mc_l2_tables_sets; - - /* Bookkeeping for used L2 tables */ - struct list_head mc_used_l2_tables; - - /* semaphore to synchronize access to above lists */ - struct semaphore wsm_l2_sem; -}; - -/* MobiCore internal trace buffer structure. */ -struct mc_trace_buf { - uint32_t version; /* version of trace buffer */ - uint32_t length; /* len of allocated buffer(includes header) */ - uint32_t write_pos; /* last write position */ - char buff[1]; /* start of the log buffer */ -}; - -/* MobiCore internal trace log setup. */ -void mobicore_log_read(void); -long mobicore_log_setup(void *); -void mobicore_log_free(void); - -/* Found in main.c */ -extern struct device *mcd; - -#define MCDRV_DBG_ERROR(dev, txt, ...) \ - dev_err(dev, "[%d] %s() ### ERROR: " txt, \ - task_pid_vnr(current), \ - __func__, \ - ##__VA_ARGS__) - -/* dummy function helper macro. */ -#define DUMMY_FUNCTION() do {} while (0) - -#if defined(DEBUG) -#if defined(DEBUG_VERBOSE) -#define MCDRV_DBG_VERBOSE MCDRV_DBG -#else -#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() -#endif - -#define MCDRV_DBG(dev, txt, ...) \ - dev_info(dev, "[%d on CPU%d] %s(): " txt, \ - task_pid_vnr(current), \ - raw_smp_processor_id(), \ - __func__, \ - ##__VA_ARGS__) - -#define MCDRV_DBG_WARN(dev, txt, ...) \ - dev_warn(dev, "[%d] %s() WARNING: " txt, \ - task_pid_vnr(current), \ - __func__, \ - ##__VA_ARGS__) - -#define MCDRV_ASSERT(cond) \ - do { \ - if (unlikely(!(cond))) { \ - panic("Assertion failed: %s:%d\n", \ - __FILE__, __LINE__); \ - } \ - } while (0) - -#else - -#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() -#define MCDRV_DBG(...) DUMMY_FUNCTION() -#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION() - -#define MCDRV_ASSERT(...) DUMMY_FUNCTION() - -#endif /* [not] defined(DEBUG) */ - -#endif /* _MC_DRV_MODULE_H */ diff --git a/drivers/gud/mobicore_driver/mc_drv_module_android.h b/drivers/gud/mobicore_driver/mc_drv_module_android.h deleted file mode 100644 index d6f216138ef..00000000000 --- a/drivers/gud/mobicore_driver/mc_drv_module_android.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Header file of MobiCore Driver Kernel Module. - * - * Android specific defines - * - * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _MC_DRV_MODULE_ANDROID_H_ -#define _MC_DRV_MODULE_ANDROID_H_ - -#ifdef CONFIG_ANDROID -/* - * Defines needed to identify the Daemon in Android systems - * For the full list see: - * platform_system_core/include/private/android_filesystem_config.h in the - * Android source tree - */ - -/* traditional unix root user */ -#define AID_ROOT 0 -/* system server */ -#define AID_SYSTEM 1000 -/* access to misc storage */ -#define AID_MISC 9998 -#define AID_NOBODY 9999 -/* first app user */ -#define AID_APP 10000 - -#endif /* CONFIG_ANDROID */ - -#endif /* _MC_DRV_MODULE_ANDROID_H_ */ - diff --git a/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h b/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h deleted file mode 100644 index 0d4f92c1cc1..00000000000 --- a/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Header file of MobiCore Driver Kernel Module. - * - * MobiCore Fast Call interface - * - * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _MC_DRV_MODULE_FASTCALLS_H_ -#define _MC_DRV_MODULE_FASTCALLS_H_ - -#include "mc_drv_module.h" - -/* - * MobiCore SMCs - */ -enum mc_smc_codes { - MC_SMC_N_YIELD = 0x3, /* Yield to switch from NWd to SWd. */ - MC_SMC_N_SIQ = 0x4 /* SIQ to switch from NWd to SWd. */ -}; - -/* - * MobiCore fast calls. See MCI documentation - */ -enum mc_fast_call_codes { - MC_FC_INIT = -1, - MC_FC_INFO = -2, - MC_FC_POWER = -3, - MC_FC_DUMP = -4, - MC_FC_NWD_TRACE = -31 /* Mem trace setup fastcall */ -}; - -/* - * return code for fast calls - */ -enum mc_fast_calls_result { - MC_FC_RET_OK = 0, - MC_FC_RET_ERR_INVALID = 1, - MC_FC_RET_ERR_ALREADY_INITIALIZED = 5 -}; - -/* structure wrappers for specific fastcalls */ - -/* generic fast call parameters */ -union fc_generic { - struct { - uint32_t cmd; - uint32_t param[3]; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t param[2]; - } as_out; -}; - -/* fast call init */ -union mc_fc_init { - union fc_generic as_generic; - struct { - uint32_t cmd; - uint32_t base; - uint32_t nq_info; - uint32_t mcp_info; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t rfu[2]; - } as_out; -}; - -/* fast call info parameters */ -union mc_fc_info { - union fc_generic as_generic; - struct { - uint32_t cmd; - uint32_t ext_info_id; - uint32_t rfu[2]; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t state; - uint32_t ext_info; - } as_out; -}; - -/* fast call S-Yield parameters */ -union mc_fc_s_yield { - union fc_generic as_generic; - struct { - uint32_t cmd; - uint32_t rfu[3]; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t rfu[2]; - } as_out; -}; - -/* fast call N-SIQ parameters */ -union mc_fc_nsiq { - union fc_generic as_generic; - struct { - uint32_t cmd; - uint32_t rfu[3]; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t rfu[2]; - } as_out; -}; - -/** - * mc_fastcall() - fast call to MobiCore - * - * @fc_generic: pointer to fast call data - */ -static inline void mc_fastcall(union fc_generic *fc_generic) -{ - MCDRV_ASSERT(fc_generic != NULL); - - /* - * We only expect to make smc calls on CPU0 otherwise something wrong - * will happen - */ - MCDRV_ASSERT(raw_smp_processor_id() == 0); - - /* Required by an old version of MobiCore, subject to be removed. */ - mb(); -#ifdef MC_SMC_FASTCALL - { - int ret = 0; - ret = smc_fastcall((void *)fc_generic, sizeof(*fc_generic)); - } -#else - { - /* SVC expect values in r0-r3 */ - register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd; - register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0]; - register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1]; - register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2]; - - /* one of the famous preprocessor hacks to stingitize things.*/ -#define __STR2(x) (#x) -#define __STR(x) __STR2(x) - - /* - * Compiler does not support certain instructions - * "SMC": secure monitor call - */ -#define ASM_ARM_SMC 0xE1600070 - /* - * "BPKT": debugging breakpoint. - * We keep this, as is comes quite handy for debugging. - */ -#define ASM_ARM_BPKT 0xE1200070 -#define ASM_THUMB_BPKT 0xBE00 - - - __asm__ volatile ( - ".word " __STR(ASM_ARM_SMC) "\n" - : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3) - ); - - /* set response */ - fc_generic->as_out.resp = reg0; - fc_generic->as_out.ret = reg1; - fc_generic->as_out.param[0] = reg2; - fc_generic->as_out.param[1] = reg3; - } -#endif -} - -/* - * convert fast call return code to linux driver module error code - */ -static inline int convert_fc_ret(uint32_t sret) -{ - int ret = -EFAULT; - - switch (sret) { - case MC_FC_RET_OK: - ret = 0; - break; - case MC_FC_RET_ERR_INVALID: - ret = -EINVAL; - break; - case MC_FC_RET_ERR_ALREADY_INITIALIZED: - ret = -EBUSY; - break; - default: - break; - } - return ret; -} - -#endif /* _MC_DRV_MODULE_FASTCALLS_H_ */ diff --git a/drivers/gud/mobicore_driver/mem.c b/drivers/gud/mobicore_driver/mem.c new file mode 100644 index 00000000000..da711ce7725 --- /dev/null +++ b/drivers/gud/mobicore_driver/mem.c @@ -0,0 +1,696 @@ +/* + * MobiCore Driver Kernel Module. + * + * This module is written as a Linux device driver. + * This driver represents the command proxy on the lowest layer, from the + * secure world to the non secure world, and vice versa. + * This driver is located in the non secure world (Linux). + * This driver offers IOCTL commands, for access to the secure world, and has + * the interface from the secure world to the normal world. + * The access to the driver is possible with a file descriptor, + * which has to be created by the fd = open(/dev/mobicore) command. + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "main.h" +#include "debug.h" +#include "mem.h" + +#include +#include +#include +#include +#include + + +/* MobiCore memory context data */ +struct mc_mem_context mem_ctx; + +/* convert L2 PTE to page pointer */ +static inline struct page *l2_pte_to_page(pte_t pte) +{ + unsigned long phys_page_addr = ((unsigned long)pte & PAGE_MASK); + unsigned int pfn = phys_page_addr >> PAGE_SHIFT; + struct page *page = pfn_to_page(pfn); + return page; +} + +/* convert page pointer to L2 PTE */ +static inline pte_t page_to_l2_pte(struct page *page) +{ + unsigned long pfn = page_to_pfn(page); + unsigned long phys_addr = (pfn << PAGE_SHIFT); + pte_t pte = (pte_t)(phys_addr & PAGE_MASK); + return pte; +} + +static inline void release_page(struct page *page) +{ + SetPageDirty(page); + + page_cache_release(page); +} + +static int lock_pages(struct task_struct *task, void *virt_start_page_addr, + int pages_no, struct page **pages) +{ + int locked_pages; + + /* lock user pages, must hold the mmap_sem to do this. */ + down_read(&(task->mm->mmap_sem)); + locked_pages = get_user_pages( + task, + task->mm, + (unsigned long)virt_start_page_addr, + pages_no, + 1, /* write access */ + 0, + pages, + NULL); + up_read(&(task->mm->mmap_sem)); + + /* check if we could lock all pages. */ + if (locked_pages != pages_no) { + MCDRV_DBG_ERROR(mcd, "get_user_pages() failed, locked_pages=%d", + locked_pages); + if (locked_pages > 0) { + /* release all locked pages. */ + release_pages(pages, locked_pages, 0); + } + return -ENOMEM; + } + + return 0; +} + +/* Get kernel pointer to shared L2 table given a per-process reference */ +struct l2table *get_l2_table_kernel_virt(struct mc_l2_table *table) +{ + if (WARN(!table, "Invalid L2 table")) + return NULL; + + if (WARN(!table->set, "Invalid L2 table set")) + return NULL; + + if (WARN(!table->set->kernel_virt, "Invalid L2 pointer")) + return NULL; + + return &(table->set->kernel_virt->table[table->idx]); +} + +/* Get physical address of a shared L2 table given a per-process reference */ +struct l2table *get_l2_table_phys(struct mc_l2_table *table) +{ + if (WARN(!table, "Invalid L2 table")) + return NULL; + if (WARN(!table->set, "Invalid L2 table set")) + return NULL; + if (WARN(!table->set->kernel_virt, "Invalid L2 phys pointer")) + return NULL; + + return &(table->set->phys->table[table->idx]); +} + +static inline int in_use(struct mc_l2_table *table) +{ + return atomic_read(&table->usage) > 0; +} + +/* + * Search the list of used l2 tables and return the one with the handle. + * Assumes the table_lock is taken. + */ +struct mc_l2_table *find_l2_table(unsigned int handle) +{ + struct mc_l2_table *table; + + list_for_each_entry(table, &mem_ctx.l2_tables, list) { + if (table->handle == handle) + return table; + } + return NULL; +} + +/* + * Allocate a new l2 table store plus L2_TABLES_PER_PAGE in the l2 free tables + * list. Assumes the table_lock is already taken by the caller above. + */ +static int alloc_table_store(void) +{ + unsigned long store; + struct mc_l2_tables_set *l2table_set; + struct mc_l2_table *l2table, *l2table2; + struct page *page; + int ret = 0, i; + /* temp list for holding the l2 tables */ + LIST_HEAD(temp); + + store = get_zeroed_page(GFP_KERNEL); + if (!store) + return -ENOMEM; + + /* + * Actually, locking is not necessary, because kernel + * memory is not supposed to get swapped out. But we + * play safe.... + */ + page = virt_to_page(store); + SetPageReserved(page); + + /* add all the descriptors to the free descriptors list */ + l2table_set = kmalloc(sizeof(*l2table_set), GFP_KERNEL | __GFP_ZERO); + if (l2table_set == NULL) { + ret = -ENOMEM; + goto free_store; + } + /* initialize */ + l2table_set->kernel_virt = (void *)store; + l2table_set->page = page; + l2table_set->phys = (void *)virt_to_phys((void *)store); + /* the set is not yet used */ + atomic_set(&l2table_set->used_tables, 0); + + /* init add to list. */ + INIT_LIST_HEAD(&(l2table_set->list)); + list_add(&l2table_set->list, &mem_ctx.l2_tables_sets); + + for (i = 0; i < L2_TABLES_PER_PAGE; i++) { + /* allocate a WSM L2 descriptor */ + l2table = kmalloc(sizeof(*l2table), GFP_KERNEL | __GFP_ZERO); + if (l2table == NULL) { + ret = -ENOMEM; + MCDRV_DBG_ERROR(mcd, "out of memory\n"); + /* Free the full temp list and the store in this case */ + goto free_temp_list; + } + + /* set set reference */ + l2table->set = l2table_set; + l2table->idx = i; + l2table->virt = get_l2_table_kernel_virt(l2table); + l2table->phys = (unsigned long)get_l2_table_phys(l2table); + atomic_set(&l2table->usage, 0); + + /* add to temp list. */ + INIT_LIST_HEAD(&l2table->list); + list_add_tail(&l2table->list, &temp); + } + + /* + * If everything went ok then merge the temp list with the global + * free list + */ + list_splice_tail(&temp, &mem_ctx.free_l2_tables); + return 0; +free_temp_list: + list_for_each_entry_safe(l2table, l2table2, &temp, list) { + kfree(l2table); + } + + list_del(&l2table_set->list); + +free_store: + free_page(store); + return ret; + +} +/* + * Get a l2 table from the free tables list or allocate a new one and + * initialize it. Assumes the table_lock is already taken. + */ +static struct mc_l2_table *alloc_l2_table(struct mc_instance *instance) +{ + int ret = 0; + struct mc_l2_table *table = NULL; + + if (list_empty(&mem_ctx.free_l2_tables)) { + ret = alloc_table_store(); + if (ret) { + MCDRV_DBG_ERROR(mcd, "Failed to allocate new store!"); + return ERR_PTR(-ENOMEM); + } + /* if it's still empty something wrong has happened */ + if (list_empty(&mem_ctx.free_l2_tables)) { + MCDRV_DBG_ERROR(mcd, + "Free list not updated correctly!"); + return ERR_PTR(-EFAULT); + } + } + + /* get a WSM L2 descriptor */ + table = list_first_entry(&mem_ctx.free_l2_tables, + struct mc_l2_table, list); + if (table == NULL) { + MCDRV_DBG_ERROR(mcd, "out of memory\n"); + return ERR_PTR(-ENOMEM); + } + /* Move it to the used l2 tables list */ + list_move_tail(&table->list, &mem_ctx.l2_tables); + + table->handle = get_unique_id(); + table->owner = instance; + + atomic_inc(&table->set->used_tables); + atomic_inc(&table->usage); + + MCDRV_DBG_VERBOSE(mcd, + "chunkPhys=%p,idx=%d", table->set->phys, table->idx); + + return table; +} + +/* + * Frees the object associated with a l2 table. Initially the object is moved + * to the free tables list, but if all the 4 lists of the store are free + * then the store is also released. + * Assumes the table_lock is already taken. + */ +static void free_l2_table(struct mc_l2_table *table) +{ + struct mc_l2_tables_set *l2table_set; + + if (WARN(!table, "Invalid table")) + return; + + l2table_set = table->set; + if (WARN(!l2table_set, "Invalid table set")) + return; + + list_move_tail(&table->list, &mem_ctx.free_l2_tables); + + /* if nobody uses this set, we can release it. */ + if (atomic_dec_and_test(&l2table_set->used_tables)) { + struct mc_l2_table *tmp; + + /* remove from list */ + list_del(&l2table_set->list); + /* + * All the l2 tables are in the free list for this set + * so we can just remove them from there + */ + list_for_each_entry_safe(table, tmp, &mem_ctx.free_l2_tables, + list) { + if (table->set == l2table_set) { + list_del(&table->list); + kfree(table); + } + } /* end while */ + + /* + * We shouldn't recover from this since it was some data + * corruption before + */ + BUG_ON(!l2table_set->page); + ClearPageReserved(l2table_set->page); + + BUG_ON(!l2table_set->kernel_virt); + free_page((unsigned long)l2table_set->kernel_virt); + + kfree(l2table_set); + } +} + +/* + * Create a L2 table in a WSM container that has been allocates previously. + * Assumes the table lock is already taken or there is no need to take like + * when first creating the l2 table the full list is locked. + * + * @task pointer to task owning WSM + * @wsm_buffer user space WSM start + * @wsm_len WSM length + * @table Pointer to L2 table details + */ +static int map_buffer(struct task_struct *task, void *wsm_buffer, + unsigned int wsm_len, struct mc_l2_table *table) +{ + int ret = 0; + unsigned int i, nr_of_pages; + /* start address of the 4 KiB page of wsm_buffer */ + void *virt_addr_page; + struct page *page; + struct l2table *l2table; + struct page **l2table_as_array_of_pointers_to_page; + /* page offset in wsm buffer */ + unsigned int offset; + + if (WARN(!wsm_buffer, "Invalid WSM buffer pointer")) + return -EINVAL; + + if (WARN(wsm_len == 0, "Invalid WSM buffer length")) + return -EINVAL; + + if (WARN(!table, "Invalid mapping table for WSM")) + return -EINVAL; + + /* no size > 1Mib supported */ + if (wsm_len > SZ_1M) { + MCDRV_DBG_ERROR(mcd, "size > 1 MiB\n"); + return -EINVAL; + } + + MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x\n", wsm_buffer, + wsm_len); + + /* + * Check if called from kernel space and if + * wsm_buffer is actually vmalloced or not + */ + if (task == NULL && !is_vmalloc_addr(wsm_buffer)) { + MCDRV_DBG_ERROR(mcd, "WSM addr is not a vmalloc address"); + return -EINVAL; + } + + /* calculate page usage */ + virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK); + offset = (unsigned int) (((unsigned long)(wsm_buffer)) & (~PAGE_MASK)); + nr_of_pages = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE; + + MCDRV_DBG_VERBOSE(mcd, "virt addr page start=0x%p, pages=%d\n", + virt_addr_page, nr_of_pages); + + /* L2 table can hold max 1MiB in 256 pages. */ + if ((nr_of_pages * PAGE_SIZE) > SZ_1M) { + MCDRV_DBG_ERROR(mcd, "WSM paged exceed 1 MiB\n"); + return -EINVAL; + } + + l2table = table->virt; + /* + * We use the memory for the L2 table to hold the pointer + * and convert them later. This works, as everything comes + * down to a 32 bit value. + */ + l2table_as_array_of_pointers_to_page = (struct page **)l2table; + + /* Request comes from user space */ + if (task != NULL && !is_vmalloc_addr(wsm_buffer)) { + /* + * lock user page in memory, so they do not get swapped + * out. + * REV axh: Kernel 2.6.27 added a new get_user_pages_fast() + * function, maybe it is called fast_gup() in some versions. + * handle user process doing a fork(). + * Child should not get things. + * http://osdir.com/ml/linux-media/2009-07/msg00813.html + * http://lwn.net/Articles/275808/ + */ + ret = lock_pages(task, virt_addr_page, nr_of_pages, + l2table_as_array_of_pointers_to_page); + if (ret != 0) { + MCDRV_DBG_ERROR(mcd, "lock_user_pages() failed\n"); + return ret; + } + } + /* Request comes from kernel space(vmalloc buffer) */ + else { + void *uaddr = wsm_buffer; + for (i = 0; i < nr_of_pages; i++) { + page = vmalloc_to_page(uaddr); + if (!page) { + MCDRV_DBG_ERROR(mcd, "failed to map address"); + return -EINVAL; + } + get_page(page); + l2table_as_array_of_pointers_to_page[i] = page; + uaddr += PAGE_SIZE; + } + } + + table->pages = nr_of_pages; + + /* + * create L2 Table entries. + * used_l2table->table contains a list of page pointers here. + * For a proper cleanup we have to ensure that the following + * code either works and used_l2table contains a valid L2 table + * - or fails and used_l2table->table contains the list of page + * pointers. + * Any mixed contents will make cleanup difficult. + */ + for (i = 0; i < nr_of_pages; i++) { + pte_t pte; + page = l2table_as_array_of_pointers_to_page[i]; + + /* + * create L2 table entry, see ARM MMU docu for details + * about flags stored in the lowest 12 bits. + * As a side reference, the Article + * "ARM's multiply-mapped memory mess" + * found in the collection at + * http://lwn.net/Articles/409032/ + * is also worth reading. + */ + pte = page_to_l2_pte(page) + | PTE_EXT_AP1 | PTE_EXT_AP0 + | PTE_CACHEABLE | PTE_BUFFERABLE + | PTE_TYPE_SMALL | PTE_TYPE_EXT | PTE_EXT_NG; + /* + * Linux uses different mappings for SMP systems(the + * sharing flag is set for the pte. In order not to + * confuse things too much in Mobicore make sure the + * shared buffers have the same flags. + * This should also be done in SWD side + */ +#ifdef CONFIG_SMP + pte |= PTE_EXT_SHARED | PTE_EXT_TEX(1); +#endif + + l2table->table_entries[i] = pte; + MCDRV_DBG_VERBOSE(mcd, "L2 entry %d: 0x%08x\n", i, + (unsigned int)(pte)); + } + + /* ensure rest of table is empty */ + while (i < 255) + l2table->table_entries[i++] = (pte_t)0; + + + return ret; +} + +/* + * Remove a L2 table in a WSM container. Afterwards the container may be + * released. Assumes the table_lock and the lock is taken. + */ +static void unmap_buffers(struct mc_l2_table *table) +{ + struct l2table *l2table; + int i; + + if (WARN_ON(!table)) + return; + + /* found the table, now release the resources. */ + MCDRV_DBG_VERBOSE(mcd, "clear L2 table, phys_base=%p, nr_of_pages=%d\n", + (void *)table->phys, table->pages); + + l2table = table->virt; + + /* release all locked user space pages */ + for (i = 0; i < table->pages; i++) { + /* convert physical entries from L2 table to page pointers */ + pte_t pte = l2table->table_entries[i]; + struct page *page = l2_pte_to_page(pte); + release_page(page); + } + + /* remember that all pages have been freed */ + table->pages = 0; +} + +/* Delete a used l2 table. Assumes the table_lock and the lock is taken */ +static void unmap_l2_table(struct mc_l2_table *table) +{ + /* Check if it's not locked by other processes too! */ + if (!atomic_dec_and_test(&table->usage)) + return; + + /* release if Nwd and Swd/MC do no longer use it. */ + unmap_buffers(table); + free_l2_table(table); +} + +int mc_free_l2_table(struct mc_instance *instance, uint32_t handle) +{ + struct mc_l2_table *table; + int ret = 0; + + if (WARN(!instance, "No instance data available")) + return -EFAULT; + + mutex_lock(&mem_ctx.table_lock); + table = find_l2_table(handle); + + if (table == NULL) { + MCDRV_DBG_VERBOSE(mcd, "entry not found"); + ret = -EINVAL; + goto err_unlock; + } + if (instance != table->owner && !is_daemon(instance)) { + MCDRV_DBG_ERROR(mcd, "instance does no own it"); + ret = -EPERM; + goto err_unlock; + } + /* free table (if no further locks exist) */ + unmap_l2_table(table); +err_unlock: + mutex_unlock(&mem_ctx.table_lock); + + return ret; +} + +int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle) +{ + int ret = 0; + struct mc_l2_table *table = NULL; + + if (WARN(!instance, "No instance data available")) + return -EFAULT; + + mutex_lock(&mem_ctx.table_lock); + table = find_l2_table(handle); + + if (table == NULL) { + MCDRV_DBG_VERBOSE(mcd, "entry not found %u\n", handle); + ret = -EINVAL; + goto table_err; + } + if (instance != table->owner && !is_daemon(instance)) { + MCDRV_DBG_ERROR(mcd, "instance does no own it\n"); + ret = -EPERM; + goto table_err; + } + + /* lock entry */ + atomic_inc(&table->usage); +table_err: + mutex_unlock(&mem_ctx.table_lock); + return ret; +} +/* + * Allocate L2 table and map buffer into it. + * That is, create respective table entries. + * Must hold Semaphore mem_ctx.wsm_l2_sem + */ +struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance, + struct task_struct *task, void *wsm_buffer, unsigned int wsm_len) +{ + int ret = 0; + struct mc_l2_table *table; + + if (WARN(!instance, "No instance data available")) + return ERR_PTR(-EFAULT); + + mutex_lock(&mem_ctx.table_lock); + table = alloc_l2_table(instance); + if (IS_ERR(table)) { + MCDRV_DBG_ERROR(mcd, "allocate_used_l2_table() failed\n"); + ret = -ENOMEM; + goto err_no_mem; + } + + /* create the L2 page for the WSM */ + ret = map_buffer(task, wsm_buffer, wsm_len, table); + + if (ret != 0) { + MCDRV_DBG_ERROR(mcd, "map_buffer() failed\n"); + unmap_l2_table(table); + goto err_no_mem; + } + MCDRV_DBG(mcd, "mapped buffer %p to table with handle %d @ %lx", + wsm_buffer, table->handle, table->phys); + + mutex_unlock(&mem_ctx.table_lock); + return table; +err_no_mem: + mutex_unlock(&mem_ctx.table_lock); + return ERR_PTR(ret); +} + +uint32_t mc_find_l2_table(struct mc_instance *instance, uint32_t handle) +{ + uint32_t ret = 0; + struct mc_l2_table *table = NULL; + + if (WARN(!instance, "No instance data available")) + return 0; + + mutex_lock(&mem_ctx.table_lock); + table = find_l2_table(handle); + + if (table == NULL) { + MCDRV_DBG_ERROR(mcd, "entry not found %u\n", handle); + ret = 0; + goto table_err; + } + + ret = table->phys; +table_err: + mutex_unlock(&mem_ctx.table_lock); + return ret; +} + +void mc_clean_l2_tables(void) +{ + struct mc_l2_table *table, *tmp; + + mutex_lock(&mem_ctx.table_lock); + /* Check if some WSM is orphaned. */ + list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) { + if (table->owner == NULL) { + MCDRV_DBG(mcd, + "clearing orphaned WSM L2: p=%lx pages=%d\n", + table->phys, table->pages); + unmap_l2_table(table); + } + } + mutex_unlock(&mem_ctx.table_lock); +} + +void mc_clear_l2_tables(struct mc_instance *instance) +{ + struct mc_l2_table *table, *tmp; + + mutex_lock(&mem_ctx.table_lock); + /* Check if some WSM is still in use. */ + list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) { + if (table->owner == instance) { + MCDRV_DBG(mcd, "release WSM L2: p=%lx pages=%d\n", + table->phys, table->pages); + /* unlock app usage and free or mark it as orphan */ + table->owner = NULL; + unmap_l2_table(table); + } + } + mutex_unlock(&mem_ctx.table_lock); +} + +int mc_init_l2_tables(void) +{ + /* init list for WSM L2 chunks. */ + INIT_LIST_HEAD(&mem_ctx.l2_tables_sets); + + /* L2 table descriptor list. */ + INIT_LIST_HEAD(&mem_ctx.l2_tables); + + /* L2 table descriptor list. */ + INIT_LIST_HEAD(&mem_ctx.free_l2_tables); + + mutex_init(&mem_ctx.table_lock); + + return 0; +} + +void mc_release_l2_tables() +{ + struct mc_l2_table *table; + /* Check if some WSM is still in use. */ + list_for_each_entry(table, &mem_ctx.l2_tables, list) { + WARN(1, "WSM L2 still in use: phys=%lx ,nr_of_pages=%d\n", + table->phys, table->pages); + } +} diff --git a/drivers/gud/mobicore_driver/mem.h b/drivers/gud/mobicore_driver/mem.h new file mode 100644 index 00000000000..a90662a7ba8 --- /dev/null +++ b/drivers/gud/mobicore_driver/mem.h @@ -0,0 +1,127 @@ +/* + * MobiCore driver module.(interface to the secure world SWD) + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MC_MEM_H_ +#define _MC_MEM_H_ + +#define FREE_FROM_SWD 1 +#define FREE_FROM_NWD 0 + +#define LOCKED_BY_APP (1U << 0) +#define LOCKED_BY_MC (1U << 1) + +/* + * MobiCore specific page tables for world shared memory. + * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level. + * MobiCore uses the default ARM format. + * + * Number of page table entries in one L2 table. This is ARM specific, an + * L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each. + */ +#define MC_ARM_L2_TABLE_ENTRIES 256 + +/* ARM level 2 (L2) table with 256 entries. Size: 1k */ +struct l2table { + pte_t table_entries[MC_ARM_L2_TABLE_ENTRIES]; +}; + +/* Number of pages for L2 tables. There are 4 table in each page. */ +#define L2_TABLES_PER_PAGE 4 + +/* Store for four L2 tables in one 4kb page*/ +struct mc_l2_table_store { + struct l2table table[L2_TABLES_PER_PAGE]; +}; + +/* Usage and maintenance information about mc_l2_table_store */ +struct mc_l2_tables_set { + struct list_head list; + /* kernel virtual address */ + struct mc_l2_table_store *kernel_virt; + /* physical address */ + struct mc_l2_table_store *phys; + /* pointer to page struct */ + struct page *page; + /* How many pages from this set are used */ + atomic_t used_tables; +}; + +/* + * L2 table allocated to the Daemon or a TLC describing a world shared buffer. + * When users map a malloc()ed area into SWd, a L2 table is allocated. + * In addition, the area of maximum 1MB virtual address space is mapped into + * the L2 table and a handle for this table is returned to the user. + */ +struct mc_l2_table { + struct list_head list; + /* Table lock */ + struct mutex lock; + /* handle as communicated to user mode */ + unsigned int handle; + /* Number of references kept to this l2 table */ + atomic_t usage; + /* owner of this L2 table */ + struct mc_instance *owner; + /* set describing where our L2 table is stored */ + struct mc_l2_tables_set *set; + /* index into L2 table set */ + unsigned int idx; + /* size of buffer */ + unsigned int pages; + /* virtual address*/ + void *virt; + unsigned long phys; +}; + +/* MobiCore Driver Memory context data. */ +struct mc_mem_context { + struct mc_instance *daemon_inst; + /* Backing store for L2 tables */ + struct list_head l2_tables_sets; + /* Bookkeeping for used L2 tables */ + struct list_head l2_tables; + /* Bookkeeping for free L2 tables */ + struct list_head free_l2_tables; + /* semaphore to synchronize access to above lists */ + struct mutex table_lock; +}; + +/* + * Allocate L2 table and map buffer into it. + * That is, create respective table entries. + */ +struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance, + struct task_struct *task, void *wsm_buffer, unsigned int wsm_len); + +/* Delete all the l2 tables associated with an instance */ +void mc_clear_l2_tables(struct mc_instance *instance); + +/* Release all orphaned L2 tables */ +void mc_clean_l2_tables(void); + +/* Delete a used l2 table. */ +int mc_free_l2_table(struct mc_instance *instance, uint32_t handle); + +/* + * Lock a l2 table - the daemon adds +1 to refcount of the L2 table + * marking it in use by SWD so it doesn't get released when the TLC dies. + */ +int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle); +/* Unlock l2 table. */ +int mc_unlock_l2_table(struct mc_instance *instance, uint32_t handle); +/* Return the phys address of l2 table. */ +uint32_t mc_find_l2_table(struct mc_instance *instance, uint32_t handle); +/* Release all used l2 tables to Linux memory space */ +void mc_release_l2_tables(void); + +/* Initialize all l2 tables structure */ +int mc_init_l2_tables(void); + +#endif /* _MC_MEM_H_ */ diff --git a/drivers/gud/mobicore_driver/ops.c b/drivers/gud/mobicore_driver/ops.c new file mode 100644 index 00000000000..509b4e9a98c --- /dev/null +++ b/drivers/gud/mobicore_driver/ops.c @@ -0,0 +1,143 @@ +/* + * MobiCore Driver Kernel Module. + * + * This module is written as a Linux device driver. + * This driver represents the command proxy on the lowest layer, from the + * secure world to the non secure world, and vice versa. + * This driver is located in the non secure world (Linux). + * This driver offers IOCTL commands, for access to the secure world, and has + * the interface from the secure world to the normal world. + * The access to the driver is possible with a file descriptor, + * which has to be created by the fd = open(/dev/mobicore) command. + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include "main.h" +#include "fastcall.h" +#include "ops.h" +#include "mem.h" +#include "debug.h" + +int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info) +{ + int ret = 0; + union mc_fc_info fc_info; + + MCDRV_DBG_VERBOSE(mcd, "enter\n"); + + memset(&fc_info, 0, sizeof(fc_info)); + fc_info.as_in.cmd = MC_FC_INFO; + fc_info.as_in.ext_info_id = ext_info_id; + + MCDRV_DBG(mcd, "fc_info <- cmd=0x%08x, ext_info_id=0x%08x\n", + fc_info.as_in.cmd, fc_info.as_in.ext_info_id); + + mc_fastcall(&(fc_info.as_generic)); + + MCDRV_DBG(mcd, + "fc_info -> r=0x%08x ret=0x%08x state=0x%08x ext_info=0x%08x", + fc_info.as_out.resp, + fc_info.as_out.ret, + fc_info.as_out.state, + fc_info.as_out.ext_info); + + ret = convert_fc_ret(fc_info.as_out.ret); + + *state = fc_info.as_out.state; + *ext_info = fc_info.as_out.ext_info; + + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); + + return ret; +} + +/* Yield to MobiCore */ +int mc_yield(void) +{ + int ret = 0; + union fc_generic yield; + + MCDRV_DBG_VERBOSE(mcd, "enter\n"); + + memset(&yield, 0, sizeof(yield)); + yield.as_in.cmd = MC_SMC_N_YIELD; + mc_fastcall(&yield); + ret = convert_fc_ret(yield.as_out.ret); + + return ret; +} + +/* call common notify */ +int mc_nsiq(void) +{ + int ret = 0; + union fc_generic nsiq; + MCDRV_DBG_VERBOSE(mcd, "enter\n"); + + memset(&nsiq, 0, sizeof(nsiq)); + nsiq.as_in.cmd = MC_SMC_N_SIQ; + mc_fastcall(&nsiq); + ret = convert_fc_ret(nsiq.as_out.ret); + + return ret; +} + +/* Call the INIT fastcall to setup MobiCore initialization */ +int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length, + uint32_t mcp_offset, uint32_t mcp_length) +{ + int ret = 0; + union mc_fc_init fc_init; + + MCDRV_DBG_VERBOSE(mcd, "enter\n"); + + memset(&fc_init, 0, sizeof(fc_init)); + + fc_init.as_in.cmd = MC_FC_INIT; + /* base address of mci buffer 4KB aligned */ + fc_init.as_in.base = base; + /* notification buffer start/length [16:16] [start, length] */ + fc_init.as_in.nq_info = (nq_offset << 16) | (nq_length & 0xFFFF); + /* mcp buffer start/length [16:16] [start, length] */ + fc_init.as_in.mcp_info = (mcp_offset << 16) | (mcp_length & 0xFFFF); + + /* + * Set KMOD notification queue to start of MCI + * mciInfo was already set up in mmap + */ + MCDRV_DBG(mcd, + "cmd=0x%08x, base=0x%08x,nq_info=0x%08x, mcp_info=0x%08x\n", + fc_init.as_in.cmd, fc_init.as_in.base, fc_init.as_in.nq_info, + fc_init.as_in.mcp_info); + + mc_fastcall(&fc_init.as_generic); + + MCDRV_DBG(mcd, "out cmd=0x%08x, ret=0x%08x\n", fc_init.as_out.resp, + fc_init.as_out.ret); + + ret = convert_fc_ret(fc_init.as_out.ret); + + MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); + + return ret; +} + +/* Return MobiCore driver version */ +uint32_t mc_get_version(void) +{ + MCDRV_DBG(mcd, "MobiCore driver version is %i.%i\n", + MCDRVMODULEAPI_VERSION_MAJOR, + MCDRVMODULEAPI_VERSION_MINOR); + + return MC_VERSION(MCDRVMODULEAPI_VERSION_MAJOR, + MCDRVMODULEAPI_VERSION_MINOR); +} diff --git a/drivers/gud/mobicore_driver/ops.h b/drivers/gud/mobicore_driver/ops.h new file mode 100644 index 00000000000..673399fef4d --- /dev/null +++ b/drivers/gud/mobicore_driver/ops.h @@ -0,0 +1,30 @@ +/* + * MobiCore driver module.(interface to the secure world SWD) + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MC_OPS_H_ +#define _MC_OPS_H_ + +#include +#include "fastcall.h" + +int mc_yield(void); +int mc_nsiq(void); +uint32_t mc_get_version(void); + +int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info); +int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length, + uint32_t mcp_offset, uint32_t mcp_length); + +static inline void mc_fastcall(void *data) +{ + work_on_cpu(0, _smc, data); +} + +#endif /* _MC_OPS_H_ */ diff --git a/drivers/gud/mobicore_driver/pm.h b/drivers/gud/mobicore_driver/pm.h new file mode 100644 index 00000000000..067f0953252 --- /dev/null +++ b/drivers/gud/mobicore_driver/pm.h @@ -0,0 +1,17 @@ +/* + * Header file of MobiCore Driver Kernel Module. + * + * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MC_PM_H_ +#define _MC_PM_H_ + +/* How much time after resume the daemon should back off */ +#define DAEMON_BACKOFF_TIME 10 + +#endif /* _MC_PM_H_ */ diff --git a/drivers/gud/mobicore_driver/public/mc_drv_module_api.h b/drivers/gud/mobicore_driver/public/mc_drv_module_api.h deleted file mode 100644 index fc6f69fb03e..00000000000 --- a/drivers/gud/mobicore_driver/public/mc_drv_module_api.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * The MobiCore Driver Kernel Module is a Linux device driver, which represents - * the command proxy on the lowest layer to the secure world (Swd). Additional - * services like memory allocation via mmap and generation of a L2 tables for - * given virtual memory are also supported. IRQ functionallity receives - * information from the SWd in the non secure world (NWd). - * As customary the driver is handled as linux device driver with "open", - * "close" and "ioctl" commands. Access to the driver is possible after the - * device "/dev/mobicore" has been opened. - * The MobiCore Driver Kernel Module must be installed via - * "insmod mcDrvModule.ko". - * - * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _MC_DRV_MODULE_API_H_ -#define _MC_DRV_MODULE_API_H_ - -#include "version.h" - -#define MC_DRV_MOD_DEVNODE "mobicore" -#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/" MC_DRV_MOD_DEVNODE - -/* - * Data exchange structure of the MC_DRV_MODULE_INIT ioctl command. - * INIT request data to SWD - */ -union mc_ioctl_init_params { - struct { - /* base address of mci buffer 4KB align */ - uint32_t base; - /* notification buffer start/length [16:16] [start, length] */ - uint32_t nq_offset; - /* length of notification queue */ - uint32_t nq_length; - /* mcp buffer start/length [16:16] [start, length] */ - uint32_t mcp_offset; - /* length of mcp buffer */ - uint32_t mcp_length; - } in; - struct { - /* nothing */ - } out; -}; - -/* - * Data exchange structure of the MC_DRV_MODULE_INFO ioctl command. - * INFO request data to the SWD - */ -union mc_ioctl_info_params { - struct { - uint32_t ext_info_id; /* extended info ID */ - } in; - struct { - uint32_t state; /* state */ - uint32_t ext_info; /* extended info */ - } out; -}; - -/* - * mmap allocates and maps contiguous memory into a process. - * We use the third parameter, void *offset, to distinguish between some cases - * offset = MC_DRV_KMOD_MMAP_WSM usual operation, pages are registered in - * device structure and freed later. - * offset = MC_DRV_KMOD_MMAP_MCI get Instance of MCI, allocates or mmaps - * the MCI to daemon - * offset = MC_DRV_KMOD_MMAP_PERSISTENTWSM special operation, without - * registration of pages - * - * In mmap(), the offset specifies which of several device I/O pages is - * requested. Linux only transfers the page number, i.e. the upper 20 bits to - * kernel module. Therefore we define our special offsets as multiples of page - * size. - */ -enum mc_mmap_memtype { - MC_DRV_KMOD_MMAP_WSM = 0, - MC_DRV_KMOD_MMAP_MCI = 4096, - MC_DRV_KMOD_MMAP_PERSISTENTWSM = 8192 -}; - -struct mc_mmap_resp { - uint32_t handle; /* WSN handle */ - uint32_t phys_addr; /* physical address of WSM (or NULL) */ - bool is_reused; /* if WSM memory was reused, or new allocated */ -}; - -/* - * Data exchange structure of the MC_DRV_KMOD_IOCTL_FREE ioctl command. - */ -union mc_ioctl_free_params { - struct { - uint32_t handle;/* driver handle */ - uint32_t pid; /* process id */ - } in; - struct { - /* nothing */ - } out; -}; - -/* - * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 - * command. - */ -union mc_ioctl_app_reg_wsm_l2_params { - struct { - uint32_t buffer; /* base address of the virtual address */ - uint32_t len; /* size of the virtual address space */ - uint32_t pid; /* process id */ - } in; - struct { - /* driver handle for locked memory */ - uint32_t handle; - - /* physical address of the L2 table */ - uint32_t phys_wsm_l2_table; - } out; -}; - - -/* - * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2 - * command. - */ -struct mc_ioctl_app_unreg_wsm_l2_params { - struct { - uint32_t handle; /* driver handle for locked memory */ - uint32_t pid; /* process id */ - } in; - struct { - /* nothing */ - } out; -}; - - -/* - * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 command. - */ -struct mc_ioctl_daemon_lock_wsm_l2_params { - struct { - uint32_t handle; /* driver handle for locked memory */ - } in; - struct { - uint32_t phys_wsm_l2_table; - } out; -}; - - -/* - * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2 - * command. - */ -struct mc_ioctl_daemon_unlock_wsm_l2_params { - struct { - uint32_t handle; /* driver handle for locked memory */ - } in; - struct { - /* nothing */ - } out; -}; - -/* - * Data exchange structure of the MC_DRV_MODULE_GET_VERSION ioctl command. - */ -struct mc_ioctl_get_version_params { - struct { - uint32_t kernel_module_version; - } out; -}; - -/* - * defines for the ioctl MobiCore driver module function call from user space. - */ -enum mc_kmod_ioctl { - - /* - * get detailed MobiCore Status - * internal, unsupported - */ - MC_DRV_KMOD_IOCTL_DUMP_STATUS = 200, - - /* - * initialize MobiCore - */ - MC_DRV_KMOD_IOCTL_FC_INIT = 201, - - /* - * get MobiCore status - */ - MC_DRV_KMOD_IOCTL_FC_INFO = 202, - - /* - * ioctl parameter to send the YIELD command to the SWD. - * Only possible in Privileged Mode. - * ioctl(fd, MC_DRV_MODULE_YIELD) - */ - MC_DRV_KMOD_IOCTL_FC_YIELD = 203, - - /* - * ioctl parameter to send the NSIQ signal to the SWD. - * Only possible in Privileged Mode - * ioctl(fd, MC_DRV_MODULE_NSIQ) - */ - MC_DRV_KMOD_IOCTL_FC_NSIQ = 204, - - /* - * ioctl parameter to tzbsp to start Mobicore binary from DDR. - * Only possible in Privileged Mode - * ioctl(fd, MC_DRV_KMOD_IOCTL_FC_EXECUTE) - * internal, unsupported - */ - MC_DRV_KMOD_IOCTL_FC_EXECUTE = 205, - - /* - * Free's memory which is formerly allocated by the driver's mmap - * command. The parameter must be this mmaped address. - * The internal instance data regarding to this address are deleted as - * well as each according memory page and its appropriated reserved bit - * is cleared (ClearPageReserved). - * Usage: ioctl(fd, MC_DRV_MODULE_FREE, &address) with address beeing of - * type long address - */ - MC_DRV_KMOD_IOCTL_FREE = 218, - - /* - * Creates a L2 Table of the given base address and the size of the - * data. - * Parameter: mc_ioctl_app_reg_wsm_l2_params - */ - MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 = 220, - - /* - * Frees the L2 table created by a MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 - * ioctl. - * Parameter: mc_ioctl_app_unreg_wsm_l2_params - */ - MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2 = 221, - - /* - * Locked memory is still in use by SWd. - * internal, unsupported - */ - MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 = 222, - MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2 = 223, - - /* - * Return kernel driver version. - * Parameter: mc_ioctl_get_version_params - */ - MC_DRV_KMOD_IOCTL_GET_VERSION = 224, -}; - - -#endif /* _MC_DRV_MODULE_API_H_ */ diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/mobicore_driver/public/mc_kernel_api.h index 6408776e1d5..7a038c4fd0d 100644 --- a/drivers/gud/mobicore_driver/public/mc_kernel_api.h +++ b/drivers/gud/mobicore_driver/public/mc_kernel_api.h @@ -1,5 +1,5 @@ /* - * Interface to Mobicore Driver Kernel Module inside Kernel. + * Interface to be used by module MobiCoreKernelAPI. * * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> * @@ -13,14 +13,14 @@ struct mc_instance; -/** +/* * mobicore_open() - Initialize a new MobiCore API instance object * * Returns a MobiCore Instance or NULL if no allocation was possible. */ struct mc_instance *mobicore_open(void); -/** +/* * mobicore_release() - Release a MobiCore instance object * @instance: MobiCore instance * @@ -28,7 +28,7 @@ struct mc_instance *mobicore_open(void); */ int mobicore_release(struct mc_instance *instance); -/** +/* * mobicore_allocate_wsm() - Allocate MobiCore WSM * @instance: instance data for MobiCore Daemon and TLCs * @requested_size: memory size requested in bytes @@ -39,35 +39,32 @@ int mobicore_release(struct mc_instance *instance); * Returns 0 if OK */ int mobicore_allocate_wsm(struct mc_instance *instance, - unsigned long requested_size, - uint32_t *handle, - void **kernel_virt_addr, - void **phys_addr); + unsigned long requested_size, uint32_t *handle, + void **virt_kernel_addr, void **phys_addr); -/** +/* * mobicore_free() - Free a WSM buffer allocated with mobicore_allocate_wsm * @instance: instance data for MobiCore Daemon and TLCs * @handle: handle of the buffer * * Returns 0 if OK */ -int mobicore_free(struct mc_instance *instance, uint32_t handle); +int mobicore_free_wsm(struct mc_instance *instance, uint32_t handle); -/** +/* * mobicore_map_vmem() - Map a virtual memory buffer structure to Mobicore * @instance: instance data for MobiCore Daemon and TLCs * @addr: address of the buffer (NB it must be kernel virtual!) * @len: buffer length (in bytes) * @handle: unique handle - * @phys_wsm_l2_table: pointer for physical address of L2 table + * @phys: pointer for physical address of L2 table * * Returns 0 if no error */ int mobicore_map_vmem(struct mc_instance *instance, void *addr, - uint32_t len, uint32_t *handle, - void **phys_wsm_l2_table); + uint32_t len, uint32_t *handle, uint32_t *phys); -/** +/* * mobicore_unmap_vmem() - Unmap a virtual memory buffer from MobiCore * @instance: instance data for MobiCore Daemon and TLCs * @handle: unique handle diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/mobicore_driver/public/mc_linux.h new file mode 100644 index 00000000000..99b77690a31 --- /dev/null +++ b/drivers/gud/mobicore_driver/public/mc_linux.h @@ -0,0 +1,209 @@ +/* + * The MobiCore Driver Kernel Module is a Linux device driver, which represents + * the command proxy on the lowest layer to the secure world (Swd). Additional + * services like memory allocation via mmap and generation of a L2 tables for + * given virtual memory are also supported. IRQ functionality receives + * information from the SWd in the non secure world (NWd). + * As customary the driver is handled as linux device driver with "open", + * "close" and "ioctl" commands. Access to the driver is possible after the + * device "/dev/mobicore" has been opened. + * The MobiCore Driver Kernel Module must be installed via + * "insmod mcDrvModule.ko". + * + * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MC_LINUX_H_ +#define _MC_LINUX_H_ + +#include "version.h" + +#define MC_ADMIN_DEVNODE "mobicore" +#define MC_USER_DEVNODE "mobicore-user" + +/* + * Data exchange structure of the MC_DRV_MODULE_INIT ioctl command. + * INIT request data to SWD + */ +struct mc_ioctl_init { + /* notification buffer start/length [16:16] [start, length] */ + uint32_t nq_offset; + /* length of notification queue */ + uint32_t nq_length; + /* mcp buffer start/length [16:16] [start, length] */ + uint32_t mcp_offset; + /* length of mcp buffer */ + uint32_t mcp_length; +}; + +/* + * Data exchange structure of the MC_DRV_MODULE_INFO ioctl command. + * INFO request data to the SWD + */ +struct mc_ioctl_info { + uint32_t ext_info_id; /* extended info ID */ + uint32_t state; /* state */ + uint32_t ext_info; /* extended info */ +}; + +/* + * Data exchange structure of the MC_IO_MAP_WSM, MC_IO_MAP_MCI, and + * MC_IO_MAP_PWSM commands. + * + * Allocate a contiguous memory buffer for a process. + * The physical address can be used as for later calls to mmap. + * The handle can be used to communicate about this buffer to the Daemon. + * For MC_IO_MAP_MCI command, the reused field indicates that MCI was set up + * already. I.e. Daemon was restarted. + */ +struct mc_ioctl_map { + size_t len; /* Buffer length */ + uint32_t handle; /* WSM handle */ + unsigned long addr; /* Virtual address */ + unsigned long phys_addr;/* physical address of WSM (or NULL) */ + bool reused; /* if WSM memory was reused, or new allocated */ +}; + +/* + * Data exchange structure of the MC_IO_REG_WSM command. + * + * Allocates a physical L2 table and maps the buffer into this page. + * Returns the physical address of the L2 table. + * The page alignment will be created and the appropriated pSize and pOffsetL2 + * will be modified to the used values. + */ +struct mc_ioctl_reg_wsm { + uint32_t buffer; /* base address of the virtual address */ + uint32_t len; /* size of the virtual address space */ + uint32_t pid; /* process id */ + uint32_t handle; /* driver handle for locked memory */ + uint32_t table_phys; /* physical address of the L2 table */ +}; + + +/* + * Data exchange structure of the MC_DRV_MODULE_FC_EXECUTE ioctl command. + * internal, unsupported + */ +struct mc_ioctl_execute { + /* base address of mobicore binary */ + uint32_t phys_start_addr; + /* length of DDR area */ + uint32_t length; +}; + +/* + * Data exchange structure of the MC_IO_RESOLVE_CONT_WSM ioctl command. + */ +struct mc_ioctl_resolv_cont_wsm { + /* driver handle for buffer */ + uint32_t handle; + /* base address of memory */ + uint32_t phys; + /* length memory */ + uint32_t length; +}; + + +/* + * defines for the ioctl mobicore driver module function call from user space. + */ +/* MobiCore IOCTL magic number */ +#define MC_IOC_MAGIC 'M' + +#define MC_IO_INIT _IOWR(MC_IOC_MAGIC, 0, struct mc_ioctl_init) +#define MC_IO_INFO _IOWR(MC_IOC_MAGIC, 1, struct mc_ioctl_info) +#define MC_IO_VERSION _IOR(MC_IOC_MAGIC, 2, uint32_t) +/* + * ioctl parameter to send the YIELD command to the SWD. + * Only possible in Privileged Mode. + * ioctl(fd, MC_DRV_MODULE_YIELD) + */ +#define MC_IO_YIELD _IO(MC_IOC_MAGIC, 3) +/* + * ioctl parameter to send the NSIQ signal to the SWD. + * Only possible in Privileged Mode + * ioctl(fd, MC_DRV_MODULE_NSIQ) + */ +#define MC_IO_NSIQ _IO(MC_IOC_MAGIC, 4) +/* + * Free's memory which is formerly allocated by the driver's mmap + * command. The parameter must be this mmaped address. + * The internal instance data regarding to this address are deleted as + * well as each according memory page and its appropriated reserved bit + * is cleared (ClearPageReserved). + * Usage: ioctl(fd, MC_DRV_MODULE_FREE, &address) with address being of + * type long address + */ +#define MC_IO_FREE _IO(MC_IOC_MAGIC, 5) +/* + * Creates a L2 Table of the given base address and the size of the + * data. + * Parameter: mc_ioctl_app_reg_wsm_l2_params + */ +#define MC_IO_REG_WSM _IOWR(MC_IOC_MAGIC, 6, struct mc_ioctl_reg_wsm) +#define MC_IO_UNREG_WSM _IO(MC_IOC_MAGIC, 7) +#define MC_IO_LOCK_WSM _IO(MC_IOC_MAGIC, 8) +#define MC_IO_UNLOCK_WSM _IO(MC_IOC_MAGIC, 9) +#define MC_IO_EXECUTE _IOWR(MC_IOC_MAGIC, 10, struct mc_ioctl_execute) + +/* + * Allocate contiguous memory for a process for later mapping with mmap. + * MC_DRV_KMOD_MMAP_WSM usual operation, pages are registered in + * device structure and freed later. + * MC_DRV_KMOD_MMAP_MCI get Instance of MCI, allocates or mmaps + * the MCI to daemon + * MC_DRV_KMOD_MMAP_PERSISTENTWSM special operation, without + * registration of pages + */ +#define MC_IO_MAP_WSM _IOWR(MC_IOC_MAGIC, 11, struct mc_ioctl_map) +#define MC_IO_MAP_MCI _IOWR(MC_IOC_MAGIC, 12, struct mc_ioctl_map) +#define MC_IO_MAP_PWSM _IOWR(MC_IOC_MAGIC, 13, struct mc_ioctl_map) + +/* + * Clean orphaned WSM buffers. Only available to the daemon and should + * only be carried out if the TLC crashes or otherwise calls exit() in + * an unexpected manner. + * The clean is needed together with the lock/unlock mechanism so the daemon + * has clear control of the mapped buffers so it can close a Trustlet before + * release all the WSM buffers, otherwise the Trustlet would be able to write + * to possibly kernel memory areas + */ +#define MC_IO_CLEAN_WSM _IO(MC_IOC_MAGIC, 14) + +/* + * Get L2 phys address of a buffer handle allocated to the user. + * Only available to the daemon. + */ +#define MC_IO_RESOLVE_WSM _IOWR(MC_IOC_MAGIC, 15, uint32_t) + +/* + * Get the phys address & length of a allocated contiguous buffer. + * Only available to the daemon */ +#define MC_IO_RESOLVE_CONT_WSM _IOWR(MC_IOC_MAGIC, 16, struct mc_ioctl_execute) + +#endif /* _MC_LINUX_H_ */ diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/mobicore_driver/public/version.h index d0d272c2ba1..b08dd95c406 100644 --- a/drivers/gud/mobicore_driver/public/version.h +++ b/drivers/gud/mobicore_driver/public/version.h @@ -26,10 +26,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _VERSION_H_ -#define _VERSION_H_ +#ifndef _MC_DRV_VERSION_H_ +#define _MC_DRV_VERSION_H_ -#define MCDRVMODULEAPI_VERSION_MAJOR 0 +#define MCDRVMODULEAPI_VERSION_MAJOR 1 #define MCDRVMODULEAPI_VERSION_MINOR 1 -#endif /* _VERSION_H_ */ +#endif /* _MC_DRV_VERSION_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/mobicore_kernelapi/clientlib.c index 264e7aaf2b5..7038e02b2ab 100644 --- a/drivers/gud/mobicore_kernelapi/clientlib.c +++ b/drivers/gud/mobicore_kernelapi/clientlib.c @@ -19,6 +19,7 @@ #include "public/mobicore_driver_api.h" #include "public/mobicore_driver_cmd.h" +#include "include/mcinq.h" #include "device.h" #include "session.h" @@ -802,6 +803,7 @@ enum mc_result mc_map(struct mc_session_handle *session_handle, void *buf, }, { session->session_id, + bulk_buf->handle, (uint32_t)bulk_buf->phys_addr_wsm_l2, (uint32_t)(bulk_buf->virt_addr) & 0xFFF, bulk_buf->len @@ -908,6 +910,14 @@ enum mc_result mc_unmap(struct mc_session_handle *session_handle, void *buf, break; } + uint32_t handle = session_find_bulk_buf(session, buf); + if (handle == 0) { + MCDRV_DBG_ERROR(mc_kapi, "Buffer not found"); + mc_result = MC_DRV_ERR_BULK_UNMAPPING; + break; + } + + /* Prepare unmap command */ struct mc_drv_cmd_unmap_bulk_mem_t cmd_unmap_bulk_mem = { { @@ -915,6 +925,7 @@ enum mc_result mc_unmap(struct mc_session_handle *session_handle, void *buf, }, { session->session_id, + handle, (uint32_t)(map_info->secure_virt_addr) } }; diff --git a/drivers/gud/mobicore_kernelapi/common.h b/drivers/gud/mobicore_kernelapi/common.h index 8e7452012bf..a15b1d79f1c 100644 --- a/drivers/gud/mobicore_kernelapi/common.h +++ b/drivers/gud/mobicore_kernelapi/common.h @@ -30,6 +30,8 @@ extern struct device *mc_kapi; dev_err(dev, "%s() ### ERROR: " txt, __func__, ##__VA_ARGS__) #if defined(DEBUG) + +/* #define DEBUG_VERBOSE */ #if defined(DEBUG_VERBOSE) #define MCDRV_DBG_VERBOSE MCDRV_DBG #else diff --git a/drivers/gud/mobicore_kernelapi/connection.c b/drivers/gud/mobicore_kernelapi/connection.c index 50473492d62..03288a049c0 100644 --- a/drivers/gud/mobicore_kernelapi/connection.c +++ b/drivers/gud/mobicore_kernelapi/connection.c @@ -189,7 +189,7 @@ int connection_process(struct connection *conn, struct sk_buff *skb) kfree_skb(conn->skb); - /* Get a reference to the incomming skb */ + /* Get a reference to the incoming skb */ conn->skb = skb_get(skb); if (conn->skb) { conn->data_msg = nlmsg_hdr(conn->skb); diff --git a/drivers/gud/mobicore_kernelapi/connection.h b/drivers/gud/mobicore_kernelapi/connection.h index da99828337c..6c3ff0037ad 100644 --- a/drivers/gud/mobicore_kernelapi/connection.h +++ b/drivers/gud/mobicore_kernelapi/connection.h @@ -11,6 +11,7 @@ #define _MC_KAPI_CONNECTION_H_ #include +#include #include #include diff --git a/drivers/gud/mobicore_kernelapi/device.c b/drivers/gud/mobicore_kernelapi/device.c index e3eb41e0eae..a17632289ed 100644 --- a/drivers/gud/mobicore_kernelapi/device.c +++ b/drivers/gud/mobicore_kernelapi/device.c @@ -1,7 +1,7 @@ /* * MobiCore client library device management. * - * Device and Trustlet Session management Funtions. + * Device and Trustlet Session management Functions. * * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> * @@ -191,7 +191,7 @@ bool mcore_device_free_contiguous_wsm(struct mcore_device_t *dev, wsm->virt_addr, wsm->handle); /* ignore return code */ - mobicore_free(dev->instance, wsm->handle); + mobicore_free_wsm(dev->instance, wsm->handle); list_del(pos); kfree(wsm); diff --git a/drivers/gud/mobicore_kernelapi/device.h b/drivers/gud/mobicore_kernelapi/device.h index 8a38b505917..16626bd735b 100644 --- a/drivers/gud/mobicore_kernelapi/device.h +++ b/drivers/gud/mobicore_kernelapi/device.h @@ -21,7 +21,7 @@ struct mcore_device_t { /* MobiCore Trustlet session associated with the device */ struct list_head session_vector; - struct list_head wsm_l2_vector; + struct list_head wsm_l2_vector; /* WSM L2 Table */ uint32_t device_id; /* Device identifier */ struct connection *connection; /* The device connection */ @@ -34,6 +34,8 @@ struct mcore_device_t { struct mcore_device_t *mcore_device_create( uint32_t device_id, struct connection *connection); void mcore_device_cleanup(struct mcore_device_t *dev); + + bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName); void mcore_device_close(struct mcore_device_t *dev); bool mcore_device_has_sessions(struct mcore_device_t *dev); diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/mobicore_kernelapi/include/mcinq.h index 85f037fc639..b8749251803 100644 --- a/drivers/gud/mobicore_kernelapi/include/mcinq.h +++ b/drivers/gud/mobicore_kernelapi/include/mcinq.h @@ -2,7 +2,7 @@ * Notifications inform the MobiCore runtime environment that information is * pending in a WSM buffer. * - * The Trustlet Connector (TLC) and the corresponding trustlet also utilize + * The Trustlet Connector (TLC) and the corresponding Trustlet also utilize * this buffer to notify each other about new data within the * Trustlet Connector Interface (TCI). * @@ -13,7 +13,7 @@ * * Notifications hold the session ID, which is used to reference the * communication partner in the other world. - * So if, e.g., the TLC in the normal world wants to notify his trustlet + * So if, e.g., the TLC in the normal world wants to notify his Trustlet * about new data in the TLC buffer * * Notification queue declarations. @@ -59,7 +59,7 @@ /* * MCP session ID is used when directly communicating with the MobiCore - * (e.g. for starting and stopping of trustlets). + * (e.g. for starting and stopping of Trustlets). */ #define SID_MCP 0 /* Invalid session id is returned in case of an error. */ diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/mobicore_kernelapi/main.c index 53eb66d5880..50359b1ebc9 100644 --- a/drivers/gud/mobicore_kernelapi/main.c +++ b/drivers/gud/mobicore_kernelapi/main.c @@ -106,7 +106,7 @@ static int mcapi_process(struct sk_buff *skb, struct nlmsghdr *nlh) c = mcapi_find_connection(seq); if (!c) { MCDRV_ERROR(mc_kapi, - "Invalid incomming connection - seq=%u!", + "Invalid incoming connection - seq=%u!", seq); ret = -1; break; @@ -150,7 +150,7 @@ static int __init mcapi_init(void) mcapi_callback, NULL, THIS_MODULE); if (!mod_ctx->sk) { - MCDRV_ERROR(mc_kapi, "register of recieve handler failed"); + MCDRV_ERROR(mc_kapi, "register of receive handler failed"); return -EFAULT; } diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h index 112df1da920..07a3ae3115c 100644 --- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h +++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h @@ -111,7 +111,7 @@ struct mc_session_handle { /* * Information structure about additional mapped Bulk buffer between the - * Trustlet Connector (Nwd) and the Trustlet (Swd). This structure is + * Trustlet Connector (NWd) and the Trustlet (SWd). This structure is * initialized from a Trustlet Connector by calling mc_map(). * In order to use the memory within a Trustlet the Trustlet Connector has to * inform the Trustlet with the content of this structure via the TCI. @@ -173,11 +173,11 @@ __MC_CLIENT_LIB_API enum mc_result mc_close_device(uint32_t device_id); * mc_open_session() - Open a new session to a Trustlet. * @session: On success, the session data will be returned * @uuid: UUID of the Trustlet to be opened - * @tci: TCI buffer for communicating with the trustlet + * @tci: TCI buffer for communicating with the Trustlet * @tci_len: Length of the TCI buffer. Maximum allowed value * is MC_MAX_TCI_LEN * - * The trustlet with the given UUID has to be available in the flash filesystem. + * The Trustlet with the given UUID has to be available in the flash filesystem. * * Write MCP open message to buffer and notify MobiCore about the availability * of a new command. @@ -213,7 +213,7 @@ __MC_CLIENT_LIB_API enum mc_result mc_open_session( * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur - * MC_DRV_ERR_INVALID_DEVICE_FILE: daemon cannot open trustlet file + * MC_DRV_ERR_INVALID_DEVICE_FILE: daemon cannot open Trustlet file */ __MC_CLIENT_LIB_API enum mc_result mc_close_session( struct mc_session_handle *session); @@ -334,7 +334,7 @@ __MC_CLIENT_LIB_API enum mc_result mc_free_wsm(uint32_t device_id, * possible offset! * @len: length of buffer block in bytes. * @map_info: Information structure about the mapped Bulk buffer - * between the TLC (Nwd) and the TL (Swd). + * between the TLC (NWd) and the TL (SWd). * * Memory allocated in user space of the TLC can be mapped as additional * communication channel (besides TCI) to the Trustlet. Limitation of the @@ -366,7 +366,7 @@ __MC_CLIENT_LIB_API enum mc_result mc_map( * @buf: Virtual address of a memory portion (relative to TLC) * shared with the TL, already includes a possible offset! * @map_info: Information structure about the mapped Bulk buffer - * between the TLC (Nwd) and the TL (Swd) + * between the TLC (NWd) and the TL (SWd) * * The bulk buffer will immediately be unmapped from the session context. * @@ -423,7 +423,7 @@ __MC_CLIENT_LIB_API enum mc_result mc_manage( /** * mc_get_session_error_code() - Get additional error information of the last - * error that occured on a session. + * error that occurred on a session. * @session: Session handle with information of the device_id and * the session_id * @last_error: >0 Trustlet has terminated itself with this value, diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h index 3e62fdd8f72..3b8eb4b721f 100644 --- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h +++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h @@ -171,6 +171,7 @@ struct mc_drv_rsp_notify_t { struct mc_drv_cmd_map_bulk_mem_payload_t { uint32_t session_id; + uint32_t handle; uint32_t phys_addr_l2; uint32_t offset_payload; uint32_t len_bulk_mem; @@ -195,6 +196,7 @@ struct mc_drv_rsp_map_bulk_mem_t { struct mc_drv_cmd_unmap_bulk_mem_payload_t { uint32_t session_id; + uint32_t handle; uint32_t secure_virtual_adr; uint32_t len_bulk_mem; }; diff --git a/drivers/gud/mobicore_kernelapi/session.c b/drivers/gud/mobicore_kernelapi/session.c index eb752898bed..dae2c0063de 100644 --- a/drivers/gud/mobicore_kernelapi/session.c +++ b/drivers/gud/mobicore_kernelapi/session.c @@ -110,7 +110,7 @@ struct bulk_buffer_descriptor *session_add_bulk_buf(struct session *session, * Prepare the interface structure for memory registration in * Kernel Module */ - void *l2_table_phys; + uint32_t l2_table_phys; uint32_t handle; int ret = mobicore_map_vmem(session->instance, buf, len, @@ -128,9 +128,10 @@ struct bulk_buffer_descriptor *session_add_bulk_buf(struct session *session, (unsigned int)l2_table_phys, handle); /* Create new descriptor */ - bulk_buf_descr = bulk_buffer_descriptor_create(buf, len, - handle, - l2_table_phys); + bulk_buf_descr = + bulk_buffer_descriptor_create(buf, len, + handle, + (void *)l2_table_phys); /* Add to vector of descriptors */ list_add_tail(&(bulk_buf_descr->list), @@ -143,10 +144,9 @@ struct bulk_buffer_descriptor *session_add_bulk_buf(struct session *session, bool session_remove_bulk_buf(struct session *session, void *virt_addr) { bool ret = true; - struct bulk_buffer_descriptor *bulk_buf_descr = NULL; + struct bulk_buffer_descriptor *bulk_buf = NULL; struct bulk_buffer_descriptor *tmp; struct list_head *pos, *q; - unsigned int phys_addr_wsm_l2; MCDRV_DBG_VERBOSE(mc_kapi, "Virtual Address = 0x%X", (unsigned int) virt_addr); @@ -155,31 +155,47 @@ bool session_remove_bulk_buf(struct session *session, void *virt_addr) list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) { tmp = list_entry(pos, struct bulk_buffer_descriptor, list); if (tmp->virt_addr == virt_addr) { - bulk_buf_descr = tmp; + bulk_buf = tmp; list_del(pos); break; } } - if (bulk_buf_descr == NULL) { + if (bulk_buf == NULL) { MCDRV_DBG_ERROR(mc_kapi, "Virtual Address not found"); ret = false; } else { - phys_addr_wsm_l2 = - (unsigned int)bulk_buf_descr->phys_addr_wsm_l2; - MCDRV_DBG_VERBOSE(mc_kapi, "WsmL2 phys=0x%X, handle=%d", - phys_addr_wsm_l2, bulk_buf_descr->handle); + (unsigned int)bulk_buf->phys_addr_wsm_l2, + bulk_buf->handle); /* ignore any error, as we cannot do anything */ int ret = mobicore_unmap_vmem(session->instance, - bulk_buf_descr->handle); + bulk_buf->handle); if (ret != 0) MCDRV_DBG_ERROR(mc_kapi, "mobicore_unmap_vmem failed: %d", ret); - kfree(bulk_buf_descr); + kfree(bulk_buf); } return ret; } + +uint32_t session_find_bulk_buf(struct session *session, void *virt_addr) +{ + struct bulk_buffer_descriptor *tmp; + struct list_head *pos, *q; + + MCDRV_DBG_VERBOSE(mc_kapi, "Virtual Address = 0x%X", + (unsigned int) virt_addr); + + /* Search and return buffer descriptor handle */ + list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) { + tmp = list_entry(pos, struct bulk_buffer_descriptor, list); + if (tmp->virt_addr == virt_addr) + return tmp->handle; + } + + return 0; +} diff --git a/drivers/gud/mobicore_kernelapi/session.h b/drivers/gud/mobicore_kernelapi/session.h index 430dd3562ea..4a834e5d81f 100644 --- a/drivers/gud/mobicore_kernelapi/session.h +++ b/drivers/gud/mobicore_kernelapi/session.h @@ -63,7 +63,7 @@ struct session { /* Descriptors of additional bulk buffer of a session */ struct list_head bulk_buffer_descriptors; - /* Informations about session */ + /* Information about session */ struct session_information session_info; uint32_t session_id; @@ -81,7 +81,7 @@ struct session *session_create( void session_cleanup(struct session *session); -/** +/* * session_add_bulk_buf() - Add address information of additional bulk * buffer memory to session and register virtual * memory in kernel module @@ -93,12 +93,12 @@ void session_cleanup(struct session *session); * address already exist, NULL is returned. * * On success the actual Bulk buffer descriptor with all address information - * is retured, NULL if an error occurs. + * is returned, NULL if an error occurs. */ struct bulk_buffer_descriptor *session_add_bulk_buf( struct session *session, void *buf, uint32_t len); -/** +/* * session_remove_bulk_buf() - Remove address information of additional bulk * buffer memory from session and unregister * virtual memory in kernel module @@ -109,17 +109,30 @@ struct bulk_buffer_descriptor *session_add_bulk_buf( */ bool session_remove_bulk_buf(struct session *session, void *buf); -/** + +/* + * session_find_bulk_buf() - Find the handle of the bulk buffer for this + * session + * + * @session: Session information structure + * @buf: The virtual address of bulk buffer. + * + * On success the actual Bulk buffer handle is returned, 0 + * if an error occurs. + */ +uint32_t session_find_bulk_buf(struct session *session, void *virt_addr); + +/* * session_set_error_info() - Set additional error information of the last - * error that occured. + * error that occurred. * @session: Session information structure * @err: The actual error */ void session_set_error_info(struct session *session, int32_t err); -/** +/* * session_get_last_err() - Get additional error information of the last - * error that occured. + * error that occurred. * @session: Session information structure * * After request the information is set to SESSION_ERR_NO. From cdd7ca4f6e1d75559ba789d8907747441efa5f37 Mon Sep 17 00:00:00 2001 From: Oana Medvesan Date: Fri, 8 Feb 2013 09:50:46 +0100 Subject: [PATCH 2346/2357] mobicore: t-base-200 Engineering Release - Improve the smc work by not using work_on_cpu anymore which in later linux versions spawns a new thread. - Unmap memory from TLC when freeing. - Enable mapping of contigous buffers to trustlets. - Logging set up by th IOCTL. - Compliant with the 3.4 Linux Kernel Version. Change-Id: Ied8f024c4dd7e101b23e3ba842fcc47f9ab583fe Signed-off-by: Oana Medvesan [hnamgund@codeaurora.org: Modify mobicore_kernelapi/main.c for 3.4 kernel compatibility, reformat commit text] Signed-off-by: Hariprasad Dhalinarasimha Acked-by: Tony Hamilton --- drivers/gud/mobicore_driver/api.c | 1 + drivers/gud/mobicore_driver/debug.h | 10 +- drivers/gud/mobicore_driver/fastcall.h | 19 ++- drivers/gud/mobicore_driver/logging.c | 127 ++++++++-------- drivers/gud/mobicore_driver/main.c | 142 +++++++++++++++--- drivers/gud/mobicore_driver/main.h | 4 +- drivers/gud/mobicore_driver/mem.c | 23 ++- drivers/gud/mobicore_driver/ops.c | 26 ++++ drivers/gud/mobicore_driver/ops.h | 5 +- .../platforms/msm8960_surf_std/platform.h | 8 +- .../mobicore_driver/public/mc_kernel_api.h | 1 + drivers/gud/mobicore_driver/public/mc_linux.h | 6 + drivers/gud/mobicore_driver/public/version.h | 1 + .../gud/mobicore_kernelapi/include/mcinq.h | 2 +- drivers/gud/mobicore_kernelapi/main.c | 14 ++ 15 files changed, 278 insertions(+), 111 deletions(-) diff --git a/drivers/gud/mobicore_driver/api.c b/drivers/gud/mobicore_driver/api.c index 2506bc2b1bc..871f6cced05 100644 --- a/drivers/gud/mobicore_driver/api.c +++ b/drivers/gud/mobicore_driver/api.c @@ -2,6 +2,7 @@ * MobiCore Driver Kernel Module. * * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * <-- Copyright Trustonic Limited 2013 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gud/mobicore_driver/debug.h b/drivers/gud/mobicore_driver/debug.h index f16660589aa..0195877f7d4 100644 --- a/drivers/gud/mobicore_driver/debug.h +++ b/drivers/gud/mobicore_driver/debug.h @@ -14,8 +14,7 @@ extern struct device *mcd; #define MCDRV_DBG_ERROR(dev, txt, ...) \ - dev_err(dev, "[%d] %s() ### ERROR: " txt, \ - task_pid_vnr(current), \ + dev_err(dev, "MobiCore %s() ### ERROR: " txt, \ __func__, \ ##__VA_ARGS__) @@ -32,15 +31,12 @@ extern struct device *mcd; #endif #define MCDRV_DBG(dev, txt, ...) \ - dev_info(dev, "[%d on CPU%d] %s(): " txt, \ - task_pid_vnr(current), \ - raw_smp_processor_id(), \ + dev_info(dev, "MobiCore %s(): " txt, \ __func__, \ ##__VA_ARGS__) #define MCDRV_DBG_WARN(dev, txt, ...) \ - dev_warn(dev, "[%d] %s() WARNING: " txt, \ - task_pid_vnr(current), \ + dev_warn(dev, "MobiCore %s() WARNING: " txt, \ __func__, \ ##__VA_ARGS__) diff --git a/drivers/gud/mobicore_driver/fastcall.h b/drivers/gud/mobicore_driver/fastcall.h index 9f360c15803..d5f9abc7868 100644 --- a/drivers/gud/mobicore_driver/fastcall.h +++ b/drivers/gud/mobicore_driver/fastcall.h @@ -15,6 +15,15 @@ #include "debug.h" +/* Use the arch_extension sec pseudo op before switching to secure world */ +#if defined(__GNUC__) && \ + defined(__GNUC_MINOR__) && \ + defined(__GNUC_PATCHLEVEL__) && \ + ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)) \ + >= 40502 +#define MC_ARCH_EXTENSION_SEC +#endif + /* * MobiCore SMCs */ @@ -93,16 +102,18 @@ union mc_fc_info { */ static inline long _smc(void *data) { + int ret = 0; union fc_generic fc_generic; - memcpy(&fc_generic, data, sizeof(union fc_generic)); + if (data == NULL) return -EPERM; + #ifdef MC_SMC_FASTCALL { - int ret = 0; - ret = smc_fastcall(data, sizeof(union fc_generic)); + ret = smc_fastcall(data, sizeof(fc_generic)); } #else + memcpy(&fc_generic, data, sizeof(union fc_generic)); { /* SVC expect values in r0-r3 */ register u32 reg0 __asm__("r0") = fc_generic.as_in.cmd; @@ -128,7 +139,7 @@ static inline long _smc(void *data) memcpy(data, &fc_generic, sizeof(union fc_generic)); } #endif - return 0; + return ret; } /* diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/mobicore_driver/logging.c index 089b91cf2bc..4160292195a 100644 --- a/drivers/gud/mobicore_driver/logging.c +++ b/drivers/gud/mobicore_driver/logging.c @@ -5,6 +5,7 @@ * buffer and the Linux log * * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * <-- Copyright Trustonic Limited 2013 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -51,17 +52,27 @@ struct logmsg_struct { uint32_t log_data; /* Value, if any */ }; +static bool prev_eol; /* Previous char was a EOL */ +static uint16_t prev_source; /* Previous Log source */ static uint32_t log_pos; /* MobiCore log previous position */ static struct mc_trace_buf *log_buf; /* MobiCore log buffer structure */ struct task_struct *log_thread; /* Log Thread task structure */ static char *log_line; /* Log Line buffer */ static uint32_t log_line_len; /* Log Line buffer current length */ +static int thread_err; -static void log_eol(void) +static void log_eol(uint16_t source) { if (!strnlen(log_line, LOG_LINE_SIZE)) return; - dev_info(mcd, "%s\n", log_line); + prev_eol = true; + /* MobiCore Userspace */ + if (prev_source) + dev_info(mcd, "%03x|%s\n", prev_source, log_line); + /* MobiCore kernel */ + else + dev_info(mcd, "%s\n", log_line); + log_line_len = 0; log_line[0] = 0; } @@ -70,53 +81,29 @@ static void log_eol(void) * Collect chars in log_line buffer and output the buffer when it is full. * No locking needed because only "mobicore_log" thread updates this buffer. */ -static void log_char(char ch) +static void log_char(char ch, uint16_t source) { if (ch == '\n' || ch == '\r') { - log_eol(); + log_eol(source); return; } - if (log_line_len >= LOG_LINE_SIZE - 1) { - dev_info(mcd, "%s\n", log_line); - log_line_len = 0; - log_line[0] = 0; - } + if (log_line_len >= LOG_LINE_SIZE - 1 || source != prev_source) + log_eol(source); + log_line[log_line_len] = ch; log_line[log_line_len + 1] = 0; log_line_len++; -} - -/* - * Put a string to the log line. - */ -static void log_str(const char *s) -{ - int i; - - for (i = 0; i < strnlen(s, LOG_LINE_SIZE); i++) - log_char(s[i]); -} - -static uint32_t process_v1log(void) -{ - char *last_char = log_buf->buff + log_buf->write_pos; - char *buff = log_buf->buff + log_pos; - while (buff != last_char) { - log_char(*(buff++)); - /* Wrap around */ - if (buff - (char *)log_buf >= log_size) - buff = log_buf->buff; - } - return buff - log_buf->buff; + prev_eol = false; + prev_source = source; } static const uint8_t HEX2ASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; -static void dbg_raw_nro(uint32_t format, uint32_t value) +static void dbg_raw_nro(uint32_t format, uint32_t value, uint16_t source) { int digits = 1; uint32_t base = (format & LOG_INTEGER_DECIMAL) ? 10 : 16; @@ -139,17 +126,17 @@ static void dbg_raw_nro(uint32_t format, uint32_t value) if (width > digits) { char ch = (base == 10) ? ' ' : '0'; while (width > digits) { - log_char(ch); + log_char(ch, source); width--; } } if (negative) - log_char('-'); + log_char('-', source); while (digits-- > 0) { uint32_t d = value / digit_base; - log_char(HEX2ASCII[d]); + log_char(HEX2ASCII[d], source); value = value - d * digit_base; digit_base /= base; } @@ -157,36 +144,32 @@ static void dbg_raw_nro(uint32_t format, uint32_t value) static void log_msg(struct logmsg_struct *msg) { - unsigned char msgtxt[5]; - int mpos = 0; - switch (msg->ctrl & LOG_TYPE_MASK) { case LOG_TYPE_CHAR: { uint32_t ch; ch = msg->log_data; while (ch != 0) { - msgtxt[mpos++] = ch&0xFF; + log_char(ch & 0xFF, msg->source); ch >>= 8; } - msgtxt[mpos] = 0; - log_str(msgtxt); break; } case LOG_TYPE_INTEGER: { - dbg_raw_nro(msg->ctrl, msg->log_data); + dbg_raw_nro(msg->ctrl, msg->log_data, msg->source); break; } default: break; } if (msg->ctrl & LOG_EOL) - log_eol(); + log_eol(msg->source); } -static uint32_t process_v2log(void) +static uint32_t process_log(void) { char *last_msg = log_buf->buff + log_buf->write_pos; char *buff = log_buf->buff + log_pos; + while (buff != last_msg) { log_msg((struct logmsg_struct *)buff); buff += sizeof(struct logmsg_struct); @@ -201,19 +184,19 @@ static uint32_t process_v2log(void) /* log_worker() - Worker thread processing the log_buf buffer. */ static int log_worker(void *p) { - if (log_buf == NULL) - return -EFAULT; + int ret = 0; + if (log_buf == NULL) { + ret = -EFAULT; + goto err_kthread; + } while (!kthread_should_stop()) { if (log_buf->write_pos == log_pos) schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); switch (log_buf->version) { - case 1: - log_pos = process_v1log(); - break; case 2: - log_pos = process_v2log(); + log_pos = process_log(); break; default: MCDRV_DBG_ERROR(mcd, "Unknown Mobicore log data"); @@ -222,11 +205,23 @@ static int log_worker(void *p) * Stop the thread as we have no idea what * happens next */ - return -EFAULT; + ret = -EFAULT; + goto err_kthread; } } +err_kthread: MCDRV_DBG(mcd, "Logging thread stopped!"); - return 0; + thread_err = ret; + /* Wait until the next kthread_stop() is called, if it was already + * called we just slip through, if there is an error signal it and + * wait to get the signal */ + set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + return ret; } /* @@ -239,6 +234,14 @@ void mobicore_log_read(void) if (log_thread == NULL || IS_ERR(log_thread)) return; + /* The thread itself is in some error condition so just get + * rid of it */ + if (thread_err != 0) { + kthread_stop(log_thread); + log_thread = NULL; + return; + } + wake_up_process(log_thread); } @@ -258,6 +261,9 @@ long mobicore_log_setup(void) log_thread = NULL; log_line = NULL; log_line_len = 0; + prev_eol = false; + prev_source = 0; + thread_err = 0; /* Sanity check for the log size */ if (log_size < PAGE_SIZE) @@ -271,11 +277,11 @@ long mobicore_log_setup(void) return -ENOMEM; } - log_thread = kthread_create(log_worker, NULL, "mobicore_log"); + log_thread = kthread_create(log_worker, NULL, "mc_log"); if (IS_ERR(log_thread)) { MCDRV_DBG_ERROR(mcd, "MobiCore log thread creation failed!"); ret = -EFAULT; - goto mobicore_log_setup_log_line; + goto err_free_line; } sched_setscheduler(log_thread, SCHED_IDLE, ¶m); @@ -288,7 +294,7 @@ long mobicore_log_setup(void) if (!log_buf) { MCDRV_DBG_ERROR(mcd, "Failed to get page for logger!"); ret = -ENOMEM; - goto mobicore_log_setup_kthread; + goto err_stop_kthread; } phys_log_buf = virt_to_phys(log_buf); @@ -308,16 +314,17 @@ long mobicore_log_setup(void) free_pages((unsigned long)log_buf, get_order(log_size)); log_buf = NULL; ret = -EIO; - goto mobicore_log_setup_kthread; + goto err_stop_kthread; } + set_task_state(log_thread, TASK_INTERRUPTIBLE); MCDRV_DBG(mcd, "fc_log Logger version %u\n", log_buf->version); return 0; -mobicore_log_setup_kthread: +err_stop_kthread: kthread_stop(log_thread); log_thread = NULL; -mobicore_log_setup_log_line: +err_free_line: kfree(log_line); log_line = NULL; return ret; diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c index 1a745b3e226..3fc9e1798ef 100644 --- a/drivers/gud/mobicore_driver/main.c +++ b/drivers/gud/mobicore_driver/main.c @@ -11,6 +11,7 @@ * fd = open(/dev/mobicore-user) * * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * <-- Copyright Trustonic Limited 2013 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -81,7 +82,7 @@ static inline void free_continguous_pages(void *addr, unsigned int order) } /* Frees the memory associated with a buffer */ -static int free_buffer(struct mc_buffer *buffer) +static int free_buffer(struct mc_buffer *buffer, bool unlock) { if (buffer->handle == 0) return -EINVAL; @@ -89,16 +90,15 @@ static int free_buffer(struct mc_buffer *buffer) if (buffer->addr == 0) return -EINVAL; - if (!atomic_dec_and_test(&buffer->usage)) { + MCDRV_DBG_VERBOSE(mcd, + "handle=%u phys_addr=0x%p, virt_addr=0x%p len=%u\n", + buffer->handle, buffer->phys, buffer->addr, buffer->len); - MCDRV_DBG_VERBOSE(mcd, "Could not free buffer h=%u", - buffer->handle); + if (!atomic_dec_and_test(&buffer->usage)) { + MCDRV_DBG_VERBOSE(mcd, "Could not free %u", buffer->handle); return 0; } - MCDRV_DBG(mcd, "handle=%u phys_addr=0x%p, virt_addr=0x%p\n", - buffer->handle, buffer->phys, buffer->addr); - list_del(&buffer->list); free_continguous_pages(buffer->addr, buffer->order); @@ -106,6 +106,37 @@ static int free_buffer(struct mc_buffer *buffer) return 0; } +static uint32_t mc_find_cont_wsm_addr(struct mc_instance *instance, void *uaddr, + uint32_t *addr, uint32_t len) +{ + int ret = 0; + struct mc_buffer *buffer; + + if (WARN(!instance, "No instance data available")) + return -EFAULT; + + mutex_lock(&instance->lock); + + mutex_lock(&ctx.bufs_lock); + + /* search for the given handle in the buffers list */ + list_for_each_entry(buffer, &ctx.cont_bufs, list) { + if (buffer->uaddr == uaddr && buffer->len == len) { + *addr = (uint32_t)buffer->addr; + goto found; + } + } + + /* Coundn't find the buffer */ + ret = -EINVAL; + +found: + mutex_unlock(&ctx.bufs_lock); + mutex_unlock(&instance->lock); + + return ret; +} + static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle, uint32_t *phys, uint32_t *len) { @@ -152,14 +183,60 @@ static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle, * Returns 0 if no error * */ -static int __free_buffer(struct mc_instance *instance, uint32_t handle) +static int __free_buffer(struct mc_instance *instance, uint32_t handle, + bool unlock) { int ret = 0; struct mc_buffer *buffer; + void *uaddr = NULL; + size_t len = 0; +#ifndef MC_VM_UNMAP + struct mm_struct *mm = current->mm; +#endif if (WARN(!instance, "No instance data available")) return -EFAULT; + mutex_lock(&ctx.bufs_lock); + /* search for the given handle in the buffers list */ + list_for_each_entry(buffer, &ctx.cont_bufs, list) { + if (buffer->handle == handle) { + uaddr = buffer->uaddr; + len = buffer->len; + goto found_buffer; + } + } + goto err; +found_buffer: + if (!is_daemon(instance) || buffer->instance != instance) + goto err; + mutex_unlock(&ctx.bufs_lock); + /* Only unmap if the request is comming from the user space and + * it hasn't already been unmapped */ + if (unlock == false && uaddr != NULL) +#ifndef MC_VM_UNMAP + /* do_munmap must be done with mm->mmap_sem taken */ + down_write(&mm->mmap_sem); + ret = do_munmap(mm, (long unsigned int)uaddr, len); + if (ret < 0) { + /* Something is not right if we end up here, better not + * clean the buffer so we just leak memory instead of + * creating security issues */ + MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped\n"); + } + up_write(&mm->mmap_sem); + if (ret < 0) + return -EINVAL; +#else + if (vm_munmap((long unsigned int)uaddr, len) < 0) { + /* Something is not right if we end up here, better not + * clean the buffer so we just leak memory instead of + * creating security issues */ + MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped\n"); + return -EINVAL; + } +#endif + mutex_lock(&ctx.bufs_lock); /* search for the given handle in the buffers list */ list_for_each_entry(buffer, &ctx.cont_bufs, list) { @@ -170,7 +247,7 @@ static int __free_buffer(struct mc_instance *instance, uint32_t handle) goto err; del_buffer: - ret = free_buffer(buffer); + ret = free_buffer(buffer, unlock); err: mutex_unlock(&ctx.bufs_lock); return ret; @@ -185,7 +262,7 @@ int mc_free_buffer(struct mc_instance *instance, uint32_t handle) mutex_lock(&instance->lock); - ret = __free_buffer(instance, handle); + ret = __free_buffer(instance, handle, false); mutex_unlock(&instance->lock); return ret; } @@ -253,8 +330,8 @@ int mc_get_buffer(struct mc_instance *instance, INIT_LIST_HEAD(&cbuffer->list); list_add(&cbuffer->list, &ctx.cont_bufs); - MCDRV_DBG(mcd, - "allocated phys=0x%p - 0x%p, size=%ld, kvirt=0x%p, h=%d\n", + MCDRV_DBG_VERBOSE(mcd, + "allocated phys=0x%p - 0x%p, size=%ld, kvirt=0x%p, h=%d\n", phys, (void *)((unsigned int)phys+allocated_size), allocated_size, addr, cbuffer->handle); *buffer = cbuffer; @@ -332,6 +409,7 @@ int mc_register_wsm_l2(struct mc_instance *instance, int ret = 0; struct mc_l2_table *table = NULL; struct task_struct *task = current; + uint32_t kbuff = 0x0; if (WARN(!instance, "No instance data available")) return -EFAULT; @@ -341,7 +419,12 @@ int mc_register_wsm_l2(struct mc_instance *instance, return -EINVAL; } - table = mc_alloc_l2_table(instance, task, (void *)buffer, len); + MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x\n", (void *)buffer, len); + + if (!mc_find_cont_wsm_addr(instance, (void *)buffer, &kbuff, len)) + table = mc_alloc_l2_table(instance, NULL, (void *)kbuff, len); + else + table = mc_alloc_l2_table(instance, task, (void *)buffer, len); if (IS_ERR(table)) { MCDRV_DBG_ERROR(mcd, "new_used_l2_table() failed\n"); @@ -421,7 +504,7 @@ static int mc_unlock_handle(struct mc_instance *instance, uint32_t handle) /* Not a l2 table, then it must be a buffer */ if (ret == -EINVAL) { /* Call the non locking variant! */ - ret = __free_buffer(instance, handle); + ret = __free_buffer(instance, handle, true); } mutex_unlock(&instance->lock); @@ -471,8 +554,8 @@ static int mc_fd_mmap(struct file *file, struct vm_area_struct *vmarea) struct mc_buffer *buffer = 0; int ret = 0; - MCDRV_DBG(mcd, "enter (vma start=0x%p, size=%ld, mci=%p)\n", - (void *)vmarea->vm_start, len, ctx.mci_base.phys); + MCDRV_DBG_VERBOSE(mcd, "enter (vma start=0x%p, size=%ld, mci=%p)\n", + (void *)vmarea->vm_start, len, ctx.mci_base.phys); if (WARN(!instance, "No instance data available")) return -EFAULT; @@ -496,7 +579,8 @@ static int mc_fd_mmap(struct file *file, struct vm_area_struct *vmarea) return -EINVAL; found: - vmarea->vm_flags |= VM_RESERVED; + buffer->uaddr = (void *)vmarea->vm_start; + vmarea->vm_flags |= VM_IO; /* * Convert kernel address to user address. Kernel address begins * at PAGE_OFFSET, user address range is below PAGE_OFFSET. @@ -507,6 +591,10 @@ static int mc_fd_mmap(struct file *file, struct vm_area_struct *vmarea) pfn = (unsigned int)paddr >> PAGE_SHIFT; ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn, buffer->len, vmarea->vm_page_prot); + /* If the remap failed then don't mark this buffer as marked + * since the unmaping will also fail */ + if (ret) + buffer->uaddr = NULL; mutex_unlock(&ctx.bufs_lock); } else { if (!is_daemon(instance)) @@ -516,7 +604,7 @@ static int mc_fd_mmap(struct file *file, struct vm_area_struct *vmarea) if (!paddr) return -EFAULT; - vmarea->vm_flags |= VM_RESERVED; + vmarea->vm_flags |= VM_IO; /* * Convert kernel address to user address. Kernel address begins * at PAGE_OFFSET, user address range is below PAGE_OFFSET. @@ -614,8 +702,8 @@ static long mc_fd_user_ioctl(struct file *file, unsigned int cmd, map.reused = 0; if (copy_to_user(uarg, &map, sizeof(map))) ret = -EFAULT; - - ret = 0; + else + ret = 0; break; } default: @@ -754,6 +842,13 @@ static long mc_fd_admin_ioctl(struct file *file, unsigned int cmd, break; } + case MC_IO_LOG_SETUP: { +#ifdef MC_MEM_TRACES + ret = mobicore_log_setup(); +#endif + break; + } + /* The rest is handled commonly by user IOCTL */ default: ret = mc_fd_user_ioctl(file, cmd, arg); @@ -887,7 +982,7 @@ int mc_release_instance(struct mc_instance *instance) list_for_each_entry_safe(buffer, tmp, &ctx.cont_bufs, list) { if (buffer->instance == instance) { buffer->instance = NULL; - free_buffer(buffer); + free_buffer(buffer, false); } } mutex_unlock(&ctx.bufs_lock); @@ -1097,10 +1192,6 @@ static int __init mobicore_init(void) goto free_admin; } -#ifdef MC_MEM_TRACES - mobicore_log_setup(); -#endif - /* initialize event counter for signaling of an IRQ to zero */ atomic_set(&ctx.isr_counter, 0); @@ -1159,6 +1250,7 @@ static void __exit mobicore_exit(void) module_init(mobicore_init); module_exit(mobicore_exit); MODULE_AUTHOR("Giesecke & Devrient GmbH"); +MODULE_AUTHOR("Trustonic Limited"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MobiCore driver"); diff --git a/drivers/gud/mobicore_driver/main.h b/drivers/gud/mobicore_driver/main.h index e23c51618c6..2c316bc7492 100644 --- a/drivers/gud/mobicore_driver/main.h +++ b/drivers/gud/mobicore_driver/main.h @@ -27,7 +27,7 @@ /* Instance data for MobiCore Daemon and TLCs. */ struct mc_instance { - /* Instance lock */ + /* lock for the instance */ struct mutex lock; /* unique handle */ unsigned int handle; @@ -48,6 +48,8 @@ struct mc_buffer { atomic_t usage; /* virtual Kernel start address */ void *addr; + /* virtual Userspace start address */ + void *uaddr; /* physical start address */ void *phys; /* order of number of pages */ diff --git a/drivers/gud/mobicore_driver/mem.c b/drivers/gud/mobicore_driver/mem.c index da711ce7725..1fe351b71d3 100644 --- a/drivers/gud/mobicore_driver/mem.c +++ b/drivers/gud/mobicore_driver/mem.c @@ -11,6 +11,7 @@ * which has to be created by the fd = open(/dev/mobicore) command. * * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * <-- Copyright Trustonic Limited 2013 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -355,14 +356,6 @@ static int map_buffer(struct task_struct *task, void *wsm_buffer, MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x\n", wsm_buffer, wsm_len); - /* - * Check if called from kernel space and if - * wsm_buffer is actually vmalloced or not - */ - if (task == NULL && !is_vmalloc_addr(wsm_buffer)) { - MCDRV_DBG_ERROR(mcd, "WSM addr is not a vmalloc address"); - return -EINVAL; - } /* calculate page usage */ virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK); @@ -405,6 +398,20 @@ static int map_buffer(struct task_struct *task, void *wsm_buffer, return ret; } } + /* Request comes from kernel space(cont buffer) */ + else if (task == NULL && !is_vmalloc_addr(wsm_buffer)) { + void *uaddr = wsm_buffer; + for (i = 0; i < nr_of_pages; i++) { + page = virt_to_page(uaddr); + if (!page) { + MCDRV_DBG_ERROR(mcd, "failed to map address"); + return -EINVAL; + } + get_page(page); + l2table_as_array_of_pointers_to_page[i] = page; + uaddr += PAGE_SIZE; + } + } /* Request comes from kernel space(vmalloc buffer) */ else { void *uaddr = wsm_buffer; diff --git a/drivers/gud/mobicore_driver/ops.c b/drivers/gud/mobicore_driver/ops.c index 509b4e9a98c..b44a84289da 100644 --- a/drivers/gud/mobicore_driver/ops.c +++ b/drivers/gud/mobicore_driver/ops.c @@ -11,6 +11,7 @@ * which has to be created by the fd = open(/dev/mobicore) command. * * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * <-- Copyright Trustonic Limited 2013 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,6 +21,8 @@ #include #include #include +#include +#include #include "main.h" #include "fastcall.h" @@ -27,6 +30,29 @@ #include "mem.h" #include "debug.h" +struct fastcall_work_struct { + struct work_struct work; + void *data; +}; + +static void fastcall_work_func(struct work_struct *work) +{ + struct fastcall_work_struct *fc_work = + container_of(work, struct fastcall_work_struct, work); + _smc(fc_work->data); +} + +void mc_fastcall(void *data) +{ + struct fastcall_work_struct work = { + .data = data, + }; + INIT_WORK(&work.work, fastcall_work_func); + schedule_work_on(0, &work.work); + + flush_work(&work.work); +} + int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info) { int ret = 0; diff --git a/drivers/gud/mobicore_driver/ops.h b/drivers/gud/mobicore_driver/ops.h index 673399fef4d..efe5f05f351 100644 --- a/drivers/gud/mobicore_driver/ops.h +++ b/drivers/gud/mobicore_driver/ops.h @@ -22,9 +22,6 @@ int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info); int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length, uint32_t mcp_offset, uint32_t mcp_length); -static inline void mc_fastcall(void *data) -{ - work_on_cpu(0, _smc, data); -} +void mc_fastcall(void *data); #endif /* _MC_OPS_H_ */ diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h index 9efa0263cb0..7febcb61d12 100644 --- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h +++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h @@ -3,6 +3,7 @@ * its internal structures and defines. * * <-- Copyright Giesecke & Devrient GmbH 2009-2012 --> + * <-- Copyright Trustonic Limited 2013 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -35,6 +36,11 @@ static inline int smc_fastcall(void *fc_generic, size_t size) } /* Enable mobicore mem traces */ -#define MC_MEM_TRACES +/* #define MC_MEM_TRACES */ + +/* Enable the use of vm_unamp instead of the deprecated do_munmap + * and other 3.7 features + */ +#define MC_VM_UNMAP #endif /* _MC_PLATFORM_H_ */ diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/mobicore_driver/public/mc_kernel_api.h index 7a038c4fd0d..cca0636b0fa 100644 --- a/drivers/gud/mobicore_driver/public/mc_kernel_api.h +++ b/drivers/gud/mobicore_driver/public/mc_kernel_api.h @@ -2,6 +2,7 @@ * Interface to be used by module MobiCoreKernelAPI. * * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> + * <-- Copyright Trustonic Limited 2013 --> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/mobicore_driver/public/mc_linux.h index 99b77690a31..bb95c26010e 100644 --- a/drivers/gud/mobicore_driver/public/mc_linux.h +++ b/drivers/gud/mobicore_driver/public/mc_linux.h @@ -11,6 +11,7 @@ * "insmod mcDrvModule.ko". * * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> + * <-- Copyright Trustonic Limited 2013 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -206,4 +207,9 @@ struct mc_ioctl_resolv_cont_wsm { * Only available to the daemon */ #define MC_IO_RESOLVE_CONT_WSM _IOWR(MC_IOC_MAGIC, 16, struct mc_ioctl_execute) +/* + * Setup the mem traces when called. + * Only available to the daemon */ +#define MC_IO_LOG_SETUP _IO(MC_IOC_MAGIC, 17) + #endif /* _MC_LINUX_H_ */ diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/mobicore_driver/public/version.h index b08dd95c406..591ca3df842 100644 --- a/drivers/gud/mobicore_driver/public/version.h +++ b/drivers/gud/mobicore_driver/public/version.h @@ -1,5 +1,6 @@ /* * <-- Copyright Giesecke & Devrient GmbH 2010-2012 --> + * <-- Copyright Trustonic Limited 2013 --> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/mobicore_kernelapi/include/mcinq.h index b8749251803..34216a78978 100644 --- a/drivers/gud/mobicore_kernelapi/include/mcinq.h +++ b/drivers/gud/mobicore_kernelapi/include/mcinq.h @@ -112,6 +112,6 @@ struct notification_queue { struct notification_queue_header hdr; /* Notification elements. */ struct notification notification[MIN_NQ_ELEM]; -} ; +}; #endif /* _MCINQ_H_ */ diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/mobicore_kernelapi/main.c index 50359b1ebc9..73de93a6d43 100644 --- a/drivers/gud/mobicore_kernelapi/main.c +++ b/drivers/gud/mobicore_kernelapi/main.c @@ -139,13 +139,27 @@ static void mcapi_callback(struct sk_buff *skb) static int __init mcapi_init(void) { + /* struct netlink_kernel_cfg netlink_cfg; */ + dev_set_name(mc_kapi, "mcapi"); dev_info(mc_kapi, "Mobicore API module initialized!\n"); + /* + * netlink_cfg.groups = 0; + * netlink_cfg.flags = 0; + * netlink_cfg.input = mcapi_callback; + * netlink_cfg.cb_mutex = NULL; + * netlink_cfg.bind = NULL; + */ mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL); /* start kernel thread */ + + /* + * mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, + * &netlink_cfg); + */ mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0, mcapi_callback, NULL, THIS_MODULE); From caf632b519daf58d1bdfbe97518308bfda9de29c Mon Sep 17 00:00:00 2001 From: Hariprasad Dhalinarasimha Date: Mon, 25 Feb 2013 11:28:17 -0800 Subject: [PATCH 2347/2357] mobicore: statically assign minor device numbers Temporarily assign static minor device numbers to the gud driver since the dynamic allocation table is exhausted. Change-Id: Ied42639cb362b0fcac6e9516174c691f57406677 Signed-off-by: Hariprasad Dhalinarasimha Acked-by: Tony Hamilton --- drivers/gud/mobicore_driver/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c index 3fc9e1798ef..df5675e230e 100644 --- a/drivers/gud/mobicore_driver/main.c +++ b/drivers/gud/mobicore_driver/main.c @@ -1112,7 +1112,7 @@ static const struct file_operations mc_admin_fops = { static struct miscdevice mc_admin_device = { .name = MC_ADMIN_DEVNODE, .mode = (S_IRWXU), - .minor = MISC_DYNAMIC_MINOR, + .minor = 253, .fops = &mc_admin_fops, }; @@ -1128,7 +1128,7 @@ static const struct file_operations mc_user_fops = { static struct miscdevice mc_user_device = { .name = MC_USER_DEVNODE, .mode = (S_IRWXU | S_IRWXG | S_IRWXO), - .minor = MISC_DYNAMIC_MINOR, + .minor = 254, .fops = &mc_user_fops, }; From cd0dd4fb57c37da6407f561d52b28a916400c6f6 Mon Sep 17 00:00:00 2001 From: Evan McClain Date: Tue, 5 Mar 2013 20:01:52 -0500 Subject: [PATCH 2348/2357] Revert "Fix warnings." This reverts commit 6f2cc2f541ea696aa6ba81520eec2ede461c03b9. --- arch/arm/mach-msm/board-mms-tsp.c | 2 +- drivers/input/misc/bmp180.c | 4 ++-- drivers/media/common/tuners/xc4000.c | 2 +- drivers/misc/a2220.c | 2 +- drivers/power/pm8xxx-ccadc.c | 2 +- fs/cifs/transport.c | 2 +- fs/ecryptfs/keystore.c | 2 +- include/linux/charging_temperature_data.h | 12 ++++++------ net/netfilter/xt_socket.c | 10 +++++----- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-msm/board-mms-tsp.c b/arch/arm/mach-msm/board-mms-tsp.c index 543d38f1374..6ce42674a4f 100644 --- a/arch/arm/mach-msm/board-mms-tsp.c +++ b/arch/arm/mach-msm/board-mms-tsp.c @@ -74,6 +74,7 @@ void melfas_vdd_on(bool onoff) static struct regulator *reg_l17; /* 1.8V */ #ifdef CONFIG_MACH_M2_VZW + static struct regulator *reg_l11; if (system_rev < BOARD_REV02) { if (onoff) gpio_direction_output(10, 1); @@ -149,7 +150,6 @@ void melfas_vdd_on(bool onoff) } #else /* 2.8V */ - static struct regulator *reg_l11; if (machine_is_ESPRESSO_VZW() && system_rev < BOARD_REV03) { if (!reg_l17) { reg_l17 = regulator_get(NULL, "8921_l17"); diff --git a/drivers/input/misc/bmp180.c b/drivers/input/misc/bmp180.c index 8eff6535069..adf025da18a 100644 --- a/drivers/input/misc/bmp180.c +++ b/drivers/input/misc/bmp180.c @@ -189,8 +189,8 @@ static int bmp180_get_raw_pressure(struct bmp180_data *barom, static int bmp180_get_pressure_data_body(struct bmp180_data *barom) { - u16 raw_temperature = 0; - u32 raw_pressure = 0; + u16 raw_temperature; + u32 raw_pressure; long x1, x2, x3, b3, b5, b6; unsigned long b4, b7; long p; diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c index 6d157c34a64..68397110b7d 100644 --- a/drivers/media/common/tuners/xc4000.c +++ b/drivers/media/common/tuners/xc4000.c @@ -935,7 +935,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, int rc = 0, is_retry = 0; u16 hwmodel; v4l2_std_id std0; - u8 hw_major = 0, hw_minor = 0, fw_major = 0, fw_minor = 0; + u8 hw_major, hw_minor, fw_major, fw_minor; dprintk(1, "%s called\n", __func__); diff --git a/drivers/misc/a2220.c b/drivers/misc/a2220.c index 46383708a36..8e396dec544 100644 --- a/drivers/misc/a2220.c +++ b/drivers/misc/a2220.c @@ -176,7 +176,7 @@ static void a2220_i2c_sw_reset(struct a2220_data *a2220, unsigned int reset_cmd) a2220_hw_reset(struct a2220_data *a2220, struct a2220img *img) { struct a2220img *vp = img; - int rc = 0, i, pass = 0; + int rc, i, pass = 0; int remaining; int retry = RETRY_CNT; unsigned char *index; diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c index b453caa6aa5..7e37daa4ed1 100644 --- a/drivers/power/pm8xxx-ccadc.c +++ b/drivers/power/pm8xxx-ccadc.c @@ -779,7 +779,7 @@ static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev) #define CCADC_CALIB_TEMP_THRESH 20 static int pm8xxx_ccadc_resume(struct device *dev) { - int rc, batt_temp = 0, delta_temp; + int rc, batt_temp, delta_temp; unsigned long current_time_sec; unsigned long time_since_last_calib; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 1607615186c..0961336513d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -569,7 +569,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, { int rc = 0; int long_op; - struct mid_q_entry *midQ = NULL; + struct mid_q_entry *midQ; char *buf = iov[0].iov_base; long_op = flags & CIFS_TIMEOUT_MASK; diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index 6154cde3a05..2333203a120 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -1150,7 +1150,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_message *msg = NULL; char *auth_tok_sig; char *payload; - size_t payload_len = 0; + size_t payload_len; int rc; rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok); diff --git a/include/linux/charging_temperature_data.h b/include/linux/charging_temperature_data.h index 0f4262220a5..db31292a400 100644 --- a/include/linux/charging_temperature_data.h +++ b/include/linux/charging_temperature_data.h @@ -29,7 +29,7 @@ #define DEFAULT_LOW_RECOVER_TEMP 0 #if defined(CONFIG_MACH_JAGUAR) -static const struct pm8xxx_adc_map_pt temp_table[] = { +static const int temp_table[][2] = { {26250, 800}, {26583, 750}, {26979, 700}, @@ -54,7 +54,7 @@ static const struct pm8xxx_adc_map_pt temp_table[] = { }; #elif defined(CONFIG_MACH_M2_ATT) -static const struct pm8xxx_adc_map_pt temp_table[] = { +static const int temp_table[][2] = { {26465, 800}, {26749, 750}, {27017, 700}, @@ -104,7 +104,7 @@ static const struct pm8xxx_adc_map_pt temp_table[] = { }; #elif defined(CONFIG_MACH_M2_VZW) -static const struct pm8xxx_adc_map_pt temp_table[] = { +static const int temp_table[][2] = { {26537, 800}, {26849, 750}, {27211, 700}, @@ -129,7 +129,7 @@ static const struct pm8xxx_adc_map_pt temp_table[] = { }; #elif defined(CONFIG_MACH_GOGH) || defined(CONFIG_MACH_INFINITE) -static const struct pm8xxx_adc_map_pt temp_table[] = { +static const int temp_table[][2] = { {26478, 800}, {27123, 700}, {27985, 600}, @@ -144,7 +144,7 @@ static const struct pm8xxx_adc_map_pt temp_table[] = { }; #elif defined(CONFIG_MACH_AEGIS2) -static const struct pm8xxx_adc_map_pt temp_table[] = { +static const int temp_table[][2] = { {27401, 650}, {27790, 600}, {28378, 550}, @@ -167,7 +167,7 @@ static const struct pm8xxx_adc_map_pt temp_table[] = { }; #else -static const struct pm8xxx_adc_map_pt temp_table[] = { +static const int temp_table[][2] = { {26250, 800}, {26583, 750}, {26979, 700}, diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 3163becc172..1e48fcf2920 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -108,9 +108,9 @@ xt_socket_get4_sk(const struct sk_buff *skb, struct xt_action_param *par) const struct iphdr *iph = ip_hdr(skb); struct udphdr _hdr, *hp = NULL; struct sock *sk; - __be32 daddr = 0, saddr = 0; - __be16 dport = 0, sport = 0; - u8 protocol = 0; + __be32 daddr, saddr; + __be16 dport, sport; + u8 protocol; #ifdef XT_SOCKET_HAVE_CONNTRACK struct nf_conn const *ct; enum ip_conntrack_info ctinfo; @@ -273,8 +273,8 @@ xt_socket_get6_sk(const struct sk_buff *skb, struct xt_action_param *par) struct ipv6hdr *iph = ipv6_hdr(skb); struct udphdr _hdr, *hp = NULL; struct sock *sk; - struct in6_addr *daddr = NULL, *saddr = NULL; - __be16 dport = 0, sport = 0; + struct in6_addr *daddr, *saddr; + __be16 dport, sport; int thoff, tproto; tproto = ipv6_find_hdr(skb, &thoff, -1, NULL); From 7aac29dfe16a10bdc586a045150b352eae1ecb7b Mon Sep 17 00:00:00 2001 From: Evan McClain Date: Tue, 5 Mar 2013 20:03:11 -0500 Subject: [PATCH 2349/2357] Revert "Revert "Fix warnings."" This reverts commit cd0dd4fb57c37da6407f561d52b28a916400c6f6. --- arch/arm/mach-msm/board-mms-tsp.c | 2 +- drivers/input/misc/bmp180.c | 4 ++-- drivers/media/common/tuners/xc4000.c | 2 +- drivers/misc/a2220.c | 2 +- drivers/power/pm8xxx-ccadc.c | 2 +- fs/cifs/transport.c | 2 +- fs/ecryptfs/keystore.c | 2 +- include/linux/charging_temperature_data.h | 12 ++++++------ net/netfilter/xt_socket.c | 10 +++++----- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-msm/board-mms-tsp.c b/arch/arm/mach-msm/board-mms-tsp.c index 6ce42674a4f..543d38f1374 100644 --- a/arch/arm/mach-msm/board-mms-tsp.c +++ b/arch/arm/mach-msm/board-mms-tsp.c @@ -74,7 +74,6 @@ void melfas_vdd_on(bool onoff) static struct regulator *reg_l17; /* 1.8V */ #ifdef CONFIG_MACH_M2_VZW - static struct regulator *reg_l11; if (system_rev < BOARD_REV02) { if (onoff) gpio_direction_output(10, 1); @@ -150,6 +149,7 @@ void melfas_vdd_on(bool onoff) } #else /* 2.8V */ + static struct regulator *reg_l11; if (machine_is_ESPRESSO_VZW() && system_rev < BOARD_REV03) { if (!reg_l17) { reg_l17 = regulator_get(NULL, "8921_l17"); diff --git a/drivers/input/misc/bmp180.c b/drivers/input/misc/bmp180.c index adf025da18a..8eff6535069 100644 --- a/drivers/input/misc/bmp180.c +++ b/drivers/input/misc/bmp180.c @@ -189,8 +189,8 @@ static int bmp180_get_raw_pressure(struct bmp180_data *barom, static int bmp180_get_pressure_data_body(struct bmp180_data *barom) { - u16 raw_temperature; - u32 raw_pressure; + u16 raw_temperature = 0; + u32 raw_pressure = 0; long x1, x2, x3, b3, b5, b6; unsigned long b4, b7; long p; diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c index 68397110b7d..6d157c34a64 100644 --- a/drivers/media/common/tuners/xc4000.c +++ b/drivers/media/common/tuners/xc4000.c @@ -935,7 +935,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, int rc = 0, is_retry = 0; u16 hwmodel; v4l2_std_id std0; - u8 hw_major, hw_minor, fw_major, fw_minor; + u8 hw_major = 0, hw_minor = 0, fw_major = 0, fw_minor = 0; dprintk(1, "%s called\n", __func__); diff --git a/drivers/misc/a2220.c b/drivers/misc/a2220.c index 8e396dec544..46383708a36 100644 --- a/drivers/misc/a2220.c +++ b/drivers/misc/a2220.c @@ -176,7 +176,7 @@ static void a2220_i2c_sw_reset(struct a2220_data *a2220, unsigned int reset_cmd) a2220_hw_reset(struct a2220_data *a2220, struct a2220img *img) { struct a2220img *vp = img; - int rc, i, pass = 0; + int rc = 0, i, pass = 0; int remaining; int retry = RETRY_CNT; unsigned char *index; diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c index 7e37daa4ed1..b453caa6aa5 100644 --- a/drivers/power/pm8xxx-ccadc.c +++ b/drivers/power/pm8xxx-ccadc.c @@ -779,7 +779,7 @@ static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev) #define CCADC_CALIB_TEMP_THRESH 20 static int pm8xxx_ccadc_resume(struct device *dev) { - int rc, batt_temp, delta_temp; + int rc, batt_temp = 0, delta_temp; unsigned long current_time_sec; unsigned long time_since_last_calib; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0961336513d..1607615186c 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -569,7 +569,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, { int rc = 0; int long_op; - struct mid_q_entry *midQ; + struct mid_q_entry *midQ = NULL; char *buf = iov[0].iov_base; long_op = flags & CIFS_TIMEOUT_MASK; diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index 2333203a120..6154cde3a05 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -1150,7 +1150,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_message *msg = NULL; char *auth_tok_sig; char *payload; - size_t payload_len; + size_t payload_len = 0; int rc; rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok); diff --git a/include/linux/charging_temperature_data.h b/include/linux/charging_temperature_data.h index db31292a400..0f4262220a5 100644 --- a/include/linux/charging_temperature_data.h +++ b/include/linux/charging_temperature_data.h @@ -29,7 +29,7 @@ #define DEFAULT_LOW_RECOVER_TEMP 0 #if defined(CONFIG_MACH_JAGUAR) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26250, 800}, {26583, 750}, {26979, 700}, @@ -54,7 +54,7 @@ static const int temp_table[][2] = { }; #elif defined(CONFIG_MACH_M2_ATT) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26465, 800}, {26749, 750}, {27017, 700}, @@ -104,7 +104,7 @@ static const struct pm8xxx_adc_map_pt temp_table[] = { }; #elif defined(CONFIG_MACH_M2_VZW) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26537, 800}, {26849, 750}, {27211, 700}, @@ -129,7 +129,7 @@ static const int temp_table[][2] = { }; #elif defined(CONFIG_MACH_GOGH) || defined(CONFIG_MACH_INFINITE) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26478, 800}, {27123, 700}, {27985, 600}, @@ -144,7 +144,7 @@ static const int temp_table[][2] = { }; #elif defined(CONFIG_MACH_AEGIS2) -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {27401, 650}, {27790, 600}, {28378, 550}, @@ -167,7 +167,7 @@ static const int temp_table[][2] = { }; #else -static const int temp_table[][2] = { +static const struct pm8xxx_adc_map_pt temp_table[] = { {26250, 800}, {26583, 750}, {26979, 700}, diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 1e48fcf2920..3163becc172 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -108,9 +108,9 @@ xt_socket_get4_sk(const struct sk_buff *skb, struct xt_action_param *par) const struct iphdr *iph = ip_hdr(skb); struct udphdr _hdr, *hp = NULL; struct sock *sk; - __be32 daddr, saddr; - __be16 dport, sport; - u8 protocol; + __be32 daddr = 0, saddr = 0; + __be16 dport = 0, sport = 0; + u8 protocol = 0; #ifdef XT_SOCKET_HAVE_CONNTRACK struct nf_conn const *ct; enum ip_conntrack_info ctinfo; @@ -273,8 +273,8 @@ xt_socket_get6_sk(const struct sk_buff *skb, struct xt_action_param *par) struct ipv6hdr *iph = ipv6_hdr(skb); struct udphdr _hdr, *hp = NULL; struct sock *sk; - struct in6_addr *daddr, *saddr; - __be16 dport, sport; + struct in6_addr *daddr = NULL, *saddr = NULL; + __be16 dport = 0, sport = 0; int thoff, tproto; tproto = ipv6_find_hdr(skb, &thoff, -1, NULL); From c24332d9f3ac56b6c7ad62a054084fd2ab4a041a Mon Sep 17 00:00:00 2001 From: detule Date: Tue, 5 Mar 2013 21:41:27 -0500 Subject: [PATCH 2350/2357] M2: fix restart to download mode (thanks to aerovan) --- arch/arm/mach-msm/restart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c index 1daff1962a6..89687d34300 100644 --- a/arch/arm/mach-msm/restart.c +++ b/arch/arm/mach-msm/restart.c @@ -270,6 +270,8 @@ void msm_restart(char mode, const char *cmd) __raw_writel(0x77665500, restart_reason); } else if (!strncmp(cmd, "recovery", 8)) { __raw_writel(0x77665502, restart_reason); + } else if (!strncmp(cmd, "download", 8)) { + __raw_writel(0x12345671, restart_reason); } else if (!strncmp(cmd, "oem-", 4)) { unsigned long code; code = simple_strtoul(cmd + 4, NULL, 16) & 0xff; From 0da182f9cd18c02253d687996a5ebeabf3a231ca Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 22 Feb 2013 11:17:19 +0530 Subject: [PATCH 2351/2357] power: pm8921-charger: Make charger removal detection workaround optional On some platforms such as MPQ8064 the charger removal detection workarounds - reverse boost fix and OVP FET stuck do not work as expected as the SMBC module is disconnected from USBout. On these targets the USB interface is not used for charging but merely to indicate the USB driver of the insertion/removal. Add a platform data variable to make this optional and enable the same for MPQ8064. Change-Id: I3fca1b357f8fc280483302f72ffbc61fb50109a7 Signed-off-by: Anirudh Ghayal --- arch/arm/mach-msm/board-8064-pmic.c | 3 +++ drivers/power/pm8921-charger.c | 7 +++++-- include/linux/mfd/pm8xxx/pm8921-charger.h | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c index 6269abbaf64..65707b19280 100644 --- a/arch/arm/mach-msm/board-8064-pmic.c +++ b/arch/arm/mach-msm/board-8064-pmic.c @@ -507,4 +507,7 @@ void __init apq8064_init_pmic(void) if (!machine_is_apq8064_mtp() && !machine_is_apq8064_liquid()) apq8064_pm8921_chg_pdata.battery_less_hardware = 1; + + if (machine_is_mpq8064_hrd()) + apq8064_pm8921_chg_pdata.disable_chg_rmvl_wrkarnd = 1; } diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c index 5f50d3139d7..1ca95f6fe83 100644 --- a/drivers/power/pm8921-charger.c +++ b/drivers/power/pm8921-charger.c @@ -293,6 +293,7 @@ struct pm8921_chg_chip { int stop_chg_upon_expiry; bool disable_aicl; int usb_type; + bool disable_chg_rmvl_wrkarnd; }; /* user space parameter to limit usb current */ @@ -2778,7 +2779,7 @@ static void unplug_check_worker(struct work_struct *work) pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma); ibat = get_prop_batt_current(chip); - if (reg_loop & VIN_ACTIVE_BIT) { + if ((reg_loop & VIN_ACTIVE_BIT) && !chip->disable_chg_rmvl_wrkarnd) { if (ibat > 0) { pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n", ibat, pm_chg_get_fsm_state(chip), reg_loop); @@ -2798,7 +2799,8 @@ static void unplug_check_worker(struct work_struct *work) active_path, active_chg_plugged_in); chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ); - if (chg_gone == 1 && active_chg_plugged_in == 1) { + if (chg_gone == 1 && active_chg_plugged_in == 1 && + !chip->disable_chg_rmvl_wrkarnd) { pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n", chg_gone, active_chg_plugged_in); unplug_ovp_fet_open(chip); @@ -4617,6 +4619,7 @@ static int __devinit pm8921_charger_probe(struct platform_device *pdev) chip->vin_min = pdata->vin_min; chip->thermal_mitigation = pdata->thermal_mitigation; chip->thermal_levels = pdata->thermal_levels; + chip->disable_chg_rmvl_wrkarnd = pdata->disable_chg_rmvl_wrkarnd; chip->cold_thr = pdata->cold_thr; chip->hot_thr = pdata->hot_thr; diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h index 785a33aa26c..1c67b1eeb3b 100644 --- a/include/linux/mfd/pm8xxx/pm8921-charger.h +++ b/include/linux/mfd/pm8xxx/pm8921-charger.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -188,6 +188,7 @@ struct pm8921_charger_platform_data { int btc_delay_ms; int btc_panic_if_cant_stop_chg; int stop_chg_upon_expiry; + bool disable_chg_rmvl_wrkarnd; }; enum pm8921_charger_source { From ab6019995e6a49d6b7267ae4ca5c103b48094196 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Tue, 5 Mar 2013 11:18:20 -0700 Subject: [PATCH 2352/2357] msm: kgsl: Check the current interrupt status before power operations Sometimes the core will go idle before the interrupt can be handled on the GPU. If that happens then we could go to a lower power state before cleaning up the pending interrupt and various entities that might be waiting for it. Consider the current interrupt status when checking for idle. CRS-fixed: 449813 Change-Id: Ic0dedbadfd2d40e4411cf3b05e1eb4c4eecf7841 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/adreno.c | 13 +++++++++++-- drivers/gpu/msm/adreno.h | 1 + drivers/gpu/msm/adreno_a2xx.c | 16 +++++++++++++++- drivers/gpu/msm/adreno_a3xx.c | 10 ++++++++++ drivers/gpu/msm/kgsl.c | 5 +---- drivers/gpu/msm/kgsl_device.h | 19 +++++++++++++++++++ drivers/gpu/msm/kgsl_events.c | 13 +++++++++++++ 7 files changed, 70 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 73ce22c0a34..1886e045362 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -2405,8 +2405,17 @@ static unsigned int adreno_isidle(struct kgsl_device *device) /* Is the ring buffer is empty? */ GSL_RB_GET_READPTR(rb, &rb->rptr); if (!device->active_cnt && (rb->rptr == rb->wptr)) { - /* Is the core idle? */ - status = is_adreno_rbbm_status_idle(device); + /* + * Are there interrupts pending? If so then pretend we + * are not idle - this avoids the possiblity that we go + * to a lower power state without handling interrupts + * first. + */ + + if (!adreno_dev->gpudev->irq_pending(adreno_dev)) { + /* Is the core idle? */ + status = is_adreno_rbbm_status_idle(device); + } } } else { status = true; diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 8a57b95574d..d319c98b969 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -132,6 +132,7 @@ struct adreno_gpudev { struct adreno_context *); irqreturn_t (*irq_handler)(struct adreno_device *); void (*irq_control)(struct adreno_device *, int); + unsigned int (*irq_pending)(struct adreno_device *); void * (*snapshot)(struct adreno_device *, void *, int *, int); void (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *); void (*start)(struct adreno_device *); diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c index c633991999a..0359a4f02be 100644 --- a/drivers/gpu/msm/adreno_a2xx.c +++ b/drivers/gpu/msm/adreno_a2xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1840,6 +1840,19 @@ static void a2xx_irq_control(struct adreno_device *adreno_dev, int state) wmb(); } +static unsigned int a2xx_irq_pending(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = &adreno_dev->dev; + unsigned int rbbm, cp, mh; + + adreno_regread(device, REG_RBBM_INT_CNTL, &rbbm); + adreno_regread(device, REG_CP_INT_CNTL, &cp); + adreno_regread(device, MH_INTERRUPT_MASK, &mh); + + return ((rbbm & RBBM_INT_MASK) || (cp & CP_INT_MASK) || + (mh & kgsl_mmu_get_int_mask())) ? 1 : 0; +} + static void a2xx_rb_init(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb) { @@ -2035,6 +2048,7 @@ struct adreno_gpudev adreno_a2xx_gpudev = { .ctxt_draw_workaround = a2xx_drawctxt_draw_workaround, .irq_handler = a2xx_irq_handler, .irq_control = a2xx_irq_control, + .irq_pending = a2xx_irq_pending, .snapshot = a2xx_snapshot, .rb_init = a2xx_rb_init, .busy_cycles = a2xx_busy_cycles, diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 0778ccb8254..43f3f861114 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -2694,6 +2694,15 @@ static void a3xx_irq_control(struct adreno_device *adreno_dev, int state) adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, 0); } +static unsigned int a3xx_irq_pending(struct adreno_device *adreno_dev) +{ + unsigned int status; + + adreno_regread(&adreno_dev->dev, A3XX_RBBM_INT_0_STATUS, &status); + + return (status & A3XX_INT_MASK) ? 1 : 0; +} + static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev) { struct kgsl_device *device = &adreno_dev->dev; @@ -2888,6 +2897,7 @@ struct adreno_gpudev adreno_a3xx_gpudev = { .rb_init = a3xx_rb_init, .irq_control = a3xx_irq_control, .irq_handler = a3xx_irq_handler, + .irq_pending = a3xx_irq_pending, .busy_cycles = a3xx_busy_cycles, .start = a3xx_start, .snapshot = a3xx_snapshot, diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index e1f5e317cea..f6c432dd120 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -903,10 +903,7 @@ static long _device_waittimestamp(struct kgsl_device_private *dev_priv, result); /* Fire off any pending suspend operations that are in flight */ - - INIT_COMPLETION(dev_priv->device->suspend_gate); - dev_priv->device->active_cnt--; - complete(&dev_priv->device->suspend_gate); + kgsl_active_count_put(dev_priv->device); return result; } diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index af869af0e59..36e7102731c 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -443,4 +443,23 @@ kgsl_context_put(struct kgsl_context *context) kref_put(&context->refcount, kgsl_context_destroy); } +/** + * kgsl_active_count_put - Decrease the device active count + * @device: Pointer to a KGSL device + * + * Decrease the active count for the KGSL device and trigger the suspend_gate + * completion if it hits zero + */ +static inline void +kgsl_active_count_put(struct kgsl_device *device) +{ + if (device->active_cnt == 1) + INIT_COMPLETION(device->suspend_gate); + + device->active_cnt--; + + if (device->active_cnt == 0) + complete(&device->suspend_gate); +} + #endif /* __KGSL_DEVICE_H */ diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c index be9b5eb312d..6c0a6fa8c5f 100644 --- a/drivers/gpu/msm/kgsl_events.c +++ b/drivers/gpu/msm/kgsl_events.c @@ -106,6 +106,13 @@ int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, } else _add_event_to_list(&device->events, event); + /* + * Increase the active count on the device to avoid going into power + * saving modes while events are pending + */ + + device->active_cnt++; + queue_work(device->work_queue, &device->ts_expired_ws); return 0; } @@ -143,6 +150,8 @@ void kgsl_cancel_events_ctxt(struct kgsl_device *device, kgsl_context_put(context); list_del(&event->list); kfree(event); + + kgsl_active_count_put(device); } /* Remove ourselves from the master pending list */ @@ -184,6 +193,8 @@ void kgsl_cancel_events(struct kgsl_device *device, list_del(&event->list); kfree(event); + + kgsl_active_count_put(device); } } EXPORT_SYMBOL(kgsl_cancel_events); @@ -215,6 +226,8 @@ static void _process_event_list(struct kgsl_device *device, list_del(&event->list); kfree(event); + + kgsl_active_count_put(device); } } From ef02fc0acc54f4cad7402197b7238388074a4f80 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Tue, 5 Mar 2013 11:19:31 -0700 Subject: [PATCH 2353/2357] msm: kgsl: Resolve a potential race in the interrupt handler In the GPU interrupt handler we attempt to clear the ts_cmp_enable for the active context so that future interrupts are skipped until someone needs one again. If for some reason the interrupt handler is delayed then there is a possiblity that the "current" context in the GPU isn't the one that fired the interrupt. In that case we could be accidently clearing a ts_cmp_enable for a context that needs it. Instead of clearing in the interrupt handler clear it from the GPU so we can be sure we got the right context. As a bonus pushing this logic to the GPU side lets us get rid of some extra register reads/writes in the interrupt handlers. Change-Id: Ic0dedbadbf350f7c4866092fa0686f9b42f3cd33 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/adreno_a2xx.c | 22 ---------------------- drivers/gpu/msm/adreno_a3xx.c | 21 +-------------------- drivers/gpu/msm/adreno_ringbuffer.c | 27 ++++++++++++++++++++++----- 3 files changed, 23 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c index 0359a4f02be..ba4e5076031 100644 --- a/drivers/gpu/msm/adreno_a2xx.c +++ b/drivers/gpu/msm/adreno_a2xx.c @@ -1708,28 +1708,6 @@ static void a2xx_cp_intrcallback(struct kgsl_device *device) return; } - if (status & CP_INT_CNTL__RB_INT_MASK) { - /* signal intr completion event */ - unsigned int context_id; - kgsl_sharedmem_readl(&device->memstore, - &context_id, - KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, - current_context)); - if (context_id < KGSL_MEMSTORE_MAX) { - /* reset per context ts_cmp_enable */ - kgsl_sharedmem_writel(&device->memstore, - KGSL_MEMSTORE_OFFSET(context_id, - ts_cmp_enable), 0); - /* Always reset global timestamp ts_cmp_enable */ - kgsl_sharedmem_writel(&device->memstore, - KGSL_MEMSTORE_OFFSET( - KGSL_MEMSTORE_GLOBAL, - ts_cmp_enable), 0); - wmb(); - } - KGSL_CMD_WARN(rb->device, "ringbuffer rb interrupt\n"); - } - for (i = 0; i < ARRAY_SIZE(kgsl_cp_error_irqs); i++) { if (status & kgsl_cp_error_irqs[i].mask) { KGSL_CMD_CRIT(rb->device, "%s\n", diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 43f3f861114..3d9ec6d234d 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -2576,26 +2576,7 @@ static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq) { struct kgsl_device *device = &adreno_dev->dev; - if (irq == A3XX_INT_CP_RB_INT) { - unsigned int context_id; - kgsl_sharedmem_readl(&device->memstore, &context_id, - KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, - current_context)); - if (context_id < KGSL_MEMSTORE_MAX) { - /* reset per context ts_cmp_enable */ - kgsl_sharedmem_writel(&device->memstore, - KGSL_MEMSTORE_OFFSET(context_id, - ts_cmp_enable), 0); - /* Always reset global timestamp ts_cmp_enable */ - kgsl_sharedmem_writel(&device->memstore, - KGSL_MEMSTORE_OFFSET( - KGSL_MEMSTORE_GLOBAL, - ts_cmp_enable), 0); - wmb(); - } - KGSL_CMD_WARN(device, "ringbuffer rb interrupt\n"); - } - + /* Wake up everybody waiting for the interrupt */ wake_up_interruptible_all(&device->wait_queue); /* Schedule work to free mem and issue ibs */ diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 7e993a20c6c..179027c3b89 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -564,10 +564,9 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0; /* 2 dwords to store the start of command sequence */ total_sizedwords += 2; - /* - * Add CP_COND_EXEC commands to generate CP_INTERRUPT only - */ - total_sizedwords += context ? 7 : 0; + + /* Add CP_COND_EXEC commands to generate CP_INTERRUPT */ + total_sizedwords += context ? 13 : 0; if (adreno_is_a3xx(adreno_dev)) total_sizedwords += 7; @@ -696,7 +695,25 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, context_id, ref_wait_ts)) >> 2); GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp); /* # of conditional command DWORDs */ - GSL_RB_WRITE(ringcmds, rcmd_gpu, 2); + GSL_RB_WRITE(ringcmds, rcmd_gpu, 8); + + /* Clear the ts_cmp_enable for the context */ + GSL_RB_WRITE(ringcmds, rcmd_gpu, + cp_type3_packet(CP_MEM_WRITE, 2)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr + + KGSL_MEMSTORE_OFFSET( + context_id, ts_cmp_enable)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0); + + /* Clear the ts_cmp_enable for the global timestamp */ + GSL_RB_WRITE(ringcmds, rcmd_gpu, + cp_type3_packet(CP_MEM_WRITE, 2)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr + + KGSL_MEMSTORE_OFFSET( + KGSL_MEMSTORE_GLOBAL, ts_cmp_enable)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0); + + /* Trigger the interrupt */ GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_INTERRUPT, 1)); GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK); From 2c22e9129c47723dd85654767d2b174c79afc20a Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Thu, 28 Feb 2013 13:40:56 -0700 Subject: [PATCH 2354/2357] msm: kgsl: Add event tracepoints Add tracepoints for tracking the lifespan of GPU events. Change-Id: Ic0dedbadf99b1efcb650608c6ac664d3c4ddafd5 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/kgsl_device.h | 1 + drivers/gpu/msm/kgsl_events.c | 15 +++++++++++++++ drivers/gpu/msm/kgsl_trace.h | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 36e7102731c..b215d8ccbb0 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -134,6 +134,7 @@ struct kgsl_event { void *priv; struct list_head list; void *owner; + unsigned int created; }; diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c index 6c0a6fa8c5f..6798eed52c8 100644 --- a/drivers/gpu/msm/kgsl_events.c +++ b/drivers/gpu/msm/kgsl_events.c @@ -16,6 +16,8 @@ #include #include +#include "kgsl_trace.h" + static void _add_event_to_list(struct list_head *head, struct kgsl_event *event) { struct list_head *n; @@ -71,6 +73,7 @@ int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, */ if (timestamp_cmp(cur_ts, ts) >= 0) { + trace_kgsl_fire_event(id, ts, 0); cb(device, priv, id, ts); return 0; } @@ -84,6 +87,9 @@ int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, event->priv = priv; event->func = cb; event->owner = owner; + event->created = jiffies; + + trace_kgsl_register_event(id, ts); /* inc refcount to avoid race conditions in cleanup */ if (context) @@ -144,6 +150,8 @@ void kgsl_cancel_events_ctxt(struct kgsl_device *device, * system got before the event was canceled */ + trace_kgsl_fire_event(id, cur, jiffies - event->created); + if (event->func) event->func(device, event->priv, id, cur); @@ -184,6 +192,10 @@ void kgsl_cancel_events(struct kgsl_device *device, * the callback knows how far the GPU made it before things went * explosion */ + + trace_kgsl_fire_event(KGSL_MEMSTORE_GLOBAL, cur, + jiffies - event->created); + if (event->func) event->func(device, event->priv, KGSL_MEMSTORE_GLOBAL, cur); @@ -218,6 +230,9 @@ static void _process_event_list(struct kgsl_device *device, * to the timestamp they wanted */ + trace_kgsl_fire_event(id, event->timestamp, + jiffies - event->created); + if (event->func) event->func(device, event->priv, id, event->timestamp); diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h index e12013dc501..c54445ca5da 100644 --- a/drivers/gpu/msm/kgsl_trace.h +++ b/drivers/gpu/msm/kgsl_trace.h @@ -535,6 +535,41 @@ TRACE_EVENT(kgsl_mmu_pagefault, ) ); +TRACE_EVENT(kgsl_register_event, + TP_PROTO(unsigned int id, unsigned int timestamp), + TP_ARGS(id, timestamp), + TP_STRUCT__entry( + __field(unsigned int, id) + __field(unsigned int, timestamp) + ), + TP_fast_assign( + __entry->id = id; + __entry->timestamp = timestamp; + ), + TP_printk( + "ctx=%d ts=%d", + __entry->id, __entry->timestamp) +); + +TRACE_EVENT(kgsl_fire_event, + TP_PROTO(unsigned int id, unsigned int ts, + unsigned int age), + TP_ARGS(id, ts, age), + TP_STRUCT__entry( + __field(unsigned int, id) + __field(unsigned int, ts) + __field(unsigned int, age) + ), + TP_fast_assign( + __entry->id = id; + __entry->ts = ts; + __entry->age = age; + ), + TP_printk( + "ctx=%d ts=%d age=%u", + __entry->id, __entry->ts, __entry->age) +); + #endif /* _KGSL_TRACE_H */ /* This part must be outside protection */ From 4a0d1f615d97dc4986f2b997a04ec54be1d99a8c Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Tue, 26 Feb 2013 15:11:00 +0530 Subject: [PATCH 2355/2357] qup_i2c: Update clock ready check condition While doing i2c transfer that involved write and immediate read, the driver will put the controller to RESET and do an immediate read before the write completes. This issue is hard to produce internally because clock stretch from slave device is involved during the failure time. CLK state in QUP status register will be FORCED_LOW_STATE. O/p fifo empty check added to determine clock idle. CRs-Fixed: 455743 Change-Id: I51c1d9f9de42381fc85710e9185aa4177f6cd302 Signed-off-by: Alok Chauhan --- drivers/i2c/busses/i2c-qup.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index b562350431d..7765830d523 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -128,6 +128,9 @@ enum { }; #define QUP_MAX_CLK_STATE_RETRIES 300 +#define DEFAULT_CLK_RATE (19200000) +#define I2C_STATUS_CLK_STATE 13 +#define QUP_OUT_FIFO_NOT_EMPTY 0x10 static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"}; @@ -375,6 +378,7 @@ qup_i2c_poll_writeready(struct qup_i2c_dev *dev, int rem) static int qup_i2c_poll_clock_ready(struct qup_i2c_dev *dev) { uint32_t retries = 0; + uint32_t op_flgs = -1, clk_state = -1; /* * Wait for the clock state to transition to either IDLE or FORCED @@ -383,16 +387,32 @@ static int qup_i2c_poll_clock_ready(struct qup_i2c_dev *dev) while (retries++ < QUP_MAX_CLK_STATE_RETRIES) { uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS); - uint32_t clk_state = (status >> 13) & 0x7; + clk_state = (status >> I2C_STATUS_CLK_STATE) & 0x7; + /* Read the operational register */ + op_flgs = readl_relaxed(dev->base + + QUP_OPERATIONAL) & QUP_OUT_FIFO_NOT_EMPTY; - if (clk_state == I2C_CLK_RESET_BUSIDLE_STATE || - clk_state == I2C_CLK_FORCED_LOW_STATE) + /* + * In very corner case when slave do clock stretching and + * output fifo will have 1 block of data space empty at + * the same time. So i2c qup will get output service + * interrupt and as it doesn't have more data to be written. + * This can lead to issue where output fifo is not empty. + */ + if (op_flgs == 0 && + (clk_state == I2C_CLK_RESET_BUSIDLE_STATE || + clk_state == I2C_CLK_FORCED_LOW_STATE)){ + dev_dbg(dev->dev, "clk_state 0x%x op_flgs [%x]\n", + clk_state, op_flgs); return 0; + } + /* 1-bit delay before we check again */ udelay(dev->one_bit_t); } - dev_err(dev->dev, "Error waiting for clk ready\n"); + dev_err(dev->dev, "Error waiting for clk ready clk_state: 0x%x op_flgs: 0x%x\n", + clk_state, op_flgs); return -ETIMEDOUT; } From fc0f7209fa1eca5231daab49450adb9dee7e658d Mon Sep 17 00:00:00 2001 From: detule Date: Wed, 6 Mar 2013 14:46:42 -0500 Subject: [PATCH 2356/2357] M2: pmic: Fix calibration delay (leading to slow panel wakes) Starting with 999ee576589682c27492184c22053d19819c0285 msm: power: update power drivers to msm-3.4 tip calibration delay is no longer hard-coded and is passed via pdata. --- arch/arm/mach-msm/board-m2-pmic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-msm/board-m2-pmic.c b/arch/arm/mach-msm/board-m2-pmic.c index 85a986ef1c1..1c4b8b1b222 100644 --- a/arch/arm/mach-msm/board-m2-pmic.c +++ b/arch/arm/mach-msm/board-m2-pmic.c @@ -980,6 +980,7 @@ static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = { static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = { .r_sense_uohm = 10000, + .calib_delay_ms = 600000, }; static struct pm8921_platform_data pm8921_platform_data __devinitdata = { From 832a849e434e283833ac68338729896857174da6 Mon Sep 17 00:00:00 2001 From: Evan McClain Date: Sat, 9 Mar 2013 12:41:56 -0500 Subject: [PATCH 2357/2357] Revert "M2: Revert "msm: display: sync point clean up"" This reverts commit f96ba4b5f7a49e8d505d8f4b6755d6ab9f5ac215. --- drivers/video/msm/msm_fb.c | 125 ++++++++----------------------------- drivers/video/msm/msm_fb.h | 3 +- include/linux/msm_mdp.h | 1 - 3 files changed, 28 insertions(+), 101 deletions(-) mode change 100755 => 100644 drivers/video/msm/msm_fb.c diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c old mode 100755 new mode 100644 index 8d05b9a5c7a..a3ec88263f4 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -452,7 +452,10 @@ static int msm_fb_probe(struct platform_device *pdev) pdev_list[pdev_list_cnt++] = pdev; msm_fb_create_sysfs(pdev); if (mfd->timeline == NULL) { - mfd->timeline = sw_sync_timeline_create("mdp-timeline"); + char timeline_name[MAX_TIMELINE_NAME_LEN]; + snprintf(timeline_name, sizeof(timeline_name), + "mdp_fb_%d", mfd->index); + mfd->timeline = sw_sync_timeline_create(timeline_name); if (mfd->timeline == NULL) { pr_err("%s: cannot create time line", __func__); return -ENOMEM; @@ -988,17 +991,7 @@ static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, if (ret) mfd->panel_power_on = curr_pwr_state; - if (mfd->timeline) { - /* Adding 1 is enough when pan_display is still - * a blocking call and with mutex protection. - * But if it is an async call, we will still - * need to add 2. Adding 2 can be safer in - * order to signal all existing fences, and it - * is harmless. */ - sw_sync_timeline_inc(mfd->timeline, 2); - mfd->timeline_value+= 2; - } - + msm_fb_release_timeline(mfd); mfd->op_enable = TRUE; } break; @@ -1799,7 +1792,7 @@ static int msm_fb_release(struct fb_info *info, int user) return ret; } -int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd) +void msm_fb_wait_for_fence(struct msm_fb_data_type *mfd) { int i, ret = 0; /* buf sync */ @@ -1820,8 +1813,13 @@ int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd) } sync_fence_put(mfd->acq_fen[i]); } + if (ret < 0) { + while (i < mfd->acq_fen_cnt) { + sync_fence_put(mfd->acq_fen[i]); + i++; + } + } mfd->acq_fen_cnt = 0; - return ret; } int msm_fb_signal_timeline(struct msm_fb_data_type *mfd) { @@ -1837,6 +1835,18 @@ int msm_fb_signal_timeline(struct msm_fb_data_type *mfd) return 0; } +void msm_fb_release_timeline(struct msm_fb_data_type *mfd) +{ + mutex_lock(&mfd->sync_mutex); + if (mfd->timeline) { + sw_sync_timeline_inc(mfd->timeline, 2); + mfd->timeline_value += 2; + } + mfd->last_rel_fence = 0; + mfd->cur_rel_fence = 0; + mutex_unlock(&mfd->sync_mutex); +} + DEFINE_SEMAPHORE(msm_fb_pan_sem); static int msm_fb_pan_idle(struct msm_fb_data_type *mfd) { @@ -2020,10 +2030,7 @@ static int msm_fb_pan_display_sub(struct fb_var_screeninfo *var, if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { pr_err("%s: can't turn on display!\n", __func__); up(&msm_fb_pan_sem); - if (mfd->timeline) { - sw_sync_timeline_inc(mfd->timeline, 2); - mfd->timeline_value+= 2; - } + msm_fb_release_timeline(mfd); return -EINVAL; } } @@ -3639,6 +3646,7 @@ static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd, return ret; } + static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd, struct mdp_buf_sync *buf_sync) { @@ -3730,101 +3738,20 @@ static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd, return ret; } -static int buf_fence_process(struct msm_fb_data_type *mfd, - struct mdp_buf_fence *buf_fence) -{ - int i, fence_cnt = 0, ret; - struct sync_fence *fence; - - if ((buf_fence->acq_fen_fd_cnt == 0) || - (buf_fence->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) || - (mfd->timeline == NULL)) - return -EINVAL; - - mutex_lock(&mfd->sync_mutex); - for (i = 0; i < buf_fence->acq_fen_fd_cnt; i++) { - fence = sync_fence_fdget(buf_fence->acq_fen_fd[i]); - if (fence == NULL) { - pr_info("%s: null fence! i=%d fd=%d\n", __func__, i, - buf_fence->acq_fen_fd[i]); - ret = -EINVAL; - break; - } - mfd->acq_fen[i] = fence; - } - fence_cnt = i; - if (ret) - goto buf_fence_err_1; - mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline, - mfd->timeline_value + 2); - if (mfd->cur_rel_sync_pt == NULL) { - pr_err("%s: cannot create sync point", __func__); - ret = -ENOMEM; - goto buf_fence_err_1; - } - /* create fence */ - mfd->cur_rel_fence = sync_fence_create("mdp-fence", - mfd->cur_rel_sync_pt); - if (mfd->cur_rel_fence == NULL) { - sync_pt_free(mfd->cur_rel_sync_pt); - mfd->cur_rel_sync_pt = NULL; - pr_err("%s: cannot create fence", __func__); - ret = -ENOMEM; - goto buf_fence_err_1; - } - /* create fd */ - mfd->cur_rel_fen_fd = get_unused_fd_flags(0); - if (mfd->cur_rel_fen_fd < 0) { - pr_err("%s: get_unused_fd_flags failed", __func__); - ret = -EIO; - goto buf_fence_err_2; - } - sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd); - buf_fence->rel_fen_fd[0] = mfd->cur_rel_fen_fd; - /* Only one released fd for now, -1 indicates an end */ - buf_fence->rel_fen_fd[1] = -1; - mfd->acq_fen_cnt = buf_fence->acq_fen_fd_cnt; - mutex_unlock(&mfd->sync_mutex); - return ret; -buf_fence_err_2: - sync_fence_put(mfd->cur_rel_fence); - mfd->cur_rel_fence = NULL; - mfd->cur_rel_fen_fd = 0; -buf_fence_err_1: - for (i = 0; i < fence_cnt; i++) - sync_fence_put(mfd->acq_fen[i]); - mfd->acq_fen_cnt = 0; - mutex_unlock(&mfd->sync_mutex); - return ret; -} static int msmfb_display_commit(struct fb_info *info, unsigned long *argp) { int ret; - u32 copy_back = FALSE; - struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; struct mdp_display_commit disp_commit; - struct mdp_buf_fence *buf_fence; ret = copy_from_user(&disp_commit, argp, sizeof(disp_commit)); if (ret) { pr_err("%s:copy_from_user failed", __func__); return ret; } - buf_fence = &disp_commit.buf_fence; - if (buf_fence->acq_fen_fd_cnt > 0) - ret = buf_fence_process(mfd, buf_fence); - if ((!ret) && (buf_fence->rel_fen_fd[0] > 0)) - copy_back = TRUE; ret = msm_fb_pan_display_ex(info, &disp_commit); - if (copy_back) { - ret = copy_to_user(argp, - &disp_commit, sizeof(disp_commit)); - if (ret) - pr_err("%s:copy_to_user failed", __func__); - } return ret; } diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h index 06a4f6a4d67..91537644d07 100644 --- a/drivers/video/msm/msm_fb.h +++ b/drivers/video/msm/msm_fb.h @@ -242,8 +242,9 @@ int msm_fb_writeback_stop(struct fb_info *info); int msm_fb_writeback_terminate(struct fb_info *info); int msm_fb_detect_client(const char *name); int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp); -int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd); +void msm_fb_wait_for_fence(struct msm_fb_data_type *mfd); int msm_fb_signal_timeline(struct msm_fb_data_type *mfd); +void msm_fb_release_timeline(struct msm_fb_data_type *mfd); #ifdef CONFIG_FB_BACKLIGHT void msm_fb_config_backlight(struct msm_fb_data_type *mfd); #endif diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h index 4332388c627..b7c46a8c1ea 100644 --- a/include/linux/msm_mdp.h +++ b/include/linux/msm_mdp.h @@ -550,7 +550,6 @@ struct mdp_display_commit { uint32_t flags; uint32_t wait_for_finish; struct fb_var_screeninfo var; - struct mdp_buf_fence buf_fence; }; struct mdp_page_protection {